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

Annotation of sys/dev/isa/aztech.c, Revision 1.1.1.1

1.1       nbrk        1: /* $OpenBSD: aztech.c,v 1.4 2002/01/23 20:30:38 mickey Exp $ */
                      2: /* $RuOBSD: aztech.c,v 1.11 2001/10/20 13:23:47 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: /* Aztech/PackardBell FM Radio Card device driver */
                     31:
                     32: /*
                     33:  * Sanyo LM7001J Direct PLL Frequency Synthesizer:
                     34:  *     ??? See http://www.redsword.com/tjacobs/geeb/fmcard.htm
                     35:  *
                     36:  * Philips TEA5712T AM/FM Stereo DTS Radio:
                     37:  *     http://www.semiconductors.philips.com/pip/TEA5712
                     38:  */
                     39:
                     40: #include <sys/param.h>
                     41: #include <sys/systm.h>
                     42: #include <sys/proc.h>
                     43: #include <sys/errno.h>
                     44: #include <sys/ioctl.h>
                     45: #include <sys/device.h>
                     46: #include <sys/radioio.h>
                     47:
                     48: #include <machine/bus.h>
                     49:
                     50: #include <dev/isa/isavar.h>
                     51: #include <dev/ic/lm700x.h>
                     52: #include <dev/radio_if.h>
                     53:
                     54: #define RF_25K 25
                     55: #define RF_50K 50
                     56: #define RF_100K        100
                     57:
                     58: #define MAX_VOL        3
                     59: #define VOLUME_RATIO(x)        (255 * x / MAX_VOL)
                     60:
                     61: #define AZ_BASE_VALID(x)       ((x == 0x350) || (x == 0x358))
                     62: #define AZTECH_CAPABILITIES    RADIO_CAPS_DETECT_STEREO |              \
                     63:                                RADIO_CAPS_DETECT_SIGNAL |              \
                     64:                                RADIO_CAPS_SET_MONO |                   \
                     65:                                RADIO_CAPS_REFERENCE_FREQ
                     66:
                     67:
                     68: #define AZTECH_STEREO  (1 << 0)
                     69: #define AZTECH_SIGNAL  (1 << 1)
                     70:
                     71: #define        AZ_WREN_ON      (1 << 1)
                     72: #define        AZ_WREN_OFF     (0 << 1)
                     73:
                     74: #define AZ_CLCK_ON     (1 << 6)
                     75: #define AZ_CLCK_OFF    (0 << 6)
                     76:
                     77: #define AZ_DATA_ON     (1 << 7)
                     78: #define AZ_DATA_OFF    (0 << 7)
                     79:
                     80: int    az_probe(struct device *, void *, void *);
                     81: void   az_attach(struct device *, struct device * self, void *);
                     82:
                     83: int    az_get_info(void *, struct radio_info *);
                     84: int    az_set_info(void *, struct radio_info *);
                     85:
                     86: struct radio_hw_if az_hw_if = {
                     87:        NULL,   /* open */
                     88:        NULL,   /* close */
                     89:        az_get_info,
                     90:        az_set_info,
                     91:        NULL
                     92: };
                     93:
                     94: struct az_softc {
                     95:        struct device   sc_dev;
                     96:
                     97:        int             mute;
                     98:        u_int8_t        vol;
                     99:        u_int32_t       freq;
                    100:        u_int32_t       rf;
                    101:        u_int32_t       stereo;
                    102:
                    103:        struct lm700x_t lm;
                    104: };
                    105:
                    106: struct cfattach az_ca = {
                    107:        sizeof(struct az_softc), az_probe, az_attach
                    108: };
                    109:
                    110: struct cfdriver az_cd = {
                    111:        NULL, "az", DV_DULL
                    112: };
                    113:
                    114: u_int  az_find(bus_space_tag_t, bus_space_handle_t);
                    115: void   az_set_mute(struct az_softc *);
                    116: void   az_set_freq(struct az_softc *, u_int32_t);
                    117: u_int8_t       az_state(bus_space_tag_t, bus_space_handle_t);
                    118:
                    119: void   az_lm700x_init(bus_space_tag_t, bus_space_handle_t, bus_size_t, u_int32_t);
                    120: void   az_lm700x_rset(bus_space_tag_t, bus_space_handle_t, bus_size_t, u_int32_t);
                    121:
                    122: u_int8_t       az_conv_vol(u_int8_t);
                    123: u_int8_t       az_unconv_vol(u_int8_t);
                    124:
                    125: int
                    126: az_probe(struct device *parent, void *self, void *aux)
                    127: {
                    128:        struct isa_attach_args *ia = aux;
                    129:        bus_space_tag_t iot = ia->ia_iot;
                    130:        bus_space_handle_t ioh;
                    131:
                    132:        int iosize = 1, iobase = ia->ia_iobase;
                    133:
                    134:        if (!AZ_BASE_VALID(iobase)) {
                    135:                printf("az: configured iobase 0x%x invalid\n", iobase);
                    136:                return (0);
                    137:        }
                    138:
                    139:        if (bus_space_map(iot, iobase, iosize, 0, &ioh))
                    140:                return (0);
                    141:
                    142:        if (!az_find(iot, ioh)) {
                    143:                bus_space_unmap(iot, ioh, iosize);
                    144:                return (0);
                    145:        }
                    146:
                    147:        bus_space_unmap(iot, ioh, iosize);
                    148:        ia->ia_iosize = iosize;
                    149:        return (1);
                    150: }
                    151:
                    152: void
                    153: az_attach(struct device *parent, struct device *self, void *aux)
                    154: {
                    155:        struct az_softc *sc = (void *) self;
                    156:        struct isa_attach_args *ia = aux;
                    157:
                    158:        sc->lm.iot = ia->ia_iot;
                    159:        sc->rf = LM700X_REF_050;
                    160:        sc->stereo = LM700X_STEREO;
                    161:        sc->mute = 0;
                    162:        sc->freq = MIN_FM_FREQ;
                    163:        sc->vol = 0;
                    164:
                    165:        /* remap I/O */
                    166:        if (bus_space_map(sc->lm.iot, ia->ia_iobase, ia->ia_iosize,
                    167:                          0, &sc->lm.ioh)) {
                    168:                printf(": bus_space_map() failed\n");
                    169:                return;
                    170:        }
                    171:
                    172:        printf(": Aztech/PackardBell\n");
                    173:
                    174:        /* Configure struct lm700x_t lm */
                    175:        sc->lm.offset = 0;
                    176:        sc->lm.wzcl = AZ_WREN_ON | AZ_CLCK_OFF | AZ_DATA_OFF;
                    177:        sc->lm.wzch = AZ_WREN_ON | AZ_CLCK_ON  | AZ_DATA_OFF;
                    178:        sc->lm.wocl = AZ_WREN_ON | AZ_CLCK_OFF | AZ_DATA_ON;
                    179:        sc->lm.woch = AZ_WREN_ON | AZ_CLCK_ON  | AZ_DATA_ON;
                    180:        sc->lm.initdata = 0;
                    181:        sc->lm.rsetdata = AZ_DATA_ON | AZ_CLCK_ON | AZ_WREN_OFF;
                    182:        sc->lm.init = az_lm700x_init;
                    183:        sc->lm.rset = az_lm700x_rset;
                    184:
                    185:        az_set_freq(sc, sc->freq);
                    186:
                    187:        radio_attach_mi(&az_hw_if, sc, &sc->sc_dev);
                    188: }
                    189:
                    190: /*
                    191:  * Mute the card
                    192:  */
                    193: void
                    194: az_set_mute(struct az_softc *sc)
                    195: {
                    196:        bus_space_write_1(sc->lm.iot, sc->lm.ioh, 0,
                    197:            sc->mute ? 0 : sc->vol);
                    198:        DELAY(6);
                    199:        bus_space_write_1(sc->lm.iot, sc->lm.ioh, 0,
                    200:            sc->mute ? 0 : sc->vol);
                    201: }
                    202:
                    203: void
                    204: az_set_freq(struct az_softc *sc, u_int32_t nfreq)
                    205: {
                    206:        u_int8_t vol;
                    207:        u_int32_t reg;
                    208:
                    209:        vol = sc->mute ? 0 : sc->vol;
                    210:
                    211:        if (nfreq > MAX_FM_FREQ)
                    212:                nfreq = MAX_FM_FREQ;
                    213:        if (nfreq < MIN_FM_FREQ)
                    214:                nfreq = MIN_FM_FREQ;
                    215:
                    216:        sc->freq = nfreq;
                    217:
                    218:        reg = lm700x_encode_freq(nfreq, sc->rf);
                    219:        reg |= sc->stereo | sc->rf | LM700X_DIVIDER_FM;
                    220:
                    221:        lm700x_hardware_write(&sc->lm, reg, vol);
                    222:
                    223:        az_set_mute(sc);
                    224: }
                    225:
                    226: /*
                    227:  * Return state of the card - tuned/not tuned, mono/stereo
                    228:  */
                    229: u_int8_t
                    230: az_state(bus_space_tag_t iot, bus_space_handle_t ioh)
                    231: {
                    232:        u_int8_t info = 0, portdata;
                    233:
                    234:        portdata = bus_space_read_1(iot, ioh, 0);
                    235:
                    236:        info |= portdata & AZTECH_STEREO ? 0 : RADIO_INFO_STEREO;
                    237:        info |= portdata & AZTECH_SIGNAL ? 0 : RADIO_INFO_SIGNAL;
                    238:
                    239:        return info;
                    240: }
                    241:
                    242: /*
                    243:  * Convert volume to hardware representation.
                    244:  * The card uses bits 00000x0x to set volume.
                    245:  */
                    246: u_int8_t
                    247: az_conv_vol(u_int8_t vol)
                    248: {
                    249:        if (vol < VOLUME_RATIO(1))
                    250:                return 0;
                    251:        else if (vol >= VOLUME_RATIO(1) && vol < VOLUME_RATIO(2))
                    252:                return 1;
                    253:        else if (vol >= VOLUME_RATIO(2) && vol < VOLUME_RATIO(3))
                    254:                return 4;
                    255:        else
                    256:                return 5;
                    257: }
                    258:
                    259: /*
                    260:  * Convert volume from hardware representation
                    261:  */
                    262: u_int8_t
                    263: az_unconv_vol(u_int8_t vol)
                    264: {
                    265:        switch (vol) {
                    266:        case 0:
                    267:                return VOLUME_RATIO(0);
                    268:        case 1:
                    269:                return VOLUME_RATIO(1);
                    270:        case 4:
                    271:                return VOLUME_RATIO(2);
                    272:        }
                    273:        return VOLUME_RATIO(3);
                    274: }
                    275:
                    276: u_int
                    277: az_find(bus_space_tag_t iot, bus_space_handle_t ioh)
                    278: {
                    279:        struct az_softc sc;
                    280:        u_int i;
                    281:
                    282:        sc.lm.iot = iot;
                    283:        sc.lm.ioh = ioh;
                    284:        sc.lm.offset = 0;
                    285:        sc.lm.wzcl = AZ_WREN_ON | AZ_CLCK_OFF | AZ_DATA_OFF;
                    286:        sc.lm.wzch = AZ_WREN_ON | AZ_CLCK_ON  | AZ_DATA_OFF;
                    287:        sc.lm.wocl = AZ_WREN_ON | AZ_CLCK_OFF | AZ_DATA_ON;
                    288:        sc.lm.woch = AZ_WREN_ON | AZ_CLCK_ON  | AZ_DATA_ON;
                    289:        sc.lm.initdata = 0;
                    290:        sc.lm.rsetdata = AZ_DATA_ON | AZ_CLCK_ON | AZ_WREN_OFF;
                    291:        sc.lm.init = az_lm700x_init;
                    292:        sc.lm.rset = az_lm700x_rset;
                    293:        sc.rf = LM700X_REF_050;
                    294:        sc.mute = 0;
                    295:        sc.stereo = LM700X_STEREO;
                    296:        sc.vol = 0;
                    297:
                    298:        /*
                    299:         * Scan whole FM range. If there is a card it'll
                    300:         * respond on some frequency.
                    301:         */
                    302:        for (i = MIN_FM_FREQ; i < MAX_FM_FREQ; i += 10) {
                    303:                az_set_freq(&sc, i);
                    304:                if (az_state(iot, ioh))
                    305:                        return 1;
                    306:        }
                    307:
                    308:        return 0;
                    309: }
                    310:
                    311: void
                    312: az_lm700x_init(bus_space_tag_t iot, bus_space_handle_t ioh, bus_size_t off,
                    313:                u_int32_t data)
                    314: {
                    315:        /* Do nothing */
                    316:        return;
                    317: }
                    318:
                    319: void
                    320: az_lm700x_rset(bus_space_tag_t iot, bus_space_handle_t ioh, bus_size_t off,
                    321:                u_int32_t data)
                    322: {
                    323:        bus_space_write_1(iot, ioh, off, data);
                    324: }
                    325:
                    326: int
                    327: az_get_info(void *v, struct radio_info *ri)
                    328: {
                    329:        struct az_softc *sc = v;
                    330:
                    331:        ri->mute = sc->mute;
                    332:        ri->volume = az_unconv_vol(sc->vol);
                    333:        ri->stereo = sc->stereo == LM700X_STEREO ? 1 : 0;
                    334:        ri->caps = AZTECH_CAPABILITIES;
                    335:        ri->rfreq = lm700x_decode_ref(sc->rf);
                    336:        ri->info = az_state(sc->lm.iot, sc->lm.ioh);
                    337:        ri->freq = sc->freq;
                    338:
                    339:        /* UNSUPPORTED */
                    340:        ri->lock = 0;
                    341:
                    342:        return (0);
                    343: }
                    344:
                    345: int
                    346: az_set_info(void *v, struct radio_info *ri)
                    347: {
                    348:        struct az_softc *sc = v;
                    349:
                    350:        sc->mute = ri->mute ? 1 : 0;
                    351:        sc->vol = az_conv_vol(ri->volume);
                    352:        sc->stereo = ri->stereo ? LM700X_STEREO : LM700X_MONO;
                    353:        sc->rf = lm700x_encode_ref(ri->rfreq);
                    354:
                    355:        az_set_freq(sc, ri->freq);
                    356:        az_set_mute(sc);
                    357:
                    358:        return (0);
                    359: }

CVSweb