Mercurial > ecos-v3_0-branch
annotate packages/devs/spi/arm/lpc2xxx/current/src/spi_lpc2xxx.cxx @ 2811:3fdf0d74f32d
Silly omission in previous checkin in transposition of patch by jifl
| author | jlarmour |
|---|---|
| date | Tue, 17 Feb 2009 09:09:15 +0000 |
| parents | a0730cb32880 |
| children |
| rev | line source |
|---|---|
| 2506 | 1 //========================================================================== |
| 2 // | |
| 3 // spi_lpc2xxx.cxx | |
| 4 // | |
| 5 // SPI driver for LPC2xxx | |
| 6 // | |
| 7 //========================================================================== | |
|
2729
74dbf4c3f2e1
Update all copyright banners to reflect FSF ownership; fix and improve licence text.
jlarmour
parents:
2506
diff
changeset
|
8 // ####ECOSGPLCOPYRIGHTBEGIN#### |
|
74dbf4c3f2e1
Update all copyright banners to reflect FSF ownership; fix and improve licence text.
jlarmour
parents:
2506
diff
changeset
|
9 // ------------------------------------------- |
|
74dbf4c3f2e1
Update all copyright banners to reflect FSF ownership; fix and improve licence text.
jlarmour
parents:
2506
diff
changeset
|
10 // This file is part of eCos, the Embedded Configurable Operating System. |
| 2788 | 11 // Copyright (C) 1998, 1999, 2000, 2001, 2002, 2009 Free Software Foundation, Inc. |
| 2506 | 12 // |
|
2729
74dbf4c3f2e1
Update all copyright banners to reflect FSF ownership; fix and improve licence text.
jlarmour
parents:
2506
diff
changeset
|
13 // eCos is free software; you can redistribute it and/or modify it under |
|
74dbf4c3f2e1
Update all copyright banners to reflect FSF ownership; fix and improve licence text.
jlarmour
parents:
2506
diff
changeset
|
14 // the terms of the GNU General Public License as published by the Free |
|
74dbf4c3f2e1
Update all copyright banners to reflect FSF ownership; fix and improve licence text.
jlarmour
parents:
2506
diff
changeset
|
15 // Software Foundation; either version 2 or (at your option) any later |
|
74dbf4c3f2e1
Update all copyright banners to reflect FSF ownership; fix and improve licence text.
jlarmour
parents:
2506
diff
changeset
|
16 // version. |
| 2506 | 17 // |
|
2729
74dbf4c3f2e1
Update all copyright banners to reflect FSF ownership; fix and improve licence text.
jlarmour
parents:
2506
diff
changeset
|
18 // eCos is distributed in the hope that it will be useful, but WITHOUT |
|
74dbf4c3f2e1
Update all copyright banners to reflect FSF ownership; fix and improve licence text.
jlarmour
parents:
2506
diff
changeset
|
19 // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
|
74dbf4c3f2e1
Update all copyright banners to reflect FSF ownership; fix and improve licence text.
jlarmour
parents:
2506
diff
changeset
|
20 // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
|
74dbf4c3f2e1
Update all copyright banners to reflect FSF ownership; fix and improve licence text.
jlarmour
parents:
2506
diff
changeset
|
21 // for more details. |
| 2506 | 22 // |
|
2729
74dbf4c3f2e1
Update all copyright banners to reflect FSF ownership; fix and improve licence text.
jlarmour
parents:
2506
diff
changeset
|
23 // You should have received a copy of the GNU General Public License |
|
74dbf4c3f2e1
Update all copyright banners to reflect FSF ownership; fix and improve licence text.
jlarmour
parents:
2506
diff
changeset
|
24 // along with eCos; if not, write to the Free Software Foundation, Inc., |
|
74dbf4c3f2e1
Update all copyright banners to reflect FSF ownership; fix and improve licence text.
jlarmour
parents:
2506
diff
changeset
|
25 // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
| 2506 | 26 // |
|
2729
74dbf4c3f2e1
Update all copyright banners to reflect FSF ownership; fix and improve licence text.
jlarmour
parents:
2506
diff
changeset
|
27 // As a special exception, if other files instantiate templates or use |
|
74dbf4c3f2e1
Update all copyright banners to reflect FSF ownership; fix and improve licence text.
jlarmour
parents:
2506
diff
changeset
|
28 // macros or inline functions from this file, or you compile this file |
|
74dbf4c3f2e1
Update all copyright banners to reflect FSF ownership; fix and improve licence text.
jlarmour
parents:
2506
diff
changeset
|
29 // and link it with other works to produce a work based on this file, |
|
74dbf4c3f2e1
Update all copyright banners to reflect FSF ownership; fix and improve licence text.
jlarmour
parents:
2506
diff
changeset
|
30 // this file does not by itself cause the resulting work to be covered by |
|
74dbf4c3f2e1
Update all copyright banners to reflect FSF ownership; fix and improve licence text.
jlarmour
parents:
2506
diff
changeset
|
31 // the GNU General Public License. However the source code for this file |
|
74dbf4c3f2e1
Update all copyright banners to reflect FSF ownership; fix and improve licence text.
jlarmour
parents:
2506
diff
changeset
|
32 // must still be made available in accordance with section (3) of the GNU |
|
74dbf4c3f2e1
Update all copyright banners to reflect FSF ownership; fix and improve licence text.
jlarmour
parents:
2506
diff
changeset
|
33 // General Public License v2. |
| 2506 | 34 // |
|
2729
74dbf4c3f2e1
Update all copyright banners to reflect FSF ownership; fix and improve licence text.
jlarmour
parents:
2506
diff
changeset
|
35 // This exception does not invalidate any other reasons why a work based |
|
74dbf4c3f2e1
Update all copyright banners to reflect FSF ownership; fix and improve licence text.
jlarmour
parents:
2506
diff
changeset
|
36 // on this file might be covered by the GNU General Public License. |
|
74dbf4c3f2e1
Update all copyright banners to reflect FSF ownership; fix and improve licence text.
jlarmour
parents:
2506
diff
changeset
|
37 // ------------------------------------------- |
|
74dbf4c3f2e1
Update all copyright banners to reflect FSF ownership; fix and improve licence text.
jlarmour
parents:
2506
diff
changeset
|
38 // ####ECOSGPLCOPYRIGHTEND#### |
| 2506 | 39 //========================================================================== |
| 40 //#####DESCRIPTIONBEGIN#### | |
| 41 // | |
| 42 // Author(s): Hans Rosenfeld <rosenfeld@grumpf.hope-2000.org> | |
| 43 // Contributors: | |
| 44 // Date: 2007-07-12 | |
| 45 // Purpose: | |
| 46 // Description: | |
| 47 // | |
| 48 //####DESCRIPTIONEND#### | |
| 49 // | |
| 50 //========================================================================== | |
| 51 | |
| 52 #include <pkgconf/hal.h> | |
| 53 #include <pkgconf/io_spi.h> | |
| 54 #include <pkgconf/devs_spi_arm_lpc2xxx.h> | |
| 55 | |
| 56 #include <cyg/infra/cyg_type.h> | |
| 57 #include <cyg/infra/cyg_ass.h> | |
| 58 #include <cyg/hal/hal_io.h> | |
| 59 #include <cyg/hal/hal_if.h> | |
| 60 #include <cyg/hal/hal_intr.h> | |
| 61 #include <cyg/io/spi.h> | |
| 62 #include <cyg/io/spi_lpc2xxx.h> | |
| 63 #include <cyg/error/codes.h> | |
| 64 | |
| 65 #define SPI_SPCR_SPIE 0x80 | |
| 66 #define SPI_SPCR_LSBF 0x40 | |
| 67 #define SPI_SPCR_MSTR 0x20 | |
| 68 #define SPI_SPCR_CPOL 0x10 | |
| 69 #define SPI_SPCR_CPHA 0x08 | |
| 70 | |
| 71 #define SPI_SPSR_SPIF 0x80 | |
| 72 #define SPI_SPSR_WCOL 0x40 | |
| 73 #define SPI_SPSR_ROVR 0x20 | |
| 74 #define SPI_SPSR_MODF 0x10 | |
| 75 #define SPI_SPSR_ABRT 0x08 | |
| 76 | |
| 77 #define SPI_SPINT 0x01 | |
| 78 | |
| 79 #ifdef CYGPKG_DEVS_SPI_ARM_LPC2XXX_BUS0 | |
| 80 cyg_spi_lpc2xxx_bus_t cyg_spi_lpc2xxx_bus0; | |
| 81 CYG_SPI_DEFINE_BUS_TABLE(cyg_spi_lpc2xxx_dev_t, 0); | |
| 82 #endif | |
| 83 #ifdef CYGPKG_DEVS_SPI_ARM_LPC2XXX_BUS1 | |
| 84 cyg_spi_lpc2xxx_bus_t cyg_spi_lpc2xxx_bus1; | |
| 85 CYG_SPI_DEFINE_BUS_TABLE(cyg_spi_lpc2xxx_dev_t, 1); | |
| 86 #endif | |
| 87 | |
| 88 /* | |
| 89 * Interrupt routine | |
| 90 * read & write the next byte until count reaches zero | |
| 91 */ | |
| 92 static cyg_uint32 | |
| 93 spi_lpc2xxx_isr(cyg_vector_t vec, cyg_addrword_t data) | |
| 94 { | |
| 95 cyg_spi_lpc2xxx_bus_t *bus = (cyg_spi_lpc2xxx_bus_t *) data; | |
| 96 cyg_uint8 tmp; | |
| 97 | |
| 98 tmp = bus->spi_dev->spsr; | |
| 99 | |
| 100 if(tmp & SPI_SPSR_MODF) | |
| 101 bus->spi_dev->spcr = bus->spi_dev->spcr | SPI_SPCR_MSTR; | |
| 102 | |
| 103 tmp = bus->spi_dev->spdr; | |
| 104 | |
| 105 if(bus->count) { | |
| 106 if(bus->rx) | |
| 107 *bus->rx++ = tmp; | |
| 108 if(--bus->count) { | |
| 109 bus->spi_dev->spint = SPI_SPINT; | |
| 110 bus->spi_dev->spdr = bus->tx ? *bus->tx++ : 0; | |
| 111 cyg_drv_interrupt_acknowledge(bus->spi_vect); | |
| 112 return CYG_ISR_HANDLED; | |
| 113 } | |
| 114 } | |
| 115 | |
| 116 bus->count = 0; | |
| 117 bus->tx = NULL; | |
| 118 bus->rx = NULL; | |
| 119 | |
| 120 bus->spi_dev->spint = SPI_SPINT; | |
| 121 cyg_drv_interrupt_acknowledge(bus->spi_vect); | |
| 122 return CYG_ISR_HANDLED | CYG_ISR_CALL_DSR; | |
| 123 } | |
| 124 | |
| 125 static void | |
| 126 spi_lpc2xxx_dsr(cyg_vector_t vec, cyg_ucount32 count, cyg_addrword_t data) | |
| 127 { | |
| 128 cyg_drv_cond_signal(&((cyg_spi_lpc2xxx_bus_t *) data)->spi_wait); | |
| 129 } | |
| 130 | |
| 131 | |
| 132 /* | |
| 133 * Configure bus for a specific baud rate | |
| 134 */ | |
| 135 static void | |
| 136 spi_lpc2xxx_baud(cyg_spi_lpc2xxx_bus_t *bus, cyg_uint32 baud) | |
| 137 { | |
| 138 cyg_uint32 ccr = 8; | |
| 139 | |
| 140 if(baud) { | |
| 141 ccr = (CYGNUM_HAL_ARM_LPC2XXX_CLOCK_SPEED | |
| 142 / CYGNUM_HAL_ARM_LPC2XXX_VPBDIV) / baud; | |
| 143 if(((CYGNUM_HAL_ARM_LPC2XXX_CLOCK_SPEED | |
| 144 / CYGNUM_HAL_ARM_LPC2XXX_VPBDIV) / ccr) > baud) | |
| 145 ccr++; | |
| 146 ccr++; | |
| 147 ccr &= 0xfe; | |
| 148 } | |
| 149 | |
| 150 bus->spi_dev->spccr = ccr < 8 ? 8 : ccr; | |
| 151 } | |
| 152 | |
| 153 /* | |
| 154 * get/set configuration | |
| 155 */ | |
| 156 static int | |
| 157 spi_lpc2xxx_get_config(cyg_spi_device *device, cyg_uint32 key, void *buf, | |
| 158 cyg_uint32 *len) | |
| 159 { | |
| 160 cyg_spi_lpc2xxx_dev_t *dev = (cyg_spi_lpc2xxx_dev_t *) device; | |
| 161 | |
| 162 switch(key) { | |
| 163 case CYG_IO_GET_CONFIG_SPI_CLOCKRATE: | |
| 164 if(*len == sizeof(cyg_uint32)) { | |
| 165 cyg_uint32 *b = (cyg_uint32 *) buf; | |
| 166 *b = dev->spi_baud; | |
| 167 } else return -EINVAL; | |
| 168 break; | |
| 169 default: | |
| 170 return -EINVAL; | |
| 171 } | |
| 172 | |
| 173 return ENOERR; | |
| 174 } | |
| 175 | |
| 176 static int | |
| 177 spi_lpc2xxx_set_config(cyg_spi_device *device, cyg_uint32 key, const void *buf, | |
| 178 cyg_uint32 *len) | |
| 179 { | |
| 180 cyg_spi_lpc2xxx_dev_t *dev = (cyg_spi_lpc2xxx_dev_t *) device; | |
| 181 | |
| 182 switch(key) { | |
|
2809
a0730cb32880
* cdl/spi_lpc2xxx.cdl: Ensure the SPI interrupts are using different
jlarmour
parents:
2788
diff
changeset
|
183 case CYG_IO_SET_CONFIG_SPI_CLOCKRATE: |
| 2506 | 184 if(*len == sizeof(cyg_uint32)) { |
| 185 dev->spi_baud = * (cyg_uint32 *) buf; | |
| 186 spi_lpc2xxx_baud((cyg_spi_lpc2xxx_bus_t *) dev->spi_device.spi_bus, | |
| 187 dev->spi_baud); | |
| 188 } | |
| 189 else return -EINVAL; | |
| 190 break; | |
| 191 default: | |
| 192 return -EINVAL; | |
| 193 } | |
| 194 | |
| 195 return ENOERR; | |
| 196 } | |
| 197 | |
| 198 | |
| 199 /* | |
| 200 * Begin transaction | |
| 201 * configure bus for device and drive CS by calling device cs() function | |
| 202 */ | |
| 203 static void | |
| 204 spi_lpc2xxx_begin(cyg_spi_device *device) | |
| 205 { | |
| 206 cyg_spi_lpc2xxx_dev_t *dev = (cyg_spi_lpc2xxx_dev_t *) device; | |
| 207 cyg_spi_lpc2xxx_bus_t *bus = | |
| 208 (cyg_spi_lpc2xxx_bus_t *) dev->spi_device.spi_bus; | |
| 209 | |
| 210 cyg_uint8 cr = | |
| 211 (dev->spi_cpha ? SPI_SPCR_CPHA : 0) | | |
| 212 (dev->spi_cpol ? SPI_SPCR_CPOL : 0) | | |
| 213 (dev->spi_lsbf ? SPI_SPCR_LSBF : 0); | |
| 214 | |
| 215 bus->spi_dev->spcr = SPI_SPCR_MSTR | cr; | |
| 216 | |
| 217 spi_lpc2xxx_baud(bus, dev->spi_baud); | |
| 218 | |
| 219 dev->spi_cs(1); | |
| 220 } | |
| 221 | |
| 222 | |
| 223 /* | |
| 224 * Transfer a buffer to a device, | |
| 225 * fill another buffer with data from the device | |
| 226 */ | |
| 227 static void | |
| 228 spi_lpc2xxx_transfer(cyg_spi_device *device, cyg_bool polled, cyg_uint32 count, | |
| 229 const cyg_uint8 *tx_data, cyg_uint8 *rx_data, | |
| 230 cyg_bool drop_cs) | |
| 231 { | |
| 232 cyg_spi_lpc2xxx_dev_t *dev = (cyg_spi_lpc2xxx_dev_t *) device; | |
| 233 cyg_spi_lpc2xxx_bus_t *bus = | |
| 234 (cyg_spi_lpc2xxx_bus_t *) dev->spi_device.spi_bus; | |
| 235 cyg_uint8 tmp; | |
| 236 | |
| 237 if(!count) return; | |
| 238 | |
| 239 if(!polled) { | |
| 240 bus->count = count; | |
| 241 bus->tx = tx_data; | |
| 242 bus->rx = rx_data; | |
| 243 | |
| 244 bus->spi_dev->spcr |= SPI_SPCR_SPIE; | |
| 245 bus->spi_dev->spdr = bus->tx ? *bus->tx++ : 0; | |
| 246 | |
| 247 cyg_drv_mutex_lock(&bus->spi_lock); | |
| 248 cyg_drv_dsr_lock(); | |
| 249 cyg_drv_interrupt_unmask(bus->spi_vect); | |
| 250 while(bus->count) | |
| 251 cyg_drv_cond_wait(&bus->spi_wait); | |
| 252 cyg_drv_interrupt_mask(bus->spi_vect); | |
| 253 cyg_drv_dsr_unlock(); | |
| 254 cyg_drv_mutex_unlock(&bus->spi_lock); | |
| 255 } else do { | |
| 256 bus->spi_dev->spdr = tx_data ? *tx_data++ : 0; | |
| 257 while(!(bus->spi_dev->spsr & SPI_SPSR_SPIF)); | |
| 258 tmp = bus->spi_dev->spdr; | |
| 259 if(rx_data) | |
| 260 *rx_data++ = tmp; | |
| 261 count--; | |
| 262 } while(count); | |
| 263 | |
| 264 if(drop_cs) | |
| 265 dev->spi_cs(0); | |
| 266 | |
| 267 return; | |
| 268 } | |
| 269 | |
| 270 | |
| 271 /* | |
| 272 * Tick | |
| 273 */ | |
| 274 static void | |
| 275 spi_lpc2xxx_tick(cyg_spi_device *device, cyg_bool polled, cyg_uint32 count) | |
| 276 { | |
| 277 spi_lpc2xxx_transfer(device, polled, count, NULL, NULL, false); | |
| 278 } | |
| 279 | |
| 280 | |
| 281 /* | |
| 282 * End transaction | |
| 283 * disable SPI bus, drop CS, reset transfer variables | |
| 284 */ | |
| 285 static void | |
| 286 spi_lpc2xxx_end(cyg_spi_device *device) | |
| 287 { | |
| 288 cyg_spi_lpc2xxx_dev_t *dev = (cyg_spi_lpc2xxx_dev_t *) device; | |
| 289 cyg_spi_lpc2xxx_bus_t *bus = | |
| 290 (cyg_spi_lpc2xxx_bus_t *) dev->spi_device.spi_bus; | |
| 291 | |
| 292 bus->spi_dev->spcr = 0; | |
| 293 dev->spi_cs(0); | |
| 294 | |
| 295 bus->count = 0; | |
| 296 bus->tx = NULL; | |
| 297 bus->rx = NULL; | |
| 298 } | |
| 299 | |
| 300 | |
| 301 /* | |
| 302 * Driver & bus initialization | |
| 303 */ | |
| 304 static void | |
| 305 spi_lpc2xxx_init_bus(cyg_spi_lpc2xxx_bus_t *bus, | |
| 306 cyg_addrword_t dev, | |
|
2809
a0730cb32880
* cdl/spi_lpc2xxx.cdl: Ensure the SPI interrupts are using different
jlarmour
parents:
2788
diff
changeset
|
307 cyg_vector_t vec, |
|
a0730cb32880
* cdl/spi_lpc2xxx.cdl: Ensure the SPI interrupts are using different
jlarmour
parents:
2788
diff
changeset
|
308 cyg_priority_t prio) |
| 2506 | 309 { |
| 310 bus->spi_bus.spi_transaction_begin = spi_lpc2xxx_begin; | |
| 311 bus->spi_bus.spi_transaction_transfer = spi_lpc2xxx_transfer; | |
| 312 bus->spi_bus.spi_transaction_tick = spi_lpc2xxx_tick; | |
| 313 bus->spi_bus.spi_transaction_end = spi_lpc2xxx_end; | |
| 314 bus->spi_bus.spi_get_config = spi_lpc2xxx_get_config; | |
| 315 bus->spi_bus.spi_set_config = spi_lpc2xxx_set_config; | |
| 316 CYG_SPI_BUS_COMMON_INIT(&bus->spi_bus); | |
| 317 | |
| 318 cyg_drv_mutex_init(&bus->spi_lock); | |
| 319 cyg_drv_cond_init(&bus->spi_wait, &bus->spi_lock); | |
| 320 | |
| 321 bus->spi_dev = (struct spi_dev *) dev; | |
| 322 bus->spi_vect = vec; | |
|
2809
a0730cb32880
* cdl/spi_lpc2xxx.cdl: Ensure the SPI interrupts are using different
jlarmour
parents:
2788
diff
changeset
|
323 bus->spi_prio = prio; |
| 2506 | 324 cyg_drv_interrupt_create( |
|
2809
a0730cb32880
* cdl/spi_lpc2xxx.cdl: Ensure the SPI interrupts are using different
jlarmour
parents:
2788
diff
changeset
|
325 vec, prio, (cyg_addrword_t) bus, |
| 2506 | 326 &spi_lpc2xxx_isr, &spi_lpc2xxx_dsr, |
| 327 &bus->spi_hand, &bus->spi_intr); | |
| 328 cyg_drv_interrupt_attach(bus->spi_hand); | |
| 329 } | |
| 330 | |
| 331 /* | |
| 332 * initialization class | |
| 333 */ | |
| 334 class cyg_spi_lpc2xxx_init_class { | |
| 335 public: | |
| 336 cyg_spi_lpc2xxx_init_class(void) { | |
| 337 cyg_uint32 addr, tmp; | |
| 338 | |
| 339 #ifdef CYGPKG_DEVS_SPI_ARM_LPC2XXX_BUS0 | |
| 340 addr = (CYGARC_HAL_LPC2XXX_REG_PIN_BASE | |
| 341 + CYGARC_HAL_LPC2XXX_REG_PINSEL0); | |
| 342 HAL_READ_UINT32(addr, tmp); | |
| 343 tmp |= 0x5500; | |
| 344 HAL_WRITE_UINT32(addr, tmp); | |
| 345 | |
| 346 spi_lpc2xxx_init_bus(&cyg_spi_lpc2xxx_bus0, | |
| 347 CYGARC_HAL_LPC2XXX_REG_SPI0_BASE, | |
|
2809
a0730cb32880
* cdl/spi_lpc2xxx.cdl: Ensure the SPI interrupts are using different
jlarmour
parents:
2788
diff
changeset
|
348 CYGNUM_HAL_INTERRUPT_SPI0, |
|
2811
3fdf0d74f32d
Silly omission in previous checkin in transposition of patch by jifl
jlarmour
parents:
2809
diff
changeset
|
349 CYGNUM_IO_SPI_ARM_LPC2XXX_BUS0_INTPRIO); |
| 2506 | 350 #endif |
| 351 #ifdef CYGPKG_DEVS_SPI_ARM_LPC2XXX_BUS1 | |
| 352 addr = (CYGARC_HAL_LPC2XXX_REG_PIN_BASE | |
| 353 + CYGARC_HAL_LPC2XXX_REG_PINSEL1); | |
| 354 HAL_READ_UINT32(addr, tmp); | |
| 355 tmp |= 0x2a8; | |
| 356 HAL_WRITE_UINT32(addr, tmp); | |
| 357 spi_lpc2xxx_init_bus(&cyg_spi_lpc2xxx_bus1, | |
| 358 CYGARC_HAL_LPC2XXX_REG_SPI1_BASE, | |
|
2809
a0730cb32880
* cdl/spi_lpc2xxx.cdl: Ensure the SPI interrupts are using different
jlarmour
parents:
2788
diff
changeset
|
359 CYGNUM_HAL_INTERRUPT_SPI1, |
|
2811
3fdf0d74f32d
Silly omission in previous checkin in transposition of patch by jifl
jlarmour
parents:
2809
diff
changeset
|
360 CYGNUM_IO_SPI_ARM_LPC2XXX_BUS1_INTPRIO); |
| 2506 | 361 #endif |
| 362 } | |
| 363 }; | |
| 364 | |
| 365 static cyg_spi_lpc2xxx_init_class spi_lpc2xxx_init | |
| 2788 | 366 CYGBLD_ATTRIB_INIT_PRI(CYG_INIT_BUS_SPI); |
| 2506 | 367 |
