1 // SPDX-License-Identifier: GPL-2.0-only
3 * OpenCores tiny SPI master driver
5 * http://opencores.org/project,tiny_spi
7 * Copyright (C) 2011 Thomas Chou <thomas@wytron.com.tw>
9 * Based on spi_s3c24xx.c, which is:
10 * Copyright (c) 2006 Ben Dooks
11 * Copyright (c) 2006 Simtec Electronics
12 * Ben Dooks <ben@simtec.co.uk>
15 #include <linux/interrupt.h>
16 #include <linux/errno.h>
17 #include <linux/module.h>
18 #include <linux/platform_device.h>
19 #include <linux/spi/spi.h>
20 #include <linux/spi/spi_bitbang.h>
21 #include <linux/spi/spi_oc_tiny.h>
23 #include <linux/gpio.h>
26 #define DRV_NAME "spi_oc_tiny"
28 #define TINY_SPI_RXDATA 0
29 #define TINY_SPI_TXDATA 4
30 #define TINY_SPI_STATUS 8
31 #define TINY_SPI_CONTROL 12
32 #define TINY_SPI_BAUD 16
34 #define TINY_SPI_STATUS_TXE 0x1
35 #define TINY_SPI_STATUS_TXR 0x2
38 /* bitbang has to be first */
39 struct spi_bitbang bitbang
;
40 struct completion done
;
45 unsigned int baudwidth
;
47 unsigned int speed_hz
;
50 unsigned int txc
, rxc
;
57 static inline struct tiny_spi
*tiny_spi_to_hw(struct spi_device
*sdev
)
59 return spi_master_get_devdata(sdev
->master
);
62 static unsigned int tiny_spi_baud(struct spi_device
*spi
, unsigned int hz
)
64 struct tiny_spi
*hw
= tiny_spi_to_hw(spi
);
66 return min(DIV_ROUND_UP(hw
->freq
, hz
* 2), (1U << hw
->baudwidth
)) - 1;
69 static void tiny_spi_chipselect(struct spi_device
*spi
, int is_active
)
71 struct tiny_spi
*hw
= tiny_spi_to_hw(spi
);
73 if (hw
->gpio_cs_count
> 0) {
74 gpio_set_value(hw
->gpio_cs
[spi
->chip_select
],
75 (spi
->mode
& SPI_CS_HIGH
) ? is_active
: !is_active
);
79 static int tiny_spi_setup_transfer(struct spi_device
*spi
,
80 struct spi_transfer
*t
)
82 struct tiny_spi
*hw
= tiny_spi_to_hw(spi
);
83 unsigned int baud
= hw
->baud
;
86 if (t
->speed_hz
&& t
->speed_hz
!= hw
->speed_hz
)
87 baud
= tiny_spi_baud(spi
, t
->speed_hz
);
89 writel(baud
, hw
->base
+ TINY_SPI_BAUD
);
90 writel(hw
->mode
, hw
->base
+ TINY_SPI_CONTROL
);
94 static int tiny_spi_setup(struct spi_device
*spi
)
96 struct tiny_spi
*hw
= tiny_spi_to_hw(spi
);
98 if (spi
->max_speed_hz
!= hw
->speed_hz
) {
99 hw
->speed_hz
= spi
->max_speed_hz
;
100 hw
->baud
= tiny_spi_baud(spi
, hw
->speed_hz
);
102 hw
->mode
= spi
->mode
& (SPI_CPOL
| SPI_CPHA
);
106 static inline void tiny_spi_wait_txr(struct tiny_spi
*hw
)
108 while (!(readb(hw
->base
+ TINY_SPI_STATUS
) &
109 TINY_SPI_STATUS_TXR
))
113 static inline void tiny_spi_wait_txe(struct tiny_spi
*hw
)
115 while (!(readb(hw
->base
+ TINY_SPI_STATUS
) &
116 TINY_SPI_STATUS_TXE
))
120 static int tiny_spi_txrx_bufs(struct spi_device
*spi
, struct spi_transfer
*t
)
122 struct tiny_spi
*hw
= tiny_spi_to_hw(spi
);
123 const u8
*txp
= t
->tx_buf
;
128 /* use interrupt driven data transfer */
135 /* send the first byte */
137 writeb(hw
->txp
? *hw
->txp
++ : 0,
138 hw
->base
+ TINY_SPI_TXDATA
);
140 writeb(hw
->txp
? *hw
->txp
++ : 0,
141 hw
->base
+ TINY_SPI_TXDATA
);
143 writeb(TINY_SPI_STATUS_TXR
, hw
->base
+ TINY_SPI_STATUS
);
145 writeb(hw
->txp
? *hw
->txp
++ : 0,
146 hw
->base
+ TINY_SPI_TXDATA
);
148 writeb(TINY_SPI_STATUS_TXE
, hw
->base
+ TINY_SPI_STATUS
);
151 wait_for_completion(&hw
->done
);
153 /* we need to tighten the transfer loop */
154 writeb(txp
? *txp
++ : 0, hw
->base
+ TINY_SPI_TXDATA
);
155 for (i
= 1; i
< t
->len
; i
++) {
156 writeb(txp
? *txp
++ : 0, hw
->base
+ TINY_SPI_TXDATA
);
158 if (rxp
|| (i
!= t
->len
- 1))
159 tiny_spi_wait_txr(hw
);
161 *rxp
++ = readb(hw
->base
+ TINY_SPI_TXDATA
);
163 tiny_spi_wait_txe(hw
);
165 *rxp
++ = readb(hw
->base
+ TINY_SPI_RXDATA
);
171 static irqreturn_t
tiny_spi_irq(int irq
, void *dev
)
173 struct tiny_spi
*hw
= dev
;
175 writeb(0, hw
->base
+ TINY_SPI_STATUS
);
176 if (hw
->rxc
+ 1 == hw
->len
) {
178 *hw
->rxp
++ = readb(hw
->base
+ TINY_SPI_RXDATA
);
183 *hw
->rxp
++ = readb(hw
->base
+ TINY_SPI_TXDATA
);
185 if (hw
->txc
< hw
->len
) {
186 writeb(hw
->txp
? *hw
->txp
++ : 0,
187 hw
->base
+ TINY_SPI_TXDATA
);
189 writeb(TINY_SPI_STATUS_TXR
,
190 hw
->base
+ TINY_SPI_STATUS
);
192 writeb(TINY_SPI_STATUS_TXE
,
193 hw
->base
+ TINY_SPI_STATUS
);
200 #include <linux/of_gpio.h>
202 static int tiny_spi_of_probe(struct platform_device
*pdev
)
204 struct tiny_spi
*hw
= platform_get_drvdata(pdev
);
205 struct device_node
*np
= pdev
->dev
.of_node
;
211 hw
->gpio_cs_count
= of_gpio_count(np
);
212 if (hw
->gpio_cs_count
> 0) {
213 hw
->gpio_cs
= devm_kcalloc(&pdev
->dev
,
214 hw
->gpio_cs_count
, sizeof(unsigned int),
219 for (i
= 0; i
< hw
->gpio_cs_count
; i
++) {
220 hw
->gpio_cs
[i
] = of_get_gpio_flags(np
, i
, NULL
);
221 if (hw
->gpio_cs
[i
] < 0)
224 hw
->bitbang
.master
->dev
.of_node
= pdev
->dev
.of_node
;
225 if (!of_property_read_u32(np
, "clock-frequency", &val
))
227 if (!of_property_read_u32(np
, "baud-width", &val
))
231 #else /* !CONFIG_OF */
232 static int tiny_spi_of_probe(struct platform_device
*pdev
)
236 #endif /* CONFIG_OF */
238 static int tiny_spi_probe(struct platform_device
*pdev
)
240 struct tiny_spi_platform_data
*platp
= dev_get_platdata(&pdev
->dev
);
242 struct spi_master
*master
;
243 struct resource
*res
;
247 master
= spi_alloc_master(&pdev
->dev
, sizeof(struct tiny_spi
));
251 /* setup the master state. */
252 master
->bus_num
= pdev
->id
;
253 master
->num_chipselect
= 255;
254 master
->mode_bits
= SPI_CPOL
| SPI_CPHA
| SPI_CS_HIGH
;
255 master
->setup
= tiny_spi_setup
;
257 hw
= spi_master_get_devdata(master
);
258 platform_set_drvdata(pdev
, hw
);
260 /* setup the state for the bitbang driver */
261 hw
->bitbang
.master
= master
;
262 hw
->bitbang
.setup_transfer
= tiny_spi_setup_transfer
;
263 hw
->bitbang
.chipselect
= tiny_spi_chipselect
;
264 hw
->bitbang
.txrx_bufs
= tiny_spi_txrx_bufs
;
266 /* find and map our resources */
267 res
= platform_get_resource(pdev
, IORESOURCE_MEM
, 0);
268 hw
->base
= devm_ioremap_resource(&pdev
->dev
, res
);
269 if (IS_ERR(hw
->base
)) {
270 err
= PTR_ERR(hw
->base
);
273 /* irq is optional */
274 hw
->irq
= platform_get_irq(pdev
, 0);
276 init_completion(&hw
->done
);
277 err
= devm_request_irq(&pdev
->dev
, hw
->irq
, tiny_spi_irq
, 0,
282 /* find platform data */
284 hw
->gpio_cs_count
= platp
->gpio_cs_count
;
285 hw
->gpio_cs
= platp
->gpio_cs
;
286 if (platp
->gpio_cs_count
&& !platp
->gpio_cs
) {
290 hw
->freq
= platp
->freq
;
291 hw
->baudwidth
= platp
->baudwidth
;
293 err
= tiny_spi_of_probe(pdev
);
297 for (i
= 0; i
< hw
->gpio_cs_count
; i
++) {
298 err
= gpio_request(hw
->gpio_cs
[i
], dev_name(&pdev
->dev
));
301 gpio_direction_output(hw
->gpio_cs
[i
], 1);
303 hw
->bitbang
.master
->num_chipselect
= max(1, hw
->gpio_cs_count
);
305 /* register our spi controller */
306 err
= spi_bitbang_start(&hw
->bitbang
);
309 dev_info(&pdev
->dev
, "base %p, irq %d\n", hw
->base
, hw
->irq
);
315 gpio_free(hw
->gpio_cs
[i
]);
317 spi_master_put(master
);
321 static int tiny_spi_remove(struct platform_device
*pdev
)
323 struct tiny_spi
*hw
= platform_get_drvdata(pdev
);
324 struct spi_master
*master
= hw
->bitbang
.master
;
327 spi_bitbang_stop(&hw
->bitbang
);
328 for (i
= 0; i
< hw
->gpio_cs_count
; i
++)
329 gpio_free(hw
->gpio_cs
[i
]);
330 spi_master_put(master
);
335 static const struct of_device_id tiny_spi_match
[] = {
336 { .compatible
= "opencores,tiny-spi-rtlsvn2", },
339 MODULE_DEVICE_TABLE(of
, tiny_spi_match
);
340 #endif /* CONFIG_OF */
342 static struct platform_driver tiny_spi_driver
= {
343 .probe
= tiny_spi_probe
,
344 .remove
= tiny_spi_remove
,
348 .of_match_table
= of_match_ptr(tiny_spi_match
),
351 module_platform_driver(tiny_spi_driver
);
353 MODULE_DESCRIPTION("OpenCores tiny SPI driver");
354 MODULE_AUTHOR("Thomas Chou <thomas@wytron.com.tw>");
355 MODULE_LICENSE("GPL");
356 MODULE_ALIAS("platform:" DRV_NAME
);