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/interrupt.h>
12 #include <linux/input.h>
13 #include <linux/platform_device.h>
15 #include <linux/slab.h>
17 #include <linux/platform_data/keyboard-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 pxa930_rotary_probe(struct platform_device
*pdev
)
86 struct pxa930_rotary_platform_data
*pdata
=
87 dev_get_platdata(&pdev
->dev
);
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
, 0,
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 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
);
189 static struct platform_driver pxa930_rotary_driver
= {
191 .name
= "pxa930-rotary",
193 .probe
= pxa930_rotary_probe
,
194 .remove
= pxa930_rotary_remove
,
196 module_platform_driver(pxa930_rotary_driver
);
198 MODULE_LICENSE("GPL");
199 MODULE_DESCRIPTION("Driver for PXA93x Enhanced Rotary Controller");
200 MODULE_AUTHOR("Yao Yong <yaoyong@marvell.com>");