From 1543e317f1da31b75942316931e8f491a8920811 Mon Sep 17 00:00:00 2001
From: hc <hc@nodka.com>
Date: Thu, 04 Jan 2024 10:08:02 +0000
Subject: [PATCH] disable FB
---
kernel/drivers/media/platform/rockchip/cif/mipi-csi2.c | 889 +++++++++++++++++++++++++++++++++++++---------------------
1 files changed, 568 insertions(+), 321 deletions(-)
diff --git a/kernel/drivers/media/platform/rockchip/cif/mipi-csi2.c b/kernel/drivers/media/platform/rockchip/cif/mipi-csi2.c
index f06a238..57d8166 100644
--- a/kernel/drivers/media/platform/rockchip/cif/mipi-csi2.c
+++ b/kernel/drivers/media/platform/rockchip/cif/mipi-csi2.c
@@ -13,159 +13,21 @@
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_graph.h>
+#include <linux/of_platform.h>
#include <linux/platform_device.h>
#include <linux/reset.h>
-#include <media/v4l2-device.h>
-#include <media/v4l2-fwnode.h>
-#include <media/v4l2-subdev.h>
-#include <media/v4l2-event.h>
#include <linux/rk-camera-module.h>
#include <media/v4l2-ioctl.h>
#include "mipi-csi2.h"
+#include <linux/regulator/consumer.h>
static int csi2_debug;
module_param_named(debug_csi2, csi2_debug, int, 0644);
MODULE_PARM_DESC(debug_csi2, "Debug level (0-1)");
-/*
- * there must be 5 pads: 1 input pad from sensor, and
- * the 4 virtual channel output pads
- */
-#define CSI2_SINK_PAD 0
-#define CSI2_NUM_SINK_PADS 1
-#define CSI2_NUM_SRC_PADS 4
-#define CSI2_NUM_PADS 5
-#define CSI2_NUM_PADS_SINGLE_LINK 2
-#define MAX_CSI2_SENSORS 2
-
-#define RKCIF_DEFAULT_WIDTH 640
-#define RKCIF_DEFAULT_HEIGHT 480
-
-/*
- * The default maximum bit-rate per lane in Mbps, if the
- * source subdev does not provide V4L2_CID_LINK_FREQ.
- */
-#define CSI2_DEFAULT_MAX_MBPS 849
-
-#define IMX_MEDIA_GRP_ID_CSI2 BIT(8)
-#define CSIHOST_MAX_ERRINT_COUNT 10
-
-/*
- * add new chip id in tail in time order
- * by increasing to distinguish csi2 host version
- */
-enum rkcsi2_chip_id {
- CHIP_PX30_CSI2,
- CHIP_RK1808_CSI2,
- CHIP_RK3128_CSI2,
- CHIP_RK3288_CSI2,
- CHIP_RV1126_CSI2,
- CHIP_RK3568_CSI2,
-};
-
-enum csi2_pads {
- RK_CSI2_PAD_SINK = 0,
- RK_CSI2X_PAD_SOURCE0,
- RK_CSI2X_PAD_SOURCE1,
- RK_CSI2X_PAD_SOURCE2,
- RK_CSI2X_PAD_SOURCE3
-};
-
-enum csi2_err {
- RK_CSI2_ERR_SOTSYN = 0x0,
- RK_CSI2_ERR_FS_FE_MIS,
- RK_CSI2_ERR_FRM_SEQ_ERR,
- RK_CSI2_ERR_CRC_ONCE,
- RK_CSI2_ERR_CRC,
- RK_CSI2_ERR_ALL,
- RK_CSI2_ERR_MAX
-};
-
-enum host_type_t {
- RK_CSI_RXHOST,
- RK_DSI_RXHOST
-};
-
-struct csi2_match_data {
- int chip_id;
- int num_pads;
-};
-
-struct csi2_sensor {
- struct v4l2_subdev *sd;
- struct v4l2_mbus_config mbus;
- int lanes;
-};
-
-struct csi2_err_stats {
- unsigned int cnt;
-};
-
-struct csi2_dev {
- struct device *dev;
- struct v4l2_subdev sd;
- struct media_pad pad[CSI2_NUM_PADS];
- struct clk_bulk_data *clks_bulk;
- int clks_num;
- struct reset_control *rsts_bulk;
-
- void __iomem *base;
- struct v4l2_async_notifier notifier;
- struct v4l2_fwnode_bus_mipi_csi2 bus;
-
- /* lock to protect all members below */
- struct mutex lock;
-
- struct v4l2_mbus_framefmt format_mbus;
- struct v4l2_rect crop;
- int stream_count;
- struct v4l2_subdev *src_sd;
- bool sink_linked[CSI2_NUM_SRC_PADS];
- struct csi2_sensor sensors[MAX_CSI2_SENSORS];
- const struct csi2_match_data *match_data;
- int num_sensors;
- atomic_t frm_sync_seq;
- struct csi2_err_stats err_list[RK_CSI2_ERR_MAX];
- int dsi_input_en;
-};
-
-#define DEVICE_NAME "rockchip-mipi-csi2"
-
-/* CSI Host Registers Define */
-#define CSIHOST_N_LANES 0x04
-#define CSIHOST_DPHY_SHUTDOWNZ 0x08
-#define CSIHOST_PHY_RSTZ 0x0c
-#define CSIHOST_RESETN 0x10
-#define CSIHOST_PHY_STATE 0x14
-#define CSIHOST_ERR1 0x20
-#define CSIHOST_ERR2 0x24
-#define CSIHOST_MSK1 0x28
-#define CSIHOST_MSK2 0x2c
-#define CSIHOST_CONTROL 0x40
-
-#define CSIHOST_ERR1_PHYERR_SPTSYNCHS 0x0000000f
-#define CSIHOST_ERR1_ERR_BNDRY_MATCH 0x000000f0
-#define CSIHOST_ERR1_ERR_SEQ 0x00000f00
-#define CSIHOST_ERR1_ERR_FRM_DATA 0x0000f000
-#define CSIHOST_ERR1_ERR_CRC 0x1f000000
-
-#define CSIHOST_ERR2_PHYERR_ESC 0x0000000f
-#define CSIHOST_ERR2_PHYERR_SOTHS 0x000000f0
-#define CSIHOST_ERR2_ECC_CORRECTED 0x00000f00
-#define CSIHOST_ERR2_ERR_ID 0x0000f000
-#define CSIHOST_ERR2_PHYERR_CODEHS 0x01000000
-
-#define SW_CPHY_EN(x) ((x) << 0)
-#define SW_DSI_EN(x) ((x) << 4)
-#define SW_DATATYPE_FS(x) ((x) << 8)
-#define SW_DATATYPE_FE(x) ((x) << 14)
-#define SW_DATATYPE_LS(x) ((x) << 20)
-#define SW_DATATYPE_LE(x) ((x) << 26)
-
#define write_csihost_reg(base, addr, val) writel(val, (addr) + (base))
#define read_csihost_reg(base, addr) readl((addr) + (base))
-static struct csi2_dev *g_csi2_dev;
static ATOMIC_NOTIFIER_HEAD(g_csi_host_chain);
int rkcif_csi2_register_notifier(struct notifier_block *nb)
@@ -183,7 +45,7 @@
return container_of(sdev, struct csi2_dev, sd);
}
-static struct csi2_sensor *sd_to_sensor(struct csi2_dev *csi2,
+static struct csi2_sensor_info *sd_to_sensor(struct csi2_dev *csi2,
struct v4l2_subdev *sd)
{
int i;
@@ -227,6 +89,7 @@
*sensor_sd = NULL;
return;
}
+
media_graph_walk_start(&graph, entity);
while ((entity = media_graph_walk_next(&graph))) {
if (entity->function == MEDIA_ENT_F_CAM_SENSOR)
@@ -234,6 +97,7 @@
}
mutex_unlock(&mdev->graph_mutex);
media_graph_walk_cleanup(&graph);
+
if (entity)
*sensor_sd = media_entity_to_v4l2_subdev(entity);
else
@@ -242,24 +106,25 @@
static void csi2_update_sensor_info(struct csi2_dev *csi2)
{
- struct csi2_sensor *sensor = &csi2->sensors[0];
struct v4l2_subdev *terminal_sensor_sd = NULL;
+ struct csi2_sensor_info *sensor = &csi2->sensors[0];
struct v4l2_mbus_config mbus;
int ret = 0;
- ret = v4l2_subdev_call(sensor->sd, video, g_mbus_config, &mbus);
+ ret = v4l2_subdev_call(sensor->sd, pad, get_mbus_config, 0, &mbus);
if (ret) {
v4l2_err(&csi2->sd, "update sensor info failed!\n");
return;
}
get_remote_terminal_sensor(&csi2->sd, &terminal_sensor_sd);
- if (terminal_sensor_sd) {
- ret = v4l2_subdev_call(terminal_sensor_sd, core, ioctl,
- RKMODULE_GET_CSI_DSI_INFO, &csi2->dsi_input_en);
- if (ret)
- csi2->dsi_input_en = 0;
+ ret = v4l2_subdev_call(terminal_sensor_sd, core, ioctl,
+ RKMODULE_GET_CSI_DSI_INFO, &csi2->dsi_input_en);
+ if (ret) {
+ v4l2_dbg(1, csi2_debug, &csi2->sd, "get CSI/DSI sel failed, default csi!\n");
+ csi2->dsi_input_en = 0;
}
+
csi2->bus.flags = mbus.flags;
switch (csi2->bus.flags & V4L2_MBUS_CSI2_LANES) {
case V4L2_MBUS_CSI2_1_LANE:
@@ -276,67 +141,89 @@
break;
default:
v4l2_warn(&csi2->sd, "lane num is invalid\n");
- csi2->bus.num_data_lanes = 0;
+ csi2->bus.num_data_lanes = 4;
break;
}
}
-static void csi2_hw_do_reset(struct csi2_dev *csi2)
+static void csi2_hw_do_reset(struct csi2_hw *csi2_hw)
{
- reset_control_assert(csi2->rsts_bulk);
+
+ if (!csi2_hw->rsts_bulk)
+ return;
+
+ reset_control_assert(csi2_hw->rsts_bulk);
udelay(5);
- reset_control_deassert(csi2->rsts_bulk);
+ reset_control_deassert(csi2_hw->rsts_bulk);
}
-static int csi2_enable_clks(struct csi2_dev *csi2)
+static int csi2_enable_clks(struct csi2_hw *csi2_hw)
{
int ret = 0;
- ret = clk_bulk_prepare_enable(csi2->clks_num, csi2->clks_bulk);
+ if (!csi2_hw->clks_bulk)
+ return -EINVAL;
+
+ ret = clk_bulk_prepare_enable(csi2_hw->clks_num, csi2_hw->clks_bulk);
if (ret)
- dev_err(csi2->dev, "failed to enable clks\n");
+ dev_err(csi2_hw->dev, "failed to enable clks\n");
return ret;
}
-static void csi2_disable_clks(struct csi2_dev *csi2)
+static void csi2_disable_clks(struct csi2_hw *csi2_hw)
{
- clk_bulk_disable_unprepare(csi2->clks_num, csi2->clks_bulk);
+ if (!csi2_hw->clks_bulk)
+ return;
+ clk_bulk_disable_unprepare(csi2_hw->clks_num, csi2_hw->clks_bulk);
}
-static void csi2_disable(struct csi2_dev *csi2)
+static void csi2_disable(struct csi2_hw *csi2_hw)
{
- void __iomem *base = csi2->base;
-
- write_csihost_reg(base, CSIHOST_RESETN, 0);
- write_csihost_reg(base, CSIHOST_MSK1, 0xffffffff);
- write_csihost_reg(base, CSIHOST_MSK2, 0xffffffff);
+ write_csihost_reg(csi2_hw->base, CSIHOST_RESETN, 0);
+ write_csihost_reg(csi2_hw->base, CSIHOST_MSK1, 0xffffffff);
+ write_csihost_reg(csi2_hw->base, CSIHOST_MSK2, 0xffffffff);
}
-static void csi2_enable(struct csi2_dev *csi2,
+static int csi2_g_mbus_config(struct v4l2_subdev *sd, unsigned int pad_id,
+ struct v4l2_mbus_config *mbus);
+
+static void csi2_enable(struct csi2_hw *csi2_hw,
enum host_type_t host_type)
{
- void __iomem *base = csi2->base;
+ void __iomem *base = csi2_hw->base;
+ struct csi2_dev *csi2 = csi2_hw->csi2;
int lanes = csi2->bus.num_data_lanes;
+ struct v4l2_mbus_config mbus;
+ u32 val = 0;
+
+ csi2_g_mbus_config(&csi2->sd, 0, &mbus);
+ if (mbus.type == V4L2_MBUS_CSI2_DPHY)
+ val = SW_CPHY_EN(0);
+ else if (mbus.type == V4L2_MBUS_CSI2_CPHY)
+ val = SW_CPHY_EN(1);
write_csihost_reg(base, CSIHOST_N_LANES, lanes - 1);
if (host_type == RK_DSI_RXHOST) {
- write_csihost_reg(base, CSIHOST_CONTROL,
- SW_CPHY_EN(0) | SW_DSI_EN(1) |
- SW_DATATYPE_FS(0x01) | SW_DATATYPE_FE(0x11) |
- SW_DATATYPE_LS(0x21) | SW_DATATYPE_LE(0x31));
+ val |= SW_DSI_EN(1) | SW_DATATYPE_FS(0x01) |
+ SW_DATATYPE_FE(0x11) | SW_DATATYPE_LS(0x21) |
+ SW_DATATYPE_LE(0x31);
+ write_csihost_reg(base, CSIHOST_CONTROL, val);
/* Disable some error interrupt when HOST work on DSI RX mode */
write_csihost_reg(base, CSIHOST_MSK1, 0xe00000f0);
write_csihost_reg(base, CSIHOST_MSK2, 0xff00);
} else {
- write_csihost_reg(base, CSIHOST_CONTROL,
- SW_CPHY_EN(0) | SW_DSI_EN(0));
- write_csihost_reg(base, CSIHOST_MSK1, 0);
+ val |= SW_DSI_EN(0) | SW_DATATYPE_FS(0x0) |
+ SW_DATATYPE_FE(0x01) | SW_DATATYPE_LS(0x02) |
+ SW_DATATYPE_LE(0x03);
+ write_csihost_reg(base, CSIHOST_CONTROL, val);
+ write_csihost_reg(base, CSIHOST_MSK1, 0x0);
write_csihost_reg(base, CSIHOST_MSK2, 0xf000);
+ csi2->is_check_sot_sync = true;
}
write_csihost_reg(base, CSIHOST_RESETN, 1);
@@ -346,15 +233,9 @@
{
enum host_type_t host_type;
int ret, i;
+ int csi_idx = 0;
atomic_set(&csi2->frm_sync_seq, 0);
-
- csi2_hw_do_reset(csi2);
- ret = csi2_enable_clks(csi2);
- if (ret) {
- v4l2_err(&csi2->sd, "%s: enable clks failed\n", __func__);
- return ret;
- }
csi2_update_sensor_info(csi2);
@@ -363,7 +244,18 @@
else
host_type = RK_CSI_RXHOST;
- csi2_enable(csi2, host_type);
+ for (i = 0; i < csi2->csi_info.csi_num; i++) {
+ csi_idx = csi2->csi_info.csi_idx[i];
+ csi2_hw_do_reset(csi2->csi2_hw[csi_idx]);
+ ret = csi2_enable_clks(csi2->csi2_hw[csi_idx]);
+ if (ret) {
+ v4l2_err(&csi2->sd, "%s: enable clks failed\n", __func__);
+ return ret;
+ }
+ enable_irq(csi2->csi2_hw[csi_idx]->irq1);
+ enable_irq(csi2->csi2_hw[csi_idx]->irq2);
+ csi2_enable(csi2->csi2_hw[csi_idx], host_type);
+ }
pr_debug("stream sd: %s\n", csi2->src_sd->name);
ret = v4l2_subdev_call(csi2->src_sd, video, s_stream, 1);
@@ -377,20 +269,33 @@
return 0;
err_assert_reset:
- csi2_disable(csi2);
- csi2_disable_clks(csi2);
+ for (i = 0; i < csi2->csi_info.csi_num; i++) {
+ csi_idx = csi2->csi_info.csi_idx[i];
+ disable_irq(csi2->csi2_hw[csi_idx]->irq1);
+ disable_irq(csi2->csi2_hw[csi_idx]->irq2);
+ csi2_disable(csi2->csi2_hw[csi_idx]);
+ csi2_disable_clks(csi2->csi2_hw[csi_idx]);
+ }
return ret;
}
static void csi2_stop(struct csi2_dev *csi2)
{
+ int i = 0;
+ int csi_idx = 0;
+
/* stop upstream */
v4l2_subdev_call(csi2->src_sd, video, s_stream, 0);
- csi2_disable(csi2);
- csi2_hw_do_reset(csi2);
- csi2_disable_clks(csi2);
+ for (i = 0; i < csi2->csi_info.csi_num; i++) {
+ csi_idx = csi2->csi_info.csi_idx[i];
+ disable_irq(csi2->csi2_hw[csi_idx]->irq1);
+ disable_irq(csi2->csi2_hw[csi_idx]->irq2);
+ csi2_disable(csi2->csi2_hw[csi_idx]);
+ csi2_hw_do_reset(csi2->csi2_hw[csi_idx]);
+ csi2_disable_clks(csi2->csi2_hw[csi_idx]);
+ }
}
/*
@@ -500,6 +405,7 @@
csi2->crop.left = 0;
csi2->crop.width = RKCIF_DEFAULT_WIDTH;
csi2->crop.height = RKCIF_DEFAULT_HEIGHT;
+ csi2->bus.num_data_lanes = 4;
return media_entity_pads_init(&sd->entity, num_pads, csi2->pad);
}
@@ -556,10 +462,12 @@
switch (sel->target) {
case V4L2_SEL_TGT_CROP_BOUNDS:
if (sel->which == V4L2_SUBDEV_FORMAT_ACTIVE) {
+ sel->pad = 0;
ret = v4l2_subdev_call(sensor, pad, get_selection,
cfg, sel);
if (ret) {
fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE;
+ fmt.pad = 0;
ret = v4l2_subdev_call(sensor, pad, get_fmt, NULL, &fmt);
if (!ret) {
csi2->format_mbus = fmt.format;
@@ -608,16 +516,16 @@
return ret;
}
-static int csi2_g_mbus_config(struct v4l2_subdev *sd,
+static int csi2_g_mbus_config(struct v4l2_subdev *sd, unsigned int pad_id,
struct v4l2_mbus_config *mbus)
{
struct csi2_dev *csi2 = sd_to_dev(sd);
struct v4l2_subdev *sensor_sd = get_remote_sensor(sd);
int ret;
- ret = v4l2_subdev_call(sensor_sd, video, g_mbus_config, mbus);
+ ret = v4l2_subdev_call(sensor_sd, pad, get_mbus_config, 0, mbus);
if (ret) {
- mbus->type = V4L2_MBUS_CSI2;
+ mbus->type = V4L2_MBUS_CSI2_DPHY;
mbus->flags = csi2->bus.flags;
mbus->flags |= BIT(csi2->bus.num_data_lanes - 1);
}
@@ -630,50 +538,118 @@
.link_validate = v4l2_subdev_link_validate,
};
-void rkcif_csi2_event_inc_sof(void)
+void rkcif_csi2_event_reset_pipe(struct csi2_dev *csi2_dev, int reset_src)
{
- if (g_csi2_dev) {
+ if (csi2_dev) {
struct v4l2_event event = {
- .type = V4L2_EVENT_FRAME_SYNC,
- .u.frame_sync.frame_sequence =
- atomic_inc_return(&g_csi2_dev->frm_sync_seq) - 1,
+ .type = V4L2_EVENT_RESET_DEV,
+ .reserved[0] = reset_src,
};
- v4l2_event_queue(g_csi2_dev->sd.devnode, &event);
+ v4l2_event_queue(csi2_dev->sd.devnode, &event);
}
}
-u32 rkcif_csi2_get_sof(void)
+void rkcif_csi2_event_inc_sof(struct csi2_dev *csi2_dev)
{
- if (g_csi2_dev) {
- return atomic_read(&g_csi2_dev->frm_sync_seq) - 1;
+ if (csi2_dev) {
+ struct v4l2_event event = {
+ .type = V4L2_EVENT_FRAME_SYNC,
+ .u.frame_sync.frame_sequence =
+ atomic_inc_return(&csi2_dev->frm_sync_seq) - 1,
+ };
+ v4l2_event_queue(csi2_dev->sd.devnode, &event);
}
+}
+
+u32 rkcif_csi2_get_sof(struct csi2_dev *csi2_dev)
+{
+ if (csi2_dev)
+ return atomic_read(&csi2_dev->frm_sync_seq) - 1;
return 0;
}
-void rkcif_csi2_set_sof(u32 seq)
+void rkcif_csi2_set_sof(struct csi2_dev *csi2_dev, u32 seq)
{
- if (g_csi2_dev) {
- atomic_set(&g_csi2_dev->frm_sync_seq, seq);
- }
+ if (csi2_dev)
+ atomic_set(&csi2_dev->frm_sync_seq, seq);
}
static int rkcif_csi2_subscribe_event(struct v4l2_subdev *sd, struct v4l2_fh *fh,
struct v4l2_event_subscription *sub)
{
- if (sub->type != V4L2_EVENT_FRAME_SYNC)
+ if (sub->type == V4L2_EVENT_FRAME_SYNC ||
+ sub->type == V4L2_EVENT_RESET_DEV)
+ return v4l2_event_subscribe(fh, sub, RKCIF_V4L2_EVENT_ELEMS, NULL);
+ else
return -EINVAL;
-
- return v4l2_event_subscribe(fh, sub, 0, NULL);
}
+
+static int rkcif_csi2_s_power(struct v4l2_subdev *sd, int on)
+{
+ return 0;
+}
+
+static long rkcif_csi2_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg)
+{
+ struct csi2_dev *csi2 = sd_to_dev(sd);
+ struct v4l2_subdev *sensor = get_remote_sensor(sd);
+ long ret = 0;
+ int i = 0;
+
+ switch (cmd) {
+ case RKCIF_CMD_SET_CSI_IDX:
+ csi2->csi_info = *((struct rkcif_csi_info *)arg);
+ for (i = 0; i < csi2->csi_info.csi_num; i++)
+ csi2->csi2_hw[csi2->csi_info.csi_idx[i]]->csi2 = csi2;
+ if (csi2->match_data->chip_id > CHIP_RV1126_CSI2)
+ ret = v4l2_subdev_call(sensor, core, ioctl,
+ RKCIF_CMD_SET_CSI_IDX,
+ arg);
+ break;
+ default:
+ ret = -ENOIOCTLCMD;
+ break;
+ }
+
+ return ret;
+}
+
+#ifdef CONFIG_COMPAT
+static long rkcif_csi2_compat_ioctl32(struct v4l2_subdev *sd,
+ unsigned int cmd, unsigned long arg)
+{
+ void __user *up = compat_ptr(arg);
+ struct rkcif_csi_info csi_info;
+ long ret;
+
+ switch (cmd) {
+ case RKCIF_CMD_SET_CSI_IDX:
+ if (copy_from_user(&csi_info, up, sizeof(struct rkcif_csi_info)))
+ return -EFAULT;
+
+ ret = rkcif_csi2_ioctl(sd, cmd, &csi_info);
+ break;
+ default:
+ ret = -ENOIOCTLCMD;
+ break;
+ }
+
+ return ret;
+}
+#endif
static const struct v4l2_subdev_core_ops csi2_core_ops = {
.subscribe_event = rkcif_csi2_subscribe_event,
.unsubscribe_event = v4l2_event_subdev_unsubscribe,
+ .s_power = rkcif_csi2_s_power,
+ .ioctl = rkcif_csi2_ioctl,
+#ifdef CONFIG_COMPAT
+ .compat_ioctl32 = rkcif_csi2_compat_ioctl32,
+#endif
};
static const struct v4l2_subdev_video_ops csi2_video_ops = {
- .g_mbus_config = csi2_g_mbus_config,
.s_stream = csi2_s_stream,
};
@@ -682,6 +658,7 @@
.set_fmt = csi2_get_set_fmt,
.get_selection = csi2_get_selection,
.set_selection = csi2_set_selection,
+ .get_mbus_config = csi2_g_mbus_config,
};
static const struct v4l2_subdev_ops csi2_subdev_ops = {
@@ -694,15 +671,10 @@
struct v4l2_fwnode_endpoint *vep,
struct v4l2_async_subdev *asd)
{
- struct v4l2_subdev *sd = dev_get_drvdata(dev);
- struct csi2_dev *csi2 = sd_to_dev(sd);
-
if (vep->base.port != 0) {
dev_err(dev, "The csi host node needs to parse port 0\n");
return -EINVAL;
}
-
- csi2->bus = vep->bus.mipi_csi2;
return 0;
}
@@ -716,7 +688,7 @@
struct csi2_dev *csi2 = container_of(notifier,
struct csi2_dev,
notifier);
- struct csi2_sensor *sensor;
+ struct csi2_sensor_info *sensor;
struct media_link *link;
unsigned int pad, ret;
@@ -772,10 +744,10 @@
struct csi2_dev *csi2 = container_of(notifier,
struct csi2_dev,
notifier);
- struct csi2_sensor *sensor = sd_to_sensor(csi2, sd);
+ struct csi2_sensor_info *sensor = sd_to_sensor(csi2, sd);
- sensor->sd = NULL;
-
+ if (sensor)
+ sensor->sd = NULL;
}
static const struct
@@ -784,65 +756,133 @@
.unbind = csi2_notifier_unbind,
};
+static void csi2_find_err_vc(int val, char *vc_info)
+{
+ int i;
+ char cur_str[CSI_VCINFO_LEN] = {0};
+
+ memset(vc_info, 0, sizeof(*vc_info));
+ for (i = 0; i < 4; i++) {
+ if ((val >> i) & 0x1) {
+ snprintf(cur_str, CSI_VCINFO_LEN, " %d", i);
+ if (strlen(vc_info) + strlen(cur_str) < CSI_VCINFO_LEN)
+ strncat(vc_info, cur_str, strlen(cur_str));
+ }
+ }
+}
+
+#define csi2_err_strncat(dst_str, src_str) {\
+ if (strlen(dst_str) + strlen(src_str) < CSI_ERRSTR_LEN)\
+ strncat(dst_str, src_str, strlen(src_str)); }
+
static irqreturn_t rk_csirx_irq1_handler(int irq, void *ctx)
{
struct device *dev = ctx;
- struct csi2_dev *csi2 = sd_to_dev(dev_get_drvdata(dev));
+ struct csi2_hw *csi2_hw = dev_get_drvdata(dev);
+ struct csi2_dev *csi2 = NULL;
struct csi2_err_stats *err_list = NULL;
unsigned long err_stat = 0;
u32 val;
+ char err_str[CSI_ERRSTR_LEN] = {0};
+ char cur_str[CSI_ERRSTR_LEN] = {0};
+ char vc_info[CSI_VCINFO_LEN] = {0};
+ bool is_add_cnt = false;
- val = read_csihost_reg(csi2->base, CSIHOST_ERR1);
+ if (!csi2_hw) {
+ disable_irq_nosync(irq);
+ return IRQ_HANDLED;
+ }
+
+ csi2 = csi2_hw->csi2;
+ if (!csi2) {
+ disable_irq_nosync(irq);
+ return IRQ_HANDLED;
+ }
+ val = read_csihost_reg(csi2_hw->base, CSIHOST_ERR1);
if (val) {
- write_csihost_reg(csi2->base,
- CSIHOST_ERR1, 0x0);
-
if (val & CSIHOST_ERR1_PHYERR_SPTSYNCHS) {
err_list = &csi2->err_list[RK_CSI2_ERR_SOTSYN];
err_list->cnt++;
- v4l2_err(&csi2->sd,
- "ERR1: start of transmission error(no synchronization achieved), reg: 0x%x,cnt:%d\n",
- val, err_list->cnt);
+ if (csi2->match_data->chip_id == CHIP_RK3588_CSI2) {
+ if (err_list->cnt > 3 &&
+ csi2->err_list[RK_CSI2_ERR_ALL].cnt <= err_list->cnt) {
+ csi2->is_check_sot_sync = false;
+ write_csihost_reg(csi2_hw->base, CSIHOST_MSK1, 0xf);
+ }
+ if (csi2->is_check_sot_sync) {
+ csi2_find_err_vc(val & 0xf, vc_info);
+ snprintf(cur_str, CSI_ERRSTR_LEN, "(sot sync,lane:%s) ", vc_info);
+ csi2_err_strncat(err_str, cur_str);
+ }
+ } else {
+ csi2_find_err_vc(val & 0xf, vc_info);
+ snprintf(cur_str, CSI_ERRSTR_LEN, "(sot sync,lane:%s) ", vc_info);
+ csi2_err_strncat(err_str, cur_str);
+ is_add_cnt = true;
+ }
}
if (val & CSIHOST_ERR1_ERR_BNDRY_MATCH) {
err_list = &csi2->err_list[RK_CSI2_ERR_FS_FE_MIS];
err_list->cnt++;
- v4l2_err(&csi2->sd,
- "ERR1: error matching frame start with frame end, reg: 0x%x,cnt:%d\n",
- val, err_list->cnt);
+ csi2_find_err_vc((val >> 4) & 0xf, vc_info);
+ snprintf(cur_str, CSI_ERRSTR_LEN, "(fs/fe mis,vc:%s) ", vc_info);
+ csi2_err_strncat(err_str, cur_str);
+ if (csi2->match_data->chip_id < CHIP_RK3588_CSI2)
+ is_add_cnt = true;
}
if (val & CSIHOST_ERR1_ERR_SEQ) {
err_list = &csi2->err_list[RK_CSI2_ERR_FRM_SEQ_ERR];
err_list->cnt++;
- v4l2_err(&csi2->sd,
- "ERR1: incorrect frame sequence detected, reg: 0x%x,cnt:%d\n",
- val, err_list->cnt);
+ csi2_find_err_vc((val >> 8) & 0xf, vc_info);
+ snprintf(cur_str, CSI_ERRSTR_LEN, "(f_seq,vc:%s) ", vc_info);
+ csi2_err_strncat(err_str, cur_str);
}
if (val & CSIHOST_ERR1_ERR_FRM_DATA) {
err_list = &csi2->err_list[RK_CSI2_ERR_CRC_ONCE];
+ is_add_cnt = true;
err_list->cnt++;
- v4l2_dbg(1, csi2_debug, &csi2->sd,
- "ERR1: at least one crc error, reg: 0x%x\n,cnt:%d", val, err_list->cnt);
+ csi2_find_err_vc((val >> 12) & 0xf, vc_info);
+ snprintf(cur_str, CSI_ERRSTR_LEN, "(err_data,vc:%s) ", vc_info);
+ csi2_err_strncat(err_str, cur_str);
}
if (val & CSIHOST_ERR1_ERR_CRC) {
err_list = &csi2->err_list[RK_CSI2_ERR_CRC];
err_list->cnt++;
- v4l2_err(&csi2->sd,
- "ERR1: crc errors, reg: 0x%x, cnt:%d\n",
- val, err_list->cnt);
+ is_add_cnt = true;
+ csi2_find_err_vc((val >> 24) & 0xf, vc_info);
+ snprintf(cur_str, CSI_ERRSTR_LEN, "(crc,vc:%s) ", vc_info);
+ csi2_err_strncat(err_str, cur_str);
}
- csi2->err_list[RK_CSI2_ERR_ALL].cnt++;
- err_stat = ((csi2->err_list[RK_CSI2_ERR_FS_FE_MIS].cnt & 0xff) << 8) |
- ((csi2->err_list[RK_CSI2_ERR_ALL].cnt) & 0xff);
+ if (val & CSIHOST_ERR1_ERR_ECC2) {
+ err_list = &csi2->err_list[RK_CSI2_ERR_CRC];
+ err_list->cnt++;
+ is_add_cnt = true;
+ snprintf(cur_str, CSI_ERRSTR_LEN, "(ecc2) ");
+ csi2_err_strncat(err_str, cur_str);
+ }
- atomic_notifier_call_chain(&g_csi_host_chain,
- err_stat,
- NULL);
+ if (val & CSIHOST_ERR1_ERR_CTRL) {
+ csi2_find_err_vc((val >> 16) & 0xf, vc_info);
+ snprintf(cur_str, CSI_ERRSTR_LEN, "(ctrl,vc:%s) ", vc_info);
+ csi2_err_strncat(err_str, cur_str);
+ }
+
+ pr_err("%s ERR1:0x%x %s\n", csi2_hw->dev_name, val, err_str);
+
+ if (is_add_cnt) {
+ csi2->err_list[RK_CSI2_ERR_ALL].cnt++;
+ err_stat = ((csi2->err_list[RK_CSI2_ERR_FS_FE_MIS].cnt & 0xff) << 8) |
+ ((csi2->err_list[RK_CSI2_ERR_ALL].cnt) & 0xff);
+
+ atomic_notifier_call_chain(&g_csi_host_chain,
+ err_stat,
+ &csi2->csi_info.csi_idx[csi2->csi_info.csi_num - 1]);
+ }
}
@@ -852,27 +892,45 @@
static irqreturn_t rk_csirx_irq2_handler(int irq, void *ctx)
{
struct device *dev = ctx;
- struct csi2_dev *csi2 = sd_to_dev(dev_get_drvdata(dev));
+ struct csi2_hw *csi2_hw = dev_get_drvdata(dev);
u32 val;
+ char cur_str[CSI_ERRSTR_LEN] = {0};
+ char err_str[CSI_ERRSTR_LEN] = {0};
+ char vc_info[CSI_VCINFO_LEN] = {0};
- val = read_csihost_reg(csi2->base, CSIHOST_ERR2);
+ if (!csi2_hw) {
+ disable_irq_nosync(irq);
+ return IRQ_HANDLED;
+ }
+
+ val = read_csihost_reg(csi2_hw->base, CSIHOST_ERR2);
if (val) {
- if (val & CSIHOST_ERR2_PHYERR_ESC)
- v4l2_err(&csi2->sd, "ERR2: escape entry error(ULPM), reg: 0x%x\n", val);
- if (val & CSIHOST_ERR2_PHYERR_SOTHS)
- v4l2_err(&csi2->sd,
- "ERR2: start of transmission error(synchronization can still be achieved), reg: 0x%x\n",
- val);
- if (val & CSIHOST_ERR2_ECC_CORRECTED)
- v4l2_dbg(1, csi2_debug, &csi2->sd,
- "ERR2: header error detected and corrected, reg: 0x%x\n",
- val);
- if (val & CSIHOST_ERR2_ERR_ID)
- v4l2_err(&csi2->sd,
- "ERR2: unrecognized or unimplemented data type detected, reg: 0x%x\n",
- val);
- if (val & CSIHOST_ERR2_PHYERR_CODEHS)
- v4l2_err(&csi2->sd, "ERR2: receiv error code, reg: 0x%x\n", val);
+ if (val & CSIHOST_ERR2_PHYERR_ESC) {
+ csi2_find_err_vc(val & 0xf, vc_info);
+ snprintf(cur_str, CSI_ERRSTR_LEN, "(ULPM,lane:%s) ", vc_info);
+ csi2_err_strncat(err_str, cur_str);
+ }
+ if (val & CSIHOST_ERR2_PHYERR_SOTHS) {
+ csi2_find_err_vc((val >> 4) & 0xf, vc_info);
+ snprintf(cur_str, CSI_ERRSTR_LEN, "(sot,lane:%s) ", vc_info);
+ csi2_err_strncat(err_str, cur_str);
+ }
+ if (val & CSIHOST_ERR2_ECC_CORRECTED) {
+ csi2_find_err_vc((val >> 8) & 0xf, vc_info);
+ snprintf(cur_str, CSI_ERRSTR_LEN, "(ecc,vc:%s) ", vc_info);
+ csi2_err_strncat(err_str, cur_str);
+ }
+ if (val & CSIHOST_ERR2_ERR_ID) {
+ csi2_find_err_vc((val >> 12) & 0xf, vc_info);
+ snprintf(cur_str, CSI_ERRSTR_LEN, "(err id,vc:%s) ", vc_info);
+ csi2_err_strncat(err_str, cur_str);
+ }
+ if (val & CSIHOST_ERR2_PHYERR_CODEHS) {
+ snprintf(cur_str, CSI_ERRSTR_LEN, "(err code) ");
+ csi2_err_strncat(err_str, cur_str);
+ }
+
+ pr_err("%s ERR2:0x%x %s\n", csi2_hw->dev_name, val, err_str);
}
return IRQ_HANDLED;
@@ -883,15 +941,14 @@
struct v4l2_async_notifier *ntf = &csi2->notifier;
int ret;
+ v4l2_async_notifier_init(ntf);
+
ret = v4l2_async_notifier_parse_fwnode_endpoints_by_port(csi2->dev,
&csi2->notifier,
sizeof(struct v4l2_async_subdev), 0,
csi2_parse_endpoint);
if (ret < 0)
return ret;
-
- if (!ntf->num_subdevs)
- return -ENODEV; /* no endpoint */
csi2->sd.subdev_notifier = &csi2->notifier;
csi2->notifier.ops = &csi2_async_ops;
@@ -912,21 +969,43 @@
static const struct csi2_match_data rk1808_csi2_match_data = {
.chip_id = CHIP_RK1808_CSI2,
.num_pads = CSI2_NUM_PADS,
+ .num_hw = 1,
};
static const struct csi2_match_data rk3288_csi2_match_data = {
.chip_id = CHIP_RK3288_CSI2,
.num_pads = CSI2_NUM_PADS_SINGLE_LINK,
+ .num_hw = 1,
};
static const struct csi2_match_data rv1126_csi2_match_data = {
.chip_id = CHIP_RV1126_CSI2,
.num_pads = CSI2_NUM_PADS,
+ .num_hw = 1,
};
static const struct csi2_match_data rk3568_csi2_match_data = {
.chip_id = CHIP_RK3568_CSI2,
.num_pads = CSI2_NUM_PADS,
+ .num_hw = 1,
+};
+
+static const struct csi2_match_data rk3588_csi2_match_data = {
+ .chip_id = CHIP_RK3588_CSI2,
+ .num_pads = CSI2_NUM_PADS_MAX,
+ .num_hw = 6,
+};
+
+static const struct csi2_match_data rv1106_csi2_match_data = {
+ .chip_id = CHIP_RV1106_CSI2,
+ .num_pads = CSI2_NUM_PADS_MAX,
+ .num_hw = 2,
+};
+
+static const struct csi2_match_data rk3562_csi2_match_data = {
+ .chip_id = CHIP_RK3562_CSI2,
+ .num_pads = CSI2_NUM_PADS_MAX,
+ .num_hw = 4,
};
static const struct of_device_id csi2_dt_ids[] = {
@@ -946,19 +1025,64 @@
.compatible = "rockchip,rv1126-mipi-csi2",
.data = &rv1126_csi2_match_data,
},
+ {
+ .compatible = "rockchip,rk3588-mipi-csi2",
+ .data = &rk3588_csi2_match_data,
+ },
+ {
+ .compatible = "rockchip,rv1106-mipi-csi2",
+ .data = &rv1106_csi2_match_data,
+ },
+ {
+ .compatible = "rockchip,rk3562-mipi-csi2",
+ .data = &rk3562_csi2_match_data,
+ },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, csi2_dt_ids);
+static int csi2_attach_hw(struct csi2_dev *csi2)
+{
+ struct device_node *np;
+ struct platform_device *pdev;
+ struct csi2_hw *hw;
+ int i = 0;
+
+ for (i = 0; i < csi2->match_data->num_hw; i++) {
+ np = of_parse_phandle(csi2->dev->of_node, "rockchip,hw", i);
+ if (!np || !of_device_is_available(np)) {
+ dev_err(csi2->dev, "failed to get csi2 hw node\n");
+ return -ENODEV;
+ }
+
+ pdev = of_find_device_by_node(np);
+ of_node_put(np);
+ if (!pdev) {
+ dev_err(csi2->dev, "failed to get csi2 hw from node\n");
+ return -ENODEV;
+ }
+
+ hw = platform_get_drvdata(pdev);
+ if (!hw) {
+ dev_err(csi2->dev, "failed attach csi2 hw\n");
+ return -EINVAL;
+ }
+
+ hw->csi2 = csi2;
+ csi2->csi2_hw[i] = hw;
+ }
+ dev_info(csi2->dev, "attach to csi2 hw node\n");
+
+ return 0;
+}
+
static int csi2_probe(struct platform_device *pdev)
{
const struct of_device_id *match;
- struct device *dev = &pdev->dev;
struct device_node *node = pdev->dev.of_node;
struct csi2_dev *csi2 = NULL;
- struct resource *res;
const struct csi2_match_data *data;
- int ret, irq;
+ int ret;
match = of_match_node(csi2_dt_ids, node);
if (IS_ERR(match))
@@ -972,6 +1096,7 @@
csi2->dev = &pdev->dev;
csi2->match_data = data;
+ csi2->dev_name = node->name;
v4l2_subdev_init(&csi2->sd, &csi2_subdev_ops);
v4l2_set_subdevdata(&csi2->sd, &pdev->dev);
csi2->sd.entity.ops = &csi2_entity_ops;
@@ -983,59 +1108,11 @@
v4l2_err(&csi2->sd, "failed to copy name\n");
platform_set_drvdata(pdev, &csi2->sd);
- csi2->clks_num = devm_clk_bulk_get_all(dev, &csi2->clks_bulk);
- if (csi2->clks_num < 0)
- dev_err(dev, "failed to get csi2 clks\n");
-
- csi2->rsts_bulk = devm_reset_control_array_get_optional_exclusive(dev);
- if (IS_ERR(csi2->rsts_bulk)) {
- if (PTR_ERR(csi2->rsts_bulk) != -EPROBE_DEFER)
- dev_err(dev, "failed to get csi2 reset\n");
- return PTR_ERR(csi2->rsts_bulk);
+ ret = csi2_attach_hw(csi2);
+ if (ret) {
+ v4l2_err(&csi2->sd, "must enable all mipi csi2 hw node\n");
+ return -EINVAL;
}
-
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- csi2->base = devm_ioremap_resource(&pdev->dev, res);
- if (IS_ERR(csi2->base)) {
- resource_size_t offset = res->start;
- resource_size_t size = resource_size(res);
-
- dev_warn(&pdev->dev, "avoid secondary mipi resource check!\n");
-
- csi2->base = devm_ioremap(&pdev->dev, offset, size);
- if (IS_ERR(csi2->base)) {
- dev_err(&pdev->dev, "Failed to ioremap resource\n");
-
- return PTR_ERR(csi2->base);
- }
- }
-
- irq = platform_get_irq_byname(pdev, "csi-intr1");
- if (irq > 0) {
- ret = devm_request_irq(&pdev->dev, irq,
- rk_csirx_irq1_handler, 0,
- dev_driver_string(&pdev->dev),
- &pdev->dev);
- if (ret < 0)
- v4l2_err(&csi2->sd, "request csi-intr1 irq failed: %d\n",
- ret);
- } else {
- v4l2_err(&csi2->sd, "No found irq csi-intr1\n");
- }
-
- irq = platform_get_irq_byname(pdev, "csi-intr2");
- if (irq > 0) {
- ret = devm_request_irq(&pdev->dev, irq,
- rk_csirx_irq2_handler, 0,
- dev_driver_string(&pdev->dev),
- &pdev->dev);
- if (ret < 0)
- v4l2_err(&csi2->sd, "request csi-intr2 failed: %d\n",
- ret);
- } else {
- v4l2_err(&csi2->sd, "No found irq csi-intr2\n");
- }
-
mutex_init(&csi2->lock);
ret = csi2_media_init(&csi2->sd);
@@ -1044,10 +1121,6 @@
ret = csi2_notifier(csi2);
if (ret)
goto rmmutex;
-
- csi2_hw_do_reset(csi2);
-
- g_csi2_dev = csi2;
v4l2_info(&csi2->sd, "probe success, v4l2_dev:%s!\n", csi2->sd.v4l2_dev->name);
@@ -1079,16 +1152,190 @@
.remove = csi2_remove,
};
-int __init rkcif_csi2_plat_drv_init(void)
+int rkcif_csi2_plat_drv_init(void)
{
return platform_driver_register(&csi2_driver);
}
-void __exit rkcif_csi2_plat_drv_exit(void)
+void rkcif_csi2_plat_drv_exit(void)
{
platform_driver_unregister(&csi2_driver);
}
+static const struct csi2_hw_match_data rk1808_csi2_hw_match_data = {
+ .chip_id = CHIP_RK1808_CSI2,
+};
+
+static const struct csi2_hw_match_data rk3288_csi2_hw_match_data = {
+ .chip_id = CHIP_RK3288_CSI2,
+};
+
+static const struct csi2_hw_match_data rv1126_csi2_hw_match_data = {
+ .chip_id = CHIP_RV1126_CSI2,
+};
+
+static const struct csi2_hw_match_data rk3568_csi2_hw_match_data = {
+ .chip_id = CHIP_RK3568_CSI2,
+};
+
+static const struct csi2_hw_match_data rk3588_csi2_hw_match_data = {
+ .chip_id = CHIP_RK3588_CSI2,
+};
+
+static const struct csi2_hw_match_data rv1106_csi2_hw_match_data = {
+ .chip_id = CHIP_RV1106_CSI2,
+};
+
+static const struct csi2_hw_match_data rk3562_csi2_hw_match_data = {
+ .chip_id = CHIP_RK3562_CSI2,
+};
+
+static const struct of_device_id csi2_hw_ids[] = {
+ {
+ .compatible = "rockchip,rk1808-mipi-csi2-hw",
+ .data = &rk1808_csi2_hw_match_data,
+ },
+ {
+ .compatible = "rockchip,rk3288-mipi-csi2-hw",
+ .data = &rk3288_csi2_hw_match_data,
+ },
+ {
+ .compatible = "rockchip,rk3568-mipi-csi2-hw",
+ .data = &rk3568_csi2_hw_match_data,
+ },
+ {
+ .compatible = "rockchip,rv1126-mipi-csi2-hw",
+ .data = &rv1126_csi2_hw_match_data,
+ },
+ {
+ .compatible = "rockchip,rk3588-mipi-csi2-hw",
+ .data = &rk3588_csi2_hw_match_data,
+ },
+ {
+ .compatible = "rockchip,rv1106-mipi-csi2-hw",
+ .data = &rv1106_csi2_hw_match_data,
+ },
+ {
+ .compatible = "rockchip,rk3562-mipi-csi2-hw",
+ .data = &rk3588_csi2_hw_match_data,
+ },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, csi2_hw_ids);
+
+static int csi2_hw_probe(struct platform_device *pdev)
+{
+ const struct of_device_id *match;
+ struct device *dev = &pdev->dev;
+ struct device_node *node = pdev->dev.of_node;
+ struct csi2_hw *csi2_hw = NULL;
+ struct resource *res;
+ const struct csi2_hw_match_data *data;
+ int ret, irq;
+
+ dev_info(&pdev->dev, "enter mipi csi2 hw probe!\n");
+ match = of_match_node(csi2_hw_ids, node);
+ if (IS_ERR(match))
+ return PTR_ERR(match);
+ data = match->data;
+
+ csi2_hw = devm_kzalloc(&pdev->dev, sizeof(*csi2_hw), GFP_KERNEL);
+ if (!csi2_hw)
+ return -ENOMEM;
+
+ csi2_hw->dev = &pdev->dev;
+ csi2_hw->match_data = data;
+
+ csi2_hw->dev_name = node->name;
+
+ csi2_hw->clks_num = devm_clk_bulk_get_all(dev, &csi2_hw->clks_bulk);
+ if (csi2_hw->clks_num < 0) {
+ csi2_hw->clks_num = 0;
+ dev_err(dev, "failed to get csi2 clks\n");
+ }
+
+ csi2_hw->rsts_bulk = devm_reset_control_array_get_optional_exclusive(dev);
+ if (IS_ERR(csi2_hw->rsts_bulk)) {
+ if (PTR_ERR(csi2_hw->rsts_bulk) != -EPROBE_DEFER)
+ dev_err(dev, "failed to get csi2 reset\n");
+ csi2_hw->rsts_bulk = NULL;
+ }
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ csi2_hw->base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(csi2_hw->base)) {
+ resource_size_t offset = res->start;
+ resource_size_t size = resource_size(res);
+
+ dev_warn(&pdev->dev, "avoid secondary mipi resource check!\n");
+
+ csi2_hw->base = devm_ioremap(&pdev->dev, offset, size);
+ if (IS_ERR(csi2_hw->base)) {
+ dev_err(&pdev->dev, "Failed to ioremap resource\n");
+
+ return PTR_ERR(csi2_hw->base);
+ }
+ }
+
+ irq = platform_get_irq_byname(pdev, "csi-intr1");
+ if (irq > 0) {
+ irq_set_status_flags(irq, IRQ_NOAUTOEN);
+ ret = devm_request_irq(&pdev->dev, irq,
+ rk_csirx_irq1_handler, 0,
+ dev_driver_string(&pdev->dev),
+ &pdev->dev);
+ if (ret < 0)
+ dev_err(&pdev->dev, "request csi-intr1 irq failed: %d\n",
+ ret);
+ csi2_hw->irq1 = irq;
+ } else {
+ dev_err(&pdev->dev, "No found irq csi-intr1\n");
+ }
+
+ irq = platform_get_irq_byname(pdev, "csi-intr2");
+ if (irq > 0) {
+ irq_set_status_flags(irq, IRQ_NOAUTOEN);
+ ret = devm_request_irq(&pdev->dev, irq,
+ rk_csirx_irq2_handler, 0,
+ dev_driver_string(&pdev->dev),
+ &pdev->dev);
+ if (ret < 0)
+ dev_err(&pdev->dev, "request csi-intr2 failed: %d\n",
+ ret);
+ csi2_hw->irq2 = irq;
+ } else {
+ dev_err(&pdev->dev, "No found irq csi-intr2\n");
+ }
+ platform_set_drvdata(pdev, csi2_hw);
+ dev_info(&pdev->dev, "probe success, v4l2_dev:%s!\n", csi2_hw->dev_name);
+
+ return 0;
+}
+
+static int csi2_hw_remove(struct platform_device *pdev)
+{
+ return 0;
+}
+
+static struct platform_driver csi2_hw_driver = {
+ .driver = {
+ .name = DEVICE_NAME_HW,
+ .of_match_table = csi2_hw_ids,
+ },
+ .probe = csi2_hw_probe,
+ .remove = csi2_hw_remove,
+};
+
+int rkcif_csi2_hw_plat_drv_init(void)
+{
+ return platform_driver_register(&csi2_hw_driver);
+}
+
+void rkcif_csi2_hw_plat_drv_exit(void)
+{
+ platform_driver_unregister(&csi2_hw_driver);
+}
+
MODULE_DESCRIPTION("Rockchip MIPI CSI2 driver");
MODULE_AUTHOR("Macrofly.xu <xuhf@rock-chips.com>");
MODULE_LICENSE("GPL");
--
Gitblit v1.6.2