Re: [PATCH 12/13] viafb: via_i2c.c, via_i2c.h, viamode.c, viamode.c
From: Ben Dooks <ben-linux@fluff.org>
Date: 2008-06-30 15:44:30
Also in:
lkml
On Mon, Jun 30, 2008 at 03:51:19PM +0800, JosephChan@via.com.tw wrote:
quoted hunk ↗ jump to hunk
via_i2c.c, via_i2c.h: Implement i2c specification. viamode.c, viamode.c: all support modes information. Signed-off-by: Joseph Chan <redacted> diff -Nur a/drivers/video/via/via_i2c.c b/drivers/video/via/via_i2c.c--- a/drivers/video/via/via_i2c.c 1970-01-01 08:00:00.000000000 +0800 +++ b/drivers/video/via/via_i2c.c 2008-06-30 08:53:33.000000000 +0800@@ -0,0 +1,377 @@ +/* + * Copyright 1998-2008 VIA Technologies, Inc. All Rights Reserved. + * Copyright 2001-2008 S3 Graphics, Inc. All Rights Reserved. + + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public + * License as published by the Free Software Foundation; + * either version 2, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTIES OR REPRESENTATIONS; without even + * the implied warranty of MERCHANTABILITY or FITNESS FOR + * A PARTICULAR PURPOSE.See the GNU General Public License + * for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include "global.h" + +/* i2c delay for microsecond*/ +void viafb_delays(int count) +{ + u8 data; + while (count--) { + /* delay 1 us */ + data = inb(DELAYPORT); + data = inb(DELAYPORT); + data = inb(DELAYPORT); + data = inb(DELAYPORT); + data = inb(DELAYPORT); + } + +} + +/* Write I2C BUS SDA And SCL*/ +static void i2cWriteSdaScl(u8 sda, u8 scl) +{ + u8 data; + u16 port_addr; + + if (viaparinfo->chip_info->chip_on_slot == PORT_ON_AMR) { + + data = ((scl << 1) | sda) << 4; + /* enable I2C port */ + data = data | BIT0; + + port_addr = I2CPORT; + /* Write Register Value */ + viafb_write_reg(I2CPORTINDEX, port_addr, data); + } else { + if (viaparinfo->chip_info->chip_on_slot == PORT_ON_AGP) { + data = ((scl << 1) | sda) << 4; + /* enable GPIO write port */ + data = data | (BIT6 + BIT7); + port_addr = GPIOPORT; + /* Write Register Value */ + viafb_write_reg(GPIOPORTINDEX, port_addr, data); + } + } +} + +static void i2cReadSdaScl(u8 *pSda, u8 *pScl) +{ + u8 data; + u16 port_addr; + + if (viaparinfo->chip_info->chip_on_slot == PORT_ON_AMR) { + port_addr = I2CPORT; + data = viafb_read_reg(port_addr, I2CPORTINDEX); + *pSda = (data >> 2) & BIT0; /* get sda */ + *pScl = (data >> 3) & BIT0; /* get scl */ + } else { + if (viaparinfo->chip_info->chip_on_slot == PORT_ON_AGP) { + port_addr = GPIOPORT; + data = viafb_read_reg(port_addr, GPIOPORTINDEX); + *pSda = (data >> 2) & BIT0; /* get sda */ + *pScl = (data >> 3) & BIT0; /* get scl */ + } + } +} + +static void i2cWriteSdaSclDelay(u8 sda, u8 scl) +{ + i2cWriteSdaScl(sda, scl); + viafb_delays(16); /* Wait 16 uS */ +} + +static void i2cStartSignal(void) +{ + i2cWriteSdaSclDelay(1, 1); + i2cWriteSdaSclDelay(0, 1); + i2cWriteSdaSclDelay(0, 0); +} + +static void i2cStopSignal(void) +{ + u8 data; + u16 port_addr; + + i2cWriteSdaSclDelay(0, 0); + i2cWriteSdaSclDelay(0, 1); + i2cWriteSdaSclDelay(1, 1); + + if (viaparinfo->chip_info->chip_on_slot == PORT_ON_AGP) { + /* disable GPIO write port */ + data = 0x3c; + port_addr = GPIOPORT; + /* Write Register Value */ + viafb_write_reg(GPIOPORTINDEX, port_addr, data); + } + viafb_delays(2); + +} + +static void disableSdaGPIO(void) +{ + u8 data; + u16 port_addr; + + if (viaparinfo->chip_info->chip_on_slot == PORT_ON_AGP) { + port_addr = GPIOPORT; + data = viafb_read_reg(port_addr, GPIOPORTINDEX); + /* disable GPIO write port */ + data = data & (~BIT6); + /* Write Register Value */ + viafb_write_reg(GPIOPORTINDEX, port_addr, data); + } +} + +static void writeSclGPIO(u8 scl) +{ + u8 data; + u16 port_addr; + + if (viaparinfo->chip_info->chip_on_slot == PORT_ON_AGP) { + port_addr = GPIOPORT; + data = viafb_read_reg(port_addr, GPIOPORTINDEX); + data = data & (~BIT5); + /* write data to clock */ + data = (data | (scl << 5)) & (~BIT6); + /* Write Register Value */ + viafb_write_reg(GPIOPORTINDEX, port_addr, data); + } +} + +static int i2CWaitForSlave(void) +{ + int time_out = 20000; + u8 sda, scl; + + while (time_out--) { + i2cReadSdaScl(&sda, &scl); + if (scl) + return OK; /* Successful stall */ + viafb_delays(1); /* wait 1 uS */ + } + return FAIL; /* Slave fail */ +} + +static int i2cOutByte(u8 data) +{ + u8 sda, scl; + u8 out_byte; + int bit_count = 8; + int status; + + out_byte = data; + while (bit_count--) { + sda = (out_byte >> 7) & 1; /* Load MSB */ + out_byte = out_byte << 1; /* next bit. */ + i2cWriteSdaSclDelay(sda, 0); + i2cWriteSdaSclDelay(sda, 1); + + status = i2CWaitForSlave(); + if (status == FAIL) + return status; + i2cWriteSdaSclDelay(sda, 0); + + } + + if ((viaparinfo->chip_info->chip_on_slot == PORT_ON_AGP)) { + + writeSclGPIO(0); + disableSdaGPIO(); + viafb_delays(2); + writeSclGPIO(1); + viafb_delays(2); + i2cReadSdaScl(&sda, &scl); + writeSclGPIO(0); + viafb_delays(2); + if (sda == 0) + status = OK; + else + status = FAIL; + } else { + i2cWriteSdaSclDelay(1, 0); + i2cWriteSdaSclDelay(1, 1); + status = i2CWaitForSlave(); + if (status == FAIL) + return status; + + i2cReadSdaScl(&sda, &scl); + if (sda == 0) { + i2cWriteSdaSclDelay(1, 0); + status = OK; + } else { + + i2cWriteSdaSclDelay(1, 0); + status = FAIL; + } + } + return status; +} + +static int i2cInputByte(u8 *pInByte, int ack) +{ + + int bit_count = 8; + u8 sda, scl; + u8 data = 0; + int status; + + disableSdaGPIO(); + + while (bit_count--) { + if ((viaparinfo->chip_info->chip_on_slot == PORT_ON_AGP)) { + + writeSclGPIO(1); + viafb_delays(2); + status = i2CWaitForSlave(); + if (status == FAIL) + return FAIL; + i2cReadSdaScl(&sda, &scl); + data = data << 1; + data |= sda; + writeSclGPIO(0); + viafb_delays(2); + + } else { + i2cWriteSdaSclDelay(1, 1); + status = i2CWaitForSlave(); + if (status == FAIL) + return FAIL; + i2cReadSdaScl(&sda, &scl); + data = data << 1; + data |= sda; + i2cWriteSdaSclDelay(1, 0); + } + } + *pInByte = data; + + if (ack) { + i2cWriteSdaSclDelay(0, 0); + i2cWriteSdaSclDelay(0, 1); + status = i2CWaitForSlave(); + if (status == FAIL) + return status; + i2cWriteSdaSclDelay(0, 0); + } else { + i2cWriteSdaSclDelay(1, 0); + i2cWriteSdaSclDelay(1, 1); + status = i2CWaitForSlave(); + if (status == FAIL) + return status; + } + i2cWriteSdaSclDelay(1, 0); + + return OK; +} + +int viafb_i2cReadByte(u8 slave_addr, u8 index, u8 *pData) +{ + + int status; + + i2cStartSignal(); + + status = i2cOutByte(slave_addr); + if (status == FAIL) { + i2cStopSignal(); + return FAIL; + } + status = i2cOutByte(index); + + if (status == FAIL) { + i2cStopSignal(); + return FAIL; + } + + i2cStartSignal(); + status = i2cOutByte(slave_addr | BIT0); + if (status == FAIL) { + i2cStopSignal(); + return FAIL; + } + status = i2cInputByte(pData, 0); + if (status == FAIL) { + i2cStopSignal(); + return FAIL; + } + + i2cStopSignal(); + return OK; +} + +int viafb_i2cWriteByte(u8 slave_addr, u8 index, u8 data) +{ + + int status; + + i2cStartSignal(); + status = i2cOutByte(slave_addr); + if (status == FAIL) { + i2cStopSignal(); + return FAIL; + } + status = i2cOutByte(index); + if (status == FAIL) { + i2cStopSignal(); + return FAIL; + } + status = i2cOutByte(data); + if (status == FAIL) { + i2cStopSignal(); + return FAIL; + } + i2cStopSignal(); + return OK; +} + +int viafb_i2cReadBytes(u8 slave_addr, u8 index, u8 *buff, int buff_len) +{ + + int status, i; + + i2cStartSignal(); + + status = i2cOutByte(slave_addr); + if (status == FAIL) { + i2cStopSignal(); + return FAIL; + } + + status = i2cOutByte(index); + if (status == FAIL) { + i2cStopSignal(); + return FAIL; + } + + i2cStartSignal(); + status = i2cOutByte(slave_addr | BIT0); + if (status == FAIL) { + i2cStopSignal(); + return FAIL; + } + + for (i = 0; i < buff_len; i++) { + if (buff_len == 1) + status = i2cInputByte(buff, 0); /* send NACK */ + else if (i < buff_len - 1) + status = i2cInputByte(buff, 1); /* send ACK */ + else + status = i2cInputByte(buff, 0); /* send NACK */ + if (status == FAIL) { + i2cStopSignal(); + return (FAIL); + } + buff++; + } + + i2cStopSignal(); + return OK; +}
This looks like an attempt at re-doing the already extant i2c gpio algorithm. Either export via gpiolib and use the i2c-gpio adapter or use the i2c bit-banging algorithm. -- Ben ------------------------------------------------------------------------- Check out the new SourceForge.net Marketplace. It's the best place to buy or sell services for just about anything Open Source. http://sourceforge.net/services/buy/index.php