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 4dfd459b738cf1f65b3eac4e0a9b19bc93cc91c6 212 lines 4.9 kB view raw
1/* 2 * Driver for the enhanced rotary controller on pxa930 and pxa935 3 * 4 * This program is free software; you can redistribute it and/or modify 5 * it under the terms of the GNU General Public License version 2 as 6 * published by the Free Software Foundation. 7 */ 8 9#include <linux/kernel.h> 10#include <linux/module.h> 11#include <linux/init.h> 12#include <linux/interrupt.h> 13#include <linux/input.h> 14#include <linux/platform_device.h> 15#include <linux/io.h> 16 17#include <mach/pxa930_rotary.h> 18 19#define SBCR (0x04) 20#define ERCR (0x0c) 21 22#define SBCR_ERSB (1 << 5) 23 24struct pxa930_rotary { 25 struct input_dev *input_dev; 26 void __iomem *mmio_base; 27 int last_ercr; 28 29 struct pxa930_rotary_platform_data *pdata; 30}; 31 32static void clear_sbcr(struct pxa930_rotary *r) 33{ 34 uint32_t sbcr = __raw_readl(r->mmio_base + SBCR); 35 36 __raw_writel(sbcr | SBCR_ERSB, r->mmio_base + SBCR); 37 __raw_writel(sbcr & ~SBCR_ERSB, r->mmio_base + SBCR); 38} 39 40static irqreturn_t rotary_irq(int irq, void *dev_id) 41{ 42 struct pxa930_rotary *r = dev_id; 43 struct pxa930_rotary_platform_data *pdata = r->pdata; 44 int ercr, delta, key; 45 46 ercr = __raw_readl(r->mmio_base + ERCR) & 0xf; 47 clear_sbcr(r); 48 49 delta = ercr - r->last_ercr; 50 if (delta == 0) 51 return IRQ_HANDLED; 52 53 r->last_ercr = ercr; 54 55 if (pdata->up_key && pdata->down_key) { 56 key = (delta > 0) ? pdata->up_key : pdata->down_key; 57 input_report_key(r->input_dev, key, 1); 58 input_sync(r->input_dev); 59 input_report_key(r->input_dev, key, 0); 60 } else 61 input_report_rel(r->input_dev, pdata->rel_code, delta); 62 63 input_sync(r->input_dev); 64 65 return IRQ_HANDLED; 66} 67 68static int pxa930_rotary_open(struct input_dev *dev) 69{ 70 struct pxa930_rotary *r = input_get_drvdata(dev); 71 72 clear_sbcr(r); 73 74 return 0; 75} 76 77static void pxa930_rotary_close(struct input_dev *dev) 78{ 79 struct pxa930_rotary *r = input_get_drvdata(dev); 80 81 clear_sbcr(r); 82} 83 84static int __devinit pxa930_rotary_probe(struct platform_device *pdev) 85{ 86 struct pxa930_rotary_platform_data *pdata = pdev->dev.platform_data; 87 struct pxa930_rotary *r; 88 struct input_dev *input_dev; 89 struct resource *res; 90 int irq; 91 int err; 92 93 irq = platform_get_irq(pdev, 0); 94 if (irq < 0) { 95 dev_err(&pdev->dev, "no irq for rotary controller\n"); 96 return -ENXIO; 97 } 98 99 res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 100 if (!res) { 101 dev_err(&pdev->dev, "no I/O memory defined\n"); 102 return -ENXIO; 103 } 104 105 if (!pdata) { 106 dev_err(&pdev->dev, "no platform data defined\n"); 107 return -EINVAL; 108 } 109 110 r = kzalloc(sizeof(struct pxa930_rotary), GFP_KERNEL); 111 if (!r) 112 return -ENOMEM; 113 114 r->mmio_base = ioremap_nocache(res->start, resource_size(res)); 115 if (r->mmio_base == NULL) { 116 dev_err(&pdev->dev, "failed to remap IO memory\n"); 117 err = -ENXIO; 118 goto failed_free; 119 } 120 121 r->pdata = pdata; 122 platform_set_drvdata(pdev, r); 123 124 /* allocate and register the input device */ 125 input_dev = input_allocate_device(); 126 if (!input_dev) { 127 dev_err(&pdev->dev, "failed to allocate input device\n"); 128 err = -ENOMEM; 129 goto failed_free_io; 130 } 131 132 input_dev->name = pdev->name; 133 input_dev->id.bustype = BUS_HOST; 134 input_dev->open = pxa930_rotary_open; 135 input_dev->close = pxa930_rotary_close; 136 input_dev->dev.parent = &pdev->dev; 137 138 if (pdata->up_key && pdata->down_key) { 139 __set_bit(pdata->up_key, input_dev->keybit); 140 __set_bit(pdata->down_key, input_dev->keybit); 141 __set_bit(EV_KEY, input_dev->evbit); 142 } else { 143 __set_bit(pdata->rel_code, input_dev->relbit); 144 __set_bit(EV_REL, input_dev->evbit); 145 } 146 147 r->input_dev = input_dev; 148 input_set_drvdata(input_dev, r); 149 150 err = request_irq(irq, rotary_irq, IRQF_DISABLED, 151 "enhanced rotary", r); 152 if (err) { 153 dev_err(&pdev->dev, "failed to request IRQ\n"); 154 goto failed_free_input; 155 } 156 157 err = input_register_device(input_dev); 158 if (err) { 159 dev_err(&pdev->dev, "failed to register input device\n"); 160 goto failed_free_irq; 161 } 162 163 return 0; 164 165failed_free_irq: 166 free_irq(irq, r); 167failed_free_input: 168 input_free_device(input_dev); 169failed_free_io: 170 iounmap(r->mmio_base); 171failed_free: 172 kfree(r); 173 return err; 174} 175 176static int __devexit pxa930_rotary_remove(struct platform_device *pdev) 177{ 178 struct pxa930_rotary *r = platform_get_drvdata(pdev); 179 180 free_irq(platform_get_irq(pdev, 0), r); 181 input_unregister_device(r->input_dev); 182 iounmap(r->mmio_base); 183 platform_set_drvdata(pdev, NULL); 184 kfree(r); 185 186 return 0; 187} 188 189static struct platform_driver pxa930_rotary_driver = { 190 .driver = { 191 .name = "pxa930-rotary", 192 .owner = THIS_MODULE, 193 }, 194 .probe = pxa930_rotary_probe, 195 .remove = __devexit_p(pxa930_rotary_remove), 196}; 197 198static int __init pxa930_rotary_init(void) 199{ 200 return platform_driver_register(&pxa930_rotary_driver); 201} 202module_init(pxa930_rotary_init); 203 204static void __exit pxa930_rotary_exit(void) 205{ 206 platform_driver_unregister(&pxa930_rotary_driver); 207} 208module_exit(pxa930_rotary_exit); 209 210MODULE_LICENSE("GPL"); 211MODULE_DESCRIPTION("Driver for PXA93x Enhanced Rotary Controller"); 212MODULE_AUTHOR("Yao Yong <yaoyong@marvell.com>");