Commit | Line | Data |
---|---|---|
529d6dad SB |
1 | /* |
2 | * Copyright (C) ST-Ericsson AB 2010 | |
c2cd0a56 | 3 | * Author: Daniel Martensson |
529d6dad SB |
4 | * License terms: GNU General Public License (GPL) version 2. |
5 | */ | |
529d6dad SB |
6 | #include <linux/init.h> |
7 | #include <linux/module.h> | |
8 | #include <linux/device.h> | |
9 | #include <linux/platform_device.h> | |
10 | #include <linux/string.h> | |
11 | #include <linux/semaphore.h> | |
12 | #include <linux/workqueue.h> | |
13 | #include <linux/completion.h> | |
14 | #include <linux/list.h> | |
15 | #include <linux/interrupt.h> | |
16 | #include <linux/dma-mapping.h> | |
17 | #include <linux/delay.h> | |
18 | #include <linux/sched.h> | |
19 | #include <linux/debugfs.h> | |
20 | #include <net/caif/caif_spi.h> | |
21 | ||
22 | #ifndef CONFIG_CAIF_SPI_SYNC | |
98a21ef0 | 23 | #define SPI_DATA_POS 0 |
529d6dad SB |
24 | static inline int forward_to_spi_cmd(struct cfspi *cfspi) |
25 | { | |
26 | return cfspi->rx_cpck_len; | |
27 | } | |
28 | #else | |
98a21ef0 | 29 | #define SPI_DATA_POS SPI_CMD_SZ |
529d6dad SB |
30 | static inline int forward_to_spi_cmd(struct cfspi *cfspi) |
31 | { | |
32 | return 0; | |
33 | } | |
34 | #endif | |
35 | ||
36 | int spi_frm_align = 2; | |
2c24a5d1 SB |
37 | |
38 | /* | |
39 | * SPI padding options. | |
40 | * Warning: must be a base of 2 (& operation used) and can not be zero ! | |
41 | */ | |
42 | int spi_up_head_align = 1 << 1; | |
43 | int spi_up_tail_align = 1 << 0; | |
44 | int spi_down_head_align = 1 << 2; | |
45 | int spi_down_tail_align = 1 << 1; | |
529d6dad SB |
46 | |
47 | #ifdef CONFIG_DEBUG_FS | |
48 | static inline void debugfs_store_prev(struct cfspi *cfspi) | |
49 | { | |
50 | /* Store previous command for debugging reasons.*/ | |
51 | cfspi->pcmd = cfspi->cmd; | |
52 | /* Store previous transfer. */ | |
53 | cfspi->tx_ppck_len = cfspi->tx_cpck_len; | |
54 | cfspi->rx_ppck_len = cfspi->rx_cpck_len; | |
55 | } | |
56 | #else | |
57 | static inline void debugfs_store_prev(struct cfspi *cfspi) | |
58 | { | |
59 | } | |
60 | #endif | |
61 | ||
62 | void cfspi_xfer(struct work_struct *work) | |
63 | { | |
64 | struct cfspi *cfspi; | |
65 | u8 *ptr = NULL; | |
66 | unsigned long flags; | |
67 | int ret; | |
68 | cfspi = container_of(work, struct cfspi, work); | |
69 | ||
70 | /* Initialize state. */ | |
71 | cfspi->cmd = SPI_CMD_EOT; | |
72 | ||
73 | for (;;) { | |
74 | ||
75 | cfspi_dbg_state(cfspi, CFSPI_STATE_WAITING); | |
76 | ||
77 | /* Wait for master talk or transmit event. */ | |
78 | wait_event_interruptible(cfspi->wait, | |
79 | test_bit(SPI_XFER, &cfspi->state) || | |
80 | test_bit(SPI_TERMINATE, &cfspi->state)); | |
81 | ||
82 | if (test_bit(SPI_TERMINATE, &cfspi->state)) | |
83 | return; | |
84 | ||
85 | #if CFSPI_DBG_PREFILL | |
86 | /* Prefill buffers for easier debugging. */ | |
87 | memset(cfspi->xfer.va_tx, 0xFF, SPI_DMA_BUF_LEN); | |
88 | memset(cfspi->xfer.va_rx, 0xFF, SPI_DMA_BUF_LEN); | |
89 | #endif /* CFSPI_DBG_PREFILL */ | |
90 | ||
91 | cfspi_dbg_state(cfspi, CFSPI_STATE_AWAKE); | |
92 | ||
93 | /* Check whether we have a committed frame. */ | |
94 | if (cfspi->tx_cpck_len) { | |
95 | int len; | |
96 | ||
97 | cfspi_dbg_state(cfspi, CFSPI_STATE_FETCH_PKT); | |
98 | ||
25985edc | 99 | /* Copy committed SPI frames after the SPI indication. */ |
529d6dad SB |
100 | ptr = (u8 *) cfspi->xfer.va_tx; |
101 | ptr += SPI_IND_SZ; | |
102 | len = cfspi_xmitfrm(cfspi, ptr, cfspi->tx_cpck_len); | |
103 | WARN_ON(len != cfspi->tx_cpck_len); | |
104 | } | |
105 | ||
106 | cfspi_dbg_state(cfspi, CFSPI_STATE_GET_NEXT); | |
107 | ||
108 | /* Get length of next frame to commit. */ | |
109 | cfspi->tx_npck_len = cfspi_xmitlen(cfspi); | |
110 | ||
111 | WARN_ON(cfspi->tx_npck_len > SPI_DMA_BUF_LEN); | |
112 | ||
113 | /* | |
114 | * Add indication and length at the beginning of the frame, | |
115 | * using little endian. | |
116 | */ | |
117 | ptr = (u8 *) cfspi->xfer.va_tx; | |
118 | *ptr++ = SPI_CMD_IND; | |
119 | *ptr++ = (SPI_CMD_IND & 0xFF00) >> 8; | |
120 | *ptr++ = cfspi->tx_npck_len & 0x00FF; | |
121 | *ptr++ = (cfspi->tx_npck_len & 0xFF00) >> 8; | |
122 | ||
123 | /* Calculate length of DMAs. */ | |
124 | cfspi->xfer.tx_dma_len = cfspi->tx_cpck_len + SPI_IND_SZ; | |
125 | cfspi->xfer.rx_dma_len = cfspi->rx_cpck_len + SPI_CMD_SZ; | |
126 | ||
127 | /* Add SPI TX frame alignment padding, if necessary. */ | |
128 | if (cfspi->tx_cpck_len && | |
129 | (cfspi->xfer.tx_dma_len % spi_frm_align)) { | |
130 | ||
131 | cfspi->xfer.tx_dma_len += spi_frm_align - | |
132 | (cfspi->xfer.tx_dma_len % spi_frm_align); | |
133 | } | |
134 | ||
135 | /* Add SPI RX frame alignment padding, if necessary. */ | |
136 | if (cfspi->rx_cpck_len && | |
137 | (cfspi->xfer.rx_dma_len % spi_frm_align)) { | |
138 | ||
139 | cfspi->xfer.rx_dma_len += spi_frm_align - | |
140 | (cfspi->xfer.rx_dma_len % spi_frm_align); | |
141 | } | |
142 | ||
143 | cfspi_dbg_state(cfspi, CFSPI_STATE_INIT_XFER); | |
144 | ||
145 | /* Start transfer. */ | |
146 | ret = cfspi->dev->init_xfer(&cfspi->xfer, cfspi->dev); | |
147 | WARN_ON(ret); | |
148 | ||
149 | cfspi_dbg_state(cfspi, CFSPI_STATE_WAIT_ACTIVE); | |
150 | ||
151 | /* | |
152 | * TODO: We might be able to make an assumption if this is the | |
153 | * first loop. Make sure that minimum toggle time is respected. | |
154 | */ | |
155 | udelay(MIN_TRANSITION_TIME_USEC); | |
156 | ||
157 | cfspi_dbg_state(cfspi, CFSPI_STATE_SIG_ACTIVE); | |
158 | ||
25985edc | 159 | /* Signal that we are ready to receive data. */ |
529d6dad SB |
160 | cfspi->dev->sig_xfer(true, cfspi->dev); |
161 | ||
162 | cfspi_dbg_state(cfspi, CFSPI_STATE_WAIT_XFER_DONE); | |
163 | ||
164 | /* Wait for transfer completion. */ | |
165 | wait_for_completion(&cfspi->comp); | |
166 | ||
167 | cfspi_dbg_state(cfspi, CFSPI_STATE_XFER_DONE); | |
168 | ||
169 | if (cfspi->cmd == SPI_CMD_EOT) { | |
170 | /* | |
171 | * Clear the master talk bit. A xfer is always at | |
172 | * least two bursts. | |
173 | */ | |
174 | clear_bit(SPI_SS_ON, &cfspi->state); | |
175 | } | |
176 | ||
177 | cfspi_dbg_state(cfspi, CFSPI_STATE_WAIT_INACTIVE); | |
178 | ||
179 | /* Make sure that the minimum toggle time is respected. */ | |
180 | if (SPI_XFER_TIME_USEC(cfspi->xfer.tx_dma_len, | |
181 | cfspi->dev->clk_mhz) < | |
182 | MIN_TRANSITION_TIME_USEC) { | |
183 | ||
184 | udelay(MIN_TRANSITION_TIME_USEC - | |
185 | SPI_XFER_TIME_USEC | |
186 | (cfspi->xfer.tx_dma_len, cfspi->dev->clk_mhz)); | |
187 | } | |
188 | ||
189 | cfspi_dbg_state(cfspi, CFSPI_STATE_SIG_INACTIVE); | |
190 | ||
191 | /* De-assert transfer signal. */ | |
192 | cfspi->dev->sig_xfer(false, cfspi->dev); | |
193 | ||
194 | /* Check whether we received a CAIF packet. */ | |
195 | if (cfspi->rx_cpck_len) { | |
196 | int len; | |
197 | ||
198 | cfspi_dbg_state(cfspi, CFSPI_STATE_DELIVER_PKT); | |
199 | ||
200 | /* Parse SPI frame. */ | |
201 | ptr = ((u8 *)(cfspi->xfer.va_rx + SPI_DATA_POS)); | |
202 | ||
203 | len = cfspi_rxfrm(cfspi, ptr, cfspi->rx_cpck_len); | |
204 | WARN_ON(len != cfspi->rx_cpck_len); | |
205 | } | |
206 | ||
207 | /* Check the next SPI command and length. */ | |
208 | ptr = (u8 *) cfspi->xfer.va_rx; | |
209 | ||
210 | ptr += forward_to_spi_cmd(cfspi); | |
211 | ||
212 | cfspi->cmd = *ptr++; | |
213 | cfspi->cmd |= ((*ptr++) << 8) & 0xFF00; | |
214 | cfspi->rx_npck_len = *ptr++; | |
215 | cfspi->rx_npck_len |= ((*ptr++) << 8) & 0xFF00; | |
216 | ||
217 | WARN_ON(cfspi->rx_npck_len > SPI_DMA_BUF_LEN); | |
218 | WARN_ON(cfspi->cmd > SPI_CMD_EOT); | |
219 | ||
220 | debugfs_store_prev(cfspi); | |
221 | ||
222 | /* Check whether the master issued an EOT command. */ | |
223 | if (cfspi->cmd == SPI_CMD_EOT) { | |
224 | /* Reset state. */ | |
225 | cfspi->tx_cpck_len = 0; | |
226 | cfspi->rx_cpck_len = 0; | |
227 | } else { | |
228 | /* Update state. */ | |
229 | cfspi->tx_cpck_len = cfspi->tx_npck_len; | |
230 | cfspi->rx_cpck_len = cfspi->rx_npck_len; | |
231 | } | |
232 | ||
233 | /* | |
234 | * Check whether we need to clear the xfer bit. | |
235 | * Spin lock needed for packet insertion. | |
236 | * Test and clear of different bits | |
237 | * are not supported. | |
238 | */ | |
239 | spin_lock_irqsave(&cfspi->lock, flags); | |
240 | if (cfspi->cmd == SPI_CMD_EOT && !cfspi_xmitlen(cfspi) | |
241 | && !test_bit(SPI_SS_ON, &cfspi->state)) | |
242 | clear_bit(SPI_XFER, &cfspi->state); | |
243 | ||
244 | spin_unlock_irqrestore(&cfspi->lock, flags); | |
245 | } | |
246 | } | |
247 | ||
248 | struct platform_driver cfspi_spi_driver = { | |
249 | .probe = cfspi_spi_probe, | |
250 | .remove = cfspi_spi_remove, | |
251 | .driver = { | |
252 | .name = "cfspi_sspi", | |
253 | .owner = THIS_MODULE, | |
254 | }, | |
255 | }; |