2019-06-04 11:11:33 +03:00
// SPDX-License-Identifier: GPL-2.0-only
2012-06-07 02:11:05 +04:00
/*
* One - shot LED Trigger
*
* Copyright 2012 , Fabio Baltieri < fabio . baltieri @ gmail . com >
*
* Based on ledtrig - timer . c by Richard Purdie < rpurdie @ openedhand . com >
*/
# include <linux/module.h>
# include <linux/kernel.h>
# include <linux/init.h>
# include <linux/device.h>
# include <linux/ctype.h>
# include <linux/slab.h>
# include <linux/leds.h>
2013-02-20 12:36:01 +04:00
# include "../leds.h"
2012-06-07 02:11:05 +04:00
# define DEFAULT_DELAY 100
struct oneshot_trig_data {
unsigned int invert ;
} ;
static ssize_t led_shot ( struct device * dev ,
struct device_attribute * attr , const char * buf , size_t size )
{
2018-07-02 23:05:29 +03:00
struct led_classdev * led_cdev = led_trigger_get_led ( dev ) ;
struct oneshot_trig_data * oneshot_data = led_trigger_get_drvdata ( dev ) ;
2012-06-07 02:11:05 +04:00
led_blink_set_oneshot ( led_cdev ,
& led_cdev - > blink_delay_on , & led_cdev - > blink_delay_off ,
oneshot_data - > invert ) ;
/* content is ignored */
return size ;
}
static ssize_t led_invert_show ( struct device * dev ,
struct device_attribute * attr , char * buf )
{
2018-07-02 23:05:29 +03:00
struct oneshot_trig_data * oneshot_data = led_trigger_get_drvdata ( dev ) ;
2012-06-07 02:11:05 +04:00
return sprintf ( buf , " %u \n " , oneshot_data - > invert ) ;
}
static ssize_t led_invert_store ( struct device * dev ,
struct device_attribute * attr , const char * buf , size_t size )
{
2018-07-02 23:05:29 +03:00
struct led_classdev * led_cdev = led_trigger_get_led ( dev ) ;
struct oneshot_trig_data * oneshot_data = led_trigger_get_drvdata ( dev ) ;
2012-06-07 02:11:05 +04:00
unsigned long state ;
int ret ;
ret = kstrtoul ( buf , 0 , & state ) ;
if ( ret )
return ret ;
oneshot_data - > invert = ! ! state ;
if ( oneshot_data - > invert )
2015-10-07 12:10:41 +03:00
led_set_brightness_nosleep ( led_cdev , LED_FULL ) ;
2012-06-07 02:11:05 +04:00
else
2015-10-07 12:10:41 +03:00
led_set_brightness_nosleep ( led_cdev , LED_OFF ) ;
2012-06-07 02:11:05 +04:00
return size ;
}
static ssize_t led_delay_on_show ( struct device * dev ,
struct device_attribute * attr , char * buf )
{
2018-07-02 23:05:29 +03:00
struct led_classdev * led_cdev = led_trigger_get_led ( dev ) ;
2012-06-07 02:11:05 +04:00
return sprintf ( buf , " %lu \n " , led_cdev - > blink_delay_on ) ;
}
static ssize_t led_delay_on_store ( struct device * dev ,
struct device_attribute * attr , const char * buf , size_t size )
{
2018-07-02 23:05:29 +03:00
struct led_classdev * led_cdev = led_trigger_get_led ( dev ) ;
2012-06-07 02:11:05 +04:00
unsigned long state ;
int ret ;
ret = kstrtoul ( buf , 0 , & state ) ;
if ( ret )
return ret ;
led_cdev - > blink_delay_on = state ;
return size ;
}
2018-07-02 23:05:29 +03:00
2012-06-07 02:11:05 +04:00
static ssize_t led_delay_off_show ( struct device * dev ,
struct device_attribute * attr , char * buf )
{
2018-07-02 23:05:29 +03:00
struct led_classdev * led_cdev = led_trigger_get_led ( dev ) ;
2012-06-07 02:11:05 +04:00
return sprintf ( buf , " %lu \n " , led_cdev - > blink_delay_off ) ;
}
static ssize_t led_delay_off_store ( struct device * dev ,
struct device_attribute * attr , const char * buf , size_t size )
{
2018-07-02 23:05:29 +03:00
struct led_classdev * led_cdev = led_trigger_get_led ( dev ) ;
2012-06-07 02:11:05 +04:00
unsigned long state ;
int ret ;
ret = kstrtoul ( buf , 0 , & state ) ;
if ( ret )
return ret ;
led_cdev - > blink_delay_off = state ;
return size ;
}
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 DEVICE_ATTR ( invert , 0644 , led_invert_show , led_invert_store ) ;
static DEVICE_ATTR ( shot , 0200 , NULL , led_shot ) ;
2018-07-02 23:05:29 +03:00
static struct attribute * oneshot_trig_attrs [ ] = {
& dev_attr_delay_on . attr ,
& dev_attr_delay_off . attr ,
& dev_attr_invert . attr ,
& dev_attr_shot . attr ,
NULL
} ;
ATTRIBUTE_GROUPS ( oneshot_trig ) ;
2019-01-09 17:44:48 +03:00
static void pattern_init ( struct led_classdev * led_cdev )
{
u32 * pattern ;
unsigned int size = 0 ;
pattern = led_get_default_pattern ( led_cdev , & size ) ;
if ( ! pattern )
goto out_default ;
if ( size ! = 2 ) {
dev_warn ( led_cdev - > dev ,
" Expected 2 but got %u values for delays pattern \n " ,
size ) ;
goto out_default ;
}
led_cdev - > blink_delay_on = pattern [ 0 ] ;
led_cdev - > blink_delay_off = pattern [ 1 ] ;
kfree ( pattern ) ;
return ;
out_default :
kfree ( pattern ) ;
led_cdev - > blink_delay_on = DEFAULT_DELAY ;
led_cdev - > blink_delay_off = DEFAULT_DELAY ;
}
2018-07-02 23:05:21 +03:00
static int oneshot_trig_activate ( struct led_classdev * led_cdev )
2012-06-07 02:11:05 +04:00
{
struct oneshot_trig_data * oneshot_data ;
oneshot_data = kzalloc ( sizeof ( * oneshot_data ) , GFP_KERNEL ) ;
if ( ! oneshot_data )
2018-07-02 23:05:29 +03:00
return - ENOMEM ;
led_set_trigger_data ( led_cdev , oneshot_data ) ;
2012-06-07 02:11:05 +04:00
2019-01-09 17:44:48 +03:00
if ( led_cdev - > flags & LED_INIT_DEFAULT_TRIGGER ) {
pattern_init ( led_cdev ) ;
/*
* Mark as initialized even on pattern_init ( ) error because
* any consecutive call to it would produce the same error .
*/
led_cdev - > flags & = ~ LED_INIT_DEFAULT_TRIGGER ;
}
2012-06-07 02:11:05 +04:00
2018-07-02 23:05:21 +03:00
return 0 ;
2012-06-07 02:11:05 +04:00
}
static void oneshot_trig_deactivate ( struct led_classdev * led_cdev )
{
2018-07-02 23:05:29 +03:00
struct oneshot_trig_data * oneshot_data = led_get_trigger_data ( led_cdev ) ;
2012-06-07 02:11:05 +04:00
2018-07-02 23:05:29 +03:00
kfree ( oneshot_data ) ;
2012-06-07 02:11:05 +04:00
/* Stop blinking */
2012-06-14 00:34:30 +04:00
led_set_brightness ( led_cdev , LED_OFF ) ;
2012-06-07 02:11:05 +04:00
}
static struct led_trigger oneshot_led_trigger = {
. name = " oneshot " ,
. activate = oneshot_trig_activate ,
. deactivate = oneshot_trig_deactivate ,
2018-07-02 23:05:29 +03:00
. groups = oneshot_trig_groups ,
2012-06-07 02:11:05 +04:00
} ;
2018-07-02 23:05:29 +03:00
module_led_trigger ( oneshot_led_trigger ) ;
2012-06-07 02:11:05 +04:00
MODULE_AUTHOR ( " Fabio Baltieri <fabio.baltieri@gmail.com> " ) ;
MODULE_DESCRIPTION ( " One-shot LED trigger " ) ;
2015-11-12 12:20:39 +03:00
MODULE_LICENSE ( " GPL v2 " ) ;