Root/target/linux/brcm63xx/patches-3.3/011-spi-add-Broadcom-BCM63xx-SPI-controller-driver.patch

1From 5f592b818a2c5731bb12137e7cffc3aa6e24ee5a Mon Sep 17 00:00:00 2001
2From: Florian Fainelli <florian@openwrt.org>
3Date: Wed, 1 Feb 2012 09:14:09 +0000
4Subject: [PATCH 13/63] spi: add Broadcom BCM63xx SPI controller driver
5
6This patch adds support for the SPI controller found on the Broadcom BCM63xx
7SoCs.
8
9Signed-off-by: Tanguy Bouzeloc <tanguy.bouzeloc@efixo.com>
10Signed-off-by: Florian Fainelli <florian@openwrt.org>
11Acked-by: Grant Likely <grant.likely@secretlab.ca>
12---
13 drivers/spi/Kconfig | 6 +
14 drivers/spi/Makefile | 1 +
15 drivers/spi/spi-bcm63xx.c | 486 +++++++++++++++++++++++++++++++++++++++++++++
16 3 files changed, 493 insertions(+), 0 deletions(-)
17 create mode 100644 drivers/spi/spi-bcm63xx.c
18
19--- a/drivers/spi/Kconfig
20+++ b/drivers/spi/Kconfig
21@@ -94,6 +94,12 @@ config SPI_AU1550
22       If you say yes to this option, support will be included for the
23       PSC SPI controller found on Au1550, Au1200 and Au1300 series.
24 
25+config SPI_BCM63XX
26+ tristate "Broadcom BCM63xx SPI controller"
27+ depends on BCM63XX
28+ help
29+ Enable support for the SPI controller on the Broadcom BCM63xx SoCs.
30+
31 config SPI_BITBANG
32     tristate "Utilities for Bitbanging SPI masters"
33     help
34--- a/drivers/spi/Makefile
35+++ b/drivers/spi/Makefile
36@@ -14,6 +14,7 @@ obj-$(CONFIG_SPI_ALTERA) += spi-altera.
37 obj-$(CONFIG_SPI_ATMEL) += spi-atmel.o
38 obj-$(CONFIG_SPI_ATH79) += spi-ath79.o
39 obj-$(CONFIG_SPI_AU1550) += spi-au1550.o
40+obj-$(CONFIG_SPI_BCM63XX) += spi-bcm63xx.o
41 obj-$(CONFIG_SPI_BFIN) += spi-bfin5xx.o
42 obj-$(CONFIG_SPI_BFIN_SPORT) += spi-bfin-sport.o
43 obj-$(CONFIG_SPI_BITBANG) += spi-bitbang.o
44--- /dev/null
45+++ b/drivers/spi/spi-bcm63xx.c
46@@ -0,0 +1,486 @@
47+/*
48+ * Broadcom BCM63xx SPI controller support
49+ *
50+ * Copyright (C) 2009-2011 Florian Fainelli <florian@openwrt.org>
51+ * Copyright (C) 2010 Tanguy Bouzeloc <tanguy.bouzeloc@efixo.com>
52+ *
53+ * This program is free software; you can redistribute it and/or
54+ * modify it under the terms of the GNU General Public License
55+ * as published by the Free Software Foundation; either version 2
56+ * of the License, or (at your option) any later version.
57+ *
58+ * This program is distributed in the hope that it will be useful,
59+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
60+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
61+ * GNU General Public License for more details.
62+ *
63+ * You should have received a copy of the GNU General Public License
64+ * along with this program; if not, write to the
65+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
66+ */
67+
68+#include <linux/kernel.h>
69+#include <linux/init.h>
70+#include <linux/clk.h>
71+#include <linux/io.h>
72+#include <linux/module.h>
73+#include <linux/platform_device.h>
74+#include <linux/delay.h>
75+#include <linux/interrupt.h>
76+#include <linux/spi/spi.h>
77+#include <linux/completion.h>
78+#include <linux/err.h>
79+
80+#include <bcm63xx_dev_spi.h>
81+
82+#define PFX KBUILD_MODNAME
83+#define DRV_VER "0.1.2"
84+
85+struct bcm63xx_spi {
86+ spinlock_t lock;
87+ int stopping;
88+ struct completion done;
89+
90+ void __iomem *regs;
91+ int irq;
92+
93+ /* Platform data */
94+ u32 speed_hz;
95+ unsigned fifo_size;
96+
97+ /* Data buffers */
98+ const unsigned char *tx_ptr;
99+ unsigned char *rx_ptr;
100+
101+ /* data iomem */
102+ u8 __iomem *tx_io;
103+ const u8 __iomem *rx_io;
104+
105+ int remaining_bytes;
106+
107+ struct clk *clk;
108+ struct platform_device *pdev;
109+};
110+
111+static inline u8 bcm_spi_readb(struct bcm63xx_spi *bs,
112+ unsigned int offset)
113+{
114+ return bcm_readb(bs->regs + bcm63xx_spireg(offset));
115+}
116+
117+static inline u16 bcm_spi_readw(struct bcm63xx_spi *bs,
118+ unsigned int offset)
119+{
120+ return bcm_readw(bs->regs + bcm63xx_spireg(offset));
121+}
122+
123+static inline void bcm_spi_writeb(struct bcm63xx_spi *bs,
124+ u8 value, unsigned int offset)
125+{
126+ bcm_writeb(value, bs->regs + bcm63xx_spireg(offset));
127+}
128+
129+static inline void bcm_spi_writew(struct bcm63xx_spi *bs,
130+ u16 value, unsigned int offset)
131+{
132+ bcm_writew(value, bs->regs + bcm63xx_spireg(offset));
133+}
134+
135+static const unsigned bcm63xx_spi_freq_table[SPI_CLK_MASK][2] = {
136+ { 20000000, SPI_CLK_20MHZ },
137+ { 12500000, SPI_CLK_12_50MHZ },
138+ { 6250000, SPI_CLK_6_250MHZ },
139+ { 3125000, SPI_CLK_3_125MHZ },
140+ { 1563000, SPI_CLK_1_563MHZ },
141+ { 781000, SPI_CLK_0_781MHZ },
142+ { 391000, SPI_CLK_0_391MHZ }
143+};
144+
145+static int bcm63xx_spi_setup_transfer(struct spi_device *spi,
146+ struct spi_transfer *t)
147+{
148+ struct bcm63xx_spi *bs = spi_master_get_devdata(spi->master);
149+ u8 bits_per_word;
150+ u8 clk_cfg, reg;
151+ u32 hz;
152+ int i;
153+
154+ bits_per_word = (t) ? t->bits_per_word : spi->bits_per_word;
155+ hz = (t) ? t->speed_hz : spi->max_speed_hz;
156+ if (bits_per_word != 8) {
157+ dev_err(&spi->dev, "%s, unsupported bits_per_word=%d\n",
158+ __func__, bits_per_word);
159+ return -EINVAL;
160+ }
161+
162+ if (spi->chip_select > spi->master->num_chipselect) {
163+ dev_err(&spi->dev, "%s, unsupported slave %d\n",
164+ __func__, spi->chip_select);
165+ return -EINVAL;
166+ }
167+
168+ /* Find the closest clock configuration */
169+ for (i = 0; i < SPI_CLK_MASK; i++) {
170+ if (hz >= bcm63xx_spi_freq_table[i][0]) {
171+ clk_cfg = bcm63xx_spi_freq_table[i][1];
172+ break;
173+ }
174+ }
175+
176+ /* No matching configuration found, default to lowest */
177+ if (i == SPI_CLK_MASK)
178+ clk_cfg = SPI_CLK_0_391MHZ;
179+
180+ /* clear existing clock configuration bits of the register */
181+ reg = bcm_spi_readb(bs, SPI_CLK_CFG);
182+ reg &= ~SPI_CLK_MASK;
183+ reg |= clk_cfg;
184+
185+ bcm_spi_writeb(bs, reg, SPI_CLK_CFG);
186+ dev_dbg(&spi->dev, "Setting clock register to %02x (hz %d)\n",
187+ clk_cfg, hz);
188+
189+ return 0;
190+}
191+
192+/* the spi->mode bits understood by this driver: */
193+#define MODEBITS (SPI_CPOL | SPI_CPHA)
194+
195+static int bcm63xx_spi_setup(struct spi_device *spi)
196+{
197+ struct bcm63xx_spi *bs;
198+ int ret;
199+
200+ bs = spi_master_get_devdata(spi->master);
201+
202+ if (bs->stopping)
203+ return -ESHUTDOWN;
204+
205+ if (!spi->bits_per_word)
206+ spi->bits_per_word = 8;
207+
208+ if (spi->mode & ~MODEBITS) {
209+ dev_err(&spi->dev, "%s, unsupported mode bits %x\n",
210+ __func__, spi->mode & ~MODEBITS);
211+ return -EINVAL;
212+ }
213+
214+ ret = bcm63xx_spi_setup_transfer(spi, NULL);
215+ if (ret < 0) {
216+ dev_err(&spi->dev, "setup: unsupported mode bits %x\n",
217+ spi->mode & ~MODEBITS);
218+ return ret;
219+ }
220+
221+ dev_dbg(&spi->dev, "%s, mode %d, %u bits/w, %u nsec/bit\n",
222+ __func__, spi->mode & MODEBITS, spi->bits_per_word, 0);
223+
224+ return 0;
225+}
226+
227+/* Fill the TX FIFO with as many bytes as possible */
228+static void bcm63xx_spi_fill_tx_fifo(struct bcm63xx_spi *bs)
229+{
230+ u8 size;
231+
232+ /* Fill the Tx FIFO with as many bytes as possible */
233+ size = bs->remaining_bytes < bs->fifo_size ? bs->remaining_bytes :
234+ bs->fifo_size;
235+ memcpy_toio(bs->tx_io, bs->tx_ptr, size);
236+ bs->remaining_bytes -= size;
237+}
238+
239+static int bcm63xx_txrx_bufs(struct spi_device *spi, struct spi_transfer *t)
240+{
241+ struct bcm63xx_spi *bs = spi_master_get_devdata(spi->master);
242+ u16 msg_ctl;
243+ u16 cmd;
244+
245+ dev_dbg(&spi->dev, "txrx: tx %p, rx %p, len %d\n",
246+ t->tx_buf, t->rx_buf, t->len);
247+
248+ /* Transmitter is inhibited */
249+ bs->tx_ptr = t->tx_buf;
250+ bs->rx_ptr = t->rx_buf;
251+ init_completion(&bs->done);
252+
253+ if (t->tx_buf) {
254+ bs->remaining_bytes = t->len;
255+ bcm63xx_spi_fill_tx_fifo(bs);
256+ }
257+
258+ /* Enable the command done interrupt which
259+ * we use to determine completion of a command */
260+ bcm_spi_writeb(bs, SPI_INTR_CMD_DONE, SPI_INT_MASK);
261+
262+ /* Fill in the Message control register */
263+ msg_ctl = (t->len << SPI_BYTE_CNT_SHIFT);
264+
265+ if (t->rx_buf && t->tx_buf)
266+ msg_ctl |= (SPI_FD_RW << SPI_MSG_TYPE_SHIFT);
267+ else if (t->rx_buf)
268+ msg_ctl |= (SPI_HD_R << SPI_MSG_TYPE_SHIFT);
269+ else if (t->tx_buf)
270+ msg_ctl |= (SPI_HD_W << SPI_MSG_TYPE_SHIFT);
271+
272+ bcm_spi_writew(bs, msg_ctl, SPI_MSG_CTL);
273+
274+ /* Issue the transfer */
275+ cmd = SPI_CMD_START_IMMEDIATE;
276+ cmd |= (0 << SPI_CMD_PREPEND_BYTE_CNT_SHIFT);
277+ cmd |= (spi->chip_select << SPI_CMD_DEVICE_ID_SHIFT);
278+ bcm_spi_writew(bs, cmd, SPI_CMD);
279+ wait_for_completion(&bs->done);
280+
281+ /* Disable the CMD_DONE interrupt */
282+ bcm_spi_writeb(bs, 0, SPI_INT_MASK);
283+
284+ return t->len - bs->remaining_bytes;
285+}
286+
287+static int bcm63xx_transfer(struct spi_device *spi, struct spi_message *m)
288+{
289+ struct bcm63xx_spi *bs = spi_master_get_devdata(spi->master);
290+ struct spi_transfer *t;
291+ int ret = 0;
292+
293+ if (unlikely(list_empty(&m->transfers)))
294+ return -EINVAL;
295+
296+ if (bs->stopping)
297+ return -ESHUTDOWN;
298+
299+ list_for_each_entry(t, &m->transfers, transfer_list) {
300+ ret += bcm63xx_txrx_bufs(spi, t);
301+ }
302+
303+ m->complete(m->context);
304+
305+ return ret;
306+}
307+
308+/* This driver supports single master mode only. Hence
309+ * CMD_DONE is the only interrupt we care about
310+ */
311+static irqreturn_t bcm63xx_spi_interrupt(int irq, void *dev_id)
312+{
313+ struct spi_master *master = (struct spi_master *)dev_id;
314+ struct bcm63xx_spi *bs = spi_master_get_devdata(master);
315+ u8 intr;
316+ u16 cmd;
317+
318+ /* Read interupts and clear them immediately */
319+ intr = bcm_spi_readb(bs, SPI_INT_STATUS);
320+ bcm_spi_writeb(bs, SPI_INTR_CLEAR_ALL, SPI_INT_STATUS);
321+ bcm_spi_writeb(bs, 0, SPI_INT_MASK);
322+
323+ /* A tansfer completed */
324+ if (intr & SPI_INTR_CMD_DONE) {
325+ u8 rx_tail;
326+
327+ rx_tail = bcm_spi_readb(bs, SPI_RX_TAIL);
328+
329+ /* Read out all the data */
330+ if (rx_tail)
331+ memcpy_fromio(bs->rx_ptr, bs->rx_io, rx_tail);
332+
333+ /* See if there is more data to send */
334+ if (bs->remaining_bytes > 0) {
335+ bcm63xx_spi_fill_tx_fifo(bs);
336+
337+ /* Start the transfer */
338+ bcm_spi_writew(bs, SPI_HD_W << SPI_MSG_TYPE_SHIFT,
339+ SPI_MSG_CTL);
340+ cmd = bcm_spi_readw(bs, SPI_CMD);
341+ cmd |= SPI_CMD_START_IMMEDIATE;
342+ cmd |= (0 << SPI_CMD_PREPEND_BYTE_CNT_SHIFT);
343+ bcm_spi_writeb(bs, SPI_INTR_CMD_DONE, SPI_INT_MASK);
344+ bcm_spi_writew(bs, cmd, SPI_CMD);
345+ } else {
346+ complete(&bs->done);
347+ }
348+ }
349+
350+ return IRQ_HANDLED;
351+}
352+
353+
354+static int __devinit bcm63xx_spi_probe(struct platform_device *pdev)
355+{
356+ struct resource *r;
357+ struct device *dev = &pdev->dev;
358+ struct bcm63xx_spi_pdata *pdata = pdev->dev.platform_data;
359+ int irq;
360+ struct spi_master *master;
361+ struct clk *clk;
362+ struct bcm63xx_spi *bs;
363+ int ret;
364+
365+ r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
366+ if (!r) {
367+ dev_err(dev, "no iomem\n");
368+ ret = -ENXIO;
369+ goto out;
370+ }
371+
372+ irq = platform_get_irq(pdev, 0);
373+ if (irq < 0) {
374+ dev_err(dev, "no irq\n");
375+ ret = -ENXIO;
376+ goto out;
377+ }
378+
379+ clk = clk_get(dev, "spi");
380+ if (IS_ERR(clk)) {
381+ dev_err(dev, "no clock for device\n");
382+ ret = PTR_ERR(clk);
383+ goto out;
384+ }
385+
386+ master = spi_alloc_master(dev, sizeof(*bs));
387+ if (!master) {
388+ dev_err(dev, "out of memory\n");
389+ ret = -ENOMEM;
390+ goto out_clk;
391+ }
392+
393+ bs = spi_master_get_devdata(master);
394+ init_completion(&bs->done);
395+
396+ platform_set_drvdata(pdev, master);
397+ bs->pdev = pdev;
398+
399+ if (!devm_request_mem_region(&pdev->dev, r->start,
400+ resource_size(r), PFX)) {
401+ dev_err(dev, "iomem request failed\n");
402+ ret = -ENXIO;
403+ goto out_err;
404+ }
405+
406+ bs->regs = devm_ioremap_nocache(&pdev->dev, r->start,
407+ resource_size(r));
408+ if (!bs->regs) {
409+ dev_err(dev, "unable to ioremap regs\n");
410+ ret = -ENOMEM;
411+ goto out_err;
412+ }
413+
414+ bs->irq = irq;
415+ bs->clk = clk;
416+ bs->fifo_size = pdata->fifo_size;
417+
418+ ret = devm_request_irq(&pdev->dev, irq, bcm63xx_spi_interrupt, 0,
419+ pdev->name, master);
420+ if (ret) {
421+ dev_err(dev, "unable to request irq\n");
422+ goto out_err;
423+ }
424+
425+ master->bus_num = pdata->bus_num;
426+ master->num_chipselect = pdata->num_chipselect;
427+ master->setup = bcm63xx_spi_setup;
428+ master->transfer = bcm63xx_transfer;
429+ bs->speed_hz = pdata->speed_hz;
430+ bs->stopping = 0;
431+ bs->tx_io = (u8 *)(bs->regs + bcm63xx_spireg(SPI_MSG_DATA));
432+ bs->rx_io = (const u8 *)(bs->regs + bcm63xx_spireg(SPI_RX_DATA));
433+ spin_lock_init(&bs->lock);
434+
435+ /* Initialize hardware */
436+ clk_enable(bs->clk);
437+ bcm_spi_writeb(bs, SPI_INTR_CLEAR_ALL, SPI_INT_STATUS);
438+
439+ /* register and we are done */
440+ ret = spi_register_master(master);
441+ if (ret) {
442+ dev_err(dev, "spi register failed\n");
443+ goto out_clk_disable;
444+ }
445+
446+ dev_info(dev, "at 0x%08x (irq %d, FIFOs size %d) v%s\n",
447+ r->start, irq, bs->fifo_size, DRV_VER);
448+
449+ return 0;
450+
451+out_clk_disable:
452+ clk_disable(clk);
453+out_err:
454+ platform_set_drvdata(pdev, NULL);
455+ spi_master_put(master);
456+out_clk:
457+ clk_put(clk);
458+out:
459+ return ret;
460+}
461+
462+static int __devexit bcm63xx_spi_remove(struct platform_device *pdev)
463+{
464+ struct spi_master *master = platform_get_drvdata(pdev);
465+ struct bcm63xx_spi *bs = spi_master_get_devdata(master);
466+
467+ /* reset spi block */
468+ bcm_spi_writeb(bs, 0, SPI_INT_MASK);
469+ spin_lock(&bs->lock);
470+ bs->stopping = 1;
471+
472+ /* HW shutdown */
473+ clk_disable(bs->clk);
474+ clk_put(bs->clk);
475+
476+ spin_unlock(&bs->lock);
477+ platform_set_drvdata(pdev, 0);
478+ spi_unregister_master(master);
479+
480+ return 0;
481+}
482+
483+#ifdef CONFIG_PM
484+static int bcm63xx_spi_suspend(struct device *dev)
485+{
486+ struct spi_master *master =
487+ platform_get_drvdata(to_platform_device(dev));
488+ struct bcm63xx_spi *bs = spi_master_get_devdata(master);
489+
490+ clk_disable(bs->clk);
491+
492+ return 0;
493+}
494+
495+static int bcm63xx_spi_resume(struct device *dev)
496+{
497+ struct spi_master *master =
498+ platform_get_drvdata(to_platform_device(dev));
499+ struct bcm63xx_spi *bs = spi_master_get_devdata(master);
500+
501+ clk_enable(bs->clk);
502+
503+ return 0;
504+}
505+
506+static const struct dev_pm_ops bcm63xx_spi_pm_ops = {
507+ .suspend = bcm63xx_spi_suspend,
508+ .resume = bcm63xx_spi_resume,
509+};
510+
511+#define BCM63XX_SPI_PM_OPS (&bcm63xx_spi_pm_ops)
512+#else
513+#define BCM63XX_SPI_PM_OPS NULL
514+#endif
515+
516+static struct platform_driver bcm63xx_spi_driver = {
517+ .driver = {
518+ .name = "bcm63xx-spi",
519+ .owner = THIS_MODULE,
520+ .pm = BCM63XX_SPI_PM_OPS,
521+ },
522+ .probe = bcm63xx_spi_probe,
523+ .remove = __devexit_p(bcm63xx_spi_remove),
524+};
525+
526+module_platform_driver(bcm63xx_spi_driver);
527+
528+MODULE_ALIAS("platform:bcm63xx_spi");
529+MODULE_AUTHOR("Florian Fainelli <florian@openwrt.org>");
530+MODULE_AUTHOR("Tanguy Bouzeloc <tanguy.bouzeloc@efixo.com>");
531+MODULE_DESCRIPTION("Broadcom BCM63xx SPI Controller driver");
532+MODULE_LICENSE("GPL");
533

Archive Download this file



interactive