aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/spi/spi_sh_sci.c
diff options
context:
space:
mode:
authorMagnus Damm <magnus.damm@gmail.com>2008-02-06 04:38:15 -0500
committerLinus Torvalds <torvalds@woody.linux-foundation.org>2008-02-06 13:41:11 -0500
commit37e466408796300ec935e15f01b4ca88678b96ef (patch)
tree946465d14460a9dec3552c746850d4706c5981f1 /drivers/spi/spi_sh_sci.c
parentb359fbc4582abf346fa6773b2bc1d63581fda582 (diff)
spi: SuperH SPI using SCI
Add support for SPI over SCI pins. SCI is a very simple serial controller block that can be found on older SuperH processors. In theory it is possible to use the SCI hardware block in syncronous mode, but this version of the driver simply hooks up the bit banging code on the SCI pins. Signed-off-by: Magnus Damm <damm@igel.co.jp> Signed-off-by: David Brownell <dbrownell@users.sourceforge.net> Cc: Paul Mundt <lethal@linux-sh.org> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'drivers/spi/spi_sh_sci.c')
-rw-r--r--drivers/spi/spi_sh_sci.c205
1 files changed, 205 insertions, 0 deletions
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");