aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/usb/em28xx
diff options
context:
space:
mode:
authorFrank Schaefer <fschaefer.oss@googlemail.com>2013-03-27 16:06:34 -0400
committerMauro Carvalho Chehab <mchehab@redhat.com>2013-03-29 05:40:10 -0400
commitbde03684323d12b5da0834475bf9964f064a403b (patch)
tree17956683772b40dd12a67b8a083598259b1dba14 /drivers/media/usb/em28xx
parent0af0b25a64458c3ee002efe6e7542013b94a268a (diff)
[media] em28xx: add probing procedure for OmniVision sensors
OmniVision sensors are used as well in Empiatech based cameras such as the "SpeedLink Vicious And Devine Laplace" webcam (EM2765 + Omnivision OV2640). With this patch applied, OminiVision sensors with 8 bit address and register width are detected (recent models have a 16 bit address width and use different client addresses). The most commonly used sensors (including the ones listed by Empiatech) are detected properly, although there is no support for them yet. Signed-off-by: Frank Schäfer <fschaefer.oss@googlemail.com> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Diffstat (limited to 'drivers/media/usb/em28xx')
-rw-r--r--drivers/media/usb/em28xx/em28xx-camera.c114
1 files changed, 113 insertions, 1 deletions
diff --git a/drivers/media/usb/em28xx/em28xx-camera.c b/drivers/media/usb/em28xx/em28xx-camera.c
index d744af6f7d08..e8b3322242c0 100644
--- a/drivers/media/usb/em28xx/em28xx-camera.c
+++ b/drivers/media/usb/em28xx/em28xx-camera.c
@@ -34,6 +34,13 @@ static unsigned short micron_sensor_addrs[] = {
34 I2C_CLIENT_END 34 I2C_CLIENT_END
35}; 35};
36 36
37/* Possible i2c addresses of Omnivision sensors */
38static unsigned short omnivision_sensor_addrs[] = {
39 0x42 >> 1, /* OV7725, OV7670/60/48 */
40 0x60 >> 1, /* OV2640, OV9650/53/55 */
41 I2C_CLIENT_END
42};
43
37 44
38/* FIXME: Should be replaced by a proper mt9m111 driver */ 45/* FIXME: Should be replaced by a proper mt9m111 driver */
39static int em28xx_initialize_mt9m111(struct em28xx *dev) 46static int em28xx_initialize_mt9m111(struct em28xx *dev)
@@ -182,13 +189,118 @@ static int em28xx_probe_sensor_micron(struct em28xx *dev)
182} 189}
183 190
184/* 191/*
185 * This method works for webcams with Micron sensors 192 * Probes Omnivision sensors with 8 bit address and register width
186 */ 193 */
194static int em28xx_probe_sensor_omnivision(struct em28xx *dev)
195{
196 int ret, i;
197 char *name;
198 u8 reg;
199 u16 id;
200 struct i2c_client client = dev->i2c_client[dev->def_i2c_bus];
201
202 dev->em28xx_sensor = EM28XX_NOSENSOR;
203 /* NOTE: these devices have the register auto incrementation disabled
204 * by default, so we have to use single byte reads ! */
205 for (i = 0; omnivision_sensor_addrs[i] != I2C_CLIENT_END; i++) {
206 client.addr = omnivision_sensor_addrs[i];
207 /* Read manufacturer ID from registers 0x1c-0x1d (BE) */
208 reg = 0x1c;
209 ret = i2c_smbus_read_byte_data(&client, reg);
210 if (ret < 0) {
211 if (ret != -ENODEV)
212 em28xx_errdev("couldn't read from i2c device 0x%02x: error %i\n",
213 client.addr << 1, ret);
214 continue;
215 }
216 id = ret << 8;
217 reg = 0x1d;
218 ret = i2c_smbus_read_byte_data(&client, reg);
219 if (ret < 0) {
220 em28xx_errdev("couldn't read from i2c device 0x%02x: error %i\n",
221 client.addr << 1, ret);
222 continue;
223 }
224 id += ret;
225 /* Check manufacturer ID */
226 if (id != 0x7fa2)
227 continue;
228 /* Read product ID from registers 0x0a-0x0b (BE) */
229 reg = 0x0a;
230 ret = i2c_smbus_read_byte_data(&client, reg);
231 if (ret < 0) {
232 em28xx_errdev("couldn't read from i2c device 0x%02x: error %i\n",
233 client.addr << 1, ret);
234 continue;
235 }
236 id = ret << 8;
237 reg = 0x0b;
238 ret = i2c_smbus_read_byte_data(&client, reg);
239 if (ret < 0) {
240 em28xx_errdev("couldn't read from i2c device 0x%02x: error %i\n",
241 client.addr << 1, ret);
242 continue;
243 }
244 id += ret;
245 /* Check product ID */
246 switch (id) {
247 case 0x2642:
248 name = "OV2640";
249 break;
250 case 0x7648:
251 name = "OV7648";
252 break;
253 case 0x7660:
254 name = "OV7660";
255 break;
256 case 0x7673:
257 name = "OV7670";
258 break;
259 case 0x7720:
260 name = "OV7720";
261 break;
262 case 0x7721:
263 name = "OV7725";
264 break;
265 case 0x9648: /* Rev 2 */
266 case 0x9649: /* Rev 3 */
267 name = "OV9640";
268 break;
269 case 0x9650:
270 case 0x9652: /* OV9653 */
271 name = "OV9650";
272 break;
273 case 0x9656: /* Rev 4 */
274 case 0x9657: /* Rev 5 */
275 name = "OV9655";
276 break;
277 default:
278 em28xx_info("unknown OmniVision sensor detected: 0x%04x\n",
279 id);
280 return 0;
281 }
282
283 if (dev->em28xx_sensor == EM28XX_NOSENSOR)
284 em28xx_info("unsupported sensor detected: %s\n", name);
285 else
286 em28xx_info("sensor %s detected\n", name);
287
288 dev->i2c_client[dev->def_i2c_bus].addr = client.addr;
289 return 0;
290 }
291
292 return -ENODEV;
293}
294
187int em28xx_detect_sensor(struct em28xx *dev) 295int em28xx_detect_sensor(struct em28xx *dev)
188{ 296{
189 int ret; 297 int ret;
190 298
191 ret = em28xx_probe_sensor_micron(dev); 299 ret = em28xx_probe_sensor_micron(dev);
300
301 if (dev->em28xx_sensor == EM28XX_NOSENSOR && ret < 0)
302 ret = em28xx_probe_sensor_omnivision(dev);
303
192 if (dev->em28xx_sensor == EM28XX_NOSENSOR && ret < 0) { 304 if (dev->em28xx_sensor == EM28XX_NOSENSOR && ret < 0) {
193 em28xx_info("No sensor detected\n"); 305 em28xx_info("No sensor detected\n");
194 return -ENODEV; 306 return -ENODEV;