summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFrank Schaefer <fschaefer.oss@googlemail.com>2013-03-03 22:37:41 +0400
committerMauro Carvalho Chehab <mchehab@redhat.com>2013-03-04 23:21:34 +0400
commitd832c5b28aff3c9aadfbde3002b640058eee6294 (patch)
tree4bc34cf5f153cf34be27c26002263662a3ee3fce
parent87b52439cff4a8b745f419b9e99fa68a5533c342 (diff)
downloadlinux-d832c5b28aff3c9aadfbde3002b640058eee6294.tar.xz
[media] em28xx: add helper function for reading data blocks from i2c clients
Add a helper function for reading data blocks from i2c devices with 8 or 16 bit address width and 8 bit register width. This allows us to reduce the size of new code added by the following patches. Works only for devices with activated register auto incrementation. Signed-off-by: Frank Schäfer <fschaefer.oss@googlemail.com> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
-rw-r--r--drivers/media/usb/em28xx/em28xx-i2c.c74
1 files changed, 46 insertions, 28 deletions
diff --git a/drivers/media/usb/em28xx/em28xx-i2c.c b/drivers/media/usb/em28xx/em28xx-i2c.c
index 3f0012c9cf25..438cfbcb9bf5 100644
--- a/drivers/media/usb/em28xx/em28xx-i2c.c
+++ b/drivers/media/usb/em28xx/em28xx-i2c.c
@@ -370,51 +370,69 @@ static inline unsigned long em28xx_hash_mem(char *buf, int length, int bits)
return (hash >> (32 - bits)) & 0xffffffffUL;
}
+/* Helper function to read data blocks from i2c clients with 8 or 16 bit
+ * address width, 8 bit register width and auto incrementation been activated */
+static int em28xx_i2c_read_block(struct em28xx *dev, u16 addr, bool addr_w16,
+ u16 len, u8 *data)
+{
+ int remain = len, rsize, rsize_max, ret;
+ u8 buf[2];
+
+ /* Sanity check */
+ if (addr + remain > (addr_w16 * 0xff00 + 0xff + 1))
+ return -EINVAL;
+ /* Select address */
+ buf[0] = addr >> 8;
+ buf[1] = addr & 0xff;
+ ret = i2c_master_send(&dev->i2c_client, buf + !addr_w16, 1 + addr_w16);
+ if (ret < 0)
+ return ret;
+ /* Read data */
+ if (dev->board.is_em2800)
+ rsize_max = 4;
+ else
+ rsize_max = 64;
+ while (remain > 0) {
+ if (remain > rsize_max)
+ rsize = rsize_max;
+ else
+ rsize = remain;
+
+ ret = i2c_master_recv(&dev->i2c_client, data, rsize);
+ if (ret < 0)
+ return ret;
+
+ remain -= rsize;
+ data += rsize;
+ }
+
+ return len;
+}
+
static int em28xx_i2c_eeprom(struct em28xx *dev, unsigned char *eedata, int len)
{
- unsigned char buf[2], *p = eedata;
+ unsigned char buf, *p = eedata;
struct em28xx_eeprom *em_eeprom = (void *)eedata;
- int i, err, size = len, block, block_max;
+ int i, err;
dev->i2c_client.addr = 0xa0 >> 1;
/* Check if board has eeprom */
- err = i2c_master_recv(&dev->i2c_client, buf, 0);
+ err = i2c_master_recv(&dev->i2c_client, &buf, 0);
if (err < 0) {
em28xx_info("board has no eeprom\n");
memset(eedata, 0, len);
return -ENODEV;
}
- /* Select address memory address 0x00(00) */
- buf[0] = 0;
- buf[1] = 0;
- err = i2c_master_send(&dev->i2c_client, buf, 1 + dev->eeprom_addrwidth_16bit);
- if (err != 1 + dev->eeprom_addrwidth_16bit) {
+ /* Read EEPROM content */
+ err = em28xx_i2c_read_block(dev, 0x0000, dev->eeprom_addrwidth_16bit,
+ len, p);
+ if (err != len) {
em28xx_errdev("failed to read eeprom (err=%d)\n", err);
return err;
}
- /* Read eeprom content */
- if (dev->board.is_em2800)
- block_max = 4;
- else
- block_max = 64;
- while (size > 0) {
- if (size > block_max)
- block = block_max;
- else
- block = size;
-
- if (block !=
- (err = i2c_master_recv(&dev->i2c_client, p, block))) {
- em28xx_errdev("i2c eeprom read error (err=%d)\n", err);
- return err;
- }
- size -= block;
- p += block;
- }
-
/* Display eeprom content */
for (i = 0; i < len; i++) {
if (0 == (i % 16)) {