1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* |
3 | * max7359_keypad.c - MAX7359 Key Switch Controller Driver |
4 | * |
5 | * Copyright (C) 2009 Samsung Electronics |
6 | * Kim Kyuwon <q1.kim@samsung.com> |
7 | * |
8 | * Based on pxa27x_keypad.c |
9 | * |
10 | * Datasheet: http://www.maxim-ic.com/quick_view2.cfm/qv_pk/5456 |
11 | */ |
12 | |
13 | #include <linux/module.h> |
14 | #include <linux/i2c.h> |
15 | #include <linux/slab.h> |
16 | #include <linux/interrupt.h> |
17 | #include <linux/pm.h> |
18 | #include <linux/input.h> |
19 | #include <linux/input/matrix_keypad.h> |
20 | |
21 | #define MAX7359_MAX_KEY_ROWS 8 |
22 | #define MAX7359_MAX_KEY_COLS 8 |
23 | #define MAX7359_MAX_KEY_NUM (MAX7359_MAX_KEY_ROWS * MAX7359_MAX_KEY_COLS) |
24 | #define MAX7359_ROW_SHIFT 3 |
25 | |
26 | /* |
27 | * MAX7359 registers |
28 | */ |
29 | #define MAX7359_REG_KEYFIFO 0x00 |
30 | #define MAX7359_REG_CONFIG 0x01 |
31 | #define MAX7359_REG_DEBOUNCE 0x02 |
32 | #define MAX7359_REG_INTERRUPT 0x03 |
33 | #define MAX7359_REG_PORTS 0x04 |
34 | #define MAX7359_REG_KEYREP 0x05 |
35 | #define MAX7359_REG_SLEEP 0x06 |
36 | |
37 | /* |
38 | * Configuration register bits |
39 | */ |
40 | #define MAX7359_CFG_SLEEP (1 << 7) |
41 | #define MAX7359_CFG_INTERRUPT (1 << 5) |
42 | #define MAX7359_CFG_KEY_RELEASE (1 << 3) |
43 | #define MAX7359_CFG_WAKEUP (1 << 1) |
44 | #define MAX7359_CFG_TIMEOUT (1 << 0) |
45 | |
46 | /* |
47 | * Autosleep register values (ms) |
48 | */ |
49 | #define MAX7359_AUTOSLEEP_8192 0x01 |
50 | #define MAX7359_AUTOSLEEP_4096 0x02 |
51 | #define MAX7359_AUTOSLEEP_2048 0x03 |
52 | #define MAX7359_AUTOSLEEP_1024 0x04 |
53 | #define MAX7359_AUTOSLEEP_512 0x05 |
54 | #define MAX7359_AUTOSLEEP_256 0x06 |
55 | |
56 | struct max7359_keypad { |
57 | /* matrix key code map */ |
58 | unsigned short keycodes[MAX7359_MAX_KEY_NUM]; |
59 | |
60 | struct input_dev *input_dev; |
61 | struct i2c_client *client; |
62 | }; |
63 | |
64 | static int max7359_write_reg(struct i2c_client *client, u8 reg, u8 val) |
65 | { |
66 | int ret = i2c_smbus_write_byte_data(client, command: reg, value: val); |
67 | |
68 | if (ret < 0) |
69 | dev_err(&client->dev, "%s: reg 0x%x, val 0x%x, err %d\n" , |
70 | __func__, reg, val, ret); |
71 | return ret; |
72 | } |
73 | |
74 | static int max7359_read_reg(struct i2c_client *client, int reg) |
75 | { |
76 | int ret = i2c_smbus_read_byte_data(client, command: reg); |
77 | |
78 | if (ret < 0) |
79 | dev_err(&client->dev, "%s: reg 0x%x, err %d\n" , |
80 | __func__, reg, ret); |
81 | return ret; |
82 | } |
83 | |
84 | /* runs in an IRQ thread -- can (and will!) sleep */ |
85 | static irqreturn_t max7359_interrupt(int irq, void *dev_id) |
86 | { |
87 | struct max7359_keypad *keypad = dev_id; |
88 | struct input_dev *input_dev = keypad->input_dev; |
89 | int val, row, col, release, code; |
90 | |
91 | val = max7359_read_reg(client: keypad->client, MAX7359_REG_KEYFIFO); |
92 | row = val & 0x7; |
93 | col = (val >> 3) & 0x7; |
94 | release = val & 0x40; |
95 | |
96 | code = MATRIX_SCAN_CODE(row, col, MAX7359_ROW_SHIFT); |
97 | |
98 | dev_dbg(&keypad->client->dev, |
99 | "key[%d:%d] %s\n" , row, col, release ? "release" : "press" ); |
100 | |
101 | input_event(dev: input_dev, EV_MSC, MSC_SCAN, value: code); |
102 | input_report_key(dev: input_dev, code: keypad->keycodes[code], value: !release); |
103 | input_sync(dev: input_dev); |
104 | |
105 | return IRQ_HANDLED; |
106 | } |
107 | |
108 | /* |
109 | * Let MAX7359 fall into a deep sleep: |
110 | * If no keys are pressed, enter sleep mode for 8192 ms. And if any |
111 | * key is pressed, the MAX7359 returns to normal operating mode. |
112 | */ |
113 | static inline void max7359_fall_deepsleep(struct i2c_client *client) |
114 | { |
115 | max7359_write_reg(client, MAX7359_REG_SLEEP, MAX7359_AUTOSLEEP_8192); |
116 | } |
117 | |
118 | /* |
119 | * Let MAX7359 take a catnap: |
120 | * Autosleep just for 256 ms. |
121 | */ |
122 | static inline void max7359_take_catnap(struct i2c_client *client) |
123 | { |
124 | max7359_write_reg(client, MAX7359_REG_SLEEP, MAX7359_AUTOSLEEP_256); |
125 | } |
126 | |
127 | static int max7359_open(struct input_dev *dev) |
128 | { |
129 | struct max7359_keypad *keypad = input_get_drvdata(dev); |
130 | |
131 | max7359_take_catnap(client: keypad->client); |
132 | |
133 | return 0; |
134 | } |
135 | |
136 | static void max7359_close(struct input_dev *dev) |
137 | { |
138 | struct max7359_keypad *keypad = input_get_drvdata(dev); |
139 | |
140 | max7359_fall_deepsleep(client: keypad->client); |
141 | } |
142 | |
143 | static void max7359_initialize(struct i2c_client *client) |
144 | { |
145 | max7359_write_reg(client, MAX7359_REG_CONFIG, |
146 | MAX7359_CFG_KEY_RELEASE | /* Key release enable */ |
147 | MAX7359_CFG_WAKEUP); /* Key press wakeup enable */ |
148 | |
149 | /* Full key-scan functionality */ |
150 | max7359_write_reg(client, MAX7359_REG_DEBOUNCE, val: 0x1F); |
151 | |
152 | /* nINT asserts every debounce cycles */ |
153 | max7359_write_reg(client, MAX7359_REG_INTERRUPT, val: 0x01); |
154 | |
155 | max7359_fall_deepsleep(client); |
156 | } |
157 | |
158 | static int max7359_probe(struct i2c_client *client) |
159 | { |
160 | const struct matrix_keymap_data *keymap_data = |
161 | dev_get_platdata(dev: &client->dev); |
162 | struct max7359_keypad *keypad; |
163 | struct input_dev *input_dev; |
164 | int ret; |
165 | int error; |
166 | |
167 | if (!client->irq) { |
168 | dev_err(&client->dev, "The irq number should not be zero\n" ); |
169 | return -EINVAL; |
170 | } |
171 | |
172 | /* Detect MAX7359: The initial Keys FIFO value is '0x3F' */ |
173 | ret = max7359_read_reg(client, MAX7359_REG_KEYFIFO); |
174 | if (ret < 0) { |
175 | dev_err(&client->dev, "failed to detect device\n" ); |
176 | return -ENODEV; |
177 | } |
178 | |
179 | dev_dbg(&client->dev, "keys FIFO is 0x%02x\n" , ret); |
180 | |
181 | keypad = devm_kzalloc(dev: &client->dev, size: sizeof(struct max7359_keypad), |
182 | GFP_KERNEL); |
183 | if (!keypad) { |
184 | dev_err(&client->dev, "failed to allocate memory\n" ); |
185 | return -ENOMEM; |
186 | } |
187 | |
188 | input_dev = devm_input_allocate_device(&client->dev); |
189 | if (!input_dev) { |
190 | dev_err(&client->dev, "failed to allocate input device\n" ); |
191 | return -ENOMEM; |
192 | } |
193 | |
194 | keypad->client = client; |
195 | keypad->input_dev = input_dev; |
196 | |
197 | input_dev->name = client->name; |
198 | input_dev->id.bustype = BUS_I2C; |
199 | input_dev->open = max7359_open; |
200 | input_dev->close = max7359_close; |
201 | input_dev->dev.parent = &client->dev; |
202 | |
203 | input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REP); |
204 | input_dev->keycodesize = sizeof(keypad->keycodes[0]); |
205 | input_dev->keycodemax = ARRAY_SIZE(keypad->keycodes); |
206 | input_dev->keycode = keypad->keycodes; |
207 | |
208 | input_set_capability(dev: input_dev, EV_MSC, MSC_SCAN); |
209 | input_set_drvdata(dev: input_dev, data: keypad); |
210 | |
211 | error = matrix_keypad_build_keymap(keymap_data, NULL, |
212 | MAX7359_MAX_KEY_ROWS, |
213 | MAX7359_MAX_KEY_COLS, |
214 | keymap: keypad->keycodes, |
215 | input_dev); |
216 | if (error) { |
217 | dev_err(&client->dev, "failed to build keymap\n" ); |
218 | return error; |
219 | } |
220 | |
221 | error = devm_request_threaded_irq(dev: &client->dev, irq: client->irq, NULL, |
222 | thread_fn: max7359_interrupt, |
223 | IRQF_TRIGGER_LOW | IRQF_ONESHOT, |
224 | devname: client->name, dev_id: keypad); |
225 | if (error) { |
226 | dev_err(&client->dev, "failed to register interrupt\n" ); |
227 | return error; |
228 | } |
229 | |
230 | /* Register the input device */ |
231 | error = input_register_device(input_dev); |
232 | if (error) { |
233 | dev_err(&client->dev, "failed to register input device\n" ); |
234 | return error; |
235 | } |
236 | |
237 | /* Initialize MAX7359 */ |
238 | max7359_initialize(client); |
239 | |
240 | device_init_wakeup(dev: &client->dev, enable: 1); |
241 | |
242 | return 0; |
243 | } |
244 | |
245 | static int max7359_suspend(struct device *dev) |
246 | { |
247 | struct i2c_client *client = to_i2c_client(dev); |
248 | |
249 | max7359_fall_deepsleep(client); |
250 | |
251 | if (device_may_wakeup(dev: &client->dev)) |
252 | enable_irq_wake(irq: client->irq); |
253 | |
254 | return 0; |
255 | } |
256 | |
257 | static int max7359_resume(struct device *dev) |
258 | { |
259 | struct i2c_client *client = to_i2c_client(dev); |
260 | |
261 | if (device_may_wakeup(dev: &client->dev)) |
262 | disable_irq_wake(irq: client->irq); |
263 | |
264 | /* Restore the default setting */ |
265 | max7359_take_catnap(client); |
266 | |
267 | return 0; |
268 | } |
269 | |
270 | static DEFINE_SIMPLE_DEV_PM_OPS(max7359_pm, max7359_suspend, max7359_resume); |
271 | |
272 | static const struct i2c_device_id max7359_ids[] = { |
273 | { "max7359" , 0 }, |
274 | { } |
275 | }; |
276 | MODULE_DEVICE_TABLE(i2c, max7359_ids); |
277 | |
278 | static struct i2c_driver max7359_i2c_driver = { |
279 | .driver = { |
280 | .name = "max7359" , |
281 | .pm = pm_sleep_ptr(&max7359_pm), |
282 | }, |
283 | .probe = max7359_probe, |
284 | .id_table = max7359_ids, |
285 | }; |
286 | |
287 | module_i2c_driver(max7359_i2c_driver); |
288 | |
289 | MODULE_AUTHOR("Kim Kyuwon <q1.kim@samsung.com>" ); |
290 | MODULE_DESCRIPTION("MAX7359 Key Switch Controller Driver" ); |
291 | MODULE_LICENSE("GPL v2" ); |
292 | |