1 // SPDX-License-Identifier: GPL-2.0-only
3 * Copyright (c) 2008-2009 Nuvoton technology corporation.
5 * Wan ZongShun <mcuos.com@gmail.com>
8 #include <linux/kernel.h>
9 #include <linux/module.h>
10 #include <linux/interrupt.h>
11 #include <linux/input.h>
12 #include <linux/device.h>
13 #include <linux/platform_device.h>
14 #include <linux/clk.h>
15 #include <linux/err.h>
17 #include <linux/slab.h>
19 #include <linux/platform_data/keypad-w90p910.h>
21 /* Keypad Interface Control Registers */
23 #define KPI_3KCONF 0x04
24 #define KPI_LPCONF 0x08
25 #define KPI_STATUS 0x0C
27 #define IS1KEY (0x01 << 16)
28 #define INTTR (0x01 << 21)
29 #define KEY0R (0x0f << 3)
31 #define DEBOUNCE_BIT 0x08
32 #define KSIZE0 (0x01 << 16)
33 #define KSIZE1 (0x01 << 17)
34 #define KPSEL (0x01 << 19)
35 #define ENKP (0x01 << 18)
37 #define KGET_RAW(n) (((n) & KEY0R) >> 3)
38 #define KGET_COLUMN(n) ((n) & KEY0C)
40 #define W90P910_NUM_ROWS 8
41 #define W90P910_NUM_COLS 8
42 #define W90P910_ROW_SHIFT 3
44 struct w90p910_keypad
{
45 const struct w90p910_keypad_platform_data
*pdata
;
47 struct input_dev
*input_dev
;
48 void __iomem
*mmio_base
;
50 unsigned short keymap
[W90P910_NUM_ROWS
* W90P910_NUM_COLS
];
53 static void w90p910_keypad_scan_matrix(struct w90p910_keypad
*keypad
,
56 struct input_dev
*input_dev
= keypad
->input_dev
;
57 unsigned int row
= KGET_RAW(status
);
58 unsigned int col
= KGET_COLUMN(status
);
59 unsigned int code
= MATRIX_SCAN_CODE(row
, col
, W90P910_ROW_SHIFT
);
60 unsigned int key
= keypad
->keymap
[code
];
62 input_event(input_dev
, EV_MSC
, MSC_SCAN
, code
);
63 input_report_key(input_dev
, key
, 1);
64 input_sync(input_dev
);
66 input_event(input_dev
, EV_MSC
, MSC_SCAN
, code
);
67 input_report_key(input_dev
, key
, 0);
68 input_sync(input_dev
);
71 static irqreturn_t
w90p910_keypad_irq_handler(int irq
, void *dev_id
)
73 struct w90p910_keypad
*keypad
= dev_id
;
74 unsigned int kstatus
, val
;
76 kstatus
= __raw_readl(keypad
->mmio_base
+ KPI_STATUS
);
81 w90p910_keypad_scan_matrix(keypad
, kstatus
);
86 static int w90p910_keypad_open(struct input_dev
*dev
)
88 struct w90p910_keypad
*keypad
= input_get_drvdata(dev
);
89 const struct w90p910_keypad_platform_data
*pdata
= keypad
->pdata
;
90 unsigned int val
, config
;
92 /* Enable unit clock */
93 clk_enable(keypad
->clk
);
95 val
= __raw_readl(keypad
->mmio_base
+ KPI_CONF
);
96 val
|= (KPSEL
| ENKP
);
97 val
&= ~(KSIZE0
| KSIZE1
);
99 config
= pdata
->prescale
| (pdata
->debounce
<< DEBOUNCE_BIT
);
103 __raw_writel(val
, keypad
->mmio_base
+ KPI_CONF
);
108 static void w90p910_keypad_close(struct input_dev
*dev
)
110 struct w90p910_keypad
*keypad
= input_get_drvdata(dev
);
112 /* Disable clock unit */
113 clk_disable(keypad
->clk
);
116 static int w90p910_keypad_probe(struct platform_device
*pdev
)
118 const struct w90p910_keypad_platform_data
*pdata
=
119 dev_get_platdata(&pdev
->dev
);
120 const struct matrix_keymap_data
*keymap_data
;
121 struct w90p910_keypad
*keypad
;
122 struct input_dev
*input_dev
;
123 struct resource
*res
;
128 dev_err(&pdev
->dev
, "no platform data defined\n");
132 keymap_data
= pdata
->keymap_data
;
134 irq
= platform_get_irq(pdev
, 0);
136 dev_err(&pdev
->dev
, "failed to get keypad irq\n");
140 keypad
= kzalloc(sizeof(struct w90p910_keypad
), GFP_KERNEL
);
141 input_dev
= input_allocate_device();
142 if (!keypad
|| !input_dev
) {
143 dev_err(&pdev
->dev
, "failed to allocate driver data\n");
148 keypad
->pdata
= pdata
;
149 keypad
->input_dev
= input_dev
;
152 res
= platform_get_resource(pdev
, IORESOURCE_MEM
, 0);
154 dev_err(&pdev
->dev
, "failed to get I/O memory\n");
159 res
= request_mem_region(res
->start
, resource_size(res
), pdev
->name
);
161 dev_err(&pdev
->dev
, "failed to request I/O memory\n");
166 keypad
->mmio_base
= ioremap(res
->start
, resource_size(res
));
167 if (keypad
->mmio_base
== NULL
) {
168 dev_err(&pdev
->dev
, "failed to remap I/O memory\n");
170 goto failed_free_res
;
173 keypad
->clk
= clk_get(&pdev
->dev
, NULL
);
174 if (IS_ERR(keypad
->clk
)) {
175 dev_err(&pdev
->dev
, "failed to get keypad clock\n");
176 error
= PTR_ERR(keypad
->clk
);
180 /* set multi-function pin for w90p910 kpi. */
181 mfp_set_groupi(&pdev
->dev
);
183 input_dev
->name
= pdev
->name
;
184 input_dev
->id
.bustype
= BUS_HOST
;
185 input_dev
->open
= w90p910_keypad_open
;
186 input_dev
->close
= w90p910_keypad_close
;
187 input_dev
->dev
.parent
= &pdev
->dev
;
189 error
= matrix_keypad_build_keymap(keymap_data
, NULL
,
190 W90P910_NUM_ROWS
, W90P910_NUM_COLS
,
191 keypad
->keymap
, input_dev
);
193 dev_err(&pdev
->dev
, "failed to build keymap\n");
197 error
= request_irq(keypad
->irq
, w90p910_keypad_irq_handler
,
198 0, pdev
->name
, keypad
);
200 dev_err(&pdev
->dev
, "failed to request IRQ\n");
204 __set_bit(EV_REP
, input_dev
->evbit
);
205 input_set_capability(input_dev
, EV_MSC
, MSC_SCAN
);
206 input_set_drvdata(input_dev
, keypad
);
208 /* Register the input device */
209 error
= input_register_device(input_dev
);
211 dev_err(&pdev
->dev
, "failed to register input device\n");
212 goto failed_free_irq
;
215 platform_set_drvdata(pdev
, keypad
);
219 free_irq(irq
, keypad
);
221 clk_put(keypad
->clk
);
223 iounmap(keypad
->mmio_base
);
225 release_mem_region(res
->start
, resource_size(res
));
227 input_free_device(input_dev
);
232 static int w90p910_keypad_remove(struct platform_device
*pdev
)
234 struct w90p910_keypad
*keypad
= platform_get_drvdata(pdev
);
235 struct resource
*res
;
237 free_irq(keypad
->irq
, keypad
);
239 clk_put(keypad
->clk
);
241 input_unregister_device(keypad
->input_dev
);
243 iounmap(keypad
->mmio_base
);
244 res
= platform_get_resource(pdev
, IORESOURCE_MEM
, 0);
245 release_mem_region(res
->start
, resource_size(res
));
252 static struct platform_driver w90p910_keypad_driver
= {
253 .probe
= w90p910_keypad_probe
,
254 .remove
= w90p910_keypad_remove
,
256 .name
= "nuc900-kpi",
259 module_platform_driver(w90p910_keypad_driver
);
261 MODULE_AUTHOR("Wan ZongShun <mcuos.com@gmail.com>");
262 MODULE_DESCRIPTION("w90p910 keypad driver");
263 MODULE_LICENSE("GPL");
264 MODULE_ALIAS("platform:nuc900-keypad");