diff options
Diffstat (limited to 'drivers/video/omap2/displays-new/panel-lgphilips-lb035q02.c')
-rw-r--r-- | drivers/video/omap2/displays-new/panel-lgphilips-lb035q02.c | 358 |
1 files changed, 0 insertions, 358 deletions
diff --git a/drivers/video/omap2/displays-new/panel-lgphilips-lb035q02.c b/drivers/video/omap2/displays-new/panel-lgphilips-lb035q02.c deleted file mode 100644 index 2e6b513222d9..000000000000 --- a/drivers/video/omap2/displays-new/panel-lgphilips-lb035q02.c +++ /dev/null | |||
@@ -1,358 +0,0 @@ | |||
1 | /* | ||
2 | * LG.Philips LB035Q02 LCD Panel driver | ||
3 | * | ||
4 | * Copyright (C) 2013 Texas Instruments | ||
5 | * Author: Tomi Valkeinen <tomi.valkeinen@ti.com> | ||
6 | * Based on a driver by: Steve Sakoman <steve@sakoman.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify it | ||
9 | * under the terms of the GNU General Public License version 2 as published by | ||
10 | * the Free Software Foundation. | ||
11 | */ | ||
12 | |||
13 | #include <linux/module.h> | ||
14 | #include <linux/delay.h> | ||
15 | #include <linux/spi/spi.h> | ||
16 | #include <linux/mutex.h> | ||
17 | #include <linux/gpio.h> | ||
18 | |||
19 | #include <video/omapdss.h> | ||
20 | #include <video/omap-panel-data.h> | ||
21 | |||
22 | static struct omap_video_timings lb035q02_timings = { | ||
23 | .x_res = 320, | ||
24 | .y_res = 240, | ||
25 | |||
26 | .pixelclock = 6500000, | ||
27 | |||
28 | .hsw = 2, | ||
29 | .hfp = 20, | ||
30 | .hbp = 68, | ||
31 | |||
32 | .vsw = 2, | ||
33 | .vfp = 4, | ||
34 | .vbp = 18, | ||
35 | |||
36 | .vsync_level = OMAPDSS_SIG_ACTIVE_LOW, | ||
37 | .hsync_level = OMAPDSS_SIG_ACTIVE_LOW, | ||
38 | .data_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE, | ||
39 | .de_level = OMAPDSS_SIG_ACTIVE_HIGH, | ||
40 | .sync_pclk_edge = OMAPDSS_DRIVE_SIG_OPPOSITE_EDGES, | ||
41 | }; | ||
42 | |||
43 | struct panel_drv_data { | ||
44 | struct omap_dss_device dssdev; | ||
45 | struct omap_dss_device *in; | ||
46 | |||
47 | struct spi_device *spi; | ||
48 | |||
49 | int data_lines; | ||
50 | |||
51 | struct omap_video_timings videomode; | ||
52 | |||
53 | int reset_gpio; | ||
54 | int backlight_gpio; | ||
55 | int enable_gpio; | ||
56 | }; | ||
57 | |||
58 | #define to_panel_data(p) container_of(p, struct panel_drv_data, dssdev) | ||
59 | |||
60 | static int lb035q02_write_reg(struct spi_device *spi, u8 reg, u16 val) | ||
61 | { | ||
62 | struct spi_message msg; | ||
63 | struct spi_transfer index_xfer = { | ||
64 | .len = 3, | ||
65 | .cs_change = 1, | ||
66 | }; | ||
67 | struct spi_transfer value_xfer = { | ||
68 | .len = 3, | ||
69 | }; | ||
70 | u8 buffer[16]; | ||
71 | |||
72 | spi_message_init(&msg); | ||
73 | |||
74 | /* register index */ | ||
75 | buffer[0] = 0x70; | ||
76 | buffer[1] = 0x00; | ||
77 | buffer[2] = reg & 0x7f; | ||
78 | index_xfer.tx_buf = buffer; | ||
79 | spi_message_add_tail(&index_xfer, &msg); | ||
80 | |||
81 | /* register value */ | ||
82 | buffer[4] = 0x72; | ||
83 | buffer[5] = val >> 8; | ||
84 | buffer[6] = val; | ||
85 | value_xfer.tx_buf = buffer + 4; | ||
86 | spi_message_add_tail(&value_xfer, &msg); | ||
87 | |||
88 | return spi_sync(spi, &msg); | ||
89 | } | ||
90 | |||
91 | static void init_lb035q02_panel(struct spi_device *spi) | ||
92 | { | ||
93 | /* Init sequence from page 28 of the lb035q02 spec */ | ||
94 | lb035q02_write_reg(spi, 0x01, 0x6300); | ||
95 | lb035q02_write_reg(spi, 0x02, 0x0200); | ||
96 | lb035q02_write_reg(spi, 0x03, 0x0177); | ||
97 | lb035q02_write_reg(spi, 0x04, 0x04c7); | ||
98 | lb035q02_write_reg(spi, 0x05, 0xffc0); | ||
99 | lb035q02_write_reg(spi, 0x06, 0xe806); | ||
100 | lb035q02_write_reg(spi, 0x0a, 0x4008); | ||
101 | lb035q02_write_reg(spi, 0x0b, 0x0000); | ||
102 | lb035q02_write_reg(spi, 0x0d, 0x0030); | ||
103 | lb035q02_write_reg(spi, 0x0e, 0x2800); | ||
104 | lb035q02_write_reg(spi, 0x0f, 0x0000); | ||
105 | lb035q02_write_reg(spi, 0x16, 0x9f80); | ||
106 | lb035q02_write_reg(spi, 0x17, 0x0a0f); | ||
107 | lb035q02_write_reg(spi, 0x1e, 0x00c1); | ||
108 | lb035q02_write_reg(spi, 0x30, 0x0300); | ||
109 | lb035q02_write_reg(spi, 0x31, 0x0007); | ||
110 | lb035q02_write_reg(spi, 0x32, 0x0000); | ||
111 | lb035q02_write_reg(spi, 0x33, 0x0000); | ||
112 | lb035q02_write_reg(spi, 0x34, 0x0707); | ||
113 | lb035q02_write_reg(spi, 0x35, 0x0004); | ||
114 | lb035q02_write_reg(spi, 0x36, 0x0302); | ||
115 | lb035q02_write_reg(spi, 0x37, 0x0202); | ||
116 | lb035q02_write_reg(spi, 0x3a, 0x0a0d); | ||
117 | lb035q02_write_reg(spi, 0x3b, 0x0806); | ||
118 | } | ||
119 | |||
120 | static int lb035q02_connect(struct omap_dss_device *dssdev) | ||
121 | { | ||
122 | struct panel_drv_data *ddata = to_panel_data(dssdev); | ||
123 | struct omap_dss_device *in = ddata->in; | ||
124 | int r; | ||
125 | |||
126 | if (omapdss_device_is_connected(dssdev)) | ||
127 | return 0; | ||
128 | |||
129 | r = in->ops.dpi->connect(in, dssdev); | ||
130 | if (r) | ||
131 | return r; | ||
132 | |||
133 | init_lb035q02_panel(ddata->spi); | ||
134 | |||
135 | return 0; | ||
136 | } | ||
137 | |||
138 | static void lb035q02_disconnect(struct omap_dss_device *dssdev) | ||
139 | { | ||
140 | struct panel_drv_data *ddata = to_panel_data(dssdev); | ||
141 | struct omap_dss_device *in = ddata->in; | ||
142 | |||
143 | if (!omapdss_device_is_connected(dssdev)) | ||
144 | return; | ||
145 | |||
146 | in->ops.dpi->disconnect(in, dssdev); | ||
147 | } | ||
148 | |||
149 | static int lb035q02_enable(struct omap_dss_device *dssdev) | ||
150 | { | ||
151 | struct panel_drv_data *ddata = to_panel_data(dssdev); | ||
152 | struct omap_dss_device *in = ddata->in; | ||
153 | int r; | ||
154 | |||
155 | if (!omapdss_device_is_connected(dssdev)) | ||
156 | return -ENODEV; | ||
157 | |||
158 | if (omapdss_device_is_enabled(dssdev)) | ||
159 | return 0; | ||
160 | |||
161 | in->ops.dpi->set_data_lines(in, ddata->data_lines); | ||
162 | in->ops.dpi->set_timings(in, &ddata->videomode); | ||
163 | |||
164 | r = in->ops.dpi->enable(in); | ||
165 | if (r) | ||
166 | return r; | ||
167 | |||
168 | if (gpio_is_valid(ddata->enable_gpio)) | ||
169 | gpio_set_value_cansleep(ddata->enable_gpio, 1); | ||
170 | |||
171 | if (gpio_is_valid(ddata->backlight_gpio)) | ||
172 | gpio_set_value_cansleep(ddata->backlight_gpio, 1); | ||
173 | |||
174 | dssdev->state = OMAP_DSS_DISPLAY_ACTIVE; | ||
175 | |||
176 | return 0; | ||
177 | } | ||
178 | |||
179 | static void lb035q02_disable(struct omap_dss_device *dssdev) | ||
180 | { | ||
181 | struct panel_drv_data *ddata = to_panel_data(dssdev); | ||
182 | struct omap_dss_device *in = ddata->in; | ||
183 | |||
184 | if (!omapdss_device_is_enabled(dssdev)) | ||
185 | return; | ||
186 | |||
187 | if (gpio_is_valid(ddata->enable_gpio)) | ||
188 | gpio_set_value_cansleep(ddata->enable_gpio, 0); | ||
189 | |||
190 | if (gpio_is_valid(ddata->backlight_gpio)) | ||
191 | gpio_set_value_cansleep(ddata->backlight_gpio, 0); | ||
192 | |||
193 | in->ops.dpi->disable(in); | ||
194 | |||
195 | dssdev->state = OMAP_DSS_DISPLAY_DISABLED; | ||
196 | } | ||
197 | |||
198 | static void lb035q02_set_timings(struct omap_dss_device *dssdev, | ||
199 | struct omap_video_timings *timings) | ||
200 | { | ||
201 | struct panel_drv_data *ddata = to_panel_data(dssdev); | ||
202 | struct omap_dss_device *in = ddata->in; | ||
203 | |||
204 | ddata->videomode = *timings; | ||
205 | dssdev->panel.timings = *timings; | ||
206 | |||
207 | in->ops.dpi->set_timings(in, timings); | ||
208 | } | ||
209 | |||
210 | static void lb035q02_get_timings(struct omap_dss_device *dssdev, | ||
211 | struct omap_video_timings *timings) | ||
212 | { | ||
213 | struct panel_drv_data *ddata = to_panel_data(dssdev); | ||
214 | |||
215 | *timings = ddata->videomode; | ||
216 | } | ||
217 | |||
218 | static int lb035q02_check_timings(struct omap_dss_device *dssdev, | ||
219 | struct omap_video_timings *timings) | ||
220 | { | ||
221 | struct panel_drv_data *ddata = to_panel_data(dssdev); | ||
222 | struct omap_dss_device *in = ddata->in; | ||
223 | |||
224 | return in->ops.dpi->check_timings(in, timings); | ||
225 | } | ||
226 | |||
227 | static struct omap_dss_driver lb035q02_ops = { | ||
228 | .connect = lb035q02_connect, | ||
229 | .disconnect = lb035q02_disconnect, | ||
230 | |||
231 | .enable = lb035q02_enable, | ||
232 | .disable = lb035q02_disable, | ||
233 | |||
234 | .set_timings = lb035q02_set_timings, | ||
235 | .get_timings = lb035q02_get_timings, | ||
236 | .check_timings = lb035q02_check_timings, | ||
237 | |||
238 | .get_resolution = omapdss_default_get_resolution, | ||
239 | }; | ||
240 | |||
241 | static int lb035q02_probe_pdata(struct spi_device *spi) | ||
242 | { | ||
243 | const struct panel_lb035q02_platform_data *pdata; | ||
244 | struct panel_drv_data *ddata = dev_get_drvdata(&spi->dev); | ||
245 | struct omap_dss_device *dssdev, *in; | ||
246 | |||
247 | pdata = dev_get_platdata(&spi->dev); | ||
248 | |||
249 | in = omap_dss_find_output(pdata->source); | ||
250 | if (in == NULL) { | ||
251 | dev_err(&spi->dev, "failed to find video source '%s'\n", | ||
252 | pdata->source); | ||
253 | return -EPROBE_DEFER; | ||
254 | } | ||
255 | |||
256 | ddata->in = in; | ||
257 | |||
258 | ddata->data_lines = pdata->data_lines; | ||
259 | |||
260 | dssdev = &ddata->dssdev; | ||
261 | dssdev->name = pdata->name; | ||
262 | |||
263 | ddata->enable_gpio = pdata->enable_gpio; | ||
264 | ddata->backlight_gpio = pdata->backlight_gpio; | ||
265 | |||
266 | return 0; | ||
267 | } | ||
268 | |||
269 | static int lb035q02_panel_spi_probe(struct spi_device *spi) | ||
270 | { | ||
271 | struct panel_drv_data *ddata; | ||
272 | struct omap_dss_device *dssdev; | ||
273 | int r; | ||
274 | |||
275 | ddata = devm_kzalloc(&spi->dev, sizeof(*ddata), GFP_KERNEL); | ||
276 | if (ddata == NULL) | ||
277 | return -ENOMEM; | ||
278 | |||
279 | dev_set_drvdata(&spi->dev, ddata); | ||
280 | |||
281 | ddata->spi = spi; | ||
282 | |||
283 | if (dev_get_platdata(&spi->dev)) { | ||
284 | r = lb035q02_probe_pdata(spi); | ||
285 | if (r) | ||
286 | return r; | ||
287 | } else { | ||
288 | return -ENODEV; | ||
289 | } | ||
290 | |||
291 | if (gpio_is_valid(ddata->enable_gpio)) { | ||
292 | r = devm_gpio_request_one(&spi->dev, ddata->enable_gpio, | ||
293 | GPIOF_OUT_INIT_LOW, "panel enable"); | ||
294 | if (r) | ||
295 | goto err_gpio; | ||
296 | } | ||
297 | |||
298 | if (gpio_is_valid(ddata->backlight_gpio)) { | ||
299 | r = devm_gpio_request_one(&spi->dev, ddata->backlight_gpio, | ||
300 | GPIOF_OUT_INIT_LOW, "panel backlight"); | ||
301 | if (r) | ||
302 | goto err_gpio; | ||
303 | } | ||
304 | |||
305 | ddata->videomode = lb035q02_timings; | ||
306 | |||
307 | dssdev = &ddata->dssdev; | ||
308 | dssdev->dev = &spi->dev; | ||
309 | dssdev->driver = &lb035q02_ops; | ||
310 | dssdev->type = OMAP_DISPLAY_TYPE_DPI; | ||
311 | dssdev->owner = THIS_MODULE; | ||
312 | dssdev->panel.timings = ddata->videomode; | ||
313 | dssdev->phy.dpi.data_lines = ddata->data_lines; | ||
314 | |||
315 | r = omapdss_register_display(dssdev); | ||
316 | if (r) { | ||
317 | dev_err(&spi->dev, "Failed to register panel\n"); | ||
318 | goto err_reg; | ||
319 | } | ||
320 | |||
321 | return 0; | ||
322 | |||
323 | err_reg: | ||
324 | err_gpio: | ||
325 | omap_dss_put_device(ddata->in); | ||
326 | return r; | ||
327 | } | ||
328 | |||
329 | static int lb035q02_panel_spi_remove(struct spi_device *spi) | ||
330 | { | ||
331 | struct panel_drv_data *ddata = dev_get_drvdata(&spi->dev); | ||
332 | struct omap_dss_device *dssdev = &ddata->dssdev; | ||
333 | struct omap_dss_device *in = ddata->in; | ||
334 | |||
335 | omapdss_unregister_display(dssdev); | ||
336 | |||
337 | lb035q02_disable(dssdev); | ||
338 | lb035q02_disconnect(dssdev); | ||
339 | |||
340 | omap_dss_put_device(in); | ||
341 | |||
342 | return 0; | ||
343 | } | ||
344 | |||
345 | static struct spi_driver lb035q02_spi_driver = { | ||
346 | .probe = lb035q02_panel_spi_probe, | ||
347 | .remove = lb035q02_panel_spi_remove, | ||
348 | .driver = { | ||
349 | .name = "panel_lgphilips_lb035q02", | ||
350 | .owner = THIS_MODULE, | ||
351 | }, | ||
352 | }; | ||
353 | |||
354 | module_spi_driver(lb035q02_spi_driver); | ||
355 | |||
356 | MODULE_AUTHOR("Tomi Valkeinen <tomi.valkeinen@ti.com>"); | ||
357 | MODULE_DESCRIPTION("LG.Philips LB035Q02 LCD Panel driver"); | ||
358 | MODULE_LICENSE("GPL"); | ||