xref: /openbsd/sys/dev/pci/fmsradio.c (revision 0f9891f1)
1 /*	$OpenBSD: fmsradio.c,v 1.9 2024/05/24 06:02:53 jsg Exp $	*/
2 
3 /*
4  * Copyright (c) 2002 Vladimir Popov <jumbo@narod.ru>
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26  * SUCH DAMAGE.
27  */
28 
29 /* Device Driver for FM Tuners attached to FM801 */
30 
31 /* Currently supported tuners:
32  *  o SoundForte RadioLink SF64-PCR PCI Radio Card
33  *  o SoundForte Quad X-treme SF256-PCP-R PCI Sound Card with FM Radio
34  *  o SoundForte Theatre X-treme 5.1 SF256-PCS-R PCI Sound Card with FM Radio
35  */
36 
37 #include <sys/param.h>
38 #include <sys/systm.h>
39 #include <sys/malloc.h>
40 #include <sys/device.h>
41 #include <sys/errno.h>
42 #include <sys/audioio.h>
43 #include <sys/radioio.h>
44 
45 #include <machine/bus.h>
46 
47 #include <dev/radio_if.h>
48 
49 #include <dev/ic/ac97.h>
50 
51 #include <dev/pci/fmsreg.h>
52 #include <dev/pci/fmsvar.h>
53 
54 #include <dev/ic/tea5757.h>
55 
56 #define TUNER_UNKNOWN		0
57 #define TUNER_SF256PCPR		1
58 #define TUNER_SF64PCR		2
59 #define TUNER_SF256PCS		3
60 
61 #define SF64PCR_CAPS		RADIO_CAPS_DETECT_STEREO |	\
62 				RADIO_CAPS_DETECT_SIGNAL |	\
63 				RADIO_CAPS_SET_MONO |	\
64 				RADIO_CAPS_HW_SEARCH |	\
65 				RADIO_CAPS_HW_AFC |	\
66 				RADIO_CAPS_LOCK_SENSITIVITY
67 
68 #define SF256PCPR_CAPS		RADIO_CAPS_DETECT_STEREO |	\
69 				RADIO_CAPS_SET_MONO |	\
70 				RADIO_CAPS_HW_SEARCH |	\
71 				RADIO_CAPS_HW_AFC |	\
72 				RADIO_CAPS_LOCK_SENSITIVITY
73 
74 #define SF256PCS_CAPS		RADIO_CAPS_SET_MONO |	\
75 				RADIO_CAPS_HW_SEARCH |	\
76 				RADIO_CAPS_HW_AFC |	\
77 				RADIO_CAPS_LOCK_SENSITIVITY
78 
79 #define PCR_WREN_ON		0
80 #define PCR_WREN_OFF		FM_IO_PIN1
81 #define PCR_CLOCK_ON		FM_IO_PIN0
82 #define PCR_CLOCK_OFF		0
83 #define PCR_DATA_ON		FM_IO_PIN2
84 #define PCR_DATA_OFF		0
85 
86 #define PCR_SIGNAL		0x80
87 #define PCR_STEREO		0x80
88 #define PCR_INFO_SIGNAL		(1 << 24)
89 #define PCR_INFO_STEREO		(1 << 25)
90 
91 #define PCPR_WREN_ON		0
92 #define PCPR_WREN_OFF		FM_IO_PIN2
93 #define PCPR_CLOCK_ON		FM_IO_PIN0
94 #define PCPR_CLOCK_OFF		0
95 #define PCPR_DATA_ON		FM_IO_PIN1
96 #define PCPR_DATA_OFF		0
97 #define PCPR_INFO_STEREO	0x04
98 
99 #define PCS_WREN_ON		0
100 #define PCS_WREN_OFF		FM_IO_PIN2
101 #define PCS_CLOCK_ON		FM_IO_PIN3
102 #define PCS_CLOCK_OFF		0
103 #define PCS_DATA_ON		FM_IO_PIN1
104 #define PCS_DATA_OFF		0
105 
106 /*
107  * Function prototypes
108  */
109 void	fmsradio_set_mute(struct fms_softc *);
110 
111 void	sf64pcr_init(bus_space_tag_t, bus_space_handle_t, bus_size_t, u_int32_t);
112 void	sf64pcr_rset(bus_space_tag_t, bus_space_handle_t, bus_size_t, u_int32_t);
113 void	sf64pcr_write_bit(bus_space_tag_t, bus_space_handle_t, bus_size_t, int);
114 u_int32_t	sf64pcr_hw_read(bus_space_tag_t, bus_space_handle_t, bus_size_t);
115 int sf64pcr_probe(struct fms_softc *);
116 
117 void	sf256pcpr_init(bus_space_tag_t, bus_space_handle_t, bus_size_t, u_int32_t);
118 void	sf256pcpr_rset(bus_space_tag_t, bus_space_handle_t, bus_size_t, u_int32_t);
119 void	sf256pcpr_write_bit(bus_space_tag_t, bus_space_handle_t, bus_size_t, int);
120 u_int32_t	sf256pcpr_hw_read(bus_space_tag_t, bus_space_handle_t, bus_size_t);
121 int sf256pcpr_probe(struct fms_softc *);
122 
123 void	sf256pcs_init(bus_space_tag_t, bus_space_handle_t, bus_size_t, u_int32_t);
124 void	sf256pcs_rset(bus_space_tag_t, bus_space_handle_t, bus_size_t, u_int32_t);
125 void	sf256pcs_write_bit(bus_space_tag_t, bus_space_handle_t, bus_size_t, int);
126 u_int32_t	sf256pcs_hw_read(bus_space_tag_t, bus_space_handle_t, bus_size_t);
127 int	sf256pcs_probe(struct fms_softc *);
128 
129 int	fmsradio_get_info(void *, struct radio_info *);
130 int	fmsradio_set_info(void *, struct radio_info *);
131 int	fmsradio_search(void *, int);
132 
133 const struct radio_hw_if fmsradio_hw_if = {
134 	NULL,   /* open */
135 	NULL,   /* close */
136 	fmsradio_get_info,
137 	fmsradio_set_info,
138 	fmsradio_search
139 };
140 
141 struct fmsradio_if {
142 	int			type; /* Card type */
143 
144 	int			mute;
145 	u_int8_t		vol;
146 	u_int32_t		freq;
147 	u_int32_t		stereo;
148 	u_int32_t		lock;
149 
150 	struct tea5757_t	tea;
151 };
152 
153 int
fmsradio_attach(struct fms_softc * sc)154 fmsradio_attach(struct fms_softc *sc)
155 {
156 	struct fmsradio_if *r;
157 
158 	r = malloc(sizeof(struct fmsradio_if), M_DEVBUF, M_NOWAIT);
159 	if (r == NULL) {
160 		printf("%s: cannot allocate memory for FM tuner config\n",
161 				sc->sc_dev.dv_xname);
162 		return TUNER_UNKNOWN;
163 	}
164 
165 	sc->radio = r;
166 	r->tea.iot = sc->sc_iot;
167 	r->tea.ioh = sc->sc_ioh;
168 	r->tea.offset = FM_IO_CTL;
169 	r->tea.flags = sc->sc_dev.dv_cfdata->cf_flags;
170 	r->vol = 0;
171 	r->mute = 0;
172 	r->freq = MIN_FM_FREQ;
173 	r->stereo = TEA5757_STEREO;
174 	r->lock = TEA5757_S030;
175 
176 	r->type = TUNER_UNKNOWN;
177 	if ((r->type = sf64pcr_probe(sc)) == TUNER_SF64PCR)
178 		printf("%s: SF64-PCR FM Radio\n", sc->sc_dev.dv_xname);
179 	else if ((r->type = sf256pcpr_probe(sc)) == TUNER_SF256PCPR)
180 		printf("%s: SF256-PCP-R FM Radio\n", sc->sc_dev.dv_xname);
181 	else if ((r->type = sf256pcs_probe(sc)) == TUNER_SF256PCS)
182 		printf("%s: SF256-PCS-R FM Radio\n", sc->sc_dev.dv_xname);
183 	else
184 		return TUNER_UNKNOWN;
185 
186 	fmsradio_set_mute(sc);
187 	radio_attach_mi(&fmsradio_hw_if, sc, &sc->sc_dev);
188 	return r->type;
189 }
190 
191 /* SF256-PCS specific routines */
192 int
sf256pcs_probe(struct fms_softc * sc)193 sf256pcs_probe(struct fms_softc *sc)
194 {
195 	struct fmsradio_if *radio = (struct fmsradio_if *)sc->radio;
196 	u_int32_t freq;
197 
198 	radio->tea.init = sf256pcs_init;
199 	radio->tea.rset = sf256pcs_rset;
200 	radio->tea.write_bit = sf256pcs_write_bit;
201 	radio->tea.read = sf256pcs_hw_read;
202 
203 	tea5757_set_freq(&radio->tea, radio->stereo,
204 	    radio->lock, radio->freq);
205 	freq = tea5757_decode_freq(sf256pcs_hw_read(radio->tea.iot,
206 	    radio->tea.ioh, radio->tea.offset),
207 	    radio->tea.flags & TEA5757_TEA5759);
208 	if (freq != radio->freq)
209 		return TUNER_UNKNOWN;
210 
211 	return TUNER_SF256PCS;
212 }
213 
214 u_int32_t
sf256pcs_hw_read(bus_space_tag_t iot,bus_space_handle_t ioh,bus_size_t offset)215 sf256pcs_hw_read(bus_space_tag_t iot, bus_space_handle_t ioh, bus_size_t offset)
216 {
217 	u_int32_t res = 0ul;
218 	u_int16_t i, d;
219 
220 	d  = FM_IO_GPIO(FM_IO_PIN1 | FM_IO_PIN2 | FM_IO_PIN3) | PCS_WREN_OFF;
221 
222 	/* Now read data in */
223 	d |= FM_IO_GPIO_IN(PCS_DATA_ON) | PCS_DATA_ON;
224 
225 	bus_space_write_2(iot, ioh, offset, d | PCS_CLOCK_OFF);
226 
227 	/* Read the register */
228 	i = 24;
229 	while (i--) {
230 		res <<= 1;
231 		bus_space_write_2(iot, ioh, offset, d | PCS_CLOCK_ON);
232 		bus_space_write_2(iot, ioh, offset, d | PCS_CLOCK_OFF);
233 		res |= bus_space_read_2(iot, ioh, offset) &
234 		   PCS_DATA_ON ? 1 : 0;
235 	}
236 
237 	return (res & (TEA5757_DATA | TEA5757_FREQ));
238 }
239 
240 void
sf256pcs_write_bit(bus_space_tag_t iot,bus_space_handle_t ioh,bus_size_t off,int bit)241 sf256pcs_write_bit(bus_space_tag_t iot, bus_space_handle_t ioh,
242     bus_size_t off, int bit)
243 {
244 	u_int16_t data, wren;
245 
246 	wren  = FM_IO_GPIO(FM_IO_PIN1 | FM_IO_PIN2 | FM_IO_PIN3);
247 	wren |= PCS_WREN_ON;
248 	data = bit ? PCPR_DATA_ON : PCS_DATA_OFF;
249 
250 	bus_space_write_2(iot, ioh, off, PCS_CLOCK_OFF | wren | data);
251 	bus_space_write_2(iot, ioh, off, PCS_CLOCK_ON  | wren | data);
252 	bus_space_write_2(iot, ioh, off, PCS_CLOCK_OFF | wren | data);
253 }
254 
255 void
sf256pcs_init(bus_space_tag_t iot,bus_space_handle_t ioh,bus_size_t offset,u_int32_t d)256 sf256pcs_init(bus_space_tag_t iot, bus_space_handle_t ioh,
257     bus_size_t offset, u_int32_t d)
258 {
259 	d  = FM_IO_GPIO(FM_IO_PIN1 | FM_IO_PIN2 | FM_IO_PIN3);
260 	d |= PCS_WREN_ON | PCS_DATA_OFF | PCS_CLOCK_OFF;
261 
262 	bus_space_write_2(iot, ioh, offset, d);
263 	bus_space_write_2(iot, ioh, offset, d);
264 }
265 
266 void
sf256pcs_rset(bus_space_tag_t iot,bus_space_handle_t ioh,bus_size_t offset,u_int32_t d)267 sf256pcs_rset(bus_space_tag_t iot, bus_space_handle_t ioh,
268     bus_size_t offset, u_int32_t d)
269 {
270 	d  = FM_IO_GPIO(FM_IO_PIN1 | FM_IO_PIN2 | FM_IO_PIN3);
271 	d |= PCS_WREN_OFF | PCS_DATA_OFF | PCS_CLOCK_OFF;
272 
273 	bus_space_write_2(iot, ioh, offset, d);
274 	bus_space_write_2(iot, ioh, offset, d);
275 }
276 
277 /* SF256-PCP-R specific routines */
278 int
sf256pcpr_probe(struct fms_softc * sc)279 sf256pcpr_probe(struct fms_softc *sc)
280 {
281 	struct fmsradio_if *radio = (struct fmsradio_if *)sc->radio;
282 	u_int32_t freq;
283 
284 	radio->tea.init = sf256pcpr_init;
285 	radio->tea.rset = sf256pcpr_rset;
286 	radio->tea.write_bit = sf256pcpr_write_bit;
287 	radio->tea.read = sf256pcpr_hw_read;
288 
289 	tea5757_set_freq(&radio->tea, radio->stereo,
290 	    radio->lock, radio->freq);
291 	freq = tea5757_decode_freq(sf256pcpr_hw_read(radio->tea.iot,
292 	    radio->tea.ioh, radio->tea.offset),
293 	    radio->tea.flags & TEA5757_TEA5759);
294 	if (freq != radio->freq)
295 		return TUNER_UNKNOWN;
296 
297 	return TUNER_SF256PCPR;
298 }
299 
300 u_int32_t
sf256pcpr_hw_read(bus_space_tag_t iot,bus_space_handle_t ioh,bus_size_t offset)301 sf256pcpr_hw_read(bus_space_tag_t iot, bus_space_handle_t ioh,
302     bus_size_t offset)
303 {
304 	u_int32_t res = 0ul;
305 	u_int16_t i, d;
306 
307 	d  = FM_IO_GPIO_ALL | FM_IO_GPIO_IN(PCPR_DATA_ON | FM_IO_PIN3);
308 
309 	/* Now read data in */
310 	d |= PCPR_WREN_OFF | PCPR_DATA_ON;
311 
312 	bus_space_write_2(iot, ioh, offset, d | PCPR_CLOCK_OFF);
313 
314 	/* Read the register */
315 	i = 24;
316 	while (i--) {
317 		res <<= 1;
318 		bus_space_write_2(iot, ioh, offset, d | PCPR_CLOCK_ON);
319 		bus_space_write_2(iot, ioh, offset, d | PCPR_CLOCK_OFF);
320 		res |= bus_space_read_2(iot, ioh, offset) &
321 		    PCPR_DATA_ON ? 1 : 0;
322 	}
323 
324 	return (res & (TEA5757_DATA | TEA5757_FREQ));
325 }
326 
327 void
sf256pcpr_write_bit(bus_space_tag_t iot,bus_space_handle_t ioh,bus_size_t off,int bit)328 sf256pcpr_write_bit(bus_space_tag_t iot, bus_space_handle_t ioh,
329     bus_size_t off, int bit)
330 {
331 	u_int16_t data, wren;
332 
333 	wren  = FM_IO_GPIO_ALL | FM_IO_GPIO_IN(FM_IO_PIN3) | PCPR_WREN_ON;
334 	data = bit ? PCPR_DATA_ON : PCPR_DATA_OFF;
335 
336 	bus_space_write_2(iot, ioh, off, PCPR_CLOCK_OFF | wren | data);
337 	bus_space_write_2(iot, ioh, off, PCPR_CLOCK_ON  | wren | data);
338 	bus_space_write_2(iot, ioh, off, PCPR_CLOCK_OFF | wren | data);
339 }
340 
341 void
sf256pcpr_init(bus_space_tag_t iot,bus_space_handle_t ioh,bus_size_t offset,u_int32_t d)342 sf256pcpr_init(bus_space_tag_t iot, bus_space_handle_t ioh,
343     bus_size_t offset, u_int32_t d)
344 {
345 	d  = FM_IO_GPIO_ALL | FM_IO_GPIO_IN(FM_IO_PIN3);
346 	d |= PCPR_WREN_ON | PCPR_DATA_OFF | PCPR_CLOCK_OFF;
347 
348 	bus_space_write_2(iot, ioh, offset, d);
349 	bus_space_write_2(iot, ioh, offset, d);
350 }
351 
352 void
sf256pcpr_rset(bus_space_tag_t iot,bus_space_handle_t ioh,bus_size_t offset,u_int32_t d)353 sf256pcpr_rset(bus_space_tag_t iot, bus_space_handle_t ioh,
354     bus_size_t offset, u_int32_t d)
355 {
356 	d  = FM_IO_GPIO_ALL | FM_IO_GPIO_IN(FM_IO_PIN3);
357 	d |= PCPR_WREN_OFF | PCPR_DATA_OFF | PCPR_CLOCK_OFF;
358 
359 	bus_space_write_2(iot, ioh, offset, d);
360 	bus_space_write_2(iot, ioh, offset, d);
361 }
362 
363 /* SF64-PCR specific routines */
364 int
sf64pcr_probe(struct fms_softc * sc)365 sf64pcr_probe(struct fms_softc *sc)
366 {
367 	struct fmsradio_if *radio = (struct fmsradio_if *)sc->radio;
368 	u_int32_t freq;
369 
370 	radio->tea.init = sf64pcr_init;
371 	radio->tea.rset = sf64pcr_rset;
372 	radio->tea.write_bit = sf64pcr_write_bit;
373 	radio->tea.read = sf64pcr_hw_read;
374 
375 	tea5757_set_freq(&radio->tea, radio->stereo,
376 	    radio->lock, radio->freq);
377 	freq = tea5757_decode_freq(sf64pcr_hw_read(radio->tea.iot,
378 	    radio->tea.ioh, radio->tea.offset),
379 	    radio->tea.flags & TEA5757_TEA5759);
380 	if (freq != radio->freq)
381 		return TUNER_UNKNOWN;
382 
383 	return TUNER_SF64PCR;
384 }
385 
386 u_int32_t
sf64pcr_hw_read(bus_space_tag_t iot,bus_space_handle_t ioh,bus_size_t offset)387 sf64pcr_hw_read(bus_space_tag_t iot, bus_space_handle_t ioh, bus_size_t offset)
388 {
389 	u_int32_t res = 0ul;
390 	u_int16_t d, i, ind = 0;
391 
392 	d  = FM_IO_GPIO_ALL | FM_IO_GPIO_IN(PCR_DATA_ON | FM_IO_PIN3);
393 
394 	/* Now read data in */
395 	d |= PCR_WREN_OFF | PCR_DATA_ON;
396 
397 	bus_space_write_2(iot, ioh, offset, d | PCR_CLOCK_OFF);
398 	DELAY(4);
399 
400 	/* Read the register */
401 	i = 23;
402 	while (i--) {
403 		bus_space_write_2(iot, ioh, offset, d | PCR_CLOCK_ON);
404 		DELAY(4);
405 
406 		bus_space_write_2(iot, ioh, offset, d | PCR_CLOCK_OFF);
407 		DELAY(4);
408 
409 		res |= bus_space_read_2(iot, ioh, offset) & PCR_DATA_ON ? 1 : 0;
410 		res <<= 1;
411 	}
412 
413 	bus_space_write_2(iot, ioh, offset, d | PCR_CLOCK_ON);
414 	DELAY(4);
415 
416 	i = bus_space_read_1(iot, ioh, offset);
417 	ind = i & PCR_SIGNAL ? (1 << 1) : (0 << 1); /* Tuning */
418 
419 	bus_space_write_2(iot, ioh, offset, d | PCR_CLOCK_OFF);
420 
421 	i = bus_space_read_2(iot, ioh, offset);
422 	ind |= i & PCR_STEREO ? (1 << 0) : (0 << 0); /* Mono */
423 	res |= i & PCR_DATA_ON ? (1 << 0) : (0 << 0);
424 
425 	return (res & (TEA5757_DATA | TEA5757_FREQ)) | (ind << 24);
426 }
427 
428 void
sf64pcr_write_bit(bus_space_tag_t iot,bus_space_handle_t ioh,bus_size_t off,int bit)429 sf64pcr_write_bit(bus_space_tag_t iot, bus_space_handle_t ioh,
430     bus_size_t off, int bit)
431 {
432 	u_int16_t data, wren;
433 
434 	wren  = FM_IO_GPIO_ALL | FM_IO_GPIO_IN(FM_IO_PIN3) | PCR_WREN_ON;
435 	data = bit ? PCR_DATA_ON : PCR_DATA_OFF;
436 
437 	bus_space_write_2(iot, ioh, off, PCR_CLOCK_OFF | wren | data);
438 	DELAY(4);
439 	bus_space_write_2(iot, ioh, off, PCR_CLOCK_ON | wren | data);
440 	DELAY(4);
441 	bus_space_write_2(iot, ioh, off, PCR_CLOCK_OFF | wren | data);
442 	DELAY(4);
443 }
444 
445 void
sf64pcr_init(bus_space_tag_t iot,bus_space_handle_t ioh,bus_size_t offset,u_int32_t d)446 sf64pcr_init(bus_space_tag_t iot, bus_space_handle_t ioh,
447     bus_size_t offset, u_int32_t d)
448 {
449 	d  = FM_IO_GPIO_ALL | FM_IO_GPIO_IN(FM_IO_PIN3);
450 	d |= PCR_WREN_ON | PCR_DATA_ON | PCR_CLOCK_OFF;
451 
452 	bus_space_write_2(iot, ioh, offset, d);
453 	DELAY(4);
454 }
455 
456 void
sf64pcr_rset(bus_space_tag_t iot,bus_space_handle_t ioh,bus_size_t offset,u_int32_t d)457 sf64pcr_rset(bus_space_tag_t iot, bus_space_handle_t ioh,
458     bus_size_t offset, u_int32_t d)
459 {
460 	/* Do nothing */
461 	return;
462 }
463 
464 
465 /* Common tuner routines */
466 /*
467  * Mute/unmute
468  */
469 void
fmsradio_set_mute(struct fms_softc * sc)470 fmsradio_set_mute(struct fms_softc *sc)
471 {
472 	struct fmsradio_if *radio = (struct fmsradio_if *)sc->radio;
473 	u_int16_t v, mute, unmute;
474 
475 	switch (radio->type) {
476 	case TUNER_SF256PCS:
477 		mute = FM_IO_GPIO(FM_IO_PIN1 | FM_IO_PIN2 | FM_IO_PIN3);
478 		unmute = mute | PCS_WREN_OFF;
479 		break;
480 	case TUNER_SF256PCPR:
481 		mute  = FM_IO_GPIO_ALL | FM_IO_GPIO_IN(FM_IO_PIN3);
482 		unmute = mute | PCPR_WREN_OFF;
483 		break;
484 	case TUNER_SF64PCR:
485 		mute  = FM_IO_GPIO_ALL | FM_IO_GPIO_IN(FM_IO_PIN3);
486 		unmute = mute | PCR_WREN_OFF;
487 		break;
488 	default:
489 		return;
490 	}
491 	v = (radio->mute || !radio->vol) ? mute : unmute;
492 	bus_space_write_2(radio->tea.iot, radio->tea.ioh,
493 	    radio->tea.offset, v);
494 	DELAY(64);
495 	bus_space_write_2(radio->tea.iot, radio->tea.ioh,
496 	    radio->tea.offset, v);
497 }
498 
499 int
fmsradio_get_info(void * v,struct radio_info * ri)500 fmsradio_get_info(void *v, struct radio_info *ri)
501 {
502 	struct fms_softc *sc = v;
503 	struct fmsradio_if *radio = (struct fmsradio_if *)sc->radio;
504 	u_int32_t buf;
505 
506 	ri->mute = radio->mute;
507 	ri->volume = radio->vol ? 255 : 0;
508 	ri->stereo = radio->stereo == TEA5757_STEREO ? 1 : 0;
509 	ri->lock = tea5757_decode_lock(radio->lock);
510 
511 	switch (radio->type) {
512 	case TUNER_SF256PCS:
513 		ri->caps = SF256PCS_CAPS;
514 		buf = sf256pcs_hw_read(radio->tea.iot, radio->tea.ioh,
515 		    radio->tea.offset);
516 		ri->info = 0; /* UNSUPPORTED */
517 		break;
518 	case TUNER_SF256PCPR:
519 		ri->caps = SF256PCPR_CAPS;
520 		buf = sf256pcpr_hw_read(radio->tea.iot, radio->tea.ioh,
521 		    radio->tea.offset);
522 		ri->info = bus_space_read_2(radio->tea.iot, radio->tea.ioh,
523 			FM_VOLUME) == PCPR_INFO_STEREO ?
524 			RADIO_INFO_STEREO : 0;
525 		break;
526 	case TUNER_SF64PCR:
527 		ri->caps = SF64PCR_CAPS;
528 		buf = sf64pcr_hw_read(radio->tea.iot, radio->tea.ioh,
529 		    radio->tea.offset);
530 		ri->info  = buf & PCR_INFO_SIGNAL ? 0 : RADIO_INFO_SIGNAL;
531 		ri->info |= buf & PCR_INFO_STEREO ? 0 : RADIO_INFO_STEREO;
532 		break;
533 	default:
534 		return EINVAL;
535 	}
536 
537 	ri->freq = radio->freq = tea5757_decode_freq(buf,
538 			sc->sc_dev.dv_cfdata->cf_flags & TEA5757_TEA5759);
539 
540 	fmsradio_set_mute(sc);
541 
542 	/* UNSUPPORTED */
543 	ri->rfreq = 0;
544 
545 	return (0);
546 }
547 
548 int
fmsradio_set_info(void * v,struct radio_info * ri)549 fmsradio_set_info(void *v, struct radio_info *ri)
550 {
551 	struct fms_softc *sc = v;
552 	struct fmsradio_if *radio = (struct fmsradio_if *)sc->radio;
553 
554 	radio->mute = ri->mute ? 1 : 0;
555 	radio->vol = ri->volume ? 255 : 0;
556 	radio->stereo = ri->stereo ? TEA5757_STEREO: TEA5757_MONO;
557 	radio->lock = tea5757_encode_lock(ri->lock);
558 	ri->freq = radio->freq = tea5757_set_freq(&radio->tea,
559 		radio->lock, radio->stereo, ri->freq);
560 	fmsradio_set_mute(sc);
561 
562 	return (0);
563 }
564 
565 int
fmsradio_search(void * v,int f)566 fmsradio_search(void *v, int f)
567 {
568 	struct fms_softc *sc = v;
569 	struct fmsradio_if *radio = (struct fmsradio_if *)sc->radio;
570 
571 	tea5757_search(&radio->tea, radio->lock,
572 			radio->stereo, f);
573 	fmsradio_set_mute(sc);
574 
575 	return (0);
576 }
577