Commit 0512c04a authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'for-next' of git://git.kernel.org/pub/scm/linux/kernel/git/cooloney/linux-leds

Pull LED subsystem update from Bryan Wu.

* 'for-next' of git://git.kernel.org/pub/scm/linux/kernel/git/cooloney/linux-leds: (61 commits)
  leds: leds-sunfire: use dev_err()/pr_err() instead of printk()
  leds: 88pm860x: Add missing of_node_put()
  leds: tca6507: Use of_get_child_count()
  leds: leds-pwm: make it depend on PWM and not HAVE_PWM
  Documentation: leds: update LP55xx family devices
  leds-lp55xx: fix problem on removing LED attributes
  leds-lp5521/5523: add author and copyright description
  leds-lp5521/5523: use new lp55xx common header
  leds-lp55xx: clean up headers
  leds-lp55xx: clean up definitions
  leds-lp55xx: clean up unused data and functions
  leds-lp55xx: clean up _remove()
  leds-lp55xx: add new function for removing device attribtues
  leds-lp55xx: code refactoring on selftest function
  leds-lp55xx: use common device attribute driver function
  leds-lp55xx: support device specific attributes
  leds-lp5523: use generic firmware interface
  leds-lp5521: use generic firmware interface
  leds-lp55xx: support firmware interface
  leds-lp55xx: add new lp55xx_register_sysfs() for the firmware interface
  ...
parents 5115f3c1 4b07c5d5
LED connected to PWM
Required properties:
- compatible : should be "pwm-leds".
Each LED is represented as a sub-node of the pwm-leds device. Each
node's name represents the name of the corresponding LED.
LED sub-node properties:
- pwms : PWM property to point to the PWM device (phandle)/port (id) and to
specify the period time to be used: <&phandle id period_ns>;
- pwm-names : (optional) Name to be used by the PWM subsystem for the PWM device
For the pwms and pwm-names property please refer to:
Documentation/devicetree/bindings/pwm/pwm.txt
- max-brightness : Maximum brightness possible for the LED
- label : (optional)
see Documentation/devicetree/bindings/leds/common.txt
- linux,default-trigger : (optional)
see Documentation/devicetree/bindings/leds/common.txt
Example:
twl_pwm: pwm {
/* provides two PWMs (id 0, 1 for PWM1 and PWM2) */
compatible = "ti,twl6030-pwm";
#pwm-cells = <2>;
};
twl_pwmled: pwmled {
/* provides one PWM (id 0 for Charing indicator LED) */
compatible = "ti,twl6030-pwmled";
#pwm-cells = <2>;
};
pwmleds {
compatible = "pwm-leds";
kpad {
label = "omap4::keypad";
pwms = <&twl_pwm 0 7812500>;
max-brightness = <127>;
};
charging {
label = "omap4:green:chrg";
pwms = <&twl_pwmled 0 7812500>;
max-brightness = <255>;
};
};
LEDs conected to tca6507
Required properties:
- compatible : should be : "ti,tca6507".
Each led is represented as a sub-node of the ti,tca6507 device.
LED sub-node properties:
- label : (optional) see Documentation/devicetree/bindings/leds/common.txt
- reg : number of LED line (could be from 0 to 6)
- linux,default-trigger : (optional)
see Documentation/devicetree/bindings/leds/common.txt
Examples:
tca6507@45 {
compatible = "ti,tca6507";
#address-cells = <1>;
#size-cells = <0>;
reg = <0x45>;
led0: red-aux@0 {
label = "red:aux";
reg = <0x0>;
};
led1: green-aux@1 {
label = "green:aux";
reg = <0x5>;
linux,default-trigger = "default-on";
};
};
...@@ -6,5 +6,7 @@ leds-lp5521.txt ...@@ -6,5 +6,7 @@ leds-lp5521.txt
- notes on how to use the leds-lp5521 driver. - notes on how to use the leds-lp5521 driver.
leds-lp5523.txt leds-lp5523.txt
- notes on how to use the leds-lp5523 driver. - notes on how to use the leds-lp5523 driver.
leds-lp55xx.txt
- description about lp55xx common driver.
leds-lm3556.txt leds-lm3556.txt
- notes on how to use the leds-lm3556 driver. - notes on how to use the leds-lm3556 driver.
...@@ -17,19 +17,8 @@ lp5521:channelx, where x is 0 .. 2 ...@@ -17,19 +17,8 @@ lp5521:channelx, where x is 0 .. 2
All three channels can be also controlled using the engine micro programs. All three channels can be also controlled using the engine micro programs.
More details of the instructions can be found from the public data sheet. More details of the instructions can be found from the public data sheet.
Control interface for the engines: LP5521 has the internal program memory for running various LED patterns.
x is 1 .. 3 For the details, please refer to 'firmware' section in leds-lp55xx.txt
enginex_mode : disabled, load, run
enginex_load : store program (visible only in engine load mode)
Example (start to blink the channel 2 led):
cd /sys/class/leds/lp5521:channel2/device
echo "load" > engine3_mode
echo "037f4d0003ff6000" > engine3_load
echo "run" > engine3_mode
stop the engine:
echo "disabled" > engine3_mode
sysfs contains a selftest entry. sysfs contains a selftest entry.
The test communicates with the chip and checks that The test communicates with the chip and checks that
...@@ -47,7 +36,7 @@ The name of each channel can be configurable. ...@@ -47,7 +36,7 @@ The name of each channel can be configurable.
If the name field is not defined, the default name will be set to 'xxxx:channelN' If the name field is not defined, the default name will be set to 'xxxx:channelN'
(XXXX : pdata->label or i2c client name, N : channel number) (XXXX : pdata->label or i2c client name, N : channel number)
static struct lp5521_led_config lp5521_led_config[] = { static struct lp55xx_led_config lp5521_led_config[] = {
{ {
.name = "red", .name = "red",
.chan_nr = 0, .chan_nr = 0,
...@@ -81,10 +70,10 @@ static void lp5521_enable(bool state) ...@@ -81,10 +70,10 @@ static void lp5521_enable(bool state)
/* Control of chip enable signal */ /* Control of chip enable signal */
} }
static struct lp5521_platform_data lp5521_platform_data = { static struct lp55xx_platform_data lp5521_platform_data = {
.led_config = lp5521_led_config, .led_config = lp5521_led_config,
.num_channels = ARRAY_SIZE(lp5521_led_config), .num_channels = ARRAY_SIZE(lp5521_led_config),
.clock_mode = LP5521_CLOCK_EXT, .clock_mode = LP55XX_CLOCK_EXT,
.setup_resources = lp5521_setup, .setup_resources = lp5521_setup,
.release_resources = lp5521_release, .release_resources = lp5521_release,
.enable = lp5521_enable, .enable = lp5521_enable,
...@@ -105,47 +94,9 @@ example of update_config : ...@@ -105,47 +94,9 @@ example of update_config :
LP5521_CP_MODE_AUTO | LP5521_R_TO_BATT | \ LP5521_CP_MODE_AUTO | LP5521_R_TO_BATT | \
LP5521_CLK_INT) LP5521_CLK_INT)
static struct lp5521_platform_data lp5521_pdata = { static struct lp55xx_platform_data lp5521_pdata = {
.led_config = lp5521_led_config, .led_config = lp5521_led_config,
.num_channels = ARRAY_SIZE(lp5521_led_config), .num_channels = ARRAY_SIZE(lp5521_led_config),
.clock_mode = LP5521_CLOCK_INT, .clock_mode = LP55XX_CLOCK_INT,
.update_config = LP5521_CONFIGS, .update_config = LP5521_CONFIGS,
}; };
LED patterns : LP5521 has autonomous operation without external control.
Pattern data can be defined in the platform data.
example of led pattern data :
/* RGB(50,5,0) 500ms on, 500ms off, infinite loop */
static u8 pattern_red[] = {
0x40, 0x32, 0x60, 0x00, 0x40, 0x00, 0x60, 0x00,
};
static u8 pattern_green[] = {
0x40, 0x05, 0x60, 0x00, 0x40, 0x00, 0x60, 0x00,
};
static struct lp5521_led_pattern board_led_patterns[] = {
{
.r = pattern_red,
.g = pattern_green,
.size_r = ARRAY_SIZE(pattern_red),
.size_g = ARRAY_SIZE(pattern_green),
},
};
static struct lp5521_platform_data lp5521_platform_data = {
.led_config = lp5521_led_config,
.num_channels = ARRAY_SIZE(lp5521_led_config),
.clock_mode = LP5521_CLOCK_EXT,
.patterns = board_led_patterns,
.num_patterns = ARRAY_SIZE(board_led_patterns),
};
Then predefined led pattern(s) can be executed via the sysfs.
To start the pattern #1,
# echo 1 > /sys/bus/i2c/devices/xxxx/led_pattern
(xxxx : i2c bus & slave address)
To end the pattern,
# echo 0 > /sys/bus/i2c/devices/xxxx/led_pattern
...@@ -27,25 +27,8 @@ c) Default ...@@ -27,25 +27,8 @@ c) Default
If both fields are NULL, 'lp5523' is used by default. If both fields are NULL, 'lp5523' is used by default.
/sys/class/leds/lp5523:channelN (N: 0 ~ 8) /sys/class/leds/lp5523:channelN (N: 0 ~ 8)
The chip provides 3 engines. Each engine can control channels without LP5523 has the internal program memory for running various LED patterns.
interaction from the main CPU. Details of the micro engine code can be found For the details, please refer to 'firmware' section in leds-lp55xx.txt
from the public data sheet. Leds can be muxed to different channels.
Control interface for the engines:
x is 1 .. 3
enginex_mode : disabled, load, run
enginex_load : microcode load (visible only in load mode)
enginex_leds : led mux control (visible only in load mode)
cd /sys/class/leds/lp5523:channel2/device
echo "load" > engine3_mode
echo "9d80400004ff05ff437f0000" > engine3_load
echo "111111111" > engine3_leds
echo "run" > engine3_mode
sysfs contains a selftest entry. It measures each channel
voltage level and checks if it looks reasonable. If the level is too high,
the led is missing; if the level is too low, there is a short circuit.
Selftest uses always the current from the platform data. Selftest uses always the current from the platform data.
...@@ -58,7 +41,7 @@ Example platform data: ...@@ -58,7 +41,7 @@ Example platform data:
Note - chan_nr can have values between 0 and 8. Note - chan_nr can have values between 0 and 8.
static struct lp5523_led_config lp5523_led_config[] = { static struct lp55xx_led_config lp5523_led_config[] = {
{ {
.name = "D1", .name = "D1",
.chan_nr = 0, .chan_nr = 0,
...@@ -88,10 +71,10 @@ static void lp5523_enable(bool state) ...@@ -88,10 +71,10 @@ static void lp5523_enable(bool state)
/* Control chip enable signal */ /* Control chip enable signal */
} }
static struct lp5523_platform_data lp5523_platform_data = { static struct lp55xx_platform_data lp5523_platform_data = {
.led_config = lp5523_led_config, .led_config = lp5523_led_config,
.num_channels = ARRAY_SIZE(lp5523_led_config), .num_channels = ARRAY_SIZE(lp5523_led_config),
.clock_mode = LP5523_CLOCK_EXT, .clock_mode = LP55XX_CLOCK_EXT,
.setup_resources = lp5523_setup, .setup_resources = lp5523_setup,
.release_resources = lp5523_release, .release_resources = lp5523_release,
.enable = lp5523_enable, .enable = lp5523_enable,
......
LP5521/LP5523/LP55231 Common Driver
===================================
Authors: Milo(Woogyom) Kim <milo.kim@ti.com>
Description
-----------
LP5521, LP5523/55231 have common features as below.
Register access via the I2C
Device initialization/deinitialization
Create LED class devices for multiple output channels
Device attributes for user-space interface
Program memory for running LED patterns
The LP55xx common driver provides these features using exported functions.
lp55xx_init_device() / lp55xx_deinit_device()
lp55xx_register_leds() / lp55xx_unregister_leds()
lp55xx_regsister_sysfs() / lp55xx_unregister_sysfs()
( Driver Structure Data )
In lp55xx common driver, two different data structure is used.
o lp55xx_led
control multi output LED channels such as led current, channel index.
o lp55xx_chip
general chip control such like the I2C and platform data.
For example, LP5521 has maximum 3 LED channels.
LP5523/55231 has 9 output channels.
lp55xx_chip for LP5521 ... lp55xx_led #1
lp55xx_led #2
lp55xx_led #3
lp55xx_chip for LP5523 ... lp55xx_led #1
lp55xx_led #2
.
.
lp55xx_led #9
( Chip Dependent Code )
To support device specific configurations, special structure
'lpxx_device_config' is used.
Maximum number of channels
Reset command, chip enable command
Chip specific initialization
Brightness control register access
Setting LED output current
Program memory address access for running patterns
Additional device specific attributes
( Firmware Interface )
LP55xx family devices have the internal program memory for running
various LED patterns.
This pattern data is saved as a file in the user-land or
hex byte string is written into the memory through the I2C.
LP55xx common driver supports the firmware interface.
LP55xx chips have three program engines.
To load and run the pattern, the programming sequence is following.
(1) Select an engine number (1/2/3)
(2) Mode change to load
(3) Write pattern data into selected area
(4) Mode change to run
The LP55xx common driver provides simple interfaces as below.
select_engine : Select which engine is used for running program
run_engine : Start program which is loaded via the firmware interface
firmware : Load program data
For example, run blinking pattern in engine #1 of LP5521
echo 1 > /sys/bus/i2c/devices/xxxx/select_engine
echo 1 > /sys/class/firmware/lp5521/loading
echo "4000600040FF6000" > /sys/class/firmware/lp5521/data
echo 0 > /sys/class/firmware/lp5521/loading
echo 1 > /sys/bus/i2c/devices/xxxx/run_engine
For example, run blinking pattern in engine #3 of LP55231
echo 3 > /sys/bus/i2c/devices/xxxx/select_engine
echo 1 > /sys/class/firmware/lp55231/loading
echo "9d0740ff7e0040007e00a0010000" > /sys/class/firmware/lp55231/data
echo 0 > /sys/class/firmware/lp55231/loading
echo 1 > /sys/bus/i2c/devices/xxxx/run_engine
To start blinking patterns in engine #2 and #3 simultaneously,
for idx in 2 3
do
echo $idx > /sys/class/leds/red/device/select_engine
sleep 0.1
echo 1 > /sys/class/firmware/lp5521/loading
echo "4000600040FF6000" > /sys/class/firmware/lp5521/data
echo 0 > /sys/class/firmware/lp5521/loading
done
echo 1 > /sys/class/leds/red/device/run_engine
Here is another example for LP5523.
echo 2 > /sys/bus/i2c/devices/xxxx/select_engine
echo 1 > /sys/class/firmware/lp5523/loading
echo "9d80400004ff05ff437f0000" > /sys/class/firmware/lp5523/data
echo 0 > /sys/class/firmware/lp5523/loading
echo 1 > /sys/bus/i2c/devices/xxxx/run_engine
As soon as 'loading' is set to 0, registered callback is called.
Inside the callback, the selected engine is loaded and memory is updated.
To run programmed pattern, 'run_engine' attribute should be enabled.
( 'run_engine' and 'firmware_cb' )
The sequence of running the program data is common.
But each device has own specific register addresses for commands.
To support this, 'run_engine' and 'firmware_cb' are configurable in each driver.
run_engine : Control the selected engine
firmware_cb : The callback function after loading the firmware is done.
Chip specific commands for loading and updating program memory.
...@@ -40,7 +40,7 @@ ...@@ -40,7 +40,7 @@
#include <sound/tpa6130a2-plat.h> #include <sound/tpa6130a2-plat.h>
#include <media/radio-si4713.h> #include <media/radio-si4713.h>
#include <media/si4713.h> #include <media/si4713.h>
#include <linux/leds-lp5523.h> #include <linux/platform_data/leds-lp55xx.h>
#include <linux/platform_data/tsl2563.h> #include <linux/platform_data/tsl2563.h>
#include <linux/lis3lv02d.h> #include <linux/lis3lv02d.h>
...@@ -160,7 +160,7 @@ static struct tsl2563_platform_data rx51_tsl2563_platform_data = { ...@@ -160,7 +160,7 @@ static struct tsl2563_platform_data rx51_tsl2563_platform_data = {
#endif #endif
#if defined(CONFIG_LEDS_LP5523) || defined(CONFIG_LEDS_LP5523_MODULE) #if defined(CONFIG_LEDS_LP5523) || defined(CONFIG_LEDS_LP5523_MODULE)
static struct lp5523_led_config rx51_lp5523_led_config[] = { static struct lp55xx_led_config rx51_lp5523_led_config[] = {
{ {
.name = "lp5523:kb1", .name = "lp5523:kb1",
.chan_nr = 0, .chan_nr = 0,
...@@ -216,10 +216,10 @@ static void rx51_lp5523_enable(bool state) ...@@ -216,10 +216,10 @@ static void rx51_lp5523_enable(bool state)
gpio_set_value(RX51_LP5523_CHIP_EN_GPIO, !!state); gpio_set_value(RX51_LP5523_CHIP_EN_GPIO, !!state);
} }
static struct lp5523_platform_data rx51_lp5523_platform_data = { static struct lp55xx_platform_data rx51_lp5523_platform_data = {
.led_config = rx51_lp5523_led_config, .led_config = rx51_lp5523_led_config,
.num_channels = ARRAY_SIZE(rx51_lp5523_led_config), .num_channels = ARRAY_SIZE(rx51_lp5523_led_config),
.clock_mode = LP5523_CLOCK_AUTO, .clock_mode = LP55XX_CLOCK_AUTO,
.setup_resources = rx51_lp5523_setup, .setup_resources = rx51_lp5523_setup,
.release_resources = rx51_lp5523_release, .release_resources = rx51_lp5523_release,
.enable = rx51_lp5523_enable, .enable = rx51_lp5523_enable,
......
...@@ -28,7 +28,7 @@ ...@@ -28,7 +28,7 @@
#include <linux/mfd/tps6105x.h> #include <linux/mfd/tps6105x.h>
#include <linux/mfd/abx500/ab8500-gpio.h> #include <linux/mfd/abx500/ab8500-gpio.h>
#include <linux/mfd/abx500/ab8500-codec.h> #include <linux/mfd/abx500/ab8500-codec.h>
#include <linux/leds-lp5521.h> #include <linux/platform_data/leds-lp55xx.h>
#include <linux/input.h> #include <linux/input.h>
#include <linux/smsc911x.h> #include <linux/smsc911x.h>
#include <linux/gpio_keys.h> #include <linux/gpio_keys.h>
...@@ -301,7 +301,7 @@ static struct tc3589x_platform_data mop500_tc35892_data = { ...@@ -301,7 +301,7 @@ static struct tc3589x_platform_data mop500_tc35892_data = {
.irq_base = MOP500_EGPIO_IRQ_BASE, .irq_base = MOP500_EGPIO_IRQ_BASE,
}; };
static struct lp5521_led_config lp5521_pri_led[] = { static struct lp55xx_led_config lp5521_pri_led[] = {
[0] = { [0] = {
.chan_nr = 0, .chan_nr = 0,
.led_current = 0x2f, .led_current = 0x2f,
...@@ -319,14 +319,14 @@ static struct lp5521_led_config lp5521_pri_led[] = { ...@@ -319,14 +319,14 @@ static struct lp5521_led_config lp5521_pri_led[] = {
}, },
}; };
static struct lp5521_platform_data __initdata lp5521_pri_data = { static struct lp55xx_platform_data __initdata lp5521_pri_data = {
.label = "lp5521_pri", .label = "lp5521_pri",
.led_config = &lp5521_pri_led[0], .led_config = &lp5521_pri_led[0],
.num_channels = 3, .num_channels = 3,
.clock_mode = LP5521_CLOCK_EXT, .clock_mode = LP55XX_CLOCK_EXT,
}; };
static struct lp5521_led_config lp5521_sec_led[] = { static struct lp55xx_led_config lp5521_sec_led[] = {
[0] = { [0] = {
.chan_nr = 0, .chan_nr = 0,
.led_current = 0x2f, .led_current = 0x2f,
...@@ -344,11 +344,11 @@ static struct lp5521_led_config lp5521_sec_led[] = { ...@@ -344,11 +344,11 @@ static struct lp5521_led_config lp5521_sec_led[] = {
}, },
}; };
static struct lp5521_platform_data __initdata lp5521_sec_data = { static struct lp55xx_platform_data __initdata lp5521_sec_data = {
.label = "lp5521_sec", .label = "lp5521_sec",
.led_config = &lp5521_sec_led[0], .led_config = &lp5521_sec_led[0],
.num_channels = 3, .num_channels = 3,
.clock_mode = LP5521_CLOCK_EXT, .clock_mode = LP55XX_CLOCK_EXT,
}; };
static struct i2c_board_info __initdata mop500_i2c0_devices[] = { static struct i2c_board_info __initdata mop500_i2c0_devices[] = {
......
...@@ -193,9 +193,18 @@ config LEDS_LP3944 ...@@ -193,9 +193,18 @@ config LEDS_LP3944
To compile this driver as a module, choose M here: the To compile this driver as a module, choose M here: the
module will be called leds-lp3944. module will be called leds-lp3944.
config LEDS_LP55XX_COMMON
tristate "Common Driver for TI/National LP5521 and LP5523/55231"
depends on LEDS_LP5521 || LEDS_LP5523
select FW_LOADER
help
This option supports common operations for LP5521 and LP5523/55231
devices.
config LEDS_LP5521 config LEDS_LP5521
tristate "LED Support for N.S. LP5521 LED driver chip" tristate "LED Support for N.S. LP5521 LED driver chip"
depends on LEDS_CLASS && I2C depends on LEDS_CLASS && I2C
select LEDS_LP55XX_COMMON
help help
If you say yes here you get support for the National Semiconductor If you say yes here you get support for the National Semiconductor
LP5521 LED driver. It is 3 channel chip with programmable engines. LP5521 LED driver. It is 3 channel chip with programmable engines.
...@@ -205,6 +214,7 @@ config LEDS_LP5521 ...@@ -205,6 +214,7 @@ config LEDS_LP5521
config LEDS_LP5523 config LEDS_LP5523
tristate "LED Support for TI/National LP5523/55231 LED driver chip" tristate "LED Support for TI/National LP5523/55231 LED driver chip"
depends on LEDS_CLASS && I2C depends on LEDS_CLASS && I2C
select LEDS_LP55XX_COMMON
help help
If you say yes here you get support for TI/National Semiconductor If you say yes here you get support for TI/National Semiconductor
LP5523/55231 LED driver. LP5523/55231 LED driver.
...@@ -310,7 +320,7 @@ config LEDS_DAC124S085 ...@@ -310,7 +320,7 @@ config LEDS_DAC124S085
config LEDS_PWM config LEDS_PWM
tristate "PWM driven LED Support" tristate "PWM driven LED Support"
depends on LEDS_CLASS depends on LEDS_CLASS
depends on HAVE_PWM depends on PWM
help help
This option enables support for pwm driven LEDs This option enables support for pwm driven LEDs
......
...@@ -23,6 +23,7 @@ obj-$(CONFIG_LEDS_PCA9532) += leds-pca9532.o ...@@ -23,6 +23,7 @@ obj-$(CONFIG_LEDS_PCA9532) += leds-pca9532.o
obj-$(CONFIG_LEDS_GPIO_REGISTER) += leds-gpio-register.o obj-$(CONFIG_LEDS_GPIO_REGISTER) += leds-gpio-register.o
obj-$(CONFIG_LEDS_GPIO) += leds-gpio.o obj-$(CONFIG_LEDS_GPIO) += leds-gpio.o
obj-$(CONFIG_LEDS_LP3944) += leds-lp3944.o obj-$(CONFIG_LEDS_LP3944) += leds-lp3944.o
obj-$(CONFIG_LEDS_LP55XX_COMMON) += leds-lp55xx-common.o
obj-$(CONFIG_LEDS_LP5521) += leds-lp5521.o obj-$(CONFIG_LEDS_LP5521) += leds-lp5521.o
obj-$(CONFIG_LEDS_LP5523) += leds-lp5523.o obj-$(CONFIG_LEDS_LP5523) += leds-lp5523.o
obj-$(CONFIG_LEDS_LP8788) += leds-lp8788.o obj-$(CONFIG_LEDS_LP8788) += leds-lp8788.o
......
...@@ -128,8 +128,10 @@ static void pm860x_led_set(struct led_classdev *cdev, ...@@ -128,8 +128,10 @@ static void pm860x_led_set(struct led_classdev *cdev,
static int pm860x_led_dt_init(struct platform_device *pdev, static int pm860x_led_dt_init(struct platform_device *pdev,
struct pm860x_led *data) struct pm860x_led *data)
{ {
struct device_node *nproot = pdev->dev.parent->of_node, *np; struct device_node *nproot, *np;
int iset = 0; int iset = 0;
nproot = of_node_get(pdev->dev.parent->of_node);
if (!nproot) if (!nproot)
return -ENODEV; return -ENODEV;
nproot = of_find_node_by_name(nproot, "leds"); nproot = of_find_node_by_name(nproot, "leds");
...@@ -145,6 +147,7 @@ static int pm860x_led_dt_init(struct platform_device *pdev, ...@@ -145,6 +147,7 @@ static int pm860x_led_dt_init(struct platform_device *pdev,
break; break;
} }
} }
of_node_put(nproot);
return 0; return 0;
} }
#else #else
......
...@@ -187,6 +187,40 @@ static void lm3530_als_configure(struct lm3530_platform_data *pdata, ...@@ -187,6 +187,40 @@ static void lm3530_als_configure(struct lm3530_platform_data *pdata,
(pdata->als2_resistor_sel << LM3530_ALS2_IMP_SHIFT); (pdata->als2_resistor_sel << LM3530_ALS2_IMP_SHIFT);
} }
static int lm3530_led_enable(struct lm3530_data *drvdata)
{
int ret;
if (drvdata->enable)
return 0;
ret = regulator_enable(drvdata->regulator);
if (ret) {
dev_err(drvdata->led_dev.dev, "Failed to enable vin:%d\n", ret);
return ret;
}
drvdata->enable = true;
return 0;
}
static void lm3530_led_disable(struct lm3530_data *drvdata)
{
int ret;
if (!drvdata->enable)
return;
ret = regulator_disable(drvdata->regulator);
if (ret) {
dev_err(drvdata->led_dev.dev, "Failed to disable vin:%d\n",
ret);
return;
}
drvdata->enable = false;
}
static int lm3530_init_registers(struct lm3530_data *drvdata) static int lm3530_init_registers(struct lm3530_data *drvdata)
{ {
int ret = 0; int ret = 0;
...@@ -245,15 +279,9 @@ static int lm3530_init_registers(struct lm3530_data *drvdata) ...@@ -245,15 +279,9 @@ static int lm3530_init_registers(struct lm3530_data *drvdata)
reg_val[12] = LM3530_DEF_ZT_3; /* LM3530_ALS_Z3T_REG */ reg_val[12] = LM3530_DEF_ZT_3; /* LM3530_ALS_Z3T_REG */
reg_val[13] = LM3530_DEF_ZT_4; /* LM3530_ALS_Z4T_REG */ reg_val[13] = LM3530_DEF_ZT_4; /* LM3530_ALS_Z4T_REG */
if (!drvdata->enable) { ret = lm3530_led_enable(drvdata);
ret = regulator_enable(drvdata->regulator); if (ret)
if (ret) { return ret;
dev_err(&drvdata->client->dev,
"Enable regulator failed\n");
return ret;
}
drvdata->enable = true;
}
for (i = 0; i < LM3530_REG_MAX; i++) { for (i = 0; i < LM3530_REG_MAX; i++) {
/* do not update brightness register when pwm mode */ /* do not update brightness register when pwm mode */
...@@ -305,13 +333,8 @@ static void lm3530_brightness_set(struct led_classdev *led_cdev, ...@@ -305,13 +333,8 @@ static void lm3530_brightness_set(struct led_classdev *led_cdev,
else else
drvdata->brightness = brt_val; drvdata->brightness = brt_val;
if (brt_val == 0) { if (brt_val == 0)
err = regulator_disable(drvdata->regulator); lm3530_led_disable(drvdata);
if (err)
dev_err(&drvdata->client->dev,
"Disable regulator failed\n");
drvdata->enable = false;
}
break; break;
case LM3530_BL_MODE_ALS: case LM3530_BL_MODE_ALS:
break; break;
...@@ -458,8 +481,7 @@ static int lm3530_remove(struct i2c_client *client) ...@@ -458,8 +481,7 @@ static int lm3530_remove(struct i2c_client *client)
device_remove_file(drvdata->led_dev.dev, &dev_attr_mode); device_remove_file(drvdata->led_dev.dev, &dev_attr_mode);
if (drvdata->enable) lm3530_led_disable(drvdata);
regulator_disable(drvdata->regulator);
led_classdev_unregister(&drvdata->led_dev); led_classdev_unregister(&drvdata->led_dev);
return 0; return 0;
} }
......
...@@ -380,7 +380,7 @@ static void lm355x_indicator_brightness_set(struct led_classdev *cdev, ...@@ -380,7 +380,7 @@ static void lm355x_indicator_brightness_set(struct led_classdev *cdev,
/* indicator pattern only for lm3556*/ /* indicator pattern only for lm3556*/
static ssize_t lm3556_indicator_pattern_store(struct device *dev, static ssize_t lm3556_indicator_pattern_store(struct device *dev,
struct device_attribute *devAttr, struct device_attribute *attr,
const char *buf, size_t size) const char *buf, size_t size)
{ {
ssize_t ret; ssize_t ret;
......
...@@ -176,7 +176,7 @@ static int lm3642_control(struct lm3642_chip_data *chip, ...@@ -176,7 +176,7 @@ static int lm3642_control(struct lm3642_chip_data *chip,
/* torch pin config for lm3642*/ /* torch pin config for lm3642*/
static ssize_t lm3642_torch_pin_store(struct device *dev, static ssize_t lm3642_torch_pin_store(struct device *dev,
struct device_attribute *devAttr, struct device_attribute *attr,
const char *buf, size_t size) const char *buf, size_t size)
{ {
ssize_t ret; ssize_t ret;
...@@ -233,7 +233,7 @@ static void lm3642_torch_brightness_set(struct led_classdev *cdev, ...@@ -233,7 +233,7 @@ static void lm3642_torch_brightness_set(struct led_classdev *cdev,
/* strobe pin config for lm3642*/ /* strobe pin config for lm3642*/
static ssize_t lm3642_strobe_pin_store(struct device *dev, static ssize_t lm3642_strobe_pin_store(struct device *dev,
struct device_attribute *devAttr, struct device_attribute *attr,
const char *buf, size_t size) const char *buf, size_t size)
{ {
ssize_t ret; ssize_t ret;
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
/*
* LP55XX Common Driver Header
*
* Copyright (C) 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.
*
* Derived from leds-lp5521.c, leds-lp5523.c
*/
#ifndef _LEDS_LP55XX_COMMON_H
#define _LEDS_LP55XX_COMMON_H
enum lp55xx_engine_index {
LP55XX_ENGINE_INVALID,
LP55XX_ENGINE_1,
LP55XX_ENGINE_2,
LP55XX_ENGINE_3,
};
struct lp55xx_led;
struct lp55xx_chip;
/*
* struct lp55xx_reg
* @addr : Register address
* @val : Register value
*/
struct lp55xx_reg {
u8 addr;
u8 val;
};
/*
* struct lp55xx_device_config
* @reset : Chip specific reset command
* @enable : Chip specific enable command
* @max_channel : Maximum number of channels
* @post_init_device : Chip specific initialization code
* @brightness_work_fn : Brightness work function
* @set_led_current : LED current set function
* @firmware_cb : Call function when the firmware is loaded
* @run_engine : Run internal engine for pattern
* @dev_attr_group : Device specific attributes
*/
struct lp55xx_device_config {
const struct lp55xx_reg reset;
const struct lp55xx_reg enable;
const int max_channel;
/* define if the device has specific initialization process */
int (*post_init_device) (struct lp55xx_chip *chip);
/* access brightness register */
void (*brightness_work_fn)(struct work_struct *work);
/* current setting function */
void (*set_led_current) (struct lp55xx_led *led, u8 led_current);
/* access program memory when the firmware is loaded */
void (*firmware_cb)(struct lp55xx_chip *chip);
/* used for running firmware LED patterns */
void (*run_engine) (struct lp55xx_chip *chip, bool start);
/* additional device specific attributes */
const struct attribute_group *dev_attr_group;
};
/*
* struct lp55xx_chip
* @cl : I2C communication for access registers
* @pdata : Platform specific data
* @lock : Lock for user-space interface
* @num_leds : Number of registered LEDs
* @cfg : Device specific configuration data
* @engine_idx : Selected engine number
* @fw : Firmware data for running a LED pattern
*/
struct lp55xx_chip {
struct i2c_client *cl;
struct lp55xx_platform_data *pdata;
struct mutex lock; /* lock for user-space interface */
int num_leds;
struct lp55xx_device_config *cfg;
enum lp55xx_engine_index engine_idx;
const struct firmware *fw;
};
/*
* struct lp55xx_led
* @chan_nr : Channel number
* @cdev : LED class device
* @led_current : Current setting at each led channel
* @max_current : Maximun current at each led channel
* @brightness_work : Workqueue for brightness control
* @brightness : Brightness value
* @chip : The lp55xx chip data
*/
struct lp55xx_led {
int chan_nr;
struct led_classdev cdev;
u8 led_current;
u8 max_current;
struct work_struct brightness_work;
u8 brightness;
struct lp55xx_chip *chip;
};
/* register access */
extern int lp55xx_write(struct lp55xx_chip *chip, u8 reg, u8 val);
extern int lp55xx_read(struct lp55xx_chip *chip, u8 reg, u8 *val);
extern int lp55xx_update_bits(struct lp55xx_chip *chip, u8 reg,
u8 mask, u8 val);
/* common device init/deinit functions */
extern int lp55xx_init_device(struct lp55xx_chip *chip);
extern void lp55xx_deinit_device(struct lp55xx_chip *chip);
/* common LED class device functions */
extern int lp55xx_register_leds(struct lp55xx_led *led,
struct lp55xx_chip *chip);
extern void lp55xx_unregister_leds(struct lp55xx_led *led,
struct lp55xx_chip *chip);
/* common device attributes functions */
extern int lp55xx_register_sysfs(struct lp55xx_chip *chip);
extern void lp55xx_unregister_sysfs(struct lp55xx_chip *chip);
#endif /* _LEDS_LP55XX_COMMON_H */
...@@ -130,9 +130,10 @@ static int lp8788_led_probe(struct platform_device *pdev) ...@@ -130,9 +130,10 @@ static int lp8788_led_probe(struct platform_device *pdev)
struct lp8788 *lp = dev_get_drvdata(pdev->dev.parent); struct lp8788 *lp = dev_get_drvdata(pdev->dev.parent);
struct lp8788_led_platform_data *led_pdata; struct lp8788_led_platform_data *led_pdata;
struct lp8788_led *led; struct lp8788_led *led;
struct device *dev = &pdev->dev;
int ret; int ret;
led = devm_kzalloc(lp->dev, sizeof(struct lp8788_led), GFP_KERNEL); led = devm_kzalloc(dev, sizeof(struct lp8788_led), GFP_KERNEL);
if (!led) if (!led)
return -ENOMEM; return -ENOMEM;
...@@ -154,13 +155,13 @@ static int lp8788_led_probe(struct platform_device *pdev) ...@@ -154,13 +155,13 @@ static int lp8788_led_probe(struct platform_device *pdev)
ret = lp8788_led_init_device(led, led_pdata); ret = lp8788_led_init_device(led, led_pdata);
if (ret) { if (ret) {
dev_err(lp->dev, "led init device err: %d\n", ret); dev_err(dev, "led init device err: %d\n", ret);
return ret; return ret;
} }
ret = led_classdev_register(lp->dev, &led->led_dev); ret = led_classdev_register(dev, &led->led_dev);
if (ret) { if (ret) {
dev_err(lp->dev, "led register err: %d\n", ret); dev_err(dev, "led register err: %d\n", ret);
return ret; return ret;
} }
......
...@@ -186,7 +186,7 @@ static int pca9532_set_blink(struct led_classdev *led_cdev, ...@@ -186,7 +186,7 @@ static int pca9532_set_blink(struct led_classdev *led_cdev,
int err = 0; int err = 0;
if (*delay_on == 0 && *delay_off == 0) { if (*delay_on == 0 && *delay_off == 0) {
/* led subsystem ask us for a blink rate */ /* led subsystem ask us for a blink rate */
*delay_on = 1000; *delay_on = 1000;
*delay_off = 1000; *delay_off = 1000;
} }
...@@ -311,7 +311,6 @@ static int pca9532_destroy_devices(struct pca9532_data *data, int n_devs) ...@@ -311,7 +311,6 @@ static int pca9532_destroy_devices(struct pca9532_data *data, int n_devs)
break; break;
case PCA9532_TYPE_N2100_BEEP: case PCA9532_TYPE_N2100_BEEP:
if (data->idev != NULL) { if (data->idev != NULL) {
input_unregister_device(data->idev);
cancel_work_sync(&data->work); cancel_work_sync(&data->work);
data->idev = NULL; data->idev = NULL;
} }
...@@ -382,7 +381,7 @@ static int pca9532_configure(struct i2c_client *client, ...@@ -382,7 +381,7 @@ static int pca9532_configure(struct i2c_client *client,
BUG_ON(data->idev); BUG_ON(data->idev);
led->state = PCA9532_PWM1; led->state = PCA9532_PWM1;
pca9532_setled(led); pca9532_setled(led);
data->idev = input_allocate_device(); data->idev = devm_input_allocate_device(&client->dev);
if (data->idev == NULL) { if (data->idev == NULL) {
err = -ENOMEM; err = -ENOMEM;
goto exit; goto exit;
...@@ -401,7 +400,6 @@ static int pca9532_configure(struct i2c_client *client, ...@@ -401,7 +400,6 @@ static int pca9532_configure(struct i2c_client *client,
INIT_WORK(&data->work, pca9532_input_work); INIT_WORK(&data->work, pca9532_input_work);
err = input_register_device(data->idev); err = input_register_device(data->idev);
if (err) { if (err) {
input_free_device(data->idev);
cancel_work_sync(&data->work); cancel_work_sync(&data->work);
data->idev = NULL; data->idev = NULL;
goto exit; goto exit;
......
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/of_platform.h>
#include <linux/fb.h> #include <linux/fb.h>
#include <linux/leds.h> #include <linux/leds.h>
#include <linux/err.h> #include <linux/err.h>
...@@ -30,6 +31,11 @@ struct led_pwm_data { ...@@ -30,6 +31,11 @@ struct led_pwm_data {
unsigned int period; unsigned int period;
}; };
struct led_pwm_priv {
int num_leds;
struct led_pwm_data leds[0];
};
static void led_pwm_set(struct led_classdev *led_cdev, static void led_pwm_set(struct led_classdev *led_cdev,
enum led_brightness brightness) enum led_brightness brightness)
{ {
...@@ -47,88 +53,152 @@ static void led_pwm_set(struct led_classdev *led_cdev, ...@@ -47,88 +53,152 @@ static void led_pwm_set(struct led_classdev *led_cdev,
} }
} }
static int led_pwm_probe(struct platform_device *pdev) static inline size_t sizeof_pwm_leds_priv(int num_leds)
{ {
struct led_pwm_platform_data *pdata = pdev->dev.platform_data; return sizeof(struct led_pwm_priv) +
struct led_pwm *cur_led; (sizeof(struct led_pwm_data) * num_leds);
struct led_pwm_data *leds_data, *led_dat; }
int i, ret = 0;
static struct led_pwm_priv *led_pwm_create_of(struct platform_device *pdev)
{
struct device_node *node = pdev->dev.of_node;
struct device_node *child;
struct led_pwm_priv *priv;
int count, ret;
if (!pdata) /* count LEDs in this device, so we know how much to allocate */
return -EBUSY; count = of_get_child_count(node);
if (!count)
return NULL;
leds_data = devm_kzalloc(&pdev->dev, priv = devm_kzalloc(&pdev->dev, sizeof_pwm_leds_priv(count),
sizeof(struct led_pwm_data) * pdata->num_leds, GFP_KERNEL);
GFP_KERNEL); if (!priv)
if (!leds_data) return NULL;
return -ENOMEM;
for (i = 0; i < pdata->num_leds; i++) { for_each_child_of_node(node, child) {
cur_led = &pdata->leds[i]; struct led_pwm_data *led_dat = &priv->leds[priv->num_leds];
led_dat = &leds_data[i];
led_dat->pwm = pwm_request(cur_led->pwm_id, led_dat->cdev.name = of_get_property(child, "label",
cur_led->name); NULL) ? : child->name;
led_dat->pwm = devm_of_pwm_get(&pdev->dev, child, NULL);
if (IS_ERR(led_dat->pwm)) { if (IS_ERR(led_dat->pwm)) {
ret = PTR_ERR(led_dat->pwm); dev_err(&pdev->dev, "unable to request PWM for %s\n",
dev_err(&pdev->dev, "unable to request PWM %d\n", led_dat->cdev.name);
cur_led->pwm_id);
goto err; goto err;
} }
/* Get the period from PWM core when n*/
led_dat->period = pwm_get_period(led_dat->pwm);
led_dat->cdev.default_trigger = of_get_property(child,
"linux,default-trigger", NULL);
of_property_read_u32(child, "max-brightness",
&led_dat->cdev.max_brightness);
led_dat->cdev.name = cur_led->name;
led_dat->cdev.default_trigger = cur_led->default_trigger;
led_dat->active_low = cur_led->active_low;
led_dat->period = cur_led->pwm_period_ns;
led_dat->cdev.brightness_set = led_pwm_set; led_dat->cdev.brightness_set = led_pwm_set;
led_dat->cdev.brightness = LED_OFF; led_dat->cdev.brightness = LED_OFF;
led_dat->cdev.max_brightness = cur_led->max_brightness;
led_dat->cdev.flags |= LED_CORE_SUSPENDRESUME; led_dat->cdev.flags |= LED_CORE_SUSPENDRESUME;
ret = led_classdev_register(&pdev->dev, &led_dat->cdev); ret = led_classdev_register(&pdev->dev, &led_dat->cdev);
if (ret < 0) { if (ret < 0) {
pwm_free(led_dat->pwm); dev_err(&pdev->dev, "failed to register for %s\n",
led_dat->cdev.name);
of_node_put(child);
goto err; goto err;
} }
priv->num_leds++;
} }
platform_set_drvdata(pdev, leds_data); return priv;
err:
while (priv->num_leds--)
led_classdev_unregister(&priv->leds[priv->num_leds].cdev);
return 0; return NULL;
}
err: static int led_pwm_probe(struct platform_device *pdev)
if (i > 0) { {
for (i = i - 1; i >= 0; i--) { struct led_pwm_platform_data *pdata = pdev->dev.platform_data;
led_classdev_unregister(&leds_data[i].cdev); struct led_pwm_priv *priv;
pwm_free(leds_data[i].pwm); int i, ret = 0;
if (pdata && pdata->num_leds) {
priv = devm_kzalloc(&pdev->dev,
sizeof_pwm_leds_priv(pdata->num_leds),
GFP_KERNEL);
if (!priv)
return -ENOMEM;
for (i = 0; i < pdata->num_leds; i++) {
struct led_pwm *cur_led = &pdata->leds[i];
struct led_pwm_data *led_dat = &priv->leds[i];
led_dat->pwm = devm_pwm_get(&pdev->dev, cur_led->name);
if (IS_ERR(led_dat->pwm)) {
ret = PTR_ERR(led_dat->pwm);
dev_err(&pdev->dev,
"unable to request PWM for %s\n",
cur_led->name);
goto err;
}
led_dat->cdev.name = cur_led->name;
led_dat->cdev.default_trigger = cur_led->default_trigger;
led_dat->active_low = cur_led->active_low;
led_dat->period = cur_led->pwm_period_ns;
led_dat->cdev.brightness_set = led_pwm_set;
led_dat->cdev.brightness = LED_OFF;
led_dat->cdev.max_brightness = cur_led->max_brightness;
led_dat->cdev.flags |= LED_CORE_SUSPENDRESUME;
ret = led_classdev_register(&pdev->dev, &led_dat->cdev);
if (ret < 0)
goto err;
} }
priv->num_leds = pdata->num_leds;
} else {
priv = led_pwm_create_of(pdev);
if (!priv)
return -ENODEV;
} }
platform_set_drvdata(pdev, priv);
return 0;
err:
while (i--)
led_classdev_unregister(&priv->leds[i].cdev);
return ret; return ret;
} }
static int led_pwm_remove(struct platform_device *pdev) static int led_pwm_remove(struct platform_device *pdev)
{ {
struct led_pwm_priv *priv = platform_get_drvdata(pdev);
int i; int i;
struct led_pwm_platform_data *pdata = pdev->dev.platform_data;
struct led_pwm_data *leds_data;
leds_data = platform_get_drvdata(pdev); for (i = 0; i < priv->num_leds; i++)
led_classdev_unregister(&priv->leds[i].cdev);
for (i = 0; i < pdata->num_leds; i++) {
led_classdev_unregister(&leds_data[i].cdev);
pwm_free(leds_data[i].pwm);
}
return 0; return 0;
} }
static const struct of_device_id of_pwm_leds_match[] = {
{ .compatible = "pwm-leds", },
{},
};
MODULE_DEVICE_TABLE(of, of_pwm_leds_match);
static struct platform_driver led_pwm_driver = { static struct platform_driver led_pwm_driver = {
.probe = led_pwm_probe, .probe = led_pwm_probe,
.remove = led_pwm_remove, .remove = led_pwm_remove,
.driver = { .driver = {
.name = "leds_pwm", .name = "leds_pwm",
.owner = THIS_MODULE, .owner = THIS_MODULE,
.of_match_table = of_match_ptr(of_pwm_leds_match),
}, },
}; };
......
...@@ -133,24 +133,24 @@ static int r_tpu_enable(struct r_tpu_priv *p, enum led_brightness brightness) ...@@ -133,24 +133,24 @@ static int r_tpu_enable(struct r_tpu_priv *p, enum led_brightness brightness)
rate = clk_get_rate(p->clk); rate = clk_get_rate(p->clk);
/* pick the lowest acceptable rate */ /* pick the lowest acceptable rate */
for (k = 0; k < ARRAY_SIZE(prescaler); k++) for (k = ARRAY_SIZE(prescaler) - 1; k >= 0; k--)
if ((rate / prescaler[k]) < p->min_rate) if ((rate / prescaler[k]) >= p->min_rate)
break; break;
if (!k) { if (k < 0) {
dev_err(&p->pdev->dev, "clock rate mismatch\n"); dev_err(&p->pdev->dev, "clock rate mismatch\n");
goto err0; goto err0;
} }
dev_dbg(&p->pdev->dev, "rate = %lu, prescaler %u\n", dev_dbg(&p->pdev->dev, "rate = %lu, prescaler %u\n",
rate, prescaler[k - 1]); rate, prescaler[k]);
/* clear TCNT on TGRB match, count on rising edge, set prescaler */ /* clear TCNT on TGRB match, count on rising edge, set prescaler */
r_tpu_write(p, TCR, 0x0040 | (k - 1)); r_tpu_write(p, TCR, 0x0040 | k);
/* output 0 until TGRA, output 1 until TGRB */ /* output 0 until TGRA, output 1 until TGRB */
r_tpu_write(p, TIOR, 0x0002); r_tpu_write(p, TIOR, 0x0002);
rate /= prescaler[k - 1] * p->refresh_rate; rate /= prescaler[k] * p->refresh_rate;
r_tpu_write(p, TGRB, rate); r_tpu_write(p, TGRB, rate);
dev_dbg(&p->pdev->dev, "TRGB = 0x%04lx\n", rate); dev_dbg(&p->pdev->dev, "TRGB = 0x%04lx\n", rate);
......
...@@ -63,8 +63,7 @@ MODULE_LICENSE("GPL"); ...@@ -63,8 +63,7 @@ MODULE_LICENSE("GPL");
/* /*
* PCI ID of the Intel ICH7 LPC Device within which the GPIO block lives. * PCI ID of the Intel ICH7 LPC Device within which the GPIO block lives.
*/ */
static const struct pci_device_id ich7_lpc_pci_id[] = static DEFINE_PCI_DEVICE_TABLE(ich7_lpc_pci_id) = {
{
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH7_0) }, { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH7_0) },
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH7_1) }, { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH7_1) },
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH7_30) }, { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH7_30) },
......
...@@ -3,6 +3,8 @@ ...@@ -3,6 +3,8 @@
* Copyright (C) 2008 David S. Miller <davem@davemloft.net> * Copyright (C) 2008 David S. Miller <davem@davemloft.net>
*/ */
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/init.h> #include <linux/init.h>
...@@ -14,9 +16,6 @@ ...@@ -14,9 +16,6 @@
#include <asm/fhc.h> #include <asm/fhc.h>
#include <asm/upa.h> #include <asm/upa.h>
#define DRIVER_NAME "leds-sunfire"
#define PFX DRIVER_NAME ": "
MODULE_AUTHOR("David S. Miller (davem@davemloft.net)"); MODULE_AUTHOR("David S. Miller (davem@davemloft.net)");
MODULE_DESCRIPTION("Sun Fire LED driver"); MODULE_DESCRIPTION("Sun Fire LED driver");
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
...@@ -130,14 +129,14 @@ static int sunfire_led_generic_probe(struct platform_device *pdev, ...@@ -130,14 +129,14 @@ static int sunfire_led_generic_probe(struct platform_device *pdev,
int i, err; int i, err;
if (pdev->num_resources != 1) { if (pdev->num_resources != 1) {
printk(KERN_ERR PFX "Wrong number of resources %d, should be 1\n", dev_err(&pdev->dev, "Wrong number of resources %d, should be 1\n",
pdev->num_resources); pdev->num_resources);
return -EINVAL; return -EINVAL;
} }
p = devm_kzalloc(&pdev->dev, sizeof(*p), GFP_KERNEL); p = devm_kzalloc(&pdev->dev, sizeof(*p), GFP_KERNEL);
if (!p) { if (!p) {
printk(KERN_ERR PFX "Could not allocate struct sunfire_drvdata\n"); dev_err(&pdev->dev, "Could not allocate struct sunfire_drvdata\n");
return -ENOMEM; return -ENOMEM;
} }
...@@ -152,7 +151,7 @@ static int sunfire_led_generic_probe(struct platform_device *pdev, ...@@ -152,7 +151,7 @@ static int sunfire_led_generic_probe(struct platform_device *pdev,
err = led_classdev_register(&pdev->dev, lp); err = led_classdev_register(&pdev->dev, lp);
if (err) { if (err) {
printk(KERN_ERR PFX "Could not register %s LED\n", dev_err(&pdev->dev, "Could not register %s LED\n",
lp->name); lp->name);
for (i--; i >= 0; i--) for (i--; i >= 0; i--)
led_classdev_unregister(&p->leds[i].led_cdev); led_classdev_unregister(&p->leds[i].led_cdev);
...@@ -188,7 +187,7 @@ static struct led_type clockboard_led_types[NUM_LEDS_PER_BOARD] = { ...@@ -188,7 +187,7 @@ static struct led_type clockboard_led_types[NUM_LEDS_PER_BOARD] = {
{ {
.name = "clockboard-right", .name = "clockboard-right",
.handler = clockboard_right_set, .handler = clockboard_right_set,
.default_trigger= "heartbeat", .default_trigger = "heartbeat",
}, },
}; };
...@@ -209,7 +208,7 @@ static struct led_type fhc_led_types[NUM_LEDS_PER_BOARD] = { ...@@ -209,7 +208,7 @@ static struct led_type fhc_led_types[NUM_LEDS_PER_BOARD] = {
{ {
.name = "fhc-right", .name = "fhc-right",
.handler = fhc_right_set, .handler = fhc_right_set,
.default_trigger= "heartbeat", .default_trigger = "heartbeat",
}, },
}; };
...@@ -244,13 +243,13 @@ static int __init sunfire_leds_init(void) ...@@ -244,13 +243,13 @@ static int __init sunfire_leds_init(void)
int err = platform_driver_register(&sunfire_clockboard_led_driver); int err = platform_driver_register(&sunfire_clockboard_led_driver);
if (err) { if (err) {
printk(KERN_ERR PFX "Could not register clock board LED driver\n"); pr_err("Could not register clock board LED driver\n");
return err; return err;
} }
err = platform_driver_register(&sunfire_fhc_led_driver); err = platform_driver_register(&sunfire_fhc_led_driver);
if (err) { if (err) {
printk(KERN_ERR PFX "Could not register FHC LED driver\n"); pr_err("Could not register FHC LED driver\n");
platform_driver_unregister(&sunfire_clockboard_led_driver); platform_driver_unregister(&sunfire_clockboard_led_driver);
} }
......
...@@ -667,8 +667,68 @@ static void tca6507_remove_gpio(struct tca6507_chip *tca) ...@@ -667,8 +667,68 @@ static void tca6507_remove_gpio(struct tca6507_chip *tca)
} }
#endif /* CONFIG_GPIOLIB */ #endif /* CONFIG_GPIOLIB */
#ifdef CONFIG_OF
static struct tca6507_platform_data *
tca6507_led_dt_init(struct i2c_client *client)
{
struct device_node *np = client->dev.of_node, *child;
struct tca6507_platform_data *pdata;
struct led_info *tca_leds;
int count;
count = of_get_child_count(np);
if (!count || count > NUM_LEDS)
return ERR_PTR(-ENODEV);
tca_leds = devm_kzalloc(&client->dev,
sizeof(struct led_info) * count, GFP_KERNEL);
if (!tca_leds)
return ERR_PTR(-ENOMEM);
for_each_child_of_node(np, child) {
struct led_info led;
u32 reg;
int ret;
led.name =
of_get_property(child, "label", NULL) ? : child->name;
led.default_trigger =
of_get_property(child, "linux,default-trigger", NULL);
ret = of_property_read_u32(child, "reg", &reg);
if (ret != 0)
continue;
tca_leds[reg] = led;
}
pdata = devm_kzalloc(&client->dev,
sizeof(struct tca6507_platform_data), GFP_KERNEL);
if (!pdata)
return ERR_PTR(-ENOMEM);
pdata->leds.leds = tca_leds;
pdata->leds.num_leds = count;
return pdata;
}
static const struct of_device_id of_tca6507_leds_match[] = {
{ .compatible = "ti,tca6507", },
{},
};
#else
static struct tca6507_platform_data *
tca6507_led_dt_init(struct i2c_client *client)
{
return ERR_PTR(-ENODEV);
}
#define of_tca6507_leds_match NULL
#endif
static int tca6507_probe(struct i2c_client *client, static int tca6507_probe(struct i2c_client *client,
const struct i2c_device_id *id) const struct i2c_device_id *id)
{ {
struct tca6507_chip *tca; struct tca6507_chip *tca;
struct i2c_adapter *adapter; struct i2c_adapter *adapter;
...@@ -683,9 +743,12 @@ static int tca6507_probe(struct i2c_client *client, ...@@ -683,9 +743,12 @@ static int tca6507_probe(struct i2c_client *client,
return -EIO; return -EIO;
if (!pdata || pdata->leds.num_leds != NUM_LEDS) { if (!pdata || pdata->leds.num_leds != NUM_LEDS) {
dev_err(&client->dev, "Need %d entries in platform-data list\n", pdata = tca6507_led_dt_init(client);
NUM_LEDS); if (IS_ERR(pdata)) {
return -ENODEV; dev_err(&client->dev, "Need %d entries in platform-data list\n",
NUM_LEDS);
return PTR_ERR(pdata);
}
} }
tca = devm_kzalloc(&client->dev, sizeof(*tca), GFP_KERNEL); tca = devm_kzalloc(&client->dev, sizeof(*tca), GFP_KERNEL);
if (!tca) if (!tca)
...@@ -750,6 +813,7 @@ static struct i2c_driver tca6507_driver = { ...@@ -750,6 +813,7 @@ static struct i2c_driver tca6507_driver = {
.driver = { .driver = {
.name = "leds-tca6507", .name = "leds-tca6507",
.owner = THIS_MODULE, .owner = THIS_MODULE,
.of_match_table = of_tca6507_leds_match,
}, },
.probe = tca6507_probe, .probe = tca6507_probe,
.remove = tca6507_remove, .remove = tca6507_remove,
......
...@@ -157,7 +157,7 @@ static int wm831x_status_blink_set(struct led_classdev *led_cdev, ...@@ -157,7 +157,7 @@ static int wm831x_status_blink_set(struct led_classdev *led_cdev,
return ret; return ret;
} }
static const char *led_src_texts[] = { static const char * const led_src_texts[] = {
"otp", "otp",
"power", "power",
"charger", "charger",
......
...@@ -471,7 +471,7 @@ static struct pwm_chip *of_node_to_pwmchip(struct device_node *np) ...@@ -471,7 +471,7 @@ static struct pwm_chip *of_node_to_pwmchip(struct device_node *np)
} }
/** /**
* of_pwm_request() - request a PWM via the PWM framework * of_pwm_get() - request a PWM via the PWM framework
* @np: device node to get the PWM from * @np: device node to get the PWM from
* @con_id: consumer name * @con_id: consumer name
* *
...@@ -486,8 +486,7 @@ static struct pwm_chip *of_node_to_pwmchip(struct device_node *np) ...@@ -486,8 +486,7 @@ static struct pwm_chip *of_node_to_pwmchip(struct device_node *np)
* becomes mandatory for devices that look up the PWM device via the con_id * becomes mandatory for devices that look up the PWM device via the con_id
* parameter. * parameter.
*/ */
static struct pwm_device *of_pwm_request(struct device_node *np, struct pwm_device *of_pwm_get(struct device_node *np, const char *con_id)
const char *con_id)
{ {
struct pwm_device *pwm = NULL; struct pwm_device *pwm = NULL;
struct of_phandle_args args; struct of_phandle_args args;
...@@ -545,6 +544,7 @@ static struct pwm_device *of_pwm_request(struct device_node *np, ...@@ -545,6 +544,7 @@ static struct pwm_device *of_pwm_request(struct device_node *np,
return pwm; return pwm;
} }
EXPORT_SYMBOL_GPL(of_pwm_get);
/** /**
* pwm_add_table() - register PWM device consumers * pwm_add_table() - register PWM device consumers
...@@ -587,7 +587,7 @@ struct pwm_device *pwm_get(struct device *dev, const char *con_id) ...@@ -587,7 +587,7 @@ struct pwm_device *pwm_get(struct device *dev, const char *con_id)
/* look up via DT first */ /* look up via DT first */
if (IS_ENABLED(CONFIG_OF) && dev && dev->of_node) if (IS_ENABLED(CONFIG_OF) && dev && dev->of_node)
return of_pwm_request(dev->of_node, con_id); return of_pwm_get(dev->of_node, con_id);
/* /*
* We look up the provider in the static table typically provided by * We look up the provider in the static table typically provided by
...@@ -708,6 +708,36 @@ struct pwm_device *devm_pwm_get(struct device *dev, const char *con_id) ...@@ -708,6 +708,36 @@ struct pwm_device *devm_pwm_get(struct device *dev, const char *con_id)
} }
EXPORT_SYMBOL_GPL(devm_pwm_get); EXPORT_SYMBOL_GPL(devm_pwm_get);
/**
* devm_of_pwm_get() - resource managed of_pwm_get()
* @dev: device for PWM consumer
* @np: device node to get the PWM from
* @con_id: consumer name
*
* This function performs like of_pwm_get() but the acquired PWM device will
* automatically be released on driver detach.
*/
struct pwm_device *devm_of_pwm_get(struct device *dev, struct device_node *np,
const char *con_id)
{
struct pwm_device **ptr, *pwm;
ptr = devres_alloc(devm_pwm_release, sizeof(**ptr), GFP_KERNEL);
if (!ptr)
return ERR_PTR(-ENOMEM);
pwm = of_pwm_get(np, con_id);
if (!IS_ERR(pwm)) {
*ptr = pwm;
devres_add(dev, ptr);
} else {
devres_free(ptr);
}
return pwm;
}
EXPORT_SYMBOL_GPL(devm_of_pwm_get);
static int devm_pwm_match(struct device *dev, void *res, void *data) static int devm_pwm_match(struct device *dev, void *res, void *data)
{ {
struct pwm_device **p = res; struct pwm_device **p = res;
......
/*
* LP5523 LED Driver
*
* Copyright (C) 2010 Nokia Corporation
*
* Contact: Samu Onkalo <samu.p.onkalo@nokia.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.
*
* 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., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA
*/
#ifndef __LINUX_LP5523_H
#define __LINUX_LP5523_H
/* See Documentation/leds/leds-lp5523.txt */
struct lp5523_led_config {
const char *name;
u8 chan_nr;
u8 led_current; /* mA x10, 0 if led is not connected */
u8 max_current;
};
#define LP5523_CLOCK_AUTO 0
#define LP5523_CLOCK_INT 1
#define LP5523_CLOCK_EXT 2
struct lp5523_platform_data {
struct lp5523_led_config *led_config;
u8 num_channels;
u8 clock_mode;
int (*setup_resources)(void);
void (*release_resources)(void);
void (*enable)(bool state);
const char *label;
};
#endif /* __LINUX_LP5523_H */
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
struct led_pwm { struct led_pwm {
const char *name; const char *name;
const char *default_trigger; const char *default_trigger;
unsigned pwm_id; unsigned pwm_id __deprecated;
u8 active_low; u8 active_low;
unsigned max_brightness; unsigned max_brightness;
unsigned pwm_period_ns; unsigned pwm_period_ns;
......
/* /*
* LP5521 LED chip driver. * LP55XX Platform Data Header
* *
* Copyright (C) 2010 Nokia Corporation * Copyright (C) 2012 Texas Instruments
* *
* Contact: Samu Onkalo <samu.p.onkalo@nokia.com> * Author: Milo(Woogyom) Kim <milo.kim@ti.com>
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License * modify it under the terms of the GNU General Public License
* version 2 as published by the Free Software Foundation. * version 2 as published by the Free Software Foundation.
* *
* This program is distributed in the hope that it will be useful, but * Derived from leds-lp5521.h, leds-lp5523.h
* 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., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA
*/ */
#ifndef __LINUX_LP5521_H #ifndef _LEDS_LP55XX_H
#define __LINUX_LP5521_H #define _LEDS_LP55XX_H
/* See Documentation/leds/leds-lp5521.txt */
struct lp5521_led_config { /* Clock configuration */
char *name; #define LP55XX_CLOCK_AUTO 0
u8 chan_nr; #define LP55XX_CLOCK_INT 1
u8 led_current; /* mA x10, 0 if led is not connected */ #define LP55XX_CLOCK_EXT 2
u8 max_current;
};
struct lp5521_led_pattern { /* Bits in LP5521 CONFIG register. 'update_config' in lp55xx_platform_data */
u8 *r;
u8 *g;
u8 *b;
u8 size_r;
u8 size_g;
u8 size_b;
};
#define LP5521_CLOCK_AUTO 0
#define LP5521_CLOCK_INT 1
#define LP5521_CLOCK_EXT 2
/* Bits in CONFIG register */
#define LP5521_PWM_HF 0x40 /* PWM: 0 = 256Hz, 1 = 558Hz */ #define LP5521_PWM_HF 0x40 /* PWM: 0 = 256Hz, 1 = 558Hz */
#define LP5521_PWRSAVE_EN 0x20 /* 1 = Power save mode */ #define LP5521_PWRSAVE_EN 0x20 /* 1 = Power save mode */
#define LP5521_CP_MODE_OFF 0 /* Charge pump (CP) off */ #define LP5521_CP_MODE_OFF 0 /* Charge pump (CP) off */
...@@ -57,17 +32,56 @@ struct lp5521_led_pattern { ...@@ -57,17 +32,56 @@ struct lp5521_led_pattern {
#define LP5521_CLK_INT 1 /* Internal clock */ #define LP5521_CLK_INT 1 /* Internal clock */
#define LP5521_CLK_AUTO 2 /* Automatic clock selection */ #define LP5521_CLK_AUTO 2 /* Automatic clock selection */
struct lp5521_platform_data { struct lp55xx_led_config {
struct lp5521_led_config *led_config; const char *name;
u8 num_channels; u8 chan_nr;
u8 clock_mode; u8 led_current; /* mA x10, 0 if led is not connected */
int (*setup_resources)(void); u8 max_current;
void (*release_resources)(void); };
void (*enable)(bool state);
struct lp55xx_predef_pattern {
u8 *r;
u8 *g;
u8 *b;
u8 size_r;
u8 size_g;
u8 size_b;
};
/*
* struct lp55xx_platform_data
* @led_config : Configurable led class device
* @num_channels : Number of LED channels
* @label : Used for naming LEDs
* @clock_mode : Input clock mode. LP55XX_CLOCK_AUTO or _INT or _EXT
* @setup_resources : Platform specific function before enabling the chip
* @release_resources : Platform specific function after disabling the chip
* @enable : EN pin control by platform side
* @patterns : Predefined pattern data for RGB channels
* @num_patterns : Number of patterns
* @update_config : Value of CONFIG register
*/
struct lp55xx_platform_data {
/* LED channel configuration */
struct lp55xx_led_config *led_config;
u8 num_channels;
const char *label; const char *label;
u8 update_config;
struct lp5521_led_pattern *patterns; /* Clock configuration */
int num_patterns; u8 clock_mode;
/* Platform specific functions */
int (*setup_resources)(void);
void (*release_resources)(void);
void (*enable)(bool state);
/* Predefined pattern data */
struct lp55xx_predef_pattern *patterns;
unsigned int num_patterns;
/* _CONFIG register */
u8 update_config;
}; };
#endif /* __LINUX_LP5521_H */ #endif /* _LEDS_LP55XX_H */
...@@ -174,10 +174,13 @@ struct pwm_device *pwm_request_from_chip(struct pwm_chip *chip, ...@@ -174,10 +174,13 @@ struct pwm_device *pwm_request_from_chip(struct pwm_chip *chip,
struct pwm_device *of_pwm_xlate_with_flags(struct pwm_chip *pc, struct pwm_device *of_pwm_xlate_with_flags(struct pwm_chip *pc,
const struct of_phandle_args *args); const struct of_phandle_args *args);
struct pwm_device *pwm_get(struct device *dev, const char *consumer); struct pwm_device *pwm_get(struct device *dev, const char *con_id);
struct pwm_device *of_pwm_get(struct device_node *np, const char *con_id);
void pwm_put(struct pwm_device *pwm); void pwm_put(struct pwm_device *pwm);
struct pwm_device *devm_pwm_get(struct device *dev, const char *consumer); struct pwm_device *devm_pwm_get(struct device *dev, const char *con_id);
struct pwm_device *devm_of_pwm_get(struct device *dev, struct device_node *np,
const char *con_id);
void devm_pwm_put(struct device *dev, struct pwm_device *pwm); void devm_pwm_put(struct device *dev, struct pwm_device *pwm);
#else #else
static inline int pwm_set_chip_data(struct pwm_device *pwm, void *data) static inline int pwm_set_chip_data(struct pwm_device *pwm, void *data)
...@@ -213,6 +216,12 @@ static inline struct pwm_device *pwm_get(struct device *dev, ...@@ -213,6 +216,12 @@ static inline struct pwm_device *pwm_get(struct device *dev,
return ERR_PTR(-ENODEV); return ERR_PTR(-ENODEV);
} }
static inline struct pwm_device *of_pwm_get(struct device_node *np,
const char *con_id)
{
return ERR_PTR(-ENODEV);
}
static inline void pwm_put(struct pwm_device *pwm) static inline void pwm_put(struct pwm_device *pwm)
{ {
} }
...@@ -223,6 +232,13 @@ static inline struct pwm_device *devm_pwm_get(struct device *dev, ...@@ -223,6 +232,13 @@ static inline struct pwm_device *devm_pwm_get(struct device *dev,
return ERR_PTR(-ENODEV); return ERR_PTR(-ENODEV);
} }
static inline struct pwm_device *devm_of_pwm_get(struct device *dev,
struct device_node *np,
const char *con_id)
{
return ERR_PTR(-ENODEV);
}
static inline void devm_pwm_put(struct device *dev, struct pwm_device *pwm) static inline void devm_pwm_put(struct device *dev, struct pwm_device *pwm)
{ {
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment