Back to home page

LXR

 
 

    


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

0001 /* SPDX-License-Identifier: BSD-2-Clause */
0002 
0003 /**
0004  * @file
0005  *
0006  * @ingroup RTEMSBSPsARMLPC24XX_io
0007  *
0008  * @brief Input and output module.
0009  */
0010 
0011 /*
0012  * Copyright (C) 2009, 2012 embedded brains GmbH & Co. KG
0013  *
0014  * Redistribution and use in source and binary forms, with or without
0015  * modification, are permitted provided that the following conditions
0016  * are met:
0017  * 1. Redistributions of source code must retain the above copyright
0018  *    notice, this list of conditions and the following disclaimer.
0019  * 2. Redistributions in binary form must reproduce the above copyright
0020  *    notice, this list of conditions and the following disclaimer in the
0021  *    documentation and/or other materials provided with the distribution.
0022  *
0023  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
0024  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
0025  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
0026  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
0027  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
0028  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
0029  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
0030  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
0031  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
0032  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
0033  * POSSIBILITY OF SUCH DAMAGE.
0034  */
0035 
0036 #include <bsp.h>
0037 #include <bsp/io.h>
0038 #include <bsp/start.h>
0039 #include <bsp/system-clocks.h>
0040 
0041 #define LPC24XX_PIN_SELECT(index) ((index) >> 4U)
0042 
0043 #define LPC24XX_PIN_SELECT_SHIFT(index) (((index) & 0xfU) << 1U)
0044 
0045 #define LPC24XX_PIN_SELECT_MASK 0x3U
0046 
0047 rtems_status_code lpc24xx_gpio_config(
0048   unsigned index,
0049   lpc24xx_gpio_settings settings
0050 )
0051 {
0052   if (index <= LPC24XX_IO_INDEX_MAX) {
0053     rtems_interrupt_level level;
0054     uint32_t port = LPC24XX_IO_PORT(index);
0055     uint32_t port_bit = LPC24XX_IO_PORT_BIT(index);
0056     uint32_t output = (settings & LPC24XX_GPIO_OUTPUT) != 0 ? 1U : 0U;
0057     uint32_t resistor = settings & 0x3U;
0058     #ifdef ARM_MULTILIB_ARCH_V4
0059       uint32_t select = LPC24XX_PIN_SELECT(index);
0060       uint32_t shift = LPC24XX_PIN_SELECT_SHIFT(index);
0061 
0062       /* Get resistor flags */
0063       switch (resistor) {
0064         case LPC24XX_GPIO_RESISTOR_PULL_UP:
0065           resistor = 0x0U;
0066           break;
0067         case LPC24XX_GPIO_RESISTOR_NONE:
0068           resistor = 0x2U;
0069           break;
0070         case LPC24XX_GPIO_RESISTOR_PULL_DOWN:
0071           resistor = 0x3U;
0072           break;
0073         default:
0074           return RTEMS_INVALID_NUMBER;
0075       }
0076     #else
0077       uint32_t iocon_mask = IOCON_HYS | IOCON_INV
0078         | IOCON_SLEW | IOCON_OD | IOCON_FILTER;
0079       uint32_t iocon = (settings & iocon_mask) | IOCON_ADMODE;
0080       uint32_t iocon_invalid = settings & ~(iocon_mask | LPC24XX_GPIO_OUTPUT);
0081 
0082       /* Get resistor flags */
0083       switch (resistor) {
0084         case LPC24XX_GPIO_RESISTOR_NONE:
0085           resistor = IOCON_MODE(0);
0086           break;
0087         case LPC24XX_GPIO_RESISTOR_PULL_DOWN:
0088           resistor = IOCON_MODE(1);
0089           break;
0090         case LPC24XX_GPIO_RESISTOR_PULL_UP:
0091           resistor = IOCON_MODE(2);
0092           break;
0093         case LPC17XX_GPIO_HYSTERESIS:
0094           resistor = IOCON_MODE(3);
0095           break;
0096       }
0097       iocon |= resistor;
0098 
0099       if (iocon_invalid != 0) {
0100         return RTEMS_INVALID_NUMBER;
0101       }
0102 
0103       if (output && (settings & LPC17XX_GPIO_INPUT_INVERT) != 0) {
0104         return RTEMS_INVALID_NUMBER;
0105       }
0106 
0107       if ((settings & LPC17XX_GPIO_INPUT_FILTER) == 0) {
0108         iocon |= IOCON_FILTER;
0109       } else {
0110         iocon &= ~IOCON_FILTER;
0111       }
0112     #endif
0113 
0114     rtems_interrupt_disable(level);
0115 
0116     #ifdef ARM_MULTILIB_ARCH_V4
0117       /* Resistor */
0118       LPC24XX_PINMODE [select] =
0119         (LPC24XX_PINMODE [select] & ~(LPC24XX_PIN_SELECT_MASK << shift))
0120           | ((resistor & LPC24XX_PIN_SELECT_MASK) << shift);
0121     #else
0122       LPC17XX_IOCON [index] = iocon;
0123     #endif
0124 
0125     rtems_interrupt_flash(level);
0126 
0127     /* Input or output */
0128     LPC24XX_FIO [port].dir =
0129       (LPC24XX_FIO [port].dir & ~(1U << port_bit)) | (output << port_bit);
0130 
0131     rtems_interrupt_enable(level);
0132   } else {
0133     return RTEMS_INVALID_ID;
0134   }
0135 
0136   return RTEMS_SUCCESSFUL;
0137 }
0138 
0139 #define LPC24XX_MODULE_ENTRY(mod, pwr, clk, idx) \
0140   [mod] = { \
0141     .power = pwr, \
0142     .clock = clk, \
0143     .index = idx \
0144   }
0145 
0146 typedef struct {
0147   unsigned char power : 1;
0148   unsigned char clock : 1;
0149   unsigned char index : 6;
0150 } lpc24xx_module_entry;
0151 
0152 static const lpc24xx_module_entry lpc24xx_module_table [] = {
0153   #ifdef ARM_MULTILIB_ARCH_V4
0154     LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_ACF, 0, 1, 15),
0155   #endif
0156   LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_ADC, 1, 1, 12),
0157   #ifdef ARM_MULTILIB_ARCH_V4
0158     LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_BAT_RAM, 0, 1, 16),
0159   #endif
0160   LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_CAN_0, 1, 1, 13),
0161   LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_CAN_1, 1, 1, 14),
0162   LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_DAC, 0, 1, 11),
0163   LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_EMC, 1, 0, 11),
0164   LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_ETHERNET, 1, 0, 30),
0165   LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_GPDMA, 1, 1, 29),
0166   #ifdef ARM_MULTILIB_ARCH_V4
0167     LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_GPIO, 0, 1, 17),
0168   #else
0169     LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_GPIO, 0, 1, 15),
0170   #endif
0171   LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_I2C_0, 1, 1, 7),
0172   LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_I2C_1, 1, 1, 19),
0173   LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_I2C_2, 1, 1, 26),
0174   LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_I2S, 1, 1, 27),
0175   #ifdef ARM_MULTILIB_ARCH_V4
0176     LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_LCD, 1, 0, 20),
0177   #else
0178     LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_LCD, 1, 0, 0),
0179   #endif
0180   LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_MCI, 1, 1, 28),
0181   #ifdef ARM_MULTILIB_ARCH_V7M
0182     LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_MCPWM, 1, 1, 17),
0183   #endif
0184   LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_PCB, 0, 1, 18),
0185   LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_PWM_0, 1, 1, 5),
0186   LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_PWM_1, 1, 1, 6),
0187   #ifdef ARM_MULTILIB_ARCH_V7M
0188     LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_QEI, 1, 1, 18),
0189   #endif
0190   LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_RTC, 1, 1, 9),
0191   #ifdef ARM_MULTILIB_ARCH_V4
0192     LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_SPI, 1, 1, 8),
0193   #endif
0194   LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_SSP_0, 1, 1, 21),
0195   LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_SSP_1, 1, 1, 10),
0196   #ifdef ARM_MULTILIB_ARCH_V7M
0197     LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_SSP_2, 1, 1, 20),
0198   #endif
0199   LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_SYSCON, 0, 1, 30),
0200   LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_TIMER_0, 1, 1, 1),
0201   LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_TIMER_1, 1, 1, 2),
0202   LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_TIMER_2, 1, 1, 22),
0203   LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_TIMER_3, 1, 1, 23),
0204   LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_UART_0, 1, 1, 3),
0205   LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_UART_1, 1, 1, 4),
0206   LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_UART_2, 1, 1, 24),
0207   LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_UART_3, 1, 1, 25),
0208   #ifdef ARM_MULTILIB_ARCH_V7M
0209     LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_UART_4, 1, 1, 8),
0210   #endif
0211   #ifdef ARM_MULTILIB_ARCH_V4
0212     LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_WDT, 0, 1, 0),
0213   #endif
0214   LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_USB, 1, 0, 31)
0215 };
0216 
0217 static rtems_status_code lpc24xx_module_do_enable(
0218   lpc24xx_module module,
0219   lpc24xx_module_clock clock,
0220   bool enable
0221 )
0222 {
0223   rtems_interrupt_level level;
0224   bool has_power = false;
0225   bool has_clock = false;
0226   unsigned index = 0;
0227   #ifdef ARM_MULTILIB_ARCH_V7M
0228     volatile lpc17xx_scb *scb = &LPC17XX_SCB;
0229   #endif
0230 
0231   if ((unsigned) module >= LPC24XX_MODULE_COUNT) {
0232       return RTEMS_INVALID_ID;
0233   }
0234 
0235   #ifdef ARM_MULTILIB_ARCH_V4
0236     if (clock == LPC24XX_MODULE_PCLK_DEFAULT) {
0237       #if LPC24XX_PCLKDIV == 1U
0238         clock = LPC24XX_MODULE_CCLK;
0239       #elif LPC24XX_PCLKDIV == 2U
0240         clock = LPC24XX_MODULE_CCLK_2;
0241       #elif LPC24XX_PCLKDIV == 4U
0242         clock = LPC24XX_MODULE_CCLK_4;
0243       #elif LPC24XX_PCLKDIV == 8U
0244         clock = LPC24XX_MODULE_CCLK_8;
0245       #endif
0246     }
0247 
0248     if ((clock & ~LPC24XX_MODULE_CLOCK_MASK) != 0U) {
0249       return RTEMS_INVALID_CLOCK;
0250     }
0251   #else
0252     if (clock != LPC24XX_MODULE_PCLK_DEFAULT) {
0253       return RTEMS_INVALID_CLOCK;
0254     }
0255   #endif
0256 
0257   has_power = lpc24xx_module_table [module].power;
0258   has_clock = lpc24xx_module_table [module].clock;
0259   index = lpc24xx_module_table [module].index;
0260 
0261   /* Enable or disable module */
0262   if (enable) {
0263     if (has_power) {
0264       rtems_interrupt_disable(level);
0265       #ifdef ARM_MULTILIB_ARCH_V4
0266         PCONP |= 1U << index;
0267       #else
0268         scb->pconp |= 1U << index;
0269       #endif
0270       rtems_interrupt_enable(level);
0271     }
0272 
0273     if (module != LPC24XX_MODULE_USB) {
0274       if (has_clock) {
0275         #ifdef ARM_MULTILIB_ARCH_V4
0276           unsigned clock_shift = 2U * index;
0277 
0278           rtems_interrupt_disable(level);
0279           if (clock_shift < 32U) {
0280             PCLKSEL0 = (PCLKSEL0 & ~(LPC24XX_MODULE_CLOCK_MASK << clock_shift))
0281                 | (clock << clock_shift);
0282           } else {
0283             clock_shift -= 32U;
0284             PCLKSEL1 = (PCLKSEL1 & ~(LPC24XX_MODULE_CLOCK_MASK << clock_shift))
0285                 | (clock << clock_shift);
0286           }
0287           rtems_interrupt_enable(level);
0288         #endif
0289       }
0290     } else {
0291       #ifdef ARM_MULTILIB_ARCH_V4
0292         unsigned pllclk = lpc24xx_pllclk();
0293         unsigned usbsel = pllclk / 48000000U - 1U;
0294 
0295         if (
0296           usbsel > 15U
0297             || (usbsel % 2U != 1U)
0298             || (pllclk % 48000000U) != 0U
0299         ) {
0300           return RTEMS_INCORRECT_STATE;
0301         }
0302 
0303         USBCLKCFG = usbsel;
0304       #else
0305         uint32_t pllclk = lpc24xx_pllclk();
0306         uint32_t usbclk = 48000000U;
0307 
0308         if (pllclk % usbclk == 0U) {
0309           uint32_t usbdiv = pllclk / usbclk;
0310 
0311           scb->usbclksel = LPC17XX_SCB_USBCLKSEL_USBDIV(usbdiv)
0312             | LPC17XX_SCB_USBCLKSEL_USBSEL(1);
0313         } else {
0314           return RTEMS_INCORRECT_STATE;
0315         }
0316       #endif
0317     }
0318   } else {
0319     if (has_power) {
0320       rtems_interrupt_disable(level);
0321       #ifdef ARM_MULTILIB_ARCH_V4
0322         PCONP &= ~(1U << index);
0323       #else
0324         scb->pconp &= ~(1U << index);
0325       #endif
0326       rtems_interrupt_enable(level);
0327     }
0328   }
0329 
0330   return RTEMS_SUCCESSFUL;
0331 }
0332 
0333 rtems_status_code lpc24xx_module_enable(
0334   lpc24xx_module module,
0335   lpc24xx_module_clock clock
0336 )
0337 {
0338   return lpc24xx_module_do_enable(module, clock, true);
0339 }
0340 
0341 rtems_status_code lpc24xx_module_disable(
0342   lpc24xx_module module
0343 )
0344 {
0345   return lpc24xx_module_do_enable(
0346     module,
0347     LPC24XX_MODULE_PCLK_DEFAULT,
0348     false
0349   );
0350 }
0351 
0352 bool lpc24xx_module_is_enabled(lpc24xx_module module)
0353 {
0354   bool enabled = false;
0355 
0356   if ((unsigned) module < LPC24XX_MODULE_COUNT) {
0357     bool has_power = lpc24xx_module_table [module].power;
0358 
0359     if (has_power) {
0360       unsigned index = lpc24xx_module_table [module].index;
0361       #ifdef ARM_MULTILIB_ARCH_V4
0362         uint32_t pconp = PCONP;
0363       #else
0364         uint32_t pconp = LPC17XX_SCB.pconp;
0365       #endif
0366 
0367       enabled = (pconp & (1U << index)) != 0;
0368     } else {
0369       enabled = true;
0370     }
0371   }
0372 
0373   return enabled;
0374 }
0375 
0376 typedef rtems_status_code (*lpc24xx_pin_visitor)(
0377   #ifdef ARM_MULTILIB_ARCH_V4
0378     volatile uint32_t *pinsel,
0379     uint32_t pinsel_mask,
0380     uint32_t pinsel_value,
0381   #else
0382     volatile uint32_t *iocon,
0383     lpc24xx_pin_range pin_range,
0384   #endif
0385   volatile uint32_t *fio_dir,
0386   uint32_t fio_bit
0387 );
0388 
0389 static BSP_START_TEXT_SECTION __attribute__((flatten)) rtems_status_code
0390 lpc24xx_pin_set_function(
0391   #ifdef ARM_MULTILIB_ARCH_V4
0392     volatile uint32_t *pinsel,
0393     uint32_t pinsel_mask,
0394     uint32_t pinsel_value,
0395   #else
0396     volatile uint32_t *iocon,
0397     lpc24xx_pin_range pin_range,
0398   #endif
0399   volatile uint32_t *fio_dir,
0400   uint32_t fio_bit
0401 )
0402 {
0403   #ifdef ARM_MULTILIB_ARCH_V4
0404     rtems_interrupt_level level;
0405 
0406     rtems_interrupt_disable(level);
0407     *pinsel = (*pinsel & ~pinsel_mask) | pinsel_value;
0408     rtems_interrupt_enable(level);
0409   #else
0410     uint32_t iocon_extra = 0;
0411     uint32_t iocon_not_analog = IOCON_ADMODE;
0412 
0413     /* TODO */
0414     switch (pin_range.fields.type) {
0415       case LPC17XX_PIN_TYPE_ADC:
0416       case LPC17XX_PIN_TYPE_DAC:
0417         iocon_not_analog = 0;
0418         break;
0419       case LPC17XX_PIN_TYPE_I2C_FAST_PLUS:
0420         iocon_extra |= IOCON_HS;
0421         break;
0422       case LPC17XX_PIN_TYPE_OPEN_DRAIN:
0423         iocon_extra |= IOCON_OD;
0424         break;
0425       case LPC17XX_PIN_TYPE_FAST_SLEW_RATE:
0426         iocon_extra |= IOCON_SLEW;
0427         break;
0428       default:
0429         break;
0430     }
0431 
0432     *iocon = IOCON_FUNC(pin_range.fields.function) | iocon_extra | iocon_not_analog;
0433   #endif
0434 
0435   return RTEMS_SUCCESSFUL;
0436 }
0437 
0438 static BSP_START_TEXT_SECTION rtems_status_code lpc24xx_pin_check_function(
0439   #ifdef ARM_MULTILIB_ARCH_V4
0440     volatile uint32_t *pinsel,
0441     uint32_t pinsel_mask,
0442     uint32_t pinsel_value,
0443   #else
0444     volatile uint32_t *iocon,
0445     lpc24xx_pin_range pin_range,
0446   #endif
0447   volatile uint32_t *fio_dir,
0448   uint32_t fio_bit
0449 )
0450 {
0451   #ifdef ARM_MULTILIB_ARCH_V4
0452     if ((*pinsel & pinsel_mask) == pinsel_value) {
0453       return RTEMS_SUCCESSFUL;
0454     } else {
0455       return RTEMS_IO_ERROR;
0456     }
0457   #else
0458     /* TODO */
0459     return RTEMS_IO_ERROR;
0460   #endif
0461 }
0462 
0463 static BSP_START_TEXT_SECTION __attribute__((flatten)) rtems_status_code
0464 lpc24xx_pin_set_input(
0465   #ifdef ARM_MULTILIB_ARCH_V4
0466     volatile uint32_t *pinsel,
0467     uint32_t pinsel_mask,
0468     uint32_t pinsel_value,
0469   #else
0470     volatile uint32_t *iocon,
0471     lpc24xx_pin_range pin_range,
0472   #endif
0473   volatile uint32_t *fio_dir,
0474   uint32_t fio_bit
0475 )
0476 {
0477   rtems_interrupt_level level;
0478 
0479   rtems_interrupt_disable(level);
0480   *fio_dir &= ~fio_bit;
0481   #ifdef ARM_MULTILIB_ARCH_V4
0482     *pinsel &= ~pinsel_mask;
0483   #else
0484     *iocon = IOCON_MODE(2) | IOCON_ADMODE | IOCON_FILTER;
0485   #endif
0486   rtems_interrupt_enable(level);
0487 
0488   return RTEMS_SUCCESSFUL;
0489 }
0490 
0491 static BSP_START_TEXT_SECTION rtems_status_code lpc24xx_pin_check_input(
0492   #ifdef ARM_MULTILIB_ARCH_V4
0493     volatile uint32_t *pinsel,
0494     uint32_t pinsel_mask,
0495     uint32_t pinsel_value,
0496   #else
0497     volatile uint32_t *iocon,
0498     lpc24xx_pin_range pin_range,
0499   #endif
0500   volatile uint32_t *fio_dir,
0501   uint32_t fio_bit
0502 )
0503 {
0504   rtems_status_code sc = RTEMS_IO_ERROR;
0505   bool is_input = (*fio_dir & fio_bit) == 0;
0506 
0507   if (is_input) {
0508     #ifdef ARM_MULTILIB_ARCH_V4
0509       bool is_gpio = (*pinsel & pinsel_mask) == 0;
0510     #else
0511       bool is_gpio = IOCON_FUNC_GET(*iocon) == 0;
0512     #endif
0513 
0514     if (is_gpio) {
0515       sc = RTEMS_SUCCESSFUL;
0516     }
0517   }
0518 
0519   return sc;
0520 }
0521 
0522 static BSP_START_DATA_SECTION const lpc24xx_pin_visitor
0523   lpc24xx_pin_visitors [] = {
0524   [LPC24XX_PIN_SET_FUNCTION] = lpc24xx_pin_set_function,
0525   [LPC24XX_PIN_CHECK_FUNCTION] = lpc24xx_pin_check_function,
0526   [LPC24XX_PIN_SET_INPUT] = lpc24xx_pin_set_input,
0527   [LPC24XX_PIN_CHECK_INPUT] = lpc24xx_pin_check_input
0528 };
0529 
0530 BSP_START_TEXT_SECTION rtems_status_code lpc24xx_pin_config(
0531   const lpc24xx_pin_range *pins,
0532   lpc24xx_pin_action action
0533 )
0534 {
0535   rtems_status_code sc = RTEMS_SUCCESSFUL;
0536 
0537   if ((unsigned) action <= LPC24XX_PIN_CHECK_INPUT) {
0538     lpc24xx_pin_visitor visitor = lpc24xx_pin_visitors [action];
0539     lpc24xx_pin_range terminal = LPC24XX_PIN_TERMINAL;
0540     lpc24xx_pin_range pin_range = *pins;
0541     uint32_t previous_port_bit = pin_range.fields.port_bit;
0542 
0543     while (sc == RTEMS_SUCCESSFUL && pin_range.value != terminal.value) {
0544       uint32_t port = pin_range.fields.port;
0545       uint32_t port_bit = pin_range.fields.port_bit;
0546       uint32_t port_bit_last = port_bit;
0547       uint32_t range = pin_range.fields.range;
0548       #ifdef ARM_MULTILIB_ARCH_V4
0549         uint32_t function = pin_range.fields.function;
0550       #endif
0551       volatile uint32_t *fio_dir = &LPC24XX_FIO [port].dir;
0552 
0553       if (range) {
0554         port_bit = previous_port_bit;
0555       }
0556 
0557       while (sc == RTEMS_SUCCESSFUL && port_bit <= port_bit_last) {
0558         uint32_t index = LPC24XX_IO_INDEX_BY_PORT(port, port_bit);
0559         uint32_t fio_bit = 1U << port_bit;
0560         #ifdef ARM_MULTILIB_ARCH_V4
0561           uint32_t select = LPC24XX_PIN_SELECT(index);
0562           uint32_t shift = LPC24XX_PIN_SELECT_SHIFT(index);
0563           volatile uint32_t *pinsel = &LPC24XX_PINSEL [select];
0564           uint32_t pinsel_mask = LPC24XX_PIN_SELECT_MASK << shift;
0565           uint32_t pinsel_value = (function & LPC24XX_PIN_SELECT_MASK) << shift;
0566 
0567           sc = (*visitor)(pinsel, pinsel_mask, pinsel_value, fio_dir, fio_bit);
0568         #else
0569           volatile uint32_t *iocon = &LPC17XX_IOCON [index];
0570 
0571           sc = (*visitor)(iocon, pin_range, fio_dir, fio_bit);
0572         #endif
0573 
0574         ++port_bit;
0575       }
0576 
0577       ++pins;
0578       previous_port_bit = port_bit;
0579       pin_range = *pins;
0580     }
0581   } else {
0582     sc = RTEMS_NOT_DEFINED;
0583   }
0584 
0585   return sc;
0586 }