brintos

brintos / linux-shallow public Read only

0
0
Text · 4.7 KiB · bee3bd4 Raw
201 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * One-shot LED Trigger4 *5 * Copyright 2012, Fabio Baltieri <fabio.baltieri@gmail.com>6 *7 * Based on ledtrig-timer.c by Richard Purdie <rpurdie@openedhand.com>8 */9 10#include <linux/module.h>11#include <linux/kernel.h>12#include <linux/init.h>13#include <linux/device.h>14#include <linux/ctype.h>15#include <linux/slab.h>16#include <linux/leds.h>17#include "../leds.h"18 19#define DEFAULT_DELAY 10020 21struct oneshot_trig_data {22	unsigned int invert;23};24 25static ssize_t led_shot(struct device *dev,26		struct device_attribute *attr, const char *buf, size_t size)27{28	struct led_classdev *led_cdev = led_trigger_get_led(dev);29	struct oneshot_trig_data *oneshot_data = led_trigger_get_drvdata(dev);30 31	led_blink_set_oneshot(led_cdev,32			&led_cdev->blink_delay_on, &led_cdev->blink_delay_off,33			oneshot_data->invert);34 35	/* content is ignored */36	return size;37}38static ssize_t led_invert_show(struct device *dev,39		struct device_attribute *attr, char *buf)40{41	struct oneshot_trig_data *oneshot_data = led_trigger_get_drvdata(dev);42 43	return sprintf(buf, "%u\n", oneshot_data->invert);44}45 46static ssize_t led_invert_store(struct device *dev,47		struct device_attribute *attr, const char *buf, size_t size)48{49	struct led_classdev *led_cdev = led_trigger_get_led(dev);50	struct oneshot_trig_data *oneshot_data = led_trigger_get_drvdata(dev);51	unsigned long state;52	int ret;53 54	ret = kstrtoul(buf, 0, &state);55	if (ret)56		return ret;57 58	oneshot_data->invert = !!state;59 60	if (oneshot_data->invert)61		led_set_brightness_nosleep(led_cdev, LED_FULL);62	else63		led_set_brightness_nosleep(led_cdev, LED_OFF);64 65	return size;66}67 68static ssize_t led_delay_on_show(struct device *dev,69		struct device_attribute *attr, char *buf)70{71	struct led_classdev *led_cdev = led_trigger_get_led(dev);72 73	return sprintf(buf, "%lu\n", led_cdev->blink_delay_on);74}75 76static ssize_t led_delay_on_store(struct device *dev,77		struct device_attribute *attr, const char *buf, size_t size)78{79	struct led_classdev *led_cdev = led_trigger_get_led(dev);80	unsigned long state;81	int ret;82 83	ret = kstrtoul(buf, 0, &state);84	if (ret)85		return ret;86 87	led_cdev->blink_delay_on = state;88 89	return size;90}91 92static ssize_t led_delay_off_show(struct device *dev,93		struct device_attribute *attr, char *buf)94{95	struct led_classdev *led_cdev = led_trigger_get_led(dev);96 97	return sprintf(buf, "%lu\n", led_cdev->blink_delay_off);98}99 100static ssize_t led_delay_off_store(struct device *dev,101		struct device_attribute *attr, const char *buf, size_t size)102{103	struct led_classdev *led_cdev = led_trigger_get_led(dev);104	unsigned long state;105	int ret;106 107	ret = kstrtoul(buf, 0, &state);108	if (ret)109		return ret;110 111	led_cdev->blink_delay_off = state;112 113	return size;114}115 116static DEVICE_ATTR(delay_on, 0644, led_delay_on_show, led_delay_on_store);117static DEVICE_ATTR(delay_off, 0644, led_delay_off_show, led_delay_off_store);118static DEVICE_ATTR(invert, 0644, led_invert_show, led_invert_store);119static DEVICE_ATTR(shot, 0200, NULL, led_shot);120 121static struct attribute *oneshot_trig_attrs[] = {122	&dev_attr_delay_on.attr,123	&dev_attr_delay_off.attr,124	&dev_attr_invert.attr,125	&dev_attr_shot.attr,126	NULL127};128ATTRIBUTE_GROUPS(oneshot_trig);129 130static void pattern_init(struct led_classdev *led_cdev)131{132	u32 *pattern;133	unsigned int size = 0;134 135	pattern = led_get_default_pattern(led_cdev, &size);136	if (!pattern)137		goto out_default;138 139	if (size != 2) {140		dev_warn(led_cdev->dev,141			 "Expected 2 but got %u values for delays pattern\n",142			 size);143		goto out_default;144	}145 146	led_cdev->blink_delay_on = pattern[0];147	led_cdev->blink_delay_off = pattern[1];148	kfree(pattern);149 150	return;151 152out_default:153	kfree(pattern);154	led_cdev->blink_delay_on = DEFAULT_DELAY;155	led_cdev->blink_delay_off = DEFAULT_DELAY;156}157 158static int oneshot_trig_activate(struct led_classdev *led_cdev)159{160	struct oneshot_trig_data *oneshot_data;161 162	oneshot_data = kzalloc(sizeof(*oneshot_data), GFP_KERNEL);163	if (!oneshot_data)164		return -ENOMEM;165 166	led_set_trigger_data(led_cdev, oneshot_data);167 168	if (led_cdev->flags & LED_INIT_DEFAULT_TRIGGER) {169		pattern_init(led_cdev);170		/*171		 * Mark as initialized even on pattern_init() error because172		 * any consecutive call to it would produce the same error.173		 */174		led_cdev->flags &= ~LED_INIT_DEFAULT_TRIGGER;175	}176 177	return 0;178}179 180static void oneshot_trig_deactivate(struct led_classdev *led_cdev)181{182	struct oneshot_trig_data *oneshot_data = led_get_trigger_data(led_cdev);183 184	kfree(oneshot_data);185 186	/* Stop blinking */187	led_set_brightness(led_cdev, LED_OFF);188}189 190static struct led_trigger oneshot_led_trigger = {191	.name     = "oneshot",192	.activate = oneshot_trig_activate,193	.deactivate = oneshot_trig_deactivate,194	.groups = oneshot_trig_groups,195};196module_led_trigger(oneshot_led_trigger);197 198MODULE_AUTHOR("Fabio Baltieri <fabio.baltieri@gmail.com>");199MODULE_DESCRIPTION("One-shot LED trigger");200MODULE_LICENSE("GPL v2");201