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/interrupt.h>
10 #include <linux/irq.h>
12 #include <linux/platform_device.h>
13 #include <linux/input.h>
14 #include <linux/slab.h>
16 #include <asm/portmux.h>
17 #include <asm/bfin_rotary.h>
19 static const u16 per_cnt
[] = {
27 struct input_dev
*input
;
30 unsigned int down_key
;
31 unsigned int button_key
;
32 unsigned int rel_code
;
33 unsigned short cnt_config
;
34 unsigned short cnt_imask
;
35 unsigned short cnt_debounce
;
38 static void report_key_event(struct input_dev
*input
, int keycode
)
40 /* simulate a press-n-release */
41 input_report_key(input
, keycode
, 1);
43 input_report_key(input
, keycode
, 0);
47 static void report_rotary_event(struct bfin_rot
*rotary
, int delta
)
49 struct input_dev
*input
= rotary
->input
;
52 report_key_event(input
,
53 delta
> 0 ? rotary
->up_key
: rotary
->down_key
);
55 input_report_rel(input
, rotary
->rel_code
, delta
);
60 static irqreturn_t
bfin_rotary_isr(int irq
, void *dev_id
)
62 struct platform_device
*pdev
= dev_id
;
63 struct bfin_rot
*rotary
= platform_get_drvdata(pdev
);
66 switch (bfin_read_CNT_STATUS()) {
73 delta
= bfin_read_CNT_COUNTER();
75 report_rotary_event(rotary
, delta
);
79 report_key_event(rotary
->input
, rotary
->button_key
);
86 bfin_write_CNT_COMMAND(W1LCNT_ZERO
); /* Clear COUNTER */
87 bfin_write_CNT_STATUS(-1); /* Clear STATUS */
92 static int bfin_rotary_probe(struct platform_device
*pdev
)
94 struct bfin_rotary_platform_data
*pdata
= dev_get_platdata(&pdev
->dev
);
95 struct bfin_rot
*rotary
;
96 struct input_dev
*input
;
99 /* Basic validation */
100 if ((pdata
->rotary_up_key
&& !pdata
->rotary_down_key
) ||
101 (!pdata
->rotary_up_key
&& pdata
->rotary_down_key
)) {
105 error
= peripheral_request_list(per_cnt
, dev_name(&pdev
->dev
));
107 dev_err(&pdev
->dev
, "requesting peripherals failed\n");
111 rotary
= kzalloc(sizeof(struct bfin_rot
), GFP_KERNEL
);
112 input
= input_allocate_device();
113 if (!rotary
|| !input
) {
118 rotary
->input
= input
;
120 rotary
->up_key
= pdata
->rotary_up_key
;
121 rotary
->down_key
= pdata
->rotary_down_key
;
122 rotary
->button_key
= pdata
->rotary_button_key
;
123 rotary
->rel_code
= pdata
->rotary_rel_code
;
125 error
= rotary
->irq
= platform_get_irq(pdev
, 0);
129 input
->name
= pdev
->name
;
130 input
->phys
= "bfin-rotary/input0";
131 input
->dev
.parent
= &pdev
->dev
;
133 input_set_drvdata(input
, rotary
);
135 input
->id
.bustype
= BUS_HOST
;
136 input
->id
.vendor
= 0x0001;
137 input
->id
.product
= 0x0001;
138 input
->id
.version
= 0x0100;
140 if (rotary
->up_key
) {
141 __set_bit(EV_KEY
, input
->evbit
);
142 __set_bit(rotary
->up_key
, input
->keybit
);
143 __set_bit(rotary
->down_key
, input
->keybit
);
145 __set_bit(EV_REL
, input
->evbit
);
146 __set_bit(rotary
->rel_code
, input
->relbit
);
149 if (rotary
->button_key
) {
150 __set_bit(EV_KEY
, input
->evbit
);
151 __set_bit(rotary
->button_key
, input
->keybit
);
154 error
= request_irq(rotary
->irq
, bfin_rotary_isr
,
155 0, dev_name(&pdev
->dev
), pdev
);
158 "unable to claim irq %d; error %d\n",
163 error
= input_register_device(input
);
166 "unable to register input device (%d)\n", error
);
170 if (pdata
->rotary_button_key
)
171 bfin_write_CNT_IMASK(CZMIE
);
173 if (pdata
->mode
& ROT_DEBE
)
174 bfin_write_CNT_DEBOUNCE(pdata
->debounce
& DPRESCALE
);
177 bfin_write_CNT_CONFIG(bfin_read_CNT_CONFIG() |
178 (pdata
->mode
& ~CNTE
));
180 bfin_write_CNT_IMASK(bfin_read_CNT_IMASK() | UCIE
| DCIE
);
181 bfin_write_CNT_CONFIG(bfin_read_CNT_CONFIG() | CNTE
);
183 platform_set_drvdata(pdev
, rotary
);
184 device_init_wakeup(&pdev
->dev
, 1);
189 free_irq(rotary
->irq
, pdev
);
191 input_free_device(input
);
193 peripheral_free_list(per_cnt
);
198 static int bfin_rotary_remove(struct platform_device
*pdev
)
200 struct bfin_rot
*rotary
= platform_get_drvdata(pdev
);
202 bfin_write_CNT_CONFIG(0);
203 bfin_write_CNT_IMASK(0);
205 free_irq(rotary
->irq
, pdev
);
206 input_unregister_device(rotary
->input
);
207 peripheral_free_list(per_cnt
);
215 static int bfin_rotary_suspend(struct device
*dev
)
217 struct platform_device
*pdev
= to_platform_device(dev
);
218 struct bfin_rot
*rotary
= platform_get_drvdata(pdev
);
220 rotary
->cnt_config
= bfin_read_CNT_CONFIG();
221 rotary
->cnt_imask
= bfin_read_CNT_IMASK();
222 rotary
->cnt_debounce
= bfin_read_CNT_DEBOUNCE();
224 if (device_may_wakeup(&pdev
->dev
))
225 enable_irq_wake(rotary
->irq
);
230 static int bfin_rotary_resume(struct device
*dev
)
232 struct platform_device
*pdev
= to_platform_device(dev
);
233 struct bfin_rot
*rotary
= platform_get_drvdata(pdev
);
235 bfin_write_CNT_DEBOUNCE(rotary
->cnt_debounce
);
236 bfin_write_CNT_IMASK(rotary
->cnt_imask
);
237 bfin_write_CNT_CONFIG(rotary
->cnt_config
& ~CNTE
);
239 if (device_may_wakeup(&pdev
->dev
))
240 disable_irq_wake(rotary
->irq
);
242 if (rotary
->cnt_config
& CNTE
)
243 bfin_write_CNT_CONFIG(rotary
->cnt_config
);
248 static const struct dev_pm_ops bfin_rotary_pm_ops
= {
249 .suspend
= bfin_rotary_suspend
,
250 .resume
= bfin_rotary_resume
,
254 static struct platform_driver bfin_rotary_device_driver
= {
255 .probe
= bfin_rotary_probe
,
256 .remove
= bfin_rotary_remove
,
258 .name
= "bfin-rotary",
259 .owner
= THIS_MODULE
,
261 .pm
= &bfin_rotary_pm_ops
,
265 module_platform_driver(bfin_rotary_device_driver
);
267 MODULE_LICENSE("GPL");
268 MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
269 MODULE_DESCRIPTION("Rotary Counter driver for Blackfin Processors");
270 MODULE_ALIAS("platform:bfin-rotary");