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 #if !defined(SSP0) && defined(LPC_SSP0)
36 #if !defined(SSP1) && defined(LPC_SSP1)
39 #if !defined(SSP2) && defined(LPC_SSP2)
42 #if !defined(SC) && defined(LPC_SC)
46 #define SSP_CR0_DSS_m 0x000f /* Data Size Select (num bits - 1) */
47 #define SSP_CR0_FRF_m 0x0030 /* Frame Format: 0 SPI, 1 TI, 2 Microwire */
48 #define SSP_CR0_CPOL_m 0x0040 /* SPI Clock Polarity. 0 low between frames, 1 high */
49 #define SSP_CR0_CPHA_m 0x0080 /* SPI Clock Phase. 0 capture in midle, 1 at end */
50 #define SSP_CR0_SCR_m 0xff00 /* Serial Clock Rate. PCLK / (CPSDVSR × [SCR+1]) */
52 #define SSP_CR1_LBM_m 0x0001 /* Loop Back Mode */
53 #define SSP_CR1_SSE_m 0x0002 /* SSP Enable */
54 #define SSP_CR1_MS_m 0x0004 /* Master (0)/Slave (1) Mode */
55 #define SSP_CR1_SOD_m 0x0008 /* Slave Output Disable */
57 #define SSP_SR_TFE_m 0x0001 /* Tx FIFO Empty */
58 #define SSP_SR_TNF_m 0x0002 /* Tx FIFO Not Full */
59 #define SSP_SR_RNE_m 0x0004 /* Rx FIFO Not Empty */
60 #define SSP_SR_RFF_m 0x0008 /* Rx FIFO Full */
61 #define SSP_SR_BSY_m 0x0010 /* SSP is busy or the Tx FIFO is not empty */
63 /* interrupt sources assignment for IMSC, RIS, MIS and ICR registers */
64 #define SSP_IRQ_ROR_m 1 /* Rx frame owerwritten old data in full Rx FIFO */
65 #define SSP_IRQ_RT_m 2 /* Rx FIFO is not empty and not read in timeout */
66 #define SSP_IRQ_RX_m 4 /* Rx FIFO is at least half full */
67 #define SSP_IRQ_TX_m 8 /* Tx FIFO is at least half empty */
69 #define SSP_DMACR_RXDMAE_m 0x1 /* DMA for the Rx FIFO enable */
70 #define SSP_DMACR_TXDMAE_m 0x2 /* DMA for the Tx FIFO enable */
72 /********************************************************************/
73 /* Motorola LPC17xx SSP specific SPI functions */
75 IRQ_HANDLER_FNC(spi_lpcssp_isr);
76 static int spi_lpcssp_ctrl_fnc(struct spi_drv *ifc, int ctrl, void *p);
78 #define SPI_LPCSSP_CS_PIN_COUNT 4
80 typedef struct spi_lpcssp_drv {
84 rtems_irq_connect_data *irq_data;
86 typeof(SSP0) ssp_regs;
88 unsigned cs_gpio_pin[SPI_LPCSSP_CS_PIN_COUNT];
94 #define SSP_PIN_NA ((unsigned)-1)
97 spi_lpcssp_assert_ss(spi_drv_t *ifc, int addr)
100 spi_lpcssp_drv_t *lpcssp_drv=UL_CONTAINEROF(ifc,spi_lpcssp_drv_t,spi_drv);
102 for(i = 0; i < SPI_LPCSSP_CS_PIN_COUNT; i++, addr >>= 1) {
103 if(lpcssp_drv->cs_gpio_pin[i]!=SSP_PIN_NA)
104 hal_gpio_set_value(lpcssp_drv->cs_gpio_pin[i], !(addr & 1));
109 spi_lpcssp_negate_ss(spi_drv_t *ifc)
112 spi_lpcssp_drv_t *lpcssp_drv=UL_CONTAINEROF(ifc,spi_lpcssp_drv_t,spi_drv);
114 for(i = 0; i < SPI_LPCSSP_CS_PIN_COUNT; i++) {
115 if(lpcssp_drv->cs_gpio_pin[i]!=SSP_PIN_NA)
116 hal_gpio_set_value(lpcssp_drv->cs_gpio_pin[i], 1);
120 /* master transaction finished => generate STOP */
122 spi_lpcssp_sfnc_ms_end(struct spi_drv *ifc, int code)
124 spi_isr_lock_level_t saveif;
127 spi_isr_lock(saveif);
130 spi_isr_unlock(saveif);
132 spi_rq_queue_del_item(msg);
133 msg->flags|=SPI_MSG_FINISHED;
135 spi_isr_unlock(saveif);
137 msg->callback(ifc,SPI_MSG_FINISHED,msg);
144 /* master mode error condition */
146 spi_lpcssp_sfnc_ms_err(struct spi_drv *ifc, int code)
148 spi_isr_lock_level_t saveif;
151 spi_isr_lock(saveif);
154 spi_isr_unlock(saveif);
156 spi_rq_queue_del_item(msg);
157 msg->flags|=SPI_MSG_FAIL;
159 spi_isr_unlock(saveif);
162 msg->callback(ifc,SPI_MSG_FAIL,msg);
169 IRQ_HANDLER_FNC(spi_lpcssp_isr)
171 spi_isr_lock_level_t saveif;
173 unsigned dr, rxcnt, txcnt, rq_len;
176 spi_lpcssp_drv_t *lpcssp_drv = (spi_lpcssp_drv_t*)irq_handler_get_context();
179 msg=lpcssp_drv->spi_drv.msg_act;
181 spi_isr_lock(saveif);
182 msg=lpcssp_drv->spi_drv.msg_act=spi_rq_queue_first(&lpcssp_drv->spi_drv);
183 spi_isr_unlock(saveif);
185 lpcssp_drv->ssp_regs->IMSC = 0;
188 while(lpcssp_drv->ssp_regs->SR & SSP_SR_RNE_m)
189 dr=lpcssp_drv->ssp_regs->DR;
191 lpcssp_drv->txcnt = 0;
192 lpcssp_drv->rxcnt = 0;
193 lpcssp_drv->data16_fl = 0;
195 spi_lpcssp_assert_ss(&lpcssp_drv->spi_drv, msg->addr);
198 data16_fl = lpcssp_drv->data16_fl;
199 rq_len = msg->rq_len;
201 rxcnt = lpcssp_drv->rxcnt;
202 txcnt = lpcssp_drv->txcnt;
204 lpcssp_drv->ssp_regs->ICR = SSP_IRQ_RT_m;
206 while(lpcssp_drv->ssp_regs->SR & SSP_SR_RNE_m) {
207 dr = lpcssp_drv->ssp_regs->DR;
208 if(msg->rx_buf && (rxcnt < rq_len)) {
209 msg->rx_buf[rxcnt++] = dr;
211 msg->rx_buf[rxcnt++] = dr >> 16;
216 stop_fl = !(lpcssp_drv->ssp_regs->SR & SSP_SR_TNF_m) || (txcnt >= rq_len);
221 dr = msg->tx_buf[txcnt++];
223 dr |= msg->rx_buf[txcnt++] << 8;
225 txcnt += data16_fl? 2: 1;
227 lpcssp_drv->ssp_regs->DR = dr;
228 if(lpcssp_drv->ssp_regs->SR & SSP_SR_RNE_m)
232 lpcssp_drv->rxcnt = rxcnt;
233 lpcssp_drv->txcnt = txcnt;
235 if((rxcnt >= rq_len) ||
236 (!msg->rx_buf && (txcnt >= rq_len) &&
237 !(lpcssp_drv->ssp_regs->SR & SSP_SR_BSY_m))) {
238 spi_lpcssp_negate_ss(&lpcssp_drv->spi_drv);
239 spi_lpcssp_sfnc_ms_end(&lpcssp_drv->spi_drv, 0);
243 lpcssp_drv->ssp_regs->IMSC = SSP_IRQ_TX_m;
245 lpcssp_drv->ssp_regs->IMSC = SSP_IRQ_RX_m | SSP_IRQ_RT_m;
251 static int spi_lpcssp_ctrl_fnc(spi_drv_t *ifc, int ctrl, void *p)
253 spi_lpcssp_drv_t *lpcssp_drv=UL_CONTAINEROF(ifc,spi_lpcssp_drv_t,spi_drv);
256 case SPI_CTRL_WAKE_RQ:
257 if(!(ifc->flags&SPI_IFC_ON))
259 if(spi_rq_queue_is_empty(ifc))
262 rtems_event_send(lpcssp_drv->task, SPI_EVENT_WAKE_RQ);
264 lpcssp_drv->ssp_regs->IMSC = SSP_IRQ_TX_m;
265 #endif /*WITH_RTEMS*/
273 int spi_lpcssp_init(spi_drv_t *ifc)
276 spi_lpcssp_drv_t *lpcssp_drv=UL_CONTAINEROF(ifc,spi_lpcssp_drv_t,spi_drv);
277 spi_isr_lock_level_t saveif;
279 lpcssp_drv->ssp_regs->IMSC = 0;
280 lpcssp_drv->ssp_regs->CR1 = SSP_CR1_SSE_m * 0;
282 spi_rq_queue_init_head(ifc);
284 ifc->ctrl_fnc=spi_lpcssp_ctrl_fnc;
286 if(lpcssp_drv->ssp_regs == SSP0) {
287 SC->PCONP |= (21 << 10); /*PCSSP0*/
289 hal_pin_conf(SCK0_PIN);
292 hal_pin_conf(SSEL0_PIN);
295 hal_pin_conf(MISO0_PIN);
298 hal_pin_conf(MOSI0_PIN);
300 } else if(lpcssp_drv->ssp_regs == SSP1) {
301 SC->PCONP |= (1 << 10); /*PCSSP1*/
303 hal_pin_conf(SCK1_PIN);
306 hal_pin_conf(SSEL1_PIN);
309 hal_pin_conf(MISO1_PIN);
312 hal_pin_conf(MOSI1_PIN);
316 request_irq(lpcssp_drv->irqnum, spi_lpcssp_isr, 0, "spi", lpcssp_drv);
318 lpcssp_drv->ssp_regs->CR0 = __val2mfld(SSP_CR0_DSS_m, 8 - 1) | __val2mfld(SSP_CR0_FRF_m, 0) |
319 SSP_CR0_CPOL_m * 1 | SSP_CR0_CPHA_m * 1 |
320 __val2mfld(SSP_CR0_SCR_m, 15);
321 lpcssp_drv->ssp_regs->CR1 = SSP_CR1_LBM_m * 0 | SSP_CR1_SSE_m * 1 | SSP_CR1_MS_m * 0 |
324 for(i = 0; i < SPI_LPCSSP_CS_PIN_COUNT; i++) {
325 if(lpcssp_drv->cs_gpio_pin[i]!=SSP_PIN_NA)
326 hal_pin_conf(lpcssp_drv->cs_gpio_pin[i]);
329 lpcssp_drv->ssp_regs->CPSR = 2;
331 spi_isr_lock(saveif);
332 ifc->flags |= SPI_IFC_ON;
333 spi_isr_unlock(saveif);
338 spi_lpcssp_drv_t spi0_lpcssp_drv = {
342 .ctrl_fnc=spi_lpcssp_ctrl_fnc,
370 spi_lpcssp_drv_t spi1_lpcssp_drv = {
374 .ctrl_fnc=spi_lpcssp_ctrl_fnc,
402 spi_drv_t *spi_find_drv(char *name, int number)
407 if(number>1) return NULL;
409 ifc=&spi0_lpcssp_drv.spi_drv;
411 ifc=&spi1_lpcssp_drv.spi_drv;
412 if(!(ifc->flags&SPI_IFC_ON)){
413 ret=spi_lpcssp_init(ifc);
414 if(ret<0) return NULL;