Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/drivers/input/misc/sparcspkr.c
15109 views
1
/*
2
* Driver for PC-speaker like devices found on various Sparc systems.
3
*
4
* Copyright (c) 2002 Vojtech Pavlik
5
* Copyright (c) 2002, 2006, 2008 David S. Miller ([email protected])
6
*/
7
#include <linux/kernel.h>
8
#include <linux/module.h>
9
#include <linux/init.h>
10
#include <linux/input.h>
11
#include <linux/of_device.h>
12
#include <linux/slab.h>
13
14
#include <asm/io.h>
15
16
MODULE_AUTHOR("David S. Miller <[email protected]>");
17
MODULE_DESCRIPTION("Sparc Speaker beeper driver");
18
MODULE_LICENSE("GPL");
19
20
struct grover_beep_info {
21
void __iomem *freq_regs;
22
void __iomem *enable_reg;
23
};
24
25
struct bbc_beep_info {
26
u32 clock_freq;
27
void __iomem *regs;
28
};
29
30
struct sparcspkr_state {
31
const char *name;
32
int (*event)(struct input_dev *dev, unsigned int type, unsigned int code, int value);
33
spinlock_t lock;
34
struct input_dev *input_dev;
35
union {
36
struct grover_beep_info grover;
37
struct bbc_beep_info bbc;
38
} u;
39
};
40
41
static u32 bbc_count_to_reg(struct bbc_beep_info *info, unsigned int count)
42
{
43
u32 val, clock_freq = info->clock_freq;
44
int i;
45
46
if (!count)
47
return 0;
48
49
if (count <= clock_freq >> 20)
50
return 1 << 18;
51
52
if (count >= clock_freq >> 12)
53
return 1 << 10;
54
55
val = 1 << 18;
56
for (i = 19; i >= 11; i--) {
57
val >>= 1;
58
if (count <= clock_freq >> i)
59
break;
60
}
61
62
return val;
63
}
64
65
static int bbc_spkr_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
66
{
67
struct sparcspkr_state *state = dev_get_drvdata(dev->dev.parent);
68
struct bbc_beep_info *info = &state->u.bbc;
69
unsigned int count = 0;
70
unsigned long flags;
71
72
if (type != EV_SND)
73
return -1;
74
75
switch (code) {
76
case SND_BELL: if (value) value = 1000;
77
case SND_TONE: break;
78
default: return -1;
79
}
80
81
if (value > 20 && value < 32767)
82
count = 1193182 / value;
83
84
count = bbc_count_to_reg(info, count);
85
86
spin_lock_irqsave(&state->lock, flags);
87
88
if (count) {
89
outb(0x01, info->regs + 0);
90
outb(0x00, info->regs + 2);
91
outb((count >> 16) & 0xff, info->regs + 3);
92
outb((count >> 8) & 0xff, info->regs + 4);
93
outb(0x00, info->regs + 5);
94
} else {
95
outb(0x00, info->regs + 0);
96
}
97
98
spin_unlock_irqrestore(&state->lock, flags);
99
100
return 0;
101
}
102
103
static int grover_spkr_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
104
{
105
struct sparcspkr_state *state = dev_get_drvdata(dev->dev.parent);
106
struct grover_beep_info *info = &state->u.grover;
107
unsigned int count = 0;
108
unsigned long flags;
109
110
if (type != EV_SND)
111
return -1;
112
113
switch (code) {
114
case SND_BELL: if (value) value = 1000;
115
case SND_TONE: break;
116
default: return -1;
117
}
118
119
if (value > 20 && value < 32767)
120
count = 1193182 / value;
121
122
spin_lock_irqsave(&state->lock, flags);
123
124
if (count) {
125
/* enable counter 2 */
126
outb(inb(info->enable_reg) | 3, info->enable_reg);
127
/* set command for counter 2, 2 byte write */
128
outb(0xB6, info->freq_regs + 1);
129
/* select desired HZ */
130
outb(count & 0xff, info->freq_regs + 0);
131
outb((count >> 8) & 0xff, info->freq_regs + 0);
132
} else {
133
/* disable counter 2 */
134
outb(inb_p(info->enable_reg) & 0xFC, info->enable_reg);
135
}
136
137
spin_unlock_irqrestore(&state->lock, flags);
138
139
return 0;
140
}
141
142
static int __devinit sparcspkr_probe(struct device *dev)
143
{
144
struct sparcspkr_state *state = dev_get_drvdata(dev);
145
struct input_dev *input_dev;
146
int error;
147
148
input_dev = input_allocate_device();
149
if (!input_dev)
150
return -ENOMEM;
151
152
input_dev->name = state->name;
153
input_dev->phys = "sparc/input0";
154
input_dev->id.bustype = BUS_ISA;
155
input_dev->id.vendor = 0x001f;
156
input_dev->id.product = 0x0001;
157
input_dev->id.version = 0x0100;
158
input_dev->dev.parent = dev;
159
160
input_dev->evbit[0] = BIT_MASK(EV_SND);
161
input_dev->sndbit[0] = BIT_MASK(SND_BELL) | BIT_MASK(SND_TONE);
162
163
input_dev->event = state->event;
164
165
error = input_register_device(input_dev);
166
if (error) {
167
input_free_device(input_dev);
168
return error;
169
}
170
171
state->input_dev = input_dev;
172
173
return 0;
174
}
175
176
static void sparcspkr_shutdown(struct platform_device *dev)
177
{
178
struct sparcspkr_state *state = dev_get_drvdata(&dev->dev);
179
struct input_dev *input_dev = state->input_dev;
180
181
/* turn off the speaker */
182
state->event(input_dev, EV_SND, SND_BELL, 0);
183
}
184
185
static int __devinit bbc_beep_probe(struct platform_device *op)
186
{
187
struct sparcspkr_state *state;
188
struct bbc_beep_info *info;
189
struct device_node *dp;
190
int err = -ENOMEM;
191
192
state = kzalloc(sizeof(*state), GFP_KERNEL);
193
if (!state)
194
goto out_err;
195
196
state->name = "Sparc BBC Speaker";
197
state->event = bbc_spkr_event;
198
spin_lock_init(&state->lock);
199
200
dp = of_find_node_by_path("/");
201
err = -ENODEV;
202
if (!dp)
203
goto out_free;
204
205
info = &state->u.bbc;
206
info->clock_freq = of_getintprop_default(dp, "clock-frequency", 0);
207
if (!info->clock_freq)
208
goto out_free;
209
210
info->regs = of_ioremap(&op->resource[0], 0, 6, "bbc beep");
211
if (!info->regs)
212
goto out_free;
213
214
dev_set_drvdata(&op->dev, state);
215
216
err = sparcspkr_probe(&op->dev);
217
if (err)
218
goto out_clear_drvdata;
219
220
return 0;
221
222
out_clear_drvdata:
223
dev_set_drvdata(&op->dev, NULL);
224
of_iounmap(&op->resource[0], info->regs, 6);
225
226
out_free:
227
kfree(state);
228
out_err:
229
return err;
230
}
231
232
static int __devexit bbc_remove(struct platform_device *op)
233
{
234
struct sparcspkr_state *state = dev_get_drvdata(&op->dev);
235
struct input_dev *input_dev = state->input_dev;
236
struct bbc_beep_info *info = &state->u.bbc;
237
238
/* turn off the speaker */
239
state->event(input_dev, EV_SND, SND_BELL, 0);
240
241
input_unregister_device(input_dev);
242
243
of_iounmap(&op->resource[0], info->regs, 6);
244
245
dev_set_drvdata(&op->dev, NULL);
246
kfree(state);
247
248
return 0;
249
}
250
251
static const struct of_device_id bbc_beep_match[] = {
252
{
253
.name = "beep",
254
.compatible = "SUNW,bbc-beep",
255
},
256
{},
257
};
258
259
static struct platform_driver bbc_beep_driver = {
260
.driver = {
261
.name = "bbcbeep",
262
.owner = THIS_MODULE,
263
.of_match_table = bbc_beep_match,
264
},
265
.probe = bbc_beep_probe,
266
.remove = __devexit_p(bbc_remove),
267
.shutdown = sparcspkr_shutdown,
268
};
269
270
static int __devinit grover_beep_probe(struct platform_device *op)
271
{
272
struct sparcspkr_state *state;
273
struct grover_beep_info *info;
274
int err = -ENOMEM;
275
276
state = kzalloc(sizeof(*state), GFP_KERNEL);
277
if (!state)
278
goto out_err;
279
280
state->name = "Sparc Grover Speaker";
281
state->event = grover_spkr_event;
282
spin_lock_init(&state->lock);
283
284
info = &state->u.grover;
285
info->freq_regs = of_ioremap(&op->resource[2], 0, 2, "grover beep freq");
286
if (!info->freq_regs)
287
goto out_free;
288
289
info->enable_reg = of_ioremap(&op->resource[3], 0, 1, "grover beep enable");
290
if (!info->enable_reg)
291
goto out_unmap_freq_regs;
292
293
dev_set_drvdata(&op->dev, state);
294
295
err = sparcspkr_probe(&op->dev);
296
if (err)
297
goto out_clear_drvdata;
298
299
return 0;
300
301
out_clear_drvdata:
302
dev_set_drvdata(&op->dev, NULL);
303
of_iounmap(&op->resource[3], info->enable_reg, 1);
304
305
out_unmap_freq_regs:
306
of_iounmap(&op->resource[2], info->freq_regs, 2);
307
out_free:
308
kfree(state);
309
out_err:
310
return err;
311
}
312
313
static int __devexit grover_remove(struct platform_device *op)
314
{
315
struct sparcspkr_state *state = dev_get_drvdata(&op->dev);
316
struct grover_beep_info *info = &state->u.grover;
317
struct input_dev *input_dev = state->input_dev;
318
319
/* turn off the speaker */
320
state->event(input_dev, EV_SND, SND_BELL, 0);
321
322
input_unregister_device(input_dev);
323
324
of_iounmap(&op->resource[3], info->enable_reg, 1);
325
of_iounmap(&op->resource[2], info->freq_regs, 2);
326
327
dev_set_drvdata(&op->dev, NULL);
328
kfree(state);
329
330
return 0;
331
}
332
333
static const struct of_device_id grover_beep_match[] = {
334
{
335
.name = "beep",
336
.compatible = "SUNW,smbus-beep",
337
},
338
{},
339
};
340
341
static struct platform_driver grover_beep_driver = {
342
.driver = {
343
.name = "groverbeep",
344
.owner = THIS_MODULE,
345
.of_match_table = grover_beep_match,
346
},
347
.probe = grover_beep_probe,
348
.remove = __devexit_p(grover_remove),
349
.shutdown = sparcspkr_shutdown,
350
};
351
352
static int __init sparcspkr_init(void)
353
{
354
int err = platform_driver_register(&bbc_beep_driver);
355
356
if (!err) {
357
err = platform_driver_register(&grover_beep_driver);
358
if (err)
359
platform_driver_unregister(&bbc_beep_driver);
360
}
361
362
return err;
363
}
364
365
static void __exit sparcspkr_exit(void)
366
{
367
platform_driver_unregister(&bbc_beep_driver);
368
platform_driver_unregister(&grover_beep_driver);
369
}
370
371
module_init(sparcspkr_init);
372
module_exit(sparcspkr_exit);
373
374