diff options
Diffstat (limited to 'drivers/input/misc/ixp4xx-beeper.c')
-rw-r--r-- | drivers/input/misc/ixp4xx-beeper.c | 183 |
1 files changed, 183 insertions, 0 deletions
diff --git a/drivers/input/misc/ixp4xx-beeper.c b/drivers/input/misc/ixp4xx-beeper.c new file mode 100644 index 000000000000..d448bb5e4869 --- /dev/null +++ b/drivers/input/misc/ixp4xx-beeper.c | |||
@@ -0,0 +1,183 @@ | |||
1 | /* | ||
2 | * Generic IXP4xx beeper driver | ||
3 | * | ||
4 | * Copyright (C) 2005 Tower Technologies | ||
5 | * | ||
6 | * based on nslu2-io.c | ||
7 | * Copyright (C) 2004 Karen Spearel | ||
8 | * | ||
9 | * Author: Alessandro Zummo <a.zummo@towertech.it> | ||
10 | * Maintainers: http://www.nslu2-linux.org/ | ||
11 | * | ||
12 | * This program is free software; you can redistribute it and/or modify | ||
13 | * it under the terms of the GNU General Public License version 2 as | ||
14 | * published by the Free Software Foundation. | ||
15 | * | ||
16 | */ | ||
17 | |||
18 | #include <linux/module.h> | ||
19 | #include <linux/input.h> | ||
20 | #include <linux/delay.h> | ||
21 | #include <linux/platform_device.h> | ||
22 | #include <asm/hardware.h> | ||
23 | |||
24 | MODULE_AUTHOR("Alessandro Zummo <a.zummo@towertech.it>"); | ||
25 | MODULE_DESCRIPTION("ixp4xx beeper driver"); | ||
26 | MODULE_LICENSE("GPL"); | ||
27 | |||
28 | static DEFINE_SPINLOCK(beep_lock); | ||
29 | |||
30 | static void ixp4xx_spkr_control(unsigned int pin, unsigned int count) | ||
31 | { | ||
32 | unsigned long flags; | ||
33 | |||
34 | spin_lock_irqsave(&beep_lock, flags); | ||
35 | |||
36 | if (count) { | ||
37 | gpio_line_config(pin, IXP4XX_GPIO_OUT); | ||
38 | gpio_line_set(pin, IXP4XX_GPIO_LOW); | ||
39 | |||
40 | *IXP4XX_OSRT2 = (count & ~IXP4XX_OST_RELOAD_MASK) | IXP4XX_OST_ENABLE; | ||
41 | } else { | ||
42 | gpio_line_config(pin, IXP4XX_GPIO_IN); | ||
43 | gpio_line_set(pin, IXP4XX_GPIO_HIGH); | ||
44 | |||
45 | *IXP4XX_OSRT2 = 0; | ||
46 | } | ||
47 | |||
48 | spin_unlock_irqrestore(&beep_lock, flags); | ||
49 | } | ||
50 | |||
51 | static int ixp4xx_spkr_event(struct input_dev *dev, unsigned int type, unsigned int code, int value) | ||
52 | { | ||
53 | unsigned int pin = (unsigned int) dev->private; | ||
54 | unsigned int count = 0; | ||
55 | |||
56 | if (type != EV_SND) | ||
57 | return -1; | ||
58 | |||
59 | switch (code) { | ||
60 | case SND_BELL: | ||
61 | if (value) | ||
62 | value = 1000; | ||
63 | case SND_TONE: | ||
64 | break; | ||
65 | default: | ||
66 | return -1; | ||
67 | } | ||
68 | |||
69 | if (value > 20 && value < 32767) | ||
70 | #ifndef FREQ | ||
71 | count = (ixp4xx_get_board_tick_rate() / (value * 4)) - 1; | ||
72 | #else | ||
73 | count = (FREQ / (value * 4)) - 1; | ||
74 | #endif | ||
75 | |||
76 | ixp4xx_spkr_control(pin, count); | ||
77 | |||
78 | return 0; | ||
79 | } | ||
80 | |||
81 | static irqreturn_t ixp4xx_spkr_interrupt(int irq, void *dev_id, struct pt_regs *regs) | ||
82 | { | ||
83 | /* clear interrupt */ | ||
84 | *IXP4XX_OSST = IXP4XX_OSST_TIMER_2_PEND; | ||
85 | |||
86 | /* flip the beeper output */ | ||
87 | *IXP4XX_GPIO_GPOUTR ^= (1 << (unsigned int) dev_id); | ||
88 | |||
89 | return IRQ_HANDLED; | ||
90 | } | ||
91 | |||
92 | static int __devinit ixp4xx_spkr_probe(struct platform_device *dev) | ||
93 | { | ||
94 | struct input_dev *input_dev; | ||
95 | int err; | ||
96 | |||
97 | input_dev = input_allocate_device(); | ||
98 | if (!input_dev) | ||
99 | return -ENOMEM; | ||
100 | |||
101 | input_dev->private = (void *) dev->id; | ||
102 | input_dev->name = "ixp4xx beeper", | ||
103 | input_dev->phys = "ixp4xx/gpio"; | ||
104 | input_dev->id.bustype = BUS_HOST; | ||
105 | input_dev->id.vendor = 0x001f; | ||
106 | input_dev->id.product = 0x0001; | ||
107 | input_dev->id.version = 0x0100; | ||
108 | input_dev->cdev.dev = &dev->dev; | ||
109 | |||
110 | input_dev->evbit[0] = BIT(EV_SND); | ||
111 | input_dev->sndbit[0] = BIT(SND_BELL) | BIT(SND_TONE); | ||
112 | input_dev->event = ixp4xx_spkr_event; | ||
113 | |||
114 | err = request_irq(IRQ_IXP4XX_TIMER2, &ixp4xx_spkr_interrupt, | ||
115 | SA_INTERRUPT | SA_TIMER, "ixp4xx-beeper", (void *) dev->id); | ||
116 | if (err) | ||
117 | goto err_free_device; | ||
118 | |||
119 | err = input_register_device(input_dev); | ||
120 | if (err) | ||
121 | goto err_free_irq; | ||
122 | |||
123 | platform_set_drvdata(dev, input_dev); | ||
124 | |||
125 | return 0; | ||
126 | |||
127 | err_free_irq: | ||
128 | free_irq(IRQ_IXP4XX_TIMER2, dev); | ||
129 | err_free_device: | ||
130 | input_free_device(input_dev); | ||
131 | |||
132 | return err; | ||
133 | } | ||
134 | |||
135 | static int __devexit ixp4xx_spkr_remove(struct platform_device *dev) | ||
136 | { | ||
137 | struct input_dev *input_dev = platform_get_drvdata(dev); | ||
138 | unsigned int pin = (unsigned int) input_dev->private; | ||
139 | |||
140 | input_unregister_device(input_dev); | ||
141 | platform_set_drvdata(dev, NULL); | ||
142 | |||
143 | /* turn the speaker off */ | ||
144 | disable_irq(IRQ_IXP4XX_TIMER2); | ||
145 | ixp4xx_spkr_control(pin, 0); | ||
146 | |||
147 | free_irq(IRQ_IXP4XX_TIMER2, dev); | ||
148 | |||
149 | return 0; | ||
150 | } | ||
151 | |||
152 | static void ixp4xx_spkr_shutdown(struct platform_device *dev) | ||
153 | { | ||
154 | struct input_dev *input_dev = platform_get_drvdata(dev); | ||
155 | unsigned int pin = (unsigned int) input_dev->private; | ||
156 | |||
157 | /* turn off the speaker */ | ||
158 | disable_irq(IRQ_IXP4XX_TIMER2); | ||
159 | ixp4xx_spkr_control(pin, 0); | ||
160 | } | ||
161 | |||
162 | static struct platform_driver ixp4xx_spkr_platform_driver = { | ||
163 | .driver = { | ||
164 | .name = "ixp4xx-beeper", | ||
165 | .owner = THIS_MODULE, | ||
166 | }, | ||
167 | .probe = ixp4xx_spkr_probe, | ||
168 | .remove = __devexit_p(ixp4xx_spkr_remove), | ||
169 | .shutdown = ixp4xx_spkr_shutdown, | ||
170 | }; | ||
171 | |||
172 | static int __init ixp4xx_spkr_init(void) | ||
173 | { | ||
174 | return platform_driver_register(&ixp4xx_spkr_platform_driver); | ||
175 | } | ||
176 | |||
177 | static void __exit ixp4xx_spkr_exit(void) | ||
178 | { | ||
179 | platform_driver_unregister(&ixp4xx_spkr_platform_driver); | ||
180 | } | ||
181 | |||
182 | module_init(ixp4xx_spkr_init); | ||
183 | module_exit(ixp4xx_spkr_exit); | ||