2 * Copyright (C) 2013 Daniel Tang <tangrs@tangrs.id.au>
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2, as
6 * published by the Free Software Foundation.
9 #include <linux/input/matrix_keypad.h>
10 #include <linux/platform_device.h>
11 #include <linux/interrupt.h>
13 #include <linux/delay.h>
14 #include <linux/input.h>
15 #include <linux/slab.h>
16 #include <linux/clk.h>
17 #include <linux/module.h>
20 #define KEYPAD_SCAN_MODE 0x00
21 #define KEYPAD_CNTL 0x04
22 #define KEYPAD_INT 0x08
23 #define KEYPAD_INTMSK 0x0C
25 #define KEYPAD_DATA 0x10
26 #define KEYPAD_GPIO 0x30
28 #define KEYPAD_UNKNOWN_INT 0x40
29 #define KEYPAD_UNKNOWN_INT_STS 0x44
31 #define KEYPAD_BITMASK_COLS 11
32 #define KEYPAD_BITMASK_ROWS 8
34 struct nspire_keypad
{
35 void __iomem
*reg_base
;
38 struct input_dev
*input
;
41 struct matrix_keymap_data
*keymap
;
44 /* Maximum delay estimated assuming 33MHz APB */
45 u32 scan_interval
; /* In microseconds (~2000us max) */
46 u32 row_delay
; /* In microseconds (~500us max) */
48 u16 state
[KEYPAD_BITMASK_ROWS
];
53 static irqreturn_t
nspire_keypad_irq(int irq
, void *dev_id
)
55 struct nspire_keypad
*keypad
= dev_id
;
56 struct input_dev
*input
= keypad
->input
;
57 unsigned short *keymap
= input
->keycode
;
64 int_sts
= readl(keypad
->reg_base
+ KEYPAD_INT
) & keypad
->int_mask
;
68 memcpy_fromio(state
, keypad
->reg_base
+ KEYPAD_DATA
, sizeof(state
));
70 for (row
= 0; row
< KEYPAD_BITMASK_ROWS
; row
++) {
72 if (keypad
->active_low
)
75 changed
= bits
^ keypad
->state
[row
];
79 keypad
->state
[row
] = bits
;
81 for (col
= 0; col
< KEYPAD_BITMASK_COLS
; col
++) {
82 if (!(changed
& (1U << col
)))
85 code
= MATRIX_SCAN_CODE(row
, col
, keypad
->row_shift
);
86 input_event(input
, EV_MSC
, MSC_SCAN
, code
);
87 input_report_key(input
, keymap
[code
],
94 writel(0x3, keypad
->reg_base
+ KEYPAD_INT
);
99 static int nspire_keypad_chip_init(struct nspire_keypad
*keypad
)
101 unsigned long val
= 0, cycles_per_us
, delay_cycles
, row_delay_cycles
;
103 cycles_per_us
= (clk_get_rate(keypad
->clk
) / 1000000);
104 if (cycles_per_us
== 0)
107 delay_cycles
= cycles_per_us
* keypad
->scan_interval
;
108 WARN_ON(delay_cycles
>= (1 << 16)); /* Overflow */
109 delay_cycles
&= 0xffff;
111 row_delay_cycles
= cycles_per_us
* keypad
->row_delay
;
112 WARN_ON(row_delay_cycles
>= (1 << 14)); /* Overflow */
113 row_delay_cycles
&= 0x3fff;
115 val
|= 3 << 0; /* Set scan mode to 3 (continuous scan) */
116 val
|= row_delay_cycles
<< 2; /* Delay between scanning each row */
117 val
|= delay_cycles
<< 16; /* Delay between scans */
118 writel(val
, keypad
->reg_base
+ KEYPAD_SCAN_MODE
);
120 val
= (KEYPAD_BITMASK_ROWS
& 0xff) | (KEYPAD_BITMASK_COLS
& 0xff)<<8;
121 writel(val
, keypad
->reg_base
+ KEYPAD_CNTL
);
123 /* Enable interrupts */
124 keypad
->int_mask
= 1 << 1;
125 writel(keypad
->int_mask
, keypad
->reg_base
+ KEYPAD_INTMSK
);
127 /* Disable GPIO interrupts to prevent hanging on touchpad */
128 /* Possibly used to detect touchpad events */
129 writel(0, keypad
->reg_base
+ KEYPAD_UNKNOWN_INT
);
130 /* Acknowledge existing interrupts */
131 writel(~0, keypad
->reg_base
+ KEYPAD_UNKNOWN_INT_STS
);
136 static int nspire_keypad_open(struct input_dev
*input
)
138 struct nspire_keypad
*keypad
= input_get_drvdata(input
);
141 error
= clk_prepare_enable(keypad
->clk
);
145 error
= nspire_keypad_chip_init(keypad
);
147 clk_disable_unprepare(keypad
->clk
);
154 static void nspire_keypad_close(struct input_dev
*input
)
156 struct nspire_keypad
*keypad
= input_get_drvdata(input
);
158 clk_disable_unprepare(keypad
->clk
);
161 static int nspire_keypad_probe(struct platform_device
*pdev
)
163 const struct device_node
*of_node
= pdev
->dev
.of_node
;
164 struct nspire_keypad
*keypad
;
165 struct input_dev
*input
;
166 struct resource
*res
;
170 irq
= platform_get_irq(pdev
, 0);
172 dev_err(&pdev
->dev
, "failed to get keypad irq\n");
176 keypad
= devm_kzalloc(&pdev
->dev
, sizeof(struct nspire_keypad
),
179 dev_err(&pdev
->dev
, "failed to allocate keypad memory\n");
183 keypad
->row_shift
= get_count_order(KEYPAD_BITMASK_COLS
);
185 error
= of_property_read_u32(of_node
, "scan-interval",
186 &keypad
->scan_interval
);
188 dev_err(&pdev
->dev
, "failed to get scan-interval\n");
192 error
= of_property_read_u32(of_node
, "row-delay",
195 dev_err(&pdev
->dev
, "failed to get row-delay\n");
199 keypad
->active_low
= of_property_read_bool(of_node
, "active-low");
201 keypad
->clk
= devm_clk_get(&pdev
->dev
, NULL
);
202 if (IS_ERR(keypad
->clk
)) {
203 dev_err(&pdev
->dev
, "unable to get clock\n");
204 return PTR_ERR(keypad
->clk
);
207 res
= platform_get_resource(pdev
, IORESOURCE_MEM
, 0);
208 keypad
->reg_base
= devm_ioremap_resource(&pdev
->dev
, res
);
209 if (IS_ERR(keypad
->reg_base
))
210 return PTR_ERR(keypad
->reg_base
);
212 keypad
->input
= input
= devm_input_allocate_device(&pdev
->dev
);
214 dev_err(&pdev
->dev
, "failed to allocate input device\n");
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
);
252 platform_set_drvdata(pdev
, keypad
);
255 "TI-NSPIRE keypad at %pR (scan_interval=%uus, row_delay=%uus%s)\n",
256 res
, keypad
->row_delay
, keypad
->scan_interval
,
257 keypad
->active_low
? ", active_low" : "");
262 static const struct of_device_id nspire_keypad_dt_match
[] = {
263 { .compatible
= "ti,nspire-keypad" },
266 MODULE_DEVICE_TABLE(of
, nspire_keypad_dt_match
);
268 static struct platform_driver nspire_keypad_driver
= {
270 .name
= "nspire-keypad",
271 .of_match_table
= nspire_keypad_dt_match
,
273 .probe
= nspire_keypad_probe
,
276 module_platform_driver(nspire_keypad_driver
);
278 MODULE_LICENSE("GPL");
279 MODULE_DESCRIPTION("TI-NSPIRE Keypad Driver");