1d2912cb1SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
2ca632f55SGrant Likely /*
3ca632f55SGrant Likely * SH SCI SPI interface
4ca632f55SGrant Likely *
5ca632f55SGrant Likely * Copyright (c) 2008 Magnus Damm
6ca632f55SGrant Likely *
7ca632f55SGrant Likely * Based on S3C24XX GPIO based SPI driver, which is:
8ca632f55SGrant Likely * Copyright (c) 2006 Ben Dooks
9ca632f55SGrant Likely * Copyright (c) 2006 Simtec Electronics
10ca632f55SGrant Likely */
11ca632f55SGrant Likely
12ca632f55SGrant Likely #include <linux/kernel.h>
13ca632f55SGrant Likely #include <linux/delay.h>
14ca632f55SGrant Likely #include <linux/spinlock.h>
15ca632f55SGrant Likely #include <linux/platform_device.h>
16ca632f55SGrant Likely
17ca632f55SGrant Likely #include <linux/spi/spi.h>
18ca632f55SGrant Likely #include <linux/spi/spi_bitbang.h>
19d7614de4SPaul Gortmaker #include <linux/module.h>
20ca632f55SGrant Likely
21ca632f55SGrant Likely #include <asm/spi.h>
22ca632f55SGrant Likely #include <asm/io.h>
23ca632f55SGrant Likely
24ca632f55SGrant Likely struct sh_sci_spi {
25ca632f55SGrant Likely struct spi_bitbang bitbang;
26ca632f55SGrant Likely
27ca632f55SGrant Likely void __iomem *membase;
28ca632f55SGrant Likely unsigned char val;
29ca632f55SGrant Likely struct sh_spi_info *info;
30ca632f55SGrant Likely struct platform_device *dev;
31ca632f55SGrant Likely };
32ca632f55SGrant Likely
33ca632f55SGrant Likely #define SCSPTR(sp) (sp->membase + 0x1c)
34ca632f55SGrant Likely #define PIN_SCK (1 << 2)
35ca632f55SGrant Likely #define PIN_TXD (1 << 0)
36ca632f55SGrant Likely #define PIN_RXD PIN_TXD
37ca632f55SGrant Likely #define PIN_INIT ((1 << 1) | (1 << 3) | PIN_SCK | PIN_TXD)
38ca632f55SGrant Likely
setbits(struct sh_sci_spi * sp,int bits,int on)39ca632f55SGrant Likely static inline void setbits(struct sh_sci_spi *sp, int bits, int on)
40ca632f55SGrant Likely {
41ca632f55SGrant Likely /*
42ca632f55SGrant Likely * We are the only user of SCSPTR so no locking is required.
43ca632f55SGrant Likely * Reading bit 2 and 0 in SCSPTR gives pin state as input.
44ca632f55SGrant Likely * Writing the same bits sets the output value.
45ca632f55SGrant Likely * This makes regular read-modify-write difficult so we
46ca632f55SGrant Likely * use sp->val to keep track of the latest register value.
47ca632f55SGrant Likely */
48ca632f55SGrant Likely
49ca632f55SGrant Likely if (on)
50ca632f55SGrant Likely sp->val |= bits;
51ca632f55SGrant Likely else
52ca632f55SGrant Likely sp->val &= ~bits;
53ca632f55SGrant Likely
54ca632f55SGrant Likely iowrite8(sp->val, SCSPTR(sp));
55ca632f55SGrant Likely }
56ca632f55SGrant Likely
setsck(struct spi_device * dev,int on)57ca632f55SGrant Likely static inline void setsck(struct spi_device *dev, int on)
58ca632f55SGrant Likely {
59*91a940bbSYang Yingliang setbits(spi_controller_get_devdata(dev->controller), PIN_SCK, on);
60ca632f55SGrant Likely }
61ca632f55SGrant Likely
setmosi(struct spi_device * dev,int on)62ca632f55SGrant Likely static inline void setmosi(struct spi_device *dev, int on)
63ca632f55SGrant Likely {
64*91a940bbSYang Yingliang setbits(spi_controller_get_devdata(dev->controller), PIN_TXD, on);
65ca632f55SGrant Likely }
66ca632f55SGrant Likely
getmiso(struct spi_device * dev)67ca632f55SGrant Likely static inline u32 getmiso(struct spi_device *dev)
68ca632f55SGrant Likely {
69*91a940bbSYang Yingliang struct sh_sci_spi *sp = spi_controller_get_devdata(dev->controller);
70ca632f55SGrant Likely
71ca632f55SGrant Likely return (ioread8(SCSPTR(sp)) & PIN_RXD) ? 1 : 0;
72ca632f55SGrant Likely }
73ca632f55SGrant Likely
74ca632f55SGrant Likely #define spidelay(x) ndelay(x)
75ca632f55SGrant Likely
76ca632f55SGrant Likely #include "spi-bitbang-txrx.h"
77ca632f55SGrant Likely
sh_sci_spi_txrx_mode0(struct spi_device * spi,unsigned nsecs,u32 word,u8 bits,unsigned flags)78ca632f55SGrant Likely static u32 sh_sci_spi_txrx_mode0(struct spi_device *spi,
79304d3436SLorenzo Bianconi unsigned nsecs, u32 word, u8 bits,
80304d3436SLorenzo Bianconi unsigned flags)
81ca632f55SGrant Likely {
82304d3436SLorenzo Bianconi return bitbang_txrx_be_cpha0(spi, nsecs, 0, flags, word, bits);
83ca632f55SGrant Likely }
84ca632f55SGrant Likely
sh_sci_spi_txrx_mode1(struct spi_device * spi,unsigned nsecs,u32 word,u8 bits,unsigned flags)85ca632f55SGrant Likely static u32 sh_sci_spi_txrx_mode1(struct spi_device *spi,
86304d3436SLorenzo Bianconi unsigned nsecs, u32 word, u8 bits,
87304d3436SLorenzo Bianconi unsigned flags)
88ca632f55SGrant Likely {
89304d3436SLorenzo Bianconi return bitbang_txrx_be_cpha1(spi, nsecs, 0, flags, word, bits);
90ca632f55SGrant Likely }
91ca632f55SGrant Likely
sh_sci_spi_txrx_mode2(struct spi_device * spi,unsigned nsecs,u32 word,u8 bits,unsigned flags)92ca632f55SGrant Likely static u32 sh_sci_spi_txrx_mode2(struct spi_device *spi,
93304d3436SLorenzo Bianconi unsigned nsecs, u32 word, u8 bits,
94304d3436SLorenzo Bianconi unsigned flags)
95ca632f55SGrant Likely {
96304d3436SLorenzo Bianconi return bitbang_txrx_be_cpha0(spi, nsecs, 1, flags, word, bits);
97ca632f55SGrant Likely }
98ca632f55SGrant Likely
sh_sci_spi_txrx_mode3(struct spi_device * spi,unsigned nsecs,u32 word,u8 bits,unsigned flags)99ca632f55SGrant Likely static u32 sh_sci_spi_txrx_mode3(struct spi_device *spi,
100304d3436SLorenzo Bianconi unsigned nsecs, u32 word, u8 bits,
101304d3436SLorenzo Bianconi unsigned flags)
102ca632f55SGrant Likely {
103304d3436SLorenzo Bianconi return bitbang_txrx_be_cpha1(spi, nsecs, 1, flags, word, bits);
104ca632f55SGrant Likely }
105ca632f55SGrant Likely
sh_sci_spi_chipselect(struct spi_device * dev,int value)106ca632f55SGrant Likely static void sh_sci_spi_chipselect(struct spi_device *dev, int value)
107ca632f55SGrant Likely {
108*91a940bbSYang Yingliang struct sh_sci_spi *sp = spi_controller_get_devdata(dev->controller);
109ca632f55SGrant Likely
110ed8eb250SAxel Lin if (sp->info->chip_select)
1119e264f3fSAmit Kumar Mahapatra via Alsa-devel (sp->info->chip_select)(sp->info, spi_get_chipselect(dev, 0), value);
112ca632f55SGrant Likely }
113ca632f55SGrant Likely
sh_sci_spi_probe(struct platform_device * dev)114ca632f55SGrant Likely static int sh_sci_spi_probe(struct platform_device *dev)
115ca632f55SGrant Likely {
116ca632f55SGrant Likely struct resource *r;
117*91a940bbSYang Yingliang struct spi_controller *host;
118ca632f55SGrant Likely struct sh_sci_spi *sp;
119ca632f55SGrant Likely int ret;
120ca632f55SGrant Likely
121*91a940bbSYang Yingliang host = spi_alloc_host(&dev->dev, sizeof(struct sh_sci_spi));
122*91a940bbSYang Yingliang if (host == NULL) {
123*91a940bbSYang Yingliang dev_err(&dev->dev, "failed to allocate spi host\n");
124ca632f55SGrant Likely ret = -ENOMEM;
125ca632f55SGrant Likely goto err0;
126ca632f55SGrant Likely }
127ca632f55SGrant Likely
128*91a940bbSYang Yingliang sp = spi_controller_get_devdata(host);
129ca632f55SGrant Likely
130ca632f55SGrant Likely platform_set_drvdata(dev, sp);
1318074cf06SJingoo Han sp->info = dev_get_platdata(&dev->dev);
132ed8eb250SAxel Lin if (!sp->info) {
133ed8eb250SAxel Lin dev_err(&dev->dev, "platform data is missing\n");
134ed8eb250SAxel Lin ret = -ENOENT;
135ed8eb250SAxel Lin goto err1;
136ed8eb250SAxel Lin }
137ca632f55SGrant Likely
138ca632f55SGrant Likely /* setup spi bitbang adaptor */
139*91a940bbSYang Yingliang sp->bitbang.master = host;
140ca632f55SGrant Likely sp->bitbang.master->bus_num = sp->info->bus_num;
141ca632f55SGrant Likely sp->bitbang.master->num_chipselect = sp->info->num_chipselect;
142ca632f55SGrant Likely sp->bitbang.chipselect = sh_sci_spi_chipselect;
143ca632f55SGrant Likely
144ca632f55SGrant Likely sp->bitbang.txrx_word[SPI_MODE_0] = sh_sci_spi_txrx_mode0;
145ca632f55SGrant Likely sp->bitbang.txrx_word[SPI_MODE_1] = sh_sci_spi_txrx_mode1;
146ca632f55SGrant Likely sp->bitbang.txrx_word[SPI_MODE_2] = sh_sci_spi_txrx_mode2;
147ca632f55SGrant Likely sp->bitbang.txrx_word[SPI_MODE_3] = sh_sci_spi_txrx_mode3;
148ca632f55SGrant Likely
149ca632f55SGrant Likely r = platform_get_resource(dev, IORESOURCE_MEM, 0);
150ca632f55SGrant Likely if (r == NULL) {
151ca632f55SGrant Likely ret = -ENOENT;
152ca632f55SGrant Likely goto err1;
153ca632f55SGrant Likely }
154ca632f55SGrant Likely sp->membase = ioremap(r->start, resource_size(r));
155ca632f55SGrant Likely if (!sp->membase) {
156ca632f55SGrant Likely ret = -ENXIO;
157ca632f55SGrant Likely goto err1;
158ca632f55SGrant Likely }
159ca632f55SGrant Likely sp->val = ioread8(SCSPTR(sp));
160ca632f55SGrant Likely setbits(sp, PIN_INIT, 1);
161ca632f55SGrant Likely
162ca632f55SGrant Likely ret = spi_bitbang_start(&sp->bitbang);
163ca632f55SGrant Likely if (!ret)
164ca632f55SGrant Likely return 0;
165ca632f55SGrant Likely
166ca632f55SGrant Likely setbits(sp, PIN_INIT, 0);
167ca632f55SGrant Likely iounmap(sp->membase);
168ca632f55SGrant Likely err1:
169*91a940bbSYang Yingliang spi_controller_put(sp->bitbang.master);
170ca632f55SGrant Likely err0:
171ca632f55SGrant Likely return ret;
172ca632f55SGrant Likely }
173ca632f55SGrant Likely
sh_sci_spi_remove(struct platform_device * dev)17480dc51daSUwe Kleine-König static void sh_sci_spi_remove(struct platform_device *dev)
175ca632f55SGrant Likely {
176ca632f55SGrant Likely struct sh_sci_spi *sp = platform_get_drvdata(dev);
177ca632f55SGrant Likely
178ca632f55SGrant Likely spi_bitbang_stop(&sp->bitbang);
17925f8a7ccSJürg Billeter setbits(sp, PIN_INIT, 0);
18025f8a7ccSJürg Billeter iounmap(sp->membase);
181*91a940bbSYang Yingliang spi_controller_put(sp->bitbang.master);
182ca632f55SGrant Likely }
183ca632f55SGrant Likely
184ca632f55SGrant Likely static struct platform_driver sh_sci_spi_drv = {
185ca632f55SGrant Likely .probe = sh_sci_spi_probe,
18680dc51daSUwe Kleine-König .remove_new = sh_sci_spi_remove,
187ca632f55SGrant Likely .driver = {
188ca632f55SGrant Likely .name = "spi_sh_sci",
189ca632f55SGrant Likely },
190ca632f55SGrant Likely };
191940ab889SGrant Likely module_platform_driver(sh_sci_spi_drv);
192ca632f55SGrant Likely
193ca632f55SGrant Likely MODULE_DESCRIPTION("SH SCI SPI Driver");
194ca632f55SGrant Likely MODULE_AUTHOR("Magnus Damm <damm@opensource.se>");
195ca632f55SGrant Likely MODULE_LICENSE("GPL");
196ca632f55SGrant Likely MODULE_ALIAS("platform:spi_sh_sci");
197