18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci I2C functions 48c2ecf20Sopenharmony_ci Copyright (C) 2003-2004 Kevin Thayer <nufan_wfk at yahoo.com> 58c2ecf20Sopenharmony_ci Copyright (C) 2005-2007 Hans Verkuil <hverkuil@xs4all.nl> 68c2ecf20Sopenharmony_ci 78c2ecf20Sopenharmony_ci */ 88c2ecf20Sopenharmony_ci 98c2ecf20Sopenharmony_ci/* 108c2ecf20Sopenharmony_ci This file includes an i2c implementation that was reverse engineered 118c2ecf20Sopenharmony_ci from the Hauppauge windows driver. Older ivtv versions used i2c-algo-bit, 128c2ecf20Sopenharmony_ci which whilst fine under most circumstances, had trouble with the Zilog 138c2ecf20Sopenharmony_ci CPU on the PVR-150 which handles IR functions (occasional inability to 148c2ecf20Sopenharmony_ci communicate with the chip until it was reset) and also with the i2c 158c2ecf20Sopenharmony_ci bus being completely unreachable when multiple PVR cards were present. 168c2ecf20Sopenharmony_ci 178c2ecf20Sopenharmony_ci The implementation is very similar to i2c-algo-bit, but there are enough 188c2ecf20Sopenharmony_ci subtle differences that the two are hard to merge. The general strategy 198c2ecf20Sopenharmony_ci employed by i2c-algo-bit is to use udelay() to implement the timing 208c2ecf20Sopenharmony_ci when putting out bits on the scl/sda lines. The general strategy taken 218c2ecf20Sopenharmony_ci here is to poll the lines for state changes (see ivtv_waitscl and 228c2ecf20Sopenharmony_ci ivtv_waitsda). In addition there are small delays at various locations 238c2ecf20Sopenharmony_ci which poll the SCL line 5 times (ivtv_scldelay). I would guess that 248c2ecf20Sopenharmony_ci since this is memory mapped I/O that the length of those delays is tied 258c2ecf20Sopenharmony_ci to the PCI bus clock. There is some extra code to do with recovery 268c2ecf20Sopenharmony_ci and retries. Since it is not known what causes the actual i2c problems 278c2ecf20Sopenharmony_ci in the first place, the only goal if one was to attempt to use 288c2ecf20Sopenharmony_ci i2c-algo-bit would be to try to make it follow the same code path. 298c2ecf20Sopenharmony_ci This would be a lot of work, and I'm also not convinced that it would 308c2ecf20Sopenharmony_ci provide a generic benefit to i2c-algo-bit. Therefore consider this 318c2ecf20Sopenharmony_ci an engineering solution -- not pretty, but it works. 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_ci Some more general comments about what we are doing: 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_ci The i2c bus is a 2 wire serial bus, with clock (SCL) and data (SDA) 368c2ecf20Sopenharmony_ci lines. To communicate on the bus (as a master, we don't act as a slave), 378c2ecf20Sopenharmony_ci we first initiate a start condition (ivtv_start). We then write the 388c2ecf20Sopenharmony_ci address of the device that we want to communicate with, along with a flag 398c2ecf20Sopenharmony_ci that indicates whether this is a read or a write. The slave then issues 408c2ecf20Sopenharmony_ci an ACK signal (ivtv_ack), which tells us that it is ready for reading / 418c2ecf20Sopenharmony_ci writing. We then proceed with reading or writing (ivtv_read/ivtv_write), 428c2ecf20Sopenharmony_ci and finally issue a stop condition (ivtv_stop) to make the bus available 438c2ecf20Sopenharmony_ci to other masters. 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_ci There is an additional form of transaction where a write may be 468c2ecf20Sopenharmony_ci immediately followed by a read. In this case, there is no intervening 478c2ecf20Sopenharmony_ci stop condition. (Only the msp3400 chip uses this method of data transfer). 488c2ecf20Sopenharmony_ci */ 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_ci#include "ivtv-driver.h" 518c2ecf20Sopenharmony_ci#include "ivtv-cards.h" 528c2ecf20Sopenharmony_ci#include "ivtv-gpio.h" 538c2ecf20Sopenharmony_ci#include "ivtv-i2c.h" 548c2ecf20Sopenharmony_ci#include <media/drv-intf/cx25840.h> 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_ci/* i2c implementation for cx23415/6 chip, ivtv project. 578c2ecf20Sopenharmony_ci * Author: Kevin Thayer (nufan_wfk at yahoo.com) 588c2ecf20Sopenharmony_ci */ 598c2ecf20Sopenharmony_ci/* i2c stuff */ 608c2ecf20Sopenharmony_ci#define IVTV_REG_I2C_SETSCL_OFFSET 0x7000 618c2ecf20Sopenharmony_ci#define IVTV_REG_I2C_SETSDA_OFFSET 0x7004 628c2ecf20Sopenharmony_ci#define IVTV_REG_I2C_GETSCL_OFFSET 0x7008 638c2ecf20Sopenharmony_ci#define IVTV_REG_I2C_GETSDA_OFFSET 0x700c 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_ci#define IVTV_CS53L32A_I2C_ADDR 0x11 668c2ecf20Sopenharmony_ci#define IVTV_M52790_I2C_ADDR 0x48 678c2ecf20Sopenharmony_ci#define IVTV_CX25840_I2C_ADDR 0x44 688c2ecf20Sopenharmony_ci#define IVTV_SAA7115_I2C_ADDR 0x21 698c2ecf20Sopenharmony_ci#define IVTV_SAA7127_I2C_ADDR 0x44 708c2ecf20Sopenharmony_ci#define IVTV_SAA717x_I2C_ADDR 0x21 718c2ecf20Sopenharmony_ci#define IVTV_MSP3400_I2C_ADDR 0x40 728c2ecf20Sopenharmony_ci#define IVTV_HAUPPAUGE_I2C_ADDR 0x50 738c2ecf20Sopenharmony_ci#define IVTV_WM8739_I2C_ADDR 0x1a 748c2ecf20Sopenharmony_ci#define IVTV_WM8775_I2C_ADDR 0x1b 758c2ecf20Sopenharmony_ci#define IVTV_TEA5767_I2C_ADDR 0x60 768c2ecf20Sopenharmony_ci#define IVTV_UPD64031A_I2C_ADDR 0x12 778c2ecf20Sopenharmony_ci#define IVTV_UPD64083_I2C_ADDR 0x5c 788c2ecf20Sopenharmony_ci#define IVTV_VP27SMPX_I2C_ADDR 0x5b 798c2ecf20Sopenharmony_ci#define IVTV_M52790_I2C_ADDR 0x48 808c2ecf20Sopenharmony_ci#define IVTV_AVERMEDIA_IR_RX_I2C_ADDR 0x40 818c2ecf20Sopenharmony_ci#define IVTV_HAUP_EXT_IR_RX_I2C_ADDR 0x1a 828c2ecf20Sopenharmony_ci#define IVTV_HAUP_INT_IR_RX_I2C_ADDR 0x18 838c2ecf20Sopenharmony_ci#define IVTV_Z8F0811_IR_TX_I2C_ADDR 0x70 848c2ecf20Sopenharmony_ci#define IVTV_Z8F0811_IR_RX_I2C_ADDR 0x71 858c2ecf20Sopenharmony_ci#define IVTV_ADAPTEC_IR_ADDR 0x6b 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_ci/* This array should match the IVTV_HW_ defines */ 888c2ecf20Sopenharmony_cistatic const u8 hw_addrs[] = { 898c2ecf20Sopenharmony_ci IVTV_CX25840_I2C_ADDR, 908c2ecf20Sopenharmony_ci IVTV_SAA7115_I2C_ADDR, 918c2ecf20Sopenharmony_ci IVTV_SAA7127_I2C_ADDR, 928c2ecf20Sopenharmony_ci IVTV_MSP3400_I2C_ADDR, 938c2ecf20Sopenharmony_ci 0, 948c2ecf20Sopenharmony_ci IVTV_WM8775_I2C_ADDR, 958c2ecf20Sopenharmony_ci IVTV_CS53L32A_I2C_ADDR, 968c2ecf20Sopenharmony_ci 0, 978c2ecf20Sopenharmony_ci IVTV_SAA7115_I2C_ADDR, 988c2ecf20Sopenharmony_ci IVTV_UPD64031A_I2C_ADDR, 998c2ecf20Sopenharmony_ci IVTV_UPD64083_I2C_ADDR, 1008c2ecf20Sopenharmony_ci IVTV_SAA717x_I2C_ADDR, 1018c2ecf20Sopenharmony_ci IVTV_WM8739_I2C_ADDR, 1028c2ecf20Sopenharmony_ci IVTV_VP27SMPX_I2C_ADDR, 1038c2ecf20Sopenharmony_ci IVTV_M52790_I2C_ADDR, 1048c2ecf20Sopenharmony_ci 0, /* IVTV_HW_GPIO dummy driver ID */ 1058c2ecf20Sopenharmony_ci IVTV_AVERMEDIA_IR_RX_I2C_ADDR, /* IVTV_HW_I2C_IR_RX_AVER */ 1068c2ecf20Sopenharmony_ci IVTV_HAUP_EXT_IR_RX_I2C_ADDR, /* IVTV_HW_I2C_IR_RX_HAUP_EXT */ 1078c2ecf20Sopenharmony_ci IVTV_HAUP_INT_IR_RX_I2C_ADDR, /* IVTV_HW_I2C_IR_RX_HAUP_INT */ 1088c2ecf20Sopenharmony_ci IVTV_Z8F0811_IR_RX_I2C_ADDR, /* IVTV_HW_Z8F0811_IR_HAUP */ 1098c2ecf20Sopenharmony_ci IVTV_ADAPTEC_IR_ADDR, /* IVTV_HW_I2C_IR_RX_ADAPTEC */ 1108c2ecf20Sopenharmony_ci}; 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_ci/* This array should match the IVTV_HW_ defines */ 1138c2ecf20Sopenharmony_cistatic const char * const hw_devicenames[] = { 1148c2ecf20Sopenharmony_ci "cx25840", 1158c2ecf20Sopenharmony_ci "saa7115", 1168c2ecf20Sopenharmony_ci "saa7127_auto", /* saa7127 or saa7129 */ 1178c2ecf20Sopenharmony_ci "msp3400", 1188c2ecf20Sopenharmony_ci "tuner", 1198c2ecf20Sopenharmony_ci "wm8775", 1208c2ecf20Sopenharmony_ci "cs53l32a", 1218c2ecf20Sopenharmony_ci "tveeprom", 1228c2ecf20Sopenharmony_ci "saa7114", 1238c2ecf20Sopenharmony_ci "upd64031a", 1248c2ecf20Sopenharmony_ci "upd64083", 1258c2ecf20Sopenharmony_ci "saa717x", 1268c2ecf20Sopenharmony_ci "wm8739", 1278c2ecf20Sopenharmony_ci "vp27smpx", 1288c2ecf20Sopenharmony_ci "m52790", 1298c2ecf20Sopenharmony_ci "gpio", 1308c2ecf20Sopenharmony_ci "ir_video", /* IVTV_HW_I2C_IR_RX_AVER */ 1318c2ecf20Sopenharmony_ci "ir_video", /* IVTV_HW_I2C_IR_RX_HAUP_EXT */ 1328c2ecf20Sopenharmony_ci "ir_video", /* IVTV_HW_I2C_IR_RX_HAUP_INT */ 1338c2ecf20Sopenharmony_ci "ir_z8f0811_haup", /* IVTV_HW_Z8F0811_IR_HAUP */ 1348c2ecf20Sopenharmony_ci "ir_video", /* IVTV_HW_I2C_IR_RX_ADAPTEC */ 1358c2ecf20Sopenharmony_ci}; 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_cistatic int get_key_adaptec(struct IR_i2c *ir, enum rc_proto *protocol, 1388c2ecf20Sopenharmony_ci u32 *scancode, u8 *toggle) 1398c2ecf20Sopenharmony_ci{ 1408c2ecf20Sopenharmony_ci unsigned char keybuf[4]; 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_ci keybuf[0] = 0x00; 1438c2ecf20Sopenharmony_ci i2c_master_send(ir->c, keybuf, 1); 1448c2ecf20Sopenharmony_ci /* poll IR chip */ 1458c2ecf20Sopenharmony_ci if (i2c_master_recv(ir->c, keybuf, sizeof(keybuf)) != sizeof(keybuf)) { 1468c2ecf20Sopenharmony_ci return 0; 1478c2ecf20Sopenharmony_ci } 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_ci /* key pressed ? */ 1508c2ecf20Sopenharmony_ci if (keybuf[2] == 0xff) 1518c2ecf20Sopenharmony_ci return 0; 1528c2ecf20Sopenharmony_ci 1538c2ecf20Sopenharmony_ci /* remove repeat bit */ 1548c2ecf20Sopenharmony_ci keybuf[2] &= 0x7f; 1558c2ecf20Sopenharmony_ci keybuf[3] |= 0x80; 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_ci *protocol = RC_PROTO_UNKNOWN; 1588c2ecf20Sopenharmony_ci *scancode = keybuf[3] | keybuf[2] << 8 | keybuf[1] << 16 |keybuf[0] << 24; 1598c2ecf20Sopenharmony_ci *toggle = 0; 1608c2ecf20Sopenharmony_ci return 1; 1618c2ecf20Sopenharmony_ci} 1628c2ecf20Sopenharmony_ci 1638c2ecf20Sopenharmony_cistatic int ivtv_i2c_new_ir(struct ivtv *itv, u32 hw, const char *type, u8 addr) 1648c2ecf20Sopenharmony_ci{ 1658c2ecf20Sopenharmony_ci struct i2c_board_info info; 1668c2ecf20Sopenharmony_ci struct i2c_adapter *adap = &itv->i2c_adap; 1678c2ecf20Sopenharmony_ci struct IR_i2c_init_data *init_data = &itv->ir_i2c_init_data; 1688c2ecf20Sopenharmony_ci unsigned short addr_list[2] = { addr, I2C_CLIENT_END }; 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_ci /* Only allow one IR receiver to be registered per board */ 1718c2ecf20Sopenharmony_ci if (itv->hw_flags & IVTV_HW_IR_ANY) 1728c2ecf20Sopenharmony_ci return -1; 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_ci /* Our default information for ir-kbd-i2c.c to use */ 1758c2ecf20Sopenharmony_ci switch (hw) { 1768c2ecf20Sopenharmony_ci case IVTV_HW_I2C_IR_RX_AVER: 1778c2ecf20Sopenharmony_ci init_data->ir_codes = RC_MAP_AVERMEDIA_CARDBUS; 1788c2ecf20Sopenharmony_ci init_data->internal_get_key_func = 1798c2ecf20Sopenharmony_ci IR_KBD_GET_KEY_AVERMEDIA_CARDBUS; 1808c2ecf20Sopenharmony_ci init_data->type = RC_PROTO_BIT_OTHER; 1818c2ecf20Sopenharmony_ci init_data->name = "AVerMedia AVerTV card"; 1828c2ecf20Sopenharmony_ci break; 1838c2ecf20Sopenharmony_ci case IVTV_HW_I2C_IR_RX_HAUP_EXT: 1848c2ecf20Sopenharmony_ci case IVTV_HW_I2C_IR_RX_HAUP_INT: 1858c2ecf20Sopenharmony_ci init_data->ir_codes = RC_MAP_HAUPPAUGE; 1868c2ecf20Sopenharmony_ci init_data->internal_get_key_func = IR_KBD_GET_KEY_HAUP; 1878c2ecf20Sopenharmony_ci init_data->type = RC_PROTO_BIT_RC5; 1888c2ecf20Sopenharmony_ci init_data->name = itv->card_name; 1898c2ecf20Sopenharmony_ci break; 1908c2ecf20Sopenharmony_ci case IVTV_HW_Z8F0811_IR_HAUP: 1918c2ecf20Sopenharmony_ci /* Default to grey remote */ 1928c2ecf20Sopenharmony_ci init_data->ir_codes = RC_MAP_HAUPPAUGE; 1938c2ecf20Sopenharmony_ci init_data->internal_get_key_func = IR_KBD_GET_KEY_HAUP_XVR; 1948c2ecf20Sopenharmony_ci init_data->type = RC_PROTO_BIT_RC5 | RC_PROTO_BIT_RC6_MCE | 1958c2ecf20Sopenharmony_ci RC_PROTO_BIT_RC6_6A_32; 1968c2ecf20Sopenharmony_ci init_data->name = itv->card_name; 1978c2ecf20Sopenharmony_ci break; 1988c2ecf20Sopenharmony_ci case IVTV_HW_I2C_IR_RX_ADAPTEC: 1998c2ecf20Sopenharmony_ci init_data->get_key = get_key_adaptec; 2008c2ecf20Sopenharmony_ci init_data->name = itv->card_name; 2018c2ecf20Sopenharmony_ci /* FIXME: The protocol and RC_MAP needs to be corrected */ 2028c2ecf20Sopenharmony_ci init_data->ir_codes = RC_MAP_EMPTY; 2038c2ecf20Sopenharmony_ci init_data->type = RC_PROTO_BIT_UNKNOWN; 2048c2ecf20Sopenharmony_ci break; 2058c2ecf20Sopenharmony_ci } 2068c2ecf20Sopenharmony_ci 2078c2ecf20Sopenharmony_ci memset(&info, 0, sizeof(struct i2c_board_info)); 2088c2ecf20Sopenharmony_ci info.platform_data = init_data; 2098c2ecf20Sopenharmony_ci strscpy(info.type, type, I2C_NAME_SIZE); 2108c2ecf20Sopenharmony_ci 2118c2ecf20Sopenharmony_ci return IS_ERR(i2c_new_scanned_device(adap, &info, addr_list, NULL)) ? 2128c2ecf20Sopenharmony_ci -1 : 0; 2138c2ecf20Sopenharmony_ci} 2148c2ecf20Sopenharmony_ci 2158c2ecf20Sopenharmony_ci/* Instantiate the IR receiver device using probing -- undesirable */ 2168c2ecf20Sopenharmony_civoid ivtv_i2c_new_ir_legacy(struct ivtv *itv) 2178c2ecf20Sopenharmony_ci{ 2188c2ecf20Sopenharmony_ci struct i2c_board_info info; 2198c2ecf20Sopenharmony_ci /* 2208c2ecf20Sopenharmony_ci * The external IR receiver is at i2c address 0x34. 2218c2ecf20Sopenharmony_ci * The internal IR receiver is at i2c address 0x30. 2228c2ecf20Sopenharmony_ci * 2238c2ecf20Sopenharmony_ci * In theory, both can be fitted, and Hauppauge suggests an external 2248c2ecf20Sopenharmony_ci * overrides an internal. That's why we probe 0x1a (~0x34) first. CB 2258c2ecf20Sopenharmony_ci * 2268c2ecf20Sopenharmony_ci * Some of these addresses we probe may collide with other i2c address 2278c2ecf20Sopenharmony_ci * allocations, so this function must be called after all other i2c 2288c2ecf20Sopenharmony_ci * devices we care about are registered. 2298c2ecf20Sopenharmony_ci */ 2308c2ecf20Sopenharmony_ci static const unsigned short addr_list[] = { 2318c2ecf20Sopenharmony_ci 0x1a, /* Hauppauge IR external - collides with WM8739 */ 2328c2ecf20Sopenharmony_ci 0x18, /* Hauppauge IR internal */ 2338c2ecf20Sopenharmony_ci I2C_CLIENT_END 2348c2ecf20Sopenharmony_ci }; 2358c2ecf20Sopenharmony_ci 2368c2ecf20Sopenharmony_ci memset(&info, 0, sizeof(struct i2c_board_info)); 2378c2ecf20Sopenharmony_ci strscpy(info.type, "ir_video", I2C_NAME_SIZE); 2388c2ecf20Sopenharmony_ci i2c_new_scanned_device(&itv->i2c_adap, &info, addr_list, NULL); 2398c2ecf20Sopenharmony_ci} 2408c2ecf20Sopenharmony_ci 2418c2ecf20Sopenharmony_ciint ivtv_i2c_register(struct ivtv *itv, unsigned idx) 2428c2ecf20Sopenharmony_ci{ 2438c2ecf20Sopenharmony_ci struct v4l2_subdev *sd; 2448c2ecf20Sopenharmony_ci struct i2c_adapter *adap = &itv->i2c_adap; 2458c2ecf20Sopenharmony_ci const char *type = hw_devicenames[idx]; 2468c2ecf20Sopenharmony_ci u32 hw = 1 << idx; 2478c2ecf20Sopenharmony_ci 2488c2ecf20Sopenharmony_ci if (hw == IVTV_HW_TUNER) { 2498c2ecf20Sopenharmony_ci /* special tuner handling */ 2508c2ecf20Sopenharmony_ci sd = v4l2_i2c_new_subdev(&itv->v4l2_dev, adap, type, 0, 2518c2ecf20Sopenharmony_ci itv->card_i2c->radio); 2528c2ecf20Sopenharmony_ci if (sd) 2538c2ecf20Sopenharmony_ci sd->grp_id = 1 << idx; 2548c2ecf20Sopenharmony_ci sd = v4l2_i2c_new_subdev(&itv->v4l2_dev, adap, type, 0, 2558c2ecf20Sopenharmony_ci itv->card_i2c->demod); 2568c2ecf20Sopenharmony_ci if (sd) 2578c2ecf20Sopenharmony_ci sd->grp_id = 1 << idx; 2588c2ecf20Sopenharmony_ci sd = v4l2_i2c_new_subdev(&itv->v4l2_dev, adap, type, 0, 2598c2ecf20Sopenharmony_ci itv->card_i2c->tv); 2608c2ecf20Sopenharmony_ci if (sd) 2618c2ecf20Sopenharmony_ci sd->grp_id = 1 << idx; 2628c2ecf20Sopenharmony_ci return sd ? 0 : -1; 2638c2ecf20Sopenharmony_ci } 2648c2ecf20Sopenharmony_ci 2658c2ecf20Sopenharmony_ci if (hw & IVTV_HW_IR_ANY) 2668c2ecf20Sopenharmony_ci return ivtv_i2c_new_ir(itv, hw, type, hw_addrs[idx]); 2678c2ecf20Sopenharmony_ci 2688c2ecf20Sopenharmony_ci /* Is it not an I2C device or one we do not wish to register? */ 2698c2ecf20Sopenharmony_ci if (!hw_addrs[idx]) 2708c2ecf20Sopenharmony_ci return -1; 2718c2ecf20Sopenharmony_ci 2728c2ecf20Sopenharmony_ci /* It's an I2C device other than an analog tuner or IR chip */ 2738c2ecf20Sopenharmony_ci if (hw == IVTV_HW_UPD64031A || hw == IVTV_HW_UPD6408X) { 2748c2ecf20Sopenharmony_ci sd = v4l2_i2c_new_subdev(&itv->v4l2_dev, 2758c2ecf20Sopenharmony_ci adap, type, 0, I2C_ADDRS(hw_addrs[idx])); 2768c2ecf20Sopenharmony_ci } else if (hw == IVTV_HW_CX25840) { 2778c2ecf20Sopenharmony_ci struct cx25840_platform_data pdata; 2788c2ecf20Sopenharmony_ci struct i2c_board_info cx25840_info = { 2798c2ecf20Sopenharmony_ci .type = "cx25840", 2808c2ecf20Sopenharmony_ci .addr = hw_addrs[idx], 2818c2ecf20Sopenharmony_ci .platform_data = &pdata, 2828c2ecf20Sopenharmony_ci }; 2838c2ecf20Sopenharmony_ci 2848c2ecf20Sopenharmony_ci memset(&pdata, 0, sizeof(pdata)); 2858c2ecf20Sopenharmony_ci pdata.pvr150_workaround = itv->pvr150_workaround; 2868c2ecf20Sopenharmony_ci sd = v4l2_i2c_new_subdev_board(&itv->v4l2_dev, adap, 2878c2ecf20Sopenharmony_ci &cx25840_info, NULL); 2888c2ecf20Sopenharmony_ci } else { 2898c2ecf20Sopenharmony_ci sd = v4l2_i2c_new_subdev(&itv->v4l2_dev, 2908c2ecf20Sopenharmony_ci adap, type, hw_addrs[idx], NULL); 2918c2ecf20Sopenharmony_ci } 2928c2ecf20Sopenharmony_ci if (sd) 2938c2ecf20Sopenharmony_ci sd->grp_id = 1 << idx; 2948c2ecf20Sopenharmony_ci return sd ? 0 : -1; 2958c2ecf20Sopenharmony_ci} 2968c2ecf20Sopenharmony_ci 2978c2ecf20Sopenharmony_cistruct v4l2_subdev *ivtv_find_hw(struct ivtv *itv, u32 hw) 2988c2ecf20Sopenharmony_ci{ 2998c2ecf20Sopenharmony_ci struct v4l2_subdev *result = NULL; 3008c2ecf20Sopenharmony_ci struct v4l2_subdev *sd; 3018c2ecf20Sopenharmony_ci 3028c2ecf20Sopenharmony_ci spin_lock(&itv->v4l2_dev.lock); 3038c2ecf20Sopenharmony_ci v4l2_device_for_each_subdev(sd, &itv->v4l2_dev) { 3048c2ecf20Sopenharmony_ci if (sd->grp_id == hw) { 3058c2ecf20Sopenharmony_ci result = sd; 3068c2ecf20Sopenharmony_ci break; 3078c2ecf20Sopenharmony_ci } 3088c2ecf20Sopenharmony_ci } 3098c2ecf20Sopenharmony_ci spin_unlock(&itv->v4l2_dev.lock); 3108c2ecf20Sopenharmony_ci return result; 3118c2ecf20Sopenharmony_ci} 3128c2ecf20Sopenharmony_ci 3138c2ecf20Sopenharmony_ci/* Set the serial clock line to the desired state */ 3148c2ecf20Sopenharmony_cistatic void ivtv_setscl(struct ivtv *itv, int state) 3158c2ecf20Sopenharmony_ci{ 3168c2ecf20Sopenharmony_ci /* write them out */ 3178c2ecf20Sopenharmony_ci /* write bits are inverted */ 3188c2ecf20Sopenharmony_ci write_reg(~state, IVTV_REG_I2C_SETSCL_OFFSET); 3198c2ecf20Sopenharmony_ci} 3208c2ecf20Sopenharmony_ci 3218c2ecf20Sopenharmony_ci/* Set the serial data line to the desired state */ 3228c2ecf20Sopenharmony_cistatic void ivtv_setsda(struct ivtv *itv, int state) 3238c2ecf20Sopenharmony_ci{ 3248c2ecf20Sopenharmony_ci /* write them out */ 3258c2ecf20Sopenharmony_ci /* write bits are inverted */ 3268c2ecf20Sopenharmony_ci write_reg(~state & 1, IVTV_REG_I2C_SETSDA_OFFSET); 3278c2ecf20Sopenharmony_ci} 3288c2ecf20Sopenharmony_ci 3298c2ecf20Sopenharmony_ci/* Read the serial clock line */ 3308c2ecf20Sopenharmony_cistatic int ivtv_getscl(struct ivtv *itv) 3318c2ecf20Sopenharmony_ci{ 3328c2ecf20Sopenharmony_ci return read_reg(IVTV_REG_I2C_GETSCL_OFFSET) & 1; 3338c2ecf20Sopenharmony_ci} 3348c2ecf20Sopenharmony_ci 3358c2ecf20Sopenharmony_ci/* Read the serial data line */ 3368c2ecf20Sopenharmony_cistatic int ivtv_getsda(struct ivtv *itv) 3378c2ecf20Sopenharmony_ci{ 3388c2ecf20Sopenharmony_ci return read_reg(IVTV_REG_I2C_GETSDA_OFFSET) & 1; 3398c2ecf20Sopenharmony_ci} 3408c2ecf20Sopenharmony_ci 3418c2ecf20Sopenharmony_ci/* Implement a short delay by polling the serial clock line */ 3428c2ecf20Sopenharmony_cistatic void ivtv_scldelay(struct ivtv *itv) 3438c2ecf20Sopenharmony_ci{ 3448c2ecf20Sopenharmony_ci int i; 3458c2ecf20Sopenharmony_ci 3468c2ecf20Sopenharmony_ci for (i = 0; i < 5; ++i) 3478c2ecf20Sopenharmony_ci ivtv_getscl(itv); 3488c2ecf20Sopenharmony_ci} 3498c2ecf20Sopenharmony_ci 3508c2ecf20Sopenharmony_ci/* Wait for the serial clock line to become set to a specific value */ 3518c2ecf20Sopenharmony_cistatic int ivtv_waitscl(struct ivtv *itv, int val) 3528c2ecf20Sopenharmony_ci{ 3538c2ecf20Sopenharmony_ci int i; 3548c2ecf20Sopenharmony_ci 3558c2ecf20Sopenharmony_ci ivtv_scldelay(itv); 3568c2ecf20Sopenharmony_ci for (i = 0; i < 1000; ++i) { 3578c2ecf20Sopenharmony_ci if (ivtv_getscl(itv) == val) 3588c2ecf20Sopenharmony_ci return 1; 3598c2ecf20Sopenharmony_ci } 3608c2ecf20Sopenharmony_ci return 0; 3618c2ecf20Sopenharmony_ci} 3628c2ecf20Sopenharmony_ci 3638c2ecf20Sopenharmony_ci/* Wait for the serial data line to become set to a specific value */ 3648c2ecf20Sopenharmony_cistatic int ivtv_waitsda(struct ivtv *itv, int val) 3658c2ecf20Sopenharmony_ci{ 3668c2ecf20Sopenharmony_ci int i; 3678c2ecf20Sopenharmony_ci 3688c2ecf20Sopenharmony_ci ivtv_scldelay(itv); 3698c2ecf20Sopenharmony_ci for (i = 0; i < 1000; ++i) { 3708c2ecf20Sopenharmony_ci if (ivtv_getsda(itv) == val) 3718c2ecf20Sopenharmony_ci return 1; 3728c2ecf20Sopenharmony_ci } 3738c2ecf20Sopenharmony_ci return 0; 3748c2ecf20Sopenharmony_ci} 3758c2ecf20Sopenharmony_ci 3768c2ecf20Sopenharmony_ci/* Wait for the slave to issue an ACK */ 3778c2ecf20Sopenharmony_cistatic int ivtv_ack(struct ivtv *itv) 3788c2ecf20Sopenharmony_ci{ 3798c2ecf20Sopenharmony_ci int ret = 0; 3808c2ecf20Sopenharmony_ci 3818c2ecf20Sopenharmony_ci if (ivtv_getscl(itv) == 1) { 3828c2ecf20Sopenharmony_ci IVTV_DEBUG_HI_I2C("SCL was high starting an ack\n"); 3838c2ecf20Sopenharmony_ci ivtv_setscl(itv, 0); 3848c2ecf20Sopenharmony_ci if (!ivtv_waitscl(itv, 0)) { 3858c2ecf20Sopenharmony_ci IVTV_DEBUG_I2C("Could not set SCL low starting an ack\n"); 3868c2ecf20Sopenharmony_ci return -EREMOTEIO; 3878c2ecf20Sopenharmony_ci } 3888c2ecf20Sopenharmony_ci } 3898c2ecf20Sopenharmony_ci ivtv_setsda(itv, 1); 3908c2ecf20Sopenharmony_ci ivtv_scldelay(itv); 3918c2ecf20Sopenharmony_ci ivtv_setscl(itv, 1); 3928c2ecf20Sopenharmony_ci if (!ivtv_waitsda(itv, 0)) { 3938c2ecf20Sopenharmony_ci IVTV_DEBUG_I2C("Slave did not ack\n"); 3948c2ecf20Sopenharmony_ci ret = -EREMOTEIO; 3958c2ecf20Sopenharmony_ci } 3968c2ecf20Sopenharmony_ci ivtv_setscl(itv, 0); 3978c2ecf20Sopenharmony_ci if (!ivtv_waitscl(itv, 0)) { 3988c2ecf20Sopenharmony_ci IVTV_DEBUG_I2C("Failed to set SCL low after ACK\n"); 3998c2ecf20Sopenharmony_ci ret = -EREMOTEIO; 4008c2ecf20Sopenharmony_ci } 4018c2ecf20Sopenharmony_ci return ret; 4028c2ecf20Sopenharmony_ci} 4038c2ecf20Sopenharmony_ci 4048c2ecf20Sopenharmony_ci/* Write a single byte to the i2c bus and wait for the slave to ACK */ 4058c2ecf20Sopenharmony_cistatic int ivtv_sendbyte(struct ivtv *itv, unsigned char byte) 4068c2ecf20Sopenharmony_ci{ 4078c2ecf20Sopenharmony_ci int i, bit; 4088c2ecf20Sopenharmony_ci 4098c2ecf20Sopenharmony_ci IVTV_DEBUG_HI_I2C("write %x\n",byte); 4108c2ecf20Sopenharmony_ci for (i = 0; i < 8; ++i, byte<<=1) { 4118c2ecf20Sopenharmony_ci ivtv_setscl(itv, 0); 4128c2ecf20Sopenharmony_ci if (!ivtv_waitscl(itv, 0)) { 4138c2ecf20Sopenharmony_ci IVTV_DEBUG_I2C("Error setting SCL low\n"); 4148c2ecf20Sopenharmony_ci return -EREMOTEIO; 4158c2ecf20Sopenharmony_ci } 4168c2ecf20Sopenharmony_ci bit = (byte>>7)&1; 4178c2ecf20Sopenharmony_ci ivtv_setsda(itv, bit); 4188c2ecf20Sopenharmony_ci if (!ivtv_waitsda(itv, bit)) { 4198c2ecf20Sopenharmony_ci IVTV_DEBUG_I2C("Error setting SDA\n"); 4208c2ecf20Sopenharmony_ci return -EREMOTEIO; 4218c2ecf20Sopenharmony_ci } 4228c2ecf20Sopenharmony_ci ivtv_setscl(itv, 1); 4238c2ecf20Sopenharmony_ci if (!ivtv_waitscl(itv, 1)) { 4248c2ecf20Sopenharmony_ci IVTV_DEBUG_I2C("Slave not ready for bit\n"); 4258c2ecf20Sopenharmony_ci return -EREMOTEIO; 4268c2ecf20Sopenharmony_ci } 4278c2ecf20Sopenharmony_ci } 4288c2ecf20Sopenharmony_ci ivtv_setscl(itv, 0); 4298c2ecf20Sopenharmony_ci if (!ivtv_waitscl(itv, 0)) { 4308c2ecf20Sopenharmony_ci IVTV_DEBUG_I2C("Error setting SCL low\n"); 4318c2ecf20Sopenharmony_ci return -EREMOTEIO; 4328c2ecf20Sopenharmony_ci } 4338c2ecf20Sopenharmony_ci return ivtv_ack(itv); 4348c2ecf20Sopenharmony_ci} 4358c2ecf20Sopenharmony_ci 4368c2ecf20Sopenharmony_ci/* Read a byte from the i2c bus and send a NACK if applicable (i.e. for the 4378c2ecf20Sopenharmony_ci final byte) */ 4388c2ecf20Sopenharmony_cistatic int ivtv_readbyte(struct ivtv *itv, unsigned char *byte, int nack) 4398c2ecf20Sopenharmony_ci{ 4408c2ecf20Sopenharmony_ci int i; 4418c2ecf20Sopenharmony_ci 4428c2ecf20Sopenharmony_ci *byte = 0; 4438c2ecf20Sopenharmony_ci 4448c2ecf20Sopenharmony_ci ivtv_setsda(itv, 1); 4458c2ecf20Sopenharmony_ci ivtv_scldelay(itv); 4468c2ecf20Sopenharmony_ci for (i = 0; i < 8; ++i) { 4478c2ecf20Sopenharmony_ci ivtv_setscl(itv, 0); 4488c2ecf20Sopenharmony_ci ivtv_scldelay(itv); 4498c2ecf20Sopenharmony_ci ivtv_setscl(itv, 1); 4508c2ecf20Sopenharmony_ci if (!ivtv_waitscl(itv, 1)) { 4518c2ecf20Sopenharmony_ci IVTV_DEBUG_I2C("Error setting SCL high\n"); 4528c2ecf20Sopenharmony_ci return -EREMOTEIO; 4538c2ecf20Sopenharmony_ci } 4548c2ecf20Sopenharmony_ci *byte = ((*byte)<<1)|ivtv_getsda(itv); 4558c2ecf20Sopenharmony_ci } 4568c2ecf20Sopenharmony_ci ivtv_setscl(itv, 0); 4578c2ecf20Sopenharmony_ci ivtv_scldelay(itv); 4588c2ecf20Sopenharmony_ci ivtv_setsda(itv, nack); 4598c2ecf20Sopenharmony_ci ivtv_scldelay(itv); 4608c2ecf20Sopenharmony_ci ivtv_setscl(itv, 1); 4618c2ecf20Sopenharmony_ci ivtv_scldelay(itv); 4628c2ecf20Sopenharmony_ci ivtv_setscl(itv, 0); 4638c2ecf20Sopenharmony_ci ivtv_scldelay(itv); 4648c2ecf20Sopenharmony_ci IVTV_DEBUG_HI_I2C("read %x\n",*byte); 4658c2ecf20Sopenharmony_ci return 0; 4668c2ecf20Sopenharmony_ci} 4678c2ecf20Sopenharmony_ci 4688c2ecf20Sopenharmony_ci/* Issue a start condition on the i2c bus to alert slaves to prepare for 4698c2ecf20Sopenharmony_ci an address write */ 4708c2ecf20Sopenharmony_cistatic int ivtv_start(struct ivtv *itv) 4718c2ecf20Sopenharmony_ci{ 4728c2ecf20Sopenharmony_ci int sda; 4738c2ecf20Sopenharmony_ci 4748c2ecf20Sopenharmony_ci sda = ivtv_getsda(itv); 4758c2ecf20Sopenharmony_ci if (sda != 1) { 4768c2ecf20Sopenharmony_ci IVTV_DEBUG_HI_I2C("SDA was low at start\n"); 4778c2ecf20Sopenharmony_ci ivtv_setsda(itv, 1); 4788c2ecf20Sopenharmony_ci if (!ivtv_waitsda(itv, 1)) { 4798c2ecf20Sopenharmony_ci IVTV_DEBUG_I2C("SDA stuck low\n"); 4808c2ecf20Sopenharmony_ci return -EREMOTEIO; 4818c2ecf20Sopenharmony_ci } 4828c2ecf20Sopenharmony_ci } 4838c2ecf20Sopenharmony_ci if (ivtv_getscl(itv) != 1) { 4848c2ecf20Sopenharmony_ci ivtv_setscl(itv, 1); 4858c2ecf20Sopenharmony_ci if (!ivtv_waitscl(itv, 1)) { 4868c2ecf20Sopenharmony_ci IVTV_DEBUG_I2C("SCL stuck low at start\n"); 4878c2ecf20Sopenharmony_ci return -EREMOTEIO; 4888c2ecf20Sopenharmony_ci } 4898c2ecf20Sopenharmony_ci } 4908c2ecf20Sopenharmony_ci ivtv_setsda(itv, 0); 4918c2ecf20Sopenharmony_ci ivtv_scldelay(itv); 4928c2ecf20Sopenharmony_ci return 0; 4938c2ecf20Sopenharmony_ci} 4948c2ecf20Sopenharmony_ci 4958c2ecf20Sopenharmony_ci/* Issue a stop condition on the i2c bus to release it */ 4968c2ecf20Sopenharmony_cistatic int ivtv_stop(struct ivtv *itv) 4978c2ecf20Sopenharmony_ci{ 4988c2ecf20Sopenharmony_ci int i; 4998c2ecf20Sopenharmony_ci 5008c2ecf20Sopenharmony_ci if (ivtv_getscl(itv) != 0) { 5018c2ecf20Sopenharmony_ci IVTV_DEBUG_HI_I2C("SCL not low when stopping\n"); 5028c2ecf20Sopenharmony_ci ivtv_setscl(itv, 0); 5038c2ecf20Sopenharmony_ci if (!ivtv_waitscl(itv, 0)) { 5048c2ecf20Sopenharmony_ci IVTV_DEBUG_I2C("SCL could not be set low\n"); 5058c2ecf20Sopenharmony_ci } 5068c2ecf20Sopenharmony_ci } 5078c2ecf20Sopenharmony_ci ivtv_setsda(itv, 0); 5088c2ecf20Sopenharmony_ci ivtv_scldelay(itv); 5098c2ecf20Sopenharmony_ci ivtv_setscl(itv, 1); 5108c2ecf20Sopenharmony_ci if (!ivtv_waitscl(itv, 1)) { 5118c2ecf20Sopenharmony_ci IVTV_DEBUG_I2C("SCL could not be set high\n"); 5128c2ecf20Sopenharmony_ci return -EREMOTEIO; 5138c2ecf20Sopenharmony_ci } 5148c2ecf20Sopenharmony_ci ivtv_scldelay(itv); 5158c2ecf20Sopenharmony_ci ivtv_setsda(itv, 1); 5168c2ecf20Sopenharmony_ci if (!ivtv_waitsda(itv, 1)) { 5178c2ecf20Sopenharmony_ci IVTV_DEBUG_I2C("resetting I2C\n"); 5188c2ecf20Sopenharmony_ci for (i = 0; i < 16; ++i) { 5198c2ecf20Sopenharmony_ci ivtv_setscl(itv, 0); 5208c2ecf20Sopenharmony_ci ivtv_scldelay(itv); 5218c2ecf20Sopenharmony_ci ivtv_setscl(itv, 1); 5228c2ecf20Sopenharmony_ci ivtv_scldelay(itv); 5238c2ecf20Sopenharmony_ci ivtv_setsda(itv, 1); 5248c2ecf20Sopenharmony_ci } 5258c2ecf20Sopenharmony_ci ivtv_waitsda(itv, 1); 5268c2ecf20Sopenharmony_ci return -EREMOTEIO; 5278c2ecf20Sopenharmony_ci } 5288c2ecf20Sopenharmony_ci return 0; 5298c2ecf20Sopenharmony_ci} 5308c2ecf20Sopenharmony_ci 5318c2ecf20Sopenharmony_ci/* Write a message to the given i2c slave. do_stop may be 0 to prevent 5328c2ecf20Sopenharmony_ci issuing the i2c stop condition (when following with a read) */ 5338c2ecf20Sopenharmony_cistatic int ivtv_write(struct ivtv *itv, unsigned char addr, unsigned char *data, u32 len, int do_stop) 5348c2ecf20Sopenharmony_ci{ 5358c2ecf20Sopenharmony_ci int retry, ret = -EREMOTEIO; 5368c2ecf20Sopenharmony_ci u32 i; 5378c2ecf20Sopenharmony_ci 5388c2ecf20Sopenharmony_ci for (retry = 0; ret != 0 && retry < 8; ++retry) { 5398c2ecf20Sopenharmony_ci ret = ivtv_start(itv); 5408c2ecf20Sopenharmony_ci 5418c2ecf20Sopenharmony_ci if (ret == 0) { 5428c2ecf20Sopenharmony_ci ret = ivtv_sendbyte(itv, addr<<1); 5438c2ecf20Sopenharmony_ci for (i = 0; ret == 0 && i < len; ++i) 5448c2ecf20Sopenharmony_ci ret = ivtv_sendbyte(itv, data[i]); 5458c2ecf20Sopenharmony_ci } 5468c2ecf20Sopenharmony_ci if (ret != 0 || do_stop) { 5478c2ecf20Sopenharmony_ci ivtv_stop(itv); 5488c2ecf20Sopenharmony_ci } 5498c2ecf20Sopenharmony_ci } 5508c2ecf20Sopenharmony_ci if (ret) 5518c2ecf20Sopenharmony_ci IVTV_DEBUG_I2C("i2c write to %x failed\n", addr); 5528c2ecf20Sopenharmony_ci return ret; 5538c2ecf20Sopenharmony_ci} 5548c2ecf20Sopenharmony_ci 5558c2ecf20Sopenharmony_ci/* Read data from the given i2c slave. A stop condition is always issued. */ 5568c2ecf20Sopenharmony_cistatic int ivtv_read(struct ivtv *itv, unsigned char addr, unsigned char *data, u32 len) 5578c2ecf20Sopenharmony_ci{ 5588c2ecf20Sopenharmony_ci int retry, ret = -EREMOTEIO; 5598c2ecf20Sopenharmony_ci u32 i; 5608c2ecf20Sopenharmony_ci 5618c2ecf20Sopenharmony_ci for (retry = 0; ret != 0 && retry < 8; ++retry) { 5628c2ecf20Sopenharmony_ci ret = ivtv_start(itv); 5638c2ecf20Sopenharmony_ci if (ret == 0) 5648c2ecf20Sopenharmony_ci ret = ivtv_sendbyte(itv, (addr << 1) | 1); 5658c2ecf20Sopenharmony_ci for (i = 0; ret == 0 && i < len; ++i) { 5668c2ecf20Sopenharmony_ci ret = ivtv_readbyte(itv, &data[i], i == len - 1); 5678c2ecf20Sopenharmony_ci } 5688c2ecf20Sopenharmony_ci ivtv_stop(itv); 5698c2ecf20Sopenharmony_ci } 5708c2ecf20Sopenharmony_ci if (ret) 5718c2ecf20Sopenharmony_ci IVTV_DEBUG_I2C("i2c read from %x failed\n", addr); 5728c2ecf20Sopenharmony_ci return ret; 5738c2ecf20Sopenharmony_ci} 5748c2ecf20Sopenharmony_ci 5758c2ecf20Sopenharmony_ci/* Kernel i2c transfer implementation. Takes a number of messages to be read 5768c2ecf20Sopenharmony_ci or written. If a read follows a write, this will occur without an 5778c2ecf20Sopenharmony_ci intervening stop condition */ 5788c2ecf20Sopenharmony_cistatic int ivtv_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg *msgs, int num) 5798c2ecf20Sopenharmony_ci{ 5808c2ecf20Sopenharmony_ci struct v4l2_device *v4l2_dev = i2c_get_adapdata(i2c_adap); 5818c2ecf20Sopenharmony_ci struct ivtv *itv = to_ivtv(v4l2_dev); 5828c2ecf20Sopenharmony_ci int retval; 5838c2ecf20Sopenharmony_ci int i; 5848c2ecf20Sopenharmony_ci 5858c2ecf20Sopenharmony_ci mutex_lock(&itv->i2c_bus_lock); 5868c2ecf20Sopenharmony_ci for (i = retval = 0; retval == 0 && i < num; i++) { 5878c2ecf20Sopenharmony_ci if (msgs[i].flags & I2C_M_RD) 5888c2ecf20Sopenharmony_ci retval = ivtv_read(itv, msgs[i].addr, msgs[i].buf, msgs[i].len); 5898c2ecf20Sopenharmony_ci else { 5908c2ecf20Sopenharmony_ci /* if followed by a read, don't stop */ 5918c2ecf20Sopenharmony_ci int stop = !(i + 1 < num && msgs[i + 1].flags == I2C_M_RD); 5928c2ecf20Sopenharmony_ci 5938c2ecf20Sopenharmony_ci retval = ivtv_write(itv, msgs[i].addr, msgs[i].buf, msgs[i].len, stop); 5948c2ecf20Sopenharmony_ci } 5958c2ecf20Sopenharmony_ci } 5968c2ecf20Sopenharmony_ci mutex_unlock(&itv->i2c_bus_lock); 5978c2ecf20Sopenharmony_ci return retval ? retval : num; 5988c2ecf20Sopenharmony_ci} 5998c2ecf20Sopenharmony_ci 6008c2ecf20Sopenharmony_ci/* Kernel i2c capabilities */ 6018c2ecf20Sopenharmony_cistatic u32 ivtv_functionality(struct i2c_adapter *adap) 6028c2ecf20Sopenharmony_ci{ 6038c2ecf20Sopenharmony_ci return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL; 6048c2ecf20Sopenharmony_ci} 6058c2ecf20Sopenharmony_ci 6068c2ecf20Sopenharmony_cistatic const struct i2c_algorithm ivtv_algo = { 6078c2ecf20Sopenharmony_ci .master_xfer = ivtv_xfer, 6088c2ecf20Sopenharmony_ci .functionality = ivtv_functionality, 6098c2ecf20Sopenharmony_ci}; 6108c2ecf20Sopenharmony_ci 6118c2ecf20Sopenharmony_ci/* template for our-bit banger */ 6128c2ecf20Sopenharmony_cistatic const struct i2c_adapter ivtv_i2c_adap_hw_template = { 6138c2ecf20Sopenharmony_ci .name = "ivtv i2c driver", 6148c2ecf20Sopenharmony_ci .algo = &ivtv_algo, 6158c2ecf20Sopenharmony_ci .algo_data = NULL, /* filled from template */ 6168c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 6178c2ecf20Sopenharmony_ci}; 6188c2ecf20Sopenharmony_ci 6198c2ecf20Sopenharmony_cistatic void ivtv_setscl_old(void *data, int state) 6208c2ecf20Sopenharmony_ci{ 6218c2ecf20Sopenharmony_ci struct ivtv *itv = (struct ivtv *)data; 6228c2ecf20Sopenharmony_ci 6238c2ecf20Sopenharmony_ci if (state) 6248c2ecf20Sopenharmony_ci itv->i2c_state |= 0x01; 6258c2ecf20Sopenharmony_ci else 6268c2ecf20Sopenharmony_ci itv->i2c_state &= ~0x01; 6278c2ecf20Sopenharmony_ci 6288c2ecf20Sopenharmony_ci /* write them out */ 6298c2ecf20Sopenharmony_ci /* write bits are inverted */ 6308c2ecf20Sopenharmony_ci write_reg(~itv->i2c_state, IVTV_REG_I2C_SETSCL_OFFSET); 6318c2ecf20Sopenharmony_ci} 6328c2ecf20Sopenharmony_ci 6338c2ecf20Sopenharmony_cistatic void ivtv_setsda_old(void *data, int state) 6348c2ecf20Sopenharmony_ci{ 6358c2ecf20Sopenharmony_ci struct ivtv *itv = (struct ivtv *)data; 6368c2ecf20Sopenharmony_ci 6378c2ecf20Sopenharmony_ci if (state) 6388c2ecf20Sopenharmony_ci itv->i2c_state |= 0x01; 6398c2ecf20Sopenharmony_ci else 6408c2ecf20Sopenharmony_ci itv->i2c_state &= ~0x01; 6418c2ecf20Sopenharmony_ci 6428c2ecf20Sopenharmony_ci /* write them out */ 6438c2ecf20Sopenharmony_ci /* write bits are inverted */ 6448c2ecf20Sopenharmony_ci write_reg(~itv->i2c_state, IVTV_REG_I2C_SETSDA_OFFSET); 6458c2ecf20Sopenharmony_ci} 6468c2ecf20Sopenharmony_ci 6478c2ecf20Sopenharmony_cistatic int ivtv_getscl_old(void *data) 6488c2ecf20Sopenharmony_ci{ 6498c2ecf20Sopenharmony_ci struct ivtv *itv = (struct ivtv *)data; 6508c2ecf20Sopenharmony_ci 6518c2ecf20Sopenharmony_ci return read_reg(IVTV_REG_I2C_GETSCL_OFFSET) & 1; 6528c2ecf20Sopenharmony_ci} 6538c2ecf20Sopenharmony_ci 6548c2ecf20Sopenharmony_cistatic int ivtv_getsda_old(void *data) 6558c2ecf20Sopenharmony_ci{ 6568c2ecf20Sopenharmony_ci struct ivtv *itv = (struct ivtv *)data; 6578c2ecf20Sopenharmony_ci 6588c2ecf20Sopenharmony_ci return read_reg(IVTV_REG_I2C_GETSDA_OFFSET) & 1; 6598c2ecf20Sopenharmony_ci} 6608c2ecf20Sopenharmony_ci 6618c2ecf20Sopenharmony_ci/* template for i2c-bit-algo */ 6628c2ecf20Sopenharmony_cistatic const struct i2c_adapter ivtv_i2c_adap_template = { 6638c2ecf20Sopenharmony_ci .name = "ivtv i2c driver", 6648c2ecf20Sopenharmony_ci .algo = NULL, /* set by i2c-algo-bit */ 6658c2ecf20Sopenharmony_ci .algo_data = NULL, /* filled from template */ 6668c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 6678c2ecf20Sopenharmony_ci}; 6688c2ecf20Sopenharmony_ci 6698c2ecf20Sopenharmony_ci#define IVTV_ALGO_BIT_TIMEOUT (2) /* seconds */ 6708c2ecf20Sopenharmony_ci 6718c2ecf20Sopenharmony_cistatic const struct i2c_algo_bit_data ivtv_i2c_algo_template = { 6728c2ecf20Sopenharmony_ci .setsda = ivtv_setsda_old, 6738c2ecf20Sopenharmony_ci .setscl = ivtv_setscl_old, 6748c2ecf20Sopenharmony_ci .getsda = ivtv_getsda_old, 6758c2ecf20Sopenharmony_ci .getscl = ivtv_getscl_old, 6768c2ecf20Sopenharmony_ci .udelay = IVTV_DEFAULT_I2C_CLOCK_PERIOD / 2, /* microseconds */ 6778c2ecf20Sopenharmony_ci .timeout = IVTV_ALGO_BIT_TIMEOUT * HZ, /* jiffies */ 6788c2ecf20Sopenharmony_ci}; 6798c2ecf20Sopenharmony_ci 6808c2ecf20Sopenharmony_cistatic const struct i2c_client ivtv_i2c_client_template = { 6818c2ecf20Sopenharmony_ci .name = "ivtv internal", 6828c2ecf20Sopenharmony_ci}; 6838c2ecf20Sopenharmony_ci 6848c2ecf20Sopenharmony_ci/* init + register i2c adapter */ 6858c2ecf20Sopenharmony_ciint init_ivtv_i2c(struct ivtv *itv) 6868c2ecf20Sopenharmony_ci{ 6878c2ecf20Sopenharmony_ci int retval; 6888c2ecf20Sopenharmony_ci 6898c2ecf20Sopenharmony_ci IVTV_DEBUG_I2C("i2c init\n"); 6908c2ecf20Sopenharmony_ci 6918c2ecf20Sopenharmony_ci /* Sanity checks for the I2C hardware arrays. They must be the 6928c2ecf20Sopenharmony_ci * same size. 6938c2ecf20Sopenharmony_ci */ 6948c2ecf20Sopenharmony_ci if (ARRAY_SIZE(hw_devicenames) != ARRAY_SIZE(hw_addrs)) { 6958c2ecf20Sopenharmony_ci IVTV_ERR("Mismatched I2C hardware arrays\n"); 6968c2ecf20Sopenharmony_ci return -ENODEV; 6978c2ecf20Sopenharmony_ci } 6988c2ecf20Sopenharmony_ci if (itv->options.newi2c > 0) { 6998c2ecf20Sopenharmony_ci itv->i2c_adap = ivtv_i2c_adap_hw_template; 7008c2ecf20Sopenharmony_ci } else { 7018c2ecf20Sopenharmony_ci itv->i2c_adap = ivtv_i2c_adap_template; 7028c2ecf20Sopenharmony_ci itv->i2c_algo = ivtv_i2c_algo_template; 7038c2ecf20Sopenharmony_ci } 7048c2ecf20Sopenharmony_ci itv->i2c_algo.udelay = itv->options.i2c_clock_period / 2; 7058c2ecf20Sopenharmony_ci itv->i2c_algo.data = itv; 7068c2ecf20Sopenharmony_ci itv->i2c_adap.algo_data = &itv->i2c_algo; 7078c2ecf20Sopenharmony_ci 7088c2ecf20Sopenharmony_ci sprintf(itv->i2c_adap.name + strlen(itv->i2c_adap.name), " #%d", 7098c2ecf20Sopenharmony_ci itv->instance); 7108c2ecf20Sopenharmony_ci i2c_set_adapdata(&itv->i2c_adap, &itv->v4l2_dev); 7118c2ecf20Sopenharmony_ci 7128c2ecf20Sopenharmony_ci itv->i2c_client = ivtv_i2c_client_template; 7138c2ecf20Sopenharmony_ci itv->i2c_client.adapter = &itv->i2c_adap; 7148c2ecf20Sopenharmony_ci itv->i2c_adap.dev.parent = &itv->pdev->dev; 7158c2ecf20Sopenharmony_ci 7168c2ecf20Sopenharmony_ci IVTV_DEBUG_I2C("setting scl and sda to 1\n"); 7178c2ecf20Sopenharmony_ci ivtv_setscl(itv, 1); 7188c2ecf20Sopenharmony_ci ivtv_setsda(itv, 1); 7198c2ecf20Sopenharmony_ci 7208c2ecf20Sopenharmony_ci if (itv->options.newi2c > 0) 7218c2ecf20Sopenharmony_ci retval = i2c_add_adapter(&itv->i2c_adap); 7228c2ecf20Sopenharmony_ci else 7238c2ecf20Sopenharmony_ci retval = i2c_bit_add_bus(&itv->i2c_adap); 7248c2ecf20Sopenharmony_ci 7258c2ecf20Sopenharmony_ci return retval; 7268c2ecf20Sopenharmony_ci} 7278c2ecf20Sopenharmony_ci 7288c2ecf20Sopenharmony_civoid exit_ivtv_i2c(struct ivtv *itv) 7298c2ecf20Sopenharmony_ci{ 7308c2ecf20Sopenharmony_ci IVTV_DEBUG_I2C("i2c exit\n"); 7318c2ecf20Sopenharmony_ci 7328c2ecf20Sopenharmony_ci i2c_del_adapter(&itv->i2c_adap); 7338c2ecf20Sopenharmony_ci} 734