diff options
author | Yoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com> | 2011-02-14 20:30:32 -0500 |
---|---|---|
committer | Grant Likely <grant.likely@secretlab.ca> | 2011-02-22 16:59:54 -0500 |
commit | 5c05dd0750402f174302cf2b8cdf4111be080dcb (patch) | |
tree | 2c4da06e9b58d28aec35f85df31f768045e4a8fa /drivers/spi | |
parent | 0ff56cd85a2c5104a36d84662b9180c219e8604e (diff) |
spi: add support for SuperH SPI
The SH7757 has SPI0 module. This patch supports it.
Signed-off-by: Yoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com>
[grant.likely@secretlab.ca: fixed Makefile ordering, added
__dev{init,exit} annotations, removed DRIVER_VERSION (this is
mainline, the version == the kernel version) and tidied some
indentation & style stuff]
Signed-off-by: Grant Likely <grant.likely@secretlab.ca>
Diffstat (limited to 'drivers/spi')
-rw-r--r-- | drivers/spi/Kconfig | 6 | ||||
-rw-r--r-- | drivers/spi/Makefile | 1 | ||||
-rw-r--r-- | drivers/spi/spi_sh.c | 543 |
3 files changed, 550 insertions, 0 deletions
diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig index e85b248800c7..cdeb01f45bc2 100644 --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig | |||
@@ -343,6 +343,12 @@ config SPI_SH_MSIOF | |||
343 | help | 343 | help |
344 | SPI driver for SuperH MSIOF blocks. | 344 | SPI driver for SuperH MSIOF blocks. |
345 | 345 | ||
346 | config SPI_SH | ||
347 | tristate "SuperH SPI controller" | ||
348 | depends on SUPERH | ||
349 | help | ||
350 | SPI driver for SuperH SPI blocks. | ||
351 | |||
346 | config SPI_SH_SCI | 352 | config SPI_SH_SCI |
347 | tristate "SuperH SCI SPI controller" | 353 | tristate "SuperH SCI SPI controller" |
348 | depends on SUPERH | 354 | depends on SUPERH |
diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile index e111a0f322a9..8b5a315045a6 100644 --- a/drivers/spi/Makefile +++ b/drivers/spi/Makefile | |||
@@ -48,6 +48,7 @@ obj-$(CONFIG_SPI_TEGRA) += spi_tegra.o | |||
48 | obj-$(CONFIG_SPI_TOPCLIFF_PCH) += spi_topcliff_pch.o | 48 | obj-$(CONFIG_SPI_TOPCLIFF_PCH) += spi_topcliff_pch.o |
49 | obj-$(CONFIG_SPI_TXX9) += spi_txx9.o | 49 | obj-$(CONFIG_SPI_TXX9) += spi_txx9.o |
50 | obj-$(CONFIG_SPI_XILINX) += xilinx_spi.o | 50 | obj-$(CONFIG_SPI_XILINX) += xilinx_spi.o |
51 | obj-$(CONFIG_SPI_SH) += spi_sh.o | ||
51 | obj-$(CONFIG_SPI_SH_SCI) += spi_sh_sci.o | 52 | obj-$(CONFIG_SPI_SH_SCI) += spi_sh_sci.o |
52 | obj-$(CONFIG_SPI_SH_MSIOF) += spi_sh_msiof.o | 53 | obj-$(CONFIG_SPI_SH_MSIOF) += spi_sh_msiof.o |
53 | obj-$(CONFIG_SPI_STMP3XXX) += spi_stmp.o | 54 | obj-$(CONFIG_SPI_STMP3XXX) += spi_stmp.o |
diff --git a/drivers/spi/spi_sh.c b/drivers/spi/spi_sh.c new file mode 100644 index 000000000000..869a07d375d6 --- /dev/null +++ b/drivers/spi/spi_sh.c | |||
@@ -0,0 +1,543 @@ | |||
1 | /* | ||
2 | * SH SPI bus driver | ||
3 | * | ||
4 | * Copyright (C) 2011 Renesas Solutions Corp. | ||
5 | * | ||
6 | * Based on pxa2xx_spi.c: | ||
7 | * Copyright (C) 2005 Stephen Street / StreetFire Sound Labs | ||
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 as published by | ||
11 | * the Free Software Foundation; version 2 of the License. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, | ||
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
16 | * GNU General Public License for more details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU General Public License | ||
19 | * along with this program; if not, write to the Free Software | ||
20 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | ||
21 | * | ||
22 | */ | ||
23 | |||
24 | #include <linux/module.h> | ||
25 | #include <linux/kernel.h> | ||
26 | #include <linux/sched.h> | ||
27 | #include <linux/errno.h> | ||
28 | #include <linux/timer.h> | ||
29 | #include <linux/delay.h> | ||
30 | #include <linux/list.h> | ||
31 | #include <linux/workqueue.h> | ||
32 | #include <linux/interrupt.h> | ||
33 | #include <linux/platform_device.h> | ||
34 | #include <linux/io.h> | ||
35 | #include <linux/spi/spi.h> | ||
36 | |||
37 | #define SPI_SH_TBR 0x00 | ||
38 | #define SPI_SH_RBR 0x00 | ||
39 | #define SPI_SH_CR1 0x08 | ||
40 | #define SPI_SH_CR2 0x10 | ||
41 | #define SPI_SH_CR3 0x18 | ||
42 | #define SPI_SH_CR4 0x20 | ||
43 | #define SPI_SH_CR5 0x28 | ||
44 | |||
45 | /* CR1 */ | ||
46 | #define SPI_SH_TBE 0x80 | ||
47 | #define SPI_SH_TBF 0x40 | ||
48 | #define SPI_SH_RBE 0x20 | ||
49 | #define SPI_SH_RBF 0x10 | ||
50 | #define SPI_SH_PFONRD 0x08 | ||
51 | #define SPI_SH_SSDB 0x04 | ||
52 | #define SPI_SH_SSD 0x02 | ||
53 | #define SPI_SH_SSA 0x01 | ||
54 | |||
55 | /* CR2 */ | ||
56 | #define SPI_SH_RSTF 0x80 | ||
57 | #define SPI_SH_LOOPBK 0x40 | ||
58 | #define SPI_SH_CPOL 0x20 | ||
59 | #define SPI_SH_CPHA 0x10 | ||
60 | #define SPI_SH_L1M0 0x08 | ||
61 | |||
62 | /* CR3 */ | ||
63 | #define SPI_SH_MAX_BYTE 0xFF | ||
64 | |||
65 | /* CR4 */ | ||
66 | #define SPI_SH_TBEI 0x80 | ||
67 | #define SPI_SH_TBFI 0x40 | ||
68 | #define SPI_SH_RBEI 0x20 | ||
69 | #define SPI_SH_RBFI 0x10 | ||
70 | #define SPI_SH_WPABRT 0x04 | ||
71 | #define SPI_SH_SSS 0x01 | ||
72 | |||
73 | /* CR8 */ | ||
74 | #define SPI_SH_P1L0 0x80 | ||
75 | #define SPI_SH_PP1L0 0x40 | ||
76 | #define SPI_SH_MUXI 0x20 | ||
77 | #define SPI_SH_MUXIRQ 0x10 | ||
78 | |||
79 | #define SPI_SH_FIFO_SIZE 32 | ||
80 | #define SPI_SH_SEND_TIMEOUT (3 * HZ) | ||
81 | #define SPI_SH_RECEIVE_TIMEOUT (HZ >> 3) | ||
82 | |||
83 | #undef DEBUG | ||
84 | |||
85 | struct spi_sh_data { | ||
86 | void __iomem *addr; | ||
87 | int irq; | ||
88 | struct spi_master *master; | ||
89 | struct list_head queue; | ||
90 | struct workqueue_struct *workqueue; | ||
91 | struct work_struct ws; | ||
92 | unsigned long cr1; | ||
93 | wait_queue_head_t wait; | ||
94 | spinlock_t lock; | ||
95 | }; | ||
96 | |||
97 | static void spi_sh_write(struct spi_sh_data *ss, unsigned long data, | ||
98 | unsigned long offset) | ||
99 | { | ||
100 | writel(data, ss->addr + offset); | ||
101 | } | ||
102 | |||
103 | static unsigned long spi_sh_read(struct spi_sh_data *ss, unsigned long offset) | ||
104 | { | ||
105 | return readl(ss->addr + offset); | ||
106 | } | ||
107 | |||
108 | static void spi_sh_set_bit(struct spi_sh_data *ss, unsigned long val, | ||
109 | unsigned long offset) | ||
110 | { | ||
111 | unsigned long tmp; | ||
112 | |||
113 | tmp = spi_sh_read(ss, offset); | ||
114 | tmp |= val; | ||
115 | spi_sh_write(ss, tmp, offset); | ||
116 | } | ||
117 | |||
118 | static void spi_sh_clear_bit(struct spi_sh_data *ss, unsigned long val, | ||
119 | unsigned long offset) | ||
120 | { | ||
121 | unsigned long tmp; | ||
122 | |||
123 | tmp = spi_sh_read(ss, offset); | ||
124 | tmp &= ~val; | ||
125 | spi_sh_write(ss, tmp, offset); | ||
126 | } | ||
127 | |||
128 | static void clear_fifo(struct spi_sh_data *ss) | ||
129 | { | ||
130 | spi_sh_set_bit(ss, SPI_SH_RSTF, SPI_SH_CR2); | ||
131 | spi_sh_clear_bit(ss, SPI_SH_RSTF, SPI_SH_CR2); | ||
132 | } | ||
133 | |||
134 | static int spi_sh_wait_receive_buffer(struct spi_sh_data *ss) | ||
135 | { | ||
136 | int timeout = 100000; | ||
137 | |||
138 | while (spi_sh_read(ss, SPI_SH_CR1) & SPI_SH_RBE) { | ||
139 | udelay(10); | ||
140 | if (timeout-- < 0) | ||
141 | return -ETIMEDOUT; | ||
142 | } | ||
143 | return 0; | ||
144 | } | ||
145 | |||
146 | static int spi_sh_wait_write_buffer_empty(struct spi_sh_data *ss) | ||
147 | { | ||
148 | int timeout = 100000; | ||
149 | |||
150 | while (!(spi_sh_read(ss, SPI_SH_CR1) & SPI_SH_TBE)) { | ||
151 | udelay(10); | ||
152 | if (timeout-- < 0) | ||
153 | return -ETIMEDOUT; | ||
154 | } | ||
155 | return 0; | ||
156 | } | ||
157 | |||
158 | static int spi_sh_send(struct spi_sh_data *ss, struct spi_message *mesg, | ||
159 | struct spi_transfer *t) | ||
160 | { | ||
161 | int i, retval = 0; | ||
162 | int remain = t->len; | ||
163 | int cur_len; | ||
164 | unsigned char *data; | ||
165 | unsigned long tmp; | ||
166 | long ret; | ||
167 | |||
168 | if (t->len) | ||
169 | spi_sh_set_bit(ss, SPI_SH_SSA, SPI_SH_CR1); | ||
170 | |||
171 | data = (unsigned char *)t->tx_buf; | ||
172 | while (remain > 0) { | ||
173 | cur_len = min(SPI_SH_FIFO_SIZE, remain); | ||
174 | for (i = 0; i < cur_len && | ||
175 | !(spi_sh_read(ss, SPI_SH_CR4) & | ||
176 | SPI_SH_WPABRT) && | ||
177 | !(spi_sh_read(ss, SPI_SH_CR1) & SPI_SH_TBF); | ||
178 | i++) | ||
179 | spi_sh_write(ss, (unsigned long)data[i], SPI_SH_TBR); | ||
180 | |||
181 | if (spi_sh_read(ss, SPI_SH_CR4) & SPI_SH_WPABRT) { | ||
182 | /* Abort SPI operation */ | ||
183 | spi_sh_set_bit(ss, SPI_SH_WPABRT, SPI_SH_CR4); | ||
184 | retval = -EIO; | ||
185 | break; | ||
186 | } | ||
187 | |||
188 | cur_len = i; | ||
189 | |||
190 | remain -= cur_len; | ||
191 | data += cur_len; | ||
192 | |||
193 | if (remain > 0) { | ||
194 | ss->cr1 &= ~SPI_SH_TBE; | ||
195 | spi_sh_set_bit(ss, SPI_SH_TBE, SPI_SH_CR4); | ||
196 | ret = wait_event_interruptible_timeout(ss->wait, | ||
197 | ss->cr1 & SPI_SH_TBE, | ||
198 | SPI_SH_SEND_TIMEOUT); | ||
199 | if (ret == 0 && !(ss->cr1 & SPI_SH_TBE)) { | ||
200 | printk(KERN_ERR "%s: timeout\n", __func__); | ||
201 | return -ETIMEDOUT; | ||
202 | } | ||
203 | } | ||
204 | } | ||
205 | |||
206 | if (list_is_last(&t->transfer_list, &mesg->transfers)) { | ||
207 | tmp = spi_sh_read(ss, SPI_SH_CR1); | ||
208 | tmp = tmp & ~(SPI_SH_SSD | SPI_SH_SSDB); | ||
209 | spi_sh_write(ss, tmp, SPI_SH_CR1); | ||
210 | spi_sh_set_bit(ss, SPI_SH_SSA, SPI_SH_CR1); | ||
211 | |||
212 | ss->cr1 &= ~SPI_SH_TBE; | ||
213 | spi_sh_set_bit(ss, SPI_SH_TBE, SPI_SH_CR4); | ||
214 | ret = wait_event_interruptible_timeout(ss->wait, | ||
215 | ss->cr1 & SPI_SH_TBE, | ||
216 | SPI_SH_SEND_TIMEOUT); | ||
217 | if (ret == 0 && (ss->cr1 & SPI_SH_TBE)) { | ||
218 | printk(KERN_ERR "%s: timeout\n", __func__); | ||
219 | return -ETIMEDOUT; | ||
220 | } | ||
221 | } | ||
222 | |||
223 | return retval; | ||
224 | } | ||
225 | |||
226 | static int spi_sh_receive(struct spi_sh_data *ss, struct spi_message *mesg, | ||
227 | struct spi_transfer *t) | ||
228 | { | ||
229 | int i; | ||
230 | int remain = t->len; | ||
231 | int cur_len; | ||
232 | unsigned char *data; | ||
233 | unsigned long tmp; | ||
234 | long ret; | ||
235 | |||
236 | if (t->len > SPI_SH_MAX_BYTE) | ||
237 | spi_sh_write(ss, SPI_SH_MAX_BYTE, SPI_SH_CR3); | ||
238 | else | ||
239 | spi_sh_write(ss, t->len, SPI_SH_CR3); | ||
240 | |||
241 | tmp = spi_sh_read(ss, SPI_SH_CR1); | ||
242 | tmp = tmp & ~(SPI_SH_SSD | SPI_SH_SSDB); | ||
243 | spi_sh_write(ss, tmp, SPI_SH_CR1); | ||
244 | spi_sh_set_bit(ss, SPI_SH_SSA, SPI_SH_CR1); | ||
245 | |||
246 | spi_sh_wait_write_buffer_empty(ss); | ||
247 | |||
248 | data = (unsigned char *)t->rx_buf; | ||
249 | while (remain > 0) { | ||
250 | if (remain >= SPI_SH_FIFO_SIZE) { | ||
251 | ss->cr1 &= ~SPI_SH_RBF; | ||
252 | spi_sh_set_bit(ss, SPI_SH_RBF, SPI_SH_CR4); | ||
253 | ret = wait_event_interruptible_timeout(ss->wait, | ||
254 | ss->cr1 & SPI_SH_RBF, | ||
255 | SPI_SH_RECEIVE_TIMEOUT); | ||
256 | if (ret == 0 && | ||
257 | spi_sh_read(ss, SPI_SH_CR1) & SPI_SH_RBE) { | ||
258 | printk(KERN_ERR "%s: timeout\n", __func__); | ||
259 | return -ETIMEDOUT; | ||
260 | } | ||
261 | } | ||
262 | |||
263 | cur_len = min(SPI_SH_FIFO_SIZE, remain); | ||
264 | for (i = 0; i < cur_len; i++) { | ||
265 | if (spi_sh_wait_receive_buffer(ss)) | ||
266 | break; | ||
267 | data[i] = (unsigned char)spi_sh_read(ss, SPI_SH_RBR); | ||
268 | } | ||
269 | |||
270 | remain -= cur_len; | ||
271 | data += cur_len; | ||
272 | } | ||
273 | |||
274 | /* deassert CS when SPI is receiving. */ | ||
275 | if (t->len > SPI_SH_MAX_BYTE) { | ||
276 | clear_fifo(ss); | ||
277 | spi_sh_write(ss, 1, SPI_SH_CR3); | ||
278 | } else { | ||
279 | spi_sh_write(ss, 0, SPI_SH_CR3); | ||
280 | } | ||
281 | |||
282 | return 0; | ||
283 | } | ||
284 | |||
285 | static void spi_sh_work(struct work_struct *work) | ||
286 | { | ||
287 | struct spi_sh_data *ss = container_of(work, struct spi_sh_data, ws); | ||
288 | struct spi_message *mesg; | ||
289 | struct spi_transfer *t; | ||
290 | unsigned long flags; | ||
291 | int ret; | ||
292 | |||
293 | pr_debug("%s: enter\n", __func__); | ||
294 | |||
295 | spin_lock_irqsave(&ss->lock, flags); | ||
296 | while (!list_empty(&ss->queue)) { | ||
297 | mesg = list_entry(ss->queue.next, struct spi_message, queue); | ||
298 | list_del_init(&mesg->queue); | ||
299 | |||
300 | spin_unlock_irqrestore(&ss->lock, flags); | ||
301 | list_for_each_entry(t, &mesg->transfers, transfer_list) { | ||
302 | pr_debug("tx_buf = %p, rx_buf = %p\n", | ||
303 | t->tx_buf, t->rx_buf); | ||
304 | pr_debug("len = %d, delay_usecs = %d\n", | ||
305 | t->len, t->delay_usecs); | ||
306 | |||
307 | if (t->tx_buf) { | ||
308 | ret = spi_sh_send(ss, mesg, t); | ||
309 | if (ret < 0) | ||
310 | goto error; | ||
311 | } | ||
312 | if (t->rx_buf) { | ||
313 | ret = spi_sh_receive(ss, mesg, t); | ||
314 | if (ret < 0) | ||
315 | goto error; | ||
316 | } | ||
317 | mesg->actual_length += t->len; | ||
318 | } | ||
319 | spin_lock_irqsave(&ss->lock, flags); | ||
320 | |||
321 | mesg->status = 0; | ||
322 | mesg->complete(mesg->context); | ||
323 | } | ||
324 | |||
325 | clear_fifo(ss); | ||
326 | spi_sh_set_bit(ss, SPI_SH_SSD, SPI_SH_CR1); | ||
327 | udelay(100); | ||
328 | |||
329 | spi_sh_clear_bit(ss, SPI_SH_SSA | SPI_SH_SSDB | SPI_SH_SSD, | ||
330 | SPI_SH_CR1); | ||
331 | |||
332 | clear_fifo(ss); | ||
333 | |||
334 | spin_unlock_irqrestore(&ss->lock, flags); | ||
335 | |||
336 | return; | ||
337 | |||
338 | error: | ||
339 | mesg->status = ret; | ||
340 | mesg->complete(mesg->context); | ||
341 | |||
342 | spi_sh_clear_bit(ss, SPI_SH_SSA | SPI_SH_SSDB | SPI_SH_SSD, | ||
343 | SPI_SH_CR1); | ||
344 | clear_fifo(ss); | ||
345 | |||
346 | } | ||
347 | |||
348 | static int spi_sh_setup(struct spi_device *spi) | ||
349 | { | ||
350 | struct spi_sh_data *ss = spi_master_get_devdata(spi->master); | ||
351 | |||
352 | if (!spi->bits_per_word) | ||
353 | spi->bits_per_word = 8; | ||
354 | |||
355 | pr_debug("%s: enter\n", __func__); | ||
356 | |||
357 | spi_sh_write(ss, 0xfe, SPI_SH_CR1); /* SPI sycle stop */ | ||
358 | spi_sh_write(ss, 0x00, SPI_SH_CR1); /* CR1 init */ | ||
359 | spi_sh_write(ss, 0x00, SPI_SH_CR3); /* CR3 init */ | ||
360 | |||
361 | clear_fifo(ss); | ||
362 | |||
363 | /* 1/8 clock */ | ||
364 | spi_sh_write(ss, spi_sh_read(ss, SPI_SH_CR2) | 0x07, SPI_SH_CR2); | ||
365 | udelay(10); | ||
366 | |||
367 | return 0; | ||
368 | } | ||
369 | |||
370 | static int spi_sh_transfer(struct spi_device *spi, struct spi_message *mesg) | ||
371 | { | ||
372 | struct spi_sh_data *ss = spi_master_get_devdata(spi->master); | ||
373 | unsigned long flags; | ||
374 | |||
375 | pr_debug("%s: enter\n", __func__); | ||
376 | pr_debug("\tmode = %02x\n", spi->mode); | ||
377 | |||
378 | spin_lock_irqsave(&ss->lock, flags); | ||
379 | |||
380 | mesg->actual_length = 0; | ||
381 | mesg->status = -EINPROGRESS; | ||
382 | |||
383 | spi_sh_clear_bit(ss, SPI_SH_SSA, SPI_SH_CR1); | ||
384 | |||
385 | list_add_tail(&mesg->queue, &ss->queue); | ||
386 | queue_work(ss->workqueue, &ss->ws); | ||
387 | |||
388 | spin_unlock_irqrestore(&ss->lock, flags); | ||
389 | |||
390 | return 0; | ||
391 | } | ||
392 | |||
393 | static void spi_sh_cleanup(struct spi_device *spi) | ||
394 | { | ||
395 | struct spi_sh_data *ss = spi_master_get_devdata(spi->master); | ||
396 | |||
397 | pr_debug("%s: enter\n", __func__); | ||
398 | |||
399 | spi_sh_clear_bit(ss, SPI_SH_SSA | SPI_SH_SSDB | SPI_SH_SSD, | ||
400 | SPI_SH_CR1); | ||
401 | } | ||
402 | |||
403 | static irqreturn_t spi_sh_irq(int irq, void *_ss) | ||
404 | { | ||
405 | struct spi_sh_data *ss = (struct spi_sh_data *)_ss; | ||
406 | unsigned long cr1; | ||
407 | |||
408 | cr1 = spi_sh_read(ss, SPI_SH_CR1); | ||
409 | if (cr1 & SPI_SH_TBE) | ||
410 | ss->cr1 |= SPI_SH_TBE; | ||
411 | if (cr1 & SPI_SH_TBF) | ||
412 | ss->cr1 |= SPI_SH_TBF; | ||
413 | if (cr1 & SPI_SH_RBE) | ||
414 | ss->cr1 |= SPI_SH_RBE; | ||
415 | if (cr1 & SPI_SH_RBF) | ||
416 | ss->cr1 |= SPI_SH_RBF; | ||
417 | |||
418 | if (ss->cr1) { | ||
419 | spi_sh_clear_bit(ss, ss->cr1, SPI_SH_CR4); | ||
420 | wake_up(&ss->wait); | ||
421 | } | ||
422 | |||
423 | return IRQ_HANDLED; | ||
424 | } | ||
425 | |||
426 | static int __devexit spi_sh_remove(struct platform_device *pdev) | ||
427 | { | ||
428 | struct spi_sh_data *ss = dev_get_drvdata(&pdev->dev); | ||
429 | |||
430 | destroy_workqueue(ss->workqueue); | ||
431 | free_irq(ss->irq, ss); | ||
432 | iounmap(ss->addr); | ||
433 | spi_master_put(ss->master); | ||
434 | |||
435 | return 0; | ||
436 | } | ||
437 | |||
438 | static int __devinit spi_sh_probe(struct platform_device *pdev) | ||
439 | { | ||
440 | struct resource *res; | ||
441 | struct spi_master *master; | ||
442 | struct spi_sh_data *ss; | ||
443 | int ret, irq; | ||
444 | |||
445 | /* get base addr */ | ||
446 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
447 | if (unlikely(res == NULL)) { | ||
448 | dev_err(&pdev->dev, "invalid resource\n"); | ||
449 | return -EINVAL; | ||
450 | } | ||
451 | |||
452 | irq = platform_get_irq(pdev, 0); | ||
453 | if (irq < 0) { | ||
454 | dev_err(&pdev->dev, "platform_get_irq error\n"); | ||
455 | return -ENODEV; | ||
456 | } | ||
457 | |||
458 | master = spi_alloc_master(&pdev->dev, sizeof(struct spi_sh_data)); | ||
459 | if (master == NULL) { | ||
460 | dev_err(&pdev->dev, "spi_alloc_master error.\n"); | ||
461 | return -ENOMEM; | ||
462 | } | ||
463 | |||
464 | ss = spi_master_get_devdata(master); | ||
465 | dev_set_drvdata(&pdev->dev, ss); | ||
466 | |||
467 | ss->irq = irq; | ||
468 | ss->master = master; | ||
469 | ss->addr = ioremap(res->start, resource_size(res)); | ||
470 | if (ss->addr == NULL) { | ||
471 | dev_err(&pdev->dev, "ioremap error.\n"); | ||
472 | ret = -ENOMEM; | ||
473 | goto error1; | ||
474 | } | ||
475 | INIT_LIST_HEAD(&ss->queue); | ||
476 | spin_lock_init(&ss->lock); | ||
477 | INIT_WORK(&ss->ws, spi_sh_work); | ||
478 | init_waitqueue_head(&ss->wait); | ||
479 | ss->workqueue = create_singlethread_workqueue( | ||
480 | dev_name(master->dev.parent)); | ||
481 | if (ss->workqueue == NULL) { | ||
482 | dev_err(&pdev->dev, "create workqueue error\n"); | ||
483 | ret = -EBUSY; | ||
484 | goto error2; | ||
485 | } | ||
486 | |||
487 | ret = request_irq(irq, spi_sh_irq, IRQF_DISABLED, "spi_sh", ss); | ||
488 | if (ret < 0) { | ||
489 | dev_err(&pdev->dev, "request_irq error\n"); | ||
490 | goto error3; | ||
491 | } | ||
492 | |||
493 | master->num_chipselect = 2; | ||
494 | master->bus_num = pdev->id; | ||
495 | master->setup = spi_sh_setup; | ||
496 | master->transfer = spi_sh_transfer; | ||
497 | master->cleanup = spi_sh_cleanup; | ||
498 | |||
499 | ret = spi_register_master(master); | ||
500 | if (ret < 0) { | ||
501 | printk(KERN_ERR "spi_register_master error.\n"); | ||
502 | goto error4; | ||
503 | } | ||
504 | |||
505 | return 0; | ||
506 | |||
507 | error4: | ||
508 | free_irq(irq, ss); | ||
509 | error3: | ||
510 | destroy_workqueue(ss->workqueue); | ||
511 | error2: | ||
512 | iounmap(ss->addr); | ||
513 | error1: | ||
514 | spi_master_put(master); | ||
515 | |||
516 | return ret; | ||
517 | } | ||
518 | |||
519 | static struct platform_driver spi_sh_driver = { | ||
520 | .probe = spi_sh_probe, | ||
521 | .remove = __devexit_p(spi_sh_remove), | ||
522 | .driver = { | ||
523 | .name = "sh_spi", | ||
524 | .owner = THIS_MODULE, | ||
525 | }, | ||
526 | }; | ||
527 | |||
528 | static int __init spi_sh_init(void) | ||
529 | { | ||
530 | return platform_driver_register(&spi_sh_driver); | ||
531 | } | ||
532 | module_init(spi_sh_init); | ||
533 | |||
534 | static void __exit spi_sh_exit(void) | ||
535 | { | ||
536 | platform_driver_unregister(&spi_sh_driver); | ||
537 | } | ||
538 | module_exit(spi_sh_exit); | ||
539 | |||
540 | MODULE_DESCRIPTION("SH SPI bus driver"); | ||
541 | MODULE_LICENSE("GPL"); | ||
542 | MODULE_AUTHOR("Yoshihiro Shimoda"); | ||
543 | MODULE_ALIAS("platform:sh_spi"); | ||