summaryrefslogtreecommitdiffstats
path: root/meta/recipes-kernel/linux/linux-omap-2.6.29/dss2/0009-DSS2-Add-acx565akm-panel.patch
diff options
context:
space:
mode:
Diffstat (limited to 'meta/recipes-kernel/linux/linux-omap-2.6.29/dss2/0009-DSS2-Add-acx565akm-panel.patch')
-rw-r--r--meta/recipes-kernel/linux/linux-omap-2.6.29/dss2/0009-DSS2-Add-acx565akm-panel.patch778
1 files changed, 778 insertions, 0 deletions
diff --git a/meta/recipes-kernel/linux/linux-omap-2.6.29/dss2/0009-DSS2-Add-acx565akm-panel.patch b/meta/recipes-kernel/linux/linux-omap-2.6.29/dss2/0009-DSS2-Add-acx565akm-panel.patch
new file mode 100644
index 0000000000..3f55f04460
--- /dev/null
+++ b/meta/recipes-kernel/linux/linux-omap-2.6.29/dss2/0009-DSS2-Add-acx565akm-panel.patch
@@ -0,0 +1,778 @@
1From 66e16f86d3f4c5b34b37e965c65102b7192371de Mon Sep 17 00:00:00 2001
2From: Imre Deak <imre.deak@nokia.com>
3Date: Thu, 2 Apr 2009 11:47:13 +0300
4Subject: [PATCH] DSS2: Add acx565akm panel
5
6Signed-off-by: Imre Deak <imre.deak@nokia.com>
7---
8 drivers/video/omap2/displays/Kconfig | 8 +
9 drivers/video/omap2/displays/Makefile | 2 +
10 drivers/video/omap2/displays/panel-acx565akm.c | 712 ++++++++++++++++++++++++
11 drivers/video/omap2/displays/panel-acx565akm.h | 9 +
12 4 files changed, 731 insertions(+), 0 deletions(-)
13 create mode 100644 drivers/video/omap2/displays/panel-acx565akm.c
14 create mode 100644 drivers/video/omap2/displays/panel-acx565akm.h
15
16diff --git a/drivers/video/omap2/displays/Kconfig b/drivers/video/omap2/displays/Kconfig
17index 356ceb1..3feecee 100644
18--- a/drivers/video/omap2/displays/Kconfig
19+++ b/drivers/video/omap2/displays/Kconfig
20@@ -28,4 +28,12 @@ config CTRL_BLIZZARD
21 tristate "Blizzard Controller"
22 help
23 Blizzard Controller (hack)
24+
25+config PANEL_ACX565AKM
26+ tristate "ACX565AKM LCD Panel"
27+ depends on OMAP2_DSS_SDI
28+ select BACKLIGHT_CLASS_DEVICE
29+ help
30+ LCD Panel used in RX51
31+
32 endmenu
33diff --git a/drivers/video/omap2/displays/Makefile b/drivers/video/omap2/displays/Makefile
34index 1b74b7e..9bafcb6 100644
35--- a/drivers/video/omap2/displays/Makefile
36+++ b/drivers/video/omap2/displays/Makefile
37@@ -4,3 +4,5 @@ obj-$(CONFIG_PANEL_SHARP_LS037V7DW01) += panel-sharp-ls037v7dw01.o
38
39 obj-$(CONFIG_CTRL_BLIZZARD) += ctrl-blizzard.o
40 obj-$(CONFIG_PANEL_N800) += panel-n800.o
41+
42+obj-$(CONFIG_PANEL_ACX565AKM) += panel-acx565akm.o
43diff --git a/drivers/video/omap2/displays/panel-acx565akm.c b/drivers/video/omap2/displays/panel-acx565akm.c
44new file mode 100644
45index 0000000..2679d6c
46--- /dev/null
47+++ b/drivers/video/omap2/displays/panel-acx565akm.c
48@@ -0,0 +1,712 @@
49+#include <linux/kernel.h>
50+#include <linux/module.h>
51+#include <linux/clk.h>
52+#include <linux/platform_device.h>
53+#include <linux/delay.h>
54+#include <linux/spi/spi.h>
55+#include <linux/jiffies.h>
56+#include <linux/sched.h>
57+#include <linux/backlight.h>
58+#include <linux/fb.h>
59+
60+#include <mach/display.h>
61+#include <mach/dma.h>
62+
63+#include "panel-acx565akm.h"
64+
65+#define MIPID_CMD_READ_DISP_ID 0x04
66+#define MIPID_CMD_READ_RED 0x06
67+#define MIPID_CMD_READ_GREEN 0x07
68+#define MIPID_CMD_READ_BLUE 0x08
69+#define MIPID_CMD_READ_DISP_STATUS 0x09
70+#define MIPID_CMD_RDDSDR 0x0F
71+#define MIPID_CMD_SLEEP_IN 0x10
72+#define MIPID_CMD_SLEEP_OUT 0x11
73+#define MIPID_CMD_DISP_OFF 0x28
74+#define MIPID_CMD_DISP_ON 0x29
75+#define MIPID_CMD_WRITE_DISP_BRIGHTNESS 0x51
76+#define MIPID_CMD_READ_DISP_BRIGHTNESS 0x52
77+#define MIPID_CMD_WRITE_CTRL_DISP 0x53
78+
79+#define CTRL_DISP_BRIGHTNESS_CTRL_ON (1 << 5)
80+#define CTRL_DISP_AMBIENT_LIGHT_CTRL_ON (1 << 4)
81+#define CTRL_DISP_BACKLIGHT_ON (1 << 2)
82+#define CTRL_DISP_AUTO_BRIGHTNESS_ON (1 << 1)
83+
84+#define MIPID_CMD_READ_CTRL_DISP 0x54
85+#define MIPID_CMD_WRITE_CABC 0x55
86+#define MIPID_CMD_READ_CABC 0x56
87+
88+#define MIPID_VER_LPH8923 3
89+#define MIPID_VER_LS041Y3 4
90+#define MIPID_VER_L4F00311 8
91+#define MIPID_VER_ACX565AKM 9
92+
93+struct acx565akm_device {
94+ struct backlight_device *bl_dev;
95+ int enabled;
96+ int model;
97+ int revision;
98+ u8 display_id[3];
99+ int has_bc:1;
100+ int has_cabc:1;
101+ unsigned int saved_bklight_level;
102+ unsigned long hw_guard_end; /* next value of jiffies
103+ when we can issue the
104+ next sleep in/out command */
105+ unsigned long hw_guard_wait; /* max guard time in jiffies */
106+
107+ struct spi_device *spi;
108+ struct mutex mutex;
109+ struct omap_panel panel;
110+ struct omap_display *display;
111+};
112+
113+static int acx565akm_bl_update_status(struct backlight_device *dev);
114+
115+static void acx565akm_transfer(struct acx565akm_device *md, int cmd,
116+ const u8 *wbuf, int wlen, u8 *rbuf, int rlen)
117+{
118+ struct spi_message m;
119+ struct spi_transfer *x, xfer[5];
120+ int r;
121+
122+ BUG_ON(md->spi == NULL);
123+
124+ spi_message_init(&m);
125+
126+ memset(xfer, 0, sizeof(xfer));
127+ x = &xfer[0];
128+
129+ cmd &= 0xff;
130+ x->tx_buf = &cmd;
131+ x->bits_per_word = 9;
132+ x->len = 2;
133+
134+ if (rlen > 1 && wlen == 0) {
135+ /*
136+ * Between the command and the response data there is a
137+ * dummy clock cycle. Add an extra bit after the command
138+ * word to account for this.
139+ */
140+ x->bits_per_word = 10;
141+ cmd <<= 1;
142+ }
143+ spi_message_add_tail(x, &m);
144+
145+ if (wlen) {
146+ x++;
147+ x->tx_buf = wbuf;
148+ x->len = wlen;
149+ x->bits_per_word = 9;
150+ spi_message_add_tail(x, &m);
151+ }
152+
153+ if (rlen) {
154+ x++;
155+ x->rx_buf = rbuf;
156+ x->len = rlen;
157+ spi_message_add_tail(x, &m);
158+ }
159+
160+ r = spi_sync(md->spi, &m);
161+ if (r < 0)
162+ dev_dbg(&md->spi->dev, "spi_sync %d\n", r);
163+}
164+
165+static inline void acx565akm_cmd(struct acx565akm_device *md, int cmd)
166+{
167+ acx565akm_transfer(md, cmd, NULL, 0, NULL, 0);
168+}
169+
170+static inline void acx565akm_write(struct acx565akm_device *md,
171+ int reg, const u8 *buf, int len)
172+{
173+ acx565akm_transfer(md, reg, buf, len, NULL, 0);
174+}
175+
176+static inline void acx565akm_read(struct acx565akm_device *md,
177+ int reg, u8 *buf, int len)
178+{
179+ acx565akm_transfer(md, reg, NULL, 0, buf, len);
180+}
181+
182+static void hw_guard_start(struct acx565akm_device *md, int guard_msec)
183+{
184+ md->hw_guard_wait = msecs_to_jiffies(guard_msec);
185+ md->hw_guard_end = jiffies + md->hw_guard_wait;
186+}
187+
188+static void hw_guard_wait(struct acx565akm_device *md)
189+{
190+ unsigned long wait = md->hw_guard_end - jiffies;
191+
192+ if ((long)wait > 0 && wait <= md->hw_guard_wait) {
193+ set_current_state(TASK_UNINTERRUPTIBLE);
194+ schedule_timeout(wait);
195+ }
196+}
197+
198+static void set_sleep_mode(struct acx565akm_device *md, int on)
199+{
200+ int cmd, sleep_time = 50;
201+
202+ if (on)
203+ cmd = MIPID_CMD_SLEEP_IN;
204+ else
205+ cmd = MIPID_CMD_SLEEP_OUT;
206+ hw_guard_wait(md);
207+ acx565akm_cmd(md, cmd);
208+ hw_guard_start(md, 120);
209+ /*
210+ * When we enable the panel, it seems we _have_ to sleep
211+ * 120 ms before sending the init string. When disabling the
212+ * panel we'll sleep for the duration of 2 frames, so that the
213+ * controller can still provide the PCLK,HS,VS signals. */
214+ if (!on)
215+ sleep_time = 120;
216+ msleep(sleep_time);
217+}
218+
219+static void set_display_state(struct acx565akm_device *md, int enabled)
220+{
221+ int cmd = enabled ? MIPID_CMD_DISP_ON : MIPID_CMD_DISP_OFF;
222+
223+ acx565akm_cmd(md, cmd);
224+}
225+
226+static int panel_enabled(struct acx565akm_device *md)
227+{
228+ u32 disp_status;
229+ int enabled;
230+
231+ acx565akm_read(md, MIPID_CMD_READ_DISP_STATUS, (u8 *)&disp_status, 4);
232+ disp_status = __be32_to_cpu(disp_status);
233+ enabled = (disp_status & (1 << 17)) && (disp_status & (1 << 10));
234+ dev_dbg(&md->spi->dev,
235+ "LCD panel %senabled by bootloader (status 0x%04x)\n",
236+ enabled ? "" : "not ", disp_status);
237+ return enabled;
238+}
239+
240+static void enable_backlight_ctrl(struct acx565akm_device *md, int enable)
241+{
242+ u16 ctrl;
243+
244+ acx565akm_read(md, MIPID_CMD_READ_CTRL_DISP, (u8 *)&ctrl, 1);
245+ if (enable) {
246+ ctrl |= CTRL_DISP_BRIGHTNESS_CTRL_ON |
247+ CTRL_DISP_BACKLIGHT_ON;
248+ } else {
249+ ctrl &= ~(CTRL_DISP_BRIGHTNESS_CTRL_ON |
250+ CTRL_DISP_BACKLIGHT_ON);
251+ }
252+
253+ ctrl |= 1 << 8;
254+ acx565akm_write(md, MIPID_CMD_WRITE_CTRL_DISP, (u8 *)&ctrl, 2);
255+}
256+
257+static void set_cabc_mode(struct acx565akm_device *md, int mode)
258+{
259+ u16 cabc_ctrl;
260+
261+ cabc_ctrl = 0;
262+ acx565akm_read(md, MIPID_CMD_READ_CABC, (u8 *)&cabc_ctrl, 1);
263+ cabc_ctrl &= ~3;
264+ cabc_ctrl |= (1 << 8) | (mode & 3);
265+ acx565akm_write(md, MIPID_CMD_WRITE_CABC, (u8 *)&cabc_ctrl, 2);
266+}
267+
268+static int get_cabc_mode(struct acx565akm_device *md)
269+{
270+ u8 cabc_ctrl;
271+
272+ acx565akm_read(md, MIPID_CMD_READ_CABC, &cabc_ctrl, 1);
273+ return cabc_ctrl & 3;
274+}
275+
276+static int panel_detect(struct acx565akm_device *md)
277+{
278+ acx565akm_read(md, MIPID_CMD_READ_DISP_ID, md->display_id, 3);
279+ dev_dbg(&md->spi->dev, "MIPI display ID: %02x%02x%02x\n",
280+ md->display_id[0], md->display_id[1], md->display_id[2]);
281+
282+ switch (md->display_id[0]) {
283+ case 0x10:
284+ md->model = MIPID_VER_ACX565AKM;
285+ md->panel.name = "acx565akm";
286+ md->has_bc = 1;
287+ md->has_cabc = 1;
288+ break;
289+ case 0x29:
290+ md->model = MIPID_VER_L4F00311;
291+ md->panel.name = "l4f00311";
292+ break;
293+ case 0x45:
294+ md->model = MIPID_VER_LPH8923;
295+ md->panel.name = "lph8923";
296+ break;
297+ case 0x83:
298+ md->model = MIPID_VER_LS041Y3;
299+ md->panel.name = "ls041y3";
300+ break;
301+ default:
302+ md->panel.name = "unknown";
303+ dev_err(&md->spi->dev, "invalid display ID\n");
304+ return -ENODEV;
305+ }
306+
307+ md->revision = md->display_id[1];
308+
309+ pr_info("omapfb: %s rev %02x LCD detected\n",
310+ md->panel.name, md->revision);
311+
312+ return 0;
313+}
314+
315+static int acx565akm_panel_enable(struct omap_display *display)
316+{
317+ struct acx565akm_device *md =
318+ (struct acx565akm_device *)display->panel->priv;
319+
320+ dev_dbg(&md->spi->dev, "%s\n", __func__);
321+
322+ mutex_lock(&md->mutex);
323+
324+ if (display->hw_config.panel_enable)
325+ display->hw_config.panel_enable(display);
326+
327+ md->enabled = panel_enabled(md);
328+
329+ if (md->enabled) {
330+ dev_dbg(&md->spi->dev, "panel already enabled\n");
331+ mutex_unlock(&md->mutex);
332+ return 0;
333+ }
334+
335+ set_sleep_mode(md, 0);
336+ md->enabled = 1;
337+ set_display_state(md, 1);
338+
339+ mutex_unlock(&md->mutex);
340+
341+ return acx565akm_bl_update_status(md->bl_dev);
342+}
343+
344+static void acx565akm_panel_disable(struct omap_display *display)
345+{
346+ struct acx565akm_device *md =
347+ (struct acx565akm_device *)display->panel->priv;
348+
349+ dev_dbg(&md->spi->dev, "%s\n", __func__);
350+
351+ mutex_lock(&md->mutex);
352+
353+ if (!md->enabled) {
354+ mutex_unlock(&md->mutex);
355+ return;
356+ }
357+ set_display_state(md, 0);
358+ set_sleep_mode(md, 1);
359+ md->enabled = 0;
360+
361+ if (display->hw_config.panel_disable)
362+ display->hw_config.panel_disable(display);
363+
364+ mutex_unlock(&md->mutex);
365+}
366+
367+#if 0
368+static void acx565akm_set_mode(struct omap_display *display,
369+ int x_res, int y_res, int bpp)
370+{
371+ struct acx565akm_device *md =
372+ (struct acx565akm_device *)display->panel->priv;
373+ u16 par;
374+
375+ switch (bpp) {
376+ case 16:
377+ par = 0x150;
378+ break;
379+ case 18:
380+ par = 0x160;
381+ break;
382+ case 24:
383+ par = 0x170;
384+ break;
385+ }
386+
387+ acx565akm_write(md, 0x3a, (u8 *)&par, 2);
388+}
389+#endif
390+
391+static int acx565akm_panel_suspend(struct omap_display *display)
392+{
393+ acx565akm_panel_disable(display);
394+ return 0;
395+}
396+
397+static int acx565akm_panel_resume(struct omap_display *display)
398+{
399+ return acx565akm_panel_enable(display);
400+}
401+
402+static void acx565akm_set_brightness(struct acx565akm_device *md, int level)
403+{
404+ int bv;
405+
406+ bv = level | (1 << 8);
407+ acx565akm_write(md, MIPID_CMD_WRITE_DISP_BRIGHTNESS, (u8 *)&bv, 2);
408+
409+ if (level)
410+ enable_backlight_ctrl(md, 1);
411+ else
412+ enable_backlight_ctrl(md, 0);
413+}
414+
415+static int acx565akm_get_actual_brightness(struct acx565akm_device *md)
416+{
417+ u8 bv;
418+
419+ acx565akm_read(md, MIPID_CMD_READ_DISP_BRIGHTNESS, &bv, 1);
420+
421+ return bv;
422+}
423+
424+static int acx565akm_bl_update_status(struct backlight_device *dev)
425+{
426+ struct acx565akm_device *md = dev_get_drvdata(&dev->dev);
427+ struct omap_display *display = md->display;
428+ int r;
429+ int level;
430+
431+ dev_dbg(&md->spi->dev, "%s\n", __func__);
432+
433+ if (display->hw_config.set_backlight == NULL)
434+ return -ENODEV;
435+
436+ mutex_lock(&md->mutex);
437+
438+ if (dev->props.fb_blank == FB_BLANK_UNBLANK &&
439+ dev->props.power == FB_BLANK_UNBLANK)
440+ level = dev->props.brightness;
441+ else
442+ level = 0;
443+
444+ r = 0;
445+ if (md->has_bc)
446+ acx565akm_set_brightness(md, level);
447+ else
448+ if (display->hw_config.set_backlight != NULL)
449+ r = display->hw_config.set_backlight(display, level);
450+ else
451+ r = -ENODEV;
452+
453+ mutex_unlock(&md->mutex);
454+
455+ return r;
456+}
457+
458+static int acx565akm_bl_get_intensity(struct backlight_device *dev)
459+{
460+ struct acx565akm_device *md = dev_get_drvdata(&dev->dev);
461+ struct omap_display *display = md->display;
462+
463+ dev_dbg(&dev->dev, "%s\n", __func__);
464+
465+ if (md->has_bc && display->hw_config.set_backlight == NULL)
466+ return -ENODEV;
467+
468+ if (dev->props.fb_blank == FB_BLANK_UNBLANK &&
469+ dev->props.power == FB_BLANK_UNBLANK) {
470+ if (md->has_bc)
471+ return acx565akm_get_actual_brightness(md);
472+ else
473+ return dev->props.brightness;
474+ }
475+
476+ return 0;
477+}
478+
479+static struct backlight_ops acx565akm_bl_ops = {
480+ .get_brightness = acx565akm_bl_get_intensity,
481+ .update_status = acx565akm_bl_update_status,
482+};
483+
484+static const char *cabc_modes[] = {
485+ "off", /* used also always when CABC is not supported */
486+ "ui",
487+ "still-image",
488+ "moving-image",
489+};
490+
491+static ssize_t show_cabc_mode(struct device *dev,
492+ struct device_attribute *attr,
493+ char *buf)
494+{
495+ struct acx565akm_device *md = dev_get_drvdata(dev);
496+ const char *mode_str;
497+ int mode;
498+ int len;
499+
500+ if (!md->has_cabc)
501+ mode = 0;
502+ else
503+ mode = get_cabc_mode(md);
504+ mode_str = "unknown";
505+ if (mode >= 0 && mode < ARRAY_SIZE(cabc_modes))
506+ mode_str = cabc_modes[mode];
507+ len = snprintf(buf, PAGE_SIZE, "%s\n", mode_str);
508+
509+ return len < PAGE_SIZE - 1 ? len : PAGE_SIZE - 1;
510+}
511+
512+static ssize_t store_cabc_mode(struct device *dev,
513+ struct device_attribute *attr,
514+ const char *buf, size_t count)
515+{
516+ struct acx565akm_device *md = dev_get_drvdata(dev);
517+ int i;
518+
519+ for (i = 0; i < ARRAY_SIZE(cabc_modes); i++) {
520+ const char *mode_str = cabc_modes[i];
521+ int cmp_len = strlen(mode_str);
522+
523+ if (count > 0 && buf[count - 1] == '\n')
524+ count--;
525+ if (count != cmp_len)
526+ continue;
527+
528+ if (strncmp(buf, mode_str, cmp_len) == 0)
529+ break;
530+ }
531+
532+ if (i == ARRAY_SIZE(cabc_modes))
533+ return -EINVAL;
534+
535+ if (!md->has_cabc && i != 0)
536+ return -EINVAL;
537+
538+ mutex_lock(&md->mutex);
539+ set_cabc_mode(md, i);
540+ mutex_unlock(&md->mutex);
541+
542+ return count;
543+}
544+
545+static ssize_t show_cabc_available_modes(struct device *dev,
546+ struct device_attribute *attr,
547+ char *buf)
548+{
549+ struct acx565akm_device *md = dev_get_drvdata(dev);
550+ int len;
551+ int i;
552+
553+ if (!md->has_cabc)
554+ return snprintf(buf, PAGE_SIZE, "%s\n", cabc_modes[0]);
555+
556+ for (i = 0, len = 0;
557+ len < PAGE_SIZE && i < ARRAY_SIZE(cabc_modes); i++)
558+ len += snprintf(&buf[len], PAGE_SIZE - len, "%s%s%s",
559+ i ? " " : "", cabc_modes[i],
560+ i == ARRAY_SIZE(cabc_modes) - 1 ? "\n" : "");
561+
562+ return len < PAGE_SIZE ? len : PAGE_SIZE - 1;
563+}
564+
565+static DEVICE_ATTR(cabc_mode, S_IRUGO | S_IWUSR,
566+ show_cabc_mode, store_cabc_mode);
567+static DEVICE_ATTR(cabc_available_modes, S_IRUGO,
568+ show_cabc_available_modes, NULL);
569+
570+static struct attribute *bldev_attrs[] = {
571+ &dev_attr_cabc_mode.attr,
572+ &dev_attr_cabc_available_modes.attr,
573+ NULL,
574+};
575+
576+static struct attribute_group bldev_attr_group = {
577+ .attrs = bldev_attrs,
578+};
579+
580+static int acx565akm_panel_init(struct omap_display *display)
581+{
582+ struct omap_panel *panel = display->panel;
583+ struct acx565akm_panel_data *panel_data = display->hw_config.panel_data;
584+ struct acx565akm_device *md = (struct acx565akm_device *)panel->priv;
585+
586+ struct backlight_device *bldev;
587+ int brightness;
588+ int max_brightness;
589+ int r;
590+
591+ dev_dbg(&md->spi->dev, "%s\n", __func__);
592+
593+ if (!panel_data) {
594+ dev_err(&md->spi->dev, "no panel data\n");
595+ return -ENODEV;
596+ }
597+
598+ mutex_init(&md->mutex);
599+ md->display = display;
600+
601+ if (display->hw_config.panel_enable)
602+ display->hw_config.panel_enable(display);
603+
604+ md->enabled = panel_enabled(md);
605+
606+ r = panel_detect(md);
607+ if (r) {
608+ if (!md->enabled && display->hw_config.panel_disable)
609+ display->hw_config.panel_disable(display);
610+ mutex_unlock(&md->mutex);
611+ return r;
612+ }
613+
614+ if (!panel_data->bc_connected) {
615+ md->has_bc = 0;
616+ md->has_cabc = 0;
617+ }
618+
619+#if 0
620+ acx565akm_set_mode(display, panel->timings.x_res, panel->timings.y_res,
621+ panel->bpp);
622+#endif
623+
624+ if (!md->enabled)
625+ display->hw_config.panel_disable(display);
626+
627+ bldev = backlight_device_register("acx565akm", &md->spi->dev,
628+ md, &acx565akm_bl_ops);
629+ md->bl_dev = bldev;
630+
631+ if (md->has_cabc) {
632+ r = sysfs_create_group(&bldev->dev.kobj, &bldev_attr_group);
633+ if (r) {
634+ dev_err(&bldev->dev, "failed to create sysfs files\n");
635+ backlight_device_unregister(bldev);
636+ return r;
637+ }
638+ }
639+
640+ bldev->props.fb_blank = FB_BLANK_UNBLANK;
641+ bldev->props.power = FB_BLANK_UNBLANK;
642+
643+ if (md->has_bc)
644+ max_brightness = 255;
645+ else
646+ max_brightness = display->hw_config.max_backlight_level;
647+
648+ if (md->has_bc)
649+ brightness = acx565akm_get_actual_brightness(md);
650+ else {
651+ if (display->hw_config.get_backlight != NULL)
652+ brightness = display->hw_config.get_backlight(display);
653+ else
654+ brightness = 0;
655+ }
656+
657+ bldev->props.max_brightness = max_brightness;
658+ bldev->props.brightness = brightness;
659+ acx565akm_bl_update_status(bldev);
660+
661+ return 0;
662+}
663+
664+static struct omap_panel acx565akm_panel = {
665+ .name = "panel-acx565akm",
666+ .init = acx565akm_panel_init,
667+ .suspend = acx565akm_panel_suspend,
668+ .resume = acx565akm_panel_resume,
669+ .enable = acx565akm_panel_enable,
670+ .disable = acx565akm_panel_disable,
671+
672+ .timings = {
673+ .x_res = 800,
674+ .y_res = 480,
675+
676+ .pixel_clock = 24000,
677+
678+ .hsw = 4,
679+ .hfp = 16,
680+ .hbp = 12,
681+
682+ .vsw = 3,
683+ .vfp = 3,
684+ .vbp = 3,
685+ },
686+
687+ .config = OMAP_DSS_LCD_TFT,
688+
689+ .recommended_bpp = 16,
690+
691+ /*
692+ * supported modes: 12bpp(444), 16bpp(565), 18bpp(666), 24bpp(888)
693+ * resolutions.
694+ */
695+};
696+
697+static int acx565akm_spi_probe(struct spi_device *spi)
698+{
699+ struct acx565akm_device *md;
700+
701+ dev_dbg(&md->spi->dev, "%s\n", __func__);
702+
703+ md = kzalloc(sizeof(*md), GFP_KERNEL);
704+ if (md == NULL) {
705+ dev_err(&spi->dev, "out of memory\n");
706+ return -ENOMEM;
707+ }
708+
709+ spi->mode = SPI_MODE_3;
710+ md->spi = spi;
711+ dev_set_drvdata(&spi->dev, md);
712+ md->panel = acx565akm_panel;
713+ acx565akm_panel.priv = md;
714+
715+ omap_dss_register_panel(&acx565akm_panel);
716+
717+ return 0;
718+}
719+
720+static int acx565akm_spi_remove(struct spi_device *spi)
721+{
722+ struct acx565akm_device *md = dev_get_drvdata(&spi->dev);
723+
724+ dev_dbg(&md->spi->dev, "%s\n", __func__);
725+
726+ sysfs_remove_group(&md->bl_dev->dev.kobj, &bldev_attr_group);
727+ backlight_device_unregister(md->bl_dev);
728+ omap_dss_unregister_panel(&acx565akm_panel);
729+
730+ kfree(md);
731+
732+ return 0;
733+}
734+
735+static struct spi_driver acx565akm_spi_driver = {
736+ .driver = {
737+ .name = "acx565akm",
738+ .bus = &spi_bus_type,
739+ .owner = THIS_MODULE,
740+ },
741+ .probe = acx565akm_spi_probe,
742+ .remove = __devexit_p(acx565akm_spi_remove),
743+};
744+
745+static int __init acx565akm_init(void)
746+{
747+ return spi_register_driver(&acx565akm_spi_driver);
748+}
749+
750+static void __exit acx565akm_exit(void)
751+{
752+ spi_unregister_driver(&acx565akm_spi_driver);
753+}
754+
755+module_init(acx565akm_init);
756+module_exit(acx565akm_exit);
757+
758+MODULE_AUTHOR("Tomi Valkeinen <tomi.valkeinen@nokia.com>");
759+MODULE_DESCRIPTION("acx565akm LCD Driver");
760+MODULE_LICENSE("GPL");
761diff --git a/drivers/video/omap2/displays/panel-acx565akm.h b/drivers/video/omap2/displays/panel-acx565akm.h
762new file mode 100644
763index 0000000..6d3727b
764--- /dev/null
765+++ b/drivers/video/omap2/displays/panel-acx565akm.h
766@@ -0,0 +1,9 @@
767+#ifndef __DRIVERS_VIDEO_OMAP2_DISPLAYS_PANEL_ACX565AKM_H
768+#define __DRIVERS_VIDEO_OMAP2_DISPLAYS_PANEL_ACX565AKM_H
769+
770+struct acx565akm_panel_data {
771+ unsigned bc_connected:1;
772+};
773+
774+#endif
775+
776--
7771.5.6.5
778