📄 ivtv-i2c.c
字号:
IVTV_DEBUG_I2C("resetting I2C\n"); for (i = 0; i < 16; ++i) { ivtv_setscl(itv, 0); ivtv_scldelay(itv); ivtv_setscl(itv, 1); ivtv_scldelay(itv); ivtv_setsda(itv, 1); } ivtv_waitsda(itv, 1); return -EREMOTEIO; } return 0;}/* Write a message to the given i2c slave. do_stop may be 0 to prevent issuing the i2c stop condition (when following with a read) */static int ivtv_write(struct ivtv *itv, unsigned char addr, unsigned char *data, u32 len, int do_stop){ int retry, ret = -EREMOTEIO; u32 i; for (retry = 0; ret != 0 && retry < 8; ++retry) { ret = ivtv_start(itv); if (ret == 0) { ret = ivtv_sendbyte(itv, addr<<1); for (i = 0; ret == 0 && i < len; ++i) ret = ivtv_sendbyte(itv, data[i]); } if (ret != 0 || do_stop) { ivtv_stop(itv); } } if (ret) IVTV_DEBUG_I2C("i2c write to %x failed\n", addr); return ret;}/* Read data from the given i2c slave. A stop condition is always issued. */static int ivtv_read(struct ivtv *itv, unsigned char addr, unsigned char *data, u32 len){ int retry, ret = -EREMOTEIO; u32 i; for (retry = 0; ret != 0 && retry < 8; ++retry) { ret = ivtv_start(itv); if (ret == 0) ret = ivtv_sendbyte(itv, (addr << 1) | 1); for (i = 0; ret == 0 && i < len; ++i) { ret = ivtv_readbyte(itv, &data[i], i == len - 1); } ivtv_stop(itv); } if (ret) IVTV_DEBUG_I2C("i2c read from %x failed\n", addr); return ret;}/* Kernel i2c transfer implementation. Takes a number of messages to be read or written. If a read follows a write, this will occur without an intervening stop condition */static int ivtv_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg *msgs, int num){ struct ivtv *itv = i2c_get_adapdata(i2c_adap); int retval; int i; mutex_lock(&itv->i2c_bus_lock); for (i = retval = 0; retval == 0 && i < num; i++) { if (msgs[i].flags & I2C_M_RD) retval = ivtv_read(itv, msgs[i].addr, msgs[i].buf, msgs[i].len); else { /* if followed by a read, don't stop */ int stop = !(i + 1 < num && msgs[i + 1].flags == I2C_M_RD); retval = ivtv_write(itv, msgs[i].addr, msgs[i].buf, msgs[i].len, stop); } } mutex_unlock(&itv->i2c_bus_lock); return retval ? retval : num;}/* Kernel i2c capabilities */static u32 ivtv_functionality(struct i2c_adapter *adap){ return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;}static struct i2c_algorithm ivtv_algo = { .master_xfer = ivtv_xfer, .functionality = ivtv_functionality,};/* template for our-bit banger */static struct i2c_adapter ivtv_i2c_adap_hw_template = { .name = "ivtv i2c driver", .id = I2C_HW_B_CX2341X, .algo = &ivtv_algo, .algo_data = NULL, /* filled from template */ .client_register = attach_inform, .client_unregister = detach_inform, .owner = THIS_MODULE,#ifdef I2C_ADAP_CLASS_TV_ANALOG .class = I2C_ADAP_CLASS_TV_ANALOG,#endif};static void ivtv_setscl_old(void *data, int state){ struct ivtv *itv = (struct ivtv *)data; if (state) itv->i2c_state |= 0x01; else itv->i2c_state &= ~0x01; /* write them out */ /* write bits are inverted */ write_reg(~itv->i2c_state, IVTV_REG_I2C_SETSCL_OFFSET);}static void ivtv_setsda_old(void *data, int state){ struct ivtv *itv = (struct ivtv *)data; if (state) itv->i2c_state |= 0x01; else itv->i2c_state &= ~0x01; /* write them out */ /* write bits are inverted */ write_reg(~itv->i2c_state, IVTV_REG_I2C_SETSDA_OFFSET);}static int ivtv_getscl_old(void *data){ struct ivtv *itv = (struct ivtv *)data; return read_reg(IVTV_REG_I2C_GETSCL_OFFSET) & 1;}static int ivtv_getsda_old(void *data){ struct ivtv *itv = (struct ivtv *)data; return read_reg(IVTV_REG_I2C_GETSDA_OFFSET) & 1;}/* template for i2c-bit-algo */static struct i2c_adapter ivtv_i2c_adap_template = { .name = "ivtv i2c driver", .id = I2C_HW_B_CX2341X, /* algo-bit is OR'd with this */ .algo = NULL, /* set by i2c-algo-bit */ .algo_data = NULL, /* filled from template */ .client_register = attach_inform, .client_unregister = detach_inform, .owner = THIS_MODULE,#ifdef I2C_ADAP_CLASS_TV_ANALOG .class = I2C_ADAP_CLASS_TV_ANALOG,#endif};static const struct i2c_algo_bit_data ivtv_i2c_algo_template = { .setsda = ivtv_setsda_old, .setscl = ivtv_setscl_old, .getsda = ivtv_getsda_old, .getscl = ivtv_getscl_old, .udelay = 10, .timeout = 200,};static struct i2c_client ivtv_i2c_client_template = { .name = "ivtv internal",};int ivtv_call_i2c_client(struct ivtv *itv, int addr, unsigned int cmd, void *arg){ struct i2c_client *client; int retval; int i; IVTV_DEBUG_I2C("call_i2c_client addr=%02x\n", addr); for (i = 0; i < I2C_CLIENTS_MAX; i++) { client = itv->i2c_clients[i]; if (client == NULL) { continue; } if (client->driver->command == NULL) { continue; } if (addr == client->addr) { retval = client->driver->command(client, cmd, arg); return retval; } } if (cmd != VIDIOC_G_CHIP_IDENT) IVTV_ERR("i2c addr 0x%02x not found for command 0x%x\n", addr, cmd); return -ENODEV;}/* Find the i2c device based on the driver ID and return its i2c address or -ENODEV if no matching device was found. */static int ivtv_i2c_id_addr(struct ivtv *itv, u32 id){ struct i2c_client *client; int retval = -ENODEV; int i; for (i = 0; i < I2C_CLIENTS_MAX; i++) { client = itv->i2c_clients[i]; if (client == NULL) continue; if (id == client->driver->id) { retval = client->addr; break; } } return retval;}/* Find the i2c device name matching the DRIVERID */static const char *ivtv_i2c_id_name(u32 id){ int i; for (i = 0; i < ARRAY_SIZE(hw_driverids); i++) if (hw_driverids[i] == id) return hw_drivernames[i]; return "unknown device";}/* Find the i2c device name matching the IVTV_HW_ flag */static const char *ivtv_i2c_hw_name(u32 hw){ int i; for (i = 0; i < ARRAY_SIZE(hw_driverids); i++) if (1 << i == hw) return hw_drivernames[i]; return "unknown device";}/* Find the i2c device matching the IVTV_HW_ flag and return its i2c address or -ENODEV if no matching device was found. */int ivtv_i2c_hw_addr(struct ivtv *itv, u32 hw){ int i; for (i = 0; i < ARRAY_SIZE(hw_driverids); i++) if (1 << i == hw) return ivtv_i2c_id_addr(itv, hw_driverids[i]); return -ENODEV;}/* Calls i2c device based on IVTV_HW_ flag. If hw == 0, then do nothing. If hw == IVTV_HW_GPIO then call the gpio handler. */int ivtv_i2c_hw(struct ivtv *itv, u32 hw, unsigned int cmd, void *arg){ int addr; if (hw == IVTV_HW_GPIO) return ivtv_gpio(itv, cmd, arg); if (hw == 0) return 0; addr = ivtv_i2c_hw_addr(itv, hw); if (addr < 0) { IVTV_ERR("i2c hardware 0x%08x (%s) not found for command 0x%x\n", hw, ivtv_i2c_hw_name(hw), cmd); return addr; } return ivtv_call_i2c_client(itv, addr, cmd, arg);}/* Calls i2c device based on I2C driver ID. */int ivtv_i2c_id(struct ivtv *itv, u32 id, unsigned int cmd, void *arg){ int addr; addr = ivtv_i2c_id_addr(itv, id); if (addr < 0) { if (cmd != VIDIOC_G_CHIP_IDENT) IVTV_ERR("i2c ID 0x%08x (%s) not found for command 0x%x\n", id, ivtv_i2c_id_name(id), cmd); return addr; } return ivtv_call_i2c_client(itv, addr, cmd, arg);}int ivtv_cx25840(struct ivtv *itv, unsigned int cmd, void *arg){ return ivtv_call_i2c_client(itv, IVTV_CX25840_I2C_ADDR, cmd, arg);}int ivtv_saa7115(struct ivtv *itv, unsigned int cmd, void *arg){ return ivtv_call_i2c_client(itv, IVTV_SAA7115_I2C_ADDR, cmd, arg);}int ivtv_saa7127(struct ivtv *itv, unsigned int cmd, void *arg){ return ivtv_call_i2c_client(itv, IVTV_SAA7127_I2C_ADDR, cmd, arg);}int ivtv_saa717x(struct ivtv *itv, unsigned int cmd, void *arg){ return ivtv_call_i2c_client(itv, IVTV_SAA717x_I2C_ADDR, cmd, arg);}int ivtv_upd64031a(struct ivtv *itv, unsigned int cmd, void *arg){ return ivtv_call_i2c_client(itv, IVTV_UPD64031A_I2C_ADDR, cmd, arg);}int ivtv_upd64083(struct ivtv *itv, unsigned int cmd, void *arg){ return ivtv_call_i2c_client(itv, IVTV_UPD64083_I2C_ADDR, cmd, arg);}/* broadcast cmd for all I2C clients and for the gpio subsystem */void ivtv_call_i2c_clients(struct ivtv *itv, unsigned int cmd, void *arg){ if (itv->i2c_adap.algo == NULL) { IVTV_ERR("Adapter is not set"); return; } i2c_clients_command(&itv->i2c_adap, cmd, arg); if (itv->hw_flags & IVTV_HW_GPIO) ivtv_gpio(itv, cmd, arg);}/* init + register i2c algo-bit adapter */int init_ivtv_i2c(struct ivtv *itv){ IVTV_DEBUG_I2C("i2c init\n"); if (itv->options.newi2c > 0) { memcpy(&itv->i2c_adap, &ivtv_i2c_adap_hw_template, sizeof(struct i2c_adapter)); } else { memcpy(&itv->i2c_adap, &ivtv_i2c_adap_template, sizeof(struct i2c_adapter)); memcpy(&itv->i2c_algo, &ivtv_i2c_algo_template, sizeof(struct i2c_algo_bit_data)); itv->i2c_algo.data = itv; itv->i2c_adap.algo_data = &itv->i2c_algo; } sprintf(itv->i2c_adap.name + strlen(itv->i2c_adap.name), " #%d", itv->num); i2c_set_adapdata(&itv->i2c_adap, itv); memcpy(&itv->i2c_client, &ivtv_i2c_client_template, sizeof(struct i2c_client)); itv->i2c_client.adapter = &itv->i2c_adap; itv->i2c_adap.dev.parent = &itv->dev->dev; IVTV_DEBUG_I2C("setting scl and sda to 1\n"); ivtv_setscl(itv, 1); ivtv_setsda(itv, 1); if (itv->options.newi2c > 0) return i2c_add_adapter(&itv->i2c_adap); else return i2c_bit_add_bus(&itv->i2c_adap);}void exit_ivtv_i2c(struct ivtv *itv){ IVTV_DEBUG_I2C("i2c exit\n"); i2c_del_adapter(&itv->i2c_adap);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -