blob: ed1068ac055f46d275823e0e3b0f4be0f83fa3b7 [file] [log] [blame]
Gabor Juhos8efaef42011-01-04 21:28:22 +01001/*
2 * SPI controller driver for the Atheros AR71XX/AR724X/AR913X SoCs
3 *
4 * Copyright (C) 2009-2011 Gabor Juhos <juhosg@openwrt.org>
5 *
6 * This driver has been based on the spi-gpio.c:
7 * Copyright (C) 2006,2008 David Brownell
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License version 2 as
11 * published by the Free Software Foundation.
12 *
13 */
14
15#include <linux/kernel.h>
Gabor Juhos807cc4b2011-11-16 20:01:43 +010016#include <linux/module.h>
Gabor Juhos8efaef42011-01-04 21:28:22 +010017#include <linux/delay.h>
18#include <linux/spinlock.h>
Gabor Juhos8efaef42011-01-04 21:28:22 +010019#include <linux/platform_device.h>
20#include <linux/io.h>
21#include <linux/spi/spi.h>
22#include <linux/spi/spi_bitbang.h>
23#include <linux/bitops.h>
Linus Walleij8db79542019-01-07 16:51:51 +010024#include <linux/gpio/consumer.h>
Gabor Juhos440114f2012-12-27 10:42:24 +010025#include <linux/clk.h>
26#include <linux/err.h>
Gabor Juhos8efaef42011-01-04 21:28:22 +010027
28#include <asm/mach-ath79/ar71xx_regs.h>
29#include <asm/mach-ath79/ath79_spi_platform.h>
30
31#define DRV_NAME "ath79-spi"
32
Gabor Juhos440114f2012-12-27 10:42:24 +010033#define ATH79_SPI_RRW_DELAY_FACTOR 12000
34#define MHZ (1000 * 1000)
35
Gabor Juhos8efaef42011-01-04 21:28:22 +010036struct ath79_spi {
37 struct spi_bitbang bitbang;
38 u32 ioc_base;
39 u32 reg_ctrl;
40 void __iomem *base;
Gabor Juhos440114f2012-12-27 10:42:24 +010041 struct clk *clk;
Aravind Thokalada470d62017-06-27 22:01:11 +053042 unsigned int rrw_delay;
Gabor Juhos8efaef42011-01-04 21:28:22 +010043};
44
Aravind Thokalada470d62017-06-27 22:01:11 +053045static inline u32 ath79_spi_rr(struct ath79_spi *sp, unsigned int reg)
Gabor Juhos8efaef42011-01-04 21:28:22 +010046{
47 return ioread32(sp->base + reg);
48}
49
Aravind Thokalada470d62017-06-27 22:01:11 +053050static inline void ath79_spi_wr(struct ath79_spi *sp, unsigned int reg, u32 val)
Gabor Juhos8efaef42011-01-04 21:28:22 +010051{
52 iowrite32(val, sp->base + reg);
53}
54
55static inline struct ath79_spi *ath79_spidev_to_sp(struct spi_device *spi)
56{
57 return spi_master_get_devdata(spi->master);
58}
59
Aravind Thokalada470d62017-06-27 22:01:11 +053060static inline void ath79_spi_delay(struct ath79_spi *sp, unsigned int nsecs)
Gabor Juhos440114f2012-12-27 10:42:24 +010061{
62 if (nsecs > sp->rrw_delay)
63 ndelay(nsecs - sp->rrw_delay);
64}
65
Gabor Juhos8efaef42011-01-04 21:28:22 +010066static void ath79_spi_chipselect(struct spi_device *spi, int is_active)
67{
68 struct ath79_spi *sp = ath79_spidev_to_sp(spi);
69 int cs_high = (spi->mode & SPI_CS_HIGH) ? is_active : !is_active;
70
71 if (is_active) {
72 /* set initial clock polarity */
73 if (spi->mode & SPI_CPOL)
74 sp->ioc_base |= AR71XX_SPI_IOC_CLK;
75 else
76 sp->ioc_base &= ~AR71XX_SPI_IOC_CLK;
77
78 ath79_spi_wr(sp, AR71XX_SPI_REG_IOC, sp->ioc_base);
79 }
80
Linus Walleij8db79542019-01-07 16:51:51 +010081 if (spi->cs_gpiod) {
82 /*
83 * SPI chipselect is normally active-low, but
84 * inversion semantics are handled by gpiolib.
85 *
86 * FIXME: is this ever used? The driver doesn't
87 * set SPI_MASTER_GPIO_SS so this callback should not
88 * get called if a CS GPIO is found by the SPI core.
89 */
90 gpiod_set_value_cansleep(spi->cs_gpiod, is_active);
Gabor Juhos8efaef42011-01-04 21:28:22 +010091 } else {
Felix Fietkau22c76322016-12-09 20:48:52 +010092 u32 cs_bit = AR71XX_SPI_IOC_CS(spi->chip_select);
93
Gabor Juhos8efaef42011-01-04 21:28:22 +010094 if (cs_high)
Felix Fietkau22c76322016-12-09 20:48:52 +010095 sp->ioc_base |= cs_bit;
Gabor Juhos8efaef42011-01-04 21:28:22 +010096 else
Felix Fietkau22c76322016-12-09 20:48:52 +010097 sp->ioc_base &= ~cs_bit;
Gabor Juhos8efaef42011-01-04 21:28:22 +010098
99 ath79_spi_wr(sp, AR71XX_SPI_REG_IOC, sp->ioc_base);
100 }
101
102}
103
Gabor Juhosc4a31f42012-12-27 10:42:28 +0100104static void ath79_spi_enable(struct ath79_spi *sp)
Gabor Juhos8efaef42011-01-04 21:28:22 +0100105{
Gabor Juhos8efaef42011-01-04 21:28:22 +0100106 /* enable GPIO mode */
107 ath79_spi_wr(sp, AR71XX_SPI_REG_FS, AR71XX_SPI_FS_GPIO);
108
109 /* save CTRL register */
110 sp->reg_ctrl = ath79_spi_rr(sp, AR71XX_SPI_REG_CTRL);
111 sp->ioc_base = ath79_spi_rr(sp, AR71XX_SPI_REG_IOC);
112
113 /* TODO: setup speed? */
114 ath79_spi_wr(sp, AR71XX_SPI_REG_CTRL, 0x43);
Gabor Juhosc4a31f42012-12-27 10:42:28 +0100115}
116
117static void ath79_spi_disable(struct ath79_spi *sp)
118{
119 /* restore CTRL register */
120 ath79_spi_wr(sp, AR71XX_SPI_REG_CTRL, sp->reg_ctrl);
121 /* disable GPIO mode */
122 ath79_spi_wr(sp, AR71XX_SPI_REG_FS, 0);
123}
124
125static int ath79_spi_setup_cs(struct spi_device *spi)
126{
Alban Bedel83f0f392015-04-24 16:19:24 +0200127 struct ath79_spi *sp = ath79_spidev_to_sp(spi);
Gabor Juhosc4a31f42012-12-27 10:42:28 +0100128
Linus Walleij8db79542019-01-07 16:51:51 +0100129 if (!spi->cs_gpiod) {
Felix Fietkau22c76322016-12-09 20:48:52 +0100130 u32 cs_bit = AR71XX_SPI_IOC_CS(spi->chip_select);
131
Alban Bedel83f0f392015-04-24 16:19:24 +0200132 if (spi->mode & SPI_CS_HIGH)
Felix Fietkau22c76322016-12-09 20:48:52 +0100133 sp->ioc_base &= ~cs_bit;
Alban Bedel83f0f392015-04-24 16:19:24 +0200134 else
Felix Fietkau22c76322016-12-09 20:48:52 +0100135 sp->ioc_base |= cs_bit;
Alban Bedel83f0f392015-04-24 16:19:24 +0200136
137 ath79_spi_wr(sp, AR71XX_SPI_REG_IOC, sp->ioc_base);
Gabor Juhos8efaef42011-01-04 21:28:22 +0100138 }
139
Linus Walleij8db79542019-01-07 16:51:51 +0100140 return 0;
Gabor Juhos8efaef42011-01-04 21:28:22 +0100141}
142
143static int ath79_spi_setup(struct spi_device *spi)
144{
145 int status = 0;
146
Gabor Juhos8efaef42011-01-04 21:28:22 +0100147 if (!spi->controller_state) {
148 status = ath79_spi_setup_cs(spi);
149 if (status)
150 return status;
151 }
152
153 status = spi_bitbang_setup(spi);
Gabor Juhos8efaef42011-01-04 21:28:22 +0100154
155 return status;
156}
157
158static void ath79_spi_cleanup(struct spi_device *spi)
159{
Gabor Juhos8efaef42011-01-04 21:28:22 +0100160 spi_bitbang_cleanup(spi);
161}
162
Aravind Thokalada470d62017-06-27 22:01:11 +0530163static u32 ath79_spi_txrx_mode0(struct spi_device *spi, unsigned int nsecs,
Lorenzo Bianconi304d3432018-07-28 10:19:13 +0200164 u32 word, u8 bits, unsigned flags)
Gabor Juhos8efaef42011-01-04 21:28:22 +0100165{
166 struct ath79_spi *sp = ath79_spidev_to_sp(spi);
167 u32 ioc = sp->ioc_base;
168
169 /* clock starts at inactive polarity */
170 for (word <<= (32 - bits); likely(bits); bits--) {
171 u32 out;
172
173 if (word & (1 << 31))
174 out = ioc | AR71XX_SPI_IOC_DO;
175 else
176 out = ioc & ~AR71XX_SPI_IOC_DO;
177
178 /* setup MSB (to slave) on trailing edge */
179 ath79_spi_wr(sp, AR71XX_SPI_REG_IOC, out);
Gabor Juhos440114f2012-12-27 10:42:24 +0100180 ath79_spi_delay(sp, nsecs);
Gabor Juhos8efaef42011-01-04 21:28:22 +0100181 ath79_spi_wr(sp, AR71XX_SPI_REG_IOC, out | AR71XX_SPI_IOC_CLK);
Gabor Juhos440114f2012-12-27 10:42:24 +0100182 ath79_spi_delay(sp, nsecs);
Gabor Juhos72611db2012-12-27 10:42:25 +0100183 if (bits == 1)
184 ath79_spi_wr(sp, AR71XX_SPI_REG_IOC, out);
Gabor Juhos8efaef42011-01-04 21:28:22 +0100185
186 word <<= 1;
187 }
188
189 return ath79_spi_rr(sp, AR71XX_SPI_REG_RDS);
190}
191
Grant Likelyfd4a3192012-12-07 16:57:14 +0000192static int ath79_spi_probe(struct platform_device *pdev)
Gabor Juhos8efaef42011-01-04 21:28:22 +0100193{
194 struct spi_master *master;
195 struct ath79_spi *sp;
196 struct ath79_spi_platform_data *pdata;
197 struct resource *r;
Gabor Juhos440114f2012-12-27 10:42:24 +0100198 unsigned long rate;
Gabor Juhos8efaef42011-01-04 21:28:22 +0100199 int ret;
200
201 master = spi_alloc_master(&pdev->dev, sizeof(*sp));
202 if (master == NULL) {
203 dev_err(&pdev->dev, "failed to allocate spi master\n");
204 return -ENOMEM;
205 }
206
207 sp = spi_master_get_devdata(master);
Alban Bedel85f62472015-04-24 16:19:22 +0200208 master->dev.of_node = pdev->dev.of_node;
Gabor Juhos8efaef42011-01-04 21:28:22 +0100209 platform_set_drvdata(pdev, sp);
210
Jingoo Han8074cf02013-07-30 16:58:59 +0900211 pdata = dev_get_platdata(&pdev->dev);
Gabor Juhos8efaef42011-01-04 21:28:22 +0100212
Linus Walleij8db79542019-01-07 16:51:51 +0100213 master->use_gpio_descriptors = true;
Stephen Warren24778be2013-05-21 20:36:35 -0600214 master->bits_per_word_mask = SPI_BPW_RANGE_MASK(1, 32);
Gabor Juhos8efaef42011-01-04 21:28:22 +0100215 master->setup = ath79_spi_setup;
216 master->cleanup = ath79_spi_cleanup;
217 if (pdata) {
218 master->bus_num = pdata->bus_num;
219 master->num_chipselect = pdata->num_chipselect;
Gabor Juhos8efaef42011-01-04 21:28:22 +0100220 }
221
Axel Lin94c69f72013-09-10 15:43:41 +0800222 sp->bitbang.master = master;
Gabor Juhos8efaef42011-01-04 21:28:22 +0100223 sp->bitbang.chipselect = ath79_spi_chipselect;
224 sp->bitbang.txrx_word[SPI_MODE_0] = ath79_spi_txrx_mode0;
225 sp->bitbang.setup_transfer = spi_bitbang_setup_transfer;
226 sp->bitbang.flags = SPI_CS_HIGH;
227
228 r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
Heiner Kallweitb7a2a1c2015-09-27 18:47:35 +0200229 sp->base = devm_ioremap_resource(&pdev->dev, r);
230 if (IS_ERR(sp->base)) {
231 ret = PTR_ERR(sp->base);
Gabor Juhos8efaef42011-01-04 21:28:22 +0100232 goto err_put_master;
233 }
234
Jingoo Hana6f4c8e2013-12-09 19:14:58 +0900235 sp->clk = devm_clk_get(&pdev->dev, "ahb");
Gabor Juhos440114f2012-12-27 10:42:24 +0100236 if (IS_ERR(sp->clk)) {
237 ret = PTR_ERR(sp->clk);
Jingoo Hana6f4c8e2013-12-09 19:14:58 +0900238 goto err_put_master;
Gabor Juhos440114f2012-12-27 10:42:24 +0100239 }
240
Alban Bedel3e19acd2015-04-24 16:19:23 +0200241 ret = clk_prepare_enable(sp->clk);
Gabor Juhos440114f2012-12-27 10:42:24 +0100242 if (ret)
Jingoo Hana6f4c8e2013-12-09 19:14:58 +0900243 goto err_put_master;
Gabor Juhos440114f2012-12-27 10:42:24 +0100244
245 rate = DIV_ROUND_UP(clk_get_rate(sp->clk), MHZ);
246 if (!rate) {
247 ret = -EINVAL;
248 goto err_clk_disable;
249 }
250
251 sp->rrw_delay = ATH79_SPI_RRW_DELAY_FACTOR / rate;
252 dev_dbg(&pdev->dev, "register read/write delay is %u nsecs\n",
253 sp->rrw_delay);
254
Gabor Juhosc4a31f42012-12-27 10:42:28 +0100255 ath79_spi_enable(sp);
Gabor Juhos8efaef42011-01-04 21:28:22 +0100256 ret = spi_bitbang_start(&sp->bitbang);
257 if (ret)
Gabor Juhosc4a31f42012-12-27 10:42:28 +0100258 goto err_disable;
Gabor Juhos8efaef42011-01-04 21:28:22 +0100259
260 return 0;
261
Gabor Juhosc4a31f42012-12-27 10:42:28 +0100262err_disable:
263 ath79_spi_disable(sp);
Gabor Juhos440114f2012-12-27 10:42:24 +0100264err_clk_disable:
Alban Bedel3e19acd2015-04-24 16:19:23 +0200265 clk_disable_unprepare(sp->clk);
Gabor Juhos8efaef42011-01-04 21:28:22 +0100266err_put_master:
Gabor Juhos8efaef42011-01-04 21:28:22 +0100267 spi_master_put(sp->bitbang.master);
268
269 return ret;
270}
271
Grant Likelyfd4a3192012-12-07 16:57:14 +0000272static int ath79_spi_remove(struct platform_device *pdev)
Gabor Juhos8efaef42011-01-04 21:28:22 +0100273{
274 struct ath79_spi *sp = platform_get_drvdata(pdev);
275
276 spi_bitbang_stop(&sp->bitbang);
Gabor Juhosc4a31f42012-12-27 10:42:28 +0100277 ath79_spi_disable(sp);
Alban Bedel3e19acd2015-04-24 16:19:23 +0200278 clk_disable_unprepare(sp->clk);
Gabor Juhos8efaef42011-01-04 21:28:22 +0100279 spi_master_put(sp->bitbang.master);
280
281 return 0;
282}
283
Gabor Juhos7410e842013-02-05 20:57:55 +0100284static void ath79_spi_shutdown(struct platform_device *pdev)
285{
286 ath79_spi_remove(pdev);
287}
288
Alban Bedel85f62472015-04-24 16:19:22 +0200289static const struct of_device_id ath79_spi_of_match[] = {
290 { .compatible = "qca,ar7100-spi", },
291 { },
292};
Javier Martinez Canillasd7a32392016-11-23 13:37:11 -0300293MODULE_DEVICE_TABLE(of, ath79_spi_of_match);
Alban Bedel85f62472015-04-24 16:19:22 +0200294
Gabor Juhos8efaef42011-01-04 21:28:22 +0100295static struct platform_driver ath79_spi_driver = {
296 .probe = ath79_spi_probe,
Grant Likelyfd4a3192012-12-07 16:57:14 +0000297 .remove = ath79_spi_remove,
Gabor Juhos7410e842013-02-05 20:57:55 +0100298 .shutdown = ath79_spi_shutdown,
Gabor Juhos8efaef42011-01-04 21:28:22 +0100299 .driver = {
300 .name = DRV_NAME,
Alban Bedel85f62472015-04-24 16:19:22 +0200301 .of_match_table = ath79_spi_of_match,
Gabor Juhos8efaef42011-01-04 21:28:22 +0100302 },
303};
Grant Likely940ab882011-10-05 11:29:49 -0600304module_platform_driver(ath79_spi_driver);
Gabor Juhos8efaef42011-01-04 21:28:22 +0100305
306MODULE_DESCRIPTION("SPI controller driver for Atheros AR71XX/AR724X/AR913X");
307MODULE_AUTHOR("Gabor Juhos <juhosg@openwrt.org>");
308MODULE_LICENSE("GPL v2");
309MODULE_ALIAS("platform:" DRV_NAME);