mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-09-29 13:53:33 +00:00
Merge branch 'for-next' of git://git.kernel.org/pub/scm/linux/kernel/git/cooloney/linux-leds
Pull LED subsystem update from Bryan Wu: "Basically this cycle is mostly cleanup for LED subsystem" * 'for-next' of git://git.kernel.org/pub/scm/linux/kernel/git/cooloney/linux-leds: leds: s3c24xx: Remove hardware.h inclusion leds: replace list_for_each with list_for_each_entry leds: kirkwood: Cleanup in header files leds: pwm: Remove a warning on non-DT platforms leds: leds-pwm: fix duty time overflow. leds: leds-mc13783: Remove unneeded mc13xxx_{un}lock leds: leds-mc13783: Remove duplicate field in platform data drivers: leds: leds-tca6507: check CONFIG_GPIOLIB whether defined for 'gpio_base' leds: lp5523: Support LED MUX configuration on running a pattern leds: lp5521/5523: Fix multiple engine usage bug LEDS: tca6507 - fix up some comments. LEDS: tca6507: add device-tree support for GPIO configuration. LEDS: tca6507 - fix bugs in parsing of device-tree configuration.
This commit is contained in:
commit
268943fb75
14 changed files with 226 additions and 230 deletions
|
@ -2,6 +2,13 @@ LEDs connected to tca6507
|
||||||
|
|
||||||
Required properties:
|
Required properties:
|
||||||
- compatible : should be : "ti,tca6507".
|
- compatible : should be : "ti,tca6507".
|
||||||
|
- #address-cells: must be 1
|
||||||
|
- #size-cells: must be 0
|
||||||
|
- reg: typically 0x45.
|
||||||
|
|
||||||
|
Optional properties:
|
||||||
|
- gpio-controller: allows lines to be used as output-only GPIOs.
|
||||||
|
- #gpio-cells: if present, must be 0.
|
||||||
|
|
||||||
Each led is represented as a sub-node of the ti,tca6507 device.
|
Each led is represented as a sub-node of the ti,tca6507 device.
|
||||||
|
|
||||||
|
@ -10,6 +17,7 @@ LED sub-node properties:
|
||||||
- reg : number of LED line (could be from 0 to 6)
|
- reg : number of LED line (could be from 0 to 6)
|
||||||
- linux,default-trigger : (optional)
|
- linux,default-trigger : (optional)
|
||||||
see Documentation/devicetree/bindings/leds/common.txt
|
see Documentation/devicetree/bindings/leds/common.txt
|
||||||
|
- compatible: either "led" (the default) or "gpio".
|
||||||
|
|
||||||
Examples:
|
Examples:
|
||||||
|
|
||||||
|
@ -19,6 +27,9 @@ tca6507@45 {
|
||||||
#size-cells = <0>;
|
#size-cells = <0>;
|
||||||
reg = <0x45>;
|
reg = <0x45>;
|
||||||
|
|
||||||
|
gpio-controller;
|
||||||
|
#gpio-cells = <2>;
|
||||||
|
|
||||||
led0: red-aux@0 {
|
led0: red-aux@0 {
|
||||||
label = "red:aux";
|
label = "red:aux";
|
||||||
reg = <0x0>;
|
reg = <0x0>;
|
||||||
|
@ -29,5 +40,10 @@ tca6507@45 {
|
||||||
reg = <0x5>;
|
reg = <0x5>;
|
||||||
linux,default-trigger = "default-on";
|
linux,default-trigger = "default-on";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
wifi-reset@6 {
|
||||||
|
reg = <0x6>;
|
||||||
|
compatible = "gpio";
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -73,6 +73,10 @@ select_engine : Select which engine is used for running program
|
||||||
run_engine : Start program which is loaded via the firmware interface
|
run_engine : Start program which is loaded via the firmware interface
|
||||||
firmware : Load program data
|
firmware : Load program data
|
||||||
|
|
||||||
|
In case of LP5523, one more command is required, 'enginex_leds'.
|
||||||
|
It is used for selecting LED output(s) at each engine number.
|
||||||
|
In more details, please refer to 'leds-lp5523.txt'.
|
||||||
|
|
||||||
For example, run blinking pattern in engine #1 of LP5521
|
For example, run blinking pattern in engine #1 of LP5521
|
||||||
echo 1 > /sys/bus/i2c/devices/xxxx/select_engine
|
echo 1 > /sys/bus/i2c/devices/xxxx/select_engine
|
||||||
echo 1 > /sys/class/firmware/lp5521/loading
|
echo 1 > /sys/class/firmware/lp5521/loading
|
||||||
|
@ -81,10 +85,12 @@ echo 0 > /sys/class/firmware/lp5521/loading
|
||||||
echo 1 > /sys/bus/i2c/devices/xxxx/run_engine
|
echo 1 > /sys/bus/i2c/devices/xxxx/run_engine
|
||||||
|
|
||||||
For example, run blinking pattern in engine #3 of LP55231
|
For example, run blinking pattern in engine #3 of LP55231
|
||||||
|
Two LEDs are configured as pattern output channels.
|
||||||
echo 3 > /sys/bus/i2c/devices/xxxx/select_engine
|
echo 3 > /sys/bus/i2c/devices/xxxx/select_engine
|
||||||
echo 1 > /sys/class/firmware/lp55231/loading
|
echo 1 > /sys/class/firmware/lp55231/loading
|
||||||
echo "9d0740ff7e0040007e00a0010000" > /sys/class/firmware/lp55231/data
|
echo "9d0740ff7e0040007e00a0010000" > /sys/class/firmware/lp55231/data
|
||||||
echo 0 > /sys/class/firmware/lp55231/loading
|
echo 0 > /sys/class/firmware/lp55231/loading
|
||||||
|
echo "000001100" > /sys/bus/i2c/devices/xxxx/engine3_leds
|
||||||
echo 1 > /sys/bus/i2c/devices/xxxx/run_engine
|
echo 1 > /sys/bus/i2c/devices/xxxx/run_engine
|
||||||
|
|
||||||
To start blinking patterns in engine #2 and #3 simultaneously,
|
To start blinking patterns in engine #2 and #3 simultaneously,
|
||||||
|
@ -99,17 +105,19 @@ done
|
||||||
echo 1 > /sys/class/leds/red/device/run_engine
|
echo 1 > /sys/class/leds/red/device/run_engine
|
||||||
|
|
||||||
Here is another example for LP5523.
|
Here is another example for LP5523.
|
||||||
|
Full LED strings are selected by 'engine2_leds'.
|
||||||
echo 2 > /sys/bus/i2c/devices/xxxx/select_engine
|
echo 2 > /sys/bus/i2c/devices/xxxx/select_engine
|
||||||
echo 1 > /sys/class/firmware/lp5523/loading
|
echo 1 > /sys/class/firmware/lp5523/loading
|
||||||
echo "9d80400004ff05ff437f0000" > /sys/class/firmware/lp5523/data
|
echo "9d80400004ff05ff437f0000" > /sys/class/firmware/lp5523/data
|
||||||
echo 0 > /sys/class/firmware/lp5523/loading
|
echo 0 > /sys/class/firmware/lp5523/loading
|
||||||
|
echo "111111111" > /sys/bus/i2c/devices/xxxx/engine2_leds
|
||||||
echo 1 > /sys/bus/i2c/devices/xxxx/run_engine
|
echo 1 > /sys/bus/i2c/devices/xxxx/run_engine
|
||||||
|
|
||||||
As soon as 'loading' is set to 0, registered callback is called.
|
As soon as 'loading' is set to 0, registered callback is called.
|
||||||
Inside the callback, the selected engine is loaded and memory is updated.
|
Inside the callback, the selected engine is loaded and memory is updated.
|
||||||
To run programmed pattern, 'run_engine' attribute should be enabled.
|
To run programmed pattern, 'run_engine' attribute should be enabled.
|
||||||
|
|
||||||
The pattern sqeuence of LP8501 is same as LP5523.
|
The pattern sqeuence of LP8501 is similar to LP5523.
|
||||||
However pattern data is specific.
|
However pattern data is specific.
|
||||||
Ex 1) Engine 1 is used
|
Ex 1) Engine 1 is used
|
||||||
echo 1 > /sys/bus/i2c/devices/xxxx/select_engine
|
echo 1 > /sys/bus/i2c/devices/xxxx/select_engine
|
||||||
|
|
|
@ -236,32 +236,26 @@ static struct mc13xxx_led_platform_data moboard_led[] = {
|
||||||
{
|
{
|
||||||
.id = MC13783_LED_R1,
|
.id = MC13783_LED_R1,
|
||||||
.name = "coreboard-led-4:red",
|
.name = "coreboard-led-4:red",
|
||||||
.max_current = 2,
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
.id = MC13783_LED_G1,
|
.id = MC13783_LED_G1,
|
||||||
.name = "coreboard-led-4:green",
|
.name = "coreboard-led-4:green",
|
||||||
.max_current = 2,
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
.id = MC13783_LED_B1,
|
.id = MC13783_LED_B1,
|
||||||
.name = "coreboard-led-4:blue",
|
.name = "coreboard-led-4:blue",
|
||||||
.max_current = 2,
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
.id = MC13783_LED_R2,
|
.id = MC13783_LED_R2,
|
||||||
.name = "coreboard-led-5:red",
|
.name = "coreboard-led-5:red",
|
||||||
.max_current = 3,
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
.id = MC13783_LED_G2,
|
.id = MC13783_LED_G2,
|
||||||
.name = "coreboard-led-5:green",
|
.name = "coreboard-led-5:green",
|
||||||
.max_current = 3,
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
.id = MC13783_LED_B2,
|
.id = MC13783_LED_B2,
|
||||||
.name = "coreboard-led-5:blue",
|
.name = "coreboard-led-5:blue",
|
||||||
.max_current = 3,
|
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -271,8 +265,14 @@ static struct mc13xxx_leds_platform_data moboard_leds = {
|
||||||
.led_control[0] = MC13783_LED_C0_ENABLE | MC13783_LED_C0_ABMODE(0),
|
.led_control[0] = MC13783_LED_C0_ENABLE | MC13783_LED_C0_ABMODE(0),
|
||||||
.led_control[1] = MC13783_LED_C1_SLEWLIM,
|
.led_control[1] = MC13783_LED_C1_SLEWLIM,
|
||||||
.led_control[2] = MC13783_LED_C2_SLEWLIM,
|
.led_control[2] = MC13783_LED_C2_SLEWLIM,
|
||||||
.led_control[3] = MC13783_LED_C3_PERIOD(0),
|
.led_control[3] = MC13783_LED_C3_PERIOD(0) |
|
||||||
.led_control[4] = MC13783_LED_C3_PERIOD(0),
|
MC13783_LED_C3_CURRENT_R1(2) |
|
||||||
|
MC13783_LED_C3_CURRENT_G1(2) |
|
||||||
|
MC13783_LED_C3_CURRENT_B1(2),
|
||||||
|
.led_control[4] = MC13783_LED_C4_PERIOD(0) |
|
||||||
|
MC13783_LED_C4_CURRENT_R2(3) |
|
||||||
|
MC13783_LED_C4_CURRENT_G2(3) |
|
||||||
|
MC13783_LED_C4_CURRENT_B2(3),
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct mc13xxx_buttons_platform_data moboard_buttons = {
|
static struct mc13xxx_buttons_platform_data moboard_buttons = {
|
||||||
|
|
|
@ -242,18 +242,14 @@ EXPORT_SYMBOL_GPL(led_trigger_unregister);
|
||||||
void led_trigger_event(struct led_trigger *trig,
|
void led_trigger_event(struct led_trigger *trig,
|
||||||
enum led_brightness brightness)
|
enum led_brightness brightness)
|
||||||
{
|
{
|
||||||
struct list_head *entry;
|
struct led_classdev *led_cdev;
|
||||||
|
|
||||||
if (!trig)
|
if (!trig)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
read_lock(&trig->leddev_list_lock);
|
read_lock(&trig->leddev_list_lock);
|
||||||
list_for_each(entry, &trig->led_cdevs) {
|
list_for_each_entry(led_cdev, &trig->led_cdevs, trig_list)
|
||||||
struct led_classdev *led_cdev;
|
|
||||||
|
|
||||||
led_cdev = list_entry(entry, struct led_classdev, trig_list);
|
|
||||||
led_set_brightness(led_cdev, brightness);
|
led_set_brightness(led_cdev, brightness);
|
||||||
}
|
|
||||||
read_unlock(&trig->leddev_list_lock);
|
read_unlock(&trig->leddev_list_lock);
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(led_trigger_event);
|
EXPORT_SYMBOL_GPL(led_trigger_event);
|
||||||
|
@ -264,16 +260,13 @@ static void led_trigger_blink_setup(struct led_trigger *trig,
|
||||||
int oneshot,
|
int oneshot,
|
||||||
int invert)
|
int invert)
|
||||||
{
|
{
|
||||||
struct list_head *entry;
|
struct led_classdev *led_cdev;
|
||||||
|
|
||||||
if (!trig)
|
if (!trig)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
read_lock(&trig->leddev_list_lock);
|
read_lock(&trig->leddev_list_lock);
|
||||||
list_for_each(entry, &trig->led_cdevs) {
|
list_for_each_entry(led_cdev, &trig->led_cdevs, trig_list) {
|
||||||
struct led_classdev *led_cdev;
|
|
||||||
|
|
||||||
led_cdev = list_entry(entry, struct led_classdev, trig_list);
|
|
||||||
if (oneshot)
|
if (oneshot)
|
||||||
led_blink_set_oneshot(led_cdev, delay_on, delay_off,
|
led_blink_set_oneshot(led_cdev, delay_on, delay_off,
|
||||||
invert);
|
invert);
|
||||||
|
|
|
@ -152,12 +152,26 @@ static void lp5521_load_engine(struct lp55xx_chip *chip)
|
||||||
lp5521_wait_opmode_done();
|
lp5521_wait_opmode_done();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void lp5521_stop_engine(struct lp55xx_chip *chip)
|
static void lp5521_stop_all_engines(struct lp55xx_chip *chip)
|
||||||
{
|
{
|
||||||
lp55xx_write(chip, LP5521_REG_OP_MODE, 0);
|
lp55xx_write(chip, LP5521_REG_OP_MODE, 0);
|
||||||
lp5521_wait_opmode_done();
|
lp5521_wait_opmode_done();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void lp5521_stop_engine(struct lp55xx_chip *chip)
|
||||||
|
{
|
||||||
|
enum lp55xx_engine_index idx = chip->engine_idx;
|
||||||
|
u8 mask[] = {
|
||||||
|
[LP55XX_ENGINE_1] = LP5521_MODE_R_M,
|
||||||
|
[LP55XX_ENGINE_2] = LP5521_MODE_G_M,
|
||||||
|
[LP55XX_ENGINE_3] = LP5521_MODE_B_M,
|
||||||
|
};
|
||||||
|
|
||||||
|
lp55xx_update_bits(chip, LP5521_REG_OP_MODE, mask[idx], 0);
|
||||||
|
|
||||||
|
lp5521_wait_opmode_done();
|
||||||
|
}
|
||||||
|
|
||||||
static void lp5521_run_engine(struct lp55xx_chip *chip, bool start)
|
static void lp5521_run_engine(struct lp55xx_chip *chip, bool start)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
|
@ -564,7 +578,7 @@ static int lp5521_remove(struct i2c_client *client)
|
||||||
struct lp55xx_led *led = i2c_get_clientdata(client);
|
struct lp55xx_led *led = i2c_get_clientdata(client);
|
||||||
struct lp55xx_chip *chip = led->chip;
|
struct lp55xx_chip *chip = led->chip;
|
||||||
|
|
||||||
lp5521_stop_engine(chip);
|
lp5521_stop_all_engines(chip);
|
||||||
lp55xx_unregister_sysfs(chip);
|
lp55xx_unregister_sysfs(chip);
|
||||||
lp55xx_unregister_leds(led, chip);
|
lp55xx_unregister_leds(led, chip);
|
||||||
lp55xx_deinit_device(chip);
|
lp55xx_deinit_device(chip);
|
||||||
|
|
|
@ -195,12 +195,26 @@ static void lp5523_load_engine_and_select_page(struct lp55xx_chip *chip)
|
||||||
lp55xx_write(chip, LP5523_REG_PROG_PAGE_SEL, page_sel[idx]);
|
lp55xx_write(chip, LP5523_REG_PROG_PAGE_SEL, page_sel[idx]);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void lp5523_stop_engine(struct lp55xx_chip *chip)
|
static void lp5523_stop_all_engines(struct lp55xx_chip *chip)
|
||||||
{
|
{
|
||||||
lp55xx_write(chip, LP5523_REG_OP_MODE, 0);
|
lp55xx_write(chip, LP5523_REG_OP_MODE, 0);
|
||||||
lp5523_wait_opmode_done();
|
lp5523_wait_opmode_done();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void lp5523_stop_engine(struct lp55xx_chip *chip)
|
||||||
|
{
|
||||||
|
enum lp55xx_engine_index idx = chip->engine_idx;
|
||||||
|
u8 mask[] = {
|
||||||
|
[LP55XX_ENGINE_1] = LP5523_MODE_ENG1_M,
|
||||||
|
[LP55XX_ENGINE_2] = LP5523_MODE_ENG2_M,
|
||||||
|
[LP55XX_ENGINE_3] = LP5523_MODE_ENG3_M,
|
||||||
|
};
|
||||||
|
|
||||||
|
lp55xx_update_bits(chip, LP5523_REG_OP_MODE, mask[idx], 0);
|
||||||
|
|
||||||
|
lp5523_wait_opmode_done();
|
||||||
|
}
|
||||||
|
|
||||||
static void lp5523_turn_off_channels(struct lp55xx_chip *chip)
|
static void lp5523_turn_off_channels(struct lp55xx_chip *chip)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
@ -311,7 +325,7 @@ static int lp5523_init_program_engine(struct lp55xx_chip *chip)
|
||||||
}
|
}
|
||||||
|
|
||||||
out:
|
out:
|
||||||
lp5523_stop_engine(chip);
|
lp5523_stop_all_engines(chip);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -782,7 +796,7 @@ static int lp5523_remove(struct i2c_client *client)
|
||||||
struct lp55xx_led *led = i2c_get_clientdata(client);
|
struct lp55xx_led *led = i2c_get_clientdata(client);
|
||||||
struct lp55xx_chip *chip = led->chip;
|
struct lp55xx_chip *chip = led->chip;
|
||||||
|
|
||||||
lp5523_stop_engine(chip);
|
lp5523_stop_all_engines(chip);
|
||||||
lp55xx_unregister_sysfs(chip);
|
lp55xx_unregister_sysfs(chip);
|
||||||
lp55xx_unregister_leds(led, chip);
|
lp55xx_unregister_leds(led, chip);
|
||||||
lp55xx_deinit_device(chip);
|
lp55xx_deinit_device(chip);
|
||||||
|
|
|
@ -210,6 +210,7 @@ static void lp55xx_firmware_loaded(const struct firmware *fw, void *context)
|
||||||
{
|
{
|
||||||
struct lp55xx_chip *chip = context;
|
struct lp55xx_chip *chip = context;
|
||||||
struct device *dev = &chip->cl->dev;
|
struct device *dev = &chip->cl->dev;
|
||||||
|
enum lp55xx_engine_index idx = chip->engine_idx;
|
||||||
|
|
||||||
if (!fw) {
|
if (!fw) {
|
||||||
dev_err(dev, "firmware request failed\n");
|
dev_err(dev, "firmware request failed\n");
|
||||||
|
@ -219,6 +220,7 @@ static void lp55xx_firmware_loaded(const struct firmware *fw, void *context)
|
||||||
/* handling firmware data is chip dependent */
|
/* handling firmware data is chip dependent */
|
||||||
mutex_lock(&chip->lock);
|
mutex_lock(&chip->lock);
|
||||||
|
|
||||||
|
chip->engines[idx - 1].mode = LP55XX_ENGINE_LOAD;
|
||||||
chip->fw = fw;
|
chip->fw = fw;
|
||||||
if (chip->cfg->firmware_cb)
|
if (chip->cfg->firmware_cb)
|
||||||
chip->cfg->firmware_cb(chip);
|
chip->cfg->firmware_cb(chip);
|
||||||
|
|
|
@ -117,9 +117,7 @@ static void mc13xxx_led_work(struct work_struct *work)
|
||||||
BUG();
|
BUG();
|
||||||
}
|
}
|
||||||
|
|
||||||
mc13xxx_lock(led->master);
|
|
||||||
mc13xxx_reg_rmw(led->master, reg, mask << shift, value << shift);
|
mc13xxx_reg_rmw(led->master, reg, mask << shift, value << shift);
|
||||||
mc13xxx_unlock(led->master);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void mc13xxx_led_set(struct led_classdev *led_cdev,
|
static void mc13xxx_led_set(struct led_classdev *led_cdev,
|
||||||
|
@ -132,75 +130,6 @@ static void mc13xxx_led_set(struct led_classdev *led_cdev,
|
||||||
schedule_work(&led->work);
|
schedule_work(&led->work);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int __init mc13xxx_led_setup(struct mc13xxx_led *led, int max_current)
|
|
||||||
{
|
|
||||||
int shift, mask, reg, ret, bank;
|
|
||||||
|
|
||||||
switch (led->id) {
|
|
||||||
case MC13783_LED_MD:
|
|
||||||
reg = MC13XXX_REG_LED_CONTROL(2);
|
|
||||||
shift = 0;
|
|
||||||
mask = 0x07;
|
|
||||||
break;
|
|
||||||
case MC13783_LED_AD:
|
|
||||||
reg = MC13XXX_REG_LED_CONTROL(2);
|
|
||||||
shift = 3;
|
|
||||||
mask = 0x07;
|
|
||||||
break;
|
|
||||||
case MC13783_LED_KP:
|
|
||||||
reg = MC13XXX_REG_LED_CONTROL(2);
|
|
||||||
shift = 6;
|
|
||||||
mask = 0x07;
|
|
||||||
break;
|
|
||||||
case MC13783_LED_R1:
|
|
||||||
case MC13783_LED_G1:
|
|
||||||
case MC13783_LED_B1:
|
|
||||||
case MC13783_LED_R2:
|
|
||||||
case MC13783_LED_G2:
|
|
||||||
case MC13783_LED_B2:
|
|
||||||
case MC13783_LED_R3:
|
|
||||||
case MC13783_LED_G3:
|
|
||||||
case MC13783_LED_B3:
|
|
||||||
bank = (led->id - MC13783_LED_R1) / 3;
|
|
||||||
reg = MC13XXX_REG_LED_CONTROL(3) + bank;
|
|
||||||
shift = ((led->id - MC13783_LED_R1) - bank * 3) * 2;
|
|
||||||
mask = 0x03;
|
|
||||||
break;
|
|
||||||
case MC13892_LED_MD:
|
|
||||||
reg = MC13XXX_REG_LED_CONTROL(0);
|
|
||||||
shift = 9;
|
|
||||||
mask = 0x07;
|
|
||||||
break;
|
|
||||||
case MC13892_LED_AD:
|
|
||||||
reg = MC13XXX_REG_LED_CONTROL(0);
|
|
||||||
shift = 21;
|
|
||||||
mask = 0x07;
|
|
||||||
break;
|
|
||||||
case MC13892_LED_KP:
|
|
||||||
reg = MC13XXX_REG_LED_CONTROL(1);
|
|
||||||
shift = 9;
|
|
||||||
mask = 0x07;
|
|
||||||
break;
|
|
||||||
case MC13892_LED_R:
|
|
||||||
case MC13892_LED_G:
|
|
||||||
case MC13892_LED_B:
|
|
||||||
bank = (led->id - MC13892_LED_R) / 2;
|
|
||||||
reg = MC13XXX_REG_LED_CONTROL(2) + bank;
|
|
||||||
shift = ((led->id - MC13892_LED_R) - bank * 2) * 12 + 9;
|
|
||||||
mask = 0x07;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
BUG();
|
|
||||||
}
|
|
||||||
|
|
||||||
mc13xxx_lock(led->master);
|
|
||||||
ret = mc13xxx_reg_rmw(led->master, reg, mask << shift,
|
|
||||||
max_current << shift);
|
|
||||||
mc13xxx_unlock(led->master);
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int __init mc13xxx_led_probe(struct platform_device *pdev)
|
static int __init mc13xxx_led_probe(struct platform_device *pdev)
|
||||||
{
|
{
|
||||||
struct mc13xxx_leds_platform_data *pdata = dev_get_platdata(&pdev->dev);
|
struct mc13xxx_leds_platform_data *pdata = dev_get_platdata(&pdev->dev);
|
||||||
|
@ -233,31 +162,22 @@ static int __init mc13xxx_led_probe(struct platform_device *pdev)
|
||||||
leds->num_leds = num_leds;
|
leds->num_leds = num_leds;
|
||||||
platform_set_drvdata(pdev, leds);
|
platform_set_drvdata(pdev, leds);
|
||||||
|
|
||||||
mc13xxx_lock(mcdev);
|
|
||||||
for (i = 0; i < devtype->num_regs; i++) {
|
for (i = 0; i < devtype->num_regs; i++) {
|
||||||
reg = pdata->led_control[i];
|
reg = pdata->led_control[i];
|
||||||
WARN_ON(reg >= (1 << 24));
|
WARN_ON(reg >= (1 << 24));
|
||||||
ret = mc13xxx_reg_write(mcdev, MC13XXX_REG_LED_CONTROL(i), reg);
|
ret = mc13xxx_reg_write(mcdev, MC13XXX_REG_LED_CONTROL(i), reg);
|
||||||
if (ret)
|
if (ret)
|
||||||
break;
|
return ret;
|
||||||
}
|
|
||||||
mc13xxx_unlock(mcdev);
|
|
||||||
|
|
||||||
if (ret) {
|
|
||||||
dev_err(&pdev->dev, "Unable to init LED driver\n");
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0; i < num_leds; i++) {
|
for (i = 0; i < num_leds; i++) {
|
||||||
const char *name, *trig;
|
const char *name, *trig;
|
||||||
char max_current;
|
|
||||||
|
|
||||||
ret = -EINVAL;
|
ret = -EINVAL;
|
||||||
|
|
||||||
id = pdata->led[i].id;
|
id = pdata->led[i].id;
|
||||||
name = pdata->led[i].name;
|
name = pdata->led[i].name;
|
||||||
trig = pdata->led[i].default_trigger;
|
trig = pdata->led[i].default_trigger;
|
||||||
max_current = pdata->led[i].max_current;
|
|
||||||
|
|
||||||
if ((id > devtype->led_max) || (id < devtype->led_min)) {
|
if ((id > devtype->led_max) || (id < devtype->led_min)) {
|
||||||
dev_err(&pdev->dev, "Invalid ID %i\n", id);
|
dev_err(&pdev->dev, "Invalid ID %i\n", id);
|
||||||
|
@ -280,11 +200,6 @@ static int __init mc13xxx_led_probe(struct platform_device *pdev)
|
||||||
|
|
||||||
INIT_WORK(&leds->led[i].work, mc13xxx_led_work);
|
INIT_WORK(&leds->led[i].work, mc13xxx_led_work);
|
||||||
|
|
||||||
ret = mc13xxx_led_setup(&leds->led[i], max_current);
|
|
||||||
if (ret) {
|
|
||||||
dev_err(&pdev->dev, "Unable to setup LED %i\n", id);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
ret = led_classdev_register(pdev->dev.parent,
|
ret = led_classdev_register(pdev->dev.parent,
|
||||||
&leds->led[i].cdev);
|
&leds->led[i].cdev);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
|
@ -313,10 +228,8 @@ static int mc13xxx_led_remove(struct platform_device *pdev)
|
||||||
cancel_work_sync(&leds->led[i].work);
|
cancel_work_sync(&leds->led[i].work);
|
||||||
}
|
}
|
||||||
|
|
||||||
mc13xxx_lock(mcdev);
|
|
||||||
for (i = 0; i < leds->devtype->num_regs; i++)
|
for (i = 0; i < leds->devtype->num_regs; i++)
|
||||||
mc13xxx_reg_write(mcdev, MC13XXX_REG_LED_CONTROL(i), 0);
|
mc13xxx_reg_write(mcdev, MC13XXX_REG_LED_CONTROL(i), 0);
|
||||||
mc13xxx_unlock(mcdev);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -66,9 +66,11 @@ static void led_pwm_set(struct led_classdev *led_cdev,
|
||||||
struct led_pwm_data *led_dat =
|
struct led_pwm_data *led_dat =
|
||||||
container_of(led_cdev, struct led_pwm_data, cdev);
|
container_of(led_cdev, struct led_pwm_data, cdev);
|
||||||
unsigned int max = led_dat->cdev.max_brightness;
|
unsigned int max = led_dat->cdev.max_brightness;
|
||||||
unsigned int period = led_dat->period;
|
unsigned long long duty = led_dat->period;
|
||||||
|
|
||||||
led_dat->duty = brightness * period / max;
|
duty *= brightness;
|
||||||
|
do_div(duty, max);
|
||||||
|
led_dat->duty = duty;
|
||||||
|
|
||||||
if (led_dat->can_sleep)
|
if (led_dat->can_sleep)
|
||||||
schedule_work(&led_dat->work);
|
schedule_work(&led_dat->work);
|
||||||
|
@ -85,11 +87,10 @@ static inline size_t sizeof_pwm_leds_priv(int num_leds)
|
||||||
static int led_pwm_create_of(struct platform_device *pdev,
|
static int led_pwm_create_of(struct platform_device *pdev,
|
||||||
struct led_pwm_priv *priv)
|
struct led_pwm_priv *priv)
|
||||||
{
|
{
|
||||||
struct device_node *node = pdev->dev.of_node;
|
|
||||||
struct device_node *child;
|
struct device_node *child;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
for_each_child_of_node(node, child) {
|
for_each_child_of_node(pdev->dev.of_node, child) {
|
||||||
struct led_pwm_data *led_dat = &priv->leds[priv->num_leds];
|
struct led_pwm_data *led_dat = &priv->leds[priv->num_leds];
|
||||||
|
|
||||||
led_dat->cdev.name = of_get_property(child, "label",
|
led_dat->cdev.name = of_get_property(child, "label",
|
||||||
|
|
|
@ -18,11 +18,10 @@
|
||||||
#include <linux/gpio.h>
|
#include <linux/gpio.h>
|
||||||
#include <linux/slab.h>
|
#include <linux/slab.h>
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
|
#include <linux/platform_data/leds-s3c24xx.h>
|
||||||
|
|
||||||
#include <mach/hardware.h>
|
|
||||||
#include <mach/regs-gpio.h>
|
#include <mach/regs-gpio.h>
|
||||||
#include <plat/gpio-cfg.h>
|
#include <plat/gpio-cfg.h>
|
||||||
#include <linux/platform_data/leds-s3c24xx.h>
|
|
||||||
|
|
||||||
/* our context */
|
/* our context */
|
||||||
|
|
||||||
|
|
|
@ -4,77 +4,87 @@
|
||||||
* The TCA6507 is a programmable LED controller that can drive 7
|
* The TCA6507 is a programmable LED controller that can drive 7
|
||||||
* separate lines either by holding them low, or by pulsing them
|
* separate lines either by holding them low, or by pulsing them
|
||||||
* with modulated width.
|
* with modulated width.
|
||||||
* The modulation can be varied in a simple pattern to produce a blink or
|
* The modulation can be varied in a simple pattern to produce a
|
||||||
* double-blink.
|
* blink or double-blink.
|
||||||
*
|
*
|
||||||
* This driver can configure each line either as a 'GPIO' which is out-only
|
* This driver can configure each line either as a 'GPIO' which is
|
||||||
* (no pull-up) or as an LED with variable brightness and hardware-assisted
|
* out-only (pull-up resistor required) or as an LED with variable
|
||||||
* blinking.
|
* brightness and hardware-assisted blinking.
|
||||||
*
|
*
|
||||||
* Apart from OFF and ON there are three programmable brightness levels which
|
* Apart from OFF and ON there are three programmable brightness
|
||||||
* can be programmed from 0 to 15 and indicate how many 500usec intervals in
|
* levels which can be programmed from 0 to 15 and indicate how many
|
||||||
* each 8msec that the led is 'on'. The levels are named MASTER, BANK0 and
|
* 500usec intervals in each 8msec that the led is 'on'. The levels
|
||||||
* BANK1.
|
* are named MASTER, BANK0 and BANK1.
|
||||||
*
|
*
|
||||||
* There are two different blink rates that can be programmed, each with
|
* There are two different blink rates that can be programmed, each
|
||||||
* separate time for rise, on, fall, off and second-off. Thus if 3 or more
|
* with separate time for rise, on, fall, off and second-off. Thus if
|
||||||
* different non-trivial rates are required, software must be used for the extra
|
* 3 or more different non-trivial rates are required, software must
|
||||||
* rates. The two different blink rates must align with the two levels BANK0 and
|
* be used for the extra rates. The two different blink rates must
|
||||||
* BANK1.
|
* align with the two levels BANK0 and BANK1. This driver does not
|
||||||
* This driver does not support double-blink so 'second-off' always matches
|
* support double-blink so 'second-off' always matches 'off'.
|
||||||
* 'off'.
|
|
||||||
*
|
*
|
||||||
* Only 16 different times can be programmed in a roughly logarithmic scale from
|
* Only 16 different times can be programmed in a roughly logarithmic
|
||||||
* 64ms to 16320ms. To be precise the possible times are:
|
* scale from 64ms to 16320ms. To be precise the possible times are:
|
||||||
* 0, 64, 128, 192, 256, 384, 512, 768,
|
* 0, 64, 128, 192, 256, 384, 512, 768,
|
||||||
* 1024, 1536, 2048, 3072, 4096, 5760, 8128, 16320
|
* 1024, 1536, 2048, 3072, 4096, 5760, 8128, 16320
|
||||||
*
|
*
|
||||||
* Times that cannot be closely matched with these must be
|
* Times that cannot be closely matched with these must be handled in
|
||||||
* handled in software. This driver allows 12.5% error in matching.
|
* software. This driver allows 12.5% error in matching.
|
||||||
*
|
*
|
||||||
* This driver does not allow rise/fall rates to be set explicitly. When trying
|
* This driver does not allow rise/fall rates to be set explicitly.
|
||||||
* to match a given 'on' or 'off' period, an appropriate pair of 'change' and
|
* When trying to match a given 'on' or 'off' period, an appropriate
|
||||||
* 'hold' times are chosen to get a close match. If the target delay is even,
|
* pair of 'change' and 'hold' times are chosen to get a close match.
|
||||||
* the 'change' number will be the smaller; if odd, the 'hold' number will be
|
* If the target delay is even, the 'change' number will be the
|
||||||
* the smaller.
|
* smaller; if odd, the 'hold' number will be the smaller.
|
||||||
|
|
||||||
* Choosing pairs of delays with 12.5% errors allows us to match delays in the
|
* Choosing pairs of delays with 12.5% errors allows us to match
|
||||||
* ranges: 56-72, 112-144, 168-216, 224-27504, 28560-36720.
|
* delays in the ranges: 56-72, 112-144, 168-216, 224-27504,
|
||||||
* 26% of the achievable sums can be matched by multiple pairings. For example
|
* 28560-36720.
|
||||||
* 1536 == 1536+0, 1024+512, or 768+768. This driver will always choose the
|
* 26% of the achievable sums can be matched by multiple pairings.
|
||||||
* pairing with the least maximum - 768+768 in this case. Other pairings are
|
* For example 1536 == 1536+0, 1024+512, or 768+768.
|
||||||
* not available.
|
* This driver will always choose the pairing with the least
|
||||||
|
* maximum - 768+768 in this case. Other pairings are not available.
|
||||||
*
|
*
|
||||||
* Access to the 3 levels and 2 blinks are on a first-come, first-served basis.
|
* Access to the 3 levels and 2 blinks are on a first-come,
|
||||||
* Access can be shared by multiple leds if they have the same level and
|
* first-served basis. Access can be shared by multiple leds if they
|
||||||
* either same blink rates, or some don't blink.
|
* have the same level and either same blink rates, or some don't
|
||||||
* When a led changes, it relinquishes access and tries again, so it might
|
* blink. When a led changes, it relinquishes access and tries again,
|
||||||
* lose access to hardware blink.
|
* so it might lose access to hardware blink.
|
||||||
* If a blink engine cannot be allocated, software blink is used.
|
|
||||||
* If the desired brightness cannot be allocated, the closest available non-zero
|
|
||||||
* brightness is used. As 'full' is always available, the worst case would be
|
|
||||||
* to have two different blink rates at '1', with Max at '2', then other leds
|
|
||||||
* will have to choose between '2' and '16'. Hopefully this is not likely.
|
|
||||||
*
|
*
|
||||||
* Each bank (BANK0 and BANK1) has two usage counts - LEDs using the brightness
|
* If a blink engine cannot be allocated, software blink is used. If
|
||||||
* and LEDs using the blink. It can only be reprogrammed when the appropriate
|
* the desired brightness cannot be allocated, the closest available
|
||||||
* counter is zero. The MASTER level has a single usage count.
|
* non-zero brightness is used. As 'full' is always available, the
|
||||||
|
* worst case would be to have two different blink rates at '1', with
|
||||||
|
* Max at '2', then other leds will have to choose between '2' and
|
||||||
|
* '16'. Hopefully this is not likely.
|
||||||
*
|
*
|
||||||
* Each Led has programmable 'on' and 'off' time as milliseconds. With each
|
* Each bank (BANK0 and BANK1) has two usage counts - LEDs using the
|
||||||
* there is a flag saying if it was explicitly requested or defaulted.
|
* brightness and LEDs using the blink. It can only be reprogrammed
|
||||||
* Similarly the banks know if each time was explicit or a default. Defaults
|
* when the appropriate counter is zero. The MASTER level has a
|
||||||
* are permitted to be changed freely - they are not recognised when matching.
|
* single usage count.
|
||||||
|
*
|
||||||
|
* Each LED has programmable 'on' and 'off' time as milliseconds.
|
||||||
|
* With each there is a flag saying if it was explicitly requested or
|
||||||
|
* defaulted. Similarly the banks know if each time was explicit or a
|
||||||
|
* default. Defaults are permitted to be changed freely - they are
|
||||||
|
* not recognised when matching.
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* An led-tca6507 device must be provided with platform data. This data
|
* An led-tca6507 device must be provided with platform data or
|
||||||
* lists for each output: the name, default trigger, and whether the signal
|
* configured via devicetree.
|
||||||
* is being used as a GPiO rather than an led. 'struct led_plaform_data'
|
|
||||||
* is used for this. If 'name' is NULL, the output isn't used. If 'flags'
|
|
||||||
* is TCA6507_MAKE_CPIO, the output is a GPO.
|
|
||||||
* The "struct led_platform_data" can be embedded in a
|
|
||||||
* "struct tca6507_platform_data" which adds a 'gpio_base' for the GPiOs,
|
|
||||||
* and a 'setup' callback which is called once the GPiOs are available.
|
|
||||||
*
|
*
|
||||||
|
* The platform-data lists for each output: the name, default trigger,
|
||||||
|
* and whether the signal is being used as a GPIO rather than an LED.
|
||||||
|
* 'struct led_plaform_data' is used for this. If 'name' is NULL, the
|
||||||
|
* output isn't used. If 'flags' is TCA6507_MAKE_GPIO, the output is
|
||||||
|
* a GPO. The "struct led_platform_data" can be embedded in a "struct
|
||||||
|
* tca6507_platform_data" which adds a 'gpio_base' for the GPIOs, and
|
||||||
|
* a 'setup' callback which is called once the GPIOs are available.
|
||||||
|
*
|
||||||
|
* When configured via devicetree there is one child for each output.
|
||||||
|
* The "reg" determines the output number and "compatible" determines
|
||||||
|
* whether it is an LED or a GPIO. "linux,default-trigger" can set a
|
||||||
|
* default trigger.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
|
@ -192,17 +202,18 @@ MODULE_DEVICE_TABLE(i2c, tca6507_id);
|
||||||
static int choose_times(int msec, int *c1p, int *c2p)
|
static int choose_times(int msec, int *c1p, int *c2p)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* Choose two timecodes which add to 'msec' as near as possible.
|
* Choose two timecodes which add to 'msec' as near as
|
||||||
* The first returned is the 'on' or 'off' time. The second is to be
|
* possible. The first returned is the 'on' or 'off' time.
|
||||||
* used as a 'fade-on' or 'fade-off' time. If 'msec' is even,
|
* The second is to be used as a 'fade-on' or 'fade-off' time.
|
||||||
* the first will not be smaller than the second. If 'msec' is odd,
|
* If 'msec' is even, the first will not be smaller than the
|
||||||
* the first will not be larger than the second.
|
* second. If 'msec' is odd, the first will not be larger
|
||||||
* If we cannot get a sum within 1/8 of 'msec' fail with -EINVAL,
|
* than the second.
|
||||||
* otherwise return the sum that was achieved, plus 1 if the first is
|
* If we cannot get a sum within 1/8 of 'msec' fail with
|
||||||
* smaller.
|
* -EINVAL, otherwise return the sum that was achieved, plus 1
|
||||||
* If two possibilities are equally good (e.g. 512+0, 256+256), choose
|
* if the first is smaller.
|
||||||
* the first pair so there is more change-time visible (i.e. it is
|
* If two possibilities are equally good (e.g. 512+0,
|
||||||
* softer).
|
* 256+256), choose the first pair so there is more
|
||||||
|
* change-time visible (i.e. it is softer).
|
||||||
*/
|
*/
|
||||||
int c1, c2;
|
int c1, c2;
|
||||||
int tmax = msec * 9 / 8;
|
int tmax = msec * 9 / 8;
|
||||||
|
@ -255,8 +266,8 @@ static int choose_times(int msec, int *c1p, int *c2p)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Update the register file with the appropriate 3-bit state for
|
* Update the register file with the appropriate 3-bit state for the
|
||||||
* the given led.
|
* given led.
|
||||||
*/
|
*/
|
||||||
static void set_select(struct tca6507_chip *tca, int led, int val)
|
static void set_select(struct tca6507_chip *tca, int led, int val)
|
||||||
{
|
{
|
||||||
|
@ -274,9 +285,9 @@ static void set_select(struct tca6507_chip *tca, int led, int val)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Update the register file with the appropriate 4-bit code for
|
/* Update the register file with the appropriate 4-bit code for one
|
||||||
* one bank or other. This can be used for timers, for levels, or
|
* bank or other. This can be used for timers, for levels, or for
|
||||||
* for initialisation.
|
* initialization.
|
||||||
*/
|
*/
|
||||||
static void set_code(struct tca6507_chip *tca, int reg, int bank, int new)
|
static void set_code(struct tca6507_chip *tca, int reg, int bank, int new)
|
||||||
{
|
{
|
||||||
|
@ -309,7 +320,7 @@ static void set_level(struct tca6507_chip *tca, int bank, int level)
|
||||||
tca->bank[bank].level = level;
|
tca->bank[bank].level = level;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Record all relevant time code for a given bank */
|
/* Record all relevant time codes for a given bank */
|
||||||
static void set_times(struct tca6507_chip *tca, int bank)
|
static void set_times(struct tca6507_chip *tca, int bank)
|
||||||
{
|
{
|
||||||
int c1, c2;
|
int c1, c2;
|
||||||
|
@ -317,7 +328,8 @@ static void set_times(struct tca6507_chip *tca, int bank)
|
||||||
|
|
||||||
result = choose_times(tca->bank[bank].ontime, &c1, &c2);
|
result = choose_times(tca->bank[bank].ontime, &c1, &c2);
|
||||||
dev_dbg(&tca->client->dev,
|
dev_dbg(&tca->client->dev,
|
||||||
"Chose on times %d(%d) %d(%d) for %dms\n", c1, time_codes[c1],
|
"Chose on times %d(%d) %d(%d) for %dms\n",
|
||||||
|
c1, time_codes[c1],
|
||||||
c2, time_codes[c2], tca->bank[bank].ontime);
|
c2, time_codes[c2], tca->bank[bank].ontime);
|
||||||
set_code(tca, TCA6507_FADE_ON, bank, c2);
|
set_code(tca, TCA6507_FADE_ON, bank, c2);
|
||||||
set_code(tca, TCA6507_FULL_ON, bank, c1);
|
set_code(tca, TCA6507_FULL_ON, bank, c1);
|
||||||
|
@ -325,7 +337,8 @@ static void set_times(struct tca6507_chip *tca, int bank)
|
||||||
|
|
||||||
result = choose_times(tca->bank[bank].offtime, &c1, &c2);
|
result = choose_times(tca->bank[bank].offtime, &c1, &c2);
|
||||||
dev_dbg(&tca->client->dev,
|
dev_dbg(&tca->client->dev,
|
||||||
"Chose off times %d(%d) %d(%d) for %dms\n", c1, time_codes[c1],
|
"Chose off times %d(%d) %d(%d) for %dms\n",
|
||||||
|
c1, time_codes[c1],
|
||||||
c2, time_codes[c2], tca->bank[bank].offtime);
|
c2, time_codes[c2], tca->bank[bank].offtime);
|
||||||
set_code(tca, TCA6507_FADE_OFF, bank, c2);
|
set_code(tca, TCA6507_FADE_OFF, bank, c2);
|
||||||
set_code(tca, TCA6507_FIRST_OFF, bank, c1);
|
set_code(tca, TCA6507_FIRST_OFF, bank, c1);
|
||||||
|
@ -373,7 +386,8 @@ static void led_release(struct tca6507_led *led)
|
||||||
|
|
||||||
static int led_prepare(struct tca6507_led *led)
|
static int led_prepare(struct tca6507_led *led)
|
||||||
{
|
{
|
||||||
/* Assign this led to a bank, configuring that bank if necessary. */
|
/* Assign this led to a bank, configuring that bank if
|
||||||
|
* necessary. */
|
||||||
int level = TO_LEVEL(led->led_cdev.brightness);
|
int level = TO_LEVEL(led->led_cdev.brightness);
|
||||||
struct tca6507_chip *tca = led->chip;
|
struct tca6507_chip *tca = led->chip;
|
||||||
int c1, c2;
|
int c1, c2;
|
||||||
|
@ -389,10 +403,10 @@ static int led_prepare(struct tca6507_led *led)
|
||||||
|
|
||||||
if (led->ontime == 0 || led->offtime == 0) {
|
if (led->ontime == 0 || led->offtime == 0) {
|
||||||
/*
|
/*
|
||||||
* Just set the brightness, choosing first usable bank.
|
* Just set the brightness, choosing first usable
|
||||||
* If none perfect, choose best.
|
* bank. If none perfect, choose best. Count
|
||||||
* Count backwards so we check MASTER bank first
|
* backwards so we check MASTER bank first to avoid
|
||||||
* to avoid wasting a timer.
|
* wasting a timer.
|
||||||
*/
|
*/
|
||||||
int best = -1;/* full-on */
|
int best = -1;/* full-on */
|
||||||
int diff = 15-level;
|
int diff = 15-level;
|
||||||
|
@ -433,9 +447,9 @@ static int led_prepare(struct tca6507_led *led)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We have on/off time so we need to try to allocate a timing bank.
|
* We have on/off time so we need to try to allocate a timing
|
||||||
* First check if times are compatible with hardware and give up if
|
* bank. First check if times are compatible with hardware
|
||||||
* not.
|
* and give up if not.
|
||||||
*/
|
*/
|
||||||
if (choose_times(led->ontime, &c1, &c2) < 0)
|
if (choose_times(led->ontime, &c1, &c2) < 0)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
@ -523,8 +537,8 @@ static int led_assign(struct tca6507_led *led)
|
||||||
err = led_prepare(led);
|
err = led_prepare(led);
|
||||||
if (err) {
|
if (err) {
|
||||||
/*
|
/*
|
||||||
* Can only fail on timer setup. In that case we need to
|
* Can only fail on timer setup. In that case we need
|
||||||
* re-establish as steady level.
|
* to re-establish as steady level.
|
||||||
*/
|
*/
|
||||||
led->ontime = 0;
|
led->ontime = 0;
|
||||||
led->offtime = 0;
|
led->offtime = 0;
|
||||||
|
@ -594,8 +608,8 @@ static void tca6507_gpio_set_value(struct gpio_chip *gc,
|
||||||
|
|
||||||
spin_lock_irqsave(&tca->lock, flags);
|
spin_lock_irqsave(&tca->lock, flags);
|
||||||
/*
|
/*
|
||||||
* 'OFF' is floating high, and 'ON' is pulled down, so it has the
|
* 'OFF' is floating high, and 'ON' is pulled down, so it has
|
||||||
* inverse sense of 'val'.
|
* the inverse sense of 'val'.
|
||||||
*/
|
*/
|
||||||
set_select(tca, tca->gpio_map[offset],
|
set_select(tca, tca->gpio_map[offset],
|
||||||
val ? TCA6507_LS_LED_OFF : TCA6507_LS_LED_ON);
|
val ? TCA6507_LS_LED_OFF : TCA6507_LS_LED_ON);
|
||||||
|
@ -638,6 +652,9 @@ static int tca6507_probe_gpios(struct i2c_client *client,
|
||||||
tca->gpio.direction_output = tca6507_gpio_direction_output;
|
tca->gpio.direction_output = tca6507_gpio_direction_output;
|
||||||
tca->gpio.set = tca6507_gpio_set_value;
|
tca->gpio.set = tca6507_gpio_set_value;
|
||||||
tca->gpio.dev = &client->dev;
|
tca->gpio.dev = &client->dev;
|
||||||
|
#ifdef CONFIG_OF_GPIO
|
||||||
|
tca->gpio.of_node = of_node_get(client->dev.of_node);
|
||||||
|
#endif
|
||||||
err = gpiochip_add(&tca->gpio);
|
err = gpiochip_add(&tca->gpio);
|
||||||
if (err) {
|
if (err) {
|
||||||
tca->gpio.ngpio = 0;
|
tca->gpio.ngpio = 0;
|
||||||
|
@ -682,7 +699,7 @@ tca6507_led_dt_init(struct i2c_client *client)
|
||||||
return ERR_PTR(-ENODEV);
|
return ERR_PTR(-ENODEV);
|
||||||
|
|
||||||
tca_leds = devm_kzalloc(&client->dev,
|
tca_leds = devm_kzalloc(&client->dev,
|
||||||
sizeof(struct led_info) * count, GFP_KERNEL);
|
sizeof(struct led_info) * NUM_LEDS, GFP_KERNEL);
|
||||||
if (!tca_leds)
|
if (!tca_leds)
|
||||||
return ERR_PTR(-ENOMEM);
|
return ERR_PTR(-ENOMEM);
|
||||||
|
|
||||||
|
@ -695,9 +712,11 @@ tca6507_led_dt_init(struct i2c_client *client)
|
||||||
of_get_property(child, "label", NULL) ? : child->name;
|
of_get_property(child, "label", NULL) ? : child->name;
|
||||||
led.default_trigger =
|
led.default_trigger =
|
||||||
of_get_property(child, "linux,default-trigger", NULL);
|
of_get_property(child, "linux,default-trigger", NULL);
|
||||||
|
led.flags = 0;
|
||||||
|
if (of_property_match_string(child, "compatible", "gpio") >= 0)
|
||||||
|
led.flags |= TCA6507_MAKE_GPIO;
|
||||||
ret = of_property_read_u32(child, "reg", ®);
|
ret = of_property_read_u32(child, "reg", ®);
|
||||||
if (ret != 0)
|
if (ret != 0 || reg < 0 || reg >= NUM_LEDS)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
tca_leds[reg] = led;
|
tca_leds[reg] = led;
|
||||||
|
@ -708,8 +727,10 @@ tca6507_led_dt_init(struct i2c_client *client)
|
||||||
return ERR_PTR(-ENOMEM);
|
return ERR_PTR(-ENOMEM);
|
||||||
|
|
||||||
pdata->leds.leds = tca_leds;
|
pdata->leds.leds = tca_leds;
|
||||||
pdata->leds.num_leds = count;
|
pdata->leds.num_leds = NUM_LEDS;
|
||||||
|
#ifdef CONFIG_GPIOLIB
|
||||||
|
pdata->gpio_base = -1;
|
||||||
|
#endif
|
||||||
return pdata;
|
return pdata;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -110,9 +110,6 @@ struct mc13xxx_led_platform_data {
|
||||||
int id;
|
int id;
|
||||||
const char *name;
|
const char *name;
|
||||||
const char *default_trigger;
|
const char *default_trigger;
|
||||||
|
|
||||||
/* Three or two bits current selection depending on the led */
|
|
||||||
char max_current;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#define MAX_LED_CONTROL_REGS 6
|
#define MAX_LED_CONTROL_REGS 6
|
||||||
|
@ -121,7 +118,7 @@ struct mc13xxx_leds_platform_data {
|
||||||
struct mc13xxx_led_platform_data *led;
|
struct mc13xxx_led_platform_data *led;
|
||||||
int num_leds;
|
int num_leds;
|
||||||
|
|
||||||
/* LED Control 0 */
|
/* MC13783 LED Control 0 */
|
||||||
#define MC13783_LED_C0_ENABLE (1 << 0)
|
#define MC13783_LED_C0_ENABLE (1 << 0)
|
||||||
#define MC13783_LED_C0_TRIODE_MD (1 << 7)
|
#define MC13783_LED_C0_TRIODE_MD (1 << 7)
|
||||||
#define MC13783_LED_C0_TRIODE_AD (1 << 8)
|
#define MC13783_LED_C0_TRIODE_AD (1 << 8)
|
||||||
|
@ -129,21 +126,43 @@ struct mc13xxx_leds_platform_data {
|
||||||
#define MC13783_LED_C0_BOOST (1 << 10)
|
#define MC13783_LED_C0_BOOST (1 << 10)
|
||||||
#define MC13783_LED_C0_ABMODE(x) (((x) & 0x7) << 11)
|
#define MC13783_LED_C0_ABMODE(x) (((x) & 0x7) << 11)
|
||||||
#define MC13783_LED_C0_ABREF(x) (((x) & 0x3) << 14)
|
#define MC13783_LED_C0_ABREF(x) (((x) & 0x3) << 14)
|
||||||
/* LED Control 1 */
|
/* MC13783 LED Control 1 */
|
||||||
#define MC13783_LED_C1_TC1HALF (1 << 18)
|
#define MC13783_LED_C1_TC1HALF (1 << 18)
|
||||||
#define MC13783_LED_C1_SLEWLIM (1 << 23)
|
#define MC13783_LED_C1_SLEWLIM (1 << 23)
|
||||||
/* LED Control 2 */
|
/* MC13783 LED Control 2 */
|
||||||
|
#define MC13783_LED_C2_CURRENT_MD(x) (((x) & 0x7) << 0)
|
||||||
|
#define MC13783_LED_C2_CURRENT_AD(x) (((x) & 0x7) << 3)
|
||||||
|
#define MC13783_LED_C2_CURRENT_KP(x) (((x) & 0x7) << 6)
|
||||||
#define MC13783_LED_C2_PERIOD(x) (((x) & 0x3) << 21)
|
#define MC13783_LED_C2_PERIOD(x) (((x) & 0x3) << 21)
|
||||||
#define MC13783_LED_C2_SLEWLIM (1 << 23)
|
#define MC13783_LED_C2_SLEWLIM (1 << 23)
|
||||||
/* LED Control 3 */
|
/* MC13783 LED Control 3 */
|
||||||
|
#define MC13783_LED_C3_CURRENT_R1(x) (((x) & 0x3) << 0)
|
||||||
|
#define MC13783_LED_C3_CURRENT_G1(x) (((x) & 0x3) << 2)
|
||||||
|
#define MC13783_LED_C3_CURRENT_B1(x) (((x) & 0x3) << 4)
|
||||||
#define MC13783_LED_C3_PERIOD(x) (((x) & 0x3) << 21)
|
#define MC13783_LED_C3_PERIOD(x) (((x) & 0x3) << 21)
|
||||||
#define MC13783_LED_C3_TRIODE_TC1 (1 << 23)
|
#define MC13783_LED_C3_TRIODE_TC1 (1 << 23)
|
||||||
/* LED Control 4 */
|
/* MC13783 LED Control 4 */
|
||||||
|
#define MC13783_LED_C4_CURRENT_R2(x) (((x) & 0x3) << 0)
|
||||||
|
#define MC13783_LED_C4_CURRENT_G2(x) (((x) & 0x3) << 2)
|
||||||
|
#define MC13783_LED_C4_CURRENT_B2(x) (((x) & 0x3) << 4)
|
||||||
#define MC13783_LED_C4_PERIOD(x) (((x) & 0x3) << 21)
|
#define MC13783_LED_C4_PERIOD(x) (((x) & 0x3) << 21)
|
||||||
#define MC13783_LED_C4_TRIODE_TC2 (1 << 23)
|
#define MC13783_LED_C4_TRIODE_TC2 (1 << 23)
|
||||||
/* LED Control 5 */
|
/* MC13783 LED Control 5 */
|
||||||
|
#define MC13783_LED_C5_CURRENT_R3(x) (((x) & 0x3) << 0)
|
||||||
|
#define MC13783_LED_C5_CURRENT_G3(x) (((x) & 0x3) << 2)
|
||||||
|
#define MC13783_LED_C5_CURRENT_B3(x) (((x) & 0x3) << 4)
|
||||||
#define MC13783_LED_C5_PERIOD(x) (((x) & 0x3) << 21)
|
#define MC13783_LED_C5_PERIOD(x) (((x) & 0x3) << 21)
|
||||||
#define MC13783_LED_C5_TRIODE_TC3 (1 << 23)
|
#define MC13783_LED_C5_TRIODE_TC3 (1 << 23)
|
||||||
|
/* MC13892 LED Control 0 */
|
||||||
|
#define MC13892_LED_C0_CURRENT_MD(x) (((x) & 0x7) << 9)
|
||||||
|
#define MC13892_LED_C0_CURRENT_AD(x) (((x) & 0x7) << 21)
|
||||||
|
/* MC13892 LED Control 1 */
|
||||||
|
#define MC13892_LED_C1_CURRENT_KP(x) (((x) & 0x7) << 9)
|
||||||
|
/* MC13892 LED Control 2 */
|
||||||
|
#define MC13892_LED_C2_CURRENT_R(x) (((x) & 0x7) << 9)
|
||||||
|
#define MC13892_LED_C2_CURRENT_G(x) (((x) & 0x7) << 21)
|
||||||
|
/* MC13892 LED Control 3 */
|
||||||
|
#define MC13892_LED_C3_CURRENT_B(x) (((x) & 0x7) << 9)
|
||||||
u32 led_control[MAX_LED_CONTROL_REGS];
|
u32 led_control[MAX_LED_CONTROL_REGS];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,4 @@
|
||||||
/*
|
/*
|
||||||
* arch/arm/mach-kirkwood/include/mach/leds-netxbig.h
|
|
||||||
*
|
|
||||||
* Platform data structure for netxbig LED driver
|
* Platform data structure for netxbig LED driver
|
||||||
*
|
*
|
||||||
* This file is licensed under the terms of the GNU General Public
|
* This file is licensed under the terms of the GNU General Public
|
||||||
|
@ -8,8 +6,8 @@
|
||||||
* warranty of any kind, whether express or implied.
|
* warranty of any kind, whether express or implied.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef __MACH_LEDS_NETXBIG_H
|
#ifndef __LEDS_KIRKWOOD_NETXBIG_H
|
||||||
#define __MACH_LEDS_NETXBIG_H
|
#define __LEDS_KIRKWOOD_NETXBIG_H
|
||||||
|
|
||||||
struct netxbig_gpio_ext {
|
struct netxbig_gpio_ext {
|
||||||
unsigned *addr;
|
unsigned *addr;
|
||||||
|
@ -52,4 +50,4 @@ struct netxbig_led_platform_data {
|
||||||
int num_leds;
|
int num_leds;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* __MACH_LEDS_NETXBIG_H */
|
#endif /* __LEDS_KIRKWOOD_NETXBIG_H */
|
||||||
|
|
|
@ -1,6 +1,4 @@
|
||||||
/*
|
/*
|
||||||
* arch/arm/mach-kirkwood/include/mach/leds-ns2.h
|
|
||||||
*
|
|
||||||
* Platform data structure for Network Space v2 LED driver
|
* Platform data structure for Network Space v2 LED driver
|
||||||
*
|
*
|
||||||
* This file is licensed under the terms of the GNU General Public
|
* This file is licensed under the terms of the GNU General Public
|
||||||
|
@ -8,8 +6,8 @@
|
||||||
* warranty of any kind, whether express or implied.
|
* warranty of any kind, whether express or implied.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef __MACH_LEDS_NS2_H
|
#ifndef __LEDS_KIRKWOOD_NS2_H
|
||||||
#define __MACH_LEDS_NS2_H
|
#define __LEDS_KIRKWOOD_NS2_H
|
||||||
|
|
||||||
struct ns2_led {
|
struct ns2_led {
|
||||||
const char *name;
|
const char *name;
|
||||||
|
@ -23,4 +21,4 @@ struct ns2_led_platform_data {
|
||||||
struct ns2_led *leds;
|
struct ns2_led *leds;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* __MACH_LEDS_NS2_H */
|
#endif /* __LEDS_KIRKWOOD_NS2_H */
|
||||||
|
|
Loading…
Reference in a new issue