From 1543e317f1da31b75942316931e8f491a8920811 Mon Sep 17 00:00:00 2001
From: hc <hc@nodka.com>
Date: Thu, 04 Jan 2024 10:08:02 +0000
Subject: [PATCH] disable FB
---
kernel/drivers/media/i2c/ov7670.c | 232 +++++++++++++++++++++++++++++++++++++--------------------
1 files changed, 150 insertions(+), 82 deletions(-)
diff --git a/kernel/drivers/media/i2c/ov7670.c b/kernel/drivers/media/i2c/ov7670.c
index 1f71c14..e47800c 100644
--- a/kernel/drivers/media/i2c/ov7670.c
+++ b/kernel/drivers/media/i2c/ov7670.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* A V4L2 driver for OmniVision OV7670 cameras.
*
@@ -6,9 +7,6 @@
* McClelland's ovcamchip code.
*
* Copyright 2006-7 Jonathan Corbet <corbet@lwn.net>
- *
- * This file may be distributed under the terms of the GNU General
- * Public License, version 2.
*/
#include <linux/clk.h>
#include <linux/init.h>
@@ -20,6 +18,7 @@
#include <linux/gpio.h>
#include <linux/gpio/consumer.h>
#include <media/v4l2-device.h>
+#include <media/v4l2-event.h>
#include <media/v4l2-ctrls.h>
#include <media/v4l2-fwnode.h>
#include <media/v4l2-mediabus.h>
@@ -240,7 +239,9 @@
};
struct v4l2_mbus_framefmt format;
struct ov7670_format_struct *fmt; /* Current format */
+ struct ov7670_win_size *wsize;
struct clk *clk;
+ int on;
struct gpio_desc *resetb_gpio;
struct gpio_desc *pwdn_gpio;
unsigned int mbus_config; /* Media bus configuration flags */
@@ -809,13 +810,25 @@
(4 * clkrc);
}
+static int ov7675_apply_framerate(struct v4l2_subdev *sd)
+{
+ struct ov7670_info *info = to_state(sd);
+ int ret;
+
+ ret = ov7670_write(sd, REG_CLKRC, info->clkrc);
+ if (ret < 0)
+ return ret;
+
+ return ov7670_write(sd, REG_DBLV,
+ info->pll_bypass ? DBLV_BYPASS : DBLV_X4);
+}
+
static int ov7675_set_framerate(struct v4l2_subdev *sd,
struct v4l2_fract *tpf)
{
struct ov7670_info *info = to_state(sd);
u32 clkrc;
int pll_factor;
- int ret;
/*
* The formula is fps = 5/4*pixclk for YUV/RGB and
@@ -824,19 +837,10 @@
* pixclk = clock_speed / (clkrc + 1) * PLLfactor
*
*/
- if (info->pll_bypass) {
- pll_factor = 1;
- ret = ov7670_write(sd, REG_DBLV, DBLV_BYPASS);
- } else {
- pll_factor = PLL_FACTOR;
- ret = ov7670_write(sd, REG_DBLV, DBLV_X4);
- }
- if (ret < 0)
- return ret;
-
if (tpf->numerator == 0 || tpf->denominator == 0) {
clkrc = 0;
} else {
+ pll_factor = info->pll_bypass ? 1 : PLL_FACTOR;
clkrc = (5 * pll_factor * info->clock_speed * tpf->numerator) /
(4 * tpf->denominator);
if (info->fmt->mbus_code == MEDIA_BUS_FMT_SBGGR8_1X8)
@@ -858,9 +862,13 @@
/* Recalculate frame rate */
ov7675_get_framerate(sd, tpf);
- ret = ov7670_write(sd, REG_CLKRC, info->clkrc);
- if (ret < 0)
- return ret;
+ /*
+ * If the device is not powered up by the host driver do
+ * not apply any changes to H/W at this time. Instead
+ * the framerate will be restored right after power-up.
+ */
+ if (info->on)
+ return ov7675_apply_framerate(sd);
return 0;
}
@@ -893,7 +901,16 @@
info->clkrc = (info->clkrc & 0x80) | div;
tpf->numerator = 1;
tpf->denominator = info->clock_speed / div;
- return ov7670_write(sd, REG_CLKRC, info->clkrc);
+
+ /*
+ * If the device is not powered up by the host driver do
+ * not apply any changes to H/W at this time. Instead
+ * the framerate will be restored right after power-up.
+ */
+ if (info->on)
+ return ov7670_write(sd, REG_CLKRC, info->clkrc);
+
+ return 0;
}
/*
@@ -1003,48 +1020,20 @@
return 0;
}
-/*
- * Set a format.
- */
-static int ov7670_set_fmt(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
- struct v4l2_subdev_format *format)
+static int ov7670_apply_fmt(struct v4l2_subdev *sd)
{
- struct ov7670_format_struct *ovfmt;
- struct ov7670_win_size *wsize;
struct ov7670_info *info = to_state(sd);
-#ifdef CONFIG_VIDEO_V4L2_SUBDEV_API
- struct v4l2_mbus_framefmt *mbus_fmt;
-#endif
+ struct ov7670_win_size *wsize = info->wsize;
unsigned char com7, com10 = 0;
int ret;
- if (format->pad)
- return -EINVAL;
-
- if (format->which == V4L2_SUBDEV_FORMAT_TRY) {
- ret = ov7670_try_fmt_internal(sd, &format->format, NULL, NULL);
- if (ret)
- return ret;
-#ifdef CONFIG_VIDEO_V4L2_SUBDEV_API
- mbus_fmt = v4l2_subdev_get_try_format(sd, cfg, format->pad);
- *mbus_fmt = format->format;
- return 0;
-#else
- return -ENOTTY;
-#endif
- }
-
- ret = ov7670_try_fmt_internal(sd, &format->format, &ovfmt, &wsize);
- if (ret)
- return ret;
/*
* COM7 is a pain in the ass, it doesn't like to be read then
* quickly written afterward. But we have everything we need
* to set it absolutely here, as long as the format-specific
* register sets list it first.
*/
- com7 = ovfmt->regs[0].value;
+ com7 = info->fmt->regs[0].value;
com7 |= wsize->com7_bit;
ret = ov7670_write(sd, REG_COM7, com7);
if (ret)
@@ -1066,7 +1055,7 @@
/*
* Now write the rest of the array. Also store start/stops
*/
- ret = ov7670_write_array(sd, ovfmt->regs + 1);
+ ret = ov7670_write_array(sd, info->fmt->regs + 1);
if (ret)
return ret;
@@ -1081,8 +1070,6 @@
return ret;
}
- info->fmt = ovfmt;
-
/*
* If we're running RGB565, we must rewrite clkrc after setting
* the other parameters or the image looks poor. If we're *not*
@@ -1096,6 +1083,48 @@
ret = ov7670_write(sd, REG_CLKRC, info->clkrc);
if (ret)
return ret;
+
+ return 0;
+}
+
+/*
+ * Set a format.
+ */
+static int ov7670_set_fmt(struct v4l2_subdev *sd,
+ struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_format *format)
+{
+ struct ov7670_info *info = to_state(sd);
+#ifdef CONFIG_VIDEO_V4L2_SUBDEV_API
+ struct v4l2_mbus_framefmt *mbus_fmt;
+#endif
+ int ret;
+
+ if (format->pad)
+ return -EINVAL;
+
+ if (format->which == V4L2_SUBDEV_FORMAT_TRY) {
+ ret = ov7670_try_fmt_internal(sd, &format->format, NULL, NULL);
+ if (ret)
+ return ret;
+#ifdef CONFIG_VIDEO_V4L2_SUBDEV_API
+ mbus_fmt = v4l2_subdev_get_try_format(sd, cfg, format->pad);
+ *mbus_fmt = format->format;
+#endif
+ return 0;
+ }
+
+ ret = ov7670_try_fmt_internal(sd, &format->format, &info->fmt, &info->wsize);
+ if (ret)
+ return ret;
+
+ /*
+ * If the device is not powered up by the host driver do
+ * not apply any changes to H/W at this time. Instead
+ * the frame format will be restored right after power-up.
+ */
+ if (info->on)
+ return ov7670_apply_fmt(sd);
return 0;
}
@@ -1115,7 +1144,7 @@
format->format = *mbus_fmt;
return 0;
#else
- return -ENOTTY;
+ return -EINVAL;
#endif
} else {
format->format = info->format;
@@ -1606,17 +1635,58 @@
}
#endif
+static void ov7670_power_on(struct v4l2_subdev *sd)
+{
+ struct ov7670_info *info = to_state(sd);
+
+ if (info->on)
+ return;
+
+ clk_prepare_enable(info->clk);
+
+ if (info->pwdn_gpio)
+ gpiod_set_value(info->pwdn_gpio, 0);
+ if (info->resetb_gpio) {
+ gpiod_set_value(info->resetb_gpio, 1);
+ usleep_range(500, 1000);
+ gpiod_set_value(info->resetb_gpio, 0);
+ }
+ if (info->pwdn_gpio || info->resetb_gpio || info->clk)
+ usleep_range(3000, 5000);
+
+ info->on = true;
+}
+
+static void ov7670_power_off(struct v4l2_subdev *sd)
+{
+ struct ov7670_info *info = to_state(sd);
+
+ if (!info->on)
+ return;
+
+ clk_disable_unprepare(info->clk);
+
+ if (info->pwdn_gpio)
+ gpiod_set_value(info->pwdn_gpio, 1);
+
+ info->on = false;
+}
+
static int ov7670_s_power(struct v4l2_subdev *sd, int on)
{
struct ov7670_info *info = to_state(sd);
- if (info->pwdn_gpio)
- gpiod_set_value(info->pwdn_gpio, !on);
- if (on && info->resetb_gpio) {
- gpiod_set_value(info->resetb_gpio, 1);
- usleep_range(500, 1000);
- gpiod_set_value(info->resetb_gpio, 0);
- usleep_range(3000, 5000);
+ if (info->on == on)
+ return 0;
+
+ if (on) {
+ ov7670_power_on (sd);
+ ov7670_init(sd, 0);
+ ov7670_apply_fmt(sd);
+ ov7675_apply_framerate(sd);
+ v4l2_ctrl_handler_setup(&info->hdl);
+ } else {
+ ov7670_power_off (sd);
}
return 0;
@@ -1651,6 +1721,10 @@
static const struct v4l2_subdev_core_ops ov7670_core_ops = {
.reset = ov7670_reset,
.init = ov7670_init,
+ .s_power = ov7670_s_power,
+ .log_status = v4l2_ctrl_subdev_log_status,
+ .subscribe_event = v4l2_ctrl_subdev_subscribe_event,
+ .unsubscribe_event = v4l2_event_subdev_unsubscribe,
#ifdef CONFIG_VIDEO_ADV_DEBUG
.g_register = ov7670_g_register,
.s_register = ov7670_s_register,
@@ -1728,7 +1802,7 @@
struct ov7670_info *info)
{
struct fwnode_handle *fwnode = dev_fwnode(dev);
- struct v4l2_fwnode_endpoint bus_cfg;
+ struct v4l2_fwnode_endpoint bus_cfg = { .bus_type = 0 };
struct fwnode_handle *ep;
int ret;
@@ -1750,7 +1824,7 @@
if (bus_cfg.bus_type != V4L2_MBUS_PARALLEL) {
dev_err(dev, "Unsupported media bus type\n");
- return ret;
+ return -EINVAL;
}
info->mbus_config = bus_cfg.bus.parallel.flags;
@@ -1773,7 +1847,7 @@
#ifdef CONFIG_VIDEO_V4L2_SUBDEV_API
sd->internal_ops = &ov7670_subdev_internal_ops;
- sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
+ sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE | V4L2_SUBDEV_FL_HAS_EVENTS;
#endif
info->clock_speed = 30; /* default: a guess */
@@ -1812,23 +1886,20 @@
else
return ret;
}
- if (info->clk) {
- ret = clk_prepare_enable(info->clk);
- if (ret)
- return ret;
-
- info->clock_speed = clk_get_rate(info->clk) / 1000000;
- if (info->clock_speed < 10 || info->clock_speed > 48) {
- ret = -EINVAL;
- goto clk_disable;
- }
- }
ret = ov7670_init_gpio(client, info);
if (ret)
- goto clk_disable;
+ return ret;
- ov7670_s_power(sd, 1);
+ ov7670_power_on(sd);
+
+ if (info->clk) {
+ info->clock_speed = clk_get_rate(info->clk) / 1000000;
+ if (info->clock_speed < 10 || info->clock_speed > 48) {
+ ret = -EINVAL;
+ goto power_off;
+ }
+ }
/* Make sure it's an ov7670 */
ret = ov7670_detect(sd);
@@ -1843,6 +1914,7 @@
info->devtype = &ov7670_devdata[id->driver_data];
info->fmt = &ov7670_formats[0];
+ info->wsize = &info->devtype->win_sizes[0];
ov7670_get_default_format(sd, &info->format);
@@ -1908,6 +1980,7 @@
if (ret < 0)
goto entity_cleanup;
+ ov7670_power_off(sd);
return 0;
entity_cleanup:
@@ -1915,12 +1988,9 @@
hdl_free:
v4l2_ctrl_handler_free(&info->hdl);
power_off:
- ov7670_s_power(sd, 0);
-clk_disable:
- clk_disable_unprepare(info->clk);
+ ov7670_power_off(sd);
return ret;
}
-
static int ov7670_remove(struct i2c_client *client)
{
@@ -1929,9 +1999,7 @@
v4l2_async_unregister_subdev(sd);
v4l2_ctrl_handler_free(&info->hdl);
- clk_disable_unprepare(info->clk);
media_entity_cleanup(&info->sd.entity);
- ov7670_s_power(sd, 0);
return 0;
}
--
Gitblit v1.6.2