采用简单的驱动进行分析,方便:
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, ¬ifier_list, list) {

最低0.47元/天 解锁文章

被折叠的 条评论
为什么被折叠?



