diff options
Diffstat (limited to 'drivers/leds')
38 files changed, 788 insertions, 481 deletions
diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig index 875bbe4c962..a1b044e7eaa 100644 --- a/drivers/leds/Kconfig +++ b/drivers/leds/Kconfig @@ -406,12 +406,12 @@ config LEDS_MC13783  	depends on MFD_MC13XXX  	help  	  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  	tristate "LED support for Network Space v2 GPIO LEDs"  	depends on LEDS_CLASS -	depends on ARCH_KIRKWOOD +	depends on ARCH_KIRKWOOD || MACH_KIRKWOOD  	default y  	help  	  This option enable support for the dual-GPIO LED found on the @@ -421,7 +421,7 @@ config LEDS_NS2  config LEDS_NETXBIG  	tristate "LED support for Big Network series LEDs"  	depends on LEDS_CLASS -	depends on ARCH_KIRKWOOD +	depends on ARCH_KIRKWOOD || MACH_KIRKWOOD  	default y  	help  	  This option enable support for LEDs found on the LaCie 2Big @@ -464,11 +464,13 @@ config LEDS_LM355x  config LEDS_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  	  This option enables support for the LEDs on the Bachmann OT200.  	  Say Y to enable LEDs on the Bachmann OT200. +comment "LED driver for blink(1) USB RGB LED is under Special HID drivers (HID_THINGM)" +  config LEDS_BLINKM  	tristate "LED support for the BlinkM I2C RGB LED"  	depends on LEDS_CLASS @@ -477,6 +479,14 @@ config LEDS_BLINKM  	  This option enables support for the BlinkM RGB LED connected  	  through I2C. Say Y to enable support for the BlinkM LED. +config LEDS_VERSATILE +	tristate "LED support for the ARM Versatile and RealView" +	depends on ARCH_REALVIEW || ARCH_VERSATILE +	depends on LEDS_CLASS +	help +	  This option enabled support for the LEDs on the ARM Versatile +	  and RealView boards. Say Y to enabled these. +  comment "LED Triggers"  source "drivers/leds/trigger/Kconfig" diff --git a/drivers/leds/Makefile b/drivers/leds/Makefile index 8979b0b2c85..79c5155199a 100644 --- a/drivers/leds/Makefile +++ b/drivers/leds/Makefile @@ -53,6 +53,7 @@ obj-$(CONFIG_LEDS_ASIC3)		+= leds-asic3.o  obj-$(CONFIG_LEDS_MAX8997)		+= leds-max8997.o  obj-$(CONFIG_LEDS_LM355x)		+= leds-lm355x.o  obj-$(CONFIG_LEDS_BLINKM)		+= leds-blinkm.o +obj-$(CONFIG_LEDS_VERSATILE)		+= leds-versatile.o  # LED SPI Drivers  obj-$(CONFIG_LEDS_DAC124S085)		+= leds-dac124s085.o diff --git a/drivers/leds/dell-led.c b/drivers/leds/dell-led.c index e5c57389efd..c36acaf566a 100644 --- a/drivers/leds/dell-led.c +++ b/drivers/leds/dell-led.c @@ -15,12 +15,15 @@  #include <linux/leds.h>  #include <linux/slab.h>  #include <linux/module.h> +#include <linux/dmi.h> +#include <linux/dell-led.h>  MODULE_AUTHOR("Louis Davis/Jim Dailey");  MODULE_DESCRIPTION("Dell LED Control Driver");  MODULE_LICENSE("GPL");  #define DELL_LED_BIOS_GUID "F6E4FE6E-909D-47cb-8BAB-C9F6F2F8D396" +#define DELL_APP_GUID "A80593CE-A997-11DA-B012-B622A1EF5492"  MODULE_ALIAS("wmi:" DELL_LED_BIOS_GUID);  /* Error Result Codes: */ @@ -39,6 +42,149 @@ MODULE_ALIAS("wmi:" DELL_LED_BIOS_GUID);  #define CMD_LED_OFF	17  #define CMD_LED_BLINK	18 +struct app_wmi_args { +	u16 class; +	u16 selector; +	u32 arg1; +	u32 arg2; +	u32 arg3; +	u32 arg4; +	u32 res1; +	u32 res2; +	u32 res3; +	u32 res4; +	char dummy[92]; +}; + +#define GLOBAL_MIC_MUTE_ENABLE	0x364 +#define GLOBAL_MIC_MUTE_DISABLE	0x365 + +struct dell_bios_data_token { +	u16 tokenid; +	u16 location; +	u16 value; +}; + +struct __attribute__ ((__packed__)) dell_bios_calling_interface { +	struct	dmi_header header; +	u16	cmd_io_addr; +	u8	cmd_io_code; +	u32	supported_cmds; +	struct	dell_bios_data_token damap[]; +}; + +static struct dell_bios_data_token dell_mic_tokens[2]; + +static int dell_wmi_perform_query(struct app_wmi_args *args) +{ +	struct app_wmi_args *bios_return; +	union acpi_object *obj; +	struct acpi_buffer input; +	struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL }; +	acpi_status status; +	u32 rc = -EINVAL; + +	input.length = 128; +	input.pointer = args; + +	status = wmi_evaluate_method(DELL_APP_GUID, 0, 1, &input, &output); +	if (!ACPI_SUCCESS(status)) +		goto err_out0; + +	obj = output.pointer; +	if (!obj) +		goto err_out0; + +	if (obj->type != ACPI_TYPE_BUFFER) +		goto err_out1; + +	bios_return = (struct app_wmi_args *)obj->buffer.pointer; +	rc = bios_return->res1; +	if (rc) +		goto err_out1; + +	memcpy(args, bios_return, sizeof(struct app_wmi_args)); +	rc = 0; + + err_out1: +	kfree(obj); + err_out0: +	return rc; +} + +static void __init find_micmute_tokens(const struct dmi_header *dm, void *dummy) +{ +	struct dell_bios_calling_interface *calling_interface; +	struct dell_bios_data_token *token; +	int token_size = sizeof(struct dell_bios_data_token); +	int i = 0; + +	if (dm->type == 0xda && dm->length > 17) { +		calling_interface = container_of(dm, +				struct dell_bios_calling_interface, header); + +		token = &calling_interface->damap[i]; +		while (token->tokenid != 0xffff) { +			if (token->tokenid == GLOBAL_MIC_MUTE_DISABLE) +				memcpy(&dell_mic_tokens[0], token, token_size); +			else if (token->tokenid == GLOBAL_MIC_MUTE_ENABLE) +				memcpy(&dell_mic_tokens[1], token, token_size); + +			i++; +			token = &calling_interface->damap[i]; +		} +	} +} + +static int dell_micmute_led_set(int state) +{ +	struct app_wmi_args args; +	struct dell_bios_data_token *token; + +	if (!wmi_has_guid(DELL_APP_GUID)) +		return -ENODEV; + +	if (state == 0 || state == 1) +		token = &dell_mic_tokens[state]; +	else +		return -EINVAL; + +	memset(&args, 0, sizeof(struct app_wmi_args)); + +	args.class = 1; +	args.arg1 = token->location; +	args.arg2 = token->value; + +	dell_wmi_perform_query(&args); + +	return state; +} + +int dell_app_wmi_led_set(int whichled, int on) +{ +	int state = 0; + +	switch (whichled) { +	case DELL_LED_MICMUTE: +		state = dell_micmute_led_set(on); +		break; +	default: +		pr_warn("led type %x is not supported\n", whichled); +		break; +	} + +	return state; +} +EXPORT_SYMBOL_GPL(dell_app_wmi_led_set); + +static int __init dell_micmute_led_init(void) +{ +	memset(dell_mic_tokens, 0, sizeof(struct dell_bios_data_token) * 2); +	dmi_walk(find_micmute_tokens, NULL); + +	return 0; +} +  struct bios_args {  	unsigned char length;  	unsigned char result_code; @@ -181,21 +327,32 @@ static int __init dell_led_init(void)  {  	int error = 0; -	if (!wmi_has_guid(DELL_LED_BIOS_GUID)) +	if (!wmi_has_guid(DELL_LED_BIOS_GUID) && !wmi_has_guid(DELL_APP_GUID))  		return -ENODEV; -	error = led_off(); -	if (error != 0) -		return -ENODEV; +	if (wmi_has_guid(DELL_APP_GUID)) +		error = dell_micmute_led_init(); -	return led_classdev_register(NULL, &dell_led); +	if (wmi_has_guid(DELL_LED_BIOS_GUID)) { +		error = led_off(); +		if (error != 0) +			return -ENODEV; + +		error = led_classdev_register(NULL, &dell_led); +	} + +	return error;  }  static void __exit dell_led_exit(void)  { -	led_classdev_unregister(&dell_led); +	int error = 0; -	led_off(); +	if (wmi_has_guid(DELL_LED_BIOS_GUID)) { +		error = led_off(); +		if (error == 0) +			led_classdev_unregister(&dell_led); +	}  }  module_init(dell_led_init); diff --git a/drivers/leds/led-core.c b/drivers/leds/led-core.c index ce8921a753a..71b40d3bf77 100644 --- a/drivers/leds/led-core.c +++ b/drivers/leds/led-core.c @@ -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_off = delay_off; -	/* never on - don't blink */ -	if (!delay_on) +	/* never on - just set to off */ +	if (!delay_on) { +		__led_set_brightness(led_cdev, LED_OFF);  		return; +	}  	/* never off - just set to brightness */  	if (!delay_off) { diff --git a/drivers/leds/led-triggers.c b/drivers/leds/led-triggers.c index 3c972b2f989..c3734f10fdd 100644 --- a/drivers/leds/led-triggers.c +++ b/drivers/leds/led-triggers.c @@ -13,7 +13,6 @@  #include <linux/module.h>  #include <linux/kernel.h> -#include <linux/init.h>  #include <linux/list.h>  #include <linux/spinlock.h>  #include <linux/device.h> @@ -220,9 +219,12 @@ void led_trigger_unregister(struct led_trigger *trig)  {  	struct led_classdev *led_cdev; +	if (list_empty_careful(&trig->next_trig)) +		return; +  	/* Remove from the list of led triggers */  	down_write(&triggers_list_lock); -	list_del(&trig->next_trig); +	list_del_init(&trig->next_trig);  	up_write(&triggers_list_lock);  	/* Remove anyone actively using this trigger */ @@ -242,18 +244,14 @@ EXPORT_SYMBOL_GPL(led_trigger_unregister);  void led_trigger_event(struct led_trigger *trig,  			enum led_brightness brightness)  { -	struct list_head *entry; +	struct led_classdev *led_cdev;  	if (!trig)  		return;  	read_lock(&trig->leddev_list_lock); -	list_for_each(entry, &trig->led_cdevs) { -		struct led_classdev *led_cdev; - -		led_cdev = list_entry(entry, struct led_classdev, trig_list); +	list_for_each_entry(led_cdev, &trig->led_cdevs, trig_list)  		led_set_brightness(led_cdev, brightness); -	}  	read_unlock(&trig->leddev_list_lock);  }  EXPORT_SYMBOL_GPL(led_trigger_event); @@ -264,16 +262,13 @@ static void led_trigger_blink_setup(struct led_trigger *trig,  			     int oneshot,  			     int invert)  { -	struct list_head *entry; +	struct led_classdev *led_cdev;  	if (!trig)  		return;  	read_lock(&trig->leddev_list_lock); -	list_for_each(entry, &trig->led_cdevs) { -		struct led_classdev *led_cdev; - -		led_cdev = list_entry(entry, struct led_classdev, trig_list); +	list_for_each_entry(led_cdev, &trig->led_cdevs, trig_list) {  		if (oneshot)  			led_blink_set_oneshot(led_cdev, delay_on, delay_off,  					      invert); diff --git a/drivers/leds/leds-88pm860x.c b/drivers/leds/leds-88pm860x.c index 5f588c0a376..c2def5551ce 100644 --- a/drivers/leds/leds-88pm860x.c +++ b/drivers/leds/leds-88pm860x.c @@ -11,7 +11,6 @@   */  #include <linux/kernel.h> -#include <linux/init.h>  #include <linux/of.h>  #include <linux/platform_device.h>  #include <linux/i2c.h> @@ -131,10 +130,9 @@ static int pm860x_led_dt_init(struct platform_device *pdev,  	struct device_node *nproot, *np;  	int iset = 0; -	nproot = of_node_get(pdev->dev.parent->of_node); -	if (!nproot) +	if (!pdev->dev.parent->of_node)  		return -ENODEV; -	nproot = of_find_node_by_name(nproot, "leds"); +	nproot = of_get_child_by_name(pdev->dev.parent->of_node, "leds");  	if (!nproot) {  		dev_err(&pdev->dev, "failed to find leds node\n");  		return -ENODEV; diff --git a/drivers/leds/leds-adp5520.c b/drivers/leds/leds-adp5520.c index 7e311a120b1..5036d7b4f82 100644 --- a/drivers/leds/leds-adp5520.c +++ b/drivers/leds/leds-adp5520.c @@ -15,7 +15,6 @@  #include <linux/module.h>  #include <linux/kernel.h> -#include <linux/init.h>  #include <linux/platform_device.h>  #include <linux/leds.h>  #include <linux/workqueue.h> @@ -121,13 +120,10 @@ static int adp5520_led_probe(struct platform_device *pdev)  	led = devm_kzalloc(&pdev->dev, sizeof(*led) * pdata->num_leds,  				GFP_KERNEL); -	if (led == NULL) { -		dev_err(&pdev->dev, "failed to alloc memory\n"); +	if (!led)  		return -ENOMEM; -	}  	ret = adp5520_led_prepare(pdev); -  	if (ret) {  		dev_err(&pdev->dev, "failed to write\n");  		return ret; diff --git a/drivers/leds/leds-asic3.c b/drivers/leds/leds-asic3.c index 6de216a89a0..70c74a7f0df 100644 --- a/drivers/leds/leds-asic3.c +++ b/drivers/leds/leds-asic3.c @@ -7,7 +7,6 @@   */  #include <linux/kernel.h> -#include <linux/init.h>  #include <linux/platform_device.h>  #include <linux/leds.h>  #include <linux/slab.h> diff --git a/drivers/leds/leds-bd2802.c b/drivers/leds/leds-bd2802.c index fb5a3472d61..6078c15d345 100644 --- a/drivers/leds/leds-bd2802.c +++ b/drivers/leds/leds-bd2802.c @@ -678,10 +678,8 @@ static int bd2802_probe(struct i2c_client *client,  	int ret, i;  	led = devm_kzalloc(&client->dev, sizeof(struct bd2802_led), GFP_KERNEL); -	if (!led) { -		dev_err(&client->dev, "failed to allocate driver data\n"); +	if (!led)  		return -ENOMEM; -	}  	led->client = client;  	pdata = led->pdata = dev_get_platdata(&client->dev); diff --git a/drivers/leds/leds-blinkm.c b/drivers/leds/leds-blinkm.c index a502678cc7f..d0452b099ae 100644 --- a/drivers/leds/leds-blinkm.c +++ b/drivers/leds/leds-blinkm.c @@ -18,7 +18,6 @@   */  #include <linux/module.h> -#include <linux/init.h>  #include <linux/slab.h>  #include <linux/jiffies.h>  #include <linux/i2c.h> @@ -161,13 +160,10 @@ static ssize_t show_color_common(struct device *dev, char *buf, int color)  	switch (color) {  	case RED:  		return scnprintf(buf, PAGE_SIZE, "%02X\n", data->red); -		break;  	case GREEN:  		return scnprintf(buf, PAGE_SIZE, "%02X\n", data->green); -		break;  	case BLUE:  		return scnprintf(buf, PAGE_SIZE, "%02X\n", data->blue); -		break;  	default:  		return -EINVAL;  	} @@ -447,7 +443,7 @@ static void led_work(struct work_struct *work)  {  	int ret;  	struct blinkm_led *led; -	struct blinkm_data *data ; +	struct blinkm_data *data;  	struct blinkm_work *blm_work = work_to_blmwork(work);  	led = blm_work->blinkm_led; diff --git a/drivers/leds/leds-clevo-mail.c b/drivers/leds/leds-clevo-mail.c index d93e2455da5..f58a354428e 100644 --- a/drivers/leds/leds-clevo-mail.c +++ b/drivers/leds/leds-clevo-mail.c @@ -19,7 +19,7 @@ MODULE_AUTHOR("Márton Németh <nm127@freemail.hu>");  MODULE_DESCRIPTION("Clevo mail LED driver");  MODULE_LICENSE("GPL"); -static bool __initdata nodetect; +static bool nodetect;  module_param_named(nodetect, nodetect, bool, 0);  MODULE_PARM_DESC(nodetect, "Skip DMI hardware detection"); @@ -153,7 +153,7 @@ static struct led_classdev clevo_mail_led = {  	.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);  } @@ -165,7 +165,6 @@ static int clevo_mail_led_remove(struct platform_device *pdev)  }  static struct platform_driver clevo_mail_led_driver = { -	.probe		= clevo_mail_led_probe,  	.remove		= clevo_mail_led_remove,  	.driver		= {  		.name		= KBUILD_MODNAME, diff --git a/drivers/leds/leds-cobalt-qube.c b/drivers/leds/leds-cobalt-qube.c index 8abcb66db01..910339d86ed 100644 --- a/drivers/leds/leds-cobalt-qube.c +++ b/drivers/leds/leds-cobalt-qube.c @@ -3,7 +3,6 @@   *   * Control the Cobalt Qube/RaQ front LED   */ -#include <linux/init.h>  #include <linux/io.h>  #include <linux/ioport.h>  #include <linux/leds.h> diff --git a/drivers/leds/leds-da903x.c b/drivers/leds/leds-da903x.c index 2a4b87f8091..54b8b5216b8 100644 --- a/drivers/leds/leds-da903x.c +++ b/drivers/leds/leds-da903x.c @@ -14,7 +14,6 @@  #include <linux/module.h>  #include <linux/kernel.h> -#include <linux/init.h>  #include <linux/platform_device.h>  #include <linux/leds.h>  #include <linux/workqueue.h> @@ -109,10 +108,8 @@ static int da903x_led_probe(struct platform_device *pdev)  	}  	led = devm_kzalloc(&pdev->dev, sizeof(struct da903x_led), GFP_KERNEL); -	if (led == NULL) { -		dev_err(&pdev->dev, "failed to alloc memory for LED%d\n", id); +	if (!led)  		return -ENOMEM; -	}  	led->cdev.name = pdata->name;  	led->cdev.default_trigger = pdata->default_trigger; diff --git a/drivers/leds/leds-da9052.c b/drivers/leds/leds-da9052.c index 865d4faf874..e4da1f460ac 100644 --- a/drivers/leds/leds-da9052.c +++ b/drivers/leds/leds-da9052.c @@ -14,7 +14,6 @@  #include <linux/module.h>  #include <linux/kernel.h> -#include <linux/init.h>  #include <linux/platform_device.h>  #include <linux/leds.h>  #include <linux/workqueue.h> @@ -127,8 +126,7 @@ static int da9052_led_probe(struct platform_device *pdev)  	led = devm_kzalloc(&pdev->dev,  			   sizeof(struct da9052_led) * pled->num_leds,  			   GFP_KERNEL); -	if (led == NULL) { -		dev_err(&pdev->dev, "Failed to alloc memory\n"); +	if (!led) {  		error = -ENOMEM;  		goto err;  	} diff --git a/drivers/leds/leds-dac124s085.c b/drivers/leds/leds-dac124s085.c index 1f9d8e62d37..db3ba8b4251 100644 --- a/drivers/leds/leds-dac124s085.c +++ b/drivers/leds/leds-dac124s085.c @@ -101,7 +101,6 @@ eledcr:  	while (i--)  		led_classdev_unregister(&dac->leds[i].ldev); -	spi_set_drvdata(spi, NULL);  	return ret;  } @@ -115,8 +114,6 @@ static int dac124s085_remove(struct spi_device *spi)  		cancel_work_sync(&dac->leds[i].work);  	} -	spi_set_drvdata(spi, NULL); -  	return 0;  } diff --git a/drivers/leds/leds-fsg.c b/drivers/leds/leds-fsg.c index b4d5a44cc41..2b4dc738dcd 100644 --- a/drivers/leds/leds-fsg.c +++ b/drivers/leds/leds-fsg.c @@ -16,7 +16,6 @@   */  #include <linux/kernel.h> -#include <linux/init.h>  #include <linux/platform_device.h>  #include <linux/leds.h>  #include <linux/module.h> diff --git a/drivers/leds/leds-gpio.c b/drivers/leds/leds-gpio.c index e8b01e57348..57ff20fecf5 100644 --- a/drivers/leds/leds-gpio.c +++ b/drivers/leds/leds-gpio.c @@ -11,10 +11,10 @@   *   */  #include <linux/kernel.h> -#include <linux/init.h>  #include <linux/platform_device.h>  #include <linux/gpio.h>  #include <linux/leds.h> +#include <linux/of.h>  #include <linux/of_platform.h>  #include <linux/of_gpio.h>  #include <linux/slab.h> @@ -170,11 +170,11 @@ static struct gpio_leds_priv *gpio_leds_create_of(struct platform_device *pdev)  	int count, ret;  	/* count LEDs in this device, so we know how much to allocate */ -	count = of_get_child_count(np); +	count = of_get_available_child_count(np);  	if (!count)  		return ERR_PTR(-ENODEV); -	for_each_child_of_node(np, child) +	for_each_available_child_of_node(np, child)  		if (of_get_gpio(child, 0) == -EPROBE_DEFER)  			return ERR_PTR(-EPROBE_DEFER); @@ -183,7 +183,7 @@ static struct gpio_leds_priv *gpio_leds_create_of(struct platform_device *pdev)  	if (!priv)  		return ERR_PTR(-ENOMEM); -	for_each_child_of_node(np, child) { +	for_each_available_child_of_node(np, child) {  		struct gpio_led led = {};  		enum of_gpio_flags flags;  		const char *state; @@ -203,6 +203,9 @@ static struct gpio_leds_priv *gpio_leds_create_of(struct platform_device *pdev)  				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++],  				      &pdev->dev, NULL);  		if (ret < 0) { @@ -223,6 +226,8 @@ static const struct of_device_id of_gpio_leds_match[] = {  	{ .compatible = "gpio-leds", },  	{},  }; + +MODULE_DEVICE_TABLE(of, of_gpio_leds_match);  #else /* CONFIG_OF_GPIO */  static struct gpio_leds_priv *gpio_leds_create_of(struct platform_device *pdev)  { diff --git a/drivers/leds/leds-hp6xx.c b/drivers/leds/leds-hp6xx.c index 366b6055e33..d61a98896c7 100644 --- a/drivers/leds/leds-hp6xx.c +++ b/drivers/leds/leds-hp6xx.c @@ -12,7 +12,6 @@  #include <linux/module.h>  #include <linux/kernel.h> -#include <linux/init.h>  #include <linux/platform_device.h>  #include <linux/leds.h>  #include <asm/hd64461.h> diff --git a/drivers/leds/leds-lm3533.c b/drivers/leds/leds-lm3533.c index 027ede73b80..e2c642c1169 100644 --- a/drivers/leds/leds-lm3533.c +++ b/drivers/leds/leds-lm3533.c @@ -12,7 +12,6 @@   */  #include <linux/module.h> -#include <linux/init.h>  #include <linux/leds.h>  #include <linux/mfd/core.h>  #include <linux/mutex.h> diff --git a/drivers/leds/leds-lp5521.c b/drivers/leds/leds-lp5521.c index 05188351711..8ca197af286 100644 --- a/drivers/leds/leds-lp5521.c +++ b/drivers/leds/leds-lp5521.c @@ -25,7 +25,6 @@  #include <linux/delay.h>  #include <linux/firmware.h>  #include <linux/i2c.h> -#include <linux/init.h>  #include <linux/leds.h>  #include <linux/module.h>  #include <linux/mutex.h> @@ -152,12 +151,26 @@ static void lp5521_load_engine(struct lp55xx_chip *chip)  	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);  	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)  {  	int ret; @@ -244,18 +257,12 @@ static int lp5521_update_program_memory(struct lp55xx_chip *chip,  	if (i % 2)  		goto err; -	mutex_lock(&chip->lock); -  	for (i = 0; i < LP5521_PROGRAM_LENGTH; i++) {  		ret = lp55xx_write(chip, addr[idx] + i, pattern[i]); -		if (ret) { -			mutex_unlock(&chip->lock); +		if (ret)  			return -EINVAL; -		}  	} -	mutex_unlock(&chip->lock); -  	return size;  err: @@ -427,15 +434,17 @@ static ssize_t store_engine_load(struct device *dev,  {  	struct lp55xx_led *led = i2c_get_clientdata(to_i2c_client(dev));  	struct lp55xx_chip *chip = led->chip; +	int ret;  	mutex_lock(&chip->lock);  	chip->engine_idx = nr;  	lp5521_load_engine(chip); +	ret = lp5521_update_program_memory(chip, buf, len);  	mutex_unlock(&chip->lock); -	return lp5521_update_program_memory(chip, buf, len); +	return ret;  }  store_load(1)  store_load(2) @@ -568,7 +577,7 @@ static int lp5521_remove(struct i2c_client *client)  	struct lp55xx_led *led = i2c_get_clientdata(client);  	struct lp55xx_chip *chip = led->chip; -	lp5521_stop_engine(chip); +	lp5521_stop_all_engines(chip);  	lp55xx_unregister_sysfs(chip);  	lp55xx_unregister_leds(led, chip);  	lp55xx_deinit_device(chip); diff --git a/drivers/leds/leds-lp5523.c b/drivers/leds/leds-lp5523.c index fe3bcbb5747..9e1716f8098 100644 --- a/drivers/leds/leds-lp5523.c +++ b/drivers/leds/leds-lp5523.c @@ -1,5 +1,5 @@  /* - * lp5523.c - LP5523 LED Driver + * lp5523.c - LP5523, LP55231 LED Driver   *   * Copyright (C) 2010 Nokia Corporation   * Copyright (C) 2012 Texas Instruments @@ -25,16 +25,24 @@  #include <linux/delay.h>  #include <linux/firmware.h>  #include <linux/i2c.h> -#include <linux/init.h>  #include <linux/leds.h>  #include <linux/module.h>  #include <linux/mutex.h> +#include <linux/of.h>  #include <linux/platform_data/leds-lp55xx.h>  #include <linux/slab.h>  #include "leds-lp55xx-common.h" -#define LP5523_PROGRAM_LENGTH		32 +#define LP5523_PROGRAM_LENGTH		32	/* bytes */ +/* Memory is used like this: +   0x00 engine 1 program +   0x10 engine 2 program +   0x20 engine 3 program +   0x30 engine 1 muxing info +   0x40 engine 2 muxing info +   0x50 engine 3 muxing info +*/  #define LP5523_MAX_LEDS			9  /* Registers */ @@ -186,12 +194,26 @@ static void lp5523_load_engine_and_select_page(struct lp55xx_chip *chip)  	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);  	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)  {  	int i; @@ -302,7 +324,7 @@ static int lp5523_init_program_engine(struct lp55xx_chip *chip)  	}  out: -	lp5523_stop_engine(chip); +	lp5523_stop_all_engines(chip);  	return ret;  } @@ -336,18 +358,12 @@ static int lp5523_update_program_memory(struct lp55xx_chip *chip,  	if (i % 2)  		goto err; -	mutex_lock(&chip->lock); -  	for (i = 0; i < LP5523_PROGRAM_LENGTH; i++) {  		ret = lp55xx_write(chip, LP5523_REG_PROG_MEM + i, pattern[i]); -		if (ret) { -			mutex_unlock(&chip->lock); +		if (ret)  			return -EINVAL; -		}  	} -	mutex_unlock(&chip->lock); -  	return size;  err: @@ -547,15 +563,17 @@ static ssize_t store_engine_load(struct device *dev,  {  	struct lp55xx_led *led = i2c_get_clientdata(to_i2c_client(dev));  	struct lp55xx_chip *chip = led->chip; +	int ret;  	mutex_lock(&chip->lock);  	chip->engine_idx = nr;  	lp5523_load_engine_and_select_page(chip); +	ret = lp5523_update_program_memory(chip, buf, len);  	mutex_unlock(&chip->lock); -	return lp5523_update_program_memory(chip, buf, len); +	return ret;  }  store_load(1)  store_load(2) @@ -777,7 +795,7 @@ static int lp5523_remove(struct i2c_client *client)  	struct lp55xx_led *led = i2c_get_clientdata(client);  	struct lp55xx_chip *chip = led->chip; -	lp5523_stop_engine(chip); +	lp5523_stop_all_engines(chip);  	lp55xx_unregister_sysfs(chip);  	lp55xx_unregister_leds(led, chip);  	lp55xx_deinit_device(chip); @@ -796,6 +814,7 @@ MODULE_DEVICE_TABLE(i2c, lp5523_id);  #ifdef CONFIG_OF  static const struct of_device_id of_lp5523_leds_match[] = {  	{ .compatible = "national,lp5523", }, +	{ .compatible = "ti,lp55231", },  	{},  }; diff --git a/drivers/leds/leds-lp5562.c b/drivers/leds/leds-lp5562.c index 2585cfd5771..ca85724ab13 100644 --- a/drivers/leds/leds-lp5562.c +++ b/drivers/leds/leds-lp5562.c @@ -13,10 +13,10 @@  #include <linux/delay.h>  #include <linux/firmware.h>  #include <linux/i2c.h> -#include <linux/init.h>  #include <linux/leds.h>  #include <linux/module.h>  #include <linux/mutex.h> +#include <linux/of.h>  #include <linux/platform_data/leds-lp55xx.h>  #include <linux/slab.h> @@ -346,9 +346,9 @@ static void lp5562_write_program_memory(struct lp55xx_chip *chip,  /* check the size of program count */  static inline bool _is_pc_overflow(struct lp55xx_predef_pattern *ptn)  { -	return (ptn->size_r >= LP5562_PROGRAM_LENGTH || -		ptn->size_g >= LP5562_PROGRAM_LENGTH || -		ptn->size_b >= LP5562_PROGRAM_LENGTH); +	return ptn->size_r >= LP5562_PROGRAM_LENGTH || +	       ptn->size_g >= LP5562_PROGRAM_LENGTH || +	       ptn->size_b >= LP5562_PROGRAM_LENGTH;  }  static int lp5562_run_predef_led_pattern(struct lp55xx_chip *chip, int mode) diff --git a/drivers/leds/leds-lp55xx-common.c b/drivers/leds/leds-lp55xx-common.c index 351825b96f1..88317b4f7bf 100644 --- a/drivers/leds/leds-lp55xx-common.c +++ b/drivers/leds/leds-lp55xx-common.c @@ -20,6 +20,8 @@  #include <linux/module.h>  #include <linux/platform_data/leds-lp55xx.h>  #include <linux/slab.h> +#include <linux/gpio.h> +#include <linux/of_gpio.h>  #include "leds-lp55xx-common.h" @@ -165,6 +167,7 @@ static int lp55xx_init_led(struct lp55xx_led *led,  	led->led_current = pdata->led_config[chan].led_current;  	led->max_current = pdata->led_config[chan].max_current;  	led->chan_nr = pdata->led_config[chan].chan_nr; +	led->cdev.default_trigger = pdata->led_config[chan].default_trigger;  	if (led->chan_nr >= max_channel) {  		dev_err(dev, "Use channel numbers between 0 and %d\n", @@ -207,6 +210,7 @@ static void lp55xx_firmware_loaded(const struct firmware *fw, void *context)  {  	struct lp55xx_chip *chip = context;  	struct device *dev = &chip->cl->dev; +	enum lp55xx_engine_index idx = chip->engine_idx;  	if (!fw) {  		dev_err(dev, "firmware request failed\n"); @@ -216,6 +220,7 @@ static void lp55xx_firmware_loaded(const struct firmware *fw, void *context)  	/* handling firmware data is chip dependent */  	mutex_lock(&chip->lock); +	chip->engines[idx - 1].mode = LP55XX_ENGINE_LOAD;  	chip->fw = fw;  	if (chip->cfg->firmware_cb)  		chip->cfg->firmware_cb(chip); @@ -406,18 +411,18 @@ int lp55xx_init_device(struct lp55xx_chip *chip)  	if (!pdata || !cfg)  		return -EINVAL; -	if (pdata->setup_resources) { -		ret = pdata->setup_resources(); +	if (gpio_is_valid(pdata->enable_gpio)) { +		ret = devm_gpio_request_one(dev, pdata->enable_gpio, +					    GPIOF_DIR_OUT, "lp5523_enable");  		if (ret < 0) { -			dev_err(dev, "setup resoure err: %d\n", ret); +			dev_err(dev, "could not acquire enable gpio (err=%d)\n", +				ret);  			goto err;  		} -	} -	if (pdata->enable) { -		pdata->enable(0); +		gpio_set_value(pdata->enable_gpio, 0);  		usleep_range(1000, 2000); /* Keep enable down at least 1ms */ -		pdata->enable(1); +		gpio_set_value(pdata->enable_gpio, 1);  		usleep_range(1000, 2000); /* 500us abs min. */  	} @@ -458,11 +463,8 @@ void lp55xx_deinit_device(struct lp55xx_chip *chip)  	if (chip->clk)  		clk_disable_unprepare(chip->clk); -	if (pdata->enable) -		pdata->enable(0); - -	if (pdata->release_resources) -		pdata->release_resources(); +	if (gpio_is_valid(pdata->enable_gpio)) +		gpio_set_value(pdata->enable_gpio, 0);  }  EXPORT_SYMBOL_GPL(lp55xx_deinit_device); @@ -586,6 +588,8 @@ int lp55xx_of_populate_pdata(struct device *dev, struct device_node *np)  		of_property_read_string(child, "chan-name", &cfg[i].name);  		of_property_read_u8(child, "led-cur", &cfg[i].led_current);  		of_property_read_u8(child, "max-cur", &cfg[i].max_current); +		cfg[i].default_trigger = +			of_get_property(child, "linux,default-trigger", NULL);  		i++;  	} @@ -593,6 +597,8 @@ int lp55xx_of_populate_pdata(struct device *dev, struct device_node *np)  	of_property_read_string(np, "label", &pdata->label);  	of_property_read_u8(np, "clock-mode", &pdata->clock_mode); +	pdata->enable_gpio = of_get_named_gpio(np, "enable-gpio", 0); +  	/* LP8501 specific */  	of_property_read_u8(np, "pwr-sel", (u8 *)&pdata->pwr_sel); diff --git a/drivers/leds/leds-lp8501.c b/drivers/leds/leds-lp8501.c index 8d55a780ca4..00f068b0fa6 100644 --- a/drivers/leds/leds-lp8501.c +++ b/drivers/leds/leds-lp8501.c @@ -18,6 +18,7 @@  #include <linux/leds.h>  #include <linux/module.h>  #include <linux/mutex.h> +#include <linux/of.h>  #include <linux/platform_data/leds-lp55xx.h>  #include <linux/slab.h> @@ -262,7 +263,7 @@ static void lp8501_firmware_loaded(struct lp55xx_chip *chip)  	}  	/* -	 * Program momery sequence +	 * Program memory sequence  	 *  1) set engine mode to "LOAD"  	 *  2) write firmware data into program memory  	 */ diff --git a/drivers/leds/leds-lt3593.c b/drivers/leds/leds-lt3593.c index 3417e5be7b5..059f5b1f355 100644 --- a/drivers/leds/leds-lt3593.c +++ b/drivers/leds/leds-lt3593.c @@ -17,7 +17,6 @@   */  #include <linux/kernel.h> -#include <linux/init.h>  #include <linux/platform_device.h>  #include <linux/leds.h>  #include <linux/workqueue.h> diff --git a/drivers/leds/leds-mc13783.c b/drivers/leds/leds-mc13783.c index fa9b439323b..f1db88e2513 100644 --- a/drivers/leds/leds-mc13783.c +++ b/drivers/leds/leds-mc13783.c @@ -1,5 +1,5 @@  /* - * LEDs driver for Freescale MC13783/MC13892 + * LEDs driver for Freescale MC13783/MC13892/MC34708   *   * Copyright (C) 2010 Philippe Rétornaz   * @@ -17,57 +17,56 @@  #include <linux/module.h>  #include <linux/kernel.h> -#include <linux/init.h>  #include <linux/platform_device.h>  #include <linux/leds.h> +#include <linux/of.h>  #include <linux/workqueue.h>  #include <linux/mfd/mc13xxx.h> -#define MC13XXX_REG_LED_CONTROL(x)	(51 + (x)) -  struct mc13xxx_led_devtype {  	int	led_min;  	int	led_max;  	int	num_regs; +	u32	ledctrl_base;  };  struct mc13xxx_led {  	struct led_classdev	cdev;  	struct work_struct	work; -	struct mc13xxx		*master;  	enum led_brightness	new_brightness;  	int			id; +	struct mc13xxx_leds	*leds;  };  struct mc13xxx_leds { +	struct mc13xxx			*master;  	struct mc13xxx_led_devtype	*devtype;  	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)  {  	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) {  	case MC13783_LED_MD: -		reg = MC13XXX_REG_LED_CONTROL(2); -		shift = 9; -		mask = 0x0f; -		value = led->new_brightness >> 4; -		break;  	case MC13783_LED_AD: -		reg = MC13XXX_REG_LED_CONTROL(2); -		shift = 13; -		mask = 0x0f; -		value = led->new_brightness >> 4; -		break;  	case MC13783_LED_KP: -		reg = MC13XXX_REG_LED_CONTROL(2); -		shift = 17; -		mask = 0x0f; -		value = led->new_brightness >> 4; +		reg = 2; +		shift = 9 + (led->id - MC13783_LED_MD) * 4;  		break;  	case MC13783_LED_R1:  	case MC13783_LED_G1: @@ -80,46 +79,35 @@ static void mc13xxx_led_work(struct work_struct *work)  	case MC13783_LED_B3:  		off = led->id - MC13783_LED_R1;  		bank = off / 3; -		reg = MC13XXX_REG_LED_CONTROL(3) + bank; +		reg = 3 + bank;  		shift = (off - bank * 3) * 5 + 6; -		value = led->new_brightness >> 3; -		mask = 0x1f;  		break;  	case MC13892_LED_MD: -		reg = MC13XXX_REG_LED_CONTROL(0); -		shift = 3; -		mask = 0x3f; -		value = led->new_brightness >> 2; -		break;  	case MC13892_LED_AD: -		reg = MC13XXX_REG_LED_CONTROL(0); -		shift = 15; -		mask = 0x3f; -		value = led->new_brightness >> 2; -		break;  	case MC13892_LED_KP: -		reg = MC13XXX_REG_LED_CONTROL(1); -		shift = 3; -		mask = 0x3f; -		value = led->new_brightness >> 2; +		reg = (led->id - MC13892_LED_MD) / 2; +		shift = 3 + (led->id - MC13892_LED_MD) * 12;  		break;  	case MC13892_LED_R:  	case MC13892_LED_G:  	case MC13892_LED_B:  		off = led->id - MC13892_LED_R;  		bank = off / 2; -		reg = MC13XXX_REG_LED_CONTROL(2) + bank; +		reg = 2 + bank;  		shift = (off - bank * 2) * 12 + 3; -		value = led->new_brightness >> 2; -		mask = 0x3f; +		break; +	case MC34708_LED_R: +	case MC34708_LED_G: +		reg = 0; +		shift = 3 + (led->id - MC34708_LED_R) * 12;  		break;  	default:  		BUG();  	} -	mc13xxx_lock(led->master); -	mc13xxx_reg_rmw(led->master, reg, mask << shift, value << shift); -	mc13xxx_unlock(led->master); +	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, @@ -132,163 +120,153 @@ static void mc13xxx_led_set(struct led_classdev *led_cdev,  	schedule_work(&led->work);  } -static int __init mc13xxx_led_setup(struct mc13xxx_led *led, int max_current) +#ifdef CONFIG_OF +static struct mc13xxx_leds_platform_data __init *mc13xxx_led_probe_dt( +	struct platform_device *pdev)  { -	int shift, mask, reg, ret, bank; +	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; -	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(); +	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;  	} -	mc13xxx_lock(led->master); -	ret = mc13xxx_reg_rmw(led->master, reg, mask << shift, -			      max_current << shift); -	mc13xxx_unlock(led->master); +	for_each_child_of_node(parent, child) { +		const char *str; +		u32 tmp; -	return ret; +		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)  { -	struct mc13xxx_leds_platform_data *pdata = dev_get_platdata(&pdev->dev); -	struct mc13xxx *mcdev = dev_get_drvdata(pdev->dev.parent); +	struct device *dev = &pdev->dev; +	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 *)pdev->id_entry->driver_data;  	struct mc13xxx_leds *leds; -	int i, id, num_leds, ret = -ENODATA; -	u32 reg, init_led = 0; +	int i, id, ret = -ENODATA; +	u32 init_led = 0; -	if (!pdata) { -		dev_err(&pdev->dev, "Missing platform data\n"); -		return -ENODEV; -	} +	leds = devm_kzalloc(dev, sizeof(*leds), GFP_KERNEL); +	if (!leds) +		return -ENOMEM; + +	leds->devtype = devtype; +	leds->master = mcdev; +	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; -	num_leds = pdata->num_leds; +	leds->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); +	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 = devm_kzalloc(&pdev->dev, num_leds * sizeof(struct mc13xxx_led) + -			    sizeof(struct mc13xxx_leds), GFP_KERNEL); -	if (!leds) +	leds->led = devm_kzalloc(dev, leds->num_leds * sizeof(*leds->led), +				 GFP_KERNEL); +	if (!leds->led)  		return -ENOMEM; -	leds->devtype = devtype; -	leds->num_leds = num_leds; -	platform_set_drvdata(pdev, leds); - -	mc13xxx_lock(mcdev);  	for (i = 0; i < devtype->num_regs; i++) { -		reg = pdata->led_control[i]; -		WARN_ON(reg >= (1 << 24)); -		ret = mc13xxx_reg_write(mcdev, MC13XXX_REG_LED_CONTROL(i), reg); +		ret = mc13xxx_reg_write(mcdev, leds->devtype->ledctrl_base + i, +					pdata->led_control[i]);  		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 < leds->num_leds; i++) {  		const char *name, *trig; -		char max_current;  		ret = -EINVAL;  		id = pdata->led[i].id;  		name = pdata->led[i].name;  		trig = pdata->led[i].default_trigger; -		max_current = pdata->led[i].max_current;  		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;  		}  		if (init_led & (1 << id)) { -			dev_warn(&pdev->dev, -				 "LED %i already initialized\n", id); +			dev_warn(dev, "LED %i already initialized\n", id);  			break;  		}  		init_led |= 1 << 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.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 = LED_OFF; +		leds->led[i].cdev.max_brightness = mc13xxx_max_brightness(id);  		INIT_WORK(&leds->led[i].work, mc13xxx_led_work); -		ret = mc13xxx_led_setup(&leds->led[i], max_current); +		ret = led_classdev_register(dev->parent, &leds->led[i].cdev);  		if (ret) { -			dev_err(&pdev->dev, "Unable to setup LED %i\n", id); -			break; -		} -		ret = led_classdev_register(pdev->dev.parent, -					    &leds->led[i].cdev); -		if (ret) { -			dev_err(&pdev->dev, "Failed to register LED %i\n", id); +			dev_err(dev, "Failed to register LED %i\n", id);  			break;  		}  	} @@ -304,7 +282,6 @@ static int __init mc13xxx_led_probe(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);  	int i; @@ -313,11 +290,6 @@ static int mc13xxx_led_remove(struct platform_device *pdev)  		cancel_work_sync(&leds->led[i].work);  	} -	mc13xxx_lock(mcdev); -	for (i = 0; i < leds->devtype->num_regs; i++) -		mc13xxx_reg_write(mcdev, MC13XXX_REG_LED_CONTROL(i), 0); -	mc13xxx_unlock(mcdev); -  	return 0;  } @@ -325,17 +297,27 @@ static const struct mc13xxx_led_devtype mc13783_led_devtype = {  	.led_min	= MC13783_LED_MD,  	.led_max	= MC13783_LED_B3,  	.num_regs	= 6, +	.ledctrl_base	= 51,  };  static const struct mc13xxx_led_devtype mc13892_led_devtype = {  	.led_min	= MC13892_LED_MD,  	.led_max	= MC13892_LED_B,  	.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[] = {  	{ "mc13783-led", (kernel_ulong_t)&mc13783_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); diff --git a/drivers/leds/leds-netxbig.c b/drivers/leds/leds-netxbig.c index 2f9f141084b..e97f443a6e0 100644 --- a/drivers/leds/leds-netxbig.c +++ b/drivers/leds/leds-netxbig.c @@ -21,7 +21,6 @@   */  #include <linux/module.h> -#include <linux/init.h>  #include <linux/irq.h>  #include <linux/slab.h>  #include <linux/spinlock.h> diff --git a/drivers/leds/leds-ns2.c b/drivers/leds/leds-ns2.c index 141f13438e8..efa625883c8 100644 --- a/drivers/leds/leds-ns2.c +++ b/drivers/leds/leds-ns2.c @@ -23,13 +23,13 @@   */  #include <linux/kernel.h> -#include <linux/init.h>  #include <linux/platform_device.h>  #include <linux/slab.h>  #include <linux/gpio.h>  #include <linux/leds.h>  #include <linux/module.h>  #include <linux/platform_data/leds-kirkwood-ns2.h> +#include <linux/of.h>  #include <linux/of_gpio.h>  /* diff --git a/drivers/leds/leds-ot200.c b/drivers/leds/leds-ot200.c index 98cae529373..c9d90609846 100644 --- a/drivers/leds/leds-ot200.c +++ b/drivers/leds/leds-ot200.c @@ -8,7 +8,6 @@   */  #include <linux/kernel.h> -#include <linux/init.h>  #include <linux/platform_device.h>  #include <linux/slab.h>  #include <linux/leds.h> diff --git a/drivers/leds/leds-pwm.c b/drivers/leds/leds-pwm.c index bb6f9489854..d672bb4480f 100644 --- a/drivers/leds/leds-pwm.c +++ b/drivers/leds/leds-pwm.c @@ -14,7 +14,6 @@  #include <linux/module.h>  #include <linux/kernel.h> -#include <linux/init.h>  #include <linux/platform_device.h>  #include <linux/of_platform.h>  #include <linux/fb.h> @@ -66,9 +65,15 @@ static void led_pwm_set(struct led_classdev *led_cdev,  	struct led_pwm_data *led_dat =  		container_of(led_cdev, struct led_pwm_data, cdev);  	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); + +	if (led_dat->active_low) +		duty = led_dat->period - duty; + +	led_dat->duty = duty;  	if (led_dat->can_sleep)  		schedule_work(&led_dat->work); @@ -82,140 +87,136 @@ static inline size_t sizeof_pwm_leds_priv(int num_leds)  		      (sizeof(struct led_pwm_data) * num_leds);  } -static struct led_pwm_priv *led_pwm_create_of(struct platform_device *pdev) +static void led_pwm_cleanup(struct led_pwm_priv *priv)  { -	struct device_node *node = pdev->dev.of_node; -	struct device_node *child; -	struct led_pwm_priv *priv; -	int count, ret; +	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); +	} +} -	/* count LEDs in this device, so we know how much to allocate */ -	count = of_get_child_count(node); -	if (!count) -		return NULL; +static int led_pwm_add(struct device *dev, struct led_pwm_priv *priv, +		       struct led_pwm *led, struct device_node *child) +{ +	struct led_pwm_data *led_data = &priv->leds[priv->num_leds]; +	int ret; + +	led_data->active_low = led->active_low; +	led_data->cdev.name = led->name; +	led_data->cdev.default_trigger = led->default_trigger; +	led_data->cdev.brightness_set = led_pwm_set; +	led_data->cdev.brightness = LED_OFF; +	led_data->cdev.max_brightness = led->max_brightness; +	led_data->cdev.flags = LED_CORE_SUSPENDRESUME; + +	if (child) +		led_data->pwm = devm_of_pwm_get(dev, child, NULL); +	else +		led_data->pwm = devm_pwm_get(dev, led->name); +	if (IS_ERR(led_data->pwm)) { +		ret = PTR_ERR(led_data->pwm); +		dev_err(dev, "unable to request PWM for %s: %d\n", +			led->name, ret); +		return ret; +	} -	priv = devm_kzalloc(&pdev->dev, sizeof_pwm_leds_priv(count), -			    GFP_KERNEL); -	if (!priv) -		return NULL; +	if (child) +		led_data->period = pwm_get_period(led_data->pwm); -	for_each_child_of_node(node, child) { -		struct led_pwm_data *led_dat = &priv->leds[priv->num_leds]; +	led_data->can_sleep = pwm_can_sleep(led_data->pwm); +	if (led_data->can_sleep) +		INIT_WORK(&led_data->work, led_pwm_work); -		led_dat->cdev.name = of_get_property(child, "label", -						     NULL) ? : child->name; +	led_data->period = pwm_get_period(led_data->pwm); +	if (!led_data->period && (led->pwm_period_ns > 0)) +		led_data->period = led->pwm_period_ns; -		led_dat->pwm = devm_of_pwm_get(&pdev->dev, child, NULL); -		if (IS_ERR(led_dat->pwm)) { -			dev_err(&pdev->dev, "unable to request PWM for %s\n", -				led_dat->cdev.name); -			goto err; -		} -		/* Get the period from PWM core when n*/ -		led_dat->period = pwm_get_period(led_dat->pwm); +	ret = led_classdev_register(dev, &led_data->cdev); +	if (ret == 0) { +		priv->num_leds++; +	} else { +		dev_err(dev, "failed to register PWM led for %s: %d\n", +			led->name, ret); +	} -		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); +	return ret; +} + +static int led_pwm_create_of(struct device *dev, struct led_pwm_priv *priv) +{ +	struct device_node *child; +	struct led_pwm led; +	int ret = 0; + +	memset(&led, 0, sizeof(led)); -		led_dat->cdev.brightness_set = led_pwm_set; -		led_dat->cdev.brightness = LED_OFF; -		led_dat->cdev.flags |= LED_CORE_SUSPENDRESUME; +	for_each_child_of_node(dev->of_node, child) { +		led.name = of_get_property(child, "label", NULL) ? : +			   child->name; -		led_dat->can_sleep = pwm_can_sleep(led_dat->pwm); -		if (led_dat->can_sleep) -			INIT_WORK(&led_dat->work, led_pwm_work); +		led.default_trigger = of_get_property(child, +						"linux,default-trigger", NULL); +		led.active_low = of_property_read_bool(child, "active-low"); +		of_property_read_u32(child, "max-brightness", +				     &led.max_brightness); -		ret = led_classdev_register(&pdev->dev, &led_dat->cdev); -		if (ret < 0) { -			dev_err(&pdev->dev, "failed to register for %s\n", -				led_dat->cdev.name); +		ret = led_pwm_add(dev, priv, &led, child); +		if (ret) {  			of_node_put(child); -			goto err; +			break;  		} -		priv->num_leds++;  	} -	return priv; -err: -	while (priv->num_leds--) -		led_classdev_unregister(&priv->leds[priv->num_leds].cdev); - -	return NULL; +	return ret;  }  static int led_pwm_probe(struct platform_device *pdev)  {  	struct led_pwm_platform_data *pdata = dev_get_platdata(&pdev->dev);  	struct led_pwm_priv *priv; -	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; - -			led_dat->can_sleep = pwm_can_sleep(led_dat->pwm); -			if (led_dat->can_sleep) -				INIT_WORK(&led_dat->work, led_pwm_work); - -			ret = led_classdev_register(&pdev->dev, &led_dat->cdev); -			if (ret < 0) -				goto err; +	int count, i; +	int ret = 0; + +	if (pdata) +		count = pdata->num_leds; +	else +		count = of_get_child_count(pdev->dev.of_node); + +	if (!count) +		return -EINVAL; + +	priv = devm_kzalloc(&pdev->dev, sizeof_pwm_leds_priv(count), +			    GFP_KERNEL); +	if (!priv) +		return -ENOMEM; + +	if (pdata) { +		for (i = 0; i < count; i++) { +			ret = led_pwm_add(&pdev->dev, priv, &pdata->leds[i], +					  NULL); +			if (ret) +				break;  		} -		priv->num_leds = pdata->num_leds;  	} else { -		priv = led_pwm_create_of(pdev); -		if (!priv) -			return -ENODEV; +		ret = led_pwm_create_of(&pdev->dev, priv); +	} + +	if (ret) { +		led_pwm_cleanup(priv); +		return ret;  	}  	platform_set_drvdata(pdev, priv);  	return 0; - -err: -	while (i--) -		led_classdev_unregister(&priv->leds[i].cdev); - -	return ret;  }  static int led_pwm_remove(struct platform_device *pdev)  {  	struct led_pwm_priv *priv = platform_get_drvdata(pdev); -	int i; -	for (i = 0; i < priv->num_leds; i++) { -		led_classdev_unregister(&priv->leds[i].cdev); -		if (priv->leds[i].can_sleep) -			cancel_work_sync(&priv->leds[i].work); -	} +	led_pwm_cleanup(priv);  	return 0;  } @@ -232,7 +233,7 @@ static struct platform_driver led_pwm_driver = {  	.driver		= {  		.name	= "leds_pwm",  		.owner	= THIS_MODULE, -		.of_match_table = of_match_ptr(of_pwm_leds_match), +		.of_match_table = of_pwm_leds_match,  	},  }; diff --git a/drivers/leds/leds-s3c24xx.c b/drivers/leds/leds-s3c24xx.c index 76483fb5ee4..785eb53a87f 100644 --- a/drivers/leds/leds-s3c24xx.c +++ b/drivers/leds/leds-s3c24xx.c @@ -12,16 +12,15 @@  */  #include <linux/kernel.h> -#include <linux/init.h>  #include <linux/platform_device.h>  #include <linux/leds.h>  #include <linux/gpio.h>  #include <linux/slab.h>  #include <linux/module.h> +#include <linux/platform_data/leds-s3c24xx.h> -#include <mach/hardware.h>  #include <mach/regs-gpio.h> -#include <linux/platform_data/leds-s3c24xx.h> +#include <plat/gpio-cfg.h>  /* our context */ @@ -77,10 +76,8 @@ static int s3c24xx_led_probe(struct platform_device *dev)  	led = devm_kzalloc(&dev->dev, sizeof(struct s3c24xx_gpio_led),  			   GFP_KERNEL); -	if (led == NULL) { -		dev_err(&dev->dev, "No memory for device\n"); +	if (!led)  		return -ENOMEM; -	}  	platform_set_drvdata(dev, led); diff --git a/drivers/leds/leds-ss4200.c b/drivers/leds/leds-ss4200.c index 5b8f938a8d7..2eb3ef62962 100644 --- a/drivers/leds/leds-ss4200.c +++ b/drivers/leds/leds-ss4200.c @@ -63,7 +63,7 @@ MODULE_LICENSE("GPL");  /*   * 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_1) },  	{ 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;  } -static bool __initdata nodetect; +static bool nodetect;  module_param_named(nodetect, nodetect, bool, 0);  MODULE_PARM_DESC(nodetect, "Skip DMI-based hardware detection"); diff --git a/drivers/leds/leds-sunfire.c b/drivers/leds/leds-sunfire.c index 388632d23d4..0b8cc4a021a 100644 --- a/drivers/leds/leds-sunfire.c +++ b/drivers/leds/leds-sunfire.c @@ -135,10 +135,8 @@ static int sunfire_led_generic_probe(struct platform_device *pdev,  	}  	p = devm_kzalloc(&pdev->dev, sizeof(*p), GFP_KERNEL); -	if (!p) { -		dev_err(&pdev->dev, "Could not allocate struct sunfire_drvdata\n"); +	if (!p)  		return -ENOMEM; -	}  	for (i = 0; i < NUM_LEDS_PER_BOARD; i++) {  		struct led_classdev *lp = &p->leds[i].led_cdev; diff --git a/drivers/leds/leds-tca6507.c b/drivers/leds/leds-tca6507.c index 8cc304f3672..3d9e267a56c 100644 --- a/drivers/leds/leds-tca6507.c +++ b/drivers/leds/leds-tca6507.c @@ -4,77 +4,87 @@   * The TCA6507 is a programmable LED controller that can drive 7   * separate lines either by holding them low, or by pulsing them   * with modulated width. - * The modulation can be varied in a simple pattern to produce a blink or - * double-blink. + * The modulation can be varied in a simple pattern to produce a + * blink or double-blink.   * - * This driver can configure each line either as a 'GPIO' which is out-only - * (no pull-up) or as an LED with variable brightness and hardware-assisted - * blinking. + * This driver can configure each line either as a 'GPIO' which is + * out-only (pull-up resistor required) or as an LED with variable + * brightness and hardware-assisted blinking.   * - * Apart from OFF and ON there are three programmable brightness levels which - * can be programmed from 0 to 15 and indicate how many 500usec intervals in - * each 8msec that the led is 'on'.  The levels are named MASTER, BANK0 and - * BANK1. + * Apart from OFF and ON there are three programmable brightness + * levels which can be programmed from 0 to 15 and indicate how many + * 500usec intervals in each 8msec that the led is 'on'.  The levels + * are named MASTER, BANK0 and BANK1.   * - * There are two different blink rates that can be programmed, each with - * separate time for rise, on, fall, off and second-off.  Thus if 3 or more - * different non-trivial rates are required, software must be used for the extra - * rates. The two different blink rates must align with the two levels BANK0 and - * BANK1. - * This driver does not support double-blink so 'second-off' always matches - * 'off'. + * There are two different blink rates that can be programmed, each + * with separate time for rise, on, fall, off and second-off.  Thus if + * 3 or more different non-trivial rates are required, software must + * be used for the extra rates. The two different blink rates must + * align with the two levels BANK0 and BANK1.  This driver does not + * support double-blink so 'second-off' always matches 'off'.   * - * Only 16 different times can be programmed in a roughly logarithmic scale from - * 64ms to 16320ms.  To be precise the possible times are: + * Only 16 different times can be programmed in a roughly logarithmic + * scale from 64ms to 16320ms.  To be precise the possible times are:   *    0, 64, 128, 192, 256, 384, 512, 768,   *    1024, 1536, 2048, 3072, 4096, 5760, 8128, 16320   * - * Times that cannot be closely matched with these must be - * handled in software.  This driver allows 12.5% error in matching. + * Times that cannot be closely matched with these must be handled in + * software.  This driver allows 12.5% error in matching.   * - * This driver does not allow rise/fall rates to be set explicitly.  When trying - * to match a given 'on' or 'off' period, an appropriate pair of 'change' and - * 'hold' times are chosen to get a close match.  If the target delay is even, - * the 'change' number will be the 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 - * ranges: 56-72, 112-144, 168-216, 224-27504, 28560-36720. - * 26% of the achievable sums can be matched by multiple pairings. For example - * 1536 == 1536+0, 1024+512, or 768+768.  This driver will always choose the - * pairing with the least maximum - 768+768 in this case.  Other pairings are - * not available. + * This driver does not allow rise/fall rates to be set explicitly. + * When trying to match a given 'on' or 'off' period, an appropriate + * pair of 'change' and 'hold' times are chosen to get a close match. + * If the target delay is even, the 'change' number will be the + * 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 ranges: 56-72, 112-144, 168-216, 224-27504, + * 28560-36720. + * 26% of the achievable sums can be matched by multiple pairings. + * For example 1536 == 1536+0, 1024+512, or 768+768. + * 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 can be shared by multiple leds if they have the same level and - * either same blink rates, or some don't blink. - * When a led changes, it relinquishes access and tries again, 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. + * Access to the 3 levels and 2 blinks are on a first-come, + * first-served basis.  Access can be shared by multiple leds if they + * have the same level and either same blink rates, or some don't + * blink.  When a led changes, it relinquishes access and tries again, + * so it might lose access to hardware blink.   * - * Each bank (BANK0 and BANK1) has two usage counts - LEDs using the brightness - * and LEDs using the blink.  It can only be reprogrammed when the appropriate - * counter is zero.  The MASTER level has a single usage count. + * 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 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. + * Each bank (BANK0 and BANK1) has two usage counts - LEDs using the + * brightness and LEDs using the blink.  It can only be reprogrammed + * when the appropriate counter is zero.  The MASTER level has a + * 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 - * 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_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.   * + * An led-tca6507 device must be provided with platform data or + * configured via devicetree. + * + * 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> @@ -192,17 +202,18 @@ MODULE_DEVICE_TABLE(i2c, tca6507_id);  static int choose_times(int msec, int *c1p, int *c2p)  {  	/* -	 * Choose two timecodes which add to 'msec' as near as possible. -	 * The first returned is the 'on' or 'off' time.  The second is to be -	 * used as a 'fade-on' or 'fade-off' time.  If 'msec' is even, -	 * the first will not be smaller than the second.  If 'msec' is odd, -	 * the first will not be larger than the second. -	 * If we cannot get a sum within 1/8 of 'msec' fail with -EINVAL, -	 * otherwise return the sum that was achieved, plus 1 if the first is -	 * smaller. -	 * If two possibilities are equally good (e.g. 512+0, 256+256), choose -	 * the first pair so there is more change-time visible (i.e. it is -	 * softer). +	 * Choose two timecodes which add to 'msec' as near as +	 * possible.  The first returned is the 'on' or 'off' time. +	 * The second is to be used as a 'fade-on' or 'fade-off' time. +	 * If 'msec' is even, the first will not be smaller than the +	 * second.  If 'msec' is odd, the first will not be larger +	 * than the second. +	 * If we cannot get a sum within 1/8 of 'msec' fail with +	 * -EINVAL, otherwise return the sum that was achieved, plus 1 +	 * if the first is smaller. +	 * If two possibilities are equally good (e.g. 512+0, +	 * 256+256), choose the first pair so there is more +	 * change-time visible (i.e. it is softer).  	 */  	int c1, c2;  	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 - * the given led. + * Update the register file with the appropriate 3-bit state for the + * given led.   */  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 - * one bank or other.  This can be used for timers, for levels, or - * for initialisation. +/* Update the register file with the appropriate 4-bit code for one + * bank or other.  This can be used for timers, for levels, or for + * initialization.   */  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;  } -/* 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)  {  	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);  	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);  	set_code(tca, TCA6507_FADE_ON, bank, c2);  	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);  	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);  	set_code(tca, TCA6507_FADE_OFF, bank, c2);  	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)  { -	/* 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);  	struct tca6507_chip *tca = led->chip;  	int c1, c2; @@ -389,10 +403,10 @@ static int led_prepare(struct tca6507_led *led)  	if (led->ontime == 0 || led->offtime == 0) {  		/* -		 * Just set the brightness, choosing first usable bank. -		 * If none perfect, choose best. -		 * Count backwards so we check MASTER bank first -		 * to avoid wasting a timer. +		 * Just set the brightness, choosing first usable +		 * bank.  If none perfect, choose best.  Count +		 * backwards so we check MASTER bank first to avoid +		 * wasting a timer.  		 */  		int best = -1;/* full-on */  		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. -	 * First check if times are compatible with hardware and give up if -	 * not. +	 * We have on/off time so we need to try to allocate a timing +	 * bank.  First check if times are compatible with hardware +	 * and give up if not.  	 */  	if (choose_times(led->ontime, &c1, &c2) < 0)  		return -EINVAL; @@ -523,8 +537,8 @@ static int led_assign(struct tca6507_led *led)  	err = led_prepare(led);  	if (err) {  		/* -		 * Can only fail on timer setup.  In that case we need to -		 * re-establish as steady level. +		 * Can only fail on timer setup.  In that case we need +		 * to re-establish as steady level.  		 */  		led->ontime = 0;  		led->offtime = 0; @@ -594,8 +608,8 @@ static void tca6507_gpio_set_value(struct gpio_chip *gc,  	spin_lock_irqsave(&tca->lock, flags);  	/* -	 * 'OFF' is floating high, and 'ON' is pulled down, so it has the -	 * inverse sense of 'val'. +	 * 'OFF' is floating high, and 'ON' is pulled down, so it has +	 * the inverse sense of 'val'.  	 */  	set_select(tca, tca->gpio_map[offset],  		   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.set = tca6507_gpio_set_value;  	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);  	if (err) {  		tca->gpio.ngpio = 0; @@ -682,7 +699,7 @@ tca6507_led_dt_init(struct i2c_client *client)  		return ERR_PTR(-ENODEV);  	tca_leds = devm_kzalloc(&client->dev, -			sizeof(struct led_info) * count, GFP_KERNEL); +			sizeof(struct led_info) * NUM_LEDS, GFP_KERNEL);  	if (!tca_leds)  		return ERR_PTR(-ENOMEM); @@ -695,9 +712,11 @@ tca6507_led_dt_init(struct i2c_client *client)  			of_get_property(child, "label", NULL) ? : child->name;  		led.default_trigger =  			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", ®); -		if (ret != 0) +		if (ret != 0 || reg < 0 || reg >= NUM_LEDS)  			continue;  		tca_leds[reg] = led; @@ -708,8 +727,10 @@ tca6507_led_dt_init(struct i2c_client *client)  		return ERR_PTR(-ENOMEM);  	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;  } diff --git a/drivers/leds/leds-versatile.c b/drivers/leds/leds-versatile.c new file mode 100644 index 00000000000..80553022d66 --- /dev/null +++ b/drivers/leds/leds-versatile.c @@ -0,0 +1,110 @@ +/* + * Driver for the 8 user LEDs found on the RealViews and Versatiles + * Based on DaVinci's DM365 board code + * + * License terms: GNU General Public License (GPL) version 2 + * Author: Linus Walleij <triad@df.lth.se> + */ +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/module.h> +#include <linux/io.h> +#include <linux/slab.h> +#include <linux/leds.h> +#include <linux/platform_device.h> + +struct versatile_led { +	void __iomem		*base; +	struct led_classdev	cdev; +	u8			mask; +}; + +/* + * The triggers lines up below will only be used if the + * LED triggers are compiled in. + */ +static const struct { +	const char *name; +	const char *trigger; +} versatile_leds[] = { +	{ "versatile:0", "heartbeat", }, +	{ "versatile:1", "mmc0", }, +	{ "versatile:2", "cpu0" }, +	{ "versatile:3", "cpu1" }, +	{ "versatile:4", "cpu2" }, +	{ "versatile:5", "cpu3" }, +	{ "versatile:6", }, +	{ "versatile:7", }, +}; + +static void versatile_led_set(struct led_classdev *cdev, +			      enum led_brightness b) +{ +	struct versatile_led *led = container_of(cdev, +						 struct versatile_led, cdev); +	u32 reg = readl(led->base); + +	if (b != LED_OFF) +		reg |= led->mask; +	else +		reg &= ~led->mask; +	writel(reg, led->base); +} + +static enum led_brightness versatile_led_get(struct led_classdev *cdev) +{ +	struct versatile_led *led = container_of(cdev, +						 struct versatile_led, cdev); +	u32 reg = readl(led->base); + +	return (reg & led->mask) ? LED_FULL : LED_OFF; +} + +static int versatile_leds_probe(struct platform_device *dev) +{ +	int i; +	struct resource *res; +	void __iomem *base; + +	res = platform_get_resource(dev, IORESOURCE_MEM, 0); +	base = devm_ioremap_resource(&dev->dev, res); +	if (IS_ERR(base)) +		return PTR_ERR(base); + +	/* All off */ +	writel(0, base); +	for (i = 0; i < ARRAY_SIZE(versatile_leds); i++) { +		struct versatile_led *led; + +		led = kzalloc(sizeof(*led), GFP_KERNEL); +		if (!led) +			break; + +		led->base = base; +		led->cdev.name = versatile_leds[i].name; +		led->cdev.brightness_set = versatile_led_set; +		led->cdev.brightness_get = versatile_led_get; +		led->cdev.default_trigger = versatile_leds[i].trigger; +		led->mask = BIT(i); + +		if (led_classdev_register(NULL, &led->cdev) < 0) { +			kfree(led); +			break; +		} +	} + +	return 0; +} + +static struct platform_driver versatile_leds_driver = { +	.driver = { +		.name   = "versatile-leds", +	}, +	.probe = versatile_leds_probe, +}; + +module_platform_driver(versatile_leds_driver); + +MODULE_AUTHOR("Linus Walleij <linus.walleij@linaro.org>"); +MODULE_DESCRIPTION("ARM Versatile LED driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/leds/leds-wm831x-status.c b/drivers/leds/leds-wm831x-status.c index 0a1a13f3a6a..e72c974142d 100644 --- a/drivers/leds/leds-wm831x-status.c +++ b/drivers/leds/leds-wm831x-status.c @@ -10,7 +10,6 @@   */  #include <linux/kernel.h> -#include <linux/init.h>  #include <linux/platform_device.h>  #include <linux/slab.h>  #include <linux/leds.h> diff --git a/drivers/leds/leds-wm8350.c b/drivers/leds/leds-wm8350.c index 3f75fd22fd4..4133ffe2901 100644 --- a/drivers/leds/leds-wm8350.c +++ b/drivers/leds/leds-wm8350.c @@ -10,7 +10,6 @@   */  #include <linux/kernel.h> -#include <linux/init.h>  #include <linux/platform_device.h>  #include <linux/leds.h>  #include <linux/err.h> diff --git a/drivers/leds/trigger/ledtrig-cpu.c b/drivers/leds/trigger/ledtrig-cpu.c index 118335eccc5..aec0f02b6b3 100644 --- a/drivers/leds/trigger/ledtrig-cpu.c +++ b/drivers/leds/trigger/ledtrig-cpu.c @@ -26,6 +26,7 @@  #include <linux/percpu.h>  #include <linux/syscore_ops.h>  #include <linux/rwsem.h> +#include <linux/cpu.h>  #include "../leds.h"  #define MAX_NAME_LEN	8 @@ -46,7 +47,7 @@ static DEFINE_PER_CPU(struct led_trigger_cpu, cpu_trig);   */  void ledtrig_cpu(enum cpu_led_event ledevt)  { -	struct led_trigger_cpu *trig = &__get_cpu_var(cpu_trig); +	struct led_trigger_cpu *trig = this_cpu_ptr(&cpu_trig);  	/* Locate the correct CPU LED */  	switch (ledevt) { @@ -92,6 +93,26 @@ static struct syscore_ops ledtrig_cpu_syscore_ops = {  	.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)  {  	int cpu; @@ -113,6 +134,7 @@ static int __init ledtrig_cpu_init(void)  	}  	register_syscore_ops(&ledtrig_cpu_syscore_ops); +	register_cpu_notifier(&ledtrig_cpu_nb);  	pr_info("ledtrig-cpu: registered to indicate activity on CPUs\n"); @@ -124,6 +146,8 @@ static void __exit ledtrig_cpu_exit(void)  {  	int cpu; +	unregister_cpu_notifier(&ledtrig_cpu_nb); +  	for_each_possible_cpu(cpu) {  		struct led_trigger_cpu *trig = &per_cpu(cpu_trig, cpu);  | 
