Commit eb855fd8 authored by Linus Torvalds's avatar Linus Torvalds

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 default-on trigger
  leds: Document the context brightness_set needs
  leds: Add new driver for the LEDs on the Freecom FSG-3
  leds: Add support to leds with readable status
  leds: enable support for blink_set() platform hook in leds-gpio
  leds: Cleanup various whitespace and code style issues
  leds: disable triggers on brightness set
  leds: Add mail LED support for "Clevo D400P"
parents bf16ae25 060856c7
...@@ -19,6 +19,12 @@ optimises away. ...@@ -19,6 +19,12 @@ optimises away.
Complex triggers whilst available to all LEDs have LED specific Complex triggers whilst available to all LEDs have LED specific
parameters and work on a per LED basis. The timer trigger is an example. parameters and work on a per LED basis. The timer trigger is an example.
The timer trigger will periodically change the LED brightness between
LED_OFF and the current brightness setting. The "on" and "off" time can
be specified via /sys/class/leds/<device>/delay_{on,off} in milliseconds.
You can change the brightness value of a LED independently of the timer
trigger. However, if you set the brightness value to LED_OFF it will
also disable the timer trigger.
You can change triggers in a similar manner to the way an IO scheduler You can change triggers in a similar manner to the way an IO scheduler
is chosen (via /sys/class/leds/<device>/trigger). Trigger specific is chosen (via /sys/class/leds/<device>/trigger). Trigger specific
...@@ -63,9 +69,9 @@ value if it is called with *delay_on==0 && *delay_off==0 parameters. In ...@@ -63,9 +69,9 @@ 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 this case the driver should give back the chosen value through delay_on
and delay_off parameters to the leds subsystem. and delay_off parameters to the leds subsystem.
Any call to the brightness_set() callback function should cancel the Setting the brightness to zero with brightness_set() callback function
previously programmed hardware blinking function so setting the brightness should completely turn off the LED and cancel the previously programmed
to 0 can also cancel the blinking of the LED. hardware blinking function, if any.
Known Issues Known Issues
......
...@@ -65,6 +65,12 @@ config LEDS_NET48XX ...@@ -65,6 +65,12 @@ config LEDS_NET48XX
This option enables support for the Soekris net4801 and net4826 error This option enables support for the Soekris net4801 and net4826 error
LED. LED.
config LEDS_FSG
tristate "LED Support for the Freecom FSG-3"
depends on LEDS_CLASS && MACH_FSG
help
This option enables support for the LEDs on the Freecom FSG-3.
config LEDS_WRAP config LEDS_WRAP
tristate "LED Support for the WRAP series LEDs" tristate "LED Support for the WRAP series LEDs"
depends on LEDS_CLASS && SCx200_GPIO depends on LEDS_CLASS && SCx200_GPIO
...@@ -127,6 +133,7 @@ config LEDS_CLEVO_MAIL ...@@ -127,6 +133,7 @@ config LEDS_CLEVO_MAIL
This module can drive the mail LED for the following notebooks: This module can drive the mail LED for the following notebooks:
Clevo D400P
Clevo D410J Clevo D410J
Clevo D410V Clevo D410V
Clevo D400V/D470V (not tested, but might work) Clevo D400V/D470V (not tested, but might work)
...@@ -134,6 +141,9 @@ config LEDS_CLEVO_MAIL ...@@ -134,6 +141,9 @@ config LEDS_CLEVO_MAIL
Clevo M5x0N (not tested, but might work) Clevo M5x0N (not tested, but might work)
Positivo Mobile (Clevo M5x0V) Positivo Mobile (Clevo M5x0V)
If your model is not listed here you can try the "nodetect"
module paramter.
To compile this driver as a module, choose M here: the To compile this driver as a module, choose M here: the
module will be called leds-clevo-mail. module will be called leds-clevo-mail.
...@@ -173,4 +183,11 @@ config LEDS_TRIGGER_HEARTBEAT ...@@ -173,4 +183,11 @@ config LEDS_TRIGGER_HEARTBEAT
load average. load average.
If unsure, say Y. If unsure, say Y.
config LEDS_TRIGGER_DEFAULT_ON
tristate "LED Default ON Trigger"
depends on LEDS_TRIGGERS
help
This allows LEDs to be initialised in the ON state.
If unsure, say Y.
endif # NEW_LEDS endif # NEW_LEDS
...@@ -20,8 +20,10 @@ obj-$(CONFIG_LEDS_GPIO) += leds-gpio.o ...@@ -20,8 +20,10 @@ obj-$(CONFIG_LEDS_GPIO) += leds-gpio.o
obj-$(CONFIG_LEDS_CM_X270) += leds-cm-x270.o obj-$(CONFIG_LEDS_CM_X270) += leds-cm-x270.o
obj-$(CONFIG_LEDS_CLEVO_MAIL) += leds-clevo-mail.o obj-$(CONFIG_LEDS_CLEVO_MAIL) += leds-clevo-mail.o
obj-$(CONFIG_LEDS_HP6XX) += leds-hp6xx.o obj-$(CONFIG_LEDS_HP6XX) += leds-hp6xx.o
obj-$(CONFIG_LEDS_FSG) += leds-fsg.o
# LED Triggers # LED Triggers
obj-$(CONFIG_LEDS_TRIGGER_TIMER) += ledtrig-timer.o obj-$(CONFIG_LEDS_TRIGGER_TIMER) += ledtrig-timer.o
obj-$(CONFIG_LEDS_TRIGGER_IDE_DISK) += ledtrig-ide-disk.o obj-$(CONFIG_LEDS_TRIGGER_IDE_DISK) += ledtrig-ide-disk.o
obj-$(CONFIG_LEDS_TRIGGER_HEARTBEAT) += ledtrig-heartbeat.o obj-$(CONFIG_LEDS_TRIGGER_HEARTBEAT) += ledtrig-heartbeat.o
obj-$(CONFIG_LEDS_TRIGGER_DEFAULT_ON) += ledtrig-default-on.o
...@@ -24,6 +24,12 @@ ...@@ -24,6 +24,12 @@
static struct class *leds_class; static struct class *leds_class;
static void led_update_brightness(struct led_classdev *led_cdev)
{
if (led_cdev->brightness_get)
led_cdev->brightness = led_cdev->brightness_get(led_cdev);
}
static ssize_t led_brightness_show(struct device *dev, static ssize_t led_brightness_show(struct device *dev,
struct device_attribute *attr, char *buf) struct device_attribute *attr, char *buf)
{ {
...@@ -31,6 +37,7 @@ static ssize_t led_brightness_show(struct device *dev, ...@@ -31,6 +37,7 @@ static ssize_t led_brightness_show(struct device *dev,
ssize_t ret = 0; ssize_t ret = 0;
/* no lock needed for this */ /* no lock needed for this */
led_update_brightness(led_cdev);
sprintf(buf, "%u\n", led_cdev->brightness); sprintf(buf, "%u\n", led_cdev->brightness);
ret = strlen(buf) + 1; ret = strlen(buf) + 1;
...@@ -51,6 +58,9 @@ static ssize_t led_brightness_store(struct device *dev, ...@@ -51,6 +58,9 @@ static ssize_t led_brightness_store(struct device *dev,
if (count == size) { if (count == size) {
ret = count; ret = count;
if (state == LED_OFF)
led_trigger_remove(led_cdev);
led_set_brightness(led_cdev, state); led_set_brightness(led_cdev, state);
} }
...@@ -110,6 +120,8 @@ int led_classdev_register(struct device *parent, struct led_classdev *led_cdev) ...@@ -110,6 +120,8 @@ int led_classdev_register(struct device *parent, struct led_classdev *led_cdev)
list_add_tail(&led_cdev->node, &leds_list); list_add_tail(&led_cdev->node, &leds_list);
up_write(&leds_list_lock); up_write(&leds_list_lock);
led_update_brightness(led_cdev);
#ifdef CONFIG_LEDS_TRIGGERS #ifdef CONFIG_LEDS_TRIGGERS
init_rwsem(&led_cdev->trigger_lock); init_rwsem(&led_cdev->trigger_lock);
......
...@@ -19,7 +19,7 @@ ...@@ -19,7 +19,7 @@
#include "leds.h" #include "leds.h"
DECLARE_RWSEM(leds_list_lock); DECLARE_RWSEM(leds_list_lock);
LIST_HEAD(leds_list); EXPORT_SYMBOL_GPL(leds_list_lock);
LIST_HEAD(leds_list);
EXPORT_SYMBOL_GPL(leds_list); EXPORT_SYMBOL_GPL(leds_list);
EXPORT_SYMBOL_GPL(leds_list_lock);
...@@ -29,6 +29,8 @@ ...@@ -29,6 +29,8 @@
static DECLARE_RWSEM(triggers_list_lock); static DECLARE_RWSEM(triggers_list_lock);
static LIST_HEAD(trigger_list); static LIST_HEAD(trigger_list);
/* Used by LED Class */
ssize_t led_trigger_store(struct device *dev, struct device_attribute *attr, ssize_t led_trigger_store(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count) const char *buf, size_t count)
{ {
...@@ -45,9 +47,7 @@ ssize_t led_trigger_store(struct device *dev, struct device_attribute *attr, ...@@ -45,9 +47,7 @@ ssize_t led_trigger_store(struct device *dev, struct device_attribute *attr,
trigger_name[len - 1] = '\0'; trigger_name[len - 1] = '\0';
if (!strcmp(trigger_name, "none")) { if (!strcmp(trigger_name, "none")) {
down_write(&led_cdev->trigger_lock); led_trigger_remove(led_cdev);
led_trigger_set(led_cdev, NULL);
up_write(&led_cdev->trigger_lock);
return count; return count;
} }
...@@ -66,7 +66,7 @@ ssize_t led_trigger_store(struct device *dev, struct device_attribute *attr, ...@@ -66,7 +66,7 @@ ssize_t led_trigger_store(struct device *dev, struct device_attribute *attr,
return -EINVAL; return -EINVAL;
} }
EXPORT_SYMBOL_GPL(led_trigger_store);
ssize_t led_trigger_show(struct device *dev, struct device_attribute *attr, ssize_t led_trigger_show(struct device *dev, struct device_attribute *attr,
char *buf) char *buf)
...@@ -96,24 +96,7 @@ ssize_t led_trigger_show(struct device *dev, struct device_attribute *attr, ...@@ -96,24 +96,7 @@ ssize_t led_trigger_show(struct device *dev, struct device_attribute *attr,
len += sprintf(len+buf, "\n"); len += sprintf(len+buf, "\n");
return len; return len;
} }
EXPORT_SYMBOL_GPL(led_trigger_show);
void led_trigger_event(struct led_trigger *trigger,
enum led_brightness brightness)
{
struct list_head *entry;
if (!trigger)
return;
read_lock(&trigger->leddev_list_lock);
list_for_each(entry, &trigger->led_cdevs) {
struct led_classdev *led_cdev;
led_cdev = list_entry(entry, struct led_classdev, trig_list);
led_set_brightness(led_cdev, brightness);
}
read_unlock(&trigger->leddev_list_lock);
}
/* Caller must ensure led_cdev->trigger_lock held */ /* Caller must ensure led_cdev->trigger_lock held */
void led_trigger_set(struct led_classdev *led_cdev, struct led_trigger *trigger) void led_trigger_set(struct led_classdev *led_cdev, struct led_trigger *trigger)
...@@ -124,7 +107,8 @@ void led_trigger_set(struct led_classdev *led_cdev, struct led_trigger *trigger) ...@@ -124,7 +107,8 @@ void led_trigger_set(struct led_classdev *led_cdev, struct led_trigger *trigger)
if (led_cdev->trigger) { if (led_cdev->trigger) {
write_lock_irqsave(&led_cdev->trigger->leddev_list_lock, flags); write_lock_irqsave(&led_cdev->trigger->leddev_list_lock, flags);
list_del(&led_cdev->trig_list); list_del(&led_cdev->trig_list);
write_unlock_irqrestore(&led_cdev->trigger->leddev_list_lock, flags); write_unlock_irqrestore(&led_cdev->trigger->leddev_list_lock,
flags);
if (led_cdev->trigger->deactivate) if (led_cdev->trigger->deactivate)
led_cdev->trigger->deactivate(led_cdev); led_cdev->trigger->deactivate(led_cdev);
led_set_brightness(led_cdev, LED_OFF); led_set_brightness(led_cdev, LED_OFF);
...@@ -138,6 +122,15 @@ void led_trigger_set(struct led_classdev *led_cdev, struct led_trigger *trigger) ...@@ -138,6 +122,15 @@ void led_trigger_set(struct led_classdev *led_cdev, struct led_trigger *trigger)
} }
led_cdev->trigger = trigger; led_cdev->trigger = trigger;
} }
EXPORT_SYMBOL_GPL(led_trigger_set);
void led_trigger_remove(struct led_classdev *led_cdev)
{
down_write(&led_cdev->trigger_lock);
led_trigger_set(led_cdev, NULL);
up_write(&led_cdev->trigger_lock);
}
EXPORT_SYMBOL_GPL(led_trigger_remove);
void led_trigger_set_default(struct led_classdev *led_cdev) void led_trigger_set_default(struct led_classdev *led_cdev)
{ {
...@@ -155,6 +148,9 @@ void led_trigger_set_default(struct led_classdev *led_cdev) ...@@ -155,6 +148,9 @@ void led_trigger_set_default(struct led_classdev *led_cdev)
up_write(&led_cdev->trigger_lock); up_write(&led_cdev->trigger_lock);
up_read(&triggers_list_lock); up_read(&triggers_list_lock);
} }
EXPORT_SYMBOL_GPL(led_trigger_set_default);
/* LED Trigger Interface */
int led_trigger_register(struct led_trigger *trigger) int led_trigger_register(struct led_trigger *trigger)
{ {
...@@ -181,26 +177,7 @@ int led_trigger_register(struct led_trigger *trigger) ...@@ -181,26 +177,7 @@ int led_trigger_register(struct led_trigger *trigger)
return 0; return 0;
} }
EXPORT_SYMBOL_GPL(led_trigger_register);
void led_trigger_register_simple(const char *name, struct led_trigger **tp)
{
struct led_trigger *trigger;
int err;
trigger = kzalloc(sizeof(struct led_trigger), GFP_KERNEL);
if (trigger) {
trigger->name = name;
err = led_trigger_register(trigger);
if (err < 0)
printk(KERN_WARNING "LED trigger %s failed to register"
" (%d)\n", name, err);
} else
printk(KERN_WARNING "LED trigger %s failed to register"
" (no memory)\n", name);
*tp = trigger;
}
void led_trigger_unregister(struct led_trigger *trigger) void led_trigger_unregister(struct led_trigger *trigger)
{ {
...@@ -221,28 +198,57 @@ void led_trigger_unregister(struct led_trigger *trigger) ...@@ -221,28 +198,57 @@ void led_trigger_unregister(struct led_trigger *trigger)
} }
up_read(&leds_list_lock); up_read(&leds_list_lock);
} }
EXPORT_SYMBOL_GPL(led_trigger_unregister);
void led_trigger_unregister_simple(struct led_trigger *trigger) /* Simple LED Tigger Interface */
void led_trigger_event(struct led_trigger *trigger,
enum led_brightness brightness)
{ {
if (trigger) struct list_head *entry;
led_trigger_unregister(trigger);
kfree(trigger); if (!trigger)
return;
read_lock(&trigger->leddev_list_lock);
list_for_each(entry, &trigger->led_cdevs) {
struct led_classdev *led_cdev;
led_cdev = list_entry(entry, struct led_classdev, trig_list);
led_set_brightness(led_cdev, brightness);
}
read_unlock(&trigger->leddev_list_lock);
} }
EXPORT_SYMBOL_GPL(led_trigger_event);
/* Used by LED Class */ void led_trigger_register_simple(const char *name, struct led_trigger **tp)
EXPORT_SYMBOL_GPL(led_trigger_set); {
EXPORT_SYMBOL_GPL(led_trigger_set_default); struct led_trigger *trigger;
EXPORT_SYMBOL_GPL(led_trigger_show); int err;
EXPORT_SYMBOL_GPL(led_trigger_store);
/* LED Trigger Interface */ trigger = kzalloc(sizeof(struct led_trigger), GFP_KERNEL);
EXPORT_SYMBOL_GPL(led_trigger_register);
EXPORT_SYMBOL_GPL(led_trigger_unregister);
/* Simple LED Tigger Interface */ if (trigger) {
trigger->name = name;
err = led_trigger_register(trigger);
if (err < 0)
printk(KERN_WARNING "LED trigger %s failed to register"
" (%d)\n", name, err);
} else
printk(KERN_WARNING "LED trigger %s failed to register"
" (no memory)\n", name);
*tp = trigger;
}
EXPORT_SYMBOL_GPL(led_trigger_register_simple); EXPORT_SYMBOL_GPL(led_trigger_register_simple);
void led_trigger_unregister_simple(struct led_trigger *trigger)
{
if (trigger)
led_trigger_unregister(trigger);
kfree(trigger);
}
EXPORT_SYMBOL_GPL(led_trigger_unregister_simple); EXPORT_SYMBOL_GPL(led_trigger_unregister_simple);
EXPORT_SYMBOL_GPL(led_trigger_event);
MODULE_AUTHOR("Richard Purdie"); MODULE_AUTHOR("Richard Purdie");
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
......
...@@ -14,7 +14,7 @@ ...@@ -14,7 +14,7 @@
#define CLEVO_MAIL_LED_BLINK_1HZ 0x008A #define CLEVO_MAIL_LED_BLINK_1HZ 0x008A
#define CLEVO_MAIL_LED_BLINK_0_5HZ 0x0083 #define CLEVO_MAIL_LED_BLINK_0_5HZ 0x0083
MODULE_AUTHOR("Mrton Nmeth <nm127@freemail.hu>"); MODULE_AUTHOR("Márton Németh <nm127@freemail.hu>");
MODULE_DESCRIPTION("Clevo mail LED driver"); MODULE_DESCRIPTION("Clevo mail LED driver");
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
...@@ -67,6 +67,16 @@ static struct dmi_system_id __initdata mail_led_whitelist[] = { ...@@ -67,6 +67,16 @@ static struct dmi_system_id __initdata mail_led_whitelist[] = {
DMI_MATCH(DMI_PRODUCT_VERSION, "VT6198") DMI_MATCH(DMI_PRODUCT_VERSION, "VT6198")
} }
}, },
{
.callback = clevo_mail_led_dmi_callback,
.ident = "Clevo D400P",
.matches = {
DMI_MATCH(DMI_BOARD_VENDOR, "Clevo"),
DMI_MATCH(DMI_BOARD_NAME, "D400P"),
DMI_MATCH(DMI_BOARD_VERSION, "Rev.A"),
DMI_MATCH(DMI_PRODUCT_VERSION, "0106")
}
},
{ {
.callback = clevo_mail_led_dmi_callback, .callback = clevo_mail_led_dmi_callback,
.ident = "Clevo D410V", .ident = "Clevo D410V",
...@@ -93,8 +103,8 @@ static void clevo_mail_led_set(struct led_classdev *led_cdev, ...@@ -93,8 +103,8 @@ static void clevo_mail_led_set(struct led_classdev *led_cdev,
} }
static int clevo_mail_led_blink(struct led_classdev *led_cdev, static int clevo_mail_led_blink(struct led_classdev *led_cdev,
unsigned long* delay_on, unsigned long *delay_on,
unsigned long* delay_off) unsigned long *delay_off)
{ {
int status = -EINVAL; int status = -EINVAL;
......
...@@ -21,7 +21,8 @@ ...@@ -21,7 +21,8 @@
#include <asm/arch/pxa-regs.h> #include <asm/arch/pxa-regs.h>
#include <asm/hardware/scoop.h> #include <asm/hardware/scoop.h>
static void corgiled_amber_set(struct led_classdev *led_cdev, enum led_brightness value) static void corgiled_amber_set(struct led_classdev *led_cdev,
enum led_brightness value)
{ {
if (value) if (value)
GPSR0 = GPIO_bit(CORGI_GPIO_LED_ORANGE); GPSR0 = GPIO_bit(CORGI_GPIO_LED_ORANGE);
...@@ -29,7 +30,8 @@ static void corgiled_amber_set(struct led_classdev *led_cdev, enum led_brightnes ...@@ -29,7 +30,8 @@ static void corgiled_amber_set(struct led_classdev *led_cdev, enum led_brightnes
GPCR0 = GPIO_bit(CORGI_GPIO_LED_ORANGE); GPCR0 = GPIO_bit(CORGI_GPIO_LED_ORANGE);
} }
static void corgiled_green_set(struct led_classdev *led_cdev, enum led_brightness value) static void corgiled_green_set(struct led_classdev *led_cdev,
enum led_brightness value)
{ {
if (value) if (value)
set_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_LED_GREEN); set_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_LED_GREEN);
...@@ -53,7 +55,8 @@ static struct led_classdev corgi_green_led = { ...@@ -53,7 +55,8 @@ static struct led_classdev corgi_green_led = {
static int corgiled_suspend(struct platform_device *dev, pm_message_t state) static int corgiled_suspend(struct platform_device *dev, pm_message_t state)
{ {
#ifdef CONFIG_LEDS_TRIGGERS #ifdef CONFIG_LEDS_TRIGGERS
if (corgi_amber_led.trigger && strcmp(corgi_amber_led.trigger->name, "sharpsl-charge")) if (corgi_amber_led.trigger &&
strcmp(corgi_amber_led.trigger->name, "sharpsl-charge"))
#endif #endif
led_classdev_suspend(&corgi_amber_led); led_classdev_suspend(&corgi_amber_led);
led_classdev_suspend(&corgi_green_led); led_classdev_suspend(&corgi_green_led);
......
/*
* LED Driver for the Freecom FSG-3
*
* Copyright (c) 2008 Rod Whitby <rod@whitby.id.au>
*
* Author: Rod Whitby <rod@whitby.id.au>
*
* Based on leds-spitz.c
* Copyright 2005-2006 Openedhand Ltd.
* Author: Richard Purdie <rpurdie@openedhand.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
*/
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/platform_device.h>
#include <linux/leds.h>
#include <asm/arch/hardware.h>
#include <asm/io.h>
static short __iomem *latch_address;
static unsigned short latch_value;
static void fsg_led_wlan_set(struct led_classdev *led_cdev,
enum led_brightness value)
{
if (value) {
latch_value &= ~(1 << FSG_LED_WLAN_BIT);
*latch_address = latch_value;
} else {
latch_value |= (1 << FSG_LED_WLAN_BIT);
*latch_address = latch_value;
}
}
static void fsg_led_wan_set(struct led_classdev *led_cdev,
enum led_brightness value)
{
if (value) {
latch_value &= ~(1 << FSG_LED_WAN_BIT);
*latch_address = latch_value;
} else {
latch_value |= (1 << FSG_LED_WAN_BIT);
*latch_address = latch_value;
}
}
static void fsg_led_sata_set(struct led_classdev *led_cdev,
enum led_brightness value)
{
if (value) {
latch_value &= ~(1 << FSG_LED_SATA_BIT);
*latch_address = latch_value;
} else {
latch_value |= (1 << FSG_LED_SATA_BIT);
*latch_address = latch_value;
}
}
static void fsg_led_usb_set(struct led_classdev *led_cdev,
enum led_brightness value)
{
if (value) {
latch_value &= ~(1 << FSG_LED_USB_BIT);
*latch_address = latch_value;
} else {
latch_value |= (1 << FSG_LED_USB_BIT);
*latch_address = latch_value;
}
}
static void fsg_led_sync_set(struct led_classdev *led_cdev,
enum led_brightness value)
{
if (value) {
latch_value &= ~(1 << FSG_LED_SYNC_BIT);
*latch_address = latch_value;
} else {
latch_value |= (1 << FSG_LED_SYNC_BIT);
*latch_address = latch_value;
}
}
static void fsg_led_ring_set(struct led_classdev *led_cdev,
enum led_brightness value)
{
if (value) {
latch_value &= ~(1 << FSG_LED_RING_BIT);
*latch_address = latch_value;
} else {
latch_value |= (1 << FSG_LED_RING_BIT);
*latch_address = latch_value;
}
}
static struct led_classdev fsg_wlan_led = {
.name = "fsg:blue:wlan",
.brightness_set = fsg_led_wlan_set,
};
static struct led_classdev fsg_wan_led = {
.name = "fsg:blue:wan",
.brightness_set = fsg_led_wan_set,
};
static struct led_classdev fsg_sata_led = {
.name = "fsg:blue:sata",
.brightness_set = fsg_led_sata_set,
};
static struct led_classdev fsg_usb_led = {
.name = "fsg:blue:usb",
.brightness_set = fsg_led_usb_set,
};
static struct led_classdev fsg_sync_led = {
.name = "fsg:blue:sync",
.brightness_set = fsg_led_sync_set,
};
static struct led_classdev fsg_ring_led = {
.name = "fsg:blue:ring",
.brightness_set = fsg_led_ring_set,
};
#ifdef CONFIG_PM
static int fsg_led_suspend(struct platform_device *dev, pm_message_t state)
{
led_classdev_suspend(&fsg_wlan_led);
led_classdev_suspend(&fsg_wan_led);
led_classdev_suspend(&fsg_sata_led);
led_classdev_suspend(&fsg_usb_led);
led_classdev_suspend(&fsg_sync_led);
led_classdev_suspend(&fsg_ring_led);
return 0;
}
static int fsg_led_resume(struct platform_device *dev)
{
led_classdev_resume(&fsg_wlan_led);
led_classdev_resume(&fsg_wan_led);
led_classdev_resume(&fsg_sata_led);
led_classdev_resume(&fsg_usb_led);
led_classdev_resume(&fsg_sync_led);
led_classdev_resume(&fsg_ring_led);
return 0;
}
#endif
static int fsg_led_probe(struct platform_device *pdev)
{
int ret;
ret = led_classdev_register(&pdev->dev, &fsg_wlan_led);
if (ret < 0)
goto failwlan;
ret = led_classdev_register(&pdev->dev, &fsg_wan_led);
if (ret < 0)
goto failwan;
ret = led_classdev_register(&pdev->dev, &fsg_sata_led);
if (ret < 0)
goto failsata;
ret = led_classdev_register(&pdev->dev, &fsg_usb_led);
if (ret < 0)
goto failusb;
ret = led_classdev_register(&pdev->dev, &fsg_sync_led);
if (ret < 0)
goto failsync;
ret = led_classdev_register(&pdev->dev, &fsg_ring_led);
if (ret < 0)
goto failring;
/* Map the LED chip select address space */
latch_address = (unsigned short *) ioremap(IXP4XX_EXP_BUS_BASE(2), 512);
if (!latch_address) {
ret = -ENOMEM;
goto failremap;
}
latch_value = 0xffff;
*latch_address = latch_value;
return ret;
failremap:
led_classdev_unregister(&fsg_ring_led);
failring:
led_classdev_unregister(&fsg_sync_led);
failsync:
led_classdev_unregister(&fsg_usb_led);
failusb:
led_classdev_unregister(&fsg_sata_led);
failsata:
led_classdev_unregister(&fsg_wan_led);
failwan:
led_classdev_unregister(&fsg_wlan_led);
failwlan:
return ret;
}
static int fsg_led_remove(struct platform_device *pdev)
{
iounmap(latch_address);
led_classdev_unregister(&fsg_wlan_led);
led_classdev_unregister(&fsg_wan_led);
led_classdev_unregister(&fsg_sata_led);
led_classdev_unregister(&fsg_usb_led);
led_classdev_unregister(&fsg_sync_led);
led_classdev_unregister(&fsg_ring_led);
return 0;
}
static struct platform_driver fsg_led_driver = {
.probe = fsg_led_probe,
.remove = fsg_led_remove,
#ifdef CONFIG_PM
.suspend = fsg_led_suspend,
.resume = fsg_led_resume,
#endif
.driver = {
.name = "fsg-led",
},
};
static int __init fsg_led_init(void)
{
return platform_driver_register(&fsg_led_driver);
}
static void __exit fsg_led_exit(void)
{
platform_driver_unregister(&fsg_led_driver);
}
module_init(fsg_led_init);
module_exit(fsg_led_exit);
MODULE_AUTHOR("Rod Whitby <rod@whitby.id.au>");
MODULE_DESCRIPTION("Freecom FSG-3 LED driver");
MODULE_LICENSE("GPL");
...@@ -24,6 +24,8 @@ struct gpio_led_data { ...@@ -24,6 +24,8 @@ struct gpio_led_data {
u8 new_level; u8 new_level;
u8 can_sleep; u8 can_sleep;
u8 active_low; u8 active_low;
int (*platform_gpio_blink_set)(unsigned gpio,
unsigned long *delay_on, unsigned long *delay_off);
}; };
static void gpio_led_work(struct work_struct *work) static void gpio_led_work(struct work_struct *work)
...@@ -60,6 +62,15 @@ static void gpio_led_set(struct led_classdev *led_cdev, ...@@ -60,6 +62,15 @@ static void gpio_led_set(struct led_classdev *led_cdev,
gpio_set_value(led_dat->gpio, level); gpio_set_value(led_dat->gpio, level);
} }
static int gpio_blink_set(struct led_classdev *led_cdev,
unsigned long *delay_on, unsigned long *delay_off)
{
struct gpio_led_data *led_dat =
container_of(led_cdev, struct gpio_led_data, cdev);
return led_dat->platform_gpio_blink_set(led_dat->gpio, delay_on, delay_off);
}
static int gpio_led_probe(struct platform_device *pdev) static int gpio_led_probe(struct platform_device *pdev)
{ {
struct gpio_led_platform_data *pdata = pdev->dev.platform_data; struct gpio_led_platform_data *pdata = pdev->dev.platform_data;
...@@ -88,6 +99,10 @@ static int gpio_led_probe(struct platform_device *pdev) ...@@ -88,6 +99,10 @@ static int gpio_led_probe(struct platform_device *pdev)
led_dat->gpio = cur_led->gpio; led_dat->gpio = cur_led->gpio;
led_dat->can_sleep = gpio_cansleep(cur_led->gpio); led_dat->can_sleep = gpio_cansleep(cur_led->gpio);
led_dat->active_low = cur_led->active_low; led_dat->active_low = cur_led->active_low;
if (pdata->gpio_blink_set) {
led_dat->platform_gpio_blink_set = pdata->gpio_blink_set;
led_dat->cdev.blink_set = gpio_blink_set;
}
led_dat->cdev.brightness_set = gpio_led_set; led_dat->cdev.brightness_set = gpio_led_set;
led_dat->cdev.brightness = LED_OFF; led_dat->cdev.brightness = LED_OFF;
......
...@@ -27,18 +27,18 @@ void h1940_greenled_set(struct led_classdev *led_dev, enum led_brightness value) ...@@ -27,18 +27,18 @@ void h1940_greenled_set(struct led_classdev *led_dev, enum led_brightness value)
{ {
switch (value) { switch (value) {
case LED_HALF: case LED_HALF:
h1940_latch_control(0,H1940_LATCH_LED_FLASH); h1940_latch_control(0, H1940_LATCH_LED_FLASH);
s3c2410_gpio_setpin(S3C2410_GPA7,1); s3c2410_gpio_setpin(S3C2410_GPA7, 1);
break; break;
case LED_FULL: case LED_FULL:
h1940_latch_control(0,H1940_LATCH_LED_GREEN); h1940_latch_control(0, H1940_LATCH_LED_GREEN);
s3c2410_gpio_setpin(S3C2410_GPA7,1); s3c2410_gpio_setpin(S3C2410_GPA7, 1);
break; break;
default: default:
case LED_OFF: case LED_OFF:
h1940_latch_control(H1940_LATCH_LED_FLASH,0); h1940_latch_control(H1940_LATCH_LED_FLASH, 0);
h1940_latch_control(H1940_LATCH_LED_GREEN,0); h1940_latch_control(H1940_LATCH_LED_GREEN, 0);
s3c2410_gpio_setpin(S3C2410_GPA7,0); s3c2410_gpio_setpin(S3C2410_GPA7, 0);
break; break;
} }
} }
...@@ -56,18 +56,18 @@ void h1940_redled_set(struct led_classdev *led_dev, enum led_brightness value) ...@@ -56,18 +56,18 @@ void h1940_redled_set(struct led_classdev *led_dev, enum led_brightness value)
{ {
switch (value) { switch (value) {
case LED_HALF: case LED_HALF:
h1940_latch_control(0,H1940_LATCH_LED_FLASH); h1940_latch_control(0, H1940_LATCH_LED_FLASH);
s3c2410_gpio_setpin(S3C2410_GPA1,1); s3c2410_gpio_setpin(S3C2410_GPA1, 1);
break; break;
case LED_FULL: case LED_FULL:
h1940_latch_control(0,H1940_LATCH_LED_RED); h1940_latch_control(0, H1940_LATCH_LED_RED);
s3c2410_gpio_setpin(S3C2410_GPA1,1); s3c2410_gpio_setpin(S3C2410_GPA1, 1);
break; break;
default: default:
case LED_OFF: case LED_OFF:
h1940_latch_control(H1940_LATCH_LED_FLASH,0); h1940_latch_control(H1940_LATCH_LED_FLASH, 0);
h1940_latch_control(H1940_LATCH_LED_RED,0); h1940_latch_control(H1940_LATCH_LED_RED, 0);
s3c2410_gpio_setpin(S3C2410_GPA1,0); s3c2410_gpio_setpin(S3C2410_GPA1, 0);
break; break;
} }
} }
...@@ -86,11 +86,11 @@ void h1940_blueled_set(struct led_classdev *led_dev, enum led_brightness value) ...@@ -86,11 +86,11 @@ void h1940_blueled_set(struct led_classdev *led_dev, enum led_brightness value)
{ {
if (value) { if (value) {
/* flashing Blue */ /* flashing Blue */
h1940_latch_control(0,H1940_LATCH_LED_FLASH); h1940_latch_control(0, H1940_LATCH_LED_FLASH);
s3c2410_gpio_setpin(S3C2410_GPA3,1); s3c2410_gpio_setpin(S3C2410_GPA3, 1);
} else { } else {
h1940_latch_control(H1940_LATCH_LED_FLASH,0); h1940_latch_control(H1940_LATCH_LED_FLASH, 0);
s3c2410_gpio_setpin(S3C2410_GPA3,0); s3c2410_gpio_setpin(S3C2410_GPA3, 0);
} }
} }
......
...@@ -17,7 +17,8 @@ ...@@ -17,7 +17,8 @@
#include <asm/hd64461.h> #include <asm/hd64461.h>
#include <asm/hp6xx.h> #include <asm/hp6xx.h>
static void hp6xxled_green_set(struct led_classdev *led_cdev, enum led_brightness value) static void hp6xxled_green_set(struct led_classdev *led_cdev,
enum led_brightness value)
{ {
u8 v8; u8 v8;
...@@ -28,7 +29,8 @@ static void hp6xxled_green_set(struct led_classdev *led_cdev, enum led_brightnes ...@@ -28,7 +29,8 @@ static void hp6xxled_green_set(struct led_classdev *led_cdev, enum led_brightnes
outb(v8 | PKDR_LED_GREEN, PKDR); outb(v8 | PKDR_LED_GREEN, PKDR);
} }
static void hp6xxled_red_set(struct led_classdev *led_cdev, enum led_brightness value) static void hp6xxled_red_set(struct led_classdev *led_cdev,
enum led_brightness value)
{ {
u16 v16; u16 v16;
......
...@@ -21,7 +21,8 @@ ...@@ -21,7 +21,8 @@
#include <asm/arch/pxa-regs.h> #include <asm/arch/pxa-regs.h>
#include <asm/arch/spitz.h> #include <asm/arch/spitz.h>
static void spitzled_amber_set(struct led_classdev *led_cdev, enum led_brightness value) static void spitzled_amber_set(struct led_classdev *led_cdev,
enum led_brightness value)
{ {
if (value) if (value)
set_scoop_gpio(&spitzscoop_device.dev, SPITZ_SCP_LED_ORANGE); set_scoop_gpio(&spitzscoop_device.dev, SPITZ_SCP_LED_ORANGE);
...@@ -29,7 +30,8 @@ static void spitzled_amber_set(struct led_classdev *led_cdev, enum led_brightnes ...@@ -29,7 +30,8 @@ static void spitzled_amber_set(struct led_classdev *led_cdev, enum led_brightnes
reset_scoop_gpio(&spitzscoop_device.dev, SPITZ_SCP_LED_ORANGE); reset_scoop_gpio(&spitzscoop_device.dev, SPITZ_SCP_LED_ORANGE);
} }
static void spitzled_green_set(struct led_classdev *led_cdev, enum led_brightness value) static void spitzled_green_set(struct led_classdev *led_cdev,
enum led_brightness value)
{ {
if (value) if (value)
set_scoop_gpio(&spitzscoop_device.dev, SPITZ_SCP_LED_GREEN); set_scoop_gpio(&spitzscoop_device.dev, SPITZ_SCP_LED_GREEN);
...@@ -53,7 +55,8 @@ static struct led_classdev spitz_green_led = { ...@@ -53,7 +55,8 @@ static struct led_classdev spitz_green_led = {
static int spitzled_suspend(struct platform_device *dev, pm_message_t state) static int spitzled_suspend(struct platform_device *dev, pm_message_t state)
{ {
#ifdef CONFIG_LEDS_TRIGGERS #ifdef CONFIG_LEDS_TRIGGERS
if (spitz_amber_led.trigger && strcmp(spitz_amber_led.trigger->name, "sharpsl-charge")) if (spitz_amber_led.trigger &&
strcmp(spitz_amber_led.trigger->name, "sharpsl-charge"))
#endif #endif
led_classdev_suspend(&spitz_amber_led); led_classdev_suspend(&spitz_amber_led);
led_classdev_suspend(&spitz_green_led); led_classdev_suspend(&spitz_green_led);
......
...@@ -27,6 +27,11 @@ static inline void led_set_brightness(struct led_classdev *led_cdev, ...@@ -27,6 +27,11 @@ static inline void led_set_brightness(struct led_classdev *led_cdev,
led_cdev->brightness_set(led_cdev, value); led_cdev->brightness_set(led_cdev, value);
} }
static inline int led_get_brightness(struct led_classdev *led_cdev)
{
return led_cdev->brightness;
}
extern struct rw_semaphore leds_list_lock; extern struct rw_semaphore leds_list_lock;
extern struct list_head leds_list; extern struct list_head leds_list;
...@@ -34,9 +39,11 @@ extern struct list_head leds_list; ...@@ -34,9 +39,11 @@ extern struct list_head leds_list;
void led_trigger_set_default(struct led_classdev *led_cdev); void led_trigger_set_default(struct led_classdev *led_cdev);
void led_trigger_set(struct led_classdev *led_cdev, void led_trigger_set(struct led_classdev *led_cdev,
struct led_trigger *trigger); struct led_trigger *trigger);
void led_trigger_remove(struct led_classdev *led_cdev);
#else #else
#define led_trigger_set_default(x) do {} while(0) #define led_trigger_set_default(x) do {} while (0)
#define led_trigger_set(x, y) do {} while(0) #define led_trigger_set(x, y) do {} while (0)
#define led_trigger_remove(x) do {} while (0)
#endif #endif
ssize_t led_trigger_store(struct device *dev, struct device_attribute *attr, ssize_t led_trigger_store(struct device *dev, struct device_attribute *attr,
......
/*
* LED Kernel Default ON Trigger
*
* Copyright 2008 Nick Forbes <nick.forbes@incepta.com>
*
* Based on Richard Purdie's ledtrig-timer.c.
*
* 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/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/leds.h>
#include "leds.h"
static void defon_trig_activate(struct led_classdev *led_cdev)
{
led_set_brightness(led_cdev, LED_FULL);
}
static struct led_trigger defon_led_trigger = {
.name = "default-on",
.activate = defon_trig_activate,
};
static int __init defon_trig_init(void)
{
return led_trigger_register(&defon_led_trigger);
}
static void __exit defon_trig_exit(void)
{
led_trigger_unregister(&defon_led_trigger);
}
module_init(defon_trig_init);
module_exit(defon_trig_exit);
MODULE_AUTHOR("Nick Forbes <nick.forbes@incepta.com>");
MODULE_DESCRIPTION("Default-ON LED trigger");
MODULE_LICENSE("GPL");
...@@ -25,6 +25,9 @@ ...@@ -25,6 +25,9 @@
#include "leds.h" #include "leds.h"
struct timer_trig_data { struct timer_trig_data {
int brightness_on; /* LED brightness during "on" period.
* (LED_OFF < brightness_on <= LED_FULL)
*/
unsigned long delay_on; /* milliseconds on */ unsigned long delay_on; /* milliseconds on */
unsigned long delay_off; /* milliseconds off */ unsigned long delay_off; /* milliseconds off */
struct timer_list timer; struct timer_list timer;
...@@ -34,17 +37,26 @@ static void led_timer_function(unsigned long data) ...@@ -34,17 +37,26 @@ static void led_timer_function(unsigned long data)
{ {
struct led_classdev *led_cdev = (struct led_classdev *) data; struct led_classdev *led_cdev = (struct led_classdev *) data;
struct timer_trig_data *timer_data = led_cdev->trigger_data; struct timer_trig_data *timer_data = led_cdev->trigger_data;
unsigned long brightness = LED_OFF; unsigned long brightness;
unsigned long delay = timer_data->delay_off; unsigned long delay;
if (!timer_data->delay_on || !timer_data->delay_off) { if (!timer_data->delay_on || !timer_data->delay_off) {
led_set_brightness(led_cdev, LED_OFF); led_set_brightness(led_cdev, LED_OFF);
return; return;
} }
if (!led_cdev->brightness) { brightness = led_get_brightness(led_cdev);
brightness = LED_FULL; if (!brightness) {
/* Time to switch the LED on. */
brightness = timer_data->brightness_on;
delay = timer_data->delay_on; delay = timer_data->delay_on;
} else {
/* Store the current brightness value to be able
* to restore it when the delay_off period is over.
*/
timer_data->brightness_on = brightness;
brightness = LED_OFF;
delay = timer_data->delay_off;
} }
led_set_brightness(led_cdev, brightness); led_set_brightness(led_cdev, brightness);
...@@ -156,6 +168,9 @@ static void timer_trig_activate(struct led_classdev *led_cdev) ...@@ -156,6 +168,9 @@ static void timer_trig_activate(struct led_classdev *led_cdev)
if (!timer_data) if (!timer_data)
return; return;
timer_data->brightness_on = led_get_brightness(led_cdev);
if (timer_data->brightness_on == LED_OFF)
timer_data->brightness_on = LED_FULL;
led_cdev->trigger_data = timer_data; led_cdev->trigger_data = timer_data;
init_timer(&timer_data->timer); init_timer(&timer_data->timer);
......
...@@ -35,8 +35,11 @@ struct led_classdev { ...@@ -35,8 +35,11 @@ struct led_classdev {
#define LED_SUSPENDED (1 << 0) #define LED_SUSPENDED (1 << 0)
/* Set LED brightness level */ /* Set LED brightness level */
/* Must not sleep, use a workqueue if needed */
void (*brightness_set)(struct led_classdev *led_cdev, void (*brightness_set)(struct led_classdev *led_cdev,
enum led_brightness brightness); enum led_brightness brightness);
/* Get LED brightness level */
enum led_brightness (*brightness_get)(struct led_classdev *led_cdev);
/* Activate hardware accelerated blink */ /* Activate hardware accelerated blink */
int (*blink_set)(struct led_classdev *led_cdev, int (*blink_set)(struct led_classdev *led_cdev,
...@@ -126,6 +129,9 @@ struct gpio_led { ...@@ -126,6 +129,9 @@ struct gpio_led {
struct gpio_led_platform_data { struct gpio_led_platform_data {
int num_leds; int num_leds;
struct gpio_led *leds; struct gpio_led *leds;
int (*gpio_blink_set)(unsigned gpio,
unsigned long *delay_on,
unsigned long *delay_off);
}; };
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment