Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

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