1 /* 2 * SPEAr Keyboard Driver 3 * Based on omap-keypad driver 4 * 5 * Copyright (C) 2010 ST Microelectronics 6 * Rajeev Kumar <rajeevkumar.linux@gmail.com> 7 * 8 * This file is licensed under the terms of the GNU General Public 9 * License version 2. This program is licensed "as is" without any 10 * warranty of any kind, whether express or implied. 11 */ 12 13 #include <linux/clk.h> 14 #include <linux/errno.h> 15 #include <linux/interrupt.h> 16 #include <linux/input.h> 17 #include <linux/input/matrix_keypad.h> 18 #include <linux/io.h> 19 #include <linux/irq.h> 20 #include <linux/kernel.h> 21 #include <linux/module.h> 22 #include <linux/of.h> 23 #include <linux/platform_device.h> 24 #include <linux/slab.h> 25 #include <linux/types.h> 26 27 /* Keyboard Registers */ 28 #define MODE_CTL_REG 0x00 29 #define STATUS_REG 0x0C 30 #define DATA_REG 0x10 31 #define INTR_MASK 0x54 32 33 /* Register Values */ 34 #define NUM_ROWS 16 35 #define NUM_COLS 16 36 #define MODE_CTL_PCLK_FREQ_SHIFT 9 37 #define MODE_CTL_PCLK_FREQ_MSK 0x7F 38 39 #define MODE_CTL_KEYBOARD (0x2 << 0) 40 #define MODE_CTL_SCAN_RATE_10 (0x0 << 2) 41 #define MODE_CTL_SCAN_RATE_20 (0x1 << 2) 42 #define MODE_CTL_SCAN_RATE_40 (0x2 << 2) 43 #define MODE_CTL_SCAN_RATE_80 (0x3 << 2) 44 #define MODE_CTL_KEYNUM_SHIFT 6 45 #define MODE_CTL_START_SCAN (0x1 << 8) 46 47 #define STATUS_DATA_AVAIL (0x1 << 1) 48 49 #define DATA_ROW_MASK 0xF0 50 #define DATA_COLUMN_MASK 0x0F 51 52 #define ROW_SHIFT 4 53 54 struct spear_kbd { 55 struct input_dev *input; 56 void __iomem *io_base; 57 struct clk *clk; 58 unsigned int irq; 59 u32 mode; 60 u32 suspended_rate; 61 u32 mode_ctl_reg; 62 unsigned short last_key; 63 unsigned short keycodes[NUM_ROWS * NUM_COLS]; 64 bool irq_wake_enabled; 65 }; 66 67 static irqreturn_t spear_kbd_interrupt(int irq, void *dev_id) 68 { 69 struct spear_kbd *kbd = dev_id; 70 struct input_dev *input = kbd->input; 71 unsigned int key; 72 u32 sts, val; 73 74 sts = readl_relaxed(kbd->io_base + STATUS_REG); 75 if (!(sts & STATUS_DATA_AVAIL)) 76 return IRQ_NONE; 77 78 if (kbd->last_key != KEY_RESERVED) { 79 input_report_key(input, kbd->last_key, 0); 80 kbd->last_key = KEY_RESERVED; 81 } 82 83 /* following reads active (row, col) pair */ 84 val = readl_relaxed(kbd->io_base + DATA_REG) & 85 (DATA_ROW_MASK | DATA_COLUMN_MASK); 86 key = kbd->keycodes[val]; 87 88 input_event(input, EV_MSC, MSC_SCAN, val); 89 input_report_key(input, key, 1); 90 input_sync(input); 91 92 kbd->last_key = key; 93 94 /* clear interrupt */ 95 writel_relaxed(0, kbd->io_base + STATUS_REG); 96 97 return IRQ_HANDLED; 98 } 99 100 static int spear_kbd_open(struct input_dev *dev) 101 { 102 struct spear_kbd *kbd = input_get_drvdata(dev); 103 int error; 104 u32 val; 105 106 kbd->last_key = KEY_RESERVED; 107 108 error = clk_enable(kbd->clk); 109 if (error) 110 return error; 111 112 /* keyboard rate to be programmed is input clock (in MHz) - 1 */ 113 val = clk_get_rate(kbd->clk) / 1000000 - 1; 114 val = (val & MODE_CTL_PCLK_FREQ_MSK) << MODE_CTL_PCLK_FREQ_SHIFT; 115 116 /* program keyboard */ 117 val = MODE_CTL_SCAN_RATE_80 | MODE_CTL_KEYBOARD | val | 118 (kbd->mode << MODE_CTL_KEYNUM_SHIFT); 119 writel_relaxed(val, kbd->io_base + MODE_CTL_REG); 120 writel_relaxed(1, kbd->io_base + STATUS_REG); 121 122 /* start key scan */ 123 val = readl_relaxed(kbd->io_base + MODE_CTL_REG); 124 val |= MODE_CTL_START_SCAN; 125 writel_relaxed(val, kbd->io_base + MODE_CTL_REG); 126 127 return 0; 128 } 129 130 static void spear_kbd_close(struct input_dev *dev) 131 { 132 struct spear_kbd *kbd = input_get_drvdata(dev); 133 u32 val; 134 135 /* stop key scan */ 136 val = readl_relaxed(kbd->io_base + MODE_CTL_REG); 137 val &= ~MODE_CTL_START_SCAN; 138 writel_relaxed(val, kbd->io_base + MODE_CTL_REG); 139 140 clk_disable(kbd->clk); 141 142 kbd->last_key = KEY_RESERVED; 143 } 144 145 static int spear_kbd_probe(struct platform_device *pdev) 146 { 147 struct spear_kbd *kbd; 148 struct input_dev *input_dev; 149 int irq; 150 int error; 151 152 irq = platform_get_irq(pdev, 0); 153 if (irq < 0) 154 return irq; 155 156 kbd = devm_kzalloc(&pdev->dev, sizeof(*kbd), GFP_KERNEL); 157 if (!kbd) { 158 dev_err(&pdev->dev, "not enough memory for driver data\n"); 159 return -ENOMEM; 160 } 161 162 error = device_property_read_u32(&pdev->dev, "st,mode", &kbd->mode); 163 if (error) { 164 dev_err(&pdev->dev, "Invalid or missing mode\n"); 165 return error; 166 } 167 168 device_property_read_u32(&pdev->dev, "suspended_rate", &kbd->suspended_rate); 169 170 input_dev = devm_input_allocate_device(&pdev->dev); 171 if (!input_dev) { 172 dev_err(&pdev->dev, "unable to allocate input device\n"); 173 return -ENOMEM; 174 } 175 176 kbd->input = input_dev; 177 kbd->irq = irq; 178 179 kbd->io_base = devm_platform_get_and_ioremap_resource(pdev, 0, NULL); 180 if (IS_ERR(kbd->io_base)) 181 return PTR_ERR(kbd->io_base); 182 183 kbd->clk = devm_clk_get_prepared(&pdev->dev, NULL); 184 if (IS_ERR(kbd->clk)) 185 return PTR_ERR(kbd->clk); 186 187 input_dev->name = "Spear Keyboard"; 188 input_dev->phys = "keyboard/input0"; 189 input_dev->id.bustype = BUS_HOST; 190 input_dev->id.vendor = 0x0001; 191 input_dev->id.product = 0x0001; 192 input_dev->id.version = 0x0100; 193 input_dev->open = spear_kbd_open; 194 input_dev->close = spear_kbd_close; 195 196 error = matrix_keypad_build_keymap(NULL, NULL, NUM_ROWS, NUM_COLS, 197 kbd->keycodes, input_dev); 198 if (error) { 199 dev_err(&pdev->dev, "Failed to build keymap\n"); 200 return error; 201 } 202 203 if (device_property_read_bool(&pdev->dev, "autorepeat")) 204 __set_bit(EV_REP, input_dev->evbit); 205 input_set_capability(input_dev, EV_MSC, MSC_SCAN); 206 207 input_set_drvdata(input_dev, kbd); 208 209 error = devm_request_irq(&pdev->dev, irq, spear_kbd_interrupt, 0, 210 "keyboard", kbd); 211 if (error) { 212 dev_err(&pdev->dev, "request_irq failed\n"); 213 return error; 214 } 215 216 error = input_register_device(input_dev); 217 if (error) { 218 dev_err(&pdev->dev, "Unable to register keyboard device\n"); 219 return error; 220 } 221 222 device_init_wakeup(&pdev->dev, 1); 223 platform_set_drvdata(pdev, kbd); 224 225 return 0; 226 } 227 228 static int spear_kbd_suspend(struct device *dev) 229 { 230 struct platform_device *pdev = to_platform_device(dev); 231 struct spear_kbd *kbd = platform_get_drvdata(pdev); 232 struct input_dev *input_dev = kbd->input; 233 unsigned int rate = 0, mode_ctl_reg, val; 234 235 guard(mutex)(&input_dev->mutex); 236 237 /* explicitly enable clock as we may program device */ 238 clk_enable(kbd->clk); 239 240 mode_ctl_reg = readl_relaxed(kbd->io_base + MODE_CTL_REG); 241 242 if (device_may_wakeup(&pdev->dev)) { 243 if (!enable_irq_wake(kbd->irq)) 244 kbd->irq_wake_enabled = true; 245 246 /* 247 * reprogram the keyboard operating frequency as on some 248 * platform it may change during system suspended 249 */ 250 if (kbd->suspended_rate) 251 rate = kbd->suspended_rate / 1000000 - 1; 252 else 253 rate = clk_get_rate(kbd->clk) / 1000000 - 1; 254 255 val = mode_ctl_reg & 256 ~(MODE_CTL_PCLK_FREQ_MSK << MODE_CTL_PCLK_FREQ_SHIFT); 257 val |= (rate & MODE_CTL_PCLK_FREQ_MSK) 258 << MODE_CTL_PCLK_FREQ_SHIFT; 259 writel_relaxed(val, kbd->io_base + MODE_CTL_REG); 260 261 } else { 262 if (input_device_enabled(input_dev)) { 263 writel_relaxed(mode_ctl_reg & ~MODE_CTL_START_SCAN, 264 kbd->io_base + MODE_CTL_REG); 265 clk_disable(kbd->clk); 266 } 267 } 268 269 /* store current configuration */ 270 if (input_device_enabled(input_dev)) 271 kbd->mode_ctl_reg = mode_ctl_reg; 272 273 /* restore previous clk state */ 274 clk_disable(kbd->clk); 275 276 return 0; 277 } 278 279 static int spear_kbd_resume(struct device *dev) 280 { 281 struct platform_device *pdev = to_platform_device(dev); 282 struct spear_kbd *kbd = platform_get_drvdata(pdev); 283 struct input_dev *input_dev = kbd->input; 284 285 guard(mutex)(&input_dev->mutex); 286 287 if (device_may_wakeup(&pdev->dev)) { 288 if (kbd->irq_wake_enabled) { 289 kbd->irq_wake_enabled = false; 290 disable_irq_wake(kbd->irq); 291 } 292 } else { 293 if (input_device_enabled(input_dev)) 294 clk_enable(kbd->clk); 295 } 296 297 /* restore current configuration */ 298 if (input_device_enabled(input_dev)) 299 writel_relaxed(kbd->mode_ctl_reg, kbd->io_base + MODE_CTL_REG); 300 301 return 0; 302 } 303 304 static DEFINE_SIMPLE_DEV_PM_OPS(spear_kbd_pm_ops, 305 spear_kbd_suspend, spear_kbd_resume); 306 307 #ifdef CONFIG_OF 308 static const struct of_device_id spear_kbd_id_table[] = { 309 { .compatible = "st,spear300-kbd" }, 310 {} 311 }; 312 MODULE_DEVICE_TABLE(of, spear_kbd_id_table); 313 #endif 314 315 static struct platform_driver spear_kbd_driver = { 316 .probe = spear_kbd_probe, 317 .driver = { 318 .name = "keyboard", 319 .pm = pm_sleep_ptr(&spear_kbd_pm_ops), 320 .of_match_table = of_match_ptr(spear_kbd_id_table), 321 }, 322 }; 323 module_platform_driver(spear_kbd_driver); 324 325 MODULE_AUTHOR("Rajeev Kumar"); 326 MODULE_DESCRIPTION("SPEAr Keyboard Driver"); 327 MODULE_LICENSE("GPL"); 328