2012-02-28 01:51:40 -03:00
/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation .
*
* 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/kernel.h>
# include <linux/init.h>
# include <linux/module.h>
# include <linux/interrupt.h>
# include <linux/gpio.h>
# include <linux/slab.h>
2013-10-18 00:07:15 -03:00
# include <linux/of.h>
2013-02-08 18:47:30 -03:00
# include <linux/of_gpio.h>
2012-02-28 01:51:40 -03:00
# include <linux/platform_device.h>
# include <linux/irq.h>
# include <media/rc-core.h>
2015-11-16 08:35:53 -02:00
# include <linux/platform_data/media/gpio-ir-recv.h>
2012-02-28 01:51:40 -03:00
# define GPIO_IR_DRIVER_NAME "gpio-rc-recv"
# define GPIO_IR_DEVICE_NAME "gpio_ir_recv"
struct gpio_rc_dev {
struct rc_dev * rcdev ;
2012-03-10 04:58:18 -03:00
int gpio_nr ;
2012-02-28 01:51:40 -03:00
bool active_low ;
} ;
2013-02-08 18:47:30 -03:00
# ifdef CONFIG_OF
/*
* Translate OpenFirmware node properties into platform_data
*/
static int gpio_ir_recv_get_devtree_pdata ( struct device * dev ,
struct gpio_ir_recv_platform_data * pdata )
{
struct device_node * np = dev - > of_node ;
enum of_gpio_flags flags ;
int gpio ;
gpio = of_get_gpio_flags ( np , 0 , & flags ) ;
if ( gpio < 0 ) {
if ( gpio ! = - EPROBE_DEFER )
dev_err ( dev , " Failed to get gpio flags (%d) \n " , gpio ) ;
return gpio ;
}
pdata - > gpio_nr = gpio ;
pdata - > active_low = ( flags & OF_GPIO_ACTIVE_LOW ) ;
/* probe() takes care of map_name == NULL or allowed_protos == 0 */
pdata - > map_name = of_get_property ( np , " linux,rc-map-name " , NULL ) ;
pdata - > allowed_protos = 0 ;
return 0 ;
}
2015-03-16 16:54:33 -03:00
static const struct of_device_id gpio_ir_recv_of_match [ ] = {
2013-02-08 18:47:30 -03:00
{ . compatible = " gpio-ir-receiver " , } ,
{ } ,
} ;
MODULE_DEVICE_TABLE ( of , gpio_ir_recv_of_match ) ;
# else /* !CONFIG_OF */
# define gpio_ir_recv_get_devtree_pdata(dev, pdata) (-ENOSYS)
# endif
2012-02-28 01:51:40 -03:00
static irqreturn_t gpio_ir_recv_irq ( int irq , void * dev_id )
{
struct gpio_rc_dev * gpio_dev = dev_id ;
2012-03-10 04:58:18 -03:00
int gval ;
2012-02-28 01:51:40 -03:00
int rc = 0 ;
2015-06-02 11:43:50 -03:00
gval = gpio_get_value ( gpio_dev - > gpio_nr ) ;
2012-02-28 01:51:40 -03:00
if ( gval < 0 )
goto err_get_value ;
if ( gpio_dev - > active_low )
gval = ! gval ;
2017-08-07 08:38:10 -04:00
rc = ir_raw_event_store_edge ( gpio_dev - > rcdev , gval = = 1 ) ;
2012-02-28 01:51:40 -03:00
if ( rc < 0 )
goto err_get_value ;
err_get_value :
return IRQ_HANDLED ;
}
2012-12-21 13:17:53 -08:00
static int gpio_ir_recv_probe ( struct platform_device * pdev )
2012-02-28 01:51:40 -03:00
{
2017-09-07 20:34:35 -03:00
struct device * dev = & pdev - > dev ;
2012-02-28 01:51:40 -03:00
struct gpio_rc_dev * gpio_dev ;
struct rc_dev * rcdev ;
2017-09-07 20:34:35 -03:00
const struct gpio_ir_recv_platform_data * pdata = dev - > platform_data ;
2012-02-28 01:51:40 -03:00
int rc ;
2013-02-08 18:47:30 -03:00
if ( pdev - > dev . of_node ) {
struct gpio_ir_recv_platform_data * dtpdata =
2017-09-07 20:34:35 -03:00
devm_kzalloc ( dev , sizeof ( * dtpdata ) , GFP_KERNEL ) ;
2013-02-08 18:47:30 -03:00
if ( ! dtpdata )
return - ENOMEM ;
2017-09-07 20:34:35 -03:00
rc = gpio_ir_recv_get_devtree_pdata ( dev , dtpdata ) ;
2013-02-08 18:47:30 -03:00
if ( rc )
return rc ;
pdata = dtpdata ;
}
2012-02-28 01:51:40 -03:00
if ( ! pdata )
return - EINVAL ;
if ( pdata - > gpio_nr < 0 )
return - EINVAL ;
2017-09-07 20:35:22 -03:00
gpio_dev = devm_kzalloc ( dev , sizeof ( * gpio_dev ) , GFP_KERNEL ) ;
2012-02-28 01:51:40 -03:00
if ( ! gpio_dev )
return - ENOMEM ;
2017-09-07 20:36:11 -03:00
rcdev = devm_rc_allocate_device ( dev , RC_DRIVER_IR_RAW ) ;
2017-09-07 20:35:22 -03:00
if ( ! rcdev )
return - ENOMEM ;
2012-02-28 01:51:40 -03:00
2012-06-18 15:02:20 -03:00
rcdev - > priv = gpio_dev ;
2017-07-01 12:13:19 -04:00
rcdev - > device_name = GPIO_IR_DEVICE_NAME ;
2012-06-18 15:02:20 -03:00
rcdev - > input_phys = GPIO_IR_DEVICE_NAME " /input0 " ;
2012-02-28 01:51:40 -03:00
rcdev - > input_id . bustype = BUS_HOST ;
2012-06-18 15:02:20 -03:00
rcdev - > input_id . vendor = 0x0001 ;
rcdev - > input_id . product = 0x0001 ;
rcdev - > input_id . version = 0x0100 ;
2017-09-07 20:34:35 -03:00
rcdev - > dev . parent = dev ;
2012-02-28 01:51:40 -03:00
rcdev - > driver_name = GPIO_IR_DRIVER_NAME ;
2017-01-26 14:37:33 -02:00
rcdev - > min_timeout = 1 ;
2015-09-23 11:07:08 -03:00
rcdev - > timeout = IR_DEFAULT_TIMEOUT ;
rcdev - > max_timeout = 10 * IR_DEFAULT_TIMEOUT ;
2012-07-03 06:27:19 -03:00
if ( pdata - > allowed_protos )
2014-04-03 20:32:21 -03:00
rcdev - > allowed_protocols = pdata - > allowed_protos ;
2012-07-03 06:27:19 -03:00
else
2017-08-07 16:20:58 -04:00
rcdev - > allowed_protocols = RC_PROTO_BIT_ALL_IR_DECODER ;
2012-06-18 15:02:44 -03:00
rcdev - > map_name = pdata - > map_name ? : RC_MAP_EMPTY ;
2012-02-28 01:51:40 -03:00
gpio_dev - > rcdev = rcdev ;
gpio_dev - > gpio_nr = pdata - > gpio_nr ;
gpio_dev - > active_low = pdata - > active_low ;
2017-09-07 20:36:39 -03:00
rc = devm_gpio_request_one ( dev , pdata - > gpio_nr , GPIOF_DIR_IN ,
" gpio-ir-recv " ) ;
2012-02-28 01:51:40 -03:00
if ( rc < 0 )
2017-09-07 20:36:11 -03:00
return rc ;
2012-02-28 01:51:40 -03:00
2017-09-07 20:37:07 -03:00
rc = devm_rc_register_device ( dev , rcdev ) ;
2012-02-28 01:51:40 -03:00
if ( rc < 0 ) {
2017-09-07 20:34:35 -03:00
dev_err ( dev , " failed to register rc device (%d) \n " , rc ) ;
2017-09-07 20:37:07 -03:00
return rc ;
2012-02-28 01:51:40 -03:00
}
platform_set_drvdata ( pdev , gpio_dev ) ;
2017-09-07 20:38:20 -03:00
return devm_request_irq ( dev , gpio_to_irq ( pdata - > gpio_nr ) ,
gpio_ir_recv_irq ,
IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING ,
" gpio-ir-recv-irq " , gpio_dev ) ;
2012-02-28 01:51:40 -03:00
}
# ifdef CONFIG_PM
static int gpio_ir_recv_suspend ( struct device * dev )
{
struct platform_device * pdev = to_platform_device ( dev ) ;
struct gpio_rc_dev * gpio_dev = platform_get_drvdata ( pdev ) ;
if ( device_may_wakeup ( dev ) )
enable_irq_wake ( gpio_to_irq ( gpio_dev - > gpio_nr ) ) ;
else
disable_irq ( gpio_to_irq ( gpio_dev - > gpio_nr ) ) ;
return 0 ;
}
static int gpio_ir_recv_resume ( struct device * dev )
{
struct platform_device * pdev = to_platform_device ( dev ) ;
struct gpio_rc_dev * gpio_dev = platform_get_drvdata ( pdev ) ;
if ( device_may_wakeup ( dev ) )
disable_irq_wake ( gpio_to_irq ( gpio_dev - > gpio_nr ) ) ;
else
enable_irq ( gpio_to_irq ( gpio_dev - > gpio_nr ) ) ;
return 0 ;
}
static const struct dev_pm_ops gpio_ir_recv_pm_ops = {
. suspend = gpio_ir_recv_suspend ,
. resume = gpio_ir_recv_resume ,
} ;
# endif
static struct platform_driver gpio_ir_recv_driver = {
. probe = gpio_ir_recv_probe ,
. driver = {
. name = GPIO_IR_DRIVER_NAME ,
2013-02-08 18:47:30 -03:00
. of_match_table = of_match_ptr ( gpio_ir_recv_of_match ) ,
2012-02-28 01:51:40 -03:00
# ifdef CONFIG_PM
. pm = & gpio_ir_recv_pm_ops ,
# endif
} ,
} ;
2012-06-18 15:03:06 -03:00
module_platform_driver ( gpio_ir_recv_driver ) ;
2012-02-28 01:51:40 -03:00
MODULE_DESCRIPTION ( " GPIO IR Receiver driver " ) ;
MODULE_LICENSE ( " GPL v2 " ) ;