Blame view

drivers/spi/spi-s3c24xx.c 16.3 KB
ca632f556   Grant Likely   spi: reorganize d...
1
  /*
7fba53402   Ben Dooks   [PATCH] S3C24XX: ...
2
   * Copyright (c) 2006 Ben Dooks
bec0806cf   Ben Dooks   spi_s3c24xx: add ...
3
   * Copyright 2006-2009 Simtec Electronics
7fba53402   Ben Dooks   [PATCH] S3C24XX: ...
4
5
6
7
8
9
10
   *	Ben Dooks <ben@simtec.co.uk>
   *
   * This program is free software; you can redistribute it and/or modify
   * it under the terms of the GNU General Public License version 2 as
   * published by the Free Software Foundation.
   *
  */
7fba53402   Ben Dooks   [PATCH] S3C24XX: ...
11
12
13
14
15
16
17
18
19
  #include <linux/init.h>
  #include <linux/spinlock.h>
  #include <linux/workqueue.h>
  #include <linux/interrupt.h>
  #include <linux/delay.h>
  #include <linux/errno.h>
  #include <linux/err.h>
  #include <linux/clk.h>
  #include <linux/platform_device.h>
ee9c1fbfe   Ben Dooks   spi: use generic ...
20
  #include <linux/gpio.h>
1a0c220f7   Ben Dooks   spi_s3c24xx: fix ...
21
  #include <linux/io.h>
5a0e3ad6a   Tejun Heo   include cleanup: ...
22
  #include <linux/slab.h>
7fba53402   Ben Dooks   [PATCH] S3C24XX: ...
23
24
25
  
  #include <linux/spi/spi.h>
  #include <linux/spi/spi_bitbang.h>
d7614de42   Paul Gortmaker   spi: Add module.h...
26
  #include <linux/module.h>
7fba53402   Ben Dooks   [PATCH] S3C24XX: ...
27

136227087   Ben Dooks   [ARM] S3C: Move p...
28
  #include <plat/regs-spi.h>
a09e64fbc   Russell King   [ARM] Move includ...
29
  #include <mach/spi.h>
7fba53402   Ben Dooks   [PATCH] S3C24XX: ...
30

bec0806cf   Ben Dooks   spi_s3c24xx: add ...
31
32
  #include <plat/fiq.h>
  #include <asm/fiq.h>
ca632f556   Grant Likely   spi: reorganize d...
33
  #include "spi-s3c24xx-fiq.h"
bec0806cf   Ben Dooks   spi_s3c24xx: add ...
34

570327d9f   Ben Dooks   spi_s3c24xx: cach...
35
36
37
38
39
40
41
42
43
44
45
46
47
  /**
   * s3c24xx_spi_devstate - per device data
   * @hz: Last frequency calculated for @sppre field.
   * @mode: Last mode setting for the @spcon field.
   * @spcon: Value to write to the SPCON register.
   * @sppre: Value to write to the SPPRE register.
   */
  struct s3c24xx_spi_devstate {
  	unsigned int	hz;
  	unsigned int	mode;
  	u8		spcon;
  	u8		sppre;
  };
bec0806cf   Ben Dooks   spi_s3c24xx: add ...
48
49
50
51
52
53
  enum spi_fiq_mode {
  	FIQ_MODE_NONE	= 0,
  	FIQ_MODE_TX	= 1,
  	FIQ_MODE_RX	= 2,
  	FIQ_MODE_TXRX	= 3,
  };
7fba53402   Ben Dooks   [PATCH] S3C24XX: ...
54
55
56
57
58
59
60
61
62
  struct s3c24xx_spi {
  	/* bitbang has to be first */
  	struct spi_bitbang	 bitbang;
  	struct completion	 done;
  
  	void __iomem		*regs;
  	int			 irq;
  	int			 len;
  	int			 count;
bec0806cf   Ben Dooks   spi_s3c24xx: add ...
63
64
65
66
  	struct fiq_handler	 fiq_handler;
  	enum spi_fiq_mode	 fiq_mode;
  	unsigned char		 fiq_inuse;
  	unsigned char		 fiq_claimed;
6c912a3d3   Arnaud Patard   [PATCH] spi_s3c24...
67
  	void			(*set_cs)(struct s3c2410_spi_info *spi,
8736b9270   Ben Dooks   [PATCH] S3C24XX: ...
68
  					  int cs, int pol);
7fba53402   Ben Dooks   [PATCH] S3C24XX: ...
69
70
71
72
73
74
75
76
77
78
79
  	/* data buffers */
  	const unsigned char	*tx;
  	unsigned char		*rx;
  
  	struct clk		*clk;
  	struct resource		*ioarea;
  	struct spi_master	*master;
  	struct spi_device	*curdev;
  	struct device		*dev;
  	struct s3c2410_spi_info *pdata;
  };
bec0806cf   Ben Dooks   spi_s3c24xx: add ...
80

7fba53402   Ben Dooks   [PATCH] S3C24XX: ...
81
82
83
84
85
86
87
  #define SPCON_DEFAULT (S3C2410_SPCON_MSTR | S3C2410_SPCON_SMOD_INT)
  #define SPPIN_DEFAULT (S3C2410_SPPIN_KEEP)
  
  static inline struct s3c24xx_spi *to_hw(struct spi_device *sdev)
  {
  	return spi_master_get_devdata(sdev->master);
  }
8736b9270   Ben Dooks   [PATCH] S3C24XX: ...
88
89
  static void s3c24xx_spi_gpiocs(struct s3c2410_spi_info *spi, int cs, int pol)
  {
ee9c1fbfe   Ben Dooks   spi: use generic ...
90
  	gpio_set_value(spi->pin_cs, pol);
8736b9270   Ben Dooks   [PATCH] S3C24XX: ...
91
  }
7fba53402   Ben Dooks   [PATCH] S3C24XX: ...
92
93
  static void s3c24xx_spi_chipsel(struct spi_device *spi, int value)
  {
570327d9f   Ben Dooks   spi_s3c24xx: cach...
94
  	struct s3c24xx_spi_devstate *cs = spi->controller_state;
7fba53402   Ben Dooks   [PATCH] S3C24XX: ...
95
96
  	struct s3c24xx_spi *hw = to_hw(spi);
  	unsigned int cspol = spi->mode & SPI_CS_HIGH ? 1 : 0;
570327d9f   Ben Dooks   spi_s3c24xx: cach...
97
98
  
  	/* change the chipselect state and the state of the spi engine clock */
7fba53402   Ben Dooks   [PATCH] S3C24XX: ...
99
100
101
  
  	switch (value) {
  	case BITBANG_CS_INACTIVE:
3d2c5b415   Ben Dooks   spi: fix use of s...
102
  		hw->set_cs(hw->pdata, spi->chip_select, cspol^1);
570327d9f   Ben Dooks   spi_s3c24xx: cach...
103
  		writeb(cs->spcon, hw->regs + S3C2410_SPCON);
7fba53402   Ben Dooks   [PATCH] S3C24XX: ...
104
105
106
  		break;
  
  	case BITBANG_CS_ACTIVE:
570327d9f   Ben Dooks   spi_s3c24xx: cach...
107
108
  		writeb(cs->spcon | S3C2410_SPCON_ENSCK,
  		       hw->regs + S3C2410_SPCON);
3d2c5b415   Ben Dooks   spi: fix use of s...
109
  		hw->set_cs(hw->pdata, spi->chip_select, cspol);
7fba53402   Ben Dooks   [PATCH] S3C24XX: ...
110
  		break;
7fba53402   Ben Dooks   [PATCH] S3C24XX: ...
111
112
  	}
  }
570327d9f   Ben Dooks   spi_s3c24xx: cach...
113
114
  static int s3c24xx_spi_update_state(struct spi_device *spi,
  				    struct spi_transfer *t)
7fba53402   Ben Dooks   [PATCH] S3C24XX: ...
115
116
  {
  	struct s3c24xx_spi *hw = to_hw(spi);
570327d9f   Ben Dooks   spi_s3c24xx: cach...
117
  	struct s3c24xx_spi_devstate *cs = spi->controller_state;
7fba53402   Ben Dooks   [PATCH] S3C24XX: ...
118
119
120
  	unsigned int bpw;
  	unsigned int hz;
  	unsigned int div;
b89787845   Ben Dooks   spi_s3c24xx: fix ...
121
  	unsigned long clk;
7fba53402   Ben Dooks   [PATCH] S3C24XX: ...
122
123
124
  
  	bpw = t ? t->bits_per_word : spi->bits_per_word;
  	hz  = t ? t->speed_hz : spi->max_speed_hz;
191529756   Ben Dooks   spi_s3c24xx: fix ...
125
126
127
128
129
  	if (!bpw)
  		bpw = 8;
  
  	if (!hz)
  		hz = spi->max_speed_hz;
7fba53402   Ben Dooks   [PATCH] S3C24XX: ...
130
131
132
133
134
  	if (bpw != 8) {
  		dev_err(&spi->dev, "invalid bits-per-word (%d)
  ", bpw);
  		return -EINVAL;
  	}
570327d9f   Ben Dooks   spi_s3c24xx: cach...
135
  	if (spi->mode != cs->mode) {
bec0806cf   Ben Dooks   spi_s3c24xx: add ...
136
  		u8 spcon = SPCON_DEFAULT | S3C2410_SPCON_ENSCK;
570327d9f   Ben Dooks   spi_s3c24xx: cach...
137
138
139
  
  		if (spi->mode & SPI_CPHA)
  			spcon |= S3C2410_SPCON_CPHA_FMTB;
7fba53402   Ben Dooks   [PATCH] S3C24XX: ...
140

570327d9f   Ben Dooks   spi_s3c24xx: cach...
141
142
  		if (spi->mode & SPI_CPOL)
  			spcon |= S3C2410_SPCON_CPOL_HIGH;
7fba53402   Ben Dooks   [PATCH] S3C24XX: ...
143

570327d9f   Ben Dooks   spi_s3c24xx: cach...
144
145
146
  		cs->mode = spi->mode;
  		cs->spcon = spcon;
  	}
b89787845   Ben Dooks   spi_s3c24xx: fix ...
147

570327d9f   Ben Dooks   spi_s3c24xx: cach...
148
149
150
  	if (cs->hz != hz) {
  		clk = clk_get_rate(hw->clk);
  		div = DIV_ROUND_UP(clk, hz * 2) - 1;
b89787845   Ben Dooks   spi_s3c24xx: fix ...
151

570327d9f   Ben Dooks   spi_s3c24xx: cach...
152
153
  		if (div > 255)
  			div = 255;
7fba53402   Ben Dooks   [PATCH] S3C24XX: ...
154

570327d9f   Ben Dooks   spi_s3c24xx: cach...
155
156
157
158
159
160
  		dev_dbg(&spi->dev, "pre-scaler=%d (wanted %d, got %ld)
  ",
  			div, hz, clk / (2 * (div + 1)));
  
  		cs->hz = hz;
  		cs->sppre = div;
7fba53402   Ben Dooks   [PATCH] S3C24XX: ...
161
  	}
7fba53402   Ben Dooks   [PATCH] S3C24XX: ...
162
163
164
  
  	return 0;
  }
570327d9f   Ben Dooks   spi_s3c24xx: cach...
165
166
167
168
169
170
171
172
173
174
175
176
177
  static int s3c24xx_spi_setupxfer(struct spi_device *spi,
  				 struct spi_transfer *t)
  {
  	struct s3c24xx_spi_devstate *cs = spi->controller_state;
  	struct s3c24xx_spi *hw = to_hw(spi);
  	int ret;
  
  	ret = s3c24xx_spi_update_state(spi, t);
  	if (!ret)
  		writeb(cs->sppre, hw->regs + S3C2410_SPPRE);
  
  	return ret;
  }
7fba53402   Ben Dooks   [PATCH] S3C24XX: ...
178
179
  static int s3c24xx_spi_setup(struct spi_device *spi)
  {
570327d9f   Ben Dooks   spi_s3c24xx: cach...
180
181
  	struct s3c24xx_spi_devstate *cs = spi->controller_state;
  	struct s3c24xx_spi *hw = to_hw(spi);
7fba53402   Ben Dooks   [PATCH] S3C24XX: ...
182
  	int ret;
570327d9f   Ben Dooks   spi_s3c24xx: cach...
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
  	/* allocate settings on the first call */
  	if (!cs) {
  		cs = kzalloc(sizeof(struct s3c24xx_spi_devstate), GFP_KERNEL);
  		if (!cs) {
  			dev_err(&spi->dev, "no memory for controller state
  ");
  			return -ENOMEM;
  		}
  
  		cs->spcon = SPCON_DEFAULT;
  		cs->hz = -1;
  		spi->controller_state = cs;
  	}
  
  	/* initialise the state from the device */
  	ret = s3c24xx_spi_update_state(spi, NULL);
  	if (ret)
7fba53402   Ben Dooks   [PATCH] S3C24XX: ...
200
  		return ret;
570327d9f   Ben Dooks   spi_s3c24xx: cach...
201
202
203
204
205
  
  	spin_lock(&hw->bitbang.lock);
  	if (!hw->bitbang.busy) {
  		hw->bitbang.chipselect(spi, BITBANG_CS_INACTIVE);
  		/* need to ndelay for 0.5 clocktick ? */
7fba53402   Ben Dooks   [PATCH] S3C24XX: ...
206
  	}
570327d9f   Ben Dooks   spi_s3c24xx: cach...
207
  	spin_unlock(&hw->bitbang.lock);
7fba53402   Ben Dooks   [PATCH] S3C24XX: ...
208

7fba53402   Ben Dooks   [PATCH] S3C24XX: ...
209
210
  	return 0;
  }
570327d9f   Ben Dooks   spi_s3c24xx: cach...
211
212
213
214
  static void s3c24xx_spi_cleanup(struct spi_device *spi)
  {
  	kfree(spi->controller_state);
  }
7fba53402   Ben Dooks   [PATCH] S3C24XX: ...
215
216
  static inline unsigned int hw_txbyte(struct s3c24xx_spi *hw, int count)
  {
4b1badf5d   David Brownell   [PATCH] SPI: defi...
217
  	return hw->tx ? hw->tx[count] : 0;
7fba53402   Ben Dooks   [PATCH] S3C24XX: ...
218
  }
bec0806cf   Ben Dooks   spi_s3c24xx: add ...
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
  #ifdef CONFIG_SPI_S3C24XX_FIQ
  /* Support for FIQ based pseudo-DMA to improve the transfer speed.
   *
   * This code uses the assembly helper in spi_s3c24xx_spi.S which is
   * used by the FIQ core to move data between main memory and the peripheral
   * block. Since this is code running on the processor, there is no problem
   * with cache coherency of the buffers, so we can use any buffer we like.
   */
  
  /**
   * struct spi_fiq_code - FIQ code and header
   * @length: The length of the code fragment, excluding this header.
   * @ack_offset: The offset from @data to the word to place the IRQ ACK bit at.
   * @data: The code itself to install as a FIQ handler.
   */
  struct spi_fiq_code {
  	u32	length;
  	u32	ack_offset;
  	u8	data[0];
  };
  
  extern struct spi_fiq_code s3c24xx_spi_fiq_txrx;
  extern struct spi_fiq_code s3c24xx_spi_fiq_tx;
  extern struct spi_fiq_code s3c24xx_spi_fiq_rx;
  
  /**
   * ack_bit - turn IRQ into IRQ acknowledgement bit
   * @irq: The interrupt number
   *
   * Returns the bit to write to the interrupt acknowledge register.
   */
  static inline u32 ack_bit(unsigned int irq)
  {
  	return 1 << (irq - IRQ_EINT0);
  }
  
  /**
   * s3c24xx_spi_tryfiq - attempt to claim and setup FIQ for transfer
   * @hw: The hardware state.
   *
   * Claim the FIQ handler (only one can be active at any one time) and
   * then setup the correct transfer code for this transfer.
   *
3ad2f3fbb   Daniel Mack   tree-wide: Assort...
262
   * This call updates all the necessary state information if successful,
bec0806cf   Ben Dooks   spi_s3c24xx: add ...
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
   * so the caller does not need to do anything more than start the transfer
   * as normal, since the IRQ will have been re-routed to the FIQ handler.
  */
  void s3c24xx_spi_tryfiq(struct s3c24xx_spi *hw)
  {
  	struct pt_regs regs;
  	enum spi_fiq_mode mode;
  	struct spi_fiq_code *code;
  	int ret;
  
  	if (!hw->fiq_claimed) {
  		/* try and claim fiq if we haven't got it, and if not
  		 * then return and simply use another transfer method */
  
  		ret = claim_fiq(&hw->fiq_handler);
  		if (ret)
  			return;
  	}
  
  	if (hw->tx && !hw->rx)
  		mode = FIQ_MODE_TX;
  	else if (hw->rx && !hw->tx)
  		mode = FIQ_MODE_RX;
  	else
  		mode = FIQ_MODE_TXRX;
  
  	regs.uregs[fiq_rspi] = (long)hw->regs;
  	regs.uregs[fiq_rrx]  = (long)hw->rx;
  	regs.uregs[fiq_rtx]  = (long)hw->tx + 1;
  	regs.uregs[fiq_rcount] = hw->len - 1;
  	regs.uregs[fiq_rirq] = (long)S3C24XX_VA_IRQ;
  
  	set_fiq_regs(&regs);
  
  	if (hw->fiq_mode != mode) {
  		u32 *ack_ptr;
  
  		hw->fiq_mode = mode;
  
  		switch (mode) {
  		case FIQ_MODE_TX:
  			code = &s3c24xx_spi_fiq_tx;
  			break;
  		case FIQ_MODE_RX:
  			code = &s3c24xx_spi_fiq_rx;
  			break;
  		case FIQ_MODE_TXRX:
  			code = &s3c24xx_spi_fiq_txrx;
  			break;
  		default:
  			code = NULL;
  		}
  
  		BUG_ON(!code);
  
  		ack_ptr = (u32 *)&code->data[code->ack_offset];
  		*ack_ptr = ack_bit(hw->irq);
  
  		set_fiq_handler(&code->data, code->length);
  	}
  
  	s3c24xx_set_fiq(hw->irq, true);
  
  	hw->fiq_mode = mode;
  	hw->fiq_inuse = 1;
  }
  
  /**
   * s3c24xx_spi_fiqop - FIQ core code callback
   * @pw: Data registered with the handler
   * @release: Whether this is a release or a return.
   *
   * Called by the FIQ code when another module wants to use the FIQ, so
   * return whether we are currently using this or not and then update our
   * internal state.
   */
  static int s3c24xx_spi_fiqop(void *pw, int release)
  {
  	struct s3c24xx_spi *hw = pw;
  	int ret = 0;
  
  	if (release) {
  		if (hw->fiq_inuse)
  			ret = -EBUSY;
  
  		/* note, we do not need to unroute the FIQ, as the FIQ
  		 * vector code de-routes it to signal the end of transfer */
  
  		hw->fiq_mode = FIQ_MODE_NONE;
  		hw->fiq_claimed = 0;
  	} else {
  		hw->fiq_claimed = 1;
  	}
  
  	return ret;
  }
  
  /**
   * s3c24xx_spi_initfiq - setup the information for the FIQ core
   * @hw: The hardware state.
   *
   * Setup the fiq_handler block to pass to the FIQ core.
   */
  static inline void s3c24xx_spi_initfiq(struct s3c24xx_spi *hw)
  {
  	hw->fiq_handler.dev_id = hw;
  	hw->fiq_handler.name = dev_name(hw->dev);
  	hw->fiq_handler.fiq_op = s3c24xx_spi_fiqop;
  }
  
  /**
   * s3c24xx_spi_usefiq - return if we should be using FIQ.
   * @hw: The hardware state.
   *
   * Return true if the platform data specifies whether this channel is
   * allowed to use the FIQ.
   */
  static inline bool s3c24xx_spi_usefiq(struct s3c24xx_spi *hw)
  {
  	return hw->pdata->use_fiq;
  }
  
  /**
   * s3c24xx_spi_usingfiq - return if channel is using FIQ
   * @spi: The hardware state.
   *
   * Return whether the channel is currently using the FIQ (separate from
   * whether the FIQ is claimed).
   */
  static inline bool s3c24xx_spi_usingfiq(struct s3c24xx_spi *spi)
  {
  	return spi->fiq_inuse;
  }
  #else
  
  static inline void s3c24xx_spi_initfiq(struct s3c24xx_spi *s) { }
  static inline void s3c24xx_spi_tryfiq(struct s3c24xx_spi *s) { }
  static inline bool s3c24xx_spi_usefiq(struct s3c24xx_spi *s) { return false; }
  static inline bool s3c24xx_spi_usingfiq(struct s3c24xx_spi *s) { return false; }
  
  #endif /* CONFIG_SPI_S3C24XX_FIQ */
7fba53402   Ben Dooks   [PATCH] S3C24XX: ...
404
405
406
  static int s3c24xx_spi_txrx(struct spi_device *spi, struct spi_transfer *t)
  {
  	struct s3c24xx_spi *hw = to_hw(spi);
7fba53402   Ben Dooks   [PATCH] S3C24XX: ...
407
408
409
410
  	hw->tx = t->tx_buf;
  	hw->rx = t->rx_buf;
  	hw->len = t->len;
  	hw->count = 0;
4bb5eba06   Ben Dooks   spi: spi_s3c24xx ...
411
  	init_completion(&hw->done);
bec0806cf   Ben Dooks   spi_s3c24xx: add ...
412
413
414
  	hw->fiq_inuse = 0;
  	if (s3c24xx_spi_usefiq(hw) && t->len >= 3)
  		s3c24xx_spi_tryfiq(hw);
7fba53402   Ben Dooks   [PATCH] S3C24XX: ...
415
416
  	/* send the first byte */
  	writeb(hw_txbyte(hw, 0), hw->regs + S3C2410_SPTDAT);
4bb5eba06   Ben Dooks   spi: spi_s3c24xx ...
417

7fba53402   Ben Dooks   [PATCH] S3C24XX: ...
418
  	wait_for_completion(&hw->done);
7fba53402   Ben Dooks   [PATCH] S3C24XX: ...
419
420
  	return hw->count;
  }
7d12e780e   David Howells   IRQ: Maintain reg...
421
  static irqreturn_t s3c24xx_spi_irq(int irq, void *dev)
7fba53402   Ben Dooks   [PATCH] S3C24XX: ...
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
  {
  	struct s3c24xx_spi *hw = dev;
  	unsigned int spsta = readb(hw->regs + S3C2410_SPSTA);
  	unsigned int count = hw->count;
  
  	if (spsta & S3C2410_SPSTA_DCOL) {
  		dev_dbg(hw->dev, "data-collision
  ");
  		complete(&hw->done);
  		goto irq_done;
  	}
  
  	if (!(spsta & S3C2410_SPSTA_READY)) {
  		dev_dbg(hw->dev, "spi not ready for tx?
  ");
  		complete(&hw->done);
  		goto irq_done;
  	}
bec0806cf   Ben Dooks   spi_s3c24xx: add ...
440
441
  	if (!s3c24xx_spi_usingfiq(hw)) {
  		hw->count++;
7fba53402   Ben Dooks   [PATCH] S3C24XX: ...
442

bec0806cf   Ben Dooks   spi_s3c24xx: add ...
443
444
  		if (hw->rx)
  			hw->rx[count] = readb(hw->regs + S3C2410_SPRDAT);
7fba53402   Ben Dooks   [PATCH] S3C24XX: ...
445

bec0806cf   Ben Dooks   spi_s3c24xx: add ...
446
447
448
449
450
451
452
453
454
455
456
457
  		count++;
  
  		if (count < hw->len)
  			writeb(hw_txbyte(hw, count), hw->regs + S3C2410_SPTDAT);
  		else
  			complete(&hw->done);
  	} else {
  		hw->count = hw->len;
  		hw->fiq_inuse = 0;
  
  		if (hw->rx)
  			hw->rx[hw->len-1] = readb(hw->regs + S3C2410_SPRDAT);
7fba53402   Ben Dooks   [PATCH] S3C24XX: ...
458

7fba53402   Ben Dooks   [PATCH] S3C24XX: ...
459
  		complete(&hw->done);
bec0806cf   Ben Dooks   spi_s3c24xx: add ...
460
  	}
7fba53402   Ben Dooks   [PATCH] S3C24XX: ...
461
462
463
464
  
   irq_done:
  	return IRQ_HANDLED;
  }
5aa6cf302   Ben Dooks   spi: S3C24XX: res...
465
466
467
468
469
470
471
472
473
474
475
  static void s3c24xx_spi_initialsetup(struct s3c24xx_spi *hw)
  {
  	/* for the moment, permanently enable the clock */
  
  	clk_enable(hw->clk);
  
  	/* program defaults into the registers */
  
  	writeb(0xff, hw->regs + S3C2410_SPPRE);
  	writeb(SPPIN_DEFAULT, hw->regs + S3C2410_SPPIN);
  	writeb(SPCON_DEFAULT, hw->regs + S3C2410_SPCON);
cf46b973f   Ben Dooks   spi_s3c24xx: pin ...
476

ee9c1fbfe   Ben Dooks   spi: use generic ...
477
478
479
480
481
482
483
  	if (hw->pdata) {
  		if (hw->set_cs == s3c24xx_spi_gpiocs)
  			gpio_direction_output(hw->pdata->pin_cs, 1);
  
  		if (hw->pdata->gpio_setup)
  			hw->pdata->gpio_setup(hw->pdata, 1);
  	}
5aa6cf302   Ben Dooks   spi: S3C24XX: res...
484
  }
940ab8896   Grant Likely   drivercore: Add h...
485
  static int __devinit s3c24xx_spi_probe(struct platform_device *pdev)
7fba53402   Ben Dooks   [PATCH] S3C24XX: ...
486
  {
50f426b55   Ben Dooks   spi: spi_s3c24xx ...
487
  	struct s3c2410_spi_info *pdata;
7fba53402   Ben Dooks   [PATCH] S3C24XX: ...
488
489
  	struct s3c24xx_spi *hw;
  	struct spi_master *master;
7fba53402   Ben Dooks   [PATCH] S3C24XX: ...
490
491
  	struct resource *res;
  	int err = 0;
7fba53402   Ben Dooks   [PATCH] S3C24XX: ...
492
493
494
495
496
497
498
499
500
501
502
503
504
  
  	master = spi_alloc_master(&pdev->dev, sizeof(struct s3c24xx_spi));
  	if (master == NULL) {
  		dev_err(&pdev->dev, "No memory for spi_master
  ");
  		err = -ENOMEM;
  		goto err_nomem;
  	}
  
  	hw = spi_master_get_devdata(master);
  	memset(hw, 0, sizeof(struct s3c24xx_spi));
  
  	hw->master = spi_master_get(master);
50f426b55   Ben Dooks   spi: spi_s3c24xx ...
505
  	hw->pdata = pdata = pdev->dev.platform_data;
7fba53402   Ben Dooks   [PATCH] S3C24XX: ...
506
  	hw->dev = &pdev->dev;
50f426b55   Ben Dooks   spi: spi_s3c24xx ...
507
  	if (pdata == NULL) {
7fba53402   Ben Dooks   [PATCH] S3C24XX: ...
508
509
510
511
512
513
514
515
  		dev_err(&pdev->dev, "No platform data supplied
  ");
  		err = -ENOENT;
  		goto err_no_pdata;
  	}
  
  	platform_set_drvdata(pdev, hw);
  	init_completion(&hw->done);
bec0806cf   Ben Dooks   spi_s3c24xx: add ...
516
517
518
  	/* initialise fiq handler */
  
  	s3c24xx_spi_initfiq(hw);
d1e778063   Ben Dooks   spi: spi_s3c24xx ...
519
  	/* setup the master state. */
e7db06b5d   David Brownell   spi: move more sp...
520
521
  	/* the spi->mode bits understood by this driver: */
  	master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH;
d1e778063   Ben Dooks   spi: spi_s3c24xx ...
522
  	master->num_chipselect = hw->pdata->num_cs;
cb1d0a7a5   Ben Dooks   spi_s3c24xx: real...
523
  	master->bus_num = pdata->bus_num;
d1e778063   Ben Dooks   spi: spi_s3c24xx ...
524

7fba53402   Ben Dooks   [PATCH] S3C24XX: ...
525
526
527
528
529
530
  	/* setup the state for the bitbang driver */
  
  	hw->bitbang.master         = hw->master;
  	hw->bitbang.setup_transfer = s3c24xx_spi_setupxfer;
  	hw->bitbang.chipselect     = s3c24xx_spi_chipsel;
  	hw->bitbang.txrx_bufs      = s3c24xx_spi_txrx;
570327d9f   Ben Dooks   spi_s3c24xx: cach...
531
532
533
  
  	hw->master->setup  = s3c24xx_spi_setup;
  	hw->master->cleanup = s3c24xx_spi_cleanup;
7fba53402   Ben Dooks   [PATCH] S3C24XX: ...
534
535
536
537
538
539
540
541
542
543
544
545
546
  
  	dev_dbg(hw->dev, "bitbang at %p
  ", &hw->bitbang);
  
  	/* find and map our resources */
  
  	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
  	if (res == NULL) {
  		dev_err(&pdev->dev, "Cannot get IORESOURCE_MEM
  ");
  		err = -ENOENT;
  		goto err_no_iores;
  	}
b5e3afb5e   Ben Dooks   spi_s3c24xx: use ...
547
  	hw->ioarea = request_mem_region(res->start, resource_size(res),
7fba53402   Ben Dooks   [PATCH] S3C24XX: ...
548
549
550
551
552
553
554
555
  					pdev->name);
  
  	if (hw->ioarea == NULL) {
  		dev_err(&pdev->dev, "Cannot reserve region
  ");
  		err = -ENXIO;
  		goto err_no_iores;
  	}
b5e3afb5e   Ben Dooks   spi_s3c24xx: use ...
556
  	hw->regs = ioremap(res->start, resource_size(res));
7fba53402   Ben Dooks   [PATCH] S3C24XX: ...
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
  	if (hw->regs == NULL) {
  		dev_err(&pdev->dev, "Cannot map IO
  ");
  		err = -ENXIO;
  		goto err_no_iomap;
  	}
  
  	hw->irq = platform_get_irq(pdev, 0);
  	if (hw->irq < 0) {
  		dev_err(&pdev->dev, "No IRQ specified
  ");
  		err = -ENOENT;
  		goto err_no_irq;
  	}
  
  	err = request_irq(hw->irq, s3c24xx_spi_irq, 0, pdev->name, hw);
  	if (err) {
  		dev_err(&pdev->dev, "Cannot claim IRQ
  ");
  		goto err_no_irq;
  	}
  
  	hw->clk = clk_get(&pdev->dev, "spi");
  	if (IS_ERR(hw->clk)) {
  		dev_err(&pdev->dev, "No clock for device
  ");
  		err = PTR_ERR(hw->clk);
  		goto err_no_clk;
  	}
7fba53402   Ben Dooks   [PATCH] S3C24XX: ...
586
  	/* setup any gpio we can */
50f426b55   Ben Dooks   spi: spi_s3c24xx ...
587
  	if (!pdata->set_cs) {
ee9c1fbfe   Ben Dooks   spi: use generic ...
588
589
590
591
592
  		if (pdata->pin_cs < 0) {
  			dev_err(&pdev->dev, "No chipselect pin
  ");
  			goto err_register;
  		}
8736b9270   Ben Dooks   [PATCH] S3C24XX: ...
593

ee9c1fbfe   Ben Dooks   spi: use generic ...
594
595
596
597
598
599
600
601
602
  		err = gpio_request(pdata->pin_cs, dev_name(&pdev->dev));
  		if (err) {
  			dev_err(&pdev->dev, "Failed to get gpio for cs
  ");
  			goto err_register;
  		}
  
  		hw->set_cs = s3c24xx_spi_gpiocs;
  		gpio_direction_output(pdata->pin_cs, 1);
8736b9270   Ben Dooks   [PATCH] S3C24XX: ...
603
  	} else
50f426b55   Ben Dooks   spi: spi_s3c24xx ...
604
  		hw->set_cs = pdata->set_cs;
7fba53402   Ben Dooks   [PATCH] S3C24XX: ...
605

ee9c1fbfe   Ben Dooks   spi: use generic ...
606
  	s3c24xx_spi_initialsetup(hw);
7fba53402   Ben Dooks   [PATCH] S3C24XX: ...
607
608
609
610
611
612
613
614
  	/* register our spi controller */
  
  	err = spi_bitbang_start(&hw->bitbang);
  	if (err) {
  		dev_err(&pdev->dev, "Failed to register SPI master
  ");
  		goto err_register;
  	}
7fba53402   Ben Dooks   [PATCH] S3C24XX: ...
615
616
617
  	return 0;
  
   err_register:
ee9c1fbfe   Ben Dooks   spi: use generic ...
618
619
  	if (hw->set_cs == s3c24xx_spi_gpiocs)
  		gpio_free(pdata->pin_cs);
7fba53402   Ben Dooks   [PATCH] S3C24XX: ...
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
  	clk_disable(hw->clk);
  	clk_put(hw->clk);
  
   err_no_clk:
  	free_irq(hw->irq, hw);
  
   err_no_irq:
  	iounmap(hw->regs);
  
   err_no_iomap:
  	release_resource(hw->ioarea);
  	kfree(hw->ioarea);
  
   err_no_iores:
   err_no_pdata:
a419aef8b   Joe Perches   trivial: remove u...
635
  	spi_master_put(hw->master);
7fba53402   Ben Dooks   [PATCH] S3C24XX: ...
636
637
638
639
  
   err_nomem:
  	return err;
  }
940ab8896   Grant Likely   drivercore: Add h...
640
  static int __devexit s3c24xx_spi_remove(struct platform_device *dev)
7fba53402   Ben Dooks   [PATCH] S3C24XX: ...
641
642
643
644
  {
  	struct s3c24xx_spi *hw = platform_get_drvdata(dev);
  
  	platform_set_drvdata(dev, NULL);
c6e7b8cb1   Axel Lin   spi/spi_s3c24xx: ...
645
  	spi_bitbang_stop(&hw->bitbang);
7fba53402   Ben Dooks   [PATCH] S3C24XX: ...
646
647
648
649
650
651
  
  	clk_disable(hw->clk);
  	clk_put(hw->clk);
  
  	free_irq(hw->irq, hw);
  	iounmap(hw->regs);
ee9c1fbfe   Ben Dooks   spi: use generic ...
652
653
  	if (hw->set_cs == s3c24xx_spi_gpiocs)
  		gpio_free(hw->pdata->pin_cs);
7fba53402   Ben Dooks   [PATCH] S3C24XX: ...
654
655
656
657
658
659
660
661
662
  	release_resource(hw->ioarea);
  	kfree(hw->ioarea);
  
  	spi_master_put(hw->master);
  	return 0;
  }
  
  
  #ifdef CONFIG_PM
6d6132070   Ben Dooks   spi_s3c24xx: use ...
663
  static int s3c24xx_spi_suspend(struct device *dev)
7fba53402   Ben Dooks   [PATCH] S3C24XX: ...
664
  {
6d6132070   Ben Dooks   spi_s3c24xx: use ...
665
  	struct s3c24xx_spi *hw = platform_get_drvdata(to_platform_device(dev));
7fba53402   Ben Dooks   [PATCH] S3C24XX: ...
666

cf46b973f   Ben Dooks   spi_s3c24xx: pin ...
667
668
  	if (hw->pdata && hw->pdata->gpio_setup)
  		hw->pdata->gpio_setup(hw->pdata, 0);
7fba53402   Ben Dooks   [PATCH] S3C24XX: ...
669
670
671
  	clk_disable(hw->clk);
  	return 0;
  }
6d6132070   Ben Dooks   spi_s3c24xx: use ...
672
  static int s3c24xx_spi_resume(struct device *dev)
7fba53402   Ben Dooks   [PATCH] S3C24XX: ...
673
  {
6d6132070   Ben Dooks   spi_s3c24xx: use ...
674
  	struct s3c24xx_spi *hw = platform_get_drvdata(to_platform_device(dev));
7fba53402   Ben Dooks   [PATCH] S3C24XX: ...
675

5aa6cf302   Ben Dooks   spi: S3C24XX: res...
676
  	s3c24xx_spi_initialsetup(hw);
7fba53402   Ben Dooks   [PATCH] S3C24XX: ...
677
678
  	return 0;
  }
471452104   Alexey Dobriyan   const: constify r...
679
  static const struct dev_pm_ops s3c24xx_spi_pmops = {
6d6132070   Ben Dooks   spi_s3c24xx: use ...
680
681
682
683
684
  	.suspend	= s3c24xx_spi_suspend,
  	.resume		= s3c24xx_spi_resume,
  };
  
  #define S3C24XX_SPI_PMOPS &s3c24xx_spi_pmops
7fba53402   Ben Dooks   [PATCH] S3C24XX: ...
685
  #else
6d6132070   Ben Dooks   spi_s3c24xx: use ...
686
687
  #define S3C24XX_SPI_PMOPS NULL
  #endif /* CONFIG_PM */
7fba53402   Ben Dooks   [PATCH] S3C24XX: ...
688

7e38c3c44   Kay Sievers   spi: fix platform...
689
  MODULE_ALIAS("platform:s3c2410-spi");
42cde4309   Ben Dooks   spi_s3c24xx: fix ...
690
  static struct platform_driver s3c24xx_spi_driver = {
940ab8896   Grant Likely   drivercore: Add h...
691
692
  	.probe		= s3c24xx_spi_probe,
  	.remove		= __devexit_p(s3c24xx_spi_remove),
7fba53402   Ben Dooks   [PATCH] S3C24XX: ...
693
694
695
  	.driver		= {
  		.name	= "s3c2410-spi",
  		.owner	= THIS_MODULE,
6d6132070   Ben Dooks   spi_s3c24xx: use ...
696
  		.pm	= S3C24XX_SPI_PMOPS,
7fba53402   Ben Dooks   [PATCH] S3C24XX: ...
697
698
  	},
  };
940ab8896   Grant Likely   drivercore: Add h...
699
  module_platform_driver(s3c24xx_spi_driver);
7fba53402   Ben Dooks   [PATCH] S3C24XX: ...
700
701
702
703
  
  MODULE_DESCRIPTION("S3C24XX SPI Driver");
  MODULE_AUTHOR("Ben Dooks, <ben@simtec.co.uk>");
  MODULE_LICENSE("GPL");