Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Zhou Zhu and committed by
Linus Torvalds
641b4b1b 3c76f15f

+199
+8
drivers/video/mmp/hw/Kconfig
··· 9 9 this controller is used on Marvell PXA910, 10 10 MMP2, MMP3, PXA988 chips 11 11 12 + config 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 + 12 20 endif
+1
drivers/video/mmp/hw/Makefile
··· 1 1 obj-$(CONFIG_MMP_DISP_CONTROLLER) += mmp_ctrl.o 2 + obj-$(CONFIG_MMP_DISP_SPI) += mmp_spi.o
+6
drivers/video/mmp/hw/mmp_ctrl.c
··· 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 544 dev_info(ctrl->dev, "device init done\n"); 539 545 540 546 return 0;
+4
drivers/video/mmp/hw/mmp_ctrl.h
··· 1967 1967 return NULL; 1968 1968 } 1969 1969 } 1970 + 1971 + #ifdef CONFIG_MMP_DISP_SPI 1972 + extern int lcd_spi_register(struct mmphw_ctrl *ctrl); 1973 + #endif 1970 1974 #endif /* _MMP_CTRL_H_ */
+180
drivers/video/mmp/hw/mmp_spi.c
··· 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 + */ 43 + static 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 + 94 + static 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 + 120 + static 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 + 150 + int 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 + }