xref: /linux/drivers/input/misc/sparcspkr.c (revision 858259cf7d1c443c836a2022b78cb281f0a9b95e)
1 /*
2  *  Driver for PC-speaker like devices found on various Sparc systems.
3  *
4  *  Copyright (c) 2002 Vojtech Pavlik
5  *  Copyright (c) 2002 David S. Miller (davem@redhat.com)
6  */
7 #include <linux/config.h>
8 #include <linux/kernel.h>
9 #include <linux/module.h>
10 #include <linux/init.h>
11 #include <linux/input.h>
12 
13 #include <asm/io.h>
14 #include <asm/ebus.h>
15 #ifdef CONFIG_SPARC64
16 #include <asm/isa.h>
17 #endif
18 
19 MODULE_AUTHOR("David S. Miller <davem@redhat.com>");
20 MODULE_DESCRIPTION("Sparc Speaker beeper driver");
21 MODULE_LICENSE("GPL");
22 
23 static unsigned long beep_iobase;
24 static struct input_dev *sparcspkr_dev;
25 
26 DEFINE_SPINLOCK(beep_lock);
27 
28 static void __init init_sparcspkr_struct(void)
29 {
30 	sparcspkr_dev->evbit[0] = BIT(EV_SND);
31 	sparcspkr_dev->sndbit[0] = BIT(SND_BELL) | BIT(SND_TONE);
32 
33 	sparcspkr_dev->phys = "sparc/input0";
34 	sparcspkr_dev->id.bustype = BUS_ISA;
35 	sparcspkr_dev->id.vendor = 0x001f;
36 	sparcspkr_dev->id.product = 0x0001;
37 	sparcspkr_dev->id.version = 0x0100;
38 }
39 
40 static int ebus_spkr_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
41 {
42 	unsigned int count = 0;
43 	unsigned long flags;
44 
45 	if (type != EV_SND)
46 		return -1;
47 
48 	switch (code) {
49 		case SND_BELL: if (value) value = 1000;
50 		case SND_TONE: break;
51 		default: return -1;
52 	}
53 
54 	if (value > 20 && value < 32767)
55 		count = 1193182 / value;
56 
57 	spin_lock_irqsave(&beep_lock, flags);
58 
59 	/* EBUS speaker only has on/off state, the frequency does not
60 	 * appear to be programmable.
61 	 */
62 	if (count) {
63 		if (beep_iobase & 0x2UL)
64 			outb(1, beep_iobase);
65 		else
66 			outl(1, beep_iobase);
67 	} else {
68 		if (beep_iobase & 0x2UL)
69 			outb(0, beep_iobase);
70 		else
71 			outl(0, beep_iobase);
72 	}
73 
74 	spin_unlock_irqrestore(&beep_lock, flags);
75 
76 	return 0;
77 }
78 
79 static int __init init_ebus_beep(struct linux_ebus_device *edev)
80 {
81 	beep_iobase = edev->resource[0].start;
82 
83 	sparcspkr_dev = input_allocate_device();
84 	if (!sparcspkr_dev)
85 		return -ENOMEM;
86 
87 	sparcspkr_dev->name = "Sparc EBUS Speaker";
88 	sparcspkr_dev->event = ebus_spkr_event;
89 
90 	input_register_device(sparcspkr_dev);
91 
92 	return 0;
93 }
94 
95 #ifdef CONFIG_SPARC64
96 static int isa_spkr_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
97 {
98 	unsigned int count = 0;
99 	unsigned long flags;
100 
101 	if (type != EV_SND)
102 		return -1;
103 
104 	switch (code) {
105 		case SND_BELL: if (value) value = 1000;
106 		case SND_TONE: break;
107 		default: return -1;
108 	}
109 
110 	if (value > 20 && value < 32767)
111 		count = 1193182 / value;
112 
113 	spin_lock_irqsave(&beep_lock, flags);
114 
115 	if (count) {
116 		/* enable counter 2 */
117 		outb(inb(beep_iobase + 0x61) | 3, beep_iobase + 0x61);
118 		/* set command for counter 2, 2 byte write */
119 		outb(0xB6, beep_iobase + 0x43);
120 		/* select desired HZ */
121 		outb(count & 0xff, beep_iobase + 0x42);
122 		outb((count >> 8) & 0xff, beep_iobase + 0x42);
123 	} else {
124 		/* disable counter 2 */
125 		outb(inb_p(beep_iobase + 0x61) & 0xFC, beep_iobase + 0x61);
126 	}
127 
128 	spin_unlock_irqrestore(&beep_lock, flags);
129 
130 	return 0;
131 }
132 
133 static int __init init_isa_beep(struct sparc_isa_device *isa_dev)
134 {
135 	beep_iobase = isa_dev->resource.start;
136 
137 	sparcspkr_dev = input_allocate_device();
138 	if (!sparcspkr_dev)
139 		return -ENOMEM;
140 
141 	init_sparcspkr_struct();
142 
143 	sparcspkr_dev->name = "Sparc ISA Speaker";
144 	sparcspkr_dev->event = isa_spkr_event;
145 
146 	input_register_device(sparcspkr_dev);
147 
148 	return 0;
149 }
150 #endif
151 
152 static int __init sparcspkr_init(void)
153 {
154 	struct linux_ebus *ebus;
155 	struct linux_ebus_device *edev = NULL;
156 #ifdef CONFIG_SPARC64
157 	struct sparc_isa_bridge *isa_br;
158 	struct sparc_isa_device *isa_dev;
159 #endif
160 
161 	for_each_ebus(ebus) {
162 		for_each_ebusdev(edev, ebus) {
163 			if (!strcmp(edev->prom_name, "beep"))
164 				return init_ebus_beep(edev);
165 		}
166 	}
167 #ifdef CONFIG_SPARC64
168 	for_each_isa(isa_br) {
169 		for_each_isadev(isa_dev, isa_br) {
170 			/* A hack, the beep device's base lives in
171 			 * the DMA isa node.
172 			 */
173 			if (!strcmp(isa_dev->prom_name, "dma"))
174 				return init_isa_beep(isa_dev);
175 		}
176 	}
177 #endif
178 
179 	return -ENODEV;
180 }
181 
182 static void __exit sparcspkr_exit(void)
183 {
184 	input_unregister_device(sparcspkr_dev);
185 }
186 
187 module_init(sparcspkr_init);
188 module_exit(sparcspkr_exit);
189