Root/target/linux/cns21xx/patches-2.6.37/105-cns21xx-spi-driver.patch

1--- a/include/linux/spi/spi.h
2+++ b/include/linux/spi/spi.h
3@@ -445,6 +445,8 @@ struct spi_transfer {
4     u16 delay_usecs;
5     u32 speed_hz;
6 
7+ unsigned last_in_message_list;
8+
9     struct list_head transfer_list;
10 };
11 
12--- a/drivers/spi/Kconfig
13+++ b/drivers/spi/Kconfig
14@@ -167,6 +167,14 @@ config SPI_GPIO_OLD
15 
16       If unsure, say N.
17 
18+config SPI_CNS21XX
19+ tristate "Cavium Netowrks CNS21xx SPI master"
20+ depends on ARCH_CNS21XX && EXPERIMENTAL
21+ select SPI_BITBANG
22+ help
23+ This driver supports the buil-in SPI controller of the Cavium Networks
24+ CNS21xx SoCs.
25+
26 config SPI_IMX
27     tristate "Freescale i.MX SPI controllers"
28     depends on ARCH_MXC
29--- a/drivers/spi/Makefile
30+++ b/drivers/spi/Makefile
31@@ -50,6 +50,7 @@ obj-$(CONFIG_SPI_SH_SCI) += spi_sh_sci.
32 obj-$(CONFIG_SPI_SH_MSIOF) += spi_sh_msiof.o
33 obj-$(CONFIG_SPI_STMP3XXX) += spi_stmp.o
34 obj-$(CONFIG_SPI_NUC900) += spi_nuc900.o
35+obj-$(CONFIG_SPI_CNS21XX) += spi_cns21xx.o
36 
37 # special build for s3c24xx spi driver with fiq support
38 spi_s3c24xx_hw-y := spi_s3c24xx.o
39--- a/drivers/spi/spi_bitbang.c
40+++ b/drivers/spi/spi_bitbang.c
41@@ -337,6 +337,13 @@ static void bitbang_work(struct work_str
42                  */
43                 if (!m->is_dma_mapped)
44                     t->rx_dma = t->tx_dma = 0;
45+
46+ if (t->transfer_list.next == &m->transfers) {
47+ t->last_in_message_list = 1;
48+ } else {
49+ t->last_in_message_list = 0;
50+ }
51+
52                 status = bitbang->txrx_bufs(spi, t);
53             }
54             if (status > 0)
55--- /dev/null
56+++ b/drivers/spi/spi_cns21xx.c
57@@ -0,0 +1,520 @@
58+/*
59+ * Copyright (c) 2008 Cavium Networks
60+ * Copyright (c) 2010 Gabor Juhos <juhosg@openwrt.org>
61+ *
62+ * This file is free software; you can redistribute it and/or modify
63+ * it under the terms of the GNU General Public License, Version 2, as
64+ * published by the Free Software Foundation.
65+ */
66+
67+#include <linux/init.h>
68+#include <linux/spinlock.h>
69+#include <linux/workqueue.h>
70+#include <linux/interrupt.h>
71+#include <linux/delay.h>
72+#include <linux/errno.h>
73+#include <linux/platform_device.h>
74+#include <linux/io.h>
75+#include <linux/spi/spi.h>
76+#include <linux/spi/spi_bitbang.h>
77+
78+#include <mach/hardware.h>
79+#include <mach/cns21xx.h>
80+
81+#define DRIVER_NAME "cns21xx-spi"
82+
83+#ifdef CONFIG_CNS21XX_SPI_DEBUG
84+#define DBG(fmt, args...) pr_info("[CNS21XX_SPI_DEBUG]" fmt, ## args)
85+#else
86+#define DBG(fmt, args...) do {} while (0)
87+#endif /* CNS21XX_SPI_DEBUG */
88+
89+#define SPI_REG_CFG 0x40
90+#define SPI_REG_STAT 0x44
91+#define SPI_REG_BIT_RATE 0x48
92+#define SPI_REG_TX_CTRL 0x4c
93+#define SPI_REG_TX_DATA 0x50
94+#define SPI_REG_RX_CTRL 0x54
95+#define SPI_REG_RX_DATA 0x58
96+#define SPI_REG_FIFO_TX_CFG 0x5c
97+#define SPI_REG_FIFO_TX_CTRL 0x60
98+#define SPI_REG_FIFO_RX_CFG 0x64
99+#define SPI_REG_INTR_STAT 0x68
100+#define SPI_REG_INTR_ENA 0x6c
101+
102+#define CFG_SPI_EN BIT(31)
103+#define CFG_SPI_CLKPOL BIT(14)
104+#define CFG_SPI_CLKPHA BIT(13)
105+#define CFG_SPI_MASTER_EN BIT(11)
106+#define CFG_SPI_CHAR_LEN_M 0x3
107+#define CFG_SPI_CHAR_LEN_8BITS 0
108+#define CFG_SPI_CHAR_LEN_16BITS 1
109+#define CFG_SPI_CHAR_LEN_24BITS 2
110+#define CFG_SPI_CHAR_LEN_32BITS 3
111+
112+#define STAT_SPI_BUSY_STA BIT(1)
113+
114+#define BIT_RATE_DIV_1 0
115+#define BIT_RATE_DIV_2 1
116+#define BIT_RATE_DIV_4 2
117+#define BIT_RATE_DIV_8 3
118+#define BIT_RATE_DIV_16 4
119+#define BIT_RATE_DIV_32 5
120+#define BIT_RATE_DIV_64 6
121+#define BIT_RATE_DIV_128 7
122+
123+#define TX_CTRL_SPI_TXDAT_EOF BIT(2)
124+#define TX_CTRL_SPI_TXCH_NUM_M 0x3
125+#define TX_CTRL_CLEAR_MASK (TX_CTRL_SPI_TXDAT_EOF | \
126+ TX_CTRL_SPI_TXCH_NUM_M)
127+
128+#define RX_CTRL_SPI_RXDAT_EOF BIT(2)
129+#define RX_CTRL_SPI_RXCH_NUM_M 0x3
130+
131+#define INTR_STAT_SPI_TXBF_UNRN_FG BIT(7)
132+#define INTR_STAT_SPI_RXBF_OVRN_FG BIT(6)
133+#define INTR_STAT_SPI_TXFF_UNRN_FG BIT(5)
134+#define INTR_STAT_SPI_RXFF_OVRN_FG BIT(4)
135+#define INTR_STAT_SPI_TXBUF_FG BIT(3)
136+#define INTR_STAT_SPI_RXBUF_FG BIT(2)
137+#define INTR_STAT_SPI_TXFF_FG BIT(1)
138+#define INTR_STAT_SPI_RXFF_FG BIT(0)
139+
140+#define INTR_STAT_CLEAR_MASK (INTR_STAT_SPI_TXBF_UNRN_FG | \
141+ INTR_STAT_SPI_RXBF_OVRN_FG | \
142+ INTR_STAT_SPI_TXFF_UNRN_FG | \
143+ INTR_STAT_SPI_RXFF_OVRN_FG)
144+
145+#define FIFO_TX_CFG_SPI_TXFF_THRED_M 0x3
146+#define FIFO_TX_CFG_SPI_TXFF_THRED_S 4
147+#define FIFO_TX_CFG_SPI_TXFF_THRED_2 0
148+#define FIFO_TX_CFG_SPI_TXFF_THRED_4 1
149+#define FIFO_TX_CFG_SPI_TXFF_THRED_6 0
150+#define FIFO_TX_CFG_SPI_TXFF_STATUS_M 0xf
151+
152+#define FIFO_RX_CFG_SPI_RXFF_THRED_M 0x3
153+#define FIFO_RX_CFG_SPI_RXFF_THRED_S 4
154+#define FIFO_RX_CFG_SPI_RXFF_THRED_2 0
155+#define FIFO_RX_CFG_SPI_RXFF_THRED_4 1
156+#define FIFO_RX_CFG_SPI_RXFF_THRED_6 0
157+#define FIFO_RX_CFG_SPI_RXFF_STATUS_M 0xf
158+
159+#define CNS21XX_SPI_NUM_BIT_RATES 8
160+
161+struct cns21xx_spi {
162+ struct spi_bitbang bitbang;
163+
164+ struct spi_master *master;
165+ struct device *dev;
166+ void __iomem *base;
167+ struct resource *region;
168+
169+ unsigned freq_max;
170+ unsigned freq_min;
171+
172+};
173+
174+static inline struct cns21xx_spi *to_hw(struct spi_device *spi)
175+{
176+ return spi_master_get_devdata(spi->master);
177+}
178+
179+static inline u32 cns21xx_spi_rr(struct cns21xx_spi *hw, unsigned int reg)
180+{
181+ return __raw_readl(hw->base + reg);
182+}
183+
184+static inline void cns21xx_spi_wr(struct cns21xx_spi *hw, u32 val,
185+ unsigned int reg)
186+{
187+ __raw_writel(val, hw->base + reg);
188+}
189+
190+#define CNS21XX_SPI_RETRY_COUNT 100
191+static inline int cns21xx_spi_wait(struct cns21xx_spi *hw, unsigned int reg,
192+ u32 mask, u32 val)
193+{
194+ int retry_cnt = 0;
195+
196+ do {
197+ if ((cns21xx_spi_rr(hw, reg) & mask) == val)
198+ break;
199+
200+ if (++retry_cnt > CNS21XX_SPI_RETRY_COUNT) {
201+ dev_err(hw->dev, "timeout waiting on register %02x\n",
202+ reg);
203+ return -EIO;
204+ }
205+ } while (1);
206+
207+ return 0;
208+}
209+
210+static int cns21xx_spi_txrx_word(struct cns21xx_spi *hw, u8 tx_channel,
211+ u8 tx_eof_flag, u32 tx_data, u32 *rx_data)
212+{
213+ unsigned int tx_ctrl;
214+ u8 rx_channel;
215+ u8 rx_eof_flag;
216+ int err = 0;
217+
218+ err = cns21xx_spi_wait(hw, SPI_REG_STAT, STAT_SPI_BUSY_STA, 0);
219+ if (err)
220+ return err;
221+
222+ err = cns21xx_spi_wait(hw, SPI_REG_INTR_STAT, INTR_STAT_SPI_TXBUF_FG,
223+ INTR_STAT_SPI_TXBUF_FG);
224+ if (err)
225+ return err;
226+
227+ tx_ctrl = cns21xx_spi_rr(hw, SPI_REG_TX_CTRL);
228+ tx_ctrl &= ~(TX_CTRL_CLEAR_MASK);
229+ tx_ctrl |= (tx_channel & TX_CTRL_SPI_TXCH_NUM_M);
230+ tx_ctrl |= (tx_eof_flag) ? TX_CTRL_SPI_TXDAT_EOF : 0;
231+ cns21xx_spi_wr(hw, tx_ctrl, SPI_REG_TX_CTRL);
232+
233+ cns21xx_spi_wr(hw, tx_data, SPI_REG_TX_DATA);
234+
235+ err = cns21xx_spi_wait(hw, SPI_REG_INTR_STAT, INTR_STAT_SPI_RXBUF_FG,
236+ INTR_STAT_SPI_RXBUF_FG);
237+ if (err)
238+ return err;
239+
240+ rx_channel = cns21xx_spi_rr(hw, SPI_REG_RX_CTRL) &
241+ RX_CTRL_SPI_RXCH_NUM_M;
242+
243+ rx_eof_flag = (cns21xx_spi_rr(hw, SPI_REG_RX_CTRL) &
244+ RX_CTRL_SPI_RXDAT_EOF) ? 1 : 0;
245+
246+ *rx_data = cns21xx_spi_rr(hw, SPI_REG_RX_DATA);
247+
248+ if ((tx_channel != rx_channel) || (tx_eof_flag != rx_eof_flag))
249+ return -EPROTO;
250+
251+ return 0;
252+}
253+
254+static void cns21xx_spi_chipselect(struct spi_device *spi, int value)
255+{
256+ struct cns21xx_spi *hw = to_hw(spi);
257+ unsigned int spi_config;
258+ unsigned int tx_ctrl;
259+
260+ switch (value) {
261+ case BITBANG_CS_INACTIVE:
262+ break;
263+
264+ case BITBANG_CS_ACTIVE:
265+ spi_config = cns21xx_spi_rr(hw, SPI_REG_CFG);
266+
267+ if (spi->mode & SPI_CPHA)
268+ spi_config |= CFG_SPI_CLKPHA;
269+ else
270+ spi_config &= ~CFG_SPI_CLKPHA;
271+
272+ if (spi->mode & SPI_CPOL)
273+ spi_config |= CFG_SPI_CLKPOL;
274+ else
275+ spi_config &= ~CFG_SPI_CLKPOL;
276+
277+ cns21xx_spi_wr(hw, spi_config, SPI_REG_CFG);
278+
279+ tx_ctrl = cns21xx_spi_rr(hw, SPI_REG_TX_CTRL);
280+ tx_ctrl &= ~(TX_CTRL_CLEAR_MASK);
281+ tx_ctrl |= (spi->chip_select & TX_CTRL_SPI_TXCH_NUM_M);
282+ cns21xx_spi_wr(hw, tx_ctrl, SPI_REG_TX_CTRL);
283+
284+ break;
285+ }
286+}
287+
288+static int cns21xx_spi_setup(struct spi_device *spi)
289+{
290+ struct cns21xx_spi *hw = to_hw(spi);
291+
292+ if (spi->bits_per_word != 8) {
293+ dev_err(&spi->dev, "%s: invalid bits_per_word=%u\n",
294+ __func__, spi->bits_per_word);
295+ return -EINVAL;
296+ }
297+
298+ if (spi->max_speed_hz == 0)
299+ spi->max_speed_hz = hw->freq_max;
300+
301+ if (spi->max_speed_hz > hw->freq_max ||
302+ spi->max_speed_hz < hw->freq_min) {
303+ dev_err(&spi->dev, "%s: max_speed_hz=%u out of range\n",
304+ __func__, spi->max_speed_hz);
305+ return -EINVAL;
306+ }
307+
308+ return 0;
309+}
310+
311+static int cns21xx_spi_setup_transfer(struct spi_device *spi,
312+ struct spi_transfer *t)
313+{
314+ struct cns21xx_spi *hw = to_hw(spi);
315+ u8 bits_per_word;
316+ u32 hz;
317+ int i;
318+
319+ bits_per_word = (t) ? t->bits_per_word : spi->bits_per_word;
320+ hz = t ? t->speed_hz : spi->max_speed_hz;
321+
322+ if (!bits_per_word)
323+ bits_per_word = spi->bits_per_word;
324+
325+ if (!hz)
326+ hz = spi->max_speed_hz;
327+
328+ if (bits_per_word != 8) {
329+ dev_err(&spi->dev, "%s: invalid bits_per_word=%u\n",
330+ __func__, bits_per_word);
331+ return -EINVAL;
332+ }
333+
334+ if (hz > spi->max_speed_hz || hz > hw->freq_max || hz < hw->freq_min) {
335+ dev_err(&spi->dev, "%s: max_speed_hz=%u out of range\n",
336+ __func__, hz);
337+ return -EINVAL;
338+ }
339+
340+ for (i = 0; i < CNS21XX_SPI_NUM_BIT_RATES; i++)
341+ if (spi->max_speed_hz > (cns21xx_get_apb_freq() >> i))
342+ break;
343+
344+ DBG("max_speed:%uHz, curr_speed:%luHz, rate_index=%d\n",
345+ spi->max_speed_hz, cns21xx_get_apb_freq() / (1 << i), i);
346+
347+ cns21xx_spi_wr(hw, i, SPI_REG_BIT_RATE);
348+
349+ return 0;
350+}
351+
352+static int cns21xx_spi_txrx(struct spi_device *spi, struct spi_transfer *t)
353+{
354+ struct cns21xx_spi *hw = to_hw(spi);
355+ const unsigned char *tx_buf;
356+ unsigned char *rx_buf;
357+ u32 rx_data;
358+ int tx_eof;
359+ int err = 0;
360+ int i;
361+
362+ tx_buf = t->tx_buf;
363+ rx_buf = t->rx_buf;
364+ tx_eof = t->last_in_message_list;
365+
366+ DBG("txrx: tx %p, rx %p, len %d\n", tx_buf, rx_buf, t->len);
367+
368+ if (tx_buf) {
369+ for (i = 0; i < t->len; i++)
370+ DBG("tx_buf[%02d]: 0x%02x\n", i, tx_buf[i]);
371+
372+ for (i = 0; i < (t->len - 1); i++) {
373+ err = cns21xx_spi_txrx_word(hw, spi->chip_select, 0,
374+ tx_buf[i], &rx_data);
375+ if (err)
376+ goto done;
377+
378+ if (rx_buf) {
379+ rx_buf[i] = rx_data;
380+ DBG("rx_buf[%02d]:0x%02x\n", i, rx_buf[i]);
381+ }
382+ }
383+
384+ err = cns21xx_spi_txrx_word(hw, spi->chip_select, tx_eof,
385+ tx_buf[i], &rx_data);
386+ if (err)
387+ goto done;
388+
389+ if ((tx_eof) && rx_buf) {
390+ rx_buf[i] = rx_data;
391+ DBG("rx_buf[%02d]:0x%02x\n", i, rx_buf[i]);
392+ }
393+ } else if (rx_buf) {
394+ for (i = 0; i < (t->len - 1); i++) {
395+ err = cns21xx_spi_txrx_word(hw, spi->chip_select, 0,
396+ 0xff, &rx_data);
397+ if (err)
398+ goto done;
399+
400+ rx_buf[i] = rx_data;
401+ DBG("rx_buf[%02d]:0x%02x\n", i, rx_buf[i]);
402+ }
403+
404+ err = cns21xx_spi_txrx_word(hw, spi->chip_select, tx_eof,
405+ 0xff, &rx_data);
406+ if (err)
407+ goto done;
408+
409+ rx_buf[i] = rx_data;
410+ DBG("rx_buf[%02d]:0x%02x\n", i, rx_buf[i]);
411+ }
412+
413+ done:
414+ return (err) ? err : t->len;
415+}
416+
417+static void __init cns21xx_spi_hw_init(struct cns21xx_spi *hw)
418+{
419+ u32 t;
420+ u32 pclk;
421+
422+ /* Setup configuration register */
423+ cns21xx_spi_wr(hw, CFG_SPI_MASTER_EN, SPI_REG_CFG);
424+
425+ /* Set default clock to PCLK/2 */
426+ cns21xx_spi_wr(hw, BIT_RATE_DIV_2, SPI_REG_BIT_RATE);
427+
428+ /* Configure SPI's Tx channel */
429+ cns21xx_spi_wr(hw, 0, SPI_REG_TX_CTRL);
430+
431+ /* Configure Tx FIFO Threshold */
432+ t = cns21xx_spi_rr(hw, SPI_REG_FIFO_TX_CFG);
433+ t &= ~(FIFO_TX_CFG_SPI_TXFF_THRED_M << FIFO_TX_CFG_SPI_TXFF_THRED_S);
434+ t |= (FIFO_TX_CFG_SPI_TXFF_THRED_2 << FIFO_TX_CFG_SPI_TXFF_THRED_S);
435+ cns21xx_spi_wr(hw, t, SPI_REG_FIFO_TX_CFG);
436+
437+ /* Configure Rx FIFO Threshold */
438+ t = cns21xx_spi_rr(hw, SPI_REG_FIFO_RX_CFG);
439+ t &= ~(FIFO_RX_CFG_SPI_RXFF_THRED_M << FIFO_RX_CFG_SPI_RXFF_THRED_S);
440+ t |= (FIFO_RX_CFG_SPI_RXFF_THRED_2 << FIFO_RX_CFG_SPI_RXFF_THRED_S);
441+ cns21xx_spi_wr(hw, t, SPI_REG_FIFO_RX_CFG);
442+
443+ /* Disable interrupts, and clear interrupt status */
444+ cns21xx_spi_wr(hw, 0, SPI_REG_INTR_ENA);
445+ cns21xx_spi_wr(hw, INTR_STAT_CLEAR_MASK, SPI_REG_INTR_STAT);
446+
447+ (void) cns21xx_spi_rr(hw, SPI_REG_RX_DATA);
448+
449+ /* Enable SPI */
450+ t = cns21xx_spi_rr(hw, SPI_REG_CFG);
451+ t |= CFG_SPI_EN;
452+ cns21xx_spi_wr(hw, t, SPI_REG_CFG);
453+
454+ pclk = cns21xx_get_apb_freq();
455+ hw->freq_max = pclk;
456+ hw->freq_min = pclk / (1 << BIT_RATE_DIV_128);
457+}
458+
459+static int __init cns21xx_spi_probe(struct platform_device *pdev)
460+{
461+ struct cns21xx_spi *hw;
462+ struct spi_master *master;
463+ struct resource *res;
464+ int err = 0;
465+
466+ master = spi_alloc_master(&pdev->dev, sizeof(struct cns21xx_spi));
467+ if (!master) {
468+ dev_err(&pdev->dev, "No memory for spi_master\n");
469+ return -ENOMEM;
470+ }
471+
472+ hw = spi_master_get_devdata(master);
473+
474+ platform_set_drvdata(pdev, hw);
475+ hw->master = spi_master_get(master);
476+ hw->dev = &pdev->dev;
477+
478+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
479+ if (!res) {
480+ dev_dbg(&pdev->dev, "no MEM resource found\n");
481+ err = -ENOENT;
482+ goto err_put_master;
483+ }
484+
485+ hw->region = request_mem_region(res->start, resource_size(res),
486+ dev_name(&pdev->dev));
487+ if (!hw->region) {
488+ dev_err(&pdev->dev, "unable to reserve iomem region\n");
489+ err = -ENXIO;
490+ goto err_put_master;
491+ }
492+
493+ hw->base = ioremap(res->start, resource_size(res));
494+ if (!hw->base) {
495+ dev_err(&pdev->dev, "ioremap failed\n");
496+ err = -ENOENT;
497+ goto err_release_region;
498+ }
499+
500+ cns21xx_spi_hw_init(hw);
501+
502+ master->bus_num = pdev->id;
503+ if (master->bus_num == -1)
504+ master->bus_num = 0;
505+
506+ master->num_chipselect = 4;
507+ master->setup = cns21xx_spi_setup;
508+
509+ hw->bitbang.master = hw->master;
510+ hw->bitbang.chipselect = cns21xx_spi_chipselect;
511+ hw->bitbang.txrx_bufs = cns21xx_spi_txrx;
512+ hw->bitbang.setup_transfer = cns21xx_spi_setup_transfer;
513+
514+ err = spi_bitbang_start(&hw->bitbang);
515+ if (err) {
516+ dev_err(hw->dev, "unable to register SPI master\n");
517+ goto err_unmap;
518+ }
519+
520+ dev_info(hw->dev, "iomem at %08x\n", res->start);
521+
522+ return 0;
523+
524+ err_unmap:
525+ iounmap(hw->base);
526+
527+ err_release_region:
528+ release_resource(hw->region);
529+ kfree(hw->region);
530+
531+ err_put_master:
532+ spi_master_put(hw->bitbang.master);
533+ platform_set_drvdata(pdev, NULL);
534+
535+ return err;
536+}
537+
538+static int __devexit cns21xx_spi_remove(struct platform_device *pdev)
539+{
540+ struct cns21xx_spi *hw = platform_get_drvdata(pdev);
541+
542+ spi_bitbang_stop(&hw->bitbang);
543+ iounmap(hw->base);
544+ release_resource(hw->region);
545+ kfree(hw->region);
546+ spi_master_put(hw->bitbang.master);
547+ platform_set_drvdata(pdev, NULL);
548+
549+ return 0;
550+}
551+
552+static struct platform_driver cns21xx_spi_driver = {
553+ .remove = __devexit_p(cns21xx_spi_remove),
554+ .driver = {
555+ .name = DRIVER_NAME,
556+ .owner = THIS_MODULE,
557+ },
558+};
559+
560+static int __init cns21xx_spi_init(void)
561+{
562+ return platform_driver_probe(&cns21xx_spi_driver, cns21xx_spi_probe);
563+}
564+
565+static void __exit cns21xx_spi_exit(void)
566+{
567+ platform_driver_unregister(&cns21xx_spi_driver);
568+}
569+
570+module_init(cns21xx_spi_init);
571+module_exit(cns21xx_spi_exit);
572+
573+MODULE_DESCRIPTION("Cavium Networks CNS21xx SPI Controller driver");
574+MODULE_AUTHOR("STAR Semi Corp.");
575+MODULE_AUTHOR("Gabor Juhos <juhosg@openwrt.org>");
576+MODULE_LICENSE("GPL v2");
577+MODULE_ALIAS("platform:" DRIVER_NAME);
578

Archive Download this file



interactive