1 /* $NetBSD: ausmbus_psc.c,v 1.8 2007/10/17 19:55:35 garbled 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.8 2007/10/17 19:55:35 garbled 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, \ 71 val); \ 72 delay(100); 73 74 static int ausmbus_match(struct device *, struct cfdata *, void *); 75 static void ausmbus_attach(struct device *, struct device *, void *); 76 77 CFATTACH_DECL(ausmbus, sizeof(struct ausmbus_softc), 78 ausmbus_match, ausmbus_attach, NULL, NULL); 79 80 /* fuctions for i2c_controller */ 81 static int ausmbus_acquire_bus(void *, int); 82 static void ausmbus_release_bus(void *, int); 83 static int ausmbus_exec(void *cookie, i2c_op_t op, i2c_addr_t addr, 84 const void *cmd, size_t cmdlen, void *vbuf, 85 size_t buflen, int flags); 86 87 /* subroutine functions for i2c_controller */ 88 static int ausmbus_receive_1(struct ausmbus_softc *, uint8_t *); 89 static int ausmbus_read_1(struct ausmbus_softc *, uint8_t, uint8_t *); 90 static int ausmbus_read_2(struct ausmbus_softc *, uint8_t, uint16_t *); 91 static int ausmbus_send_1(struct ausmbus_softc *, uint8_t); 92 static int ausmbus_write_1(struct ausmbus_softc *, uint8_t, uint8_t); 93 static int ausmbus_write_2(struct ausmbus_softc *, uint8_t, uint16_t); 94 static int ausmbus_wait_mastertx(struct ausmbus_softc *sc); 95 static int ausmbus_wait_masterrx(struct ausmbus_softc *sc); 96 static int ausmbus_initiate_xfer(void *, i2c_addr_t, int); 97 static int ausmbus_read_byte(void *arg, uint8_t *vp, int flags); 98 static int ausmbus_write_byte(void *arg, uint8_t v, int flags); 99 100 101 static int 102 ausmbus_match(struct device *parent, struct cfdata *cf, void *aux) 103 { 104 struct aupsc_attach_args *aa = (struct aupsc_attach_args *)aux; 105 106 if (strcmp(aa->aupsc_name, cf->cf_name) != 0) 107 return 0; 108 109 return 1; 110 } 111 112 static void 113 ausmbus_attach(struct device *parent, struct device *self, void *aux) 114 { 115 struct ausmbus_softc *sc = (struct ausmbus_softc *)self; 116 struct aupsc_attach_args *aa = (struct aupsc_attach_args *)aux; 117 struct i2cbus_attach_args iba; 118 119 aprint_normal(": Alchemy PSC SMBus protocol\n"); 120 121 /* Initialize PSC */ 122 sc->sc_ctrl = aa->aupsc_ctrl; 123 124 /* Initialize i2c_controller for SMBus */ 125 sc->sc_i2c.ic_cookie = sc; 126 sc->sc_i2c.ic_acquire_bus = ausmbus_acquire_bus; 127 sc->sc_i2c.ic_release_bus = ausmbus_release_bus; 128 sc->sc_i2c.ic_send_start = NULL; 129 sc->sc_i2c.ic_send_stop = NULL; 130 sc->sc_i2c.ic_initiate_xfer = NULL; 131 sc->sc_i2c.ic_read_byte = NULL; 132 sc->sc_i2c.ic_write_byte = NULL; 133 sc->sc_i2c.ic_exec = ausmbus_exec; 134 sc->sc_smbus_timeout = 10; 135 136 iba.iba_tag = &sc->sc_i2c; 137 (void) config_found_ia(&sc->sc_dev, "i2cbus", &iba, iicbus_print); 138 } 139 140 static int 141 ausmbus_acquire_bus(void *arg, int flags) 142 { 143 struct ausmbus_softc *sc = arg; 144 uint32_t v; 145 146 /* Select SMBus Protocol & Enable PSC */ 147 sc->sc_ctrl.psc_enable(sc, AUPSC_SEL_SMBUS); 148 v = ausmbus_reg_read(sc, AUPSC_SMBSTAT); 149 if ((v & SMBUS_STAT_SR) == 0) { 150 /* PSC is not ready */ 151 return -1; 152 } 153 154 /* Setup SMBus Configuration register */ 155 v = SMBUS_CFG_DD; /* Disable DMA */ 156 v |= SMBUS_CFG_RT_SET(SMBUS_CFG_RT_FIFO8); /* Rx FIFO 8data */ 157 v |= SMBUS_CFG_TT_SET(SMBUS_CFG_TT_FIFO8); /* Tx FIFO 8data */ 158 v |= SMBUS_CFG_DIV_SET(SMBUS_CFG_DIV8); /* pscn_mainclk/8 */ 159 v &= ~SMBUS_CFG_SFM; /* Standard Mode */ 160 ausmbus_reg_write(sc, AUPSC_SMBCFG, v); 161 162 /* Setup SMBus Protocol Timing register */ 163 v = SMBUS_TMR_TH_SET(SMBUS_TMR_STD_TH) 164 | SMBUS_TMR_PS_SET(SMBUS_TMR_STD_PS) 165 | SMBUS_TMR_PU_SET(SMBUS_TMR_STD_PU) 166 | SMBUS_TMR_SH_SET(SMBUS_TMR_STD_SH) 167 | SMBUS_TMR_SU_SET(SMBUS_TMR_STD_SU) 168 | SMBUS_TMR_CL_SET(SMBUS_TMR_STD_CL) 169 | SMBUS_TMR_CH_SET(SMBUS_TMR_STD_CH); 170 ausmbus_reg_write(sc, AUPSC_SMBTMR, v); 171 172 /* Setup SMBus Mask register */ 173 v = SMBUS_MSK_ALLMASK; 174 ausmbus_reg_write(sc, AUPSC_SMBMSK, v); 175 176 /* SMBus Enable */ 177 v = ausmbus_reg_read(sc, AUPSC_SMBCFG); 178 v |= SMBUS_CFG_DE; 179 ausmbus_reg_write(sc, AUPSC_SMBCFG, v); 180 v = ausmbus_reg_read(sc, AUPSC_SMBSTAT); 181 if ((v & SMBUS_STAT_SR) == 0) { 182 /* SMBus is not ready */ 183 return -1; 184 } 185 186 #ifdef AUSMBUS_PSC_DEBUG 187 aprint_normal("AuSMBus enabled.\n"); 188 aprint_normal("AuSMBus smbconfig: 0x%08x\n", 189 ausmbus_reg_read(sc, AUPSC_SMBCFG)); 190 aprint_normal("AuSMBus smbstatus: 0x%08x\n", 191 ausmbus_reg_read(sc, AUPSC_SMBSTAT)); 192 aprint_normal("AuSMBus smbtmr : 0x%08x\n", 193 ausmbus_reg_read(sc, AUPSC_SMBTMR)); 194 aprint_normal("AuSMBus smbmask : 0x%08x\n", 195 ausmbus_reg_read(sc, AUPSC_SMBMSK)); 196 #endif 197 198 return 0; 199 } 200 201 static void 202 ausmbus_release_bus(void *arg, int flags) 203 { 204 struct ausmbus_softc *sc = arg; 205 206 ausmbus_reg_write(sc, AUPSC_SMBCFG, 0); 207 sc->sc_ctrl.psc_disable(sc); 208 209 return; 210 } 211 212 static int 213 ausmbus_exec(void *cookie, i2c_op_t op, i2c_addr_t addr, const void *vcmd, 214 size_t cmdlen, void *vbuf, size_t buflen, int flags) 215 { 216 struct ausmbus_softc *sc = (struct ausmbus_softc *)cookie; 217 const uint8_t *cmd = vcmd; 218 219 sc->sc_smbus_slave_addr = addr; 220 221 /* Receive byte */ 222 if ((I2C_OP_READ_P(op)) && (cmdlen == 0) && (buflen == 1)) { 223 return ausmbus_receive_1(sc, (uint8_t *)vbuf); 224 } 225 226 /* Read byte */ 227 if ((I2C_OP_READ_P(op)) && (cmdlen == 1) && (buflen == 1)) { 228 return ausmbus_read_1(sc, *cmd, (uint8_t *)vbuf); 229 } 230 231 /* Read word */ 232 if ((I2C_OP_READ_P(op)) && (cmdlen == 1) && (buflen == 2)) { 233 return ausmbus_read_2(sc, *cmd, (uint16_t *)vbuf); 234 } 235 236 /* Send byte */ 237 if ((I2C_OP_WRITE_P(op)) && (cmdlen == 0) && (buflen == 1)) { 238 return ausmbus_send_1(sc, *((uint8_t *)vbuf)); 239 } 240 241 /* Write byte */ 242 if ((I2C_OP_WRITE_P(op)) && (cmdlen == 1) && (buflen == 1)) { 243 return ausmbus_write_1(sc, *cmd, *((uint8_t *)vbuf)); 244 } 245 246 /* Write word */ 247 if ((I2C_OP_WRITE_P(op)) && (cmdlen == 1) && (buflen == 2)) { 248 return ausmbus_write_2(sc, *cmd, *((uint16_t *)vbuf)); 249 } 250 251 /* 252 * XXX: TODO Please Support other protocols defined in SMBus 2.0 253 * - Quick Command 254 * - Process call 255 * - Block write/read 256 * - Clock write-block read process cal 257 * - SMBus host notify protocol 258 */ 259 260 return -1; 261 } 262 263 static int 264 ausmbus_receive_1(struct ausmbus_softc *sc, uint8_t *vp) 265 { 266 int error; 267 268 error = ausmbus_initiate_xfer(sc, sc->sc_smbus_slave_addr, I2C_F_READ); 269 if (error != 0) { 270 return error; 271 } 272 error = ausmbus_read_byte(sc, vp, I2C_F_STOP); 273 if (error != 0) { 274 return error; 275 } 276 277 return 0; 278 } 279 280 static int 281 ausmbus_read_1(struct ausmbus_softc *sc, uint8_t cmd, uint8_t *vp) 282 { 283 int error; 284 285 error = ausmbus_initiate_xfer(sc, sc->sc_smbus_slave_addr, I2C_F_WRITE); 286 if (error != 0) { 287 return error; 288 } 289 290 error = ausmbus_write_byte(sc, cmd, I2C_F_READ); 291 if (error != 0) { 292 return error; 293 } 294 295 error = ausmbus_initiate_xfer(sc, sc->sc_smbus_slave_addr, I2C_F_READ); 296 if (error != 0) { 297 return error; 298 } 299 300 error = ausmbus_read_byte(sc, vp, I2C_F_STOP); 301 if (error != 0) { 302 return error; 303 } 304 305 return 0; 306 } 307 308 static int 309 ausmbus_read_2(struct ausmbus_softc *sc, uint8_t cmd, uint16_t *vp) 310 { 311 int error; 312 uint8_t high, low; 313 314 error = ausmbus_initiate_xfer(sc, sc->sc_smbus_slave_addr, I2C_F_WRITE); 315 if (error != 0) { 316 return error; 317 } 318 319 error = ausmbus_write_byte(sc, cmd, I2C_F_READ); 320 if (error != 0) { 321 return error; 322 } 323 324 error = ausmbus_initiate_xfer(sc, sc->sc_smbus_slave_addr, I2C_F_READ); 325 if (error != 0) { 326 return error; 327 } 328 329 error = ausmbus_read_byte(sc, &low, 0); 330 if (error != 0) { 331 return error; 332 } 333 334 error = ausmbus_read_byte(sc, &high, I2C_F_STOP); 335 if (error != 0) { 336 return error; 337 } 338 339 *vp = (high << 8) | low; 340 341 return 0; 342 } 343 344 static int 345 ausmbus_send_1(struct ausmbus_softc *sc, uint8_t val) 346 { 347 int error; 348 349 error = ausmbus_initiate_xfer(sc, sc->sc_smbus_slave_addr, I2C_F_WRITE); 350 if (error != 0) { 351 return error; 352 } 353 354 error = ausmbus_write_byte(sc, val, I2C_F_STOP); 355 if (error != 0) { 356 return error; 357 } 358 359 return 0; 360 } 361 362 static int 363 ausmbus_write_1(struct ausmbus_softc *sc, uint8_t cmd, uint8_t val) 364 { 365 int error; 366 367 error = ausmbus_initiate_xfer(sc, sc->sc_smbus_slave_addr, I2C_F_WRITE); 368 if (error != 0) { 369 return error; 370 } 371 372 error = ausmbus_write_byte(sc, cmd, 0); 373 if (error != 0) { 374 return error; 375 } 376 377 error = ausmbus_write_byte(sc, val, I2C_F_STOP); 378 if (error != 0) { 379 return error; 380 } 381 382 return 0; 383 } 384 385 static int 386 ausmbus_write_2(struct ausmbus_softc *sc, uint8_t cmd, uint16_t val) 387 { 388 int error; 389 uint8_t high, low; 390 391 high = (val >> 8) & 0xff; 392 low = val & 0xff; 393 394 error = ausmbus_initiate_xfer(sc, sc->sc_smbus_slave_addr, I2C_F_WRITE); 395 if (error != 0) { 396 return error; 397 } 398 399 error = ausmbus_write_byte(sc, cmd, 0); 400 if (error != 0) { 401 return error; 402 } 403 404 error = ausmbus_write_byte(sc, low, 0); 405 if (error != 0) { 406 return error; 407 } 408 409 error = ausmbus_write_byte(sc, high, I2C_F_STOP); 410 if (error != 0) { 411 return error; 412 } 413 414 return 0; 415 } 416 417 static int 418 ausmbus_wait_mastertx(struct ausmbus_softc *sc) 419 { 420 uint32_t v; 421 int timeout; 422 int txerr = 0; 423 424 timeout = sc->sc_smbus_timeout; 425 426 do { 427 v = ausmbus_reg_read(sc, AUPSC_SMBEVNT); 428 #ifdef AUSMBUS_PSC_DEBUG 429 aprint_normal("AuSMBus: ausmbus_wait_mastertx(): psc_smbevnt=0x%08x\n", v); 430 #endif 431 if ((v & SMBUS_EVNT_TU) != 0) 432 break; 433 if ((v & SMBUS_EVNT_MD) != 0) 434 break; 435 if ((v & (SMBUS_EVNT_DN | SMBUS_EVNT_AN | SMBUS_EVNT_AL)) 436 != 0) { 437 txerr = 1; 438 break; 439 } 440 timeout--; 441 delay(1); 442 } while (timeout > 0); 443 444 if (txerr != 0) { 445 ausmbus_reg_write(sc, AUPSC_SMBEVNT, 446 SMBUS_EVNT_DN | SMBUS_EVNT_AN | SMBUS_EVNT_AL); 447 #ifdef AUSMBUS_PSC_DEBUG 448 aprint_normal("AuSMBus: ausmbus_wait_mastertx(): Tx error\n"); 449 #endif 450 return -1; 451 } 452 453 /* Reset Event TU (Tx Underflow) */ 454 ausmbus_reg_write(sc, AUPSC_SMBEVNT, SMBUS_EVNT_TU | SMBUS_EVNT_MD); 455 456 #ifdef AUSMBUS_PSC_DEBUG 457 v = ausmbus_reg_read(sc, AUPSC_SMBEVNT); 458 aprint_normal("AuSMBus: ausmbus_wait_mastertx(): psc_smbevnt=0x%08x (reset)\n", v); 459 #endif 460 return 0; 461 } 462 463 static int 464 ausmbus_wait_masterrx(struct ausmbus_softc *sc) 465 { 466 uint32_t v; 467 int timeout; 468 timeout = sc->sc_smbus_timeout; 469 470 if (ausmbus_wait_mastertx(sc) != 0) 471 return -1; 472 473 do { 474 v = ausmbus_reg_read(sc, AUPSC_SMBSTAT); 475 #ifdef AUSMBUS_PSC_DEBUG 476 aprint_normal("AuSMBus: ausmbus_wait_masterrx(): psc_smbstat=0x%08x\n", v); 477 #endif 478 if ((v & SMBUS_STAT_RE) == 0) 479 break; 480 timeout--; 481 delay(1); 482 } while (timeout > 0); 483 484 return 0; 485 } 486 487 static int 488 ausmbus_initiate_xfer(void *arg, i2c_addr_t addr, int flags) 489 { 490 struct ausmbus_softc *sc = arg; 491 uint32_t v; 492 493 /* Tx/Rx Slave Address */ 494 v = (addr << 1) & SMBUS_TXRX_ADDRDATA; 495 if ((flags & I2C_F_READ) != 0) 496 v |= 1; 497 ausmbus_reg_write(sc, AUPSC_SMBTXRX, v); 498 499 /* Master Start */ 500 ausmbus_reg_write(sc, AUPSC_SMBPCR, SMBUS_PCR_MS); 501 502 if (ausmbus_wait_mastertx(sc) != 0) 503 return -1; 504 505 return 0; 506 } 507 508 static int 509 ausmbus_read_byte(void *arg, uint8_t *vp, int flags) 510 { 511 struct ausmbus_softc *sc = arg; 512 uint32_t v; 513 514 if ((flags & I2C_F_STOP) != 0) { 515 ausmbus_reg_write(sc, AUPSC_SMBTXRX, SMBUS_TXRX_STP); 516 } else { 517 ausmbus_reg_write(sc, AUPSC_SMBTXRX, 0); 518 } 519 520 if (ausmbus_wait_masterrx(sc) != 0) 521 return -1; 522 523 v = ausmbus_reg_read(sc, AUPSC_SMBTXRX); 524 *vp = v & SMBUS_TXRX_ADDRDATA; 525 526 return 0; 527 } 528 529 static int 530 ausmbus_write_byte(void *arg, uint8_t v, int flags) 531 { 532 struct ausmbus_softc *sc = arg; 533 534 if ((flags & I2C_F_STOP) != 0) { 535 ausmbus_reg_write(sc, AUPSC_SMBTXRX, (v | SMBUS_TXRX_STP)); 536 } else if ((flags & I2C_F_READ) != 0) { 537 ausmbus_reg_write(sc, AUPSC_SMBTXRX, (v | SMBUS_TXRX_RSR)); 538 } else { 539 ausmbus_reg_write(sc, AUPSC_SMBTXRX, v); 540 } 541 542 if (ausmbus_wait_mastertx(sc) != 0) 543 return -1; 544 545 return 0; 546 } 547