Commit | Line | Data |
---|---|---|
f62ca4e2 LK |
1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | // Copyright (c) 2021 Sunplus Inc. | |
3 | // Author: Li-hao Kuo <lhjeff911@gmail.com> | |
4 | ||
5 | #include <linux/bitfield.h> | |
6 | #include <linux/clk.h> | |
7 | #include <linux/delay.h> | |
8 | #include <linux/dma-mapping.h> | |
9 | #include <linux/interrupt.h> | |
10 | #include <linux/module.h> | |
11 | #include <linux/of.h> | |
12 | #include <linux/platform_device.h> | |
13 | #include <linux/pm_runtime.h> | |
14 | #include <linux/reset.h> | |
15 | #include <linux/spi/spi.h> | |
16 | ||
17 | #define SP7021_DATA_RDY_REG 0x0044 | |
18 | #define SP7021_SLAVE_DMA_CTRL_REG 0x0048 | |
19 | #define SP7021_SLAVE_DMA_LENGTH_REG 0x004c | |
20 | #define SP7021_SLAVE_DMA_ADDR_REG 0x004c | |
21 | ||
22 | #define SP7021_SLAVE_DATA_RDY BIT(0) | |
23 | #define SP7021_SLAVE_SW_RST BIT(1) | |
24 | #define SP7021_SLA_DMA_W_INT BIT(8) | |
25 | #define SP7021_SLAVE_CLR_INT BIT(8) | |
26 | #define SP7021_SLAVE_DMA_EN BIT(0) | |
27 | #define SP7021_SLAVE_DMA_RW BIT(6) | |
28 | #define SP7021_SLAVE_DMA_CMD GENMASK(3, 2) | |
29 | ||
30 | #define SP7021_FIFO_REG 0x0034 | |
31 | #define SP7021_SPI_STATUS_REG 0x0038 | |
32 | #define SP7021_SPI_CONFIG_REG 0x003c | |
33 | #define SP7021_INT_BUSY_REG 0x004c | |
34 | #define SP7021_DMA_CTRL_REG 0x0050 | |
35 | ||
36 | #define SP7021_SPI_START_FD BIT(0) | |
37 | #define SP7021_FD_SW_RST BIT(1) | |
38 | #define SP7021_TX_EMP_FLAG BIT(2) | |
39 | #define SP7021_RX_EMP_FLAG BIT(4) | |
40 | #define SP7021_RX_FULL_FLAG BIT(5) | |
41 | #define SP7021_FINISH_FLAG BIT(6) | |
42 | ||
43 | #define SP7021_TX_CNT_MASK GENMASK(11, 8) | |
44 | #define SP7021_RX_CNT_MASK GENMASK(15, 12) | |
45 | #define SP7021_TX_LEN_MASK GENMASK(23, 16) | |
46 | #define SP7021_GET_LEN_MASK GENMASK(31, 24) | |
47 | #define SP7021_SET_TX_LEN GENMASK(23, 16) | |
48 | #define SP7021_SET_XFER_LEN GENMASK(31, 24) | |
49 | ||
50 | #define SP7021_CPOL_FD BIT(0) | |
51 | #define SP7021_CPHA_R BIT(1) | |
52 | #define SP7021_CPHA_W BIT(2) | |
53 | #define SP7021_LSB_SEL BIT(4) | |
54 | #define SP7021_CS_POR BIT(5) | |
55 | #define SP7021_FD_SEL BIT(6) | |
56 | ||
57 | #define SP7021_RX_UNIT GENMASK(8, 7) | |
58 | #define SP7021_TX_UNIT GENMASK(10, 9) | |
59 | #define SP7021_TX_EMP_FLAG_MASK BIT(11) | |
60 | #define SP7021_RX_FULL_FLAG_MASK BIT(14) | |
61 | #define SP7021_FINISH_FLAG_MASK BIT(15) | |
62 | #define SP7021_CLEAN_RW_BYTE GENMASK(10, 7) | |
63 | #define SP7021_CLEAN_FLUG_MASK GENMASK(15, 11) | |
64 | #define SP7021_CLK_MASK GENMASK(31, 16) | |
65 | ||
66 | #define SP7021_INT_BYPASS BIT(3) | |
67 | #define SP7021_CLR_MASTER_INT BIT(6) | |
68 | ||
69 | #define SP7021_SPI_DATA_SIZE (255) | |
70 | #define SP7021_FIFO_DATA_LEN (16) | |
71 | ||
f62ca4e2 LK |
72 | enum { |
73 | SP7021_MASTER_MODE = 0, | |
74 | SP7021_SLAVE_MODE = 1, | |
75 | }; | |
76 | ||
77 | struct sp7021_spi_ctlr { | |
78 | struct device *dev; | |
79 | struct spi_controller *ctlr; | |
80 | void __iomem *m_base; | |
81 | void __iomem *s_base; | |
82 | u32 xfer_conf; | |
83 | int mode; | |
84 | int m_irq; | |
85 | int s_irq; | |
86 | struct clk *spi_clk; | |
87 | struct reset_control *rstc; | |
f62ca4e2 LK |
88 | // data xfer lock |
89 | struct mutex buf_lock; | |
90 | struct completion isr_done; | |
91 | struct completion slave_isr; | |
92 | unsigned int rx_cur_len; | |
93 | unsigned int tx_cur_len; | |
94 | unsigned int data_unit; | |
95 | const u8 *tx_buf; | |
96 | u8 *rx_buf; | |
97 | }; | |
98 | ||
99 | static irqreturn_t sp7021_spi_slave_irq(int irq, void *dev) | |
100 | { | |
101 | struct sp7021_spi_ctlr *pspim = dev; | |
102 | unsigned int data_status; | |
103 | ||
104 | data_status = readl(pspim->s_base + SP7021_DATA_RDY_REG); | |
47e8fe57 LK |
105 | data_status |= SP7021_SLAVE_CLR_INT; |
106 | writel(data_status , pspim->s_base + SP7021_DATA_RDY_REG); | |
f62ca4e2 LK |
107 | complete(&pspim->slave_isr); |
108 | return IRQ_HANDLED; | |
109 | } | |
110 | ||
111 | static int sp7021_spi_slave_abort(struct spi_controller *ctlr) | |
112 | { | |
113 | struct sp7021_spi_ctlr *pspim = spi_master_get_devdata(ctlr); | |
114 | ||
115 | complete(&pspim->slave_isr); | |
116 | complete(&pspim->isr_done); | |
117 | return 0; | |
118 | } | |
119 | ||
6938e02f | 120 | static int sp7021_spi_slave_tx(struct spi_device *spi, struct spi_transfer *xfer) |
f62ca4e2 LK |
121 | { |
122 | struct sp7021_spi_ctlr *pspim = spi_controller_get_devdata(spi->controller); | |
47e8fe57 | 123 | u32 value; |
f62ca4e2 LK |
124 | |
125 | reinit_completion(&pspim->slave_isr); | |
47e8fe57 LK |
126 | value = SP7021_SLAVE_DMA_EN | SP7021_SLAVE_DMA_RW | FIELD_PREP(SP7021_SLAVE_DMA_CMD, 3); |
127 | writel(value, pspim->s_base + SP7021_SLAVE_DMA_CTRL_REG); | |
f62ca4e2 LK |
128 | writel(xfer->len, pspim->s_base + SP7021_SLAVE_DMA_LENGTH_REG); |
129 | writel(xfer->tx_dma, pspim->s_base + SP7021_SLAVE_DMA_ADDR_REG); | |
47e8fe57 LK |
130 | value = readl(pspim->s_base + SP7021_DATA_RDY_REG); |
131 | value |= SP7021_SLAVE_DATA_RDY; | |
132 | writel(value, pspim->s_base + SP7021_DATA_RDY_REG); | |
f62ca4e2 LK |
133 | if (wait_for_completion_interruptible(&pspim->isr_done)) { |
134 | dev_err(&spi->dev, "%s() wait_for_completion err\n", __func__); | |
135 | return -EINTR; | |
136 | } | |
137 | return 0; | |
138 | } | |
139 | ||
6938e02f | 140 | static int sp7021_spi_slave_rx(struct spi_device *spi, struct spi_transfer *xfer) |
f62ca4e2 LK |
141 | { |
142 | struct sp7021_spi_ctlr *pspim = spi_controller_get_devdata(spi->controller); | |
47e8fe57 | 143 | u32 value; |
f62ca4e2 LK |
144 | |
145 | reinit_completion(&pspim->isr_done); | |
47e8fe57 LK |
146 | value = SP7021_SLAVE_DMA_EN | FIELD_PREP(SP7021_SLAVE_DMA_CMD, 3); |
147 | writel(value, pspim->s_base + SP7021_SLAVE_DMA_CTRL_REG); | |
f62ca4e2 LK |
148 | writel(xfer->len, pspim->s_base + SP7021_SLAVE_DMA_LENGTH_REG); |
149 | writel(xfer->rx_dma, pspim->s_base + SP7021_SLAVE_DMA_ADDR_REG); | |
150 | if (wait_for_completion_interruptible(&pspim->isr_done)) { | |
151 | dev_err(&spi->dev, "%s() wait_for_completion err\n", __func__); | |
152 | return -EINTR; | |
153 | } | |
154 | writel(SP7021_SLAVE_SW_RST, pspim->s_base + SP7021_SLAVE_DMA_CTRL_REG); | |
47e8fe57 | 155 | return 0; |
f62ca4e2 LK |
156 | } |
157 | ||
6938e02f | 158 | static void sp7021_spi_master_rb(struct sp7021_spi_ctlr *pspim, unsigned int len) |
f62ca4e2 LK |
159 | { |
160 | int i; | |
161 | ||
162 | for (i = 0; i < len; i++) { | |
163 | pspim->rx_buf[pspim->rx_cur_len] = | |
164 | readl(pspim->m_base + SP7021_FIFO_REG); | |
165 | pspim->rx_cur_len++; | |
166 | } | |
167 | } | |
168 | ||
6938e02f | 169 | static void sp7021_spi_master_wb(struct sp7021_spi_ctlr *pspim, unsigned int len) |
f62ca4e2 LK |
170 | { |
171 | int i; | |
172 | ||
173 | for (i = 0; i < len; i++) { | |
174 | writel(pspim->tx_buf[pspim->tx_cur_len], | |
175 | pspim->m_base + SP7021_FIFO_REG); | |
176 | pspim->tx_cur_len++; | |
177 | } | |
178 | } | |
179 | ||
180 | static irqreturn_t sp7021_spi_master_irq(int irq, void *dev) | |
181 | { | |
182 | struct sp7021_spi_ctlr *pspim = dev; | |
183 | unsigned int tx_cnt, total_len; | |
184 | unsigned int tx_len, rx_cnt; | |
185 | unsigned int fd_status; | |
f62ca4e2 LK |
186 | bool isrdone = false; |
187 | u32 value; | |
188 | ||
189 | fd_status = readl(pspim->m_base + SP7021_SPI_STATUS_REG); | |
190 | tx_cnt = FIELD_GET(SP7021_TX_CNT_MASK, fd_status); | |
191 | tx_len = FIELD_GET(SP7021_TX_LEN_MASK, fd_status); | |
192 | total_len = FIELD_GET(SP7021_GET_LEN_MASK, fd_status); | |
193 | ||
194 | if ((fd_status & SP7021_TX_EMP_FLAG) && (fd_status & SP7021_RX_EMP_FLAG) && total_len == 0) | |
195 | return IRQ_NONE; | |
196 | ||
197 | if (tx_len == 0 && total_len == 0) | |
198 | return IRQ_NONE; | |
199 | ||
f62ca4e2 LK |
200 | rx_cnt = FIELD_GET(SP7021_RX_CNT_MASK, fd_status); |
201 | if (fd_status & SP7021_RX_FULL_FLAG) | |
202 | rx_cnt = pspim->data_unit; | |
203 | ||
204 | tx_cnt = min(tx_len - pspim->tx_cur_len, pspim->data_unit - tx_cnt); | |
205 | dev_dbg(pspim->dev, "fd_st=0x%x rx_c:%d tx_c:%d tx_l:%d", | |
206 | fd_status, rx_cnt, tx_cnt, tx_len); | |
207 | ||
208 | if (rx_cnt > 0) | |
209 | sp7021_spi_master_rb(pspim, rx_cnt); | |
210 | if (tx_cnt > 0) | |
211 | sp7021_spi_master_wb(pspim, tx_cnt); | |
212 | ||
213 | fd_status = readl(pspim->m_base + SP7021_SPI_STATUS_REG); | |
214 | tx_len = FIELD_GET(SP7021_TX_LEN_MASK, fd_status); | |
215 | total_len = FIELD_GET(SP7021_GET_LEN_MASK, fd_status); | |
216 | ||
217 | if (fd_status & SP7021_FINISH_FLAG || tx_len == pspim->tx_cur_len) { | |
218 | while (total_len != pspim->rx_cur_len) { | |
219 | fd_status = readl(pspim->m_base + SP7021_SPI_STATUS_REG); | |
220 | total_len = FIELD_GET(SP7021_GET_LEN_MASK, fd_status); | |
221 | if (fd_status & SP7021_RX_FULL_FLAG) | |
222 | rx_cnt = pspim->data_unit; | |
223 | else | |
224 | rx_cnt = FIELD_GET(SP7021_RX_CNT_MASK, fd_status); | |
225 | ||
226 | if (rx_cnt > 0) | |
227 | sp7021_spi_master_rb(pspim, rx_cnt); | |
228 | } | |
229 | value = readl(pspim->m_base + SP7021_INT_BUSY_REG); | |
230 | value |= SP7021_CLR_MASTER_INT; | |
231 | writel(value, pspim->m_base + SP7021_INT_BUSY_REG); | |
232 | writel(SP7021_FINISH_FLAG, pspim->m_base + SP7021_SPI_STATUS_REG); | |
233 | isrdone = true; | |
234 | } | |
235 | ||
236 | if (isrdone) | |
237 | complete(&pspim->isr_done); | |
f62ca4e2 LK |
238 | return IRQ_HANDLED; |
239 | } | |
240 | ||
241 | static void sp7021_prep_transfer(struct spi_controller *ctlr, struct spi_device *spi) | |
242 | { | |
243 | struct sp7021_spi_ctlr *pspim = spi_master_get_devdata(ctlr); | |
244 | ||
245 | pspim->tx_cur_len = 0; | |
246 | pspim->rx_cur_len = 0; | |
247 | pspim->data_unit = SP7021_FIFO_DATA_LEN; | |
248 | } | |
249 | ||
250 | // preliminary set CS, CPOL, CPHA and LSB | |
251 | static int sp7021_spi_controller_prepare_message(struct spi_controller *ctlr, | |
252 | struct spi_message *msg) | |
253 | { | |
254 | struct sp7021_spi_ctlr *pspim = spi_master_get_devdata(ctlr); | |
255 | struct spi_device *s = msg->spi; | |
256 | u32 valus, rs = 0; | |
257 | ||
258 | valus = readl(pspim->m_base + SP7021_SPI_STATUS_REG); | |
259 | valus |= SP7021_FD_SW_RST; | |
260 | writel(valus, pspim->m_base + SP7021_SPI_STATUS_REG); | |
261 | rs |= SP7021_FD_SEL; | |
262 | if (s->mode & SPI_CPOL) | |
263 | rs |= SP7021_CPOL_FD; | |
264 | ||
265 | if (s->mode & SPI_LSB_FIRST) | |
266 | rs |= SP7021_LSB_SEL; | |
267 | ||
268 | if (s->mode & SPI_CS_HIGH) | |
269 | rs |= SP7021_CS_POR; | |
270 | ||
271 | if (s->mode & SPI_CPHA) | |
272 | rs |= SP7021_CPHA_R; | |
273 | else | |
274 | rs |= SP7021_CPHA_W; | |
275 | ||
276 | rs |= FIELD_PREP(SP7021_TX_UNIT, 0) | FIELD_PREP(SP7021_RX_UNIT, 0); | |
277 | pspim->xfer_conf = rs; | |
278 | if (pspim->xfer_conf & SP7021_CPOL_FD) | |
279 | writel(pspim->xfer_conf, pspim->m_base + SP7021_SPI_CONFIG_REG); | |
280 | ||
281 | return 0; | |
282 | } | |
283 | ||
284 | static void sp7021_spi_setup_clk(struct spi_controller *ctlr, struct spi_transfer *xfer) | |
285 | { | |
286 | struct sp7021_spi_ctlr *pspim = spi_master_get_devdata(ctlr); | |
287 | u32 clk_rate, clk_sel, div; | |
288 | ||
289 | clk_rate = clk_get_rate(pspim->spi_clk); | |
47e8fe57 LK |
290 | div = max(2U, clk_rate / xfer->speed_hz); |
291 | ||
f62ca4e2 | 292 | clk_sel = (div / 2) - 1; |
47e8fe57 | 293 | pspim->xfer_conf &= ~SP7021_CLK_MASK; |
f62ca4e2 LK |
294 | pspim->xfer_conf |= FIELD_PREP(SP7021_CLK_MASK, clk_sel); |
295 | writel(pspim->xfer_conf, pspim->m_base + SP7021_SPI_CONFIG_REG); | |
296 | } | |
297 | ||
298 | static int sp7021_spi_master_transfer_one(struct spi_controller *ctlr, struct spi_device *spi, | |
299 | struct spi_transfer *xfer) | |
300 | { | |
301 | struct sp7021_spi_ctlr *pspim = spi_master_get_devdata(ctlr); | |
302 | unsigned long timeout = msecs_to_jiffies(1000); | |
303 | unsigned int xfer_cnt, xfer_len, last_len; | |
304 | unsigned int i, len_temp; | |
305 | u32 reg_temp; | |
f62ca4e2 LK |
306 | |
307 | xfer_cnt = xfer->len / SP7021_SPI_DATA_SIZE; | |
308 | last_len = xfer->len % SP7021_SPI_DATA_SIZE; | |
309 | ||
310 | for (i = 0; i <= xfer_cnt; i++) { | |
311 | mutex_lock(&pspim->buf_lock); | |
312 | sp7021_prep_transfer(ctlr, spi); | |
313 | sp7021_spi_setup_clk(ctlr, xfer); | |
314 | reinit_completion(&pspim->isr_done); | |
315 | ||
316 | if (i == xfer_cnt) | |
317 | xfer_len = last_len; | |
318 | else | |
319 | xfer_len = SP7021_SPI_DATA_SIZE; | |
320 | ||
321 | pspim->tx_buf = xfer->tx_buf + i * SP7021_SPI_DATA_SIZE; | |
322 | pspim->rx_buf = xfer->rx_buf + i * SP7021_SPI_DATA_SIZE; | |
323 | ||
324 | if (pspim->tx_cur_len < xfer_len) { | |
325 | len_temp = min(pspim->data_unit, xfer_len); | |
326 | sp7021_spi_master_wb(pspim, len_temp); | |
327 | } | |
328 | reg_temp = readl(pspim->m_base + SP7021_SPI_CONFIG_REG); | |
329 | reg_temp &= ~SP7021_CLEAN_RW_BYTE; | |
330 | reg_temp &= ~SP7021_CLEAN_FLUG_MASK; | |
331 | reg_temp |= SP7021_FD_SEL | SP7021_FINISH_FLAG_MASK | | |
332 | SP7021_TX_EMP_FLAG_MASK | SP7021_RX_FULL_FLAG_MASK | | |
333 | FIELD_PREP(SP7021_TX_UNIT, 0) | FIELD_PREP(SP7021_RX_UNIT, 0); | |
334 | writel(reg_temp, pspim->m_base + SP7021_SPI_CONFIG_REG); | |
335 | ||
336 | reg_temp = FIELD_PREP(SP7021_SET_TX_LEN, xfer_len) | | |
337 | FIELD_PREP(SP7021_SET_XFER_LEN, xfer_len) | | |
338 | SP7021_SPI_START_FD; | |
339 | writel(reg_temp, pspim->m_base + SP7021_SPI_STATUS_REG); | |
340 | ||
341 | if (!wait_for_completion_interruptible_timeout(&pspim->isr_done, timeout)) { | |
342 | dev_err(&spi->dev, "wait_for_completion err\n"); | |
20dc69ca | 343 | mutex_unlock(&pspim->buf_lock); |
f62ca4e2 LK |
344 | return -ETIMEDOUT; |
345 | } | |
346 | ||
347 | reg_temp = readl(pspim->m_base + SP7021_SPI_STATUS_REG); | |
348 | if (reg_temp & SP7021_FINISH_FLAG) { | |
349 | writel(SP7021_FINISH_FLAG, pspim->m_base + SP7021_SPI_STATUS_REG); | |
350 | writel(readl(pspim->m_base + SP7021_SPI_CONFIG_REG) & | |
351 | SP7021_CLEAN_FLUG_MASK, pspim->m_base + SP7021_SPI_CONFIG_REG); | |
352 | } | |
353 | ||
354 | if (pspim->xfer_conf & SP7021_CPOL_FD) | |
355 | writel(pspim->xfer_conf, pspim->m_base + SP7021_SPI_CONFIG_REG); | |
356 | ||
357 | mutex_unlock(&pspim->buf_lock); | |
f62ca4e2 | 358 | } |
47e8fe57 | 359 | return 0; |
f62ca4e2 LK |
360 | } |
361 | ||
362 | static int sp7021_spi_slave_transfer_one(struct spi_controller *ctlr, struct spi_device *spi, | |
363 | struct spi_transfer *xfer) | |
364 | { | |
365 | struct sp7021_spi_ctlr *pspim = spi_master_get_devdata(ctlr); | |
366 | struct device *dev = pspim->dev; | |
5790597d | 367 | int ret; |
f62ca4e2 | 368 | |
5790597d | 369 | if (xfer->tx_buf && !xfer->rx_buf) { |
f62ca4e2 LK |
370 | xfer->tx_dma = dma_map_single(dev, (void *)xfer->tx_buf, |
371 | xfer->len, DMA_TO_DEVICE); | |
372 | if (dma_mapping_error(dev, xfer->tx_dma)) | |
373 | return -ENOMEM; | |
07025cea YL |
374 | ret = sp7021_spi_slave_tx(spi, xfer); |
375 | dma_unmap_single(dev, xfer->tx_dma, xfer->len, DMA_TO_DEVICE); | |
5790597d | 376 | } else if (xfer->rx_buf && !xfer->tx_buf) { |
f62ca4e2 LK |
377 | xfer->rx_dma = dma_map_single(dev, xfer->rx_buf, xfer->len, |
378 | DMA_FROM_DEVICE); | |
379 | if (dma_mapping_error(dev, xfer->rx_dma)) | |
380 | return -ENOMEM; | |
f62ca4e2 | 381 | ret = sp7021_spi_slave_rx(spi, xfer); |
f62ca4e2 | 382 | dma_unmap_single(dev, xfer->rx_dma, xfer->len, DMA_FROM_DEVICE); |
5790597d LK |
383 | } else { |
384 | dev_dbg(&ctlr->dev, "%s() wrong command\n", __func__); | |
385 | return -EINVAL; | |
386 | } | |
f62ca4e2 LK |
387 | |
388 | spi_finalize_current_transfer(ctlr); | |
389 | return ret; | |
390 | } | |
391 | ||
392 | static void sp7021_spi_disable_unprepare(void *data) | |
393 | { | |
394 | clk_disable_unprepare(data); | |
395 | } | |
396 | ||
397 | static void sp7021_spi_reset_control_assert(void *data) | |
398 | { | |
399 | reset_control_assert(data); | |
400 | } | |
401 | ||
402 | static int sp7021_spi_controller_probe(struct platform_device *pdev) | |
403 | { | |
404 | struct device *dev = &pdev->dev; | |
405 | struct sp7021_spi_ctlr *pspim; | |
406 | struct spi_controller *ctlr; | |
407 | int mode, ret; | |
408 | ||
409 | pdev->id = of_alias_get_id(pdev->dev.of_node, "sp_spi"); | |
410 | ||
411 | if (device_property_read_bool(dev, "spi-slave")) | |
412 | mode = SP7021_SLAVE_MODE; | |
413 | else | |
414 | mode = SP7021_MASTER_MODE; | |
415 | ||
416 | if (mode == SP7021_SLAVE_MODE) | |
417 | ctlr = devm_spi_alloc_slave(dev, sizeof(*pspim)); | |
418 | else | |
419 | ctlr = devm_spi_alloc_master(dev, sizeof(*pspim)); | |
420 | if (!ctlr) | |
421 | return -ENOMEM; | |
47e8fe57 | 422 | device_set_node(&ctlr->dev, dev_fwnode(dev)); |
f62ca4e2 LK |
423 | ctlr->bus_num = pdev->id; |
424 | ctlr->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH | SPI_LSB_FIRST; | |
425 | ctlr->auto_runtime_pm = true; | |
426 | ctlr->prepare_message = sp7021_spi_controller_prepare_message; | |
427 | if (mode == SP7021_SLAVE_MODE) { | |
428 | ctlr->transfer_one = sp7021_spi_slave_transfer_one; | |
429 | ctlr->slave_abort = sp7021_spi_slave_abort; | |
430 | ctlr->flags = SPI_CONTROLLER_HALF_DUPLEX; | |
431 | } else { | |
432 | ctlr->bits_per_word_mask = SPI_BPW_MASK(8); | |
433 | ctlr->min_speed_hz = 40000; | |
434 | ctlr->max_speed_hz = 25000000; | |
435 | ctlr->use_gpio_descriptors = true; | |
436 | ctlr->flags = SPI_CONTROLLER_MUST_RX | SPI_CONTROLLER_MUST_TX; | |
437 | ctlr->transfer_one = sp7021_spi_master_transfer_one; | |
438 | } | |
439 | platform_set_drvdata(pdev, ctlr); | |
440 | pspim = spi_controller_get_devdata(ctlr); | |
441 | pspim->mode = mode; | |
442 | pspim->ctlr = ctlr; | |
443 | pspim->dev = dev; | |
f62ca4e2 LK |
444 | mutex_init(&pspim->buf_lock); |
445 | init_completion(&pspim->isr_done); | |
446 | init_completion(&pspim->slave_isr); | |
447 | ||
448 | pspim->m_base = devm_platform_ioremap_resource_byname(pdev, "master"); | |
449 | if (IS_ERR(pspim->m_base)) | |
450 | return dev_err_probe(dev, PTR_ERR(pspim->m_base), "m_base get fail\n"); | |
451 | ||
452 | pspim->s_base = devm_platform_ioremap_resource_byname(pdev, "slave"); | |
453 | if (IS_ERR(pspim->s_base)) | |
454 | return dev_err_probe(dev, PTR_ERR(pspim->s_base), "s_base get fail\n"); | |
455 | ||
456 | pspim->m_irq = platform_get_irq_byname(pdev, "master_risc"); | |
457 | if (pspim->m_irq < 0) | |
458 | return pspim->m_irq; | |
459 | ||
460 | pspim->s_irq = platform_get_irq_byname(pdev, "slave_risc"); | |
461 | if (pspim->s_irq < 0) | |
462 | return pspim->s_irq; | |
463 | ||
f62ca4e2 LK |
464 | pspim->spi_clk = devm_clk_get(dev, NULL); |
465 | if (IS_ERR(pspim->spi_clk)) | |
466 | return dev_err_probe(dev, PTR_ERR(pspim->spi_clk), "clk get fail\n"); | |
467 | ||
468 | pspim->rstc = devm_reset_control_get_exclusive(dev, NULL); | |
469 | if (IS_ERR(pspim->rstc)) | |
470 | return dev_err_probe(dev, PTR_ERR(pspim->rstc), "rst get fail\n"); | |
471 | ||
472 | ret = clk_prepare_enable(pspim->spi_clk); | |
473 | if (ret) | |
474 | return dev_err_probe(dev, ret, "failed to enable clk\n"); | |
475 | ||
476 | ret = devm_add_action_or_reset(dev, sp7021_spi_disable_unprepare, pspim->spi_clk); | |
477 | if (ret) | |
478 | return ret; | |
479 | ||
480 | ret = reset_control_deassert(pspim->rstc); | |
481 | if (ret) | |
482 | return dev_err_probe(dev, ret, "failed to deassert reset\n"); | |
483 | ||
484 | ret = devm_add_action_or_reset(dev, sp7021_spi_reset_control_assert, pspim->rstc); | |
485 | if (ret) | |
486 | return ret; | |
487 | ||
47e8fe57 LK |
488 | ret = devm_request_irq(dev, pspim->m_irq, sp7021_spi_master_irq, |
489 | IRQF_TRIGGER_RISING, pdev->name, pspim); | |
490 | if (ret) | |
491 | return ret; | |
492 | ||
493 | ret = devm_request_irq(dev, pspim->s_irq, sp7021_spi_slave_irq, | |
494 | IRQF_TRIGGER_RISING, pdev->name, pspim); | |
495 | if (ret) | |
496 | return ret; | |
497 | ||
f62ca4e2 LK |
498 | pm_runtime_enable(dev); |
499 | ret = spi_register_controller(ctlr); | |
500 | if (ret) { | |
501 | pm_runtime_disable(dev); | |
502 | return dev_err_probe(dev, ret, "spi_register_master fail\n"); | |
503 | } | |
504 | return 0; | |
505 | } | |
506 | ||
507 | static int sp7021_spi_controller_remove(struct platform_device *pdev) | |
508 | { | |
509 | struct spi_controller *ctlr = dev_get_drvdata(&pdev->dev); | |
510 | ||
511 | spi_unregister_controller(ctlr); | |
512 | pm_runtime_disable(&pdev->dev); | |
513 | pm_runtime_set_suspended(&pdev->dev); | |
514 | return 0; | |
515 | } | |
516 | ||
517 | static int __maybe_unused sp7021_spi_controller_suspend(struct device *dev) | |
518 | { | |
519 | struct spi_controller *ctlr = dev_get_drvdata(dev); | |
520 | struct sp7021_spi_ctlr *pspim = spi_master_get_devdata(ctlr); | |
521 | ||
522 | return reset_control_assert(pspim->rstc); | |
523 | } | |
524 | ||
525 | static int __maybe_unused sp7021_spi_controller_resume(struct device *dev) | |
526 | { | |
527 | struct spi_controller *ctlr = dev_get_drvdata(dev); | |
528 | struct sp7021_spi_ctlr *pspim = spi_master_get_devdata(ctlr); | |
529 | ||
530 | reset_control_deassert(pspim->rstc); | |
531 | return clk_prepare_enable(pspim->spi_clk); | |
532 | } | |
533 | ||
6938e02f | 534 | #ifdef CONFIG_PM |
f62ca4e2 LK |
535 | static int sp7021_spi_runtime_suspend(struct device *dev) |
536 | { | |
537 | struct spi_controller *ctlr = dev_get_drvdata(dev); | |
538 | struct sp7021_spi_ctlr *pspim = spi_master_get_devdata(ctlr); | |
539 | ||
540 | return reset_control_assert(pspim->rstc); | |
541 | } | |
542 | ||
543 | static int sp7021_spi_runtime_resume(struct device *dev) | |
544 | { | |
545 | struct spi_controller *ctlr = dev_get_drvdata(dev); | |
546 | struct sp7021_spi_ctlr *pspim = spi_master_get_devdata(ctlr); | |
547 | ||
548 | return reset_control_deassert(pspim->rstc); | |
549 | } | |
6938e02f | 550 | #endif |
f62ca4e2 LK |
551 | |
552 | static const struct dev_pm_ops sp7021_spi_pm_ops = { | |
553 | SET_RUNTIME_PM_OPS(sp7021_spi_runtime_suspend, | |
554 | sp7021_spi_runtime_resume, NULL) | |
555 | SET_SYSTEM_SLEEP_PM_OPS(sp7021_spi_controller_suspend, | |
556 | sp7021_spi_controller_resume) | |
557 | }; | |
558 | ||
559 | static const struct of_device_id sp7021_spi_controller_ids[] = { | |
560 | { .compatible = "sunplus,sp7021-spi" }, | |
561 | {} | |
562 | }; | |
563 | MODULE_DEVICE_TABLE(of, sp7021_spi_controller_ids); | |
564 | ||
565 | static struct platform_driver sp7021_spi_controller_driver = { | |
566 | .probe = sp7021_spi_controller_probe, | |
567 | .remove = sp7021_spi_controller_remove, | |
568 | .driver = { | |
569 | .name = "sunplus,sp7021-spi-controller", | |
570 | .of_match_table = sp7021_spi_controller_ids, | |
571 | .pm = &sp7021_spi_pm_ops, | |
572 | }, | |
573 | }; | |
574 | module_platform_driver(sp7021_spi_controller_driver); | |
575 | ||
576 | MODULE_AUTHOR("Li-hao Kuo <lhjeff911@gmail.com>"); | |
577 | MODULE_DESCRIPTION("Sunplus SPI controller driver"); | |
578 | MODULE_LICENSE("GPL"); |