7 * @brief Common functions and data for the Sonix SN9C20x webcam bridge chips.
9 * @note Copyright (C) Dave Neuer
13 * This program is free software; you can redistribute it and/or modify
14 * it under the terms of the GNU General Public License as published by
15 * the Free Software Foundation; either version 2 of the License, or
18 * This program is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU General Public License for more details.
23 * You should have received a copy of the GNU General Public License
24 * along with this program; if not, write to the Free Software
25 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
28 #include <linux/delay.h>
29 #include <linux/errno.h>
30 #include <linux/string.h>
34 int sn9c20x_i2c_ack_wait(struct usb_microdia
*, bool, bool *);
37 * @brief Read a single byte of data from an I2C slave
39 * @param dev Pointer to the device
40 * @param slave The id of the I2C slave device
41 * @param address The address of the register on the slave to read
42 * @param flags The appropriate flags for bus speed and physical connection
43 * @param data A pointer to the location at which the result should be stored
45 * @return Zero for success or a negative error value
48 int sn9c20x_read_i2c_data(struct usb_microdia
* dev
, __u8 slave
, __u8 nbytes
, __u8 address
,
49 __u8 flags
, __u8
* result
)
54 if(!dev
|| nbytes
> 4)
57 /* first, we must do a dummy write of just the address */
58 ret
= sn9c20x_write_i2c_data(dev
, slave
, 0, address
, flags
, NULL
);
63 /* now we issue the same command but with the read bit set
64 * and no slave register address */
65 ret
= sn9c20x_write_i2c_data(dev
, slave
, nbytes
- 1, 0, flags
|
66 SN9C20X_I2C_READ
, row
);
70 /* finally, ask the bridge for the data */
71 ret
= usb_microdia_control_read(dev
, 0x10c2, row
, 5);
75 for(i
= 0, j
= 5 - nbytes
; i
< nbytes
; i
++, j
++)
81 static const char *wasread
= "read from";
82 static const char *waswrite
= "write to";
85 * @brief Write up to 5 bytes of data to an I2C slave
87 * @param dev Pointer to the device
88 * @param slave The id of the I2C slave device
89 * @param nbytes The number of bytes of data
90 * @param address The address of the register on the slave to write
91 * @param flags The appropriate flags for bus speed and physical connection
92 * @param data An array containing the data to write
94 * @return Zero for success or a negative error value
97 int sn9c20x_write_i2c_data(struct usb_microdia
* dev
, __u8 slave
, __u8 nbytes
,
98 __u8 address
, __u8 flags
, const __u8 data
[nbytes
])
102 bool slave_error
= 0;
104 if(!dev
|| (nbytes
> 0 && !data
) || nbytes
> 4)
107 /* from the point of view of the bridge, the length
108 * includes the address */
109 row
[0] = flags
| ((nbytes
+ 1) << 4);
112 row
[7] = 0x10; /* I think this means we want an ack */
114 for(i
= 0; i
< 4; i
++)
115 row
[i
+ 3] = i
< nbytes
? data
[i
] : 0;
117 UDIA_DEBUG("I2C %s %02x: %02x %02x %02x %02x %02x %02x %02x %02x\n",
118 (flags
& SN9C20X_I2C_READ
? wasread
: waswrite
), address
,
119 row
[0], row
[1], row
[2], row
[3], row
[4], row
[5], row
[6], row
[7]);
121 ret
= usb_microdia_control_write(dev
, 0x10c0, row
, 8);
123 ret
= sn9c20x_i2c_ack_wait(dev
, flags
& SN9C20X_I2C_400KHZ
,
127 UDIA_ERROR("I2C slave %x returned error during %s address %x\n",
129 (flags
& SN9C20X_I2C_READ
? wasread
: waswrite
),
131 return -1000; // there should be no interference with USB errors
136 UDIA_ERROR("No ack from I2C slave %x for %s address %x\n",
138 (flags
& SN9C20X_I2C_READ
? wasread
: waswrite
),
146 int sn9c20x_i2c_ack_wait(struct usb_microdia
*dev
, bool highspeed
, bool * slave_error
)
150 int delay
= highspeed
? 100 : 400;
152 for(i
= 0; i
< 5; i
++) {
153 ret
= usb_microdia_control_read(dev
, 0x10c0, &readbuf
, 1);
157 else if(readbuf
& SN9C20X_I2C_ERROR
) {
159 /* probably should come up w/ an error value and
160 * return it via the error return */
163 else if(readbuf
& SN9C20X_I2C_READY
)