Lines Matching +full:hb +full:- +full:pll +full:- +full:clock
1 // SPDX-License-Identifier: GPL-2.0-only
9 * Copyright 2006-7 Jonathan Corbet <corbet@lwn.net>
20 #include <media/v4l2-device.h>
21 #include <media/v4l2-event.h>
22 #include <media/v4l2-ctrls.h>
23 #include <media/v4l2-fwnode.h>
24 #include <media/v4l2-mediabus.h>
25 #include <media/v4l2-image-sizes.h>
29 MODULE_DESCRIPTION("A low-level driver for OmniVision ov7670 sensors");
34 MODULE_PARM_DESC(debug, "Debug level (0-1)");
67 #define CLK_EXT 0x40 /* Use external clock directly */
68 #define CLK_SCALE 0x3f /* Mask for internal clock scale */
76 #define COM7_RGB 0x04 /* bits 0 and 2 - RGB format */
87 #define REG_COM9 0x14 /* Control 9 - gain ceiling */
92 #define COM10_VS_LEAD 0x04 /* VSYNC on clock leading edge */
113 #define TSLB_YLAST 0x04 /* UYVY or VYUY - see com13 */
125 #define COM13_UVSWAP 0x01 /* V before U - w/TSLB */
127 #define COM14_DCWEN 0x10 /* DCW/PCLK-scale enable */
138 #define COM17_AECWIN 0xc0 /* AEC window - must match COM4 */
145 * Order: v-red, v-green, v-blue, u-red, u-green, u-blue
147 * They are nine-bit signed quantities, with the sign bit
148 * stored in 0x58. Sign for v-red is bit 0, and up from there.
160 #define REG_DBLV 0x6b /* PLL control an debugging */
161 #define DBLV_BYPASS 0x0a /* Bypass PLL */
162 #define DBLV_X4 0x4a /* clock x4 */
163 #define DBLV_X6 0x8a /* clock x6 */
164 #define DBLV_X8 0xca /* clock x8 */
250 int clock_speed; /* External clock speed (MHz) */
251 u8 clkrc; /* Clock divider value */
265 return &container_of(ctrl->handler, struct ov7670_info, hdl)->sd; in to_sd()
272 * is really no making sense of most of these - lots of "reserved" values
286 * Clock scale: 3 = 15fps
290 { REG_CLKRC, 0x1 }, /* OV: clock scale (30 fps) */
295 * make sense - hstop is less than hstart. But they work...
384 /* Extra-weird stuff. Some sort of multiplexor register */
471 * Low-level register I/O.
518 msg.addr = client->addr; in ov7670_read_i2c()
522 ret = i2c_transfer(client->adapter, &msg, 1); in ov7670_read_i2c()
531 ret = i2c_transfer(client->adapter, &msg, 1); in ov7670_read_i2c()
548 msg.addr = client->addr; in ov7670_write_i2c()
552 ret = i2c_transfer(client->adapter, &msg, 1); in ov7670_write_i2c()
564 if (info->use_smbus) in ov7670_read()
574 if (info->use_smbus) in ov7670_write()
598 while (vals->reg_num != 0xff || vals->value != 0xff) { in ov7670_write_array()
599 int ret = ov7670_write(sd, vals->reg_num, vals->value); in ov7670_write_array()
636 return -ENODEV; in ov7670_detect()
641 return -ENODEV; in ov7670_detect()
649 return -ENODEV; in ov7670_detect()
654 return -ENODEV; in ov7670_detect()
674 .cmatrix = { 128, -128, 0, -34, -94, 128 },
680 .cmatrix = { 179, -179, 0, -61, -176, 228 },
686 .cmatrix = { 179, -179, 0, -61, -176, 228 },
703 * QCIF mode is done (by OV) in a very strange way - it actually looks like
704 * VGA with weird scaling options - they do *not* use the canned QCIF mode
796 u32 clkrc = info->clkrc; in ov7675_get_framerate()
799 if (info->pll_bypass) in ov7675_get_framerate()
805 if (info->fmt->mbus_code == MEDIA_BUS_FMT_SBGGR8_1X8) in ov7675_get_framerate()
808 tpf->numerator = 1; in ov7675_get_framerate()
809 tpf->denominator = (5 * pll_factor * info->clock_speed) / in ov7675_get_framerate()
818 ret = ov7670_write(sd, REG_CLKRC, info->clkrc); in ov7675_apply_framerate()
823 info->pll_bypass ? DBLV_BYPASS : DBLV_X4); in ov7675_apply_framerate()
840 if (tpf->numerator == 0 || tpf->denominator == 0) { in ov7675_set_framerate()
843 pll_factor = info->pll_bypass ? 1 : PLL_FACTOR; in ov7675_set_framerate()
844 clkrc = (5 * pll_factor * info->clock_speed * tpf->numerator) / in ov7675_set_framerate()
845 (4 * tpf->denominator); in ov7675_set_framerate()
846 if (info->fmt->mbus_code == MEDIA_BUS_FMT_SBGGR8_1X8) in ov7675_set_framerate()
848 clkrc--; in ov7675_set_framerate()
852 * The datasheet claims that clkrc = 0 will divide the input clock by 1 in ov7675_set_framerate()
860 info->clkrc = clkrc; in ov7675_set_framerate()
868 * the framerate will be restored right after power-up. in ov7675_set_framerate()
870 if (info->on) in ov7675_set_framerate()
881 tpf->numerator = 1; in ov7670_get_framerate_legacy()
882 tpf->denominator = info->clock_speed; in ov7670_get_framerate_legacy()
883 if ((info->clkrc & CLK_EXT) == 0 && (info->clkrc & CLK_SCALE) > 1) in ov7670_get_framerate_legacy()
884 tpf->denominator /= (info->clkrc & CLK_SCALE); in ov7670_get_framerate_legacy()
893 if (tpf->numerator == 0 || tpf->denominator == 0) in ov7670_set_framerate_legacy()
896 div = (tpf->numerator * info->clock_speed) / tpf->denominator; in ov7670_set_framerate_legacy()
901 info->clkrc = (info->clkrc & 0x80) | div; in ov7670_set_framerate_legacy()
902 tpf->numerator = 1; in ov7670_set_framerate_legacy()
903 tpf->denominator = info->clock_speed / div; in ov7670_set_framerate_legacy()
908 * the framerate will be restored right after power-up. in ov7670_set_framerate_legacy()
910 if (info->on) in ov7670_set_framerate_legacy()
911 return ov7670_write(sd, REG_CLKRC, info->clkrc); in ov7670_set_framerate_legacy()
952 if (code->pad || code->index >= N_OV7670_FMTS) in ov7670_enum_mbus_code()
953 return -EINVAL; in ov7670_enum_mbus_code()
955 code->code = ov7670_formats[code->index].mbus_code; in ov7670_enum_mbus_code()
967 unsigned int n_win_sizes = info->devtype->n_win_sizes; in ov7670_try_fmt_internal()
971 if (ov7670_formats[index].mbus_code == fmt->code) in ov7670_try_fmt_internal()
976 fmt->code = ov7670_formats[0].mbus_code; in ov7670_try_fmt_internal()
983 fmt->field = V4L2_FIELD_NONE; in ov7670_try_fmt_internal()
989 if (info->min_width || info->min_height) in ov7670_try_fmt_internal()
991 wsize = info->devtype->win_sizes + i; in ov7670_try_fmt_internal()
993 if (wsize->width < info->min_width || in ov7670_try_fmt_internal()
994 wsize->height < info->min_height) { in ov7670_try_fmt_internal()
1003 for (wsize = info->devtype->win_sizes; in ov7670_try_fmt_internal()
1004 wsize < info->devtype->win_sizes + win_sizes_limit; wsize++) in ov7670_try_fmt_internal()
1005 if (fmt->width >= wsize->width && fmt->height >= wsize->height) in ov7670_try_fmt_internal()
1007 if (wsize >= info->devtype->win_sizes + win_sizes_limit) in ov7670_try_fmt_internal()
1008 wsize--; /* Take the smallest one */ in ov7670_try_fmt_internal()
1014 fmt->width = wsize->width; in ov7670_try_fmt_internal()
1015 fmt->height = wsize->height; in ov7670_try_fmt_internal()
1016 fmt->colorspace = ov7670_formats[index].colorspace; in ov7670_try_fmt_internal()
1018 info->format = *fmt; in ov7670_try_fmt_internal()
1026 struct ov7670_win_size *wsize = info->wsize; in ov7670_apply_fmt()
1033 * to set it absolutely here, as long as the format-specific in ov7670_apply_fmt()
1036 com7 = info->fmt->regs[0].value; in ov7670_apply_fmt()
1037 com7 |= wsize->com7_bit; in ov7670_apply_fmt()
1045 if (info->mbus_config & V4L2_MBUS_VSYNC_ACTIVE_LOW) in ov7670_apply_fmt()
1047 if (info->mbus_config & V4L2_MBUS_HSYNC_ACTIVE_LOW) in ov7670_apply_fmt()
1049 if (info->pclk_hb_disable) in ov7670_apply_fmt()
1058 ret = ov7670_write_array(sd, info->fmt->regs + 1); in ov7670_apply_fmt()
1062 ret = ov7670_set_hw(sd, wsize->hstart, wsize->hstop, wsize->vstart, in ov7670_apply_fmt()
1063 wsize->vstop); in ov7670_apply_fmt()
1067 if (wsize->regs) { in ov7670_apply_fmt()
1068 ret = ov7670_write_array(sd, wsize->regs); in ov7670_apply_fmt()
1083 ret = ov7670_write(sd, REG_CLKRC, info->clkrc); in ov7670_apply_fmt()
1103 if (format->pad) in ov7670_set_fmt()
1104 return -EINVAL; in ov7670_set_fmt()
1106 if (format->which == V4L2_SUBDEV_FORMAT_TRY) { in ov7670_set_fmt()
1107 ret = ov7670_try_fmt_internal(sd, &format->format, NULL, NULL); in ov7670_set_fmt()
1111 mbus_fmt = v4l2_subdev_get_try_format(sd, cfg, format->pad); in ov7670_set_fmt()
1112 *mbus_fmt = format->format; in ov7670_set_fmt()
1117 ret = ov7670_try_fmt_internal(sd, &format->format, &info->fmt, &info->wsize); in ov7670_set_fmt()
1124 * the frame format will be restored right after power-up. in ov7670_set_fmt()
1126 if (info->on) in ov7670_set_fmt()
1141 if (format->which == V4L2_SUBDEV_FORMAT_TRY) { in ov7670_get_fmt()
1144 format->format = *mbus_fmt; in ov7670_get_fmt()
1147 return -EINVAL; in ov7670_get_fmt()
1150 format->format = info->format; in ov7670_get_fmt()
1166 info->devtype->get_framerate(sd, &ival->interval); in ov7670_g_frame_interval()
1174 struct v4l2_fract *tpf = &ival->interval; in ov7670_s_frame_interval()
1178 return info->devtype->set_framerate(sd, tpf); in ov7670_s_frame_interval()
1183 * Frame intervals. Since frame rates are controlled with the clock
1195 unsigned int n_win_sizes = info->devtype->n_win_sizes; in ov7670_enum_frame_interval()
1198 if (fie->pad) in ov7670_enum_frame_interval()
1199 return -EINVAL; in ov7670_enum_frame_interval()
1200 if (fie->index >= ARRAY_SIZE(ov7670_frame_rates)) in ov7670_enum_frame_interval()
1201 return -EINVAL; in ov7670_enum_frame_interval()
1210 struct ov7670_win_size *win = &info->devtype->win_sizes[i]; in ov7670_enum_frame_interval()
1212 if (info->min_width && win->width < info->min_width) in ov7670_enum_frame_interval()
1214 if (info->min_height && win->height < info->min_height) in ov7670_enum_frame_interval()
1216 if (fie->width == win->width && fie->height == win->height) in ov7670_enum_frame_interval()
1220 return -EINVAL; in ov7670_enum_frame_interval()
1221 fie->interval.numerator = 1; in ov7670_enum_frame_interval()
1222 fie->interval.denominator = ov7670_frame_rates[fie->index]; in ov7670_enum_frame_interval()
1235 int num_valid = -1; in ov7670_enum_frame_size()
1236 __u32 index = fse->index; in ov7670_enum_frame_size()
1237 unsigned int n_win_sizes = info->devtype->n_win_sizes; in ov7670_enum_frame_size()
1239 if (fse->pad) in ov7670_enum_frame_size()
1240 return -EINVAL; in ov7670_enum_frame_size()
1247 struct ov7670_win_size *win = &info->devtype->win_sizes[i]; in ov7670_enum_frame_size()
1248 if (info->min_width && win->width < info->min_width) in ov7670_enum_frame_size()
1250 if (info->min_height && win->height < info->min_height) in ov7670_enum_frame_size()
1253 fse->min_width = fse->max_width = win->width; in ov7670_enum_frame_size()
1254 fse->min_height = fse->max_height = win->height; in ov7670_enum_frame_size()
1259 return -EINVAL; in ov7670_enum_frame_size()
1284 if (matrix[i] < -255) in ov7670_store_cmatrix()
1287 raw = (-1 * matrix[i]) & 0xff; in ov7670_store_cmatrix()
1305 * So here is a simple table of sine values, 0-90 degrees, in steps
1309 * carefully limited to -180 <= theta <= 180.
1325 theta = -theta; in ov7670_sine()
1326 chs = -1; in ov7670_sine()
1331 theta -= 90; in ov7670_sine()
1332 sine = 1000 - ov7670_sin_table[theta/SIN_STEP]; in ov7670_sine()
1339 theta = 90 - theta; in ov7670_cosine()
1341 theta -= 360; in ov7670_cosine()
1342 else if (theta < -180) in ov7670_cosine()
1358 matrix[i] = (info->fmt->cmatrix[i] * sat) >> 7; in ov7670_calc_cmatrix()
1372 matrix[3] = (matrix[3]*costh - matrix[0]*sinth)/1000; in ov7670_calc_cmatrix()
1373 matrix[4] = (matrix[4]*costh - matrix[1]*sinth)/1000; in ov7670_calc_cmatrix()
1374 matrix[5] = (matrix[5]*costh - matrix[2]*sinth)/1000; in ov7670_calc_cmatrix()
1400 return (128 - v) | 0x80; in ov7670_abs_to_sm()
1546 "8-bar color bar",
1568 switch (ctrl->id) { in ov7670_g_volatile_ctrl()
1570 return ov7670_g_gain(sd, &info->gain->val); in ov7670_g_volatile_ctrl()
1572 return -EINVAL; in ov7670_g_volatile_ctrl()
1580 switch (ctrl->id) { in ov7670_s_ctrl()
1582 return ov7670_s_brightness(sd, ctrl->val); in ov7670_s_ctrl()
1584 return ov7670_s_contrast(sd, ctrl->val); in ov7670_s_ctrl()
1587 info->saturation->val, info->hue->val); in ov7670_s_ctrl()
1589 return ov7670_s_vflip(sd, ctrl->val); in ov7670_s_ctrl()
1591 return ov7670_s_hflip(sd, ctrl->val); in ov7670_s_ctrl()
1595 if (!ctrl->val) { in ov7670_s_ctrl()
1597 return ov7670_s_gain(sd, info->gain->val); in ov7670_s_ctrl()
1599 return ov7670_s_autogain(sd, ctrl->val); in ov7670_s_ctrl()
1603 if (ctrl->val == V4L2_EXPOSURE_MANUAL) { in ov7670_s_ctrl()
1605 return ov7670_s_exp(sd, info->exposure->val); in ov7670_s_ctrl()
1607 return ov7670_s_autoexp(sd, ctrl->val); in ov7670_s_ctrl()
1609 return ov7670_s_test_pattern(sd, ctrl->val); in ov7670_s_ctrl()
1611 return -EINVAL; in ov7670_s_ctrl()
1625 ret = ov7670_read(sd, reg->reg & 0xff, &val); in ov7670_g_register()
1626 reg->val = val; in ov7670_g_register()
1627 reg->size = 1; in ov7670_g_register()
1633 ov7670_write(sd, reg->reg & 0xff, reg->val & 0xff); in ov7670_s_register()
1642 if (info->on) in ov7670_power_on()
1645 clk_prepare_enable(info->clk); in ov7670_power_on()
1647 if (info->pwdn_gpio) in ov7670_power_on()
1648 gpiod_set_value(info->pwdn_gpio, 0); in ov7670_power_on()
1649 if (info->resetb_gpio) { in ov7670_power_on()
1650 gpiod_set_value(info->resetb_gpio, 1); in ov7670_power_on()
1652 gpiod_set_value(info->resetb_gpio, 0); in ov7670_power_on()
1654 if (info->pwdn_gpio || info->resetb_gpio || info->clk) in ov7670_power_on()
1657 info->on = true; in ov7670_power_on()
1664 if (!info->on) in ov7670_power_off()
1667 clk_disable_unprepare(info->clk); in ov7670_power_off()
1669 if (info->pwdn_gpio) in ov7670_power_off()
1670 gpiod_set_value(info->pwdn_gpio, 1); in ov7670_power_off()
1672 info->on = false; in ov7670_power_off()
1679 if (info->on == on) in ov7670_s_power()
1687 v4l2_ctrl_handler_setup(&info->hdl); in ov7670_s_power()
1700 format->width = info->devtype->win_sizes[0].width; in ov7670_get_default_format()
1701 format->height = info->devtype->win_sizes[0].height; in ov7670_get_default_format()
1702 format->colorspace = info->fmt->colorspace; in ov7670_get_default_format()
1703 format->code = info->fmt->mbus_code; in ov7670_get_default_format()
1704 format->field = V4L2_FIELD_NONE; in ov7670_get_default_format()
1711 v4l2_subdev_get_try_format(sd, fh->pad, 0); in ov7670_open()
1719 /* ----------------------------------------------------------------------- */
1759 /* ----------------------------------------------------------------------- */
1778 info->pwdn_gpio = devm_gpiod_get_optional(&client->dev, "powerdown", in ov7670_init_gpio()
1780 if (IS_ERR(info->pwdn_gpio)) { in ov7670_init_gpio()
1781 dev_info(&client->dev, "can't get %s GPIO\n", "powerdown"); in ov7670_init_gpio()
1782 return PTR_ERR(info->pwdn_gpio); in ov7670_init_gpio()
1785 info->resetb_gpio = devm_gpiod_get_optional(&client->dev, "reset", in ov7670_init_gpio()
1787 if (IS_ERR(info->resetb_gpio)) { in ov7670_init_gpio()
1788 dev_info(&client->dev, "can't get %s GPIO\n", "reset"); in ov7670_init_gpio()
1789 return PTR_ERR(info->resetb_gpio); in ov7670_init_gpio()
1798 * ov7670_parse_dt() - Parse device tree to collect mbus configuration
1810 return -EINVAL; in ov7670_parse_dt()
1812 info->pclk_hb_disable = false; in ov7670_parse_dt()
1813 if (fwnode_property_present(fwnode, "ov7670,pclk-hb-disable")) in ov7670_parse_dt()
1814 info->pclk_hb_disable = true; in ov7670_parse_dt()
1818 return -EINVAL; in ov7670_parse_dt()
1829 info->mbus_config = bus_cfg.bus.parallel.flags; in ov7670_parse_dt()
1842 info = devm_kzalloc(&client->dev, sizeof(*info), GFP_KERNEL); in ov7670_probe()
1844 return -ENOMEM; in ov7670_probe()
1845 sd = &info->sd; in ov7670_probe()
1849 sd->internal_ops = &ov7670_subdev_internal_ops; in ov7670_probe()
1850 sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE | V4L2_SUBDEV_FL_HAS_EVENTS; in ov7670_probe()
1853 info->clock_speed = 30; /* default: a guess */ in ov7670_probe()
1855 if (dev_fwnode(&client->dev)) { in ov7670_probe()
1856 ret = ov7670_parse_dt(&client->dev, info); in ov7670_probe()
1860 } else if (client->dev.platform_data) { in ov7670_probe()
1861 struct ov7670_config *config = client->dev.platform_data; in ov7670_probe()
1867 info->min_width = config->min_width; in ov7670_probe()
1868 info->min_height = config->min_height; in ov7670_probe()
1869 info->use_smbus = config->use_smbus; in ov7670_probe()
1871 if (config->clock_speed) in ov7670_probe()
1872 info->clock_speed = config->clock_speed; in ov7670_probe()
1874 if (config->pll_bypass) in ov7670_probe()
1875 info->pll_bypass = true; in ov7670_probe()
1877 if (config->pclk_hb_disable) in ov7670_probe()
1878 info->pclk_hb_disable = true; in ov7670_probe()
1881 info->clk = devm_clk_get(&client->dev, "xclk"); /* optional */ in ov7670_probe()
1882 if (IS_ERR(info->clk)) { in ov7670_probe()
1883 ret = PTR_ERR(info->clk); in ov7670_probe()
1884 if (ret == -ENOENT) in ov7670_probe()
1885 info->clk = NULL; in ov7670_probe()
1896 if (info->clk) { in ov7670_probe()
1897 info->clock_speed = clk_get_rate(info->clk) / 1000000; in ov7670_probe()
1898 if (info->clock_speed < 10 || info->clock_speed > 48) { in ov7670_probe()
1899 ret = -EINVAL; in ov7670_probe()
1909 client->addr << 1, client->adapter->name); in ov7670_probe()
1913 client->addr << 1, client->adapter->name); in ov7670_probe()
1915 info->devtype = &ov7670_devdata[id->driver_data]; in ov7670_probe()
1916 info->fmt = &ov7670_formats[0]; in ov7670_probe()
1917 info->wsize = &info->devtype->win_sizes[0]; in ov7670_probe()
1919 ov7670_get_default_format(sd, &info->format); in ov7670_probe()
1921 info->clkrc = 0; in ov7670_probe()
1926 info->devtype->set_framerate(sd, &tpf); in ov7670_probe()
1928 v4l2_ctrl_handler_init(&info->hdl, 10); in ov7670_probe()
1929 v4l2_ctrl_new_std(&info->hdl, &ov7670_ctrl_ops, in ov7670_probe()
1931 v4l2_ctrl_new_std(&info->hdl, &ov7670_ctrl_ops, in ov7670_probe()
1933 v4l2_ctrl_new_std(&info->hdl, &ov7670_ctrl_ops, in ov7670_probe()
1935 v4l2_ctrl_new_std(&info->hdl, &ov7670_ctrl_ops, in ov7670_probe()
1937 info->saturation = v4l2_ctrl_new_std(&info->hdl, &ov7670_ctrl_ops, in ov7670_probe()
1939 info->hue = v4l2_ctrl_new_std(&info->hdl, &ov7670_ctrl_ops, in ov7670_probe()
1940 V4L2_CID_HUE, -180, 180, 5, 0); in ov7670_probe()
1941 info->gain = v4l2_ctrl_new_std(&info->hdl, &ov7670_ctrl_ops, in ov7670_probe()
1943 info->auto_gain = v4l2_ctrl_new_std(&info->hdl, &ov7670_ctrl_ops, in ov7670_probe()
1945 info->exposure = v4l2_ctrl_new_std(&info->hdl, &ov7670_ctrl_ops, in ov7670_probe()
1947 info->auto_exposure = v4l2_ctrl_new_std_menu(&info->hdl, &ov7670_ctrl_ops, in ov7670_probe()
1950 v4l2_ctrl_new_std_menu_items(&info->hdl, &ov7670_ctrl_ops, in ov7670_probe()
1952 ARRAY_SIZE(ov7670_test_pattern_menu) - 1, 0, 0, in ov7670_probe()
1954 sd->ctrl_handler = &info->hdl; in ov7670_probe()
1955 if (info->hdl.error) { in ov7670_probe()
1956 ret = info->hdl.error; in ov7670_probe()
1964 v4l2_ctrl_auto_cluster(2, &info->auto_gain, 0, true); in ov7670_probe()
1965 v4l2_ctrl_auto_cluster(2, &info->auto_exposure, in ov7670_probe()
1967 v4l2_ctrl_cluster(2, &info->saturation); in ov7670_probe()
1970 info->pad.flags = MEDIA_PAD_FL_SOURCE; in ov7670_probe()
1971 info->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR; in ov7670_probe()
1972 ret = media_entity_pads_init(&info->sd.entity, 1, &info->pad); in ov7670_probe()
1977 v4l2_ctrl_handler_setup(&info->hdl); in ov7670_probe()
1979 ret = v4l2_async_register_subdev(&info->sd); in ov7670_probe()
1987 media_entity_cleanup(&info->sd.entity); in ov7670_probe()
1989 v4l2_ctrl_handler_free(&info->hdl); in ov7670_probe()
2001 v4l2_ctrl_handler_free(&info->hdl); in ov7670_remove()
2002 media_entity_cleanup(&info->sd.entity); in ov7670_remove()