forked from Minki/linux
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: Convert from struct class_device to struct device leds: leds-gpio for ngw100 leds: Add warning printks in error paths leds: Fix trigger unregister_simple if register_simple fails leds: Use menuconfig objects II - LED leds: Teach leds-gpio to handle timer-unsafe GPIOs leds: Add generic GPIO LED driver
This commit is contained in:
commit
d7f5e3df35
@ -13,6 +13,7 @@
|
||||
#include <linux/linkage.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/leds.h>
|
||||
#include <linux/spi/spi.h>
|
||||
|
||||
#include <asm/io.h>
|
||||
@ -21,6 +22,7 @@
|
||||
#include <asm/arch/at32ap7000.h>
|
||||
#include <asm/arch/board.h>
|
||||
#include <asm/arch/init.h>
|
||||
#include <asm/arch/portmux.h>
|
||||
|
||||
/* Initialized by bootloader-specific startup code. */
|
||||
struct tag *bootloader_tags __initdata;
|
||||
@ -100,8 +102,31 @@ void __init setup_board(void)
|
||||
at32_setup_serial_console(0);
|
||||
}
|
||||
|
||||
static const struct gpio_led ngw_leds[] = {
|
||||
{ .name = "sys", .gpio = GPIO_PIN_PA(16), .active_low = 1,
|
||||
.default_trigger = "heartbeat",
|
||||
},
|
||||
{ .name = "a", .gpio = GPIO_PIN_PA(19), .active_low = 1, },
|
||||
{ .name = "b", .gpio = GPIO_PIN_PE(19), .active_low = 1, },
|
||||
};
|
||||
|
||||
static const struct gpio_led_platform_data ngw_led_data = {
|
||||
.num_leds = ARRAY_SIZE(ngw_leds),
|
||||
.leds = (void *) ngw_leds,
|
||||
};
|
||||
|
||||
static struct platform_device ngw_gpio_leds = {
|
||||
.name = "leds-gpio",
|
||||
.id = -1,
|
||||
.dev = {
|
||||
.platform_data = (void *) &ngw_led_data,
|
||||
}
|
||||
};
|
||||
|
||||
static int __init atngw100_init(void)
|
||||
{
|
||||
unsigned i;
|
||||
|
||||
/*
|
||||
* ATNGW100 uses 16-bit SDRAM interface, so we don't need to
|
||||
* reserve any pins for it.
|
||||
@ -116,6 +141,12 @@ static int __init atngw100_init(void)
|
||||
|
||||
at32_add_device_spi(0, spi0_board_info, ARRAY_SIZE(spi0_board_info));
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(ngw_leds); i++) {
|
||||
at32_select_gpio(ngw_leds[i].gpio,
|
||||
AT32_GPIOF_OUTPUT | AT32_GPIOF_HIGH);
|
||||
}
|
||||
platform_device_register(&ngw_gpio_leds);
|
||||
|
||||
return 0;
|
||||
}
|
||||
postcore_initcall(atngw100_init);
|
||||
|
@ -712,7 +712,21 @@ CONFIG_SPI_ATMEL=y
|
||||
#
|
||||
# LED devices
|
||||
#
|
||||
# CONFIG_NEW_LEDS is not set
|
||||
CONFIG_NEW_LEDS=y
|
||||
CONFIG_LEDS_CLASS=y
|
||||
|
||||
#
|
||||
# LED drivers
|
||||
#
|
||||
CONFIG_LEDS_GPIO=y
|
||||
|
||||
#
|
||||
# LED Triggers
|
||||
#
|
||||
CONFIG_LEDS_TRIGGERS=y
|
||||
CONFIG_LEDS_TRIGGER_TIMER=y
|
||||
CONFIG_LEDS_TRIGGER_HEARTBEAT=y
|
||||
|
||||
|
||||
#
|
||||
# LED drivers
|
||||
|
@ -1,9 +1,6 @@
|
||||
|
||||
menu "LED devices"
|
||||
depends on HAS_IOMEM
|
||||
|
||||
config NEW_LEDS
|
||||
menuconfig NEW_LEDS
|
||||
bool "LED Support"
|
||||
depends on HAS_IOMEM
|
||||
help
|
||||
Say Y to enable Linux LED support. This allows control of supported
|
||||
LEDs from both userspace and optionally, by kernel events (triggers).
|
||||
@ -11,9 +8,10 @@ config NEW_LEDS
|
||||
This is not related to standard keyboard LEDs which are controlled
|
||||
via the input system.
|
||||
|
||||
if NEW_LEDS
|
||||
|
||||
config LEDS_CLASS
|
||||
tristate "LED Class Support"
|
||||
depends on NEW_LEDS
|
||||
help
|
||||
This option enables the led sysfs class in /sys/class/leds. You'll
|
||||
need this to do anything useful with LEDs. If unsure, say N.
|
||||
@ -95,11 +93,18 @@ config LEDS_COBALT
|
||||
help
|
||||
This option enables support for the front LED on Cobalt Server
|
||||
|
||||
config LEDS_GPIO
|
||||
tristate "LED Support for GPIO connected LEDs"
|
||||
depends on LEDS_CLASS && GENERIC_GPIO
|
||||
help
|
||||
This option enables support for the LEDs connected to GPIO
|
||||
outputs. To be useful the particular board must have LEDs
|
||||
and they must be connected to the GPIO lines.
|
||||
|
||||
comment "LED Triggers"
|
||||
|
||||
config LEDS_TRIGGERS
|
||||
bool "LED Trigger support"
|
||||
depends on NEW_LEDS
|
||||
help
|
||||
This option enables trigger support for the leds class.
|
||||
These triggers allow kernel events to drive the LEDs and can
|
||||
@ -128,5 +133,4 @@ config LEDS_TRIGGER_HEARTBEAT
|
||||
load average.
|
||||
If unsure, say Y.
|
||||
|
||||
endmenu
|
||||
|
||||
endif # NEW_LEDS
|
||||
|
@ -16,6 +16,7 @@ obj-$(CONFIG_LEDS_NET48XX) += leds-net48xx.o
|
||||
obj-$(CONFIG_LEDS_WRAP) += leds-wrap.o
|
||||
obj-$(CONFIG_LEDS_H1940) += leds-h1940.o
|
||||
obj-$(CONFIG_LEDS_COBALT) += leds-cobalt.o
|
||||
obj-$(CONFIG_LEDS_GPIO) += leds-gpio.o
|
||||
|
||||
# LED Triggers
|
||||
obj-$(CONFIG_LEDS_TRIGGER_TIMER) += ledtrig-timer.o
|
||||
|
@ -2,7 +2,7 @@
|
||||
* LED Class Core
|
||||
*
|
||||
* Copyright (C) 2005 John Lenz <lenz@cs.wisc.edu>
|
||||
* Copyright (C) 2005-2006 Richard Purdie <rpurdie@openedhand.com>
|
||||
* Copyright (C) 2005-2007 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
|
||||
@ -24,9 +24,10 @@
|
||||
|
||||
static struct class *leds_class;
|
||||
|
||||
static ssize_t led_brightness_show(struct class_device *dev, char *buf)
|
||||
static ssize_t led_brightness_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct led_classdev *led_cdev = class_get_devdata(dev);
|
||||
struct led_classdev *led_cdev = dev_get_drvdata(dev);
|
||||
ssize_t ret = 0;
|
||||
|
||||
/* no lock needed for this */
|
||||
@ -36,10 +37,10 @@ static ssize_t led_brightness_show(struct class_device *dev, char *buf)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static ssize_t led_brightness_store(struct class_device *dev,
|
||||
const char *buf, size_t size)
|
||||
static ssize_t led_brightness_store(struct device *dev,
|
||||
struct device_attribute *attr, const char *buf, size_t size)
|
||||
{
|
||||
struct led_classdev *led_cdev = class_get_devdata(dev);
|
||||
struct led_classdev *led_cdev = dev_get_drvdata(dev);
|
||||
ssize_t ret = -EINVAL;
|
||||
char *after;
|
||||
unsigned long state = simple_strtoul(buf, &after, 10);
|
||||
@ -56,10 +57,9 @@ static ssize_t led_brightness_store(struct class_device *dev,
|
||||
return ret;
|
||||
}
|
||||
|
||||
static CLASS_DEVICE_ATTR(brightness, 0644, led_brightness_show,
|
||||
led_brightness_store);
|
||||
static DEVICE_ATTR(brightness, 0644, led_brightness_show, led_brightness_store);
|
||||
#ifdef CONFIG_LEDS_TRIGGERS
|
||||
static CLASS_DEVICE_ATTR(trigger, 0644, led_trigger_show, led_trigger_store);
|
||||
static DEVICE_ATTR(trigger, 0644, led_trigger_show, led_trigger_store);
|
||||
#endif
|
||||
|
||||
/**
|
||||
@ -93,16 +93,15 @@ int led_classdev_register(struct device *parent, struct led_classdev *led_cdev)
|
||||
{
|
||||
int rc;
|
||||
|
||||
led_cdev->class_dev = class_device_create(leds_class, NULL, 0,
|
||||
parent, "%s", led_cdev->name);
|
||||
if (unlikely(IS_ERR(led_cdev->class_dev)))
|
||||
return PTR_ERR(led_cdev->class_dev);
|
||||
led_cdev->dev = device_create(leds_class, parent, 0, "%s",
|
||||
led_cdev->name);
|
||||
if (unlikely(IS_ERR(led_cdev->dev)))
|
||||
return PTR_ERR(led_cdev->dev);
|
||||
|
||||
class_set_devdata(led_cdev->class_dev, led_cdev);
|
||||
dev_set_drvdata(led_cdev->dev, led_cdev);
|
||||
|
||||
/* register the attributes */
|
||||
rc = class_device_create_file(led_cdev->class_dev,
|
||||
&class_device_attr_brightness);
|
||||
rc = device_create_file(led_cdev->dev, &dev_attr_brightness);
|
||||
if (rc)
|
||||
goto err_out;
|
||||
|
||||
@ -114,8 +113,7 @@ int led_classdev_register(struct device *parent, struct led_classdev *led_cdev)
|
||||
#ifdef CONFIG_LEDS_TRIGGERS
|
||||
rwlock_init(&led_cdev->trigger_lock);
|
||||
|
||||
rc = class_device_create_file(led_cdev->class_dev,
|
||||
&class_device_attr_trigger);
|
||||
rc = device_create_file(led_cdev->dev, &dev_attr_trigger);
|
||||
if (rc)
|
||||
goto err_out_led_list;
|
||||
|
||||
@ -123,18 +121,17 @@ int led_classdev_register(struct device *parent, struct led_classdev *led_cdev)
|
||||
#endif
|
||||
|
||||
printk(KERN_INFO "Registered led device: %s\n",
|
||||
led_cdev->class_dev->class_id);
|
||||
led_cdev->name);
|
||||
|
||||
return 0;
|
||||
|
||||
#ifdef CONFIG_LEDS_TRIGGERS
|
||||
err_out_led_list:
|
||||
class_device_remove_file(led_cdev->class_dev,
|
||||
&class_device_attr_brightness);
|
||||
device_remove_file(led_cdev->dev, &dev_attr_brightness);
|
||||
list_del(&led_cdev->node);
|
||||
#endif
|
||||
err_out:
|
||||
class_device_unregister(led_cdev->class_dev);
|
||||
device_unregister(led_cdev->dev);
|
||||
return rc;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(led_classdev_register);
|
||||
@ -147,18 +144,16 @@ EXPORT_SYMBOL_GPL(led_classdev_register);
|
||||
*/
|
||||
void led_classdev_unregister(struct led_classdev *led_cdev)
|
||||
{
|
||||
class_device_remove_file(led_cdev->class_dev,
|
||||
&class_device_attr_brightness);
|
||||
device_remove_file(led_cdev->dev, &dev_attr_brightness);
|
||||
#ifdef CONFIG_LEDS_TRIGGERS
|
||||
class_device_remove_file(led_cdev->class_dev,
|
||||
&class_device_attr_trigger);
|
||||
device_remove_file(led_cdev->dev, &dev_attr_trigger);
|
||||
write_lock(&led_cdev->trigger_lock);
|
||||
if (led_cdev->trigger)
|
||||
led_trigger_set(led_cdev, NULL);
|
||||
write_unlock(&led_cdev->trigger_lock);
|
||||
#endif
|
||||
|
||||
class_device_unregister(led_cdev->class_dev);
|
||||
device_unregister(led_cdev->dev);
|
||||
|
||||
write_lock(&leds_list_lock);
|
||||
list_del(&led_cdev->node);
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* LED Triggers Core
|
||||
*
|
||||
* Copyright 2005-2006 Openedhand Ltd.
|
||||
* Copyright 2005-2007 Openedhand Ltd.
|
||||
*
|
||||
* Author: Richard Purdie <rpurdie@openedhand.com>
|
||||
*
|
||||
@ -28,10 +28,10 @@
|
||||
static DEFINE_RWLOCK(triggers_list_lock);
|
||||
static LIST_HEAD(trigger_list);
|
||||
|
||||
ssize_t led_trigger_store(struct class_device *dev, const char *buf,
|
||||
size_t count)
|
||||
ssize_t led_trigger_store(struct device *dev, struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct led_classdev *led_cdev = class_get_devdata(dev);
|
||||
struct led_classdev *led_cdev = dev_get_drvdata(dev);
|
||||
char trigger_name[TRIG_NAME_MAX];
|
||||
struct led_trigger *trig;
|
||||
size_t len;
|
||||
@ -67,9 +67,10 @@ ssize_t led_trigger_store(struct class_device *dev, const char *buf,
|
||||
}
|
||||
|
||||
|
||||
ssize_t led_trigger_show(struct class_device *dev, char *buf)
|
||||
ssize_t led_trigger_show(struct device *dev, struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct led_classdev *led_cdev = class_get_devdata(dev);
|
||||
struct led_classdev *led_cdev = dev_get_drvdata(dev);
|
||||
struct led_trigger *trig;
|
||||
int len = 0;
|
||||
|
||||
@ -183,13 +184,20 @@ int led_trigger_register(struct led_trigger *trigger)
|
||||
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;
|
||||
led_trigger_register(trigger);
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
@ -215,7 +223,8 @@ void led_trigger_unregister(struct led_trigger *trigger)
|
||||
|
||||
void led_trigger_unregister_simple(struct led_trigger *trigger)
|
||||
{
|
||||
led_trigger_unregister(trigger);
|
||||
if (trigger)
|
||||
led_trigger_unregister(trigger);
|
||||
kfree(trigger);
|
||||
}
|
||||
|
||||
|
199
drivers/leds/leds-gpio.c
Normal file
199
drivers/leds/leds-gpio.c
Normal file
@ -0,0 +1,199 @@
|
||||
/*
|
||||
* LEDs driver for GPIOs
|
||||
*
|
||||
* Copyright (C) 2007 8D Technologies inc.
|
||||
* Raphael Assenat <raph@8d.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 <linux/workqueue.h>
|
||||
|
||||
#include <asm/gpio.h>
|
||||
|
||||
struct gpio_led_data {
|
||||
struct led_classdev cdev;
|
||||
unsigned gpio;
|
||||
struct work_struct work;
|
||||
u8 new_level;
|
||||
u8 can_sleep;
|
||||
u8 active_low;
|
||||
};
|
||||
|
||||
static void gpio_led_work(struct work_struct *work)
|
||||
{
|
||||
struct gpio_led_data *led_dat =
|
||||
container_of(work, struct gpio_led_data, work);
|
||||
|
||||
gpio_set_value_cansleep(led_dat->gpio, led_dat->new_level);
|
||||
}
|
||||
|
||||
static void gpio_led_set(struct led_classdev *led_cdev,
|
||||
enum led_brightness value)
|
||||
{
|
||||
struct gpio_led_data *led_dat =
|
||||
container_of(led_cdev, struct gpio_led_data, cdev);
|
||||
int level;
|
||||
|
||||
if (value == LED_OFF)
|
||||
level = 0;
|
||||
else
|
||||
level = 1;
|
||||
|
||||
if (led_dat->active_low)
|
||||
level = !level;
|
||||
|
||||
/* setting GPIOs with I2C/etc requires a preemptible task context */
|
||||
if (led_dat->can_sleep) {
|
||||
if (preempt_count()) {
|
||||
led_dat->new_level = level;
|
||||
schedule_work(&led_dat->work);
|
||||
} else
|
||||
gpio_set_value_cansleep(led_dat->gpio, level);
|
||||
} else
|
||||
gpio_set_value(led_dat->gpio, level);
|
||||
}
|
||||
|
||||
static int __init gpio_led_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct gpio_led_platform_data *pdata = pdev->dev.platform_data;
|
||||
struct gpio_led *cur_led;
|
||||
struct gpio_led_data *leds_data, *led_dat;
|
||||
int i, ret = 0;
|
||||
|
||||
if (!pdata)
|
||||
return -EBUSY;
|
||||
|
||||
leds_data = kzalloc(sizeof(struct gpio_led_data) * pdata->num_leds,
|
||||
GFP_KERNEL);
|
||||
if (!leds_data)
|
||||
return -ENOMEM;
|
||||
|
||||
for (i = 0; i < pdata->num_leds; i++) {
|
||||
cur_led = &pdata->leds[i];
|
||||
led_dat = &leds_data[i];
|
||||
|
||||
led_dat->cdev.name = cur_led->name;
|
||||
led_dat->cdev.default_trigger = cur_led->default_trigger;
|
||||
led_dat->gpio = cur_led->gpio;
|
||||
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;
|
||||
|
||||
ret = gpio_request(led_dat->gpio, led_dat->cdev.name);
|
||||
if (ret < 0)
|
||||
goto err;
|
||||
|
||||
gpio_direction_output(led_dat->gpio, led_dat->active_low);
|
||||
|
||||
ret = led_classdev_register(&pdev->dev, &led_dat->cdev);
|
||||
if (ret < 0) {
|
||||
gpio_free(led_dat->gpio);
|
||||
goto err;
|
||||
}
|
||||
|
||||
INIT_WORK(&led_dat->work, gpio_led_work);
|
||||
}
|
||||
|
||||
platform_set_drvdata(pdev, leds_data);
|
||||
|
||||
return 0;
|
||||
|
||||
err:
|
||||
if (i > 0) {
|
||||
for (i = i - 1; i >= 0; i--) {
|
||||
led_classdev_unregister(&leds_data[i].cdev);
|
||||
gpio_free(leds_data[i].gpio);
|
||||
}
|
||||
}
|
||||
|
||||
flush_scheduled_work();
|
||||
kfree(leds_data);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int __exit gpio_led_remove(struct platform_device *pdev)
|
||||
{
|
||||
int i;
|
||||
struct gpio_led_platform_data *pdata = pdev->dev.platform_data;
|
||||
struct gpio_led_data *leds_data;
|
||||
|
||||
leds_data = platform_get_drvdata(pdev);
|
||||
|
||||
for (i = 0; i < pdata->num_leds; i++) {
|
||||
led_classdev_unregister(&leds_data[i].cdev);
|
||||
gpio_free(leds_data[i].gpio);
|
||||
}
|
||||
|
||||
kfree(leds_data);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
static int gpio_led_suspend(struct platform_device *pdev, pm_message_t state)
|
||||
{
|
||||
struct gpio_led_platform_data *pdata = pdev->dev.platform_data;
|
||||
struct gpio_led_data *leds_data;
|
||||
int i;
|
||||
|
||||
leds_data = platform_get_drvdata(pdev);
|
||||
|
||||
for (i = 0; i < pdata->num_leds; i++)
|
||||
led_classdev_suspend(&leds_data[i].cdev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int gpio_led_resume(struct platform_device *pdev)
|
||||
{
|
||||
struct gpio_led_platform_data *pdata = pdev->dev.platform_data;
|
||||
struct gpio_led_data *leds_data;
|
||||
int i;
|
||||
|
||||
leds_data = platform_get_drvdata(pdev);
|
||||
|
||||
for (i = 0; i < pdata->num_leds; i++)
|
||||
led_classdev_resume(&leds_data[i].cdev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
#define gpio_led_suspend NULL
|
||||
#define gpio_led_resume NULL
|
||||
#endif
|
||||
|
||||
static struct platform_driver gpio_led_driver = {
|
||||
.remove = __exit_p(gpio_led_remove),
|
||||
.suspend = gpio_led_suspend,
|
||||
.resume = gpio_led_resume,
|
||||
.driver = {
|
||||
.name = "leds-gpio",
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
};
|
||||
|
||||
static int __init gpio_led_init(void)
|
||||
{
|
||||
return platform_driver_probe(&gpio_led_driver, gpio_led_probe);
|
||||
}
|
||||
|
||||
static void __exit gpio_led_exit(void)
|
||||
{
|
||||
platform_driver_unregister(&gpio_led_driver);
|
||||
}
|
||||
|
||||
module_init(gpio_led_init);
|
||||
module_exit(gpio_led_exit);
|
||||
|
||||
MODULE_AUTHOR("Raphael Assenat <raph@8d.com>");
|
||||
MODULE_DESCRIPTION("GPIO LED driver");
|
||||
MODULE_LICENSE("GPL");
|
@ -19,7 +19,7 @@
|
||||
static void locomoled_brightness_set(struct led_classdev *led_cdev,
|
||||
enum led_brightness value, int offset)
|
||||
{
|
||||
struct locomo_dev *locomo_dev = LOCOMO_DEV(led_cdev->class_dev->dev);
|
||||
struct locomo_dev *locomo_dev = LOCOMO_DEV(led_cdev->dev);
|
||||
unsigned long flags;
|
||||
|
||||
local_irq_save(flags);
|
||||
|
@ -13,6 +13,7 @@
|
||||
#ifndef __LEDS_H_INCLUDED
|
||||
#define __LEDS_H_INCLUDED
|
||||
|
||||
#include <linux/device.h>
|
||||
#include <linux/leds.h>
|
||||
|
||||
static inline void led_set_brightness(struct led_classdev *led_cdev,
|
||||
@ -37,8 +38,9 @@ void led_trigger_set(struct led_classdev *led_cdev,
|
||||
#define led_trigger_set(x, y) do {} while(0)
|
||||
#endif
|
||||
|
||||
ssize_t led_trigger_store(struct class_device *dev, const char *buf,
|
||||
size_t count);
|
||||
ssize_t led_trigger_show(struct class_device *dev, char *buf);
|
||||
ssize_t led_trigger_store(struct device *dev, struct device_attribute *attr,
|
||||
const char *buf, size_t count);
|
||||
ssize_t led_trigger_show(struct device *dev, struct device_attribute *attr,
|
||||
char *buf);
|
||||
|
||||
#endif /* __LEDS_H_INCLUDED */
|
||||
|
@ -52,9 +52,10 @@ static void led_timer_function(unsigned long data)
|
||||
mod_timer(&timer_data->timer, jiffies + msecs_to_jiffies(delay));
|
||||
}
|
||||
|
||||
static ssize_t led_delay_on_show(struct class_device *dev, char *buf)
|
||||
static ssize_t led_delay_on_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct led_classdev *led_cdev = class_get_devdata(dev);
|
||||
struct led_classdev *led_cdev = dev_get_drvdata(dev);
|
||||
struct timer_trig_data *timer_data = led_cdev->trigger_data;
|
||||
|
||||
sprintf(buf, "%lu\n", timer_data->delay_on);
|
||||
@ -62,10 +63,10 @@ static ssize_t led_delay_on_show(struct class_device *dev, char *buf)
|
||||
return strlen(buf) + 1;
|
||||
}
|
||||
|
||||
static ssize_t led_delay_on_store(struct class_device *dev, const char *buf,
|
||||
size_t size)
|
||||
static ssize_t led_delay_on_store(struct device *dev,
|
||||
struct device_attribute *attr, const char *buf, size_t size)
|
||||
{
|
||||
struct led_classdev *led_cdev = class_get_devdata(dev);
|
||||
struct led_classdev *led_cdev = dev_get_drvdata(dev);
|
||||
struct timer_trig_data *timer_data = led_cdev->trigger_data;
|
||||
int ret = -EINVAL;
|
||||
char *after;
|
||||
@ -84,9 +85,10 @@ static ssize_t led_delay_on_store(struct class_device *dev, const char *buf,
|
||||
return ret;
|
||||
}
|
||||
|
||||
static ssize_t led_delay_off_show(struct class_device *dev, char *buf)
|
||||
static ssize_t led_delay_off_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct led_classdev *led_cdev = class_get_devdata(dev);
|
||||
struct led_classdev *led_cdev = dev_get_drvdata(dev);
|
||||
struct timer_trig_data *timer_data = led_cdev->trigger_data;
|
||||
|
||||
sprintf(buf, "%lu\n", timer_data->delay_off);
|
||||
@ -94,10 +96,10 @@ static ssize_t led_delay_off_show(struct class_device *dev, char *buf)
|
||||
return strlen(buf) + 1;
|
||||
}
|
||||
|
||||
static ssize_t led_delay_off_store(struct class_device *dev, const char *buf,
|
||||
size_t size)
|
||||
static ssize_t led_delay_off_store(struct device *dev,
|
||||
struct device_attribute *attr, const char *buf, size_t size)
|
||||
{
|
||||
struct led_classdev *led_cdev = class_get_devdata(dev);
|
||||
struct led_classdev *led_cdev = dev_get_drvdata(dev);
|
||||
struct timer_trig_data *timer_data = led_cdev->trigger_data;
|
||||
int ret = -EINVAL;
|
||||
char *after;
|
||||
@ -116,10 +118,8 @@ static ssize_t led_delay_off_store(struct class_device *dev, const char *buf,
|
||||
return ret;
|
||||
}
|
||||
|
||||
static CLASS_DEVICE_ATTR(delay_on, 0644, led_delay_on_show,
|
||||
led_delay_on_store);
|
||||
static CLASS_DEVICE_ATTR(delay_off, 0644, led_delay_off_show,
|
||||
led_delay_off_store);
|
||||
static DEVICE_ATTR(delay_on, 0644, led_delay_on_show, led_delay_on_store);
|
||||
static DEVICE_ATTR(delay_off, 0644, led_delay_off_show, led_delay_off_store);
|
||||
|
||||
static void timer_trig_activate(struct led_classdev *led_cdev)
|
||||
{
|
||||
@ -136,18 +136,17 @@ static void timer_trig_activate(struct led_classdev *led_cdev)
|
||||
timer_data->timer.function = led_timer_function;
|
||||
timer_data->timer.data = (unsigned long) led_cdev;
|
||||
|
||||
rc = class_device_create_file(led_cdev->class_dev,
|
||||
&class_device_attr_delay_on);
|
||||
if (rc) goto err_out;
|
||||
rc = class_device_create_file(led_cdev->class_dev,
|
||||
&class_device_attr_delay_off);
|
||||
if (rc) goto err_out_delayon;
|
||||
rc = device_create_file(led_cdev->dev, &dev_attr_delay_on);
|
||||
if (rc)
|
||||
goto err_out;
|
||||
rc = device_create_file(led_cdev->dev, &dev_attr_delay_off);
|
||||
if (rc)
|
||||
goto err_out_delayon;
|
||||
|
||||
return;
|
||||
|
||||
err_out_delayon:
|
||||
class_device_remove_file(led_cdev->class_dev,
|
||||
&class_device_attr_delay_on);
|
||||
device_remove_file(led_cdev->dev, &dev_attr_delay_on);
|
||||
err_out:
|
||||
led_cdev->trigger_data = NULL;
|
||||
kfree(timer_data);
|
||||
@ -158,10 +157,8 @@ static void timer_trig_deactivate(struct led_classdev *led_cdev)
|
||||
struct timer_trig_data *timer_data = led_cdev->trigger_data;
|
||||
|
||||
if (timer_data) {
|
||||
class_device_remove_file(led_cdev->class_dev,
|
||||
&class_device_attr_delay_on);
|
||||
class_device_remove_file(led_cdev->class_dev,
|
||||
&class_device_attr_delay_off);
|
||||
device_remove_file(led_cdev->dev, &dev_attr_delay_on);
|
||||
device_remove_file(led_cdev->dev, &dev_attr_delay_off);
|
||||
del_timer_sync(&timer_data->timer);
|
||||
kfree(timer_data);
|
||||
}
|
||||
|
@ -15,7 +15,6 @@
|
||||
#include <linux/list.h>
|
||||
|
||||
struct device;
|
||||
struct class_device;
|
||||
/*
|
||||
* LED Core
|
||||
*/
|
||||
@ -37,7 +36,7 @@ struct led_classdev {
|
||||
void (*brightness_set)(struct led_classdev *led_cdev,
|
||||
enum led_brightness brightness);
|
||||
|
||||
struct class_device *class_dev;
|
||||
struct device *dev;
|
||||
struct list_head node; /* LED Device list */
|
||||
char *default_trigger; /* Trigger to use */
|
||||
|
||||
@ -109,4 +108,18 @@ extern void ledtrig_ide_activity(void);
|
||||
#define ledtrig_ide_activity() do {} while(0)
|
||||
#endif
|
||||
|
||||
/* For the leds-gpio driver */
|
||||
struct gpio_led {
|
||||
const char *name;
|
||||
char *default_trigger;
|
||||
unsigned gpio;
|
||||
u8 active_low;
|
||||
};
|
||||
|
||||
struct gpio_led_platform_data {
|
||||
int num_leds;
|
||||
struct gpio_led *leds;
|
||||
};
|
||||
|
||||
|
||||
#endif /* __LINUX_LEDS_H_INCLUDED */
|
||||
|
Loading…
Reference in New Issue
Block a user