blob: 74312a862ba80b235f731cf6fbe867b0f96ffdff [file] [log] [blame]
Shadi Ammouri60cadec2008-08-05 13:01:09 -07001/*
Grant Likelyca632f52011-06-06 01:16:30 -06002 * Marvell Orion SPI controller driver
Shadi Ammouri60cadec2008-08-05 13:01:09 -07003 *
4 * Author: Shadi Ammouri <shadi@marvell.com>
5 * Copyright (C) 2007-2008 Marvell Ltd.
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
10 */
11
12#include <linux/init.h>
13#include <linux/interrupt.h>
14#include <linux/delay.h>
15#include <linux/platform_device.h>
16#include <linux/err.h>
17#include <linux/io.h>
18#include <linux/spi/spi.h>
Paul Gortmakerd7614de2011-07-03 15:44:29 -040019#include <linux/module.h>
Andrew Lunnf814f9a2012-07-23 12:08:09 +020020#include <linux/of.h>
Andrew Lunn4574b882012-04-06 17:17:26 +020021#include <linux/clk.h>
Shadi Ammouri60cadec2008-08-05 13:01:09 -070022#include <asm/unaligned.h>
23
24#define DRIVER_NAME "orion_spi"
25
26#define ORION_NUM_CHIPSELECTS 1 /* only one slave is supported*/
27#define ORION_SPI_WAIT_RDY_MAX_LOOP 2000 /* in usec */
28
29#define ORION_SPI_IF_CTRL_REG 0x00
30#define ORION_SPI_IF_CONFIG_REG 0x04
31#define ORION_SPI_DATA_OUT_REG 0x08
32#define ORION_SPI_DATA_IN_REG 0x0c
33#define ORION_SPI_INT_CAUSE_REG 0x10
34
35#define ORION_SPI_IF_8_16_BIT_MODE (1 << 5)
36#define ORION_SPI_CLK_PRESCALE_MASK 0x1F
37
38struct orion_spi {
39 struct work_struct work;
40
41 /* Lock access to transfer list. */
42 spinlock_t lock;
43
44 struct list_head msg_queue;
45 struct spi_master *master;
46 void __iomem *base;
47 unsigned int max_speed;
48 unsigned int min_speed;
49 struct orion_spi_info *spi_info;
Andrew Lunn4574b882012-04-06 17:17:26 +020050 struct clk *clk;
Shadi Ammouri60cadec2008-08-05 13:01:09 -070051};
52
53static struct workqueue_struct *orion_spi_wq;
54
55static inline void __iomem *spi_reg(struct orion_spi *orion_spi, u32 reg)
56{
57 return orion_spi->base + reg;
58}
59
60static inline void
61orion_spi_setbits(struct orion_spi *orion_spi, u32 reg, u32 mask)
62{
63 void __iomem *reg_addr = spi_reg(orion_spi, reg);
64 u32 val;
65
66 val = readl(reg_addr);
67 val |= mask;
68 writel(val, reg_addr);
69}
70
71static inline void
72orion_spi_clrbits(struct orion_spi *orion_spi, u32 reg, u32 mask)
73{
74 void __iomem *reg_addr = spi_reg(orion_spi, reg);
75 u32 val;
76
77 val = readl(reg_addr);
78 val &= ~mask;
79 writel(val, reg_addr);
80}
81
82static int orion_spi_set_transfer_size(struct orion_spi *orion_spi, int size)
83{
84 if (size == 16) {
85 orion_spi_setbits(orion_spi, ORION_SPI_IF_CONFIG_REG,
86 ORION_SPI_IF_8_16_BIT_MODE);
87 } else if (size == 8) {
88 orion_spi_clrbits(orion_spi, ORION_SPI_IF_CONFIG_REG,
89 ORION_SPI_IF_8_16_BIT_MODE);
90 } else {
91 pr_debug("Bad bits per word value %d (only 8 or 16 are "
92 "allowed).\n", size);
93 return -EINVAL;
94 }
95
96 return 0;
97}
98
99static int orion_spi_baudrate_set(struct spi_device *spi, unsigned int speed)
100{
101 u32 tclk_hz;
102 u32 rate;
103 u32 prescale;
104 u32 reg;
105 struct orion_spi *orion_spi;
106
107 orion_spi = spi_master_get_devdata(spi->master);
108
Andrew Lunn4574b882012-04-06 17:17:26 +0200109 tclk_hz = clk_get_rate(orion_spi->clk);
Shadi Ammouri60cadec2008-08-05 13:01:09 -0700110
111 /*
112 * the supported rates are: 4,6,8...30
113 * round up as we look for equal or less speed
114 */
115 rate = DIV_ROUND_UP(tclk_hz, speed);
116 rate = roundup(rate, 2);
117
118 /* check if requested speed is too small */
119 if (rate > 30)
120 return -EINVAL;
121
122 if (rate < 4)
123 rate = 4;
124
125 /* Convert the rate to SPI clock divisor value. */
126 prescale = 0x10 + rate/2;
127
128 reg = readl(spi_reg(orion_spi, ORION_SPI_IF_CONFIG_REG));
129 reg = ((reg & ~ORION_SPI_CLK_PRESCALE_MASK) | prescale);
130 writel(reg, spi_reg(orion_spi, ORION_SPI_IF_CONFIG_REG));
131
132 return 0;
133}
134
135/*
136 * called only when no transfer is active on the bus
137 */
138static int
139orion_spi_setup_transfer(struct spi_device *spi, struct spi_transfer *t)
140{
141 struct orion_spi *orion_spi;
142 unsigned int speed = spi->max_speed_hz;
143 unsigned int bits_per_word = spi->bits_per_word;
144 int rc;
145
146 orion_spi = spi_master_get_devdata(spi->master);
147
148 if ((t != NULL) && t->speed_hz)
149 speed = t->speed_hz;
150
151 if ((t != NULL) && t->bits_per_word)
152 bits_per_word = t->bits_per_word;
153
154 rc = orion_spi_baudrate_set(spi, speed);
155 if (rc)
156 return rc;
157
158 return orion_spi_set_transfer_size(orion_spi, bits_per_word);
159}
160
161static void orion_spi_set_cs(struct orion_spi *orion_spi, int enable)
162{
163 if (enable)
164 orion_spi_setbits(orion_spi, ORION_SPI_IF_CTRL_REG, 0x1);
165 else
166 orion_spi_clrbits(orion_spi, ORION_SPI_IF_CTRL_REG, 0x1);
167}
168
169static inline int orion_spi_wait_till_ready(struct orion_spi *orion_spi)
170{
171 int i;
172
173 for (i = 0; i < ORION_SPI_WAIT_RDY_MAX_LOOP; i++) {
174 if (readl(spi_reg(orion_spi, ORION_SPI_INT_CAUSE_REG)))
175 return 1;
176 else
177 udelay(1);
178 }
179
180 return -1;
181}
182
183static inline int
184orion_spi_write_read_8bit(struct spi_device *spi,
185 const u8 **tx_buf, u8 **rx_buf)
186{
187 void __iomem *tx_reg, *rx_reg, *int_reg;
188 struct orion_spi *orion_spi;
189
190 orion_spi = spi_master_get_devdata(spi->master);
191 tx_reg = spi_reg(orion_spi, ORION_SPI_DATA_OUT_REG);
192 rx_reg = spi_reg(orion_spi, ORION_SPI_DATA_IN_REG);
193 int_reg = spi_reg(orion_spi, ORION_SPI_INT_CAUSE_REG);
194
195 /* clear the interrupt cause register */
196 writel(0x0, int_reg);
197
198 if (tx_buf && *tx_buf)
199 writel(*(*tx_buf)++, tx_reg);
200 else
201 writel(0, tx_reg);
202
203 if (orion_spi_wait_till_ready(orion_spi) < 0) {
204 dev_err(&spi->dev, "TXS timed out\n");
205 return -1;
206 }
207
208 if (rx_buf && *rx_buf)
209 *(*rx_buf)++ = readl(rx_reg);
210
211 return 1;
212}
213
214static inline int
215orion_spi_write_read_16bit(struct spi_device *spi,
216 const u16 **tx_buf, u16 **rx_buf)
217{
218 void __iomem *tx_reg, *rx_reg, *int_reg;
219 struct orion_spi *orion_spi;
220
221 orion_spi = spi_master_get_devdata(spi->master);
222 tx_reg = spi_reg(orion_spi, ORION_SPI_DATA_OUT_REG);
223 rx_reg = spi_reg(orion_spi, ORION_SPI_DATA_IN_REG);
224 int_reg = spi_reg(orion_spi, ORION_SPI_INT_CAUSE_REG);
225
226 /* clear the interrupt cause register */
227 writel(0x0, int_reg);
228
229 if (tx_buf && *tx_buf)
230 writel(__cpu_to_le16(get_unaligned((*tx_buf)++)), tx_reg);
231 else
232 writel(0, tx_reg);
233
234 if (orion_spi_wait_till_ready(orion_spi) < 0) {
235 dev_err(&spi->dev, "TXS timed out\n");
236 return -1;
237 }
238
239 if (rx_buf && *rx_buf)
240 put_unaligned(__le16_to_cpu(readl(rx_reg)), (*rx_buf)++);
241
242 return 1;
243}
244
245static unsigned int
246orion_spi_write_read(struct spi_device *spi, struct spi_transfer *xfer)
247{
248 struct orion_spi *orion_spi;
249 unsigned int count;
250 int word_len;
251
252 orion_spi = spi_master_get_devdata(spi->master);
253 word_len = spi->bits_per_word;
254 count = xfer->len;
255
256 if (word_len == 8) {
257 const u8 *tx = xfer->tx_buf;
258 u8 *rx = xfer->rx_buf;
259
260 do {
261 if (orion_spi_write_read_8bit(spi, &tx, &rx) < 0)
262 goto out;
263 count--;
264 } while (count);
265 } else if (word_len == 16) {
266 const u16 *tx = xfer->tx_buf;
267 u16 *rx = xfer->rx_buf;
268
269 do {
270 if (orion_spi_write_read_16bit(spi, &tx, &rx) < 0)
271 goto out;
272 count -= 2;
273 } while (count);
274 }
275
276out:
277 return xfer->len - count;
278}
279
280
281static void orion_spi_work(struct work_struct *work)
282{
283 struct orion_spi *orion_spi =
284 container_of(work, struct orion_spi, work);
285
286 spin_lock_irq(&orion_spi->lock);
287 while (!list_empty(&orion_spi->msg_queue)) {
288 struct spi_message *m;
289 struct spi_device *spi;
290 struct spi_transfer *t = NULL;
291 int par_override = 0;
292 int status = 0;
293 int cs_active = 0;
294
295 m = container_of(orion_spi->msg_queue.next, struct spi_message,
296 queue);
297
298 list_del_init(&m->queue);
299 spin_unlock_irq(&orion_spi->lock);
300
301 spi = m->spi;
302
303 /* Load defaults */
304 status = orion_spi_setup_transfer(spi, NULL);
305
306 if (status < 0)
307 goto msg_done;
308
309 list_for_each_entry(t, &m->transfers, transfer_list) {
310 if (par_override || t->speed_hz || t->bits_per_word) {
311 par_override = 1;
312 status = orion_spi_setup_transfer(spi, t);
313 if (status < 0)
314 break;
315 if (!t->speed_hz && !t->bits_per_word)
316 par_override = 0;
317 }
318
319 if (!cs_active) {
320 orion_spi_set_cs(orion_spi, 1);
321 cs_active = 1;
322 }
323
324 if (t->len)
325 m->actual_length +=
326 orion_spi_write_read(spi, t);
327
328 if (t->delay_usecs)
329 udelay(t->delay_usecs);
330
331 if (t->cs_change) {
332 orion_spi_set_cs(orion_spi, 0);
333 cs_active = 0;
334 }
335 }
336
337msg_done:
338 if (cs_active)
339 orion_spi_set_cs(orion_spi, 0);
340
341 m->status = status;
342 m->complete(m->context);
343
344 spin_lock_irq(&orion_spi->lock);
345 }
346
347 spin_unlock_irq(&orion_spi->lock);
348}
349
350static int __init orion_spi_reset(struct orion_spi *orion_spi)
351{
352 /* Verify that the CS is deasserted */
353 orion_spi_set_cs(orion_spi, 0);
354
355 return 0;
356}
357
358static int orion_spi_setup(struct spi_device *spi)
359{
360 struct orion_spi *orion_spi;
361
362 orion_spi = spi_master_get_devdata(spi->master);
363
Shadi Ammouri60cadec2008-08-05 13:01:09 -0700364 if ((spi->max_speed_hz == 0)
365 || (spi->max_speed_hz > orion_spi->max_speed))
366 spi->max_speed_hz = orion_spi->max_speed;
367
368 if (spi->max_speed_hz < orion_spi->min_speed) {
369 dev_err(&spi->dev, "setup: requested speed too low %d Hz\n",
370 spi->max_speed_hz);
371 return -EINVAL;
372 }
373
374 /*
375 * baudrate & width will be set orion_spi_setup_transfer
376 */
377 return 0;
378}
379
380static int orion_spi_transfer(struct spi_device *spi, struct spi_message *m)
381{
382 struct orion_spi *orion_spi;
383 struct spi_transfer *t = NULL;
384 unsigned long flags;
385
386 m->actual_length = 0;
387 m->status = 0;
388
389 /* reject invalid messages and transfers */
390 if (list_empty(&m->transfers) || !m->complete)
391 return -EINVAL;
392
393 orion_spi = spi_master_get_devdata(spi->master);
394
395 list_for_each_entry(t, &m->transfers, transfer_list) {
396 unsigned int bits_per_word = spi->bits_per_word;
397
398 if (t->tx_buf == NULL && t->rx_buf == NULL && t->len) {
399 dev_err(&spi->dev,
400 "message rejected : "
401 "invalid transfer data buffers\n");
402 goto msg_rejected;
403 }
404
Julia Lawalle447d352010-09-29 17:31:29 +0900405 if (t->bits_per_word)
Shadi Ammouri60cadec2008-08-05 13:01:09 -0700406 bits_per_word = t->bits_per_word;
407
408 if ((bits_per_word != 8) && (bits_per_word != 16)) {
409 dev_err(&spi->dev,
410 "message rejected : "
411 "invalid transfer bits_per_word (%d bits)\n",
412 bits_per_word);
413 goto msg_rejected;
414 }
415 /*make sure buffer length is even when working in 16 bit mode*/
Julia Lawalle447d352010-09-29 17:31:29 +0900416 if ((t->bits_per_word == 16) && (t->len & 1)) {
Shadi Ammouri60cadec2008-08-05 13:01:09 -0700417 dev_err(&spi->dev,
418 "message rejected : "
419 "odd data length (%d) while in 16 bit mode\n",
420 t->len);
421 goto msg_rejected;
422 }
423
Lennert Buytenhekf2fe1632008-10-03 15:23:39 -0700424 if (t->speed_hz && t->speed_hz < orion_spi->min_speed) {
Shadi Ammouri60cadec2008-08-05 13:01:09 -0700425 dev_err(&spi->dev,
426 "message rejected : "
427 "device min speed (%d Hz) exceeds "
428 "required transfer speed (%d Hz)\n",
429 orion_spi->min_speed, t->speed_hz);
430 goto msg_rejected;
431 }
432 }
433
434
435 spin_lock_irqsave(&orion_spi->lock, flags);
436 list_add_tail(&m->queue, &orion_spi->msg_queue);
437 queue_work(orion_spi_wq, &orion_spi->work);
438 spin_unlock_irqrestore(&orion_spi->lock, flags);
439
440 return 0;
441msg_rejected:
442 /* Message rejected and not queued */
443 m->status = -EINVAL;
444 if (m->complete)
445 m->complete(m->context);
446 return -EINVAL;
447}
448
449static int __init orion_spi_probe(struct platform_device *pdev)
450{
451 struct spi_master *master;
452 struct orion_spi *spi;
453 struct resource *r;
454 struct orion_spi_info *spi_info;
Andrew Lunn4574b882012-04-06 17:17:26 +0200455 unsigned long tclk_hz;
Shadi Ammouri60cadec2008-08-05 13:01:09 -0700456 int status = 0;
Andrew Lunnf814f9a2012-07-23 12:08:09 +0200457 const u32 *iprop;
458 int size;
Shadi Ammouri60cadec2008-08-05 13:01:09 -0700459
460 spi_info = pdev->dev.platform_data;
461
462 master = spi_alloc_master(&pdev->dev, sizeof *spi);
463 if (master == NULL) {
464 dev_dbg(&pdev->dev, "master allocation failed\n");
465 return -ENOMEM;
466 }
467
468 if (pdev->id != -1)
469 master->bus_num = pdev->id;
Andrew Lunnf814f9a2012-07-23 12:08:09 +0200470 if (pdev->dev.of_node) {
471 iprop = of_get_property(pdev->dev.of_node, "cell-index",
472 &size);
473 if (iprop && size == sizeof(*iprop))
474 master->bus_num = *iprop;
475 }
Shadi Ammouri60cadec2008-08-05 13:01:09 -0700476
David Brownelle7db06b2009-06-17 16:26:04 -0700477 /* we support only mode 0, and no options */
478 master->mode_bits = 0;
479
Shadi Ammouri60cadec2008-08-05 13:01:09 -0700480 master->setup = orion_spi_setup;
481 master->transfer = orion_spi_transfer;
482 master->num_chipselect = ORION_NUM_CHIPSELECTS;
483
484 dev_set_drvdata(&pdev->dev, master);
485
486 spi = spi_master_get_devdata(master);
487 spi->master = master;
488 spi->spi_info = spi_info;
489
Andrew Lunn4574b882012-04-06 17:17:26 +0200490 spi->clk = clk_get(&pdev->dev, NULL);
491 if (IS_ERR(spi->clk)) {
492 status = PTR_ERR(spi->clk);
493 goto out;
494 }
495
496 clk_prepare(spi->clk);
497 clk_enable(spi->clk);
498 tclk_hz = clk_get_rate(spi->clk);
499 spi->max_speed = DIV_ROUND_UP(tclk_hz, 4);
500 spi->min_speed = DIV_ROUND_UP(tclk_hz, 30);
Shadi Ammouri60cadec2008-08-05 13:01:09 -0700501
502 r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
503 if (r == NULL) {
504 status = -ENODEV;
Andrew Lunn4574b882012-04-06 17:17:26 +0200505 goto out_rel_clk;
Shadi Ammouri60cadec2008-08-05 13:01:09 -0700506 }
507
Joe Perches8e2943c2011-06-10 18:11:25 -0700508 if (!request_mem_region(r->start, resource_size(r),
Kay Sievers6c7377a2009-03-24 16:38:21 -0700509 dev_name(&pdev->dev))) {
Shadi Ammouri60cadec2008-08-05 13:01:09 -0700510 status = -EBUSY;
Andrew Lunn4574b882012-04-06 17:17:26 +0200511 goto out_rel_clk;
Shadi Ammouri60cadec2008-08-05 13:01:09 -0700512 }
513 spi->base = ioremap(r->start, SZ_1K);
514
515 INIT_WORK(&spi->work, orion_spi_work);
516
517 spin_lock_init(&spi->lock);
518 INIT_LIST_HEAD(&spi->msg_queue);
519
520 if (orion_spi_reset(spi) < 0)
521 goto out_rel_mem;
522
Andrew Lunnf814f9a2012-07-23 12:08:09 +0200523 master->dev.of_node = pdev->dev.of_node;
Shadi Ammouri60cadec2008-08-05 13:01:09 -0700524 status = spi_register_master(master);
525 if (status < 0)
526 goto out_rel_mem;
527
528 return status;
529
530out_rel_mem:
Joe Perches8e2943c2011-06-10 18:11:25 -0700531 release_mem_region(r->start, resource_size(r));
Andrew Lunn4574b882012-04-06 17:17:26 +0200532out_rel_clk:
533 clk_disable_unprepare(spi->clk);
534 clk_put(spi->clk);
Shadi Ammouri60cadec2008-08-05 13:01:09 -0700535out:
536 spi_master_put(master);
537 return status;
538}
539
540
541static int __exit orion_spi_remove(struct platform_device *pdev)
542{
543 struct spi_master *master;
544 struct orion_spi *spi;
545 struct resource *r;
546
547 master = dev_get_drvdata(&pdev->dev);
548 spi = spi_master_get_devdata(master);
549
550 cancel_work_sync(&spi->work);
551
Andrew Lunn4574b882012-04-06 17:17:26 +0200552 clk_disable_unprepare(spi->clk);
553 clk_put(spi->clk);
554
Shadi Ammouri60cadec2008-08-05 13:01:09 -0700555 r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
Joe Perches8e2943c2011-06-10 18:11:25 -0700556 release_mem_region(r->start, resource_size(r));
Shadi Ammouri60cadec2008-08-05 13:01:09 -0700557
558 spi_unregister_master(master);
559
560 return 0;
561}
562
563MODULE_ALIAS("platform:" DRIVER_NAME);
564
Andrew Lunnf814f9a2012-07-23 12:08:09 +0200565static const struct of_device_id orion_spi_of_match_table[] __devinitdata = {
566 { .compatible = "marvell,orion-spi", },
567 {}
568};
569MODULE_DEVICE_TABLE(of, orion_spi_of_match_table);
570
Shadi Ammouri60cadec2008-08-05 13:01:09 -0700571static struct platform_driver orion_spi_driver = {
572 .driver = {
573 .name = DRIVER_NAME,
574 .owner = THIS_MODULE,
Andrew Lunnf814f9a2012-07-23 12:08:09 +0200575 .of_match_table = of_match_ptr(orion_spi_of_match_table),
Shadi Ammouri60cadec2008-08-05 13:01:09 -0700576 },
577 .remove = __exit_p(orion_spi_remove),
578};
579
580static int __init orion_spi_init(void)
581{
582 orion_spi_wq = create_singlethread_workqueue(
583 orion_spi_driver.driver.name);
584 if (orion_spi_wq == NULL)
585 return -ENOMEM;
586
587 return platform_driver_probe(&orion_spi_driver, orion_spi_probe);
588}
589module_init(orion_spi_init);
590
591static void __exit orion_spi_exit(void)
592{
593 flush_workqueue(orion_spi_wq);
594 platform_driver_unregister(&orion_spi_driver);
595
596 destroy_workqueue(orion_spi_wq);
597}
598module_exit(orion_spi_exit);
599
600MODULE_DESCRIPTION("Orion SPI driver");
601MODULE_AUTHOR("Shadi Ammouri <shadi@marvell.com>");
602MODULE_LICENSE("GPL");