PATCH: Add the OLPC DCON to the backlight infrastructure
Jordan Crouse
jordan.crouse at amd.com
Tue Nov 7 22:37:11 EST 2006
Commit: 89ca0c5a674fcf78fd87bb541e75ae3139422ecb
Parent: 75588273ae499a26d01f6a0a828306b1cb5d34c3
commit 89ca0c5a674fcf78fd87bb541e75ae3139422ecb
Author: Jordan Crouse <jordan.crouse at amd.com>
AuthorDate: Mon Oct 2 10:40:53 2006 -0600
Commit: Jordan Crouse <jordan.crouse at amd.com>
CommitDate: Tue Oct 3 13:49:02 2006 -0600
PATCH: Add the OLPC DCON to the backlight infrastructure
---
drivers/video/backlight/Kconfig | 7 +++
drivers/video/backlight/Makefile | 1
drivers/video/backlight/dcon_bl.c | 88 ++++++++++++++++++++++++++++++++++++
drivers/video/geode/gxfb_dcon.c | 91 ++++++++++++++++++++++++++++++++-----
drivers/video/geode/gxfb_dcon.h | 8 +++
5 files changed, 183 insertions(+), 12 deletions(-)
diff --git a/drivers/video/backlight/Kconfig b/drivers/video/backlight/Kconfig
index 022f9d3..81870cd 100644
--- a/drivers/video/backlight/Kconfig
+++ b/drivers/video/backlight/Kconfig
@@ -66,3 +66,10 @@ config BACKLIGHT_HP680
If you have a HP Jornada 680, say y to enable the
backlight driver.
+config BACKLIGHT_DCON
+ tristate "OLPC DCON Backlight Driver"
+ depends on BACKLIGHT_DEVICE && FB_GEODE_GX_DCON
+ default y
+ help
+ Enable the backlight driver for the OLPC Display CONtroller
+
diff --git a/drivers/video/backlight/Makefile b/drivers/video/backlight/Makefile
index 65e5553..c39f221 100644
--- a/drivers/video/backlight/Makefile
+++ b/drivers/video/backlight/Makefile
@@ -5,3 +5,4 @@ obj-$(CONFIG_BACKLIGHT_CLASS_DEVICE) +=
obj-$(CONFIG_BACKLIGHT_CORGI) += corgi_bl.o
obj-$(CONFIG_BACKLIGHT_HP680) += hp680_bl.o
obj-$(CONFIG_BACKLIGHT_LOCOMO) += locomolcd.o
+obj-$(CONFIG_BACKLIGHT_DCON) += dcon_bl.o
diff --git a/drivers/video/backlight/dcon_bl.c b/drivers/video/backlight/dcon_bl.c
new file mode 100644
index 0000000..d356c36
--- /dev/null
+++ b/drivers/video/backlight/dcon_bl.c
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2006 Advanced Micro Devices, Inc.
+ *
+ * This program is free software. You can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation: either version 1 or
+ * (at your option) any later version.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/err.h>
+#include <linux/fb.h>
+#include <linux/platform_device.h>
+#include <linux/backlight.h>
+#include "../geode/gxfb_dcon.h"
+
+static struct backlight_device *dconbl_dev;
+
+static int dconbl_set(struct backlight_device *dev) {
+
+ int level = dev->props->brightness;
+ int power = dev->props->power;
+
+ /* If we are blanking, then just turn off the backlight all together */
+
+ if (power != FB_BLANK_UNBLANK)
+ level = 0;
+
+ gxfb_dcon_setbl(level);
+ return 0;
+}
+
+static int dconbl_get(struct backlight_device *dev) {
+ return gxfb_dcon_getbl();
+}
+
+static struct backlight_properties dcon_data = {
+ .owner = THIS_MODULE,
+ .get_brightness = dconbl_get,
+ .update_status = dconbl_set,
+ .max_brightness = 15
+};
+
+static int dconbl_probe(struct platform_device *dev)
+{
+ dconbl_dev = backlight_device_register("dcon-bl", NULL, &dcon_data);
+
+ if (IS_ERR(dconbl_dev))
+ return PTR_ERR(dconbl_dev);
+
+ dcon_data.brightness = gxfb_dcon_getbl();
+ return 0;
+}
+
+static int dconbl_remove(struct platform_device *dev)
+{
+ backlight_device_unregister(dconbl_dev);
+ return 0;
+}
+
+/* Note: We dont define suspend and resume functions here -
+ we cannot assume the user wanted the backlight to be changed
+ while in the suspended mode
+*/
+
+static struct platform_driver dconbl_driver = {
+ .probe = dconbl_probe,
+ .remove = dconbl_remove,
+ .driver = {
+ .name = "dcon-bl"
+ }
+};
+
+static int __init dconbl_init(void) {
+ return platform_driver_register(&dconbl_driver);
+}
+
+static void __exit dconbl_exit(void) {
+ platform_driver_unregister(&dconbl_driver);
+}
+
+module_init(dconbl_init);
+module_exit(dconbl_exit);
+
+MODULE_AUTHOR("Advanced Micro Devices, Inc.");
+MODULE_DESCRIPTION("OLPC DCON backlight Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/video/geode/gxfb_dcon.c b/drivers/video/geode/gxfb_dcon.c
index e1eed59..ec1489a 100644
--- a/drivers/video/geode/gxfb_dcon.c
+++ b/drivers/video/geode/gxfb_dcon.c
@@ -14,6 +14,7 @@ #include <linux/kernel.h>
#include <linux/fb.h>
#include "geodefb.h"
#include <linux/i2c.h>
+#include <linux/platform_device.h>
#include <linux/i2c-id.h>
#include <linux/interrupt.h>
#include <linux/delay.h>
@@ -45,6 +46,9 @@ #define DCONIOC_GETBL _IOW('d'
static struct i2c_driver dcon_driver;
static struct i2c_client *dcon_client;
+/* Platform devices */
+static struct platform_device *dcon_bl_dev;
+
/* Base address of the GPIO registers */
static unsigned long gpio_base;
@@ -66,10 +70,58 @@ extern unsigned long gxfb_dc_regs;
extern int gxfb_powerdown(struct fb_info *info);
extern int gxfb_powerup(struct fb_info *info);
+
+#define dcon_write(reg,val) i2c_smbus_write_word_data(dcon_client,reg,val)
+#define dcon_read(reg) i2c_smbus_read_word_data(dcon_client,reg)
+
+/* ===== API functions - these are called by a variety of users ==== */
+
+static int gxfb_bl_val = -1;
+
+/* To cut down on SMBUS, we assume that getbl and setbl are the only entities that change the BL,
+ so we shadow the variable
+*/
+
+int gxfb_dcon_getbl(void) {
+
+ if (dcon_client == NULL)
+ return 0;
+
+ if (gxfb_bl_val == -1)
+ gxfb_bl_val = dcon_read(DCON_REG_BRIGHT) & 0x0F;
+
+ return (dcon_disp_mode & MODE_BL_ENABLE) ? gxfb_bl_val : 0;
+}
+
+void gxfb_dcon_setbl(int level) {
+
+ if (dcon_client == NULL)
+ return;
+
+ if (level == 0) {
+ if ((dcon_disp_mode & MODE_BL_ENABLE)) {
+ dcon_disp_mode &= ~MODE_BL_ENABLE;
+ dcon_write(DCON_REG_MODE, dcon_disp_mode);
+ }
+
+ return;
+ }
+
+ if (!(dcon_disp_mode & MODE_BL_ENABLE)) {
+ dcon_disp_mode |= MODE_BL_ENABLE;
+ dcon_write(DCON_REG_MODE, dcon_disp_mode);
+ }
+
+ gxfb_bl_val = level & 0x0F;
+ dcon_write(DCON_REG_BRIGHT, gxfb_bl_val);
+}
+
+EXPORT_SYMBOL(gxfb_dcon_getbl);
+EXPORT_SYMBOL(gxfb_dcon_setbl);
+
static int dcon_set_source(struct fb_info *info, int arg)
{
struct geodefb_par *par = info->par;
- unsigned long val;
if (dcon_source == arg)
return 0;
@@ -77,25 +129,24 @@ static int dcon_set_source(struct fb_inf
dcon_source = arg;
if (arg == DCON_SOURCE_CPU) {
- struct geodefb_par *par = info->par;
unsigned long timeo = jiffies + (10 * HZ);
unsigned long scanline1, scanline2;
/* Power up the graphics engine */
gxfb_powerup(info);
- /* Wait for up to a second for our output to coincide with
+ /* Wait for up to a second for our output to coincide with
DCON's */
-
+
while (time_before(jiffies, timeo)) {
- unsigned long dconblnk =
+ unsigned long dconblnk =
(inl(gpio_base + GPIOx_READ_BACK) >> 12) & 1;
- scanline1 =
+ scanline1 =
readl((void __iomem *)(gxfb_dc_regs + 0x6c));
scanline1 >>= 16;
scanline1 &= 0x7ff;
- if (!dconblnk && scanline1 >= resumeline &&
+ if (!dconblnk && scanline1 >= resumeline &&
scanline1 <= (resumeline+2))
goto ready;
@@ -242,12 +293,11 @@ static int gxfb_dcon_ioctl(struct fb_inf
karg = 0;
break;
- case DCONIOC_SETBL:
+ case DCONIOC_SETBL:
if (get_user(karg, (int __user *)arg))
return -EFAULT;
- i2c_smbus_write_word_data(dcon_client, DCON_REG_BRIGHT,
- karg & 0x0F);
+ gxfb_dcon_setbl(karg);
karg = 0;
break;
@@ -255,8 +305,7 @@ static int gxfb_dcon_ioctl(struct fb_inf
if (get_user(karg, (int __user *)arg))
return -EFAULT;
- val = i2c_smbus_read_word_data(dcon_client, DCON_REG_BRIGHT);
- karg = val & 0x0F;
+ karg = gxfb_dcon_getbl();
break;
default:
@@ -344,6 +393,21 @@ static int dcon_probe(struct i2c_adapter
i2c_smbus_write_word_data(client, 0x43, 0x0101);
}
+ /* Now create a backlight device on the platform bus - note that failures here are non fatal */
+
+ dcon_bl_dev = platform_device_alloc("dcon-bl", -1);
+
+ if (dcon_bl_dev == NULL) {
+ printk(KERN_INFO "gxfb-dcon: Couldn't allocate the BL device.\n");
+ return 0;
+ }
+
+ if (platform_device_add(dcon_bl_dev)) {
+ printk(KERN_INFO "gxfb-dcon: Couldn't attach the BL device.\n");
+ platform_device_put(dcon_bl_dev);
+ dcon_bl_dev = NULL;
+ }
+
return 0;
}
@@ -368,6 +432,9 @@ static int dcon_detach(struct i2c_client
if ((rc = i2c_detach_client(client)) == 0)
kfree(i2c_get_clientdata(client));
+ if (dcon_bl_dev != NULL)
+ platform_device_unregister(dcon_bl_dev);
+
return rc;
}
diff --git a/drivers/video/geode/gxfb_dcon.h b/drivers/video/geode/gxfb_dcon.h
index 31598e9..140f2f0 100644
--- a/drivers/video/geode/gxfb_dcon.h
+++ b/drivers/video/geode/gxfb_dcon.h
@@ -68,4 +68,12 @@ #define DCON_OUTPUT_MONO 1
/* Interrupt */
#define DCON_IRQ 6
+/* Functions available to the world */
+
+/* Set the backlight */
+void gxfb_dcon_setbl(int);
+
+/* Get the backlight value */
+int gxfb_dcon_getbl(void);
+
#endif
More information about the Commits-kernel
mailing list