leds: CPCAP LED driver initial submission
authorDan Murphy <wldm10@motorola.com>
Thu, 27 May 2010 18:41:02 +0000 (13:41 -0500)
committerColin Cross <ccross@android.com>
Wed, 6 Oct 2010 23:33:00 +0000 (16:33 -0700)
Initial submission of the Home key LED code.
Code was ported from Sholes and updated with a work queue

Change-Id: Ib25313471cd21fb941b8fa4ecab3811b6ef35d74
Signed-off-by: Dan Murphy <wldm10@motorola.com>
drivers/leds/Kconfig
drivers/leds/Makefile
drivers/leds/leds-ld-cpcap-disp.c [new file with mode: 0755]
include/linux/leds-ld-cpcap.h [new file with mode: 0644]

index 8e37852364f87f1058aacf6d09db5d53758b82cf..79a73be5e836ca95f014775e8e9370c560566dd6 100644 (file)
@@ -144,6 +144,12 @@ config LEDS_AUO_PANEL
        help
          This option enables support for AUO display backlight driver
 
+config LEDS_CPCAP_DISP
+       tristate "LED Support for Display LEDS connected to CPCAP"
+       depends on LEDS_CLASS && MFD_CPCAP
+       help
+         This option enables support for display LEDs connected to CPCAP
+
 config LEDS_GPIO
        tristate "LED Support for GPIO connected LEDs"
        depends on GENERIC_GPIO
index 19b63453d0d76c537e52047bc8b1906e03762e4d..ac8203b3f07fb6b4d09f03d4cffaa52f1f1b9ff7 100644 (file)
@@ -39,6 +39,7 @@ obj-$(CONFIG_LEDS_DELL_NETBOOKS)      += dell-led.o
 obj-$(CONFIG_LEDS_MC13783)             += leds-mc13783.o
 obj-$(CONFIG_LEDS_NS2)                 += leds-ns2.o
 obj-$(CONFIG_LEDS_AUO_PANEL)           += leds-auo-panel-backlight.o
+obj-$(CONFIG_LEDS_CPCAP_DISP)          += leds-ld-cpcap-disp.o
 
 # LED SPI Drivers
 obj-$(CONFIG_LEDS_DAC124S085)          += leds-dac124s085.o
diff --git a/drivers/leds/leds-ld-cpcap-disp.c b/drivers/leds/leds-ld-cpcap-disp.c
new file mode 100755 (executable)
index 0000000..564e927
--- /dev/null
@@ -0,0 +1,186 @@
+/*
+ * Copyright (C) 2009 Motorola, Inc.
+ *
+ * This program is free dispware; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free dispware Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free dispware
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ * 02111-1307, USA
+ */
+
+#include <linux/err.h>
+#include <linux/leds.h>
+#include <linux/leds-ld-cpcap.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/workqueue.h>
+#include <linux/regulator/consumer.h>
+#include <linux/spi/cpcap.h>
+#include <linux/spi/cpcap-regbits.h>
+
+struct disp_button_led_data {
+       struct led_classdev disp_button_class_dev;
+       struct cpcap_device *cpcap;
+       struct regulator *regulator;
+       struct work_struct brightness_work;
+       enum led_brightness brightness;
+       int regulator_state;
+};
+
+static void disp_button_set(struct led_classdev *led_cdev,
+                           enum led_brightness brightness)
+{
+       struct disp_button_led_data *disp_button_led_data =
+               container_of(led_cdev, struct disp_button_led_data,
+               disp_button_class_dev);
+
+       if (brightness > 255)
+               brightness = 255;
+
+       disp_button_led_data->brightness = brightness;
+       schedule_work(&disp_button_led_data->brightness_work);
+}
+EXPORT_SYMBOL(disp_button_set);
+
+static void disp_button_brightness_work(struct work_struct *work)
+{
+       int cpcap_status = 0;
+       unsigned short brightness = 0;
+
+       struct disp_button_led_data *disp_button_led_data =
+           container_of(work, struct disp_button_led_data, brightness_work);
+
+       brightness = disp_button_led_data->brightness;
+
+       if (brightness > 0) {
+               brightness = (LD_DISP_BUTTON_DUTY_CYCLE |
+                       LD_DISP_BUTTON_CURRENT | LD_DISP_BUTTON_ON);
+
+               if ((disp_button_led_data->regulator) &&
+                   (disp_button_led_data->regulator_state == 0)) {
+                       regulator_enable(disp_button_led_data->regulator);
+                       disp_button_led_data->regulator_state = 1;
+               }
+
+               cpcap_status = cpcap_regacc_write(disp_button_led_data->cpcap,
+                                                 CPCAP_REG_KLC,
+                                                 brightness,
+                                                 LD_DISP_BUTTON_CPCAP_MASK);
+
+               if (cpcap_status < 0)
+                       pr_err("%s: Writing to the register failed for %i\n",
+                              __func__, cpcap_status);
+
+       } else {
+               if ((disp_button_led_data->regulator) &&
+                   (disp_button_led_data->regulator_state == 1)) {
+                       regulator_disable(disp_button_led_data->regulator);
+                       disp_button_led_data->regulator_state = 0;
+               }
+               /* Due to a HW issue turn off the current then
+               turn off the duty cycle */
+               brightness = 0x01;
+               cpcap_status = cpcap_regacc_write(disp_button_led_data->cpcap,
+                                         CPCAP_REG_KLC, brightness,
+                                         LD_DISP_BUTTON_CPCAP_MASK);
+
+               brightness = 0x00;
+               cpcap_status = cpcap_regacc_write(disp_button_led_data->cpcap,
+                                                 CPCAP_REG_KLC, brightness,
+                                                 LD_DISP_BUTTON_CPCAP_MASK);
+
+               if (cpcap_status < 0)
+                       pr_err("%s: Writing to the register failed for %i\n",
+                              __func__, cpcap_status);
+       }
+}
+
+static int disp_button_probe(struct platform_device *pdev)
+{
+       int ret = 0;
+       struct disp_button_led_data *info;
+
+       if (pdev == NULL) {
+               pr_err("%s: platform data required\n", __func__);
+               return -ENODEV;
+
+       }
+       info = kzalloc(sizeof(struct disp_button_led_data), GFP_KERNEL);
+       if (info == NULL) {
+               ret = -ENOMEM;
+               return ret;
+       }
+
+       info->cpcap = pdev->dev.platform_data;
+       platform_set_drvdata(pdev, info);
+
+       info->regulator = regulator_get(&pdev->dev, LD_SUPPLY);
+       if (IS_ERR(info->regulator)) {
+               pr_err("%s: Cannot get %s regulator\n", __func__, LD_SUPPLY);
+               ret = PTR_ERR(info->regulator);
+               goto exit_request_reg_failed;
+
+       }
+       info->regulator_state = 0;
+
+       info->disp_button_class_dev.name = "button-backlight";
+       info->disp_button_class_dev.brightness_set = disp_button_set;
+       ret = led_classdev_register(&pdev->dev, &info->disp_button_class_dev);
+       if (ret < 0) {
+               pr_err("%s:Register button backlight class failed\n", __func__);
+               goto err_reg_button_class_failed;
+       }
+       INIT_WORK(&info->brightness_work, disp_button_brightness_work);
+       return ret;
+
+err_reg_button_class_failed:
+       if (info->regulator)
+               regulator_put(info->regulator);
+exit_request_reg_failed:
+       kfree(info);
+       return ret;
+}
+
+static int disp_button_remove(struct platform_device *pdev)
+{
+       struct disp_button_led_data *info = platform_get_drvdata(pdev);
+
+       if (info->regulator)
+               regulator_put(info->regulator);
+
+       led_classdev_unregister(&info->disp_button_class_dev);
+       return 0;
+}
+
+static struct platform_driver ld_disp_button_driver = {
+       .probe = disp_button_probe,
+       .remove = disp_button_remove,
+       .driver = {
+                  .name = LD_DISP_BUTTON_DEV,
+       },
+};
+
+static int __init led_disp_button_init(void)
+{
+       return platform_driver_register(&ld_disp_button_driver);
+}
+
+static void __exit led_disp_button_exit(void)
+{
+       platform_driver_unregister(&ld_disp_button_driver);
+}
+
+module_init(led_disp_button_init);
+module_exit(led_disp_button_exit);
+
+MODULE_DESCRIPTION("Display Button Lighting driver");
+MODULE_AUTHOR("Motorola");
+MODULE_LICENSE("GPL");
diff --git a/include/linux/leds-ld-cpcap.h b/include/linux/leds-ld-cpcap.h
new file mode 100644 (file)
index 0000000..4881fb4
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2009 Motorola, Inc.
+ *
+ * This program is free dispware; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free dispware Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free dispware
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ * 02111-1307, USA
+ */
+
+#ifndef __LED_LD_CPCAP_H__
+#define __LED_LD_CPCAP_H__
+
+#define LD_MSG_IND_DEV "notification-led"
+#define LD_DISP_BUTTON_DEV "button-backlight"
+#define LD_KPAD_DEV "keyboard-backlight"
+#define LD_AF_LED_DEV "af-led"
+#define LD_SUPPLY "sw5"
+
+#define LD_MSG_IND_ON               0x1
+#define LD_MSG_IND_CURRENT          0x2
+#define LD_MSG_IND_LO_CURRENT       0x0
+
+#define LD_MSG_IND_CPCAP_MASK       0x3FF
+
+#define LD_MSG_IND_LOW              0x20
+#define LD_MSG_IND_LOW_MED          0x20
+#define LD_MSG_IND_MEDIUM           0x30
+#define LD_MSG_IND_MED_HIGH         0x40
+#define LD_MSG_IND_HIGH             0x50
+
+#define LD_LED_RED                  0x01
+#define LD_LED_GREEN                0x02
+#define LD_LED_BLUE                 0x04
+
+#define LD_DISP_BUTTON_ON           0x1
+#define LD_DISP_BUTTON_CURRENT      0x0
+#define LD_DISP_BUTTON_DUTY_CYCLE      0x2A0
+#define LD_DISP_BUTTON_CPCAP_MASK      0x3FF
+
+#define LD_BLED_CPCAP_DUTY_CYCLE    0x41
+#define LD_BLED_CPCAP_MASK          0x3FF
+#define LD_BLED_CPCAP_CURRENT       0x6
+
+#define LD_ALT_ADBL_CURRENT         0x4
+
+#endif  /* __LED_LD_CPCAP_H__ */