/* $NetBSD: ucb1200.c,v 1.4 2000/03/12 15:36:11 uch Exp $ */ /* * Copyright (c) 2000, by UCHIYAMA Yasushi * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. The name of the developer may NOT be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * */ /* * Device driver for PHILIPS UCB1200 Advanced modem/audio analog front-end */ #define UCB1200DEBUG #include "opt_tx39_debug.h" #include #include #include #include #include #include #include #include #include #include #ifdef UCB1200DEBUG int ucb1200debug = 0; #define DPRINTF(arg) if (ucb1200debug) printf arg; #define DPRINTFN(n, arg) if (ucb1200debug > (n)) printf arg; #else #define DPRINTF(arg) #define DPRINTFN(n, arg) #endif struct ucbchild_state { int (*cs_busy) __P((void*)); void *cs_arg; }; struct ucb1200_softc { struct device sc_dev; struct device *sc_parent; /* parent (TX39 SIB module) */ tx_chipset_tag_t sc_tc; int sc_snd_rate; /* passed down from SIB module */ int sc_tel_rate; /* inquire child module state */ struct ucbchild_state sc_child[UCB1200_MODULE_MAX]; }; int ucb1200_match __P((struct device*, struct cfdata*, void*)); void ucb1200_attach __P((struct device*, struct device*, void*)); int ucb1200_print __P((void*, const char*)); int ucb1200_search __P((struct device*, struct cfdata*, void*)); int ucb1200_check_id __P((u_int16_t, int)); #ifdef UCB1200DEBUG void ucb1200_dump __P((struct ucb1200_softc*)); #endif struct cfattach ucb_ca = { sizeof(struct ucb1200_softc), ucb1200_match, ucb1200_attach }; const struct ucb_id { u_int16_t id; const char *product; } ucb_id[] = { { UCB1100_ID, "PHILIPS UCB1100" }, { UCB1200_ID, "PHILIPS UCB1200" }, { UCB1300_ID, "PHILIPS UCB1300" }, { TC35413F_ID, "TOSHIBA TC35413F" }, { 0, 0 } }; int ucb1200_match(parent, cf, aux) struct device *parent; struct cfdata *cf; void *aux; { struct txsib_attach_args *sa = aux; u_int16_t reg; if (sa->sa_slot != 0) /* UCB1200 must be subframe 0 */ return 0; reg = txsibsf0_reg_read(sa->sa_tc, UCB1200_ID_REG); return (ucb1200_check_id(reg, 0)); } void ucb1200_attach(parent, self, aux) struct device *parent; struct device *self; void *aux; { struct txsib_attach_args *sa = aux; struct ucb1200_softc *sc = (void*)self; u_int16_t reg; printf(": "); sc->sc_tc = sa->sa_tc; sc->sc_parent = parent; sc->sc_snd_rate = sa->sa_snd_rate; sc->sc_tel_rate = sa->sa_tel_rate; tx39sib_enable1(sc->sc_parent); tx39sib_enable2(sc->sc_parent); #ifdef UCB1200DEBUG if (ucb1200debug) ucb1200_dump(sc); #endif reg = txsibsf0_reg_read(sa->sa_tc, UCB1200_ID_REG); (void)ucb1200_check_id(reg, 1); printf("\n"); config_search(ucb1200_search, self, ucb1200_print); } int ucb1200_search(parent, cf, aux) struct device *parent; struct cfdata *cf; void *aux; { struct ucb1200_softc *sc = (void*)parent; struct ucb1200_attach_args ucba; ucba.ucba_tc = sc->sc_tc; ucba.ucba_snd_rate = sc->sc_snd_rate; ucba.ucba_tel_rate = sc->sc_tel_rate; ucba.ucba_sib = sc->sc_parent; ucba.ucba_ucb = parent; if ((*cf->cf_attach->ca_match)(parent, cf, &ucba)) config_attach(parent, cf, &ucba, ucb1200_print); return 0; } int ucb1200_print(aux, pnp) void *aux; const char *pnp; { return pnp ? QUIET : UNCONF; } int ucb1200_check_id(idreg, print) u_int16_t idreg; int print; { int i; for (i = 0; ucb_id[i].product; i++) { if (ucb_id[i].id == idreg) { if (print) { printf("%s", ucb_id[i].product); } return (1); } } return 0; } void ucb1200_state_install(dev, sfun, sarg, sid) struct device *dev; int (*sfun) __P((void*)); void *sarg; int sid; { struct ucb1200_softc *sc = (void*)dev; sc->sc_child[sid].cs_busy = sfun; sc->sc_child[sid].cs_arg = sarg; } int ucb1200_state_idle(dev) struct device *dev; { struct ucb1200_softc *sc = (void*)dev; struct ucbchild_state *cs; int i; cs = sc->sc_child; for (i = 0; i < UCB1200_MODULE_MAX; i++, cs++) if (cs->cs_busy) if ((*cs->cs_busy)(cs->cs_arg)) return 0; return 1; /* idle state */ } #ifdef UCB1200DEBUG void ucb1200_dump(sc) struct ucb1200_softc *sc; { const char *regname[] = { "IO_DATA ", "IO_DIR ", "POSINTEN ", "NEGINTEN ", "INTSTAT ", "TELECOMCTRLA ", "TELECOMCTRLB ", "AUDIOCTRLA ", "AUDIOCTRLB ", "TOUCHSCREENCTRL", "ADCCTRL ", "ADCDATA ", "ID ", "MODE ", "RESERVED ", "NULL " }; tx_chipset_tag_t tc = sc->sc_tc; u_int16_t reg; int i; printf("\n\t[UCB1200 register]\n"); for (i = 0; i < 16; i++) { reg = txsibsf0_reg_read(tc, i); printf("%s(%02d) 0x%04x ", regname[i], i, reg); bitdisp(reg); } } #endif /* UCB1200DEBUG */