Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Input: add st-keyscan driver

This patch adds ST Keyscan driver to use the keypad hw a subset of ST
boards provide. Specific board setup will be put in the given dt.

Signed-off-by: Gabriel Fernandez <gabriel.fernandez@linaro.org>
Signed-off-by: Giuseppe Condorelli <giuseppe.condorelli@st.com>
Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>

authored by

Gabriel FERNANDEZ and committed by
Dmitry Torokhov
062589b1 c8986208

+346
+60
Documentation/devicetree/bindings/input/st-keyscan.txt
··· 1 + * ST Keyscan controller Device Tree bindings 2 + 3 + The ST keyscan controller Device Tree binding is based on the 4 + matrix-keymap. 5 + 6 + Required properties: 7 + - compatible: "st,sti-keyscan" 8 + 9 + - reg: Register base address and size of st-keyscan controller. 10 + 11 + - interrupts: Interrupt number for the st-keyscan controller. 12 + 13 + - clocks: Must contain one entry, for the module clock. 14 + See ../clocks/clock-bindings.txt for details. 15 + 16 + - pinctrl: Should specify pin control groups used for this controller. 17 + See ../pinctrl/pinctrl-bindings.txt for details. 18 + 19 + - linux,keymap: The keymap for keys as described in the binding document 20 + devicetree/bindings/input/matrix-keymap.txt. 21 + 22 + - keypad,num-rows: Number of row lines connected to the keypad controller. 23 + 24 + - keypad,num-columns: Number of column lines connected to the keypad 25 + controller. 26 + 27 + Optional property: 28 + - st,debounce_us: Debouncing interval time in microseconds 29 + 30 + Example: 31 + 32 + keyscan: keyscan@fe4b0000 { 33 + compatible = "st,sti-keyscan"; 34 + reg = <0xfe4b0000 0x2000>; 35 + interrupts = <GIC_SPI 212 IRQ_TYPE_NONE>; 36 + clocks = <&CLK_SYSIN>; 37 + pinctrl-names = "default"; 38 + pinctrl-0 = <&pinctrl_keyscan>; 39 + 40 + keypad,num-rows = <4>; 41 + keypad,num-columns = <4>; 42 + st,debounce_us = <5000>; 43 + 44 + linux,keymap = < MATRIX_KEY(0x00, 0x00, KEY_F13) 45 + MATRIX_KEY(0x00, 0x01, KEY_F9) 46 + MATRIX_KEY(0x00, 0x02, KEY_F5) 47 + MATRIX_KEY(0x00, 0x03, KEY_F1) 48 + MATRIX_KEY(0x01, 0x00, KEY_F14) 49 + MATRIX_KEY(0x01, 0x01, KEY_F10) 50 + MATRIX_KEY(0x01, 0x02, KEY_F6) 51 + MATRIX_KEY(0x01, 0x03, KEY_F2) 52 + MATRIX_KEY(0x02, 0x00, KEY_F15) 53 + MATRIX_KEY(0x02, 0x01, KEY_F11) 54 + MATRIX_KEY(0x02, 0x02, KEY_F7) 55 + MATRIX_KEY(0x02, 0x03, KEY_F3) 56 + MATRIX_KEY(0x03, 0x00, KEY_F16) 57 + MATRIX_KEY(0x03, 0x01, KEY_F12) 58 + MATRIX_KEY(0x03, 0x02, KEY_F8) 59 + MATRIX_KEY(0x03, 0x03, KEY_F4) >; 60 + };
+11
drivers/input/keyboard/Kconfig
··· 524 524 To compile this driver as a module, choose M here: the 525 525 module will be called stowaway. 526 526 527 + config KEYBOARD_ST_KEYSCAN 528 + tristate "STMicroelectronics keyscan support" 529 + depends on ARCH_STI || COMPILE_TEST 530 + select INPUT_MATRIXKMAP 531 + help 532 + Say Y here if you want to use a keypad attached to the keyscan block 533 + on some STMicroelectronics SoC devices. 534 + 535 + To compile this driver as a module, choose M here: the 536 + module will be called st-keyscan. 537 + 527 538 config KEYBOARD_SUNKBD 528 539 tristate "Sun Type 4 and Type 5 keyboard" 529 540 select SERIO
+1
drivers/input/keyboard/Makefile
··· 51 51 obj-$(CONFIG_KEYBOARD_SPEAR) += spear-keyboard.o 52 52 obj-$(CONFIG_KEYBOARD_STMPE) += stmpe-keypad.o 53 53 obj-$(CONFIG_KEYBOARD_STOWAWAY) += stowaway.o 54 + obj-$(CONFIG_KEYBOARD_ST_KEYSCAN) += st-keyscan.o 54 55 obj-$(CONFIG_KEYBOARD_SUNKBD) += sunkbd.o 55 56 obj-$(CONFIG_KEYBOARD_TC3589X) += tc3589x-keypad.o 56 57 obj-$(CONFIG_KEYBOARD_TEGRA) += tegra-kbc.o
+274
drivers/input/keyboard/st-keyscan.c
··· 1 + /* 2 + * STMicroelectronics Key Scanning driver 3 + * 4 + * Copyright (c) 2014 STMicroelectonics Ltd. 5 + * Author: Stuart Menefy <stuart.menefy@st.com> 6 + * 7 + * Based on sh_keysc.c, copyright 2008 Magnus Damm 8 + * 9 + * This program is free software; you can redistribute it and/or modify 10 + * it under the terms of the GNU General Public License version 2 as 11 + * published by the Free Software Foundation. 12 + */ 13 + 14 + #include <linux/module.h> 15 + #include <linux/interrupt.h> 16 + #include <linux/platform_device.h> 17 + #include <linux/clk.h> 18 + #include <linux/io.h> 19 + #include <linux/input/matrix_keypad.h> 20 + 21 + #define ST_KEYSCAN_MAXKEYS 16 22 + 23 + #define KEYSCAN_CONFIG_OFF 0x0 24 + #define KEYSCAN_CONFIG_ENABLE 0x1 25 + #define KEYSCAN_DEBOUNCE_TIME_OFF 0x4 26 + #define KEYSCAN_MATRIX_STATE_OFF 0x8 27 + #define KEYSCAN_MATRIX_DIM_OFF 0xc 28 + #define KEYSCAN_MATRIX_DIM_X_SHIFT 0x0 29 + #define KEYSCAN_MATRIX_DIM_Y_SHIFT 0x2 30 + 31 + struct st_keyscan { 32 + void __iomem *base; 33 + int irq; 34 + struct clk *clk; 35 + struct input_dev *input_dev; 36 + unsigned long last_state; 37 + unsigned int n_rows; 38 + unsigned int n_cols; 39 + unsigned int debounce_us; 40 + }; 41 + 42 + static irqreturn_t keyscan_isr(int irq, void *dev_id) 43 + { 44 + struct st_keyscan *keypad = dev_id; 45 + unsigned short *keycode = keypad->input_dev->keycode; 46 + unsigned long state, change; 47 + int bit_nr; 48 + 49 + state = readl(keypad->base + KEYSCAN_MATRIX_STATE_OFF) & 0xffff; 50 + change = keypad->last_state ^ state; 51 + keypad->last_state = state; 52 + 53 + for_each_set_bit(bit_nr, &change, BITS_PER_LONG) 54 + input_report_key(keypad->input_dev, 55 + keycode[bit_nr], state & BIT(bit_nr)); 56 + 57 + input_sync(keypad->input_dev); 58 + 59 + return IRQ_HANDLED; 60 + } 61 + 62 + static int keyscan_start(struct st_keyscan *keypad) 63 + { 64 + int error; 65 + 66 + error = clk_enable(keypad->clk); 67 + if (error) 68 + return error; 69 + 70 + writel(keypad->debounce_us * (clk_get_rate(keypad->clk) / 1000000), 71 + keypad->base + KEYSCAN_DEBOUNCE_TIME_OFF); 72 + 73 + writel(((keypad->n_cols - 1) << KEYSCAN_MATRIX_DIM_X_SHIFT) | 74 + ((keypad->n_rows - 1) << KEYSCAN_MATRIX_DIM_Y_SHIFT), 75 + keypad->base + KEYSCAN_MATRIX_DIM_OFF); 76 + 77 + writel(KEYSCAN_CONFIG_ENABLE, keypad->base + KEYSCAN_CONFIG_OFF); 78 + 79 + return 0; 80 + } 81 + 82 + static void keyscan_stop(struct st_keyscan *keypad) 83 + { 84 + writel(0, keypad->base + KEYSCAN_CONFIG_OFF); 85 + 86 + clk_disable(keypad->clk); 87 + } 88 + 89 + static int keyscan_open(struct input_dev *dev) 90 + { 91 + struct st_keyscan *keypad = input_get_drvdata(dev); 92 + 93 + return keyscan_start(keypad); 94 + } 95 + 96 + static void keyscan_close(struct input_dev *dev) 97 + { 98 + struct st_keyscan *keypad = input_get_drvdata(dev); 99 + 100 + keyscan_stop(keypad); 101 + } 102 + 103 + static int keypad_matrix_key_parse_dt(struct st_keyscan *keypad_data) 104 + { 105 + struct device *dev = keypad_data->input_dev->dev.parent; 106 + struct device_node *np = dev->of_node; 107 + int error; 108 + 109 + error = matrix_keypad_parse_of_params(dev, &keypad_data->n_rows, 110 + &keypad_data->n_cols); 111 + if (error) { 112 + dev_err(dev, "failed to parse keypad params\n"); 113 + return error; 114 + } 115 + 116 + of_property_read_u32(np, "st,debounce-us", &keypad_data->debounce_us); 117 + 118 + dev_dbg(dev, "n_rows=%d n_col=%d debounce=%d\n", 119 + keypad_data->n_rows, keypad_data->n_cols, 120 + keypad_data->debounce_us); 121 + 122 + return 0; 123 + } 124 + 125 + static int keyscan_probe(struct platform_device *pdev) 126 + { 127 + struct st_keyscan *keypad_data; 128 + struct input_dev *input_dev; 129 + struct resource *res; 130 + int error; 131 + 132 + if (!pdev->dev.of_node) { 133 + dev_err(&pdev->dev, "no DT data present\n"); 134 + return -EINVAL; 135 + } 136 + 137 + keypad_data = devm_kzalloc(&pdev->dev, sizeof(*keypad_data), 138 + GFP_KERNEL); 139 + if (!keypad_data) 140 + return -ENOMEM; 141 + 142 + input_dev = devm_input_allocate_device(&pdev->dev); 143 + if (!input_dev) { 144 + dev_err(&pdev->dev, "failed to allocate the input device\n"); 145 + return -ENOMEM; 146 + } 147 + 148 + input_dev->name = pdev->name; 149 + input_dev->phys = "keyscan-keys/input0"; 150 + input_dev->dev.parent = &pdev->dev; 151 + input_dev->open = keyscan_open; 152 + input_dev->close = keyscan_close; 153 + 154 + input_dev->id.bustype = BUS_HOST; 155 + 156 + error = keypad_matrix_key_parse_dt(keypad_data); 157 + if (error) 158 + return error; 159 + 160 + error = matrix_keypad_build_keymap(NULL, NULL, 161 + keypad_data->n_rows, 162 + keypad_data->n_cols, 163 + NULL, input_dev); 164 + if (error) { 165 + dev_err(&pdev->dev, "failed to build keymap\n"); 166 + return error; 167 + } 168 + 169 + input_set_drvdata(input_dev, keypad_data); 170 + 171 + keypad_data->input_dev = input_dev; 172 + 173 + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 174 + keypad_data->base = devm_ioremap_resource(&pdev->dev, res); 175 + if (IS_ERR(keypad_data->base)) 176 + return PTR_ERR(keypad_data->base); 177 + 178 + keypad_data->clk = devm_clk_get(&pdev->dev, NULL); 179 + if (IS_ERR(keypad_data->clk)) { 180 + dev_err(&pdev->dev, "cannot get clock\n"); 181 + return PTR_ERR(keypad_data->clk); 182 + } 183 + 184 + error = clk_enable(keypad_data->clk); 185 + if (error) { 186 + dev_err(&pdev->dev, "failed to enable clock\n"); 187 + return error; 188 + } 189 + 190 + keyscan_stop(keypad_data); 191 + 192 + keypad_data->irq = platform_get_irq(pdev, 0); 193 + if (keypad_data->irq < 0) { 194 + dev_err(&pdev->dev, "no IRQ specified\n"); 195 + return -EINVAL; 196 + } 197 + 198 + error = devm_request_irq(&pdev->dev, keypad_data->irq, keyscan_isr, 0, 199 + pdev->name, keypad_data); 200 + if (error) { 201 + dev_err(&pdev->dev, "failed to request IRQ\n"); 202 + return error; 203 + } 204 + 205 + error = input_register_device(input_dev); 206 + if (error) { 207 + dev_err(&pdev->dev, "failed to register input device\n"); 208 + return error; 209 + } 210 + 211 + platform_set_drvdata(pdev, keypad_data); 212 + 213 + device_set_wakeup_capable(&pdev->dev, 1); 214 + 215 + return 0; 216 + } 217 + 218 + static int keyscan_suspend(struct device *dev) 219 + { 220 + struct platform_device *pdev = to_platform_device(dev); 221 + struct st_keyscan *keypad = platform_get_drvdata(pdev); 222 + struct input_dev *input = keypad->input_dev; 223 + 224 + mutex_lock(&input->mutex); 225 + 226 + if (device_may_wakeup(dev)) 227 + enable_irq_wake(keypad->irq); 228 + else if (input->users) 229 + keyscan_stop(keypad); 230 + 231 + mutex_unlock(&input->mutex); 232 + return 0; 233 + } 234 + 235 + static int keyscan_resume(struct device *dev) 236 + { 237 + struct platform_device *pdev = to_platform_device(dev); 238 + struct st_keyscan *keypad = platform_get_drvdata(pdev); 239 + struct input_dev *input = keypad->input_dev; 240 + int retval = 0; 241 + 242 + mutex_lock(&input->mutex); 243 + 244 + if (device_may_wakeup(dev)) 245 + disable_irq_wake(keypad->irq); 246 + else if (input->users) 247 + retval = keyscan_start(keypad); 248 + 249 + mutex_unlock(&input->mutex); 250 + return retval; 251 + } 252 + 253 + static SIMPLE_DEV_PM_OPS(keyscan_dev_pm_ops, keyscan_suspend, keyscan_resume); 254 + 255 + static const struct of_device_id keyscan_of_match[] = { 256 + { .compatible = "st,sti-keyscan" }, 257 + { }, 258 + }; 259 + MODULE_DEVICE_TABLE(of, keyscan_of_match); 260 + 261 + static struct platform_driver keyscan_device_driver = { 262 + .probe = keyscan_probe, 263 + .driver = { 264 + .name = "st-keyscan", 265 + .pm = &keyscan_dev_pm_ops, 266 + .of_match_table = of_match_ptr(keyscan_of_match), 267 + } 268 + }; 269 + 270 + module_platform_driver(keyscan_device_driver); 271 + 272 + MODULE_AUTHOR("Stuart Menefy <stuart.menefy@st.com>"); 273 + MODULE_DESCRIPTION("STMicroelectronics keyscan device driver"); 274 + MODULE_LICENSE("GPL");