summaryrefslogtreecommitdiffstats
path: root/meta/recipes-kernel/linux/linux-netbook-2.6.33.2/linux-2.6.35-OMAP-DSS2-Add-ACX565AKM-Panel-Driver.patch
diff options
context:
space:
mode:
authorSaul Wold <Saul.Wold@intel.com>2010-09-24 15:36:24 -0700
committerSaul Wold <Saul.Wold@intel.com>2010-09-24 16:43:21 -0700
commit239a368d5715d8f5b7733f9400339c2350c49369 (patch)
tree2953f12b45e590d9e14b6f72f8e4ee7188e41508 /meta/recipes-kernel/linux/linux-netbook-2.6.33.2/linux-2.6.35-OMAP-DSS2-Add-ACX565AKM-Panel-Driver.patch
parentc5b9525263dac6844d152e40acf8cee4d27b60bc (diff)
downloadpoky-239a368d5715d8f5b7733f9400339c2350c49369.tar.gz
netbook: Correct netbook build by moving netbook configuration from moblin to meta
Signed-off-by: Saul Wold <Saul.Wold@intel.com>
Diffstat (limited to 'meta/recipes-kernel/linux/linux-netbook-2.6.33.2/linux-2.6.35-OMAP-DSS2-Add-ACX565AKM-Panel-Driver.patch')
-rw-r--r--meta/recipes-kernel/linux/linux-netbook-2.6.33.2/linux-2.6.35-OMAP-DSS2-Add-ACX565AKM-Panel-Driver.patch813
1 files changed, 813 insertions, 0 deletions
diff --git a/meta/recipes-kernel/linux/linux-netbook-2.6.33.2/linux-2.6.35-OMAP-DSS2-Add-ACX565AKM-Panel-Driver.patch b/meta/recipes-kernel/linux/linux-netbook-2.6.33.2/linux-2.6.35-OMAP-DSS2-Add-ACX565AKM-Panel-Driver.patch
new file mode 100644
index 0000000000..0b3b501293
--- /dev/null
+++ b/meta/recipes-kernel/linux/linux-netbook-2.6.33.2/linux-2.6.35-OMAP-DSS2-Add-ACX565AKM-Panel-Driver.patch
@@ -0,0 +1,813 @@
1From 635f44cfde6c057a2ecbb8c9d9a67225e53b6545 Mon Sep 17 00:00:00 2001
2From: Roger Quadros <roger.quadros@nokia.com>
3Date: Wed, 10 Mar 2010 17:32:44 +0200
4Subject: [PATCH 3/10] OMAP: DSS2: Add ACX565AKM Panel Driver
5
6From: Roger Quadros <roger.quadros@nokia.com>
7
8Patch-mainline: 2.6.35?
9Git-repo: http://www.gitorious.org/linux-omap-dss2/linux/commit/4f2308f3be2fe631412ea85a80c91414c3bfe730
10
11This is the panel used on Nokia N900
12
13Signed-off-by: Roger Quadros <roger.quadros@nokia.com>
14---
15 drivers/video/omap2/displays/Kconfig | 6 +
16 drivers/video/omap2/displays/Makefile | 1 +
17 drivers/video/omap2/displays/panel-acx565akm.c | 760 ++++++++++++++++++++++++
18 3 files changed, 767 insertions(+), 0 deletions(-)
19 create mode 100644 drivers/video/omap2/displays/panel-acx565akm.c
20
21diff --git a/drivers/video/omap2/displays/Kconfig b/drivers/video/omap2/displays/Kconfig
22index b12a59c..1f5b7d1 100644
23--- a/drivers/video/omap2/displays/Kconfig
24+++ b/drivers/video/omap2/displays/Kconfig
25@@ -19,4 +19,10 @@ config PANEL_TAAL
26 help
27 Taal DSI command mode panel from TPO.
28
29+config PANEL_ACX565AKM
30+ tristate "ACX565AKM Panel"
31+ depends on OMAP2_DSS_SDI
32+ select BACKLIGHT_CLASS_DEVICE
33+ help
34+ This is the LCD panel used on Nokia N900
35 endmenu
36diff --git a/drivers/video/omap2/displays/Makefile b/drivers/video/omap2/displays/Makefile
37index 9556464..0af16b7 100644
38--- a/drivers/video/omap2/displays/Makefile
39+++ b/drivers/video/omap2/displays/Makefile
40@@ -2,3 +2,4 @@ obj-$(CONFIG_PANEL_GENERIC) += panel-generic.o
41 obj-$(CONFIG_PANEL_SHARP_LS037V7DW01) += panel-sharp-ls037v7dw01.o
42
43 obj-$(CONFIG_PANEL_TAAL) += panel-taal.o
44+obj-$(CONFIG_PANEL_ACX565AKM) += panel-acx565akm.o
45diff --git a/drivers/video/omap2/displays/panel-acx565akm.c b/drivers/video/omap2/displays/panel-acx565akm.c
46new file mode 100644
47index 0000000..27e9847
48--- /dev/null
49+++ b/drivers/video/omap2/displays/panel-acx565akm.c
50@@ -0,0 +1,760 @@
51+/*
52+ * Support for ACX565AKM LCD Panel used on Nokia N900
53+ *
54+ * Copyright (C) 2010 Nokia Corporation
55+ *
56+ * Original Driver Author: Imre Deak <imre.deak@nokia.com>
57+ * Based on panel-generic.c by Tomi Valkeinen <tomi.valkeinen@nokia.com>
58+ * Adapted to new DSS2 framework: Roger Quadros <roger.quadros@nokia.com>
59+ *
60+ * This program is free software; you can redistribute it and/or modify it
61+ * under the terms of the GNU General Public License version 2 as published by
62+ * the Free Software Foundation.
63+ *
64+ * This program is distributed in the hope that it will be useful, but WITHOUT
65+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
66+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
67+ * more details.
68+ *
69+ * You should have received a copy of the GNU General Public License along with
70+ * this program. If not, see <http://www.gnu.org/licenses/>.
71+ */
72+
73+#include <linux/kernel.h>
74+#include <linux/module.h>
75+#include <linux/platform_device.h>
76+#include <linux/delay.h>
77+#include <linux/spi/spi.h>
78+#include <linux/jiffies.h>
79+#include <linux/sched.h>
80+#include <linux/backlight.h>
81+#include <linux/fb.h>
82+
83+#include <plat/display.h>
84+
85+#define MIPID_CMD_READ_DISP_ID 0x04
86+#define MIPID_CMD_READ_RED 0x06
87+#define MIPID_CMD_READ_GREEN 0x07
88+#define MIPID_CMD_READ_BLUE 0x08
89+#define MIPID_CMD_READ_DISP_STATUS 0x09
90+#define MIPID_CMD_RDDSDR 0x0F
91+#define MIPID_CMD_SLEEP_IN 0x10
92+#define MIPID_CMD_SLEEP_OUT 0x11
93+#define MIPID_CMD_DISP_OFF 0x28
94+#define MIPID_CMD_DISP_ON 0x29
95+#define MIPID_CMD_WRITE_DISP_BRIGHTNESS 0x51
96+#define MIPID_CMD_READ_DISP_BRIGHTNESS 0x52
97+#define MIPID_CMD_WRITE_CTRL_DISP 0x53
98+
99+#define CTRL_DISP_BRIGHTNESS_CTRL_ON (1 << 5)
100+#define CTRL_DISP_AMBIENT_LIGHT_CTRL_ON (1 << 4)
101+#define CTRL_DISP_BACKLIGHT_ON (1 << 2)
102+#define CTRL_DISP_AUTO_BRIGHTNESS_ON (1 << 1)
103+
104+#define MIPID_CMD_READ_CTRL_DISP 0x54
105+#define MIPID_CMD_WRITE_CABC 0x55
106+#define MIPID_CMD_READ_CABC 0x56
107+
108+#define MIPID_VER_LPH8923 3
109+#define MIPID_VER_LS041Y3 4
110+#define MIPID_VER_L4F00311 8
111+#define MIPID_VER_ACX565AKM 9
112+
113+struct acx565akm_device {
114+ char *name;
115+ int enabled;
116+ int model;
117+ int revision;
118+ u8 display_id[3];
119+ unsigned has_bc:1;
120+ unsigned has_cabc:1;
121+ unsigned cabc_mode;
122+ unsigned long hw_guard_end; /* next value of jiffies
123+ when we can issue the
124+ next sleep in/out command */
125+ unsigned long hw_guard_wait; /* max guard time in jiffies */
126+
127+ struct spi_device *spi;
128+ struct mutex mutex;
129+
130+ struct omap_dss_device *dssdev;
131+ struct backlight_device *bl_dev;
132+};
133+
134+static struct acx565akm_device acx_dev;
135+static int acx565akm_bl_update_status(struct backlight_device *dev);
136+
137+/*--------------------MIPID interface-----------------------------*/
138+
139+static void acx565akm_transfer(struct acx565akm_device *md, int cmd,
140+ const u8 *wbuf, int wlen, u8 *rbuf, int rlen)
141+{
142+ struct spi_message m;
143+ struct spi_transfer *x, xfer[5];
144+ int r;
145+
146+ BUG_ON(md->spi == NULL);
147+
148+ spi_message_init(&m);
149+
150+ memset(xfer, 0, sizeof(xfer));
151+ x = &xfer[0];
152+
153+ cmd &= 0xff;
154+ x->tx_buf = &cmd;
155+ x->bits_per_word = 9;
156+ x->len = 2;
157+
158+ if (rlen > 1 && wlen == 0) {
159+ /*
160+ * Between the command and the response data there is a
161+ * dummy clock cycle. Add an extra bit after the command
162+ * word to account for this.
163+ */
164+ x->bits_per_word = 10;
165+ cmd <<= 1;
166+ }
167+ spi_message_add_tail(x, &m);
168+
169+ if (wlen) {
170+ x++;
171+ x->tx_buf = wbuf;
172+ x->len = wlen;
173+ x->bits_per_word = 9;
174+ spi_message_add_tail(x, &m);
175+ }
176+
177+ if (rlen) {
178+ x++;
179+ x->rx_buf = rbuf;
180+ x->len = rlen;
181+ spi_message_add_tail(x, &m);
182+ }
183+
184+ r = spi_sync(md->spi, &m);
185+ if (r < 0)
186+ dev_dbg(&md->spi->dev, "spi_sync %d\n", r);
187+}
188+
189+static inline void acx565akm_cmd(struct acx565akm_device *md, int cmd)
190+{
191+ acx565akm_transfer(md, cmd, NULL, 0, NULL, 0);
192+}
193+
194+static inline void acx565akm_write(struct acx565akm_device *md,
195+ int reg, const u8 *buf, int len)
196+{
197+ acx565akm_transfer(md, reg, buf, len, NULL, 0);
198+}
199+
200+static inline void acx565akm_read(struct acx565akm_device *md,
201+ int reg, u8 *buf, int len)
202+{
203+ acx565akm_transfer(md, reg, NULL, 0, buf, len);
204+}
205+
206+static void hw_guard_start(struct acx565akm_device *md, int guard_msec)
207+{
208+ md->hw_guard_wait = msecs_to_jiffies(guard_msec);
209+ md->hw_guard_end = jiffies + md->hw_guard_wait;
210+}
211+
212+static void hw_guard_wait(struct acx565akm_device *md)
213+{
214+ unsigned long wait = md->hw_guard_end - jiffies;
215+
216+ if ((long)wait > 0 && wait <= md->hw_guard_wait) {
217+ set_current_state(TASK_UNINTERRUPTIBLE);
218+ schedule_timeout(wait);
219+ }
220+}
221+
222+/*----------------------MIPID wrappers----------------------------*/
223+
224+static void set_sleep_mode(struct acx565akm_device *md, int on)
225+{
226+ int cmd;
227+
228+ if (on)
229+ cmd = MIPID_CMD_SLEEP_IN;
230+ else
231+ cmd = MIPID_CMD_SLEEP_OUT;
232+ /*
233+ * We have to keep 120msec between sleep in/out commands.
234+ * (8.2.15, 8.2.16).
235+ */
236+ hw_guard_wait(md);
237+ acx565akm_cmd(md, cmd);
238+ hw_guard_start(md, 120);
239+}
240+
241+static void set_display_state(struct acx565akm_device *md, int enabled)
242+{
243+ int cmd = enabled ? MIPID_CMD_DISP_ON : MIPID_CMD_DISP_OFF;
244+
245+ acx565akm_cmd(md, cmd);
246+}
247+
248+static int panel_enabled(struct acx565akm_device *md)
249+{
250+ u32 disp_status;
251+ int enabled;
252+
253+ acx565akm_read(md, MIPID_CMD_READ_DISP_STATUS, (u8 *)&disp_status, 4);
254+ disp_status = __be32_to_cpu(disp_status);
255+ enabled = (disp_status & (1 << 17)) && (disp_status & (1 << 10));
256+ dev_dbg(&md->spi->dev,
257+ "LCD panel %senabled by bootloader (status 0x%04x)\n",
258+ enabled ? "" : "not ", disp_status);
259+ return enabled;
260+}
261+
262+static int panel_detect(struct acx565akm_device *md)
263+{
264+ acx565akm_read(md, MIPID_CMD_READ_DISP_ID, md->display_id, 3);
265+ dev_dbg(&md->spi->dev, "MIPI display ID: %02x%02x%02x\n",
266+ md->display_id[0], md->display_id[1], md->display_id[2]);
267+
268+ switch (md->display_id[0]) {
269+ case 0x10:
270+ md->model = MIPID_VER_ACX565AKM;
271+ md->name = "acx565akm";
272+ md->has_bc = 1;
273+ md->has_cabc = 1;
274+ break;
275+ case 0x29:
276+ md->model = MIPID_VER_L4F00311;
277+ md->name = "l4f00311";
278+ break;
279+ case 0x45:
280+ md->model = MIPID_VER_LPH8923;
281+ md->name = "lph8923";
282+ break;
283+ case 0x83:
284+ md->model = MIPID_VER_LS041Y3;
285+ md->name = "ls041y3";
286+ break;
287+ default:
288+ md->name = "unknown";
289+ dev_err(&md->spi->dev, "invalid display ID\n");
290+ return -ENODEV;
291+ }
292+
293+ md->revision = md->display_id[1];
294+
295+ dev_info(&md->spi->dev, "omapfb: %s rev %02x LCD detected\n",
296+ md->name, md->revision);
297+
298+ return 0;
299+}
300+
301+/*----------------------Backlight Control-------------------------*/
302+
303+static void enable_backlight_ctrl(struct acx565akm_device *md, int enable)
304+{
305+ u16 ctrl;
306+
307+ acx565akm_read(md, MIPID_CMD_READ_CTRL_DISP, (u8 *)&ctrl, 1);
308+ if (enable) {
309+ ctrl |= CTRL_DISP_BRIGHTNESS_CTRL_ON |
310+ CTRL_DISP_BACKLIGHT_ON;
311+ } else {
312+ ctrl &= ~(CTRL_DISP_BRIGHTNESS_CTRL_ON |
313+ CTRL_DISP_BACKLIGHT_ON);
314+ }
315+
316+ ctrl |= 1 << 8;
317+ acx565akm_write(md, MIPID_CMD_WRITE_CTRL_DISP, (u8 *)&ctrl, 2);
318+}
319+
320+static void set_cabc_mode(struct acx565akm_device *md, unsigned mode)
321+{
322+ u16 cabc_ctrl;
323+
324+ md->cabc_mode = mode;
325+ if (!md->enabled)
326+ return;
327+ cabc_ctrl = 0;
328+ acx565akm_read(md, MIPID_CMD_READ_CABC, (u8 *)&cabc_ctrl, 1);
329+ cabc_ctrl &= ~3;
330+ cabc_ctrl |= (1 << 8) | (mode & 3);
331+ acx565akm_write(md, MIPID_CMD_WRITE_CABC, (u8 *)&cabc_ctrl, 2);
332+}
333+
334+static unsigned get_cabc_mode(struct acx565akm_device *md)
335+{
336+ return md->cabc_mode;
337+}
338+
339+static unsigned get_hw_cabc_mode(struct acx565akm_device *md)
340+{
341+ u8 cabc_ctrl;
342+
343+ acx565akm_read(md, MIPID_CMD_READ_CABC, &cabc_ctrl, 1);
344+ return cabc_ctrl & 3;
345+}
346+
347+static void acx565akm_set_brightness(struct acx565akm_device *md, int level)
348+{
349+ int bv;
350+
351+ bv = level | (1 << 8);
352+ acx565akm_write(md, MIPID_CMD_WRITE_DISP_BRIGHTNESS, (u8 *)&bv, 2);
353+
354+ if (level)
355+ enable_backlight_ctrl(md, 1);
356+ else
357+ enable_backlight_ctrl(md, 0);
358+}
359+
360+static int acx565akm_get_actual_brightness(struct acx565akm_device *md)
361+{
362+ u8 bv;
363+
364+ acx565akm_read(md, MIPID_CMD_READ_DISP_BRIGHTNESS, &bv, 1);
365+
366+ return bv;
367+}
368+
369+
370+static int acx565akm_bl_update_status(struct backlight_device *dev)
371+{
372+ struct acx565akm_device *md = dev_get_drvdata(&dev->dev);
373+ int r;
374+ int level;
375+
376+ dev_dbg(&md->spi->dev, "%s\n", __func__);
377+
378+ mutex_lock(&md->mutex);
379+
380+ if (dev->props.fb_blank == FB_BLANK_UNBLANK &&
381+ dev->props.power == FB_BLANK_UNBLANK)
382+ level = dev->props.brightness;
383+ else
384+ level = 0;
385+
386+ r = 0;
387+ if (md->has_bc)
388+ acx565akm_set_brightness(md, level);
389+ else if (md->dssdev->set_backlight)
390+ r = md->dssdev->set_backlight(md->dssdev, level);
391+ else
392+ r = -ENODEV;
393+
394+ mutex_unlock(&md->mutex);
395+
396+ return r;
397+}
398+
399+static int acx565akm_bl_get_intensity(struct backlight_device *dev)
400+{
401+ struct acx565akm_device *md = dev_get_drvdata(&dev->dev);
402+
403+ dev_dbg(&dev->dev, "%s\n", __func__);
404+
405+ if (!md->has_bc && md->dssdev->set_backlight == NULL)
406+ return -ENODEV;
407+
408+ if (dev->props.fb_blank == FB_BLANK_UNBLANK &&
409+ dev->props.power == FB_BLANK_UNBLANK) {
410+ if (md->has_bc)
411+ return acx565akm_get_actual_brightness(md);
412+ else
413+ return dev->props.brightness;
414+ }
415+
416+ return 0;
417+}
418+
419+static struct backlight_ops acx565akm_bl_ops = {
420+ .get_brightness = acx565akm_bl_get_intensity,
421+ .update_status = acx565akm_bl_update_status,
422+};
423+
424+/*--------------------Auto Brightness control via Sysfs---------------------*/
425+
426+static const char *cabc_modes[] = {
427+ "off", /* always used when CABC is not supported */
428+ "ui",
429+ "still-image",
430+ "moving-image",
431+};
432+
433+static ssize_t show_cabc_mode(struct device *dev,
434+ struct device_attribute *attr,
435+ char *buf)
436+{
437+ struct acx565akm_device *md = dev_get_drvdata(dev);
438+ const char *mode_str;
439+ int mode;
440+ int len;
441+
442+ if (!md->has_cabc)
443+ mode = 0;
444+ else
445+ mode = get_cabc_mode(md);
446+ mode_str = "unknown";
447+ if (mode >= 0 && mode < ARRAY_SIZE(cabc_modes))
448+ mode_str = cabc_modes[mode];
449+ len = snprintf(buf, PAGE_SIZE, "%s\n", mode_str);
450+
451+ return len < PAGE_SIZE - 1 ? len : PAGE_SIZE - 1;
452+}
453+
454+static ssize_t store_cabc_mode(struct device *dev,
455+ struct device_attribute *attr,
456+ const char *buf, size_t count)
457+{
458+ struct acx565akm_device *md = dev_get_drvdata(dev);
459+ int i;
460+
461+ for (i = 0; i < ARRAY_SIZE(cabc_modes); i++) {
462+ const char *mode_str = cabc_modes[i];
463+ int cmp_len = strlen(mode_str);
464+
465+ if (count > 0 && buf[count - 1] == '\n')
466+ count--;
467+ if (count != cmp_len)
468+ continue;
469+
470+ if (strncmp(buf, mode_str, cmp_len) == 0)
471+ break;
472+ }
473+
474+ if (i == ARRAY_SIZE(cabc_modes))
475+ return -EINVAL;
476+
477+ if (!md->has_cabc && i != 0)
478+ return -EINVAL;
479+
480+ mutex_lock(&md->mutex);
481+ set_cabc_mode(md, i);
482+ mutex_unlock(&md->mutex);
483+
484+ return count;
485+}
486+
487+static ssize_t show_cabc_available_modes(struct device *dev,
488+ struct device_attribute *attr,
489+ char *buf)
490+{
491+ struct acx565akm_device *md = dev_get_drvdata(dev);
492+ int len;
493+ int i;
494+
495+ if (!md->has_cabc)
496+ return snprintf(buf, PAGE_SIZE, "%s\n", cabc_modes[0]);
497+
498+ for (i = 0, len = 0;
499+ len < PAGE_SIZE && i < ARRAY_SIZE(cabc_modes); i++)
500+ len += snprintf(&buf[len], PAGE_SIZE - len, "%s%s%s",
501+ i ? " " : "", cabc_modes[i],
502+ i == ARRAY_SIZE(cabc_modes) - 1 ? "\n" : "");
503+
504+ return len < PAGE_SIZE ? len : PAGE_SIZE - 1;
505+}
506+
507+static DEVICE_ATTR(cabc_mode, S_IRUGO | S_IWUSR,
508+ show_cabc_mode, store_cabc_mode);
509+static DEVICE_ATTR(cabc_available_modes, S_IRUGO,
510+ show_cabc_available_modes, NULL);
511+
512+static struct attribute *bldev_attrs[] = {
513+ &dev_attr_cabc_mode.attr,
514+ &dev_attr_cabc_available_modes.attr,
515+ NULL,
516+};
517+
518+static struct attribute_group bldev_attr_group = {
519+ .attrs = bldev_attrs,
520+};
521+
522+/*---------------------------ACX Panel----------------------------*/
523+
524+static struct omap_video_timings acx_panel_timings = {
525+ .x_res = 800,
526+ .y_res = 480,
527+ .pixel_clock = 24000,
528+ .hfp = 28,
529+ .hsw = 4,
530+ .hbp = 24,
531+ .vfp = 3,
532+ .vsw = 3,
533+ .vbp = 4,
534+};
535+
536+static int acx_panel_probe(struct omap_dss_device *dssdev)
537+{
538+ int r;
539+ struct acx565akm_device *md = &acx_dev;
540+ struct backlight_device *bldev;
541+ int max_brightness, brightness;
542+
543+ dev_dbg(&dssdev->dev, "%s\n", __func__);
544+ dssdev->panel.config = OMAP_DSS_LCD_TFT | OMAP_DSS_LCD_IVS |
545+ OMAP_DSS_LCD_IHS;
546+ /* FIXME AC bias ? */
547+ dssdev->panel.timings = acx_panel_timings;
548+ dssdev->panel.recommended_bpp = 16;
549+
550+ if (dssdev->platform_enable)
551+ dssdev->platform_enable(dssdev);
552+ /*
553+ * After reset we have to wait 5 msec before the first
554+ * command can be sent.
555+ */
556+ msleep(5);
557+
558+ md->enabled = panel_enabled(md);
559+
560+ r = panel_detect(md);
561+ if (r) {
562+ dev_err(&dssdev->dev, "%s panel detect error\n", __func__);
563+ if (!md->enabled && dssdev->platform_disable)
564+ dssdev->platform_disable(dssdev);
565+ return r;
566+ }
567+
568+ mutex_lock(&acx_dev.mutex);
569+ acx_dev.dssdev = dssdev;
570+ mutex_unlock(&acx_dev.mutex);
571+
572+ if (!md->enabled) {
573+ if (dssdev->platform_disable)
574+ dssdev->platform_disable(dssdev);
575+ }
576+
577+ /*------- Backlight control --------*/
578+
579+ bldev = backlight_device_register("acx565akm", &md->spi->dev,
580+ md, &acx565akm_bl_ops);
581+ md->bl_dev = bldev;
582+ if (md->has_cabc) {
583+ r = sysfs_create_group(&bldev->dev.kobj, &bldev_attr_group);
584+ if (r) {
585+ dev_err(&bldev->dev,
586+ "%s failed to create sysfs files\n", __func__);
587+ backlight_device_unregister(bldev);
588+ return r;
589+ }
590+ md->cabc_mode = get_hw_cabc_mode(md);
591+ }
592+
593+ bldev->props.fb_blank = FB_BLANK_UNBLANK;
594+ bldev->props.power = FB_BLANK_UNBLANK;
595+
596+ if (md->has_bc)
597+ max_brightness = 255;
598+ else
599+ max_brightness = dssdev->max_backlight_level;
600+
601+ if (md->has_bc)
602+ brightness = acx565akm_get_actual_brightness(md);
603+ else if (dssdev->get_backlight)
604+ brightness = dssdev->get_backlight(dssdev);
605+ else
606+ brightness = 0;
607+
608+ bldev->props.max_brightness = max_brightness;
609+ bldev->props.brightness = brightness;
610+
611+ acx565akm_bl_update_status(bldev);
612+ return 0;
613+}
614+
615+static void acx_panel_remove(struct omap_dss_device *dssdev)
616+{
617+ struct acx565akm_device *md = &acx_dev;
618+
619+ dev_dbg(&dssdev->dev, "%s\n", __func__);
620+ sysfs_remove_group(&md->bl_dev->dev.kobj, &bldev_attr_group);
621+ backlight_device_unregister(md->bl_dev);
622+ mutex_lock(&acx_dev.mutex);
623+ acx_dev.dssdev = NULL;
624+ mutex_unlock(&acx_dev.mutex);
625+}
626+
627+static int acx_panel_power_on(struct omap_dss_device *dssdev)
628+{
629+ struct acx565akm_device *md = &acx_dev;
630+ int r;
631+
632+ dev_dbg(&dssdev->dev, "%s\n", __func__);
633+
634+ mutex_lock(&md->mutex);
635+
636+ if (dssdev->platform_enable) {
637+ r = dssdev->platform_enable(dssdev);
638+ if (r)
639+ return r;
640+ }
641+
642+ if (md->enabled) {
643+ dev_dbg(&md->spi->dev, "panel already enabled\n");
644+ mutex_unlock(&md->mutex);
645+ return 0;
646+ }
647+
648+ /*
649+ * We have to meet all the following delay requirements:
650+ * 1. tRW: reset pulse width 10usec (7.12.1)
651+ * 2. tRT: reset cancel time 5msec (7.12.1)
652+ * 3. Providing PCLK,HS,VS signals for 2 frames = ~50msec worst
653+ * case (7.6.2)
654+ * 4. 120msec before the sleep out command (7.12.1)
655+ */
656+ msleep(120);
657+
658+ set_sleep_mode(md, 0);
659+ md->enabled = 1;
660+
661+ /* 5msec between sleep out and the next command. (8.2.16) */
662+ msleep(5);
663+ set_display_state(md, 1);
664+ set_cabc_mode(md, md->cabc_mode);
665+
666+ mutex_unlock(&md->mutex);
667+
668+ return acx565akm_bl_update_status(md->bl_dev);
669+}
670+
671+static void acx_panel_power_off(struct omap_dss_device *dssdev)
672+{
673+ struct acx565akm_device *md = &acx_dev;
674+
675+ dev_dbg(&dssdev->dev, "%s\n", __func__);
676+
677+ mutex_lock(&md->mutex);
678+
679+ if (!md->enabled) {
680+ mutex_unlock(&md->mutex);
681+ return;
682+ }
683+ set_display_state(md, 0);
684+ set_sleep_mode(md, 1);
685+ md->enabled = 0;
686+ /*
687+ * We have to provide PCLK,HS,VS signals for 2 frames (worst case
688+ * ~50msec) after sending the sleep in command and asserting the
689+ * reset signal. We probably could assert the reset w/o the delay
690+ * but we still delay to avoid possible artifacts. (7.6.1)
691+ */
692+ msleep(50);
693+
694+ if (dssdev->platform_disable)
695+ dssdev->platform_disable(dssdev);
696+
697+ mutex_unlock(&md->mutex);
698+}
699+
700+static int acx_panel_enable(struct omap_dss_device *dssdev)
701+{
702+ int r;
703+
704+ dev_dbg(&dssdev->dev, "%s\n", __func__);
705+ r = acx_panel_power_on(dssdev);
706+
707+ if (r)
708+ return r;
709+
710+ dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
711+ return 0;
712+}
713+
714+static void acx_panel_disable(struct omap_dss_device *dssdev)
715+{
716+ dev_dbg(&dssdev->dev, "%s\n", __func__);
717+ acx_panel_power_off(dssdev);
718+ dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
719+}
720+
721+static int acx_panel_suspend(struct omap_dss_device *dssdev)
722+{
723+ dev_dbg(&dssdev->dev, "%s\n", __func__);
724+ acx_panel_power_off(dssdev);
725+ dssdev->state = OMAP_DSS_DISPLAY_SUSPENDED;
726+ return 0;
727+}
728+
729+static int acx_panel_resume(struct omap_dss_device *dssdev)
730+{
731+ int r;
732+
733+ dev_dbg(&dssdev->dev, "%s\n", __func__);
734+ r = acx_panel_power_on(dssdev);
735+ if (r)
736+ return r;
737+
738+ dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
739+ return 0;
740+}
741+
742+static struct omap_dss_driver acx_panel_driver = {
743+ .probe = acx_panel_probe,
744+ .remove = acx_panel_remove,
745+
746+ .enable = acx_panel_enable,
747+ .disable = acx_panel_disable,
748+ .suspend = acx_panel_suspend,
749+ .resume = acx_panel_resume,
750+
751+ .driver = {
752+ .name = "panel-acx565akm",
753+ .owner = THIS_MODULE,
754+ },
755+};
756+
757+/*--------------------SPI probe-------------------------*/
758+
759+static int acx565akm_spi_probe(struct spi_device *spi)
760+{
761+ struct acx565akm_device *md = &acx_dev;
762+
763+ dev_dbg(&spi->dev, "%s\n", __func__);
764+
765+ spi->mode = SPI_MODE_3;
766+ md->spi = spi;
767+ mutex_init(&md->mutex);
768+ dev_set_drvdata(&spi->dev, md);
769+
770+ omap_dss_register_driver(&acx_panel_driver);
771+
772+ return 0;
773+}
774+
775+static int acx565akm_spi_remove(struct spi_device *spi)
776+{
777+ struct acx565akm_device *md = dev_get_drvdata(&spi->dev);
778+
779+ dev_dbg(&md->spi->dev, "%s\n", __func__);
780+ omap_dss_unregister_driver(&acx_panel_driver);
781+
782+ return 0;
783+}
784+
785+static struct spi_driver acx565akm_spi_driver = {
786+ .driver = {
787+ .name = "acx565akm",
788+ .bus = &spi_bus_type,
789+ .owner = THIS_MODULE,
790+ },
791+ .probe = acx565akm_spi_probe,
792+ .remove = __devexit_p(acx565akm_spi_remove),
793+};
794+
795+static int __init acx565akm_init(void)
796+{
797+ return spi_register_driver(&acx565akm_spi_driver);
798+}
799+
800+static void __exit acx565akm_exit(void)
801+{
802+ spi_unregister_driver(&acx565akm_spi_driver);
803+}
804+
805+module_init(acx565akm_init);
806+module_exit(acx565akm_exit);
807+
808+MODULE_AUTHOR("Nokia Corporation");
809+MODULE_DESCRIPTION("acx565akm LCD Driver");
810+MODULE_LICENSE("GPL");
811--
8121.6.0.4
813