Blame view

drivers/spi/spi-omap-uwire.c 12.4 KB
fdb3c18d6   David Brownell   [PATCH] SPI contr...
1
  /*
ca632f556   Grant Likely   spi: reorganize d...
2
   * MicroWire interface driver for OMAP
fdb3c18d6   David Brownell   [PATCH] SPI contr...
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
   *
   * Copyright 2003 MontaVista Software Inc. <source@mvista.com>
   *
   * Ported to 2.6 OMAP uwire interface.
   * Copyright (C) 2004 Texas Instruments.
   *
   * Generalization patches by Juha Yrjola <juha.yrjola@nokia.com>
   *
   * Copyright (C) 2005 David Brownell (ported to 2.6 SPI interface)
   * Copyright (C) 2006 Nokia
   *
   * Many updates by Imre Deak <imre.deak@nokia.com>
   *
   * This program is free software; you can redistribute it and/or modify it
   * under the terms of the GNU General Public License as published by the
   * Free Software Foundation; either version 2 of the License, or (at your
   * option) any later version.
   *
   * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
   * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
   * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
   * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
   * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
   * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
   * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
   * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
   * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
   * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
fdb3c18d6   David Brownell   [PATCH] SPI contr...
31
32
33
34
35
   */
  #include <linux/kernel.h>
  #include <linux/init.h>
  #include <linux/delay.h>
  #include <linux/platform_device.h>
fdb3c18d6   David Brownell   [PATCH] SPI contr...
36
37
38
  #include <linux/interrupt.h>
  #include <linux/err.h>
  #include <linux/clk.h>
5a0e3ad6a   Tejun Heo   include cleanup: ...
39
  #include <linux/slab.h>
1820a8fc8   Mark Brown   spi: omap-uwire: ...
40
  #include <linux/device.h>
fdb3c18d6   David Brownell   [PATCH] SPI contr...
41
42
43
  
  #include <linux/spi/spi.h>
  #include <linux/spi/spi_bitbang.h>
d7614de42   Paul Gortmaker   spi: Add module.h...
44
  #include <linux/module.h>
ec17a7f20   Sachin Kamat   spi: omap-uwire: ...
45
  #include <linux/io.h>
fdb3c18d6   David Brownell   [PATCH] SPI contr...
46

a09e64fbc   Russell King   [ARM] Move includ...
47
  #include <mach/hardware.h>
fdb3c18d6   David Brownell   [PATCH] SPI contr...
48
  #include <asm/mach-types.h>
70c494c31   Tony Lindgren   ARM: OMAP1: Make ...
49
  #include <mach/mux.h>
68cb700c5   Tony Lindgren   ARM: OMAP1: Move ...
50
51
  
  #include <mach/omap7xx.h>	/* OMAP7XX_IO_CONF registers */
fdb3c18d6   David Brownell   [PATCH] SPI contr...
52
53
54
55
56
57
  
  
  /* FIXME address is now a platform device resource,
   * and irqs should show there too...
   */
  #define UWIRE_BASE_PHYS		0xFFFB3000
fdb3c18d6   David Brownell   [PATCH] SPI contr...
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
  
  /* uWire Registers: */
  #define UWIRE_IO_SIZE 0x20
  #define UWIRE_TDR     0x00
  #define UWIRE_RDR     0x00
  #define UWIRE_CSR     0x01
  #define UWIRE_SR1     0x02
  #define UWIRE_SR2     0x03
  #define UWIRE_SR3     0x04
  #define UWIRE_SR4     0x05
  #define UWIRE_SR5     0x06
  
  /* CSR bits */
  #define	RDRB	(1 << 15)
  #define	CSRB	(1 << 14)
  #define	START	(1 << 13)
  #define	CS_CMD	(1 << 12)
  
  /* SR1 or SR2 bits */
  #define UWIRE_READ_FALLING_EDGE		0x0001
  #define UWIRE_READ_RISING_EDGE		0x0000
  #define UWIRE_WRITE_FALLING_EDGE	0x0000
  #define UWIRE_WRITE_RISING_EDGE		0x0002
  #define UWIRE_CS_ACTIVE_LOW		0x0000
  #define UWIRE_CS_ACTIVE_HIGH		0x0004
  #define UWIRE_FREQ_DIV_2		0x0000
  #define UWIRE_FREQ_DIV_4		0x0008
  #define UWIRE_FREQ_DIV_8		0x0010
  #define UWIRE_CHK_READY			0x0020
  #define UWIRE_CLK_INVERTED		0x0040
  
  
  struct uwire_spi {
  	struct spi_bitbang	bitbang;
  	struct clk		*ck;
  };
  
  struct uwire_state {
fdb3c18d6   David Brownell   [PATCH] SPI contr...
96
97
98
99
  	unsigned	div1_idx;
  };
  
  /* REVISIT compile time constant for idx_shift? */
55c381e48   Russell King   [ARM] omap: conve...
100
101
102
103
  /*
   * Or, put it in a structure which is used throughout the driver;
   * that avoids having to issue two loads for each bit of static data.
   */
fdb3c18d6   David Brownell   [PATCH] SPI contr...
104
  static unsigned int uwire_idx_shift;
55c381e48   Russell King   [ARM] omap: conve...
105
  static void __iomem *uwire_base;
fdb3c18d6   David Brownell   [PATCH] SPI contr...
106
107
108
  
  static inline void uwire_write_reg(int idx, u16 val)
  {
55c381e48   Russell King   [ARM] omap: conve...
109
  	__raw_writew(val, uwire_base + (idx << uwire_idx_shift));
fdb3c18d6   David Brownell   [PATCH] SPI contr...
110
111
112
113
  }
  
  static inline u16 uwire_read_reg(int idx)
  {
55c381e48   Russell King   [ARM] omap: conve...
114
  	return __raw_readw(uwire_base + (idx << uwire_idx_shift));
fdb3c18d6   David Brownell   [PATCH] SPI contr...
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
  }
  
  static inline void omap_uwire_configure_mode(u8 cs, unsigned long flags)
  {
  	u16	w, val = 0;
  	int	shift, reg;
  
  	if (flags & UWIRE_CLK_INVERTED)
  		val ^= 0x03;
  	val = flags & 0x3f;
  	if (cs & 1)
  		shift = 6;
  	else
  		shift = 0;
  	if (cs <= 1)
  		reg = UWIRE_SR1;
  	else
  		reg = UWIRE_SR2;
  
  	w = uwire_read_reg(reg);
  	w &= ~(0x3f << shift);
  	w |= val << shift;
  	uwire_write_reg(reg, w);
  }
  
  static int wait_uwire_csr_flag(u16 mask, u16 val, int might_not_catch)
  {
  	u16 w;
  	int c = 0;
  	unsigned long max_jiffies = jiffies + HZ;
  
  	for (;;) {
  		w = uwire_read_reg(UWIRE_CSR);
  		if ((w & mask) == val)
  			break;
  		if (time_after(jiffies, max_jiffies)) {
  			printk(KERN_ERR "%s: timeout. reg=%#06x "
  					"mask=%#06x val=%#06x
  ",
b687d2a8f   Harvey Harrison   spi: replace rema...
154
  			       __func__, w, mask, val);
fdb3c18d6   David Brownell   [PATCH] SPI contr...
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
  			return -1;
  		}
  		c++;
  		if (might_not_catch && c > 64)
  			break;
  	}
  	return 0;
  }
  
  static void uwire_set_clk1_div(int div1_idx)
  {
  	u16 w;
  
  	w = uwire_read_reg(UWIRE_SR3);
  	w &= ~(0x03 << 1);
  	w |= div1_idx << 1;
  	uwire_write_reg(UWIRE_SR3, w);
  }
  
  static void uwire_chipselect(struct spi_device *spi, int value)
  {
  	struct	uwire_state *ust = spi->controller_state;
  	u16	w;
  	int	old_cs;
  
  
  	BUG_ON(wait_uwire_csr_flag(CSRB, 0, 0));
  
  	w = uwire_read_reg(UWIRE_CSR);
  	old_cs = (w >> 10) & 0x03;
  	if (value == BITBANG_CS_INACTIVE || old_cs != spi->chip_select) {
  		/* Deselect this CS, or the previous CS */
  		w &= ~CS_CMD;
  		uwire_write_reg(UWIRE_CSR, w);
  	}
  	/* activate specfied chipselect */
  	if (value == BITBANG_CS_ACTIVE) {
  		uwire_set_clk1_div(ust->div1_idx);
  		/* invert clock? */
  		if (spi->mode & SPI_CPOL)
  			uwire_write_reg(UWIRE_SR4, 1);
  		else
  			uwire_write_reg(UWIRE_SR4, 0);
  
  		w = spi->chip_select << 10;
  		w |= CS_CMD;
  		uwire_write_reg(UWIRE_CSR, w);
  	}
  }
  
  static int uwire_txrx(struct spi_device *spi, struct spi_transfer *t)
  {
fdb3c18d6   David Brownell   [PATCH] SPI contr...
207
  	unsigned	len = t->len;
160f8d069   Jarkko Nikula   spi: omap-uwire: ...
208
  	unsigned	bits = t->bits_per_word;
fdb3c18d6   David Brownell   [PATCH] SPI contr...
209
210
  	unsigned	bytes;
  	u16		val, w;
a419aef8b   Joe Perches   trivial: remove u...
211
  	int		status = 0;
fdb3c18d6   David Brownell   [PATCH] SPI contr...
212
213
214
  
  	if (!t->tx_buf && !t->rx_buf)
  		return 0;
fdb3c18d6   David Brownell   [PATCH] SPI contr...
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
  	w = spi->chip_select << 10;
  	w |= CS_CMD;
  
  	if (t->tx_buf) {
  		const u8	*buf = t->tx_buf;
  
  		/* NOTE:  DMA could be used for TX transfers */
  
  		/* write one or two bytes at a time */
  		while (len >= 1) {
  			/* tx bit 15 is first sent; we byteswap multibyte words
  			 * (msb-first) on the way out from memory.
  			 */
  			val = *buf++;
  			if (bits > 8) {
  				bytes = 2;
  				val |= *buf++ << 8;
  			} else
  				bytes = 1;
  			val <<= 16 - bits;
  
  #ifdef	VERBOSE
  			pr_debug("%s: write-%d =%04x
  ",
6c7377ab6   Kay Sievers   spi: struct devic...
239
  					dev_name(&spi->dev), bits, val);
fdb3c18d6   David Brownell   [PATCH] SPI contr...
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
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
  #endif
  			if (wait_uwire_csr_flag(CSRB, 0, 0))
  				goto eio;
  
  			uwire_write_reg(UWIRE_TDR, val);
  
  			/* start write */
  			val = START | w | (bits << 5);
  
  			uwire_write_reg(UWIRE_CSR, val);
  			len -= bytes;
  
  			/* Wait till write actually starts.
  			 * This is needed with MPU clock 60+ MHz.
  			 * REVISIT: we may not have time to catch it...
  			 */
  			if (wait_uwire_csr_flag(CSRB, CSRB, 1))
  				goto eio;
  
  			status += bytes;
  		}
  
  		/* REVISIT:  save this for later to get more i/o overlap */
  		if (wait_uwire_csr_flag(CSRB, 0, 0))
  			goto eio;
  
  	} else if (t->rx_buf) {
  		u8		*buf = t->rx_buf;
  
  		/* read one or two bytes at a time */
  		while (len) {
  			if (bits > 8) {
  				bytes = 2;
  			} else
  				bytes = 1;
  
  			/* start read */
  			val = START | w | (bits << 0);
  			uwire_write_reg(UWIRE_CSR, val);
  			len -= bytes;
  
  			/* Wait till read actually starts */
  			(void) wait_uwire_csr_flag(CSRB, CSRB, 1);
  
  			if (wait_uwire_csr_flag(RDRB | CSRB,
  						RDRB, 0))
  				goto eio;
  
  			/* rx bit 0 is last received; multibyte words will
  			 * be properly byteswapped on the way to memory.
  			 */
  			val = uwire_read_reg(UWIRE_RDR);
  			val &= (1 << bits) - 1;
  			*buf++ = (u8) val;
  			if (bytes == 2)
  				*buf++ = val >> 8;
  			status += bytes;
  #ifdef	VERBOSE
  			pr_debug("%s: read-%d =%04x
  ",
6c7377ab6   Kay Sievers   spi: struct devic...
300
  					dev_name(&spi->dev), bits, val);
fdb3c18d6   David Brownell   [PATCH] SPI contr...
301
302
303
304
305
306
307
308
309
310
311
312
313
314
  #endif
  
  		}
  	}
  	return status;
  eio:
  	return -EIO;
  }
  
  static int uwire_setup_transfer(struct spi_device *spi, struct spi_transfer *t)
  {
  	struct uwire_state	*ust = spi->controller_state;
  	struct uwire_spi	*uwire;
  	unsigned		flags = 0;
fdb3c18d6   David Brownell   [PATCH] SPI contr...
315
316
317
318
319
320
321
322
  	unsigned		hz;
  	unsigned long		rate;
  	int			div1_idx;
  	int			div1;
  	int			div2;
  	int			status;
  
  	uwire = spi_master_get_devdata(spi->master);
fdb3c18d6   David Brownell   [PATCH] SPI contr...
323
324
325
326
327
328
329
330
331
332
333
334
335
  	/* mode 0..3, clock inverted separately;
  	 * standard nCS signaling;
  	 * don't treat DI=high as "not ready"
  	 */
  	if (spi->mode & SPI_CS_HIGH)
  		flags |= UWIRE_CS_ACTIVE_HIGH;
  
  	if (spi->mode & SPI_CPOL)
  		flags |= UWIRE_CLK_INVERTED;
  
  	switch (spi->mode & (SPI_CPOL | SPI_CPHA)) {
  	case SPI_MODE_0:
  	case SPI_MODE_3:
e5f1b194a   Imre Deak   omap_uwire: SPI_C...
336
  		flags |= UWIRE_WRITE_FALLING_EDGE | UWIRE_READ_RISING_EDGE;
fdb3c18d6   David Brownell   [PATCH] SPI contr...
337
338
339
  		break;
  	case SPI_MODE_1:
  	case SPI_MODE_2:
e5f1b194a   Imre Deak   omap_uwire: SPI_C...
340
  		flags |= UWIRE_WRITE_RISING_EDGE | UWIRE_READ_FALLING_EDGE;
fdb3c18d6   David Brownell   [PATCH] SPI contr...
341
342
343
344
345
  		break;
  	}
  
  	/* assume it's already enabled */
  	rate = clk_get_rate(uwire->ck);
160f8d069   Jarkko Nikula   spi: omap-uwire: ...
346
  	if (t != NULL)
fdb3c18d6   David Brownell   [PATCH] SPI contr...
347
  		hz = t->speed_hz;
160f8d069   Jarkko Nikula   spi: omap-uwire: ...
348
349
  	else
  		hz = spi->max_speed_hz;
fdb3c18d6   David Brownell   [PATCH] SPI contr...
350
351
  
  	if (!hz) {
6c7377ab6   Kay Sievers   spi: struct devic...
352
353
  		pr_debug("%s: zero speed?
  ", dev_name(&spi->dev));
fdb3c18d6   David Brownell   [PATCH] SPI contr...
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
  		status = -EINVAL;
  		goto done;
  	}
  
  	/* F_INT = mpu_xor_clk / DIV1 */
  	for (div1_idx = 0; div1_idx < 4; div1_idx++) {
  		switch (div1_idx) {
  		case 0:
  			div1 = 2;
  			break;
  		case 1:
  			div1 = 4;
  			break;
  		case 2:
  			div1 = 7;
  			break;
  		default:
  		case 3:
  			div1 = 10;
  			break;
  		}
  		div2 = (rate / div1 + hz - 1) / hz;
  		if (div2 <= 8)
  			break;
  	}
  	if (div1_idx == 4) {
  		pr_debug("%s: lowest clock %ld, need %d
  ",
6c7377ab6   Kay Sievers   spi: struct devic...
382
  			dev_name(&spi->dev), rate / 10 / 8, hz);
fdb3c18d6   David Brownell   [PATCH] SPI contr...
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
  		status = -EDOM;
  		goto done;
  	}
  
  	/* we have to cache this and reset in uwire_chipselect as this is a
  	 * global parameter and another uwire device can change it under
  	 * us */
  	ust->div1_idx = div1_idx;
  	uwire_set_clk1_div(div1_idx);
  
  	rate /= div1;
  
  	switch (div2) {
  	case 0:
  	case 1:
  	case 2:
  		flags |= UWIRE_FREQ_DIV_2;
  		rate /= 2;
  		break;
  	case 3:
  	case 4:
  		flags |= UWIRE_FREQ_DIV_4;
  		rate /= 4;
  		break;
  	case 5:
  	case 6:
  	case 7:
  	case 8:
  		flags |= UWIRE_FREQ_DIV_8;
  		rate /= 8;
  		break;
  	}
  	omap_uwire_configure_mode(spi->chip_select, flags);
  	pr_debug("%s: uwire flags %02x, armxor %lu KHz, SCK %lu KHz
  ",
b687d2a8f   Harvey Harrison   spi: replace rema...
418
  			__func__, flags,
fdb3c18d6   David Brownell   [PATCH] SPI contr...
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
  			clk_get_rate(uwire->ck) / 1000,
  			rate / 1000);
  	status = 0;
  done:
  	return status;
  }
  
  static int uwire_setup(struct spi_device *spi)
  {
  	struct uwire_state *ust = spi->controller_state;
  
  	if (ust == NULL) {
  		ust = kzalloc(sizeof(*ust), GFP_KERNEL);
  		if (ust == NULL)
  			return -ENOMEM;
  		spi->controller_state = ust;
  	}
  
  	return uwire_setup_transfer(spi, NULL);
  }
bb2d1c36c   David Brownell   [PATCH] SPI contr...
439
  static void uwire_cleanup(struct spi_device *spi)
fdb3c18d6   David Brownell   [PATCH] SPI contr...
440
441
442
443
444
445
446
  {
  	kfree(spi->controller_state);
  }
  
  static void uwire_off(struct uwire_spi *uwire)
  {
  	uwire_write_reg(UWIRE_SR3, 0);
badfae429   Qing Zhang   spi: omap-uwire: ...
447
  	clk_disable_unprepare(uwire->ck);
fdb3c18d6   David Brownell   [PATCH] SPI contr...
448
449
  	spi_master_put(uwire->bitbang.master);
  }
2deff8d60   Grant Likely   spi: Remove erron...
450
  static int uwire_probe(struct platform_device *pdev)
fdb3c18d6   David Brownell   [PATCH] SPI contr...
451
452
453
454
455
456
457
458
459
460
  {
  	struct spi_master	*master;
  	struct uwire_spi	*uwire;
  	int			status;
  
  	master = spi_alloc_master(&pdev->dev, sizeof *uwire);
  	if (!master)
  		return -ENODEV;
  
  	uwire = spi_master_get_devdata(master);
55c381e48   Russell King   [ARM] omap: conve...
461

b3f6a5750   Himangi Saraogi   spi: omap-uwire: ...
462
  	uwire_base = devm_ioremap(&pdev->dev, UWIRE_BASE_PHYS, UWIRE_IO_SIZE);
55c381e48   Russell King   [ARM] omap: conve...
463
464
465
466
467
468
  	if (!uwire_base) {
  		dev_dbg(&pdev->dev, "can't ioremap UWIRE
  ");
  		spi_master_put(master);
  		return -ENOMEM;
  	}
24b5a82cf   Jingoo Han   spi: use platform...
469
  	platform_set_drvdata(pdev, uwire);
fdb3c18d6   David Brownell   [PATCH] SPI contr...
470

b3f6a5750   Himangi Saraogi   spi: omap-uwire: ...
471
  	uwire->ck = devm_clk_get(&pdev->dev, "fck");
b1ad37963   Russell King   [ARM] omap: spi: ...
472
473
474
475
  	if (IS_ERR(uwire->ck)) {
  		status = PTR_ERR(uwire->ck);
  		dev_dbg(&pdev->dev, "no functional clock?
  ");
fdb3c18d6   David Brownell   [PATCH] SPI contr...
476
  		spi_master_put(master);
b1ad37963   Russell King   [ARM] omap: spi: ...
477
  		return status;
fdb3c18d6   David Brownell   [PATCH] SPI contr...
478
  	}
badfae429   Qing Zhang   spi: omap-uwire: ...
479
  	clk_prepare_enable(uwire->ck);
fdb3c18d6   David Brownell   [PATCH] SPI contr...
480

7a8f48f8c   Alistair Buxton   OMAP7XX: omap_uwi...
481
  	if (cpu_is_omap7xx())
fdb3c18d6   David Brownell   [PATCH] SPI contr...
482
483
484
485
486
  		uwire_idx_shift = 1;
  	else
  		uwire_idx_shift = 2;
  
  	uwire_write_reg(UWIRE_SR3, 1);
e7db06b5d   David Brownell   spi: move more sp...
487
488
  	/* the spi->mode bits understood by this driver: */
  	master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH;
790fc55a7   Axel Lin   spi: omap-uwire: ...
489
  	master->bits_per_word_mask = SPI_BPW_RANGE_MASK(1, 16);
70d6027ff   David Brownell   spi: add spi_mast...
490
  	master->flags = SPI_MASTER_HALF_DUPLEX;
fdb3c18d6   David Brownell   [PATCH] SPI contr...
491
492
493
494
495
496
497
498
499
500
501
  	master->bus_num = 2;	/* "official" */
  	master->num_chipselect = 4;
  	master->setup = uwire_setup;
  	master->cleanup = uwire_cleanup;
  
  	uwire->bitbang.master = master;
  	uwire->bitbang.chipselect = uwire_chipselect;
  	uwire->bitbang.setup_transfer = uwire_setup_transfer;
  	uwire->bitbang.txrx_bufs = uwire_txrx;
  
  	status = spi_bitbang_start(&uwire->bitbang);
55c381e48   Russell King   [ARM] omap: conve...
502
  	if (status < 0) {
fdb3c18d6   David Brownell   [PATCH] SPI contr...
503
  		uwire_off(uwire);
55c381e48   Russell King   [ARM] omap: conve...
504
  	}
fdb3c18d6   David Brownell   [PATCH] SPI contr...
505
506
  	return status;
  }
2deff8d60   Grant Likely   spi: Remove erron...
507
  static int uwire_remove(struct platform_device *pdev)
fdb3c18d6   David Brownell   [PATCH] SPI contr...
508
  {
24b5a82cf   Jingoo Han   spi: use platform...
509
  	struct uwire_spi	*uwire = platform_get_drvdata(pdev);
fdb3c18d6   David Brownell   [PATCH] SPI contr...
510
511
  
  	// FIXME remove all child devices, somewhere ...
d9721ae14   Axel Lin   spi: bitbang: Mak...
512
  	spi_bitbang_stop(&uwire->bitbang);
fdb3c18d6   David Brownell   [PATCH] SPI contr...
513
  	uwire_off(uwire);
d9721ae14   Axel Lin   spi: bitbang: Mak...
514
  	return 0;
fdb3c18d6   David Brownell   [PATCH] SPI contr...
515
  }
7e38c3c44   Kay Sievers   spi: fix platform...
516
517
  /* work with hotplug and coldplug */
  MODULE_ALIAS("platform:omap_uwire");
fdb3c18d6   David Brownell   [PATCH] SPI contr...
518
519
520
  static struct platform_driver uwire_driver = {
  	.driver = {
  		.name		= "omap_uwire",
fdb3c18d6   David Brownell   [PATCH] SPI contr...
521
  	},
93e9c9001   Wolfram Sang   spi: spi-omap-uwi...
522
523
  	.probe = uwire_probe,
  	.remove = uwire_remove,
fdb3c18d6   David Brownell   [PATCH] SPI contr...
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
  	// suspend ... unuse ck
  	// resume ... use ck
  };
  
  static int __init omap_uwire_init(void)
  {
  	/* FIXME move these into the relevant board init code. also, include
  	 * H3 support; it uses tsc2101 like H2 (on a different chipselect).
  	 */
  
  	if (machine_is_omap_h2()) {
  		/* defaults: W21 SDO, U18 SDI, V19 SCL */
  		omap_cfg_reg(N14_1610_UWIRE_CS0);
  		omap_cfg_reg(N15_1610_UWIRE_CS1);
  	}
  	if (machine_is_omap_perseus2()) {
  		/* configure pins: MPU_UW_nSCS1, MPU_UW_SDO, MPU_UW_SCLK */
7a8f48f8c   Alistair Buxton   OMAP7XX: omap_uwi...
541
542
  		int val = omap_readl(OMAP7XX_IO_CONF_9) & ~0x00EEE000;
  		omap_writel(val | 0x00AAA000, OMAP7XX_IO_CONF_9);
fdb3c18d6   David Brownell   [PATCH] SPI contr...
543
  	}
93e9c9001   Wolfram Sang   spi: spi-omap-uwi...
544
  	return platform_driver_register(&uwire_driver);
fdb3c18d6   David Brownell   [PATCH] SPI contr...
545
546
547
548
549
550
551
552
553
554
555
  }
  
  static void __exit omap_uwire_exit(void)
  {
  	platform_driver_unregister(&uwire_driver);
  }
  
  subsys_initcall(omap_uwire_init);
  module_exit(omap_uwire_exit);
  
  MODULE_LICENSE("GPL");