TPS6116x is an EasyScale backlight controller device.  This driver supports
TPS6116x devices connected on a single GPIO.

Signed-off-by: Cyril Chemparathy <[email protected]>
---
 drivers/video/backlight/Kconfig    |    7 +
 drivers/video/backlight/Makefile   |    2 +-
 drivers/video/backlight/tps6116x.c |  299 ++++++++++++++++++++++++++++++++++++
 3 files changed, 307 insertions(+), 1 deletions(-)
 create mode 100644 drivers/video/backlight/tps6116x.c

diff --git a/drivers/video/backlight/Kconfig b/drivers/video/backlight/Kconfig
index e54a337..06e868e 100644
--- a/drivers/video/backlight/Kconfig
+++ b/drivers/video/backlight/Kconfig
@@ -307,6 +307,13 @@ config BACKLIGHT_PCF50633
          If you have a backlight driven by a NXP PCF50633 MFD, say Y here to
          enable its driver.
 
+config BACKLIGHT_TPS6116X
+       tristate "TPS6116X LCD Backlight"
+       depends on GENERIC_GPIO
+       help
+         This driver controls the LCD backlight level for EasyScale capable
+         SSP connected backlight controllers.
+
 endif # BACKLIGHT_CLASS_DEVICE
 
 endif # BACKLIGHT_LCD_SUPPORT
diff --git a/drivers/video/backlight/Makefile b/drivers/video/backlight/Makefile
index 44c0f81..5d407c8 100644
--- a/drivers/video/backlight/Makefile
+++ b/drivers/video/backlight/Makefile
@@ -35,4 +35,4 @@ obj-$(CONFIG_BACKLIGHT_ADP5520)       += adp5520_bl.o
 obj-$(CONFIG_BACKLIGHT_ADP8860)        += adp8860_bl.o
 obj-$(CONFIG_BACKLIGHT_88PM860X) += 88pm860x_bl.o
 obj-$(CONFIG_BACKLIGHT_PCF50633)       += pcf50633-backlight.o
-
+obj-$(CONFIG_BACKLIGHT_TPS6116X)+= tps6116x.o
diff --git a/drivers/video/backlight/tps6116x.c 
b/drivers/video/backlight/tps6116x.c
new file mode 100644
index 0000000..7f846ab
--- /dev/null
+++ b/drivers/video/backlight/tps6116x.c
@@ -0,0 +1,299 @@
+/*
+ * TPS6116X LCD Backlight Controller Driver
+ *
+ * Copyright (C) 2010 Texas Instruments
+ *
+ * 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 version 2.
+ *
+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any kind,
+ * whether express or implied; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/fb.h>
+#include <linux/err.h>
+#include <linux/delay.h>
+#include <linux/gpio.h>
+#include <linux/backlight.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/consumer.h>
+
+#define TPS6116X_MAX_INTENSITY         31
+#define TPS6116X_DEFAULT_INTENSITY     10
+
+/* Easyscale timing w/ margin (usecs) */
+#define T_POWER_SETTLE                 2000
+#define T_ES_DELAY                     120
+#define T_ES_DETECT                    280
+#define T_ES_WINDOW                    (1000 - T_ES_DELAY - T_ES_DETECT)
+#define T_START                                3
+#define T_EOS                          3
+#define T_INACTIVE                     3
+#define T_ACTIVE                       (3 * T_INACTIVE)
+
+#define CMD_SET                                0x72
+
+struct tps6116x {
+       struct ti_ssp_device            *handle;
+       struct device                   *dev;
+       int                             gpio;
+       struct mutex                    lock;
+       int                             intensity;
+       struct backlight_properties     props;
+       struct backlight_device         *bl;
+       struct regulator                *regulator;
+       bool                            power;
+       bool                            suspended;
+};
+
+static int __set_power(struct tps6116x *hw, bool power)
+{
+       unsigned long flags;
+       int error;
+
+       if (power == hw->power)
+               return 0; /* nothing to do */
+
+       /* disabling is simple... choke power */
+       if (!power) {
+               error = regulator_disable(hw->regulator);
+               goto done;
+       }
+
+       /* set ctrl pin init state for easyscale detection */
+       gpio_set_value(hw->gpio, 0);
+
+       error = regulator_enable(hw->regulator);
+       if (error < 0)
+               goto done;
+
+       udelay(T_POWER_SETTLE);
+
+       /*
+        * Now that the controller is powered up, we need to put it into 1-wire
+        * mode.  This is a timing sensitive operation, hence the irq disable.
+        * Ideally, this should happen rarely, and mostly at init, so disabling
+        * interrupts for the duration should not be a problem.
+        */
+       local_irq_save(flags);
+
+       gpio_set_value(hw->gpio, 1);
+       udelay(T_ES_DELAY);
+       gpio_set_value(hw->gpio, 0);
+       udelay(T_ES_DETECT);
+       gpio_set_value(hw->gpio, 1);
+
+       local_irq_restore(flags);
+
+done:
+       if (error >= 0)
+               hw->power = power;
+
+       return error;
+}
+
+static void __write_byte(struct tps6116x *hw, u8 data)
+{
+       int bit;
+
+       gpio_set_value(hw->gpio, 1);
+       udelay(T_START);
+
+       for (bit = 0; bit < 8; bit++, data <<= 1) {
+               int val = data & 0x80;
+               int t_lo = val ? T_INACTIVE : T_ACTIVE;
+               int t_hi = val ? T_ACTIVE : T_INACTIVE;
+
+               gpio_set_value(hw->gpio, 0);
+               udelay(t_lo);
+               gpio_set_value(hw->gpio, 1);
+               udelay(t_hi);
+       }
+
+       gpio_set_value(hw->gpio, 0);
+       udelay(T_EOS);
+       gpio_set_value(hw->gpio, 1);
+}
+
+static void __set_intensity(struct tps6116x *hw, int intensity)
+{
+       unsigned long flags;
+
+       intensity = clamp(intensity, 0, TPS6116X_MAX_INTENSITY);
+
+       local_irq_save(flags);
+       __write_byte(hw, CMD_SET);
+       __write_byte(hw, intensity);
+       local_irq_restore(flags);
+}
+
+static int set_intensity(struct tps6116x *hw, int intensity)
+{
+       int error = 0;
+
+       if (intensity == hw->intensity)
+               return 0;
+
+       mutex_lock(&hw->lock);
+
+       error = __set_power(hw, intensity ? true : false);
+       if (error < 0)
+               goto error;
+
+       if (intensity > 0)
+               __set_intensity(hw, intensity);
+
+       hw->intensity = intensity;
+error:
+       mutex_unlock(&hw->lock);
+
+       return error;
+}
+
+static int get_brightness(struct backlight_device *bl)
+{
+       struct tps6116x *hw = bl_get_data(bl);
+
+       return hw->intensity;
+}
+
+static int update_status(struct backlight_device *bl)
+{
+       struct tps6116x *hw = bl_get_data(bl);
+       int intensity = bl->props.brightness;
+
+       if (hw->suspended || hw->props.state & BL_CORE_SUSPENDED)
+               intensity = 0;
+       if (bl->props.power != FB_BLANK_UNBLANK)
+               intensity = 0;
+       if (bl->props.fb_blank != FB_BLANK_UNBLANK)
+               intensity = 0;
+
+       return set_intensity(hw, intensity);
+}
+
+static const struct backlight_ops tps6116x_backlight_ops = {
+       .options        = BL_CORE_SUSPENDRESUME,
+       .get_brightness = get_brightness,
+       .update_status  = update_status,
+};
+
+static int __devinit tps6116x_probe(struct platform_device *pdev)
+{
+       struct tps6116x *hw;
+       struct device *dev = &pdev->dev;
+       struct backlight_properties props;
+       int error;
+
+       hw = kzalloc(sizeof(struct tps6116x), GFP_KERNEL);
+       if (!hw) {
+               dev_err(dev, "cannot allocate driver data\n");
+               return -ENOMEM;
+       }
+       platform_set_drvdata(pdev, hw);
+
+       hw->gpio = (int)dev->platform_data;
+       hw->dev = dev;
+
+       mutex_init(&hw->lock);
+
+       hw->regulator = regulator_get(dev, "vlcd");
+       if (IS_ERR(hw->regulator)) {
+               error = PTR_ERR(hw->regulator);
+               dev_err(dev, "cannot claim regulator\n");
+               goto error_regulator;
+       }
+
+       error = gpio_request_one(hw->gpio, GPIOF_DIR_OUT, dev_name(dev));
+       if (error < 0) {
+               dev_err(dev, "cannot claim gpio\n");
+               goto error_gpio;
+       }
+
+       memset(&props, 0, sizeof(props));
+       props.max_brightness = TPS6116X_MAX_INTENSITY;
+       props.brightness     = TPS6116X_DEFAULT_INTENSITY;
+       props.power          = FB_BLANK_UNBLANK;
+
+       hw->bl = backlight_device_register("tps6116x", hw->dev, hw,
+                                          &tps6116x_backlight_ops, &props);
+       if (IS_ERR(hw->bl)) {
+               error = PTR_ERR(hw->bl);
+               dev_err(dev, "backlight registration failed\n");
+               goto error_register;
+       }
+
+       update_status(hw->bl);
+       dev_info(dev, "registered backlight controller\n");
+       return 0;
+
+error_register:
+       gpio_free(hw->gpio);
+error_gpio:
+       regulator_put(hw->regulator);
+error_regulator:
+       kfree(hw);
+       platform_set_drvdata(pdev, NULL);
+       return error;
+}
+
+static int __devexit tps6116x_remove(struct platform_device *pdev)
+{
+       struct tps6116x *hw = platform_get_drvdata(pdev);
+
+       backlight_device_unregister(hw->bl);
+       regulator_disable(hw->regulator);
+       regulator_put(hw->regulator);
+       gpio_free(hw->gpio);
+       kfree(hw);
+       platform_set_drvdata(pdev, NULL);
+       return 0;
+}
+
+static int tps6116x_suspend(struct platform_device *pdev, pm_message_t state)
+{
+       struct tps6116x *hw = platform_get_drvdata(pdev);
+       hw->suspended = true;
+       update_status(hw->bl);
+       return 0;
+}
+
+static int tps6116x_resume(struct platform_device *pdev)
+{
+       struct tps6116x *hw = platform_get_drvdata(pdev);
+       hw->suspended = false;
+       update_status(hw->bl);
+       return 0;
+}
+
+static struct platform_driver tps6116x_driver = {
+       .probe          = tps6116x_probe,
+       .remove         = __devexit_p(tps6116x_remove),
+       .suspend        = tps6116x_suspend,
+       .resume         = tps6116x_resume,
+       .driver         = {
+               .name   = "tps6116x",
+               .owner  = THIS_MODULE,
+       },
+};
+
+static int __init tps6116x_init(void)
+{
+       return platform_driver_register(&tps6116x_driver);
+}
+module_init(tps6116x_init);
+
+static void __exit tps6116x_exit(void)
+{
+       platform_driver_unregister(&tps6116x_driver);
+}
+module_exit(tps6116x_exit);
+
+MODULE_DESCRIPTION("SSP TPS6116X Driver");
+MODULE_AUTHOR("Cyril Chemparathy");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:tps6116x");
-- 
1.7.1


------------------------------------------------------------------------------
Protect Your Site and Customers from Malware Attacks
Learn about various malware tactics and how to avoid them. Understand 
malware threats, the impact they can have on your business, and how you 
can protect your company and customers by using code signing.
http://p.sf.net/sfu/oracle-sfdevnl
_______________________________________________
spi-devel-general mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/spi-devel-general

Reply via email to