diff options
-rw-r--r-- | drivers/media/video/gspca/spca508.c | 59 |
1 files changed, 55 insertions, 4 deletions
diff --git a/drivers/media/video/gspca/spca508.c b/drivers/media/video/gspca/spca508.c index 2ed2669bac3..9696c4caf5c 100644 --- a/drivers/media/video/gspca/spca508.c +++ b/drivers/media/video/gspca/spca508.c @@ -1304,19 +1304,70 @@ static int reg_read(struct gspca_dev *gspca_dev, return gspca_dev->usb_buf[0]; } +/* send 1 or 2 bytes to the sensor via the Synchronous Serial Interface */ +static int ssi_w(struct gspca_dev *gspca_dev, + u16 reg, u16 val) +{ + struct usb_device *dev = gspca_dev->dev; + int ret, retry; + + ret = reg_write(dev, 0x8802, reg >> 8); + if (ret < 0) + goto out; + ret = reg_write(dev, 0x8801, reg & 0x00ff); + if (ret < 0) + goto out; + if ((reg & 0xff00) == 0x1000) { /* if 2 bytes */ + ret = reg_write(dev, 0x8805, val & 0x00ff); + if (ret < 0) + goto out; + val >>= 8; + } + ret = reg_write(dev, 0x8800, val); + if (ret < 0) + goto out; + + /* poll until not busy */ + retry = 10; + for (;;) { + ret = reg_read(gspca_dev, 0x8803); + if (ret < 0) + break; + if (gspca_dev->usb_buf[0] == 0) + break; + if (--retry <= 0) { + PDEBUG(D_ERR, "ssi_w busy %02x", + gspca_dev->usb_buf[0]); + ret = -1; + break; + } + msleep(8); + } + +out: + return ret; +} + static int write_vector(struct gspca_dev *gspca_dev, const u16 (*data)[2]) { struct usb_device *dev = gspca_dev->dev; - int ret; + int ret = 0; while ((*data)[1] != 0) { - ret = reg_write(dev, (*data)[1], (*data)[0]); + if ((*data)[1] & 0x8000) { + if ((*data)[1] == 0xdd00) /* delay */ + msleep((*data)[0]); + else + ret = reg_write(dev, (*data)[1], (*data)[0]); + } else { + ret = ssi_w(gspca_dev, (*data)[1], (*data)[0]); + } if (ret < 0) - return ret; + break; data++; } - return 0; + return ret; } /* this function is called at probe time */ |