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>
16 #include <linux/slab.h>
18 #include <mach/pxa930_rotary.h>
23 #define SBCR_ERSB (1 << 5)
25 struct pxa930_rotary
{
26 struct input_dev
*input_dev
;
27 void __iomem
*mmio_base
;
30 struct pxa930_rotary_platform_data
*pdata
;
33 static void clear_sbcr(struct pxa930_rotary
*r
)
35 uint32_t sbcr
= __raw_readl(r
->mmio_base
+ SBCR
);
37 __raw_writel(sbcr
| SBCR_ERSB
, r
->mmio_base
+ SBCR
);
38 __raw_writel(sbcr
& ~SBCR_ERSB
, r
->mmio_base
+ SBCR
);
41 static irqreturn_t
rotary_irq(int irq
, void *dev_id
)
43 struct pxa930_rotary
*r
= dev_id
;
44 struct pxa930_rotary_platform_data
*pdata
= r
->pdata
;
47 ercr
= __raw_readl(r
->mmio_base
+ ERCR
) & 0xf;
50 delta
= ercr
- r
->last_ercr
;
56 if (pdata
->up_key
&& pdata
->down_key
) {
57 key
= (delta
> 0) ? pdata
->up_key
: pdata
->down_key
;
58 input_report_key(r
->input_dev
, key
, 1);
59 input_sync(r
->input_dev
);
60 input_report_key(r
->input_dev
, key
, 0);
62 input_report_rel(r
->input_dev
, pdata
->rel_code
, delta
);
64 input_sync(r
->input_dev
);
69 static int pxa930_rotary_open(struct input_dev
*dev
)
71 struct pxa930_rotary
*r
= input_get_drvdata(dev
);
78 static void pxa930_rotary_close(struct input_dev
*dev
)
80 struct pxa930_rotary
*r
= input_get_drvdata(dev
);
85 static int __devinit
pxa930_rotary_probe(struct platform_device
*pdev
)
87 struct pxa930_rotary_platform_data
*pdata
= pdev
->dev
.platform_data
;
88 struct pxa930_rotary
*r
;
89 struct input_dev
*input_dev
;
94 irq
= platform_get_irq(pdev
, 0);
96 dev_err(&pdev
->dev
, "no irq for rotary controller\n");
100 res
= platform_get_resource(pdev
, IORESOURCE_MEM
, 0);
102 dev_err(&pdev
->dev
, "no I/O memory defined\n");
107 dev_err(&pdev
->dev
, "no platform data defined\n");
111 r
= kzalloc(sizeof(struct pxa930_rotary
), GFP_KERNEL
);
115 r
->mmio_base
= ioremap_nocache(res
->start
, resource_size(res
));
116 if (r
->mmio_base
== NULL
) {
117 dev_err(&pdev
->dev
, "failed to remap IO memory\n");
123 platform_set_drvdata(pdev
, r
);
125 /* allocate and register the input device */
126 input_dev
= input_allocate_device();
128 dev_err(&pdev
->dev
, "failed to allocate input device\n");
133 input_dev
->name
= pdev
->name
;
134 input_dev
->id
.bustype
= BUS_HOST
;
135 input_dev
->open
= pxa930_rotary_open
;
136 input_dev
->close
= pxa930_rotary_close
;
137 input_dev
->dev
.parent
= &pdev
->dev
;
139 if (pdata
->up_key
&& pdata
->down_key
) {
140 __set_bit(pdata
->up_key
, input_dev
->keybit
);
141 __set_bit(pdata
->down_key
, input_dev
->keybit
);
142 __set_bit(EV_KEY
, input_dev
->evbit
);
144 __set_bit(pdata
->rel_code
, input_dev
->relbit
);
145 __set_bit(EV_REL
, input_dev
->evbit
);
148 r
->input_dev
= input_dev
;
149 input_set_drvdata(input_dev
, r
);
151 err
= request_irq(irq
, rotary_irq
, IRQF_DISABLED
,
152 "enhanced rotary", r
);
154 dev_err(&pdev
->dev
, "failed to request IRQ\n");
155 goto failed_free_input
;
158 err
= input_register_device(input_dev
);
160 dev_err(&pdev
->dev
, "failed to register input device\n");
161 goto failed_free_irq
;
169 input_free_device(input_dev
);
171 iounmap(r
->mmio_base
);
177 static int __devexit
pxa930_rotary_remove(struct platform_device
*pdev
)
179 struct pxa930_rotary
*r
= platform_get_drvdata(pdev
);
181 free_irq(platform_get_irq(pdev
, 0), r
);
182 input_unregister_device(r
->input_dev
);
183 iounmap(r
->mmio_base
);
184 platform_set_drvdata(pdev
, NULL
);
190 static struct platform_driver pxa930_rotary_driver
= {
192 .name
= "pxa930-rotary",
193 .owner
= THIS_MODULE
,
195 .probe
= pxa930_rotary_probe
,
196 .remove
= __devexit_p(pxa930_rotary_remove
),
199 static int __init
pxa930_rotary_init(void)
201 return platform_driver_register(&pxa930_rotary_driver
);
203 module_init(pxa930_rotary_init
);
205 static void __exit
pxa930_rotary_exit(void)
207 platform_driver_unregister(&pxa930_rotary_driver
);
209 module_exit(pxa930_rotary_exit
);
211 MODULE_LICENSE("GPL");
212 MODULE_DESCRIPTION("Driver for PXA93x Enhanced Rotary Controller");
213 MODULE_AUTHOR("Yao Yong <yaoyong@marvell.com>");