Blame view

drivers/spi/spi-sh-msiof.c 17.3 KB
8051effcb   Magnus Damm   spi: SuperH MSIOF...
1
2
3
4
5
6
7
8
9
10
  /*
   * SuperH MSIOF SPI Master Interface
   *
   * Copyright (c) 2009 Magnus Damm
   *
   * 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.
   *
   */
e2dbf5ebc   Guennadi Liakhovetski   spi/spi_sh_msiof:...
11
12
13
  #include <linux/bitmap.h>
  #include <linux/clk.h>
  #include <linux/completion.h>
8051effcb   Magnus Damm   spi: SuperH MSIOF...
14
  #include <linux/delay.h>
e2dbf5ebc   Guennadi Liakhovetski   spi/spi_sh_msiof:...
15
16
17
  #include <linux/err.h>
  #include <linux/gpio.h>
  #include <linux/init.h>
8051effcb   Magnus Damm   spi: SuperH MSIOF...
18
  #include <linux/interrupt.h>
e2dbf5ebc   Guennadi Liakhovetski   spi/spi_sh_msiof:...
19
20
  #include <linux/io.h>
  #include <linux/kernel.h>
d7614de42   Paul Gortmaker   spi: Add module.h...
21
  #include <linux/module.h>
8051effcb   Magnus Damm   spi: SuperH MSIOF...
22
  #include <linux/platform_device.h>
8051effcb   Magnus Damm   spi: SuperH MSIOF...
23
  #include <linux/pm_runtime.h>
8051effcb   Magnus Damm   spi: SuperH MSIOF...
24

e2dbf5ebc   Guennadi Liakhovetski   spi/spi_sh_msiof:...
25
  #include <linux/spi/sh_msiof.h>
8051effcb   Magnus Damm   spi: SuperH MSIOF...
26
27
  #include <linux/spi/spi.h>
  #include <linux/spi/spi_bitbang.h>
8051effcb   Magnus Damm   spi: SuperH MSIOF...
28

8051effcb   Magnus Damm   spi: SuperH MSIOF...
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
  #include <asm/unaligned.h>
  
  struct sh_msiof_spi_priv {
  	struct spi_bitbang bitbang; /* must be first for spi_bitbang.c */
  	void __iomem *mapbase;
  	struct clk *clk;
  	struct platform_device *pdev;
  	struct sh_msiof_spi_info *info;
  	struct completion done;
  	unsigned long flags;
  	int tx_fifo_size;
  	int rx_fifo_size;
  };
  
  #define TMDR1	0x00
  #define TMDR2	0x04
  #define TMDR3	0x08
  #define RMDR1	0x10
  #define RMDR2	0x14
  #define RMDR3	0x18
  #define TSCR	0x20
  #define RSCR	0x22
  #define CTR	0x28
  #define FCTR	0x30
  #define STR	0x40
  #define IER	0x44
  #define TDR1	0x48
  #define TDR2	0x4c
  #define TFDR	0x50
  #define RDR1	0x58
  #define RDR2	0x5c
  #define RFDR	0x60
  
  #define CTR_TSCKE (1 << 15)
  #define CTR_TFSE  (1 << 14)
  #define CTR_TXE   (1 << 9)
  #define CTR_RXE   (1 << 8)
  
  #define STR_TEOF  (1 << 23)
  #define STR_REOF  (1 << 7)
e2dbf5ebc   Guennadi Liakhovetski   spi/spi_sh_msiof:...
69
  static u32 sh_msiof_read(struct sh_msiof_spi_priv *p, int reg_offs)
8051effcb   Magnus Damm   spi: SuperH MSIOF...
70
71
72
73
74
75
76
77
78
79
80
  {
  	switch (reg_offs) {
  	case TSCR:
  	case RSCR:
  		return ioread16(p->mapbase + reg_offs);
  	default:
  		return ioread32(p->mapbase + reg_offs);
  	}
  }
  
  static void sh_msiof_write(struct sh_msiof_spi_priv *p, int reg_offs,
e2dbf5ebc   Guennadi Liakhovetski   spi/spi_sh_msiof:...
81
  			   u32 value)
8051effcb   Magnus Damm   spi: SuperH MSIOF...
82
83
84
85
86
87
88
89
90
91
92
93
94
  {
  	switch (reg_offs) {
  	case TSCR:
  	case RSCR:
  		iowrite16(value, p->mapbase + reg_offs);
  		break;
  	default:
  		iowrite32(value, p->mapbase + reg_offs);
  		break;
  	}
  }
  
  static int sh_msiof_modify_ctr_wait(struct sh_msiof_spi_priv *p,
e2dbf5ebc   Guennadi Liakhovetski   spi/spi_sh_msiof:...
95
  				    u32 clr, u32 set)
8051effcb   Magnus Damm   spi: SuperH MSIOF...
96
  {
e2dbf5ebc   Guennadi Liakhovetski   spi/spi_sh_msiof:...
97
98
  	u32 mask = clr | set;
  	u32 data;
8051effcb   Magnus Damm   spi: SuperH MSIOF...
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
  	int k;
  
  	data = sh_msiof_read(p, CTR);
  	data &= ~clr;
  	data |= set;
  	sh_msiof_write(p, CTR, data);
  
  	for (k = 100; k > 0; k--) {
  		if ((sh_msiof_read(p, CTR) & mask) == set)
  			break;
  
  		udelay(10);
  	}
  
  	return k > 0 ? 0 : -ETIMEDOUT;
  }
  
  static irqreturn_t sh_msiof_spi_irq(int irq, void *data)
  {
  	struct sh_msiof_spi_priv *p = data;
  
  	/* just disable the interrupt and wake up */
  	sh_msiof_write(p, IER, 0);
  	complete(&p->done);
  
  	return IRQ_HANDLED;
  }
  
  static struct {
  	unsigned short div;
  	unsigned short scr;
  } const sh_msiof_spi_clk_table[] = {
  	{ 1, 0x0007 },
  	{ 2, 0x0000 },
  	{ 4, 0x0001 },
  	{ 8, 0x0002 },
  	{ 16, 0x0003 },
  	{ 32, 0x0004 },
  	{ 64, 0x1f00 },
  	{ 128, 0x1f01 },
  	{ 256, 0x1f02 },
  	{ 512, 0x1f03 },
  	{ 1024, 0x1f04 },
  };
  
  static void sh_msiof_spi_set_clk_regs(struct sh_msiof_spi_priv *p,
  				      unsigned long parent_rate,
  				      unsigned long spi_hz)
  {
  	unsigned long div = 1024;
  	size_t k;
  
  	if (!WARN_ON(!spi_hz || !parent_rate))
  		div = parent_rate / spi_hz;
  
  	/* TODO: make more fine grained */
  
  	for (k = 0; k < ARRAY_SIZE(sh_msiof_spi_clk_table); k++) {
  		if (sh_msiof_spi_clk_table[k].div >= div)
  			break;
  	}
  
  	k = min_t(int, k, ARRAY_SIZE(sh_msiof_spi_clk_table) - 1);
  
  	sh_msiof_write(p, TSCR, sh_msiof_spi_clk_table[k].scr);
  	sh_msiof_write(p, RSCR, sh_msiof_spi_clk_table[k].scr);
  }
  
  static void sh_msiof_spi_set_pin_regs(struct sh_msiof_spi_priv *p,
e2dbf5ebc   Guennadi Liakhovetski   spi/spi_sh_msiof:...
168
169
  				      u32 cpol, u32 cpha,
  				      u32 tx_hi_z, u32 lsb_first)
8051effcb   Magnus Damm   spi: SuperH MSIOF...
170
  {
e2dbf5ebc   Guennadi Liakhovetski   spi/spi_sh_msiof:...
171
  	u32 tmp;
8051effcb   Magnus Damm   spi: SuperH MSIOF...
172
173
174
  	int edge;
  
  	/*
e8708ef7e   Markus Pietrek   spi: spi_sh_msiof...
175
176
177
178
179
  	 * CPOL CPHA     TSCKIZ RSCKIZ TEDG REDG
  	 *    0    0         10     10    1    1
  	 *    0    1         10     10    0    0
  	 *    1    0         11     11    0    0
  	 *    1    1         11     11    1    1
8051effcb   Magnus Damm   spi: SuperH MSIOF...
180
  	 */
8051effcb   Magnus Damm   spi: SuperH MSIOF...
181
182
183
184
185
186
187
  	sh_msiof_write(p, FCTR, 0);
  	sh_msiof_write(p, TMDR1, 0xe2000005 | (lsb_first << 24));
  	sh_msiof_write(p, RMDR1, 0x22000005 | (lsb_first << 24));
  
  	tmp = 0xa0000000;
  	tmp |= cpol << 30; /* TSCKIZ */
  	tmp |= cpol << 28; /* RSCKIZ */
e2dbf5ebc   Guennadi Liakhovetski   spi/spi_sh_msiof:...
188
  	edge = cpol ^ !cpha;
8051effcb   Magnus Damm   spi: SuperH MSIOF...
189
190
  
  	tmp |= edge << 27; /* TEDG */
e8708ef7e   Markus Pietrek   spi: spi_sh_msiof...
191
  	tmp |= edge << 26; /* REDG */
8051effcb   Magnus Damm   spi: SuperH MSIOF...
192
193
194
195
196
197
  	tmp |= (tx_hi_z ? 2 : 0) << 22; /* TXDIZ */
  	sh_msiof_write(p, CTR, tmp);
  }
  
  static void sh_msiof_spi_set_mode_regs(struct sh_msiof_spi_priv *p,
  				       const void *tx_buf, void *rx_buf,
e2dbf5ebc   Guennadi Liakhovetski   spi/spi_sh_msiof:...
198
  				       u32 bits, u32 words)
8051effcb   Magnus Damm   spi: SuperH MSIOF...
199
  {
e2dbf5ebc   Guennadi Liakhovetski   spi/spi_sh_msiof:...
200
  	u32 dr2 = ((bits - 1) << 24) | ((words - 1) << 16);
8051effcb   Magnus Damm   spi: SuperH MSIOF...
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
  
  	if (tx_buf)
  		sh_msiof_write(p, TMDR2, dr2);
  	else
  		sh_msiof_write(p, TMDR2, dr2 | 1);
  
  	if (rx_buf)
  		sh_msiof_write(p, RMDR2, dr2);
  
  	sh_msiof_write(p, IER, STR_TEOF | STR_REOF);
  }
  
  static void sh_msiof_reset_str(struct sh_msiof_spi_priv *p)
  {
  	sh_msiof_write(p, STR, sh_msiof_read(p, STR));
  }
  
  static void sh_msiof_spi_write_fifo_8(struct sh_msiof_spi_priv *p,
  				      const void *tx_buf, int words, int fs)
  {
e2dbf5ebc   Guennadi Liakhovetski   spi/spi_sh_msiof:...
221
  	const u8 *buf_8 = tx_buf;
8051effcb   Magnus Damm   spi: SuperH MSIOF...
222
223
224
225
226
227
228
229
230
  	int k;
  
  	for (k = 0; k < words; k++)
  		sh_msiof_write(p, TFDR, buf_8[k] << fs);
  }
  
  static void sh_msiof_spi_write_fifo_16(struct sh_msiof_spi_priv *p,
  				       const void *tx_buf, int words, int fs)
  {
e2dbf5ebc   Guennadi Liakhovetski   spi/spi_sh_msiof:...
231
  	const u16 *buf_16 = tx_buf;
8051effcb   Magnus Damm   spi: SuperH MSIOF...
232
233
234
235
236
237
238
239
240
  	int k;
  
  	for (k = 0; k < words; k++)
  		sh_msiof_write(p, TFDR, buf_16[k] << fs);
  }
  
  static void sh_msiof_spi_write_fifo_16u(struct sh_msiof_spi_priv *p,
  					const void *tx_buf, int words, int fs)
  {
e2dbf5ebc   Guennadi Liakhovetski   spi/spi_sh_msiof:...
241
  	const u16 *buf_16 = tx_buf;
8051effcb   Magnus Damm   spi: SuperH MSIOF...
242
243
244
245
246
247
248
249
250
  	int k;
  
  	for (k = 0; k < words; k++)
  		sh_msiof_write(p, TFDR, get_unaligned(&buf_16[k]) << fs);
  }
  
  static void sh_msiof_spi_write_fifo_32(struct sh_msiof_spi_priv *p,
  				       const void *tx_buf, int words, int fs)
  {
e2dbf5ebc   Guennadi Liakhovetski   spi/spi_sh_msiof:...
251
  	const u32 *buf_32 = tx_buf;
8051effcb   Magnus Damm   spi: SuperH MSIOF...
252
253
254
255
256
257
258
259
260
  	int k;
  
  	for (k = 0; k < words; k++)
  		sh_msiof_write(p, TFDR, buf_32[k] << fs);
  }
  
  static void sh_msiof_spi_write_fifo_32u(struct sh_msiof_spi_priv *p,
  					const void *tx_buf, int words, int fs)
  {
e2dbf5ebc   Guennadi Liakhovetski   spi/spi_sh_msiof:...
261
  	const u32 *buf_32 = tx_buf;
8051effcb   Magnus Damm   spi: SuperH MSIOF...
262
263
264
265
266
  	int k;
  
  	for (k = 0; k < words; k++)
  		sh_msiof_write(p, TFDR, get_unaligned(&buf_32[k]) << fs);
  }
9dabb3f32   Guennadi Liakhovetski   spi/spi_sh_msiof:...
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
  static void sh_msiof_spi_write_fifo_s32(struct sh_msiof_spi_priv *p,
  					const void *tx_buf, int words, int fs)
  {
  	const u32 *buf_32 = tx_buf;
  	int k;
  
  	for (k = 0; k < words; k++)
  		sh_msiof_write(p, TFDR, swab32(buf_32[k] << fs));
  }
  
  static void sh_msiof_spi_write_fifo_s32u(struct sh_msiof_spi_priv *p,
  					 const void *tx_buf, int words, int fs)
  {
  	const u32 *buf_32 = tx_buf;
  	int k;
  
  	for (k = 0; k < words; k++)
  		sh_msiof_write(p, TFDR, swab32(get_unaligned(&buf_32[k]) << fs));
  }
8051effcb   Magnus Damm   spi: SuperH MSIOF...
286
287
288
  static void sh_msiof_spi_read_fifo_8(struct sh_msiof_spi_priv *p,
  				     void *rx_buf, int words, int fs)
  {
e2dbf5ebc   Guennadi Liakhovetski   spi/spi_sh_msiof:...
289
  	u8 *buf_8 = rx_buf;
8051effcb   Magnus Damm   spi: SuperH MSIOF...
290
291
292
293
294
295
296
297
298
  	int k;
  
  	for (k = 0; k < words; k++)
  		buf_8[k] = sh_msiof_read(p, RFDR) >> fs;
  }
  
  static void sh_msiof_spi_read_fifo_16(struct sh_msiof_spi_priv *p,
  				      void *rx_buf, int words, int fs)
  {
e2dbf5ebc   Guennadi Liakhovetski   spi/spi_sh_msiof:...
299
  	u16 *buf_16 = rx_buf;
8051effcb   Magnus Damm   spi: SuperH MSIOF...
300
301
302
303
304
305
306
307
308
  	int k;
  
  	for (k = 0; k < words; k++)
  		buf_16[k] = sh_msiof_read(p, RFDR) >> fs;
  }
  
  static void sh_msiof_spi_read_fifo_16u(struct sh_msiof_spi_priv *p,
  				       void *rx_buf, int words, int fs)
  {
e2dbf5ebc   Guennadi Liakhovetski   spi/spi_sh_msiof:...
309
  	u16 *buf_16 = rx_buf;
8051effcb   Magnus Damm   spi: SuperH MSIOF...
310
311
312
313
314
315
316
317
318
  	int k;
  
  	for (k = 0; k < words; k++)
  		put_unaligned(sh_msiof_read(p, RFDR) >> fs, &buf_16[k]);
  }
  
  static void sh_msiof_spi_read_fifo_32(struct sh_msiof_spi_priv *p,
  				      void *rx_buf, int words, int fs)
  {
e2dbf5ebc   Guennadi Liakhovetski   spi/spi_sh_msiof:...
319
  	u32 *buf_32 = rx_buf;
8051effcb   Magnus Damm   spi: SuperH MSIOF...
320
321
322
323
324
325
326
327
328
  	int k;
  
  	for (k = 0; k < words; k++)
  		buf_32[k] = sh_msiof_read(p, RFDR) >> fs;
  }
  
  static void sh_msiof_spi_read_fifo_32u(struct sh_msiof_spi_priv *p,
  				       void *rx_buf, int words, int fs)
  {
e2dbf5ebc   Guennadi Liakhovetski   spi/spi_sh_msiof:...
329
  	u32 *buf_32 = rx_buf;
8051effcb   Magnus Damm   spi: SuperH MSIOF...
330
331
332
333
334
  	int k;
  
  	for (k = 0; k < words; k++)
  		put_unaligned(sh_msiof_read(p, RFDR) >> fs, &buf_32[k]);
  }
9dabb3f32   Guennadi Liakhovetski   spi/spi_sh_msiof:...
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
  static void sh_msiof_spi_read_fifo_s32(struct sh_msiof_spi_priv *p,
  				       void *rx_buf, int words, int fs)
  {
  	u32 *buf_32 = rx_buf;
  	int k;
  
  	for (k = 0; k < words; k++)
  		buf_32[k] = swab32(sh_msiof_read(p, RFDR) >> fs);
  }
  
  static void sh_msiof_spi_read_fifo_s32u(struct sh_msiof_spi_priv *p,
  				       void *rx_buf, int words, int fs)
  {
  	u32 *buf_32 = rx_buf;
  	int k;
  
  	for (k = 0; k < words; k++)
  		put_unaligned(swab32(sh_msiof_read(p, RFDR) >> fs), &buf_32[k]);
  }
8051effcb   Magnus Damm   spi: SuperH MSIOF...
354
355
356
357
358
  static int sh_msiof_spi_bits(struct spi_device *spi, struct spi_transfer *t)
  {
  	int bits;
  
  	bits = t ? t->bits_per_word : 0;
e2dbf5ebc   Guennadi Liakhovetski   spi/spi_sh_msiof:...
359
360
  	if (!bits)
  		bits = spi->bits_per_word;
8051effcb   Magnus Damm   spi: SuperH MSIOF...
361
362
363
364
365
366
367
368
369
  	return bits;
  }
  
  static unsigned long sh_msiof_spi_hz(struct spi_device *spi,
  				     struct spi_transfer *t)
  {
  	unsigned long hz;
  
  	hz = t ? t->speed_hz : 0;
e2dbf5ebc   Guennadi Liakhovetski   spi/spi_sh_msiof:...
370
371
  	if (!hz)
  		hz = spi->max_speed_hz;
8051effcb   Magnus Damm   spi: SuperH MSIOF...
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
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
  	return hz;
  }
  
  static int sh_msiof_spi_setup_transfer(struct spi_device *spi,
  				       struct spi_transfer *t)
  {
  	int bits;
  
  	/* noting to check hz values against since parent clock is disabled */
  
  	bits = sh_msiof_spi_bits(spi, t);
  	if (bits < 8)
  		return -EINVAL;
  	if (bits > 32)
  		return -EINVAL;
  
  	return spi_bitbang_setup_transfer(spi, t);
  }
  
  static void sh_msiof_spi_chipselect(struct spi_device *spi, int is_on)
  {
  	struct sh_msiof_spi_priv *p = spi_master_get_devdata(spi->master);
  	int value;
  
  	/* chip select is active low unless SPI_CS_HIGH is set */
  	if (spi->mode & SPI_CS_HIGH)
  		value = (is_on == BITBANG_CS_ACTIVE) ? 1 : 0;
  	else
  		value = (is_on == BITBANG_CS_ACTIVE) ? 0 : 1;
  
  	if (is_on == BITBANG_CS_ACTIVE) {
  		if (!test_and_set_bit(0, &p->flags)) {
  			pm_runtime_get_sync(&p->pdev->dev);
  			clk_enable(p->clk);
  		}
  
  		/* Configure pins before asserting CS */
  		sh_msiof_spi_set_pin_regs(p, !!(spi->mode & SPI_CPOL),
  					  !!(spi->mode & SPI_CPHA),
  					  !!(spi->mode & SPI_3WIRE),
  					  !!(spi->mode & SPI_LSB_FIRST));
  	}
  
  	/* use spi->controller data for CS (same strategy as spi_gpio) */
  	gpio_set_value((unsigned)spi->controller_data, value);
  
  	if (is_on == BITBANG_CS_INACTIVE) {
  		if (test_and_clear_bit(0, &p->flags)) {
  			clk_disable(p->clk);
  			pm_runtime_put(&p->pdev->dev);
  		}
  	}
  }
  
  static int sh_msiof_spi_txrx_once(struct sh_msiof_spi_priv *p,
  				  void (*tx_fifo)(struct sh_msiof_spi_priv *,
  						  const void *, int, int),
  				  void (*rx_fifo)(struct sh_msiof_spi_priv *,
  						  void *, int, int),
  				  const void *tx_buf, void *rx_buf,
  				  int words, int bits)
  {
  	int fifo_shift;
  	int ret;
  
  	/* limit maximum word transfer to rx/tx fifo size */
  	if (tx_buf)
  		words = min_t(int, words, p->tx_fifo_size);
  	if (rx_buf)
  		words = min_t(int, words, p->rx_fifo_size);
  
  	/* the fifo contents need shifting */
  	fifo_shift = 32 - bits;
  
  	/* setup msiof transfer mode registers */
  	sh_msiof_spi_set_mode_regs(p, tx_buf, rx_buf, bits, words);
  
  	/* write tx fifo */
  	if (tx_buf)
  		tx_fifo(p, tx_buf, words, fifo_shift);
  
  	/* setup clock and rx/tx signals */
  	ret = sh_msiof_modify_ctr_wait(p, 0, CTR_TSCKE);
  	if (rx_buf)
  		ret = ret ? ret : sh_msiof_modify_ctr_wait(p, 0, CTR_RXE);
  	ret = ret ? ret : sh_msiof_modify_ctr_wait(p, 0, CTR_TXE);
  
  	/* start by setting frame bit */
  	INIT_COMPLETION(p->done);
  	ret = ret ? ret : sh_msiof_modify_ctr_wait(p, 0, CTR_TFSE);
  	if (ret) {
  		dev_err(&p->pdev->dev, "failed to start hardware
  ");
  		goto err;
  	}
  
  	/* wait for tx fifo to be emptied / rx fifo to be filled */
  	wait_for_completion(&p->done);
  
  	/* read rx fifo */
  	if (rx_buf)
  		rx_fifo(p, rx_buf, words, fifo_shift);
  
  	/* clear status bits */
  	sh_msiof_reset_str(p);
  
  	/* shut down frame, tx/tx and clock signals */
  	ret = sh_msiof_modify_ctr_wait(p, CTR_TFSE, 0);
  	ret = ret ? ret : sh_msiof_modify_ctr_wait(p, CTR_TXE, 0);
  	if (rx_buf)
  		ret = ret ? ret : sh_msiof_modify_ctr_wait(p, CTR_RXE, 0);
  	ret = ret ? ret : sh_msiof_modify_ctr_wait(p, CTR_TSCKE, 0);
  	if (ret) {
  		dev_err(&p->pdev->dev, "failed to shut down hardware
  ");
  		goto err;
  	}
  
  	return words;
  
   err:
  	sh_msiof_write(p, IER, 0);
  	return ret;
  }
  
  static int sh_msiof_spi_txrx(struct spi_device *spi, struct spi_transfer *t)
  {
  	struct sh_msiof_spi_priv *p = spi_master_get_devdata(spi->master);
  	void (*tx_fifo)(struct sh_msiof_spi_priv *, const void *, int, int);
  	void (*rx_fifo)(struct sh_msiof_spi_priv *, void *, int, int);
  	int bits;
  	int bytes_per_word;
  	int bytes_done;
  	int words;
  	int n;
9dabb3f32   Guennadi Liakhovetski   spi/spi_sh_msiof:...
507
  	bool swab;
8051effcb   Magnus Damm   spi: SuperH MSIOF...
508
509
  
  	bits = sh_msiof_spi_bits(spi, t);
9dabb3f32   Guennadi Liakhovetski   spi/spi_sh_msiof:...
510
511
512
513
514
515
  	if (bits <= 8 && t->len > 15 && !(t->len & 3)) {
  		bits = 32;
  		swab = true;
  	} else {
  		swab = false;
  	}
8051effcb   Magnus Damm   spi: SuperH MSIOF...
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
  	/* setup bytes per word and fifo read/write functions */
  	if (bits <= 8) {
  		bytes_per_word = 1;
  		tx_fifo = sh_msiof_spi_write_fifo_8;
  		rx_fifo = sh_msiof_spi_read_fifo_8;
  	} else if (bits <= 16) {
  		bytes_per_word = 2;
  		if ((unsigned long)t->tx_buf & 0x01)
  			tx_fifo = sh_msiof_spi_write_fifo_16u;
  		else
  			tx_fifo = sh_msiof_spi_write_fifo_16;
  
  		if ((unsigned long)t->rx_buf & 0x01)
  			rx_fifo = sh_msiof_spi_read_fifo_16u;
  		else
  			rx_fifo = sh_msiof_spi_read_fifo_16;
9dabb3f32   Guennadi Liakhovetski   spi/spi_sh_msiof:...
532
533
534
535
536
537
538
539
540
541
542
  	} else if (swab) {
  		bytes_per_word = 4;
  		if ((unsigned long)t->tx_buf & 0x03)
  			tx_fifo = sh_msiof_spi_write_fifo_s32u;
  		else
  			tx_fifo = sh_msiof_spi_write_fifo_s32;
  
  		if ((unsigned long)t->rx_buf & 0x03)
  			rx_fifo = sh_msiof_spi_read_fifo_s32u;
  		else
  			rx_fifo = sh_msiof_spi_read_fifo_s32;
8051effcb   Magnus Damm   spi: SuperH MSIOF...
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
  	} else {
  		bytes_per_word = 4;
  		if ((unsigned long)t->tx_buf & 0x03)
  			tx_fifo = sh_msiof_spi_write_fifo_32u;
  		else
  			tx_fifo = sh_msiof_spi_write_fifo_32;
  
  		if ((unsigned long)t->rx_buf & 0x03)
  			rx_fifo = sh_msiof_spi_read_fifo_32u;
  		else
  			rx_fifo = sh_msiof_spi_read_fifo_32;
  	}
  
  	/* setup clocks (clock already enabled in chipselect()) */
  	sh_msiof_spi_set_clk_regs(p, clk_get_rate(p->clk),
  				  sh_msiof_spi_hz(spi, t));
  
  	/* transfer in fifo sized chunks */
  	words = t->len / bytes_per_word;
  	bytes_done = 0;
  
  	while (bytes_done < t->len) {
8a6afb9a9   Guennadi Liakhovetski   spi/spi_sh_msiof:...
565
566
  		void *rx_buf = t->rx_buf ? t->rx_buf + bytes_done : NULL;
  		const void *tx_buf = t->tx_buf ? t->tx_buf + bytes_done : NULL;
8051effcb   Magnus Damm   spi: SuperH MSIOF...
567
  		n = sh_msiof_spi_txrx_once(p, tx_fifo, rx_fifo,
8a6afb9a9   Guennadi Liakhovetski   spi/spi_sh_msiof:...
568
569
  					   tx_buf,
  					   rx_buf,
8051effcb   Magnus Damm   spi: SuperH MSIOF...
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
  					   words, bits);
  		if (n < 0)
  			break;
  
  		bytes_done += n * bytes_per_word;
  		words -= n;
  	}
  
  	return bytes_done;
  }
  
  static u32 sh_msiof_spi_txrx_word(struct spi_device *spi, unsigned nsecs,
  				  u32 word, u8 bits)
  {
  	BUG(); /* unused but needed by bitbang code */
  	return 0;
  }
  
  static int sh_msiof_spi_probe(struct platform_device *pdev)
  {
  	struct resource	*r;
  	struct spi_master *master;
  	struct sh_msiof_spi_priv *p;
  	char clk_name[16];
  	int i;
  	int ret;
  
  	master = spi_alloc_master(&pdev->dev, sizeof(struct sh_msiof_spi_priv));
  	if (master == NULL) {
  		dev_err(&pdev->dev, "failed to allocate spi master
  ");
  		ret = -ENOMEM;
  		goto err0;
  	}
  
  	p = spi_master_get_devdata(master);
  
  	platform_set_drvdata(pdev, p);
  	p->info = pdev->dev.platform_data;
  	init_completion(&p->done);
  
  	snprintf(clk_name, sizeof(clk_name), "msiof%d", pdev->id);
  	p->clk = clk_get(&pdev->dev, clk_name);
  	if (IS_ERR(p->clk)) {
  		dev_err(&pdev->dev, "cannot get clock \"%s\"
  ", clk_name);
  		ret = PTR_ERR(p->clk);
  		goto err1;
  	}
  
  	r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
  	i = platform_get_irq(pdev, 0);
  	if (!r || i < 0) {
  		dev_err(&pdev->dev, "cannot get platform resources
  ");
  		ret = -ENOENT;
  		goto err2;
  	}
  	p->mapbase = ioremap_nocache(r->start, resource_size(r));
  	if (!p->mapbase) {
  		dev_err(&pdev->dev, "unable to ioremap
  ");
  		ret = -ENXIO;
  		goto err2;
  	}
38ada214f   Yong Zhang   spi: irq: Remove ...
635
  	ret = request_irq(i, sh_msiof_spi_irq, 0,
8051effcb   Magnus Damm   spi: SuperH MSIOF...
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
  			  dev_name(&pdev->dev), p);
  	if (ret) {
  		dev_err(&pdev->dev, "unable to request irq
  ");
  		goto err3;
  	}
  
  	p->pdev = pdev;
  	pm_runtime_enable(&pdev->dev);
  
  	/* The standard version of MSIOF use 64 word FIFOs */
  	p->tx_fifo_size = 64;
  	p->rx_fifo_size = 64;
  
  	/* Platform data may override FIFO sizes */
  	if (p->info->tx_fifo_override)
  		p->tx_fifo_size = p->info->tx_fifo_override;
  	if (p->info->rx_fifo_override)
  		p->rx_fifo_size = p->info->rx_fifo_override;
  
  	/* init master and bitbang code */
  	master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH;
  	master->mode_bits |= SPI_LSB_FIRST | SPI_3WIRE;
  	master->flags = 0;
  	master->bus_num = pdev->id;
  	master->num_chipselect = p->info->num_chipselect;
  	master->setup = spi_bitbang_setup;
  	master->cleanup = spi_bitbang_cleanup;
  
  	p->bitbang.master = master;
  	p->bitbang.chipselect = sh_msiof_spi_chipselect;
  	p->bitbang.setup_transfer = sh_msiof_spi_setup_transfer;
  	p->bitbang.txrx_bufs = sh_msiof_spi_txrx;
  	p->bitbang.txrx_word[SPI_MODE_0] = sh_msiof_spi_txrx_word;
  	p->bitbang.txrx_word[SPI_MODE_1] = sh_msiof_spi_txrx_word;
  	p->bitbang.txrx_word[SPI_MODE_2] = sh_msiof_spi_txrx_word;
  	p->bitbang.txrx_word[SPI_MODE_3] = sh_msiof_spi_txrx_word;
  
  	ret = spi_bitbang_start(&p->bitbang);
  	if (ret == 0)
  		return 0;
  
  	pm_runtime_disable(&pdev->dev);
   err3:
  	iounmap(p->mapbase);
   err2:
  	clk_put(p->clk);
   err1:
  	spi_master_put(master);
   err0:
  	return ret;
  }
  
  static int sh_msiof_spi_remove(struct platform_device *pdev)
  {
  	struct sh_msiof_spi_priv *p = platform_get_drvdata(pdev);
  	int ret;
  
  	ret = spi_bitbang_stop(&p->bitbang);
  	if (!ret) {
  		pm_runtime_disable(&pdev->dev);
d95defaca   Guennadi Liakhovetski   spi/spi_sh_msiof:...
697
  		free_irq(platform_get_irq(pdev, 0), p);
8051effcb   Magnus Damm   spi: SuperH MSIOF...
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
  		iounmap(p->mapbase);
  		clk_put(p->clk);
  		spi_master_put(p->bitbang.master);
  	}
  	return ret;
  }
  
  static int sh_msiof_spi_runtime_nop(struct device *dev)
  {
  	/* Runtime PM callback shared between ->runtime_suspend()
  	 * and ->runtime_resume(). Simply returns success.
  	 *
  	 * This driver re-initializes all registers after
  	 * pm_runtime_get_sync() anyway so there is no need
  	 * to save and restore registers here.
  	 */
  	return 0;
  }
  
  static struct dev_pm_ops sh_msiof_spi_dev_pm_ops = {
  	.runtime_suspend = sh_msiof_spi_runtime_nop,
  	.runtime_resume = sh_msiof_spi_runtime_nop,
  };
  
  static struct platform_driver sh_msiof_spi_drv = {
  	.probe		= sh_msiof_spi_probe,
  	.remove		= sh_msiof_spi_remove,
  	.driver		= {
  		.name		= "spi_sh_msiof",
  		.owner		= THIS_MODULE,
  		.pm		= &sh_msiof_spi_dev_pm_ops,
  	},
  };
940ab8896   Grant Likely   drivercore: Add h...
731
  module_platform_driver(sh_msiof_spi_drv);
8051effcb   Magnus Damm   spi: SuperH MSIOF...
732
733
734
735
736
  
  MODULE_DESCRIPTION("SuperH MSIOF SPI Master Interface Driver");
  MODULE_AUTHOR("Magnus Damm");
  MODULE_LICENSE("GPL v2");
  MODULE_ALIAS("platform:spi_sh_msiof");