Changeset fe83cef6 in rtems
- Timestamp:
- 01/11/10 16:14:47 (14 years ago)
- Branches:
- 4.10, 4.11, 5, master
- Children:
- 29a3d72c
- Parents:
- 04a82e9c
- Location:
- c/src/lib/libcpu/bfin
- Files:
-
- 5 edited
Legend:
- Unmodified
- Added
- Removed
-
c/src/lib/libcpu/bfin/ChangeLog
r04a82e9c rfe83cef6 1 2010-01-11 Allan Hessenflow <allanh@kallisti.com> 2 3 * serial/spi.c, serial/spi.h: 4 Fill in skeleton with functional SPI master code. 5 * include/spiRegs.h: 6 Correct spi shadow register declaration. 7 1 8 2009-12-11 Ralf Corsépius <ralf.corsepius@rtems.org> 2 9 -
c/src/lib/libcpu/bfin/README
r04a82e9c rfe83cef6 10 10 processor variant they're being built for. 11 11 12 serial/sp i* and serial/sport* are currently just placeholders.13 serial/twi* does not contain enough code to do anything useful; 14 it is however a start at anI2C driver.12 serial/sport* is currently just a placeholders. serial/twi* does not 13 contain enough code to do anything useful; it is however a start at an 14 I2C driver. 15 15 -
c/src/lib/libcpu/bfin/include/spiRegs.h
r04a82e9c rfe83cef6 1 1 /* Blackfin SPI Registers 2 2 * 3 * Copyright (c) 20 08Kallisti Labs, Los Gatos, CA, USA3 * Copyright (c) 2010 Kallisti Labs, Los Gatos, CA, USA 4 4 * written by Allan Hessenflow <allanh@kallisti.com> 5 5 * … … 23 23 #define SPI_RDBR_OFFSET 0x0010 24 24 #define SPI_BAUD_OFFSET 0x0014 25 #define SPI_SHADOW 25 #define SPI_SHADOW_OFFSET 0x0018 26 26 27 27 -
c/src/lib/libcpu/bfin/serial/spi.c
r04a82e9c rfe83cef6 1 /* placeholder (just a shell) */2 3 1 /* SPI driver for Blackfin 4 2 * 5 * Copyright (c) 20 08Kallisti Labs, Los Gatos, CA, USA3 * Copyright (c) 2010 Kallisti Labs, Los Gatos, CA, USA 6 4 * written by Allan Hessenflow <allanh@kallisti.com> 7 5 * … … 13 11 */ 14 12 15 16 13 #include <stdlib.h> 17 #include <rtems.h> 14 #include <bsp.h> 15 #include <rtems/error.h> 16 #include <rtems/bspIo.h> 17 #include <errno.h> 18 18 #include <rtems/libi2c.h> 19 20 19 #include <libcpu/spiRegs.h> 21 20 #include "spi.h" 22 21 23 22 24 static rtems_status_code spiInit(rtems_libi2c_bus_t *bus) { 25 bfin_spi_softc_t *softc; 26 rtems_status_code status; 27 28 softc = &(((bfin_spi_desc_t *)(bus))->softc); 29 30 status = rtems_semaphore_create(rtems_build_name('s','p','i','s'), 23 #ifndef BFIN_REG16 24 #define BFIN_REG16(base, offset) \ 25 (*((uint16_t volatile *) ((uint8_t *)(base) + (offset)))) 26 #endif 27 28 29 static bfin_spi_state_t *bfin_spi; 30 31 32 void bfin_spi_isr(int v) { 33 bfin_spi_state_t *state; 34 uint16_t r; 35 36 state = bfin_spi; 37 if (state->len > state->bytes_per_word) { 38 if (state->wr_ptr) { 39 if (state->bytes_per_word == 2) 40 r = *(uint16_t *) state->wr_ptr; 41 else 42 r = (uint16_t) *state->wr_ptr; 43 state->wr_ptr += state->bytes_per_word; 44 } else 45 r = state->idle_pattern; 46 BFIN_REG16(state->base, SPI_TDBR_OFFSET) = r; 47 } 48 state->len -= state->bytes_per_word; 49 if (state->len <= 0) { 50 /* 51 The transfers are done, so I don't want to kick off another 52 transfer or get any more interrupts. Reading the last word from 53 SPI_SHADOW instead of SPI_RDBR should prevent it from triggering 54 another transfer, but that doesn't clear the interrupt flag. I 55 could mask the interrupt in the SIC, but that would preclude ever 56 using the DMA channel that shares the interrupt independently (and 57 they might just share it with something more important in some other 58 member of the Blackfin family). And who knows what problems it 59 might cause in this code potentially dealing with that still pended 60 interrupt at the beginning of the next transfer. 61 62 So instead I disable the SPI interface, read the data from RDBR 63 (thus clearing the interrupt but not triggering another transfer 64 since the interface is disabled), then re-eanble the interface. 65 This has the problem that the bf537 tri-states the SPI signals 66 while the interface is disabled. Either adding pull-ups on at 67 least the chip select signals, or using GPIOs for them so they're 68 not controlled by the SPI module, would be correct fixes for that 69 (really pull-ups/downs should be added to the SPI CLK and MOSI 70 signals as well to insure they cannot float into some region that 71 causes input structures to consume excessive power). Or they can 72 all be left alone, assuming that there's enough capacitance on the 73 lines to prevent any problems for the short time they're being left 74 disabled. 75 76 An alternative approach I attempted involved switching TIMOD 77 between RDBR and TDBR when starting and finishing a transfer, but 78 I didn't get anywhere with that. In my limited testing TIMOD TDBR 79 wasn't behaving as I expected it to, but maybe with more 80 experimentation I'd find some solution there. However I'm out 81 of time for this project, at least for now. 82 */ 83 84 BFIN_REG16(state->base, SPI_CTL_OFFSET) &= ~SPI_CTL_SPE; 85 r = BFIN_REG16(state->base, SPI_RDBR_OFFSET); 86 BFIN_REG16(state->base, SPI_CTL_OFFSET) |= SPI_CTL_SPE; 87 rtems_semaphore_release(state->sem); 88 } else 89 r = BFIN_REG16(state->base, SPI_RDBR_OFFSET); 90 91 if (state->rd_ptr) { 92 if (state->bytes_per_word == 2) 93 *(uint16_t *) state->rd_ptr = r; 94 else 95 *state->rd_ptr = (uint8_t) r; 96 state->rd_ptr += state->bytes_per_word; 97 } 98 } 99 100 static rtems_status_code setTFRMode(rtems_libi2c_bus_t *bus, 101 const rtems_libi2c_tfr_mode_t *tfrMode) { 102 rtems_status_code result; 103 bfin_spi_state_t *state; 104 uint32_t divisor; 105 uint16_t ctrl; 106 107 result = RTEMS_SUCCESSFUL; 108 state = &((bfin_spi_bus_t *) bus)->p; 109 110 if (result == RTEMS_SUCCESSFUL) { 111 if (tfrMode->bits_per_char != 8 && 112 tfrMode->bits_per_char != 16) 113 result = RTEMS_INVALID_NUMBER; 114 if (tfrMode->baudrate <= 0) 115 result = RTEMS_INVALID_NUMBER; 116 } 117 if (result == RTEMS_SUCCESSFUL) { 118 divisor = (SCLK / 2 + tfrMode->baudrate - 1) / 119 tfrMode->baudrate; 120 if (divisor < 2) 121 divisor = 2; 122 else if (divisor > 65535) 123 result = RTEMS_INVALID_NUMBER; 124 } 125 if (result == RTEMS_SUCCESSFUL) { 126 state->idle_pattern = (uint16_t) tfrMode->idle_char; 127 state->bytes_per_word = (tfrMode->bits_per_char > 8) ? 2 : 1; 128 BFIN_REG16(state->base, SPI_BAUD_OFFSET) = divisor; 129 ctrl = BFIN_REG16(state->base, SPI_CTL_OFFSET); 130 if (tfrMode->lsb_first) 131 ctrl |= SPI_CTL_LSBF; 132 else 133 ctrl &= ~SPI_CTL_LSBF; 134 if (tfrMode->bits_per_char > 8) 135 ctrl |= SPI_CTL_SIZE; 136 else 137 ctrl &= ~SPI_CTL_SIZE; 138 if (tfrMode->clock_inv) 139 ctrl |= SPI_CTL_CPOL; 140 else 141 ctrl &= ~SPI_CTL_CPOL; 142 if (tfrMode->clock_phs) 143 ctrl |= SPI_CTL_CPHA; 144 else 145 ctrl &= ~SPI_CTL_CPHA; 146 BFIN_REG16(state->base, SPI_CTL_OFFSET) = ctrl; 147 } 148 149 return result; 150 } 151 152 static int readWrite(rtems_libi2c_bus_t *bus, uint8_t *rdBuf, 153 const uint8_t *wrBuf, int len) { 154 rtems_status_code result; 155 bfin_spi_state_t *state; 156 uint16_t r; 157 158 result = RTEMS_SUCCESSFUL; 159 state = &((bfin_spi_bus_t *) bus)->p; 160 161 if (len) { 162 state->rd_ptr = rdBuf; 163 state->wr_ptr = wrBuf; 164 state->len = len; 165 if (state->wr_ptr) { 166 if (state->bytes_per_word == 2) 167 r = *(uint16_t *) state->wr_ptr; 168 else 169 r = (uint16_t) *state->wr_ptr; 170 state->wr_ptr += state->bytes_per_word; 171 } else 172 r = state->idle_pattern; 173 BFIN_REG16(state->base, SPI_TDBR_OFFSET) = r; 174 BFIN_REG16(state->base, SPI_RDBR_OFFSET); /* trigger */ 175 /* wait until done */ 176 do { 177 result = rtems_semaphore_obtain(state->sem, RTEMS_WAIT, 100); 178 } while (result == RTEMS_SUCCESSFUL && state->len > 0); 179 } 180 181 return (result == RTEMS_SUCCESSFUL) ? len : -result; 182 } 183 184 185 rtems_status_code bfin_spi_init(rtems_libi2c_bus_t *bus) { 186 rtems_status_code result; 187 bfin_spi_state_t *state; 188 189 state = &((bfin_spi_bus_t *) bus)->p; 190 191 BFIN_REG16(state->base, SPI_CTL_OFFSET) = SPI_CTL_SPE | 192 SPI_CTL_MSTR | 193 SPI_CTL_CPHA | 194 SPI_CTL_TIMOD_RDBR; 195 196 result = rtems_semaphore_create(rtems_build_name('s','p','i','s'), 31 197 0, 32 198 RTEMS_FIFO | RTEMS_SIMPLE_BINARY_SEMAPHORE, 33 199 0, 34 &softc->irq_sema_id); 35 36 return status; 37 } 38 39 static rtems_status_code spiSendStart(rtems_libi2c_bus_t *bus) { 40 bfin_spi_softc_t *softc; 41 rtems_status_code status; 42 43 status = RTEMS_SUCCESSFUL; 44 softc = &(((bfin_spi_desc_t *)(bus))->softc); 45 46 return status; 47 } 48 49 static rtems_status_code spiSendStop(rtems_libi2c_bus_t *bus) { 50 bfin_spi_softc_t *softc; 51 rtems_status_code status; 52 53 status = RTEMS_SUCCESSFUL; 54 softc = &(((bfin_spi_desc_t *)(bus))->softc); 55 56 return status; 57 } 58 59 static rtems_status_code spiSendAddr(rtems_libi2c_bus_t *bus, 60 uint32_t addr, int rw) { 61 bfin_spi_softc_t *softc; 62 rtems_status_code status; 63 64 status = RTEMS_SUCCESSFUL; 65 softc = &(((bfin_spi_desc_t *)(bus))->softc); 66 67 return status; 68 } 69 70 static int spiReadBytes(rtems_libi2c_bus_t *bus, 71 unsigned char *buf, int len) { 72 bfin_spi_softc_t *softc; 73 74 softc = &(((bfin_spi_desc_t *)(bus))->softc); 75 76 return 0; 77 } 78 79 static int spiWriteBytes(rtems_libi2c_bus_t *bus, 80 unsigned char *buf, int len) { 81 bfin_spi_softc_t *softc; 82 83 softc = &(((bfin_spi_desc_t *)(bus))->softc); 84 85 return 0; 86 } 87 88 static int spiIoctl(rtems_libi2c_bus_t *bus, int cmd, void *arg) { 89 bfin_spi_softc_t *softc; 90 91 softc = &(((bfin_spi_desc_t *)(bus))->softc); 92 93 94 return 0; 95 } 96 97 void bfin_spi_isr(int source) { 98 } 99 100 rtems_libi2c_bus_ops_t bfin_spi_libi2c_bus_ops = { 101 init: spiInit, 102 send_start: spiSendStart, 103 send_stop: spiSendStop, 104 send_addr: spiSendAddr, 105 read_bytes: spiReadBytes, 106 write_bytes: spiWriteBytes, 107 ioctl: spiIoctl 108 }; 109 200 &state->sem); 201 if (result == RTEMS_SUCCESSFUL) 202 bfin_spi = state; /* for isr */ 203 204 return result; 205 } 206 207 rtems_status_code bfin_spi_send_start(rtems_libi2c_bus_t *bus) { 208 209 return RTEMS_SUCCESSFUL; 210 } 211 212 int bfin_spi_read_bytes(rtems_libi2c_bus_t *bus, unsigned char *buf, int len) { 213 214 return readWrite(bus, buf, NULL, len); 215 } 216 217 int bfin_spi_write_bytes(rtems_libi2c_bus_t *bus, unsigned char *buf, int len) { 218 219 return readWrite(bus, NULL, buf, len); 220 } 221 222 int bfin_spi_ioctl(rtems_libi2c_bus_t *bus, int cmd, void *arg) { 223 int result; 224 225 result = -RTEMS_NOT_DEFINED; 226 switch(cmd) { 227 case RTEMS_LIBI2C_IOCTL_SET_TFRMODE: 228 result = -setTFRMode(bus, (const rtems_libi2c_tfr_mode_t *) arg); 229 break; 230 case RTEMS_LIBI2C_IOCTL_READ_WRITE: 231 result = readWrite(bus, 232 ((rtems_libi2c_read_write_t *) arg)->rd_buf, 233 ((rtems_libi2c_read_write_t *) arg)->wr_buf, 234 ((rtems_libi2c_read_write_t *) arg)->byte_cnt); 235 break; 236 default: 237 break; 238 } 239 240 return result; 241 } 242 -
c/src/lib/libcpu/bfin/serial/spi.h
r04a82e9c rfe83cef6 1 /* placeholder (just a shell) */2 3 1 /* 4 2 * RTEMS driver for Blackfin SPI 5 3 * 6 * COPYRIGHT (c) 20 08Kallisti Labs, Los Gatos, CA, USA4 * COPYRIGHT (c) 2010 Kallisti Labs, Los Gatos, CA, USA 7 5 * written by Allan Hessenflow <allanh@kallisti.com> 8 6 * … … 14 12 */ 15 13 16 17 #ifndef _spi_h_ 18 #define _spi_h_ 19 14 #ifndef _spi_h 15 #define _spi_h 20 16 21 17 #ifdef __cplusplus … … 23 19 #endif 24 20 25 26 21 typedef struct { 27 /* parameters provided by bsp */ 28 uint32_t freq; 29 void *base; 30 bool fast; 31 /* internal use */ 32 rtems_id irq_sema_id; 33 } bfin_spi_softc_t; 22 void *base; 23 /* remaining entries are for internal use */ 24 rtems_id sem; 25 int bytes_per_word; 26 uint16_t idle_pattern; 27 uint8_t *rd_ptr; 28 const uint8_t *wr_ptr; 29 int len; 30 } bfin_spi_state_t; 34 31 35 32 typedef struct { 36 33 rtems_libi2c_bus_t bus; 37 bfin_spi_s oftc_t softc;38 } bfin_spi_ desc_t;34 bfin_spi_state_t p; 35 } bfin_spi_bus_t; 39 36 40 37 41 extern rtems_libi2c_bus_ops_t bfin_spi_libi2c_bus_ops;38 void bfin_spi_isr(int v); 42 39 40 rtems_status_code bfin_spi_init(rtems_libi2c_bus_t *bus); 43 41 44 void bfin_spi_isr(int source);42 rtems_status_code bfin_spi_send_start(rtems_libi2c_bus_t *bus); 45 43 44 int bfin_spi_read_bytes(rtems_libi2c_bus_t *bus, unsigned char *buf, int len); 45 46 int bfin_spi_write_bytes(rtems_libi2c_bus_t *bus, unsigned char *buf, int len); 47 48 int bfin_spi_ioctl(rtems_libi2c_bus_t *bus, int cmd, void *arg); 46 49 47 50 #ifdef __cplusplus … … 49 52 #endif 50 53 51 #endif /* _spi_h_ */52 54 55 #endif /* _spi_h */
Note: See TracChangeset
for help on using the changeset viewer.