]>
Commit | Line | Data |
---|---|---|
01387959 AZ |
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> | |
a09d31ff | 22 | #include <linux/interrupt.h> |
e9c9fc23 | 23 | #include <linux/gpio.h> |
a09e64fb | 24 | #include <mach/hardware.h> |
01387959 AZ |
25 | |
26 | MODULE_AUTHOR("Alessandro Zummo <a.zummo@towertech.it>"); | |
27 | MODULE_DESCRIPTION("ixp4xx beeper driver"); | |
28 | MODULE_LICENSE("GPL"); | |
589499c0 | 29 | MODULE_ALIAS("platform:ixp4xx-beeper"); |
01387959 AZ |
30 | |
31 | static DEFINE_SPINLOCK(beep_lock); | |
32 | ||
075df31a LW |
33 | static int ixp4xx_timer2_irq; |
34 | ||
01387959 AZ |
35 | static void ixp4xx_spkr_control(unsigned int pin, unsigned int count) |
36 | { | |
37 | unsigned long flags; | |
38 | ||
39 | spin_lock_irqsave(&beep_lock, flags); | |
40 | ||
e9c9fc23 LW |
41 | if (count) { |
42 | gpio_direction_output(pin, 0); | |
01387959 AZ |
43 | *IXP4XX_OSRT2 = (count & ~IXP4XX_OST_RELOAD_MASK) | IXP4XX_OST_ENABLE; |
44 | } else { | |
e9c9fc23 LW |
45 | gpio_direction_output(pin, 1); |
46 | gpio_direction_input(pin); | |
01387959 AZ |
47 | *IXP4XX_OSRT2 = 0; |
48 | } | |
49 | ||
50 | spin_unlock_irqrestore(&beep_lock, flags); | |
51 | } | |
52 | ||
53 | static int ixp4xx_spkr_event(struct input_dev *dev, unsigned int type, unsigned int code, int value) | |
54 | { | |
643bd272 | 55 | unsigned int pin = (unsigned int) input_get_drvdata(dev); |
01387959 AZ |
56 | unsigned int count = 0; |
57 | ||
58 | if (type != EV_SND) | |
59 | return -1; | |
60 | ||
61 | switch (code) { | |
62 | case SND_BELL: | |
63 | if (value) | |
64 | value = 1000; | |
65 | case SND_TONE: | |
66 | break; | |
67 | default: | |
68 | return -1; | |
69 | } | |
70 | ||
71 | if (value > 20 && value < 32767) | |
3ae1a6b1 | 72 | count = (ixp4xx_timer_freq / (value * 4)) - 1; |
01387959 AZ |
73 | |
74 | ixp4xx_spkr_control(pin, count); | |
75 | ||
76 | return 0; | |
77 | } | |
78 | ||
7d12e780 | 79 | static irqreturn_t ixp4xx_spkr_interrupt(int irq, void *dev_id) |
01387959 | 80 | { |
b22973d0 LW |
81 | unsigned int pin = (unsigned int) dev_id; |
82 | ||
01387959 AZ |
83 | /* clear interrupt */ |
84 | *IXP4XX_OSST = IXP4XX_OSST_TIMER_2_PEND; | |
85 | ||
86 | /* flip the beeper output */ | |
b22973d0 | 87 | gpio_set_value(pin, !gpio_get_value(pin)); |
01387959 AZ |
88 | |
89 | return IRQ_HANDLED; | |
90 | } | |
91 | ||
5298cc4c | 92 | static int ixp4xx_spkr_probe(struct platform_device *dev) |
01387959 AZ |
93 | { |
94 | struct input_dev *input_dev; | |
075df31a | 95 | int irq; |
01387959 AZ |
96 | int err; |
97 | ||
98 | input_dev = input_allocate_device(); | |
99 | if (!input_dev) | |
100 | return -ENOMEM; | |
101 | ||
373f9713 DT |
102 | input_set_drvdata(input_dev, (void *) dev->id); |
103 | ||
01387959 AZ |
104 | input_dev->name = "ixp4xx beeper", |
105 | input_dev->phys = "ixp4xx/gpio"; | |
106 | input_dev->id.bustype = BUS_HOST; | |
107 | input_dev->id.vendor = 0x001f; | |
108 | input_dev->id.product = 0x0001; | |
109 | input_dev->id.version = 0x0100; | |
293e6392 | 110 | input_dev->dev.parent = &dev->dev; |
01387959 | 111 | |
7b19ada2 JS |
112 | input_dev->evbit[0] = BIT_MASK(EV_SND); |
113 | input_dev->sndbit[0] = BIT_MASK(SND_BELL) | BIT_MASK(SND_TONE); | |
01387959 AZ |
114 | input_dev->event = ixp4xx_spkr_event; |
115 | ||
075df31a LW |
116 | irq = platform_get_irq(dev, 0); |
117 | if (irq < 0) { | |
118 | err = irq; | |
119 | goto err_free_device; | |
120 | } | |
121 | ||
b22973d0 LW |
122 | err = gpio_request(dev->id, "ixp4-beeper"); |
123 | if (err) | |
124 | goto err_free_device; | |
125 | ||
075df31a | 126 | err = request_irq(irq, &ixp4xx_spkr_interrupt, |
ec4665c4 | 127 | IRQF_NO_SUSPEND, "ixp4xx-beeper", |
2dd93203 | 128 | (void *) dev->id); |
01387959 | 129 | if (err) |
b22973d0 | 130 | goto err_free_gpio; |
075df31a | 131 | ixp4xx_timer2_irq = irq; |
01387959 AZ |
132 | |
133 | err = input_register_device(input_dev); | |
134 | if (err) | |
135 | goto err_free_irq; | |
136 | ||
137 | platform_set_drvdata(dev, input_dev); | |
138 | ||
139 | return 0; | |
140 | ||
141 | err_free_irq: | |
075df31a | 142 | free_irq(irq, (void *)dev->id); |
b22973d0 LW |
143 | err_free_gpio: |
144 | gpio_free(dev->id); | |
01387959 AZ |
145 | err_free_device: |
146 | input_free_device(input_dev); | |
147 | ||
148 | return err; | |
149 | } | |
150 | ||
e2619cf7 | 151 | static int ixp4xx_spkr_remove(struct platform_device *dev) |
01387959 AZ |
152 | { |
153 | struct input_dev *input_dev = platform_get_drvdata(dev); | |
373f9713 | 154 | unsigned int pin = (unsigned int) input_get_drvdata(input_dev); |
01387959 AZ |
155 | |
156 | input_unregister_device(input_dev); | |
01387959 AZ |
157 | |
158 | /* turn the speaker off */ | |
075df31a | 159 | disable_irq(ixp4xx_timer2_irq); |
01387959 AZ |
160 | ixp4xx_spkr_control(pin, 0); |
161 | ||
075df31a | 162 | free_irq(ixp4xx_timer2_irq, (void *)dev->id); |
b22973d0 | 163 | gpio_free(dev->id); |
01387959 AZ |
164 | |
165 | return 0; | |
166 | } | |
167 | ||
168 | static void ixp4xx_spkr_shutdown(struct platform_device *dev) | |
169 | { | |
170 | struct input_dev *input_dev = platform_get_drvdata(dev); | |
373f9713 | 171 | unsigned int pin = (unsigned int) input_get_drvdata(input_dev); |
01387959 AZ |
172 | |
173 | /* turn off the speaker */ | |
075df31a | 174 | disable_irq(ixp4xx_timer2_irq); |
01387959 AZ |
175 | ixp4xx_spkr_control(pin, 0); |
176 | } | |
177 | ||
178 | static struct platform_driver ixp4xx_spkr_platform_driver = { | |
179 | .driver = { | |
180 | .name = "ixp4xx-beeper", | |
01387959 AZ |
181 | }, |
182 | .probe = ixp4xx_spkr_probe, | |
1cb0aa88 | 183 | .remove = ixp4xx_spkr_remove, |
01387959 AZ |
184 | .shutdown = ixp4xx_spkr_shutdown, |
185 | }; | |
840a746b | 186 | module_platform_driver(ixp4xx_spkr_platform_driver); |
01387959 | 187 |