From: Charlie Paul <cpaul.windri...@gmail.com> Driver changes to the leds to support the AXXIA 5500 board.
Signed-off-by: Charlie Paul <cpaul.windri...@gmail.com> --- drivers/leds/ledtrig-rbs.c | 248 +++++++++++++++++++++++++++++++++++++++++ drivers/leds/trigger/Kconfig | 7 ++ drivers/leds/trigger/Makefile | 1 + 3 files changed, 256 insertions(+) create mode 100644 drivers/leds/ledtrig-rbs.c diff --git a/drivers/leds/ledtrig-rbs.c b/drivers/leds/ledtrig-rbs.c new file mode 100644 index 0000000..1ce9615 --- /dev/null +++ b/drivers/leds/ledtrig-rbs.c @@ -0,0 +1,248 @@ +/* + * LED RBS Trigger + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + */ + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/device.h> +#include <linux/ctype.h> +#include <linux/leds.h> +#include <linux/timer.h> +#include <linux/slab.h> + +#define RBS_LED_MAXPHASES 6 + +struct rbs_led_phase { + int led; + int delay; /* us */ +}; + +struct rbs_led_mode { + char *name; + int nphases; + struct rbs_led_phase phases[RBS_LED_MAXPHASES]; +}; + +struct rbs_led { + struct timer_list delay_timer; + struct mutex mode_lock; + int cphase; + struct rbs_led_mode *mode; +}; + +/* RBS LED modes */ +static struct rbs_led_mode mode_steady_on = { + .name = "on", + .nphases = 1, + .phases = { + {1, -1 /* infinitive */} + }, +}; + +static struct rbs_led_mode mode_steady_off = { + .name = "off", + .nphases = 1, + .phases = { + {0, -1 /* infinitive */} + }, +}; + +static struct rbs_led_mode mode_slow_blink = { + .name = "slow", + .nphases = 2, + .phases = { + {0, 1000000}, + {1, 1000000} + }, +}; + +static struct rbs_led_mode mode_fast_blink = { + .name = "fast", + .nphases = 2, + .phases = { + {0, 31250}, + {1, 31250} + }, +}; + +static struct rbs_led_mode mode_double_flash_on = { + .name = "double-on", + .nphases = 6, + .phases = { + {0, 300000}, + {1, 350000}, + {0, 300000}, + {1, 350000}, + {0, 300000}, + {1, 2400000}, + }, +}; + +static struct rbs_led_mode mode_double_flash_off = { + .name = "double-off", + .nphases = 6, + .phases = { + {0, 300000}, + {1, 350000}, + {0, 300000}, + {1, 350000}, + {0, 300000}, + {0, 2400000}, + }, +}; +static struct rbs_led_mode *rbs_led_modes[] = { + &mode_steady_on, + &mode_steady_off, + &mode_slow_blink, + &mode_fast_blink, + &mode_double_flash_on, + &mode_double_flash_off, + NULL +}; + +static void rbs_led_timer(unsigned long data) +{ + struct led_classdev *led_cdev = (void *)data; + struct rbs_led *led = led_cdev->trigger_data; + int delay; + + /* toggle led */ + if (led->mode->phases[led->cphase].led) + led_brightness_set(led_cdev, LED_FULL); + else + led_brightness_set(led_cdev, LED_OFF); + + delay = led->mode->phases[led->cphase].delay; + + if (++led->cphase >= led->mode->nphases) + led->cphase = 0; + + if (delay != -1) + mod_timer(&led->delay_timer, + jiffies + usecs_to_jiffies(delay)); +} + +static ssize_t led_mode_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct led_classdev *led_cdev = dev_get_drvdata(dev); + struct rbs_led *led = led_cdev->trigger_data; + + return sprintf(buf, "%s\n", led->mode->name); +} + +static ssize_t led_mode_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t size) +{ + struct led_classdev *led_cdev = dev_get_drvdata(dev); + struct rbs_led *led = led_cdev->trigger_data; + int i; + + if (!led) + return -EINVAL; + + for (i = 0; rbs_led_modes[i]; i++) { + if (!strncmp(rbs_led_modes[i]->name, buf, + strlen(rbs_led_modes[i]->name))) + break; + } + if (!rbs_led_modes[i]) + return -EINVAL; + + mutex_lock(&led->mode_lock); + + /* replace led mode */ + del_timer_sync(&led->delay_timer); + led_brightness_set(led_cdev, LED_OFF); + + led->cphase = 0; + led->mode = rbs_led_modes[i]; + + mod_timer(&led->delay_timer, jiffies + 1); + + mutex_unlock(&led->mode_lock); + + return size; +} + +static DEVICE_ATTR(mode, 0644, led_mode_show, led_mode_store); + +static void rbs_trig_activate(struct led_classdev *led_cdev) +{ + int ret; + struct rbs_led *led; + + led_cdev->trigger_data = NULL; + + led = kzalloc(sizeof(*led), GFP_KERNEL); + if (led == NULL) + return; + + mutex_init(&led->mode_lock); + + /* default mode - steady off */ + led->mode = &mode_steady_off; + + init_timer(&led->delay_timer); + led->delay_timer.function = rbs_led_timer; + led->delay_timer.data = (unsigned long) led_cdev; + + ret = device_create_file(led_cdev->dev, &dev_attr_mode); + if (ret) + goto fail; + + led_cdev->trigger_data = led; + + return; + +fail: + kfree(led); +} + +static void rbs_trig_deactivate(struct led_classdev *led_cdev) +{ + struct rbs_led *led = led_cdev->trigger_data; + + if (led) { + device_remove_file(led_cdev->dev, &dev_attr_mode); + del_timer_sync(&led->delay_timer); + kfree(led); + led_cdev->trigger_data = NULL; + } + + led_brightness_set(led_cdev, LED_OFF); +} + +static struct led_trigger rbs_led_trigger = { + .name = "rbs", + .activate = rbs_trig_activate, + .deactivate = rbs_trig_deactivate, +}; + +static int __init rbs_led_trig_init(void) +{ + return led_trigger_register(&rbs_led_trigger); +} + +static void __exit rbs_led_trig_exit(void) +{ + led_trigger_unregister(&rbs_led_trigger); +} + +module_init(rbs_led_trig_init); +module_exit(rbs_led_trig_exit); + +MODULE_AUTHOR("Andrey Panteleev <andrey.xx.pantel...@ericsson.com"); +MODULE_DESCRIPTION("RBS LED trigger"); +MODULE_LICENSE("GPL"); diff --git a/drivers/leds/trigger/Kconfig b/drivers/leds/trigger/Kconfig index 49794b4..259acf5 100644 --- a/drivers/leds/trigger/Kconfig +++ b/drivers/leds/trigger/Kconfig @@ -108,4 +108,11 @@ config LEDS_TRIGGER_CAMERA This enables direct flash/torch on/off by the driver, kernel space. If unsure, say Y. +config LEDS_TRIGGER_RBS + tristate "LED RBS Trigger" + depends on LEDS_TRIGGERS + help + This allows LEDs to be controlled in RBS fashion. + If unsure, say Y. + endif # LEDS_TRIGGERS diff --git a/drivers/leds/trigger/Makefile b/drivers/leds/trigger/Makefile index 1abf48d..3af243a 100644 --- a/drivers/leds/trigger/Makefile +++ b/drivers/leds/trigger/Makefile @@ -8,3 +8,4 @@ obj-$(CONFIG_LEDS_TRIGGER_CPU) += ledtrig-cpu.o obj-$(CONFIG_LEDS_TRIGGER_DEFAULT_ON) += ledtrig-default-on.o obj-$(CONFIG_LEDS_TRIGGER_TRANSIENT) += ledtrig-transient.o obj-$(CONFIG_LEDS_TRIGGER_CAMERA) += ledtrig-camera.o +obj-$(CONFIG_LEDS_TRIGGER_RBS) += ledtrig-rbs.o -- 1.7.9.5 -- _______________________________________________ linux-yocto mailing list linux-yocto@yoctoproject.org https://lists.yoctoproject.org/listinfo/linux-yocto