Added support for O_NONBLOCK in DQBUF ioctl
[microdia.git] / sn9c20x.c
blobfc9455627da8dc2149fd8ddcb197bf05dbfa925a
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"
35 int sn9c20x_i2c_ack_wait(struct usb_microdia *, bool, bool *);
38 /**
39 * @brief Initializes IC2-registers 0x10c0-0x10c7
41 * @param dev Pointer to the device
42 * @param flags The appropriate flags for bus speed and physical connection
43 * @param slave The id of the I2C slave device
45 * @return Zero (success) or negative (USB-error value)
48 int sn9c20x_initialize_i2c(struct usb_microdia * dev, __u8 flags, __u8 slave)
50 __u8 buf[8];
51 int ret;
53 buf[0] = 0x81 & flags;
54 buf[1] = slave;
55 buf[2] = 0x00;
56 buf[3] = 0x00;
57 buf[4] = 0x00;
58 buf[5] = 0x00;
59 buf[6] = 0x00;
60 buf[7] = 0x00;
61 ret = usb_microdia_control_write(dev, 0x10c0, buf, 8);
62 if (ret < 0)
63 return ret;
64 else
65 return 0;
68 /**
69 * @brief Read a single byte of data from an I2C slave
71 * @param dev Pointer to the device
72 * @param slave The id of the I2C slave device
73 * @param nbytes Number of bytes to read
74 * @param address The address of the register on the slave to read
75 * @param flags The appropriate flags for bus speed and physical connection
76 * @param result A pointer to the location at which the result should be stored
78 * @return Zero for success or a negative error value
81 int sn9c20x_read_i2c_data(struct usb_microdia * dev, __u8 slave, __u8 nbytes, __u8 address,
82 __u8 flags, __u8 * result)
84 int ret, i, j;
85 __u8 row[5];
87 if(!dev || nbytes > 4)
88 return -EINVAL;
90 /* first, we must do a dummy write of just the address */
91 ret = sn9c20x_write_i2c_data(dev, slave, 0, address, flags, NULL);
92 if(ret < 0)
93 return ret;
95 memset(row, 0, 5);
96 /* now we issue the same command but with the read bit set
97 * and no slave register address */
98 ret = sn9c20x_write_i2c_data(dev, slave, nbytes - 1, 0, flags |
99 SN9C20X_I2C_READ, row);
100 if(ret < 0)
101 return ret;
103 /* finally, ask the bridge for the data */
104 ret = usb_microdia_control_read(dev, 0x10c2, row, 5);
105 if(ret < 0)
106 return ret;
108 for(i = 0, j = 5 - nbytes; i < nbytes; i++, j++)
109 result[i] = row[j];
111 return 0;
114 static const char *wasread = "read from";
115 static const char *waswrite = "write to";
118 * @brief Write up to 5 bytes of data to an I2C slave
120 * @param dev Pointer to the device
121 * @param slave The id of the I2C slave device
122 * @param nbytes The number of bytes of data
123 * @param address The address of the register on the slave to write
124 * @param flags The appropriate flags for bus speed and physical connection
125 * @param data An array containing the data to write
127 * @return Zero for success or a negative error value
130 int sn9c20x_write_i2c_data(struct usb_microdia * dev, __u8 slave, __u8 nbytes,
131 __u8 address, __u8 flags, const __u8 data[nbytes])
133 int ret, i;
134 __u8 row[8];
135 bool slave_error = 0;
137 if(!dev || (nbytes > 0 && !data) || nbytes > 4)
138 return -EINVAL;
140 /* from the point of view of the bridge, the length
141 * includes the address */
142 row[0] = flags | ((nbytes + 1) << 4);
143 row[1] = slave;
144 row[2] = address;
145 row[7] = 0x10; /* I think this means we want an ack */
147 for(i = 0; i < 4; i++)
148 row[i + 3] = i < nbytes ? data[i] : 0;
150 UDIA_DEBUG("I2C %s %02x: %02x %02x %02x %02x %02x %02x %02x %02x\n",
151 (flags & SN9C20X_I2C_READ ? wasread : waswrite), address,
152 row[0], row[1], row[2], row[3], row[4], row[5], row[6], row[7]);
154 ret = usb_microdia_control_write(dev, 0x10c0, row, 8);
155 if(ret >= 0)
156 ret = sn9c20x_i2c_ack_wait(dev, flags & SN9C20X_I2C_400KHZ,
157 &slave_error);
159 if(slave_error) {
160 UDIA_ERROR("I2C slave %x returned error during %s address %x\n",
161 slave,
162 (flags & SN9C20X_I2C_READ ? wasread : waswrite),
163 address);
164 return -1000; // there should be no interference with USB errors
167 if(ret < 0) {
168 /* we got no ack */
169 UDIA_ERROR("No ack from I2C slave %x for %s address %x\n",
170 slave,
171 (flags & SN9C20X_I2C_READ ? wasread : waswrite),
172 address);
173 return ret;
176 return 0;
180 * @brief Wait until the I2C slave is ready for the next operation
182 * @param dev Pointer to the device
183 * @param highspeed
184 * @param slave_error
186 * @return Zero for success or a negative error value
189 int sn9c20x_i2c_ack_wait(struct usb_microdia *dev, bool highspeed, bool * slave_error)
191 int ret, i;
192 __u8 readbuf;
193 int delay = highspeed ? 100 : 400;
195 for(i = 0; i< 5; i++) {
196 ret = usb_microdia_control_read(dev, 0x10c0, &readbuf, 1);
198 if(ret < 0)
199 return ret;
200 else if(readbuf & SN9C20X_I2C_ERROR) {
201 *slave_error = 1;
202 /* probably should come up w/ an error value and
203 * return it via the error return */
204 return 0;
206 else if(readbuf & SN9C20X_I2C_READY)
207 return 0;
208 else
209 udelay(delay);
212 return -EBUSY;