Linux Audio

Check our new training course

Loading...
v3.1
  1/*
  2 * Driver for a keypad w/16 buttons connected to a PCF8574 I2C I/O expander
  3 *
  4 * Copyright 2005-2008 Analog Devices Inc.
  5 *
  6 * Licensed under the GPL-2 or later.
  7 */
  8
  9#include <linux/module.h>
 10#include <linux/init.h>
 11#include <linux/input.h>
 12#include <linux/interrupt.h>
 13#include <linux/i2c.h>
 14#include <linux/slab.h>
 15#include <linux/workqueue.h>
 16
 17#define DRV_NAME "pcf8574_keypad"
 18
 19static const unsigned char pcf8574_kp_btncode[] = {
 20	[0] = KEY_RESERVED,
 21	[1] = KEY_ENTER,
 22	[2] = KEY_BACKSLASH,
 23	[3] = KEY_0,
 24	[4] = KEY_RIGHTBRACE,
 25	[5] = KEY_C,
 26	[6] = KEY_9,
 27	[7] = KEY_8,
 28	[8] = KEY_7,
 29	[9] = KEY_B,
 30	[10] = KEY_6,
 31	[11] = KEY_5,
 32	[12] = KEY_4,
 33	[13] = KEY_A,
 34	[14] = KEY_3,
 35	[15] = KEY_2,
 36	[16] = KEY_1
 37};
 38
 39struct kp_data {
 40	unsigned short btncode[ARRAY_SIZE(pcf8574_kp_btncode)];
 41	struct input_dev *idev;
 42	struct i2c_client *client;
 43	char name[64];
 44	char phys[32];
 45	unsigned char laststate;
 46};
 47
 48static short read_state(struct kp_data *lp)
 49{
 50	unsigned char x, y, a, b;
 51
 52	i2c_smbus_write_byte(lp->client, 240);
 53	x = 0xF & (~(i2c_smbus_read_byte(lp->client) >> 4));
 54
 55	i2c_smbus_write_byte(lp->client, 15);
 56	y = 0xF & (~i2c_smbus_read_byte(lp->client));
 57
 58	for (a = 0; x > 0; a++)
 59		x = x >> 1;
 60	for (b = 0; y > 0; b++)
 61		y = y >> 1;
 62
 63	return ((a - 1) * 4) + b;
 64}
 65
 66static irqreturn_t pcf8574_kp_irq_handler(int irq, void *dev_id)
 67{
 68	struct kp_data *lp = dev_id;
 69	unsigned char nextstate = read_state(lp);
 70
 71	if (lp->laststate != nextstate) {
 72		int key_down = nextstate < ARRAY_SIZE(lp->btncode);
 73		unsigned short keycode = key_down ?
 74			lp->btncode[nextstate] : lp->btncode[lp->laststate];
 75
 76		input_report_key(lp->idev, keycode, key_down);
 77		input_sync(lp->idev);
 78
 79		lp->laststate = nextstate;
 80	}
 81
 82	return IRQ_HANDLED;
 83}
 84
 85static int __devinit pcf8574_kp_probe(struct i2c_client *client, const struct i2c_device_id *id)
 86{
 87	int i, ret;
 88	struct input_dev *idev;
 89	struct kp_data *lp;
 90
 91	if (i2c_smbus_write_byte(client, 240) < 0) {
 92		dev_err(&client->dev, "probe: write fail\n");
 93		return -ENODEV;
 94	}
 95
 96	lp = kzalloc(sizeof(*lp), GFP_KERNEL);
 97	if (!lp)
 98		return -ENOMEM;
 99
100	idev = input_allocate_device();
101	if (!idev) {
102		dev_err(&client->dev, "Can't allocate input device\n");
103		ret = -ENOMEM;
104		goto fail_allocate;
105	}
106
107	lp->idev = idev;
108	lp->client = client;
109
110	idev->evbit[0] = BIT_MASK(EV_KEY);
111	idev->keycode = lp->btncode;
112	idev->keycodesize = sizeof(lp->btncode[0]);
113	idev->keycodemax = ARRAY_SIZE(lp->btncode);
114
115	for (i = 0; i < ARRAY_SIZE(pcf8574_kp_btncode); i++) {
116		lp->btncode[i] = pcf8574_kp_btncode[i];
117		__set_bit(lp->btncode[i] & KEY_MAX, idev->keybit);
 
 
118	}
 
119
120	sprintf(lp->name, DRV_NAME);
121	sprintf(lp->phys, "kp_data/input0");
122
123	idev->name = lp->name;
124	idev->phys = lp->phys;
125	idev->id.bustype = BUS_I2C;
126	idev->id.vendor = 0x0001;
127	idev->id.product = 0x0001;
128	idev->id.version = 0x0100;
129
130	lp->laststate = read_state(lp);
131
132	ret = request_threaded_irq(client->irq, NULL, pcf8574_kp_irq_handler,
133				   IRQF_TRIGGER_LOW | IRQF_ONESHOT,
134				   DRV_NAME, lp);
135	if (ret) {
136		dev_err(&client->dev, "IRQ %d is not free\n", client->irq);
137		goto fail_free_device;
138	}
139
140	ret = input_register_device(idev);
141	if (ret) {
142		dev_err(&client->dev, "input_register_device() failed\n");
143		goto fail_free_irq;
144	}
145
146	i2c_set_clientdata(client, lp);
147	return 0;
148
149 fail_free_irq:
150	free_irq(client->irq, lp);
151 fail_free_device:
152	input_free_device(idev);
153 fail_allocate:
154	kfree(lp);
155
156	return ret;
157}
158
159static int __devexit pcf8574_kp_remove(struct i2c_client *client)
160{
161	struct kp_data *lp = i2c_get_clientdata(client);
162
163	free_irq(client->irq, lp);
164
165	input_unregister_device(lp->idev);
166	kfree(lp);
167
168	return 0;
169}
170
171#ifdef CONFIG_PM
172static int pcf8574_kp_resume(struct device *dev)
173{
174	struct i2c_client *client = to_i2c_client(dev);
175
176	enable_irq(client->irq);
177
178	return 0;
179}
180
181static int pcf8574_kp_suspend(struct device *dev)
182{
183	struct i2c_client *client = to_i2c_client(dev);
184
185	disable_irq(client->irq);
186
187	return 0;
188}
189
190static const struct dev_pm_ops pcf8574_kp_pm_ops = {
191	.suspend	= pcf8574_kp_suspend,
192	.resume		= pcf8574_kp_resume,
193};
194
195#else
196# define pcf8574_kp_resume  NULL
197# define pcf8574_kp_suspend NULL
198#endif
199
200static const struct i2c_device_id pcf8574_kp_id[] = {
201	{ DRV_NAME, 0 },
202	{ }
203};
204MODULE_DEVICE_TABLE(i2c, pcf8574_kp_id);
205
206static struct i2c_driver pcf8574_kp_driver = {
207	.driver = {
208		.name  = DRV_NAME,
209		.owner = THIS_MODULE,
210#ifdef CONFIG_PM
211		.pm = &pcf8574_kp_pm_ops,
212#endif
213	},
214	.probe    = pcf8574_kp_probe,
215	.remove   = __devexit_p(pcf8574_kp_remove),
216	.id_table = pcf8574_kp_id,
217};
218
219static int __init pcf8574_kp_init(void)
220{
221	return i2c_add_driver(&pcf8574_kp_driver);
222}
223module_init(pcf8574_kp_init);
224
225static void __exit pcf8574_kp_exit(void)
226{
227	i2c_del_driver(&pcf8574_kp_driver);
228}
229module_exit(pcf8574_kp_exit);
230
231MODULE_AUTHOR("Michael Hennerich");
232MODULE_DESCRIPTION("Keypad input driver for 16 keys connected to PCF8574");
233MODULE_LICENSE("GPL");
v4.6
  1/*
  2 * Driver for a keypad w/16 buttons connected to a PCF8574 I2C I/O expander
  3 *
  4 * Copyright 2005-2008 Analog Devices Inc.
  5 *
  6 * Licensed under the GPL-2 or later.
  7 */
  8
  9#include <linux/module.h>
 
 10#include <linux/input.h>
 11#include <linux/interrupt.h>
 12#include <linux/i2c.h>
 13#include <linux/slab.h>
 14#include <linux/workqueue.h>
 15
 16#define DRV_NAME "pcf8574_keypad"
 17
 18static const unsigned char pcf8574_kp_btncode[] = {
 19	[0] = KEY_RESERVED,
 20	[1] = KEY_ENTER,
 21	[2] = KEY_BACKSLASH,
 22	[3] = KEY_0,
 23	[4] = KEY_RIGHTBRACE,
 24	[5] = KEY_C,
 25	[6] = KEY_9,
 26	[7] = KEY_8,
 27	[8] = KEY_7,
 28	[9] = KEY_B,
 29	[10] = KEY_6,
 30	[11] = KEY_5,
 31	[12] = KEY_4,
 32	[13] = KEY_A,
 33	[14] = KEY_3,
 34	[15] = KEY_2,
 35	[16] = KEY_1
 36};
 37
 38struct kp_data {
 39	unsigned short btncode[ARRAY_SIZE(pcf8574_kp_btncode)];
 40	struct input_dev *idev;
 41	struct i2c_client *client;
 42	char name[64];
 43	char phys[32];
 44	unsigned char laststate;
 45};
 46
 47static short read_state(struct kp_data *lp)
 48{
 49	unsigned char x, y, a, b;
 50
 51	i2c_smbus_write_byte(lp->client, 240);
 52	x = 0xF & (~(i2c_smbus_read_byte(lp->client) >> 4));
 53
 54	i2c_smbus_write_byte(lp->client, 15);
 55	y = 0xF & (~i2c_smbus_read_byte(lp->client));
 56
 57	for (a = 0; x > 0; a++)
 58		x = x >> 1;
 59	for (b = 0; y > 0; b++)
 60		y = y >> 1;
 61
 62	return ((a - 1) * 4) + b;
 63}
 64
 65static irqreturn_t pcf8574_kp_irq_handler(int irq, void *dev_id)
 66{
 67	struct kp_data *lp = dev_id;
 68	unsigned char nextstate = read_state(lp);
 69
 70	if (lp->laststate != nextstate) {
 71		int key_down = nextstate < ARRAY_SIZE(lp->btncode);
 72		unsigned short keycode = key_down ?
 73			lp->btncode[nextstate] : lp->btncode[lp->laststate];
 74
 75		input_report_key(lp->idev, keycode, key_down);
 76		input_sync(lp->idev);
 77
 78		lp->laststate = nextstate;
 79	}
 80
 81	return IRQ_HANDLED;
 82}
 83
 84static int pcf8574_kp_probe(struct i2c_client *client, const struct i2c_device_id *id)
 85{
 86	int i, ret;
 87	struct input_dev *idev;
 88	struct kp_data *lp;
 89
 90	if (i2c_smbus_write_byte(client, 240) < 0) {
 91		dev_err(&client->dev, "probe: write fail\n");
 92		return -ENODEV;
 93	}
 94
 95	lp = kzalloc(sizeof(*lp), GFP_KERNEL);
 96	if (!lp)
 97		return -ENOMEM;
 98
 99	idev = input_allocate_device();
100	if (!idev) {
101		dev_err(&client->dev, "Can't allocate input device\n");
102		ret = -ENOMEM;
103		goto fail_allocate;
104	}
105
106	lp->idev = idev;
107	lp->client = client;
108
109	idev->evbit[0] = BIT_MASK(EV_KEY);
110	idev->keycode = lp->btncode;
111	idev->keycodesize = sizeof(lp->btncode[0]);
112	idev->keycodemax = ARRAY_SIZE(lp->btncode);
113
114	for (i = 0; i < ARRAY_SIZE(pcf8574_kp_btncode); i++) {
115		if (lp->btncode[i] <= KEY_MAX) {
116			lp->btncode[i] = pcf8574_kp_btncode[i];
117			__set_bit(lp->btncode[i], idev->keybit);
118		}
119	}
120	__clear_bit(KEY_RESERVED, idev->keybit);
121
122	sprintf(lp->name, DRV_NAME);
123	sprintf(lp->phys, "kp_data/input0");
124
125	idev->name = lp->name;
126	idev->phys = lp->phys;
127	idev->id.bustype = BUS_I2C;
128	idev->id.vendor = 0x0001;
129	idev->id.product = 0x0001;
130	idev->id.version = 0x0100;
131
132	lp->laststate = read_state(lp);
133
134	ret = request_threaded_irq(client->irq, NULL, pcf8574_kp_irq_handler,
135				   IRQF_TRIGGER_LOW | IRQF_ONESHOT,
136				   DRV_NAME, lp);
137	if (ret) {
138		dev_err(&client->dev, "IRQ %d is not free\n", client->irq);
139		goto fail_free_device;
140	}
141
142	ret = input_register_device(idev);
143	if (ret) {
144		dev_err(&client->dev, "input_register_device() failed\n");
145		goto fail_free_irq;
146	}
147
148	i2c_set_clientdata(client, lp);
149	return 0;
150
151 fail_free_irq:
152	free_irq(client->irq, lp);
153 fail_free_device:
154	input_free_device(idev);
155 fail_allocate:
156	kfree(lp);
157
158	return ret;
159}
160
161static int pcf8574_kp_remove(struct i2c_client *client)
162{
163	struct kp_data *lp = i2c_get_clientdata(client);
164
165	free_irq(client->irq, lp);
166
167	input_unregister_device(lp->idev);
168	kfree(lp);
169
170	return 0;
171}
172
173#ifdef CONFIG_PM
174static int pcf8574_kp_resume(struct device *dev)
175{
176	struct i2c_client *client = to_i2c_client(dev);
177
178	enable_irq(client->irq);
179
180	return 0;
181}
182
183static int pcf8574_kp_suspend(struct device *dev)
184{
185	struct i2c_client *client = to_i2c_client(dev);
186
187	disable_irq(client->irq);
188
189	return 0;
190}
191
192static const struct dev_pm_ops pcf8574_kp_pm_ops = {
193	.suspend	= pcf8574_kp_suspend,
194	.resume		= pcf8574_kp_resume,
195};
196
197#else
198# define pcf8574_kp_resume  NULL
199# define pcf8574_kp_suspend NULL
200#endif
201
202static const struct i2c_device_id pcf8574_kp_id[] = {
203	{ DRV_NAME, 0 },
204	{ }
205};
206MODULE_DEVICE_TABLE(i2c, pcf8574_kp_id);
207
208static struct i2c_driver pcf8574_kp_driver = {
209	.driver = {
210		.name  = DRV_NAME,
 
211#ifdef CONFIG_PM
212		.pm = &pcf8574_kp_pm_ops,
213#endif
214	},
215	.probe    = pcf8574_kp_probe,
216	.remove   = pcf8574_kp_remove,
217	.id_table = pcf8574_kp_id,
218};
219
220module_i2c_driver(pcf8574_kp_driver);
 
 
 
 
 
 
 
 
 
 
221
222MODULE_AUTHOR("Michael Hennerich");
223MODULE_DESCRIPTION("Keypad input driver for 16 keys connected to PCF8574");
224MODULE_LICENSE("GPL");