1 /* 2 * SPEAr Keyboard Driver 3 * Based on omap-keypad driver 4 * 5 * Copyright (C) 2010 ST Microelectronics 6 * Rajeev Kumar<rajeev-dlh.kumar@st.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/init.h> 16 #include <linux/interrupt.h> 17 #include <linux/input.h> 18 #include <linux/io.h> 19 #include <linux/irq.h> 20 #include <linux/kernel.h> 21 #include <linux/module.h> 22 #include <linux/platform_device.h> 23 #include <linux/pm_wakeup.h> 24 #include <linux/slab.h> 25 #include <linux/types.h> 26 #include <plat/keyboard.h> 27 28 /* Keyboard Registers */ 29 #define MODE_REG 0x00 /* 16 bit reg */ 30 #define STATUS_REG 0x0C /* 2 bit reg */ 31 #define DATA_REG 0x10 /* 8 bit reg */ 32 #define INTR_MASK 0x54 33 34 /* Register Values */ 35 /* 36 * pclk freq mask = (APB FEQ -1)= 82 MHZ.Programme bit 15-9 in mode 37 * control register as 1010010(82MHZ) 38 */ 39 #define PCLK_FREQ_MSK 0xA400 /* 82 MHz */ 40 #define START_SCAN 0x0100 41 #define SCAN_RATE_10 0x0000 42 #define SCAN_RATE_20 0x0004 43 #define SCAN_RATE_40 0x0008 44 #define SCAN_RATE_80 0x000C 45 #define MODE_KEYBOARD 0x0002 46 #define DATA_AVAIL 0x2 47 48 #define KEY_MASK 0xFF000000 49 #define KEY_VALUE 0x00FFFFFF 50 #define ROW_MASK 0xF0 51 #define COLUMN_MASK 0x0F 52 #define ROW_SHIFT 4 53 54 struct spear_kbd { 55 struct input_dev *input; 56 struct resource *res; 57 void __iomem *io_base; 58 struct clk *clk; 59 unsigned int irq; 60 unsigned short last_key; 61 unsigned short keycodes[256]; 62 }; 63 64 static irqreturn_t spear_kbd_interrupt(int irq, void *dev_id) 65 { 66 struct spear_kbd *kbd = dev_id; 67 struct input_dev *input = kbd->input; 68 unsigned int key; 69 u8 sts, val; 70 71 sts = readb(kbd->io_base + STATUS_REG); 72 if (sts & DATA_AVAIL) 73 return IRQ_NONE; 74 75 if (kbd->last_key != KEY_RESERVED) { 76 input_report_key(input, kbd->last_key, 0); 77 kbd->last_key = KEY_RESERVED; 78 } 79 80 /* following reads active (row, col) pair */ 81 val = readb(kbd->io_base + DATA_REG); 82 key = kbd->keycodes[val]; 83 84 input_event(input, EV_MSC, MSC_SCAN, val); 85 input_report_key(input, key, 1); 86 input_sync(input); 87 88 kbd->last_key = key; 89 90 /* clear interrupt */ 91 writeb(0, kbd->io_base + STATUS_REG); 92 93 return IRQ_HANDLED; 94 } 95 96 static int spear_kbd_open(struct input_dev *dev) 97 { 98 struct spear_kbd *kbd = input_get_drvdata(dev); 99 int error; 100 u16 val; 101 102 kbd->last_key = KEY_RESERVED; 103 104 error = clk_enable(kbd->clk); 105 if (error) 106 return error; 107 108 /* program keyboard */ 109 val = SCAN_RATE_80 | MODE_KEYBOARD | PCLK_FREQ_MSK; 110 writew(val, kbd->io_base + MODE_REG); 111 writeb(1, kbd->io_base + STATUS_REG); 112 113 /* start key scan */ 114 val = readw(kbd->io_base + MODE_REG); 115 val |= START_SCAN; 116 writew(val, kbd->io_base + MODE_REG); 117 118 return 0; 119 } 120 121 static void spear_kbd_close(struct input_dev *dev) 122 { 123 struct spear_kbd *kbd = input_get_drvdata(dev); 124 u16 val; 125 126 /* stop key scan */ 127 val = readw(kbd->io_base + MODE_REG); 128 val &= ~START_SCAN; 129 writew(val, kbd->io_base + MODE_REG); 130 131 clk_disable(kbd->clk); 132 133 kbd->last_key = KEY_RESERVED; 134 } 135 136 static int __devinit spear_kbd_probe(struct platform_device *pdev) 137 { 138 const struct kbd_platform_data *pdata = pdev->dev.platform_data; 139 const struct matrix_keymap_data *keymap; 140 struct spear_kbd *kbd; 141 struct input_dev *input_dev; 142 struct resource *res; 143 int irq; 144 int error; 145 146 if (!pdata) { 147 dev_err(&pdev->dev, "Invalid platform data\n"); 148 return -EINVAL; 149 } 150 151 keymap = pdata->keymap; 152 if (!keymap) { 153 dev_err(&pdev->dev, "no keymap defined\n"); 154 return -EINVAL; 155 } 156 157 res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 158 if (!res) { 159 dev_err(&pdev->dev, "no keyboard resource defined\n"); 160 return -EBUSY; 161 } 162 163 irq = platform_get_irq(pdev, 0); 164 if (irq < 0) { 165 dev_err(&pdev->dev, "not able to get irq for the device\n"); 166 return irq; 167 } 168 169 kbd = kzalloc(sizeof(*kbd), GFP_KERNEL); 170 input_dev = input_allocate_device(); 171 if (!kbd || !input_dev) { 172 dev_err(&pdev->dev, "out of memory\n"); 173 error = -ENOMEM; 174 goto err_free_mem; 175 } 176 177 kbd->input = input_dev; 178 kbd->irq = irq; 179 kbd->res = request_mem_region(res->start, resource_size(res), 180 pdev->name); 181 if (!kbd->res) { 182 dev_err(&pdev->dev, "keyboard region already claimed\n"); 183 error = -EBUSY; 184 goto err_free_mem; 185 } 186 187 kbd->io_base = ioremap(res->start, resource_size(res)); 188 if (!kbd->io_base) { 189 dev_err(&pdev->dev, "ioremap failed for kbd_region\n"); 190 error = -ENOMEM; 191 goto err_release_mem_region; 192 } 193 194 kbd->clk = clk_get(&pdev->dev, NULL); 195 if (IS_ERR(kbd->clk)) { 196 error = PTR_ERR(kbd->clk); 197 goto err_iounmap; 198 } 199 200 input_dev->name = "Spear Keyboard"; 201 input_dev->phys = "keyboard/input0"; 202 input_dev->dev.parent = &pdev->dev; 203 input_dev->id.bustype = BUS_HOST; 204 input_dev->id.vendor = 0x0001; 205 input_dev->id.product = 0x0001; 206 input_dev->id.version = 0x0100; 207 input_dev->open = spear_kbd_open; 208 input_dev->close = spear_kbd_close; 209 210 __set_bit(EV_KEY, input_dev->evbit); 211 if (pdata->rep) 212 __set_bit(EV_REP, input_dev->evbit); 213 input_set_capability(input_dev, EV_MSC, MSC_SCAN); 214 215 input_dev->keycode = kbd->keycodes; 216 input_dev->keycodesize = sizeof(kbd->keycodes[0]); 217 input_dev->keycodemax = ARRAY_SIZE(kbd->keycodes); 218 219 matrix_keypad_build_keymap(keymap, ROW_SHIFT, 220 input_dev->keycode, input_dev->keybit); 221 222 input_set_drvdata(input_dev, kbd); 223 224 error = request_irq(irq, spear_kbd_interrupt, 0, "keyboard", kbd); 225 if (error) { 226 dev_err(&pdev->dev, "request_irq fail\n"); 227 goto err_put_clk; 228 } 229 230 error = input_register_device(input_dev); 231 if (error) { 232 dev_err(&pdev->dev, "Unable to register keyboard device\n"); 233 goto err_free_irq; 234 } 235 236 device_init_wakeup(&pdev->dev, 1); 237 platform_set_drvdata(pdev, kbd); 238 239 return 0; 240 241 err_free_irq: 242 free_irq(kbd->irq, kbd); 243 err_put_clk: 244 clk_put(kbd->clk); 245 err_iounmap: 246 iounmap(kbd->io_base); 247 err_release_mem_region: 248 release_mem_region(res->start, resource_size(res)); 249 err_free_mem: 250 input_free_device(input_dev); 251 kfree(kbd); 252 253 return error; 254 } 255 256 static int __devexit spear_kbd_remove(struct platform_device *pdev) 257 { 258 struct spear_kbd *kbd = platform_get_drvdata(pdev); 259 260 free_irq(kbd->irq, kbd); 261 input_unregister_device(kbd->input); 262 clk_put(kbd->clk); 263 iounmap(kbd->io_base); 264 release_mem_region(kbd->res->start, resource_size(kbd->res)); 265 kfree(kbd); 266 267 device_init_wakeup(&pdev->dev, 1); 268 platform_set_drvdata(pdev, NULL); 269 270 return 0; 271 } 272 273 #ifdef CONFIG_PM 274 static int spear_kbd_suspend(struct device *dev) 275 { 276 struct platform_device *pdev = to_platform_device(dev); 277 struct spear_kbd *kbd = platform_get_drvdata(pdev); 278 struct input_dev *input_dev = kbd->input; 279 280 mutex_lock(&input_dev->mutex); 281 282 if (input_dev->users) 283 clk_enable(kbd->clk); 284 285 if (device_may_wakeup(&pdev->dev)) 286 enable_irq_wake(kbd->irq); 287 288 mutex_unlock(&input_dev->mutex); 289 290 return 0; 291 } 292 293 static int spear_kbd_resume(struct device *dev) 294 { 295 struct platform_device *pdev = to_platform_device(dev); 296 struct spear_kbd *kbd = platform_get_drvdata(pdev); 297 struct input_dev *input_dev = kbd->input; 298 299 mutex_lock(&input_dev->mutex); 300 301 if (device_may_wakeup(&pdev->dev)) 302 disable_irq_wake(kbd->irq); 303 304 if (input_dev->users) 305 clk_enable(kbd->clk); 306 307 mutex_unlock(&input_dev->mutex); 308 309 return 0; 310 } 311 312 static const struct dev_pm_ops spear_kbd_pm_ops = { 313 .suspend = spear_kbd_suspend, 314 .resume = spear_kbd_resume, 315 }; 316 #endif 317 318 static struct platform_driver spear_kbd_driver = { 319 .probe = spear_kbd_probe, 320 .remove = __devexit_p(spear_kbd_remove), 321 .driver = { 322 .name = "keyboard", 323 .owner = THIS_MODULE, 324 #ifdef CONFIG_PM 325 .pm = &spear_kbd_pm_ops, 326 #endif 327 }, 328 }; 329 330 static int __init spear_kbd_init(void) 331 { 332 return platform_driver_register(&spear_kbd_driver); 333 } 334 module_init(spear_kbd_init); 335 336 static void __exit spear_kbd_exit(void) 337 { 338 platform_driver_unregister(&spear_kbd_driver); 339 } 340 module_exit(spear_kbd_exit); 341 342 MODULE_AUTHOR("Rajeev Kumar"); 343 MODULE_DESCRIPTION("SPEAr Keyboard Driver"); 344 MODULE_LICENSE("GPL"); 345