hc
2023-12-11 d2ccde1c8e90d38cee87a1b0309ad2827f3fd30d
kernel/drivers/media/i2c/ov7670.c
....@@ -1,3 +1,4 @@
1
+// SPDX-License-Identifier: GPL-2.0-only
12 /*
23 * A V4L2 driver for OmniVision OV7670 cameras.
34 *
....@@ -6,9 +7,6 @@
67 * McClelland's ovcamchip code.
78 *
89 * Copyright 2006-7 Jonathan Corbet <corbet@lwn.net>
9
- *
10
- * This file may be distributed under the terms of the GNU General
11
- * Public License, version 2.
1210 */
1311 #include <linux/clk.h>
1412 #include <linux/init.h>
....@@ -20,6 +18,7 @@
2018 #include <linux/gpio.h>
2119 #include <linux/gpio/consumer.h>
2220 #include <media/v4l2-device.h>
21
+#include <media/v4l2-event.h>
2322 #include <media/v4l2-ctrls.h>
2423 #include <media/v4l2-fwnode.h>
2524 #include <media/v4l2-mediabus.h>
....@@ -240,7 +239,9 @@
240239 };
241240 struct v4l2_mbus_framefmt format;
242241 struct ov7670_format_struct *fmt; /* Current format */
242
+ struct ov7670_win_size *wsize;
243243 struct clk *clk;
244
+ int on;
244245 struct gpio_desc *resetb_gpio;
245246 struct gpio_desc *pwdn_gpio;
246247 unsigned int mbus_config; /* Media bus configuration flags */
....@@ -809,13 +810,25 @@
809810 (4 * clkrc);
810811 }
811812
813
+static int ov7675_apply_framerate(struct v4l2_subdev *sd)
814
+{
815
+ struct ov7670_info *info = to_state(sd);
816
+ int ret;
817
+
818
+ ret = ov7670_write(sd, REG_CLKRC, info->clkrc);
819
+ if (ret < 0)
820
+ return ret;
821
+
822
+ return ov7670_write(sd, REG_DBLV,
823
+ info->pll_bypass ? DBLV_BYPASS : DBLV_X4);
824
+}
825
+
812826 static int ov7675_set_framerate(struct v4l2_subdev *sd,
813827 struct v4l2_fract *tpf)
814828 {
815829 struct ov7670_info *info = to_state(sd);
816830 u32 clkrc;
817831 int pll_factor;
818
- int ret;
819832
820833 /*
821834 * The formula is fps = 5/4*pixclk for YUV/RGB and
....@@ -824,19 +837,10 @@
824837 * pixclk = clock_speed / (clkrc + 1) * PLLfactor
825838 *
826839 */
827
- if (info->pll_bypass) {
828
- pll_factor = 1;
829
- ret = ov7670_write(sd, REG_DBLV, DBLV_BYPASS);
830
- } else {
831
- pll_factor = PLL_FACTOR;
832
- ret = ov7670_write(sd, REG_DBLV, DBLV_X4);
833
- }
834
- if (ret < 0)
835
- return ret;
836
-
837840 if (tpf->numerator == 0 || tpf->denominator == 0) {
838841 clkrc = 0;
839842 } else {
843
+ pll_factor = info->pll_bypass ? 1 : PLL_FACTOR;
840844 clkrc = (5 * pll_factor * info->clock_speed * tpf->numerator) /
841845 (4 * tpf->denominator);
842846 if (info->fmt->mbus_code == MEDIA_BUS_FMT_SBGGR8_1X8)
....@@ -858,9 +862,13 @@
858862 /* Recalculate frame rate */
859863 ov7675_get_framerate(sd, tpf);
860864
861
- ret = ov7670_write(sd, REG_CLKRC, info->clkrc);
862
- if (ret < 0)
863
- return ret;
865
+ /*
866
+ * If the device is not powered up by the host driver do
867
+ * not apply any changes to H/W at this time. Instead
868
+ * the framerate will be restored right after power-up.
869
+ */
870
+ if (info->on)
871
+ return ov7675_apply_framerate(sd);
864872
865873 return 0;
866874 }
....@@ -893,7 +901,16 @@
893901 info->clkrc = (info->clkrc & 0x80) | div;
894902 tpf->numerator = 1;
895903 tpf->denominator = info->clock_speed / div;
896
- return ov7670_write(sd, REG_CLKRC, info->clkrc);
904
+
905
+ /*
906
+ * If the device is not powered up by the host driver do
907
+ * not apply any changes to H/W at this time. Instead
908
+ * the framerate will be restored right after power-up.
909
+ */
910
+ if (info->on)
911
+ return ov7670_write(sd, REG_CLKRC, info->clkrc);
912
+
913
+ return 0;
897914 }
898915
899916 /*
....@@ -1003,48 +1020,20 @@
10031020 return 0;
10041021 }
10051022
1006
-/*
1007
- * Set a format.
1008
- */
1009
-static int ov7670_set_fmt(struct v4l2_subdev *sd,
1010
- struct v4l2_subdev_pad_config *cfg,
1011
- struct v4l2_subdev_format *format)
1023
+static int ov7670_apply_fmt(struct v4l2_subdev *sd)
10121024 {
1013
- struct ov7670_format_struct *ovfmt;
1014
- struct ov7670_win_size *wsize;
10151025 struct ov7670_info *info = to_state(sd);
1016
-#ifdef CONFIG_VIDEO_V4L2_SUBDEV_API
1017
- struct v4l2_mbus_framefmt *mbus_fmt;
1018
-#endif
1026
+ struct ov7670_win_size *wsize = info->wsize;
10191027 unsigned char com7, com10 = 0;
10201028 int ret;
10211029
1022
- if (format->pad)
1023
- return -EINVAL;
1024
-
1025
- if (format->which == V4L2_SUBDEV_FORMAT_TRY) {
1026
- ret = ov7670_try_fmt_internal(sd, &format->format, NULL, NULL);
1027
- if (ret)
1028
- return ret;
1029
-#ifdef CONFIG_VIDEO_V4L2_SUBDEV_API
1030
- mbus_fmt = v4l2_subdev_get_try_format(sd, cfg, format->pad);
1031
- *mbus_fmt = format->format;
1032
- return 0;
1033
-#else
1034
- return -ENOTTY;
1035
-#endif
1036
- }
1037
-
1038
- ret = ov7670_try_fmt_internal(sd, &format->format, &ovfmt, &wsize);
1039
- if (ret)
1040
- return ret;
10411030 /*
10421031 * COM7 is a pain in the ass, it doesn't like to be read then
10431032 * quickly written afterward. But we have everything we need
10441033 * to set it absolutely here, as long as the format-specific
10451034 * register sets list it first.
10461035 */
1047
- com7 = ovfmt->regs[0].value;
1036
+ com7 = info->fmt->regs[0].value;
10481037 com7 |= wsize->com7_bit;
10491038 ret = ov7670_write(sd, REG_COM7, com7);
10501039 if (ret)
....@@ -1066,7 +1055,7 @@
10661055 /*
10671056 * Now write the rest of the array. Also store start/stops
10681057 */
1069
- ret = ov7670_write_array(sd, ovfmt->regs + 1);
1058
+ ret = ov7670_write_array(sd, info->fmt->regs + 1);
10701059 if (ret)
10711060 return ret;
10721061
....@@ -1081,8 +1070,6 @@
10811070 return ret;
10821071 }
10831072
1084
- info->fmt = ovfmt;
1085
-
10861073 /*
10871074 * If we're running RGB565, we must rewrite clkrc after setting
10881075 * the other parameters or the image looks poor. If we're *not*
....@@ -1096,6 +1083,48 @@
10961083 ret = ov7670_write(sd, REG_CLKRC, info->clkrc);
10971084 if (ret)
10981085 return ret;
1086
+
1087
+ return 0;
1088
+}
1089
+
1090
+/*
1091
+ * Set a format.
1092
+ */
1093
+static int ov7670_set_fmt(struct v4l2_subdev *sd,
1094
+ struct v4l2_subdev_pad_config *cfg,
1095
+ struct v4l2_subdev_format *format)
1096
+{
1097
+ struct ov7670_info *info = to_state(sd);
1098
+#ifdef CONFIG_VIDEO_V4L2_SUBDEV_API
1099
+ struct v4l2_mbus_framefmt *mbus_fmt;
1100
+#endif
1101
+ int ret;
1102
+
1103
+ if (format->pad)
1104
+ return -EINVAL;
1105
+
1106
+ if (format->which == V4L2_SUBDEV_FORMAT_TRY) {
1107
+ ret = ov7670_try_fmt_internal(sd, &format->format, NULL, NULL);
1108
+ if (ret)
1109
+ return ret;
1110
+#ifdef CONFIG_VIDEO_V4L2_SUBDEV_API
1111
+ mbus_fmt = v4l2_subdev_get_try_format(sd, cfg, format->pad);
1112
+ *mbus_fmt = format->format;
1113
+#endif
1114
+ return 0;
1115
+ }
1116
+
1117
+ ret = ov7670_try_fmt_internal(sd, &format->format, &info->fmt, &info->wsize);
1118
+ if (ret)
1119
+ return ret;
1120
+
1121
+ /*
1122
+ * If the device is not powered up by the host driver do
1123
+ * not apply any changes to H/W at this time. Instead
1124
+ * the frame format will be restored right after power-up.
1125
+ */
1126
+ if (info->on)
1127
+ return ov7670_apply_fmt(sd);
10991128
11001129 return 0;
11011130 }
....@@ -1115,7 +1144,7 @@
11151144 format->format = *mbus_fmt;
11161145 return 0;
11171146 #else
1118
- return -ENOTTY;
1147
+ return -EINVAL;
11191148 #endif
11201149 } else {
11211150 format->format = info->format;
....@@ -1606,17 +1635,58 @@
16061635 }
16071636 #endif
16081637
1638
+static void ov7670_power_on(struct v4l2_subdev *sd)
1639
+{
1640
+ struct ov7670_info *info = to_state(sd);
1641
+
1642
+ if (info->on)
1643
+ return;
1644
+
1645
+ clk_prepare_enable(info->clk);
1646
+
1647
+ if (info->pwdn_gpio)
1648
+ gpiod_set_value(info->pwdn_gpio, 0);
1649
+ if (info->resetb_gpio) {
1650
+ gpiod_set_value(info->resetb_gpio, 1);
1651
+ usleep_range(500, 1000);
1652
+ gpiod_set_value(info->resetb_gpio, 0);
1653
+ }
1654
+ if (info->pwdn_gpio || info->resetb_gpio || info->clk)
1655
+ usleep_range(3000, 5000);
1656
+
1657
+ info->on = true;
1658
+}
1659
+
1660
+static void ov7670_power_off(struct v4l2_subdev *sd)
1661
+{
1662
+ struct ov7670_info *info = to_state(sd);
1663
+
1664
+ if (!info->on)
1665
+ return;
1666
+
1667
+ clk_disable_unprepare(info->clk);
1668
+
1669
+ if (info->pwdn_gpio)
1670
+ gpiod_set_value(info->pwdn_gpio, 1);
1671
+
1672
+ info->on = false;
1673
+}
1674
+
16091675 static int ov7670_s_power(struct v4l2_subdev *sd, int on)
16101676 {
16111677 struct ov7670_info *info = to_state(sd);
16121678
1613
- if (info->pwdn_gpio)
1614
- gpiod_set_value(info->pwdn_gpio, !on);
1615
- if (on && info->resetb_gpio) {
1616
- gpiod_set_value(info->resetb_gpio, 1);
1617
- usleep_range(500, 1000);
1618
- gpiod_set_value(info->resetb_gpio, 0);
1619
- usleep_range(3000, 5000);
1679
+ if (info->on == on)
1680
+ return 0;
1681
+
1682
+ if (on) {
1683
+ ov7670_power_on (sd);
1684
+ ov7670_init(sd, 0);
1685
+ ov7670_apply_fmt(sd);
1686
+ ov7675_apply_framerate(sd);
1687
+ v4l2_ctrl_handler_setup(&info->hdl);
1688
+ } else {
1689
+ ov7670_power_off (sd);
16201690 }
16211691
16221692 return 0;
....@@ -1651,6 +1721,10 @@
16511721 static const struct v4l2_subdev_core_ops ov7670_core_ops = {
16521722 .reset = ov7670_reset,
16531723 .init = ov7670_init,
1724
+ .s_power = ov7670_s_power,
1725
+ .log_status = v4l2_ctrl_subdev_log_status,
1726
+ .subscribe_event = v4l2_ctrl_subdev_subscribe_event,
1727
+ .unsubscribe_event = v4l2_event_subdev_unsubscribe,
16541728 #ifdef CONFIG_VIDEO_ADV_DEBUG
16551729 .g_register = ov7670_g_register,
16561730 .s_register = ov7670_s_register,
....@@ -1728,7 +1802,7 @@
17281802 struct ov7670_info *info)
17291803 {
17301804 struct fwnode_handle *fwnode = dev_fwnode(dev);
1731
- struct v4l2_fwnode_endpoint bus_cfg;
1805
+ struct v4l2_fwnode_endpoint bus_cfg = { .bus_type = 0 };
17321806 struct fwnode_handle *ep;
17331807 int ret;
17341808
....@@ -1773,7 +1847,7 @@
17731847
17741848 #ifdef CONFIG_VIDEO_V4L2_SUBDEV_API
17751849 sd->internal_ops = &ov7670_subdev_internal_ops;
1776
- sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
1850
+ sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE | V4L2_SUBDEV_FL_HAS_EVENTS;
17771851 #endif
17781852
17791853 info->clock_speed = 30; /* default: a guess */
....@@ -1812,23 +1886,20 @@
18121886 else
18131887 return ret;
18141888 }
1815
- if (info->clk) {
1816
- ret = clk_prepare_enable(info->clk);
1817
- if (ret)
1818
- return ret;
1819
-
1820
- info->clock_speed = clk_get_rate(info->clk) / 1000000;
1821
- if (info->clock_speed < 10 || info->clock_speed > 48) {
1822
- ret = -EINVAL;
1823
- goto clk_disable;
1824
- }
1825
- }
18261889
18271890 ret = ov7670_init_gpio(client, info);
18281891 if (ret)
1829
- goto clk_disable;
1892
+ return ret;
18301893
1831
- ov7670_s_power(sd, 1);
1894
+ ov7670_power_on(sd);
1895
+
1896
+ if (info->clk) {
1897
+ info->clock_speed = clk_get_rate(info->clk) / 1000000;
1898
+ if (info->clock_speed < 10 || info->clock_speed > 48) {
1899
+ ret = -EINVAL;
1900
+ goto power_off;
1901
+ }
1902
+ }
18321903
18331904 /* Make sure it's an ov7670 */
18341905 ret = ov7670_detect(sd);
....@@ -1843,6 +1914,7 @@
18431914
18441915 info->devtype = &ov7670_devdata[id->driver_data];
18451916 info->fmt = &ov7670_formats[0];
1917
+ info->wsize = &info->devtype->win_sizes[0];
18461918
18471919 ov7670_get_default_format(sd, &info->format);
18481920
....@@ -1908,6 +1980,7 @@
19081980 if (ret < 0)
19091981 goto entity_cleanup;
19101982
1983
+ ov7670_power_off(sd);
19111984 return 0;
19121985
19131986 entity_cleanup:
....@@ -1915,12 +1988,9 @@
19151988 hdl_free:
19161989 v4l2_ctrl_handler_free(&info->hdl);
19171990 power_off:
1918
- ov7670_s_power(sd, 0);
1919
-clk_disable:
1920
- clk_disable_unprepare(info->clk);
1991
+ ov7670_power_off(sd);
19211992 return ret;
19221993 }
1923
-
19241994
19251995 static int ov7670_remove(struct i2c_client *client)
19261996 {
....@@ -1929,9 +1999,7 @@
19291999
19302000 v4l2_async_unregister_subdev(sd);
19312001 v4l2_ctrl_handler_free(&info->hdl);
1932
- clk_disable_unprepare(info->clk);
19332002 media_entity_cleanup(&info->sd.entity);
1934
- ov7670_s_power(sd, 0);
19352003 return 0;
19362004 }
19372005