diff options
author | Dan Murphy <dmurphy@ti.com> | 2011-06-09 09:24:40 -0500 |
---|---|---|
committer | Ziyann <jaraidaniel@gmail.com> | 2014-10-03 01:17:48 +0200 |
commit | 225e02b7ee6c5d46e5c835e963bc61900491c1ec (patch) | |
tree | 18e6ea38883b998917774d10d84b05af122c23b4 | |
parent | 3132bfe8ae3860c7b796bfdf1ff21f8cf20fba9b (diff) | |
download | kernel_samsung_tuna-225e02b7ee6c5d46e5c835e963bc61900491c1ec.zip kernel_samsung_tuna-225e02b7ee6c5d46e5c835e963bc61900491c1ec.tar.gz kernel_samsung_tuna-225e02b7ee6c5d46e5c835e963bc61900491c1ec.tar.bz2 |
[Blaze] SFH7741 Proximity:Port SFH7741 k39 driver to k3.0
Port SFH7741 k39 driver to k3.0
Change-Id: I9dfb7cf82b09cd24e28e1808faf84536401d9ce9
Signed-off-by: Arthur Philpott <arthur.philpott@ti.com>
-rw-r--r-- | drivers/input/misc/sfh7741.c | 317 | ||||
-rw-r--r-- | include/linux/input/sfh7741.h | 46 |
2 files changed, 363 insertions, 0 deletions
diff --git a/drivers/input/misc/sfh7741.c b/drivers/input/misc/sfh7741.c new file mode 100644 index 0000000..6664365 --- /dev/null +++ b/drivers/input/misc/sfh7741.c @@ -0,0 +1,317 @@ +/* + * SFH7741 Proximity Driver + * + * Copyright (C) 2010 Texas Instruments + * + * Author: Shubhrajyoti D <shubhrajyoti@ti.com> + * + * 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 <linux/interrupt.h> +#include <linux/pm.h> +#include <linux/platform_device.h> +#include <linux/input.h> +#include <linux/input/sfh7741.h> +#include <linux/slab.h> +#include <linux/workqueue.h> + +#define SFH7741_PROX_ON 1 +#define SFH7741_PROX_OFF 0 + +#define SFH7741_SUSPEND_RESUME + +#define SFH7741_POLL_RATE 250 + +struct sfh7741_drvdata { + struct input_dev *input; + struct delayed_work input_work; + int irq; + int prox_enable; + int on_before_suspend; + int req_poll_rate; + /* mutex for sysfs operations */ + struct mutex lock; + struct sfh7741_platform_data *pdata; + void (*activate_func)(int state); + int (*read_prox)(void); +}; + +static irqreturn_t sfh7741_isr(int irq, void *dev_id) +{ + struct sfh7741_drvdata *ddata = dev_id; + int proximity; + + proximity = ddata->read_prox(); + input_report_abs(ddata->input, ABS_DISTANCE, proximity); + input_sync(ddata->input); + + return IRQ_HANDLED; +} + +static ssize_t set_prox_state(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + int state = SFH7741_PROX_OFF; + 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 != SFH7741_PROX_OFF) + state = SFH7741_PROX_ON; + + mutex_lock(&ddata->lock); + if (state != ddata->prox_enable) { + if (state) { + if (ddata->irq) { + enable_irq(ddata->irq); + if (ddata->pdata->flags & SFH7741_WAKEABLE_INT) + enable_irq_wake(ddata->irq); + } else { + ddata->req_poll_rate = SFH7741_POLL_RATE; + schedule_delayed_work(&ddata->input_work, 0); + } + } else { + if (ddata->irq) { + disable_irq_nosync(ddata->irq); + if (ddata->pdata->flags & SFH7741_WAKEABLE_INT) + disable_irq_wake(ddata->irq); + } else { + cancel_delayed_work_sync(&ddata->input_work); + ddata->req_poll_rate = 0; + } + } + + ddata->activate_func(state); + ddata->prox_enable = state; + } + + mutex_unlock(&ddata->lock); + return strnlen(buf, count); +} + + +static void sfh7741_work(struct work_struct *work) +{ + struct sfh7741_drvdata *ddata = container_of((struct delayed_work *)work, + struct sfh7741_drvdata, + input_work); + int proximity; + + proximity = ddata->read_prox(); + input_report_abs(ddata->input, ABS_DISTANCE, proximity); + input_sync(ddata->input); + if (!ddata->irq) + schedule_delayed_work(&ddata->input_work, + msecs_to_jiffies(ddata->req_poll_rate)); +} + +static ssize_t show_prox_state(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct platform_device *pdev = to_platform_device(dev); + struct sfh7741_drvdata *ddata = platform_get_drvdata(pdev); + return sprintf(buf, "%u\n", ddata->prox_enable); +} +static DEVICE_ATTR(state, S_IWUSR | S_IRUGO, show_prox_state, set_prox_state); + + +static struct attribute *sfh7741_attributes[] = { + &dev_attr_state.attr, + NULL +}; + +static const struct attribute_group sfh7741_attr_group = { + .attrs = sfh7741_attributes, +}; + +static int __devinit sfh7741_probe(struct platform_device *pdev) +{ + struct sfh7741_drvdata *ddata; + struct input_dev *input; + struct device *dev = &pdev->dev; + int error; + + pr_info("%s: Proximity sensor\n", __func__); + + if (pdev->dev.platform_data == NULL) { + pr_err("%s: Platform data is NULL\n", __func__); + return -EINVAL; + } + + ddata = kzalloc(sizeof(struct sfh7741_drvdata), + GFP_KERNEL); + if (!ddata) { + pr_err("%s:Could not allocate memory for Proximity\n", + __func__); + return -ENOMEM; + } + + ddata->pdata = pdev->dev.platform_data; + if (!ddata->pdata->activate_func || + !ddata->pdata->read_prox) { + pr_err("%s:Read Prox or Activate is NULL\n", __func__); + error = -EINVAL; + goto fail0; + } + + input = input_allocate_device(); + if (!input) { + pr_err("%s: Failed to allocate input device\n", __func__); + error = -ENOMEM; + goto fail0; + } + + input->name = pdev->name; + input->phys = "sfh7741/input0"; + input->dev.parent = &pdev->dev; + + input->id.bustype = BUS_HOST; + ddata->irq = ddata->pdata->irq; + ddata->prox_enable = ddata->pdata->prox_enable; + ddata->req_poll_rate = 0; + ddata->activate_func = ddata->pdata->activate_func; + ddata->read_prox = ddata->pdata->read_prox; + + 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) { + pr_err("%s: Unable to register input device,error: %d\n", + __func__, error); + goto fail1; + } + + if (ddata->irq) { + error = request_threaded_irq(ddata->irq , NULL , + sfh7741_isr, + ddata->pdata->irq_flags, + "sfh7741_irq", ddata); + if (error) { + pr_err("%s: Unable to claim irq %d; error %d\n", + __func__, ddata->pdata->irq, error); + goto fail2; + } + } else { + INIT_DELAYED_WORK(&ddata->input_work, sfh7741_work); + } + + mutex_init(&ddata->lock); + + platform_set_drvdata(pdev, ddata); + + error = sysfs_create_group(&dev->kobj, &sfh7741_attr_group); + if (error) { + pr_err("%s: Failed to create sysfs entries\n", __func__); + mutex_destroy(&ddata->lock); + } + + disable_irq_nosync(ddata->irq); + + return 0; + +fail2: + input_unregister_device(input); + platform_set_drvdata(pdev, NULL); +fail1: + input_free_device(input); +fail0: + kfree(ddata); + return error; + +} + +static int __devexit sfh7741_remove(struct platform_device *pdev) +{ + struct sfh7741_drvdata *ddata = platform_get_drvdata(pdev); + struct device *dev = &pdev->dev; + mutex_destroy(&ddata->lock); + sysfs_remove_group(&dev->kobj, &sfh7741_attr_group); + free_irq(ddata->irq, (void *)ddata); + input_unregister_device(ddata->input); + kfree(ddata); + return 0; +} + +#ifdef CONFIG_PM +#ifdef SFH7741_SUSPEND_RESUME +static int sfh7741_suspend(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct sfh7741_drvdata *ddata = platform_get_drvdata(pdev); + /* Save the prox state for the resume */ + ddata->on_before_suspend = ddata->prox_enable; + + 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); + int proximity = 0; + + if (ddata->on_before_suspend) { + proximity = ddata->read_prox(); + input_report_abs(ddata->input, ABS_DISTANCE, proximity); + input_sync(ddata->input); + } + return 0; +} + +static const struct dev_pm_ops sfh7741_pm_ops = { + .suspend = sfh7741_suspend, + .resume = sfh7741_resume, +}; +#endif +#endif + +static struct platform_driver sfh7741_device_driver = { + .probe = sfh7741_probe, + .remove = __devexit_p(sfh7741_remove), + .driver = { + .name = SFH7741_NAME, + .owner = THIS_MODULE, +#ifdef CONFIG_PM +#ifdef SFH7741_SUSPEND_RESUME + .pm = &sfh7741_pm_ops, +#endif +#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 sensor SFH7741 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..223b27f --- /dev/null +++ b/include/linux/input/sfh7741.h @@ -0,0 +1,46 @@ +/* + * sfh7741.h + * SFH7741 Proximity sensor driver + * + * Copyright (C) 2010 Texas Instruments + * Author: Shubhrajyoti D <shubhrajyoti@ti.com> + * + * 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, see <http://www.gnu.org/licenses/>. + */ + +#ifndef __SFH7741_H +#define __SFH7741_H + +#define SFH7741_NAME "sfh7741" + +#define SFH7741_WAKEABLE_INT (1 << 0) +#define SFH7741_DEFAULT_ON (1 << 1) + +/* + * struct sfh7741_platform_data - SFH7741 Platform data + * @irq: IRQ assigned + * @prox_enable: State of the sensor + * @activate_func: function called to activate/deactivate the sensor + * @read_prox: function to read the sensor output + */ +struct sfh7741_platform_data { + int flags; + int irq; + int irq_flags; + int prox_enable; + void (*activate_func)(int state); + int (*read_prox)(void); +}; + +#endif + |