usbvision-i2c.c revision f2242ee5474f46d87a45cd4e214b5c3aa02ff293
1/* 2 * I2C_ALGO_USB.C 3 * i2c algorithm for USB-I2C Bridges 4 * 5 * Copyright (c) 1999-2005 Joerg Heckenbach <joerg@heckenbach-aw.de> 6 * Dwaine Garden <dwainegarden@rogers.com> 7 * 8 * This module is part of usbvision driver project. 9 * Updates to driver completed by Dwaine P. Garden 10 * 11 * This program is free software; you can redistribute it and/or modify 12 * it under the terms of the GNU General Public License as published by 13 * the Free Software Foundation; either version 2 of the License, or 14 * (at your option) any later version. 15 * 16 * This program is distributed in the hope that it will be useful, 17 * but WITHOUT ANY WARRANTY; without even the implied warranty of 18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 19 * GNU General Public License for more details. 20 * 21 * You should have received a copy of the GNU General Public License 22 * along with this program; if not, write to the Free Software 23 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 24 */ 25 26 27#include <linux/kernel.h> 28#include <linux/module.h> 29#include <linux/delay.h> 30#include <linux/slab.h> 31#include <linux/version.h> 32 #include <linux/utsname.h> 33#include <linux/init.h> 34#include <asm/uaccess.h> 35#include <linux/ioport.h> 36#include <linux/errno.h> 37#include <linux/sched.h> 38#include <linux/usb.h> 39#include <linux/i2c.h> 40#include "usbvision-i2c.h" 41 42static int debug_i2c_usb = 0; 43 44#if defined(module_param) // Showing parameters under SYSFS 45module_param (debug_i2c_usb, int, 0444); // debug_i2c_usb mode of the device driver 46#else 47MODULE_PARM(debug_i2c_usb, "i"); // debug_i2c_usb mode of the device driver 48#endif 49 50 51static inline int try_write_address(struct i2c_adapter *i2c_adap, 52 unsigned char addr, int retries) 53{ 54 struct i2c_algo_usb_data *adap = i2c_adap->algo_data; 55 void *data; 56 int i, ret = -1; 57 char buf[4]; 58 59 data = i2c_get_adapdata(i2c_adap); 60 buf[0] = 0x00; 61 for (i = 0; i <= retries; i++) { 62 ret = (adap->outb(data, addr, buf, 1)); 63 if (ret == 1) 64 break; /* success! */ 65 udelay(5 /*adap->udelay */ ); 66 if (i == retries) /* no success */ 67 break; 68 udelay(adap->udelay); 69 } 70 if (debug_i2c_usb) { 71 if (i) { 72 info("%s: Needed %d retries for address %#2x", __FUNCTION__, i, addr); 73 info("%s: Maybe there's no device at this address", __FUNCTION__); 74 } 75 } 76 return ret; 77} 78 79static inline int try_read_address(struct i2c_adapter *i2c_adap, 80 unsigned char addr, int retries) 81{ 82 struct i2c_algo_usb_data *adap = i2c_adap->algo_data; 83 void *data; 84 int i, ret = -1; 85 char buf[4]; 86 87 data = i2c_get_adapdata(i2c_adap); 88 for (i = 0; i <= retries; i++) { 89 ret = (adap->inb(data, addr, buf, 1)); 90 if (ret == 1) 91 break; /* success! */ 92 udelay(5 /*adap->udelay */ ); 93 if (i == retries) /* no success */ 94 break; 95 udelay(adap->udelay); 96 } 97 if (debug_i2c_usb) { 98 if (i) { 99 info("%s: Needed %d retries for address %#2x", __FUNCTION__, i, addr); 100 info("%s: Maybe there's no device at this address", __FUNCTION__); 101 } 102 } 103 return ret; 104} 105 106static inline int usb_find_address(struct i2c_adapter *i2c_adap, 107 struct i2c_msg *msg, int retries, 108 unsigned char *add) 109{ 110 unsigned short flags = msg->flags; 111 112 unsigned char addr; 113 int ret; 114 if ((flags & I2C_M_TEN)) { 115 /* a ten bit address */ 116 addr = 0xf0 | ((msg->addr >> 7) & 0x03); 117 /* try extended address code... */ 118 ret = try_write_address(i2c_adap, addr, retries); 119 if (ret != 1) { 120 err("died at extended address code, while writing"); 121 return -EREMOTEIO; 122 } 123 add[0] = addr; 124 if (flags & I2C_M_RD) { 125 /* okay, now switch into reading mode */ 126 addr |= 0x01; 127 ret = try_read_address(i2c_adap, addr, retries); 128 if (ret != 1) { 129 err("died at extended address code, while reading"); 130 return -EREMOTEIO; 131 } 132 } 133 134 } else { /* normal 7bit address */ 135 addr = (msg->addr << 1); 136 if (flags & I2C_M_RD) 137 addr |= 1; 138 if (flags & I2C_M_REV_DIR_ADDR) 139 addr ^= 1; 140 141 add[0] = addr; 142 if (flags & I2C_M_RD) 143 ret = try_read_address(i2c_adap, addr, retries); 144 else 145 ret = try_write_address(i2c_adap, addr, retries); 146 147 if (ret != 1) { 148 return -EREMOTEIO; 149 } 150 } 151 return 0; 152} 153 154static int 155usb_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg msgs[], int num) 156{ 157 struct i2c_msg *pmsg; 158 struct i2c_algo_usb_data *adap = i2c_adap->algo_data; 159 void *data; 160 int i, ret; 161 unsigned char addr; 162 163 data = i2c_get_adapdata(i2c_adap); 164 165 for (i = 0; i < num; i++) { 166 pmsg = &msgs[i]; 167 ret = usb_find_address(i2c_adap, pmsg, i2c_adap->retries, &addr); 168 if (ret != 0) { 169 if (debug_i2c_usb) { 170 info("%s: got NAK from device, message #%d\n", __FUNCTION__, i); 171 } 172 return (ret < 0) ? ret : -EREMOTEIO; 173 } 174 175 if (pmsg->flags & I2C_M_RD) { 176 /* read bytes into buffer */ 177 ret = (adap->inb(data, addr, pmsg->buf, pmsg->len)); 178 if (ret < pmsg->len) { 179 return (ret < 0) ? ret : -EREMOTEIO; 180 } 181 } else { 182 /* write bytes from buffer */ 183 ret = (adap->outb(data, addr, pmsg->buf, pmsg->len)); 184 if (ret < pmsg->len) { 185 return (ret < 0) ? ret : -EREMOTEIO; 186 } 187 } 188 } 189 return num; 190} 191 192static int algo_control(struct i2c_adapter *adapter, unsigned int cmd, unsigned long arg) 193{ 194 return 0; 195} 196 197static u32 usb_func(struct i2c_adapter *adap) 198{ 199 return I2C_FUNC_SMBUS_EMUL | I2C_FUNC_10BIT_ADDR | I2C_FUNC_PROTOCOL_MANGLING; 200} 201 202 203/* -----exported algorithm data: ------------------------------------- */ 204 205static struct i2c_algorithm i2c_usb_algo = { 206 .master_xfer = usb_xfer, 207 .smbus_xfer = NULL, 208 .algo_control = algo_control, 209 .functionality = usb_func, 210}; 211 212 213/* 214 * registering functions to load algorithms at runtime 215 */ 216int usbvision_i2c_usb_add_bus(struct i2c_adapter *adap) 217{ 218 /* register new adapter to i2c module... */ 219 220 adap->algo = &i2c_usb_algo; 221 222 adap->timeout = 100; /* default values, should */ 223 adap->retries = 3; /* be replaced by defines */ 224 225#ifdef MODULE 226 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 21) 227 MOD_INC_USE_COUNT; 228 #endif 229#endif 230 231 i2c_add_adapter(adap); 232 233 if (debug_i2c_usb) { 234 info("i2c bus for %s registered", adap->name); 235 } 236 237 return 0; 238} 239 240 241int usbvision_i2c_usb_del_bus(struct i2c_adapter *adap) 242{ 243 244 i2c_del_adapter(adap); 245 246 if (debug_i2c_usb) { 247 info("i2c bus for %s unregistered", adap->name); 248 } 249#ifdef MODULE 250 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 21) 251 MOD_DEC_USE_COUNT; 252 #endif 253#endif 254 255 return 0; 256} 257 258EXPORT_SYMBOL(usbvision_i2c_usb_add_bus); 259EXPORT_SYMBOL(usbvision_i2c_usb_del_bus); 260