diff options
author | Leilk Liu <leilk.liu@mediatek.com> | 2015-08-07 03:19:50 -0400 |
---|---|---|
committer | Mark Brown <broonie@kernel.org> | 2015-08-07 09:35:13 -0400 |
commit | a568231f463225eb31593f71446a267a03ae0528 (patch) | |
tree | 7057798991d11bfc84ac4c6aa9f448454a08123b /drivers/spi/spi-mt65xx.c | |
parent | 0d850e7cdc69962e85abd7f7dcd2359f293f835a (diff) |
spi: mediatek: Add spi bus for Mediatek MT8173
This patch adds basic spi bus for MT8173.
Signed-off-by: Leilk Liu <leilk.liu@mediatek.com>
Signed-off-by: Mark Brown <broonie@kernel.org>
Diffstat (limited to 'drivers/spi/spi-mt65xx.c')
-rw-r--r-- | drivers/spi/spi-mt65xx.c | 749 |
1 files changed, 749 insertions, 0 deletions
diff --git a/drivers/spi/spi-mt65xx.c b/drivers/spi/spi-mt65xx.c new file mode 100644 index 000000000000..4676b0122b89 --- /dev/null +++ b/drivers/spi/spi-mt65xx.c | |||
@@ -0,0 +1,749 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2015 MediaTek Inc. | ||
3 | * Author: Leilk Liu <leilk.liu@mediatek.com> | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify | ||
6 | * it under the terms of the GNU General Public License version 2 as | ||
7 | * published by the Free Software Foundation. | ||
8 | * | ||
9 | * This program is distributed in the hope that it will be useful, | ||
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | * GNU General Public License for more details. | ||
13 | */ | ||
14 | |||
15 | #include <linux/clk.h> | ||
16 | #include <linux/device.h> | ||
17 | #include <linux/err.h> | ||
18 | #include <linux/interrupt.h> | ||
19 | #include <linux/ioport.h> | ||
20 | #include <linux/module.h> | ||
21 | #include <linux/of.h> | ||
22 | #include <linux/platform_device.h> | ||
23 | #include <linux/platform_data/spi-mt65xx.h> | ||
24 | #include <linux/pm_runtime.h> | ||
25 | #include <linux/spi/spi.h> | ||
26 | |||
27 | #define SPI_CFG0_REG 0x0000 | ||
28 | #define SPI_CFG1_REG 0x0004 | ||
29 | #define SPI_TX_SRC_REG 0x0008 | ||
30 | #define SPI_RX_DST_REG 0x000c | ||
31 | #define SPI_TX_DATA_REG 0x0010 | ||
32 | #define SPI_RX_DATA_REG 0x0014 | ||
33 | #define SPI_CMD_REG 0x0018 | ||
34 | #define SPI_STATUS0_REG 0x001c | ||
35 | #define SPI_PAD_SEL_REG 0x0024 | ||
36 | |||
37 | #define SPI_CFG0_SCK_HIGH_OFFSET 0 | ||
38 | #define SPI_CFG0_SCK_LOW_OFFSET 8 | ||
39 | #define SPI_CFG0_CS_HOLD_OFFSET 16 | ||
40 | #define SPI_CFG0_CS_SETUP_OFFSET 24 | ||
41 | |||
42 | #define SPI_CFG1_CS_IDLE_OFFSET 0 | ||
43 | #define SPI_CFG1_PACKET_LOOP_OFFSET 8 | ||
44 | #define SPI_CFG1_PACKET_LENGTH_OFFSET 16 | ||
45 | #define SPI_CFG1_GET_TICK_DLY_OFFSET 30 | ||
46 | |||
47 | #define SPI_CFG1_CS_IDLE_MASK 0xff | ||
48 | #define SPI_CFG1_PACKET_LOOP_MASK 0xff00 | ||
49 | #define SPI_CFG1_PACKET_LENGTH_MASK 0x3ff0000 | ||
50 | |||
51 | #define SPI_CMD_ACT_OFFSET 0 | ||
52 | #define SPI_CMD_RESUME_OFFSET 1 | ||
53 | #define SPI_CMD_CPHA_OFFSET 8 | ||
54 | #define SPI_CMD_CPOL_OFFSET 9 | ||
55 | #define SPI_CMD_TXMSBF_OFFSET 12 | ||
56 | #define SPI_CMD_RXMSBF_OFFSET 13 | ||
57 | #define SPI_CMD_RX_ENDIAN_OFFSET 14 | ||
58 | #define SPI_CMD_TX_ENDIAN_OFFSET 15 | ||
59 | |||
60 | #define SPI_CMD_RST BIT(2) | ||
61 | #define SPI_CMD_PAUSE_EN BIT(4) | ||
62 | #define SPI_CMD_DEASSERT BIT(5) | ||
63 | #define SPI_CMD_CPHA BIT(8) | ||
64 | #define SPI_CMD_CPOL BIT(9) | ||
65 | #define SPI_CMD_RX_DMA BIT(10) | ||
66 | #define SPI_CMD_TX_DMA BIT(11) | ||
67 | #define SPI_CMD_TXMSBF BIT(12) | ||
68 | #define SPI_CMD_RXMSBF BIT(13) | ||
69 | #define SPI_CMD_RX_ENDIAN BIT(14) | ||
70 | #define SPI_CMD_TX_ENDIAN BIT(15) | ||
71 | #define SPI_CMD_FINISH_IE BIT(16) | ||
72 | #define SPI_CMD_PAUSE_IE BIT(17) | ||
73 | |||
74 | #define MTK_SPI_QUIRK_PAD_SELECT 1 | ||
75 | /* Must explicitly send dummy Tx bytes to do Rx only transfer */ | ||
76 | #define MTK_SPI_QUIRK_MUST_TX 1 | ||
77 | |||
78 | #define MT8173_SPI_MAX_PAD_SEL 3 | ||
79 | |||
80 | #define MTK_SPI_IDLE 0 | ||
81 | #define MTK_SPI_PAUSED 1 | ||
82 | |||
83 | #define MTK_SPI_MAX_FIFO_SIZE 32 | ||
84 | #define MTK_SPI_PACKET_SIZE 1024 | ||
85 | |||
86 | struct mtk_spi_compatible { | ||
87 | u32 need_pad_sel; | ||
88 | u32 must_tx; | ||
89 | }; | ||
90 | |||
91 | struct mtk_spi { | ||
92 | void __iomem *base; | ||
93 | u32 state; | ||
94 | u32 pad_sel; | ||
95 | struct clk *spi_clk, *parent_clk; | ||
96 | struct spi_transfer *cur_transfer; | ||
97 | u32 xfer_len; | ||
98 | struct scatterlist *tx_sgl, *rx_sgl; | ||
99 | u32 tx_sgl_len, rx_sgl_len; | ||
100 | const struct mtk_spi_compatible *dev_comp; | ||
101 | }; | ||
102 | |||
103 | static const struct mtk_spi_compatible mt6589_compat = { | ||
104 | .need_pad_sel = 0, | ||
105 | .must_tx = 0, | ||
106 | }; | ||
107 | |||
108 | static const struct mtk_spi_compatible mt8135_compat = { | ||
109 | .need_pad_sel = 0, | ||
110 | .must_tx = 0, | ||
111 | }; | ||
112 | |||
113 | static const struct mtk_spi_compatible mt8173_compat = { | ||
114 | .need_pad_sel = MTK_SPI_QUIRK_PAD_SELECT, | ||
115 | .must_tx = MTK_SPI_QUIRK_MUST_TX, | ||
116 | }; | ||
117 | |||
118 | /* | ||
119 | * A piece of default chip info unless the platform | ||
120 | * supplies it. | ||
121 | */ | ||
122 | static const struct mtk_chip_config mtk_default_chip_info = { | ||
123 | .rx_mlsb = 1, | ||
124 | .tx_mlsb = 1, | ||
125 | .tx_endian = 0, | ||
126 | .rx_endian = 0, | ||
127 | }; | ||
128 | |||
129 | static const struct of_device_id mtk_spi_of_match[] = { | ||
130 | { .compatible = "mediatek,mt6589-spi", .data = (void *)&mt6589_compat }, | ||
131 | { .compatible = "mediatek,mt8135-spi", .data = (void *)&mt8135_compat }, | ||
132 | { .compatible = "mediatek,mt8173-spi", .data = (void *)&mt8173_compat }, | ||
133 | {} | ||
134 | }; | ||
135 | MODULE_DEVICE_TABLE(of, mtk_spi_of_match); | ||
136 | |||
137 | static void mtk_spi_reset(struct mtk_spi *mdata) | ||
138 | { | ||
139 | u32 reg_val; | ||
140 | |||
141 | /* set the software reset bit in SPI_CMD_REG. */ | ||
142 | reg_val = readl(mdata->base + SPI_CMD_REG); | ||
143 | reg_val |= SPI_CMD_RST; | ||
144 | writel(reg_val, mdata->base + SPI_CMD_REG); | ||
145 | |||
146 | reg_val = readl(mdata->base + SPI_CMD_REG); | ||
147 | reg_val &= ~SPI_CMD_RST; | ||
148 | writel(reg_val, mdata->base + SPI_CMD_REG); | ||
149 | } | ||
150 | |||
151 | static void mtk_spi_config(struct mtk_spi *mdata, | ||
152 | struct mtk_chip_config *chip_config) | ||
153 | { | ||
154 | u32 reg_val; | ||
155 | |||
156 | reg_val = readl(mdata->base + SPI_CMD_REG); | ||
157 | |||
158 | /* set the mlsbx and mlsbtx */ | ||
159 | reg_val &= ~(SPI_CMD_TXMSBF | SPI_CMD_RXMSBF); | ||
160 | reg_val |= (chip_config->tx_mlsb << SPI_CMD_TXMSBF_OFFSET); | ||
161 | reg_val |= (chip_config->rx_mlsb << SPI_CMD_RXMSBF_OFFSET); | ||
162 | |||
163 | /* set the tx/rx endian */ | ||
164 | reg_val &= ~(SPI_CMD_TX_ENDIAN | SPI_CMD_RX_ENDIAN); | ||
165 | reg_val |= (chip_config->tx_endian << SPI_CMD_TX_ENDIAN_OFFSET); | ||
166 | reg_val |= (chip_config->rx_endian << SPI_CMD_RX_ENDIAN_OFFSET); | ||
167 | |||
168 | /* set finish and pause interrupt always enable */ | ||
169 | reg_val |= SPI_CMD_FINISH_IE | SPI_CMD_PAUSE_EN; | ||
170 | |||
171 | /* disable dma mode */ | ||
172 | reg_val &= ~(SPI_CMD_TX_DMA | SPI_CMD_RX_DMA); | ||
173 | |||
174 | /* disable deassert mode */ | ||
175 | reg_val &= ~SPI_CMD_DEASSERT; | ||
176 | |||
177 | writel(reg_val, mdata->base + SPI_CMD_REG); | ||
178 | |||
179 | /* pad select */ | ||
180 | if (mdata->dev_comp->need_pad_sel) | ||
181 | writel(mdata->pad_sel, mdata->base + SPI_PAD_SEL_REG); | ||
182 | } | ||
183 | |||
184 | static int mtk_spi_prepare_hardware(struct spi_master *master) | ||
185 | { | ||
186 | struct spi_transfer *trans; | ||
187 | struct mtk_spi *mdata = spi_master_get_devdata(master); | ||
188 | struct spi_message *msg = master->cur_msg; | ||
189 | int ret; | ||
190 | |||
191 | ret = clk_prepare_enable(mdata->spi_clk); | ||
192 | if (ret < 0) { | ||
193 | dev_err(&master->dev, "failed to enable clock (%d)\n", ret); | ||
194 | return ret; | ||
195 | } | ||
196 | |||
197 | trans = list_first_entry(&msg->transfers, struct spi_transfer, | ||
198 | transfer_list); | ||
199 | if (trans->cs_change == 0) { | ||
200 | mdata->state = MTK_SPI_IDLE; | ||
201 | mtk_spi_reset(mdata); | ||
202 | } | ||
203 | |||
204 | return ret; | ||
205 | } | ||
206 | |||
207 | static int mtk_spi_unprepare_hardware(struct spi_master *master) | ||
208 | { | ||
209 | struct mtk_spi *mdata = spi_master_get_devdata(master); | ||
210 | |||
211 | clk_disable_unprepare(mdata->spi_clk); | ||
212 | |||
213 | return 0; | ||
214 | } | ||
215 | |||
216 | static int mtk_spi_prepare_message(struct spi_master *master, | ||
217 | struct spi_message *msg) | ||
218 | { | ||
219 | u32 reg_val; | ||
220 | u8 cpha, cpol; | ||
221 | struct mtk_chip_config *chip_config; | ||
222 | struct spi_device *spi = msg->spi; | ||
223 | struct mtk_spi *mdata = spi_master_get_devdata(master); | ||
224 | |||
225 | cpha = spi->mode & SPI_CPHA ? 1 : 0; | ||
226 | cpol = spi->mode & SPI_CPOL ? 1 : 0; | ||
227 | |||
228 | reg_val = readl(mdata->base + SPI_CMD_REG); | ||
229 | reg_val &= ~(SPI_CMD_CPHA | SPI_CMD_CPOL); | ||
230 | reg_val |= (cpha << SPI_CMD_CPHA_OFFSET); | ||
231 | reg_val |= (cpol << SPI_CMD_CPOL_OFFSET); | ||
232 | writel(reg_val, mdata->base + SPI_CMD_REG); | ||
233 | |||
234 | chip_config = spi->controller_data; | ||
235 | if (!chip_config) { | ||
236 | chip_config = (void *)&mtk_default_chip_info; | ||
237 | spi->controller_data = chip_config; | ||
238 | } | ||
239 | mtk_spi_config(mdata, chip_config); | ||
240 | |||
241 | return 0; | ||
242 | } | ||
243 | |||
244 | static void mtk_spi_set_cs(struct spi_device *spi, bool enable) | ||
245 | { | ||
246 | u32 reg_val; | ||
247 | struct mtk_spi *mdata = spi_master_get_devdata(spi->master); | ||
248 | |||
249 | reg_val = readl(mdata->base + SPI_CMD_REG); | ||
250 | if (!enable) | ||
251 | reg_val |= SPI_CMD_PAUSE_EN; | ||
252 | else | ||
253 | reg_val &= ~SPI_CMD_PAUSE_EN; | ||
254 | writel(reg_val, mdata->base + SPI_CMD_REG); | ||
255 | } | ||
256 | |||
257 | static void mtk_spi_prepare_transfer(struct spi_master *master, | ||
258 | struct spi_transfer *xfer) | ||
259 | { | ||
260 | u32 spi_clk_hz, div, high_time, low_time, holdtime, | ||
261 | setuptime, cs_idletime, reg_val = 0; | ||
262 | struct mtk_spi *mdata = spi_master_get_devdata(master); | ||
263 | |||
264 | spi_clk_hz = clk_get_rate(mdata->spi_clk); | ||
265 | if (xfer->speed_hz < spi_clk_hz / 2) | ||
266 | div = DIV_ROUND_UP(spi_clk_hz, xfer->speed_hz); | ||
267 | else | ||
268 | div = 1; | ||
269 | |||
270 | high_time = (div + 1) / 2; | ||
271 | low_time = (div + 1) / 2; | ||
272 | holdtime = (div + 1) / 2 * 2; | ||
273 | setuptime = (div + 1) / 2 * 2; | ||
274 | cs_idletime = (div + 1) / 2 * 2; | ||
275 | |||
276 | reg_val |= (((high_time - 1) & 0xff) << SPI_CFG0_SCK_HIGH_OFFSET); | ||
277 | reg_val |= (((low_time - 1) & 0xff) << SPI_CFG0_SCK_LOW_OFFSET); | ||
278 | reg_val |= (((holdtime - 1) & 0xff) << SPI_CFG0_CS_HOLD_OFFSET); | ||
279 | reg_val |= (((setuptime - 1) & 0xff) << SPI_CFG0_CS_SETUP_OFFSET); | ||
280 | writel(reg_val, mdata->base + SPI_CFG0_REG); | ||
281 | |||
282 | reg_val = readl(mdata->base + SPI_CFG1_REG); | ||
283 | reg_val &= ~SPI_CFG1_CS_IDLE_MASK; | ||
284 | reg_val |= (((cs_idletime - 1) & 0xff) << SPI_CFG1_CS_IDLE_OFFSET); | ||
285 | writel(reg_val, mdata->base + SPI_CFG1_REG); | ||
286 | } | ||
287 | |||
288 | static void mtk_spi_setup_packet(struct spi_master *master) | ||
289 | { | ||
290 | u32 packet_size, packet_loop, reg_val; | ||
291 | struct mtk_spi *mdata = spi_master_get_devdata(master); | ||
292 | |||
293 | packet_size = min_t(unsigned, mdata->xfer_len, MTK_SPI_PACKET_SIZE); | ||
294 | packet_loop = mdata->xfer_len / packet_size; | ||
295 | |||
296 | reg_val = readl(mdata->base + SPI_CFG1_REG); | ||
297 | reg_val &= ~(SPI_CFG1_PACKET_LENGTH_MASK + SPI_CFG1_PACKET_LOOP_MASK); | ||
298 | reg_val |= (packet_size - 1) << SPI_CFG1_PACKET_LENGTH_OFFSET; | ||
299 | reg_val |= (packet_loop - 1) << SPI_CFG1_PACKET_LOOP_OFFSET; | ||
300 | writel(reg_val, mdata->base + SPI_CFG1_REG); | ||
301 | } | ||
302 | |||
303 | static void mtk_spi_enable_transfer(struct spi_master *master) | ||
304 | { | ||
305 | int cmd; | ||
306 | struct mtk_spi *mdata = spi_master_get_devdata(master); | ||
307 | |||
308 | cmd = readl(mdata->base + SPI_CMD_REG); | ||
309 | if (mdata->state == MTK_SPI_IDLE) | ||
310 | cmd |= 1 << SPI_CMD_ACT_OFFSET; | ||
311 | else | ||
312 | cmd |= 1 << SPI_CMD_RESUME_OFFSET; | ||
313 | writel(cmd, mdata->base + SPI_CMD_REG); | ||
314 | } | ||
315 | |||
316 | static int mtk_spi_get_mult_delta(int xfer_len) | ||
317 | { | ||
318 | int mult_delta; | ||
319 | |||
320 | if (xfer_len > MTK_SPI_PACKET_SIZE) | ||
321 | mult_delta = xfer_len % MTK_SPI_PACKET_SIZE; | ||
322 | else | ||
323 | mult_delta = 0; | ||
324 | |||
325 | return mult_delta; | ||
326 | } | ||
327 | |||
328 | static void mtk_spi_update_mdata_len(struct spi_master *master) | ||
329 | { | ||
330 | int mult_delta; | ||
331 | struct mtk_spi *mdata = spi_master_get_devdata(master); | ||
332 | |||
333 | if (mdata->tx_sgl_len && mdata->rx_sgl_len) { | ||
334 | if (mdata->tx_sgl_len > mdata->rx_sgl_len) { | ||
335 | mult_delta = mtk_spi_get_mult_delta(mdata->rx_sgl_len); | ||
336 | mdata->xfer_len = mdata->rx_sgl_len - mult_delta; | ||
337 | mdata->rx_sgl_len = mult_delta; | ||
338 | mdata->tx_sgl_len -= mdata->xfer_len; | ||
339 | } else { | ||
340 | mult_delta = mtk_spi_get_mult_delta(mdata->tx_sgl_len); | ||
341 | mdata->xfer_len = mdata->tx_sgl_len - mult_delta; | ||
342 | mdata->tx_sgl_len = mult_delta; | ||
343 | mdata->rx_sgl_len -= mdata->xfer_len; | ||
344 | } | ||
345 | } else if (mdata->tx_sgl_len) { | ||
346 | mult_delta = mtk_spi_get_mult_delta(mdata->tx_sgl_len); | ||
347 | mdata->xfer_len = mdata->tx_sgl_len - mult_delta; | ||
348 | mdata->tx_sgl_len = mult_delta; | ||
349 | } else if (mdata->rx_sgl_len) { | ||
350 | mult_delta = mtk_spi_get_mult_delta(mdata->rx_sgl_len); | ||
351 | mdata->xfer_len = mdata->rx_sgl_len - mult_delta; | ||
352 | mdata->rx_sgl_len = mult_delta; | ||
353 | } | ||
354 | } | ||
355 | |||
356 | static void mtk_spi_setup_dma_addr(struct spi_master *master, | ||
357 | struct spi_transfer *xfer) | ||
358 | { | ||
359 | struct mtk_spi *mdata = spi_master_get_devdata(master); | ||
360 | |||
361 | if (mdata->tx_sgl) | ||
362 | writel(cpu_to_le32(xfer->tx_dma), mdata->base + SPI_TX_SRC_REG); | ||
363 | if (mdata->rx_sgl) | ||
364 | writel(cpu_to_le32(xfer->rx_dma), mdata->base + SPI_RX_DST_REG); | ||
365 | } | ||
366 | |||
367 | static int mtk_spi_fifo_transfer(struct spi_master *master, | ||
368 | struct spi_device *spi, | ||
369 | struct spi_transfer *xfer) | ||
370 | { | ||
371 | int cnt, i; | ||
372 | struct mtk_spi *mdata = spi_master_get_devdata(master); | ||
373 | |||
374 | mdata->cur_transfer = xfer; | ||
375 | mdata->xfer_len = xfer->len; | ||
376 | mtk_spi_prepare_transfer(master, xfer); | ||
377 | mtk_spi_setup_packet(master); | ||
378 | |||
379 | if (xfer->len % 4) | ||
380 | cnt = xfer->len / 4 + 1; | ||
381 | else | ||
382 | cnt = xfer->len / 4; | ||
383 | |||
384 | for (i = 0; i < cnt; i++) | ||
385 | writel(*((u32 *)xfer->tx_buf + i), | ||
386 | mdata->base + SPI_TX_DATA_REG); | ||
387 | |||
388 | mtk_spi_enable_transfer(master); | ||
389 | |||
390 | return 1; | ||
391 | } | ||
392 | |||
393 | static int mtk_spi_dma_transfer(struct spi_master *master, | ||
394 | struct spi_device *spi, | ||
395 | struct spi_transfer *xfer) | ||
396 | { | ||
397 | int cmd; | ||
398 | struct mtk_spi *mdata = spi_master_get_devdata(master); | ||
399 | |||
400 | mdata->tx_sgl = NULL; | ||
401 | mdata->rx_sgl = NULL; | ||
402 | mdata->tx_sgl_len = 0; | ||
403 | mdata->rx_sgl_len = 0; | ||
404 | mdata->cur_transfer = xfer; | ||
405 | |||
406 | mtk_spi_prepare_transfer(master, xfer); | ||
407 | |||
408 | cmd = readl(mdata->base + SPI_CMD_REG); | ||
409 | if (xfer->tx_buf) | ||
410 | cmd |= SPI_CMD_TX_DMA; | ||
411 | if (xfer->rx_buf) | ||
412 | cmd |= SPI_CMD_RX_DMA; | ||
413 | writel(cmd, mdata->base + SPI_CMD_REG); | ||
414 | |||
415 | if (xfer->tx_buf) | ||
416 | mdata->tx_sgl = xfer->tx_sg.sgl; | ||
417 | if (xfer->rx_buf) | ||
418 | mdata->rx_sgl = xfer->rx_sg.sgl; | ||
419 | |||
420 | if (mdata->tx_sgl) { | ||
421 | xfer->tx_dma = sg_dma_address(mdata->tx_sgl); | ||
422 | mdata->tx_sgl_len = sg_dma_len(mdata->tx_sgl); | ||
423 | } | ||
424 | if (mdata->rx_sgl) { | ||
425 | xfer->rx_dma = sg_dma_address(mdata->rx_sgl); | ||
426 | mdata->rx_sgl_len = sg_dma_len(mdata->rx_sgl); | ||
427 | } | ||
428 | |||
429 | mtk_spi_update_mdata_len(master); | ||
430 | mtk_spi_setup_packet(master); | ||
431 | mtk_spi_setup_dma_addr(master, xfer); | ||
432 | mtk_spi_enable_transfer(master); | ||
433 | |||
434 | return 1; | ||
435 | } | ||
436 | |||
437 | static int mtk_spi_transfer_one(struct spi_master *master, | ||
438 | struct spi_device *spi, | ||
439 | struct spi_transfer *xfer) | ||
440 | { | ||
441 | if (master->can_dma(master, spi, xfer)) | ||
442 | return mtk_spi_dma_transfer(master, spi, xfer); | ||
443 | else | ||
444 | return mtk_spi_fifo_transfer(master, spi, xfer); | ||
445 | } | ||
446 | |||
447 | static bool mtk_spi_can_dma(struct spi_master *master, | ||
448 | struct spi_device *spi, | ||
449 | struct spi_transfer *xfer) | ||
450 | { | ||
451 | return xfer->len > MTK_SPI_MAX_FIFO_SIZE; | ||
452 | } | ||
453 | |||
454 | static irqreturn_t mtk_spi_interrupt(int irq, void *dev_id) | ||
455 | { | ||
456 | u32 cmd, reg_val, i; | ||
457 | struct spi_master *master = dev_id; | ||
458 | struct mtk_spi *mdata = spi_master_get_devdata(master); | ||
459 | struct spi_transfer *trans = mdata->cur_transfer; | ||
460 | |||
461 | reg_val = readl(mdata->base + SPI_STATUS0_REG); | ||
462 | if (reg_val & 0x2) | ||
463 | mdata->state = MTK_SPI_PAUSED; | ||
464 | else | ||
465 | mdata->state = MTK_SPI_IDLE; | ||
466 | |||
467 | if (!master->can_dma(master, master->cur_msg->spi, trans)) { | ||
468 | /* xfer len is not N*4 bytes every time in a transfer, | ||
469 | * but SPI_RX_DATA_REG must reads 4 bytes once, | ||
470 | * so rx buffer byte by byte. | ||
471 | */ | ||
472 | if (trans->rx_buf) { | ||
473 | for (i = 0; i < mdata->xfer_len; i++) { | ||
474 | if (i % 4 == 0) | ||
475 | reg_val = | ||
476 | readl(mdata->base + SPI_RX_DATA_REG); | ||
477 | *((u8 *)(trans->rx_buf + i)) = | ||
478 | (reg_val >> ((i % 4) * 8)) & 0xff; | ||
479 | } | ||
480 | } | ||
481 | spi_finalize_current_transfer(master); | ||
482 | return IRQ_HANDLED; | ||
483 | } | ||
484 | |||
485 | if (mdata->tx_sgl) | ||
486 | trans->tx_dma += mdata->xfer_len; | ||
487 | if (mdata->rx_sgl) | ||
488 | trans->rx_dma += mdata->xfer_len; | ||
489 | |||
490 | if (mdata->tx_sgl && (mdata->tx_sgl_len == 0)) { | ||
491 | mdata->tx_sgl = sg_next(mdata->tx_sgl); | ||
492 | if (mdata->tx_sgl) { | ||
493 | trans->tx_dma = sg_dma_address(mdata->tx_sgl); | ||
494 | mdata->tx_sgl_len = sg_dma_len(mdata->tx_sgl); | ||
495 | } | ||
496 | } | ||
497 | if (mdata->rx_sgl && (mdata->rx_sgl_len == 0)) { | ||
498 | mdata->rx_sgl = sg_next(mdata->rx_sgl); | ||
499 | if (mdata->rx_sgl) { | ||
500 | trans->rx_dma = sg_dma_address(mdata->rx_sgl); | ||
501 | mdata->rx_sgl_len = sg_dma_len(mdata->rx_sgl); | ||
502 | } | ||
503 | } | ||
504 | |||
505 | if (!mdata->tx_sgl && !mdata->rx_sgl) { | ||
506 | /* spi disable dma */ | ||
507 | cmd = readl(mdata->base + SPI_CMD_REG); | ||
508 | cmd &= ~SPI_CMD_TX_DMA; | ||
509 | cmd &= ~SPI_CMD_RX_DMA; | ||
510 | writel(cmd, mdata->base + SPI_CMD_REG); | ||
511 | |||
512 | spi_finalize_current_transfer(master); | ||
513 | return IRQ_HANDLED; | ||
514 | } | ||
515 | |||
516 | mtk_spi_update_mdata_len(master); | ||
517 | mtk_spi_setup_packet(master); | ||
518 | mtk_spi_setup_dma_addr(master, trans); | ||
519 | mtk_spi_enable_transfer(master); | ||
520 | |||
521 | return IRQ_HANDLED; | ||
522 | } | ||
523 | |||
524 | static int mtk_spi_probe(struct platform_device *pdev) | ||
525 | { | ||
526 | struct spi_master *master; | ||
527 | struct mtk_spi *mdata; | ||
528 | const struct of_device_id *of_id; | ||
529 | struct resource *res; | ||
530 | int irq, ret; | ||
531 | |||
532 | master = spi_alloc_master(&pdev->dev, sizeof(*mdata)); | ||
533 | if (!master) { | ||
534 | dev_err(&pdev->dev, "failed to alloc spi master\n"); | ||
535 | return -ENOMEM; | ||
536 | } | ||
537 | |||
538 | master->auto_runtime_pm = true; | ||
539 | master->dev.of_node = pdev->dev.of_node; | ||
540 | master->mode_bits = SPI_CPOL | SPI_CPHA; | ||
541 | |||
542 | master->set_cs = mtk_spi_set_cs; | ||
543 | master->prepare_transfer_hardware = mtk_spi_prepare_hardware; | ||
544 | master->unprepare_transfer_hardware = mtk_spi_unprepare_hardware; | ||
545 | master->prepare_message = mtk_spi_prepare_message; | ||
546 | master->transfer_one = mtk_spi_transfer_one; | ||
547 | master->can_dma = mtk_spi_can_dma; | ||
548 | |||
549 | of_id = of_match_node(mtk_spi_of_match, pdev->dev.of_node); | ||
550 | if (!of_id) { | ||
551 | dev_err(&pdev->dev, "failed to probe of_node\n"); | ||
552 | ret = -EINVAL; | ||
553 | goto err_put_master; | ||
554 | } | ||
555 | |||
556 | mdata = spi_master_get_devdata(master); | ||
557 | mdata->dev_comp = of_id->data; | ||
558 | if (mdata->dev_comp->must_tx) | ||
559 | master->flags = SPI_MASTER_MUST_TX; | ||
560 | |||
561 | if (mdata->dev_comp->need_pad_sel) { | ||
562 | ret = of_property_read_u32(pdev->dev.of_node, | ||
563 | "mediatek,pad-select", | ||
564 | &mdata->pad_sel); | ||
565 | if (ret) { | ||
566 | dev_err(&pdev->dev, "failed to read pad select: %d\n", | ||
567 | ret); | ||
568 | goto err_put_master; | ||
569 | } | ||
570 | |||
571 | if (mdata->pad_sel > MT8173_SPI_MAX_PAD_SEL) { | ||
572 | dev_err(&pdev->dev, "wrong pad-select: %u\n", | ||
573 | mdata->pad_sel); | ||
574 | ret = -EINVAL; | ||
575 | goto err_put_master; | ||
576 | } | ||
577 | } | ||
578 | |||
579 | platform_set_drvdata(pdev, master); | ||
580 | |||
581 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
582 | if (!res) { | ||
583 | ret = -ENODEV; | ||
584 | dev_err(&pdev->dev, "failed to determine base address\n"); | ||
585 | goto err_put_master; | ||
586 | } | ||
587 | |||
588 | mdata->base = devm_ioremap_resource(&pdev->dev, res); | ||
589 | if (IS_ERR(mdata->base)) { | ||
590 | ret = PTR_ERR(mdata->base); | ||
591 | goto err_put_master; | ||
592 | } | ||
593 | |||
594 | irq = platform_get_irq(pdev, 0); | ||
595 | if (irq < 0) { | ||
596 | dev_err(&pdev->dev, "failed to get irq (%d)\n", irq); | ||
597 | ret = irq; | ||
598 | goto err_put_master; | ||
599 | } | ||
600 | |||
601 | if (!pdev->dev.dma_mask) | ||
602 | pdev->dev.dma_mask = &pdev->dev.coherent_dma_mask; | ||
603 | |||
604 | ret = devm_request_irq(&pdev->dev, irq, mtk_spi_interrupt, | ||
605 | IRQF_TRIGGER_NONE, dev_name(&pdev->dev), master); | ||
606 | if (ret) { | ||
607 | dev_err(&pdev->dev, "failed to register irq (%d)\n", ret); | ||
608 | goto err_put_master; | ||
609 | } | ||
610 | |||
611 | mdata->spi_clk = devm_clk_get(&pdev->dev, "spi-clk"); | ||
612 | if (IS_ERR(mdata->spi_clk)) { | ||
613 | ret = PTR_ERR(mdata->spi_clk); | ||
614 | dev_err(&pdev->dev, "failed to get spi-clk: %d\n", ret); | ||
615 | goto err_put_master; | ||
616 | } | ||
617 | |||
618 | mdata->parent_clk = devm_clk_get(&pdev->dev, "parent-clk"); | ||
619 | if (IS_ERR(mdata->parent_clk)) { | ||
620 | ret = PTR_ERR(mdata->parent_clk); | ||
621 | dev_err(&pdev->dev, "failed to get parent-clk: %d\n", ret); | ||
622 | goto err_put_master; | ||
623 | } | ||
624 | |||
625 | ret = clk_prepare_enable(mdata->spi_clk); | ||
626 | if (ret < 0) { | ||
627 | dev_err(&pdev->dev, "failed to enable spi_clk (%d)\n", ret); | ||
628 | goto err_put_master; | ||
629 | } | ||
630 | |||
631 | ret = clk_set_parent(mdata->spi_clk, mdata->parent_clk); | ||
632 | if (ret < 0) { | ||
633 | dev_err(&pdev->dev, "failed to clk_set_parent (%d)\n", ret); | ||
634 | goto err_disable_clk; | ||
635 | } | ||
636 | |||
637 | clk_disable_unprepare(mdata->spi_clk); | ||
638 | |||
639 | pm_runtime_enable(&pdev->dev); | ||
640 | |||
641 | ret = devm_spi_register_master(&pdev->dev, master); | ||
642 | if (ret) { | ||
643 | dev_err(&pdev->dev, "failed to register master (%d)\n", ret); | ||
644 | goto err_put_master; | ||
645 | } | ||
646 | |||
647 | return 0; | ||
648 | |||
649 | err_disable_clk: | ||
650 | clk_disable_unprepare(mdata->spi_clk); | ||
651 | err_put_master: | ||
652 | spi_master_put(master); | ||
653 | |||
654 | return ret; | ||
655 | } | ||
656 | |||
657 | static int mtk_spi_remove(struct platform_device *pdev) | ||
658 | { | ||
659 | struct spi_master *master = platform_get_drvdata(pdev); | ||
660 | struct mtk_spi *mdata = spi_master_get_devdata(master); | ||
661 | |||
662 | pm_runtime_disable(&pdev->dev); | ||
663 | |||
664 | mtk_spi_reset(mdata); | ||
665 | clk_disable_unprepare(mdata->spi_clk); | ||
666 | spi_master_put(master); | ||
667 | |||
668 | return 0; | ||
669 | } | ||
670 | |||
671 | #ifdef CONFIG_PM_SLEEP | ||
672 | static int mtk_spi_suspend(struct device *dev) | ||
673 | { | ||
674 | int ret; | ||
675 | struct spi_master *master = dev_get_drvdata(dev); | ||
676 | struct mtk_spi *mdata = spi_master_get_devdata(master); | ||
677 | |||
678 | ret = spi_master_suspend(master); | ||
679 | if (ret) | ||
680 | return ret; | ||
681 | |||
682 | if (!pm_runtime_suspended(dev)) | ||
683 | clk_disable_unprepare(mdata->spi_clk); | ||
684 | |||
685 | return ret; | ||
686 | } | ||
687 | |||
688 | static int mtk_spi_resume(struct device *dev) | ||
689 | { | ||
690 | int ret; | ||
691 | struct spi_master *master = dev_get_drvdata(dev); | ||
692 | struct mtk_spi *mdata = spi_master_get_devdata(master); | ||
693 | |||
694 | if (!pm_runtime_suspended(dev)) { | ||
695 | ret = clk_prepare_enable(mdata->spi_clk); | ||
696 | if (ret < 0) | ||
697 | return ret; | ||
698 | } | ||
699 | |||
700 | ret = spi_master_resume(master); | ||
701 | if (ret < 0) | ||
702 | clk_disable_unprepare(mdata->spi_clk); | ||
703 | |||
704 | return ret; | ||
705 | } | ||
706 | #endif /* CONFIG_PM_SLEEP */ | ||
707 | |||
708 | #ifdef CONFIG_PM | ||
709 | static int mtk_spi_runtime_suspend(struct device *dev) | ||
710 | { | ||
711 | struct spi_master *master = dev_get_drvdata(dev); | ||
712 | struct mtk_spi *mdata = spi_master_get_devdata(master); | ||
713 | |||
714 | clk_disable_unprepare(mdata->spi_clk); | ||
715 | |||
716 | return 0; | ||
717 | } | ||
718 | |||
719 | static int mtk_spi_runtime_resume(struct device *dev) | ||
720 | { | ||
721 | struct spi_master *master = dev_get_drvdata(dev); | ||
722 | struct mtk_spi *mdata = spi_master_get_devdata(master); | ||
723 | |||
724 | return clk_prepare_enable(mdata->spi_clk); | ||
725 | } | ||
726 | #endif /* CONFIG_PM */ | ||
727 | |||
728 | static const struct dev_pm_ops mtk_spi_pm = { | ||
729 | SET_SYSTEM_SLEEP_PM_OPS(mtk_spi_suspend, mtk_spi_resume) | ||
730 | SET_RUNTIME_PM_OPS(mtk_spi_runtime_suspend, | ||
731 | mtk_spi_runtime_resume, NULL) | ||
732 | }; | ||
733 | |||
734 | struct platform_driver mtk_spi_driver = { | ||
735 | .driver = { | ||
736 | .name = "mtk-spi", | ||
737 | .pm = &mtk_spi_pm, | ||
738 | .of_match_table = mtk_spi_of_match, | ||
739 | }, | ||
740 | .probe = mtk_spi_probe, | ||
741 | .remove = mtk_spi_remove, | ||
742 | }; | ||
743 | |||
744 | module_platform_driver(mtk_spi_driver); | ||
745 | |||
746 | MODULE_DESCRIPTION("MTK SPI Controller driver"); | ||
747 | MODULE_AUTHOR("Leilk Liu <leilk.liu@mediatek.com>"); | ||
748 | MODULE_LICENSE("GPL v2"); | ||
749 | MODULE_ALIAS("platform: mtk_spi"); | ||