diff options
author | Frank Schaefer <fschaefer.oss@googlemail.com> | 2013-03-27 17:06:32 -0300 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@redhat.com> | 2013-03-29 06:38:08 -0300 |
commit | 176013b19e848204895bfcaea8b9b39fba5b26dd (patch) | |
tree | 4b993a31f4f0378e9420c86562c6050bb9bdb8ae /drivers/media/usb | |
parent | 855ff38e880f57814ea5c0cbea853da11fcdf42f (diff) |
[media] em28xx: detect further Micron sensors
Add further Micron chip IDs to be able to identify all Micron sensors listed
by Empiatech.
Also probe the two alternate i2c addresses used by Micron sensors with 8 bit
address and 16 bit register width.
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')
-rw-r--r-- | drivers/media/usb/em28xx/em28xx-camera.c | 126 |
1 files changed, 95 insertions, 31 deletions
diff --git a/drivers/media/usb/em28xx/em28xx-camera.c b/drivers/media/usb/em28xx/em28xx-camera.c index 28dd8489ac9c..2e4856aebae8 100644 --- a/drivers/media/usb/em28xx/em28xx-camera.c +++ b/drivers/media/usb/em28xx/em28xx-camera.c @@ -26,6 +26,15 @@ #include "em28xx.h" +/* Possible i2c addresses of Micron sensors */ +static unsigned short micron_sensor_addrs[] = { + 0xb8 >> 1, /* MT9V111, MT9V403 */ + 0xba >> 1, /* MT9M001/011/111/112, MT9V011/012/112, MT9D011 */ + 0x90 >> 1, /* MT9V012/112, MT9D011 (alternative address) */ + I2C_CLIENT_END +}; + + /* FIXME: Should be replaced by a proper mt9m111 driver */ static int em28xx_initialize_mt9m111(struct em28xx *dev) { @@ -78,44 +87,99 @@ static int em28xx_initialize_mt9m001(struct em28xx *dev) */ int em28xx_detect_sensor(struct em28xx *dev) { - int ret; + int ret, i; char *name; u8 reg; __be16 id_be; u16 id; - /* Micron sensor detection */ - dev->i2c_client[dev->def_i2c_bus].addr = 0xba >> 1; - reg = 0; - i2c_master_send(&dev->i2c_client[dev->def_i2c_bus], ®, 1); - ret = i2c_master_recv(&dev->i2c_client[dev->def_i2c_bus], - (char *)&id_be, 2); - if (ret != 2) - return -EINVAL; - - id = be16_to_cpu(id_be); - switch (id) { - case 0x8232: /* mt9v011 640x480 1.3 Mpix sensor */ - case 0x8243: /* mt9v011 rev B 640x480 1.3 Mpix sensor */ - name = "mt9v011"; - dev->em28xx_sensor = EM28XX_MT9V011; - break; - case 0x143a: /* MT9M111 as found in the ECS G200 */ - name = "mt9m111"; - dev->em28xx_sensor = EM28XX_MT9M111; - break; - case 0x8431: - name = "mt9m001"; - dev->em28xx_sensor = EM28XX_MT9M001; - break; - default: - em28xx_info("unknown Micron sensor detected: 0x%04x\n", id); - return -EINVAL; + struct i2c_client client = dev->i2c_client[dev->def_i2c_bus]; + + dev->em28xx_sensor = EM28XX_NOSENSOR; + /* Probe Micron sensors with 8 bit address and 16 bit register width */ + for (i = 0; micron_sensor_addrs[i] != I2C_CLIENT_END; i++) { + client.addr = micron_sensor_addrs[i]; + /* NOTE: i2c_smbus_read_word_data() doesn't work with BE data */ + /* Read chip ID from register 0x00 */ + reg = 0x00; + ret = i2c_master_send(&client, ®, 1); + if (ret < 0) { + if (ret != -ENODEV) + em28xx_errdev("couldn't read from i2c device 0x%02x: error %i\n", + client.addr << 1, ret); + continue; + } + ret = i2c_master_recv(&client, (u8 *)&id_be, 2); + if (ret < 0) { + em28xx_errdev("couldn't read from i2c device 0x%02x: error %i\n", + client.addr << 1, ret); + continue; + } + id = be16_to_cpu(id_be); + /* Read chip ID from register 0xff */ + reg = 0xff; + ret = i2c_master_send(&client, ®, 1); + if (ret < 0) { + em28xx_errdev("couldn't read from i2c device 0x%02x: error %i\n", + client.addr << 1, ret); + continue; + } + ret = i2c_master_recv(&client, (u8 *)&id_be, 2); + if (ret < 0) { + em28xx_errdev("couldn't read from i2c device 0x%02x: error %i\n", + client.addr << 1, ret); + continue; + } + /* Validate chip ID to be sure we have a Micron device */ + if (id != be16_to_cpu(id_be)) + continue; + /* Check chip ID */ + id = be16_to_cpu(id_be); + switch (id) { + case 0x1222: + name = "MT9V012"; /* MI370 */ /* 640x480 */ + break; + case 0x1229: + name = "MT9V112"; /* 640x480 */ + break; + case 0x1433: + name = "MT9M011"; /* 1280x1024 */ + break; + case 0x143a: /* found in the ECS G200 */ + name = "MT9M111"; /* MI1310 */ /* 1280x1024 */ + dev->em28xx_sensor = EM28XX_MT9M111; + break; + case 0x148c: + name = "MT9M112"; /* MI1320 */ /* 1280x1024 */ + break; + case 0x1511: + name = "MT9D011"; /* MI2010 */ /* 1600x1200 */ + break; + case 0x8232: + case 0x8243: /* rev B */ + name = "MT9V011"; /* MI360 */ /* 640x480 */ + dev->em28xx_sensor = EM28XX_MT9V011; + break; + case 0x8431: + name = "MT9M001"; /* 1280x1024 */ + dev->em28xx_sensor = EM28XX_MT9M001; + break; + default: + em28xx_info("unknown Micron sensor detected: 0x%04x\n", + id); + return -EINVAL; + } + + if (dev->em28xx_sensor == EM28XX_NOSENSOR) + em28xx_info("unsupported sensor detected: %s\n", name); + else + em28xx_info("sensor %s detected\n", name); + + dev->i2c_client[dev->def_i2c_bus].addr = client.addr; + return 0; } - em28xx_info("sensor %s detected\n", name); - - return 0; + return -ENODEV; } int em28xx_init_camera(struct em28xx *dev) |