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

Configure Feed

Select the types of activity you want to include in your feed.

at v3.1-rc10 344 lines 7.9 kB view raw
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 54struct 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 64static 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 96static 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 121static 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 136static 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 241err_free_irq: 242 free_irq(kbd->irq, kbd); 243err_put_clk: 244 clk_put(kbd->clk); 245err_iounmap: 246 iounmap(kbd->io_base); 247err_release_mem_region: 248 release_mem_region(res->start, resource_size(res)); 249err_free_mem: 250 input_free_device(input_dev); 251 kfree(kbd); 252 253 return error; 254} 255 256static 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 274static 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 293static 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 312static const struct dev_pm_ops spear_kbd_pm_ops = { 313 .suspend = spear_kbd_suspend, 314 .resume = spear_kbd_resume, 315}; 316#endif 317 318static 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 330static int __init spear_kbd_init(void) 331{ 332 return platform_driver_register(&spear_kbd_driver); 333} 334module_init(spear_kbd_init); 335 336static void __exit spear_kbd_exit(void) 337{ 338 platform_driver_unregister(&spear_kbd_driver); 339} 340module_exit(spear_kbd_exit); 341 342MODULE_AUTHOR("Rajeev Kumar"); 343MODULE_DESCRIPTION("SPEAr Keyboard Driver"); 344MODULE_LICENSE("GPL");