Commit e8a2a176 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'leds_for_4.4' of git://git.kernel.org/pub/scm/linux/kernel/git/j.anaszewski/linux-leds

Pull LED updates from Jacek Anaszewski:

 - Move the out-of-LED-tree led-sead3 driver to the LED subsystem.

 - Add 'invert' sysfs attribute to the heartbeat trigger.

 - Add Device Tree support to the leds-netxbig driver and add related DT
   nodes to the kirkwood-netxbig.dtsi and kirkwood-net5big.dts files.
   Remove static LED setup from the related board files.

 - Remove redundant brightness conversion operation from leds-netxbig.

 - Improve leds-bcm6328 driver: improve default-state handling, add more
   init configuration options, print invalid LED instead of warning only
   about maximum LED value.

 - Add a shutdown function for setting gpio-leds into off state when
   shutting down.

 - Fix DT flash timeout property naming in leds-aat1290.txt.

 - Switch to using devm prefixed version of led_classdev_register()
   (leds-cobalt-qube, leds-hp6xx, leds-ot200, leds-ipaq-micro,
   leds-netxbig, leds-locomo, leds-menf21bmc, leds-net48xx, leds-wrap).

 - Add missing of_node_put (leds-powernv, leds-bcm6358, leds-bcm6328,
   leds-88pm860x).

 - Coding style fixes and cleanups: led-class/led-core, leds-ipaq-micro.

* tag 'leds_for_4.4' of git://git.kernel.org/pub/scm/linux/kernel/git/j.anaszewski/linux-leds: (27 commits)
  leds: 88pm860x: add missing of_node_put
  leds: bcm6328: add missing of_node_put
  leds: bcm6358: add missing of_node_put
  powerpc/powernv: add missing of_node_put
  leds: leds-wrap.c: Use devm_led_classdev_register
  leds: aat1290: Fix property naming of flash-timeout-us
  leds: leds-net48xx: Use devm_led_classdev_register
  leds: leds-menf21bmc.c: Use devm_led_class_register
  leds: leds-locomo.c: Use devm_led_classdev_register
  leds: leds-gpio: add shutdown function
  Documentation: leds: update DT bindings for leds-bcm6328
  leds-bcm6328: add more init configuration options
  leds-bcm6328: simplify and improve default-state handling
  leds-bcm6328: print invalid LED
  leds: netxbig: set led_classdev max_brightness
  leds: netxbig: convert to use the devm_ functions
  ARM: mvebu: remove static LED setup for netxbig boards
  ARM: Kirkwood: add LED DT entries for netxbig boards
  leds: netxbig: add device tree binding
  leds: triggers: add invert to heartbeat
  ...
parents 5062ecdb ffdc307d
Binding for the GPIO extension bus found on some LaCie/Seagate boards
(Example: 2Big/5Big Network v2, 2Big NAS).
Required properties:
- compatible: "lacie,netxbig-gpio-ext".
- addr-gpios: GPIOs representing the address register (LSB -> MSB).
- data-gpios: GPIOs representing the data register (LSB -> MSB).
- enable-gpio: latches the new configuration (address, data) on raising edge.
Example:
netxbig_gpio_ext: netxbig-gpio-ext {
compatible = "lacie,netxbig-gpio-ext";
addr-gpios = <&gpio1 15 GPIO_ACTIVE_HIGH
&gpio1 16 GPIO_ACTIVE_HIGH
&gpio1 17 GPIO_ACTIVE_HIGH>;
data-gpios = <&gpio1 12 GPIO_ACTIVE_HIGH
&gpio1 13 GPIO_ACTIVE_HIGH
&gpio1 14 GPIO_ACTIVE_HIGH>;
enable-gpio = <&gpio0 29 GPIO_ACTIVE_HIGH>;
};
......@@ -27,9 +27,9 @@ Required properties of the LED child node:
- flash-max-microamp : see Documentation/devicetree/bindings/leds/common.txt
Maximum flash LED supply current can be calculated using
following formula: I = 1A * 162kohm / Rset.
- flash-timeout-us : see Documentation/devicetree/bindings/leds/common.txt
Maximum flash timeout can be calculated using following
formula: T = 8.82 * 10^9 * Ct.
- flash-max-timeout-us : see Documentation/devicetree/bindings/leds/common.txt
Maximum flash timeout can be calculated using following
formula: T = 8.82 * 10^9 * Ct.
Optional properties of the LED child node:
- label : see Documentation/devicetree/bindings/leds/common.txt
......@@ -54,7 +54,7 @@ aat1290 {
label = "aat1290-flash";
led-max-microamp = <520833>;
flash-max-microamp = <1012500>;
flash-timeout-us = <1940000>;
flash-max-timeout-us = <1940000>;
};
};
......
......@@ -29,6 +29,14 @@ Required properties:
Optional properties:
- brcm,serial-leds : Boolean, enables Serial LEDs.
Default : false
- brcm,serial-mux : Boolean, enables Serial LEDs multiplexing.
Default : false
- brcm,serial-clk-low : Boolean, makes clock signal active low.
Default : false
- brcm,serial-dat-low : Boolean, makes data signal active low.
Default : false
- brcm,serial-shift-inv : Boolean, inverts Serial LEDs shift direction.
Default : false
Each LED is represented as a sub-node of the brcm,bcm6328-leds device.
......@@ -110,6 +118,8 @@ Scenario 2 : BCM63268 with Serial/GPHY0 LEDs
#size-cells = <0>;
reg = <0x10001900 0x24>;
brcm,serial-leds;
brcm,serial-dat-low;
brcm,serial-shift-inv;
gphy0_spd0@0 {
reg = <0>;
......
Binding for the CPLD LEDs (GPIO extension bus) found on some LaCie/Seagate
boards (Example: 2Big/5Big Network v2, 2Big NAS).
Required properties:
- compatible: "lacie,netxbig-leds".
- gpio-ext: Phandle for the gpio-ext bus.
Optional properties:
- timers: Timer array. Each timer entry is represented by three integers:
Mode (gpio-ext bus), delay_on and delay_off.
Each LED is represented as a sub-node of the netxbig-leds device.
Required sub-node properties:
- mode-addr: Mode register address on gpio-ext bus.
- mode-val: Mode to value mapping. Each entry is represented by two integers:
A mode and the corresponding value on the gpio-ext bus.
- bright-addr: Brightness register address on gpio-ext bus.
- max-brightness: Maximum brightness value.
Optional sub-node properties:
- label: Name for this LED. If omitted, the label is taken from the node name.
- linux,default-trigger: Trigger assigned to the LED.
Example:
netxbig-leds {
compatible = "lacie,netxbig-leds";
gpio-ext = &gpio_ext;
timers = <NETXBIG_LED_TIMER1 500 500
NETXBIG_LED_TIMER2 500 1000>;
blue-power {
label = "netxbig:blue:power";
mode-addr = <0>;
mode-val = <NETXBIG_LED_OFF 0
NETXBIG_LED_ON 1
NETXBIG_LED_TIMER1 3
NETXBIG_LED_TIMER2 7>;
bright-addr = <1>;
max-brightness = <7>;
};
red-power {
label = "netxbig:red:power";
mode-addr = <0>;
mode-val = <NETXBIG_LED_OFF 0
NETXBIG_LED_ON 2
NETXBIG_LED_TIMER1 4>;
bright-addr = <1>;
max-brightness = <7>;
};
blue-sata0 {
label = "netxbig:blue:sata0";
mode-addr = <3>;
mode-val = <NETXBIG_LED_OFF 0
NETXBIG_LED_ON 7
NETXBIG_LED_SATA 1
NETXBIG_LED_TIMER1 3>;
bright-addr = <2>;
max-brightness = <7>;
};
red-sata0 {
label = "netxbig:red:sata0";
mode-addr = <3>;
mode-val = <NETXBIG_LED_OFF 0
NETXBIG_LED_ON 2
NETXBIG_LED_TIMER1 4>;
bright-addr = <2>;
max-brightness = <7>;
};
blue-sata1 {
label = "netxbig:blue:sata1";
mode-addr = <4>;
mode-val = <NETXBIG_LED_OFF 0
NETXBIG_LED_ON 7
NETXBIG_LED_SATA 1
NETXBIG_LED_TIMER1 3>;
bright-addr = <2>;
max-brightness = <7>;
};
red-sata1 {
label = "netxbig:red:sata1";
mode-addr = <4>;
mode-val = <NETXBIG_LED_OFF 0
NETXBIG_LED_ON 2
NETXBIG_LED_TIMER1 4>;
bright-addr = <2>;
max-brightness = <7>;
};
};
......@@ -86,6 +86,66 @@ g762_clk: g762-oscillator {
clock-frequency = <32768>;
};
};
netxbig-leds {
blue-sata2 {
label = "netxbig:blue:sata2";
mode-addr = <5>;
mode-val = <NETXBIG_LED_OFF 0
NETXBIG_LED_ON 7
NETXBIG_LED_SATA 1
NETXBIG_LED_TIMER1 3>;
bright-addr = <2>;
max-brightness = <7>;
};
red-sata2 {
label = "netxbig:red:sata2";
mode-addr = <5>;
mode-val = <NETXBIG_LED_OFF 0
NETXBIG_LED_ON 2
NETXBIG_LED_TIMER1 4>;
bright-addr = <2>;
max-brightness = <7>;
};
blue-sata3 {
label = "netxbig:blue:sata3";
mode-addr = <6>;
mode-val = <NETXBIG_LED_OFF 0
NETXBIG_LED_ON 7
NETXBIG_LED_SATA 1
NETXBIG_LED_TIMER1 3>;
bright-addr = <2>;
max-brightness = <7>;
};
red-sata3 {
label = "netxbig:red:sata3";
mode-addr = <6>;
mode-val = <NETXBIG_LED_OFF 0
NETXBIG_LED_ON 2
NETXBIG_LED_TIMER1 4>;
bright-addr = <2>;
max-brightness = <7>;
};
blue-sata4 {
label = "netxbig:blue:sata4";
mode-addr = <7>;
mode-val = <NETXBIG_LED_OFF 0
NETXBIG_LED_ON 7
NETXBIG_LED_SATA 1
NETXBIG_LED_TIMER1 3>;
bright-addr = <2>;
max-brightness = <7>;
};
red-sata4 {
label = "netxbig:red:sata4";
mode-addr = <7>;
mode-val = <NETXBIG_LED_OFF 0
NETXBIG_LED_ON 2
NETXBIG_LED_TIMER1 4>;
bright-addr = <2>;
max-brightness = <7>;
};
};
};
&mdio {
......
......@@ -13,6 +13,7 @@
* warranty of any kind, whether express or implied.
*/
#include <dt-bindings/leds/leds-netxbig.h>
#include "kirkwood.dtsi"
#include "kirkwood-6281.dtsi"
......@@ -105,6 +106,85 @@ regulator@1 {
gpio = <&gpio0 16 GPIO_ACTIVE_HIGH>;
};
};
netxbig_gpio_ext: netxbig-gpio-ext {
compatible = "lacie,netxbig-gpio-ext";
addr-gpios = <&gpio1 15 GPIO_ACTIVE_HIGH
&gpio1 16 GPIO_ACTIVE_HIGH
&gpio1 17 GPIO_ACTIVE_HIGH>;
data-gpios = <&gpio1 12 GPIO_ACTIVE_HIGH
&gpio1 13 GPIO_ACTIVE_HIGH
&gpio1 14 GPIO_ACTIVE_HIGH>;
enable-gpio = <&gpio0 29 GPIO_ACTIVE_HIGH>;
};
netxbig-leds {
compatible = "lacie,netxbig-leds";
gpio-ext = <&netxbig_gpio_ext>;
timers = <NETXBIG_LED_TIMER1 500 500
NETXBIG_LED_TIMER2 500 1000>;
blue-power {
label = "netxbig:blue:power";
mode-addr = <0>;
mode-val = <NETXBIG_LED_OFF 0
NETXBIG_LED_ON 1
NETXBIG_LED_TIMER1 3
NETXBIG_LED_TIMER2 7>;
bright-addr = <1>;
max-brightness = <7>;
};
red-power {
label = "netxbig:red:power";
mode-addr = <0>;
mode-val = <NETXBIG_LED_OFF 0
NETXBIG_LED_ON 2
NETXBIG_LED_TIMER1 4>;
bright-addr = <1>;
max-brightness = <7>;
};
blue-sata0 {
label = "netxbig:blue:sata0";
mode-addr = <3>;
mode-val = <NETXBIG_LED_OFF 0
NETXBIG_LED_ON 7
NETXBIG_LED_SATA 1
NETXBIG_LED_TIMER1 3>;
bright-addr = <2>;
max-brightness = <7>;
};
red-sata0 {
label = "netxbig:red:sata0";
mode-addr = <3>;
mode-val = <NETXBIG_LED_OFF 0
NETXBIG_LED_ON 2
NETXBIG_LED_TIMER1 4>;
bright-addr = <2>;
max-brightness = <7>;
};
blue-sata1 {
label = "netxbig:blue:sata1";
mode-addr = <4>;
mode-val = <NETXBIG_LED_OFF 0
NETXBIG_LED_ON 7
NETXBIG_LED_SATA 1
NETXBIG_LED_TIMER1 3>;
bright-addr = <2>;
max-brightness = <7>;
};
red-sata1 {
label = "netxbig:red:sata1";
mode-addr = <4>;
mode-val = <NETXBIG_LED_OFF 0
NETXBIG_LED_ON 2
NETXBIG_LED_TIMER1 4>;
bright-addr = <2>;
max-brightness = <7>;
};
};
};
&mdio {
......
......@@ -117,11 +117,4 @@ config MACH_KIRKWOOD
Say 'Y' here if you want your kernel to support boards based
on the Marvell Kirkwood device tree.
config MACH_NETXBIG
bool "LaCie 2Big and 5Big Network v2"
depends on MACH_KIRKWOOD
help
Say 'Y' here if you want your kernel to support the
LaCie 2Big and 5Big Network v2
endif
......@@ -13,4 +13,3 @@ endif
obj-$(CONFIG_MACH_DOVE) += dove.o
obj-$(CONFIG_MACH_KIRKWOOD) += kirkwood.o kirkwood-pm.o
obj-$(CONFIG_MACH_NETXBIG) += netxbig.o
......@@ -25,7 +25,6 @@
#include "kirkwood.h"
#include "kirkwood-pm.h"
#include "common.h"
#include "board.h"
static struct resource kirkwood_cpufreq_resources[] = {
[0] = {
......@@ -180,9 +179,6 @@ static void __init kirkwood_dt_init(void)
kirkwood_pm_init();
kirkwood_dt_eth_fixup();
if (of_machine_is_compatible("lacie,netxbig"))
netxbig_init();
of_platform_populate(NULL, of_default_bus_match_table, auxdata, NULL);
}
......
/*
* arch/arm/mach-mvbu/board-netxbig.c
*
* LaCie 2Big and 5Big Network v2 board setup
*
* Copyright (C) 2010 Simon Guinot <sguinot@lacie.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.
*
* 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.
*/
#include <linux/kernel.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/platform_data/leds-kirkwood-netxbig.h>
#include "common.h"
/*****************************************************************************
* GPIO extension LEDs
****************************************************************************/
/*
* The LEDs are controlled by a CPLD and can be configured through a GPIO
* extension bus:
*
* - address register : bit [0-2] -> GPIO [47-49]
* - data register : bit [0-2] -> GPIO [44-46]
* - enable register : GPIO 29
*/
static int netxbig_v2_gpio_ext_addr[] = { 47, 48, 49 };
static int netxbig_v2_gpio_ext_data[] = { 44, 45, 46 };
static struct netxbig_gpio_ext netxbig_v2_gpio_ext = {
.addr = netxbig_v2_gpio_ext_addr,
.num_addr = ARRAY_SIZE(netxbig_v2_gpio_ext_addr),
.data = netxbig_v2_gpio_ext_data,
.num_data = ARRAY_SIZE(netxbig_v2_gpio_ext_data),
.enable = 29,
};
/*
* Address register selection:
*
* addr | register
* ----------------------------
* 0 | front LED
* 1 | front LED brightness
* 2 | SATA LED brightness
* 3 | SATA0 LED
* 4 | SATA1 LED
* 5 | SATA2 LED
* 6 | SATA3 LED
* 7 | SATA4 LED
*
* Data register configuration:
*
* data | LED brightness
* -------------------------------------------------
* 0 | min (off)
* - | -
* 7 | max
*
* data | front LED mode
* -------------------------------------------------
* 0 | fix off
* 1 | fix blue on
* 2 | fix red on
* 3 | blink blue on=1 sec and blue off=1 sec
* 4 | blink red on=1 sec and red off=1 sec
* 5 | blink blue on=2.5 sec and red on=0.5 sec
* 6 | blink blue on=1 sec and red on=1 sec
* 7 | blink blue on=0.5 sec and blue off=2.5 sec
*
* data | SATA LED mode
* -------------------------------------------------
* 0 | fix off
* 1 | SATA activity blink
* 2 | fix red on
* 3 | blink blue on=1 sec and blue off=1 sec
* 4 | blink red on=1 sec and red off=1 sec
* 5 | blink blue on=2.5 sec and red on=0.5 sec
* 6 | blink blue on=1 sec and red on=1 sec
* 7 | fix blue on
*/
static int netxbig_v2_red_mled[NETXBIG_LED_MODE_NUM] = {
[NETXBIG_LED_OFF] = 0,
[NETXBIG_LED_ON] = 2,
[NETXBIG_LED_SATA] = NETXBIG_LED_INVALID_MODE,
[NETXBIG_LED_TIMER1] = 4,
[NETXBIG_LED_TIMER2] = NETXBIG_LED_INVALID_MODE,
};
static int netxbig_v2_blue_pwr_mled[NETXBIG_LED_MODE_NUM] = {
[NETXBIG_LED_OFF] = 0,
[NETXBIG_LED_ON] = 1,
[NETXBIG_LED_SATA] = NETXBIG_LED_INVALID_MODE,
[NETXBIG_LED_TIMER1] = 3,
[NETXBIG_LED_TIMER2] = 7,
};
static int netxbig_v2_blue_sata_mled[NETXBIG_LED_MODE_NUM] = {
[NETXBIG_LED_OFF] = 0,
[NETXBIG_LED_ON] = 7,
[NETXBIG_LED_SATA] = 1,
[NETXBIG_LED_TIMER1] = 3,
[NETXBIG_LED_TIMER2] = NETXBIG_LED_INVALID_MODE,
};
static struct netxbig_led_timer netxbig_v2_led_timer[] = {
[0] = {
.delay_on = 500,
.delay_off = 500,
.mode = NETXBIG_LED_TIMER1,
},
[1] = {
.delay_on = 500,
.delay_off = 1000,
.mode = NETXBIG_LED_TIMER2,
},
};
#define NETXBIG_LED(_name, maddr, mval, baddr) \
{ .name = _name, \
.mode_addr = maddr, \
.mode_val = mval, \
.bright_addr = baddr }
static struct netxbig_led net2big_v2_leds_ctrl[] = {
NETXBIG_LED("net2big-v2:blue:power", 0, netxbig_v2_blue_pwr_mled, 1),
NETXBIG_LED("net2big-v2:red:power", 0, netxbig_v2_red_mled, 1),
NETXBIG_LED("net2big-v2:blue:sata0", 3, netxbig_v2_blue_sata_mled, 2),
NETXBIG_LED("net2big-v2:red:sata0", 3, netxbig_v2_red_mled, 2),
NETXBIG_LED("net2big-v2:blue:sata1", 4, netxbig_v2_blue_sata_mled, 2),
NETXBIG_LED("net2big-v2:red:sata1", 4, netxbig_v2_red_mled, 2),
};
static struct netxbig_led_platform_data net2big_v2_leds_data = {
.gpio_ext = &netxbig_v2_gpio_ext,
.timer = netxbig_v2_led_timer,
.num_timer = ARRAY_SIZE(netxbig_v2_led_timer),
.leds = net2big_v2_leds_ctrl,
.num_leds = ARRAY_SIZE(net2big_v2_leds_ctrl),
};
static struct netxbig_led net5big_v2_leds_ctrl[] = {
NETXBIG_LED("net5big-v2:blue:power", 0, netxbig_v2_blue_pwr_mled, 1),
NETXBIG_LED("net5big-v2:red:power", 0, netxbig_v2_red_mled, 1),
NETXBIG_LED("net5big-v2:blue:sata0", 3, netxbig_v2_blue_sata_mled, 2),
NETXBIG_LED("net5big-v2:red:sata0", 3, netxbig_v2_red_mled, 2),
NETXBIG_LED("net5big-v2:blue:sata1", 4, netxbig_v2_blue_sata_mled, 2),
NETXBIG_LED("net5big-v2:red:sata1", 4, netxbig_v2_red_mled, 2),
NETXBIG_LED("net5big-v2:blue:sata2", 5, netxbig_v2_blue_sata_mled, 2),
NETXBIG_LED("net5big-v2:red:sata2", 5, netxbig_v2_red_mled, 2),
NETXBIG_LED("net5big-v2:blue:sata3", 6, netxbig_v2_blue_sata_mled, 2),
NETXBIG_LED("net5big-v2:red:sata3", 6, netxbig_v2_red_mled, 2),
NETXBIG_LED("net5big-v2:blue:sata4", 7, netxbig_v2_blue_sata_mled, 2),
NETXBIG_LED("net5big-v2:red:sata4", 7, netxbig_v2_red_mled, 2),
};
static struct netxbig_led_platform_data net5big_v2_leds_data = {
.gpio_ext = &netxbig_v2_gpio_ext,
.timer = netxbig_v2_led_timer,
.num_timer = ARRAY_SIZE(netxbig_v2_led_timer),
.leds = net5big_v2_leds_ctrl,
.num_leds = ARRAY_SIZE(net5big_v2_leds_ctrl),
};
static struct platform_device netxbig_v2_leds = {
.name = "leds-netxbig",
.id = -1,
.dev = {
.platform_data = &net2big_v2_leds_data,
},
};
void __init netxbig_init(void)
{
if (of_machine_is_compatible("lacie,net5big_v2"))
netxbig_v2_leds.dev.platform_data = &net5big_v2_leds_data;
platform_device_register(&netxbig_v2_leds);
}
......@@ -12,6 +12,4 @@ obj-y := sead3-lcd.o sead3-display.o sead3-init.o \
sead3-int.o sead3-platform.o sead3-reset.o \
sead3-setup.o sead3-time.o
obj-y += leds-sead3.o
obj-$(CONFIG_EARLY_PRINTK) += sead3-console.o
......@@ -556,6 +556,16 @@ config LEDS_KTD2692
Say Y to enable this driver.
config LEDS_SEAD3
tristate "LED support for the MIPS SEAD 3 board"
depends on LEDS_CLASS && MIPS_SEAD3
help
Say Y here to include support for the FLED and PLED LEDs on SEAD3 eval
boards.
This driver can also be built as a module. If so the module
will be called leds-sead3.
comment "LED driver for blink(1) USB RGB LED is under Special HID drivers (HID_THINGM)"
config LEDS_BLINKM
......
......@@ -65,6 +65,7 @@ obj-$(CONFIG_LEDS_VERSATILE) += leds-versatile.o
obj-$(CONFIG_LEDS_MENF21BMC) += leds-menf21bmc.o
obj-$(CONFIG_LEDS_KTD2692) += leds-ktd2692.o
obj-$(CONFIG_LEDS_POWERNV) += leds-powernv.o
obj-$(CONFIG_LEDS_SEAD3) += leds-sead3.o
# LED SPI Drivers
obj-$(CONFIG_LEDS_DAC124S085) += leds-dac124s085.o
......
......@@ -102,70 +102,6 @@ static const struct attribute_group *led_groups[] = {
NULL,
};
static void led_timer_function(unsigned long data)
{
struct led_classdev *led_cdev = (void *)data;
unsigned long brightness;
unsigned long delay;
if (!led_cdev->blink_delay_on || !led_cdev->blink_delay_off) {
led_set_brightness_async(led_cdev, LED_OFF);
return;
}
if (led_cdev->flags & LED_BLINK_ONESHOT_STOP) {
led_cdev->flags &= ~LED_BLINK_ONESHOT_STOP;
return;
}
brightness = led_get_brightness(led_cdev);
if (!brightness) {
/* Time to switch the LED on. */
if (led_cdev->delayed_set_value) {
led_cdev->blink_brightness =
led_cdev->delayed_set_value;
led_cdev->delayed_set_value = 0;
}
brightness = led_cdev->blink_brightness;
delay = led_cdev->blink_delay_on;
} else {
/* Store the current brightness value to be able
* to restore it when the delay_off period is over.
*/
led_cdev->blink_brightness = brightness;
brightness = LED_OFF;
delay = led_cdev->blink_delay_off;
}
led_set_brightness_async(led_cdev, brightness);
/* Return in next iteration if led is in one-shot mode and we are in
* the final blink state so that the led is toggled each delay_on +
* delay_off milliseconds in worst case.
*/
if (led_cdev->flags & LED_BLINK_ONESHOT) {
if (led_cdev->flags & LED_BLINK_INVERT) {
if (brightness)
led_cdev->flags |= LED_BLINK_ONESHOT_STOP;
} else {
if (!brightness)
led_cdev->flags |= LED_BLINK_ONESHOT_STOP;
}
}
mod_timer(&led_cdev->blink_timer, jiffies + msecs_to_jiffies(delay));
}
static void set_brightness_delayed(struct work_struct *ws)
{
struct led_classdev *led_cdev =
container_of(ws, struct led_classdev, set_brightness_work);
led_stop_software_blink(led_cdev);
led_set_brightness_async(led_cdev, led_cdev->delayed_set_value);
}
/**
* led_classdev_suspend - suspend an led_classdev.
* @led_cdev: the led_classdev to suspend.
......@@ -283,10 +219,7 @@ int led_classdev_register(struct device *parent, struct led_classdev *led_cdev)
led_update_brightness(led_cdev);
INIT_WORK(&led_cdev->set_brightness_work, set_brightness_delayed);
setup_timer(&led_cdev->blink_timer, led_timer_function,
(unsigned long)led_cdev);
led_init_core(led_cdev);
#ifdef CONFIG_LEDS_TRIGGERS
led_trigger_set_default(led_cdev);
......
......@@ -25,6 +25,70 @@ EXPORT_SYMBOL_GPL(leds_list_lock);
LIST_HEAD(leds_list);
EXPORT_SYMBOL_GPL(leds_list);
static void led_timer_function(unsigned long data)
{
struct led_classdev *led_cdev = (void *)data;
unsigned long brightness;
unsigned long delay;
if (!led_cdev->blink_delay_on || !led_cdev->blink_delay_off) {
led_set_brightness_async(led_cdev, LED_OFF);
return;
}
if (led_cdev->flags & LED_BLINK_ONESHOT_STOP) {
led_cdev->flags &= ~LED_BLINK_ONESHOT_STOP;
return;
}
brightness = led_get_brightness(led_cdev);
if (!brightness) {
/* Time to switch the LED on. */
if (led_cdev->delayed_set_value) {
led_cdev->blink_brightness =
led_cdev->delayed_set_value;
led_cdev->delayed_set_value = 0;
}
brightness = led_cdev->blink_brightness;
delay = led_cdev->blink_delay_on;
} else {
/* Store the current brightness value to be able
* to restore it when the delay_off period is over.
*/
led_cdev->blink_brightness = brightness;
brightness = LED_OFF;
delay = led_cdev->blink_delay_off;
}
led_set_brightness_async(led_cdev, brightness);
/* Return in next iteration if led is in one-shot mode and we are in
* the final blink state so that the led is toggled each delay_on +
* delay_off milliseconds in worst case.
*/
if (led_cdev->flags & LED_BLINK_ONESHOT) {
if (led_cdev->flags & LED_BLINK_INVERT) {
if (brightness)
led_cdev->flags |= LED_BLINK_ONESHOT_STOP;
} else {
if (!brightness)
led_cdev->flags |= LED_BLINK_ONESHOT_STOP;
}
}
mod_timer(&led_cdev->blink_timer, jiffies + msecs_to_jiffies(delay));
}
static void set_brightness_delayed(struct work_struct *ws)
{
struct led_classdev *led_cdev =
container_of(ws, struct led_classdev, set_brightness_work);
led_stop_software_blink(led_cdev);
led_set_brightness_async(led_cdev, led_cdev->delayed_set_value);
}
static void led_set_software_blink(struct led_classdev *led_cdev,
unsigned long delay_on,
unsigned long delay_off)
......@@ -72,6 +136,15 @@ static void led_blink_setup(struct led_classdev *led_cdev,
led_set_software_blink(led_cdev, *delay_on, *delay_off);
}
void led_init_core(struct led_classdev *led_cdev)
{
INIT_WORK(&led_cdev->set_brightness_work, set_brightness_delayed);
setup_timer(&led_cdev->blink_timer, led_timer_function,
(unsigned long)led_cdev);
}
EXPORT_SYMBOL_GPL(led_init_core);
void led_blink_set(struct led_classdev *led_cdev,
unsigned long *delay_on,
unsigned long *delay_off)
......
......@@ -142,6 +142,7 @@ static int pm860x_led_dt_init(struct platform_device *pdev,
of_property_read_u32(np, "marvell,88pm860x-iset",
&iset);
data->iset = PM8606_LED_CURRENT(iset);
of_node_put(np);
break;
}
}
......
......@@ -41,6 +41,11 @@
#define BCM6328_SERIAL_LED_SHIFT_DIR BIT(16)
#define BCM6328_LED_SHIFT_TEST BIT(30)
#define BCM6328_LED_TEST BIT(31)
#define BCM6328_INIT_MASK (BCM6328_SERIAL_LED_EN | \
BCM6328_SERIAL_LED_MUX | \
BCM6328_SERIAL_LED_CLK_NPOL | \
BCM6328_SERIAL_LED_DATA_PPOL | \
BCM6328_SERIAL_LED_SHIFT_DIR)
#define BCM6328_LED_MODE_MASK 3
#define BCM6328_LED_MODE_OFF 0
......@@ -281,11 +286,10 @@ static int bcm6328_led(struct device *dev, struct device_node *nc, u32 reg,
"linux,default-trigger",
NULL);
spin_lock_irqsave(lock, flags);
if (!of_property_read_string(nc, "default-state", &state)) {
spin_lock_irqsave(lock, flags);
if (!strcmp(state, "on")) {
led->cdev.brightness = LED_FULL;
bcm6328_led_mode(led, BCM6328_LED_MODE_ON);
} else if (!strcmp(state, "keep")) {
void __iomem *mode;
unsigned long val, shift;
......@@ -296,21 +300,28 @@ static int bcm6328_led(struct device *dev, struct device_node *nc, u32 reg,
else
mode = mem + BCM6328_REG_MODE_LO;
val = bcm6328_led_read(mode) >> (shift % 16);
val = bcm6328_led_read(mode) >>
BCM6328_LED_SHIFT(shift % 16);
val &= BCM6328_LED_MODE_MASK;
if (val == BCM6328_LED_MODE_ON)
if ((led->active_low && val == BCM6328_LED_MODE_ON) ||
(!led->active_low && val == BCM6328_LED_MODE_OFF))
led->cdev.brightness = LED_FULL;
else {
else
led->cdev.brightness = LED_OFF;
bcm6328_led_mode(led, BCM6328_LED_MODE_OFF);
}
} else {
led->cdev.brightness = LED_OFF;
bcm6328_led_mode(led, BCM6328_LED_MODE_OFF);
}
spin_unlock_irqrestore(lock, flags);
} else {
led->cdev.brightness = LED_OFF;
}
if ((led->active_low && led->cdev.brightness == LED_FULL) ||
(!led->active_low && led->cdev.brightness == LED_OFF))
bcm6328_led_mode(led, BCM6328_LED_MODE_ON);
else
bcm6328_led_mode(led, BCM6328_LED_MODE_OFF);
spin_unlock_irqrestore(lock, flags);
led->cdev.brightness_set = bcm6328_led_set;
led->cdev.blink_set = bcm6328_blink_set;
......@@ -360,9 +371,17 @@ static int bcm6328_leds_probe(struct platform_device *pdev)
bcm6328_led_write(mem + BCM6328_REG_LNKACTSEL_LO, 0);
val = bcm6328_led_read(mem + BCM6328_REG_INIT);
val &= ~BCM6328_SERIAL_LED_EN;
val &= ~(BCM6328_INIT_MASK);
if (of_property_read_bool(np, "brcm,serial-leds"))
val |= BCM6328_SERIAL_LED_EN;
if (of_property_read_bool(np, "brcm,serial-mux"))
val |= BCM6328_SERIAL_LED_MUX;
if (of_property_read_bool(np, "brcm,serial-clk-low"))
val |= BCM6328_SERIAL_LED_CLK_NPOL;
if (!of_property_read_bool(np, "brcm,serial-dat-low"))
val |= BCM6328_SERIAL_LED_DATA_PPOL;
if (!of_property_read_bool(np, "brcm,serial-shift-inv"))
val |= BCM6328_SERIAL_LED_SHIFT_DIR;
bcm6328_led_write(mem + BCM6328_REG_INIT, val);
for_each_available_child_of_node(np, child) {
......@@ -373,7 +392,7 @@ static int bcm6328_leds_probe(struct platform_device *pdev)
continue;
if (reg >= BCM6328_LED_MAX_COUNT) {
dev_err(dev, "invalid LED (>= %d)\n",
dev_err(dev, "invalid LED (%u >= %d)\n", reg,
BCM6328_LED_MAX_COUNT);
continue;
}
......@@ -384,8 +403,10 @@ static int bcm6328_leds_probe(struct platform_device *pdev)
rc = bcm6328_led(dev, child, reg, mem, lock,
blink_leds, blink_delay);
if (rc < 0)
if (rc < 0) {
of_node_put(child);
return rc;
}
}
return 0;
......
......@@ -215,8 +215,10 @@ static int bcm6358_leds_probe(struct platform_device *pdev)
}
rc = bcm6358_led(dev, child, reg, mem, lock);
if (rc < 0)
if (rc < 0) {
of_node_put(child);
return rc;
}
}
return 0;
......
......@@ -36,7 +36,6 @@ static struct led_classdev qube_front_led = {
static int cobalt_qube_led_probe(struct platform_device *pdev)
{
struct resource *res;
int retval;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res)
......@@ -49,31 +48,11 @@ static int cobalt_qube_led_probe(struct platform_device *pdev)
led_value = LED_FRONT_LEFT | LED_FRONT_RIGHT;
writeb(led_value, led_port);
retval = led_classdev_register(&pdev->dev, &qube_front_led);
if (retval)
goto err_null;
return 0;
err_null:
led_port = NULL;
return retval;
}
static int cobalt_qube_led_remove(struct platform_device *pdev)
{
led_classdev_unregister(&qube_front_led);
if (led_port)
led_port = NULL;
return 0;
return devm_led_classdev_register(&pdev->dev, &qube_front_led);
}
static struct platform_driver cobalt_qube_led_driver = {
.probe = cobalt_qube_led_probe,
.remove = cobalt_qube_led_remove,
.driver = {
.name = "cobalt-qube-leds",
},
......
......@@ -291,9 +291,22 @@ static int gpio_led_remove(struct platform_device *pdev)
return 0;
}
static void gpio_led_shutdown(struct platform_device *pdev)
{
struct gpio_leds_priv *priv = platform_get_drvdata(pdev);
int i;
for (i = 0; i < priv->num_leds; i++) {
struct gpio_led_data *led = &priv->leds[i];
gpio_led_set(&led->cdev, LED_OFF);
}
}
static struct platform_driver gpio_led_driver = {
.probe = gpio_led_probe,
.remove = gpio_led_remove,
.shutdown = gpio_led_shutdown,
.driver = {
.name = "leds-gpio",
.of_match_table = of_gpio_leds_match,
......
......@@ -59,28 +59,15 @@ static int hp6xxled_probe(struct platform_device *pdev)
{
int ret;
ret = led_classdev_register(&pdev->dev, &hp6xx_red_led);
ret = devm_led_classdev_register(&pdev->dev, &hp6xx_red_led);
if (ret < 0)
return ret;
ret = led_classdev_register(&pdev->dev, &hp6xx_green_led);
if (ret < 0)
led_classdev_unregister(&hp6xx_red_led);
return ret;
}
static int hp6xxled_remove(struct platform_device *pdev)
{
led_classdev_unregister(&hp6xx_red_led);
led_classdev_unregister(&hp6xx_green_led);
return 0;
return devm_led_classdev_register(&pdev->dev, &hp6xx_green_led);
}
static struct platform_driver hp6xxled_driver = {
.probe = hp6xxled_probe,
.remove = hp6xxled_remove,
.driver = {
.name = "hp6xx-led",
},
......
......@@ -16,9 +16,9 @@
#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 */
#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)
......@@ -79,14 +79,14 @@ static int micro_leds_blink_set(struct led_classdev *led_cdev,
};
msg.tx_data[0] = LED_GREEN;
if (*delay_on > IPAQ_LED_MAX_DUTY ||
if (*delay_on > IPAQ_LED_MAX_DUTY ||
*delay_off > IPAQ_LED_MAX_DUTY)
return -EINVAL;
return -EINVAL;
if (*delay_on == 0 && *delay_off == 0) {
*delay_on = 100;
*delay_off = 100;
}
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)
......@@ -111,7 +111,7 @@ static int micro_leds_probe(struct platform_device *pdev)
{
int ret;
ret = led_classdev_register(&pdev->dev, &micro_led);
ret = devm_led_classdev_register(&pdev->dev, &micro_led);
if (ret) {
dev_err(&pdev->dev, "registering led failed: %d\n", ret);
return ret;
......@@ -121,18 +121,11 @@ static int micro_leds_probe(struct platform_device *pdev)
return 0;
}
static int micro_leds_remove(struct platform_device *pdev)
{
led_classdev_unregister(&micro_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);
......
......@@ -59,23 +59,13 @@ static int locomoled_probe(struct locomo_dev *ldev)
{
int ret;
ret = led_classdev_register(&ldev->dev, &locomo_led0);
ret = devm_led_classdev_register(&ldev->dev, &locomo_led0);
if (ret < 0)
return ret;
ret = led_classdev_register(&ldev->dev, &locomo_led1);
if (ret < 0)
led_classdev_unregister(&locomo_led0);
return ret;
return devm_led_classdev_register(&ldev->dev, &locomo_led1);
}
static int locomoled_remove(struct locomo_dev *dev)
{
led_classdev_unregister(&locomo_led0);
led_classdev_unregister(&locomo_led1);
return 0;
}
static struct locomo_driver locomoled_driver = {
.drv = {
......@@ -83,7 +73,6 @@ static struct locomo_driver locomoled_driver = {
},
.devid = LOCOMO_DEVID_LED,
.probe = locomoled_probe,
.remove = locomoled_remove,
};
static int __init locomoled_init(void)
......
......@@ -87,36 +87,20 @@ static int menf21bmc_led_probe(struct platform_device *pdev)
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;
ret = devm_led_classdev_register(&pdev->dev, &leds[i].cdev);
if (ret < 0) {
dev_err(&pdev->dev, "failed to register LED device\n");
return ret;
}
}
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",
},
......
......@@ -39,18 +39,11 @@ static struct led_classdev net48xx_error_led = {
static int net48xx_led_probe(struct platform_device *pdev)
{
return led_classdev_register(&pdev->dev, &net48xx_error_led);
}
static int net48xx_led_remove(struct platform_device *pdev)
{
led_classdev_unregister(&net48xx_error_led);
return 0;
return devm_led_classdev_register(&pdev->dev, &net48xx_error_led);
}
static struct platform_driver net48xx_led_driver = {
.probe = net48xx_led_probe,
.remove = net48xx_led_remove,
.driver = {
.name = DRVNAME,
},
......
......@@ -26,6 +26,7 @@
#include <linux/spinlock.h>
#include <linux/platform_device.h>
#include <linux/gpio.h>
#include <linux/of_gpio.h>
#include <linux/leds.h>
#include <linux/platform_data/leds-kirkwood-netxbig.h>
......@@ -70,7 +71,8 @@ static void gpio_ext_set_value(struct netxbig_gpio_ext *gpio_ext,
spin_unlock_irqrestore(&gpio_ext_lock, flags);
}
static int gpio_ext_init(struct netxbig_gpio_ext *gpio_ext)
static int gpio_ext_init(struct platform_device *pdev,
struct netxbig_gpio_ext *gpio_ext)
{
int err;
int i;
......@@ -80,46 +82,28 @@ static int gpio_ext_init(struct netxbig_gpio_ext *gpio_ext)
/* Configure address GPIOs. */
for (i = 0; i < gpio_ext->num_addr; i++) {
err = gpio_request_one(gpio_ext->addr[i], GPIOF_OUT_INIT_LOW,
"GPIO extension addr");
err = devm_gpio_request_one(&pdev->dev, gpio_ext->addr[i],
GPIOF_OUT_INIT_LOW,
"GPIO extension addr");
if (err)
goto err_free_addr;
return err;
}
/* Configure data GPIOs. */
for (i = 0; i < gpio_ext->num_data; i++) {
err = gpio_request_one(gpio_ext->data[i], GPIOF_OUT_INIT_LOW,
"GPIO extension data");
err = devm_gpio_request_one(&pdev->dev, gpio_ext->data[i],
GPIOF_OUT_INIT_LOW,
"GPIO extension data");
if (err)
goto err_free_data;
return err;
}
/* Configure "enable select" GPIO. */
err = gpio_request_one(gpio_ext->enable, GPIOF_OUT_INIT_LOW,
"GPIO extension enable");
err = devm_gpio_request_one(&pdev->dev, gpio_ext->enable,
GPIOF_OUT_INIT_LOW,
"GPIO extension enable");
if (err)
goto err_free_data;
return err;
return 0;
err_free_data:
for (i = i - 1; i >= 0; i--)
gpio_free(gpio_ext->data[i]);
i = gpio_ext->num_addr;
err_free_addr:
for (i = i - 1; i >= 0; i--)
gpio_free(gpio_ext->addr[i]);
return err;
}
static void gpio_ext_free(struct netxbig_gpio_ext *gpio_ext)
{
int i;
gpio_free(gpio_ext->enable);
for (i = gpio_ext->num_addr - 1; i >= 0; i--)
gpio_free(gpio_ext->addr[i]);
for (i = gpio_ext->num_data - 1; i >= 0; i--)
gpio_free(gpio_ext->data[i]);
}
/*
......@@ -132,7 +116,6 @@ struct netxbig_led_data {
int mode_addr;
int *mode_val;
int bright_addr;
int bright_max;
struct netxbig_led_timer *timer;
int num_timer;
enum netxbig_led_mode mode;
......@@ -194,7 +177,7 @@ static void netxbig_led_set(struct led_classdev *led_cdev,
struct netxbig_led_data *led_dat =
container_of(led_cdev, struct netxbig_led_data, cdev);
enum netxbig_led_mode mode;
int mode_val, bright_val;
int mode_val;
int set_brightness = 1;
unsigned long flags;
......@@ -220,12 +203,9 @@ static void netxbig_led_set(struct led_classdev *led_cdev,
* SATA LEDs. So, change the brightness setting for a single
* SATA LED will affect all the others.
*/
if (set_brightness) {
bright_val = DIV_ROUND_UP(value * led_dat->bright_max,
LED_FULL);
if (set_brightness)
gpio_ext_set_value(led_dat->gpio_ext,
led_dat->bright_addr, bright_val);
}
led_dat->bright_addr, value);
spin_unlock_irqrestore(&led_dat->lock, flags);
}
......@@ -299,18 +279,11 @@ static struct attribute *netxbig_led_attrs[] = {
};
ATTRIBUTE_GROUPS(netxbig_led);
static void delete_netxbig_led(struct netxbig_led_data *led_dat)
static int create_netxbig_led(struct platform_device *pdev,
struct netxbig_led_platform_data *pdata,
struct netxbig_led_data *led_dat,
const struct netxbig_led *template)
{
led_classdev_unregister(&led_dat->cdev);
}
static int
create_netxbig_led(struct platform_device *pdev,
struct netxbig_led_data *led_dat,
const struct netxbig_led *template)
{
struct netxbig_led_platform_data *pdata = dev_get_platdata(&pdev->dev);
spin_lock_init(&led_dat->lock);
led_dat->gpio_ext = pdata->gpio_ext;
led_dat->cdev.name = template->name;
......@@ -329,11 +302,11 @@ create_netxbig_led(struct platform_device *pdev,
*/
led_dat->sata = 0;
led_dat->cdev.brightness = LED_OFF;
led_dat->cdev.max_brightness = template->bright_max;
led_dat->cdev.flags |= LED_CORE_SUSPENDRESUME;
led_dat->mode_addr = template->mode_addr;
led_dat->mode_val = template->mode_val;
led_dat->bright_addr = template->bright_addr;
led_dat->bright_max = (1 << pdata->gpio_ext->num_data) - 1;
led_dat->timer = pdata->timer;
led_dat->num_timer = pdata->num_timer;
/*
......@@ -343,67 +316,274 @@ create_netxbig_led(struct platform_device *pdev,
if (led_dat->mode_val[NETXBIG_LED_SATA] != NETXBIG_LED_INVALID_MODE)
led_dat->cdev.groups = netxbig_led_groups;
return led_classdev_register(&pdev->dev, &led_dat->cdev);
return devm_led_classdev_register(&pdev->dev, &led_dat->cdev);
}
static int netxbig_led_probe(struct platform_device *pdev)
#ifdef CONFIG_OF_GPIO
static int gpio_ext_get_of_pdata(struct device *dev, struct device_node *np,
struct netxbig_gpio_ext *gpio_ext)
{
struct netxbig_led_platform_data *pdata = dev_get_platdata(&pdev->dev);
struct netxbig_led_data *leds_data;
int i;
int *addr, *data;
int num_addr, num_data;
int ret;
int i;
if (!pdata)
return -EINVAL;
leds_data = devm_kzalloc(&pdev->dev,
sizeof(struct netxbig_led_data) * pdata->num_leds, GFP_KERNEL);
if (!leds_data)
ret = of_gpio_named_count(np, "addr-gpios");
if (ret < 0) {
dev_err(dev,
"Failed to count GPIOs in DT property addr-gpios\n");
return ret;
}
num_addr = ret;
addr = devm_kzalloc(dev, num_addr * sizeof(*addr), GFP_KERNEL);
if (!addr)
return -ENOMEM;
ret = gpio_ext_init(pdata->gpio_ext);
if (ret < 0)
for (i = 0; i < num_addr; i++) {
ret = of_get_named_gpio(np, "addr-gpios", i);
if (ret < 0)
return ret;
addr[i] = ret;
}
gpio_ext->addr = addr;
gpio_ext->num_addr = num_addr;
ret = of_gpio_named_count(np, "data-gpios");
if (ret < 0) {
dev_err(dev,
"Failed to count GPIOs in DT property data-gpios\n");
return ret;
}
num_data = ret;
data = devm_kzalloc(dev, num_data * sizeof(*data), GFP_KERNEL);
if (!data)
return -ENOMEM;
for (i = 0; i < pdata->num_leds; i++) {
ret = create_netxbig_led(pdev, &leds_data[i], &pdata->leds[i]);
for (i = 0; i < num_data; i++) {
ret = of_get_named_gpio(np, "data-gpios", i);
if (ret < 0)
goto err_free_leds;
return ret;
data[i] = ret;
}
gpio_ext->data = data;
gpio_ext->num_data = num_data;
platform_set_drvdata(pdev, leds_data);
ret = of_get_named_gpio(np, "enable-gpio", 0);
if (ret < 0) {
dev_err(dev,
"Failed to get GPIO from DT property enable-gpio\n");
return ret;
}
gpio_ext->enable = ret;
return 0;
}
static int netxbig_leds_get_of_pdata(struct device *dev,
struct netxbig_led_platform_data *pdata)
{
struct device_node *np = dev->of_node;
struct device_node *gpio_ext_np;
struct device_node *child;
struct netxbig_gpio_ext *gpio_ext;
struct netxbig_led_timer *timers;
struct netxbig_led *leds, *led;
int num_timers;
int num_leds = 0;
int ret;
int i;
err_free_leds:
for (i = i - 1; i >= 0; i--)
delete_netxbig_led(&leds_data[i]);
/* GPIO extension */
gpio_ext_np = of_parse_phandle(np, "gpio-ext", 0);
if (!gpio_ext_np) {
dev_err(dev, "Failed to get DT handle gpio-ext\n");
return -EINVAL;
}
gpio_ext_free(pdata->gpio_ext);
gpio_ext = devm_kzalloc(dev, sizeof(*gpio_ext), GFP_KERNEL);
if (!gpio_ext)
return -ENOMEM;
ret = gpio_ext_get_of_pdata(dev, gpio_ext_np, gpio_ext);
if (ret)
return ret;
of_node_put(gpio_ext_np);
pdata->gpio_ext = gpio_ext;
/* Timers (optional) */
ret = of_property_count_u32_elems(np, "timers");
if (ret > 0) {
if (ret % 3)
return -EINVAL;
num_timers = ret / 3;
timers = devm_kzalloc(dev, num_timers * sizeof(*timers),
GFP_KERNEL);
if (!timers)
return -ENOMEM;
for (i = 0; i < num_timers; i++) {
u32 tmp;
of_property_read_u32_index(np, "timers", 3 * i,
&timers[i].mode);
if (timers[i].mode >= NETXBIG_LED_MODE_NUM)
return -EINVAL;
of_property_read_u32_index(np, "timers",
3 * i + 1, &tmp);
timers[i].delay_on = tmp;
of_property_read_u32_index(np, "timers",
3 * i + 2, &tmp);
timers[i].delay_off = tmp;
}
pdata->timer = timers;
pdata->num_timer = num_timers;
}
/* LEDs */
num_leds = of_get_child_count(np);
if (!num_leds) {
dev_err(dev, "No LED subnodes found in DT\n");
return -ENODEV;
}
leds = devm_kzalloc(dev, num_leds * sizeof(*leds), GFP_KERNEL);
if (!leds)
return -ENOMEM;
led = leds;
for_each_child_of_node(np, child) {
const char *string;
int *mode_val;
int num_modes;
ret = of_property_read_u32(child, "mode-addr",
&led->mode_addr);
if (ret)
goto err_node_put;
ret = of_property_read_u32(child, "bright-addr",
&led->bright_addr);
if (ret)
goto err_node_put;
ret = of_property_read_u32(child, "max-brightness",
&led->bright_max);
if (ret)
goto err_node_put;
mode_val =
devm_kzalloc(dev,
NETXBIG_LED_MODE_NUM * sizeof(*mode_val),
GFP_KERNEL);
if (!mode_val) {
ret = -ENOMEM;
goto err_node_put;
}
for (i = 0; i < NETXBIG_LED_MODE_NUM; i++)
mode_val[i] = NETXBIG_LED_INVALID_MODE;
ret = of_property_count_u32_elems(child, "mode-val");
if (ret < 0 || ret % 2) {
ret = -EINVAL;
goto err_node_put;
}
num_modes = ret / 2;
if (num_modes > NETXBIG_LED_MODE_NUM) {
ret = -EINVAL;
goto err_node_put;
}
for (i = 0; i < num_modes; i++) {
int mode;
int val;
of_property_read_u32_index(child,
"mode-val", 2 * i, &mode);
of_property_read_u32_index(child,
"mode-val", 2 * i + 1, &val);
if (mode >= NETXBIG_LED_MODE_NUM) {
ret = -EINVAL;
goto err_node_put;
}
mode_val[mode] = val;
}
led->mode_val = mode_val;
if (!of_property_read_string(child, "label", &string))
led->name = string;
else
led->name = child->name;
if (!of_property_read_string(child,
"linux,default-trigger", &string))
led->default_trigger = string;
led++;
}
pdata->leds = leds;
pdata->num_leds = num_leds;
return 0;
err_node_put:
of_node_put(child);
return ret;
}
static int netxbig_led_remove(struct platform_device *pdev)
static const struct of_device_id of_netxbig_leds_match[] = {
{ .compatible = "lacie,netxbig-leds", },
{},
};
#else
static inline int
netxbig_leds_get_of_pdata(struct device *dev,
struct netxbig_led_platform_data *pdata)
{
return -ENODEV;
}
#endif /* CONFIG_OF_GPIO */
static int netxbig_led_probe(struct platform_device *pdev)
{
struct netxbig_led_platform_data *pdata = dev_get_platdata(&pdev->dev);
struct netxbig_led_data *leds_data;
int i;
int ret;
leds_data = platform_get_drvdata(pdev);
if (!pdata) {
pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
if (!pdata)
return -ENOMEM;
ret = netxbig_leds_get_of_pdata(&pdev->dev, pdata);
if (ret)
return ret;
}
leds_data = devm_kzalloc(&pdev->dev,
pdata->num_leds * sizeof(*leds_data),
GFP_KERNEL);
if (!leds_data)
return -ENOMEM;
for (i = 0; i < pdata->num_leds; i++)
delete_netxbig_led(&leds_data[i]);
ret = gpio_ext_init(pdev, pdata->gpio_ext);
if (ret < 0)
return ret;
gpio_ext_free(pdata->gpio_ext);
for (i = 0; i < pdata->num_leds; i++) {
ret = create_netxbig_led(pdev, pdata,
&leds_data[i], &pdata->leds[i]);
if (ret < 0)
return ret;
}
return 0;
}
static struct platform_driver netxbig_led_driver = {
.probe = netxbig_led_probe,
.remove = netxbig_led_remove,
.driver = {
.name = "leds-netxbig",
.name = "leds-netxbig",
.of_match_table = of_match_ptr(of_netxbig_leds_match),
},
};
......
......@@ -124,9 +124,9 @@ static int ot200_led_probe(struct platform_device *pdev)
leds[i].cdev.name = leds[i].name;
leds[i].cdev.brightness_set = ot200_led_brightness_set;
ret = led_classdev_register(&pdev->dev, &leds[i].cdev);
ret = devm_led_classdev_register(&pdev->dev, &leds[i].cdev);
if (ret < 0)
goto err;
return ret;
}
leds_front = 0; /* turn off all front leds */
......@@ -135,27 +135,10 @@ static int ot200_led_probe(struct platform_device *pdev)
outb(leds_back, 0x5a);
return 0;
err:
for (i = i - 1; i >= 0; i--)
led_classdev_unregister(&leds[i].cdev);
return ret;
}
static int ot200_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 ot200_led_driver = {
.probe = ot200_led_probe,
.remove = ot200_led_remove,
.driver = {
.name = "leds-ot200",
},
......
......@@ -262,15 +262,19 @@ static int powernv_led_classdev(struct platform_device *pdev,
while ((cur = of_prop_next_string(p, cur)) != NULL) {
powernv_led = devm_kzalloc(dev, sizeof(*powernv_led),
GFP_KERNEL);
if (!powernv_led)
if (!powernv_led) {
of_node_put(np);
return -ENOMEM;
}
powernv_led->common = powernv_led_common;
powernv_led->loc_code = (char *)np->name;
rc = powernv_led_create(dev, powernv_led, cur);
if (rc)
if (rc) {
of_node_put(np);
return rc;
}
} /* while end */
}
......
......@@ -59,6 +59,7 @@ static int sead3_led_remove(struct platform_device *pdev)
{
led_classdev_unregister(&sead3_pled);
led_classdev_unregister(&sead3_fled);
return 0;
}
......
......@@ -76,39 +76,19 @@ static int wrap_led_probe(struct platform_device *pdev)
{
int ret;
ret = led_classdev_register(&pdev->dev, &wrap_power_led);
ret = devm_led_classdev_register(&pdev->dev, &wrap_power_led);
if (ret < 0)
return ret;
ret = led_classdev_register(&pdev->dev, &wrap_error_led);
ret = devm_led_classdev_register(&pdev->dev, &wrap_error_led);
if (ret < 0)
goto err1;
ret = led_classdev_register(&pdev->dev, &wrap_extra_led);
if (ret < 0)
goto err2;
return ret;
err2:
led_classdev_unregister(&wrap_error_led);
err1:
led_classdev_unregister(&wrap_power_led);
return ret;
}
return ret;
static int wrap_led_remove(struct platform_device *pdev)
{
led_classdev_unregister(&wrap_power_led);
led_classdev_unregister(&wrap_error_led);
led_classdev_unregister(&wrap_extra_led);
return 0;
return devm_led_classdev_register(&pdev->dev, &wrap_extra_led);
}
static struct platform_driver wrap_led_driver = {
.probe = wrap_led_probe,
.remove = wrap_led_remove,
.driver = {
.name = DRVNAME,
},
......
......@@ -44,6 +44,7 @@ static inline int led_get_brightness(struct led_classdev *led_cdev)
return led_cdev->brightness;
}
void led_init_core(struct led_classdev *led_cdev);
void led_stop_software_blink(struct led_classdev *led_cdev);
extern struct rw_semaphore leds_list_lock;
......
......@@ -27,6 +27,7 @@ struct heartbeat_trig_data {
unsigned int phase;
unsigned int period;
struct timer_list timer;
unsigned int invert;
};
static void led_heartbeat_function(unsigned long data)
......@@ -56,21 +57,27 @@ static void led_heartbeat_function(unsigned long data)
msecs_to_jiffies(heartbeat_data->period);
delay = msecs_to_jiffies(70);
heartbeat_data->phase++;
brightness = led_cdev->max_brightness;
if (!heartbeat_data->invert)
brightness = led_cdev->max_brightness;
break;
case 1:
delay = heartbeat_data->period / 4 - msecs_to_jiffies(70);
heartbeat_data->phase++;
if (heartbeat_data->invert)
brightness = led_cdev->max_brightness;
break;
case 2:
delay = msecs_to_jiffies(70);
heartbeat_data->phase++;
brightness = led_cdev->max_brightness;
if (!heartbeat_data->invert)
brightness = led_cdev->max_brightness;
break;
default:
delay = heartbeat_data->period - heartbeat_data->period / 4 -
msecs_to_jiffies(70);
heartbeat_data->phase = 0;
if (heartbeat_data->invert)
brightness = led_cdev->max_brightness;
break;
}
......@@ -78,15 +85,50 @@ static void led_heartbeat_function(unsigned long data)
mod_timer(&heartbeat_data->timer, jiffies + delay);
}
static ssize_t led_invert_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct led_classdev *led_cdev = dev_get_drvdata(dev);
struct heartbeat_trig_data *heartbeat_data = led_cdev->trigger_data;
return sprintf(buf, "%u\n", heartbeat_data->invert);
}
static ssize_t led_invert_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t size)
{
struct led_classdev *led_cdev = dev_get_drvdata(dev);
struct heartbeat_trig_data *heartbeat_data = led_cdev->trigger_data;
unsigned long state;
int ret;
ret = kstrtoul(buf, 0, &state);
if (ret)
return ret;
heartbeat_data->invert = !!state;
return size;
}
static DEVICE_ATTR(invert, 0644, led_invert_show, led_invert_store);
static void heartbeat_trig_activate(struct led_classdev *led_cdev)
{
struct heartbeat_trig_data *heartbeat_data;
int rc;
heartbeat_data = kzalloc(sizeof(*heartbeat_data), GFP_KERNEL);
if (!heartbeat_data)
return;
led_cdev->trigger_data = heartbeat_data;
rc = device_create_file(led_cdev->dev, &dev_attr_invert);
if (rc) {
kfree(led_cdev->trigger_data);
return;
}
setup_timer(&heartbeat_data->timer,
led_heartbeat_function, (unsigned long) led_cdev);
heartbeat_data->phase = 0;
......@@ -100,6 +142,7 @@ static void heartbeat_trig_deactivate(struct led_classdev *led_cdev)
if (led_cdev->activated) {
del_timer_sync(&heartbeat_data->timer);
device_remove_file(led_cdev->dev, &dev_attr_invert);
kfree(heartbeat_data);
led_cdev->activated = false;
}
......
/*
* Board functions for Marvell System On Chip
*
* Copyright (C) 2014
*
* Andrew Lunn <andrew@lunn.ch>
* This header provides constants for netxbig LED bindings.
*
* This file is licensed under the terms of the GNU General Public
* License version 2. This program is licensed "as is" without any
* warranty of any kind, whether express or implied.
*/
#ifndef __ARCH_MVEBU_BOARD_H
#define __ARCH_MVEBU_BOARD_H
#ifndef _DT_BINDINGS_LEDS_NETXBIG_H
#define _DT_BINDINGS_LEDS_NETXBIG_H
#define NETXBIG_LED_OFF 0
#define NETXBIG_LED_ON 1
#define NETXBIG_LED_SATA 2
#define NETXBIG_LED_TIMER1 3
#define NETXBIG_LED_TIMER2 4
#ifdef CONFIG_MACH_NETXBIG
void netxbig_init(void);
#else
static inline void netxbig_init(void) {};
#endif
#endif
#endif /* _DT_BINDINGS_LEDS_NETXBIG_H */
......@@ -40,6 +40,7 @@ struct netxbig_led {
int mode_addr;
int *mode_val;
int bright_addr;
int bright_max;
};
struct netxbig_led_platform_data {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment