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/init.h>
10 #include <linux/interrupt.h>
11 #include <linux/irq.h>
13 #include <linux/platform_device.h>
14 #include <linux/input.h>
15 #include <linux/slab.h>
17 #include <asm/portmux.h>
18 #include <asm/bfin_rotary.h>
20 static const u16 per_cnt
[] = {
28 struct input_dev
*input
;
31 unsigned int down_key
;
32 unsigned int button_key
;
33 unsigned int rel_code
;
34 unsigned short cnt_config
;
35 unsigned short cnt_imask
;
36 unsigned short cnt_debounce
;
39 static void report_key_event(struct input_dev
*input
, int keycode
)
41 /* simulate a press-n-release */
42 input_report_key(input
, keycode
, 1);
44 input_report_key(input
, keycode
, 0);
48 static void report_rotary_event(struct bfin_rot
*rotary
, int delta
)
50 struct input_dev
*input
= rotary
->input
;
53 report_key_event(input
,
54 delta
> 0 ? rotary
->up_key
: rotary
->down_key
);
56 input_report_rel(input
, rotary
->rel_code
, delta
);
61 static irqreturn_t
bfin_rotary_isr(int irq
, void *dev_id
)
63 struct platform_device
*pdev
= dev_id
;
64 struct bfin_rot
*rotary
= platform_get_drvdata(pdev
);
67 switch (bfin_read_CNT_STATUS()) {
74 delta
= bfin_read_CNT_COUNTER();
76 report_rotary_event(rotary
, delta
);
80 report_key_event(rotary
->input
, rotary
->button_key
);
87 bfin_write_CNT_COMMAND(W1LCNT_ZERO
); /* Clear COUNTER */
88 bfin_write_CNT_STATUS(-1); /* Clear STATUS */
93 static int bfin_rotary_probe(struct platform_device
*pdev
)
95 struct bfin_rotary_platform_data
*pdata
= pdev
->dev
.platform_data
;
96 struct bfin_rot
*rotary
;
97 struct input_dev
*input
;
100 /* Basic validation */
101 if ((pdata
->rotary_up_key
&& !pdata
->rotary_down_key
) ||
102 (!pdata
->rotary_up_key
&& pdata
->rotary_down_key
)) {
106 error
= peripheral_request_list(per_cnt
, dev_name(&pdev
->dev
));
108 dev_err(&pdev
->dev
, "requesting peripherals failed\n");
112 rotary
= kzalloc(sizeof(struct bfin_rot
), GFP_KERNEL
);
113 input
= input_allocate_device();
114 if (!rotary
|| !input
) {
119 rotary
->input
= input
;
121 rotary
->up_key
= pdata
->rotary_up_key
;
122 rotary
->down_key
= pdata
->rotary_down_key
;
123 rotary
->button_key
= pdata
->rotary_button_key
;
124 rotary
->rel_code
= pdata
->rotary_rel_code
;
126 error
= rotary
->irq
= platform_get_irq(pdev
, 0);
130 input
->name
= pdev
->name
;
131 input
->phys
= "bfin-rotary/input0";
132 input
->dev
.parent
= &pdev
->dev
;
134 input_set_drvdata(input
, rotary
);
136 input
->id
.bustype
= BUS_HOST
;
137 input
->id
.vendor
= 0x0001;
138 input
->id
.product
= 0x0001;
139 input
->id
.version
= 0x0100;
141 if (rotary
->up_key
) {
142 __set_bit(EV_KEY
, input
->evbit
);
143 __set_bit(rotary
->up_key
, input
->keybit
);
144 __set_bit(rotary
->down_key
, input
->keybit
);
146 __set_bit(EV_REL
, input
->evbit
);
147 __set_bit(rotary
->rel_code
, input
->relbit
);
150 if (rotary
->button_key
) {
151 __set_bit(EV_KEY
, input
->evbit
);
152 __set_bit(rotary
->button_key
, input
->keybit
);
155 error
= request_irq(rotary
->irq
, bfin_rotary_isr
,
156 0, dev_name(&pdev
->dev
), pdev
);
159 "unable to claim irq %d; error %d\n",
164 error
= input_register_device(input
);
167 "unable to register input device (%d)\n", error
);
171 if (pdata
->rotary_button_key
)
172 bfin_write_CNT_IMASK(CZMIE
);
174 if (pdata
->mode
& ROT_DEBE
)
175 bfin_write_CNT_DEBOUNCE(pdata
->debounce
& DPRESCALE
);
178 bfin_write_CNT_CONFIG(bfin_read_CNT_CONFIG() |
179 (pdata
->mode
& ~CNTE
));
181 bfin_write_CNT_IMASK(bfin_read_CNT_IMASK() | UCIE
| DCIE
);
182 bfin_write_CNT_CONFIG(bfin_read_CNT_CONFIG() | CNTE
);
184 platform_set_drvdata(pdev
, rotary
);
185 device_init_wakeup(&pdev
->dev
, 1);
190 free_irq(rotary
->irq
, pdev
);
192 input_free_device(input
);
194 peripheral_free_list(per_cnt
);
199 static int bfin_rotary_remove(struct platform_device
*pdev
)
201 struct bfin_rot
*rotary
= platform_get_drvdata(pdev
);
203 bfin_write_CNT_CONFIG(0);
204 bfin_write_CNT_IMASK(0);
206 free_irq(rotary
->irq
, pdev
);
207 input_unregister_device(rotary
->input
);
208 peripheral_free_list(per_cnt
);
211 platform_set_drvdata(pdev
, NULL
);
217 static int bfin_rotary_suspend(struct device
*dev
)
219 struct platform_device
*pdev
= to_platform_device(dev
);
220 struct bfin_rot
*rotary
= platform_get_drvdata(pdev
);
222 rotary
->cnt_config
= bfin_read_CNT_CONFIG();
223 rotary
->cnt_imask
= bfin_read_CNT_IMASK();
224 rotary
->cnt_debounce
= bfin_read_CNT_DEBOUNCE();
226 if (device_may_wakeup(&pdev
->dev
))
227 enable_irq_wake(rotary
->irq
);
232 static int bfin_rotary_resume(struct device
*dev
)
234 struct platform_device
*pdev
= to_platform_device(dev
);
235 struct bfin_rot
*rotary
= platform_get_drvdata(pdev
);
237 bfin_write_CNT_DEBOUNCE(rotary
->cnt_debounce
);
238 bfin_write_CNT_IMASK(rotary
->cnt_imask
);
239 bfin_write_CNT_CONFIG(rotary
->cnt_config
& ~CNTE
);
241 if (device_may_wakeup(&pdev
->dev
))
242 disable_irq_wake(rotary
->irq
);
244 if (rotary
->cnt_config
& CNTE
)
245 bfin_write_CNT_CONFIG(rotary
->cnt_config
);
250 static const struct dev_pm_ops bfin_rotary_pm_ops
= {
251 .suspend
= bfin_rotary_suspend
,
252 .resume
= bfin_rotary_resume
,
256 static struct platform_driver bfin_rotary_device_driver
= {
257 .probe
= bfin_rotary_probe
,
258 .remove
= bfin_rotary_remove
,
260 .name
= "bfin-rotary",
261 .owner
= THIS_MODULE
,
263 .pm
= &bfin_rotary_pm_ops
,
267 module_platform_driver(bfin_rotary_device_driver
);
269 MODULE_LICENSE("GPL");
270 MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
271 MODULE_DESCRIPTION("Rotary Counter driver for Blackfin Processors");
272 MODULE_ALIAS("platform:bfin-rotary");