I’ve built a V4L2 driver based on kernel_source/drivers/media/i2c/ov5693.c
I attempted to make the module loadable by adding an i2c_new_device call to the __init function which correctly detects the device and calls probe. But a /dev/video* device is not being created. What do I need to do to make that happen?
Here are the contents of my __init function:
static struct i2c_client *daxc02_client;
static int __init daxc02_module_init(void)
{
int retval;
struct i2c_adapter *adapter;
pr_info("daxc02: initializing driver.\n");
retval = i2c_add_driver(&daxc02_i2c_driver);
if(retval) return retval;
adapter = i2c_get_adapter(6);
if (!adapter) return -EINVAL;
daxc02_client = i2c_new_device(adapter, &daxc02_camera_i2c_device);
if (!daxc02_client) return -EINVAL;
return 0;
}
And my probe:
static int daxc02_probe(struct i2c_client *client, const struct i2c_device_id *id)
{
struct camera_common_data *common_data;
struct mt9m021_platform_data *mt9m021_pdata = client->dev.platform_data;
struct daxc02 *priv;
struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
char debugfs_name[10];
int err;
pr_info("daxc02: probing v4l2 sensor.\n");
common_data = devm_kzalloc(&client->dev, sizeof(struct camera_common_data), GFP_KERNEL);
if (!common_data) return -ENOMEM;
priv = devm_kzalloc(&client->dev,
sizeof(struct daxc02) + sizeof(struct v4l2_ctrl *) *
ARRAY_SIZE(ctrl_config_list),
GFP_KERNEL);
if (!priv) return -ENOMEM;
priv->pdata = daxc02_parse_dt(client);
if (!priv->pdata)
{
dev_err(&client->dev, "unable to get platform data\n");
return -EFAULT;
}
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WORD_DATA))
{
dev_warn(&client->dev, "i2c-adapter doesn't support I2C_FUNC_SMBUS_WORD\n");
return -EIO;
}
common_data->numlanes = 4;
common_data->csi_port = 2;
common_data->ops = &daxc02_common_ops;
common_data->ctrl_handler = &priv->ctrl_handler;
common_data->i2c_client = client;
common_data->power = &priv->power;
common_data->ctrls = priv->ctrls;
common_data->priv = (void *)priv;
common_data->numctrls = ARRAY_SIZE(ctrl_config_list);
common_data->def_width = MT9M021_PIXEL_ARRAY_WIDTH;
common_data->def_height = MT9M021_PIXEL_ARRAY_HEIGHT;
common_data->fmt_width = common_data->def_width;
common_data->fmt_height = common_data->def_height;
common_data->def_clk_freq = MT9M021_TARGET_FREQ;
priv->i2c_client = client;
priv->s_data = common_data;
priv->subdev = &common_data->subdev;
priv->subdev->dev = &client->dev;
priv->s_data->dev = &client->dev;
priv->subdev->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
priv->mt9m021_pdata = mt9m021_pdata;
priv->crop.width = MT9M021_WINDOW_WIDTH_MAX;
priv->crop.height = MT9M021_WINDOW_HEIGHT_MAX;
priv->crop.left = MT9M021_COLUMN_START_DEF;
priv->crop.top = MT9M021_ROW_START_DEF;
priv->format.code = V4L2_MBUS_FMT_SGRBG12_1X12;
priv->format.width = MT9M021_WINDOW_WIDTH_DEF;
priv->format.height = MT9M021_WINDOW_HEIGHT_DEF;
priv->format.field = V4L2_FIELD_NONE;
priv->format.colorspace = V4L2_COLORSPACE_SRGB;
err = daxc02_power_get(priv);
if (err) return err;
sprintf(debugfs_name, "daxc02_%c", common_data->csi_port + 'a');
dev_dbg(&client->dev, "%s: name %s\n", __func__, debugfs_name);
camera_common_create_debugfs(common_data, debugfs_name);
v4l2_i2c_subdev_init(priv->subdev, client, &daxc02_subdev_ops);
err = daxc02_ctrls_init(priv);
if (err) return err;
priv->subdev->internal_ops = &mt9m021_subdev_internal_ops;
priv->subdev->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE |
V4L2_SUBDEV_FL_HAS_EVENTS;
#if defined(CONFIG_MEDIA_CONTROLLER)
priv->pad.flags = MEDIA_PAD_FL_SOURCE;
priv->subdev->entity.type = MEDIA_ENT_T_V4L2_SUBDEV_SENSOR;
priv->subdev->entity.ops = &daxc02_media_ops;
err = media_entity_init(&priv->subdev->entity, 1, &priv->pad, 0);
if (err < 0)
{
dev_err(&client->dev, "unable to init media entity\n");
return err;
}
#endif
err = v4l2_async_register_subdev(priv->subdev);
if (err) return err;
pr_info("daxc02: probe successful.\n");
return 0;
}