From 9370bb92b2d16684ee45cf24e879c93c509162da Mon Sep 17 00:00:00 2001 From: hc <hc@nodka.com> Date: Thu, 19 Dec 2024 01:47:39 +0000 Subject: [PATCH] add wifi6 8852be driver --- 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