V4L/DVB (4924): Fix some bugs on usbvision due to the merge into one module
[safe/jmp/linux-2.6] / drivers / media / video / usbvision / usbvision-i2c.c
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
42 static int debug_i2c_usb = 0;   
43
44 #if defined(module_param)                               // Showing parameters under SYSFS
45 module_param (debug_i2c_usb, int, 0444);                        // debug_i2c_usb mode of the device driver
46 #else
47 MODULE_PARM(debug_i2c_usb, "i");                                // debug_i2c_usb mode of the device driver
48 #endif
49
50
51 static 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
79 static 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
106 static 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
154 static int
155 usb_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
192 static int algo_control(struct i2c_adapter *adapter, unsigned int cmd, unsigned long arg)
193 {
194         return 0;
195 }
196
197 static 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
205 static struct i2c_algorithm i2c_usb_algo = {
206         .master_xfer   = usb_xfer,
207         .smbus_xfer    = NULL,
208         .slave_send    = NULL,
209         .slave_recv    = NULL,
210         .algo_control  = algo_control,
211         .functionality = usb_func,
212 };
213
214
215 /*
216  * registering functions to load algorithms at runtime
217  */
218 int usbvision_i2c_usb_add_bus(struct i2c_adapter *adap)
219 {
220         /* register new adapter to i2c module... */
221
222         adap->algo = &i2c_usb_algo;
223
224         adap->timeout = 100;    /* default values, should       */
225         adap->retries = 3;      /* be replaced by defines       */
226
227 #ifdef MODULE
228         #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 21)
229                 MOD_INC_USE_COUNT;
230         #endif
231 #endif
232
233         i2c_add_adapter(adap);
234
235         if (debug_i2c_usb) {
236                 info("i2c bus for %s registered", adap->name);
237         }
238
239         return 0;
240 }
241
242
243 int usbvision_i2c_usb_del_bus(struct i2c_adapter *adap)
244 {
245
246         i2c_del_adapter(adap);
247
248         if (debug_i2c_usb) {
249                 info("i2c bus for %s unregistered", adap->name);
250         }
251 #ifdef MODULE
252         #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 21)
253                 MOD_DEC_USE_COUNT;
254         #endif
255 #endif
256
257         return 0;
258 }
259
260 EXPORT_SYMBOL(usbvision_i2c_usb_add_bus);
261 EXPORT_SYMBOL(usbvision_i2c_usb_del_bus);