Back to home page

LXR

 
 

    


File indexing completed on 2025-05-11 08:23:03

0001 /**
0002  * @file
0003  *
0004  * @ingroup RTEMSBSPsARMLPC176X
0005  *
0006  * @brief Input/output module methods.
0007  */
0008 
0009 /*
0010  * Copyright (c) 2014 Taller Technologies.
0011  *
0012  * @author  Boretto Martin    (martin.boretto@tallertechnologies.com)
0013  * @author  Diaz Marcos (marcos.diaz@tallertechnologies.com)
0014  * @author  Lenarduzzi Federico  (federico.lenarduzzi@tallertechnologies.com)
0015  * @author  Daniel Chicco  (daniel.chicco@tallertechnologies.com)
0016  *
0017  * The license and distribution terms for this file may be
0018  * found in the file LICENSE in this distribution or at
0019  * http://www.rtems.org/license/LICENSE.
0020  */
0021 
0022 #include <rtems/status-checks.h>
0023 #include <bsp.h>
0024 #include <bsp/io.h>
0025 #include <bsp/start.h>
0026 #include <bsp/system-clocks.h>
0027 
0028 /**
0029  * @brief Modules table according to the LPC176x
0030  */
0031 static const lpc176x_module_entry lpc176x_module_table[] = {
0032   LPC176X_MODULE_ENTRY( LPC176X_MODULE_WD, 0, 1, 0 ),
0033   LPC176X_MODULE_ENTRY( LPC176X_MODULE_ADC, 1, 1, 12 ),
0034   LPC176X_MODULE_ENTRY( LPC176X_MODULE_CAN_0, 1, 1, 13 ),
0035   LPC176X_MODULE_ENTRY( LPC176X_MODULE_CAN_1, 1, 1, 14 ),
0036   LPC176X_MODULE_ENTRY(LPC176X_MODULE_ACCF, 0, 1, 15),
0037   LPC176X_MODULE_ENTRY( LPC176X_MODULE_DAC, 0, 1, 11 ),
0038   LPC176X_MODULE_ENTRY( LPC176X_MODULE_GPDMA, 1, 1, 29 ),
0039   LPC176X_MODULE_ENTRY( LPC176X_MODULE_GPIO, 0, 1, 15 ),
0040   LPC176X_MODULE_ENTRY( LPC176X_MODULE_I2S, 1, 1, 27 ),
0041   LPC176X_MODULE_ENTRY( LPC176X_MODULE_MCI, 1, 1, 28 ),
0042   LPC176X_MODULE_ENTRY( LPC176X_MODULE_MCPWM, 1, 1, 17 ),
0043   LPC176X_MODULE_ENTRY( LPC176X_MODULE_PCB, 0, 1, 18 ),
0044   LPC176X_MODULE_ENTRY( LPC176X_MODULE_PWM_0, 1, 1, 5 ),
0045   LPC176X_MODULE_ENTRY( LPC176X_MODULE_PWM_1, 1, 1, 6 ),
0046   LPC176X_MODULE_ENTRY( LPC176X_MODULE_QEI, 1, 1, 18 ),
0047   LPC176X_MODULE_ENTRY( LPC176X_MODULE_RTC, 1, 1, 9 ),
0048   LPC176X_MODULE_ENTRY( LPC176X_MODULE_SYSCON, 0, 1, 30 ),
0049   LPC176X_MODULE_ENTRY( LPC176X_MODULE_TIMER_0, 1, 1, 1 ),
0050   LPC176X_MODULE_ENTRY( LPC176X_MODULE_TIMER_1, 1, 1, 2 ),
0051   LPC176X_MODULE_ENTRY( LPC176X_MODULE_TIMER_2, 1, 1, 22 ),
0052   LPC176X_MODULE_ENTRY( LPC176X_MODULE_TIMER_3, 1, 1, 23 ),
0053   LPC176X_MODULE_ENTRY( LPC176X_MODULE_UART_0, 1, 1, 3 ),
0054   LPC176X_MODULE_ENTRY( LPC176X_MODULE_UART_1, 1, 1, 4 ),
0055   LPC176X_MODULE_ENTRY( LPC176X_MODULE_UART_2, 1, 1, 24 ),
0056   LPC176X_MODULE_ENTRY( LPC176X_MODULE_UART_3, 1, 1, 25 ),
0057   LPC176X_MODULE_ENTRY( LPC176X_MODULE_USB, 1, 0, 31 )
0058 };
0059 
0060 inline void lpc176x_pin_select(
0061   const uint32_t             pin,
0062   const lpc176x_pin_function function
0063 )
0064 {
0065   assert( pin <= LPC176X_IO_INDEX_MAX
0066     && function < LPC176X_PIN_FUNCTION_COUNT );
0067   const uint32_t           pin_selected = LPC176X_PIN_SELECT( pin );
0068   volatile uint32_t *const pinsel = &LPC176X_PINSEL[ pin_selected ];
0069   const uint32_t           shift = LPC176X_PIN_SELECT_SHIFT( pin );
0070   *pinsel = SET_FIELD( *pinsel, function,
0071     LPC176X_PIN_SELECT_MASK << shift, shift );
0072 }
0073 
0074 void lpc176x_pin_set_mode(
0075   const uint32_t             pin,
0076   const lpc176x_pin_mode mode
0077 )
0078 {
0079   assert( pin <= LPC176X_IO_INDEX_MAX
0080     && mode < LPC176X_PIN_MODE_COUNT );
0081   const uint32_t           pin_selected = LPC176X_PIN_SELECT( pin );
0082   volatile uint32_t *const pinmode = &LPC176X_PINMODE[ pin_selected ];
0083   const uint32_t           shift = LPC176X_PIN_SELECT_SHIFT( pin );
0084   *pinmode = SET_FIELD( *pinmode, mode,
0085     LPC176X_PIN_SELECT_MASK << shift, shift );
0086 }
0087 
0088 /**
0089  * @brief Checks if the module has power.
0090  *
0091  * @param has_power Power.
0092  * @param index Index to shift.
0093  * @param turn_on Turn on/off the power.
0094  * @param level Interrupts value.
0095  */
0096 static rtems_status_code check_power(
0097   const bool            has_power,
0098   const unsigned        index,
0099   const bool            turn_on,
0100   rtems_interrupt_level level
0101 )
0102 {
0103   rtems_status_code status_code = RTEMS_INVALID_NUMBER;
0104 
0105   if ( index <= LPC176X_MODULE_BITS_COUNT ) {
0106     if ( has_power ) {
0107       rtems_interrupt_disable( level );
0108 
0109       if ( turn_on ) {
0110         LPC176X_SCB.pconp |= 1u << index;
0111       } else {
0112         LPC176X_SCB.pconp &= ~( 1u << index );
0113       }
0114 
0115       rtems_interrupt_enable( level );
0116     }
0117 
0118     /* else implies that the module has not power. Also,
0119        there is nothing to do. */
0120 
0121     status_code = RTEMS_SUCCESSFUL;
0122   }
0123 
0124   /* else implies an invalid index number. Also, the function
0125      does not return successful. */
0126 
0127   return status_code;
0128 }
0129 
0130 /**
0131  * @brief Sets the correct value according to the specific peripheral clock.
0132  *
0133  * @param  is_first_pclksel Represents the first pclksel.
0134  * @param  clock The clock to set for this module.
0135  * @param  clock_shift Value to clock shift.
0136  */
0137 static inline void set_pclksel_value(
0138   const uint32_t             pclksel,
0139   const lpc176x_module_clock clock,
0140   const unsigned             clock_shift
0141 )
0142 {
0143   assert( pclksel < LPC176X_SCB_PCLKSEL_COUNT );
0144   const uint32_t setclock = ( clock << clock_shift );
0145   const uint32_t mask = ~( LPC176X_MODULE_CLOCK_MASK << clock_shift );
0146   LPC176X_SCB.pclksel[ pclksel ] = ( LPC176X_SCB.pclksel[ pclksel ] & mask ) |
0147                                    setclock;
0148 }
0149 
0150 /**
0151  * @brief Checks if the module has clock.
0152  *
0153  * @param has_clock Clock.
0154  * @param index Index to shift.
0155  * @param clock The clock to set for this module.
0156  * @param level Interrupts value.
0157  */
0158 static rtems_status_code check_clock(
0159   const bool                 has_clock,
0160   const unsigned             index,
0161   const lpc176x_module_clock clock,
0162   rtems_interrupt_level      level
0163 )
0164 {
0165   rtems_status_code status_code = RTEMS_INVALID_NUMBER;
0166 
0167   if ( index <= LPC176X_MODULE_BITS_COUNT ) {
0168     if ( has_clock ) {
0169       unsigned clock_shift = 2u * index;
0170       rtems_interrupt_disable( level );
0171 
0172       if ( clock_shift < LPC176X_MODULE_BITS_COUNT ) {
0173         /* Sets the pclksel 0. */
0174         set_pclksel_value( LPC176X_SCB_PCLKSEL0, clock, clock_shift );
0175       } else {
0176         /* Sets the pclksel 1. */
0177         clock_shift -= LPC176X_MODULE_BITS_COUNT;
0178         set_pclksel_value( LPC176X_SCB_PCLKSEL1, clock, clock_shift );
0179       }
0180 
0181       rtems_interrupt_enable( level );
0182     }
0183 
0184     /* else implies that the module has not clock. Also,
0185        there is nothing to do. */
0186 
0187     status_code = RTEMS_SUCCESSFUL;
0188   }
0189 
0190   /* else implies an invalid index number. Also, the function
0191      does not return successful. */
0192 
0193   return status_code;
0194 }
0195 
0196 /**
0197  * @brief Checks the usb module.
0198  *
0199  * @return RTEMS_SUCCESFUL if the usb module is correct.
0200  */
0201 static rtems_status_code check_usb_module( void )
0202 {
0203   rtems_status_code status_code = RTEMS_INCORRECT_STATE;
0204   const uint32_t    pllclk = lpc176x_pllclk();
0205   const uint32_t    usbclk = LPC176X_USB_CLOCK;
0206 
0207   if ( pllclk % usbclk == 0u ) {
0208     const uint32_t usbdiv = pllclk / usbclk;
0209 
0210     LPC176X_SCB.usbclksel = LPC176X_SCB_USBCLKSEL_USBDIV( usbdiv ) |
0211                             LPC176X_SCB_USBCLKSEL_USBSEL( 1 );
0212     status_code = RTEMS_SUCCESSFUL;
0213   }
0214 
0215   /* else implies that the module has an incorrect pllclk or usbclk value.
0216       Also, there is nothing to do. */
0217 
0218   return status_code;
0219 }
0220 
0221 /**
0222  * @brief Enables the current module.
0223  *
0224  * @param  module  Current module to enable/disable.
0225  * @param  clock The clock to set for this module.
0226  * @param enable TRUE if the module is enable.
0227  * @return RTEMS_SUCCESSFULL if the module was enabled successfully.
0228  */
0229 static rtems_status_code enable_disable_module(
0230   const lpc176x_module       module,
0231   const lpc176x_module_clock clock,
0232   const bool                 enable
0233 )
0234 {
0235   rtems_status_code     status_code;
0236   rtems_interrupt_level level = 0u;
0237 
0238   const bool     has_power = lpc176x_module_table[ module ].power;
0239   const bool     has_clock = lpc176x_module_table[ module ].clock;
0240   const unsigned index = lpc176x_module_table[ module ].index;
0241 
0242   assert( index <= LPC176X_MODULE_BITS_COUNT );
0243 
0244   /* Enable or disable module */
0245   if ( enable ) {
0246     status_code = check_power( has_power, index, true, level );
0247     RTEMS_CHECK_SC( status_code,
0248       "Checking index shift to turn on power of the module." );
0249 
0250     if ( module != LPC176X_MODULE_USB ) {
0251       status_code = check_clock( has_clock, index, clock, level );
0252       RTEMS_CHECK_SC( status_code,
0253         "Checking index shift to set pclksel to the current module." );
0254     } else {
0255       status_code = check_usb_module();
0256       RTEMS_CHECK_SC( status_code,
0257         "Checking pll clock to set usb clock to the current module." );
0258     }
0259   } else {
0260     status_code = check_power( has_power, index, false, level );
0261     RTEMS_CHECK_SC( status_code,
0262       "Checking index shift to turn off power of the module." );
0263   }
0264 
0265   return status_code;
0266 }
0267 
0268 /**
0269  * @brief Enables the module power and clock.
0270  *
0271  * @param  module Device to enable.
0272  * @param  clock  The clock to set for this module.
0273  * @param  enable Enable or disable the module.
0274  * @return RTEMS_SUCCESSFULL if the module was enabled succesfully.
0275  */
0276 static rtems_status_code lpc176x_module_do_enable(
0277   const lpc176x_module module,
0278   lpc176x_module_clock clock,
0279   const bool           enable
0280 )
0281 {
0282   rtems_status_code status_code = RTEMS_SUCCESSFUL;
0283 
0284   if ( (unsigned) module >= LPC176X_MODULE_COUNT ) {
0285     return RTEMS_INVALID_ID;
0286   }
0287 
0288   /* else implies that the module has a correct value. Also,
0289      there is nothing to do. */
0290 
0291   if ( clock == LPC176X_MODULE_PCLK_DEFAULT ) {
0292 #if ( LPC176X_PCLKDIV == 1u )
0293     clock = LPC176X_MODULE_CCLK;
0294 #elif ( LPC176X_PCLKDIV == 2u )
0295     clock = LPC176X_MODULE_CCLK_2;
0296 #elif ( LPC176X_PCLKDIV == 4u )
0297     clock = LPC176X_MODULE_CCLK_4;
0298 #elif ( LPC176X_PCLKDIV == 8u )
0299     clock = LPC176X_MODULE_CCLK_8;
0300 #else
0301 #error "Unexpected clock divisor."
0302 #endif
0303   }
0304 
0305   /* else implies that the clock has a correct divisor. */
0306 
0307   if ( ( clock & ~LPC176X_MODULE_CLOCK_MASK ) == 0u ) {
0308     status_code = enable_disable_module( module, clock, enable );
0309     RTEMS_CHECK_SC( status_code, "Checking the module to enable/disable." );
0310   } else {
0311     status_code = RTEMS_INVALID_CLOCK;
0312   }
0313 
0314   return status_code;
0315 }
0316 
0317 inline rtems_status_code lpc176x_module_enable(
0318   const lpc176x_module module,
0319   lpc176x_module_clock clock
0320 )
0321 {
0322   return lpc176x_module_do_enable( module, clock, true );
0323 }
0324 
0325 inline rtems_status_code lpc176x_module_disable( const lpc176x_module module )
0326 {
0327   return lpc176x_module_do_enable( module,
0328     LPC176X_MODULE_PCLK_DEFAULT,
0329     false );
0330 }
0331 
0332 bool lpc176x_module_is_enabled( const lpc176x_module module )
0333 {
0334   assert( (unsigned) module < LPC176X_MODULE_COUNT );
0335 
0336   const bool has_power = lpc176x_module_table[ module ].power;
0337   bool       enabled;
0338 
0339   if ( has_power ) {
0340     const unsigned index = lpc176x_module_table[ module ].index;
0341     const uint32_t pconp = LPC176X_SCB.pconp;
0342 
0343     enabled = ( pconp & ( 1u << index ) ) != 0u;
0344   } else {
0345     enabled = true;
0346   }
0347 
0348   return enabled;
0349 }