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 v2.6.34-rc1 281 lines 7.0 kB view raw
1/* 2 * Copyright (c) 2008-2009 Nuvoton technology corporation. 3 * 4 * Wan ZongShun <mcuos.com@gmail.com> 5 * 6 * This program is free software; you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License as published by 8 * the Free Software Foundation;version 2 of the License. 9 * 10 */ 11 12#include <linux/kernel.h> 13#include <linux/module.h> 14#include <linux/init.h> 15#include <linux/interrupt.h> 16#include <linux/input.h> 17#include <linux/device.h> 18#include <linux/platform_device.h> 19#include <linux/clk.h> 20#include <linux/err.h> 21#include <linux/io.h> 22 23#include <mach/w90p910_keypad.h> 24 25/* Keypad Interface Control Registers */ 26#define KPI_CONF 0x00 27#define KPI_3KCONF 0x04 28#define KPI_LPCONF 0x08 29#define KPI_STATUS 0x0C 30 31#define IS1KEY (0x01 << 16) 32#define INTTR (0x01 << 21) 33#define KEY0R (0x0f << 3) 34#define KEY0C 0x07 35#define DEBOUNCE_BIT 0x08 36#define KSIZE0 (0x01 << 16) 37#define KSIZE1 (0x01 << 17) 38#define KPSEL (0x01 << 19) 39#define ENKP (0x01 << 18) 40 41#define KGET_RAW(n) (((n) & KEY0R) >> 3) 42#define KGET_COLUMN(n) ((n) & KEY0C) 43 44#define W90P910_MAX_KEY_NUM (8 * 8) 45#define W90P910_ROW_SHIFT 3 46 47struct w90p910_keypad { 48 const struct w90p910_keypad_platform_data *pdata; 49 struct clk *clk; 50 struct input_dev *input_dev; 51 void __iomem *mmio_base; 52 int irq; 53 unsigned short keymap[W90P910_MAX_KEY_NUM]; 54}; 55 56static void w90p910_keypad_scan_matrix(struct w90p910_keypad *keypad, 57 unsigned int status) 58{ 59 struct input_dev *input_dev = keypad->input_dev; 60 unsigned int row = KGET_RAW(status); 61 unsigned int col = KGET_COLUMN(status); 62 unsigned int code = MATRIX_SCAN_CODE(row, col, W90P910_ROW_SHIFT); 63 unsigned int key = keypad->keymap[code]; 64 65 input_event(input_dev, EV_MSC, MSC_SCAN, code); 66 input_report_key(input_dev, key, 1); 67 input_sync(input_dev); 68 69 input_event(input_dev, EV_MSC, MSC_SCAN, code); 70 input_report_key(input_dev, key, 0); 71 input_sync(input_dev); 72} 73 74static irqreturn_t w90p910_keypad_irq_handler(int irq, void *dev_id) 75{ 76 struct w90p910_keypad *keypad = dev_id; 77 unsigned int kstatus, val; 78 79 kstatus = __raw_readl(keypad->mmio_base + KPI_STATUS); 80 81 val = INTTR | IS1KEY; 82 83 if (kstatus & val) 84 w90p910_keypad_scan_matrix(keypad, kstatus); 85 86 return IRQ_HANDLED; 87} 88 89static int w90p910_keypad_open(struct input_dev *dev) 90{ 91 struct w90p910_keypad *keypad = input_get_drvdata(dev); 92 const struct w90p910_keypad_platform_data *pdata = keypad->pdata; 93 unsigned int val, config; 94 95 /* Enable unit clock */ 96 clk_enable(keypad->clk); 97 98 val = __raw_readl(keypad->mmio_base + KPI_CONF); 99 val |= (KPSEL | ENKP); 100 val &= ~(KSIZE0 | KSIZE1); 101 102 config = pdata->prescale | (pdata->debounce << DEBOUNCE_BIT); 103 104 val |= config; 105 106 __raw_writel(val, keypad->mmio_base + KPI_CONF); 107 108 return 0; 109} 110 111static void w90p910_keypad_close(struct input_dev *dev) 112{ 113 struct w90p910_keypad *keypad = input_get_drvdata(dev); 114 115 /* Disable clock unit */ 116 clk_disable(keypad->clk); 117} 118 119static int __devinit w90p910_keypad_probe(struct platform_device *pdev) 120{ 121 const struct w90p910_keypad_platform_data *pdata = 122 pdev->dev.platform_data; 123 const struct matrix_keymap_data *keymap_data; 124 struct w90p910_keypad *keypad; 125 struct input_dev *input_dev; 126 struct resource *res; 127 int irq; 128 int error; 129 130 if (!pdata) { 131 dev_err(&pdev->dev, "no platform data defined\n"); 132 return -EINVAL; 133 } 134 135 keymap_data = pdata->keymap_data; 136 137 irq = platform_get_irq(pdev, 0); 138 if (irq < 0) { 139 dev_err(&pdev->dev, "failed to get keypad irq\n"); 140 return -ENXIO; 141 } 142 143 keypad = kzalloc(sizeof(struct w90p910_keypad), GFP_KERNEL); 144 input_dev = input_allocate_device(); 145 if (!keypad || !input_dev) { 146 dev_err(&pdev->dev, "failed to allocate driver data\n"); 147 error = -ENOMEM; 148 goto failed_free; 149 } 150 151 keypad->pdata = pdata; 152 keypad->input_dev = input_dev; 153 keypad->irq = irq; 154 155 res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 156 if (res == NULL) { 157 dev_err(&pdev->dev, "failed to get I/O memory\n"); 158 error = -ENXIO; 159 goto failed_free; 160 } 161 162 res = request_mem_region(res->start, resource_size(res), pdev->name); 163 if (res == NULL) { 164 dev_err(&pdev->dev, "failed to request I/O memory\n"); 165 error = -EBUSY; 166 goto failed_free; 167 } 168 169 keypad->mmio_base = ioremap(res->start, resource_size(res)); 170 if (keypad->mmio_base == NULL) { 171 dev_err(&pdev->dev, "failed to remap I/O memory\n"); 172 error = -ENXIO; 173 goto failed_free_res; 174 } 175 176 keypad->clk = clk_get(&pdev->dev, NULL); 177 if (IS_ERR(keypad->clk)) { 178 dev_err(&pdev->dev, "failed to get keypad clock\n"); 179 error = PTR_ERR(keypad->clk); 180 goto failed_free_io; 181 } 182 183 /* set multi-function pin for w90p910 kpi. */ 184 mfp_set_groupi(&pdev->dev); 185 186 input_dev->name = pdev->name; 187 input_dev->id.bustype = BUS_HOST; 188 input_dev->open = w90p910_keypad_open; 189 input_dev->close = w90p910_keypad_close; 190 input_dev->dev.parent = &pdev->dev; 191 192 input_dev->keycode = keypad->keymap; 193 input_dev->keycodesize = sizeof(keypad->keymap[0]); 194 input_dev->keycodemax = ARRAY_SIZE(keypad->keymap); 195 196 input_set_drvdata(input_dev, keypad); 197 198 input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REP); 199 input_set_capability(input_dev, EV_MSC, MSC_SCAN); 200 201 matrix_keypad_build_keymap(keymap_data, W90P910_ROW_SHIFT, 202 input_dev->keycode, input_dev->keybit); 203 204 error = request_irq(keypad->irq, w90p910_keypad_irq_handler, 205 IRQF_DISABLED, pdev->name, keypad); 206 if (error) { 207 dev_err(&pdev->dev, "failed to request IRQ\n"); 208 goto failed_put_clk; 209 } 210 211 /* Register the input device */ 212 error = input_register_device(input_dev); 213 if (error) { 214 dev_err(&pdev->dev, "failed to register input device\n"); 215 goto failed_free_irq; 216 } 217 218 platform_set_drvdata(pdev, keypad); 219 return 0; 220 221failed_free_irq: 222 free_irq(irq, pdev); 223failed_put_clk: 224 clk_put(keypad->clk); 225failed_free_io: 226 iounmap(keypad->mmio_base); 227failed_free_res: 228 release_mem_region(res->start, resource_size(res)); 229failed_free: 230 input_free_device(input_dev); 231 kfree(keypad); 232 return error; 233} 234 235static int __devexit w90p910_keypad_remove(struct platform_device *pdev) 236{ 237 struct w90p910_keypad *keypad = platform_get_drvdata(pdev); 238 struct resource *res; 239 240 free_irq(keypad->irq, pdev); 241 242 clk_put(keypad->clk); 243 244 input_unregister_device(keypad->input_dev); 245 246 iounmap(keypad->mmio_base); 247 res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 248 release_mem_region(res->start, resource_size(res)); 249 250 platform_set_drvdata(pdev, NULL); 251 kfree(keypad); 252 253 return 0; 254} 255 256static struct platform_driver w90p910_keypad_driver = { 257 .probe = w90p910_keypad_probe, 258 .remove = __devexit_p(w90p910_keypad_remove), 259 .driver = { 260 .name = "nuc900-keypad", 261 .owner = THIS_MODULE, 262 }, 263}; 264 265static int __init w90p910_keypad_init(void) 266{ 267 return platform_driver_register(&w90p910_keypad_driver); 268} 269 270static void __exit w90p910_keypad_exit(void) 271{ 272 platform_driver_unregister(&w90p910_keypad_driver); 273} 274 275module_init(w90p910_keypad_init); 276module_exit(w90p910_keypad_exit); 277 278MODULE_AUTHOR("Wan ZongShun <mcuos.com@gmail.com>"); 279MODULE_DESCRIPTION("w90p910 keypad driver"); 280MODULE_LICENSE("GPL"); 281MODULE_ALIAS("platform:nuc900-keypad");