From patchwork Mon May 3 05:46:18 2010 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Shubhrajyoti Datta X-Patchwork-Id: 96414 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by demeter.kernel.org (8.14.3/8.14.3) with ESMTP id o435kPvr003274 for ; Mon, 3 May 2010 05:46:26 GMT Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1753211Ab0ECFqZ (ORCPT ); Mon, 3 May 2010 01:46:25 -0400 Received: from arroyo.ext.ti.com ([192.94.94.40]:37663 "EHLO arroyo.ext.ti.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752348Ab0ECFqY convert rfc822-to-8bit (ORCPT ); Mon, 3 May 2010 01:46:24 -0400 Received: from dbdp20.itg.ti.com ([172.24.170.38]) by arroyo.ext.ti.com (8.13.7/8.13.7) with ESMTP id o435kLsQ006420 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=NO); Mon, 3 May 2010 00:46:23 -0500 Received: from dbde71.ent.ti.com (localhost [127.0.0.1]) by dbdp20.itg.ti.com (8.13.8/8.13.8) with ESMTP id o435kKiM016014; Mon, 3 May 2010 11:16:20 +0530 (IST) Received: from dbde02.ent.ti.com ([172.24.170.145]) by dbde71.ent.ti.com ([172.24.170.149]) with mapi; Mon, 3 May 2010 11:16:20 +0530 From: "Datta, Shubhrajyoti" To: "linux-input@vger.kernel.org" , "linux-omap@vger.kernel.org" CC: "Ossi.Kauppinen@vti.fi" , "Datta, Shubhrajyoti" Date: Mon, 3 May 2010 11:16:18 +0530 Subject: [RFC][PATCH1/2] SFH7741: proximity sensor driver support Thread-Topic: [RFC][PATCH1/2] SFH7741: proximity sensor driver support Thread-Index: Acrqgpw4G9jd2m+XR1KpJ0KyaLH1kQAAEF7Q Message-ID: <0680EC522D0CC943BC586913CF3768C003B3164B2F@dbde02.ent.ti.com> Accept-Language: en-US Content-Language: en-US X-MS-Has-Attach: X-MS-TNEF-Correlator: acceptlanguage: en-US MIME-Version: 1.0 Sender: linux-omap-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-omap@vger.kernel.org X-Greylist: IP, sender and recipient auto-whitelisted, not delayed by milter-greylist-4.2.3 (demeter.kernel.org [140.211.167.41]); Mon, 03 May 2010 05:46:26 +0000 (UTC) diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig index 16ec523..5919358 100644 --- a/drivers/input/misc/Kconfig +++ b/drivers/input/misc/Kconfig @@ -319,4 +319,13 @@ config INPUT_PCAP To compile this driver as a module, choose M here: the module will be called pcap_keys. +config SENSORS_SFH7741 + tristate "Proximity sensor" + default y + help + Say Y here if you want to use proximity sensor sfh7741. + + To compile this driver as a module, choose M here: the + module will be called sfh7741. + endif diff --git a/drivers/input/misc/Makefile b/drivers/input/misc/Makefile index a8b8485..b2cac12 100644 --- a/drivers/input/misc/Makefile +++ b/drivers/input/misc/Makefile @@ -30,4 +30,5 @@ obj-$(CONFIG_INPUT_WINBOND_CIR) += winbond-cir.o obj-$(CONFIG_INPUT_WISTRON_BTNS) += wistron_btns.o obj-$(CONFIG_INPUT_WM831X_ON) += wm831x-on.o obj-$(CONFIG_INPUT_YEALINK) += yealink.o +obj-$(CONFIG_SENSORS_SFH7741) += sfh7741.o diff --git a/drivers/input/misc/sfh7741.c b/drivers/input/misc/sfh7741.c new file mode 100644 index 0000000..b4febfe --- /dev/null +++ b/drivers/input/misc/sfh7741.c @@ -0,0 +1,308 @@ +/* + * sfh7741.c + * + * SFH7741 Proximity Driver + * + * Copyright (C) 2010 Texas Instruments + * + * Author: Shubhrajyoti Datta + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include +#include +#include +#include + +struct sfh7741_drvdata { + struct input_dev *input; + int proximity_out; + int gpio_en; +}; + +static DEFINE_MUTEX(prox_enable_mutex); +static int prox_enable = 1; + +static irqreturn_t sfh7741_isr(int irq, void *dev_id) +{ + struct sfh7741_drvdata *ddata = dev_id; + + int proximity = gpio_get_value(ddata->proximity_out); + input_report_abs(ddata->input, ABS_DISTANCE, proximity); + input_sync(ddata->input); + + return IRQ_HANDLED; +} + +static int __devinit sfh7741_setup(struct device *dev, + struct sfh7741_drvdata *ddata + ) +{ + int error; + char *desc = "sfh7741"; + + error = gpio_request(ddata->proximity_out, desc); + if (error < 0) { + dev_err(dev, "failed to request GPIO %d, error %d\n", + ddata->proximity_out, error); + return error; + } + + error = gpio_direction_input(ddata->proximity_out); + if (error < 0) { + dev_err(dev, "failed to configure direction for GPIO %d,\ + error %d\n", ddata->proximity_out, error); + goto fail1; + } + + error = request_threaded_irq(gpio_to_irq(ddata->proximity_out) , NULL , + sfh7741_isr, + IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING + | IRQF_ONESHOT, + desc, ddata); + if (error) { + dev_err(dev, "Unable to claim irq %d; error %d\n", + gpio_to_irq(ddata->proximity_out), error); + goto fail1; + } + + error = gpio_request(ddata->gpio_en, desc); + if (error < 0) { + dev_err(dev, "failed to request GPIO %d, error %d\n", + ddata->gpio_en, error); + goto fail2; + } + + error = gpio_direction_output(ddata->gpio_en , 1); + if (error < 0) { + dev_err(dev, "%s: GPIO configuration failed: GPIO %d,\ + error %d\n",__func__, ddata->gpio_en, error); + goto fail3; + } + return 0; + +fail3: + gpio_free(ddata->gpio_en); +fail2: + free_irq(gpio_to_irq(ddata->proximity_out), &ddata); +fail1: + gpio_free(ddata->proximity_out); + return error; +} + +static ssize_t set_prox_state(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + int state , error; + struct platform_device *pdev = to_platform_device(dev); + struct sfh7741_drvdata *ddata = platform_get_drvdata(pdev); + + if (sscanf(buf, "%u", &state) != 1) + return -EINVAL; + + if ((state != 1) && (state != 0)) + return -EINVAL; + + error = gpio_direction_output(ddata->gpio_en , state); + if (error < 0) { + dev_err(dev, "%s: GPIO configuration failed: GPIO %d,\ + error %d\n",__func__, ddata->gpio_en, error); + } + mutex_lock(&prox_enable_mutex); + if (state != prox_enable) { + if (state) + enable_irq(gpio_to_irq(ddata->proximity_out)); + else + disable_irq(gpio_to_irq(ddata->proximity_out)); + prox_enable = state; + } + mutex_unlock(&prox_enable_mutex); + return strnlen(buf, count); +} + +static ssize_t show_prox_state(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + return sprintf(buf, "%u\n", prox_enable); +} +static DEVICE_ATTR(state, S_IWUSR | S_IRUGO, show_prox_state, set_prox_state); + +static ssize_t show_proximity(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + int proximity; + struct platform_device *pdev = to_platform_device(dev); + struct sfh7741_drvdata *ddata = platform_get_drvdata(pdev); + + proximity = gpio_get_value(ddata->proximity_out); + return sprintf(buf, "%u\n", proximity); +} +static DEVICE_ATTR(proximity, S_IRUGO, show_proximity, NULL); + +static struct attribute *sfh7741_attributes[] = { + &dev_attr_state.attr, + &dev_attr_proximity.attr, + NULL +}; + +static const struct attribute_group sfh7741_attr_group = { + .attrs = sfh7741_attributes, +}; + +static int __devinit sfh7741_probe(struct platform_device *pdev) +{ + struct sfh7741_platform_data *pdata = pdev->dev.platform_data; + struct sfh7741_drvdata *ddata; + struct device *dev = &pdev->dev; + struct input_dev *input; + int error; + + pr_info("SFH7741: Proximity sensor\n"); + + ddata = kzalloc(sizeof(struct sfh7741_drvdata), + GFP_KERNEL); + input = input_allocate_device(); + if (!ddata || !input) { + dev_err(dev, "failed to allocate input device\n"); + return -ENOMEM; + } + + input->name = pdev->name; + input->phys = "sfh7741/input0"; + input->dev.parent = &pdev->dev; + + input->id.bustype = BUS_HOST; + ddata->proximity_out = pdata->gpio_intr; + ddata->gpio_en = pdata->gpio_en; + + ddata->input = input; + __set_bit(EV_ABS, input->evbit); + + input_set_abs_params(input, ABS_DISTANCE, 0, 1, 0, 0); + + error = input_register_device(input); + if (error) { + dev_err(dev, "Unable to register input device,error: %d\n" + , error); + goto fail1; + } + + platform_set_drvdata(pdev, ddata); + error = sfh7741_setup(dev, ddata); + if (error) + goto fail2; + + error = sysfs_create_group(&dev->kobj, &sfh7741_attr_group); + if (error) + dev_err(dev, "failed to create sysfs entries \n"); + + return 0; + +fail2: + input_unregister_device(input); + platform_set_drvdata(pdev, NULL); +fail1: + input_free_device(input); + kfree(ddata); + return error; + +} + +static int __devexit sfh7741_remove(struct platform_device *pdev) +{ + struct sfh7741_drvdata *ddata = platform_get_drvdata(pdev); + int irq ; + struct device *dev = &pdev->dev; + + sysfs_remove_group(&dev->kobj, &sfh7741_attr_group); + gpio_free(ddata->gpio_en); + + irq = gpio_to_irq(ddata->proximity_out); + free_irq(irq, (void *)ddata); + gpio_free(ddata->proximity_out); + + input_unregister_device(ddata->input); + kfree(ddata); + return 0; +} + +#ifdef CONFIG_PM +static int sfh7741_suspend(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct sfh7741_drvdata *ddata = platform_get_drvdata(pdev); + + error = gpio_direction_output(ddata->gpio_en , 0); + if (error < 0) { + dev_err(dev, "%s: GPIO configuration failed: GPIO %d,\ + error %d\n",__func__, ddata->gpio_en, error); + } + return 0; +} + +static int sfh7741_resume(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct sfh7741_drvdata *ddata = platform_get_drvdata(pdev); + + error = gpio_direction_output(ddata->gpio_en , 1); + if (error < 0) { + dev_err(dev, "%s: GPIO configuration failed: GPIO %d,\ + error %d\n",__func__, ddata->gpio_en, error); + } + return 0; +} + +static const struct dev_pm_ops sfh7741_pm_ops = { + .suspend = sfh7741_suspend, + .resume = sfh7741_resume, +}; +#endif + +static struct platform_driver sfh7741_device_driver = { + .probe = sfh7741_probe, + .remove = __devexit_p(sfh7741_remove), + .driver = { + .name = "sfh7741", + .owner = THIS_MODULE, +#ifdef CONFIG_PM + .pm = &sfh7741_pm_ops, +#endif + } +}; + +static int __init sfh7741_init(void) +{ + return platform_driver_register(&sfh7741_device_driver); +} + +static void __exit sfh7741_exit(void) +{ + platform_driver_unregister(&sfh7741_device_driver); +} + +module_init(sfh7741_init); +module_exit(sfh7741_exit); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Texas Instruments"); +MODULE_DESCRIPTION("Proximity driver "); +MODULE_ALIAS("platform:sfh7741"); + diff --git a/include/linux/input/sfh7741.h b/include/linux/input/sfh7741.h new file mode 100644 index 0000000..801c971 --- /dev/null +++ b/include/linux/input/sfh7741.h @@ -0,0 +1,14 @@ +/* + * Configuration and driver data for Proximity driver. + */ + +#ifndef __SFH7741_H +#define __SFH7741_H + +struct sfh7741_platform_data { + int gpio_intr; + int gpio_en; +}; + +#endif +