kernel: update 3.18 to 3.18.14
[openwrt/svn-archive/archive.git] / target / linux / xburst / patches-3.18 / 006-Add-ili8960-lcd-driver.patch
1 From 8741ead92bc93e66740237e51b88b8690ebcbba3 Mon Sep 17 00:00:00 2001
2 From: Lars-Peter Clausen <lars@metafoo.de>
3 Date: Sun, 1 Aug 2010 21:19:40 +0200
4 Subject: [PATCH 6/7] Add ili8960 lcd driver
5
6 Includes the following changes from the jz-3.5 branch:
7 - Use module_spi_driver
8 - Use devm_kzalloc
9 - Use kstrtoul
10
11 Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
12 ---
13 drivers/video/backlight/Kconfig | 7 +
14 drivers/video/backlight/Makefile | 1 +
15 drivers/video/backlight/ili8960.c | 262 +++++++++++++++++++++++++++++++++++++
16 3 files changed, 270 insertions(+)
17 create mode 100644 drivers/video/backlight/ili8960.c
18
19 --- a/drivers/video/backlight/Kconfig
20 +++ b/drivers/video/backlight/Kconfig
21 @@ -59,6 +59,13 @@ config LCD_LTV350QV
22
23 The LTV350QV panel is present on all ATSTK1000 boards.
24
25 +config LCD_ILI8960
26 + tristate "Ilitek ili8960 LCD driver"
27 + depends on LCD_CLASS_DEVICE && SPI
28 + default n
29 + help
30 + Driver for the Ilitek ili8960 LCD controller chip.
31 +
32 config LCD_ILI922X
33 tristate "ILI Technology ILI9221/ILI9222 support"
34 depends on SPI
35 --- a/drivers/video/backlight/Makefile
36 +++ b/drivers/video/backlight/Makefile
37 @@ -5,6 +5,7 @@ obj-$(CONFIG_LCD_CLASS_DEVICE) += lcd.o
38 obj-$(CONFIG_LCD_CORGI) += corgi_lcd.o
39 obj-$(CONFIG_LCD_HP700) += jornada720_lcd.o
40 obj-$(CONFIG_LCD_HX8357) += hx8357.o
41 +obj-$(CONFIG_LCD_ILI8960) += ili8960.o
42 obj-$(CONFIG_LCD_ILI922X) += ili922x.o
43 obj-$(CONFIG_LCD_ILI9320) += ili9320.o
44 obj-$(CONFIG_LCD_L4F00242T03) += l4f00242t03.o
45 --- /dev/null
46 +++ b/drivers/video/backlight/ili8960.c
47 @@ -0,0 +1,262 @@
48 +/*
49 + * Copyright (C) 2009-2010, Lars-Peter Clausen <lars@metafoo.de>
50 + * Driver for Ilitek ili8960 LCD
51 + *
52 + * This program is free software; you can redistribute it and/or modify it
53 + * under the terms of the GNU General Public License as published by the
54 + * Free Software Foundation; either version 2 of the License, or (at your
55 + * option) any later version.
56 + *
57 + * You should have received a copy of the GNU General Public License along
58 + * with this program; if not, write to the Free Software Foundation, Inc.,
59 + * 675 Mass Ave, Cambridge, MA 02139, USA.
60 + *
61 + */
62 +
63 +#include <linux/module.h>
64 +#include <linux/spi/spi.h>
65 +#include <linux/lcd.h>
66 +#include <linux/delay.h>
67 +
68 +struct ili8960 {
69 + struct spi_device *spi;
70 + struct lcd_device *lcd;
71 + bool enabled;
72 + unsigned int brightness;
73 +};
74 +
75 +#define ILI8960_REG_BRIGHTNESS 0x03
76 +#define ILI8960_REG_POWER 0x05
77 +#define ILI8960_REG_CONTRAST 0x0d
78 +
79 +static int ili8960_write_reg(struct spi_device *spi, uint8_t reg,
80 + uint8_t data)
81 +{
82 + uint8_t buf[2];
83 + buf[0] = ((reg & 0x40) << 1) | (reg & 0x3f);
84 + buf[1] = data;
85 +
86 + return spi_write(spi, buf, sizeof(buf));
87 +}
88 +
89 +static int ili8960_programm_power(struct spi_device *spi, bool enabled)
90 +{
91 + int ret;
92 +
93 + if (enabled)
94 + mdelay(20);
95 +
96 + ret = ili8960_write_reg(spi, ILI8960_REG_POWER, enabled ? 0xc7 : 0xc6);
97 +
98 + if (!enabled)
99 + mdelay(20);
100 +
101 + return ret;
102 +}
103 +
104 +static int ili8960_set_power(struct lcd_device *lcd, int power)
105 +{
106 + struct ili8960 *ili8960 = lcd_get_data(lcd);
107 +
108 + switch (power) {
109 + case FB_BLANK_UNBLANK:
110 + ili8960->enabled = true;
111 + break;
112 + default:
113 + return 0;
114 + }
115 +
116 + return ili8960_programm_power(ili8960->spi, ili8960->enabled);
117 +}
118 +
119 +static int ili8960_early_set_power(struct lcd_device *lcd, int power)
120 +{
121 + struct ili8960 *ili8960 = lcd_get_data(lcd);
122 +
123 + switch (power) {
124 + case FB_BLANK_UNBLANK:
125 + return 0;
126 + default:
127 + ili8960->enabled = false;
128 + break;
129 + }
130 +
131 + return ili8960_programm_power(ili8960->spi, ili8960->enabled);
132 +}
133 +
134 +static int ili8960_get_power(struct lcd_device *lcd)
135 +{
136 + struct ili8960 *ili8960 = lcd_get_data(lcd);
137 + return ili8960->enabled ? FB_BLANK_UNBLANK : FB_BLANK_POWERDOWN;
138 +}
139 +
140 +static int ili8960_set_contrast(struct lcd_device *lcd, int contrast)
141 +{
142 + struct ili8960 *ili8960 = lcd_get_data(lcd);
143 +
144 + return ili8960_write_reg(ili8960->spi, ILI8960_REG_CONTRAST, contrast);
145 +}
146 +
147 +static int ili8960_set_mode(struct lcd_device *lcd, struct fb_videomode *mode)
148 +{
149 + if (mode->xres != 320 && mode->yres != 240)
150 + return -EINVAL;
151 +
152 + return 0;
153 +}
154 +
155 +static int ili8960_set_brightness(struct ili8960 *ili8960, int brightness)
156 +{
157 + int ret;
158 +
159 + ret = ili8960_write_reg(ili8960->spi, ILI8960_REG_BRIGHTNESS, brightness);
160 +
161 + if (ret == 0)
162 + ili8960->brightness = brightness;
163 +
164 + return ret;
165 +}
166 +
167 +static ssize_t ili8960_show_brightness(struct device *dev,
168 + struct device_attribute *attr, char *buf)
169 +{
170 + struct lcd_device *ld = to_lcd_device(dev);
171 + struct ili8960 *ili8960 = lcd_get_data(ld);
172 +
173 + return sprintf(buf, "%u\n", ili8960->brightness);
174 +}
175 +
176 +static ssize_t ili8960_store_brightness(struct device *dev,
177 + struct device_attribute *attr, const char *buf, size_t count)
178 +{
179 + struct lcd_device *ld = to_lcd_device(dev);
180 + struct ili8960 *ili8960 = lcd_get_data(ld);
181 + unsigned long brightness;
182 + int ret;
183 +
184 + ret = kstrtoul(buf, 0, &brightness);
185 + if (ret)
186 + return ret;
187 +
188 + if (brightness > 255)
189 + return -EINVAL;
190 +
191 + ili8960_set_brightness(ili8960, brightness);
192 +
193 + return count;
194 +}
195 +
196 +
197 +static DEVICE_ATTR(brightness, 0644, ili8960_show_brightness,
198 + ili8960_store_brightness);
199 +
200 +static struct lcd_ops ili8960_lcd_ops = {
201 + .set_power = ili8960_set_power,
202 + .early_set_power = ili8960_early_set_power,
203 + .get_power = ili8960_get_power,
204 + .set_contrast = ili8960_set_contrast,
205 + .set_mode = ili8960_set_mode,
206 +};
207 +
208 +static int ili8960_probe(struct spi_device *spi)
209 +{
210 + int ret;
211 + struct ili8960 *ili8960;
212 +
213 + ili8960 = devm_kzalloc(&spi->dev, sizeof(*ili8960), GFP_KERNEL);
214 + if (!ili8960)
215 + return -ENOMEM;
216 +
217 + spi->bits_per_word = 8;
218 + spi->mode = SPI_MODE_3;
219 +
220 + ret = spi_setup(spi);
221 + if (ret) {
222 + dev_err(&spi->dev, "Failed to setup spi\n");
223 + return ret;
224 + }
225 +
226 + ili8960->spi = spi;
227 +
228 + ili8960->lcd = lcd_device_register("ili8960-lcd", &spi->dev, ili8960,
229 + &ili8960_lcd_ops);
230 +
231 + if (IS_ERR(ili8960->lcd)) {
232 + ret = PTR_ERR(ili8960->lcd);
233 + dev_err(&spi->dev, "Failed to register lcd device: %d\n", ret);
234 + return ret;
235 + }
236 +
237 + ili8960->lcd->props.max_contrast = 255;
238 +
239 + ret = device_create_file(&ili8960->lcd->dev, &dev_attr_brightness);
240 + if (ret)
241 + goto err_unregister_lcd;
242 +
243 + ili8960_programm_power(ili8960->spi, true);
244 + ili8960->enabled = true;
245 +
246 + spi_set_drvdata(spi, ili8960);
247 +
248 + ili8960_write_reg(spi, 0x13, 0x01);
249 +
250 + return 0;
251 +err_unregister_lcd:
252 + lcd_device_unregister(ili8960->lcd);
253 + return ret;
254 +}
255 +
256 +static int ili8960_remove(struct spi_device *spi)
257 +{
258 + struct ili8960 *ili8960 = spi_get_drvdata(spi);
259 +
260 + device_remove_file(&ili8960->lcd->dev, &dev_attr_brightness);
261 + lcd_device_unregister(ili8960->lcd);
262 +
263 + spi_set_drvdata(spi, NULL);
264 + return 0;
265 +}
266 +
267 +#ifdef CONFIG_PM
268 +
269 +static int ili8960_suspend(struct spi_device *spi, pm_message_t state)
270 +{
271 + struct ili8960 *ili8960 = spi_get_drvdata(spi);
272 +
273 + if (ili8960->enabled)
274 + ili8960_programm_power(ili8960->spi, false);
275 +
276 + return 0;
277 +}
278 +
279 +static int ili8960_resume(struct spi_device *spi)
280 +{
281 + struct ili8960 *ili8960 = spi_get_drvdata(spi);
282 +
283 + if (ili8960->enabled)
284 + ili8960_programm_power(ili8960->spi, true);
285 +
286 + return 0;
287 +}
288 +
289 +#else
290 +#define ili8960_suspend NULL
291 +#define ili8960_resume NULL
292 +#endif
293 +
294 +static struct spi_driver ili8960_driver = {
295 + .driver = {
296 + .name = "ili8960",
297 + .owner = THIS_MODULE,
298 + },
299 + .probe = ili8960_probe,
300 + .remove = ili8960_remove,
301 + .suspend = ili8960_suspend,
302 + .resume = ili8960_resume,
303 +};
304 +module_spi_driver(ili8960_driver);
305 +
306 +MODULE_AUTHOR("Lars-Peter Clausen");
307 +MODULE_LICENSE("GPL");
308 +MODULE_DESCRIPTION("LCD driver for Ilitek ili8960");
309 +MODULE_ALIAS("spi:ili8960");