aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJavier Martin <javier.martin@vista-silicon.com>2013-01-29 05:16:59 -0500
committerMauro Carvalho Chehab <mchehab@redhat.com>2013-02-08 11:27:48 -0500
commitf6dd927f34d64014c4b196132b5cdf9f2e2a3ae5 (patch)
tree0bba7563d6acbcc3c53bcd8e3b02e9e4def95524
parentf748cd3ec8039a01d260ba0d51687afdf93c6e67 (diff)
[media] media: ov7670: calculate framerate properly for ov7675
According to the datasheet ov7675 uses a formula to achieve the desired framerate that is different from the operations done in the current code. In fact, this formula should apply to ov7670 too. This would mean that current code is wrong but, in order to preserve compatibility, the new formula will be used for ov7675 only. Signed-off-by: Javier Martin <javier.martin@vista-silicon.com> Cc: Jonathan Corbet <corbet@lwn.net> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
-rw-r--r--drivers/media/i2c/ov7670.c136
1 files changed, 118 insertions, 18 deletions
diff --git a/drivers/media/i2c/ov7670.c b/drivers/media/i2c/ov7670.c
index 88e64739fefd..dea2917a2b12 100644
--- a/drivers/media/i2c/ov7670.c
+++ b/drivers/media/i2c/ov7670.c
@@ -47,6 +47,8 @@ MODULE_PARM_DESC(debug, "Debug level (0-1)");
47 */ 47 */
48#define OV7670_I2C_ADDR 0x42 48#define OV7670_I2C_ADDR 0x42
49 49
50#define PLL_FACTOR 4
51
50/* Registers */ 52/* Registers */
51#define REG_GAIN 0x00 /* Gain lower 8 bits (rest in vref) */ 53#define REG_GAIN 0x00 /* Gain lower 8 bits (rest in vref) */
52#define REG_BLUE 0x01 /* blue gain */ 54#define REG_BLUE 0x01 /* blue gain */
@@ -164,6 +166,12 @@ MODULE_PARM_DESC(debug, "Debug level (0-1)");
164 166
165#define REG_GFIX 0x69 /* Fix gain control */ 167#define REG_GFIX 0x69 /* Fix gain control */
166 168
169#define REG_DBLV 0x6b /* PLL control an debugging */
170#define DBLV_BYPASS 0x00 /* Bypass PLL */
171#define DBLV_X4 0x01 /* clock x4 */
172#define DBLV_X6 0x10 /* clock x6 */
173#define DBLV_X8 0x11 /* clock x8 */
174
167#define REG_REG76 0x76 /* OV's name */ 175#define REG_REG76 0x76 /* OV's name */
168#define R76_BLKPCOR 0x80 /* Black pixel correction enable */ 176#define R76_BLKPCOR 0x80 /* Black pixel correction enable */
169#define R76_WHTPCOR 0x40 /* White pixel correction enable */ 177#define R76_WHTPCOR 0x40 /* White pixel correction enable */
@@ -203,6 +211,9 @@ struct ov7670_devtype {
203 /* formats supported for each model */ 211 /* formats supported for each model */
204 struct ov7670_win_size *win_sizes; 212 struct ov7670_win_size *win_sizes;
205 unsigned int n_win_sizes; 213 unsigned int n_win_sizes;
214 /* callbacks for frame rate control */
215 int (*set_framerate)(struct v4l2_subdev *, struct v4l2_fract *);
216 void (*get_framerate)(struct v4l2_subdev *, struct v4l2_fract *);
206}; 217};
207 218
208/* 219/*
@@ -739,6 +750,98 @@ static struct ov7670_win_size ov7675_win_sizes[] = {
739 } 750 }
740}; 751};
741 752
753static void ov7675_get_framerate(struct v4l2_subdev *sd,
754 struct v4l2_fract *tpf)
755{
756 struct ov7670_info *info = to_state(sd);
757 u32 clkrc = info->clkrc;
758 u32 pll_factor = PLL_FACTOR;
759
760 clkrc++;
761 if (info->fmt->mbus_code == V4L2_MBUS_FMT_SBGGR8_1X8)
762 clkrc = (clkrc >> 1);
763
764 tpf->numerator = 1;
765 tpf->denominator = (5 * pll_factor * info->clock_speed) /
766 (4 * clkrc);
767}
768
769static int ov7675_set_framerate(struct v4l2_subdev *sd,
770 struct v4l2_fract *tpf)
771{
772 struct ov7670_info *info = to_state(sd);
773 u32 clkrc;
774 u32 pll_factor = PLL_FACTOR;
775 int ret;
776
777 /*
778 * The formula is fps = 5/4*pixclk for YUV/RGB and
779 * fps = 5/2*pixclk for RAW.
780 *
781 * pixclk = clock_speed / (clkrc + 1) * PLLfactor
782 *
783 */
784 if (tpf->numerator == 0 || tpf->denominator == 0) {
785 clkrc = 0;
786 } else {
787 clkrc = (5 * pll_factor * info->clock_speed * tpf->numerator) /
788 (4 * tpf->denominator);
789 if (info->fmt->mbus_code == V4L2_MBUS_FMT_SBGGR8_1X8)
790 clkrc = (clkrc << 1);
791 clkrc--;
792 }
793
794 /*
795 * The datasheet claims that clkrc = 0 will divide the input clock by 1
796 * but we've checked with an oscilloscope that it divides by 2 instead.
797 * So, if clkrc = 0 just bypass the divider.
798 */
799 if (clkrc <= 0)
800 clkrc = CLK_EXT;
801 else if (clkrc > CLK_SCALE)
802 clkrc = CLK_SCALE;
803 info->clkrc = clkrc;
804
805 /* Recalculate frame rate */
806 ov7675_get_framerate(sd, tpf);
807
808 ret = ov7670_write(sd, REG_CLKRC, info->clkrc);
809 if (ret < 0)
810 return ret;
811 return ov7670_write(sd, REG_DBLV, DBLV_X4);
812}
813
814static void ov7670_get_framerate_legacy(struct v4l2_subdev *sd,
815 struct v4l2_fract *tpf)
816{
817 struct ov7670_info *info = to_state(sd);
818
819 tpf->numerator = 1;
820 tpf->denominator = info->clock_speed;
821 if ((info->clkrc & CLK_EXT) == 0 && (info->clkrc & CLK_SCALE) > 1)
822 tpf->denominator /= (info->clkrc & CLK_SCALE);
823}
824
825static int ov7670_set_framerate_legacy(struct v4l2_subdev *sd,
826 struct v4l2_fract *tpf)
827{
828 struct ov7670_info *info = to_state(sd);
829 int div;
830
831 if (tpf->numerator == 0 || tpf->denominator == 0)
832 div = 1; /* Reset to full rate */
833 else
834 div = (tpf->numerator * info->clock_speed) / tpf->denominator;
835 if (div == 0)
836 div = 1;
837 else if (div > CLK_SCALE)
838 div = CLK_SCALE;
839 info->clkrc = (info->clkrc & 0x80) | div;
840 tpf->numerator = 1;
841 tpf->denominator = info->clock_speed / div;
842 return ov7670_write(sd, REG_CLKRC, info->clkrc);
843}
844
742/* 845/*
743 * Store a set of start/stop values into the camera. 846 * Store a set of start/stop values into the camera.
744 */ 847 */
@@ -913,10 +1016,8 @@ static int ov7670_g_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *parms)
913 1016
914 memset(cp, 0, sizeof(struct v4l2_captureparm)); 1017 memset(cp, 0, sizeof(struct v4l2_captureparm));
915 cp->capability = V4L2_CAP_TIMEPERFRAME; 1018 cp->capability = V4L2_CAP_TIMEPERFRAME;
916 cp->timeperframe.numerator = 1; 1019 info->devtype->get_framerate(sd, &cp->timeperframe);
917 cp->timeperframe.denominator = info->clock_speed; 1020
918 if ((info->clkrc & CLK_EXT) == 0 && (info->clkrc & CLK_SCALE) > 1)
919 cp->timeperframe.denominator /= (info->clkrc & CLK_SCALE);
920 return 0; 1021 return 0;
921} 1022}
922 1023
@@ -925,25 +1026,13 @@ static int ov7670_s_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *parms)
925 struct v4l2_captureparm *cp = &parms->parm.capture; 1026 struct v4l2_captureparm *cp = &parms->parm.capture;
926 struct v4l2_fract *tpf = &cp->timeperframe; 1027 struct v4l2_fract *tpf = &cp->timeperframe;
927 struct ov7670_info *info = to_state(sd); 1028 struct ov7670_info *info = to_state(sd);
928 int div;
929 1029
930 if (parms->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) 1030 if (parms->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
931 return -EINVAL; 1031 return -EINVAL;
932 if (cp->extendedmode != 0) 1032 if (cp->extendedmode != 0)
933 return -EINVAL; 1033 return -EINVAL;
934 1034
935 if (tpf->numerator == 0 || tpf->denominator == 0) 1035 return info->devtype->set_framerate(sd, tpf);
936 div = 1; /* Reset to full rate */
937 else
938 div = (tpf->numerator * info->clock_speed) / tpf->denominator;
939 if (div == 0)
940 div = 1;
941 else if (div > CLK_SCALE)
942 div = CLK_SCALE;
943 info->clkrc = (info->clkrc & 0x80) | div;
944 tpf->numerator = 1;
945 tpf->denominator = info->clock_speed / div;
946 return ov7670_write(sd, REG_CLKRC, info->clkrc);
947} 1036}
948 1037
949 1038
@@ -1560,16 +1649,21 @@ static const struct ov7670_devtype ov7670_devdata[] = {
1560 [MODEL_OV7670] = { 1649 [MODEL_OV7670] = {
1561 .win_sizes = ov7670_win_sizes, 1650 .win_sizes = ov7670_win_sizes,
1562 .n_win_sizes = ARRAY_SIZE(ov7670_win_sizes), 1651 .n_win_sizes = ARRAY_SIZE(ov7670_win_sizes),
1652 .set_framerate = ov7670_set_framerate_legacy,
1653 .get_framerate = ov7670_get_framerate_legacy,
1563 }, 1654 },
1564 [MODEL_OV7675] = { 1655 [MODEL_OV7675] = {
1565 .win_sizes = ov7675_win_sizes, 1656 .win_sizes = ov7675_win_sizes,
1566 .n_win_sizes = ARRAY_SIZE(ov7675_win_sizes), 1657 .n_win_sizes = ARRAY_SIZE(ov7675_win_sizes),
1658 .set_framerate = ov7675_set_framerate,
1659 .get_framerate = ov7675_get_framerate,
1567 }, 1660 },
1568}; 1661};
1569 1662
1570static int ov7670_probe(struct i2c_client *client, 1663static int ov7670_probe(struct i2c_client *client,
1571 const struct i2c_device_id *id) 1664 const struct i2c_device_id *id)
1572{ 1665{
1666 struct v4l2_fract tpf;
1573 struct v4l2_subdev *sd; 1667 struct v4l2_subdev *sd;
1574 struct ov7670_info *info; 1668 struct ov7670_info *info;
1575 int ret; 1669 int ret;
@@ -1611,7 +1705,13 @@ static int ov7670_probe(struct i2c_client *client,
1611 info->devtype = &ov7670_devdata[id->driver_data]; 1705 info->devtype = &ov7670_devdata[id->driver_data];
1612 info->fmt = &ov7670_formats[0]; 1706 info->fmt = &ov7670_formats[0];
1613 info->sat = 128; /* Review this */ 1707 info->sat = 128; /* Review this */
1614 info->clkrc = info->clock_speed / 30; 1708 info->clkrc = 0;
1709
1710 /* Set default frame rate to 30 fps */
1711 tpf.numerator = 1;
1712 tpf.denominator = 30;
1713 info->devtype->set_framerate(sd, &tpf);
1714
1615 return 0; 1715 return 0;
1616} 1716}
1617 1717