PATCH: Add the OLPC DCON to the backlight infrastructure

Jordan Crouse jordan.crouse at amd.unroutablecom
Wed Nov 29 11:14:54 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