sparcspkr.c 7.8 KB
Newer Older
L
Linus Torvalds 已提交
1 2 3 4
/*
 *  Driver for PC-speaker like devices found on various Sparc systems.
 *
 *  Copyright (c) 2002 Vojtech Pavlik
5
 *  Copyright (c) 2002, 2006, 2008 David S. Miller (davem@davemloft.net)
L
Linus Torvalds 已提交
6 7 8 9 10
 */
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/input.h>
11
#include <linux/of_device.h>
12
#include <linux/slab.h>
L
Linus Torvalds 已提交
13 14 15

#include <asm/io.h>

16
MODULE_AUTHOR("David S. Miller <davem@davemloft.net>");
17
MODULE_DESCRIPTION("Sparc Speaker beeper driver");
L
Linus Torvalds 已提交
18 19
MODULE_LICENSE("GPL");

20 21 22 23 24 25 26 27 28 29
struct grover_beep_info {
	void __iomem	*freq_regs;
	void __iomem	*enable_reg;
};

struct bbc_beep_info {
	u32		clock_freq;
	void __iomem	*regs;
};

30 31 32 33 34
struct sparcspkr_state {
	const char		*name;
	int (*event)(struct input_dev *dev, unsigned int type, unsigned int code, int value);
	spinlock_t		lock;
	struct input_dev	*input_dev;
35 36 37 38
	union {
		struct grover_beep_info grover;
		struct bbc_beep_info bbc;
	} u;
39
};
L
Linus Torvalds 已提交
40

41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65
static u32 bbc_count_to_reg(struct bbc_beep_info *info, unsigned int count)
{
	u32 val, clock_freq = info->clock_freq;
	int i;

	if (!count)
		return 0;

	if (count <= clock_freq >> 20)
		return 1 << 18;

	if (count >= clock_freq >> 12)
		return 1 << 10;

	val = 1 << 18;
	for (i = 19; i >= 11; i--) {
		val >>= 1;
		if (count <= clock_freq >> i)
			break;
	}

	return val;
}

static int bbc_spkr_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
L
Linus Torvalds 已提交
66
{
67
	struct sparcspkr_state *state = dev_get_drvdata(dev->dev.parent);
68
	struct bbc_beep_info *info = &state->u.bbc;
L
Linus Torvalds 已提交
69 70 71 72 73 74 75 76 77 78 79 80 81 82 83
	unsigned int count = 0;
	unsigned long flags;

	if (type != EV_SND)
		return -1;

	switch (code) {
		case SND_BELL: if (value) value = 1000;
		case SND_TONE: break;
		default: return -1;
	}

	if (value > 20 && value < 32767)
		count = 1193182 / value;

84 85
	count = bbc_count_to_reg(info, count);

86
	spin_lock_irqsave(&state->lock, flags);
L
Linus Torvalds 已提交
87

88 89 90 91 92 93 94 95 96
	if (count) {
		outb(0x01,                 info->regs + 0);
		outb(0x00,                 info->regs + 2);
		outb((count >> 16) & 0xff, info->regs + 3);
		outb((count >>  8) & 0xff, info->regs + 4);
		outb(0x00,                 info->regs + 5);
	} else {
		outb(0x00,                 info->regs + 0);
	}
L
Linus Torvalds 已提交
97

98
	spin_unlock_irqrestore(&state->lock, flags);
L
Linus Torvalds 已提交
99 100 101 102

	return 0;
}

103
static int grover_spkr_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
L
Linus Torvalds 已提交
104
{
105
	struct sparcspkr_state *state = dev_get_drvdata(dev->dev.parent);
106
	struct grover_beep_info *info = &state->u.grover;
L
Linus Torvalds 已提交
107 108 109 110 111 112 113 114 115 116 117 118 119 120 121
	unsigned int count = 0;
	unsigned long flags;

	if (type != EV_SND)
		return -1;

	switch (code) {
		case SND_BELL: if (value) value = 1000;
		case SND_TONE: break;
		default: return -1;
	}

	if (value > 20 && value < 32767)
		count = 1193182 / value;

122
	spin_lock_irqsave(&state->lock, flags);
L
Linus Torvalds 已提交
123 124 125

	if (count) {
		/* enable counter 2 */
126
		outb(inb(info->enable_reg) | 3, info->enable_reg);
L
Linus Torvalds 已提交
127
		/* set command for counter 2, 2 byte write */
128
		outb(0xB6, info->freq_regs + 1);
L
Linus Torvalds 已提交
129
		/* select desired HZ */
130 131
		outb(count & 0xff, info->freq_regs + 0);
		outb((count >> 8) & 0xff, info->freq_regs + 0);
L
Linus Torvalds 已提交
132 133
	} else {
		/* disable counter 2 */
134
		outb(inb_p(info->enable_reg) & 0xFC, info->enable_reg);
L
Linus Torvalds 已提交
135 136
	}

137
	spin_unlock_irqrestore(&state->lock, flags);
L
Linus Torvalds 已提交
138 139 140 141

	return 0;
}

B
Bill Pemberton 已提交
142
static int sparcspkr_probe(struct device *dev)
L
Linus Torvalds 已提交
143
{
144
	struct sparcspkr_state *state = dev_get_drvdata(dev);
145 146
	struct input_dev *input_dev;
	int error;
L
Linus Torvalds 已提交
147

148 149
	input_dev = input_allocate_device();
	if (!input_dev)
150 151
		return -ENOMEM;

152
	input_dev->name = state->name;
153 154 155 156 157
	input_dev->phys = "sparc/input0";
	input_dev->id.bustype = BUS_ISA;
	input_dev->id.vendor = 0x001f;
	input_dev->id.product = 0x0001;
	input_dev->id.version = 0x0100;
158
	input_dev->dev.parent = dev;
L
Linus Torvalds 已提交
159

160 161
	input_dev->evbit[0] = BIT_MASK(EV_SND);
	input_dev->sndbit[0] = BIT_MASK(SND_BELL) | BIT_MASK(SND_TONE);
L
Linus Torvalds 已提交
162

163
	input_dev->event = state->event;
164 165 166 167 168 169 170

	error = input_register_device(input_dev);
	if (error) {
		input_free_device(input_dev);
		return error;
	}

171
	state->input_dev = input_dev;
L
Linus Torvalds 已提交
172 173 174

	return 0;
}
175

176
static void sparcspkr_shutdown(struct platform_device *dev)
177
{
178
	struct sparcspkr_state *state = platform_get_drvdata(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
}

B
Bill Pemberton 已提交
185
static int bbc_beep_probe(struct platform_device *op)
186
{
187 188 189 190
	struct sparcspkr_state *state;
	struct bbc_beep_info *info;
	struct device_node *dp;
	int err = -ENOMEM;
191

192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213
	state = kzalloc(sizeof(*state), GFP_KERNEL);
	if (!state)
		goto out_err;

	state->name = "Sparc BBC Speaker";
	state->event = bbc_spkr_event;
	spin_lock_init(&state->lock);

	dp = of_find_node_by_path("/");
	err = -ENODEV;
	if (!dp)
		goto out_free;

	info = &state->u.bbc;
	info->clock_freq = of_getintprop_default(dp, "clock-frequency", 0);
	if (!info->clock_freq)
		goto out_free;

	info->regs = of_ioremap(&op->resource[0], 0, 6, "bbc beep");
	if (!info->regs)
		goto out_free;

214
	platform_set_drvdata(op, state);
215 216 217 218

	err = sparcspkr_probe(&op->dev);
	if (err)
		goto out_clear_drvdata;
219 220

	return 0;
221 222 223 224 225 226 227 228

out_clear_drvdata:
	of_iounmap(&op->resource[0], info->regs, 6);

out_free:
	kfree(state);
out_err:
	return err;
229 230
}

B
Bill Pemberton 已提交
231
static int bbc_remove(struct platform_device *op)
232
{
233
	struct sparcspkr_state *state = platform_get_drvdata(op);
234 235
	struct input_dev *input_dev = state->input_dev;
	struct bbc_beep_info *info = &state->u.bbc;
236

237 238
	/* turn off the speaker */
	state->event(input_dev, EV_SND, SND_BELL, 0);
239

240
	input_unregister_device(input_dev);
241

242
	of_iounmap(&op->resource[0], info->regs, 6);
243

244
	kfree(state);
245 246

	return 0;
247 248
}

249
static const struct of_device_id bbc_beep_match[] = {
250 251
	{
		.name = "beep",
252
		.compatible = "SUNW,bbc-beep",
253
	},
254
	{},
255 256
};

257
static struct platform_driver bbc_beep_driver = {
258 259 260 261 262
	.driver = {
		.name = "bbcbeep",
		.owner = THIS_MODULE,
		.of_match_table = bbc_beep_match,
	},
263
	.probe		= bbc_beep_probe,
B
Bill Pemberton 已提交
264
	.remove		= bbc_remove,
265 266
	.shutdown	= sparcspkr_shutdown,
};
267

B
Bill Pemberton 已提交
268
static int grover_beep_probe(struct platform_device *op)
269
{
270
	struct sparcspkr_state *state;
271 272
	struct grover_beep_info *info;
	int err = -ENOMEM;
273

274 275
	state = kzalloc(sizeof(*state), GFP_KERNEL);
	if (!state)
276
		goto out_err;
277

278 279
	state->name = "Sparc Grover Speaker";
	state->event = grover_spkr_event;
280 281
	spin_lock_init(&state->lock);

282 283 284 285
	info = &state->u.grover;
	info->freq_regs = of_ioremap(&op->resource[2], 0, 2, "grover beep freq");
	if (!info->freq_regs)
		goto out_free;
286

287 288 289 290
	info->enable_reg = of_ioremap(&op->resource[3], 0, 1, "grover beep enable");
	if (!info->enable_reg)
		goto out_unmap_freq_regs;

291
	platform_set_drvdata(op, state);
292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309

	err = sparcspkr_probe(&op->dev);
	if (err)
		goto out_clear_drvdata;

	return 0;

out_clear_drvdata:
	of_iounmap(&op->resource[3], info->enable_reg, 1);

out_unmap_freq_regs:
	of_iounmap(&op->resource[2], info->freq_regs, 2);
out_free:
	kfree(state);
out_err:
	return err;
}

B
Bill Pemberton 已提交
310
static int grover_remove(struct platform_device *op)
311
{
312
	struct sparcspkr_state *state = platform_get_drvdata(op);
313 314 315 316 317 318 319 320 321 322 323 324
	struct grover_beep_info *info = &state->u.grover;
	struct input_dev *input_dev = state->input_dev;

	/* turn off the speaker */
	state->event(input_dev, EV_SND, SND_BELL, 0);

	input_unregister_device(input_dev);

	of_iounmap(&op->resource[3], info->enable_reg, 1);
	of_iounmap(&op->resource[2], info->freq_regs, 2);

	kfree(state);
325 326

	return 0;
327
}
328

329
static const struct of_device_id grover_beep_match[] = {
330
	{
331 332
		.name = "beep",
		.compatible = "SUNW,smbus-beep",
333 334 335
	},
	{},
};
336

337
static struct platform_driver grover_beep_driver = {
338 339 340 341 342
	.driver = {
		.name = "groverbeep",
		.owner = THIS_MODULE,
		.of_match_table = grover_beep_match,
	},
343
	.probe		= grover_beep_probe,
B
Bill Pemberton 已提交
344
	.remove		= grover_remove,
345 346
	.shutdown	= sparcspkr_shutdown,
};
L
Linus Torvalds 已提交
347 348 349

static int __init sparcspkr_init(void)
{
350
	int err = platform_driver_register(&bbc_beep_driver);
351 352

	if (!err) {
353
		err = platform_driver_register(&grover_beep_driver);
354
		if (err)
355
			platform_driver_unregister(&bbc_beep_driver);
L
Linus Torvalds 已提交
356 357
	}

358
	return err;
L
Linus Torvalds 已提交
359 360 361 362
}

static void __exit sparcspkr_exit(void)
{
363 364
	platform_driver_unregister(&bbc_beep_driver);
	platform_driver_unregister(&grover_beep_driver);
L
Linus Torvalds 已提交
365 366 367 368
}

module_init(sparcspkr_init);
module_exit(sparcspkr_exit);