Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

media: i2c: ov5640: add Rockchip-specific support #316

Merged
merged 1 commit into from
Jan 16, 2025
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
98 changes: 94 additions & 4 deletions drivers/media/i2c/ov5640.c
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,19 @@
#include <linux/regulator/consumer.h>
#include <linux/slab.h>
#include <linux/types.h>
#include <linux/version.h>
#include <linux/rk-camera-module.h>
#include <media/v4l2-async.h>
#include <media/v4l2-ctrls.h>
#include <media/v4l2-device.h>
#include <media/v4l2-event.h>
#include <media/v4l2-fwnode.h>
#include <media/v4l2-subdev.h>

#define DRIVER_VERSION KERNEL_VERSION(0, 0x01, 0x1)

#define OV5640_LANES 2

/* min/typical/max system clock (xclk) frequencies */
#define OV5640_XCLK_MIN 6000000
#define OV5640_XCLK_MAX 54000000
Expand Down Expand Up @@ -119,6 +125,8 @@
#define OV5640_REG_SDE_CTRL5 0x5585
#define OV5640_REG_AVG_READOUT 0x56a1

#define OV5640_NAME "ov5640"

enum ov5640_mode_id {
OV5640_MODE_QQVGA_160_120 = 0,
OV5640_MODE_QCIF_176_144,
Expand Down Expand Up @@ -465,6 +473,11 @@ struct ov5640_dev {

bool pending_mode_change;
bool streaming;

u32 module_index;
const char *module_facing;
const char *module_name;
const char *len_name;
};

static inline struct ov5640_dev *to_ov5640_dev(struct v4l2_subdev *sd)
Expand Down Expand Up @@ -3747,16 +3760,60 @@ static int ov5640_init_cfg(struct v4l2_subdev *sd,
return 0;
}

static void ov5640_get_module_inf(struct ov5640_dev *sensor,
struct rkmodule_inf *inf)
{
memset(inf, 0, sizeof(*inf));
strscpy(inf->base.sensor, OV5640_NAME, sizeof(inf->base.sensor));
strscpy(inf->base.module, sensor->module_name,
sizeof(inf->base.module));
strscpy(inf->base.lens, sensor->len_name, sizeof(inf->base.lens));
}

static long ov5640_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg)
{
struct ov5640_dev *sensor = to_ov5640_dev(sd);
long ret = 0;

switch (cmd) {
case RKMODULE_GET_MODULE_INFO:
ov5640_get_module_inf(sensor, (struct rkmodule_inf *)arg);
break;
default:
ret = -ENOIOCTLCMD;
break;
}

return ret;
}

static int ov5640_g_mbus_config(struct v4l2_subdev *sd, unsigned int pad_id,
struct v4l2_mbus_config *config)
{
config->type = V4L2_MBUS_CSI2_DPHY;
config->bus.mipi_csi2.num_data_lanes = OV5640_LANES;

return 0;
}

static int ov5640_g_input_status(struct v4l2_subdev *sd, u32 *status)
{
*status = 0;
return 0;
}

static const struct v4l2_subdev_core_ops ov5640_core_ops = {
.log_status = v4l2_ctrl_subdev_log_status,
.subscribe_event = v4l2_ctrl_subdev_subscribe_event,
.unsubscribe_event = v4l2_event_subdev_unsubscribe,
.ioctl = ov5640_ioctl,
};

static const struct v4l2_subdev_video_ops ov5640_video_ops = {
.g_frame_interval = ov5640_g_frame_interval,
.s_frame_interval = ov5640_s_frame_interval,
.s_stream = ov5640_s_stream,
.g_input_status = ov5640_g_input_status,
};

static const struct v4l2_subdev_pad_ops ov5640_pad_ops = {
Expand All @@ -3767,6 +3824,7 @@ static const struct v4l2_subdev_pad_ops ov5640_pad_ops = {
.get_selection = ov5640_get_selection,
.enum_frame_size = ov5640_enum_frame_size,
.enum_frame_interval = ov5640_enum_frame_interval,
.get_mbus_config = ov5640_g_mbus_config,
};

static const struct v4l2_subdev_ops ov5640_subdev_ops = {
Expand Down Expand Up @@ -3809,13 +3867,22 @@ static int ov5640_check_chip_id(struct ov5640_dev *sensor)
return 0;
}

static int ov5640_probe(struct i2c_client *client)
static int ov5640_probe(struct i2c_client *client,
const struct i2c_device_id *did)
{
struct device *dev = &client->dev;
struct device_node *np = dev->of_node;
struct fwnode_handle *endpoint;
struct ov5640_dev *sensor;
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);

sensor = devm_kzalloc(dev, sizeof(*sensor), GFP_KERNEL);
if (!sensor)
return -ENOMEM;
Expand Down Expand Up @@ -3859,6 +3926,19 @@ static int ov5640_probe(struct i2c_client *client)
return -EINVAL;
}

ret = of_property_read_u32(np, RKMODULE_CAMERA_MODULE_INDEX,
&sensor->module_index);
ret |= of_property_read_string(np, RKMODULE_CAMERA_MODULE_FACING,
&sensor->module_facing);
ret |= of_property_read_string(np, RKMODULE_CAMERA_MODULE_NAME,
&sensor->module_name);
ret |= of_property_read_string(np, RKMODULE_CAMERA_LENS_NAME,
&sensor->len_name);
if (ret) {
dev_err(dev, "could not get module information!\n");
return -EINVAL;
}

/* get system clock (xclk) */
sensor->xclk = devm_clk_get(dev, "xclk");
if (IS_ERR(sensor->xclk)) {
Expand Down Expand Up @@ -3886,7 +3966,8 @@ static int ov5640_probe(struct i2c_client *client)
if (IS_ERR(sensor->reset_gpio))
return PTR_ERR(sensor->reset_gpio);

v4l2_i2c_subdev_init(&sensor->sd, client, &ov5640_subdev_ops);
sd = &sensor->sd;
v4l2_i2c_subdev_init(sd, client, &ov5640_subdev_ops);

sensor->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE |
V4L2_SUBDEV_FL_HAS_EVENTS;
Expand Down Expand Up @@ -3920,6 +4001,15 @@ static int ov5640_probe(struct i2c_client *client)
if (ret)
goto err_pm_runtime;

memset(facing, 0, sizeof(facing));
if (strcmp(sensor->module_facing, "back") == 0)
facing[0] = 'b';
else
facing[0] = 'f';

snprintf(sd->name, sizeof(sd->name), "m%02d_%s_%s %s",
sensor->module_index, facing,
OV5640_NAME, dev_name(sd->dev));
ret = v4l2_async_register_subdev_sensor(&sensor->sd);
if (ret)
goto err_pm_runtime;
Expand Down Expand Up @@ -3977,12 +4067,12 @@ MODULE_DEVICE_TABLE(of, ov5640_dt_ids);

static struct i2c_driver ov5640_i2c_driver = {
.driver = {
.name = "ov5640",
.name = OV5640_NAME,
.of_match_table = ov5640_dt_ids,
.pm = &ov5640_pm_ops,
},
.id_table = ov5640_id,
.probe_new = ov5640_probe,
.probe = ov5640_probe,
.remove = ov5640_remove,
};

Expand Down
Loading