(三)v4l2: 根据应用层顺序,查看驱动

采用简单的驱动进行分析,方便:

ov9650.c    D:\source_code\linux-4.19.11\drivers\media\i2c
 

第一步

static struct i2c_driver ov965x_i2c_driver = {
	.driver = {
		.name	= DRIVER_NAME,
		.of_match_table = of_match_ptr(ov965x_of_match),
	},
	.probe		= ov965x_probe,
	.remove		= ov965x_remove,
	.id_table	= ov965x_id,
};

module_i2c_driver(ov965x_i2c_driver);

第二布  设置设备树 或者 id_table

static const struct i2c_device_id ov965x_id[] = {
	{ "OV9650", 0 },
	{ "OV9652", 0 },
	{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(i2c, ov965x_id);

#if IS_ENABLED(CONFIG_OF)
static const struct of_device_id ov965x_of_match[] = {
	{ .compatible = "ovti,ov9650", },
	{ .compatible = "ovti,ov9652", },
	{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, ov965x_of_match);
#endif

m5602_ov9650.h    D:\source_code\linux-4.19.11\drivers\media\usb\gspca\m5602
 

/* Kernel module parameters */
extern int force_sensor;
extern bool dump_sensor;

int ov9650_probe(struct sd *sd);
int ov9650_init(struct sd *sd);
int ov9650_init_controls(struct sd *sd);
int ov9650_start(struct sd *sd);
int ov9650_stop(struct sd *sd);
void ov9650_disconnect(struct sd *sd);

static const struct m5602_sensor ov9650 = {
	.name = "OV9650",
	.i2c_slave_id = 0x60,
	.i2c_regW = 1,
	.probe = ov9650_probe,
	.init = ov9650_init,
	.init_controls = ov9650_init_controls,
	.start = ov9650_start,
	.stop = ov9650_stop,
	.disconnect = ov9650_disconnect,
};

m5602_ov9650.c    D:\source_code\linux-4.19.11\drivers\media\usb\gspca\m5602
 


第三步:  执行probe函数

struct ov965x {
	struct v4l2_subdev sd;
	struct media_pad pad;
	enum v4l2_mbus_type bus_type;
	struct gpio_desc *gpios[NUM_GPIOS];
	/* External master clock frequency */
	unsigned long mclk_frequency;
	struct clk *clk;

	/* Protects the struct fields below */
	struct mutex lock;

	struct i2c_client *client;

	/* Exposure row interval in us */
	unsigned int exp_row_interval;

	unsigned short id;
	const struct ov965x_framesize *frame_size;
	/* YUYV sequence (pixel format) control register */
	u8 tslb_reg;
	struct v4l2_mbus_framefmt format;

	struct ov965x_ctrls ctrls;
	/* Pointer to frame rate control data structure */
	const struct ov965x_interval *fiv;

	int streaming;
	int power;

	u8 apply_frame_fmt;
};


struct ov9650_platform_data {
	unsigned long mclk_frequency;
	int gpio_pwdn;
	int gpio_reset;
};


static int ov965x_probe(struct i2c_client *client,
			const struct i2c_device_id *id) :
    const struct ov9650_platform_data *pdata = client->dev.platform_data;
	struct v4l2_subdev *sd;
	struct ov965x *ov965x;

    ov965x = devm_kzalloc(&client->dev, sizeof(*ov965x), GFP_KERNEL);

    ov965x->client = client;

    if (pdata) {
		if (pdata->mclk_frequency == 0) {
			dev_err(&client->dev, "MCLK frequency not specified\n");
			return -EINVAL;
		}
		ov965x->mclk_frequency = pdata->mclk_frequency;  //初始化时钟

		ret = ov965x_configure_gpios_pdata(ov965x, pdata); //设置gpio 看后面
		if (ret < 0)
			return ret;
	} else if (dev_fwnode(&client->dev)) {
		ov965x->clk = devm_clk_get(&ov965x->client->dev, NULL);
		if (IS_ERR(ov965x->clk))
			return PTR_ERR(ov965x->clk);
		ov965x->mclk_frequency = clk_get_rate(ov965x->clk);

		ret = ov965x_configure_gpios(ov965x);
		if (ret < 0)
			return ret;
	} else {
		dev_err(&client->dev,
			"Neither platform data nor device property specified\n");

		return -EINVAL;
	}


    // 以上只是用来初始化 时钟等。
    sd = &ov965x->sd;
	v4l2_i2c_subdev_init(sd, client, &ov965x_subdev_ops);
            static const struct v4l2_subdev_ops ov965x_subdev_ops = {
	                .core = &ov965x_core_ops,
	                .pad = &ov965x_pad_ops,
	                .video = &ov965x_video_ops,
                };

	strlcpy(sd->name, DRIVER_NAME, sizeof(sd->name));

	sd->internal_ops = &ov965x_sd_internal_ops;
                static const struct v4l2_subdev_internal_ops ov965x_sd_internal_ops = {
	                 .open = ov965x_open,
                };
	sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE |
		     V4L2_SUBDEV_FL_HAS_EVENTS;

    ret = ov965x_initialize_controls(ov965x);   // 很重要 看下面

    ov965x_get_default_format(&ov965x->format);   // 初始化 format

    ov965x->frame_size = &ov965x_framesizes[0];
	ov965x->fiv = &ov965x_intervals[0]; 

    ret = ov965x_detect_sensor(sd);

    /* Update exposure time min/max to match frame format */
	ov965x_update_exposure_ctrl(ov965x);

	ret = v4l2_async_register_subdev(sd);
        list_for_each_entry(notifier, &notifier_list, list) {
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值