flo: lid: add hall sensor driver

Change-Id: I0f8506f6e74d329b108dfb92f9604884636c9c9a
Signed-off-by: hsuan-chih_chen <hsuan-chih_chen@asus.com>
Signed-off-by: paris_yeh <paris_yeh@asus.com>
This commit is contained in:
hsuan-chih_chen 2013-04-02 17:06:31 +08:00 committed by Iliyan Malchev
parent 7dd2a48252
commit d6768814c1
3 changed files with 242 additions and 0 deletions

View file

@ -174,6 +174,10 @@ config INPUT_KEYRESET
To compile this driver as a module, choose M here: the
module will be called keyreset.
config INPUT_LID
tristate "Hall Sensor"
depends on INPUT
comment "Input Device Drivers"
source "drivers/input/keyboard/Kconfig"

View file

@ -26,3 +26,4 @@ obj-$(CONFIG_INPUT_MISC) += misc/
obj-$(CONFIG_INPUT_APMPOWER) += apm-power.o
obj-$(CONFIG_INPUT_OF_MATRIX_KEYMAP) += of_keymap.o
obj-$(CONFIG_INPUT_KEYRESET) += keyreset.o
obj-$(CONFIG_INPUT_LID) += lid.o

237
drivers/input/lid.c Normal file
View file

@ -0,0 +1,237 @@
/*
* ASUS Lid driver.
*/
#include <linux/module.h>
#include <linux/err.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
#include <linux/init.h>
#include <linux/input.h>
#include <linux/platform_device.h>
#include <linux/workqueue.h>
#include <linux/gpio_event.h>
#include <linux/gpio.h>
#define LID_DEBUG 0
#define CONVERSION_TIME_MS 50
#if LID_DEBUG
#define LID_INFO(format, arg...) \
pr_info("hall_sensor: [%s] " format , __func__ , ##arg)
#else
#define LID_INFO(format, arg...) do { } while (0)
#endif
#define LID_NOTICE(format, arg...) \
pr_notice("hall_sensor: [%s] " format , __func__ , ##arg)
#define LID_ERR(format, arg...) \
pr_err("hall_sensor: [%s] " format , __func__ , ##arg)
struct delayed_work lid_hall_sensor_work;
/*
* functions declaration
*/
static void lid_report_function(struct work_struct *dat);
static int lid_input_device_create(void);
static ssize_t show_lid_status(struct device *class,
struct device_attribute *attr, char *buf);
/*
* global variable
*/
static unsigned int hall_sensor_gpio = 36;
static int hall_sensor_irq;
static struct workqueue_struct *lid_wq;
static struct input_dev *lid_indev;
static DEVICE_ATTR(lid_status, S_IWUSR | S_IRUGO, show_lid_status, NULL);
/* Attribute Descriptor */
static struct attribute *lid_attrs[] = {
&dev_attr_lid_status.attr,
NULL
};
/* Attribute group */
static struct attribute_group lid_attr_group = {
.attrs = lid_attrs,
};
static ssize_t show_lid_status(struct device *class,
struct device_attribute *attr, char *buf)
{
char *s = buf;
s += sprintf(buf, "%u\n",
gpio_get_value(hall_sensor_gpio) ? 1 : 0);
return s - buf;
}
static irqreturn_t lid_interrupt_handler(int irq, void *dev_id)
{
if (irq == hall_sensor_irq) {
LID_NOTICE("LID interrupt handler...gpio: %d..\n",
gpio_get_value(hall_sensor_gpio));
queue_delayed_work(lid_wq, &lid_hall_sensor_work, 0);
}
return IRQ_HANDLED;
}
static void lid_report_function(struct work_struct *dat)
{
int value = 0;
if (!lid_indev) {
LID_ERR("LID input device doesn't exist\n");
return;
}
msleep(CONVERSION_TIME_MS);
value = gpio_get_value(hall_sensor_gpio) ? 1 : 0;
input_report_switch(lid_indev, SW_LID, !value);
input_sync(lid_indev);
LID_NOTICE("SW_LID report value = %d\n", value);
}
static int lid_input_device_create(void){
int err = 0;
lid_indev = input_allocate_device();
if (!lid_indev) {
LID_ERR("lid_indev allocation fails\n");
err = -ENOMEM;
goto exit;
}
lid_indev->name = "lid_input";
lid_indev->phys = "/dev/input/lid_indev";
set_bit(EV_SW, lid_indev->evbit);
set_bit(SW_LID, lid_indev->swbit);
err = input_register_device(lid_indev);
if (err) {
LID_ERR("lid_indev registration fails\n");
goto exit_input_free;
}
return 0;
exit_input_free:
input_free_device(lid_indev);
lid_indev = NULL;
exit:
return err;
}
static int __init lid_driver_probe(struct platform_device *pdev)
{
int ret = 0, irq = 0;
unsigned long irqflags;
if (!pdev)
return -EINVAL;
pr_info("ASUSTek: %s", __func__);
ret = sysfs_create_group(&pdev->dev.kobj, &lid_attr_group);
if (ret) {
LID_ERR("Unable to create sysfs, error: %d\n",
ret);
goto fail_sysfs;
}
ret = lid_input_device_create();
if (ret) {
LID_ERR(
"Unable to register input device, error: %d\n",
ret);
goto fail_create;
}
if (!gpio_is_valid(hall_sensor_gpio)) {
LID_ERR("Invalid GPIO %d\n", hall_sensor_gpio);
goto fail_create;
}
ret = gpio_request(hall_sensor_gpio, "LID");
if (ret < 0) {
LID_ERR("Failed to request GPIO %d\n",
hall_sensor_gpio);
goto fail_create;
}
ret = gpio_direction_input(hall_sensor_gpio);
if (ret < 0) {
LID_ERR(
"Failed to configure direction for GPIO %d\n",
hall_sensor_gpio);
goto fail_free;
}
irq = gpio_to_irq(hall_sensor_gpio);
hall_sensor_irq = irq;
if (irq < 0) {
LID_ERR("Unable to get irq number for GPIO %d\n",
hall_sensor_gpio);
goto fail_free;
}
irqflags = IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING;
ret = request_any_context_irq(irq, lid_interrupt_handler,
irqflags, "hall_sensor",
lid_indev);
if (ret < 0) {
LID_ERR("Unable to claim irq %d\n", irq);
goto fail_free;
}
device_init_wakeup(&pdev->dev, 1);
enable_irq_wake(irq);
lid_wq = create_singlethread_workqueue("lid_wq");
INIT_DELAYED_WORK_DEFERRABLE(&lid_hall_sensor_work,
lid_report_function);
return ret;
fail_free:
gpio_free(hall_sensor_gpio);
fail_create:
sysfs_remove_group(&pdev->dev.kobj, &lid_attr_group);
fail_sysfs:
return ret;
}
static int __devexit lid_driver_remove(struct platform_device *pdev)
{
sysfs_remove_group(&pdev->dev.kobj, &lid_attr_group);
free_irq(hall_sensor_irq, NULL);
cancel_delayed_work_sync(&lid_hall_sensor_work);
if (gpio_is_valid(hall_sensor_gpio))
gpio_free(hall_sensor_gpio);
input_unregister_device(lid_indev);
device_init_wakeup(&pdev->dev, 0);
return 0;
}
static struct platform_driver asustek_lid_driver __refdata = {
.probe = lid_driver_probe,
.remove = __devexit_p(lid_driver_remove),
.driver = {
.name = "asustek_lid",
.owner = THIS_MODULE,
},
};
module_platform_driver(asustek_lid_driver);
MODULE_DESCRIPTION("Hall Sensor Driver");
MODULE_LICENSE("GPL");