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

backlight: spi driver for LMS283GF05 LCD

ADd support for the SPI part of LMS283GF05 LCD. The LCD uses SPI for
initialization and powerdown sequences. No further defails are specified
in the datasheet about the initialization/powerdown sequence, just the
magic numbers that have to be sent over SPI bus. This LCD can be found in
the Aeronix Zipit Z2 handheld.

Signed-off-by: Marek Vasut <marek.vasut@gmail.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Richard Purdie <rpurdie@linux.intel.com>

authored by

Marek Vasut and committed by
Richard Purdie
5036cc41 156ff0d4

+278
+7
drivers/video/backlight/Kconfig
··· 31 31 Say y here to support the LCD panels usually found on SHARP 32 32 corgi (C7x0) and spitz (Cxx00) models. 33 33 34 + config LCD_LMS283GF05 35 + tristate "Samsung LMS283GF05 LCD" 36 + depends on LCD_CLASS_DEVICE && SPI_MASTER && GENERIC_GPIO 37 + help 38 + SPI driver for Samsung LMS283GF05. This provides basic support 39 + for powering the LCD up/down through a sysfs interface. 40 + 34 41 config LCD_LTV350QV 35 42 tristate "Samsung LTV350QV LCD Panel" 36 43 depends on LCD_CLASS_DEVICE && SPI_MASTER
+1
drivers/video/backlight/Makefile
··· 3 3 obj-$(CONFIG_LCD_CLASS_DEVICE) += lcd.o 4 4 obj-$(CONFIG_LCD_CORGI) += corgi_lcd.o 5 5 obj-$(CONFIG_LCD_HP700) += jornada720_lcd.o 6 + obj-$(CONFIG_LCD_LMS283GF05) += lms283gf05.o 6 7 obj-$(CONFIG_LCD_LTV350QV) += ltv350qv.o 7 8 obj-$(CONFIG_LCD_ILI9320) += ili9320.o 8 9 obj-$(CONFIG_LCD_PLATFORM) += platform_lcd.o
+242
drivers/video/backlight/lms283gf05.c
··· 1 + /* 2 + * lms283gf05.c -- support for Samsung LMS283GF05 LCD 3 + * 4 + * Copyright (c) 2009 Marek Vasut <marek.vasut@gmail.com> 5 + * 6 + * This program is free software; you can redistribute it and/or modify 7 + * it under the terms of the GNU General Public License version 2 as 8 + * published by the Free Software Foundation. 9 + */ 10 + 11 + #include <linux/device.h> 12 + #include <linux/kernel.h> 13 + #include <linux/delay.h> 14 + #include <linux/gpio.h> 15 + #include <linux/lcd.h> 16 + 17 + #include <linux/spi/spi.h> 18 + #include <linux/spi/lms283gf05.h> 19 + 20 + struct lms283gf05_state { 21 + struct spi_device *spi; 22 + struct lcd_device *ld; 23 + }; 24 + 25 + struct lms283gf05_seq { 26 + unsigned char reg; 27 + unsigned short value; 28 + unsigned char delay; 29 + }; 30 + 31 + /* Magic sequences supplied by manufacturer, for details refer to datasheet */ 32 + static struct lms283gf05_seq disp_initseq[] = { 33 + /* REG, VALUE, DELAY */ 34 + { 0x07, 0x0000, 0 }, 35 + { 0x13, 0x0000, 10 }, 36 + 37 + { 0x11, 0x3004, 0 }, 38 + { 0x14, 0x200F, 0 }, 39 + { 0x10, 0x1a20, 0 }, 40 + { 0x13, 0x0040, 50 }, 41 + 42 + { 0x13, 0x0060, 0 }, 43 + { 0x13, 0x0070, 200 }, 44 + 45 + { 0x01, 0x0127, 0 }, 46 + { 0x02, 0x0700, 0 }, 47 + { 0x03, 0x1030, 0 }, 48 + { 0x08, 0x0208, 0 }, 49 + { 0x0B, 0x0620, 0 }, 50 + { 0x0C, 0x0110, 0 }, 51 + { 0x30, 0x0120, 0 }, 52 + { 0x31, 0x0127, 0 }, 53 + { 0x32, 0x0000, 0 }, 54 + { 0x33, 0x0503, 0 }, 55 + { 0x34, 0x0727, 0 }, 56 + { 0x35, 0x0124, 0 }, 57 + { 0x36, 0x0706, 0 }, 58 + { 0x37, 0x0701, 0 }, 59 + { 0x38, 0x0F00, 0 }, 60 + { 0x39, 0x0F00, 0 }, 61 + { 0x40, 0x0000, 0 }, 62 + { 0x41, 0x0000, 0 }, 63 + { 0x42, 0x013f, 0 }, 64 + { 0x43, 0x0000, 0 }, 65 + { 0x44, 0x013f, 0 }, 66 + { 0x45, 0x0000, 0 }, 67 + { 0x46, 0xef00, 0 }, 68 + { 0x47, 0x013f, 0 }, 69 + { 0x48, 0x0000, 0 }, 70 + { 0x07, 0x0015, 30 }, 71 + 72 + { 0x07, 0x0017, 0 }, 73 + 74 + { 0x20, 0x0000, 0 }, 75 + { 0x21, 0x0000, 0 }, 76 + { 0x22, 0x0000, 0 } 77 + }; 78 + 79 + static struct lms283gf05_seq disp_pdwnseq[] = { 80 + { 0x07, 0x0016, 30 }, 81 + 82 + { 0x07, 0x0004, 0 }, 83 + { 0x10, 0x0220, 20 }, 84 + 85 + { 0x13, 0x0060, 50 }, 86 + 87 + { 0x13, 0x0040, 50 }, 88 + 89 + { 0x13, 0x0000, 0 }, 90 + { 0x10, 0x0000, 0 } 91 + }; 92 + 93 + 94 + static void lms283gf05_reset(unsigned long gpio, bool inverted) 95 + { 96 + gpio_set_value(gpio, !inverted); 97 + mdelay(100); 98 + gpio_set_value(gpio, inverted); 99 + mdelay(20); 100 + gpio_set_value(gpio, !inverted); 101 + mdelay(20); 102 + } 103 + 104 + static void lms283gf05_toggle(struct spi_device *spi, 105 + struct lms283gf05_seq *seq, int sz) 106 + { 107 + char buf[3]; 108 + int i; 109 + 110 + for (i = 0; i < sz; i++) { 111 + buf[0] = 0x74; 112 + buf[1] = 0x00; 113 + buf[2] = seq[i].reg; 114 + spi_write(spi, buf, 3); 115 + 116 + buf[0] = 0x76; 117 + buf[1] = seq[i].value >> 8; 118 + buf[2] = seq[i].value & 0xff; 119 + spi_write(spi, buf, 3); 120 + 121 + mdelay(seq[i].delay); 122 + } 123 + } 124 + 125 + static int lms283gf05_power_set(struct lcd_device *ld, int power) 126 + { 127 + struct lms283gf05_state *st = lcd_get_data(ld); 128 + struct spi_device *spi = st->spi; 129 + struct lms283gf05_pdata *pdata = spi->dev.platform_data; 130 + 131 + if (power) { 132 + if (pdata) 133 + lms283gf05_reset(pdata->reset_gpio, 134 + pdata->reset_inverted); 135 + lms283gf05_toggle(spi, disp_initseq, ARRAY_SIZE(disp_initseq)); 136 + } else { 137 + lms283gf05_toggle(spi, disp_pdwnseq, ARRAY_SIZE(disp_pdwnseq)); 138 + if (pdata) 139 + gpio_set_value(pdata->reset_gpio, 140 + pdata->reset_inverted); 141 + } 142 + 143 + return 0; 144 + } 145 + 146 + static struct lcd_ops lms_ops = { 147 + .set_power = lms283gf05_power_set, 148 + .get_power = NULL, 149 + }; 150 + 151 + static int __devinit lms283gf05_probe(struct spi_device *spi) 152 + { 153 + struct lms283gf05_state *st; 154 + struct lms283gf05_pdata *pdata = spi->dev.platform_data; 155 + struct lcd_device *ld; 156 + int ret = 0; 157 + 158 + if (pdata != NULL) { 159 + ret = gpio_request(pdata->reset_gpio, "LMS285GF05 RESET"); 160 + if (ret) 161 + return ret; 162 + 163 + ret = gpio_direction_output(pdata->reset_gpio, 164 + !pdata->reset_inverted); 165 + if (ret) 166 + goto err; 167 + } 168 + 169 + st = kzalloc(sizeof(struct lms283gf05_state), GFP_KERNEL); 170 + if (st == NULL) { 171 + dev_err(&spi->dev, "No memory for device state\n"); 172 + ret = -ENOMEM; 173 + goto err; 174 + } 175 + 176 + ld = lcd_device_register("lms283gf05", &spi->dev, st, &lms_ops); 177 + if (IS_ERR(ld)) { 178 + ret = PTR_ERR(ld); 179 + goto err2; 180 + } 181 + 182 + st->spi = spi; 183 + st->ld = ld; 184 + 185 + dev_set_drvdata(&spi->dev, st); 186 + 187 + /* kick in the LCD */ 188 + if (pdata) 189 + lms283gf05_reset(pdata->reset_gpio, pdata->reset_inverted); 190 + lms283gf05_toggle(spi, disp_initseq, ARRAY_SIZE(disp_initseq)); 191 + 192 + return 0; 193 + 194 + err2: 195 + kfree(st); 196 + err: 197 + if (pdata != NULL) 198 + gpio_free(pdata->reset_gpio); 199 + 200 + return ret; 201 + } 202 + 203 + static int __devexit lms283gf05_remove(struct spi_device *spi) 204 + { 205 + struct lms283gf05_state *st = dev_get_drvdata(&spi->dev); 206 + struct lms283gf05_pdata *pdata = st->spi->dev.platform_data; 207 + 208 + lcd_device_unregister(st->ld); 209 + 210 + if (pdata != NULL) 211 + gpio_free(pdata->reset_gpio); 212 + 213 + kfree(st); 214 + 215 + return 0; 216 + } 217 + 218 + static struct spi_driver lms283gf05_driver = { 219 + .driver = { 220 + .name = "lms283gf05", 221 + .owner = THIS_MODULE, 222 + }, 223 + .probe = lms283gf05_probe, 224 + .remove = __devexit_p(lms283gf05_remove), 225 + }; 226 + 227 + static __init int lms283gf05_init(void) 228 + { 229 + return spi_register_driver(&lms283gf05_driver); 230 + } 231 + 232 + static __exit void lms283gf05_exit(void) 233 + { 234 + spi_unregister_driver(&lms283gf05_driver); 235 + } 236 + 237 + module_init(lms283gf05_init); 238 + module_exit(lms283gf05_exit); 239 + 240 + MODULE_AUTHOR("Marek Vasut <marek.vasut@gmail.com>"); 241 + MODULE_DESCRIPTION("LCD283GF05 LCD"); 242 + MODULE_LICENSE("GPL v2");
+28
include/linux/spi/lms283gf05.h
··· 1 + /* 2 + * lms283gf05.h - Platform glue for Samsung LMS283GF05 LCD 3 + * 4 + * Copyright (C) 2009 Marek Vasut <marek.vasut@gmail.com> 5 + * 6 + * This program is free software; you can redistribute it and/or modify 7 + * it under the terms of the GNU General Public License version 2 as 8 + * published by the Free Software Foundation. 9 + * 10 + * This program is distributed in the hope that it will be useful, 11 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 + * GNU General Public License for more details. 14 + * 15 + * You should have received a copy of the GNU General Public License 16 + * along with this program; if not, write to the Free Software 17 + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 18 + */ 19 + 20 + #ifndef _INCLUDE_LINUX_SPI_LMS283GF05_H_ 21 + #define _INCLUDE_LINUX_SPI_LMS283GF05_H_ 22 + 23 + struct lms283gf05_pdata { 24 + unsigned long reset_gpio; 25 + bool reset_inverted; 26 + }; 27 + 28 + #endif /* _INCLUDE_LINUX_SPI_LMS283GF05_H_ */