Linux Audio

Check our new training course

Loading...
Note: File does not exist in v3.1.
  1/*
  2 * LM8333 keypad driver
  3 * Copyright (C) 2012 Wolfram Sang, Pengutronix <w.sang@pengutronix.de>
  4 *
  5 * This program is free software; you can redistribute it and/or modify
  6 * it under the terms of the GNU General Public License as published by
  7 * the Free Software Foundation; either version 2 of the License.
  8 */
  9
 10#include <linux/module.h>
 11#include <linux/slab.h>
 12#include <linux/irq.h>
 13#include <linux/i2c.h>
 14#include <linux/interrupt.h>
 15#include <linux/input/matrix_keypad.h>
 16#include <linux/input/lm8333.h>
 17
 18#define LM8333_FIFO_READ		0x20
 19#define LM8333_DEBOUNCE			0x22
 20#define LM8333_READ_INT			0xD0
 21#define LM8333_ACTIVE			0xE4
 22#define LM8333_READ_ERROR		0xF0
 23
 24#define LM8333_KEYPAD_IRQ		(1 << 0)
 25#define LM8333_ERROR_IRQ		(1 << 3)
 26
 27#define LM8333_ERROR_KEYOVR		0x04
 28#define LM8333_ERROR_FIFOOVR		0x40
 29
 30#define LM8333_FIFO_TRANSFER_SIZE	16
 31
 32#define LM8333_NUM_ROWS		8
 33#define LM8333_NUM_COLS		16
 34#define LM8333_ROW_SHIFT	4
 35
 36struct lm8333 {
 37	struct i2c_client *client;
 38	struct input_dev *input;
 39	unsigned short keycodes[LM8333_NUM_ROWS << LM8333_ROW_SHIFT];
 40};
 41
 42/* The accessors try twice because the first access may be needed for wakeup */
 43#define LM8333_READ_RETRIES 2
 44
 45int lm8333_read8(struct lm8333 *lm8333, u8 cmd)
 46{
 47	int retries = 0, ret;
 48
 49	do {
 50		ret = i2c_smbus_read_byte_data(lm8333->client, cmd);
 51	} while (ret < 0 && retries++ < LM8333_READ_RETRIES);
 52
 53	return ret;
 54}
 55
 56int lm8333_write8(struct lm8333 *lm8333, u8 cmd, u8 val)
 57{
 58	int retries = 0, ret;
 59
 60	do {
 61		ret = i2c_smbus_write_byte_data(lm8333->client, cmd, val);
 62	} while (ret < 0 && retries++ < LM8333_READ_RETRIES);
 63
 64	return ret;
 65}
 66
 67int lm8333_read_block(struct lm8333 *lm8333, u8 cmd, u8 len, u8 *buf)
 68{
 69	int retries = 0, ret;
 70
 71	do {
 72		ret = i2c_smbus_read_i2c_block_data(lm8333->client,
 73						    cmd, len, buf);
 74	} while (ret < 0 && retries++ < LM8333_READ_RETRIES);
 75
 76	return ret;
 77}
 78
 79static void lm8333_key_handler(struct lm8333 *lm8333)
 80{
 81	struct input_dev *input = lm8333->input;
 82	u8 keys[LM8333_FIFO_TRANSFER_SIZE];
 83	u8 code, pressed;
 84	int i, ret;
 85
 86	ret = lm8333_read_block(lm8333, LM8333_FIFO_READ,
 87				LM8333_FIFO_TRANSFER_SIZE, keys);
 88	if (ret != LM8333_FIFO_TRANSFER_SIZE) {
 89		dev_err(&lm8333->client->dev,
 90			"Error %d while reading FIFO\n", ret);
 91		return;
 92	}
 93
 94	for (i = 0; keys[i] && i < LM8333_FIFO_TRANSFER_SIZE; i++) {
 95		pressed = keys[i] & 0x80;
 96		code = keys[i] & 0x7f;
 97
 98		input_event(input, EV_MSC, MSC_SCAN, code);
 99		input_report_key(input, lm8333->keycodes[code], pressed);
100	}
101
102	input_sync(input);
103}
104
105static irqreturn_t lm8333_irq_thread(int irq, void *data)
106{
107	struct lm8333 *lm8333 = data;
108	u8 status = lm8333_read8(lm8333, LM8333_READ_INT);
109
110	if (!status)
111		return IRQ_NONE;
112
113	if (status & LM8333_ERROR_IRQ) {
114		u8 err = lm8333_read8(lm8333, LM8333_READ_ERROR);
115
116		if (err & (LM8333_ERROR_KEYOVR | LM8333_ERROR_FIFOOVR)) {
117			u8 dummy[LM8333_FIFO_TRANSFER_SIZE];
118
119			lm8333_read_block(lm8333, LM8333_FIFO_READ,
120					LM8333_FIFO_TRANSFER_SIZE, dummy);
121		}
122		dev_err(&lm8333->client->dev, "Got error %02x\n", err);
123	}
124
125	if (status & LM8333_KEYPAD_IRQ)
126		lm8333_key_handler(lm8333);
127
128	return IRQ_HANDLED;
129}
130
131static int __devinit lm8333_probe(struct i2c_client *client,
132				  const struct i2c_device_id *id)
133{
134	const struct lm8333_platform_data *pdata = client->dev.platform_data;
135	struct lm8333 *lm8333;
136	struct input_dev *input;
137	int err, active_time;
138
139	if (!pdata)
140		return -EINVAL;
141
142	active_time = pdata->active_time ?: 500;
143	if (active_time / 3 <= pdata->debounce_time / 3) {
144		dev_err(&client->dev, "Active time not big enough!\n");
145		return -EINVAL;
146	}
147
148	lm8333 = kzalloc(sizeof(*lm8333), GFP_KERNEL);
149	input = input_allocate_device();
150	if (!lm8333 || !input) {
151		err = -ENOMEM;
152		goto free_mem;
153	}
154
155	lm8333->client = client;
156	lm8333->input = input;
157
158	input->name = client->name;
159	input->dev.parent = &client->dev;
160	input->id.bustype = BUS_I2C;
161
162	input_set_capability(input, EV_MSC, MSC_SCAN);
163
164	err = matrix_keypad_build_keymap(pdata->matrix_data, NULL,
165					 LM8333_NUM_ROWS, LM8333_NUM_COLS,
166					 lm8333->keycodes, input);
167	if (err)
168		goto free_mem;
169
170	if (pdata->debounce_time) {
171		err = lm8333_write8(lm8333, LM8333_DEBOUNCE,
172				    pdata->debounce_time / 3);
173		if (err)
174			dev_warn(&client->dev, "Unable to set debounce time\n");
175	}
176
177	if (pdata->active_time) {
178		err = lm8333_write8(lm8333, LM8333_ACTIVE,
179				    pdata->active_time / 3);
180		if (err)
181			dev_warn(&client->dev, "Unable to set active time\n");
182	}
183
184	err = request_threaded_irq(client->irq, NULL, lm8333_irq_thread,
185				   IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
186				   "lm8333", lm8333);
187	if (err)
188		goto free_mem;
189
190	err = input_register_device(input);
191	if (err)
192		goto free_irq;
193
194	i2c_set_clientdata(client, lm8333);
195	return 0;
196
197 free_irq:
198	free_irq(client->irq, lm8333);
199 free_mem:
200	input_free_device(input);
201	kfree(lm8333);
202	return err;
203}
204
205static int __devexit lm8333_remove(struct i2c_client *client)
206{
207	struct lm8333 *lm8333 = i2c_get_clientdata(client);
208
209	free_irq(client->irq, lm8333);
210	input_unregister_device(lm8333->input);
211	kfree(lm8333);
212
213	return 0;
214}
215
216static const struct i2c_device_id lm8333_id[] = {
217	{ "lm8333", 0 },
218	{ }
219};
220MODULE_DEVICE_TABLE(i2c, lm8333_id);
221
222static struct i2c_driver lm8333_driver = {
223	.driver = {
224		.name		= "lm8333",
225		.owner		= THIS_MODULE,
226	},
227	.probe		= lm8333_probe,
228	.remove		= __devexit_p(lm8333_remove),
229	.id_table	= lm8333_id,
230};
231module_i2c_driver(lm8333_driver);
232
233MODULE_AUTHOR("Wolfram Sang <w.sang@pengutronix.de>");
234MODULE_DESCRIPTION("LM8333 keyboard driver");
235MODULE_LICENSE("GPL v2");