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

4.104.115
Last change on this file since 9364cf66 was 9364cf66, checked in by Thomas Doerfler <Thomas.Doerfler@…>, on Jul 17, 2009 at 3:16:50 PM

adding lpc24xx BSP parts

  • Property mode set to 100644
File size: 14.4 KB
Line 
1/**
2 * @file
3 *
4 * @ingroup lpc24xx
5 *
6 * 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
24#define LPC24XX_IO_SELECT( index) (index >> 4U)
25
26#define LPC24XX_IO_SELECT_SHIFT( index) ((index & 0xfU) << 1U)
27
28#define LPC24XX_IO_SELECT_MASK 0x3U
29
30#define LPC24XX_IO_PRIMARY 0x0U
31
32#define LPC24XX_IO_ALTERNATE_0 0x1U
33
34#define LPC24XX_IO_ALTERNATE_1 0x2U
35
36#define LPC24XX_IO_ALTERNATE_2 0x3U
37
38#define LPC24XX_IO_HEADER_FLAG 0x80U
39
40#define LPC24XX_IO_ENTRY( b, e, f) \
41  { .function = f, .begin = b, .end = e }
42
43#define LPC24XX_IO_HEADER( module, index, config) \
44  { .function = config | LPC24XX_IO_HEADER_FLAG, .begin = module, .end = index }
45
46typedef struct  __attribute__ ((__packed__)) {
47  unsigned char function;
48  unsigned char begin;
49  unsigned char end;
50} lpc24xx_io_entry;
51
52typedef void (*lpc24xx_io_iterate_routine)( unsigned /* index */, unsigned /* function */);
53
54static const lpc24xx_io_entry lpc24xx_io_config_table [] = {
55  /* EMC */
56  LPC24XX_IO_HEADER( LPC24XX_MODULE_EMC, 0, 0),
57  LPC24XX_IO_ENTRY( LPC24XX_IO_INDEX_BY_PORT( 2, 16), LPC24XX_IO_INDEX_BY_PORT( 2, 22), LPC24XX_IO_ALTERNATE_0),
58  LPC24XX_IO_ENTRY( LPC24XX_IO_INDEX_BY_PORT( 2, 24), LPC24XX_IO_INDEX_BY_PORT( 2, 26), LPC24XX_IO_ALTERNATE_0),
59  LPC24XX_IO_ENTRY( LPC24XX_IO_INDEX_BY_PORT( 2, 26), LPC24XX_IO_INDEX_BY_PORT( 2, 30), LPC24XX_IO_ALTERNATE_0),
60  LPC24XX_IO_ENTRY( LPC24XX_IO_INDEX_BY_PORT( 3, 0), LPC24XX_IO_INDEX_BY_PORT( 3, 16), LPC24XX_IO_ALTERNATE_0),
61  LPC24XX_IO_ENTRY( LPC24XX_IO_INDEX_BY_PORT( 4, 0), LPC24XX_IO_INDEX_BY_PORT( 4, 28), LPC24XX_IO_ALTERNATE_0),
62  LPC24XX_IO_ENTRY( LPC24XX_IO_INDEX_BY_PORT( 4, 30), LPC24XX_IO_INDEX_BY_PORT( 5, 0), LPC24XX_IO_ALTERNATE_0),
63
64  /* UART */
65  LPC24XX_IO_HEADER( LPC24XX_MODULE_UART, 0, 0),
66  LPC24XX_IO_ENTRY( LPC24XX_IO_INDEX_BY_PORT( 0, 2), LPC24XX_IO_INDEX_BY_PORT( 0, 4), LPC24XX_IO_ALTERNATE_0),
67  LPC24XX_IO_HEADER( LPC24XX_MODULE_UART, 1, 0),
68  LPC24XX_IO_ENTRY( LPC24XX_IO_INDEX_BY_PORT( 0, 15), LPC24XX_IO_INDEX_BY_PORT( 0, 17), LPC24XX_IO_ALTERNATE_1),
69  LPC24XX_IO_HEADER( LPC24XX_MODULE_UART, 1, 1),
70  LPC24XX_IO_ENTRY( LPC24XX_IO_INDEX_BY_PORT( 2, 0), LPC24XX_IO_INDEX_BY_PORT( 2, 2), LPC24XX_IO_ALTERNATE_2),
71  LPC24XX_IO_HEADER( LPC24XX_MODULE_UART, 1, 2),
72  LPC24XX_IO_ENTRY( LPC24XX_IO_INDEX_BY_PORT( 3, 16), LPC24XX_IO_INDEX_BY_PORT( 3, 18), LPC24XX_IO_ALTERNATE_1),
73  LPC24XX_IO_HEADER( LPC24XX_MODULE_UART, 2, 0),
74  LPC24XX_IO_ENTRY( LPC24XX_IO_INDEX_BY_PORT( 0, 10), LPC24XX_IO_INDEX_BY_PORT( 0, 12), LPC24XX_IO_ALTERNATE_1),
75  LPC24XX_IO_HEADER( LPC24XX_MODULE_UART, 2, 1),
76  LPC24XX_IO_ENTRY( LPC24XX_IO_INDEX_BY_PORT( 2, 8), LPC24XX_IO_INDEX_BY_PORT( 2, 10), LPC24XX_IO_ALTERNATE_1),
77  LPC24XX_IO_HEADER( LPC24XX_MODULE_UART, 2, 2),
78  LPC24XX_IO_ENTRY( LPC24XX_IO_INDEX_BY_PORT( 4, 22), LPC24XX_IO_INDEX_BY_PORT( 4, 24), LPC24XX_IO_ALTERNATE_1),
79  LPC24XX_IO_HEADER( LPC24XX_MODULE_UART, 3, 0),
80  LPC24XX_IO_ENTRY( LPC24XX_IO_INDEX_BY_PORT( 0, 0), LPC24XX_IO_INDEX_BY_PORT( 0, 2), LPC24XX_IO_ALTERNATE_2),
81  LPC24XX_IO_HEADER( LPC24XX_MODULE_UART, 3, 1),
82  LPC24XX_IO_ENTRY( LPC24XX_IO_INDEX_BY_PORT( 0, 25), LPC24XX_IO_INDEX_BY_PORT( 0, 27), LPC24XX_IO_ALTERNATE_2),
83  LPC24XX_IO_HEADER( LPC24XX_MODULE_UART, 3, 2),
84  LPC24XX_IO_ENTRY( LPC24XX_IO_INDEX_BY_PORT( 4, 28), LPC24XX_IO_INDEX_BY_PORT( 4, 30), LPC24XX_IO_ALTERNATE_2),
85
86  /* Ethernet */
87  LPC24XX_IO_HEADER( LPC24XX_MODULE_ETHERNET, 0, 0),
88  LPC24XX_IO_ENTRY( LPC24XX_IO_INDEX_BY_PORT( 1, 0), LPC24XX_IO_INDEX_BY_PORT( 1, 18), LPC24XX_IO_ALTERNATE_0),
89  LPC24XX_IO_HEADER( LPC24XX_MODULE_ETHERNET, 0, 1),
90  LPC24XX_IO_ENTRY( LPC24XX_IO_INDEX_BY_PORT( 1, 0), LPC24XX_IO_INDEX_BY_PORT( 1, 2), LPC24XX_IO_ALTERNATE_0),
91  LPC24XX_IO_ENTRY( LPC24XX_IO_INDEX_BY_PORT( 1, 4), LPC24XX_IO_INDEX_BY_PORT( 1, 5), LPC24XX_IO_ALTERNATE_0),
92  LPC24XX_IO_ENTRY( LPC24XX_IO_INDEX_BY_PORT( 1, 8), LPC24XX_IO_INDEX_BY_PORT( 1, 11), LPC24XX_IO_ALTERNATE_0),
93  LPC24XX_IO_ENTRY( LPC24XX_IO_INDEX_BY_PORT( 1, 14), LPC24XX_IO_INDEX_BY_PORT( 1, 18), LPC24XX_IO_ALTERNATE_0),
94
95  /* ADC */
96  LPC24XX_IO_HEADER( LPC24XX_MODULE_ADC, 0, 0),
97  LPC24XX_IO_ENTRY( LPC24XX_IO_INDEX_BY_PORT( 0, 12), LPC24XX_IO_INDEX_BY_PORT( 0, 14), LPC24XX_IO_ALTERNATE_2),
98
99  /* I2C */
100  LPC24XX_IO_HEADER( LPC24XX_MODULE_I2C, 0, 0),
101  LPC24XX_IO_ENTRY( LPC24XX_IO_INDEX_BY_PORT( 0, 27), LPC24XX_IO_INDEX_BY_PORT( 0, 29), LPC24XX_IO_ALTERNATE_0),
102  LPC24XX_IO_HEADER( LPC24XX_MODULE_I2C, 1, 0),
103  LPC24XX_IO_ENTRY( LPC24XX_IO_INDEX_BY_PORT( 0, 0), LPC24XX_IO_INDEX_BY_PORT( 0, 2), LPC24XX_IO_ALTERNATE_2),
104  LPC24XX_IO_HEADER( LPC24XX_MODULE_I2C, 1, 1),
105  LPC24XX_IO_ENTRY( LPC24XX_IO_INDEX_BY_PORT( 0, 19), LPC24XX_IO_INDEX_BY_PORT( 0, 21), LPC24XX_IO_ALTERNATE_2),
106  LPC24XX_IO_HEADER( LPC24XX_MODULE_I2C, 1, 2),
107  LPC24XX_IO_ENTRY( LPC24XX_IO_INDEX_BY_PORT( 2, 14), LPC24XX_IO_INDEX_BY_PORT( 2, 16), LPC24XX_IO_ALTERNATE_2),
108  LPC24XX_IO_HEADER( LPC24XX_MODULE_I2C, 2, 0),
109  LPC24XX_IO_ENTRY( LPC24XX_IO_INDEX_BY_PORT( 0, 10), LPC24XX_IO_INDEX_BY_PORT( 0, 12), LPC24XX_IO_ALTERNATE_1),
110  LPC24XX_IO_HEADER( LPC24XX_MODULE_I2C, 2, 1),
111  LPC24XX_IO_ENTRY( LPC24XX_IO_INDEX_BY_PORT( 2, 30), LPC24XX_IO_INDEX_BY_PORT( 3, 0), LPC24XX_IO_ALTERNATE_2),
112  LPC24XX_IO_HEADER( LPC24XX_MODULE_I2C, 2, 2),
113  LPC24XX_IO_ENTRY( LPC24XX_IO_INDEX_BY_PORT( 4, 20), LPC24XX_IO_INDEX_BY_PORT( 4, 22), LPC24XX_IO_ALTERNATE_1),
114
115  /* USB */
116  LPC24XX_IO_HEADER( LPC24XX_MODULE_USB, 0, 0),
117  LPC24XX_IO_ENTRY( LPC24XX_IO_INDEX_BY_PORT( 0, 29), LPC24XX_IO_INDEX_BY_PORT( 0, 31), LPC24XX_IO_ALTERNATE_0),
118  LPC24XX_IO_ENTRY( LPC24XX_IO_INDEX_BY_PORT( 1, 19), LPC24XX_IO_INDEX_BY_PORT( 1, 20), LPC24XX_IO_ALTERNATE_1),
119};
120
121static size_t lpc24xx_io_get_entry_index( lpc24xx_module module, unsigned index, unsigned config)
122{
123  size_t i = 0;
124
125  config |= LPC24XX_IO_HEADER_FLAG;
126
127  for (i = 0; i < sizeof( lpc24xx_io_config_table); ++i) {
128    const lpc24xx_io_entry *e = lpc24xx_io_config_table + i;
129
130    if (e->function == config && e->begin == module && e->end == index) {
131      return i + 1;
132    }
133  }
134
135  return (size_t) -1;
136}
137
138static void lpc24xx_io_do_config( unsigned index, unsigned function)
139{
140  rtems_interrupt_level level;
141  unsigned select = LPC24XX_IO_SELECT( index);
142  unsigned shift = LPC24XX_IO_SELECT_SHIFT( index);
143
144  rtems_interrupt_disable( level);
145
146  LPC24XX_PINSEL [select] =
147    (LPC24XX_PINSEL [select] & ~(LPC24XX_IO_SELECT_MASK << shift))
148      | ((function & LPC24XX_IO_SELECT_MASK) << shift);
149
150  rtems_interrupt_flash( level);
151
152  LPC24XX_PINMODE [select] &= ~(LPC24XX_IO_SELECT_MASK << shift);
153
154  rtems_interrupt_enable( level);
155}
156
157static void lpc24xx_io_do_release( unsigned index, unsigned function)
158{
159  rtems_interrupt_level level;
160  unsigned select = LPC24XX_IO_SELECT( index);
161  unsigned shift = LPC24XX_IO_SELECT_SHIFT( index);
162
163  rtems_interrupt_disable( level);
164  LPC24XX_PINSEL [select] =
165    (LPC24XX_PINSEL [select] & ~(LPC24XX_IO_SELECT_MASK << shift));
166  rtems_interrupt_enable( level);
167}
168
169static rtems_status_code lpc24xx_io_iterate(
170  lpc24xx_module module,
171  unsigned index,
172  unsigned config,
173  lpc24xx_io_iterate_routine routine
174)
175{
176  size_t i = lpc24xx_io_get_entry_index( module, index, config);
177
178  if (i != (size_t) -1) {
179    const lpc24xx_io_entry * const table_end = lpc24xx_io_config_table
180      + sizeof( lpc24xx_io_config_table) / sizeof( lpc24xx_io_config_table [0]);
181    const lpc24xx_io_entry *e = lpc24xx_io_config_table + i;
182
183    while (e != table_end && (e->function & LPC24XX_IO_HEADER_FLAG) == 0) {
184      unsigned j = e->begin;
185      unsigned end = e->end;
186      unsigned function = e->function;
187
188      while (j < end) {
189        routine( j, function);
190
191        ++j;
192      }
193
194      ++e;
195    }
196  } else {
197    return RTEMS_INVALID_ID;
198  }
199
200  return RTEMS_SUCCESSFUL;
201}
202
203rtems_status_code lpc24xx_io_config(
204  lpc24xx_module module,
205  unsigned index,
206  unsigned config
207)
208{
209  return lpc24xx_io_iterate( module, index, config, lpc24xx_io_do_config);
210}
211
212rtems_status_code lpc24xx_io_release(
213  lpc24xx_module module,
214  unsigned index,
215  unsigned config
216)
217{
218  return lpc24xx_io_iterate( module, index, config, lpc24xx_io_do_release);
219}
220
221rtems_status_code lpc24xx_gpio_config(
222  unsigned index,
223  lpc24xx_gpio_settings settings
224)
225{
226  if (index <= LPC24XX_IO_INDEX_MAX) {
227    rtems_interrupt_level level;
228    unsigned port = LPC24XX_IO_PORT( index);
229    unsigned bit = LPC24XX_IO_PORT_BIT( index);
230    unsigned select = LPC24XX_IO_SELECT( index);
231    unsigned shift = LPC24XX_IO_SELECT_SHIFT( index);
232    unsigned resistor = settings & LPC24XX_GPIO_RESISTOR_MASK;
233    unsigned output = (settings & LPC24XX_GPIO_OUTPUT) != 0 ? 1U : 0U;
234
235    /* Get resistor flags */
236    switch (resistor) {
237      case LPC24XX_GPIO_RESISTOR_PULL_UP:
238      case LPC24XX_GPIO_RESISTOR_DEFAULT:
239        resistor = 0x0U;
240        break;
241      case LPC24XX_GPIO_RESISTOR_NONE:
242        resistor = 0x2U;
243        break;
244      case LPC24XX_GPIO_RESISTOR_PULL_DOWN:
245        resistor = 0x3U;
246        break;
247      default:
248        return RTEMS_INVALID_NUMBER;
249    }
250
251    rtems_interrupt_disable( level);
252
253    /* Resistor */
254    LPC24XX_PINMODE [select] =
255      (LPC24XX_PINMODE [select] & ~(LPC24XX_IO_SELECT_MASK << shift))
256        | ((resistor & LPC24XX_IO_SELECT_MASK) << shift); 
257
258    rtems_interrupt_flash( level);
259
260    /* Input or output */
261    LPC24XX_FIO [port].dir =
262      (LPC24XX_FIO [port].dir & ~(1U << bit)) | (output << bit);
263
264    rtems_interrupt_enable( level);
265  } else {
266    return RTEMS_INVALID_ID;
267  }
268
269  return RTEMS_SUCCESSFUL;
270}
271
272static rtems_status_code lpc24xx_module_do_enable(
273  lpc24xx_module module,
274  unsigned index,
275  lpc24xx_module_clock clock,
276  bool enable
277)
278{
279  const unsigned NO_POWER = 32U;
280  const unsigned INVALID = 33U;
281  unsigned power_bit = INVALID;
282  unsigned clock_shift = INVALID;
283
284  /* Check clock value */
285  if ((clock & ~LPC24XX_MODULE_CLOCK_MASK) != 0U) {
286    return RTEMS_INVALID_NUMBER;
287  }
288
289  /* Get power bit */
290  switch (module) {
291    case LPC24XX_MODULE_ACF:
292      if (index == 0) {
293        power_bit = NO_POWER;
294        clock_shift = 30U;
295      }
296      break;
297    case LPC24XX_MODULE_ADC:
298      if (index == 0) {
299        power_bit = 12U;
300      }
301      break;
302    case LPC24XX_MODULE_BAT_RAM:
303      if (index == 0) {
304        power_bit = NO_POWER;
305        clock_shift = 32U;
306      }
307      break;
308    case LPC24XX_MODULE_CAN:
309      if (index < 2) {
310        power_bit = 13U + index;
311      }
312      break;
313    case LPC24XX_MODULE_DAC:
314      if (index == 0) {
315        power_bit = NO_POWER;
316        clock_shift = 22U;
317      }
318      break;
319    case LPC24XX_MODULE_EMC:
320      if (index == 0) {
321        power_bit = 11U;
322      }
323      break;
324    case LPC24XX_MODULE_ETHERNET:
325      if (index == 0) {
326        power_bit = 30U;
327      }
328      break;
329    case LPC24XX_MODULE_GPDMA:
330      if (index == 0) {
331        power_bit = 29U;
332      }
333      break;
334    case LPC24XX_MODULE_GPIO:
335      if (index == 0) {
336        power_bit = NO_POWER;
337        clock_shift = 34U;
338      }
339      break;
340    case LPC24XX_MODULE_I2C:
341      switch (index) {
342        case 0U:
343          power_bit = 7U;
344          break;
345        case 1U:
346          power_bit = 19U;
347          break;
348        case 2U:
349          power_bit = 26U;
350          break;
351      }
352      break;
353    case LPC24XX_MODULE_I2S:
354      if (index == 0) {
355        power_bit = 27U;
356      }
357      break;
358    case LPC24XX_MODULE_LCD:
359      if (index == 0) {
360        power_bit = 20U;
361      }
362      break;
363    case LPC24XX_MODULE_MCI:
364      if (index == 0) {
365        power_bit = 28U;
366      }
367      break;
368    case LPC24XX_MODULE_PCB:
369      if (index == 0) {
370        power_bit = NO_POWER;
371        clock_shift = 36U;
372      }
373      break;
374    case LPC24XX_MODULE_PWM:
375      if (index < 2) {
376        power_bit = 5U + index;
377      }
378      break;
379    case LPC24XX_MODULE_RTC:
380      if (index == 0) {
381        power_bit = 9U;
382      }
383      break;
384    case LPC24XX_MODULE_SPI:
385      if (index == 0) {
386        power_bit = 8U;
387      }
388      break;
389    case LPC24XX_MODULE_SSP:
390      switch (index) {
391        case 0U:
392          power_bit = 21U;
393          break;
394        case 1U:
395          power_bit = 10U;
396          break;
397      }
398      break;
399    case LPC24XX_MODULE_SYSCON:
400      if (index == 0) {
401        power_bit = NO_POWER;
402        clock_shift = 60U;
403      }
404      break;
405    case LPC24XX_MODULE_TIMER:
406      if (index < 2) {
407        power_bit = 1U + index;
408      } else if (index < 4) {
409        power_bit = 20U + index;
410      }
411      break;
412    case LPC24XX_MODULE_UART:
413      if (index < 2) {
414        power_bit = 3U + index;
415      } else if (index < 4) {
416        power_bit = 22U + index;
417      }
418      break;
419    case LPC24XX_MODULE_USB:
420      if (index == 0) {
421        power_bit = 31U;
422      }
423      break;
424    case LPC24XX_MODULE_WDT:
425      if (index == 0) {
426        power_bit = NO_POWER;
427        clock_shift = 0U;
428      }
429      break;
430    default:
431      return RTEMS_INVALID_ID;
432  }
433
434  /* Check power bit */
435  if (power_bit == INVALID) {
436    return RTEMS_INVALID_ID;
437  }
438
439  /* Get clock shift */
440  if (clock_shift == INVALID) {
441    clock_shift = power_bit << 1U;
442  }
443
444  /* Enable or disable module */
445  if (enable) {
446    rtems_interrupt_level level;
447
448    rtems_interrupt_disable( level);
449    PCONP |= 1U << power_bit;
450    rtems_interrupt_enable( level);
451
452    if (module != LPC24XX_MODULE_USB) {
453      rtems_interrupt_disable( level);
454      if (clock_shift < 32U) {
455        PCLKSEL0 = (PCLKSEL0 & ~(LPC24XX_MODULE_CLOCK_MASK << clock_shift))
456            | (clock << clock_shift);
457      } else {
458        clock_shift -= 32U;
459        PCLKSEL1 = (PCLKSEL1 & ~(LPC24XX_MODULE_CLOCK_MASK << clock_shift))
460            | (clock << clock_shift);
461      }
462      rtems_interrupt_enable( level);
463    } else {
464      unsigned pllclk = lpc24xx_pllclk();
465      unsigned usbsel = pllclk / 48000000U - 1U;
466
467      if (usbsel > 15U || (usbsel % 2U != 1U) || (pllclk % 48000000U) != 0U) {
468        return RTEMS_INCORRECT_STATE;
469      }
470
471      USBCLKCFG = usbsel;
472    }
473  } else {
474    rtems_interrupt_level level;
475
476    rtems_interrupt_disable( level);
477    PCONP &= ~(1U << power_bit);
478    rtems_interrupt_enable( level);
479  }
480
481  return RTEMS_SUCCESSFUL;
482}
483
484rtems_status_code lpc24xx_module_enable(
485  lpc24xx_module module,
486  unsigned index,
487  lpc24xx_module_clock clock
488)
489{
490  return lpc24xx_module_do_enable( module, index, clock, true);
491}
492
493rtems_status_code lpc24xx_module_disable(
494  lpc24xx_module module,
495  unsigned index
496)
497{
498  return lpc24xx_module_do_enable( module, index, 0U, false);
499}
Note: See TracBrowser for help on using the repository browser.