1 /*******************************************************************
2 Components for embedded applications builded for
3 laboratory and medical instruments firmware
5 spi_lpcssp.c - SPI communication driver for LPC17xx SSP interface
7 Copyright holders and project originators
8 (C) 2001-2010 by Pavel Pisa pisa@cmp.felk.cvut.cz
9 (C) 2002-2010 by PiKRON Ltd. http://www.pikron.com
11 The COLAMI components can be used and copied under next licenses
12 - MPL - Mozilla Public License
13 - GPL - GNU Public License
14 - LGPL - Lesser GNU Public License
15 - and other licenses added by project originators
16 Code can be modified and re-distributed under any combination
17 of the above listed licenses. If contributor does not agree with
18 some of the licenses, he can delete appropriate line.
19 Warning, if you delete all lines, you are not allowed to
20 distribute code or build project.
21 *******************************************************************/
27 #include "spi_internal.h"
30 #include <system_def.h>
33 #define SSP_CR0_DSS_m 0x000f /* Data Size Select (num bits - 1) */
34 #define SSP_CR0_FRF_m 0x0030 /* Frame Format: 0 SPI, 1 TI, 2 Microwire */
35 #define SSP_CR0_CPOL_m 0x0040 /* SPI Clock Polarity. 0 low between frames, 1 high */
36 #define SSP_CR0_CPHA_m 0x0080 /* SPI Clock Phase. 0 capture in midle, 1 at end */
37 #define SSP_CR0_SCR_m 0xff00 /* Serial Clock Rate. PCLK / (CPSDVSR × [SCR+1]) */
39 #define SSP_CR1_LBM_m 0x0001 /* Loop Back Mode */
40 #define SSP_CR1_SSE_m 0x0002 /* SSP Enable */
41 #define SSP_CR1_MS_m 0x0004 /* Master (0)/Slave (1) Mode */
42 #define SSP_CR1_SOD_m 0x0008 /* Slave Output Disable */
44 #define SSP_SR_TFE_m 0x0001 /* Tx FIFO Empty */
45 #define SSP_SR_TNF_m 0x0002 /* Tx FIFO Not Full */
46 #define SSP_SR_RNE_m 0x0004 /* Rx FIFO Not Empty */
47 #define SSP_SR_RFF_m 0x0008 /* Rx FIFO Full */
48 #define SSP_SR_BSY_m 0x0010 /* SSP is busy or the Tx FIFO is not empty */
50 /* interrupt sources assignment for IMSC, RIS, MIS and ICR registers */
51 #define SSP_IRQ_ROR_m 1 /* Rx frame owerwritten old data in full Rx FIFO */
52 #define SSP_IRQ_RT_m 2 /* Rx FIFO is not empty and not read in timeout */
53 #define SSP_IRQ_RX_m 4 /* Rx FIFO is at least half full */
54 #define SSP_IRQ_TX_m 8 /* Tx FIFO is at least half empty */
56 #define SSP_DMACR_RXDMAE_m 0x1 /* DMA for the Rx FIFO enable */
57 #define SSP_DMACR_TXDMAE_m 0x2 /* DMA for the Tx FIFO enable */
59 /********************************************************************/
60 /* Motorola LPC17xx SSP specific SPI functions */
62 IRQ_HANDLER_FNC(spi_lpcssp_isr);
63 static int spi_lpcssp_ctrl_fnc(struct spi_drv *ifc, int ctrl, void *p);
65 #define SPI_LPCSSP_CS_PIN_COUNT 4
67 typedef struct spi_lpcssp_drv {
71 rtems_irq_connect_data *irq_data;
73 typeof(SSP0) ssp_regs;
75 unsigned cs_gpio_pin[SPI_LPCSSP_CS_PIN_COUNT];
81 #define SSP_PIN_NA ((unsigned)-1)
84 spi_lpcssp_assert_ss(spi_drv_t *ifc, int addr)
87 spi_lpcssp_drv_t *lpcssp_drv=UL_CONTAINEROF(ifc,spi_lpcssp_drv_t,spi_drv);
89 for(i = 0; i < SPI_LPCSSP_CS_PIN_COUNT; i++, addr >>= 1) {
90 if(lpcssp_drv->cs_gpio_pin[i]!=SSP_PIN_NA)
91 hal_gpio_set_value(lpcssp_drv->cs_gpio_pin[i], !(addr & 1));
96 spi_lpcssp_negate_ss(spi_drv_t *ifc)
99 spi_lpcssp_drv_t *lpcssp_drv=UL_CONTAINEROF(ifc,spi_lpcssp_drv_t,spi_drv);
101 for(i = 0; i < SPI_LPCSSP_CS_PIN_COUNT; i++) {
102 if(lpcssp_drv->cs_gpio_pin[i]!=SSP_PIN_NA)
103 hal_gpio_set_value(lpcssp_drv->cs_gpio_pin[i], 1);
107 /* master transaction finished => generate STOP */
109 spi_lpcssp_sfnc_ms_end(struct spi_drv *ifc, int code)
111 spi_isr_lock_level_t saveif;
114 spi_isr_lock(saveif);
117 spi_isr_unlock(saveif);
119 spi_rq_queue_del_item(msg);
120 msg->flags|=SPI_MSG_FINISHED;
122 spi_isr_unlock(saveif);
124 msg->callback(ifc,SPI_MSG_FINISHED,msg);
131 /* master mode error condition */
133 spi_lpcssp_sfnc_ms_err(struct spi_drv *ifc, int code)
135 spi_isr_lock_level_t saveif;
138 spi_isr_lock(saveif);
141 spi_isr_unlock(saveif);
143 spi_rq_queue_del_item(msg);
144 msg->flags|=SPI_MSG_FAIL;
146 spi_isr_unlock(saveif);
149 msg->callback(ifc,SPI_MSG_FAIL,msg);
156 IRQ_HANDLER_FNC(spi_lpcssp_isr)
158 spi_isr_lock_level_t saveif;
160 unsigned dr, rxcnt, txcnt, rq_len;
163 spi_lpcssp_drv_t *lpcssp_drv = (spi_lpcssp_drv_t*)irq_handler_get_context();
166 msg=lpcssp_drv->spi_drv.msg_act;
168 spi_isr_lock(saveif);
169 msg=lpcssp_drv->spi_drv.msg_act=spi_rq_queue_first(&lpcssp_drv->spi_drv);
170 spi_isr_unlock(saveif);
172 lpcssp_drv->ssp_regs->IMSC = 0;
175 while(lpcssp_drv->ssp_regs->SR & SSP_SR_RNE_m)
176 dr=lpcssp_drv->ssp_regs->DR;
178 lpcssp_drv->txcnt = 0;
179 lpcssp_drv->rxcnt = 0;
180 lpcssp_drv->data16_fl = 0;
182 spi_lpcssp_assert_ss(&lpcssp_drv->spi_drv, msg->addr);
185 data16_fl = lpcssp_drv->data16_fl;
186 rq_len = msg->rq_len;
188 rxcnt = lpcssp_drv->rxcnt;
189 txcnt = lpcssp_drv->txcnt;
191 lpcssp_drv->ssp_regs->ICR = SSP_IRQ_RT_m;
193 while(lpcssp_drv->ssp_regs->SR & SSP_SR_RNE_m) {
194 dr = lpcssp_drv->ssp_regs->DR;
195 if(msg->rx_buf && (rxcnt < rq_len)) {
196 msg->rx_buf[rxcnt++] = dr;
198 msg->rx_buf[rxcnt++] = dr >> 16;
203 stop_fl = !(lpcssp_drv->ssp_regs->SR & SSP_SR_TNF_m) || (txcnt >= rq_len);
208 dr = msg->tx_buf[txcnt++];
210 dr |= msg->rx_buf[txcnt++] << 8;
212 txcnt += data16_fl? 2: 1;
214 lpcssp_drv->ssp_regs->DR = dr;
215 if(lpcssp_drv->ssp_regs->SR & SSP_SR_RNE_m)
219 lpcssp_drv->rxcnt = rxcnt;
220 lpcssp_drv->txcnt = txcnt;
222 if((rxcnt >= rq_len) ||
223 (!msg->rx_buf && (txcnt >= rq_len) &&
224 !(lpcssp_drv->ssp_regs->SR & SSP_SR_BSY_m))) {
225 spi_lpcssp_negate_ss(&lpcssp_drv->spi_drv);
226 spi_lpcssp_sfnc_ms_end(&lpcssp_drv->spi_drv, 0);
230 lpcssp_drv->ssp_regs->IMSC = SSP_IRQ_TX_m;
232 lpcssp_drv->ssp_regs->IMSC = SSP_IRQ_RX_m | SSP_IRQ_RT_m;
238 static int spi_lpcssp_ctrl_fnc(spi_drv_t *ifc, int ctrl, void *p)
240 spi_lpcssp_drv_t *lpcssp_drv=UL_CONTAINEROF(ifc,spi_lpcssp_drv_t,spi_drv);
243 case SPI_CTRL_WAKE_RQ:
244 if(!(ifc->flags&SPI_IFC_ON))
246 if(spi_rq_queue_is_empty(ifc))
249 rtems_event_send(lpcssp_drv->task, SPI_EVENT_WAKE_RQ);
251 lpcssp_drv->ssp_regs->IMSC = SSP_IRQ_TX_m;
252 #endif /*WITH_RTEMS*/
260 int spi_lpcssp_init(spi_drv_t *ifc)
263 spi_lpcssp_drv_t *lpcssp_drv=UL_CONTAINEROF(ifc,spi_lpcssp_drv_t,spi_drv);
264 spi_isr_lock_level_t saveif;
266 lpcssp_drv->ssp_regs->IMSC = 0;
267 lpcssp_drv->ssp_regs->CR1 = SSP_CR1_SSE_m * 0;
269 spi_rq_queue_init_head(ifc);
271 ifc->ctrl_fnc=spi_lpcssp_ctrl_fnc;
273 if(lpcssp_drv->ssp_regs == SSP0) {
274 SC->PCONP |= (21 << 10); /*PCSSP0*/
276 hal_pin_conf(SCK0_PIN);
279 hal_pin_conf(SSEL0_PIN);
282 hal_pin_conf(MISO0_PIN);
285 hal_pin_conf(MOSI0_PIN);
287 } else if(lpcssp_drv->ssp_regs == SSP1) {
288 SC->PCONP |= (1 << 10); /*PCSSP1*/
290 hal_pin_conf(SCK1_PIN);
293 hal_pin_conf(SSEL1_PIN);
296 hal_pin_conf(MISO1_PIN);
299 hal_pin_conf(MOSI1_PIN);
303 request_irq(lpcssp_drv->irqnum, spi_lpcssp_isr, 0, "spi", lpcssp_drv);
305 lpcssp_drv->ssp_regs->CR0 = __val2mfld(SSP_CR0_DSS_m, 8 - 1) | __val2mfld(SSP_CR0_FRF_m, 0) |
306 SSP_CR0_CPOL_m * 1 | SSP_CR0_CPHA_m * 1 |
307 __val2mfld(SSP_CR0_SCR_m, 15);
308 lpcssp_drv->ssp_regs->CR1 = SSP_CR1_LBM_m * 0 | SSP_CR1_SSE_m * 1 | SSP_CR1_MS_m * 0 |
311 for(i = 0; i < SPI_LPCSSP_CS_PIN_COUNT; i++) {
312 if(lpcssp_drv->cs_gpio_pin[i]!=SSP_PIN_NA)
313 hal_pin_conf(lpcssp_drv->cs_gpio_pin[i]);
316 lpcssp_drv->ssp_regs->CPSR = 2;
318 spi_isr_lock(saveif);
319 ifc->flags |= SPI_IFC_ON;
320 spi_isr_unlock(saveif);
325 spi_lpcssp_drv_t spi0_lpcssp_drv = {
329 .ctrl_fnc=spi_lpcssp_ctrl_fnc,
357 spi_lpcssp_drv_t spi1_lpcssp_drv = {
361 .ctrl_fnc=spi_lpcssp_ctrl_fnc,
389 spi_drv_t *spi_find_drv(char *name, int number)
394 if(number>1) return NULL;
396 ifc=&spi0_lpcssp_drv.spi_drv;
398 ifc=&spi1_lpcssp_drv.spi_drv;
399 if(!(ifc->flags&SPI_IFC_ON)){
400 ret=spi_lpcssp_init(ifc);
401 if(ret<0) return NULL;