summaryrefslogtreecommitdiff
path: root/drivers/leds
diff options
context:
space:
mode:
authorRob Herring <r.herring@freescale.com>2009-10-19 14:43:19 -0500
committerRob Herring <r.herring@freescale.com>2009-10-26 16:57:04 -0500
commit460b55880e47a98943f5072bc03ffcfcc8a40a14 (patch)
tree5690552665f0b7843e6552e4d5fe7b63cbc78f51 /drivers/leds
parent40abba66d676c6c7aff57a5fbd1345974c90b2fe (diff)
ENGR00117389 Port 5.0.0 release to 2.6.31
This is i.MX BSP 5.0.0 release ported to 2.6.31 Signed-off-by: Rob Herring <r.herring@freescale.com> Signed-off-by: Alan Tull <r80115@freescale.com> Signed-off-by: Xinyu Chen <xinyu.chen@freescale.com>
Diffstat (limited to 'drivers/leds')
-rw-r--r--drivers/leds/Kconfig12
-rw-r--r--drivers/leds/Makefile2
-rw-r--r--drivers/leds/leds-mc13892.c152
-rw-r--r--drivers/leds/leds-stmp378x-pwm.c190
4 files changed, 356 insertions, 0 deletions
diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig
index 7c8e7122aaa9..f5dea97da61f 100644
--- a/drivers/leds/Kconfig
+++ b/drivers/leds/Kconfig
@@ -17,6 +17,14 @@ config LEDS_CLASS
comment "LED drivers"
+config LEDS_STMP378X
+ tristate "Support for PWM LEDs on STMP378X"
+ depends on LEDS_CLASS && MACH_STMP378X
+ help
+ This option enables support for the LEDs connected to PWM
+ outputs on the Freescale STMP378X.
+
+
config LEDS_ATMEL_PWM
tristate "LED Support using Atmel PWM outputs"
depends on LEDS_CLASS && ATMEL_PWM
@@ -24,6 +32,10 @@ config LEDS_ATMEL_PWM
This option enables support for LEDs driven using outputs
of the dedicated PWM controller found on newer Atmel SOCs.
+config LEDS_MC13892
+ tristate "LED Support for mc13892 pmic"
+ depends on LEDS_CLASS && MXC_MC13892_LIGHT
+
config LEDS_LOCOMO
tristate "LED Support for Locomo device"
depends on LEDS_CLASS && SHARP_LOCOMO
diff --git a/drivers/leds/Makefile b/drivers/leds/Makefile
index e8cdcf77a4c3..b830a51c62f7 100644
--- a/drivers/leds/Makefile
+++ b/drivers/leds/Makefile
@@ -7,6 +7,8 @@ obj-$(CONFIG_LEDS_TRIGGERS) += led-triggers.o
# LED Platform Drivers
obj-$(CONFIG_LEDS_ATMEL_PWM) += leds-atmel-pwm.o
obj-$(CONFIG_LEDS_BD2802) += leds-bd2802.o
+obj-$(CONFIG_LEDS_MC13892) += leds-mc13892.o
+obj-$(CONFIG_LEDS_STMP378X) += leds-stmp378x-pwm.o
obj-$(CONFIG_LEDS_LOCOMO) += leds-locomo.o
obj-$(CONFIG_LEDS_MIKROTIK_RB532) += leds-rb532.o
obj-$(CONFIG_LEDS_S3C24XX) += leds-s3c24xx.o
diff --git a/drivers/leds/leds-mc13892.c b/drivers/leds/leds-mc13892.c
new file mode 100644
index 000000000000..9edd20446235
--- /dev/null
+++ b/drivers/leds/leds-mc13892.c
@@ -0,0 +1,152 @@
+/*
+ * Copyright 2008-2009 Freescale Semiconductor, Inc. All Rights Reserved.
+ */
+
+/*
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/leds.h>
+#include <linux/pmic_light.h>
+
+static void mc13892_led_set(struct led_classdev *led_cdev,
+ enum led_brightness value)
+{
+ struct platform_device *dev = to_platform_device(led_cdev->dev->parent);
+ int led_ch;
+
+ switch (dev->id) {
+ case 'r':
+ led_ch = LIT_RED;
+ break;
+ case 'g':
+ led_ch = LIT_GREEN;
+ break;
+ case 'b':
+ led_ch = LIT_BLUE;
+ break;
+ default:
+ return;
+ }
+
+ /* set current with medium value, in case current is too large */
+ mc13892_bklit_set_current(led_ch, LIT_CURR_12);
+ /* max duty cycle is 63, brightness needs to be divided by 4 */
+ mc13892_bklit_set_dutycycle(led_ch, value / 4);
+
+}
+
+static int mc13892_led_remove(struct platform_device *dev)
+{
+ struct led_classdev *led_cdev = platform_get_drvdata(dev);
+
+ led_classdev_unregister(led_cdev);
+ kfree(led_cdev->name);
+ kfree(led_cdev);
+
+ return 0;
+}
+
+#define LED_NAME_LEN 16
+
+static int mc13892_led_probe(struct platform_device *dev)
+{
+ int ret;
+ struct led_classdev *led_cdev;
+ char *name;
+
+ led_cdev = kzalloc(sizeof(struct led_classdev), GFP_KERNEL);
+ if (led_cdev == NULL) {
+ dev_err(&dev->dev, "No memory for device\n");
+ return -ENOMEM;
+ }
+ name = kzalloc(LED_NAME_LEN, GFP_KERNEL);
+ if (name == NULL) {
+ dev_err(&dev->dev, "No memory for device\n");
+ ret = -ENOMEM;
+ goto exit_err;
+ }
+
+ strcpy(name, dev->name);
+ ret = strlen(dev->name);
+ if (ret > LED_NAME_LEN - 2) {
+ dev_err(&dev->dev, "led name is too long\n");
+ goto exit_err1;
+ }
+ name[ret] = dev->id;
+ name[ret + 1] = '\0';
+ led_cdev->name = name;
+ led_cdev->brightness_set = mc13892_led_set;
+
+ ret = led_classdev_register(&dev->dev, led_cdev);
+ if (ret < 0) {
+ dev_err(&dev->dev, "led_classdev_register failed\n");
+ goto exit_err1;
+ }
+
+ platform_set_drvdata(dev, led_cdev);
+
+ return 0;
+ exit_err1:
+ kfree(led_cdev->name);
+ exit_err:
+ kfree(led_cdev);
+ return ret;
+}
+
+#ifdef CONFIG_PM
+static int mc13892_led_suspend(struct platform_device *dev, pm_message_t state)
+{
+ struct led_classdev *led_cdev = platform_get_drvdata(dev);
+
+ led_classdev_suspend(led_cdev);
+ return 0;
+}
+
+static int mc13892_led_resume(struct platform_device *dev)
+{
+ struct led_classdev *led_cdev = platform_get_drvdata(dev);
+
+ led_classdev_resume(led_cdev);
+ return 0;
+}
+#else
+#define mc13892_led_suspend NULL
+#define mc13892_led_resume NULL
+#endif
+
+static struct platform_driver mc13892_led_driver = {
+ .probe = mc13892_led_probe,
+ .remove = mc13892_led_remove,
+ .suspend = mc13892_led_suspend,
+ .resume = mc13892_led_resume,
+ .driver = {
+ .name = "pmic_leds",
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init mc13892_led_init(void)
+{
+ return platform_driver_register(&mc13892_led_driver);
+}
+
+static void __exit mc13892_led_exit(void)
+{
+ platform_driver_unregister(&mc13892_led_driver);
+}
+
+module_init(mc13892_led_init);
+module_exit(mc13892_led_exit);
+
+MODULE_DESCRIPTION("Led driver for PMIC mc13892");
+MODULE_AUTHOR("Freescale Semiconductor, Inc.");
+MODULE_LICENSE("GPL");
diff --git a/drivers/leds/leds-stmp378x-pwm.c b/drivers/leds/leds-stmp378x-pwm.c
new file mode 100644
index 000000000000..f0865db4eb90
--- /dev/null
+++ b/drivers/leds/leds-stmp378x-pwm.c
@@ -0,0 +1,190 @@
+/*
+ * Freescale STMP378X PWM LED driver
+ *
+ * Author: Drew Benedetti <drewb@embeddedalley.com>
+ *
+ * Copyright 2008-2009 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
+ */
+
+/*
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/leds.h>
+#include <linux/err.h>
+#include <linux/clk.h>
+#include <mach/hardware.h>
+#include <mach/regs-pwm.h>
+#include <mach/regs-clkctrl.h>
+#include <mach/pwm-led.h>
+#include <mach/stmp3xxx.h>
+
+/* Up to 5 PWM lines are available. */
+#define PWM_MAX 5
+
+/* PWM enables are the lowest PWM_MAX bits of HW_PWM_CTRL register */
+#define BM_PWM_CTRL_PWM_ENABLE(n) ((1<<(n)) & ((1<<(PWM_MAX))-1))
+#define BF_PWM_PERIODn_SETTINGS \
+ (BF_PWM_PERIODn_CDIV(5) | /* divide by 64 */ \
+ BF_PWM_PERIODn_INACTIVE_STATE(2) | /* low */ \
+ BF_PWM_PERIODn_ACTIVE_STATE(3) | /* high */ \
+ BF_PWM_PERIODn_PERIOD(LED_FULL)) /* 255 cycles */
+
+struct stmp378x_led {
+ struct led_classdev led_dev;
+ int in_use;
+};
+
+static struct stmp378x_led leds[PWM_MAX];
+
+static struct clk *pwm_clk;
+
+static void stmp378x_pwm_led_brightness_set(struct led_classdev *pled,
+ enum led_brightness value)
+{
+ unsigned int pwmn;
+
+ pwmn = container_of(pled, struct stmp378x_led, led_dev) - leds;
+
+ if (pwmn < PWM_MAX && leds[pwmn].in_use) {
+ HW_PWM_CTRL_CLR(BM_PWM_CTRL_PWM_ENABLE(pwmn));
+ HW_PWM_ACTIVEn_WR(pwmn, BF_PWM_ACTIVEn_INACTIVE(value) |
+ BF_PWM_ACTIVEn_ACTIVE(0));
+ HW_PWM_PERIODn_WR(pwmn, BF_PWM_PERIODn_SETTINGS);
+ HW_PWM_CTRL_SET(BM_PWM_CTRL_PWM_ENABLE(pwmn));
+ }
+}
+
+static int stmp378x_pwm_led_probe(struct platform_device *pdev)
+{
+ struct led_classdev *led;
+ unsigned int pwmn;
+ int leds_in_use = 0, rc = 0;
+ int i;
+
+ stmp3xxx_reset_block(REGS_PWM_BASE, 1);
+
+ pwm_clk = clk_get(&pdev->dev, "pwm");
+ if (IS_ERR(pwm_clk)) {
+ rc = PTR_ERR(pwm_clk);
+ return rc;
+ }
+
+ clk_enable(pwm_clk);
+
+ for (i = 0; i < pdev->num_resources; i++) {
+
+ if (pdev->resource[i].flags & IORESOURCE_DISABLED)
+ continue;
+
+ pwmn = pdev->resource[i].start;
+ if (pwmn >= PWM_MAX) {
+ dev_err(&pdev->dev, "PWM %d doesn't exist\n", pwmn);
+ continue;
+ }
+
+ rc = pwm_led_pinmux_request(pwmn, "stmp378x_pwm_led");
+ if (rc) {
+ dev_err(&pdev->dev,
+ "PWM %d is not available (err=%d)\n",
+ pwmn, rc);
+ continue;
+ }
+
+ led = &leds[pwmn].led_dev;
+
+ led->flags = pdev->resource[i].flags;
+ led->name = pdev->resource[i].name;
+ led->brightness = LED_HALF;
+ led->flags = 0;
+ led->brightness_set = stmp378x_pwm_led_brightness_set;
+ led->default_trigger = 0;
+
+ rc = led_classdev_register(&pdev->dev, led);
+ if (rc < 0) {
+ dev_err(&pdev->dev,
+ "Unable to register LED device %d (err=%d)\n",
+ pwmn, rc);
+ pwm_led_pinmux_free(pwmn, "stmp378x_pwm_led");
+ continue;
+ }
+
+ /* PWM LED is available now */
+ leds[pwmn].in_use = !0;
+ leds_in_use++;
+
+ /* Set default brightness */
+ stmp378x_pwm_led_brightness_set(led, LED_HALF);
+ }
+
+ if (leds_in_use == 0) {
+ dev_info(&pdev->dev, "No PWM LEDs available\n");
+ clk_disable(pwm_clk);
+ clk_put(pwm_clk);
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
+static int stmp378x_pwm_led_remove(struct platform_device *pdev)
+{
+ unsigned int pwmn;
+
+ for (pwmn = 0; pwmn < PWM_MAX; pwmn++) {
+
+ if (!leds[pwmn].in_use)
+ continue;
+
+ /* Disable LED */
+ HW_PWM_CTRL_CLR(BM_PWM_CTRL_PWM_ENABLE(pwmn));
+ HW_PWM_ACTIVEn_WR(pwmn, BF_PWM_ACTIVEn_INACTIVE(0) |
+ BF_PWM_ACTIVEn_ACTIVE(0));
+ HW_PWM_PERIODn_WR(pwmn, BF_PWM_PERIODn_SETTINGS);
+
+ led_classdev_unregister(&leds[pwmn].led_dev);
+ pwm_led_pinmux_free(pwmn, "stmp378x_pwm_led");
+
+ leds[pwmn].led_dev.name = 0;
+ leds[pwmn].in_use = 0;
+ }
+
+ clk_disable(pwm_clk);
+ clk_put(pwm_clk);
+
+ return 0;
+}
+
+
+static struct platform_driver stmp378x_pwm_led_driver = {
+ .probe = stmp378x_pwm_led_probe,
+ .remove = stmp378x_pwm_led_remove,
+ .driver = {
+ .name = "stmp378x-pwm-led",
+ },
+};
+
+static int __init stmp378x_pwm_led_init(void)
+{
+ return platform_driver_register(&stmp378x_pwm_led_driver);
+}
+
+static void __exit stmp378x_pwm_led_exit(void)
+{
+ platform_driver_unregister(&stmp378x_pwm_led_driver);
+}
+
+module_init(stmp378x_pwm_led_init);
+module_exit(stmp378x_pwm_led_exit);
+
+MODULE_AUTHOR("Drew Benedetti <drewb@embeddedalley.com>");
+MODULE_DESCRIPTION("STMP378X PWM LED driver");
+MODULE_LICENSE("GPL");