rk3568制冷项目驱动开发流程汇总(只适用于部分模块CIF DVP等,自用)

news2024/12/24 21:03:20

采用fpga输入,3568采集并显示至hdmi

RKVICAP 驱动框架说明
        RKVICAP驱动主要是基于 v4l2 / media 框架实现硬件的配置、中断处理、控制 buffer 轮转,以及控制 subdevice(如 mipi dphy sensor) 的上下电等功能。
        对于RK356X 芯片而言, VICAP 只有单核,同时拥有 dvp/mipi 两种接口, dvp 接口对应一个 rkvicap_dvp 节点,mipi 接口对应一个 rkvicap_mipi_lvds 节点(与 RV1126/RV1109 VICAP FULL 同名),各节点可独立采集。
        为了将VICAP 采集数据信息同步给 isp 驱动,需要将 VICAP 驱动生成的逻辑 sditf 节点链接到 isp 所生成的虚拟节点设备。DVP 接口对应 rkvicap_dvp_sditf 节点, VICAP FULL mipi/lvds 接口对应 rkvicap_mipi_lvds_sditf节点, VICAP LITE 对应 rkvicap_lite_sditf

1.DVP camera

RK3568有一个DVP接口,支持BT601/BT656/BT1120等,同样的,如果是RAW的sensor,需要配置到ISP,如果是YUV的,则不需经过ISP,关键配置如下

(1)在sensor驱动的g_mbus_config接口中,通过flag指明当前sensor的hsync-acitve/vsyncactive/pclk-ative的有效极性,否则会导致无法收到数据;

static int avafpga_g_mbus_config(struct v4l2_subdev *sd, unsigned int pad_id,
				struct v4l2_mbus_config *config)
{
	config->type = V4L2_MBUS_BT656;
	config->flags = V4L2_MBUS_HSYNC_ACTIVE_HIGH |
			        V4L2_MBUS_VSYNC_ACTIVE_HIGH |
			        V4L2_MBUS_PCLK_SAMPLE_RISING;
	return 0;
}
(2)设备树的节点中hsync-active/vsync-active 不要配置,否则 v4l2 框架异步注册时会识别为 BT601;
(3)pclk-sample/bus-width 可选;
bus-width = <16>;
pclk-sample = <1>;

(4)必须实现v4l2_subdev_video_ops中的querystd接口,指明当前接口为ATSC接口,否则会导致无法收到数据;

static int avafpga_querystd(struct v4l2_subdev *sd, v4l2_std_id *std)
{
	*std = V4L2_STD_ATSC;
	return 0;
}

(5)必须实现RKMODULE_GET_BT656_MBUS_INFOBT656/BT1120都是调用这个ioctl,接口兼容,实现参考drivers/media/i2c/nvp6158_drv/nvp6158_v4l2.c

static __maybe_unused void
avafpga_get_bt656_module_inf(struct avafpga *avafpga,
			       struct rkmodule_bt656_mbus_info *inf)
{
	memset(inf, 0, sizeof(*inf));
	inf->flags = RKMODULE_CAMERA_BT656_PARSE_ID_LSB;
	switch (avafpga->ch_nums) {
	case 1:
		inf->flags |= RKMODULE_CAMERA_BT656_CHANNEL_0;
		break;
	case 2:
		inf->flags |= RKMODULE_CAMERA_BT656_CHANNEL_0 |
			      RKMODULE_CAMERA_BT656_CHANNEL_1;
		break;
	case 4:
		inf->flags |= RKMODULE_CAMERA_BT656_CHANNELS;
		break;
	default:
		inf->flags |= RKMODULE_CAMERA_BT656_CHANNELS;
	}
}

static long avafpga_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg)
{
	long ret = 0;
	switch (cmd) {

	default:
		ret = -ENOTTY;
		break;
	}

	return ret;
}

#ifdef CONFIG_COMPAT
static long avafpga_compat_ioctl32(struct v4l2_subdev *sd,
				   unsigned int cmd, unsigned long arg)
{
	long ret = 0;
	//struct rkmodule_bt656_mbus_info *bt565_inf;
	switch (cmd) {
		
	default:
		ret = -ENOIOCTLCMD;
		break;
	}

	return ret;
}
#endif

#define DST_XPOS 0
#define DST_YPOS 0
#define DST_WIDTH 1536 //1920
#define DST_HEIGHT 576 //1080

static int avafpga_get_selection(struct v4l2_subdev *sd,
				struct v4l2_subdev_pad_config *cfg,
				struct v4l2_subdev_selection *sel)
{
	if (sel->target == V4L2_SEL_TGT_CROP_BOUNDS) {
		sel->r.left = DST_XPOS;
		sel->r.top = DST_YPOS;
		sel->r.width = DST_WIDTH;
		sel->r.height = DST_HEIGHT;
		return 0;
	}
	return -EINVAL;
}

static int avafpga_initialize_controls(struct avafpga *avafpga)
{
	int ret;
	struct v4l2_ctrl_handler *handler;
	const struct avafpga_mode *mode;
	u32 h_blank, v_blank;

	handler = &avafpga->ctrl_handler;
	mode = avafpga->cur_mode;

	ret = v4l2_ctrl_handler_init(handler, 2);
	if (ret)
		return ret;
	handler->lock = &avafpga->mutex;

	h_blank = mode->hts_def - mode->width;
	avafpga->hblank_ctrl = v4l2_ctrl_new_std(handler, NULL,
				V4L2_CID_HBLANK, h_blank, h_blank, 1, h_blank);

	v_blank = mode->vts_def - mode->height;
	avafpga->vblank_ctrl = v4l2_ctrl_new_std(handler, NULL,
				V4L2_CID_VBLANK, v_blank, v_blank, 1, v_blank);

	if (handler->error) {
		ret = handler->error;
		dev_err(&avafpga->client->dev,
			"Failed to init controls(%d)\n", ret);
		goto err_free_handler;
	}

	avafpga->subdev.ctrl_handler = handler;

	return 0;

err_free_handler:
	v4l2_ctrl_handler_free(handler);

	return ret;
}

static const struct v4l2_subdev_core_ops avafpga_core_ops = {
	.s_power = avafpga_s_power,
	.ioctl = avafpga_ioctl,
#ifdef CONFIG_COMPAT
	.compat_ioctl32 = avafpga_compat_ioctl32,
#endif
};

(6)pinctrl需要引用对,以对bt656/bt1120相关gpio做相应iomux,否则会导致无法收到数据。

dts 配置如下:
&i2c0 {
    status =  "okay";

    sensor@3c{
        status =  "okay";
        compatible = "firefly,pc9202";
        reg = <0x3c>;
        wd-en-gpio = <&gpio3 23 GPIO_ACTIVE_HIGH>;
    };

	
	avafpga: avafpga@32 {
		status = "okay";
		compatible = "ava,fpga";
		reg = <0x32>;
		clocks = <&cru CLK_CIF_OUT>;
		clock-names = "xvclk";

		power-domains = <&power RK3568_PD_VI>;
		pwdn-gpios = <&gpio4 RK_PB4 GPIO_ACTIVE_HIGH>;
		reset-gpios = <&gpio3 RK_PB6 GPIO_ACTIVE_HIGH>;
		rockchip,grf = <&grf>;
		pinctrl-names = "default";
		pinctrl-0 = <&cif_clk&cif_dvp_clk&cif_dvp_bus16&cif_dvp_bus8>;
		rockchip,camera-module-index = <0>;
		rockchip,camera-module-facing = "back";
		rockchip,camera-module-name = "default";
		rockchip,camera-module-lens-name = "default";
		rockchip,dvp_mode = "BT1120"; //BT656 or BT1120 or BT656_TEST
		port {
			cam_para_out2: endpoint {
				remote-endpoint = <&dvp_in_bcam>;
				bus-width = <16>;
				pclk-sample = <1>;
			};
		};
	};
};

&rkcif {
        status = "okay";
};

&rkcif_mmu {
        status = "okay";
};

&rkcif_dvp {
        status = "okay";
		port {
		dvp_in_bcam: endpoint {
		remote-endpoint = <&cam_para_out2>;
		bus-width = <16>;
		};
		};
};

(7)/rk356x_sdk-linux5.10/kernel/drivers/media/i2c目录下增加fpga.c,并在kconfig和makefile中增加相关模块的设置

//kconfig
config VIDEO_FPGA
	tristate "AVA FPGA sensor support"
	depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API
	depends on MEDIA_CAMERA_SUPPORT
	help
	  This is a Video4Linux2 sensor driver for the AVA
	  FPGA camera.

	  To compile this driver as a module, choose M here: the
	  module will be called fpga.
//makefile
obj-y += fpga.o

完整的fpga的c代码如下,亦可见附件(开始未设置ioctl,上电v4l2抓图时,打印_avafpga_start_stream enter然后崩掉,后经查阅资料以及参考rv1126的内容,加入ioctl和vblank的ctrl对应部分,可以成功获取数据,且不会崩掉)

#include <linux/clk.h>
#include <linux/device.h>
#include <linux/delay.h>
#include <linux/gpio/consumer.h>
#include <linux/i2c.h>
#include <linux/module.h>
#include <linux/pm_runtime.h>
#include <linux/regulator/consumer.h>
#include <linux/sysfs.h>
#include <linux/slab.h>
#include <linux/version.h>
#include <linux/rk-camera-module.h>
#include <media/media-entity.h>
#include <media/v4l2-async.h>
#include <media/v4l2-ctrls.h>
#include <media/v4l2-subdev.h>
#include <linux/pinctrl/consumer.h>
#include <linux/rk-preisp.h>

#include <media/v4l2-fwnode.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/of_graph.h>
#include <linux/of_platform.h>
#include <linux/of_gpio.h>
#include <linux/mfd/syscon.h>
#include <linux/version.h>


#define DRIVER_VERSION			KERNEL_VERSION(0, 0x0, 0x01)
//#define PIX_FORMAT			MEDIA_BUS_FMT_UYVY8_2X8
#define PIX_FORMAT                    MEDIA_BUS_FMT_YUYV8_2X8
#define AVAFPGA_NAME			"avafpga"

struct regval {
	u16 addr;
	u8 val;
};

struct avafpga_mode {
	u32 width;
	u32 height;
	struct v4l2_fract max_fps;
	u32 hts_def;
	u32 vts_def;
	u32 exp_def;
	const struct regval *reg_list;
};

struct avafpga {
	struct i2c_client	*client;
	struct clk		*xvclk;
	struct gpio_desc	*reset_gpio;
	struct gpio_desc	*pwdn_gpio;

	struct v4l2_subdev	subdev;
	struct media_pad	pad;
	struct v4l2_ctrl_handler ctrl_handler;
	struct v4l2_ctrl	*exposure;
	struct v4l2_ctrl	*anal_gain;
	struct v4l2_ctrl	*digi_gain;
	struct v4l2_ctrl	*hblank;
	struct v4l2_ctrl	*vblank;
	struct v4l2_ctrl	*test_pattern;
	struct mutex		mutex;
	bool			streaming;
	bool			power_on;
	const struct avafpga_mode *cur_mode;
	u32			module_index;
	const char		*module_facing;
	const char		*module_name;
	const char		*len_name;
	u32			ch_nums;
	//hjk
	struct v4l2_ctrl	*vblank_ctrl;
	struct v4l2_ctrl	*hblank_ctrl;

	u8 is_reset;
};

#define to_avafpga(sd) container_of(sd, struct avafpga, subdev)

static const struct avafpga_mode supported_modes[] = {
	{
		//.width = 1920,
		//.height = 1080,
		.width = 1536,
		.height = 576,		
		.max_fps = {
			.numerator = 10000,
			.denominator = 600000,
		},
		.exp_def = 0x0100,
		.hts_def = 0x044c * 2,
		.vts_def = 0x0465,
	}
};

static int __avafpga_start_stream(struct avafpga *avafpga)
{
	printk(KERN_ERR "%s enter\n", __func__);
	avafpga->is_reset = 1;//hjk1126
	printk(KERN_ERR "%s exit\n", __func__);//hjk1126

	return 0;
}

static int __avafpga_stop_stream(struct avafpga *avafpga)
{
	printk(KERN_ERR "%s enter\n", __func__);
	return 0;
}

static int avafpga_s_stream(struct v4l2_subdev *sd, int on)
{
	struct avafpga *avafpga = to_avafpga(sd);
	struct i2c_client *client = avafpga->client;
	int ret = 0;

	mutex_lock(&avafpga->mutex);
	on = !!on;
	if (on == avafpga->streaming)
		goto unlock_and_return;

	if (on) {
		ret = pm_runtime_get_sync(&client->dev);
		if (ret < 0) {
			pm_runtime_put_noidle(&client->dev);
			goto unlock_and_return;
		}

		ret = __avafpga_start_stream(avafpga);
		if (ret) {
			v4l2_err(sd, "start stream failed while write regs\n");
			pm_runtime_put(&client->dev);
			goto unlock_and_return;
		}
	} else {
		__avafpga_stop_stream(avafpga);
		pm_runtime_put(&client->dev);
	}

	avafpga->streaming = on;
unlock_and_return:
	mutex_unlock(&avafpga->mutex);

	return ret;
}


#ifdef CONFIG_VIDEO_V4L2_SUBDEV_API
static int avafpga_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
{
	struct avafpga *avafpga = to_avafpga(sd);
	struct v4l2_mbus_framefmt *try_fmt =
				v4l2_subdev_get_try_format(sd, fh->pad, 0);
	const struct avafpga_mode *def_mode = &supported_modes[0];

	mutex_lock(&avafpga->mutex);
	/* Initialize try_fmt */
	try_fmt->width = def_mode->width;
	try_fmt->height = def_mode->height;
	try_fmt->code = PIX_FORMAT;
	try_fmt->field = V4L2_FIELD_NONE;
	mutex_unlock(&avafpga->mutex);
	/* No crop or compose */

	return 0;
}
#endif

static int avafpga_g_mbus_config(struct v4l2_subdev *sd, unsigned int pad_id,
				struct v4l2_mbus_config *config)
{
	//config->type = V4L2_MBUS_BT656;
	//config->flags = V4L2_MBUS_PCLK_SAMPLE_RISING;

	config->type = V4L2_MBUS_BT656;
	config->flags = V4L2_MBUS_PCLK_SAMPLE_RISING;
	//config->flags = V4L2_MBUS_HSYNC_ACTIVE_LOW |
 			//V4L2_MBUS_VSYNC_ACTIVE_LOW |
			//V4L2_MBUS_PCLK_SAMPLE_FALLING;
	//config->type = V4L2_MBUS_BT656;
	//config->flags = RKMODULE_CAMERA_BT656_CHANNELS |
				//V4L2_MBUS_PCLK_SAMPLE_RISING;

	//config->type = V4L2_MBUS_BT656;
	config->flags = V4L2_MBUS_HSYNC_ACTIVE_HIGH |
			V4L2_MBUS_VSYNC_ACTIVE_HIGH |
			V4L2_MBUS_PCLK_SAMPLE_RISING;
	return 0;

}

static int avafpga_g_frame_interval(struct v4l2_subdev *sd,
				   struct v4l2_subdev_frame_interval *fi)
{
	struct avafpga *avafpga = to_avafpga(sd);
	const struct avafpga_mode *mode = avafpga->cur_mode;

	mutex_lock(&avafpga->mutex);
	fi->interval = mode->max_fps;
	mutex_unlock(&avafpga->mutex);

	return 0;
}

static int avafpga_querystd(struct v4l2_subdev *sd, v4l2_std_id *std)
{
	*std = V4L2_STD_ATSC;
	return 0;
}


static int avafpga_enum_frame_interval(struct v4l2_subdev *sd,
				       struct v4l2_subdev_pad_config *cfg,
				       struct v4l2_subdev_frame_interval_enum *fie)
{
	if (fie->index >= ARRAY_SIZE(supported_modes))
		return -EINVAL;

	//if (fie->code != PIX_FORMAT)
		//return -EINVAL;

	fie->width = supported_modes[fie->index].width;
	fie->height = supported_modes[fie->index].height;
	fie->interval = supported_modes[fie->index].max_fps;
	return 0;
}

static int avafpga_enum_mbus_code(struct v4l2_subdev *sd,
				 struct v4l2_subdev_pad_config *cfg,
				 struct v4l2_subdev_mbus_code_enum *code)
{
	if (code->index != 0)
		return -EINVAL;
	code->code = PIX_FORMAT;

	return 0;
}

static int avafpga_enum_frame_sizes(struct v4l2_subdev *sd,
				   struct v4l2_subdev_pad_config *cfg,
				   struct v4l2_subdev_frame_size_enum *fse)
{
	if (fse->index >= ARRAY_SIZE(supported_modes))
		return -EINVAL;

	//if (fse->code != PIX_FORMAT)//hjk1126中没有这个
		//return -EINVAL;//hjk1126中没有这个

	fse->min_width  = supported_modes[fse->index].width;
	fse->max_width  = supported_modes[fse->index].width;
	fse->max_height = supported_modes[fse->index].height;
	fse->min_height = supported_modes[fse->index].height;

	return 0;
}

static int avafpga_set_fmt(struct v4l2_subdev *sd,
			  struct v4l2_subdev_pad_config *cfg,
			  struct v4l2_subdev_format *fmt)
{
	struct avafpga *avafpga = to_avafpga(sd);
	const struct avafpga_mode *mode;

	mutex_lock(&avafpga->mutex);

	mode = avafpga->cur_mode;
	fmt->format.code = PIX_FORMAT;
	fmt->format.width = mode->width;
	fmt->format.height = mode->height;
	fmt->format.field = V4L2_FIELD_NONE;
	//fmt->format.field = V4L2_FIELD_INTERLACED;
	if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
#ifdef CONFIG_VIDEO_V4L2_SUBDEV_API
		*v4l2_subdev_get_try_format(sd, cfg, fmt->pad) = fmt->format;
#else
		mutex_unlock(&avafpga->mutex);
		return -ENOTTY;
#endif
	} else {
		avafpga->cur_mode = mode;
	}

	mutex_unlock(&avafpga->mutex);

	return 0;
}

static int avafpga_get_fmt(struct v4l2_subdev *sd,
			  struct v4l2_subdev_pad_config *cfg,
			  struct v4l2_subdev_format *fmt)
{
	struct avafpga *avafpga = to_avafpga(sd);
	const struct avafpga_mode *mode = avafpga->cur_mode;

	mutex_lock(&avafpga->mutex);
	if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
#ifdef CONFIG_VIDEO_V4L2_SUBDEV_API
		fmt->format = *v4l2_subdev_get_try_format(sd, cfg, fmt->pad);
#else
		mutex_unlock(&avafpga->mutex);
		return -ENOTTY;
#endif
	} else {
		fmt->format.width = mode->width;
		fmt->format.height = mode->height;
		fmt->format.code = PIX_FORMAT;
		fmt->format.field = V4L2_FIELD_NONE;
	}
	mutex_unlock(&avafpga->mutex);

	return 0;
}

static int avafpga_s_power(struct v4l2_subdev *sd, int on)
{
	struct avafpga *avafpga = to_avafpga(sd);
	struct i2c_client *client = avafpga->client;
	int ret = 0;

	mutex_lock(&avafpga->mutex);

	/* If the power state is not modified - no work to do. */
	if (avafpga->power_on == !!on)
		goto unlock_and_return;

	if (on) {
		ret = pm_runtime_get_sync(&client->dev);
		if (ret < 0) {
			pm_runtime_put_noidle(&client->dev);
			goto unlock_and_return;
		}

		avafpga->power_on = true;
	} else {
		pm_runtime_put(&client->dev);
		avafpga->power_on = false;
	}

unlock_and_return:
	mutex_unlock(&avafpga->mutex);

	return ret;
}

static int __avafpga_power_on(struct avafpga *avafpga)
{
	return 0;
}

static void __avafpga_power_off(struct avafpga *avafpga)
{
	return;
}

static int avafpga_runtime_resume(struct device *dev)
{
	struct i2c_client *client = to_i2c_client(dev);
	struct v4l2_subdev *sd = i2c_get_clientdata(client);
	struct avafpga *avafpga = to_avafpga(sd);

	return __avafpga_power_on(avafpga);
}

static int avafpga_runtime_suspend(struct device *dev)
{
	struct i2c_client *client = to_i2c_client(dev);
	struct v4l2_subdev *sd = i2c_get_clientdata(client);
	struct avafpga *avafpga = to_avafpga(sd);

	__avafpga_power_off(avafpga);

	return 0;
}

hjk///
static __maybe_unused void
avafpga_get_bt656_module_inf(struct avafpga *avafpga,
			       struct rkmodule_bt656_mbus_info *inf)
{
	memset(inf, 0, sizeof(*inf));
	inf->flags = RKMODULE_CAMERA_BT656_PARSE_ID_LSB;
	switch (avafpga->ch_nums) {
	case 1:
		inf->flags |= RKMODULE_CAMERA_BT656_CHANNEL_0;
		break;
	case 2:
		inf->flags |= RKMODULE_CAMERA_BT656_CHANNEL_0 |
			      RKMODULE_CAMERA_BT656_CHANNEL_1;
		break;
	case 4:
		inf->flags |= RKMODULE_CAMERA_BT656_CHANNELS;
		break;
	default:
		inf->flags |= RKMODULE_CAMERA_BT656_CHANNELS;
	}
}

static long avafpga_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg)
{
	long ret = 0;
	//struct avafpga *avafpga = to_avafpga(sd);
	switch (cmd) {
		/*case RKMODULE_GET_BT656_MBUS_INFO:
		avafpga_get_bt656_module_inf(avafpga,
					       (struct rkmodule_bt656_mbus_info
						*)arg);
		break;*/

	default:
		ret = -ENOTTY;
		break;
	}

	return ret;
}

#ifdef CONFIG_COMPAT
static long avafpga_compat_ioctl32(struct v4l2_subdev *sd,
				   unsigned int cmd, unsigned long arg)
{
	//void __user *up = compat_ptr(arg);
	//struct rkmodule_inf *inf;
	//struct rkmodule_awb_cfg *cfg;
	//int *seq;
	long ret = 0;
	//struct rkmodule_bt656_mbus_info *bt565_inf;
	switch (cmd) {
		/*case RKMODULE_GET_BT656_MBUS_INFO:
		bt565_inf = kzalloc(sizeof(*bt565_inf), GFP_KERNEL);
		if (!bt565_inf) {
			ret = -ENOMEM;
			return ret;
		}

		ret = avafpga_ioctl(sd, cmd, bt565_inf);
		if (!ret) {
			ret = copy_to_user(up, bt565_inf, sizeof(*bt565_inf));
			if (ret)
				ret = -EFAULT;
		}
		kfree(bt565_inf);
		break;*/
	default:
		ret = -ENOIOCTLCMD;
		break;
	}

	return ret;
}
#endif

#define DST_XPOS 0
#define DST_YPOS 0
#define DST_WIDTH 1536 //1920
#define DST_HEIGHT 576 //1080

static int avafpga_get_selection(struct v4l2_subdev *sd,
				struct v4l2_subdev_pad_config *cfg,
				struct v4l2_subdev_selection *sel)
{
	if (sel->target == V4L2_SEL_TGT_CROP_BOUNDS) {
		sel->r.left = DST_XPOS;
		sel->r.top = DST_YPOS;
		sel->r.width = DST_WIDTH;
		sel->r.height = DST_HEIGHT;
		return 0;
	}
	return -EINVAL;
}

static int avafpga_initialize_controls(struct avafpga *avafpga)
{
	int ret;
	struct v4l2_ctrl_handler *handler;
	const struct avafpga_mode *mode;
	u32 h_blank, v_blank;

	handler = &avafpga->ctrl_handler;
	mode = avafpga->cur_mode;

	ret = v4l2_ctrl_handler_init(handler, 2);
	if (ret)
		return ret;
	handler->lock = &avafpga->mutex;

	h_blank = mode->hts_def - mode->width;
	avafpga->hblank_ctrl = v4l2_ctrl_new_std(handler, NULL,
				V4L2_CID_HBLANK, h_blank, h_blank, 1, h_blank);

	v_blank = mode->vts_def - mode->height;
	avafpga->vblank_ctrl = v4l2_ctrl_new_std(handler, NULL,
				V4L2_CID_VBLANK, v_blank, v_blank, 1, v_blank);

	if (handler->error) {
		ret = handler->error;
		dev_err(&avafpga->client->dev,
			"Failed to init controls(%d)\n", ret);
		goto err_free_handler;
	}

	avafpga->subdev.ctrl_handler = handler;

	return 0;

err_free_handler:
	v4l2_ctrl_handler_free(handler);

	return ret;
}
hjk//

static const struct dev_pm_ops avafpga_pm_ops = {
	SET_RUNTIME_PM_OPS(avafpga_runtime_suspend,
			   avafpga_runtime_resume, NULL)
};

#ifdef CONFIG_VIDEO_V4L2_SUBDEV_API
static const struct v4l2_subdev_internal_ops avafpga_internal_ops = {
	.open = avafpga_open,
};
#endif

static const struct v4l2_subdev_core_ops avafpga_core_ops = {
	.s_power = avafpga_s_power,
	//hjk
	.ioctl = avafpga_ioctl,
#ifdef CONFIG_COMPAT
	.compat_ioctl32 = avafpga_compat_ioctl32,
#endif
    //hjk
};

static const struct v4l2_subdev_video_ops avafpga_video_ops = {
	.s_stream = avafpga_s_stream,
	.g_frame_interval = avafpga_g_frame_interval,
	.querystd = avafpga_querystd,
};

static const struct v4l2_subdev_pad_ops avafpga_pad_ops = {
	.enum_mbus_code = avafpga_enum_mbus_code,
	.enum_frame_size = avafpga_enum_frame_sizes,
	.enum_frame_interval = avafpga_enum_frame_interval,
	.get_fmt = avafpga_get_fmt,
	.set_fmt = avafpga_set_fmt,
	.get_selection = avafpga_get_selection,
	.get_mbus_config = avafpga_g_mbus_config,
};

static const struct v4l2_subdev_ops avafpga_subdev_ops = {
	.core	= &avafpga_core_ops,
	.video	= &avafpga_video_ops,
	.pad	= &avafpga_pad_ops,
};


static int avafpga_probe(struct i2c_client *client,
			const struct i2c_device_id *id)
{
	struct device *dev = &client->dev;
	struct avafpga *avafpga;
	struct v4l2_subdev *sd;
	char facing[2];
	int ret;

	dev_info(dev, "driver version: %02x.%02x.%02x",
		DRIVER_VERSION >> 16,
		(DRIVER_VERSION & 0xff00) >> 8,
		DRIVER_VERSION & 0x00ff);

	avafpga = devm_kzalloc(dev, sizeof(*avafpga), GFP_KERNEL);
	if (!avafpga)
		return -ENOMEM;

	avafpga->client = client;
	avafpga->cur_mode = &supported_modes[0];

	avafpga->xvclk = devm_clk_get(dev, "xvclk");
	if (IS_ERR(avafpga->xvclk)) {
		dev_err(dev, "Failed to get xvclk\n");
		return -EINVAL;
	}
	//avafpga->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW);
	//if (IS_ERR(avafpga->reset_gpio))
		//dev_warn(dev, "Failed to get reset-gpios\n");
	//avafpga->pwdn_gpio = devm_gpiod_get(dev, "pwdn", GPIOD_OUT_LOW);
	//if (IS_ERR(avafpga->pwdn_gpio))
		//dev_warn(dev, "Failed to get pwdn-gpios\n");

	mutex_init(&avafpga->mutex);

	sd = &avafpga->subdev;
	v4l2_i2c_subdev_init(sd, client, &avafpga_subdev_ops);

	//hjk
	ret = avafpga_initialize_controls(avafpga);
	if (ret) {
		dev_err(dev, "Failed to initialize controls fpga\n");
		goto err_free_handler;
	}
	//hjk

	ret = __avafpga_power_on(avafpga);
	if (ret)
		goto err_free_handler;

#ifdef CONFIG_VIDEO_V4L2_SUBDEV_API
	sd->internal_ops = &avafpga_internal_ops;
	sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE |
		     V4L2_SUBDEV_FL_HAS_EVENTS;
#endif

#if defined(CONFIG_MEDIA_CONTROLLER)
	avafpga->pad.flags = MEDIA_PAD_FL_SOURCE;
	sd->entity.function = MEDIA_ENT_F_CAM_SENSOR;
	ret = media_entity_pads_init(&sd->entity, 1, &avafpga->pad);
	if (ret < 0)
		goto err_power_off;
#endif

	memset(facing, 0, sizeof(facing));

	if (!sd->dev)
		dev_err(dev, "sd dev is null\n");

	snprintf(sd->name, sizeof(sd->name), "m%02d_%s_%s %s",
		 avafpga->module_index, facing,
		 AVAFPGA_NAME, dev_name(sd->dev));

	ret = v4l2_async_register_subdev_sensor_common(sd);
	if (ret) {
		dev_err(dev, "v4l2 async register subdev failed\n");
		goto err_clean_entity;
	}

	pm_runtime_set_active(dev);
	pm_runtime_enable(dev);
	pm_runtime_idle(dev);

	dev_err(dev, "v4l2 async register subdev sucessfully\n");

	return 0;

err_clean_entity:
#if defined(CONFIG_MEDIA_CONTROLLER)
	media_entity_cleanup(&sd->entity);
#endif
err_power_off:
	__avafpga_power_off(avafpga);
err_free_handler:
	v4l2_ctrl_handler_free(&avafpga->ctrl_handler);

	mutex_destroy(&avafpga->mutex);

	return ret;
}

static int avafpga_remove(struct i2c_client *client)
{
	struct v4l2_subdev *sd = i2c_get_clientdata(client);
	struct avafpga *avafpga = to_avafpga(sd);

	v4l2_async_unregister_subdev(sd);
#if defined(CONFIG_MEDIA_CONTROLLER)
	media_entity_cleanup(&sd->entity);
#endif
	v4l2_ctrl_handler_free(&avafpga->ctrl_handler);
	mutex_destroy(&avafpga->mutex);

	pm_runtime_disable(&client->dev);
	if (!pm_runtime_status_suspended(&client->dev))
		__avafpga_power_off(avafpga);
	pm_runtime_set_suspended(&client->dev);

	return 0;
}

#if IS_ENABLED(CONFIG_OF)
static const struct of_device_id avafpga_of_match[] = {
	{ .compatible = "ava,fpga" },
	{},
};
MODULE_DEVICE_TABLE(of, avafpga_of_match);
#endif

static const struct i2c_device_id avafpga_match_id[] = {
	{"ava,fpga", 0 },
	{},
};

static struct i2c_driver avafpga_i2c_driver = {
	.driver = {
		.name = AVAFPGA_NAME,
		.of_match_table = of_match_ptr(avafpga_of_match),
	},
	.probe		= &avafpga_probe,
	.remove		= &avafpga_remove,
	.id_table	= avafpga_match_id,
};

static int __init sensor_mod_init(void)
{
	return i2c_add_driver(&avafpga_i2c_driver);
}

static void __exit sensor_mod_exit(void)
{
	i2c_del_driver(&avafpga_i2c_driver);
}

device_initcall_sync(sensor_mod_init);
module_exit(sensor_mod_exit);

MODULE_DESCRIPTION("AVA FPGA sensor driver");
MODULE_LICENSE("GPL v2");

编译后会在路径下生成fpga.o,加载进内核模块

具体的调试结果如下

 

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2264914.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

怎么在idea中创建springboot项目

最近想系统学习下springboot&#xff0c;尝试一下全栈路线 从零开始&#xff0c;下面将叙述下如何创建项目 环境 首先确保自己环境没问题 jdkMavenidea 创建springboot项目 1.打开idea&#xff0c;选择file->New->Project 2.选择Spring Initializr->设置JDK->…

springboot476基于vue篮球联盟管理系统(论文+源码)_kaic

摘 要 如今社会上各行各业&#xff0c;都喜欢用自己行业的专属软件工作&#xff0c;互联网发展到这个时候&#xff0c;人们已经发现离不开了互联网。新技术的产生&#xff0c;往往能解决一些老技术的弊端问题。因为传统篮球联盟管理系统信息管理难度大&#xff0c;容错率低&am…

蓝桥杯嵌入式备赛教程(1、led,2、lcd,3、key)

一、工程模版创建流程 第一步 创建新项目 第二步 选择型号和管脚封装 第三步 RCC使能 外部时钟&#xff0c;高速外部时钟 第四步晶振时钟配置 由数据手册7.1可知外部晶振频率为24MHz 最后一项设置为80 按下回车他会自动配置时钟 第五步&#xff0c;如果不勾选可能程序只会…

步进电机位置速度双环控制实现

步进电机位置速度双环控制实现 野火stm32电机教学 提高部分-第11讲 步进电机位置速度双环控制实现(1)_哔哩哔哩_bilibili PID模型 位置环作为外环,速度环作为内环。设定目标位置和实际转轴位置的位置偏差,经过位置PID获得位置期望,然后讲位置期望(位置变化反映了转轴的速…

devops和ICCID简介

Devops DevOps&#xff08;Development 和 Operations 的组合&#xff09;是一种软件开发和 IT 运维的哲学&#xff0c;旨在促进开发、技术运营和质量保障&#xff08;QA&#xff09;部门之间的沟通、协作与整合。它强调自动化流程&#xff0c;持续集成&#xff08;CI&#xf…

Apache RocketMQ 5.1.3安装部署文档

官方文档不好使&#xff0c;可以说是一坨… 关键词&#xff1a;Apache RocketMQ 5.0 JDK 17 废话少说&#xff0c;开整。 1.版本 官网地址&#xff0c;版本如下。 https://rocketmq.apache.org/download2.配置文件 2.1namesrv端口 在ROCKETMQ_HOME/conf下 新增namesrv.pro…

数据结构:算法篇:快速排序;直接插入排序

目录 快速排序 直接插入排序 改良版冒泡排序 快速排序 理解&#xff1a; ①从待排序元素中选定一个基准元素&#xff1b; ②以基准元素将数据分为两部分&#xff1a;&#xff08;可以将&#xff1a;大于基准元素放左&#xff0c;小于基准元素放右&#xff09; ③对左半部分…

运维工程师面试系统监控与优化自动化与脚本云计算的理解虚拟化技术的优点和缺点

前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c; 忍不住分享一下给大家。点击跳转到网站 学习总结 1、掌握 JAVA入门到进阶知识(持续写作中……&#xff09; 2、学会Oracle数据库入门到入土用法(创作中……&#xff09; 3、手把…

如何打造用户友好的维护页面:6个创意提升WordPress网站体验

在网站运营中&#xff0c;无论是个人博主还是大型企业网站的管理员&#xff0c;难免会遇到需要维护的情况。无论是服务器迁移、插件更新&#xff0c;还是突发的技术故障&#xff0c;都可能导致网站短暂无法访问。这时&#xff0c;设计维护页面能很好的缓解用户的不满&#xff0…

postman读取文件执行

要从文件获取的变量 text 在pre-request 中写从文件获取数据的脚本。脚本实现了&#xff0c;设置了text默认值&#xff0c;从文件读取text列&#xff0c;将text存入环境变量 //获取text参数 var text "济南天气"; if(data.text){ text data.text } pm.environment.…

37. Three.js案例-绘制部分球体

37. Three.js案例-绘制部分球体 实现效果 知识点 WebGLRenderer WebGLRenderer 是Three.js中的一个渲染器类&#xff0c;用于将3D场景渲染到网页上。 构造器 WebGLRenderer( parameters : Object ) 参数类型描述parametersObject渲染器的配置参数&#xff0c;可选。 常用…

【Rust自学】4.4. 引用与借用

4.4.0 写在正文之前 这一节的内容其实就相当于C的智能指针移动语义在编译器层面做了一些约束。Rust中引用的写法通过编译器的约束写成了C中最理想、最规范的指针写法。所以学过C的人对这一章肯定会非常熟悉。 喜欢的话别忘了点赞、收藏加关注哦&#xff08;加关注即可阅读全文…

电脑使用CDR时弹出错误“计算机丢失mfc140u.dll”是什么原因?“计算机丢失mfc140u.dll”要怎么解决?

电脑使用CDR时弹出“计算机丢失mfc140u.dll”错误&#xff1a;原因与解决方案 在日常电脑使用中&#xff0c;我们时常会遇到各种系统报错和文件丢失问题。特别是当我们使用某些特定软件&#xff0c;如CorelDRAW&#xff08;简称CDR&#xff09;时&#xff0c;可能会遇到“计算…

C# 基本信息介绍

总目录 前言 对 C# 做一个基本信息介绍&#xff0c;让我们对 C# 有个基本的认识。 在进行本文的阅读之前&#xff0c;可以瞧瞧 编程基础知识简述 简单的入个门儿。 一、C# 1. C# 概述 C#是由微软公司发布的一种由C和C衍生出来的面向对象的编程语言。 2. C# 详细介绍 C#&am…

『Linux学习笔记』FRPC 详细介绍及配置解析!

『Linux学习笔记』FRPC 详细介绍及配置解析&#xff01; 文章目录 一. FRPC 详细介绍及配置解析FRPC 的主要功能FRPC 配置文件解析全局配置代理配置第一个代理服务第二个代理服务 配置文件整体工作流程常见配置项说明FRPC 的使用步骤注意事项结论 二. 参考文献 一. FRPC 详细介…

WPS工具栏灰色怎么办

WPS离线不登录&#xff0c;开启工具栏等相关功能 当你在使用WPS的过程中&#xff0c;若因网络问题或其他特殊原因&#xff0c;导致无法登录使用WPS时&#xff0c;可根据以下步骤开启离线兼容模式&#xff0c;开启此模式后&#xff0c;可在未登录的状态下&#xff0c;激活并使用…

【微信小程序】2|轮播图 | 我的咖啡店-综合实训

轮播图 引言 在微信小程序中&#xff0c;轮播图是一种常见的用户界面元素&#xff0c;用于展示广告、产品图片等。本文将通过“我的咖啡店”小程序的轮播图实现&#xff0c;详细介绍如何在微信小程序中创建和管理轮播图。 轮播图数据准备 首先&#xff0c;在home.js文件中&a…

JavaEE进阶--mybatis使用测试日志参数传递浏览器访问

文章目录 1.项目创建2.mybatis的使用2.1创建初始页面2.2补充yml文件2.3navicate表2.4用户类的编写2.5查询接口2.6运行测试 3.细节说明3.1java开发规范3.2关于包3.3持久层代码 4.测试文件4.1如何生成4.2生成位置4.3补充方法 5.配置mybatis日志6.参数传递6.1单个参数6.2多个参数 …

IDEA用jformdesigner插件做管理系统MVC架构

在 IntelliJ IDEA 中结合 JFormDesigner 插件&#xff0c;通过 Swing 框架实现一个管理系统的 MVC 架构是一种经典的开发方式。以下是具体的步骤和实现思路&#xff0c;包含从项目创建到 MVC 架构的核心代码实现。 1. 项目结构设计 为了清晰的 MVC 分层架构&#xff0c;建议按…

学习Cookie 提升

目录 Cookie 的覆盖​​​​​​​ Cookie下的path 特点 设置Cookie 路径 实例 Cookie的最大存活时间 设置Cookie 存活时间 实例 Cookie 和session的区别 和联系 Cookie 的覆盖 当 key相同 和只要path的上级目录的路径相同&#xff0c;就可以被替换掉 value 值 如下图…