?? w9968cf.c
字號:
static int w9968cf_smbus_stop(struct w9968cf_device* cam){ int err = 0; err += w9968cf_write_sb(cam, 0x0011); /* SDE=1, SDA=0, SCL=1 */ err += w9968cf_write_sb(cam, 0x0013); /* SDE=1, SDA=1, SCL=1 */ return err;}static int w9968cf_smbus_write_byte(struct w9968cf_device* cam, u8 v){ u8 bit; int err = 0, sda; for (bit = 0 ; bit < 8 ; bit++) { sda = (v & 0x80) ? 2 : 0; v <<= 1; /* SDE=1, SDA=sda, SCL=0 */ err += w9968cf_write_sb(cam, 0x10 | sda); /* SDE=1, SDA=sda, SCL=1 */ err += w9968cf_write_sb(cam, 0x11 | sda); /* SDE=1, SDA=sda, SCL=0 */ err += w9968cf_write_sb(cam, 0x10 | sda); } return err;}static int w9968cf_smbus_read_byte(struct w9968cf_device* cam, u8* v){ u8 bit; int err = 0; *v = 0; for (bit = 0 ; bit < 8 ; bit++) { *v <<= 1; err += w9968cf_write_sb(cam, 0x0013); *v |= (w9968cf_read_sb(cam) & 0x0008) ? 1 : 0; err += w9968cf_write_sb(cam, 0x0012); } return err;}static int w9968cf_smbus_write_ack(struct w9968cf_device* cam){ int err = 0; err += w9968cf_write_sb(cam, 0x0010); /* SDE=1, SDA=0, SCL=0 */ err += w9968cf_write_sb(cam, 0x0011); /* SDE=1, SDA=0, SCL=1 */ err += w9968cf_write_sb(cam, 0x0010); /* SDE=1, SDA=0, SCL=0 */ return err;}static int w9968cf_smbus_read_ack(struct w9968cf_device* cam){ int err = 0, sda; err += w9968cf_write_sb(cam, 0x0013); /* SDE=1, SDA=1, SCL=1 */ sda = (w9968cf_read_sb(cam) & 0x08) ? 1 : 0; /* sda = SDA */ err += w9968cf_write_sb(cam, 0x0012); /* SDE=1, SDA=1, SCL=0 */ if (sda < 0) err += sda; if (sda == 1) { DBG(6, "Couldn't receive the ACK") err += -1; } return err;}/* This seems to refresh the communication through the serial bus */static int w9968cf_smbus_refresh_bus(struct w9968cf_device* cam){ int err = 0, j; for (j = 1; j <= 10; j++) { err = w9968cf_write_reg(cam, 0x0020, 0x01); err += w9968cf_write_reg(cam, 0x0000, 0x01); if (err) break; } return err;}/* SMBus protocol: S Addr Wr [A] Subaddr [A] Value [A] P */static intw9968cf_i2c_adap_fastwrite_byte_data(struct w9968cf_device* cam, u16 address, u8 subaddress,u8 value){ u16* data = cam->data_buffer; int err = 0; err += w9968cf_smbus_refresh_bus(cam); /* Enable SBUS outputs */ err += w9968cf_write_sb(cam, 0x0020); data[0] = 0x082f | ((address & 0x80) ? 0x1500 : 0x0); data[0] |= (address & 0x40) ? 0x4000 : 0x0; data[1] = 0x2082 | ((address & 0x40) ? 0x0005 : 0x0); data[1] |= (address & 0x20) ? 0x0150 : 0x0; data[1] |= (address & 0x10) ? 0x5400 : 0x0; data[2] = 0x8208 | ((address & 0x08) ? 0x0015 : 0x0); data[2] |= (address & 0x04) ? 0x0540 : 0x0; data[2] |= (address & 0x02) ? 0x5000 : 0x0; data[3] = 0x1d20 | ((address & 0x02) ? 0x0001 : 0x0); data[3] |= (address & 0x01) ? 0x0054 : 0x0; err += w9968cf_write_fsb(cam, data); data[0] = 0x8208 | ((subaddress & 0x80) ? 0x0015 : 0x0); data[0] |= (subaddress & 0x40) ? 0x0540 : 0x0; data[0] |= (subaddress & 0x20) ? 0x5000 : 0x0; data[1] = 0x0820 | ((subaddress & 0x20) ? 0x0001 : 0x0); data[1] |= (subaddress & 0x10) ? 0x0054 : 0x0; data[1] |= (subaddress & 0x08) ? 0x1500 : 0x0; data[1] |= (subaddress & 0x04) ? 0x4000 : 0x0; data[2] = 0x2082 | ((subaddress & 0x04) ? 0x0005 : 0x0); data[2] |= (subaddress & 0x02) ? 0x0150 : 0x0; data[2] |= (subaddress & 0x01) ? 0x5400 : 0x0; data[3] = 0x001d; err += w9968cf_write_fsb(cam, data); data[0] = 0x8208 | ((value & 0x80) ? 0x0015 : 0x0); data[0] |= (value & 0x40) ? 0x0540 : 0x0; data[0] |= (value & 0x20) ? 0x5000 : 0x0; data[1] = 0x0820 | ((value & 0x20) ? 0x0001 : 0x0); data[1] |= (value & 0x10) ? 0x0054 : 0x0; data[1] |= (value & 0x08) ? 0x1500 : 0x0; data[1] |= (value & 0x04) ? 0x4000 : 0x0; data[2] = 0x2082 | ((value & 0x04) ? 0x0005 : 0x0); data[2] |= (value & 0x02) ? 0x0150 : 0x0; data[2] |= (value & 0x01) ? 0x5400 : 0x0; data[3] = 0xfe1d; err += w9968cf_write_fsb(cam, data); /* Disable SBUS outputs */ err += w9968cf_write_sb(cam, 0x0000); if (!err) DBG(5, "I2C write byte data done, addr.0x%04X, subaddr.0x%02X " "value 0x%02X", address, subaddress, value) else DBG(5, "I2C write byte data failed, addr.0x%04X, " "subaddr.0x%02X, value 0x%02X", address, subaddress, value) return err;}/* SMBus protocol: S Addr Wr [A] Subaddr [A] P S Addr+1 Rd [A] [Value] NA P */static intw9968cf_i2c_adap_read_byte_data(struct w9968cf_device* cam, u16 address, u8 subaddress, u8* value){ int err = 0; /* Serial data enable */ err += w9968cf_write_sb(cam, 0x0013); /* don't change ! */ err += w9968cf_smbus_start(cam); err += w9968cf_smbus_write_byte(cam, address); err += w9968cf_smbus_read_ack(cam); err += w9968cf_smbus_write_byte(cam, subaddress); err += w9968cf_smbus_read_ack(cam); err += w9968cf_smbus_stop(cam); err += w9968cf_smbus_start(cam); err += w9968cf_smbus_write_byte(cam, address + 1); err += w9968cf_smbus_read_ack(cam); err += w9968cf_smbus_read_byte(cam, value); err += w9968cf_smbus_write_ack(cam); err += w9968cf_smbus_stop(cam); /* Serial data disable */ err += w9968cf_write_sb(cam, 0x0000); if (!err) DBG(5, "I2C read byte data done, addr.0x%04X, " "subaddr.0x%02X, value 0x%02X", address, subaddress, *value) else DBG(5, "I2C read byte data failed, addr.0x%04X, " "subaddr.0x%02X, wrong value 0x%02X", address, subaddress, *value) return err;}/* SMBus protocol: S Addr+1 Rd [A] [Value] NA P */static intw9968cf_i2c_adap_read_byte(struct w9968cf_device* cam, u16 address, u8* value){ int err = 0; /* Serial data enable */ err += w9968cf_write_sb(cam, 0x0013); err += w9968cf_smbus_start(cam); err += w9968cf_smbus_write_byte(cam, address + 1); err += w9968cf_smbus_read_ack(cam); err += w9968cf_smbus_read_byte(cam, value); err += w9968cf_smbus_write_ack(cam); err += w9968cf_smbus_stop(cam); /* Serial data disable */ err += w9968cf_write_sb(cam, 0x0000); if (!err) DBG(5, "I2C read byte done, addr.0x%04X, " "value 0x%02X", address, *value) else DBG(5, "I2C read byte failed, addr.0x%04X, " "wrong value 0x%02X", address, *value) return err;}/* SMBus protocol: S Addr Wr [A] Value [A] P */static intw9968cf_i2c_adap_write_byte(struct w9968cf_device* cam, u16 address, u8 value){ DBG(4, "i2c_write_byte() is an unsupported transfer mode") return -EINVAL;}/**************************************************************************** * I2C interface to kernel * ****************************************************************************/static intw9968cf_i2c_smbus_xfer(struct i2c_adapter *adapter, u16 addr, unsigned short flags, char read_write, u8 command, int size, union i2c_smbus_data *data){ struct w9968cf_device* cam = i2c_get_adapdata(adapter); u8 i; int err = 0; switch (addr) { case OV6xx0_SID: case OV7xx0_SID: break; default: DBG(4, "Rejected slave ID 0x%04X", addr) return -EINVAL; } if (size == I2C_SMBUS_BYTE) { /* Why addr <<= 1? See OVXXX0_SID defines in ovcamchip.h */ addr <<= 1; if (read_write == I2C_SMBUS_WRITE) err = w9968cf_i2c_adap_write_byte(cam, addr, command); else if (read_write == I2C_SMBUS_READ) err = w9968cf_i2c_adap_read_byte(cam,addr,&data->byte); } else if (size == I2C_SMBUS_BYTE_DATA) { addr <<= 1; if (read_write == I2C_SMBUS_WRITE) err = w9968cf_i2c_adap_fastwrite_byte_data(cam, addr, command, data->byte); else if (read_write == I2C_SMBUS_READ) { for (i = 1; i <= W9968CF_I2C_RW_RETRIES; i++) { err = w9968cf_i2c_adap_read_byte_data(cam,addr, command, &data->byte); if (err) { if (w9968cf_smbus_refresh_bus(cam)) { err = -EIO; break; } } else break; } } else return -EINVAL; } else { DBG(4, "Unsupported I2C transfer mode (%d)", size) return -EINVAL; } return err;}static u32 w9968cf_i2c_func(struct i2c_adapter* adap){ return I2C_FUNC_SMBUS_READ_BYTE | I2C_FUNC_SMBUS_READ_BYTE_DATA | I2C_FUNC_SMBUS_WRITE_BYTE_DATA;}static int w9968cf_i2c_attach_inform(struct i2c_client* client){ struct w9968cf_device* cam = i2c_get_adapdata(client->adapter); int id = client->driver->id, err = 0; if (id == I2C_DRIVERID_OVCAMCHIP) { cam->sensor_client = client; err = w9968cf_sensor_init(cam); if (err) { cam->sensor_client = NULL; return err; } } else { DBG(4, "Rejected client [%s] with driver [%s]", client->name, client->driver->driver.name) return -EINVAL; } DBG(5, "I2C attach client [%s] with driver [%s]", client->name, client->driver->driver.name) return 0;}static int w9968cf_i2c_detach_inform(struct i2c_client* client){ struct w9968cf_device* cam = i2c_get_adapdata(client->adapter); if (cam->sensor_client == client) cam->sensor_client = NULL; DBG(5, "I2C detach client [%s]", client->name) return 0;}static intw9968cf_i2c_control(struct i2c_adapter* adapter, unsigned int cmd, unsigned long arg){ return 0;}static int w9968cf_i2c_init(struct w9968cf_device* cam){ int err = 0; static struct i2c_algorithm algo = { .smbus_xfer = w9968cf_i2c_smbus_xfer, .algo_control = w9968cf_i2c_control, .functionality = w9968cf_i2c_func, }; static struct i2c_adapter adap = { .id = I2C_HW_SMBUS_W9968CF, .class = I2C_CLASS_CAM_DIGITAL, .owner = THIS_MODULE, .client_register = w9968cf_i2c_attach_inform, .client_unregister = w9968cf_i2c_detach_inform, .algo = &algo, }; memcpy(&cam->i2c_adapter, &adap, sizeof(struct i2c_adapter)); strcpy(cam->i2c_adapter.name, "w9968cf"); i2c_set_adapdata(&cam->i2c_adapter, cam); DBG(6, "Registering I2C adapter with kernel...") err = i2c_add_adapter(&cam->i2c_adapter); if (err) DBG(1, "Failed to register the I2C adapter") else DBG(5, "I2C adapter registered") return err;}/****************************************************************************
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -