17e6fb56fSmrg/* 2983b4bf2Smrg * Copyright 2009 Luc Verhaegen. 37e6fb56fSmrg * Copyright 2004 The Unichrome Project [unichrome.sf.net] 47e6fb56fSmrg * Copyright 1998-2003 VIA Technologies, Inc. All Rights Reserved. 57e6fb56fSmrg * Copyright 2001-2003 S3 Graphics, Inc. All Rights Reserved. 67e6fb56fSmrg * 77e6fb56fSmrg * Permission is hereby granted, free of charge, to any person obtaining a 87e6fb56fSmrg * copy of this software and associated documentation files (the "Software"), 97e6fb56fSmrg * to deal in the Software without restriction, including without limitation 107e6fb56fSmrg * the rights to use, copy, modify, merge, publish, distribute, sub license, 117e6fb56fSmrg * and/or sell copies of the Software, and to permit persons to whom the 127e6fb56fSmrg * Software is furnished to do so, subject to the following conditions: 137e6fb56fSmrg * 147e6fb56fSmrg * The above copyright notice and this permission notice (including the 157e6fb56fSmrg * next paragraph) shall be included in all copies or substantial portions 167e6fb56fSmrg * of the Software. 177e6fb56fSmrg * 187e6fb56fSmrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 197e6fb56fSmrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 207e6fb56fSmrg * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL 217e6fb56fSmrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 227e6fb56fSmrg * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 237e6fb56fSmrg * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 247e6fb56fSmrg * DEALINGS IN THE SOFTWARE. 257e6fb56fSmrg */ 267e6fb56fSmrg 277e6fb56fSmrg/* 28963d66acSmrg * Implements three I2C buses through registers SR26, SR2C, and SR31. 297e6fb56fSmrg */ 307e6fb56fSmrg 317e6fb56fSmrg#ifdef HAVE_CONFIG_H 327e6fb56fSmrg#include "config.h" 337e6fb56fSmrg#endif 347e6fb56fSmrg 357e6fb56fSmrg#include "via_driver.h" 367e6fb56fSmrg 377e6fb56fSmrg#define SDA_READ 0x04 387e6fb56fSmrg#define SCL_READ 0x08 397e6fb56fSmrg#define SDA_WRITE 0x10 407e6fb56fSmrg#define SCL_WRITE 0x20 417e6fb56fSmrg 427e6fb56fSmrg/* 43963d66acSmrg * First I2C Bus: Typically used for detecting a VGA monitor. 447e6fb56fSmrg */ 457e6fb56fSmrgstatic void 467e6fb56fSmrgViaI2C1PutBits(I2CBusPtr Bus, int clock, int data) 477e6fb56fSmrg{ 4890b17f1bSmrg vgaHWPtr hwp = Bus->DriverPrivate.ptr; 497e6fb56fSmrg CARD8 value = 0x01; /* Enable */ 507e6fb56fSmrg 517e6fb56fSmrg if (clock) 527e6fb56fSmrg value |= SCL_WRITE; 537e6fb56fSmrg 547e6fb56fSmrg if (data) 557e6fb56fSmrg value |= SDA_WRITE; 567e6fb56fSmrg 577e6fb56fSmrg ViaSeqMask(hwp, 0x26, value, 0x01 | SCL_WRITE | SDA_WRITE); 587e6fb56fSmrg} 597e6fb56fSmrg 607e6fb56fSmrgstatic void 617e6fb56fSmrgViaI2C1GetBits(I2CBusPtr Bus, int *clock, int *data) 627e6fb56fSmrg{ 6390b17f1bSmrg vgaHWPtr hwp = Bus->DriverPrivate.ptr; 647e6fb56fSmrg CARD8 value = hwp->readSeq(hwp, 0x26); 657e6fb56fSmrg 667e6fb56fSmrg *clock = (value & SCL_READ) != 0; 677e6fb56fSmrg *data = (value & SDA_READ) != 0; 687e6fb56fSmrg} 697e6fb56fSmrg 707e6fb56fSmrgstatic I2CBusPtr 7190b17f1bSmrgViaI2CBus1Init(ScrnInfoPtr pScrn) 727e6fb56fSmrg{ 73963d66acSmrg DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, 74963d66acSmrg "Entered ViaI2CBus1Init.\n")); 75963d66acSmrg 767e6fb56fSmrg I2CBusPtr pI2CBus = xf86CreateI2CBusRec(); 7790b17f1bSmrg vgaHWPtr hwp = VGAHWPTR(pScrn); 787e6fb56fSmrg 79963d66acSmrg if (!pI2CBus) { 80963d66acSmrg DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_ERROR, 81963d66acSmrg "xf86CreateI2CBusRec failed.\n")); 82963d66acSmrg xf86DrvMsg(pScrn->scrnIndex, X_ERROR, 83963d66acSmrg "Initialization of I2C Bus 1 failed.\n"); 84963d66acSmrg DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, 85963d66acSmrg "Exiting ViaI2CBus1Init.\n")); 867e6fb56fSmrg return NULL; 87963d66acSmrg } 887e6fb56fSmrg 89963d66acSmrg pI2CBus->BusName = "I2C Bus 1"; 9090b17f1bSmrg pI2CBus->scrnIndex = pScrn->scrnIndex; 917e6fb56fSmrg pI2CBus->I2CPutBits = ViaI2C1PutBits; 927e6fb56fSmrg pI2CBus->I2CGetBits = ViaI2C1GetBits; 9390b17f1bSmrg pI2CBus->DriverPrivate.ptr = hwp; 9490b17f1bSmrg pI2CBus->ByteTimeout = 2200; 9590b17f1bSmrg pI2CBus->StartTimeout = 550; 9690b17f1bSmrg pI2CBus->HoldTime = 40; 9790b17f1bSmrg pI2CBus->BitTimeout = 40; 987e6fb56fSmrg 997e6fb56fSmrg if (!xf86I2CBusInit(pI2CBus)) { 100963d66acSmrg DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_ERROR, 101963d66acSmrg "xf86I2CBusInit failed.\n")); 1027e6fb56fSmrg xf86DestroyI2CBusRec(pI2CBus, TRUE, FALSE); 103963d66acSmrg xf86DrvMsg(pScrn->scrnIndex, X_ERROR, 104963d66acSmrg "Initialization of I2C Bus 1 failed.\n"); 105963d66acSmrg DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, 106963d66acSmrg "Exiting ViaI2CBus1Init.\n")); 1077e6fb56fSmrg return NULL; 1087e6fb56fSmrg } 109963d66acSmrg 110963d66acSmrg DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, 111963d66acSmrg "Exiting ViaI2CBus1Init.\n")); 1127e6fb56fSmrg return pI2CBus; 1137e6fb56fSmrg} 1147e6fb56fSmrg 1157e6fb56fSmrg/* 116963d66acSmrg * Second I2C Bus: Used to detect a DVI monitor, VGA monitor via 117963d66acSmrg * a DVI-I connector, or TV encoders. 1187e6fb56fSmrg */ 1197e6fb56fSmrgstatic void 1207e6fb56fSmrgViaI2C2PutBits(I2CBusPtr Bus, int clock, int data) 1217e6fb56fSmrg{ 12290b17f1bSmrg vgaHWPtr hwp = Bus->DriverPrivate.ptr; 1237e6fb56fSmrg CARD8 value = 0x01; /* Enable */ 1247e6fb56fSmrg 1257e6fb56fSmrg if (clock) 1267e6fb56fSmrg value |= SCL_WRITE; 1277e6fb56fSmrg 1287e6fb56fSmrg if (data) 1297e6fb56fSmrg value |= SDA_WRITE; 1307e6fb56fSmrg 1317e6fb56fSmrg ViaSeqMask(hwp, 0x31, value, 0x01 | SCL_WRITE | SDA_WRITE); 1327e6fb56fSmrg} 1337e6fb56fSmrg 1347e6fb56fSmrgstatic void 1357e6fb56fSmrgViaI2C2GetBits(I2CBusPtr Bus, int *clock, int *data) 1367e6fb56fSmrg{ 13790b17f1bSmrg vgaHWPtr hwp = Bus->DriverPrivate.ptr; 1387e6fb56fSmrg CARD8 value = hwp->readSeq(hwp, 0x31); 1397e6fb56fSmrg 1407e6fb56fSmrg *clock = (value & SCL_READ) != 0; 1417e6fb56fSmrg *data = (value & SDA_READ) != 0; 1427e6fb56fSmrg} 1437e6fb56fSmrg 1447e6fb56fSmrgstatic I2CBusPtr 14590b17f1bSmrgViaI2CBus2Init(ScrnInfoPtr pScrn) 1467e6fb56fSmrg{ 147963d66acSmrg DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, 148963d66acSmrg "Entered ViaI2CBus2Init.\n")); 149963d66acSmrg 1507e6fb56fSmrg I2CBusPtr pI2CBus = xf86CreateI2CBusRec(); 15190b17f1bSmrg vgaHWPtr hwp = VGAHWPTR(pScrn); 1527e6fb56fSmrg 153963d66acSmrg if (!pI2CBus) { 154963d66acSmrg DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_ERROR, 155963d66acSmrg "xf86CreateI2CBusRec failed.\n")); 156963d66acSmrg xf86DrvMsg(pScrn->scrnIndex, X_ERROR, 157963d66acSmrg "Initialization of I2C Bus 2 failed.\n"); 158963d66acSmrg DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, 159963d66acSmrg "Exiting ViaI2CBus2Init.\n")); 1607e6fb56fSmrg return NULL; 161963d66acSmrg } 1627e6fb56fSmrg 163963d66acSmrg pI2CBus->BusName = "I2C Bus 2"; 16490b17f1bSmrg pI2CBus->scrnIndex = pScrn->scrnIndex; 1657e6fb56fSmrg pI2CBus->I2CPutBits = ViaI2C2PutBits; 1667e6fb56fSmrg pI2CBus->I2CGetBits = ViaI2C2GetBits; 16790b17f1bSmrg pI2CBus->DriverPrivate.ptr = hwp; 1687e6fb56fSmrg 1697e6fb56fSmrg if (!xf86I2CBusInit(pI2CBus)) { 170963d66acSmrg DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_ERROR, 171963d66acSmrg "xf86I2CBusInit failed.\n")); 1727e6fb56fSmrg xf86DestroyI2CBusRec(pI2CBus, TRUE, FALSE); 173963d66acSmrg xf86DrvMsg(pScrn->scrnIndex, X_ERROR, 174963d66acSmrg "Initialization of I2C Bus 2 failed.\n"); 175963d66acSmrg DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, 176963d66acSmrg "Exiting ViaI2CBus2Init.\n")); 1777e6fb56fSmrg return NULL; 1787e6fb56fSmrg } 179963d66acSmrg 180963d66acSmrg DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, 181963d66acSmrg "Exiting ViaI2CBus2Init.\n")); 1827e6fb56fSmrg return pI2CBus; 1837e6fb56fSmrg} 1847e6fb56fSmrg 1857e6fb56fSmrg/* 186963d66acSmrg * Third I2C Bus: Implemented via manipulation of GPIO (General 187963d66acSmrg * Purpose I/O) pins. 1887e6fb56fSmrg */ 1897e6fb56fSmrgstatic Bool 1907e6fb56fSmrgViaI2C3Start(I2CBusPtr b, int timeout) 1917e6fb56fSmrg{ 19290b17f1bSmrg vgaHWPtr hwp = b->DriverPrivate.ptr; 1937e6fb56fSmrg 1947e6fb56fSmrg ViaSeqMask(hwp, 0x2C, 0xF0, 0xF0); 1957e6fb56fSmrg b->I2CUDelay(b, b->RiseFallTime); 1967e6fb56fSmrg 1977e6fb56fSmrg ViaSeqMask(hwp, 0x2C, 0x00, 0x10); 1987e6fb56fSmrg b->I2CUDelay(b, b->HoldTime); 1997e6fb56fSmrg ViaSeqMask(hwp, 0x2C, 0x00, 0x20); 2007e6fb56fSmrg b->I2CUDelay(b, b->HoldTime); 2017e6fb56fSmrg 2027e6fb56fSmrg return TRUE; 2037e6fb56fSmrg} 2047e6fb56fSmrg 2057e6fb56fSmrgstatic Bool 2067e6fb56fSmrgViaI2C3Address(I2CDevPtr d, I2CSlaveAddr addr) 2077e6fb56fSmrg{ 2087e6fb56fSmrg I2CBusPtr b = d->pI2CBus; 2097e6fb56fSmrg 2107e6fb56fSmrg#ifdef X_NEED_I2CSTART 2117e6fb56fSmrg if (b->I2CStart(d->pI2CBus, d->StartTimeout)) { 2127e6fb56fSmrg#else 2137e6fb56fSmrg if (ViaI2C3Start(d->pI2CBus, d->StartTimeout)) { 2147e6fb56fSmrg#endif 2157e6fb56fSmrg if (b->I2CPutByte(d, addr & 0xFF)) { 2167e6fb56fSmrg if ((addr & 0xF8) != 0xF0 && (addr & 0xFE) != 0x00) 2177e6fb56fSmrg return TRUE; 2187e6fb56fSmrg 2197e6fb56fSmrg if (b->I2CPutByte(d, (addr >> 8) & 0xFF)) 2207e6fb56fSmrg return TRUE; 2217e6fb56fSmrg } 2227e6fb56fSmrg 2237e6fb56fSmrg b->I2CStop(d); 2247e6fb56fSmrg } 2257e6fb56fSmrg return FALSE; 2267e6fb56fSmrg} 2277e6fb56fSmrg 2287e6fb56fSmrgstatic void 2297e6fb56fSmrgViaI2C3Stop(I2CDevPtr d) 2307e6fb56fSmrg{ 2317e6fb56fSmrg I2CBusPtr b = d->pI2CBus; 23290b17f1bSmrg vgaHWPtr hwp = b->DriverPrivate.ptr; 2337e6fb56fSmrg 2347e6fb56fSmrg ViaSeqMask(hwp, 0x2C, 0xC0, 0xF0); 2357e6fb56fSmrg b->I2CUDelay(b, b->RiseFallTime); 2367e6fb56fSmrg 2377e6fb56fSmrg ViaSeqMask(hwp, 0x2C, 0x20, 0x20); 2387e6fb56fSmrg b->I2CUDelay(b, b->HoldTime); 2397e6fb56fSmrg 2407e6fb56fSmrg ViaSeqMask(hwp, 0x2C, 0x10, 0x10); 2417e6fb56fSmrg b->I2CUDelay(b, b->HoldTime); 2427e6fb56fSmrg 2437e6fb56fSmrg ViaSeqMask(hwp, 0x2C, 0x00, 0x20); 2447e6fb56fSmrg b->I2CUDelay(b, b->HoldTime); 2457e6fb56fSmrg} 2467e6fb56fSmrg 2477e6fb56fSmrgstatic void 2487e6fb56fSmrgViaI2C3PutBit(I2CBusPtr b, Bool sda, int timeout) 2497e6fb56fSmrg{ 25090b17f1bSmrg vgaHWPtr hwp = b->DriverPrivate.ptr; 2517e6fb56fSmrg 2527e6fb56fSmrg if (sda) 2537e6fb56fSmrg ViaSeqMask(hwp, 0x2C, 0x50, 0x50); 2547e6fb56fSmrg else 2557e6fb56fSmrg ViaSeqMask(hwp, 0x2C, 0x40, 0x50); 2567e6fb56fSmrg b->I2CUDelay(b, b->RiseFallTime / 5); 2577e6fb56fSmrg 2587e6fb56fSmrg ViaSeqMask(hwp, 0x2C, 0xA0, 0xA0); 2597e6fb56fSmrg b->I2CUDelay(b, b->HoldTime); 2607e6fb56fSmrg b->I2CUDelay(b, timeout); 2617e6fb56fSmrg 2627e6fb56fSmrg ViaSeqMask(hwp, 0x2C, 0x80, 0xA0); 2637e6fb56fSmrg b->I2CUDelay(b, b->RiseFallTime / 5); 2647e6fb56fSmrg} 2657e6fb56fSmrg 2667e6fb56fSmrgstatic Bool 2677e6fb56fSmrgViaI2C3PutByte(I2CDevPtr d, I2CByte data) 2687e6fb56fSmrg{ 2697e6fb56fSmrg I2CBusPtr b = d->pI2CBus; 27090b17f1bSmrg vgaHWPtr hwp = b->DriverPrivate.ptr; 2717e6fb56fSmrg Bool ret; 2727e6fb56fSmrg int i; 2737e6fb56fSmrg 2747e6fb56fSmrg for (i = 7; i >= 0; i--) 2757e6fb56fSmrg ViaI2C3PutBit(b, (data >> i) & 0x01, b->BitTimeout); 2767e6fb56fSmrg 2777e6fb56fSmrg /* Raise first to avoid false positives. */ 2787e6fb56fSmrg ViaSeqMask(hwp, 0x2C, 0x50, 0x50); 2797e6fb56fSmrg ViaSeqMask(hwp, 0x2C, 0x00, 0x40); 2807e6fb56fSmrg b->I2CUDelay(b, b->RiseFallTime); 2817e6fb56fSmrg ViaSeqMask(hwp, 0x2C, 0xA0, 0xA0); 2827e6fb56fSmrg 2837e6fb56fSmrg if (hwp->readSeq(hwp, 0x2C) & 0x04) 2847e6fb56fSmrg ret = FALSE; 2857e6fb56fSmrg else 2867e6fb56fSmrg ret = TRUE; 2877e6fb56fSmrg 2887e6fb56fSmrg ViaSeqMask(hwp, 0x2C, 0x80, 0xA0); 2897e6fb56fSmrg b->I2CUDelay(b, b->RiseFallTime); 2907e6fb56fSmrg 2917e6fb56fSmrg return ret; 2927e6fb56fSmrg} 2937e6fb56fSmrg 2947e6fb56fSmrgstatic Bool 2957e6fb56fSmrgViaI2C3GetBit(I2CBusPtr b, int timeout) 2967e6fb56fSmrg{ 29790b17f1bSmrg vgaHWPtr hwp = b->DriverPrivate.ptr; 2987e6fb56fSmrg Bool ret; 2997e6fb56fSmrg 3007e6fb56fSmrg ViaSeqMask(hwp, 0x2c, 0x80, 0xC0); 3017e6fb56fSmrg b->I2CUDelay(b, b->RiseFallTime / 5); 3027e6fb56fSmrg ViaSeqMask(hwp, 0x2c, 0xA0, 0xA0); 3037e6fb56fSmrg b->I2CUDelay(b, 3 * b->HoldTime); 3047e6fb56fSmrg b->I2CUDelay(b, timeout); 3057e6fb56fSmrg 3067e6fb56fSmrg if (hwp->readSeq(hwp, 0x2C) & 0x04) 3077e6fb56fSmrg ret = TRUE; 3087e6fb56fSmrg else 3097e6fb56fSmrg ret = FALSE; 3107e6fb56fSmrg 3117e6fb56fSmrg ViaSeqMask(hwp, 0x2C, 0x80, 0xA0); 3127e6fb56fSmrg b->I2CUDelay(b, b->HoldTime); 3137e6fb56fSmrg b->I2CUDelay(b, b->RiseFallTime / 5); 3147e6fb56fSmrg 3157e6fb56fSmrg return ret; 3167e6fb56fSmrg} 3177e6fb56fSmrg 3187e6fb56fSmrgstatic Bool 3197e6fb56fSmrgViaI2C3GetByte(I2CDevPtr d, I2CByte * data, Bool last) 3207e6fb56fSmrg{ 3217e6fb56fSmrg I2CBusPtr b = d->pI2CBus; 32290b17f1bSmrg vgaHWPtr hwp = b->DriverPrivate.ptr; 3237e6fb56fSmrg int i; 3247e6fb56fSmrg 3257e6fb56fSmrg *data = 0x00; 3267e6fb56fSmrg 3277e6fb56fSmrg for (i = 7; i >= 0; i--) 3287e6fb56fSmrg if (ViaI2C3GetBit(b, b->BitTimeout)) 3297e6fb56fSmrg *data |= 0x01 << i; 3307e6fb56fSmrg 3317e6fb56fSmrg if (last) /* send NACK */ 3327e6fb56fSmrg ViaSeqMask(hwp, 0x2C, 0x50, 0x50); 3337e6fb56fSmrg else /* send ACK */ 3347e6fb56fSmrg ViaSeqMask(hwp, 0x2C, 0x40, 0x50); 3357e6fb56fSmrg 3367e6fb56fSmrg ViaSeqMask(hwp, 0x2C, 0xA0, 0xA0); 3377e6fb56fSmrg b->I2CUDelay(b, b->HoldTime); 3387e6fb56fSmrg 3397e6fb56fSmrg ViaSeqMask(hwp, 0x2C, 0x80, 0xA0); 3407e6fb56fSmrg 3417e6fb56fSmrg return TRUE; 3427e6fb56fSmrg} 3437e6fb56fSmrg 344963d66acSmrgstatic void 345963d66acSmrgViaI2C3SimplePutBits(I2CBusPtr Bus, int clock, int data) 346963d66acSmrg{ 347963d66acSmrg vgaHWPtr hwp = Bus->DriverPrivate.ptr; 348963d66acSmrg CARD8 value = 0xC0; 349963d66acSmrg 350963d66acSmrg if (clock) 351963d66acSmrg value |= SCL_WRITE; 352963d66acSmrg 353963d66acSmrg if (data) 354963d66acSmrg value |= SDA_WRITE; 355963d66acSmrg 356963d66acSmrg ViaSeqMask(hwp, 0x2C, value, 0xC0 | SCL_WRITE | SDA_WRITE); 357963d66acSmrg} 358963d66acSmrg 359963d66acSmrgstatic void 360963d66acSmrgViaI2C3SimpleGetBits(I2CBusPtr Bus, int *clock, int *data) 361963d66acSmrg{ 362963d66acSmrg vgaHWPtr hwp = Bus->DriverPrivate.ptr; 363963d66acSmrg CARD8 value = hwp->readSeq(hwp, 0x2C); 364963d66acSmrg 365963d66acSmrg *clock = (value & SCL_READ) != 0; 366963d66acSmrg *data = (value & SDA_READ) != 0; 367963d66acSmrg} 368963d66acSmrg 3697e6fb56fSmrgstatic I2CBusPtr 37090b17f1bSmrgViaI2CBus3Init(ScrnInfoPtr pScrn) 3717e6fb56fSmrg{ 372963d66acSmrg DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, 373963d66acSmrg "Entered ViaI2CBus3Init.\n")); 374963d66acSmrg 3757e6fb56fSmrg I2CBusPtr pI2CBus = xf86CreateI2CBusRec(); 37690b17f1bSmrg vgaHWPtr hwp = VGAHWPTR(pScrn); 377963d66acSmrg VIAPtr pVia = VIAPTR(pScrn); 3787e6fb56fSmrg 379963d66acSmrg if (!pI2CBus) { 380963d66acSmrg DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_ERROR, 381963d66acSmrg "xf86CreateI2CBusRec failed.\n")); 382963d66acSmrg xf86DrvMsg(pScrn->scrnIndex, X_ERROR, 383963d66acSmrg "Initialization of I2C Bus 3 failed.\n"); 384963d66acSmrg DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, 385963d66acSmrg "Exiting ViaI2CBus3Init.\n")); 3867e6fb56fSmrg return NULL; 387963d66acSmrg } 3887e6fb56fSmrg 389963d66acSmrg pI2CBus->BusName = "I2C Bus 3"; 39090b17f1bSmrg pI2CBus->scrnIndex = pScrn->scrnIndex; 39190b17f1bSmrg pI2CBus->DriverPrivate.ptr = hwp; 3927e6fb56fSmrg 393963d66acSmrg switch (pVia->Chipset) { 394963d66acSmrg case VIA_P4M800PRO: 395963d66acSmrg DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, 396963d66acSmrg "using alternative PutBits/GetBits functions for I2C Bus 3\n")); 397963d66acSmrg pI2CBus->I2CPutBits = ViaI2C3SimplePutBits; 398963d66acSmrg pI2CBus->I2CGetBits = ViaI2C3SimpleGetBits; 399963d66acSmrg break; 400963d66acSmrg default: 401963d66acSmrg pI2CBus->I2CAddress = ViaI2C3Address; 402963d66acSmrg#ifdef X_NEED_I2CSTART 403963d66acSmrg pI2CBus->I2CStart = ViaI2C3Start; 404963d66acSmrg#endif 405963d66acSmrg pI2CBus->I2CStop = ViaI2C3Stop; 406963d66acSmrg pI2CBus->I2CPutByte = ViaI2C3PutByte; 407963d66acSmrg pI2CBus->I2CGetByte = ViaI2C3GetByte; 408963d66acSmrg pI2CBus->DriverPrivate.ptr = hwp; 409963d66acSmrg 410963d66acSmrg pI2CBus->BitTimeout = 10; 411963d66acSmrg pI2CBus->ByteTimeout = 10; 412963d66acSmrg pI2CBus->HoldTime = 10; 413963d66acSmrg pI2CBus->StartTimeout = 10; 414963d66acSmrg break; 415963d66acSmrg } 4167e6fb56fSmrg 4177e6fb56fSmrg if (!xf86I2CBusInit(pI2CBus)) { 418963d66acSmrg DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_ERROR, 419963d66acSmrg "xf86I2CBusInit failed.\n")); 4207e6fb56fSmrg xf86DestroyI2CBusRec(pI2CBus, TRUE, FALSE); 421963d66acSmrg xf86DrvMsg(pScrn->scrnIndex, X_ERROR, 422963d66acSmrg "Initialization of I2C Bus 3 failed.\n"); 423963d66acSmrg DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, 424963d66acSmrg "Exiting ViaI2CBus3Init.\n")); 4257e6fb56fSmrg return NULL; 4267e6fb56fSmrg } 427963d66acSmrg 428963d66acSmrg DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, 429963d66acSmrg "Exiting ViaI2CBus3Init.\n")); 4307e6fb56fSmrg return pI2CBus; 4317e6fb56fSmrg} 4327e6fb56fSmrg 4337e6fb56fSmrg#ifdef HAVE_DEBUG 4347e6fb56fSmrgstatic void 4357e6fb56fSmrgViaI2CScan(I2CBusPtr Bus) 4367e6fb56fSmrg{ 4377e6fb56fSmrg CARD8 i; 4387e6fb56fSmrg 439963d66acSmrg DEBUG(xf86DrvMsg(Bus->scrnIndex, X_INFO, 440963d66acSmrg "Entered ViaI2CScan.\n")); 441963d66acSmrg 442963d66acSmrg xf86DrvMsg(Bus->scrnIndex, X_INFO, "Scanning %s.\n", 4437e6fb56fSmrg Bus->BusName); 4447e6fb56fSmrg 4457e6fb56fSmrg for (i = 0x10; i < 0xF0; i += 2) 4467e6fb56fSmrg if (xf86I2CProbeAddress(Bus, i)) 4477e6fb56fSmrg xf86DrvMsg(Bus->scrnIndex, X_PROBED, "Found slave on %s " 448963d66acSmrg "- 0x%02X.\n", Bus->BusName, i); 449963d66acSmrg 450963d66acSmrg DEBUG(xf86DrvMsg(Bus->scrnIndex, X_INFO, 451963d66acSmrg "Exiting ViaI2CScan.\n")); 4527e6fb56fSmrg} 4537e6fb56fSmrg#endif /* HAVE_DEBUG */ 4547e6fb56fSmrg 4557e6fb56fSmrgvoid 4567e6fb56fSmrgViaI2CInit(ScrnInfoPtr pScrn) 4577e6fb56fSmrg{ 4587e6fb56fSmrg VIAPtr pVia = VIAPTR(pScrn); 4597e6fb56fSmrg 460963d66acSmrg DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, 461963d66acSmrg "Entered ViaI2CInit.\n")); 4627e6fb56fSmrg 46390b17f1bSmrg if (pVia->I2CDevices & VIA_I2C_BUS1) 46490b17f1bSmrg pVia->pI2CBus1 = ViaI2CBus1Init(pScrn); 46590b17f1bSmrg if (pVia->I2CDevices & VIA_I2C_BUS2) 46690b17f1bSmrg pVia->pI2CBus2 = ViaI2CBus2Init(pScrn); 46790b17f1bSmrg if (pVia->I2CDevices & VIA_I2C_BUS3) 46890b17f1bSmrg pVia->pI2CBus3 = ViaI2CBus3Init(pScrn); 4697e6fb56fSmrg 4707e6fb56fSmrg#ifdef HAVE_DEBUG 4717e6fb56fSmrg if (pVia->I2CScan) { 4727e6fb56fSmrg if (pVia->pI2CBus2) 4737e6fb56fSmrg ViaI2CScan(pVia->pI2CBus2); 4747e6fb56fSmrg if (pVia->pI2CBus3) 4757e6fb56fSmrg ViaI2CScan(pVia->pI2CBus3); 4767e6fb56fSmrg } 4777e6fb56fSmrg#endif 478963d66acSmrg 479963d66acSmrg DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, 480963d66acSmrg "Exiting ViaI2CInit.\n")); 4817e6fb56fSmrg} 482983b4bf2Smrg 483983b4bf2Smrg/* 484983b4bf2Smrg * The code originated from Luc Verhaegen's xf86-video-unichrome DDX. 485983b4bf2Smrg * 486983b4bf2Smrg * Sure, it is polluting namespace, but this one is quite useful. 487983b4bf2Smrg */ 488983b4bf2SmrgBool 489983b4bf2Smrgxf86I2CMaskByte(I2CDevPtr d, I2CByte subaddr, I2CByte value, I2CByte mask) 490983b4bf2Smrg{ 491983b4bf2Smrg I2CByte tmp; 492983b4bf2Smrg Bool ret; 493983b4bf2Smrg 494983b4bf2Smrg ret = xf86I2CReadByte(d, subaddr, &tmp); 495983b4bf2Smrg if (!ret) 496983b4bf2Smrg return FALSE; 497983b4bf2Smrg 498983b4bf2Smrg tmp &= ~mask; 499983b4bf2Smrg tmp |= (value & mask); 500983b4bf2Smrg 501983b4bf2Smrg return xf86I2CWriteByte(d, subaddr, tmp); 502983b4bf2Smrg} 503