Hey,

as I recently obtained such a PCMCIA card, I try to revive the wnv_cs driver
for Winnov Videum Traveler video cards. First (non-working, but compiling
and able to access the EEPROM and to detect the decoder) results may be
found at

http://git.kernel.org/?p=linux/kernel/git/brodo/pcmcia-2.6.git;a=shortlog;h=refs/heads/wnv

Now, I got a bit stuck at the i2c level -- do the following access functions
look familiar to one of the i2c experts? If so, which algo driver is to be
used? Is this an i2c_smbus_, or some very custom interface not worth
converting to use the i2c subsystem? Many thanks!

Best,
        Dominik

PS: The i2c addresses used in this driver are > 0x7f (e.g. 0xa0, 0x8e, 0x48,
        0x4a, 0x34, 0xa8, 0x68)


/*
 *        2
 *      I   C   B U S   I N T E R F A C E
 *
 */

static __u16
in_ctl(struct videum_device *dev)
{       return wavi_readreg(dev, WAVI_CTL);
}
static void
out_ctl(struct videum_device *dev)
{       wavi_writereg(dev, WAVI_CTL, dev->ctl);
}
static void
i2c_delay(void)
{       udelay(2);
}
static void
i2c_clock(struct videum_device *dev, int c)
{       int     t = 1000;
        if (c) dev->ctl |= WAVI_I2CBIT; else dev->ctl &= ~WAVI_I2CBIT;
        out_ctl(dev);
        if (!c) while (--t && (in_ctl(dev) & WAVI_I2CBIT));
}
static void
i2c_data(struct videum_device *dev, int d)
{       if (d) dev->ctl |= WAVI_IMDBIT; else dev->ctl &= ~WAVI_IMDBIT;
        out_ctl(dev);
}
/* BUG: I2C bit read routines, polarity */

static void
i2c_start(struct videum_device *dev)
{       dev->ctl &= ~(WAVI_I2CBIT | WAVI_IMDBIT);
        out_ctl(dev);           i2c_delay();
        i2c_data(dev, 1);       i2c_delay();
        i2c_clock(dev, 0);      i2c_delay();
}

static int
i2c_get_ack(struct videum_device *dev)
{
        i2c_clock(dev, 1);      i2c_delay();
        i2c_data(dev, 0);       i2c_delay();
        i2c_clock(dev, 0);      i2c_delay();
        i2c_delay();
        return in_ctl(dev) & WAVI_IMDBIT;
}

static void
i2c_send_ack(struct videum_device *dev)
{
        i2c_clock(dev, 1);      i2c_delay();
        i2c_data(dev, 1);       i2c_delay();
        i2c_clock(dev, 0);      i2c_delay();
}

static void
i2c_send_nak(struct videum_device *dev)
{
        i2c_clock(dev, 1);      i2c_delay();
        i2c_data(dev, 0);       i2c_delay();
        i2c_clock(dev, 0);      i2c_delay();
}

static void
i2c_end(struct videum_device *dev)
{
        i2c_clock(dev, 1);      i2c_delay();
        i2c_data(dev, 1);       i2c_delay();
        i2c_clock(dev, 0);      i2c_delay();
        i2c_data(dev, 0);       i2c_delay();
}

static void
i2c_vpxrestart(struct videum_device *dev)
{
        i2c_clock(dev, 1);      i2c_delay();
        i2c_data(dev, 0);       i2c_delay();
        i2c_clock(dev, 0);      i2c_delay();
}

static void
i2c_out8(struct videum_device *dev,
         int    ndata)
{
        int     i;
        
        ndata = ~ndata;
        for (i = 0; i < 8; ++i)
        {
                i2c_clock(dev, 1);              i2c_delay();
                i2c_data(dev, ndata & 128);     i2c_delay();
                i2c_clock(dev, 0);              i2c_delay();
                ndata <<= 1;
        }
}

static int
i2c_in8(struct videum_device *dev)
{
        int     i;
        int     ndata = ~0;

        dev->ctl &= ~WAVI_IMDBIT;// Don't write to h/w now
        for (i = 0; i < 8; ++i)
        {
                i2c_clock(dev, 1);      i2c_delay();
                i2c_clock(dev, 0);      i2c_delay();
                ndata = (in_ctl(dev) & 1) | (ndata << 1);
        }
        return ~ndata;
}

static void
i2c_get_ready(struct videum_device *dev)
{/*     Prepare I2C bus for operation   */
        dev->ctl = in_ctl(dev); /* initialize the CTL register shadow */
        i2c_end(dev);   /* idle the I2C bus */
}

static int
i2c_error(struct videum_device *dev)
{
        i2c_end(dev);
        return -1;
}

// Returns -1 on error.
static int i2c_read_reg_byte(struct videum_device *dev, int addr, int reg)
{       int     ndata;

        i2c_start(dev);
        i2c_out8(dev, addr);
        if (!i2c_get_ack(dev))
                return i2c_error(dev);/* no ACK from device */
        i2c_out8(dev, reg);
        i2c_get_ack(dev); /* assume it succeeds if the first one succeeded */
        if (addr == 0x86 || addr == 0x8E)/* ITT VPX is a little different  */
                i2c_vpxrestart(dev);
        else
                i2c_end(dev);
        i2c_start(dev);
        i2c_out8(dev, addr | 1);
        if (!i2c_get_ack(dev))
                return i2c_error(dev);
        ndata = i2c_in8(dev);
        if (addr == 0x86 || addr == 0x8E)/* ITT VPX is a little different  */
                i2c_send_nak(dev);
        i2c_end(dev);
        return ndata;
}

static int /* -1 on error */
i2c_write_reg_byte(struct videum_device *dev, 
                   int addr, int reg, int ndata)
{
        i2c_start(dev);
        i2c_out8(dev, addr);
        if (!i2c_get_ack(dev))
                return i2c_error(dev);/* no ACK from device */
        i2c_out8(dev, reg);
        i2c_get_ack(dev);
        i2c_out8(dev, ndata);
        i2c_get_ack(dev);
        i2c_end(dev);
        return 0;
}

static int /* -1 on error */
i2c_read_reg_word(struct videum_device *dev, 
                  int addr, int reg)
{
        int     ndata;
        
        i2c_start(dev);
        i2c_out8(dev, addr);
        if (!i2c_get_ack(dev))
                return i2c_error(dev);/* no ACK from device */
        i2c_out8(dev, reg);
        i2c_get_ack(dev); /* assume it succeeds if the first one succeeded */
        if (addr == 0x86 || addr == 0x8E)/* ITT VPX is a little different  */
                i2c_vpxrestart(dev);
        else
                i2c_end(dev);
        i2c_start(dev);
        i2c_out8(dev, addr | 1);
        if (!i2c_get_ack(dev))
                return i2c_error(dev);
        ndata = i2c_in8(dev) << 8;
        i2c_send_ack(dev);
        ndata |= i2c_in8(dev);
        i2c_send_nak(dev);
        i2c_end(dev);
        return ndata;
}

static int /* -1 on error */
i2c_write_reg_word(struct videum_device *dev, 
                   int addr, int reg, int ndata)
{
        i2c_start(dev);
        i2c_out8(dev, addr);
        if (!i2c_get_ack(dev))
                return i2c_error(dev);/* no ACK from device */
        i2c_out8(dev, reg);
        i2c_get_ack(dev);
        i2c_out8(dev, ndata >> 8);
        i2c_get_ack(dev);
        i2c_out8(dev, ndata & 0xFF);
        i2c_get_ack(dev);
        i2c_end(dev);
        return 0;
}

--
To unsubscribe from this list: send the line "unsubscribe linux-i2c" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to