1 // SPDX-License-Identifier: GPL-2.0-only
3 * Copyright (C) 2013 Daniel Tang <tangrs@tangrs.id.au>
6 #include <linux/input/matrix_keypad.h>
7 #include <linux/platform_device.h>
8 #include <linux/interrupt.h>
10 #include <linux/delay.h>
11 #include <linux/input.h>
12 #include <linux/slab.h>
13 #include <linux/clk.h>
14 #include <linux/module.h>
17 #define KEYPAD_SCAN_MODE 0x00
18 #define KEYPAD_CNTL 0x04
19 #define KEYPAD_INT 0x08
20 #define KEYPAD_INTMSK 0x0C
22 #define KEYPAD_DATA 0x10
23 #define KEYPAD_GPIO 0x30
25 #define KEYPAD_UNKNOWN_INT 0x40
26 #define KEYPAD_UNKNOWN_INT_STS 0x44
28 #define KEYPAD_BITMASK_COLS 11
29 #define KEYPAD_BITMASK_ROWS 8
31 struct nspire_keypad
{
32 void __iomem
*reg_base
;
35 struct input_dev
*input
;
38 struct matrix_keymap_data
*keymap
;
41 /* Maximum delay estimated assuming 33MHz APB */
42 u32 scan_interval
; /* In microseconds (~2000us max) */
43 u32 row_delay
; /* In microseconds (~500us max) */
45 u16 state
[KEYPAD_BITMASK_ROWS
];
50 static irqreturn_t
nspire_keypad_irq(int irq
, void *dev_id
)
52 struct nspire_keypad
*keypad
= dev_id
;
53 struct input_dev
*input
= keypad
->input
;
54 unsigned short *keymap
= input
->keycode
;
61 int_sts
= readl(keypad
->reg_base
+ KEYPAD_INT
) & keypad
->int_mask
;
65 memcpy_fromio(state
, keypad
->reg_base
+ KEYPAD_DATA
, sizeof(state
));
67 for (row
= 0; row
< KEYPAD_BITMASK_ROWS
; row
++) {
69 if (keypad
->active_low
)
72 changed
= bits
^ keypad
->state
[row
];
76 keypad
->state
[row
] = bits
;
78 for (col
= 0; col
< KEYPAD_BITMASK_COLS
; col
++) {
79 if (!(changed
& (1U << col
)))
82 code
= MATRIX_SCAN_CODE(row
, col
, keypad
->row_shift
);
83 input_event(input
, EV_MSC
, MSC_SCAN
, code
);
84 input_report_key(input
, keymap
[code
],
91 writel(0x3, keypad
->reg_base
+ KEYPAD_INT
);
96 static int nspire_keypad_open(struct input_dev
*input
)
98 struct nspire_keypad
*keypad
= input_get_drvdata(input
);
99 unsigned long val
= 0, cycles_per_us
, delay_cycles
, row_delay_cycles
;
102 error
= clk_prepare_enable(keypad
->clk
);
106 cycles_per_us
= (clk_get_rate(keypad
->clk
) / 1000000);
107 if (cycles_per_us
== 0)
110 delay_cycles
= cycles_per_us
* keypad
->scan_interval
;
111 WARN_ON(delay_cycles
>= (1 << 16)); /* Overflow */
112 delay_cycles
&= 0xffff;
114 row_delay_cycles
= cycles_per_us
* keypad
->row_delay
;
115 WARN_ON(row_delay_cycles
>= (1 << 14)); /* Overflow */
116 row_delay_cycles
&= 0x3fff;
118 val
|= 3 << 0; /* Set scan mode to 3 (continuous scan) */
119 val
|= row_delay_cycles
<< 2; /* Delay between scanning each row */
120 val
|= delay_cycles
<< 16; /* Delay between scans */
121 writel(val
, keypad
->reg_base
+ KEYPAD_SCAN_MODE
);
123 val
= (KEYPAD_BITMASK_ROWS
& 0xff) | (KEYPAD_BITMASK_COLS
& 0xff)<<8;
124 writel(val
, keypad
->reg_base
+ KEYPAD_CNTL
);
126 /* Enable interrupts */
127 keypad
->int_mask
= 1 << 1;
128 writel(keypad
->int_mask
, keypad
->reg_base
+ KEYPAD_INTMSK
);
133 static void nspire_keypad_close(struct input_dev
*input
)
135 struct nspire_keypad
*keypad
= input_get_drvdata(input
);
137 /* Disable interrupts */
138 writel(0, keypad
->reg_base
+ KEYPAD_INTMSK
);
139 /* Acknowledge existing interrupts */
140 writel(~0, keypad
->reg_base
+ KEYPAD_INT
);
142 clk_disable_unprepare(keypad
->clk
);
145 static int nspire_keypad_probe(struct platform_device
*pdev
)
147 const struct device_node
*of_node
= pdev
->dev
.of_node
;
148 struct nspire_keypad
*keypad
;
149 struct input_dev
*input
;
150 struct resource
*res
;
154 irq
= platform_get_irq(pdev
, 0);
158 keypad
= devm_kzalloc(&pdev
->dev
, sizeof(struct nspire_keypad
),
161 dev_err(&pdev
->dev
, "failed to allocate keypad memory\n");
165 keypad
->row_shift
= get_count_order(KEYPAD_BITMASK_COLS
);
167 error
= of_property_read_u32(of_node
, "scan-interval",
168 &keypad
->scan_interval
);
170 dev_err(&pdev
->dev
, "failed to get scan-interval\n");
174 error
= of_property_read_u32(of_node
, "row-delay",
177 dev_err(&pdev
->dev
, "failed to get row-delay\n");
181 keypad
->active_low
= of_property_read_bool(of_node
, "active-low");
183 keypad
->clk
= devm_clk_get(&pdev
->dev
, NULL
);
184 if (IS_ERR(keypad
->clk
)) {
185 dev_err(&pdev
->dev
, "unable to get clock\n");
186 return PTR_ERR(keypad
->clk
);
189 keypad
->reg_base
= devm_platform_get_and_ioremap_resource(pdev
, 0, &res
);
190 if (IS_ERR(keypad
->reg_base
))
191 return PTR_ERR(keypad
->reg_base
);
193 keypad
->input
= input
= devm_input_allocate_device(&pdev
->dev
);
195 dev_err(&pdev
->dev
, "failed to allocate input device\n");
199 error
= clk_prepare_enable(keypad
->clk
);
201 dev_err(&pdev
->dev
, "failed to enable clock\n");
205 /* Disable interrupts */
206 writel(0, keypad
->reg_base
+ KEYPAD_INTMSK
);
207 /* Acknowledge existing interrupts */
208 writel(~0, keypad
->reg_base
+ KEYPAD_INT
);
210 /* Disable GPIO interrupts to prevent hanging on touchpad */
211 /* Possibly used to detect touchpad events */
212 writel(0, keypad
->reg_base
+ KEYPAD_UNKNOWN_INT
);
213 /* Acknowledge existing GPIO interrupts */
214 writel(~0, keypad
->reg_base
+ KEYPAD_UNKNOWN_INT_STS
);
216 clk_disable_unprepare(keypad
->clk
);
218 input_set_drvdata(input
, keypad
);
220 input
->id
.bustype
= BUS_HOST
;
221 input
->name
= "nspire-keypad";
222 input
->open
= nspire_keypad_open
;
223 input
->close
= nspire_keypad_close
;
225 __set_bit(EV_KEY
, input
->evbit
);
226 __set_bit(EV_REP
, input
->evbit
);
227 input_set_capability(input
, EV_MSC
, MSC_SCAN
);
229 error
= matrix_keypad_build_keymap(NULL
, NULL
,
234 dev_err(&pdev
->dev
, "building keymap failed\n");
238 error
= devm_request_irq(&pdev
->dev
, irq
, nspire_keypad_irq
, 0,
239 "nspire_keypad", keypad
);
241 dev_err(&pdev
->dev
, "allocate irq %d failed\n", irq
);
245 error
= input_register_device(input
);
248 "unable to register input device: %d\n", error
);
253 "TI-NSPIRE keypad at %pR (scan_interval=%uus, row_delay=%uus%s)\n",
254 res
, keypad
->row_delay
, keypad
->scan_interval
,
255 keypad
->active_low
? ", active_low" : "");
260 static const struct of_device_id nspire_keypad_dt_match
[] = {
261 { .compatible
= "ti,nspire-keypad" },
264 MODULE_DEVICE_TABLE(of
, nspire_keypad_dt_match
);
266 static struct platform_driver nspire_keypad_driver
= {
268 .name
= "nspire-keypad",
269 .of_match_table
= nspire_keypad_dt_match
,
271 .probe
= nspire_keypad_probe
,
274 module_platform_driver(nspire_keypad_driver
);
276 MODULE_LICENSE("GPL");
277 MODULE_DESCRIPTION("TI-NSPIRE Keypad Driver");