Add enable/disable/suspend functions for AuXXXX PSC devices.

This commit is contained in:
shige 2006-03-06 17:15:03 +00:00
parent f38dbbf211
commit 01a719a41a
2 changed files with 116 additions and 15 deletions

View File

@ -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 <sys/cdefs.h>
__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 <mips/alchemy/include/aureg.h>
#include <mips/alchemy/dev/aupscreg.h>
#include <mips/alchemy/dev/aupscvar.h>
#include <mips/alchemy/dev/smbusreg.h>
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);
}

View File

@ -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_ */