diff options
Diffstat (limited to 'drivers/spi/spi-s3c24xx.c')
-rw-r--r-- | drivers/spi/spi-s3c24xx.c | 745 |
1 files changed, 745 insertions, 0 deletions
diff --git a/drivers/spi/spi-s3c24xx.c b/drivers/spi/spi-s3c24xx.c new file mode 100644 index 000000000000..1996ac57ef91 --- /dev/null +++ b/drivers/spi/spi-s3c24xx.c | |||
@@ -0,0 +1,745 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2006 Ben Dooks | ||
3 | * Copyright 2006-2009 Simtec Electronics | ||
4 | * Ben Dooks <ben@simtec.co.uk> | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License version 2 as | ||
8 | * published by the Free Software Foundation. | ||
9 | * | ||
10 | */ | ||
11 | |||
12 | #include <linux/init.h> | ||
13 | #include <linux/spinlock.h> | ||
14 | #include <linux/workqueue.h> | ||
15 | #include <linux/interrupt.h> | ||
16 | #include <linux/delay.h> | ||
17 | #include <linux/errno.h> | ||
18 | #include <linux/err.h> | ||
19 | #include <linux/clk.h> | ||
20 | #include <linux/platform_device.h> | ||
21 | #include <linux/gpio.h> | ||
22 | #include <linux/io.h> | ||
23 | #include <linux/slab.h> | ||
24 | |||
25 | #include <linux/spi/spi.h> | ||
26 | #include <linux/spi/spi_bitbang.h> | ||
27 | |||
28 | #include <plat/regs-spi.h> | ||
29 | #include <mach/spi.h> | ||
30 | |||
31 | #include <plat/fiq.h> | ||
32 | #include <asm/fiq.h> | ||
33 | |||
34 | #include "spi-s3c24xx-fiq.h" | ||
35 | |||
36 | /** | ||
37 | * s3c24xx_spi_devstate - per device data | ||
38 | * @hz: Last frequency calculated for @sppre field. | ||
39 | * @mode: Last mode setting for the @spcon field. | ||
40 | * @spcon: Value to write to the SPCON register. | ||
41 | * @sppre: Value to write to the SPPRE register. | ||
42 | */ | ||
43 | struct s3c24xx_spi_devstate { | ||
44 | unsigned int hz; | ||
45 | unsigned int mode; | ||
46 | u8 spcon; | ||
47 | u8 sppre; | ||
48 | }; | ||
49 | |||
50 | enum spi_fiq_mode { | ||
51 | FIQ_MODE_NONE = 0, | ||
52 | FIQ_MODE_TX = 1, | ||
53 | FIQ_MODE_RX = 2, | ||
54 | FIQ_MODE_TXRX = 3, | ||
55 | }; | ||
56 | |||
57 | struct s3c24xx_spi { | ||
58 | /* bitbang has to be first */ | ||
59 | struct spi_bitbang bitbang; | ||
60 | struct completion done; | ||
61 | |||
62 | void __iomem *regs; | ||
63 | int irq; | ||
64 | int len; | ||
65 | int count; | ||
66 | |||
67 | struct fiq_handler fiq_handler; | ||
68 | enum spi_fiq_mode fiq_mode; | ||
69 | unsigned char fiq_inuse; | ||
70 | unsigned char fiq_claimed; | ||
71 | |||
72 | void (*set_cs)(struct s3c2410_spi_info *spi, | ||
73 | int cs, int pol); | ||
74 | |||
75 | /* data buffers */ | ||
76 | const unsigned char *tx; | ||
77 | unsigned char *rx; | ||
78 | |||
79 | struct clk *clk; | ||
80 | struct resource *ioarea; | ||
81 | struct spi_master *master; | ||
82 | struct spi_device *curdev; | ||
83 | struct device *dev; | ||
84 | struct s3c2410_spi_info *pdata; | ||
85 | }; | ||
86 | |||
87 | |||
88 | #define SPCON_DEFAULT (S3C2410_SPCON_MSTR | S3C2410_SPCON_SMOD_INT) | ||
89 | #define SPPIN_DEFAULT (S3C2410_SPPIN_KEEP) | ||
90 | |||
91 | static inline struct s3c24xx_spi *to_hw(struct spi_device *sdev) | ||
92 | { | ||
93 | return spi_master_get_devdata(sdev->master); | ||
94 | } | ||
95 | |||
96 | static void s3c24xx_spi_gpiocs(struct s3c2410_spi_info *spi, int cs, int pol) | ||
97 | { | ||
98 | gpio_set_value(spi->pin_cs, pol); | ||
99 | } | ||
100 | |||
101 | static void s3c24xx_spi_chipsel(struct spi_device *spi, int value) | ||
102 | { | ||
103 | struct s3c24xx_spi_devstate *cs = spi->controller_state; | ||
104 | struct s3c24xx_spi *hw = to_hw(spi); | ||
105 | unsigned int cspol = spi->mode & SPI_CS_HIGH ? 1 : 0; | ||
106 | |||
107 | /* change the chipselect state and the state of the spi engine clock */ | ||
108 | |||
109 | switch (value) { | ||
110 | case BITBANG_CS_INACTIVE: | ||
111 | hw->set_cs(hw->pdata, spi->chip_select, cspol^1); | ||
112 | writeb(cs->spcon, hw->regs + S3C2410_SPCON); | ||
113 | break; | ||
114 | |||
115 | case BITBANG_CS_ACTIVE: | ||
116 | writeb(cs->spcon | S3C2410_SPCON_ENSCK, | ||
117 | hw->regs + S3C2410_SPCON); | ||
118 | hw->set_cs(hw->pdata, spi->chip_select, cspol); | ||
119 | break; | ||
120 | } | ||
121 | } | ||
122 | |||
123 | static int s3c24xx_spi_update_state(struct spi_device *spi, | ||
124 | struct spi_transfer *t) | ||
125 | { | ||
126 | struct s3c24xx_spi *hw = to_hw(spi); | ||
127 | struct s3c24xx_spi_devstate *cs = spi->controller_state; | ||
128 | unsigned int bpw; | ||
129 | unsigned int hz; | ||
130 | unsigned int div; | ||
131 | unsigned long clk; | ||
132 | |||
133 | bpw = t ? t->bits_per_word : spi->bits_per_word; | ||
134 | hz = t ? t->speed_hz : spi->max_speed_hz; | ||
135 | |||
136 | if (!bpw) | ||
137 | bpw = 8; | ||
138 | |||
139 | if (!hz) | ||
140 | hz = spi->max_speed_hz; | ||
141 | |||
142 | if (bpw != 8) { | ||
143 | dev_err(&spi->dev, "invalid bits-per-word (%d)\n", bpw); | ||
144 | return -EINVAL; | ||
145 | } | ||
146 | |||
147 | if (spi->mode != cs->mode) { | ||
148 | u8 spcon = SPCON_DEFAULT | S3C2410_SPCON_ENSCK; | ||
149 | |||
150 | if (spi->mode & SPI_CPHA) | ||
151 | spcon |= S3C2410_SPCON_CPHA_FMTB; | ||
152 | |||
153 | if (spi->mode & SPI_CPOL) | ||
154 | spcon |= S3C2410_SPCON_CPOL_HIGH; | ||
155 | |||
156 | cs->mode = spi->mode; | ||
157 | cs->spcon = spcon; | ||
158 | } | ||
159 | |||
160 | if (cs->hz != hz) { | ||
161 | clk = clk_get_rate(hw->clk); | ||
162 | div = DIV_ROUND_UP(clk, hz * 2) - 1; | ||
163 | |||
164 | if (div > 255) | ||
165 | div = 255; | ||
166 | |||
167 | dev_dbg(&spi->dev, "pre-scaler=%d (wanted %d, got %ld)\n", | ||
168 | div, hz, clk / (2 * (div + 1))); | ||
169 | |||
170 | cs->hz = hz; | ||
171 | cs->sppre = div; | ||
172 | } | ||
173 | |||
174 | return 0; | ||
175 | } | ||
176 | |||
177 | static int s3c24xx_spi_setupxfer(struct spi_device *spi, | ||
178 | struct spi_transfer *t) | ||
179 | { | ||
180 | struct s3c24xx_spi_devstate *cs = spi->controller_state; | ||
181 | struct s3c24xx_spi *hw = to_hw(spi); | ||
182 | int ret; | ||
183 | |||
184 | ret = s3c24xx_spi_update_state(spi, t); | ||
185 | if (!ret) | ||
186 | writeb(cs->sppre, hw->regs + S3C2410_SPPRE); | ||
187 | |||
188 | return ret; | ||
189 | } | ||
190 | |||
191 | static int s3c24xx_spi_setup(struct spi_device *spi) | ||
192 | { | ||
193 | struct s3c24xx_spi_devstate *cs = spi->controller_state; | ||
194 | struct s3c24xx_spi *hw = to_hw(spi); | ||
195 | int ret; | ||
196 | |||
197 | /* allocate settings on the first call */ | ||
198 | if (!cs) { | ||
199 | cs = kzalloc(sizeof(struct s3c24xx_spi_devstate), GFP_KERNEL); | ||
200 | if (!cs) { | ||
201 | dev_err(&spi->dev, "no memory for controller state\n"); | ||
202 | return -ENOMEM; | ||
203 | } | ||
204 | |||
205 | cs->spcon = SPCON_DEFAULT; | ||
206 | cs->hz = -1; | ||
207 | spi->controller_state = cs; | ||
208 | } | ||
209 | |||
210 | /* initialise the state from the device */ | ||
211 | ret = s3c24xx_spi_update_state(spi, NULL); | ||
212 | if (ret) | ||
213 | return ret; | ||
214 | |||
215 | spin_lock(&hw->bitbang.lock); | ||
216 | if (!hw->bitbang.busy) { | ||
217 | hw->bitbang.chipselect(spi, BITBANG_CS_INACTIVE); | ||
218 | /* need to ndelay for 0.5 clocktick ? */ | ||
219 | } | ||
220 | spin_unlock(&hw->bitbang.lock); | ||
221 | |||
222 | return 0; | ||
223 | } | ||
224 | |||
225 | static void s3c24xx_spi_cleanup(struct spi_device *spi) | ||
226 | { | ||
227 | kfree(spi->controller_state); | ||
228 | } | ||
229 | |||
230 | static inline unsigned int hw_txbyte(struct s3c24xx_spi *hw, int count) | ||
231 | { | ||
232 | return hw->tx ? hw->tx[count] : 0; | ||
233 | } | ||
234 | |||
235 | #ifdef CONFIG_SPI_S3C24XX_FIQ | ||
236 | /* Support for FIQ based pseudo-DMA to improve the transfer speed. | ||
237 | * | ||
238 | * This code uses the assembly helper in spi_s3c24xx_spi.S which is | ||
239 | * used by the FIQ core to move data between main memory and the peripheral | ||
240 | * block. Since this is code running on the processor, there is no problem | ||
241 | * with cache coherency of the buffers, so we can use any buffer we like. | ||
242 | */ | ||
243 | |||
244 | /** | ||
245 | * struct spi_fiq_code - FIQ code and header | ||
246 | * @length: The length of the code fragment, excluding this header. | ||
247 | * @ack_offset: The offset from @data to the word to place the IRQ ACK bit at. | ||
248 | * @data: The code itself to install as a FIQ handler. | ||
249 | */ | ||
250 | struct spi_fiq_code { | ||
251 | u32 length; | ||
252 | u32 ack_offset; | ||
253 | u8 data[0]; | ||
254 | }; | ||
255 | |||
256 | extern struct spi_fiq_code s3c24xx_spi_fiq_txrx; | ||
257 | extern struct spi_fiq_code s3c24xx_spi_fiq_tx; | ||
258 | extern struct spi_fiq_code s3c24xx_spi_fiq_rx; | ||
259 | |||
260 | /** | ||
261 | * ack_bit - turn IRQ into IRQ acknowledgement bit | ||
262 | * @irq: The interrupt number | ||
263 | * | ||
264 | * Returns the bit to write to the interrupt acknowledge register. | ||
265 | */ | ||
266 | static inline u32 ack_bit(unsigned int irq) | ||
267 | { | ||
268 | return 1 << (irq - IRQ_EINT0); | ||
269 | } | ||
270 | |||
271 | /** | ||
272 | * s3c24xx_spi_tryfiq - attempt to claim and setup FIQ for transfer | ||
273 | * @hw: The hardware state. | ||
274 | * | ||
275 | * Claim the FIQ handler (only one can be active at any one time) and | ||
276 | * then setup the correct transfer code for this transfer. | ||
277 | * | ||
278 | * This call updates all the necessary state information if successful, | ||
279 | * so the caller does not need to do anything more than start the transfer | ||
280 | * as normal, since the IRQ will have been re-routed to the FIQ handler. | ||
281 | */ | ||
282 | void s3c24xx_spi_tryfiq(struct s3c24xx_spi *hw) | ||
283 | { | ||
284 | struct pt_regs regs; | ||
285 | enum spi_fiq_mode mode; | ||
286 | struct spi_fiq_code *code; | ||
287 | int ret; | ||
288 | |||
289 | if (!hw->fiq_claimed) { | ||
290 | /* try and claim fiq if we haven't got it, and if not | ||
291 | * then return and simply use another transfer method */ | ||
292 | |||
293 | ret = claim_fiq(&hw->fiq_handler); | ||
294 | if (ret) | ||
295 | return; | ||
296 | } | ||
297 | |||
298 | if (hw->tx && !hw->rx) | ||
299 | mode = FIQ_MODE_TX; | ||
300 | else if (hw->rx && !hw->tx) | ||
301 | mode = FIQ_MODE_RX; | ||
302 | else | ||
303 | mode = FIQ_MODE_TXRX; | ||
304 | |||
305 | regs.uregs[fiq_rspi] = (long)hw->regs; | ||
306 | regs.uregs[fiq_rrx] = (long)hw->rx; | ||
307 | regs.uregs[fiq_rtx] = (long)hw->tx + 1; | ||
308 | regs.uregs[fiq_rcount] = hw->len - 1; | ||
309 | regs.uregs[fiq_rirq] = (long)S3C24XX_VA_IRQ; | ||
310 | |||
311 | set_fiq_regs(®s); | ||
312 | |||
313 | if (hw->fiq_mode != mode) { | ||
314 | u32 *ack_ptr; | ||
315 | |||
316 | hw->fiq_mode = mode; | ||
317 | |||
318 | switch (mode) { | ||
319 | case FIQ_MODE_TX: | ||
320 | code = &s3c24xx_spi_fiq_tx; | ||
321 | break; | ||
322 | case FIQ_MODE_RX: | ||
323 | code = &s3c24xx_spi_fiq_rx; | ||
324 | break; | ||
325 | case FIQ_MODE_TXRX: | ||
326 | code = &s3c24xx_spi_fiq_txrx; | ||
327 | break; | ||
328 | default: | ||
329 | code = NULL; | ||
330 | } | ||
331 | |||
332 | BUG_ON(!code); | ||
333 | |||
334 | ack_ptr = (u32 *)&code->data[code->ack_offset]; | ||
335 | *ack_ptr = ack_bit(hw->irq); | ||
336 | |||
337 | set_fiq_handler(&code->data, code->length); | ||
338 | } | ||
339 | |||
340 | s3c24xx_set_fiq(hw->irq, true); | ||
341 | |||
342 | hw->fiq_mode = mode; | ||
343 | hw->fiq_inuse = 1; | ||
344 | } | ||
345 | |||
346 | /** | ||
347 | * s3c24xx_spi_fiqop - FIQ core code callback | ||
348 | * @pw: Data registered with the handler | ||
349 | * @release: Whether this is a release or a return. | ||
350 | * | ||
351 | * Called by the FIQ code when another module wants to use the FIQ, so | ||
352 | * return whether we are currently using this or not and then update our | ||
353 | * internal state. | ||
354 | */ | ||
355 | static int s3c24xx_spi_fiqop(void *pw, int release) | ||
356 | { | ||
357 | struct s3c24xx_spi *hw = pw; | ||
358 | int ret = 0; | ||
359 | |||
360 | if (release) { | ||
361 | if (hw->fiq_inuse) | ||
362 | ret = -EBUSY; | ||
363 | |||
364 | /* note, we do not need to unroute the FIQ, as the FIQ | ||
365 | * vector code de-routes it to signal the end of transfer */ | ||
366 | |||
367 | hw->fiq_mode = FIQ_MODE_NONE; | ||
368 | hw->fiq_claimed = 0; | ||
369 | } else { | ||
370 | hw->fiq_claimed = 1; | ||
371 | } | ||
372 | |||
373 | return ret; | ||
374 | } | ||
375 | |||
376 | /** | ||
377 | * s3c24xx_spi_initfiq - setup the information for the FIQ core | ||
378 | * @hw: The hardware state. | ||
379 | * | ||
380 | * Setup the fiq_handler block to pass to the FIQ core. | ||
381 | */ | ||
382 | static inline void s3c24xx_spi_initfiq(struct s3c24xx_spi *hw) | ||
383 | { | ||
384 | hw->fiq_handler.dev_id = hw; | ||
385 | hw->fiq_handler.name = dev_name(hw->dev); | ||
386 | hw->fiq_handler.fiq_op = s3c24xx_spi_fiqop; | ||
387 | } | ||
388 | |||
389 | /** | ||
390 | * s3c24xx_spi_usefiq - return if we should be using FIQ. | ||
391 | * @hw: The hardware state. | ||
392 | * | ||
393 | * Return true if the platform data specifies whether this channel is | ||
394 | * allowed to use the FIQ. | ||
395 | */ | ||
396 | static inline bool s3c24xx_spi_usefiq(struct s3c24xx_spi *hw) | ||
397 | { | ||
398 | return hw->pdata->use_fiq; | ||
399 | } | ||
400 | |||
401 | /** | ||
402 | * s3c24xx_spi_usingfiq - return if channel is using FIQ | ||
403 | * @spi: The hardware state. | ||
404 | * | ||
405 | * Return whether the channel is currently using the FIQ (separate from | ||
406 | * whether the FIQ is claimed). | ||
407 | */ | ||
408 | static inline bool s3c24xx_spi_usingfiq(struct s3c24xx_spi *spi) | ||
409 | { | ||
410 | return spi->fiq_inuse; | ||
411 | } | ||
412 | #else | ||
413 | |||
414 | static inline void s3c24xx_spi_initfiq(struct s3c24xx_spi *s) { } | ||
415 | static inline void s3c24xx_spi_tryfiq(struct s3c24xx_spi *s) { } | ||
416 | static inline bool s3c24xx_spi_usefiq(struct s3c24xx_spi *s) { return false; } | ||
417 | static inline bool s3c24xx_spi_usingfiq(struct s3c24xx_spi *s) { return false; } | ||
418 | |||
419 | #endif /* CONFIG_SPI_S3C24XX_FIQ */ | ||
420 | |||
421 | static int s3c24xx_spi_txrx(struct spi_device *spi, struct spi_transfer *t) | ||
422 | { | ||
423 | struct s3c24xx_spi *hw = to_hw(spi); | ||
424 | |||
425 | hw->tx = t->tx_buf; | ||
426 | hw->rx = t->rx_buf; | ||
427 | hw->len = t->len; | ||
428 | hw->count = 0; | ||
429 | |||
430 | init_completion(&hw->done); | ||
431 | |||
432 | hw->fiq_inuse = 0; | ||
433 | if (s3c24xx_spi_usefiq(hw) && t->len >= 3) | ||
434 | s3c24xx_spi_tryfiq(hw); | ||
435 | |||
436 | /* send the first byte */ | ||
437 | writeb(hw_txbyte(hw, 0), hw->regs + S3C2410_SPTDAT); | ||
438 | |||
439 | wait_for_completion(&hw->done); | ||
440 | return hw->count; | ||
441 | } | ||
442 | |||
443 | static irqreturn_t s3c24xx_spi_irq(int irq, void *dev) | ||
444 | { | ||
445 | struct s3c24xx_spi *hw = dev; | ||
446 | unsigned int spsta = readb(hw->regs + S3C2410_SPSTA); | ||
447 | unsigned int count = hw->count; | ||
448 | |||
449 | if (spsta & S3C2410_SPSTA_DCOL) { | ||
450 | dev_dbg(hw->dev, "data-collision\n"); | ||
451 | complete(&hw->done); | ||
452 | goto irq_done; | ||
453 | } | ||
454 | |||
455 | if (!(spsta & S3C2410_SPSTA_READY)) { | ||
456 | dev_dbg(hw->dev, "spi not ready for tx?\n"); | ||
457 | complete(&hw->done); | ||
458 | goto irq_done; | ||
459 | } | ||
460 | |||
461 | if (!s3c24xx_spi_usingfiq(hw)) { | ||
462 | hw->count++; | ||
463 | |||
464 | if (hw->rx) | ||
465 | hw->rx[count] = readb(hw->regs + S3C2410_SPRDAT); | ||
466 | |||
467 | count++; | ||
468 | |||
469 | if (count < hw->len) | ||
470 | writeb(hw_txbyte(hw, count), hw->regs + S3C2410_SPTDAT); | ||
471 | else | ||
472 | complete(&hw->done); | ||
473 | } else { | ||
474 | hw->count = hw->len; | ||
475 | hw->fiq_inuse = 0; | ||
476 | |||
477 | if (hw->rx) | ||
478 | hw->rx[hw->len-1] = readb(hw->regs + S3C2410_SPRDAT); | ||
479 | |||
480 | complete(&hw->done); | ||
481 | } | ||
482 | |||
483 | irq_done: | ||
484 | return IRQ_HANDLED; | ||
485 | } | ||
486 | |||
487 | static void s3c24xx_spi_initialsetup(struct s3c24xx_spi *hw) | ||
488 | { | ||
489 | /* for the moment, permanently enable the clock */ | ||
490 | |||
491 | clk_enable(hw->clk); | ||
492 | |||
493 | /* program defaults into the registers */ | ||
494 | |||
495 | writeb(0xff, hw->regs + S3C2410_SPPRE); | ||
496 | writeb(SPPIN_DEFAULT, hw->regs + S3C2410_SPPIN); | ||
497 | writeb(SPCON_DEFAULT, hw->regs + S3C2410_SPCON); | ||
498 | |||
499 | if (hw->pdata) { | ||
500 | if (hw->set_cs == s3c24xx_spi_gpiocs) | ||
501 | gpio_direction_output(hw->pdata->pin_cs, 1); | ||
502 | |||
503 | if (hw->pdata->gpio_setup) | ||
504 | hw->pdata->gpio_setup(hw->pdata, 1); | ||
505 | } | ||
506 | } | ||
507 | |||
508 | static int __init s3c24xx_spi_probe(struct platform_device *pdev) | ||
509 | { | ||
510 | struct s3c2410_spi_info *pdata; | ||
511 | struct s3c24xx_spi *hw; | ||
512 | struct spi_master *master; | ||
513 | struct resource *res; | ||
514 | int err = 0; | ||
515 | |||
516 | master = spi_alloc_master(&pdev->dev, sizeof(struct s3c24xx_spi)); | ||
517 | if (master == NULL) { | ||
518 | dev_err(&pdev->dev, "No memory for spi_master\n"); | ||
519 | err = -ENOMEM; | ||
520 | goto err_nomem; | ||
521 | } | ||
522 | |||
523 | hw = spi_master_get_devdata(master); | ||
524 | memset(hw, 0, sizeof(struct s3c24xx_spi)); | ||
525 | |||
526 | hw->master = spi_master_get(master); | ||
527 | hw->pdata = pdata = pdev->dev.platform_data; | ||
528 | hw->dev = &pdev->dev; | ||
529 | |||
530 | if (pdata == NULL) { | ||
531 | dev_err(&pdev->dev, "No platform data supplied\n"); | ||
532 | err = -ENOENT; | ||
533 | goto err_no_pdata; | ||
534 | } | ||
535 | |||
536 | platform_set_drvdata(pdev, hw); | ||
537 | init_completion(&hw->done); | ||
538 | |||
539 | /* initialise fiq handler */ | ||
540 | |||
541 | s3c24xx_spi_initfiq(hw); | ||
542 | |||
543 | /* setup the master state. */ | ||
544 | |||
545 | /* the spi->mode bits understood by this driver: */ | ||
546 | master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH; | ||
547 | |||
548 | master->num_chipselect = hw->pdata->num_cs; | ||
549 | master->bus_num = pdata->bus_num; | ||
550 | |||
551 | /* setup the state for the bitbang driver */ | ||
552 | |||
553 | hw->bitbang.master = hw->master; | ||
554 | hw->bitbang.setup_transfer = s3c24xx_spi_setupxfer; | ||
555 | hw->bitbang.chipselect = s3c24xx_spi_chipsel; | ||
556 | hw->bitbang.txrx_bufs = s3c24xx_spi_txrx; | ||
557 | |||
558 | hw->master->setup = s3c24xx_spi_setup; | ||
559 | hw->master->cleanup = s3c24xx_spi_cleanup; | ||
560 | |||
561 | dev_dbg(hw->dev, "bitbang at %p\n", &hw->bitbang); | ||
562 | |||
563 | /* find and map our resources */ | ||
564 | |||
565 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
566 | if (res == NULL) { | ||
567 | dev_err(&pdev->dev, "Cannot get IORESOURCE_MEM\n"); | ||
568 | err = -ENOENT; | ||
569 | goto err_no_iores; | ||
570 | } | ||
571 | |||
572 | hw->ioarea = request_mem_region(res->start, resource_size(res), | ||
573 | pdev->name); | ||
574 | |||
575 | if (hw->ioarea == NULL) { | ||
576 | dev_err(&pdev->dev, "Cannot reserve region\n"); | ||
577 | err = -ENXIO; | ||
578 | goto err_no_iores; | ||
579 | } | ||
580 | |||
581 | hw->regs = ioremap(res->start, resource_size(res)); | ||
582 | if (hw->regs == NULL) { | ||
583 | dev_err(&pdev->dev, "Cannot map IO\n"); | ||
584 | err = -ENXIO; | ||
585 | goto err_no_iomap; | ||
586 | } | ||
587 | |||
588 | hw->irq = platform_get_irq(pdev, 0); | ||
589 | if (hw->irq < 0) { | ||
590 | dev_err(&pdev->dev, "No IRQ specified\n"); | ||
591 | err = -ENOENT; | ||
592 | goto err_no_irq; | ||
593 | } | ||
594 | |||
595 | err = request_irq(hw->irq, s3c24xx_spi_irq, 0, pdev->name, hw); | ||
596 | if (err) { | ||
597 | dev_err(&pdev->dev, "Cannot claim IRQ\n"); | ||
598 | goto err_no_irq; | ||
599 | } | ||
600 | |||
601 | hw->clk = clk_get(&pdev->dev, "spi"); | ||
602 | if (IS_ERR(hw->clk)) { | ||
603 | dev_err(&pdev->dev, "No clock for device\n"); | ||
604 | err = PTR_ERR(hw->clk); | ||
605 | goto err_no_clk; | ||
606 | } | ||
607 | |||
608 | /* setup any gpio we can */ | ||
609 | |||
610 | if (!pdata->set_cs) { | ||
611 | if (pdata->pin_cs < 0) { | ||
612 | dev_err(&pdev->dev, "No chipselect pin\n"); | ||
613 | goto err_register; | ||
614 | } | ||
615 | |||
616 | err = gpio_request(pdata->pin_cs, dev_name(&pdev->dev)); | ||
617 | if (err) { | ||
618 | dev_err(&pdev->dev, "Failed to get gpio for cs\n"); | ||
619 | goto err_register; | ||
620 | } | ||
621 | |||
622 | hw->set_cs = s3c24xx_spi_gpiocs; | ||
623 | gpio_direction_output(pdata->pin_cs, 1); | ||
624 | } else | ||
625 | hw->set_cs = pdata->set_cs; | ||
626 | |||
627 | s3c24xx_spi_initialsetup(hw); | ||
628 | |||
629 | /* register our spi controller */ | ||
630 | |||
631 | err = spi_bitbang_start(&hw->bitbang); | ||
632 | if (err) { | ||
633 | dev_err(&pdev->dev, "Failed to register SPI master\n"); | ||
634 | goto err_register; | ||
635 | } | ||
636 | |||
637 | return 0; | ||
638 | |||
639 | err_register: | ||
640 | if (hw->set_cs == s3c24xx_spi_gpiocs) | ||
641 | gpio_free(pdata->pin_cs); | ||
642 | |||
643 | clk_disable(hw->clk); | ||
644 | clk_put(hw->clk); | ||
645 | |||
646 | err_no_clk: | ||
647 | free_irq(hw->irq, hw); | ||
648 | |||
649 | err_no_irq: | ||
650 | iounmap(hw->regs); | ||
651 | |||
652 | err_no_iomap: | ||
653 | release_resource(hw->ioarea); | ||
654 | kfree(hw->ioarea); | ||
655 | |||
656 | err_no_iores: | ||
657 | err_no_pdata: | ||
658 | spi_master_put(hw->master); | ||
659 | |||
660 | err_nomem: | ||
661 | return err; | ||
662 | } | ||
663 | |||
664 | static int __exit s3c24xx_spi_remove(struct platform_device *dev) | ||
665 | { | ||
666 | struct s3c24xx_spi *hw = platform_get_drvdata(dev); | ||
667 | |||
668 | platform_set_drvdata(dev, NULL); | ||
669 | |||
670 | spi_bitbang_stop(&hw->bitbang); | ||
671 | |||
672 | clk_disable(hw->clk); | ||
673 | clk_put(hw->clk); | ||
674 | |||
675 | free_irq(hw->irq, hw); | ||
676 | iounmap(hw->regs); | ||
677 | |||
678 | if (hw->set_cs == s3c24xx_spi_gpiocs) | ||
679 | gpio_free(hw->pdata->pin_cs); | ||
680 | |||
681 | release_resource(hw->ioarea); | ||
682 | kfree(hw->ioarea); | ||
683 | |||
684 | spi_master_put(hw->master); | ||
685 | return 0; | ||
686 | } | ||
687 | |||
688 | |||
689 | #ifdef CONFIG_PM | ||
690 | |||
691 | static int s3c24xx_spi_suspend(struct device *dev) | ||
692 | { | ||
693 | struct s3c24xx_spi *hw = platform_get_drvdata(to_platform_device(dev)); | ||
694 | |||
695 | if (hw->pdata && hw->pdata->gpio_setup) | ||
696 | hw->pdata->gpio_setup(hw->pdata, 0); | ||
697 | |||
698 | clk_disable(hw->clk); | ||
699 | return 0; | ||
700 | } | ||
701 | |||
702 | static int s3c24xx_spi_resume(struct device *dev) | ||
703 | { | ||
704 | struct s3c24xx_spi *hw = platform_get_drvdata(to_platform_device(dev)); | ||
705 | |||
706 | s3c24xx_spi_initialsetup(hw); | ||
707 | return 0; | ||
708 | } | ||
709 | |||
710 | static const struct dev_pm_ops s3c24xx_spi_pmops = { | ||
711 | .suspend = s3c24xx_spi_suspend, | ||
712 | .resume = s3c24xx_spi_resume, | ||
713 | }; | ||
714 | |||
715 | #define S3C24XX_SPI_PMOPS &s3c24xx_spi_pmops | ||
716 | #else | ||
717 | #define S3C24XX_SPI_PMOPS NULL | ||
718 | #endif /* CONFIG_PM */ | ||
719 | |||
720 | MODULE_ALIAS("platform:s3c2410-spi"); | ||
721 | static struct platform_driver s3c24xx_spi_driver = { | ||
722 | .remove = __exit_p(s3c24xx_spi_remove), | ||
723 | .driver = { | ||
724 | .name = "s3c2410-spi", | ||
725 | .owner = THIS_MODULE, | ||
726 | .pm = S3C24XX_SPI_PMOPS, | ||
727 | }, | ||
728 | }; | ||
729 | |||
730 | static int __init s3c24xx_spi_init(void) | ||
731 | { | ||
732 | return platform_driver_probe(&s3c24xx_spi_driver, s3c24xx_spi_probe); | ||
733 | } | ||
734 | |||
735 | static void __exit s3c24xx_spi_exit(void) | ||
736 | { | ||
737 | platform_driver_unregister(&s3c24xx_spi_driver); | ||
738 | } | ||
739 | |||
740 | module_init(s3c24xx_spi_init); | ||
741 | module_exit(s3c24xx_spi_exit); | ||
742 | |||
743 | MODULE_DESCRIPTION("S3C24XX SPI Driver"); | ||
744 | MODULE_AUTHOR("Ben Dooks, <ben@simtec.co.uk>"); | ||
745 | MODULE_LICENSE("GPL"); | ||