2 * Rotary counter driver for Analog Devices Blackfin Processors
4 * Copyright 2008-2009 Analog Devices Inc.
5 * Licensed under the GPL-2 or later.
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>
14 #include <linux/platform_device.h>
15 #include <linux/input.h>
16 #include <linux/slab.h>
18 #include <asm/portmux.h>
19 #include <asm/bfin_rotary.h>
21 static const u16 per_cnt
[] = {
29 struct input_dev
*input
;
32 unsigned int down_key
;
33 unsigned int button_key
;
34 unsigned int rel_code
;
35 unsigned short cnt_config
;
36 unsigned short cnt_imask
;
37 unsigned short cnt_debounce
;
40 static void report_key_event(struct input_dev
*input
, int keycode
)
42 /* simulate a press-n-release */
43 input_report_key(input
, keycode
, 1);
45 input_report_key(input
, keycode
, 0);
49 static void report_rotary_event(struct bfin_rot
*rotary
, int delta
)
51 struct input_dev
*input
= rotary
->input
;
54 report_key_event(input
,
55 delta
> 0 ? rotary
->up_key
: rotary
->down_key
);
57 input_report_rel(input
, rotary
->rel_code
, delta
);
62 static irqreturn_t
bfin_rotary_isr(int irq
, void *dev_id
)
64 struct platform_device
*pdev
= dev_id
;
65 struct bfin_rot
*rotary
= platform_get_drvdata(pdev
);
68 switch (bfin_read_CNT_STATUS()) {
75 delta
= bfin_read_CNT_COUNTER();
77 report_rotary_event(rotary
, delta
);
81 report_key_event(rotary
->input
, rotary
->button_key
);
88 bfin_write_CNT_COMMAND(W1LCNT_ZERO
); /* Clear COUNTER */
89 bfin_write_CNT_STATUS(-1); /* Clear STATUS */
94 static int __devinit
bfin_rotary_probe(struct platform_device
*pdev
)
96 struct bfin_rotary_platform_data
*pdata
= pdev
->dev
.platform_data
;
97 struct bfin_rot
*rotary
;
98 struct input_dev
*input
;
101 /* Basic validation */
102 if ((pdata
->rotary_up_key
&& !pdata
->rotary_down_key
) ||
103 (!pdata
->rotary_up_key
&& pdata
->rotary_down_key
)) {
107 error
= peripheral_request_list(per_cnt
, dev_name(&pdev
->dev
));
109 dev_err(&pdev
->dev
, "requesting peripherals failed\n");
113 rotary
= kzalloc(sizeof(struct bfin_rot
), GFP_KERNEL
);
114 input
= input_allocate_device();
115 if (!rotary
|| !input
) {
120 rotary
->input
= input
;
122 rotary
->up_key
= pdata
->rotary_up_key
;
123 rotary
->down_key
= pdata
->rotary_down_key
;
124 rotary
->button_key
= pdata
->rotary_button_key
;
125 rotary
->rel_code
= pdata
->rotary_rel_code
;
127 error
= rotary
->irq
= platform_get_irq(pdev
, 0);
131 input
->name
= pdev
->name
;
132 input
->phys
= "bfin-rotary/input0";
133 input
->dev
.parent
= &pdev
->dev
;
135 input_set_drvdata(input
, rotary
);
137 input
->id
.bustype
= BUS_HOST
;
138 input
->id
.vendor
= 0x0001;
139 input
->id
.product
= 0x0001;
140 input
->id
.version
= 0x0100;
142 if (rotary
->up_key
) {
143 __set_bit(EV_KEY
, input
->evbit
);
144 __set_bit(rotary
->up_key
, input
->keybit
);
145 __set_bit(rotary
->down_key
, input
->keybit
);
147 __set_bit(EV_REL
, input
->evbit
);
148 __set_bit(rotary
->rel_code
, input
->relbit
);
151 if (rotary
->button_key
) {
152 __set_bit(EV_KEY
, input
->evbit
);
153 __set_bit(rotary
->button_key
, input
->keybit
);
156 error
= request_irq(rotary
->irq
, bfin_rotary_isr
,
157 0, dev_name(&pdev
->dev
), pdev
);
160 "unable to claim irq %d; error %d\n",
165 error
= input_register_device(input
);
168 "unable to register input device (%d)\n", error
);
172 if (pdata
->rotary_button_key
)
173 bfin_write_CNT_IMASK(CZMIE
);
175 if (pdata
->mode
& ROT_DEBE
)
176 bfin_write_CNT_DEBOUNCE(pdata
->debounce
& DPRESCALE
);
179 bfin_write_CNT_CONFIG(bfin_read_CNT_CONFIG() |
180 (pdata
->mode
& ~CNTE
));
182 bfin_write_CNT_IMASK(bfin_read_CNT_IMASK() | UCIE
| DCIE
);
183 bfin_write_CNT_CONFIG(bfin_read_CNT_CONFIG() | CNTE
);
185 platform_set_drvdata(pdev
, rotary
);
186 device_init_wakeup(&pdev
->dev
, 1);
191 free_irq(rotary
->irq
, pdev
);
193 input_free_device(input
);
195 peripheral_free_list(per_cnt
);
200 static int __devexit
bfin_rotary_remove(struct platform_device
*pdev
)
202 struct bfin_rot
*rotary
= platform_get_drvdata(pdev
);
204 bfin_write_CNT_CONFIG(0);
205 bfin_write_CNT_IMASK(0);
207 free_irq(rotary
->irq
, pdev
);
208 input_unregister_device(rotary
->input
);
209 peripheral_free_list(per_cnt
);
212 platform_set_drvdata(pdev
, NULL
);
218 static int bfin_rotary_suspend(struct device
*dev
)
220 struct platform_device
*pdev
= to_platform_device(dev
);
221 struct bfin_rot
*rotary
= platform_get_drvdata(pdev
);
223 rotary
->cnt_config
= bfin_read_CNT_CONFIG();
224 rotary
->cnt_imask
= bfin_read_CNT_IMASK();
225 rotary
->cnt_debounce
= bfin_read_CNT_DEBOUNCE();
227 if (device_may_wakeup(&pdev
->dev
))
228 enable_irq_wake(rotary
->irq
);
233 static int bfin_rotary_resume(struct device
*dev
)
235 struct platform_device
*pdev
= to_platform_device(dev
);
236 struct bfin_rot
*rotary
= platform_get_drvdata(pdev
);
238 bfin_write_CNT_DEBOUNCE(rotary
->cnt_debounce
);
239 bfin_write_CNT_IMASK(rotary
->cnt_imask
);
240 bfin_write_CNT_CONFIG(rotary
->cnt_config
& ~CNTE
);
242 if (device_may_wakeup(&pdev
->dev
))
243 disable_irq_wake(rotary
->irq
);
245 if (rotary
->cnt_config
& CNTE
)
246 bfin_write_CNT_CONFIG(rotary
->cnt_config
);
251 static const struct dev_pm_ops bfin_rotary_pm_ops
= {
252 .suspend
= bfin_rotary_suspend
,
253 .resume
= bfin_rotary_resume
,
257 static struct platform_driver bfin_rotary_device_driver
= {
258 .probe
= bfin_rotary_probe
,
259 .remove
= __devexit_p(bfin_rotary_remove
),
261 .name
= "bfin-rotary",
262 .owner
= THIS_MODULE
,
264 .pm
= &bfin_rotary_pm_ops
,
269 static int __init
bfin_rotary_init(void)
271 return platform_driver_register(&bfin_rotary_device_driver
);
273 module_init(bfin_rotary_init
);
275 static void __exit
bfin_rotary_exit(void)
277 platform_driver_unregister(&bfin_rotary_device_driver
);
279 module_exit(bfin_rotary_exit
);
281 MODULE_LICENSE("GPL");
282 MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
283 MODULE_DESCRIPTION("Rotary Counter driver for Blackfin Processors");
284 MODULE_ALIAS("platform:bfin-rotary");