aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Documentation/devicetree/bindings/mtd/orion-nand.txt4
-rw-r--r--Documentation/leds/00-INDEX2
-rw-r--r--Documentation/leds/leds-blinkm.txt80
-rw-r--r--Documentation/leds/leds-lm3556.txt85
-rw-r--r--Documentation/leds/ledtrig-oneshot.txt59
-rw-r--r--MAINTAINERS16
-rw-r--r--arch/arm/Kconfig2
-rw-r--r--arch/arm/boot/dts/kirkwood-dns320.dts2
-rw-r--r--arch/arm/boot/dts/kirkwood-dns325.dts2
-rw-r--r--arch/arm/boot/dts/kirkwood-dreamplug.dts2
-rw-r--r--arch/arm/boot/dts/kirkwood-ib62x0.dts2
-rw-r--r--arch/arm/boot/dts/kirkwood-iconnect.dts2
-rw-r--r--arch/arm/boot/dts/kirkwood.dtsi6
-rw-r--r--arch/arm/boot/dts/tegra20-trimslice.dts2
-rw-r--r--arch/arm/mach-dove/common.c4
-rw-r--r--arch/arm/mach-kirkwood/common.c70
-rw-r--r--arch/arm/mach-mxs/mach-mxs.c8
-rw-r--r--arch/arm/mach-tegra/board-harmony-power.c33
-rw-r--r--arch/powerpc/configs/g5_defconfig103
-rw-r--r--arch/powerpc/configs/ppc64_defconfig6
-rw-r--r--arch/powerpc/configs/pseries_defconfig6
-rw-r--r--arch/powerpc/kernel/entry_32.S12
-rw-r--r--arch/powerpc/kernel/ftrace.c11
-rw-r--r--arch/powerpc/kernel/rtas_flash.c2
-rw-r--r--arch/powerpc/kvm/bookehv_interrupts.S77
-rw-r--r--drivers/crypto/mv_cesa.c4
-rw-r--r--drivers/leds/Kconfig39
-rw-r--r--drivers/leds/Makefile4
-rw-r--r--drivers/leds/led-class.c27
-rw-r--r--drivers/leds/led-core.c66
-rw-r--r--drivers/leds/led-triggers.c114
-rw-r--r--drivers/leds/leds-88pm860x.c9
-rw-r--r--drivers/leds/leds-adp5520.c8
-rw-r--r--drivers/leds/leds-asic3.c16
-rw-r--r--drivers/leds/leds-atmel-pwm.c5
-rw-r--r--drivers/leds/leds-bd2802.c8
-rw-r--r--drivers/leds/leds-blinkm.c815
-rw-r--r--drivers/leds/leds-da903x.c9
-rw-r--r--drivers/leds/leds-dac124s085.c4
-rw-r--r--drivers/leds/leds-gpio.c11
-rw-r--r--drivers/leds/leds-lm3530.c24
-rw-r--r--drivers/leds/leds-lm3556.c512
-rw-r--r--drivers/leds/leds-lp3944.c9
-rw-r--r--drivers/leds/leds-lp5521.c20
-rw-r--r--drivers/leds/leds-lp5523.c30
-rw-r--r--drivers/leds/leds-lp8788.c193
-rw-r--r--drivers/leds/leds-lt3593.c9
-rw-r--r--drivers/leds/leds-max8997.c93
-rw-r--r--drivers/leds/leds-mc13783.c9
-rw-r--r--drivers/leds/leds-netxbig.c10
-rw-r--r--drivers/leds/leds-ns2.c19
-rw-r--r--drivers/leds/leds-pca9532.c10
-rw-r--r--drivers/leds/leds-pca955x.c18
-rw-r--r--drivers/leds/leds-pca9633.c6
-rw-r--r--drivers/leds/leds-pwm.c7
-rw-r--r--drivers/leds/leds-regulator.c9
-rw-r--r--drivers/leds/leds-renesas-tpu.c23
-rw-r--r--drivers/leds/leds-s3c24xx.c44
-rw-r--r--drivers/leds/leds-sunfire.c21
-rw-r--r--drivers/leds/leds-tca6507.c17
-rw-r--r--drivers/leds/leds.h2
-rw-r--r--drivers/leds/ledtrig-backlight.c8
-rw-r--r--drivers/leds/ledtrig-default-on.c2
-rw-r--r--drivers/leds/ledtrig-gpio.c6
-rw-r--r--drivers/leds/ledtrig-heartbeat.c2
-rw-r--r--drivers/leds/ledtrig-ide-disk.c25
-rw-r--r--drivers/leds/ledtrig-oneshot.c204
-rw-r--r--drivers/leds/ledtrig-timer.c2
-rw-r--r--drivers/leds/ledtrig-transient.c8
-rw-r--r--drivers/mmc/host/mvsdio.c4
-rw-r--r--drivers/mtd/nand/orion_nand.c6
-rw-r--r--drivers/net/ethernet/marvell/mv643xx_eth.c6
-rw-r--r--drivers/net/usb/kaweth.c2
-rw-r--r--drivers/rtc/rtc-mv.c2
-rw-r--r--drivers/usb/host/ehci-orion.c4
-rw-r--r--drivers/video/aty/radeon_monitor.c35
-rw-r--r--include/linux/cpumask.h15
-rw-r--r--include/linux/init.h3
-rw-r--r--include/linux/leds.h29
-rw-r--r--include/linux/platform_data/leds-lm3556.h50
-rw-r--r--init/main.c1
-rw-r--r--net/core/rtnetlink.c8
-rw-r--r--net/ipv4/tcp.c5
-rw-r--r--net/ipv4/tcp_input.c5
-rw-r--r--net/ipv4/tcp_ipv4.c14
-rw-r--r--net/ipv4/tcp_minisocks.c1
-rw-r--r--net/mac80211/led.c2
-rw-r--r--net/openvswitch/actions.c3
-rw-r--r--sound/soc/kirkwood/kirkwood-i2s.c8
89 files changed, 2676 insertions, 606 deletions
diff --git a/Documentation/devicetree/bindings/mtd/orion-nand.txt b/Documentation/devicetree/bindings/mtd/orion-nand.txt
index b2356b7d2fa4..2d6ab660e603 100644
--- a/Documentation/devicetree/bindings/mtd/orion-nand.txt
+++ b/Documentation/devicetree/bindings/mtd/orion-nand.txt
@@ -1,7 +1,7 @@
NAND support for Marvell Orion SoC platforms
Required properties:
-- compatible : "mrvl,orion-nand".
+- compatible : "marvell,orion-nand".
- reg : Base physical address of the NAND and length of memory mapped
region
@@ -24,7 +24,7 @@ nand@f4000000 {
ale = <1>;
bank-width = <1>;
chip-delay = <25>;
- compatible = "mrvl,orion-nand";
+ compatible = "marvell,orion-nand";
reg = <0xf4000000 0x400>;
partition@0 {
diff --git a/Documentation/leds/00-INDEX b/Documentation/leds/00-INDEX
index 29f481df32c7..5fefe374892f 100644
--- a/Documentation/leds/00-INDEX
+++ b/Documentation/leds/00-INDEX
@@ -6,3 +6,5 @@ leds-lp5521.txt
- notes on how to use the leds-lp5521 driver.
leds-lp5523.txt
- notes on how to use the leds-lp5523 driver.
+leds-lm3556.txt
+ - notes on how to use the leds-lm3556 driver.
diff --git a/Documentation/leds/leds-blinkm.txt b/Documentation/leds/leds-blinkm.txt
new file mode 100644
index 000000000000..9dd92f4cf4e1
--- /dev/null
+++ b/Documentation/leds/leds-blinkm.txt
@@ -0,0 +1,80 @@
+The leds-blinkm driver supports the devices of the BlinkM family.
+
+They are RGB-LED modules driven by a (AT)tiny microcontroller and
+communicate through I2C. The default address of these modules is
+0x09 but this can be changed through a command. By this you could
+dasy-chain up to 127 BlinkMs on an I2C bus.
+
+The device accepts RGB and HSB color values through separate commands.
+Also you can store blinking sequences as "scripts" in
+the controller and run them. Also fading is an option.
+
+The interface this driver provides is 2-fold:
+
+a) LED class interface for use with triggers
+############################################
+
+The registration follows the scheme:
+blinkm-<i2c-bus-nr>-<i2c-device-nr>-<color>
+
+$ ls -h /sys/class/leds/blinkm-6-*
+/sys/class/leds/blinkm-6-9-blue:
+brightness device max_brightness power subsystem trigger uevent
+
+/sys/class/leds/blinkm-6-9-green:
+brightness device max_brightness power subsystem trigger uevent
+
+/sys/class/leds/blinkm-6-9-red:
+brightness device max_brightness power subsystem trigger uevent
+
+(same is /sys/bus/i2c/devices/6-0009/leds)
+
+We can control the colors separated into red, green and blue and
+assign triggers on each color.
+
+E.g.:
+
+$ cat blinkm-6-9-blue/brightness
+05
+
+$ echo 200 > blinkm-6-9-blue/brightness
+$
+
+$ modprobe ledtrig-heartbeat
+$ echo heartbeat > blinkm-6-9-green/trigger
+$
+
+
+b) Sysfs group to control rgb, fade, hsb, scripts ...
+#####################################################
+
+This extended interface is available as folder blinkm
+in the sysfs folder of the I2C device.
+E.g. below /sys/bus/i2c/devices/6-0009/blinkm
+
+$ ls -h /sys/bus/i2c/devices/6-0009/blinkm/
+blue green red test
+
+Currently supported is just setting red, green, blue
+and a test sequence.
+
+E.g.:
+
+$ cat *
+00
+00
+00
+#Write into test to start test sequence!#
+
+$ echo 1 > test
+$
+
+$ echo 255 > red
+$
+
+
+
+as of 6/2012
+
+dl9pf <at> gmx <dot> de
+
diff --git a/Documentation/leds/leds-lm3556.txt b/Documentation/leds/leds-lm3556.txt
new file mode 100644
index 000000000000..d9eb91b51913
--- /dev/null
+++ b/Documentation/leds/leds-lm3556.txt
@@ -0,0 +1,85 @@
+Kernel driver for lm3556
+========================
+
+*Texas Instrument:
+ 1.5 A Synchronous Boost LED Flash Driver w/ High-Side Current Source
+* Datasheet: http://www.national.com/ds/LM/LM3556.pdf
+
+Authors:
+ Daniel Jeong
+ Contact:Daniel Jeong(daniel.jeong-at-ti.com, gshark.jeong-at-gmail.com)
+
+Description
+-----------
+There are 3 functions in LM3556, Flash, Torch and Indicator.
+
+FLASH MODE
+In Flash Mode, the LED current source(LED) provides 16 target current levels
+from 93.75 mA to 1500 mA.The Flash currents are adjusted via the CURRENT
+CONTROL REGISTER(0x09).Flash mode is activated by the ENABLE REGISTER(0x0A),
+or by pulling the STROBE pin HIGH.
+LM3556 Flash can be controlled through sys/class/leds/flash/brightness file
+* if STROBE pin is enabled, below example control brightness only, and
+ON / OFF will be controlled by STROBE pin.
+
+Flash Example:
+OFF : #echo 0 > sys/class/leds/flash/brightness
+93.75 mA: #echo 1 > sys/class/leds/flash/brightness
+... .....
+1500 mA: #echo 16 > sys/class/leds/flash/brightness
+
+TORCH MODE
+In Torch Mode, the current source(LED) is programmed via the CURRENT CONTROL
+REGISTER(0x09).Torch Mode is activated by the ENABLE REGISTER(0x0A) or by the
+hardware TORCH input.
+LM3556 torch can be controlled through sys/class/leds/torch/brightness file.
+* if TORCH pin is enabled, below example control brightness only,
+and ON / OFF will be controlled by TORCH pin.
+
+Torch Example:
+OFF : #echo 0 > sys/class/leds/torch/brightness
+46.88 mA: #echo 1 > sys/class/leds/torch/brightness
+... .....
+375 mA : #echo 8 > sys/class/leds/torch/brightness
+
+INDICATOR MODE
+Indicator pattern can be set through sys/class/leds/indicator/pattern file,
+and 4 patterns are pre-defined in indicator_pattern array.
+According to N-lank, Pulse time and N Period values, different pattern wiill
+be generated.If you want new patterns for your own device, change
+indicator_pattern array with your own values and INDIC_PATTERN_SIZE.
+Please refer datasheet for more detail about N-Blank, Pulse time and N Period.
+
+Indicator pattern example:
+pattern 0: #echo 0 > sys/class/leds/indicator/pattern
+....
+pattern 3: #echo 3 > sys/class/leds/indicator/pattern
+
+Indicator brightness can be controlled through
+sys/class/leds/indicator/brightness file.
+
+Example:
+OFF : #echo 0 > sys/class/leds/indicator/brightness
+5.86 mA : #echo 1 > sys/class/leds/indicator/brightness
+........
+46.875mA : #echo 8 > sys/class/leds/indicator/brightness
+
+Notes
+-----
+Driver expects it is registered using the i2c_board_info mechanism.
+To register the chip at address 0x63 on specific adapter, set the platform data
+according to include/linux/platform_data/leds-lm3556.h, set the i2c board info
+
+Example:
+ static struct i2c_board_info __initdata board_i2c_ch4[] = {
+ {
+ I2C_BOARD_INFO(LM3556_NAME, 0x63),
+ .platform_data = &lm3556_pdata,
+ },
+ };
+
+and register it in the platform init function
+
+Example:
+ board_register_i2c_bus(4, 400,
+ board_i2c_ch4, ARRAY_SIZE(board_i2c_ch4));
diff --git a/Documentation/leds/ledtrig-oneshot.txt b/Documentation/leds/ledtrig-oneshot.txt
new file mode 100644
index 000000000000..07cd1fa41a3a
--- /dev/null
+++ b/Documentation/leds/ledtrig-oneshot.txt
@@ -0,0 +1,59 @@
+One-shot LED Trigger
+====================
+
+This is a LED trigger useful for signaling the user of an event where there are
+no clear trap points to put standard led-on and led-off settings. Using this
+trigger, the application needs only to signal the trigger when an event has
+happened, than the trigger turns the LED on and than keeps it off for a
+specified amount of time.
+
+This trigger is meant to be usable both for sporadic and dense events. In the
+first case, the trigger produces a clear single controlled blink for each
+event, while in the latter it keeps blinking at constant rate, as to signal
+that the events are arriving continuously.
+
+A one-shot LED only stays in a constant state when there are no events. An
+additional "invert" property specifies if the LED has to stay off (normal) or
+on (inverted) when not rearmed.
+
+The trigger can be activated from user space on led class devices as shown
+below:
+
+ echo oneshot > trigger
+
+This adds the following sysfs attributes to the LED:
+
+ delay_on - specifies for how many milliseconds the LED has to stay at
+ LED_FULL brightness after it has been armed.
+ Default to 100 ms.
+
+ delay_off - specifies for how many milliseconds the LED has to stay at
+ LED_OFF brightness after it has been armed.
+ Default to 100 ms.
+
+ invert - reverse the blink logic. If set to 0 (default) blink on for delay_on
+ ms, then blink off for delay_off ms, leaving the LED normally off. If
+ set to 1, blink off for delay_off ms, then blink on for delay_on ms,
+ leaving the LED normally on.
+ Setting this value also immediately change the LED state.
+
+ shot - write any non-empty string to signal an events, this starts a blink
+ sequence if not already running.
+
+Example use-case: network devices, initialization:
+
+ echo oneshot > trigger # set trigger for this led
+ echo 33 > delay_on # blink at 1 / (33 + 33) Hz on continuous traffic
+ echo 33 > delay_off
+
+interface goes up:
+
+ echo 1 > invert # set led as normally-on, turn the led on
+
+packet received/transmitted:
+
+ echo 1 > shot # led starts blinking, ignored if already blinking
+
+interface goes down
+
+ echo 0 > invert # set led as normally-off, turn the led off
diff --git a/MAINTAINERS b/MAINTAINERS
index 8f363b005226..bd451649f13a 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1186,6 +1186,17 @@ S: Maintained
F: arch/arm/mach-pxa/vpac270.c
F: arch/arm/mach-pxa/include/mach/vpac270.h
+ARM/VT8500 ARM ARCHITECTURE
+M: Tony Prisk <linux@prisktech.co.nz>
+L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
+S: Maintained
+F: arch/arm/mach-vt8500/
+F: drivers/video/vt8500lcdfb.*
+F: drivers/video/wm8505fb*
+F: drivers/video/wmt_ge_rops.*
+F: drivers/tty/serial/vt8500_serial.c
+F: drivers/rtc/rtc-vt8500-c
+
ARM/ZIPIT Z2 SUPPORT
M: Marek Vasut <marek.vasut@gmail.com>
L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
@@ -1529,6 +1540,11 @@ W: http://blackfin.uclinux.org/
S: Supported
F: drivers/i2c/busses/i2c-bfin-twi.c
+BLINKM RGB LED DRIVER
+M: Jan-Simon Moeller <jansimon.moeller@gmx.de>
+S: Maintained
+F: drivers/leds/leds-blinkm.c
+
BLOCK LAYER
M: Jens Axboe <axboe@kernel.dk>
T: git git://git.kernel.org/pub/scm/linux/kernel/git/axboe/linux-block.git
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index b25c9d3c379a..9124ff75fe53 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -279,7 +279,6 @@ config ARCH_INTEGRATOR
select ICST
select GENERIC_CLOCKEVENTS
select PLAT_VERSATILE
- select PLAT_VERSATILE_CLOCK
select PLAT_VERSATILE_FPGA_IRQ
select NEED_MACH_IO_H
select NEED_MACH_MEMORY_H
@@ -336,7 +335,6 @@ config ARCH_VEXPRESS
select ICST
select NO_IOPORT
select PLAT_VERSATILE
- select PLAT_VERSATILE_CLOCK
select PLAT_VERSATILE_CLCD
select REGULATOR_FIXED_VOLTAGE if REGULATOR
help
diff --git a/arch/arm/boot/dts/kirkwood-dns320.dts b/arch/arm/boot/dts/kirkwood-dns320.dts
index dc09a735b04a..9a33077130e8 100644
--- a/arch/arm/boot/dts/kirkwood-dns320.dts
+++ b/arch/arm/boot/dts/kirkwood-dns320.dts
@@ -4,7 +4,7 @@
/ {
model = "D-Link DNS-320 NAS (Rev A1)";
- compatible = "dlink,dns-320-a1", "dlink,dns-320", "dlink,dns-kirkwood", "mrvl,kirkwood-88f6281", "mrvl,kirkwood";
+ compatible = "dlink,dns-320-a1", "dlink,dns-320", "dlink,dns-kirkwood", "marvell,kirkwood-88f6281", "marvell,kirkwood";
memory {
device_type = "memory";
diff --git a/arch/arm/boot/dts/kirkwood-dns325.dts b/arch/arm/boot/dts/kirkwood-dns325.dts
index c2a5562525d2..16734c1b5dfe 100644
--- a/arch/arm/boot/dts/kirkwood-dns325.dts
+++ b/arch/arm/boot/dts/kirkwood-dns325.dts
@@ -4,7 +4,7 @@
/ {
model = "D-Link DNS-325 NAS (Rev A1)";
- compatible = "dlink,dns-325-a1", "dlink,dns-325", "dlink,dns-kirkwood", "mrvl,kirkwood-88f6281", "mrvl,kirkwood";
+ compatible = "dlink,dns-325-a1", "dlink,dns-325", "dlink,dns-kirkwood", "marvell,kirkwood-88f6281", "marvell,kirkwood";
memory {
device_type = "memory";
diff --git a/arch/arm/boot/dts/kirkwood-dreamplug.dts b/arch/arm/boot/dts/kirkwood-dreamplug.dts
index a5376b84227f..78b0f06a09a2 100644
--- a/arch/arm/boot/dts/kirkwood-dreamplug.dts
+++ b/arch/arm/boot/dts/kirkwood-dreamplug.dts
@@ -4,7 +4,7 @@
/ {
model = "Globalscale Technologies Dreamplug";
- compatible = "globalscale,dreamplug-003-ds2001", "globalscale,dreamplug", "mrvl,kirkwood-88f6281", "mrvl,kirkwood";
+ compatible = "globalscale,dreamplug-003-ds2001", "globalscale,dreamplug", "marvell,kirkwood-88f6281", "marvell,kirkwood";
memory {
device_type = "memory";
diff --git a/arch/arm/boot/dts/kirkwood-ib62x0.dts b/arch/arm/boot/dts/kirkwood-ib62x0.dts
index ada0f0c23085..f59dcf6dc45f 100644
--- a/arch/arm/boot/dts/kirkwood-ib62x0.dts
+++ b/arch/arm/boot/dts/kirkwood-ib62x0.dts
@@ -4,7 +4,7 @@
/ {
model = "RaidSonic ICY BOX IB-NAS62x0 (Rev B)";
- compatible = "raidsonic,ib-nas6210-b", "raidsonic,ib-nas6220-b", "raidsonic,ib-nas6210", "raidsonic,ib-nas6220", "raidsonic,ib-nas62x0", "mrvl,kirkwood-88f6281", "mrvl,kirkwood";
+ compatible = "raidsonic,ib-nas6210-b", "raidsonic,ib-nas6220-b", "raidsonic,ib-nas6210", "raidsonic,ib-nas6220", "raidsonic,ib-nas62x0", "marvell,kirkwood-88f6281", "marvell,kirkwood";
memory {
device_type = "memory";
diff --git a/arch/arm/boot/dts/kirkwood-iconnect.dts b/arch/arm/boot/dts/kirkwood-iconnect.dts
index 1ba75d4adecc..026a1f82d813 100644
--- a/arch/arm/boot/dts/kirkwood-iconnect.dts
+++ b/arch/arm/boot/dts/kirkwood-iconnect.dts
@@ -4,7 +4,7 @@
/ {
model = "Iomega Iconnect";
- compatible = "iom,iconnect-1.1", "iom,iconnect", "mrvl,kirkwood-88f6281", "mrvl,kirkwood";
+ compatible = "iom,iconnect-1.1", "iom,iconnect", "marvell,kirkwood-88f6281", "marvell,kirkwood";
memory {
device_type = "memory";
diff --git a/arch/arm/boot/dts/kirkwood.dtsi b/arch/arm/boot/dts/kirkwood.dtsi
index 926528b81baa..f95dbc190ab6 100644
--- a/arch/arm/boot/dts/kirkwood.dtsi
+++ b/arch/arm/boot/dts/kirkwood.dtsi
@@ -1,7 +1,7 @@
/include/ "skeleton.dtsi"
/ {
- compatible = "mrvl,kirkwood";
+ compatible = "marvell,kirkwood";
ocp@f1000000 {
compatible = "simple-bus";
@@ -28,7 +28,7 @@
};
rtc@10300 {
- compatible = "mrvl,kirkwood-rtc", "mrvl,orion-rtc";
+ compatible = "marvell,kirkwood-rtc", "marvell,orion-rtc";
reg = <0x10300 0x20>;
interrupts = <53>;
};
@@ -39,7 +39,7 @@
cle = <0>;
ale = <1>;
bank-width = <1>;
- compatible = "mrvl,orion-nand";
+ compatible = "marvell,orion-nand";
reg = <0x3000000 0x400>;
chip-delay = <25>;
/* set partition map and/or chip-delay in board dts */
diff --git a/arch/arm/boot/dts/tegra20-trimslice.dts b/arch/arm/boot/dts/tegra20-trimslice.dts
index 9de5636023f6..27fb8a67ea42 100644
--- a/arch/arm/boot/dts/tegra20-trimslice.dts
+++ b/arch/arm/boot/dts/tegra20-trimslice.dts
@@ -276,9 +276,11 @@
usb@c5000000 {
status = "okay";
+ nvidia,vbus-gpio = <&gpio 170 0>; /* gpio PV2 */
};
usb@c5004000 {
+ status = "okay";
nvidia,phy-reset-gpio = <&gpio 168 0>; /* gpio PV0 */
};
diff --git a/arch/arm/mach-dove/common.c b/arch/arm/mach-dove/common.c
index 9493076fc594..4db5de54b6a7 100644
--- a/arch/arm/mach-dove/common.c
+++ b/arch/arm/mach-dove/common.c
@@ -101,8 +101,8 @@ void __init dove_ehci1_init(void)
****************************************************************************/
void __init dove_ge00_init(struct mv643xx_eth_platform_data *eth_data)
{
- orion_ge00_init(eth_data,
- DOVE_GE00_PHYS_BASE, IRQ_DOVE_GE00_SUM, 0);
+ orion_ge00_init(eth_data, DOVE_GE00_PHYS_BASE,
+ IRQ_DOVE_GE00_SUM, IRQ_DOVE_GE00_ERR);
}
/*****************************************************************************
diff --git a/arch/arm/mach-kirkwood/common.c b/arch/arm/mach-kirkwood/common.c
index f261cd242643..c9201539ffbd 100644
--- a/arch/arm/mach-kirkwood/common.c
+++ b/arch/arm/mach-kirkwood/common.c
@@ -67,6 +67,14 @@ void __init kirkwood_map_io(void)
* CLK tree
****************************************************************************/
+static void enable_sata0(void)
+{
+ /* Enable PLL and IVREF */
+ writel(readl(SATA0_PHY_MODE_2) | 0xf, SATA0_PHY_MODE_2);
+ /* Enable PHY */
+ writel(readl(SATA0_IF_CTRL) & ~0x200, SATA0_IF_CTRL);
+}
+
static void disable_sata0(void)
{
/* Disable PLL and IVREF */
@@ -75,6 +83,14 @@ static void disable_sata0(void)
writel(readl(SATA0_IF_CTRL) | 0x200, SATA0_IF_CTRL);
}
+static void enable_sata1(void)
+{
+ /* Enable PLL and IVREF */
+ writel(readl(SATA1_PHY_MODE_2) | 0xf, SATA1_PHY_MODE_2);
+ /* Enable PHY */
+ writel(readl(SATA1_IF_CTRL) & ~0x200, SATA1_IF_CTRL);
+}
+
static void disable_sata1(void)
{
/* Disable PLL and IVREF */
@@ -107,23 +123,38 @@ static void disable_pcie1(void)
}
}
-/* An extended version of the gated clk. This calls fn() before
- * disabling the clock. We use this to turn off PHYs etc. */
+/* An extended version of the gated clk. This calls fn_en()/fn_dis
+ * before enabling/disabling the clock. We use this to turn on/off
+ * PHYs etc. */
struct clk_gate_fn {
struct clk_gate gate;
- void (*fn)(void);
+ void (*fn_en)(void);
+ void (*fn_dis)(void);
};
#define to_clk_gate_fn(_gate) container_of(_gate, struct clk_gate_fn, gate)
#define to_clk_gate(_hw) container_of(_hw, struct clk_gate, hw)
+static int clk_gate_fn_enable(struct clk_hw *hw)
+{
+ struct clk_gate *gate = to_clk_gate(hw);
+ struct clk_gate_fn *gate_fn = to_clk_gate_fn(gate);
+ int ret;
+
+ ret = clk_gate_ops.enable(hw);
+ if (!ret && gate_fn->fn_en)
+ gate_fn->fn_en();
+
+ return ret;
+}
+
static void clk_gate_fn_disable(struct clk_hw *hw)
{
struct clk_gate *gate = to_clk_gate(hw);
struct clk_gate_fn *gate_fn = to_clk_gate_fn(gate);
- if (gate_fn->fn)
- gate_fn->fn();
+ if (gate_fn->fn_dis)
+ gate_fn->fn_dis();
clk_gate_ops.disable(hw);
}
@@ -135,7 +166,7 @@ static struct clk __init *clk_register_gate_fn(struct device *dev,
const char *parent_name, unsigned long flags,
void __iomem *reg, u8 bit_idx,
u8 clk_gate_flags, spinlock_t *lock,
- void (*fn)(void))
+ void (*fn_en)(void), void (*fn_dis)(void))
{
struct clk_gate_fn *gate_fn;
struct clk *clk;
@@ -159,11 +190,14 @@ static struct clk __init *clk_register_gate_fn(struct device *dev,
gate_fn->gate.flags = clk_gate_flags;
gate_fn->gate.lock = lock;
gate_fn->gate.hw.init = &init;
- gate_fn->fn = fn;
+ gate_fn->fn_en = fn_en;
+ gate_fn->fn_dis = fn_dis;
- /* ops is the gate ops, but with our disable function */
- if (clk_gate_fn_ops.disable != clk_gate_fn_disable) {
+ /* ops is the gate ops, but with our enable/disable functions */
+ if (clk_gate_fn_ops.enable != clk_gate_fn_enable ||
+ clk_gate_fn_ops.disable != clk_gate_fn_disable) {
clk_gate_fn_ops = clk_gate_ops;
+ clk_gate_fn_ops.enable = clk_gate_fn_enable;
clk_gate_fn_ops.disable = clk_gate_fn_disable;
}
@@ -187,11 +221,12 @@ static struct clk __init *kirkwood_register_gate(const char *name, u8 bit_idx)
static struct clk __init *kirkwood_register_gate_fn(const char *name,
u8 bit_idx,
- void (*fn)(void))
+ void (*fn_en)(void),
+ void (*fn_dis)(void))
{
return clk_register_gate_fn(NULL, name, "tclk", 0,
(void __iomem *)CLOCK_GATING_CTRL,
- bit_idx, 0, &gating_lock, fn);
+ bit_idx, 0, &gating_lock, fn_en, fn_dis);
}
static struct clk *ge0, *ge1;
@@ -208,18 +243,18 @@ void __init kirkwood_clk_init(void)
ge0 = kirkwood_register_gate("ge0", CGC_BIT_GE0);
ge1 = kirkwood_register_gate("ge1", CGC_BIT_GE1);
sata0 = kirkwood_register_gate_fn("sata0", CGC_BIT_SATA0,
- disable_sata0);
+ enable_sata0, disable_sata0);
sata1 = kirkwood_register_gate_fn("sata1", CGC_BIT_SATA1,
- disable_sata1);
+ enable_sata1, disable_sata1);
usb0 = kirkwood_register_gate("usb0", CGC_BIT_USB0);
sdio = kirkwood_register_gate("sdio", CGC_BIT_SDIO);
crypto = kirkwood_register_gate("crypto", CGC_BIT_CRYPTO);
xor0 = kirkwood_register_gate("xor0", CGC_BIT_XOR0);
xor1 = kirkwood_register_gate("xor1", CGC_BIT_XOR1);
pex0 = kirkwood_register_gate_fn("pex0", CGC_BIT_PEX0,
- disable_pcie0);
+ NULL, disable_pcie0);
pex1 = kirkwood_register_gate_fn("pex1", CGC_BIT_PEX1,
- disable_pcie1);
+ NULL, disable_pcie1);
audio = kirkwood_register_gate("audio", CGC_BIT_AUDIO);
kirkwood_register_gate("tdm", CGC_BIT_TDM);
kirkwood_register_gate("tsu", CGC_BIT_TSU);
@@ -241,6 +276,11 @@ void __init kirkwood_clk_init(void)
orion_clkdev_add("0", "pcie", pex0);
orion_clkdev_add("1", "pcie", pex1);
orion_clkdev_add(NULL, "kirkwood-i2s", audio);
+
+ /* Marvell says runit is used by SPI, UART, NAND, TWSI, ...,
+ * so should never be gated.
+ */
+ clk_prepare_enable(runit);
}
/*****************************************************************************
diff --git a/arch/arm/mach-mxs/mach-mxs.c b/arch/arm/mach-mxs/mach-mxs.c
index 648bdd05d38b..8dabfe81d07c 100644
--- a/arch/arm/mach-mxs/mach-mxs.c
+++ b/arch/arm/mach-mxs/mach-mxs.c
@@ -162,7 +162,7 @@ enum mac_oui {
static void __init update_fec_mac_prop(enum mac_oui oui)
{
struct device_node *np, *from = NULL;
- struct property *oldmac, *newmac;
+ struct property *newmac;
const u32 *ocotp = mxs_get_ocotp();
u8 *macaddr;
u32 val;
@@ -208,11 +208,7 @@ static void __init update_fec_mac_prop(enum mac_oui oui)
macaddr[4] = (val >> 8) & 0xff;
macaddr[5] = (val >> 0) & 0xff;
- oldmac = of_find_property(np, newmac->name, NULL);
- if (oldmac)
- prom_update_property(np, newmac, oldmac);
- else
- prom_add_property(np, newmac);
+ prom_update_property(np, newmac);
}
}
diff --git a/arch/arm/mach-tegra/board-harmony-power.c b/arch/arm/mach-tegra/board-harmony-power.c
index 44dcb2e869b5..8fd387bf31f0 100644
--- a/arch/arm/mach-tegra/board-harmony-power.c
+++ b/arch/arm/mach-tegra/board-harmony-power.c
@@ -19,6 +19,7 @@
#include <linux/platform_device.h>
#include <linux/gpio.h>
#include <linux/regulator/machine.h>
+#include <linux/regulator/fixed.h>
#include <linux/mfd/tps6586x.h>
#include <linux/of.h>
#include <linux/of_i2c.h>
@@ -34,7 +35,9 @@ static struct regulator_consumer_supply tps658621_ldo0_supply[] = {
};
static struct regulator_init_data ldo0_data = {
+ .supply_regulator = "vdd_sm2",
.constraints = {
+ .name = "vdd_ldo0",
.min_uV = 3300 * 1000,
.max_uV = 3300 * 1000,
.valid_modes_mask = (REGULATOR_MODE_NORMAL |
@@ -48,9 +51,11 @@ static struct regulator_init_data ldo0_data = {
.consumer_supplies = tps658621_ldo0_supply,
};
-#define HARMONY_REGULATOR_INIT(_id, _minmv, _maxmv) \
+#define HARMONY_REGULATOR_INIT(_id, _name, _supply, _minmv, _maxmv) \
static struct regulator_init_data _id##_data = { \
+ .supply_regulator = _supply, \
.constraints = { \
+ .name = _name, \
.min_uV = (_minmv)*1000, \
.max_uV = (_maxmv)*1000, \
.valid_modes_mask = (REGULATOR_MODE_NORMAL | \
@@ -61,18 +66,18 @@ static struct regulator_init_data ldo0_data = {
}, \
}
-HARMONY_REGULATOR_INIT(sm0, 725, 1500);
-HARMONY_REGULATOR_INIT(sm1, 725, 1500);
-HARMONY_REGULATOR_INIT(sm2, 3000, 4550);
-HARMONY_REGULATOR_INIT(ldo1, 725, 1500);
-HARMONY_REGULATOR_INIT(ldo2, 725, 1500);
-HARMONY_REGULATOR_INIT(ldo3, 1250, 3300);
-HARMONY_REGULATOR_INIT(ldo4, 1700, 2475);
-HARMONY_REGULATOR_INIT(ldo5, 1250, 3300);
-HARMONY_REGULATOR_INIT(ldo6, 1250, 3300);
-HARMONY_REGULATOR_INIT(ldo7, 1250, 3300);
-HARMONY_REGULATOR_INIT(ldo8, 1250, 3300);
-HARMONY_REGULATOR_INIT(ldo9, 1250, 3300);
+HARMONY_REGULATOR_INIT(sm0, "vdd_sm0", "vdd_sys", 725, 1500);
+HARMONY_REGULATOR_INIT(sm1, "vdd_sm1", "vdd_sys", 725, 1500);
+HARMONY_REGULATOR_INIT(sm2, "vdd_sm2", "vdd_sys", 3000, 4550);
+HARMONY_REGULATOR_INIT(ldo1, "vdd_ldo1", "vdd_sm2", 725, 1500);
+HARMONY_REGULATOR_INIT(ldo2, "vdd_ldo2", "vdd_sm2", 725, 1500);
+HARMONY_REGULATOR_INIT(ldo3, "vdd_ldo3", "vdd_sm2", 1250, 3300);
+HARMONY_REGULATOR_INIT(ldo4, "vdd_ldo4", "vdd_sm2", 1700, 2475);
+HARMONY_REGULATOR_INIT(ldo5, "vdd_ldo5", NULL, 1250, 3300);
+HARMONY_REGULATOR_INIT(ldo6, "vdd_ldo6", "vdd_sm2", 1250, 3300);
+HARMONY_REGULATOR_INIT(ldo7, "vdd_ldo7", "vdd_sm2", 1250, 3300);
+HARMONY_REGULATOR_INIT(ldo8, "vdd_ldo8", "vdd_sm2", 1250, 3300);
+HARMONY_REGULATOR_INIT(ldo9, "vdd_ldo9", "vdd_sm2", 1250, 3300);
#define TPS_REG(_id, _data) \
{ \
@@ -115,6 +120,8 @@ static struct i2c_board_info __initdata harmony_regulators[] = {
int __init harmony_regulator_init(void)
{
if (machine_is_harmony()) {
+ regulator_register_always_on(0, "vdd_sys",
+ NULL, 0, 5000000);
i2c_register_board_info(3, harmony_regulators, 1);
} else { /* Harmony, booted using device tree */
struct device_node *np;
diff --git a/arch/powerpc/configs/g5_defconfig b/arch/powerpc/configs/g5_defconfig
index 07b7f2af2dca..15130066e5e2 100644
--- a/arch/powerpc/configs/g5_defconfig
+++ b/arch/powerpc/configs/g5_defconfig
@@ -1,10 +1,8 @@
-CONFIG_PPC64=y
-CONFIG_ALTIVEC=y
-CONFIG_SMP=y
-CONFIG_NR_CPUS=4
CONFIG_EXPERIMENTAL=y
CONFIG_SYSVIPC=y
CONFIG_POSIX_MQUEUE=y
+CONFIG_NO_HZ=y
+CONFIG_HIGH_RES_TIMERS=y
CONFIG_IKCONFIG=y
CONFIG_IKCONFIG_PROC=y
CONFIG_BLK_DEV_INITRD=y
@@ -15,16 +13,15 @@ CONFIG_MODULES=y
CONFIG_MODULE_UNLOAD=y
CONFIG_MODVERSIONS=y
CONFIG_MODULE_SRCVERSION_ALL=y
-# CONFIG_PPC_PSERIES is not set
+CONFIG_PARTITION_ADVANCED=y
+CONFIG_MAC_PARTITION=y
+CONFIG_SMP=y
+CONFIG_NR_CPUS=4
+CONFIG_KEXEC=y
+# CONFIG_RELOCATABLE is not set
CONFIG_CPU_FREQ=y
CONFIG_CPU_FREQ_GOV_POWERSAVE=y
CONFIG_CPU_FREQ_GOV_USERSPACE=y
-CONFIG_CPU_FREQ_PMAC64=y
-CONFIG_NO_HZ=y
-CONFIG_HIGH_RES_TIMERS=y
-CONFIG_KEXEC=y
-CONFIG_IRQ_ALL_CPUS=y
-# CONFIG_MIGRATION is not set
CONFIG_PCI_MSI=y
CONFIG_NET=y
CONFIG_PACKET=y
@@ -52,7 +49,6 @@ CONFIG_NF_CT_NETLINK=m
CONFIG_NF_CONNTRACK_IPV4=m
CONFIG_IP_NF_QUEUE=m
CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
-CONFIG_PROC_DEVICETREE=y
CONFIG_BLK_DEV_LOOP=y
CONFIG_BLK_DEV_NBD=m
CONFIG_BLK_DEV_RAM=y
@@ -60,8 +56,6 @@ CONFIG_BLK_DEV_RAM_SIZE=65536
CONFIG_CDROM_PKTCDVD=m
CONFIG_IDE=y
CONFIG_BLK_DEV_IDECD=y
-CONFIG_BLK_DEV_IDE_PMAC=y
-CONFIG_BLK_DEV_IDE_PMAC_ATA100FIRST=y
CONFIG_BLK_DEV_SD=y
CONFIG_CHR_DEV_ST=y
CONFIG_BLK_DEV_SR=y
@@ -85,33 +79,24 @@ CONFIG_DM_CRYPT=m
CONFIG_DM_SNAPSHOT=m
CONFIG_DM_MIRROR=m
CONFIG_DM_ZERO=m
-CONFIG_IEEE1394=y
-CONFIG_IEEE1394_OHCI1394=y
-CONFIG_IEEE1394_SBP2=m
-CONFIG_IEEE1394_ETH1394=m
-CONFIG_IEEE1394_RAWIO=y
-CONFIG_IEEE1394_VIDEO1394=m
-CONFIG_IEEE1394_DV1394=m
-CONFIG_ADB_PMU=y
-CONFIG_PMAC_SMU=y
+CONFIG_MACINTOSH_DRIVERS=y
CONFIG_MAC_EMUMOUSEBTN=y
-CONFIG_THERM_PM72=y
-CONFIG_WINDFARM=y
-CONFIG_WINDFARM_PM81=y
-CONFIG_WINDFARM_PM91=y
-CONFIG_WINDFARM_PM112=y
-CONFIG_WINDFARM_PM121=y
CONFIG_NETDEVICES=y
-CONFIG_DUMMY=m
CONFIG_BONDING=m
-CONFIG_TUN=m
-CONFIG_NET_ETHERNET=y
+CONFIG_DUMMY=m
CONFIG_MII=y
-CONFIG_SUNGEM=y
+CONFIG_TUN=m
CONFIG_ACENIC=m
CONFIG_ACENIC_OMIT_TIGON_I=y
-CONFIG_E1000=y
CONFIG_TIGON3=y
+CONFIG_E1000=y
+CONFIG_SUNGEM=y
+CONFIG_PPP=m
+CONFIG_PPP_BSDCOMP=m
+CONFIG_PPP_DEFLATE=m
+CONFIG_PPPOE=m
+CONFIG_PPP_ASYNC=m
+CONFIG_PPP_SYNC_TTY=m
CONFIG_USB_CATC=m
CONFIG_USB_KAWETH=m
CONFIG_USB_PEGASUS=m
@@ -121,36 +106,24 @@ CONFIG_USB_USBNET=m
# CONFIG_USB_NET_NET1080 is not set
# CONFIG_USB_NET_CDC_SUBSET is not set
# CONFIG_USB_NET_ZAURUS is not set
-CONFIG_PPP=m
-CONFIG_PPP_ASYNC=m
-CONFIG_PPP_SYNC_TTY=m
-CONFIG_PPP_DEFLATE=m
-CONFIG_PPP_BSDCOMP=m
-CONFIG_PPPOE=m
# CONFIG_INPUT_MOUSEDEV_PSAUX is not set
CONFIG_INPUT_JOYDEV=m
CONFIG_INPUT_EVDEV=y
-# CONFIG_KEYBOARD_ATKBD is not set
# CONFIG_MOUSE_PS2 is not set
-# CONFIG_SERIO_I8042 is not set
# CONFIG_SERIO_SERPORT is not set
+CONFIG_VT_HW_CONSOLE_BINDING=y
# CONFIG_HW_RANDOM is not set
CONFIG_GEN_RTC=y
CONFIG_RAW_DRIVER=y
CONFIG_I2C_CHARDEV=y
# CONFIG_HWMON is not set
-CONFIG_AGP=m
-CONFIG_AGP_UNINORTH=m
+CONFIG_AGP=y
+CONFIG_DRM=y
+CONFIG_DRM_NOUVEAU=y
CONFIG_VIDEO_OUTPUT_CONTROL=m
-CONFIG_FB=y
CONFIG_FIRMWARE_EDID=y
CONFIG_FB_TILEBLITTING=y
-CONFIG_FB_OF=y
-CONFIG_FB_NVIDIA=y
-CONFIG_FB_NVIDIA_I2C=y
CONFIG_FB_RADEON=y
-# CONFIG_VGA_CONSOLE is not set
-CONFIG_FRAMEBUFFER_CONSOLE=y
CONFIG_LOGO=y
CONFIG_SOUND=m
CONFIG_SND=m
@@ -158,15 +131,7 @@ CONFIG_SND_SEQUENCER=m
CONFIG_SND_MIXER_OSS=m
CONFIG_SND_PCM_OSS=m
CONFIG_SND_SEQUENCER_OSS=y
-CONFIG_SND_POWERMAC=m
-CONFIG_SND_AOA=m
-CONFIG_SND_AOA_FABRIC_LAYOUT=m
-CONFIG_SND_AOA_ONYX=m
-CONFIG_SND_AOA_TAS=m
-CONFIG_SND_AOA_TOONIE=m
CONFIG_SND_USB_AUDIO=m
-CONFIG_HID_PID=y
-CONFIG_USB_HIDDEV=y
CONFIG_HID_GYRATION=y
CONFIG_LOGITECH_FF=y
CONFIG_HID_PANTHERLORD=y
@@ -174,13 +139,12 @@ CONFIG_HID_PETALYNX=y
CONFIG_HID_SAMSUNG=y
CONFIG_HID_SONY=y
CONFIG_HID_SUNPLUS=y
+CONFIG_HID_PID=y
+CONFIG_USB_HIDDEV=y
CONFIG_USB=y
-CONFIG_USB_DEVICEFS=y
CONFIG_USB_MON=y
CONFIG_USB_EHCI_HCD=y
-# CONFIG_USB_EHCI_HCD_PPC_OF is not set
CONFIG_USB_OHCI_HCD=y
-CONFIG_USB_OHCI_HCD_PPC_OF_BE=y
CONFIG_USB_ACM=m
CONFIG_USB_PRINTER=y
CONFIG_USB_STORAGE=y
@@ -244,8 +208,6 @@ CONFIG_REISERFS_FS_POSIX_ACL=y
CONFIG_REISERFS_FS_SECURITY=y
CONFIG_XFS_FS=m
CONFIG_XFS_POSIX_ACL=y
-CONFIG_INOTIFY=y
-CONFIG_AUTOFS_FS=m
CONFIG_ISO9660_FS=y
CONFIG_JOLIET=y
CONFIG_ZISOFS=y
@@ -259,14 +221,12 @@ CONFIG_HFS_FS=m
CONFIG_HFSPLUS_FS=m
CONFIG_CRAMFS=y
CONFIG_NFS_FS=y
-CONFIG_NFS_V3=y
CONFIG_NFS_V3_ACL=y
CONFIG_NFS_V4=y
CONFIG_NFSD=y
CONFIG_NFSD_V3_ACL=y
CONFIG_NFSD_V4=y
CONFIG_CIFS=m
-CONFIG_PARTITION_ADVANCED=y
CONFIG_NLS_CODEPAGE_437=y
CONFIG_NLS_CODEPAGE_1250=y
CONFIG_NLS_CODEPAGE_1251=y
@@ -274,29 +234,23 @@ CONFIG_NLS_ASCII=y
CONFIG_NLS_ISO8859_1=y
CONFIG_NLS_ISO8859_15=y
CONFIG_NLS_UTF8=y
-CONFIG_CRC_T10DIF=y
-CONFIG_LIBCRC32C=m
CONFIG_MAGIC_SYSRQ=y
+# CONFIG_UNUSED_SYMBOLS is not set
CONFIG_DEBUG_FS=y
CONFIG_DEBUG_KERNEL=y
CONFIG_DEBUG_MUTEXES=y
-# CONFIG_RCU_CPU_STALL_DETECTOR is not set
CONFIG_LATENCYTOP=y
-CONFIG_SYSCTL_SYSCALL_CHECK=y
-CONFIG_BOOTX_TEXT=y
+CONFIG_STRICT_DEVMEM=y
CONFIG_CRYPTO_NULL=m
CONFIG_CRYPTO_TEST=m
-CONFIG_CRYPTO_ECB=m
CONFIG_CRYPTO_PCBC=m
CONFIG_CRYPTO_HMAC=y
-CONFIG_CRYPTO_MD4=m
CONFIG_CRYPTO_MICHAEL_MIC=m
CONFIG_CRYPTO_SHA256=m
CONFIG_CRYPTO_SHA512=m
CONFIG_CRYPTO_WP512=m
CONFIG_CRYPTO_AES=m
CONFIG_CRYPTO_ANUBIS=m
-CONFIG_CRYPTO_ARC4=m
CONFIG_CRYPTO_BLOWFISH=m
CONFIG_CRYPTO_CAST5=m
CONFIG_CRYPTO_CAST6=m
@@ -306,3 +260,6 @@ CONFIG_CRYPTO_TEA=m
CONFIG_CRYPTO_TWOFISH=m
# CONFIG_CRYPTO_ANSI_CPRNG is not set
# CONFIG_CRYPTO_HW is not set
+# CONFIG_VIRTUALIZATION is not set
+CONFIG_CRC_T10DIF=y
+CONFIG_LIBCRC32C=m
diff --git a/arch/powerpc/configs/ppc64_defconfig b/arch/powerpc/configs/ppc64_defconfig
index f2fe0c2b41e4..db27c82e0542 100644
--- a/arch/powerpc/configs/ppc64_defconfig
+++ b/arch/powerpc/configs/ppc64_defconfig
@@ -279,7 +279,8 @@ CONFIG_HVC_RTAS=y
CONFIG_HVC_BEAT=y
CONFIG_HVCS=m
CONFIG_IBM_BSR=m
-# CONFIG_HW_RANDOM is not set
+CONFIG_HW_RANDOM=m
+CONFIG_HW_RANDOM_PSERIES=m
CONFIG_RAW_DRIVER=y
CONFIG_I2C_CHARDEV=y
CONFIG_I2C_AMD8111=y
@@ -485,7 +486,8 @@ CONFIG_CRYPTO_TEA=m
CONFIG_CRYPTO_TWOFISH=m
CONFIG_CRYPTO_LZO=m
# CONFIG_CRYPTO_ANSI_CPRNG is not set
-# CONFIG_CRYPTO_HW is not set
+CONFIG_CRYPTO_HW=y
+CONFIG_CRYPTO_DEV_NX=m
CONFIG_VIRTUALIZATION=y
CONFIG_KVM_BOOK3S_64=m
CONFIG_KVM_BOOK3S_64_HV=y
diff --git a/arch/powerpc/configs/pseries_defconfig b/arch/powerpc/configs/pseries_defconfig
index 187fb8d53605..1f65b3c9b59a 100644
--- a/arch/powerpc/configs/pseries_defconfig
+++ b/arch/powerpc/configs/pseries_defconfig
@@ -226,7 +226,8 @@ CONFIG_HVC_CONSOLE=y
CONFIG_HVC_RTAS=y
CONFIG_HVCS=m
CONFIG_IBM_BSR=m
-# CONFIG_HW_RANDOM is not set
+CONFIG_HW_RANDOM=m
+CONFIG_HW_RANDOM_PSERIES=m
CONFIG_GEN_RTC=y
CONFIG_RAW_DRIVER=y
CONFIG_MAX_RAW_DEVS=1024
@@ -367,7 +368,8 @@ CONFIG_CRYPTO_TEA=m
CONFIG_CRYPTO_TWOFISH=m
CONFIG_CRYPTO_LZO=m
# CONFIG_CRYPTO_ANSI_CPRNG is not set
-# CONFIG_CRYPTO_HW is not set
+CONFIG_CRYPTO_HW=y
+CONFIG_CRYPTO_DEV_NX=m
CONFIG_VIRTUALIZATION=y
CONFIG_KVM_BOOK3S_64=m
CONFIG_KVM_BOOK3S_64_HV=y
diff --git a/arch/powerpc/kernel/entry_32.S b/arch/powerpc/kernel/entry_32.S
index 5207d5a405e2..ead5016b02d0 100644
--- a/arch/powerpc/kernel/entry_32.S
+++ b/arch/powerpc/kernel/entry_32.S
@@ -89,10 +89,14 @@ crit_transfer_to_handler:
mfspr r0,SPRN_SRR1
stw r0,_SRR1(r11)
+ /* set the stack limit to the current stack
+ * and set the limit to protect the thread_info
+ * struct
+ */
mfspr r8,SPRN_SPRG_THREAD
lwz r0,KSP_LIMIT(r8)
stw r0,SAVED_KSP_LIMIT(r11)
- CURRENT_THREAD_INFO(r0, r1)
+ rlwimi r0,r1,0,0,(31-THREAD_SHIFT)
stw r0,KSP_LIMIT(r8)
/* fall through */
#endif
@@ -109,10 +113,14 @@ crit_transfer_to_handler:
mfspr r0,SPRN_SRR1
stw r0,crit_srr1@l(0)
+ /* set the stack limit to the current stack
+ * and set the limit to protect the thread_info
+ * struct
+ */
mfspr r8,SPRN_SPRG_THREAD
lwz r0,KSP_LIMIT(r8)
stw r0,saved_ksp_limit@l(0)
- CURRENT_THREAD_INFO(r0, r1)
+ rlwimi r0,r1,0,0,(31-THREAD_SHIFT)
stw r0,KSP_LIMIT(r8)
/* fall through */
#endif
diff --git a/arch/powerpc/kernel/ftrace.c b/arch/powerpc/kernel/ftrace.c
index 91b46b7f6f0d..1fb78561096a 100644
--- a/arch/powerpc/kernel/ftrace.c
+++ b/arch/powerpc/kernel/ftrace.c
@@ -630,18 +630,17 @@ void prepare_ftrace_return(unsigned long *parent, unsigned long self_addr)
return;
}
- if (ftrace_push_return_trace(old, self_addr, &trace.depth, 0) == -EBUSY) {
- *parent = old;
- return;
- }
-
trace.func = self_addr;
+ trace.depth = current->curr_ret_stack + 1;
/* Only trace if the calling function expects to */
if (!ftrace_graph_entry(&trace)) {
- current->curr_ret_stack--;
*parent = old;
+ return;
}
+
+ if (ftrace_push_return_trace(old, self_addr, &trace.depth, 0) == -EBUSY)
+ *parent = old;
}
#endif /* CONFIG_FUNCTION_GRAPH_TRACER */
diff --git a/arch/powerpc/kernel/rtas_flash.c b/arch/powerpc/kernel/rtas_flash.c
index 4174b4b23246..2c0ee6405633 100644
--- a/arch/powerpc/kernel/rtas_flash.c
+++ b/arch/powerpc/kernel/rtas_flash.c
@@ -709,7 +709,7 @@ static int __init rtas_flash_init(void)
if (rtas_token("ibm,update-flash-64-and-reboot") ==
RTAS_UNKNOWN_SERVICE) {
- printk(KERN_ERR "rtas_flash: no firmware flash support\n");
+ pr_info("rtas_flash: no firmware flash support\n");
return 1;
}
diff --git a/arch/powerpc/kvm/bookehv_interrupts.S b/arch/powerpc/kvm/bookehv_interrupts.S
index d28c2d43ac1b..099fe8272b57 100644
--- a/arch/powerpc/kvm/bookehv_interrupts.S
+++ b/arch/powerpc/kvm/bookehv_interrupts.S
@@ -50,8 +50,9 @@
#define HOST_R2 (3 * LONGBYTES)
#define HOST_CR (4 * LONGBYTES)
#define HOST_NV_GPRS (5 * LONGBYTES)
-#define HOST_NV_GPR(n) (HOST_NV_GPRS + ((n - 14) * LONGBYTES))
-#define HOST_MIN_STACK_SIZE (HOST_NV_GPR(31) + LONGBYTES)
+#define __HOST_NV_GPR(n) (HOST_NV_GPRS + ((n - 14) * LONGBYTES))
+#define HOST_NV_GPR(n) __HOST_NV_GPR(__REG_##n)
+#define HOST_MIN_STACK_SIZE (HOST_NV_GPR(R31) + LONGBYTES)
#define HOST_STACK_SIZE ((HOST_MIN_STACK_SIZE + 15) & ~15) /* Align. */
#define HOST_STACK_LR (HOST_STACK_SIZE + LONGBYTES) /* In caller stack frame. */
@@ -410,24 +411,24 @@ heavyweight_exit:
PPC_STL r31, VCPU_GPR(R31)(r4)
/* Load host non-volatile register state from host stack. */
- PPC_LL r14, HOST_NV_GPR(r14)(r1)
- PPC_LL r15, HOST_NV_GPR(r15)(r1)
- PPC_LL r16, HOST_NV_GPR(r16)(r1)
- PPC_LL r17, HOST_NV_GPR(r17)(r1)
- PPC_LL r18, HOST_NV_GPR(r18)(r1)
- PPC_LL r19, HOST_NV_GPR(r19)(r1)
- PPC_LL r20, HOST_NV_GPR(r20)(r1)
- PPC_LL r21, HOST_NV_GPR(r21)(r1)
- PPC_LL r22, HOST_NV_GPR(r22)(r1)
- PPC_LL r23, HOST_NV_GPR(r23)(r1)
- PPC_LL r24, HOST_NV_GPR(r24)(r1)
- PPC_LL r25, HOST_NV_GPR(r25)(r1)
- PPC_LL r26, HOST_NV_GPR(r26)(r1)
- PPC_LL r27, HOST_NV_GPR(r27)(r1)
- PPC_LL r28, HOST_NV_GPR(r28)(r1)
- PPC_LL r29, HOST_NV_GPR(r29)(r1)
- PPC_LL r30, HOST_NV_GPR(r30)(r1)
- PPC_LL r31, HOST_NV_GPR(r31)(r1)
+ PPC_LL r14, HOST_NV_GPR(R14)(r1)
+ PPC_LL r15, HOST_NV_GPR(R15)(r1)
+ PPC_LL r16, HOST_NV_GPR(R16)(r1)
+ PPC_LL r17, HOST_NV_GPR(R17)(r1)
+ PPC_LL r18, HOST_NV_GPR(R18)(r1)
+ PPC_LL r19, HOST_NV_GPR(R19)(r1)
+ PPC_LL r20, HOST_NV_GPR(R20)(r1)
+ PPC_LL r21, HOST_NV_GPR(R21)(r1)
+ PPC_LL r22, HOST_NV_GPR(R22)(r1)
+ PPC_LL r23, HOST_NV_GPR(R23)(r1)
+ PPC_LL r24, HOST_NV_GPR(R24)(r1)
+ PPC_LL r25, HOST_NV_GPR(R25)(r1)
+ PPC_LL r26, HOST_NV_GPR(R26)(r1)
+ PPC_LL r27, HOST_NV_GPR(R27)(r1)
+ PPC_LL r28, HOST_NV_GPR(R28)(r1)
+ PPC_LL r29, HOST_NV_GPR(R29)(r1)
+ PPC_LL r30, HOST_NV_GPR(R30)(r1)
+ PPC_LL r31, HOST_NV_GPR(R31)(r1)
/* Return to kvm_vcpu_run(). */
mtlr r5
@@ -453,24 +454,24 @@ _GLOBAL(__kvmppc_vcpu_run)
stw r5, HOST_CR(r1)
/* Save host non-volatile register state to stack. */
- PPC_STL r14, HOST_NV_GPR(r14)(r1)
- PPC_STL r15, HOST_NV_GPR(r15)(r1)
- PPC_STL r16, HOST_NV_GPR(r16)(r1)
- PPC_STL r17, HOST_NV_GPR(r17)(r1)
- PPC_STL r18, HOST_NV_GPR(r18)(r1)
- PPC_STL r19, HOST_NV_GPR(r19)(r1)
- PPC_STL r20, HOST_NV_GPR(r20)(r1)
- PPC_STL r21, HOST_NV_GPR(r21)(r1)
- PPC_STL r22, HOST_NV_GPR(r22)(r1)
- PPC_STL r23, HOST_NV_GPR(r23)(r1)
- PPC_STL r24, HOST_NV_GPR(r24)(r1)
- PPC_STL r25, HOST_NV_GPR(r25)(r1)
- PPC_STL r26, HOST_NV_GPR(r26)(r1)
- PPC_STL r27, HOST_NV_GPR(r27)(r1)
- PPC_STL r28, HOST_NV_GPR(r28)(r1)
- PPC_STL r29, HOST_NV_GPR(r29)(r1)
- PPC_STL r30, HOST_NV_GPR(r30)(r1)
- PPC_STL r31, HOST_NV_GPR(r31)(r1)
+ PPC_STL r14, HOST_NV_GPR(R14)(r1)
+ PPC_STL r15, HOST_NV_GPR(R15)(r1)
+ PPC_STL r16, HOST_NV_GPR(R16)(r1)
+ PPC_STL r17, HOST_NV_GPR(R17)(r1)
+ PPC_STL r18, HOST_NV_GPR(R18)(r1)
+ PPC_STL r19, HOST_NV_GPR(R19)(r1)
+ PPC_STL r20, HOST_NV_GPR(R20)(r1)
+ PPC_STL r21, HOST_NV_GPR(R21)(r1)
+ PPC_STL r22, HOST_NV_GPR(R22)(r1)
+ PPC_STL r23, HOST_NV_GPR(R23)(r1)
+ PPC_STL r24, HOST_NV_GPR(R24)(r1)
+ PPC_STL r25, HOST_NV_GPR(R25)(r1)
+ PPC_STL r26, HOST_NV_GPR(R26)(r1)
+ PPC_STL r27, HOST_NV_GPR(R27)(r1)
+ PPC_STL r28, HOST_NV_GPR(R28)(r1)
+ PPC_STL r29, HOST_NV_GPR(R29)(r1)
+ PPC_STL r30, HOST_NV_GPR(R30)(r1)
+ PPC_STL r31, HOST_NV_GPR(R31)(r1)
/* Load guest non-volatiles. */
PPC_LL r14, VCPU_GPR(R14)(r4)
diff --git a/drivers/crypto/mv_cesa.c b/drivers/crypto/mv_cesa.c
index 0d4071754352..21c1a87032b7 100644
--- a/drivers/crypto/mv_cesa.c
+++ b/drivers/crypto/mv_cesa.c
@@ -1127,6 +1127,10 @@ err_unreg_ecb:
crypto_unregister_alg(&mv_aes_alg_ecb);
err_irq:
free_irq(irq, cp);
+ if (!IS_ERR(cp->clk)) {
+ clk_disable_unprepare(cp->clk);
+ clk_put(cp->clk);
+ }
err_thread:
kthread_stop(cp->queue_th);
err_unmap_sram:
diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig
index 12b2b55c519e..c96bbaadeebd 100644
--- a/drivers/leds/Kconfig
+++ b/drivers/leds/Kconfig
@@ -200,6 +200,13 @@ config LEDS_LP5523
Driver provides direct control via LED class and interface for
programming the engines.
+config LEDS_LP8788
+ tristate "LED support for the TI LP8788 PMIC"
+ depends on LEDS_CLASS
+ depends on MFD_LP8788
+ help
+ This option enables support for the Keyboard LEDs on the LP8788 PMIC.
+
config LEDS_CLEVO_MAIL
tristate "Mail LED on Clevo notebook"
depends on LEDS_CLASS
@@ -415,6 +422,14 @@ config LEDS_MAX8997
This option enables support for on-chip LED drivers on
MAXIM MAX8997 PMIC.
+config LEDS_LM3556
+ tristate "LED support for LM3556 Chip"
+ depends on LEDS_CLASS && I2C
+ select REGMAP_I2C
+ help
+ This option enables support for LEDs connected to LM3556.
+ LM3556 includes Torch, Flash and Indicator functions.
+
config LEDS_OT200
tristate "LED support for the Bachmann OT200"
depends on LEDS_CLASS && HAS_IOMEM
@@ -422,6 +437,14 @@ 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_BLINKM
+ tristate "LED support for the BlinkM I2C RGB LED"
+ depends on LEDS_CLASS
+ depends on I2C
+ help
+ This option enables support for the BlinkM RGB LED connected
+ through I2C. Say Y to enable support for the BlinkM LED.
+
config LEDS_TRIGGERS
bool "LED Trigger support"
depends on LEDS_CLASS
@@ -443,6 +466,20 @@ config LEDS_TRIGGER_TIMER
If unsure, say Y.
+config LEDS_TRIGGER_ONESHOT
+ tristate "LED One-shot Trigger"
+ depends on LEDS_TRIGGERS
+ help
+ This allows LEDs to blink in one-shot pulses with parameters
+ controlled via sysfs. It's useful to notify the user on
+ sporadic events, when there are no clear begin and end trap points,
+ or on dense events, where this blinks the LED at constant rate if
+ rearmed continuously.
+
+ It also shows how to use the led_blink_set_oneshot() function.
+
+ If unsure, say Y.
+
config LEDS_TRIGGER_IDE_DISK
bool "LED IDE Disk Trigger"
depends on IDE_GD_ATA
@@ -497,7 +534,7 @@ config LEDS_TRIGGER_TRANSIENT
depends on LEDS_TRIGGERS
help
This allows one time activation of a transient state on
- GPIO/PWM based hadrware.
+ GPIO/PWM based hardware.
If unsure, say Y.
endif # NEW_LEDS
diff --git a/drivers/leds/Makefile b/drivers/leds/Makefile
index f8958cd6cf6e..a4429a9217bc 100644
--- a/drivers/leds/Makefile
+++ b/drivers/leds/Makefile
@@ -24,6 +24,7 @@ obj-$(CONFIG_LEDS_GPIO) += leds-gpio.o
obj-$(CONFIG_LEDS_LP3944) += leds-lp3944.o
obj-$(CONFIG_LEDS_LP5521) += leds-lp5521.o
obj-$(CONFIG_LEDS_LP5523) += leds-lp5523.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_HP6XX) += leds-hp6xx.o
@@ -47,12 +48,15 @@ obj-$(CONFIG_LEDS_NETXBIG) += leds-netxbig.o
obj-$(CONFIG_LEDS_ASIC3) += leds-asic3.o
obj-$(CONFIG_LEDS_RENESAS_TPU) += leds-renesas-tpu.o
obj-$(CONFIG_LEDS_MAX8997) += leds-max8997.o
+obj-$(CONFIG_LEDS_LM3556) += leds-lm3556.o
+obj-$(CONFIG_LEDS_BLINKM) += leds-blinkm.o
# LED SPI Drivers
obj-$(CONFIG_LEDS_DAC124S085) += leds-dac124s085.o
# LED Triggers
obj-$(CONFIG_LEDS_TRIGGER_TIMER) += ledtrig-timer.o
+obj-$(CONFIG_LEDS_TRIGGER_ONESHOT) += ledtrig-oneshot.o
obj-$(CONFIG_LEDS_TRIGGER_IDE_DISK) += ledtrig-ide-disk.o
obj-$(CONFIG_LEDS_TRIGGER_HEARTBEAT) += ledtrig-heartbeat.o
obj-$(CONFIG_LEDS_TRIGGER_BACKLIGHT) += ledtrig-backlight.o
diff --git a/drivers/leds/led-class.c b/drivers/leds/led-class.c
index e663e6f413e9..c599095bc005 100644
--- a/drivers/leds/led-class.c
+++ b/drivers/leds/led-class.c
@@ -53,7 +53,7 @@ static ssize_t led_brightness_store(struct device *dev,
if (state == LED_OFF)
led_trigger_remove(led_cdev);
- led_set_brightness(led_cdev, state);
+ __led_set_brightness(led_cdev, state);
return size;
}
@@ -82,7 +82,12 @@ static void led_timer_function(unsigned long data)
unsigned long delay;
if (!led_cdev->blink_delay_on || !led_cdev->blink_delay_off) {
- led_set_brightness(led_cdev, LED_OFF);
+ __led_set_brightness(led_cdev, LED_OFF);
+ return;
+ }
+
+ if (led_cdev->flags & LED_BLINK_ONESHOT_STOP) {
+ led_cdev->flags &= ~LED_BLINK_ONESHOT_STOP;
return;
}
@@ -100,7 +105,21 @@ static void led_timer_function(unsigned long data)
delay = led_cdev->blink_delay_off;
}
- led_set_brightness(led_cdev, brightness);
+ __led_set_brightness(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));
}
@@ -203,7 +222,7 @@ void led_classdev_unregister(struct led_classdev *led_cdev)
#endif
/* Stop blinking */
- led_brightness_set(led_cdev, LED_OFF);
+ led_set_brightness(led_cdev, LED_OFF);
device_unregister(led_cdev->dev);
diff --git a/drivers/leds/led-core.c b/drivers/leds/led-core.c
index d65353d8d3fc..2ab05af3de31 100644
--- a/drivers/leds/led-core.c
+++ b/drivers/leds/led-core.c
@@ -24,14 +24,6 @@ EXPORT_SYMBOL_GPL(leds_list_lock);
LIST_HEAD(leds_list);
EXPORT_SYMBOL_GPL(leds_list);
-static void led_stop_software_blink(struct led_classdev *led_cdev)
-{
- /* deactivate previous settings */
- del_timer_sync(&led_cdev->blink_timer);
- led_cdev->blink_delay_on = 0;
- led_cdev->blink_delay_off = 0;
-}
-
static void led_set_software_blink(struct led_classdev *led_cdev,
unsigned long delay_on,
unsigned long delay_off)
@@ -53,7 +45,7 @@ static void led_set_software_blink(struct led_classdev *led_cdev,
/* never off - just set to brightness */
if (!delay_off) {
- led_set_brightness(led_cdev, led_cdev->blink_brightness);
+ __led_set_brightness(led_cdev, led_cdev->blink_brightness);
return;
}
@@ -61,13 +53,12 @@ static void led_set_software_blink(struct led_classdev *led_cdev,
}
-void led_blink_set(struct led_classdev *led_cdev,
- unsigned long *delay_on,
- unsigned long *delay_off)
+static void led_blink_setup(struct led_classdev *led_cdev,
+ unsigned long *delay_on,
+ unsigned long *delay_off)
{
- del_timer_sync(&led_cdev->blink_timer);
-
- if (led_cdev->blink_set &&
+ if (!(led_cdev->flags & LED_BLINK_ONESHOT) &&
+ led_cdev->blink_set &&
!led_cdev->blink_set(led_cdev, delay_on, delay_off))
return;
@@ -77,12 +68,49 @@ void led_blink_set(struct led_classdev *led_cdev,
led_set_software_blink(led_cdev, *delay_on, *delay_off);
}
+
+void led_blink_set(struct led_classdev *led_cdev,
+ unsigned long *delay_on,
+ unsigned long *delay_off)
+{
+ del_timer_sync(&led_cdev->blink_timer);
+
+ led_cdev->flags &= ~LED_BLINK_ONESHOT;
+ led_cdev->flags &= ~LED_BLINK_ONESHOT_STOP;
+
+ led_blink_setup(led_cdev, delay_on, delay_off);
+}
EXPORT_SYMBOL(led_blink_set);
-void led_brightness_set(struct led_classdev *led_cdev,
+void led_blink_set_oneshot(struct led_classdev *led_cdev,
+ unsigned long *delay_on,
+ unsigned long *delay_off,
+ int invert)
+{
+ if ((led_cdev->flags & LED_BLINK_ONESHOT) &&
+ timer_pending(&led_cdev->blink_timer))
+ return;
+
+ led_cdev->flags |= LED_BLINK_ONESHOT;
+ led_cdev->flags &= ~LED_BLINK_ONESHOT_STOP;
+
+ if (invert)
+ led_cdev->flags |= LED_BLINK_INVERT;
+ else
+ led_cdev->flags &= ~LED_BLINK_INVERT;
+
+ led_blink_setup(led_cdev, delay_on, delay_off);
+}
+EXPORT_SYMBOL(led_blink_set_oneshot);
+
+void led_set_brightness(struct led_classdev *led_cdev,
enum led_brightness brightness)
{
- led_stop_software_blink(led_cdev);
- led_cdev->brightness_set(led_cdev, brightness);
+ /* stop and clear soft-blink timer */
+ del_timer_sync(&led_cdev->blink_timer);
+ led_cdev->blink_delay_on = 0;
+ led_cdev->blink_delay_off = 0;
+
+ __led_set_brightness(led_cdev, brightness);
}
-EXPORT_SYMBOL(led_brightness_set);
+EXPORT_SYMBOL(led_set_brightness);
diff --git a/drivers/leds/led-triggers.c b/drivers/leds/led-triggers.c
index 46b4c766335d..6157cbbf4113 100644
--- a/drivers/leds/led-triggers.c
+++ b/drivers/leds/led-triggers.c
@@ -99,7 +99,7 @@ ssize_t led_trigger_show(struct device *dev, struct device_attribute *attr,
EXPORT_SYMBOL_GPL(led_trigger_show);
/* Caller must ensure led_cdev->trigger_lock held */
-void led_trigger_set(struct led_classdev *led_cdev, struct led_trigger *trigger)
+void led_trigger_set(struct led_classdev *led_cdev, struct led_trigger *trig)
{
unsigned long flags;
@@ -112,15 +112,15 @@ void led_trigger_set(struct led_classdev *led_cdev, struct led_trigger *trigger)
if (led_cdev->trigger->deactivate)
led_cdev->trigger->deactivate(led_cdev);
led_cdev->trigger = NULL;
- led_brightness_set(led_cdev, LED_OFF);
+ led_set_brightness(led_cdev, LED_OFF);
}
- if (trigger) {
- write_lock_irqsave(&trigger->leddev_list_lock, flags);
- list_add_tail(&led_cdev->trig_list, &trigger->led_cdevs);
- write_unlock_irqrestore(&trigger->leddev_list_lock, flags);
- led_cdev->trigger = trigger;
- if (trigger->activate)
- trigger->activate(led_cdev);
+ if (trig) {
+ write_lock_irqsave(&trig->leddev_list_lock, flags);
+ list_add_tail(&led_cdev->trig_list, &trig->led_cdevs);
+ write_unlock_irqrestore(&trig->leddev_list_lock, flags);
+ led_cdev->trigger = trig;
+ if (trig->activate)
+ trig->activate(led_cdev);
}
}
EXPORT_SYMBOL_GPL(led_trigger_set);
@@ -153,24 +153,24 @@ EXPORT_SYMBOL_GPL(led_trigger_set_default);
/* LED Trigger Interface */
-int led_trigger_register(struct led_trigger *trigger)
+int led_trigger_register(struct led_trigger *trig)
{
struct led_classdev *led_cdev;
- struct led_trigger *trig;
+ struct led_trigger *_trig;
- rwlock_init(&trigger->leddev_list_lock);
- INIT_LIST_HEAD(&trigger->led_cdevs);
+ rwlock_init(&trig->leddev_list_lock);
+ INIT_LIST_HEAD(&trig->led_cdevs);
down_write(&triggers_list_lock);
/* Make sure the trigger's name isn't already in use */
- list_for_each_entry(trig, &trigger_list, next_trig) {
- if (!strcmp(trig->name, trigger->name)) {
+ list_for_each_entry(_trig, &trigger_list, next_trig) {
+ if (!strcmp(_trig->name, trig->name)) {
up_write(&triggers_list_lock);
return -EEXIST;
}
}
/* Add to the list of led triggers */
- list_add_tail(&trigger->next_trig, &trigger_list);
+ list_add_tail(&trig->next_trig, &trigger_list);
up_write(&triggers_list_lock);
/* Register with any LEDs that have this as a default trigger */
@@ -178,8 +178,8 @@ int led_trigger_register(struct led_trigger *trigger)
list_for_each_entry(led_cdev, &leds_list, node) {
down_write(&led_cdev->trigger_lock);
if (!led_cdev->trigger && led_cdev->default_trigger &&
- !strcmp(led_cdev->default_trigger, trigger->name))
- led_trigger_set(led_cdev, trigger);
+ !strcmp(led_cdev->default_trigger, trig->name))
+ led_trigger_set(led_cdev, trig);
up_write(&led_cdev->trigger_lock);
}
up_read(&leds_list_lock);
@@ -188,20 +188,20 @@ int led_trigger_register(struct led_trigger *trigger)
}
EXPORT_SYMBOL_GPL(led_trigger_register);
-void led_trigger_unregister(struct led_trigger *trigger)
+void led_trigger_unregister(struct led_trigger *trig)
{
struct led_classdev *led_cdev;
/* Remove from the list of led triggers */
down_write(&triggers_list_lock);
- list_del(&trigger->next_trig);
+ list_del(&trig->next_trig);
up_write(&triggers_list_lock);
/* Remove anyone actively using this trigger */
down_read(&leds_list_lock);
list_for_each_entry(led_cdev, &leds_list, node) {
down_write(&led_cdev->trigger_lock);
- if (led_cdev->trigger == trigger)
+ if (led_cdev->trigger == trig)
led_trigger_set(led_cdev, NULL);
up_write(&led_cdev->trigger_lock);
}
@@ -211,58 +211,80 @@ EXPORT_SYMBOL_GPL(led_trigger_unregister);
/* Simple LED Tigger Interface */
-void led_trigger_event(struct led_trigger *trigger,
+void led_trigger_event(struct led_trigger *trig,
enum led_brightness brightness)
{
struct list_head *entry;
- if (!trigger)
+ if (!trig)
return;
- read_lock(&trigger->leddev_list_lock);
- list_for_each(entry, &trigger->led_cdevs) {
+ read_lock(&trig->leddev_list_lock);
+ list_for_each(entry, &trig->led_cdevs) {
struct led_classdev *led_cdev;
led_cdev = list_entry(entry, struct led_classdev, trig_list);
led_set_brightness(led_cdev, brightness);
}
- read_unlock(&trigger->leddev_list_lock);
+ read_unlock(&trig->leddev_list_lock);
}
EXPORT_SYMBOL_GPL(led_trigger_event);
-void led_trigger_blink(struct led_trigger *trigger,
- unsigned long *delay_on,
- unsigned long *delay_off)
+static void led_trigger_blink_setup(struct led_trigger *trig,
+ unsigned long *delay_on,
+ unsigned long *delay_off,
+ int oneshot,
+ int invert)
{
struct list_head *entry;
- if (!trigger)
+ if (!trig)
return;
- read_lock(&trigger->leddev_list_lock);
- list_for_each(entry, &trigger->led_cdevs) {
+ read_lock(&trig->leddev_list_lock);
+ list_for_each(entry, &trig->led_cdevs) {
struct led_classdev *led_cdev;
led_cdev = list_entry(entry, struct led_classdev, trig_list);
- led_blink_set(led_cdev, delay_on, delay_off);
+ if (oneshot)
+ led_blink_set_oneshot(led_cdev, delay_on, delay_off,
+ invert);
+ else
+ led_blink_set(led_cdev, delay_on, delay_off);
}
- read_unlock(&trigger->leddev_list_lock);
+ read_unlock(&trig->leddev_list_lock);
+}
+
+void led_trigger_blink(struct led_trigger *trig,
+ unsigned long *delay_on,
+ unsigned long *delay_off)
+{
+ led_trigger_blink_setup(trig, delay_on, delay_off, 0, 0);
}
EXPORT_SYMBOL_GPL(led_trigger_blink);
+void led_trigger_blink_oneshot(struct led_trigger *trig,
+ unsigned long *delay_on,
+ unsigned long *delay_off,
+ int invert)
+{
+ led_trigger_blink_setup(trig, delay_on, delay_off, 1, invert);
+}
+EXPORT_SYMBOL_GPL(led_trigger_blink_oneshot);
+
void led_trigger_register_simple(const char *name, struct led_trigger **tp)
{
- struct led_trigger *trigger;
+ struct led_trigger *trig;
int err;
- trigger = kzalloc(sizeof(struct led_trigger), GFP_KERNEL);
+ trig = kzalloc(sizeof(struct led_trigger), GFP_KERNEL);
- if (trigger) {
- trigger->name = name;
- err = led_trigger_register(trigger);
+ if (trig) {
+ trig->name = name;
+ err = led_trigger_register(trig);
if (err < 0) {
- kfree(trigger);
- trigger = NULL;
+ kfree(trig);
+ trig = NULL;
printk(KERN_WARNING "LED trigger %s failed to register"
" (%d)\n", name, err);
}
@@ -270,15 +292,15 @@ void led_trigger_register_simple(const char *name, struct led_trigger **tp)
printk(KERN_WARNING "LED trigger %s failed to register"
" (no memory)\n", name);
- *tp = trigger;
+ *tp = trig;
}
EXPORT_SYMBOL_GPL(led_trigger_register_simple);
-void led_trigger_unregister_simple(struct led_trigger *trigger)
+void led_trigger_unregister_simple(struct led_trigger *trig)
{
- if (trigger)
- led_trigger_unregister(trigger);
- kfree(trigger);
+ if (trig)
+ led_trigger_unregister(trig);
+ kfree(trig);
}
EXPORT_SYMBOL_GPL(led_trigger_unregister_simple);
diff --git a/drivers/leds/leds-88pm860x.c b/drivers/leds/leds-88pm860x.c
index 5b61aaf7ac0f..61897cfeeda6 100644
--- a/drivers/leds/leds-88pm860x.c
+++ b/drivers/leds/leds-88pm860x.c
@@ -209,7 +209,7 @@ static int pm860x_led_probe(struct platform_device *pdev)
return -EINVAL;
}
- data = kzalloc(sizeof(struct pm860x_led), GFP_KERNEL);
+ data = devm_kzalloc(&pdev->dev, sizeof(struct pm860x_led), GFP_KERNEL);
if (data == NULL)
return -ENOMEM;
strncpy(data->name, res->name, MFD_NAME_SIZE - 1);
@@ -220,7 +220,6 @@ static int pm860x_led_probe(struct platform_device *pdev)
data->port = pdata->flags;
if (data->port < 0) {
dev_err(&pdev->dev, "check device failed\n");
- kfree(data);
return -EINVAL;
}
@@ -233,13 +232,10 @@ static int pm860x_led_probe(struct platform_device *pdev)
ret = led_classdev_register(chip->dev, &data->cdev);
if (ret < 0) {
dev_err(&pdev->dev, "Failed to register LED: %d\n", ret);
- goto out;
+ return ret;
}
pm860x_led_set(&data->cdev, 0);
return 0;
-out:
- kfree(data);
- return ret;
}
static int pm860x_led_remove(struct platform_device *pdev)
@@ -247,7 +243,6 @@ static int pm860x_led_remove(struct platform_device *pdev)
struct pm860x_led *data = platform_get_drvdata(pdev);
led_classdev_unregister(&data->cdev);
- kfree(data);
return 0;
}
diff --git a/drivers/leds/leds-adp5520.c b/drivers/leds/leds-adp5520.c
index b1400db3f839..aa56a867693a 100644
--- a/drivers/leds/leds-adp5520.c
+++ b/drivers/leds/leds-adp5520.c
@@ -119,7 +119,8 @@ static int __devinit adp5520_led_probe(struct platform_device *pdev)
return -EFAULT;
}
- led = kzalloc(sizeof(*led) * pdata->num_leds, GFP_KERNEL);
+ led = devm_kzalloc(&pdev->dev, sizeof(*led) * pdata->num_leds,
+ GFP_KERNEL);
if (led == NULL) {
dev_err(&pdev->dev, "failed to alloc memory\n");
return -ENOMEM;
@@ -129,7 +130,7 @@ static int __devinit adp5520_led_probe(struct platform_device *pdev)
if (ret) {
dev_err(&pdev->dev, "failed to write\n");
- goto err_free;
+ return ret;
}
for (i = 0; i < pdata->num_leds; ++i) {
@@ -179,8 +180,6 @@ err:
}
}
-err_free:
- kfree(led);
return ret;
}
@@ -200,7 +199,6 @@ static int __devexit adp5520_led_remove(struct platform_device *pdev)
cancel_work_sync(&led[i].work);
}
- kfree(led);
return 0;
}
diff --git a/drivers/leds/leds-asic3.c b/drivers/leds/leds-asic3.c
index 525a92492837..5de74ff90dcf 100644
--- a/drivers/leds/leds-asic3.c
+++ b/drivers/leds/leds-asic3.c
@@ -99,12 +99,13 @@ static int __devinit asic3_led_probe(struct platform_device *pdev)
ret = mfd_cell_enable(pdev);
if (ret < 0)
- goto ret0;
+ return ret;
- led->cdev = kzalloc(sizeof(struct led_classdev), GFP_KERNEL);
+ led->cdev = devm_kzalloc(&pdev->dev, sizeof(struct led_classdev),
+ GFP_KERNEL);
if (!led->cdev) {
ret = -ENOMEM;
- goto ret1;
+ goto out;
}
led->cdev->name = led->name;
@@ -115,15 +116,12 @@ static int __devinit asic3_led_probe(struct platform_device *pdev)
ret = led_classdev_register(&pdev->dev, led->cdev);
if (ret < 0)
- goto ret2;
+ goto out;
return 0;
-ret2:
- kfree(led->cdev);
-ret1:
+out:
(void) mfd_cell_disable(pdev);
-ret0:
return ret;
}
@@ -133,8 +131,6 @@ static int __devexit asic3_led_remove(struct platform_device *pdev)
led_classdev_unregister(led->cdev);
- kfree(led->cdev);
-
return mfd_cell_disable(pdev);
}
diff --git a/drivers/leds/leds-atmel-pwm.c b/drivers/leds/leds-atmel-pwm.c
index 64ad702a2ecc..45430632faab 100644
--- a/drivers/leds/leds-atmel-pwm.c
+++ b/drivers/leds/leds-atmel-pwm.c
@@ -46,7 +46,8 @@ static int __devinit pwmled_probe(struct platform_device *pdev)
if (!pdata || pdata->num_leds < 1)
return -ENODEV;
- leds = kcalloc(pdata->num_leds, sizeof(*leds), GFP_KERNEL);
+ leds = devm_kzalloc(&pdev->dev, pdata->num_leds * sizeof(*leds),
+ GFP_KERNEL);
if (!leds)
return -ENOMEM;
@@ -108,7 +109,6 @@ err:
pwm_channel_free(&leds[i].pwmc);
}
}
- kfree(leds);
return status;
}
@@ -129,7 +129,6 @@ static int __exit pwmled_remove(struct platform_device *pdev)
pwm_channel_free(&led->pwmc);
}
- kfree(leds);
platform_set_drvdata(pdev, NULL);
return 0;
}
diff --git a/drivers/leds/leds-bd2802.c b/drivers/leds/leds-bd2802.c
index 591cbdf5a046..89ca6a2a19d1 100644
--- a/drivers/leds/leds-bd2802.c
+++ b/drivers/leds/leds-bd2802.c
@@ -677,7 +677,7 @@ static int __devinit bd2802_probe(struct i2c_client *client,
struct bd2802_led_platform_data *pdata;
int ret, i;
- led = kzalloc(sizeof(struct bd2802_led), GFP_KERNEL);
+ led = devm_kzalloc(&client->dev, sizeof(struct bd2802_led), GFP_KERNEL);
if (!led) {
dev_err(&client->dev, "failed to allocate driver data\n");
return -ENOMEM;
@@ -697,7 +697,7 @@ static int __devinit bd2802_probe(struct i2c_client *client,
ret = bd2802_write_byte(client, BD2802_REG_CLKSETUP, 0x00);
if (ret < 0) {
dev_err(&client->dev, "failed to detect device\n");
- goto failed_free;
+ return ret;
} else
dev_info(&client->dev, "return 0x%02x\n", ret);
@@ -729,9 +729,6 @@ static int __devinit bd2802_probe(struct i2c_client *client,
failed_unregister_dev_file:
for (i--; i >= 0; i--)
device_remove_file(&led->client->dev, bd2802_attributes[i]);
-failed_free:
- kfree(led);
-
return ret;
}
@@ -746,7 +743,6 @@ static int __exit bd2802_remove(struct i2c_client *client)
bd2802_disable_adv_conf(led);
for (i = 0; i < ARRAY_SIZE(bd2802_attributes); i++)
device_remove_file(&led->client->dev, bd2802_attributes[i]);
- kfree(led);
return 0;
}
diff --git a/drivers/leds/leds-blinkm.c b/drivers/leds/leds-blinkm.c
new file mode 100644
index 000000000000..f7c3d7f1ec52
--- /dev/null
+++ b/drivers/leds/leds-blinkm.c
@@ -0,0 +1,815 @@
+/*
+ * leds-blinkm.c
+ * (c) Jan-Simon Möller (dl9pf@gmx.de)
+ *
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/jiffies.h>
+#include <linux/i2c.h>
+#include <linux/err.h>
+#include <linux/mutex.h>
+#include <linux/sysfs.h>
+#include <linux/printk.h>
+#include <linux/pm_runtime.h>
+#include <linux/leds.h>
+#include <linux/delay.h>
+
+/* Addresses to scan - BlinkM is on 0x09 by default*/
+static const unsigned short normal_i2c[] = { 0x09, I2C_CLIENT_END };
+
+static int blinkm_transfer_hw(struct i2c_client *client, int cmd);
+static int blinkm_test_run(struct i2c_client *client);
+
+struct blinkm_led {
+ struct i2c_client *i2c_client;
+ struct led_classdev led_cdev;
+ int id;
+ atomic_t active;
+};
+
+struct blinkm_work {
+ struct blinkm_led *blinkm_led;
+ struct work_struct work;
+};
+
+#define cdev_to_blmled(c) container_of(c, struct blinkm_led, led_cdev)
+#define work_to_blmwork(c) container_of(c, struct blinkm_work, work)
+
+struct blinkm_data {
+ struct i2c_client *i2c_client;
+ struct mutex update_lock;
+ /* used for led class interface */
+ struct blinkm_led blinkm_leds[3];
+ /* used for "blinkm" sysfs interface */
+ u8 red; /* color red */
+ u8 green; /* color green */
+ u8 blue; /* color blue */
+ /* next values to use for transfer */
+ u8 next_red; /* color red */
+ u8 next_green; /* color green */
+ u8 next_blue; /* color blue */
+ /* internal use */
+ u8 args[7]; /* set of args for transmission */
+ u8 i2c_addr; /* i2c addr */
+ u8 fw_ver; /* firmware version */
+ /* used, but not from userspace */
+ u8 hue; /* HSB hue */
+ u8 saturation; /* HSB saturation */
+ u8 brightness; /* HSB brightness */
+ u8 next_hue; /* HSB hue */
+ u8 next_saturation; /* HSB saturation */
+ u8 next_brightness; /* HSB brightness */
+ /* currently unused / todo */
+ u8 fade_speed; /* fade speed 1 - 255 */
+ s8 time_adjust; /* time adjust -128 - 127 */
+ u8 fade:1; /* fade on = 1, off = 0 */
+ u8 rand:1; /* rand fade mode on = 1 */
+ u8 script_id; /* script ID */
+ u8 script_repeats; /* repeats of script */
+ u8 script_startline; /* line to start */
+};
+
+/* Colors */
+#define RED 0
+#define GREEN 1
+#define BLUE 2
+
+/* mapping command names to cmd chars - see datasheet */
+#define BLM_GO_RGB 0
+#define BLM_FADE_RGB 1
+#define BLM_FADE_HSB 2
+#define BLM_FADE_RAND_RGB 3
+#define BLM_FADE_RAND_HSB 4
+#define BLM_PLAY_SCRIPT 5
+#define BLM_STOP_SCRIPT 6
+#define BLM_SET_FADE_SPEED 7
+#define BLM_SET_TIME_ADJ 8
+#define BLM_GET_CUR_RGB 9
+#define BLM_WRITE_SCRIPT_LINE 10
+#define BLM_READ_SCRIPT_LINE 11
+#define BLM_SET_SCRIPT_LR 12 /* Length & Repeats */
+#define BLM_SET_ADDR 13
+#define BLM_GET_ADDR 14
+#define BLM_GET_FW_VER 15
+#define BLM_SET_STARTUP_PARAM 16
+
+/* BlinkM Commands
+ * as extracted out of the datasheet:
+ *
+ * cmdchar = command (ascii)
+ * cmdbyte = command in hex
+ * nr_args = number of arguments (to send)
+ * nr_ret = number of return values (to read)
+ * dir = direction (0 = read, 1 = write, 2 = both)
+ *
+ */
+static const struct {
+ char cmdchar;
+ u8 cmdbyte;
+ u8 nr_args;
+ u8 nr_ret;
+ u8 dir:2;
+} blinkm_cmds[17] = {
+ /* cmdchar, cmdbyte, nr_args, nr_ret, dir */
+ { 'n', 0x6e, 3, 0, 1},
+ { 'c', 0x63, 3, 0, 1},
+ { 'h', 0x68, 3, 0, 1},
+ { 'C', 0x43, 3, 0, 1},
+ { 'H', 0x48, 3, 0, 1},
+ { 'p', 0x70, 3, 0, 1},
+ { 'o', 0x6f, 0, 0, 1},
+ { 'f', 0x66, 1, 0, 1},
+ { 't', 0x74, 1, 0, 1},
+ { 'g', 0x67, 0, 3, 0},
+ { 'W', 0x57, 7, 0, 1},
+ { 'R', 0x52, 2, 5, 2},
+ { 'L', 0x4c, 3, 0, 1},
+ { 'A', 0x41, 4, 0, 1},
+ { 'a', 0x61, 0, 1, 0},
+ { 'Z', 0x5a, 0, 1, 0},
+ { 'B', 0x42, 5, 0, 1},
+};
+
+static ssize_t show_color_common(struct device *dev, char *buf, int color)
+{
+ struct i2c_client *client;
+ struct blinkm_data *data;
+ int ret;
+
+ client = to_i2c_client(dev);
+ data = i2c_get_clientdata(client);
+
+ ret = blinkm_transfer_hw(client, BLM_GET_CUR_RGB);
+ if (ret < 0)
+ return ret;
+ switch (color) {
+ case RED:
+ return scnprintf(buf, PAGE_SIZE, "%02X\n", data->red);
+ break;
+ case GREEN:
+ return scnprintf(buf, PAGE_SIZE, "%02X\n", data->green);
+ break;
+ case BLUE:
+ return scnprintf(buf, PAGE_SIZE, "%02X\n", data->blue);
+ break;
+ default:
+ return -EINVAL;
+ }
+ return -EINVAL;
+}
+
+static int store_color_common(struct device *dev, const char *buf, int color)
+{
+ struct i2c_client *client;
+ struct blinkm_data *data;
+ int ret;
+ u8 value;
+
+ client = to_i2c_client(dev);
+ data = i2c_get_clientdata(client);
+
+ ret = kstrtou8(buf, 10, &value);
+ if (ret < 0) {
+ dev_err(dev, "BlinkM: value too large!\n");
+ return ret;
+ }
+
+ switch (color) {
+ case RED:
+ data->next_red = value;
+ break;
+ case GREEN:
+ data->next_green = value;
+ break;
+ case BLUE:
+ data->next_blue = value;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ dev_dbg(dev, "next_red = %d, next_green = %d, next_blue = %d\n",
+ data->next_red, data->next_green, data->next_blue);
+
+ /* if mode ... */
+ ret = blinkm_transfer_hw(client, BLM_GO_RGB);
+ if (ret < 0) {
+ dev_err(dev, "BlinkM: can't set RGB\n");
+ return ret;
+ }
+ return 0;
+}
+
+static ssize_t show_red(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ return show_color_common(dev, buf, RED);
+}
+
+static ssize_t store_red(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ int ret;
+
+ ret = store_color_common(dev, buf, RED);
+ if (ret < 0)
+ return ret;
+ return count;
+}
+
+static DEVICE_ATTR(red, S_IRUGO | S_IWUSR, show_red, store_red);
+
+static ssize_t show_green(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ return show_color_common(dev, buf, GREEN);
+}
+
+static ssize_t store_green(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+
+ int ret;
+
+ ret = store_color_common(dev, buf, GREEN);
+ if (ret < 0)
+ return ret;
+ return count;
+}
+
+static DEVICE_ATTR(green, S_IRUGO | S_IWUSR, show_green, store_green);
+
+static ssize_t show_blue(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ return show_color_common(dev, buf, BLUE);
+}
+
+static ssize_t store_blue(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ int ret;
+
+ ret = store_color_common(dev, buf, BLUE);
+ if (ret < 0)
+ return ret;
+ return count;
+}
+
+static DEVICE_ATTR(blue, S_IRUGO | S_IWUSR, show_blue, store_blue);
+
+static ssize_t show_test(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ return scnprintf(buf, PAGE_SIZE,
+ "#Write into test to start test sequence!#\n");
+}
+
+static ssize_t store_test(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+
+ struct i2c_client *client;
+ int ret;
+ client = to_i2c_client(dev);
+
+ /*test */
+ ret = blinkm_test_run(client);
+ if (ret < 0)
+ return ret;
+
+ return count;
+}
+
+static DEVICE_ATTR(test, S_IRUGO | S_IWUSR, show_test, store_test);
+
+/* TODO: HSB, fade, timeadj, script ... */
+
+static struct attribute *blinkm_attrs[] = {
+ &dev_attr_red.attr,
+ &dev_attr_green.attr,
+ &dev_attr_blue.attr,
+ &dev_attr_test.attr,
+ NULL,
+};
+
+static struct attribute_group blinkm_group = {
+ .name = "blinkm",
+ .attrs = blinkm_attrs,
+};
+
+static int blinkm_write(struct i2c_client *client, int cmd, u8 *arg)
+{
+ int result;
+ int i;
+ int arglen = blinkm_cmds[cmd].nr_args;
+ /* write out cmd to blinkm - always / default step */
+ result = i2c_smbus_write_byte(client, blinkm_cmds[cmd].cmdbyte);
+ if (result < 0)
+ return result;
+ /* no args to write out */
+ if (arglen == 0)
+ return 0;
+
+ for (i = 0; i < arglen; i++) {
+ /* repeat for arglen */
+ result = i2c_smbus_write_byte(client, arg[i]);
+ if (result < 0)
+ return result;
+ }
+ return 0;
+}
+
+static int blinkm_read(struct i2c_client *client, int cmd, u8 *arg)
+{
+ int result;
+ int i;
+ int retlen = blinkm_cmds[cmd].nr_ret;
+ for (i = 0; i < retlen; i++) {
+ /* repeat for retlen */
+ result = i2c_smbus_read_byte(client);
+ if (result < 0)
+ return result;
+ arg[i] = result;
+ }
+
+ return 0;
+}
+
+static int blinkm_transfer_hw(struct i2c_client *client, int cmd)
+{
+ /* the protocol is simple but non-standard:
+ * e.g. cmd 'g' (= 0x67) for "get device address"
+ * - which defaults to 0x09 - would be the sequence:
+ * a) write 0x67 to the device (byte write)
+ * b) read the value (0x09) back right after (byte read)
+ *
+ * Watch out for "unfinished" sequences (i.e. not enough reads
+ * or writes after a command. It will make the blinkM misbehave.
+ * Sequence is key here.
+ */
+
+ /* args / return are in private data struct */
+ struct blinkm_data *data = i2c_get_clientdata(client);
+
+ /* We start hardware transfers which are not to be
+ * mixed with other commands. Aquire a lock now. */
+ if (mutex_lock_interruptible(&data->update_lock) < 0)
+ return -EAGAIN;
+
+ /* switch cmd - usually write before reads */
+ switch (cmd) {
+ case BLM_FADE_RAND_RGB:
+ case BLM_GO_RGB:
+ case BLM_FADE_RGB:
+ data->args[0] = data->next_red;
+ data->args[1] = data->next_green;
+ data->args[2] = data->next_blue;
+ blinkm_write(client, cmd, data->args);
+ data->red = data->args[0];
+ data->green = data->args[1];
+ data->blue = data->args[2];
+ break;
+ case BLM_FADE_HSB:
+ case BLM_FADE_RAND_HSB:
+ data->args[0] = data->next_hue;
+ data->args[1] = data->next_saturation;
+ data->args[2] = data->next_brightness;
+ blinkm_write(client, cmd, data->args);
+ data->hue = data->next_hue;
+ data->saturation = data->next_saturation;
+ data->brightness = data->next_brightness;
+ break;
+ case BLM_PLAY_SCRIPT:
+ data->args[0] = data->script_id;
+ data->args[1] = data->script_repeats;
+ data->args[2] = data->script_startline;
+ blinkm_write(client, cmd, data->args);
+ break;
+ case BLM_STOP_SCRIPT:
+ blinkm_write(client, cmd, NULL);
+ break;
+ case BLM_GET_CUR_RGB:
+ data->args[0] = data->red;
+ data->args[1] = data->green;
+ data->args[2] = data->blue;
+ blinkm_write(client, cmd, NULL);
+ blinkm_read(client, cmd, data->args);
+ data->red = data->args[0];
+ data->green = data->args[1];
+ data->blue = data->args[2];
+ break;
+ case BLM_GET_ADDR:
+ data->args[0] = data->i2c_addr;
+ blinkm_write(client, cmd, NULL);
+ blinkm_read(client, cmd, data->args);
+ data->i2c_addr = data->args[0];
+ break;
+ case BLM_SET_TIME_ADJ:
+ case BLM_SET_FADE_SPEED:
+ case BLM_READ_SCRIPT_LINE:
+ case BLM_WRITE_SCRIPT_LINE:
+ case BLM_SET_SCRIPT_LR:
+ case BLM_SET_ADDR:
+ case BLM_GET_FW_VER:
+ case BLM_SET_STARTUP_PARAM:
+ dev_err(&client->dev,
+ "BlinkM: cmd %d not implemented yet.\n", cmd);
+ break;
+ default:
+ dev_err(&client->dev, "BlinkM: unknown command %d\n", cmd);
+ mutex_unlock(&data->update_lock);
+ return -EINVAL;
+ } /* end switch(cmd) */
+
+ /* transfers done, unlock */
+ mutex_unlock(&data->update_lock);
+ return 0;
+}
+
+static void led_work(struct work_struct *work)
+{
+ int ret;
+ struct blinkm_led *led;
+ struct blinkm_data *data ;
+ struct blinkm_work *blm_work = work_to_blmwork(work);
+
+ led = blm_work->blinkm_led;
+ data = i2c_get_clientdata(led->i2c_client);
+ ret = blinkm_transfer_hw(led->i2c_client, BLM_GO_RGB);
+ atomic_dec(&led->active);
+ dev_dbg(&led->i2c_client->dev,
+ "# DONE # next_red = %d, next_green = %d,"
+ " next_blue = %d, active = %d\n",
+ data->next_red, data->next_green,
+ data->next_blue, atomic_read(&led->active));
+ kfree(blm_work);
+}
+
+static int blinkm_led_common_set(struct led_classdev *led_cdev,
+ enum led_brightness value, int color)
+{
+ /* led_brightness is 0, 127 or 255 - we just use it here as-is */
+ struct blinkm_led *led = cdev_to_blmled(led_cdev);
+ struct blinkm_data *data = i2c_get_clientdata(led->i2c_client);
+ struct blinkm_work *bl_work;
+
+ switch (color) {
+ case RED:
+ /* bail out if there's no change */
+ if (data->next_red == (u8) value)
+ return 0;
+ /* we assume a quite fast sequence here ([off]->on->off)
+ * think of network led trigger - we cannot blink that fast, so
+ * in case we already have a off->on->off transition queued up,
+ * we refuse to queue up more.
+ * Revisit: fast-changing brightness. */
+ if (atomic_read(&led->active) > 1)
+ return 0;
+ data->next_red = (u8) value;
+ break;
+ case GREEN:
+ /* bail out if there's no change */
+ if (data->next_green == (u8) value)
+ return 0;
+ /* we assume a quite fast sequence here ([off]->on->off)
+ * Revisit: fast-changing brightness. */
+ if (atomic_read(&led->active) > 1)
+ return 0;
+ data->next_green = (u8) value;
+ break;
+ case BLUE:
+ /* bail out if there's no change */
+ if (data->next_blue == (u8) value)
+ return 0;
+ /* we assume a quite fast sequence here ([off]->on->off)
+ * Revisit: fast-changing brightness. */
+ if (atomic_read(&led->active) > 1)
+ return 0;
+ data->next_blue = (u8) value;
+ break;
+
+ default:
+ dev_err(&led->i2c_client->dev, "BlinkM: unknown color.\n");
+ return -EINVAL;
+ }
+
+ bl_work = kzalloc(sizeof(*bl_work), GFP_ATOMIC);
+ if (!bl_work)
+ return -ENOMEM;
+
+ atomic_inc(&led->active);
+ dev_dbg(&led->i2c_client->dev,
+ "#TO_SCHED# next_red = %d, next_green = %d,"
+ " next_blue = %d, active = %d\n",
+ data->next_red, data->next_green,
+ data->next_blue, atomic_read(&led->active));
+
+ /* a fresh work _item_ for each change */
+ bl_work->blinkm_led = led;
+ INIT_WORK(&bl_work->work, led_work);
+ /* queue work in own queue for easy sync on exit*/
+ schedule_work(&bl_work->work);
+
+ return 0;
+}
+
+static void blinkm_led_red_set(struct led_classdev *led_cdev,
+ enum led_brightness value)
+{
+ blinkm_led_common_set(led_cdev, value, RED);
+}
+
+static void blinkm_led_green_set(struct led_classdev *led_cdev,
+ enum led_brightness value)
+{
+ blinkm_led_common_set(led_cdev, value, GREEN);
+}
+
+static void blinkm_led_blue_set(struct led_classdev *led_cdev,
+ enum led_brightness value)
+{
+ blinkm_led_common_set(led_cdev, value, BLUE);
+}
+
+static void blinkm_init_hw(struct i2c_client *client)
+{
+ int ret;
+ ret = blinkm_transfer_hw(client, BLM_STOP_SCRIPT);
+ ret = blinkm_transfer_hw(client, BLM_GO_RGB);
+}
+
+static int blinkm_test_run(struct i2c_client *client)
+{
+ int ret;
+ struct blinkm_data *data = i2c_get_clientdata(client);
+
+ data->next_red = 0x01;
+ data->next_green = 0x05;
+ data->next_blue = 0x10;
+ ret = blinkm_transfer_hw(client, BLM_GO_RGB);
+ if (ret < 0)
+ return ret;
+ msleep(2000);
+
+ data->next_red = 0x25;
+ data->next_green = 0x10;
+ data->next_blue = 0x31;
+ ret = blinkm_transfer_hw(client, BLM_FADE_RGB);
+ if (ret < 0)
+ return ret;
+ msleep(2000);
+
+ data->next_hue = 0x50;
+ data->next_saturation = 0x10;
+ data->next_brightness = 0x20;
+ ret = blinkm_transfer_hw(client, BLM_FADE_HSB);
+ if (ret < 0)
+ return ret;
+ msleep(2000);
+
+ return 0;
+}
+
+/* Return 0 if detection is successful, -ENODEV otherwise */
+static int blinkm_detect(struct i2c_client *client, struct i2c_board_info *info)
+{
+ struct i2c_adapter *adapter = client->adapter;
+ int ret;
+ int count = 99;
+ u8 tmpargs[7];
+
+ if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA
+ | I2C_FUNC_SMBUS_WORD_DATA
+ | I2C_FUNC_SMBUS_WRITE_BYTE))
+ return -ENODEV;
+
+ /* Now, we do the remaining detection. Simple for now. */
+ /* We might need more guards to protect other i2c slaves */
+
+ /* make sure the blinkM is balanced (read/writes) */
+ while (count > 0) {
+ ret = blinkm_write(client, BLM_GET_ADDR, NULL);
+ usleep_range(5000, 10000);
+ ret = blinkm_read(client, BLM_GET_ADDR, tmpargs);
+ usleep_range(5000, 10000);
+ if (tmpargs[0] == 0x09)
+ count = 0;
+ count--;
+ }
+
+ /* Step 1: Read BlinkM address back - cmd_char 'a' */
+ ret = blinkm_write(client, BLM_GET_ADDR, NULL);
+ if (ret < 0)
+ return ret;
+ usleep_range(20000, 30000); /* allow a small delay */
+ ret = blinkm_read(client, BLM_GET_ADDR, tmpargs);
+ if (ret < 0)
+ return ret;
+
+ if (tmpargs[0] != 0x09) {
+ dev_err(&client->dev, "enodev DEV ADDR = 0x%02X\n", tmpargs[0]);
+ return -ENODEV;
+ }
+
+ strlcpy(info->type, "blinkm", I2C_NAME_SIZE);
+ return 0;
+}
+
+static int __devinit blinkm_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct blinkm_data *data;
+ struct blinkm_led *led[3];
+ int err, i;
+ char blinkm_led_name[28];
+
+ data = devm_kzalloc(&client->dev,
+ sizeof(struct blinkm_data), GFP_KERNEL);
+ if (!data) {
+ err = -ENOMEM;
+ goto exit;
+ }
+
+ data->i2c_addr = 0x09;
+ data->i2c_addr = 0x08;
+ /* i2c addr - use fake addr of 0x08 initially (real is 0x09) */
+ data->fw_ver = 0xfe;
+ /* firmware version - use fake until we read real value
+ * (currently broken - BlinkM confused!) */
+ data->script_id = 0x01;
+ data->i2c_client = client;
+
+ i2c_set_clientdata(client, data);
+ mutex_init(&data->update_lock);
+
+ /* Register sysfs hooks */
+ err = sysfs_create_group(&client->dev.kobj, &blinkm_group);
+ if (err < 0) {
+ dev_err(&client->dev, "couldn't register sysfs group\n");
+ goto exit;
+ }
+
+ for (i = 0; i < 3; i++) {
+ /* RED = 0, GREEN = 1, BLUE = 2 */
+ led[i] = &data->blinkm_leds[i];
+ led[i]->i2c_client = client;
+ led[i]->id = i;
+ led[i]->led_cdev.max_brightness = 255;
+ led[i]->led_cdev.flags = LED_CORE_SUSPENDRESUME;
+ atomic_set(&led[i]->active, 0);
+ switch (i) {
+ case RED:
+ snprintf(blinkm_led_name, sizeof(blinkm_led_name),
+ "blinkm-%d-%d-red",
+ client->adapter->nr,
+ client->addr);
+ led[i]->led_cdev.name = blinkm_led_name;
+ led[i]->led_cdev.brightness_set = blinkm_led_red_set;
+ err = led_classdev_register(&client->dev,
+ &led[i]->led_cdev);
+ if (err < 0) {
+ dev_err(&client->dev,
+ "couldn't register LED %s\n",
+ led[i]->led_cdev.name);
+ goto failred;
+ }
+ break;
+ case GREEN:
+ snprintf(blinkm_led_name, sizeof(blinkm_led_name),
+ "blinkm-%d-%d-green",
+ client->adapter->nr,
+ client->addr);
+ led[i]->led_cdev.name = blinkm_led_name;
+ led[i]->led_cdev.brightness_set = blinkm_led_green_set;
+ err = led_classdev_register(&client->dev,
+ &led[i]->led_cdev);
+ if (err < 0) {
+ dev_err(&client->dev,
+ "couldn't register LED %s\n",
+ led[i]->led_cdev.name);
+ goto failgreen;
+ }
+ break;
+ case BLUE:
+ snprintf(blinkm_led_name, sizeof(blinkm_led_name),
+ "blinkm-%d-%d-blue",
+ client->adapter->nr,
+ client->addr);
+ led[i]->led_cdev.name = blinkm_led_name;
+ led[i]->led_cdev.brightness_set = blinkm_led_blue_set;
+ err = led_classdev_register(&client->dev,
+ &led[i]->led_cdev);
+ if (err < 0) {
+ dev_err(&client->dev,
+ "couldn't register LED %s\n",
+ led[i]->led_cdev.name);
+ goto failblue;
+ }
+ break;
+ } /* end switch */
+ } /* end for */
+
+ /* Initialize the blinkm */
+ blinkm_init_hw(client);
+
+ return 0;
+
+failblue:
+ led_classdev_unregister(&led[GREEN]->led_cdev);
+
+failgreen:
+ led_classdev_unregister(&led[RED]->led_cdev);
+
+failred:
+ sysfs_remove_group(&client->dev.kobj, &blinkm_group);
+exit:
+ return err;
+}
+
+static int __devexit blinkm_remove(struct i2c_client *client)
+{
+ struct blinkm_data *data = i2c_get_clientdata(client);
+ int ret = 0;
+ int i;
+
+ /* make sure no workqueue entries are pending */
+ for (i = 0; i < 3; i++) {
+ flush_scheduled_work();
+ led_classdev_unregister(&data->blinkm_leds[i].led_cdev);
+ }
+
+ /* reset rgb */
+ data->next_red = 0x00;
+ data->next_green = 0x00;
+ data->next_blue = 0x00;
+ ret = blinkm_transfer_hw(client, BLM_FADE_RGB);
+ if (ret < 0)
+ dev_err(&client->dev, "Failure in blinkm_remove ignored. Continuing.\n");
+
+ /* reset hsb */
+ data->next_hue = 0x00;
+ data->next_saturation = 0x00;
+ data->next_brightness = 0x00;
+ ret = blinkm_transfer_hw(client, BLM_FADE_HSB);
+ if (ret < 0)
+ dev_err(&client->dev, "Failure in blinkm_remove ignored. Continuing.\n");
+
+ /* red fade to off */
+ data->next_red = 0xff;
+ ret = blinkm_transfer_hw(client, BLM_GO_RGB);
+ if (ret < 0)
+ dev_err(&client->dev, "Failure in blinkm_remove ignored. Continuing.\n");
+
+ /* off */
+ data->next_red = 0x00;
+ ret = blinkm_transfer_hw(client, BLM_FADE_RGB);
+ if (ret < 0)
+ dev_err(&client->dev, "Failure in blinkm_remove ignored. Continuing.\n");
+
+ sysfs_remove_group(&client->dev.kobj, &blinkm_group);
+ return 0;
+}
+
+static const struct i2c_device_id blinkm_id[] = {
+ {"blinkm", 0},
+ {}
+};
+
+MODULE_DEVICE_TABLE(i2c, blinkm_id);
+
+ /* This is the driver that will be inserted */
+static struct i2c_driver blinkm_driver = {
+ .class = I2C_CLASS_HWMON,
+ .driver = {
+ .name = "blinkm",
+ },
+ .probe = blinkm_probe,
+ .remove = __devexit_p(blinkm_remove),
+ .id_table = blinkm_id,
+ .detect = blinkm_detect,
+ .address_list = normal_i2c,
+};
+
+module_i2c_driver(blinkm_driver);
+
+MODULE_AUTHOR("Jan-Simon Moeller <dl9pf@gmx.de>");
+MODULE_DESCRIPTION("BlinkM RGB LED driver");
+MODULE_LICENSE("GPL");
+
diff --git a/drivers/leds/leds-da903x.c b/drivers/leds/leds-da903x.c
index d9cd73ebd6c4..cc77c9d92615 100644
--- a/drivers/leds/leds-da903x.c
+++ b/drivers/leds/leds-da903x.c
@@ -108,7 +108,7 @@ static int __devinit da903x_led_probe(struct platform_device *pdev)
return -EINVAL;
}
- led = kzalloc(sizeof(struct da903x_led), GFP_KERNEL);
+ led = devm_kzalloc(&pdev->dev, sizeof(struct da903x_led), GFP_KERNEL);
if (led == NULL) {
dev_err(&pdev->dev, "failed to alloc memory for LED%d\n", id);
return -ENOMEM;
@@ -129,15 +129,11 @@ static int __devinit da903x_led_probe(struct platform_device *pdev)
ret = led_classdev_register(led->master, &led->cdev);
if (ret) {
dev_err(&pdev->dev, "failed to register LED %d\n", id);
- goto err;
+ return ret;
}
platform_set_drvdata(pdev, led);
return 0;
-
-err:
- kfree(led);
- return ret;
}
static int __devexit da903x_led_remove(struct platform_device *pdev)
@@ -145,7 +141,6 @@ static int __devexit da903x_led_remove(struct platform_device *pdev)
struct da903x_led *led = platform_get_drvdata(pdev);
led_classdev_unregister(&led->cdev);
- kfree(led);
return 0;
}
diff --git a/drivers/leds/leds-dac124s085.c b/drivers/leds/leds-dac124s085.c
index d56c14269ff0..1f9d8e62d37e 100644
--- a/drivers/leds/leds-dac124s085.c
+++ b/drivers/leds/leds-dac124s085.c
@@ -69,7 +69,7 @@ static int dac124s085_probe(struct spi_device *spi)
struct dac124s085_led *led;
int i, ret;
- dac = kzalloc(sizeof(*dac), GFP_KERNEL);
+ dac = devm_kzalloc(&spi->dev, sizeof(*dac), GFP_KERNEL);
if (!dac)
return -ENOMEM;
@@ -102,7 +102,6 @@ eledcr:
led_classdev_unregister(&dac->leds[i].ldev);
spi_set_drvdata(spi, NULL);
- kfree(dac);
return ret;
}
@@ -117,7 +116,6 @@ static int dac124s085_remove(struct spi_device *spi)
}
spi_set_drvdata(spi, NULL);
- kfree(dac);
return 0;
}
diff --git a/drivers/leds/leds-gpio.c b/drivers/leds/leds-gpio.c
index f4c470a3bc8d..c032b2180340 100644
--- a/drivers/leds/leds-gpio.c
+++ b/drivers/leds/leds-gpio.c
@@ -178,7 +178,8 @@ static struct gpio_leds_priv * __devinit gpio_leds_create_of(struct platform_dev
if (!count)
return NULL;
- priv = kzalloc(sizeof_gpio_leds_priv(count), GFP_KERNEL);
+ priv = devm_kzalloc(&pdev->dev, sizeof_gpio_leds_priv(count),
+ GFP_KERNEL);
if (!priv)
return NULL;
@@ -215,7 +216,6 @@ static struct gpio_leds_priv * __devinit gpio_leds_create_of(struct platform_dev
err:
for (count = priv->num_leds - 2; count >= 0; count--)
delete_gpio_led(&priv->leds[count]);
- kfree(priv);
return NULL;
}
@@ -239,8 +239,9 @@ static int __devinit gpio_led_probe(struct platform_device *pdev)
int i, ret = 0;
if (pdata && pdata->num_leds) {
- priv = kzalloc(sizeof_gpio_leds_priv(pdata->num_leds),
- GFP_KERNEL);
+ priv = devm_kzalloc(&pdev->dev,
+ sizeof_gpio_leds_priv(pdata->num_leds),
+ GFP_KERNEL);
if (!priv)
return -ENOMEM;
@@ -253,7 +254,6 @@ static int __devinit gpio_led_probe(struct platform_device *pdev)
/* On failure: unwind the led creations */
for (i = i - 1; i >= 0; i--)
delete_gpio_led(&priv->leds[i]);
- kfree(priv);
return ret;
}
}
@@ -277,7 +277,6 @@ static int __devexit gpio_led_remove(struct platform_device *pdev)
delete_gpio_led(&priv->leds[i]);
dev_set_drvdata(&pdev->dev, NULL);
- kfree(priv);
return 0;
}
diff --git a/drivers/leds/leds-lm3530.c b/drivers/leds/leds-lm3530.c
index 84ba6de8039c..23637bdb275d 100644
--- a/drivers/leds/leds-lm3530.c
+++ b/drivers/leds/leds-lm3530.c
@@ -386,28 +386,24 @@ static int __devinit lm3530_probe(struct i2c_client *client,
if (pdata == NULL) {
dev_err(&client->dev, "platform data required\n");
- err = -ENODEV;
- goto err_out;
+ return -ENODEV;
}
/* BL mode */
if (pdata->mode > LM3530_BL_MODE_PWM) {
dev_err(&client->dev, "Illegal Mode request\n");
- err = -EINVAL;
- goto err_out;
+ return -EINVAL;
}
if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
dev_err(&client->dev, "I2C_FUNC_I2C not supported\n");
- err = -EIO;
- goto err_out;
+ return -EIO;
}
- drvdata = kzalloc(sizeof(struct lm3530_data), GFP_KERNEL);
- if (drvdata == NULL) {
- err = -ENOMEM;
- goto err_out;
- }
+ drvdata = devm_kzalloc(&client->dev, sizeof(struct lm3530_data),
+ GFP_KERNEL);
+ if (drvdata == NULL)
+ return -ENOMEM;
drvdata->mode = pdata->mode;
drvdata->client = client;
@@ -425,7 +421,7 @@ static int __devinit lm3530_probe(struct i2c_client *client,
dev_err(&client->dev, "regulator get failed\n");
err = PTR_ERR(drvdata->regulator);
drvdata->regulator = NULL;
- goto err_regulator_get;
+ return err;
}
if (drvdata->pdata->brt_val) {
@@ -458,9 +454,6 @@ err_create_file:
err_class_register:
err_reg_init:
regulator_put(drvdata->regulator);
-err_regulator_get:
- kfree(drvdata);
-err_out:
return err;
}
@@ -474,7 +467,6 @@ static int __devexit lm3530_remove(struct i2c_client *client)
regulator_disable(drvdata->regulator);
regulator_put(drvdata->regulator);
led_classdev_unregister(&drvdata->led_dev);
- kfree(drvdata);
return 0;
}
diff --git a/drivers/leds/leds-lm3556.c b/drivers/leds/leds-lm3556.c
new file mode 100644
index 000000000000..3062abd9a532
--- /dev/null
+++ b/drivers/leds/leds-lm3556.c
@@ -0,0 +1,512 @@
+/*
+ * Simple driver for Texas Instruments LM3556 LED Flash driver chip (Rev0x03)
+ * Copyright (C) 2012 Texas Instruments
+ *
+ * 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.
+ *
+ * Please refer Documentation/leds/leds-lm3556.txt file.
+ */
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/leds.h>
+#include <linux/slab.h>
+#include <linux/platform_device.h>
+#include <linux/fs.h>
+#include <linux/regmap.h>
+#include <linux/platform_data/leds-lm3556.h>
+
+#define REG_FILT_TIME (0x0)
+#define REG_IVFM_MODE (0x1)
+#define REG_NTC (0x2)
+#define REG_INDIC_TIME (0x3)
+#define REG_INDIC_BLINK (0x4)
+#define REG_INDIC_PERIOD (0x5)
+#define REG_TORCH_TIME (0x6)
+#define REG_CONF (0x7)
+#define REG_FLASH (0x8)
+#define REG_I_CTRL (0x9)
+#define REG_ENABLE (0xA)
+#define REG_FLAG (0xB)
+#define REG_MAX (0xB)
+
+#define IVFM_FILTER_TIME_SHIFT (3)
+#define UVLO_EN_SHIFT (7)
+#define HYSTERSIS_SHIFT (5)
+#define IVM_D_TH_SHIFT (2)
+#define IVFM_ADJ_MODE_SHIFT (0)
+#define NTC_EVENT_LVL_SHIFT (5)
+#define NTC_TRIP_TH_SHIFT (2)
+#define NTC_BIAS_I_LVL_SHIFT (0)
+#define INDIC_RAMP_UP_TIME_SHIFT (3)
+#define INDIC_RAMP_DN_TIME_SHIFT (0)
+#define INDIC_N_BLANK_SHIFT (4)
+#define INDIC_PULSE_TIME_SHIFT (0)
+#define INDIC_N_PERIOD_SHIFT (0)
+#define TORCH_RAMP_UP_TIME_SHIFT (3)
+#define TORCH_RAMP_DN_TIME_SHIFT (0)
+#define STROBE_USUAGE_SHIFT (7)
+#define STROBE_PIN_POLARITY_SHIFT (6)
+#define TORCH_PIN_POLARITY_SHIFT (5)
+#define TX_PIN_POLARITY_SHIFT (4)
+#define TX_EVENT_LVL_SHIFT (3)
+#define IVFM_EN_SHIFT (2)
+#define NTC_MODE_SHIFT (1)
+#define INDIC_MODE_SHIFT (0)
+#define INDUCTOR_I_LIMIT_SHIFT (6)
+#define FLASH_RAMP_TIME_SHIFT (3)
+#define FLASH_TOUT_TIME_SHIFT (0)
+#define TORCH_I_SHIFT (4)
+#define FLASH_I_SHIFT (0)
+#define NTC_EN_SHIFT (7)
+#define TX_PIN_EN_SHIFT (6)
+#define STROBE_PIN_EN_SHIFT (5)
+#define TORCH_PIN_EN_SHIFT (4)
+#define PRECHG_MODE_EN_SHIFT (3)
+#define PASS_MODE_ONLY_EN_SHIFT (2)
+#define MODE_BITS_SHIFT (0)
+
+#define IVFM_FILTER_TIME_MASK (0x3)
+#define UVLO_EN_MASK (0x1)
+#define HYSTERSIS_MASK (0x3)
+#define IVM_D_TH_MASK (0x7)
+#define IVFM_ADJ_MODE_MASK (0x3)
+#define NTC_EVENT_LVL_MASK (0x1)
+#define NTC_TRIP_TH_MASK (0x7)
+#define NTC_BIAS_I_LVL_MASK (0x3)
+#define INDIC_RAMP_UP_TIME_MASK (0x7)
+#define INDIC_RAMP_DN_TIME_MASK (0x7)
+#define INDIC_N_BLANK_MASK (0x7)
+#define INDIC_PULSE_TIME_MASK (0x7)
+#define INDIC_N_PERIOD_MASK (0x7)
+#define TORCH_RAMP_UP_TIME_MASK (0x7)
+#define TORCH_RAMP_DN_TIME_MASK (0x7)
+#define STROBE_USUAGE_MASK (0x1)
+#define STROBE_PIN_POLARITY_MASK (0x1)
+#define TORCH_PIN_POLARITY_MASK (0x1)
+#define TX_PIN_POLARITY_MASK (0x1)
+#define TX_EVENT_LVL_MASK (0x1)
+#define IVFM_EN_MASK (0x1)
+#define NTC_MODE_MASK (0x1)
+#define INDIC_MODE_MASK (0x1)
+#define INDUCTOR_I_LIMIT_MASK (0x3)
+#define FLASH_RAMP_TIME_MASK (0x7)
+#define FLASH_TOUT_TIME_MASK (0x7)
+#define TORCH_I_MASK (0x7)
+#define FLASH_I_MASK (0xF)
+#define NTC_EN_MASK (0x1)
+#define TX_PIN_EN_MASK (0x1)
+#define STROBE_PIN_EN_MASK (0x1)
+#define TORCH_PIN_EN_MASK (0x1)
+#define PRECHG_MODE_EN_MASK (0x1)
+#define PASS_MODE_ONLY_EN_MASK (0x1)
+#define MODE_BITS_MASK (0x13)
+#define EX_PIN_CONTROL_MASK (0xF1)
+#define EX_PIN_ENABLE_MASK (0x70)
+
+enum lm3556_indic_pulse_time {
+ PULSE_TIME_0_MS = 0,
+ PULSE_TIME_32_MS,
+ PULSE_TIME_64_MS,
+ PULSE_TIME_92_MS,
+ PULSE_TIME_128_MS,
+ PULSE_TIME_160_MS,
+ PULSE_TIME_196_MS,
+ PULSE_TIME_224_MS,
+ PULSE_TIME_256_MS,
+ PULSE_TIME_288_MS,
+ PULSE_TIME_320_MS,
+ PULSE_TIME_352_MS,
+ PULSE_TIME_384_MS,
+ PULSE_TIME_416_MS,
+ PULSE_TIME_448_MS,
+ PULSE_TIME_480_MS,
+};
+
+enum lm3556_indic_n_blank {
+ INDIC_N_BLANK_0 = 0,
+ INDIC_N_BLANK_1,
+ INDIC_N_BLANK_2,
+ INDIC_N_BLANK_3,
+ INDIC_N_BLANK_4,
+ INDIC_N_BLANK_5,
+ INDIC_N_BLANK_6,
+ INDIC_N_BLANK_7,
+ INDIC_N_BLANK_8,
+ INDIC_N_BLANK_9,
+ INDIC_N_BLANK_10,
+ INDIC_N_BLANK_11,
+ INDIC_N_BLANK_12,
+ INDIC_N_BLANK_13,
+ INDIC_N_BLANK_14,
+ INDIC_N_BLANK_15,
+};
+
+enum lm3556_indic_period {
+ INDIC_PERIOD_0 = 0,
+ INDIC_PERIOD_1,
+ INDIC_PERIOD_2,
+ INDIC_PERIOD_3,
+ INDIC_PERIOD_4,
+ INDIC_PERIOD_5,
+ INDIC_PERIOD_6,
+ INDIC_PERIOD_7,
+};
+
+enum lm3556_mode {
+ MODES_STASNDBY = 0,
+ MODES_INDIC,
+ MODES_TORCH,
+ MODES_FLASH
+};
+
+#define INDIC_PATTERN_SIZE 4
+
+struct indicator {
+ u8 blinking;
+ u8 period_cnt;
+};
+
+struct lm3556_chip_data {
+ struct device *dev;
+
+ struct led_classdev cdev_flash;
+ struct led_classdev cdev_torch;
+ struct led_classdev cdev_indicator;
+
+ struct lm3556_platform_data *pdata;
+ struct regmap *regmap;
+ struct mutex lock;
+
+ unsigned int last_flag;
+};
+
+/* indicator pattern */
+static struct indicator indicator_pattern[INDIC_PATTERN_SIZE] = {
+ [0] = {(INDIC_N_BLANK_1 << INDIC_N_BLANK_SHIFT)
+ | PULSE_TIME_32_MS, INDIC_PERIOD_1},
+ [1] = {(INDIC_N_BLANK_15 << INDIC_N_BLANK_SHIFT)
+ | PULSE_TIME_32_MS, INDIC_PERIOD_2},
+ [2] = {(INDIC_N_BLANK_10 << INDIC_N_BLANK_SHIFT)
+ | PULSE_TIME_32_MS, INDIC_PERIOD_4},
+ [3] = {(INDIC_N_BLANK_5 << INDIC_N_BLANK_SHIFT)
+ | PULSE_TIME_32_MS, INDIC_PERIOD_7},
+};
+
+/* chip initialize */
+static int __devinit lm3556_chip_init(struct lm3556_chip_data *chip)
+{
+ unsigned int reg_val;
+ int ret;
+ struct lm3556_platform_data *pdata = chip->pdata;
+
+ /* set config register */
+ ret = regmap_read(chip->regmap, REG_CONF, &reg_val);
+ if (ret < 0) {
+ dev_err(chip->dev, "Failed to read REG_CONF Register\n");
+ goto out;
+ }
+
+ reg_val &= (~EX_PIN_CONTROL_MASK);
+ reg_val |= ((pdata->torch_pin_polarity & 0x01)
+ << TORCH_PIN_POLARITY_SHIFT);
+ reg_val |= ((pdata->strobe_usuage & 0x01) << STROBE_USUAGE_SHIFT);
+ reg_val |= ((pdata->strobe_pin_polarity & 0x01)
+ << STROBE_PIN_POLARITY_SHIFT);
+ reg_val |= ((pdata->tx_pin_polarity & 0x01) << TX_PIN_POLARITY_SHIFT);
+ reg_val |= ((pdata->indicator_mode & 0x01) << INDIC_MODE_SHIFT);
+
+ ret = regmap_write(chip->regmap, REG_CONF, reg_val);
+ if (ret < 0) {
+ dev_err(chip->dev, "Failed to write REG_CONF Regisgter\n");
+ goto out;
+ }
+
+ /* set enable register */
+ ret = regmap_read(chip->regmap, REG_ENABLE, &reg_val);
+ if (ret < 0) {
+ dev_err(chip->dev, "Failed to read REG_ENABLE Register\n");
+ goto out;
+ }
+
+ reg_val &= (~EX_PIN_ENABLE_MASK);
+ reg_val |= ((pdata->torch_pin_en & 0x01) << TORCH_PIN_EN_SHIFT);
+ reg_val |= ((pdata->strobe_pin_en & 0x01) << STROBE_PIN_EN_SHIFT);
+ reg_val |= ((pdata->tx_pin_en & 0x01) << TX_PIN_EN_SHIFT);
+
+ ret = regmap_write(chip->regmap, REG_ENABLE, reg_val);
+ if (ret < 0) {
+ dev_err(chip->dev, "Failed to write REG_ENABLE Regisgter\n");
+ goto out;
+ }
+
+out:
+ return ret;
+}
+
+/* chip control */
+static int lm3556_control(struct lm3556_chip_data *chip,
+ u8 brightness, enum lm3556_mode opmode)
+{
+ int ret;
+ struct lm3556_platform_data *pdata = chip->pdata;
+
+ ret = regmap_read(chip->regmap, REG_FLAG, &chip->last_flag);
+ if (ret < 0) {
+ dev_err(chip->dev, "Failed to read REG_FLAG Register\n");
+ goto out;
+ }
+
+ if (chip->last_flag)
+ dev_info(chip->dev, "Last FLAG is 0x%x\n", chip->last_flag);
+
+ /* brightness 0 means off-state */
+ if (!brightness)
+ opmode = MODES_STASNDBY;
+
+ switch (opmode) {
+ case MODES_TORCH:
+ ret = regmap_update_bits(chip->regmap, REG_I_CTRL,
+ TORCH_I_MASK << TORCH_I_SHIFT,
+ (brightness - 1) << TORCH_I_SHIFT);
+
+ if (pdata->torch_pin_en)
+ opmode |= (TORCH_PIN_EN_MASK << TORCH_PIN_EN_SHIFT);
+ break;
+
+ case MODES_FLASH:
+ ret = regmap_update_bits(chip->regmap, REG_I_CTRL,
+ FLASH_I_MASK << FLASH_I_SHIFT,
+ (brightness - 1) << FLASH_I_SHIFT);
+ break;
+
+ case MODES_INDIC:
+ ret = regmap_update_bits(chip->regmap, REG_I_CTRL,
+ TORCH_I_MASK << TORCH_I_SHIFT,
+ (brightness - 1) << TORCH_I_SHIFT);
+ break;
+
+ case MODES_STASNDBY:
+ if (pdata->torch_pin_en)
+ opmode |= (TORCH_PIN_EN_MASK << TORCH_PIN_EN_SHIFT);
+ break;
+
+ default:
+ return ret;
+ }
+ if (ret < 0) {
+ dev_err(chip->dev, "Failed to write REG_I_CTRL Register\n");
+ goto out;
+ }
+ ret = regmap_update_bits(chip->regmap, REG_ENABLE,
+ MODE_BITS_MASK << MODE_BITS_SHIFT,
+ opmode << MODE_BITS_SHIFT);
+
+out:
+ return ret;
+}
+
+/* torch */
+static void lm3556_torch_brightness_set(struct led_classdev *cdev,
+ enum led_brightness brightness)
+{
+ struct lm3556_chip_data *chip =
+ container_of(cdev, struct lm3556_chip_data, cdev_torch);
+
+ mutex_lock(&chip->lock);
+ lm3556_control(chip, brightness, MODES_TORCH);
+ mutex_unlock(&chip->lock);
+}
+
+/* flash */
+static void lm3556_strobe_brightness_set(struct led_classdev *cdev,
+ enum led_brightness brightness)
+{
+ struct lm3556_chip_data *chip =
+ container_of(cdev, struct lm3556_chip_data, cdev_flash);
+
+ mutex_lock(&chip->lock);
+ lm3556_control(chip, brightness, MODES_FLASH);
+ mutex_unlock(&chip->lock);
+}
+
+/* indicator */
+static void lm3556_indicator_brightness_set(struct led_classdev *cdev,
+ enum led_brightness brightness)
+{
+ struct lm3556_chip_data *chip =
+ container_of(cdev, struct lm3556_chip_data, cdev_indicator);
+
+ mutex_lock(&chip->lock);
+ lm3556_control(chip, brightness, MODES_INDIC);
+ mutex_unlock(&chip->lock);
+}
+
+/* indicator pattern */
+static ssize_t lm3556_indicator_pattern_store(struct device *dev,
+ struct device_attribute *devAttr,
+ const char *buf, size_t size)
+{
+ ssize_t ret;
+ struct led_classdev *led_cdev = dev_get_drvdata(dev);
+ struct lm3556_chip_data *chip =
+ container_of(led_cdev, struct lm3556_chip_data, cdev_indicator);
+ unsigned int state;
+
+ ret = kstrtouint(buf, 10, &state);
+ if (ret)
+ goto out;
+ if (state > INDIC_PATTERN_SIZE - 1)
+ state = INDIC_PATTERN_SIZE - 1;
+
+ ret = regmap_write(chip->regmap, REG_INDIC_BLINK,
+ indicator_pattern[state].blinking);
+ if (ret < 0) {
+ dev_err(chip->dev, "Failed to write REG_ENABLE Regisgter\n");
+ goto out;
+ }
+
+ ret = regmap_write(chip->regmap, REG_INDIC_PERIOD,
+ indicator_pattern[state].period_cnt);
+ if (ret < 0) {
+ dev_err(chip->dev, "Failed to write REG_ENABLE Regisgter\n");
+ goto out;
+ }
+
+ return size;
+out:
+ dev_err(chip->dev, "Indicator pattern doesn't saved\n");
+ return size;
+}
+
+static DEVICE_ATTR(pattern, 0666, NULL, lm3556_indicator_pattern_store);
+
+static const struct regmap_config lm3556_regmap = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .max_register = REG_MAX,
+};
+
+/* module initialize */
+static int __devinit lm3556_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct lm3556_platform_data *pdata = client->dev.platform_data;
+ struct lm3556_chip_data *chip;
+
+ int err;
+
+ if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
+ dev_err(&client->dev, "i2c functionality check fail.\n");
+ return -EOPNOTSUPP;
+ }
+
+ if (pdata == NULL) {
+ dev_err(&client->dev, "Needs Platform Data.\n");
+ return -ENODATA;
+ }
+
+ chip =
+ devm_kzalloc(&client->dev, sizeof(struct lm3556_chip_data),
+ GFP_KERNEL);
+ if (!chip)
+ return -ENOMEM;
+
+ chip->dev = &client->dev;
+ chip->pdata = pdata;
+
+ chip->regmap = devm_regmap_init_i2c(client, &lm3556_regmap);
+ if (IS_ERR(chip->regmap)) {
+ err = PTR_ERR(chip->regmap);
+ dev_err(&client->dev, "Failed to allocate register map: %d\n",
+ err);
+ return err;
+ }
+
+ mutex_init(&chip->lock);
+ i2c_set_clientdata(client, chip);
+
+ err = lm3556_chip_init(chip);
+ if (err < 0)
+ goto err_out;
+
+ /* flash */
+ chip->cdev_flash.name = "flash";
+ chip->cdev_flash.max_brightness = 16;
+ chip->cdev_flash.brightness_set = lm3556_strobe_brightness_set;
+ err = led_classdev_register((struct device *)
+ &client->dev, &chip->cdev_flash);
+ if (err < 0)
+ goto err_out;
+ /* torch */
+ chip->cdev_torch.name = "torch";
+ chip->cdev_torch.max_brightness = 8;
+ chip->cdev_torch.brightness_set = lm3556_torch_brightness_set;
+ err = led_classdev_register((struct device *)
+ &client->dev, &chip->cdev_torch);
+ if (err < 0)
+ goto err_create_torch_file;
+ /* indicator */
+ chip->cdev_indicator.name = "indicator";
+ chip->cdev_indicator.max_brightness = 8;
+ chip->cdev_indicator.brightness_set = lm3556_indicator_brightness_set;
+ err = led_classdev_register((struct device *)
+ &client->dev, &chip->cdev_indicator);
+ if (err < 0)
+ goto err_create_indicator_file;
+
+ err = device_create_file(chip->cdev_indicator.dev, &dev_attr_pattern);
+ if (err < 0)
+ goto err_create_pattern_file;
+
+ dev_info(&client->dev, "LM3556 is initialized\n");
+ 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:
+ led_classdev_unregister(&chip->cdev_flash);
+err_out:
+ return err;
+}
+
+static int __devexit lm3556_remove(struct i2c_client *client)
+{
+ struct lm3556_chip_data *chip = i2c_get_clientdata(client);
+
+ device_remove_file(chip->cdev_indicator.dev, &dev_attr_pattern);
+ led_classdev_unregister(&chip->cdev_indicator);
+ led_classdev_unregister(&chip->cdev_torch);
+ led_classdev_unregister(&chip->cdev_flash);
+ regmap_write(chip->regmap, REG_ENABLE, 0);
+ return 0;
+}
+
+static const struct i2c_device_id lm3556_id[] = {
+ {LM3556_NAME, 0},
+ {}
+};
+
+MODULE_DEVICE_TABLE(i2c, lm3556_id);
+
+static struct i2c_driver lm3556_i2c_driver = {
+ .driver = {
+ .name = LM3556_NAME,
+ .owner = THIS_MODULE,
+ .pm = NULL,
+ },
+ .probe = lm3556_probe,
+ .remove = __devexit_p(lm3556_remove),
+ .id_table = lm3556_id,
+};
+
+module_i2c_driver(lm3556_i2c_driver);
+
+MODULE_DESCRIPTION("Texas Instruments Flash Lighting driver for LM3556");
+MODULE_AUTHOR("Daniel Jeong <daniel.jeong@ti.com>");
+MODULE_AUTHOR("G.Shark Jeong <gshark.jeong@gmail.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/leds/leds-lp3944.c b/drivers/leds/leds-lp3944.c
index b8f9f0a5d431..c298f7d9f535 100644
--- a/drivers/leds/leds-lp3944.c
+++ b/drivers/leds/leds-lp3944.c
@@ -393,7 +393,8 @@ static int __devinit lp3944_probe(struct i2c_client *client,
return -ENODEV;
}
- data = kzalloc(sizeof(struct lp3944_data), GFP_KERNEL);
+ data = devm_kzalloc(&client->dev, sizeof(struct lp3944_data),
+ GFP_KERNEL);
if (!data)
return -ENOMEM;
@@ -403,10 +404,8 @@ static int __devinit lp3944_probe(struct i2c_client *client,
mutex_init(&data->lock);
err = lp3944_configure(client, data, lp3944_pdata);
- if (err < 0) {
- kfree(data);
+ if (err < 0)
return err;
- }
dev_info(&client->dev, "lp3944 enabled\n");
return 0;
@@ -431,8 +430,6 @@ static int __devexit lp3944_remove(struct i2c_client *client)
break;
}
- kfree(data);
-
return 0;
}
diff --git a/drivers/leds/leds-lp5521.c b/drivers/leds/leds-lp5521.c
index 23815624f35e..2064aefedc07 100644
--- a/drivers/leds/leds-lp5521.c
+++ b/drivers/leds/leds-lp5521.c
@@ -744,7 +744,7 @@ static int __devinit lp5521_probe(struct i2c_client *client,
int ret, i, led;
u8 buf;
- chip = kzalloc(sizeof(*chip), GFP_KERNEL);
+ chip = devm_kzalloc(&client->dev, sizeof(*chip), GFP_KERNEL);
if (!chip)
return -ENOMEM;
@@ -755,8 +755,7 @@ static int __devinit lp5521_probe(struct i2c_client *client,
if (!pdata) {
dev_err(&client->dev, "no platform data\n");
- ret = -EINVAL;
- goto fail1;
+ return -EINVAL;
}
mutex_init(&chip->lock);
@@ -766,7 +765,7 @@ static int __devinit lp5521_probe(struct i2c_client *client,
if (pdata->setup_resources) {
ret = pdata->setup_resources();
if (ret < 0)
- goto fail1;
+ return ret;
}
if (pdata->enable) {
@@ -807,7 +806,7 @@ static int __devinit lp5521_probe(struct i2c_client *client,
ret = lp5521_configure(client);
if (ret < 0) {
dev_err(&client->dev, "error configuring chip\n");
- goto fail2;
+ goto fail1;
}
/* Initialize leds */
@@ -822,7 +821,7 @@ static int __devinit lp5521_probe(struct i2c_client *client,
ret = lp5521_init_led(&chip->leds[led], client, i, pdata);
if (ret) {
dev_err(&client->dev, "error initializing leds\n");
- goto fail3;
+ goto fail2;
}
chip->num_leds++;
@@ -840,21 +839,19 @@ static int __devinit lp5521_probe(struct i2c_client *client,
ret = lp5521_register_sysfs(client);
if (ret) {
dev_err(&client->dev, "registering sysfs failed\n");
- goto fail3;
+ goto fail2;
}
return ret;
-fail3:
+fail2:
for (i = 0; i < chip->num_leds; i++) {
led_classdev_unregister(&chip->leds[i].cdev);
cancel_work_sync(&chip->leds[i].brightness_work);
}
-fail2:
+fail1:
if (pdata->enable)
pdata->enable(0);
if (pdata->release_resources)
pdata->release_resources();
-fail1:
- kfree(chip);
return ret;
}
@@ -875,7 +872,6 @@ static int __devexit lp5521_remove(struct i2c_client *client)
chip->pdata->enable(0);
if (chip->pdata->release_resources)
chip->pdata->release_resources();
- kfree(chip);
return 0;
}
diff --git a/drivers/leds/leds-lp5523.c b/drivers/leds/leds-lp5523.c
index 857a3e15f2dd..fbc12acada95 100644
--- a/drivers/leds/leds-lp5523.c
+++ b/drivers/leds/leds-lp5523.c
@@ -877,7 +877,7 @@ static int __devinit lp5523_probe(struct i2c_client *client,
struct lp5523_platform_data *pdata;
int ret, i, led;
- chip = kzalloc(sizeof(*chip), GFP_KERNEL);
+ chip = devm_kzalloc(&client->dev, sizeof(*chip), GFP_KERNEL);
if (!chip)
return -ENOMEM;
@@ -888,8 +888,7 @@ static int __devinit lp5523_probe(struct i2c_client *client,
if (!pdata) {
dev_err(&client->dev, "no platform data\n");
- ret = -EINVAL;
- goto fail1;
+ return -EINVAL;
}
mutex_init(&chip->lock);
@@ -899,7 +898,7 @@ static int __devinit lp5523_probe(struct i2c_client *client,
if (pdata->setup_resources) {
ret = pdata->setup_resources();
if (ret < 0)
- goto fail1;
+ return ret;
}
if (pdata->enable) {
@@ -916,7 +915,7 @@ static int __devinit lp5523_probe(struct i2c_client *client,
*/
ret = lp5523_detect(client);
if (ret)
- goto fail2;
+ goto fail1;
dev_info(&client->dev, "LP5523 Programmable led chip found\n");
@@ -925,13 +924,13 @@ static int __devinit lp5523_probe(struct i2c_client *client,
ret = lp5523_init_engine(&chip->engines[i], i + 1);
if (ret) {
dev_err(&client->dev, "error initializing engine\n");
- goto fail2;
+ goto fail1;
}
}
ret = lp5523_configure(client);
if (ret < 0) {
dev_err(&client->dev, "error configuring chip\n");
- goto fail2;
+ goto fail1;
}
/* Initialize leds */
@@ -943,10 +942,13 @@ static int __devinit lp5523_probe(struct i2c_client *client,
if (pdata->led_config[i].led_current == 0)
continue;
+ INIT_WORK(&chip->leds[led].brightness_work,
+ lp5523_led_brightness_work);
+
ret = lp5523_init_led(&chip->leds[led], &client->dev, i, pdata);
if (ret) {
dev_err(&client->dev, "error initializing leds\n");
- goto fail3;
+ goto fail2;
}
chip->num_leds++;
@@ -956,30 +958,25 @@ static int __devinit lp5523_probe(struct i2c_client *client,
LP5523_REG_LED_CURRENT_BASE + chip->leds[led].chan_nr,
chip->leds[led].led_current);
- INIT_WORK(&(chip->leds[led].brightness_work),
- lp5523_led_brightness_work);
-
led++;
}
ret = lp5523_register_sysfs(client);
if (ret) {
dev_err(&client->dev, "registering sysfs failed\n");
- goto fail3;
+ goto fail2;
}
return ret;
-fail3:
+fail2:
for (i = 0; i < chip->num_leds; i++) {
led_classdev_unregister(&chip->leds[i].cdev);
cancel_work_sync(&chip->leds[i].brightness_work);
}
-fail2:
+fail1:
if (pdata->enable)
pdata->enable(0);
if (pdata->release_resources)
pdata->release_resources();
-fail1:
- kfree(chip);
return ret;
}
@@ -999,7 +996,6 @@ static int lp5523_remove(struct i2c_client *client)
chip->pdata->enable(0);
if (chip->pdata->release_resources)
chip->pdata->release_resources();
- kfree(chip);
return 0;
}
diff --git a/drivers/leds/leds-lp8788.c b/drivers/leds/leds-lp8788.c
new file mode 100644
index 000000000000..53bd136f1ef0
--- /dev/null
+++ b/drivers/leds/leds-lp8788.c
@@ -0,0 +1,193 @@
+/*
+ * TI LP8788 MFD - keyled driver
+ *
+ * Copyright 2012 Texas Instruments
+ *
+ * Author: Milo(Woogyom) Kim <milo.kim@ti.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/err.h>
+#include <linux/platform_device.h>
+#include <linux/leds.h>
+#include <linux/mutex.h>
+#include <linux/mfd/lp8788.h>
+#include <linux/mfd/lp8788-isink.h>
+
+#define MAX_BRIGHTNESS LP8788_ISINK_MAX_PWM
+#define DEFAULT_LED_NAME "keyboard-backlight"
+
+struct lp8788_led {
+ struct lp8788 *lp;
+ struct mutex lock;
+ struct work_struct work;
+ struct led_classdev led_dev;
+ enum lp8788_isink_number isink_num;
+ enum led_brightness brightness;
+ int on;
+};
+
+struct lp8788_led_config {
+ enum lp8788_isink_scale scale;
+ enum lp8788_isink_number num;
+ int iout;
+};
+
+static struct lp8788_led_config default_led_config = {
+ .scale = LP8788_ISINK_SCALE_100mA,
+ .num = LP8788_ISINK_3,
+ .iout = 0,
+};
+
+static int lp8788_led_init_device(struct lp8788_led *led,
+ struct lp8788_led_platform_data *pdata)
+{
+ struct lp8788_led_config *cfg = &default_led_config;
+ u8 addr, mask, val;
+ int ret;
+
+ if (pdata) {
+ cfg->scale = pdata->scale;
+ cfg->num = pdata->num;
+ cfg->iout = pdata->iout_code;
+ }
+
+ led->isink_num = cfg->num;
+
+ /* scale configuration */
+ addr = LP8788_ISINK_CTRL;
+ mask = 1 << (cfg->num + LP8788_ISINK_SCALE_OFFSET);
+ val = cfg->scale << cfg->num;
+ ret = lp8788_update_bits(led->lp, addr, mask, val);
+ if (ret)
+ return ret;
+
+ /* current configuration */
+ addr = lp8788_iout_addr[cfg->num];
+ mask = lp8788_iout_mask[cfg->num];
+ val = cfg->iout;
+
+ return lp8788_update_bits(led->lp, addr, mask, val);
+}
+
+static void lp8788_led_enable(struct lp8788_led *led,
+ enum lp8788_isink_number num, int on)
+{
+ u8 mask = 1 << num;
+ u8 val = on << num;
+
+ if (lp8788_update_bits(led->lp, LP8788_ISINK_CTRL, mask, val))
+ return;
+
+ led->on = on;
+}
+
+static void lp8788_led_work(struct work_struct *work)
+{
+ struct lp8788_led *led = container_of(work, struct lp8788_led, work);
+ enum lp8788_isink_number num = led->isink_num;
+ int enable;
+ u8 val = led->brightness;
+
+ mutex_lock(&led->lock);
+
+ switch (num) {
+ case LP8788_ISINK_1:
+ case LP8788_ISINK_2:
+ case LP8788_ISINK_3:
+ lp8788_write_byte(led->lp, lp8788_pwm_addr[num], val);
+ break;
+ default:
+ mutex_unlock(&led->lock);
+ return;
+ }
+
+ enable = (val > 0) ? 1 : 0;
+ if (enable != led->on)
+ lp8788_led_enable(led, num, enable);
+
+ mutex_unlock(&led->lock);
+}
+
+static void lp8788_brightness_set(struct led_classdev *led_cdev,
+ enum led_brightness brt_val)
+{
+ struct lp8788_led *led =
+ container_of(led_cdev, struct lp8788_led, led_dev);
+
+ led->brightness = brt_val;
+ schedule_work(&led->work);
+}
+
+static __devinit int lp8788_led_probe(struct platform_device *pdev)
+{
+ struct lp8788 *lp = dev_get_drvdata(pdev->dev.parent);
+ struct lp8788_led_platform_data *led_pdata;
+ struct lp8788_led *led;
+ int ret;
+
+ led = devm_kzalloc(lp->dev, sizeof(struct lp8788_led), GFP_KERNEL);
+ if (!led)
+ return -ENOMEM;
+
+ led->lp = lp;
+ led->led_dev.max_brightness = MAX_BRIGHTNESS;
+ led->led_dev.brightness_set = lp8788_brightness_set;
+
+ led_pdata = lp->pdata ? lp->pdata->led_pdata : NULL;
+
+ if (!led_pdata || !led_pdata->name)
+ led->led_dev.name = DEFAULT_LED_NAME;
+ else
+ led->led_dev.name = led_pdata->name;
+
+ mutex_init(&led->lock);
+ INIT_WORK(&led->work, lp8788_led_work);
+
+ platform_set_drvdata(pdev, led);
+
+ ret = lp8788_led_init_device(led, led_pdata);
+ if (ret) {
+ dev_err(lp->dev, "led init device err: %d\n", ret);
+ return ret;
+ }
+
+ ret = led_classdev_register(lp->dev, &led->led_dev);
+ if (ret) {
+ dev_err(lp->dev, "led register err: %d\n", ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int __devexit lp8788_led_remove(struct platform_device *pdev)
+{
+ struct lp8788_led *led = platform_get_drvdata(pdev);
+
+ led_classdev_unregister(&led->led_dev);
+ flush_work_sync(&led->work);
+
+ return 0;
+}
+
+static struct platform_driver lp8788_led_driver = {
+ .probe = lp8788_led_probe,
+ .remove = __devexit_p(lp8788_led_remove),
+ .driver = {
+ .name = LP8788_DEV_KEYLED,
+ .owner = THIS_MODULE,
+ },
+};
+module_platform_driver(lp8788_led_driver);
+
+MODULE_DESCRIPTION("Texas Instruments LP8788 Keyboard LED Driver");
+MODULE_AUTHOR("Milo Kim");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:lp8788-keyled");
diff --git a/drivers/leds/leds-lt3593.c b/drivers/leds/leds-lt3593.c
index e311a96c4469..09a732217f6d 100644
--- a/drivers/leds/leds-lt3593.c
+++ b/drivers/leds/leds-lt3593.c
@@ -149,8 +149,9 @@ static int __devinit lt3593_led_probe(struct platform_device *pdev)
if (!pdata)
return -EBUSY;
- leds_data = kzalloc(sizeof(struct lt3593_led_data) * pdata->num_leds,
- GFP_KERNEL);
+ leds_data = devm_kzalloc(&pdev->dev,
+ sizeof(struct lt3593_led_data) * pdata->num_leds,
+ GFP_KERNEL);
if (!leds_data)
return -ENOMEM;
@@ -169,8 +170,6 @@ err:
for (i = i - 1; i >= 0; i--)
delete_lt3593_led(&leds_data[i]);
- kfree(leds_data);
-
return ret;
}
@@ -185,8 +184,6 @@ static int __devexit lt3593_led_remove(struct platform_device *pdev)
for (i = 0; i < pdata->num_leds; i++)
delete_lt3593_led(&leds_data[i]);
- kfree(leds_data);
-
return 0;
}
diff --git a/drivers/leds/leds-max8997.c b/drivers/leds/leds-max8997.c
index f4c0e37fad1e..569e36de37df 100644
--- a/drivers/leds/leds-max8997.c
+++ b/drivers/leds/leds-max8997.c
@@ -49,71 +49,37 @@ struct max8997_led {
struct mutex mutex;
};
-static void max8997_led_clear_mode(struct max8997_led *led,
- enum max8997_led_mode mode)
-{
- struct i2c_client *client = led->iodev->i2c;
- u8 val = 0, mask = 0;
- int ret;
-
- switch (mode) {
- case MAX8997_FLASH_MODE:
- mask = led->id ?
- MAX8997_LED1_FLASH_MASK : MAX8997_LED0_FLASH_MASK;
- break;
- case MAX8997_MOVIE_MODE:
- mask = led->id ?
- MAX8997_LED1_MOVIE_MASK : MAX8997_LED0_MOVIE_MASK;
- break;
- case MAX8997_FLASH_PIN_CONTROL_MODE:
- mask = led->id ?
- MAX8997_LED1_FLASH_PIN_MASK : MAX8997_LED0_FLASH_PIN_MASK;
- break;
- case MAX8997_MOVIE_PIN_CONTROL_MODE:
- mask = led->id ?
- MAX8997_LED1_MOVIE_PIN_MASK : MAX8997_LED0_MOVIE_PIN_MASK;
- break;
- default:
- break;
- }
-
- if (mask) {
- ret = max8997_update_reg(client,
- MAX8997_REG_LEN_CNTL, val, mask);
- if (ret)
- dev_err(led->iodev->dev,
- "failed to update register(%d)\n", ret);
- }
-}
-
static void max8997_led_set_mode(struct max8997_led *led,
enum max8997_led_mode mode)
{
int ret;
struct i2c_client *client = led->iodev->i2c;
- u8 mask = 0;
-
- /* First, clear the previous mode */
- max8997_led_clear_mode(led, led->led_mode);
+ u8 mask = 0, val;
switch (mode) {
case MAX8997_FLASH_MODE:
- mask = led->id ?
+ mask = MAX8997_LED1_FLASH_MASK | MAX8997_LED0_FLASH_MASK;
+ val = led->id ?
MAX8997_LED1_FLASH_MASK : MAX8997_LED0_FLASH_MASK;
led->cdev.max_brightness = MAX8997_LED_FLASH_MAX_BRIGHTNESS;
break;
case MAX8997_MOVIE_MODE:
- mask = led->id ?
+ mask = MAX8997_LED1_MOVIE_MASK | MAX8997_LED0_MOVIE_MASK;
+ val = led->id ?
MAX8997_LED1_MOVIE_MASK : MAX8997_LED0_MOVIE_MASK;
led->cdev.max_brightness = MAX8997_LED_MOVIE_MAX_BRIGHTNESS;
break;
case MAX8997_FLASH_PIN_CONTROL_MODE:
- mask = led->id ?
+ mask = MAX8997_LED1_FLASH_PIN_MASK |
+ MAX8997_LED0_FLASH_PIN_MASK;
+ val = led->id ?
MAX8997_LED1_FLASH_PIN_MASK : MAX8997_LED0_FLASH_PIN_MASK;
led->cdev.max_brightness = MAX8997_LED_FLASH_MAX_BRIGHTNESS;
break;
case MAX8997_MOVIE_PIN_CONTROL_MODE:
- mask = led->id ?
+ mask = MAX8997_LED1_MOVIE_PIN_MASK |
+ MAX8997_LED0_MOVIE_PIN_MASK;
+ val = led->id ?
MAX8997_LED1_MOVIE_PIN_MASK : MAX8997_LED0_MOVIE_PIN_MASK;
led->cdev.max_brightness = MAX8997_LED_MOVIE_MAX_BRIGHTNESS;
break;
@@ -123,8 +89,8 @@ static void max8997_led_set_mode(struct max8997_led *led,
}
if (mask) {
- ret = max8997_update_reg(client,
- MAX8997_REG_LEN_CNTL, mask, mask);
+ ret = max8997_update_reg(client, MAX8997_REG_LEN_CNTL, val,
+ mask);
if (ret)
dev_err(led->iodev->dev,
"failed to update register(%d)\n", ret);
@@ -276,11 +242,9 @@ static int __devinit max8997_led_probe(struct platform_device *pdev)
return -ENODEV;
}
- led = kzalloc(sizeof(*led), GFP_KERNEL);
- if (led == NULL) {
- ret = -ENOMEM;
- goto err_mem;
- }
+ led = devm_kzalloc(&pdev->dev, sizeof(*led), GFP_KERNEL);
+ if (led == NULL)
+ return -ENOMEM;
led->id = pdev->id;
snprintf(name, sizeof(name), "max8997-led%d", pdev->id);
@@ -315,23 +279,17 @@ static int __devinit max8997_led_probe(struct platform_device *pdev)
ret = led_classdev_register(&pdev->dev, &led->cdev);
if (ret < 0)
- goto err_led;
+ 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);
- goto err_file;
+ led_classdev_unregister(&led->cdev);
+ return ret;
}
return 0;
-
-err_file:
- led_classdev_unregister(&led->cdev);
-err_led:
- kfree(led);
-err_mem:
- return ret;
}
static int __devexit max8997_led_remove(struct platform_device *pdev)
@@ -340,7 +298,6 @@ static int __devexit max8997_led_remove(struct platform_device *pdev)
device_remove_file(led->cdev.dev, &dev_attr_mode);
led_classdev_unregister(&led->cdev);
- kfree(led);
return 0;
}
@@ -354,17 +311,7 @@ static struct platform_driver max8997_led_driver = {
.remove = __devexit_p(max8997_led_remove),
};
-static int __init max8997_led_init(void)
-{
- return platform_driver_register(&max8997_led_driver);
-}
-module_init(max8997_led_init);
-
-static void __exit max8997_led_exit(void)
-{
- platform_driver_unregister(&max8997_led_driver);
-}
-module_exit(max8997_led_exit);
+module_platform_driver(max8997_led_driver);
MODULE_AUTHOR("Donggeun Kim <dg77.kim@samsung.com>");
MODULE_DESCRIPTION("MAX8997 LED driver");
diff --git a/drivers/leds/leds-mc13783.c b/drivers/leds/leds-mc13783.c
index 4cc6a2e3df34..2a5d43400677 100644
--- a/drivers/leds/leds-mc13783.c
+++ b/drivers/leds/leds-mc13783.c
@@ -280,7 +280,8 @@ static int __devinit mc13783_led_probe(struct platform_device *pdev)
return -EINVAL;
}
- led = kcalloc(pdata->num_leds, sizeof(*led), GFP_KERNEL);
+ led = devm_kzalloc(&pdev->dev, pdata->num_leds * sizeof(*led),
+ GFP_KERNEL);
if (led == NULL) {
dev_err(&pdev->dev, "failed to alloc memory\n");
return -ENOMEM;
@@ -289,7 +290,7 @@ static int __devinit mc13783_led_probe(struct platform_device *pdev)
ret = mc13783_leds_prepare(pdev);
if (ret) {
dev_err(&pdev->dev, "unable to init led driver\n");
- goto err_free;
+ return ret;
}
for (i = 0; i < pdata->num_leds; i++) {
@@ -344,8 +345,6 @@ err_register:
cancel_work_sync(&led[i].work);
}
-err_free:
- kfree(led);
return ret;
}
@@ -372,7 +371,7 @@ static int __devexit mc13783_led_remove(struct platform_device *pdev)
mc13xxx_unlock(dev);
- kfree(led);
+ platform_set_drvdata(pdev, NULL);
return 0;
}
diff --git a/drivers/leds/leds-netxbig.c b/drivers/leds/leds-netxbig.c
index 73973fdbd8be..e37618e363cf 100644
--- a/drivers/leds/leds-netxbig.c
+++ b/drivers/leds/leds-netxbig.c
@@ -362,14 +362,14 @@ static int __devinit netxbig_led_probe(struct platform_device *pdev)
if (!pdata)
return -EINVAL;
- leds_data = kzalloc(sizeof(struct netxbig_led_data) * pdata->num_leds,
- GFP_KERNEL);
+ leds_data = devm_kzalloc(&pdev->dev,
+ sizeof(struct netxbig_led_data) * pdata->num_leds, GFP_KERNEL);
if (!leds_data)
return -ENOMEM;
ret = gpio_ext_init(pdata->gpio_ext);
if (ret < 0)
- goto err_free_data;
+ return ret;
for (i = 0; i < pdata->num_leds; i++) {
ret = create_netxbig_led(pdev, &leds_data[i], &pdata->leds[i]);
@@ -386,9 +386,6 @@ err_free_leds:
delete_netxbig_led(&leds_data[i]);
gpio_ext_free(pdata->gpio_ext);
-err_free_data:
- kfree(leds_data);
-
return ret;
}
@@ -404,7 +401,6 @@ static int __devexit netxbig_led_remove(struct platform_device *pdev)
delete_netxbig_led(&leds_data[i]);
gpio_ext_free(pdata->gpio_ext);
- kfree(leds_data);
return 0;
}
diff --git a/drivers/leds/leds-ns2.c b/drivers/leds/leds-ns2.c
index 01cf89ec6944..10528dafb043 100644
--- a/drivers/leds/leds-ns2.c
+++ b/drivers/leds/leds-ns2.c
@@ -273,29 +273,23 @@ static int __devinit ns2_led_probe(struct platform_device *pdev)
if (!pdata)
return -EINVAL;
- leds_data = kzalloc(sizeof(struct ns2_led_data) *
+ leds_data = devm_kzalloc(&pdev->dev, sizeof(struct ns2_led_data) *
pdata->num_leds, GFP_KERNEL);
if (!leds_data)
return -ENOMEM;
for (i = 0; i < pdata->num_leds; i++) {
ret = create_ns2_led(pdev, &leds_data[i], &pdata->leds[i]);
- if (ret < 0)
- goto err;
-
+ if (ret < 0) {
+ for (i = i - 1; i >= 0; i--)
+ delete_ns2_led(&leds_data[i]);
+ return ret;
+ }
}
platform_set_drvdata(pdev, leds_data);
return 0;
-
-err:
- for (i = i - 1; i >= 0; i--)
- delete_ns2_led(&leds_data[i]);
-
- kfree(leds_data);
-
- return ret;
}
static int __devexit ns2_led_remove(struct platform_device *pdev)
@@ -309,7 +303,6 @@ static int __devexit ns2_led_remove(struct platform_device *pdev)
for (i = 0; i < pdata->num_leds; i++)
delete_ns2_led(&leds_data[i]);
- kfree(leds_data);
platform_set_drvdata(pdev, NULL);
return 0;
diff --git a/drivers/leds/leds-pca9532.c b/drivers/leds/leds-pca9532.c
index ceccab44b5b8..cee8a5b483ac 100644
--- a/drivers/leds/leds-pca9532.c
+++ b/drivers/leds/leds-pca9532.c
@@ -449,7 +449,6 @@ static int pca9532_probe(struct i2c_client *client,
{
struct pca9532_data *data = i2c_get_clientdata(client);
struct pca9532_platform_data *pca9532_pdata = client->dev.platform_data;
- int err;
if (!pca9532_pdata)
return -EIO;
@@ -458,7 +457,7 @@ static int pca9532_probe(struct i2c_client *client,
I2C_FUNC_SMBUS_BYTE_DATA))
return -EIO;
- data = kzalloc(sizeof(*data), GFP_KERNEL);
+ data = devm_kzalloc(&client->dev, sizeof(*data), GFP_KERNEL);
if (!data)
return -ENOMEM;
@@ -469,11 +468,7 @@ static int pca9532_probe(struct i2c_client *client,
data->client = client;
mutex_init(&data->update_lock);
- err = pca9532_configure(client, data, pca9532_pdata);
- if (err)
- kfree(data);
-
- return err;
+ return pca9532_configure(client, data, pca9532_pdata);
}
static int pca9532_remove(struct i2c_client *client)
@@ -485,7 +480,6 @@ static int pca9532_remove(struct i2c_client *client)
if (err)
return err;
- kfree(data);
return 0;
}
diff --git a/drivers/leds/leds-pca955x.c b/drivers/leds/leds-pca955x.c
index 5f462dbf0dbb..aef3cf0432fe 100644
--- a/drivers/leds/leds-pca955x.c
+++ b/drivers/leds/leds-pca955x.c
@@ -293,15 +293,14 @@ static int __devinit pca955x_probe(struct i2c_client *client,
}
}
- pca955x = kzalloc(sizeof(*pca955x), GFP_KERNEL);
+ pca955x = devm_kzalloc(&client->dev, sizeof(*pca955x), GFP_KERNEL);
if (!pca955x)
return -ENOMEM;
- pca955x->leds = kzalloc(sizeof(*pca955x_led) * chip->bits, GFP_KERNEL);
- if (!pca955x->leds) {
- err = -ENOMEM;
- goto exit_nomem;
- }
+ pca955x->leds = devm_kzalloc(&client->dev,
+ sizeof(*pca955x_led) * chip->bits, GFP_KERNEL);
+ if (!pca955x->leds)
+ return -ENOMEM;
i2c_set_clientdata(client, pca955x);
@@ -361,10 +360,6 @@ exit:
cancel_work_sync(&pca955x->leds[i].work);
}
- kfree(pca955x->leds);
-exit_nomem:
- kfree(pca955x);
-
return err;
}
@@ -378,9 +373,6 @@ static int __devexit pca955x_remove(struct i2c_client *client)
cancel_work_sync(&pca955x->leds[i].work);
}
- kfree(pca955x->leds);
- kfree(pca955x);
-
return 0;
}
diff --git a/drivers/leds/leds-pca9633.c b/drivers/leds/leds-pca9633.c
index d8926fd031aa..edcd706c5631 100644
--- a/drivers/leds/leds-pca9633.c
+++ b/drivers/leds/leds-pca9633.c
@@ -108,7 +108,7 @@ static int __devinit pca9633_probe(struct i2c_client *client,
}
}
- pca9633 = kcalloc(4, sizeof(*pca9633), GFP_KERNEL);
+ pca9633 = devm_kzalloc(&client->dev, 4 * sizeof(*pca9633), GFP_KERNEL);
if (!pca9633)
return -ENOMEM;
@@ -156,8 +156,6 @@ exit:
cancel_work_sync(&pca9633[i].work);
}
- kfree(pca9633);
-
return err;
}
@@ -171,8 +169,6 @@ static int __devexit pca9633_remove(struct i2c_client *client)
cancel_work_sync(&pca9633[i].work);
}
- kfree(pca9633);
-
return 0;
}
diff --git a/drivers/leds/leds-pwm.c b/drivers/leds/leds-pwm.c
index 3ed92f34bd44..f2e44c719437 100644
--- a/drivers/leds/leds-pwm.c
+++ b/drivers/leds/leds-pwm.c
@@ -57,7 +57,8 @@ static int led_pwm_probe(struct platform_device *pdev)
if (!pdata)
return -EBUSY;
- leds_data = kzalloc(sizeof(struct led_pwm_data) * pdata->num_leds,
+ leds_data = devm_kzalloc(&pdev->dev,
+ sizeof(struct led_pwm_data) * pdata->num_leds,
GFP_KERNEL);
if (!leds_data)
return -ENOMEM;
@@ -103,8 +104,6 @@ err:
}
}
- kfree(leds_data);
-
return ret;
}
@@ -121,8 +120,6 @@ static int __devexit led_pwm_remove(struct platform_device *pdev)
pwm_free(leds_data[i].pwm);
}
- kfree(leds_data);
-
return 0;
}
diff --git a/drivers/leds/leds-regulator.c b/drivers/leds/leds-regulator.c
index df7e963bddd3..25d382d60fa9 100644
--- a/drivers/leds/leds-regulator.c
+++ b/drivers/leds/leds-regulator.c
@@ -158,7 +158,7 @@ static int __devinit regulator_led_probe(struct platform_device *pdev)
return PTR_ERR(vcc);
}
- led = kzalloc(sizeof(*led), GFP_KERNEL);
+ led = devm_kzalloc(&pdev->dev, sizeof(*led), GFP_KERNEL);
if (led == NULL) {
ret = -ENOMEM;
goto err_vcc;
@@ -169,7 +169,7 @@ static int __devinit regulator_led_probe(struct platform_device *pdev)
dev_err(&pdev->dev, "Invalid default brightness %d\n",
pdata->brightness);
ret = -EINVAL;
- goto err_led;
+ goto err_vcc;
}
led->value = pdata->brightness;
@@ -190,7 +190,7 @@ static int __devinit regulator_led_probe(struct platform_device *pdev)
ret = led_classdev_register(&pdev->dev, &led->cdev);
if (ret < 0) {
cancel_work_sync(&led->work);
- goto err_led;
+ goto err_vcc;
}
/* to expose the default value to userspace */
@@ -201,8 +201,6 @@ static int __devinit regulator_led_probe(struct platform_device *pdev)
return 0;
-err_led:
- kfree(led);
err_vcc:
regulator_put(vcc);
return ret;
@@ -216,7 +214,6 @@ static int __devexit regulator_led_remove(struct platform_device *pdev)
cancel_work_sync(&led->work);
regulator_led_disable(led);
regulator_put(led->vcc);
- kfree(led);
return 0;
}
diff --git a/drivers/leds/leds-renesas-tpu.c b/drivers/leds/leds-renesas-tpu.c
index 32fe337d5c68..9ee12c28059a 100644
--- a/drivers/leds/leds-renesas-tpu.c
+++ b/drivers/leds/leds-renesas-tpu.c
@@ -243,31 +243,30 @@ static int __devinit r_tpu_probe(struct platform_device *pdev)
struct led_renesas_tpu_config *cfg = pdev->dev.platform_data;
struct r_tpu_priv *p;
struct resource *res;
- int ret = -ENXIO;
+ int ret;
if (!cfg) {
dev_err(&pdev->dev, "missing platform data\n");
goto err0;
}
- p = kzalloc(sizeof(*p), GFP_KERNEL);
+ p = devm_kzalloc(&pdev->dev, sizeof(*p), GFP_KERNEL);
if (p == NULL) {
dev_err(&pdev->dev, "failed to allocate driver data\n");
- ret = -ENOMEM;
- goto err0;
+ return -ENOMEM;
}
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res) {
dev_err(&pdev->dev, "failed to get I/O memory\n");
- goto err1;
+ return -ENXIO;
}
/* map memory, let mapbase point to our channel */
p->mapbase = ioremap_nocache(res->start, resource_size(res));
if (p->mapbase == NULL) {
dev_err(&pdev->dev, "failed to remap I/O memory\n");
- goto err1;
+ return -ENXIO;
}
/* get hold of clock */
@@ -275,7 +274,7 @@ static int __devinit r_tpu_probe(struct platform_device *pdev)
if (IS_ERR(p->clk)) {
dev_err(&pdev->dev, "cannot get clock\n");
ret = PTR_ERR(p->clk);
- goto err2;
+ goto err0;
}
p->pdev = pdev;
@@ -294,7 +293,7 @@ static int __devinit r_tpu_probe(struct platform_device *pdev)
p->ldev.flags |= LED_CORE_SUSPENDRESUME;
ret = led_classdev_register(&pdev->dev, &p->ldev);
if (ret < 0)
- goto err3;
+ goto err1;
/* max_brightness may be updated by the LED core code */
p->min_rate = p->ldev.max_brightness * p->refresh_rate;
@@ -302,14 +301,11 @@ static int __devinit r_tpu_probe(struct platform_device *pdev)
pm_runtime_enable(&pdev->dev);
return 0;
- err3:
+ err1:
r_tpu_set_pin(p, R_TPU_PIN_UNUSED, LED_OFF);
clk_put(p->clk);
- err2:
- iounmap(p->mapbase);
- err1:
- kfree(p);
err0:
+ iounmap(p->mapbase);
return ret;
}
@@ -327,7 +323,6 @@ static int __devexit r_tpu_remove(struct platform_device *pdev)
clk_put(p->clk);
iounmap(p->mapbase);
- kfree(p);
return 0;
}
diff --git a/drivers/leds/leds-s3c24xx.c b/drivers/leds/leds-s3c24xx.c
index bd0a5ed49c42..942f0ea18178 100644
--- a/drivers/leds/leds-s3c24xx.c
+++ b/drivers/leds/leds-s3c24xx.c
@@ -45,17 +45,19 @@ static void s3c24xx_led_set(struct led_classdev *led_cdev,
{
struct s3c24xx_gpio_led *led = to_gpio(led_cdev);
struct s3c24xx_led_platdata *pd = led->pdata;
+ int state = (value ? 1 : 0) ^ (pd->flags & S3C24XX_LEDF_ACTLOW);
/* there will be a short delay between setting the output and
* going from output to input when using tristate. */
- s3c2410_gpio_setpin(pd->gpio, (value ? 1 : 0) ^
- (pd->flags & S3C24XX_LEDF_ACTLOW));
-
- if (pd->flags & S3C24XX_LEDF_TRISTATE)
- s3c2410_gpio_cfgpin(pd->gpio,
- value ? S3C2410_GPIO_OUTPUT : S3C2410_GPIO_INPUT);
+ gpio_set_value(pd->gpio, state);
+ if (pd->flags & S3C24XX_LEDF_TRISTATE) {
+ if (value)
+ gpio_direction_output(pd->gpio, state);
+ else
+ gpio_direction_input(pd->gpio);
+ }
}
static int s3c24xx_led_remove(struct platform_device *dev)
@@ -63,7 +65,6 @@ static int s3c24xx_led_remove(struct platform_device *dev)
struct s3c24xx_gpio_led *led = pdev_to_gpio(dev);
led_classdev_unregister(&led->cdev);
- kfree(led);
return 0;
}
@@ -74,7 +75,8 @@ static int s3c24xx_led_probe(struct platform_device *dev)
struct s3c24xx_gpio_led *led;
int ret;
- led = kzalloc(sizeof(struct s3c24xx_gpio_led), GFP_KERNEL);
+ led = devm_kzalloc(&dev->dev, sizeof(struct s3c24xx_gpio_led),
+ GFP_KERNEL);
if (led == NULL) {
dev_err(&dev->dev, "No memory for device\n");
return -ENOMEM;
@@ -89,27 +91,27 @@ static int s3c24xx_led_probe(struct platform_device *dev)
led->pdata = pdata;
+ ret = devm_gpio_request(&dev->dev, pdata->gpio, "S3C24XX_LED");
+ if (ret < 0)
+ return ret;
+
/* no point in having a pull-up if we are always driving */
- if (pdata->flags & S3C24XX_LEDF_TRISTATE) {
- s3c2410_gpio_setpin(pdata->gpio, 0);
- s3c2410_gpio_cfgpin(pdata->gpio, S3C2410_GPIO_INPUT);
- } else {
- s3c2410_gpio_pullup(pdata->gpio, 0);
- s3c2410_gpio_setpin(pdata->gpio, 0);
- s3c2410_gpio_cfgpin(pdata->gpio, S3C2410_GPIO_OUTPUT);
- }
+ s3c_gpio_setpull(pdata->gpio, S3C_GPIO_PULL_NONE);
+
+ if (pdata->flags & S3C24XX_LEDF_TRISTATE)
+ gpio_direction_input(pdata->gpio);
+ else
+ gpio_direction_output(pdata->gpio,
+ pdata->flags & S3C24XX_LEDF_ACTLOW ? 1 : 0);
/* register our new led device */
ret = led_classdev_register(&dev->dev, &led->cdev);
- if (ret < 0) {
+ if (ret < 0)
dev_err(&dev->dev, "led_classdev_register failed\n");
- kfree(led);
- return ret;
- }
- return 0;
+ return ret;
}
static struct platform_driver s3c24xx_led_driver = {
diff --git a/drivers/leds/leds-sunfire.c b/drivers/leds/leds-sunfire.c
index 1757396b20b3..134d9a4b34f1 100644
--- a/drivers/leds/leds-sunfire.c
+++ b/drivers/leds/leds-sunfire.c
@@ -132,15 +132,13 @@ static int __devinit sunfire_led_generic_probe(struct platform_device *pdev,
if (pdev->num_resources != 1) {
printk(KERN_ERR PFX "Wrong number of resources %d, should be 1\n",
pdev->num_resources);
- err = -EINVAL;
- goto out;
+ return -EINVAL;
}
- p = kzalloc(sizeof(*p), GFP_KERNEL);
+ p = devm_kzalloc(&pdev->dev, sizeof(*p), GFP_KERNEL);
if (!p) {
printk(KERN_ERR PFX "Could not allocate struct sunfire_drvdata\n");
- err = -ENOMEM;
- goto out;
+ return -ENOMEM;
}
for (i = 0; i < NUM_LEDS_PER_BOARD; i++) {
@@ -156,20 +154,15 @@ static int __devinit sunfire_led_generic_probe(struct platform_device *pdev,
if (err) {
printk(KERN_ERR PFX "Could not register %s LED\n",
lp->name);
- goto out_unregister_led_cdevs;
+ for (i--; i >= 0; i--)
+ led_classdev_unregister(&p->leds[i].led_cdev);
+ return err;
}
}
dev_set_drvdata(&pdev->dev, p);
return 0;
-
-out_unregister_led_cdevs:
- for (i--; i >= 0; i--)
- led_classdev_unregister(&p->leds[i].led_cdev);
- kfree(p);
-out:
- return err;
}
static int __devexit sunfire_led_generic_remove(struct platform_device *pdev)
@@ -180,8 +173,6 @@ static int __devexit sunfire_led_generic_remove(struct platform_device *pdev)
for (i = 0; i < NUM_LEDS_PER_BOARD; i++)
led_classdev_unregister(&p->leds[i].led_cdev);
- kfree(p);
-
return 0;
}
diff --git a/drivers/leds/leds-tca6507.c b/drivers/leds/leds-tca6507.c
index 6c1c14f31635..dabcf7ae8d0f 100644
--- a/drivers/leds/leds-tca6507.c
+++ b/drivers/leds/leds-tca6507.c
@@ -687,7 +687,7 @@ static int __devinit tca6507_probe(struct i2c_client *client,
NUM_LEDS);
return -ENODEV;
}
- tca = kzalloc(sizeof(*tca), GFP_KERNEL);
+ tca = devm_kzalloc(&client->dev, sizeof(*tca), GFP_KERNEL);
if (!tca)
return -ENOMEM;
@@ -727,7 +727,6 @@ exit:
if (tca->leds[i].led_cdev.name)
led_classdev_unregister(&tca->leds[i].led_cdev);
}
- kfree(tca);
return err;
}
@@ -743,7 +742,6 @@ static int __devexit tca6507_remove(struct i2c_client *client)
}
tca6507_remove_gpio(tca);
cancel_work_sync(&tca->work);
- kfree(tca);
return 0;
}
@@ -758,18 +756,7 @@ static struct i2c_driver tca6507_driver = {
.id_table = tca6507_id,
};
-static int __init tca6507_leds_init(void)
-{
- return i2c_add_driver(&tca6507_driver);
-}
-
-static void __exit tca6507_leds_exit(void)
-{
- i2c_del_driver(&tca6507_driver);
-}
-
-module_init(tca6507_leds_init);
-module_exit(tca6507_leds_exit);
+module_i2c_driver(tca6507_driver);
MODULE_AUTHOR("NeilBrown <neilb@suse.de>");
MODULE_DESCRIPTION("TCA6507 LED/GPO driver");
diff --git a/drivers/leds/leds.h b/drivers/leds/leds.h
index e77c7f8dcdd4..d02acd496126 100644
--- a/drivers/leds/leds.h
+++ b/drivers/leds/leds.h
@@ -17,7 +17,7 @@
#include <linux/rwsem.h>
#include <linux/leds.h>
-static inline void led_set_brightness(struct led_classdev *led_cdev,
+static inline void __led_set_brightness(struct led_classdev *led_cdev,
enum led_brightness value)
{
if (value > led_cdev->max_brightness)
diff --git a/drivers/leds/ledtrig-backlight.c b/drivers/leds/ledtrig-backlight.c
index e2726867c5d4..b941685f2227 100644
--- a/drivers/leds/ledtrig-backlight.c
+++ b/drivers/leds/ledtrig-backlight.c
@@ -46,9 +46,9 @@ static int fb_notifier_callback(struct notifier_block *p,
if ((n->old_status == UNBLANK) ^ n->invert) {
n->brightness = led->brightness;
- led_set_brightness(led, LED_OFF);
+ __led_set_brightness(led, LED_OFF);
} else {
- led_set_brightness(led, n->brightness);
+ __led_set_brightness(led, n->brightness);
}
n->old_status = new_status;
@@ -87,9 +87,9 @@ static ssize_t bl_trig_invert_store(struct device *dev,
/* After inverting, we need to update the LED. */
if ((n->old_status == BLANK) ^ n->invert)
- led_set_brightness(led, LED_OFF);
+ __led_set_brightness(led, LED_OFF);
else
- led_set_brightness(led, n->brightness);
+ __led_set_brightness(led, n->brightness);
return num;
}
diff --git a/drivers/leds/ledtrig-default-on.c b/drivers/leds/ledtrig-default-on.c
index a4ef54b9d508..eac1f1b1adac 100644
--- a/drivers/leds/ledtrig-default-on.c
+++ b/drivers/leds/ledtrig-default-on.c
@@ -19,7 +19,7 @@
static void defon_trig_activate(struct led_classdev *led_cdev)
{
- led_set_brightness(led_cdev, led_cdev->max_brightness);
+ __led_set_brightness(led_cdev, led_cdev->max_brightness);
}
static struct led_trigger defon_led_trigger = {
diff --git a/drivers/leds/ledtrig-gpio.c b/drivers/leds/ledtrig-gpio.c
index f057c101b896..ba215dc42f98 100644
--- a/drivers/leds/ledtrig-gpio.c
+++ b/drivers/leds/ledtrig-gpio.c
@@ -54,12 +54,12 @@ static void gpio_trig_work(struct work_struct *work)
if (tmp) {
if (gpio_data->desired_brightness)
- led_set_brightness(gpio_data->led,
+ __led_set_brightness(gpio_data->led,
gpio_data->desired_brightness);
else
- led_set_brightness(gpio_data->led, LED_FULL);
+ __led_set_brightness(gpio_data->led, LED_FULL);
} else {
- led_set_brightness(gpio_data->led, LED_OFF);
+ __led_set_brightness(gpio_data->led, LED_OFF);
}
}
diff --git a/drivers/leds/ledtrig-heartbeat.c b/drivers/leds/ledtrig-heartbeat.c
index a019fbb70880..1edc7463ce83 100644
--- a/drivers/leds/ledtrig-heartbeat.c
+++ b/drivers/leds/ledtrig-heartbeat.c
@@ -74,7 +74,7 @@ static void led_heartbeat_function(unsigned long data)
break;
}
- led_set_brightness(led_cdev, brightness);
+ __led_set_brightness(led_cdev, brightness);
mod_timer(&heartbeat_data->timer, jiffies + delay);
}
diff --git a/drivers/leds/ledtrig-ide-disk.c b/drivers/leds/ledtrig-ide-disk.c
index ec099fcbcb00..2cd7c0cf5924 100644
--- a/drivers/leds/ledtrig-ide-disk.c
+++ b/drivers/leds/ledtrig-ide-disk.c
@@ -12,39 +12,22 @@
*/
#include <linux/module.h>
-#include <linux/jiffies.h>
#include <linux/kernel.h>
#include <linux/init.h>
-#include <linux/timer.h>
#include <linux/leds.h>
-static void ledtrig_ide_timerfunc(unsigned long data);
+#define BLINK_DELAY 30
DEFINE_LED_TRIGGER(ledtrig_ide);
-static DEFINE_TIMER(ledtrig_ide_timer, ledtrig_ide_timerfunc, 0, 0);
-static int ide_activity;
-static int ide_lastactivity;
+static unsigned long ide_blink_delay = BLINK_DELAY;
void ledtrig_ide_activity(void)
{
- ide_activity++;
- if (!timer_pending(&ledtrig_ide_timer))
- mod_timer(&ledtrig_ide_timer, jiffies + msecs_to_jiffies(10));
+ led_trigger_blink_oneshot(ledtrig_ide,
+ &ide_blink_delay, &ide_blink_delay, 0);
}
EXPORT_SYMBOL(ledtrig_ide_activity);
-static void ledtrig_ide_timerfunc(unsigned long data)
-{
- if (ide_lastactivity != ide_activity) {
- ide_lastactivity = ide_activity;
- /* INT_MAX will set each LED to its maximum brightness */
- led_trigger_event(ledtrig_ide, INT_MAX);
- mod_timer(&ledtrig_ide_timer, jiffies + msecs_to_jiffies(10));
- } else {
- led_trigger_event(ledtrig_ide, LED_OFF);
- }
-}
-
static int __init ledtrig_ide_init(void)
{
led_trigger_register_simple("ide-disk", &ledtrig_ide);
diff --git a/drivers/leds/ledtrig-oneshot.c b/drivers/leds/ledtrig-oneshot.c
new file mode 100644
index 000000000000..2c029aa5c4f1
--- /dev/null
+++ b/drivers/leds/ledtrig-oneshot.c
@@ -0,0 +1,204 @@
+/*
+ * One-shot LED Trigger
+ *
+ * Copyright 2012, Fabio Baltieri <fabio.baltieri@gmail.com>
+ *
+ * Based on ledtrig-timer.c by Richard Purdie <rpurdie@openedhand.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/ctype.h>
+#include <linux/slab.h>
+#include <linux/leds.h>
+#include "leds.h"
+
+#define DEFAULT_DELAY 100
+
+struct oneshot_trig_data {
+ unsigned int invert;
+};
+
+static ssize_t led_shot(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t size)
+{
+ struct led_classdev *led_cdev = dev_get_drvdata(dev);
+ struct oneshot_trig_data *oneshot_data = led_cdev->trigger_data;
+
+ led_blink_set_oneshot(led_cdev,
+ &led_cdev->blink_delay_on, &led_cdev->blink_delay_off,
+ oneshot_data->invert);
+
+ /* content is ignored */
+ return size;
+}
+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 oneshot_trig_data *oneshot_data = led_cdev->trigger_data;
+
+ return sprintf(buf, "%u\n", oneshot_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 oneshot_trig_data *oneshot_data = led_cdev->trigger_data;
+ unsigned long state;
+ int ret;
+
+ ret = kstrtoul(buf, 0, &state);
+ if (ret)
+ return ret;
+
+ oneshot_data->invert = !!state;
+
+ if (oneshot_data->invert)
+ __led_set_brightness(led_cdev, LED_FULL);
+ else
+ __led_set_brightness(led_cdev, LED_OFF);
+
+ return size;
+}
+
+static ssize_t led_delay_on_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct led_classdev *led_cdev = dev_get_drvdata(dev);
+
+ return sprintf(buf, "%lu\n", led_cdev->blink_delay_on);
+}
+
+static ssize_t led_delay_on_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t size)
+{
+ struct led_classdev *led_cdev = dev_get_drvdata(dev);
+ unsigned long state;
+ int ret;
+
+ ret = kstrtoul(buf, 0, &state);
+ if (ret)
+ return ret;
+
+ led_cdev->blink_delay_on = state;
+
+ return size;
+}
+static ssize_t led_delay_off_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct led_classdev *led_cdev = dev_get_drvdata(dev);
+
+ return sprintf(buf, "%lu\n", led_cdev->blink_delay_off);
+}
+
+static ssize_t led_delay_off_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t size)
+{
+ struct led_classdev *led_cdev = dev_get_drvdata(dev);
+ unsigned long state;
+ int ret;
+
+ ret = kstrtoul(buf, 0, &state);
+ if (ret)
+ return ret;
+
+ led_cdev->blink_delay_off = state;
+
+ return size;
+}
+
+static DEVICE_ATTR(delay_on, 0644, led_delay_on_show, led_delay_on_store);
+static DEVICE_ATTR(delay_off, 0644, led_delay_off_show, led_delay_off_store);
+static DEVICE_ATTR(invert, 0644, led_invert_show, led_invert_store);
+static DEVICE_ATTR(shot, 0200, NULL, led_shot);
+
+static void oneshot_trig_activate(struct led_classdev *led_cdev)
+{
+ struct oneshot_trig_data *oneshot_data;
+ int rc;
+
+ oneshot_data = kzalloc(sizeof(*oneshot_data), GFP_KERNEL);
+ if (!oneshot_data)
+ return;
+
+ led_cdev->trigger_data = oneshot_data;
+
+ rc = device_create_file(led_cdev->dev, &dev_attr_delay_on);
+ if (rc)
+ goto err_out_trig_data;
+ rc = device_create_file(led_cdev->dev, &dev_attr_delay_off);
+ if (rc)
+ goto err_out_delayon;
+ rc = device_create_file(led_cdev->dev, &dev_attr_invert);
+ if (rc)
+ goto err_out_delayoff;
+ rc = device_create_file(led_cdev->dev, &dev_attr_shot);
+ if (rc)
+ goto err_out_invert;
+
+ led_cdev->blink_delay_on = DEFAULT_DELAY;
+ led_cdev->blink_delay_off = DEFAULT_DELAY;
+
+ led_cdev->activated = true;
+
+ return;
+
+err_out_invert:
+ device_remove_file(led_cdev->dev, &dev_attr_invert);
+err_out_delayoff:
+ device_remove_file(led_cdev->dev, &dev_attr_delay_off);
+err_out_delayon:
+ device_remove_file(led_cdev->dev, &dev_attr_delay_on);
+err_out_trig_data:
+ kfree(led_cdev->trigger_data);
+}
+
+static void oneshot_trig_deactivate(struct led_classdev *led_cdev)
+{
+ struct oneshot_trig_data *oneshot_data = led_cdev->trigger_data;
+
+ if (led_cdev->activated) {
+ device_remove_file(led_cdev->dev, &dev_attr_delay_on);
+ device_remove_file(led_cdev->dev, &dev_attr_delay_off);
+ device_remove_file(led_cdev->dev, &dev_attr_invert);
+ device_remove_file(led_cdev->dev, &dev_attr_shot);
+ kfree(oneshot_data);
+ led_cdev->activated = false;
+ }
+
+ /* Stop blinking */
+ led_set_brightness(led_cdev, LED_OFF);
+}
+
+static struct led_trigger oneshot_led_trigger = {
+ .name = "oneshot",
+ .activate = oneshot_trig_activate,
+ .deactivate = oneshot_trig_deactivate,
+};
+
+static int __init oneshot_trig_init(void)
+{
+ return led_trigger_register(&oneshot_led_trigger);
+}
+
+static void __exit oneshot_trig_exit(void)
+{
+ led_trigger_unregister(&oneshot_led_trigger);
+}
+
+module_init(oneshot_trig_init);
+module_exit(oneshot_trig_exit);
+
+MODULE_AUTHOR("Fabio Baltieri <fabio.baltieri@gmail.com>");
+MODULE_DESCRIPTION("One-shot LED trigger");
+MODULE_LICENSE("GPL");
diff --git a/drivers/leds/ledtrig-timer.c b/drivers/leds/ledtrig-timer.c
index 9010f7abaf2c..f774d0592204 100644
--- a/drivers/leds/ledtrig-timer.c
+++ b/drivers/leds/ledtrig-timer.c
@@ -104,7 +104,7 @@ static void timer_trig_deactivate(struct led_classdev *led_cdev)
}
/* Stop blinking */
- led_brightness_set(led_cdev, LED_OFF);
+ led_set_brightness(led_cdev, LED_OFF);
}
static struct led_trigger timer_led_trigger = {
diff --git a/drivers/leds/ledtrig-transient.c b/drivers/leds/ledtrig-transient.c
index 83179f435e1e..398f1042c43e 100644
--- a/drivers/leds/ledtrig-transient.c
+++ b/drivers/leds/ledtrig-transient.c
@@ -41,7 +41,7 @@ static void transient_timer_function(unsigned long data)
struct transient_trig_data *transient_data = led_cdev->trigger_data;
transient_data->activate = 0;
- led_set_brightness(led_cdev, transient_data->restore_state);
+ __led_set_brightness(led_cdev, transient_data->restore_state);
}
static ssize_t transient_activate_show(struct device *dev,
@@ -72,7 +72,7 @@ static ssize_t transient_activate_store(struct device *dev,
if (state == 0 && transient_data->activate == 1) {
del_timer(&transient_data->timer);
transient_data->activate = state;
- led_set_brightness(led_cdev, transient_data->restore_state);
+ __led_set_brightness(led_cdev, transient_data->restore_state);
return size;
}
@@ -80,7 +80,7 @@ static ssize_t transient_activate_store(struct device *dev,
if (state == 1 && transient_data->activate == 0 &&
transient_data->duration != 0) {
transient_data->activate = state;
- led_set_brightness(led_cdev, transient_data->state);
+ __led_set_brightness(led_cdev, transient_data->state);
transient_data->restore_state =
(transient_data->state == LED_FULL) ? LED_OFF : LED_FULL;
mod_timer(&transient_data->timer,
@@ -203,7 +203,7 @@ static void transient_trig_deactivate(struct led_classdev *led_cdev)
if (led_cdev->activated) {
del_timer_sync(&transient_data->timer);
- led_set_brightness(led_cdev, transient_data->restore_state);
+ __led_set_brightness(led_cdev, transient_data->restore_state);
device_remove_file(led_cdev->dev, &dev_attr_activate);
device_remove_file(led_cdev->dev, &dev_attr_duration);
device_remove_file(led_cdev->dev, &dev_attr_state);
diff --git a/drivers/mmc/host/mvsdio.c b/drivers/mmc/host/mvsdio.c
index 3b9136c1a475..a61cb5fca22d 100644
--- a/drivers/mmc/host/mvsdio.c
+++ b/drivers/mmc/host/mvsdio.c
@@ -839,6 +839,10 @@ out:
if (r)
release_resource(r);
if (mmc)
+ if (!IS_ERR_OR_NULL(host->clk)) {
+ clk_disable_unprepare(host->clk);
+ clk_put(host->clk);
+ }
mmc_free_host(mmc);
return ret;
diff --git a/drivers/mtd/nand/orion_nand.c b/drivers/mtd/nand/orion_nand.c
index 513dc88a05ca..fc5a868c436e 100644
--- a/drivers/mtd/nand/orion_nand.c
+++ b/drivers/mtd/nand/orion_nand.c
@@ -183,6 +183,10 @@ static int __init orion_nand_probe(struct platform_device *pdev)
return 0;
no_dev:
+ if (!IS_ERR(clk)) {
+ clk_disable_unprepare(clk);
+ clk_put(clk);
+ }
platform_set_drvdata(pdev, NULL);
iounmap(io_base);
no_res:
@@ -214,7 +218,7 @@ static int __devexit orion_nand_remove(struct platform_device *pdev)
#ifdef CONFIG_OF
static struct of_device_id orion_nand_of_match_table[] = {
- { .compatible = "mrvl,orion-nand", },
+ { .compatible = "marvell,orion-nand", },
{},
};
#endif
diff --git a/drivers/net/ethernet/marvell/mv643xx_eth.c b/drivers/net/ethernet/marvell/mv643xx_eth.c
index 770ee557924c..087b9e0669f1 100644
--- a/drivers/net/ethernet/marvell/mv643xx_eth.c
+++ b/drivers/net/ethernet/marvell/mv643xx_eth.c
@@ -2983,6 +2983,12 @@ static int mv643xx_eth_probe(struct platform_device *pdev)
return 0;
out:
+#if defined(CONFIG_HAVE_CLK)
+ if (!IS_ERR(mp->clk)) {
+ clk_disable_unprepare(mp->clk);
+ clk_put(mp->clk);
+ }
+#endif
free_netdev(dev);
return err;
diff --git a/drivers/net/usb/kaweth.c b/drivers/net/usb/kaweth.c
index d8ad55284389..c3d03490c97d 100644
--- a/drivers/net/usb/kaweth.c
+++ b/drivers/net/usb/kaweth.c
@@ -1314,7 +1314,7 @@ static int kaweth_internal_control_msg(struct usb_device *usb_dev,
int retv;
int length = 0; /* shut up GCC */
- urb = usb_alloc_urb(0, GFP_NOIO);
+ urb = usb_alloc_urb(0, GFP_ATOMIC);
if (!urb)
return -ENOMEM;
diff --git a/drivers/rtc/rtc-mv.c b/drivers/rtc/rtc-mv.c
index b2185f4255aa..ebc1649d45d6 100644
--- a/drivers/rtc/rtc-mv.c
+++ b/drivers/rtc/rtc-mv.c
@@ -297,7 +297,7 @@ static int __exit mv_rtc_remove(struct platform_device *pdev)
#ifdef CONFIG_OF
static struct of_device_id rtc_mv_of_match_table[] = {
- { .compatible = "mrvl,orion-rtc", },
+ { .compatible = "marvell,orion-rtc", },
{}
};
#endif
diff --git a/drivers/usb/host/ehci-orion.c b/drivers/usb/host/ehci-orion.c
index 9408da83eaf1..8892d3642cef 100644
--- a/drivers/usb/host/ehci-orion.c
+++ b/drivers/usb/host/ehci-orion.c
@@ -283,6 +283,10 @@ static int __devinit ehci_orion_drv_probe(struct platform_device *pdev)
err4:
usb_put_hcd(hcd);
err3:
+ if (!IS_ERR(clk)) {
+ clk_disable_unprepare(clk);
+ clk_put(clk);
+ }
iounmap(regs);
err2:
release_mem_region(res->start, resource_size(res));
diff --git a/drivers/video/aty/radeon_monitor.c b/drivers/video/aty/radeon_monitor.c
index 9261c918fde8..5c23eac0eb9a 100644
--- a/drivers/video/aty/radeon_monitor.c
+++ b/drivers/video/aty/radeon_monitor.c
@@ -730,6 +730,25 @@ static void radeon_videomode_to_var(struct fb_var_screeninfo *var,
var->vmode = mode->vmode;
}
+#ifdef CONFIG_PPC_PSERIES
+static int is_powerblade(const char *model)
+{
+ struct device_node *root;
+ const char* cp;
+ int len, l, rc = 0;
+
+ root = of_find_node_by_path("/");
+ if (root && model) {
+ l = strlen(model);
+ cp = of_get_property(root, "model", &len);
+ if (cp)
+ rc = memcmp(model, cp, min(len, l)) == 0;
+ of_node_put(root);
+ }
+ return rc;
+}
+#endif
+
/*
* Build the modedb for head 1 (head 2 will come later), check panel infos
* from either BIOS or EDID, and pick up the default mode
@@ -865,6 +884,22 @@ void __devinit radeon_check_modes(struct radeonfb_info *rinfo, const char *mode_
has_default_mode = 1;
}
+#ifdef CONFIG_PPC_PSERIES
+ if (!has_default_mode && (
+ is_powerblade("IBM,8842") || /* JS20 */
+ is_powerblade("IBM,8844") || /* JS21 */
+ is_powerblade("IBM,7998") || /* JS12/JS21/JS22 */
+ is_powerblade("IBM,0792") || /* QS21 */
+ is_powerblade("IBM,0793") /* QS22 */
+ )) {
+ printk("Falling back to 800x600 on JSxx hardware\n");
+ if (fb_find_mode(&info->var, info, "800x600@60",
+ info->monspecs.modedb,
+ info->monspecs.modedb_len, NULL, 8) != 0)
+ has_default_mode = 1;
+ }
+#endif
+
/*
* Still no mode, let's pick up a default from the db
*/
diff --git a/include/linux/cpumask.h b/include/linux/cpumask.h
index a2c819d3c96e..032560295fcb 100644
--- a/include/linux/cpumask.h
+++ b/include/linux/cpumask.h
@@ -272,6 +272,8 @@ static inline void cpumask_clear_cpu(int cpu, struct cpumask *dstp)
* @cpu: cpu number (< nr_cpu_ids)
* @cpumask: the cpumask pointer
*
+ * Returns 1 if @cpu is set in @cpumask, else returns 0
+ *
* No static inline type checking - see Subtlety (1) above.
*/
#define cpumask_test_cpu(cpu, cpumask) \
@@ -282,6 +284,8 @@ static inline void cpumask_clear_cpu(int cpu, struct cpumask *dstp)
* @cpu: cpu number (< nr_cpu_ids)
* @cpumask: the cpumask pointer
*
+ * Returns 1 if @cpu is set in old bitmap of @cpumask, else returns 0
+ *
* test_and_set_bit wrapper for cpumasks.
*/
static inline int cpumask_test_and_set_cpu(int cpu, struct cpumask *cpumask)
@@ -294,6 +298,8 @@ static inline int cpumask_test_and_set_cpu(int cpu, struct cpumask *cpumask)
* @cpu: cpu number (< nr_cpu_ids)
* @cpumask: the cpumask pointer
*
+ * Returns 1 if @cpu is set in old bitmap of @cpumask, else returns 0
+ *
* test_and_clear_bit wrapper for cpumasks.
*/
static inline int cpumask_test_and_clear_cpu(int cpu, struct cpumask *cpumask)
@@ -324,6 +330,8 @@ static inline void cpumask_clear(struct cpumask *dstp)
* @dstp: the cpumask result
* @src1p: the first input
* @src2p: the second input
+ *
+ * If *@dstp is empty, returns 0, else returns 1
*/
static inline int cpumask_and(struct cpumask *dstp,
const struct cpumask *src1p,
@@ -365,6 +373,8 @@ static inline void cpumask_xor(struct cpumask *dstp,
* @dstp: the cpumask result
* @src1p: the first input
* @src2p: the second input
+ *
+ * If *@dstp is empty, returns 0, else returns 1
*/
static inline int cpumask_andnot(struct cpumask *dstp,
const struct cpumask *src1p,
@@ -414,6 +424,8 @@ static inline bool cpumask_intersects(const struct cpumask *src1p,
* cpumask_subset - (*src1p & ~*src2p) == 0
* @src1p: the first input
* @src2p: the second input
+ *
+ * Returns 1 if *@src1p is a subset of *@src2p, else returns 0
*/
static inline int cpumask_subset(const struct cpumask *src1p,
const struct cpumask *src2p)
@@ -579,9 +591,8 @@ static inline int cpulist_scnprintf(char *buf, int len,
}
/**
- * cpulist_parse_user - extract a cpumask from a user string of ranges
+ * cpulist_parse - extract a cpumask from a user string of ranges
* @buf: the buffer to extract from
- * @len: the length of the buffer
* @dstp: the cpumask to set.
*
* Returns -errno, or 0 for success.
diff --git a/include/linux/init.h b/include/linux/init.h
index 6b951095a42f..5e664f671615 100644
--- a/include/linux/init.h
+++ b/include/linux/init.h
@@ -191,6 +191,7 @@ extern bool initcall_debug;
* initializes variables that couldn't be statically initialized.
*
* This only exists for built-in code, not for modules.
+ * Keep main.c:initcall_level_names[] in sync.
*/
#define pure_initcall(fn) __define_initcall("0",fn,0)
@@ -280,7 +281,7 @@ void __init parse_early_options(char *cmdline);
#else /* MODULE */
-/* Don't use these in modules, but some people do... */
+/* Don't use these in loadable modules, but some people do... */
#define early_initcall(fn) module_init(fn)
#define core_initcall(fn) module_init(fn)
#define postcore_initcall(fn) module_init(fn)
diff --git a/include/linux/leds.h b/include/linux/leds.h
index 39eee41d8c6f..3aade1d8f410 100644
--- a/include/linux/leds.h
+++ b/include/linux/leds.h
@@ -38,6 +38,9 @@ struct led_classdev {
#define LED_SUSPENDED (1 << 0)
/* Upper 16 bits reflect control information */
#define LED_CORE_SUSPENDRESUME (1 << 16)
+#define LED_BLINK_ONESHOT (1 << 17)
+#define LED_BLINK_ONESHOT_STOP (1 << 18)
+#define LED_BLINK_INVERT (1 << 19)
/* Set LED brightness level */
/* Must not sleep, use a workqueue if needed */
@@ -103,7 +106,25 @@ extern void led_blink_set(struct led_classdev *led_cdev,
unsigned long *delay_on,
unsigned long *delay_off);
/**
- * led_brightness_set - set LED brightness
+ * led_blink_set_oneshot - do a oneshot software blink
+ * @led_cdev: the LED to start blinking
+ * @delay_on: the time it should be on (in ms)
+ * @delay_off: the time it should ble off (in ms)
+ * @invert: blink off, then on, leaving the led on
+ *
+ * This function makes the LED blink one time for delay_on +
+ * delay_off time, ignoring the request if another one-shot
+ * blink is already in progress.
+ *
+ * If invert is set, led blinks for delay_off first, then for
+ * delay_on and leave the led on after the on-off cycle.
+ */
+extern void led_blink_set_oneshot(struct led_classdev *led_cdev,
+ unsigned long *delay_on,
+ unsigned long *delay_off,
+ int invert);
+/**
+ * led_set_brightness - set LED brightness
* @led_cdev: the LED to set
* @brightness: the brightness to set it to
*
@@ -111,7 +132,7 @@ extern void led_blink_set(struct led_classdev *led_cdev,
* software blink timer that implements blinking when the
* hardware doesn't.
*/
-extern void led_brightness_set(struct led_classdev *led_cdev,
+extern void led_set_brightness(struct led_classdev *led_cdev,
enum led_brightness brightness);
/*
@@ -150,6 +171,10 @@ extern void led_trigger_event(struct led_trigger *trigger,
extern void led_trigger_blink(struct led_trigger *trigger,
unsigned long *delay_on,
unsigned long *delay_off);
+extern void led_trigger_blink_oneshot(struct led_trigger *trigger,
+ unsigned long *delay_on,
+ unsigned long *delay_off,
+ int invert);
#else
diff --git a/include/linux/platform_data/leds-lm3556.h b/include/linux/platform_data/leds-lm3556.h
new file mode 100644
index 000000000000..4b4e7d6b0527
--- /dev/null
+++ b/include/linux/platform_data/leds-lm3556.h
@@ -0,0 +1,50 @@
+/*
+ * Simple driver for Texas Instruments LM3556 LED Flash driver chip (Rev0x03)
+ * Copyright (C) 2012 Texas Instruments
+ *
+ * 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.
+ *
+ */
+
+#ifndef __LINUX_LM3556_H
+#define __LINUX_LM3556_H
+
+#define LM3556_NAME "leds-lm3556"
+
+enum lm3556_pin_polarity {
+ PIN_LOW_ACTIVE = 0,
+ PIN_HIGH_ACTIVE,
+};
+
+enum lm3556_pin_enable {
+ PIN_DISABLED = 0,
+ PIN_ENABLED,
+};
+
+enum lm3556_strobe_usuage {
+ STROBE_EDGE_DETECT = 0,
+ STROBE_LEVEL_DETECT,
+};
+
+enum lm3556_indic_mode {
+ INDIC_MODE_INTERNAL = 0,
+ INDIC_MODE_EXTERNAL,
+};
+
+struct lm3556_platform_data {
+ enum lm3556_pin_enable torch_pin_en;
+ enum lm3556_pin_polarity torch_pin_polarity;
+
+ enum lm3556_strobe_usuage strobe_usuage;
+ enum lm3556_pin_enable strobe_pin_en;
+ enum lm3556_pin_polarity strobe_pin_polarity;
+
+ enum lm3556_pin_enable tx_pin_en;
+ enum lm3556_pin_polarity tx_pin_polarity;
+
+ enum lm3556_indic_mode indicator_mode;
+};
+
+#endif /* __LINUX_LM3556_H */
diff --git a/init/main.c b/init/main.c
index eb72a5c4c844..95316a1b4a76 100644
--- a/init/main.c
+++ b/init/main.c
@@ -725,6 +725,7 @@ static initcall_t *initcall_levels[] __initdata = {
__initcall_end,
};
+/* Keep these in sync with initcalls in include/linux/init.h */
static char *initcall_level_names[] __initdata = {
"early",
"core",
diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c
index 334b930e0de3..bc9e380f0abf 100644
--- a/net/core/rtnetlink.c
+++ b/net/core/rtnetlink.c
@@ -659,6 +659,12 @@ static void set_operstate(struct net_device *dev, unsigned char transition)
}
}
+static unsigned int rtnl_dev_get_flags(const struct net_device *dev)
+{
+ return (dev->flags & ~(IFF_PROMISC | IFF_ALLMULTI)) |
+ (dev->gflags & (IFF_PROMISC | IFF_ALLMULTI));
+}
+
static unsigned int rtnl_dev_combine_flags(const struct net_device *dev,
const struct ifinfomsg *ifm)
{
@@ -667,7 +673,7 @@ static unsigned int rtnl_dev_combine_flags(const struct net_device *dev,
/* bugwards compatibility: ifi_change == 0 is treated as ~0 */
if (ifm->ifi_change)
flags = (flags & ifm->ifi_change) |
- (dev->flags & ~ifm->ifi_change);
+ (rtnl_dev_get_flags(dev) & ~ifm->ifi_change);
return flags;
}
diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c
index 581ecf02c6b5..e7e6eeae49c0 100644
--- a/net/ipv4/tcp.c
+++ b/net/ipv4/tcp.c
@@ -2681,7 +2681,10 @@ static int do_tcp_setsockopt(struct sock *sk, int level,
/* Cap the max timeout in ms TCP will retry/retrans
* before giving up and aborting (ETIMEDOUT) a connection.
*/
- icsk->icsk_user_timeout = msecs_to_jiffies(val);
+ if (val < 0)
+ err = -EINVAL;
+ else
+ icsk->icsk_user_timeout = msecs_to_jiffies(val);
break;
default:
err = -ENOPROTOOPT;
diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c
index 3e07a64ca44e..a356e1fecf9a 100644
--- a/net/ipv4/tcp_input.c
+++ b/net/ipv4/tcp_input.c
@@ -5475,7 +5475,9 @@ int tcp_rcv_established(struct sock *sk, struct sk_buff *skb,
if (tp->copied_seq == tp->rcv_nxt &&
len - tcp_header_len <= tp->ucopy.len) {
#ifdef CONFIG_NET_DMA
- if (tcp_dma_try_early_copy(sk, skb, tcp_header_len)) {
+ if (tp->ucopy.task == current &&
+ sock_owned_by_user(sk) &&
+ tcp_dma_try_early_copy(sk, skb, tcp_header_len)) {
copied_early = 1;
eaten = 1;
}
@@ -5603,6 +5605,7 @@ void tcp_finish_connect(struct sock *sk, struct sk_buff *skb)
if (skb != NULL) {
sk->sk_rx_dst = dst_clone(skb_dst(skb));
+ inet_sk(sk)->rx_dst_ifindex = skb->skb_iif;
security_inet_conn_established(sk, skb);
}
diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c
index b6b07c93924c..2fbd9921253f 100644
--- a/net/ipv4/tcp_ipv4.c
+++ b/net/ipv4/tcp_ipv4.c
@@ -1620,17 +1620,15 @@ int tcp_v4_do_rcv(struct sock *sk, struct sk_buff *skb)
sock_rps_save_rxhash(sk, skb);
if (sk->sk_rx_dst) {
struct dst_entry *dst = sk->sk_rx_dst;
- if (dst->ops->check(dst, 0) == NULL) {
+ if (inet_sk(sk)->rx_dst_ifindex != skb->skb_iif ||
+ dst->ops->check(dst, 0) == NULL) {
dst_release(dst);
sk->sk_rx_dst = NULL;
}
}
if (unlikely(sk->sk_rx_dst == NULL)) {
- struct inet_sock *icsk = inet_sk(sk);
- struct rtable *rt = skb_rtable(skb);
-
- sk->sk_rx_dst = dst_clone(&rt->dst);
- icsk->rx_dst_ifindex = inet_iif(skb);
+ sk->sk_rx_dst = dst_clone(skb_dst(skb));
+ inet_sk(sk)->rx_dst_ifindex = skb->skb_iif;
}
if (tcp_rcv_established(sk, skb, tcp_hdr(skb), skb->len)) {
rsk = sk;
@@ -1709,11 +1707,11 @@ void tcp_v4_early_demux(struct sk_buff *skb)
skb->destructor = sock_edemux;
if (sk->sk_state != TCP_TIME_WAIT) {
struct dst_entry *dst = sk->sk_rx_dst;
- struct inet_sock *icsk = inet_sk(sk);
+
if (dst)
dst = dst_check(dst, 0);
if (dst &&
- icsk->rx_dst_ifindex == skb->skb_iif)
+ inet_sk(sk)->rx_dst_ifindex == skb->skb_iif)
skb_dst_set_noref(skb, dst);
}
}
diff --git a/net/ipv4/tcp_minisocks.c b/net/ipv4/tcp_minisocks.c
index 5912ac3fd240..3f1cc2028edd 100644
--- a/net/ipv4/tcp_minisocks.c
+++ b/net/ipv4/tcp_minisocks.c
@@ -388,6 +388,7 @@ struct sock *tcp_create_openreq_child(struct sock *sk, struct request_sock *req,
struct tcp_cookie_values *oldcvp = oldtp->cookie_values;
newsk->sk_rx_dst = dst_clone(skb_dst(skb));
+ inet_sk(newsk)->rx_dst_ifindex = skb->skb_iif;
/* TCP Cookie Transactions require space for the cookie pair,
* as it differs for each connection. There is no need to
diff --git a/net/mac80211/led.c b/net/mac80211/led.c
index 1bf7903496f8..bcffa6903129 100644
--- a/net/mac80211/led.c
+++ b/net/mac80211/led.c
@@ -276,7 +276,7 @@ static void ieee80211_stop_tpt_led_trig(struct ieee80211_local *local)
read_lock(&tpt_trig->trig.leddev_list_lock);
list_for_each_entry(led_cdev, &tpt_trig->trig.led_cdevs, trig_list)
- led_brightness_set(led_cdev, LED_OFF);
+ led_set_brightness(led_cdev, LED_OFF);
read_unlock(&tpt_trig->trig.leddev_list_lock);
}
diff --git a/net/openvswitch/actions.c b/net/openvswitch/actions.c
index 320fa0e6951a..f3f96badf5aa 100644
--- a/net/openvswitch/actions.c
+++ b/net/openvswitch/actions.c
@@ -325,9 +325,6 @@ static int sample(struct datapath *dp, struct sk_buff *skb,
}
}
- if (!acts_list)
- return 0;
-
return do_execute_actions(dp, skb, nla_data(acts_list),
nla_len(acts_list), true);
}
diff --git a/sound/soc/kirkwood/kirkwood-i2s.c b/sound/soc/kirkwood/kirkwood-i2s.c
index fa4556750451..7646dd7f30cb 100644
--- a/sound/soc/kirkwood/kirkwood-i2s.c
+++ b/sound/soc/kirkwood/kirkwood-i2s.c
@@ -458,7 +458,13 @@ static __devinit int kirkwood_i2s_dev_probe(struct platform_device *pdev)
}
clk_prepare_enable(priv->clk);
- return snd_soc_register_dai(&pdev->dev, &kirkwood_i2s_dai);
+ err = snd_soc_register_dai(&pdev->dev, &kirkwood_i2s_dai);
+ if (!err)
+ return 0;
+ dev_err(&pdev->dev, "snd_soc_register_dai failed\n");
+
+ clk_disable_unprepare(priv->clk);
+ clk_put(priv->clk);
err_ioremap:
iounmap(priv->io);