Blame view

drivers/spi/spi-bitbang.c 10.5 KB
9904f22a7   David Brownell   [PATCH] spi: add ...
1
  /*
ca632f556   Grant Likely   spi: reorganize d...
2
   * polling/bitbanging SPI master controller driver utilities
9904f22a7   David Brownell   [PATCH] spi: add ...
3
4
5
6
7
8
9
10
11
12
   *
   * 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 program is distributed in the hope that it will be useful,
   * but WITHOUT ANY WARRANTY; without even the implied warranty of
   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   * GNU General Public License for more details.
9904f22a7   David Brownell   [PATCH] spi: add ...
13
   */
9904f22a7   David Brownell   [PATCH] spi: add ...
14
15
16
  #include <linux/spinlock.h>
  #include <linux/workqueue.h>
  #include <linux/interrupt.h>
d7614de42   Paul Gortmaker   spi: Add module.h...
17
  #include <linux/module.h>
9904f22a7   David Brownell   [PATCH] spi: add ...
18
19
20
  #include <linux/delay.h>
  #include <linux/errno.h>
  #include <linux/platform_device.h>
5a0e3ad6a   Tejun Heo   include cleanup: ...
21
  #include <linux/slab.h>
9904f22a7   David Brownell   [PATCH] spi: add ...
22
23
24
  
  #include <linux/spi/spi.h>
  #include <linux/spi/spi_bitbang.h>
003768659   Heiner Kallweit   spi: bitbang: swi...
25
  #define SPI_BITBANG_CS_DELAY	100
9904f22a7   David Brownell   [PATCH] spi: add ...
26
27
28
29
30
31
32
33
34
35
36
  
  /*----------------------------------------------------------------------*/
  
  /*
   * FIRST PART (OPTIONAL):  word-at-a-time spi_transfer support.
   * Use this for GPIO or shift-register level hardware APIs.
   *
   * spi_bitbang_cs is in spi_device->controller_state, which is unavailable
   * to glue code.  These bitbang setup() and cleanup() routines are always
   * used, though maybe they're called from controller-aware code.
   *
03ddcbc5d   Uwe Kleine-König   spi/bitbang: triv...
37
   * chipselect() and friends may use spi_device->controller_data and
9904f22a7   David Brownell   [PATCH] spi: add ...
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
   * controller registers as appropriate.
   *
   *
   * NOTE:  SPI controller pins can often be used as GPIO pins instead,
   * which means you could use a bitbang driver either to get hardware
   * working quickly, or testing for differences that aren't speed related.
   */
  
  struct spi_bitbang_cs {
  	unsigned	nsecs;	/* (clock cycle time)/2 */
  	u32		(*txrx_word)(struct spi_device *spi, unsigned nsecs,
  					u32 word, u8 bits);
  	unsigned	(*txrx_bufs)(struct spi_device *,
  					u32 (*txrx_word)(
  						struct spi_device *spi,
  						unsigned nsecs,
  						u32 word, u8 bits),
  					unsigned, struct spi_transfer *);
  };
  
  static unsigned bitbang_txrx_8(
  	struct spi_device	*spi,
  	u32			(*txrx_word)(struct spi_device *spi,
  					unsigned nsecs,
  					u32 word, u8 bits),
  	unsigned		ns,
  	struct spi_transfer	*t
  ) {
766ed7044   Laxman Dewangan   spi: remove check...
66
  	unsigned		bits = t->bits_per_word;
9904f22a7   David Brownell   [PATCH] spi: add ...
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
  	unsigned		count = t->len;
  	const u8		*tx = t->tx_buf;
  	u8			*rx = t->rx_buf;
  
  	while (likely(count > 0)) {
  		u8		word = 0;
  
  		if (tx)
  			word = *tx++;
  		word = txrx_word(spi, ns, word, bits);
  		if (rx)
  			*rx++ = word;
  		count -= 1;
  	}
  	return t->len - count;
  }
  
  static unsigned bitbang_txrx_16(
  	struct spi_device	*spi,
  	u32			(*txrx_word)(struct spi_device *spi,
  					unsigned nsecs,
  					u32 word, u8 bits),
  	unsigned		ns,
  	struct spi_transfer	*t
  ) {
766ed7044   Laxman Dewangan   spi: remove check...
92
  	unsigned		bits = t->bits_per_word;
9904f22a7   David Brownell   [PATCH] spi: add ...
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
  	unsigned		count = t->len;
  	const u16		*tx = t->tx_buf;
  	u16			*rx = t->rx_buf;
  
  	while (likely(count > 1)) {
  		u16		word = 0;
  
  		if (tx)
  			word = *tx++;
  		word = txrx_word(spi, ns, word, bits);
  		if (rx)
  			*rx++ = word;
  		count -= 2;
  	}
  	return t->len - count;
  }
  
  static unsigned bitbang_txrx_32(
  	struct spi_device	*spi,
  	u32			(*txrx_word)(struct spi_device *spi,
  					unsigned nsecs,
  					u32 word, u8 bits),
  	unsigned		ns,
  	struct spi_transfer	*t
  ) {
766ed7044   Laxman Dewangan   spi: remove check...
118
  	unsigned		bits = t->bits_per_word;
9904f22a7   David Brownell   [PATCH] spi: add ...
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
  	unsigned		count = t->len;
  	const u32		*tx = t->tx_buf;
  	u32			*rx = t->rx_buf;
  
  	while (likely(count > 3)) {
  		u32		word = 0;
  
  		if (tx)
  			word = *tx++;
  		word = txrx_word(spi, ns, word, bits);
  		if (rx)
  			*rx++ = word;
  		count -= 4;
  	}
  	return t->len - count;
  }
ff9f4771b   Kumar Gala   [PATCH] SPI: Rena...
135
  int spi_bitbang_setup_transfer(struct spi_device *spi, struct spi_transfer *t)
4cff33f94   Imre Deak   [PATCH] SPI: per-...
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
  {
  	struct spi_bitbang_cs	*cs = spi->controller_state;
  	u8			bits_per_word;
  	u32			hz;
  
  	if (t) {
  		bits_per_word = t->bits_per_word;
  		hz = t->speed_hz;
  	} else {
  		bits_per_word = 0;
  		hz = 0;
  	}
  
  	/* spi_transfer level calls that work per-word */
  	if (!bits_per_word)
  		bits_per_word = spi->bits_per_word;
  	if (bits_per_word <= 8)
  		cs->txrx_bufs = bitbang_txrx_8;
  	else if (bits_per_word <= 16)
  		cs->txrx_bufs = bitbang_txrx_16;
  	else if (bits_per_word <= 32)
  		cs->txrx_bufs = bitbang_txrx_32;
  	else
  		return -EINVAL;
  
  	/* nsecs = (clock period)/2 */
  	if (!hz)
  		hz = spi->max_speed_hz;
1e316d756   David Brownell   [PATCH] SPI: spi_...
164
165
166
167
168
  	if (hz) {
  		cs->nsecs = (1000000000/2) / hz;
  		if (cs->nsecs > (MAX_UDELAY_MS * 1000 * 1000))
  			return -EINVAL;
  	}
4cff33f94   Imre Deak   [PATCH] SPI: per-...
169
170
171
  
  	return 0;
  }
ff9f4771b   Kumar Gala   [PATCH] SPI: Rena...
172
  EXPORT_SYMBOL_GPL(spi_bitbang_setup_transfer);
4cff33f94   Imre Deak   [PATCH] SPI: per-...
173

9904f22a7   David Brownell   [PATCH] spi: add ...
174
175
176
177
178
179
180
  /**
   * spi_bitbang_setup - default setup for per-word I/O loops
   */
  int spi_bitbang_setup(struct spi_device *spi)
  {
  	struct spi_bitbang_cs	*cs = spi->controller_state;
  	struct spi_bitbang	*bitbang;
ccf77cc4a   David Brownell   [PATCH] SPI: devi...
181
  	bitbang = spi_master_get_devdata(spi->master);
9904f22a7   David Brownell   [PATCH] spi: add ...
182
  	if (!cs) {
cff93c58f   Jingoo Han   spi: bitbang: Fix...
183
  		cs = kzalloc(sizeof(*cs), GFP_KERNEL);
9904f22a7   David Brownell   [PATCH] spi: add ...
184
185
186
187
  		if (!cs)
  			return -ENOMEM;
  		spi->controller_state = cs;
  	}
9904f22a7   David Brownell   [PATCH] spi: add ...
188

9904f22a7   David Brownell   [PATCH] spi: add ...
189
190
191
192
  	/* per-word shift register access, in hardware or bitbanging */
  	cs->txrx_word = bitbang->txrx_word[spi->mode & (SPI_CPOL|SPI_CPHA)];
  	if (!cs->txrx_word)
  		return -EINVAL;
7d0ec8b6f   Pelle Nilsson   spi: bitbang: Mak...
193
194
195
196
197
  	if (bitbang->setup_transfer) {
  		int retval = bitbang->setup_transfer(spi, NULL);
  		if (retval < 0)
  			return retval;
  	}
9904f22a7   David Brownell   [PATCH] spi: add ...
198

7d0771970   David Brownell   spi: move common ...
199
200
  	dev_dbg(&spi->dev, "%s, %u nsec/bit
  ", __func__, 2 * cs->nsecs);
9904f22a7   David Brownell   [PATCH] spi: add ...
201
202
203
204
205
206
207
  
  	/* NOTE we _need_ to call chipselect() early, ideally with adapter
  	 * setup, unless the hardware defaults cooperate to avoid confusion
  	 * between normal (active low) and inverted chipselects.
  	 */
  
  	/* deselect chip (low or high) */
c15f6ed3a   Nicolas Boichat   spi: bitbang: Rep...
208
  	mutex_lock(&bitbang->lock);
9904f22a7   David Brownell   [PATCH] spi: add ...
209
  	if (!bitbang->busy) {
8275c642c   Vitaly Wool   [PATCH] spi: use ...
210
  		bitbang->chipselect(spi, BITBANG_CS_INACTIVE);
9904f22a7   David Brownell   [PATCH] spi: add ...
211
212
  		ndelay(cs->nsecs);
  	}
c15f6ed3a   Nicolas Boichat   spi: bitbang: Rep...
213
  	mutex_unlock(&bitbang->lock);
9904f22a7   David Brownell   [PATCH] spi: add ...
214
215
216
217
218
219
220
221
  
  	return 0;
  }
  EXPORT_SYMBOL_GPL(spi_bitbang_setup);
  
  /**
   * spi_bitbang_cleanup - default cleanup for per-word I/O loops
   */
0ffa02850   Hans-Peter Nilsson   [PATCH] SPI clean...
222
  void spi_bitbang_cleanup(struct spi_device *spi)
9904f22a7   David Brownell   [PATCH] spi: add ...
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
  {
  	kfree(spi->controller_state);
  }
  EXPORT_SYMBOL_GPL(spi_bitbang_cleanup);
  
  static int spi_bitbang_bufs(struct spi_device *spi, struct spi_transfer *t)
  {
  	struct spi_bitbang_cs	*cs = spi->controller_state;
  	unsigned		nsecs = cs->nsecs;
  
  	return cs->txrx_bufs(spi, cs->txrx_word, nsecs, t);
  }
  
  /*----------------------------------------------------------------------*/
  
  /*
   * SECOND PART ... simple transfer queue runner.
   *
   * This costs a task context per controller, running the queue by
   * performing each transfer in sequence.  Smarter hardware can queue
   * several DMA transfers at once, and process several controller queues
   * in parallel; this driver doesn't match such hardware very well.
   *
   * Drivers can provide word-at-a-time i/o primitives, or provide
   * transfer-at-a-time ones to leverage dma or fifo hardware.
   */
2025172e3   Mark Brown   spi/bitbang: Use ...
249
250
251
  
  static int spi_bitbang_prepare_hardware(struct spi_master *spi)
  {
cff93c58f   Jingoo Han   spi: bitbang: Fix...
252
  	struct spi_bitbang	*bitbang;
2025172e3   Mark Brown   spi/bitbang: Use ...
253
254
  
  	bitbang = spi_master_get_devdata(spi);
c15f6ed3a   Nicolas Boichat   spi: bitbang: Rep...
255
  	mutex_lock(&bitbang->lock);
2025172e3   Mark Brown   spi/bitbang: Use ...
256
  	bitbang->busy = 1;
c15f6ed3a   Nicolas Boichat   spi: bitbang: Rep...
257
  	mutex_unlock(&bitbang->lock);
2025172e3   Mark Brown   spi/bitbang: Use ...
258
259
260
  
  	return 0;
  }
d60990d59   Fabio Estevam   spi: spi-bitbang:...
261
  static int spi_bitbang_transfer_one(struct spi_master *master,
003768659   Heiner Kallweit   spi: bitbang: swi...
262
263
  				    struct spi_device *spi,
  				    struct spi_transfer *transfer)
9904f22a7   David Brownell   [PATCH] spi: add ...
264
  {
003768659   Heiner Kallweit   spi: bitbang: swi...
265
266
  	struct spi_bitbang *bitbang = spi_master_get_devdata(master);
  	int status = 0;
91b308586   Mark Brown   spi/bitbang: Fact...
267

003768659   Heiner Kallweit   spi: bitbang: swi...
268
269
270
271
  	if (bitbang->setup_transfer) {
  		status = bitbang->setup_transfer(spi, transfer);
  		if (status < 0)
  			goto out;
91b308586   Mark Brown   spi/bitbang: Fact...
272
  	}
003768659   Heiner Kallweit   spi: bitbang: swi...
273
274
  	if (transfer->len)
  		status = bitbang->txrx_bufs(spi, transfer);
91b308586   Mark Brown   spi/bitbang: Fact...
275

003768659   Heiner Kallweit   spi: bitbang: swi...
276
277
278
279
  	if (status == transfer->len)
  		status = 0;
  	else if (status >= 0)
  		status = -EREMOTEIO;
91b308586   Mark Brown   spi/bitbang: Fact...
280

003768659   Heiner Kallweit   spi: bitbang: swi...
281
282
  out:
  	spi_finalize_current_transfer(master);
9904f22a7   David Brownell   [PATCH] spi: add ...
283

2025172e3   Mark Brown   spi/bitbang: Use ...
284
  	return status;
9904f22a7   David Brownell   [PATCH] spi: add ...
285
  }
2025172e3   Mark Brown   spi/bitbang: Use ...
286
  static int spi_bitbang_unprepare_hardware(struct spi_master *spi)
9904f22a7   David Brownell   [PATCH] spi: add ...
287
  {
cff93c58f   Jingoo Han   spi: bitbang: Fix...
288
  	struct spi_bitbang	*bitbang;
9904f22a7   David Brownell   [PATCH] spi: add ...
289

2025172e3   Mark Brown   spi/bitbang: Use ...
290
  	bitbang = spi_master_get_devdata(spi);
9904f22a7   David Brownell   [PATCH] spi: add ...
291

c15f6ed3a   Nicolas Boichat   spi: bitbang: Rep...
292
  	mutex_lock(&bitbang->lock);
2025172e3   Mark Brown   spi/bitbang: Use ...
293
  	bitbang->busy = 0;
c15f6ed3a   Nicolas Boichat   spi: bitbang: Rep...
294
  	mutex_unlock(&bitbang->lock);
9904f22a7   David Brownell   [PATCH] spi: add ...
295

2025172e3   Mark Brown   spi/bitbang: Use ...
296
  	return 0;
9904f22a7   David Brownell   [PATCH] spi: add ...
297
  }
9904f22a7   David Brownell   [PATCH] spi: add ...
298

003768659   Heiner Kallweit   spi: bitbang: swi...
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
  static void spi_bitbang_set_cs(struct spi_device *spi, bool enable)
  {
  	struct spi_bitbang *bitbang = spi_master_get_devdata(spi->master);
  
  	/* SPI core provides CS high / low, but bitbang driver
  	 * expects CS active
  	 * spi device driver takes care of handling SPI_CS_HIGH
  	 */
  	enable = (!!(spi->mode & SPI_CS_HIGH) == enable);
  
  	ndelay(SPI_BITBANG_CS_DELAY);
  	bitbang->chipselect(spi, enable ? BITBANG_CS_ACTIVE :
  			    BITBANG_CS_INACTIVE);
  	ndelay(SPI_BITBANG_CS_DELAY);
  }
9904f22a7   David Brownell   [PATCH] spi: add ...
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
  /*----------------------------------------------------------------------*/
  
  /**
   * spi_bitbang_start - start up a polled/bitbanging SPI master driver
   * @bitbang: driver handle
   *
   * Caller should have zero-initialized all parts of the structure, and then
   * provided callbacks for chip selection and I/O loops.  If the master has
   * a transfer method, its final step should call spi_bitbang_transfer; or,
   * that's the default if the transfer routine is not initialized.  It should
   * also set up the bus number and number of chipselects.
   *
   * For i/o loops, provide callbacks either per-word (for bitbanging, or for
   * hardware that basically exposes a shift register) or per-spi_transfer
   * (which takes better advantage of hardware like fifos or DMA engines).
   *
7f8c7619e   Hans-Peter Nilsson   [PATCH] spi_bitba...
330
331
332
333
   * Drivers using per-word I/O loops should use (or call) spi_bitbang_setup,
   * spi_bitbang_cleanup and spi_bitbang_setup_transfer to handle those spi
   * master methods.  Those methods are the defaults if the bitbang->txrx_bufs
   * routine isn't initialized.
9904f22a7   David Brownell   [PATCH] spi: add ...
334
335
336
337
   *
   * This routine registers the spi_master, which will process requests in a
   * dedicated task, keeping IRQs unblocked most of the time.  To stop
   * processing those requests, call spi_bitbang_stop().
702a4879e   Axel Lin   spi: bitbang: Let...
338
339
340
341
342
   *
   * On success, this routine will take a reference to master. The caller is
   * responsible for calling spi_bitbang_stop() to decrement the reference and
   * spi_master_put() as counterpart of spi_alloc_master() to prevent a memory
   * leak.
9904f22a7   David Brownell   [PATCH] spi: add ...
343
344
345
   */
  int spi_bitbang_start(struct spi_bitbang *bitbang)
  {
7a5d8ca12   Guennadi Liakhovetski   spi: bitbang: sim...
346
  	struct spi_master *master = bitbang->master;
702a4879e   Axel Lin   spi: bitbang: Let...
347
  	int ret;
9904f22a7   David Brownell   [PATCH] spi: add ...
348

7a5d8ca12   Guennadi Liakhovetski   spi: bitbang: sim...
349
  	if (!master || !bitbang->chipselect)
9904f22a7   David Brownell   [PATCH] spi: add ...
350
  		return -EINVAL;
c15f6ed3a   Nicolas Boichat   spi: bitbang: Rep...
351
  	mutex_init(&bitbang->lock);
9904f22a7   David Brownell   [PATCH] spi: add ...
352

7a5d8ca12   Guennadi Liakhovetski   spi: bitbang: sim...
353
354
  	if (!master->mode_bits)
  		master->mode_bits = SPI_CPOL | SPI_CPHA | bitbang->flags;
e7db06b5d   David Brownell   spi: move more sp...
355

2025172e3   Mark Brown   spi/bitbang: Use ...
356
357
358
359
360
  	if (master->transfer || master->transfer_one_message)
  		return -EINVAL;
  
  	master->prepare_transfer_hardware = spi_bitbang_prepare_hardware;
  	master->unprepare_transfer_hardware = spi_bitbang_unprepare_hardware;
003768659   Heiner Kallweit   spi: bitbang: swi...
361
362
  	master->transfer_one = spi_bitbang_transfer_one;
  	master->set_cs = spi_bitbang_set_cs;
2025172e3   Mark Brown   spi/bitbang: Use ...
363

9904f22a7   David Brownell   [PATCH] spi: add ...
364
365
366
  	if (!bitbang->txrx_bufs) {
  		bitbang->use_dma = 0;
  		bitbang->txrx_bufs = spi_bitbang_bufs;
7a5d8ca12   Guennadi Liakhovetski   spi: bitbang: sim...
367
  		if (!master->setup) {
ff9f4771b   Kumar Gala   [PATCH] SPI: Rena...
368
369
370
  			if (!bitbang->setup_transfer)
  				bitbang->setup_transfer =
  					 spi_bitbang_setup_transfer;
7a5d8ca12   Guennadi Liakhovetski   spi: bitbang: sim...
371
372
  			master->setup = spi_bitbang_setup;
  			master->cleanup = spi_bitbang_cleanup;
9904f22a7   David Brownell   [PATCH] spi: add ...
373
  		}
52ade7362   Uwe Kleine-König   spi/bitbang: don'...
374
  	}
9904f22a7   David Brownell   [PATCH] spi: add ...
375
376
377
378
  
  	/* driver may get busy before register() returns, especially
  	 * if someone registered boardinfo for devices
  	 */
702a4879e   Axel Lin   spi: bitbang: Let...
379
380
381
382
383
  	ret = spi_register_master(spi_master_get(master));
  	if (ret)
  		spi_master_put(master);
  
  	return 0;
9904f22a7   David Brownell   [PATCH] spi: add ...
384
385
386
387
388
389
  }
  EXPORT_SYMBOL_GPL(spi_bitbang_start);
  
  /**
   * spi_bitbang_stop - stops the task providing spi communication
   */
d9721ae14   Axel Lin   spi: bitbang: Mak...
390
  void spi_bitbang_stop(struct spi_bitbang *bitbang)
9904f22a7   David Brownell   [PATCH] spi: add ...
391
  {
a836f5856   Chris Lesiak   [PATCH] spi: dest...
392
  	spi_unregister_master(bitbang->master);
9904f22a7   David Brownell   [PATCH] spi: add ...
393
394
395
396
  }
  EXPORT_SYMBOL_GPL(spi_bitbang_stop);
  
  MODULE_LICENSE("GPL");