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 codeBelow is the dmesg log after the dtoverlay commandBelow is the dmesg for the insmod command. There are some debug prints.After inserting px6130 driver, i checked if the driver is loaded well.From now on, below are the v4l2-ctl command logsdmesg for v4l2-ctl --all -d 0dmesg for the v4l2-ctl d 0 -stream-count=10Please, let me know what are wrong in order to get video buffers.
Thank you.
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");
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
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
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
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
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)
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
Thank you.
Statistics: Posted by stupid dog — Thu Nov 14, 2024 11:15 am