diff options
author | Matthieu Herrb <matthieu@cvs.openbsd.org> | 2008-07-12 12:48:49 +0000 |
---|---|---|
committer | Matthieu Herrb <matthieu@cvs.openbsd.org> | 2008-07-12 12:48:49 +0000 |
commit | 3e1b3ae1e6599585267353c38c315b794c811e3e (patch) | |
tree | a53485de47517ca802a9459b5ffad45bdcac955f /driver/xf86-video-openchrome/src/via_i2c.c | |
parent | 8e76c09c21a4d0dc958abe1866dcb65e5050def5 (diff) |
Import the openchrome video driver, version 0.2.902. Discussed with
bernd@ and oga@. Tested by many in snaphots.
Diffstat (limited to 'driver/xf86-video-openchrome/src/via_i2c.c')
-rw-r--r-- | driver/xf86-video-openchrome/src/via_i2c.c | 380 |
1 files changed, 380 insertions, 0 deletions
diff --git a/driver/xf86-video-openchrome/src/via_i2c.c b/driver/xf86-video-openchrome/src/via_i2c.c new file mode 100644 index 000000000..80bc5de63 --- /dev/null +++ b/driver/xf86-video-openchrome/src/via_i2c.c @@ -0,0 +1,380 @@ +/* + * Copyright 2004 The Unichrome Project [unichrome.sf.net] + * Copyright 1998-2003 VIA Technologies, Inc. All Rights Reserved. + * Copyright 2001-2003 S3 Graphics, Inc. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sub license, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +/* + * Implements three i2c busses through registers SR26, SR2c, and SR31. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "via_driver.h" +#include "via_vgahw.h" + +#define SDA_READ 0x04 +#define SCL_READ 0x08 +#define SDA_WRITE 0x10 +#define SCL_WRITE 0x20 + + +/* + * CRT I2C + */ + +static void +ViaI2C1PutBits(I2CBusPtr Bus, int clock, int data) +{ + vgaHWPtr hwp = VGAHWPTR(xf86Screens[Bus->scrnIndex]); + CARD8 value = 0x01; /* Enable */ + + if (clock) + value |= SCL_WRITE; + + if (data) + value |= SDA_WRITE; + + ViaSeqMask(hwp, 0x26, value, 0x01 | SCL_WRITE | SDA_WRITE); +} + +static void +ViaI2C1GetBits(I2CBusPtr Bus, int *clock, int *data) +{ + vgaHWPtr hwp = VGAHWPTR(xf86Screens[Bus->scrnIndex]); + CARD8 value = hwp->readSeq(hwp, 0x26); + + *clock = (value & SCL_READ) != 0; + *data = (value & SDA_READ) != 0; +} + +static I2CBusPtr +ViaI2CBus1Init(int scrnIndex) +{ + I2CBusPtr pI2CBus = xf86CreateI2CBusRec(); + + DEBUG(xf86DrvMsg(scrnIndex, X_INFO, "ViaI2CBus1Init\n")); + + if (!pI2CBus) + return NULL; + + pI2CBus->BusName = "I2C bus 1"; + pI2CBus->scrnIndex = scrnIndex; + pI2CBus->I2CPutBits = ViaI2C1PutBits; + pI2CBus->I2CGetBits = ViaI2C1GetBits; + + if (!xf86I2CBusInit(pI2CBus)) { + xf86DestroyI2CBusRec(pI2CBus, TRUE, FALSE); + return NULL; + } + + return pI2CBus; +} + + +/* + * First data bus I2C: tends to have TV-encoders. + */ + +static void +ViaI2C2PutBits(I2CBusPtr Bus, int clock, int data) +{ + vgaHWPtr hwp = VGAHWPTR(xf86Screens[Bus->scrnIndex]); + CARD8 value = 0x01; /* Enable */ + + if (clock) + value |= SCL_WRITE; + + if (data) + value |= SDA_WRITE; + + ViaSeqMask(hwp, 0x31, value, 0x01 | SCL_WRITE | SDA_WRITE); +} + +static void +ViaI2C2GetBits(I2CBusPtr Bus, int *clock, int *data) +{ + vgaHWPtr hwp = VGAHWPTR(xf86Screens[Bus->scrnIndex]); + CARD8 value = hwp->readSeq(hwp, 0x31); + + *clock = (value & SCL_READ) != 0; + *data = (value & SDA_READ) != 0; +} + +static I2CBusPtr +ViaI2CBus2Init(int scrnIndex) +{ + I2CBusPtr pI2CBus = xf86CreateI2CBusRec(); + + DEBUG(xf86DrvMsg(scrnIndex, X_INFO, "ViaI2cBus2Init\n")); + + if (!pI2CBus) + return NULL; + + pI2CBus->BusName = "I2C bus 2"; + pI2CBus->scrnIndex = scrnIndex; + pI2CBus->I2CPutBits = ViaI2C2PutBits; + pI2CBus->I2CGetBits = ViaI2C2GetBits; + + if (!xf86I2CBusInit(pI2CBus)) { + xf86DestroyI2CBusRec(pI2CBus, TRUE, FALSE); + return NULL; + } + + return pI2CBus; +} + + +/* + * A third I2C bus is implemented by a few IO pins. + * Requires higher level functions to be used properly. + */ + +static Bool +ViaI2C3Start(I2CBusPtr b, int timeout) +{ + vgaHWPtr hwp = VGAHWPTR(xf86Screens[b->scrnIndex]); + + ViaSeqMask(hwp, 0x2C, 0xF0, 0xF0); + b->I2CUDelay(b, b->RiseFallTime); + + ViaSeqMask(hwp, 0x2C, 0x00, 0x10); + b->I2CUDelay(b, b->HoldTime); + ViaSeqMask(hwp, 0x2C, 0x00, 0x20); + b->I2CUDelay(b, b->HoldTime); + + return TRUE; +} + +static Bool +ViaI2C3Address(I2CDevPtr d, I2CSlaveAddr addr) +{ + I2CBusPtr b = d->pI2CBus; + +#ifdef X_NEED_I2CSTART + if (b->I2CStart(d->pI2CBus, d->StartTimeout)) { +#else + if (ViaI2C3Start(d->pI2CBus, d->StartTimeout)) { +#endif + if (b->I2CPutByte(d, addr & 0xFF)) { + if ((addr & 0xF8) != 0xF0 && (addr & 0xFE) != 0x00) + return TRUE; + + if (b->I2CPutByte(d, (addr >> 8) & 0xFF)) + return TRUE; + } + + b->I2CStop(d); + } + + return FALSE; +} + +static void +ViaI2C3Stop(I2CDevPtr d) +{ + I2CBusPtr b = d->pI2CBus; + vgaHWPtr hwp = VGAHWPTR(xf86Screens[b->scrnIndex]); + + ViaSeqMask(hwp, 0x2C, 0xC0, 0xF0); + b->I2CUDelay(b, b->RiseFallTime); + + ViaSeqMask(hwp, 0x2C, 0x20, 0x20); + b->I2CUDelay(b, b->HoldTime); + + ViaSeqMask(hwp, 0x2C, 0x10, 0x10); + b->I2CUDelay(b, b->HoldTime); + + ViaSeqMask(hwp, 0x2C, 0x00, 0x20); + b->I2CUDelay(b, b->HoldTime); +} + +static void +ViaI2C3PutBit(I2CBusPtr b, Bool sda, int timeout) +{ + vgaHWPtr hwp = VGAHWPTR(xf86Screens[b->scrnIndex]); + + if (sda) + ViaSeqMask(hwp, 0x2C, 0x50, 0x50); + else + ViaSeqMask(hwp, 0x2C, 0x40, 0x50); + b->I2CUDelay(b, b->RiseFallTime / 5); + + ViaSeqMask(hwp, 0x2C, 0xA0, 0xA0); + b->I2CUDelay(b, b->HoldTime); + b->I2CUDelay(b, timeout); + + ViaSeqMask(hwp, 0x2C, 0x80, 0xA0); + b->I2CUDelay(b, b->RiseFallTime / 5); +} + +static Bool +ViaI2C3PutByte(I2CDevPtr d, I2CByte data) +{ + I2CBusPtr b = d->pI2CBus; + vgaHWPtr hwp = VGAHWPTR(xf86Screens[b->scrnIndex]); + Bool ret; + int i; + + for (i = 7; i >= 0; i--) + ViaI2C3PutBit(b, (data >> i) & 0x01, b->BitTimeout); + + /* Raise first to avoid false positives. */ + ViaSeqMask(hwp, 0x2C, 0x50, 0x50); + ViaSeqMask(hwp, 0x2C, 0x00, 0x40); + b->I2CUDelay(b, b->RiseFallTime); + ViaSeqMask(hwp, 0x2C, 0xA0, 0xA0); + + if (hwp->readSeq(hwp, 0x2C) & 0x04) + ret = FALSE; + else + ret = TRUE; + + ViaSeqMask(hwp, 0x2C, 0x80, 0xA0); + b->I2CUDelay(b, b->RiseFallTime); + + return ret; +} + +static Bool +ViaI2C3GetBit(I2CBusPtr b, int timeout) +{ + vgaHWPtr hwp = VGAHWPTR(xf86Screens[b->scrnIndex]); + Bool ret; + + ViaSeqMask(hwp, 0x2c, 0x80, 0xC0); + b->I2CUDelay(b, b->RiseFallTime / 5); + ViaSeqMask(hwp, 0x2c, 0xA0, 0xA0); + b->I2CUDelay(b, 3 * b->HoldTime); + b->I2CUDelay(b, timeout); + + if (hwp->readSeq(hwp, 0x2C) & 0x04) + ret = TRUE; + else + ret = FALSE; + + ViaSeqMask(hwp, 0x2C, 0x80, 0xA0); + b->I2CUDelay(b, b->HoldTime); + b->I2CUDelay(b, b->RiseFallTime / 5); + + return ret; +} + +static Bool +ViaI2C3GetByte(I2CDevPtr d, I2CByte * data, Bool last) +{ + I2CBusPtr b = d->pI2CBus; + vgaHWPtr hwp = VGAHWPTR(xf86Screens[b->scrnIndex]); + int i; + + *data = 0x00; + + for (i = 7; i >= 0; i--) + if (ViaI2C3GetBit(b, b->BitTimeout)) + *data |= 0x01 << i; + + if (last) /* send NACK */ + ViaSeqMask(hwp, 0x2C, 0x50, 0x50); + else /* send ACK */ + ViaSeqMask(hwp, 0x2C, 0x40, 0x50); + + ViaSeqMask(hwp, 0x2C, 0xA0, 0xA0); + b->I2CUDelay(b, b->HoldTime); + + ViaSeqMask(hwp, 0x2C, 0x80, 0xA0); + + return TRUE; +} + +static I2CBusPtr +ViaI2CBus3Init(int scrnIndex) +{ + I2CBusPtr pI2CBus = xf86CreateI2CBusRec(); + + DEBUG(xf86DrvMsg(scrnIndex, X_INFO, "ViaI2CBus3Init\n")); + + if (!pI2CBus) + return NULL; + + pI2CBus->BusName = "I2C bus 3"; + pI2CBus->scrnIndex = scrnIndex; + pI2CBus->I2CAddress = ViaI2C3Address; +#ifdef X_NEED_I2CSTART + pI2CBus->I2CStart = ViaI2C3Start; +#endif + pI2CBus->I2CStop = ViaI2C3Stop; + pI2CBus->I2CPutByte = ViaI2C3PutByte; + pI2CBus->I2CGetByte = ViaI2C3GetByte; + + pI2CBus->HoldTime = 10; + pI2CBus->BitTimeout = 10; + pI2CBus->ByteTimeout = 10; + pI2CBus->StartTimeout = 10; + + if (!xf86I2CBusInit(pI2CBus)) { + xf86DestroyI2CBusRec(pI2CBus, TRUE, FALSE); + return NULL; + } + + return pI2CBus; +} + + +#ifdef HAVE_DEBUG +static void +ViaI2CScan(I2CBusPtr Bus) +{ + CARD8 i; + + xf86DrvMsg(Bus->scrnIndex, X_INFO, "ViaI2CScan: Scanning %s\n", + Bus->BusName); + + for (i = 0x10; i < 0xF0; i += 2) + if (xf86I2CProbeAddress(Bus, i)) + xf86DrvMsg(Bus->scrnIndex, X_PROBED, "Found slave on %s " + "- 0x%02X\n", Bus->BusName, i); +} +#endif /* HAVE_DEBUG */ + + +void +ViaI2CInit(ScrnInfoPtr pScrn) +{ + VIAPtr pVia = VIAPTR(pScrn); + + DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, "ViaI2CInit\n")); + + pVia->pI2CBus1 = ViaI2CBus1Init(pScrn->scrnIndex); + pVia->pI2CBus2 = ViaI2CBus2Init(pScrn->scrnIndex); + pVia->pI2CBus3 = ViaI2CBus3Init(pScrn->scrnIndex); + +#ifdef HAVE_DEBUG + if (pVia->I2CScan) { + if (pVia->pI2CBus2) + ViaI2CScan(pVia->pI2CBus2); + if (pVia->pI2CBus3) + ViaI2CScan(pVia->pI2CBus3); + } +#endif +} |