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

4.115
Last change on this file since 4a6cc2a was 4a6cc2a, checked in by Sebastian Huber <sebastian.huber@…>, on 11/08/11 at 10:39:46

2011-11-08 Sebastian Huber <sebastian.huber@…>

  • include/lpc17xx.h: New file.
  • Makefile.am, preinstall.am: Reflect change above. Update due to API changes.
  • configure.ac, console/console-config.c, include/bsp.h, include/io.h, include/irq.h, include/lcd.h, include/lpc-clock-config.h, include/lpc24xx.h, include/start-config.h, irq/irq-dispatch.c, irq/irq.c, misc/bspidle.c, misc/io.c, misc/lcd.c, misc/restart.c, misc/system-clocks.c, ssp/ssp.c, startup/bspreset.c, startup/bspstart.c, startup/bspstarthooks.c, startup/start-config-emc-dynamic.c, startup/start-config-emc-static.c, startup/start-config-pinsel.c: Basic support for LPC17XX. New memory configurations for W9825G2JB75I, IS42S32800B, and SST39VF3201.
  • Property mode set to 100644
File size: 11.3 KB
Line 
1/**
2 * @file
3 *
4 * @ingroup lpc24xx_io
5 *
6 * @brief Input and output module.
7 */
8
9/*
10 * Copyright (c) 2009-2011 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.com/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    #endif
64
65    rtems_interrupt_disable(level);
66
67    #ifdef ARM_MULTILIB_ARCH_V4
68      /* Resistor */
69      LPC24XX_PINMODE [select] =
70        (LPC24XX_PINMODE [select] & ~(LPC24XX_PIN_SELECT_MASK << shift))
71          | ((resistor & LPC24XX_PIN_SELECT_MASK) << shift);
72    #endif
73
74    rtems_interrupt_flash(level);
75
76    /* Input or output */
77    LPC24XX_FIO [port].dir =
78      (LPC24XX_FIO [port].dir & ~(1U << port_bit)) | (output << port_bit);
79
80    rtems_interrupt_enable(level);
81  } else {
82    return RTEMS_INVALID_ID;
83  }
84
85  return RTEMS_SUCCESSFUL;
86}
87
88#define LPC24XX_MODULE_ENTRY(mod, pwr, clk, idx) \
89  [mod] = { \
90    .power = pwr, \
91    .clock = clk, \
92    .index = idx \
93  }
94
95typedef struct {
96  unsigned char power : 1;
97  unsigned char clock : 1;
98  unsigned char index : 6;
99} lpc24xx_module_entry;
100
101static const lpc24xx_module_entry lpc24xx_module_table [] = {
102  #ifdef ARM_MULTILIB_ARCH_V4
103    LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_ACF, 0, 1, 15),
104  #endif
105  LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_ADC, 1, 1, 12),
106  #ifdef ARM_MULTILIB_ARCH_V4
107    LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_BAT_RAM, 0, 1, 16),
108  #endif
109  LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_CAN_0, 1, 1, 13),
110  LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_CAN_1, 1, 1, 14),
111  LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_DAC, 0, 1, 11),
112  LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_EMC, 1, 0, 11),
113  LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_ETHERNET, 1, 0, 30),
114  LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_GPDMA, 1, 1, 29),
115  #ifdef ARM_MULTILIB_ARCH_V4
116    LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_GPIO, 0, 1, 17),
117  #else
118    LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_GPIO, 0, 1, 15),
119  #endif
120  LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_I2C_0, 1, 1, 7),
121  LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_I2C_1, 1, 1, 19),
122  LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_I2C_2, 1, 1, 26),
123  LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_I2S, 1, 1, 27),
124  #ifdef ARM_MULTILIB_ARCH_V4
125    LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_LCD, 1, 0, 20),
126  #else
127    LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_LCD, 1, 0, 0),
128  #endif
129  LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_MCI, 1, 1, 28),
130  LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_PCB, 0, 1, 18),
131  LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_PWM_0, 1, 1, 5),
132  LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_PWM_1, 1, 1, 6),
133  LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_RTC, 1, 1, 9),
134  #ifdef ARM_MULTILIB_ARCH_V4
135    LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_SPI, 1, 1, 8),
136  #endif
137  LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_SSP_0, 1, 1, 21),
138  LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_SSP_1, 1, 1, 10),
139  LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_SYSCON, 0, 1, 30),
140  LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_TIMER_0, 1, 1, 1),
141  LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_TIMER_1, 1, 1, 2),
142  LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_TIMER_2, 1, 1, 22),
143  LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_TIMER_3, 1, 1, 23),
144  LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_UART_0, 1, 1, 3),
145  LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_UART_1, 1, 1, 4),
146  LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_UART_2, 1, 1, 24),
147  LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_UART_3, 1, 1, 25),
148  #ifdef ARM_MULTILIB_ARCH_V4
149    LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_WDT, 0, 1, 0),
150  #endif
151  LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_USB, 1, 0, 31)
152};
153
154static rtems_status_code lpc24xx_module_do_enable(
155  lpc24xx_module module,
156  lpc24xx_module_clock clock,
157  bool enable
158)
159{
160  rtems_interrupt_level level;
161  bool has_power = false;
162  bool has_clock = false;
163  unsigned index = 0;
164
165  if ((unsigned) module >= LPC24XX_MODULE_COUNT) {
166      return RTEMS_INVALID_ID;
167  }
168
169  #ifdef ARM_MULTILIB_ARCH_V4
170    if (clock == LPC24XX_MODULE_PCLK_DEFAULT) {
171      #if LPC24XX_PCLKDIV == 1U
172        clock = LPC24XX_MODULE_CCLK;
173      #elif LPC24XX_PCLKDIV == 2U
174        clock = LPC24XX_MODULE_CCLK_2;
175      #elif LPC24XX_PCLKDIV == 4U
176        clock = LPC24XX_MODULE_CCLK_4;
177      #elif LPC24XX_PCLKDIV == 8U
178        clock = LPC24XX_MODULE_CCLK_8;
179      #endif
180    }
181
182    if ((clock & ~LPC24XX_MODULE_CLOCK_MASK) != 0U) {
183      return RTEMS_INVALID_CLOCK;
184    }
185  #endif
186
187  has_power = lpc24xx_module_table [module].power;
188  has_clock = lpc24xx_module_table [module].clock;
189  index = lpc24xx_module_table [module].index;
190
191  /* Enable or disable module */
192  if (enable) {
193    if (has_power) {
194      rtems_interrupt_disable(level);
195      #ifdef ARM_MULTILIB_ARCH_V4
196        PCONP |= 1U << index;
197      #endif
198      rtems_interrupt_enable(level);
199    }
200
201    if (module != LPC24XX_MODULE_USB) {
202      if (has_clock) {
203        #ifdef ARM_MULTILIB_ARCH_V4
204          unsigned clock_shift = 2U * index;
205
206          rtems_interrupt_disable(level);
207          if (clock_shift < 32U) {
208            PCLKSEL0 = (PCLKSEL0 & ~(LPC24XX_MODULE_CLOCK_MASK << clock_shift))
209                | (clock << clock_shift);
210          } else {
211            clock_shift -= 32U;
212            PCLKSEL1 = (PCLKSEL1 & ~(LPC24XX_MODULE_CLOCK_MASK << clock_shift))
213                | (clock << clock_shift);
214          }
215          rtems_interrupt_enable(level);
216        #endif
217      }
218    } else {
219      #ifdef ARM_MULTILIB_ARCH_V4
220        unsigned pllclk = lpc24xx_pllclk();
221        unsigned usbsel = pllclk / 48000000U - 1U;
222
223        if (
224          usbsel > 15U
225            || (usbsel % 2U != 1U)
226            || (pllclk % 48000000U) != 0U
227        ) {
228          return RTEMS_INCORRECT_STATE;
229        }
230
231        USBCLKCFG = usbsel;
232      #endif
233    }
234  } else {
235    if (has_power) {
236      rtems_interrupt_disable(level);
237      #ifdef ARM_MULTILIB_ARCH_V4
238        PCONP &= ~(1U << index);
239      #endif
240      rtems_interrupt_enable(level);
241    }
242  }
243
244  return RTEMS_SUCCESSFUL;
245}
246
247rtems_status_code lpc24xx_module_enable(
248  lpc24xx_module module,
249  lpc24xx_module_clock clock
250)
251{
252  return lpc24xx_module_do_enable(module, clock, true);
253}
254
255rtems_status_code lpc24xx_module_disable(
256  lpc24xx_module module
257)
258{
259  return lpc24xx_module_do_enable(module, 0U, false);
260}
261
262typedef rtems_status_code (*lpc24xx_pin_visitor)(
263  #ifdef ARM_MULTILIB_ARCH_V4
264    volatile uint32_t *pinsel,
265    uint32_t pinsel_mask,
266    uint32_t pinsel_value,
267  #endif
268  volatile uint32_t *fio_dir,
269  uint32_t fio_bit
270);
271
272static BSP_START_TEXT_SECTION __attribute__((flatten)) rtems_status_code
273lpc24xx_pin_set_function(
274  #ifdef ARM_MULTILIB_ARCH_V4
275    volatile uint32_t *pinsel,
276    uint32_t pinsel_mask,
277    uint32_t pinsel_value,
278  #endif
279  volatile uint32_t *fio_dir,
280  uint32_t fio_bit
281)
282{
283  #ifdef ARM_MULTILIB_ARCH_V4
284    rtems_interrupt_level level;
285
286    rtems_interrupt_disable(level);
287    *pinsel = (*pinsel & ~pinsel_mask) | pinsel_value;
288    rtems_interrupt_enable(level);
289  #endif
290
291  return RTEMS_SUCCESSFUL;
292}
293
294static BSP_START_TEXT_SECTION rtems_status_code lpc24xx_pin_check_function(
295  #ifdef ARM_MULTILIB_ARCH_V4
296    volatile uint32_t *pinsel,
297    uint32_t pinsel_mask,
298    uint32_t pinsel_value,
299  #endif
300  volatile uint32_t *fio_dir,
301  uint32_t fio_bit
302)
303{
304  #ifdef ARM_MULTILIB_ARCH_V4
305    if ((*pinsel & pinsel_mask) == pinsel_value) {
306      return RTEMS_SUCCESSFUL;
307    } else {
308      return RTEMS_IO_ERROR;
309    }
310  #endif
311}
312
313static BSP_START_TEXT_SECTION __attribute__((flatten)) rtems_status_code
314lpc24xx_pin_set_input(
315  #ifdef ARM_MULTILIB_ARCH_V4
316    volatile uint32_t *pinsel,
317    uint32_t pinsel_mask,
318    uint32_t pinsel_value,
319  #endif
320  volatile uint32_t *fio_dir,
321  uint32_t fio_bit
322)
323{
324  rtems_interrupt_level level;
325
326  rtems_interrupt_disable(level);
327  *fio_dir &= ~fio_bit;
328  #ifdef ARM_MULTILIB_ARCH_V4
329    *pinsel &= ~pinsel_mask;
330  #endif
331  rtems_interrupt_enable(level);
332
333  return RTEMS_SUCCESSFUL;
334}
335
336static BSP_START_TEXT_SECTION rtems_status_code lpc24xx_pin_check_input(
337  #ifdef ARM_MULTILIB_ARCH_V4
338    volatile uint32_t *pinsel,
339    uint32_t pinsel_mask,
340    uint32_t pinsel_value,
341  #endif
342  volatile uint32_t *fio_dir,
343  uint32_t fio_bit
344)
345{
346  rtems_status_code sc = RTEMS_IO_ERROR;
347  bool is_input = (*fio_dir & fio_bit) == 0;
348
349  if (is_input) {
350    #ifdef ARM_MULTILIB_ARCH_V4
351      bool is_gpio = (*pinsel & pinsel_mask) == 0;
352    #endif
353
354    if (is_gpio) {
355      sc = RTEMS_SUCCESSFUL;
356    }
357  }
358
359  return sc;
360}
361
362static BSP_START_DATA_SECTION const lpc24xx_pin_visitor
363  lpc24xx_pin_visitors [] = {
364  [LPC24XX_PIN_SET_FUNCTION] = lpc24xx_pin_set_function,
365  [LPC24XX_PIN_CHECK_FUNCTION] = lpc24xx_pin_check_function,
366  [LPC24XX_PIN_SET_INPUT] = lpc24xx_pin_set_input,
367  [LPC24XX_PIN_CHECK_INPUT] = lpc24xx_pin_check_input
368};
369
370BSP_START_TEXT_SECTION rtems_status_code lpc24xx_pin_config(
371  const lpc24xx_pin_range *pins,
372  lpc24xx_pin_action action
373)
374{
375  rtems_status_code sc = RTEMS_SUCCESSFUL;
376
377  if ((unsigned) action <= LPC24XX_PIN_CHECK_INPUT) {
378    lpc24xx_pin_visitor visitor = lpc24xx_pin_visitors [action];
379    lpc24xx_pin_range terminal = LPC24XX_PIN_TERMINAL;
380    lpc24xx_pin_range pin_range = *pins;
381    uint32_t previous_port_bit = pin_range.fields.port_bit;
382
383    while (sc == RTEMS_SUCCESSFUL && pin_range.value != terminal.value) {
384      uint32_t port = pin_range.fields.port;
385      uint32_t port_bit = pin_range.fields.port_bit;
386      uint32_t port_bit_last = port_bit;
387      uint32_t range = pin_range.fields.range;
388      #ifdef ARM_MULTILIB_ARCH_V4
389        uint32_t function = pin_range.fields.function;
390      #endif
391      volatile uint32_t *fio_dir = &LPC24XX_FIO [port].dir;
392
393      if (range) {
394        port_bit = previous_port_bit;
395      }
396
397      while (sc == RTEMS_SUCCESSFUL && port_bit <= port_bit_last) {
398        uint32_t index = LPC24XX_IO_INDEX_BY_PORT(port, port_bit);
399        uint32_t fio_bit = 1U << port_bit;
400        #ifdef ARM_MULTILIB_ARCH_V4
401          uint32_t select = LPC24XX_PIN_SELECT(index);
402          uint32_t shift = LPC24XX_PIN_SELECT_SHIFT(index);
403          volatile uint32_t *pinsel = &LPC24XX_PINSEL [select];
404          uint32_t pinsel_mask = LPC24XX_PIN_SELECT_MASK << shift;
405          uint32_t pinsel_value = (function & LPC24XX_PIN_SELECT_MASK) << shift;
406
407          sc = (*visitor)(pinsel, pinsel_mask, pinsel_value, fio_dir, fio_bit);
408        #endif
409
410        ++port_bit;
411      }
412
413      ++pins;
414      previous_port_bit = port_bit;
415      pin_range = *pins;
416    }
417  } else {
418    sc = RTEMS_NOT_DEFINED;
419  }
420
421  return sc;
422}
Note: See TracBrowser for help on using the repository browser.