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