1a6c2ba28Sakpm@osdl.org /* 2f7abcd38SMauro Carvalho Chehab em28xx-i2c.c - driver for Empia EM2800/EM2820/2840 USB video capture devices 3a6c2ba28Sakpm@osdl.org 4f7abcd38SMauro Carvalho Chehab Copyright (C) 2005 Ludovico Cavedon <cavedon@sssup.it> 5f7abcd38SMauro Carvalho Chehab Markus Rechberger <mrechberger@gmail.com> 62e7c6dc3SMauro Carvalho Chehab Mauro Carvalho Chehab <mchehab@infradead.org> 7f7abcd38SMauro Carvalho Chehab Sascha Sommer <saschasommer@freenet.de> 8a6c2ba28Sakpm@osdl.org 9a6c2ba28Sakpm@osdl.org This program is free software; you can redistribute it and/or modify 10a6c2ba28Sakpm@osdl.org it under the terms of the GNU General Public License as published by 11a6c2ba28Sakpm@osdl.org the Free Software Foundation; either version 2 of the License, or 12a6c2ba28Sakpm@osdl.org (at your option) any later version. 13a6c2ba28Sakpm@osdl.org 14a6c2ba28Sakpm@osdl.org This program is distributed in the hope that it will be useful, 15a6c2ba28Sakpm@osdl.org but WITHOUT ANY WARRANTY; without even the implied warranty of 16a6c2ba28Sakpm@osdl.org MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17a6c2ba28Sakpm@osdl.org GNU General Public License for more details. 18a6c2ba28Sakpm@osdl.org 19a6c2ba28Sakpm@osdl.org You should have received a copy of the GNU General Public License 20a6c2ba28Sakpm@osdl.org along with this program; if not, write to the Free Software 21a6c2ba28Sakpm@osdl.org Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 22a6c2ba28Sakpm@osdl.org */ 23a6c2ba28Sakpm@osdl.org 24a6c2ba28Sakpm@osdl.org #include <linux/module.h> 25a6c2ba28Sakpm@osdl.org #include <linux/kernel.h> 26a6c2ba28Sakpm@osdl.org #include <linux/usb.h> 27a6c2ba28Sakpm@osdl.org #include <linux/i2c.h> 28a6c2ba28Sakpm@osdl.org 29f7abcd38SMauro Carvalho Chehab #include "em28xx.h" 306c362c8eSMauro Carvalho Chehab #include "tuner-xc2028.h" 315e453dc7SMichael Krufky #include <media/v4l2-common.h> 32d5e52653SMauro Carvalho Chehab #include <media/tuner.h> 33a6c2ba28Sakpm@osdl.org 34a6c2ba28Sakpm@osdl.org /* ----------------------------------------------------------- */ 35a6c2ba28Sakpm@osdl.org 36ff699e6bSDouglas Schilling Landgraf static unsigned int i2c_scan; 37a6c2ba28Sakpm@osdl.org module_param(i2c_scan, int, 0444); 38a6c2ba28Sakpm@osdl.org MODULE_PARM_DESC(i2c_scan, "scan i2c bus at insmod time"); 39a6c2ba28Sakpm@osdl.org 40ff699e6bSDouglas Schilling Landgraf static unsigned int i2c_debug; 41a6c2ba28Sakpm@osdl.org module_param(i2c_debug, int, 0644); 42a6c2ba28Sakpm@osdl.org MODULE_PARM_DESC(i2c_debug, "enable debug messages [i2c]"); 43a6c2ba28Sakpm@osdl.org 446ea54d93SDouglas Schilling Landgraf #define dprintk2(lvl, fmt, args...) \ 456ea54d93SDouglas Schilling Landgraf do { \ 466ea54d93SDouglas Schilling Landgraf if (i2c_debug >= lvl) { \ 47d5e52653SMauro Carvalho Chehab printk(KERN_DEBUG "%s at %s: " fmt, \ 486ea54d93SDouglas Schilling Landgraf dev->name, __func__ , ##args); \ 496ea54d93SDouglas Schilling Landgraf } \ 506ea54d93SDouglas Schilling Landgraf } while (0) 51a6c2ba28Sakpm@osdl.org 52a6c2ba28Sakpm@osdl.org /* 53f5ae371aSFrank Schaefer * em2800_i2c_send_bytes() 54f5ae371aSFrank Schaefer * send up to 4 bytes to the em2800 i2c device 55596d92d5SMauro Carvalho Chehab */ 56f5ae371aSFrank Schaefer static int em2800_i2c_send_bytes(struct em28xx *dev, u8 addr, u8 *buf, u16 len) 57596d92d5SMauro Carvalho Chehab { 58596d92d5SMauro Carvalho Chehab int ret; 59596d92d5SMauro Carvalho Chehab int write_timeout; 60a6bad040SFrank Schaefer u8 b2[6]; 61f5ae371aSFrank Schaefer 62f5ae371aSFrank Schaefer if (len < 1 || len > 4) 63f5ae371aSFrank Schaefer return -EOPNOTSUPP; 64f5ae371aSFrank Schaefer 65596d92d5SMauro Carvalho Chehab BUG_ON(len < 1 || len > 4); 66596d92d5SMauro Carvalho Chehab b2[5] = 0x80 + len - 1; 67596d92d5SMauro Carvalho Chehab b2[4] = addr; 68596d92d5SMauro Carvalho Chehab b2[3] = buf[0]; 69596d92d5SMauro Carvalho Chehab if (len > 1) 70596d92d5SMauro Carvalho Chehab b2[2] = buf[1]; 71596d92d5SMauro Carvalho Chehab if (len > 2) 72596d92d5SMauro Carvalho Chehab b2[1] = buf[2]; 73596d92d5SMauro Carvalho Chehab if (len > 3) 74596d92d5SMauro Carvalho Chehab b2[0] = buf[3]; 75596d92d5SMauro Carvalho Chehab 762fcc82d8SFrank Schaefer /* trigger write */ 773acf2809SMauro Carvalho Chehab ret = dev->em28xx_write_regs(dev, 4 - len, &b2[4 - len], 2 + len); 78596d92d5SMauro Carvalho Chehab if (ret != 2 + len) { 7945f04e82SFrank Schaefer em28xx_warn("failed to trigger write to i2c address 0x%x " 8045f04e82SFrank Schaefer "(error=%i)\n", addr, ret); 8145f04e82SFrank Schaefer return (ret < 0) ? ret : -EIO; 82596d92d5SMauro Carvalho Chehab } 832fcc82d8SFrank Schaefer /* wait for completion */ 842fcc82d8SFrank Schaefer for (write_timeout = EM2800_I2C_XFER_TIMEOUT; write_timeout > 0; 85596d92d5SMauro Carvalho Chehab write_timeout -= 5) { 863acf2809SMauro Carvalho Chehab ret = dev->em28xx_read_reg(dev, 0x05); 8745f04e82SFrank Schaefer if (ret == 0x80 + len - 1) { 88596d92d5SMauro Carvalho Chehab return len; 8945f04e82SFrank Schaefer } else if (ret == 0x94 + len - 1) { 9045f04e82SFrank Schaefer return -ENODEV; 9145f04e82SFrank Schaefer } else if (ret < 0) { 9245f04e82SFrank Schaefer em28xx_warn("failed to get i2c transfer status from " 9345f04e82SFrank Schaefer "bridge register (error=%i)\n", ret); 9445f04e82SFrank Schaefer return ret; 9545f04e82SFrank Schaefer } 96e8e41da4SMarkus Rechberger msleep(5); 97596d92d5SMauro Carvalho Chehab } 9845f04e82SFrank Schaefer em28xx_warn("write to i2c device at 0x%x timed out\n", addr); 99596d92d5SMauro Carvalho Chehab return -EIO; 100596d92d5SMauro Carvalho Chehab } 101596d92d5SMauro Carvalho Chehab 102596d92d5SMauro Carvalho Chehab /* 103596d92d5SMauro Carvalho Chehab * em2800_i2c_recv_bytes() 1042fcc82d8SFrank Schaefer * read up to 4 bytes from the em2800 i2c device 105596d92d5SMauro Carvalho Chehab */ 106a6bad040SFrank Schaefer static int em2800_i2c_recv_bytes(struct em28xx *dev, u8 addr, u8 *buf, u16 len) 107596d92d5SMauro Carvalho Chehab { 1082fcc82d8SFrank Schaefer u8 buf2[4]; 109596d92d5SMauro Carvalho Chehab int ret; 1102fcc82d8SFrank Schaefer int read_timeout; 1112fcc82d8SFrank Schaefer int i; 112f5ae371aSFrank Schaefer 113f5ae371aSFrank Schaefer if (len < 1 || len > 4) 114f5ae371aSFrank Schaefer return -EOPNOTSUPP; 115f5ae371aSFrank Schaefer 1162fcc82d8SFrank Schaefer /* trigger read */ 1172fcc82d8SFrank Schaefer buf2[1] = 0x84 + len - 1; 1182fcc82d8SFrank Schaefer buf2[0] = addr; 1192fcc82d8SFrank Schaefer ret = dev->em28xx_write_regs(dev, 0x04, buf2, 2); 1202fcc82d8SFrank Schaefer if (ret != 2) { 1212fcc82d8SFrank Schaefer em28xx_warn("failed to trigger read from i2c address 0x%x " 1222fcc82d8SFrank Schaefer "(error=%i)\n", addr, ret); 1232fcc82d8SFrank Schaefer return (ret < 0) ? ret : -EIO; 1242fcc82d8SFrank Schaefer } 1252fcc82d8SFrank Schaefer 1262fcc82d8SFrank Schaefer /* wait for completion */ 1272fcc82d8SFrank Schaefer for (read_timeout = EM2800_I2C_XFER_TIMEOUT; read_timeout > 0; 1282fcc82d8SFrank Schaefer read_timeout -= 5) { 1292fcc82d8SFrank Schaefer ret = dev->em28xx_read_reg(dev, 0x05); 1302fcc82d8SFrank Schaefer if (ret == 0x84 + len - 1) { 1312fcc82d8SFrank Schaefer break; 1322fcc82d8SFrank Schaefer } else if (ret == 0x94 + len - 1) { 1332fcc82d8SFrank Schaefer return -ENODEV; 1342fcc82d8SFrank Schaefer } else if (ret < 0) { 1352fcc82d8SFrank Schaefer em28xx_warn("failed to get i2c transfer status from " 1362fcc82d8SFrank Schaefer "bridge register (error=%i)\n", ret); 137596d92d5SMauro Carvalho Chehab return ret; 138596d92d5SMauro Carvalho Chehab } 1392fcc82d8SFrank Schaefer msleep(5); 1402fcc82d8SFrank Schaefer } 1412fcc82d8SFrank Schaefer if (ret != 0x84 + len - 1) 1422fcc82d8SFrank Schaefer em28xx_warn("read from i2c device at 0x%x timed out\n", addr); 1432fcc82d8SFrank Schaefer 1442fcc82d8SFrank Schaefer /* get the received message */ 1452fcc82d8SFrank Schaefer ret = dev->em28xx_read_reg_req_len(dev, 0x00, 4-len, buf2, len); 1462fcc82d8SFrank Schaefer if (ret != len) { 1472fcc82d8SFrank Schaefer em28xx_warn("reading from i2c device at 0x%x failed: " 1482fcc82d8SFrank Schaefer "couldn't get the received message from the bridge " 1492fcc82d8SFrank Schaefer "(error=%i)\n", addr, ret); 1502fcc82d8SFrank Schaefer return (ret < 0) ? ret : -EIO; 1512fcc82d8SFrank Schaefer } 1522fcc82d8SFrank Schaefer for (i = 0; i < len; i++) 1532fcc82d8SFrank Schaefer buf[i] = buf2[len - 1 - i]; 1542fcc82d8SFrank Schaefer 155596d92d5SMauro Carvalho Chehab return ret; 156596d92d5SMauro Carvalho Chehab } 1572fcc82d8SFrank Schaefer 1582fcc82d8SFrank Schaefer /* 1592fcc82d8SFrank Schaefer * em2800_i2c_check_for_device() 1602fcc82d8SFrank Schaefer * check if there is an i2c device at the supplied address 1612fcc82d8SFrank Schaefer */ 1622fcc82d8SFrank Schaefer static int em2800_i2c_check_for_device(struct em28xx *dev, u8 addr) 1632fcc82d8SFrank Schaefer { 1642fcc82d8SFrank Schaefer u8 buf; 1652fcc82d8SFrank Schaefer int ret; 1662fcc82d8SFrank Schaefer 1672fcc82d8SFrank Schaefer ret = em2800_i2c_recv_bytes(dev, addr, &buf, 1); 1682fcc82d8SFrank Schaefer if (ret == 1) 1692fcc82d8SFrank Schaefer return 0; 1702fcc82d8SFrank Schaefer return (ret < 0) ? ret : -EIO; 171596d92d5SMauro Carvalho Chehab } 172596d92d5SMauro Carvalho Chehab 173596d92d5SMauro Carvalho Chehab /* 1743acf2809SMauro Carvalho Chehab * em28xx_i2c_send_bytes() 175a6c2ba28Sakpm@osdl.org */ 176a6bad040SFrank Schaefer static int em28xx_i2c_send_bytes(struct em28xx *dev, u16 addr, u8 *buf, 177a6bad040SFrank Schaefer u16 len, int stop) 178a6c2ba28Sakpm@osdl.org { 179bbc70e64SMauro Carvalho Chehab int write_timeout, ret; 180a6c2ba28Sakpm@osdl.org 181f5ae371aSFrank Schaefer if (len < 1 || len > 64) 182f5ae371aSFrank Schaefer return -EOPNOTSUPP; 18345f04e82SFrank Schaefer /* NOTE: limited by the USB ctrl message constraints 18445f04e82SFrank Schaefer * Zero length reads always succeed, even if no device is connected */ 185f5ae371aSFrank Schaefer 18645f04e82SFrank Schaefer /* Write to i2c device */ 18745f04e82SFrank Schaefer ret = dev->em28xx_write_regs_req(dev, stop ? 2 : 3, addr, buf, len); 18845f04e82SFrank Schaefer if (ret != len) { 18945f04e82SFrank Schaefer if (ret < 0) { 19045f04e82SFrank Schaefer em28xx_warn("writing to i2c device at 0x%x failed " 19145f04e82SFrank Schaefer "(error=%i)\n", addr, ret); 19245f04e82SFrank Schaefer return ret; 19345f04e82SFrank Schaefer } else { 19445f04e82SFrank Schaefer em28xx_warn("%i bytes write to i2c device at 0x%x " 19545f04e82SFrank Schaefer "requested, but %i bytes written\n", 19645f04e82SFrank Schaefer len, addr, ret); 19745f04e82SFrank Schaefer return -EIO; 19845f04e82SFrank Schaefer } 19945f04e82SFrank Schaefer } 200a6c2ba28Sakpm@osdl.org 20145f04e82SFrank Schaefer /* Check success of the i2c operation */ 2022fcc82d8SFrank Schaefer for (write_timeout = EM2800_I2C_XFER_TIMEOUT; write_timeout > 0; 203bbc70e64SMauro Carvalho Chehab write_timeout -= 5) { 204bbc70e64SMauro Carvalho Chehab ret = dev->em28xx_read_reg(dev, 0x05); 20545f04e82SFrank Schaefer if (ret == 0) { /* success */ 20645f04e82SFrank Schaefer return len; 20745f04e82SFrank Schaefer } else if (ret == 0x10) { 20845f04e82SFrank Schaefer return -ENODEV; 20945f04e82SFrank Schaefer } else if (ret < 0) { 21045f04e82SFrank Schaefer em28xx_warn("failed to read i2c transfer status from " 21145f04e82SFrank Schaefer "bridge (error=%i)\n", ret); 21245f04e82SFrank Schaefer return ret; 213bbc70e64SMauro Carvalho Chehab } 21445f04e82SFrank Schaefer msleep(5); 21545f04e82SFrank Schaefer /* NOTE: do we really have to wait for success ? 21645f04e82SFrank Schaefer Never seen anything else than 0x00 or 0x10 21745f04e82SFrank Schaefer (even with high payload) ... */ 21845f04e82SFrank Schaefer } 21945f04e82SFrank Schaefer em28xx_warn("write to i2c device at 0x%x timed out\n", addr); 22045f04e82SFrank Schaefer return -EIO; 221a6c2ba28Sakpm@osdl.org } 222a6c2ba28Sakpm@osdl.org 223a6c2ba28Sakpm@osdl.org /* 2243acf2809SMauro Carvalho Chehab * em28xx_i2c_recv_bytes() 225a6c2ba28Sakpm@osdl.org * read a byte from the i2c device 226a6c2ba28Sakpm@osdl.org */ 227a6bad040SFrank Schaefer static int em28xx_i2c_recv_bytes(struct em28xx *dev, u16 addr, u8 *buf, u16 len) 228a6c2ba28Sakpm@osdl.org { 229a6c2ba28Sakpm@osdl.org int ret; 230f5ae371aSFrank Schaefer 231f5ae371aSFrank Schaefer if (len < 1 || len > 64) 232f5ae371aSFrank Schaefer return -EOPNOTSUPP; 23345f04e82SFrank Schaefer /* NOTE: limited by the USB ctrl message constraints 23445f04e82SFrank Schaefer * Zero length reads always succeed, even if no device is connected */ 235f5ae371aSFrank Schaefer 23645f04e82SFrank Schaefer /* Read data from i2c device */ 2373acf2809SMauro Carvalho Chehab ret = dev->em28xx_read_reg_req_len(dev, 2, addr, buf, len); 23845f04e82SFrank Schaefer if (ret != len) { 239a6c2ba28Sakpm@osdl.org if (ret < 0) { 24045f04e82SFrank Schaefer em28xx_warn("reading from i2c device at 0x%x failed " 24145f04e82SFrank Schaefer "(error=%i)\n", addr, ret); 24245f04e82SFrank Schaefer return ret; 24345f04e82SFrank Schaefer } else { 24445f04e82SFrank Schaefer em28xx_warn("%i bytes requested from i2c device at " 24545f04e82SFrank Schaefer "0x%x, but %i bytes received\n", 24645f04e82SFrank Schaefer len, addr, ret); 24745f04e82SFrank Schaefer return -EIO; 24845f04e82SFrank Schaefer } 24945f04e82SFrank Schaefer } 25045f04e82SFrank Schaefer 25145f04e82SFrank Schaefer /* Check success of the i2c operation */ 25245f04e82SFrank Schaefer ret = dev->em28xx_read_reg(dev, 0x05); 25345f04e82SFrank Schaefer if (ret < 0) { 25445f04e82SFrank Schaefer em28xx_warn("failed to read i2c transfer status from " 25545f04e82SFrank Schaefer "bridge (error=%i)\n", ret); 256a6c2ba28Sakpm@osdl.org return ret; 257a6c2ba28Sakpm@osdl.org } 25845f04e82SFrank Schaefer if (ret > 0) { 25945f04e82SFrank Schaefer if (ret == 0x10) { 260a6c2ba28Sakpm@osdl.org return -ENODEV; 26145f04e82SFrank Schaefer } else { 26245f04e82SFrank Schaefer em28xx_warn("unknown i2c error (status=%i)\n", ret); 26345f04e82SFrank Schaefer return -EIO; 26445f04e82SFrank Schaefer } 26545f04e82SFrank Schaefer } 26645f04e82SFrank Schaefer return len; 267a6c2ba28Sakpm@osdl.org } 268a6c2ba28Sakpm@osdl.org 269a6c2ba28Sakpm@osdl.org /* 2703acf2809SMauro Carvalho Chehab * em28xx_i2c_check_for_device() 271a6c2ba28Sakpm@osdl.org * check if there is a i2c_device at the supplied address 272a6c2ba28Sakpm@osdl.org */ 273a6bad040SFrank Schaefer static int em28xx_i2c_check_for_device(struct em28xx *dev, u16 addr) 274a6c2ba28Sakpm@osdl.org { 275a6c2ba28Sakpm@osdl.org int ret; 27645f04e82SFrank Schaefer u8 buf; 277a6c2ba28Sakpm@osdl.org 27845f04e82SFrank Schaefer ret = em28xx_i2c_recv_bytes(dev, addr, &buf, 1); 27945f04e82SFrank Schaefer if (ret == 1) 280a6c2ba28Sakpm@osdl.org return 0; 28145f04e82SFrank Schaefer return (ret < 0) ? ret : -EIO; 282a6c2ba28Sakpm@osdl.org } 283a6c2ba28Sakpm@osdl.org 284a6c2ba28Sakpm@osdl.org /* 2853acf2809SMauro Carvalho Chehab * em28xx_i2c_xfer() 286a6c2ba28Sakpm@osdl.org * the main i2c transfer function 287a6c2ba28Sakpm@osdl.org */ 2883acf2809SMauro Carvalho Chehab static int em28xx_i2c_xfer(struct i2c_adapter *i2c_adap, 289a6c2ba28Sakpm@osdl.org struct i2c_msg msgs[], int num) 290a6c2ba28Sakpm@osdl.org { 2913acf2809SMauro Carvalho Chehab struct em28xx *dev = i2c_adap->algo_data; 292a6c2ba28Sakpm@osdl.org int addr, rc, i, byte; 293a6c2ba28Sakpm@osdl.org 294a6c2ba28Sakpm@osdl.org if (num <= 0) 295a6c2ba28Sakpm@osdl.org return 0; 296a6c2ba28Sakpm@osdl.org for (i = 0; i < num; i++) { 297a6c2ba28Sakpm@osdl.org addr = msgs[i].addr << 1; 298d5e52653SMauro Carvalho Chehab dprintk2(2, "%s %s addr=%x len=%d:", 299a6c2ba28Sakpm@osdl.org (msgs[i].flags & I2C_M_RD) ? "read" : "write", 300a6c2ba28Sakpm@osdl.org i == num - 1 ? "stop" : "nonstop", addr, msgs[i].len); 301a6c2ba28Sakpm@osdl.org if (!msgs[i].len) { /* no len: check only for device presence */ 302505b6d0bSMauro Carvalho Chehab if (dev->board.is_em2800) 303596d92d5SMauro Carvalho Chehab rc = em2800_i2c_check_for_device(dev, addr); 304596d92d5SMauro Carvalho Chehab else 3053acf2809SMauro Carvalho Chehab rc = em28xx_i2c_check_for_device(dev, addr); 30645f04e82SFrank Schaefer if (rc == -ENODEV) { 30745f04e82SFrank Schaefer if (i2c_debug >= 2) 30845f04e82SFrank Schaefer printk(" no device\n"); 309a6c2ba28Sakpm@osdl.org return rc; 310a6c2ba28Sakpm@osdl.org } 311596d92d5SMauro Carvalho Chehab } else if (msgs[i].flags & I2C_M_RD) { 312a6c2ba28Sakpm@osdl.org /* read bytes */ 313505b6d0bSMauro Carvalho Chehab if (dev->board.is_em2800) 314596d92d5SMauro Carvalho Chehab rc = em2800_i2c_recv_bytes(dev, addr, 315596d92d5SMauro Carvalho Chehab msgs[i].buf, 316596d92d5SMauro Carvalho Chehab msgs[i].len); 317596d92d5SMauro Carvalho Chehab else 3183acf2809SMauro Carvalho Chehab rc = em28xx_i2c_recv_bytes(dev, addr, 319596d92d5SMauro Carvalho Chehab msgs[i].buf, 320a6c2ba28Sakpm@osdl.org msgs[i].len); 321d5e52653SMauro Carvalho Chehab if (i2c_debug >= 2) { 3226ea54d93SDouglas Schilling Landgraf for (byte = 0; byte < msgs[i].len; byte++) 323a6c2ba28Sakpm@osdl.org printk(" %02x", msgs[i].buf[byte]); 324a6c2ba28Sakpm@osdl.org } 325a6c2ba28Sakpm@osdl.org } else { 326a6c2ba28Sakpm@osdl.org /* write bytes */ 327d5e52653SMauro Carvalho Chehab if (i2c_debug >= 2) { 328a6c2ba28Sakpm@osdl.org for (byte = 0; byte < msgs[i].len; byte++) 329a6c2ba28Sakpm@osdl.org printk(" %02x", msgs[i].buf[byte]); 330a6c2ba28Sakpm@osdl.org } 331505b6d0bSMauro Carvalho Chehab if (dev->board.is_em2800) 332596d92d5SMauro Carvalho Chehab rc = em2800_i2c_send_bytes(dev, addr, 333596d92d5SMauro Carvalho Chehab msgs[i].buf, 334596d92d5SMauro Carvalho Chehab msgs[i].len); 335596d92d5SMauro Carvalho Chehab else 3363acf2809SMauro Carvalho Chehab rc = em28xx_i2c_send_bytes(dev, addr, 337596d92d5SMauro Carvalho Chehab msgs[i].buf, 338596d92d5SMauro Carvalho Chehab msgs[i].len, 339a6c2ba28Sakpm@osdl.org i == num - 1); 340e8e41da4SMarkus Rechberger } 34145f04e82SFrank Schaefer if (rc < 0) { 34245f04e82SFrank Schaefer if (i2c_debug >= 2) 34345f04e82SFrank Schaefer printk(" ERROR: %i\n", rc); 34445f04e82SFrank Schaefer return rc; 34545f04e82SFrank Schaefer } 346d5e52653SMauro Carvalho Chehab if (i2c_debug >= 2) 347a6c2ba28Sakpm@osdl.org printk("\n"); 348a6c2ba28Sakpm@osdl.org } 349a6c2ba28Sakpm@osdl.org 350a6c2ba28Sakpm@osdl.org return num; 351a6c2ba28Sakpm@osdl.org } 352a6c2ba28Sakpm@osdl.org 35303910cc3SMauro Carvalho Chehab /* based on linux/sunrpc/svcauth.h and linux/hash.h 35403910cc3SMauro Carvalho Chehab * The original hash function returns a different value, if arch is x86_64 35503910cc3SMauro Carvalho Chehab * or i386. 35603910cc3SMauro Carvalho Chehab */ 35703910cc3SMauro Carvalho Chehab static inline unsigned long em28xx_hash_mem(char *buf, int length, int bits) 35803910cc3SMauro Carvalho Chehab { 35903910cc3SMauro Carvalho Chehab unsigned long hash = 0; 36003910cc3SMauro Carvalho Chehab unsigned long l = 0; 36103910cc3SMauro Carvalho Chehab int len = 0; 36203910cc3SMauro Carvalho Chehab unsigned char c; 36303910cc3SMauro Carvalho Chehab do { 36403910cc3SMauro Carvalho Chehab if (len == length) { 36503910cc3SMauro Carvalho Chehab c = (char)len; 36603910cc3SMauro Carvalho Chehab len = -1; 36703910cc3SMauro Carvalho Chehab } else 36803910cc3SMauro Carvalho Chehab c = *buf++; 36903910cc3SMauro Carvalho Chehab l = (l << 8) | c; 37003910cc3SMauro Carvalho Chehab len++; 37103910cc3SMauro Carvalho Chehab if ((len & (32 / 8 - 1)) == 0) 37203910cc3SMauro Carvalho Chehab hash = ((hash^l) * 0x9e370001UL); 37303910cc3SMauro Carvalho Chehab } while (len); 37403910cc3SMauro Carvalho Chehab 37503910cc3SMauro Carvalho Chehab return (hash >> (32 - bits)) & 0xffffffffUL; 37603910cc3SMauro Carvalho Chehab } 37703910cc3SMauro Carvalho Chehab 3783acf2809SMauro Carvalho Chehab static int em28xx_i2c_eeprom(struct em28xx *dev, unsigned char *eedata, int len) 379a6c2ba28Sakpm@osdl.org { 380a6c2ba28Sakpm@osdl.org unsigned char buf, *p = eedata; 3813acf2809SMauro Carvalho Chehab struct em28xx_eeprom *em_eeprom = (void *)eedata; 38290271964SFrank Schaefer int i, err, size = len, block, block_max; 383a6c2ba28Sakpm@osdl.org 384fec528b7SMauro Carvalho Chehab if (dev->chip_id == CHIP_ID_EM2874 || 385fec528b7SMauro Carvalho Chehab dev->chip_id == CHIP_ID_EM28174 || 386fec528b7SMauro Carvalho Chehab dev->chip_id == CHIP_ID_EM2884) { 387a527c9f8SDevin Heitmueller /* Empia switched to a 16-bit addressable eeprom in newer 388a527c9f8SDevin Heitmueller devices. While we could certainly write a routine to read 389a527c9f8SDevin Heitmueller the eeprom, there is nothing of use in there that cannot be 390a527c9f8SDevin Heitmueller accessed through registers, and there is the risk that we 391a527c9f8SDevin Heitmueller could corrupt the eeprom (since a 16-bit read call is 392a527c9f8SDevin Heitmueller interpreted as a write call by 8-bit eeproms). 393a527c9f8SDevin Heitmueller */ 394a527c9f8SDevin Heitmueller return 0; 395a527c9f8SDevin Heitmueller } 396a527c9f8SDevin Heitmueller 397a6c2ba28Sakpm@osdl.org dev->i2c_client.addr = 0xa0 >> 1; 398596d92d5SMauro Carvalho Chehab 399596d92d5SMauro Carvalho Chehab /* Check if board has eeprom */ 400596d92d5SMauro Carvalho Chehab err = i2c_master_recv(&dev->i2c_client, &buf, 0); 401f2a01a00SDouglas Schilling Landgraf if (err < 0) { 402c41109fcSMauro Carvalho Chehab em28xx_errdev("board has no eeprom\n"); 403c41109fcSMauro Carvalho Chehab memset(eedata, 0, len); 404c41109fcSMauro Carvalho Chehab return -ENODEV; 405f2a01a00SDouglas Schilling Landgraf } 406596d92d5SMauro Carvalho Chehab 407a6c2ba28Sakpm@osdl.org buf = 0; 4086ea54d93SDouglas Schilling Landgraf 4096ea54d93SDouglas Schilling Landgraf err = i2c_master_send(&dev->i2c_client, &buf, 1); 4106ea54d93SDouglas Schilling Landgraf if (err != 1) { 411a6c2ba28Sakpm@osdl.org printk(KERN_INFO "%s: Huh, no eeprom present (err=%d)?\n", 412a6c2ba28Sakpm@osdl.org dev->name, err); 413f2a01a00SDouglas Schilling Landgraf return err; 414a6c2ba28Sakpm@osdl.org } 41590271964SFrank Schaefer 41690271964SFrank Schaefer if (dev->board.is_em2800) 41790271964SFrank Schaefer block_max = 4; 41890271964SFrank Schaefer else 41990271964SFrank Schaefer block_max = 64; 42090271964SFrank Schaefer 421a6c2ba28Sakpm@osdl.org while (size > 0) { 42290271964SFrank Schaefer if (size > block_max) 42390271964SFrank Schaefer block = block_max; 424a6c2ba28Sakpm@osdl.org else 425a6c2ba28Sakpm@osdl.org block = size; 426a6c2ba28Sakpm@osdl.org 427a6c2ba28Sakpm@osdl.org if (block != 428a6c2ba28Sakpm@osdl.org (err = i2c_master_recv(&dev->i2c_client, p, block))) { 429a6c2ba28Sakpm@osdl.org printk(KERN_WARNING 430a6c2ba28Sakpm@osdl.org "%s: i2c eeprom read error (err=%d)\n", 431a6c2ba28Sakpm@osdl.org dev->name, err); 432f2a01a00SDouglas Schilling Landgraf return err; 433a6c2ba28Sakpm@osdl.org } 434a6c2ba28Sakpm@osdl.org size -= block; 435a6c2ba28Sakpm@osdl.org p += block; 436a6c2ba28Sakpm@osdl.org } 437a6c2ba28Sakpm@osdl.org for (i = 0; i < len; i++) { 438a6c2ba28Sakpm@osdl.org if (0 == (i % 16)) 439a6c2ba28Sakpm@osdl.org printk(KERN_INFO "%s: i2c eeprom %02x:", dev->name, i); 440a6c2ba28Sakpm@osdl.org printk(" %02x", eedata[i]); 441a6c2ba28Sakpm@osdl.org if (15 == (i % 16)) 442a6c2ba28Sakpm@osdl.org printk("\n"); 443a6c2ba28Sakpm@osdl.org } 444a6c2ba28Sakpm@osdl.org 44503910cc3SMauro Carvalho Chehab if (em_eeprom->id == 0x9567eb1a) 44603910cc3SMauro Carvalho Chehab dev->hash = em28xx_hash_mem(eedata, len, 32); 44703910cc3SMauro Carvalho Chehab 4481bee0184SMauro Carvalho Chehab printk(KERN_INFO "%s: EEPROM ID= 0x%08x, EEPROM hash = 0x%08lx\n", 4491bee0184SMauro Carvalho Chehab dev->name, em_eeprom->id, dev->hash); 4501bee0184SMauro Carvalho Chehab 4511bee0184SMauro Carvalho Chehab printk(KERN_INFO "%s: EEPROM info:\n", dev->name); 452a6c2ba28Sakpm@osdl.org 453a6c2ba28Sakpm@osdl.org switch (em_eeprom->chip_conf >> 4 & 0x3) { 454a6c2ba28Sakpm@osdl.org case 0: 4551bee0184SMauro Carvalho Chehab printk(KERN_INFO "%s:\tNo audio on board.\n", dev->name); 456a6c2ba28Sakpm@osdl.org break; 457a6c2ba28Sakpm@osdl.org case 1: 4581bee0184SMauro Carvalho Chehab printk(KERN_INFO "%s:\tAC97 audio (5 sample rates)\n", 4591bee0184SMauro Carvalho Chehab dev->name); 460a6c2ba28Sakpm@osdl.org break; 461a6c2ba28Sakpm@osdl.org case 2: 462a1a6ee74SNicola Soranzo printk(KERN_INFO "%s:\tI2S audio, sample rate=32k\n", 463a1a6ee74SNicola Soranzo dev->name); 464a6c2ba28Sakpm@osdl.org break; 465a6c2ba28Sakpm@osdl.org case 3: 466a1a6ee74SNicola Soranzo printk(KERN_INFO "%s:\tI2S audio, 3 sample rates\n", 467a1a6ee74SNicola Soranzo dev->name); 468a6c2ba28Sakpm@osdl.org break; 469a6c2ba28Sakpm@osdl.org } 470a6c2ba28Sakpm@osdl.org 471a6c2ba28Sakpm@osdl.org if (em_eeprom->chip_conf & 1 << 3) 4721bee0184SMauro Carvalho Chehab printk(KERN_INFO "%s:\tUSB Remote wakeup capable\n", dev->name); 473a6c2ba28Sakpm@osdl.org 474a6c2ba28Sakpm@osdl.org if (em_eeprom->chip_conf & 1 << 2) 4751bee0184SMauro Carvalho Chehab printk(KERN_INFO "%s:\tUSB Self power capable\n", dev->name); 476a6c2ba28Sakpm@osdl.org 477a6c2ba28Sakpm@osdl.org switch (em_eeprom->chip_conf & 0x3) { 478a6c2ba28Sakpm@osdl.org case 0: 4791bee0184SMauro Carvalho Chehab printk(KERN_INFO "%s:\t500mA max power\n", dev->name); 480a6c2ba28Sakpm@osdl.org break; 481a6c2ba28Sakpm@osdl.org case 1: 4821bee0184SMauro Carvalho Chehab printk(KERN_INFO "%s:\t400mA max power\n", dev->name); 483a6c2ba28Sakpm@osdl.org break; 484a6c2ba28Sakpm@osdl.org case 2: 4851bee0184SMauro Carvalho Chehab printk(KERN_INFO "%s:\t300mA max power\n", dev->name); 486a6c2ba28Sakpm@osdl.org break; 487a6c2ba28Sakpm@osdl.org case 3: 4881bee0184SMauro Carvalho Chehab printk(KERN_INFO "%s:\t200mA max power\n", dev->name); 489a6c2ba28Sakpm@osdl.org break; 490a6c2ba28Sakpm@osdl.org } 4911bee0184SMauro Carvalho Chehab printk(KERN_INFO "%s:\tTable at 0x%02x, strings=0x%04x, 0x%04x, 0x%04x\n", 4921bee0184SMauro Carvalho Chehab dev->name, 4936ea54d93SDouglas Schilling Landgraf em_eeprom->string_idx_table, 4946ea54d93SDouglas Schilling Landgraf em_eeprom->string1, 4956ea54d93SDouglas Schilling Landgraf em_eeprom->string2, 4966ea54d93SDouglas Schilling Landgraf em_eeprom->string3); 497a6c2ba28Sakpm@osdl.org 498a6c2ba28Sakpm@osdl.org return 0; 499a6c2ba28Sakpm@osdl.org } 500a6c2ba28Sakpm@osdl.org 501a6c2ba28Sakpm@osdl.org /* ----------------------------------------------------------- */ 502a6c2ba28Sakpm@osdl.org 503a6c2ba28Sakpm@osdl.org /* 504a6c2ba28Sakpm@osdl.org * functionality() 505a6c2ba28Sakpm@osdl.org */ 506a6c2ba28Sakpm@osdl.org static u32 functionality(struct i2c_adapter *adap) 507a6c2ba28Sakpm@osdl.org { 508eaf33c40SFrank Schaefer struct em28xx *dev = adap->algo_data; 509eaf33c40SFrank Schaefer u32 func_flags = I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL; 510eaf33c40SFrank Schaefer if (dev->board.is_em2800) 511eaf33c40SFrank Schaefer func_flags &= ~I2C_FUNC_SMBUS_WRITE_BLOCK_DATA; 512eaf33c40SFrank Schaefer return func_flags; 513a6c2ba28Sakpm@osdl.org } 514a6c2ba28Sakpm@osdl.org 5153acf2809SMauro Carvalho Chehab static struct i2c_algorithm em28xx_algo = { 5163acf2809SMauro Carvalho Chehab .master_xfer = em28xx_i2c_xfer, 517a6c2ba28Sakpm@osdl.org .functionality = functionality, 518a6c2ba28Sakpm@osdl.org }; 519a6c2ba28Sakpm@osdl.org 5203acf2809SMauro Carvalho Chehab static struct i2c_adapter em28xx_adap_template = { 521a6c2ba28Sakpm@osdl.org .owner = THIS_MODULE, 5223acf2809SMauro Carvalho Chehab .name = "em28xx", 5233acf2809SMauro Carvalho Chehab .algo = &em28xx_algo, 524a6c2ba28Sakpm@osdl.org }; 525a6c2ba28Sakpm@osdl.org 5263acf2809SMauro Carvalho Chehab static struct i2c_client em28xx_client_template = { 5273acf2809SMauro Carvalho Chehab .name = "em28xx internal", 528a6c2ba28Sakpm@osdl.org }; 529a6c2ba28Sakpm@osdl.org 530a6c2ba28Sakpm@osdl.org /* ----------------------------------------------------------- */ 531a6c2ba28Sakpm@osdl.org 532a6c2ba28Sakpm@osdl.org /* 533a6c2ba28Sakpm@osdl.org * i2c_devs 534a6c2ba28Sakpm@osdl.org * incomplete list of known devices 535a6c2ba28Sakpm@osdl.org */ 536a6c2ba28Sakpm@osdl.org static char *i2c_devs[128] = { 537*0b3966e4SFrank Schaefer [0x3e >> 1] = "remote IR sensor", 538a6c2ba28Sakpm@osdl.org [0x4a >> 1] = "saa7113h", 539729841edSMartin Blumenstingl [0x52 >> 1] = "drxk", 540a6c2ba28Sakpm@osdl.org [0x60 >> 1] = "remote IR sensor", 541da45a2a5SMarkus Rechberger [0x8e >> 1] = "remote IR sensor", 542a6c2ba28Sakpm@osdl.org [0x86 >> 1] = "tda9887", 543a6c2ba28Sakpm@osdl.org [0x80 >> 1] = "msp34xx", 544a6c2ba28Sakpm@osdl.org [0x88 >> 1] = "msp34xx", 545a6c2ba28Sakpm@osdl.org [0xa0 >> 1] = "eeprom", 5462bd1d9ebSVitaly Wool [0xb0 >> 1] = "tda9874", 547a6c2ba28Sakpm@osdl.org [0xb8 >> 1] = "tvp5150a", 548791a08fcSMauro Carvalho Chehab [0xba >> 1] = "webcam sensor or tvp5150a", 549a6c2ba28Sakpm@osdl.org [0xc0 >> 1] = "tuner (analog)", 550a6c2ba28Sakpm@osdl.org [0xc2 >> 1] = "tuner (analog)", 551a6c2ba28Sakpm@osdl.org [0xc4 >> 1] = "tuner (analog)", 552a6c2ba28Sakpm@osdl.org [0xc6 >> 1] = "tuner (analog)", 553a6c2ba28Sakpm@osdl.org }; 554a6c2ba28Sakpm@osdl.org 555a6c2ba28Sakpm@osdl.org /* 556a6c2ba28Sakpm@osdl.org * do_i2c_scan() 557a6c2ba28Sakpm@osdl.org * check i2c address range for devices 558a6c2ba28Sakpm@osdl.org */ 559fad7b958SSascha Sommer void em28xx_do_i2c_scan(struct em28xx *dev) 560a6c2ba28Sakpm@osdl.org { 561fad7b958SSascha Sommer u8 i2c_devicelist[128]; 562a6c2ba28Sakpm@osdl.org unsigned char buf; 563a6c2ba28Sakpm@osdl.org int i, rc; 564a6c2ba28Sakpm@osdl.org 565fad7b958SSascha Sommer memset(i2c_devicelist, 0, ARRAY_SIZE(i2c_devicelist)); 566fad7b958SSascha Sommer 56753c4e955SMauro Carvalho Chehab for (i = 0; i < ARRAY_SIZE(i2c_devs); i++) { 568fad7b958SSascha Sommer dev->i2c_client.addr = i; 569fad7b958SSascha Sommer rc = i2c_master_recv(&dev->i2c_client, &buf, 0); 570a6c2ba28Sakpm@osdl.org if (rc < 0) 571a6c2ba28Sakpm@osdl.org continue; 572fad7b958SSascha Sommer i2c_devicelist[i] = i; 573fad7b958SSascha Sommer printk(KERN_INFO "%s: found i2c device @ 0x%x [%s]\n", 574fad7b958SSascha Sommer dev->name, i << 1, i2c_devs[i] ? i2c_devs[i] : "???"); 575a6c2ba28Sakpm@osdl.org } 576fad7b958SSascha Sommer 577fad7b958SSascha Sommer dev->i2c_hash = em28xx_hash_mem(i2c_devicelist, 578fad7b958SSascha Sommer ARRAY_SIZE(i2c_devicelist), 32); 579a6c2ba28Sakpm@osdl.org } 580a6c2ba28Sakpm@osdl.org 581a6c2ba28Sakpm@osdl.org /* 5823acf2809SMauro Carvalho Chehab * em28xx_i2c_register() 583a6c2ba28Sakpm@osdl.org * register i2c bus 584a6c2ba28Sakpm@osdl.org */ 5853acf2809SMauro Carvalho Chehab int em28xx_i2c_register(struct em28xx *dev) 586a6c2ba28Sakpm@osdl.org { 587f2a01a00SDouglas Schilling Landgraf int retval; 588f2a01a00SDouglas Schilling Landgraf 5893acf2809SMauro Carvalho Chehab BUG_ON(!dev->em28xx_write_regs || !dev->em28xx_read_reg); 5903acf2809SMauro Carvalho Chehab BUG_ON(!dev->em28xx_write_regs_req || !dev->em28xx_read_reg_req); 5913acf2809SMauro Carvalho Chehab dev->i2c_adap = em28xx_adap_template; 592a6c2ba28Sakpm@osdl.org dev->i2c_adap.dev.parent = &dev->udev->dev; 593a6c2ba28Sakpm@osdl.org strcpy(dev->i2c_adap.name, dev->name); 594a6c2ba28Sakpm@osdl.org dev->i2c_adap.algo_data = dev; 595f2cf250aSDouglas Schilling Landgraf i2c_set_adapdata(&dev->i2c_adap, &dev->v4l2_dev); 596f2a01a00SDouglas Schilling Landgraf 597f2a01a00SDouglas Schilling Landgraf retval = i2c_add_adapter(&dev->i2c_adap); 598f2a01a00SDouglas Schilling Landgraf if (retval < 0) { 599f2a01a00SDouglas Schilling Landgraf em28xx_errdev("%s: i2c_add_adapter failed! retval [%d]\n", 600f2a01a00SDouglas Schilling Landgraf __func__, retval); 601f2a01a00SDouglas Schilling Landgraf return retval; 602f2a01a00SDouglas Schilling Landgraf } 603a6c2ba28Sakpm@osdl.org 6043acf2809SMauro Carvalho Chehab dev->i2c_client = em28xx_client_template; 605a6c2ba28Sakpm@osdl.org dev->i2c_client.adapter = &dev->i2c_adap; 606a6c2ba28Sakpm@osdl.org 607f2a01a00SDouglas Schilling Landgraf retval = em28xx_i2c_eeprom(dev, dev->eedata, sizeof(dev->eedata)); 608c41109fcSMauro Carvalho Chehab if ((retval < 0) && (retval != -ENODEV)) { 609f2a01a00SDouglas Schilling Landgraf em28xx_errdev("%s: em28xx_i2_eeprom failed! retval [%d]\n", 610f2a01a00SDouglas Schilling Landgraf __func__, retval); 611c41109fcSMauro Carvalho Chehab 612f2a01a00SDouglas Schilling Landgraf return retval; 613f2a01a00SDouglas Schilling Landgraf } 614a6c2ba28Sakpm@osdl.org 615a6c2ba28Sakpm@osdl.org if (i2c_scan) 616fad7b958SSascha Sommer em28xx_do_i2c_scan(dev); 617c41109fcSMauro Carvalho Chehab 618a6c2ba28Sakpm@osdl.org return 0; 619a6c2ba28Sakpm@osdl.org } 620a6c2ba28Sakpm@osdl.org 621a6c2ba28Sakpm@osdl.org /* 6223acf2809SMauro Carvalho Chehab * em28xx_i2c_unregister() 623a6c2ba28Sakpm@osdl.org * unregister i2c_bus 624a6c2ba28Sakpm@osdl.org */ 6253acf2809SMauro Carvalho Chehab int em28xx_i2c_unregister(struct em28xx *dev) 626a6c2ba28Sakpm@osdl.org { 627a6c2ba28Sakpm@osdl.org i2c_del_adapter(&dev->i2c_adap); 628a6c2ba28Sakpm@osdl.org return 0; 629a6c2ba28Sakpm@osdl.org } 630