162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci I2C functions 462306a36Sopenharmony_ci Copyright (C) 2003-2004 Kevin Thayer <nufan_wfk at yahoo.com> 562306a36Sopenharmony_ci Copyright (C) 2005-2007 Hans Verkuil <hverkuil@xs4all.nl> 662306a36Sopenharmony_ci 762306a36Sopenharmony_ci */ 862306a36Sopenharmony_ci 962306a36Sopenharmony_ci/* 1062306a36Sopenharmony_ci This file includes an i2c implementation that was reverse engineered 1162306a36Sopenharmony_ci from the Hauppauge windows driver. Older ivtv versions used i2c-algo-bit, 1262306a36Sopenharmony_ci which whilst fine under most circumstances, had trouble with the Zilog 1362306a36Sopenharmony_ci CPU on the PVR-150 which handles IR functions (occasional inability to 1462306a36Sopenharmony_ci communicate with the chip until it was reset) and also with the i2c 1562306a36Sopenharmony_ci bus being completely unreachable when multiple PVR cards were present. 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_ci The implementation is very similar to i2c-algo-bit, but there are enough 1862306a36Sopenharmony_ci subtle differences that the two are hard to merge. The general strategy 1962306a36Sopenharmony_ci employed by i2c-algo-bit is to use udelay() to implement the timing 2062306a36Sopenharmony_ci when putting out bits on the scl/sda lines. The general strategy taken 2162306a36Sopenharmony_ci here is to poll the lines for state changes (see ivtv_waitscl and 2262306a36Sopenharmony_ci ivtv_waitsda). In addition there are small delays at various locations 2362306a36Sopenharmony_ci which poll the SCL line 5 times (ivtv_scldelay). I would guess that 2462306a36Sopenharmony_ci since this is memory mapped I/O that the length of those delays is tied 2562306a36Sopenharmony_ci to the PCI bus clock. There is some extra code to do with recovery 2662306a36Sopenharmony_ci and retries. Since it is not known what causes the actual i2c problems 2762306a36Sopenharmony_ci in the first place, the only goal if one was to attempt to use 2862306a36Sopenharmony_ci i2c-algo-bit would be to try to make it follow the same code path. 2962306a36Sopenharmony_ci This would be a lot of work, and I'm also not convinced that it would 3062306a36Sopenharmony_ci provide a generic benefit to i2c-algo-bit. Therefore consider this 3162306a36Sopenharmony_ci an engineering solution -- not pretty, but it works. 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_ci Some more general comments about what we are doing: 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_ci The i2c bus is a 2 wire serial bus, with clock (SCL) and data (SDA) 3662306a36Sopenharmony_ci lines. To communicate on the bus (as a master, we don't act as a slave), 3762306a36Sopenharmony_ci we first initiate a start condition (ivtv_start). We then write the 3862306a36Sopenharmony_ci address of the device that we want to communicate with, along with a flag 3962306a36Sopenharmony_ci that indicates whether this is a read or a write. The slave then issues 4062306a36Sopenharmony_ci an ACK signal (ivtv_ack), which tells us that it is ready for reading / 4162306a36Sopenharmony_ci writing. We then proceed with reading or writing (ivtv_read/ivtv_write), 4262306a36Sopenharmony_ci and finally issue a stop condition (ivtv_stop) to make the bus available 4362306a36Sopenharmony_ci to other masters. 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_ci There is an additional form of transaction where a write may be 4662306a36Sopenharmony_ci immediately followed by a read. In this case, there is no intervening 4762306a36Sopenharmony_ci stop condition. (Only the msp3400 chip uses this method of data transfer). 4862306a36Sopenharmony_ci */ 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_ci#include "ivtv-driver.h" 5162306a36Sopenharmony_ci#include "ivtv-cards.h" 5262306a36Sopenharmony_ci#include "ivtv-gpio.h" 5362306a36Sopenharmony_ci#include "ivtv-i2c.h" 5462306a36Sopenharmony_ci#include <media/drv-intf/cx25840.h> 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_ci/* i2c implementation for cx23415/6 chip, ivtv project. 5762306a36Sopenharmony_ci * Author: Kevin Thayer (nufan_wfk at yahoo.com) 5862306a36Sopenharmony_ci */ 5962306a36Sopenharmony_ci/* i2c stuff */ 6062306a36Sopenharmony_ci#define IVTV_REG_I2C_SETSCL_OFFSET 0x7000 6162306a36Sopenharmony_ci#define IVTV_REG_I2C_SETSDA_OFFSET 0x7004 6262306a36Sopenharmony_ci#define IVTV_REG_I2C_GETSCL_OFFSET 0x7008 6362306a36Sopenharmony_ci#define IVTV_REG_I2C_GETSDA_OFFSET 0x700c 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_ci#define IVTV_CS53L32A_I2C_ADDR 0x11 6662306a36Sopenharmony_ci#define IVTV_M52790_I2C_ADDR 0x48 6762306a36Sopenharmony_ci#define IVTV_CX25840_I2C_ADDR 0x44 6862306a36Sopenharmony_ci#define IVTV_SAA7115_I2C_ADDR 0x21 6962306a36Sopenharmony_ci#define IVTV_SAA7127_I2C_ADDR 0x44 7062306a36Sopenharmony_ci#define IVTV_SAA717x_I2C_ADDR 0x21 7162306a36Sopenharmony_ci#define IVTV_MSP3400_I2C_ADDR 0x40 7262306a36Sopenharmony_ci#define IVTV_HAUPPAUGE_I2C_ADDR 0x50 7362306a36Sopenharmony_ci#define IVTV_WM8739_I2C_ADDR 0x1a 7462306a36Sopenharmony_ci#define IVTV_WM8775_I2C_ADDR 0x1b 7562306a36Sopenharmony_ci#define IVTV_TEA5767_I2C_ADDR 0x60 7662306a36Sopenharmony_ci#define IVTV_UPD64031A_I2C_ADDR 0x12 7762306a36Sopenharmony_ci#define IVTV_UPD64083_I2C_ADDR 0x5c 7862306a36Sopenharmony_ci#define IVTV_VP27SMPX_I2C_ADDR 0x5b 7962306a36Sopenharmony_ci#define IVTV_M52790_I2C_ADDR 0x48 8062306a36Sopenharmony_ci#define IVTV_AVERMEDIA_IR_RX_I2C_ADDR 0x40 8162306a36Sopenharmony_ci#define IVTV_HAUP_EXT_IR_RX_I2C_ADDR 0x1a 8262306a36Sopenharmony_ci#define IVTV_HAUP_INT_IR_RX_I2C_ADDR 0x18 8362306a36Sopenharmony_ci#define IVTV_Z8F0811_IR_TX_I2C_ADDR 0x70 8462306a36Sopenharmony_ci#define IVTV_Z8F0811_IR_RX_I2C_ADDR 0x71 8562306a36Sopenharmony_ci#define IVTV_ADAPTEC_IR_ADDR 0x6b 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_ci/* This array should match the IVTV_HW_ defines */ 8862306a36Sopenharmony_cistatic const u8 hw_addrs[IVTV_HW_MAX_BITS] = { 8962306a36Sopenharmony_ci IVTV_CX25840_I2C_ADDR, 9062306a36Sopenharmony_ci IVTV_SAA7115_I2C_ADDR, 9162306a36Sopenharmony_ci IVTV_SAA7127_I2C_ADDR, 9262306a36Sopenharmony_ci IVTV_MSP3400_I2C_ADDR, 9362306a36Sopenharmony_ci 0, 9462306a36Sopenharmony_ci IVTV_WM8775_I2C_ADDR, 9562306a36Sopenharmony_ci IVTV_CS53L32A_I2C_ADDR, 9662306a36Sopenharmony_ci 0, 9762306a36Sopenharmony_ci IVTV_SAA7115_I2C_ADDR, 9862306a36Sopenharmony_ci IVTV_UPD64031A_I2C_ADDR, 9962306a36Sopenharmony_ci IVTV_UPD64083_I2C_ADDR, 10062306a36Sopenharmony_ci IVTV_SAA717x_I2C_ADDR, 10162306a36Sopenharmony_ci IVTV_WM8739_I2C_ADDR, 10262306a36Sopenharmony_ci IVTV_VP27SMPX_I2C_ADDR, 10362306a36Sopenharmony_ci IVTV_M52790_I2C_ADDR, 10462306a36Sopenharmony_ci 0, /* IVTV_HW_GPIO dummy driver ID */ 10562306a36Sopenharmony_ci IVTV_AVERMEDIA_IR_RX_I2C_ADDR, /* IVTV_HW_I2C_IR_RX_AVER */ 10662306a36Sopenharmony_ci IVTV_HAUP_EXT_IR_RX_I2C_ADDR, /* IVTV_HW_I2C_IR_RX_HAUP_EXT */ 10762306a36Sopenharmony_ci IVTV_HAUP_INT_IR_RX_I2C_ADDR, /* IVTV_HW_I2C_IR_RX_HAUP_INT */ 10862306a36Sopenharmony_ci IVTV_Z8F0811_IR_RX_I2C_ADDR, /* IVTV_HW_Z8F0811_IR_HAUP */ 10962306a36Sopenharmony_ci IVTV_ADAPTEC_IR_ADDR, /* IVTV_HW_I2C_IR_RX_ADAPTEC */ 11062306a36Sopenharmony_ci}; 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_ci/* This array should match the IVTV_HW_ defines */ 11362306a36Sopenharmony_cistatic const char * const hw_devicenames[IVTV_HW_MAX_BITS] = { 11462306a36Sopenharmony_ci "cx25840", 11562306a36Sopenharmony_ci "saa7115", 11662306a36Sopenharmony_ci "saa7127_auto", /* saa7127 or saa7129 */ 11762306a36Sopenharmony_ci "msp3400", 11862306a36Sopenharmony_ci "tuner", 11962306a36Sopenharmony_ci "wm8775", 12062306a36Sopenharmony_ci "cs53l32a", 12162306a36Sopenharmony_ci "tveeprom", 12262306a36Sopenharmony_ci "saa7114", 12362306a36Sopenharmony_ci "upd64031a", 12462306a36Sopenharmony_ci "upd64083", 12562306a36Sopenharmony_ci "saa717x", 12662306a36Sopenharmony_ci "wm8739", 12762306a36Sopenharmony_ci "vp27smpx", 12862306a36Sopenharmony_ci "m52790", 12962306a36Sopenharmony_ci "gpio", 13062306a36Sopenharmony_ci "ir_video", /* IVTV_HW_I2C_IR_RX_AVER */ 13162306a36Sopenharmony_ci "ir_video", /* IVTV_HW_I2C_IR_RX_HAUP_EXT */ 13262306a36Sopenharmony_ci "ir_video", /* IVTV_HW_I2C_IR_RX_HAUP_INT */ 13362306a36Sopenharmony_ci "ir_z8f0811_haup", /* IVTV_HW_Z8F0811_IR_HAUP */ 13462306a36Sopenharmony_ci "ir_video", /* IVTV_HW_I2C_IR_RX_ADAPTEC */ 13562306a36Sopenharmony_ci}; 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_cistatic int get_key_adaptec(struct IR_i2c *ir, enum rc_proto *protocol, 13862306a36Sopenharmony_ci u32 *scancode, u8 *toggle) 13962306a36Sopenharmony_ci{ 14062306a36Sopenharmony_ci unsigned char keybuf[4]; 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_ci keybuf[0] = 0x00; 14362306a36Sopenharmony_ci i2c_master_send(ir->c, keybuf, 1); 14462306a36Sopenharmony_ci /* poll IR chip */ 14562306a36Sopenharmony_ci if (i2c_master_recv(ir->c, keybuf, sizeof(keybuf)) != sizeof(keybuf)) { 14662306a36Sopenharmony_ci return 0; 14762306a36Sopenharmony_ci } 14862306a36Sopenharmony_ci 14962306a36Sopenharmony_ci /* key pressed ? */ 15062306a36Sopenharmony_ci if (keybuf[2] == 0xff) 15162306a36Sopenharmony_ci return 0; 15262306a36Sopenharmony_ci 15362306a36Sopenharmony_ci /* remove repeat bit */ 15462306a36Sopenharmony_ci keybuf[2] &= 0x7f; 15562306a36Sopenharmony_ci keybuf[3] |= 0x80; 15662306a36Sopenharmony_ci 15762306a36Sopenharmony_ci *protocol = RC_PROTO_UNKNOWN; 15862306a36Sopenharmony_ci *scancode = keybuf[3] | keybuf[2] << 8 | keybuf[1] << 16 |keybuf[0] << 24; 15962306a36Sopenharmony_ci *toggle = 0; 16062306a36Sopenharmony_ci return 1; 16162306a36Sopenharmony_ci} 16262306a36Sopenharmony_ci 16362306a36Sopenharmony_cistatic int ivtv_i2c_new_ir(struct ivtv *itv, u32 hw, const char *type, u8 addr) 16462306a36Sopenharmony_ci{ 16562306a36Sopenharmony_ci struct i2c_board_info info; 16662306a36Sopenharmony_ci struct i2c_adapter *adap = &itv->i2c_adap; 16762306a36Sopenharmony_ci struct IR_i2c_init_data *init_data = &itv->ir_i2c_init_data; 16862306a36Sopenharmony_ci unsigned short addr_list[2] = { addr, I2C_CLIENT_END }; 16962306a36Sopenharmony_ci 17062306a36Sopenharmony_ci /* Only allow one IR receiver to be registered per board */ 17162306a36Sopenharmony_ci if (itv->hw_flags & IVTV_HW_IR_ANY) 17262306a36Sopenharmony_ci return -1; 17362306a36Sopenharmony_ci 17462306a36Sopenharmony_ci /* Our default information for ir-kbd-i2c.c to use */ 17562306a36Sopenharmony_ci switch (hw) { 17662306a36Sopenharmony_ci case IVTV_HW_I2C_IR_RX_AVER: 17762306a36Sopenharmony_ci init_data->ir_codes = RC_MAP_AVERMEDIA_CARDBUS; 17862306a36Sopenharmony_ci init_data->internal_get_key_func = 17962306a36Sopenharmony_ci IR_KBD_GET_KEY_AVERMEDIA_CARDBUS; 18062306a36Sopenharmony_ci init_data->type = RC_PROTO_BIT_OTHER; 18162306a36Sopenharmony_ci init_data->name = "AVerMedia AVerTV card"; 18262306a36Sopenharmony_ci break; 18362306a36Sopenharmony_ci case IVTV_HW_I2C_IR_RX_HAUP_EXT: 18462306a36Sopenharmony_ci case IVTV_HW_I2C_IR_RX_HAUP_INT: 18562306a36Sopenharmony_ci init_data->ir_codes = RC_MAP_HAUPPAUGE; 18662306a36Sopenharmony_ci init_data->internal_get_key_func = IR_KBD_GET_KEY_HAUP; 18762306a36Sopenharmony_ci init_data->type = RC_PROTO_BIT_RC5; 18862306a36Sopenharmony_ci init_data->name = itv->card_name; 18962306a36Sopenharmony_ci break; 19062306a36Sopenharmony_ci case IVTV_HW_Z8F0811_IR_HAUP: 19162306a36Sopenharmony_ci /* Default to grey remote */ 19262306a36Sopenharmony_ci init_data->ir_codes = RC_MAP_HAUPPAUGE; 19362306a36Sopenharmony_ci init_data->internal_get_key_func = IR_KBD_GET_KEY_HAUP_XVR; 19462306a36Sopenharmony_ci init_data->type = RC_PROTO_BIT_RC5 | RC_PROTO_BIT_RC6_MCE | 19562306a36Sopenharmony_ci RC_PROTO_BIT_RC6_6A_32; 19662306a36Sopenharmony_ci init_data->name = itv->card_name; 19762306a36Sopenharmony_ci break; 19862306a36Sopenharmony_ci case IVTV_HW_I2C_IR_RX_ADAPTEC: 19962306a36Sopenharmony_ci init_data->get_key = get_key_adaptec; 20062306a36Sopenharmony_ci init_data->name = itv->card_name; 20162306a36Sopenharmony_ci /* FIXME: The protocol and RC_MAP needs to be corrected */ 20262306a36Sopenharmony_ci init_data->ir_codes = RC_MAP_EMPTY; 20362306a36Sopenharmony_ci init_data->type = RC_PROTO_BIT_UNKNOWN; 20462306a36Sopenharmony_ci break; 20562306a36Sopenharmony_ci } 20662306a36Sopenharmony_ci 20762306a36Sopenharmony_ci memset(&info, 0, sizeof(struct i2c_board_info)); 20862306a36Sopenharmony_ci info.platform_data = init_data; 20962306a36Sopenharmony_ci strscpy(info.type, type, I2C_NAME_SIZE); 21062306a36Sopenharmony_ci 21162306a36Sopenharmony_ci return IS_ERR(i2c_new_scanned_device(adap, &info, addr_list, NULL)) ? 21262306a36Sopenharmony_ci -1 : 0; 21362306a36Sopenharmony_ci} 21462306a36Sopenharmony_ci 21562306a36Sopenharmony_ci/* Instantiate the IR receiver device using probing -- undesirable */ 21662306a36Sopenharmony_civoid ivtv_i2c_new_ir_legacy(struct ivtv *itv) 21762306a36Sopenharmony_ci{ 21862306a36Sopenharmony_ci struct i2c_board_info info; 21962306a36Sopenharmony_ci /* 22062306a36Sopenharmony_ci * The external IR receiver is at i2c address 0x34. 22162306a36Sopenharmony_ci * The internal IR receiver is at i2c address 0x30. 22262306a36Sopenharmony_ci * 22362306a36Sopenharmony_ci * In theory, both can be fitted, and Hauppauge suggests an external 22462306a36Sopenharmony_ci * overrides an internal. That's why we probe 0x1a (~0x34) first. CB 22562306a36Sopenharmony_ci * 22662306a36Sopenharmony_ci * Some of these addresses we probe may collide with other i2c address 22762306a36Sopenharmony_ci * allocations, so this function must be called after all other i2c 22862306a36Sopenharmony_ci * devices we care about are registered. 22962306a36Sopenharmony_ci */ 23062306a36Sopenharmony_ci static const unsigned short addr_list[] = { 23162306a36Sopenharmony_ci 0x1a, /* Hauppauge IR external - collides with WM8739 */ 23262306a36Sopenharmony_ci 0x18, /* Hauppauge IR internal */ 23362306a36Sopenharmony_ci I2C_CLIENT_END 23462306a36Sopenharmony_ci }; 23562306a36Sopenharmony_ci 23662306a36Sopenharmony_ci memset(&info, 0, sizeof(struct i2c_board_info)); 23762306a36Sopenharmony_ci strscpy(info.type, "ir_video", I2C_NAME_SIZE); 23862306a36Sopenharmony_ci i2c_new_scanned_device(&itv->i2c_adap, &info, addr_list, NULL); 23962306a36Sopenharmony_ci} 24062306a36Sopenharmony_ci 24162306a36Sopenharmony_ciint ivtv_i2c_register(struct ivtv *itv, unsigned idx) 24262306a36Sopenharmony_ci{ 24362306a36Sopenharmony_ci struct i2c_adapter *adap = &itv->i2c_adap; 24462306a36Sopenharmony_ci struct v4l2_subdev *sd; 24562306a36Sopenharmony_ci const char *type; 24662306a36Sopenharmony_ci u32 hw; 24762306a36Sopenharmony_ci 24862306a36Sopenharmony_ci if (idx >= IVTV_HW_MAX_BITS) 24962306a36Sopenharmony_ci return -ENODEV; 25062306a36Sopenharmony_ci 25162306a36Sopenharmony_ci type = hw_devicenames[idx]; 25262306a36Sopenharmony_ci hw = 1 << idx; 25362306a36Sopenharmony_ci 25462306a36Sopenharmony_ci if (hw == IVTV_HW_TUNER) { 25562306a36Sopenharmony_ci /* special tuner handling */ 25662306a36Sopenharmony_ci sd = v4l2_i2c_new_subdev(&itv->v4l2_dev, adap, type, 0, 25762306a36Sopenharmony_ci itv->card_i2c->radio); 25862306a36Sopenharmony_ci if (sd) 25962306a36Sopenharmony_ci sd->grp_id = 1 << idx; 26062306a36Sopenharmony_ci sd = v4l2_i2c_new_subdev(&itv->v4l2_dev, adap, type, 0, 26162306a36Sopenharmony_ci itv->card_i2c->demod); 26262306a36Sopenharmony_ci if (sd) 26362306a36Sopenharmony_ci sd->grp_id = 1 << idx; 26462306a36Sopenharmony_ci sd = v4l2_i2c_new_subdev(&itv->v4l2_dev, adap, type, 0, 26562306a36Sopenharmony_ci itv->card_i2c->tv); 26662306a36Sopenharmony_ci if (sd) 26762306a36Sopenharmony_ci sd->grp_id = 1 << idx; 26862306a36Sopenharmony_ci return sd ? 0 : -1; 26962306a36Sopenharmony_ci } 27062306a36Sopenharmony_ci 27162306a36Sopenharmony_ci if (hw & IVTV_HW_IR_ANY) 27262306a36Sopenharmony_ci return ivtv_i2c_new_ir(itv, hw, type, hw_addrs[idx]); 27362306a36Sopenharmony_ci 27462306a36Sopenharmony_ci /* Is it not an I2C device or one we do not wish to register? */ 27562306a36Sopenharmony_ci if (!hw_addrs[idx]) 27662306a36Sopenharmony_ci return -1; 27762306a36Sopenharmony_ci 27862306a36Sopenharmony_ci /* It's an I2C device other than an analog tuner or IR chip */ 27962306a36Sopenharmony_ci if (hw == IVTV_HW_UPD64031A || hw == IVTV_HW_UPD6408X) { 28062306a36Sopenharmony_ci sd = v4l2_i2c_new_subdev(&itv->v4l2_dev, 28162306a36Sopenharmony_ci adap, type, 0, I2C_ADDRS(hw_addrs[idx])); 28262306a36Sopenharmony_ci } else if (hw == IVTV_HW_CX25840) { 28362306a36Sopenharmony_ci struct cx25840_platform_data pdata; 28462306a36Sopenharmony_ci struct i2c_board_info cx25840_info = { 28562306a36Sopenharmony_ci .type = "cx25840", 28662306a36Sopenharmony_ci .addr = hw_addrs[idx], 28762306a36Sopenharmony_ci .platform_data = &pdata, 28862306a36Sopenharmony_ci }; 28962306a36Sopenharmony_ci 29062306a36Sopenharmony_ci memset(&pdata, 0, sizeof(pdata)); 29162306a36Sopenharmony_ci pdata.pvr150_workaround = itv->pvr150_workaround; 29262306a36Sopenharmony_ci sd = v4l2_i2c_new_subdev_board(&itv->v4l2_dev, adap, 29362306a36Sopenharmony_ci &cx25840_info, NULL); 29462306a36Sopenharmony_ci } else { 29562306a36Sopenharmony_ci sd = v4l2_i2c_new_subdev(&itv->v4l2_dev, 29662306a36Sopenharmony_ci adap, type, hw_addrs[idx], NULL); 29762306a36Sopenharmony_ci } 29862306a36Sopenharmony_ci if (sd) 29962306a36Sopenharmony_ci sd->grp_id = 1 << idx; 30062306a36Sopenharmony_ci return sd ? 0 : -1; 30162306a36Sopenharmony_ci} 30262306a36Sopenharmony_ci 30362306a36Sopenharmony_cistruct v4l2_subdev *ivtv_find_hw(struct ivtv *itv, u32 hw) 30462306a36Sopenharmony_ci{ 30562306a36Sopenharmony_ci struct v4l2_subdev *result = NULL; 30662306a36Sopenharmony_ci struct v4l2_subdev *sd; 30762306a36Sopenharmony_ci 30862306a36Sopenharmony_ci spin_lock(&itv->v4l2_dev.lock); 30962306a36Sopenharmony_ci v4l2_device_for_each_subdev(sd, &itv->v4l2_dev) { 31062306a36Sopenharmony_ci if (sd->grp_id == hw) { 31162306a36Sopenharmony_ci result = sd; 31262306a36Sopenharmony_ci break; 31362306a36Sopenharmony_ci } 31462306a36Sopenharmony_ci } 31562306a36Sopenharmony_ci spin_unlock(&itv->v4l2_dev.lock); 31662306a36Sopenharmony_ci return result; 31762306a36Sopenharmony_ci} 31862306a36Sopenharmony_ci 31962306a36Sopenharmony_ci/* Set the serial clock line to the desired state */ 32062306a36Sopenharmony_cistatic void ivtv_setscl(struct ivtv *itv, int state) 32162306a36Sopenharmony_ci{ 32262306a36Sopenharmony_ci /* write them out */ 32362306a36Sopenharmony_ci /* write bits are inverted */ 32462306a36Sopenharmony_ci write_reg(~state, IVTV_REG_I2C_SETSCL_OFFSET); 32562306a36Sopenharmony_ci} 32662306a36Sopenharmony_ci 32762306a36Sopenharmony_ci/* Set the serial data line to the desired state */ 32862306a36Sopenharmony_cistatic void ivtv_setsda(struct ivtv *itv, int state) 32962306a36Sopenharmony_ci{ 33062306a36Sopenharmony_ci /* write them out */ 33162306a36Sopenharmony_ci /* write bits are inverted */ 33262306a36Sopenharmony_ci write_reg(~state & 1, IVTV_REG_I2C_SETSDA_OFFSET); 33362306a36Sopenharmony_ci} 33462306a36Sopenharmony_ci 33562306a36Sopenharmony_ci/* Read the serial clock line */ 33662306a36Sopenharmony_cistatic int ivtv_getscl(struct ivtv *itv) 33762306a36Sopenharmony_ci{ 33862306a36Sopenharmony_ci return read_reg(IVTV_REG_I2C_GETSCL_OFFSET) & 1; 33962306a36Sopenharmony_ci} 34062306a36Sopenharmony_ci 34162306a36Sopenharmony_ci/* Read the serial data line */ 34262306a36Sopenharmony_cistatic int ivtv_getsda(struct ivtv *itv) 34362306a36Sopenharmony_ci{ 34462306a36Sopenharmony_ci return read_reg(IVTV_REG_I2C_GETSDA_OFFSET) & 1; 34562306a36Sopenharmony_ci} 34662306a36Sopenharmony_ci 34762306a36Sopenharmony_ci/* Implement a short delay by polling the serial clock line */ 34862306a36Sopenharmony_cistatic void ivtv_scldelay(struct ivtv *itv) 34962306a36Sopenharmony_ci{ 35062306a36Sopenharmony_ci int i; 35162306a36Sopenharmony_ci 35262306a36Sopenharmony_ci for (i = 0; i < 5; ++i) 35362306a36Sopenharmony_ci ivtv_getscl(itv); 35462306a36Sopenharmony_ci} 35562306a36Sopenharmony_ci 35662306a36Sopenharmony_ci/* Wait for the serial clock line to become set to a specific value */ 35762306a36Sopenharmony_cistatic int ivtv_waitscl(struct ivtv *itv, int val) 35862306a36Sopenharmony_ci{ 35962306a36Sopenharmony_ci int i; 36062306a36Sopenharmony_ci 36162306a36Sopenharmony_ci ivtv_scldelay(itv); 36262306a36Sopenharmony_ci for (i = 0; i < 1000; ++i) { 36362306a36Sopenharmony_ci if (ivtv_getscl(itv) == val) 36462306a36Sopenharmony_ci return 1; 36562306a36Sopenharmony_ci } 36662306a36Sopenharmony_ci return 0; 36762306a36Sopenharmony_ci} 36862306a36Sopenharmony_ci 36962306a36Sopenharmony_ci/* Wait for the serial data line to become set to a specific value */ 37062306a36Sopenharmony_cistatic int ivtv_waitsda(struct ivtv *itv, int val) 37162306a36Sopenharmony_ci{ 37262306a36Sopenharmony_ci int i; 37362306a36Sopenharmony_ci 37462306a36Sopenharmony_ci ivtv_scldelay(itv); 37562306a36Sopenharmony_ci for (i = 0; i < 1000; ++i) { 37662306a36Sopenharmony_ci if (ivtv_getsda(itv) == val) 37762306a36Sopenharmony_ci return 1; 37862306a36Sopenharmony_ci } 37962306a36Sopenharmony_ci return 0; 38062306a36Sopenharmony_ci} 38162306a36Sopenharmony_ci 38262306a36Sopenharmony_ci/* Wait for the slave to issue an ACK */ 38362306a36Sopenharmony_cistatic int ivtv_ack(struct ivtv *itv) 38462306a36Sopenharmony_ci{ 38562306a36Sopenharmony_ci int ret = 0; 38662306a36Sopenharmony_ci 38762306a36Sopenharmony_ci if (ivtv_getscl(itv) == 1) { 38862306a36Sopenharmony_ci IVTV_DEBUG_HI_I2C("SCL was high starting an ack\n"); 38962306a36Sopenharmony_ci ivtv_setscl(itv, 0); 39062306a36Sopenharmony_ci if (!ivtv_waitscl(itv, 0)) { 39162306a36Sopenharmony_ci IVTV_DEBUG_I2C("Could not set SCL low starting an ack\n"); 39262306a36Sopenharmony_ci return -EREMOTEIO; 39362306a36Sopenharmony_ci } 39462306a36Sopenharmony_ci } 39562306a36Sopenharmony_ci ivtv_setsda(itv, 1); 39662306a36Sopenharmony_ci ivtv_scldelay(itv); 39762306a36Sopenharmony_ci ivtv_setscl(itv, 1); 39862306a36Sopenharmony_ci if (!ivtv_waitsda(itv, 0)) { 39962306a36Sopenharmony_ci IVTV_DEBUG_I2C("Slave did not ack\n"); 40062306a36Sopenharmony_ci ret = -EREMOTEIO; 40162306a36Sopenharmony_ci } 40262306a36Sopenharmony_ci ivtv_setscl(itv, 0); 40362306a36Sopenharmony_ci if (!ivtv_waitscl(itv, 0)) { 40462306a36Sopenharmony_ci IVTV_DEBUG_I2C("Failed to set SCL low after ACK\n"); 40562306a36Sopenharmony_ci ret = -EREMOTEIO; 40662306a36Sopenharmony_ci } 40762306a36Sopenharmony_ci return ret; 40862306a36Sopenharmony_ci} 40962306a36Sopenharmony_ci 41062306a36Sopenharmony_ci/* Write a single byte to the i2c bus and wait for the slave to ACK */ 41162306a36Sopenharmony_cistatic int ivtv_sendbyte(struct ivtv *itv, unsigned char byte) 41262306a36Sopenharmony_ci{ 41362306a36Sopenharmony_ci int i, bit; 41462306a36Sopenharmony_ci 41562306a36Sopenharmony_ci IVTV_DEBUG_HI_I2C("write %x\n",byte); 41662306a36Sopenharmony_ci for (i = 0; i < 8; ++i, byte<<=1) { 41762306a36Sopenharmony_ci ivtv_setscl(itv, 0); 41862306a36Sopenharmony_ci if (!ivtv_waitscl(itv, 0)) { 41962306a36Sopenharmony_ci IVTV_DEBUG_I2C("Error setting SCL low\n"); 42062306a36Sopenharmony_ci return -EREMOTEIO; 42162306a36Sopenharmony_ci } 42262306a36Sopenharmony_ci bit = (byte>>7)&1; 42362306a36Sopenharmony_ci ivtv_setsda(itv, bit); 42462306a36Sopenharmony_ci if (!ivtv_waitsda(itv, bit)) { 42562306a36Sopenharmony_ci IVTV_DEBUG_I2C("Error setting SDA\n"); 42662306a36Sopenharmony_ci return -EREMOTEIO; 42762306a36Sopenharmony_ci } 42862306a36Sopenharmony_ci ivtv_setscl(itv, 1); 42962306a36Sopenharmony_ci if (!ivtv_waitscl(itv, 1)) { 43062306a36Sopenharmony_ci IVTV_DEBUG_I2C("Slave not ready for bit\n"); 43162306a36Sopenharmony_ci return -EREMOTEIO; 43262306a36Sopenharmony_ci } 43362306a36Sopenharmony_ci } 43462306a36Sopenharmony_ci ivtv_setscl(itv, 0); 43562306a36Sopenharmony_ci if (!ivtv_waitscl(itv, 0)) { 43662306a36Sopenharmony_ci IVTV_DEBUG_I2C("Error setting SCL low\n"); 43762306a36Sopenharmony_ci return -EREMOTEIO; 43862306a36Sopenharmony_ci } 43962306a36Sopenharmony_ci return ivtv_ack(itv); 44062306a36Sopenharmony_ci} 44162306a36Sopenharmony_ci 44262306a36Sopenharmony_ci/* Read a byte from the i2c bus and send a NACK if applicable (i.e. for the 44362306a36Sopenharmony_ci final byte) */ 44462306a36Sopenharmony_cistatic int ivtv_readbyte(struct ivtv *itv, unsigned char *byte, int nack) 44562306a36Sopenharmony_ci{ 44662306a36Sopenharmony_ci int i; 44762306a36Sopenharmony_ci 44862306a36Sopenharmony_ci *byte = 0; 44962306a36Sopenharmony_ci 45062306a36Sopenharmony_ci ivtv_setsda(itv, 1); 45162306a36Sopenharmony_ci ivtv_scldelay(itv); 45262306a36Sopenharmony_ci for (i = 0; i < 8; ++i) { 45362306a36Sopenharmony_ci ivtv_setscl(itv, 0); 45462306a36Sopenharmony_ci ivtv_scldelay(itv); 45562306a36Sopenharmony_ci ivtv_setscl(itv, 1); 45662306a36Sopenharmony_ci if (!ivtv_waitscl(itv, 1)) { 45762306a36Sopenharmony_ci IVTV_DEBUG_I2C("Error setting SCL high\n"); 45862306a36Sopenharmony_ci return -EREMOTEIO; 45962306a36Sopenharmony_ci } 46062306a36Sopenharmony_ci *byte = ((*byte)<<1)|ivtv_getsda(itv); 46162306a36Sopenharmony_ci } 46262306a36Sopenharmony_ci ivtv_setscl(itv, 0); 46362306a36Sopenharmony_ci ivtv_scldelay(itv); 46462306a36Sopenharmony_ci ivtv_setsda(itv, nack); 46562306a36Sopenharmony_ci ivtv_scldelay(itv); 46662306a36Sopenharmony_ci ivtv_setscl(itv, 1); 46762306a36Sopenharmony_ci ivtv_scldelay(itv); 46862306a36Sopenharmony_ci ivtv_setscl(itv, 0); 46962306a36Sopenharmony_ci ivtv_scldelay(itv); 47062306a36Sopenharmony_ci IVTV_DEBUG_HI_I2C("read %x\n",*byte); 47162306a36Sopenharmony_ci return 0; 47262306a36Sopenharmony_ci} 47362306a36Sopenharmony_ci 47462306a36Sopenharmony_ci/* Issue a start condition on the i2c bus to alert slaves to prepare for 47562306a36Sopenharmony_ci an address write */ 47662306a36Sopenharmony_cistatic int ivtv_start(struct ivtv *itv) 47762306a36Sopenharmony_ci{ 47862306a36Sopenharmony_ci int sda; 47962306a36Sopenharmony_ci 48062306a36Sopenharmony_ci sda = ivtv_getsda(itv); 48162306a36Sopenharmony_ci if (sda != 1) { 48262306a36Sopenharmony_ci IVTV_DEBUG_HI_I2C("SDA was low at start\n"); 48362306a36Sopenharmony_ci ivtv_setsda(itv, 1); 48462306a36Sopenharmony_ci if (!ivtv_waitsda(itv, 1)) { 48562306a36Sopenharmony_ci IVTV_DEBUG_I2C("SDA stuck low\n"); 48662306a36Sopenharmony_ci return -EREMOTEIO; 48762306a36Sopenharmony_ci } 48862306a36Sopenharmony_ci } 48962306a36Sopenharmony_ci if (ivtv_getscl(itv) != 1) { 49062306a36Sopenharmony_ci ivtv_setscl(itv, 1); 49162306a36Sopenharmony_ci if (!ivtv_waitscl(itv, 1)) { 49262306a36Sopenharmony_ci IVTV_DEBUG_I2C("SCL stuck low at start\n"); 49362306a36Sopenharmony_ci return -EREMOTEIO; 49462306a36Sopenharmony_ci } 49562306a36Sopenharmony_ci } 49662306a36Sopenharmony_ci ivtv_setsda(itv, 0); 49762306a36Sopenharmony_ci ivtv_scldelay(itv); 49862306a36Sopenharmony_ci return 0; 49962306a36Sopenharmony_ci} 50062306a36Sopenharmony_ci 50162306a36Sopenharmony_ci/* Issue a stop condition on the i2c bus to release it */ 50262306a36Sopenharmony_cistatic int ivtv_stop(struct ivtv *itv) 50362306a36Sopenharmony_ci{ 50462306a36Sopenharmony_ci int i; 50562306a36Sopenharmony_ci 50662306a36Sopenharmony_ci if (ivtv_getscl(itv) != 0) { 50762306a36Sopenharmony_ci IVTV_DEBUG_HI_I2C("SCL not low when stopping\n"); 50862306a36Sopenharmony_ci ivtv_setscl(itv, 0); 50962306a36Sopenharmony_ci if (!ivtv_waitscl(itv, 0)) { 51062306a36Sopenharmony_ci IVTV_DEBUG_I2C("SCL could not be set low\n"); 51162306a36Sopenharmony_ci } 51262306a36Sopenharmony_ci } 51362306a36Sopenharmony_ci ivtv_setsda(itv, 0); 51462306a36Sopenharmony_ci ivtv_scldelay(itv); 51562306a36Sopenharmony_ci ivtv_setscl(itv, 1); 51662306a36Sopenharmony_ci if (!ivtv_waitscl(itv, 1)) { 51762306a36Sopenharmony_ci IVTV_DEBUG_I2C("SCL could not be set high\n"); 51862306a36Sopenharmony_ci return -EREMOTEIO; 51962306a36Sopenharmony_ci } 52062306a36Sopenharmony_ci ivtv_scldelay(itv); 52162306a36Sopenharmony_ci ivtv_setsda(itv, 1); 52262306a36Sopenharmony_ci if (!ivtv_waitsda(itv, 1)) { 52362306a36Sopenharmony_ci IVTV_DEBUG_I2C("resetting I2C\n"); 52462306a36Sopenharmony_ci for (i = 0; i < 16; ++i) { 52562306a36Sopenharmony_ci ivtv_setscl(itv, 0); 52662306a36Sopenharmony_ci ivtv_scldelay(itv); 52762306a36Sopenharmony_ci ivtv_setscl(itv, 1); 52862306a36Sopenharmony_ci ivtv_scldelay(itv); 52962306a36Sopenharmony_ci ivtv_setsda(itv, 1); 53062306a36Sopenharmony_ci } 53162306a36Sopenharmony_ci ivtv_waitsda(itv, 1); 53262306a36Sopenharmony_ci return -EREMOTEIO; 53362306a36Sopenharmony_ci } 53462306a36Sopenharmony_ci return 0; 53562306a36Sopenharmony_ci} 53662306a36Sopenharmony_ci 53762306a36Sopenharmony_ci/* Write a message to the given i2c slave. do_stop may be 0 to prevent 53862306a36Sopenharmony_ci issuing the i2c stop condition (when following with a read) */ 53962306a36Sopenharmony_cistatic int ivtv_write(struct ivtv *itv, unsigned char addr, unsigned char *data, u32 len, int do_stop) 54062306a36Sopenharmony_ci{ 54162306a36Sopenharmony_ci int retry, ret = -EREMOTEIO; 54262306a36Sopenharmony_ci u32 i; 54362306a36Sopenharmony_ci 54462306a36Sopenharmony_ci for (retry = 0; ret != 0 && retry < 8; ++retry) { 54562306a36Sopenharmony_ci ret = ivtv_start(itv); 54662306a36Sopenharmony_ci 54762306a36Sopenharmony_ci if (ret == 0) { 54862306a36Sopenharmony_ci ret = ivtv_sendbyte(itv, addr<<1); 54962306a36Sopenharmony_ci for (i = 0; ret == 0 && i < len; ++i) 55062306a36Sopenharmony_ci ret = ivtv_sendbyte(itv, data[i]); 55162306a36Sopenharmony_ci } 55262306a36Sopenharmony_ci if (ret != 0 || do_stop) { 55362306a36Sopenharmony_ci ivtv_stop(itv); 55462306a36Sopenharmony_ci } 55562306a36Sopenharmony_ci } 55662306a36Sopenharmony_ci if (ret) 55762306a36Sopenharmony_ci IVTV_DEBUG_I2C("i2c write to %x failed\n", addr); 55862306a36Sopenharmony_ci return ret; 55962306a36Sopenharmony_ci} 56062306a36Sopenharmony_ci 56162306a36Sopenharmony_ci/* Read data from the given i2c slave. A stop condition is always issued. */ 56262306a36Sopenharmony_cistatic int ivtv_read(struct ivtv *itv, unsigned char addr, unsigned char *data, u32 len) 56362306a36Sopenharmony_ci{ 56462306a36Sopenharmony_ci int retry, ret = -EREMOTEIO; 56562306a36Sopenharmony_ci u32 i; 56662306a36Sopenharmony_ci 56762306a36Sopenharmony_ci for (retry = 0; ret != 0 && retry < 8; ++retry) { 56862306a36Sopenharmony_ci ret = ivtv_start(itv); 56962306a36Sopenharmony_ci if (ret == 0) 57062306a36Sopenharmony_ci ret = ivtv_sendbyte(itv, (addr << 1) | 1); 57162306a36Sopenharmony_ci for (i = 0; ret == 0 && i < len; ++i) { 57262306a36Sopenharmony_ci ret = ivtv_readbyte(itv, &data[i], i == len - 1); 57362306a36Sopenharmony_ci } 57462306a36Sopenharmony_ci ivtv_stop(itv); 57562306a36Sopenharmony_ci } 57662306a36Sopenharmony_ci if (ret) 57762306a36Sopenharmony_ci IVTV_DEBUG_I2C("i2c read from %x failed\n", addr); 57862306a36Sopenharmony_ci return ret; 57962306a36Sopenharmony_ci} 58062306a36Sopenharmony_ci 58162306a36Sopenharmony_ci/* Kernel i2c transfer implementation. Takes a number of messages to be read 58262306a36Sopenharmony_ci or written. If a read follows a write, this will occur without an 58362306a36Sopenharmony_ci intervening stop condition */ 58462306a36Sopenharmony_cistatic int ivtv_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg *msgs, int num) 58562306a36Sopenharmony_ci{ 58662306a36Sopenharmony_ci struct v4l2_device *v4l2_dev = i2c_get_adapdata(i2c_adap); 58762306a36Sopenharmony_ci struct ivtv *itv = to_ivtv(v4l2_dev); 58862306a36Sopenharmony_ci int retval; 58962306a36Sopenharmony_ci int i; 59062306a36Sopenharmony_ci 59162306a36Sopenharmony_ci mutex_lock(&itv->i2c_bus_lock); 59262306a36Sopenharmony_ci for (i = retval = 0; retval == 0 && i < num; i++) { 59362306a36Sopenharmony_ci if (msgs[i].flags & I2C_M_RD) 59462306a36Sopenharmony_ci retval = ivtv_read(itv, msgs[i].addr, msgs[i].buf, msgs[i].len); 59562306a36Sopenharmony_ci else { 59662306a36Sopenharmony_ci /* if followed by a read, don't stop */ 59762306a36Sopenharmony_ci int stop = !(i + 1 < num && msgs[i + 1].flags == I2C_M_RD); 59862306a36Sopenharmony_ci 59962306a36Sopenharmony_ci retval = ivtv_write(itv, msgs[i].addr, msgs[i].buf, msgs[i].len, stop); 60062306a36Sopenharmony_ci } 60162306a36Sopenharmony_ci } 60262306a36Sopenharmony_ci mutex_unlock(&itv->i2c_bus_lock); 60362306a36Sopenharmony_ci return retval ? retval : num; 60462306a36Sopenharmony_ci} 60562306a36Sopenharmony_ci 60662306a36Sopenharmony_ci/* Kernel i2c capabilities */ 60762306a36Sopenharmony_cistatic u32 ivtv_functionality(struct i2c_adapter *adap) 60862306a36Sopenharmony_ci{ 60962306a36Sopenharmony_ci return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL; 61062306a36Sopenharmony_ci} 61162306a36Sopenharmony_ci 61262306a36Sopenharmony_cistatic const struct i2c_algorithm ivtv_algo = { 61362306a36Sopenharmony_ci .master_xfer = ivtv_xfer, 61462306a36Sopenharmony_ci .functionality = ivtv_functionality, 61562306a36Sopenharmony_ci}; 61662306a36Sopenharmony_ci 61762306a36Sopenharmony_ci/* template for our-bit banger */ 61862306a36Sopenharmony_cistatic const struct i2c_adapter ivtv_i2c_adap_hw_template = { 61962306a36Sopenharmony_ci .name = "ivtv i2c driver", 62062306a36Sopenharmony_ci .algo = &ivtv_algo, 62162306a36Sopenharmony_ci .algo_data = NULL, /* filled from template */ 62262306a36Sopenharmony_ci .owner = THIS_MODULE, 62362306a36Sopenharmony_ci}; 62462306a36Sopenharmony_ci 62562306a36Sopenharmony_cistatic void ivtv_setscl_old(void *data, int state) 62662306a36Sopenharmony_ci{ 62762306a36Sopenharmony_ci struct ivtv *itv = (struct ivtv *)data; 62862306a36Sopenharmony_ci 62962306a36Sopenharmony_ci if (state) 63062306a36Sopenharmony_ci itv->i2c_state |= 0x01; 63162306a36Sopenharmony_ci else 63262306a36Sopenharmony_ci itv->i2c_state &= ~0x01; 63362306a36Sopenharmony_ci 63462306a36Sopenharmony_ci /* write them out */ 63562306a36Sopenharmony_ci /* write bits are inverted */ 63662306a36Sopenharmony_ci write_reg(~itv->i2c_state, IVTV_REG_I2C_SETSCL_OFFSET); 63762306a36Sopenharmony_ci} 63862306a36Sopenharmony_ci 63962306a36Sopenharmony_cistatic void ivtv_setsda_old(void *data, int state) 64062306a36Sopenharmony_ci{ 64162306a36Sopenharmony_ci struct ivtv *itv = (struct ivtv *)data; 64262306a36Sopenharmony_ci 64362306a36Sopenharmony_ci if (state) 64462306a36Sopenharmony_ci itv->i2c_state |= 0x01; 64562306a36Sopenharmony_ci else 64662306a36Sopenharmony_ci itv->i2c_state &= ~0x01; 64762306a36Sopenharmony_ci 64862306a36Sopenharmony_ci /* write them out */ 64962306a36Sopenharmony_ci /* write bits are inverted */ 65062306a36Sopenharmony_ci write_reg(~itv->i2c_state, IVTV_REG_I2C_SETSDA_OFFSET); 65162306a36Sopenharmony_ci} 65262306a36Sopenharmony_ci 65362306a36Sopenharmony_cistatic int ivtv_getscl_old(void *data) 65462306a36Sopenharmony_ci{ 65562306a36Sopenharmony_ci struct ivtv *itv = (struct ivtv *)data; 65662306a36Sopenharmony_ci 65762306a36Sopenharmony_ci return read_reg(IVTV_REG_I2C_GETSCL_OFFSET) & 1; 65862306a36Sopenharmony_ci} 65962306a36Sopenharmony_ci 66062306a36Sopenharmony_cistatic int ivtv_getsda_old(void *data) 66162306a36Sopenharmony_ci{ 66262306a36Sopenharmony_ci struct ivtv *itv = (struct ivtv *)data; 66362306a36Sopenharmony_ci 66462306a36Sopenharmony_ci return read_reg(IVTV_REG_I2C_GETSDA_OFFSET) & 1; 66562306a36Sopenharmony_ci} 66662306a36Sopenharmony_ci 66762306a36Sopenharmony_ci/* template for i2c-bit-algo */ 66862306a36Sopenharmony_cistatic const struct i2c_adapter ivtv_i2c_adap_template = { 66962306a36Sopenharmony_ci .name = "ivtv i2c driver", 67062306a36Sopenharmony_ci .algo = NULL, /* set by i2c-algo-bit */ 67162306a36Sopenharmony_ci .algo_data = NULL, /* filled from template */ 67262306a36Sopenharmony_ci .owner = THIS_MODULE, 67362306a36Sopenharmony_ci}; 67462306a36Sopenharmony_ci 67562306a36Sopenharmony_ci#define IVTV_ALGO_BIT_TIMEOUT (2) /* seconds */ 67662306a36Sopenharmony_ci 67762306a36Sopenharmony_cistatic const struct i2c_algo_bit_data ivtv_i2c_algo_template = { 67862306a36Sopenharmony_ci .setsda = ivtv_setsda_old, 67962306a36Sopenharmony_ci .setscl = ivtv_setscl_old, 68062306a36Sopenharmony_ci .getsda = ivtv_getsda_old, 68162306a36Sopenharmony_ci .getscl = ivtv_getscl_old, 68262306a36Sopenharmony_ci .udelay = IVTV_DEFAULT_I2C_CLOCK_PERIOD / 2, /* microseconds */ 68362306a36Sopenharmony_ci .timeout = IVTV_ALGO_BIT_TIMEOUT * HZ, /* jiffies */ 68462306a36Sopenharmony_ci}; 68562306a36Sopenharmony_ci 68662306a36Sopenharmony_cistatic const struct i2c_client ivtv_i2c_client_template = { 68762306a36Sopenharmony_ci .name = "ivtv internal", 68862306a36Sopenharmony_ci}; 68962306a36Sopenharmony_ci 69062306a36Sopenharmony_ci/* init + register i2c adapter */ 69162306a36Sopenharmony_ciint init_ivtv_i2c(struct ivtv *itv) 69262306a36Sopenharmony_ci{ 69362306a36Sopenharmony_ci int retval; 69462306a36Sopenharmony_ci 69562306a36Sopenharmony_ci IVTV_DEBUG_I2C("i2c init\n"); 69662306a36Sopenharmony_ci 69762306a36Sopenharmony_ci /* Sanity checks for the I2C hardware arrays. They must be the 69862306a36Sopenharmony_ci * same size. 69962306a36Sopenharmony_ci */ 70062306a36Sopenharmony_ci if (ARRAY_SIZE(hw_devicenames) != ARRAY_SIZE(hw_addrs)) { 70162306a36Sopenharmony_ci IVTV_ERR("Mismatched I2C hardware arrays\n"); 70262306a36Sopenharmony_ci return -ENODEV; 70362306a36Sopenharmony_ci } 70462306a36Sopenharmony_ci if (itv->options.newi2c > 0) { 70562306a36Sopenharmony_ci itv->i2c_adap = ivtv_i2c_adap_hw_template; 70662306a36Sopenharmony_ci } else { 70762306a36Sopenharmony_ci itv->i2c_adap = ivtv_i2c_adap_template; 70862306a36Sopenharmony_ci itv->i2c_algo = ivtv_i2c_algo_template; 70962306a36Sopenharmony_ci } 71062306a36Sopenharmony_ci itv->i2c_algo.udelay = itv->options.i2c_clock_period / 2; 71162306a36Sopenharmony_ci itv->i2c_algo.data = itv; 71262306a36Sopenharmony_ci itv->i2c_adap.algo_data = &itv->i2c_algo; 71362306a36Sopenharmony_ci 71462306a36Sopenharmony_ci sprintf(itv->i2c_adap.name + strlen(itv->i2c_adap.name), " #%d", 71562306a36Sopenharmony_ci itv->instance); 71662306a36Sopenharmony_ci i2c_set_adapdata(&itv->i2c_adap, &itv->v4l2_dev); 71762306a36Sopenharmony_ci 71862306a36Sopenharmony_ci itv->i2c_client = ivtv_i2c_client_template; 71962306a36Sopenharmony_ci itv->i2c_client.adapter = &itv->i2c_adap; 72062306a36Sopenharmony_ci itv->i2c_adap.dev.parent = &itv->pdev->dev; 72162306a36Sopenharmony_ci 72262306a36Sopenharmony_ci IVTV_DEBUG_I2C("setting scl and sda to 1\n"); 72362306a36Sopenharmony_ci ivtv_setscl(itv, 1); 72462306a36Sopenharmony_ci ivtv_setsda(itv, 1); 72562306a36Sopenharmony_ci 72662306a36Sopenharmony_ci if (itv->options.newi2c > 0) 72762306a36Sopenharmony_ci retval = i2c_add_adapter(&itv->i2c_adap); 72862306a36Sopenharmony_ci else 72962306a36Sopenharmony_ci retval = i2c_bit_add_bus(&itv->i2c_adap); 73062306a36Sopenharmony_ci 73162306a36Sopenharmony_ci return retval; 73262306a36Sopenharmony_ci} 73362306a36Sopenharmony_ci 73462306a36Sopenharmony_civoid exit_ivtv_i2c(struct ivtv *itv) 73562306a36Sopenharmony_ci{ 73662306a36Sopenharmony_ci IVTV_DEBUG_I2C("i2c exit\n"); 73762306a36Sopenharmony_ci 73862306a36Sopenharmony_ci i2c_del_adapter(&itv->i2c_adap); 73962306a36Sopenharmony_ci} 740