aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/spi/Kconfig7
-rw-r--r--drivers/spi/Makefile1
-rw-r--r--drivers/spi/spi_sh_sci.c205
3 files changed, 213 insertions, 0 deletions
diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
index aaaea81e412a..69e28ed272c1 100644
--- a/drivers/spi/Kconfig
+++ b/drivers/spi/Kconfig
@@ -176,6 +176,13 @@ config SPI_S3C24XX_GPIO
176 the inbuilt hardware cannot provide the transfer mode, or 176 the inbuilt hardware cannot provide the transfer mode, or
177 where the board is using non hardware connected pins. 177 where the board is using non hardware connected pins.
178 178
179config SPI_SH_SCI
180 tristate "SuperH SCI SPI controller"
181 depends on SPI_MASTER && SUPERH
182 select SPI_BITBANG
183 help
184 SPI driver for SuperH SCI blocks.
185
179config SPI_TXX9 186config SPI_TXX9
180 tristate "Toshiba TXx9 SPI controller" 187 tristate "Toshiba TXx9 SPI controller"
181 depends on SPI_MASTER && GENERIC_GPIO && CPU_TX49XX 188 depends on SPI_MASTER && GENERIC_GPIO && CPU_TX49XX
diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile
index 41fbac45c323..7fca043ce723 100644
--- a/drivers/spi/Makefile
+++ b/drivers/spi/Makefile
@@ -27,6 +27,7 @@ obj-$(CONFIG_SPI_S3C24XX_GPIO) += spi_s3c24xx_gpio.o
27obj-$(CONFIG_SPI_S3C24XX) += spi_s3c24xx.o 27obj-$(CONFIG_SPI_S3C24XX) += spi_s3c24xx.o
28obj-$(CONFIG_SPI_TXX9) += spi_txx9.o 28obj-$(CONFIG_SPI_TXX9) += spi_txx9.o
29obj-$(CONFIG_SPI_XILINX) += xilinx_spi.o 29obj-$(CONFIG_SPI_XILINX) += xilinx_spi.o
30obj-$(CONFIG_SPI_SH_SCI) += spi_sh_sci.o
30# ... add above this line ... 31# ... add above this line ...
31 32
32# SPI protocol drivers (device/link on bus) 33# SPI protocol drivers (device/link on bus)
diff --git a/drivers/spi/spi_sh_sci.c b/drivers/spi/spi_sh_sci.c
new file mode 100644
index 000000000000..3dbe71b16d60
--- /dev/null
+++ b/drivers/spi/spi_sh_sci.c
@@ -0,0 +1,205 @@
1/*
2 * SH SCI SPI interface
3 *
4 * Copyright (c) 2008 Magnus Damm
5 *
6 * Based on S3C24XX GPIO based SPI driver, which is:
7 * Copyright (c) 2006 Ben Dooks
8 * Copyright (c) 2006 Simtec Electronics
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License version 2 as
12 * published by the Free Software Foundation.
13 *
14 */
15
16#include <linux/kernel.h>
17#include <linux/init.h>
18#include <linux/delay.h>
19#include <linux/spinlock.h>
20#include <linux/workqueue.h>
21#include <linux/platform_device.h>
22
23#include <linux/spi/spi.h>
24#include <linux/spi/spi_bitbang.h>
25
26#include <asm/spi.h>
27#include <asm/io.h>
28
29struct sh_sci_spi {
30 struct spi_bitbang bitbang;
31
32 void __iomem *membase;
33 unsigned char val;
34 struct sh_spi_info *info;
35 struct platform_device *dev;
36};
37
38#define SCSPTR(sp) (sp->membase + 0x1c)
39#define PIN_SCK (1 << 2)
40#define PIN_TXD (1 << 0)
41#define PIN_RXD PIN_TXD
42#define PIN_INIT ((1 << 1) | (1 << 3) | PIN_SCK | PIN_TXD)
43
44static inline void setbits(struct sh_sci_spi *sp, int bits, int on)
45{
46 /*
47 * We are the only user of SCSPTR so no locking is required.
48 * Reading bit 2 and 0 in SCSPTR gives pin state as input.
49 * Writing the same bits sets the output value.
50 * This makes regular read-modify-write difficult so we
51 * use sp->val to keep track of the latest register value.
52 */
53
54 if (on)
55 sp->val |= bits;
56 else
57 sp->val &= ~bits;
58
59 iowrite8(sp->val, SCSPTR(sp));
60}
61
62static inline void setsck(struct spi_device *dev, int on)
63{
64 setbits(spi_master_get_devdata(dev->master), PIN_SCK, on);
65}
66
67static inline void setmosi(struct spi_device *dev, int on)
68{
69 setbits(spi_master_get_devdata(dev->master), PIN_TXD, on);
70}
71
72static inline u32 getmiso(struct spi_device *dev)
73{
74 struct sh_sci_spi *sp = spi_master_get_devdata(dev->master);
75
76 return (ioread8(SCSPTR(sp)) & PIN_RXD) ? 1 : 0;
77}
78
79#define spidelay(x) ndelay(x)
80
81#define EXPAND_BITBANG_TXRX
82#include <linux/spi/spi_bitbang.h>
83
84static u32 sh_sci_spi_txrx_mode0(struct spi_device *spi,
85 unsigned nsecs, u32 word, u8 bits)
86{
87 return bitbang_txrx_be_cpha0(spi, nsecs, 0, word, bits);
88}
89
90static u32 sh_sci_spi_txrx_mode1(struct spi_device *spi,
91 unsigned nsecs, u32 word, u8 bits)
92{
93 return bitbang_txrx_be_cpha1(spi, nsecs, 0, word, bits);
94}
95
96static u32 sh_sci_spi_txrx_mode2(struct spi_device *spi,
97 unsigned nsecs, u32 word, u8 bits)
98{
99 return bitbang_txrx_be_cpha0(spi, nsecs, 1, word, bits);
100}
101
102static u32 sh_sci_spi_txrx_mode3(struct spi_device *spi,
103 unsigned nsecs, u32 word, u8 bits)
104{
105 return bitbang_txrx_be_cpha1(spi, nsecs, 1, word, bits);
106}
107
108static void sh_sci_spi_chipselect(struct spi_device *dev, int value)
109{
110 struct sh_sci_spi *sp = spi_master_get_devdata(dev->master);
111
112 if (sp->info && sp->info->chip_select)
113 (sp->info->chip_select)(sp->info, dev->chip_select, value);
114}
115
116static int sh_sci_spi_probe(struct platform_device *dev)
117{
118 struct resource *r;
119 struct spi_master *master;
120 struct sh_sci_spi *sp;
121 int ret;
122
123 master = spi_alloc_master(&dev->dev, sizeof(struct sh_sci_spi));
124 if (master == NULL) {
125 dev_err(&dev->dev, "failed to allocate spi master\n");
126 ret = -ENOMEM;
127 goto err0;
128 }
129
130 sp = spi_master_get_devdata(master);
131
132 platform_set_drvdata(dev, sp);
133 sp->info = dev->dev.platform_data;
134
135 /* setup spi bitbang adaptor */
136 sp->bitbang.master = spi_master_get(master);
137 sp->bitbang.master->bus_num = sp->info->bus_num;
138 sp->bitbang.master->num_chipselect = sp->info->num_chipselect;
139 sp->bitbang.chipselect = sh_sci_spi_chipselect;
140
141 sp->bitbang.txrx_word[SPI_MODE_0] = sh_sci_spi_txrx_mode0;
142 sp->bitbang.txrx_word[SPI_MODE_1] = sh_sci_spi_txrx_mode1;
143 sp->bitbang.txrx_word[SPI_MODE_2] = sh_sci_spi_txrx_mode2;
144 sp->bitbang.txrx_word[SPI_MODE_3] = sh_sci_spi_txrx_mode3;
145
146 r = platform_get_resource(dev, IORESOURCE_MEM, 0);
147 if (r == NULL) {
148 ret = -ENOENT;
149 goto err1;
150 }
151 sp->membase = ioremap(r->start, r->end - r->start + 1);
152 if (!sp->membase) {
153 ret = -ENXIO;
154 goto err1;
155 }
156 sp->val = ioread8(SCSPTR(sp));
157 setbits(sp, PIN_INIT, 1);
158
159 ret = spi_bitbang_start(&sp->bitbang);
160 if (!ret)
161 return 0;
162
163 setbits(sp, PIN_INIT, 0);
164 iounmap(sp->membase);
165 err1:
166 spi_master_put(sp->bitbang.master);
167 err0:
168 return ret;
169}
170
171static int sh_sci_spi_remove(struct platform_device *dev)
172{
173 struct sh_sci_spi *sp = platform_get_drvdata(dev);
174
175 iounmap(sp->membase);
176 setbits(sp, PIN_INIT, 0);
177 spi_bitbang_stop(&sp->bitbang);
178 spi_master_put(sp->bitbang.master);
179 return 0;
180}
181
182static struct platform_driver sh_sci_spi_drv = {
183 .probe = sh_sci_spi_probe,
184 .remove = sh_sci_spi_remove,
185 .driver = {
186 .name = "spi_sh_sci",
187 .owner = THIS_MODULE,
188 },
189};
190
191static int __init sh_sci_spi_init(void)
192{
193 return platform_driver_register(&sh_sci_spi_drv);
194}
195module_init(sh_sci_spi_init);
196
197static void __exit sh_sci_spi_exit(void)
198{
199 platform_driver_unregister(&sh_sci_spi_drv);
200}
201module_exit(sh_sci_spi_exit);
202
203MODULE_DESCRIPTION("SH SCI SPI Driver");
204MODULE_AUTHOR("Magnus Damm <damm@opensource.se>");
205MODULE_LICENSE("GPL");