blob: 3918639140436e16707f854d8a5a5b9725515ce7 [file] [log] [blame]
Fabio Estevam6126fd82018-05-02 16:18:29 -03001// SPDX-License-Identifier: GPL-2.0+
2//
3// Freescale i.MX7ULP LPSPI driver
4//
5// Copyright 2016 Freescale Semiconductor, Inc.
Clark Wang07d71552018-12-07 02:50:34 +00006// Copyright 2018 NXP Semiconductors
Gao Pan53149872016-11-22 21:52:17 +08007
8#include <linux/clk.h>
9#include <linux/completion.h>
10#include <linux/delay.h>
11#include <linux/err.h>
12#include <linux/interrupt.h>
13#include <linux/io.h>
14#include <linux/irq.h>
15#include <linux/kernel.h>
16#include <linux/module.h>
17#include <linux/of.h>
18#include <linux/of_device.h>
19#include <linux/platform_device.h>
20#include <linux/slab.h>
21#include <linux/spi/spi.h>
22#include <linux/spi/spi_bitbang.h>
23#include <linux/types.h>
24
25#define DRIVER_NAME "fsl_lpspi"
26
27/* i.MX7ULP LPSPI registers */
28#define IMX7ULP_VERID 0x0
29#define IMX7ULP_PARAM 0x4
30#define IMX7ULP_CR 0x10
31#define IMX7ULP_SR 0x14
32#define IMX7ULP_IER 0x18
33#define IMX7ULP_DER 0x1c
34#define IMX7ULP_CFGR0 0x20
35#define IMX7ULP_CFGR1 0x24
36#define IMX7ULP_DMR0 0x30
37#define IMX7ULP_DMR1 0x34
38#define IMX7ULP_CCR 0x40
39#define IMX7ULP_FCR 0x58
40#define IMX7ULP_FSR 0x5c
41#define IMX7ULP_TCR 0x60
42#define IMX7ULP_TDR 0x64
43#define IMX7ULP_RSR 0x70
44#define IMX7ULP_RDR 0x74
45
46/* General control register field define */
47#define CR_RRF BIT(9)
48#define CR_RTF BIT(8)
49#define CR_RST BIT(1)
50#define CR_MEN BIT(0)
Clark Wang6a130442019-01-07 07:47:41 +000051#define SR_MBF BIT(24)
Gao Pan53149872016-11-22 21:52:17 +080052#define SR_TCF BIT(10)
Clark Wangc23fdef2019-01-07 07:47:38 +000053#define SR_FCF BIT(9)
Gao Pan53149872016-11-22 21:52:17 +080054#define SR_RDF BIT(1)
55#define SR_TDF BIT(0)
56#define IER_TCIE BIT(10)
Clark Wangc23fdef2019-01-07 07:47:38 +000057#define IER_FCIE BIT(9)
Gao Pan53149872016-11-22 21:52:17 +080058#define IER_RDIE BIT(1)
59#define IER_TDIE BIT(0)
60#define CFGR1_PCSCFG BIT(27)
Clark Wangbcd87312018-12-07 02:50:36 +000061#define CFGR1_PINCFG (BIT(24)|BIT(25))
Gao Pan53149872016-11-22 21:52:17 +080062#define CFGR1_PCSPOL BIT(8)
63#define CFGR1_NOSTALL BIT(3)
64#define CFGR1_MASTER BIT(0)
Clark Wang6a130442019-01-07 07:47:41 +000065#define FSR_RXCOUNT (BIT(16)|BIT(17)|BIT(18))
Gao Pan53149872016-11-22 21:52:17 +080066#define RSR_RXEMPTY BIT(1)
67#define TCR_CPOL BIT(31)
68#define TCR_CPHA BIT(30)
69#define TCR_CONT BIT(21)
70#define TCR_CONTC BIT(20)
71#define TCR_RXMSK BIT(19)
72#define TCR_TXMSK BIT(18)
73
74static int clkdivs[] = {1, 2, 4, 8, 16, 32, 64, 128};
75
76struct lpspi_config {
77 u8 bpw;
78 u8 chip_select;
79 u8 prescale;
80 u16 mode;
81 u32 speed_hz;
82};
83
84struct fsl_lpspi_data {
85 struct device *dev;
86 void __iomem *base;
87 struct clk *clk;
Clark Wangbcd87312018-12-07 02:50:36 +000088 bool is_slave;
Gao Pan53149872016-11-22 21:52:17 +080089
90 void *rx_buf;
91 const void *tx_buf;
92 void (*tx)(struct fsl_lpspi_data *);
93 void (*rx)(struct fsl_lpspi_data *);
94
95 u32 remain;
Clark Wangcf868742018-12-07 02:50:38 +000096 u8 watermark;
Gao Pan53149872016-11-22 21:52:17 +080097 u8 txfifosize;
98 u8 rxfifosize;
99
100 struct lpspi_config config;
101 struct completion xfer_done;
Clark Wangbcd87312018-12-07 02:50:36 +0000102
103 bool slave_aborted;
Gao Pan53149872016-11-22 21:52:17 +0800104};
105
106static const struct of_device_id fsl_lpspi_dt_ids[] = {
107 { .compatible = "fsl,imx7ulp-spi", },
108 { /* sentinel */ }
109};
110MODULE_DEVICE_TABLE(of, fsl_lpspi_dt_ids);
111
112#define LPSPI_BUF_RX(type) \
113static void fsl_lpspi_buf_rx_##type(struct fsl_lpspi_data *fsl_lpspi) \
114{ \
115 unsigned int val = readl(fsl_lpspi->base + IMX7ULP_RDR); \
116 \
117 if (fsl_lpspi->rx_buf) { \
118 *(type *)fsl_lpspi->rx_buf = val; \
119 fsl_lpspi->rx_buf += sizeof(type); \
120 } \
121}
122
123#define LPSPI_BUF_TX(type) \
124static void fsl_lpspi_buf_tx_##type(struct fsl_lpspi_data *fsl_lpspi) \
125{ \
126 type val = 0; \
127 \
128 if (fsl_lpspi->tx_buf) { \
129 val = *(type *)fsl_lpspi->tx_buf; \
130 fsl_lpspi->tx_buf += sizeof(type); \
131 } \
132 \
133 fsl_lpspi->remain -= sizeof(type); \
134 writel(val, fsl_lpspi->base + IMX7ULP_TDR); \
135}
136
137LPSPI_BUF_RX(u8)
138LPSPI_BUF_TX(u8)
139LPSPI_BUF_RX(u16)
140LPSPI_BUF_TX(u16)
141LPSPI_BUF_RX(u32)
142LPSPI_BUF_TX(u32)
143
144static void fsl_lpspi_intctrl(struct fsl_lpspi_data *fsl_lpspi,
145 unsigned int enable)
146{
147 writel(enable, fsl_lpspi->base + IMX7ULP_IER);
148}
149
Clark Wang07d71552018-12-07 02:50:34 +0000150static int lpspi_prepare_xfer_hardware(struct spi_controller *controller)
Gao Pan53149872016-11-22 21:52:17 +0800151{
Clark Wang07d71552018-12-07 02:50:34 +0000152 struct fsl_lpspi_data *fsl_lpspi =
153 spi_controller_get_devdata(controller);
Gao Pan53149872016-11-22 21:52:17 +0800154
155 return clk_prepare_enable(fsl_lpspi->clk);
156}
157
Clark Wang07d71552018-12-07 02:50:34 +0000158static int lpspi_unprepare_xfer_hardware(struct spi_controller *controller)
Gao Pan53149872016-11-22 21:52:17 +0800159{
Clark Wang07d71552018-12-07 02:50:34 +0000160 struct fsl_lpspi_data *fsl_lpspi =
161 spi_controller_get_devdata(controller);
Gao Pan53149872016-11-22 21:52:17 +0800162
163 clk_disable_unprepare(fsl_lpspi->clk);
164
165 return 0;
166}
167
Gao Pan53149872016-11-22 21:52:17 +0800168static void fsl_lpspi_write_tx_fifo(struct fsl_lpspi_data *fsl_lpspi)
169{
170 u8 txfifo_cnt;
Clark Wangc23fdef2019-01-07 07:47:38 +0000171 u32 temp;
Gao Pan53149872016-11-22 21:52:17 +0800172
173 txfifo_cnt = readl(fsl_lpspi->base + IMX7ULP_FSR) & 0xff;
174
175 while (txfifo_cnt < fsl_lpspi->txfifosize) {
176 if (!fsl_lpspi->remain)
177 break;
178 fsl_lpspi->tx(fsl_lpspi);
179 txfifo_cnt++;
180 }
181
Clark Wangc23fdef2019-01-07 07:47:38 +0000182 if (txfifo_cnt < fsl_lpspi->txfifosize) {
183 if (!fsl_lpspi->is_slave) {
184 temp = readl(fsl_lpspi->base + IMX7ULP_TCR);
185 temp &= ~TCR_CONTC;
186 writel(temp, fsl_lpspi->base + IMX7ULP_TCR);
187 }
188
189 fsl_lpspi_intctrl(fsl_lpspi, IER_FCIE);
190 } else
Gao Pan53149872016-11-22 21:52:17 +0800191 fsl_lpspi_intctrl(fsl_lpspi, IER_TDIE);
192}
193
194static void fsl_lpspi_read_rx_fifo(struct fsl_lpspi_data *fsl_lpspi)
195{
196 while (!(readl(fsl_lpspi->base + IMX7ULP_RSR) & RSR_RXEMPTY))
197 fsl_lpspi->rx(fsl_lpspi);
198}
199
200static void fsl_lpspi_set_cmd(struct fsl_lpspi_data *fsl_lpspi,
201 bool is_first_xfer)
202{
203 u32 temp = 0;
204
205 temp |= fsl_lpspi->config.bpw - 1;
Gao Pane3a49392016-11-24 19:04:43 +0800206 temp |= (fsl_lpspi->config.mode & 0x3) << 30;
Clark Wangbcd87312018-12-07 02:50:36 +0000207 if (!fsl_lpspi->is_slave) {
208 temp |= fsl_lpspi->config.prescale << 27;
209 temp |= (fsl_lpspi->config.chip_select & 0x3) << 24;
Gao Pan53149872016-11-22 21:52:17 +0800210
Clark Wangbcd87312018-12-07 02:50:36 +0000211 /*
212 * Set TCR_CONT will keep SS asserted after current transfer.
213 * For the first transfer, clear TCR_CONTC to assert SS.
214 * For subsequent transfer, set TCR_CONTC to keep SS asserted.
215 */
216 temp |= TCR_CONT;
217 if (is_first_xfer)
218 temp &= ~TCR_CONTC;
219 else
220 temp |= TCR_CONTC;
221 }
Gao Pan53149872016-11-22 21:52:17 +0800222 writel(temp, fsl_lpspi->base + IMX7ULP_TCR);
223
224 dev_dbg(fsl_lpspi->dev, "TCR=0x%x\n", temp);
225}
226
227static void fsl_lpspi_set_watermark(struct fsl_lpspi_data *fsl_lpspi)
228{
Gao Pan53149872016-11-22 21:52:17 +0800229 u32 temp;
230
Clark Wangcf868742018-12-07 02:50:38 +0000231 temp = fsl_lpspi->watermark >> 1 | (fsl_lpspi->watermark >> 1) << 16;
Gao Pan53149872016-11-22 21:52:17 +0800232
233 writel(temp, fsl_lpspi->base + IMX7ULP_FCR);
234
235 dev_dbg(fsl_lpspi->dev, "FCR=0x%x\n", temp);
236}
237
238static int fsl_lpspi_set_bitrate(struct fsl_lpspi_data *fsl_lpspi)
239{
240 struct lpspi_config config = fsl_lpspi->config;
241 unsigned int perclk_rate, scldiv;
242 u8 prescale;
243
244 perclk_rate = clk_get_rate(fsl_lpspi->clk);
245 for (prescale = 0; prescale < 8; prescale++) {
246 scldiv = perclk_rate /
247 (clkdivs[prescale] * config.speed_hz) - 2;
248 if (scldiv < 256) {
249 fsl_lpspi->config.prescale = prescale;
250 break;
251 }
252 }
253
254 if (prescale == 8 && scldiv >= 256)
255 return -EINVAL;
256
Clark Wangcf868742018-12-07 02:50:38 +0000257 writel(scldiv | (scldiv << 8) | ((scldiv >> 1) << 16),
258 fsl_lpspi->base + IMX7ULP_CCR);
Gao Pan53149872016-11-22 21:52:17 +0800259
260 dev_dbg(fsl_lpspi->dev, "perclk=%d, speed=%d, prescale =%d, scldiv=%d\n",
261 perclk_rate, config.speed_hz, prescale, scldiv);
262
263 return 0;
264}
265
266static int fsl_lpspi_config(struct fsl_lpspi_data *fsl_lpspi)
267{
268 u32 temp;
269 int ret;
270
Clark Wangbcd87312018-12-07 02:50:36 +0000271 if (!fsl_lpspi->is_slave) {
272 ret = fsl_lpspi_set_bitrate(fsl_lpspi);
273 if (ret)
274 return ret;
275 }
Gao Pan53149872016-11-22 21:52:17 +0800276
277 fsl_lpspi_set_watermark(fsl_lpspi);
278
Clark Wangbcd87312018-12-07 02:50:36 +0000279 if (!fsl_lpspi->is_slave)
280 temp = CFGR1_MASTER;
281 else
282 temp = CFGR1_PINCFG;
Gao Pan53149872016-11-22 21:52:17 +0800283 if (fsl_lpspi->config.mode & SPI_CS_HIGH)
284 temp |= CFGR1_PCSPOL;
285 writel(temp, fsl_lpspi->base + IMX7ULP_CFGR1);
286
287 temp = readl(fsl_lpspi->base + IMX7ULP_CR);
288 temp |= CR_RRF | CR_RTF | CR_MEN;
289 writel(temp, fsl_lpspi->base + IMX7ULP_CR);
290
291 return 0;
292}
293
294static void fsl_lpspi_setup_transfer(struct spi_device *spi,
295 struct spi_transfer *t)
296{
Clark Wang07d71552018-12-07 02:50:34 +0000297 struct fsl_lpspi_data *fsl_lpspi =
298 spi_controller_get_devdata(spi->controller);
Gao Pan53149872016-11-22 21:52:17 +0800299
300 fsl_lpspi->config.mode = spi->mode;
301 fsl_lpspi->config.bpw = t ? t->bits_per_word : spi->bits_per_word;
302 fsl_lpspi->config.speed_hz = t ? t->speed_hz : spi->max_speed_hz;
303 fsl_lpspi->config.chip_select = spi->chip_select;
304
305 if (!fsl_lpspi->config.speed_hz)
306 fsl_lpspi->config.speed_hz = spi->max_speed_hz;
307 if (!fsl_lpspi->config.bpw)
308 fsl_lpspi->config.bpw = spi->bits_per_word;
309
310 /* Initialize the functions for transfer */
311 if (fsl_lpspi->config.bpw <= 8) {
312 fsl_lpspi->rx = fsl_lpspi_buf_rx_u8;
313 fsl_lpspi->tx = fsl_lpspi_buf_tx_u8;
314 } else if (fsl_lpspi->config.bpw <= 16) {
315 fsl_lpspi->rx = fsl_lpspi_buf_rx_u16;
316 fsl_lpspi->tx = fsl_lpspi_buf_tx_u16;
317 } else {
318 fsl_lpspi->rx = fsl_lpspi_buf_rx_u32;
319 fsl_lpspi->tx = fsl_lpspi_buf_tx_u32;
320 }
321
Clark Wangcf868742018-12-07 02:50:38 +0000322 if (t->len <= fsl_lpspi->txfifosize)
323 fsl_lpspi->watermark = t->len;
324 else
325 fsl_lpspi->watermark = fsl_lpspi->txfifosize;
326
Gao Pan53149872016-11-22 21:52:17 +0800327 fsl_lpspi_config(fsl_lpspi);
328}
329
Clark Wangbcd87312018-12-07 02:50:36 +0000330static int fsl_lpspi_slave_abort(struct spi_controller *controller)
331{
332 struct fsl_lpspi_data *fsl_lpspi =
333 spi_controller_get_devdata(controller);
334
335 fsl_lpspi->slave_aborted = true;
336 complete(&fsl_lpspi->xfer_done);
337 return 0;
338}
339
340static int fsl_lpspi_wait_for_completion(struct spi_controller *controller)
341{
342 struct fsl_lpspi_data *fsl_lpspi =
343 spi_controller_get_devdata(controller);
344
345 if (fsl_lpspi->is_slave) {
346 if (wait_for_completion_interruptible(&fsl_lpspi->xfer_done) ||
347 fsl_lpspi->slave_aborted) {
348 dev_dbg(fsl_lpspi->dev, "interrupted\n");
349 return -EINTR;
350 }
351 } else {
352 if (!wait_for_completion_timeout(&fsl_lpspi->xfer_done, HZ)) {
353 dev_dbg(fsl_lpspi->dev, "wait for completion timeout\n");
354 return -ETIMEDOUT;
355 }
356 }
357
358 return 0;
359}
360
Clark Wanga15dc3d2019-01-07 07:47:43 +0000361static int fsl_lpspi_reset(struct fsl_lpspi_data *fsl_lpspi)
362{
363 u32 temp;
364
365 /* Disable all interrupt */
366 fsl_lpspi_intctrl(fsl_lpspi, 0);
367
368 /* W1C for all flags in SR */
369 temp = 0x3F << 8;
370 writel(temp, fsl_lpspi->base + IMX7ULP_SR);
371
372 /* Clear FIFO and disable module */
373 temp = CR_RRF | CR_RTF;
374 writel(temp, fsl_lpspi->base + IMX7ULP_CR);
375
376 return 0;
377}
378
Clark Wang07d71552018-12-07 02:50:34 +0000379static int fsl_lpspi_transfer_one(struct spi_controller *controller,
Gao Pan53149872016-11-22 21:52:17 +0800380 struct spi_device *spi,
381 struct spi_transfer *t)
382{
Clark Wang07d71552018-12-07 02:50:34 +0000383 struct fsl_lpspi_data *fsl_lpspi =
384 spi_controller_get_devdata(controller);
Gao Pan53149872016-11-22 21:52:17 +0800385 int ret;
386
387 fsl_lpspi->tx_buf = t->tx_buf;
388 fsl_lpspi->rx_buf = t->rx_buf;
389 fsl_lpspi->remain = t->len;
390
391 reinit_completion(&fsl_lpspi->xfer_done);
Clark Wangbcd87312018-12-07 02:50:36 +0000392 fsl_lpspi->slave_aborted = false;
393
Gao Pan53149872016-11-22 21:52:17 +0800394 fsl_lpspi_write_tx_fifo(fsl_lpspi);
Gao Pand2ad0a622016-11-28 11:02:59 +0800395
Clark Wangbcd87312018-12-07 02:50:36 +0000396 ret = fsl_lpspi_wait_for_completion(controller);
397 if (ret)
398 return ret;
Gao Pan53149872016-11-22 21:52:17 +0800399
Clark Wanga15dc3d2019-01-07 07:47:43 +0000400 fsl_lpspi_reset(fsl_lpspi);
401
Gao Pand989eed2016-12-02 11:50:01 +0800402 return 0;
Gao Pan53149872016-11-22 21:52:17 +0800403}
404
Clark Wang07d71552018-12-07 02:50:34 +0000405static int fsl_lpspi_transfer_one_msg(struct spi_controller *controller,
Gao Pan53149872016-11-22 21:52:17 +0800406 struct spi_message *msg)
407{
Clark Wang07d71552018-12-07 02:50:34 +0000408 struct fsl_lpspi_data *fsl_lpspi =
409 spi_controller_get_devdata(controller);
Gao Pan53149872016-11-22 21:52:17 +0800410 struct spi_device *spi = msg->spi;
411 struct spi_transfer *xfer;
412 bool is_first_xfer = true;
Geert Uytterhoevencc4a7ff2016-12-14 12:20:55 +0100413 int ret = 0;
Gao Pan53149872016-11-22 21:52:17 +0800414
415 msg->status = 0;
416 msg->actual_length = 0;
417
418 list_for_each_entry(xfer, &msg->transfers, transfer_list) {
419 fsl_lpspi_setup_transfer(spi, xfer);
420 fsl_lpspi_set_cmd(fsl_lpspi, is_first_xfer);
421
422 is_first_xfer = false;
423
Clark Wang07d71552018-12-07 02:50:34 +0000424 ret = fsl_lpspi_transfer_one(controller, spi, xfer);
Gao Pan53149872016-11-22 21:52:17 +0800425 if (ret < 0)
426 goto complete;
427
428 msg->actual_length += xfer->len;
429 }
430
431complete:
Gao Pan53149872016-11-22 21:52:17 +0800432 msg->status = ret;
Clark Wang07d71552018-12-07 02:50:34 +0000433 spi_finalize_current_message(controller);
Gao Pan53149872016-11-22 21:52:17 +0800434
435 return ret;
436}
437
438static irqreturn_t fsl_lpspi_isr(int irq, void *dev_id)
439{
Clark Wangc23fdef2019-01-07 07:47:38 +0000440 u32 temp_SR, temp_IER;
Gao Pan53149872016-11-22 21:52:17 +0800441 struct fsl_lpspi_data *fsl_lpspi = dev_id;
Gao Pan53149872016-11-22 21:52:17 +0800442
Clark Wangc23fdef2019-01-07 07:47:38 +0000443 temp_IER = readl(fsl_lpspi->base + IMX7ULP_IER);
Gao Pan53149872016-11-22 21:52:17 +0800444 fsl_lpspi_intctrl(fsl_lpspi, 0);
Clark Wangc23fdef2019-01-07 07:47:38 +0000445 temp_SR = readl(fsl_lpspi->base + IMX7ULP_SR);
Gao Pan53149872016-11-22 21:52:17 +0800446
447 fsl_lpspi_read_rx_fifo(fsl_lpspi);
448
Clark Wangc23fdef2019-01-07 07:47:38 +0000449 if ((temp_SR & SR_TDF) && (temp_IER & IER_TDIE)) {
Gao Pan53149872016-11-22 21:52:17 +0800450 fsl_lpspi_write_tx_fifo(fsl_lpspi);
Clark Wangc23fdef2019-01-07 07:47:38 +0000451 return IRQ_HANDLED;
452 }
Gao Pan53149872016-11-22 21:52:17 +0800453
Clark Wang6a130442019-01-07 07:47:41 +0000454 if (temp_SR & SR_MBF ||
455 readl(fsl_lpspi->base + IMX7ULP_FSR) & FSR_RXCOUNT) {
456 writel(SR_FCF, fsl_lpspi->base + IMX7ULP_SR);
457 fsl_lpspi_intctrl(fsl_lpspi, IER_FCIE);
458 return IRQ_HANDLED;
459 }
460
Clark Wangc23fdef2019-01-07 07:47:38 +0000461 if (temp_SR & SR_FCF && (temp_IER & IER_FCIE)) {
462 writel(SR_FCF, fsl_lpspi->base + IMX7ULP_SR);
Gao Pan53149872016-11-22 21:52:17 +0800463 complete(&fsl_lpspi->xfer_done);
Gao Pan53149872016-11-22 21:52:17 +0800464 return IRQ_HANDLED;
465 }
466
467 return IRQ_NONE;
468}
469
470static int fsl_lpspi_probe(struct platform_device *pdev)
471{
472 struct fsl_lpspi_data *fsl_lpspi;
Clark Wang07d71552018-12-07 02:50:34 +0000473 struct spi_controller *controller;
Gao Pan53149872016-11-22 21:52:17 +0800474 struct resource *res;
475 int ret, irq;
Gao Panb88a0de2016-11-28 11:03:00 +0800476 u32 temp;
Gao Pan53149872016-11-22 21:52:17 +0800477
Clark Wangbcd87312018-12-07 02:50:36 +0000478 if (of_property_read_bool((&pdev->dev)->of_node, "spi-slave"))
479 controller = spi_alloc_slave(&pdev->dev,
Clark Wang07d71552018-12-07 02:50:34 +0000480 sizeof(struct fsl_lpspi_data));
Clark Wangbcd87312018-12-07 02:50:36 +0000481 else
482 controller = spi_alloc_master(&pdev->dev,
483 sizeof(struct fsl_lpspi_data));
484
Clark Wang07d71552018-12-07 02:50:34 +0000485 if (!controller)
Gao Pan53149872016-11-22 21:52:17 +0800486 return -ENOMEM;
487
Clark Wang07d71552018-12-07 02:50:34 +0000488 platform_set_drvdata(pdev, controller);
Gao Pan53149872016-11-22 21:52:17 +0800489
Clark Wang07d71552018-12-07 02:50:34 +0000490 controller->bits_per_word_mask = SPI_BPW_RANGE_MASK(8, 32);
491 controller->bus_num = pdev->id;
Gao Pan53149872016-11-22 21:52:17 +0800492
Clark Wang07d71552018-12-07 02:50:34 +0000493 fsl_lpspi = spi_controller_get_devdata(controller);
Gao Pan53149872016-11-22 21:52:17 +0800494 fsl_lpspi->dev = &pdev->dev;
Clark Wangbcd87312018-12-07 02:50:36 +0000495 fsl_lpspi->is_slave = of_property_read_bool((&pdev->dev)->of_node,
496 "spi-slave");
Gao Pan53149872016-11-22 21:52:17 +0800497
Clark Wang07d71552018-12-07 02:50:34 +0000498 controller->transfer_one_message = fsl_lpspi_transfer_one_msg;
499 controller->prepare_transfer_hardware = lpspi_prepare_xfer_hardware;
500 controller->unprepare_transfer_hardware = lpspi_unprepare_xfer_hardware;
501 controller->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH;
502 controller->flags = SPI_MASTER_MUST_RX | SPI_MASTER_MUST_TX;
503 controller->dev.of_node = pdev->dev.of_node;
504 controller->bus_num = pdev->id;
Clark Wangbcd87312018-12-07 02:50:36 +0000505 controller->slave_abort = fsl_lpspi_slave_abort;
Gao Pan53149872016-11-22 21:52:17 +0800506
507 init_completion(&fsl_lpspi->xfer_done);
508
509 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
510 fsl_lpspi->base = devm_ioremap_resource(&pdev->dev, res);
511 if (IS_ERR(fsl_lpspi->base)) {
512 ret = PTR_ERR(fsl_lpspi->base);
Clark Wang07d71552018-12-07 02:50:34 +0000513 goto out_controller_put;
Gao Pan53149872016-11-22 21:52:17 +0800514 }
515
516 irq = platform_get_irq(pdev, 0);
517 if (irq < 0) {
518 ret = irq;
Clark Wang07d71552018-12-07 02:50:34 +0000519 goto out_controller_put;
Gao Pan53149872016-11-22 21:52:17 +0800520 }
521
522 ret = devm_request_irq(&pdev->dev, irq, fsl_lpspi_isr, 0,
523 dev_name(&pdev->dev), fsl_lpspi);
524 if (ret) {
525 dev_err(&pdev->dev, "can't get irq%d: %d\n", irq, ret);
Clark Wang07d71552018-12-07 02:50:34 +0000526 goto out_controller_put;
Gao Pan53149872016-11-22 21:52:17 +0800527 }
528
529 fsl_lpspi->clk = devm_clk_get(&pdev->dev, "ipg");
530 if (IS_ERR(fsl_lpspi->clk)) {
531 ret = PTR_ERR(fsl_lpspi->clk);
Clark Wang07d71552018-12-07 02:50:34 +0000532 goto out_controller_put;
Gao Pan53149872016-11-22 21:52:17 +0800533 }
534
Gao Panb88a0de2016-11-28 11:03:00 +0800535 ret = clk_prepare_enable(fsl_lpspi->clk);
536 if (ret) {
537 dev_err(&pdev->dev, "can't enable lpspi clock, ret=%d\n", ret);
Clark Wang07d71552018-12-07 02:50:34 +0000538 goto out_controller_put;
Gao Panb88a0de2016-11-28 11:03:00 +0800539 }
540
541 temp = readl(fsl_lpspi->base + IMX7ULP_PARAM);
542 fsl_lpspi->txfifosize = 1 << (temp & 0x0f);
543 fsl_lpspi->rxfifosize = 1 << ((temp >> 8) & 0x0f);
544
545 clk_disable_unprepare(fsl_lpspi->clk);
546
Clark Wang07d71552018-12-07 02:50:34 +0000547 ret = devm_spi_register_controller(&pdev->dev, controller);
Gao Pan53149872016-11-22 21:52:17 +0800548 if (ret < 0) {
Clark Wang07d71552018-12-07 02:50:34 +0000549 dev_err(&pdev->dev, "spi_register_controller error.\n");
550 goto out_controller_put;
Gao Pan53149872016-11-22 21:52:17 +0800551 }
552
553 return 0;
554
Clark Wang07d71552018-12-07 02:50:34 +0000555out_controller_put:
556 spi_controller_put(controller);
Gao Pan53149872016-11-22 21:52:17 +0800557
558 return ret;
559}
560
561static int fsl_lpspi_remove(struct platform_device *pdev)
562{
Clark Wang07d71552018-12-07 02:50:34 +0000563 struct spi_controller *controller = platform_get_drvdata(pdev);
564 struct fsl_lpspi_data *fsl_lpspi =
565 spi_controller_get_devdata(controller);
Gao Pan53149872016-11-22 21:52:17 +0800566
567 clk_disable_unprepare(fsl_lpspi->clk);
568
569 return 0;
570}
571
572static struct platform_driver fsl_lpspi_driver = {
573 .driver = {
Gao Pan102ecc472017-01-04 17:38:16 +0800574 .name = DRIVER_NAME,
575 .of_match_table = fsl_lpspi_dt_ids,
576 },
Gao Pan53149872016-11-22 21:52:17 +0800577 .probe = fsl_lpspi_probe,
578 .remove = fsl_lpspi_remove,
579};
580module_platform_driver(fsl_lpspi_driver);
581
Clark Wang07d71552018-12-07 02:50:34 +0000582MODULE_DESCRIPTION("LPSPI Controller driver");
Gao Pan53149872016-11-22 21:52:17 +0800583MODULE_AUTHOR("Gao Pan <pandy.gao@nxp.com>");
Gao Panb6787b62016-12-02 11:50:00 +0800584MODULE_LICENSE("GPL");