Merge branch 'hwmon-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jdelv...
[pandora-kernel.git] / drivers / media / video / gspca / stv06xx / stv06xx_hdcs.c
index e5024c8..17531b4 100644 (file)
@@ -37,10 +37,10 @@ static const struct ctrl hdcs1x00_ctrl[] = {
                        .type           = V4L2_CTRL_TYPE_INTEGER,
                        .name           = "exposure",
                        .minimum        = 0x00,
-                       .maximum        = 0xffff,
+                       .maximum        = 0xff,
                        .step           = 0x1,
-                       .default_value  = HDCS_DEFAULT_EXPOSURE,
-                       .flags          = V4L2_CTRL_FLAG_SLIDER
+                       .default_value  = HDCS_DEFAULT_EXPOSURE,
+                       .flags          = V4L2_CTRL_FLAG_SLIDER
                },
                .set = hdcs_set_exposure,
                .get = hdcs_get_exposure
@@ -52,8 +52,8 @@ static const struct ctrl hdcs1x00_ctrl[] = {
                        .minimum        = 0x00,
                        .maximum        = 0xff,
                        .step           = 0x1,
-                       .default_value  = HDCS_DEFAULT_GAIN,
-                       .flags          = V4L2_CTRL_FLAG_SLIDER
+                       .default_value  = HDCS_DEFAULT_GAIN,
+                       .flags          = V4L2_CTRL_FLAG_SLIDER
                },
                .set = hdcs_set_gain,
                .get = hdcs_get_gain
@@ -74,7 +74,35 @@ static struct v4l2_pix_format hdcs1x00_mode[] = {
        }
 };
 
-static const struct ctrl hdcs1020_ctrl[] = {};
+static const struct ctrl hdcs1020_ctrl[] = {
+       {
+               {
+                       .id             = V4L2_CID_EXPOSURE,
+                       .type           = V4L2_CTRL_TYPE_INTEGER,
+                       .name           = "exposure",
+                       .minimum        = 0x00,
+                       .maximum        = 0xffff,
+                       .step           = 0x1,
+                       .default_value  = HDCS_DEFAULT_EXPOSURE,
+                       .flags          = V4L2_CTRL_FLAG_SLIDER
+               },
+               .set = hdcs_set_exposure,
+               .get = hdcs_get_exposure
+       }, {
+               {
+                       .id             = V4L2_CID_GAIN,
+                       .type           = V4L2_CTRL_TYPE_INTEGER,
+                       .name           = "gain",
+                       .minimum        = 0x00,
+                       .maximum        = 0xff,
+                       .step           = 0x1,
+                       .default_value  = HDCS_DEFAULT_GAIN,
+                       .flags          = V4L2_CTRL_FLAG_SLIDER
+               },
+               .set = hdcs_set_gain,
+               .get = hdcs_get_gain
+       }
+};
 
 static struct v4l2_pix_format hdcs1020_mode[] = {
        {
@@ -120,6 +148,7 @@ struct hdcs {
        } exp;
 
        int psmp;
+       u8 exp_cache, gain_cache;
 };
 
 static int hdcs_reg_write_seq(struct sd *sd, u8 reg, u8 *vals, u8 len)
@@ -134,7 +163,8 @@ static int hdcs_reg_write_seq(struct sd *sd, u8 reg, u8 *vals, u8 len)
        for (i = 0; i < len; i++) {
                regs[2 * i] = reg;
                regs[2 * i + 1] = vals[i];
-               /* All addresses are shifted left one bit as bit 0 toggles r/w */
+               /* All addresses are shifted left one bit
+                * as bit 0 toggles r/w */
                reg += 2;
        }
 
@@ -205,34 +235,8 @@ static int hdcs_get_exposure(struct gspca_dev *gspca_dev, __s32 *val)
        struct sd *sd = (struct sd *) gspca_dev;
        struct hdcs *hdcs = sd->sensor_priv;
 
-       /* Column time period */
-       int ct;
-       /* Column processing period */
-       int cp;
-       /* Row processing period */
-       int rp;
-       int cycles;
-       int err;
-       int rowexp;
-       u16 data[2];
-
-       err = stv06xx_read_sensor(sd, HDCS_ROWEXPL, &data[0]);
-       if (err < 0)
-               return err;
+       *val = hdcs->exp_cache;
 
-       err = stv06xx_read_sensor(sd, HDCS_ROWEXPH, &data[1]);
-       if (err < 0)
-               return err;
-
-       rowexp = (data[1] << 8) | data[0];
-
-       ct = hdcs->exp.cto + hdcs->psmp + (HDCS_ADC_START_SIG_DUR + 2);
-       cp = hdcs->exp.cto + (hdcs->w * ct / 2);
-       rp = hdcs->exp.rs + cp;
-
-       cycles = rp * rowexp;
-       *val = cycles / HDCS_CLK_FREQ_MHZ;
-       PDEBUG(D_V4L2, "Read exposure %d", *val);
        return 0;
 }
 
@@ -252,9 +256,12 @@ static int hdcs_set_exposure(struct gspca_dev *gspca_dev, __s32 val)
           within the column processing period */
        int mnct;
        int cycles, err;
-       u8 exp[4];
+       u8 exp[14];
+
+       val &= 0xff;
+       hdcs->exp_cache = val;
 
-       cycles = val * HDCS_CLK_FREQ_MHZ;
+       cycles = val * HDCS_CLK_FREQ_MHZ * 257;
 
        ct = hdcs->exp.cto + hdcs->psmp + (HDCS_ADC_START_SIG_DUR + 2);
        cp = hdcs->exp.cto + (hdcs->w * ct / 2);
@@ -288,73 +295,79 @@ static int hdcs_set_exposure(struct gspca_dev *gspca_dev, __s32 val)
                srowexp = max_srowexp;
 
        if (IS_1020(sd)) {
-               exp[0] = rowexp & 0xff;
-               exp[1] = rowexp >> 8;
-               exp[2] = (srowexp >> 2) & 0xff;
-               /* this clears exposure error flag */
-               exp[3] = 0x1;
-               err = hdcs_reg_write_seq(sd, HDCS_ROWEXPL, exp, 4);
+               exp[0] = HDCS20_CONTROL;
+               exp[1] = 0x00;          /* Stop streaming */
+               exp[2] = HDCS_ROWEXPL;
+               exp[3] = rowexp & 0xff;
+               exp[4] = HDCS_ROWEXPH;
+               exp[5] = rowexp >> 8;
+               exp[6] = HDCS20_SROWEXP;
+               exp[7] = (srowexp >> 2) & 0xff;
+               exp[8] = HDCS20_ERROR;
+               exp[9] = 0x10;          /* Clear exposure error flag*/
+               exp[10] = HDCS20_CONTROL;
+               exp[11] = 0x04;         /* Restart streaming */
+               err = stv06xx_write_sensor_bytes(sd, exp, 6);
        } else {
-               exp[0] = rowexp & 0xff;
-               exp[1] = rowexp >> 8;
-               exp[2] = srowexp & 0xff;
-               exp[3] = srowexp >> 8;
-               err = hdcs_reg_write_seq(sd, HDCS_ROWEXPL, exp, 4);
+               exp[0] = HDCS00_CONTROL;
+               exp[1] = 0x00;         /* Stop streaming */
+               exp[2] = HDCS_ROWEXPL;
+               exp[3] = rowexp & 0xff;
+               exp[4] = HDCS_ROWEXPH;
+               exp[5] = rowexp >> 8;
+               exp[6] = HDCS00_SROWEXPL;
+               exp[7] = srowexp & 0xff;
+               exp[8] = HDCS00_SROWEXPH;
+               exp[9] = srowexp >> 8;
+               exp[10] = HDCS_STATUS;
+               exp[11] = 0x10;         /* Clear exposure error flag*/
+               exp[12] = HDCS00_CONTROL;
+               exp[13] = 0x04;         /* Restart streaming */
+               err = stv06xx_write_sensor_bytes(sd, exp, 7);
                if (err < 0)
                        return err;
-
-               /* clear exposure error flag */
-               err = stv06xx_write_sensor(sd,
-                    HDCS_STATUS, BIT(4));
        }
        PDEBUG(D_V4L2, "Writing exposure %d, rowexp %d, srowexp %d",
               val, rowexp, srowexp);
        return err;
 }
 
-static int hdcs_set_gains(struct sd *sd, u8 r, u8 g, u8 b)
+static int hdcs_set_gains(struct sd *sd, u8 g)
 {
+       struct hdcs *hdcs = sd->sensor_priv;
+       int err;
        u8 gains[4];
 
+       hdcs->gain_cache = g;
+
        /* the voltage gain Av = (1 + 19 * val / 127) * (1 + bit7) */
-       if (r > 127)
-               r = 0x80 | (r / 2);
        if (g > 127)
                g = 0x80 | (g / 2);
-       if (b > 127)
-               b = 0x80 | (b / 2);
 
        gains[0] = g;
-       gains[1] = r;
-       gains[2] = b;
+       gains[1] = g;
+       gains[2] = g;
        gains[3] = g;
 
-       return hdcs_reg_write_seq(sd, HDCS_ERECPGA, gains, 4);
+       err = hdcs_reg_write_seq(sd, HDCS_ERECPGA, gains, 4);
+               return err;
 }
 
 static int hdcs_get_gain(struct gspca_dev *gspca_dev, __s32 *val)
 {
        struct sd *sd = (struct sd *) gspca_dev;
-       int err;
-       u16 data;
+       struct hdcs *hdcs = sd->sensor_priv;
 
-       err = stv06xx_read_sensor(sd, HDCS_ERECPGA, &data);
+       *val = hdcs->gain_cache;
 
-       /* Bit 7 doubles the gain */
-       if (data & 0x80)
-               *val = (data & 0x7f) * 2;
-       else
-               *val = data;
-
-       PDEBUG(D_V4L2, "Read gain %d", *val);
-       return err;
+       return 0;
 }
 
 static int hdcs_set_gain(struct gspca_dev *gspca_dev, __s32 val)
 {
        PDEBUG(D_V4L2, "Writing gain %d", val);
        return hdcs_set_gains((struct sd *) gspca_dev,
-                              val & 0xff, val & 0xff, val & 0xff);
+                              val & 0xff);
 }
 
 static int hdcs_set_size(struct sd *sd,
@@ -572,16 +585,15 @@ static int hdcs_init(struct sd *sd)
        if (err < 0)
                return err;
 
-       err = hdcs_set_gains(sd, HDCS_DEFAULT_GAIN, HDCS_DEFAULT_GAIN,
-                            HDCS_DEFAULT_GAIN);
+       err = hdcs_set_gains(sd, HDCS_DEFAULT_GAIN);
        if (err < 0)
                return err;
 
-       err = hdcs_set_exposure(&sd->gspca_dev, HDCS_DEFAULT_EXPOSURE);
+       err = hdcs_set_size(sd, hdcs->array.width, hdcs->array.height);
        if (err < 0)
                return err;
 
-       err = hdcs_set_size(sd, hdcs->array.width, hdcs->array.height);
+       err = hdcs_set_exposure(&sd->gspca_dev, HDCS_DEFAULT_EXPOSURE);
        return err;
 }