sparcspkr.c 8.0 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>
L
Linus Torvalds 已提交
12 13 14

#include <asm/io.h>

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

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

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

29 30 31 32 33
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;
34 35 36 37
	union {
		struct grover_beep_info grover;
		struct bbc_beep_info bbc;
	} u;
38
};
L
Linus Torvalds 已提交
39

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
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 已提交
65
{
66
	struct sparcspkr_state *state = dev_get_drvdata(dev->dev.parent);
67
	struct bbc_beep_info *info = &state->u.bbc;
L
Linus Torvalds 已提交
68 69 70 71 72 73 74 75 76 77 78 79 80 81 82
	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;

83 84
	count = bbc_count_to_reg(info, count);

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

87 88 89 90 91 92 93 94 95
	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 已提交
96

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

	return 0;
}

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

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

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

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

	return 0;
}

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

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

151
	input_dev->name = state->name;
152 153 154 155 156
	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;
157
	input_dev->dev.parent = dev;
L
Linus Torvalds 已提交
158

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

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

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

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

	return 0;
}
174

175
static int sparcspkr_shutdown(struct of_device *dev)
176
{
177 178
	struct sparcspkr_state *state = dev_get_drvdata(&dev->dev);
	struct input_dev *input_dev = state->input_dev;
179 180

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

183 184 185
	return 0;
}

186
static int __devinit bbc_beep_probe(struct of_device *op, const struct of_device_id *match)
187
{
188 189 190 191
	struct sparcspkr_state *state;
	struct bbc_beep_info *info;
	struct device_node *dp;
	int err = -ENOMEM;
192

193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219
	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;

	dev_set_drvdata(&op->dev, state);

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

	return 0;
222 223 224 225 226 227 228 229 230

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

out_free:
	kfree(state);
out_err:
	return err;
231 232
}

233
static int bbc_remove(struct of_device *op)
234
{
235 236 237
	struct sparcspkr_state *state = dev_get_drvdata(&op->dev);
	struct input_dev *input_dev = state->input_dev;
	struct bbc_beep_info *info = &state->u.bbc;
238

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

242
	input_unregister_device(input_dev);
243

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

246 247
	dev_set_drvdata(&op->dev, NULL);
	kfree(state);
248 249

	return 0;
250 251
}

252
static struct of_device_id bbc_beep_match[] = {
253 254
	{
		.name = "beep",
255
		.compatible = "SUNW,bbc-beep",
256
	},
257
	{},
258 259
};

260 261 262 263 264
static struct of_platform_driver bbc_beep_driver = {
	.name		= "bbcbeep",
	.match_table	= bbc_beep_match,
	.probe		= bbc_beep_probe,
	.remove		= __devexit_p(bbc_remove),
265 266
	.shutdown	= sparcspkr_shutdown,
};
267

268
static int __devinit grover_beep_probe(struct of_device *op, const struct of_device_id *match)
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 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326
	info->enable_reg = of_ioremap(&op->resource[3], 0, 1, "grover beep enable");
	if (!info->enable_reg)
		goto out_unmap_freq_regs;

	dev_set_drvdata(&op->dev, state);

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

	return 0;

out_clear_drvdata:
	dev_set_drvdata(&op->dev, NULL);
	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;
}

static int grover_remove(struct of_device *op)
{
	struct sparcspkr_state *state = dev_get_drvdata(&op->dev);
	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);

	dev_set_drvdata(&op->dev, NULL);
	kfree(state);
327 328

	return 0;
329
}
330

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

339 340 341 342 343
static struct of_platform_driver grover_beep_driver = {
	.name		= "groverbeep",
	.match_table	= grover_beep_match,
	.probe		= grover_beep_probe,
	.remove		= __devexit_p(grover_remove),
344 345
	.shutdown	= sparcspkr_shutdown,
};
L
Linus Torvalds 已提交
346 347 348

static int __init sparcspkr_init(void)
{
349 350
	int err = of_register_driver(&bbc_beep_driver,
				     &of_platform_bus_type);
351 352

	if (!err) {
353 354
		err = of_register_driver(&grover_beep_driver,
					 &of_platform_bus_type);
355
		if (err)
356
			of_unregister_driver(&bbc_beep_driver);
L
Linus Torvalds 已提交
357 358
	}

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

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

module_init(sparcspkr_init);
module_exit(sparcspkr_exit);