2 * Driver for the enhanced rotary controller on pxa930 and pxa935
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.
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>
17 #include <mach/pxa930_rotary.h>
22 #define SBCR_ERSB (1 << 5)
24 struct pxa930_rotary
{
25 struct input_dev
*input_dev
;
26 void __iomem
*mmio_base
;
29 struct pxa930_rotary_platform_data
*pdata
;
32 static void clear_sbcr(struct pxa930_rotary
*r
)
34 uint32_t sbcr
= __raw_readl(r
->mmio_base
+ SBCR
);
36 __raw_writel(sbcr
| SBCR_ERSB
, r
->mmio_base
+ SBCR
);
37 __raw_writel(sbcr
& ~SBCR_ERSB
, r
->mmio_base
+ SBCR
);
40 static irqreturn_t
rotary_irq(int irq
, void *dev_id
)
42 struct pxa930_rotary
*r
= dev_id
;
43 struct pxa930_rotary_platform_data
*pdata
= r
->pdata
;
46 ercr
= __raw_readl(r
->mmio_base
+ ERCR
) & 0xf;
49 delta
= ercr
- r
->last_ercr
;
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);
61 input_report_rel(r
->input_dev
, pdata
->rel_code
, delta
);
63 input_sync(r
->input_dev
);
68 static int pxa930_rotary_open(struct input_dev
*dev
)
70 struct pxa930_rotary
*r
= input_get_drvdata(dev
);
77 static void pxa930_rotary_close(struct input_dev
*dev
)
79 struct pxa930_rotary
*r
= input_get_drvdata(dev
);
84 static int __devinit
pxa930_rotary_probe(struct platform_device
*pdev
)
86 struct pxa930_rotary_platform_data
*pdata
= pdev
->dev
.platform_data
;
87 struct pxa930_rotary
*r
;
88 struct input_dev
*input_dev
;
93 irq
= platform_get_irq(pdev
, 0);
95 dev_err(&pdev
->dev
, "no irq for rotary controller\n");
99 res
= platform_get_resource(pdev
, IORESOURCE_MEM
, 0);
101 dev_err(&pdev
->dev
, "no I/O memory defined\n");
106 dev_err(&pdev
->dev
, "no platform data defined\n");
110 r
= kzalloc(sizeof(struct pxa930_rotary
), GFP_KERNEL
);
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");
122 platform_set_drvdata(pdev
, r
);
124 /* allocate and register the input device */
125 input_dev
= input_allocate_device();
127 dev_err(&pdev
->dev
, "failed to allocate input device\n");
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
;
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
);
143 __set_bit(pdata
->rel_code
, input_dev
->relbit
);
144 __set_bit(EV_REL
, input_dev
->evbit
);
147 r
->input_dev
= input_dev
;
148 input_set_drvdata(input_dev
, r
);
150 err
= request_irq(irq
, rotary_irq
, IRQF_DISABLED
,
151 "enhanced rotary", r
);
153 dev_err(&pdev
->dev
, "failed to request IRQ\n");
154 goto failed_free_input
;
157 err
= input_register_device(input_dev
);
159 dev_err(&pdev
->dev
, "failed to register input device\n");
160 goto failed_free_irq
;
168 input_free_device(input_dev
);
170 iounmap(r
->mmio_base
);
176 static int __devexit
pxa930_rotary_remove(struct platform_device
*pdev
)
178 struct pxa930_rotary
*r
= platform_get_drvdata(pdev
);
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
);
189 static struct platform_driver pxa930_rotary_driver
= {
191 .name
= "pxa930-rotary",
192 .owner
= THIS_MODULE
,
194 .probe
= pxa930_rotary_probe
,
195 .remove
= __devexit_p(pxa930_rotary_remove
),
198 static int __init
pxa930_rotary_init(void)
200 return platform_driver_register(&pxa930_rotary_driver
);
202 module_init(pxa930_rotary_init
);
204 static void __exit
pxa930_rotary_exit(void)
206 platform_driver_unregister(&pxa930_rotary_driver
);
208 module_exit(pxa930_rotary_exit
);
210 MODULE_LICENSE("GPL");
211 MODULE_DESCRIPTION("Driver for PXA93x Enhanced Rotary Controller");
212 MODULE_AUTHOR("Yao Yong <yaoyong@marvell.com>");