Subject: RFC: Alchemy Au1550 SMBus driver on PSC
To: None <port-evbmips@NetBSD.org>
From: Shigeyuki Fukushima <shige@netbsd.org>
List: port-evbmips
Date: 03/03/2006 02:50:52
This is a multi-part message in MIME format.
--------------030904010605000502030701
Content-Type: text/plain; charset=ISO-8859-1
Content-Transfer-Encoding: 7bit

Hi,

I'm implementing SMBus driver on PSC(bus) device.
Would you like to review the following files (attached with this mail):

  sys-arch-mips.diff:	diffs for sys/arch/mips from -current.
  ausmbus_psc.c:	smbus driver.
  smbusreg.c:		definitions for SMBus registers
			(Au1550 DataBook 8.5)

With implementing this driver, I revised up aupsc.c.
Please review it intensively.
-- 
Kind Regards,
--- shige
Shigeyuki Fukushima <shige@{FreeBSD,jp.FreeBSD,NetBSD}.org>

--------------030904010605000502030701
Content-Type: text/plain;
 name="sys-arch-mips.diff"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline;
 filename="sys-arch-mips.diff"

? sys/arch/mips/alchemy/dev/ausmbus_psc.c
? sys/arch/mips/alchemy/dev/smbusreg.h
Index: sys/arch/mips/alchemy/dev/aupsc.c
===================================================================
RCS file: /cvsroot/src/sys/arch/mips/alchemy/dev/aupsc.c,v
retrieving revision 1.1
diff -u -r1.1 aupsc.c
--- sys/arch/mips/alchemy/dev/aupsc.c	24 Feb 2006 14:34:31 -0000	1.1
+++ sys/arch/mips/alchemy/dev/aupsc.c	2 Mar 2006 17:39:41 -0000
@@ -59,21 +59,30 @@
 
 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 +106,7 @@
 	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 +120,37 @@
 	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");
 
+	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;
+
 	for (i = 0 ; aupsc_protos[i].name != NULL ; i++) {
+		struct aupsc_protocol_device p;
+		uint32_t s;
+
 		pa.aupsc_name = aupsc_protos[i].name;
-		pa.aupsc_bust = sc->sc_bust;
-		pa.aupsc_bush = sc->sc_bush;
 
-		(void) config_found_sm_loc(self, "aupsc", NULL,
-			&pa, aupsc_print, aupsc_submatch);
+		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 +172,59 @@
 
 	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);
+}
Index: sys/arch/mips/alchemy/dev/aupscreg.h
===================================================================
RCS file: /cvsroot/src/sys/arch/mips/alchemy/dev/aupscreg.h,v
retrieving revision 1.1
diff -u -r1.1 aupscreg.h
--- sys/arch/mips/alchemy/dev/aupscreg.h	24 Feb 2006 14:34:31 -0000	1.1
+++ sys/arch/mips/alchemy/dev/aupscreg.h	2 Mar 2006 17:39:41 -0000
@@ -68,10 +68,13 @@
  *    00 = Disable/Reset
  *    01 = Reserved
  *    10 = Suspend
- *    10 = Enable
+ *    11 = Enable
  */
 #define	AUPSC_CTRL			0x04	/* R/W */
 #  define	AUPSC_CTRL_ENA(x)	(x & 0x03)
+#  define	AUPSC_CTRL_DISABLE	0
+#  define	AUPSC_CTRL_SUSPEND	2
+#  define	AUPSC_CTRL_ENABLE	3
 
 /* 0x0008 - 0x002F: Protocol-specific registers */
 
@@ -124,5 +127,6 @@
 #define	AUPSC_SMBEVNT			0x18	/* R/W */
 #define	AUPSC_SMBTXRX			0x1c	/* R/W */
 #define	AUPSC_SMBTMR			0x20	/* R/W */
+#include <mips/alchemy/dev/smbusreg.h>
 
 #endif	/* _MIPS_ALCHEMY_DEV_AUPSCREG_H_ */
Index: sys/arch/mips/alchemy/dev/aupscvar.h
===================================================================
RCS file: /cvsroot/src/sys/arch/mips/alchemy/dev/aupscvar.h,v
retrieving revision 1.1
diff -u -r1.1 aupscvar.h
--- sys/arch/mips/alchemy/dev/aupscvar.h	24 Feb 2006 14:34:31 -0000	1.1
+++ sys/arch/mips/alchemy/dev/aupscvar.h	2 Mar 2006 17:39:41 -0000
@@ -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_ */
Index: sys/arch/mips/conf/files.alchemy
===================================================================
RCS file: /cvsroot/src/sys/arch/mips/conf/files.alchemy,v
retrieving revision 1.10
diff -u -r1.10 files.alchemy
--- sys/arch/mips/conf/files.alchemy	24 Feb 2006 14:34:31 -0000	1.10
+++ sys/arch/mips/conf/files.alchemy	2 Mar 2006 17:39:42 -0000
@@ -60,10 +60,15 @@
 file	arch/mips/alchemy/dev/augpio.c		augpio
 
 # On-chip PSC
-device	aupsc
+device	aupsc { [addr=-1] }
 attach	aupsc at aubus
 file	arch/mips/alchemy/dev/aupsc.c		aupsc
 
+# On-chip PSC SMBus Protocol
+device	ausmbus: i2cbus, i2c_bitbang
+attach	ausmbus at aupsc
+file	arch/mips/alchemy/dev/ausmbus_psc.c	ausmbus
+
 # On-chip PCMCIA
 #
 # XXX: NOTE: As of Feb. 22, 2006, the aupcmcia bus is not quite

--------------030904010605000502030701
Content-Type: text/plain;
 name="ausmbus_psc.c"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline;
 filename="ausmbus_psc.c"

/* $NetBSD$ */

/*-
 * Copyright (c) 2006 Shigeyuki Fukushima.
 * All rights reserved.
 *
 * Written by Shigeyuki Fukushima.
 *
 * 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. Redistributions in binary form must reproduce the above
 *    copyright notice, this list of conditions and the following
 *    disclaimer in the documentation and/or other materials provided
 *    with the distribution.
 * 3. The name of the author 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 ``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 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.
 */

#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD$");

#include "locators.h"

#include <sys/param.h>
#include <sys/systm.h>
#include <sys/device.h>
#include <sys/errno.h>
#include <sys/lock.h>

#include <machine/bus.h>
#include <machine/cpu.h>

#include <mips/alchemy/dev/aupscreg.h>
#include <mips/alchemy/dev/aupscvar.h>
#include <mips/alchemy/dev/smbusreg.h>

#include <dev/i2c/i2cvar.h>
#include <dev/i2c/i2c_bitbang.h>

struct ausmbus_softc {
	struct device			sc_dev;

	/* protocol comoon fields */
	struct aupsc_controller		sc_ctrl;

	/* protocol specific fields */
	struct i2c_controller		sc_i2c;
	i2c_addr_t			sc_smbus_slave_addr;
};

static int	ausmbus_match(struct device *, struct cfdata *, void *);
static void	ausmbus_attach(struct device *, struct device *, void *);

CFATTACH_DECL(ausmbus, sizeof(struct ausmbus_softc),
	ausmbus_match, ausmbus_attach, NULL, NULL);

/* fuctions for i2c_controller */
static int	ausmbus_acquire_bus(void *, int);
static void	ausmbus_release_bus(void *, int);
static int	ausmbus_exec(void *cookie, i2c_op_t op, i2c_addr_t addr,
				const void *cmd, size_t cmdlen, void *vbuf,
				size_t buflen, int flags);
static uint32_t	ausmbus_reg_read(struct ausmbus_softc *, int);
static void	ausmbus_reg_write(struct ausmbus_softc *, int, uint32_t);

static int
ausmbus_match(struct device *parent, struct cfdata *cf, void *aux)
{
	struct aupsc_attach_args *aa = (struct aupsc_attach_args *)aux;

	if (strcmp(aa->aupsc_name, cf->cf_name) != 0)
		return 0;

	return 1;
}

static void
ausmbus_attach(struct device *parent, struct device *self, void *aux)
{
	struct ausmbus_softc *sc = (struct ausmbus_softc *)self;
	struct aupsc_attach_args *aa = (struct aupsc_attach_args *)aux;
	struct i2cbus_attach_args iba;

	aprint_normal(": Alchemy PSC SMBus protocol\n");

	/* Initialize PSC */
	sc->sc_ctrl = aa->aupsc_ctrl;

	/* Initialize i2c_controller for SMBus */
	sc->sc_i2c.ic_cookie = sc;
	sc->sc_i2c.ic_acquire_bus = ausmbus_acquire_bus;
	sc->sc_i2c.ic_release_bus = ausmbus_release_bus;
	sc->sc_i2c.ic_send_start = NULL;
	sc->sc_i2c.ic_send_stop = NULL;
	sc->sc_i2c.ic_initiate_xfer = NULL;
	sc->sc_i2c.ic_read_byte = NULL;
	sc->sc_i2c.ic_write_byte = NULL;
	sc->sc_i2c.ic_exec = ausmbus_exec;
	
	ausmbus_acquire_bus(sc, 0);
	ausmbus_release_bus(sc, 0);

	iba.iba_name = "iic";
	iba.iba_tag = &sc->sc_i2c;
	(void) config_found(&sc->sc_dev, &iba, iicbus_print);
}

static int
ausmbus_acquire_bus(void *arg, int flags)
{
	struct ausmbus_softc *sc = arg;
	uint32_t v;

	/* Select SMBus Protocol & Enable PSC */
	sc->sc_ctrl.psc_enable(sc, AUPSC_SEL_SMBUS);
	v = ausmbus_reg_read(sc, AUPSC_SMBSTAT);
	if ((v & SMBUS_STAT_SR) == 0) {
		/* PSC is not ready */
		return -1;
	}

	/* Setup SMBus Configuration register */
	v = SMBUS_CFG_DD;				/* Disable DMA */
	v |= SMBUS_CFG_RT_SET(SMBUS_CFG_RT_FIFO8);	/* Rx FIFO 8data */
	v |= SMBUS_CFG_TT_SET(SMBUS_CFG_TT_FIFO8);	/* Tx FIFO 8data */
	v |= SMBUS_CFG_DIV_SET(SMBUS_CFG_DIV8);		/* pscn_mainclk/8 */
	v &= ~SMBUS_CFG_SFM;				/* Standard Mode */
	ausmbus_reg_write(sc, AUPSC_SMBCFG, v);

	/* Setup SMBus Protocol Timing register */
	v = SMBUS_TMR_TH_SET(0)
		| SMBUS_TMR_PS_SET(0xf) | SMBUS_TMR_PU_SET(0xf)
		| SMBUS_TMR_SH_SET(0xf) | SMBUS_TMR_SU_SET(0xf)
		| SMBUS_TMR_CL_SET(0xf) | SMBUS_TMR_CH_SET(0xf);
	ausmbus_reg_write(sc, AUPSC_SMBTMR, v);

	/* Setup SMBus Mask register */
	v = SMBUS_MSK_ALLMASK;
	ausmbus_reg_write(sc, AUPSC_SMBMSK, v);

	/* SMBus Enable */
	v = ausmbus_reg_read(sc, AUPSC_SMBCFG);
	v |= SMBUS_CFG_DE;
	ausmbus_reg_write(sc, AUPSC_SMBCFG, v);
	v = ausmbus_reg_read(sc, AUPSC_SMBSTAT);
	if ((v & SMBUS_STAT_SR) == 0) {
		/* SMBus is not ready */
		return -1;
	}

#if 0
	printf("config: 0x%08x\n", ausmbus_reg_read(sc, AUPSC_SMBCFG));
	printf("status: 0x%08x\n", ausmbus_reg_read(sc, AUPSC_SMBSTAT));
	printf("tmr   : 0x%08x\n", ausmbus_reg_read(sc, AUPSC_SMBTMR));
	printf("mask  : 0x%08x\n", ausmbus_reg_read(sc, AUPSC_SMBMSK));
#endif

	return 0;
}

static void
ausmbus_release_bus(void *arg, int flags)
{
	struct ausmbus_softc *sc = arg;

	ausmbus_reg_write(sc, AUPSC_SMBCFG, 0);
	sc->sc_ctrl.psc_disable(sc);

	return;
}

static int
ausmbus_exec(void *cookie, i2c_op_t op, i2c_addr_t addr, const void *cmd,
	size_t cmdlen, void *vbuf, size_t buflen, int flags)
{
	struct ausmbus_softc *sc  = (struct ausmbus_softc *)cookie;
	sc->sc_smbus_slave_addr  = addr;

	/* XXX now implementing... */
	return -1;
}

static uint32_t
ausmbus_reg_read(struct ausmbus_softc *sc, int reg)
{

	return bus_space_read_4(sc->sc_ctrl.psc_bust, sc->sc_ctrl.psc_bush,
		reg);
}

static void
ausmbus_reg_write(struct ausmbus_softc *sc, int reg, uint32_t val)
{

	bus_space_write_4(sc->sc_ctrl.psc_bust, sc->sc_ctrl.psc_bush,
		reg, val);
}

--------------030904010605000502030701
Content-Type: text/plain;
 name="smbusreg.h"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline;
 filename="smbusreg.h"

/* $NetBSD$ */

/*-
 * Copyright (c) 2006 Shigeyuki Fukushima.
 * All rights reserved.
 *
 * Written by Shigeyuki Fukushima.
 *
 * 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. Redistributions in binary form must reproduce the above
 *    copyright notice, this list of conditions and the following
 *    disclaimer in the documentation and/or other materials provided
 *    with the distribution.
 * 3. The name of the author 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 ``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 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.
 */

#ifndef	_MIPS_ALCHEMY_SMBUSREG_H_
#define	_MIPS_ALCHEMY_SMBUSREG_H_

/*
 * psc_smbcfg: SMBus Configuration Register
 *   RT: Rx FIFO Threshold
 *   TT: Tx FIFO Threshold
 *   DD: Disable DMA Transfers
 *   DE: Device Enable
 *   DIV: PSC Clock Divider	(see psc_smbtmr)
 *   GCE: General Call Enable
 *   SFM: Standard/Fast Mode
 *   SLV: Slave Address
 */
#define	SMBUS_CFG_RT		(3u << 30)	/* R/W */
#define	  SMBUS_CFG_RT_SET(x)	((x & 0x3) << 30)
#define	  SMBUS_CFG_RT_FIFO1	0
#define	  SMBUS_CFG_RT_FIFO2	1
#define	  SMBUS_CFG_RT_FIFO4	2
#define	  SMBUS_CFG_RT_FIFO8	3
#define	SMBUS_CFG_TT		(3u << 28)	/* R/W */
#define	  SMBUS_CFG_TT_SET(x)	((x & 0x3) << 28)
#define	  SMBUS_CFG_TT_FIFO1	0
#define	  SMBUS_CFG_TT_FIFO2	1
#define	  SMBUS_CFG_TT_FIFO4	2
#define	  SMBUS_CFG_TT_FIFO8	3
#define	SMBUS_CFG_DD		(1u << 27)	/* R/W */
#define	SMBUS_CFG_DE		(1u << 26)	/* R/W */
#define	SMBUS_CFG_DIV		(3u << 13)	/* R/W */
#define	  SMBUS_CFG_DIV_SET(x)	((x & 0x3) << 13)
#define	  SMBUS_CFG_DIV2	0	/* PSC_CLK = pscn_mainclk / 2 */
#define	  SMBUS_CFG_DIV4	1	/* PSC_CLK = pscn_mainclk / 4 */
#define	  SMBUS_CFG_DIV8	2	/* PSC_CLK = pscn_mainclk / 8 */
#define	  SMBUS_CFG_DIV16	3	/* PSC_CLK = pscn_mainclk / 16 */
#define	SMBUS_CFG_GCE		(1u << 3)	/* R/W */
#define	SMBUS_CFG_SFM		(1u << 8)	/* R/W */
#define	SMBUS_CFG_SLV		(127u << 1)	/* R/W */

/*
 * psc_smbmsk: SMBus Mask Register
 *   DN: Data Not-acknowledged
 *   AN: Address Not-acknowledged
 *   AL: Arbitration Lost
 *   RR: Mask Rx FIFO request intterrupt
 *   RO: Mask Rx FIFO overflow intterrupt
 *   RU: Mask Rx FIFO uderflow intterrupt
 *   TR: Mask Tx FIFO request intterrupt
 *   TO: Mask Tx FIFO overflow intterrupt
 *   TU: Mask Tx FIFO uderflow intterrupt
 *   SD: Mask Slave Done intterrupt
 *   MD: Mask Master Done intterrupt
 */
#define	SMBUS_MSK_DN		(1u << 30)	/* R/W */
#define	SMBUS_MSK_AN		(1u << 29)	/* R/W */
#define	SMBUS_MSK_AL		(1u << 28)	/* R/W */
#define	SMBUS_MSK_RR		(1u << 13)	/* R/W */
#define	SMBUS_MSK_RO		(1u << 12)	/* R/W */
#define	SMBUS_MSK_RU		(1u << 11)	/* R/W */
#define	SMBUS_MSK_TR		(1u << 10)	/* R/W */
#define	SMBUS_MSK_TO		(1u << 9)	/* R/W */
#define	SMBUS_MSK_TU		(1u << 8)	/* R/W */
#define	SMBUS_MSK_SD		(1u << 5)	/* R/W */
#define	SMBUS_MSK_MD		(1u << 4)	/* R/W */
#define SMBUS_MSK_ALLMASK	(SMBUS_MSK_DN | SMBUS_MSK_AN | SMBUS_MSK_AL \
				 | SMBUS_MSK_RR | SMBUS_MSK_RO | SMBUS_MSK_RU \
				 | SMBUS_MSK_TR | SMBUS_MSK_TO | SMBUS_MSK_TU \
				 | SMBUS_MSK_SD | SMBUS_MSK_MD)

/*
 * psc_smbpcr: SMBus Protocol Control Register
 *   DC: Data Clear
 *   MS: Master Start
 */
#define	SMBUS_PCR_DC		(1u << 2)	/* R/W */
#define	SMBUS_PCR_MS		(1u << 0)	/* R/W */

/*
 * psc_smbstat: SMBus Status Register
 *   BB: SMBus bus busy
 *   RF: Receive FIFO full
 *   RE: Receive FIFO empty
 *   RR: Receive request
 *   TF: Transfer FIFO full
 *   TE: Transfer FIFO empty
 *   TR: Transfer request
 *   SB: Slave busy
 *   MB: Master busy
 *   DI: Device interrupt
 *   DR: Device ready
 *   SR: PSC ready
 */
#define	SMBUS_STAT_BB		(1u << 28)	/* Read only */
#define	SMBUS_STAT_RF		(1u << 13)	/* Read only */
#define	SMBUS_STAT_RE		(1u << 12)	/* Read only */
#define	SMBUS_STAT_RR		(1u << 11)	/* Read only */
#define	SMBUS_STAT_TF		(1u << 10)	/* Read only */
#define	SMBUS_STAT_TE		(1u << 9)	/* Read only */
#define	SMBUS_STAT_TR		(1u << 8)	/* Read only */
#define	SMBUS_STAT_SB		(1u << 5)	/* Read only */
#define	SMBUS_STAT_MB		(1u << 4)	/* Read only */
#define	SMBUS_STAT_DI		(1u << 2)	/* Read only */
#define	SMBUS_STAT_DR		(1u << 1)	/* Read only */
#define	SMBUS_STAT_SR		(1u << 0)	/* Read only */

/*
 * psc_smbevnt: SMBus Event Register
 *   DN: Data Not-acknowledged
 *   AN: Address Not-acknowledged
 *   AL: Arbitration Lost
 *   RR: Mask Rx FIFO request intterrupt
 *   RO: Mask Rx FIFO overflow intterrupt
 *   RU: Mask Rx FIFO uderflow intterrupt
 *   TR: Mask Tx FIFO request intterrupt
 *   TO: Mask Tx FIFO overflow intterrupt
 *   TU: Mask Tx FIFO uderflow intterrupt
 *   SD: Mask Slave Done intterrupt
 *   MD: Mask Master Done intterrupt
 */
#define	SMBUS_EVNT_DN		(1u << 30)	/* R/W */
#define	SMBUS_EVNT_AN		(1u << 29)	/* R/W */
#define	SMBUS_EVNT_AL		(1u << 28)	/* R/W */
#define	SMBUS_EVNT_RR		(1u << 13)	/* R/W */
#define	SMBUS_EVNT_RO		(1u << 12)	/* R/W */
#define	SMBUS_EVNT_RU		(1u << 11)	/* R/W */
#define	SMBUS_EVNT_TR		(1u << 10)	/* R/W */
#define	SMBUS_EVNT_TO		(1u << 9)	/* R/W */
#define	SMBUS_EVNT_TU		(1u << 8)	/* R/W */
#define	SMBUS_EVNT_SD		(1u << 5)	/* R/W */
#define	SMBUS_EVNT_MD		(1u << 4)	/* R/W */

/*
 * psc_smbtxrx: SMBus Tx/Rx Data Register
 *   STP: Stop
 *   RSR: Restart
 *   ADDRDATA: Address/Data
 */
#define SMBUS_TXRX_STP		(1u << 29)	/* Write only */
#define SMBUS_TXRX_RSR		(1u << 28)	/* Write only */
#define SMBUS_TXRX_ADDRDATA	(255u << 0)	/* R/W */


/*
 * psc_smbtmr: SMBus Protocol Timers Register
 *   TH: Tx Data Hold Timer
 *   PS: Stop->Start Buffer Timer
 *   PU: Stop Setup Timer
 *   SH: Start Hold Timer
 *   SU: Start Setup Timer
 *   CL: Clock Low
 *   CH: Clock High
 *
 * [SMBus Timing Parameter Values]
 *
 * 		Standard Mode			Fast Mode
 * Timer Name	(pscn_mainclk/8) = 6.25MHz	(pscn_mainclk/2) = 25MHz
 * 		Time unit = 160ns		Time unit = 40ns
 * 		psc_smbtmr	Bus Timings	psc_smbtmr	Bus Timings
 * Tx Hold	TX = 0x00	480ns		TH = 0x02	320ns
 * Stop->Start	PS = 0x0F	4800ns		PS = 0x0F	1320ns
 * Stop Setup	PU = 0x0F	4000ns		PU = 0x0B	600ns
 * Start Hold	SH = 0x0F	4000ns		SH = 0x0B	600ns
 * Start Setup	SU = 0x0F	4800ns		SU = 0x0B	600ns
 * Clock Low	CL = 0x0F	4800ns		CL = 0x0F	1320ns
 * Clock High	CH = 0x0F	4000ns		CH = 0x0B	600ns
 */
#define SMBUS_TMR_TH		(3u << 30)	/* R/W */
#define   SMBUS_TMR_TH_SET(x)	((x &  0x3) << 30)
#define SMBUS_TMR_PS		(31u << 25)	/* R/W */
#define   SMBUS_TMR_PS_SET(x)	((x & 0x1f) << 25)
#define SMBUS_TMR_PU		(31u << 20)	/* R/W */
#define   SMBUS_TMR_PU_SET(x)	((x & 0x1f) << 20)
#define SMBUS_TMR_SH		(31u << 15)	/* R/W */
#define   SMBUS_TMR_SH_SET(x)	((x & 0x1f) << 15)
#define SMBUS_TMR_SU		(31u << 10)	/* R/W */
#define   SMBUS_TMR_SU_SET(x)	((x & 0x1f) << 10)
#define SMBUS_TMR_CL		(31u << 5)	/* R/W */
#define   SMBUS_TMR_CL_SET(x)	((x & 0x1f) << 5)
#define SMBUS_TMR_CH		(31u << 0)	/* R/W */
#define   SMBUS_TMR_CH_SET(x)	((x & 0x1f) << 0)

#endif	/* _MIPS_ALCHEMY_SMBUSREG_H_ */

--------------030904010605000502030701--