2011-02-07 13:05:46 +03:00
/*
* Copyright 2011 Analog Devices Inc .
*
* Licensed under the GPL - 2.
*
*/
# include <linux/kernel.h>
# include <linux/module.h>
# include <linux/platform_device.h>
# include <linux/slab.h>
2011-05-18 17:42:11 +04:00
# include <linux/list.h>
2012-09-06 13:05:00 +04:00
# include <linux/irq_work.h>
2011-02-07 13:05:46 +03:00
2012-04-25 18:54:58 +04:00
# include <linux/iio/iio.h>
# include <linux/iio/trigger.h>
2011-02-07 13:05:46 +03:00
2011-05-18 17:42:11 +04:00
struct iio_sysfs_trig {
struct iio_trigger * trig ;
2012-09-06 13:05:00 +04:00
struct irq_work work ;
2011-05-18 17:42:11 +04:00
int id ;
struct list_head l ;
} ;
static LIST_HEAD ( iio_sysfs_trig_list ) ;
2013-09-23 14:49:00 +04:00
static DEFINE_MUTEX ( iio_sysfs_trig_list_mut ) ;
2011-05-18 17:42:11 +04:00
static int iio_sysfs_trigger_probe ( int id ) ;
static ssize_t iio_sysfs_trig_add ( struct device * dev ,
struct device_attribute * attr ,
const char * buf ,
size_t len )
{
int ret ;
unsigned long input ;
2013-06-01 11:10:00 +04:00
ret = kstrtoul ( buf , 10 , & input ) ;
2011-05-18 17:42:11 +04:00
if ( ret )
return ret ;
ret = iio_sysfs_trigger_probe ( input ) ;
if ( ret )
return ret ;
return len ;
}
static DEVICE_ATTR ( add_trigger , S_IWUSR , NULL , & iio_sysfs_trig_add ) ;
static int iio_sysfs_trigger_remove ( int id ) ;
static ssize_t iio_sysfs_trig_remove ( struct device * dev ,
struct device_attribute * attr ,
const char * buf ,
size_t len )
{
int ret ;
unsigned long input ;
2013-06-01 11:10:00 +04:00
ret = kstrtoul ( buf , 10 , & input ) ;
2011-05-18 17:42:11 +04:00
if ( ret )
return ret ;
ret = iio_sysfs_trigger_remove ( input ) ;
if ( ret )
return ret ;
return len ;
}
static DEVICE_ATTR ( remove_trigger , S_IWUSR , NULL , & iio_sysfs_trig_remove ) ;
static struct attribute * iio_sysfs_trig_attrs [ ] = {
& dev_attr_add_trigger . attr ,
& dev_attr_remove_trigger . attr ,
NULL ,
} ;
static const struct attribute_group iio_sysfs_trig_group = {
. attrs = iio_sysfs_trig_attrs ,
} ;
static const struct attribute_group * iio_sysfs_trig_groups [ ] = {
& iio_sysfs_trig_group ,
NULL
} ;
2011-08-24 20:28:35 +04:00
/* Nothing to actually do upon release */
static void iio_trigger_sysfs_release ( struct device * dev )
{
}
2011-05-18 17:42:11 +04:00
static struct device iio_sysfs_trig_dev = {
. bus = & iio_bus_type ,
. groups = iio_sysfs_trig_groups ,
2011-08-24 20:28:35 +04:00
. release = & iio_trigger_sysfs_release ,
2011-05-18 17:42:11 +04:00
} ;
2012-09-06 13:05:00 +04:00
static void iio_sysfs_trigger_work ( struct irq_work * work )
{
struct iio_sysfs_trig * trig = container_of ( work , struct iio_sysfs_trig ,
work ) ;
iio_trigger_poll ( trig - > trig , 0 ) ;
}
2011-02-07 13:05:46 +03:00
static ssize_t iio_sysfs_trigger_poll ( struct device * dev ,
struct device_attribute * attr , const char * buf , size_t count )
{
2012-06-21 21:10:59 +04:00
struct iio_trigger * trig = to_iio_trigger ( dev ) ;
2013-03-25 12:58:00 +04:00
struct iio_sysfs_trig * sysfs_trig = iio_trigger_get_drvdata ( trig ) ;
2012-09-06 13:05:00 +04:00
irq_work_queue ( & sysfs_trig - > work ) ;
2011-02-07 13:05:46 +03:00
return count ;
}
static DEVICE_ATTR ( trigger_now , S_IWUSR , NULL , iio_sysfs_trigger_poll ) ;
static struct attribute * iio_sysfs_trigger_attrs [ ] = {
& dev_attr_trigger_now . attr ,
NULL ,
} ;
static const struct attribute_group iio_sysfs_trigger_attr_group = {
. attrs = iio_sysfs_trigger_attrs ,
} ;
2011-05-18 17:42:22 +04:00
static const struct attribute_group * iio_sysfs_trigger_attr_groups [ ] = {
& iio_sysfs_trigger_attr_group ,
NULL
} ;
2011-08-12 20:08:38 +04:00
static const struct iio_trigger_ops iio_sysfs_trigger_ops = {
. owner = THIS_MODULE ,
} ;
2011-05-18 17:42:11 +04:00
static int iio_sysfs_trigger_probe ( int id )
2011-02-07 13:05:46 +03:00
{
2011-05-18 17:42:11 +04:00
struct iio_sysfs_trig * t ;
2011-02-07 13:05:46 +03:00
int ret ;
2011-05-18 17:42:11 +04:00
bool foundit = false ;
2013-09-23 14:49:00 +04:00
mutex_lock ( & iio_sysfs_trig_list_mut ) ;
2011-05-18 17:42:11 +04:00
list_for_each_entry ( t , & iio_sysfs_trig_list , l )
if ( id = = t - > id ) {
foundit = true ;
break ;
}
if ( foundit ) {
ret = - EINVAL ;
goto out1 ;
}
t = kmalloc ( sizeof ( * t ) , GFP_KERNEL ) ;
if ( t = = NULL ) {
2011-02-07 13:05:46 +03:00
ret = - ENOMEM ;
2011-05-18 17:42:22 +04:00
goto out1 ;
2011-05-18 17:42:11 +04:00
}
t - > id = id ;
2012-04-26 15:35:01 +04:00
t - > trig = iio_trigger_alloc ( " sysfstrig%d " , id ) ;
2011-05-18 17:42:11 +04:00
if ( ! t - > trig ) {
ret = - ENOMEM ;
goto free_t ;
2011-02-07 13:05:46 +03:00
}
2011-05-18 17:42:22 +04:00
t - > trig - > dev . groups = iio_sysfs_trigger_attr_groups ;
2011-08-12 20:08:38 +04:00
t - > trig - > ops = & iio_sysfs_trigger_ops ;
2011-05-18 17:42:11 +04:00
t - > trig - > dev . parent = & iio_sysfs_trig_dev ;
2013-03-25 12:58:00 +04:00
iio_trigger_set_drvdata ( t - > trig , t ) ;
2012-09-06 13:05:00 +04:00
init_irq_work ( & t - > work , iio_sysfs_trigger_work ) ;
2011-02-07 13:05:46 +03:00
2011-05-18 17:42:11 +04:00
ret = iio_trigger_register ( t - > trig ) ;
if ( ret )
goto out2 ;
list_add ( & t - > l , & iio_sysfs_trig_list ) ;
__module_get ( THIS_MODULE ) ;
2013-09-23 14:49:00 +04:00
mutex_unlock ( & iio_sysfs_trig_list_mut ) ;
2011-02-07 13:05:46 +03:00
return 0 ;
2011-05-18 17:42:11 +04:00
2011-02-07 13:05:46 +03:00
out2 :
2012-04-26 15:35:01 +04:00
iio_trigger_put ( t - > trig ) ;
2011-05-18 17:42:11 +04:00
free_t :
kfree ( t ) ;
2011-02-07 13:05:46 +03:00
out1 :
2013-09-23 14:49:00 +04:00
mutex_unlock ( & iio_sysfs_trig_list_mut ) ;
2011-02-07 13:05:46 +03:00
return ret ;
}
2011-05-18 17:42:11 +04:00
static int iio_sysfs_trigger_remove ( int id )
2011-02-07 13:05:46 +03:00
{
2011-05-18 17:42:11 +04:00
bool foundit = false ;
struct iio_sysfs_trig * t ;
2013-09-23 14:49:00 +04:00
mutex_lock ( & iio_sysfs_trig_list_mut ) ;
2011-05-18 17:42:11 +04:00
list_for_each_entry ( t , & iio_sysfs_trig_list , l )
if ( id = = t - > id ) {
foundit = true ;
break ;
}
if ( ! foundit ) {
2013-09-23 14:49:00 +04:00
mutex_unlock ( & iio_sysfs_trig_list_mut ) ;
2011-05-18 17:42:11 +04:00
return - EINVAL ;
}
2011-02-07 13:05:46 +03:00
2011-05-18 17:42:11 +04:00
iio_trigger_unregister ( t - > trig ) ;
2012-04-26 15:35:01 +04:00
iio_trigger_free ( t - > trig ) ;
2011-02-07 13:05:46 +03:00
2011-05-18 17:42:11 +04:00
list_del ( & t - > l ) ;
kfree ( t ) ;
module_put ( THIS_MODULE ) ;
2013-09-23 14:49:00 +04:00
mutex_unlock ( & iio_sysfs_trig_list_mut ) ;
2011-02-07 13:05:46 +03:00
return 0 ;
}
static int __init iio_sysfs_trig_init ( void )
{
2011-05-18 17:42:11 +04:00
device_initialize ( & iio_sysfs_trig_dev ) ;
dev_set_name ( & iio_sysfs_trig_dev , " iio_sysfs_trigger " ) ;
return device_add ( & iio_sysfs_trig_dev ) ;
2011-02-07 13:05:46 +03:00
}
module_init ( iio_sysfs_trig_init ) ;
static void __exit iio_sysfs_trig_exit ( void )
{
2011-05-18 17:42:11 +04:00
device_unregister ( & iio_sysfs_trig_dev ) ;
2011-02-07 13:05:46 +03:00
}
module_exit ( iio_sysfs_trig_exit ) ;
MODULE_AUTHOR ( " Michael Hennerich <hennerich@blackfin.uclinux.org> " ) ;
MODULE_DESCRIPTION ( " Sysfs based trigger for the iio subsystem " ) ;
MODULE_LICENSE ( " GPL v2 " ) ;
MODULE_ALIAS ( " platform:iio-trig-sysfs " ) ;