Quantcast
Channel: Raspberry Pi Forums
Viewing all articles
Browse latest Browse all 3843

Interfacing (DSI, CSI, I2C, etc.) • Re: MIPI-CSI2 camera having ISP

$
0
0
6by9, Thank you for your reply.

You advised me to perform a simple test with V4L2 and informed me that reviewing the driver source code would be necessary to resolve the issue. Therefore, I am providing the driver source code and the logs from the V4L2 command for your review.

Below is our driver source code

Code:

// SPDX-License-Identifier: GPL-2.0/* * A V4L2 driver for Pixelplus PX6130 cameras. * * Based on Samsung S5K6AAFX SXGA 1/6" 1.3M CMOS Image Sensor driver * Copyright (C) 2011 Sylwester Nawrocki <s.nawrocki@samsung.com> * * Based on Pixelplus OV5647 Camera Driver * Copyright (C) 2006-7 Jonathan Corbet <corbet@lwn.net> * * Copyright (C) 2016, Synopsys, Inc. */#include <linux/clk.h>#include <linux/delay.h>#include <linux/gpio/consumer.h>#include <linux/i2c.h>#include <linux/init.h>#include <linux/io.h>#include <linux/module.h>#include <linux/of_graph.h>#include <linux/pm_runtime.h>#include <linux/regulator/consumer.h>#include <linux/slab.h>#include <linux/videodev2.h>#include <media/v4l2-ctrls.h>#include <media/v4l2-device.h>#include <media/v4l2-event.h>#include <media/v4l2-fwnode.h>#include <media/v4l2-image-sizes.h>#include <media/v4l2-mediabus.h>#define MIPI_CTRL00_CLOCK_LANE_GATEBIT(5)#define MIPI_CTRL00_LINE_SYNC_ENABLEBIT(4)#define MIPI_CTRL00_BUS_IDLEBIT(2)#define MIPI_CTRL00_CLOCK_LANE_DISABLEBIT(0)#define PX6130_NATIVE_WIDTH1280U#define PX6130_NATIVE_HEIGHT960U#define PX6130_PIXEL_ARRAY_LEFT0U#define PX6130_PIXEL_ARRAY_TOP0U#define PX6130_PIXEL_ARRAY_WIDTH1280U#define PX6130_PIXEL_ARRAY_HEIGHT960U#define PX6130_VBLANK_MIN0#define PX6130_VTS_MAX32767/* regulator supplies */static const char * const PX6130_supply_names[] = {"avdd",/* Analog power */"dovdd",/* Digital I/O power */"dvdd",/* Digital core power */};#define PX6130_NUM_SUPPLIES ARRAY_SIZE(PX6130_supply_names)struct regval_list {u16 addr;u8 data;};struct PX6130_mode {struct v4l2_mbus_framefmtformat;struct v4l2_rectcrop;u64pixel_rate;inthts;intvts;const struct regval_list*reg_list;unsigned intnum_regs;};struct PX6130 {struct v4l2_subdevsd;struct media_padpad;struct mutexlock;struct clk*xclk;struct gpio_desc*pwdn;struct regulator_bulk_data supplies[PX6130_NUM_SUPPLIES];boolclock_ncont;struct v4l2_ctrl_handlerctrls;const struct PX6130_mode*mode;struct v4l2_ctrl*pixel_rate;struct v4l2_ctrl*hblank;struct v4l2_ctrl*vblank;struct v4l2_ctrl*exposure;struct v4l2_ctrl*hflip;struct v4l2_ctrl*vflip;boolstreaming;};static inline struct PX6130 *to_sensor(struct v4l2_subdev *sd){return container_of(sd, struct PX6130, sd);}static struct regval_list PX6130_1280x960_YUV422[] = {{ 0x0000, 0x00 },{ 0x0001, 0x01 },};static const struct PX6130_mode PX6130_modes[] = {{.format = { .code = MEDIA_BUS_FMT_YUYV8_2X8,.colorspace= V4L2_COLORSPACE_RAW,.field= V4L2_FIELD_NONE,.width= 1280,.height= 960},.crop = {.left= 0,.top= 0,.width= 1280,.height= 960},.pixel_rate= 87500000,.hts= 1280,.vts= 960 + PX6130_VBLANK_MIN,.reg_list= PX6130_1280x960_YUV422,.num_regs= ARRAY_SIZE(PX6130_1280x960_YUV422)},};#define PX6130_DEFAULT_MODE (&PX6130_modes[0])#define PX6130_DEFAULT_FORMAT (PX6130_modes[0].format)static int PX6130_write16(struct v4l2_subdev *sd, u16 reg, u16 val){unsigned char data[4] = { reg >> 8, reg & 0xff, val >> 8, val & 0xff};struct i2c_client *client = v4l2_get_subdevdata(sd);int ret;ret = i2c_master_send(client, data, 4);/* * Writing the wrong number of bytes also needs to be flagged as an * error. Success needs to produce a 0 return code. */if (ret == 4) {ret = 0;} else {dev_dbg(&client->dev, "%s: i2c write error, reg: %x\n",__func__, reg);return ret;}return 0;}static int PX6130_write(struct v4l2_subdev *sd, u16 reg, u8 val){unsigned char data[3] = { reg >> 8, reg & 0xff, val};struct i2c_client *client = v4l2_get_subdevdata(sd);int ret;ret = i2c_master_send(client, data, 3);/* * Writing the wrong number of bytes also needs to be flagged as an * error. Success needs to produce a 0 return code. */if (ret == 3) {ret = 0;} else {dev_dbg(&client->dev, "%s: i2c write error, reg: %x\n",__func__, reg);if (ret >= 0)ret = -EINVAL;}return 0;}static int PX6130_read(struct v4l2_subdev *sd, u16 reg, u8 *val){struct i2c_client *client = v4l2_get_subdevdata(sd);u8 buf[2] = { reg >> 8, reg & 0xff };struct i2c_msg msg[2];int ret;msg[0].addr = client->addr;msg[0].flags = client->flags;msg[0].buf = buf;msg[0].len = sizeof(buf);msg[1].addr = client->addr;msg[1].flags = client->flags | I2C_M_RD;msg[1].buf = buf;msg[1].len = 1;ret = i2c_transfer(client->adapter, msg, 2);if (ret != 2) {dev_err(&client->dev, "%s: i2c read error, reg: %x = %d\n",__func__, reg, ret);return ret >= 0 ? -EINVAL : ret;}*val = buf[0];return 0;}static int PX6130_write_array(struct v4l2_subdev *sd,      const struct regval_list *regs, int array_size){int i, ret;for (i = 0; i < array_size; i++) {ret = PX6130_write(sd, regs[i].addr, regs[i].data);if (ret < 0)return ret;}return 0;}static int PX6130_set_virtual_channel(struct v4l2_subdev *sd, int channel){u8 channel_id = 0;int ret = 0;channel_id &= ~(3 << 6);return ret;}static int PX6130_set_mode(struct v4l2_subdev *sd){struct i2c_client *client = v4l2_get_subdevdata(sd);struct PX6130 *sensor = to_sensor(sd);u8 resetval, rdval;int ret;ret = PX6130_set_virtual_channel(sd, 0);if (ret < 0)return ret;return 0;}static int PX6130_stream_on(struct v4l2_subdev *sd){struct i2c_client *client = v4l2_get_subdevdata(sd);struct PX6130 *sensor = to_sensor(sd);u8 val = MIPI_CTRL00_BUS_IDLE;int ret;ret = PX6130_set_mode(sd);if (ret) {dev_err(&client->dev, "Failed to program sensor mode: %d\n", ret);return ret;}/* Apply customized values from user when stream starts. */ret =  __v4l2_ctrl_handler_setup(sd->ctrl_handler);dev_dbg(&client->dev, "%s(%d): ret %d\n", __func__, __LINE__, ret);if (ret)return ret;return 0;}static int PX6130_stream_off(struct v4l2_subdev *sd){struct i2c_client *client = v4l2_get_subdevdata(sd);int ret;dev_dbg(&client->dev, "%s(%d)\n", __func__, __LINE__);return 0;}static int PX6130_power_on(struct device *dev){struct PX6130 *sensor = dev_get_drvdata(dev);int ret;dev_dbg(dev, "PX6130 power on\n");return 0;error_clk_disable:clk_disable_unprepare(sensor->xclk);error_pwdn:gpiod_set_value_cansleep(sensor->pwdn, 1);regulator_bulk_disable(PX6130_NUM_SUPPLIES, sensor->supplies);return ret;}static int PX6130_power_off(struct device *dev){struct PX6130 *sensor = dev_get_drvdata(dev);u8 rdval;int ret;dev_dbg(dev, "PX6130 power off\n");return 0;}#ifdef CONFIG_VIDEO_ADV_DEBUGstatic int PX6130_sensor_get_register(struct v4l2_subdev *sd,      struct v4l2_dbg_register *reg){pr_info("%s(%d): %d\n", __func__, __LINE__, which);int ret;u8 val;ret = PX6130_read(sd, reg->reg & 0xff, &val);if (ret < 0)return ret;reg->val = val;reg->size = 1;return 0;}static int PX6130_sensor_set_register(struct v4l2_subdev *sd,      const struct v4l2_dbg_register *reg){pr_info("%s(%d): %d\n", __func__, __LINE__, which);return PX6130_write(sd, reg->reg & 0xff, reg->val & 0xff);}#endifstatic const struct v4l2_rect *__PX6130_get_pad_crop(struct PX6130 *PX6130,      struct v4l2_subdev_state *sd_state,      unsigned int pad, enum v4l2_subdev_format_whence which){pr_info("%s(%d): %d\n", __func__, __LINE__, which);switch (which) {case V4L2_SUBDEV_FORMAT_TRY:return v4l2_subdev_get_try_crop(&PX6130->sd, sd_state, pad);case V4L2_SUBDEV_FORMAT_ACTIVE:return &PX6130->mode->crop;}return NULL;}static int PX6130_s_stream(struct v4l2_subdev *sd, int enable){struct i2c_client *client = v4l2_get_subdevdata(sd);struct PX6130 *sensor = to_sensor(sd);int ret;dev_info(&client->dev, "dbg_info: %s, line: %d\n", __func__, __LINE__);mutex_lock(&sensor->lock);if (sensor->streaming == enable) {mutex_unlock(&sensor->lock);dev_info(&client->dev, "dbg_info: %s, line: %d\n", __func__, __LINE__);return 0;}if (enable) {ret = pm_runtime_resume_and_get(&client->dev);if (ret < 0)goto error_unlock;ret = PX6130_stream_on(sd);if (ret < 0) {dev_err(&client->dev, "stream start failed: %d\n", ret);goto error_pm;}} else {ret = PX6130_stream_off(sd);if (ret < 0) {dev_err(&client->dev, "stream stop failed: %d\n", ret);goto error_pm;}pm_runtime_put(&client->dev);}sensor->streaming = enable;mutex_unlock(&sensor->lock);return 0;error_pm:pm_runtime_put(&client->dev);error_unlock:mutex_unlock(&sensor->lock);return ret;}static const struct v4l2_subdev_video_ops PX6130_subdev_video_ops = {.s_stream =PX6130_s_stream,};/* This function returns the mbus code for the current settings of the   HFLIP and VFLIP controls. */static u32 PX6130_get_mbus_code(struct v4l2_subdev *sd){struct PX6130 *sensor = to_sensor(sd);/* The control values are only 0 or 1. */struct i2c_client *client = v4l2_get_subdevdata(sd);int index =  sensor->hflip->val | (sensor->vflip->val << 1);static const u32 codes[4] = {MEDIA_BUS_FMT_YUYV8_2X8,MEDIA_BUS_FMT_UYVY8_2X8,MEDIA_BUS_FMT_YVYU8_2X8,MEDIA_BUS_FMT_VYUY8_2X8};return codes[index];}static int PX6130_enum_mbus_code(struct v4l2_subdev *sd, struct v4l2_subdev_state *sd_state, struct v4l2_subdev_mbus_code_enum *code){if (code->index > 0)return -EINVAL;code->code = PX6130_get_mbus_code(sd);return 0;}static int PX6130_enum_frame_size(struct v4l2_subdev *sd,  struct v4l2_subdev_state *sd_state,  struct v4l2_subdev_frame_size_enum *fse){const struct v4l2_mbus_framefmt *fmt;struct i2c_client *client = v4l2_get_subdevdata(sd);dev_info(&client->dev, "dbg_info: %s(%d), state:%x, fse:%x\n",__func__, __LINE__, sd_state, fse);if (fse->code != PX6130_get_mbus_code(sd) ||    fse->index >= ARRAY_SIZE(PX6130_modes)){dev_info(&client->dev, "Err!! code: %d, index: %d, mbus: %d, size : %d\n",fse->code, fse->index, PX6130_get_mbus_code(sd), ARRAY_SIZE(PX6130_modes));return -EINVAL;}fmt = &PX6130_modes[fse->index].format;dev_info(&client->dev, "dbg_info: %s(%d) (%d, %d)\n",__func__, __LINE__, fmt->width, fmt->height);fse->min_width = fmt->width;fse->max_width = fmt->width;fse->min_height = fmt->height;fse->max_height = fmt->height;return 0;}static int PX6130_get_pad_fmt(struct v4l2_subdev *sd,      struct v4l2_subdev_state *sd_state,      struct v4l2_subdev_format *format){struct i2c_client *client = v4l2_get_subdevdata(sd);dev_dbg(&client->dev, "%s(%d)\n", __func__, __LINE__);struct PX6130 *sensor = to_sensor(sd);if (!sensor) {dev_dbg(&client->dev, "sensor is NULL\n");}if (!sensor->mode) {dev_dbg(&client->dev, "sensor->mode is NULL\n");}struct v4l2_mbus_framefmt *fmt = &format->format;const struct v4l2_mbus_framefmt *sensor_format;mutex_lock(&sensor->lock);switch (format->which) {case V4L2_SUBDEV_FORMAT_TRY:sensor_format = v4l2_subdev_get_try_format(sd, sd_state,   format->pad);break;default:sensor_format = &sensor->mode->format;break;}*fmt = *sensor_format;/* The code we pass back must reflect the current h/vflips. */fmt->code = PX6130_get_mbus_code(sd);mutex_unlock(&sensor->lock);return 0;}static int PX6130_set_pad_fmt(struct v4l2_subdev *sd,      struct v4l2_subdev_state *sd_state,      struct v4l2_subdev_format *format){struct v4l2_mbus_framefmt *fmt = &format->format;struct PX6130 *sensor = to_sensor(sd);struct i2c_client *client = v4l2_get_subdevdata(sd);const struct PX6130_mode *mode;dev_dbg(&client->dev, "%s(%d)\n", __func__, __LINE__);mode = v4l2_find_nearest_size(PX6130_modes, ARRAY_SIZE(PX6130_modes),      format.width, format.height,      fmt->width, fmt->height);/* Update the sensor mode and apply at it at streamon time. */mutex_lock(&sensor->lock);if (format->which == V4L2_SUBDEV_FORMAT_TRY) {*v4l2_subdev_get_try_format(sd, sd_state, format->pad) = mode->format;} else {// we don't need to control for exposure now/*int exposure_max, exposure_def;int hblank, vblank;sensor->mode = mode;__v4l2_ctrl_modify_range(sensor->pixel_rate, mode->pixel_rate, mode->pixel_rate, 1, mode->pixel_rate);hblank = mode->hts - mode->format.width;__v4l2_ctrl_modify_range(sensor->hblank, hblank, PX6130_HTS_MAX - mode->format.width, 1, hblank);vblank = mode->vts - mode->format.height;__v4l2_ctrl_modify_range(sensor->vblank, PX6130_VBLANK_MIN, PX6130_VTS_MAX - mode->format.height, 1, vblank);__v4l2_ctrl_s_ctrl(sensor->vblank, vblank);exposure_max = mode->vts - 4;exposure_def = min(exposure_max, PX6130_EXPOSURE_DEFAULT);__v4l2_ctrl_modify_range(sensor->exposure, sensor->exposure->minimum, exposure_max, sensor->exposure->step, exposure_def); */}*fmt = mode->format;/* The code we pass back must reflect the current h/vflips. */fmt->code = PX6130_get_mbus_code(sd);mutex_unlock(&sensor->lock);return 0;}static int PX6130_get_selection(struct v4l2_subdev *sd,struct v4l2_subdev_state *sd_state,struct v4l2_subdev_selection *sel){struct i2c_client *client = v4l2_get_subdevdata(sd);dev_dbg(&client->dev, "%s(%d)\n", __func__, __LINE__);switch (sel->target) {case V4L2_SEL_TGT_CROP: {struct PX6130 *sensor = to_sensor(sd);mutex_lock(&sensor->lock);sel->r = *__PX6130_get_pad_crop(sensor, sd_state, sel->pad,sel->which);mutex_unlock(&sensor->lock);return 0;}case V4L2_SEL_TGT_NATIVE_SIZE:sel->r.top = 0;sel->r.left = 0;sel->r.width = PX6130_NATIVE_WIDTH;sel->r.height = PX6130_NATIVE_HEIGHT;return 0;case V4L2_SEL_TGT_CROP_DEFAULT:case V4L2_SEL_TGT_CROP_BOUNDS:sel->r.top = PX6130_PIXEL_ARRAY_TOP;sel->r.left = PX6130_PIXEL_ARRAY_LEFT;sel->r.width = PX6130_PIXEL_ARRAY_WIDTH;sel->r.height = PX6130_PIXEL_ARRAY_HEIGHT;return 0;}return -EINVAL;}/* Subdev core operations registration */static const struct v4l2_subdev_core_ops PX6130_subdev_core_ops = {.subscribe_event= v4l2_ctrl_subdev_subscribe_event,.unsubscribe_event= v4l2_event_subdev_unsubscribe,#ifdef CONFIG_VIDEO_ADV_DEBUG.g_register= PX6130_sensor_get_register,.s_register= PX6130_sensor_set_register,#endif//.subscribe_event = v4l2_ctrl_subdev_subscribe_event,//.unsubscribe_event = v4l2_event_subdev_unsubscribe,};static const struct v4l2_subdev_pad_ops PX6130_subdev_pad_ops = {.enum_mbus_code= PX6130_enum_mbus_code,.enum_frame_size= PX6130_enum_frame_size,.set_fmt= PX6130_set_pad_fmt,.get_fmt= PX6130_get_pad_fmt,.get_selection= PX6130_get_selection,};static const struct v4l2_subdev_ops PX6130_subdev_ops = {.core= &PX6130_subdev_core_ops,.video= &PX6130_subdev_video_ops,.pad= &PX6130_subdev_pad_ops,};static int PX6130_detect(struct v4l2_subdev *sd){struct i2c_client *client = v4l2_get_subdevdata(sd);u8 read;int ret = 0;return ret;}static int PX6130_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh){struct v4l2_mbus_framefmt *format =v4l2_subdev_get_try_format(sd, fh->state, 0);struct v4l2_rect *crop = v4l2_subdev_get_try_crop(sd, fh->state, 0);crop->left = PX6130_PIXEL_ARRAY_LEFT;crop->top = PX6130_PIXEL_ARRAY_TOP;crop->width = PX6130_PIXEL_ARRAY_WIDTH;crop->height = PX6130_PIXEL_ARRAY_HEIGHT;*format = PX6130_DEFAULT_FORMAT;return 0;}static const struct v4l2_subdev_internal_ops PX6130_subdev_internal_ops = {.open = PX6130_open,};static int PX6130_s_ctrl(struct v4l2_ctrl *ctrl){struct PX6130 *sensor = container_of(ctrl->handler,    struct PX6130, ctrls);struct v4l2_subdev *sd = &sensor->sd;struct i2c_client *client = v4l2_get_subdevdata(sd);int ret = 0;dev_info(&client->dev, "dbg_info: %s, line: %d\n", __func__, __LINE__);return ret;}static const struct v4l2_ctrl_ops PX6130_ctrl_ops = {.s_ctrl = PX6130_s_ctrl,};static int PX6130_init_controls(struct PX6130 *sensor, struct device *dev){struct i2c_client *client = v4l2_get_subdevdata(&sensor->sd);int hblank, exposure_max, exposure_def;struct v4l2_fwnode_device_properties props;dev_info(dev, "dbg_info: %s(%d)\n", __func__, __LINE__);v4l2_ctrl_handler_init(&sensor->ctrls, 2);dev_info(dev, "dbg_info: %s(%d), err: %d\n", __func__, __LINE__, sensor->ctrls.error);/*v4l2_ctrl_new_std(&sensor->ctrls, &PX6130_ctrl_ops,  V4L2_CID_AUTOGAIN, 0, 1, 1, 0);v4l2_ctrl_new_std(&sensor->ctrls, &PX6130_ctrl_ops,  V4L2_CID_AUTO_WHITE_BALANCE, 0, 1, 1, 0);v4l2_ctrl_new_std_menu(&sensor->ctrls, &PX6130_ctrl_ops,       V4L2_CID_EXPOSURE_AUTO, V4L2_EXPOSURE_MANUAL,       0, V4L2_EXPOSURE_MANUAL);exposure_max = sensor->mode->vts - 4;exposure_def = min(exposure_max, PX6130_EXPOSURE_DEFAULT);sensor->exposure = v4l2_ctrl_new_std(&sensor->ctrls, &PX6130_ctrl_ops,     V4L2_CID_EXPOSURE,     PX6130_EXPOSURE_MIN,     exposure_max, PX6130_EXPOSURE_STEP,     exposure_def);// min: 16 = 1.0x; max (10 bits); default: 32 = 2.0x.v4l2_ctrl_new_std(&sensor->ctrls, &PX6130_ctrl_ops,  V4L2_CID_ANALOGUE_GAIN, 16, 1023, 1, 32);// By default, PIXEL_RATE is read only, but it does change per modesensor->pixel_rate = v4l2_ctrl_new_std(&sensor->ctrls, &PX6130_ctrl_ops,       V4L2_CID_PIXEL_RATE,       sensor->mode->pixel_rate,       sensor->mode->pixel_rate, 1,       sensor->mode->pixel_rate);hblank = sensor->mode->hts - sensor->mode->format.width;sensor->hblank = v4l2_ctrl_new_std(&sensor->ctrls, &PX6130_ctrl_ops,   V4L2_CID_HBLANK, hblank,   PX6130_HTS_MAX -   sensor->mode->format.width, 1,   hblank);sensor->vblank = v4l2_ctrl_new_std(&sensor->ctrls, &PX6130_ctrl_ops,   V4L2_CID_VBLANK, PX6130_VBLANK_MIN,   PX6130_VTS_MAX -   sensor->mode->format.height, 1,   sensor->mode->vts -   sensor->mode->format.height);v4l2_ctrl_new_std_menu_items(&sensor->ctrls, &PX6130_ctrl_ops,     V4L2_CID_TEST_PATTERN,     ARRAY_SIZE(PX6130_test_pattern_menu) - 1,     0, 0, PX6130_test_pattern_menu);*/sensor->hflip = v4l2_ctrl_new_std(&sensor->ctrls, &PX6130_ctrl_ops,  V4L2_CID_HFLIP, 0, 1, 1, 0);dev_info(dev, "dbg_info: %s(%d), err: %d\n", __func__, __LINE__, sensor->ctrls.error);if (sensor->hflip)sensor->hflip->flags |= V4L2_CTRL_FLAG_MODIFY_LAYOUT;sensor->vflip = v4l2_ctrl_new_std(&sensor->ctrls, &PX6130_ctrl_ops,  V4L2_CID_VFLIP, 0, 1, 1, 0);dev_info(dev, "dbg_info: %s(%d), err: %d\n", __func__, __LINE__, sensor->ctrls.error);if (sensor->vflip)sensor->vflip->flags |= V4L2_CTRL_FLAG_MODIFY_LAYOUT;v4l2_fwnode_device_parse(dev, &props);dev_info(dev, "dbg_info: %s(%d), err: %d\n", __func__, __LINE__, sensor->ctrls.error);v4l2_ctrl_new_fwnode_properties(&sensor->ctrls, &PX6130_ctrl_ops,&props);dev_info(dev, "dbg_info: %s(%d), err: %d\n", __func__, __LINE__, sensor->ctrls.error);if (sensor->ctrls.error) {dev_info(dev, "dbg_info: %s(%d), err: %d\n", __func__, __LINE__, sensor->ctrls.error);goto handler_free;}dev_info(dev, "dbg_info: %s(%d), err: %d\n", __func__, __LINE__, sensor->ctrls.error);//sensor->pixel_rate->flags |= V4L2_CTRL_FLAG_READ_ONLY;dev_info(dev, "dbg_info: %s(%d), err: %x\n", __func__, __LINE__, sensor->ctrls);sensor->sd.ctrl_handler = &sensor->ctrls;dev_info(dev, "dbg_info: %s, line: %d\n", __func__, __LINE__);return 0;handler_free:dev_info(&client->dev, "%s Controls initialization failed (%d)\n",__func__, sensor->ctrls.error);v4l2_ctrl_handler_free(&sensor->ctrls);return sensor->ctrls.error;}static int PX6130_parse_dt(struct PX6130 *sensor, struct device_node *np){struct v4l2_fwnode_endpoint bus_cfg = {.bus_type = V4L2_MBUS_CSI2_DPHY,};struct device_node *ep;int ret;ep = of_graph_get_next_endpoint(np, NULL);if (!ep)return -EINVAL;ret = v4l2_fwnode_endpoint_parse(of_fwnode_handle(ep), &bus_cfg);if (ret)goto out;sensor->clock_ncont = bus_cfg.bus.mipi_csi2.flags &      V4L2_MBUS_CSI2_NONCONTINUOUS_CLOCK;out:of_node_put(ep);return ret;}static int PX6130_probe(struct i2c_client *client){struct device_node *np = client->dev.of_node;struct device *dev = &client->dev;struct PX6130 *sensor;struct v4l2_subdev *sd;u32 xclk_freq;int ret;sensor = devm_kzalloc(dev, sizeof(*sensor), GFP_KERNEL);if (!sensor)return -ENOMEM;if (IS_ENABLED(CONFIG_OF) && np) {ret = PX6130_parse_dt(sensor, np);if (ret) {dev_err(dev, "DT parsing error: %d\n", ret);return ret;}}// In our image sensor there is an xclk block, so we don't need to send clock to the CIS/*sensor->xclk = devm_clk_get(dev, NULL);if (IS_ERR(sensor->xclk)) {dev_err(dev, "could not get xclk");return PTR_ERR(sensor->xclk);}xclk_freq = clk_get_rate(sensor->xclk);if (xclk_freq != 25000000) {dev_err(dev, "Unsupported clock frequency: %u\n", xclk_freq);return -EINVAL;}*/// CIS doesn't get power from the rpi board, later we will change that rpi board supplies power to CIS/* Request the power down GPIO asserted. *//*sensor->pwdn = devm_gpiod_get_optional(dev, "pwdn", GPIOD_OUT_HIGH);if (IS_ERR(sensor->pwdn)) {dev_err(dev, "Failed to get 'pwdn' gpio\n");return -EINVAL;}ret = PX6130_configure_regulators(dev, sensor);if (ret) {dev_err(dev, "Failed to get power regulators\n");return ret;}*/mutex_init(&sensor->lock);sensor->mode = PX6130_DEFAULT_MODE;ret = PX6130_init_controls(sensor, dev);dev_info(dev, "dbg_info: %s, line: %d, ret: %d\n", __func__, __LINE__, ret);dev_info(dev, "dbg_info: %s, line: %d, sensor: %x\n", __func__, __LINE__, &sensor->sd);if (ret)goto mutex_destroy;sd = &sensor->sd;dev_info(dev, "dbg_info: %s, line: %d\n", __func__, __LINE__);v4l2_i2c_subdev_init(sd, client, &PX6130_subdev_ops);dev_info(dev, "dbg_info: %s, line: %d\n", __func__, __LINE__);sd->internal_ops = &PX6130_subdev_internal_ops;sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE | V4L2_SUBDEV_FL_HAS_EVENTS;sensor->pad.flags = MEDIA_PAD_FL_SOURCE;sd->entity.function = MEDIA_ENT_F_CAM_SENSOR;ret = media_entity_pads_init(&sd->entity, 1, &sensor->pad);dev_info(dev, "dbg_info: %s, line: %d, ret: %d\n", __func__, __LINE__, ret);if (ret < 0)goto ctrl_handler_free;// 외부에서 직접 전원을 받음으로 필요 없음/*ret = PX6130_power_on(dev);if (ret)goto entity_cleanup;ret = PX6130_detect(sd);if (ret < 0)goto power_off;*/dev_info(dev, "dbg_info: %s, line: %d\n", __func__, __LINE__);ret = v4l2_async_register_subdev_sensor(sd);dev_info(dev, "dbg_info: %s, line: %d, ret: %d\n", __func__, __LINE__, ret);if (ret < 0)goto power_off;// 외부에서 직접 전원을 받음으로 필요 없없음/* Enable runtime PM and turn off the device *//*pm_runtime_set_active(dev);pm_runtime_enable(dev);pm_runtime_idle(dev);*/dev_info(dev, "Pixelplus PX6130 camera driver probed\n");return 0;power_off:PX6130_power_off(dev);entity_cleanup:media_entity_cleanup(&sd->entity);ctrl_handler_free:v4l2_ctrl_handler_free(&sensor->ctrls);mutex_destroy:mutex_destroy(&sensor->lock);return ret;}static void PX6130_remove(struct i2c_client *client){struct v4l2_subdev *sd = i2c_get_clientdata(client);struct PX6130 *sensor = to_sensor(sd);v4l2_async_unregister_subdev(&sensor->sd);media_entity_cleanup(&sensor->sd.entity);v4l2_ctrl_handler_free(&sensor->ctrls);v4l2_device_unregister_subdev(sd);pm_runtime_disable(&client->dev);mutex_destroy(&sensor->lock);}static const struct dev_pm_ops PX6130_pm_ops = {SET_RUNTIME_PM_OPS(PX6130_power_off, PX6130_power_on, NULL)};static const struct i2c_device_id PX6130_id[] = {{ "px6130", 0 },{ /* sentinel */ }};MODULE_DEVICE_TABLE(i2c, PX6130_id);#if IS_ENABLED(CONFIG_OF)static const struct of_device_id PX6130_of_match[] = {{ .compatible = "pixelplus,px6130" },{ /* sentinel */ },};MODULE_DEVICE_TABLE(of, PX6130_of_match);#endifstatic struct i2c_driver PX6130_driver = {.driver = {.of_match_table = of_match_ptr(PX6130_of_match),.name= "px6130",//.pm= &PX6130_pm_ops,},.probe= PX6130_probe,.remove= PX6130_remove,.id_table= PX6130_id,};module_i2c_driver(PX6130_driver);MODULE_AUTHOR("shkang <info@pixelplus.com>");MODULE_DESCRIPTION("A low-level driver for Pixelplus PX6130 sensors");MODULE_LICENSE("GPL v2");
Below is the dmesg log after the dtoverlay command

Code:

raspi4@raspi4:~/px6130/driver $ sudo dtoverlay px6130[  623.414784] OF: overlay: WARNING: memory leak will occur if overlay removed, property: /soc/i2c@7e205000/status[  623.414830] OF: overlay: WARNING: memory leak will occur if overlay removed, property: /soc/i2c0mux/status[  623.414852] OF: overlay: WARNING: memory leak will occur if overlay removed, property: /soc/i2c0mux/i2c@1/status[  623.414922] OF: overlay: WARNING: memory leak will occur if overlay removed, property: /soc/csi@7e801000/status[  623.424279] platform fe801000.csi: Fixed dependency cycle(s) with /soc/i2c0mux/i2c@1/px6130@36[  623.525175] i2c i2c-22: Added multiplexed i2c bus 0[  623.525740] i2c i2c-22: Added multiplexed i2c bus 10
Below is the dmesg for the insmod command. There are some debug prints.

Code:

raspi4@raspi4:~/px6130/driver $ sudo insmod px6130.ko[  671.771993] px6130: loading out-of-tree module taints kernel.[  671.773403] px6130 10-0034: dbg_info: PX6130_init_controls(664)[  671.773429] px6130 10-0034: dbg_info: PX6130_init_controls(667), err: 0[  671.773459] px6130 10-0034: dbg_info: PX6130_init_controls(721), err: 0[  671.773473] px6130 10-0034: dbg_info: PX6130_init_controls(728), err: 0[  671.773488] px6130 10-0034: dbg_info: PX6130_init_controls(734), err: 0[  671.773498] px6130 10-0034: dbg_info: PX6130_init_controls(738), err: 0[  671.773508] px6130 10-0034: dbg_info: PX6130_init_controls(745), err: 0[  671.773517] px6130 10-0034: dbg_info: PX6130_init_controls(747), err: 820bb750[  671.773528] px6130 10-0034: dbg_info: PX6130_init_controls, line: 750[  671.773537] px6130 10-0034: dbg_info: PX6130_probe, line: 844, ret: 0[  671.773547] px6130 10-0034: dbg_info: PX6130_probe, line: 845, sensor: 68db080[  671.773558] px6130 10-0034: dbg_info: PX6130_probe, line: 850[  671.773570] px6130 10-0034: dbg_info: PX6130_probe, line: 852[  671.773582] px6130 10-0034: dbg_info: PX6130_probe, line: 859, ret: 0[  671.773592] px6130 10-0034: dbg_info: PX6130_probe, line: 875[  671.774738] px6130 10-0034: dbg_info: PX6130_probe, line: 877, ret: 0[  671.774762] px6130 10-0034: Pixelplus PX6130 camera driver probed[  671.874323] px6130 10-0034: dbg_info: PX6130_enum_frame_size(434), state:0, fse:8149bb88[  671.874354] px6130 10-0034: dbg_info: PX6130_enum_frame_size(444) (1280, 960)[  671.874382] px6130 10-0034: dbg_info: PX6130_enum_frame_size(434), state:0, fse:8149bb88[  671.874390] px6130 10-0034: Err!! code: 8200, index: 2, mbus: 8200, size : 1[  671.876177] px6130 10-0034: dbg_info: PX6130_enum_frame_size(434), state:0, fse:8149bb88[  671.876204] px6130 10-0034: dbg_info: PX6130_enum_frame_size(444) (1280, 960)[  671.876233] px6130 10-0034: dbg_info: PX6130_enum_frame_size(434), state:0, fse:8149bb88[  671.876241] px6130 10-0034: Err!! code: 8200, index: 2, mbus: 8200, size : 1
After inserting px6130 driver, i checked if the driver is loaded well.

Code:

raspi4@raspi4:~/px6130/driver $ lsmodModule                  Size  Used bypx6130                 12288  1bcm2835_unicam         49152  0v4l2_dv_timings        32768  1 bcm2835_unicami2c_mux_pinctrl        12288  0v4l2_fwnode            20480  2 bcm2835_unicam,px6130i2c_mux                12288  1 i2c_mux_pinctrlv4l2_async             20480  3 v4l2_fwnode,bcm2835_unicam,px6130rfcomm                 53248  4snd_seq_dummy          12288  0snd_hrtimer            12288  1snd_seq                81920  7 snd_seq_dummysnd_seq_device         16384  1 snd_seqcmac                   12288  3algif_hash             12288  1aes_arm64              12288  3aes_generic            32768  1 aes_arm64algif_skcipher         12288  1af_alg                 24576  6 algif_hash,algif_skcipherbnep                   24576  2brcmfmac_wcc           12288  0hci_uart               49152  0brcmfmac              348160  1 brcmfmac_wccbtbcm                  24576  1 hci_uartbluetooth             606208  33 hci_uart,btbcm,bnep,rfcommjoydev                 24576  0brcmutil               24576  1 brcmfmaccfg80211              983040  1 brcmfmacecdh_generic           16384  2 bluetoothraspberrypi_hwmon      12288  0ecc                    36864  1 ecdh_genericbcm2835_isp            28672  0rpivid_hevc            45056  0bcm2835_codec          45056  0v4l2_mem2mem           45056  2 bcm2835_codec,rpivid_hevcvideobuf2_dma_contig    16384  4 bcm2835_codec,bcm2835_unicam,rpivid_hevc,bcm2835_ispbinfmt_misc            16384  1bcm2835_v4l2           40960  0rfkill                 32768  6 bluetooth,cfg80211libaes                 12288  3 aes_arm64,bluetooth,aes_genericbcm2835_mmal_vchiq     36864  3 bcm2835_codec,bcm2835_v4l2,bcm2835_ispvideobuf2_vmalloc      12288  1 bcm2835_v4l2videobuf2_memops       12288  2 videobuf2_vmalloc,videobuf2_dma_contigvideobuf2_v4l2         32768  6 bcm2835_codec,bcm2835_unicam,bcm2835_v4l2,rpivid_hevc,v4l2_mem2mem,bcm2835_ispvideodev              303104  10 v4l2_async,bcm2835_codec,v4l2_fwnode,videobuf2_v4l2,bcm2835_unicam,bcm2835_v4l2,rpivid_hevc,v4l2_mem2mem,px6130,bcm2835_ispraspberrypi_gpiomem    12288  0videobuf2_common       69632  10 bcm2835_codec,videobuf2_vmalloc,videobuf2_dma_contig,videobuf2_v4l2,bcm2835_unicam,bcm2835_v4l2,rpivid_hevc,v4l2_mem2mem,videobuf2_memops,bcm2835_ispsnd_bcm2835            24576  1vc_sm_cma              28672  2 bcm2835_mmal_vchiq,bcm2835_ispmc                     61440  10 v4l2_async,videodev,bcm2835_codec,videobuf2_v4l2,bcm2835_unicam,videobuf2_common,rpivid_hevc,v4l2_mem2mem,px6130,bcm2835_ispnvmem_rmem             12288  0uio_pdrv_genirq        12288  0uio                    20480  1 uio_pdrv_genirqi2c_dev                16384  0ledtrig_pattern        12288  0fuse                  139264  5dm_mod                143360  0ip_tables              32768  0x_tables               49152  1 ip_tablesipv6                  565248  46vc4                   376832  32snd_soc_hdmi_codec     20480  2drm_display_helper     16384  1 vc4cec                    53248  1 vc4drm_dma_helper         24576  3 vc4v3d                    90112  6gpu_sched              49152  1 v3ddrm_kms_helper        212992  2 drm_dma_helper,vc4drm_shmem_helper       24576  1 v3ddrm                   643072  21 gpu_sched,drm_kms_helper,drm_dma_helper,v3d,vc4,drm_shmem_helper,drm_display_helperdrm_panel_orientation_quirks    28672  1 drmsnd_soc_core          286720  2 vc4,snd_soc_hdmi_codecsnd_compress           16384  1 snd_soc_coresnd_pcm_dmaengine      16384  1 snd_soc_corei2c_brcmstb            12288  0snd_pcm               139264  5 snd_bcm2835,snd_soc_hdmi_codec,snd_compress,snd_soc_core,snd_pcm_dmaenginei2c_bcm2835            16384  1snd_timer              36864  3 snd_seq,snd_hrtimer,snd_pcmsnd                   110592  14 snd_seq,snd_seq_device,snd_bcm2835,snd_soc_hdmi_codec,snd_timer,snd_compress,snd_soc_core,snd_pcmbacklight              24576  2 drm_kms_helper,drm
From now on, below are the v4l2-ctl command logs

Code:

raspi4@raspi4:~/px6130/driver $ v4l2-ctl --all -d 0Driver Info:Driver name      : unicamCard type        : unicamBus info         : platform:fe801000.csiDriver version   : 6.6.51Capabilities     : 0x85a00001Video CaptureMetadata CaptureRead/WriteStreamingExtended Pix FormatDevice CapabilitiesDevice Caps      : 0x05200001Video CaptureRead/WriteStreamingExtended Pix FormatMedia Driver Info:Driver name      : unicamModel            : unicamSerial           : Bus info         : platform:fe801000.csiMedia version    : 6.6.51Hardware revision: 0x00000000 (0)Driver version   : 6.6.51Interface Info:ID               : 0x03000005Type             : V4L VideoEntity Info:ID               : 0x00000003 (3)Name             : unicam-imageFunction         : V4L2 I/OFlags            : defaultPad 0x01000004   : 0: Sink  Link 0x02000007: from remote pad 0x1000002 of entity 'px6130 10-0034' (Camera Sensor): Data, Enabled, ImmutablePriority: 2Video input : 0 (Camera 0: ok)Format Video Capture:Width/Height      : 1280/960Pixel Format      : 'YUYV' (YUYV 4:2:2)Field             : NoneBytes per Line    : 2560Size Image        : 2457600Colorspace        : RawTransfer Function : Default (maps to None)YCbCr/HSV Encoding: Default (maps to ITU-R 601)Quantization      : Default (maps to Limited Range)Flags             : Crop Capability Video Capture:Bounds      : Left 0, Top 0, Width 1280, Height 960Default     : Left 0, Top 0, Width 1280, Height 960Pixel Aspect: 1/1Selection Video Capture: crop, Left 0, Top 0, Width 1280, Height 960, Flags: Selection Video Capture: crop_default, Left 0, Top 0, Width 1280, Height 960, Flags: Selection Video Capture: crop_bounds, Left 0, Top 0, Width 1280, Height 960, Flags: Selection Video Capture: native_size, Left 0, Top 0, Width 1280, Height 960, Flags: User Controls                horizontal_flip 0x00980914 (bool)   : default=0 value=0 flags=modify-layout                  vertical_flip 0x00980915 (bool)   : default=0 value=0 flags=modify-layout
dmesg for v4l2-ctl --all -d 0

Code:

[  755.341655] __PX6130_get_pad_crop(332): 1[  755.343980] __PX6130_get_pad_crop(332): 1

Code:

raspi4@raspi4:~/px6130/driver $ v4l2-ctl -d 0 --stream-mmap --stream-count=10VIDIOC_STREAMON returned -1 (Permission denied)
dmesg for the v4l2-ctl d 0 -stream-count=10

Code:

[  804.712006] __PX6130_get_pad_crop(332): 1[  804.723132] px6130 10-0034: dbg_info: PX6130_s_stream, line: 349[  804.723152] unicam fe801000.csi: stream on failed in subdev
Please, let me know what are wrong in order to get video buffers.

Thank you.

Statistics: Posted by stupid dog — Thu Nov 14, 2024 11:15 am



Viewing all articles
Browse latest Browse all 3843

Trending Articles