aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/input/keyboard/Kconfig10
-rw-r--r--drivers/input/keyboard/Makefile1
-rw-r--r--drivers/input/keyboard/lm8333.c236
-rw-r--r--include/linux/input/lm8333.h24
4 files changed, 271 insertions, 0 deletions
diff --git a/drivers/input/keyboard/Kconfig b/drivers/input/keyboard/Kconfig
index f354813a13e..7eaf93fe512 100644
--- a/drivers/input/keyboard/Kconfig
+++ b/drivers/input/keyboard/Kconfig
@@ -309,6 +309,16 @@ config KEYBOARD_LM8323
309 To compile this driver as a module, choose M here: the 309 To compile this driver as a module, choose M here: the
310 module will be called lm8323. 310 module will be called lm8323.
311 311
312config KEYBOARD_LM8333
313 tristate "LM8333 keypad chip"
314 depends on I2C
315 help
316 If you say yes here you get support for the National Semiconductor
317 LM8333 keypad controller.
318
319 To compile this driver as a module, choose M here: the
320 module will be called lm8333.
321
312config KEYBOARD_LOCOMO 322config KEYBOARD_LOCOMO
313 tristate "LoCoMo Keyboard Support" 323 tristate "LoCoMo Keyboard Support"
314 depends on SHARP_LOCOMO 324 depends on SHARP_LOCOMO
diff --git a/drivers/input/keyboard/Makefile b/drivers/input/keyboard/Makefile
index df7061f1291..b03b02456a8 100644
--- a/drivers/input/keyboard/Makefile
+++ b/drivers/input/keyboard/Makefile
@@ -24,6 +24,7 @@ obj-$(CONFIG_KEYBOARD_HP6XX) += jornada680_kbd.o
24obj-$(CONFIG_KEYBOARD_HP7XX) += jornada720_kbd.o 24obj-$(CONFIG_KEYBOARD_HP7XX) += jornada720_kbd.o
25obj-$(CONFIG_KEYBOARD_LKKBD) += lkkbd.o 25obj-$(CONFIG_KEYBOARD_LKKBD) += lkkbd.o
26obj-$(CONFIG_KEYBOARD_LM8323) += lm8323.o 26obj-$(CONFIG_KEYBOARD_LM8323) += lm8323.o
27obj-$(CONFIG_KEYBOARD_LM8333) += lm8333.o
27obj-$(CONFIG_KEYBOARD_LOCOMO) += locomokbd.o 28obj-$(CONFIG_KEYBOARD_LOCOMO) += locomokbd.o
28obj-$(CONFIG_KEYBOARD_MAPLE) += maple_keyb.o 29obj-$(CONFIG_KEYBOARD_MAPLE) += maple_keyb.o
29obj-$(CONFIG_KEYBOARD_MATRIX) += matrix_keypad.o 30obj-$(CONFIG_KEYBOARD_MATRIX) += matrix_keypad.o
diff --git a/drivers/input/keyboard/lm8333.c b/drivers/input/keyboard/lm8333.c
new file mode 100644
index 00000000000..9a8c4a6cf5c
--- /dev/null
+++ b/drivers/input/keyboard/lm8333.c
@@ -0,0 +1,236 @@
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_ROW_SHIFT 4
33#define LM8333_NUM_ROWS 8
34
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->keycode = lm8333->keycodes;
163 input->keycodesize = sizeof(lm8333->keycodes[0]);
164 input->keycodemax = ARRAY_SIZE(lm8333->keycodes);
165 input->evbit[0] = BIT_MASK(EV_KEY);
166 input_set_capability(input, EV_MSC, MSC_SCAN);
167
168 matrix_keypad_build_keymap(pdata->matrix_data, LM8333_ROW_SHIFT,
169 input->keycode, input->keybit);
170
171 if (pdata->debounce_time) {
172 err = lm8333_write8(lm8333, LM8333_DEBOUNCE,
173 pdata->debounce_time / 3);
174 if (err)
175 dev_warn(&client->dev, "Unable to set debounce time\n");
176 }
177
178 if (pdata->active_time) {
179 err = lm8333_write8(lm8333, LM8333_ACTIVE,
180 pdata->active_time / 3);
181 if (err)
182 dev_warn(&client->dev, "Unable to set active time\n");
183 }
184
185 err = request_threaded_irq(client->irq, NULL, lm8333_irq_thread,
186 IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
187 "lm8333", lm8333);
188 if (err)
189 goto free_mem;
190
191 err = input_register_device(input);
192 if (err)
193 goto free_irq;
194
195 i2c_set_clientdata(client, lm8333);
196 return 0;
197
198 free_irq:
199 free_irq(client->irq, lm8333);
200 free_mem:
201 input_free_device(input);
202 kfree(lm8333);
203 return err;
204}
205
206static int __devexit lm8333_remove(struct i2c_client *client)
207{
208 struct lm8333 *lm8333 = i2c_get_clientdata(client);
209
210 free_irq(client->irq, lm8333);
211 input_unregister_device(lm8333->input);
212 kfree(lm8333);
213
214 return 0;
215}
216
217static const struct i2c_device_id lm8333_id[] = {
218 { "lm8333", 0 },
219 { }
220};
221MODULE_DEVICE_TABLE(i2c, lm8333_id);
222
223static struct i2c_driver lm8333_driver = {
224 .driver = {
225 .name = "lm8333",
226 .owner = THIS_MODULE,
227 },
228 .probe = lm8333_probe,
229 .remove = __devexit_p(lm8333_remove),
230 .id_table = lm8333_id,
231};
232module_i2c_driver(lm8333_driver);
233
234MODULE_AUTHOR("Wolfram Sang <w.sang@pengutronix.de>");
235MODULE_DESCRIPTION("LM8333 keyboard driver");
236MODULE_LICENSE("GPL v2");
diff --git a/include/linux/input/lm8333.h b/include/linux/input/lm8333.h
new file mode 100644
index 00000000000..79f918c6e8c
--- /dev/null
+++ b/include/linux/input/lm8333.h
@@ -0,0 +1,24 @@
1/*
2 * public include for LM8333 keypad driver - same license as driver
3 * Copyright (C) 2012 Wolfram Sang, Pengutronix <w.sang@pengutronix.de>
4 */
5
6#ifndef _LM8333_H
7#define _LM8333_H
8
9struct lm8333;
10
11struct lm8333_platform_data {
12 /* Keymap data */
13 const struct matrix_keymap_data *matrix_data;
14 /* Active timeout before enter HALT mode in microseconds */
15 unsigned active_time;
16 /* Debounce interval in microseconds */
17 unsigned debounce_time;
18};
19
20extern int lm8333_read8(struct lm8333 *lm8333, u8 cmd);
21extern int lm8333_write8(struct lm8333 *lm8333, u8 cmd, u8 val);
22extern int lm8333_read_block(struct lm8333 *lm8333, u8 cmd, u8 len, u8 *buf);
23
24#endif /* _LM8333_H */