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

4.115
Last change on this file since dd853a3 was dd853a3, checked in by Sebastian Huber <sebastian.huber@…>, on 12/03/10 at 09:56:48

2010-12-03 Sebastian Huber <sebastian.huber@…>

  • include/lcd.h, misc/lcd.c: New files.
  • misc/io.c, include/io.h: Documentation, bug fixes, more configurations.
  • include/lpc24xx.h: Added DAC and I2S.
  • Makefile.am, bsp_specs, preinstall.am, startup/bspstarthooks.c, startup/linkcmds.lpc2362, startup/linkcmds.lpc23xx_tli800, startup/linkcmds.lpc24xx_ea, startup/linkcmds.lpc24xx_ncs_ram, startup/linkcmds.lpc24xx_ncs_rom_ext, startup/linkcmds.lpc24xx_ncs_rom_int: Update due to linker command file changes.
  • Property mode set to 100644
File size: 13.1 KB
Line 
1/**
2 * @file
3 *
4 * @ingroup lpc24xx_io
5 *
6 * @brief Input and output module.
7 */
8
9/*
10 * Copyright (c) 2009, 2010
11 * embedded brains GmbH
12 * Obere Lagerstr. 30
13 * D-82178 Puchheim
14 * Germany
15 * <rtems@embedded-brains.de>
16 *
17 * The license and distribution terms for this file may be
18 * found in the file LICENSE in this distribution or at
19 * http://www.rtems.com/license/LICENSE.
20 */
21
22#include <bsp/io.h>
23#include <bsp/system-clocks.h>
24
25#define LPC24XX_IO_SELECT(pin) (pin >> 4U)
26
27#define LPC24XX_IO_SELECT_SHIFT(pin) ((pin & 0xfU) << 1U)
28
29#define LPC24XX_IO_SELECT_MASK 0x3U
30
31#define LPC24XX_IO_PRIMARY 0x0U
32
33#define LPC24XX_IO_ALTERNATE_0 0x1U
34
35#define LPC24XX_IO_ALTERNATE_1 0x2U
36
37#define LPC24XX_IO_ALTERNATE_2 0x3U
38
39#define LPC24XX_IO_ENTRY(mod, cfg, begin_port, begin_index, last_port, last_index, function) \
40  { \
41    .module = mod, \
42    .config = cfg, \
43    .pin_begin = LPC24XX_IO_INDEX_BY_PORT(begin_port, begin_index), \
44    .pin_last = LPC24XX_IO_INDEX_BY_PORT(last_port, last_index), \
45    .pin_function = function \
46  }
47
48typedef struct {
49  unsigned module : 6;
50  unsigned config : 4;
51  unsigned pin_begin : 8;
52  unsigned pin_last : 8;
53  unsigned pin_function : 3;
54} lpc24xx_io_entry;
55
56typedef void (*lpc24xx_io_iterate_routine)(unsigned pin, unsigned function);
57
58static const lpc24xx_io_entry lpc24xx_io_config_table [] = {
59  /* UART */
60  LPC24XX_IO_ENTRY(LPC24XX_MODULE_UART_0, 0, 0, 2, 0, 3, LPC24XX_IO_ALTERNATE_0),
61  LPC24XX_IO_ENTRY(LPC24XX_MODULE_UART_1, 0, 0, 15, 0, 16, LPC24XX_IO_ALTERNATE_0),
62  LPC24XX_IO_ENTRY(LPC24XX_MODULE_UART_1, 1, 2, 0, 2, 1, LPC24XX_IO_ALTERNATE_1),
63  LPC24XX_IO_ENTRY(LPC24XX_MODULE_UART_1, 2, 3, 16, 3, 17, LPC24XX_IO_ALTERNATE_2),
64  LPC24XX_IO_ENTRY(LPC24XX_MODULE_UART_2, 0, 0, 10, 0, 11, LPC24XX_IO_ALTERNATE_0),
65  LPC24XX_IO_ENTRY(LPC24XX_MODULE_UART_2, 1, 2, 8, 2, 9, LPC24XX_IO_ALTERNATE_1),
66  LPC24XX_IO_ENTRY(LPC24XX_MODULE_UART_2, 2, 4, 22, 4, 23, LPC24XX_IO_ALTERNATE_1),
67  LPC24XX_IO_ENTRY(LPC24XX_MODULE_UART_3, 0, 0, 0, 0, 1, LPC24XX_IO_ALTERNATE_1),
68  LPC24XX_IO_ENTRY(LPC24XX_MODULE_UART_3, 1, 0, 25, 0, 26, LPC24XX_IO_ALTERNATE_2),
69  LPC24XX_IO_ENTRY(LPC24XX_MODULE_UART_3, 2, 4, 28, 4, 29, LPC24XX_IO_ALTERNATE_2),
70
71  /* Ethernet */
72  LPC24XX_IO_ENTRY(LPC24XX_MODULE_ETHERNET, 0, 1, 0, 1, 17, LPC24XX_IO_ALTERNATE_0),
73  LPC24XX_IO_ENTRY(LPC24XX_MODULE_ETHERNET, 1, 1, 0, 1, 1, LPC24XX_IO_ALTERNATE_0),
74  LPC24XX_IO_ENTRY(LPC24XX_MODULE_ETHERNET, 1, 1, 4, 1, 4, LPC24XX_IO_ALTERNATE_0),
75  LPC24XX_IO_ENTRY(LPC24XX_MODULE_ETHERNET, 1, 1, 8, 1, 10, LPC24XX_IO_ALTERNATE_0),
76  LPC24XX_IO_ENTRY(LPC24XX_MODULE_ETHERNET, 1, 1, 14, 1, 17, LPC24XX_IO_ALTERNATE_0),
77
78  /* ADC */
79  LPC24XX_IO_ENTRY(LPC24XX_MODULE_ADC, 0, 0, 12, 0, 13, LPC24XX_IO_ALTERNATE_2),
80  LPC24XX_IO_ENTRY(LPC24XX_MODULE_ADC, 1, 0, 23, 0, 25, LPC24XX_IO_ALTERNATE_0),
81  LPC24XX_IO_ENTRY(LPC24XX_MODULE_ADC, 2, 0, 26, 0, 26, LPC24XX_IO_ALTERNATE_0),
82  LPC24XX_IO_ENTRY(LPC24XX_MODULE_ADC, 2, 1, 30, 1, 31, LPC24XX_IO_ALTERNATE_2),
83
84  /* I2C */
85  LPC24XX_IO_ENTRY(LPC24XX_MODULE_I2C_0, 0, 0, 27, 0, 28, LPC24XX_IO_ALTERNATE_0),
86  LPC24XX_IO_ENTRY(LPC24XX_MODULE_I2C_1, 0, 0, 0, 0, 1, LPC24XX_IO_ALTERNATE_2),
87  LPC24XX_IO_ENTRY(LPC24XX_MODULE_I2C_1, 1, 0, 19, 0, 20, LPC24XX_IO_ALTERNATE_2),
88  LPC24XX_IO_ENTRY(LPC24XX_MODULE_I2C_1, 2, 2, 14, 2, 15, LPC24XX_IO_ALTERNATE_2),
89  LPC24XX_IO_ENTRY(LPC24XX_MODULE_I2C_2, 0, 0, 10, 0, 11, LPC24XX_IO_ALTERNATE_1),
90  LPC24XX_IO_ENTRY(LPC24XX_MODULE_I2C_2, 1, 2, 30, 2, 31, LPC24XX_IO_ALTERNATE_2),
91  LPC24XX_IO_ENTRY(LPC24XX_MODULE_I2C_2, 2, 4, 20, 4, 21, LPC24XX_IO_ALTERNATE_1),
92
93  /* I2S */
94  LPC24XX_IO_ENTRY(LPC24XX_MODULE_I2S, 0, 0, 4, 0, 9, LPC24XX_IO_ALTERNATE_0),
95  LPC24XX_IO_ENTRY(LPC24XX_MODULE_I2S, 1, 0, 23, 0, 25, LPC24XX_IO_ALTERNATE_1),
96  LPC24XX_IO_ENTRY(LPC24XX_MODULE_I2S, 1, 2, 11, 2, 13, LPC24XX_IO_ALTERNATE_2),
97
98  /* SSP */
99  LPC24XX_IO_ENTRY(LPC24XX_MODULE_SSP_0, 0, 0, 15, 0, 18, LPC24XX_IO_ALTERNATE_1),
100  LPC24XX_IO_ENTRY(LPC24XX_MODULE_SSP_0, 1, 1, 20, 0, 21, LPC24XX_IO_ALTERNATE_2),
101  LPC24XX_IO_ENTRY(LPC24XX_MODULE_SSP_0, 1, 1, 23, 0, 24, LPC24XX_IO_ALTERNATE_2),
102  LPC24XX_IO_ENTRY(LPC24XX_MODULE_SSP_0, 2, 2, 22, 2, 23, LPC24XX_IO_ALTERNATE_2),
103  LPC24XX_IO_ENTRY(LPC24XX_MODULE_SSP_0, 2, 2, 26, 2, 27, LPC24XX_IO_ALTERNATE_2),
104  LPC24XX_IO_ENTRY(LPC24XX_MODULE_SSP_1, 0, 0, 6, 0, 9, LPC24XX_IO_ALTERNATE_1),
105  LPC24XX_IO_ENTRY(LPC24XX_MODULE_SSP_1, 1, 0, 12, 0, 13, LPC24XX_IO_ALTERNATE_1),
106  LPC24XX_IO_ENTRY(LPC24XX_MODULE_SSP_1, 1, 0, 14, 0, 14, LPC24XX_IO_ALTERNATE_2),
107  LPC24XX_IO_ENTRY(LPC24XX_MODULE_SSP_1, 1, 1, 31, 1, 31, LPC24XX_IO_ALTERNATE_1),
108  LPC24XX_IO_ENTRY(LPC24XX_MODULE_SSP_1, 2, 4, 20, 4, 23, LPC24XX_IO_ALTERNATE_2),
109
110  /* USB */
111  LPC24XX_IO_ENTRY(LPC24XX_MODULE_USB, 0, 0, 29, 0, 30, LPC24XX_IO_ALTERNATE_0),
112  LPC24XX_IO_ENTRY(LPC24XX_MODULE_USB, 0, 1, 19, 1, 19, LPC24XX_IO_ALTERNATE_1),
113
114  /* SPI */
115  LPC24XX_IO_ENTRY(LPC24XX_MODULE_SPI, 0, 0, 15, 0, 18, LPC24XX_IO_ALTERNATE_2),
116
117  /* PWM */
118  LPC24XX_IO_ENTRY(LPC24XX_MODULE_PWM_1, 0, 2, 0, 2, 0, LPC24XX_IO_ALTERNATE_0),
119
120  /* LCD */
121  LPC24XX_IO_ENTRY(LPC24XX_MODULE_LCD, 0, 0, 4, 0, 9, LPC24XX_IO_ALTERNATE_0),
122  LPC24XX_IO_ENTRY(LPC24XX_MODULE_LCD, 0, 1, 20, 1, 29, LPC24XX_IO_ALTERNATE_0),
123  LPC24XX_IO_ENTRY(LPC24XX_MODULE_LCD, 0, 2, 0, 2, 3, LPC24XX_IO_ALTERNATE_2),
124  LPC24XX_IO_ENTRY(LPC24XX_MODULE_LCD, 0, 2, 5, 2, 9, LPC24XX_IO_ALTERNATE_2),
125  LPC24XX_IO_ENTRY(LPC24XX_MODULE_LCD, 0, 2, 12, 2, 13, LPC24XX_IO_ALTERNATE_0),
126  LPC24XX_IO_ENTRY(LPC24XX_MODULE_LCD, 0, 4, 28, 4, 29, LPC24XX_IO_ALTERNATE_1),
127  LPC24XX_IO_ENTRY(LPC24XX_MODULE_LCD, 1, 1, 20, 1, 29, LPC24XX_IO_ALTERNATE_0),
128  LPC24XX_IO_ENTRY(LPC24XX_MODULE_LCD, 1, 2, 0, 2, 3, LPC24XX_IO_ALTERNATE_2),
129  LPC24XX_IO_ENTRY(LPC24XX_MODULE_LCD, 1, 2, 5, 2, 9, LPC24XX_IO_ALTERNATE_2),
130  LPC24XX_IO_ENTRY(LPC24XX_MODULE_LCD, 1, 2, 12, 2, 13, LPC24XX_IO_ALTERNATE_0),
131  LPC24XX_IO_ENTRY(LPC24XX_MODULE_LCD, 1, 4, 28, 4, 29, LPC24XX_IO_ALTERNATE_1),
132
133  /* DAC */
134  LPC24XX_IO_ENTRY(LPC24XX_MODULE_DAC, 0, 0, 26, 0, 26, LPC24XX_IO_ALTERNATE_1),
135
136  /* Terminate */
137  LPC24XX_IO_ENTRY(LPC24XX_MODULE_COUNT, 0, 0, 0, 0, 0, 0)
138};
139
140static rtems_status_code lpc24xx_io_iterate(
141  lpc24xx_module module,
142  unsigned config,
143  lpc24xx_io_iterate_routine routine
144)
145{
146  rtems_status_code sc = RTEMS_SUCCESSFUL;
147  const lpc24xx_io_entry *e = &lpc24xx_io_config_table [0];
148
149  while (e->module != LPC24XX_MODULE_COUNT) {
150    if (e->module == module && e->config == config) {
151      unsigned pin = e->pin_begin;
152      unsigned last = e->pin_last;
153      unsigned function = e->pin_function;
154
155      while (pin <= last) {
156        (*routine)(pin, function);
157
158        ++pin;
159      }
160
161      sc = RTEMS_SUCCESSFUL;
162    }
163    ++e;
164  }
165
166  return sc;
167}
168
169static void lpc24xx_io_do_config(unsigned pin, unsigned function)
170{
171  rtems_interrupt_level level;
172  unsigned select = LPC24XX_IO_SELECT(pin);
173  unsigned shift = LPC24XX_IO_SELECT_SHIFT(pin);
174  unsigned mask = LPC24XX_IO_SELECT_MASK << shift;
175  unsigned pinsel = 0;
176
177  rtems_interrupt_disable(level);
178  pinsel = LPC24XX_PINSEL [select];
179  pinsel &= ~mask;
180  pinsel |= (function & LPC24XX_IO_SELECT_MASK) << shift;
181  LPC24XX_PINSEL [select] = pinsel;
182  rtems_interrupt_enable(level);
183}
184
185static void lpc24xx_io_do_release(unsigned pin, unsigned function)
186{
187  rtems_interrupt_level level;
188  unsigned select = LPC24XX_IO_SELECT(pin);
189  unsigned shift = LPC24XX_IO_SELECT_SHIFT(pin);
190  unsigned mask = LPC24XX_IO_SELECT_MASK << shift;
191
192  rtems_interrupt_disable(level);
193  LPC24XX_PINSEL [select] &= ~mask;
194  rtems_interrupt_enable(level);
195}
196
197rtems_status_code lpc24xx_io_config(
198  lpc24xx_module module,
199  unsigned config
200)
201{
202  return lpc24xx_io_iterate(module, config, lpc24xx_io_do_config);
203}
204
205rtems_status_code lpc24xx_io_release(
206  lpc24xx_module module,
207  unsigned config
208)
209{
210  return lpc24xx_io_iterate(module, config, lpc24xx_io_do_release);
211}
212
213rtems_status_code lpc24xx_gpio_config(
214  unsigned pin,
215  lpc24xx_gpio_settings settings
216)
217{
218  if (pin <= LPC24XX_IO_INDEX_MAX) {
219    rtems_interrupt_level level;
220    unsigned port = LPC24XX_IO_PORT(pin);
221    unsigned bit = LPC24XX_IO_PORT_BIT(pin);
222    unsigned select = LPC24XX_IO_SELECT(pin);
223    unsigned shift = LPC24XX_IO_SELECT_SHIFT(pin);
224    unsigned resistor = settings & LPC24XX_GPIO_RESISTOR_MASK;
225    unsigned output = (settings & LPC24XX_GPIO_OUTPUT) != 0 ? 1U : 0U;
226
227    /* Get resistor flags */
228    switch (resistor) {
229      case LPC24XX_GPIO_RESISTOR_PULL_UP:
230      case LPC24XX_GPIO_RESISTOR_DEFAULT:
231        resistor = 0x0U;
232        break;
233      case LPC24XX_GPIO_RESISTOR_NONE:
234        resistor = 0x2U;
235        break;
236      case LPC24XX_GPIO_RESISTOR_PULL_DOWN:
237        resistor = 0x3U;
238        break;
239      default:
240        return RTEMS_INVALID_NUMBER;
241    }
242
243    rtems_interrupt_disable(level);
244
245    /* Resistor */
246    LPC24XX_PINMODE [select] =
247      (LPC24XX_PINMODE [select] & ~(LPC24XX_IO_SELECT_MASK << shift))
248        | ((resistor & LPC24XX_IO_SELECT_MASK) << shift);
249
250    rtems_interrupt_flash(level);
251
252    /* Input or output */
253    LPC24XX_FIO [port].dir =
254      (LPC24XX_FIO [port].dir & ~(1U << bit)) | (output << bit);
255
256    rtems_interrupt_enable(level);
257  } else {
258    return RTEMS_INVALID_ID;
259  }
260
261  return RTEMS_SUCCESSFUL;
262}
263
264#define LPC24XX_MODULE_ENTRY(mod, pwr, clk, idx) \
265  [mod] = { \
266    .power = pwr, \
267    .clock = clk, \
268    .index = idx \
269  }
270
271typedef struct {
272  unsigned char power : 1;
273  unsigned char clock : 1;
274  unsigned char index : 6;
275} lpc24xx_module_entry;
276
277static const lpc24xx_module_entry lpc24xx_module_table [] = {
278  LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_ACF, 0, 1, 15),
279  LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_ADC, 1, 1, 12),
280  LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_BAT_RAM, 0, 1, 16),
281  LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_CAN_0, 1, 1, 13),
282  LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_CAN_1, 1, 1, 14),
283  LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_DAC, 0, 1, 11),
284  LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_EMC, 1, 0, 11),
285  LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_ETHERNET, 1, 0, 30),
286  LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_GPDMA, 1, 1, 29),
287  LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_GPIO, 0, 1, 17),
288  LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_I2C_0, 1, 1, 7),
289  LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_I2C_1, 1, 1, 19),
290  LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_I2C_2, 1, 1, 26),
291  LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_I2S, 1, 1, 27),
292  LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_LCD, 1, 0, 20),
293  LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_MCI, 1, 1, 28),
294  LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_PCB, 0, 1, 18),
295  LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_PWM_0, 1, 1, 5),
296  LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_PWM_1, 1, 1, 6),
297  LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_RTC, 1, 1, 9),
298  LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_SPI, 1, 1, 8),
299  LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_SSP_0, 1, 1, 21),
300  LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_SSP_1, 1, 1, 10),
301  LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_SYSCON, 0, 1, 30),
302  LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_TIMER_0, 1, 1, 1),
303  LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_TIMER_1, 1, 1, 2),
304  LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_TIMER_2, 1, 1, 22),
305  LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_TIMER_3, 1, 1, 23),
306  LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_UART_0, 1, 1, 3),
307  LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_UART_1, 1, 1, 4),
308  LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_UART_2, 1, 1, 24),
309  LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_UART_3, 1, 1, 25),
310  LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_USB, 1, 0, 31),
311  LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_WDT, 0, 1, 0)
312};
313
314static rtems_status_code lpc24xx_module_do_enable(
315  lpc24xx_module module,
316  lpc24xx_module_clock clock,
317  bool enable
318)
319{
320  rtems_interrupt_level level;
321  bool has_power = false;
322  bool has_clock = false;
323  unsigned index = 0;
324
325  if ((unsigned) module >= LPC24XX_MODULE_COUNT) {
326      return RTEMS_INVALID_ID;
327  }
328
329  if ((clock & ~LPC24XX_MODULE_CLOCK_MASK) != 0U) {
330    return RTEMS_INVALID_NUMBER;
331  }
332
333  has_power = lpc24xx_module_table [module].power;
334  has_clock = lpc24xx_module_table [module].clock;
335  index = lpc24xx_module_table [module].index;
336
337  /* Enable or disable module */
338  if (enable) {
339    if (has_power) {
340      rtems_interrupt_disable(level);
341      PCONP |= 1U << index;
342      rtems_interrupt_enable(level);
343    }
344
345    if (module != LPC24XX_MODULE_USB) {
346      if (has_clock) {
347        unsigned clock_shift = 2U * index;
348
349        rtems_interrupt_disable(level);
350        if (clock_shift < 32U) {
351          PCLKSEL0 = (PCLKSEL0 & ~(LPC24XX_MODULE_CLOCK_MASK << clock_shift))
352              | (clock << clock_shift);
353        } else {
354          clock_shift -= 32U;
355          PCLKSEL1 = (PCLKSEL1 & ~(LPC24XX_MODULE_CLOCK_MASK << clock_shift))
356              | (clock << clock_shift);
357        }
358        rtems_interrupt_enable(level);
359      }
360    } else {
361      unsigned pllclk = lpc24xx_pllclk();
362      unsigned usbsel = pllclk / 48000000U - 1U;
363
364      if (usbsel > 15U || (usbsel % 2U != 1U) || (pllclk % 48000000U) != 0U) {
365        return RTEMS_INCORRECT_STATE;
366      }
367
368      USBCLKCFG = usbsel;
369    }
370  } else {
371    if (has_power) {
372      rtems_interrupt_disable(level);
373      PCONP &= ~(1U << index);
374      rtems_interrupt_enable(level);
375    }
376  }
377
378  return RTEMS_SUCCESSFUL;
379}
380
381rtems_status_code lpc24xx_module_enable(
382  lpc24xx_module module,
383  lpc24xx_module_clock clock
384)
385{
386  return lpc24xx_module_do_enable(module, clock, true);
387}
388
389rtems_status_code lpc24xx_module_disable(
390  lpc24xx_module module
391)
392{
393  return lpc24xx_module_do_enable(module, 0U, false);
394}
Note: See TracBrowser for help on using the repository browser.