linux/drivers/leds/trigger/ledtrig-oneshot.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * One-shot LED Trigger
   4 *
   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 100
  20
  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        else
  63                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        NULL
 127};
 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 because
 172                 * 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