Adding stop stream support for 627b
[microdia.git] / sn9c20x.c
bloba265ffa86ad45fd67f28c8d8ce943f3325c7e9f9
1 /**
2 * @file sn9c20x.c
3 * @author Dave Neuer
4 * @date 2008-03-02
5 * @version v0.0.0
7 * @brief Common functions and data for the Sonix SN9C20x webcam bridge chips.
9 * @note Copyright (C) Dave Neuer
11 * @par Licences
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
16 * any later version.
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>
31 #include "microdia.h"
32 #include "sn9c20x.h"
34 int sn9c20x_i2c_ack_wait(struct usb_microdia *, bool, bool *);
36 /**
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)
51 int ret, i, j;
52 __u8 row[5];
54 if(!dev || nbytes > 4)
55 return -EINVAL;
57 /* first, we must do a dummy write of just the address */
58 ret = sn9c20x_write_i2c_data(dev, slave, 0, address, flags, NULL);
59 if(ret < 0)
60 return ret;
62 memset(row, 0, 5);
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);
67 if(ret < 0)
68 return ret;
70 /* finally, ask the bridge for the data */
71 ret = usb_microdia_control_read(dev, 0x10c2, row, 5);
72 if(ret < 0)
73 return ret;
75 for(i = 0, j = 5 - nbytes; i < nbytes; i++, j++)
76 result[i] = row[j];
78 return 0;
81 static const char *wasread = "read from";
82 static const char *waswrite = "write to";
84 /**
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])
100 int ret, i;
101 __u8 row[8];
102 bool slave_error = 0;
104 if(!dev || (nbytes > 0 && !data) || nbytes > 4)
105 return -EINVAL;
107 /* from the point of view of the bridge, the length
108 * includes the address */
109 row[0] = flags | ((nbytes + 1) << 4);
110 row[1] = slave;
111 row[2] = address;
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);
122 if(ret >= 0)
123 ret = sn9c20x_i2c_ack_wait(dev, flags & SN9C20X_I2C_400KHZ,
124 &slave_error);
126 if(slave_error) {
127 UDIA_ERROR("I2C slave %x returned error during %s address %x\n",
128 slave,
129 (flags & SN9C20X_I2C_READ ? wasread : waswrite),
130 address);
131 return -1000; // there should be no interference with USB errors
134 if(ret < 0) {
135 /* we got no ack */
136 UDIA_ERROR("No ack from I2C slave %x for %s address %x\n",
137 slave,
138 (flags & SN9C20X_I2C_READ ? wasread : waswrite),
139 address);
140 return ret;
143 return 0;
146 int sn9c20x_i2c_ack_wait(struct usb_microdia *dev, bool highspeed, bool * slave_error)
148 int ret, i;
149 __u8 readbuf;
150 int delay = highspeed ? 100 : 400;
152 for(i = 0; i< 5; i++) {
153 ret = usb_microdia_control_read(dev, 0x10c0, &readbuf, 1);
155 if(ret < 0)
156 return ret;
157 else if(readbuf & SN9C20X_I2C_ERROR) {
158 *slave_error = 1;
159 /* probably should come up w/ an error value and
160 * return it via the error return */
161 return 0;
163 else if(readbuf & SN9C20X_I2C_READY)
164 return 0;
165 else
166 udelay(delay);
169 return -EBUSY;