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

Pull LED updates from Bryan Wu:
 "This cycle we got:
   - new driver for leds-mc13783
   - bug fixes
   - code cleanup"

* 'for-next' of git://git.kernel.org/pub/scm/linux/kernel/git/cooloney/linux-leds:
  leds: make sure we unregister a trigger only once
  leds: leds-pwm: properly clean up after probe failure
  leds: clevo-mail: Make probe function __init
  leds-ot200: Fix dependencies
  leds-gpio: of: introduce MODULE_DEVICE_TABLE for module autoloading
  leds: clevo-mail: remove __initdata marker
  leds: leds-ss4200: remove __initdata marker
  leds: blinkm: remove unnecessary spaces
  leds: lp5562: remove unnecessary parentheses
  leds: leds-ss4200: remove DEFINE_PCI_DEVICE_TABLE macro
  leds: leds-s3c24xx: Trivial cleanup in header file
  drivers/leds: delete non-required instances of include <linux/init.h>
  leds: leds-gpio: add retain-state-suspended property
  leds: leds-mc13783: Add devicetree support
  leds: leds-mc13783: Remove unnecessary cleaning of registers on exit
  leds: leds-mc13783: Use proper "max_brightness" value fo LEDs
  leds: leds-mc13783: Use LED core PM functions
  leds: leds-mc13783: Add MC34708 LED support
  leds: Turn off led if blinking is disabled
  ledtrig-cpu: Handle CPU hot(un)plugging
This commit is contained in:
Linus Torvalds 2014-04-10 09:06:10 -07:00
commit 4162877d3f
33 changed files with 276 additions and 130 deletions

View File

@ -21,6 +21,8 @@ LED sub-node properties:
on). The "keep" setting will keep the LED at whatever its current on). The "keep" setting will keep the LED at whatever its current
state is, without producing a glitch. The default is off if this state is, without producing a glitch. The default is off if this
property is not present. property is not present.
- retain-state-suspended: (optional) The suspend state can be retained.Such
as charge-led gpio.
Examples: Examples:
@ -50,3 +52,13 @@ run-control {
default-state = "on"; default-state = "on";
}; };
}; };
leds {
compatible = "gpio-leds";
charger-led {
gpios = <&gpio1 2 0>;
linux,default-trigger = "max8903-charger-charging";
retain-state-suspended;
};
};

View File

@ -10,9 +10,44 @@ Optional properties:
- fsl,mc13xxx-uses-touch : Indicate the touchscreen controller is being used - fsl,mc13xxx-uses-touch : Indicate the touchscreen controller is being used
Sub-nodes: Sub-nodes:
- leds : Contain the led nodes and initial register values in property
"led-control". Number of register depends of used IC, for MC13783 is 6,
for MC13892 is 4, for MC34708 is 1. See datasheet for bits definitions of
these registers.
- #address-cells: Must be 1.
- #size-cells: Must be 0.
Each led node should contain "reg", which used as LED ID (described below).
Optional properties "label" and "linux,default-trigger" is described in
Documentation/devicetree/bindings/leds/common.txt.
- regulators : Contain the regulator nodes. The regulators are bound using - regulators : Contain the regulator nodes. The regulators are bound using
their names as listed below with their registers and bits for enabling. their names as listed below with their registers and bits for enabling.
MC13783 LED IDs:
0 : Main display
1 : AUX display
2 : Keypad
3 : Red 1
4 : Green 1
5 : Blue 1
6 : Red 2
7 : Green 2
8 : Blue 2
9 : Red 3
10 : Green 3
11 : Blue 3
MC13892 LED IDs:
0 : Main display
1 : AUX display
2 : Keypad
3 : Red
4 : Green
5 : Blue
MC34708 LED IDs:
0 : Charger Red
1 : Charger Green
MC13783 regulators: MC13783 regulators:
sw1a : regulator SW1A (register 24, bit 0) sw1a : regulator SW1A (register 24, bit 0)
sw1b : regulator SW1B (register 25, bit 0) sw1b : regulator SW1B (register 25, bit 0)
@ -89,6 +124,18 @@ ecspi@70010000 { /* ECSPI1 */
interrupt-parent = <&gpio0>; interrupt-parent = <&gpio0>;
interrupts = <8>; interrupts = <8>;
leds {
#address-cells = <1>;
#size-cells = <0>;
led-control = <0x000 0x000 0x0e0 0x000>;
sysled {
reg = <3>;
label = "system:red:live";
linux,default-trigger = "heartbeat";
};
};
regulators { regulators {
sw1_reg: mc13892__sw1 { sw1_reg: mc13892__sw1 {
regulator-min-microvolt = <600000>; regulator-min-microvolt = <600000>;

View File

@ -416,7 +416,7 @@ config LEDS_MC13783
depends on MFD_MC13XXX depends on MFD_MC13XXX
help help
This option enable support for on-chip LED drivers found This option enable support for on-chip LED drivers found
on Freescale Semiconductor MC13783/MC13892 PMIC. on Freescale Semiconductor MC13783/MC13892/MC34708 PMIC.
config LEDS_NS2 config LEDS_NS2
tristate "LED support for Network Space v2 GPIO LEDs" tristate "LED support for Network Space v2 GPIO LEDs"
@ -474,7 +474,7 @@ config LEDS_LM355x
config LEDS_OT200 config LEDS_OT200
tristate "LED support for the Bachmann OT200" tristate "LED support for the Bachmann OT200"
depends on LEDS_CLASS && HAS_IOMEM depends on LEDS_CLASS && HAS_IOMEM && (X86_32 || COMPILE_TEST)
help help
This option enables support for the LEDs on the Bachmann OT200. This option enables support for the LEDs on the Bachmann OT200.
Say Y to enable LEDs on the Bachmann OT200. Say Y to enable LEDs on the Bachmann OT200.

View File

@ -39,9 +39,11 @@ static void led_set_software_blink(struct led_classdev *led_cdev,
led_cdev->blink_delay_on = delay_on; led_cdev->blink_delay_on = delay_on;
led_cdev->blink_delay_off = delay_off; led_cdev->blink_delay_off = delay_off;
/* never on - don't blink */ /* never on - just set to off */
if (!delay_on) if (!delay_on) {
__led_set_brightness(led_cdev, LED_OFF);
return; return;
}
/* never off - just set to brightness */ /* never off - just set to brightness */
if (!delay_off) { if (!delay_off) {

View File

@ -13,7 +13,6 @@
#include <linux/module.h> #include <linux/module.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/init.h>
#include <linux/list.h> #include <linux/list.h>
#include <linux/spinlock.h> #include <linux/spinlock.h>
#include <linux/device.h> #include <linux/device.h>
@ -220,9 +219,12 @@ void led_trigger_unregister(struct led_trigger *trig)
{ {
struct led_classdev *led_cdev; struct led_classdev *led_cdev;
if (list_empty_careful(&trig->next_trig))
return;
/* Remove from the list of led triggers */ /* Remove from the list of led triggers */
down_write(&triggers_list_lock); down_write(&triggers_list_lock);
list_del(&trig->next_trig); list_del_init(&trig->next_trig);
up_write(&triggers_list_lock); up_write(&triggers_list_lock);
/* Remove anyone actively using this trigger */ /* Remove anyone actively using this trigger */

View File

@ -11,7 +11,6 @@
*/ */
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/init.h>
#include <linux/of.h> #include <linux/of.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/i2c.h> #include <linux/i2c.h>

View File

@ -15,7 +15,6 @@
#include <linux/module.h> #include <linux/module.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/init.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/leds.h> #include <linux/leds.h>
#include <linux/workqueue.h> #include <linux/workqueue.h>

View File

@ -7,7 +7,6 @@
*/ */
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/init.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/leds.h> #include <linux/leds.h>
#include <linux/slab.h> #include <linux/slab.h>

View File

@ -18,7 +18,6 @@
*/ */
#include <linux/module.h> #include <linux/module.h>
#include <linux/init.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/jiffies.h> #include <linux/jiffies.h>
#include <linux/i2c.h> #include <linux/i2c.h>

View File

@ -19,7 +19,7 @@ MODULE_AUTHOR("Márton Németh <nm127@freemail.hu>");
MODULE_DESCRIPTION("Clevo mail LED driver"); MODULE_DESCRIPTION("Clevo mail LED driver");
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
static bool __initdata nodetect; static bool nodetect;
module_param_named(nodetect, nodetect, bool, 0); module_param_named(nodetect, nodetect, bool, 0);
MODULE_PARM_DESC(nodetect, "Skip DMI hardware detection"); MODULE_PARM_DESC(nodetect, "Skip DMI hardware detection");
@ -153,7 +153,7 @@ static struct led_classdev clevo_mail_led = {
.flags = LED_CORE_SUSPENDRESUME, .flags = LED_CORE_SUSPENDRESUME,
}; };
static int clevo_mail_led_probe(struct platform_device *pdev) static int __init clevo_mail_led_probe(struct platform_device *pdev)
{ {
return led_classdev_register(&pdev->dev, &clevo_mail_led); return led_classdev_register(&pdev->dev, &clevo_mail_led);
} }
@ -165,7 +165,6 @@ static int clevo_mail_led_remove(struct platform_device *pdev)
} }
static struct platform_driver clevo_mail_led_driver = { static struct platform_driver clevo_mail_led_driver = {
.probe = clevo_mail_led_probe,
.remove = clevo_mail_led_remove, .remove = clevo_mail_led_remove,
.driver = { .driver = {
.name = KBUILD_MODNAME, .name = KBUILD_MODNAME,

View File

@ -3,7 +3,6 @@
* *
* Control the Cobalt Qube/RaQ front LED * Control the Cobalt Qube/RaQ front LED
*/ */
#include <linux/init.h>
#include <linux/io.h> #include <linux/io.h>
#include <linux/ioport.h> #include <linux/ioport.h>
#include <linux/leds.h> #include <linux/leds.h>

View File

@ -14,7 +14,6 @@
#include <linux/module.h> #include <linux/module.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/init.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/leds.h> #include <linux/leds.h>
#include <linux/workqueue.h> #include <linux/workqueue.h>

View File

@ -14,7 +14,6 @@
#include <linux/module.h> #include <linux/module.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/init.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/leds.h> #include <linux/leds.h>
#include <linux/workqueue.h> #include <linux/workqueue.h>

View File

@ -16,7 +16,6 @@
*/ */
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/init.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/leds.h> #include <linux/leds.h>
#include <linux/module.h> #include <linux/module.h>

View File

@ -11,7 +11,6 @@
* *
*/ */
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/init.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/gpio.h> #include <linux/gpio.h>
#include <linux/leds.h> #include <linux/leds.h>
@ -204,6 +203,9 @@ static struct gpio_leds_priv *gpio_leds_create_of(struct platform_device *pdev)
led.default_state = LEDS_GPIO_DEFSTATE_OFF; led.default_state = LEDS_GPIO_DEFSTATE_OFF;
} }
if (of_get_property(child, "retain-state-suspended", NULL))
led.retain_state_suspended = 1;
ret = create_gpio_led(&led, &priv->leds[priv->num_leds++], ret = create_gpio_led(&led, &priv->leds[priv->num_leds++],
&pdev->dev, NULL); &pdev->dev, NULL);
if (ret < 0) { if (ret < 0) {
@ -224,6 +226,8 @@ static const struct of_device_id of_gpio_leds_match[] = {
{ .compatible = "gpio-leds", }, { .compatible = "gpio-leds", },
{}, {},
}; };
MODULE_DEVICE_TABLE(of, of_gpio_leds_match);
#else /* CONFIG_OF_GPIO */ #else /* CONFIG_OF_GPIO */
static struct gpio_leds_priv *gpio_leds_create_of(struct platform_device *pdev) static struct gpio_leds_priv *gpio_leds_create_of(struct platform_device *pdev)
{ {

View File

@ -12,7 +12,6 @@
#include <linux/module.h> #include <linux/module.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/init.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/leds.h> #include <linux/leds.h>
#include <asm/hd64461.h> #include <asm/hd64461.h>

View File

@ -12,7 +12,6 @@
*/ */
#include <linux/module.h> #include <linux/module.h>
#include <linux/init.h>
#include <linux/leds.h> #include <linux/leds.h>
#include <linux/mfd/core.h> #include <linux/mfd/core.h>
#include <linux/mutex.h> #include <linux/mutex.h>

View File

@ -25,7 +25,6 @@
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/firmware.h> #include <linux/firmware.h>
#include <linux/i2c.h> #include <linux/i2c.h>
#include <linux/init.h>
#include <linux/leds.h> #include <linux/leds.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/mutex.h> #include <linux/mutex.h>

View File

@ -25,7 +25,6 @@
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/firmware.h> #include <linux/firmware.h>
#include <linux/i2c.h> #include <linux/i2c.h>
#include <linux/init.h>
#include <linux/leds.h> #include <linux/leds.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/mutex.h> #include <linux/mutex.h>

View File

@ -13,7 +13,6 @@
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/firmware.h> #include <linux/firmware.h>
#include <linux/i2c.h> #include <linux/i2c.h>
#include <linux/init.h>
#include <linux/leds.h> #include <linux/leds.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/mutex.h> #include <linux/mutex.h>
@ -347,9 +346,9 @@ static void lp5562_write_program_memory(struct lp55xx_chip *chip,
/* check the size of program count */ /* check the size of program count */
static inline bool _is_pc_overflow(struct lp55xx_predef_pattern *ptn) static inline bool _is_pc_overflow(struct lp55xx_predef_pattern *ptn)
{ {
return (ptn->size_r >= LP5562_PROGRAM_LENGTH || return ptn->size_r >= LP5562_PROGRAM_LENGTH ||
ptn->size_g >= LP5562_PROGRAM_LENGTH || ptn->size_g >= LP5562_PROGRAM_LENGTH ||
ptn->size_b >= LP5562_PROGRAM_LENGTH); ptn->size_b >= LP5562_PROGRAM_LENGTH;
} }
static int lp5562_run_predef_led_pattern(struct lp55xx_chip *chip, int mode) static int lp5562_run_predef_led_pattern(struct lp55xx_chip *chip, int mode)

View File

@ -17,7 +17,6 @@
*/ */
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/init.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/leds.h> #include <linux/leds.h>
#include <linux/workqueue.h> #include <linux/workqueue.h>

View File

@ -1,5 +1,5 @@
/* /*
* LEDs driver for Freescale MC13783/MC13892 * LEDs driver for Freescale MC13783/MC13892/MC34708
* *
* Copyright (C) 2010 Philippe Rétornaz * Copyright (C) 2010 Philippe Rétornaz
* *
@ -17,57 +17,56 @@
#include <linux/module.h> #include <linux/module.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/init.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/leds.h> #include <linux/leds.h>
#include <linux/of.h>
#include <linux/workqueue.h> #include <linux/workqueue.h>
#include <linux/mfd/mc13xxx.h> #include <linux/mfd/mc13xxx.h>
#define MC13XXX_REG_LED_CONTROL(x) (51 + (x))
struct mc13xxx_led_devtype { struct mc13xxx_led_devtype {
int led_min; int led_min;
int led_max; int led_max;
int num_regs; int num_regs;
u32 ledctrl_base;
}; };
struct mc13xxx_led { struct mc13xxx_led {
struct led_classdev cdev; struct led_classdev cdev;
struct work_struct work; struct work_struct work;
struct mc13xxx *master;
enum led_brightness new_brightness; enum led_brightness new_brightness;
int id; int id;
struct mc13xxx_leds *leds;
}; };
struct mc13xxx_leds { struct mc13xxx_leds {
struct mc13xxx *master;
struct mc13xxx_led_devtype *devtype; struct mc13xxx_led_devtype *devtype;
int num_leds; int num_leds;
struct mc13xxx_led led[0]; struct mc13xxx_led *led;
}; };
static unsigned int mc13xxx_max_brightness(int id)
{
if (id >= MC13783_LED_MD && id <= MC13783_LED_KP)
return 0x0f;
else if (id >= MC13783_LED_R1 && id <= MC13783_LED_B3)
return 0x1f;
return 0x3f;
}
static void mc13xxx_led_work(struct work_struct *work) static void mc13xxx_led_work(struct work_struct *work)
{ {
struct mc13xxx_led *led = container_of(work, struct mc13xxx_led, work); struct mc13xxx_led *led = container_of(work, struct mc13xxx_led, work);
int reg, mask, value, bank, off, shift; struct mc13xxx_leds *leds = led->leds;
unsigned int reg, bank, off, shift;
switch (led->id) { switch (led->id) {
case MC13783_LED_MD: case MC13783_LED_MD:
reg = MC13XXX_REG_LED_CONTROL(2);
shift = 9;
mask = 0x0f;
value = led->new_brightness >> 4;
break;
case MC13783_LED_AD: case MC13783_LED_AD:
reg = MC13XXX_REG_LED_CONTROL(2);
shift = 13;
mask = 0x0f;
value = led->new_brightness >> 4;
break;
case MC13783_LED_KP: case MC13783_LED_KP:
reg = MC13XXX_REG_LED_CONTROL(2); reg = 2;
shift = 17; shift = 9 + (led->id - MC13783_LED_MD) * 4;
mask = 0x0f;
value = led->new_brightness >> 4;
break; break;
case MC13783_LED_R1: case MC13783_LED_R1:
case MC13783_LED_G1: case MC13783_LED_G1:
@ -80,44 +79,35 @@ static void mc13xxx_led_work(struct work_struct *work)
case MC13783_LED_B3: case MC13783_LED_B3:
off = led->id - MC13783_LED_R1; off = led->id - MC13783_LED_R1;
bank = off / 3; bank = off / 3;
reg = MC13XXX_REG_LED_CONTROL(3) + bank; reg = 3 + bank;
shift = (off - bank * 3) * 5 + 6; shift = (off - bank * 3) * 5 + 6;
value = led->new_brightness >> 3;
mask = 0x1f;
break; break;
case MC13892_LED_MD: case MC13892_LED_MD:
reg = MC13XXX_REG_LED_CONTROL(0);
shift = 3;
mask = 0x3f;
value = led->new_brightness >> 2;
break;
case MC13892_LED_AD: case MC13892_LED_AD:
reg = MC13XXX_REG_LED_CONTROL(0);
shift = 15;
mask = 0x3f;
value = led->new_brightness >> 2;
break;
case MC13892_LED_KP: case MC13892_LED_KP:
reg = MC13XXX_REG_LED_CONTROL(1); reg = (led->id - MC13892_LED_MD) / 2;
shift = 3; shift = 3 + (led->id - MC13892_LED_MD) * 12;
mask = 0x3f;
value = led->new_brightness >> 2;
break; break;
case MC13892_LED_R: case MC13892_LED_R:
case MC13892_LED_G: case MC13892_LED_G:
case MC13892_LED_B: case MC13892_LED_B:
off = led->id - MC13892_LED_R; off = led->id - MC13892_LED_R;
bank = off / 2; bank = off / 2;
reg = MC13XXX_REG_LED_CONTROL(2) + bank; reg = 2 + bank;
shift = (off - bank * 2) * 12 + 3; shift = (off - bank * 2) * 12 + 3;
value = led->new_brightness >> 2; break;
mask = 0x3f; case MC34708_LED_R:
case MC34708_LED_G:
reg = 0;
shift = 3 + (led->id - MC34708_LED_R) * 12;
break; break;
default: default:
BUG(); BUG();
} }
mc13xxx_reg_rmw(led->master, reg, mask << shift, value << shift); mc13xxx_reg_rmw(leds->master, leds->devtype->ledctrl_base + reg,
mc13xxx_max_brightness(led->id) << shift,
led->new_brightness << shift);
} }
static void mc13xxx_led_set(struct led_classdev *led_cdev, static void mc13xxx_led_set(struct led_classdev *led_cdev,
@ -130,47 +120,121 @@ static void mc13xxx_led_set(struct led_classdev *led_cdev,
schedule_work(&led->work); schedule_work(&led->work);
} }
#ifdef CONFIG_OF
static struct mc13xxx_leds_platform_data __init *mc13xxx_led_probe_dt(
struct platform_device *pdev)
{
struct mc13xxx_leds *leds = platform_get_drvdata(pdev);
struct mc13xxx_leds_platform_data *pdata;
struct device_node *parent, *child;
struct device *dev = &pdev->dev;
int i = 0, ret = -ENODATA;
pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
if (!pdata)
return ERR_PTR(-ENOMEM);
of_node_get(dev->parent->of_node);
parent = of_find_node_by_name(dev->parent->of_node, "leds");
if (!parent)
goto out_node_put;
ret = of_property_read_u32_array(parent, "led-control",
pdata->led_control,
leds->devtype->num_regs);
if (ret)
goto out_node_put;
pdata->num_leds = of_get_child_count(parent);
pdata->led = devm_kzalloc(dev, pdata->num_leds * sizeof(*pdata->led),
GFP_KERNEL);
if (!pdata->led) {
ret = -ENOMEM;
goto out_node_put;
}
for_each_child_of_node(parent, child) {
const char *str;
u32 tmp;
if (of_property_read_u32(child, "reg", &tmp))
continue;
pdata->led[i].id = leds->devtype->led_min + tmp;
if (!of_property_read_string(child, "label", &str))
pdata->led[i].name = str;
if (!of_property_read_string(child, "linux,default-trigger",
&str))
pdata->led[i].default_trigger = str;
i++;
}
pdata->num_leds = i;
ret = i > 0 ? 0 : -ENODATA;
out_node_put:
of_node_put(parent);
return ret ? ERR_PTR(ret) : pdata;
}
#else
static inline struct mc13xxx_leds_platform_data __init *mc13xxx_led_probe_dt(
struct platform_device *pdev)
{
return ERR_PTR(-ENOSYS);
}
#endif
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 device *dev = &pdev->dev;
struct mc13xxx *mcdev = dev_get_drvdata(pdev->dev.parent); struct mc13xxx_leds_platform_data *pdata = dev_get_platdata(dev);
struct mc13xxx *mcdev = dev_get_drvdata(dev->parent);
struct mc13xxx_led_devtype *devtype = struct mc13xxx_led_devtype *devtype =
(struct mc13xxx_led_devtype *)pdev->id_entry->driver_data; (struct mc13xxx_led_devtype *)pdev->id_entry->driver_data;
struct mc13xxx_leds *leds; struct mc13xxx_leds *leds;
int i, id, num_leds, ret = -ENODATA; int i, id, ret = -ENODATA;
u32 reg, init_led = 0; u32 init_led = 0;
if (!pdata) { leds = devm_kzalloc(dev, sizeof(*leds), GFP_KERNEL);
dev_err(&pdev->dev, "Missing platform data\n");
return -ENODEV;
}
num_leds = pdata->num_leds;
if ((num_leds < 1) ||
(num_leds > (devtype->led_max - devtype->led_min + 1))) {
dev_err(&pdev->dev, "Invalid LED count %d\n", num_leds);
return -EINVAL;
}
leds = devm_kzalloc(&pdev->dev, num_leds * sizeof(struct mc13xxx_led) +
sizeof(struct mc13xxx_leds), GFP_KERNEL);
if (!leds) if (!leds)
return -ENOMEM; return -ENOMEM;
leds->devtype = devtype; leds->devtype = devtype;
leds->num_leds = num_leds; leds->master = mcdev;
platform_set_drvdata(pdev, leds); platform_set_drvdata(pdev, leds);
if (dev->parent->of_node) {
pdata = mc13xxx_led_probe_dt(pdev);
if (IS_ERR(pdata))
return PTR_ERR(pdata);
} else if (!pdata)
return -ENODATA;
leds->num_leds = pdata->num_leds;
if ((leds->num_leds < 1) ||
(leds->num_leds > (devtype->led_max - devtype->led_min + 1))) {
dev_err(dev, "Invalid LED count %d\n", leds->num_leds);
return -EINVAL;
}
leds->led = devm_kzalloc(dev, leds->num_leds * sizeof(*leds->led),
GFP_KERNEL);
if (!leds->led)
return -ENOMEM;
for (i = 0; i < devtype->num_regs; i++) { for (i = 0; i < devtype->num_regs; i++) {
reg = pdata->led_control[i]; ret = mc13xxx_reg_write(mcdev, leds->devtype->ledctrl_base + i,
WARN_ON(reg >= (1 << 24)); pdata->led_control[i]);
ret = mc13xxx_reg_write(mcdev, MC13XXX_REG_LED_CONTROL(i), reg);
if (ret) if (ret)
return ret; return ret;
} }
for (i = 0; i < num_leds; i++) { for (i = 0; i < leds->num_leds; i++) {
const char *name, *trig; const char *name, *trig;
ret = -EINVAL; ret = -EINVAL;
@ -180,30 +244,29 @@ static int __init mc13xxx_led_probe(struct platform_device *pdev)
trig = pdata->led[i].default_trigger; trig = pdata->led[i].default_trigger;
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(dev, "Invalid ID %i\n", id);
break; break;
} }
if (init_led & (1 << id)) { if (init_led & (1 << id)) {
dev_warn(&pdev->dev, dev_warn(dev, "LED %i already initialized\n", id);
"LED %i already initialized\n", id);
break; break;
} }
init_led |= 1 << id; init_led |= 1 << id;
leds->led[i].id = id; leds->led[i].id = id;
leds->led[i].master = mcdev; leds->led[i].leds = leds;
leds->led[i].cdev.name = name; leds->led[i].cdev.name = name;
leds->led[i].cdev.default_trigger = trig; leds->led[i].cdev.default_trigger = trig;
leds->led[i].cdev.flags = LED_CORE_SUSPENDRESUME;
leds->led[i].cdev.brightness_set = mc13xxx_led_set; leds->led[i].cdev.brightness_set = mc13xxx_led_set;
leds->led[i].cdev.brightness = LED_OFF; leds->led[i].cdev.max_brightness = mc13xxx_max_brightness(id);
INIT_WORK(&leds->led[i].work, mc13xxx_led_work); INIT_WORK(&leds->led[i].work, mc13xxx_led_work);
ret = led_classdev_register(pdev->dev.parent, ret = led_classdev_register(dev->parent, &leds->led[i].cdev);
&leds->led[i].cdev);
if (ret) { if (ret) {
dev_err(&pdev->dev, "Failed to register LED %i\n", id); dev_err(dev, "Failed to register LED %i\n", id);
break; break;
} }
} }
@ -219,7 +282,6 @@ static int __init mc13xxx_led_probe(struct platform_device *pdev)
static int mc13xxx_led_remove(struct platform_device *pdev) static int mc13xxx_led_remove(struct platform_device *pdev)
{ {
struct mc13xxx *mcdev = dev_get_drvdata(pdev->dev.parent);
struct mc13xxx_leds *leds = platform_get_drvdata(pdev); struct mc13xxx_leds *leds = platform_get_drvdata(pdev);
int i; int i;
@ -228,9 +290,6 @@ static int mc13xxx_led_remove(struct platform_device *pdev)
cancel_work_sync(&leds->led[i].work); cancel_work_sync(&leds->led[i].work);
} }
for (i = 0; i < leds->devtype->num_regs; i++)
mc13xxx_reg_write(mcdev, MC13XXX_REG_LED_CONTROL(i), 0);
return 0; return 0;
} }
@ -238,17 +297,27 @@ static const struct mc13xxx_led_devtype mc13783_led_devtype = {
.led_min = MC13783_LED_MD, .led_min = MC13783_LED_MD,
.led_max = MC13783_LED_B3, .led_max = MC13783_LED_B3,
.num_regs = 6, .num_regs = 6,
.ledctrl_base = 51,
}; };
static const struct mc13xxx_led_devtype mc13892_led_devtype = { static const struct mc13xxx_led_devtype mc13892_led_devtype = {
.led_min = MC13892_LED_MD, .led_min = MC13892_LED_MD,
.led_max = MC13892_LED_B, .led_max = MC13892_LED_B,
.num_regs = 4, .num_regs = 4,
.ledctrl_base = 51,
};
static const struct mc13xxx_led_devtype mc34708_led_devtype = {
.led_min = MC34708_LED_R,
.led_max = MC34708_LED_G,
.num_regs = 1,
.ledctrl_base = 54,
}; };
static const struct platform_device_id mc13xxx_led_id_table[] = { static const struct platform_device_id mc13xxx_led_id_table[] = {
{ "mc13783-led", (kernel_ulong_t)&mc13783_led_devtype, }, { "mc13783-led", (kernel_ulong_t)&mc13783_led_devtype, },
{ "mc13892-led", (kernel_ulong_t)&mc13892_led_devtype, }, { "mc13892-led", (kernel_ulong_t)&mc13892_led_devtype, },
{ "mc34708-led", (kernel_ulong_t)&mc34708_led_devtype, },
{ } { }
}; };
MODULE_DEVICE_TABLE(platform, mc13xxx_led_id_table); MODULE_DEVICE_TABLE(platform, mc13xxx_led_id_table);

View File

@ -21,7 +21,6 @@
*/ */
#include <linux/module.h> #include <linux/module.h>
#include <linux/init.h>
#include <linux/irq.h> #include <linux/irq.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/spinlock.h> #include <linux/spinlock.h>

View File

@ -23,7 +23,6 @@
*/ */
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/init.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/gpio.h> #include <linux/gpio.h>

View File

@ -8,7 +8,6 @@
*/ */
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/init.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/leds.h> #include <linux/leds.h>

View File

@ -14,7 +14,6 @@
#include <linux/module.h> #include <linux/module.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/init.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/of_platform.h> #include <linux/of_platform.h>
#include <linux/fb.h> #include <linux/fb.h>
@ -84,6 +83,15 @@ static inline size_t sizeof_pwm_leds_priv(int num_leds)
(sizeof(struct led_pwm_data) * num_leds); (sizeof(struct led_pwm_data) * num_leds);
} }
static void led_pwm_cleanup(struct led_pwm_priv *priv)
{
while (priv->num_leds--) {
led_classdev_unregister(&priv->leds[priv->num_leds].cdev);
if (priv->leds[priv->num_leds].can_sleep)
cancel_work_sync(&priv->leds[priv->num_leds].work);
}
}
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)
{ {
@ -131,8 +139,7 @@ static int led_pwm_create_of(struct platform_device *pdev,
return 0; return 0;
err: err:
while (priv->num_leds--) led_pwm_cleanup(priv);
led_classdev_unregister(&priv->leds[priv->num_leds].cdev);
return ret; return ret;
} }
@ -200,8 +207,8 @@ static int led_pwm_probe(struct platform_device *pdev)
return 0; return 0;
err: err:
while (i--) priv->num_leds = i;
led_classdev_unregister(&priv->leds[i].cdev); led_pwm_cleanup(priv);
return ret; return ret;
} }
@ -209,13 +216,8 @@ err:
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); struct led_pwm_priv *priv = platform_get_drvdata(pdev);
int i;
for (i = 0; i < priv->num_leds; i++) { led_pwm_cleanup(priv);
led_classdev_unregister(&priv->leds[i].cdev);
if (priv->leds[i].can_sleep)
cancel_work_sync(&priv->leds[i].work);
}
return 0; return 0;
} }

View File

@ -12,7 +12,6 @@
*/ */
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/init.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/leds.h> #include <linux/leds.h>
#include <linux/gpio.h> #include <linux/gpio.h>

View File

@ -63,7 +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 DEFINE_PCI_DEVICE_TABLE(ich7_lpc_pci_id) = { static const struct pci_device_id 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) },
@ -78,7 +78,7 @@ static int __init ss4200_led_dmi_callback(const struct dmi_system_id *id)
return 1; return 1;
} }
static bool __initdata nodetect; static bool nodetect;
module_param_named(nodetect, nodetect, bool, 0); module_param_named(nodetect, nodetect, bool, 0);
MODULE_PARM_DESC(nodetect, "Skip DMI-based hardware detection"); MODULE_PARM_DESC(nodetect, "Skip DMI-based hardware detection");

View File

@ -10,7 +10,6 @@
*/ */
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/init.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/leds.h> #include <linux/leds.h>

View File

@ -10,7 +10,6 @@
*/ */
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/init.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/leds.h> #include <linux/leds.h>
#include <linux/err.h> #include <linux/err.h>

View File

@ -26,6 +26,7 @@
#include <linux/percpu.h> #include <linux/percpu.h>
#include <linux/syscore_ops.h> #include <linux/syscore_ops.h>
#include <linux/rwsem.h> #include <linux/rwsem.h>
#include <linux/cpu.h>
#include "../leds.h" #include "../leds.h"
#define MAX_NAME_LEN 8 #define MAX_NAME_LEN 8
@ -92,6 +93,26 @@ static struct syscore_ops ledtrig_cpu_syscore_ops = {
.resume = ledtrig_cpu_syscore_resume, .resume = ledtrig_cpu_syscore_resume,
}; };
static int ledtrig_cpu_notify(struct notifier_block *self,
unsigned long action, void *hcpu)
{
switch (action & ~CPU_TASKS_FROZEN) {
case CPU_STARTING:
ledtrig_cpu(CPU_LED_START);
break;
case CPU_DYING:
ledtrig_cpu(CPU_LED_STOP);
break;
}
return NOTIFY_OK;
}
static struct notifier_block ledtrig_cpu_nb = {
.notifier_call = ledtrig_cpu_notify,
};
static int __init ledtrig_cpu_init(void) static int __init ledtrig_cpu_init(void)
{ {
int cpu; int cpu;
@ -113,6 +134,7 @@ static int __init ledtrig_cpu_init(void)
} }
register_syscore_ops(&ledtrig_cpu_syscore_ops); register_syscore_ops(&ledtrig_cpu_syscore_ops);
register_cpu_notifier(&ledtrig_cpu_nb);
pr_info("ledtrig-cpu: registered to indicate activity on CPUs\n"); pr_info("ledtrig-cpu: registered to indicate activity on CPUs\n");
@ -124,6 +146,8 @@ static void __exit ledtrig_cpu_exit(void)
{ {
int cpu; int cpu;
unregister_cpu_notifier(&ledtrig_cpu_nb);
for_each_possible_cpu(cpu) { for_each_possible_cpu(cpu) {
struct led_trigger_cpu *trig = &per_cpu(cpu_trig, cpu); struct led_trigger_cpu *trig = &per_cpu(cpu_trig, cpu);

View File

@ -104,6 +104,9 @@ enum {
MC13892_LED_R, MC13892_LED_R,
MC13892_LED_G, MC13892_LED_G,
MC13892_LED_B, MC13892_LED_B,
/* MC34708 LED IDs */
MC34708_LED_R,
MC34708_LED_G,
}; };
struct mc13xxx_led_platform_data { struct mc13xxx_led_platform_data {
@ -163,6 +166,9 @@ struct mc13xxx_leds_platform_data {
#define MC13892_LED_C2_CURRENT_G(x) (((x) & 0x7) << 21) #define MC13892_LED_C2_CURRENT_G(x) (((x) & 0x7) << 21)
/* MC13892 LED Control 3 */ /* MC13892 LED Control 3 */
#define MC13892_LED_C3_CURRENT_B(x) (((x) & 0x7) << 9) #define MC13892_LED_C3_CURRENT_B(x) (((x) & 0x7) << 9)
/* MC34708 LED Control 0 */
#define MC34708_LED_C0_CURRENT_R(x) (((x) & 0x3) << 9)
#define MC34708_LED_C0_CURRENT_G(x) (((x) & 0x3) << 21)
u32 led_control[MAX_LED_CONTROL_REGS]; u32 led_control[MAX_LED_CONTROL_REGS];
}; };

View File

@ -1,5 +1,4 @@
/* arch/arm/mach-s3c2410/include/mach/leds-gpio.h /*
*
* Copyright (c) 2006 Simtec Electronics * Copyright (c) 2006 Simtec Electronics
* http://armlinux.simtec.co.uk/ * http://armlinux.simtec.co.uk/
* Ben Dooks <ben@simtec.co.uk> * Ben Dooks <ben@simtec.co.uk>
@ -11,8 +10,8 @@
* published by the Free Software Foundation. * published by the Free Software Foundation.
*/ */
#ifndef __ASM_ARCH_LEDSGPIO_H #ifndef __LEDS_S3C24XX_H
#define __ASM_ARCH_LEDSGPIO_H "leds-gpio.h" #define __LEDS_S3C24XX_H
#define S3C24XX_LEDF_ACTLOW (1<<0) /* LED is on when GPIO low */ #define S3C24XX_LEDF_ACTLOW (1<<0) /* LED is on when GPIO low */
#define S3C24XX_LEDF_TRISTATE (1<<1) /* tristate to turn off */ #define S3C24XX_LEDF_TRISTATE (1<<1) /* tristate to turn off */
@ -25,4 +24,4 @@ struct s3c24xx_led_platdata {
char *def_trigger; char *def_trigger;
}; };
#endif /* __ASM_ARCH_LEDSGPIO_H */ #endif /* __LEDS_S3C24XX_H */