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