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