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