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 = dev_get_platdata(&client->dev);
 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        free_irq(client->irq, dt);
 214
 215        input_unregister_device(dt->input);
 216        kfree(dt);
 217
 218        gpio_free(pdata->vout_gpio);
 219
 220        if (pdata->hw_shutdown)
 221                pdata->hw_shutdown(client);
 222
 223        return 0;
 224}
 225
 226static int __maybe_unused gp2a_suspend(struct device *dev)
 227{
 228        struct i2c_client *client = to_i2c_client(dev);
 229        struct gp2a_data *dt = i2c_get_clientdata(client);
 230        int retval = 0;
 231
 232        if (device_may_wakeup(&client->dev)) {
 233                enable_irq_wake(client->irq);
 234        } else {
 235                mutex_lock(&dt->input->mutex);
 236                if (dt->input->users)
 237                        retval = gp2a_disable(dt);
 238                mutex_unlock(&dt->input->mutex);
 239        }
 240
 241        return retval;
 242}
 243
 244static int __maybe_unused gp2a_resume(struct device *dev)
 245{
 246        struct i2c_client *client = to_i2c_client(dev);
 247        struct gp2a_data *dt = i2c_get_clientdata(client);
 248        int retval = 0;
 249
 250        if (device_may_wakeup(&client->dev)) {
 251                disable_irq_wake(client->irq);
 252        } else {
 253                mutex_lock(&dt->input->mutex);
 254                if (dt->input->users)
 255                        retval = gp2a_enable(dt);
 256                mutex_unlock(&dt->input->mutex);
 257        }
 258
 259        return retval;
 260}
 261
 262static SIMPLE_DEV_PM_OPS(gp2a_pm, gp2a_suspend, gp2a_resume);
 263
 264static const struct i2c_device_id gp2a_i2c_id[] = {
 265        { GP2A_I2C_NAME, 0 },
 266        { }
 267};
 268MODULE_DEVICE_TABLE(i2c, gp2a_i2c_id);
 269
 270static struct i2c_driver gp2a_i2c_driver = {
 271        .driver = {
 272                .name   = GP2A_I2C_NAME,
 273                .pm     = &gp2a_pm,
 274        },
 275        .probe          = gp2a_probe,
 276        .remove         = gp2a_remove,
 277        .id_table       = gp2a_i2c_id,
 278};
 279
 280module_i2c_driver(gp2a_i2c_driver);
 281
 282MODULE_AUTHOR("Courtney Cavin <courtney.cavin@sonyericsson.com>");
 283MODULE_DESCRIPTION("Sharp GP2AP002A00F I2C Proximity/Opto sensor driver");
 284MODULE_LICENSE("GPL v2");
 285