source: rtems/c/src/lib/libbsp/arm/lpc24xx/misc/io.c @ c499856

4.115
Last change on this file since c499856 was c499856, checked in by Chris Johns <chrisj@…>, on 03/20/14 at 21:10:47

Change all references of rtems.com to rtems.org.

  • Property mode set to 100644
File size: 15.0 KB
Line 
1/**
2 * @file
3 *
4 * @ingroup lpc24xx_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
399    /* TODO */
400    switch (pin_range.fields.type) {
401      case LPC17XX_PIN_TYPE_I2C_FAST_PLUS:
402        iocon_extra |= IOCON_HS;
403        break;
404      case LPC17XX_PIN_TYPE_OPEN_DRAIN:
405        iocon_extra |= IOCON_OD;
406        break;
407      default:
408        break;
409    }
410
411    *iocon = IOCON_FUNC(pin_range.fields.function) | iocon_extra;
412  #endif
413
414  return RTEMS_SUCCESSFUL;
415}
416
417static BSP_START_TEXT_SECTION rtems_status_code lpc24xx_pin_check_function(
418  #ifdef ARM_MULTILIB_ARCH_V4
419    volatile uint32_t *pinsel,
420    uint32_t pinsel_mask,
421    uint32_t pinsel_value,
422  #else
423    volatile uint32_t *iocon,
424    lpc24xx_pin_range pin_range,
425  #endif
426  volatile uint32_t *fio_dir,
427  uint32_t fio_bit
428)
429{
430  #ifdef ARM_MULTILIB_ARCH_V4
431    if ((*pinsel & pinsel_mask) == pinsel_value) {
432      return RTEMS_SUCCESSFUL;
433    } else {
434      return RTEMS_IO_ERROR;
435    }
436  #else
437    /* TODO */
438    return RTEMS_IO_ERROR;
439  #endif
440}
441
442static BSP_START_TEXT_SECTION __attribute__((flatten)) rtems_status_code
443lpc24xx_pin_set_input(
444  #ifdef ARM_MULTILIB_ARCH_V4
445    volatile uint32_t *pinsel,
446    uint32_t pinsel_mask,
447    uint32_t pinsel_value,
448  #else
449    volatile uint32_t *iocon,
450    lpc24xx_pin_range pin_range,
451  #endif
452  volatile uint32_t *fio_dir,
453  uint32_t fio_bit
454)
455{
456  rtems_interrupt_level level;
457
458  rtems_interrupt_disable(level);
459  *fio_dir &= ~fio_bit;
460  #ifdef ARM_MULTILIB_ARCH_V4
461    *pinsel &= ~pinsel_mask;
462  #else
463    *iocon = IOCON_MODE(2) | IOCON_ADMODE | IOCON_FILTER;
464  #endif
465  rtems_interrupt_enable(level);
466
467  return RTEMS_SUCCESSFUL;
468}
469
470static BSP_START_TEXT_SECTION rtems_status_code lpc24xx_pin_check_input(
471  #ifdef ARM_MULTILIB_ARCH_V4
472    volatile uint32_t *pinsel,
473    uint32_t pinsel_mask,
474    uint32_t pinsel_value,
475  #else
476    volatile uint32_t *iocon,
477    lpc24xx_pin_range pin_range,
478  #endif
479  volatile uint32_t *fio_dir,
480  uint32_t fio_bit
481)
482{
483  rtems_status_code sc = RTEMS_IO_ERROR;
484  bool is_input = (*fio_dir & fio_bit) == 0;
485
486  if (is_input) {
487    #ifdef ARM_MULTILIB_ARCH_V4
488      bool is_gpio = (*pinsel & pinsel_mask) == 0;
489    #else
490      bool is_gpio = IOCON_FUNC_GET(*iocon) == 0;
491    #endif
492
493    if (is_gpio) {
494      sc = RTEMS_SUCCESSFUL;
495    }
496  }
497
498  return sc;
499}
500
501static BSP_START_DATA_SECTION const lpc24xx_pin_visitor
502  lpc24xx_pin_visitors [] = {
503  [LPC24XX_PIN_SET_FUNCTION] = lpc24xx_pin_set_function,
504  [LPC24XX_PIN_CHECK_FUNCTION] = lpc24xx_pin_check_function,
505  [LPC24XX_PIN_SET_INPUT] = lpc24xx_pin_set_input,
506  [LPC24XX_PIN_CHECK_INPUT] = lpc24xx_pin_check_input
507};
508
509BSP_START_TEXT_SECTION rtems_status_code lpc24xx_pin_config(
510  const lpc24xx_pin_range *pins,
511  lpc24xx_pin_action action
512)
513{
514  rtems_status_code sc = RTEMS_SUCCESSFUL;
515
516  if ((unsigned) action <= LPC24XX_PIN_CHECK_INPUT) {
517    lpc24xx_pin_visitor visitor = lpc24xx_pin_visitors [action];
518    lpc24xx_pin_range terminal = LPC24XX_PIN_TERMINAL;
519    lpc24xx_pin_range pin_range = *pins;
520    uint32_t previous_port_bit = pin_range.fields.port_bit;
521
522    while (sc == RTEMS_SUCCESSFUL && pin_range.value != terminal.value) {
523      uint32_t port = pin_range.fields.port;
524      uint32_t port_bit = pin_range.fields.port_bit;
525      uint32_t port_bit_last = port_bit;
526      uint32_t range = pin_range.fields.range;
527      #ifdef ARM_MULTILIB_ARCH_V4
528        uint32_t function = pin_range.fields.function;
529      #endif
530      volatile uint32_t *fio_dir = &LPC24XX_FIO [port].dir;
531
532      if (range) {
533        port_bit = previous_port_bit;
534      }
535
536      while (sc == RTEMS_SUCCESSFUL && port_bit <= port_bit_last) {
537        uint32_t index = LPC24XX_IO_INDEX_BY_PORT(port, port_bit);
538        uint32_t fio_bit = 1U << port_bit;
539        #ifdef ARM_MULTILIB_ARCH_V4
540          uint32_t select = LPC24XX_PIN_SELECT(index);
541          uint32_t shift = LPC24XX_PIN_SELECT_SHIFT(index);
542          volatile uint32_t *pinsel = &LPC24XX_PINSEL [select];
543          uint32_t pinsel_mask = LPC24XX_PIN_SELECT_MASK << shift;
544          uint32_t pinsel_value = (function & LPC24XX_PIN_SELECT_MASK) << shift;
545
546          sc = (*visitor)(pinsel, pinsel_mask, pinsel_value, fio_dir, fio_bit);
547        #else
548          volatile uint32_t *iocon = &LPC17XX_IOCON [index];
549
550          sc = (*visitor)(iocon, pin_range, fio_dir, fio_bit);
551        #endif
552
553        ++port_bit;
554      }
555
556      ++pins;
557      previous_port_bit = port_bit;
558      pin_range = *pins;
559    }
560  } else {
561    sc = RTEMS_NOT_DEFINED;
562  }
563
564  return sc;
565}
Note: See TracBrowser for help on using the repository browser.