| Bryan Wu | 31a6296 | 2010-03-21 23:23:24 -0700 | [diff] [blame] | 1 | /* | 
 | 2 |  * AD714X CapTouch Programmable Controller driver (I2C bus) | 
 | 3 |  * | 
| Michael Hennerich | 9eff794 | 2011-08-22 09:45:42 -0700 | [diff] [blame] | 4 |  * Copyright 2009-2011 Analog Devices Inc. | 
| Bryan Wu | 31a6296 | 2010-03-21 23:23:24 -0700 | [diff] [blame] | 5 |  * | 
 | 6 |  * Licensed under the GPL-2 or later. | 
 | 7 |  */ | 
 | 8 |  | 
 | 9 | #include <linux/input.h>	/* BUS_I2C */ | 
 | 10 | #include <linux/i2c.h> | 
 | 11 | #include <linux/module.h> | 
 | 12 | #include <linux/types.h> | 
| Mark Brown | 6b7cfd1 | 2011-02-11 08:49:05 -0800 | [diff] [blame] | 13 | #include <linux/pm.h> | 
| Bryan Wu | 31a6296 | 2010-03-21 23:23:24 -0700 | [diff] [blame] | 14 | #include "ad714x.h" | 
 | 15 |  | 
 | 16 | #ifdef CONFIG_PM | 
| Mark Brown | 6b7cfd1 | 2011-02-11 08:49:05 -0800 | [diff] [blame] | 17 | static int ad714x_i2c_suspend(struct device *dev) | 
| Bryan Wu | 31a6296 | 2010-03-21 23:23:24 -0700 | [diff] [blame] | 18 | { | 
| Mark Brown | 6b7cfd1 | 2011-02-11 08:49:05 -0800 | [diff] [blame] | 19 | 	return ad714x_disable(i2c_get_clientdata(to_i2c_client(dev))); | 
| Bryan Wu | 31a6296 | 2010-03-21 23:23:24 -0700 | [diff] [blame] | 20 | } | 
 | 21 |  | 
| Mark Brown | 6b7cfd1 | 2011-02-11 08:49:05 -0800 | [diff] [blame] | 22 | static int ad714x_i2c_resume(struct device *dev) | 
| Bryan Wu | 31a6296 | 2010-03-21 23:23:24 -0700 | [diff] [blame] | 23 | { | 
| Mark Brown | 6b7cfd1 | 2011-02-11 08:49:05 -0800 | [diff] [blame] | 24 | 	return ad714x_enable(i2c_get_clientdata(to_i2c_client(dev))); | 
| Bryan Wu | 31a6296 | 2010-03-21 23:23:24 -0700 | [diff] [blame] | 25 | } | 
| Bryan Wu | 31a6296 | 2010-03-21 23:23:24 -0700 | [diff] [blame] | 26 | #endif | 
 | 27 |  | 
| Mark Brown | 6b7cfd1 | 2011-02-11 08:49:05 -0800 | [diff] [blame] | 28 | static SIMPLE_DEV_PM_OPS(ad714x_i2c_pm, ad714x_i2c_suspend, ad714x_i2c_resume); | 
 | 29 |  | 
| Dmitry Torokhov | c0409fe | 2011-08-22 09:45:39 -0700 | [diff] [blame] | 30 | static int ad714x_i2c_write(struct ad714x_chip *chip, | 
 | 31 | 			    unsigned short reg, unsigned short data) | 
| Bryan Wu | 31a6296 | 2010-03-21 23:23:24 -0700 | [diff] [blame] | 32 | { | 
| Dmitry Torokhov | c0409fe | 2011-08-22 09:45:39 -0700 | [diff] [blame] | 33 | 	struct i2c_client *client = to_i2c_client(chip->dev); | 
 | 34 | 	int error; | 
| Bryan Wu | 31a6296 | 2010-03-21 23:23:24 -0700 | [diff] [blame] | 35 |  | 
| Dmitry Torokhov | c0409fe | 2011-08-22 09:45:39 -0700 | [diff] [blame] | 36 | 	chip->xfer_buf[0] = cpu_to_be16(reg); | 
 | 37 | 	chip->xfer_buf[1] = cpu_to_be16(data); | 
| Bryan Wu | 31a6296 | 2010-03-21 23:23:24 -0700 | [diff] [blame] | 38 |  | 
| Dmitry Torokhov | c0409fe | 2011-08-22 09:45:39 -0700 | [diff] [blame] | 39 | 	error = i2c_master_send(client, (u8 *)chip->xfer_buf, | 
 | 40 | 				2 * sizeof(*chip->xfer_buf)); | 
 | 41 | 	if (unlikely(error < 0)) { | 
 | 42 | 		dev_err(&client->dev, "I2C write error: %d\n", error); | 
 | 43 | 		return error; | 
| Bryan Wu | 31a6296 | 2010-03-21 23:23:24 -0700 | [diff] [blame] | 44 | 	} | 
 | 45 |  | 
| Dmitry Torokhov | c0409fe | 2011-08-22 09:45:39 -0700 | [diff] [blame] | 46 | 	return 0; | 
| Bryan Wu | 31a6296 | 2010-03-21 23:23:24 -0700 | [diff] [blame] | 47 | } | 
 | 48 |  | 
| Dmitry Torokhov | c0409fe | 2011-08-22 09:45:39 -0700 | [diff] [blame] | 49 | static int ad714x_i2c_read(struct ad714x_chip *chip, | 
| Michael Hennerich | 9eff794 | 2011-08-22 09:45:42 -0700 | [diff] [blame] | 50 | 			   unsigned short reg, unsigned short *data, size_t len) | 
| Bryan Wu | 31a6296 | 2010-03-21 23:23:24 -0700 | [diff] [blame] | 51 | { | 
| Dmitry Torokhov | c0409fe | 2011-08-22 09:45:39 -0700 | [diff] [blame] | 52 | 	struct i2c_client *client = to_i2c_client(chip->dev); | 
| Michael Hennerich | 9eff794 | 2011-08-22 09:45:42 -0700 | [diff] [blame] | 53 | 	int i; | 
| Dmitry Torokhov | c0409fe | 2011-08-22 09:45:39 -0700 | [diff] [blame] | 54 | 	int error; | 
| Bryan Wu | 31a6296 | 2010-03-21 23:23:24 -0700 | [diff] [blame] | 55 |  | 
| Dmitry Torokhov | c0409fe | 2011-08-22 09:45:39 -0700 | [diff] [blame] | 56 | 	chip->xfer_buf[0] = cpu_to_be16(reg); | 
| Bryan Wu | 31a6296 | 2010-03-21 23:23:24 -0700 | [diff] [blame] | 57 |  | 
| Dmitry Torokhov | c0409fe | 2011-08-22 09:45:39 -0700 | [diff] [blame] | 58 | 	error = i2c_master_send(client, (u8 *)chip->xfer_buf, | 
 | 59 | 				sizeof(*chip->xfer_buf)); | 
 | 60 | 	if (error >= 0) | 
 | 61 | 		error = i2c_master_recv(client, (u8 *)chip->xfer_buf, | 
| Michael Hennerich | 9eff794 | 2011-08-22 09:45:42 -0700 | [diff] [blame] | 62 | 					len * sizeof(*chip->xfer_buf)); | 
| Bryan Wu | 31a6296 | 2010-03-21 23:23:24 -0700 | [diff] [blame] | 63 |  | 
| Dmitry Torokhov | c0409fe | 2011-08-22 09:45:39 -0700 | [diff] [blame] | 64 | 	if (unlikely(error < 0)) { | 
 | 65 | 		dev_err(&client->dev, "I2C read error: %d\n", error); | 
 | 66 | 		return error; | 
 | 67 | 	} | 
 | 68 |  | 
| Michael Hennerich | 9eff794 | 2011-08-22 09:45:42 -0700 | [diff] [blame] | 69 | 	for (i = 0; i < len; i++) | 
 | 70 | 		data[i] = be16_to_cpu(chip->xfer_buf[i]); | 
 | 71 |  | 
| Dmitry Torokhov | c0409fe | 2011-08-22 09:45:39 -0700 | [diff] [blame] | 72 | 	return 0; | 
| Bryan Wu | 31a6296 | 2010-03-21 23:23:24 -0700 | [diff] [blame] | 73 | } | 
 | 74 |  | 
| Bill Pemberton | 5298cc4 | 2012-11-23 21:38:25 -0800 | [diff] [blame] | 75 | static int ad714x_i2c_probe(struct i2c_client *client, | 
| Bryan Wu | 31a6296 | 2010-03-21 23:23:24 -0700 | [diff] [blame] | 76 | 					const struct i2c_device_id *id) | 
 | 77 | { | 
 | 78 | 	struct ad714x_chip *chip; | 
 | 79 |  | 
 | 80 | 	chip = ad714x_probe(&client->dev, BUS_I2C, client->irq, | 
 | 81 | 			    ad714x_i2c_read, ad714x_i2c_write); | 
 | 82 | 	if (IS_ERR(chip)) | 
 | 83 | 		return PTR_ERR(chip); | 
 | 84 |  | 
 | 85 | 	i2c_set_clientdata(client, chip); | 
 | 86 |  | 
 | 87 | 	return 0; | 
 | 88 | } | 
 | 89 |  | 
| Bill Pemberton | e2619cf | 2012-11-23 21:50:47 -0800 | [diff] [blame] | 90 | static int ad714x_i2c_remove(struct i2c_client *client) | 
| Bryan Wu | 31a6296 | 2010-03-21 23:23:24 -0700 | [diff] [blame] | 91 | { | 
 | 92 | 	struct ad714x_chip *chip = i2c_get_clientdata(client); | 
 | 93 |  | 
 | 94 | 	ad714x_remove(chip); | 
| Bryan Wu | 31a6296 | 2010-03-21 23:23:24 -0700 | [diff] [blame] | 95 |  | 
 | 96 | 	return 0; | 
 | 97 | } | 
 | 98 |  | 
 | 99 | static const struct i2c_device_id ad714x_id[] = { | 
 | 100 | 	{ "ad7142_captouch", 0 }, | 
| Barry Song | 6c04d7b | 2010-03-21 23:23:29 -0700 | [diff] [blame] | 101 | 	{ "ad7143_captouch", 0 }, | 
| Bryan Wu | 31a6296 | 2010-03-21 23:23:24 -0700 | [diff] [blame] | 102 | 	{ "ad7147_captouch", 0 }, | 
| Barry Song | 6c04d7b | 2010-03-21 23:23:29 -0700 | [diff] [blame] | 103 | 	{ "ad7147a_captouch", 0 }, | 
 | 104 | 	{ "ad7148_captouch", 0 }, | 
| Bryan Wu | 31a6296 | 2010-03-21 23:23:24 -0700 | [diff] [blame] | 105 | 	{ } | 
 | 106 | }; | 
 | 107 | MODULE_DEVICE_TABLE(i2c, ad714x_id); | 
 | 108 |  | 
 | 109 | static struct i2c_driver ad714x_i2c_driver = { | 
 | 110 | 	.driver = { | 
 | 111 | 		.name = "ad714x_captouch", | 
| Mark Brown | 6b7cfd1 | 2011-02-11 08:49:05 -0800 | [diff] [blame] | 112 | 		.pm   = &ad714x_i2c_pm, | 
| Bryan Wu | 31a6296 | 2010-03-21 23:23:24 -0700 | [diff] [blame] | 113 | 	}, | 
 | 114 | 	.probe    = ad714x_i2c_probe, | 
| Bill Pemberton | 1cb0aa8 | 2012-11-23 21:27:39 -0800 | [diff] [blame] | 115 | 	.remove   = ad714x_i2c_remove, | 
| Bryan Wu | 31a6296 | 2010-03-21 23:23:24 -0700 | [diff] [blame] | 116 | 	.id_table = ad714x_id, | 
 | 117 | }; | 
 | 118 |  | 
| Axel Lin | 1b92c1c | 2012-03-16 23:05:41 -0700 | [diff] [blame] | 119 | module_i2c_driver(ad714x_i2c_driver); | 
| Bryan Wu | 31a6296 | 2010-03-21 23:23:24 -0700 | [diff] [blame] | 120 |  | 
 | 121 | MODULE_DESCRIPTION("Analog Devices AD714X Capacitance Touch Sensor I2C Bus Driver"); | 
 | 122 | MODULE_AUTHOR("Barry Song <21cnbao@gmail.com>"); | 
 | 123 | MODULE_LICENSE("GPL"); |