diff options
Diffstat (limited to 'drivers/leds')
-rw-r--r-- | drivers/leds/Kconfig | 38 | ||||
-rw-r--r-- | drivers/leds/Makefile | 4 | ||||
-rw-r--r-- | drivers/leds/led-class.c | 28 | ||||
-rw-r--r-- | drivers/leds/led-core.c | 19 | ||||
-rw-r--r-- | drivers/leds/leds-atmel-pwm.c | 149 | ||||
-rw-r--r-- | drivers/leds/leds-gpio-register.c | 5 | ||||
-rw-r--r-- | drivers/leds/leds-gpio.c | 14 | ||||
-rw-r--r-- | drivers/leds/leds-ipaq-micro.c | 141 | ||||
-rw-r--r-- | drivers/leds/leds-lm3530.c | 20 | ||||
-rw-r--r-- | drivers/leds/leds-lm3533.c | 20 | ||||
-rw-r--r-- | drivers/leds/leds-lm355x.c | 21 | ||||
-rw-r--r-- | drivers/leds/leds-lm3642.c | 30 | ||||
-rw-r--r-- | drivers/leds/leds-lp3944.c | 3 | ||||
-rw-r--r-- | drivers/leds/leds-lp55xx-common.c | 20 | ||||
-rw-r--r-- | drivers/leds/leds-max8997.c | 16 | ||||
-rw-r--r-- | drivers/leds/leds-menf21bmc.c | 131 | ||||
-rw-r--r-- | drivers/leds/leds-netxbig.c | 31 | ||||
-rw-r--r-- | drivers/leds/leds-ns2.c | 16 | ||||
-rw-r--r-- | drivers/leds/leds-pca9532.c | 10 | ||||
-rw-r--r-- | drivers/leds/leds-pca963x.c | 28 | ||||
-rw-r--r-- | drivers/leds/leds-ss4200.c | 14 | ||||
-rw-r--r-- | drivers/leds/leds-syscon.c | 166 | ||||
-rw-r--r-- | drivers/leds/leds-tca6507.c | 7 | ||||
-rw-r--r-- | drivers/leds/leds-wm831x-status.c | 23 | ||||
-rw-r--r-- | drivers/leds/trigger/ledtrig-gpio.c | 2 |
25 files changed, 622 insertions, 334 deletions
diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig index a1b044e7eaad..a210338cfeb1 100644 --- a/drivers/leds/Kconfig +++ b/drivers/leds/Kconfig @@ -32,14 +32,6 @@ config LEDS_88PM860X This option enables support for on-chip LED drivers found on Marvell Semiconductor 88PM8606 PMIC. -config LEDS_ATMEL_PWM - tristate "LED Support using Atmel PWM outputs" - depends on LEDS_CLASS - depends on ATMEL_PWM - help - This option enables support for LEDs driven using outputs - of the dedicated PWM controller found on newer Atmel SOCs. - config LEDS_LM3530 tristate "LCD Backlight driver for LM3530" depends on LEDS_CLASS @@ -143,6 +135,13 @@ config LEDS_SUNFIRE This option enables support for the Left, Middle, and Right LEDs on the I/O and CPU boards of SunFire UltraSPARC servers. +config LEDS_IPAQ_MICRO + tristate "LED Support for the Compaq iPAQ h3xxx" + depends on MFD_IPAQ_MICRO + help + Choose this option if you want to use the notification LED on + Compaq/HP iPAQ h3100 and h3600. + config LEDS_HP6XX tristate "LED Support for the HP Jornada 6xx" depends on LEDS_CLASS @@ -411,7 +410,7 @@ config LEDS_MC13783 config LEDS_NS2 tristate "LED support for Network Space v2 GPIO LEDs" depends on LEDS_CLASS - depends on ARCH_KIRKWOOD || MACH_KIRKWOOD + depends on MACH_KIRKWOOD default y help This option enable support for the dual-GPIO LED found on the @@ -421,7 +420,7 @@ config LEDS_NS2 config LEDS_NETXBIG tristate "LED support for Big Network series LEDs" depends on LEDS_CLASS - depends on ARCH_KIRKWOOD || MACH_KIRKWOOD + depends on MACH_KIRKWOOD default y help This option enable support for LEDs found on the LaCie 2Big @@ -469,6 +468,15 @@ config LEDS_OT200 This option enables support for the LEDs on the Bachmann OT200. Say Y to enable LEDs on the Bachmann OT200. +config LEDS_MENF21BMC + tristate "LED support for the MEN 14F021P00 BMC" + depends on LEDS_CLASS && MFD_MENF21BMC + help + Say Y here to include support for the MEN 14F021P00 BMC LEDs. + + This driver can also be built as a module. If so the module + will be called leds-menf21bmc. + comment "LED driver for blink(1) USB RGB LED is under Special HID drivers (HID_THINGM)" config LEDS_BLINKM @@ -479,6 +487,16 @@ config LEDS_BLINKM This option enables support for the BlinkM RGB LED connected through I2C. Say Y to enable support for the BlinkM LED. +config LEDS_SYSCON + bool "LED support for LEDs on system controllers" + depends on LEDS_CLASS=y + depends on MFD_SYSCON + depends on OF + help + This option enabled support for the LEDs on syscon type + devices. This will only work with device tree enabled + devices. + config LEDS_VERSATILE tristate "LED support for the ARM Versatile and RealView" depends on ARCH_REALVIEW || ARCH_VERSATILE diff --git a/drivers/leds/Makefile b/drivers/leds/Makefile index 79c5155199a7..a2b164741465 100644 --- a/drivers/leds/Makefile +++ b/drivers/leds/Makefile @@ -6,7 +6,6 @@ obj-$(CONFIG_LEDS_TRIGGERS) += led-triggers.o # LED Platform Drivers obj-$(CONFIG_LEDS_88PM860X) += leds-88pm860x.o -obj-$(CONFIG_LEDS_ATMEL_PWM) += leds-atmel-pwm.o obj-$(CONFIG_LEDS_BD2802) += leds-bd2802.o obj-$(CONFIG_LEDS_LOCOMO) += leds-locomo.o obj-$(CONFIG_LEDS_LM3530) += leds-lm3530.o @@ -31,6 +30,7 @@ obj-$(CONFIG_LEDS_LP8501) += leds-lp8501.o obj-$(CONFIG_LEDS_LP8788) += leds-lp8788.o obj-$(CONFIG_LEDS_TCA6507) += leds-tca6507.o obj-$(CONFIG_LEDS_CLEVO_MAIL) += leds-clevo-mail.o +obj-$(CONFIG_LEDS_IPAQ_MICRO) += leds-ipaq-micro.o obj-$(CONFIG_LEDS_HP6XX) += leds-hp6xx.o obj-$(CONFIG_LEDS_OT200) += leds-ot200.o obj-$(CONFIG_LEDS_FSG) += leds-fsg.o @@ -53,7 +53,9 @@ obj-$(CONFIG_LEDS_ASIC3) += leds-asic3.o obj-$(CONFIG_LEDS_MAX8997) += leds-max8997.o obj-$(CONFIG_LEDS_LM355x) += leds-lm355x.o obj-$(CONFIG_LEDS_BLINKM) += leds-blinkm.o +obj-$(CONFIG_LEDS_SYSCON) += leds-syscon.o obj-$(CONFIG_LEDS_VERSATILE) += leds-versatile.o +obj-$(CONFIG_LEDS_MENF21BMC) += leds-menf21bmc.o # LED SPI Drivers obj-$(CONFIG_LEDS_DAC124S085) += leds-dac124s085.o diff --git a/drivers/leds/led-class.c b/drivers/leds/led-class.c index f37d63cf726b..7440c58b8e6f 100644 --- a/drivers/leds/led-class.c +++ b/drivers/leds/led-class.c @@ -9,26 +9,21 @@ * published by the Free Software Foundation. */ -#include <linux/module.h> -#include <linux/kernel.h> +#include <linux/ctype.h> +#include <linux/device.h> +#include <linux/err.h> #include <linux/init.h> +#include <linux/kernel.h> +#include <linux/leds.h> #include <linux/list.h> +#include <linux/module.h> +#include <linux/slab.h> #include <linux/spinlock.h> -#include <linux/device.h> #include <linux/timer.h> -#include <linux/err.h> -#include <linux/ctype.h> -#include <linux/leds.h> #include "leds.h" static struct class *leds_class; -static void led_update_brightness(struct led_classdev *led_cdev) -{ - if (led_cdev->brightness_get) - led_cdev->brightness = led_cdev->brightness_get(led_cdev); -} - static ssize_t brightness_show(struct device *dev, struct device_attribute *attr, char *buf) { @@ -59,14 +54,14 @@ static ssize_t brightness_store(struct device *dev, } static DEVICE_ATTR_RW(brightness); -static ssize_t led_max_brightness_show(struct device *dev, +static ssize_t max_brightness_show(struct device *dev, struct device_attribute *attr, char *buf) { struct led_classdev *led_cdev = dev_get_drvdata(dev); return sprintf(buf, "%u\n", led_cdev->max_brightness); } -static DEVICE_ATTR(max_brightness, 0444, led_max_brightness_show, NULL); +static DEVICE_ATTR_RO(max_brightness); #ifdef CONFIG_LEDS_TRIGGERS static DEVICE_ATTR(trigger, 0644, led_trigger_show, led_trigger_store); @@ -210,8 +205,9 @@ static const struct dev_pm_ops leds_class_dev_pm_ops = { */ int led_classdev_register(struct device *parent, struct led_classdev *led_cdev) { - led_cdev->dev = device_create(leds_class, parent, 0, led_cdev, - "%s", led_cdev->name); + led_cdev->dev = device_create_with_groups(leds_class, parent, 0, + led_cdev, led_cdev->groups, + "%s", led_cdev->name); if (IS_ERR(led_cdev->dev)) return PTR_ERR(led_cdev->dev); diff --git a/drivers/leds/led-core.c b/drivers/leds/led-core.c index 71b40d3bf776..aaa8eba9099f 100644 --- a/drivers/leds/led-core.c +++ b/drivers/leds/led-core.c @@ -12,10 +12,11 @@ */ #include <linux/kernel.h> +#include <linux/leds.h> #include <linux/list.h> #include <linux/module.h> +#include <linux/mutex.h> #include <linux/rwsem.h> -#include <linux/leds.h> #include "leds.h" DECLARE_RWSEM(leds_list_lock); @@ -126,3 +127,19 @@ void led_set_brightness(struct led_classdev *led_cdev, __led_set_brightness(led_cdev, brightness); } EXPORT_SYMBOL(led_set_brightness); + +int led_update_brightness(struct led_classdev *led_cdev) +{ + int ret = 0; + + if (led_cdev->brightness_get) { + ret = led_cdev->brightness_get(led_cdev); + if (ret >= 0) { + led_cdev->brightness = ret; + return 0; + } + } + + return ret; +} +EXPORT_SYMBOL(led_update_brightness); diff --git a/drivers/leds/leds-atmel-pwm.c b/drivers/leds/leds-atmel-pwm.c deleted file mode 100644 index 56cec8d6a2ac..000000000000 --- a/drivers/leds/leds-atmel-pwm.c +++ /dev/null @@ -1,149 +0,0 @@ -#include <linux/kernel.h> -#include <linux/platform_device.h> -#include <linux/leds.h> -#include <linux/io.h> -#include <linux/atmel_pwm.h> -#include <linux/slab.h> -#include <linux/module.h> - - -struct pwmled { - struct led_classdev cdev; - struct pwm_channel pwmc; - struct gpio_led *desc; - u32 mult; - u8 active_low; -}; - - -/* - * For simplicity, we use "brightness" as if it were a linear function - * of PWM duty cycle. However, a logarithmic function of duty cycle is - * probably a better match for perceived brightness: two is half as bright - * as four, four is half as bright as eight, etc - */ -static void pwmled_brightness(struct led_classdev *cdev, enum led_brightness b) -{ - struct pwmled *led; - - /* update the duty cycle for the *next* period */ - led = container_of(cdev, struct pwmled, cdev); - pwm_channel_writel(&led->pwmc, PWM_CUPD, led->mult * (unsigned) b); -} - -/* - * NOTE: we reuse the platform_data structure of GPIO leds, - * but repurpose its "gpio" number as a PWM channel number. - */ -static int pwmled_probe(struct platform_device *pdev) -{ - const struct gpio_led_platform_data *pdata; - struct pwmled *leds; - int i; - int status; - - pdata = dev_get_platdata(&pdev->dev); - if (!pdata || pdata->num_leds < 1) - return -ENODEV; - - leds = devm_kzalloc(&pdev->dev, pdata->num_leds * sizeof(*leds), - GFP_KERNEL); - if (!leds) - return -ENOMEM; - - for (i = 0; i < pdata->num_leds; i++) { - struct pwmled *led = leds + i; - const struct gpio_led *dat = pdata->leds + i; - u32 tmp; - - led->cdev.name = dat->name; - led->cdev.brightness = LED_OFF; - led->cdev.brightness_set = pwmled_brightness; - led->cdev.default_trigger = dat->default_trigger; - - led->active_low = dat->active_low; - - status = pwm_channel_alloc(dat->gpio, &led->pwmc); - if (status < 0) - goto err; - - /* - * Prescale clock by 2^x, so PWM counts in low MHz. - * Start each cycle with the LED active, so increasing - * the duty cycle gives us more time on (== brighter). - */ - tmp = 5; - if (!led->active_low) - tmp |= PWM_CPR_CPOL; - pwm_channel_writel(&led->pwmc, PWM_CMR, tmp); - - /* - * Pick a period so PWM cycles at 100+ Hz; and a multiplier - * for scaling duty cycle: brightness * mult. - */ - tmp = (led->pwmc.mck / (1 << 5)) / 100; - tmp /= 255; - led->mult = tmp; - pwm_channel_writel(&led->pwmc, PWM_CDTY, - led->cdev.brightness * 255); - pwm_channel_writel(&led->pwmc, PWM_CPRD, - LED_FULL * tmp); - - pwm_channel_enable(&led->pwmc); - - /* Hand it over to the LED framework */ - status = led_classdev_register(&pdev->dev, &led->cdev); - if (status < 0) { - pwm_channel_free(&led->pwmc); - goto err; - } - } - - platform_set_drvdata(pdev, leds); - return 0; - -err: - if (i > 0) { - for (i = i - 1; i >= 0; i--) { - led_classdev_unregister(&leds[i].cdev); - pwm_channel_free(&leds[i].pwmc); - } - } - - return status; -} - -static int pwmled_remove(struct platform_device *pdev) -{ - const struct gpio_led_platform_data *pdata; - struct pwmled *leds; - unsigned i; - - pdata = dev_get_platdata(&pdev->dev); - leds = platform_get_drvdata(pdev); - - for (i = 0; i < pdata->num_leds; i++) { - struct pwmled *led = leds + i; - - led_classdev_unregister(&led->cdev); - pwm_channel_free(&led->pwmc); - } - - return 0; -} - -static struct platform_driver pwmled_driver = { - .driver = { - .name = "leds-atmel-pwm", - .owner = THIS_MODULE, - }, - /* REVISIT add suspend() and resume() methods */ - .probe = pwmled_probe, - .remove = pwmled_remove, -}; - -module_platform_driver(pwmled_driver); - -MODULE_DESCRIPTION("Driver for LEDs with PWM-controlled brightness"); -MODULE_LICENSE("GPL"); -MODULE_ALIAS("platform:leds-atmel-pwm"); diff --git a/drivers/leds/leds-gpio-register.c b/drivers/leds/leds-gpio-register.c index 1c4ed5510f35..75717ba68ae0 100644 --- a/drivers/leds/leds-gpio-register.c +++ b/drivers/leds/leds-gpio-register.c @@ -7,9 +7,9 @@ * Free Software Foundation. */ #include <linux/err.h> +#include <linux/leds.h> #include <linux/platform_device.h> #include <linux/slab.h> -#include <linux/leds.h> /** * gpio_led_register_device - register a gpio-led device @@ -28,6 +28,9 @@ struct platform_device *__init gpio_led_register_device( struct platform_device *ret; struct gpio_led_platform_data _pdata = *pdata; + if (!pdata->num_leds) + return ERR_PTR(-EINVAL); + _pdata.leds = kmemdup(pdata->leds, pdata->num_leds * sizeof(*pdata->leds), GFP_KERNEL); if (!_pdata.leds) diff --git a/drivers/leds/leds-gpio.c b/drivers/leds/leds-gpio.c index 57ff20fecf57..b4518c8751c8 100644 --- a/drivers/leds/leds-gpio.c +++ b/drivers/leds/leds-gpio.c @@ -10,17 +10,17 @@ * published by the Free Software Foundation. * */ -#include <linux/kernel.h> -#include <linux/platform_device.h> +#include <linux/err.h> #include <linux/gpio.h> +#include <linux/kernel.h> #include <linux/leds.h> +#include <linux/module.h> #include <linux/of.h> -#include <linux/of_platform.h> #include <linux/of_gpio.h> +#include <linux/of_platform.h> +#include <linux/platform_device.h> #include <linux/slab.h> #include <linux/workqueue.h> -#include <linux/module.h> -#include <linux/err.h> struct gpio_led_data { struct led_classdev cdev; @@ -36,7 +36,7 @@ struct gpio_led_data { static void gpio_led_work(struct work_struct *work) { - struct gpio_led_data *led_dat = + struct gpio_led_data *led_dat = container_of(work, struct gpio_led_data, work); if (led_dat->blinking) { @@ -235,14 +235,12 @@ static struct gpio_leds_priv *gpio_leds_create_of(struct platform_device *pdev) } #endif /* CONFIG_OF_GPIO */ - static int gpio_led_probe(struct platform_device *pdev) { struct gpio_led_platform_data *pdata = dev_get_platdata(&pdev->dev); struct gpio_leds_priv *priv; int i, ret = 0; - if (pdata && pdata->num_leds) { priv = devm_kzalloc(&pdev->dev, sizeof_gpio_leds_priv(pdata->num_leds), diff --git a/drivers/leds/leds-ipaq-micro.c b/drivers/leds/leds-ipaq-micro.c new file mode 100644 index 000000000000..3776f516cd88 --- /dev/null +++ b/drivers/leds/leds-ipaq-micro.c @@ -0,0 +1,141 @@ +/* + * 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. + * + * h3xxx atmel micro companion support, notification LED subdevice + * + * Author : Linus Walleij <linus.walleij@linaro.org> + */ + +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/mfd/ipaq-micro.h> +#include <linux/leds.h> + +#define LED_YELLOW 0x00 +#define LED_GREEN 0x01 + +#define LED_EN (1 << 4) /* LED ON/OFF 0:off, 1:on */ +#define LED_AUTOSTOP (1 << 5) /* LED ON/OFF auto stop set 0:disable, 1:enable */ +#define LED_ALWAYS (1 << 6) /* LED Interrupt Mask 0:No mask, 1:mask */ + +static void micro_leds_brightness_set(struct led_classdev *led_cdev, + enum led_brightness value) +{ + struct ipaq_micro *micro = dev_get_drvdata(led_cdev->dev->parent->parent); + /* + * In this message: + * Byte 0 = LED color: 0 = yellow, 1 = green + * yellow LED is always ~30 blinks per minute + * Byte 1 = duration (flags?) appears to be ignored + * Byte 2 = green ontime in 1/10 sec (deciseconds) + * 1 = 1/10 second + * 0 = 256/10 second + * Byte 3 = green offtime in 1/10 sec (deciseconds) + * 1 = 1/10 second + * 0 = 256/10 seconds + */ + struct ipaq_micro_msg msg = { + .id = MSG_NOTIFY_LED, + .tx_len = 4, + }; + + msg.tx_data[0] = LED_GREEN; + msg.tx_data[1] = 0; + if (value) { + msg.tx_data[2] = 0; /* Duty cycle 256 */ + msg.tx_data[3] = 1; + } else { + msg.tx_data[2] = 1; + msg.tx_data[3] = 0; /* Duty cycle 256 */ + } + ipaq_micro_tx_msg_sync(micro, &msg); +} + +/* Maximum duty cycle in ms 256/10 sec = 25600 ms */ +#define IPAQ_LED_MAX_DUTY 25600 + +static int micro_leds_blink_set(struct led_classdev *led_cdev, + unsigned long *delay_on, + unsigned long *delay_off) +{ + struct ipaq_micro *micro = dev_get_drvdata(led_cdev->dev->parent->parent); + /* + * In this message: + * Byte 0 = LED color: 0 = yellow, 1 = green + * yellow LED is always ~30 blinks per minute + * Byte 1 = duration (flags?) appears to be ignored + * Byte 2 = green ontime in 1/10 sec (deciseconds) + * 1 = 1/10 second + * 0 = 256/10 second + * Byte 3 = green offtime in 1/10 sec (deciseconds) + * 1 = 1/10 second + * 0 = 256/10 seconds + */ + struct ipaq_micro_msg msg = { + .id = MSG_NOTIFY_LED, + .tx_len = 4, + }; + + msg.tx_data[0] = LED_GREEN; + if (*delay_on > IPAQ_LED_MAX_DUTY || + *delay_off > IPAQ_LED_MAX_DUTY) + return -EINVAL; + + if (*delay_on == 0 && *delay_off == 0) { + *delay_on = 100; + *delay_off = 100; + } + + msg.tx_data[1] = 0; + if (*delay_on >= IPAQ_LED_MAX_DUTY) + msg.tx_data[2] = 0; + else + msg.tx_data[2] = (u8) DIV_ROUND_CLOSEST(*delay_on, 100); + if (*delay_off >= IPAQ_LED_MAX_DUTY) + msg.tx_data[3] = 0; + else + msg.tx_data[3] = (u8) DIV_ROUND_CLOSEST(*delay_off, 100); + return ipaq_micro_tx_msg_sync(micro, &msg); +} + +static struct led_classdev micro_led = { + .name = "led-ipaq-micro", + .brightness_set = micro_leds_brightness_set, + .blink_set = micro_leds_blink_set, + .flags = LED_CORE_SUSPENDRESUME, +}; + +static int micro_leds_probe(struct platform_device *pdev) +{ + int ret; + + ret = led_classdev_register(&pdev->dev, µ_led); + if (ret) { + dev_err(&pdev->dev, "registering led failed: %d\n", ret); + return ret; + } + dev_info(&pdev->dev, "iPAQ micro notification LED driver\n"); + + return 0; +} + +static int micro_leds_remove(struct platform_device *pdev) +{ + led_classdev_unregister(µ_led); + return 0; +} + +static struct platform_driver micro_leds_device_driver = { + .driver = { + .name = "ipaq-micro-leds", + }, + .probe = micro_leds_probe, + .remove = micro_leds_remove, +}; +module_platform_driver(micro_leds_device_driver); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("driver for iPAQ Atmel micro leds"); +MODULE_ALIAS("platform:ipaq-micro-leds"); diff --git a/drivers/leds/leds-lm3530.c b/drivers/leds/leds-lm3530.c index 652368c2ea9a..91325de3cd33 100644 --- a/drivers/leds/leds-lm3530.c +++ b/drivers/leds/leds-lm3530.c @@ -400,6 +400,12 @@ static ssize_t lm3530_mode_set(struct device *dev, struct device_attribute } static DEVICE_ATTR(mode, 0644, lm3530_mode_get, lm3530_mode_set); +static struct attribute *lm3530_attrs[] = { + &dev_attr_mode.attr, + NULL +}; +ATTRIBUTE_GROUPS(lm3530); + static int lm3530_probe(struct i2c_client *client, const struct i2c_device_id *id) { @@ -436,6 +442,7 @@ static int lm3530_probe(struct i2c_client *client, drvdata->led_dev.name = LM3530_LED_DEV; drvdata->led_dev.brightness_set = lm3530_brightness_set; drvdata->led_dev.max_brightness = MAX_BRIGHTNESS; + drvdata->led_dev.groups = lm3530_groups; i2c_set_clientdata(client, drvdata); @@ -461,26 +468,13 @@ static int lm3530_probe(struct i2c_client *client, return err; } - err = device_create_file(drvdata->led_dev.dev, &dev_attr_mode); - if (err < 0) { - dev_err(&client->dev, "File device creation failed: %d\n", err); - err = -ENODEV; - goto err_create_file; - } - return 0; - -err_create_file: - led_classdev_unregister(&drvdata->led_dev); - return err; } static int lm3530_remove(struct i2c_client *client) { struct lm3530_data *drvdata = i2c_get_clientdata(client); - device_remove_file(drvdata->led_dev.dev, &dev_attr_mode); - lm3530_led_disable(drvdata); led_classdev_unregister(&drvdata->led_dev); return 0; diff --git a/drivers/leds/leds-lm3533.c b/drivers/leds/leds-lm3533.c index e2c642c1169b..cbf61a40137d 100644 --- a/drivers/leds/leds-lm3533.c +++ b/drivers/leds/leds-lm3533.c @@ -645,6 +645,11 @@ static struct attribute_group lm3533_led_attribute_group = { .attrs = lm3533_led_attributes }; +static const struct attribute_group *lm3533_led_attribute_groups[] = { + &lm3533_led_attribute_group, + NULL +}; + static int lm3533_led_setup(struct lm3533_led *led, struct lm3533_led_platform_data *pdata) { @@ -692,6 +697,7 @@ static int lm3533_led_probe(struct platform_device *pdev) led->cdev.brightness_get = lm3533_led_get; led->cdev.blink_set = lm3533_led_blink_set; led->cdev.brightness = LED_OFF; + led->cdev.groups = lm3533_led_attribute_groups, led->id = pdev->id; mutex_init(&led->mutex); @@ -715,25 +721,16 @@ static int lm3533_led_probe(struct platform_device *pdev) led->cb.dev = led->cdev.dev; - ret = sysfs_create_group(&led->cdev.dev->kobj, - &lm3533_led_attribute_group); - if (ret < 0) { - dev_err(&pdev->dev, "failed to create sysfs attributes\n"); - goto err_unregister; - } - ret = lm3533_led_setup(led, pdata); if (ret) - goto err_sysfs_remove; + goto err_unregister; ret = lm3533_ctrlbank_enable(&led->cb); if (ret) - goto err_sysfs_remove; + goto err_unregister; return 0; -err_sysfs_remove: - sysfs_remove_group(&led->cdev.dev->kobj, &lm3533_led_attribute_group); err_unregister: led_classdev_unregister(&led->cdev); flush_work(&led->work); @@ -748,7 +745,6 @@ static int lm3533_led_remove(struct platform_device *pdev) dev_dbg(&pdev->dev, "%s\n", __func__); lm3533_ctrlbank_disable(&led->cb); - sysfs_remove_group(&led->cdev.dev->kobj, &lm3533_led_attribute_group); led_classdev_unregister(&led->cdev); flush_work(&led->work); diff --git a/drivers/leds/leds-lm355x.c b/drivers/leds/leds-lm355x.c index 591eb5e58ae3..f5112cb2d991 100644 --- a/drivers/leds/leds-lm355x.c +++ b/drivers/leds/leds-lm355x.c @@ -413,6 +413,12 @@ out: static DEVICE_ATTR(pattern, S_IWUSR, NULL, lm3556_indicator_pattern_store); +static struct attribute *lm355x_indicator_attrs[] = { + &dev_attr_pattern.attr, + NULL +}; +ATTRIBUTE_GROUPS(lm355x_indicator); + static const struct regmap_config lm355x_regmap = { .reg_bits = 8, .val_bits = 8, @@ -501,25 +507,18 @@ static int lm355x_probe(struct i2c_client *client, else chip->cdev_indicator.max_brightness = 8; chip->cdev_indicator.brightness_set = lm355x_indicator_brightness_set; + /* indicator pattern control only for LM3556 */ + if (id->driver_data == CHIP_LM3556) + chip->cdev_indicator.groups = lm355x_indicator_groups; err = led_classdev_register((struct device *) &client->dev, &chip->cdev_indicator); if (err < 0) goto err_create_indicator_file; - /* indicator pattern control only for LM3554 */ - if (id->driver_data == CHIP_LM3556) { - err = - device_create_file(chip->cdev_indicator.dev, - &dev_attr_pattern); - if (err < 0) - goto err_create_pattern_file; - } dev_info(&client->dev, "%s is initialized\n", lm355x_name[id->driver_data]); return 0; -err_create_pattern_file: - led_classdev_unregister(&chip->cdev_indicator); err_create_indicator_file: led_classdev_unregister(&chip->cdev_torch); err_create_torch_file: @@ -534,8 +533,6 @@ static int lm355x_remove(struct i2c_client *client) struct lm355x_reg_data *preg = chip->regs; regmap_write(chip->regmap, preg[REG_OPMODE].regno, 0); - if (chip->type == CHIP_LM3556) - device_remove_file(chip->cdev_indicator.dev, &dev_attr_pattern); led_classdev_unregister(&chip->cdev_indicator); flush_work(&chip->work_indicator); led_classdev_unregister(&chip->cdev_torch); diff --git a/drivers/leds/leds-lm3642.c b/drivers/leds/leds-lm3642.c index ceb6b3cde6fe..d3dec0132769 100644 --- a/drivers/leds/leds-lm3642.c +++ b/drivers/leds/leds-lm3642.c @@ -313,6 +313,18 @@ static const struct regmap_config lm3642_regmap = { .max_register = REG_MAX, }; +static struct attribute *lm3642_flash_attrs[] = { + &dev_attr_strobe_pin.attr, + NULL +}; +ATTRIBUTE_GROUPS(lm3642_flash); + +static struct attribute *lm3642_torch_attrs[] = { + &dev_attr_torch_pin.attr, + NULL +}; +ATTRIBUTE_GROUPS(lm3642_torch); + static int lm3642_probe(struct i2c_client *client, const struct i2c_device_id *id) { @@ -364,17 +376,13 @@ static int lm3642_probe(struct i2c_client *client, chip->cdev_flash.max_brightness = 16; chip->cdev_flash.brightness_set = lm3642_strobe_brightness_set; chip->cdev_flash.default_trigger = "flash"; + chip->cdev_flash.groups = lm3642_flash_groups, err = led_classdev_register((struct device *) &client->dev, &chip->cdev_flash); if (err < 0) { dev_err(chip->dev, "failed to register flash\n"); goto err_out; } - err = device_create_file(chip->cdev_flash.dev, &dev_attr_strobe_pin); - if (err < 0) { - dev_err(chip->dev, "failed to create strobe-pin file\n"); - goto err_create_flash_pin_file; - } /* torch */ INIT_WORK(&chip->work_torch, lm3642_deferred_torch_brightness_set); @@ -382,17 +390,13 @@ static int lm3642_probe(struct i2c_client *client, chip->cdev_torch.max_brightness = 8; chip->cdev_torch.brightness_set = lm3642_torch_brightness_set; chip->cdev_torch.default_trigger = "torch"; + chip->cdev_torch.groups = lm3642_torch_groups, err = led_classdev_register((struct device *) &client->dev, &chip->cdev_torch); if (err < 0) { dev_err(chip->dev, "failed to register torch\n"); goto err_create_torch_file; } - err = device_create_file(chip->cdev_torch.dev, &dev_attr_torch_pin); - if (err < 0) { - dev_err(chip->dev, "failed to create torch-pin file\n"); - goto err_create_torch_pin_file; - } /* indicator */ INIT_WORK(&chip->work_indicator, @@ -411,12 +415,8 @@ static int lm3642_probe(struct i2c_client *client, return 0; err_create_indicator_file: - device_remove_file(chip->cdev_torch.dev, &dev_attr_torch_pin); -err_create_torch_pin_file: led_classdev_unregister(&chip->cdev_torch); err_create_torch_file: - device_remove_file(chip->cdev_flash.dev, &dev_attr_strobe_pin); -err_create_flash_pin_file: led_classdev_unregister(&chip->cdev_flash); err_out: return err; @@ -428,10 +428,8 @@ static int lm3642_remove(struct i2c_client *client) led_classdev_unregister(&chip->cdev_indicator); flush_work(&chip->work_indicator); - device_remove_file(chip->cdev_torch.dev, &dev_attr_torch_pin); led_classdev_unregister(&chip->cdev_torch); flush_work(&chip->work_torch); - device_remove_file(chip->cdev_flash.dev, &dev_attr_strobe_pin); led_classdev_unregister(&chip->cdev_flash); flush_work(&chip->work_flash); regmap_write(chip->regmap, REG_ENABLE, 0); diff --git a/drivers/leds/leds-lp3944.c b/drivers/leds/leds-lp3944.c index 8e1abdcd4c9d..53144fb96167 100644 --- a/drivers/leds/leds-lp3944.c +++ b/drivers/leds/leds-lp3944.c @@ -335,7 +335,8 @@ static int lp3944_configure(struct i2c_client *client, } /* to expose the default value to userspace */ - led->ldev.brightness = led->status; + led->ldev.brightness = + (enum led_brightness) led->status; /* Set the default led status */ err = lp3944_led_set(led, led->status); diff --git a/drivers/leds/leds-lp55xx-common.c b/drivers/leds/leds-lp55xx-common.c index 88317b4f7bf3..77c26bc32eed 100644 --- a/drivers/leds/leds-lp55xx-common.c +++ b/drivers/leds/leds-lp55xx-common.c @@ -127,15 +127,12 @@ static DEVICE_ATTR(led_current, S_IRUGO | S_IWUSR, lp55xx_show_current, lp55xx_store_current); static DEVICE_ATTR(max_current, S_IRUGO , lp55xx_show_max_current, NULL); -static struct attribute *lp55xx_led_attributes[] = { +static struct attribute *lp55xx_led_attrs[] = { &dev_attr_led_current.attr, &dev_attr_max_current.attr, NULL, }; - -static struct attribute_group lp55xx_led_attr_group = { - .attrs = lp55xx_led_attributes -}; +ATTRIBUTE_GROUPS(lp55xx_led); static void lp55xx_set_brightness(struct led_classdev *cdev, enum led_brightness brightness) @@ -176,6 +173,7 @@ static int lp55xx_init_led(struct lp55xx_led *led, } led->cdev.brightness_set = lp55xx_set_brightness; + led->cdev.groups = lp55xx_led_groups; if (pdata->led_config[chan].name) { led->cdev.name = pdata->led_config[chan].name; @@ -185,24 +183,12 @@ static int lp55xx_init_led(struct lp55xx_led *led, led->cdev.name = name; } - /* - * register led class device for each channel and - * add device attributes - */ - ret = led_classdev_register(dev, &led->cdev); if (ret) { dev_err(dev, "led register err: %d\n", ret); return ret; } - ret = sysfs_create_group(&led->cdev.dev->kobj, &lp55xx_led_attr_group); - if (ret) { - dev_err(dev, "led sysfs err: %d\n", ret); - led_classdev_unregister(&led->cdev); - return ret; - } - return 0; } diff --git a/drivers/leds/leds-max8997.c b/drivers/leds/leds-max8997.c index f449a8bdddc7..607bc2755aba 100644 --- a/drivers/leds/leds-max8997.c +++ b/drivers/leds/leds-max8997.c @@ -229,6 +229,12 @@ static ssize_t max8997_led_store_mode(struct device *dev, static DEVICE_ATTR(mode, 0644, max8997_led_show_mode, max8997_led_store_mode); +static struct attribute *max8997_attrs[] = { + &dev_attr_mode.attr, + NULL +}; +ATTRIBUTE_GROUPS(max8997); + static int max8997_led_probe(struct platform_device *pdev) { struct max8997_dev *iodev = dev_get_drvdata(pdev->dev.parent); @@ -253,6 +259,7 @@ static int max8997_led_probe(struct platform_device *pdev) led->cdev.brightness_set = max8997_led_brightness_set; led->cdev.flags |= LED_CORE_SUSPENDRESUME; led->cdev.brightness = 0; + led->cdev.groups = max8997_groups; led->iodev = iodev; /* initialize mode and brightness according to platform_data */ @@ -281,14 +288,6 @@ static int max8997_led_probe(struct platform_device *pdev) if (ret < 0) return ret; - ret = device_create_file(led->cdev.dev, &dev_attr_mode); - if (ret != 0) { - dev_err(&pdev->dev, - "failed to create file: %d\n", ret); - led_classdev_unregister(&led->cdev); - return ret; - } - return 0; } @@ -296,7 +295,6 @@ static int max8997_led_remove(struct platform_device *pdev) { struct max8997_led *led = platform_get_drvdata(pdev); - device_remove_file(led->cdev.dev, &dev_attr_mode); led_classdev_unregister(&led->cdev); return 0; diff --git a/drivers/leds/leds-menf21bmc.c b/drivers/leds/leds-menf21bmc.c new file mode 100644 index 000000000000..89dd57769e3b --- /dev/null +++ b/drivers/leds/leds-menf21bmc.c @@ -0,0 +1,131 @@ +/* + * MEN 14F021P00 Board Management Controller (BMC) LEDs Driver. + * + * This is the core LED driver of the MEN 14F021P00 BMC. + * There are four LEDs available which can be switched on and off. + * STATUS LED, HOT SWAP LED, USER LED 1, USER LED 2 + * + * Copyright (C) 2014 MEN Mikro Elektronik Nuernberg GmbH + * + * 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. + */ + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/platform_device.h> +#include <linux/leds.h> +#include <linux/i2c.h> + +#define BMC_CMD_LED_GET_SET 0xA0 +#define BMC_BIT_LED_STATUS BIT(0) +#define BMC_BIT_LED_HOTSWAP BIT(1) +#define BMC_BIT_LED_USER1 BIT(2) +#define BMC_BIT_LED_USER2 BIT(3) + +struct menf21bmc_led { + struct led_classdev cdev; + u8 led_bit; + const char *name; + struct i2c_client *i2c_client; +}; + +static struct menf21bmc_led leds[] = { + { + .name = "menf21bmc:led_status", + .led_bit = BMC_BIT_LED_STATUS, + }, + { + .name = "menf21bmc:led_hotswap", + .led_bit = BMC_BIT_LED_HOTSWAP, + }, + { + .name = "menf21bmc:led_user1", + .led_bit = BMC_BIT_LED_USER1, + }, + { + .name = "menf21bmc:led_user2", + .led_bit = BMC_BIT_LED_USER2, + } +}; + +static DEFINE_MUTEX(led_lock); + +static void +menf21bmc_led_set(struct led_classdev *led_cdev, enum led_brightness value) +{ + int led_val; + struct menf21bmc_led *led = container_of(led_cdev, + struct menf21bmc_led, cdev); + + mutex_lock(&led_lock); + led_val = i2c_smbus_read_byte_data(led->i2c_client, + BMC_CMD_LED_GET_SET); + if (led_val < 0) + goto err_out; + + if (value == LED_OFF) + led_val &= ~led->led_bit; + else + led_val |= led->led_bit; + + i2c_smbus_write_byte_data(led->i2c_client, + BMC_CMD_LED_GET_SET, led_val); +err_out: + mutex_unlock(&led_lock); +} + +static int menf21bmc_led_probe(struct platform_device *pdev) +{ + int i; + int ret; + struct i2c_client *i2c_client = to_i2c_client(pdev->dev.parent); + + for (i = 0; i < ARRAY_SIZE(leds); i++) { + leds[i].cdev.name = leds[i].name; + leds[i].cdev.brightness_set = menf21bmc_led_set; + leds[i].i2c_client = i2c_client; + ret = led_classdev_register(&pdev->dev, &leds[i].cdev); + if (ret < 0) + goto err_free_leds; + } + dev_info(&pdev->dev, "MEN 140F21P00 BMC LED device enabled\n"); + + return 0; + +err_free_leds: + dev_err(&pdev->dev, "failed to register LED device\n"); + + for (i = i - 1; i >= 0; i--) + led_classdev_unregister(&leds[i].cdev); + + return ret; +} + +static int menf21bmc_led_remove(struct platform_device *pdev) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(leds); i++) + led_classdev_unregister(&leds[i].cdev); + + return 0; +} + +static struct platform_driver menf21bmc_led = { + .probe = menf21bmc_led_probe, + .remove = menf21bmc_led_remove, + .driver = { + .name = "menf21bmc_led", + .owner = THIS_MODULE, + }, +}; + +module_platform_driver(menf21bmc_led); + +MODULE_AUTHOR("Andreas Werner <andreas.werner@men.de>"); +MODULE_DESCRIPTION("MEN 14F021P00 BMC led driver"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:menf21bmc_led"); diff --git a/drivers/leds/leds-netxbig.c b/drivers/leds/leds-netxbig.c index e97f443a6e07..64fde485dcaa 100644 --- a/drivers/leds/leds-netxbig.c +++ b/drivers/leds/leds-netxbig.c @@ -293,10 +293,14 @@ static ssize_t netxbig_led_sata_show(struct device *dev, static DEVICE_ATTR(sata, 0644, netxbig_led_sata_show, netxbig_led_sata_store); +static struct attribute *netxbig_led_attrs[] = { + &dev_attr_sata.attr, + NULL +}; +ATTRIBUTE_GROUPS(netxbig_led); + static void delete_netxbig_led(struct netxbig_led_data *led_dat) { - if (led_dat->mode_val[NETXBIG_LED_SATA] != NETXBIG_LED_INVALID_MODE) - device_remove_file(led_dat->cdev.dev, &dev_attr_sata); led_classdev_unregister(&led_dat->cdev); } @@ -306,7 +310,6 @@ create_netxbig_led(struct platform_device *pdev, const struct netxbig_led *template) { struct netxbig_led_platform_data *pdata = dev_get_platdata(&pdev->dev); - int ret; spin_lock_init(&led_dat->lock); led_dat->gpio_ext = pdata->gpio_ext; @@ -327,6 +330,12 @@ create_netxbig_led(struct platform_device *pdev, led_dat->sata = 0; led_dat->cdev.brightness = LED_OFF; led_dat->cdev.flags |= LED_CORE_SUSPENDRESUME; + /* + * If available, expose the SATA activity blink capability through + * a "sata" sysfs attribute. + */ + if (led_dat->mode_val[NETXBIG_LED_SATA] != NETXBIG_LED_INVALID_MODE) + led_dat->cdev.groups = netxbig_led_groups; led_dat->mode_addr = template->mode_addr; led_dat->mode_val = template->mode_val; led_dat->bright_addr = template->bright_addr; @@ -334,21 +343,7 @@ create_netxbig_led(struct platform_device *pdev, led_dat->timer = pdata->timer; led_dat->num_timer = pdata->num_timer; - ret = led_classdev_register(&pdev->dev, &led_dat->cdev); - if (ret < 0) - return ret; - - /* - * If available, expose the SATA activity blink capability through - * a "sata" sysfs attribute. - */ - if (led_dat->mode_val[NETXBIG_LED_SATA] != NETXBIG_LED_INVALID_MODE) { - ret = device_create_file(led_dat->cdev.dev, &dev_attr_sata); - if (ret) - led_classdev_unregister(&led_dat->cdev); - } - - return ret; + return led_classdev_register(&pdev->dev, &led_dat->cdev); } static int netxbig_led_probe(struct platform_device *pdev) diff --git a/drivers/leds/leds-ns2.c b/drivers/leds/leds-ns2.c index efa625883c83..231993d1fe21 100644 --- a/drivers/leds/leds-ns2.c +++ b/drivers/leds/leds-ns2.c @@ -185,6 +185,12 @@ static ssize_t ns2_led_sata_show(struct device *dev, static DEVICE_ATTR(sata, 0644, ns2_led_sata_show, ns2_led_sata_store); +static struct attribute *ns2_led_attrs[] = { + &dev_attr_sata.attr, + NULL +}; +ATTRIBUTE_GROUPS(ns2_led); + static int create_ns2_led(struct platform_device *pdev, struct ns2_led_data *led_dat, const struct ns2_led *template) @@ -219,6 +225,7 @@ create_ns2_led(struct platform_device *pdev, struct ns2_led_data *led_dat, led_dat->cdev.blink_set = NULL; led_dat->cdev.brightness_set = ns2_led_set; led_dat->cdev.flags |= LED_CORE_SUSPENDRESUME; + led_dat->cdev.groups = ns2_led_groups; led_dat->cmd = template->cmd; led_dat->slow = template->slow; @@ -235,20 +242,11 @@ create_ns2_led(struct platform_device *pdev, struct ns2_led_data *led_dat, if (ret < 0) return ret; - ret = device_create_file(led_dat->cdev.dev, &dev_attr_sata); - if (ret < 0) - goto err_free_cdev; - return 0; - -err_free_cdev: - led_classdev_unregister(&led_dat->cdev); - return ret; } static void delete_ns2_led(struct ns2_led_data *led_dat) { - device_remove_file(led_dat->cdev.dev, &dev_attr_sata); led_classdev_unregister(&led_dat->cdev); } diff --git a/drivers/leds/leds-pca9532.c b/drivers/leds/leds-pca9532.c index 4a0e786b7832..5a6363d161a2 100644 --- a/drivers/leds/leds-pca9532.c +++ b/drivers/leds/leds-pca9532.c @@ -319,14 +319,8 @@ static int pca9532_destroy_devices(struct pca9532_data *data, int n_devs) } #ifdef CONFIG_LEDS_PCA9532_GPIO - if (data->gpio.dev) { - int err = gpiochip_remove(&data->gpio); - if (err) { - dev_err(&data->client->dev, "%s failed, %d\n", - "gpiochip_remove()", err); - return err; - } - } + if (data->gpio.dev) + gpiochip_remove(&data->gpio); #endif return 0; diff --git a/drivers/leds/leds-pca963x.c b/drivers/leds/leds-pca963x.c index 82589c0a5689..f110b4c456ba 100644 --- a/drivers/leds/leds-pca963x.c +++ b/drivers/leds/leds-pca963x.c @@ -12,7 +12,7 @@ * directory of this archive for more details. * * LED driver for the PCA9633 I2C LED driver (7-bit slave address 0x62) - * LED driver for the PCA9634 I2C LED driver (7-bit slave address set by hw.) + * LED driver for the PCA9634/5 I2C LED driver (7-bit slave address set by hw.) * * Note that hardware blinking violates the leds infrastructure driver * interface since the hardware only supports blinking all LEDs with the @@ -52,6 +52,7 @@ enum pca963x_type { pca9633, pca9634, + pca9635, }; struct pca963x_chipdef { @@ -74,6 +75,12 @@ static struct pca963x_chipdef pca963x_chipdefs[] = { .ledout_base = 0xc, .n_leds = 8, }, + [pca9635] = { + .grppwm = 0x12, + .grpfreq = 0x13, + .ledout_base = 0x14, + .n_leds = 16, + }, }; /* Total blink period in milliseconds */ @@ -84,6 +91,7 @@ static const struct i2c_device_id pca963x_id[] = { { "pca9632", pca9633 }, { "pca9633", pca9633 }, { "pca9634", pca9634 }, + { "pca9635", pca9635 }, { } }; MODULE_DEVICE_TABLE(i2c, pca963x_id); @@ -107,7 +115,7 @@ struct pca963x_led { struct work_struct work; enum led_brightness brightness; struct led_classdev led_cdev; - int led_num; /* 0 .. 7 potentially */ + int led_num; /* 0 .. 15 potentially */ enum pca963x_cmd cmd; char name[32]; u8 gdc; @@ -321,6 +329,7 @@ static const struct of_device_id of_pca963x_match[] = { { .compatible = "nxp,pca9632", }, { .compatible = "nxp,pca9633", }, { .compatible = "nxp,pca9634", }, + { .compatible = "nxp,pca9635", }, {}, }; #else @@ -375,9 +384,8 @@ static int pca963x_probe(struct i2c_client *client, pca963x_chip->leds = pca963x; /* Turn off LEDs by default*/ - i2c_smbus_write_byte_data(client, chip->ledout_base, 0x00); - if (chip->n_leds > 4) - i2c_smbus_write_byte_data(client, chip->ledout_base + 1, 0x00); + for (i = 0; i < chip->n_leds / 4; i++) + i2c_smbus_write_byte_data(client, chip->ledout_base + i, 0x00); for (i = 0; i < chip->n_leds; i++) { pca963x[i].led_num = i; @@ -415,9 +423,13 @@ static int pca963x_probe(struct i2c_client *client, /* Disable LED all-call address and set normal mode */ i2c_smbus_write_byte_data(client, PCA963X_MODE1, 0x00); - /* Configure output: open-drain or totem pole (push-pull) */ - if (pdata && pdata->outdrv == PCA963X_OPEN_DRAIN) - i2c_smbus_write_byte_data(client, PCA963X_MODE2, 0x01); + if (pdata) { + /* Configure output: open-drain or totem pole (push-pull) */ + if (pdata->outdrv == PCA963X_OPEN_DRAIN) + i2c_smbus_write_byte_data(client, PCA963X_MODE2, 0x01); + else + i2c_smbus_write_byte_data(client, PCA963X_MODE2, 0x05); + } return 0; diff --git a/drivers/leds/leds-ss4200.c b/drivers/leds/leds-ss4200.c index 2eb3ef62962b..046cb7008745 100644 --- a/drivers/leds/leds-ss4200.c +++ b/drivers/leds/leds-ss4200.c @@ -469,6 +469,12 @@ static ssize_t nas_led_blink_store(struct device *dev, static DEVICE_ATTR(blink, 0644, nas_led_blink_show, nas_led_blink_store); +static struct attribute *nasgpio_led_attrs[] = { + &dev_attr_blink.attr, + NULL +}; +ATTRIBUTE_GROUPS(nasgpio_led); + static int register_nasgpio_led(int led_nr) { int ret; @@ -481,20 +487,18 @@ static int register_nasgpio_led(int led_nr) led->brightness = LED_FULL; led->brightness_set = nasgpio_led_set_brightness; led->blink_set = nasgpio_led_set_blink; + led->groups = nasgpio_led_groups; ret = led_classdev_register(&nas_gpio_pci_dev->dev, led); if (ret) return ret; - ret = device_create_file(led->dev, &dev_attr_blink); - if (ret) - led_classdev_unregister(led); - return ret; + + return 0; } static void unregister_nasgpio_led(int led_nr) { struct led_classdev *led = get_classdev_for_led_nr(led_nr); led_classdev_unregister(led); - device_remove_file(led->dev, &dev_attr_blink); } /* * module load/initialization diff --git a/drivers/leds/leds-syscon.c b/drivers/leds/leds-syscon.c new file mode 100644 index 000000000000..3afec79c43f4 --- /dev/null +++ b/drivers/leds/leds-syscon.c @@ -0,0 +1,166 @@ +/* + * Generic Syscon LEDs Driver + * + * Copyright (c) 2014, Linaro Limited + * Author: Linus Walleij <linus.walleij@linaro.org> + * + * 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. + * + * 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 Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * This driver provides system reboot functionality for APM X-Gene SoC. + * For system shutdown, this is board specify. If a board designer + * implements GPIO shutdown, use the gpio-poweroff.c driver. + */ +#include <linux/io.h> +#include <linux/of_device.h> +#include <linux/of_address.h> +#include <linux/platform_device.h> +#include <linux/stat.h> +#include <linux/slab.h> +#include <linux/mfd/syscon.h> +#include <linux/regmap.h> +#include <linux/leds.h> + +/** + * struct syscon_led - state container for syscon based LEDs + * @cdev: LED class device for this LED + * @map: regmap to access the syscon device backing this LED + * @offset: the offset into the syscon regmap for the LED register + * @mask: the bit in the register corresponding to the LED + * @state: current state of the LED + */ +struct syscon_led { + struct led_classdev cdev; + struct regmap *map; + u32 offset; + u32 mask; + bool state; +}; + +static void syscon_led_set(struct led_classdev *led_cdev, + enum led_brightness value) +{ + struct syscon_led *sled = + container_of(led_cdev, struct syscon_led, cdev); + u32 val; + int ret; + + if (value == LED_OFF) { + val = 0; + sled->state = false; + } else { + val = sled->mask; + sled->state = true; + } + + ret = regmap_update_bits(sled->map, sled->offset, sled->mask, val); + if (ret < 0) + dev_err(sled->cdev.dev, "error updating LED status\n"); +} + +static const struct of_device_id syscon_match[] = { + { .compatible = "syscon", }, + {}, +}; + +static int __init syscon_leds_init(void) +{ + const struct of_device_id *devid; + struct device_node *np; + struct device_node *child; + struct regmap *map; + struct platform_device *pdev; + struct device *dev; + int ret; + + np = of_find_matching_node_and_match(NULL, syscon_match, + &devid); + if (!np) + return -ENODEV; + + map = syscon_node_to_regmap(np); + if (IS_ERR(map)) + return PTR_ERR(map); + + /* + * If the map is there, the device should be there, we allocate + * memory on the syscon device's behalf here. + */ + pdev = of_find_device_by_node(np); + if (!pdev) + return -ENODEV; + dev = &pdev->dev; + + for_each_available_child_of_node(np, child) { + struct syscon_led *sled; + const char *state; + + /* Only check for register-bit-leds */ + if (of_property_match_string(child, "compatible", + "register-bit-led") < 0) + continue; + + sled = devm_kzalloc(dev, sizeof(*sled), GFP_KERNEL); + if (!sled) + return -ENOMEM; + + sled->map = map; + + if (of_property_read_u32(child, "offset", &sled->offset)) + return -EINVAL; + if (of_property_read_u32(child, "mask", &sled->mask)) + return -EINVAL; + sled->cdev.name = + of_get_property(child, "label", NULL) ? : child->name; + sled->cdev.default_trigger = + of_get_property(child, "linux,default-trigger", NULL); + + state = of_get_property(child, "default-state", NULL); + if (state) { + if (!strcmp(state, "keep")) { + u32 val; + + ret = regmap_read(map, sled->offset, &val); + if (ret < 0) + return ret; + sled->state = !!(val & sled->mask); + } else if (!strcmp(state, "on")) { + sled->state = true; + ret = regmap_update_bits(map, sled->offset, + sled->mask, + sled->mask); + if (ret < 0) + return ret; + } else { + sled->state = false; + ret = regmap_update_bits(map, sled->offset, + sled->mask, 0); + if (ret < 0) + return ret; + } + + } + sled->cdev.brightness_set = syscon_led_set; + + ret = led_classdev_register(dev, &sled->cdev); + if (ret < 0) + return ret; + + dev_info(dev, "registered LED %s\n", sled->cdev.name); + } + + return 0; +} +device_initcall(syscon_leds_init); diff --git a/drivers/leds/leds-tca6507.c b/drivers/leds/leds-tca6507.c index 3d9e267a56c4..20fa8e77f186 100644 --- a/drivers/leds/leds-tca6507.c +++ b/drivers/leds/leds-tca6507.c @@ -667,11 +667,8 @@ static int tca6507_probe_gpios(struct i2c_client *client, static void tca6507_remove_gpio(struct tca6507_chip *tca) { - if (tca->gpio.ngpio) { - int err = gpiochip_remove(&tca->gpio); - dev_err(&tca->client->dev, "%s failed, %d\n", - "gpiochip_remove()", err); - } + if (tca->gpio.ngpio) + gpiochip_remove(&tca->gpio); } #else /* CONFIG_GPIOLIB */ static int tca6507_probe_gpios(struct i2c_client *client, diff --git a/drivers/leds/leds-wm831x-status.c b/drivers/leds/leds-wm831x-status.c index e72c974142d0..1b71e0701002 100644 --- a/drivers/leds/leds-wm831x-status.c +++ b/drivers/leds/leds-wm831x-status.c @@ -219,6 +219,12 @@ static ssize_t wm831x_status_src_store(struct device *dev, static DEVICE_ATTR(src, 0644, wm831x_status_src_show, wm831x_status_src_store); +static struct attribute *wm831x_status_attrs[] = { + &dev_attr_src.attr, + NULL +}; +ATTRIBUTE_GROUPS(wm831x_status); + static int wm831x_status_probe(struct platform_device *pdev) { struct wm831x *wm831x = dev_get_drvdata(pdev->dev.parent); @@ -232,8 +238,7 @@ static int wm831x_status_probe(struct platform_device *pdev) res = platform_get_resource(pdev, IORESOURCE_REG, 0); if (res == NULL) { dev_err(&pdev->dev, "No register resource\n"); - ret = -EINVAL; - goto err; + return -EINVAL; } drvdata = devm_kzalloc(&pdev->dev, sizeof(struct wm831x_status), @@ -284,31 +289,21 @@ static int wm831x_status_probe(struct platform_device *pdev) drvdata->cdev.default_trigger = pdata.default_trigger; drvdata->cdev.brightness_set = wm831x_status_set; drvdata->cdev.blink_set = wm831x_status_blink_set; + drvdata->cdev.groups = wm831x_status_groups; 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; + return ret; } - 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); -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); return 0; diff --git a/drivers/leds/trigger/ledtrig-gpio.c b/drivers/leds/trigger/ledtrig-gpio.c index 35812e3a37f2..c86c41826476 100644 --- a/drivers/leds/trigger/ledtrig-gpio.c +++ b/drivers/leds/trigger/ledtrig-gpio.c @@ -48,7 +48,7 @@ static void gpio_trig_work(struct work_struct *work) if (!gpio_data->gpio) return; - tmp = gpio_get_value(gpio_data->gpio); + tmp = gpio_get_value_cansleep(gpio_data->gpio); if (gpio_data->inverted) tmp = !tmp; |