summaryrefslogtreecommitdiffstats
path: root/drivers/spi
diff options
context:
space:
mode:
authorKeiji Hayashibara <hayashibara.keiji@socionext.com>2018-08-01 03:29:12 -0400
committerMark Brown <broonie@kernel.org>2018-08-01 06:22:37 -0400
commit5ba155a4d4cc8e4cdd3db6df7d03271a3bd91177 (patch)
tree2305f0f12b7291379855241df751a2f463b0194b /drivers/spi
parent4dcd5c2781f3c5c7851800649047658956d590af (diff)
spi: add SPI controller driver for UniPhier SoC
Add SPI controller driver implemented in Socionext UniPhier SoCs. UniPhier SoCs have two types SPI controllers; SCSSI supports a single channel, and MCSSI supports multiple channels. This driver supports SCSSI only. This controller has 32bit TX/RX FIFO with depth of eight entry, and supports the SPI master mode only. This commit is implemented in PIO transfer mode, not DMA transfer. Signed-off-by: Kunihiko Hayashi <hayashi.kunihiko@socionext.com> Signed-off-by: Keiji Hayashibara <hayashibara.keiji@socionext.com> Reviewed-by: Andy Shevchenko <andy.shevchenko@gmail.com> Signed-off-by: Mark Brown <broonie@kernel.org>
Diffstat (limited to 'drivers/spi')
-rw-r--r--drivers/spi/Kconfig13
-rw-r--r--drivers/spi/Makefile1
-rw-r--r--drivers/spi/spi-uniphier.c525
3 files changed, 539 insertions, 0 deletions
diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
index ad5d68e1dab7..671d078349cc 100644
--- a/drivers/spi/Kconfig
+++ b/drivers/spi/Kconfig
@@ -688,6 +688,19 @@ config SPI_TXX9
688 help 688 help
689 SPI driver for Toshiba TXx9 MIPS SoCs 689 SPI driver for Toshiba TXx9 MIPS SoCs
690 690
691config SPI_UNIPHIER
692 tristate "Socionext UniPhier SPI Controller"
693 depends on (ARCH_UNIPHIER || COMPILE_TEST) && OF
694 help
695 This enables a driver for the Socionext UniPhier SoC SCSSI SPI controller.
696
697 UniPhier SoCs have SCSSI and MCSSI SPI controllers.
698 Every UniPhier SoC has SCSSI which supports single channel.
699 Older UniPhier Pro4/Pro5 also has MCSSI which support multiple channels.
700 This driver supports SCSSI only.
701
702 If your SoC supports SCSSI, say Y here.
703
691config SPI_XCOMM 704config SPI_XCOMM
692 tristate "Analog Devices AD-FMCOMMS1-EBZ SPI-I2C-bridge driver" 705 tristate "Analog Devices AD-FMCOMMS1-EBZ SPI-I2C-bridge driver"
693 depends on I2C 706 depends on I2C
diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile
index cb1f4378b87c..a90d55970036 100644
--- a/drivers/spi/Makefile
+++ b/drivers/spi/Makefile
@@ -101,6 +101,7 @@ spi-thunderx-objs := spi-cavium.o spi-cavium-thunderx.o
101obj-$(CONFIG_SPI_THUNDERX) += spi-thunderx.o 101obj-$(CONFIG_SPI_THUNDERX) += spi-thunderx.o
102obj-$(CONFIG_SPI_TOPCLIFF_PCH) += spi-topcliff-pch.o 102obj-$(CONFIG_SPI_TOPCLIFF_PCH) += spi-topcliff-pch.o
103obj-$(CONFIG_SPI_TXX9) += spi-txx9.o 103obj-$(CONFIG_SPI_TXX9) += spi-txx9.o
104obj-$(CONFIG_SPI_UNIPHIER) += spi-uniphier.o
104obj-$(CONFIG_SPI_XCOMM) += spi-xcomm.o 105obj-$(CONFIG_SPI_XCOMM) += spi-xcomm.o
105obj-$(CONFIG_SPI_XILINX) += spi-xilinx.o 106obj-$(CONFIG_SPI_XILINX) += spi-xilinx.o
106obj-$(CONFIG_SPI_XLP) += spi-xlp.o 107obj-$(CONFIG_SPI_XLP) += spi-xlp.o
diff --git a/drivers/spi/spi-uniphier.c b/drivers/spi/spi-uniphier.c
new file mode 100644
index 000000000000..089985465890
--- /dev/null
+++ b/drivers/spi/spi-uniphier.c
@@ -0,0 +1,525 @@
1// SPDX-License-Identifier: GPL-2.0
2// spi-uniphier.c - Socionext UniPhier SPI controller driver
3// Copyright 2012 Panasonic Corporation
4// Copyright 2016-2018 Socionext Inc.
5
6#include <linux/kernel.h>
7#include <linux/bitfield.h>
8#include <linux/bitops.h>
9#include <linux/clk.h>
10#include <linux/interrupt.h>
11#include <linux/io.h>
12#include <linux/module.h>
13#include <linux/of.h>
14#include <linux/of_platform.h>
15#include <linux/platform_device.h>
16#include <linux/spi/spi.h>
17
18#include <asm/unaligned.h>
19
20#define SSI_TIMEOUT_MS 2000
21#define SSI_MAX_CLK_DIVIDER 254
22#define SSI_MIN_CLK_DIVIDER 4
23
24struct uniphier_spi_priv {
25 void __iomem *base;
26 struct clk *clk;
27 struct spi_master *master;
28 struct completion xfer_done;
29
30 int error;
31 unsigned int tx_bytes;
32 unsigned int rx_bytes;
33 const u8 *tx_buf;
34 u8 *rx_buf;
35
36 bool is_save_param;
37 u8 bits_per_word;
38 u16 mode;
39 u32 speed_hz;
40};
41
42#define SSI_CTL 0x00
43#define SSI_CTL_EN BIT(0)
44
45#define SSI_CKS 0x04
46#define SSI_CKS_CKRAT_MASK GENMASK(7, 0)
47#define SSI_CKS_CKPHS BIT(14)
48#define SSI_CKS_CKINIT BIT(13)
49#define SSI_CKS_CKDLY BIT(12)
50
51#define SSI_TXWDS 0x08
52#define SSI_TXWDS_WDLEN_MASK GENMASK(13, 8)
53#define SSI_TXWDS_TDTF_MASK GENMASK(7, 6)
54#define SSI_TXWDS_DTLEN_MASK GENMASK(5, 0)
55
56#define SSI_RXWDS 0x0c
57#define SSI_RXWDS_DTLEN_MASK GENMASK(5, 0)
58
59#define SSI_FPS 0x10
60#define SSI_FPS_FSPOL BIT(15)
61#define SSI_FPS_FSTRT BIT(14)
62
63#define SSI_SR 0x14
64#define SSI_SR_RNE BIT(0)
65
66#define SSI_IE 0x18
67#define SSI_IE_RCIE BIT(3)
68#define SSI_IE_RORIE BIT(0)
69
70#define SSI_IS 0x1c
71#define SSI_IS_RXRS BIT(9)
72#define SSI_IS_RCID BIT(3)
73#define SSI_IS_RORID BIT(0)
74
75#define SSI_IC 0x1c
76#define SSI_IC_TCIC BIT(4)
77#define SSI_IC_RCIC BIT(3)
78#define SSI_IC_RORIC BIT(0)
79
80#define SSI_FC 0x20
81#define SSI_FC_TXFFL BIT(12)
82#define SSI_FC_TXFTH_MASK GENMASK(11, 8)
83#define SSI_FC_RXFFL BIT(4)
84#define SSI_FC_RXFTH_MASK GENMASK(3, 0)
85
86#define SSI_TXDR 0x24
87#define SSI_RXDR 0x24
88
89#define SSI_FIFO_DEPTH 8U
90
91static inline unsigned int bytes_per_word(unsigned int bits)
92{
93 return bits <= 8 ? 1 : (bits <= 16 ? 2 : 4);
94}
95
96static inline void uniphier_spi_irq_enable(struct spi_device *spi, u32 mask)
97{
98 struct uniphier_spi_priv *priv = spi_master_get_devdata(spi->master);
99 u32 val;
100
101 val = readl(priv->base + SSI_IE);
102 val |= mask;
103 writel(val, priv->base + SSI_IE);
104}
105
106static inline void uniphier_spi_irq_disable(struct spi_device *spi, u32 mask)
107{
108 struct uniphier_spi_priv *priv = spi_master_get_devdata(spi->master);
109 u32 val;
110
111 val = readl(priv->base + SSI_IE);
112 val &= ~mask;
113 writel(val, priv->base + SSI_IE);
114}
115
116static void uniphier_spi_set_mode(struct spi_device *spi)
117{
118 struct uniphier_spi_priv *priv = spi_master_get_devdata(spi->master);
119 u32 val1, val2;
120
121 /*
122 * clock setting
123 * CKPHS capture timing. 0:rising edge, 1:falling edge
124 * CKINIT clock initial level. 0:low, 1:high
125 * CKDLY clock delay. 0:no delay, 1:delay depending on FSTRT
126 * (FSTRT=0: 1 clock, FSTRT=1: 0.5 clock)
127 *
128 * frame setting
129 * FSPOL frame signal porarity. 0: low, 1: high
130 * FSTRT start frame timing
131 * 0: rising edge of clock, 1: falling edge of clock
132 */
133 switch (spi->mode & (SPI_CPOL | SPI_CPHA)) {
134 case SPI_MODE_0:
135 /* CKPHS=1, CKINIT=0, CKDLY=1, FSTRT=0 */
136 val1 = SSI_CKS_CKPHS | SSI_CKS_CKDLY;
137 val2 = 0;
138 break;
139 case SPI_MODE_1:
140 /* CKPHS=0, CKINIT=0, CKDLY=0, FSTRT=1 */
141 val1 = 0;
142 val2 = SSI_FPS_FSTRT;
143 break;
144 case SPI_MODE_2:
145 /* CKPHS=0, CKINIT=1, CKDLY=1, FSTRT=1 */
146 val1 = SSI_CKS_CKINIT | SSI_CKS_CKDLY;
147 val2 = SSI_FPS_FSTRT;
148 break;
149 case SPI_MODE_3:
150 /* CKPHS=1, CKINIT=1, CKDLY=0, FSTRT=0 */
151 val1 = SSI_CKS_CKPHS | SSI_CKS_CKINIT;
152 val2 = 0;
153 break;
154 }
155
156 if (!(spi->mode & SPI_CS_HIGH))
157 val2 |= SSI_FPS_FSPOL;
158
159 writel(val1, priv->base + SSI_CKS);
160 writel(val2, priv->base + SSI_FPS);
161
162 val1 = 0;
163 if (spi->mode & SPI_LSB_FIRST)
164 val1 |= FIELD_PREP(SSI_TXWDS_TDTF_MASK, 1);
165 writel(val1, priv->base + SSI_TXWDS);
166 writel(val1, priv->base + SSI_RXWDS);
167}
168
169static void uniphier_spi_set_transfer_size(struct spi_device *spi, int size)
170{
171 struct uniphier_spi_priv *priv = spi_master_get_devdata(spi->master);
172 u32 val;
173
174 val = readl(priv->base + SSI_TXWDS);
175 val &= ~(SSI_TXWDS_WDLEN_MASK | SSI_TXWDS_DTLEN_MASK);
176 val |= FIELD_PREP(SSI_TXWDS_WDLEN_MASK, size);
177 val |= FIELD_PREP(SSI_TXWDS_DTLEN_MASK, size);
178 writel(val, priv->base + SSI_TXWDS);
179
180 val = readl(priv->base + SSI_RXWDS);
181 val &= ~SSI_RXWDS_DTLEN_MASK;
182 val |= FIELD_PREP(SSI_RXWDS_DTLEN_MASK, size);
183 writel(val, priv->base + SSI_RXWDS);
184}
185
186static void uniphier_spi_set_baudrate(struct spi_device *spi,
187 unsigned int speed)
188{
189 struct uniphier_spi_priv *priv = spi_master_get_devdata(spi->master);
190 u32 val, ckdiv;
191
192 /*
193 * the supported rates are even numbers from 4 to 254. (4,6,8...254)
194 * round up as we look for equal or less speed
195 */
196 ckdiv = DIV_ROUND_UP(clk_get_rate(priv->clk), speed);
197 ckdiv = round_up(ckdiv, 2);
198
199 val = readl(priv->base + SSI_CKS);
200 val &= ~SSI_CKS_CKRAT_MASK;
201 val |= ckdiv & SSI_CKS_CKRAT_MASK;
202 writel(val, priv->base + SSI_CKS);
203}
204
205static void uniphier_spi_setup_transfer(struct spi_device *spi,
206 struct spi_transfer *t)
207{
208 struct uniphier_spi_priv *priv = spi_master_get_devdata(spi->master);
209 u32 val;
210
211 priv->error = 0;
212 priv->tx_buf = t->tx_buf;
213 priv->rx_buf = t->rx_buf;
214 priv->tx_bytes = priv->rx_bytes = t->len;
215
216 if (!priv->is_save_param || priv->mode != spi->mode) {
217 uniphier_spi_set_mode(spi);
218 priv->mode = spi->mode;
219 }
220
221 if (!priv->is_save_param || priv->bits_per_word != t->bits_per_word) {
222 uniphier_spi_set_transfer_size(spi, t->bits_per_word);
223 priv->bits_per_word = t->bits_per_word;
224 }
225
226 if (!priv->is_save_param || priv->speed_hz != t->speed_hz) {
227 uniphier_spi_set_baudrate(spi, t->speed_hz);
228 priv->speed_hz = t->speed_hz;
229 }
230
231 if (!priv->is_save_param)
232 priv->is_save_param = true;
233
234 /* reset FIFOs */
235 val = SSI_FC_TXFFL | SSI_FC_RXFFL;
236 writel(val, priv->base + SSI_FC);
237}
238
239static void uniphier_spi_send(struct uniphier_spi_priv *priv)
240{
241 int wsize;
242 u32 val = 0;
243
244 wsize = min(bytes_per_word(priv->bits_per_word), priv->tx_bytes);
245 priv->tx_bytes -= wsize;
246
247 if (priv->tx_buf) {
248 switch (wsize) {
249 case 1:
250 val = *priv->tx_buf;
251 break;
252 case 2:
253 val = get_unaligned_le16(priv->tx_buf);
254 break;
255 case 4:
256 val = get_unaligned_le32(priv->tx_buf);
257 break;
258 }
259
260 priv->tx_buf += wsize;
261 }
262
263 writel(val, priv->base + SSI_TXDR);
264}
265
266static void uniphier_spi_recv(struct uniphier_spi_priv *priv)
267{
268 int rsize;
269 u32 val;
270
271 rsize = min(bytes_per_word(priv->bits_per_word), priv->rx_bytes);
272 priv->rx_bytes -= rsize;
273
274 val = readl(priv->base + SSI_RXDR);
275
276 if (priv->rx_buf) {
277 switch (rsize) {
278 case 1:
279 *priv->rx_buf = val;
280 break;
281 case 2:
282 put_unaligned_le16(val, priv->rx_buf);
283 break;
284 case 4:
285 put_unaligned_le32(val, priv->rx_buf);
286 break;
287 }
288
289 priv->rx_buf += rsize;
290 }
291}
292
293static void uniphier_spi_fill_tx_fifo(struct uniphier_spi_priv *priv)
294{
295 unsigned int tx_count;
296 u32 val;
297
298 tx_count = DIV_ROUND_UP(priv->tx_bytes,
299 bytes_per_word(priv->bits_per_word));
300 tx_count = min(tx_count, SSI_FIFO_DEPTH);
301
302 /* set fifo threshold */
303 val = readl(priv->base + SSI_FC);
304 val &= ~(SSI_FC_TXFTH_MASK | SSI_FC_RXFTH_MASK);
305 val |= FIELD_PREP(SSI_FC_TXFTH_MASK, tx_count);
306 val |= FIELD_PREP(SSI_FC_RXFTH_MASK, tx_count);
307 writel(val, priv->base + SSI_FC);
308
309 while (tx_count--)
310 uniphier_spi_send(priv);
311}
312
313static void uniphier_spi_set_cs(struct spi_device *spi, bool enable)
314{
315 struct uniphier_spi_priv *priv = spi_master_get_devdata(spi->master);
316 u32 val;
317
318 val = readl(priv->base + SSI_FPS);
319
320 if (enable)
321 val |= SSI_FPS_FSPOL;
322 else
323 val &= ~SSI_FPS_FSPOL;
324
325 writel(val, priv->base + SSI_FPS);
326}
327
328static int uniphier_spi_transfer_one(struct spi_master *master,
329 struct spi_device *spi,
330 struct spi_transfer *t)
331{
332 struct uniphier_spi_priv *priv = spi_master_get_devdata(master);
333 int status;
334
335 uniphier_spi_setup_transfer(spi, t);
336
337 reinit_completion(&priv->xfer_done);
338
339 uniphier_spi_fill_tx_fifo(priv);
340
341 uniphier_spi_irq_enable(spi, SSI_IE_RCIE | SSI_IE_RORIE);
342
343 status = wait_for_completion_timeout(&priv->xfer_done,
344 msecs_to_jiffies(SSI_TIMEOUT_MS));
345
346 uniphier_spi_irq_disable(spi, SSI_IE_RCIE | SSI_IE_RORIE);
347
348 if (status < 0)
349 return status;
350
351 return priv->error;
352}
353
354static int uniphier_spi_prepare_transfer_hardware(struct spi_master *master)
355{
356 struct uniphier_spi_priv *priv = spi_master_get_devdata(master);
357
358 writel(SSI_CTL_EN, priv->base + SSI_CTL);
359
360 return 0;
361}
362
363static int uniphier_spi_unprepare_transfer_hardware(struct spi_master *master)
364{
365 struct uniphier_spi_priv *priv = spi_master_get_devdata(master);
366
367 writel(0, priv->base + SSI_CTL);
368
369 return 0;
370}
371
372static irqreturn_t uniphier_spi_handler(int irq, void *dev_id)
373{
374 struct uniphier_spi_priv *priv = dev_id;
375 u32 val, stat;
376
377 stat = readl(priv->base + SSI_IS);
378 val = SSI_IC_TCIC | SSI_IC_RCIC | SSI_IC_RORIC;
379 writel(val, priv->base + SSI_IC);
380
381 /* rx fifo overrun */
382 if (stat & SSI_IS_RORID) {
383 priv->error = -EIO;
384 goto done;
385 }
386
387 /* rx complete */
388 if ((stat & SSI_IS_RCID) && (stat & SSI_IS_RXRS)) {
389 while ((readl(priv->base + SSI_SR) & SSI_SR_RNE) &&
390 (priv->rx_bytes - priv->tx_bytes) > 0)
391 uniphier_spi_recv(priv);
392
393 if ((readl(priv->base + SSI_SR) & SSI_SR_RNE) ||
394 (priv->rx_bytes != priv->tx_bytes)) {
395 priv->error = -EIO;
396 goto done;
397 } else if (priv->rx_bytes == 0)
398 goto done;
399
400 /* next tx transfer */
401 uniphier_spi_fill_tx_fifo(priv);
402
403 return IRQ_HANDLED;
404 }
405
406 return IRQ_NONE;
407
408done:
409 complete(&priv->xfer_done);
410 return IRQ_HANDLED;
411}
412
413static int uniphier_spi_probe(struct platform_device *pdev)
414{
415 struct uniphier_spi_priv *priv;
416 struct spi_master *master;
417 struct resource *res;
418 unsigned long clk_rate;
419 int irq;
420 int ret;
421
422 master = spi_alloc_master(&pdev->dev, sizeof(*priv));
423 if (!master)
424 return -ENOMEM;
425
426 platform_set_drvdata(pdev, master);
427
428 priv = spi_master_get_devdata(master);
429 priv->master = master;
430 priv->is_save_param = false;
431
432 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
433 priv->base = devm_ioremap_resource(&pdev->dev, res);
434 if (IS_ERR(priv->base)) {
435 ret = PTR_ERR(priv->base);
436 goto out_master_put;
437 }
438
439 priv->clk = devm_clk_get(&pdev->dev, NULL);
440 if (IS_ERR(priv->clk)) {
441 dev_err(&pdev->dev, "failed to get clock\n");
442 ret = PTR_ERR(priv->clk);
443 goto out_master_put;
444 }
445
446 ret = clk_prepare_enable(priv->clk);
447 if (ret)
448 goto out_master_put;
449
450 irq = platform_get_irq(pdev, 0);
451 if (irq < 0) {
452 dev_err(&pdev->dev, "failed to get IRQ\n");
453 ret = irq;
454 goto out_disable_clk;
455 }
456
457 ret = devm_request_irq(&pdev->dev, irq, uniphier_spi_handler,
458 0, "uniphier-spi", priv);
459 if (ret) {
460 dev_err(&pdev->dev, "failed to request IRQ\n");
461 goto out_disable_clk;
462 }
463
464 init_completion(&priv->xfer_done);
465
466 clk_rate = clk_get_rate(priv->clk);
467
468 master->max_speed_hz = DIV_ROUND_UP(clk_rate, SSI_MIN_CLK_DIVIDER);
469 master->min_speed_hz = DIV_ROUND_UP(clk_rate, SSI_MAX_CLK_DIVIDER);
470 master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH | SPI_LSB_FIRST;
471 master->dev.of_node = pdev->dev.of_node;
472 master->bus_num = pdev->id;
473 master->bits_per_word_mask = SPI_BPW_RANGE_MASK(1, 32);
474
475 master->set_cs = uniphier_spi_set_cs;
476 master->transfer_one = uniphier_spi_transfer_one;
477 master->prepare_transfer_hardware
478 = uniphier_spi_prepare_transfer_hardware;
479 master->unprepare_transfer_hardware
480 = uniphier_spi_unprepare_transfer_hardware;
481 master->num_chipselect = 1;
482
483 ret = devm_spi_register_master(&pdev->dev, master);
484 if (ret)
485 goto out_disable_clk;
486
487 return 0;
488
489out_disable_clk:
490 clk_disable_unprepare(priv->clk);
491
492out_master_put:
493 spi_master_put(master);
494 return ret;
495}
496
497static int uniphier_spi_remove(struct platform_device *pdev)
498{
499 struct uniphier_spi_priv *priv = platform_get_drvdata(pdev);
500
501 clk_disable_unprepare(priv->clk);
502
503 return 0;
504}
505
506static const struct of_device_id uniphier_spi_match[] = {
507 { .compatible = "socionext,uniphier-scssi" },
508 { /* sentinel */ }
509};
510MODULE_DEVICE_TABLE(of, uniphier_spi_match);
511
512static struct platform_driver uniphier_spi_driver = {
513 .probe = uniphier_spi_probe,
514 .remove = uniphier_spi_remove,
515 .driver = {
516 .name = "uniphier-spi",
517 .of_match_table = uniphier_spi_match,
518 },
519};
520module_platform_driver(uniphier_spi_driver);
521
522MODULE_AUTHOR("Kunihiko Hayashi <hayashi.kunihiko@socionext.com>");
523MODULE_AUTHOR("Keiji Hayashibara <hayashibara.keiji@socionext.com>");
524MODULE_DESCRIPTION("Socionext UniPhier SPI controller driver");
525MODULE_LICENSE("GPL v2");