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.33 283 lines 6.4 kB view raw
1/* 2 * Rotary counter driver for Analog Devices Blackfin Processors 3 * 4 * Copyright 2008-2009 Analog Devices Inc. 5 * Licensed under the GPL-2 or later. 6 */ 7 8#include <linux/module.h> 9#include <linux/version.h> 10#include <linux/init.h> 11#include <linux/interrupt.h> 12#include <linux/irq.h> 13#include <linux/pm.h> 14#include <linux/platform_device.h> 15#include <linux/input.h> 16 17#include <asm/portmux.h> 18#include <asm/bfin_rotary.h> 19 20static const u16 per_cnt[] = { 21 P_CNT_CUD, 22 P_CNT_CDG, 23 P_CNT_CZM, 24 0 25}; 26 27struct bfin_rot { 28 struct input_dev *input; 29 int irq; 30 unsigned int up_key; 31 unsigned int down_key; 32 unsigned int button_key; 33 unsigned int rel_code; 34 unsigned short cnt_config; 35 unsigned short cnt_imask; 36 unsigned short cnt_debounce; 37}; 38 39static void report_key_event(struct input_dev *input, int keycode) 40{ 41 /* simulate a press-n-release */ 42 input_report_key(input, keycode, 1); 43 input_sync(input); 44 input_report_key(input, keycode, 0); 45 input_sync(input); 46} 47 48static void report_rotary_event(struct bfin_rot *rotary, int delta) 49{ 50 struct input_dev *input = rotary->input; 51 52 if (rotary->up_key) { 53 report_key_event(input, 54 delta > 0 ? rotary->up_key : rotary->down_key); 55 } else { 56 input_report_rel(input, rotary->rel_code, delta); 57 input_sync(input); 58 } 59} 60 61static irqreturn_t bfin_rotary_isr(int irq, void *dev_id) 62{ 63 struct platform_device *pdev = dev_id; 64 struct bfin_rot *rotary = platform_get_drvdata(pdev); 65 int delta; 66 67 switch (bfin_read_CNT_STATUS()) { 68 69 case ICII: 70 break; 71 72 case UCII: 73 case DCII: 74 delta = bfin_read_CNT_COUNTER(); 75 if (delta) 76 report_rotary_event(rotary, delta); 77 break; 78 79 case CZMII: 80 report_key_event(rotary->input, rotary->button_key); 81 break; 82 83 default: 84 break; 85 } 86 87 bfin_write_CNT_COMMAND(W1LCNT_ZERO); /* Clear COUNTER */ 88 bfin_write_CNT_STATUS(-1); /* Clear STATUS */ 89 90 return IRQ_HANDLED; 91} 92 93static int __devinit bfin_rotary_probe(struct platform_device *pdev) 94{ 95 struct bfin_rotary_platform_data *pdata = pdev->dev.platform_data; 96 struct bfin_rot *rotary; 97 struct input_dev *input; 98 int error; 99 100 /* Basic validation */ 101 if ((pdata->rotary_up_key && !pdata->rotary_down_key) || 102 (!pdata->rotary_up_key && pdata->rotary_down_key)) { 103 return -EINVAL; 104 } 105 106 error = peripheral_request_list(per_cnt, dev_name(&pdev->dev)); 107 if (error) { 108 dev_err(&pdev->dev, "requesting peripherals failed\n"); 109 return error; 110 } 111 112 rotary = kzalloc(sizeof(struct bfin_rot), GFP_KERNEL); 113 input = input_allocate_device(); 114 if (!rotary || !input) { 115 error = -ENOMEM; 116 goto out1; 117 } 118 119 rotary->input = input; 120 121 rotary->up_key = pdata->rotary_up_key; 122 rotary->down_key = pdata->rotary_down_key; 123 rotary->button_key = pdata->rotary_button_key; 124 rotary->rel_code = pdata->rotary_rel_code; 125 126 error = rotary->irq = platform_get_irq(pdev, 0); 127 if (error < 0) 128 goto out1; 129 130 input->name = pdev->name; 131 input->phys = "bfin-rotary/input0"; 132 input->dev.parent = &pdev->dev; 133 134 input_set_drvdata(input, rotary); 135 136 input->id.bustype = BUS_HOST; 137 input->id.vendor = 0x0001; 138 input->id.product = 0x0001; 139 input->id.version = 0x0100; 140 141 if (rotary->up_key) { 142 __set_bit(EV_KEY, input->evbit); 143 __set_bit(rotary->up_key, input->keybit); 144 __set_bit(rotary->down_key, input->keybit); 145 } else { 146 __set_bit(EV_REL, input->evbit); 147 __set_bit(rotary->rel_code, input->relbit); 148 } 149 150 if (rotary->button_key) { 151 __set_bit(EV_KEY, input->evbit); 152 __set_bit(rotary->button_key, input->keybit); 153 } 154 155 error = request_irq(rotary->irq, bfin_rotary_isr, 156 0, dev_name(&pdev->dev), pdev); 157 if (error) { 158 dev_err(&pdev->dev, 159 "unable to claim irq %d; error %d\n", 160 rotary->irq, error); 161 goto out1; 162 } 163 164 error = input_register_device(input); 165 if (error) { 166 dev_err(&pdev->dev, 167 "unable to register input device (%d)\n", error); 168 goto out2; 169 } 170 171 if (pdata->rotary_button_key) 172 bfin_write_CNT_IMASK(CZMIE); 173 174 if (pdata->mode & ROT_DEBE) 175 bfin_write_CNT_DEBOUNCE(pdata->debounce & DPRESCALE); 176 177 if (pdata->mode) 178 bfin_write_CNT_CONFIG(bfin_read_CNT_CONFIG() | 179 (pdata->mode & ~CNTE)); 180 181 bfin_write_CNT_IMASK(bfin_read_CNT_IMASK() | UCIE | DCIE); 182 bfin_write_CNT_CONFIG(bfin_read_CNT_CONFIG() | CNTE); 183 184 platform_set_drvdata(pdev, rotary); 185 device_init_wakeup(&pdev->dev, 1); 186 187 return 0; 188 189out2: 190 free_irq(rotary->irq, pdev); 191out1: 192 input_free_device(input); 193 kfree(rotary); 194 peripheral_free_list(per_cnt); 195 196 return error; 197} 198 199static int __devexit bfin_rotary_remove(struct platform_device *pdev) 200{ 201 struct bfin_rot *rotary = platform_get_drvdata(pdev); 202 203 bfin_write_CNT_CONFIG(0); 204 bfin_write_CNT_IMASK(0); 205 206 free_irq(rotary->irq, pdev); 207 input_unregister_device(rotary->input); 208 peripheral_free_list(per_cnt); 209 210 kfree(rotary); 211 platform_set_drvdata(pdev, NULL); 212 213 return 0; 214} 215 216#ifdef CONFIG_PM 217static int bfin_rotary_suspend(struct device *dev) 218{ 219 struct platform_device *pdev = to_platform_device(dev); 220 struct bfin_rot *rotary = platform_get_drvdata(pdev); 221 222 rotary->cnt_config = bfin_read_CNT_CONFIG(); 223 rotary->cnt_imask = bfin_read_CNT_IMASK(); 224 rotary->cnt_debounce = bfin_read_CNT_DEBOUNCE(); 225 226 if (device_may_wakeup(&pdev->dev)) 227 enable_irq_wake(rotary->irq); 228 229 return 0; 230} 231 232static int bfin_rotary_resume(struct device *dev) 233{ 234 struct platform_device *pdev = to_platform_device(dev); 235 struct bfin_rot *rotary = platform_get_drvdata(pdev); 236 237 bfin_write_CNT_DEBOUNCE(rotary->cnt_debounce); 238 bfin_write_CNT_IMASK(rotary->cnt_imask); 239 bfin_write_CNT_CONFIG(rotary->cnt_config & ~CNTE); 240 241 if (device_may_wakeup(&pdev->dev)) 242 disable_irq_wake(rotary->irq); 243 244 if (rotary->cnt_config & CNTE) 245 bfin_write_CNT_CONFIG(rotary->cnt_config); 246 247 return 0; 248} 249 250static const struct dev_pm_ops bfin_rotary_pm_ops = { 251 .suspend = bfin_rotary_suspend, 252 .resume = bfin_rotary_resume, 253}; 254#endif 255 256static struct platform_driver bfin_rotary_device_driver = { 257 .probe = bfin_rotary_probe, 258 .remove = __devexit_p(bfin_rotary_remove), 259 .driver = { 260 .name = "bfin-rotary", 261 .owner = THIS_MODULE, 262#ifdef CONFIG_PM 263 .pm = &bfin_rotary_pm_ops, 264#endif 265 }, 266}; 267 268static int __init bfin_rotary_init(void) 269{ 270 return platform_driver_register(&bfin_rotary_device_driver); 271} 272module_init(bfin_rotary_init); 273 274static void __exit bfin_rotary_exit(void) 275{ 276 platform_driver_unregister(&bfin_rotary_device_driver); 277} 278module_exit(bfin_rotary_exit); 279 280MODULE_LICENSE("GPL"); 281MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>"); 282MODULE_DESCRIPTION("Rotary Counter driver for Blackfin Processors"); 283MODULE_ALIAS("platform:bfin-rotary");