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

Interfacing (DSI, CSI, I2C, etc.) • Inquiry About Connecting an Unofficial MIPI-CSI2 Camera

$
0
0
Hello,

I previously posted a similar message, and although I am still a beginner when it comes to developing camera device drivers, I am working hard to make progress. I have disabled the media controller as you suggested and set the clock mode to continuous to match the MIPI output. Since the last time, I have made some advancements.

First of all, the camera module I am using has an ISP built into the image sensor. Therefore, instead of Bayer format, the output is in YUV422 format. Please refer to the attached file.

Active Resolution : 1280 x 960, YUV422, 30fps
Blank : 1195(Horizontal), 40(Vertical)
Pixel rate : 74.25MHz
MIPI PHY clock : 192MHz

I have attached my DTS file and driver source code for reference.
Device tree file

Code:

// SPDX-License-Identifier: GPL-2.0-only// Definitions for Analog Devices ADV7282-M video to CSI2 bridge on VC I2C bus/dts-v1/;/plugin/;/{compatible = "brcm,bcm2835";fragment@0 {target = <&i2c_csi_dsi>;__overlay__ {#address-cells = <1>;#size-cells = <0>;status = "okay";px6130: px6130@36 {compatible = "pixelplus,px6130";reg = <0x36>;status = "okay";//clock-frequency = <24000000>;port {px6130_out: endpoint {remote-endpoint = <&csi1_ep>;clock-lanes = <0>;data-lanes = <1 2>;link-frequencies =/bits/ 64 <384000000>;};};};};};fragment@1 {target = <&csi1>;__overlay__ {status = "okay";port {csi1_ep: endpoint {remote-endpoint = <&px6130_out>;data-lanes = <1 2>;};};};};fragment@2 {target = <&i2c0if>;__overlay__ {status = "okay";};};fragment@3 {target = <&i2c0mux>;__overlay__ {status = "okay";};};fragment@4 {target = <&csi1>;__dormant__ {brcm,media-controller;};};__overrides__ {addr =<&px6130>,"reg:0";media-controller = <0>,"=4";};};
Driver source codes

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 OV7670 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_HORIZONTAL_TOTAL_SIZE2475U// pixel domain#define PX6130_VERTICAL_TOTAL_SIZE1000U// pixel domain#define PX6130_VBLANK_MIN0#define PX6130_VTS_MAX32767#define PX6130_HTS_MAX0x1fff/* 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_SMPTE170M,.field= V4L2_FIELD_NONE,.width= PX6130_PIXEL_ARRAY_WIDTH,.height= PX6130_PIXEL_ARRAY_HEIGHT},.crop = {.left= 0,.top= 0,.width= PX6130_PIXEL_ARRAY_WIDTH,.height= PX6130_PIXEL_ARRAY_HEIGHT},.pixel_rate= 74250000,.hts= PX6130_HORIZONTAL_TOTAL_SIZE,.vts= PX6130_VERTICAL_TOTAL_SIZE,.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);dev_info(&client->dev, "%s(%d) ret: %d\n", __func__, __LINE__, ret);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);dev_info(&client->dev, "%s(%d) ret: %d\n", __func__, __LINE__, ret);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_info(&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_info(&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_info(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_info(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 = 0;dev_info(&client->dev, "dbg_info: %s, line: %d, enable: %d(%d)\n", __func__, __LINE__, enable, sensor->streaming);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);dev_info(&client->dev, "%s(%d) ret: %d\n", __func__, __LINE__, ret);if (ret < 0) {dev_info(&client->dev, "%s(%d) ret: %d\n", __func__, __LINE__, ret);goto error_unlock;}ret = PX6130_stream_on(sd);dev_info(&client->dev, "%s(%d) ret: %d\n", __func__, __LINE__, ret);if (ret < 0) {dev_info(&client->dev, "stream start failed: %d\n", ret);goto error_pm;}} else {dev_info(&client->dev, "dbg_info: %s, line: %d\n", __func__, __LINE__);ret = PX6130_stream_off(sd);if (ret < 0) {dev_info(&client->dev, "stream stop failed: %d\n", ret);goto error_pm;}//pm_runtime_put(&client->dev);}sensor->streaming = enable;mutex_unlock(&sensor->lock);dev_info(&client->dev, "dbg_info: %s, line: %d\n", __func__, __LINE__);return 0;error_pm:dev_info(&client->dev, "dbg_info: %s, line: %d\n", __func__, __LINE__);pm_runtime_put(&client->dev);error_unlock:dev_info(&client->dev, "dbg_info: %s, line: %d\n", __func__, __LINE__);mutex_unlock(&sensor->lock);return ret;}static int PX6130_g_frame_interval(struct v4l2_subdev *sd,                                   struct v4l2_subdev_frame_interval *interval){struct PX6130 *sensor = to_sensor(sd);struct i2c_client *client = v4l2_get_subdevdata(sd);dev_info(&client->dev, "%s, %d\n", __func__, __LINE__);// 고정된 프레임 속도를 반환interval->interval.numerator = 1;interval->interval.denominator = 30; // 고정된 30fpsreturn 0;}/* 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 i2c_client *client = v4l2_get_subdevdata(sd);dev_info(&client->dev, "%s, %d\n", __func__, __LINE__);struct PX6130 *sensor = to_sensor(sd);/* The control values are only 0 or 1. *///int index =  sensor->hflip->val | (sensor->vflip->val << 1);int index = 0;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_info(&client->dev, "%s(%d), fmt: %d\n", __func__, __LINE__, format->which);struct PX6130 *sensor = to_sensor(sd);if (!sensor) {dev_info(&client->dev, "sensor is NULL\n");}if (!sensor->mode) {dev_info(&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;dev_info(&client->dev, "size(%d, %d), code: %d, fld: %d, color: %d, yuv_enc: %d, hsv_enc: %d\n",fmt->width, fmt->height, fmt->code, fmt->field, fmt->colorspace, fmt->ycbcr_enc, fmt->hsv_enc);/* 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_info(&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 nowint 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_info(&client->dev, "%s(%d), target: %d\n", __func__, __LINE__, sel->target);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_video_ops PX6130_subdev_video_ops = {.s_stream =PX6130_s_stream,.g_frame_interval = PX6130_g_frame_interval,};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 i2c_client *client = v4l2_get_subdevdata(sd);dev_info(&client->dev, "%s, %d\n", __func__, __LINE__);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, id: %d\n", __func__, __LINE__, ctrl->id);switch (ctrl->id) {case V4L2_CID_PIXEL_RATE:dev_info(&client->dev, "V4L2_CID_PIXEL_RATE val:%d\n", ctrl->val);/* Read-only, but we adjust it based on mode. */break;case V4L2_CID_HFLIP:/* There's an in-built hflip in the sensor, so account for that here. *///PX6130_s_flip(sd, PX6130_REG_HFLIP, !ctrl->val);break;case V4L2_CID_VFLIP:dev_info(&client->dev, "V4L2_CID_VFLIP val:%d\n", ctrl->val);//PX6130_s_flip(sd, PX6130_REG_VFLIP, ctrl->val);break;case V4L2_CID_HBLANK:dev_info(&client->dev, "V4L2_CID_HBLANK val:%d\n", ctrl->val);break;case V4L2_CID_VBLANK:dev_info(&client->dev, "V4L2_CID_VBLANK val:%d\n", ctrl->val);break;case V4L2_CID_LINK_FREQ:dev_info(&client->dev, "V4L2_CID_LINK_FREQ val:%d\n", ctrl->val);break;default:dev_info(&client->dev, "Control (id:0x%x, val:0x%x) not supported\n", ctrl->id, ctrl->val);return -EINVAL;};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, vblank, exposure_max, exposure_def;struct v4l2_fwnode_device_properties props;v4l2_ctrl_handler_init(&sensor->ctrls, 5);/*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);vblank = sensor->mode->vts - sensor->mode->format.height;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,   vblank);dev_info(dev, "dbg_info: %s(%d), blank(%d, %d), sensor_blank(%d, %d)\n",__func__, __LINE__, hblank, vblank, sensor->hblank, sensor->vblank);   /*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);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);if (sensor->vflip)sensor->vflip->flags |= V4L2_CTRL_FLAG_MODIFY_LAYOUT;v4l2_fwnode_device_parse(dev, &props);v4l2_ctrl_new_fwnode_properties(&sensor->ctrls, &PX6130_ctrl_ops,&props);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, line: %d\n", __func__, __LINE__);sensor->pixel_rate->flags |= V4L2_CTRL_FLAG_READ_ONLY;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, sensor: %x\n", __func__, __LINE__, ret, &sensor->sd);if (ret)goto mutex_destroy;sd = &sensor->sd;v4l2_i2c_subdev_init(sd, client, &PX6130_subdev_ops);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;// power from an external power supply, we don't need it/*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;// power from an external power supply, we don't need it/* 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("Ramiro Oliveira <roliveir@synopsys.com>");MODULE_DESCRIPTION("A low-level driver for Pixelplus PX6130 sensors");MODULE_LICENSE("GPL v2");
The issue I am currently facing is that the video buffer is not being received correctly. As shown in the diagram below, only about 5000 bytes of data are being received initially.

Code:

raspi4@raspberrypi:~/px6130/driver $ sudo dtoverlay px6130
dmesg

Code:

[  146.919447] OF: overlay: WARNING: memory leak will occur if overlay removed, property: /soc/i2c0mux/i2c@1/status[  146.919558] OF: overlay: WARNING: memory leak will occur if overlay removed, property: /soc/csi@7e801000/status[  146.919592] OF: overlay: WARNING: memory leak will occur if overlay removed, property: /soc/i2c@7e205000/status[  146.919613] OF: overlay: WARNING: memory leak will occur if overlay removed, property: /soc/i2c0mux/status[  147.030756] i2c i2c-22: Added multiplexed i2c bus 0[  147.031105] i2c i2c-22: Added multiplexed i2c bus 10

Code:

raspi4@raspberrypi:~/px6130/driver $ sudo insmod px6130.ko
dmesg

Code:

[  153.497572] px6130: loading out-of-tree module taints kernel.[  153.498847] px6130 10-0036: dbg_info: PX6130_init_controls(775), blank(1195, 40), sensor_blank(1103197696, 1131448064)[  153.498883] px6130 10-0036: dbg_info: PX6130_init_controls, line: 807[  153.498894] px6130 10-0036: dbg_info: PX6130_init_controls, line: 811[  153.498904] px6130 10-0036: dbg_info: PX6130_probe, line: 905, ret: 0, sensor: 6cee1c80[  153.498921] px6130 10-0036: dbg_info: PX6130_probe, line: 917, ret: 0[  153.498931] px6130 10-0036: dbg_info: PX6130_probe, line: 933[  153.498969] px6130 10-0036: PX6130_get_pad_fmt(484), fmt: 1[  153.498979] px6130 10-0036: size(1280, 960), code: 8200, fld: 1, color: 1, yuv_enc: 0, hsv_enc: 0[  153.498993] px6130 10-0036: PX6130_get_mbus_code, 424[  153.499002] px6130 10-0036: PX6130_get_pad_fmt(484), fmt: 1[  153.499012] px6130 10-0036: size(1280, 960), code: 8200, fld: 1, color: 1, yuv_enc: 0, hsv_enc: 0[  153.499024] px6130 10-0036: PX6130_get_mbus_code, 424[  153.499772] px6130 10-0036: dbg_info: PX6130_probe, line: 935, ret: 0[  153.499791] px6130 10-0036: Pixelplus PX6130 camera driver probed[  153.584676] px6130 10-0036: PX6130_open, 658[  153.591964] px6130 10-0036: PX6130_get_mbus_code, 424[  153.591991] px6130 10-0036: PX6130_get_mbus_code, 424[  153.591996] px6130 10-0036: dbg_info: PX6130_enum_frame_size(459), state:0, fse:813d3b88[  153.592002] px6130 10-0036: PX6130_get_mbus_code, 424[  153.592006] px6130 10-0036: dbg_info: PX6130_enum_frame_size(469) (1280, 960)[  153.592022] px6130 10-0036: PX6130_get_mbus_code, 424[  153.592026] px6130 10-0036: dbg_info: PX6130_enum_frame_size(459), state:0, fse:813d3b88[  153.592030] px6130 10-0036: PX6130_get_mbus_code, 424[  153.592033] px6130 10-0036: PX6130_get_mbus_code, 424[  153.592036] px6130 10-0036: Err!! code: 8200, index: 2, mbus: 8200, size : 1[  153.592041] px6130 10-0036: PX6130_get_mbus_code, 424[  153.596291] px6130 10-0036: PX6130_get_mbus_code, 424[  153.596314] px6130 10-0036: PX6130_get_mbus_code, 424[  153.596318] px6130 10-0036: dbg_info: PX6130_enum_frame_size(459), state:0, fse:813d3b88[  153.596323] px6130 10-0036: PX6130_get_mbus_code, 424[  153.596326] px6130 10-0036: dbg_info: PX6130_enum_frame_size(469) (1280, 960)[  153.596346] px6130 10-0036: PX6130_get_mbus_code, 424[  153.596349] px6130 10-0036: dbg_info: PX6130_enum_frame_size(459), state:0, fse:813d3b88[  153.596354] px6130 10-0036: PX6130_get_mbus_code, 424[  153.596357] px6130 10-0036: PX6130_get_mbus_code, 424[  153.596360] px6130 10-0036: Err!! code: 8200, index: 2, mbus: 8200, size : 1[  153.596365] px6130 10-0036: PX6130_get_mbus_code, 424

Code:

raspi4@raspberrypi:~/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-0036' (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        : SMPTE 170MTransfer Function : Default (maps to Rec. 709)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: Streaming Parameters Video Capture:Capabilities     : timeperframeFrames per second: 30.000 (30/1)Read buffers     : 2User Controls                horizontal_flip 0x00980914 (bool)   : default=0 value=0 flags=modify-layout                  vertical_flip 0x00980915 (bool)   : default=0 value=0 flags=modify-layoutImage Source Controls              vertical_blanking 0x009e0901 (int)    : min=0 max=31807 step=1 default=40 value=40            horizontal_blanking 0x009e0902 (int)    : min=1195 max=6911 step=1 default=1195 value=1195Image Processing Controls                     pixel_rate 0x009f0902 (int64)  : min=74250000 max=74250000 step=1 default=74250000 value=74250000 flags=read-only
dmesg

Code:

[  170.999868] px6130 10-0036: PX6130_get_selection(581), target: 0[  170.999904] __PX6130_get_pad_crop(337): 1[  171.000821] px6130 10-0036: PX6130_get_pad_fmt(484), fmt: 1[  171.000843] px6130 10-0036: size(1280, 960), code: 8200, fld: 1, color: 1, yuv_enc: 0, hsv_enc: 0[  171.000861] px6130 10-0036: PX6130_get_mbus_code, 424[  171.000907] px6130 10-0036: PX6130_get_mbus_code, 424[  171.001107] px6130 10-0036: PX6130_get_selection(581), target: 2[  171.001119] px6130 10-0036: PX6130_get_selection(581), target: 1[  171.001435] px6130 10-0036: PX6130_get_selection(581), target: 0[  171.001452] __PX6130_get_pad_crop(337): 1[  171.001487] px6130 10-0036: PX6130_get_selection(581), target: 1[  171.001517] px6130 10-0036: PX6130_get_selection(581), target: 2[  171.001546] px6130 10-0036: PX6130_get_selection(581), target: 256[  171.001559] px6130 10-0036: PX6130_get_selection(581), target: 257[  171.001571] px6130 10-0036: PX6130_get_selection(581), target: 258[  171.001583] px6130 10-0036: PX6130_get_selection(581), target: 259[  171.001595] px6130 10-0036: PX6130_get_selection(581), target: 3[  171.001661] px6130 10-0036: PX6130_g_frame_interval, 409[  171.001987] px6130 10-0036: PX6130_get_selection(581), target: 256

Code:

raspi4@raspberrypi:~/px6130/driver $ v4l2-ctl -d 0 --stream-mmap --stream-count=10 --stream-to=output.raw<<<<<<<<<<
dmesg

Code:

[  336.646032] px6130 10-0036: PX6130_get_selection(581), target: 0[  336.646067] __PX6130_get_pad_crop(337): 1[  336.646370] px6130 10-0036: PX6130_get_selection(581), target: 256[  336.670597] px6130 10-0036: PX6130_get_pad_fmt(484), fmt: 1[  336.670641] px6130 10-0036: size(1280, 960), code: 8200, fld: 1, color: 1, yuv_enc: 0, hsv_enc: 0[  336.670656] px6130 10-0036: PX6130_get_mbus_code, 424[  336.675232] px6130 10-0036: dbg_info: PX6130_s_stream, line: 354, enable: 1(0)[  336.675261] px6130 10-0036: PX6130_s_stream(365) ret: 0[  336.675273] px6130 10-0036: PX6130_set_mode(239) ret: 0[  336.675284] px6130 10-0036: PX6130_stream_on(254) ret: 0[  336.675299] px6130 10-0036: dbg_info: PX6130_s_ctrl, line: 685, id: 10356994[  336.675310] px6130 10-0036: V4L2_CID_HBLANK val:1195[  336.675319] px6130 10-0036: dbg_info: PX6130_s_ctrl, line: 685, id: 10356993[  336.675329] px6130 10-0036: V4L2_CID_VBLANK val:40[  336.675338] px6130 10-0036: dbg_info: PX6130_s_ctrl, line: 685, id: 9963796[  336.675348] px6130 10-0036: dbg_info: PX6130_s_ctrl, line: 685, id: 9963797[  336.675358] px6130 10-0036: V4L2_CID_VFLIP val:0[  336.675366] px6130 10-0036: PX6130_stream_on(262): ret 0[  336.675375] px6130 10-0036: PX6130_s_stream(372) ret: 0[  336.675384] px6130 10-0036: dbg_info: PX6130_s_stream, line: 389[  336.675429] px6130 10-0036: PX6130_get_pad_fmt(484), fmt: 1[  336.675439] px6130 10-0036: size(1280, 960), code: 8200, fld: 1, color: 1, yuv_enc: 0, hsv_enc: 0[  336.675452] px6130 10-0036: PX6130_get_mbus_code, 424[  337.196646] px6130 10-0036: dbg_info: PX6130_s_stream, line: 354, enable: 0(1)[  337.196668] px6130 10-0036: dbg_info: PX6130_s_stream, line: 378[  337.196672] px6130 10-0036: PX6130_stream_off(273)[  337.196676] px6130 10-0036: dbg_info: PX6130_s_stream, line: 389
I have also attached the image data received via MIPI. I would greatly appreciate it if you could help me resolve this problem.

Thank you.
actual_img.jpg

configuration.png

received_img.png

Statistics: Posted by stupid dog — Fri Nov 29, 2024 10:56 am — Replies 0 — Views 32



Viewing all articles
Browse latest Browse all 4387

Trending Articles