2013-11-25 19:17:09 -08:00
/*
* Generic GPIO beeper driver
*
2014-04-25 23:45:05 -07:00
* Copyright ( C ) 2013 - 2014 Alexander Shiyan < shc_work @ mail . ru >
2013-11-25 19:17:09 -08:00
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation ; either version 2 of the License , or
* ( at your option ) any later version .
*/
# include <linux/input.h>
# include <linux/module.h>
2014-04-25 23:45:05 -07:00
# include <linux/gpio/consumer.h>
# include <linux/of.h>
2013-11-25 19:17:09 -08:00
# include <linux/workqueue.h>
# include <linux/platform_device.h>
# define BEEPER_MODNAME "gpio-beeper"
struct gpio_beeper {
struct work_struct work ;
2014-04-25 23:45:05 -07:00
struct gpio_desc * desc ;
2013-11-25 19:17:09 -08:00
bool beeping ;
} ;
static void gpio_beeper_toggle ( struct gpio_beeper * beep , bool on )
{
2014-04-25 23:45:05 -07:00
gpiod_set_value_cansleep ( beep - > desc , on ) ;
2013-11-25 19:17:09 -08:00
}
static void gpio_beeper_work ( struct work_struct * work )
{
struct gpio_beeper * beep = container_of ( work , struct gpio_beeper , work ) ;
gpio_beeper_toggle ( beep , beep - > beeping ) ;
}
static int gpio_beeper_event ( struct input_dev * dev , unsigned int type ,
unsigned int code , int value )
{
struct gpio_beeper * beep = input_get_drvdata ( dev ) ;
if ( type ! = EV_SND | | code ! = SND_BELL )
return - ENOTSUPP ;
if ( value < 0 )
return - EINVAL ;
beep - > beeping = value ;
/* Schedule work to actually turn the beeper on or off */
schedule_work ( & beep - > work ) ;
return 0 ;
}
static void gpio_beeper_close ( struct input_dev * input )
{
struct gpio_beeper * beep = input_get_drvdata ( input ) ;
cancel_work_sync ( & beep - > work ) ;
gpio_beeper_toggle ( beep , false ) ;
}
static int gpio_beeper_probe ( struct platform_device * pdev )
{
struct gpio_beeper * beep ;
struct input_dev * input ;
beep = devm_kzalloc ( & pdev - > dev , sizeof ( * beep ) , GFP_KERNEL ) ;
if ( ! beep )
return - ENOMEM ;
2015-06-16 17:02:13 -07:00
beep - > desc = devm_gpiod_get ( & pdev - > dev , NULL , GPIOD_OUT_LOW ) ;
2014-04-25 23:45:05 -07:00
if ( IS_ERR ( beep - > desc ) )
return PTR_ERR ( beep - > desc ) ;
2013-11-25 19:17:09 -08:00
input = devm_input_allocate_device ( & pdev - > dev ) ;
if ( ! input )
return - ENOMEM ;
INIT_WORK ( & beep - > work , gpio_beeper_work ) ;
input - > name = pdev - > name ;
input - > id . bustype = BUS_HOST ;
input - > id . vendor = 0x0001 ;
input - > id . product = 0x0001 ;
input - > id . version = 0x0100 ;
input - > close = gpio_beeper_close ;
input - > event = gpio_beeper_event ;
input_set_capability ( input , EV_SND , SND_BELL ) ;
input_set_drvdata ( input , beep ) ;
return input_register_device ( input ) ;
}
2014-04-25 23:45:05 -07:00
# ifdef CONFIG_OF
2014-05-07 13:02:39 -07:00
static const struct of_device_id gpio_beeper_of_match [ ] = {
2013-11-25 19:17:09 -08:00
{ . compatible = BEEPER_MODNAME , } ,
{ }
} ;
MODULE_DEVICE_TABLE ( of , gpio_beeper_of_match ) ;
2014-04-25 23:45:05 -07:00
# endif
2013-11-25 19:17:09 -08:00
static struct platform_driver gpio_beeper_platform_driver = {
. driver = {
. name = BEEPER_MODNAME ,
2014-04-25 23:45:05 -07:00
. of_match_table = of_match_ptr ( gpio_beeper_of_match ) ,
2013-11-25 19:17:09 -08:00
} ,
. probe = gpio_beeper_probe ,
} ;
module_platform_driver ( gpio_beeper_platform_driver ) ;
MODULE_LICENSE ( " GPL " ) ;
MODULE_AUTHOR ( " Alexander Shiyan <shc_work@mail.ru> " ) ;
MODULE_DESCRIPTION ( " Generic GPIO beeper driver " ) ;