aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/spi/spi_mpc83xx.c
diff options
context:
space:
mode:
authorKumar Gala <galak@kernel.crashing.org>2006-05-20 18:00:15 -0400
committerLinus Torvalds <torvalds@g5.osdl.org>2006-05-21 15:59:19 -0400
commitccf06998fe179ae2cc9517ed1d75433dc0b5032d (patch)
tree88696d35b5bb168c3f7f2a3b56a683c919e33bed /drivers/spi/spi_mpc83xx.c
parentba1a051319dc2bec9f43b7cef11c6e5270107fd6 (diff)
[PATCH] spi: add spi master driver for Freescale MPC83xx SPI controller
This driver supports the SPI controller on the MPC83xx SoC devices from Freescale. Note, this driver supports only the simple shift register SPI controller and not the descriptor based CPM or QUICCEngine SPI controller. Signed-off-by: Kumar Gala <galak@kernel.crashing.org> Signed-off-by: David Brownell <dbrownell@users.sourceforge.net> Cc: Greg KH <greg@kroah.com> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'drivers/spi/spi_mpc83xx.c')
-rw-r--r--drivers/spi/spi_mpc83xx.c483
1 files changed, 483 insertions, 0 deletions
diff --git a/drivers/spi/spi_mpc83xx.c b/drivers/spi/spi_mpc83xx.c
new file mode 100644
index 000000000000..5d92a7e5cb41
--- /dev/null
+++ b/drivers/spi/spi_mpc83xx.c
@@ -0,0 +1,483 @@
1/*
2 * MPC83xx SPI controller driver.
3 *
4 * Maintainer: Kumar Gala
5 *
6 * Copyright (C) 2006 Polycom, Inc.
7 *
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU General Public License as published by the
10 * Free Software Foundation; either version 2 of the License, or (at your
11 * option) any later version.
12 */
13#include <linux/module.h>
14#include <linux/init.h>
15#include <linux/types.h>
16#include <linux/kernel.h>
17#include <linux/completion.h>
18#include <linux/interrupt.h>
19#include <linux/delay.h>
20#include <linux/irq.h>
21#include <linux/device.h>
22#include <linux/spi/spi.h>
23#include <linux/spi/spi_bitbang.h>
24#include <linux/platform_device.h>
25#include <linux/fsl_devices.h>
26
27#include <asm/irq.h>
28#include <asm/io.h>
29
30/* SPI Controller registers */
31struct mpc83xx_spi_reg {
32 u8 res1[0x20];
33 __be32 mode;
34 __be32 event;
35 __be32 mask;
36 __be32 command;
37 __be32 transmit;
38 __be32 receive;
39};
40
41/* SPI Controller mode register definitions */
42#define SPMODE_CI_INACTIVEHIGH (1 << 29)
43#define SPMODE_CP_BEGIN_EDGECLK (1 << 28)
44#define SPMODE_DIV16 (1 << 27)
45#define SPMODE_REV (1 << 26)
46#define SPMODE_MS (1 << 25)
47#define SPMODE_ENABLE (1 << 24)
48#define SPMODE_LEN(x) ((x) << 20)
49#define SPMODE_PM(x) ((x) << 16)
50
51/*
52 * Default for SPI Mode:
53 * SPI MODE 0 (inactive low, phase middle, MSB, 8-bit length, slow clk
54 */
55#define SPMODE_INIT_VAL (SPMODE_CI_INACTIVEHIGH | SPMODE_DIV16 | SPMODE_REV | \
56 SPMODE_MS | SPMODE_LEN(7) | SPMODE_PM(0xf))
57
58/* SPIE register values */
59#define SPIE_NE 0x00000200 /* Not empty */
60#define SPIE_NF 0x00000100 /* Not full */
61
62/* SPIM register values */
63#define SPIM_NE 0x00000200 /* Not empty */
64#define SPIM_NF 0x00000100 /* Not full */
65
66/* SPI Controller driver's private data. */
67struct mpc83xx_spi {
68 /* bitbang has to be first */
69 struct spi_bitbang bitbang;
70 struct completion done;
71
72 struct mpc83xx_spi_reg __iomem *base;
73
74 /* rx & tx bufs from the spi_transfer */
75 const void *tx;
76 void *rx;
77
78 /* functions to deal with different sized buffers */
79 void (*get_rx) (u32 rx_data, struct mpc83xx_spi *);
80 u32(*get_tx) (struct mpc83xx_spi *);
81
82 unsigned int count;
83 u32 irq;
84
85 unsigned nsecs; /* (clock cycle time)/2 */
86
87 u32 sysclk;
88 void (*activate_cs) (u8 cs, u8 polarity);
89 void (*deactivate_cs) (u8 cs, u8 polarity);
90};
91
92static inline void mpc83xx_spi_write_reg(__be32 __iomem * reg, u32 val)
93{
94 out_be32(reg, val);
95}
96
97static inline u32 mpc83xx_spi_read_reg(__be32 __iomem * reg)
98{
99 return in_be32(reg);
100}
101
102#define MPC83XX_SPI_RX_BUF(type) \
103void mpc83xx_spi_rx_buf_##type(u32 data, struct mpc83xx_spi *mpc83xx_spi) \
104{ \
105 type * rx = mpc83xx_spi->rx; \
106 *rx++ = (type)data; \
107 mpc83xx_spi->rx = rx; \
108}
109
110#define MPC83XX_SPI_TX_BUF(type) \
111u32 mpc83xx_spi_tx_buf_##type(struct mpc83xx_spi *mpc83xx_spi) \
112{ \
113 u32 data; \
114 const type * tx = mpc83xx_spi->tx; \
115 data = *tx++; \
116 mpc83xx_spi->tx = tx; \
117 return data; \
118}
119
120MPC83XX_SPI_RX_BUF(u8)
121MPC83XX_SPI_RX_BUF(u16)
122MPC83XX_SPI_RX_BUF(u32)
123MPC83XX_SPI_TX_BUF(u8)
124MPC83XX_SPI_TX_BUF(u16)
125MPC83XX_SPI_TX_BUF(u32)
126
127static void mpc83xx_spi_chipselect(struct spi_device *spi, int value)
128{
129 struct mpc83xx_spi *mpc83xx_spi;
130 u8 pol = spi->mode & SPI_CS_HIGH ? 1 : 0;
131
132 mpc83xx_spi = spi_master_get_devdata(spi->master);
133
134 if (value == BITBANG_CS_INACTIVE) {
135 if (mpc83xx_spi->deactivate_cs)
136 mpc83xx_spi->deactivate_cs(spi->chip_select, pol);
137 }
138
139 if (value == BITBANG_CS_ACTIVE) {
140 u32 regval = mpc83xx_spi_read_reg(&mpc83xx_spi->base->mode);
141 u32 len = spi->bits_per_word;
142 if (len == 32)
143 len = 0;
144 else
145 len = len - 1;
146
147 /* mask out bits we are going to set */
148 regval &= ~0x38ff0000;
149
150 if (spi->mode & SPI_CPHA)
151 regval |= SPMODE_CP_BEGIN_EDGECLK;
152 if (spi->mode & SPI_CPOL)
153 regval |= SPMODE_CI_INACTIVEHIGH;
154
155 regval |= SPMODE_LEN(len);
156
157 if ((mpc83xx_spi->sysclk / spi->max_speed_hz) >= 64) {
158 u8 pm = mpc83xx_spi->sysclk / (spi->max_speed_hz * 64);
159 regval |= SPMODE_PM(pm) | SPMODE_DIV16;
160 } else {
161 u8 pm = mpc83xx_spi->sysclk / (spi->max_speed_hz * 4);
162 regval |= SPMODE_PM(pm);
163 }
164
165 mpc83xx_spi_write_reg(&mpc83xx_spi->base->mode, regval);
166 if (mpc83xx_spi->activate_cs)
167 mpc83xx_spi->activate_cs(spi->chip_select, pol);
168 }
169}
170
171static
172int mpc83xx_spi_setup_transfer(struct spi_device *spi, struct spi_transfer *t)
173{
174 struct mpc83xx_spi *mpc83xx_spi;
175 u32 regval;
176 u8 bits_per_word;
177 u32 hz;
178
179 mpc83xx_spi = spi_master_get_devdata(spi->master);
180
181 if (t) {
182 bits_per_word = t->bits_per_word;
183 hz = t->speed_hz;
184 } else {
185 bits_per_word = 0;
186 hz = 0;
187 }
188
189 /* spi_transfer level calls that work per-word */
190 if (!bits_per_word)
191 bits_per_word = spi->bits_per_word;
192
193 /* Make sure its a bit width we support [4..16, 32] */
194 if ((bits_per_word < 4)
195 || ((bits_per_word > 16) && (bits_per_word != 32)))
196 return -EINVAL;
197
198 if (bits_per_word <= 8) {
199 mpc83xx_spi->get_rx = mpc83xx_spi_rx_buf_u8;
200 mpc83xx_spi->get_tx = mpc83xx_spi_tx_buf_u8;
201 } else if (bits_per_word <= 16) {
202 mpc83xx_spi->get_rx = mpc83xx_spi_rx_buf_u16;
203 mpc83xx_spi->get_tx = mpc83xx_spi_tx_buf_u16;
204 } else if (bits_per_word <= 32) {
205 mpc83xx_spi->get_rx = mpc83xx_spi_rx_buf_u32;
206 mpc83xx_spi->get_tx = mpc83xx_spi_tx_buf_u32;
207 } else
208 return -EINVAL;
209
210 /* nsecs = (clock period)/2 */
211 if (!hz)
212 hz = spi->max_speed_hz;
213 mpc83xx_spi->nsecs = (1000000000 / 2) / hz;
214 if (mpc83xx_spi->nsecs > MAX_UDELAY_MS * 1000)
215 return -EINVAL;
216
217 if (bits_per_word == 32)
218 bits_per_word = 0;
219 else
220 bits_per_word = bits_per_word - 1;
221
222 regval = mpc83xx_spi_read_reg(&mpc83xx_spi->base->mode);
223
224 /* Mask out bits_per_wordgth */
225 regval &= 0xff0fffff;
226 regval |= SPMODE_LEN(bits_per_word);
227
228 mpc83xx_spi_write_reg(&mpc83xx_spi->base->mode, regval);
229
230 return 0;
231}
232
233static int mpc83xx_spi_setup(struct spi_device *spi)
234{
235 struct spi_bitbang *bitbang;
236 struct mpc83xx_spi *mpc83xx_spi;
237 int retval;
238
239 if (!spi->max_speed_hz)
240 return -EINVAL;
241
242 bitbang = spi_master_get_devdata(spi->master);
243 mpc83xx_spi = spi_master_get_devdata(spi->master);
244
245 if (!spi->bits_per_word)
246 spi->bits_per_word = 8;
247
248 retval = mpc83xx_spi_setup_transfer(spi, NULL);
249 if (retval < 0)
250 return retval;
251
252 dev_dbg(&spi->dev, "%s, mode %d, %u bits/w, %u nsec\n",
253 __FUNCTION__, spi->mode & (SPI_CPOL | SPI_CPHA),
254 spi->bits_per_word, 2 * mpc83xx_spi->nsecs);
255
256 /* NOTE we _need_ to call chipselect() early, ideally with adapter
257 * setup, unless the hardware defaults cooperate to avoid confusion
258 * between normal (active low) and inverted chipselects.
259 */
260
261 /* deselect chip (low or high) */
262 spin_lock(&bitbang->lock);
263 if (!bitbang->busy) {
264 bitbang->chipselect(spi, BITBANG_CS_INACTIVE);
265 ndelay(mpc83xx_spi->nsecs);
266 }
267 spin_unlock(&bitbang->lock);
268
269 return 0;
270}
271
272static int mpc83xx_spi_bufs(struct spi_device *spi, struct spi_transfer *t)
273{
274 struct mpc83xx_spi *mpc83xx_spi;
275 u32 word;
276
277 mpc83xx_spi = spi_master_get_devdata(spi->master);
278
279 mpc83xx_spi->tx = t->tx_buf;
280 mpc83xx_spi->rx = t->rx_buf;
281 mpc83xx_spi->count = t->len;
282 INIT_COMPLETION(mpc83xx_spi->done);
283
284 /* enable rx ints */
285 mpc83xx_spi_write_reg(&mpc83xx_spi->base->mask, SPIM_NE);
286
287 /* transmit word */
288 word = mpc83xx_spi->get_tx(mpc83xx_spi);
289 mpc83xx_spi_write_reg(&mpc83xx_spi->base->transmit, word);
290
291 wait_for_completion(&mpc83xx_spi->done);
292
293 /* disable rx ints */
294 mpc83xx_spi_write_reg(&mpc83xx_spi->base->mask, 0);
295
296 return t->len - mpc83xx_spi->count;
297}
298
299irqreturn_t mpc83xx_spi_irq(s32 irq, void *context_data,
300 struct pt_regs * ptregs)
301{
302 struct mpc83xx_spi *mpc83xx_spi = context_data;
303 u32 event;
304 irqreturn_t ret = IRQ_NONE;
305
306 /* Get interrupt events(tx/rx) */
307 event = mpc83xx_spi_read_reg(&mpc83xx_spi->base->event);
308
309 /* We need handle RX first */
310 if (event & SPIE_NE) {
311 u32 rx_data = mpc83xx_spi_read_reg(&mpc83xx_spi->base->receive);
312
313 if (mpc83xx_spi->rx)
314 mpc83xx_spi->get_rx(rx_data, mpc83xx_spi);
315
316 ret = IRQ_HANDLED;
317 }
318
319 if ((event & SPIE_NF) == 0)
320 /* spin until TX is done */
321 while (((event =
322 mpc83xx_spi_read_reg(&mpc83xx_spi->base->event)) &
323 SPIE_NF) == 0)
324 cpu_relax();
325
326 mpc83xx_spi->count -= 1;
327 if (mpc83xx_spi->count) {
328 if (mpc83xx_spi->tx) {
329 u32 word = mpc83xx_spi->get_tx(mpc83xx_spi);
330 mpc83xx_spi_write_reg(&mpc83xx_spi->base->transmit,
331 word);
332 }
333 } else {
334 complete(&mpc83xx_spi->done);
335 }
336
337 /* Clear the events */
338 mpc83xx_spi_write_reg(&mpc83xx_spi->base->event, event);
339
340 return ret;
341}
342
343static int __init mpc83xx_spi_probe(struct platform_device *dev)
344{
345 struct spi_master *master;
346 struct mpc83xx_spi *mpc83xx_spi;
347 struct fsl_spi_platform_data *pdata;
348 struct resource *r;
349 u32 regval;
350 int ret = 0;
351
352 /* Get resources(memory, IRQ) associated with the device */
353 master = spi_alloc_master(&dev->dev, sizeof(struct mpc83xx_spi));
354
355 if (master == NULL) {
356 ret = -ENOMEM;
357 goto err;
358 }
359
360 platform_set_drvdata(dev, master);
361 pdata = dev->dev.platform_data;
362
363 if (pdata == NULL) {
364 ret = -ENODEV;
365 goto free_master;
366 }
367
368 r = platform_get_resource(dev, IORESOURCE_MEM, 0);
369 if (r == NULL) {
370 ret = -ENODEV;
371 goto free_master;
372 }
373
374 mpc83xx_spi = spi_master_get_devdata(master);
375 mpc83xx_spi->bitbang.master = spi_master_get(master);
376 mpc83xx_spi->bitbang.chipselect = mpc83xx_spi_chipselect;
377 mpc83xx_spi->bitbang.setup_transfer = mpc83xx_spi_setup_transfer;
378 mpc83xx_spi->bitbang.txrx_bufs = mpc83xx_spi_bufs;
379 mpc83xx_spi->sysclk = pdata->sysclk;
380 mpc83xx_spi->activate_cs = pdata->activate_cs;
381 mpc83xx_spi->deactivate_cs = pdata->deactivate_cs;
382 mpc83xx_spi->get_rx = mpc83xx_spi_rx_buf_u8;
383 mpc83xx_spi->get_tx = mpc83xx_spi_tx_buf_u8;
384
385 mpc83xx_spi->bitbang.master->setup = mpc83xx_spi_setup;
386 init_completion(&mpc83xx_spi->done);
387
388 mpc83xx_spi->base = ioremap(r->start, r->end - r->start + 1);
389 if (mpc83xx_spi->base == NULL) {
390 ret = -ENOMEM;
391 goto put_master;
392 }
393
394 mpc83xx_spi->irq = platform_get_irq(dev, 0);
395
396 if (mpc83xx_spi->irq < 0) {
397 ret = -ENXIO;
398 goto unmap_io;
399 }
400
401 /* Register for SPI Interrupt */
402 ret = request_irq(mpc83xx_spi->irq, mpc83xx_spi_irq,
403 0, "mpc83xx_spi", mpc83xx_spi);
404
405 if (ret != 0)
406 goto unmap_io;
407
408 master->bus_num = pdata->bus_num;
409 master->num_chipselect = pdata->max_chipselect;
410
411 /* SPI controller initializations */
412 mpc83xx_spi_write_reg(&mpc83xx_spi->base->mode, 0);
413 mpc83xx_spi_write_reg(&mpc83xx_spi->base->mask, 0);
414 mpc83xx_spi_write_reg(&mpc83xx_spi->base->command, 0);
415 mpc83xx_spi_write_reg(&mpc83xx_spi->base->event, 0xffffffff);
416
417 /* Enable SPI interface */
418 regval = pdata->initial_spmode | SPMODE_INIT_VAL | SPMODE_ENABLE;
419 mpc83xx_spi_write_reg(&mpc83xx_spi->base->mode, regval);
420
421 ret = spi_bitbang_start(&mpc83xx_spi->bitbang);
422
423 if (ret != 0)
424 goto free_irq;
425
426 printk(KERN_INFO
427 "%s: MPC83xx SPI Controller driver at 0x%p (irq = %d)\n",
428 dev->dev.bus_id, mpc83xx_spi->base, mpc83xx_spi->irq);
429
430 return ret;
431
432free_irq:
433 free_irq(mpc83xx_spi->irq, mpc83xx_spi);
434unmap_io:
435 iounmap(mpc83xx_spi->base);
436put_master:
437 spi_master_put(master);
438free_master:
439 kfree(master);
440err:
441 return ret;
442}
443
444static int __devexit mpc83xx_spi_remove(struct platform_device *dev)
445{
446 struct mpc83xx_spi *mpc83xx_spi;
447 struct spi_master *master;
448
449 master = platform_get_drvdata(dev);
450 mpc83xx_spi = spi_master_get_devdata(master);
451
452 spi_bitbang_stop(&mpc83xx_spi->bitbang);
453 free_irq(mpc83xx_spi->irq, mpc83xx_spi);
454 iounmap(mpc83xx_spi->base);
455 spi_master_put(mpc83xx_spi->bitbang.master);
456
457 return 0;
458}
459
460static struct platform_driver mpc83xx_spi_driver = {
461 .probe = mpc83xx_spi_probe,
462 .remove = __devexit_p(mpc83xx_spi_remove),
463 .driver = {
464 .name = "mpc83xx_spi",
465 },
466};
467
468static int __init mpc83xx_spi_init(void)
469{
470 return platform_driver_register(&mpc83xx_spi_driver);
471}
472
473static void __exit mpc83xx_spi_exit(void)
474{
475 platform_driver_unregister(&mpc83xx_spi_driver);
476}
477
478module_init(mpc83xx_spi_init);
479module_exit(mpc83xx_spi_exit);
480
481MODULE_AUTHOR("Kumar Gala");
482MODULE_DESCRIPTION("Simple MPC83xx SPI Driver");
483MODULE_LICENSE("GPL");