Merge branch 'for-linus' of git://git.o-hand.com/linux-rpurdie-leds
authorLinus Torvalds <torvalds@linux-foundation.org>
Sat, 26 Sep 2009 17:50:47 +0000 (10:50 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Sat, 26 Sep 2009 17:50:47 +0000 (10:50 -0700)
* 'for-linus' of git://git.o-hand.com/linux-rpurdie-leds:
  leds: move leds-clevo-mail's probe function to .devinit.text
  leds: Fix indentation in LEDS_LP3944 Kconfig entry
  leds: Fix LED names
  leds: Fix leds-pca9532 whitespace issues
  leds: fix coding style in worker thread code for ledtrig-gpio.
  leds: gpio-leds: fix typographics fault
  leds: Add WM831x status LED driver

drivers/leds/Kconfig
drivers/leds/Makefile
drivers/leds/leds-clevo-mail.c
drivers/leds/leds-cobalt-qube.c
drivers/leds/leds-cobalt-raq.c
drivers/leds/leds-gpio.c
drivers/leds/leds-pca9532.c
drivers/leds/leds-wm831x-status.c [new file with mode: 0644]
drivers/leds/ledtrig-gpio.c
drivers/macintosh/via-pmu-led.c
include/linux/mfd/wm831x/status.h [new file with mode: 0644]

index 7c8e712..e4f599f 100644 (file)
@@ -150,9 +150,9 @@ config LEDS_LP3944
        tristate "LED Support for N.S. LP3944 (Fun Light) I2C chip"
        depends on LEDS_CLASS && I2C
        help
-    This option enables support for LEDs connected to the National
-    Semiconductor LP3944 Lighting Management Unit (LMU) also known as
-    Fun Light Chip.
+         This option enables support for LEDs connected to the National
+         Semiconductor LP3944 Lighting Management Unit (LMU) also known as
+         Fun Light Chip.
 
          To compile this driver as a module, choose M here: the
          module will be called leds-lp3944.
@@ -195,6 +195,13 @@ config LEDS_PCA955X
          LED driver chips accessed via the I2C bus.  Supported
          devices include PCA9550, PCA9551, PCA9552, and PCA9553.
 
+config LEDS_WM831X_STATUS
+       tristate "LED support for status LEDs on WM831x PMICs"
+       depends on LEDS_CLASS && MFD_WM831X
+       help
+         This option enables support for the status LEDs of the WM831x
+          series of PMICs.
+
 config LEDS_WM8350
        tristate "LED Support for WM8350 AudioPlus PMIC"
        depends on LEDS_CLASS && MFD_WM8350
index e8cdcf7..46d7270 100644 (file)
@@ -26,6 +26,7 @@ obj-$(CONFIG_LEDS_HP6XX)              += leds-hp6xx.o
 obj-$(CONFIG_LEDS_FSG)                 += leds-fsg.o
 obj-$(CONFIG_LEDS_PCA955X)             += leds-pca955x.o
 obj-$(CONFIG_LEDS_DA903X)              += leds-da903x.o
+obj-$(CONFIG_LEDS_WM831X_STATUS)       += leds-wm831x-status.o
 obj-$(CONFIG_LEDS_WM8350)              += leds-wm8350.o
 obj-$(CONFIG_LEDS_PWM)                 += leds-pwm.o
 
index f2242db..a498135 100644 (file)
@@ -153,7 +153,7 @@ static struct led_classdev clevo_mail_led = {
        .flags                  = LED_CORE_SUSPENDRESUME,
 };
 
-static int __init clevo_mail_led_probe(struct platform_device *pdev)
+static int __devinit clevo_mail_led_probe(struct platform_device *pdev)
 {
        return led_classdev_register(&pdev->dev, &clevo_mail_led);
 }
index 059aa29..8816806 100644 (file)
@@ -28,7 +28,7 @@ static void qube_front_led_set(struct led_classdev *led_cdev,
 }
 
 static struct led_classdev qube_front_led = {
-       .name                   = "qube-front",
+       .name                   = "qube::front",
        .brightness             = LED_FULL,
        .brightness_set         = qube_front_led_set,
        .default_trigger        = "ide-disk",
index 5f1ce81..defc212 100644 (file)
@@ -49,7 +49,7 @@ static void raq_web_led_set(struct led_classdev *led_cdev,
 }
 
 static struct led_classdev raq_web_led = {
-       .name           = "raq-web",
+       .name           = "raq::web",
        .brightness_set = raq_web_led_set,
 };
 
@@ -70,7 +70,7 @@ static void raq_power_off_led_set(struct led_classdev *led_cdev,
 }
 
 static struct led_classdev raq_power_off_led = {
-       .name                   = "raq-power-off",
+       .name                   = "raq::power-off",
        .brightness_set         = raq_power_off_led_set,
        .default_trigger        = "power-off",
 };
index 6b06638..7467980 100644 (file)
@@ -80,7 +80,7 @@ static int __devinit create_gpio_led(const struct gpio_led *template,
 
        /* skip leds that aren't available */
        if (!gpio_is_valid(template->gpio)) {
-               printk(KERN_INFO "Skipping unavilable LED gpio %d (%s)\n", 
+               printk(KERN_INFO "Skipping unavailable LED gpio %d (%s)\n",
                                template->gpio, template->name);
                return 0;
        }
index dba8921..708a801 100644 (file)
@@ -34,7 +34,7 @@ struct pca9532_data {
        struct i2c_client *client;
        struct pca9532_led leds[16];
        struct mutex update_lock;
-       struct input_dev    *idev;
+       struct input_dev *idev;
        struct work_struct work;
        u8 pwm[2];
        u8 psc[2];
@@ -53,9 +53,9 @@ MODULE_DEVICE_TABLE(i2c, pca9532_id);
 
 static struct i2c_driver pca9532_driver = {
        .driver = {
-               .name   = "pca9532",
+               .name = "pca9532",
        },
-       .probe  = pca9532_probe,
+       .probe = pca9532_probe,
        .remove = pca9532_remove,
        .id_table = pca9532_id,
 };
@@ -149,7 +149,7 @@ static int pca9532_set_blink(struct led_classdev *led_cdev,
 
        if (*delay_on == 0 && *delay_off == 0) {
        /* led subsystem ask us for a blink rate */
-               *delay_on  = 1000;
+               *delay_on = 1000;
                *delay_off = 1000;
        }
        if (*delay_on != *delay_off || *delay_on > 1690 || *delay_on < 6)
@@ -227,7 +227,7 @@ static int pca9532_configure(struct i2c_client *client,
                        break;
                case PCA9532_TYPE_LED:
                        led->state = pled->state;
-                       led->name =  pled->name;
+                       led->name = pled->name;
                        led->ldev.name = led->name;
                        led->ldev.brightness = LED_OFF;
                        led->ldev.brightness_set = pca9532_set_brightness;
@@ -254,7 +254,7 @@ static int pca9532_configure(struct i2c_client *client,
                        data->idev->name = pled->name;
                        data->idev->phys = "i2c/pca9532";
                        data->idev->id.bustype = BUS_HOST;
-                       data->idev->id.vendor  = 0x001f;
+                       data->idev->id.vendor = 0x001f;
                        data->idev->id.product = 0x0001;
                        data->idev->id.version = 0x0100;
                        data->idev->evbit[0] = BIT_MASK(EV_SND);
diff --git a/drivers/leds/leds-wm831x-status.c b/drivers/leds/leds-wm831x-status.c
new file mode 100644 (file)
index 0000000..c586d05
--- /dev/null
@@ -0,0 +1,341 @@
+/*
+ * LED driver for WM831x status LEDs
+ *
+ * Copyright(C) 2009 Wolfson Microelectronics PLC.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/leds.h>
+#include <linux/err.h>
+#include <linux/mfd/wm831x/core.h>
+#include <linux/mfd/wm831x/pdata.h>
+#include <linux/mfd/wm831x/status.h>
+
+
+struct wm831x_status {
+       struct led_classdev cdev;
+       struct wm831x *wm831x;
+       struct work_struct work;
+       struct mutex mutex;
+
+       spinlock_t value_lock;
+       int reg;     /* Control register */
+       int reg_val; /* Control register value */
+
+       int blink;
+       int blink_time;
+       int blink_cyc;
+       int src;
+       enum led_brightness brightness;
+};
+
+#define to_wm831x_status(led_cdev) \
+       container_of(led_cdev, struct wm831x_status, cdev)
+
+static void wm831x_status_work(struct work_struct *work)
+{
+       struct wm831x_status *led = container_of(work, struct wm831x_status,
+                                                work);
+       unsigned long flags;
+
+       mutex_lock(&led->mutex);
+
+       led->reg_val &= ~(WM831X_LED_SRC_MASK | WM831X_LED_MODE_MASK |
+                         WM831X_LED_DUTY_CYC_MASK | WM831X_LED_DUR_MASK);
+
+       spin_lock_irqsave(&led->value_lock, flags);
+
+       led->reg_val |= led->src << WM831X_LED_SRC_SHIFT;
+       if (led->blink) {
+               led->reg_val |= 2 << WM831X_LED_MODE_SHIFT;
+               led->reg_val |= led->blink_time << WM831X_LED_DUR_SHIFT;
+               led->reg_val |= led->blink_cyc;
+       } else {
+               if (led->brightness != LED_OFF)
+                       led->reg_val |= 1 << WM831X_LED_MODE_SHIFT;
+       }
+
+       spin_unlock_irqrestore(&led->value_lock, flags);
+
+       wm831x_reg_write(led->wm831x, led->reg, led->reg_val);
+
+       mutex_unlock(&led->mutex);
+}
+
+static void wm831x_status_set(struct led_classdev *led_cdev,
+                          enum led_brightness value)
+{
+       struct wm831x_status *led = to_wm831x_status(led_cdev);
+       unsigned long flags;
+
+       spin_lock_irqsave(&led->value_lock, flags);
+       led->brightness = value;
+       if (value == LED_OFF)
+               led->blink = 0;
+       schedule_work(&led->work);
+       spin_unlock_irqrestore(&led->value_lock, flags);
+}
+
+static int wm831x_status_blink_set(struct led_classdev *led_cdev,
+                                  unsigned long *delay_on,
+                                  unsigned long *delay_off)
+{
+       struct wm831x_status *led = to_wm831x_status(led_cdev);
+       unsigned long flags;
+       int ret = 0;
+
+       /* Pick some defaults if we've not been given times */
+       if (*delay_on == 0 && *delay_off == 0) {
+               *delay_on = 250;
+               *delay_off = 250;
+       }
+
+       spin_lock_irqsave(&led->value_lock, flags);
+
+       /* We only have a limited selection of settings, see if we can
+        * support the configuration we're being given */
+       switch (*delay_on) {
+       case 1000:
+               led->blink_time = 0;
+               break;
+       case 250:
+               led->blink_time = 1;
+               break;
+       case 125:
+               led->blink_time = 2;
+               break;
+       case 62:
+       case 63:
+               /* Actually 62.5ms */
+               led->blink_time = 3;
+               break;
+       default:
+               ret = -EINVAL;
+               break;
+       }
+
+       if (ret == 0) {
+               switch (*delay_off / *delay_on) {
+               case 1:
+                       led->blink_cyc = 0;
+                       break;
+               case 3:
+                       led->blink_cyc = 1;
+                       break;
+               case 4:
+                       led->blink_cyc = 2;
+                       break;
+               case 8:
+                       led->blink_cyc = 3;
+                       break;
+               default:
+                       ret = -EINVAL;
+                       break;
+               }
+       }
+
+       if (ret == 0)
+               led->blink = 1;
+       else
+               led->blink = 0;
+
+       /* Always update; if we fail turn off blinking since we expect
+        * a software fallback. */
+       schedule_work(&led->work);
+
+       spin_unlock_irqrestore(&led->value_lock, flags);
+
+       return ret;
+}
+
+static const char *led_src_texts[] = {
+       "otp",
+       "power",
+       "charger",
+       "soft",
+};
+
+static ssize_t wm831x_status_src_show(struct device *dev,
+                                     struct device_attribute *attr, char *buf)
+{
+       struct led_classdev *led_cdev = dev_get_drvdata(dev);
+       struct wm831x_status *led = to_wm831x_status(led_cdev);
+       int i;
+       ssize_t ret = 0;
+
+       mutex_lock(&led->mutex);
+
+       for (i = 0; i < ARRAY_SIZE(led_src_texts); i++)
+               if (i == led->src)
+                       ret += sprintf(&buf[ret], "[%s] ", led_src_texts[i]);
+               else
+                       ret += sprintf(&buf[ret], "%s ", led_src_texts[i]);
+
+       mutex_unlock(&led->mutex);
+
+       ret += sprintf(&buf[ret], "\n");
+
+       return ret;
+}
+
+static ssize_t wm831x_status_src_store(struct device *dev,
+                                      struct device_attribute *attr,
+                                      const char *buf, size_t size)
+{
+       struct led_classdev *led_cdev = dev_get_drvdata(dev);
+       struct wm831x_status *led = to_wm831x_status(led_cdev);
+       char name[20];
+       int i;
+       size_t len;
+
+       name[sizeof(name) - 1] = '\0';
+       strncpy(name, buf, sizeof(name) - 1);
+       len = strlen(name);
+
+       if (len && name[len - 1] == '\n')
+               name[len - 1] = '\0';
+
+       for (i = 0; i < ARRAY_SIZE(led_src_texts); i++) {
+               if (!strcmp(name, led_src_texts[i])) {
+                       mutex_lock(&led->mutex);
+
+                       led->src = i;
+                       schedule_work(&led->work);
+
+                       mutex_unlock(&led->mutex);
+               }
+       }
+
+       return size;
+}
+
+static DEVICE_ATTR(src, 0644, wm831x_status_src_show, wm831x_status_src_store);
+
+static int wm831x_status_probe(struct platform_device *pdev)
+{
+       struct wm831x *wm831x = dev_get_drvdata(pdev->dev.parent);
+       struct wm831x_pdata *chip_pdata;
+       struct wm831x_status_pdata pdata;
+       struct wm831x_status *drvdata;
+       struct resource *res;
+       int id = pdev->id % ARRAY_SIZE(chip_pdata->status);
+       int ret;
+
+       res = platform_get_resource(pdev, IORESOURCE_IO, 0);
+       if (res == NULL) {
+               dev_err(&pdev->dev, "No I/O resource\n");
+               ret = -EINVAL;
+               goto err;
+       }
+
+       drvdata = kzalloc(sizeof(struct wm831x_status), GFP_KERNEL);
+       if (!drvdata)
+               return -ENOMEM;
+       dev_set_drvdata(&pdev->dev, drvdata);
+
+       drvdata->wm831x = wm831x;
+       drvdata->reg = res->start;
+
+       if (wm831x->dev->platform_data)
+               chip_pdata = wm831x->dev->platform_data;
+       else
+               chip_pdata = NULL;
+
+       memset(&pdata, 0, sizeof(pdata));
+       if (chip_pdata && chip_pdata->status[id])
+               memcpy(&pdata, chip_pdata->status[id], sizeof(pdata));
+       else
+               pdata.name = dev_name(&pdev->dev);
+
+       mutex_init(&drvdata->mutex);
+       INIT_WORK(&drvdata->work, wm831x_status_work);
+       spin_lock_init(&drvdata->value_lock);
+
+       /* We cache the configuration register and read startup values
+        * from it. */
+       drvdata->reg_val = wm831x_reg_read(wm831x, drvdata->reg);
+
+       if (drvdata->reg_val & WM831X_LED_MODE_MASK)
+               drvdata->brightness = LED_FULL;
+       else
+               drvdata->brightness = LED_OFF;
+
+       /* Set a default source if configured, otherwise leave the
+        * current hardware setting.
+        */
+       if (pdata.default_src == WM831X_STATUS_PRESERVE) {
+               drvdata->src = drvdata->reg_val;
+               drvdata->src &= WM831X_LED_SRC_MASK;
+               drvdata->src >>= WM831X_LED_SRC_SHIFT;
+       } else {
+               drvdata->src = pdata.default_src - 1;
+       }
+
+       drvdata->cdev.name = pdata.name;
+       drvdata->cdev.default_trigger = pdata.default_trigger;
+       drvdata->cdev.brightness_set = wm831x_status_set;
+       drvdata->cdev.blink_set = wm831x_status_blink_set;
+
+       ret = led_classdev_register(wm831x->dev, &drvdata->cdev);
+       if (ret < 0) {
+               dev_err(&pdev->dev, "Failed to register LED: %d\n", ret);
+               goto err_led;
+       }
+
+       ret = device_create_file(drvdata->cdev.dev, &dev_attr_src);
+       if (ret != 0)
+               dev_err(&pdev->dev,
+                       "No source control for LED: %d\n", ret);
+
+       return 0;
+
+err_led:
+       led_classdev_unregister(&drvdata->cdev);
+       kfree(drvdata);
+err:
+       return ret;
+}
+
+static int wm831x_status_remove(struct platform_device *pdev)
+{
+       struct wm831x_status *drvdata = platform_get_drvdata(pdev);
+
+       device_remove_file(drvdata->cdev.dev, &dev_attr_src);
+       led_classdev_unregister(&drvdata->cdev);
+       kfree(drvdata);
+
+       return 0;
+}
+
+static struct platform_driver wm831x_status_driver = {
+       .driver = {
+                  .name = "wm831x-status",
+                  .owner = THIS_MODULE,
+                  },
+       .probe = wm831x_status_probe,
+       .remove = wm831x_status_remove,
+};
+
+static int __devinit wm831x_status_init(void)
+{
+       return platform_driver_register(&wm831x_status_driver);
+}
+module_init(wm831x_status_init);
+
+static void wm831x_status_exit(void)
+{
+       platform_driver_unregister(&wm831x_status_driver);
+}
+module_exit(wm831x_status_exit);
+
+MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
+MODULE_DESCRIPTION("WM831x status LED driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:wm831x-status");
index 1bc5db4..f591337 100644 (file)
@@ -44,22 +44,22 @@ static void gpio_trig_work(struct work_struct *work)
                        struct gpio_trig_data, work);
        int tmp;
 
-       if (!gpio_data->gpio)
-              return;
-
-       tmp = gpio_get_value(gpio_data->gpio);
-       if (gpio_data->inverted)
-              tmp = !tmp;
-
-       if (tmp) {
-               if (gpio_data->desired_brightness)
-                       led_set_brightness(gpio_data->led,
-                                       gpio_data->desired_brightness);
-               else
-                       led_set_brightness(gpio_data->led, LED_FULL);
-       } else {
-               led_set_brightness(gpio_data->led, LED_OFF);
-       }
+       if (!gpio_data->gpio)
+               return;
+
+       tmp = gpio_get_value(gpio_data->gpio);
+       if (gpio_data->inverted)
+               tmp = !tmp;
+
+       if (tmp) {
+               if (gpio_data->desired_brightness)
+                       led_set_brightness(gpio_data->led,
+                                          gpio_data->desired_brightness);
+               else
+                       led_set_brightness(gpio_data->led, LED_FULL);
+       } else {
+               led_set_brightness(gpio_data->led, LED_OFF);
+       }
 }
 
 static ssize_t gpio_trig_brightness_show(struct device *dev,
index 55ad956..d242976 100644 (file)
@@ -72,7 +72,7 @@ static void pmu_led_set(struct led_classdev *led_cdev,
 }
 
 static struct led_classdev pmu_led = {
-       .name = "pmu-front-led",
+       .name = "pmu-led::front",
 #ifdef CONFIG_ADB_PMU_LED_IDE
        .default_trigger = "ide-disk",
 #endif
diff --git a/include/linux/mfd/wm831x/status.h b/include/linux/mfd/wm831x/status.h
new file mode 100644 (file)
index 0000000..6bc090d
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+ * include/linux/mfd/wm831x/status.h -- Status LEDs for WM831x
+ *
+ * Copyright 2009 Wolfson Microelectronics PLC.
+ *
+ * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
+ *
+ *  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.
+ *
+ */
+
+#ifndef __MFD_WM831X_STATUS_H__
+#define __MFD_WM831X_STATUS_H__
+
+#define WM831X_LED_SRC_MASK                    0xC000  /* LED_SRC - [15:14] */
+#define WM831X_LED_SRC_SHIFT                       14  /* LED_SRC - [15:14] */
+#define WM831X_LED_SRC_WIDTH                        2  /* LED_SRC - [15:14] */
+#define WM831X_LED_MODE_MASK                   0x0300  /* LED_MODE - [9:8] */
+#define WM831X_LED_MODE_SHIFT                       8  /* LED_MODE - [9:8] */
+#define WM831X_LED_MODE_WIDTH                       2  /* LED_MODE - [9:8] */
+#define WM831X_LED_SEQ_LEN_MASK                0x0030  /* LED_SEQ_LEN - [5:4] */
+#define WM831X_LED_SEQ_LEN_SHIFT                    4  /* LED_SEQ_LEN - [5:4] */
+#define WM831X_LED_SEQ_LEN_WIDTH                    2  /* LED_SEQ_LEN - [5:4] */
+#define WM831X_LED_DUR_MASK                    0x000C  /* LED_DUR - [3:2] */
+#define WM831X_LED_DUR_SHIFT                        2  /* LED_DUR - [3:2] */
+#define WM831X_LED_DUR_WIDTH                        2  /* LED_DUR - [3:2] */
+#define WM831X_LED_DUTY_CYC_MASK               0x0003  /* LED_DUTY_CYC - [1:0] */
+#define WM831X_LED_DUTY_CYC_SHIFT                   0  /* LED_DUTY_CYC - [1:0] */
+#define WM831X_LED_DUTY_CYC_WIDTH                   2  /* LED_DUTY_CYC - [1:0] */
+
+#endif