blob: d6f51695ca5b20ec6363501c5922639d187e6189 [file] [log] [blame]
Thomas Gleixnerd2912cb2019-06-04 10:11:33 +02001// SPDX-License-Identifier: GPL-2.0-only
Grant Likelyca632f52011-06-06 01:16:30 -06002/*
Ben Dooks7fba5342006-05-20 15:00:18 -07003 * Copyright (c) 2006 Ben Dooks
Ben Dooksbec08062009-12-14 22:20:24 -08004 * Copyright 2006-2009 Simtec Electronics
Ben Dooks7fba5342006-05-20 15:00:18 -07005 * Ben Dooks <ben@simtec.co.uk>
Ben Dooks7fba5342006-05-20 15:00:18 -07006*/
7
Ben Dooks7fba5342006-05-20 15:00:18 -07008#include <linux/spinlock.h>
Ben Dooks7fba5342006-05-20 15:00:18 -07009#include <linux/interrupt.h>
10#include <linux/delay.h>
11#include <linux/errno.h>
12#include <linux/err.h>
13#include <linux/clk.h>
14#include <linux/platform_device.h>
Ben Dooksee9c1fb2009-01-06 14:41:44 -080015#include <linux/gpio.h>
Ben Dooks1a0c2202009-09-22 16:46:12 -070016#include <linux/io.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090017#include <linux/slab.h>
Ben Dooks7fba5342006-05-20 15:00:18 -070018
19#include <linux/spi/spi.h>
20#include <linux/spi/spi_bitbang.h>
Heiko Stuebnerf35ef7c2012-01-31 20:06:07 +090021#include <linux/spi/s3c24xx.h>
Arnd Bergmannf131a442019-09-03 11:31:09 +020022#include <linux/spi/s3c24xx-fiq.h>
Paul Gortmakerd7614de2011-07-03 15:44:29 -040023#include <linux/module.h>
Ben Dooks7fba5342006-05-20 15:00:18 -070024
Ben Dooksbec08062009-12-14 22:20:24 -080025#include <asm/fiq.h>
26
Arnd Bergmann0144e3f2020-08-06 20:20:37 +020027#include "spi-s3c24xx-regs.h"
Ben Dooksbec08062009-12-14 22:20:24 -080028
Ben Dooks570327d2009-09-22 16:46:14 -070029/**
Krzysztof Kozlowskie1cc0382020-08-04 17:13:56 +020030 * struct s3c24xx_spi_devstate - per device data
Ben Dooks570327d2009-09-22 16:46:14 -070031 * @hz: Last frequency calculated for @sppre field.
32 * @mode: Last mode setting for the @spcon field.
33 * @spcon: Value to write to the SPCON register.
34 * @sppre: Value to write to the SPPRE register.
35 */
36struct s3c24xx_spi_devstate {
37 unsigned int hz;
38 unsigned int mode;
39 u8 spcon;
40 u8 sppre;
41};
42
Ben Dooksbec08062009-12-14 22:20:24 -080043enum spi_fiq_mode {
44 FIQ_MODE_NONE = 0,
45 FIQ_MODE_TX = 1,
46 FIQ_MODE_RX = 2,
47 FIQ_MODE_TXRX = 3,
48};
49
Ben Dooks7fba5342006-05-20 15:00:18 -070050struct s3c24xx_spi {
51 /* bitbang has to be first */
52 struct spi_bitbang bitbang;
53 struct completion done;
54
55 void __iomem *regs;
56 int irq;
57 int len;
58 int count;
59
Ben Dooksbec08062009-12-14 22:20:24 -080060 struct fiq_handler fiq_handler;
61 enum spi_fiq_mode fiq_mode;
62 unsigned char fiq_inuse;
63 unsigned char fiq_claimed;
64
Arnaud Patard (Rtp6c912a32007-03-16 13:38:36 -080065 void (*set_cs)(struct s3c2410_spi_info *spi,
Ben Dooks8736b922007-01-26 00:56:43 -080066 int cs, int pol);
67
Ben Dooks7fba5342006-05-20 15:00:18 -070068 /* data buffers */
69 const unsigned char *tx;
70 unsigned char *rx;
71
72 struct clk *clk;
Ben Dooks7fba5342006-05-20 15:00:18 -070073 struct spi_master *master;
74 struct spi_device *curdev;
75 struct device *dev;
76 struct s3c2410_spi_info *pdata;
77};
78
79#define SPCON_DEFAULT (S3C2410_SPCON_MSTR | S3C2410_SPCON_SMOD_INT)
80#define SPPIN_DEFAULT (S3C2410_SPPIN_KEEP)
81
82static inline struct s3c24xx_spi *to_hw(struct spi_device *sdev)
83{
84 return spi_master_get_devdata(sdev->master);
85}
86
Ben Dooks8736b922007-01-26 00:56:43 -080087static void s3c24xx_spi_gpiocs(struct s3c2410_spi_info *spi, int cs, int pol)
88{
Ben Dooksee9c1fb2009-01-06 14:41:44 -080089 gpio_set_value(spi->pin_cs, pol);
Ben Dooks8736b922007-01-26 00:56:43 -080090}
91
Ben Dooks7fba5342006-05-20 15:00:18 -070092static void s3c24xx_spi_chipsel(struct spi_device *spi, int value)
93{
Ben Dooks570327d2009-09-22 16:46:14 -070094 struct s3c24xx_spi_devstate *cs = spi->controller_state;
Ben Dooks7fba5342006-05-20 15:00:18 -070095 struct s3c24xx_spi *hw = to_hw(spi);
96 unsigned int cspol = spi->mode & SPI_CS_HIGH ? 1 : 0;
Ben Dooks570327d2009-09-22 16:46:14 -070097
98 /* change the chipselect state and the state of the spi engine clock */
Ben Dooks7fba5342006-05-20 15:00:18 -070099
100 switch (value) {
101 case BITBANG_CS_INACTIVE:
Ben Dooks3d2c5b42007-04-16 22:53:22 -0700102 hw->set_cs(hw->pdata, spi->chip_select, cspol^1);
Ben Dooks570327d2009-09-22 16:46:14 -0700103 writeb(cs->spcon, hw->regs + S3C2410_SPCON);
Ben Dooks7fba5342006-05-20 15:00:18 -0700104 break;
105
106 case BITBANG_CS_ACTIVE:
Ben Dooks570327d2009-09-22 16:46:14 -0700107 writeb(cs->spcon | S3C2410_SPCON_ENSCK,
108 hw->regs + S3C2410_SPCON);
Ben Dooks3d2c5b42007-04-16 22:53:22 -0700109 hw->set_cs(hw->pdata, spi->chip_select, cspol);
Ben Dooks7fba5342006-05-20 15:00:18 -0700110 break;
Ben Dooks7fba5342006-05-20 15:00:18 -0700111 }
112}
113
Ben Dooks570327d2009-09-22 16:46:14 -0700114static int s3c24xx_spi_update_state(struct spi_device *spi,
115 struct spi_transfer *t)
Ben Dooks7fba5342006-05-20 15:00:18 -0700116{
117 struct s3c24xx_spi *hw = to_hw(spi);
Ben Dooks570327d2009-09-22 16:46:14 -0700118 struct s3c24xx_spi_devstate *cs = spi->controller_state;
Ben Dooks7fba5342006-05-20 15:00:18 -0700119 unsigned int hz;
120 unsigned int div;
Ben Dooksb8978782009-08-18 14:11:16 -0700121 unsigned long clk;
Ben Dooks7fba5342006-05-20 15:00:18 -0700122
Ben Dooks7fba5342006-05-20 15:00:18 -0700123 hz = t ? t->speed_hz : spi->max_speed_hz;
124
Ben Dooks19152972009-08-18 14:11:17 -0700125 if (!hz)
126 hz = spi->max_speed_hz;
127
Ben Dooks570327d2009-09-22 16:46:14 -0700128 if (spi->mode != cs->mode) {
Ben Dooksbec08062009-12-14 22:20:24 -0800129 u8 spcon = SPCON_DEFAULT | S3C2410_SPCON_ENSCK;
Ben Dooks7fba5342006-05-20 15:00:18 -0700130
Ben Dooks570327d2009-09-22 16:46:14 -0700131 if (spi->mode & SPI_CPHA)
132 spcon |= S3C2410_SPCON_CPHA_FMTB;
Ben Dooks7fba5342006-05-20 15:00:18 -0700133
Ben Dooks570327d2009-09-22 16:46:14 -0700134 if (spi->mode & SPI_CPOL)
135 spcon |= S3C2410_SPCON_CPOL_HIGH;
Ben Dooksb8978782009-08-18 14:11:16 -0700136
Ben Dooks570327d2009-09-22 16:46:14 -0700137 cs->mode = spi->mode;
138 cs->spcon = spcon;
139 }
Ben Dooksb8978782009-08-18 14:11:16 -0700140
Ben Dooks570327d2009-09-22 16:46:14 -0700141 if (cs->hz != hz) {
142 clk = clk_get_rate(hw->clk);
143 div = DIV_ROUND_UP(clk, hz * 2) - 1;
144
145 if (div > 255)
146 div = 255;
147
148 dev_dbg(&spi->dev, "pre-scaler=%d (wanted %d, got %ld)\n",
149 div, hz, clk / (2 * (div + 1)));
150
151 cs->hz = hz;
152 cs->sppre = div;
153 }
154
155 return 0;
156}
157
158static int s3c24xx_spi_setupxfer(struct spi_device *spi,
159 struct spi_transfer *t)
160{
161 struct s3c24xx_spi_devstate *cs = spi->controller_state;
162 struct s3c24xx_spi *hw = to_hw(spi);
163 int ret;
164
165 ret = s3c24xx_spi_update_state(spi, t);
166 if (!ret)
167 writeb(cs->sppre, hw->regs + S3C2410_SPPRE);
168
169 return ret;
170}
171
172static int s3c24xx_spi_setup(struct spi_device *spi)
173{
174 struct s3c24xx_spi_devstate *cs = spi->controller_state;
175 struct s3c24xx_spi *hw = to_hw(spi);
176 int ret;
177
178 /* allocate settings on the first call */
179 if (!cs) {
Axel Linc586feb2014-03-31 11:37:29 +0800180 cs = devm_kzalloc(&spi->dev,
181 sizeof(struct s3c24xx_spi_devstate),
182 GFP_KERNEL);
Jingoo Han0375cff2014-04-29 17:20:02 +0900183 if (!cs)
Ben Dooks570327d2009-09-22 16:46:14 -0700184 return -ENOMEM;
Ben Dooks570327d2009-09-22 16:46:14 -0700185
186 cs->spcon = SPCON_DEFAULT;
187 cs->hz = -1;
188 spi->controller_state = cs;
189 }
190
191 /* initialise the state from the device */
192 ret = s3c24xx_spi_update_state(spi, NULL);
193 if (ret)
194 return ret;
Ben Dooks7fba5342006-05-20 15:00:18 -0700195
Nicolas Boichatc15f6ed2015-08-17 11:52:54 +0800196 mutex_lock(&hw->bitbang.lock);
Ben Dooks7fba5342006-05-20 15:00:18 -0700197 if (!hw->bitbang.busy) {
198 hw->bitbang.chipselect(spi, BITBANG_CS_INACTIVE);
199 /* need to ndelay for 0.5 clocktick ? */
200 }
Nicolas Boichatc15f6ed2015-08-17 11:52:54 +0800201 mutex_unlock(&hw->bitbang.lock);
Ben Dooks7fba5342006-05-20 15:00:18 -0700202
203 return 0;
204}
205
Ben Dooks7fba5342006-05-20 15:00:18 -0700206static inline unsigned int hw_txbyte(struct s3c24xx_spi *hw, int count)
207{
David Brownell4b1badf2006-12-29 16:48:39 -0800208 return hw->tx ? hw->tx[count] : 0;
Ben Dooks7fba5342006-05-20 15:00:18 -0700209}
210
Ben Dooksbec08062009-12-14 22:20:24 -0800211#ifdef CONFIG_SPI_S3C24XX_FIQ
212/* Support for FIQ based pseudo-DMA to improve the transfer speed.
213 *
214 * This code uses the assembly helper in spi_s3c24xx_spi.S which is
215 * used by the FIQ core to move data between main memory and the peripheral
216 * block. Since this is code running on the processor, there is no problem
217 * with cache coherency of the buffers, so we can use any buffer we like.
218 */
219
220/**
221 * struct spi_fiq_code - FIQ code and header
222 * @length: The length of the code fragment, excluding this header.
223 * @ack_offset: The offset from @data to the word to place the IRQ ACK bit at.
224 * @data: The code itself to install as a FIQ handler.
225 */
226struct spi_fiq_code {
227 u32 length;
228 u32 ack_offset;
Gustavo A. R. Silva2d4ccc22020-03-20 18:25:56 -0500229 u8 data[];
Ben Dooksbec08062009-12-14 22:20:24 -0800230};
231
Ben Dooksbec08062009-12-14 22:20:24 -0800232/**
233 * s3c24xx_spi_tryfiq - attempt to claim and setup FIQ for transfer
234 * @hw: The hardware state.
235 *
236 * Claim the FIQ handler (only one can be active at any one time) and
237 * then setup the correct transfer code for this transfer.
238 *
Daniel Mack3ad2f3fb2010-02-03 08:01:28 +0800239 * This call updates all the necessary state information if successful,
Ben Dooksbec08062009-12-14 22:20:24 -0800240 * so the caller does not need to do anything more than start the transfer
241 * as normal, since the IRQ will have been re-routed to the FIQ handler.
242*/
Sachin Kamatcfeb3312013-09-10 11:20:13 +0530243static void s3c24xx_spi_tryfiq(struct s3c24xx_spi *hw)
Ben Dooksbec08062009-12-14 22:20:24 -0800244{
245 struct pt_regs regs;
246 enum spi_fiq_mode mode;
247 struct spi_fiq_code *code;
Arnd Bergmanncd4bd8f2020-08-06 20:20:48 +0200248 u32 *ack_ptr = NULL;
Ben Dooksbec08062009-12-14 22:20:24 -0800249 int ret;
250
251 if (!hw->fiq_claimed) {
252 /* try and claim fiq if we haven't got it, and if not
253 * then return and simply use another transfer method */
254
255 ret = claim_fiq(&hw->fiq_handler);
256 if (ret)
257 return;
258 }
259
260 if (hw->tx && !hw->rx)
261 mode = FIQ_MODE_TX;
262 else if (hw->rx && !hw->tx)
263 mode = FIQ_MODE_RX;
264 else
265 mode = FIQ_MODE_TXRX;
266
267 regs.uregs[fiq_rspi] = (long)hw->regs;
268 regs.uregs[fiq_rrx] = (long)hw->rx;
269 regs.uregs[fiq_rtx] = (long)hw->tx + 1;
270 regs.uregs[fiq_rcount] = hw->len - 1;
Ben Dooksbec08062009-12-14 22:20:24 -0800271
272 set_fiq_regs(&regs);
273
274 if (hw->fiq_mode != mode) {
Ben Dooksbec08062009-12-14 22:20:24 -0800275 hw->fiq_mode = mode;
276
277 switch (mode) {
278 case FIQ_MODE_TX:
279 code = &s3c24xx_spi_fiq_tx;
280 break;
281 case FIQ_MODE_RX:
282 code = &s3c24xx_spi_fiq_rx;
283 break;
284 case FIQ_MODE_TXRX:
285 code = &s3c24xx_spi_fiq_txrx;
286 break;
287 default:
288 code = NULL;
289 }
290
291 BUG_ON(!code);
292
293 ack_ptr = (u32 *)&code->data[code->ack_offset];
Ben Dooksbec08062009-12-14 22:20:24 -0800294 set_fiq_handler(&code->data, code->length);
295 }
296
Arnd Bergmanncd4bd8f2020-08-06 20:20:48 +0200297 s3c24xx_set_fiq(hw->irq, ack_ptr, true);
Ben Dooksbec08062009-12-14 22:20:24 -0800298
299 hw->fiq_mode = mode;
300 hw->fiq_inuse = 1;
301}
302
303/**
304 * s3c24xx_spi_fiqop - FIQ core code callback
305 * @pw: Data registered with the handler
306 * @release: Whether this is a release or a return.
307 *
308 * Called by the FIQ code when another module wants to use the FIQ, so
309 * return whether we are currently using this or not and then update our
310 * internal state.
311 */
312static int s3c24xx_spi_fiqop(void *pw, int release)
313{
314 struct s3c24xx_spi *hw = pw;
315 int ret = 0;
316
317 if (release) {
318 if (hw->fiq_inuse)
319 ret = -EBUSY;
320
321 /* note, we do not need to unroute the FIQ, as the FIQ
322 * vector code de-routes it to signal the end of transfer */
323
324 hw->fiq_mode = FIQ_MODE_NONE;
325 hw->fiq_claimed = 0;
326 } else {
327 hw->fiq_claimed = 1;
328 }
329
330 return ret;
331}
332
333/**
334 * s3c24xx_spi_initfiq - setup the information for the FIQ core
335 * @hw: The hardware state.
336 *
337 * Setup the fiq_handler block to pass to the FIQ core.
338 */
339static inline void s3c24xx_spi_initfiq(struct s3c24xx_spi *hw)
340{
341 hw->fiq_handler.dev_id = hw;
342 hw->fiq_handler.name = dev_name(hw->dev);
343 hw->fiq_handler.fiq_op = s3c24xx_spi_fiqop;
344}
345
346/**
347 * s3c24xx_spi_usefiq - return if we should be using FIQ.
348 * @hw: The hardware state.
349 *
350 * Return true if the platform data specifies whether this channel is
351 * allowed to use the FIQ.
352 */
353static inline bool s3c24xx_spi_usefiq(struct s3c24xx_spi *hw)
354{
355 return hw->pdata->use_fiq;
356}
357
358/**
359 * s3c24xx_spi_usingfiq - return if channel is using FIQ
360 * @spi: The hardware state.
361 *
362 * Return whether the channel is currently using the FIQ (separate from
363 * whether the FIQ is claimed).
364 */
365static inline bool s3c24xx_spi_usingfiq(struct s3c24xx_spi *spi)
366{
367 return spi->fiq_inuse;
368}
369#else
370
371static inline void s3c24xx_spi_initfiq(struct s3c24xx_spi *s) { }
372static inline void s3c24xx_spi_tryfiq(struct s3c24xx_spi *s) { }
373static inline bool s3c24xx_spi_usefiq(struct s3c24xx_spi *s) { return false; }
374static inline bool s3c24xx_spi_usingfiq(struct s3c24xx_spi *s) { return false; }
375
376#endif /* CONFIG_SPI_S3C24XX_FIQ */
377
Ben Dooks7fba5342006-05-20 15:00:18 -0700378static int s3c24xx_spi_txrx(struct spi_device *spi, struct spi_transfer *t)
379{
380 struct s3c24xx_spi *hw = to_hw(spi);
381
Ben Dooks7fba5342006-05-20 15:00:18 -0700382 hw->tx = t->tx_buf;
383 hw->rx = t->rx_buf;
384 hw->len = t->len;
385 hw->count = 0;
386
Ben Dooks4bb5eba2008-04-15 14:34:44 -0700387 init_completion(&hw->done);
388
Ben Dooksbec08062009-12-14 22:20:24 -0800389 hw->fiq_inuse = 0;
390 if (s3c24xx_spi_usefiq(hw) && t->len >= 3)
391 s3c24xx_spi_tryfiq(hw);
392
Ben Dooks7fba5342006-05-20 15:00:18 -0700393 /* send the first byte */
394 writeb(hw_txbyte(hw, 0), hw->regs + S3C2410_SPTDAT);
Ben Dooks4bb5eba2008-04-15 14:34:44 -0700395
Ben Dooks7fba5342006-05-20 15:00:18 -0700396 wait_for_completion(&hw->done);
Ben Dooks7fba5342006-05-20 15:00:18 -0700397 return hw->count;
398}
399
David Howells7d12e782006-10-05 14:55:46 +0100400static irqreturn_t s3c24xx_spi_irq(int irq, void *dev)
Ben Dooks7fba5342006-05-20 15:00:18 -0700401{
402 struct s3c24xx_spi *hw = dev;
403 unsigned int spsta = readb(hw->regs + S3C2410_SPSTA);
404 unsigned int count = hw->count;
405
406 if (spsta & S3C2410_SPSTA_DCOL) {
407 dev_dbg(hw->dev, "data-collision\n");
408 complete(&hw->done);
409 goto irq_done;
410 }
411
412 if (!(spsta & S3C2410_SPSTA_READY)) {
413 dev_dbg(hw->dev, "spi not ready for tx?\n");
414 complete(&hw->done);
415 goto irq_done;
416 }
417
Ben Dooksbec08062009-12-14 22:20:24 -0800418 if (!s3c24xx_spi_usingfiq(hw)) {
419 hw->count++;
Ben Dooks7fba5342006-05-20 15:00:18 -0700420
Ben Dooksbec08062009-12-14 22:20:24 -0800421 if (hw->rx)
422 hw->rx[count] = readb(hw->regs + S3C2410_SPRDAT);
Ben Dooks7fba5342006-05-20 15:00:18 -0700423
Ben Dooksbec08062009-12-14 22:20:24 -0800424 count++;
Ben Dooks7fba5342006-05-20 15:00:18 -0700425
Ben Dooksbec08062009-12-14 22:20:24 -0800426 if (count < hw->len)
427 writeb(hw_txbyte(hw, count), hw->regs + S3C2410_SPTDAT);
428 else
429 complete(&hw->done);
430 } else {
431 hw->count = hw->len;
432 hw->fiq_inuse = 0;
433
434 if (hw->rx)
435 hw->rx[hw->len-1] = readb(hw->regs + S3C2410_SPRDAT);
436
Ben Dooks7fba5342006-05-20 15:00:18 -0700437 complete(&hw->done);
Ben Dooksbec08062009-12-14 22:20:24 -0800438 }
Ben Dooks7fba5342006-05-20 15:00:18 -0700439
440 irq_done:
441 return IRQ_HANDLED;
442}
443
Ben Dooks5aa6cf32008-08-04 13:41:10 -0700444static void s3c24xx_spi_initialsetup(struct s3c24xx_spi *hw)
445{
446 /* for the moment, permanently enable the clock */
447
448 clk_enable(hw->clk);
449
450 /* program defaults into the registers */
451
452 writeb(0xff, hw->regs + S3C2410_SPPRE);
453 writeb(SPPIN_DEFAULT, hw->regs + S3C2410_SPPIN);
454 writeb(SPCON_DEFAULT, hw->regs + S3C2410_SPCON);
Ben Dookscf46b972008-10-15 22:02:41 -0700455
Ben Dooksee9c1fb2009-01-06 14:41:44 -0800456 if (hw->pdata) {
457 if (hw->set_cs == s3c24xx_spi_gpiocs)
458 gpio_direction_output(hw->pdata->pin_cs, 1);
459
460 if (hw->pdata->gpio_setup)
461 hw->pdata->gpio_setup(hw->pdata, 1);
462 }
Ben Dooks5aa6cf32008-08-04 13:41:10 -0700463}
464
Grant Likelyfd4a3192012-12-07 16:57:14 +0000465static int s3c24xx_spi_probe(struct platform_device *pdev)
Ben Dooks7fba5342006-05-20 15:00:18 -0700466{
Ben Dooks50f426b2008-04-15 14:34:45 -0700467 struct s3c2410_spi_info *pdata;
Ben Dooks7fba5342006-05-20 15:00:18 -0700468 struct s3c24xx_spi *hw;
469 struct spi_master *master;
Ben Dooks7fba5342006-05-20 15:00:18 -0700470 int err = 0;
Ben Dooks7fba5342006-05-20 15:00:18 -0700471
472 master = spi_alloc_master(&pdev->dev, sizeof(struct s3c24xx_spi));
473 if (master == NULL) {
474 dev_err(&pdev->dev, "No memory for spi_master\n");
Jingoo Hanc9f722e2013-12-09 19:19:13 +0900475 return -ENOMEM;
Ben Dooks7fba5342006-05-20 15:00:18 -0700476 }
477
478 hw = spi_master_get_devdata(master);
Ben Dooks7fba5342006-05-20 15:00:18 -0700479
Axel Lin94c69f72013-09-10 15:43:41 +0800480 hw->master = master;
Jingoo Han8074cf02013-07-30 16:58:59 +0900481 hw->pdata = pdata = dev_get_platdata(&pdev->dev);
Ben Dooks7fba5342006-05-20 15:00:18 -0700482 hw->dev = &pdev->dev;
483
Ben Dooks50f426b2008-04-15 14:34:45 -0700484 if (pdata == NULL) {
Ben Dooks7fba5342006-05-20 15:00:18 -0700485 dev_err(&pdev->dev, "No platform data supplied\n");
486 err = -ENOENT;
487 goto err_no_pdata;
488 }
489
490 platform_set_drvdata(pdev, hw);
491 init_completion(&hw->done);
492
Ben Dooksbec08062009-12-14 22:20:24 -0800493 /* initialise fiq handler */
494
495 s3c24xx_spi_initfiq(hw);
496
Ben Dooksd1e77802008-04-15 14:34:46 -0700497 /* setup the master state. */
498
David Brownelle7db06b2009-06-17 16:26:04 -0700499 /* the spi->mode bits understood by this driver: */
500 master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH;
501
Ben Dooksd1e77802008-04-15 14:34:46 -0700502 master->num_chipselect = hw->pdata->num_cs;
Ben Dookscb1d0a72008-07-28 15:46:33 -0700503 master->bus_num = pdata->bus_num;
Axel Lin08850fa2014-02-14 20:38:16 +0800504 master->bits_per_word_mask = SPI_BPW_MASK(8);
Ben Dooksd1e77802008-04-15 14:34:46 -0700505
Ben Dooks7fba5342006-05-20 15:00:18 -0700506 /* setup the state for the bitbang driver */
507
508 hw->bitbang.master = hw->master;
509 hw->bitbang.setup_transfer = s3c24xx_spi_setupxfer;
510 hw->bitbang.chipselect = s3c24xx_spi_chipsel;
511 hw->bitbang.txrx_bufs = s3c24xx_spi_txrx;
Ben Dooks570327d2009-09-22 16:46:14 -0700512
513 hw->master->setup = s3c24xx_spi_setup;
Ben Dooks7fba5342006-05-20 15:00:18 -0700514
515 dev_dbg(hw->dev, "bitbang at %p\n", &hw->bitbang);
516
517 /* find and map our resources */
YueHaibingb38f1f92019-09-04 21:59:07 +0800518 hw->regs = devm_platform_ioremap_resource(pdev, 0);
Jingoo Hanc9f722e2013-12-09 19:19:13 +0900519 if (IS_ERR(hw->regs)) {
520 err = PTR_ERR(hw->regs);
521 goto err_no_pdata;
Ben Dooks7fba5342006-05-20 15:00:18 -0700522 }
523
524 hw->irq = platform_get_irq(pdev, 0);
525 if (hw->irq < 0) {
Ben Dooks7fba5342006-05-20 15:00:18 -0700526 err = -ENOENT;
Jingoo Hanc9f722e2013-12-09 19:19:13 +0900527 goto err_no_pdata;
Ben Dooks7fba5342006-05-20 15:00:18 -0700528 }
529
Jingoo Hanc9f722e2013-12-09 19:19:13 +0900530 err = devm_request_irq(&pdev->dev, hw->irq, s3c24xx_spi_irq, 0,
531 pdev->name, hw);
Ben Dooks7fba5342006-05-20 15:00:18 -0700532 if (err) {
533 dev_err(&pdev->dev, "Cannot claim IRQ\n");
Jingoo Hanc9f722e2013-12-09 19:19:13 +0900534 goto err_no_pdata;
Ben Dooks7fba5342006-05-20 15:00:18 -0700535 }
536
Jingoo Hanc9f722e2013-12-09 19:19:13 +0900537 hw->clk = devm_clk_get(&pdev->dev, "spi");
Ben Dooks7fba5342006-05-20 15:00:18 -0700538 if (IS_ERR(hw->clk)) {
539 dev_err(&pdev->dev, "No clock for device\n");
540 err = PTR_ERR(hw->clk);
Jingoo Hanc9f722e2013-12-09 19:19:13 +0900541 goto err_no_pdata;
Ben Dooks7fba5342006-05-20 15:00:18 -0700542 }
543
Ben Dooks7fba5342006-05-20 15:00:18 -0700544 /* setup any gpio we can */
545
Ben Dooks50f426b2008-04-15 14:34:45 -0700546 if (!pdata->set_cs) {
Ben Dooksee9c1fb2009-01-06 14:41:44 -0800547 if (pdata->pin_cs < 0) {
548 dev_err(&pdev->dev, "No chipselect pin\n");
Julia Lawallb2af0452012-08-22 13:42:47 +0200549 err = -EINVAL;
Ben Dooksee9c1fb2009-01-06 14:41:44 -0800550 goto err_register;
551 }
Ben Dooks8736b922007-01-26 00:56:43 -0800552
Jingoo Hanc9f722e2013-12-09 19:19:13 +0900553 err = devm_gpio_request(&pdev->dev, pdata->pin_cs,
554 dev_name(&pdev->dev));
Ben Dooksee9c1fb2009-01-06 14:41:44 -0800555 if (err) {
556 dev_err(&pdev->dev, "Failed to get gpio for cs\n");
557 goto err_register;
558 }
559
560 hw->set_cs = s3c24xx_spi_gpiocs;
561 gpio_direction_output(pdata->pin_cs, 1);
Ben Dooks8736b922007-01-26 00:56:43 -0800562 } else
Ben Dooks50f426b2008-04-15 14:34:45 -0700563 hw->set_cs = pdata->set_cs;
Ben Dooks7fba5342006-05-20 15:00:18 -0700564
Ben Dooksee9c1fb2009-01-06 14:41:44 -0800565 s3c24xx_spi_initialsetup(hw);
566
Ben Dooks7fba5342006-05-20 15:00:18 -0700567 /* register our spi controller */
568
569 err = spi_bitbang_start(&hw->bitbang);
570 if (err) {
571 dev_err(&pdev->dev, "Failed to register SPI master\n");
572 goto err_register;
573 }
574
Ben Dooks7fba5342006-05-20 15:00:18 -0700575 return 0;
576
577 err_register:
578 clk_disable(hw->clk);
Ben Dooks7fba5342006-05-20 15:00:18 -0700579
Ben Dooks7fba5342006-05-20 15:00:18 -0700580 err_no_pdata:
Joe Perchesa419aef2009-08-18 11:18:35 -0700581 spi_master_put(hw->master);
Ben Dooks7fba5342006-05-20 15:00:18 -0700582 return err;
583}
584
Grant Likelyfd4a3192012-12-07 16:57:14 +0000585static int s3c24xx_spi_remove(struct platform_device *dev)
Ben Dooks7fba5342006-05-20 15:00:18 -0700586{
587 struct s3c24xx_spi *hw = platform_get_drvdata(dev);
588
Axel Linc6e7b8c2011-05-15 07:35:16 +0800589 spi_bitbang_stop(&hw->bitbang);
Ben Dooks7fba5342006-05-20 15:00:18 -0700590 clk_disable(hw->clk);
Ben Dooks7fba5342006-05-20 15:00:18 -0700591 spi_master_put(hw->master);
592 return 0;
593}
594
595
596#ifdef CONFIG_PM
597
Ben Dooks6d613202009-09-22 16:46:13 -0700598static int s3c24xx_spi_suspend(struct device *dev)
Ben Dooks7fba5342006-05-20 15:00:18 -0700599{
Axel Lina12163942013-08-09 15:35:16 +0800600 struct s3c24xx_spi *hw = dev_get_drvdata(dev);
Axel Lin38060372014-03-05 15:17:23 +0800601 int ret;
602
603 ret = spi_master_suspend(hw->master);
604 if (ret)
605 return ret;
Ben Dooks7fba5342006-05-20 15:00:18 -0700606
Ben Dookscf46b972008-10-15 22:02:41 -0700607 if (hw->pdata && hw->pdata->gpio_setup)
608 hw->pdata->gpio_setup(hw->pdata, 0);
609
Ben Dooks7fba5342006-05-20 15:00:18 -0700610 clk_disable(hw->clk);
611 return 0;
612}
613
Ben Dooks6d613202009-09-22 16:46:13 -0700614static int s3c24xx_spi_resume(struct device *dev)
Ben Dooks7fba5342006-05-20 15:00:18 -0700615{
Axel Lina12163942013-08-09 15:35:16 +0800616 struct s3c24xx_spi *hw = dev_get_drvdata(dev);
Ben Dooks7fba5342006-05-20 15:00:18 -0700617
Ben Dooks5aa6cf32008-08-04 13:41:10 -0700618 s3c24xx_spi_initialsetup(hw);
Axel Lin38060372014-03-05 15:17:23 +0800619 return spi_master_resume(hw->master);
Ben Dooks7fba5342006-05-20 15:00:18 -0700620}
621
Alexey Dobriyan47145212009-12-14 18:00:08 -0800622static const struct dev_pm_ops s3c24xx_spi_pmops = {
Ben Dooks6d613202009-09-22 16:46:13 -0700623 .suspend = s3c24xx_spi_suspend,
624 .resume = s3c24xx_spi_resume,
625};
626
627#define S3C24XX_SPI_PMOPS &s3c24xx_spi_pmops
Ben Dooks7fba5342006-05-20 15:00:18 -0700628#else
Ben Dooks6d613202009-09-22 16:46:13 -0700629#define S3C24XX_SPI_PMOPS NULL
630#endif /* CONFIG_PM */
Ben Dooks7fba5342006-05-20 15:00:18 -0700631
Kay Sievers7e38c3c2008-04-10 21:29:20 -0700632MODULE_ALIAS("platform:s3c2410-spi");
Ben Dooks42cde432008-09-13 02:33:24 -0700633static struct platform_driver s3c24xx_spi_driver = {
Grant Likely940ab882011-10-05 11:29:49 -0600634 .probe = s3c24xx_spi_probe,
Grant Likelyfd4a3192012-12-07 16:57:14 +0000635 .remove = s3c24xx_spi_remove,
Ben Dooks7fba5342006-05-20 15:00:18 -0700636 .driver = {
637 .name = "s3c2410-spi",
Ben Dooks6d613202009-09-22 16:46:13 -0700638 .pm = S3C24XX_SPI_PMOPS,
Ben Dooks7fba5342006-05-20 15:00:18 -0700639 },
640};
Grant Likely940ab882011-10-05 11:29:49 -0600641module_platform_driver(s3c24xx_spi_driver);
Ben Dooks7fba5342006-05-20 15:00:18 -0700642
643MODULE_DESCRIPTION("S3C24XX SPI Driver");
644MODULE_AUTHOR("Ben Dooks, <ben@simtec.co.uk>");
645MODULE_LICENSE("GPL");