Home | History | Annotate | Line # | Download | only in dev
ausmbus_psc.c revision 1.3
      1 /* $NetBSD: ausmbus_psc.c,v 1.3 2006/03/06 23:06:17 shige Exp $ */
      2 
      3 /*-
      4  * Copyright (c) 2006 Shigeyuki Fukushima.
      5  * All rights reserved.
      6  *
      7  * Written by Shigeyuki Fukushima.
      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
     15  *    copyright notice, this list of conditions and the following
     16  *    disclaimer in the documentation and/or other materials provided
     17  *    with the distribution.
     18  * 3. The name of the author may not be used to endorse or promote
     19  *    products derived from this software without specific prior
     20  *    written permission.
     21  *
     22  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
     23  * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
     24  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     25  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
     26  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     27  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
     28  * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     29  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
     30  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
     31  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
     32  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     33  */
     34 
     35 #include <sys/cdefs.h>
     36 __KERNEL_RCSID(0, "$NetBSD: ausmbus_psc.c,v 1.3 2006/03/06 23:06:17 shige Exp $");
     37 
     38 #include "locators.h"
     39 
     40 #include <sys/param.h>
     41 #include <sys/systm.h>
     42 #include <sys/device.h>
     43 #include <sys/errno.h>
     44 
     45 #include <machine/bus.h>
     46 #include <machine/cpu.h>
     47 
     48 #include <mips/alchemy/dev/aupscreg.h>
     49 #include <mips/alchemy/dev/aupscvar.h>
     50 #include <mips/alchemy/dev/ausmbus_pscreg.h>
     51 
     52 #include <dev/i2c/i2cvar.h>
     53 #include <dev/i2c/i2c_bitbang.h>
     54 
     55 struct ausmbus_softc {
     56 	struct device			sc_dev;
     57 
     58 	/* protocol comoon fields */
     59 	struct aupsc_controller		sc_ctrl;
     60 
     61 	/* protocol specific fields */
     62 	struct i2c_controller		sc_i2c;
     63 	i2c_addr_t			sc_smbus_slave_addr;
     64 	int				sc_smbus_timeout;
     65 };
     66 
     67 #define	ausmbus_reg_read(sc, reg) \
     68 	bus_space_read_4(sc->sc_ctrl.psc_bust, sc->sc_ctrl.psc_bush, reg)
     69 #define	ausmbus_reg_write(sc, reg, val) \
     70 	bus_space_write_4(sc->sc_ctrl.psc_bust, sc->sc_ctrl.psc_bush, reg, val)
     71 
     72 static int	ausmbus_match(struct device *, struct cfdata *, void *);
     73 static void	ausmbus_attach(struct device *, struct device *, void *);
     74 
     75 CFATTACH_DECL(ausmbus, sizeof(struct ausmbus_softc),
     76 	ausmbus_match, ausmbus_attach, NULL, NULL);
     77 
     78 /* fuctions for i2c_controller */
     79 static int	ausmbus_acquire_bus(void *, int);
     80 static void	ausmbus_release_bus(void *, int);
     81 static int	ausmbus_exec(void *cookie, i2c_op_t op, i2c_addr_t addr,
     82 				const void *cmd, size_t cmdlen, void *vbuf,
     83 				size_t buflen, int flags);
     84 
     85 /* subroutine functions for i2c_controller */
     86 static int	ausmbus_receive_1(struct ausmbus_softc *, uint8_t *);
     87 static int	ausmbus_read_1(struct ausmbus_softc *, uint8_t, uint8_t *);
     88 static int	ausmbus_send_1(struct ausmbus_softc *, uint8_t);
     89 static int	ausmbus_write_1(struct ausmbus_softc *, uint8_t, uint8_t);
     90 static int	ausmbus_wait_mastertx(struct ausmbus_softc *sc);
     91 static int	ausmbus_wait_masterrx(struct ausmbus_softc *sc);
     92 static int	ausmbus_initiate_xfer(void *, i2c_addr_t, int);
     93 static int	ausmbus_read_byte(void *arg, uint8_t *vp, int flags);
     94 static int	ausmbus_write_byte(void *arg, uint8_t v, int flags);
     95 
     96 
     97 static int
     98 ausmbus_match(struct device *parent, struct cfdata *cf, void *aux)
     99 {
    100 	struct aupsc_attach_args *aa = (struct aupsc_attach_args *)aux;
    101 
    102 	if (strcmp(aa->aupsc_name, cf->cf_name) != 0)
    103 		return 0;
    104 
    105 	return 1;
    106 }
    107 
    108 static void
    109 ausmbus_attach(struct device *parent, struct device *self, void *aux)
    110 {
    111 	struct ausmbus_softc *sc = (struct ausmbus_softc *)self;
    112 	struct aupsc_attach_args *aa = (struct aupsc_attach_args *)aux;
    113 	struct i2cbus_attach_args iba;
    114 
    115 	aprint_normal(": Alchemy PSC SMBus protocol\n");
    116 
    117 	/* Initialize PSC */
    118 	sc->sc_ctrl = aa->aupsc_ctrl;
    119 
    120 	/* Initialize i2c_controller for SMBus */
    121 	sc->sc_i2c.ic_cookie = sc;
    122 	sc->sc_i2c.ic_acquire_bus = ausmbus_acquire_bus;
    123 	sc->sc_i2c.ic_release_bus = ausmbus_release_bus;
    124 	sc->sc_i2c.ic_send_start = NULL;
    125 	sc->sc_i2c.ic_send_stop = NULL;
    126 	sc->sc_i2c.ic_initiate_xfer = NULL;
    127 	sc->sc_i2c.ic_read_byte = NULL;
    128 	sc->sc_i2c.ic_write_byte = NULL;
    129 	sc->sc_i2c.ic_exec = ausmbus_exec;
    130 	sc->sc_smbus_timeout = 10;
    131 
    132 	iba.iba_name = "iic";
    133 	iba.iba_tag = &sc->sc_i2c;
    134 	(void) config_found(&sc->sc_dev, &iba, iicbus_print);
    135 }
    136 
    137 static int
    138 ausmbus_acquire_bus(void *arg, int flags)
    139 {
    140 	struct ausmbus_softc *sc = arg;
    141 	uint32_t v;
    142 
    143 	/* Select SMBus Protocol & Enable PSC */
    144 	sc->sc_ctrl.psc_enable(sc, AUPSC_SEL_SMBUS);
    145 	v = ausmbus_reg_read(sc, AUPSC_SMBSTAT);
    146 	if ((v & SMBUS_STAT_SR) == 0) {
    147 		/* PSC is not ready */
    148 		return -1;
    149 	}
    150 
    151 	/* Setup SMBus Configuration register */
    152 	v = SMBUS_CFG_DD;				/* Disable DMA */
    153 	v |= SMBUS_CFG_RT_SET(SMBUS_CFG_RT_FIFO8);	/* Rx FIFO 8data */
    154 	v |= SMBUS_CFG_TT_SET(SMBUS_CFG_TT_FIFO8);	/* Tx FIFO 8data */
    155 	v |= SMBUS_CFG_DIV_SET(SMBUS_CFG_DIV8);		/* pscn_mainclk/8 */
    156 	v &= ~SMBUS_CFG_SFM;				/* Standard Mode */
    157 	ausmbus_reg_write(sc, AUPSC_SMBCFG, v);
    158 
    159 	/* Setup SMBus Protocol Timing register */
    160 	v = SMBUS_TMR_TH_SET(SMBUS_TMR_STD_TH)
    161 		| SMBUS_TMR_PS_SET(SMBUS_TMR_STD_PS)
    162 		| SMBUS_TMR_PU_SET(SMBUS_TMR_STD_PU)
    163 		| SMBUS_TMR_SH_SET(SMBUS_TMR_STD_SH)
    164 		| SMBUS_TMR_SU_SET(SMBUS_TMR_STD_SU)
    165 		| SMBUS_TMR_CL_SET(SMBUS_TMR_STD_CL)
    166 		| SMBUS_TMR_CH_SET(SMBUS_TMR_STD_CH);
    167 	ausmbus_reg_write(sc, AUPSC_SMBTMR, v);
    168 
    169 	/* Setup SMBus Mask register */
    170 	v = SMBUS_MSK_ALLMASK;
    171 	ausmbus_reg_write(sc, AUPSC_SMBMSK, v);
    172 
    173 	/* SMBus Enable */
    174 	v = ausmbus_reg_read(sc, AUPSC_SMBCFG);
    175 	v |= SMBUS_CFG_DE;
    176 	ausmbus_reg_write(sc, AUPSC_SMBCFG, v);
    177 	v = ausmbus_reg_read(sc, AUPSC_SMBSTAT);
    178 	if ((v & SMBUS_STAT_SR) == 0) {
    179 		/* SMBus is not ready */
    180 		return -1;
    181 	}
    182 
    183 #ifdef AUSMBUS_PSC_DEBUG
    184 	aprint_normal("AuSMBus enabled.\n");
    185 	aprint_normal("AuSMBus smbconfig: 0x%08x\n",
    186 			ausmbus_reg_read(sc, AUPSC_SMBCFG));
    187 	aprint_normal("AuSMBus smbstatus: 0x%08x\n",
    188 			ausmbus_reg_read(sc, AUPSC_SMBSTAT));
    189 	aprint_normal("AuSMBus smbtmr   : 0x%08x\n",
    190 			ausmbus_reg_read(sc, AUPSC_SMBTMR));
    191 	aprint_normal("AuSMBus smbmask  : 0x%08x\n",
    192 			ausmbus_reg_read(sc, AUPSC_SMBMSK));
    193 #endif
    194 
    195 	return 0;
    196 }
    197 
    198 static void
    199 ausmbus_release_bus(void *arg, int flags)
    200 {
    201 	struct ausmbus_softc *sc = arg;
    202 
    203 	ausmbus_reg_write(sc, AUPSC_SMBCFG, 0);
    204 	sc->sc_ctrl.psc_disable(sc);
    205 
    206 	return;
    207 }
    208 
    209 static int
    210 ausmbus_exec(void *cookie, i2c_op_t op, i2c_addr_t addr, const void *vcmd,
    211 	size_t cmdlen, void *vbuf, size_t buflen, int flags)
    212 {
    213 	struct ausmbus_softc *sc  = (struct ausmbus_softc *)cookie;
    214 	const uint8_t *cmd = vcmd;
    215 	uint8_t *buf = vbuf;
    216 
    217 	sc->sc_smbus_slave_addr  = addr;
    218 
    219 	/* Receive byte */
    220 	if ((I2C_OP_READ_P(op)) && (cmdlen == 0) && (buflen == 1)) {
    221 		return ausmbus_receive_1(sc, buf);
    222 	}
    223 
    224 	/* Read byte */
    225 	if ((I2C_OP_READ_P(op)) && (cmdlen == 1) && (buflen == 1)) {
    226 		return ausmbus_read_1(sc, *cmd, buf);
    227 	}
    228 
    229 	/* Send byte */
    230 	if ((I2C_OP_WRITE_P(op)) && (cmdlen == 0) && (buflen == 1)) {
    231 		return ausmbus_send_1(sc, *buf);
    232 	}
    233 
    234 	/* Write byte */
    235 	if ((I2C_OP_WRITE_P(op)) && (cmdlen == 1) && (buflen == 1)) {
    236 		return ausmbus_write_1(sc, *cmd, *buf);
    237 	}
    238 
    239 	/*
    240 	 * XXX: TODO Please Support other protocols defined in SMBus 2.0
    241 	 * - Quick Command
    242 	 * - Write word
    243 	 * - Read word
    244 	 * - Process call
    245 	 * - Block write/read
    246 	 * - Clock write-block read process cal
    247 	 * - SMBus host notify protocol
    248 	 */
    249 
    250 	return -1;
    251 }
    252 
    253 static int
    254 ausmbus_receive_1(struct ausmbus_softc *sc, uint8_t *vp)
    255 {
    256 	int error;
    257 
    258 	error = ausmbus_initiate_xfer(sc, sc->sc_smbus_slave_addr, I2C_F_READ);
    259 	if (error != 0) {
    260 		return error;
    261 	}
    262 	error = ausmbus_read_byte(sc, vp, I2C_F_STOP);
    263 	if (error != 0) {
    264 		return error;
    265 	}
    266 
    267 	return 0;
    268 }
    269 
    270 static int
    271 ausmbus_read_1(struct ausmbus_softc *sc, uint8_t cmd, uint8_t *vp)
    272 {
    273 	int error;
    274 
    275 	error = ausmbus_initiate_xfer(sc, sc->sc_smbus_slave_addr, I2C_F_WRITE);
    276 	if (error != 0) {
    277 		return error;
    278 	}
    279 
    280 	error = ausmbus_write_byte(sc, cmd, I2C_F_READ);
    281 	if (error != 0) {
    282 		return error;
    283 	}
    284 
    285 	error = ausmbus_initiate_xfer(sc, sc->sc_smbus_slave_addr, I2C_F_READ);
    286 	if (error != 0) {
    287 		return error;
    288 	}
    289 
    290 	error = ausmbus_read_byte(sc, vp, I2C_F_STOP);
    291 	if (error != 0) {
    292 		return error;
    293 	}
    294 
    295 	return 0;
    296 }
    297 
    298 static int
    299 ausmbus_send_1(struct ausmbus_softc *sc, uint8_t val)
    300 {
    301 	int error;
    302 
    303 	error = ausmbus_initiate_xfer(sc, sc->sc_smbus_slave_addr, I2C_F_WRITE);
    304 	if (error != 0) {
    305 		return error;
    306 	}
    307 
    308 	error = ausmbus_write_byte(sc, val, I2C_F_STOP);
    309 	if (error != 0) {
    310 		return error;
    311 	}
    312 
    313 	return 0;
    314 }
    315 
    316 static int
    317 ausmbus_write_1(struct ausmbus_softc *sc, uint8_t cmd, uint8_t val)
    318 {
    319 	int error;
    320 
    321 	error = ausmbus_initiate_xfer(sc, sc->sc_smbus_slave_addr, I2C_F_WRITE);
    322 	if (error != 0) {
    323 		return error;
    324 	}
    325 
    326 	error = ausmbus_write_byte(sc, cmd, 0);
    327 	if (error != 0) {
    328 		return error;
    329 	}
    330 
    331 	error = ausmbus_write_byte(sc, val, I2C_F_STOP);
    332 	if (error != 0) {
    333 		return error;
    334 	}
    335 
    336 	return 0;
    337 }
    338 
    339 static int
    340 ausmbus_wait_mastertx(struct ausmbus_softc *sc)
    341 {
    342 	uint32_t v;
    343 	int timeout;
    344 	int txerr = 0;
    345 
    346 	timeout = sc->sc_smbus_timeout;
    347 
    348 	do {
    349 		v = ausmbus_reg_read(sc, AUPSC_SMBEVNT);
    350 #ifdef AUSMBUS_PSC_DEBUG
    351 		aprint_normal("AuSMBus: ausmbus_wait_mastertx(): psc_smbevnt=0x%08x\n", v);
    352 #endif
    353 		if ((v & SMBUS_EVNT_TU) != 0)
    354 			break;
    355 		if ((v & SMBUS_EVNT_MD) != 0)
    356 			break;
    357 		if ((v & (SMBUS_EVNT_DN | SMBUS_EVNT_AN | SMBUS_EVNT_AL))
    358 			!= 0) {
    359 			txerr = 1;
    360 			break;
    361 		}
    362 		timeout--;
    363 		delay(1);
    364 	} while (timeout > 0);
    365 
    366 	if (txerr != 0) {
    367 		ausmbus_reg_write(sc, AUPSC_SMBEVNT,
    368 			SMBUS_EVNT_DN | SMBUS_EVNT_AN | SMBUS_EVNT_AL);
    369 #ifdef AUSMBUS_PSC_DEBUG
    370 		aprint_normal("AuSMBus: ausmbus_wait_mastertx(): Tx error\n");
    371 #endif
    372 		return -1;
    373 	}
    374 
    375 	/* Reset Event TU (Tx Underflow) */
    376 	ausmbus_reg_write(sc, AUPSC_SMBEVNT, SMBUS_EVNT_TU | SMBUS_EVNT_MD);
    377 
    378 #ifdef AUSMBUS_PSC_DEBUG
    379 	v = ausmbus_reg_read(sc, AUPSC_SMBEVNT);
    380 	aprint_normal("AuSMBus: ausmbus_wait_mastertx(): psc_smbevnt=0x%08x (reset)\n", v);
    381 #endif
    382 	return 0;
    383 }
    384 
    385 static int
    386 ausmbus_wait_masterrx(struct ausmbus_softc *sc)
    387 {
    388 	uint32_t v;
    389 	int timeout;
    390 	timeout = sc->sc_smbus_timeout;
    391 
    392 	if (ausmbus_wait_mastertx(sc) != 0)
    393 		return -1;
    394 
    395 	do {
    396 		v = ausmbus_reg_read(sc, AUPSC_SMBSTAT);
    397 #ifdef AUSMBUS_PSC_DEBUG
    398 		aprint_normal("AuSMBus: ausmbus_wait_masterrx(): psc_smbstat=0x%08x\n", v);
    399 #endif
    400 		if ((v & SMBUS_STAT_RE) == 0)
    401 			break;
    402 		timeout--;
    403 		delay(1);
    404 	} while (timeout > 0);
    405 
    406 	return 0;
    407 }
    408 
    409 static int
    410 ausmbus_initiate_xfer(void *arg, i2c_addr_t addr, int flags)
    411 {
    412 	struct ausmbus_softc *sc = arg;
    413 	uint32_t v;
    414 
    415 	/* Tx/Rx Slave Address */
    416 	v = (addr << 1) & SMBUS_TXRX_ADDRDATA;
    417 	if ((flags & I2C_F_READ) != 0)
    418 		v |= 1;
    419 	ausmbus_reg_write(sc, AUPSC_SMBTXRX, v);
    420 
    421 	/* Master Start */
    422 	ausmbus_reg_write(sc, AUPSC_SMBPCR, SMBUS_PCR_MS);
    423 
    424 	if (ausmbus_wait_mastertx(sc) != 0)
    425 		return -1;
    426 
    427 	return 0;
    428 }
    429 
    430 static int
    431 ausmbus_read_byte(void *arg, uint8_t *vp, int flags)
    432 {
    433 	struct ausmbus_softc *sc = arg;
    434 	uint32_t v;
    435 
    436 	if ((flags & I2C_F_STOP) != 0) {
    437 		ausmbus_reg_write(sc, AUPSC_SMBTXRX, SMBUS_TXRX_STP);
    438 	} else {
    439 		ausmbus_reg_write(sc, AUPSC_SMBTXRX, 0);
    440 	}
    441 
    442 	if (ausmbus_wait_masterrx(sc) != 0)
    443 		return -1;
    444 
    445 	v = ausmbus_reg_read(sc, AUPSC_SMBTXRX);
    446 	*vp = v & SMBUS_TXRX_ADDRDATA;
    447 
    448 	return 0;
    449 }
    450 
    451 static int
    452 ausmbus_write_byte(void *arg, uint8_t v, int flags)
    453 {
    454 	struct ausmbus_softc *sc = arg;
    455 
    456 	if ((flags & I2C_F_STOP) != 0)  {
    457 		ausmbus_reg_write(sc, AUPSC_SMBTXRX, (v | SMBUS_TXRX_STP));
    458 	} else if ((flags & I2C_F_READ) != 0) {
    459 		ausmbus_reg_write(sc, AUPSC_SMBTXRX, (v | SMBUS_TXRX_RSR));
    460 	} else {
    461 		ausmbus_reg_write(sc, AUPSC_SMBTXRX, v);
    462 	}
    463 
    464 	if (ausmbus_wait_mastertx(sc) != 0)
    465 		return -1;
    466 
    467 	return 0;
    468 }
    469