[BACK]Return to sf16fmr2.c CVS log [TXT][DIR] Up to [local] / sys / dev / isa

Annotation of sys/dev/isa/sf16fmr2.c, Revision 1.1

1.1     ! nbrk        1: /* $OpenBSD: sf16fmr2.c,v 1.6 2002/10/15 15:00:11 mickey Exp $ */
        !             2: /* $RuOBSD: sf16fmr2.c,v 1.12 2001/10/18 16:51:36 pva Exp $ */
        !             3:
        !             4: /*
        !             5:  * Copyright (c) 2001 Maxim Tsyplakov <tm@oganer.net>,
        !             6:  *                    Vladimir Popov <jumbo@narod.ru>
        !             7:  * All rights reserved.
        !             8:  *
        !             9:  * Redistribution and use in source and binary forms, with or without
        !            10:  * modification, are permitted provided that the following conditions
        !            11:  * are met:
        !            12:  * 1. Redistributions of source code must retain the above copyright
        !            13:  *    notice, this list of conditions and the following disclaimer.
        !            14:  * 2. Redistributions in binary form must reproduce the above copyright
        !            15:  *    notice, this list of conditions and the following disclaimer in the
        !            16:  *    documentation and/or other materials provided with the distribution.
        !            17:  *
        !            18:  * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
        !            19:  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
        !            20:  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
        !            21:  * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT,
        !            22:  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
        !            23:  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
        !            24:  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
        !            25:  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
        !            26:  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
        !            27:  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
        !            28:  */
        !            29:
        !            30: /* SoundForte RadioLink SF16-FMR2 FM Radio Card device driver */
        !            31:
        !            32: /*
        !            33:  * Philips TEA5757H AM/FM Self Tuned Radio:
        !            34:  *     http://www.semiconductors.philips.com/pip/TEA5757H
        !            35:  */
        !            36:
        !            37: #include <sys/param.h>
        !            38: #include <sys/systm.h>
        !            39: #include <sys/proc.h>
        !            40: #include <sys/errno.h>
        !            41: #include <sys/ioctl.h>
        !            42: #include <sys/device.h>
        !            43: #include <sys/radioio.h>
        !            44:
        !            45: #include <dev/isa/isavar.h>
        !            46: #include <dev/radio_if.h>
        !            47: #include <dev/ic/tea5757.h>
        !            48: #include <dev/ic/pt2254a.h>
        !            49:
        !            50: #define SF16FMR2_BASE_VALID(x) (x == 0x384)
        !            51: #define SF16FMR2_CAPABILITIES  RADIO_CAPS_DETECT_STEREO |              \
        !            52:                                RADIO_CAPS_DETECT_SIGNAL |              \
        !            53:                                RADIO_CAPS_SET_MONO |                   \
        !            54:                                RADIO_CAPS_LOCK_SENSITIVITY |           \
        !            55:                                RADIO_CAPS_HW_AFC |                     \
        !            56:                                RADIO_CAPS_HW_SEARCH
        !            57:
        !            58: #define SF16FMR2_AMP           0
        !            59: #define SF16FMR2_NOAMP         1
        !            60:
        !            61: #define SF16FMR2_AMPLIFIER     (1 << 7)
        !            62: #define SF16FMR2_SIGNAL                (1 << 3)
        !            63: #define SF16FMR2_STEREO                (1 << 3)
        !            64:
        !            65: #define SF16FMR2_MUTE          0x00
        !            66: #define SF16FMR2_UNMUTE                0x04
        !            67:
        !            68: #define SF16FMR2_DATA_ON       (1 << 0)
        !            69: #define SF16FMR2_DATA_OFF      (0 << 0)
        !            70:
        !            71: #define SF16FMR2_CLCK_ON       (1 << 1)
        !            72: #define SF16FMR2_CLCK_OFF      (0 << 1)
        !            73:
        !            74: #define SF16FMR2_WREN_ON       (0 << 2)  /* SF16-FMR2 has inverse WREN */
        !            75: #define SF16FMR2_WREN_OFF      (1 << 2)
        !            76:
        !            77: #define SF16FMR2_READ_CLOCK_LOW                \
        !            78:        SF16FMR2_DATA_ON | SF16FMR2_CLCK_OFF | SF16FMR2_WREN_OFF
        !            79:
        !            80: #define SF16FMR2_READ_CLOCK_HIGH       \
        !            81:        SF16FMR2_DATA_ON | SF16FMR2_CLCK_ON | SF16FMR2_WREN_OFF
        !            82:
        !            83: #define SF16FMR2_VOLU_STROBE_ON                (0 << 2)
        !            84: #define SF16FMR2_VOLU_STROBE_OFF       (1 << 2)
        !            85: #define SF16FMR2_VOLU_CLOCK_ON         (1 << 5)
        !            86: #define SF16FMR2_VOLU_CLOCK_OFF                (0 << 5)
        !            87: #define SF16FMR2_VOLU_DATA_ON          (1 << 6)
        !            88: #define SF16FMR2_VOLU_DATA_OFF         (0 << 6)
        !            89:
        !            90: int    sf2r_probe(struct device *, void *, void *);
        !            91: void   sf2r_attach(struct device *, struct device * self, void *);
        !            92:
        !            93: int    sf2r_get_info(void *, struct radio_info *);
        !            94: int    sf2r_set_info(void *, struct radio_info *);
        !            95: int    sf2r_search(void *, int);
        !            96:
        !            97: /* define our interface to the higher level radio driver */
        !            98: struct radio_hw_if sf2r_hw_if = {
        !            99:        NULL, /* open */
        !           100:        NULL, /* close */
        !           101:        sf2r_get_info,
        !           102:        sf2r_set_info,
        !           103:        sf2r_search
        !           104: };
        !           105:
        !           106: struct sf2r_softc {
        !           107:        struct device   sc_dev;
        !           108:
        !           109:        int             type;
        !           110:        u_int32_t       freq;
        !           111:        u_int32_t       stereo;
        !           112:        u_int32_t       lock;
        !           113:        u_int8_t        vol;
        !           114:        int     mute;
        !           115:
        !           116:        struct tea5757_t        tea;
        !           117: };
        !           118:
        !           119: struct cfattach sf2r_ca = {
        !           120:        sizeof(struct sf2r_softc), sf2r_probe, sf2r_attach
        !           121: };
        !           122:
        !           123: struct cfdriver sf2r_cd = {
        !           124:        NULL, "sf2r", DV_DULL
        !           125: };
        !           126:
        !           127: void   sf2r_set_mute(struct sf2r_softc *);
        !           128: void   sf2r_send_vol_bit(bus_space_tag_t, bus_space_handle_t, u_int32_t);
        !           129: int    sf2r_find(bus_space_tag_t, bus_space_handle_t, int);
        !           130:
        !           131: u_int32_t sf2r_read_register(bus_space_tag_t, bus_space_handle_t, bus_size_t);
        !           132:
        !           133: void   sf2r_init(bus_space_tag_t, bus_space_handle_t, bus_size_t, u_int32_t);
        !           134: void   sf2r_rset(bus_space_tag_t, bus_space_handle_t, bus_size_t, u_int32_t);
        !           135: void   sf2r_write_bit(bus_space_tag_t, bus_space_handle_t, bus_size_t, int);
        !           136:
        !           137: int
        !           138: sf2r_probe(struct device *parent, void *match, void *aux)
        !           139: {
        !           140:        struct isa_attach_args *ia = aux;
        !           141:        bus_space_tag_t iot = ia->ia_iot;
        !           142:        bus_space_handle_t ioh;
        !           143:        struct cfdata *cf = match;
        !           144:        int iosize = 1, iobase = ia->ia_iobase;
        !           145:
        !           146:        if (!SF16FMR2_BASE_VALID(iobase)) {
        !           147:                printf("sf2r: configured iobase 0x%x invalid\n", iobase);
        !           148:                return (0);
        !           149:        }
        !           150:
        !           151:        if (bus_space_map(iot, iobase, iosize, 0, &ioh))
        !           152:                return (0);
        !           153:
        !           154:        if (!sf2r_find(iot, ioh, cf->cf_flags)) {
        !           155:                bus_space_unmap(iot, ioh, iosize);
        !           156:                return (0);
        !           157:        }
        !           158:
        !           159:        bus_space_unmap(iot, ioh, iosize);
        !           160:        ia->ia_iosize = iosize;
        !           161:        return (1);
        !           162: }
        !           163:
        !           164: void
        !           165: sf2r_attach(struct device *parent, struct device *self, void *aux)
        !           166: {
        !           167:        struct sf2r_softc *sc = (void *) self;
        !           168:        struct isa_attach_args *ia = aux;
        !           169:        struct cfdata *cf = sc->sc_dev.dv_cfdata;
        !           170:        int type;
        !           171:
        !           172:        sc->tea.iot = ia->ia_iot;
        !           173:        sc->mute = 0;
        !           174:        sc->vol = 0;
        !           175:        sc->freq = MIN_FM_FREQ;
        !           176:        sc->stereo = TEA5757_STEREO;
        !           177:        sc->lock = TEA5757_S030;
        !           178:
        !           179:        /* remap I/O */
        !           180:        if (bus_space_map(sc->tea.iot, ia->ia_iobase, ia->ia_iosize,
        !           181:            0, &sc->tea.ioh)) {
        !           182:                printf(": bus_space_map() failed\n");
        !           183:                return;
        !           184:        }
        !           185:
        !           186:        sc->tea.offset = 0;
        !           187:        sc->tea.flags = cf->cf_flags;
        !           188:
        !           189:        sc->tea.init = sf2r_init;
        !           190:        sc->tea.rset = sf2r_rset;
        !           191:        sc->tea.write_bit = sf2r_write_bit;
        !           192:        sc->tea.read = sf2r_read_register;
        !           193:
        !           194:        printf(": SoundForte RadioLink SF16-FMR2\n");
        !           195:        tea5757_set_freq(&sc->tea, sc->stereo, sc->lock, sc->freq);
        !           196:        sf2r_set_mute(sc);
        !           197:
        !           198:        type = sf2r_read_register(sc->tea.iot, sc->tea.ioh, sc->tea.offset);
        !           199:        sc->type = (type >> 24) & (1 << 1)? SF16FMR2_AMP : SF16FMR2_NOAMP;
        !           200:
        !           201:        radio_attach_mi(&sf2r_hw_if, sc, &sc->sc_dev);
        !           202: }
        !           203:
        !           204: /*
        !           205:  * Mute/unmute the card
        !           206:  */
        !           207: void
        !           208: sf2r_set_mute(struct sf2r_softc *sc)
        !           209: {
        !           210:        u_int8_t mute;
        !           211:        u_int32_t reg, vol, i;
        !           212:
        !           213:        if (sc->type == SF16FMR2_NOAMP) {
        !           214:                mute = (sc->mute || !sc->vol)? SF16FMR2_MUTE : SF16FMR2_UNMUTE;
        !           215:                bus_space_write_1(sc->tea.iot, sc->tea.ioh, 0, mute);
        !           216:                DELAY(64);
        !           217:                bus_space_write_1(sc->tea.iot, sc->tea.ioh, 0, mute);
        !           218:        } else {
        !           219:                mute = sc->mute? SF16FMR2_MUTE : SF16FMR2_UNMUTE;
        !           220:                bus_space_write_1(sc->tea.iot, sc->tea.ioh, 0, mute);
        !           221:                DELAY(64);
        !           222:                bus_space_write_1(sc->tea.iot, sc->tea.ioh, 0, mute);
        !           223:
        !           224:                vol = pt2254a_encode_volume(&sc->vol, 255);
        !           225:                reg = pt2254a_compose_register(vol, vol,
        !           226:                    USE_CHANNEL, USE_CHANNEL);
        !           227:
        !           228:                bus_space_write_1(sc->tea.iot, sc->tea.ioh,
        !           229:                    0, SF16FMR2_VOLU_STROBE_OFF);
        !           230:
        !           231:                for (i = 0; i < PT2254A_REGISTER_LENGTH; i++)
        !           232:                        sf2r_send_vol_bit(sc->tea.iot, sc->tea.ioh,
        !           233:                            reg & (1 << i));
        !           234:
        !           235:                bus_space_write_1(sc->tea.iot, sc->tea.ioh,
        !           236:                    0, SF16FMR2_VOLU_STROBE_ON);
        !           237:                bus_space_write_1(sc->tea.iot, sc->tea.ioh,
        !           238:                    0, SF16FMR2_VOLU_STROBE_OFF);
        !           239:                bus_space_write_1(sc->tea.iot, sc->tea.ioh,
        !           240:                    0, 0x10 | SF16FMR2_VOLU_STROBE_OFF);
        !           241:        }
        !           242: }
        !           243:
        !           244: void
        !           245: sf2r_init(bus_space_tag_t iot, bus_space_handle_t ioh, bus_size_t off, u_int32_t d)
        !           246: {
        !           247:        bus_space_write_1(iot, ioh, off, SF16FMR2_MUTE);
        !           248: }
        !           249:
        !           250: void
        !           251: sf2r_rset(bus_space_tag_t iot, bus_space_handle_t ioh, bus_size_t off, u_int32_t d)
        !           252: {
        !           253:        bus_space_write_1(iot, ioh, off, SF16FMR2_MUTE);
        !           254:        bus_space_write_1(iot, ioh, off, SF16FMR2_UNMUTE);
        !           255: }
        !           256:
        !           257: int
        !           258: sf2r_find(bus_space_tag_t iot, bus_space_handle_t ioh, int flags)
        !           259: {
        !           260:        struct sf2r_softc sc;
        !           261:        u_int32_t freq;
        !           262:
        !           263:        sc.tea.iot = iot;
        !           264:        sc.tea.ioh = ioh;
        !           265:        sc.tea.offset = 0;
        !           266:        sc.tea.flags = flags;
        !           267:        sc.tea.init = sf2r_init;
        !           268:        sc.tea.rset = sf2r_rset;
        !           269:        sc.tea.write_bit = sf2r_write_bit;
        !           270:        sc.tea.read = sf2r_read_register;
        !           271:        sc.lock = TEA5757_S030;
        !           272:        sc.stereo = TEA5757_STEREO;
        !           273:
        !           274:        if ((bus_space_read_1(iot, ioh, 0) & 0x70) == 0x30) {
        !           275:                /*
        !           276:                 * Let's try to write and read a frequency.
        !           277:                 * If the written and read frequencies are
        !           278:                 * the same then success.
        !           279:                 */
        !           280:                sc.freq = MIN_FM_FREQ;
        !           281:                tea5757_set_freq(&sc.tea, sc.stereo, sc.lock, sc.freq);
        !           282:                sf2r_set_mute(&sc);
        !           283:                freq = sf2r_read_register(iot, ioh, sc.tea.offset);
        !           284:                if (tea5757_decode_freq(freq, sc.tea.flags & TEA5757_TEA5759)
        !           285:                    == sc.freq)
        !           286:                        return 1;
        !           287:        }
        !           288:
        !           289:        return 0;
        !           290: }
        !           291:
        !           292: void
        !           293: sf2r_write_bit(bus_space_tag_t iot, bus_space_handle_t ioh, bus_size_t off, int bit)
        !           294: {
        !           295:        u_int8_t data;
        !           296:
        !           297:        data = bit? SF16FMR2_DATA_ON : SF16FMR2_DATA_OFF;
        !           298:
        !           299:        bus_space_write_1(iot, ioh, off,
        !           300:            SF16FMR2_WREN_ON | SF16FMR2_CLCK_OFF | data);
        !           301:        bus_space_write_1(iot, ioh, off,
        !           302:            SF16FMR2_WREN_ON | SF16FMR2_CLCK_ON  | data);
        !           303:        bus_space_write_1(iot, ioh, off,
        !           304:            SF16FMR2_WREN_ON | SF16FMR2_CLCK_OFF | data);
        !           305: }
        !           306:
        !           307: u_int32_t
        !           308: sf2r_read_register(bus_space_tag_t iot, bus_space_handle_t ioh, bus_size_t off)
        !           309: {
        !           310:        u_int32_t res = 0;
        !           311:        u_int8_t i, state = 0;
        !           312:
        !           313:        bus_space_write_1(iot, ioh, off, SF16FMR2_READ_CLOCK_LOW);
        !           314:        DELAY(6);
        !           315:        bus_space_write_1(iot, ioh, off, SF16FMR2_READ_CLOCK_HIGH);
        !           316:
        !           317:        i = bus_space_read_1(iot, ioh, off);
        !           318:        DELAY(6);
        !           319:        /* Amplifier: 0 - not present, 1 - present */
        !           320:        state = i & SF16FMR2_AMPLIFIER? (1 << 2) : (0 << 2);
        !           321:        /* Signal: 0 - not tuned, 1 - tuned */
        !           322:        state |= i & SF16FMR2_SIGNAL? (0 << 1) : (1 << 1);
        !           323:
        !           324:        bus_space_write_1(iot, ioh, off, SF16FMR2_READ_CLOCK_LOW);
        !           325:        i = bus_space_read_1(iot, ioh, off);
        !           326:        /* Stereo: 0 - mono, 1 - stereo */
        !           327:        state |= i & SF16FMR2_STEREO? (0 << 0) : (1 << 0);
        !           328:        res = i & SF16FMR2_DATA_ON;
        !           329:
        !           330:        i = 23;
        !           331:        while ( i-- ) {
        !           332:                DELAY(6);
        !           333:                res <<= 1;
        !           334:                bus_space_write_1(iot, ioh, off, SF16FMR2_READ_CLOCK_HIGH);
        !           335:                DELAY(6);
        !           336:                bus_space_write_1(iot, ioh, off, SF16FMR2_READ_CLOCK_LOW);
        !           337:                res |= bus_space_read_1(iot, ioh, off) & SF16FMR2_DATA_ON;
        !           338:        }
        !           339:
        !           340:        return res | (state << 24);
        !           341: }
        !           342:
        !           343: int
        !           344: sf2r_get_info(void *v, struct radio_info *ri)
        !           345: {
        !           346:        struct sf2r_softc *sc = v;
        !           347:        u_int32_t buf;
        !           348:
        !           349:        ri->mute = sc->mute;
        !           350:        ri->volume = sc->vol? 255 : 0;
        !           351:        ri->stereo = sc->stereo == TEA5757_STEREO? 1 : 0;
        !           352:        ri->caps = SF16FMR2_CAPABILITIES;
        !           353:        ri->rfreq = 0;
        !           354:        ri->lock = tea5757_decode_lock(sc->lock);
        !           355:
        !           356:        buf = sf2r_read_register(sc->tea.iot, sc->tea.ioh, sc->tea.offset);
        !           357:        ri->freq  = sc->freq = tea5757_decode_freq(buf,
        !           358:            sc->tea.flags & TEA5757_TEA5759);
        !           359:        ri->info = 3 & (buf >> 24);
        !           360:
        !           361:        return (0);
        !           362: }
        !           363:
        !           364: int
        !           365: sf2r_set_info(void *v, struct radio_info *ri)
        !           366: {
        !           367:        struct sf2r_softc *sc = v;
        !           368:
        !           369:        sc->mute = ri->mute? 1 : 0;
        !           370:        sc->vol = ri->volume? 255 : 0;
        !           371:        sc->stereo = ri->stereo? TEA5757_STEREO: TEA5757_MONO;
        !           372:        sc->lock = tea5757_encode_lock(ri->lock);
        !           373:        ri->freq = sc->freq = tea5757_set_freq(&sc->tea,
        !           374:            sc->lock, sc->stereo, ri->freq);
        !           375:        sf2r_set_mute(sc);
        !           376:
        !           377:        return (0);
        !           378: }
        !           379:
        !           380: int
        !           381: sf2r_search(void *v, int f)
        !           382: {
        !           383:        struct sf2r_softc *sc = v;
        !           384:
        !           385:        tea5757_search(&sc->tea, sc->lock, sc->stereo, f);
        !           386:        sf2r_set_mute(sc);
        !           387:
        !           388:        return (0);
        !           389: }
        !           390:
        !           391: void
        !           392: sf2r_send_vol_bit(bus_space_tag_t iot, bus_space_handle_t ioh, u_int32_t d) {
        !           393:        u_int8_t data;
        !           394:
        !           395:        data = SF16FMR2_VOLU_STROBE_OFF;
        !           396:        data |= d? SF16FMR2_VOLU_DATA_ON : SF16FMR2_VOLU_DATA_OFF;
        !           397:
        !           398:        bus_space_write_1(iot, ioh, 0, data | SF16FMR2_VOLU_CLOCK_OFF);
        !           399:        bus_space_write_1(iot, ioh, 0, data | SF16FMR2_VOLU_CLOCK_ON);
        !           400: }

CVSweb