From: "Ying-Chun Liu (PaulLiu)" <paul....@linaro.org>

Add DA9052 video backlight driver from Dialog.
Modify Kconfig/Makefile for DA9052 video backlight driver.

Signed-off-by: Zhou Jingyu <jingyu.z...@freescale.com>
Acked-by: Lily Zhang <r58...@freescale.com>
Signed-off-by: Ying-Chun Liu (PaulLiu) <paul....@linaro.org>
---
 drivers/video/backlight/Kconfig     |    6 +
 drivers/video/backlight/Makefile    |    2 +-
 drivers/video/backlight/da9052_bl.c |  461 +++++++++++++++++++++++++++++++++++
 3 files changed, 468 insertions(+), 1 deletions(-)
 create mode 100644 drivers/video/backlight/da9052_bl.c

diff --git a/drivers/video/backlight/Kconfig b/drivers/video/backlight/Kconfig
index 0c9373b..a233749 100644
--- a/drivers/video/backlight/Kconfig
+++ b/drivers/video/backlight/Kconfig
@@ -315,6 +315,12 @@ config BACKLIGHT_PCF50633
          If you have a backlight driven by a NXP PCF50633 MFD, say Y here to
          enable its driver.
 
+config BACKLIGHT_DA9052
+       tristate "Dialog DA9052 WLED"
+       depends on PMIC_DIALOG
+       help
+         Enable the DA9052 Backlight Driver
+
 endif # BACKLIGHT_CLASS_DEVICE
 
 endif # BACKLIGHT_LCD_SUPPORT
diff --git a/drivers/video/backlight/Makefile b/drivers/video/backlight/Makefile
index b9ca849..0c8334f 100644
--- a/drivers/video/backlight/Makefile
+++ b/drivers/video/backlight/Makefile
@@ -36,4 +36,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_DA9052) += da9052_bl.o
diff --git a/drivers/video/backlight/da9052_bl.c 
b/drivers/video/backlight/da9052_bl.c
new file mode 100644
index 0000000..0692194
--- /dev/null
+++ b/drivers/video/backlight/da9052_bl.c
@@ -0,0 +1,461 @@
+/*
+ * Copyright(c) 2009 Dialog Semiconductor Ltd.
+ *
+ * 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 2 of the License, or
+ * (at your option) any later version.
+ *
+ * da9052_bl.c: Backlight driver for DA9052
+ */
+
+#include <linux/platform_device.h>
+#include <linux/fb.h>
+#include <linux/backlight.h>
+
+#include <linux/delay.h>
+
+#include <linux/mfd/da9052/da9052.h>
+#include <linux/mfd/da9052/reg.h>
+#include <linux/mfd/da9052/bl.h>
+
+
+#define DRIVER_NAME            "da9052-backlight"
+#define DRIVER_NAME1           "WLED-1"
+#define DRIVER_NAME2           "WLED-2"
+#define DRIVER_NAME3           "WLED-3"
+
+/* These flags define if Backlight LEDs are present */
+/* Set the following macros to 1, if LEDs are present. Otherwise set to 0 */
+#define DA9052_LED1_PRESENT    1
+#define DA9052_LED2_PRESENT    1
+#define DA9052_LED3_PRESENT    1
+
+#define DA9052_MAX_BRIGHTNESS  0xFF
+
+struct da9052_backlight_data {
+       struct device *da9052_dev;
+       int current_brightness;
+       struct da9052 *da9052;
+
+       int is_led1_present;
+       int is_led2_present;
+       int is_led3_present;
+};
+
+enum da9052_led_number {
+       LED1 = 1,
+       LED2,
+       LED3,
+};
+
+static int da9052_backlight_brightness_set(struct da9052_backlight_data *data,
+                       int brightness, enum da9052_led_number led)
+{
+       /*
+        * Mechanism for brightness control:
+        * For brightness control, current is used.
+        * PWM feature is not used.
+        * To use PWM feature, a fixed value of current should be defined.
+        */
+
+       int ret = 0;
+       unsigned int led_ramp_bit;
+       unsigned int led_current_register;
+       unsigned int led_current_sink_bit;
+       unsigned int led_boost_en_bit;
+       struct da9052_ssc_msg msg;
+
+       switch (led) {
+       case LED1:
+               led_ramp_bit = DA9052_LEDCONT_LED1RAMP;
+               led_current_register = DA9052_LED1CONF_REG;
+               led_current_sink_bit = DA9052_LEDCONT_LED1EN;
+               led_boost_en_bit = DA9052_BOOST_LED1INEN;
+       break;
+       case LED2:
+               led_ramp_bit = DA9052_LEDCONT_LED2RAMP;
+               led_current_register = DA9052_LED2CONF_REG;
+               led_current_sink_bit = DA9052_LEDCONT_LED2EN;
+               led_boost_en_bit = DA9052_BOOST_LED2INEN;
+       break;
+       case LED3:
+               led_ramp_bit = DA9052_LEDCONT_LED3RAMP;
+               led_current_register = DA9052_LED3CONF_REG;
+               led_current_sink_bit = DA9052_LEDCONT_LED3EN;
+               led_boost_en_bit = DA9052_BOOST_LED3INEN;
+       break;
+       default:
+               return -EIO;
+       }
+
+       /*
+               1. Configure the boost register
+               2. Configure the LED _CONT register
+               3. Configure the LEDx_CONF registers to the brightness value.
+       */
+       msg.addr = DA9052_BOOST_REG;
+       msg.data = 0x3F;
+       if (brightness) {
+               da9052_lock(data->da9052);
+               ret = data->da9052->write(data->da9052, &msg);
+               if (ret) {
+                       da9052_unlock(data->da9052);
+                       return ret;
+               }
+               da9052_unlock(data->da9052);
+       }
+
+       msg.addr = DA9052_LEDCONT_REG;
+       msg.data = 0xFF;
+       if (brightness) {
+               da9052_lock(data->da9052);
+               ret = data->da9052->write(data->da9052, &msg);
+               if (ret) {
+                       da9052_unlock(data->da9052);
+                       return ret;
+               }
+               da9052_unlock(data->da9052);
+       }
+
+       msg.addr = led_current_register;
+       msg.data = 0;
+       /* Write to the DA9052 register */
+       da9052_lock(data->da9052);
+       ret = data->da9052->write(data->da9052, &msg);
+       if (ret) {
+               da9052_unlock(data->da9052);
+               return ret;
+       }
+       da9052_unlock(data->da9052);
+       msleep(20);
+       msg.data = brightness;
+       /* Write to the DA9052 register */
+       da9052_lock(data->da9052);
+       ret = data->da9052->write(data->da9052, &msg);
+       if (ret) {
+               da9052_unlock(data->da9052);
+               return ret;
+       }
+       da9052_unlock(data->da9052);
+
+       return 0;
+}
+
+static int da9052_backlight_set(struct backlight_device *bl, int brightness)
+{
+       struct da9052_backlight_data *data = bl_get_data(bl);
+       int ret = 0;
+       /* Check for LED1 */
+       if (1 == data->is_led1_present) {
+               ret = da9052_backlight_brightness_set(data, brightness, LED1);
+               if (ret)
+                       return ret;
+       }
+       /* Check for LED2 */
+       if (1 == data->is_led2_present) {
+               ret = da9052_backlight_brightness_set(data, brightness, LED2);
+               if (ret)
+                       return ret;
+       }
+       /* Check for LED3 */
+       if (1 == data->is_led3_present) {
+               ret = da9052_backlight_brightness_set(data, brightness, LED3);
+               if (ret)
+                       return ret;
+       }
+
+       data->current_brightness = brightness;
+       return 0;
+}
+
+static int da9052_init_WLED(struct da9052_backlight_data *data,
+                       enum da9052_led_number led)
+{
+       int ret = 0;
+       unsigned int led_current_register;
+       struct da9052_ssc_msg msg;
+
+       switch (led) {
+       case LED1:
+               led_current_register = DA9052_LED1CONF_REG;
+       break;
+       case LED2:
+               led_current_register = DA9052_LED2CONF_REG;
+       break;
+       case LED3:
+               led_current_register = DA9052_LED3CONF_REG;
+       break;
+       default:
+               return -EIO;
+       }
+
+       msg.addr = DA9052_BOOST_REG;
+       msg.data = 0x00;
+       da9052_lock(data->da9052);
+       ret = data->da9052->write(data->da9052, &msg);
+       if (ret) {
+               da9052_unlock(data->da9052);
+               return ret;
+       }
+       da9052_unlock(data->da9052);
+
+       msg.addr = DA9052_LEDCONT_REG;
+       msg.data = 0x00;
+       da9052_lock(data->da9052);
+       ret = data->da9052->write(data->da9052, &msg);
+       if (ret) {
+               da9052_unlock(data->da9052);
+               return ret;
+       }
+       da9052_unlock(data->da9052);
+
+       msg.addr = led_current_register;
+       msg.data = 0;
+       da9052_lock(data->da9052);
+       ret = data->da9052->write(data->da9052, &msg);
+       da9052_unlock(data->da9052);
+       return ret;
+}
+
+static int da9052_backlight_update_status(struct backlight_device *bl)
+{
+       int brightness = bl->props.brightness;
+
+       if (bl->props.power != FB_BLANK_UNBLANK)
+               brightness = 0;
+
+       if (bl->props.fb_blank != FB_BLANK_UNBLANK)
+               brightness = 0;
+       return da9052_backlight_set(bl, brightness);
+}
+
+static int da9052_backlight_get_brightness(struct backlight_device *bl)
+{
+       struct da9052_backlight_data *data = bl_get_data(bl);
+       return data->current_brightness;
+}
+
+const struct backlight_ops da9052_backlight_ops = {
+       .update_status  = da9052_backlight_update_status,
+       .get_brightness = da9052_backlight_get_brightness,
+};
+
+static int da9052_backlight_probe1(struct platform_device *pdev)
+{
+       struct da9052_backlight_data *data;
+       struct backlight_device *bl;
+       struct backlight_properties props;
+       int ret = 0;
+       struct da9052 *da9052 = dev_get_drvdata(pdev->dev.parent);
+
+       data = kzalloc(sizeof(*data), GFP_KERNEL);
+       if (data == NULL)
+               return -ENOMEM;
+       data->da9052_dev = pdev->dev.parent;
+       data->da9052    = da9052;
+       data->current_brightness = 0;
+       data->is_led1_present = DA9052_LED1_PRESENT;
+
+       /* Init the WLED-1 bank */
+       ret = da9052_init_WLED(data, LED1);
+       if (ret)
+               return ret;
+
+       memset(&props, 0, sizeof(struct backlight_properties));
+       props.max_brightness = DA9052_MAX_BRIGHTNESS;
+       bl = backlight_device_register(pdev->name, data->da9052_dev,
+                                      data, &da9052_backlight_ops, &props);
+       if (IS_ERR(bl)) {
+               dev_err(&pdev->dev, "failed to register backlight\n");
+               kfree(data);
+               return PTR_ERR(bl);
+       }
+
+       bl->props.brightness = 0;
+
+       platform_set_drvdata(pdev, bl);
+       backlight_update_status(bl);
+
+       return 0;
+}
+static int da9052_backlight_probe2(struct platform_device *pdev)
+{
+       struct da9052_backlight_data *data;
+       struct backlight_device *bl;
+       struct da9052 *da9052 = dev_get_drvdata(pdev->dev.parent);
+       struct backlight_properties props;
+       int ret = 0;
+
+       data = kzalloc(sizeof(*data), GFP_KERNEL);
+       if (data == NULL)
+               return -ENOMEM;
+       data->da9052_dev = pdev->dev.parent;
+       data->da9052    = da9052;
+       data->current_brightness = 0;
+       data->is_led2_present = DA9052_LED2_PRESENT;
+
+       /* Init the WLED-2 bank */
+       ret = da9052_init_WLED(data, LED2);
+       if (ret)
+               return ret;
+
+       memset(&props, 0, sizeof(struct backlight_properties));
+       props.max_brightness = DA9052_MAX_BRIGHTNESS;
+       bl = backlight_device_register(pdev->name, data->da9052_dev,
+                                      data, &da9052_backlight_ops, &props);
+       if (IS_ERR(bl)) {
+               dev_err(&pdev->dev, "failed to register backlight\n");
+               kfree(data);
+               return PTR_ERR(bl);
+       }
+
+       bl->props.brightness = 0;
+
+       platform_set_drvdata(pdev, bl);
+       backlight_update_status(bl);
+
+       return 0;
+}
+static int da9052_backlight_probe3(struct platform_device *pdev)
+{
+       struct da9052_backlight_data *data;
+       struct backlight_device *bl;
+       struct da9052 *da9052 = dev_get_drvdata(pdev->dev.parent);
+       struct backlight_properties props;
+       int ret = 0;
+
+       data = kzalloc(sizeof(*data), GFP_KERNEL);
+       if (data == NULL)
+               return -ENOMEM;
+       data->da9052_dev = pdev->dev.parent;
+       data->da9052    = da9052;
+       data->current_brightness = 0;
+       data->is_led3_present = DA9052_LED3_PRESENT;
+
+       /* Init the WLED-2 bank */
+       ret = da9052_init_WLED(data, LED3);
+       if (ret)
+               return ret;
+
+       memset(&props, 0, sizeof(struct backlight_properties));
+       props.max_brightness = DA9052_MAX_BRIGHTNESS;
+       bl = backlight_device_register(pdev->name, data->da9052_dev,
+                                      data, &da9052_backlight_ops, &props);
+       if (IS_ERR(bl)) {
+               dev_err(&pdev->dev, "failed to register backlight\n");
+               kfree(data);
+               return PTR_ERR(bl);
+       }
+
+       bl->props.brightness = 0;
+
+       platform_set_drvdata(pdev, bl);
+
+       backlight_update_status(bl);
+       return 0;
+}
+
+static int da9052_backlight_remove1(struct platform_device *pdev)
+{
+       struct backlight_device *bl = platform_get_drvdata(pdev);
+       struct da9052_backlight_data *data = bl_get_data(bl);
+       int ret = 0;
+
+       /* Switch off the WLED-1 */
+       ret = da9052_init_WLED(data, LED1);
+       if (ret)
+               return ret;
+
+       backlight_device_unregister(bl);
+       kfree(data);
+       return 0;
+}
+
+static int da9052_backlight_remove2(struct platform_device *pdev)
+{
+       struct backlight_device *bl = platform_get_drvdata(pdev);
+       struct da9052_backlight_data *data = bl_get_data(bl);
+       int ret = 0;
+
+       /* Switch off the WLED-2 */
+       ret = da9052_init_WLED(data, LED2);
+       if (ret)
+               return ret;
+
+       backlight_device_unregister(bl);
+       kfree(data);
+       return 0;
+}
+static int da9052_backlight_remove3(struct platform_device *pdev)
+{
+       struct backlight_device *bl = platform_get_drvdata(pdev);
+       struct da9052_backlight_data *data = bl_get_data(bl);
+       int ret;
+
+       /* Switch off the WLED-3 */
+       ret = da9052_init_WLED(data, LED3);
+       if (ret)
+               return ret;
+
+       backlight_device_unregister(bl);
+       kfree(data);
+       return 0;
+}
+
+static struct platform_driver da9052_backlight_driver1 = {
+       .driver         = {
+               .name   = DRIVER_NAME1,
+               .owner  = THIS_MODULE,
+       },
+       .probe          = da9052_backlight_probe1,
+       .remove         = da9052_backlight_remove1,
+};
+static struct platform_driver da9052_backlight_driver2 = {
+       .driver         = {
+               .name   = DRIVER_NAME2,
+               .owner  = THIS_MODULE,
+       },
+       .probe          = da9052_backlight_probe2,
+       .remove         = da9052_backlight_remove2,
+};
+static struct platform_driver da9052_backlight_driver3 = {
+       .driver         = {
+               .name   = DRIVER_NAME3,
+               .owner  = THIS_MODULE,
+       },
+       .probe          = da9052_backlight_probe3,
+       .remove         = da9052_backlight_remove3,
+};
+
+static int __init da9052_backlight_init(void)
+{
+       s32 ret;
+       ret = platform_driver_register(&da9052_backlight_driver1);
+       if (ret)
+               return ret;
+       ret = platform_driver_register(&da9052_backlight_driver2);
+       if (ret)
+               return ret;
+
+       ret = platform_driver_register(&da9052_backlight_driver3);
+       if (ret)
+               return ret;
+
+       return ret;
+}
+module_init(da9052_backlight_init);
+
+static void __exit da9052_backlight_exit(void)
+{
+       platform_driver_unregister(&da9052_backlight_driver1);
+       platform_driver_unregister(&da9052_backlight_driver2);
+       platform_driver_unregister(&da9052_backlight_driver3);
+}
+module_exit(da9052_backlight_exit);
+
+MODULE_AUTHOR("Dialog Semiconductor Ltd <dc...@diasemi.com>");
+MODULE_DESCRIPTION("Backlight driver for Dialog DA9052 PMIC");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:" DRIVER_NAME);
+
-- 
1.7.5.3


_______________________________________________
linaro-dev mailing list
linaro-dev@lists.linaro.org
http://lists.linaro.org/mailman/listinfo/linaro-dev

Reply via email to