1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* |
3 | * Driver for the Cirrus EP93xx matrix keypad controller. |
4 | * |
5 | * Copyright (c) 2008 H Hartley Sweeten <hsweeten@visionengravers.com> |
6 | * |
7 | * Based on the pxa27x matrix keypad controller by Rodolfo Giometti. |
8 | * |
9 | * NOTE: |
10 | * |
11 | * The 3-key reset is triggered by pressing the 3 keys in |
12 | * Row 0, Columns 2, 4, and 7 at the same time. This action can |
13 | * be disabled by setting the EP93XX_KEYPAD_DISABLE_3_KEY flag. |
14 | * |
15 | * Normal operation for the matrix does not autorepeat the key press. |
16 | * This action can be enabled by setting the EP93XX_KEYPAD_AUTOREPEAT |
17 | * flag. |
18 | */ |
19 | |
20 | #include <linux/bits.h> |
21 | #include <linux/module.h> |
22 | #include <linux/platform_device.h> |
23 | #include <linux/interrupt.h> |
24 | #include <linux/clk.h> |
25 | #include <linux/io.h> |
26 | #include <linux/input.h> |
27 | #include <linux/input/matrix_keypad.h> |
28 | #include <linux/slab.h> |
29 | #include <linux/soc/cirrus/ep93xx.h> |
30 | #include <linux/platform_data/keypad-ep93xx.h> |
31 | #include <linux/pm_wakeirq.h> |
32 | |
33 | /* |
34 | * Keypad Interface Register offsets |
35 | */ |
36 | #define KEY_INIT 0x00 /* Key Scan Initialization register */ |
37 | #define KEY_DIAG 0x04 /* Key Scan Diagnostic register */ |
38 | #define KEY_REG 0x08 /* Key Value Capture register */ |
39 | |
40 | /* Key Scan Initialization Register bit defines */ |
41 | #define KEY_INIT_DBNC_MASK GENMASK(23, 16) |
42 | #define KEY_INIT_DBNC_SHIFT 16 |
43 | #define KEY_INIT_DIS3KY BIT(15) |
44 | #define KEY_INIT_DIAG BIT(14) |
45 | #define KEY_INIT_BACK BIT(13) |
46 | #define KEY_INIT_T2 BIT(12) |
47 | #define KEY_INIT_PRSCL_MASK GENMASK(9, 0) |
48 | #define KEY_INIT_PRSCL_SHIFT 0 |
49 | |
50 | /* Key Scan Diagnostic Register bit defines */ |
51 | #define KEY_DIAG_MASK GENMASK(5, 0) |
52 | #define KEY_DIAG_SHIFT 0 |
53 | |
54 | /* Key Value Capture Register bit defines */ |
55 | #define KEY_REG_K BIT(15) |
56 | #define KEY_REG_INT BIT(14) |
57 | #define KEY_REG_2KEYS BIT(13) |
58 | #define KEY_REG_1KEY BIT(12) |
59 | #define KEY_REG_KEY2_MASK GENMASK(11, 6) |
60 | #define KEY_REG_KEY2_SHIFT 6 |
61 | #define KEY_REG_KEY1_MASK GENMASK(5, 0) |
62 | #define KEY_REG_KEY1_SHIFT 0 |
63 | |
64 | #define EP93XX_MATRIX_SIZE (EP93XX_MATRIX_ROWS * EP93XX_MATRIX_COLS) |
65 | |
66 | struct ep93xx_keypad { |
67 | struct ep93xx_keypad_platform_data *pdata; |
68 | struct input_dev *input_dev; |
69 | struct clk *clk; |
70 | |
71 | void __iomem *mmio_base; |
72 | |
73 | unsigned short keycodes[EP93XX_MATRIX_SIZE]; |
74 | |
75 | int key1; |
76 | int key2; |
77 | |
78 | int irq; |
79 | |
80 | bool enabled; |
81 | }; |
82 | |
83 | static irqreturn_t ep93xx_keypad_irq_handler(int irq, void *dev_id) |
84 | { |
85 | struct ep93xx_keypad *keypad = dev_id; |
86 | struct input_dev *input_dev = keypad->input_dev; |
87 | unsigned int status; |
88 | int keycode, key1, key2; |
89 | |
90 | status = __raw_readl(addr: keypad->mmio_base + KEY_REG); |
91 | |
92 | keycode = (status & KEY_REG_KEY1_MASK) >> KEY_REG_KEY1_SHIFT; |
93 | key1 = keypad->keycodes[keycode]; |
94 | |
95 | keycode = (status & KEY_REG_KEY2_MASK) >> KEY_REG_KEY2_SHIFT; |
96 | key2 = keypad->keycodes[keycode]; |
97 | |
98 | if (status & KEY_REG_2KEYS) { |
99 | if (keypad->key1 && key1 != keypad->key1 && key2 != keypad->key1) |
100 | input_report_key(dev: input_dev, code: keypad->key1, value: 0); |
101 | |
102 | if (keypad->key2 && key1 != keypad->key2 && key2 != keypad->key2) |
103 | input_report_key(dev: input_dev, code: keypad->key2, value: 0); |
104 | |
105 | input_report_key(dev: input_dev, code: key1, value: 1); |
106 | input_report_key(dev: input_dev, code: key2, value: 1); |
107 | |
108 | keypad->key1 = key1; |
109 | keypad->key2 = key2; |
110 | |
111 | } else if (status & KEY_REG_1KEY) { |
112 | if (keypad->key1 && key1 != keypad->key1) |
113 | input_report_key(dev: input_dev, code: keypad->key1, value: 0); |
114 | |
115 | if (keypad->key2 && key1 != keypad->key2) |
116 | input_report_key(dev: input_dev, code: keypad->key2, value: 0); |
117 | |
118 | input_report_key(dev: input_dev, code: key1, value: 1); |
119 | |
120 | keypad->key1 = key1; |
121 | keypad->key2 = 0; |
122 | |
123 | } else { |
124 | input_report_key(dev: input_dev, code: keypad->key1, value: 0); |
125 | input_report_key(dev: input_dev, code: keypad->key2, value: 0); |
126 | |
127 | keypad->key1 = keypad->key2 = 0; |
128 | } |
129 | input_sync(dev: input_dev); |
130 | |
131 | return IRQ_HANDLED; |
132 | } |
133 | |
134 | static void ep93xx_keypad_config(struct ep93xx_keypad *keypad) |
135 | { |
136 | struct ep93xx_keypad_platform_data *pdata = keypad->pdata; |
137 | unsigned int val = 0; |
138 | |
139 | clk_set_rate(clk: keypad->clk, rate: pdata->clk_rate); |
140 | |
141 | if (pdata->flags & EP93XX_KEYPAD_DISABLE_3_KEY) |
142 | val |= KEY_INIT_DIS3KY; |
143 | if (pdata->flags & EP93XX_KEYPAD_DIAG_MODE) |
144 | val |= KEY_INIT_DIAG; |
145 | if (pdata->flags & EP93XX_KEYPAD_BACK_DRIVE) |
146 | val |= KEY_INIT_BACK; |
147 | if (pdata->flags & EP93XX_KEYPAD_TEST_MODE) |
148 | val |= KEY_INIT_T2; |
149 | |
150 | val |= ((pdata->debounce << KEY_INIT_DBNC_SHIFT) & KEY_INIT_DBNC_MASK); |
151 | |
152 | val |= ((pdata->prescale << KEY_INIT_PRSCL_SHIFT) & KEY_INIT_PRSCL_MASK); |
153 | |
154 | __raw_writel(val, addr: keypad->mmio_base + KEY_INIT); |
155 | } |
156 | |
157 | static int ep93xx_keypad_open(struct input_dev *pdev) |
158 | { |
159 | struct ep93xx_keypad *keypad = input_get_drvdata(dev: pdev); |
160 | |
161 | if (!keypad->enabled) { |
162 | ep93xx_keypad_config(keypad); |
163 | clk_prepare_enable(clk: keypad->clk); |
164 | keypad->enabled = true; |
165 | } |
166 | |
167 | return 0; |
168 | } |
169 | |
170 | static void ep93xx_keypad_close(struct input_dev *pdev) |
171 | { |
172 | struct ep93xx_keypad *keypad = input_get_drvdata(dev: pdev); |
173 | |
174 | if (keypad->enabled) { |
175 | clk_disable_unprepare(clk: keypad->clk); |
176 | keypad->enabled = false; |
177 | } |
178 | } |
179 | |
180 | |
181 | static int ep93xx_keypad_suspend(struct device *dev) |
182 | { |
183 | struct platform_device *pdev = to_platform_device(dev); |
184 | struct ep93xx_keypad *keypad = platform_get_drvdata(pdev); |
185 | struct input_dev *input_dev = keypad->input_dev; |
186 | |
187 | mutex_lock(&input_dev->mutex); |
188 | |
189 | if (keypad->enabled) { |
190 | clk_disable(clk: keypad->clk); |
191 | keypad->enabled = false; |
192 | } |
193 | |
194 | mutex_unlock(lock: &input_dev->mutex); |
195 | |
196 | return 0; |
197 | } |
198 | |
199 | static int ep93xx_keypad_resume(struct device *dev) |
200 | { |
201 | struct platform_device *pdev = to_platform_device(dev); |
202 | struct ep93xx_keypad *keypad = platform_get_drvdata(pdev); |
203 | struct input_dev *input_dev = keypad->input_dev; |
204 | |
205 | mutex_lock(&input_dev->mutex); |
206 | |
207 | if (input_device_enabled(dev: input_dev)) { |
208 | if (!keypad->enabled) { |
209 | ep93xx_keypad_config(keypad); |
210 | clk_enable(clk: keypad->clk); |
211 | keypad->enabled = true; |
212 | } |
213 | } |
214 | |
215 | mutex_unlock(lock: &input_dev->mutex); |
216 | |
217 | return 0; |
218 | } |
219 | |
220 | static DEFINE_SIMPLE_DEV_PM_OPS(ep93xx_keypad_pm_ops, |
221 | ep93xx_keypad_suspend, ep93xx_keypad_resume); |
222 | |
223 | static void ep93xx_keypad_release_gpio_action(void *_pdev) |
224 | { |
225 | struct platform_device *pdev = _pdev; |
226 | |
227 | ep93xx_keypad_release_gpio(pdev); |
228 | } |
229 | |
230 | static int ep93xx_keypad_probe(struct platform_device *pdev) |
231 | { |
232 | struct ep93xx_keypad *keypad; |
233 | const struct matrix_keymap_data *keymap_data; |
234 | struct input_dev *input_dev; |
235 | int err; |
236 | |
237 | keypad = devm_kzalloc(dev: &pdev->dev, size: sizeof(*keypad), GFP_KERNEL); |
238 | if (!keypad) |
239 | return -ENOMEM; |
240 | |
241 | keypad->pdata = dev_get_platdata(dev: &pdev->dev); |
242 | if (!keypad->pdata) |
243 | return -EINVAL; |
244 | |
245 | keymap_data = keypad->pdata->keymap_data; |
246 | if (!keymap_data) |
247 | return -EINVAL; |
248 | |
249 | keypad->irq = platform_get_irq(pdev, 0); |
250 | if (keypad->irq < 0) |
251 | return keypad->irq; |
252 | |
253 | keypad->mmio_base = devm_platform_ioremap_resource(pdev, index: 0); |
254 | if (IS_ERR(ptr: keypad->mmio_base)) |
255 | return PTR_ERR(ptr: keypad->mmio_base); |
256 | |
257 | err = ep93xx_keypad_acquire_gpio(pdev); |
258 | if (err) |
259 | return err; |
260 | |
261 | err = devm_add_action_or_reset(&pdev->dev, |
262 | ep93xx_keypad_release_gpio_action, pdev); |
263 | if (err) |
264 | return err; |
265 | |
266 | keypad->clk = devm_clk_get(dev: &pdev->dev, NULL); |
267 | if (IS_ERR(ptr: keypad->clk)) |
268 | return PTR_ERR(ptr: keypad->clk); |
269 | |
270 | input_dev = devm_input_allocate_device(&pdev->dev); |
271 | if (!input_dev) |
272 | return -ENOMEM; |
273 | |
274 | keypad->input_dev = input_dev; |
275 | |
276 | input_dev->name = pdev->name; |
277 | input_dev->id.bustype = BUS_HOST; |
278 | input_dev->open = ep93xx_keypad_open; |
279 | input_dev->close = ep93xx_keypad_close; |
280 | |
281 | err = matrix_keypad_build_keymap(keymap_data, NULL, |
282 | EP93XX_MATRIX_ROWS, EP93XX_MATRIX_COLS, |
283 | keymap: keypad->keycodes, input_dev); |
284 | if (err) |
285 | return err; |
286 | |
287 | if (keypad->pdata->flags & EP93XX_KEYPAD_AUTOREPEAT) |
288 | __set_bit(EV_REP, input_dev->evbit); |
289 | input_set_drvdata(dev: input_dev, data: keypad); |
290 | |
291 | err = devm_request_irq(dev: &pdev->dev, irq: keypad->irq, |
292 | handler: ep93xx_keypad_irq_handler, |
293 | irqflags: 0, devname: pdev->name, dev_id: keypad); |
294 | if (err) |
295 | return err; |
296 | |
297 | err = input_register_device(input_dev); |
298 | if (err) |
299 | return err; |
300 | |
301 | platform_set_drvdata(pdev, data: keypad); |
302 | |
303 | device_init_wakeup(dev: &pdev->dev, enable: 1); |
304 | err = dev_pm_set_wake_irq(dev: &pdev->dev, irq: keypad->irq); |
305 | if (err) |
306 | dev_warn(&pdev->dev, "failed to set up wakeup irq: %d\n" , err); |
307 | |
308 | return 0; |
309 | } |
310 | |
311 | static int ep93xx_keypad_remove(struct platform_device *pdev) |
312 | { |
313 | dev_pm_clear_wake_irq(dev: &pdev->dev); |
314 | |
315 | return 0; |
316 | } |
317 | |
318 | static struct platform_driver ep93xx_keypad_driver = { |
319 | .driver = { |
320 | .name = "ep93xx-keypad" , |
321 | .pm = pm_sleep_ptr(&ep93xx_keypad_pm_ops), |
322 | }, |
323 | .probe = ep93xx_keypad_probe, |
324 | .remove = ep93xx_keypad_remove, |
325 | }; |
326 | module_platform_driver(ep93xx_keypad_driver); |
327 | |
328 | MODULE_LICENSE("GPL" ); |
329 | MODULE_AUTHOR("H Hartley Sweeten <hsweeten@visionengravers.com>" ); |
330 | MODULE_DESCRIPTION("EP93xx Matrix Keypad Controller" ); |
331 | MODULE_ALIAS("platform:ep93xx-keypad" ); |
332 | |