瀏覽代碼

Merge branch 'for-linus' of git://git.o-hand.com/linux-rpurdie-leds

* 'for-linus' of git://git.o-hand.com/linux-rpurdie-leds:
  leds: Add HP Jornada 6xx driver
  leds: Remove the now uneeded ixp4xx driver
  leds: Add power LED to the wrap driver
  leds: Fix led-gpio active_low default brightness
  leds: hw acceleration for Clevo mail LED driver
  leds: Add support for hardware accelerated LED flashing
  leds: Standardise LED naming scheme
  leds: Add clevo notebook LED driver
Linus Torvalds 17 年之前
父節點
當前提交
3d50337f62

+ 23 - 6
Documentation/leds-class.txt

@@ -39,12 +39,33 @@ LED Device Naming
 
 Is currently of the form:
 
-"devicename:colour"
+"devicename:colour:function"
 
 There have been calls for LED properties such as colour to be exported as
 individual led class attributes. As a solution which doesn't incur as much
 overhead, I suggest these become part of the device name. The naming scheme
-above leaves scope for further attributes should they be needed.
+above leaves scope for further attributes should they be needed. If sections
+of the name don't apply, just leave that section blank.
+
+
+Hardware accelerated blink of LEDs
+==================================
+
+Some LEDs can be programmed to blink without any CPU interaction. To
+support this feature, a LED driver can optionally implement the
+blink_set() function (see <linux/leds.h>). If implemeted, triggers can
+attempt to use it before falling back to software timers. The blink_set()
+function should return 0 if the blink setting is supported, or -EINVAL
+otherwise, which means that LED blinking will be handled by software.
+
+The blink_set() function should choose a user friendly blinking
+value if it is called with *delay_on==0 && *delay_off==0 parameters. In
+this case the driver should give back the chosen value through delay_on
+and delay_off parameters to the leds subsystem.
+
+Any call to the brightness_set() callback function should cancel the
+previously programmed hardware blinking function so setting the brightness
+to 0 can also cancel the blinking of the LED.
 
 
 Known Issues
@@ -55,10 +76,6 @@ would cause nightmare dependency issues. I see this as a minor issue
 compared to the benefits the simple trigger functionality brings. The
 rest of the LED subsystem can be modular.
 
-Some leds can be programmed to flash in hardware. As this isn't a generic
-LED device property, this should be exported as a device specific sysfs
-attribute rather than part of the class if this functionality is required.
-
 
 Future Development
 ==================

+ 2 - 2
arch/arm/mach-ixp4xx/dsmg600-setup.c

@@ -71,11 +71,11 @@ static struct i2c_board_info __initdata dsmg600_i2c_board_info [] = {
 
 static struct gpio_led dsmg600_led_pins[] = {
 	{
-		.name		= "power",
+		.name		= "dsmg600:green:power",
 		.gpio		= DSMG600_LED_PWR_GPIO,
 	},
 	{
-		.name		= "wlan",
+		.name		= "dsmg600:green:wlan",
 		.gpio		= DSMG600_LED_WLAN_GPIO,
 		.active_low	= true,
 	},

+ 3 - 3
arch/arm/mach-ixp4xx/nas100d-setup.c

@@ -60,17 +60,17 @@ static struct i2c_board_info __initdata nas100d_i2c_board_info [] = {
 
 static struct gpio_led nas100d_led_pins[] = {
 	{
-		.name		= "wlan",   /* green led */
+		.name		= "nas100d:green:wlan",
 		.gpio		= NAS100D_LED_WLAN_GPIO,
 		.active_low	= true,
 	},
 	{
-		.name		= "power",  /* blue power led (off=flashing) */
+		.name		= "nas100d:blue:power",  /* (off=flashing) */
 		.gpio		= NAS100D_LED_PWR_GPIO,
 		.active_low	= true,
 	},
 	{
-		.name		= "disk",   /* yellow led */
+		.name		= "nas100d:yellow:disk",
 		.gpio		= NAS100D_LED_DISK_GPIO,
 		.active_low	= true,
 	},

+ 4 - 4
arch/arm/mach-ixp4xx/nslu2-setup.c

@@ -63,20 +63,20 @@ static struct i2c_board_info __initdata nslu2_i2c_board_info [] = {
 
 static struct gpio_led nslu2_led_pins[] = {
 	{
-		.name		= "ready",  /* green led */
+		.name		= "nslu2:green:ready",
 		.gpio		= NSLU2_LED_GRN_GPIO,
 	},
 	{
-		.name		= "status", /* red led */
+		.name		= "nslu2:red:status",
 		.gpio		= NSLU2_LED_RED_GPIO,
 	},
 	{
-		.name		= "disk-1",
+		.name		= "nslu2:green:disk-1",
 		.gpio		= NSLU2_LED_DISK1_GPIO,
 		.active_low	= true,
 	},
 	{
-		.name		= "disk-2",
+		.name		= "nslu2:green:disk-2",
 		.gpio		= NSLU2_LED_DISK2_GPIO,
 		.active_low	= true,
 	},

+ 1 - 1
drivers/hwmon/applesmc.c

@@ -905,7 +905,7 @@ static ssize_t applesmc_key_at_index_store(struct device *dev,
 }
 
 static struct led_classdev applesmc_backlight = {
-	.name			= "smc:kbd_backlight",
+	.name			= "smc::kbd_backlight",
 	.default_trigger	= "nand-disk",
 	.brightness_set		= applesmc_brightness_set,
 };

+ 2 - 2
drivers/input/misc/wistron_btns.c

@@ -998,12 +998,12 @@ static void wistron_wifi_led_set(struct led_classdev *led_cdev,
 }
 
 static struct led_classdev wistron_mail_led = {
-	.name			= "mail:green",
+	.name			= "wistron:green:mail",
 	.brightness_set		= wistron_mail_led_set,
 };
 
 static struct led_classdev wistron_wifi_led = {
-	.name			= "wifi:red",
+	.name			= "wistron:red:wifi",
 	.brightness_set		= wistron_wifi_led_set,
 };
 

+ 38 - 10
drivers/leds/Kconfig

@@ -39,15 +39,6 @@ config LEDS_SPITZ
 	  This option enables support for the LEDs on Sharp Zaurus
 	  SL-Cxx00 series (C1000, C3000, C3100).
 
-config LEDS_IXP4XX
-	tristate "LED Support for GPIO connected LEDs on IXP4XX processors"
-	depends on LEDS_CLASS && ARCH_IXP4XX
-	help
-	  This option enables support for the LEDs connected to GPIO
-	  outputs of the Intel IXP4XX processors.  To be useful the
-	  particular board must have LEDs and they must be connected
-	  to the GPIO lines.  If unsure, say Y.
-
 config LEDS_TOSA
 	tristate "LED Support for the Sharp SL-6000 series"
 	depends on LEDS_CLASS && PXA_SHARPSL
@@ -100,6 +91,13 @@ config LEDS_COBALT_RAQ
 	help
 	  This option enables support for the Cobalt Raq series LEDs.
 
+config LEDS_HP6XX
+	tristate "LED Support for the HP Jornada 6xx"
+	depends on LEDS_CLASS && SH_HP6XX
+	help
+	  This option enables led support for the handheld
+	  HP Jornada 620/660/680/690.
+
 config LEDS_GPIO
 	tristate "LED Support for GPIO connected LEDs"
 	depends on LEDS_CLASS && GENERIC_GPIO
@@ -114,6 +112,32 @@ config LEDS_CM_X270
 	help
 	  This option enables support for the CM-X270 LEDs.
 
+config LEDS_CLEVO_MAIL
+	tristate "Mail LED on Clevo notebook (EXPERIMENTAL)"
+	depends on LEDS_CLASS && X86 && SERIO_I8042 && DMI && EXPERIMENTAL
+	help
+	  This driver makes the mail LED accessible from userspace
+	  programs through the leds subsystem. This LED have three
+	  known mode: off, blink at 0.5Hz and blink at 1Hz.
+
+	  The driver supports two kinds of interface: using ledtrig-timer
+	  or through /sys/class/leds/clevo::mail/brightness. As this LED
+	  cannot change it's brightness it blinks instead. The brightness
+	  value 0 means off, 1..127 means blink at 0.5Hz and 128..255 means
+	  blink at 1Hz.
+
+	  This module can drive the mail LED for the following notebooks:
+
+	  	Clevo D410J
+	  	Clevo D410V
+	  	Clevo D400V/D470V (not tested, but might work)
+	  	Clevo M540N
+	  	Clevo M5x0N (not tested, but might work)
+	  	Positivo Mobile (Clevo M5x0V)
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called leds-clevo-mail.
+
 comment "LED Triggers"
 
 config LEDS_TRIGGERS
@@ -128,7 +152,11 @@ config LEDS_TRIGGER_TIMER
 	depends on LEDS_TRIGGERS
 	help
 	  This allows LEDs to be controlled by a programmable timer
-	  via sysfs. If unsure, say Y.
+	  via sysfs. Some LED hardware can be programmed to start
+	  blinking the LED without any further software interaction.
+	  For more details read Documentation/leds-class.txt.
+
+	  If unsure, say Y.
 
 config LEDS_TRIGGER_IDE_DISK
 	bool "LED IDE Disk Trigger"

+ 2 - 1
drivers/leds/Makefile

@@ -8,7 +8,6 @@ obj-$(CONFIG_LEDS_TRIGGERS)		+= led-triggers.o
 obj-$(CONFIG_LEDS_CORGI)		+= leds-corgi.o
 obj-$(CONFIG_LEDS_LOCOMO)		+= leds-locomo.o
 obj-$(CONFIG_LEDS_SPITZ)		+= leds-spitz.o
-obj-$(CONFIG_LEDS_IXP4XX)		+= leds-ixp4xx-gpio.o
 obj-$(CONFIG_LEDS_TOSA)			+= leds-tosa.o
 obj-$(CONFIG_LEDS_S3C24XX)		+= leds-s3c24xx.o
 obj-$(CONFIG_LEDS_AMS_DELTA)		+= leds-ams-delta.o
@@ -19,6 +18,8 @@ obj-$(CONFIG_LEDS_COBALT_QUBE)		+= leds-cobalt-qube.o
 obj-$(CONFIG_LEDS_COBALT_RAQ)		+= leds-cobalt-raq.o
 obj-$(CONFIG_LEDS_GPIO)			+= leds-gpio.o
 obj-$(CONFIG_LEDS_CM_X270)              += leds-cm-x270.o
+obj-$(CONFIG_LEDS_CLEVO_MAIL)		+= leds-clevo-mail.o
+obj-$(CONFIG_LEDS_HP6XX)		+= leds-hp6xx.o
 
 # LED Triggers
 obj-$(CONFIG_LEDS_TRIGGER_TIMER)	+= ledtrig-timer.o

+ 6 - 6
drivers/leds/leds-ams-delta.c

@@ -37,42 +37,42 @@ static void ams_delta_led_set(struct led_classdev *led_cdev,
 static struct ams_delta_led ams_delta_leds[] = {
 	{
 		.cdev		= {
-			.name		= "ams-delta:camera",
+			.name		= "ams-delta::camera",
 			.brightness_set = ams_delta_led_set,
 		},
 		.bitmask	= AMS_DELTA_LATCH1_LED_CAMERA,
 	},
 	{
 		.cdev		= {
-			.name		= "ams-delta:advert",
+			.name		= "ams-delta::advert",
 			.brightness_set = ams_delta_led_set,
 		},
 		.bitmask	= AMS_DELTA_LATCH1_LED_ADVERT,
 	},
 	{
 		.cdev		= {
-			.name		= "ams-delta:email",
+			.name		= "ams-delta::email",
 			.brightness_set = ams_delta_led_set,
 		},
 		.bitmask	= AMS_DELTA_LATCH1_LED_EMAIL,
 	},
 	{
 		.cdev		= {
-			.name		= "ams-delta:handsfree",
+			.name		= "ams-delta::handsfree",
 			.brightness_set = ams_delta_led_set,
 		},
 		.bitmask	= AMS_DELTA_LATCH1_LED_HANDSFREE,
 	},
 	{
 		.cdev		= {
-			.name		= "ams-delta:voicemail",
+			.name		= "ams-delta::voicemail",
 			.brightness_set = ams_delta_led_set,
 		},
 		.bitmask	= AMS_DELTA_LATCH1_LED_VOICEMAIL,
 	},
 	{
 		.cdev		= {
-			.name		= "ams-delta:voice",
+			.name		= "ams-delta::voice",
 			.brightness_set = ams_delta_led_set,
 		},
 		.bitmask	= AMS_DELTA_LATCH1_LED_VOICE,

+ 219 - 0
drivers/leds/leds-clevo-mail.c

@@ -0,0 +1,219 @@
+
+#include <linux/module.h>
+
+#include <linux/platform_device.h>
+#include <linux/err.h>
+#include <linux/leds.h>
+
+#include <linux/io.h>
+#include <linux/dmi.h>
+
+#include <linux/i8042.h>
+
+#define CLEVO_MAIL_LED_OFF		0x0084
+#define CLEVO_MAIL_LED_BLINK_1HZ	0x008A
+#define CLEVO_MAIL_LED_BLINK_0_5HZ	0x0083
+
+MODULE_AUTHOR("Márton Németh <nm127@freemail.hu>");
+MODULE_DESCRIPTION("Clevo mail LED driver");
+MODULE_LICENSE("GPL");
+
+static unsigned int __initdata nodetect;
+module_param_named(nodetect, nodetect, bool, 0);
+MODULE_PARM_DESC(nodetect, "Skip DMI hardware detection");
+
+static struct platform_device *pdev;
+
+static int __init clevo_mail_led_dmi_callback(const struct dmi_system_id *id)
+{
+	printk(KERN_INFO KBUILD_MODNAME ": '%s' found\n", id->ident);
+	return 1;
+}
+
+/*
+ * struct mail_led_whitelist - List of known good models
+ *
+ * Contains the known good models this driver is compatible with.
+ * When adding a new model try to be as strict as possible. This
+ * makes it possible to keep the false positives (the model is
+ * detected as working, but in reality it is not) as low as
+ * possible.
+ */
+static struct dmi_system_id __initdata mail_led_whitelist[] = {
+	{
+		.callback = clevo_mail_led_dmi_callback,
+		.ident = "Clevo D410J",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "VIA"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "K8N800"),
+			DMI_MATCH(DMI_PRODUCT_VERSION, "VT8204B")
+		}
+	},
+	{
+		.callback = clevo_mail_led_dmi_callback,
+		.ident = "Clevo M5x0N",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "CLEVO Co."),
+			DMI_MATCH(DMI_PRODUCT_NAME, "M5x0N")
+		}
+	},
+	{
+		.callback = clevo_mail_led_dmi_callback,
+		.ident = "Positivo Mobile",
+		.matches = {
+			DMI_MATCH(DMI_BOARD_VENDOR, "CLEVO Co. "),
+			DMI_MATCH(DMI_BOARD_NAME, "M5X0V "),
+			DMI_MATCH(DMI_PRODUCT_NAME, "Positivo Mobile"),
+			DMI_MATCH(DMI_PRODUCT_VERSION, "VT6198")
+		}
+	},
+	{
+		.callback = clevo_mail_led_dmi_callback,
+		.ident = "Clevo D410V",
+		.matches = {
+			DMI_MATCH(DMI_BOARD_VENDOR, "Clevo, Co."),
+			DMI_MATCH(DMI_BOARD_NAME, "D400V/D470V"),
+			DMI_MATCH(DMI_BOARD_VERSION, "SS78B"),
+			DMI_MATCH(DMI_PRODUCT_VERSION, "Rev. A1")
+		}
+	},
+	{ }
+};
+
+static void clevo_mail_led_set(struct led_classdev *led_cdev,
+				enum led_brightness value)
+{
+	if (value == LED_OFF)
+		i8042_command(NULL, CLEVO_MAIL_LED_OFF);
+	else if (value <= LED_HALF)
+		i8042_command(NULL, CLEVO_MAIL_LED_BLINK_0_5HZ);
+	else
+		i8042_command(NULL, CLEVO_MAIL_LED_BLINK_1HZ);
+
+}
+
+static int clevo_mail_led_blink(struct led_classdev *led_cdev,
+				unsigned long* delay_on,
+				unsigned long* delay_off)
+{
+	int status = -EINVAL;
+
+	if (*delay_on == 0 /* ms */ && *delay_off == 0 /* ms */) {
+		/* Special case: the leds subsystem requested us to
+		 * chose one user friendly blinking of the LED, and
+		 * start it. Let's blink the led slowly (0.5Hz).
+		 */
+		*delay_on = 1000; /* ms */
+		*delay_off = 1000; /* ms */
+		i8042_command(NULL, CLEVO_MAIL_LED_BLINK_0_5HZ);
+		status = 0;
+
+	} else if (*delay_on == 500 /* ms */ && *delay_off == 500 /* ms */) {
+		/* blink the led with 1Hz */
+		i8042_command(NULL, CLEVO_MAIL_LED_BLINK_1HZ);
+		status = 0;
+
+	} else if (*delay_on == 1000 /* ms */ && *delay_off == 1000 /* ms */) {
+		/* blink the led with 0.5Hz */
+		i8042_command(NULL, CLEVO_MAIL_LED_BLINK_0_5HZ);
+		status = 0;
+
+	} else {
+		printk(KERN_DEBUG KBUILD_MODNAME
+		       ": clevo_mail_led_blink(..., %lu, %lu),"
+		       " returning -EINVAL (unsupported)\n",
+		       *delay_on, *delay_off);
+	}
+
+	return status;
+}
+
+static struct led_classdev clevo_mail_led = {
+	.name			= "clevo::mail",
+	.brightness_set		= clevo_mail_led_set,
+	.blink_set		= clevo_mail_led_blink,
+};
+
+static int __init clevo_mail_led_probe(struct platform_device *pdev)
+{
+	return led_classdev_register(&pdev->dev, &clevo_mail_led);
+}
+
+static int clevo_mail_led_remove(struct platform_device *pdev)
+{
+	led_classdev_unregister(&clevo_mail_led);
+	return 0;
+}
+
+#ifdef CONFIG_PM
+static int clevo_mail_led_suspend(struct platform_device *dev,
+				  pm_message_t state)
+{
+	led_classdev_suspend(&clevo_mail_led);
+	return 0;
+}
+
+static int clevo_mail_led_resume(struct platform_device *dev)
+{
+	led_classdev_resume(&clevo_mail_led);
+	return 0;
+}
+#else
+#define clevo_mail_led_suspend    NULL
+#define clevo_mail_led_resume     NULL
+#endif
+
+static struct platform_driver clevo_mail_led_driver = {
+	.probe		= clevo_mail_led_probe,
+	.remove		= clevo_mail_led_remove,
+	.suspend	= clevo_mail_led_suspend,
+	.resume		= clevo_mail_led_resume,
+	.driver		= {
+		.name		= KBUILD_MODNAME,
+	},
+};
+
+static int __init clevo_mail_led_init(void)
+{
+	int error = 0;
+	int count = 0;
+
+	/* Check with the help of DMI if we are running on supported hardware */
+	if (!nodetect) {
+		count = dmi_check_system(mail_led_whitelist);
+	} else {
+		count = 1;
+		printk(KERN_ERR KBUILD_MODNAME ": Skipping DMI detection. "
+		       "If the driver works on your hardware please "
+		       "report model and the output of dmidecode in tracker "
+		       "at http://sourceforge.net/projects/clevo-mailled/\n");
+	}
+
+	if (!count)
+		return -ENODEV;
+
+	pdev = platform_device_register_simple(KBUILD_MODNAME, -1, NULL, 0);
+	if (!IS_ERR(pdev)) {
+		error = platform_driver_probe(&clevo_mail_led_driver,
+					      clevo_mail_led_probe);
+		if (error) {
+			printk(KERN_ERR KBUILD_MODNAME
+			       ": Can't probe platform driver\n");
+			platform_device_unregister(pdev);
+		}
+	} else
+		error = PTR_ERR(pdev);
+
+	return error;
+}
+
+static void __exit clevo_mail_led_exit(void)
+{
+	platform_device_unregister(pdev);
+	platform_driver_unregister(&clevo_mail_led_driver);
+
+	clevo_mail_led_set(NULL, LED_OFF);
+}
+
+module_init(clevo_mail_led_init);
+module_exit(clevo_mail_led_exit);

+ 2 - 2
drivers/leds/leds-corgi.c

@@ -38,13 +38,13 @@ static void corgiled_green_set(struct led_classdev *led_cdev, enum led_brightnes
 }
 
 static struct led_classdev corgi_amber_led = {
-	.name			= "corgi:amber",
+	.name			= "corgi:amber:charge",
 	.default_trigger	= "sharpsl-charge",
 	.brightness_set		= corgiled_amber_set,
 };
 
 static struct led_classdev corgi_green_led = {
-	.name			= "corgi:green",
+	.name			= "corgi:green:mail",
 	.default_trigger	= "nand-disk",
 	.brightness_set		= corgiled_green_set,
 };

+ 1 - 1
drivers/leds/leds-gpio.c

@@ -85,7 +85,7 @@ static int gpio_led_probe(struct platform_device *pdev)
 		led_dat->can_sleep = gpio_cansleep(cur_led->gpio);
 		led_dat->active_low = cur_led->active_low;
 		led_dat->cdev.brightness_set = gpio_led_set;
-		led_dat->cdev.brightness = cur_led->active_low ? LED_FULL : LED_OFF;
+		led_dat->cdev.brightness = LED_OFF;
 
 		ret = gpio_request(led_dat->gpio, led_dat->cdev.name);
 		if (ret < 0)

+ 120 - 0
drivers/leds/leds-hp6xx.c

@@ -0,0 +1,120 @@
+/*
+ * LED Triggers Core
+ * For the HP Jornada 620/660/680/690 handhelds
+ *
+ * Copyright 2008 Kristoffer Ericson <kristoffer.ericson@gmail.com>
+ *     this driver is based on leds-spitz.c by Richard Purdie.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/leds.h>
+#include <asm/hd64461.h>
+#include <asm/hp6xx.h>
+
+static void hp6xxled_green_set(struct led_classdev *led_cdev, enum led_brightness value)
+{
+	u8 v8;
+
+	v8 = inb(PKDR);
+	if (value)
+		outb(v8 & (~PKDR_LED_GREEN), PKDR);
+	else
+		outb(v8 | PKDR_LED_GREEN, PKDR);
+}
+
+static void hp6xxled_red_set(struct led_classdev *led_cdev, enum led_brightness value)
+{
+	u16 v16;
+
+	v16 = inw(HD64461_GPBDR);
+	if (value)
+		outw(v16 & (~HD64461_GPBDR_LED_RED), HD64461_GPBDR);
+	else
+		outw(v16 | HD64461_GPBDR_LED_RED, HD64461_GPBDR);
+}
+
+static struct led_classdev hp6xx_red_led = {
+	.name			= "hp6xx:red",
+	.default_trigger	= "hp6xx-charge",
+	.brightness_set		= hp6xxled_red_set,
+};
+
+static struct led_classdev hp6xx_green_led = {
+	.name			= "hp6xx:green",
+	.default_trigger	= "ide-disk",
+	.brightness_set		= hp6xxled_green_set,
+};
+
+#ifdef CONFIG_PM
+static int hp6xxled_suspend(struct platform_device *dev, pm_message_t state)
+{
+	led_classdev_suspend(&hp6xx_red_led);
+	led_classdev_suspend(&hp6xx_green_led);
+	return 0;
+}
+
+static int hp6xxled_resume(struct platform_device *dev)
+{
+	led_classdev_resume(&hp6xx_red_led);
+	led_classdev_resume(&hp6xx_green_led);
+	return 0;
+}
+#endif
+
+static int hp6xxled_probe(struct platform_device *pdev)
+{
+	int ret;
+
+	ret = led_classdev_register(&pdev->dev, &hp6xx_red_led);
+	if (ret < 0)
+		return ret;
+
+	ret = led_classdev_register(&pdev->dev, &hp6xx_green_led);
+	if (ret < 0)
+		led_classdev_unregister(&hp6xx_red_led);
+
+	return ret;
+}
+
+static int hp6xxled_remove(struct platform_device *pdev)
+{
+	led_classdev_unregister(&hp6xx_red_led);
+	led_classdev_unregister(&hp6xx_green_led);
+
+	return 0;
+}
+
+static struct platform_driver hp6xxled_driver = {
+	.probe		= hp6xxled_probe,
+	.remove		= hp6xxled_remove,
+#ifdef CONFIG_PM
+	.suspend	= hp6xxled_suspend,
+	.resume		= hp6xxled_resume,
+#endif
+	.driver		= {
+		.name		= "hp6xx-led",
+	},
+};
+
+static int __init hp6xxled_init(void)
+{
+	return platform_driver_register(&hp6xxled_driver);
+}
+
+static void __exit hp6xxled_exit(void)
+{
+	platform_driver_unregister(&hp6xxled_driver);
+}
+
+module_init(hp6xxled_init);
+module_exit(hp6xxled_exit);
+
+MODULE_AUTHOR("Kristoffer Ericson <kristoffer.ericson@gmail.com>");
+MODULE_DESCRIPTION("HP Jornada 6xx LED driver");
+MODULE_LICENSE("GPL");

+ 0 - 214
drivers/leds/leds-ixp4xx-gpio.c

@@ -1,214 +0,0 @@
-/*
- * IXP4XX GPIO driver LED driver
- *
- * Author: John Bowler <jbowler@acm.org>
- *
- * Copyright (c) 2006 John Bowler
- *
- * Permission is hereby granted, free of charge, to any
- * person obtaining a copy of this software and associated
- * documentation files (the "Software"), to deal in the
- * Software without restriction, including without
- * limitation the rights to use, copy, modify, merge,
- * publish, distribute, sublicense, and/or sell copies of
- * the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the
- * following conditions:
- *
- * The above copyright notice and this permission notice
- * shall be included in all copies or substantial portions
- * of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
- * ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
- * TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
- * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
- * SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
- * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- */
-
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/platform_device.h>
-#include <linux/spinlock.h>
-#include <linux/leds.h>
-#include <asm/arch/hardware.h>
-
-extern spinlock_t gpio_lock;
-
-/* Up to 16 gpio lines are possible. */
-#define GPIO_MAX 16
-static struct ixp4xxgpioled_device {
-	struct led_classdev ancestor;
-	int               flags;
-} ixp4xxgpioled_devices[GPIO_MAX];
-
-void ixp4xxgpioled_brightness_set(struct led_classdev *pled,
-				enum led_brightness value)
-{
-	const struct ixp4xxgpioled_device *const ixp4xx_dev =
-		container_of(pled, struct ixp4xxgpioled_device, ancestor);
-	const u32 gpio_pin = ixp4xx_dev - ixp4xxgpioled_devices;
-
-	if (gpio_pin < GPIO_MAX && ixp4xx_dev->ancestor.name != 0) {
-		/* Set or clear the 'gpio_pin' bit according to the style
-		 * and the required setting (value > 0 == on)
-		 */
-		const int gpio_value =
-			(value > 0) == (ixp4xx_dev->flags != IXP4XX_GPIO_LOW) ?
-				IXP4XX_GPIO_HIGH : IXP4XX_GPIO_LOW;
-
-		{
-			unsigned long flags;
-			spin_lock_irqsave(&gpio_lock, flags);
-			gpio_line_set(gpio_pin, gpio_value);
-			spin_unlock_irqrestore(&gpio_lock, flags);
-		}
-	}
-}
-
-/* LEDs are described in resources, the following iterates over the valid
- * LED resources.
- */
-#define for_all_leds(i, pdev) \
-	for (i=0; i<pdev->num_resources; ++i) \
-		if (pdev->resource[i].start < GPIO_MAX && \
-			pdev->resource[i].name != 0)
-
-/* The following applies 'operation' to each LED from the given platform,
- * the function always returns 0 to allow tail call elimination.
- */
-static int apply_to_all_leds(struct platform_device *pdev,
-	void (*operation)(struct led_classdev *pled))
-{
-	int i;
-
-	for_all_leds(i, pdev)
-		operation(&ixp4xxgpioled_devices[pdev->resource[i].start].ancestor);
-	return 0;
-}
-
-#ifdef CONFIG_PM
-static int ixp4xxgpioled_suspend(struct platform_device *pdev,
-				pm_message_t state)
-{
-	return apply_to_all_leds(pdev, led_classdev_suspend);
-}
-
-static int ixp4xxgpioled_resume(struct platform_device *pdev)
-{
-	return apply_to_all_leds(pdev, led_classdev_resume);
-}
-#endif
-
-static void ixp4xxgpioled_remove_one_led(struct led_classdev *pled)
-{
-	led_classdev_unregister(pled);
-	pled->name = 0;
-}
-
-static int ixp4xxgpioled_remove(struct platform_device *pdev)
-{
-	return apply_to_all_leds(pdev, ixp4xxgpioled_remove_one_led);
-}
-
-static int ixp4xxgpioled_probe(struct platform_device *pdev)
-{
-	/* The board level has to tell the driver where the
-	 * LEDs are connected - there is no way to find out
-	 * electrically.  It must also say whether the GPIO
-	 * lines are active high or active low.
-	 *
-	 * To do this read the num_resources (the number of
-	 * LEDs) and the struct resource (the data for each
-	 * LED).  The name comes from the resource, and it
-	 * isn't copied.
-	 */
-	int i;
-
-	for_all_leds(i, pdev) {
-		const u8 gpio_pin = pdev->resource[i].start;
-		int      rc;
-
-		if (ixp4xxgpioled_devices[gpio_pin].ancestor.name == 0) {
-			unsigned long flags;
-
-			spin_lock_irqsave(&gpio_lock, flags);
-			gpio_line_config(gpio_pin, IXP4XX_GPIO_OUT);
-			/* The config can, apparently, reset the state,
-			 * I suspect the gpio line may be an input and
-			 * the config may cause the line to be latched,
-			 * so the setting depends on how the LED is
-			 * connected to the line (which affects how it
-			 * floats if not driven).
-			 */
-			gpio_line_set(gpio_pin, IXP4XX_GPIO_HIGH);
-			spin_unlock_irqrestore(&gpio_lock, flags);
-
-			ixp4xxgpioled_devices[gpio_pin].flags =
-				pdev->resource[i].flags & IORESOURCE_BITS;
-
-			ixp4xxgpioled_devices[gpio_pin].ancestor.name =
-				pdev->resource[i].name;
-
-			/* This is how a board manufacturer makes the LED
-			 * come on on reset - the GPIO line will be high, so
-			 * make the LED light when the line is low...
-			 */
-			if (ixp4xxgpioled_devices[gpio_pin].flags != IXP4XX_GPIO_LOW)
-				ixp4xxgpioled_devices[gpio_pin].ancestor.brightness = 100;
-			else
-				ixp4xxgpioled_devices[gpio_pin].ancestor.brightness = 0;
-
-			ixp4xxgpioled_devices[gpio_pin].ancestor.flags = 0;
-
-			ixp4xxgpioled_devices[gpio_pin].ancestor.brightness_set =
-				ixp4xxgpioled_brightness_set;
-
-			ixp4xxgpioled_devices[gpio_pin].ancestor.default_trigger = 0;
-		}
-
-		rc = led_classdev_register(&pdev->dev,
-				&ixp4xxgpioled_devices[gpio_pin].ancestor);
-		if (rc < 0) {
-			ixp4xxgpioled_devices[gpio_pin].ancestor.name = 0;
-			ixp4xxgpioled_remove(pdev);
-			return rc;
-		}
-	}
-
-	return 0;
-}
-
-static struct platform_driver ixp4xxgpioled_driver = {
-	.probe   = ixp4xxgpioled_probe,
-	.remove  = ixp4xxgpioled_remove,
-#ifdef CONFIG_PM
-	.suspend = ixp4xxgpioled_suspend,
-	.resume  = ixp4xxgpioled_resume,
-#endif
-	.driver  = {
-		.name = "IXP4XX-GPIO-LED",
-	},
-};
-
-static int __init ixp4xxgpioled_init(void)
-{
-	return platform_driver_register(&ixp4xxgpioled_driver);
-}
-
-static void __exit ixp4xxgpioled_exit(void)
-{
-	platform_driver_unregister(&ixp4xxgpioled_driver);
-}
-
-module_init(ixp4xxgpioled_init);
-module_exit(ixp4xxgpioled_exit);
-
-MODULE_AUTHOR("John Bowler <jbowler@acm.org>");
-MODULE_DESCRIPTION("IXP4XX GPIO LED driver");
-MODULE_LICENSE("Dual MIT/GPL");

+ 2 - 2
drivers/leds/leds-locomo.c

@@ -43,13 +43,13 @@ static void locomoled_brightness_set1(struct led_classdev *led_cdev,
 }
 
 static struct led_classdev locomo_led0 = {
-	.name			= "locomo:amber",
+	.name			= "locomo:amber:charge",
 	.default_trigger	= "sharpsl-charge",
 	.brightness_set		= locomoled_brightness_set0,
 };
 
 static struct led_classdev locomo_led1 = {
-	.name			= "locomo:green",
+	.name			= "locomo:green:mail",
 	.default_trigger	= "nand-disk",
 	.brightness_set		= locomoled_brightness_set1,
 };

+ 1 - 1
drivers/leds/leds-net48xx.c

@@ -31,7 +31,7 @@ static void net48xx_error_led_set(struct led_classdev *led_cdev,
 }
 
 static struct led_classdev net48xx_error_led = {
-	.name		= "net48xx:error",
+	.name		= "net48xx::error",
 	.brightness_set	= net48xx_error_led_set,
 };
 

+ 5 - 3
drivers/leds/leds-spitz.c

@@ -38,13 +38,13 @@ static void spitzled_green_set(struct led_classdev *led_cdev, enum led_brightnes
 }
 
 static struct led_classdev spitz_amber_led = {
-	.name			= "spitz:amber",
+	.name			= "spitz:amber:charge",
 	.default_trigger	= "sharpsl-charge",
 	.brightness_set		= spitzled_amber_set,
 };
 
 static struct led_classdev spitz_green_led = {
-	.name			= "spitz:green",
+	.name			= "spitz:green:hddactivity",
 	.default_trigger	= "ide-disk",
 	.brightness_set		= spitzled_green_set,
 };
@@ -72,8 +72,10 @@ static int spitzled_probe(struct platform_device *pdev)
 {
 	int ret;
 
-	if (machine_is_akita())
+	if (machine_is_akita()) {
+		spitz_green_led.name = "spitz:green:mail";
 		spitz_green_led.default_trigger = "nand-disk";
+	}
 
 	ret = led_classdev_register(&pdev->dev, &spitz_amber_led);
 	if (ret < 0)

+ 2 - 2
drivers/leds/leds-tosa.c

@@ -45,13 +45,13 @@ static void tosaled_green_set(struct led_classdev *led_cdev,
 }
 
 static struct led_classdev tosa_amber_led = {
-	.name			= "tosa:amber",
+	.name			= "tosa:amber:charge",
 	.default_trigger	= "sharpsl-charge",
 	.brightness_set		= tosaled_amber_set,
 };
 
 static struct led_classdev tosa_green_led = {
-	.name			= "tosa:green",
+	.name			= "tosa:green:mail",
 	.default_trigger	= "nand-disk",
 	.brightness_set		= tosaled_green_set,
 };

+ 39 - 8
drivers/leds/leds-wrap.c

@@ -19,11 +19,21 @@
 #include <linux/scx200_gpio.h>
 
 #define DRVNAME "wrap-led"
+#define WRAP_POWER_LED_GPIO	2
 #define WRAP_ERROR_LED_GPIO	3
-#define	WRAP_EXTRA_LED_GPIO	18
+#define WRAP_EXTRA_LED_GPIO	18
 
 static struct platform_device *pdev;
 
+static void wrap_power_led_set(struct led_classdev *led_cdev,
+		enum led_brightness value)
+{
+	if (value)
+		scx200_gpio_set_low(WRAP_POWER_LED_GPIO);
+	else
+		scx200_gpio_set_high(WRAP_POWER_LED_GPIO);
+}
+
 static void wrap_error_led_set(struct led_classdev *led_cdev,
 		enum led_brightness value)
 {
@@ -42,13 +52,18 @@ static void wrap_extra_led_set(struct led_classdev *led_cdev,
 		scx200_gpio_set_high(WRAP_EXTRA_LED_GPIO);
 }
 
+static struct led_classdev wrap_power_led = {
+	.name		= "wrap::power",
+	.brightness_set	= wrap_power_led_set,
+};
+
 static struct led_classdev wrap_error_led = {
-	.name		= "wrap:error",
+	.name		= "wrap::error",
 	.brightness_set	= wrap_error_led_set,
 };
 
 static struct led_classdev wrap_extra_led = {
-	.name           = "wrap:extra",
+	.name           = "wrap::extra",
 	.brightness_set = wrap_extra_led_set,
 };
 
@@ -56,6 +71,7 @@ static struct led_classdev wrap_extra_led = {
 static int wrap_led_suspend(struct platform_device *dev,
 		pm_message_t state)
 {
+	led_classdev_suspend(&wrap_power_led);
 	led_classdev_suspend(&wrap_error_led);
 	led_classdev_suspend(&wrap_extra_led);
 	return 0;
@@ -63,6 +79,7 @@ static int wrap_led_suspend(struct platform_device *dev,
 
 static int wrap_led_resume(struct platform_device *dev)
 {
+	led_classdev_resume(&wrap_power_led);
 	led_classdev_resume(&wrap_error_led);
 	led_classdev_resume(&wrap_extra_led);
 	return 0;
@@ -76,17 +93,31 @@ static int wrap_led_probe(struct platform_device *pdev)
 {
 	int ret;
 
+	ret = led_classdev_register(&pdev->dev, &wrap_power_led);
+	if (ret < 0)
+		return ret;
+
 	ret = led_classdev_register(&pdev->dev, &wrap_error_led);
-	if (ret == 0) {
-		ret = led_classdev_register(&pdev->dev, &wrap_extra_led);
-		if (ret < 0)
-			led_classdev_unregister(&wrap_error_led);
-	}
+	if (ret < 0)
+		goto err1;
+
+	ret = led_classdev_register(&pdev->dev, &wrap_extra_led);
+	if (ret < 0)
+		goto err2;
+
+	return ret;
+
+err2:
+	led_classdev_unregister(&wrap_error_led);
+err1:
+	led_classdev_unregister(&wrap_power_led);
+
 	return ret;
 }
 
 static int wrap_led_remove(struct platform_device *pdev)
 {
+	led_classdev_unregister(&wrap_power_led);
 	led_classdev_unregister(&wrap_error_led);
 	led_classdev_unregister(&wrap_extra_led);
 	return 0;

+ 37 - 4
drivers/leds/ledtrig-timer.c

@@ -77,8 +77,21 @@ static ssize_t led_delay_on_store(struct device *dev,
 		count++;
 
 	if (count == size) {
-		timer_data->delay_on = state;
-		mod_timer(&timer_data->timer, jiffies + 1);
+		if (timer_data->delay_on != state) {
+			/* the new value differs from the previous */
+			timer_data->delay_on = state;
+
+			/* deactivate previous settings */
+			del_timer_sync(&timer_data->timer);
+
+			/* try to activate hardware acceleration, if any */
+			if (!led_cdev->blink_set ||
+			    led_cdev->blink_set(led_cdev,
+				&timer_data->delay_on, &timer_data->delay_off)) {
+				/* no hardware acceleration, blink via timer */
+				mod_timer(&timer_data->timer, jiffies + 1);
+			}
+		}
 		ret = count;
 	}
 
@@ -110,8 +123,21 @@ static ssize_t led_delay_off_store(struct device *dev,
 		count++;
 
 	if (count == size) {
-		timer_data->delay_off = state;
-		mod_timer(&timer_data->timer, jiffies + 1);
+		if (timer_data->delay_off != state) {
+			/* the new value differs from the previous */
+			timer_data->delay_off = state;
+
+			/* deactivate previous settings */
+			del_timer_sync(&timer_data->timer);
+
+			/* try to activate hardware acceleration, if any */
+			if (!led_cdev->blink_set ||
+			    led_cdev->blink_set(led_cdev,
+				&timer_data->delay_on, &timer_data->delay_off)) {
+				/* no hardware acceleration, blink via timer */
+				mod_timer(&timer_data->timer, jiffies + 1);
+			}
+		}
 		ret = count;
 	}
 
@@ -143,6 +169,13 @@ static void timer_trig_activate(struct led_classdev *led_cdev)
 	if (rc)
 		goto err_out_delayon;
 
+	/* If there is hardware support for blinking, start one
+	 * user friendly blink rate chosen by the driver.
+	 */
+	if (led_cdev->blink_set)
+		led_cdev->blink_set(led_cdev,
+			&timer_data->delay_on, &timer_data->delay_off);
+
 	return;
 
 err_out_delayon:

+ 1 - 1
drivers/misc/asus-laptop.c

@@ -239,7 +239,7 @@ static struct workqueue_struct *led_workqueue;
 	static int object##_led_wk;					\
 	static DECLARE_WORK(object##_led_work, object##_led_update);	\
 	static struct led_classdev object##_led = {			\
-		.name           = "asus:" ledname,			\
+		.name           = "asus::" ledname,			\
 		.brightness_set = object##_led_set,			\
 	}
 

+ 4 - 4
drivers/net/wireless/b43/leds.c

@@ -147,12 +147,12 @@ static void b43_map_led(struct b43_wldev *dev,
 	case B43_LED_TRANSFER:
 	case B43_LED_APTRANSFER:
 		snprintf(name, sizeof(name),
-			 "b43-%s:tx", wiphy_name(hw->wiphy));
+			 "b43-%s::tx", wiphy_name(hw->wiphy));
 		b43_register_led(dev, &dev->led_tx, name,
 				 ieee80211_get_tx_led_name(hw),
 				 led_index, activelow);
 		snprintf(name, sizeof(name),
-			 "b43-%s:rx", wiphy_name(hw->wiphy));
+			 "b43-%s::rx", wiphy_name(hw->wiphy));
 		b43_register_led(dev, &dev->led_rx, name,
 				 ieee80211_get_rx_led_name(hw),
 				 led_index, activelow);
@@ -162,7 +162,7 @@ static void b43_map_led(struct b43_wldev *dev,
 	case B43_LED_RADIO_B:
 	case B43_LED_MODE_BG:
 		snprintf(name, sizeof(name),
-			 "b43-%s:radio", wiphy_name(hw->wiphy));
+			 "b43-%s::radio", wiphy_name(hw->wiphy));
 		b43_register_led(dev, &dev->led_radio, name,
 				 b43_rfkill_led_name(dev),
 				 led_index, activelow);
@@ -173,7 +173,7 @@ static void b43_map_led(struct b43_wldev *dev,
 	case B43_LED_WEIRD:
 	case B43_LED_ASSOC:
 		snprintf(name, sizeof(name),
-			 "b43-%s:assoc", wiphy_name(hw->wiphy));
+			 "b43-%s::assoc", wiphy_name(hw->wiphy));
 		b43_register_led(dev, &dev->led_assoc, name,
 				 ieee80211_get_assoc_led_name(hw),
 				 led_index, activelow);

+ 5 - 0
include/linux/leds.h

@@ -38,6 +38,11 @@ struct led_classdev {
 	void		(*brightness_set)(struct led_classdev *led_cdev,
 					  enum led_brightness brightness);
 
+	/* Activate hardware accelerated blink */
+	int		(*blink_set)(struct led_classdev *led_cdev,
+				     unsigned long *delay_on,
+				     unsigned long *delay_off);
+
 	struct device		*dev;
 	struct list_head	 node;			/* LED Device list */
 	char			*default_trigger;	/* Trigger to use */