linux/drivers/input/misc/gp2ap002a00f.c
<<
>>
Prefs
   1/*
   2 * Copyright (C) 2011 Sony Ericsson Mobile Communications Inc.
   3 *
   4 * Author: Courtney Cavin <courtney.cavin@sonyericsson.com>
   5 * Prepared for up-stream by: Oskar Andero <oskar.andero@sonyericsson.com>
   6 *
   7 * This program is free software; you can redistribute it and/or modify
   8 * it under the terms of the GNU General Public License version 2, as
   9 * published by the Free Software Foundation.
  10 */
  11
  12#include <linux/i2c.h>
  13#include <linux/irq.h>
  14#include <linux/slab.h>
  15#include <linux/input.h>
  16#include <linux/module.h>
  17#include <linux/interrupt.h>
  18#include <linux/gpio.h>
  19#include <linux/delay.h>
  20#include <linux/input/gp2ap002a00f.h>
  21
  22struct gp2a_data {
  23        struct input_dev *input;
  24        const struct gp2a_platform_data *pdata;
  25        struct i2c_client *i2c_client;
  26};
  27
  28enum gp2a_addr {
  29        GP2A_ADDR_PROX  = 0x0,
  30        GP2A_ADDR_GAIN  = 0x1,
  31        GP2A_ADDR_HYS   = 0x2,
  32        GP2A_ADDR_CYCLE = 0x3,
  33        GP2A_ADDR_OPMOD = 0x4,
  34        GP2A_ADDR_CON   = 0x6
  35};
  36
  37enum gp2a_controls {
  38        /* Software Shutdown control: 0 = shutdown, 1 = normal operation */
  39        GP2A_CTRL_SSD   = 0x01
  40};
  41
  42static int gp2a_report(struct gp2a_data *dt)
  43{
  44        int vo = gpio_get_value(dt->pdata->vout_gpio);
  45
  46        input_report_switch(dt->input, SW_FRONT_PROXIMITY, !vo);
  47        input_sync(dt->input);
  48
  49        return 0;
  50}
  51
  52static irqreturn_t gp2a_irq(int irq, void *handle)
  53{
  54        struct gp2a_data *dt = handle;
  55
  56        gp2a_report(dt);
  57
  58        return IRQ_HANDLED;
  59}
  60
  61static int gp2a_enable(struct gp2a_data *dt)
  62{
  63        return i2c_smbus_write_byte_data(dt->i2c_client, GP2A_ADDR_OPMOD,
  64                                         GP2A_CTRL_SSD);
  65}
  66
  67static int gp2a_disable(struct gp2a_data *dt)
  68{
  69        return i2c_smbus_write_byte_data(dt->i2c_client, GP2A_ADDR_OPMOD,
  70                                         0x00);
  71}
  72
  73static int gp2a_device_open(struct input_dev *dev)
  74{
  75        struct gp2a_data *dt = input_get_drvdata(dev);
  76        int error;
  77
  78        error = gp2a_enable(dt);
  79        if (error < 0) {
  80                dev_err(&dt->i2c_client->dev,
  81                        "unable to activate, err %d\n", error);
  82                return error;
  83        }
  84
  85        gp2a_report(dt);
  86
  87        return 0;
  88}
  89
  90static void gp2a_device_close(struct input_dev *dev)
  91{
  92        struct gp2a_data *dt = input_get_drvdata(dev);
  93        int error;
  94
  95        error = gp2a_disable(dt);
  96        if (error < 0)
  97                dev_err(&dt->i2c_client->dev,
  98                        "unable to deactivate, err %d\n", error);
  99}
 100
 101static int gp2a_initialize(struct gp2a_data *dt)
 102{
 103        int error;
 104
 105        error = i2c_smbus_write_byte_data(dt->i2c_client, GP2A_ADDR_GAIN,
 106                                          0x08);
 107        if (error < 0)
 108                return error;
 109
 110        error = i2c_smbus_write_byte_data(dt->i2c_client, GP2A_ADDR_HYS,
 111                                          0xc2);
 112        if (error < 0)
 113                return error;
 114
 115        error = i2c_smbus_write_byte_data(dt->i2c_client, GP2A_ADDR_CYCLE,
 116                                          0x04);
 117        if (error < 0)
 118                return error;
 119
 120        error = gp2a_disable(dt);
 121
 122        return error;
 123}
 124
 125static int gp2a_probe(struct i2c_client *client,
 126                                const struct i2c_device_id *id)
 127{
 128        const struct gp2a_platform_data *pdata = client->dev.platform_data;
 129        struct gp2a_data *dt;
 130        int error;
 131
 132        if (!pdata)
 133                return -EINVAL;
 134
 135        if (pdata->hw_setup) {
 136                error = pdata->hw_setup(client);
 137                if (error < 0)
 138                        return error;
 139        }
 140
 141        error = gpio_request_one(pdata->vout_gpio, GPIOF_IN, GP2A_I2C_NAME);
 142        if (error)
 143                goto err_hw_shutdown;
 144
 145        dt = kzalloc(sizeof(struct gp2a_data), GFP_KERNEL);
 146        if (!dt) {
 147                error = -ENOMEM;
 148                goto err_free_gpio;
 149        }
 150
 151        dt->pdata = pdata;
 152        dt->i2c_client = client;
 153
 154        error = gp2a_initialize(dt);
 155        if (error < 0)
 156                goto err_free_mem;
 157
 158        dt->input = input_allocate_device();
 159        if (!dt->input) {
 160                error = -ENOMEM;
 161                goto err_free_mem;
 162        }
 163
 164        input_set_drvdata(dt->input, dt);
 165
 166        dt->input->open = gp2a_device_open;
 167        dt->input->close = gp2a_device_close;
 168        dt->input->name = GP2A_I2C_NAME;
 169        dt->input->id.bustype = BUS_I2C;
 170        dt->input->dev.parent = &client->dev;
 171
 172        input_set_capability(dt->input, EV_SW, SW_FRONT_PROXIMITY);
 173
 174        error = request_threaded_irq(client->irq, NULL, gp2a_irq,
 175                        IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING |
 176                                IRQF_ONESHOT,
 177                        GP2A_I2C_NAME, dt);
 178        if (error) {
 179                dev_err(&client->dev, "irq request failed\n");
 180                goto err_free_input_dev;
 181        }
 182
 183        error = input_register_device(dt->input);
 184        if (error) {
 185                dev_err(&client->dev, "device registration failed\n");
 186                goto err_free_irq;
 187        }
 188
 189        device_init_wakeup(&client->dev, pdata->wakeup);
 190        i2c_set_clientdata(client, dt);
 191
 192        return 0;
 193
 194err_free_irq:
 195        free_irq(client->irq, dt);
 196err_free_input_dev:
 197        input_free_device(dt->input);
 198err_free_mem:
 199        kfree(dt);
 200err_free_gpio:
 201        gpio_free(pdata->vout_gpio);
 202err_hw_shutdown:
 203        if (pdata->hw_shutdown)
 204                pdata->hw_shutdown(client);
 205        return error;
 206}
 207
 208static int gp2a_remove(struct i2c_client *client)
 209{
 210        struct gp2a_data *dt = i2c_get_clientdata(client);
 211        const struct gp2a_platform_data *pdata = dt->pdata;
 212
 213        device_init_wakeup(&client->dev, false);
 214
 215        free_irq(client->irq, dt);
 216
 217        input_unregister_device(dt->input);
 218        kfree(dt);
 219
 220        gpio_free(pdata->vout_gpio);
 221
 222        if (pdata->hw_shutdown)
 223                pdata->hw_shutdown(client);
 224
 225        return 0;
 226}
 227
 228#ifdef CONFIG_PM_SLEEP
 229static int gp2a_suspend(struct device *dev)
 230{
 231        struct i2c_client *client = to_i2c_client(dev);
 232        struct gp2a_data *dt = i2c_get_clientdata(client);
 233        int retval = 0;
 234
 235        if (device_may_wakeup(&client->dev)) {
 236                enable_irq_wake(client->irq);
 237        } else {
 238                mutex_lock(&dt->input->mutex);
 239                if (dt->input->users)
 240                        retval = gp2a_disable(dt);
 241                mutex_unlock(&dt->input->mutex);
 242        }
 243
 244        return retval;
 245}
 246
 247static int gp2a_resume(struct device *dev)
 248{
 249        struct i2c_client *client = to_i2c_client(dev);
 250        struct gp2a_data *dt = i2c_get_clientdata(client);
 251        int retval = 0;
 252
 253        if (device_may_wakeup(&client->dev)) {
 254                disable_irq_wake(client->irq);
 255        } else {
 256                mutex_lock(&dt->input->mutex);
 257                if (dt->input->users)
 258                        retval = gp2a_enable(dt);
 259                mutex_unlock(&dt->input->mutex);
 260        }
 261
 262        return retval;
 263}
 264#endif
 265
 266static SIMPLE_DEV_PM_OPS(gp2a_pm, gp2a_suspend, gp2a_resume);
 267
 268static const struct i2c_device_id gp2a_i2c_id[] = {
 269        { GP2A_I2C_NAME, 0 },
 270        { }
 271};
 272
 273static struct i2c_driver gp2a_i2c_driver = {
 274        .driver = {
 275                .name   = GP2A_I2C_NAME,
 276                .owner  = THIS_MODULE,
 277                .pm     = &gp2a_pm,
 278        },
 279        .probe          = gp2a_probe,
 280        .remove         = gp2a_remove,
 281        .id_table       = gp2a_i2c_id,
 282};
 283
 284module_i2c_driver(gp2a_i2c_driver);
 285
 286MODULE_AUTHOR("Courtney Cavin <courtney.cavin@sonyericsson.com>");
 287MODULE_DESCRIPTION("Sharp GP2AP002A00F I2C Proximity/Opto sensor driver");
 288MODULE_LICENSE("GPL v2");
 289