aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/video
diff options
context:
space:
mode:
authorZhou Zhu <zzhu3@marvell.com>2013-02-21 19:42:18 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2013-02-21 20:22:17 -0500
commit641b4b1b6a7cb4ab21cfd9dd7b93a1162eae4501 (patch)
treea429ff233c1ce30034cf825e6b3b945c0368eee8 /drivers/video
parent3c76f15fd5027474bf738e0a145337370d9c7a8c (diff)
video: mmpdisp: add spi port in display controller
Add spi port support in mmp display controller. This port is from display controller and for panel usage. This driver implemented and registered as a spi master. Signed-off-by: Zhou Zhu <zzhu3@marvell.com> Acked-by: Haojian Zhuang <haojian.zhuang@gmail.com> Cc: Lisa Du <cldu@marvell.com> Cc: Guoqing Li <ligq@marvell.com> Cc: Florian Tobias Schandinat <FlorianSchandinat@gmx.de> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'drivers/video')
-rw-r--r--drivers/video/mmp/hw/Kconfig8
-rw-r--r--drivers/video/mmp/hw/Makefile1
-rw-r--r--drivers/video/mmp/hw/mmp_ctrl.c6
-rw-r--r--drivers/video/mmp/hw/mmp_ctrl.h4
-rw-r--r--drivers/video/mmp/hw/mmp_spi.c180
5 files changed, 199 insertions, 0 deletions
diff --git a/drivers/video/mmp/hw/Kconfig b/drivers/video/mmp/hw/Kconfig
index 6c1dd34e8cf9..02f109a20cd0 100644
--- a/drivers/video/mmp/hw/Kconfig
+++ b/drivers/video/mmp/hw/Kconfig
@@ -9,4 +9,12 @@ config MMP_DISP_CONTROLLER
9 this controller is used on Marvell PXA910, 9 this controller is used on Marvell PXA910,
10 MMP2, MMP3, PXA988 chips 10 MMP2, MMP3, PXA988 chips
11 11
12config MMP_DISP_SPI
13 bool "mmp display controller spi port"
14 depends on MMP_DISP_CONTROLLER && SPI_MASTER
15 default y
16 help
17 Marvell MMP display hw controller spi port support
18 will register as a spi master for panel usage
19
12endif 20endif
diff --git a/drivers/video/mmp/hw/Makefile b/drivers/video/mmp/hw/Makefile
index f34ace82888e..0000a714fedf 100644
--- a/drivers/video/mmp/hw/Makefile
+++ b/drivers/video/mmp/hw/Makefile
@@ -1 +1,2 @@
1obj-$(CONFIG_MMP_DISP_CONTROLLER) += mmp_ctrl.o 1obj-$(CONFIG_MMP_DISP_CONTROLLER) += mmp_ctrl.o
2obj-$(CONFIG_MMP_DISP_SPI) += mmp_spi.o
diff --git a/drivers/video/mmp/hw/mmp_ctrl.c b/drivers/video/mmp/hw/mmp_ctrl.c
index 1b5d29992313..4bd31b2af398 100644
--- a/drivers/video/mmp/hw/mmp_ctrl.c
+++ b/drivers/video/mmp/hw/mmp_ctrl.c
@@ -535,6 +535,12 @@ static int mmphw_probe(struct platform_device *pdev)
535 } 535 }
536 } 536 }
537 537
538#ifdef CONFIG_MMP_DISP_SPI
539 ret = lcd_spi_register(ctrl);
540 if (ret < 0)
541 goto failed_path_init;
542#endif
543
538 dev_info(ctrl->dev, "device init done\n"); 544 dev_info(ctrl->dev, "device init done\n");
539 545
540 return 0; 546 return 0;
diff --git a/drivers/video/mmp/hw/mmp_ctrl.h b/drivers/video/mmp/hw/mmp_ctrl.h
index b125f53336fa..6408d8ef3abb 100644
--- a/drivers/video/mmp/hw/mmp_ctrl.h
+++ b/drivers/video/mmp/hw/mmp_ctrl.h
@@ -1967,4 +1967,8 @@ static inline struct lcd_regs *path_regs(struct mmp_path *path)
1967 return NULL; 1967 return NULL;
1968 } 1968 }
1969} 1969}
1970
1971#ifdef CONFIG_MMP_DISP_SPI
1972extern int lcd_spi_register(struct mmphw_ctrl *ctrl);
1973#endif
1970#endif /* _MMP_CTRL_H_ */ 1974#endif /* _MMP_CTRL_H_ */
diff --git a/drivers/video/mmp/hw/mmp_spi.c b/drivers/video/mmp/hw/mmp_spi.c
new file mode 100644
index 000000000000..e62ca7bf0d5e
--- /dev/null
+++ b/drivers/video/mmp/hw/mmp_spi.c
@@ -0,0 +1,180 @@
1/*
2 * linux/drivers/video/mmp/hw/mmp_spi.c
3 * using the spi in LCD controler for commands send
4 *
5 * Copyright (C) 2012 Marvell Technology Group Ltd.
6 * Authors: Guoqing Li <ligq@marvell.com>
7 * Lisa Du <cldu@marvell.com>
8 * Zhou Zhu <zzhu3@marvell.com>
9 *
10 * This program is free software; you can redistribute it and/or modify it
11 * under the terms of the GNU General Public License as published by the
12 * Free Software Foundation; either version 2 of the License, or (at your
13 * option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful, but WITHOUT
16 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
17 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
18 * more details.
19 *
20 * You should have received a copy of the GNU General Public License along with
21 * this program. If not, see <http://www.gnu.org/licenses/>.
22 *
23 */
24#include <linux/errno.h>
25#include <linux/delay.h>
26#include <linux/err.h>
27#include <linux/io.h>
28#include <linux/spi/spi.h>
29#include "mmp_ctrl.h"
30
31/**
32 * spi_write - write command to the SPI port
33 * @data: can be 8/16/32-bit, MSB justified data to write.
34 * @len: data length.
35 *
36 * Wait bus transfer complete IRQ.
37 * The caller is expected to perform the necessary locking.
38 *
39 * Returns:
40 * %-ETIMEDOUT timeout occurred
41 * 0 success
42 */
43static inline int lcd_spi_write(struct spi_device *spi, u32 data)
44{
45 int timeout = 100000, isr, ret = 0;
46 u32 tmp;
47 void *reg_base =
48 *(void **)spi_master_get_devdata(spi->master);
49
50 /* clear ISR */
51 writel_relaxed(~SPI_IRQ_MASK, reg_base + SPU_IRQ_ISR);
52
53 switch (spi->bits_per_word) {
54 case 8:
55 writel_relaxed((u8)data, reg_base + LCD_SPU_SPI_TXDATA);
56 break;
57 case 16:
58 writel_relaxed((u16)data, reg_base + LCD_SPU_SPI_TXDATA);
59 break;
60 case 32:
61 writel_relaxed((u32)data, reg_base + LCD_SPU_SPI_TXDATA);
62 break;
63 default:
64 dev_err(&spi->dev, "Wrong spi bit length\n");
65 }
66
67 /* SPI start to send command */
68 tmp = readl_relaxed(reg_base + LCD_SPU_SPI_CTRL);
69 tmp &= ~CFG_SPI_START_MASK;
70 tmp |= CFG_SPI_START(1);
71 writel(tmp, reg_base + LCD_SPU_SPI_CTRL);
72
73 isr = readl_relaxed(reg_base + SPU_IRQ_ISR);
74 while (!(isr & SPI_IRQ_ENA_MASK)) {
75 udelay(100);
76 isr = readl_relaxed(reg_base + SPU_IRQ_ISR);
77 if (!--timeout) {
78 ret = -ETIMEDOUT;
79 dev_err(&spi->dev, "spi cmd send time out\n");
80 break;
81 }
82 }
83
84 tmp = readl_relaxed(reg_base + LCD_SPU_SPI_CTRL);
85 tmp &= ~CFG_SPI_START_MASK;
86 tmp |= CFG_SPI_START(0);
87 writel_relaxed(tmp, reg_base + LCD_SPU_SPI_CTRL);
88
89 writel_relaxed(~SPI_IRQ_MASK, reg_base + SPU_IRQ_ISR);
90
91 return ret;
92}
93
94static int lcd_spi_setup(struct spi_device *spi)
95{
96 void *reg_base =
97 *(void **)spi_master_get_devdata(spi->master);
98 u32 tmp;
99
100 tmp = CFG_SCLKCNT(16) |
101 CFG_TXBITS(spi->bits_per_word) |
102 CFG_SPI_SEL(1) | CFG_SPI_ENA(1) |
103 CFG_SPI_3W4WB(1);
104 writel(tmp, reg_base + LCD_SPU_SPI_CTRL);
105
106 /*
107 * After set mode it need a time to pull up the spi singals,
108 * or it would cause the wrong waveform when send spi command,
109 * especially on pxa910h
110 */
111 tmp = readl_relaxed(reg_base + SPU_IOPAD_CONTROL);
112 if ((tmp & CFG_IOPADMODE_MASK) != IOPAD_DUMB18SPI)
113 writel_relaxed(IOPAD_DUMB18SPI |
114 (tmp & ~CFG_IOPADMODE_MASK),
115 reg_base + SPU_IOPAD_CONTROL);
116 udelay(20);
117 return 0;
118}
119
120static int lcd_spi_one_transfer(struct spi_device *spi, struct spi_message *m)
121{
122 struct spi_transfer *t;
123 int i;
124
125 list_for_each_entry(t, &m->transfers, transfer_list) {
126 switch (spi->bits_per_word) {
127 case 8:
128 for (i = 0; i < t->len; i++)
129 lcd_spi_write(spi, ((u8 *)t->tx_buf)[i]);
130 break;
131 case 16:
132 for (i = 0; i < t->len/2; i++)
133 lcd_spi_write(spi, ((u16 *)t->tx_buf)[i]);
134 break;
135 case 32:
136 for (i = 0; i < t->len/4; i++)
137 lcd_spi_write(spi, ((u32 *)t->tx_buf)[i]);
138 break;
139 default:
140 dev_err(&spi->dev, "Wrong spi bit length\n");
141 }
142 }
143
144 m->status = 0;
145 if (m->complete)
146 m->complete(m->context);
147 return 0;
148}
149
150int lcd_spi_register(struct mmphw_ctrl *ctrl)
151{
152 struct spi_master *master;
153 void **p_regbase;
154 int err;
155
156 master = spi_alloc_master(ctrl->dev, sizeof(void *));
157 if (!master) {
158 dev_err(ctrl->dev, "unable to allocate SPI master\n");
159 return -ENOMEM;
160 }
161 p_regbase = spi_master_get_devdata(master);
162 *p_regbase = ctrl->reg_base;
163
164 /* set bus num to 5 to avoid conflict with other spi hosts */
165 master->bus_num = 5;
166 master->num_chipselect = 1;
167 master->setup = lcd_spi_setup;
168 master->transfer = lcd_spi_one_transfer;
169
170 err = spi_register_master(master);
171 if (err < 0) {
172 dev_err(ctrl->dev, "unable to register SPI master\n");
173 spi_master_put(master);
174 return err;
175 }
176
177 dev_info(&master->dev, "registered\n");
178
179 return 0;
180}