xref: /openbmc/linux/drivers/spi/spi-oc-tiny.c (revision 9b9c2cd4)
1 /*
2  * OpenCores tiny SPI master driver
3  *
4  * http://opencores.org/project,tiny_spi
5  *
6  * Copyright (C) 2011 Thomas Chou <thomas@wytron.com.tw>
7  *
8  * Based on spi_s3c24xx.c, which is:
9  * Copyright (c) 2006 Ben Dooks
10  * Copyright (c) 2006 Simtec Electronics
11  *	Ben Dooks <ben@simtec.co.uk>
12  *
13  * This program is free software; you can redistribute it and/or modify
14  * it under the terms of the GNU General Public License version 2 as
15  * published by the Free Software Foundation.
16  */
17 
18 #include <linux/interrupt.h>
19 #include <linux/errno.h>
20 #include <linux/module.h>
21 #include <linux/platform_device.h>
22 #include <linux/spi/spi.h>
23 #include <linux/spi/spi_bitbang.h>
24 #include <linux/spi/spi_oc_tiny.h>
25 #include <linux/io.h>
26 #include <linux/gpio.h>
27 #include <linux/of.h>
28 
29 #define DRV_NAME "spi_oc_tiny"
30 
31 #define TINY_SPI_RXDATA 0
32 #define TINY_SPI_TXDATA 4
33 #define TINY_SPI_STATUS 8
34 #define TINY_SPI_CONTROL 12
35 #define TINY_SPI_BAUD 16
36 
37 #define TINY_SPI_STATUS_TXE 0x1
38 #define TINY_SPI_STATUS_TXR 0x2
39 
40 struct tiny_spi {
41 	/* bitbang has to be first */
42 	struct spi_bitbang bitbang;
43 	struct completion done;
44 
45 	void __iomem *base;
46 	int irq;
47 	unsigned int freq;
48 	unsigned int baudwidth;
49 	unsigned int baud;
50 	unsigned int speed_hz;
51 	unsigned int mode;
52 	unsigned int len;
53 	unsigned int txc, rxc;
54 	const u8 *txp;
55 	u8 *rxp;
56 	int gpio_cs_count;
57 	int *gpio_cs;
58 };
59 
60 static inline struct tiny_spi *tiny_spi_to_hw(struct spi_device *sdev)
61 {
62 	return spi_master_get_devdata(sdev->master);
63 }
64 
65 static unsigned int tiny_spi_baud(struct spi_device *spi, unsigned int hz)
66 {
67 	struct tiny_spi *hw = tiny_spi_to_hw(spi);
68 
69 	return min(DIV_ROUND_UP(hw->freq, hz * 2), (1U << hw->baudwidth)) - 1;
70 }
71 
72 static void tiny_spi_chipselect(struct spi_device *spi, int is_active)
73 {
74 	struct tiny_spi *hw = tiny_spi_to_hw(spi);
75 
76 	if (hw->gpio_cs_count > 0) {
77 		gpio_set_value(hw->gpio_cs[spi->chip_select],
78 			(spi->mode & SPI_CS_HIGH) ? is_active : !is_active);
79 	}
80 }
81 
82 static int tiny_spi_setup_transfer(struct spi_device *spi,
83 				   struct spi_transfer *t)
84 {
85 	struct tiny_spi *hw = tiny_spi_to_hw(spi);
86 	unsigned int baud = hw->baud;
87 
88 	if (t) {
89 		if (t->speed_hz && t->speed_hz != hw->speed_hz)
90 			baud = tiny_spi_baud(spi, t->speed_hz);
91 	}
92 	writel(baud, hw->base + TINY_SPI_BAUD);
93 	writel(hw->mode, hw->base + TINY_SPI_CONTROL);
94 	return 0;
95 }
96 
97 static int tiny_spi_setup(struct spi_device *spi)
98 {
99 	struct tiny_spi *hw = tiny_spi_to_hw(spi);
100 
101 	if (spi->max_speed_hz != hw->speed_hz) {
102 		hw->speed_hz = spi->max_speed_hz;
103 		hw->baud = tiny_spi_baud(spi, hw->speed_hz);
104 	}
105 	hw->mode = spi->mode & (SPI_CPOL | SPI_CPHA);
106 	return 0;
107 }
108 
109 static inline void tiny_spi_wait_txr(struct tiny_spi *hw)
110 {
111 	while (!(readb(hw->base + TINY_SPI_STATUS) &
112 		 TINY_SPI_STATUS_TXR))
113 		cpu_relax();
114 }
115 
116 static inline void tiny_spi_wait_txe(struct tiny_spi *hw)
117 {
118 	while (!(readb(hw->base + TINY_SPI_STATUS) &
119 		 TINY_SPI_STATUS_TXE))
120 		cpu_relax();
121 }
122 
123 static int tiny_spi_txrx_bufs(struct spi_device *spi, struct spi_transfer *t)
124 {
125 	struct tiny_spi *hw = tiny_spi_to_hw(spi);
126 	const u8 *txp = t->tx_buf;
127 	u8 *rxp = t->rx_buf;
128 	unsigned int i;
129 
130 	if (hw->irq >= 0) {
131 		/* use interrupt driven data transfer */
132 		hw->len = t->len;
133 		hw->txp = t->tx_buf;
134 		hw->rxp = t->rx_buf;
135 		hw->txc = 0;
136 		hw->rxc = 0;
137 
138 		/* send the first byte */
139 		if (t->len > 1) {
140 			writeb(hw->txp ? *hw->txp++ : 0,
141 			       hw->base + TINY_SPI_TXDATA);
142 			hw->txc++;
143 			writeb(hw->txp ? *hw->txp++ : 0,
144 			       hw->base + TINY_SPI_TXDATA);
145 			hw->txc++;
146 			writeb(TINY_SPI_STATUS_TXR, hw->base + TINY_SPI_STATUS);
147 		} else {
148 			writeb(hw->txp ? *hw->txp++ : 0,
149 			       hw->base + TINY_SPI_TXDATA);
150 			hw->txc++;
151 			writeb(TINY_SPI_STATUS_TXE, hw->base + TINY_SPI_STATUS);
152 		}
153 
154 		wait_for_completion(&hw->done);
155 	} else {
156 		/* we need to tighten the transfer loop */
157 		writeb(txp ? *txp++ : 0, hw->base + TINY_SPI_TXDATA);
158 		for (i = 1; i < t->len; i++) {
159 			writeb(txp ? *txp++ : 0, hw->base + TINY_SPI_TXDATA);
160 
161 			if (rxp || (i != t->len - 1))
162 				tiny_spi_wait_txr(hw);
163 			if (rxp)
164 				*rxp++ = readb(hw->base + TINY_SPI_TXDATA);
165 		}
166 		tiny_spi_wait_txe(hw);
167 		if (rxp)
168 			*rxp++ = readb(hw->base + TINY_SPI_RXDATA);
169 	}
170 
171 	return t->len;
172 }
173 
174 static irqreturn_t tiny_spi_irq(int irq, void *dev)
175 {
176 	struct tiny_spi *hw = dev;
177 
178 	writeb(0, hw->base + TINY_SPI_STATUS);
179 	if (hw->rxc + 1 == hw->len) {
180 		if (hw->rxp)
181 			*hw->rxp++ = readb(hw->base + TINY_SPI_RXDATA);
182 		hw->rxc++;
183 		complete(&hw->done);
184 	} else {
185 		if (hw->rxp)
186 			*hw->rxp++ = readb(hw->base + TINY_SPI_TXDATA);
187 		hw->rxc++;
188 		if (hw->txc < hw->len) {
189 			writeb(hw->txp ? *hw->txp++ : 0,
190 			       hw->base + TINY_SPI_TXDATA);
191 			hw->txc++;
192 			writeb(TINY_SPI_STATUS_TXR,
193 			       hw->base + TINY_SPI_STATUS);
194 		} else {
195 			writeb(TINY_SPI_STATUS_TXE,
196 			       hw->base + TINY_SPI_STATUS);
197 		}
198 	}
199 	return IRQ_HANDLED;
200 }
201 
202 #ifdef CONFIG_OF
203 #include <linux/of_gpio.h>
204 
205 static int tiny_spi_of_probe(struct platform_device *pdev)
206 {
207 	struct tiny_spi *hw = platform_get_drvdata(pdev);
208 	struct device_node *np = pdev->dev.of_node;
209 	unsigned int i;
210 	u32 val;
211 
212 	if (!np)
213 		return 0;
214 	hw->gpio_cs_count = of_gpio_count(np);
215 	if (hw->gpio_cs_count > 0) {
216 		hw->gpio_cs = devm_kzalloc(&pdev->dev,
217 				hw->gpio_cs_count * sizeof(unsigned int),
218 				GFP_KERNEL);
219 		if (!hw->gpio_cs)
220 			return -ENOMEM;
221 	}
222 	for (i = 0; i < hw->gpio_cs_count; i++) {
223 		hw->gpio_cs[i] = of_get_gpio_flags(np, i, NULL);
224 		if (hw->gpio_cs[i] < 0)
225 			return -ENODEV;
226 	}
227 	hw->bitbang.master->dev.of_node = pdev->dev.of_node;
228 	if (!of_property_read_u32(np, "clock-frequency", &val))
229 		hw->freq = val;
230 	if (!of_property_read_u32(np, "baud-width", &val))
231 		hw->baudwidth = val;
232 	return 0;
233 }
234 #else /* !CONFIG_OF */
235 static int tiny_spi_of_probe(struct platform_device *pdev)
236 {
237 	return 0;
238 }
239 #endif /* CONFIG_OF */
240 
241 static int tiny_spi_probe(struct platform_device *pdev)
242 {
243 	struct tiny_spi_platform_data *platp = dev_get_platdata(&pdev->dev);
244 	struct tiny_spi *hw;
245 	struct spi_master *master;
246 	struct resource *res;
247 	unsigned int i;
248 	int err = -ENODEV;
249 
250 	master = spi_alloc_master(&pdev->dev, sizeof(struct tiny_spi));
251 	if (!master)
252 		return err;
253 
254 	/* setup the master state. */
255 	master->bus_num = pdev->id;
256 	master->num_chipselect = 255;
257 	master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH;
258 	master->setup = tiny_spi_setup;
259 
260 	hw = spi_master_get_devdata(master);
261 	platform_set_drvdata(pdev, hw);
262 
263 	/* setup the state for the bitbang driver */
264 	hw->bitbang.master = master;
265 	hw->bitbang.setup_transfer = tiny_spi_setup_transfer;
266 	hw->bitbang.chipselect = tiny_spi_chipselect;
267 	hw->bitbang.txrx_bufs = tiny_spi_txrx_bufs;
268 
269 	/* find and map our resources */
270 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
271 	hw->base = devm_ioremap_resource(&pdev->dev, res);
272 	if (IS_ERR(hw->base)) {
273 		err = PTR_ERR(hw->base);
274 		goto exit;
275 	}
276 	/* irq is optional */
277 	hw->irq = platform_get_irq(pdev, 0);
278 	if (hw->irq >= 0) {
279 		init_completion(&hw->done);
280 		err = devm_request_irq(&pdev->dev, hw->irq, tiny_spi_irq, 0,
281 				       pdev->name, hw);
282 		if (err)
283 			goto exit;
284 	}
285 	/* find platform data */
286 	if (platp) {
287 		hw->gpio_cs_count = platp->gpio_cs_count;
288 		hw->gpio_cs = platp->gpio_cs;
289 		if (platp->gpio_cs_count && !platp->gpio_cs) {
290 			err = -EBUSY;
291 			goto exit;
292 		}
293 		hw->freq = platp->freq;
294 		hw->baudwidth = platp->baudwidth;
295 	} else {
296 		err = tiny_spi_of_probe(pdev);
297 		if (err)
298 			goto exit;
299 	}
300 	for (i = 0; i < hw->gpio_cs_count; i++) {
301 		err = gpio_request(hw->gpio_cs[i], dev_name(&pdev->dev));
302 		if (err)
303 			goto exit_gpio;
304 		gpio_direction_output(hw->gpio_cs[i], 1);
305 	}
306 	hw->bitbang.master->num_chipselect = max(1, hw->gpio_cs_count);
307 
308 	/* register our spi controller */
309 	err = spi_bitbang_start(&hw->bitbang);
310 	if (err)
311 		goto exit;
312 	dev_info(&pdev->dev, "base %p, irq %d\n", hw->base, hw->irq);
313 
314 	return 0;
315 
316 exit_gpio:
317 	while (i-- > 0)
318 		gpio_free(hw->gpio_cs[i]);
319 exit:
320 	spi_master_put(master);
321 	return err;
322 }
323 
324 static int tiny_spi_remove(struct platform_device *pdev)
325 {
326 	struct tiny_spi *hw = platform_get_drvdata(pdev);
327 	struct spi_master *master = hw->bitbang.master;
328 	unsigned int i;
329 
330 	spi_bitbang_stop(&hw->bitbang);
331 	for (i = 0; i < hw->gpio_cs_count; i++)
332 		gpio_free(hw->gpio_cs[i]);
333 	spi_master_put(master);
334 	return 0;
335 }
336 
337 #ifdef CONFIG_OF
338 static const struct of_device_id tiny_spi_match[] = {
339 	{ .compatible = "opencores,tiny-spi-rtlsvn2", },
340 	{},
341 };
342 MODULE_DEVICE_TABLE(of, tiny_spi_match);
343 #endif /* CONFIG_OF */
344 
345 static struct platform_driver tiny_spi_driver = {
346 	.probe = tiny_spi_probe,
347 	.remove = tiny_spi_remove,
348 	.driver = {
349 		.name = DRV_NAME,
350 		.pm = NULL,
351 		.of_match_table = of_match_ptr(tiny_spi_match),
352 	},
353 };
354 module_platform_driver(tiny_spi_driver);
355 
356 MODULE_DESCRIPTION("OpenCores tiny SPI driver");
357 MODULE_AUTHOR("Thomas Chou <thomas@wytron.com.tw>");
358 MODULE_LICENSE("GPL");
359 MODULE_ALIAS("platform:" DRV_NAME);
360