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

4.104.115
Last change on this file since c468f18b was c468f18b, checked in by Thomas Doerfler <Thomas.Doerfler@…>, on 12/15/09 at 15:20:47

add support for LPC32xx

  • Property mode set to 100644
File size: 11.5 KB
Line 
1/**
2 * @file
3 *
4 * @ingroup lpc24xx_io
5 *
6 * @brief Input and output module.
7 */
8
9/*
10 * Copyright (c) 2009
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
81  /* I2C */
82  LPC24XX_IO_ENTRY(LPC24XX_MODULE_I2C_0, 0, 0, 27, 0, 28, LPC24XX_IO_ALTERNATE_0),
83  LPC24XX_IO_ENTRY(LPC24XX_MODULE_I2C_1, 0, 0, 0, 0, 1, LPC24XX_IO_ALTERNATE_2),
84  LPC24XX_IO_ENTRY(LPC24XX_MODULE_I2C_1, 1, 0, 19, 0, 20, LPC24XX_IO_ALTERNATE_2),
85  LPC24XX_IO_ENTRY(LPC24XX_MODULE_I2C_1, 2, 2, 14, 2, 15, LPC24XX_IO_ALTERNATE_2),
86  LPC24XX_IO_ENTRY(LPC24XX_MODULE_I2C_2, 0, 0, 10, 0, 11, LPC24XX_IO_ALTERNATE_1),
87  LPC24XX_IO_ENTRY(LPC24XX_MODULE_I2C_2, 1, 2, 30, 2, 31, LPC24XX_IO_ALTERNATE_2),
88  LPC24XX_IO_ENTRY(LPC24XX_MODULE_I2C_2, 2, 4, 20, 4, 21, LPC24XX_IO_ALTERNATE_1),
89
90  /* SSP */
91  LPC24XX_IO_ENTRY(LPC24XX_MODULE_SSP_0, 0, 0, 15, 0, 18, LPC24XX_IO_ALTERNATE_1),
92  LPC24XX_IO_ENTRY(LPC24XX_MODULE_SSP_0, 1, 1, 20, 0, 21, LPC24XX_IO_ALTERNATE_2),
93  LPC24XX_IO_ENTRY(LPC24XX_MODULE_SSP_0, 1, 1, 23, 0, 24, LPC24XX_IO_ALTERNATE_2),
94  LPC24XX_IO_ENTRY(LPC24XX_MODULE_SSP_0, 2, 2, 22, 2, 23, LPC24XX_IO_ALTERNATE_2),
95  LPC24XX_IO_ENTRY(LPC24XX_MODULE_SSP_0, 2, 2, 26, 2, 27, LPC24XX_IO_ALTERNATE_2),
96  LPC24XX_IO_ENTRY(LPC24XX_MODULE_SSP_1, 0, 0, 6, 0, 9, LPC24XX_IO_ALTERNATE_1),
97  LPC24XX_IO_ENTRY(LPC24XX_MODULE_SSP_1, 1, 0, 12, 0, 13, LPC24XX_IO_ALTERNATE_1),
98  LPC24XX_IO_ENTRY(LPC24XX_MODULE_SSP_1, 1, 0, 14, 0, 14, LPC24XX_IO_ALTERNATE_2),
99  LPC24XX_IO_ENTRY(LPC24XX_MODULE_SSP_1, 1, 1, 31, 1, 31, LPC24XX_IO_ALTERNATE_1),
100  LPC24XX_IO_ENTRY(LPC24XX_MODULE_SSP_1, 2, 4, 20, 4, 23, LPC24XX_IO_ALTERNATE_2),
101
102  /* USB */
103  LPC24XX_IO_ENTRY(LPC24XX_MODULE_USB, 0, 0, 29, 0, 30, LPC24XX_IO_ALTERNATE_0),
104  LPC24XX_IO_ENTRY(LPC24XX_MODULE_USB, 0, 1, 19, 1, 19, LPC24XX_IO_ALTERNATE_1),
105
106  /* Terminate */
107  LPC24XX_IO_ENTRY(LPC24XX_MODULE_COUNT, 0, 0, 0, 0, 0, 0),
108};
109
110static rtems_status_code lpc24xx_io_iterate(
111  lpc24xx_module module,
112  unsigned config,
113  lpc24xx_io_iterate_routine routine
114)
115{
116  rtems_status_code sc = RTEMS_INVALID_ID;
117  const lpc24xx_io_entry *e = &lpc24xx_io_config_table [0];
118
119  while (e->module != LPC24XX_MODULE_COUNT) {
120    if (e->module == module && e->config == config) {
121      unsigned pin = e->pin_begin;
122      unsigned last = e->pin_last;
123      unsigned function = e->pin_function;
124
125      while (pin <= last) {
126        (*routine)(pin, function);
127
128        ++pin;
129      }
130
131      sc = RTEMS_SUCCESSFUL;
132    }
133    ++e;
134  }
135
136  return sc;
137}
138
139static void lpc24xx_io_do_config(unsigned pin, unsigned function)
140{
141  rtems_interrupt_level level;
142  unsigned select = LPC24XX_IO_SELECT(pin);
143  unsigned shift = LPC24XX_IO_SELECT_SHIFT(pin);
144
145  rtems_interrupt_disable(level);
146
147  LPC24XX_PINSEL [select] =
148    (LPC24XX_PINSEL [select] & ~(LPC24XX_IO_SELECT_MASK << shift))
149      | ((function & LPC24XX_IO_SELECT_MASK) << shift);
150
151  rtems_interrupt_flash(level);
152
153  LPC24XX_PINMODE [select] &= ~(LPC24XX_IO_SELECT_MASK << shift);
154
155  rtems_interrupt_enable(level);
156}
157
158static void lpc24xx_io_do_release(unsigned pin, unsigned function)
159{
160  rtems_interrupt_level level;
161  unsigned select = LPC24XX_IO_SELECT(pin);
162  unsigned shift = LPC24XX_IO_SELECT_SHIFT(pin);
163
164  rtems_interrupt_disable(level);
165  LPC24XX_PINSEL [select] =
166    (LPC24XX_PINSEL [select] & ~(LPC24XX_IO_SELECT_MASK << shift));
167  rtems_interrupt_enable(level);
168}
169
170rtems_status_code lpc24xx_io_config(
171  lpc24xx_module module,
172  unsigned config
173)
174{
175  return lpc24xx_io_iterate(module, config, lpc24xx_io_do_config);
176}
177
178rtems_status_code lpc24xx_io_release(
179  lpc24xx_module module,
180  unsigned config
181)
182{
183  return lpc24xx_io_iterate(module, config, lpc24xx_io_do_release);
184}
185
186rtems_status_code lpc24xx_gpio_config(
187  unsigned pin,
188  lpc24xx_gpio_settings settings
189)
190{
191  if (pin <= LPC24XX_IO_INDEX_MAX) {
192    rtems_interrupt_level level;
193    unsigned port = LPC24XX_IO_PORT(pin);
194    unsigned bit = LPC24XX_IO_PORT_BIT(pin);
195    unsigned select = LPC24XX_IO_SELECT(pin);
196    unsigned shift = LPC24XX_IO_SELECT_SHIFT(pin);
197    unsigned resistor = settings & LPC24XX_GPIO_RESISTOR_MASK;
198    unsigned output = (settings & LPC24XX_GPIO_OUTPUT) != 0 ? 1U : 0U;
199
200    /* Get resistor flags */
201    switch (resistor) {
202      case LPC24XX_GPIO_RESISTOR_PULL_UP:
203      case LPC24XX_GPIO_RESISTOR_DEFAULT:
204        resistor = 0x0U;
205        break;
206      case LPC24XX_GPIO_RESISTOR_NONE:
207        resistor = 0x2U;
208        break;
209      case LPC24XX_GPIO_RESISTOR_PULL_DOWN:
210        resistor = 0x3U;
211        break;
212      default:
213        return RTEMS_INVALID_NUMBER;
214    }
215
216    rtems_interrupt_disable(level);
217
218    /* Resistor */
219    LPC24XX_PINMODE [select] =
220      (LPC24XX_PINMODE [select] & ~(LPC24XX_IO_SELECT_MASK << shift))
221        | ((resistor & LPC24XX_IO_SELECT_MASK) << shift);
222
223    rtems_interrupt_flash(level);
224
225    /* Input or output */
226    LPC24XX_FIO [port].dir =
227      (LPC24XX_FIO [port].dir & ~(1U << bit)) | (output << bit);
228
229    rtems_interrupt_enable(level);
230  } else {
231    return RTEMS_INVALID_ID;
232  }
233
234  return RTEMS_SUCCESSFUL;
235}
236
237#define LPC24XX_MODULE_ENTRY(mod, pwr, clk, idx) \
238  [mod] = { \
239    .power = pwr, \
240    .clock = clk, \
241    .index = idx \
242  }
243
244typedef struct {
245  unsigned char power : 1;
246  unsigned char clock : 1;
247  unsigned char index : 6;
248} lpc24xx_module_entry;
249
250static const lpc24xx_module_entry lpc24xx_module_table [] = {
251  LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_ACF, 0, 1, 15),
252  LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_ADC, 1, 1, 12),
253  LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_BAT_RAM, 0, 1, 16),
254  LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_CAN_0, 1, 1, 13),
255  LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_CAN_1, 1, 1, 14),
256  LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_DAC, 0, 1, 11),
257  LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_EMC, 1, 0, 11),
258  LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_ETHERNET, 1, 0, 30),
259  LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_GPDMA, 1, 1, 29),
260  LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_GPIO, 0, 1, 17),
261  LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_I2C_0, 1, 1, 7),
262  LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_I2C_1, 1, 1, 19),
263  LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_I2C_2, 1, 1, 26),
264  LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_I2S, 1, 1, 27),
265  LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_LCD, 1, 1, 20),
266  LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_MCI, 1, 1, 28),
267  LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_PCB, 0, 1, 18),
268  LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_PWM_0, 1, 1, 5),
269  LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_PWM_1, 1, 1, 6),
270  LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_RTC, 1, 1, 9),
271  LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_SPI, 1, 1, 8),
272  LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_SSP_0, 1, 1, 21),
273  LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_SSP_1, 1, 1, 10),
274  LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_SYSCON, 0, 1, 30),
275  LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_TIMER_0, 1, 1, 1),
276  LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_TIMER_1, 1, 1, 2),
277  LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_TIMER_2, 1, 1, 22),
278  LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_TIMER_3, 1, 1, 23),
279  LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_UART_0, 1, 1, 3),
280  LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_UART_1, 1, 1, 4),
281  LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_UART_2, 1, 1, 24),
282  LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_UART_3, 1, 1, 25),
283  LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_USB, 1, 0, 31),
284  LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_WDT, 0, 1, 0)
285};
286
287static rtems_status_code lpc24xx_module_do_enable(
288  lpc24xx_module module,
289  lpc24xx_module_clock clock,
290  bool enable
291)
292{
293  rtems_interrupt_level level;
294  bool has_power = false;
295  bool has_clock = false;
296  unsigned index = 0;
297
298  if ((unsigned) module >= LPC24XX_MODULE_COUNT) {
299      return RTEMS_INVALID_ID;
300  }
301
302  if ((clock & ~LPC24XX_MODULE_CLOCK_MASK) != 0U) {
303    return RTEMS_INVALID_NUMBER;
304  }
305
306  has_power = lpc24xx_module_table [module].power;
307  has_clock = lpc24xx_module_table [module].clock;
308  index = lpc24xx_module_table [module].index;
309
310  /* Enable or disable module */
311  if (enable) {
312    if (has_power) {
313      rtems_interrupt_disable(level);
314      PCONP |= 1U << index;
315      rtems_interrupt_enable(level);
316    }
317
318    if (module != LPC24XX_MODULE_USB) {
319      if (has_clock) {
320        unsigned clock_shift = 2U * index;
321
322        rtems_interrupt_disable(level);
323        if (clock_shift < 32U) {
324          PCLKSEL0 = (PCLKSEL0 & ~(LPC24XX_MODULE_CLOCK_MASK << clock_shift))
325              | (clock << clock_shift);
326        } else {
327          clock_shift -= 32U;
328          PCLKSEL1 = (PCLKSEL1 & ~(LPC24XX_MODULE_CLOCK_MASK << clock_shift))
329              | (clock << clock_shift);
330        }
331        rtems_interrupt_enable(level);
332      }
333    } else {
334      unsigned pllclk = lpc24xx_pllclk();
335      unsigned usbsel = pllclk / 48000000U - 1U;
336
337      if (usbsel > 15U || (usbsel % 2U != 1U) || (pllclk % 48000000U) != 0U) {
338        return RTEMS_INCORRECT_STATE;
339      }
340
341      USBCLKCFG = usbsel;
342    }
343  } else {
344    if (has_power) {
345      rtems_interrupt_disable(level);
346      PCONP &= ~(1U << index);
347      rtems_interrupt_enable(level);
348    }
349  }
350
351  return RTEMS_SUCCESSFUL;
352}
353
354rtems_status_code lpc24xx_module_enable(
355  lpc24xx_module module,
356  lpc24xx_module_clock clock
357)
358{
359  return lpc24xx_module_do_enable(module, clock, true);
360}
361
362rtems_status_code lpc24xx_module_disable(
363  lpc24xx_module module
364)
365{
366  return lpc24xx_module_do_enable(module, 0U, false);
367}
Note: See TracBrowser for help on using the repository browser.