source: rtems/bsps/arm/lpc24xx/start/io.c @ 0a6b81a

Last change on this file since 0a6b81a was 0a6b81a, checked in by Sebastian Huber <sebastian.huber@…>, on May 9, 2019 at 7:53:55 AM

bsp/lpc24xx: Add LPC17XX_PIN_TYPE_FAST_SLEW_RATE

  • Property mode set to 100644
File size: 15.2 KB
Line 
1/**
2 * @file
3 *
4 * @ingroup RTEMSBSPsARMLPC24XX_io
5 *
6 * @brief Input and output module.
7 */
8
9/*
10 * Copyright (c) 2009-2012 embedded brains GmbH.  All rights reserved.
11 *
12 *  embedded brains GmbH
13 *  Obere Lagerstr. 30
14 *  82178 Puchheim
15 *  Germany
16 *  <rtems@embedded-brains.de>
17 *
18 * The license and distribution terms for this file may be
19 * found in the file LICENSE in this distribution or at
20 * http://www.rtems.org/license/LICENSE.
21 */
22
23#include <bsp.h>
24#include <bsp/io.h>
25#include <bsp/start.h>
26#include <bsp/system-clocks.h>
27
28#define LPC24XX_PIN_SELECT(index) ((index) >> 4U)
29
30#define LPC24XX_PIN_SELECT_SHIFT(index) (((index) & 0xfU) << 1U)
31
32#define LPC24XX_PIN_SELECT_MASK 0x3U
33
34rtems_status_code lpc24xx_gpio_config(
35  unsigned index,
36  lpc24xx_gpio_settings settings
37)
38{
39  if (index <= LPC24XX_IO_INDEX_MAX) {
40    rtems_interrupt_level level;
41    uint32_t port = LPC24XX_IO_PORT(index);
42    uint32_t port_bit = LPC24XX_IO_PORT_BIT(index);
43    uint32_t output = (settings & LPC24XX_GPIO_OUTPUT) != 0 ? 1U : 0U;
44    uint32_t resistor = settings & 0x3U;
45    #ifdef ARM_MULTILIB_ARCH_V4
46      uint32_t select = LPC24XX_PIN_SELECT(index);
47      uint32_t shift = LPC24XX_PIN_SELECT_SHIFT(index);
48
49      /* Get resistor flags */
50      switch (resistor) {
51        case LPC24XX_GPIO_RESISTOR_PULL_UP:
52          resistor = 0x0U;
53          break;
54        case LPC24XX_GPIO_RESISTOR_NONE:
55          resistor = 0x2U;
56          break;
57        case LPC24XX_GPIO_RESISTOR_PULL_DOWN:
58          resistor = 0x3U;
59          break;
60        default:
61          return RTEMS_INVALID_NUMBER;
62      }
63    #else
64      uint32_t iocon_mask = IOCON_HYS | IOCON_INV
65        | IOCON_SLEW | IOCON_OD | IOCON_FILTER;
66      uint32_t iocon = (settings & iocon_mask) | IOCON_ADMODE;
67      uint32_t iocon_invalid = settings & ~(iocon_mask | LPC24XX_GPIO_OUTPUT);
68
69      /* Get resistor flags */
70      switch (resistor) {
71        case LPC24XX_GPIO_RESISTOR_NONE:
72          resistor = IOCON_MODE(0);
73          break;
74        case LPC24XX_GPIO_RESISTOR_PULL_DOWN:
75          resistor = IOCON_MODE(1);
76          break;
77        case LPC24XX_GPIO_RESISTOR_PULL_UP:
78          resistor = IOCON_MODE(2);
79          break;
80        case LPC17XX_GPIO_HYSTERESIS:
81          resistor = IOCON_MODE(3);
82          break;
83      }
84      iocon |= resistor;
85
86      if (iocon_invalid != 0) {
87        return RTEMS_INVALID_NUMBER;
88      }
89
90      if (output && (settings & LPC17XX_GPIO_INPUT_INVERT) != 0) {
91        return RTEMS_INVALID_NUMBER;
92      }
93
94      if ((settings & LPC17XX_GPIO_INPUT_FILTER) == 0) {
95        iocon |= IOCON_FILTER;
96      } else {
97        iocon &= ~IOCON_FILTER;
98      }
99    #endif
100
101    rtems_interrupt_disable(level);
102
103    #ifdef ARM_MULTILIB_ARCH_V4
104      /* Resistor */
105      LPC24XX_PINMODE [select] =
106        (LPC24XX_PINMODE [select] & ~(LPC24XX_PIN_SELECT_MASK << shift))
107          | ((resistor & LPC24XX_PIN_SELECT_MASK) << shift);
108    #else
109      LPC17XX_IOCON [index] = iocon;
110    #endif
111
112    rtems_interrupt_flash(level);
113
114    /* Input or output */
115    LPC24XX_FIO [port].dir =
116      (LPC24XX_FIO [port].dir & ~(1U << port_bit)) | (output << port_bit);
117
118    rtems_interrupt_enable(level);
119  } else {
120    return RTEMS_INVALID_ID;
121  }
122
123  return RTEMS_SUCCESSFUL;
124}
125
126#define LPC24XX_MODULE_ENTRY(mod, pwr, clk, idx) \
127  [mod] = { \
128    .power = pwr, \
129    .clock = clk, \
130    .index = idx \
131  }
132
133typedef struct {
134  unsigned char power : 1;
135  unsigned char clock : 1;
136  unsigned char index : 6;
137} lpc24xx_module_entry;
138
139static const lpc24xx_module_entry lpc24xx_module_table [] = {
140  #ifdef ARM_MULTILIB_ARCH_V4
141    LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_ACF, 0, 1, 15),
142  #endif
143  LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_ADC, 1, 1, 12),
144  #ifdef ARM_MULTILIB_ARCH_V4
145    LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_BAT_RAM, 0, 1, 16),
146  #endif
147  LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_CAN_0, 1, 1, 13),
148  LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_CAN_1, 1, 1, 14),
149  LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_DAC, 0, 1, 11),
150  LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_EMC, 1, 0, 11),
151  LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_ETHERNET, 1, 0, 30),
152  LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_GPDMA, 1, 1, 29),
153  #ifdef ARM_MULTILIB_ARCH_V4
154    LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_GPIO, 0, 1, 17),
155  #else
156    LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_GPIO, 0, 1, 15),
157  #endif
158  LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_I2C_0, 1, 1, 7),
159  LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_I2C_1, 1, 1, 19),
160  LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_I2C_2, 1, 1, 26),
161  LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_I2S, 1, 1, 27),
162  #ifdef ARM_MULTILIB_ARCH_V4
163    LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_LCD, 1, 0, 20),
164  #else
165    LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_LCD, 1, 0, 0),
166  #endif
167  LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_MCI, 1, 1, 28),
168  #ifdef ARM_MULTILIB_ARCH_V7M
169    LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_MCPWM, 1, 1, 17),
170  #endif
171  LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_PCB, 0, 1, 18),
172  LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_PWM_0, 1, 1, 5),
173  LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_PWM_1, 1, 1, 6),
174  #ifdef ARM_MULTILIB_ARCH_V7M
175    LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_QEI, 1, 1, 18),
176  #endif
177  LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_RTC, 1, 1, 9),
178  #ifdef ARM_MULTILIB_ARCH_V4
179    LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_SPI, 1, 1, 8),
180  #endif
181  LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_SSP_0, 1, 1, 21),
182  LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_SSP_1, 1, 1, 10),
183  #ifdef ARM_MULTILIB_ARCH_V7M
184    LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_SSP_2, 1, 1, 20),
185  #endif
186  LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_SYSCON, 0, 1, 30),
187  LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_TIMER_0, 1, 1, 1),
188  LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_TIMER_1, 1, 1, 2),
189  LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_TIMER_2, 1, 1, 22),
190  LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_TIMER_3, 1, 1, 23),
191  LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_UART_0, 1, 1, 3),
192  LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_UART_1, 1, 1, 4),
193  LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_UART_2, 1, 1, 24),
194  LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_UART_3, 1, 1, 25),
195  #ifdef ARM_MULTILIB_ARCH_V7M
196    LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_UART_4, 1, 1, 8),
197  #endif
198  #ifdef ARM_MULTILIB_ARCH_V4
199    LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_WDT, 0, 1, 0),
200  #endif
201  LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_USB, 1, 0, 31)
202};
203
204static rtems_status_code lpc24xx_module_do_enable(
205  lpc24xx_module module,
206  lpc24xx_module_clock clock,
207  bool enable
208)
209{
210  rtems_interrupt_level level;
211  bool has_power = false;
212  bool has_clock = false;
213  unsigned index = 0;
214  #ifdef ARM_MULTILIB_ARCH_V7M
215    volatile lpc17xx_scb *scb = &LPC17XX_SCB;
216  #endif
217
218  if ((unsigned) module >= LPC24XX_MODULE_COUNT) {
219      return RTEMS_INVALID_ID;
220  }
221
222  #ifdef ARM_MULTILIB_ARCH_V4
223    if (clock == LPC24XX_MODULE_PCLK_DEFAULT) {
224      #if LPC24XX_PCLKDIV == 1U
225        clock = LPC24XX_MODULE_CCLK;
226      #elif LPC24XX_PCLKDIV == 2U
227        clock = LPC24XX_MODULE_CCLK_2;
228      #elif LPC24XX_PCLKDIV == 4U
229        clock = LPC24XX_MODULE_CCLK_4;
230      #elif LPC24XX_PCLKDIV == 8U
231        clock = LPC24XX_MODULE_CCLK_8;
232      #endif
233    }
234
235    if ((clock & ~LPC24XX_MODULE_CLOCK_MASK) != 0U) {
236      return RTEMS_INVALID_CLOCK;
237    }
238  #else
239    if (clock != LPC24XX_MODULE_PCLK_DEFAULT) {
240      return RTEMS_INVALID_CLOCK;
241    }
242  #endif
243
244  has_power = lpc24xx_module_table [module].power;
245  has_clock = lpc24xx_module_table [module].clock;
246  index = lpc24xx_module_table [module].index;
247
248  /* Enable or disable module */
249  if (enable) {
250    if (has_power) {
251      rtems_interrupt_disable(level);
252      #ifdef ARM_MULTILIB_ARCH_V4
253        PCONP |= 1U << index;
254      #else
255        scb->pconp |= 1U << index;
256      #endif
257      rtems_interrupt_enable(level);
258    }
259
260    if (module != LPC24XX_MODULE_USB) {
261      if (has_clock) {
262        #ifdef ARM_MULTILIB_ARCH_V4
263          unsigned clock_shift = 2U * index;
264
265          rtems_interrupt_disable(level);
266          if (clock_shift < 32U) {
267            PCLKSEL0 = (PCLKSEL0 & ~(LPC24XX_MODULE_CLOCK_MASK << clock_shift))
268                | (clock << clock_shift);
269          } else {
270            clock_shift -= 32U;
271            PCLKSEL1 = (PCLKSEL1 & ~(LPC24XX_MODULE_CLOCK_MASK << clock_shift))
272                | (clock << clock_shift);
273          }
274          rtems_interrupt_enable(level);
275        #endif
276      }
277    } else {
278      #ifdef ARM_MULTILIB_ARCH_V4
279        unsigned pllclk = lpc24xx_pllclk();
280        unsigned usbsel = pllclk / 48000000U - 1U;
281
282        if (
283          usbsel > 15U
284            || (usbsel % 2U != 1U)
285            || (pllclk % 48000000U) != 0U
286        ) {
287          return RTEMS_INCORRECT_STATE;
288        }
289
290        USBCLKCFG = usbsel;
291      #else
292        uint32_t pllclk = lpc24xx_pllclk();
293        uint32_t usbclk = 48000000U;
294
295        if (pllclk % usbclk == 0U) {
296          uint32_t usbdiv = pllclk / usbclk;
297
298          scb->usbclksel = LPC17XX_SCB_USBCLKSEL_USBDIV(usbdiv)
299            | LPC17XX_SCB_USBCLKSEL_USBSEL(1);
300        } else {
301          return RTEMS_INCORRECT_STATE;
302        }
303      #endif
304    }
305  } else {
306    if (has_power) {
307      rtems_interrupt_disable(level);
308      #ifdef ARM_MULTILIB_ARCH_V4
309        PCONP &= ~(1U << index);
310      #else
311        scb->pconp &= ~(1U << index);
312      #endif
313      rtems_interrupt_enable(level);
314    }
315  }
316
317  return RTEMS_SUCCESSFUL;
318}
319
320rtems_status_code lpc24xx_module_enable(
321  lpc24xx_module module,
322  lpc24xx_module_clock clock
323)
324{
325  return lpc24xx_module_do_enable(module, clock, true);
326}
327
328rtems_status_code lpc24xx_module_disable(
329  lpc24xx_module module
330)
331{
332  return lpc24xx_module_do_enable(
333    module,
334    LPC24XX_MODULE_PCLK_DEFAULT,
335    false
336  );
337}
338
339bool lpc24xx_module_is_enabled(lpc24xx_module module)
340{
341  bool enabled = false;
342
343  if ((unsigned) module < LPC24XX_MODULE_COUNT) {
344    bool has_power = lpc24xx_module_table [module].power;
345
346    if (has_power) {
347      unsigned index = lpc24xx_module_table [module].index;
348      #ifdef ARM_MULTILIB_ARCH_V4
349        uint32_t pconp = PCONP;
350      #else
351        uint32_t pconp = LPC17XX_SCB.pconp;
352      #endif
353
354      enabled = (pconp & (1U << index)) != 0;
355    } else {
356      enabled = true;
357    }
358  }
359
360  return enabled;
361}
362
363typedef rtems_status_code (*lpc24xx_pin_visitor)(
364  #ifdef ARM_MULTILIB_ARCH_V4
365    volatile uint32_t *pinsel,
366    uint32_t pinsel_mask,
367    uint32_t pinsel_value,
368  #else
369    volatile uint32_t *iocon,
370    lpc24xx_pin_range pin_range,
371  #endif
372  volatile uint32_t *fio_dir,
373  uint32_t fio_bit
374);
375
376static BSP_START_TEXT_SECTION __attribute__((flatten)) rtems_status_code
377lpc24xx_pin_set_function(
378  #ifdef ARM_MULTILIB_ARCH_V4
379    volatile uint32_t *pinsel,
380    uint32_t pinsel_mask,
381    uint32_t pinsel_value,
382  #else
383    volatile uint32_t *iocon,
384    lpc24xx_pin_range pin_range,
385  #endif
386  volatile uint32_t *fio_dir,
387  uint32_t fio_bit
388)
389{
390  #ifdef ARM_MULTILIB_ARCH_V4
391    rtems_interrupt_level level;
392
393    rtems_interrupt_disable(level);
394    *pinsel = (*pinsel & ~pinsel_mask) | pinsel_value;
395    rtems_interrupt_enable(level);
396  #else
397    uint32_t iocon_extra = 0;
398    uint32_t iocon_not_analog = IOCON_ADMODE;
399
400    /* TODO */
401    switch (pin_range.fields.type) {
402      case LPC17XX_PIN_TYPE_ADC:
403      case LPC17XX_PIN_TYPE_DAC:
404        iocon_not_analog = 0;
405        break;
406      case LPC17XX_PIN_TYPE_I2C_FAST_PLUS:
407        iocon_extra |= IOCON_HS;
408        break;
409      case LPC17XX_PIN_TYPE_OPEN_DRAIN:
410        iocon_extra |= IOCON_OD;
411        break;
412      case LPC17XX_PIN_TYPE_FAST_SLEW_RATE:
413        iocon_extra |= IOCON_SLEW;
414        break;
415      default:
416        break;
417    }
418
419    *iocon = IOCON_FUNC(pin_range.fields.function) | iocon_extra | iocon_not_analog;
420  #endif
421
422  return RTEMS_SUCCESSFUL;
423}
424
425static BSP_START_TEXT_SECTION rtems_status_code lpc24xx_pin_check_function(
426  #ifdef ARM_MULTILIB_ARCH_V4
427    volatile uint32_t *pinsel,
428    uint32_t pinsel_mask,
429    uint32_t pinsel_value,
430  #else
431    volatile uint32_t *iocon,
432    lpc24xx_pin_range pin_range,
433  #endif
434  volatile uint32_t *fio_dir,
435  uint32_t fio_bit
436)
437{
438  #ifdef ARM_MULTILIB_ARCH_V4
439    if ((*pinsel & pinsel_mask) == pinsel_value) {
440      return RTEMS_SUCCESSFUL;
441    } else {
442      return RTEMS_IO_ERROR;
443    }
444  #else
445    /* TODO */
446    return RTEMS_IO_ERROR;
447  #endif
448}
449
450static BSP_START_TEXT_SECTION __attribute__((flatten)) rtems_status_code
451lpc24xx_pin_set_input(
452  #ifdef ARM_MULTILIB_ARCH_V4
453    volatile uint32_t *pinsel,
454    uint32_t pinsel_mask,
455    uint32_t pinsel_value,
456  #else
457    volatile uint32_t *iocon,
458    lpc24xx_pin_range pin_range,
459  #endif
460  volatile uint32_t *fio_dir,
461  uint32_t fio_bit
462)
463{
464  rtems_interrupt_level level;
465
466  rtems_interrupt_disable(level);
467  *fio_dir &= ~fio_bit;
468  #ifdef ARM_MULTILIB_ARCH_V4
469    *pinsel &= ~pinsel_mask;
470  #else
471    *iocon = IOCON_MODE(2) | IOCON_ADMODE | IOCON_FILTER;
472  #endif
473  rtems_interrupt_enable(level);
474
475  return RTEMS_SUCCESSFUL;
476}
477
478static BSP_START_TEXT_SECTION rtems_status_code lpc24xx_pin_check_input(
479  #ifdef ARM_MULTILIB_ARCH_V4
480    volatile uint32_t *pinsel,
481    uint32_t pinsel_mask,
482    uint32_t pinsel_value,
483  #else
484    volatile uint32_t *iocon,
485    lpc24xx_pin_range pin_range,
486  #endif
487  volatile uint32_t *fio_dir,
488  uint32_t fio_bit
489)
490{
491  rtems_status_code sc = RTEMS_IO_ERROR;
492  bool is_input = (*fio_dir & fio_bit) == 0;
493
494  if (is_input) {
495    #ifdef ARM_MULTILIB_ARCH_V4
496      bool is_gpio = (*pinsel & pinsel_mask) == 0;
497    #else
498      bool is_gpio = IOCON_FUNC_GET(*iocon) == 0;
499    #endif
500
501    if (is_gpio) {
502      sc = RTEMS_SUCCESSFUL;
503    }
504  }
505
506  return sc;
507}
508
509static BSP_START_DATA_SECTION const lpc24xx_pin_visitor
510  lpc24xx_pin_visitors [] = {
511  [LPC24XX_PIN_SET_FUNCTION] = lpc24xx_pin_set_function,
512  [LPC24XX_PIN_CHECK_FUNCTION] = lpc24xx_pin_check_function,
513  [LPC24XX_PIN_SET_INPUT] = lpc24xx_pin_set_input,
514  [LPC24XX_PIN_CHECK_INPUT] = lpc24xx_pin_check_input
515};
516
517BSP_START_TEXT_SECTION rtems_status_code lpc24xx_pin_config(
518  const lpc24xx_pin_range *pins,
519  lpc24xx_pin_action action
520)
521{
522  rtems_status_code sc = RTEMS_SUCCESSFUL;
523
524  if ((unsigned) action <= LPC24XX_PIN_CHECK_INPUT) {
525    lpc24xx_pin_visitor visitor = lpc24xx_pin_visitors [action];
526    lpc24xx_pin_range terminal = LPC24XX_PIN_TERMINAL;
527    lpc24xx_pin_range pin_range = *pins;
528    uint32_t previous_port_bit = pin_range.fields.port_bit;
529
530    while (sc == RTEMS_SUCCESSFUL && pin_range.value != terminal.value) {
531      uint32_t port = pin_range.fields.port;
532      uint32_t port_bit = pin_range.fields.port_bit;
533      uint32_t port_bit_last = port_bit;
534      uint32_t range = pin_range.fields.range;
535      #ifdef ARM_MULTILIB_ARCH_V4
536        uint32_t function = pin_range.fields.function;
537      #endif
538      volatile uint32_t *fio_dir = &LPC24XX_FIO [port].dir;
539
540      if (range) {
541        port_bit = previous_port_bit;
542      }
543
544      while (sc == RTEMS_SUCCESSFUL && port_bit <= port_bit_last) {
545        uint32_t index = LPC24XX_IO_INDEX_BY_PORT(port, port_bit);
546        uint32_t fio_bit = 1U << port_bit;
547        #ifdef ARM_MULTILIB_ARCH_V4
548          uint32_t select = LPC24XX_PIN_SELECT(index);
549          uint32_t shift = LPC24XX_PIN_SELECT_SHIFT(index);
550          volatile uint32_t *pinsel = &LPC24XX_PINSEL [select];
551          uint32_t pinsel_mask = LPC24XX_PIN_SELECT_MASK << shift;
552          uint32_t pinsel_value = (function & LPC24XX_PIN_SELECT_MASK) << shift;
553
554          sc = (*visitor)(pinsel, pinsel_mask, pinsel_value, fio_dir, fio_bit);
555        #else
556          volatile uint32_t *iocon = &LPC17XX_IOCON [index];
557
558          sc = (*visitor)(iocon, pin_range, fio_dir, fio_bit);
559        #endif
560
561        ++port_bit;
562      }
563
564      ++pins;
565      previous_port_bit = port_bit;
566      pin_range = *pins;
567    }
568  } else {
569    sc = RTEMS_NOT_DEFINED;
570  }
571
572  return sc;
573}
Note: See TracBrowser for help on using the repository browser.