diff --git a/sys/arch/mips/alchemy/dev/aupsc.c b/sys/arch/mips/alchemy/dev/aupsc.c index 94b8ebb27b3d..12e3f9e558ec 100644 --- a/sys/arch/mips/alchemy/dev/aupsc.c +++ b/sys/arch/mips/alchemy/dev/aupsc.c @@ -1,4 +1,4 @@ -/* $NetBSD: aupsc.c,v 1.1 2006/02/24 14:34:31 shige Exp $ */ +/* $NetBSD: aupsc.c,v 1.2 2006/03/06 17:15:03 shige Exp $ */ /*- * Copyright (c) 2006 Shigeyuki Fukushima. @@ -33,7 +33,7 @@ */ #include -__KERNEL_RCSID(0, "$NetBSD: aupsc.c,v 1.1 2006/02/24 14:34:31 shige Exp $"); +__KERNEL_RCSID(0, "$NetBSD: aupsc.c,v 1.2 2006/03/06 17:15:03 shige Exp $"); #include "locators.h" @@ -49,6 +49,7 @@ __KERNEL_RCSID(0, "$NetBSD: aupsc.c,v 1.1 2006/02/24 14:34:31 shige Exp $"); #include #include #include +#include struct aupsc_softc { struct device sc_dev; @@ -59,21 +60,30 @@ struct aupsc_softc { const struct aupsc_proto { const char *name; + int protocol; + int statreg; + int statbit; } aupsc_protos [] = { + { "ausmbus", AUPSC_SEL_SMBUS, AUPSC_SMBSTAT, SMBUS_STAT_SR }, #if 0 { "auaudio" }, { "aui2s" }, { "ausmbus" }, { "auspi" }, #endif - { NULL } + { NULL, AUPSC_SEL_DISABLE, 0, 0 } }; static int aupsc_match(struct device *, struct cfdata *, void *); static void aupsc_attach(struct device *, struct device *, void *); -static int aupsc_submatch(struct device *parent, struct cfdata *cf, - const int *ldesc, void *aux); -static int aupsc_print(void *aux, const char *pnp); +static int aupsc_submatch(struct device *, struct cfdata *, const int *, + void *); +static int aupsc_print(void *, const char *); + +static void aupsc_enable(void *, int); +static void aupsc_disable(void *); +static void aupsc_suspend(void *); + CFATTACH_DECL(aupsc, sizeof(struct aupsc_softc), aupsc_match, aupsc_attach, NULL, NULL); @@ -97,6 +107,7 @@ aupsc_attach(struct device *parent, struct device *self, void *aux) struct aupsc_softc *sc = (struct aupsc_softc *)self; struct aubus_attach_args *aa = (struct aubus_attach_args *)aux; struct aupsc_attach_args pa; + struct aupsc_controller ctrl; sc->sc_bust = aa->aa_st; if (bus_space_map(sc->sc_bust, aa->aa_addr, @@ -110,16 +121,37 @@ aupsc_attach(struct device *parent, struct device *self, void *aux) rv = bus_space_read_4(sc->sc_bust, sc->sc_bush, AUPSC_SEL); bus_space_write_4(sc->sc_bust, sc->sc_bush, AUPSC_SEL, (rv & AUPSC_SEL_PS(AUPSC_SEL_DISABLE))); + bus_space_write_4(sc->sc_bust, sc->sc_bush, + AUPSC_CTRL, AUPSC_CTRL_ENA(AUPSC_CTRL_DISABLE)); aprint_normal(": Alchemy PSC\n"); - for (i = 0 ; aupsc_protos[i].name != NULL ; i++) { - pa.aupsc_name = aupsc_protos[i].name; - pa.aupsc_bust = sc->sc_bust; - pa.aupsc_bush = sc->sc_bush; + ctrl.psc_bust = sc->sc_bust; + ctrl.psc_bush = sc->sc_bush; + ctrl.psc_sel = &(sc->sc_pscsel); + ctrl.psc_enable = aupsc_enable; + ctrl.psc_disable = aupsc_disable; + ctrl.psc_suspend = aupsc_suspend; + pa.aupsc_ctrl = ctrl; - (void) config_found_sm_loc(self, "aupsc", NULL, - &pa, aupsc_print, aupsc_submatch); + for (i = 0 ; aupsc_protos[i].name != NULL ; i++) { + struct aupsc_protocol_device p; + uint32_t s; + + pa.aupsc_name = aupsc_protos[i].name; + + p.sc_dev = sc->sc_dev; + p.sc_ctrl = ctrl; + + aupsc_enable(&p, aupsc_protos[i].protocol); + s = bus_space_read_4(sc->sc_bust, sc->sc_bush, + aupsc_protos[i].statreg); + aupsc_disable(&p); + + if (s & aupsc_protos[i].statbit) { + (void) config_found_sm_loc(self, "aupsc", NULL, + &pa, aupsc_print, aupsc_submatch); + } } } @@ -141,3 +173,59 @@ aupsc_print(void *aux, const char *pnp) return UNCONF; } + +static void +aupsc_enable(void *arg, int proto) +{ + struct aupsc_protocol_device *sc = arg; + + /* XXX: (TODO) setting clock AUPSC_SEL_CLK */ + switch (proto) { + case AUPSC_SEL_SPI: + case AUPSC_SEL_I2S: + case AUPSC_SEL_AC97: + case AUPSC_SEL_SMBUS: + break; + case AUPSC_SEL_DISABLE: + aupsc_disable(arg); + break; + default: + printf("%s: aupsc_enable: unsupported protocol.\n", + sc->sc_dev.dv_xname); + return; + } + + if (*(sc->sc_ctrl.psc_sel) != AUPSC_SEL_DISABLE) { + printf("%s: aupsc_enable: please disable first.\n", + sc->sc_dev.dv_xname); + return; + } + + bus_space_write_4(sc->sc_ctrl.psc_bust, sc->sc_ctrl.psc_bush, + AUPSC_SEL, AUPSC_SEL_PS(proto)); + bus_space_write_4(sc->sc_ctrl.psc_bust, sc->sc_ctrl.psc_bush, + AUPSC_CTRL, AUPSC_CTRL_ENA(AUPSC_CTRL_ENABLE)); + delay(1); +} + +static void +aupsc_disable(void *arg) +{ + struct aupsc_protocol_device *sc = arg; + + bus_space_write_4(sc->sc_ctrl.psc_bust, sc->sc_ctrl.psc_bush, + AUPSC_SEL, AUPSC_SEL_PS(AUPSC_SEL_DISABLE)); + bus_space_write_4(sc->sc_ctrl.psc_bust, sc->sc_ctrl.psc_bush, + AUPSC_CTRL, AUPSC_CTRL_ENA(AUPSC_CTRL_DISABLE)); + delay(1); +} + +static void +aupsc_suspend(void *arg) +{ + struct aupsc_protocol_device *sc = arg; + + bus_space_write_4(sc->sc_ctrl.psc_bust, sc->sc_ctrl.psc_bush, + AUPSC_CTRL, AUPSC_CTRL_ENA(AUPSC_CTRL_SUSPEND)); + delay(1); +} diff --git a/sys/arch/mips/alchemy/dev/aupscvar.h b/sys/arch/mips/alchemy/dev/aupscvar.h index b2b95d32eeaf..f24d926abb1d 100644 --- a/sys/arch/mips/alchemy/dev/aupscvar.h +++ b/sys/arch/mips/alchemy/dev/aupscvar.h @@ -1,4 +1,4 @@ -/* $NetBSD: aupscvar.h,v 1.1 2006/02/24 14:34:31 shige Exp $ */ +/* $NetBSD: aupscvar.h,v 1.2 2006/03/06 17:15:03 shige Exp $ */ /*- * Copyright (c) 2006 Shigeyuki Fukushima. @@ -35,10 +35,23 @@ #ifndef _MIPS_ALCHEMY_DEV_AUPSCVAR_H_ #define _MIPS_ALCHEMY_DEV_AUPSCVAR_H_ +struct aupsc_controller { + bus_space_tag_t psc_bust; /* Bus space tag */ + bus_space_handle_t psc_bush; /* Bus space handle */ + int * psc_sel; /* current protocol selection */ + void (*psc_enable)(void *, int); + void (*psc_disable)(void *); + void (*psc_suspend)(void *); +}; + struct aupsc_attach_args { const char * aupsc_name; - bus_space_tag_t aupsc_bust; /* Bus space tag */ - bus_space_handle_t aupsc_bush; /* Bus space handle */ + struct aupsc_controller aupsc_ctrl; +}; + +struct aupsc_protocol_device { + struct device sc_dev; + struct aupsc_controller sc_ctrl; }; #endif /* _MIPS_ALCHEMY_DEV_AUPSCVAR_H_ */