aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2008-04-27 00:02:21 -0400
committerDavid S. Miller <davem@davemloft.net>2008-04-27 00:41:22 -0400
commit9c1a5077fdca99356c891af37931e537dea874f5 (patch)
tree221546bc66bb9987c55571aa43c4903b0d7e2ffb
parentdc8ca2a111c10f031346f6f8f82640d6bc0dd347 (diff)
input: Rewrite sparcspkr device probing.
Remove all dependencies on EBUS and ISA bus layers, which we'd like to remove as they are superfluous. While we're here, add support for proper frequency changing on BBC beep devices. Unlike the comments that were here, this device can in fact use a programmable frequency. Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--drivers/input/misc/sparcspkr.c262
1 files changed, 184 insertions, 78 deletions
diff --git a/drivers/input/misc/sparcspkr.c b/drivers/input/misc/sparcspkr.c
index fed3c375ccf3..d8765cc93d27 100644
--- a/drivers/input/misc/sparcspkr.c
+++ b/drivers/input/misc/sparcspkr.c
@@ -2,33 +2,69 @@
2 * Driver for PC-speaker like devices found on various Sparc systems. 2 * Driver for PC-speaker like devices found on various Sparc systems.
3 * 3 *
4 * Copyright (c) 2002 Vojtech Pavlik 4 * Copyright (c) 2002 Vojtech Pavlik
5 * Copyright (c) 2002, 2006 David S. Miller (davem@davemloft.net) 5 * Copyright (c) 2002, 2006, 2008 David S. Miller (davem@davemloft.net)
6 */ 6 */
7#include <linux/kernel.h> 7#include <linux/kernel.h>
8#include <linux/module.h> 8#include <linux/module.h>
9#include <linux/init.h> 9#include <linux/init.h>
10#include <linux/input.h> 10#include <linux/input.h>
11#include <linux/platform_device.h> 11#include <linux/of_device.h>
12 12
13#include <asm/io.h> 13#include <asm/io.h>
14#include <asm/ebus.h>
15#include <asm/isa.h>
16 14
17MODULE_AUTHOR("David S. Miller <davem@davemloft.net>"); 15MODULE_AUTHOR("David S. Miller <davem@davemloft.net>");
18MODULE_DESCRIPTION("Sparc Speaker beeper driver"); 16MODULE_DESCRIPTION("Sparc Speaker beeper driver");
19MODULE_LICENSE("GPL"); 17MODULE_LICENSE("GPL");
20 18
19struct grover_beep_info {
20 void __iomem *freq_regs;
21 void __iomem *enable_reg;
22};
23
24struct bbc_beep_info {
25 u32 clock_freq;
26 void __iomem *regs;
27};
28
21struct sparcspkr_state { 29struct sparcspkr_state {
22 const char *name; 30 const char *name;
23 unsigned long iobase;
24 int (*event)(struct input_dev *dev, unsigned int type, unsigned int code, int value); 31 int (*event)(struct input_dev *dev, unsigned int type, unsigned int code, int value);
25 spinlock_t lock; 32 spinlock_t lock;
26 struct input_dev *input_dev; 33 struct input_dev *input_dev;
34 union {
35 struct grover_beep_info grover;
36 struct bbc_beep_info bbc;
37 } u;
27}; 38};
28 39
29static int ebus_spkr_event(struct input_dev *dev, unsigned int type, unsigned int code, int value) 40static u32 bbc_count_to_reg(struct bbc_beep_info *info, unsigned int count)
41{
42 u32 val, clock_freq = info->clock_freq;
43 int i;
44
45 if (!count)
46 return 0;
47
48 if (count <= clock_freq >> 20)
49 return 1 << 18;
50
51 if (count >= clock_freq >> 12)
52 return 1 << 10;
53
54 val = 1 << 18;
55 for (i = 19; i >= 11; i--) {
56 val >>= 1;
57 if (count <= clock_freq >> i)
58 break;
59 }
60
61 return val;
62}
63
64static int bbc_spkr_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
30{ 65{
31 struct sparcspkr_state *state = dev_get_drvdata(dev->dev.parent); 66 struct sparcspkr_state *state = dev_get_drvdata(dev->dev.parent);
67 struct bbc_beep_info *info = &state->u.bbc;
32 unsigned int count = 0; 68 unsigned int count = 0;
33 unsigned long flags; 69 unsigned long flags;
34 70
@@ -44,24 +80,29 @@ static int ebus_spkr_event(struct input_dev *dev, unsigned int type, unsigned in
44 if (value > 20 && value < 32767) 80 if (value > 20 && value < 32767)
45 count = 1193182 / value; 81 count = 1193182 / value;
46 82
83 count = bbc_count_to_reg(info, count);
84
47 spin_lock_irqsave(&state->lock, flags); 85 spin_lock_irqsave(&state->lock, flags);
48 86
49 /* EBUS speaker only has on/off state, the frequency does not 87 if (count) {
50 * appear to be programmable. 88 outb(0x01, info->regs + 0);
51 */ 89 outb(0x00, info->regs + 2);
52 if (state->iobase & 0x2UL) 90 outb((count >> 16) & 0xff, info->regs + 3);
53 outb(!!count, state->iobase); 91 outb((count >> 8) & 0xff, info->regs + 4);
54 else 92 outb(0x00, info->regs + 5);
55 outl(!!count, state->iobase); 93 } else {
94 outb(0x00, info->regs + 0);
95 }
56 96
57 spin_unlock_irqrestore(&state->lock, flags); 97 spin_unlock_irqrestore(&state->lock, flags);
58 98
59 return 0; 99 return 0;
60} 100}
61 101
62static int isa_spkr_event(struct input_dev *dev, unsigned int type, unsigned int code, int value) 102static int grover_spkr_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
63{ 103{
64 struct sparcspkr_state *state = dev_get_drvdata(dev->dev.parent); 104 struct sparcspkr_state *state = dev_get_drvdata(dev->dev.parent);
105 struct grover_beep_info *info = &state->u.grover;
65 unsigned int count = 0; 106 unsigned int count = 0;
66 unsigned long flags; 107 unsigned long flags;
67 108
@@ -81,15 +122,15 @@ static int isa_spkr_event(struct input_dev *dev, unsigned int type, unsigned int
81 122
82 if (count) { 123 if (count) {
83 /* enable counter 2 */ 124 /* enable counter 2 */
84 outb(inb(state->iobase + 0x61) | 3, state->iobase + 0x61); 125 outb(inb(info->enable_reg) | 3, info->enable_reg);
85 /* set command for counter 2, 2 byte write */ 126 /* set command for counter 2, 2 byte write */
86 outb(0xB6, state->iobase + 0x43); 127 outb(0xB6, info->freq_regs + 1);
87 /* select desired HZ */ 128 /* select desired HZ */
88 outb(count & 0xff, state->iobase + 0x42); 129 outb(count & 0xff, info->freq_regs + 0);
89 outb((count >> 8) & 0xff, state->iobase + 0x42); 130 outb((count >> 8) & 0xff, info->freq_regs + 0);
90 } else { 131 } else {
91 /* disable counter 2 */ 132 /* disable counter 2 */
92 outb(inb_p(state->iobase + 0x61) & 0xFC, state->iobase + 0x61); 133 outb(inb_p(info->enable_reg) & 0xFC, info->enable_reg);
93 } 134 }
94 135
95 spin_unlock_irqrestore(&state->lock, flags); 136 spin_unlock_irqrestore(&state->lock, flags);
@@ -131,7 +172,7 @@ static int __devinit sparcspkr_probe(struct device *dev)
131 return 0; 172 return 0;
132} 173}
133 174
134static int __devexit sparcspkr_remove(struct of_device *dev) 175static int sparcspkr_shutdown(struct of_device *dev)
135{ 176{
136 struct sparcspkr_state *state = dev_get_drvdata(&dev->dev); 177 struct sparcspkr_state *state = dev_get_drvdata(&dev->dev);
137 struct input_dev *input_dev = state->input_dev; 178 struct input_dev *input_dev = state->input_dev;
@@ -139,115 +180,180 @@ static int __devexit sparcspkr_remove(struct of_device *dev)
139 /* turn off the speaker */ 180 /* turn off the speaker */
140 state->event(input_dev, EV_SND, SND_BELL, 0); 181 state->event(input_dev, EV_SND, SND_BELL, 0);
141 182
142 input_unregister_device(input_dev);
143
144 dev_set_drvdata(&dev->dev, NULL);
145 kfree(state);
146
147 return 0; 183 return 0;
148} 184}
149 185
150static int sparcspkr_shutdown(struct of_device *dev) 186static int __devinit bbc_beep_probe(struct of_device *op, const struct of_device_id *match)
151{ 187{
152 struct sparcspkr_state *state = dev_get_drvdata(&dev->dev); 188 struct sparcspkr_state *state;
153 struct input_dev *input_dev = state->input_dev; 189 struct bbc_beep_info *info;
190 struct device_node *dp;
191 int err = -ENOMEM;
154 192
155 /* turn off the speaker */ 193 state = kzalloc(sizeof(*state), GFP_KERNEL);
156 state->event(input_dev, EV_SND, SND_BELL, 0); 194 if (!state)
195 goto out_err;
196
197 state->name = "Sparc BBC Speaker";
198 state->event = bbc_spkr_event;
199 spin_lock_init(&state->lock);
200
201 dp = of_find_node_by_path("/");
202 err = -ENODEV;
203 if (!dp)
204 goto out_free;
205
206 info = &state->u.bbc;
207 info->clock_freq = of_getintprop_default(dp, "clock-frequency", 0);
208 if (!info->clock_freq)
209 goto out_free;
210
211 info->regs = of_ioremap(&op->resource[0], 0, 6, "bbc beep");
212 if (!info->regs)
213 goto out_free;
214
215 dev_set_drvdata(&op->dev, state);
216
217 err = sparcspkr_probe(&op->dev);
218 if (err)
219 goto out_clear_drvdata;
157 220
158 return 0; 221 return 0;
222
223out_clear_drvdata:
224 dev_set_drvdata(&op->dev, NULL);
225 of_iounmap(&op->resource[0], info->regs, 6);
226
227out_free:
228 kfree(state);
229out_err:
230 return err;
159} 231}
160 232
161static int __devinit ebus_beep_probe(struct of_device *dev, const struct of_device_id *match) 233static int bbc_remove(struct of_device *op)
162{ 234{
163 struct linux_ebus_device *edev = to_ebus_device(&dev->dev); 235 struct sparcspkr_state *state = dev_get_drvdata(&op->dev);
164 struct sparcspkr_state *state; 236 struct input_dev *input_dev = state->input_dev;
165 int err; 237 struct bbc_beep_info *info = &state->u.bbc;
166 238
167 state = kzalloc(sizeof(*state), GFP_KERNEL); 239 /* turn off the speaker */
168 if (!state) 240 state->event(input_dev, EV_SND, SND_BELL, 0);
169 return -ENOMEM;
170 241
171 state->name = "Sparc EBUS Speaker"; 242 input_unregister_device(input_dev);
172 state->iobase = edev->resource[0].start;
173 state->event = ebus_spkr_event;
174 spin_lock_init(&state->lock);
175 243
176 dev_set_drvdata(&dev->dev, state); 244 of_iounmap(&op->resource[0], info->regs, 6);
177 245
178 err = sparcspkr_probe(&dev->dev); 246 dev_set_drvdata(&op->dev, NULL);
179 if (err) { 247 kfree(state);
180 dev_set_drvdata(&dev->dev, NULL);
181 kfree(state);
182 }
183 248
184 return 0; 249 return 0;
185} 250}
186 251
187static struct of_device_id ebus_beep_match[] = { 252static struct of_device_id bbc_beep_match[] = {
188 { 253 {
189 .name = "beep", 254 .name = "beep",
255 .compatible = "SUNW,bbc-beep",
190 }, 256 },
191 {}, 257 {},
192}; 258};
193 259
194static struct of_platform_driver ebus_beep_driver = { 260static struct of_platform_driver bbc_beep_driver = {
195 .name = "beep", 261 .name = "bbcbeep",
196 .match_table = ebus_beep_match, 262 .match_table = bbc_beep_match,
197 .probe = ebus_beep_probe, 263 .probe = bbc_beep_probe,
198 .remove = __devexit_p(sparcspkr_remove), 264 .remove = __devexit_p(bbc_remove),
199 .shutdown = sparcspkr_shutdown, 265 .shutdown = sparcspkr_shutdown,
200}; 266};
201 267
202static int __devinit isa_beep_probe(struct of_device *dev, const struct of_device_id *match) 268static int __devinit grover_beep_probe(struct of_device *op, const struct of_device_id *match)
203{ 269{
204 struct sparc_isa_device *idev = to_isa_device(&dev->dev);
205 struct sparcspkr_state *state; 270 struct sparcspkr_state *state;
206 int err; 271 struct grover_beep_info *info;
272 int err = -ENOMEM;
207 273
208 state = kzalloc(sizeof(*state), GFP_KERNEL); 274 state = kzalloc(sizeof(*state), GFP_KERNEL);
209 if (!state) 275 if (!state)
210 return -ENOMEM; 276 goto out_err;
211 277
212 state->name = "Sparc ISA Speaker"; 278 state->name = "Sparc Grover Speaker";
213 state->iobase = idev->resource.start; 279 state->event = grover_spkr_event;
214 state->event = isa_spkr_event;
215 spin_lock_init(&state->lock); 280 spin_lock_init(&state->lock);
216 281
217 dev_set_drvdata(&dev->dev, state); 282 info = &state->u.grover;
283 info->freq_regs = of_ioremap(&op->resource[2], 0, 2, "grover beep freq");
284 if (!info->freq_regs)
285 goto out_free;
218 286
219 err = sparcspkr_probe(&dev->dev); 287 info->enable_reg = of_ioremap(&op->resource[3], 0, 1, "grover beep enable");
220 if (err) { 288 if (!info->enable_reg)
221 dev_set_drvdata(&dev->dev, NULL); 289 goto out_unmap_freq_regs;
222 kfree(state); 290
223 } 291 dev_set_drvdata(&op->dev, state);
292
293 err = sparcspkr_probe(&op->dev);
294 if (err)
295 goto out_clear_drvdata;
296
297 return 0;
298
299out_clear_drvdata:
300 dev_set_drvdata(&op->dev, NULL);
301 of_iounmap(&op->resource[3], info->enable_reg, 1);
302
303out_unmap_freq_regs:
304 of_iounmap(&op->resource[2], info->freq_regs, 2);
305out_free:
306 kfree(state);
307out_err:
308 return err;
309}
310
311static int grover_remove(struct of_device *op)
312{
313 struct sparcspkr_state *state = dev_get_drvdata(&op->dev);
314 struct grover_beep_info *info = &state->u.grover;
315 struct input_dev *input_dev = state->input_dev;
316
317 /* turn off the speaker */
318 state->event(input_dev, EV_SND, SND_BELL, 0);
319
320 input_unregister_device(input_dev);
321
322 of_iounmap(&op->resource[3], info->enable_reg, 1);
323 of_iounmap(&op->resource[2], info->freq_regs, 2);
324
325 dev_set_drvdata(&op->dev, NULL);
326 kfree(state);
224 327
225 return 0; 328 return 0;
226} 329}
227 330
228static struct of_device_id isa_beep_match[] = { 331static struct of_device_id grover_beep_match[] = {
229 { 332 {
230 .name = "dma", 333 .name = "beep",
334 .compatible = "SUNW,smbus-beep",
231 }, 335 },
232 {}, 336 {},
233}; 337};
234 338
235static struct of_platform_driver isa_beep_driver = { 339static struct of_platform_driver grover_beep_driver = {
236 .name = "beep", 340 .name = "groverbeep",
237 .match_table = isa_beep_match, 341 .match_table = grover_beep_match,
238 .probe = isa_beep_probe, 342 .probe = grover_beep_probe,
239 .remove = __devexit_p(sparcspkr_remove), 343 .remove = __devexit_p(grover_remove),
240 .shutdown = sparcspkr_shutdown, 344 .shutdown = sparcspkr_shutdown,
241}; 345};
242 346
243static int __init sparcspkr_init(void) 347static int __init sparcspkr_init(void)
244{ 348{
245 int err = of_register_driver(&ebus_beep_driver, &ebus_bus_type); 349 int err = of_register_driver(&bbc_beep_driver,
350 &of_platform_bus_type);
246 351
247 if (!err) { 352 if (!err) {
248 err = of_register_driver(&isa_beep_driver, &isa_bus_type); 353 err = of_register_driver(&grover_beep_driver,
354 &of_platform_bus_type);
249 if (err) 355 if (err)
250 of_unregister_driver(&ebus_beep_driver); 356 of_unregister_driver(&bbc_beep_driver);
251 } 357 }
252 358
253 return err; 359 return err;
@@ -255,8 +361,8 @@ static int __init sparcspkr_init(void)
255 361
256static void __exit sparcspkr_exit(void) 362static void __exit sparcspkr_exit(void)
257{ 363{
258 of_unregister_driver(&ebus_beep_driver); 364 of_unregister_driver(&bbc_beep_driver);
259 of_unregister_driver(&isa_beep_driver); 365 of_unregister_driver(&grover_beep_driver);
260} 366}
261 367
262module_init(sparcspkr_init); 368module_init(sparcspkr_init);