From f07db797ddeb9626199c43b78e49854aa8822429 Mon Sep 17 00:00:00 2001 From: Chen Shunqing Date: Wed, 10 Sep 2025 15:34:32 +0800 Subject: [PATCH 01/40] media: rockchip: hdmirx: add RK_HDMIRX_CMD_GET_HDR_METADATA Signed-off-by: Chen Shunqing Change-Id: Idc399fea2a76a10f8ae196e52670d88be5bedd44 --- include/uapi/linux/rk_hdmirx_config.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/include/uapi/linux/rk_hdmirx_config.h b/include/uapi/linux/rk_hdmirx_config.h index 0c35e857c5cb..d22008fc20ab 100644 --- a/include/uapi/linux/rk_hdmirx_config.h +++ b/include/uapi/linux/rk_hdmirx_config.h @@ -7,6 +7,7 @@ #ifndef _UAPI_RK_HDMIRX_CONFIG_H #define _UAPI_RK_HDMIRX_CONFIG_H +#include #include #include @@ -119,6 +120,9 @@ enum user_color_range { #define RK_HDMIRX_CMD_SET_EDID_VERSION \ _IOW('V', BASE_VIDIOC_PRIVATE + 17, int) +#define RK_HDMIRX_CMD_GET_HDR_METADATA \ + _IOR('V', BASE_VIDIOC_PRIVATE + 18, struct hdr_metadata_infoframe) + /* Private v4l2 event */ #define RK_HDMIRX_V4L2_EVENT_SIGNAL_LOST \ (V4L2_EVENT_PRIVATE_START + 1) From e2c0f45bcba2c0f527bc609ff0dbca8ece164087 Mon Sep 17 00:00:00 2001 From: Chen Shunqing Date: Tue, 12 Aug 2025 14:45:55 +0800 Subject: [PATCH 02/40] media: i2c: rk628: add hdr support Signed-off-by: Chen Shunqing Change-Id: I90ae0d96391185b5e79a5a7a8733a42964684dd0 --- drivers/media/i2c/rk628/rk628.c | 2 + drivers/media/i2c/rk628/rk628_csi_v4l2.c | 52 ++++++++++++++++++ drivers/media/i2c/rk628/rk628_hdmirx.c | 68 ++++++++++++++++++++++++ drivers/media/i2c/rk628/rk628_hdmirx.h | 14 +++++ 4 files changed, 136 insertions(+) diff --git a/drivers/media/i2c/rk628/rk628.c b/drivers/media/i2c/rk628/rk628.c index ab354f8d015e..b57dbc8e326a 100644 --- a/drivers/media/i2c/rk628/rk628.c +++ b/drivers/media/i2c/rk628/rk628.c @@ -78,6 +78,8 @@ static const struct regmap_range rk628_hdmirx_readable_ranges[] = { regmap_reg_range(HDMI_RX_PDEC_ACR_CTS, HDMI_RX_PDEC_ACR_N), regmap_reg_range(HDMI_RX_PDEC_AVI_HB, HDMI_RX_PDEC_AVI_PB), regmap_reg_range(HDMI_RX_PDEC_AIF_CTRL, HDMI_RX_PDEC_AIF_PB0), + regmap_reg_range(HDMI_RX_PDEC_GMD_HB0, HDMI_RX_PDEC_GMD_PB0), + regmap_reg_range(HDMI_RX_PDEC_DRM_HB, HDMI_RX_PDEC_DRM_PAYLOAD6), regmap_reg_range(HDMI_RX_HDMI20_CONTROL, HDMI_RX_CHLOCK_CONFIG), regmap_reg_range(HDMI_RX_SCDC_REGS0, HDMI_RX_SCDC_REGS2), regmap_reg_range(HDMI_RX_SCDC_WRDATA0, HDMI_RX_SCDC_WRDATA0), diff --git a/drivers/media/i2c/rk628/rk628_csi_v4l2.c b/drivers/media/i2c/rk628/rk628_csi_v4l2.c index f699966f89cb..a10a381bc69c 100644 --- a/drivers/media/i2c/rk628/rk628_csi_v4l2.c +++ b/drivers/media/i2c/rk628/rk628_csi_v4l2.c @@ -133,6 +133,7 @@ struct rk628_csi { bool is_streaming; bool csi_ints_en; bool dual_mipi_use; + bool hdr_support; enum user_color_range user_color_range; }; @@ -240,6 +241,41 @@ static u8 rk628f_edid_init_data[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x23, }; +static u8 rk628f_hdr_edid_init_data[] = { + 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, + 0x24, 0xD0, 0x8F, 0x62, 0x01, 0x00, 0x00, 0x00, + 0x2D, 0x21, 0x01, 0x03, 0x80, 0x78, 0x44, 0x78, + 0x0A, 0xCF, 0x74, 0xA3, 0x57, 0x4C, 0xB0, 0x23, + 0x09, 0x48, 0x4C, 0x21, 0x08, 0x00, 0x61, 0x40, + 0x01, 0x01, 0x81, 0x00, 0x95, 0x00, 0xA9, 0xC0, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x08, 0xE8, + 0x00, 0x30, 0xF2, 0x70, 0x5A, 0x80, 0xB0, 0x58, + 0x8A, 0x00, 0xC4, 0x8E, 0x21, 0x00, 0x00, 0x1E, + 0x02, 0x3A, 0x80, 0x18, 0x71, 0x38, 0x2D, 0x40, + 0x58, 0x2C, 0x45, 0x00, 0xB9, 0xA8, 0x42, 0x00, + 0x00, 0x1E, 0x00, 0x00, 0x00, 0xFC, 0x00, 0x49, + 0x46, 0x50, 0x20, 0x44, 0x69, 0x73, 0x70, 0x6C, + 0x61, 0x79, 0x0A, 0x20, 0x00, 0x00, 0x00, 0xFD, + 0x00, 0x3B, 0x46, 0x1F, 0x8C, 0x3C, 0x00, 0x0A, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x01, 0xA8, + + 0x02, 0x03, 0x40, 0xF2, 0x4D, 0x01, 0x03, 0x12, + 0x13, 0x84, 0x22, 0x1F, 0x90, 0x5D, 0x5E, 0x5F, + 0x60, 0x61, 0x23, 0x09, 0x07, 0x07, 0x83, 0x01, + 0x00, 0x00, 0x6D, 0x03, 0x0C, 0x00, 0x10, 0x00, + 0x18, 0x44, 0x20, 0x00, 0x60, 0x03, 0x02, 0x01, + 0x67, 0xD8, 0x5D, 0xC4, 0x01, 0x78, 0x80, 0x00, + 0xE3, 0x05, 0xE3, 0x01, 0xE4, 0x0F, 0x00, 0x18, + 0x00, 0xE2, 0x00, 0xCB, 0xE3, 0x06, 0x0D, 0x01, + 0x02, 0x3A, 0x80, 0x18, 0x71, 0x38, 0x2D, 0x40, + 0x58, 0x2C, 0x45, 0x00, 0xB9, 0xA8, 0x42, 0x00, + 0x00, 0x1E, 0x08, 0xE8, 0x00, 0x30, 0xF2, 0x70, + 0x5A, 0x80, 0xB0, 0x58, 0x8A, 0x00, 0xC4, 0x8E, + 0x21, 0x00, 0x00, 0x1E, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, +}; static struct rk628_edid edid_data[] = { { @@ -250,6 +286,10 @@ static struct rk628_edid edid_data[] = { .version = 2, .data = rk628f_edid_init_data, }, + { + .version = 3, + .data = rk628f_hdr_edid_init_data, + }, }; static const unsigned int rk628_csi_extcon_cable[] = { @@ -1473,6 +1513,10 @@ static void rk628_csi_initial(struct v4l2_subdev *sd) def_edid.edid = edid_init_data; csi->edid_version = 1; } + if (csi->hdr_support && csi->rk628->version >= RK628F_VERSION) { + def_edid.edid = rk628f_hdr_edid_init_data; + csi->edid_version = 3; + } rk628_csi_s_edid(sd, &def_edid); } @@ -2521,6 +2565,7 @@ static long rk628_csi_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg) struct rkmodule_capture_info *capture_info; u32 stream = 0; int edid_version, i; + struct hdr_metadata_infoframe hdmi_metadata; switch (cmd) { case RKMODULE_GET_MODULE_INFO: @@ -2619,6 +2664,10 @@ static long rk628_csi_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg) } v4l2_info(sd, "the edid version is not supported: %d\n", edid_version); return -EINVAL; + case RK_HDMIRX_CMD_GET_HDR_METADATA: + rk628_hdmirx_get_hdr_matedata(csi->rk628, &hdmi_metadata); + memcpy(arg, &hdmi_metadata, sizeof(hdmi_metadata)); + break; default: ret = -ENOIOCTLCMD; break; @@ -3223,6 +3272,9 @@ static int rk628_csi_probe_of(struct rk628_csi *csi) if (of_property_read_bool(dev->of_node, "cec-enable")) csi->cec_enable = true; + if (of_property_read_bool(dev->of_node, "hdr-support")) + csi->hdr_support = true; + if (of_property_read_bool(dev->of_node, "i2s-enable-default")) i2s_enable_default = true; diff --git a/drivers/media/i2c/rk628/rk628_hdmirx.c b/drivers/media/i2c/rk628/rk628_hdmirx.c index 9c48ab6257fd..1cd59b023287 100644 --- a/drivers/media/i2c/rk628/rk628_hdmirx.c +++ b/drivers/media/i2c/rk628/rk628_hdmirx.c @@ -1572,6 +1572,38 @@ u32 rk628_hdmirx_get_tmdsclk_cnt(struct rk628 *rk628) } EXPORT_SYMBOL(rk628_hdmirx_get_tmdsclk_cnt); +int rk628_hdmirx_get_hdr_matedata(struct rk628 *rk628, + struct hdr_metadata_infoframe *hdmi_metadata) +{ + u32 val; + int i; + + rk628_i2c_read(rk628, HDMI_RX_PDEC_DRM_HB, &val); + if (!val) + return -EINVAL; + + rk628_i2c_read(rk628, HDMI_RX_PDEC_DRM_PAYLOAD0, &val); + hdmi_metadata->eotf = (val >> 8) & 0xff; + hdmi_metadata->metadata_type = (val >> 16) & 0xff; + for (i = 0; i < 3; i++) { + rk628_i2c_read(rk628, HDMI_RX_PDEC_DRM_PAYLOAD1 + i * 4, &val); + hdmi_metadata->display_primaries[i].x = val & 0xffff; + hdmi_metadata->display_primaries[i].y = (val >> 16) & 0xffff; + } + rk628_i2c_read(rk628, HDMI_RX_PDEC_DRM_PAYLOAD4, &val); + hdmi_metadata->white_point.x = val & 0xffff; + hdmi_metadata->white_point.y = (val >> 16) & 0xffff; + rk628_i2c_read(rk628, HDMI_RX_PDEC_DRM_PAYLOAD5, &val); + hdmi_metadata->max_display_mastering_luminance = val & 0xffff; + hdmi_metadata->min_display_mastering_luminance = (val >> 16) & 0xffff; + rk628_i2c_read(rk628, HDMI_RX_PDEC_DRM_PAYLOAD6, &val); + hdmi_metadata->max_cll = val & 0xffff; + hdmi_metadata->max_fall = (val >> 16) & 0xffff; + + return 0; +} +EXPORT_SYMBOL(rk628_hdmirx_get_hdr_matedata); + struct rk628_timings { int vic; int hactive; @@ -2205,6 +2237,7 @@ static int rk628_hdmirx_status_show(struct seq_file *s, void *v) bool plugin; u32 val, htot, vtot, fps, format; u8 fmt, range, space; + struct hdr_metadata_infoframe hdmi_metadata; plugin = rk628_hdmirx_tx_5v_power_detect(rk628->hdmirx_det_gpio); seq_printf(s, "status: %s\n", plugin ? "plugin" : "plugout"); @@ -2265,6 +2298,41 @@ static int rk628_hdmirx_status_show(struct seq_file *s, void *v) else seq_puts(s, "Unknown\n"); + seq_puts(s, "EOTF: "); + if (!rk628_hdmirx_get_hdr_matedata(rk628, &hdmi_metadata)) { + switch (hdmi_metadata.eotf & 0x7) { + case HDMI_EOTF_TRADITIONAL_GAMMA_SDR: + seq_puts(s, "SDR"); + break; + case HDMI_EOTF_TRADITIONAL_GAMMA_HDR: + seq_puts(s, "HDR"); + break; + case HDMI_EOTF_SMPTE_ST2084: + seq_puts(s, "ST2084"); + break; + case HDMI_EOTF_BT_2100_HLG: + seq_puts(s, "HLG"); + break; + default: + seq_puts(s, "Not Defined\n"); + return 0; + } + seq_printf(s, "\nx0: %d", hdmi_metadata.display_primaries[0].x); + seq_printf(s, "\t\t\t\ty0: %d\n", hdmi_metadata.display_primaries[0].y); + seq_printf(s, "x1: %d", hdmi_metadata.display_primaries[1].x); + seq_printf(s, "\t\t\t\ty1: %d\n", hdmi_metadata.display_primaries[1].y); + seq_printf(s, "x2: %d", hdmi_metadata.display_primaries[2].x); + seq_printf(s, "\t\t\t\ty2: %d\n", hdmi_metadata.display_primaries[2].y); + seq_printf(s, "white x: %d", hdmi_metadata.white_point.x); + seq_printf(s, "\t\t\twhite y: %d\n", hdmi_metadata.white_point.y); + seq_printf(s, "max lum: %d", hdmi_metadata.max_display_mastering_luminance); + seq_printf(s, "\t\t\tmin lum: %d\n", hdmi_metadata.min_display_mastering_luminance); + seq_printf(s, "max cll: %d", hdmi_metadata.max_cll); + seq_printf(s, "\t\t\tmax fall: %d\n", hdmi_metadata.max_fall); + } else { + seq_puts(s, "Off\n"); + } + return 0; } diff --git a/drivers/media/i2c/rk628/rk628_hdmirx.h b/drivers/media/i2c/rk628/rk628_hdmirx.h index 99090e1841ff..ed72aa6d8007 100644 --- a/drivers/media/i2c/rk628/rk628_hdmirx.h +++ b/drivers/media/i2c/rk628/rk628_hdmirx.h @@ -8,6 +8,8 @@ #ifndef __RK628_HDMIRX_H #define __RK628_HDMIRX_H +#include +#include #include #include #include @@ -280,6 +282,16 @@ #define HDMI_RX_PDEC_AIF_CTRL (HDMI_RX_BASE + 0x03c0) #define FC_LFE_EXCHG(x) UPDATE(x, 18, 18) #define HDMI_RX_PDEC_AIF_PB0 (HDMI_RX_BASE + 0x03c8) +#define HDMI_RX_PDEC_GMD_HB0 (HDMI_RX_BASE + 0x03d0) +#define HDMI_RX_PDEC_GMD_PB0 (HDMI_RX_BASE + 0x03d4) +#define HDMI_RX_PDEC_DRM_HB (HDMI_RX_BASE + 0x04c0) +#define HDMI_RX_PDEC_DRM_PAYLOAD0 (HDMI_RX_BASE + 0x04c4) +#define HDMI_RX_PDEC_DRM_PAYLOAD1 (HDMI_RX_BASE + 0x04c8) +#define HDMI_RX_PDEC_DRM_PAYLOAD2 (HDMI_RX_BASE + 0x04cc) +#define HDMI_RX_PDEC_DRM_PAYLOAD3 (HDMI_RX_BASE + 0x04d0) +#define HDMI_RX_PDEC_DRM_PAYLOAD4 (HDMI_RX_BASE + 0x04d4) +#define HDMI_RX_PDEC_DRM_PAYLOAD5 (HDMI_RX_BASE + 0x04d8) +#define HDMI_RX_PDEC_DRM_PAYLOAD6 (HDMI_RX_BASE + 0x04dc) #define HDMI_RX_HDMI20_CONTROL (HDMI_RX_BASE + 0x0800) #define PVO1UNMUTE(x) UPDATE(x, 29, 29) @@ -545,6 +557,8 @@ int rk628_hdmirx_get_timings(struct rk628 *rk628, u8 rk628_hdmirx_get_range(struct rk628 *rk628); u8 rk628_hdmirx_get_color_space(struct rk628 *rk628); int rk628_hdmirx_get_hdcp_enc_status(struct rk628 *rk628); +int rk628_hdmirx_get_hdr_matedata(struct rk628 *rk628, + struct hdr_metadata_infoframe *hdmi_metadata); void rk628_hdmirx_controller_reset(struct rk628 *rk628); bool rk628_hdmirx_scdc_ced_err(struct rk628 *rk628); bool rk628_hdmirx_is_locked(struct rk628 *rk628); From 41c01fb27bcf5c725753d1ecd697d191405afb93 Mon Sep 17 00:00:00 2001 From: Jianwei Fan Date: Sat, 16 Aug 2025 15:55:07 +0800 Subject: [PATCH 03/40] media: i2c: rk628: add csi output yuv422 10bit support Signed-off-by: Jianwei Fan Change-Id: Ibdbb2d39287b13115babb36e6643c0a0c60eadeb --- drivers/media/i2c/rk628/rk628.h | 1 + drivers/media/i2c/rk628/rk628_csi.h | 14 +++ drivers/media/i2c/rk628/rk628_csi_v4l2.c | 105 ++++++++++++++++++----- drivers/media/i2c/rk628/rk628_hdmirx.c | 1 + drivers/media/i2c/rk628/rk628_hdmirx.h | 5 +- 5 files changed, 103 insertions(+), 23 deletions(-) diff --git a/drivers/media/i2c/rk628/rk628.h b/drivers/media/i2c/rk628/rk628.h index f8312b71a132..cc2e08b718c4 100644 --- a/drivers/media/i2c/rk628/rk628.h +++ b/drivers/media/i2c/rk628/rk628.h @@ -314,6 +314,7 @@ struct rk628 { struct gpio_desc *hdmirx_det_gpio; bool last_mipi_status; bool is_suspend; + bool is_10bit; }; #define rk628_dbg(rk628, format, ...) \ diff --git a/drivers/media/i2c/rk628/rk628_csi.h b/drivers/media/i2c/rk628/rk628_csi.h index 62438abaff38..28a3f7d34c41 100644 --- a/drivers/media/i2c/rk628/rk628_csi.h +++ b/drivers/media/i2c/rk628/rk628_csi.h @@ -115,4 +115,18 @@ #define CSI_SKIP_FRAME_NORMAL 1 +enum csi_pixfmt { + CSI_RAW8 = 0, + CSI_RAW10, + CSI_PIXEL10, + CSI_PIXEL128, + CSI_RAW12, + CSI_PIXEL12, +}; + +enum csi_datatype { + YUV422_8BIT = 0x1e, + YUV422_10BIT = 0x1f, +}; + #endif diff --git a/drivers/media/i2c/rk628/rk628_csi_v4l2.c b/drivers/media/i2c/rk628/rk628_csi_v4l2.c index a10a381bc69c..56ff4868500b 100644 --- a/drivers/media/i2c/rk628/rk628_csi_v4l2.c +++ b/drivers/media/i2c/rk628/rk628_csi_v4l2.c @@ -152,8 +152,10 @@ struct rk628_edid { }; static const s64 link_freq_menu_items[] = { - RK628_CSI_LINK_FREQ_LOW, - RK628_CSI_LINK_FREQ_HIGH, + RK628_CSI_LINK_FREQ_350M, + RK628_CSI_LINK_FREQ_450M, + RK628_CSI_LINK_FREQ_650M, + RK628_CSI_LINK_FREQ_750M, RK628_CSI_LINK_FREQ_925M, }; @@ -484,11 +486,19 @@ static int rk628_csi_get_detected_timings(struct v4l2_subdev *sd, struct rk628_csi *csi = to_csi(sd); struct v4l2_bt_timings *bt = &timings->bt; int ret; + u32 val, eotf; + csi->rk628->is_10bit = false; ret = rk628_hdmirx_get_timings(csi->rk628, timings); if (ret) return ret; + rk628_i2c_read(csi->rk628, HDMI_RX_PDEC_DRM_HB, &val); + rk628_i2c_read(csi->rk628, HDMI_RX_PDEC_DRM_PAYLOAD0, &val); + eotf = (val >> 8) & 0xff; + if (eotf == 0x02 && csi->rk628->color_format == BUS_FMT_YUV422) + csi->rk628->is_10bit = true; + v4l2_dbg(1, debug, sd, "hfp:%d, hs:%d, hbp:%d, vfp:%d, vs:%d, vbp:%d, interlace:%d\n", bt->hfrontporch, bt->hsync, bt->hbackporch, bt->vfrontporch, bt->vsync, bt->vbackporch, bt->interlaced); @@ -506,6 +516,13 @@ static int rk628_csi_get_detected_timings(struct v4l2_subdev *sd, csi->rk628->dual_mipi = false; } + if (csi->plat_data->tx_mode == CSI_MODE) { + if (csi->rk628->is_10bit) + csi->mbus_fmt_code = MEDIA_BUS_FMT_YUYV10_2X10; + else + csi->mbus_fmt_code = MEDIA_BUS_FMT_UYVY8_2X8; + } + return ret; } @@ -1060,15 +1077,31 @@ static void rk628_csi_set_csi(struct v4l2_subdev *sd) struct rk628_csi *csi = to_csi(sd); u8 video_fmt; u8 lanes = csi->csi_lanes_in_use; - u8 lane_num; - u32 wc_usrdef, val; + u8 lane_num, yc_swap; + u32 wc_usrdef, val, data_type, pixfmt; int avi_rdy; lane_num = lanes - 1; csi->rk628->dphy_lane_en = (1 << (lanes + 1)) - 1; - wc_usrdef = csi->timings.bt.width * 2; - if (csi->rk628->dual_mipi) + + if (csi->rk628->dual_mipi && !csi->rk628->is_10bit) wc_usrdef = csi->timings.bt.width; + else if (csi->rk628->dual_mipi && csi->rk628->is_10bit) + wc_usrdef = div_u64(csi->timings.bt.width * 10, 8); + else if (!csi->rk628->dual_mipi && csi->rk628->is_10bit) + wc_usrdef = div_u64(csi->timings.bt.width * 2 * 10, 8); + else + wc_usrdef = csi->timings.bt.width * 2; + + if (csi->rk628->is_10bit) { + pixfmt = CSI_RAW10; + data_type = YUV422_10BIT; + yc_swap = 1; + } else { + pixfmt = CSI_RAW8; + data_type = YUV422_8BIT; + yc_swap = 0; + } v4l2_info(sd, "%s mipi mode, word count user define: %d\n", csi->rk628->dual_mipi ? "dual" : "single", wc_usrdef); rk628_csi_disable_stream(sd); @@ -1109,6 +1142,7 @@ static void rk628_csi_set_csi(struct v4l2_subdev *sd) BYPASS_SELECT(1)); } else { rk628_i2c_update_bits(csi->rk628, CSITX_CSITX_EN, + VOP_YU_SWAP_MASK | VOP_UV_SWAP_MASK | VOP_YUV422_EN_MASK | VOP_YUV422_MODE_MASK | @@ -1116,6 +1150,7 @@ static void rk628_csi_set_csi(struct v4l2_subdev *sd) LANE_NUM_MASK | DPHY_EN_MASK | CSITX_EN_MASK, + VOP_YU_SWAP(yc_swap) | VOP_UV_SWAP(0) | VOP_YUV422_EN(1) | VOP_YUV422_MODE(2) | @@ -1149,8 +1184,8 @@ static void rk628_csi_set_csi(struct v4l2_subdev *sd) rk628_i2c_write(csi->rk628, CSITX_VOP_PATH_CTRL, VOP_WC_USERDEFINE(wc_usrdef) | - VOP_DT_USERDEFINE(YUV422_8BIT) | - VOP_PIXEL_FORMAT(0) | + VOP_DT_USERDEFINE(data_type) | + VOP_PIXEL_FORMAT(pixfmt) | VOP_WC_USERDEFINE_EN(1) | VOP_DT_USERDEFINE_EN(1) | VOP_PATH_EN(1)); @@ -1165,6 +1200,7 @@ static void rk628_csi_set_csi(struct v4l2_subdev *sd) if (csi->rk628->version >= RK628F_VERSION) { rk628_i2c_update_bits(csi->rk628, CSITX1_CSITX_EN, + VOP_YU_SWAP_MASK | VOP_UV_SWAP_MASK | VOP_YUV422_EN_MASK | VOP_YUV422_MODE_MASK | @@ -1172,6 +1208,7 @@ static void rk628_csi_set_csi(struct v4l2_subdev *sd) LANE_NUM_MASK | DPHY_EN_MASK | CSITX_EN_MASK, + VOP_YU_SWAP(yc_swap) | VOP_UV_SWAP(0) | VOP_YUV422_EN(1) | VOP_YUV422_MODE(2) | @@ -1203,8 +1240,8 @@ static void rk628_csi_set_csi(struct v4l2_subdev *sd) rk628_i2c_write(csi->rk628, CSITX1_VOP_PATH_CTRL, VOP_WC_USERDEFINE(wc_usrdef) | - VOP_DT_USERDEFINE(YUV422_8BIT) | - VOP_PIXEL_FORMAT(0) | + VOP_DT_USERDEFINE(data_type) | + VOP_PIXEL_FORMAT(pixfmt) | VOP_WC_USERDEFINE_EN(1) | VOP_DT_USERDEFINE_EN(1) | VOP_PATH_EN(1)); @@ -2185,7 +2222,7 @@ static int rk628_csi_enum_frame_interval(struct v4l2_subdev *sd, static u32 rk628_csi_get_lane_rate_mbps(struct rk628_csi *csi) { u32 lane_rate; - u32 max_lane_rate = 1300; + u32 max_lane_rate = 1800; u8 bpp, lanes; u64 pixelclock = csi->timings.bt.pixelclock; @@ -2196,23 +2233,48 @@ static u32 rk628_csi_get_lane_rate_mbps(struct rk628_csi *csi) lane_rate = div_u64(lane_rate, lanes); if (csi->rk628->dual_mipi) lane_rate /= 2; + if (csi->rk628->is_10bit) + lane_rate = div_u64(lane_rate * 5, 4); - if (lane_rate > 1300) + if (lane_rate > 1500) lane_rate = max_lane_rate; - else if (lane_rate > 700 && lane_rate <= 1300) + else if (lane_rate > 1300 && lane_rate <= 1500) + lane_rate = 1500; + else if (lane_rate > 900 && lane_rate <= 1300) lane_rate = 1300; + else if (lane_rate > 700 && lane_rate <= 900) + lane_rate = 900; else lane_rate = 700; return lane_rate; } +static int rk628_find_best_link_freq(u32 rate) +{ + u32 dist; + int cur_best_fit = 0; + u32 cur_best_fit_dist = -1; + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(link_freq_menu_items); i++) { + dist = abs(div_u64(link_freq_menu_items[i] * 2, 1000000) - rate); + if (cur_best_fit_dist == -1 || dist < cur_best_fit_dist) { + cur_best_fit_dist = dist; + cur_best_fit = i; + } + } + + return cur_best_fit; +} + static int rk628_csi_get_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_state *sd_state, struct v4l2_subdev_format *format) { struct rk628_csi *csi = to_csi(sd); u32 rate; + int index; if (!tx_5v_power_present(sd) || csi->nosignal) { v4l2_info(sd, "%s hdmirx no signal\n", __func__); @@ -2239,13 +2301,8 @@ static int rk628_csi_get_fmt(struct v4l2_subdev *sd, v4l2_dbg(1, debug, sd, "%s mipi bitrate:%u mbps\n", __func__, rate); - if (rate > 1300) - __v4l2_ctrl_s_ctrl(csi->link_freq, 2); - else if (rate <= 1300 && rate > 700) - __v4l2_ctrl_s_ctrl(csi->link_freq, 1); - else - __v4l2_ctrl_s_ctrl(csi->link_freq, 0); - + index = rk628_find_best_link_freq(rate); + __v4l2_ctrl_s_ctrl(csi->link_freq, index); __v4l2_ctrl_s_ctrl_int64(csi->pixel_rate, RK628_CSI_PIXEL_RATE_HIGH); mutex_unlock(&csi->confctl_mutex); @@ -2300,11 +2357,15 @@ static int rk628_csi_set_fmt(struct v4l2_subdev *sd, switch (code) { case MEDIA_BUS_FMT_UYVY8_2X8: - if (csi->plat_data->bus_fmt == MEDIA_BUS_FMT_UYVY8_2X8) + if (csi->mbus_fmt_code == MEDIA_BUS_FMT_UYVY8_2X8) break; return -EINVAL; case MEDIA_BUS_FMT_RGB888_1X24: - if (csi->plat_data->bus_fmt == MEDIA_BUS_FMT_RGB888_1X24) + if (csi->mbus_fmt_code == MEDIA_BUS_FMT_RGB888_1X24) + break; + return -EINVAL; + case MEDIA_BUS_FMT_YUYV10_2X10: + if (csi->mbus_fmt_code == MEDIA_BUS_FMT_YUYV10_2X10) break; return -EINVAL; default: diff --git a/drivers/media/i2c/rk628/rk628_hdmirx.c b/drivers/media/i2c/rk628/rk628_hdmirx.c index 1cd59b023287..319b552615bd 100644 --- a/drivers/media/i2c/rk628/rk628_hdmirx.c +++ b/drivers/media/i2c/rk628/rk628_hdmirx.c @@ -1753,6 +1753,7 @@ static int rk628_hdmirx_read_timing(struct rk628 *rk628, hfp = hfp * 2 * 8 / 10; hbp = hbp * 2 * 8 / 10; hs = hs * 2 * 8 / 10; + rk628->is_10bit = true; } else { htotal *= 2; hact *= 2; diff --git a/drivers/media/i2c/rk628/rk628_hdmirx.h b/drivers/media/i2c/rk628/rk628_hdmirx.h index ed72aa6d8007..ea0e091e82b0 100644 --- a/drivers/media/i2c/rk628/rk628_hdmirx.h +++ b/drivers/media/i2c/rk628/rk628_hdmirx.h @@ -460,6 +460,10 @@ #define RK628_CSI_LINK_FREQ_LOW 350000000 #define RK628_CSI_LINK_FREQ_HIGH 650000000 +#define RK628_CSI_LINK_FREQ_350M 350000000 +#define RK628_CSI_LINK_FREQ_450M 450000000 +#define RK628_CSI_LINK_FREQ_650M 650000000 +#define RK628_CSI_LINK_FREQ_750M 750000000 #define RK628_CSI_LINK_FREQ_925M 925000000 #define RK628_CSI_PIXEL_RATE_LOW 400000000 #define RK628_CSI_PIXEL_RATE_HIGH 600000000 @@ -471,7 +475,6 @@ #define CSITX_ERR_RETRY_TIMES 3 #define USE_4_LANES 4 -#define YUV422_8BIT 0x1e #define SCDC_CED_ERR_CNT 0xfff From b7f77248959605efff4bf5b7274380c16042f7e9 Mon Sep 17 00:00:00 2001 From: Jianwei Fan Date: Wed, 24 Sep 2025 15:09:27 +0800 Subject: [PATCH 04/40] media: i2c: rk628: fix hdmirx range detect when default According to the CEA-861 specification, when the RGB default color gamut is detected: When the VIC is between 2 and 127, it is CE video, i.e., limited range. When the VIC is any other value, it is IT video, i.e., full range. Signed-off-by: Jianwei Fan Change-Id: I258bd84096a340fd88e37e7f127301469baadef9 --- drivers/media/i2c/rk628/rk628_hdmirx.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/media/i2c/rk628/rk628_hdmirx.c b/drivers/media/i2c/rk628/rk628_hdmirx.c index 319b552615bd..291b63b79f10 100644 --- a/drivers/media/i2c/rk628/rk628_hdmirx.c +++ b/drivers/media/i2c/rk628/rk628_hdmirx.c @@ -1931,9 +1931,9 @@ u8 rk628_hdmirx_get_range(struct rk628 *rk628) if (dvi) color_range = HDMIRX_FULL_RANGE; if (color_range == HDMIRX_DEFAULT_RANGE) - vic ? - (color_range = HDMIRX_FULL_RANGE) : - (color_range = HDMIRX_LIMIT_RANGE); + ((vic >= 2) && (vic <= 127)) ? + (color_range = HDMIRX_LIMIT_RANGE) : + (color_range = HDMIRX_FULL_RANGE); } return color_range; From db61801669b69ab5500964942f476e38d252050d Mon Sep 17 00:00:00 2001 From: Shengfei Xu Date: Wed, 24 Sep 2025 11:52:16 +0800 Subject: [PATCH 05/40] mfd: rk806: The shutdown pin of RK806 is configurable Configure which pin controls the shutdown function via the shutown_by_pwrctrln property in the DTS. Change-Id: I7bb3adf28ff7e93fd318d08274cb88271b925027 Signed-off-by: Shengfei Xu --- drivers/mfd/rk806-core.c | 12 ++++++++++++ drivers/regulator/rk806-regulator.c | 16 +++++++++++++--- include/linux/mfd/rk806.h | 1 + 3 files changed, 26 insertions(+), 3 deletions(-) diff --git a/drivers/mfd/rk806-core.c b/drivers/mfd/rk806-core.c index d6b1af88289e..884d7913d4b9 100644 --- a/drivers/mfd/rk806-core.c +++ b/drivers/mfd/rk806-core.c @@ -789,6 +789,18 @@ static int rk806_parse_dt(struct rk806 *rk806) if (device_property_read_bool(dev, "vdc-wakeup-enable")) pdata->vdc_wakeup_enable = 1; + ret = device_property_read_u32(dev, + "shutown_by_pwrctrln", + &pdata->shutown_by_pwrctrln); + if (ret < 0) { + dev_info(dev, "shutown_by_pwrctrln missing!\n"); + pdata->shutown_by_pwrctrln = 1; + } + if ((pdata->shutown_by_pwrctrln < 1) || (pdata->shutown_by_pwrctrln > 3)) { + dev_err(dev, "shutown_by_pwrctrln out [1 3]!\n"); + pdata->shutown_by_pwrctrln = 1; + } + pdata->shutdown_sequence = devm_kzalloc(dev, RK806_ID_END * sizeof(int), GFP_KERNEL); diff --git a/drivers/regulator/rk806-regulator.c b/drivers/regulator/rk806-regulator.c index 3eba9d6e7957..3d9b5084fd82 100644 --- a/drivers/regulator/rk806-regulator.c +++ b/drivers/regulator/rk806-regulator.c @@ -1252,9 +1252,19 @@ static void rk806_regulator_shutdown(struct platform_device *pdev) if (system_state == SYSTEM_POWER_OFF) { rk806_shutdown_requence_config(rk806); - rk806_field_write(rk806, PWRCTRL1_FUN, PWRCTRL_NULL_FUN); - rk806_field_write(rk806, PWRCTRL1_POL, POL_HIGH); - rk806_field_write(rk806, PWRCTRL1_FUN, PWRCTRL_POWOFF_FUN); + if (rk806->pdata->shutown_by_pwrctrln == 2) { + rk806_field_write(rk806, PWRCTRL2_FUN, PWRCTRL_NULL_FUN); + rk806_field_write(rk806, PWRCTRL2_POL, POL_HIGH); + rk806_field_write(rk806, PWRCTRL2_FUN, PWRCTRL_POWOFF_FUN); + } else if (rk806->pdata->shutown_by_pwrctrln == 3) { + rk806_field_write(rk806, PWRCTRL3_FUN, PWRCTRL_NULL_FUN); + rk806_field_write(rk806, PWRCTRL3_POL, POL_HIGH); + rk806_field_write(rk806, PWRCTRL3_FUN, PWRCTRL_POWOFF_FUN); + } else { + rk806_field_write(rk806, PWRCTRL1_FUN, PWRCTRL_NULL_FUN); + rk806_field_write(rk806, PWRCTRL1_POL, POL_HIGH); + rk806_field_write(rk806, PWRCTRL1_FUN, PWRCTRL_POWOFF_FUN); + } } } diff --git a/include/linux/mfd/rk806.h b/include/linux/mfd/rk806.h index 2e3f75da6572..2f26475cf690 100644 --- a/include/linux/mfd/rk806.h +++ b/include/linux/mfd/rk806.h @@ -505,6 +505,7 @@ struct rk806_platform_data { int hotdie_temperture_threshold; int vdc_wakeup_enable; + int shutown_by_pwrctrln; int *shutdown_sequence; int *vb_shutdown_sequence; int *dvs_control_suspend; From 192d95fdf1ce7b8c033565859e89d54d7ea053a8 Mon Sep 17 00:00:00 2001 From: Zorro Liu Date: Wed, 24 Sep 2025 16:36:00 +0800 Subject: [PATCH 06/40] arm64: dts: rockchip: rk3576-eink: update dts configs for new shutdown method Change-Id: I18d6fb72eedea776b67ab74ba2faf554c5034ccf Signed-off-by: Zorro Liu --- arch/arm64/boot/dts/rockchip/rk3576-eink.dtsi | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/arch/arm64/boot/dts/rockchip/rk3576-eink.dtsi b/arch/arm64/boot/dts/rockchip/rk3576-eink.dtsi index e41db79c3879..d1a94c3c134d 100644 --- a/arch/arm64/boot/dts/rockchip/rk3576-eink.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk3576-eink.dtsi @@ -67,12 +67,12 @@ interrupt-parent = <&gpio0>; interrupts = <6 IRQ_TYPE_LEVEL_LOW>; - pinctrl-names = "default", "pmic-power-off"; - pinctrl-0 = <&pmic_pins>, <&rk806_dvs1_null>, <&rk806_dvs2_null>, <&rk806_dvs3_null>; - pinctrl-1 = <&rk806_dvs2_pwrdn>; + pinctrl-names = "default"; + pinctrl-0 = <&pmic_pins>; //for rk3576 have ultra sleep circuit design pwrctrl3_output = <0>; + shutown_by_pwrctrln = <2>; /* 2800mv-3500mv */ low_voltage_threshold = <3000>; From bc08d6c1b9c5a9f85be069d05f3e1b82bd304ed3 Mon Sep 17 00:00:00 2001 From: Jianwei Fan Date: Mon, 25 Aug 2025 15:40:15 +0800 Subject: [PATCH 07/40] media: i2c: rk628: add ioctl to get process output color range/space Signed-off-by: Jianwei Fan Change-Id: I777397d2e77985859e03563dd3f10a7b0c6b793e --- drivers/media/i2c/rk628/rk628_csi_v4l2.c | 9 +++++++++ drivers/media/i2c/rk628/rk628_post_process.c | 6 ++++-- drivers/media/i2c/rk628/rk628_post_process.h | 2 ++ include/uapi/linux/rk_hdmirx_config.h | 6 ++++++ 4 files changed, 21 insertions(+), 2 deletions(-) diff --git a/drivers/media/i2c/rk628/rk628_csi_v4l2.c b/drivers/media/i2c/rk628/rk628_csi_v4l2.c index 56ff4868500b..71419ecae862 100644 --- a/drivers/media/i2c/rk628/rk628_csi_v4l2.c +++ b/drivers/media/i2c/rk628/rk628_csi_v4l2.c @@ -2627,6 +2627,7 @@ static long rk628_csi_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg) u32 stream = 0; int edid_version, i; struct hdr_metadata_infoframe hdmi_metadata; + u8 input_color_space; switch (cmd) { case RKMODULE_GET_MODULE_INFO: @@ -2729,6 +2730,14 @@ static long rk628_csi_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg) rk628_hdmirx_get_hdr_matedata(csi->rk628, &hdmi_metadata); memcpy(arg, &hdmi_metadata, sizeof(hdmi_metadata)); break; + case RK_HDMIRX_CMD_GET_OUTPUT_COLOR_RANGE: + *(int *)arg = HDMIRX_FULL_RANGE; + break; + case RK_HDMIRX_CMD_GET_OUTPUT_COLOR_SPACE: + input_color_space = rk628_csc_color_space_convert(csi->rk628->color_space, + csi->rk628->color_format); + *(int *)arg = rk628_get_output_color_space(csi->rk628, input_color_space); + break; default: ret = -ENOIOCTLCMD; break; diff --git a/drivers/media/i2c/rk628/rk628_post_process.c b/drivers/media/i2c/rk628/rk628_post_process.c index 05db9ee6f6fc..ffafabf01bc1 100644 --- a/drivers/media/i2c/rk628/rk628_post_process.c +++ b/drivers/media/i2c/rk628/rk628_post_process.c @@ -1603,7 +1603,7 @@ static int rockchip_calc_post_csc(struct rk628 *rk628, struct post_csc_coef *csc return ret; } -static u8 rk628_csc_color_space_convert(u8 in_color_space, u8 format) +u8 rk628_csc_color_space_convert(u8 in_color_space, u8 format) { switch (in_color_space) { case HDMIRX_XVYCC601: @@ -1628,8 +1628,9 @@ static u8 rk628_csc_color_space_convert(u8 in_color_space, u8 format) return OPTM_CS_E_UNKNOWN; } } +EXPORT_SYMBOL(rk628_csc_color_space_convert); -static u8 rk628_get_output_color_space(struct rk628 *rk628, u8 input_color_space) +u8 rk628_get_output_color_space(struct rk628 *rk628, u8 input_color_space) { switch (input_color_space) { case OPTM_CS_E_XV_YCC_601: @@ -1646,6 +1647,7 @@ static u8 rk628_get_output_color_space(struct rk628 *rk628, u8 input_color_space return OPTM_CS_E_XV_YCC_709; } } +EXPORT_SYMBOL(rk628_get_output_color_space); static void rk628_post_process_csc(struct rk628 *rk628, bool is_input_full_range, bool is_output_full_range) diff --git a/drivers/media/i2c/rk628/rk628_post_process.h b/drivers/media/i2c/rk628/rk628_post_process.h index a9ccbcb49929..4503910b872c 100644 --- a/drivers/media/i2c/rk628/rk628_post_process.h +++ b/drivers/media/i2c/rk628/rk628_post_process.h @@ -7,6 +7,8 @@ #ifndef POST_PROCESS_H #define POST_PROCESS_H +u8 rk628_csc_color_space_convert(u8 in_color_space, u8 format); +u8 rk628_get_output_color_space(struct rk628 *rk628, u8 input_color_space); void rk628_post_process_csc_en(struct rk628 *rk628, bool input_full_range, bool output_full_range); void rk628_post_process_csc_dis(struct rk628 *rk628); void rk628_post_process_pattern_node(struct rk628 *rk628); diff --git a/include/uapi/linux/rk_hdmirx_config.h b/include/uapi/linux/rk_hdmirx_config.h index d22008fc20ab..abc6ec7c5452 100644 --- a/include/uapi/linux/rk_hdmirx_config.h +++ b/include/uapi/linux/rk_hdmirx_config.h @@ -123,6 +123,12 @@ enum user_color_range { #define RK_HDMIRX_CMD_GET_HDR_METADATA \ _IOR('V', BASE_VIDIOC_PRIVATE + 18, struct hdr_metadata_infoframe) +#define RK_HDMIRX_CMD_GET_OUTPUT_COLOR_RANGE \ + _IOR('V', BASE_VIDIOC_PRIVATE + 19, int) + +#define RK_HDMIRX_CMD_GET_OUTPUT_COLOR_SPACE \ + _IOR('V', BASE_VIDIOC_PRIVATE + 20, int) + /* Private v4l2 event */ #define RK_HDMIRX_V4L2_EVENT_SIGNAL_LOST \ (V4L2_EVENT_PRIVATE_START + 1) From 0241b8bd2a679f5dd6c5ccb6093d5196cf6d0d32 Mon Sep 17 00:00:00 2001 From: Jon Lin Date: Mon, 15 Sep 2025 18:14:37 +0800 Subject: [PATCH 08/40] phy: rockchip-snps-pcie3: Support rockchip,skip-init For special scenarios, such as after the PCIe PHY is bifurcation and with different usage like phy1 is the RC and the other phy0 is the EP. Since the EP has been initialized in the previous stage, it is not expected that repeated initialization in the kernel stage will cause the link to be disconnected. Therefore, no matter which of the two controllers performs initialization, the PHY re-initialization operation should be avoided. Change-Id: I7c04b537b18020d434d14049c5a0661739713265 Signed-off-by: Jon Lin --- .../phy/rockchip/phy-rockchip-snps-pcie3.c | 42 ++++++++++++------- 1 file changed, 26 insertions(+), 16 deletions(-) diff --git a/drivers/phy/rockchip/phy-rockchip-snps-pcie3.c b/drivers/phy/rockchip/phy-rockchip-snps-pcie3.c index 2933c6fdfb46..57965475cd05 100644 --- a/drivers/phy/rockchip/phy-rockchip-snps-pcie3.c +++ b/drivers/phy/rockchip/phy-rockchip-snps-pcie3.c @@ -59,6 +59,7 @@ struct rockchip_p3phy_priv { struct clk_bulk_data *clks; int num_clks; bool is_bifurcation; + bool is_initialized; }; struct rockchip_p3phy_ops { @@ -215,6 +216,9 @@ static int rockchip_p3phy_init(struct phy *phy) return ret; } + if (priv->is_initialized) + return 0; + reset_control_assert(priv->p30phy); udelay(1); @@ -233,6 +237,7 @@ static int rockchip_p3phy_exit(struct phy *phy) clk_bulk_disable_unprepare(priv->num_clks, priv->clks); reset_control_assert(priv->p30phy); + priv->is_initialized = false; return 0; } @@ -283,33 +288,38 @@ static int rockchip_p3phy_probe(struct platform_device *pdev) if (IS_ERR(priv->pipe_grf)) dev_info(dev, "failed to find rockchip,pipe_grf regmap\n"); - /* Configuring grf with clk enabled. */ - ret = clk_bulk_prepare_enable(priv->num_clks, priv->clks); - if (ret) { - pr_err("failed to enable PCIe bulk clks %d\n", ret); - return ret; - } + priv->is_initialized = device_property_read_bool(dev, "rockchip,skip-init"); ret = device_property_read_u32(dev, "rockchip,pcie30-phymode", &val); if (!ret) { priv->pcie30_phymode = val; if (priv->pcie30_phymode > 4) priv->pcie30_phymode = PHY_MODE_PCIE_AGGREGATION; - regmap_write(priv->phy_grf, RK3588_PCIE3PHY_GRF_CMN_CON0, - (0x7<<16) | priv->pcie30_phymode); } else { priv->pcie30_phymode = PHY_MODE_PCIE_AGGREGATION; } - /* Set pcie1ln_sel in PHP_GRF_PCIESEL_CON */ - if (!IS_ERR(priv->pipe_grf)) { - reg = priv->pcie30_phymode & 3; - if (reg) - regmap_write(priv->pipe_grf, PHP_GRF_PCIESEL_CON, - (reg << 16) | reg); - }; + if (!priv->is_initialized) { + ret = clk_bulk_prepare_enable(priv->num_clks, priv->clks); + if (ret) { + pr_err("failed to enable PCIe bulk clks %d\n", ret); + return ret; + } - clk_bulk_disable_unprepare(priv->num_clks, priv->clks); + if (priv->pcie30_phymode != PHY_MODE_PCIE_AGGREGATION) + regmap_write(priv->phy_grf, RK3588_PCIE3PHY_GRF_CMN_CON0, + (0x7 << 16) | priv->pcie30_phymode); + + /* Set pcie1ln_sel in PHP_GRF_PCIESEL_CON */ + if (!IS_ERR(priv->pipe_grf)) { + reg = priv->pcie30_phymode & 3; + if (reg) + regmap_write(priv->pipe_grf, PHP_GRF_PCIESEL_CON, + (reg << 16) | reg); + }; + + clk_bulk_disable_unprepare(priv->num_clks, priv->clks); + } priv->phy = devm_phy_create(dev, NULL, &rockchip_p3phy_ops); if (IS_ERR(priv->phy)) { From 7444be54f4be3c0db2e7ebf52d8be984943d98cc Mon Sep 17 00:00:00 2001 From: Tao Huang Date: Fri, 26 Sep 2025 11:09:05 +0800 Subject: [PATCH 09/40] rtc: rk630: Use devm_rtc_register_device() According to commit fdcfd854333b ("rtc: rework rtc_register_device() resource management"). Signed-off-by: Tao Huang Change-Id: If37750a01675a5d5e2b9231d1549e70bc349a3e7 --- drivers/rtc/rtc-rk630.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/rtc/rtc-rk630.c b/drivers/rtc/rtc-rk630.c index c931301a588d..827b19453261 100644 --- a/drivers/rtc/rtc-rk630.c +++ b/drivers/rtc/rtc-rk630.c @@ -619,7 +619,7 @@ static int rk630_rtc_probe(struct platform_device *pdev) return ret; } - return rtc_register_device(rk630_rtc->rtc); + return devm_rtc_register_device(rk630_rtc->rtc); } static struct platform_driver rk630_rtc_driver = { From 77ce0f10e6b10c434c31d009a6e6ce9216410c67 Mon Sep 17 00:00:00 2001 From: Zitong Cai Date: Thu, 18 Sep 2025 11:20:57 +0800 Subject: [PATCH 10/40] arm64: dts: rockchip: vehicle-evb: Fix the abnormal operation of dp phy when switching dp Change-Id: I86e89a26b8b356571d2870f15abbd889485d7fb6 Signed-off-by: Zitong Cai --- arch/arm64/boot/dts/rockchip/rk3576-vehicle-evb-v20.dts | 4 ++++ .../boot/dts/rockchip/rk3576-vehicle-evb-v21-mcu.dts | 4 ++++ arch/arm64/boot/dts/rockchip/rk3576-vehicle-evb-v21.dts | 4 ++++ arch/arm64/boot/dts/rockchip/rk3588-vehicle-evb-v22.dts | 9 ++++++++- arch/arm64/boot/dts/rockchip/rk3588-vehicle-evb-v23.dts | 8 ++++++++ 5 files changed, 28 insertions(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/rockchip/rk3576-vehicle-evb-v20.dts b/arch/arm64/boot/dts/rockchip/rk3576-vehicle-evb-v20.dts index fb838682d3ca..d7b9562bf4b4 100644 --- a/arch/arm64/boot/dts/rockchip/rk3576-vehicle-evb-v20.dts +++ b/arch/arm64/boot/dts/rockchip/rk3576-vehicle-evb-v20.dts @@ -561,6 +561,10 @@ status = "okay"; }; +&usbdp_phy_u3 { + status = "disabled"; +}; + &usb_drd1_dwc3 { snps,dis_u2_susphy_quirk; snps,usb2-lpm-disable; diff --git a/arch/arm64/boot/dts/rockchip/rk3576-vehicle-evb-v21-mcu.dts b/arch/arm64/boot/dts/rockchip/rk3576-vehicle-evb-v21-mcu.dts index 44162ee09a4e..27427e35d9cb 100644 --- a/arch/arm64/boot/dts/rockchip/rk3576-vehicle-evb-v21-mcu.dts +++ b/arch/arm64/boot/dts/rockchip/rk3576-vehicle-evb-v21-mcu.dts @@ -574,6 +574,10 @@ status = "okay"; }; +&usbdp_phy_u3 { + status = "disabled"; +}; + &usb_drd1_dwc3 { snps,dis_u2_susphy_quirk; snps,usb2-lpm-disable; diff --git a/arch/arm64/boot/dts/rockchip/rk3576-vehicle-evb-v21.dts b/arch/arm64/boot/dts/rockchip/rk3576-vehicle-evb-v21.dts index 9e119c0a1b16..d4b1131656a8 100644 --- a/arch/arm64/boot/dts/rockchip/rk3576-vehicle-evb-v21.dts +++ b/arch/arm64/boot/dts/rockchip/rk3576-vehicle-evb-v21.dts @@ -569,6 +569,10 @@ status = "okay"; }; +&usbdp_phy_u3 { + status = "disabled"; +}; + &usb_drd1_dwc3 { snps,dis_u2_susphy_quirk; snps,usb2-lpm-disable; diff --git a/arch/arm64/boot/dts/rockchip/rk3588-vehicle-evb-v22.dts b/arch/arm64/boot/dts/rockchip/rk3588-vehicle-evb-v22.dts index e417edfe9a5b..044001ecd81b 100644 --- a/arch/arm64/boot/dts/rockchip/rk3588-vehicle-evb-v22.dts +++ b/arch/arm64/boot/dts/rockchip/rk3588-vehicle-evb-v22.dts @@ -562,6 +562,14 @@ phy-supply = <&vcc5v0_host_usb30>; }; +&usbdp_phy0_u3 { + status = "disabled"; +}; + +&usbdp_phy1_u3 { + status = "disabled"; +}; + &vdd_log_s0 { regulator-state-mem { regulator-on-in-suspend; @@ -591,4 +599,3 @@ &vcc5v0_host { status = "disabled"; }; - diff --git a/arch/arm64/boot/dts/rockchip/rk3588-vehicle-evb-v23.dts b/arch/arm64/boot/dts/rockchip/rk3588-vehicle-evb-v23.dts index 12d8ef5d4d30..c63cc0134a2f 100644 --- a/arch/arm64/boot/dts/rockchip/rk3588-vehicle-evb-v23.dts +++ b/arch/arm64/boot/dts/rockchip/rk3588-vehicle-evb-v23.dts @@ -859,6 +859,14 @@ phy-supply = <&vcc5v0_host_usb30>; }; +&usbdp_phy0_u3 { + status = "disabled"; +}; + +&usbdp_phy1_u3 { + status = "disabled"; +}; + &vdd_log_s0 { regulator-state-mem { regulator-on-in-suspend; From 04add2900912cff7a144a7c8e791f3ef4c9387dc Mon Sep 17 00:00:00 2001 From: Zitong Cai Date: Tue, 9 Sep 2025 20:28:25 +0800 Subject: [PATCH 11/40] arm64: dts: rockchip: vehicle-evb: Fix the issue of left and right shaking in probability display Change-Id: I759f845221455c2f0f5d227282fe7167fdab75f3 Signed-off-by: Zitong Cai --- ...icle-evb-v20-serdes-mfd-display-maxim.dtsi | 56 +++++-------------- ...ehicle-serdes-mfd-display-maxim-split.dtsi | 33 ++++++----- ...3588-vehicle-serdes-mfd-display-maxim.dtsi | 47 ++++++++-------- 3 files changed, 53 insertions(+), 83 deletions(-) diff --git a/arch/arm64/boot/dts/rockchip/rk3576-vehicle-evb-v20-serdes-mfd-display-maxim.dtsi b/arch/arm64/boot/dts/rockchip/rk3576-vehicle-evb-v20-serdes-mfd-display-maxim.dtsi index 5c08a3329b03..b66f9186ebf8 100644 --- a/arch/arm64/boot/dts/rockchip/rk3576-vehicle-evb-v20-serdes-mfd-display-maxim.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk3576-vehicle-evb-v20-serdes-mfd-display-maxim.dtsi @@ -282,62 +282,34 @@ 0322 0024 //Init Default 0326 00E4 - //HSYNC_WIDTH_L - 0385 0038 - //VSYNC_WIDTH_L - 0386 0008 + //HSYNC_WIDTH_L HSYNC=32 + 0385 0020 + //VSYNC_WIDTH_L VSYNC=2 + 0386 0002 //HSYNC_WIDTH_H/VSYNC_WIDTH_H 0387 0000 - //VFP_L + //VFP_L VFP=200 03A5 00C8 //VBP_H 03A7 0000 - //VFP_H/VBP_L - 03A6 0020 - //VRES_L + //VBP_L/VFP_H VBP=8 + 03A6 0080 + //VRES_L VRES=0X02D0=720 03A8 00D0 //VRES_H 03A9 0002 - //HFP_L + //HFP_L HFP=56 03AA 0038 //HBP_H - 03AC 0002 - //HFP_H/HBP_L - 03AB 0000 - //HRES_L + 03AC 0003 + //HBP_L/HFP_H(4bit) HBP=56 + 03AB 0080 + //HRES_L HRES=0X0780=1920 03AD 0080 //HRES_H 03AE 0007 //Disable FIFO/DESKEW_EN - 03A4 00C0 - //HSYNC_WIDTH_L - 0395 0038 - //VSYNC_WIDTH_L - 0396 0008 - //HSYNC_WIDTH_H/VSYNC_WIDTH_H - 0397 0000 - //VFP_L - 03B1 00C8 - //VBP_H - 03B3 0000 - //VFP_H/VBP_L - 03B2 0020 - //VRES_L - 03B4 00D0 - //VRES_H - 03B5 0002 - //HFP_L - 03B6 0038 - //HBP_H - 03B8 0002 - //HFP_H/HBP_L - 03B7 0000 - //HRES_L - 03B9 0080 - //HRES_H - 03BA 0007 - //Disable FIFO/DESKEW_EN - 03B0 00C0 + 03A4 00C1 //Turn on video pipe 0002 0033 //Enable splitter mode reset one shot diff --git a/arch/arm64/boot/dts/rockchip/rk3588-vehicle-serdes-mfd-display-maxim-split.dtsi b/arch/arm64/boot/dts/rockchip/rk3588-vehicle-serdes-mfd-display-maxim-split.dtsi index 035c1cfb09d3..bf32c5cd090f 100644 --- a/arch/arm64/boot/dts/rockchip/rk3588-vehicle-serdes-mfd-display-maxim-split.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk3588-vehicle-serdes-mfd-display-maxim-split.dtsi @@ -499,8 +499,8 @@ 03A5 00C8 //VBP_H 03A7 0000 - //VFP_H/VBP_L VBP=8 - 03A6 0008 + //VBP_L/VFP_H VBP=8 + 03A6 0080 //VRES_L VRES=0X02D0=720 03A8 00D0 //VRES_H @@ -509,14 +509,14 @@ 03AA 0038 //HBP_H 03AC 0003 - //HFP_H/HBP_L(4bit) HBP=56 - 03AB 0008 + //HBP_L/HFP_H(4bit) HBP=56 + 03AB 0080 //HRES_L HRES=0X0780=1920 03AD 0080 //HRES_H 03AE 0007 //Disable FIFO/DESKEW_EN - 03A4 00C0 + 03A4 00C1 //HSYNC_WIDTH_L HSYNC=40 0395 0028 //VSYNC_WIDTH_L VSYNC=20 @@ -527,8 +527,8 @@ 03B1 000F //VBP_H 03B3 0000 - //VFP_H/VBP_L VBP=10 - 03B2 000A + //VBP_L/VFP_H VBP=10 + 03B2 00A0 //VRES_L VRES=0X0438=1080 03B4 0038 //VRES_H @@ -537,14 +537,14 @@ 03B6 008C //HBP_H 03B8 0006 - //HFP_H/HBP_L HBP=100 - 03B7 0004 + //HBP_L/HFP_H HBP=100 + 03B7 0040 //HRES_L HRES=0X0780=1920 03B9 0080 //HRES_H 03BA 0007 //Disable FIFO/DESKEW_EN - 03B0 00C0 + 03B0 00C1 //Turn on video pipe 0002 0033 //Enable splitter mode reset one shot @@ -740,7 +740,7 @@ panel-size= <346 194>; panel-timing { - clock-frequency = <115200000>; + clock-frequency = <115000000>; hactive = <1920>; vactive = <720>; hfront-porch = <56>; @@ -1422,7 +1422,7 @@ panel-size= <346 194>; panel-timing { - clock-frequency = <230400000>; //4128*930@60 + clock-frequency = <230000000>; //3840*720@60 hactive = <3840>; vactive = <720>; hfront-porch = <112>; @@ -1550,7 +1550,7 @@ panel-size= <346 194>; panel-timing { - clock-frequency = <115200000>; + clock-frequency = <115000000>; hactive = <1920>; vactive = <720>; hfront-porch = <56>; @@ -2101,7 +2101,7 @@ panel-size= <346 194>; panel-timing { - clock-frequency = <230400000>; //4128*930@60 + clock-frequency = <230000000>; //3840*720@60 hactive = <3840>; vactive = <720>; hfront-porch = <112>; @@ -2230,7 +2230,7 @@ panel-size= <346 194>; panel-timing { - clock-frequency = <115200000>; + clock-frequency = <115000000>; hactive = <1920>; vactive = <720>; hfront-porch = <56>; @@ -2413,8 +2413,7 @@ }; &vop { - assigned-clocks = <&cru PLL_V0PLL>; - assigned-clock-rates = <2304000000>; + status = "okay"; }; &vp0 { diff --git a/arch/arm64/boot/dts/rockchip/rk3588-vehicle-serdes-mfd-display-maxim.dtsi b/arch/arm64/boot/dts/rockchip/rk3588-vehicle-serdes-mfd-display-maxim.dtsi index fbe04680f379..3c3b31b37226 100644 --- a/arch/arm64/boot/dts/rockchip/rk3588-vehicle-serdes-mfd-display-maxim.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk3588-vehicle-serdes-mfd-display-maxim.dtsi @@ -499,8 +499,8 @@ 03A5 00C8 //VBP_H 03A7 0000 - //VFP_H/VBP_L VBP=8 - 03A6 0008 + //VBP_L/VFP_H VBP=8 + 03A6 0080 //VRES_L VRES=0X02D0=720 03A8 00D0 //VRES_H @@ -509,42 +509,42 @@ 03AA 0038 //HBP_H 03AC 0003 - //HFP_H/HBP_L(4bit) HBP=56 - 03AB 0008 + //HBP_L/HFP_H(4bit) HBP=56 + 03AB 0080 //HRES_L HRES=0X0780=1920 03AD 0080 //HRES_H 03AE 0007 //Disable FIFO/DESKEW_EN - 03A4 00C0 - //HSYNC_WIDTH_L HSYNC=40 - 0395 0028 - //VSYNC_WIDTH_L VSYNC=20 - 0396 0014 + 03A4 00C1 + //HSYNC_WIDTH_L HSYNC=32 + 0395 0020 + //VSYNC_WIDTH_L VSYNC=2 + 0396 0002 //HSYNC_WIDTH_H/VSYNC_WIDTH_H 0397 0000 - //VFP_L VFP=15 - 03B1 000F + //VFP_L VFP=200 + 03B1 00C8 //VBP_H 03B3 0000 - //VFP_H/VBP_L VBP=10 - 03B2 000A - //VRES_L VRES=0X0438=1080 - 03B4 0038 + //VBP_L/VFP_H VBP=8 + 03B2 0080 + //VRES_L VRES=0X02D0=720 + 03B4 00D0 //VRES_H - 03B5 0004 - //HFP_L HFP=140 - 03B6 008C + 03B5 0002 + //HFP_L HFP=56 + 03B6 0038 //HBP_H - 03B8 0006 - //HFP_H/HBP_L HBP=100 - 03B7 0004 + 03B8 0003 + //HBP_L/HFP_H HBP=56 + 03B7 0080 //HRES_L HRES=0X0780=1920 03B9 0080 //HRES_H 03BA 0007 //Disable FIFO/DESKEW_EN - 03B0 00C0 + 03B0 00C1 //Turn on video pipe 0002 0033 //Enable splitter mode reset one shot @@ -2103,8 +2103,7 @@ }; &vop { - assigned-clocks = <&cru PLL_V0PLL>; - assigned-clock-rates = <1150000000>; + status = "okay"; }; //dp &vp0 { From e81982d9e242815c9ce1b1e3f2db2ce7450c94d4 Mon Sep 17 00:00:00 2001 From: Jianwei Fan Date: Mon, 22 Sep 2025 10:30:34 +0800 Subject: [PATCH 12/40] media: i2c: bridge: add ioctl RK_HDMIRX_CMD_GET_SIGNAL_STABLE_STATUS Signed-off-by: Jianwei Fan Change-Id: Ibb8af426e677e3615b2eb1be4dc2dcdf15d1045b --- drivers/media/i2c/it6616.c | 33 +++++++++++++++++++++++++++------ drivers/media/i2c/lt6911c.c | 18 ++++++++++++++++++ drivers/media/i2c/lt6911uxc.c | 18 ++++++++++++++++++ drivers/media/i2c/lt6911uxe.c | 19 ++++++++++++++++++- drivers/media/i2c/lt7911d.c | 18 ++++++++++++++++++ drivers/media/i2c/lt7911uxc.c | 19 ++++++++++++++++++- drivers/media/i2c/lt8668sx.c | 19 ++++++++++++++++++- drivers/media/i2c/tc35874x.c | 18 ++++++++++++++++++ 8 files changed, 153 insertions(+), 9 deletions(-) diff --git a/drivers/media/i2c/it6616.c b/drivers/media/i2c/it6616.c index 295b7930e6a2..42fdcad6cd0f 100644 --- a/drivers/media/i2c/it6616.c +++ b/drivers/media/i2c/it6616.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #include @@ -265,7 +266,7 @@ enum av_mute_state { }; enum { - AUDIO_OFF = 0x00, + AUDIO_OFF_MODE = 0x00, AUDIO_I2S = 0x01, AUDIO_SPDIF = 0x02, }; @@ -2659,7 +2660,7 @@ static void it6616_hdmi_tx_audio_output_enable(struct it6616 *it6616, u8 output_ it6616_hdmi_chgbank(hdmi, 1); switch (output_interface) { - case AUDIO_OFF: + case AUDIO_OFF_MODE: dev_info(dev, "audio off"); it6616_hdmi_write(hdmi, 0xC7, 0x7F); // SPDIF/I2S tri-state on break; @@ -2685,7 +2686,7 @@ static void it6616_hdmi_audio_mute_clear(struct it6616 *it6616) static void it6616_hdmi_rx_audio_process(struct it6616 *it6616) { - it6616_hdmi_tx_audio_output_enable(it6616, AUDIO_OFF); + it6616_hdmi_tx_audio_output_enable(it6616, AUDIO_OFF_MODE); it6616_hdmi_rx_reset_audio_logic(it6616); it6616_hdmi_tx_audio_setup(it6616); it6616_hdmi_audio_mute_clear(it6616); @@ -3052,6 +3053,7 @@ static int it6616_initial(struct it6616 *it6616) /* get device id */ if (it6616_get_chip_id(it6616)) { dev_err(dev, "can not find it6616"); + mutex_unlock(&it6616->confctl_mutex); return -ENODEV; } @@ -3277,7 +3279,7 @@ static ssize_t mipi_reg_store(struct device *dev, if (ret) { dev_info(dev, "addr= %2.2X\n", addr); dev_info(dev, "val = %2.2X\n", val); - if (((addr <= 0xFF) && (addr >= 0x00)) && ((val <= 0xFF) && (val >= 0x00))) + if (addr <= 0xFF && val <= 0xFF) regmap_write(mipi, addr, val); } else { dev_info(dev, "it6616_fwrite_mipi_reg , error[%s]\n", buf); @@ -3409,7 +3411,7 @@ static int it6616_get_detected_timings(struct v4l2_subdev *sd, bt->il_vsync = bt->vsync + 1; } - v4l2_dbg(1, debug, sd, "act:%dx%d, total:%dx%d, pixclk:%d, fps:%d\n", + v4l2_dbg(1, debug, sd, "act:%dx%d, total:%dx%d, pixclk:%llu, fps:%d\n", bt->width, bt->height, htotal, vtotal, bt->pixelclock, fps); v4l2_dbg(1, debug, sd, "hfp:%d, hs:%d, hbp:%d, vfp:%d, vs:%d, vbp:%d\n", bt->hfrontporch, bt->hsync, bt->hbackporch, @@ -3871,6 +3873,9 @@ static long it6616_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg) case RKMODULE_GET_HDMI_MODE: *(int *)arg = RKMODULE_HDMIIN_MODE; break; + case RK_HDMIRX_CMD_GET_SIGNAL_STABLE_STATUS: + *(int *)arg = !it6616->nosignal; + break; default: ret = -ENOIOCTLCMD; break; @@ -3932,6 +3937,20 @@ static long it6616_compat_ioctl32(struct v4l2_subdev *sd, return ret; } + ret = it6616_ioctl(sd, cmd, seq); + if (!ret) { + ret = copy_to_user(up, seq, sizeof(*seq)); + if (ret) + ret = -EFAULT; + } + kfree(seq); + break; + case RK_HDMIRX_CMD_GET_SIGNAL_STABLE_STATUS: + seq = kzalloc(sizeof(*seq), GFP_KERNEL); + if (!seq) { + ret = -ENOMEM; + return ret; + } ret = it6616_ioctl(sd, cmd, seq); if (!ret) { ret = copy_to_user(up, seq, sizeof(*seq)); @@ -4257,8 +4276,10 @@ static int it6616_probe(struct i2c_client *client, it6616->edid_i2c = i2c_new_dummy_device(client->adapter, I2C_ADR_EDID >> 1); - if (!it6616->edid_i2c) + if (!it6616->edid_i2c) { + err = -EIO; goto unregister_mipi_i2c; + } it6616->hdmi_regmap = devm_regmap_init_i2c(client, &it6616_hdmi_regmap_config); diff --git a/drivers/media/i2c/lt6911c.c b/drivers/media/i2c/lt6911c.c index 6b2f33a14fc6..621d62a407a8 100644 --- a/drivers/media/i2c/lt6911c.c +++ b/drivers/media/i2c/lt6911c.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include @@ -973,6 +974,9 @@ static long lt6911c_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg) dev_dbg(<6911c->i2c_client->dev, "sensor get dphy param\n"); break; + case RK_HDMIRX_CMD_GET_SIGNAL_STABLE_STATUS: + *(int *)arg = !lt6911c->nosignal; + break; default: ret = -ENOIOCTLCMD; break; @@ -1051,6 +1055,20 @@ static long lt6911c_compat_ioctl32(struct v4l2_subdev *sd, } kfree(dphy_param); break; + case RK_HDMIRX_CMD_GET_SIGNAL_STABLE_STATUS: + seq = kzalloc(sizeof(*seq), GFP_KERNEL); + if (!seq) { + ret = -ENOMEM; + return ret; + } + ret = lt6911c_ioctl(sd, cmd, seq); + if (!ret) { + ret = copy_to_user(up, seq, sizeof(*seq)); + if (ret) + ret = -EFAULT; + } + kfree(seq); + break; default: ret = -ENOIOCTLCMD; break; diff --git a/drivers/media/i2c/lt6911uxc.c b/drivers/media/i2c/lt6911uxc.c index 0dd879dae31c..c2ba244c42ed 100644 --- a/drivers/media/i2c/lt6911uxc.c +++ b/drivers/media/i2c/lt6911uxc.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #include @@ -1028,6 +1029,9 @@ static long lt6911uxc_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg) capture_info->mode = 0; } break; + case RK_HDMIRX_CMD_GET_SIGNAL_STABLE_STATUS: + *(int *)arg = !lt6911uxc->nosignal; + break; default: ret = -ENOIOCTLCMD; break; @@ -1122,6 +1126,20 @@ static long lt6911uxc_compat_ioctl32(struct v4l2_subdev *sd, } kfree(capture_info); break; + case RK_HDMIRX_CMD_GET_SIGNAL_STABLE_STATUS: + seq = kzalloc(sizeof(*seq), GFP_KERNEL); + if (!seq) { + ret = -ENOMEM; + return ret; + } + ret = lt6911uxc_ioctl(sd, cmd, seq); + if (!ret) { + ret = copy_to_user(up, seq, sizeof(*seq)); + if (ret) + ret = -EFAULT; + } + kfree(seq); + break; default: ret = -ENOIOCTLCMD; break; diff --git a/drivers/media/i2c/lt6911uxe.c b/drivers/media/i2c/lt6911uxe.c index 64cf63cc3e08..05bf585cc75f 100644 --- a/drivers/media/i2c/lt6911uxe.c +++ b/drivers/media/i2c/lt6911uxe.c @@ -28,6 +28,7 @@ #include #include #include +#include #include #include #include @@ -41,7 +42,6 @@ #include #include #include -#include #define DRIVER_VERSION KERNEL_VERSION(0, 0x01, 0x06) @@ -1532,6 +1532,9 @@ static long lt6911uxe_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg) capture_info->multi_dev = lt6911uxe->multi_dev_info; } break; + case RK_HDMIRX_CMD_GET_SIGNAL_STABLE_STATUS: + *(int *)arg = !lt6911uxe->nosignal; + break; default: ret = -ENOIOCTLCMD; break; @@ -1647,6 +1650,20 @@ static long lt6911uxe_compat_ioctl32(struct v4l2_subdev *sd, } kfree(capture_info); break; + case RK_HDMIRX_CMD_GET_SIGNAL_STABLE_STATUS: + seq = kzalloc(sizeof(*seq), GFP_KERNEL); + if (!seq) { + ret = -ENOMEM; + return ret; + } + ret = lt6911uxe_ioctl(sd, cmd, seq); + if (!ret) { + ret = copy_to_user(up, seq, sizeof(*seq)); + if (ret) + ret = -EFAULT; + } + kfree(seq); + break; default: ret = -ENOIOCTLCMD; break; diff --git a/drivers/media/i2c/lt7911d.c b/drivers/media/i2c/lt7911d.c index 830282be4e1b..5ddac0f5370b 100644 --- a/drivers/media/i2c/lt7911d.c +++ b/drivers/media/i2c/lt7911d.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -900,6 +901,9 @@ static long lt7911d_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg) case RKMODULE_GET_HDMI_MODE: *(int *)arg = RKMODULE_HDMIIN_MODE; break; + case RK_HDMIRX_CMD_GET_SIGNAL_STABLE_STATUS: + *(int *)arg = !lt7911d->nosignal; + break; default: ret = -ENOIOCTLCMD; break; @@ -940,6 +944,20 @@ static long lt7911d_compat_ioctl32(struct v4l2_subdev *sd, return ret; } + ret = lt7911d_ioctl(sd, cmd, seq); + if (!ret) { + ret = copy_to_user(up, seq, sizeof(*seq)); + if (ret) + ret = -EFAULT; + } + kfree(seq); + break; + case RK_HDMIRX_CMD_GET_SIGNAL_STABLE_STATUS: + seq = kzalloc(sizeof(*seq), GFP_KERNEL); + if (!seq) { + ret = -ENOMEM; + return ret; + } ret = lt7911d_ioctl(sd, cmd, seq); if (!ret) { ret = copy_to_user(up, seq, sizeof(*seq)); diff --git a/drivers/media/i2c/lt7911uxc.c b/drivers/media/i2c/lt7911uxc.c index a894436bae27..eb92fbe5ff6f 100644 --- a/drivers/media/i2c/lt7911uxc.c +++ b/drivers/media/i2c/lt7911uxc.c @@ -31,6 +31,7 @@ #include #include #include +#include #include #include #include @@ -44,7 +45,6 @@ #include #include #include -#include #define DRIVER_VERSION KERNEL_VERSION(0, 0x01, 0x07) @@ -1193,6 +1193,9 @@ static long lt7911uxc_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg) dev_dbg(<7911uxc->i2c_client->dev, "sensor get dphy param\n"); break; + case RK_HDMIRX_CMD_GET_SIGNAL_STABLE_STATUS: + *(int *)arg = !lt7911uxc->nosignal; + break; default: ret = -ENOIOCTLCMD; break; @@ -1292,6 +1295,20 @@ static long lt7911uxc_compat_ioctl32(struct v4l2_subdev *sd, } kfree(dphy_param); break; + case RK_HDMIRX_CMD_GET_SIGNAL_STABLE_STATUS: + seq = kzalloc(sizeof(*seq), GFP_KERNEL); + if (!seq) { + ret = -ENOMEM; + return ret; + } + ret = lt7911uxc_ioctl(sd, cmd, seq); + if (!ret) { + ret = copy_to_user(up, seq, sizeof(*seq)); + if (ret) + ret = -EFAULT; + } + kfree(seq); + break; default: ret = -ENOIOCTLCMD; break; diff --git a/drivers/media/i2c/lt8668sx.c b/drivers/media/i2c/lt8668sx.c index 6dedf8d00995..ea4b043e634c 100644 --- a/drivers/media/i2c/lt8668sx.c +++ b/drivers/media/i2c/lt8668sx.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include @@ -33,7 +34,6 @@ #include #include #include -#include #define DRIVER_VERSION KERNEL_VERSION(0, 0x01, 0x00) @@ -1181,6 +1181,9 @@ static long lt8668sx_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg) dev_dbg(<8668sx->i2c_client->dev, "sensor get dphy param\n"); break; + case RK_HDMIRX_CMD_GET_SIGNAL_STABLE_STATUS: + *(int *)arg = !lt8668sx->nosignal; + break; default: ret = -ENOIOCTLCMD; break; @@ -1280,6 +1283,20 @@ static long lt8668sx_compat_ioctl32(struct v4l2_subdev *sd, } kfree(dphy_param); break; + case RK_HDMIRX_CMD_GET_SIGNAL_STABLE_STATUS: + seq = kzalloc(sizeof(*seq), GFP_KERNEL); + if (!seq) { + ret = -ENOMEM; + return ret; + } + ret = lt8668sx_ioctl(sd, cmd, seq); + if (!ret) { + ret = copy_to_user(up, seq, sizeof(*seq)); + if (ret) + ret = -EFAULT; + } + kfree(seq); + break; default: ret = -ENOIOCTLCMD; break; diff --git a/drivers/media/i2c/tc35874x.c b/drivers/media/i2c/tc35874x.c index 2c9bbd63e4e1..0470684ca8a4 100644 --- a/drivers/media/i2c/tc35874x.c +++ b/drivers/media/i2c/tc35874x.c @@ -43,6 +43,7 @@ #include #include #include +#include #include #include #include @@ -1946,6 +1947,9 @@ static long tc35874x_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg) case RKMODULE_GET_HDMI_MODE: *(int *)arg = RKMODULE_HDMIIN_MODE; break; + case RK_HDMIRX_CMD_GET_SIGNAL_STABLE_STATUS: + *(int *)arg = !no_signal(sd); + break; default: ret = -ENOIOCTLCMD; break; @@ -2001,6 +2005,20 @@ static long tc35874x_compat_ioctl32(struct v4l2_subdev *sd, return ret; } + ret = tc35874x_ioctl(sd, cmd, seq); + if (!ret) { + ret = copy_to_user(up, seq, sizeof(*seq)); + if (ret) + ret = -EFAULT; + } + kfree(seq); + break; + case RK_HDMIRX_CMD_GET_SIGNAL_STABLE_STATUS: + seq = kzalloc(sizeof(*seq), GFP_KERNEL); + if (!seq) { + ret = -ENOMEM; + return ret; + } ret = tc35874x_ioctl(sd, cmd, seq); if (!ret) { ret = copy_to_user(up, seq, sizeof(*seq)); From f0612ad4787c4011fd978bda57feb10260433a51 Mon Sep 17 00:00:00 2001 From: Guochun Huang Date: Fri, 26 Sep 2025 15:17:50 +0800 Subject: [PATCH 13/40] arm64: dts: rockchip: rk3588s-evb: fix panel resolution info Fixes: cc761c9b6a31 ("arm64: dts: rockchip: add rk3588/rk3588s evb mipi panel info") Fixes: 8aa80d1c81c1 ("arm64: dts: rockchip: add rk3588s-tablet-rk806-single-v10.dts") Change-Id: I78f0a49099caec0eace0002a099877f2c67484ce Signed-off-by: Guochun Huang --- arch/arm64/boot/dts/rockchip/rk3588s-evb4-lp4x.dtsi | 2 +- arch/arm64/boot/dts/rockchip/rk3588s-tablet-rk806-single.dtsi | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm64/boot/dts/rockchip/rk3588s-evb4-lp4x.dtsi b/arch/arm64/boot/dts/rockchip/rk3588s-evb4-lp4x.dtsi index 8cfbba940433..603fb80736eb 100644 --- a/arch/arm64/boot/dts/rockchip/rk3588s-evb4-lp4x.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk3588s-evb4-lp4x.dtsi @@ -380,7 +380,7 @@ native-mode = <&dsi1_timing0>; dsi1_timing0: timing0 { clock-frequency = <280000000>; - hactive = <1140>; + hactive = <1440>; vactive = <3120>; hfront-porch = <16>; hsync-len = <8>; diff --git a/arch/arm64/boot/dts/rockchip/rk3588s-tablet-rk806-single.dtsi b/arch/arm64/boot/dts/rockchip/rk3588s-tablet-rk806-single.dtsi index 2a299227d605..3f6f897a012e 100644 --- a/arch/arm64/boot/dts/rockchip/rk3588s-tablet-rk806-single.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk3588s-tablet-rk806-single.dtsi @@ -1071,7 +1071,7 @@ native-mode = <&dsi1_timing0>; dsi1_timing0: timing0 { clock-frequency = <280000000>; - hactive = <1140>; + hactive = <1440>; vactive = <3120>; hfront-porch = <16>; hsync-len = <8>; From ce6592f012785f7628e9bf6d5d2db5046532925d Mon Sep 17 00:00:00 2001 From: Haoran Han Date: Tue, 2 Sep 2025 16:10:31 +0800 Subject: [PATCH 14/40] arm64: configs: rk3576_vehicle.config: add CONFIG_VIDEO_MAX96756=y Change-Id: I05c3aa2938b6d86b7c1cf84fab4c436a9159fa8c Signed-off-by: Haoran Han --- arch/arm64/configs/rk3576_vehicle.config | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm64/configs/rk3576_vehicle.config b/arch/arm64/configs/rk3576_vehicle.config index e49df7c51019..8faefdc6eeeb 100644 --- a/arch/arm64/configs/rk3576_vehicle.config +++ b/arch/arm64/configs/rk3576_vehicle.config @@ -106,6 +106,7 @@ CONFIG_VEHICLE_GPIO_MCU_EXPANDER=y # CONFIG_VIDEO_GC4C33 is not set # CONFIG_VIDEO_GC8034 is not set # CONFIG_VIDEO_IMX415 is not set +CONFIG_VIDEO_MAX96756=y CONFIG_VIDEO_MAXIM_SERDES=y # CONFIG_VIDEO_OV02B10 is not set # CONFIG_VIDEO_OV13850 is not set From 1e7a3292b6da5e6edf8449c2bc6efe60f48db603 Mon Sep 17 00:00:00 2001 From: Jianwei Fan Date: Thu, 4 Sep 2025 17:54:37 +0800 Subject: [PATCH 15/40] media: i2c: rk628: add status variable to determine whether CSI1 is enabled Signed-off-by: Jianwei Fan Change-Id: I6f127c210f9c755400efb4dbbe1c96aed5c3f917 --- drivers/media/i2c/rk628/rk628.h | 1 + drivers/media/i2c/rk628/rk628_csi_v4l2.c | 55 +++++++++++++----------- 2 files changed, 31 insertions(+), 25 deletions(-) diff --git a/drivers/media/i2c/rk628/rk628.h b/drivers/media/i2c/rk628/rk628.h index cc2e08b718c4..51adbde3854b 100644 --- a/drivers/media/i2c/rk628/rk628.h +++ b/drivers/media/i2c/rk628/rk628.h @@ -315,6 +315,7 @@ struct rk628 { bool last_mipi_status; bool is_suspend; bool is_10bit; + bool enable_csi1; }; #define rk628_dbg(rk628, format, ...) \ diff --git a/drivers/media/i2c/rk628/rk628_csi_v4l2.c b/drivers/media/i2c/rk628/rk628_csi_v4l2.c index 71419ecae862..ba610f6f6405 100644 --- a/drivers/media/i2c/rk628/rk628_csi_v4l2.c +++ b/drivers/media/i2c/rk628/rk628_csi_v4l2.c @@ -786,12 +786,12 @@ static void rk628_csi_soft_reset(struct v4l2_subdev *sd) struct rk628_csi *csi = to_csi(sd); rk628_i2c_write(csi->rk628, CSITX_SYS_CTRL0_IMD, 0x1); - if (csi->rk628->version >= RK628F_VERSION) + if (csi->rk628->version >= RK628F_VERSION && csi->rk628->enable_csi1) rk628_i2c_write(csi->rk628, CSITX1_SYS_CTRL0_IMD, 0x1); rk628_mipi_txdata_reset(sd); rk628_i2c_write(csi->rk628, CSITX_SYS_CTRL0_IMD, 0x0); - if (csi->rk628->version >= RK628F_VERSION) + if (csi->rk628->version >= RK628F_VERSION && csi->rk628->enable_csi1) rk628_i2c_write(csi->rk628, CSITX1_SYS_CTRL0_IMD, 0x0); } @@ -814,13 +814,14 @@ static void enable_csitx(struct v4l2_subdev *sd) csi->rk628->dual_mipi ? GRF_DPHY_CH1_EN(1) : 0); rk628_i2c_update_bits(csi->rk628, GRF_POST_PROC_CON, SW_SPLIT_EN, csi->rk628->dual_mipi ? SW_SPLIT_EN : 0); + csi->rk628->enable_csi1 = csi->rk628->dual_mipi; rk628_csi_set_csi(sd); rk628_csi_soft_reset(sd); usleep_range(5000, 5500); //disabled csi state ints rk628_i2c_write(csi->rk628, CSITX_INTR_EN_IMD, 0x0fff0000); - if (csi->rk628->version >= RK628F_VERSION) + if (csi->rk628->version >= RK628F_VERSION && csi->rk628->enable_csi1) rk628_i2c_write(csi->rk628, CSITX1_INTR_EN_IMD, 0x0fff0000); rk628_i2c_update_bits(csi->rk628, CSITX_CSITX_EN, @@ -829,7 +830,7 @@ static void enable_csitx(struct v4l2_subdev *sd) DPHY_EN(1) | CSITX_EN(1)); rk628_i2c_write(csi->rk628, CSITX_CONFIG_DONE, CONFIG_DONE_IMD); - if (csi->rk628->version >= RK628F_VERSION) { + if (csi->rk628->version >= RK628F_VERSION && csi->rk628->enable_csi1) { rk628_i2c_update_bits(csi->rk628, CSITX1_CSITX_EN, DPHY_EN_MASK | CSITX_EN_MASK, @@ -844,7 +845,7 @@ static void enable_csitx(struct v4l2_subdev *sd) BYPASS_SELECT_MASK, BYPASS_SELECT(0)); rk628_i2c_write(csi->rk628, CSITX_CONFIG_DONE, CONFIG_DONE_IMD); - if (csi->rk628->version >= RK628F_VERSION) { + if (csi->rk628->version >= RK628F_VERSION && csi->rk628->enable_csi1) { rk628_i2c_write(csi->rk628, CSITX1_ERR_INTR_CLR_IMD, 0xffffffff); rk628_i2c_write(csi->rk628, CSITX1_CONFIG_DONE, CONFIG_DONE_IMD); } @@ -957,7 +958,7 @@ static void rk628_csi_disable_stream(struct v4l2_subdev *sd) csi->continues_clk ? CONT_MODE_CLK_CLR(1) : CONT_MODE_CLK_CLR(0)); rk628_i2c_write(csi->rk628, CSITX_CONFIG_DONE, CONFIG_DONE_IMD); - if (csi->rk628->version >= RK628F_VERSION) { + if (csi->rk628->version >= RK628F_VERSION && csi->rk628->enable_csi1) { rk628_i2c_update_bits(csi->rk628, CSITX1_CSITX_EN, DPHY_EN_MASK | CSITX_EN_MASK, DPHY_EN(0) | CSITX_EN(0)); @@ -1107,7 +1108,7 @@ static void rk628_csi_set_csi(struct v4l2_subdev *sd) rk628_csi_disable_stream(sd); usleep_range(5000, 5500); rk628_csi0_cru_reset(sd); - if (csi->rk628->version >= RK628F_VERSION) + if (csi->rk628->version >= RK628F_VERSION && csi->rk628->enable_csi1) rk628_csi1_cru_reset(sd); rk628_post_process_setup(sd); @@ -1198,7 +1199,7 @@ static void rk628_csi_set_csi(struct v4l2_subdev *sd) rk628_i2c_write(csi->rk628, CSITX_CONFIG_DONE, CONFIG_DONE_IMD); v4l2_dbg(1, debug, sd, "%s csi config done\n", __func__); - if (csi->rk628->version >= RK628F_VERSION) { + if (csi->rk628->version >= RK628F_VERSION && csi->rk628->enable_csi1) { rk628_i2c_update_bits(csi->rk628, CSITX1_CSITX_EN, VOP_YU_SWAP_MASK | VOP_UV_SWAP_MASK | @@ -1649,7 +1650,7 @@ static void rk628_csi_enable_csi_interrupts(struct v4l2_subdev *sd, bool en) rk628_csi_clear_csi_interrupts(sd); //disabled csi state ints rk628_i2c_write(csi->rk628, CSITX_INTR_EN_IMD, 0x0fff0000); - if (csi->rk628->version >= RK628F_VERSION) + if (csi->rk628->version >= RK628F_VERSION && csi->rk628->enable_csi1) rk628_i2c_write(csi->rk628, CSITX1_INTR_EN_IMD, 0x0fff0000); //enable csi error ints @@ -1659,7 +1660,8 @@ static void rk628_csi_enable_csi_interrupts(struct v4l2_subdev *sd, bool en) GRF_INTR0_EN, CSI_INT_EN_MASK | CSI_INT_WRITE_EN_MASK, CSI_INT_EN(3) | CSI_INT_WRITE_EN(3)); rk628_i2c_write(csi->rk628, CSITX_ERR_INTR_EN_IMD, 0x0fff0fff); - rk628_i2c_write(csi->rk628, CSITX1_ERR_INTR_EN_IMD, 0x0fff0fff); + if (csi->rk628->enable_csi1) + rk628_i2c_write(csi->rk628, CSITX1_ERR_INTR_EN_IMD, 0x0fff0fff); } else { rk628_i2c_update_bits(csi->rk628, GRF_INTR0_EN, CSI_INT_EN_MASK | CSI_INT_WRITE_EN_MASK, @@ -1673,7 +1675,8 @@ static void rk628_csi_enable_csi_interrupts(struct v4l2_subdev *sd, bool en) GRF_INTR0_EN, CSI_INT_EN_MASK | CSI_INT_WRITE_EN_MASK, CSI_INT_EN(0) | CSI_INT_WRITE_EN(3)); rk628_i2c_write(csi->rk628, CSITX_ERR_INTR_EN_IMD, 0x0fff0000); - rk628_i2c_write(csi->rk628, CSITX1_ERR_INTR_EN_IMD, 0x0fff0000); + if (csi->rk628->enable_csi1) + rk628_i2c_write(csi->rk628, CSITX1_ERR_INTR_EN_IMD, 0x0fff0000); } else { rk628_i2c_update_bits(csi->rk628, GRF_INTR0_EN, CSI_INT_EN_MASK | CSI_INT_WRITE_EN_MASK, @@ -1719,7 +1722,7 @@ static void rk628_csi_clear_csi_interrupts(struct v4l2_subdev *sd) //clr int status rk628_i2c_write(csi->rk628, CSITX_ERR_INTR_CLR_IMD, 0xffffffff); - if (csi->rk628->version >= RK628F_VERSION) + if (csi->rk628->version >= RK628F_VERSION && csi->rk628->enable_csi1) rk628_i2c_write(csi->rk628, CSITX1_ERR_INTR_CLR_IMD, 0xffffffff); if (csi->rk628->version >= RK628F_VERSION) @@ -1751,11 +1754,11 @@ static void rk628_csi_error_process(struct v4l2_subdev *sd) rk628_hdmirx_vid_enable(sd, false); rk628_csi_enable_csi_interrupts(sd, false); rk628_i2c_update_bits(csi->rk628, CSITX_CSITX_EN, CSITX_EN_MASK, CSITX_EN(0)); - if (csi->rk628->version >= RK628F_VERSION) + if (csi->rk628->version >= RK628F_VERSION && csi->rk628->enable_csi1) rk628_i2c_update_bits(csi->rk628, CSITX1_CSITX_EN, CSITX_EN_MASK, CSITX_EN(0)); rk628_i2c_write(csi->rk628, CSITX_CONFIG_DONE, CONFIG_DONE_IMD); - if (csi->rk628->version >= RK628F_VERSION) + if (csi->rk628->version >= RK628F_VERSION && csi->rk628->enable_csi1) rk628_i2c_write(csi->rk628, CSITX1_CONFIG_DONE, CONFIG_DONE_IMD); usleep_range(5000, 5500); @@ -1768,7 +1771,7 @@ static void rk628_csi_error_process(struct v4l2_subdev *sd) rk628_i2c_update_bits(csi->rk628, CSITX_CSITX_EN, CSITX_EN_MASK, CSITX_EN(1)); rk628_i2c_write(csi->rk628, CSITX_CONFIG_DONE, CONFIG_DONE_IMD); - if (csi->rk628->version >= RK628F_VERSION) { + if (csi->rk628->version >= RK628F_VERSION && csi->rk628->enable_csi1) { rk628_i2c_update_bits(csi->rk628, CSITX1_CSITX_EN, CSITX_EN_MASK, CSITX_EN(1)); rk628_i2c_write(csi->rk628, CSITX1_CONFIG_DONE, CONFIG_DONE_IMD); @@ -1776,7 +1779,7 @@ static void rk628_csi_error_process(struct v4l2_subdev *sd) for (i = 0; i < 3; i++) { rk628_i2c_read(csi->rk628, CSITX_CSITX_EN, &val); - if (csi->rk628->version >= RK628F_VERSION) + if (csi->rk628->version >= RK628F_VERSION && csi->rk628->enable_csi1) rk628_i2c_read(csi->rk628, CSITX1_CSITX_EN, &val_csi1); v4l2_dbg(1, debug, sd, "%s, csi0_status: 0x%x, csi1_status: 0x%x, i=%d\n", __func__, val, val_csi1, i); @@ -1788,7 +1791,7 @@ static void rk628_csi_error_process(struct v4l2_subdev *sd) rk628_i2c_update_bits(csi->rk628, CSITX_CSITX_EN, CSITX_EN_MASK, CSITX_EN(1)); rk628_i2c_write(csi->rk628, CSITX_CONFIG_DONE, CONFIG_DONE_IMD); - if (csi->rk628->version >= RK628F_VERSION) { + if (csi->rk628->version >= RK628F_VERSION && csi->rk628->enable_csi1) { rk628_i2c_update_bits(csi->rk628, CSITX1_CSITX_EN, CSITX_EN_MASK, CSITX_EN(1)); rk628_i2c_write(csi->rk628, @@ -1943,7 +1946,7 @@ static int rk628_csi_isr(struct v4l2_subdev *sd, u32 status, bool *handled) v4l2_dbg(1, debug, sd, "%s: int0 status: 0x%x\n", __func__, int0_status); rk628_i2c_read(csi->rk628, CSITX_ERR_INTR_RAW_STATUS_IMD, &csi0_raw_ints); - if (csi->rk628->version >= RK628F_VERSION) + if (csi->rk628->version >= RK628F_VERSION && csi->rk628->enable_csi1) rk628_i2c_read(csi->rk628, CSITX1_ERR_INTR_RAW_STATUS_IMD, &csi1_raw_ints); rk628_csi_clear_csi_interrupts(sd); @@ -2552,7 +2555,8 @@ static void rk628_csi_reset_streaming(struct v4l2_subdev *sd, int on) CONT_MODE_CLK_CLR_MASK | CONT_MODE_CLK_SET_MASK | NON_CONTINUOUS_MODE_MASK, CONT_MODE_CLK_CLR(0) | CONT_MODE_CLK_SET(1) | NON_CONTINUOUS_MODE(0)); - if (csi->rk628->version >= RK628F_VERSION) + if (csi->rk628->version >= RK628F_VERSION && + csi->rk628->enable_csi1) rk628_i2c_update_bits(csi->rk628, CSITX1_SYS_CTRL3_IMD, CONT_MODE_CLK_CLR_MASK | CONT_MODE_CLK_SET_MASK | NON_CONTINUOUS_MODE_MASK, CONT_MODE_CLK_CLR(0) | @@ -2562,7 +2566,8 @@ static void rk628_csi_reset_streaming(struct v4l2_subdev *sd, int on) CONT_MODE_CLK_CLR_MASK | CONT_MODE_CLK_SET_MASK | NON_CONTINUOUS_MODE_MASK, CONT_MODE_CLK_CLR(0) | CONT_MODE_CLK_SET(0) | NON_CONTINUOUS_MODE(1)); - if (csi->rk628->version >= RK628F_VERSION) + if (csi->rk628->version >= RK628F_VERSION && + csi->rk628->enable_csi1) rk628_i2c_update_bits(csi->rk628, CSITX1_SYS_CTRL3_IMD, CONT_MODE_CLK_CLR_MASK | CONT_MODE_CLK_SET_MASK | NON_CONTINUOUS_MODE_MASK, CONT_MODE_CLK_CLR(0) | @@ -2572,7 +2577,7 @@ static void rk628_csi_reset_streaming(struct v4l2_subdev *sd, int on) rk628_i2c_update_bits(csi->rk628, CSITX_CSITX_EN, DPHY_EN_MASK | CSITX_EN_MASK, DPHY_EN(1) | CSITX_EN(1)); rk628_i2c_write(csi->rk628, CSITX_CONFIG_DONE, CONFIG_DONE_IMD); - if (csi->rk628->version >= RK628F_VERSION) { + if (csi->rk628->version >= RK628F_VERSION && csi->rk628->enable_csi1) { rk628_i2c_update_bits(csi->rk628, CSITX1_CSITX_EN, DPHY_EN_MASK | CSITX_EN_MASK, DPHY_EN(1) | CSITX_EN(1)); rk628_i2c_write(csi->rk628, CSITX1_CONFIG_DONE, CONFIG_DONE_IMD); @@ -2756,7 +2761,7 @@ static int mipi_dphy_power_on(struct rk628_csi *csi) csi->lane_mbps = rk628_csi_get_lane_rate_mbps(csi); bus_width = csi->lane_mbps << 8; bus_width |= COMBTXPHY_MODULEA_EN; - if (csi->rk628->version >= RK628F_VERSION) + if (csi->rk628->version >= RK628F_VERSION && csi->rk628->enable_csi1) bus_width |= COMBTXPHY_MODULEB_EN; v4l2_info(sd, "%s mipi bitrate:%llu mbps\n", __func__, csi->lane_mbps); @@ -2767,7 +2772,7 @@ static int mipi_dphy_power_on(struct rk628_csi *csi) rk628_txphy_set_mode(csi->rk628, PHY_MODE_VIDEO_MIPI); rk628_mipi_dphy_init_hsfreqrange(csi->rk628, csi->lane_mbps, 0); - if (csi->rk628->version >= RK628F_VERSION) + if (csi->rk628->version >= RK628F_VERSION && csi->rk628->enable_csi1) rk628_mipi_dphy_init_hsfreqrange(csi->rk628, csi->lane_mbps, 1); rk628_txphy_power_on(csi->rk628); @@ -2779,7 +2784,7 @@ static int mipi_dphy_power_on(struct rk628_csi *csi) 0, 1000); if (ret < 0) dev_err(csi->rk628->dev, "csi0 phy is not locked\n"); - if (csi->rk628->version >= RK628F_VERSION) { + if (csi->rk628->version >= RK628F_VERSION && csi->rk628->enable_csi1) { ret = regmap_read_poll_timeout(csi->rk628->regmap[RK628_DEV_CSI1], CSITX1_CSITX_STATUS1, val, val & DPHY_PLL_LOCK, @@ -2796,7 +2801,7 @@ static int mipi_dphy_power_on(struct rk628_csi *csi) if (ret < 0) dev_err(csi->rk628->dev, "csi0 lane module is not in stop state, val: 0x%x\n", val); - if (csi->rk628->version >= RK628F_VERSION) { + if (csi->rk628->version >= RK628F_VERSION && csi->rk628->enable_csi1) { ret = regmap_read_poll_timeout(csi->rk628->regmap[RK628_DEV_CSI1], CSITX1_CSITX_STATUS1, val, (val & mask) == mask, From 97faaa82e2c85d4fd7ee2e84f0a2566857abdc26 Mon Sep 17 00:00:00 2001 From: Jianwei Fan Date: Fri, 19 Sep 2025 09:47:45 +0800 Subject: [PATCH 16/40] iio: proximity: add nds03 tof sensor Change-Id: I263bc2a7cc302ded8c940a10f73e050abdefa1de Signed-off-by: Jianwei Fan --- drivers/iio/proximity/Kconfig | 2 + drivers/iio/proximity/Makefile | 1 + drivers/iio/proximity/nds03/Kconfig | 7 + drivers/iio/proximity/nds03/Makefile | 9 + drivers/iio/proximity/nds03/nds03.h | 104 +++ drivers/iio/proximity/nds03/nds03_calib.c | 275 +++++++ drivers/iio/proximity/nds03/nds03_calib.h | 42 + drivers/iio/proximity/nds03/nds03_comm.c | 385 +++++++++ drivers/iio/proximity/nds03/nds03_comm.h | 71 ++ drivers/iio/proximity/nds03/nds03_data.c | 238 ++++++ drivers/iio/proximity/nds03/nds03_data.h | 46 ++ drivers/iio/proximity/nds03/nds03_def.h | 308 ++++++++ drivers/iio/proximity/nds03/nds03_dev.c | 743 ++++++++++++++++++ drivers/iio/proximity/nds03/nds03_dev.h | 94 +++ drivers/iio/proximity/nds03/nds03_iio.c | 235 ++++++ drivers/iio/proximity/nds03/nds03_iio.h | 31 + drivers/iio/proximity/nds03/nds03_module.c | 674 ++++++++++++++++ .../iio/proximity/nds03/nds03_module_i2c.c | 99 +++ drivers/iio/proximity/nds03/nds03_platform.c | 117 +++ drivers/iio/proximity/nds03/nds03_platform.h | 137 ++++ drivers/iio/proximity/nds03/nds03_stdint.h | 95 +++ 21 files changed, 3713 insertions(+) create mode 100644 drivers/iio/proximity/nds03/Kconfig create mode 100644 drivers/iio/proximity/nds03/Makefile create mode 100644 drivers/iio/proximity/nds03/nds03.h create mode 100644 drivers/iio/proximity/nds03/nds03_calib.c create mode 100644 drivers/iio/proximity/nds03/nds03_calib.h create mode 100644 drivers/iio/proximity/nds03/nds03_comm.c create mode 100644 drivers/iio/proximity/nds03/nds03_comm.h create mode 100644 drivers/iio/proximity/nds03/nds03_data.c create mode 100644 drivers/iio/proximity/nds03/nds03_data.h create mode 100644 drivers/iio/proximity/nds03/nds03_def.h create mode 100644 drivers/iio/proximity/nds03/nds03_dev.c create mode 100644 drivers/iio/proximity/nds03/nds03_dev.h create mode 100644 drivers/iio/proximity/nds03/nds03_iio.c create mode 100644 drivers/iio/proximity/nds03/nds03_iio.h create mode 100644 drivers/iio/proximity/nds03/nds03_module.c create mode 100644 drivers/iio/proximity/nds03/nds03_module_i2c.c create mode 100644 drivers/iio/proximity/nds03/nds03_platform.c create mode 100644 drivers/iio/proximity/nds03/nds03_platform.h create mode 100644 drivers/iio/proximity/nds03/nds03_stdint.h diff --git a/drivers/iio/proximity/Kconfig b/drivers/iio/proximity/Kconfig index e5d8fbdcc254..f2fb15eeaf7e 100644 --- a/drivers/iio/proximity/Kconfig +++ b/drivers/iio/proximity/Kconfig @@ -32,6 +32,8 @@ config CROS_EC_MKBP_PROXIMITY To compile this driver as a module, choose M here: the module will be called cros_ec_mkbp_proximity. +source "drivers/iio/proximity/nds03/Kconfig" + config ISL29501 tristate "Intersil ISL29501 Time Of Flight sensor" depends on I2C diff --git a/drivers/iio/proximity/Makefile b/drivers/iio/proximity/Makefile index cc838bb5408a..ae0028d6729a 100644 --- a/drivers/iio/proximity/Makefile +++ b/drivers/iio/proximity/Makefile @@ -6,6 +6,7 @@ # When adding new entries keep the list in alphabetical order obj-$(CONFIG_AS3935) += as3935.o obj-$(CONFIG_CROS_EC_MKBP_PROXIMITY) += cros_ec_mkbp_proximity.o +obj-$(CONFIG_DTOF_NDS03) += nds03/ obj-$(CONFIG_ISL29501) += isl29501.o obj-$(CONFIG_LIDAR_LITE_V2) += pulsedlight-lidar-lite-v2.o obj-$(CONFIG_MB1232) += mb1232.o diff --git a/drivers/iio/proximity/nds03/Kconfig b/drivers/iio/proximity/nds03/Kconfig new file mode 100644 index 000000000000..da8d3c8c258c --- /dev/null +++ b/drivers/iio/proximity/nds03/Kconfig @@ -0,0 +1,7 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +config DTOF_NDS03 + tristate "NDS03 I2C DEVICE" + depends on I2C && SYSFS + help + Using I2C diff --git a/drivers/iio/proximity/nds03/Makefile b/drivers/iio/proximity/nds03/Makefile new file mode 100644 index 000000000000..5f23d3d56d41 --- /dev/null +++ b/drivers/iio/proximity/nds03/Makefile @@ -0,0 +1,9 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# +# Makefile for the nds03 drivers. +# + +obj-$(CONFIG_DTOF_NDS03) += nds03.o +nds03-y += nds03_module.o nds03_platform.o nds03_module_i2c.o nds03_iio.o \ + nds03_dev.o nds03_data.o \ + nds03_comm.o nds03_calib.o diff --git a/drivers/iio/proximity/nds03/nds03.h b/drivers/iio/proximity/nds03/nds03.h new file mode 100644 index 000000000000..ef789ed72047 --- /dev/null +++ b/drivers/iio/proximity/nds03/nds03.h @@ -0,0 +1,104 @@ +/*! + @file nds03.h + @brief + @author lull + @date 2025-06 + @copyright Copyright (c) 2025 Shenzhen Nephotonics Semiconductor Technology Co., Ltd. + @license BSD 3-Clause License + This file is part of the Nephotonics sensor SDK. + It is licensed under the BSD 3-Clause License. + A copy of the license can be found in the project root directory, in the file named LICENSE. + */ +#ifndef __NDS03_H +#define __NDS03_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* nds03 sdk */ +#include "nds03_comm.h" +#include "nds03_dev.h" +#include "nds03_data.h" +#include "nds03_calib.h" +#include "nds03_def.h" + +#define TOF_NDS03_DRV_NAME "tof_nds03" +#define DRIVER_VERSION "1.0.4" +#define TOF_NDS03_MAJOR 255 +#define MAX_POS_BITS 32 + +/*! use debug */ +extern int nds03_enable_debug; + +#define nds03_dbgmsg(str, ...) \ + do { \ + if (nds03_enable_debug > 0) \ + printk("%s: " str, __FUNCTION__, ##__VA_ARGS__); \ + } while (0) + + +#define nds03_info(str, ...) \ + pr_info("%s: " str , __FUNCTION__, ##__VA_ARGS__) + +#define nds03_errmsg(str, ...) \ + pr_err("%s: " str, __FUNCTION__, ##__VA_ARGS__) + +#define nds03_warnmsg(str, ...) \ + pr_warn("%s: " str,__FUNCTION__, ##__VA_ARGS__) + +struct nds03_context { + + /*!< multiple device id 0 based*/ + int id; + + /*!< misc device name */ + char name[64]; + + struct i2c_client * client; + + /*!< nds03 device info */ + NDS03_Dev_t g_nds03_device; + + /*!< main dev mutex/lock */ + struct mutex work_mutex; + + // /*!< work for pseudo irq polling check */ + struct delayed_work dwork; + struct work_struct irq_work; + // /*!< input device used for sending event */ + struct input_dev *idev; + + /*!< intr gpio number */ + int irq; + + bool remove_flag; + /// /* user control configuration parameter */ + /*!< measure mode irq or poll*/ + atomic_t meas_mode; + /*!< rescheduled time use in poll mode */ + atomic_t poll_delay_ms; + /*!< use ctrl measure state */ + atomic_t is_meas; + /*!< calibtion result of the deivce */ + int calib_result; + /*!< open input file descriptor count*/ + int fd_open_count; + struct iio_dev *indio_dev; + struct nds03_iio_dev *iio; +}; + +int nds03_common_probe(struct nds03_context * ctx); +int nds03_common_remove(struct nds03_context * ctx); +int nds03_interrupt_config(NDS03_Dev_t *pNxDevice, uint8_t is_open); +int nds03_sensor_init(struct nds03_context *ctx); + +#endif diff --git a/drivers/iio/proximity/nds03/nds03_calib.c b/drivers/iio/proximity/nds03/nds03_calib.c new file mode 100644 index 000000000000..ea47934653af --- /dev/null +++ b/drivers/iio/proximity/nds03/nds03_calib.c @@ -0,0 +1,275 @@ +/** + * @file nds03_calib.c + * @author tongsheng.tang + * @brief NDS03 Calibration functions + * @version 2.x.x + * @date 2025-06 + * + * @copyright Copyright (c) 2025, Nephotonics Information Technology (Hefei) Co., Ltd. + * + * @license BSD 3-Clause License + * This file is part of the NDS03 SDK and is licensed under the BSD 3-Clause License. + * You may obtain a copy of the license in the project root directory, + * in the file named LICENSE. + */ + +#include "nds03_comm.h" +#include "nds03_dev.h" +#include "nds03_data.h" +#include "nds03_calib.h" + +/** + * @brief NDS03 Get Offset Calib Depth MM + * 获取offset标定距离 + * @param pNxDevice + * @param calib_depth_mm + * @return NDS03_Error + */ +NDS03_Error NDS03_GetOffsetCalibDepthMM(NDS03_Dev_t *pNxDevice, uint16_t *calib_depth_mm) +{ + NDS03_Error ret = NDS03_ERROR_NONE; + + CHECK_RET(NDS03_ReadHalfWord(pNxDevice, NDS03_REG_OFFSET_MM, calib_depth_mm)); + + return ret; +} + +/** + * @brief NDS03 Set Offset Calib Depth MM + * 设置offset标定距离 + * @param pNxDevice + * @param calib_depth_mm + * @return NDS03_Error + */ +NDS03_Error NDS03_SetOffsetCalibDepthMM(NDS03_Dev_t *pNxDevice, uint16_t calib_depth_mm) +{ + NDS03_Error ret = NDS03_ERROR_NONE; + + if (calib_depth_mm == 0) + CHECK_RET(NDS03_ReadHalfWord(pNxDevice, NDS03_REG_OFFSET_MM, &calib_depth_mm)); + + CHECK_RET(NDS03_WriteByte(pNxDevice, NDS03_REG_CFG_ENA, NDS03_CMD_ENA_ENABLE)); + CHECK_RET(NDS03_WriteHalfWord(pNxDevice, NDS03_REG_OFFSET_MM, calib_depth_mm)); + CHECK_RET(NDS03_WriteByte(pNxDevice, NDS03_REG_CFG_ENA, NDS03_CMD_ENA_DISABLE)); + + return ret; +} + +/** + * @brief NDS03 Offset Calibration Check + * Offset 标定检查 + * @param pNxDevice + * @param calib_depth_mm + * @return NDS03_Error + */ +static NDS03_Error NDS03_OffsetCalibrationCheck(NDS03_Dev_t *pNxDevice) +{ + NDS03_Error ret = NDS03_ERROR_NONE; + uint16_t ref_histo_max, depth[2]; + uint8_t depth_flag; + + CHECK_RET(NDS03_GetSingleRangingData(pNxDevice)); + CHECK_RET(NDS03_ReadHalfWord(pNxDevice, NDS03_REG_REF_HISTO_MAX, &ref_histo_max)); + if (ret == NDS03_ERROR_NONE && ref_histo_max < NDS03_OFFSET_REF_MAX_COUNT_TH) { + ret = NDS03_ERROR_VCSEL_ERROR; + NX_PRINTF("ref_histo_max:%d\r\n", ref_histo_max); + return ret; + } + CHECK_RET(NDS03_ReadByte(pNxDevice, NDS03_REG_DEPTH_FLAG, &depth_flag)); + CHECK_RET(NDS03_WriteByte(pNxDevice, NDS03_REG_CFG_ENA, NDS03_CMD_ENA_ENABLE)); + CHECK_RET(NDS03_WriteByte(pNxDevice, NDS03_REG_DEPTH_FLAG, 1)); + CHECK_RET(NDS03_GetSingleRangingData(pNxDevice)); + depth[0] = pNxDevice->ranging_data[0].depth; + CHECK_RET(NDS03_WriteByte(pNxDevice, NDS03_REG_DEPTH_FLAG, 2)); + CHECK_RET(NDS03_GetSingleRangingData(pNxDevice)); + depth[1] = pNxDevice->ranging_data[0].depth; + CHECK_RET(NDS03_WriteByte(pNxDevice, NDS03_REG_DEPTH_FLAG, depth_flag)); + CHECK_RET(NDS03_WriteByte(pNxDevice, NDS03_REG_CFG_ENA, NDS03_CMD_ENA_DISABLE)); + if (ret == NDS03_ERROR_NONE && ((depth[0] + NDS03_OFFSET_DEPTH_ERROR_TH < depth[1]) || + (depth[0] > depth[1] + NDS03_OFFSET_DEPTH_ERROR_TH) || + depth[0] == NDS03_DEPTH_INVALID_VALUE || depth[1] == NDS03_DEPTH_INVALID_VALUE)) { + ret = NDS03_ERROR_OFFSET_ERROR; + NX_PRINTF("depth[0]:%d depth[1]:%d\r\n", depth[0], depth[1]); + } + return ret; +} + +/** + * @brief ToF Offset 标定 + * @details 不可以指定标定距离,使用默认距离,如果没有修改,那值默认是500mm + * + * @param pNxDevice 设备模组 + * @return int8_t + * @retval 0: 成功 + * @retval !0: Offset标定失败 + */ +NDS03_Error NDS03_OffsetCalibration(NDS03_Dev_t *pNxDevice) +{ + NDS03_Error ret = NDS03_ERROR_NONE; + uint16_t ambient_bg; + + NX_PRINTF("%s Start!\r\n", __func__); + CHECK_RET(NDS03_GetSingleRangingData(pNxDevice)); + CHECK_RET(NDS03_ReadHalfWord(pNxDevice, NDS03_REG_AMBIENT, &ambient_bg)); + if (ambient_bg > NDS03_AMBIENT_TH) { + ret = NDS03_ERROR_AMBIENT_HIGH; + NX_PRINTF("ambient_bg:%d\r\n", ambient_bg); + return ret; + } + // 打开使能 + CHECK_RET(NDS03_WriteByte(pNxDevice, NDS03_REG_CMD_ENA, NDS03_CMD_ENA_ENABLE)); + CHECK_RET(NDS03_WriteByte(pNxDevice, NDS03_REG_CMD_REQ, NDS03_CMD_OFFSET_CALIB)); + CHECK_RET(NDS03_WaitforCmdVal(pNxDevice, NDS03_CMD_OFFSET_CALIB, 10000)); + CHECK_RET(NDS03_WriteByte(pNxDevice, NDS03_REG_CMD_VAL, NDS03_CMD_ENA_DISABLE)); + CHECK_RET(NDS03_ReadByte(pNxDevice, NDS03_REG_CALIB_STATE, (uint8_t*)&ret)); + CHECK_RET(NDS03_OffsetCalibrationCheck(pNxDevice)); + + NX_PRINTF("%s End!\r\n", __func__); + + return ret; +} + +/** + * @brief ToF Offset 标定 + * @details 可以指定标定距离 + * + * @param pNxDevice 设备模组 + * @param calib_depth_mm 标定距离 + * @return int8_t + * @retval 0: 成功 + * @retval !0: Offset标定失败 + */ +NDS03_Error NDS03_OffsetCalibrationAtDepth(NDS03_Dev_t *pNxDevice, uint16_t calib_depth_mm) +{ + NDS03_Error ret = NDS03_ERROR_NONE; + uint16_t ambient_bg; + + NX_PRINTF("%s Start!\r\n", __func__); + + CHECK_RET(NDS03_GetSingleRangingData(pNxDevice)); + CHECK_RET(NDS03_ReadHalfWord(pNxDevice, NDS03_REG_AMBIENT, &ambient_bg)); + if (ambient_bg > NDS03_AMBIENT_TH){ + ret = NDS03_ERROR_AMBIENT_HIGH; + NX_PRINTF("ambient:%d \r\n", ambient_bg); + return ret; + } + CHECK_RET(NDS03_SetOffsetCalibDepthMM(pNxDevice, calib_depth_mm)); + // 打开使能 + CHECK_RET(NDS03_WriteByte(pNxDevice, NDS03_REG_CMD_ENA, NDS03_CMD_ENA_ENABLE)); + CHECK_RET(NDS03_WriteByte(pNxDevice, NDS03_REG_CMD_REQ, NDS03_CMD_OFFSET_CALIB)); + CHECK_RET(NDS03_WaitforCmdVal(pNxDevice, NDS03_CMD_OFFSET_CALIB, 10000)); + CHECK_RET(NDS03_WriteByte(pNxDevice, NDS03_REG_CMD_VAL, NDS03_CMD_ENA_DISABLE)); + CHECK_RET(NDS03_ReadByte(pNxDevice, NDS03_REG_CALIB_STATE, (uint8_t*)&ret)); + CHECK_RET(NDS03_OffsetCalibrationCheck(pNxDevice)); + + NX_PRINTF("%s End!\r\n", __func__); + + return ret; +} + +/** + * @brief NDS03 Read Xtalk Data + * 读取NDS03串扰数据 + * @param pNxDevice 模组设备 + * @param rbuf 数据指针 + * @param size 数据大小 + * @return NDS03_Error + */ +static NDS03_Error NDS03_ReadXtalkData(NDS03_Dev_t *pNxDevice) +{ + NDS03_Error ret = NDS03_ERROR_NONE; + uint32_t rsize, _size; + uint8_t one_size; + uint16_t addr; + uint16_t rbuf[240]; + uint8_t *rbuf_ptr = (uint8_t *)rbuf; + uint32_t size = 240 * 2; + + CHECK_RET(NDS03_ReadByte(pNxDevice, NDS03_REG_CACHE_SIZE, &one_size)); + CHECK_RET(NDS03_ReadHalfWord(pNxDevice, 0xEC, &addr)); + _size = (uint32_t)one_size; + rsize = 0; + while ((rsize < size) && (ret == NDS03_ERROR_NONE)) { + CHECK_RET(NDS03_WriteHalfWord(pNxDevice, NDS03_REG_CACHE_ADDR, addr)); + CHECK_RET(NDS03_WriteByte(pNxDevice, NDS03_REG_CMD_ENA, 0x05)); + CHECK_RET(NDS03_WriteByte(pNxDevice, NDS03_REG_DAT_REQ, 0xC0)); + CHECK_RET(NDS03_WaitforDataVal(pNxDevice, 0xC0, 200)); + CHECK_RET(NDS03_ReadNBytes(pNxDevice, NDS03_REG_CACHE_DATA, rbuf_ptr, + ((size-rsize)>_size) ? _size:(size-rsize))); + CHECK_RET(NDS03_WriteByte(pNxDevice, NDS03_REG_DAT_VAL, NDS03_DATA_VAL_IDLE)); + rbuf_ptr += _size; + addr += _size; + rsize += _size; + } + for (int i = 80; i < 240; i++) { + if (rbuf[i] > 10000) + return -14; + } + + return ret; +} + +/** + * @brief NDS03 Xtalk Calibration + * NDS03串扰/盖板标定 + * @param pNxDevice 设备模组 + * @return int8_t + * @retval 0: 成功 + * @retval !0: xtalk标定失败 + */ +NDS03_Error NDS03_XtalkCalibration(NDS03_Dev_t *pNxDevice) +{ + NDS03_Error ret = NDS03_ERROR_NONE, calib_state = NDS03_ERROR_NONE; + uint16_t ambient_bg,ref_histo_max; + uint8_t cnt = 2; + int8_t check_xtalk_state = 0; + + NX_PRINTF("%s Start!\r\n", __func__); + do { + CHECK_RET(NDS03_GetSingleRangingData(pNxDevice)); + CHECK_RET(NDS03_ReadHalfWord(pNxDevice, NDS03_REG_AMBIENT, &ambient_bg)); + CHECK_RET(NDS03_ReadHalfWord(pNxDevice, NDS03_REG_REF_HISTO_MAX, &ref_histo_max)); + if (ambient_bg > NDS03_AMBIENT_TH) { + ret = NDS03_ERROR_AMBIENT_HIGH; + NX_PRINTF("ambient:%d\r\n", ambient_bg); + return ret; + } + if (ret == NDS03_ERROR_NONE && ref_histo_max < NDS03_OFFSET_REF_MAX_COUNT_TH) { + ret = NDS03_ERROR_VCSEL_ERROR; + NX_PRINTF("ref_histo_max:%d\r\n", ref_histo_max); + return ret; + } + // 打开使能 + CHECK_RET(NDS03_WriteByte(pNxDevice, NDS03_REG_CMD_ENA, NDS03_CMD_ENA_ENABLE)); + CHECK_RET(NDS03_WriteByte(pNxDevice, NDS03_REG_CMD_REQ, NDS03_CMD_XTALK_CALIB)); + CHECK_RET(NDS03_WaitforCmdVal(pNxDevice, NDS03_CMD_XTALK_CALIB, 5000)); + CHECK_RET(NDS03_WriteByte(pNxDevice, NDS03_REG_CMD_VAL, NDS03_CMD_ENA_DISABLE)); + CHECK_RET(NDS03_GetFirmwareVersion(pNxDevice)); + if (pNxDevice->chip_info.fw_version == 0x10203) { + CHECK_RET(NDS03_GetSingleRangingData(pNxDevice)); + check_xtalk_state = NDS03_ReadXtalkData(pNxDevice); + } + + } while (cnt-- && check_xtalk_state != 0); + CHECK_RET(NDS03_ReadByte(pNxDevice, NDS03_REG_CALIB_STATE, (uint8_t*)&calib_state)); + ret = check_xtalk_state ? check_xtalk_state : (ret | calib_state) & + (NDS03_CALIB_ERROR_XTALK_OVERFLOW | NDS03_CALIB_ERROR_XTALK_EXCESSIVE); + NX_PRINTF("%s End!\r\n", __func__); + + return ret; +} + +/** + * @brief NDS03 Get Xtalk Value + * 获取标定串扰值 + * @param pNxDevice + * @return NDS03_Error + */ +NDS03_Error NDS03_GetXTalkValue(NDS03_Dev_t *pNxDevice, uint16_t* xtalk_value) +{ + NDS03_Error ret = NDS03_ERROR_NONE; + + CHECK_RET(NDS03_ReadHalfWord(pNxDevice, NDS03_REG_XTALK, xtalk_value)); + + return ret; +} diff --git a/drivers/iio/proximity/nds03/nds03_calib.h b/drivers/iio/proximity/nds03/nds03_calib.h new file mode 100644 index 000000000000..453047f36124 --- /dev/null +++ b/drivers/iio/proximity/nds03/nds03_calib.h @@ -0,0 +1,42 @@ +/** + * @file nds03_calib.h + * @author tongsheng.tang + * @brief NDS03 Calibration functions + * @version 2.x.x + * @date 2025-06 + * + * @copyright Copyright (c) 2025, Nephotonics Information Technology (Hefei) Co., Ltd. + * + * @license BSD 3-Clause License + * This file is part of the NDS03 SDK and is licensed under the BSD 3-Clause License. + * You may obtain a copy of the license in the project root directory, in the file named LICENSE. + * + */ + +#ifndef __NDS03_CALIB_H__ +#define __NDS03_CALIB_H__ + +#include "nds03_def.h" + +/** @defgroup NDS03_Calibration_Group NDS03 Calibration Functions + * @brief NDS03 Calibration Functions + * @{ + */ + +/** 获取offset标定距离 */ +NDS03_Error NDS03_GetOffsetCalibDepthMM(NDS03_Dev_t *pNxDevice, uint16_t *calib_depth_mm); +/** 设置offset标定距离 */ +NDS03_Error NDS03_SetOffsetCalibDepthMM(NDS03_Dev_t *pNxDevice, uint16_t calib_depth_mm); +/** Offset标定函数(无标定距离设置) */ +NDS03_Error NDS03_OffsetCalibration(NDS03_Dev_t *pNxDevice); +/** Offset标定函数(有标定距离设置) */ +NDS03_Error NDS03_OffsetCalibrationAtDepth(NDS03_Dev_t *pNxDevice, uint16_t calib_depth_mm); +/** XTalk标定 */ +NDS03_Error NDS03_XtalkCalibration(NDS03_Dev_t *pNxDevice); +/** 获取标定串扰值 */ +NDS03_Error NDS03_GetXTalkValue(NDS03_Dev_t *pNxDevice, uint16_t* xtalk_value); + +/** @} NDS03_Calibration_Group */ + +#endif + diff --git a/drivers/iio/proximity/nds03/nds03_comm.c b/drivers/iio/proximity/nds03/nds03_comm.c new file mode 100644 index 000000000000..1b94a4d77c19 --- /dev/null +++ b/drivers/iio/proximity/nds03/nds03_comm.c @@ -0,0 +1,385 @@ +/** + * @file nds03_comm.c + * @author tongsheng.tang + * @brief NDS03 communication functions + * @version 2.x.x + * @date 2025-06 + * + * @copyright Copyright (c) 2025, Nephotonics Information Technology (Hefei) Co., Ltd. + * + * @license BSD 3-Clause License + * This file is part of the NDS03 SDK and is licensed under the BSD 3-Clause License. + * You may obtain a copy of the license in the project root directory, + * in the file named LICENSE. + */ + +#include "nds03_stdint.h" +#if NDS03_PLATFORM != PLATFORM_LINUX_DRIVER +#include +#include +#else +#include +#endif +#include "nds03_dev.h" +#include "nds03_comm.h" +#include "nds03_def.h" +#include "nds03_platform.h" + +/** + * @brief NDS03 Delay 1ms + * @param ms 延时时间 + * @return void + */ +NDS03_Error NDS03_Delay1ms(NDS03_Dev_t *pNxDevice, uint32_t ms) +{ + return nds03_delay_1ms(&pNxDevice->platform, ms); +} + +/** + * @brief NDS03 Delay 10us + * @param us 延时时间 + * @return void + */ +NDS03_Error NDS03_Delay10us(NDS03_Dev_t *pNxDevice, uint32_t us) +{ + return nds03_delay_10us(&pNxDevice->platform, us); +} + +/** + * @brief NDS03 Get System Clk Ms +* @param pNxDevice 模组设备 + * @param time_ms 获取时间(ms) + * @return void + */ +NDS03_Error NDS03_GetSystemClkMs(NDS03_Dev_t *pNxDevice,int32_t *time_ms) +{ + NDS03_Error ret = NDS03_ERROR_NONE; + + ret = nds03_get_system_clk_ms(&pNxDevice->platform, time_ms); + + return ret; +} + +/** + * @brief NDS03 Set XShut Pin Level + * 设置xshut引脚的电平 + * @param pNxDevice 模组设备 + * @param level xshut引脚电平,0为低电平,1为高电平 + * @return void + */ +NDS03_Error NDS03_SetXShutPinLevel(NDS03_Dev_t *pNxDevice, int8_t level) +{ + return nds03_set_xshut_pin_level(&pNxDevice->platform, level); +} + +/** + * @brief 获取当前i2c时钟频率 + * + * @param pNxDevice 模组设备 + * @param freq 获取的频率 + * @return + */ +NDS03_Error NDS03_GetI2cFreq(NDS03_Dev_t *pNxDevice, uint32_t *freq) +{ + return nds03_i2c_get_clock_frequency(&pNxDevice->platform, freq); +} + +/** + * @brief 设置当前i2c时钟频率 + * + * @param pNxDevice 模组设备 + * @param freq 设置的频率 + * @return + */ +NDS03_Error NDS03_SetI2cFreq(NDS03_Dev_t *pNxDevice, uint32_t freq) +{ + return nds03_i2c_set_clock_frequency(&pNxDevice->platform, freq); +} + +/** + * @brief 半字,即2个字节,调换数据格式 + * 小端无影响,大端会调换数据格式 + * @param buf 数据缓冲区 + * @param buf_num 数据个数 + */ +static void NDS03_HalfWordDataFmtChange(uint16_t *buf, uint16_t buf_num) +{ + uint16_t tmp; + uint8_t *pu8buf = (uint8_t*)buf; + uint16_t i; + + for (i = 0; i < buf_num; i++) { + tmp = buf[i]; + *pu8buf++ = (tmp >> 0); + *pu8buf++ = (tmp >> 8); + } +} + +/** + * @brief 1字,即4个字节,调换数据格式 + * 小端无影响,大端会调换数据格式 + * @param buf 数据缓冲区 + * @param buf_num 数据个数 + */ +static void NDS03_WordDataFmtChange(uint32_t *buf, uint16_t buf_num) +{ + uint32_t tmp; + uint8_t *pu8buf = (uint8_t*)buf; + uint16_t i; + + for (i = 0; i < buf_num; i++) { + tmp = buf[i]; + *pu8buf++ = (tmp >> 0); + *pu8buf++ = (tmp >> 8); + *pu8buf++ = (tmp >> 16); + *pu8buf++ = (tmp >> 24); + } +} + +/** + * @brief Write n Words to NDS03 + * 对NDS03的寄存器写N个字 + * @param pNxDevice: NDS03模组设备信息结构体指针 + * @param addr: 寄存器地址 + * @param wdata: 存放寄存器值的指针 + * @param len: 写数据的长度,按字个数计算 + * @return NDS03_Error +*/ +NDS03_Error NDS03_WriteNBytes(NDS03_Dev_t *pNxDevice, uint8_t addr, void *wdata, uint16_t size) +{ + NDS03_Error ret = NDS03_ERROR_NONE; + + ret = nds03_i2c_write_nbytes(&pNxDevice->platform, addr, (uint8_t*)wdata, size); + + return ret; +} + +/** + * @brief Read n Words from NDS03 + * 对NDS03的寄存器读N个字 + * @param pNxDevice: NDS03模组设备信息结构体指针 + * @param addr: 寄存器地址 + * @param rdata: 存放寄存器值的指针 + * @param len: 读数据的长度,按字个数计算 + * @return NDS03_Error +*/ +NDS03_Error NDS03_ReadNBytes(NDS03_Dev_t *pNxDevice, uint8_t addr, void *rdata, uint16_t size) +{ + NDS03_Error ret = NDS03_ERROR_NONE; + + ret = nds03_i2c_read_nbytes(&pNxDevice->platform, addr, (uint8_t*)rdata, size); + + return ret; +} + +/** + * @brief Write 1 Byte to NDS03 + * 对NDS03的寄存器写1个字节 + * @param pNxDevice: NDS03模组设备信息结构体指针 + * @param addr: 寄存器地址 + * @param wdata: 寄存器的值 + * @return NDS03_Error +*/ +NDS03_Error NDS03_WriteByte(NDS03_Dev_t *pNxDevice, uint8_t addr, uint8_t wdata) +{ + NDS03_Error ret = NDS03_ERROR_NONE; + + ret = nds03_i2c_write_nbytes(&pNxDevice->platform, addr, &wdata, 1); + + return ret; +} + +/** + * @brief Read 1 Byte from NDS03 + * 对NDS03的寄存器读1个字节 + * @param pNxDevice: NDS03模组设备信息结构体指针 + * @param addr: 寄存器地址 + * @param rdata: 寄存器的值 + * @return NDS03_Error +*/ +NDS03_Error NDS03_ReadByte(NDS03_Dev_t *pNxDevice, uint8_t addr, uint8_t *rdata) +{ + NDS03_Error ret = NDS03_ERROR_NONE; + + ret = nds03_i2c_read_nbytes(&pNxDevice->platform, addr, rdata, 1); + + return ret; +} + +/** + * @brief Write N bytes By Half-Word to NDS03 + * 对NDS03的寄存器写N个字节,使用半字写的方式 + * @param pNxDevice: NDS03模组设备信息结构体指针 + * @param addr: 寄存器地址 + * @param wdata: 寄存器的值 + * @param size: 写数据的长度,按字节个数计算 + * 注意:size必须是2的倍数 + * @return NDS03_Error +*/ +NDS03_Error NDS03_WriteNBytesByHalfWord(NDS03_Dev_t *pNxDevice, + uint8_t addr, uint16_t *wdata, uint16_t size) +{ + NDS03_Error ret = NDS03_ERROR_NONE; + + if ((size & 0x01) == 0) { + NDS03_HalfWordDataFmtChange(wdata, size / 2); + ret = nds03_i2c_write_nbytes(&pNxDevice->platform, addr, (uint8_t*)wdata, size); + NDS03_HalfWordDataFmtChange(wdata, size / 2); + } + + return ret; +} + +/** + * @brief Read N Bytes By Half-World from NDS03 + * 对NDS03的寄存器读N个字节,使用半字读的方式 + * @param pNxDevice: NDS03模组设备信息结构体指针 + * @param addr: 寄存器地址 + * @param rdata: 寄存器的值 + * @param size: 读数据的长度,按字节个数计算 + * 注意:size必须是2的倍数 + * @return NDS03_Error +*/ +NDS03_Error NDS03_ReadNBytesByHalfWord(NDS03_Dev_t *pNxDevice, uint8_t addr, uint16_t *rdata, uint16_t size) +{ + NDS03_Error ret = NDS03_ERROR_NONE; + + if ((size & 0x01) == 0 && rdata != NULL) { + ret = nds03_i2c_read_nbytes(&pNxDevice->platform, addr, (uint8_t*)rdata, size); + NDS03_HalfWordDataFmtChange(rdata, size / 2); + } + + return ret; +} + +/** + * @brief Write 2 Byte to NDS03 + * 对NDS03的寄存器写2个字节 + * @param pNxDevice: NDS03模组设备信息结构体指针 + * @param addr: 寄存器地址 + * @param wdata: 寄存器的值 + * @return NDS03_Error +*/ +NDS03_Error NDS03_WriteHalfWord(NDS03_Dev_t *pNxDevice, uint8_t addr, uint16_t wdata) +{ + NDS03_Error ret = NDS03_ERROR_NONE; + uint8_t tmp[2]; + + tmp[0] = (wdata >> 0) & 0xFF; + tmp[1] = (wdata >> 8) & 0xFF; + ret = nds03_i2c_write_nbytes(&pNxDevice->platform, addr, tmp, sizeof(tmp)); + + return ret; +} + +/** + * @brief Read 2 Byte from NDS03 + * 对NDS03的寄存器读2个字节 + * @param pNxDevice: NDS03模组设备信息结构体指针 + * @param addr: 寄存器地址 + * @param rdata: 寄存器的值 + * @return NDS03_Error +*/ +NDS03_Error NDS03_ReadHalfWord(NDS03_Dev_t *pNxDevice, uint8_t addr, uint16_t *rdata) +{ + NDS03_Error ret = NDS03_ERROR_NONE; + uint8_t tmp[2]; + + if (rdata != NULL) { + ret = nds03_i2c_read_nbytes(&pNxDevice->platform, addr, tmp, sizeof(tmp)); + *rdata = (uint16_t)tmp[0] | ((uint16_t)tmp[1] << 8); + } + + return ret; +} + +/** + * @brief Write N Bytes By Word to NDS03 + * 对NDS03的寄存器写N个字节,使用字方式 + * @param pNxDevice: NDS03模组设备信息结构体指针 + * @param addr: 寄存器地址 + * @param wdata: 寄存器的值 + * @param size: 写数据的长度,按字节个数计算 + * 注意:size必须是4的倍数 + * @return NDS03_Error +*/ +NDS03_Error NDS03_WriteNBytesByWord(NDS03_Dev_t *pNxDevice, uint8_t addr, + uint32_t *wdata, uint16_t size) +{ + NDS03_Error ret = NDS03_ERROR_NONE; + + if ((size & 0x03) == 0) { + NDS03_WordDataFmtChange(wdata, size / 4); + ret = nds03_i2c_write_nbytes(&pNxDevice->platform, addr, (uint8_t*)wdata, size); + NDS03_WordDataFmtChange(wdata, size / 4); + } + + return ret; +} + +/** + * @brief Read N Bytes By Word from NDS03 + * 对NDS03的寄存器读N个字节,使用字方式 + * @param pNxDevice: NDS03模组设备信息结构体指针 + * @param addr: 寄存器地址 + * @param rdata: 寄存器的值 + * @param size: 读数据的长度,按字节个数计算 + * 注意:size必须是4的倍数 + * @return NDS03_Error +*/ +NDS03_Error NDS03_ReadNBytesByWord(NDS03_Dev_t *pNxDevice, uint8_t addr, uint32_t *rdata, uint16_t size) +{ + NDS03_Error ret = NDS03_ERROR_NONE; + + if ((size & 0x03) == 0 && rdata != NULL) { + ret = nds03_i2c_read_nbytes(&pNxDevice->platform, addr, (uint8_t*)rdata, size); + NDS03_WordDataFmtChange(rdata, size / 4); + } + + return ret; +} + +/** + * @brief Write 4 Byte to NDS03 + * 对NDS03的寄存器写2个字节 + * @param pNxDevice: NDS03模组设备信息结构体指针 + * @param addr: 寄存器地址 + * @param wdata: 寄存器的值 + * @return NDS03_Error +*/ +NDS03_Error NDS03_WriteWord(NDS03_Dev_t *pNxDevice, uint8_t addr, uint32_t wdata) +{ + NDS03_Error ret = NDS03_ERROR_NONE; + uint8_t tmp[4]; + + tmp[0] = (wdata >> 0) & 0xFF; + tmp[1] = (wdata >> 8) & 0xFF; + tmp[2] = (wdata >> 16) & 0xFF; + tmp[3] = (wdata >> 24) & 0xFF; + ret = nds03_i2c_write_nbytes(&pNxDevice->platform, addr, tmp, sizeof(tmp)); + + return ret; +} + +/** + * @brief Read 4 Byte from NDS03 + * 对NDS03的寄存器读2个字节 + * @param pNxDevice: NDS03模组设备信息结构体指针 + * @param addr: 寄存器地址 + * @param rdata: 寄存器的值 + * @return NDS03_Error +*/ +NDS03_Error NDS03_ReadWord(NDS03_Dev_t *pNxDevice, uint8_t addr, uint32_t *rdata) +{ + NDS03_Error ret = NDS03_ERROR_NONE; + uint8_t tmp[4]; + + if (rdata != NULL) { + ret = nds03_i2c_read_nbytes(&pNxDevice->platform, addr, tmp, sizeof(tmp)); + *rdata = (uint32_t)tmp[0] | ((uint32_t)tmp[1] << 8) | + ((uint32_t)tmp[2] << 16) | ((uint32_t)tmp[3] << 24); + } + + return ret; +} + diff --git a/drivers/iio/proximity/nds03/nds03_comm.h b/drivers/iio/proximity/nds03/nds03_comm.h new file mode 100644 index 000000000000..43630b61e436 --- /dev/null +++ b/drivers/iio/proximity/nds03/nds03_comm.h @@ -0,0 +1,71 @@ +/** + * @file nds03_comm.h + * @author tongsheng.tang + * @brief NDS03 communication functions + * @version 2.x.x + * @date 2025-06 + * + * @copyright Copyright (c) 2025, Nephotonics Information Technology (Hefei) Co., Ltd. + * + * @license BSD 3-Clause License + * This file is part of the NDS03 SDK and is licensed under the BSD 3-Clause License. + * You may obtain a copy of the license in the project root directory, + * in the file named LICENSE. + */ +#ifndef __NDS03_COMM_H__ +#define __NDS03_COMM_H__ + +#include "nds03_def.h" + +/** @defgroup NDS03_Communication_Group NDS03 Communication Functions + * @brief NDS03 Communication Functions + * @{ + */ + +/** 延时时间(ms) */ +NDS03_Error NDS03_Delay1ms(NDS03_Dev_t *pNxDevice, uint32_t ms); + +/** 延时时间(10us) */ +NDS03_Error NDS03_Delay10us(NDS03_Dev_t *pNxDevice, uint32_t us); + +/** 设置xshut引脚的电平 */ +NDS03_Error NDS03_SetXShutPinLevel(NDS03_Dev_t *pNxDevice, int8_t level); + +/** NDS03设置i2c频率 */ +NDS03_Error NDS03_SetI2cFreq(NDS03_Dev_t *pNxDevice, uint32_t freq); +/** NDS03获取i2c频率 */ +NDS03_Error NDS03_GetI2cFreq(NDS03_Dev_t *pNxDevice, uint32_t *freq); +/** 对NDS03寄存器写N个字节 */ +NDS03_Error NDS03_WriteNBytes(NDS03_Dev_t *pNxDevice, uint8_t addr, void *wdata, uint16_t size); +/** 对NDS03寄存器读N个字节 */ +NDS03_Error NDS03_ReadNBytes(NDS03_Dev_t *pNxDevice, uint8_t addr, void *rdata, uint16_t size); +/** 对NDS03寄存器写1个字节 */ +NDS03_Error NDS03_WriteByte(NDS03_Dev_t *pNxDevice, uint8_t addr, uint8_t wdata); +/** 对NDS03寄存器写1个字节 */ +NDS03_Error NDS03_ReadByte(NDS03_Dev_t *pNxDevice, uint8_t addr, uint8_t *rdata); +/** 对NDS03寄存器写N个字节,使用半字方式 */ +NDS03_Error NDS03_WriteNBytesByHalfWord(NDS03_Dev_t *pNxDevice, + uint8_t addr, uint16_t *wdata, uint16_t size); +/** 对NDS03寄存器读N个字节,使用半字方式 */ +NDS03_Error NDS03_ReadNBytesByHalfWord(NDS03_Dev_t *pNxDevice, + uint8_t addr, uint16_t *rdata, uint16_t size); +/** 对NDS03寄存器写1个字 */ +NDS03_Error NDS03_WriteHalfWord(NDS03_Dev_t *pNxDevice, uint8_t addr, uint16_t wdata); +/** 对NDS03寄存器读1个字 */ +NDS03_Error NDS03_ReadHalfWord(NDS03_Dev_t *pNxDevice, uint8_t addr, uint16_t *rdata); +/** 对NDS03寄存器写N个字节,使用字方式 */ +NDS03_Error NDS03_WriteNBytesByWord(NDS03_Dev_t *pNxDevice, + uint8_t addr, uint32_t *wdata, uint16_t size); +/** 对NDS03寄存器读N个字节,使用字方式 */ +NDS03_Error NDS03_ReadNBytesByWord(NDS03_Dev_t *pNxDevice, + uint8_t addr, uint32_t *rdata, uint16_t size); +/** 对NDS03寄存器写1个字 */ +NDS03_Error NDS03_WriteWord(NDS03_Dev_t *pNxDevice, uint8_t addr, uint32_t wdata); +/** 对NDS03寄存器读1个字 */ +NDS03_Error NDS03_ReadWord(NDS03_Dev_t *pNxDevice, uint8_t addr, uint32_t *rdata); +/** 获取系统时钟时间(ms) */ +NDS03_Error NDS03_GetSystemClkMs(NDS03_Dev_t *pNxDevice,int32_t *time_ms); + +/** @} NDS03_Communication_Group */ + +#endif diff --git a/drivers/iio/proximity/nds03/nds03_data.c b/drivers/iio/proximity/nds03/nds03_data.c new file mode 100644 index 000000000000..dbc2f1824d3c --- /dev/null +++ b/drivers/iio/proximity/nds03/nds03_data.c @@ -0,0 +1,238 @@ + +/** + * @file nds03_data.c + * @author tongsheng.tang + * @brief NDS03 get depth data functions + * @version 2.x.x + * @date 2025-06 + * + * @copyright Copyright (c) 2025, Nephotonics Information Technology (Hefei) Co., Ltd. + * + * @license BSD 3-Clause License + * This file is part of the NDS03 SDK and is licensed under the BSD 3-Clause License. + * You may obtain a copy of the license in the project root directory, + * in the file named LICENSE. + */ + +#include "nds03_def.h" +#include "nds03_comm.h" +#include "nds03_dev.h" +#include "nds03_data.h" + +/** + * @brief NDS03 Get Ranging Data Ready + * 检测NDS03测距是否完成 + * @param pNxDevice 模组设备 + * @return int8_t + * @retval 函数执行结果 + * - 0:未完成 + * 1: 完成 + * - ::NDS03_ERROR_I2C:IIC通讯错误/数据异常 + */ +NDS03_Error NDS03_GetRangingDataReady(NDS03_Dev_t *pNxDevice) +{ + NDS03_Error ret = NDS03_ERROR_NONE; + uint8_t buf_valid_flag = 0x00; + + CHECK_RET(NDS03_ReadByte(pNxDevice, NDS03_REG_DAT_VAL, &buf_valid_flag)); + + if (buf_valid_flag == NDS03_DEPTH_DATA_FLAG) + return 1; + + return ret; +} + +/** + * @brief NDS03 Start Single Measurement + * 发送开始单次测量信号 + * @param pNxDevice 模组设备 + * @return int8_t + */ +NDS03_Error NDS03_StartSingleMeasurement(NDS03_Dev_t *pNxDevice) +{ + NDS03_Error ret = NDS03_ERROR_NONE; + + /* 清除标志位 */ + CHECK_RET(NDS03_WriteByte(pNxDevice, NDS03_REG_DAT_VAL, NDS03_DATA_VAL_IDLE)); + /* 发送触发信号 */ + CHECK_RET(NDS03_WriteByte(pNxDevice, NDS03_REG_DAT_REQ, NDS03_DEPTH_DATA_FLAG)); + + return ret; +} + +/** + * @brief NDS03 Start Continuous Measurement + * 发送开始连续测量信号 + * @param pNxDevice 模组设备 + * @return int8_t + */ +NDS03_Error NDS03_StartContinuousMeasurement(NDS03_Dev_t *pNxDevice) +{ + NDS03_Error ret = NDS03_ERROR_NONE; + + if (pNxDevice->config.continuous_flag == 0) { + /* 清除标志位 */ + CHECK_RET(NDS03_WriteByte(pNxDevice, NDS03_REG_DAT_VAL, NDS03_DATA_VAL_IDLE)); + /* 发送触发信号 */ + CHECK_RET(NDS03_WriteByte(pNxDevice, + NDS03_REG_DAT_REQ, NDS03_DEPTH_CONTINUOUS_FLAG)); + pNxDevice->config.continuous_flag = 1; + } + + return ret; +} + +/** + * @brief NDS03 Stop Continuous Measurement + * 发送结束连续测量信号,用于连续模式 + * @param pNxDevice 模组设备 + * @return int8_t + */ +NDS03_Error NDS03_StopContinuousMeasurement(NDS03_Dev_t *pNxDevice) +{ + NDS03_Error ret = NDS03_ERROR_NONE; + + if (pNxDevice->config.continuous_flag != 0) { + /* 清除标志位 */ + CHECK_RET(NDS03_WriteByte(pNxDevice, NDS03_REG_DAT_REQ, NDS03_DATA_REQ_IDLE)); + /* 等待测量完成 */ + CHECK_RET(NDS03_WaitforDataVal(pNxDevice, NDS03_DEPTH_CONTINUOUS_FLAG, 200)); + /* 清除标志位 */ + CHECK_RET(NDS03_WriteByte(pNxDevice, NDS03_REG_DAT_VAL, NDS03_DATA_VAL_IDLE)); + pNxDevice->config.continuous_flag = 0; + } + + return ret; +} + +/** + * @brief NDS03 Clear Data Valid Flag + * 清除NDS03测量数据的有效位,取完一次数 + * 据做的操作,通知NDS03数据已读取 + * @param pNxDevice 模组设备 + * @return NDS03_Error + */ +NDS03_Error NDS03_ClearDataValidFlag(NDS03_Dev_t *pNxDevice) +{ + NDS03_Error ret = NDS03_ERROR_NONE; + + CHECK_RET(NDS03_WriteByte(pNxDevice, NDS03_REG_DAT_VAL, NDS03_DATA_VAL_IDLE)); + + return ret; +} + +/** + * @brief NDS03 Read Ranging Data + * 读取NDS03寄存器获取测量数据,数据更新于一次测距完成后 + * @param pNxDevice 模组设备 + * @return int32_t + */ +NDS03_Error NDS03_ReadRangingData(NDS03_Dev_t *pNxDevice) +{ + NDS03_Error ret = NDS03_ERROR_NONE; + +#if NDS03_TARGET_MAX_NUM == 1 + CHECK_RET(NDS03_ReadNBytesByHalfWord(pNxDevice, + NDS03_REG_DEPTH, (uint16_t*)&pNxDevice->ranging_data[0], + sizeof(pNxDevice->ranging_data[0]))); +#endif + +#if NDS03_TARGET_MAX_NUM == 2 + CHECK_RET(NDS03_ReadNBytesByHalfWord(pNxDevice, + NDS03_REG_DEPTH, (uint16_t*)&pNxDevice->ranging_data[0], + 2 * sizeof(pNxDevice->ranging_data[0]))); +#endif + +#if NDS03_TARGET_MAX_NUM == 3 + CHECK_RET(NDS03_ReadNBytesByHalfWord(pNxDevice, + NDS03_REG_DEPTH, (uint16_t*)&pNxDevice->ranging_data[0], + 3 * sizeof(pNxDevice->ranging_data[0]))); +#endif + +#if NDS03_TARGET_MAX_NUM >= 4 + CHECK_RET(NDS03_ReadNBytesByHalfWord(pNxDevice, + NDS03_REG_DEPTH, (uint16_t*)&pNxDevice->ranging_data[0], + 4 * sizeof(pNxDevice->ranging_data[0]))); +#endif + + return ret; +} + +/** + * @brief NDS03 Get Continuous Ranging Data + * 连续模式下,从NDS03中获取一次深度数据, + * 需要与NDS03_StartContinuousMeasurement函数搭配 + * @param pNxDevice 模组设备 + * @param pData 获取到的深度和幅度数据 + * @return int32_t + */ +NDS03_Error NDS03_GetContinuousRangingData(NDS03_Dev_t *pNxDevice) +{ + NDS03_Error ret = NDS03_ERROR_NONE; + uint8_t data_cnt; + uint32_t retry_cnt = 20000; + + /* 等待测量完成 */ + do { + CHECK_RET(NDS03_ReadByte(pNxDevice, NDS03_REG_DATA_CNT, &data_cnt)); + CHECK_RET(NDS03_Delay10us(pNxDevice, 10)); + } while (data_cnt == pNxDevice->data_cnt && --retry_cnt); + pNxDevice->data_cnt = data_cnt; + if (retry_cnt != 0) { + /* 读取测量数据 */ + CHECK_RET(NDS03_ReadRangingData(pNxDevice)); + /* 清除数据有效标志位 */ + CHECK_RET(NDS03_ClearDataValidFlag(pNxDevice)); + } else { + ret = NDS03_ERROR_TIMEOUT; + } + + return ret; +} + +/** + * @brief NDS03 Get Single Ranging Data + * NDS03中获取一次深度数据 + * + * @param pNxDevice 模组设备 + * @return int32_t + */ +NDS03_Error NDS03_GetSingleRangingData(NDS03_Dev_t *pNxDevice) +{ + NDS03_Error ret = NDS03_ERROR_NONE; + int32_t timeout_ms = pNxDevice->config.range_frame_time_us / 1000; + + /* 清除标志位 */ + CHECK_RET(NDS03_WriteByte(pNxDevice, NDS03_REG_DAT_VAL, NDS03_DATA_VAL_IDLE)); + /* 发送触发信号 */ + CHECK_RET(NDS03_WriteByte(pNxDevice, NDS03_REG_DAT_REQ, NDS03_DEPTH_DATA_FLAG)); + /* 等待测量完成 */ + timeout_ms = (timeout_ms < 200) ? 200 : timeout_ms; + CHECK_RET(NDS03_WaitforDataVal(pNxDevice, NDS03_DEPTH_DATA_FLAG, timeout_ms)); + /* 读取测量数据 */ + CHECK_RET(NDS03_ReadRangingData(pNxDevice)); + /* 清除数据有效标志位 */ + CHECK_RET(NDS03_ClearDataValidFlag(pNxDevice)); + + return ret; +} + +/** + * @brief NDS03 Get Interrupt Ranging Data + * NDS03中获取一次中断深度数据 + * + * @param pNxDevice 模组设备 + * @return int32_t + */ +NDS03_Error NDS03_GetInterruptRangingData(NDS03_Dev_t *pNxDevice) +{ + NDS03_Error ret = NDS03_ERROR_NONE; + + /* 读取测量数据 */ + CHECK_RET(NDS03_ReadRangingData(pNxDevice)); + /* 清除数据有效标志位 */ + CHECK_RET(NDS03_ClearDataValidFlag(pNxDevice)); + + return ret; +} + diff --git a/drivers/iio/proximity/nds03/nds03_data.h b/drivers/iio/proximity/nds03/nds03_data.h new file mode 100644 index 000000000000..4475e4c4dbd3 --- /dev/null +++ b/drivers/iio/proximity/nds03/nds03_data.h @@ -0,0 +1,46 @@ +/** + * @file nds03_data.h + * @author tongsheng.tang + * @brief NDS03 communication and data handling functions + * @version 2.x.x + * @date 2025-06 + * + * @copyright Copyright (c) 2025, Nephotonics Information Technology (Hefei) Co., Ltd. + * + * @license BSD 3-Clause License + * This file is part of the NDS03 SDK and is licensed under the BSD 3-Clause License. + * You may obtain a copy of the license in the project root directory, + * in the file named LICENSE. + * + */ +#ifndef __NDS03_DATA_H__ +#define __NDS03_DATA_H__ + +#include "nds03_def.h" +/** @defgroup NDS03_Data_Group NDS03 Data Functions + * @brief NDS03 Data Functions + * @{ + */ + +/** 检测NDS03测距是否完成 */ +NDS03_Error NDS03_GetRangingDataReady(NDS03_Dev_t *pNxDevice); +/** 发送开始单次测量信号 */ +NDS03_Error NDS03_StartSingleMeasurement(NDS03_Dev_t *pNxDevice); +/** 发送开始连续测量信号 */ +NDS03_Error NDS03_StartContinuousMeasurement(NDS03_Dev_t *pNxDevice); +/** 发送结束连续测量信号 */ +NDS03_Error NDS03_StopContinuousMeasurement(NDS03_Dev_t *pNxDevice); +/** 清除数据有效位 */ +NDS03_Error NDS03_ClearDataValidFlag(NDS03_Dev_t *pNxDevice); +/** 读取深度和幅度值 */ +NDS03_Error NDS03_ReadRangingData(NDS03_Dev_t *pNxDevice); +/** 获取连续测量深度和幅度值 */ +NDS03_Error NDS03_GetContinuousRangingData(NDS03_Dev_t *pNxDevice); +/** 获取一次测量深度和幅度值 */ +NDS03_Error NDS03_GetSingleRangingData(NDS03_Dev_t *pNxDevice); +/** 获取一次中断数据 */ +NDS03_Error NDS03_GetInterruptRangingData(NDS03_Dev_t *pNxDevice); + +/** @} NDS03_Data_Group */ + +#endif // __NDS03_DATA_H__ diff --git a/drivers/iio/proximity/nds03/nds03_def.h b/drivers/iio/proximity/nds03/nds03_def.h new file mode 100644 index 000000000000..047c75ba7929 --- /dev/null +++ b/drivers/iio/proximity/nds03/nds03_def.h @@ -0,0 +1,308 @@ +/** + * @file nds03_def.h + * @author tongsheng.tang + * @brief NDS03's Macro definition and data structure + * @version 2.x.x + * @date 2025-06 + * + * @copyright Copyright (c) 2025, Nephotonics Information Technology (Hefei) Co., Ltd. + * + * @license BSD 3-Clause License + * This file is part of the NDS03 SDK and is licensed under the BSD 3-Clause License. + * You may obtain a copy of the license in the project root directory, + * in the file named LICENSE. + * + */ +#ifndef __NDS03_DEF_H__ +#define __NDS03_DEF_H__ + +#include "nds03_stdint.h" +#if NDS03_PLATFORM == PLATFORM_LINUX_DRIVER +#include +#else +#include +#endif +#include "nds03_platform.h" + +#ifndef DEBUG_INFO +#define DEBUG_INFO 0 /** 调试信息打印开关 */ +#endif + +#if NDS03_PLATFORM == PLATFORM_NOT_C51 +#include +#define NX_PRINTF(fmt, ...) do { if (DEBUG_INFO) printf(fmt, ##__VA_ARGS__); } while(0) + +#elif NDS03_PLATFORM == PLATFORM_LINUX_DRIVER +#include +#define NX_PRINTF(fmt, args...) do { if (DEBUG_INFO) printk(fmt, ##args); } while(0) + +#elif NDS03_PLATFORM == PLATFORM_C51 +#define NX_PRINTF(fmt, ...) + +#else +#define NX_PRINTF(fmt, ...) +#endif + +/** @defgroup NDS03_Global_Define_Group NDS03 Defines + * @brief NDS03 Defines + * @{ + */ + +/** @defgroup NDS03_Reg_Group NDS03 Register Defines + * @brief NDS03 Register Defines + * @{ + */ +#define NDS03_REG_DEV_ADDR (0x1E) /** 模组的设备地址 */ + +#define NDS03_REG_STATE (0x20) /** 模组运行状态寄存器 */ +#define NDS03_REG_DATA_CNT (0x21) /** 模组测距次数计数值 */ +#define NDS03_REG_FW_VER (0x24) /** 模组固件版本号寄存器 */ + +#define NDS03_REG_RANGE_STATE (0x28) /** 测距状态码 */ +#define NDS03_REG_CALIB_STATE (0x29) /** 标定状态码 */ +#define NDS03_REG_THERM (0x2A) /** 温度值 */ +#define NDS03_REG_AMBIENT (0x2C) /** 环境光值 */ + +#define NDS03_REG_DEPTH (0x30) /** 深度值 */ +#define NDS03_REG_CONFI (0x32) /** 置信度 */ +#define NDS03_REG_COUNT (0x34) /** 计数值 */ +#define NDS03_REG_CRATE (0x36) /** 计数率 */ +#define NDS03_REG_DEPTH2 (0x38) /** 深度值 */ +#define NDS03_REG_CONFI2 (0x3A) /** 置信度 */ +#define NDS03_REG_COUNT2 (0x3C) /** 计数值 */ +#define NDS03_REG_CRATE2 (0x3E) /** 计数率 */ +#define NDS03_REG_DEPTH3 (0x40) /** 深度值 */ +#define NDS03_REG_CONFI3 (0x42) /** 置信度 */ +#define NDS03_REG_COUNT3 (0x44) /** 计数值 */ +#define NDS03_REG_CRATE3 (0x46) /** 计数率 */ +#define NDS03_REG_DEPTH4 (0x48) /** 深度值 */ +#define NDS03_REG_CONFI4 (0x4A) /** 置信度 */ +#define NDS03_REG_COUNT4 (0x4C) /** 计数值 */ +#define NDS03_REG_CRATE4 (0x4E) /** 计数率 */ + +#define NDS03_REG_DAT_REQ (0x50) /** 获取深度请求寄存器 */ +#define NDS03_REG_DAT_VAL (0x51) /** 获取数据命令有效寄存器 */ +#define NDS03_REG_CMD_REQ (0x52) /** 命令请求寄存器 */ +#define NDS03_REG_CMD_VAL (0x53) /** 命令完成寄存器 */ +#define NDS03_REG_CMD_ENA (0x54) /** 命令使能寄存器 */ +#define NDS03_REG_CFG_ENA (0x55) /** 配置使能,该值为0xA5才能访问其他寄存器 */ +#define NDS03_REG_REF_HISTO_MAX (0x56) /** 参考直方图最大值 */ + +#define NDS03_REG_DEPTH_FLAG (0x64) /** 测距结果标志位 */ +#define NDS03_REG_SLEEP_TIME (0x66) /** 睡眠时间(ms) */ +#define NDS03_REG_PULSE_NUM (0x6C) /** 发光次数 */ + +#define NDS03_REG_DEPTH_TH_L (0x70) /** 深度低阈值 */ +#define NDS03_REG_DEPTH_TH_H (0x72) /** 深度高阈值 */ +#define NDS03_REG_GPIO1_FUNC (0x74) /** 中断功能/方式 */ +#define NDS03_REG_SLEEP_MODE (0x75) /** 睡眠方式 */ +#define NDS03_REG_CONFI_TH (0x76) /** 置信度阈值 */ +#define NDS03_REG_TARGET_NUM (0x77) /** 目标个数 */ +#define NDS03_REG_INV_TIME (0x7C) /** 测量间隔时间 */ +#define NDS03_REG_OFFSET_MM (0x90) /** offset 标定位置 */ + +#define NDS03_REG_XTALK_TH (0xB0) /** 串扰阈值 */ +#define NDS03_REG_XTALK (0xB2) /** 串扰值 */ + +#define NDS03_REG_DATA_SIZE (0x5C) /** 数据大小 */ +#define NDS03_REG_CACHE_SIZE (0x5D) /** 缓存大小 */ +#define NDS03_REG_CACHE_ADDR (0x5E) /** 缓存地址 */ +#define NDS03_REG_CACHE_DATA (0xC0) /** 缓存数据 */ + +/** @} NDS03_Reg_Group */ + +/** @defgroup NDS03_State_Group NDS03 Data Request Index + * @brief NDS03 State (NDS03_REG_STATE) + * @{ + */ + +#define NDS03_STATE_IDLE 0x00 /** 空闲状态 */ +#define NDS03_STATE_SOFT_READY 0xA5 /** 软件就绪状态 */ +#define NDS03_STATE_GOT_DEPTH 0xA6 /** 已获取深度状态 */ + +/** @} NDS03_State_Group */ + +/** @defgroup NDS03_Data_Val_Req_Idx_Group NDS03 Data Request Index + * @brief NDS03 Data Request Mask (NDS03_REG_DAT_VAL_REQ) + * @{ + */ +/** DATA REQ */ +#define NDS03_DATA_REQ_IDLE 0x00 /** 无效数据命令标志位 */ +#define NDS03_DEPTH_DATA_FLAG 0x10 /** 获取深度数据标志 */ +#define NDS03_DEPTH_CONTINUOUS_FLAG 0x13 /** 连续获取深度数据标志 */ +#define NDS03_USER_DATA_FLAG 0x50 /** 读用户数据标志位 */ +#define NDS03_GET_MODEL_FLAG 0x51 /** 获取模组型号标志位 */ +#define NDS03_CMD_READ_HGM_DATA 0xC0 /** 读直方图数据标志位 */ +#define NDS03_CMD_READ_HGM_DATA_ENA 0x05 /** 读直方图数据使能标志位 */ + +/** DATA VAL */ +#define NDS03_DATA_VAL_IDLE 0x00 /** 无效数据标志位 */ + +/** CMD REQ */ +#define NDS03_CMD_OFFSET_CALIB 0x20 /** offset标定命令 */ +#define NDS03_CMD_XTALK_CALIB 0x24 /** xtalk标定 */ +#define NDS03_CMD_WRITE_USER_DATA 0x50 /** 写用户数据区域标志位 */ + + +/** CMD VAL */ +#define NDS03_CMD_VAL_IDLE 0x00 /** 无效命令标志位 */ + +/** CMD ENA */ +#define NDS03_CMD_WRITE_USER_DATA_ENA 0xAA /** 用户数据使能标志位 */ +#define NDS03_CMD_ENA_ENABLE 0xA5 /** 配置开启标志位 */ +#define NDS03_CMD_ENA_DISABLE 0x00 /** 配置关闭标志位 */ + +/** @} NDS03_Data_Val_Req_Idx_Group */ + +/** @defgroup NDS03_Sleep_Group NDS03 Sleep Group + * @brief NDS03 Sleep (NDS03_REG_SLEEP_MODE) + * @{ + */ + +#define NDS03_MANUAL_SLEEP_TIME_OUT_WEAK_UP 0xA5 /* 手动进入软件睡眠标志位,超时唤醒 */ +#define NDS03_MANUAL_SLEEP_MANUAL_WEAK_UP 0xA4 /* 手动进入软件睡眠标志位,手动唤醒 */ +// #define NDS03_AUTO_SLEEP_MANUAL_WEAK_UP 0xA3 /* 测量结束自动进入软件睡眠标志位,手动唤醒 */ +// #define NDS03_AUTO_SLEEP_TIME_OUT_WEAK_UP 0xA2 /* 测量结束自动进入软件睡眠标志位,超时唤醒 */ + +/** @} NDS03_Sleep_Group */ + +/** @enum NDS03_Status_e + * @brief 定义NDS03状态宏 + */ +typedef int8_t NDS03_Error; + +/** @defgroup NDS03_Error_Group NDS03 Error Group + * @brief NDS03 Error Group (NDS03_REG_ERROR_FLAG) + * @{ + */ +#define NDS03_ERROR_NONE 0 /** 成功 */ +#define NDS03_ERROR_API -1 /** api接口注册失败 */ +#define NDS03_ERROR_TIMEOUT -2 /** 超时错误 */ +#define NDS03_ERROR_I2C -3 /** IIC通讯错误 */ +#define NDS03_ERROR_BOOT -4 /** 模组启动错误 */ +#define NDS03_ERROR_CALIB -5 /** 标定失败错误 */ +#define NDS03_ERROR_INIT -6 /** 初始化失败 */ +#define NDS03_ERROR_RANGING -7 /** 测距出错 */ +#define NDS03_ERROR_UPGRADE_VER -8 /** 升级版本不对 */ +#define NDS03_ERROR_UPGRADE -9 /** 升级失败 */ +#define NDS03_ERROR_AMBIENT_HIGH -10 /** 标定时环境光强过大 */ +#define NDS03_ERROR_NO_NDS03 -11 /** 不是NDS03模组 */ +#define NDS03_ERROR_VCSEL_ERROR -12 /** VCSEL不亮 */ +#define NDS03_ERROR_OFFSET_ERROR -13 /** OFFSET 标定失败 */ + +/** @} NDS03_Error_Group */ + +/** @defgroup NDS03_Calib_State_Group NDS03 Calib State Group + * @brief NDS03 Calib State Group (NDS03_REG_CALIB_STATE) + * @{ + */ +#define NDS03_CALIB_ERROR_NONE 0x00 /** 成功 */ +#define NDS03_CALIB_ERROR_XTALK_OVERFLOW 0x02 /** 串扰溢出 */ +#define NDS03_CALIB_ERROR_XTALK_EXCESSIVE 0x10 /** 串扰过大 */ +#define NDS03_CALIB_ERROR_OFFSET 0x20 /** offset标定后测距误差过大 */ +/** @} NDS03_Calib_State_Group */ + +/** @defgroup NDS03_GPIO1_Func_Group NDS03 GPIO1 Functions Define + * @brief NDS03 GPIO1 Functions Define Group (NDS03_REG_GPIO1_FUNC) + * @{ + */ + +/** REG_GPIO1_SETTING Mask */ +#define NDS03_GPIO1_FUNCTIONALITY_MASK 0x07 /** GPIO1功能配置掩码 */ +#define NDS03_GPIO1_POLARITY_MASK 0x08 /** 极性配置掩码 */ + +/** GPIO1 Functionality */ +typedef uint8_t NDS03_Gpio1Func_t; +#define NDS03_GPIO1_FUNCTIONALITY_OFF ((NDS03_Gpio1Func_t)0x00) /** 无触发中断 */ +#define NDS03_GPIO1_THRESHOLD_LOW ((NDS03_Gpio1Func_t)0x01) /** 低深度触发中断 (value < NDS03_REG_DEPTH_TH_L) */ +#define NDS03_GPIO1_THRESHOLD_HIGH ((NDS03_Gpio1Func_t)0x02) /** 高深度触发中断 (value > NDS03_REG_DEPTH_TH_H) */ +#define NDS03_GPIO1_THRESHOLD_DOMAIN_OUT ((NDS03_Gpio1Func_t)0x03) /** 低深度或高深度触发中断 (value < NDS03_REG_DEPTH_TH_L 或 value > NDS03_REG_DEPTH_TH_H) */ +#define NDS03_GPIO1_NEW_MEASURE_READY ((NDS03_Gpio1Func_t)0x04) /** 新深度数据就绪中断 */ + +/** GPIO1 polarity */ +typedef uint8_t NDS03_Gpio1Polar_t; +#define NDS03_GPIO1_POLARITY_LOW ((NDS03_Gpio1Polar_t)0x00) /** 负极性, 低电平有效 */ +#define NDS03_GPIO1_POLARITY_HIGH ((NDS03_Gpio1Polar_t)0x01) /** 正极性, 高电平有效 */ + +/** @} NDS03_GPIO1_Func_Group */ + +#define NDS03_TARGET_MAX_NUM 4 +#define NDS03_AMBIENT_TH 1000 /** 标定时环境光强阈值 */ +#define NDS03_OFFSET_DEPTH_ERROR_TH 10 /** OFFSET 标定深度误差阈值 */ +#define NDS03_OFFSET_REF_MAX_COUNT_TH 500 /** OFFSET 标定深度误差阈值 */ +#define NDS03_DEPTH_INVALID_VALUE 65300 /** 深度无效值 */ + +/** @enum NDS03_Status_e + * @brief 定义NDS03状态宏 + */ +typedef enum{ + NDS03_DISABLE = 0, ///< 关闭状态 + NDS03_ENABLE = 1 ///< 使能状态 +} NDS03_Status_e; + +/** + * @struct NDS03_RangingData_t + * + * @brief NDS03测量结果结构体 \n + * 定义存储NDS03的深度、置信度信息 + */ +typedef struct{ + uint16_t depth; ///< 测量距离 + uint16_t confi; ///< 测量置信度 + uint16_t count; ///< 计数值 + uint16_t crate; ///< 计数率 +} NDS03_RangingData_t; + + +/** + * @struct NDS03_ChipInfo_t + * + * @brief NDS03模组生产信息\n + */ +typedef struct { + uint32_t fw_version; ///< NDS03固件版本 +} NDS03_ChipInfo_t; + +/** + * @struct NDS03_DevConfig_t + * + * @brief NDS03模组配置数据\n + */ +typedef struct { + uint32_t range_frame_time_us; //< 模组取图帧间隔时间配置 + uint8_t continuous_flag; ///< 连续模式标志位 + uint8_t target_num; ///< 目标个数 +} NDS03_DevConfig_t; + +/** + * @struct NDS03_Dev_t + * + * @brief 设备类型结构体\n + */ +typedef struct { + uint8_t dev_pwr_state; ///< 设备的当前状态, 就绪模式或者休眠模式 + NDS03_DevConfig_t config; ///< 模组配置信息 + NDS03_ChipInfo_t chip_info; ///< 模组设备信息 + uint8_t data_cnt; ///< 数据获取次数 + NDS03_RangingData_t ranging_data[NDS03_TARGET_MAX_NUM]; ///< 测距数据结果 + NDS03_Platform_t platform; +} NDS03_Dev_t; + +#define NDS03_DEFAULT_SLAVE_ADDR 0x5C + +#if NDS03_PLATFORM == PLATFORM_C51 +#define CHECK_RET(func) \ + ret = func; \ + if(ret != NDS03_ERROR_NONE) \ + return ret; +#else +#define CHECK_RET(func) do { \ + ret = func; \ + if(ret != NDS03_ERROR_NONE) { \ + NX_PRINTF("%s I2c Error, ret: %d\r\n", #func, ret); \ + return ret; \ + } \ +} while (0) +#endif + +#endif diff --git a/drivers/iio/proximity/nds03/nds03_dev.c b/drivers/iio/proximity/nds03/nds03_dev.c new file mode 100644 index 000000000000..09cd9a5f2d53 --- /dev/null +++ b/drivers/iio/proximity/nds03/nds03_dev.c @@ -0,0 +1,743 @@ +/** + * @file nds03_dev.c + * @author tongsheng.tang + * @brief NDS03 device setting functions + * @version 2.x.x + * @date 2025-06 + * + * @copyright Copyright (c) 2025, Nephotonics Information Technology (Hefei) Co., Ltd. + * + * @license BSD 3-Clause License + * This file is part of the NDS03 SDK and is licensed under the BSD 3-Clause License. + * You may obtain a copy of the license in the project root directory, + * in the file named LICENSE. + * + */ + +#include "nds03_dev.h" +#include "nds03_def.h" +#include "nds03_comm.h" + +/** SDK主版本 */ +static uint8_t sdk_version_major = 2; +/** SDK次版本 */ +static uint8_t sdk_version_minor = 0; +/** SDK小版本 */ +static uint8_t sdk_version_patch = 3; + +/** + * @brief NDS03 Get SDK Version + * 获取当前SDK的软件版本号 + * @return uint32_t + * @retval 软件版本号 + */ +uint32_t NDS03_GetSdkVersion(void) +{ + return ((uint32_t)sdk_version_major << 16) + + ((uint32_t)sdk_version_minor << 8) + (uint32_t)sdk_version_patch; +} + +/** + * @brief NDS03 Get Firmware Version + * 获取NDS03模组固件版本号 + * @param pNxDevice + * @return NDS03_Error + */ +NDS03_Error NDS03_GetFirmwareVersion(NDS03_Dev_t *pNxDevice) +{ + NDS03_Error ret = NDS03_ERROR_NONE; + + CHECK_RET(NDS03_ReadWord(pNxDevice, NDS03_REG_FW_VER, &pNxDevice->chip_info.fw_version)); + return ret; +} + +/** + * @brief NDS03 Get Therm + * 获取NDS03的温度 + * @param pNxDevice + * @param therm 温度,单位为0.1度 + * @return NDS03_Error + */ +NDS03_Error NDS03_GetTherm(NDS03_Dev_t *pNxDevice, int16_t* therm) +{ + NDS03_Error ret = NDS03_ERROR_NONE; + + CHECK_RET(NDS03_ReadHalfWord(pNxDevice, NDS03_REG_THERM, (uint16_t*)therm)); + return ret; +} + +/** + * @brief NDS03 Set Pulse Num + * 设置发光次数 + * @param pNxDevice + * @param pulse_num 发光次数 + * @return NDS03_Error + */ +NDS03_Error NDS03_SetPulseNum(NDS03_Dev_t *pNxDevice, uint32_t pulse_num) +{ + NDS03_Error ret = NDS03_ERROR_NONE; + + CHECK_RET(NDS03_WriteByte(pNxDevice, NDS03_REG_CFG_ENA, NDS03_CMD_ENA_ENABLE)); + CHECK_RET(NDS03_WriteWord(pNxDevice, NDS03_REG_PULSE_NUM, pulse_num)); + CHECK_RET(NDS03_WriteByte(pNxDevice, NDS03_REG_CFG_ENA, NDS03_CMD_ENA_DISABLE)); + + return ret; +} +/** + * @brief NDS03 Get Pulse Num + * 获取发光次数 + * @param pNxDevice + * @param pulse_num 发光次数 + * @return NDS03_Error + */ +NDS03_Error NDS03_GetPulseNum(NDS03_Dev_t *pNxDevice, uint32_t *pulse_num) +{ + NDS03_Error ret = NDS03_ERROR_NONE; + + CHECK_RET(NDS03_ReadWord(pNxDevice, NDS03_REG_PULSE_NUM, pulse_num)); + + return ret; +} + +/** + * @brief NDS03 Set Frame Time + * 设置测量帧间隔时间(us) + * @param pNxDevice + * @param inv_time 测量帧间隔时间 + * @return NDS03_Error + */ +NDS03_Error NDS03_SetFrameTime(NDS03_Dev_t *pNxDevice, uint32_t frame_time_us) +{ + NDS03_Error ret = NDS03_ERROR_NONE; + + CHECK_RET(NDS03_WriteByte(pNxDevice, NDS03_REG_CFG_ENA, NDS03_CMD_ENA_ENABLE)); + CHECK_RET(NDS03_WriteWord(pNxDevice, NDS03_REG_INV_TIME, frame_time_us)); + CHECK_RET(NDS03_WriteByte(pNxDevice, NDS03_REG_CFG_ENA, NDS03_CMD_ENA_DISABLE)); + CHECK_RET(NDS03_ReadWord(pNxDevice, NDS03_REG_INV_TIME, + &pNxDevice->config.range_frame_time_us)); + + return ret; +} +/** + * @brief NDS03 Get Frame Time + * 获取帧测量间隔时间(us) + * @param pNxDevice + * @param inv_time 测量间隔时间 + * @return NDS03_Error + */ +NDS03_Error NDS03_GetFrameTime(NDS03_Dev_t *pNxDevice, uint32_t *frame_time_us) +{ + NDS03_Error ret = NDS03_ERROR_NONE; + + CHECK_RET(NDS03_ReadWord(pNxDevice, NDS03_REG_INV_TIME, + &pNxDevice->config.range_frame_time_us)); + *frame_time_us = pNxDevice->config.range_frame_time_us; + + return ret; +} + +/** + * @brief NDS03 Set Confidence threshold + * 配置置信度阈值 + * @param pNxDevice + * @param confi_th + * @return NDS03_Error + */ +NDS03_Error NDS03_SetConfiTh(NDS03_Dev_t *pNxDevice, uint8_t confi_th) +{ + NDS03_Error ret = NDS03_ERROR_NONE; + + CHECK_RET(NDS03_WriteByte(pNxDevice, NDS03_REG_CFG_ENA, NDS03_CMD_ENA_ENABLE)); + CHECK_RET(NDS03_WriteByte(pNxDevice, NDS03_REG_CONFI_TH, confi_th)); + CHECK_RET(NDS03_WriteByte(pNxDevice, NDS03_REG_CFG_ENA, NDS03_CMD_ENA_DISABLE)); + + return ret; +} + +/** + * @brief NDS03 Get Confidence threshold + * 获取置信度阈值 + * @param pNxDevice + * @param confi_th 置信度阈值 + * @return NDS03_Error + */ +NDS03_Error NDS03_GetConfiTh(NDS03_Dev_t *pNxDevice, uint8_t *confi_th) +{ + NDS03_Error ret = NDS03_ERROR_NONE; + + CHECK_RET(NDS03_ReadByte(pNxDevice, NDS03_REG_CONFI_TH, confi_th)); + + return ret; +} + +/** + * @brief NDS03 Set Target Num + * 配置目标个数 + * @param pNxDevice + * @param num + * @return NDS03_Error + */ +NDS03_Error NDS03_SetTargetNum(NDS03_Dev_t *pNxDevice, uint8_t num) +{ + NDS03_Error ret = NDS03_ERROR_NONE; + + num = (num > NDS03_TARGET_MAX_NUM) ? NDS03_TARGET_MAX_NUM : num; + CHECK_RET(NDS03_WriteByte(pNxDevice, NDS03_REG_CFG_ENA, NDS03_CMD_ENA_ENABLE)); + CHECK_RET(NDS03_WriteByte(pNxDevice, NDS03_REG_TARGET_NUM, num)); + CHECK_RET(NDS03_WriteByte(pNxDevice, NDS03_REG_CFG_ENA, NDS03_CMD_ENA_DISABLE)); + pNxDevice->config.target_num = num; + + return ret; +} + +/** + * @brief NDS03 Get Target Num + * 获取目标个数 + * @param pNxDevice + * @param num + * @return NDS03_Error + */ +NDS03_Error NDS03_GetTargetNum(NDS03_Dev_t *pNxDevice, uint8_t *num) +{ + NDS03_Error ret = NDS03_ERROR_NONE; + + CHECK_RET(NDS03_ReadByte(pNxDevice, NDS03_REG_TARGET_NUM, num)); + pNxDevice->config.target_num = *num; + + return ret; +} + +/** + * @brief NDS03 Set Gpio1 Configuration + * 设置中断引脚的功能配置 + * @param pNxDevice: NDS03模组设备信息结构体 + * @param functionality: 中断功能设置 + * NDS03_GPIO1_FUNCTIONALITY_OFF: 无功能(默认) + * NDS03_GPIO1_THRESHOLD_LOW:比较功能,当深度小于低阈值时,GPIO输出有效电平 + * NDS03_GPIO1_THRESHOLD_HIGH:比较功能,当深度大于高阈值时,GPIO输出有效电平 + * NDS03_GPIO1_THRESHOLD_DOMAIN_OUT:比较功能,当深度小于低阈值或者大于高阈值时,GPIO输出有效电平 + * NDS03_GPIO1_NEW_MEASURE_READY:深度数据有效功能,当深度数据有效时,GPIO输出有效电平 + * @param polarity: INT引脚有效电平 + * NDS03_GPIO1_POLARITY_LOW:低电平有效 + * NDS03_GPIO1_POLARITY_HIGH:高电平有效 + * @return NDS03_Error +*/ +NDS03_Error NDS03_SetGpio1Config(NDS03_Dev_t *pNxDevice, + NDS03_Gpio1Func_t functionality, NDS03_Gpio1Polar_t polarity) +{ + NDS03_Error ret = NDS03_ERROR_NONE; + uint8_t rbuf; + + CHECK_RET(NDS03_ReadByte(pNxDevice, NDS03_REG_GPIO1_FUNC, &rbuf)); + /** 设置中断功能 */ + rbuf = rbuf & (~NDS03_GPIO1_FUNCTIONALITY_MASK); + rbuf = rbuf | (functionality & NDS03_GPIO1_FUNCTIONALITY_MASK); + /** 设置中断引脚极性 */ + if (polarity == NDS03_GPIO1_POLARITY_HIGH) + rbuf = rbuf | NDS03_GPIO1_POLARITY_MASK; + else + rbuf = rbuf & (~NDS03_GPIO1_POLARITY_MASK); + + CHECK_RET(NDS03_WriteByte(pNxDevice, NDS03_REG_CFG_ENA, NDS03_CMD_ENA_ENABLE)); + CHECK_RET(NDS03_WriteByte(pNxDevice, NDS03_REG_GPIO1_FUNC, rbuf)); + CHECK_RET(NDS03_WriteByte(pNxDevice, NDS03_REG_CFG_ENA, NDS03_CMD_ENA_DISABLE)); + + return ret; +} + +/** + * @brief NDS03 Get Gpio1 Config + * 获取中断引脚的功能配置 + * @param pNxDevice: NDS03模组设备信息结构体指针 + * @param functionality: 获取到的中断功能变量指针 + * @param polarity: 获取到的中断引脚极性变量指针 + * @return NDS03_Error +*/ +NDS03_Error NDS03_GetGpio1Config(NDS03_Dev_t *pNxDevice, + NDS03_Gpio1Func_t *functionality, NDS03_Gpio1Polar_t *polarity) +{ + NDS03_Error ret = NDS03_ERROR_NONE; + uint8_t rbuf; + + CHECK_RET(NDS03_ReadByte(pNxDevice, NDS03_REG_GPIO1_FUNC, &rbuf)); + // Polarity + *polarity = ((rbuf & NDS03_GPIO1_POLARITY_MASK) == NDS03_GPIO1_POLARITY_MASK) ? + NDS03_GPIO1_POLARITY_HIGH : NDS03_GPIO1_POLARITY_LOW; + // Functionality + *functionality = rbuf & NDS03_GPIO1_FUNCTIONALITY_MASK; + + return ret; +} + +/** + * @brief NDS03 Set Depth Threshold + * 设置深度阈值 + * 该功能仅用于GPIO功能为 + * NDS03_GPIO1_THRESHOLD_LOW + * 或NDS03_GPIO1_THRESHOLD_HIGH + * 或NDS03_GPIO1_THRESHOLD_DOMAIN_OUT + * @param pNxDevice: NDS03模组设备信息结构体 + * @param depth_low: 低深度阈值 / mm + * @param depth_high: 高深度阈值 / mm + * @return NDS03_Error +*/ +NDS03_Error NDS03_SetDepthThreshold(NDS03_Dev_t *pNxDevice, + uint16_t depth_low, uint16_t depth_high) +{ + NDS03_Error ret = NDS03_ERROR_NONE; + + CHECK_RET(NDS03_WriteByte(pNxDevice, NDS03_REG_CFG_ENA, NDS03_CMD_ENA_ENABLE)); + CHECK_RET(NDS03_WriteHalfWord(pNxDevice, NDS03_REG_DEPTH_TH_L, depth_low)); + CHECK_RET(NDS03_WriteHalfWord(pNxDevice, NDS03_REG_DEPTH_TH_H, depth_high)); + CHECK_RET(NDS03_WriteByte(pNxDevice, NDS03_REG_CFG_ENA, NDS03_CMD_ENA_DISABLE)); + + return ret; +} + +/** + * @brief NDS03 Get Depth Threshold + * 获取深度阈值 + * @param pNxDevice: NDS03模组设备信息结构体 + * @param depth_low: 低深度阈值 / mm + * @param depth_high: 高深度阈值 / mm + * @return NDS03_Error +*/ +NDS03_Error NDS03_GetDepthThreshold(NDS03_Dev_t *pNxDevice, + uint16_t *depth_low, uint16_t *depth_high) +{ + NDS03_Error ret = NDS03_ERROR_NONE; + + CHECK_RET(NDS03_ReadHalfWord(pNxDevice, NDS03_REG_DEPTH_TH_L, depth_low)); + CHECK_RET(NDS03_ReadHalfWord(pNxDevice, NDS03_REG_DEPTH_TH_H, depth_high)); + + return ret; +} + +/** + * @brief NDS03 Waitfor Data Val + * 等待数据完成 + * @param pNxDevice 模组设备 + * @param flag 读命令标志位 + * @return NDS03_Error + */ +NDS03_Error NDS03_WaitforDataVal(NDS03_Dev_t *pNxDevice, uint8_t flag, int32_t timeout_ms) +{ + NDS03_Error ret = NDS03_ERROR_NONE; + uint8_t dat_valid_flag = 0x00; + int32_t retry_cnt; + + retry_cnt = timeout_ms * 2; + do { + CHECK_RET(NDS03_ReadByte(pNxDevice, NDS03_REG_DAT_VAL, &dat_valid_flag)); + if (dat_valid_flag == flag) + break; + NDS03_Delay10us(pNxDevice, 50); + } while (--retry_cnt); + + if (retry_cnt == 0) { + NX_PRINTF("data_valid_flag: %d\r\n", dat_valid_flag); + ret = NDS03_ERROR_TIMEOUT; + } + + return ret; +} + +/** + * @brief NDS03 Waitfor Cmd Val + * 等待命令完成 + * @param pNxDevice 模组设备 + * @param cmd 命令 + * @param timeout_ms 超时时间 + * @return NDS03_Error + */ +NDS03_Error NDS03_WaitforCmdVal(NDS03_Dev_t *pNxDevice, uint8_t cmd, int32_t timeout_ms) +{ + NDS03_Error ret = NDS03_ERROR_NONE; + int32_t retry_cnt; + uint8_t val; + + retry_cnt = timeout_ms * 2; + do { + CHECK_RET(NDS03_ReadByte(pNxDevice, NDS03_REG_CMD_VAL, &val)); + if (val == cmd) + break; + + NDS03_Delay10us(pNxDevice, 50); + } while (--retry_cnt); + + if (retry_cnt == 0) { + NX_PRINTF("Timeout!!, val: 0x%02x\r\n", val); + ret = NDS03_ERROR_TIMEOUT; + } + + return ret; +} + +/** + * @brief NDS03 Read Hgm Data + * 读取NDS03直方图数据 + * @param pNxDevice 模组设备 + * @param rbuf 数据指针 + * @param size 数据大小 + * @return NDS03_Error + */ +NDS03_Error NDS03_ReadHgmData(NDS03_Dev_t *pNxDevice, uint8_t *rbuf, uint32_t size) +{ + NDS03_Error ret = NDS03_ERROR_NONE; + uint32_t rsize, _size; + uint8_t one_size; + uint16_t addr = 0xe000; + + CHECK_RET(NDS03_ReadByte(pNxDevice, NDS03_REG_CACHE_SIZE, &one_size)); + _size = (uint32_t)one_size; + rsize = 0; + while ((rsize < size) && (ret == NDS03_ERROR_NONE)) { + CHECK_RET(NDS03_WriteHalfWord(pNxDevice, NDS03_REG_CACHE_ADDR, addr)); + CHECK_RET(NDS03_WriteByte(pNxDevice, NDS03_REG_CMD_ENA, 0x05)); + CHECK_RET(NDS03_WriteByte(pNxDevice, NDS03_REG_DAT_REQ, 0xC0)); + CHECK_RET(NDS03_WaitforDataVal(pNxDevice, 0xC0, 200)); + CHECK_RET(NDS03_ReadNBytes(pNxDevice, + NDS03_REG_CACHE_DATA, rbuf, + ((size - rsize) > _size) ? _size : (size - rsize))); + CHECK_RET(NDS03_WriteByte(pNxDevice, NDS03_REG_DAT_VAL, NDS03_DATA_VAL_IDLE)); + rbuf += _size; + addr += _size; + rsize += _size; + } + + return ret; +} + +/** + * @brief NDS03 Read User Data + * 读取NDS03中用户数据区域,支持任意地址循环读取,比如从0xFFF0开始读取32个字节, + * 则前16个字节数据是0xFFF0~0xFFFF的数据,后16个字节是0x0000~0x000F的数据 + * @param pNxDevice 模组设备 + * @param addr 数据地址,0x0000~0xFFFF + * @param rbuf 数据指针 + * @param size 数据大小 + * @return NDS03_Error + */ +NDS03_Error NDS03_ReadUserData(NDS03_Dev_t *pNxDevice, + uint16_t addr, uint8_t *rbuf, uint32_t size) +{ + NDS03_Error ret = NDS03_ERROR_NONE; + uint32_t rsize, _size; + uint8_t one_size; + + CHECK_RET(NDS03_ReadByte(pNxDevice, NDS03_REG_CACHE_SIZE, &one_size)); + _size = (uint32_t)one_size; + rsize = 0; + while ((rsize < size) && (ret == NDS03_ERROR_NONE)) { + CHECK_RET(NDS03_WriteHalfWord(pNxDevice, NDS03_REG_CACHE_ADDR, addr)); + CHECK_RET(NDS03_WriteByte(pNxDevice, NDS03_REG_DAT_REQ, NDS03_USER_DATA_FLAG)); + CHECK_RET(NDS03_WaitforDataVal(pNxDevice, NDS03_USER_DATA_FLAG, 200)); + CHECK_RET(NDS03_ReadNBytes(pNxDevice, NDS03_REG_CACHE_DATA, + rbuf, ((size - rsize) > _size) ? _size : (size - rsize))); + CHECK_RET(NDS03_WriteByte(pNxDevice, NDS03_REG_DAT_VAL, NDS03_DATA_VAL_IDLE)); + rbuf += _size; + addr += _size; + rsize += _size; + } + + return ret; +} + +/** + * @brief NDS03 Read User Data + * 写入NDS03中用户数据区域, 支持任意地址循环写入,比如从0xFFF0开始写入32个字节, + * 则前16个字节数据是0xFFF0~0xFFFF的数据,后16个字节是0x0000~0x000F的数据 + * @param pNxDevice 模组设备 + * @param addr 数据地址,0x0000~0xFFFF + * @param wbuf 数据指针 + * @param size 数据大小 + * @return NDS03_Error + */ +NDS03_Error NDS03_WriteUserData(NDS03_Dev_t *pNxDevice, + uint16_t addr, uint8_t *wbuf, uint32_t size) +{ + NDS03_Error ret = NDS03_ERROR_NONE; + uint32_t rsize, _size; + uint8_t one_size; + + // NX_PRINTF("%s Start\r\n", __func__); + CHECK_RET(NDS03_ReadByte(pNxDevice, NDS03_REG_CACHE_SIZE, &one_size)); + _size = (uint32_t)one_size; + rsize = 0; + while ((rsize < size) && (ret == NDS03_ERROR_NONE)) { + CHECK_RET(NDS03_WriteNBytes(pNxDevice, NDS03_REG_CACHE_DATA, + wbuf, ((size - rsize) > _size) ? _size : (size - rsize))); + CHECK_RET(NDS03_WriteByte(pNxDevice, NDS03_REG_DATA_SIZE, + ((size - rsize) > _size) ? _size : (size - rsize))); + CHECK_RET(NDS03_WriteHalfWord(pNxDevice, NDS03_REG_CACHE_ADDR, addr)); + CHECK_RET(NDS03_WriteByte(pNxDevice, NDS03_REG_CMD_ENA, + NDS03_CMD_WRITE_USER_DATA_ENA)); + CHECK_RET(NDS03_WriteByte(pNxDevice, NDS03_REG_CMD_REQ, + NDS03_CMD_WRITE_USER_DATA)); + CHECK_RET(NDS03_WaitforCmdVal(pNxDevice, NDS03_CMD_WRITE_USER_DATA, 500)); + CHECK_RET(NDS03_WriteByte(pNxDevice, NDS03_REG_CMD_VAL, NDS03_CMD_VAL_IDLE)); + wbuf += _size; + addr += _size; + rsize += _size; + } + // NX_PRINTF("%s End\r\n", __func__); + + return ret; +} + +/** + * @brief NDS03软件休眠,定时自动唤醒 + * + * @param pNxDevice 模组设备 + * @param sleep_time_ms 软件睡眠时间,达到时间后自动唤醒 + * @return NDS03_Error + */ +NDS03_Error NDS03_SoftSleepWithAutoWakeup(NDS03_Dev_t *pNxDevice, uint16_t sleep_time_ms) +{ + NDS03_Error ret = NDS03_ERROR_NONE; + + CHECK_RET(NDS03_WriteByte(pNxDevice, NDS03_REG_CFG_ENA, NDS03_CMD_ENA_ENABLE)); + CHECK_RET(NDS03_WriteHalfWord(pNxDevice, NDS03_REG_SLEEP_TIME, sleep_time_ms)); + CHECK_RET(NDS03_WriteByte(pNxDevice, NDS03_REG_SLEEP_MODE, + NDS03_MANUAL_SLEEP_TIME_OUT_WEAK_UP)); + + return ret; +} + +/** + * @brief NDS03软件休眠,需要手动唤醒 + * + * @param pNxDevice 模组设备 + * @return NDS03_Error + */ +NDS03_Error NDS03_SoftSleepWithManualWakeup(NDS03_Dev_t *pNxDevice) +{ + NDS03_Error ret = NDS03_ERROR_NONE; + + CHECK_RET(NDS03_WriteByte(pNxDevice, NDS03_REG_CFG_ENA, NDS03_CMD_ENA_ENABLE)); + CHECK_RET(NDS03_WriteByte(pNxDevice, + NDS03_REG_SLEEP_MODE, NDS03_MANUAL_SLEEP_MANUAL_WEAK_UP)); + + return ret; +} + +/** + * @brief NDS03 Sleep + * NDS03进入休眠 + * @param pNxDevice 模组设备 + * @return NDS03_Error + */ +NDS03_Error NDS03_Sleep(NDS03_Dev_t *pNxDevice) +{ + NDS03_Error ret = NDS03_ERROR_NONE; + + CHECK_RET(NDS03_SetXShutPinLevel(pNxDevice, 0)); + return ret; +} + +/** + * @brief NDS03 Wakeup + * NDS03从软件睡眠中唤醒 + * @param pNxDevice 模组设备 + * @return NDS03_Error + */ +NDS03_Error NDS03_SoftWakeup(NDS03_Dev_t *pNxDevice) +{ + NDS03_Error ret = NDS03_ERROR_NONE; + uint32_t freq; + + CHECK_RET(NDS03_GetI2cFreq(pNxDevice,&freq)); + CHECK_RET(NDS03_SetI2cFreq(pNxDevice,1000)); + + CHECK_RET(NDS03_WriteByte(pNxDevice, NDS03_REG_CFG_ENA, NDS03_CMD_ENA_ENABLE)); + CHECK_RET(NDS03_WriteByte(pNxDevice, NDS03_REG_SLEEP_MODE, 0)); + + CHECK_RET(NDS03_SetI2cFreq(pNxDevice,freq)); + + return ret; +} + +/** + * @brief NDS03 Software Sleep + * 软件睡眠 + * @param pNxDevice 模组设备 + * @param sleep_time_ms 软件睡眠时间,达到时间后自动唤醒 + * @return NDS03_Error + * @deprecated 在以后的版本会弃用,请使用NDS03_SoftSleepWithAutoWakeup() + */ +static __maybe_unused NDS03_Error NDS03_SoftSleep(NDS03_Dev_t *pNxDevice, uint16_t sleep_time_ms) +{ + NDS03_Error ret = NDS03_ERROR_NONE; + + ret |= NDS03_WriteByte(pNxDevice, NDS03_REG_CFG_ENA, NDS03_CMD_ENA_ENABLE); + ret |= NDS03_WriteHalfWord(pNxDevice, NDS03_REG_SLEEP_TIME, sleep_time_ms); + ret |= NDS03_WriteByte(pNxDevice, NDS03_REG_SLEEP_MODE, + NDS03_MANUAL_SLEEP_TIME_OUT_WEAK_UP); + + return ret; +} + +/** + * @brief NDS03 Wakeup + * NDS03从睡眠中唤醒 + * @param pNxDevice 模组设备 + * @return NDS03_Error + */ +NDS03_Error NDS03_Wakeup(NDS03_Dev_t *pNxDevice) +{ + NDS03_Error ret = NDS03_ERROR_NONE; + + CHECK_RET(NDS03_SetXShutPinLevel(pNxDevice, 1)); + return ret; +} + +/** + * @brief 判断是否为NDS03 + * + * @param pNxDevice + * @return NDS03_Error + * @arg 0: 是NDS03 + * @arg NDS03_ERROR_NO_NDS03: 不是NDS03 + * @arg others: 不确定是否为该模组,需要进一步排查,可能是I2C通信异常。 + * 如果排除I2C通信异常,则认为不是NDS03,可能是其他设备。 + */ +NDS03_Error NDS03_IsNDS03(NDS03_Dev_t *pNxDevice) +{ + NDS03_Error ret = NDS03_ERROR_NONE; + uint8_t buf[4] = {0}; + + NDS03_SetXShutPinLevel(pNxDevice, 1); + CHECK_RET(NDS03_Delay1ms(pNxDevice, 10)); + CHECK_RET(NDS03_WriteByte(pNxDevice, NDS03_REG_DAT_REQ, NDS03_GET_MODEL_FLAG)); + CHECK_RET(NDS03_WaitforDataVal(pNxDevice, NDS03_GET_MODEL_FLAG, 200)); + CHECK_RET(NDS03_ReadNBytes(pNxDevice, NDS03_REG_CACHE_DATA, buf, sizeof(buf))); + CHECK_RET(NDS03_WriteByte(pNxDevice, NDS03_REG_DAT_VAL, NDS03_DATA_VAL_IDLE)); + if ((buf[0] != 0x31) || (buf[1] != 0x53) || (buf[2] != 0x30) || (buf[3] != 0x33)) + ret = NDS03_ERROR_NO_NDS03; + + return ret; +} + +/** + * @brief NDS03 Set Device Address + * 设置模组设备地址 + * @param pNxDevice 模组设备 + * @param dev_addr + * @return NDS03_Error + */ +NDS03_Error NDS03_SetDevAddr(NDS03_Dev_t *pNxDevice, uint8_t dev_addr) +{ + NDS03_Error ret = NDS03_ERROR_NONE; + + CHECK_RET(NDS03_WriteByte(pNxDevice, NDS03_REG_DEV_ADDR, dev_addr)); + pNxDevice->platform.i2c_dev_addr = dev_addr; + + return ret; +} + +/** + * @brief NDS03 InitDevice + * 初始化设备 + * @param pNxDevice 模组设备 + * @return NDS03_Error + */ +NDS03_Error NDS03_InitDevice(NDS03_Dev_t *pNxDevice) +{ + NDS03_Error ret = NDS03_ERROR_NONE; + + // NX_PRINTF("%s Start!\r\n", __func__); + + CHECK_RET(NDS03_GetFirmwareVersion(pNxDevice)); + CHECK_RET(NDS03_ReadByte(pNxDevice, NDS03_REG_DATA_CNT, &pNxDevice->data_cnt)); + CHECK_RET(NDS03_GetFrameTime(pNxDevice, &pNxDevice->config.range_frame_time_us)); + pNxDevice->config.continuous_flag = 0; + + // NX_PRINTF("%s End!\r\n", __func__); + + return ret; +} + +/** + * @brief NDS03 Wait for Device Boot Up + * 等待NDS03模组启动 + * @param pNxDevice 模组设备 + * @return NDS03_ERROR_NONE:成功 + * NDS03_ERROR_BOOT:启动失败--请检测模组是否焊接好,还有i2c地址与读写函数是否错误。 + * NDS03_ERROR_FW:固件不兼容--请与FAE联系,是否模组的固件与SDK不兼容。 + */ +NDS03_Error NDS03_WaitDeviceBootUp(NDS03_Dev_t *pNxDevice) +{ + NDS03_Error ret = NDS03_ERROR_NONE; + int32_t try_times = 200; + uint8_t slave_addr = pNxDevice->platform.i2c_dev_addr; + + NDS03_SetXShutPinLevel(pNxDevice, 0); + CHECK_RET(NDS03_Delay10us(pNxDevice, 20)); + NDS03_SetXShutPinLevel(pNxDevice, 1); + CHECK_RET(NDS03_Delay1ms(pNxDevice, 2)); + ret = NDS03_SetXShutPinLevel(pNxDevice, 1); + pNxDevice->platform.i2c_dev_addr = (ret == NDS03_ERROR_NONE) ? + NDS03_DEFAULT_SLAVE_ADDR : pNxDevice->platform.i2c_dev_addr; + + pNxDevice->data_cnt = 0; + pNxDevice->config.continuous_flag = 0; + + do { + CHECK_RET(NDS03_Delay10us(pNxDevice, 10)); + CHECK_RET(NDS03_ReadByte(pNxDevice, NDS03_REG_STATE, &pNxDevice->dev_pwr_state)); + } while ((pNxDevice->dev_pwr_state != NDS03_STATE_SOFT_READY) && + (pNxDevice->dev_pwr_state != NDS03_STATE_GOT_DEPTH) && --try_times); + + if (0 == try_times) { + NX_PRINTF("state: 0x%02x\r\n", pNxDevice->dev_pwr_state); + NX_PRINTF("NDS03 boot error\r\n"); + return NDS03_ERROR_BOOT; + } + + if (slave_addr != pNxDevice->platform.i2c_dev_addr) + CHECK_RET(NDS03_SetDevAddr(pNxDevice, slave_addr)); + + return ret; +} + +/** + * @brief NDS03 Dirty Warning + * 脏污预警 + * @param pNxDevice 模组设备 + * @param flag 脏污预警标志位 1:脏污预警,0:正常 + * @param time_th 近距离时间阈值,单位ms + * @return NDS03_ERROR_NONE:成功 + */ +NDS03_Error NDS03_DirtyWarning(NDS03_Dev_t *pNxDevice,uint8_t *flag,uint32_t time_th) +{ + NDS03_Error ret = NDS03_ERROR_NONE; + uint16_t depth_low_th = 30; + static int32_t depth_low_count = 0, depth_low_time_sta = 0, depth_low_time_end = 0; + + if (time_th == 0) + time_th = 10 * 1000; + + if (pNxDevice->ranging_data[0].depth < depth_low_th) { + depth_low_count ++; + if (depth_low_count == 1) + NDS03_GetSystemClkMs(pNxDevice, &depth_low_time_sta); + + NDS03_GetSystemClkMs(pNxDevice, &depth_low_time_end); + if (depth_low_time_end < depth_low_time_sta) { + depth_low_time_sta = 0; + depth_low_time_end = 0; + } + } else { + depth_low_count = 0; + depth_low_time_sta = 0; + depth_low_time_end = 0; + } + + if (depth_low_count > 10 && pNxDevice->ranging_data[1].depth != NDS03_DEPTH_INVALID_VALUE) + *flag = 1; + + if ((depth_low_time_end - depth_low_time_sta) > time_th) + *flag = 1; + + return ret; +} diff --git a/drivers/iio/proximity/nds03/nds03_dev.h b/drivers/iio/proximity/nds03/nds03_dev.h new file mode 100644 index 000000000000..99780128875c --- /dev/null +++ b/drivers/iio/proximity/nds03/nds03_dev.h @@ -0,0 +1,94 @@ +/** + * @file nds03_dev.h + * @author tongsheng.tang + * @brief NDS03 device setting functions + * @version 2.x.x + * @date 2025-06 + * + * @copyright Copyright (c) 2025, Nephotonics Information Technology (Hefei) Co., Ltd. + * + * @license BSD 3-Clause License + * This file is part of the NDS03 SDK and is licensed under the BSD 3-Clause License. + * You may obtain a copy of the license in the project root directory, in the file named LICENSE. + * + */ +#ifndef __NDS03_DEV_H__ +#define __NDS03_DEV_H__ + +#include "nds03_def.h" + +/** @defgroup NDS03_Dev_Group NDS03 Device Functions + * @brief NDS03 Device Functions + * @{ + */ + +/** 获取SDK版本号 */ +uint32_t NDS03_GetSdkVersion(void); +/** 获取NDS03模组固件版本号 */ +NDS03_Error NDS03_GetFirmwareVersion(NDS03_Dev_t *pNxDevice); +/** 获取温度 */ +NDS03_Error NDS03_GetTherm(NDS03_Dev_t *pNxDevice, int16_t* therm); +/** 设置发光次数 */ +NDS03_Error NDS03_SetPulseNum(NDS03_Dev_t *pNxDevice, uint32_t pulse_num); +/** 获取发光次数 */ +NDS03_Error NDS03_GetPulseNum(NDS03_Dev_t *pNxDevice, uint32_t *pulse_num); +/** 设置测量间隔时间 */ +NDS03_Error NDS03_SetFrameTime(NDS03_Dev_t *pNxDevice, uint32_t frame_time_us); +/** 获取测量间隔时间 */ +NDS03_Error NDS03_GetFrameTime(NDS03_Dev_t *pNxDevice, uint32_t *frame_time_us); +/** 设置置信度阈值 */ +NDS03_Error NDS03_SetConfiTh(NDS03_Dev_t *pNxDevice, uint8_t confi_th); +/** 获取置信度阈值 */ +NDS03_Error NDS03_GetConfiTh(NDS03_Dev_t *pNxDevice, uint8_t *confi_th); +/** 设置目标个数 */ +NDS03_Error NDS03_SetTargetNum(NDS03_Dev_t *pNxDevice, uint8_t num); +/** 获取目标个数 */ +NDS03_Error NDS03_GetTargetNum(NDS03_Dev_t *pNxDevice, uint8_t *num); +/** 设置中断引脚功能 */ +NDS03_Error NDS03_SetGpio1Config(NDS03_Dev_t *pNxDevice, + NDS03_Gpio1Func_t functionality, NDS03_Gpio1Polar_t polarity); +/** 获取中断引脚功能 */ +NDS03_Error NDS03_GetGpio1Config(NDS03_Dev_t *pNxDevice, + NDS03_Gpio1Func_t *functionality, NDS03_Gpio1Polar_t *polarity); +/** 设置深度阈值 */ +NDS03_Error NDS03_SetDepthThreshold(NDS03_Dev_t *pNxDevice, + uint16_t depth_low, uint16_t depth_high); +/** 获取深度阈值 */ +NDS03_Error NDS03_GetDepthThreshold(NDS03_Dev_t *pNxDevice, + uint16_t *depth_low, uint16_t *depth_high); +/** 等待获取数据结束 */ +NDS03_Error NDS03_WaitforDataVal(NDS03_Dev_t *pNxDevice, uint8_t flag, int32_t timeout_ms); +/** 等待命令结束 */ +NDS03_Error NDS03_WaitforCmdVal(NDS03_Dev_t *pNxDevice, uint8_t cmd, int32_t timeout_ms); +/** 从NDS03中读取直方图数据 */ +NDS03_Error NDS03_ReadHgmData(NDS03_Dev_t *pNxDevice,uint8_t *rbuf, uint32_t size); +/** 从NDS03中读取用户数据 */ +NDS03_Error NDS03_ReadUserData(NDS03_Dev_t *pNxDevice, uint16_t addr, uint8_t *rbuf, uint32_t size); +/** 从NDS03中写入用户数据 */ +NDS03_Error NDS03_WriteUserData(NDS03_Dev_t *pNxDevice, + uint16_t addr, uint8_t *wbuf, uint32_t size); +/** NDS03进入软件睡眠,手动唤醒 */ +NDS03_Error NDS03_SoftSleepWithManualWakeup(NDS03_Dev_t *pNxDevice); +/** NDS03进入软件睡眠,自动唤醒 */ +NDS03_Error NDS03_SoftSleepWithAutoWakeup(NDS03_Dev_t *pNxDevice, uint16_t sleep_time_ms); +/** NDS03从软件睡眠中唤醒 */ +NDS03_Error NDS03_SoftWakeup(NDS03_Dev_t *pNxDevice); +/** NDS03进入睡眠 */ +NDS03_Error NDS03_Sleep(NDS03_Dev_t *pNxDevice); +/** NDS03从睡眠中唤醒 */ +NDS03_Error NDS03_Wakeup(NDS03_Dev_t *pNxDevice); +/** 判断是否为NDS03设备,返回值为0表示是NDS03设备 */ +NDS03_Error NDS03_IsNDS03(NDS03_Dev_t *pNxDevice); +/** 设置模组设备地址 */ +NDS03_Error NDS03_SetDevAddr(NDS03_Dev_t *pNxDevice, uint8_t dev_addr); +/** 初始化设备 */ +NDS03_Error NDS03_InitDevice(NDS03_Dev_t *pNxDevice); +/** 等待设备启动 */ +NDS03_Error NDS03_WaitDeviceBootUp(NDS03_Dev_t *pNxDevice); +/** 脏污预警 */ +NDS03_Error NDS03_DirtyWarning(NDS03_Dev_t *pNxDevice,uint8_t *flag,uint32_t time_th); + +/** @} NDS03_Dev_Group */ + +#endif + diff --git a/drivers/iio/proximity/nds03/nds03_iio.c b/drivers/iio/proximity/nds03/nds03_iio.c new file mode 100644 index 000000000000..a683cc292616 --- /dev/null +++ b/drivers/iio/proximity/nds03/nds03_iio.c @@ -0,0 +1,235 @@ +// SPDX-License-Identifier: GPL-2.0 +#include +#include +#include +#include +#include +#include "nds03_iio.h" +#include "nds03.h" + +#define NDS03_DISTANCE_CHANNEL { \ + .type = IIO_DISTANCE, \ + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \ + BIT(IIO_CHAN_INFO_SCALE) | \ + BIT(IIO_CHAN_INFO_ENABLE), \ + .info_mask_separate_available = BIT(IIO_CHAN_INFO_SCALE),\ + .scan_index = NDS03_IIO_CHAN_DISTANCE, \ + .scan_type = { \ + .sign = 'u', \ + .realbits = 16, \ + .storagebits = 16, \ + .endianness = IIO_LE, \ + }, \ +} + +static const int nds03_scales[] = { 1 }; + +static const struct iio_chan_spec nds03_channels[] = { + NDS03_DISTANCE_CHANNEL, + IIO_CHAN_SOFT_TIMESTAMP(NDS03_IIO_CHAN_TIMESTAMP), +}; + +static int nds03_read_avail(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + const int **vals, int *type, int *length, + long mask) +{ + switch (mask) { + case IIO_CHAN_INFO_SCALE: + *type = IIO_VAL_INT; + *vals = nds03_scales; + *length = ARRAY_SIZE(nds03_scales); + return IIO_AVAIL_LIST; + default: + return -EINVAL; + } +} + +/* === read_raw === */ +static int nds03_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int *val, int *val2, long mask) +{ + struct nds03_iio_dev *iio = iio_device_get_drvdata(indio_dev); + + switch (mask) { + case IIO_CHAN_INFO_RAW: + if (chan->scan_index == NDS03_IIO_CHAN_DISTANCE) { + *val = iio->ctx->g_nds03_device.ranging_data[0].depth; + return IIO_VAL_INT; + } + break; + case IIO_CHAN_INFO_SCALE: + *val = nds03_scales[0]; + return IIO_VAL_INT; + case IIO_CHAN_INFO_ENABLE: + *val = iio->enabled; + return IIO_VAL_INT; + + default: + return -EINVAL; + } + + return -EINVAL; +} + +static int nds03_write_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int val, int val2, long mask) +{ + switch (mask) { + case IIO_CHAN_INFO_RAW: + return -EINVAL; + case IIO_CHAN_INFO_SCALE: + /* NOTE: Default to 1 */ + return 0; + case IIO_CHAN_INFO_ENABLE: + return -EINVAL; + default: + return -EINVAL; + } +} + +static const struct iio_info nds03_iio_info = { + .read_raw = nds03_read_raw, + .write_raw = nds03_write_raw, + .read_avail= nds03_read_avail, +}; + +/* === buffer setup === */ +static void nds03_enable_work(struct work_struct *work) +{ + struct nds03_iio_dev *iio = container_of(work, struct nds03_iio_dev, enable_work); + struct nds03_context *ctx = iio->ctx; + NDS03_Dev_t *dev = &ctx->g_nds03_device; + int ret; + + mutex_lock(&ctx->work_mutex); + if (iio->enabled) + goto out; + + schedule_delayed_work(&ctx->dwork, + msecs_to_jiffies(atomic_read(&ctx->poll_delay_ms))); + atomic_set(&ctx->is_meas, 1); + ret = nds03_sensor_init(ctx); + if(ret != 0) { + dev_err(&ctx->client->dev, "nds03 sensor init failed %d\n", ret); + goto out; + } + ret = NDS03_StartContinuousMeasurement(dev); + if (ret) { + dev_err(&ctx->client->dev, "StartContinuous fail %d\n", ret); + goto out; + } + iio->enabled = true; + dev_info(&ctx->client->dev, "NDS03 sensor started\n"); + goto out; + +out: + mutex_unlock(&ctx->work_mutex); +} + +static void nds03_disable_work(struct work_struct *work) +{ + struct nds03_iio_dev *iio = container_of(work, struct nds03_iio_dev, disable_work); + struct nds03_context *ctx = iio->ctx; + NDS03_Dev_t *dev = &ctx->g_nds03_device; + + mutex_lock(&ctx->work_mutex); + if (!iio->enabled) + goto out; + + atomic_set(&ctx->is_meas, 0); + NDS03_StopContinuousMeasurement(dev); + iio->enabled = false; + dev_info(&ctx->client->dev, "NDS03 sensor stopped\n"); +out: + mutex_unlock(&ctx->work_mutex); +} + +static int nds03_buffer_preenable(struct iio_dev *indio_dev) +{ + struct nds03_iio_dev *iio = iio_device_get_drvdata(indio_dev); + + schedule_work(&iio->enable_work); + return 0; +} + +static int nds03_buffer_predisable(struct iio_dev *indio_dev) +{ + struct nds03_iio_dev *iio = iio_device_get_drvdata(indio_dev); + + schedule_work(&iio->disable_work); + return 0; +} + +static const struct iio_buffer_setup_ops nds03_buffer_setup_ops = { + .preenable = nds03_buffer_preenable, + .predisable = nds03_buffer_predisable, +}; + +int nds03_iio_init(struct nds03_context *ctx) +{ + struct device *dev = &ctx->client->dev; + struct nds03_iio_dev *iio; + int ret; + + iio = devm_kzalloc(dev, sizeof(*iio), GFP_KERNEL); + if (!iio) { + nds03_errmsg("devm_kzalloc error\n"); + return -ENOMEM; + } + + iio->indio_dev = devm_iio_device_alloc(dev, 0); + if (!iio->indio_dev) { + nds03_errmsg("devm_iio_device_alloc error\n"); + return -ENOMEM; + } + + iio->ctx = ctx; + iio->enabled = false; + INIT_WORK(&iio->enable_work, nds03_enable_work); + INIT_WORK(&iio->disable_work, nds03_disable_work); + + iio->indio_dev->name = "nds03"; + iio->indio_dev->channels = nds03_channels; + iio->indio_dev->num_channels = ARRAY_SIZE(nds03_channels); + iio->indio_dev->info = &nds03_iio_info; + iio->indio_dev->modes = INDIO_DIRECT_MODE | INDIO_BUFFER_SOFTWARE; + iio_device_set_drvdata(iio->indio_dev, iio); + + /* kfifo buffer + setup_ops */ + ret = devm_iio_kfifo_buffer_setup(dev, iio->indio_dev, &nds03_buffer_setup_ops); + if (ret) + return ret; + + ret = devm_iio_device_register(dev, iio->indio_dev); + if (ret) + return ret; + + ctx->iio = iio; + + return 0; +} +EXPORT_SYMBOL_GPL(nds03_iio_init); + +void nds03_iio_remove(struct nds03_context *ctx) +{ + return; +} +EXPORT_SYMBOL_GPL(nds03_iio_remove); + +void nds03_iio_push_data(struct nds03_context *ctx, uint16_t distance_mm) +{ + struct nds03_iio_dev *iio = ctx->iio; + struct nds03_scan scan; + + if (!iio || !iio->enabled) + return; + + scan.distance = distance_mm; + if (iio_buffer_enabled(iio->indio_dev)) + iio_push_to_buffers_with_timestamp(iio->indio_dev, &scan, + ktime_get_boottime_ns()); +} +EXPORT_SYMBOL_GPL(nds03_iio_push_data); diff --git a/drivers/iio/proximity/nds03/nds03_iio.h b/drivers/iio/proximity/nds03/nds03_iio.h new file mode 100644 index 000000000000..9f17533d68a2 --- /dev/null +++ b/drivers/iio/proximity/nds03/nds03_iio.h @@ -0,0 +1,31 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef __NDS03_IIO_H +#define __NDS03_IIO_H + +#include +#include +#include + +struct nds03_iio_dev { + struct iio_dev *indio_dev; + struct nds03_context *ctx; + bool enabled; + struct work_struct enable_work; + struct work_struct disable_work; +}; + +enum nds03_iio_chan { + NDS03_IIO_CHAN_DISTANCE, + NDS03_IIO_CHAN_TIMESTAMP, +}; + +struct nds03_scan { + __le16 distance; + s64 ts; +}; + +int nds03_iio_init(struct nds03_context *ctx); +void nds03_iio_remove(struct nds03_context *ctx); +void nds03_iio_push_data(struct nds03_context *ctx, uint16_t distance_mm); + +#endif diff --git a/drivers/iio/proximity/nds03/nds03_module.c b/drivers/iio/proximity/nds03/nds03_module.c new file mode 100644 index 000000000000..4025ca087922 --- /dev/null +++ b/drivers/iio/proximity/nds03/nds03_module.c @@ -0,0 +1,674 @@ + +/*! + @file nds03_module.c + @brief + @author lull + @date 2025-06 + @copyright Copyright (c) 2025 Shenzhen Nephotonics Semiconductor Technology Co., Ltd. + @license BSD 3-Clause License + This file is part of the Nephotonics sensor SDK. + It is licensed under the BSD 3-Clause License. + A copy of the license can be found in the project root directory, in the file named LICENSE. + */ +#include "nds03.h" +#include "nds03_iio.h" + +/* Set default value to 1 to allow to see module insertion debug messages */ +int nds03_enable_debug = 0; + +static inline NDS03_Platform_t *to_nds03_platform(struct nds03_context *ctx) +{ + return &ctx->g_nds03_device.platform; +} +static inline NDS03_Dev_t * to_nds03_dev(struct nds03_context *ctx) +{ + return &ctx->g_nds03_device; +} + +int nds03_interrupt_config(NDS03_Dev_t *pNxDevice, uint8_t is_open) +{ + int8_t retval = 0; + + if (is_open) { + retval |= NDS03_SetGpio1Config(pNxDevice, + NDS03_GPIO1_NEW_MEASURE_READY, NDS03_GPIO1_POLARITY_LOW); + /* 连续模式开启测量 */ + retval |= NDS03_StartContinuousMeasurement(pNxDevice); + } else { + /* 连续模式关闭测量 */ + retval |= NDS03_StopContinuousMeasurement(pNxDevice); + /* 关闭测距中断 */ + retval |= NDS03_SetGpio1Config(pNxDevice, + NDS03_GPIO1_FUNCTIONALITY_OFF, NDS03_GPIO1_POLARITY_LOW); + } + return retval; +} +EXPORT_SYMBOL_GPL(nds03_interrupt_config); + +int nds03_sensor_init(struct nds03_context *ctx) +{ + NDS03_Dev_t *pNxDevice = to_nds03_dev(ctx); + + NDS03_Platform_t *pdev = to_nds03_platform(ctx); + /* 函数指针结构体 */ + + if (NDS03_ERROR_NONE != nds03_platform_init(pdev, ctx->client)) { + nds03_errmsg("nds03_platform init error\n"); + return -1; + } + /* 循环等待设备启动, 若模组或者IIC读写函数有问题则会报错 */ + if (NDS03_ERROR_NONE != NDS03_WaitDeviceBootUp(pNxDevice)) { + nds03_errmsg("NDS03_WaitDeviceBootUp error\r\n"); + return -1; + } + /** 判断是否为NDS03设备 */ + if (NDS03_ERROR_NONE != NDS03_IsNDS03(pNxDevice)) { + nds03_errmsg("The device is not NDS03, please change the device!\n"); + return -2; + } + /* 初始化模组设备 */ + if (NDS03_ERROR_NONE != NDS03_InitDevice(pNxDevice)) { + nds03_errmsg("NDS03_InitDevice error!!\r\n"); + return -3; + } + if (atomic_read(&ctx->meas_mode) == 0) + nds03_interrupt_config(pNxDevice, 1); + else + nds03_interrupt_config(pNxDevice, 0); + + return 0; +} +EXPORT_SYMBOL_GPL(nds03_sensor_init); + +static void printf_ranging_data(NDS03_Dev_t *pNxDevice) +{ + nds03_info("ranging data start:\r\n"); + + nds03_info("dist start:\r\n"); + nds03_info( + "%d %d %d %d\r\n", + pNxDevice->ranging_data[0].depth, pNxDevice->ranging_data[1].depth, + pNxDevice->ranging_data[2].depth, pNxDevice->ranging_data[3].depth); + nds03_info("dist end\r\n"); + + nds03_info("confi start:\r\n"); + nds03_info( + "%d %d %d %d\r\n", + pNxDevice->ranging_data[0].confi, pNxDevice->ranging_data[1].confi, + pNxDevice->ranging_data[2].confi, pNxDevice->ranging_data[3].confi); + nds03_info("confi end\r\n"); + + nds03_info("count start:\r\n"); + nds03_info( + "%d %d %d %d\r\n", + pNxDevice->ranging_data[0].count, pNxDevice->ranging_data[1].count, + pNxDevice->ranging_data[2].count, pNxDevice->ranging_data[3].count); + nds03_info("count end\r\n"); + + nds03_info("crate start:\r\n"); + nds03_info( + "%d %d %d %d\r\n", + pNxDevice->ranging_data[0].crate, pNxDevice->ranging_data[1].crate, + pNxDevice->ranging_data[2].crate, pNxDevice->ranging_data[3].crate); + nds03_info("crate end\r\n"); + + nds03_info("ranging data end\r\n"); +} + +static int32_t nds03_make_measure(struct nds03_context *ctx) +{ + int32_t ret = 0; + NDS03_Dev_t *pNxDevice = &ctx->g_nds03_device; + + mutex_lock(&ctx->work_mutex); + /* 获取测量数据 */ + if (atomic_read(&ctx->meas_mode)) + ret = NDS03_GetSingleRangingData(pNxDevice); + else + ret = NDS03_GetInterruptRangingData(pNxDevice); + + if (ret >= 0 && nds03_enable_debug) + printf_ranging_data(pNxDevice); + + mutex_unlock(&ctx->work_mutex); + + return ret; +} + +static int __ctrl_tof_start(struct nds03_context * ctx) +{ + schedule_delayed_work(&ctx->dwork, + msecs_to_jiffies(atomic_read(&ctx->poll_delay_ms))); + atomic_set(&ctx->is_meas, 1); + + return 0; +} + +static int __ctrl_tof_stop(struct nds03_context * ctx) +{ + atomic_set(&ctx->is_meas, 0); + return 0; +} + +static int __ctrl_tof_reset(struct nds03_context * ctx) +{ + int ret = 0; + + __ctrl_tof_stop(ctx); + mutex_lock(&ctx->work_mutex); + ret = nds03_sensor_init(ctx); + if (ret != 0) + nds03_errmsg("nds03 sensor init failed\n"); + + mutex_unlock(&ctx->work_mutex); + return ret; +} + +static int32_t tof_offset_calib(struct nds03_context *ctx, uint16_t calib_dist) +{ + int32_t i, cnt = 20; + int32_t depth_sum, depth_aver; + NDS03_Dev_t *pNxDevice = to_nds03_dev(ctx); + /* 将设备处于500mm处 */ + NDS03_StopContinuousMeasurement(pNxDevice); + msleep(100); + /* 串扰标定 */ + ctx->calib_result = NDS03_XtalkCalibration(pNxDevice); + if (NDS03_ERROR_NONE != ctx->calib_result) { + nds03_info("Xtalk calib error: %d\n", ctx->calib_result); + return -1; + } + /* Offset标定 */ + ctx->calib_result = NDS03_OffsetCalibrationAtDepth(pNxDevice, calib_dist); + if(NDS03_ERROR_NONE != ctx->calib_result) { + nds03_info("Offset calib error: %d\n", ctx->calib_result); + return -1; + } + /* 获取平均值 */ + NDS03_GetSingleRangingData(pNxDevice); + NDS03_GetSingleRangingData(pNxDevice); + depth_sum = 0; + for (i = 0; i < cnt; i++) { + if (NDS03_ERROR_NONE != NDS03_GetSingleRangingData(pNxDevice)) { + nds03_info("NDS03_GetSingleRangingData error!!\r\n"); + return -1; + } + depth_sum = depth_sum + (int32_t)(uint32_t)pNxDevice->ranging_data[0].depth; + } + depth_aver = depth_sum / cnt; + if (depth_aver < (calib_dist - 20) || depth_aver > (calib_dist + 20)) { + ctx->calib_result = NDS03_ERROR_RANGING; + nds03_info("NDS03 calibration fail!!\r\n"); + return -1; + } + nds03_info("NDS03 calibration success\r\n"); + return 0; +} + +static void report_meas_event(struct nds03_context * ctx) +{ + int retval = 0; + + retval = nds03_make_measure(ctx); + if (retval < 0) + return; + + uint16_t distance = ctx->g_nds03_device.ranging_data[0].depth; + nds03_iio_push_data(ctx, distance); +} + +static irqreturn_t tof_irq_handler_i2c(int vec, void *info) +{ + struct nds03_context *ctx = (struct nds03_context *)info; + bool is_meas = atomic_read(&ctx->is_meas); + + if (ctx->irq == vec && is_meas) + schedule_work(&ctx->irq_work); + + return IRQ_HANDLED; +} + +static void nds03_work_handler(struct work_struct *work) +{ + struct nds03_context *ctx = container_of(work, struct nds03_context, dwork.work); + + if (atomic_read(&ctx->meas_mode) && atomic_read(&ctx->is_meas)) { + nds03_make_measure(ctx); + schedule_delayed_work(&ctx->dwork, + msecs_to_jiffies(atomic_read(&ctx->poll_delay_ms))); + report_meas_event(ctx); + } +} + +static void nds03_measure_irq_work(struct work_struct *work) +{ + struct nds03_context *ctx = container_of(work, struct nds03_context, irq_work); + + report_meas_event(ctx); +} + +static ssize_t nds03_show_is_meas(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct nds03_context *ctx = dev_get_drvdata(dev); + return snprintf(buf, 10, "%d\n", atomic_read(&ctx->is_meas)); +} + +static ssize_t nds03_store_is_meas(struct device *dev, + struct device_attribute *attr, const char *buf,size_t count) +{ + struct nds03_context *ctx = dev_get_drvdata(dev); + int ret = count; + + switch (buf[0]) { + case '0': + __ctrl_tof_stop(ctx); + break; + case '1': + __ctrl_tof_start(ctx); + break; + default: + nds03_warnmsg("Invalid value\n"); + ret = -EINVAL; + break; + } + return ret ; +} + +static DEVICE_ATTR(is_meas, 0660, nds03_show_is_meas, nds03_store_is_meas); + +static ssize_t nds03_show_poll_delay_ms(struct device *dev, + struct device_attribute *attr, char *buf) +{ + uint32_t poll_ms; + struct nds03_context *ctx = dev_get_drvdata(dev); + + poll_ms = atomic_read(&ctx->poll_delay_ms); + return snprintf(buf, 10, "%d\n", poll_ms); +} + +static ssize_t nds03_store_poll_delay_ms(struct device *dev, + struct device_attribute *attr, const char *buf,size_t count) +{ + struct nds03_context *ctx = dev_get_drvdata(dev); + int ret; + unsigned long delay_ms; + + ret = kstrtoul(buf, 10, &delay_ms); + if(ret < 0) { + nds03_warnmsg("Invalid input ctx\n"); + goto store_err; + } + atomic_set(&ctx->poll_delay_ms, delay_ms); + nds03_dbgmsg("Poll delay %lu ms\n", delay_ms); +store_err: + return ret < 0 ? -EINVAL : count; +} + +static DEVICE_ATTR(meas_delay_ms, 0660, nds03_show_poll_delay_ms, nds03_store_poll_delay_ms); + +static ssize_t nds03_show_meas_mode(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct nds03_context *ctx = dev_get_drvdata(dev); + + return snprintf(buf, 10, "%d\n",atomic_read(&ctx->meas_mode)); +} + +static ssize_t nds03_store_meas_mode(struct device *dev, + struct device_attribute *attr, const char *buf,size_t count) +{ + struct nds03_context *ctx = dev_get_drvdata(dev); + NDS03_Dev_t *pNxDevice = to_nds03_dev(ctx); + int ret = count; + + mutex_lock(&ctx->work_mutex); + switch (buf[0]) { + case '0': + if(ctx->irq < 0){ + nds03_warnmsg("No support Interrupt\n"); + ret = -EINVAL; + } else { + atomic_set(&ctx->meas_mode, 0); + nds03_interrupt_config(pNxDevice, 1); + nds03_dbgmsg("Enter Interrupt Mode\n"); + } + break; + case '1': + atomic_set(&ctx->meas_mode, 1); + nds03_interrupt_config(pNxDevice, 0); + nds03_dbgmsg("Enter Poll Mode\n"); + break; + default: + nds03_warnmsg("Invalid value\n"); + ret = -EINVAL; + break; + } + mutex_unlock(&ctx->work_mutex); + return ret ; +} +static DEVICE_ATTR(meas_mode, 0660, nds03_show_meas_mode, nds03_store_meas_mode); + +static ssize_t nds03_store_tof_reset(struct device *dev, + struct device_attribute *attr, const char *buf,size_t count) +{ + struct nds03_context *ctx = dev_get_drvdata(dev); + int ret = 0; + + if(buf[0] == '1') + ret = __ctrl_tof_reset(ctx); + + return ret < 0 ? ret : count; +} + +static DEVICE_ATTR(tof_reset, 0660, NULL, nds03_store_tof_reset); + +static ssize_t nds03_show_tof_calib(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct nds03_context *ctx = dev_get_drvdata(dev); + + return snprintf(buf, 10, "%d\n",ctx->calib_result); +} + +static ssize_t nds03_store_tof_calib(struct device *dev, + struct device_attribute *attr, const char *buf,size_t count) +{ + struct nds03_context *ctx = dev_get_drvdata(dev); + int ret; + unsigned long calib_dis; + + mutex_lock(&ctx->work_mutex); + ret = kstrtoul(buf, 10, &calib_dis); + if(ret < 0) { + nds03_warnmsg("Invalid input ctx\n"); + ret = -EPERM; + goto store_err; + } + nds03_info("offset calib distance: %ld mm\n", calib_dis); + ret = tof_offset_calib(ctx, calib_dis); + if (nds03_sensor_init(ctx) != 0) + nds03_errmsg("nds03 sensor init failed\n"); + +store_err: + mutex_unlock(&ctx->work_mutex); + return ret < 0 ? ret : count; +} + +static DEVICE_ATTR(tof_calib, 0660, nds03_show_tof_calib, nds03_store_tof_calib); + +static ssize_t nds03_show_enable_debug(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return snprintf(buf, 10, "%d\n", nds03_enable_debug); +} + +static ssize_t nds03_store_enable_debug(struct device *dev, + struct device_attribute *attr, const char *buf,size_t count) +{ + struct nds03_context *ctx = dev_get_drvdata(dev); + int32_t ret = 0; + + mutex_lock(&ctx->work_mutex); + switch (buf[0]) { + case '0': + nds03_enable_debug = 0; + nds03_info("close nds03 debug\n"); + break; + case '1': + nds03_enable_debug = 1; + nds03_info("open nds03 debug\n"); + break; + default: + nds03_warnmsg("Invalid value\n"); + ret = -EINVAL; + break; + } + mutex_unlock(&ctx->work_mutex); + return ret < 0 ? ret : count; +} + +static DEVICE_ATTR(enable_debug, 0660, nds03_show_enable_debug, nds03_store_enable_debug); + +static ssize_t nds03_store_tof_pulsenum(struct device *dev, + struct device_attribute *attr, const char *buf,size_t count) +{ + int ret; + unsigned long pulsenum; + struct nds03_context *ctx = dev_get_drvdata(dev); + NDS03_Dev_t *pdev = to_nds03_dev(ctx); + + ret = kstrtoul(buf, 10, &pulsenum); + if (ret < 0) { + nds03_errmsg("Invalid input ctx\n"); + return -EPERM; + } + mutex_lock(&ctx->work_mutex); + ret = NDS03_SetPulseNum(pdev, pulsenum); + mutex_unlock(&ctx->work_mutex); + nds03_info("set tof pulsenum: %ld, ret: %d\n", pulsenum, ret); + return ret < 0 ? ret : count; +} + +static DEVICE_ATTR(tof_pulsenum, 0660, NULL, nds03_store_tof_pulsenum); + +static ssize_t nds03_show_tof_xtalk(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int ret, count; + uint16_t xtalk_value; + struct nds03_context *ctx = dev_get_drvdata(dev); + NDS03_Dev_t *pdev = to_nds03_dev(ctx); + + mutex_lock(&ctx->work_mutex); + ret = NDS03_GetXTalkValue(pdev, &xtalk_value); + if (ret < 0) + nds03_errmsg("get tof xtalk_value error\n"); + mutex_unlock(&ctx->work_mutex); + count = snprintf(buf, 10, "%d\n",xtalk_value); + return ret < 0 ? ret : count; +} + +static DEVICE_ATTR(tof_xtalk, 0660, nds03_show_tof_xtalk, NULL); + +static ssize_t nds03_store_xtalk_calibration(struct device *dev, + struct device_attribute *attr, const char *buf,size_t count) +{ + int32_t ret = 0; + struct nds03_context *ctx = dev_get_drvdata(dev); + NDS03_Dev_t *pdev = to_nds03_dev(ctx); + + if (sysfs_streq(buf, "1") || sysfs_streq(buf, "on") || + sysfs_streq(buf, "start")) { + mutex_lock(&ctx->work_mutex); + NDS03_StopContinuousMeasurement(pdev); + ret = NDS03_XtalkCalibration(pdev); + if (nds03_sensor_init(ctx) != 0) + nds03_errmsg("nds03 sensor init failed\n"); + + mutex_unlock(&ctx->work_mutex); + if(ret < 0) { + nds03_errmsg("NDS03_XtalkCalibration error, ret = %d\n", ret); + return -EIO; + } + return count; + } else { + return -EINVAL; + } +} + +static DEVICE_ATTR(xtalk_calibration, 0660, NULL, nds03_store_xtalk_calibration); + +static ssize_t nds03_store_offset_calibration(struct device *dev, + struct device_attribute *attr, const char *buf,size_t count) +{ + int ret; + struct nds03_context *ctx = dev_get_drvdata(dev); + NDS03_Dev_t *pdev = to_nds03_dev(ctx); + int32_t calib_depth_mm_tmp = 0; + + ret = kstrtoint(buf, 10, &calib_depth_mm_tmp); + if (ret) + return -EINVAL; + + mutex_lock(&ctx->work_mutex); + NDS03_StopContinuousMeasurement(pdev); + ret = NDS03_OffsetCalibrationAtDepth(pdev, calib_depth_mm_tmp); + if (nds03_sensor_init(ctx) != 0) + nds03_errmsg("nds03 sensor init failed\n"); + + mutex_unlock(&ctx->work_mutex); + if (ret < 0) { + nds03_errmsg("NDS03_OffsetCalibrationAtDepth error, ret = %d\n", ret); + return -EIO; + } + + return count; +} + +static DEVICE_ATTR(offset_calibration, 0660, NULL, nds03_store_offset_calibration); + +static struct attribute *nds03_attributes[] = { + &dev_attr_is_meas.attr, + &dev_attr_meas_delay_ms.attr, + &dev_attr_meas_mode.attr, + &dev_attr_enable_debug.attr, + &dev_attr_tof_reset.attr, + &dev_attr_tof_calib.attr, + &dev_attr_tof_pulsenum.attr, + &dev_attr_tof_xtalk.attr, + &dev_attr_xtalk_calibration.attr, + &dev_attr_offset_calibration.attr, + NULL +}; + +static const struct attribute_group nds03_sysfs_groups = { + .attrs = nds03_attributes, +}; + +static void nds03_parse_device_tree(struct nds03_context *ctx) +{ + int32_t ret; + NDS03_Platform_t *pdev = to_nds03_platform(ctx); + + /* Initialize xshut gpio */ + pdev->xshut_gpio = devm_gpiod_get_optional(&ctx->client->dev, "xshut", GPIOD_OUT_HIGH); + if (IS_ERR(pdev->xshut_gpio)) { + ret = PTR_ERR(pdev->xshut_gpio); + nds03_warnmsg( "no xshut pin available, error = %d\n", ret); + return; + } else { + nds03_dbgmsg("get xshut pin success\n"); + } + + /* Initialize irq gpio*/ + atomic_set(&ctx->meas_mode, 1); //Default to polling mode + ctx->irq = -1; + pdev->intr_gpio = devm_gpiod_get_optional(&ctx->client->dev, "intr", GPIOD_IN); + if (IS_ERR(pdev->intr_gpio)) { + ret = PTR_ERR(pdev->intr_gpio); + nds03_warnmsg( "no intr pin available, error = %d\n", ret); + return; + } + nds03_dbgmsg("get intr pin success\n"); + ctx->irq = ctx->client->irq; + if (ctx->irq) { + unsigned long default_trigger = irqd_get_trigger_type(irq_get_irq_data(ctx->irq)); + ret = devm_request_threaded_irq(&ctx->client->dev, + ctx->irq, NULL, + tof_irq_handler_i2c, + default_trigger|IRQF_ONESHOT, + "nds03_interrupt", + (void *)ctx); + if (ret) { + nds03_errmsg("fail to req threaded irq rc=%d\n", ret); + } else { + nds03_info( + "request irq success, irq mode use, irq num: %d, type: %lu", + ctx->irq, default_trigger); + atomic_set(&ctx->meas_mode, 0); //Configure in interrupt mode + } + } else { + void *poll_interval_dt = NULL; + uint32_t delay_ms; + nds03_info("no irq number specified, polling mode is used\n"); + poll_interval_dt = (void *)of_get_property(ctx->client->dev.of_node, + "nds03_poll_interval", + NULL); + delay_ms = poll_interval_dt ? be32_to_cpup(poll_interval_dt) : 0; + + nds03_dbgmsg("poll delay ms:%d\n", delay_ms); + + atomic_set(&ctx->poll_delay_ms, delay_ms); + } +} + +int nds03_common_probe(struct nds03_context * ctx) +{ + int ret = 0; + u32 i2c_freq = 0; + // struct input_dev *input; + + /* Initialize mutex */ + mutex_init(&ctx->work_mutex); + + /* init work handler */ + INIT_DELAYED_WORK(&ctx->dwork, nds03_work_handler); + + INIT_WORK(&ctx->irq_work, nds03_measure_irq_work); + + atomic_set(&ctx->is_meas, 0); + + /* Parse the device tree for NDS03 sensor configuration. */ + nds03_parse_device_tree(ctx); + of_property_read_u32(ctx->client->adapter->dev.of_node, "clock-frequency", &i2c_freq); + pr_info("I2C bus number is %d, bus speed: %u Hz\n", ctx->client->adapter->nr, i2c_freq); + + ret = nds03_iio_init(ctx); + if (ret) { + nds03_errmsg("IIO init failed: %d\n", ret); + goto err_iio; + } + ctx->fd_open_count = 0; + + nds03_dbgmsg("create sysfs group successfully\n"); + + /* Initialize nds03 sensor */ + ret = nds03_sensor_init(ctx); + if (ret != 0 ) { + nds03_errmsg("Failed to init nds03 sensor error:%d\n", ret); + goto err_iio; + } + nds03_dbgmsg("init nds03 sensor successfully\n"); + + ret = sysfs_create_group(&ctx->client->dev.kobj, &nds03_sysfs_groups); + if (ret) { + nds03_errmsg("Failed to create sysfs group error:%d\n", ret); + goto exit_err; + } + ctx->remove_flag = false; + nds03_dbgmsg("register chardev successfully\n"); + + nds03_info("nds03 module registered successfully\n"); + nds03_info( "NDS03 Driver version: %s \n", DRIVER_VERSION); + return 0; + +err_iio: + nds03_iio_remove(ctx); + +exit_err: + return ret; +} +EXPORT_SYMBOL_GPL(nds03_common_probe); + +int nds03_common_remove(struct nds03_context * ctx) +{ + nds03_dbgmsg("Enter %s \n", __FUNCTION__); + cancel_delayed_work(&ctx->dwork); + ctx->remove_flag = true; + sysfs_remove_group(&ctx->client->dev.kobj, &nds03_sysfs_groups); + nds03_iio_remove(ctx); + + return 0; +} +EXPORT_SYMBOL_GPL(nds03_common_remove); diff --git a/drivers/iio/proximity/nds03/nds03_module_i2c.c b/drivers/iio/proximity/nds03/nds03_module_i2c.c new file mode 100644 index 000000000000..7ec4288479ca --- /dev/null +++ b/drivers/iio/proximity/nds03/nds03_module_i2c.c @@ -0,0 +1,99 @@ +/*! + @file nds03_module_i2c.c + @brief + @author lull + @date 2025-06 + @copyright Copyright (c) 2025 Shenzhen Nephotonics Semiconductor Technology Co., Ltd. + @license BSD 3-Clause License + This file is part of the Nephotonics sensor SDK. + It is licensed under the BSD 3-Clause License. + A copy of the license can be found in the project root directory, in the file named LICENSE. + */ +#include "nds03.h" +#include "nds03_platform.h" + +struct nds03_context *nds03_context_obj = NULL; + +// int nds03_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id) +static int nds03_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id) +{ + int ret = 0; + struct device *dev = &client->dev; + struct nds03_context * ctx = NULL; + + ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL); + if(IS_ERR(ctx)) { + nds03_errmsg("nds03_data memory allocation failed\n"); + ret = -ENOMEM; + goto module_reg_err; + } + + nds03_context_obj = ctx; + ctx->client = client; + + ret = nds03_common_probe(ctx); + if(ret != 0) { + nds03_errmsg("Failed to register nds03 module: %d\n", ret); + goto module_reg_err; + } + i2c_set_clientdata(client, ctx); + return 0; + +module_reg_err: + return ret; +} + +static void nds03_i2c_remove(struct i2c_client *client) +{ + struct nds03_context * ctx = i2c_get_clientdata(client); + nds03_common_remove(ctx); + // return 0; +} + +static const struct i2c_device_id tof_nds03_id[] = { + {TOF_NDS03_DRV_NAME, 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, tof_nds03_id); + +static const struct of_device_id tof_nds03_dt_match[] = { + { .compatible = "nx,"TOF_NDS03_DRV_NAME, }, + { } +}; +MODULE_DEVICE_TABLE(of, tof_nds03_dt_match); + +static struct i2c_driver tof_nds03_driver = { + .driver = { + .name = TOF_NDS03_DRV_NAME, + .owner = THIS_MODULE, + .of_match_table = tof_nds03_dt_match, + }, + .probe = nds03_i2c_probe, + .remove = nds03_i2c_remove, + .id_table = tof_nds03_id, + +}; + +static int __init tof_nds03_init_i2c(void) +{ + int ret = 0; + + nds03_dbgmsg("Enter\n"); + ret = i2c_add_driver(&tof_nds03_driver); + if (ret) + nds03_errmsg("%d erro ret:%d\n", __LINE__, ret); + return ret; +} + +static void __exit tof_nds03_exit_i2c(void ) +{ + nds03_dbgmsg("Exit\n"); + i2c_del_driver(&tof_nds03_driver); +} + +module_init(tof_nds03_init_i2c); +module_exit(tof_nds03_exit_i2c); + +MODULE_DESCRIPTION("Time-of-Flight sensor driver"); +MODULE_LICENSE("GPL"); +MODULE_VERSION(DRIVER_VERSION); diff --git a/drivers/iio/proximity/nds03/nds03_platform.c b/drivers/iio/proximity/nds03/nds03_platform.c new file mode 100644 index 000000000000..e3552fe7e7e0 --- /dev/null +++ b/drivers/iio/proximity/nds03/nds03_platform.c @@ -0,0 +1,117 @@ +/*! + @file nds03_platform.c + @brief + @author lull + @date 2025-06 + @copyright Copyright (c) 2025 Shenzhen Nephotonics Semiconductor Technology Co., Ltd. + @license BSD 3-Clause License + This file is part of the Nephotonics sensor SDK. + It is licensed under the BSD 3-Clause License. + A copy of the license can be found in the project root directory, in the file named LICENSE. + */ +#include "nds03_platform.h" + +int8_t nds03_platform_init(NDS03_Platform_t *pdev, void * client) +{ + pdev->client = (struct i2c_client *)client; + pdev->i2c_dev_addr = 0X5C; + + return 0; +} + +int8_t nds03_platform_uninit(NDS03_Platform_t *pdev, void * param) +{ + return 0; +} + +int8_t nds03_i2c_read_nbytes(NDS03_Platform_t *pDev, uint8_t i2c_raddr, uint8_t *i2c_rdata, uint16_t len) +{ + int8_t ret; + struct i2c_msg i2c_message[2]; + uint8_t i2c_buf[256]; + + i2c_buf[0] = i2c_raddr; + i2c_message[0].addr = pDev->i2c_dev_addr; + i2c_message[0].buf = i2c_buf; + i2c_message[0].len = 1; + i2c_message[0].flags = 0 ; //| I2C_M_STOP;//I2C_M_STOP; + + i2c_message[1].addr = pDev->i2c_dev_addr; + i2c_message[1].buf = i2c_rdata; + i2c_message[1].len = len; + i2c_message[1].flags = I2C_M_RD; + ret = i2c_transfer(pDev->client->adapter, i2c_message, 2); + if (ret != 2) { + pr_err("NDS03: i2c read error, i2c_raddr: 0x%x, reg: 0x%x, ret: %d", pDev->i2c_dev_addr, i2c_raddr, ret); + return -EIO; + } + return 0; + +} + +int8_t nds03_i2c_write_nbytes(NDS03_Platform_t *pDev, uint8_t i2c_waddr, uint8_t *i2c_wdata, uint16_t len) +{ + int32_t ret; + struct i2c_msg i2c_message; + //For user implement + uint8_t i2c_buf[256]; + + memcpy(&i2c_buf[1], i2c_wdata, len); + i2c_buf[0] = i2c_waddr; + + i2c_message.addr = pDev->i2c_dev_addr; + i2c_message.buf = i2c_buf; + i2c_message.len = len + 1; + i2c_message.flags = 0; + ret = i2c_transfer(pDev->client->adapter, &i2c_message, 1); + if (ret != 1) { + pr_err("NDS03: i2c write error, i2c_waddr: 0x%x, reg: 0x%x, ret: %d", pDev->i2c_dev_addr, i2c_waddr, ret); + return -EIO; + } + return 0; + +} + +int8_t nds03_delay_10us(NDS03_Platform_t *pDev, uint32_t wait_10us) +{ + wait_10us *= 10; + if (wait_10us < 10) + udelay(wait_10us); + else if (wait_10us < 20000) + usleep_range(wait_10us, wait_10us + 1); + else + msleep(wait_10us / 1000); + return 0; +} + +int8_t nds03_delay_1ms(NDS03_Platform_t *pDev, uint32_t wait_ms) +{ + nds03_delay_10us(pDev, wait_ms * 100); + return 0; +} + +int8_t nds03_set_xshut_pin_level(NDS03_Platform_t *pDev, int8_t level) +{ + if (pDev->xshut_gpio == NULL) { + pr_err("xshut_gpiod is not init , not setting xshut\n"); + return -1; + } + gpiod_set_value(pDev->xshut_gpio, level); + // pr_info("xshut set to %d\n", level); + return 0; +} + +int8_t nds03_i2c_get_clock_frequency(NDS03_Platform_t *pDev, uint32_t *clock_frequency) +{ + return 0; +} + +int8_t nds03_i2c_set_clock_frequency(NDS03_Platform_t *pDev, uint32_t clock_frequency) +{ + return 0; +} + +int8_t nds03_get_system_clk_ms(NDS03_Platform_t *pDev, int32_t *time_ms) +{ + return 0; +} diff --git a/drivers/iio/proximity/nds03/nds03_platform.h b/drivers/iio/proximity/nds03/nds03_platform.h new file mode 100644 index 000000000000..56d68d1ff057 --- /dev/null +++ b/drivers/iio/proximity/nds03/nds03_platform.h @@ -0,0 +1,137 @@ +/*! + @file nds03_platform.h + @brief + @author lull + @date 2025-06 + @copyright Copyright (c) 2025 Shenzhen Nephotonics Semiconductor Technology Co., Ltd. + @license BSD 3-Clause License + This file is part of the Nephotonics sensor SDK. + It is licensed under the BSD 3-Clause License. + A copy of the license can be found in the project root directory, in the file named LICENSE. + */ +#ifndef __NDS03_PLATFORM__H__ +#define __NDS03_PLATFORM__H__ + +#include "nds03_stdint.h" +#include +#include +#include +#include +/** + * @struct NDS03_Platform_t + * + * @brief NDS03平台相关定义 \n + * 定义i2c地址等,注意必须定义i2c地址 + */ +typedef struct{ + //文件描述符 + int fd; + /** 用户不可更改以下变量 @{ */ + uint8_t i2c_dev_addr; // i2c设备地址 + /** @} */ + /** 用户可根据需要添加变量 */ + struct i2c_client *client; + ////// /* nds03 device io */ + struct gpio_desc *intr_gpio; + /*!< xsdn reset (low active) gpio number to device */ + struct gpio_desc *xshut_gpio; + +} NDS03_Platform_t; + +/** + * @brief NDS03平台初始化 + * + * @param pDev 平台设备指针 + * @param void* 拓展指针 + * @return int8_t + * @retval 0:成功, 其他:失败 + */ +int8_t nds03_platform_init(NDS03_Platform_t *pdev, void *); + +/** + * @brief NDS03平台释放 + * + * @param pDev 平台设备指针 + * @param void* 拓展指针 + * @return int8_t + * @retval 0:成功, 其他:失败 + */ +int8_t nds03_platform_uninit(NDS03_Platform_t *pdev, void *); + +/** + * @brief I2C读一个字节 + * + * @param pDev 平台设备指针 + * @param i2c_raddr 读寄存器地址 + * @param i2c_rdata 读数据 + * @return int8_t + * @retval 0:成功, 其他:失败 + */ +int8_t nds03_i2c_read_nbytes(NDS03_Platform_t *pDev, uint8_t i2c_raddr, uint8_t *i2c_rdata, uint16_t len); + +/** + * @brief I2C写一个字节 + * + * @param pDev 平台设备指针 + * @param i2c_waddr 写寄存器地址 + * @param i2c_wdata 写数据 + * @return int8_t + * @retval 0:成功, 其他:失败 + */ +int8_t nds03_i2c_write_nbytes(NDS03_Platform_t *pDev, uint8_t i2c_waddr, uint8_t *i2c_wdata, uint16_t len); + +/** + * @brief 延时wait_ms毫秒 + * + * @param pDev 平台设备指针 + * @param wait_ms 输入需要延时时长 + * @return int8_t + * @retval 0:成功, 其他:失败 + */ +int8_t nds03_delay_1ms(NDS03_Platform_t *pDev, uint32_t wait_ms); + +/** + * @brief 延时10*wait_10us微秒 + * + * @param pDev 平台设备指针 + * @param wait_10us 输入需要延时时长 + * @return int8_t + * @retval 0:成功, 其他:失败 + */ +int8_t nds03_delay_10us(NDS03_Platform_t *pDev, uint32_t wait_10us); + +/** + * @brief 设置nds03 xshut引脚电平 + * + * @param pDev 平台设备指针 + * @param level 引脚电平,0为低电平,1为高电平 + * @return int8_t + * @retval 0:成功, 其他:失败 + */ +int8_t nds03_set_xshut_pin_level(NDS03_Platform_t *pDev, int8_t level); + +/*! + @brief NDS03获取当前i2c时钟频率 + @param pDev 平台设备指针 + @param clock_frequency 时钟频率指针 + @return int8_t + */ +int8_t nds03_i2c_get_clock_frequency(NDS03_Platform_t *pDev, uint32_t *clock_frequency); + +/*! + @brief NDS03设置当前i2c时钟频率 + @param pDev 平台设备指针 + @param clock_frequency 时钟频率指针 + @return int8_t + */ +int8_t nds03_i2c_set_clock_frequency(NDS03_Platform_t *pDev, uint32_t clock_frequency); +/*! + @brief 获取当前系统时间,单位ms + @param pDev + @param time_ms + @return int8_t + */ +int8_t nds03_get_system_clk_ms(NDS03_Platform_t *pDev, int32_t *time_ms); + +#endif + diff --git a/drivers/iio/proximity/nds03/nds03_stdint.h b/drivers/iio/proximity/nds03/nds03_stdint.h new file mode 100644 index 000000000000..c4657b0e98cd --- /dev/null +++ b/drivers/iio/proximity/nds03/nds03_stdint.h @@ -0,0 +1,95 @@ + +/** + * @file nds03_stdint.h + * @author tongsheng.tang + * @brief NDS03 platform-specific integer type definitions + * @version 2.x.x + * @date 2025-06 + * + * @copyright Copyright (c) 2025, Nephotonics Information Technology (Hefei) Co., Ltd. + * + * @license BSD 3-Clause License + * This file is part of the NDS03 SDK and is licensed under the BSD 3-Clause License. + * You may obtain a copy of the license in the project root directory, in the file named LICENSE. + * + */ +#ifndef __NDS03_STDINT_H__ +#define __NDS03_STDINT_H__ + +#define PLATFORM_C51 0 +#define PLATFORM_NOT_C51 1 +#define PLATFORM_LINUX_DRIVER 2 +#ifndef NDS03_PLATFORM +#define NDS03_PLATFORM PLATFORM_LINUX_DRIVER +#endif + +#if NDS03_PLATFORM == PLATFORM_NOT_C51 +#include + +#elif NDS03_PLATFORM == PLATFORM_C51 + /* exact-width signed integer types */ + typedef signed char int8_t; + typedef signed int int16_t; + typedef signed long int32_t; + + /* exact-width unsigned integer types */ + typedef unsigned char uint8_t; + typedef unsigned int uint16_t; + typedef unsigned long uint32_t; + + #define __func__ __FILE__ + + /* minimum values of exact-width signed integer types */ + #define INT32_MIN (~0x7fffffff) /* -2147483648 is unsigned */ + + /* maximum values of exact-width signed integer types */ + #define INT32_MAX 2147483647 + + /* maximum values of exact-width unsigned integer types */ + #define UINT32_MAX 4294967295u + + /* 7.18.2.2 */ + + /* minimum values of minimum-width signed integer types */ + #define INT_LEAST32_MIN (~0x7fffffff) + + /* maximum values of minimum-width signed integer types */ + #define INT_LEAST32_MAX 2147483647 + + /* maximum values of minimum-width unsigned integer types */ + #define UINT_LEAST32_MAX 4294967295u + + /* 7.18.2.3 */ + + /* minimum values of fastest minimum-width signed integer types */ + #define INT_FAST32_MIN (~0x7fffffff) + + /* maximum values of fastest minimum-width signed integer types */ + #define INT_FAST32_MAX 2147483647 + + /* maximum values of fastest minimum-width unsigned integer types */ + #define UINT_FAST32_MAX 4294967295u +#elif NDS03_PLATFORM == PLATFORM_LINUX_DRIVER + /* exact-width signed integer types */ +typedef signed char int8_t; +typedef signed short int16_t; +typedef signed int int32_t; + +/* exact-width unsigned integer types */ +typedef unsigned char uint8_t; +typedef unsigned short uint16_t; +typedef unsigned int uint32_t; + +#define __func__ __FILE__ + +/* minimum values of exact-width signed integer types */ +#define INT32_MIN (~0x7fffffff) /* -2147483648 is unsigned */ +/* maximum values of exact-width signed integer types */ +#define INT32_MAX 2147483647 + +/* maximum values of exact-width unsigned integer types */ +#define UINT32_MAX 4294967295u +#endif + +#endif /** __NDS03_STDINT_H__ */ + From 02027a2bbce84ed10e6a0982c7577342bd097c2d Mon Sep 17 00:00:00 2001 From: Sandy Huang Date: Thu, 18 Sep 2025 16:06:48 +0800 Subject: [PATCH 17/40] drm/rockchip: vop2: add SPARSE_SPLIT_SIZE_16x16 afbc format for rk3588 As SPARSE_SPLIT_SIZE_16x16 afbc format each sub block size is 16*8*4=512 Byte, This can make DDR each channel keep balanced. Signed-off-by: Sandy Huang Change-Id: I1aa7a4c6068fec80f144979dca821bf9cc534b6a --- drivers/gpu/drm/rockchip/rockchip_vop2_reg.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/gpu/drm/rockchip/rockchip_vop2_reg.c b/drivers/gpu/drm/rockchip/rockchip_vop2_reg.c index 89952e5d743c..b142e1a3ca2c 100644 --- a/drivers/gpu/drm/rockchip/rockchip_vop2_reg.c +++ b/drivers/gpu/drm/rockchip/rockchip_vop2_reg.c @@ -241,6 +241,11 @@ static const uint64_t format_modifiers_afbc[] = { AFBC_FORMAT_MOD_SPARSE | AFBC_FORMAT_MOD_SPLIT), + /* SPLIT mandates SPARSE */ + DRM_FORMAT_MOD_ARM_AFBC(AFBC_FORMAT_MOD_BLOCK_SIZE_16x16 | + AFBC_FORMAT_MOD_SPARSE | + AFBC_FORMAT_MOD_SPLIT), + DRM_FORMAT_MOD_LINEAR, DRM_FORMAT_MOD_INVALID, }; From 53b5639eb8e98fa34879b8763382ffc79ad04835 Mon Sep 17 00:00:00 2001 From: Yuefu Su Date: Wed, 24 Sep 2025 11:56:34 +0800 Subject: [PATCH 18/40] media: i2c: sc850sl: fix dual pm_runtime_put in stop_stream Signed-off-by: Yuefu Su Change-Id: I9e6c989fb34b90cb4c7a36513ec44eb03071e6e3 --- drivers/media/i2c/sc850sl.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/media/i2c/sc850sl.c b/drivers/media/i2c/sc850sl.c index 2abad1b2d37b..0c7ed5411091 100644 --- a/drivers/media/i2c/sc850sl.c +++ b/drivers/media/i2c/sc850sl.c @@ -1479,7 +1479,6 @@ static int __sc850sl_stop_stream(struct sc850sl *sc850sl) sc850sl->has_init_exp = false; if (sc850sl->is_thunderboot) { sc850sl->is_first_streamoff = true; - pm_runtime_put(&sc850sl->client->dev); } return sc850sl_write_reg(sc850sl->client, SC850SL_REG_CTRL_MODE, SC850SL_REG_VALUE_08BIT, SC850SL_MODE_SW_STANDBY); From dfbbb45bff209a05cc52cb81558142653bbc3b79 Mon Sep 17 00:00:00 2001 From: Liang Chen Date: Sun, 28 Sep 2025 14:59:17 +0800 Subject: [PATCH 19/40] arm64: dts: rockchip: rv1126bj: adjust opp-table for cpu Change-Id: I8b070f128833117196e6309bb6e1a5262807aa60 Signed-off-by: Liang Chen --- arch/arm64/boot/dts/rockchip/rv1126b.dtsi | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/arch/arm64/boot/dts/rockchip/rv1126b.dtsi b/arch/arm64/boot/dts/rockchip/rv1126b.dtsi index 043a37f41ebf..4a9985cc930b 100644 --- a/arch/arm64/boot/dts/rockchip/rv1126b.dtsi +++ b/arch/arm64/boot/dts/rockchip/rv1126b.dtsi @@ -454,18 +454,20 @@ cpu_opp_j_od_1416000000: opp-j-od-1416000000 { opp-supported-hw = <0x04 0xffff>; opp-hz = /bits/ 64 <1416000000>; - opp-microvolt = <925000 925000 1100000>; - opp-microvolt-L0 = <9750000 9750000 1100000>; - opp-microvolt-L1 = <950000 950000 1100000>; + opp-microvolt = <950000 950000 1100000>; + opp-microvolt-L0 = <1025000 1025000 1100000>; + opp-microvolt-L1 = <1000000 1000000 1100000>; + opp-microvolt-L2 = <975000 975000 1100000>; clock-latency-ns = <40000>; status = "disabled"; }; cpu_opp_j_od_1512000000: opp-j-od-1512000000 { opp-supported-hw = <0x04 0xffff>; opp-hz = /bits/ 64 <1512000000>; - opp-microvolt = <950000 950000 1100000>; - opp-microvolt-L0 = <1000000 1000000 1100000>; - opp-microvolt-L1 = <975000 975000 1100000>; + opp-microvolt = <975000 975000 1100000>; + opp-microvolt-L0 = <1050000 1050000 1100000>; + opp-microvolt-L1 = <1025000 1025000 1100000>; + opp-microvolt-L2 = <1000000 1000000 1100000>; clock-latency-ns = <40000>; status = "disabled"; }; From 7235aafc8f78df2051b5429f4514bdd65882ba37 Mon Sep 17 00:00:00 2001 From: Liang Chen Date: Sun, 28 Sep 2025 15:02:00 +0800 Subject: [PATCH 20/40] clk: rockchip: clk-pvtpll: rv1126bj: adjust pvtpll config for cpu Change-Id: I618c129b48fb172f0e7ce4754523a5414b5a8839 Signed-off-by: Liang Chen --- drivers/clk/rockchip/clk-pvtpll.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/drivers/clk/rockchip/clk-pvtpll.c b/drivers/clk/rockchip/clk-pvtpll.c index f0353ecaaabf..be1d7b777c1b 100644 --- a/drivers/clk/rockchip/clk-pvtpll.c +++ b/drivers/clk/rockchip/clk-pvtpll.c @@ -173,14 +173,14 @@ static struct pvtpll_table rv1126b_core_pvtpll_table[] = { static struct pvtpll_table rv1126bj_core_pvtpll_table[] = { /* rate_hz, ring_sel, length */ - ROCKCHIP_PVTPLL_VOLT_SEL(1900000000, 0, 30, 7), - ROCKCHIP_PVTPLL_VOLT_SEL(1850000000, 0, 30, 7), - ROCKCHIP_PVTPLL_VOLT_SEL(1800000000, 0, 30, 7), - ROCKCHIP_PVTPLL_VOLT_SEL(1750000000, 0, 30, 6), - ROCKCHIP_PVTPLL_VOLT_SEL(1700000000, 0, 30, 6), - ROCKCHIP_PVTPLL_VOLT_SEL(1608000000, 0, 30, 5), - ROCKCHIP_PVTPLL_VOLT_SEL(1512000000, 0, 30, 5), - ROCKCHIP_PVTPLL_VOLT_SEL(1416000000, 0, 34, 5), + ROCKCHIP_PVTPLL_VOLT_SEL(1900000000, 0, 32, 7), + ROCKCHIP_PVTPLL_VOLT_SEL(1850000000, 0, 32, 7), + ROCKCHIP_PVTPLL_VOLT_SEL(1800000000, 0, 32, 7), + ROCKCHIP_PVTPLL_VOLT_SEL(1750000000, 0, 32, 6), + ROCKCHIP_PVTPLL_VOLT_SEL(1700000000, 0, 32, 6), + ROCKCHIP_PVTPLL_VOLT_SEL(1608000000, 0, 32, 5), + ROCKCHIP_PVTPLL_VOLT_SEL(1512000000, 0, 34, 5), + ROCKCHIP_PVTPLL_VOLT_SEL(1416000000, 0, 38, 5), ROCKCHIP_PVTPLL_VOLT_SEL(1296000000, 0, 38, 5), ROCKCHIP_PVTPLL_VOLT_SEL(1200000000, 0, 38, 3), ROCKCHIP_PVTPLL_VOLT_SEL(1008000000, 0, 56, 1), From 36d177c27c5e4a0055ec82ec79ef84c0fc4e30bd Mon Sep 17 00:00:00 2001 From: Yuefu Su Date: Mon, 29 Sep 2025 15:36:50 +0800 Subject: [PATCH 21/40] spi: rockchip-sfc: Wait for thunder boot DMA status change before rockchip_sfc_get_gpio_descs Signed-off-by: Yuefu Su Change-Id: I977ea73a372328313cfc2728786b123abaaecc7b --- drivers/spi/spi-rockchip-sfc.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/spi/spi-rockchip-sfc.c b/drivers/spi/spi-rockchip-sfc.c index 500503c6338b..7dc9ad405dc5 100644 --- a/drivers/spi/spi-rockchip-sfc.c +++ b/drivers/spi/spi-rockchip-sfc.c @@ -1010,12 +1010,6 @@ static int rockchip_sfc_probe(struct platform_device *pdev) if (sfc->max_dll_cells > SFC_DLL_CTRL0_DLL_MAX_VER5) sfc->max_dll_cells = SFC_DLL_CTRL0_DLL_MAX_VER5; - ret = rockchip_sfc_get_gpio_descs(master, sfc); - if (ret) { - dev_err(&pdev->dev, "Failed to get gpio_descs\n"); - return ret; - } - ret = clk_prepare_enable(sfc->hclk); if (ret) { dev_err(&pdev->dev, "Failed to enable ahb clk\n"); @@ -1063,6 +1057,12 @@ static int rockchip_sfc_probe(struct platform_device *pdev) dev_err(dev, "Wait for SFC idle timeout!\n"); } + ret = rockchip_sfc_get_gpio_descs(master, sfc); + if (ret) { + dev_err(&pdev->dev, "Failed to get gpio_descs\n"); + goto err_irq; + } + ret = rockchip_sfc_init(sfc); if (ret) goto err_irq; From 18a1dd9d033bb89ec7f7f1587b6caa3563661746 Mon Sep 17 00:00:00 2001 From: Chunsheng Zhang Date: Tue, 5 Aug 2025 19:55:08 +0800 Subject: [PATCH 22/40] arm64: dts: rockchip: rv1126b-evb2: Add the rk96x_wake_aov_irq driver's dts. Change-Id: Idef5e3d08b71058b95536b23fc333f19ce6c3d65 Signed-off-by: Chunsheng Zhang --- arch/arm64/boot/dts/rockchip/rv1126b-evb2-v10.dtsi | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/arch/arm64/boot/dts/rockchip/rv1126b-evb2-v10.dtsi b/arch/arm64/boot/dts/rockchip/rv1126b-evb2-v10.dtsi index cf6b5788ea5e..db9d53a31e65 100644 --- a/arch/arm64/boot/dts/rockchip/rv1126b-evb2-v10.dtsi +++ b/arch/arm64/boot/dts/rockchip/rv1126b-evb2-v10.dtsi @@ -230,6 +230,13 @@ WIFI,host_wake_irq = <&gpio0 RK_PC0 GPIO_ACTIVE_HIGH>; status = "okay"; }; + + rk96x_wake_aov_irq: rk96x-wake-aov-irq { + compatible = "rockchip,rk96x-wake-aov-irq"; + rk96x-wake-irq-gpios = <&gpio0 RK_PC0 GPIO_ACTIVE_HIGH>; + wakeup-source; + status = "okay"; + }; }; &acdcdig_dsm { From 4c08cc80516c2eb515a1513b25516adb4f738376 Mon Sep 17 00:00:00 2001 From: Jianwei Fan Date: Wed, 17 Sep 2025 10:40:51 +0800 Subject: [PATCH 23/40] iio: imu: add inv icm42607 support Change-Id: I6a258bc331a3c3b2428faaa6a7d766cad5f83003 Signed-off-by: Jianwei Fan --- drivers/iio/imu/Kconfig | 1 + drivers/iio/imu/Makefile | 1 + drivers/iio/imu/inv_icm42607/Kconfig | 18 + drivers/iio/imu/inv_icm42607/Makefile | 7 + drivers/iio/imu/inv_icm42607/icm42607.c | 416 ++++++++++++++++++++ drivers/iio/imu/inv_icm42607/icm42607.h | 435 +++++++++++++++++++++ drivers/iio/imu/inv_icm42607/imu.h | 91 +++++ drivers/iio/imu/inv_icm42607/invimu_core.c | 270 +++++++++++++ drivers/iio/imu/inv_icm42607/invimu_core.h | 10 + drivers/iio/imu/inv_icm42607/invimu_i2c.c | 109 ++++++ drivers/iio/imu/inv_icm42607/invimu_iio.c | 295 ++++++++++++++ drivers/iio/imu/inv_icm42607/invimu_iio.h | 34 ++ 12 files changed, 1687 insertions(+) create mode 100644 drivers/iio/imu/inv_icm42607/Kconfig create mode 100644 drivers/iio/imu/inv_icm42607/Makefile create mode 100644 drivers/iio/imu/inv_icm42607/icm42607.c create mode 100644 drivers/iio/imu/inv_icm42607/icm42607.h create mode 100644 drivers/iio/imu/inv_icm42607/imu.h create mode 100644 drivers/iio/imu/inv_icm42607/invimu_core.c create mode 100644 drivers/iio/imu/inv_icm42607/invimu_core.h create mode 100644 drivers/iio/imu/inv_icm42607/invimu_i2c.c create mode 100644 drivers/iio/imu/inv_icm42607/invimu_iio.c create mode 100644 drivers/iio/imu/inv_icm42607/invimu_iio.h diff --git a/drivers/iio/imu/Kconfig b/drivers/iio/imu/Kconfig index 8d6df41dcba3..287dae6f497a 100644 --- a/drivers/iio/imu/Kconfig +++ b/drivers/iio/imu/Kconfig @@ -94,6 +94,7 @@ config KMX61 be called kmx61. source "drivers/iio/imu/inv_icm42600/Kconfig" +source "drivers/iio/imu/inv_icm42607/Kconfig" source "drivers/iio/imu/inv_icm42670/Kconfig" source "drivers/iio/imu/inv_mpu6050/Kconfig" source "drivers/iio/imu/st_lsm6dsr/Kconfig" diff --git a/drivers/iio/imu/Makefile b/drivers/iio/imu/Makefile index f2cfa8828a07..7745e4218817 100644 --- a/drivers/iio/imu/Makefile +++ b/drivers/iio/imu/Makefile @@ -22,6 +22,7 @@ obj-$(CONFIG_FXOS8700_I2C) += fxos8700_i2c.o obj-$(CONFIG_FXOS8700_SPI) += fxos8700_spi.o obj-y += inv_icm42600/ +obj-y += inv_icm42607/ obj-y += inv_icm42670/ obj-y += inv_mpu6050/ diff --git a/drivers/iio/imu/inv_icm42607/Kconfig b/drivers/iio/imu/inv_icm42607/Kconfig new file mode 100644 index 000000000000..8368bf160b69 --- /dev/null +++ b/drivers/iio/imu/inv_icm42607/Kconfig @@ -0,0 +1,18 @@ +# SPDX-License-Identifier: GPL-2.0 + +config IIO_INV_ICM42607 + tristate "INV ICM42607 driver for 6-axis IMU MEMS sensors" + depends on I2C + select IIO_BUFFER + select IIO_KFIFO_BUF + select IIO_INV_ICM42607_I2C if (I2C) + help + Say yes here to build support for INV icm42607 sensor. + + To compile this driver as a module, choose M here: the module + will be called inv_icm42607. + +config IIO_INV_ICM42607_I2C + tristate + depends on IIO_INV_ICM42607 + select REGMAP_I2C diff --git a/drivers/iio/imu/inv_icm42607/Makefile b/drivers/iio/imu/inv_icm42607/Makefile new file mode 100644 index 000000000000..dfdbf5cb7a07 --- /dev/null +++ b/drivers/iio/imu/inv_icm42607/Makefile @@ -0,0 +1,7 @@ +# SPDX-License-Identifier: GPL-2.0 +inv-icm42607-y := invimu_core.o invimu_iio.o icm42607.o + +obj-$(CONFIG_IIO_INV_ICM42607) += inv-icm42607.o + +inv-icm42607-i2c-y := invimu_i2c.o +obj-$(CONFIG_IIO_INV_ICM42607_I2C) += inv-icm42607-i2c.o diff --git a/drivers/iio/imu/inv_icm42607/icm42607.c b/drivers/iio/imu/inv_icm42607/icm42607.c new file mode 100644 index 000000000000..a65ca5a7476c --- /dev/null +++ b/drivers/iio/imu/inv_icm42607/icm42607.c @@ -0,0 +1,416 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2025 Rockchip Electronics Co., Ltd. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "icm42607.h" + +static struct imu_reg_value_map icm_acce_only_regs_cfg_map[] = { + {REG_PWR_MGMT_0, 0x03}, /* Accelerometer only mode */ + {REG_ACCEL_CONFIG0, 0x9},/* 100Hz, 16g range */ +}; + +static struct imu_reg_value_map icm_acce_gyro_regs_cfg_map[] = { + {REG_PWR_MGMT_0, 0x0f}, /* Both accelerometer and gyroscope on */ + {REG_ACCEL_CONFIG0, 0x9},/* 100Hz, 16g range */ + {REG_GYRO_CONFIG0, 0x9}, /* 100Hz, 2000dps range */ +}; + +static struct imu_reg_value_map icm_powerdown_regs_cfg_map[] = { + {REG_PWR_MGMT_0, 0x00}, +}; + +static int icm42607_regs_cfg_write(struct imu_ctrb *ctrb, + struct imu_reg_value_map *maparrays, int regcnt) +{ + int i, ret; + + if (ctrb == NULL) + return -1; + + if (regcnt <= 0) { + dev_err(ctrb->dev, "reg map len err\n"); + return -1; + } + for (i = 0; i < regcnt; i++) { + ret = regmap_write(ctrb->regmap, maparrays[i].reg, maparrays[i].value); + if (ret) { + dev_err(ctrb->dev, "regmap write err\n"); + return -1; + } + } + return 0; +} + +static int icm42607_read_id(void *ctrbp) +{ + int ret; + unsigned int val = 0; + struct imu_ctrb *ctrb = (struct imu_ctrb *)ctrbp; + + if (ctrb == NULL) + return -1; + + ret = regmap_read(ctrb->regmap, REG_WHO_AM_I, &val); + if (ret) { + dev_err(ctrb->dev, "regmap_read err\n"); + return 0; + } + dev_info(ctrb->dev, "ID = 0x%02x\n", val); + return (int)val; +} + +static int icm42607_mode_set(void *ctrbp, int mode) +{ + int ret = 0; + struct imu_ctrb *ctrb = (struct imu_ctrb *)ctrbp; + + if (ctrb == NULL) + return -1; + + switch (mode) { + case IMU_POWER_MODE_INIT: + break; + case IMU_POWER_MODE_DOWN: + ret = icm42607_regs_cfg_write(ctrb, icm_powerdown_regs_cfg_map, + sizeof(icm_powerdown_regs_cfg_map) / sizeof(struct imu_reg_value_map)); + break; + case IMU_POWER_ACCE_ONLY: + ret = icm42607_regs_cfg_write(ctrb, icm_acce_only_regs_cfg_map, + sizeof(icm_acce_only_regs_cfg_map) / sizeof(struct imu_reg_value_map)); + break; + case IMU_POWER_ACCE_GYRO: + ret = icm42607_regs_cfg_write(ctrb, icm_acce_gyro_regs_cfg_map, + sizeof(icm_acce_gyro_regs_cfg_map) / sizeof(struct imu_reg_value_map)); + break; + default: + ret = -1; + } + dev_info(ctrb->dev, "set power:%d success\n", mode); + return ret; +} + +static int icm42607_mreg_write(struct imu_ctrb *ctrb, u16 addr, u8 data) +{ + int ret; + u8 bank = addr >> 8; + u8 reg = addr & 0xFF; + + ret = regmap_write(ctrb->regmap, REG_BLK_SEL_W, bank); + usleep_range(10, 11); + ret |= regmap_write(ctrb->regmap, REG_MADDR_W, reg); + usleep_range(10, 11); + ret |= regmap_write(ctrb->regmap, REG_M_W, data); + usleep_range(10, 11); + ret |= regmap_write(ctrb->regmap, REG_BLK_SEL_W, 0); + + return ret; +} + +static int icm42607_mreg_read(struct imu_ctrb *ctrb, u16 addr, u8 *data) +{ + int ret; + u8 bank = addr >> 8; + u8 reg = addr & 0xFF; + unsigned int tmp; + + ret = regmap_write(ctrb->regmap, REG_BLK_SEL_R, bank); + usleep_range(10, 11); + ret |= regmap_write(ctrb->regmap, REG_MADDR_R, reg); + usleep_range(10, 11); + ret |= regmap_read(ctrb->regmap, REG_M_R, &tmp); + usleep_range(10, 11); + ret |= regmap_write(ctrb->regmap, REG_BLK_SEL_R, 0); + + if (!ret) + *data = (u8)tmp; + + return ret; +} + +static int icm42607_otp_reload(struct imu_ctrb *ctrb) +{ + int ret; + u8 rb; + + ret = regmap_write(ctrb->regmap, REG_PWR_MGMT_0, BIT_IDLE); + if (ret) + return ret; + usleep_range(20, 21); + + /* OTP_COPY_MODE = 2'b01 */ + ret = icm42607_mreg_read(ctrb, REG_OTP_CONFIG_MREG_TOP1, &rb); + if (ret) + return ret; + rb &= ~OTP_COPY_MODE_MASK; + rb |= BIT_OTP_COPY_NORMAL; + ret = icm42607_mreg_write(ctrb, REG_OTP_CONFIG_MREG_TOP1, rb); + if (ret) + return ret; + + /* OTP_PWR_DOWN = 0 */ + ret = icm42607_mreg_read(ctrb, REG_OTP_CTRL7_MREG_OTP, &rb); + if (ret) + return ret; + rb &= ~BIT_OTP_PWR_DOWN; + ret = icm42607_mreg_write(ctrb, REG_OTP_CTRL7_MREG_OTP, rb); + if (ret) + return ret; + usleep_range(300, 400); + + /* OTP_RELOAD = 1 */ + ret = icm42607_mreg_read(ctrb, REG_OTP_CTRL7_MREG_OTP, &rb); + if (ret) + return ret; + rb |= BIT_OTP_RELOAD; + ret = icm42607_mreg_write(ctrb, REG_OTP_CTRL7_MREG_OTP, rb); + if (ret) + return ret; + usleep_range(280, 380); + + return 0; +} + +static int icm42607_set_default_register(struct imu_ctrb *ctrb) +{ + int s = 0; + + s |= regmap_write(ctrb->regmap, REG_GYRO_CONFIG0, 0x69); + s |= regmap_write(ctrb->regmap, REG_ACCEL_CONFIG0, 0x69); + s |= regmap_write(ctrb->regmap, REG_APEX_CONFIG0, 0x08); + s |= regmap_write(ctrb->regmap, REG_APEX_CONFIG1, 0x02); + s |= regmap_write(ctrb->regmap, REG_WOM_CONFIG, 0x00); + s |= regmap_write(ctrb->regmap, REG_FIFO_CONFIG1, 0x01); + s |= regmap_write(ctrb->regmap, REG_FIFO_CONFIG2, 0x00); + s |= regmap_write(ctrb->regmap, REG_FIFO_CONFIG3, 0x00); + + s |= icm42607_mreg_write(ctrb, REG_FIFO_CONFIG5_MREG_TOP1, 0x20); + s |= icm42607_mreg_write(ctrb, REG_ST_CONFIG_MREG_TOP1, 0x00); + s |= icm42607_mreg_write(ctrb, REG_INT_SOURCE7_MREG_TOP1, 0x00); + s |= icm42607_mreg_write(ctrb, REG_INT_SOURCE8_MREG_TOP1, 0x00); + s |= icm42607_mreg_write(ctrb, REG_INT_SOURCE9_MREG_TOP1, 0x00); + s |= icm42607_mreg_write(ctrb, REG_INT_SOURCE10_MREG_TOP1, 0x00); + s |= icm42607_mreg_write(ctrb, REG_APEX_CONFIG2_MREG_TOP1, 0xA2); + s |= icm42607_mreg_write(ctrb, REG_APEX_CONFIG3_MREG_TOP1, 0x85); + s |= icm42607_mreg_write(ctrb, REG_APEX_CONFIG4_MREG_TOP1, 0x51); + s |= icm42607_mreg_write(ctrb, REG_APEX_CONFIG5_MREG_TOP1, 0x80); + s |= icm42607_mreg_write(ctrb, REG_APEX_CONFIG9_MREG_TOP1, 0x00); + s |= icm42607_mreg_write(ctrb, REG_APEX_CONFIG10_MREG_TOP1, 0x00); + s |= icm42607_mreg_write(ctrb, REG_APEX_CONFIG11_MREG_TOP1, 0x00); + s |= icm42607_mreg_write(ctrb, REG_ACCEL_WOM_X_THR_MREG_TOP1, 0x00); + s |= icm42607_mreg_write(ctrb, REG_ACCEL_WOM_Y_THR_MREG_TOP1, 0x00); + s |= icm42607_mreg_write(ctrb, REG_ACCEL_WOM_Z_THR_MREG_TOP1, 0x00); + s |= icm42607_mreg_write(ctrb, REG_GOS_USER0_MREG_TOP1, 0x00); + s |= icm42607_mreg_write(ctrb, REG_GOS_USER1_MREG_TOP1, 0x00); + s |= icm42607_mreg_write(ctrb, REG_GOS_USER2_MREG_TOP1, 0x00); + s |= icm42607_mreg_write(ctrb, REG_GOS_USER3_MREG_TOP1, 0x00); + s |= icm42607_mreg_write(ctrb, REG_GOS_USER4_MREG_TOP1, 0x00); + s |= icm42607_mreg_write(ctrb, REG_GOS_USER5_MREG_TOP1, 0x00); + s |= icm42607_mreg_write(ctrb, REG_GOS_USER6_MREG_TOP1, 0x00); + s |= icm42607_mreg_write(ctrb, REG_GOS_USER7_MREG_TOP1, 0x00); + s |= icm42607_mreg_write(ctrb, REG_GOS_USER8_MREG_TOP1, 0x00); + s |= icm42607_mreg_write(ctrb, REG_APEX_CONFIG12_MREG_TOP1, 0x00); + + return s ? -EIO : 0; +} + +static int icm42607_chip_init(void *ctrbp) +{ + struct imu_ctrb *ctrb = (struct imu_ctrb *)ctrbp; + int ret; + unsigned int val; + + if (!ctrb) + return -EINVAL; + + ret = icm42607_otp_reload(ctrb); + if (ret) { + dev_err(ctrb->dev, "OTP reload fail(%d)\n", ret); + return ret; + } + + ret = icm42607_set_default_register(ctrb); + if (ret) { + dev_err(ctrb->dev, "set default reg fail(%d)\n", ret); + return ret; + } + + val = BIT_SENSOR_DATA_ENDIAN | BIT_FIFO_COUNT_ENDIAN; + ret = regmap_write(ctrb->regmap, REG_INTF_CONFIG0, val); + if (ret) + return ret; + + val = BIT_CLK_SEL_PLL | BIT_I3C_SDR_EN | BIT_I3C_DDR_EN; + ret = regmap_write(ctrb->regmap, REG_INTF_CONFIG1, val); + if (ret) + return ret; + + return icm42607_mode_set(ctrb, IMU_POWER_MODE_DOWN); +} + +static int icm42607_read_acce_gyro_raw(void *ctrbp, void *rawdatap, uint8_t reg) +{ + int ret = 0; + uint8_t rawarrays[6] = { 0 }; + struct imu_ctrb *ctrb = (struct imu_ctrb *)ctrbp; + struct imu_3axis_data *rawdata = (struct imu_3axis_data *)rawdatap; + + if (ctrb == NULL || rawdata == NULL) + return -1; + + ret = regmap_bulk_read(ctrb->regmap, reg, rawarrays, sizeof(rawarrays)); + if (!ret) { + rawdata->raw[0] = ((uint16_t)rawarrays[0]) << 8 | rawarrays[1]; + rawdata->raw[1] = ((uint16_t)rawarrays[2]) << 8 | rawarrays[3]; + rawdata->raw[2] = ((uint16_t)rawarrays[4]) << 8 | rawarrays[5]; + } else { + dev_err(ctrb->dev, "regmap_bulk_read err:%d\n", ret); + } + return ret; +} + +static int icm42607_read_acce_raw(void *ctrbp, void *rawdatap) +{ + return icm42607_read_acce_gyro_raw(ctrbp, rawdatap, REG_ACCEL_DATA_X0_UI); +} + +static int icm42607_read_gyro_raw(void *ctrbp, void *rawdatap) +{ + return icm42607_read_acce_gyro_raw(ctrbp, rawdatap, REG_GYRO_DATA_X0_UI); +} + +static int icm42607_read_asix_one(void *ctrbp, int addr, int *datap) +{ + int ret; + struct imu_3axis_data accedata = {0}, gyrodata = {0}; + + ret = icm42607_read_acce_raw(ctrbp, &accedata); + ret = ret || icm42607_read_gyro_raw(ctrbp, &gyrodata); + switch (addr) { + case 0: + (*datap) = accedata.raw[0]; + break; + case 1: + (*datap) = accedata.raw[1]; + break; + case 2: + (*datap) = accedata.raw[2]; + break; + case 3: + (*datap) = gyrodata.raw[0]; + break; + case 4: + (*datap) = gyrodata.raw[1]; + break; + case 5: + (*datap) = gyrodata.raw[2]; + break; + } + return ret; +} + +static int icm42607_set_accel_offset(void *ctrbp, int offset, int axis) +{ + struct imu_ctrb *ctrb = (struct imu_ctrb *)ctrbp; + int ret = 0; + u8 reg_l, reg_h; + u16 val; + + offset = clamp(offset, -2048, 2047); + val = (u16)(offset & 0x0FFF); + + switch (axis) { + case 0: /* X */ + reg_l = REG_GOS_USER5_MREG_TOP1; + reg_h = REG_GOS_USER4_MREG_TOP1; + break; + case 1: /* Y */ + reg_l = REG_GOS_USER6_MREG_TOP1; + reg_h = REG_GOS_USER7_MREG_TOP1; + break; + case 2: /* Z */ + reg_l = REG_GOS_USER8_MREG_TOP1; + reg_h = REG_GOS_USER7_MREG_TOP1; + break; + default: + return -EINVAL; + } + + ret |= icm42607_mreg_write(ctrb, reg_l, val & 0xFF); + ret |= icm42607_mreg_write(ctrb, reg_h, (val >> 8) & 0x0F); + + return ret ? -EIO : 0; +} + +static int icm42607_set_gyro_offset(void *ctrbp, int offset, int axis) +{ + struct imu_ctrb *ctrb = (struct imu_ctrb *)ctrbp; + int ret = 0; + u8 reg_l, reg_h; + u16 val; + + offset = clamp(offset, -2048, 2047); + val = (u16)(offset & 0x0FFF); + + switch (axis) { + case 0: /* X */ + reg_l = REG_GOS_USER0_MREG_TOP1; + reg_h = REG_GOS_USER1_MREG_TOP1; + break; + case 1: /* Y */ + reg_l = REG_GOS_USER2_MREG_TOP1; + reg_h = REG_GOS_USER1_MREG_TOP1; + break; + case 2: /* Z */ + reg_l = REG_GOS_USER3_MREG_TOP1; + reg_h = REG_GOS_USER4_MREG_TOP1; + break; + default: + return -EINVAL; + } + + ret |= icm42607_mreg_write(ctrb, reg_l, val & 0xFF); + ret |= icm42607_mreg_write(ctrb, reg_h, (val >> 8) & 0x0F); + + return ret ? -EIO : 0; +} + +static const struct imu_info icm42607_info = { + .name = "icm42607", + .id = ICM42607_CHIP_ID, + .read_id = icm42607_read_id, + .chip_init = icm42607_chip_init, + .mode_set = icm42607_mode_set, + .read_acce_raw = icm42607_read_acce_raw, + .read_gyro_raw = icm42607_read_gyro_raw, + .read_asix_one = icm42607_read_asix_one, + .set_accel_offset = icm42607_set_accel_offset, + .set_gyro_offset = icm42607_set_gyro_offset, +}; + +struct imu_info *icm42607_chip_probe(struct imu_ctrb *ctrb) +{ + int chip_id = -1; + + chip_id = icm42607_read_id(ctrb); + if (chip_id == icm42607_info.id) { + dev_info(ctrb->dev, "probe sensor: %s, id = 0x%02X\n", + icm42607_info.name, icm42607_info.id); + return (struct imu_info *)&icm42607_info; + } + return NULL; +} diff --git a/drivers/iio/imu/inv_icm42607/icm42607.h b/drivers/iio/imu/inv_icm42607/icm42607.h new file mode 100644 index 000000000000..1d9543a22505 --- /dev/null +++ b/drivers/iio/imu/inv_icm42607/icm42607.h @@ -0,0 +1,435 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2025 Rockchip Electronics Co., Ltd. + */ + +#ifndef __ICM42607_H__ +#define __ICM42607_H__ + +#include "imu.h" + +/* Registers and associated bit definitions */ +/* Bank 0 */ +#define REG_MISC_1 0x00 +#define REG_CHIP_CONFIG_REG 0x01 +#define REG_SIGNAL_PATH_RESET 0x02 +#define REG_DRIVE_CONFIG_REG1 0x03 +#define REG_DRIVE_CONFIG_REG2 0x04 +#define REG_DRIVE_CONFIG_REG3 0x05 +#define REG_INT_CONFIG_REG 0x06 +#define REG_ODRGRID0 0x07 +#define REG_ODRGRID1 0x08 +#define REG_TEMP_DATA0_UI 0x09 +#define REG_TEMP_DATA1_UI 0x0a +#define REG_ACCEL_DATA_X0_UI 0x0b +#define REG_ACCEL_DATA_X1_UI 0x0c +#define REG_ACCEL_DATA_Y0_UI 0x0d +#define REG_ACCEL_DATA_Y1_UI 0x0e +#define REG_ACCEL_DATA_Z0_UI 0x0f +#define REG_ACCEL_DATA_Z1_UI 0x10 +#define REG_GYRO_DATA_X0_UI 0x11 +#define REG_GYRO_DATA_X1_UI 0x12 +#define REG_GYRO_DATA_Y0_UI 0x13 +#define REG_GYRO_DATA_Y1_UI 0x14 +#define REG_GYRO_DATA_Z0_UI 0x15 +#define REG_GYRO_DATA_Z1_UI 0x16 +#define REG_TMST_FSYNC1 0x17 +#define REG_TMST_FSYNC2 0x18 +#define REG_ODR_LP_STATUS 0x19 +#define REG_PWR_MGMT_0 0x1f +#define REG_GYRO_CONFIG0 0x20 +#define REG_ACCEL_CONFIG0 0x21 +#define REG_TEMP_CONFIG0 0x22 +#define REG_GYRO_CONFIG1 0x23 +#define REG_ACCEL_CONFIG1 0x24 +#define REG_APEX_CONFIG0 0x25 +#define REG_APEX_CONFIG1 0x26 +#define REG_WOM_CONFIG 0x27 +#define REG_FIFO_CONFIG1 0x28 +#define REG_FIFO_CONFIG2 0x29 +#define REG_FIFO_CONFIG3 0x2a +#define REG_INT_SOURCE0 0x2b +#define REG_INT_SOURCE1 0x2c +#define REG_INT_SOURCE3 0x2d +#define REG_INT_SOURCE4 0x2e +#define REG_FIFO_LOST_PKT0 0x2f +#define REG_FIFO_LOST_PKT1 0x30 +#define REG_APEX_DATA0 0x31 +#define REG_APEX_DATA1 0x32 +#define REG_APEX_DATA2 0x33 +#define REG_APEX_DATA3 0x34 +#define REG_INTF_CONFIG0 0x35 +#define REG_INTF_CONFIG1 0x36 +#define REG_INT_STATUS_DRDY 0x39 +#define REG_INT_STATUS 0x3a +#define REG_INT_STATUS2 0x3b +#define REG_INT_STATUS3 0x3c +#define REG_FIFO_BYTE_COUNT1 0x3d +#define REG_FIFO_BYTE_COUNT2 0x3e +#define REG_FIFO_DATA_REG 0x3f +#define REG_S4S_GYRO_TPH1 0x40 +#define REG_S4S_GYRO_TPH2 0x41 +#define REG_S4S_ACCEL_TPH1 0x42 +#define REG_S4S_ACCEL_TPH2 0x43 +#define REG_S4S_RR 0x44 +#define REG_GYR_BIAS_CFG1 0x46 +#define REG_WHO_AM_I 0x75 +#define REG_S4S_ST 0x76 +#define REG_S4S_ST_CLONE 0x77 +#define REG_S4S_DT 0x78 +#define REG_BLK_SEL_W 0x79 +#define REG_MADDR_W 0x7a +#define REG_M_W 0x7b +#define REG_BLK_SEL_R 0x7c +#define REG_MADDR_R 0x7d +#define REG_M_R 0x7e + +/* MREG_TOP1 */ +#define REG_TMST_CONFIG1_MREG_TOP1 0x00 +#define REG_FIFO_CONFIG5_MREG_TOP1 0x01 +#define REG_FIFO_CONFIG6_MREG_TOP1 0x02 +#define REG_FSYNC_CONFIG_MREG_TOP1 0x03 +#define REG_INT_CONFIG0_MREG_TOP1 0x04 +#define REG_INT_CONFIG1_MREG_TOP1 0x05 +#define REG_AFSR_CONFIG0_MREG_TOP1 0x07 +#define REG_AFSR_CONFIG1_MREG_TOP1 0x08 +#define REG_TBC_RCOSC_MREG_TOP1 0x0d +#define REG_TBC_PLL_MREG_TOP1 0x0e +#define REG_ST_CONFIG_MREG_TOP1 0x13 +#define REG_SELFTEST_MREG_TOP1 0x14 +#define REG_PADS_CONFIG3_MREG_TOP1 0x17 +#define REG_TEMP_CONFIG1_MREG_TOP1 0x1c +#define REG_TEMP_CONFIG3_MREG_TOP1 0x1e +#define REG_S4S_CONFIG1_MREG_TOP1 0x1f +#define REG_S4S_CONFIG2_MREG_TOP1 0x20 +#define REG_S4S_FREQ_RATIO1_MREG_TOP1 0x21 +#define REG_S4S_FREQ_RATIO2_MREG_TOP1 0x22 +#define REG_INTF_CONFIG6_MREG_TOP1 0x23 +#define REG_INTF_CONFIG10_MREG_TOP1 0x25 +#define REG_INTF_CONFIG7_MREG_TOP1 0x28 +#define REG_OTP_CONFIG_MREG_TOP1 0x2b +#define REG_INT_SOURCE6_MREG_TOP1 0x2f +#define REG_INT_SOURCE7_MREG_TOP1 0x30 +#define REG_INT_SOURCE8_MREG_TOP1 0x31 +#define REG_INT_SOURCE9_MREG_TOP1 0x32 +#define REG_INT_SOURCE10_MREG_TOP1 0x33 +#define REG_GYRO_PWR_CFG0_MREG_TOP1 0x38 +#define REG_ACCEL_CP_CFG0_MREG_TOP1 0x39 +#define REG_APEX_CONFIG2_MREG_TOP1 0x44 +#define REG_APEX_CONFIG3_MREG_TOP1 0x45 +#define REG_APEX_CONFIG4_MREG_TOP1 0x46 +#define REG_APEX_CONFIG5_MREG_TOP1 0x47 +#define REG_APEX_CONFIG9_MREG_TOP1 0x48 +#define REG_APEX_CONFIG10_MREG_TOP1 0x49 +#define REG_APEX_CONFIG11_MREG_TOP1 0x4a +#define REG_APEX_CONFIG12_MREG_TOP1 0x67 +#define REG_ACCEL_WOM_X_THR_MREG_TOP1 0x4b +#define REG_ACCEL_WOM_Y_THR_MREG_TOP1 0x4c +#define REG_ACCEL_WOM_Z_THR_MREG_TOP1 0x4d +#define REG_GOS_USER0_MREG_TOP1 0x4e +#define REG_GOS_USER1_MREG_TOP1 0x4f +#define REG_GOS_USER2_MREG_TOP1 0x50 +#define REG_GOS_USER3_MREG_TOP1 0x51 +#define REG_GOS_USER4_MREG_TOP1 0x52 +#define REG_GOS_USER5_MREG_TOP1 0x53 +#define REG_GOS_USER6_MREG_TOP1 0x54 +#define REG_GOS_USER7_MREG_TOP1 0x55 +#define REG_GOS_USER8_MREG_TOP1 0x56 +#define REG_ST_STATUS1_MREG_TOP1 0x63 +#define REG_ST_STATUS2_MREG_TOP1 0x64 + +/* MMEM_TOP */ +#define REG_XG_ST_DATA_MMEM_TOP 0x5000 +#define REG_YG_ST_DATA_MMEM_TOP 0x5001 +#define REG_ZG_ST_DATA_MMEM_TOP 0x5002 +#define REG_XA_ST_DATA_MMEM_TOP 0x5003 +#define REG_YA_ST_DATA_MMEM_TOP 0x5004 +#define REG_ZA_ST_DATA_MMEM_TOP 0x5005 + +/* MREG_OTP */ +#define REG_OTP_CTRL7_MREG_OTP 0x2806 + +/* Bank0 REG_GYRO_CONFIG0/REG_ACCEL_CONFIG0 */ +#define SHIFT_GYRO_FS_SEL 5 +#define SHIFT_ACCEL_FS_SEL 5 +#define SHIFT_ODR_CONF 0 +#define BIT_GYRO_FSR 0x60 +#define BIT_GYRO_ODR 0x0F +#define BIT_ACCEL_FSR 0x60 +#define ACCEL_FS_SEL 3 //(-2G, +2G) +#define GYRO_FS_SEL 3 //00~11:2000dps\1000dps\500dps\250dps +#define BIT_ACCEL_ODR 0x0F +#define BIT_SENSOR_ODR_800HZ 0x06 +#define BIT_SENSOR_ODR_400HZ 0x07 +#define BIT_SENSOR_ODR_200HZ 0x08 +#define BIT_SENSOR_ODR_100HZ 0x09 +#define BIT_SENSOR_ODR_50HZ 0x0A +#define BIT_SENSOR_ODR_25HZ 0x0B +#define BIT_SENSOR_ODR_12HZ 0x0C +#define BIT_SENSOR_ODR_6HZ 0x0D +#define BIT_SENSOR_ODR_3HZ 0x0E + +/* Bank0 REG_GYRO_CONFIG1 */ +#define BIT_GYR_UI_FLT_BW_BYPASS 0x00 +#define BIT_GYR_UI_FLT_BW_180HZ 0x01 +#define BIT_GYR_UI_FLT_BW_121HZ 0x02 +#define BIT_GYR_UI_FLT_BW_73HZ 0x03 +#define BIT_GYR_UI_FLT_BW_53HZ 0x04 +#define BIT_GYR_UI_FLT_BW_34HZ 0x05 +#define BIT_GYR_UI_FLT_BW_25HZ 0x06 +#define BIT_GYR_UI_FLT_BW_16HZ 0x07 +#define BIT_GYR_UI_AVG_IND_2X 0x00 +#define BIT_GYR_UI_AVG_IND_4X 0x10 +#define BIT_GYR_UI_AVG_IND_8X 0x20 +#define BIT_GYR_UI_AVG_IND_16X 0x30 +#define BIT_GYR_UI_AVG_IND_32X 0x40 +#define BIT_GYR_UI_AVG_IND_64X 0x50 + +/* Bank0 REG_ACCEL_CONFIG1 */ +#define BIT_ACC_FILT_BW_IND_BYPASS 0x00 +#define BIT_ACC_FILT_BW_IND_180HZ 0x01 +#define BIT_ACC_FILT_BW_IND_121HZ 0x02 +#define BIT_ACC_FILT_BW_IND_73HZ 0x03 +#define BIT_ACC_FILT_BW_IND_53HZ 0x04 +#define BIT_ACC_FILT_BW_IND_34HZ 0x05 +#define BIT_ACC_FILT_BW_IND_25HZ 0x06 +#define BIT_ACC_FILT_BW_IND_16HZ 0x07 +#define BIT_ACC_UI_AVG_IND_2X 0x00 +#define BIT_ACC_UI_AVG_IND_4X 0x10 +#define BIT_ACC_UI_AVG_IND_8X 0x20 +#define BIT_ACC_UI_AVG_IND_16X 0x30 +#define BIT_ACC_UI_AVG_IND_32X 0x40 +#define BIT_ACC_UI_AVG_IND_64X 0x50 + +/* Bank0 REG_INT_CONFIG_REG */ +#define SHIFT_INT1_MODE 0x02 +#define SHIFT_INT1_DRIVE_CIRCUIT 0x01 +#define SHIFT_INT1_POLARITY 0x00 + +/* Bank0 REG_PWR_MGMT_0 */ +#define BIT_ACCEL_MODE_OFF 0x00 +#define BIT_ACCEL_MODE_LPM 0x02 +#define BIT_ACCEL_MODE_LNM 0x03 +#define BIT_ACCEL_MODE_MASK 0x03 +#define BIT_GYRO_MODE_OFF 0x00 +#define BIT_GYRO_MODE_STBY 0x04 +#define BIT_GYRO_MODE_LPM 0x08 +#define BIT_GYRO_MODE_LNM 0x0c +#define BIT_GYRO_MODE_MASK 0x0c +#define BIT_IDLE 0x10 +#define BIT_ACCEL_LP_CLK_SEL 0x80 + +/* Bank0 REG_SIGNAL_PATH_RESET */ +#define BIT_FIFO_FLUSH 0x04 +#define BIT_SOFT_RESET_CHIP_CONFIG 0x10 + +/* Bank0 REG_INTF_CONFIG0 */ +#define BIT_SIFS_CFG_I2C_ONLY 0x02 +#define BIT_SIFS_CFG_SPI_ONLY 0x03 +#define BIT_SENSOR_DATA_ENDIAN 0x10 +#define BIT_FIFO_COUNT_ENDIAN 0x20 +#define BIT_FIFO_COUNT_FORMAT 0x40 +#define BIT_FIFO_SREG_INVALID_IND_DIS 0x80 + +/* Bank0 REG_INTF_CONFIG1 */ +#define BIT_CLK_SEL_RC 0x00 +#define BIT_CLK_SEL_PLL 0x01 +#define BIT_CLK_SEL_DIS 0x03 +#define BIT_I3C_DDR_EN 0x04 +#define BIT_I3C_SDR_EN 0x08 +#define BIT_GYRO_AFSR_MODE_LFS 0x00 +#define BIT_GYRO_AFSR_MODE_HFS 0x20 +#define BIT_GYRO_AFSR_MODE_DYN 0x40 + +/* Bank0 REG_FIFO_CONFIG1 */ +#define BIT_FIFO_MODE_NO_BYPASS 0x00 +#define BIT_FIFO_MODE_BYPASS 0x01 +#define BIT_FIFO_MODE_STREAM 0x00 +#define BIT_FIFO_MODE_STOPFULL 0x02 + +/* Bank 0 REG_INT_SOURCE0 */ +#define BIT_INT_AGC_RDY_INT1_EN 0x01 +#define BIT_INT_FIFO_FULL_INT1_EN 0x02 +#define BIT_INT_FIFO_THS_INT1_EN 0x04 +#define BIT_INT_DRDY_INT_EN 0x08 +#define BIT_INT_RESET_DONE_INT1_EN 0x10 +#define BIT_INT_PLL_RDY_INT1_EN 0x20 +#define BIT_INT_FSYNC_INT1_EN 0x40 +#define BIT_INT_ST_DONE_INT1_EN 0x80 + +/* Bank 0 REG_INT_SOURCE1 */ +#define BIT_INT_WOM_X_INT1_EN 0x01 +#define BIT_INT_WOM_Y_INT1_EN 0x02 +#define BIT_INT_WOM_Z_INT1_EN 0x04 +#define BIT_INT_WOM_XYZ_INT1_EN (BIT_INT_WOM_X_INT1_EN | \ + BIT_INT_WOM_Y_INT1_EN | BIT_INT_WOM_Z_INT1_EN) +#define BIT_INT_SMD_INT1_EN 0x08 +#define BIT_INT_I3C_PROTCL_ERR_INT1_EN 0x40 + +/* Bank0 REG_INT_STATUS_DRDY */ +#define BIT_INT_STATUS_DRDY 0x01 + +/* Bank0 REG_INT_STATUS */ +#define BIT_INT_STATUS_AGC_RDY 0x01 +#define BIT_INT_STATUS_FIFO_FULL 0x02 +#define BIT_INT_STATUS_FIFO_THS 0x04 +#define BIT_INT_STATUS_RESET_DONE 0x10 +#define BIT_INT_STATUS_PLL_RDY 0x20 +#define BIT_INT_STATUS_FSYNC 0x40 +#define BIT_INT_STATUS_ST_DONE 0x80 + +/* Bank0 REG_INT_STATUS2 */ +#define BIT_INT_STATUS_WOM_Z 0x01 +#define BIT_INT_STATUS_WOM_Y 0x02 +#define BIT_INT_STATUS_WOM_X 0x04 +#define BIT_INT_STATUS_WOM_XYZ (BIT_INT_STATUS_WOM_X | \ + BIT_INT_STATUS_WOM_Y | BIT_INT_STATUS_WOM_Z) +#define BIT_INT_STATUS_SMD 0x08 + +/* Bank 0 REG_INT_STATUS3 */ +#define BIT_INT_STATUS_LOWG_DET 0x02 +#define BIT_INT_STATUS_FF_DET 0x04 +#define BIT_INT_STATUS_TILT_DET 0x08 +#define BIT_INT_STATUS_STEP_CNT_OVFL 0x10 +#define BIT_INT_STATUS_STEP_DET 0x20 + +/* Bank0 REG_WOM_CONFIG */ +#define BIT_WOM_EN_OFF 0x00 +#define BIT_WOM_EN_ON 0x01 +#define BIT_WOM_MODE_INITIAL 0x00 +#define BIT_WOM_MODE_PREV 0x02 +#define BIT_WOM_INT_MODE_OR 0x00 +#define BIT_WOM_INT_MODE_AND 0x04 +#define BIT_WOM_INT_DUR_LEGACY 0x00 +#define BIT_WOM_INT_DUR_2ND 0x08 +#define BIT_WOM_INT_DUR_3RD 0x10 +#define BIT_WOM_INT_DUR_4TH 0x18 + +/* Bank0 REG_APEX_CONFIG0 */ +#define BIT_DMP_SRAM_RESET_APEX 0x01 +#define BIT_DMP_INIT_EN 0x04 +#define BIT_DMP_POWER_SAVE_EN 0x08 + +/* Bank0 REG_APEX_CONFIG1 */ +#define BIT_DMP_ODR_25HZ 0x00 +#define BIT_DMP_ODR_50HZ 0x02 +#define BIT_DMP_ODR_100HZ 0x03 +#define BIT_DMP_PEDO_EN 0x08 +#define BIT_DMP_TILT_EN 0x10 +#define BIT_DMP_FF_EN 0x20 +#define BIT_DMP_SMD_EN 0x40 + +/* REG_OTP_CONFIG_MREG_TOP1 */ +#define BIT_OTP_COPY_NORMAL 0x04 +#define BIT_OTP_COPY_ST_DATA 0x0C +#define OTP_COPY_MODE_MASK 0x0C + +/* REG_INT_SOURCE6_MREG_TOP1 */ +#define BIT_INT_TLT_DET_INT1_EN 0x08 +#define BIT_INT_STEP_CNT_OVFL_INT1_EN 0x10 +#define BIT_INT_STEP_DET_INT1_EN 0x20 +#define BIT_INT_LOWG_INT1_EN 0x40 +#define BIT_INT_FF_INT1_EN 0x80 + +/* REG_TMST_CONFIG1_MREG_TOP1 */ +#define BIT_TMST_EN 0x01 +#define BIT_TMST_FSYNC_EN 0x02 +#define BIT_TMST_DELTA_EN 0x04 +#define BIT_TMST_RESOL 0x08 +#define BIT_TMST_ON_SREG_EN 0x10 +#define BIT_ODR_EN_WITHOUT_SENSOR 0x40 + +/* REG_FIFO_CONFIG5_MREG_TOP1 */ +#define BIT_FIFO_ACCEL_EN 0x01 +#define BIT_FIFO_GYRO_EN 0x02 +#define BIT_FIFO_TMST_FSYNC_EN 0x04 +#define BIT_FIFO_HIRES_EN 0x08 +#define BIT_RESUME_PARTIAL_RD 0x10 +#define BIT_WM_GT_TH 0x20 + +/* REG_SELFTEST_MREG_TOP1 */ +#define BIT_EN_AX_ST 0x01 +#define BIT_EN_AY_ST 0x02 +#define BIT_EN_AZ_ST 0x04 +#define BIT_EN_GX_ST 0x08 +#define BIT_EN_GY_ST 0x10 +#define BIT_EN_GZ_ST 0x20 +#define BIT_ACCEL_ST_EN 0x40 +#define BIT_GYRO_ST_EN 0x80 + +/* REG_ST_CONFIG_MREG_TOP1 */ +#define BIT_PD_ACCEL_CP45_ST_REG 0x80 +#define SHIFT_GYRO_ST_LIM 0 +#define SHIFT_ACCEL_ST_LIM 3 +#define SHIFT_ST_NUM_SAMPLE 6 + +/* REG_ST_STATUS1_MREG_TOP1 */ +#define BIT_DMP_AX_ST_PASS 0x02 +#define BIT_DMP_AY_ST_PASS 0x04 +#define BIT_DMP_AZ_ST_PASS 0x08 +#define BIT_DMP_ACCEL_ST_DONE 0x10 +#define BIT_DMP_ACCEL_ST_PASS 0x20 + +/* REG_ST_STATUS2_MREG_TOP1 */ +#define BIT_DMP_GX_ST_PASS 0x02 +#define BIT_DMP_GY_ST_PASS 0x04 +#define BIT_DMP_GZ_ST_PASS 0x08 +#define BIT_DMP_GYRO_ST_DONE 0x10 +#define BIT_DMP_GYRO_ST_PASS 0x20 +#define BIT_DMP_ST_INCOMPLETE 0x40 + +/* REG_OTP_CTRL7_MREG_OTP */ +#define BIT_OTP_RELOAD 0x08 +#define BIT_OTP_PWR_DOWN 0x02 + + +/* fifo data packet header */ +#define BIT_FIFO_HEAD_MSG 0x80 +#define BIT_FIFO_HEAD_ACCEL 0x40 +#define BIT_FIFO_HEAD_GYRO 0x20 +#define BIT_FIFO_HEAD_20 0x10 +#define BIT_FIFO_HEAD_TMSP_ODR 0x08 +#define BIT_FIFO_HEAD_TMSP_NO_ODR 0x04 +#define BIT_FIFO_HEAD_TMSP_FSYNC 0x0C +#define BIT_FIFO_HEAD_ODR_ACCEL 0x02 +#define BIT_FIFO_HEAD_ODR_GYRO 0x01 + +/* data definitions */ +#define FIFO_PACKET_BYTE_SINGLE 8 +#define FIFO_PACKET_BYTE_6X 16 +#define FIFO_PACKET_BYTE_HIRES 20 +#define FIFO_COUNT_BYTE 2 + +/* sensor startup time */ +#define INV_ICM43600_GYRO_START_TIME 100 +#define INV_ICM43600_ACCEL_START_TIME 100 + +/* sensor stop time */ +#define INV_ICM43600_GYRO_STOP_TIME 20 + +/* M-reg access wait tile */ +#define INV_ICM42607_MCLK_WAIT_US 20 +#define INV_ICM42607_BLK_SEL_WAIT_US 10 +#define INV_ICM42607_MADDR_WAIT_US 10 +#define INV_ICM42607_M_RW_WAIT_US 10 + +/* temperature sensor */ +#define TEMP_SCALE 100 /* scale by 100 */ +#define TEMP_LSB_PER_DEG 2 /* 2LSB=1degC */ +#define TEMP_OFFSET 25 /* 25 degC */ + +/* + * INT configurations + * Polarity: 0 -> Active Low, 1 -> Active High + * Drive circuit: 0 -> Open Drain, 1 -> Push-Pull + * Mode: 0 -> Pulse, 1 -> Latch + */ +#define INT_POLARITY 1 +#define INT_DRIVE_CIRCUIT 1 +#define INT_MODE 0 + +#define ICM42607_CHIP_ID 0x61 + +struct imu_info *icm42607_chip_probe(struct imu_ctrb *ctrb); + +#endif diff --git a/drivers/iio/imu/inv_icm42607/imu.h b/drivers/iio/imu/inv_icm42607/imu.h new file mode 100644 index 000000000000..a209447a22b4 --- /dev/null +++ b/drivers/iio/imu/inv_icm42607/imu.h @@ -0,0 +1,91 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2025 Rockchip Electronics Co., Ltd. + */ + +#ifndef __IMU_H__ +#define __IMU_H__ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +enum imu_power_mode { + IMU_POWER_MODE_INIT = 0, + IMU_POWER_MODE_DOWN = 1, + IMU_POWER_ACCE_ONLY = 2, + IMU_POWER_ACCE_GYRO = 3, +}; + +enum imu_sensor_id { + IMU_SENSOR_ID_ACCE = 0, + IMU_SENSOR_ID_GYRO, + IMU_SENSOR_ID_MAX +}; + +enum imu_position_id { + IMU_P_D_0 = 0, + IMU_P_D_90 = 1, + IMU_P_D_180 = 2, + IMU_P_D_270 = 3, + IMU_D_MAX +}; + +struct imu_3axis_data { + int16_t raw[3]; + s64 ts; +}; + +struct imu_info { + char name[30]; + int id; + int (*read_id)(void *ctrbp); + int (*mode_set)(void *ctrbp, int mode); + int (*chip_init)(void *ctrbp); + int (*read_acce_raw)(void *ctrbp, void *rawdata); + int (*read_gyro_raw)(void *ctrbp, void *rawdata); + int (*read_asix_one)(void *ctrbp, int addr, int *datap); + int (*set_accel_offset)(void *ctrbp, int offset, int axis); + int (*set_gyro_offset)(void *ctrbp, int offset, int axis); +}; + +struct imu_ctrb { + struct device *dev; + struct regmap *regmap; + struct iio_dev *iio_devs[IMU_SENSOR_ID_MAX]; + struct mutex power_lock; + struct delayed_work pollingwork; + struct imu_info *chipinfo; + int irq; + int mode; + int debugon; + int position; + bool irq_enable; +}; + +struct imu_sensor { + char name[32]; + enum imu_sensor_id id; + struct imu_ctrb *ctrb; + unsigned int odr; + int calibrated; + int32_t offset_x; + int32_t offset_y; + int32_t offset_z; + uint32_t readcnt; + struct imu_3axis_data rawdata; +}; + +struct imu_reg_value_map { + uint8_t reg; + uint8_t value; +}; + +#define IMU_POLLING_TIME_MS (10) +#endif diff --git a/drivers/iio/imu/inv_icm42607/invimu_core.c b/drivers/iio/imu/inv_icm42607/invimu_core.c new file mode 100644 index 000000000000..2020d1bf569c --- /dev/null +++ b/drivers/iio/imu/inv_icm42607/invimu_core.c @@ -0,0 +1,270 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2025 Rockchip Electronics Co., Ltd. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "icm42607.h" +#include "invimu_iio.h" +#include "invimu_core.h" +#include "imu.h" + +static ssize_t invimu_debug_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t size) +{ + int val = -1; + struct iio_dev *indio_dev = dev_to_iio_dev(dev); + struct imu_sensor *sensor = iio_priv(indio_dev); + struct imu_ctrb *ctrb = sensor->ctrb; + + if (sscanf(buf, "%d\n", &val) != 1) { + dev_err(ctrb->dev, "debugon para err\n"); + return -1; + } + ctrb->debugon = val; + dev_info(ctrb->dev, "debugon set %d\n", val); + return size; +} + +static IIO_DEVICE_ATTR(in_imu_debug, 0200, NULL, invimu_debug_store, 0); + +static struct attribute *invimu_accel_attributes[] = { + &iio_dev_attr_in_imu_debug.dev_attr.attr, + NULL, +}; + +static const struct attribute_group invimu_accel_attribute_group = { + .attrs = invimu_accel_attributes, +}; + +static const struct iio_info invimu_acc_info = { + .attrs = &invimu_accel_attribute_group, + .read_raw = invimu_read_raw, + .read_avail = invimu_read_avail, + .write_raw = invimu_write_raw, + .write_raw_get_fmt = invimu_write_raw_get_fmt, +}; + +static struct attribute *invimu_anglvel_attributes[] = { + NULL, +}; + +static const struct attribute_group invimu_anglvel_attribute_group = { + .attrs = invimu_anglvel_attributes, +}; + +static const struct iio_info invimu_gryo_info = { + .attrs = &invimu_anglvel_attribute_group, + .read_raw = invimu_read_raw, + .read_avail = invimu_read_avail, + .write_raw = invimu_write_raw, + .write_raw_get_fmt = invimu_write_raw_get_fmt, +}; + +static void invimu_axis_transposition(struct imu_3axis_data *rawdata, int position) +{ + struct imu_3axis_data tempdata; + + memcpy(&tempdata, rawdata, sizeof(struct imu_3axis_data)); + if (position == IMU_P_D_90) { + rawdata->raw[0] = tempdata.raw[1]; + rawdata->raw[1] = 0 - tempdata.raw[0]; + rawdata->raw[2] = tempdata.raw[2]; + } else if (position == IMU_P_D_270) { + rawdata->raw[0] = tempdata.raw[1]; + rawdata->raw[1] = tempdata.raw[0]; + rawdata->raw[2] = tempdata.raw[2]; + } else if (position == IMU_P_D_180) { + rawdata->raw[0] = tempdata.raw[0]; + rawdata->raw[1] = -tempdata.raw[1]; + rawdata->raw[2] = tempdata.raw[2]; + } +} + +static void invimu_axis_print(struct imu_ctrb *ctrb, struct imu_sensor *sensor) +{ + int print_on = 0; + + if (ctrb == NULL || sensor == NULL) + return; + + print_on = (sensor->readcnt != 0) && ((sensor->readcnt % 6000) == 0); + print_on = (print_on) || (ctrb->debugon); + if (print_on) { + if (sensor->id == IMU_SENSOR_ID_ACCE) { + dev_info(ctrb->dev, "acce read cnt=%d, raw=%d,%d,%d\n", sensor->readcnt, + sensor->rawdata.raw[0], + sensor->rawdata.raw[1], + sensor->rawdata.raw[2]); + dev_info(ctrb->dev, "acce calib offset=%d,%d,%d\n", + sensor->offset_x, sensor->offset_y, sensor->offset_z); + } + if (sensor->id == IMU_SENSOR_ID_GYRO) { + dev_info(ctrb->dev, "gyro read cnt=%d, raw=%d,%d,%d\n", sensor->readcnt, + sensor->rawdata.raw[0], + sensor->rawdata.raw[1], + sensor->rawdata.raw[2]); + dev_info(ctrb->dev, "gyro calib offset=%d,%d,%d\n", + sensor->offset_x, sensor->offset_y, sensor->offset_z); + } + } +} + +static int invimu_data_report(struct imu_ctrb *ctrb) +{ + int i, ret = 0; + struct iio_dev *indio_dev; + struct imu_sensor *sensor; + struct imu_3axis_data rawdata; + + if (ctrb == NULL) + return -1; + + for (i = 0; i < IMU_SENSOR_ID_MAX; i++) { + indio_dev = ctrb->iio_devs[i]; + sensor = iio_priv(indio_dev); + + if (iio_buffer_enabled(indio_dev)) { + memset(&rawdata, 0, sizeof(struct imu_3axis_data)); + sensor->readcnt++; + switch (sensor->id) { + case IMU_SENSOR_ID_ACCE: + ret = ctrb->chipinfo->read_acce_raw(ctrb, &rawdata); + break; + case IMU_SENSOR_ID_GYRO: + ret = ctrb->chipinfo->read_gyro_raw(ctrb, &rawdata); + break; + default: + continue; + } + invimu_axis_transposition(&rawdata, ctrb->position); + memcpy(&sensor->rawdata, &rawdata, sizeof(struct imu_3axis_data)); + iio_push_to_buffers_with_timestamp(indio_dev, + &rawdata, ktime_get_boottime_ns()); + invimu_axis_print(ctrb, sensor); + //invimu_calibrator_process(ctrb, sensor); + } + } + return ret; +} + +static void invimu_work_handler(struct work_struct *work) +{ + struct imu_ctrb *ctrb; + + ctrb = (struct imu_ctrb *)container_of(work, struct imu_ctrb, pollingwork.work); + invimu_data_report(ctrb); + schedule_delayed_work(&ctrb->pollingwork, msecs_to_jiffies(IMU_POLLING_TIME_MS)); +} + +int invimu_chip_init(struct imu_ctrb *ctrb, bool use_spi) +{ + if (ctrb == NULL) + return -1; + + return ctrb->chipinfo->chip_init(ctrb); +} +EXPORT_SYMBOL_GPL(invimu_chip_init); + +static int invimu_parse_dt_parameters(struct device *dev, struct imu_ctrb *ctrb) +{ + int position = 0; + struct device_node *np = dev->of_node; + + ctrb->position = 0; + if (np != NULL) { + if (of_property_read_s32(np, "position", &position) == 0) { + if (position < IMU_P_D_0 || position >= IMU_D_MAX) + goto HWCIMU_PARSE_DT_ERR; + else + ctrb->position = position; + } else { + goto HWCIMU_PARSE_DT_ERR; + } + } else { + goto HWCIMU_PARSE_DT_ERR; + } + dev_info(ctrb->dev, "imu position sets %d\n", ctrb->position); + return 0; + +HWCIMU_PARSE_DT_ERR: + dev_err(ctrb->dev, "imu position sets default %d\n", ctrb->position); + return -ENODEV; +} + +int invimu_core_probe(struct device *dev, struct regmap *regmap, int irq, bool use_spi) +{ + int i, ret = 0; + struct imu_ctrb *ctrb; + struct imu_info *info = NULL; + + ctrb = devm_kzalloc(dev, sizeof(*ctrb), GFP_KERNEL); + if (!ctrb) + return -ENOMEM; + + dev_set_drvdata(dev, (void *)ctrb); + mutex_init(&ctrb->power_lock); + ctrb->dev = dev; + ctrb->regmap = regmap; + ctrb->irq = irq; + ctrb->debugon = 0; + dev_info(ctrb->dev, "probe start\n"); + + info = icm42607_chip_probe(ctrb); + if (info == NULL) { + dev_err(ctrb->dev, "no chip probed!\n"); + return -ENODEV; + } + ctrb->chipinfo = info; + + ret = invimu_chip_init(ctrb, use_spi); + if (ret) { + dev_err(ctrb->dev, "chip err\n"); + return ret; + } + + for (i = 0; i < IMU_SENSOR_ID_MAX; i++) { + ctrb->iio_devs[i] = invimu_alloc_iiodev(ctrb, + &invimu_acc_info, &invimu_gryo_info, i, ctrb->chipinfo->name); + if (!ctrb->iio_devs[i]) { + dev_err(ctrb->dev, "iio alloc err\n"); + return -ENOMEM; + } + ret = devm_iio_device_register(ctrb->dev, ctrb->iio_devs[i]); + if (ret) { + dev_err(ctrb->dev, "iio register err\n"); + return ret; + } + } + + invimu_parse_dt_parameters(dev, ctrb); + INIT_DELAYED_WORK(&ctrb->pollingwork, invimu_work_handler); + + dev_info(ctrb->dev, "probe end\n"); + return 0; +} +EXPORT_SYMBOL_GPL(invimu_core_probe); + +MODULE_DESCRIPTION("inv imu driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/iio/imu/inv_icm42607/invimu_core.h b/drivers/iio/imu/inv_icm42607/invimu_core.h new file mode 100644 index 000000000000..b5cd6b1a912c --- /dev/null +++ b/drivers/iio/imu/inv_icm42607/invimu_core.h @@ -0,0 +1,10 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2025 Rockchip Electronics Co., Ltd. + */ +#ifndef __INVIMU_CORE_H +#define __INVIMU_CORE_H + +int invimu_chip_init(struct imu_ctrb *ctrb, bool use_spi); +int invimu_core_probe(struct device *dev, struct regmap *regmap, int irq, bool use_spi); +#endif diff --git a/drivers/iio/imu/inv_icm42607/invimu_i2c.c b/drivers/iio/imu/inv_icm42607/invimu_i2c.c new file mode 100644 index 000000000000..0a1800cefc98 --- /dev/null +++ b/drivers/iio/imu/inv_icm42607/invimu_i2c.c @@ -0,0 +1,109 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2025 Rockchip Electronics Co., Ltd. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "imu.h" +#include "invimu_core.h" + +static bool invimu_writeable_reg(struct device *dev, unsigned int reg); +static bool invimu_volatile_reg(struct device *dev, unsigned int reg); + +const struct regmap_config invimu_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + .max_register = 0xff, + .cache_type = REGCACHE_RBTREE, + .writeable_reg = invimu_writeable_reg, + .volatile_reg = invimu_volatile_reg, +}; + +static bool invimu_writeable_reg(struct device *dev, unsigned int reg) +{ + return true; +} + +static bool invimu_volatile_reg(struct device *dev, unsigned int reg) +{ + return true; +} + +static int invimu_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id) +{ + struct regmap *regmap; + + regmap = devm_regmap_init_i2c(client, &invimu_regmap_config); + if (IS_ERR(regmap)) { + dev_err(&client->dev, "Failed to register i2c regmap: %p\n", regmap); + return PTR_ERR(regmap); + } + return invimu_core_probe(&client->dev, regmap, client->irq, false); +} + +static int invimu_suspend(struct device *dev) +{ + dev_info(dev, "inv_imu suspend\n"); + return 0; +} + +static int invimu_resume(struct device *dev) +{ + int ret; + struct imu_ctrb *ctrb = dev_get_drvdata(dev); + + ret = invimu_chip_init(ctrb, false); + dev_info(dev, "inv_imu resume:%d\n", ret); + return ret; +} + +static const struct dev_pm_ops invimu_pm_ops = { + .suspend = invimu_suspend, + .resume = invimu_resume, +}; + +#ifdef CONFIG_OF +static const struct of_device_id invimu_of_match[] = { + { .compatible = "inv,icm42607"}, + { }, +}; +MODULE_DEVICE_TABLE(of, invimu_of_match); +#endif + +static struct i2c_driver invimu_i2c_driver = { + .driver = { + .owner = THIS_MODULE, + .name = "invimu_i2c", + .pm = &invimu_pm_ops, + .of_match_table = of_match_ptr(invimu_of_match), + }, + .probe = invimu_i2c_probe, +}; + +static int32_t __init invimu_driver_init(void) +{ + return i2c_add_driver(&invimu_i2c_driver); +} + +static void __exit invimu_driver_exit(void) +{ + i2c_del_driver(&invimu_i2c_driver); +} + +late_initcall(invimu_driver_init); +module_exit(invimu_driver_exit); + +MODULE_DESCRIPTION("INV ICM42607 I2C driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/iio/imu/inv_icm42607/invimu_iio.c b/drivers/iio/imu/inv_icm42607/invimu_iio.c new file mode 100644 index 000000000000..ab5dfeb5526f --- /dev/null +++ b/drivers/iio/imu/inv_icm42607/invimu_iio.c @@ -0,0 +1,295 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2025 Rockchip Electronics Co., Ltd. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "icm42607.h" +#include "imu.h" +#include "invimu_iio.h" + +#define INVIMU_CHANNEL(_type, _address, _channel2, _scan_index) \ +{ \ + .type = _type, \ + .address = _address, \ + .modified = 1, \ + .channel2 = _channel2, \ + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \ + BIT(IIO_CHAN_INFO_OFFSET) | BIT(IIO_CHAN_INFO_SCALE), \ + .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ), \ + .info_mask_shared_by_all_available = BIT(IIO_CHAN_INFO_SAMP_FREQ), \ + .scan_index = _scan_index, \ + .scan_type = { \ + .sign = 's', \ + .realbits = 16, \ + .storagebits = 16, \ + .endianness = IIO_LE, \ + }, \ +} + +static const int icm42607_avail_acc_sample_freqs[] = {100}; +static const int icm42607_avail_gyro_sample_freqs[] = {100}; + +int invimu_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, int *val, int *val2, long mask) +{ + struct imu_sensor *sensor = iio_priv(indio_dev); + struct imu_ctrb *ctrb = sensor->ctrb; + + switch (mask) { + case IIO_CHAN_INFO_RAW: + ctrb->chipinfo->read_asix_one(ctrb, chan->address, val); + return IIO_VAL_INT; + case IIO_CHAN_INFO_SCALE: + if (sensor->id == IMU_SENSOR_ID_ACCE) { + *val = 980665ULL; + *val2 = 100000ULL * 2048;/* scale = 9.8 / 2048 */ + } else if (sensor->id == IMU_SENSOR_ID_GYRO) { + *val = 314159ULL; + *val2 = 1800000ULL * 143;/* scale = pi / (180 * 14.3) */ + } else { + return -EINVAL; + } + return IIO_VAL_FRACTIONAL; + case IIO_CHAN_INFO_OFFSET: + if (chan->channel2 == IIO_MOD_X) + *val = sensor->offset_x; + else if (chan->channel2 == IIO_MOD_Y) + *val = sensor->offset_y; + else if (chan->channel2 == IIO_MOD_Z) + *val = sensor->offset_z; + else + return -EINVAL; + + return IIO_VAL_INT; + case IIO_CHAN_INFO_SAMP_FREQ: + *val = sensor->odr; + return IIO_VAL_INT; + default: + return -EINVAL; + } + return IIO_VAL_INT; +} +EXPORT_SYMBOL_GPL(invimu_read_raw); + +int invimu_read_avail(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, const int **vals, int *type, int *length, long mask) +{ + struct imu_sensor *sensor = iio_priv(indio_dev); + + switch (mask) { + case IIO_CHAN_INFO_SAMP_FREQ: + *type = IIO_VAL_INT; + switch (sensor->id) { + case IMU_SENSOR_ID_ACCE: + *vals = icm42607_avail_acc_sample_freqs; + *length = ARRAY_SIZE(icm42607_avail_acc_sample_freqs); + return IIO_AVAIL_LIST; + case IMU_SENSOR_ID_GYRO: + *vals = icm42607_avail_gyro_sample_freqs; + *length = ARRAY_SIZE(icm42607_avail_gyro_sample_freqs); + return IIO_AVAIL_LIST; + default: + return -EINVAL; + } + default: + return -EINVAL; + } +} +EXPORT_SYMBOL_GPL(invimu_read_avail); + +int invimu_write_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, int val, int val2, long mask) +{ + struct imu_sensor *sensor = iio_priv(indio_dev); + struct imu_ctrb *ctrb = sensor->ctrb; + + switch (mask) { + case IIO_CHAN_INFO_SCALE: + break; + case IIO_CHAN_INFO_SAMP_FREQ: + sensor->odr = val; + break; + case IIO_CHAN_INFO_OFFSET: + switch (chan->channel2) { + case IIO_MOD_X: + sensor->offset_x = val; + break; + case IIO_MOD_Y: + sensor->offset_y = val; + break; + case IIO_MOD_Z: + sensor->offset_z = val; + break; + default: + return -EINVAL; + } + + if (sensor->id == IMU_SENSOR_ID_ACCE) + return ctrb->chipinfo->set_accel_offset(ctrb, val, chan->channel2); + else if (sensor->id == IMU_SENSOR_ID_GYRO) + return ctrb->chipinfo->set_gyro_offset(ctrb, val, chan->channel2); + else + return -EINVAL; + default: + return -EINVAL; + } + return 0; +} +EXPORT_SYMBOL_GPL(invimu_write_raw); + +int invimu_write_raw_get_fmt(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, long mask) +{ + switch (mask) { + case IIO_CHAN_INFO_SCALE: + return IIO_VAL_INT; + case IIO_CHAN_INFO_SAMP_FREQ: + return IIO_VAL_INT; + default: + return -EINVAL; + } +} +EXPORT_SYMBOL_GPL(invimu_write_raw_get_fmt); + +static const struct iio_chan_spec invimu_acc_channels[] = { + INVIMU_CHANNEL(IIO_ACCEL, 0, IIO_MOD_X, 0), + INVIMU_CHANNEL(IIO_ACCEL, 1, IIO_MOD_Y, 1), + INVIMU_CHANNEL(IIO_ACCEL, 2, IIO_MOD_Z, 2), + IIO_CHAN_SOFT_TIMESTAMP(3), +}; + +static const struct iio_chan_spec invimu_gyro_channels[] = { + INVIMU_CHANNEL(IIO_ANGL_VEL, 3, IIO_MOD_X, 0), + INVIMU_CHANNEL(IIO_ANGL_VEL, 4, IIO_MOD_Y, 1), + INVIMU_CHANNEL(IIO_ANGL_VEL, 5, IIO_MOD_Z, 2), + IIO_CHAN_SOFT_TIMESTAMP(3), +}; + +static int invimu_buffer_preenable(struct iio_dev *indio_dev) +{ + int mode, ret = 0; + struct imu_sensor *sensor = iio_priv(indio_dev); + struct imu_ctrb *ctrb = sensor->ctrb; + + mutex_lock(&ctrb->power_lock); + + switch (sensor->id) { + case IMU_SENSOR_ID_ACCE: + mode = iio_buffer_enabled(ctrb->iio_devs[IMU_SENSOR_ID_GYRO]) ? + IMU_POWER_ACCE_GYRO : IMU_POWER_ACCE_ONLY; + break; + case IMU_SENSOR_ID_GYRO: + mode = IMU_POWER_ACCE_GYRO; + break; + default: + mode = IMU_POWER_MODE_DOWN; + break; + } + ret = ctrb->chipinfo->mode_set(ctrb, mode); + + if (ret == 0 && (mode == IMU_POWER_ACCE_ONLY || mode == IMU_POWER_ACCE_GYRO)) + schedule_delayed_work(&ctrb->pollingwork, msecs_to_jiffies(IMU_POLLING_TIME_MS)); + + mutex_unlock(&ctrb->power_lock); + return ret; +} + +static int invimu_buffer_postdisable(struct iio_dev *indio_dev) +{ + int ret = 0, mode = 0; + struct imu_sensor *sensor = iio_priv(indio_dev); + struct imu_ctrb *ctrb = sensor->ctrb; + + mutex_lock(&ctrb->power_lock); + + switch (sensor->id) { + case IMU_SENSOR_ID_ACCE: + mode = iio_buffer_enabled(ctrb->iio_devs[IMU_SENSOR_ID_GYRO]) ? + IMU_POWER_ACCE_GYRO : IMU_POWER_MODE_DOWN; + break; + case IMU_SENSOR_ID_GYRO: + mode = iio_buffer_enabled(ctrb->iio_devs[IMU_SENSOR_ID_ACCE]) ? + IMU_POWER_ACCE_ONLY : IMU_POWER_MODE_DOWN; + break; + default: + mode = IMU_POWER_MODE_DOWN; + break; + } + ret = ctrb->chipinfo->mode_set(ctrb, mode); + if (ret == 0 && mode == IMU_POWER_MODE_DOWN) + cancel_delayed_work(&ctrb->pollingwork); + + mutex_unlock(&ctrb->power_lock); + return ret; +} + +static const struct iio_buffer_setup_ops invimu_buffer_ops = { + .preenable = invimu_buffer_preenable, + .postdisable = invimu_buffer_postdisable, +}; + +struct iio_dev *invimu_alloc_iiodev(struct imu_ctrb *ctrb, + const struct iio_info *acce_iio_info, const struct iio_info *gyro_iio_info, + enum imu_sensor_id id, char *name) +{ + struct imu_sensor *sensor; + struct iio_dev *indio_dev; + + indio_dev = devm_iio_device_alloc(ctrb->dev, sizeof(*sensor)); + if (!indio_dev) + return NULL; + + indio_dev->modes = INDIO_DIRECT_MODE | INDIO_BUFFER_SOFTWARE; + + devm_iio_kfifo_buffer_setup(ctrb->dev, indio_dev, &invimu_buffer_ops); + + sensor = iio_priv(indio_dev); + sensor->id = id; + sensor->ctrb = ctrb; + + switch (id) { + case IMU_SENSOR_ID_ACCE: + sensor->odr = icm42607_avail_acc_sample_freqs[0]; + indio_dev->info = acce_iio_info; + indio_dev->channels = invimu_acc_channels; + indio_dev->num_channels = ARRAY_SIZE(invimu_acc_channels); + scnprintf(sensor->name, sizeof(sensor->name), "%s_accel", name); + break; + case IMU_SENSOR_ID_GYRO: + sensor->odr = icm42607_avail_gyro_sample_freqs[0]; + indio_dev->info = gyro_iio_info; + indio_dev->channels = invimu_gyro_channels; + indio_dev->num_channels = ARRAY_SIZE(invimu_gyro_channels); + scnprintf(sensor->name, sizeof(sensor->name), "%s_gyro", name); + break; + default: + return NULL; + } + + indio_dev->name = sensor->name; + return indio_dev; +} +EXPORT_SYMBOL_GPL(invimu_alloc_iiodev); diff --git a/drivers/iio/imu/inv_icm42607/invimu_iio.h b/drivers/iio/imu/inv_icm42607/invimu_iio.h new file mode 100644 index 000000000000..f4948a201bc1 --- /dev/null +++ b/drivers/iio/imu/inv_icm42607/invimu_iio.h @@ -0,0 +1,34 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2025 Rockchip Electronics Co., Ltd. + */ + +#ifndef __INVIMU_IIO_H +#define __INVIMU_IIO_H + +#include +#include +#include +#include +#include +#include +#include +#include + +int invimu_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, int *val, int *val2, long mask); + +int invimu_read_avail(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, const int **vals, int *type, int *length, long mask); + +int invimu_write_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, int val, int val2, long mask); + +int invimu_write_raw_get_fmt(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, long mask); + +struct iio_dev *invimu_alloc_iiodev(struct imu_ctrb *ctrb, + const struct iio_info *acce_iio_info, const struct iio_info *gyro_iio_info, + enum imu_sensor_id id, char *name); + +#endif From 74626d61eceaa2224ab9a1059c144276a67c25c9 Mon Sep 17 00:00:00 2001 From: Zefa Chen Date: Mon, 29 Sep 2025 11:10:42 +0800 Subject: [PATCH 24/40] media: rockchip: vicap fixes error info of fps with toisp mode Change-Id: I661b19466f3bbaece2db9a700f3c17010a57cb66 Signed-off-by: Zefa Chen --- drivers/media/platform/rockchip/cif/capture.c | 28 +++++++++---------- drivers/media/platform/rockchip/cif/dev.h | 2 ++ drivers/media/platform/rockchip/cif/procfs.c | 7 +++-- 3 files changed, 20 insertions(+), 17 deletions(-) diff --git a/drivers/media/platform/rockchip/cif/capture.c b/drivers/media/platform/rockchip/cif/capture.c index 4693ab164847..11c78b9e442e 100644 --- a/drivers/media/platform/rockchip/cif/capture.c +++ b/drivers/media/platform/rockchip/cif/capture.c @@ -12122,7 +12122,6 @@ static void rkcif_line_wake_up_rdbk(struct rkcif_stream *stream, int mipi_id) active_buf->dbufs.sequence = stream->sequence; active_buf->dbufs.timestamp = stream->readout.fs_timestamp; active_buf->fe_timestamp = rkcif_time_get_ns(stream->cifdev); - stream->last_frame_idx = stream->frame_idx; if (stream->cifdev->hdr.hdr_mode == NO_HDR) { rkcif_s_rx_buffer(stream, &active_buf->dbufs); if (stream->cifdev->is_support_tools && stream->tools_vdev) @@ -12139,9 +12138,12 @@ static void rkcif_deal_readout_time(struct rkcif_stream *stream) struct rkcif_device *cif_dev = stream->cifdev; struct rkcif_stream *detect_stream = &cif_dev->stream[0]; unsigned long flags; + u64 cur_time = 0; spin_lock_irqsave(&stream->fps_lock, flags); - stream->readout.fe_timestamp = rkcif_time_get_ns(cif_dev); + cur_time = rkcif_time_get_ns(cif_dev); + stream->readout.rate_time = cur_time - stream->readout.fe_timestamp; + stream->readout.fe_timestamp = cur_time; if (cif_dev->inf_id == RKCIF_DVP) { spin_unlock_irqrestore(&stream->fps_lock, flags); @@ -12241,7 +12243,8 @@ static void rkcif_update_stream_interlace(struct rkcif_device *cif_dev, } } } - rkcif_deal_readout_time(stream); + if (!cif_dev->sditf[0] || cif_dev->sditf[0]->mode.rdbk_mode >= RKISP_VICAP_RDBK_AIQ) + rkcif_deal_readout_time(stream); stream->last_fe_interlaced_phase = fe_interlaced_phase; } @@ -12273,7 +12276,8 @@ static void rkcif_update_stream(struct rkcif_device *cif_dev, spin_unlock_irqrestore(&stream->fps_lock, flags); } - rkcif_deal_readout_time(stream); + if (!cif_dev->sditf[0] || cif_dev->sditf[0]->mode.rdbk_mode >= RKISP_VICAP_RDBK_AIQ) + rkcif_deal_readout_time(stream); if (!stream->is_line_wake_up) { ret = rkcif_assign_new_buffer_pingpong(stream, @@ -12281,7 +12285,6 @@ static void rkcif_update_stream(struct rkcif_device *cif_dev, mipi_id); if (ret && cif_dev->chip_id < CHIP_RK3588_CIF) return; - stream->last_frame_idx = stream->frame_idx; } else { ret = rkcif_update_new_buffer_wake_up_mode(stream); if (ret && cif_dev->chip_id < CHIP_RK3588_CIF) @@ -12318,7 +12321,7 @@ static void rkcif_update_stream_toisp(struct rkcif_device *cif_dev, stream->fps_stats.frm1_timestamp = rkcif_time_get_ns(cif_dev); spin_unlock(&stream->fps_lock); - if (cif_dev->inf_id == RKCIF_MIPI_LVDS) + if (!cif_dev->sditf[0] || cif_dev->sditf[0]->mode.rdbk_mode >= RKISP_VICAP_RDBK_AIQ) rkcif_deal_readout_time(stream); if (!stream->is_line_wake_up) @@ -12355,7 +12358,7 @@ static void rkcif_update_stream_rockit(struct rkcif_device *cif_dev, spin_unlock_irqrestore(&stream->fps_lock, flags); } - if (cif_dev->inf_id == RKCIF_MIPI_LVDS) + if (!cif_dev->sditf[0] || cif_dev->sditf[0]->mode.rdbk_mode >= RKISP_VICAP_RDBK_AIQ) rkcif_deal_readout_time(stream); rkcif_assign_new_buffer_pingpong_rockit(stream, @@ -13913,7 +13916,6 @@ static void rkcif_toisp_check_stop_status(struct sditf_priv *priv, int src_id = 0; int i = 0; u32 val = 0; - u64 cur_time = 0; int on = 0; unsigned long flags; struct v4l2_subdev *sd = NULL; @@ -13946,12 +13948,6 @@ static void rkcif_toisp_check_stop_status(struct sditf_priv *priv, stream->stopping = false; wake_up(&stream->wq_stopped); } - if (!(stream->cur_stream_mode & RKCIF_STREAM_MODE_CAPTURE)) { - cur_time = rkcif_time_get_ns(stream->cifdev); - stream->readout.total_time = cur_time - stream->readout.fe_timestamp; - stream->readout.readout_time = cur_time - stream->readout.fs_timestamp; - stream->readout.fe_timestamp = cur_time; - } spin_lock_irqsave(&stream->cifdev->stream_spinlock, flags); if (stream->is_wait_stop_complete) { @@ -14026,6 +14022,9 @@ static void rkcif_toisp_check_stop_status(struct sditf_priv *priv, if (priv->mode.rdbk_mode == RKISP_VICAP_ONLINE_UNITE || priv->mode.rdbk_mode == RKISP_VICAP_ONLINE_MULTI) priv->is_toisp_off = true; + + rkcif_deal_readout_time(stream); + switch (ch) { case RKCIF_TOISP_CH0: if (priv->cif_dev->chip_id < CHIP_RK3576_CIF) @@ -15496,6 +15495,7 @@ void rkcif_irq_pingpong_v1(struct rkcif_device *cif_dev) stream->dma_en); rkcif_update_stream_rockit(cif_dev, stream, mipi_id); } + stream->last_frame_idx = stream->frame_idx; spin_lock_irqsave(&stream->cifdev->stream_spinlock, flags); if (stream->is_single_cap && !stream->cur_skip_frame) { stream->is_single_cap = false; diff --git a/drivers/media/platform/rockchip/cif/dev.h b/drivers/media/platform/rockchip/cif/dev.h index 1a54a894203b..b105dab45c39 100644 --- a/drivers/media/platform/rockchip/cif/dev.h +++ b/drivers/media/platform/rockchip/cif/dev.h @@ -364,6 +364,7 @@ struct rkcif_fps_stats { * @readout_time: one frame of readout time * @early_time: early time of buf send to user * @total_time: totaltime of readout time in hdr + * @rate_time: single frame interval */ struct rkcif_readout_stats { u64 fs_timestamp; @@ -372,6 +373,7 @@ struct rkcif_readout_stats { u64 readout_time; u64 early_time; u64 total_time; + u64 rate_time; }; /* struct rkcif_irq_stats - take notes on irq number diff --git a/drivers/media/platform/rockchip/cif/procfs.c b/drivers/media/platform/rockchip/cif/procfs.c index 6122ab4ff2c8..ce08b5abdcc2 100644 --- a/drivers/media/platform/rockchip/cif/procfs.c +++ b/drivers/media/platform/rockchip/cif/procfs.c @@ -604,7 +604,7 @@ static void rkcif_show_format(struct rkcif_device *dev, struct seq_file *f) timestamp1 = stream->fps_stats.frm1_timestamp; spin_unlock_irqrestore(&stream->fps_lock, flags); if (dev->sditf[0] && dev->sditf[0]->mode.rdbk_mode < RKISP_VICAP_RDBK_AIQ) - fps = dev->stream[0].readout.total_time; + fps = dev->stream[0].readout.rate_time; else fps = timestamp0 > timestamp1 ? timestamp0 - timestamp1 : timestamp1 - timestamp0; @@ -638,8 +638,9 @@ static void rkcif_show_format(struct rkcif_device *dev, struct seq_file *f) } time_val = div_u64_rem(fps, 1000, &remainder); seq_printf(f, "\trate:%u.%u ms\n", time_val, remainder); - fps = div_u64(1000000, fps); - seq_printf(f, "\tfps:%llu\n", fps); + fps = div_u64(1000000000, fps); + time_val = div_u64_rem(fps, 1000, &remainder); + seq_printf(f, "\tfps:%u.%u \n", time_val, remainder); seq_puts(f, "\tirq statistics:\n"); seq_printf(f, "\t\t\ttotal:%llu\n", dev->irq_stats.frm_end_cnt[0] + From 69791e16c09b2c76923cbb1f6b2dbfa2c65b208e Mon Sep 17 00:00:00 2001 From: Zefa Chen Date: Sat, 20 Sep 2025 15:53:37 +0800 Subject: [PATCH 25/40] media: rockchip: vicap fixes error of stop stream with dvp Change-Id: I269440ee3cb46a6bdd3d7d46ebe83abe1d5595b2 Signed-off-by: Zefa Chen --- drivers/media/platform/rockchip/cif/capture.c | 34 +++++++++++++------ 1 file changed, 24 insertions(+), 10 deletions(-) diff --git a/drivers/media/platform/rockchip/cif/capture.c b/drivers/media/platform/rockchip/cif/capture.c index 11c78b9e442e..433fc334f6d0 100644 --- a/drivers/media/platform/rockchip/cif/capture.c +++ b/drivers/media/platform/rockchip/cif/capture.c @@ -5640,7 +5640,12 @@ static void rkcif_stream_stop(struct rkcif_stream *stream) } } else { - if (atomic_read(&cif_dev->pipe.stream_cnt) == 1) { + if (stream->cifdev->chip_id >= CHIP_RV1126B_CIF) { + val = rkcif_read_register(cif_dev, get_dvp_reg_index_of_id_ctrl0(stream->id)); + val &= ~(CSI_ENABLE_CAPTURE | CSI_DMA_ENABLE_RK3576); + rkcif_write_register(cif_dev, get_dvp_reg_index_of_id_ctrl0(stream->id), val); + } + if (atomic_read(&stream->cifdev->id_use_cnt) == 0) { val = rkcif_read_register(cif_dev, CIF_REG_DVP_CTRL); rkcif_write_register(cif_dev, CIF_REG_DVP_CTRL, val & (~ENABLE_CAPTURE)); @@ -7897,6 +7902,7 @@ static int rkcif_stream_start(struct rkcif_stream *stream, unsigned int mode) if (dma_state) return 0; + atomic_inc(&stream->cifdev->id_use_cnt); mbus_flags = mbus->bus.parallel.flags; if ((mbus_flags & CIF_DVP_PCLK_DUAL_EDGE) == CIF_DVP_PCLK_DUAL_EDGE) { bt1120_edge_mode = (dev->chip_id < CHIP_RK3588_CIF ? @@ -8264,6 +8270,7 @@ static int rkcif_stream_start_rv1126b(struct rkcif_stream *stream, unsigned int if (dma_state) return 0; + atomic_inc(&stream->cifdev->id_use_cnt); mbus_flags = mbus->bus.parallel.flags; if ((mbus_flags & CIF_DVP_PCLK_DUAL_EDGE) == CIF_DVP_PCLK_DUAL_EDGE) { bt1120_edge_mode = BT1120_CLOCK_DOUBLE_EDGES_RV1126B; @@ -13445,16 +13452,22 @@ static int rkcif_stop_dma_capture(struct rkcif_stream *stream) } rkcif_write_register(cif_dev, get_reg_index_of_lvds_id_ctrl0(stream->id), val); } else { - val = rkcif_read_register(cif_dev, CIF_REG_DVP_CTRL); - if (cif_dev->chip_id == CHIP_RK3588_CIF) - val &= ~DVP_DMA_EN; - else if (cif_dev->chip_id == CHIP_RV1106_CIF) - val &= ~(DVP_SW_DMA_EN(stream->id)); - if (stream->is_stop_capture) { - val &= ~ENABLE_CAPTURE; - stream->is_stop_capture = false; + if (stream->cifdev->chip_id >= CHIP_RV1126B_CIF) { + val = rkcif_read_register(cif_dev, get_dvp_reg_index_of_id_ctrl0(stream->id)); + val &= ~(CSI_ENABLE_CAPTURE | CSI_DMA_ENABLE_RK3576); + rkcif_write_register(cif_dev, get_dvp_reg_index_of_id_ctrl0(stream->id), val); + } else { + val = rkcif_read_register(cif_dev, CIF_REG_DVP_CTRL); + if (cif_dev->chip_id == CHIP_RK3588_CIF) + val &= ~DVP_DMA_EN; + else if (cif_dev->chip_id == CHIP_RV1106_CIF) + val &= ~(DVP_SW_DMA_EN(stream->id)); + if (stream->is_stop_capture) { + val &= ~ENABLE_CAPTURE; + stream->is_stop_capture = false; + } + rkcif_write_register(cif_dev, CIF_REG_DVP_CTRL, val); } - rkcif_write_register(cif_dev, CIF_REG_DVP_CTRL, val); } stream->to_stop_dma = 0; v4l2_dbg(4, rkcif_debug, &cif_dev->v4l2_dev, @@ -14249,6 +14262,7 @@ static void rkcif_deal_sof(struct rkcif_device *cif_dev) detect_stream->fs_cnt_in_single_frame++; if ((!cif_dev->sditf[0] || cif_dev->sditf[0]->mode.rdbk_mode >= RKISP_VICAP_RDBK_AIQ) && + cif_dev->inf_id == RKCIF_MIPI_LVDS && detect_stream->fs_cnt_in_single_frame > 1 && cif_dev->chip_id < CHIP_RK3588_CIF) return; From 3e9448b802151dab09dd4a487f1129d1c71a695d Mon Sep 17 00:00:00 2001 From: Zefa Chen Date: Sat, 20 Sep 2025 10:15:37 +0800 Subject: [PATCH 26/40] media: rockchip: vicap change stop dma to fs for dvp Change-Id: Ife6b32d141d4377f6a19f49e88946876f1cbd645 Signed-off-by: Zefa Chen --- drivers/media/platform/rockchip/cif/capture.c | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/drivers/media/platform/rockchip/cif/capture.c b/drivers/media/platform/rockchip/cif/capture.c index 433fc334f6d0..d03a2778f93a 100644 --- a/drivers/media/platform/rockchip/cif/capture.c +++ b/drivers/media/platform/rockchip/cif/capture.c @@ -15765,7 +15765,7 @@ void rkcif_irq_pingpong_v1(struct rkcif_device *cif_dev) cif_dev->sditf[0]->mode.rdbk_mode >= RKISP_VICAP_RDBK_AIQ) stream->buf_wake_up_cnt++; - if (stream->stopping) { + if (stream->stopping && (!stream->dma_en)) { rkcif_stream_stop(stream); stream->stopping = false; wake_up(&stream->wq_stopped); @@ -15830,6 +15830,23 @@ void rkcif_irq_pingpong_v1(struct rkcif_device *cif_dev) spin_unlock_irqrestore(&stream->fps_lock, flags); } stream->is_in_vblank = false; + spin_lock_irqsave(&stream->vbq_lock, flags); + if (stream->stopping && stream->dma_en) { + if (stream->dma_en & RKCIF_DMAEN_BY_VICAP) + stream->to_stop_dma = RKCIF_DMAEN_BY_VICAP; + else if (stream->dma_en & RKCIF_DMAEN_BY_ISP) + stream->to_stop_dma = RKCIF_DMAEN_BY_ISP; + stream->is_stop_capture = true; + } + if (stream->to_stop_dma) { + ret = rkcif_stop_dma_capture(stream); + if (!ret) { + stream->is_finish_stop_dma = true; + if (stream->is_wait_stop_complete) + stream->is_pause_stream = true; + } + } + spin_unlock_irqrestore(&stream->vbq_lock, flags); } } From fe51d80ff832296a46c94c69e190be1e225e74ee Mon Sep 17 00:00:00 2001 From: Zefa Chen Date: Tue, 30 Sep 2025 14:03:55 +0800 Subject: [PATCH 27/40] media: rockchip: vicap force update buffer addr when init stream Change-Id: I3bc59fdcc769e9beaeb303ca6f6b18dfb5b457fa Signed-off-by: Zefa Chen --- drivers/media/platform/rockchip/cif/capture.c | 67 ++++++++++--------- 1 file changed, 37 insertions(+), 30 deletions(-) diff --git a/drivers/media/platform/rockchip/cif/capture.c b/drivers/media/platform/rockchip/cif/capture.c index d03a2778f93a..1fa10183ed62 100644 --- a/drivers/media/platform/rockchip/cif/capture.c +++ b/drivers/media/platform/rockchip/cif/capture.c @@ -5041,10 +5041,25 @@ static int rkcif_csi_channel_set_v1(struct rkcif_stream *stream, channel->crop_st_y << 16 | (channel->crop_st_x + capture_info->multi_dev.pixel_offset)); + if (!(capture_info->mode == RKMODULE_MULTI_DEV_COMBINE_ONE && + index < capture_info->multi_dev.dev_num - 1)) { + if (mode == RKCIF_STREAM_MODE_CAPTURE) + rkcif_assign_new_buffer_pingpong(stream, + RKCIF_YUV_ADDR_STATE_INIT, + channel->id); + else if (mode == RKCIF_STREAM_MODE_TOISP || + mode == RKCIF_STREAM_MODE_TOISP_RDBK) + rkcif_assign_new_buffer_pingpong_toisp(stream, + RKCIF_YUV_ADDR_STATE_INIT, + channel->id); + } + val = channel->virtual_width; if (dev->chip_id >= CHIP_RV1103B_CIF && dev->sditf[0] && dev->sditf[0]->hdr_wrap_line) val |= dev->sditf[0]->hdr_wrap_line << 20; + if (dev->chip_id >= CHIP_RK3562_CIF) + val |= BIT(31); rkcif_write_register(dev, get_reg_index_of_frm0_y_vlw(channel->id), val); if (stream->lack_buf_cnt == 2) @@ -5172,18 +5187,7 @@ static int rkcif_csi_channel_set_v1(struct rkcif_stream *stream, } else { atomic_inc(&stream->cifdev->id_use_cnt); } - if (!(capture_info->mode == RKMODULE_MULTI_DEV_COMBINE_ONE && - index < capture_info->multi_dev.dev_num - 1)) { - if (mode == RKCIF_STREAM_MODE_CAPTURE) - rkcif_assign_new_buffer_pingpong(stream, - RKCIF_YUV_ADDR_STATE_INIT, - channel->id); - else if (mode == RKCIF_STREAM_MODE_TOISP || - mode == RKCIF_STREAM_MODE_TOISP_RDBK) - rkcif_assign_new_buffer_pingpong_toisp(stream, - RKCIF_YUV_ADDR_STATE_INIT, - channel->id); - } + dev->intr_mask = rkcif_read_register(dev, CIF_REG_MIPI_LVDS_INTEN); return 0; } @@ -5306,10 +5310,24 @@ static int rkcif_csi_channel_set_rv1126b(struct rkcif_stream *stream, channel->crop_st_y << 16 | (channel->crop_st_x + capture_info->multi_dev.pixel_offset)); + if (!(capture_info->mode == RKMODULE_MULTI_DEV_COMBINE_ONE && + index < capture_info->multi_dev.dev_num - 1)) { + if (mode == RKCIF_STREAM_MODE_CAPTURE) + rkcif_assign_new_buffer_pingpong(stream, + RKCIF_YUV_ADDR_STATE_INIT, + channel->id); + else if (mode == RKCIF_STREAM_MODE_TOISP || + mode == RKCIF_STREAM_MODE_TOISP_RDBK) + rkcif_assign_new_buffer_pingpong_toisp(stream, + RKCIF_YUV_ADDR_STATE_INIT, + channel->id); + } + val = channel->virtual_width; if (dev->sditf[0] && dev->sditf[0]->hdr_wrap_line) val |= dev->sditf[0]->hdr_wrap_line << 20; + val |= BIT(31); rkcif_write_register(dev, get_reg_index_of_frm0_y_vlw(channel->id), val); if (stream->lack_buf_cnt == 2) @@ -5387,18 +5405,7 @@ static int rkcif_csi_channel_set_rv1126b(struct rkcif_stream *stream, } else { atomic_inc(&stream->cifdev->id_use_cnt); } - if (!(capture_info->mode == RKMODULE_MULTI_DEV_COMBINE_ONE && - index < capture_info->multi_dev.dev_num - 1)) { - if (mode == RKCIF_STREAM_MODE_CAPTURE) - rkcif_assign_new_buffer_pingpong(stream, - RKCIF_YUV_ADDR_STATE_INIT, - channel->id); - else if (mode == RKCIF_STREAM_MODE_TOISP || - mode == RKCIF_STREAM_MODE_TOISP_RDBK) - rkcif_assign_new_buffer_pingpong_toisp(stream, - RKCIF_YUV_ADDR_STATE_INIT, - channel->id); - } + dev->intr_mask = rkcif_read_register(dev, CIF_REG_MIPI_LVDS_INTEN); return 0; } @@ -8313,7 +8320,6 @@ static int rkcif_stream_start_rv1126b(struct rkcif_stream *stream, unsigned int } } - val = stream->pixm.plane_fmt[0].bytesperline; if (stream->crop_enable) { dev->channels[stream->id].crop_en = 1; dev->channels[stream->id].crop_st_x = stream->crop[CROP_SRC_ACT].left; @@ -8328,10 +8334,6 @@ static int rkcif_stream_start_rv1126b(struct rkcif_stream *stream, unsigned int dev->channels[stream->id].crop_en = 0; } - if (dev->chip_id > CHIP_RK3562_CIF && stream->sw_dbg_en) - val = (val + 23) / 24 * 24; - - rkcif_write_register(dev, get_dvp_reg_index_of_vlw(stream->id), val); rkcif_write_register(dev, CIF_REG_DVP_SET_SIZE_ID0 + stream->id, dev->channels[stream->id].width | (dev->channels[stream->id].height << 16)); @@ -8358,6 +8360,11 @@ static int rkcif_stream_start_rv1126b(struct rkcif_stream *stream, unsigned int stream->id); } + val = stream->pixm.plane_fmt[0].bytesperline; + if (dev->chip_id > CHIP_RK3562_CIF && stream->sw_dbg_en) + val = (val + 23) / 24 * 24; + rkcif_write_register(dev, get_dvp_reg_index_of_vlw(stream->id), val | BIT(31)); + dev->workmode = RKCIF_WORKMODE_PINGPONG; href_pol = (mbus_flags & V4L2_MBUS_HSYNC_ACTIVE_HIGH) ? HSY_HIGH_ACTIVE : HSY_LOW_ACTIVE; @@ -13357,7 +13364,7 @@ void rkcif_enable_dma_capture(struct rkcif_stream *stream, bool is_only_enable) else if (cif_dev->chip_id < CHIP_RK3576_CIF) rkcif_write_register_or(cif_dev, CIF_REG_DVP_VIR_LINE_WIDTH, BIT(28) << stream->id); else - rkcif_write_register_or(cif_dev, CIF_REG_DVP_VIR_LINE_WIDTH, BIT(31)); + rkcif_write_register_or(cif_dev, get_dvp_reg_index_of_vlw(stream->id), BIT(31)); } if (mbus_cfg->type == V4L2_MBUS_CSI2_DPHY || mbus_cfg->type == V4L2_MBUS_CSI2_CPHY) { From 539fd979b625be20b72dfcf55b031d18a3d29b79 Mon Sep 17 00:00:00 2001 From: Zhang Yubing Date: Wed, 17 Jan 2024 10:35:00 +0800 Subject: [PATCH 28/40] drm/rockchip: dw-dp: support more feature active protocol converter adapters According to DP1.4a 5.3.3, To support more feature active protocol converte adapters. All the adapters are branch device, Read the Detailed Capabilities Info to get the branch type and the feature it support. For Example, the max dot clock for VGA, max TDMS clock for HDMI, the YCbCr420 support or not for HDMI 2.0, conversion to YCbCr420 from YCbCr444 or not for HDMI 2.0. According the feature of branch device, filter the resolution, color format and color depth that the branch device can't support. Change-Id: I640ce0e6324811875a9dabea846514bc3e42f915 Signed-off-by: Zhang Yubing --- drivers/gpu/drm/rockchip/dw-dp.c | 107 +++++++++++++++++++++++++++++-- 1 file changed, 103 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/rockchip/dw-dp.c b/drivers/gpu/drm/rockchip/dw-dp.c index a29212f42f78..1955bd7ed545 100644 --- a/drivers/gpu/drm/rockchip/dw-dp.c +++ b/drivers/gpu/drm/rockchip/dw-dp.c @@ -322,6 +322,7 @@ struct drm_dp_link_train { struct dw_dp_link { u8 dpcd[DP_RECEIVER_CAP_SIZE]; + u8 downstream_ports[DP_MAX_DOWNSTREAM_PORTS]; unsigned char revision; unsigned int max_rate; unsigned int rate; @@ -439,6 +440,14 @@ struct dw_dp_mst_enc { bool active; }; +struct dw_dp_dfp { + int min_tmds_clock; + int max_tmds_clock; + int max_dotclock; + u8 max_bpc; + bool ycbcr_444_to_420; +}; + struct dw_dp { const struct dw_dp_chip_data *chip_data; struct device *dev; @@ -473,12 +482,14 @@ struct dw_dp { struct dw_dp_video video; struct dw_dp_audio *audio; struct dw_dp_compliance compliance; + struct dw_dp_dfp dfp; DECLARE_BITMAP(sdp_reg_bank, SDP_REG_BANK_SIZE); bool split_mode; bool dual_connector_split; bool left_display; + bool branch_ycbcr_444_to_422; struct dw_dp *left; struct dw_dp *right; @@ -1661,6 +1672,35 @@ static int dw_dp_update_hdr_property(struct drm_connector *connector) return ret; } +static void dw_dp_update_dfp(struct dw_dp *dp, struct edid *edid) +{ + struct dw_dp_link *link = &dp->link; + struct dw_dp_dfp *dfp = &dp->dfp; + bool ycbcr_420_passthrough, ycbcr_444_to_420; + + memset(&dp->dfp, 0, sizeof(dp->dfp)); + + dfp->max_bpc = drm_dp_downstream_max_bpc(link->dpcd, link->downstream_ports, edid); + + dfp->max_dotclock = drm_dp_downstream_max_dotclock(link->dpcd, link->downstream_ports); + + dfp->min_tmds_clock = drm_dp_downstream_min_tmds_clock(link->dpcd, link->downstream_ports, + edid); + dfp->max_tmds_clock = drm_dp_downstream_max_tmds_clock(link->dpcd, link->downstream_ports, + edid); + ycbcr_420_passthrough = drm_dp_downstream_420_passthrough(link->dpcd, + link->downstream_ports); + ycbcr_444_to_420 = drm_dp_downstream_444_to_420_conversion(link->dpcd, + link->downstream_ports); + /* Prefer 4:2:0 passthrough over 4:4:4->4:2:0 conversion */ + dfp->ycbcr_444_to_420 = ycbcr_444_to_420 && !ycbcr_420_passthrough; + + dw_dp_dbg(dp, + "dfp max bpc:%d, max dot:%d, min tmds:%d, max tmds:%d, ycbcr 444 to 420:%d\n", + dfp->max_bpc, dfp->max_dotclock, dfp->min_tmds_clock, dfp->max_tmds_clock, + dfp->ycbcr_444_to_420); +} + static int dw_dp_connector_get_modes(struct drm_connector *connector) { struct dw_dp *dp = connector_to_dp(connector); @@ -1689,6 +1729,7 @@ static int dw_dp_connector_get_modes(struct drm_connector *connector) drm_connector_update_edid_property(connector, edid); num_modes = drm_add_edid_modes(connector, edid); dw_dp_update_hdr_property(connector); + dw_dp_update_dfp(dp, edid); kfree(edid); } } @@ -1922,6 +1963,9 @@ static int dw_dp_link_probe(struct dw_dp *dp) } link->sink_support_mst = drm_dp_read_mst_cap(&dp->aux, dp->link.dpcd); + ret = drm_dp_read_downstream_info(&dp->aux, link->dpcd, link->downstream_ports); + if (ret) + return ret; ret = drm_dp_dpcd_readb(&dp->aux, DP_DPRX_FEATURE_ENUMERATION_LIST, &dpcd); @@ -3016,6 +3060,9 @@ static int dw_dp_video_enable(struct dw_dp *dp, struct dw_dp_video *video, int s FIELD_PREP(HBLANK_INTERVAL_EN, 1) | FIELD_PREP(HBLANK_INTERVAL, hblank_interval)); + if (dp->branch_ycbcr_444_to_422) + drm_dp_dpcd_writeb(&dp->aux, DP_PROTOCOL_CONVERTER_CONTROL_1, + DP_CONVERSION_TO_YCBCR420_ENABLE); /* Video stream enable */ regmap_update_bits(dp->regmap, DPTX_VSAMPLE_CTRL_N(stream_id), VIDEO_STREAM_ENABLE, FIELD_PREP(VIDEO_STREAM_ENABLE, 1)); @@ -3419,6 +3466,39 @@ static ssize_t dw_dp_sim_aux_transfer(struct drm_dp_aux *aux, return dw_dp_aux_transfer(aux, msg); } +static int dw_dp_hdmi_tmds_clock(int clock, int bpc, bool ycbcr420_output) +{ + if (ycbcr420_output) + clock /= 2; + + return DIV_ROUND_CLOSEST(clock * bpc, 8); +} + +static enum drm_mode_status +dw_dp_tmds_clock_valid(struct dw_dp *dp, int bpc, + const struct drm_display_mode *mode, + const struct drm_display_info *info) +{ + int tmds_clock, min_tmds_clock, max_tmds_clock; + bool ycbcr_420_output; + + if (dp->dfp.max_dotclock && mode->clock > dp->dfp.max_dotclock) + return MODE_CLOCK_HIGH; + + ycbcr_420_output = drm_mode_is_420_only(info, mode); + tmds_clock = dw_dp_hdmi_tmds_clock(mode->clock, bpc, ycbcr_420_output); + min_tmds_clock = dp->dfp.min_tmds_clock; + max_tmds_clock = min(dp->dfp.max_tmds_clock, info->max_tmds_clock); + + if (min_tmds_clock && tmds_clock < min_tmds_clock) + return MODE_CLOCK_LOW; + + if (max_tmds_clock && tmds_clock > max_tmds_clock) + return MODE_CLOCK_HIGH; + + return MODE_OK; +} + static enum drm_mode_status dw_dp_bridge_mode_valid(struct drm_bridge *bridge, const struct drm_display_info *info, @@ -3446,6 +3526,7 @@ dw_dp_bridge_mode_valid(struct drm_bridge *bridge, min_bpp = 24; if (!link->vsc_sdp_extension_for_colorimetry_supported && + !dp->dfp.ycbcr_444_to_420 && drm_mode_is_420_only(info, &m)) return MODE_NO_420; @@ -3455,7 +3536,8 @@ dw_dp_bridge_mode_valid(struct drm_bridge *bridge, if (m.flags & DRM_MODE_FLAG_DBLCLK) return MODE_H_ILLEGAL; - return MODE_OK; + /* Assume 8bpc for the HDMI/DVI TMDS clock check */ + return dw_dp_tmds_clock_valid(dp, 8, mode, info); } static void _dw_dp_loader_protect(struct dw_dp *dp, bool on) @@ -4799,6 +4881,9 @@ out: } } + if (status == connector_status_disconnected) + memset(&dp->dfp, 0, sizeof(dp->dfp)); + return status; } @@ -4852,6 +4937,7 @@ static u32 *dw_dp_bridge_atomic_get_output_bus_fmts(struct drm_bridge *bridge, unsigned int i, j = 0; dp->eotf_type = dw_dp_get_eotf(conn_state); + dp->branch_ycbcr_444_to_422 = false; if (dp->split_mode || dp->dual_connector_split) drm_mode_convert_to_origin_mode(&mode); @@ -4895,9 +4981,16 @@ static u32 *dw_dp_bridge_atomic_get_output_bus_fmts(struct drm_bridge *bridge, fmt->color_format == DRM_COLOR_FORMAT_YCBCR420) continue; - if (drm_mode_is_420_only(di, &mode) && - fmt->color_format != DRM_COLOR_FORMAT_YCBCR420) - continue; + if (drm_mode_is_420_only(di, &mode)) { + if (dp->dfp.ycbcr_444_to_420) { + dp->branch_ycbcr_444_to_422 = true; + if (fmt->color_format != DRM_COLOR_FORMAT_YCBCR444) + continue; + } else { + if (fmt->color_format != DRM_COLOR_FORMAT_YCBCR420) + continue; + } + } if (!dw_dp_bandwidth_ok(dp, &mode, fmt->bpp, link->lanes, link->max_rate)) continue; @@ -4905,6 +4998,12 @@ static u32 *dw_dp_bridge_atomic_get_output_bus_fmts(struct drm_bridge *bridge, if (dw_dp_is_hdr_eotf(dp->eotf_type) && fmt->bpc < 8) continue; + if (dp->dfp.max_bpc && fmt->bpc > dp->dfp.max_bpc) + continue; + + if (dp->dfp.max_tmds_clock && fmt->bpc > 8) + continue; + output_fmts[j++] = fmt->bus_format; } From 7a7734a16bd5bc545ec614e5b57eaa6417416e4b Mon Sep 17 00:00:00 2001 From: Elaine Zhang Date: Thu, 9 Oct 2025 16:07:27 +0800 Subject: [PATCH 29/40] net: can: rockchip: rename rk3576_canfd.c to rk3576_can.c remove unused canfd mode func. Signed-off-by: Elaine Zhang Change-Id: Iaeda3108d0f3e44fe1fec9b231d27726f7950faa --- drivers/net/can/rockchip/Kconfig | 8 +- drivers/net/can/rockchip/Makefile | 5 +- .../rockchip/{rk3576_canfd.c => rk3576_can.c} | 789 ++++++++---------- 3 files changed, 360 insertions(+), 442 deletions(-) rename drivers/net/can/rockchip/{rk3576_canfd.c => rk3576_can.c} (55%) diff --git a/drivers/net/can/rockchip/Kconfig b/drivers/net/can/rockchip/Kconfig index 7ca3ab4351d5..1f04b52423c5 100644 --- a/drivers/net/can/rockchip/Kconfig +++ b/drivers/net/can/rockchip/Kconfig @@ -26,11 +26,11 @@ config CAN_RK3562 To compile this driver as a module, choose M here: the module will be called rk3562_can. -config CANFD_RK3576 - tristate "RK3576 CANFD controller" +config CAN_RK3576 + tristate "RK3576 CAN controller" depends on ARCH_ROCKCHIP help - Say Y here if you want to use CANFD controller found on RK3576 SoCs. + Say Y here if you want to use CAN controller found on RK3576 SoCs. To compile this driver as a module, choose M here: the module will - be called rk3576_canfd. + be called rk3576_can. diff --git a/drivers/net/can/rockchip/Makefile b/drivers/net/can/rockchip/Makefile index 4c037c281ddb..c50caa6163db 100644 --- a/drivers/net/can/rockchip/Makefile +++ b/drivers/net/can/rockchip/Makefile @@ -1,9 +1,6 @@ # SPDX-License-Identifier: GPL-2.0 -# -# Makefile for the rockchip can and canfd controller driver. -# obj-$(CONFIG_CAN_ROCKCHIP) += rockchip_can.o obj-$(CONFIG_CANFD_ROCKCHIP) += rockchip_canfd.o obj-$(CONFIG_CAN_RK3562) += rk3562_can.o -obj-$(CONFIG_CANFD_RK3576) += rk3576_canfd.o +obj-$(CONFIG_CAN_RK3576) += rk3576_can.o diff --git a/drivers/net/can/rockchip/rk3576_canfd.c b/drivers/net/can/rockchip/rk3576_can.c similarity index 55% rename from drivers/net/can/rockchip/rk3576_canfd.c rename to drivers/net/can/rockchip/rk3576_can.c index 2c0d7f056721..cfa8740d72c8 100644 --- a/drivers/net/can/rockchip/rk3576_canfd.c +++ b/drivers/net/can/rockchip/rk3576_can.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2023 Rockchip Electronics Co., Ltd. - * Rk3576 CANFD driver + * Rk3576 CAN driver */ #include @@ -30,119 +30,118 @@ #include /* registers definition */ -enum rk3576_canfd_reg { - CANFD_MODE = 0x00, - CANFD_CMD = 0x04, - CANFD_STATE = 0x08, - CANFD_INT = 0x0c, - CANFD_INT_MASK = 0x10, - CANFD_NBTP = 0x100, - CANFD_DBTP = 0x104, - CANFD_TDCR = 0x108, - CANFD_BRS_CFG = 0x10c, - CANFD_DMA_CTRL = 0x11c, - CANFD_TXFIC = 0x200, - CANFD_TXID = 0x204, - CANFD_TXDAT0 = 0x208, - CANFD_TXDAT1 = 0x20c, - CANFD_TXDAT2 = 0x210, - CANFD_TXDAT3 = 0x214, - CANFD_TXDAT4 = 0x218, - CANFD_TXDAT5 = 0x21c, - CANFD_TXDAT6 = 0x220, - CANFD_TXDAT7 = 0x224, - CANFD_TXDAT8 = 0x228, - CANFD_TXDAT9 = 0x22c, - CANFD_TXDAT10 = 0x230, - CANFD_TXDAT11 = 0x234, - CANFD_TXDAT12 = 0x238, - CANFD_TXDAT13 = 0x23c, - CANFD_TXDAT14 = 0x240, - CANFD_TXDAT15 = 0x244, - CANFD_BUF1_TXFIC = 0x280, - CANFD_BUF1_TXID = 0x284, - CANFD_BUF1_TXDAT0 = 0x288, - CANFD_BUF1_TXDAT1 = 0x28c, - CANFD_BUF1_TXDAT2 = 0x290, - CANFD_BUF1_TXDAT3 = 0x294, - CANFD_BUF1_TXDAT4 = 0x298, - CANFD_BUF1_TXDAT5 = 0x29c, - CANFD_BUF1_TXDAT6 = 0x2a0, - CANFD_BUF1_TXDAT7 = 0x2a4, - CANFD_BUF1_TXDAT8 = 0x2a8, - CANFD_BUF1_TXDAT9 = 0x2ac, - CANFD_BUF1_TXDAT10 = 0x2b0, - CANFD_BUF1_TXDAT11 = 0x2b4, - CANFD_BUF1_TXDAT12 = 0x2b8, - CANFD_BUF1_TXDAT13 = 0x2bc, - CANFD_BUF1_TXDAT14 = 0x2c0, - CANFD_BUF1_TXDAT15 = 0x2c4, - CANFD_RXFIC = 0x300, - CANFD_RXID = 0x304, - CANFD_RXTS = 0x308, - CANFD_RXDAT0 = 0x30c, - CANFD_RXDAT1 = 0x310, - CANFD_RXDAT2 = 0x314, - CANFD_RXDAT3 = 0x318, - CANFD_RXDAT4 = 0x31c, - CANFD_RXDAT5 = 0x320, - CANFD_RXDAT6 = 0x324, - CANFD_RXDAT7 = 0x328, - CANFD_RXDAT8 = 0x32c, - CANFD_RXDAT9 = 0x330, - CANFD_RXDAT10 = 0x334, - CANFD_RXDAT11 = 0x338, - CANFD_RXDAT12 = 0x33c, - CANFD_RXDAT13 = 0x340, - CANFD_RXDAT14 = 0x344, - CANFD_RXDAT15 = 0x348, - CANFD_RXFRD = 0x400, - CANFD_STR_CTL = 0x600, - CANFD_STR_STATE = 0x604, - CANFD_STR_TIMEOUT = 0x608, - CANFD_STR_WTM = 0x60c, - CANFD_EXTM_START_ADDR = 0x610, - CANFD_EXTM_SIZE = 0x614, - CANFD_EXTM_WADDR = 0x618, - CANFD_EXTM_RADDR = 0x61c, - CANFD_EXTM_AHB_TXTHR = 0x620, - CANFD_EXTM_LEFT_CNT = 0x624, - CANFD_ATF0 = 0x700, - CANFD_ATF1 = 0x704, - CANFD_ATF2 = 0x708, - CANFD_ATF3 = 0x70c, - CANFD_ATF4 = 0x710, - CANFD_ATFM0 = 0x714, - CANFD_ATFM1 = 0x718, - CANFD_ATFM2 = 0x71c, - CANFD_ATFM3 = 0x720, - CANFD_ATFM4 = 0x724, - CANFD_ATF_DLC = 0x728, - CANFD_ATF_CTL = 0x72c, - CANFD_SPACE_CTRL = 0x800, - CANFD_AUTO_RETX_CFG = 0x808, - CANFD_AUTO_RETX_STATE0 = 0x80c, - CANFD_AUTO_RETX_STATE1 = 0x810, - CANFD_OLF_CFG = 0x814, - CANFD_RXINT_CTRL = 0x818, - CANFD_RXINT_TIMEOUT = 0x81c, - CANFD_OTHER_CFG = 0x820, - CANFD_WAVE_FILTER_CFG = 0x824, - CANFD_RBC_CFG = 0x828, - CANFD_TXCRC_CFG = 0x82c, - CANFD_BUSOFFRCY_CFG = 0x830, - CANFD_BUSOFF_RCY_THR = 0x834, - CANFD_ERROR_CODE = 0x900, - CANFD_ERROR_MASK = 0x904, - CANFD_RXERRORCNT = 0x910, - CANFD_TXERRORCNT = 0x914, - CANFD_RX_RXSRAM_RDATA = 0xc00, - CANFD_RTL_VERSION = 0xf0c, +enum rk3576_can_reg { + CAN_MODE = 0x00, + CAN_CMD = 0x04, + CAN_STATE = 0x08, + CAN_INT = 0x0c, + CAN_INT_MASK = 0x10, + CAN_NBTP = 0x100, + CAN_DBTP = 0x104, + CAN_TDCR = 0x108, + CAN_DMA_CTRL = 0x11c, + CAN_TXFIC = 0x200, + CAN_TXID = 0x204, + CAN_TXDAT0 = 0x208, + CAN_TXDAT1 = 0x20c, + CAN_TXDAT2 = 0x210, + CAN_TXDAT3 = 0x214, + CAN_TXDAT4 = 0x218, + CAN_TXDAT5 = 0x21c, + CAN_TXDAT6 = 0x220, + CAN_TXDAT7 = 0x224, + CAN_TXDAT8 = 0x228, + CAN_TXDAT9 = 0x22c, + CAN_TXDAT10 = 0x230, + CAN_TXDAT11 = 0x234, + CAN_TXDAT12 = 0x238, + CAN_TXDAT13 = 0x23c, + CAN_TXDAT14 = 0x240, + CAN_TXDAT15 = 0x244, + CAN_BUF1_TXFIC = 0x280, + CAN_BUF1_TXID = 0x284, + CAN_BUF1_TXDAT0 = 0x288, + CAN_BUF1_TXDAT1 = 0x28c, + CAN_BUF1_TXDAT2 = 0x290, + CAN_BUF1_TXDAT3 = 0x294, + CAN_BUF1_TXDAT4 = 0x298, + CAN_BUF1_TXDAT5 = 0x29c, + CAN_BUF1_TXDAT6 = 0x2a0, + CAN_BUF1_TXDAT7 = 0x2a4, + CAN_BUF1_TXDAT8 = 0x2a8, + CAN_BUF1_TXDAT9 = 0x2ac, + CAN_BUF1_TXDAT10 = 0x2b0, + CAN_BUF1_TXDAT11 = 0x2b4, + CAN_BUF1_TXDAT12 = 0x2b8, + CAN_BUF1_TXDAT13 = 0x2bc, + CAN_BUF1_TXDAT14 = 0x2c0, + CAN_BUF1_TXDAT15 = 0x2c4, + CAN_RXFIC = 0x300, + CAN_RXID = 0x304, + CAN_RXTS = 0x308, + CAN_RXDAT0 = 0x30c, + CAN_RXDAT1 = 0x310, + CAN_RXDAT2 = 0x314, + CAN_RXDAT3 = 0x318, + CAN_RXDAT4 = 0x31c, + CAN_RXDAT5 = 0x320, + CAN_RXDAT6 = 0x324, + CAN_RXDAT7 = 0x328, + CAN_RXDAT8 = 0x32c, + CAN_RXDAT9 = 0x330, + CAN_RXDAT10 = 0x334, + CAN_RXDAT11 = 0x338, + CAN_RXDAT12 = 0x33c, + CAN_RXDAT13 = 0x340, + CAN_RXDAT14 = 0x344, + CAN_RXDAT15 = 0x348, + CAN_RXFRD = 0x400, + CAN_STR_CTL = 0x600, + CAN_STR_STATE = 0x604, + CAN_STR_TIMEOUT = 0x608, + CAN_STR_WTM = 0x60c, + CAN_EXTM_START_ADDR = 0x610, + CAN_EXTM_SIZE = 0x614, + CAN_EXTM_WADDR = 0x618, + CAN_EXTM_RADDR = 0x61c, + CAN_EXTM_AHB_TXTHR = 0x620, + CAN_EXTM_LEFT_CNT = 0x624, + CAN_ATF0 = 0x700, + CAN_ATF1 = 0x704, + CAN_ATF2 = 0x708, + CAN_ATF3 = 0x70c, + CAN_ATF4 = 0x710, + CAN_ATFM0 = 0x714, + CAN_ATFM1 = 0x718, + CAN_ATFM2 = 0x71c, + CAN_ATFM3 = 0x720, + CAN_ATFM4 = 0x724, + CAN_ATF_DLC = 0x728, + CAN_ATF_CTL = 0x72c, + CAN_SPACE_CTRL = 0x800, + CAN_AUTO_RETX_CFG = 0x808, + CAN_AUTO_RETX_STATE0 = 0x80c, + CAN_AUTO_RETX_STATE1 = 0x810, + CAN_OLF_CFG = 0x814, + CAN_RXINT_CTRL = 0x818, + CAN_RXINT_TIMEOUT = 0x81c, + CAN_OTHER_CFG = 0x820, + CAN_WAVE_FILTER_CFG = 0x824, + CAN_RBC_CFG = 0x828, + CAN_TXCRC_CFG = 0x82c, + CAN_BUSOFFRCY_CFG = 0x830, + CAN_BUSOFF_RCY_THR = 0x834, + CAN_ERROR_CODE = 0x900, + CAN_ERROR_MASK = 0x904, + CAN_RXERRORCNT = 0x910, + CAN_TXERRORCNT = 0x914, + CAN_RX_RXSRAM_RDATA = 0xc00, + CAN_RTL_VERSION = 0xf0c, }; enum { - ROCKCHIP_RK3576_CANFD = 0, - ROCKCHIP_RV1126B_CANFD, + ROCKCHIP_RK3576_CAN = 0, + ROCKCHIP_RV1126B_CAN, }; #define DATE_LENGTH_12_BYTE (0x9) @@ -153,9 +152,9 @@ enum { #define DATE_LENGTH_48_BYTE (0xe) #define DATE_LENGTH_64_BYTE (0xf) -#define CANFD_TX0_REQ BIT(0) -#define CANFD_TX1_REQ BIT(1) -#define CANFD_TX_REQ_FULL ((CANFD_TX0_REQ) | (CANFD_TX1_REQ)) +#define CAN_TX0_REQ BIT(0) +#define CAN_TX1_REQ BIT(1) +#define CAN_TX_REQ_FULL ((CAN_TX0_REQ) | (CAN_TX1_REQ)) #define MODE_PASS_ERR BIT(10) #define MODE_DIS_PEE BIT(9) @@ -185,13 +184,13 @@ enum { #define PASSIVE_ERR_INT BIT(4) #define TX_LOSTARB_INT BIT(5) #define BUS_ERR_INT BIT(6) -#define RX_STR_FULL_INT BIT(7) +#define RX_STR_FULL_INT BIT(7) #define RX_STR_OV_INT BIT(8) #define BUS_OFF_INT BIT(9) #define BUS_OFF_RECOVERY_INT BIT(10) #define WAKEUP_INT BIT(11) #define AUTO_RETX_FAIL_INT BIT(12) -#define MFI_INT BIT(13) +#define MFI_INT BIT(13) #define MFI_TIMEOUT BIT(14) #define RX_STR_TIMEOUT_INT BIT(15) #define BUSINT_INT BIT(16) @@ -228,9 +227,6 @@ enum { #define RECEIVE_STUFF_COUNT BIT(10) #define RECEIVE_DATA BIT(9) #define RECEIVE_DLC BIT(8) -#define RECEIVE_BRS_ESI BIT(7) -#define RECEIVE_RES BIT(6) -#define RECEIVE_FDF BIT(5) #define RECEIVE_ID2_RTR BIT(4) #define RECEIVE_SOF_IDE BIT(3) #define RECEIVE_BUS_IDLE BIT(2) @@ -249,9 +245,6 @@ enum { #define NBTP_NTSEG1_MASK (0xff << NBTP_NTSEG1_SHIFT) /* Data Bit Timing & Prescaler Register (DBTP) */ -#define DBTP_BRS_TSEG1_SHIFT 24 -#define DBTP_BRS_TSEG1_MASK (0xff << DBTP_BRS_TSEG1_SHIFT) -#define DBTP_BRS_MODE BIT(23) #define DBTP_MODE_3_SAMPLES BIT(21) #define DBTP_DSJW_SHIFT 17 #define DBTP_DSJW_MASK (0xf << DBTP_DSJW_SHIFT) @@ -269,17 +262,10 @@ enum { #define RX_DMA_ENABLE BIT(9) -#define TX_FD_ENABLE BIT(5) -#define TX_FD_BRS_ENABLE BIT(4) - #define TX_FORMAT_SHIFT 7 #define TX_FORMAT_MASK (0x1 << TX_FORMAT_SHIFT) #define TX_RTR_SHIFT 6 #define TX_RTR_MASK (0x1 << TX_RTR_SHIFT) -#define TX_FDF_SHIFT 5 -#define TX_FDF_MASK (0x1 << TX_FDF_SHIFT) -#define TX_BRS_SHIFT 4 -#define TX_BRS_MASK (0x1 << TX_BRS_SHIFT) #define TX_DLC_SHIFT 0 #define TX_DLC_MASK (0xF << TX_DLC_SHIFT) @@ -287,10 +273,6 @@ enum { #define RX_FORMAT_MASK (0x1 << RX_FORMAT_SHIFT) #define RX_RTR_SHIFT 22 #define RX_RTR_MASK (0x1 << RX_RTR_SHIFT) -#define RX_FDF_SHIFT 21 -#define RX_FDF_MASK (0x1 << RX_FDF_SHIFT) -#define RX_BRS_SHIFT 20 -#define RX_BRS_MASK (0x1 << RX_BRS_SHIFT) #define RX_DLC_SHIFT 24 #define RX_DLC_MASK (0xF << RX_DLC_SHIFT) #define RX_ISM_LEN_SHIFT 8 @@ -318,7 +300,6 @@ enum { #define EXTTM_LEFT_CNT_MASK (0x3fffff << EXTTM_LEFT_CNT_SHIFT) #define ISM_WATERMASK_CAN 0x6c /* word */ -#define ISM_WATERMASK_CANFD 0x6c /* word */ #define ESM_WATERMASK (0x50 << 8) /* word */ #define BUSOFF_RCY_MODE_EN BIT(8) @@ -348,29 +329,29 @@ enum { #define SRAM_MAX_DEPTH 256 /* word */ #define EXT_MEM_SIZE 0x2000 /* 8KByte */ -#define CANFD_FILTER_MASK 0x1fffffff +#define CAN_FILTER_MASK 0x1fffffff -#define CANFD_FIFO_CNT_MASK 0xff +#define CAN_FIFO_CNT_MASK 0xff #define CANBUSOFF_RCY_SLOW 200 /* ms */ #define CANBUSOFF_RCY_FAST 30 /* ms */ -#define DRV_NAME "rk3576_canfd" +#define DRV_NAME "rk3576_can" -enum rk3576_canfd_atf_mode { - CANFD_ATF_MASK_MODE = 0, - CANFD_ATF_LIST_MODE, +enum rk3576_can_atf_mode { + CAN_ATF_MASK_MODE = 0, + CAN_ATF_LIST_MODE, }; -enum rk3576_canfd_storage_mode { - CANFD_DATA_FLEXIBLE = 0, - CANFD_DATA_CAN_FIXED, - CANFD_DATA_CANFD_FIXED, +enum rk3576_can_storage_mode { + CAN_DATA_FLEXIBLE = 0, + CAN_DATA_CAN_DATE_4_FIXED, + CAN_DATA_CAN_DATA_18_FIXED, }; -/* rk3576_canfd private data structure */ +/* rk3576_can private data structure */ -struct rk3576_canfd { +struct rk3576_can { struct can_priv can; struct device *dev; struct napi_struct napi; @@ -395,19 +376,19 @@ struct rk3576_canfd { dma_addr_t rx_dma_dst_addr; }; -static inline u32 rk3576_canfd_read(const struct rk3576_canfd *priv, - enum rk3576_canfd_reg reg) +static inline u32 rk3576_can_read(const struct rk3576_can *priv, + enum rk3576_can_reg reg) { return readl(priv->base + reg); } -static inline void rk3576_canfd_write(const struct rk3576_canfd *priv, - enum rk3576_canfd_reg reg, u32 val) +static inline void rk3576_can_write(const struct rk3576_can *priv, + enum rk3576_can_reg reg, u32 val) { writel(val, priv->base + reg); } -static const struct can_bittiming_const rk3576_canfd_bittiming_const = { +static const struct can_bittiming_const rk3576_can_bittiming_const = { .name = DRV_NAME, .tseg1_min = 1, .tseg1_max = 128, @@ -419,7 +400,7 @@ static const struct can_bittiming_const rk3576_canfd_bittiming_const = { .brp_inc = 2, }; -static const struct can_bittiming_const rk3576_canfd_data_bittiming_const = { +static const struct can_bittiming_const rk3576_can_data_bittiming_const = { .name = DRV_NAME, .tseg1_min = 1, .tseg1_max = 32, @@ -433,40 +414,39 @@ static const struct can_bittiming_const rk3576_canfd_data_bittiming_const = { static int set_reset_mode(struct net_device *ndev) { - struct rk3576_canfd *rcan = netdev_priv(ndev); + struct rk3576_can *rcan = netdev_priv(ndev); reset_control_assert(rcan->reset); udelay(2); reset_control_deassert(rcan->reset); - rk3576_canfd_write(rcan, CANFD_MODE, 0); + rk3576_can_write(rcan, CAN_MODE, 0); netdev_dbg(ndev, "%s MODE=0x%08x\n", __func__, - rk3576_canfd_read(rcan, CANFD_MODE)); + rk3576_can_read(rcan, CAN_MODE)); return 0; } static int set_normal_mode(struct net_device *ndev) { - struct rk3576_canfd *rcan = netdev_priv(ndev); + struct rk3576_can *rcan = netdev_priv(ndev); u32 val; - val = rk3576_canfd_read(rcan, CANFD_MODE); + val = rk3576_can_read(rcan, CAN_MODE); val |= WORK_MODE; - rk3576_canfd_write(rcan, CANFD_MODE, val); + rk3576_can_write(rcan, CAN_MODE, val); netdev_dbg(ndev, "%s MODE=0x%08x\n", __func__, - rk3576_canfd_read(rcan, CANFD_MODE)); + rk3576_can_read(rcan, CAN_MODE)); return 0; } /* bittiming is called in reset_mode only */ -static int rk3576_canfd_set_bittiming(struct net_device *ndev) +static int rk3576_can_set_bittiming(struct net_device *ndev) { - struct rk3576_canfd *rcan = netdev_priv(ndev); + struct rk3576_can *rcan = netdev_priv(ndev); const struct can_bittiming *bt = &rcan->can.bittiming; - const struct can_bittiming *dbt = &rcan->can.data_bittiming; u16 brp, sjw, tseg1, tseg2; u32 reg_btp; @@ -481,58 +461,19 @@ static int rk3576_canfd_set_bittiming(struct net_device *ndev) if (rcan->can.ctrlmode & CAN_CTRLMODE_3_SAMPLES) reg_btp |= NBTP_MODE_3_SAMPLES; - rk3576_canfd_write(rcan, CANFD_NBTP, reg_btp); - - if (rcan->can.ctrlmode & CAN_CTRLMODE_FD) { - reg_btp = 0; - brp = (dbt->brp >> 1) - 1; - sjw = dbt->sjw - 1; - tseg1 = dbt->prop_seg + dbt->phase_seg1 - 1; - tseg2 = dbt->phase_seg2 - 1; - if (sjw < 2) - sjw = 2; - - if (dbt->bitrate > 2200000) { - u32 tdco; - - /* Equation based on Bosch's ROCKCHIP_CANFD User Manual's - * Transmitter Delay Compensation Section - */ - tdco = ((1 + 1 + tseg1) * (brp + 1)) - 2; - /* Max valid TDCO value is 63 */ - if (tdco > 63) - tdco = 63; - rk3576_canfd_write(rcan, CANFD_TDCR, - (tdco << TDCR_TDCO_SHIFT) | - TDCR_TDC_ENABLE); - } else { - rk3576_canfd_write(rcan, CANFD_TDCR, 0); - } - - reg_btp |= (brp << DBTP_DBRP_SHIFT) | - (sjw << DBTP_DSJW_SHIFT) | - (tseg1 << DBTP_DTSEG1_SHIFT) | - (tseg2 << DBTP_DTSEG2_SHIFT) | - DBTP_BRS_MODE | - ((tseg1 / 2) << DBTP_BRS_TSEG1_SHIFT); - - if (rcan->can.ctrlmode & CAN_CTRLMODE_3_SAMPLES) - reg_btp |= DBTP_MODE_3_SAMPLES; - - rk3576_canfd_write(rcan, CANFD_DBTP, reg_btp); - } + rk3576_can_write(rcan, CAN_NBTP, reg_btp); netdev_dbg(ndev, "%s NBTP=0x%08x, DBTP=0x%08x, TDCR=0x%08x\n", __func__, - rk3576_canfd_read(rcan, CANFD_NBTP), - rk3576_canfd_read(rcan, CANFD_DBTP), - rk3576_canfd_read(rcan, CANFD_TDCR)); + rk3576_can_read(rcan, CAN_NBTP), + rk3576_can_read(rcan, CAN_DBTP), + rk3576_can_read(rcan, CAN_TDCR)); return 0; } -static int rk3576_canfd_get_berr_counter(const struct net_device *ndev, - struct can_berr_counter *bec) +static int rk3576_can_get_berr_counter(const struct net_device *ndev, + struct can_berr_counter *bec) { - struct rk3576_canfd *rcan = netdev_priv(ndev); + struct rk3576_can *rcan = netdev_priv(ndev); int err; err = pm_runtime_get_sync(rcan->dev); @@ -542,159 +483,157 @@ static int rk3576_canfd_get_berr_counter(const struct net_device *ndev, return err; } - bec->rxerr = rk3576_canfd_read(rcan, CANFD_RXERRORCNT); - bec->txerr = rk3576_canfd_read(rcan, CANFD_TXERRORCNT); + bec->rxerr = rk3576_can_read(rcan, CAN_RXERRORCNT); + bec->txerr = rk3576_can_read(rcan, CAN_TXERRORCNT); pm_runtime_put(rcan->dev); netdev_dbg(ndev, "%s RX_ERR_CNT=0x%08x, TX_ERR_CNT=0x%08x\n", __func__, - rk3576_canfd_read(rcan, CANFD_RXERRORCNT), - rk3576_canfd_read(rcan, CANFD_TXERRORCNT)); + rk3576_can_read(rcan, CAN_RXERRORCNT), + rk3576_can_read(rcan, CAN_TXERRORCNT)); return 0; } -static int rk3576_canfd_atf_config(const struct net_device *ndev, int mode) +static int rk3576_can_atf_config(const struct net_device *ndev, int mode) { - struct rk3576_canfd *rcan = netdev_priv(ndev); + struct rk3576_can *rcan = netdev_priv(ndev); u32 id[10] = {0}; u32 dlc = 0, dlc_over = 0; switch (mode) { - case CANFD_ATF_MASK_MODE: - rk3576_canfd_write(rcan, CANFD_ATF0, id[0]); - rk3576_canfd_write(rcan, CANFD_ATF1, id[1]); - rk3576_canfd_write(rcan, CANFD_ATF2, id[2]); - rk3576_canfd_write(rcan, CANFD_ATF3, id[3]); - rk3576_canfd_write(rcan, CANFD_ATF4, id[4]); - rk3576_canfd_write(rcan, CANFD_ATFM0, 0x7fff); - rk3576_canfd_write(rcan, CANFD_ATFM1, 0x7fff); - rk3576_canfd_write(rcan, CANFD_ATFM2, 0x7fff); - rk3576_canfd_write(rcan, CANFD_ATFM3, 0x7fff); - rk3576_canfd_write(rcan, CANFD_ATFM4, 0x7fff); + case CAN_ATF_MASK_MODE: + rk3576_can_write(rcan, CAN_ATF0, id[0]); + rk3576_can_write(rcan, CAN_ATF1, id[1]); + rk3576_can_write(rcan, CAN_ATF2, id[2]); + rk3576_can_write(rcan, CAN_ATF3, id[3]); + rk3576_can_write(rcan, CAN_ATF4, id[4]); + rk3576_can_write(rcan, CAN_ATFM0, 0x7fff); + rk3576_can_write(rcan, CAN_ATFM1, 0x7fff); + rk3576_can_write(rcan, CAN_ATFM2, 0x7fff); + rk3576_can_write(rcan, CAN_ATFM3, 0x7fff); + rk3576_can_write(rcan, CAN_ATFM4, 0x7fff); break; - case CANFD_ATF_LIST_MODE: - rk3576_canfd_write(rcan, CANFD_ATF0, id[0]); - rk3576_canfd_write(rcan, CANFD_ATF1, id[1]); - rk3576_canfd_write(rcan, CANFD_ATF2, id[2]); - rk3576_canfd_write(rcan, CANFD_ATF3, id[3]); - rk3576_canfd_write(rcan, CANFD_ATF4, id[4]); - rk3576_canfd_write(rcan, CANFD_ATFM0, id[5] | (1 << 31)); - rk3576_canfd_write(rcan, CANFD_ATFM1, id[6] | (1 << 31)); - rk3576_canfd_write(rcan, CANFD_ATFM2, id[7] | (1 << 31)); - rk3576_canfd_write(rcan, CANFD_ATFM3, id[8] | (1 << 31)); - rk3576_canfd_write(rcan, CANFD_ATFM4, id[9] | (1 << 31)); + case CAN_ATF_LIST_MODE: + rk3576_can_write(rcan, CAN_ATF0, id[0]); + rk3576_can_write(rcan, CAN_ATF1, id[1]); + rk3576_can_write(rcan, CAN_ATF2, id[2]); + rk3576_can_write(rcan, CAN_ATF3, id[3]); + rk3576_can_write(rcan, CAN_ATF4, id[4]); + rk3576_can_write(rcan, CAN_ATFM0, id[5] | (1 << 31)); + rk3576_can_write(rcan, CAN_ATFM1, id[6] | (1 << 31)); + rk3576_can_write(rcan, CAN_ATFM2, id[7] | (1 << 31)); + rk3576_can_write(rcan, CAN_ATFM3, id[8] | (1 << 31)); + rk3576_can_write(rcan, CAN_ATFM4, id[9] | (1 << 31)); break; default: - rk3576_canfd_write(rcan, CANFD_ATF_CTL, 0xffff); + rk3576_can_write(rcan, CAN_ATF_CTL, 0xffff); return -EINVAL; } if (dlc) { if (dlc_over) - rk3576_canfd_write(rcan, CANFD_ATF_DLC, dlc | (1 << 4)); + rk3576_can_write(rcan, CAN_ATF_DLC, dlc | (1 << 4)); else - rk3576_canfd_write(rcan, CANFD_ATF_DLC, dlc | (1 << 4) | (1 << 5)); + rk3576_can_write(rcan, CAN_ATF_DLC, dlc | (1 << 4) | (1 << 5)); } - rk3576_canfd_write(rcan, CANFD_ATF_CTL, 0); + rk3576_can_write(rcan, CAN_ATF_CTL, 0); return 0; } -static int rk3576_canfd_start(struct net_device *ndev) +static int rk3576_can_start(struct net_device *ndev) { - struct rk3576_canfd *rcan = netdev_priv(ndev); + struct rk3576_can *rcan = netdev_priv(ndev); u32 val, ism = 0, water = 0; /* we need to enter the reset mode */ set_reset_mode(ndev); - rk3576_canfd_write(rcan, CANFD_INT_MASK, INT_ENABLE); - rk3576_canfd_atf_config(ndev, CANFD_ATF_MASK_MODE); + rk3576_can_write(rcan, CAN_INT_MASK, INT_ENABLE); + rk3576_can_atf_config(ndev, CAN_ATF_MASK_MODE); /* set mode */ - val = rk3576_canfd_read(rcan, CANFD_MODE); + val = rk3576_can_read(rcan, CAN_MODE); if (rcan->rx_max_data > 4) { - ism = CANFD_DATA_CANFD_FIXED; - water = ISM_WATERMASK_CANFD; + ism = CAN_DATA_CAN_DATA_18_FIXED; + water = ISM_WATERMASK_CAN; } else { - ism = CANFD_DATA_CAN_FIXED; + ism = CAN_DATA_CAN_DATE_4_FIXED; water = ISM_WATERMASK_CAN; } /* internal sram mode */ - rk3576_canfd_write(rcan, CANFD_STR_CTL, - (ism << ISM_SEL_SHIFT) | STORAGE_TIMEOUT_MODE); - rk3576_canfd_write(rcan, CANFD_STR_WTM, water); + rk3576_can_write(rcan, CAN_STR_CTL, + (ism << ISM_SEL_SHIFT) | STORAGE_TIMEOUT_MODE); + rk3576_can_write(rcan, CAN_STR_WTM, water); /* Loopback Mode */ if (rcan->can.ctrlmode & CAN_CTRLMODE_LOOPBACK) { val |= MODE_LBACK; - rk3576_canfd_write(rcan, CANFD_ERROR_MASK, ACK_ERROR_MASK); + rk3576_can_write(rcan, CAN_ERROR_MASK, ACK_ERROR_MASK); } else if (rcan->can.ctrlmode & CAN_CTRLMODE_LISTENONLY) { val |= MODE_SILENT; - rk3576_canfd_write(rcan, CANFD_ERROR_MASK, ACK_ERROR_MASK); + rk3576_can_write(rcan, CAN_ERROR_MASK, ACK_ERROR_MASK); } else { - rk3576_canfd_write(rcan, CANFD_ERROR_MASK, 0); + rk3576_can_write(rcan, CAN_ERROR_MASK, 0); } if (rcan->auto_retx_cnt) - rk3576_canfd_write(rcan, CANFD_AUTO_RETX_CFG, - AUTO_RETX_EN | RETX_LIMIT_EN | - (rcan->auto_retx_cnt << RETX_TIME_LIMIT_SHIFT)); + rk3576_can_write(rcan, CAN_AUTO_RETX_CFG, + AUTO_RETX_EN | RETX_LIMIT_EN | + (rcan->auto_retx_cnt << RETX_TIME_LIMIT_SHIFT)); else - rk3576_canfd_write(rcan, CANFD_AUTO_RETX_CFG, AUTO_RETX_EN); + rk3576_can_write(rcan, CAN_AUTO_RETX_CFG, AUTO_RETX_EN); - rk3576_canfd_write(rcan, CANFD_MODE, val); + rk3576_can_write(rcan, CAN_MODE, val); if (rcan->use_dma) - rk3576_canfd_write(rcan, CANFD_DMA_CTRL, RX_DMA_ENABLE | rcan->dma_thr); + rk3576_can_write(rcan, CAN_DMA_CTRL, RX_DMA_ENABLE | rcan->dma_thr); - rk3576_canfd_write(rcan, CANFD_BRS_CFG, 0x7); + rk3576_can_write(rcan, CAN_BUSOFFRCY_CFG, BUSOFF_RCY_MODE_EN | BUSOFF_RCY_CNT_FAST); + rk3576_can_write(rcan, CAN_BUSOFF_RCY_THR, BUSOFF_RCY_TIME_FAST); - rk3576_canfd_write(rcan, CANFD_BUSOFFRCY_CFG, BUSOFF_RCY_MODE_EN | BUSOFF_RCY_CNT_FAST); - rk3576_canfd_write(rcan, CANFD_BUSOFF_RCY_THR, BUSOFF_RCY_TIME_FAST); - - rk3576_canfd_set_bittiming(ndev); + rk3576_can_set_bittiming(ndev); set_normal_mode(ndev); rcan->can.state = CAN_STATE_ERROR_ACTIVE; netdev_dbg(ndev, "%s MODE=0x%08x, INT_MASK=0x%08x\n", __func__, - rk3576_canfd_read(rcan, CANFD_MODE), - rk3576_canfd_read(rcan, CANFD_INT_MASK)); + rk3576_can_read(rcan, CAN_MODE), + rk3576_can_read(rcan, CAN_INT_MASK)); return 0; } -static int rk3576_canfd_stop(struct net_device *ndev) +static int rk3576_can_stop(struct net_device *ndev) { - struct rk3576_canfd *rcan = netdev_priv(ndev); + struct rk3576_can *rcan = netdev_priv(ndev); rcan->can.state = CAN_STATE_STOPPED; /* we need to enter reset mode */ set_reset_mode(ndev); /* disable all interrupts */ - rk3576_canfd_write(rcan, CANFD_INT_MASK, 0xffffffff); + rk3576_can_write(rcan, CAN_INT_MASK, 0xffffffff); netdev_dbg(ndev, "%s MODE=0x%08x, INT_MASK=0x%08x\n", __func__, - rk3576_canfd_read(rcan, CANFD_MODE), - rk3576_canfd_read(rcan, CANFD_INT_MASK)); + rk3576_can_read(rcan, CAN_MODE), + rk3576_can_read(rcan, CAN_INT_MASK)); return 0; } -static int rk3576_canfd_set_mode(struct net_device *ndev, - enum can_mode mode) +static int rk3576_can_set_mode(struct net_device *ndev, + enum can_mode mode) { int err; switch (mode) { case CAN_MODE_START: - err = rk3576_canfd_start(ndev); + err = rk3576_can_start(ndev); if (err) { - netdev_err(ndev, "starting CANFD controller failed!\n"); + netdev_err(ndev, "starting CAN controller failed!\n"); return err; } if (netif_queue_stopped(ndev)) @@ -708,19 +647,19 @@ static int rk3576_canfd_set_mode(struct net_device *ndev, return 0; } -/* transmit a CANFD message +/* transmit a CAN message * message layout in the sk_buff should be like this: * xx xx xx xx ff ll 00 11 22 33 44 55 66 77 * [ can_id ] [flags] [len] [can data (up to 8 bytes] */ -static netdev_tx_t rk3576_canfd_start_xmit(struct sk_buff *skb, - struct net_device *ndev) +static netdev_tx_t rk3576_can_start_xmit(struct sk_buff *skb, + struct net_device *ndev) { - struct rk3576_canfd *rcan = netdev_priv(ndev); - struct canfd_frame *cf = (struct canfd_frame *)skb->data; + struct rk3576_can *rcan = netdev_priv(ndev); + struct can_frame *cf = (struct can_frame *)skb->data; u32 id, dlc; - u32 cmd = CANFD_TX0_REQ; - u32 tx_fifo = CANFD_TXFIC, tx_id = CANFD_TXID, tx_data = CANFD_TXDAT0; + u32 cmd = CAN_TX0_REQ; + u32 tx_fifo = CAN_TXFIC, tx_id = CAN_TXID, tx_data = CAN_TXDAT0; int i; if (can_dropped_invalid_skb(ndev, skb)) @@ -728,125 +667,110 @@ static netdev_tx_t rk3576_canfd_start_xmit(struct sk_buff *skb, netif_stop_queue(ndev); - if (rk3576_canfd_read(rcan, CANFD_CMD) & CANFD_TX0_REQ) { - cmd = CANFD_TX1_REQ; - if (rcan->mode == ROCKCHIP_RV1126B_CANFD) { - tx_fifo = CANFD_BUF1_TXFIC; - tx_id = CANFD_BUF1_TXID; - tx_data = CANFD_BUF1_TXDAT0; + if (rk3576_can_read(rcan, CAN_CMD) & CAN_TX0_REQ) { + cmd = CAN_TX1_REQ; + if (rcan->mode == ROCKCHIP_RV1126B_CAN) { + tx_fifo = CAN_BUF1_TXFIC; + tx_id = CAN_BUF1_TXID; + tx_data = CAN_BUF1_TXDAT0; } } /* Watch carefully on the bit sequence */ if (cf->can_id & CAN_EFF_FLAG) { - /* Extended CANFD ID format */ + /* Extended CAN ID format */ id = cf->can_id & CAN_EFF_MASK; - dlc = can_fd_len2dlc(cf->len) & TX_DLC_MASK; + dlc = cf->can_dlc & TX_DLC_MASK; dlc |= TX_FORMAT_MASK; /* Extended frames remote TX request */ if (cf->can_id & CAN_RTR_FLAG) dlc |= TX_RTR_MASK; } else { - /* Standard CANFD ID format */ + /* Standard CAN ID format */ id = cf->can_id & CAN_SFF_MASK; - dlc = can_fd_len2dlc(cf->len) & TX_DLC_MASK; + dlc = cf->can_dlc & TX_DLC_MASK; /* Standard frames remote TX request */ if (cf->can_id & CAN_RTR_FLAG) dlc |= TX_RTR_MASK; } - if ((rcan->can.ctrlmode & CAN_CTRLMODE_FD) && can_is_canfd_skb(skb)) { - dlc |= TX_FD_ENABLE; - if (cf->flags & CANFD_BRS) - dlc |= TX_FD_BRS_ENABLE; - } + rk3576_can_write(rcan, tx_id, id); + rk3576_can_write(rcan, tx_fifo, dlc); - rk3576_canfd_write(rcan, tx_id, id); - rk3576_canfd_write(rcan, tx_fifo, dlc); - - for (i = 0; i < cf->len; i += 4) - rk3576_canfd_write(rcan, tx_data + i, - *(u32 *)(cf->data + i)); + for (i = 0; i < can_cc_dlc2len(cf->can_dlc & TX_DLC_MASK); i += 4) + rk3576_can_write(rcan, tx_data + i, + *(u32 *)(cf->data + i)); can_put_echo_skb(skb, ndev, 0, 0); - rk3576_canfd_write(rcan, CANFD_CMD, cmd); + rk3576_can_write(rcan, CAN_CMD, cmd); return NETDEV_TX_OK; } -static int rk3576_canfd_rx(struct net_device *ndev, u32 addr) +static int rk3576_can_rx(struct net_device *ndev, u32 addr) { - struct rk3576_canfd *rcan = netdev_priv(ndev); + struct rk3576_can *rcan = netdev_priv(ndev); struct net_device_stats *stats = &ndev->stats; - struct canfd_frame *cf; + struct can_frame *cf; struct sk_buff *skb; - u32 id_rk3576_canfd, dlc; + u32 id_rk3576_can, dlc; int i = 0; u32 __maybe_unused ts, ret; u32 data[16] = {0}; if (rcan->use_dma) { dlc = readl(rcan->rxbuf + addr * rcan->rx_max_data); - id_rk3576_canfd = readl(rcan->rxbuf + 1 + addr * rcan->rx_max_data); + id_rk3576_can = readl(rcan->rxbuf + 1 + addr * rcan->rx_max_data); for (i = 0; i < (rcan->rx_max_data - 2); i++) data[i] = readl(rcan->rxbuf + 2 + i + addr * rcan->rx_max_data); } else { - dlc = rk3576_canfd_read(rcan, addr); - id_rk3576_canfd = rk3576_canfd_read(rcan, addr); + dlc = rk3576_can_read(rcan, addr); + id_rk3576_can = rk3576_can_read(rcan, addr); for (i = 0; i < (rcan->rx_max_data - 2); i++) - data[i] = rk3576_canfd_read(rcan, addr); + data[i] = rk3576_can_read(rcan, addr); } - /* create zero'ed CANFD frame buffer */ - if (dlc & RX_FDF_MASK) - skb = alloc_canfd_skb(ndev, &cf); - else - skb = alloc_can_skb(ndev, (struct can_frame **)&cf); + /* create zero'ed CAN frame buffer */ + skb = alloc_can_skb(ndev, (struct can_frame **)&cf); if (!skb) { stats->rx_dropped++; return 1; } - /* Change CANFD data length format to SocketCAN data format */ - if (dlc & RX_FDF_MASK) - cf->len = can_fd_dlc2len((dlc & RX_DLC_MASK) >> RX_DLC_SHIFT); - else - cf->len = can_cc_dlc2len((dlc & RX_DLC_MASK) >> RX_DLC_SHIFT); + /* Change CAN data length format to SocketCAN data format */ + cf->can_dlc = can_cc_dlc2len((dlc & RX_DLC_MASK) >> RX_DLC_SHIFT); - /* Change CANFD ID format to SocketCAN ID format */ + /* Change CAN ID format to SocketCAN ID format */ if (dlc & RX_FORMAT_MASK) { /* The received frame is an Extended format frame */ - cf->can_id = id_rk3576_canfd; + cf->can_id = id_rk3576_can; cf->can_id |= CAN_EFF_FLAG; if (dlc & RX_RTR_MASK) cf->can_id |= CAN_RTR_FLAG; } else { /* The received frame is a standard format frame */ - cf->can_id = id_rk3576_canfd; + cf->can_id = id_rk3576_can; if (dlc & RX_RTR_MASK) cf->can_id |= CAN_RTR_FLAG; } - if (dlc & RX_BRS_MASK) - cf->flags |= CANFD_BRS; - if (!(cf->can_id & CAN_RTR_FLAG)) { - /* Change CANFD data format to SocketCAN data format */ - for (i = 0; i < cf->len; i += 4) + /* Change CAN data format to SocketCAN data format */ + for (i = 0; i < cf->can_dlc; i += 4) *(u32 *)(cf->data + i) = data[i / 4]; } stats->rx_packets++; - stats->rx_bytes += cf->len; + stats->rx_bytes += cf->can_dlc; netif_rx(skb); return 1; } -/* rk3576_canfd_rx_poll - Poll routine for rx packets (NAPI) +/* rk3576_can_rx_poll - Poll routine for rx packets (NAPI) * @napi: napi structure pointer * @quota: Max number of rx packets to be processed. * @@ -855,57 +779,57 @@ static int rk3576_canfd_rx(struct net_device *ndev, u32 addr) * * Return: number of packets received */ -static int rk3576_canfd_rx_poll(struct napi_struct *napi, int quota) +static int rk3576_can_rx_poll(struct napi_struct *napi, int quota) { struct net_device *ndev = napi->dev; - struct rk3576_canfd *rcan = netdev_priv(ndev); + struct rk3576_can *rcan = netdev_priv(ndev); int work_done = 0, cnt = 0; if (rcan->use_dma) { while (work_done < rcan->quota) - work_done += rk3576_canfd_rx(ndev, work_done); + work_done += rk3576_can_rx(ndev, work_done); if (work_done <= rcan->rx_fifo_depth) { napi_complete_done(napi, work_done); - rk3576_canfd_write(rcan, CANFD_INT_MASK, INT_ENABLE); + rk3576_can_write(rcan, CAN_INT_MASK, INT_ENABLE); } } else { - quota = (rk3576_canfd_read(rcan, CANFD_STR_STATE) & rcan->rx_fifo_mask) >> + quota = (rk3576_can_read(rcan, CAN_STR_STATE) & rcan->rx_fifo_mask) >> rcan->rx_fifo_shift; quota = quota / rcan->rx_max_data; - cnt = (rk3576_canfd_read(rcan, CANFD_STR_STATE) & INTM_CNT_MASK) >> INTM_CNT_SHIFT; + cnt = (rk3576_can_read(rcan, CAN_STR_STATE) & INTM_CNT_MASK) >> INTM_CNT_SHIFT; if (quota != cnt) - quota = ((rk3576_canfd_read(rcan, CANFD_STR_STATE) & rcan->rx_fifo_mask) >> + quota = ((rk3576_can_read(rcan, CAN_STR_STATE) & rcan->rx_fifo_mask) >> rcan->rx_fifo_shift) / rcan->rx_max_data; while (work_done < quota) - work_done += rk3576_canfd_rx(ndev, CANFD_RXFRD); + work_done += rk3576_can_rx(ndev, CAN_RXFRD); if (work_done <= rcan->rx_fifo_depth) { napi_complete_done(napi, work_done); - rk3576_canfd_write(rcan, CANFD_INT_MASK, INT_ENABLE); + rk3576_can_write(rcan, CAN_INT_MASK, INT_ENABLE); } } return work_done; } -static void rk3576_canfd_rx_dma_callback(void *data) +static void rk3576_can_rx_dma_callback(void *data) { - struct rk3576_canfd *rcan = data; + struct rk3576_can *rcan = data; napi_schedule(&rcan->napi); } -static int rk3576_canfd_rx_dma(struct rk3576_canfd *rcan) +static int rk3576_can_rx_dma(struct rk3576_can *rcan) { struct dma_async_tx_descriptor *rxdesc = NULL; int quota = 0; - quota = (rk3576_canfd_read(rcan, CANFD_STR_STATE) & rcan->rx_fifo_mask) >> + quota = (rk3576_can_read(rcan, CAN_STR_STATE) & rcan->rx_fifo_mask) >> rcan->rx_fifo_shift; rcan->quota = DIV_ROUND_UP(quota, rcan->rx_max_data); if (rcan->quota == 0) { - rk3576_canfd_write(rcan, CANFD_INT_MASK, INT_ENABLE); + rk3576_can_write(rcan, CAN_INT_MASK, INT_ENABLE); return 1; } @@ -914,7 +838,7 @@ static int rk3576_canfd_rx_dma(struct rk3576_canfd *rcan) if (!rxdesc) return -EBUSY; - rxdesc->callback = rk3576_canfd_rx_dma_callback; + rxdesc->callback = rk3576_can_rx_dma_callback; rxdesc->callback_param = rcan; dmaengine_submit(rxdesc); @@ -922,9 +846,9 @@ static int rk3576_canfd_rx_dma(struct rk3576_canfd *rcan) return 1; } -static int rk3576_canfd_err(struct net_device *ndev, u32 isr) +static int rk3576_can_err(struct net_device *ndev, u32 isr) { - struct rk3576_canfd *rcan = netdev_priv(ndev); + struct rk3576_can *rcan = netdev_priv(ndev); struct net_device_stats *stats = &ndev->stats; struct can_frame *cf; struct sk_buff *skb; @@ -933,9 +857,9 @@ static int rk3576_canfd_err(struct net_device *ndev, u32 isr) skb = alloc_can_err_skb(ndev, &cf); - rxerr = rk3576_canfd_read(rcan, CANFD_RXERRORCNT); - txerr = rk3576_canfd_read(rcan, CANFD_TXERRORCNT); - sta_reg = rk3576_canfd_read(rcan, CANFD_STATE); + rxerr = rk3576_can_read(rcan, CAN_RXERRORCNT); + txerr = rk3576_can_read(rcan, CAN_TXERRORCNT); + sta_reg = rk3576_can_read(rcan, CAN_STATE); if (skb) { cf->data[6] = txerr; @@ -972,14 +896,14 @@ static int rk3576_canfd_err(struct net_device *ndev, u32 isr) } if (isr & BUSOFF_RCY_INT) { - rk3576_canfd_write(rcan, CANFD_INT_MASK, 0xffff); - rk3576_canfd_write(rcan, CANFD_INT, isr); + rk3576_can_write(rcan, CAN_INT_MASK, 0xffff); + rk3576_can_write(rcan, CAN_INT, isr); napi_schedule(&rcan->napi); - rk3576_canfd_write(rcan, CANFD_BUSOFFRCY_CFG, BUSOFF_RCY_TIME_CLR); - rk3576_canfd_write(rcan, CANFD_BUSOFF_RCY_THR, BUSOFF_RCY_TIME_SLOW); - rk3576_canfd_write(rcan, CANFD_BUSOFFRCY_CFG, - BUSOFF_RCY_MODE_EN | BUSOFF_RCY_CNT_SLOW); - rk3576_canfd_write(rcan, CANFD_INT_MASK, INT_ENABLE); + rk3576_can_write(rcan, CAN_BUSOFFRCY_CFG, BUSOFF_RCY_TIME_CLR); + rk3576_can_write(rcan, CAN_BUSOFF_RCY_THR, BUSOFF_RCY_TIME_SLOW); + rk3576_can_write(rcan, CAN_BUSOFFRCY_CFG, + BUSOFF_RCY_MODE_EN | BUSOFF_RCY_CNT_SLOW); + rk3576_can_write(rcan, CAN_INT_MASK, INT_ENABLE); netif_stop_queue(ndev); can_free_echo_skb(ndev, 0, NULL); netif_start_queue(ndev); @@ -991,29 +915,29 @@ static int rk3576_canfd_err(struct net_device *ndev, u32 isr) return 0; } -static irqreturn_t rk3576_canfd_interrupt(int irq, void *dev_id) +static irqreturn_t rk3576_can_interrupt(int irq, void *dev_id) { struct net_device *ndev = (struct net_device *)dev_id; - struct rk3576_canfd *rcan = netdev_priv(ndev); + struct rk3576_can *rcan = netdev_priv(ndev); struct net_device_stats *stats = &ndev->stats; u32 err_int = ERR_WARN_INT | RX_BUF_OV_INT | PASSIVE_ERR_INT | BUS_ERR_INT | BUS_OFF_INT | BUSOFF_RCY_INT | BUS_OFF_RECOVERY_INT | RX_STR_FULL_INT; u32 isr; - isr = rk3576_canfd_read(rcan, CANFD_INT); + isr = rk3576_can_read(rcan, CAN_INT); if ((isr & RX_STR_TIMEOUT_INT) || (isr & ISM_WTM_INT) || (isr & RX_STR_FULL_INT)) { - rk3576_canfd_write(rcan, CANFD_INT_MASK, - ISM_WTM_INT | RX_STR_TIMEOUT_INT | - RX_FINISH_INT); + rk3576_can_write(rcan, CAN_INT_MASK, + ISM_WTM_INT | RX_STR_TIMEOUT_INT | + RX_FINISH_INT); if (rcan->use_dma) - rk3576_canfd_rx_dma(rcan); + rk3576_can_rx_dma(rcan); else napi_schedule(&rcan->napi); } if (isr & TX_FINISH_INT) { - rk3576_canfd_write(rcan, CANFD_CMD, 0); + rk3576_can_write(rcan, CAN_CMD, 0); stats->tx_bytes += can_get_echo_skb(ndev, 0, NULL); stats->tx_packets++; netif_wake_queue(ndev); @@ -1021,17 +945,17 @@ static irqreturn_t rk3576_canfd_interrupt(int irq, void *dev_id) if (isr & err_int) { /* error interrupt */ - if (rk3576_canfd_err(ndev, isr)) + if (rk3576_can_err(ndev, isr)) netdev_err(ndev, "can't allocate buffer - clearing pending interrupts\n"); } - rk3576_canfd_write(rcan, CANFD_INT, isr); + rk3576_can_write(rcan, CAN_INT, isr); return IRQ_HANDLED; } -static int rk3576_canfd_open(struct net_device *ndev) +static int rk3576_can_open(struct net_device *ndev) { - struct rk3576_canfd *rcan = netdev_priv(ndev); + struct rk3576_can *rcan = netdev_priv(ndev); int err; /* common open */ @@ -1046,9 +970,9 @@ static int rk3576_canfd_open(struct net_device *ndev) goto exit; } - err = rk3576_canfd_start(ndev); + err = rk3576_can_start(ndev); if (err) { - netdev_err(ndev, "could not start CANFD peripheral\n"); + netdev_err(ndev, "could not start CAN peripheral\n"); goto exit_can_start; } @@ -1065,13 +989,13 @@ exit: return err; } -static int rk3576_canfd_close(struct net_device *ndev) +static int rk3576_can_close(struct net_device *ndev) { - struct rk3576_canfd *rcan = netdev_priv(ndev); + struct rk3576_can *rcan = netdev_priv(ndev); netif_stop_queue(ndev); napi_disable(&rcan->napi); - rk3576_canfd_stop(ndev); + rk3576_can_stop(ndev); close_candev(ndev); pm_runtime_put(rcan->dev); @@ -1079,41 +1003,41 @@ static int rk3576_canfd_close(struct net_device *ndev) return 0; } -static const struct net_device_ops rk3576_canfd_netdev_ops = { - .ndo_open = rk3576_canfd_open, - .ndo_stop = rk3576_canfd_close, - .ndo_start_xmit = rk3576_canfd_start_xmit, +static const struct net_device_ops rk3576_can_netdev_ops = { + .ndo_open = rk3576_can_open, + .ndo_stop = rk3576_can_close, + .ndo_start_xmit = rk3576_can_start_xmit, .ndo_change_mtu = can_change_mtu, }; /** - * rk3576_canfd_suspend - Suspend method for the driver + * rk3576_can_suspend - Suspend method for the driver * @dev: Address of the device structure * * Put the driver into low power mode. * Return: 0 on success and failure value on error */ -static int __maybe_unused rk3576_canfd_suspend(struct device *dev) +static int __maybe_unused rk3576_can_suspend(struct device *dev) { struct net_device *ndev = dev_get_drvdata(dev); if (netif_running(ndev)) { netif_stop_queue(ndev); netif_device_detach(ndev); - rk3576_canfd_stop(ndev); + rk3576_can_stop(ndev); } return pm_runtime_force_suspend(dev); } /** - * rk3576_canfd_resume - Resume from suspend + * rk3576_can_resume - Resume from suspend * @dev: Address of the device structure * * Resume operation after suspend. * Return: 0 on success and failure value on error */ -static int __maybe_unused rk3576_canfd_resume(struct device *dev) +static int __maybe_unused rk3576_can_resume(struct device *dev) { struct net_device *ndev = dev_get_drvdata(dev); int ret; @@ -1125,9 +1049,9 @@ static int __maybe_unused rk3576_canfd_resume(struct device *dev) } if (netif_running(ndev)) { - ret = rk3576_canfd_start(ndev); + ret = rk3576_can_start(ndev); if (ret) { - dev_err(dev, "rk3576_canfd_chip_start failed on resume\n"); + dev_err(dev, "rk3576_can_chip_start failed on resume\n"); return ret; } @@ -1139,16 +1063,16 @@ static int __maybe_unused rk3576_canfd_resume(struct device *dev) } /** - * rk3576_canfd_runtime_suspend - Runtime suspend method for the driver + * rk3576_can_runtime_suspend - Runtime suspend method for the driver * @dev: Address of the device structure * * Put the driver into low power mode. * Return: 0 always */ -static int __maybe_unused rk3576_canfd_runtime_suspend(struct device *dev) +static int __maybe_unused rk3576_can_runtime_suspend(struct device *dev) { struct net_device *ndev = dev_get_drvdata(dev); - struct rk3576_canfd *rcan = netdev_priv(ndev); + struct rk3576_can *rcan = netdev_priv(ndev); clk_bulk_disable_unprepare(rcan->num_clks, rcan->clks); @@ -1156,16 +1080,16 @@ static int __maybe_unused rk3576_canfd_runtime_suspend(struct device *dev) } /** - * rk3576_canfd_runtime_resume - Runtime resume from suspend + * rk3576_can_runtime_resume - Runtime resume from suspend * @dev: Address of the device structure * * Resume operation after suspend. * Return: 0 on success and failure value on error */ -static int __maybe_unused rk3576_canfd_runtime_resume(struct device *dev) +static int __maybe_unused rk3576_can_runtime_resume(struct device *dev) { struct net_device *ndev = dev_get_drvdata(dev); - struct rk3576_canfd *rcan = netdev_priv(ndev); + struct rk3576_can *rcan = netdev_priv(ndev); int ret; ret = clk_bulk_prepare_enable(rcan->num_clks, rcan->clks); @@ -1177,26 +1101,26 @@ static int __maybe_unused rk3576_canfd_runtime_resume(struct device *dev) return 0; } -static const struct dev_pm_ops rk3576_canfd_dev_pm_ops = { - SET_SYSTEM_SLEEP_PM_OPS(rk3576_canfd_suspend, rk3576_canfd_resume) - SET_RUNTIME_PM_OPS(rk3576_canfd_runtime_suspend, - rk3576_canfd_runtime_resume, NULL) +static const struct dev_pm_ops rk3576_can_dev_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(rk3576_can_suspend, rk3576_can_resume) + SET_RUNTIME_PM_OPS(rk3576_can_runtime_suspend, + rk3576_can_runtime_resume, NULL) }; -static const struct of_device_id rk3576_canfd_of_match[] = { +static const struct of_device_id rk3576_can_of_match[] = { { - .compatible = "rockchip,rk3576-canfd", - .data = (void *)ROCKCHIP_RK3576_CANFD + .compatible = "rockchip,rk3576-can", + .data = (void *)ROCKCHIP_RK3576_CAN }, { - .compatible = "rockchip,rv1126b-canfd", - .data = (void *)ROCKCHIP_RV1126B_CANFD + .compatible = "rockchip,rv1126b-can", + .data = (void *)ROCKCHIP_RV1126B_CAN }, {}, }; -MODULE_DEVICE_TABLE(of, rk3576_canfd_of_match); +MODULE_DEVICE_TABLE(of, rk3576_can_of_match); -static void rk3576_canfd_dma_init(struct rk3576_canfd *rcan) +static void rk3576_can_dma_init(struct rk3576_can *rcan) { struct dma_slave_config rxconf = { .direction = DMA_DEV_TO_MEM, @@ -1221,10 +1145,10 @@ static void rk3576_canfd_dma_init(struct rk3576_canfd *rcan) dmaengine_slave_config(rcan->rxchan, &rxconf); } -static int rk3576_canfd_probe(struct platform_device *pdev) +static int rk3576_can_probe(struct platform_device *pdev) { struct net_device *ndev; - struct rk3576_canfd *rcan; + struct rk3576_can *rcan; struct resource *res; void __iomem *addr; int err, irq; @@ -1241,9 +1165,9 @@ static int rk3576_canfd_probe(struct platform_device *pdev) if (IS_ERR(addr)) return -EBUSY; - ndev = alloc_candev(sizeof(struct rk3576_canfd), 1); + ndev = alloc_candev(sizeof(struct rk3576_can), 1); if (!ndev) { - dev_err(&pdev->dev, "could not allocate memory for CANFD device\n"); + dev_err(&pdev->dev, "could not allocate memory for CAN device\n"); return -ENOMEM; } rcan = netdev_priv(ndev); @@ -1251,7 +1175,7 @@ static int rk3576_canfd_probe(struct platform_device *pdev) rcan->reset = devm_reset_control_array_get(&pdev->dev, false, false); if (IS_ERR(rcan->reset)) { if (PTR_ERR(rcan->reset) != -EPROBE_DEFER) - dev_err(&pdev->dev, "failed to get canfd reset lines\n"); + dev_err(&pdev->dev, "failed to get can reset lines\n"); err = PTR_ERR(rcan->reset); goto err_free; } @@ -1268,17 +1192,14 @@ static int rk3576_canfd_probe(struct platform_device *pdev) rcan->dev = &pdev->dev; rcan->can.state = CAN_STATE_STOPPED; - rcan->can.bittiming_const = &rk3576_canfd_bittiming_const; - rcan->can.data_bittiming_const = &rk3576_canfd_data_bittiming_const; - rcan->can.do_set_mode = rk3576_canfd_set_mode; - rcan->can.do_get_berr_counter = rk3576_canfd_get_berr_counter; - rcan->can.do_set_bittiming = rk3576_canfd_set_bittiming; - rcan->can.do_set_data_bittiming = rk3576_canfd_set_bittiming; - rcan->can.ctrlmode = CAN_CTRLMODE_FD; - /* IFI CANFD can do both Bosch FD and ISO FD */ + rcan->can.bittiming_const = &rk3576_can_bittiming_const; + rcan->can.data_bittiming_const = &rk3576_can_data_bittiming_const; + rcan->can.do_set_mode = rk3576_can_set_mode; + rcan->can.do_get_berr_counter = rk3576_can_get_berr_counter; + rcan->can.do_set_bittiming = rk3576_can_set_bittiming; + rcan->can.do_set_data_bittiming = rk3576_can_set_bittiming; rcan->can.ctrlmode_supported = CAN_CTRLMODE_LOOPBACK | - CAN_CTRLMODE_LISTENONLY | - CAN_CTRLMODE_FD; + CAN_CTRLMODE_LISTENONLY; rcan->rx_fifo_shift = INTM_LEFT_CNT_SHIFT; rcan->rx_fifo_mask = INTM_LEFT_CNT_MASK; @@ -1308,14 +1229,14 @@ static int rk3576_canfd_probe(struct platform_device *pdev) rcan->rxchan = NULL; rcan->use_dma = 0; } else { - rcan->rx_dma_src_addr = res->start + CANFD_RXFRD; + rcan->rx_dma_src_addr = res->start + CAN_RXFRD; rcan->dma_size = rcan->rx_max_data * 4; rcan->use_dma = 1; } if (rcan->use_dma) - rk3576_canfd_dma_init(rcan); + rk3576_can_dma_init(rcan); - ndev->netdev_ops = &rk3576_canfd_netdev_ops; + ndev->netdev_ops = &rk3576_can_netdev_ops; ndev->irq = irq; ndev->flags |= IFF_ECHO; @@ -1329,7 +1250,7 @@ static int rk3576_canfd_probe(struct platform_device *pdev) __func__, err); goto err_pmdisable; } - netif_napi_add(ndev, &rcan->napi, rk3576_canfd_rx_poll); + netif_napi_add(ndev, &rcan->napi, rk3576_can_rx_poll); err = register_candev(ndev); if (err) { dev_err(&pdev->dev, "registering %s failed (err=%d)\n", @@ -1338,7 +1259,7 @@ static int rk3576_canfd_probe(struct platform_device *pdev) } /* register interrupt handler */ - err = devm_request_irq(&pdev->dev, irq, rk3576_canfd_interrupt, + err = devm_request_irq(&pdev->dev, irq, rk3576_can_interrupt, 0, ndev->name, ndev); if (err) { dev_err(&pdev->dev, "request_irq err: %d\n", err); @@ -1368,10 +1289,10 @@ err_free: return err; } -static int rk3576_canfd_remove(struct platform_device *pdev) +static int rk3576_can_remove(struct platform_device *pdev) { struct net_device *ndev = platform_get_drvdata(pdev); - struct rk3576_canfd *rcan = netdev_priv(ndev); + struct rk3576_can *rcan = netdev_priv(ndev); if (rcan->rxbuf) { dma_free_coherent(rcan->dev, rcan->dma_size * rcan->rx_fifo_depth, rcan->rxbuf, @@ -1390,17 +1311,17 @@ static int rk3576_canfd_remove(struct platform_device *pdev) return 0; } -static struct platform_driver rk3576_canfd_driver = { +static struct platform_driver rk3576_can_driver = { .driver = { .name = DRV_NAME, - .pm = &rk3576_canfd_dev_pm_ops, - .of_match_table = rk3576_canfd_of_match, + .pm = &rk3576_can_dev_pm_ops, + .of_match_table = rk3576_can_of_match, }, - .probe = rk3576_canfd_probe, - .remove = rk3576_canfd_remove, + .probe = rk3576_can_probe, + .remove = rk3576_can_remove, }; -module_platform_driver(rk3576_canfd_driver); +module_platform_driver(rk3576_can_driver); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Elaine Zhang "); -MODULE_DESCRIPTION("RK3576 CANFD Drivers"); +MODULE_DESCRIPTION("RK3576 CAN Drivers"); From 5b28e51f19a5cea4cc2060890f74c9fde78525b9 Mon Sep 17 00:00:00 2001 From: Elaine Zhang Date: Thu, 9 Oct 2025 18:06:31 +0800 Subject: [PATCH 30/40] arm64: configs: rockchip_linux_defconfig enable CONFIG_CAN_RK3576 Rename CONFIG_CANFD_RK3576 to CONFIG_CAN_RK3576 Signed-off-by: Elaine Zhang Change-Id: I9c1f67134ddc104e76c7cac642c027e66ce1c5f6 --- arch/arm64/configs/rockchip_linux_defconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm64/configs/rockchip_linux_defconfig b/arch/arm64/configs/rockchip_linux_defconfig index 2bdaa128c37b..c26368904f4b 100644 --- a/arch/arm64/configs/rockchip_linux_defconfig +++ b/arch/arm64/configs/rockchip_linux_defconfig @@ -220,7 +220,7 @@ CONFIG_MOTORCOMM_PHY=y CONFIG_ROCKCHIP_FEPHY=y CONFIG_ROCKCHIP_PHY=y CONFIG_RK630_PHY=y -CONFIG_CANFD_RK3576=y +CONFIG_CAN_RK3576=y CONFIG_USB_RTL8150=y CONFIG_USB_RTL8152=y CONFIG_WL_ROCKCHIP=y From 071f8bcb45b0fdca2062167bdf365c579566e3bc Mon Sep 17 00:00:00 2001 From: Elaine Zhang Date: Thu, 9 Oct 2025 18:08:42 +0800 Subject: [PATCH 31/40] ARM: dts: rockchip: rk3506: Fix compatible for can node Signed-off-by: Elaine Zhang Change-Id: I9752391f1dfea98e5425c6a553fee5e7d3e5af4d --- arch/arm/boot/dts/rk3506.dtsi | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm/boot/dts/rk3506.dtsi b/arch/arm/boot/dts/rk3506.dtsi index 77d574ac9246..a6bf49d75413 100644 --- a/arch/arm/boot/dts/rk3506.dtsi +++ b/arch/arm/boot/dts/rk3506.dtsi @@ -40,7 +40,7 @@ }; can0: can@ff320000 { - compatible = "rockchip,rk3506-canfd", "rockchip,rk3576-canfd"; + compatible = "rockchip,rk3506-can", "rockchip,rk3576-can"; reg = <0xff320000 0x1000>; interrupts = ; clocks = <&cru CLK_CAN0>, <&cru HCLK_CAN0>; @@ -53,7 +53,7 @@ }; can1: can@ff330000 { - compatible = "rockchip,rk3506-canfd", "rockchip,rk3576-canfd"; + compatible = "rockchip,rk3506-can", "rockchip,rk3576-can"; reg = <0xff330000 0x1000>; interrupts = ; clocks = <&cru CLK_CAN1>, <&cru HCLK_CAN1>; From f762a94b7c3eb794fdca5ba3d68a94e63b4a2fea Mon Sep 17 00:00:00 2001 From: Elaine Zhang Date: Thu, 9 Oct 2025 18:09:58 +0800 Subject: [PATCH 32/40] arm64: dts: rockchip: rk3576: Fix compatible for can node Signed-off-by: Elaine Zhang Change-Id: I7476a47fd36d7d7e5137e64a5e673663c35839c8 --- arch/arm64/boot/dts/rockchip/rk3576.dtsi | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm64/boot/dts/rockchip/rk3576.dtsi b/arch/arm64/boot/dts/rockchip/rk3576.dtsi index ec54470fd966..60205e003d93 100644 --- a/arch/arm64/boot/dts/rockchip/rk3576.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk3576.dtsi @@ -5547,7 +5547,7 @@ }; can0: can@2ac00000 { - compatible = "rockchip,rk3576-canfd"; + compatible = "rockchip,rk3576-can"; reg = <0x0 0x2ac00000 0x0 0x1000>; interrupts = ; clocks = <&cru CLK_CAN0>, <&cru HCLK_CAN0>; @@ -5558,7 +5558,7 @@ }; can1: can@2ac10000 { - compatible = "rockchip,rk3576-canfd"; + compatible = "rockchip,rk3576-can"; reg = <0x0 0x2ac10000 0x0 0x1000>; interrupts = ; clocks = <&cru CLK_CAN1>, <&cru HCLK_CAN1>; From 535db335d2d00606df54a440ae4f5480fc3753b6 Mon Sep 17 00:00:00 2001 From: Elaine Zhang Date: Thu, 9 Oct 2025 18:10:40 +0800 Subject: [PATCH 33/40] arm64: dts: rockchip: rv1126b: Fix compatible for can node Signed-off-by: Elaine Zhang Change-Id: Ib2c841c8fde7605c299208583638b78f13e9f365 --- arch/arm64/boot/dts/rockchip/rv1126b.dtsi | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm64/boot/dts/rockchip/rv1126b.dtsi b/arch/arm64/boot/dts/rockchip/rv1126b.dtsi index 4a9985cc930b..35de85a0ac6b 100644 --- a/arch/arm64/boot/dts/rockchip/rv1126b.dtsi +++ b/arch/arm64/boot/dts/rockchip/rv1126b.dtsi @@ -3258,7 +3258,7 @@ }; can0: can@21d40000 { - compatible = "rockchip,rv1126b-canfd"; + compatible = "rockchip,rv1126b-can"; reg = <0x21d40000 0x1000>; interrupts = ; clocks = <&cru CLK_CAN0>, <&cru HCLK_CAN0>; @@ -3271,7 +3271,7 @@ }; can1: can@21d50000 { - compatible = "rockchip,rv1126b-canfd"; + compatible = "rockchip,rv1126b-can"; reg = <0x21d50000 0x1000>; interrupts = ; clocks = <&cru CLK_CAN1>, <&cru HCLK_CAN1>; From f0433771a586535dcb0ab4a5174f4ec03596e77d Mon Sep 17 00:00:00 2001 From: Binyuan Lan Date: Thu, 9 Oct 2025 20:53:10 +0800 Subject: [PATCH 34/40] arm64: dts: rockchip: add Tablet Board devicetree for RK3576S-RK809 Signed-off-by: Binyuan Lan Change-Id: Ic944ad209f5875a302db639dfda06be385871209 --- arch/arm64/boot/dts/rockchip/Makefile | 1 + .../rockchip/rk3576s-rk809-tablet-camera.dtsi | 434 +++++ .../dts/rockchip/rk3576s-rk809-tablet-v10.dts | 1521 +++++++++++++++++ 3 files changed, 1956 insertions(+) create mode 100644 arch/arm64/boot/dts/rockchip/rk3576s-rk809-tablet-camera.dtsi create mode 100644 arch/arm64/boot/dts/rockchip/rk3576s-rk809-tablet-v10.dts diff --git a/arch/arm64/boot/dts/rockchip/Makefile b/arch/arm64/boot/dts/rockchip/Makefile index 01bd27dececb..d1c81766d08a 100644 --- a/arch/arm64/boot/dts/rockchip/Makefile +++ b/arch/arm64/boot/dts/rockchip/Makefile @@ -304,6 +304,7 @@ dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3576-vehicle-evb-v21.dtb dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3576-vehicle-evb-v21-mcu.dtb dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3576s-evb1-v10.dtb dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3576s-evb1-v10-linux.dtb +dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3576s-rk809-tablet-v10.dtb dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3576s-tablet-v10.dtb dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3588-evb1-lp4-v10.dtb dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3588-evb1-lp4-v10-dsi-dsc-MV2100UZ1.dtb diff --git a/arch/arm64/boot/dts/rockchip/rk3576s-rk809-tablet-camera.dtsi b/arch/arm64/boot/dts/rockchip/rk3576s-rk809-tablet-camera.dtsi new file mode 100644 index 000000000000..248620c8d8b3 --- /dev/null +++ b/arch/arm64/boot/dts/rockchip/rk3576s-rk809-tablet-camera.dtsi @@ -0,0 +1,434 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) +/* + * Copyright (c) 2024 Rockchip Electronics Co., Ltd. + * + */ +/ { + flash_rgb13h: flash-rgb13h { + status = "okay"; + compatible = "led,rgb13h"; + label = "gpio-flash"; + pinctrl-names = "default"; + pinctrl-0 = <&flash_led_gpios>; + led-max-microamp = <20000>; + flash-max-microamp = <20000>; + flash-max-timeout-us = <1000000>; + enable-gpio = <&gpio3 RK_PD0 GPIO_ACTIVE_HIGH>; + //mode-gpio = <&gpio2 RK_PC3 GPIO_ACTIVE_HIGH>; //EN + rockchip,camera-module-index = <0>; + rockchip,camera-module-facing = "back"; + }; + + vcc_mipipwr: vcc-mipipwr-regulator { + compatible = "regulator-fixed"; + gpio = <&gpio3 RK_PC6 GPIO_ACTIVE_HIGH>; + pinctrl-names = "default"; + pinctrl-0 = <&mipicam_pwr>; + regulator-name = "vcc_mipipwr"; + enable-active-high; + regulator-boot-on; + }; +}; + +&csi2_dcphy0 { + status = "okay"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + port@0 { + reg = <0>; + #address-cells = <1>; + #size-cells = <0>; + + mipi_in_gc05a2: endpoint@1 { + reg = <1>; + remote-endpoint = <&gc05a2_out0>; + data-lanes = <1 2 3 4>; + }; + + }; + port@1 { + reg = <1>; + #address-cells = <1>; + #size-cells = <0>; + + csidcphy0_out: endpoint@0 { + reg = <0>; + remote-endpoint = <&mipi0_csi2_input>; + }; + }; + }; +}; + +&csi2_dphy0 { + status = "okay"; + ports { + #address-cells = <1>; + #size-cells = <0>; + port@0 { + reg = <0>; + #address-cells = <1>; + #size-cells = <0>; + + mipi_in_gc02m1: endpoint@1 { + reg = <1>; + remote-endpoint = <&gc02m1_out>; + data-lanes = <1>; + }; + }; + port@1 { + reg = <1>; + #address-cells = <1>; + #size-cells = <0>; + + csidphy0_out: endpoint@0 { + reg = <0>; + remote-endpoint = <&mipi1_csi2_input>; + }; + }; + }; +}; + +&csi2_dphy3 { + status = "okay"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + port@0 { + reg = <0>; + #address-cells = <1>; + #size-cells = <0>; + + mipi_in_ov13850: endpoint@1 { + reg = <1>; + remote-endpoint = <&ov13850_out>; + data-lanes = <1 2 3 4>; + }; + }; + port@1 { + reg = <1>; + #address-cells = <1>; + #size-cells = <0>; + + csidphy3_out: endpoint@0 { + reg = <0>; + remote-endpoint = <&mipi3_csi2_input>; + }; + }; + }; +}; + +&i2c4 { + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <&i2c4m3_xfer>; + + gc02m1: gc02m1@37 { + status = "okay"; + compatible = "galaxycore,gc02m1"; + reg = <0x37>; + clocks = <&cru CLK_MIPI_CAMERAOUT_M1>; + clock-names = "xvclk"; + pinctrl-names = "default"; + pinctrl-0 = <&cam_clk1m0_clk1>; + pwdn-gpios = <&gpio3 RK_PD3 GPIO_ACTIVE_LOW>; + reset-gpios = <&gpio3 RK_PB0 GPIO_ACTIVE_HIGH>; + avdd-supply = <&vcc_mipipwr>; + //dovdd-supply = <&vcc_1v8_cam>; + //dvdd-supply = <&vcc1v2_dvp>; + dvdd-supply = <&vcc_1v2_cam>; + rockchip,camera-module-index = <2>; + rockchip,camera-module-facing = "back"; + rockchip,camera-module-name = "KYT-8789-V10"; + rockchip,camera-module-lens-name = "default"; + port { + gc02m1_out: endpoint { + remote-endpoint = <&mipi_in_gc02m1>; + data-lanes = <1>; + }; + }; + }; +}; + +&i2c5 { + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <&i2c5m3_xfer>; + + dw9714: dw9714@c { + compatible = "dongwoon,dw9714"; + status = "okay"; + reg = <0x0c>; + rockchip,camera-module-index = <0>; + rockchip,vcm-start-current = <5>; + rockchip,vcm-rated-current = <65>; + rockchip,vcm-step-mode = <5>; + rockchip,camera-module-facing = "back"; + avdd-supply = <&vcc_mipipwr>; + xsd-gpios = <&gpio3 RK_PD1 GPIO_ACTIVE_HIGH>; + }; + + gc05a2: gc05a2@37 { + compatible = "galaxycore,gc05a2"; + status = "okay"; + reg = <0x37>; + clocks = <&cru CLK_MIPI_CAMERAOUT_M0>; + clock-names = "xvclk"; + pinctrl-names = "default"; + pinctrl-0 = <&cam_clk0m0_clk0>; + pwdn-gpios = <&gpio3 RK_PC7 GPIO_ACTIVE_HIGH>; + reset-gpios = <&gpio3 RK_PA6 GPIO_ACTIVE_HIGH>; + avdd-supply = <&vcc_mipipwr>; + //dovdd-supply = <&vcc_1v8_cam>; + dvdd-supply = <&vcc_1v2_cam>; + rockchip,camera-module-index = <1>; + rockchip,camera-module-facing = "front"; + rockchip,camera-module-name = "KYT-11210-V2"; + rockchip,camera-module-lens-name = "default"; + port { + gc05a2_out0: endpoint { + remote-endpoint = <&mipi_in_gc05a2>; + data-lanes = <1 2>; + }; + }; + }; + + ov13850: ov13850@10 { + status = "okay"; + compatible = "ovti,ov13850"; + reg = <0x10>; + clocks = <&cru CLK_MIPI_CAMERAOUT_M2>; + clock-names = "xvclk"; + pinctrl-names = "default"; + pinctrl-0 = <&cam_clk2m0_clk2>; + pwdn-gpios = <&gpio3 RK_PD2 GPIO_ACTIVE_HIGH>; + reset-gpios = <&gpio3 RK_PA7 GPIO_ACTIVE_HIGH>; + dvdd-supply = <&vcc_1v2_cam>; + avdd-supply = <&vcc_mipipwr>; + //dovdd-supply = <&vcc_1v8_cam>; + rockchip,camera-module-index = <0>; + rockchip,camera-module-facing = "back"; + rockchip,camera-module-name = "G1-T-B-s5k"; + rockchip,camera-module-lens-name = "XA-0806B"; + flash-leds = <&flash_rgb13h>; + lens-focus = <&dw9714>; + port { + ov13850_out: endpoint { + remote-endpoint = <&mipi_in_ov13850>; + data-lanes = <1 2 3 4>; + }; + }; + }; +}; + +&mipi0_csi2 { + status = "okay"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + #address-cells = <1>; + #size-cells = <0>; + + mipi0_csi2_input: endpoint@1 { + reg = <1>; + remote-endpoint = <&csidcphy0_out>; + }; + }; + + port@1 { + reg = <1>; + #address-cells = <1>; + #size-cells = <0>; + + mipi0_csi2_output: endpoint@0 { + reg = <0>; + remote-endpoint = <&cif_mipi_in0>; + }; + }; + }; +}; + +&mipi3_csi2 { + status = "okay"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + #address-cells = <1>; + #size-cells = <0>; + + mipi3_csi2_input: endpoint@1 { + reg = <1>; + remote-endpoint = <&csidphy3_out>; + }; + }; + + port@1 { + reg = <1>; + #address-cells = <1>; + #size-cells = <0>; + + mipi3_csi2_output: endpoint@0 { + reg = <0>; + remote-endpoint = <&cif_mipi3_in0>; + }; + }; + }; +}; + + +&mipi1_csi2 { + status = "okay"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + #address-cells = <1>; + #size-cells = <0>; + + mipi1_csi2_input: endpoint@1 { + reg = <1>; + remote-endpoint = <&csidphy0_out>; + }; + }; + + port@1 { + reg = <1>; + #address-cells = <1>; + #size-cells = <0>; + + mipi1_csi2_output: endpoint@0 { + reg = <0>; + remote-endpoint = <&cif_mipi1_in0>; + }; + }; + }; +}; + +&pinctrl { + cam { + mipicam_pwr: mipicam-pwr { + rockchip,pins = + /* camera power en */ + <3 RK_PC6 RK_FUNC_GPIO &pcfg_pull_none>; + }; + + flash_led_gpios: flash-led { + rockchip,pins = + /* flash led enable */ + <3 RK_PD0 RK_FUNC_GPIO &pcfg_pull_none>; + }; + }; +}; + +&rkcif { + status = "okay"; +}; + +&rkcif_mipi_lvds { + status = "okay"; + + port { + cif_mipi_in0: endpoint { + remote-endpoint = <&mipi0_csi2_output>; + }; + }; +}; + +&rkcif_mipi_lvds_sditf { + status = "okay"; + + port { + mipi_lvds_sditf: endpoint { + remote-endpoint = <&isp_vir0_in0>; + }; + }; +}; + +&rkcif_mipi_lvds1 { + status = "okay"; + + port { + cif_mipi1_in0: endpoint { + remote-endpoint = <&mipi1_csi2_output>; + }; + }; +}; + +&rkcif_mipi_lvds1_sditf { + status = "okay"; + + port { + mipi_lvds1_sditf: endpoint { + remote-endpoint = <&isp_vir0_in2>; + }; + }; +}; + +&rkcif_mipi_lvds3 { + status = "okay"; + + port { + cif_mipi3_in0: endpoint { + remote-endpoint = <&mipi3_csi2_output>; + }; + }; +}; + +&rkcif_mipi_lvds3_sditf { + status = "okay"; + + port { + mipi_lvds3_sditf: endpoint { + remote-endpoint = <&isp_vir0_in1>; + }; + }; +}; + +&rkcif_mmu { + status = "okay"; +}; + +&rkisp { + status = "okay"; +}; + +&rkisp_mmu { + status = "okay"; +}; + +&rkisp_vir0 { + status = "okay"; + + port { + #address-cells = <1>; + #size-cells = <0>; + + isp_vir0_in0: endpoint@0 { + reg = <0>; + remote-endpoint = <&mipi_lvds_sditf>; + }; + + isp_vir0_in1: endpoint@1 { + reg = <1>; + remote-endpoint = <&mipi_lvds3_sditf>; + }; + + isp_vir0_in2: endpoint@2 { + reg = <2>; + remote-endpoint = <&mipi_lvds1_sditf>; + }; + }; +}; diff --git a/arch/arm64/boot/dts/rockchip/rk3576s-rk809-tablet-v10.dts b/arch/arm64/boot/dts/rockchip/rk3576s-rk809-tablet-v10.dts new file mode 100644 index 000000000000..ff5ed3797470 --- /dev/null +++ b/arch/arm64/boot/dts/rockchip/rk3576s-rk809-tablet-v10.dts @@ -0,0 +1,1521 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) +/* + * Copyright (c) 2024 Rockchip Electronics Co., Ltd. + * + */ + +/dts-v1/; + +#include +#include +#include +#include +#include +#include +#include +#include +#include "rk3576s.dtsi" +#include "rk3576-android.dtsi" +#include "rk3576s-rk809-tablet-camera.dtsi" + +/ { + model = "Rockchip RK3576S RK809 TABLET V10 Board"; + compatible = "rockchip,rk3576s-rk809-tablet-v10", "rockchip,rk3576s"; + + adc_keys: adc-keys { + compatible = "adc-keys"; + io-channels = <&saradc 1>; + io-channel-names = "buttons"; + keyup-threshold-microvolt = <1800000>; + poll-interval = <100>; + + vol-up-key { + label = "volume up"; + linux,code = ; + press-threshold-microvolt = <1750>; + }; + + vol-down-key { + label = "volume down"; + linux,code = ; + press-threshold-microvolt = <1350000>; + }; + }; + + backlight: backlight { + compatible = "pwm-backlight"; + pwms = <&pwm0_2ch_1 0 25000 0>; + brightness-levels = < + 0 20 20 21 21 22 22 23 + 23 24 24 25 25 26 26 27 + 27 28 28 29 29 30 30 31 + 31 32 32 33 33 34 34 35 + 35 36 36 37 37 38 38 39 + 40 41 42 43 44 45 46 47 + 48 49 50 51 52 53 54 55 + 56 57 58 59 60 61 62 63 + 64 65 66 67 68 69 70 71 + 72 73 74 75 76 77 78 79 + 80 81 82 83 84 85 86 87 + 88 89 90 91 92 93 94 95 + 96 97 98 99 100 101 102 103 + 104 105 106 107 108 109 110 111 + 112 113 114 115 116 117 118 119 + 120 121 122 123 124 125 126 127 + 128 129 130 131 132 133 134 135 + 136 137 138 139 140 141 142 143 + 144 145 146 147 148 149 150 151 + 152 153 154 155 156 157 158 159 + 160 161 162 163 164 165 166 167 + 168 169 170 171 172 173 174 175 + 176 177 178 179 180 181 182 183 + 184 185 186 187 188 189 190 191 + 192 193 194 195 196 197 198 199 + 200 201 202 203 204 205 206 207 + 208 209 210 211 212 213 214 215 + 216 217 218 219 220 221 222 223 + 224 225 226 227 228 229 230 231 + 232 233 234 235 236 237 238 239 + 240 241 242 243 244 245 246 247 + 248 249 250 251 252 253 254 255 + >; + default-brightness-level = <150>; + max-brightness-level = <145>; + }; + + bt-sound { + compatible = "simple-audio-card"; + simple-audio-card,format = "dsp_b"; + simple-audio-card,bitclock-inversion = <1>; + simple-audio-card,mclk-fs = <256>; + simple-audio-card,name = "rockchip,bt"; + simple-audio-card,cpu { + sound-dai = <&sai2>; + }; + simple-audio-card,codec { + sound-dai = <&bt_sco>; + }; + }; + + bt_sco: bt-sco { + compatible = "delta,dfbmcs320"; + #sound-dai-cells = <0>; + status = "okay"; + }; + + charge-animation { + compatible = "rockchip,uboot-charge"; + rockchip,uboot-charge-on = <0>; + rockchip,android-charge-on = <1>; + rockchip,uboot-low-power-voltage = <3450>; + rockchip,screen-on-voltage = <3500>; + rockchip,auto-wakeup-interval = <5>; + rockchip,uboot-exit-charge-level = <2>; + rockchip,uboot-exit-charge-voltage = <3500>; + rockchip,uboot-exit-charge-auto = <1>; + status = "okay"; + }; + + charger-manager { + compatible = "rockchip-charger-manager"; + cm-name = "battery"; + cm-poll-mode = <2>; + cm-poll-interval = <1000>; + + cm-chargers = "sc89601-charger";//cx2560x-charger,sc89601-charger + cm-chargers-phandle = <&usbc0>; + cm-fuel-gauge = "battery"; + /* monitored-battery = <&bat>; */ + extcon = <&u2phy0>; + vbus-supply = <&vbus5v0_typec>; + //cm-jeita-temp-charge-table = <0 15 2400000 4350000>, + // <15 45 2400000 4350000>, + // <45 60 2400000 4200000>; + }; + + dp0_sound: dp0-sound { + compatible = "rockchip,hdmi"; + rockchip,mclk-fs = <512>; + rockchip,card-name = "rockchip-dp0"; + rockchip,cpu = <&spdif_tx3>; + rockchip,codec = <&dp0 1>; + rockchip,jack-det; + }; + + rk809-sound { + compatible = "rockchip,multicodecs-card"; + rockchip,card-name = "rockchip-rk809"; + hp-det-gpio = <&gpio4 RK_PA4 GPIO_ACTIVE_LOW>; + io-channels = <&saradc 3>; + io-channel-names = "adc-detect"; + keyup-threshold-microvolt = <1800000>; + poll-interval = <100>; + rockchip,format = "i2s"; + rockchip,mclk-fs = <256>; + rockchip,cpu = <&sai1>; + rockchip,codec = <&rk809_codec>; + pinctrl-names = "default"; + pinctrl-0 = <&hp_det>; + play-pause-key { + label = "playpause"; + linux,code = ; + press-threshold-microvolt = <2000>; + }; + }; + + vcc_sys: vcc-sys { + compatible = "regulator-fixed"; + regulator-name = "vcc_sys"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <3800000>; + regulator-max-microvolt = <3800000>; + }; + + vcc_2v0_pldo_s3: vcc-2v0-pldo-s3 { + compatible = "regulator-fixed"; + regulator-name = "vcc_2v0_pldo_s3"; + regulator-boot-on; + regulator-always-on; + regulator-min-microvolt = <2000000>; + regulator-max-microvolt = <2000000>; + vin-supply = <&vcc_sys>; + }; + + vcc_1v1_nldo_s3: vcc-1v1-nldo-s3 { + compatible = "regulator-fixed"; + regulator-name = "vcc_1v1_nldo_s3"; + regulator-boot-on; + regulator-always-on; + regulator-min-microvolt = <1100000>; + regulator-max-microvolt = <1100000>; + vin-supply = <&vcc_sys>; + }; + + vcc_1v8_s0: vcc-1v8-s0 { + compatible = "regulator-fixed"; + regulator-name = "vcc_1v8_s0"; + regulator-boot-on; + regulator-always-on; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + vin-supply = <&vcc_1v8_s3>; + }; + + + vcc_ufs_s0: vcc-ufs-s0 { + compatible = "regulator-fixed"; + regulator-name = "vcc_ufs_s0"; + regulator-boot-on; + regulator-always-on; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + vin-supply = <&vcc_sys>; + }; + + vcc1v8_ufs_vccq2_s0: vcc1v8-ufs-vccq2-s0 { + compatible = "regulator-fixed"; + regulator-name = "vcc1v8_ufs_vccq2_s0"; + regulator-boot-on; + regulator-always-on; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + vin-supply = <&vcc_1v8_s3>; + }; + + vcc1v2_ufs_vccq_s0: vcc1v2-ufs-vccq-s0 { + compatible = "regulator-fixed"; + regulator-name = "vcc1v2_ufs_vccq_s0"; + regulator-boot-on; + regulator-always-on; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1200000>; + vin-supply = <&vcc_sys>; + }; + + vdd_cpu_big_s0: vdd-cpu-big-s0 { + compatible = "pwm-regulator"; + pwms = <&pwm1_6ch_0 0 5000 1>; + regulator-name = "vdd_cpu_big_s0"; + regulator-init-microvolt = <850000>; + regulator-min-microvolt = <550000>; + regulator-max-microvolt = <950000>; + regulator-always-on; + regulator-boot-on; + regulator-settling-time-up-us = <250>; + pwm-supply = <&vcc_sys>; + regulator-state-mem { + regulator-off-in-suspend; + regulator-suspend-microvolt = <850000>; + }; + }; + + vdd_npu_s0: vdd-npu-s0 { + compatible = "pwm-regulator"; + pwms = <&pwm1_6ch_2 0 5000 1>; + regulator-name = "vdd_npu_s0"; + //regulator-init-microvolt = <850000>; + regulator-min-microvolt = <550000>; + regulator-max-microvolt = <950000>; + regulator-always-on; + regulator-boot-on; + regulator-settling-time-up-us = <250>; + pwm-supply = <&vcc_sys>; + regulator-state-mem { + regulator-off-in-suspend; + }; + }; + + seekwcn_boot:seekwcn_boot { + compatible = "seekwave,sv6160"; + pinctrl-names = "default"; + pinctrl-0 = <&wifi_host_wake_irq>,<&wifi_chip_wake_irq>; + sv6160_path = "/vendor/bin/sv6160.bin"; + sv6160_dram_path = "/vendor/etc/firmware/RAM_RW_KERNEL_DRAM"; + sv6160_iram_path = "/vendor/etc/firmware/ROM_EXEC_KERNEL_IRAM"; + dma_type = <1>;/*1:ADMA,2:SDMA*/ + gpio_host_wake = <&gpio0 RK_PB0 GPIO_ACTIVE_LOW>; /* [> CP2AP<] */ + gpio_chip_wake = <&gpio1 RK_PC7 GPIO_ACTIVE_HIGH>; /* AP2CP */ + gpio_chip_en = <&gpio0 RK_PB5 GPIO_ACTIVE_HIGH>; /* CP POWERON */ + status = "okay"; + }; + + sdio_pwrseq: sdio-pwrseq { + compatible = "mmc-pwrseq-simple"; + pinctrl-names = "default"; + pinctrl-0 = <&wifi_power_en>; + + /* + * On the module itself this is one of these (depending + * on the actual card populated): + * - SDIO_RESET_L_WL_REG_ON + * - PDN (power down when low) + */ + post-power-on-delay-ms = <200>; + reset-gpios = <&gpio0 RK_PB5 GPIO_ACTIVE_LOW>; + }; + + wireless_bluetooth: wireless-bluetooth { + compatible = "bluetooth-platdata"; + uart_rts_gpios = <&gpio1 RK_PC2 GPIO_ACTIVE_LOW>; + pinctrl-names = "default", "rts_gpio"; + pinctrl-0 = <&uart4m1_rtsn>; + pinctrl-1 = <&uart4_gpios>; + BT,reset_gpio = <&gpio1 RK_PC7 GPIO_ACTIVE_HIGH>; + BT,wake_gpio = <&gpio1 RK_PD4 GPIO_ACTIVE_HIGH>; + BT,wake_host_irq = <&gpio0 RK_PB1 GPIO_ACTIVE_HIGH>; + status = "disabled"; + }; + + wireless_wlan: wireless-wlan { + compatible = "wlan-platdata"; + wifi_chip_type = "ap6275p"; + pinctrl-names = "default"; + pinctrl-0 = <&wifi_host_wake_irq>; + WIFI,host_wake_irq = <&gpio0 RK_PB0 GPIO_ACTIVE_HIGH>; + WIFI,poweren_gpio = <&gpio0 RK_PB5 GPIO_ACTIVE_HIGH>; + status = "disabled"; + }; +}; + +&combphy0_ps { + status = "okay"; +}; + +&cpu_l0 { + cpu-supply = <&vdd_cpu_lit_s0>; +}; + +&cpu_b0 { + cpu-supply = <&vdd_cpu_big_s0>; +}; + +&csu { + status = "okay"; +}; + +&dp { + status = "okay"; +}; + +&dp0 { + status = "okay"; +}; + +&dp0_in_vp0 { + status = "okay"; +}; + +&dsi_in_vp0 { + status = "okay"; +}; + +&dsi { + status = "okay"; + auto-calculation-mode; + //rockchip,lane-rate = <1080>; + + dsi_panel: panel@0 { + compatible = "aoly,sl008pa21y1285-b00", "simple-panel-dsi"; + reg = <0>; + backlight = <&backlight>; + + enable-gpios = <&gpio1 RK_PC6 GPIO_ACTIVE_HIGH>; + reset-gpios = <&gpio2 RK_PB4 GPIO_ACTIVE_LOW>; + tpreset-gpios = <&gpio0 RK_PC6 GPIO_ACTIVE_HIGH>; + + pinctrl-names = "default"; + pinctrl-0 = <&lcd_enable_gpio>, <&lcd_rst_gpio>; + + prepare-delay-ms = <20>; + reset-delay-ms = <20>; + init-delay-ms = <60>; + enable-delay-ms = <120>; + disable-delay-ms = <20>; + unprepare-delay-ms = <20>; + need-up-reset = <1>; + + width-mm = <137>; + height-mm = <217>; + + dsi,flags = <(MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST | + MIPI_DSI_MODE_LPM | MIPI_DSI_MODE_NO_EOT_PACKET | + MIPI_DSI_CLOCK_NON_CONTINUOUS)>; + dsi,format = ; + dsi,lanes = <4>; + + panel-init-sequence = [ + 15 00 02 41 5A + 39 00 03 41 5A 03 + 15 00 02 80 70 + 39 00 03 41 5A 2F + 15 00 02 28 00 + 15 78 02 10 00 + 39 00 03 41 5A 08 + 39 00 05 80 82 00 82 00 + 39 00 03 41 5A 09 + 39 00 11 80 1A 01 AB 93 A5 97 59 2A B1 06 00 00 80 BF 85 10 + 39 00 11 90 42 44 84 14 C6 13 99 09 C0 0B 6B 36 07 60 28 00 + 39 00 11 A0 80 90 20 AA 00 04 55 55 05 00 1F 0D 42 00 FE FF + 39 00 11 B0 03 7C F3 00 37 01 37 01 00 00 00 41 25 00 4A 00 + 39 00 11 C0 00 00 00 00 00 00 00 00 10 04 02 00 07 00 08 18 + 39 00 03 D0 00 00 + 39 00 03 41 5A 0A + 39 00 11 80 AF AF D4 30 40 2B 3A 42 4B 59 65 66 73 74 86 80 + 39 00 11 90 6F 71 67 60 56 46 3A 31 20 0E 0A 30 40 2B 3A 42 + 39 00 11 A0 4B 59 65 66 73 74 86 80 6F 71 67 60 56 46 3A 31 + 39 00 04 B0 20 0E 0A + 39 00 03 41 5A 0B + 39 00 11 80 00 00 50 B5 C5 AC 00 00 A0 6A 8B A9 AE 22 02 00 + 39 00 11 90 EF D8 B8 F7 25 70 E0 08 11 02 40 13 4F 4D 3C 35 + 39 00 09 A0 F1 A4 06 FF FF 00 03 00 + 39 00 03 41 5A 0C + 39 00 11 80 FE 68 58 02 BC 37 31 08 00 00 56 01 00 55 61 15 + 39 00 11 90 55 51 15 56 01 00 56 01 00 55 61 15 55 51 15 56 + 39 00 11 A0 B1 84 01 00 00 00 00 00 00 40 94 02 00 00 00 30 + 39 00 11 B0 28 15 80 04 00 18 00 00 00 30 0A 00 00 00 00 00 + 39 00 08 C0 00 01 05 C2 B0 00 00 + 39 00 03 41 5A 0D + 39 00 11 80 08 00 00 28 02 00 04 12 00 08 02 77 02 4A 10 F0 + 39 00 07 90 00 02 58 16 04 A1 + 39 00 03 41 5A 0E + 39 00 11 80 FF 81 68 6C 22 FD 22 00 55 55 55 55 05 5A 5A 80 + 39 00 07 90 01 00 00 60 01 00 + 39 00 03 41 5A 0F + 39 00 11 80 01 39 C1 23 63 04 80 04 06 02 28 84 0B 00 70 03 + 39 00 11 90 19 04 20 00 06 10 00 A0 05 5A 10 00 00 90 94 92 + 39 00 11 A0 1D DC 41 B3 65 C0 4A 0B 5A 71 22 80 19 4A 00 20 + 39 00 11 B0 27 9E 01 C0 19 7A 21 14 00 40 30 E0 00 2D D0 82 + 39 00 11 C0 00 00 60 18 63 D0 A0 0D 9A 21 02 10 62 84 28 03 + 39 00 11 D0 8A 88 88 48 92 09 0F 15 1E E0 31 06 04 02 14 04 + 39 00 11 E0 10 22 22 BD 84 C8 41 24 10 51 2D 3E 64 40 41 00 + 39 00 10 F0 00 27 1A 04 F5 FF FF 3F 00 00 15 40 14 00 00 + 39 00 03 41 5A 10 + 39 00 11 80 00 00 03 E7 8F 0B 00 3C 80 01 6A 0C 18 C4 20 C5 + 39 00 11 90 1C 94 D4 62 CD 3D F8 03 3F F0 03 3F 00 FF FF FF + 39 00 03 A0 81 00 + 39 00 03 41 5A 11 + 39 00 08 80 00 00 00 00 00 00 00 + 39 00 03 41 5A 12 + 39 00 11 80 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 39 00 11 90 00 10 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 39 00 11 A0 00 00 00 00 00 00 2D 23 05 FB 00 2D 23 05 FB 00 + 39 00 03 41 5A 13 + 39 00 11 80 00 08 80 15 00 90 10 18 3E 10 00 D6 03 04 18 00 + 39 00 11 90 70 88 30 90 32 70 3E 97 8B 39 30 C4 09 C4 09 C4 + 39 00 11 A0 89 4F DC 45 80 0A C4 09 C4 09 80 02 00 00 00 00 + 39 00 11 B0 00 00 00 00 00 00 1B 01 31 75 B9 42 86 CA 31 75 + 39 00 11 C0 B9 42 86 CA 00 00 00 00 0C 60 00 24 18 00 09 06 + 39 00 11 D0 40 82 01 90 60 00 24 D0 01 09 74 40 02 1D 90 40 + 39 00 11 E0 07 24 D0 01 09 1E 46 1E 46 00 00 20 C5 0F 00 C0 + 39 00 0d F0 10 40 26 4E 46 02 C8 20 80 0C 00 00 + 39 00 03 41 5A 14 + 39 00 11 80 01 02 40 2C 99 DF EF F7 9B CF 01 00 00 C0 83 38 + 39 00 11 90 31 9F 1F 10 23 E6 F3 03 B6 C2 7C 4E C0 66 98 CF + 39 00 11 A0 09 D0 0C BF 1F 01 9A E1 F7 23 00 80 07 00 00 00 + 39 00 11 B0 00 00 00 00 00 00 00 00 00 00 00 00 80 84 07 84 + 39 00 11 C0 07 05 00 30 18 0C CF 84 F9 7C 0C C5 00 F4 3C 98 + 39 00 11 D0 CF C7 50 0C 40 CF 82 F9 7C 0C C5 00 F4 1C 98 CF + 39 00 11 E0 C7 50 0C 40 CF 80 F9 7C 0C C5 00 F4 04 98 CF C7 + 39 00 11 F0 50 0C 40 4F 81 F9 7C 0C C5 00 F4 24 98 CF C7 50 + 39 00 03 41 5A 15 + 39 00 11 80 0C 40 40 80 DF 0F 00 00 00 00 00 00 00 00 00 00 + 39 00 11 90 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 39 00 11 A0 00 00 1C 00 00 00 08 42 60 0E 00 00 00 00 00 00 + 39 00 11 B0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 39 00 11 C0 00 40 00 00 00 00 00 00 00 A0 1F 40 E8 00 20 2C + 39 00 11 D0 8A 34 4D AE 6B 01 81 30 10 85 71 24 A8 6D 5B B3 + 39 00 11 E0 6D 21 C9 24 4D AE 6B 1D 46 41 0C 42 00 28 AB 6D + 39 00 11 F0 5B B3 6D 2D 8A 34 4D AE 6B 01 81 30 10 85 71 24 + 39 00 03 41 5A 16 + 39 00 11 80 A8 6D 5B B3 6D 21 C9 24 4D AE 6B 1D 46 41 0C 42 + 39 00 11 90 00 28 AB 6D 5B B3 6D 01 03 03 00 00 00 00 00 00 + 39 00 11 A0 00 00 00 00 00 00 00 00 00 00 00 00 C0 1F E1 01 + 39 00 11 B0 28 02 00 00 00 00 00 00 00 00 04 00 00 00 00 00 + 39 00 11 C0 00 00 00 00 00 00 02 06 00 00 00 00 00 00 02 00 + 39 00 11 D0 00 00 00 00 00 00 00 00 04 00 00 00 00 00 00 00 + 39 00 11 E0 00 00 00 00 01 00 00 00 00 00 00 00 00 00 00 00 + 39 00 11 F0 00 04 00 00 00 00 00 00 00 00 00 20 00 00 00 00 + 39 00 03 41 5A 17 + 39 00 11 80 00 00 00 00 00 04 00 00 00 00 00 00 00 00 00 20 + 39 00 11 90 00 00 00 00 00 00 00 00 00 10 00 00 00 00 00 00 + 39 00 11 A0 00 00 00 00 00 00 00 10 00 00 00 00 00 00 00 00 + 39 00 11 B0 40 00 00 00 00 00 00 00 00 00 01 00 00 00 00 00 + 39 00 11 C0 00 00 00 00 10 00 00 00 00 00 00 00 00 00 00 00 + 39 00 07 D0 00 01 00 00 00 00 + 39 00 03 41 5A 18 + 39 00 11 80 7F 7F FE FE FE FE FE FE FE FE FE FE D4 7F D4 D4 + 39 00 11 90 D4 D4 D4 D4 D4 D4 D4 D4 AA AA AA AA AA AA AA AA + 39 00 11 A0 AA AA AA AA 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F + 39 00 11 B0 7C 83 79 86 79 86 79 86 79 86 79 86 7A 83 7A 85 + 39 00 11 C0 7A 85 7A 85 7A 85 7A 85 7B 84 7B 84 7B 84 7B 84 + 39 00 11 D0 7B 84 7B 84 7C 83 7C 83 7C 83 7C 83 7C 83 7C 83 + 39 00 11 E0 FE 7F 7F FE FE FE FE FE FE FE FE FE FE D4 7F D4 + 39 00 11 F0 D4 D4 D4 D4 D4 D4 D4 D4 D4 AA AA AA AA AA AA AA + 39 00 03 41 5A 19 + 39 00 11 80 AA AA AA AA AA 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F + 39 00 11 90 7F 7C 83 79 86 79 86 79 86 79 86 79 86 7A 83 7A + 39 00 11 A0 85 7A 85 7A 85 7A 85 7A 85 7B 84 7B 84 7B 84 7B + 39 00 11 B0 84 7B 84 7B 84 7C 83 7C 83 7C 83 7C 83 7C 83 7C + 39 00 11 C0 83 7F 04 FF 1E 00 08 10 18 20 28 30 38 FC 00 04 + 39 00 0c D0 20 00 01 08 40 00 02 10 80 00 FC + 39 00 03 41 5A 1A + 39 00 11 80 F0 D9 C8 BA AF A6 9E 98 92 8D 88 84 00 60 F6 CF + 39 00 11 90 FC 6F F6 EF CF AF 5F 55 00 F8 00 F8 00 F8 AD 8D + 39 00 11 A0 73 60 53 4A 43 7F 78 10 A0 3F 00 00 00 00 00 00 + 39 00 11 B0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 39 00 09 C0 00 00 00 00 00 00 00 00 + 39 00 03 41 5A 1C + 39 00 11 80 00 04 08 0C 00 10 14 18 1C 00 20 28 30 38 00 40 + 39 00 11 90 48 50 58 00 60 68 70 78 00 80 88 90 98 00 A0 A8 + 39 00 11 A0 B0 B8 00 C0 C8 D0 D8 00 E0 E8 F0 F8 00 FC FE FF + 39 00 11 B0 00 00 04 08 0C 00 10 14 18 1C 00 20 28 30 38 00 + 39 00 11 C0 40 48 50 58 00 60 68 70 78 00 80 88 90 98 00 A0 + 39 00 11 D0 A8 B0 B8 00 C0 C8 D0 D8 00 E0 E8 F0 F8 00 FC FE + 39 00 11 E0 FF 00 00 04 08 0C 00 10 14 18 1C 00 20 28 30 38 + 39 00 11 F0 00 40 48 50 58 00 60 68 70 78 00 80 88 90 98 00 + 39 00 03 41 5A 1D + 39 00 11 80 A0 A8 B0 B8 00 C0 C8 D0 D8 00 E0 E8 F0 F8 00 FC + 39 00 05 90 FE FF 00 00 + 39 00 03 41 5A 1F + 39 00 11 80 5A 0F 70 09 28 30 38 40 48 50 58 60 20 30 38 40 + 39 00 11 90 48 50 58 60 20 28 38 40 48 50 58 60 20 28 30 40 + 39 00 11 A0 48 50 58 60 20 28 30 38 48 50 58 60 20 28 30 38 + 39 00 11 B0 40 50 58 60 20 28 30 38 40 48 58 60 20 28 30 38 + 39 00 11 C0 40 48 50 60 20 28 30 38 40 48 50 58 FF 5A 1E 20 + 39 00 0d D0 00 02 20 00 02 20 00 02 20 00 02 FE + 39 00 03 41 5A 20 + 39 00 11 80 44 73 03 00 CA F3 FF 6B 10 08 02 08 03 41 18 30 + 39 00 11 90 18 44 E1 40 E1 20 30 18 C8 21 41 01 39 13 44 42 + 39 00 11 A0 91 50 28 14 0A 85 03 D2 B0 80 36 7F D0 1F 12 E0 + 39 00 11 B0 18 36 1B 11 04 20 02 D0 80 B3 21 38 20 18 88 03 + 39 00 11 C0 82 01 4D 70 40 30 8D 0D A4 A2 00 80 04 38 00 50 + 39 00 11 D0 80 13 E0 00 14 C0 70 40 00 E0 81 00 00 28 0E 06 + 39 00 11 E0 43 55 55 55 55 55 D5 CC CC CC CC CC 4C 08 82 C6 + 39 00 11 F0 E0 01 00 00 00 21 42 88 00 00 00 00 00 00 00 20 + 39 00 03 41 5A 21 + 39 00 11 80 04 41 06 49 90 04 49 00 00 49 00 00 49 00 00 49 + 39 00 11 90 90 04 00 85 11 0C 00 00 40 00 00 00 00 16 00 A5 + 39 00 11 A0 00 08 08 15 10 D1 B6 45 92 8A 20 A2 6D 0B 00 54 + 39 00 11 B0 40 44 DB 16 00 48 92 24 09 E0 0F 80 55 30 01 10 + 39 00 11 C0 01 42 82 11 20 02 10 10 01 08 88 00 04 44 00 02 + 39 00 11 D0 22 00 04 91 80 1F 00 40 40 04 00 00 00 18 10 16 + 39 00 03 E0 10 00 + 39 00 03 41 5A 22 + 39 00 11 80 29 D3 00 55 55 55 55 55 55 55 55 55 55 55 1F 70 + 39 00 04 90 F0 00 00 + 39 00 03 41 5A 23 + 39 00 11 80 09 01 02 05 00 05 04 00 00 00 00 00 00 00 00 00 + 39 00 0a 90 00 FF 1F 20 00 01 00 00 FE + 39 00 03 41 5A 24 + 39 00 11 80 00 03 00 FF FF 66 00 00 00 00 00 00 00 00 24 64 + 39 00 0f 90 5A A5 5A 00 00 00 00 22 22 3A 22 00 00 00 + 39 00 03 41 5A 24 + 15 00 02 90 A5 + 39 00 03 41 5A 2F + 15 00 02 4C 03 + 15 00 02 09 01 + 39 00 03 51 ff 0f + 15 00 02 53 24 + 15 00 02 55 00 + //15 00 02 02 5a + + 05 78 01 11 + 05 0A 01 29 + ]; + + panel-exit-sequence = [ + 13 14 01 28 + 13 78 01 10 + ]; + + disp_timings0: display-timings { + native-mode = <&dsi_timing0>; + dsi_timing0: timing0 { + clock-frequency = <170000000>; + hactive = <1200>; + vactive = <1920>; + + hfront-porch = <48>; + hsync-len = <20>; + hback-porch = <38>; + + vfront-porch = <224>; + vsync-len = <6>; + vback-porch = <32>; + + hsync-active = <0>; + vsync-active = <0>; + de-active = <0>; + pixelclk-active = <0>; + }; + }; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + panel_in_dsi: endpoint { + remote-endpoint = <&dsi_out_panel>; + }; + }; + }; + }; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@1 { + reg = <1>; + dsi_out_panel: endpoint { + remote-endpoint = <&panel_in_dsi>; + }; + }; + }; + +}; + +&gpu { + mali-supply = <&vdd_gpu_s0>; + status = "okay"; +}; + +&i2c0 { + pinctrl-0 = <&i2c0m1_xfer>; + clock-frequency = <400000>; + status = "okay"; + + ts@40 { + compatible = "GSL,GSL3673_800X1280"; + reg = <0x40>; + irq_gpio_number = <&gpio0 RK_PC5 GPIO_ACTIVE_HIGH>; + rst_gpio_number = <&gpio0 RK_PD0 GPIO_ACTIVE_HIGH>; + pinctrl-names = "default"; + pinctrl-0 = <&touch_gpio>; + rockchip,panel-notifier = <&dsi_panel>; + status = "disabled"; + }; + + focaltech@38 { + compatible = "focaltech,fts"; + reg = <0x38>; + //extcon = <&dsi>; + focaltech,irq-gpio = <&gpio0 RK_PC5 GPIO_ACTIVE_HIGH>; + focaltech,reset-gpio = <&gpio0 RK_PC6 GPIO_ACTIVE_HIGH>; + focaltech,max-touch-number = <10>; + focaltech,display-coords = <0 0 1200 1920>;//AB:1920 1200, P:1200 1920 + rockchip,panel-notifier = <&dsi_panel>; + status = "okay"; + }; +}; + +&i2c1 { + status = "okay"; + + rk809: pmic@20 { + compatible = "rockchip,rk809"; + reg = <0x20>; + interrupt-parent = <&gpio0>; + interrupts = <6 IRQ_TYPE_LEVEL_LOW>; + + pinctrl-names = "default", "pmic-sleep", + "pmic-power-off", "pmic-reset"; + pinctrl-0 = <&pmic_int>; + pinctrl-1 = <&soc_slppin_slp>, <&rk817_slppin_slp>; + pinctrl-2 = <&soc_slppin_gpio>, <&rk817_slppin_pwrdn>; + pinctrl-3 = <&soc_slppin_slp>, <&rk817_slppin_slp>; + rockchip,system-power-controller; + wakeup-source; + #clock-cells = <1>; + //clock-output-names = "rk808-clkout1", "rk808-clkout2"; + + /* PWRON_ON_TIME: 0:500mS; 1:100mS */ + pwron-on-time-500ms; + + /* 1: rst regs (default in codes), 0: rst the pmic */ + pmic-reset-func = <1>; + /* not save the PMIC_POWER_EN register in uboot */ + not-save-power-en = <1>; + rockchip,clk-32k-always-on; + vcc1-supply = <&vcc_sys>; + vcc2-supply = <&vcc_sys>; + vcc3-supply = <&vcc_sys>; + vcc4-supply = <&vcc_sys>; + vcc5-supply = <&vcc_sys>; + vcc6-supply = <&vcc_sys>; + vcc7-supply = <&vcc_sys>; + vcc8-supply = <&vcc_sys>; + vcc9-supply = <&vcc_sys>; + + pwrkey { + status = "okay"; + }; + + pinctrl_rk8xx: pinctrl_rk8xx { + gpio-controller; + #gpio-cells = <2>; + + rk817_slppin_null: rk817_slppin_null { + pins = "gpio_slp"; + function = "pin_fun0"; + }; + + rk817_slppin_slp: rk817_slppin_slp { + pins = "gpio_slp"; + function = "pin_fun1"; + }; + + rk817_slppin_pwrdn: rk817_slppin_pwrdn { + pins = "gpio_slp"; + function = "pin_fun2"; + }; + + rk817_slppin_rst: rk817_slppin_rst { + pins = "gpio_slp"; + function = "pin_fun3"; + }; + }; + + regulators { + vdd_cpu_lit_s0: DCDC_REG1 { + regulator-always-on; + regulator-boot-on; + regulator-init-microvolt = <850000>; + regulator-min-microvolt = <550000>; + regulator-max-microvolt = <950000>; + regulator-ramp-delay = <12500>; + regulator-initial-mode = <0x2>; + regulator-name = "vdd_cpu_lit_s0"; + regulator-state-mem { + regulator-off-in-suspend; + regulator-suspend-microvolt = <850000>; + }; + }; + + vdd_gpu_s0: DCDC_REG2 { + regulator-boot-on; + regulator-init-microvolt = <750000>; + regulator-min-microvolt = <550000>; + regulator-max-microvolt = <900000>; + regulator-ramp-delay = <12500>; + regulator-initial-mode = <0x2>; + regulator-name = "vdd_gpu_s0"; + regulator-enable-ramp-delay = <400>; + regulator-state-mem { + regulator-off-in-suspend; + regulator-suspend-microvolt = <850000>; + }; + }; + + vdd_ddr_s0: DCDC_REG3 { + regulator-always-on; + regulator-boot-on; + regulator-initial-mode = <0x2>; + regulator-min-microvolt = <550000>; + regulator-max-microvolt = <1200000>; + regulator-name = "vdd_ddr_s0"; + regulator-state-mem { + regulator-off-in-suspend; + regulator-suspend-microvolt = <1200000>; + }; + }; + + vdd_logic_s0: vdd_log_mem_s0: DCDC_REG4 { + regulator-always-on; + regulator-boot-on; + regulator-init-microvolt = <750000>; + regulator-min-microvolt = <750000>; + regulator-max-microvolt = <750000>; + regulator-initial-mode = <0x2>; + regulator-name = "vdd_logic_s0"; + regulator-state-mem { + regulator-off-in-suspend; + regulator-suspend-microvolt = <750000>; + }; + }; + + vdda_0v85_s0: LDO_REG1 { + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <850000>; + regulator-max-microvolt = <850000>; + regulator-name = "vdda_0v85_s0"; + regulator-state-mem { + regulator-off-in-suspend; + regulator-suspend-microvolt = <850000>; + }; + }; + + vcca_1v8_s0: LDO_REG2 { + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-name = "vcca_1v8_s0"; + regulator-state-mem { + regulator-off-in-suspend; + regulator-suspend-microvolt = <1800000>; + }; + }; + + vdd_0v75_s3: LDO_REG3 { + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <750000>; + regulator-max-microvolt = <750000>; + regulator-name = "vdd_0v75_s3"; + regulator-state-mem { + regulator-on-in-suspend; + regulator-suspend-microvolt = <750000>; + }; + }; + + vcca3v3_codec: LDO_REG4 { + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <3000000>; + regulator-max-microvolt = <3000000>; + regulator-name = "vcca3v3_codec"; + regulator-state-mem { + regulator-off-in-suspend; + regulator-suspend-microvolt = <3000000>; + }; + }; + + vccio_sd_s0: LDO_REG5 { + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <3300000>; + regulator-name = "vccio_sd_s0"; + regulator-state-mem { + regulator-off-in-suspend; + regulator-suspend-microvolt = <3300000>; + }; + }; + + vcc3v3_sd_s0: LDO_REG6 { + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-name = "vcc3v3_sd_s0"; + regulator-state-mem { + regulator-off-in-suspend; + regulator-suspend-microvolt = <3300000>; + }; + }; + + vcca1v8_otp_s0: LDO_REG7 { + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-name = "vcca1v8_otp_s0"; + regulator-state-mem { + regulator-off-in-suspend; + regulator-suspend-microvolt = <1800000>; + }; + }; + + vcc_1v2_cam: LDO_REG8 { + regulator-boot-on; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1200000>; + regulator-name = "vcc_1v2_cam"; + regulator-state-mem { + regulator-off-in-suspend; + regulator-suspend-microvolt = <1200000>; + }; + }; + + vdda_1v2_s0: LDO_REG9 { + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1200000>; + regulator-name = "vdda_1v2_s0"; + regulator-state-mem { + regulator-off-in-suspend; + regulator-suspend-microvolt = <1200000>; + }; + }; + + vcc_1v8_s3: DCDC_REG5 { + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-name = "vcc_1v8_s3"; + regulator-state-mem { + regulator-on-in-suspend; + regulator-suspend-microvolt = <1800000>; + }; + }; + + vcc_3v3_motor: SWITCH_REG1 { + regulator-name = "vcc_3v3_motor"; + regulator-state-mem { + regulator-off-in-suspend; + }; + }; + + vcc_3v3_s0: SWITCH_REG2 { + regulator-always-on; + regulator-boot-on; + regulator-name = "vcc_3v3_s0"; + regulator-state-mem { + regulator-off-in-suspend; + }; + }; + }; + + battery { + compatible = "rk817,battery"; + ocv_table = <3400 3671 3686 3712 3738 3756 3773 + 3787 3802 3819 3840 3868 3916 3959 + 3998 4041 4087 4138 4191 4247 4313>; + design_capacity = <5780>; + design_qmax = <6358>; + bat_res = <100>; + sleep_enter_current = <150>; + sleep_exit_current = <180>; + sleep_filter_current = <100>; + power_off_thresd = <3400>; + zero_algorithm_vol = <3950>; + max_soc_offset = <60>; + monitor_sec = <5>; + sample_res = <10>; + virtual_power = <0>; + bat_res_up = <60>; + bat_res_down = <20>; + }; + + rk809_codec: codec { + #sound-dai-cells = <1>; + compatible = "rockchip,rk809-codec", "rockchip,rk817-codec"; + clocks = <&mclkout_sai1>; + clock-names = "mclk"; + assigned-clocks = <&mclkout_sai1>; + assigned-clock-rates = <12288000>; + pinctrl-names = "default"; + pinctrl-0 = <&sai1m0_mclk>; + hp-volume = <20>; + spk-volume = <25>; + use-ext-amplifier; + status = "okay"; + }; + }; +}; + +&i2c2 { + status = "okay"; + + icm42607_acc: icm_acc@68 { + status = "disabled"; + compatible = "icm42607_acc"; + reg = <0x68>; + irq-gpio = <&gpio0 RK_PC7 IRQ_TYPE_EDGE_RISING>; + irq_enable = <0>; + poll_delay_ms = <30>; + type = ; + layout = <1>; + }; + + icm42607_gyro: icm_gyro@69 { //real addr 0x68 + status = "disabled"; + compatible = "icm42607_gyro"; + reg = <0x69>; + poll_delay_ms = <30>; + type = ; + layout = <0>; + }; + + sensor@19 { + compatible = "gs_sc7a20"; + reg = <0x19>; + type = ; + irq_enable = <0>; + pinctrl-names = "default"; + pinctrl-0 = <&sensor_gpio>; + irq-gpio = <&gpio0 RK_PC7 IRQ_TYPE_LEVEL_LOW>; + poll_delay_ms = <10>; + layout = <7>; //<7>;//<5>; + reprobe_en = <0>; + is_sc7a20e = <0>; + swap_xy = <0>; + revert_x = <1>; + revert_y = <1>; + revert_z = <0>; + status = "disabled"; + }; + + sensorda@27{ + compatible = "gs_da223"; + reg = <0x27>; + type = ; + //irq-gpio = <&gpio0 RK_PC4 IRQ_TYPE_LEVEL_LOW>; + irq_enable = <0>; + poll_delay_ms = <10>; + layout = <6>; + //layout = <5>; + swap_xy = <0>; + revert_x = <0>; + revert_y = <1>; + revert_z = <0>; + status = "okay"; + }; +}; + +&i2c3 { + status = "okay"; + +}; + +&i2c6 { + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <&i2c6m3_xfer>; + + sc89601: sc89601@6b { + compatible = "sc,sc89601"; + reg = <0x6b>; + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <&charger_ok>; + interrupt-parent = <&gpio0>; + interrupts = ; /* IRQ_TYPE_LEVEL_LOW>;*/ + charger-phandle = <&usbc0>; + sc,battery-regulation-voltage = <4350000>; /* 4200000,4.2V , 4350000, 4232000*/ + sc,charge-current = <3000000>; /*2040000,* 2.040A, 3000000 */ + sc,termination-current = <180000>; /* 180mA, 180000 */ + sc,precharge-current = <180000>; /* 180mA */ + sc,minimum-sys-voltage = <3400000>; /*3500000, 3.5V */ + sc,boost-voltage = <5000000>; /*5100000, 5.1V */ + sc,boost-max-current = <1500000>; /*1200000, 1200mA */ + + sc,use-stat-pin = <0>; /* enable stat pin */ + sc,boost-freq = <0>; /* 1.5MHz */ + + //monitored-battery = <&bat>; + regulators { + otg-en-pin = <&gpio0 RK_PD3 GPIO_ACTIVE_HIGH>; + vbus5v0_typec: vbus5v0-typec { + regulator-compatible = "otg-vbus"; + regulator-name = "vbus5v0_typec"; + }; + }; + }; + + /* aw35615. aw35615 is compatible with fusb302. */ + usbc0: fusb302@22 { + compatible = "fcs,fusb302"; + reg = <0x22>; + interrupt-parent = <&gpio0>; + interrupts = ; + pinctrl-names = "default"; + pinctrl-0 = <&usbc0_int>; + vbus-supply = <&vbus5v0_typec>; + wakeup-source; + status = "okay"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + usbc0_role_sw: endpoint@0 { + remote-endpoint = <&usb_drd0_role_switch>; + }; + }; + }; + + usb_con: connector { + compatible = "usb-c-connector"; + label = "USB-C"; + data-role = "dual"; + power-role = "dual"; + try-power-role = "sink"; + op-sink-microwatt = <1000000>; + sink-pdos = + ; + source-pdos = + ; + + altmodes { + #address-cells = <1>; + #size-cells = <0>; + + altmode@0 { + reg = <0>; + svid = <0xff01>; + vdo = <0xffffffff>; + }; + }; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + usbc0_orien_sw: endpoint { + remote-endpoint = <&usbdp_phy_orientation_switch>; + }; + }; + + port@1 { + reg = <1>; + dp_altmode_mux: endpoint { + remote-endpoint = <&usbdp_phy_dp_altmode_mux>; + }; + }; + }; + }; + }; +}; + +&i2c9 { + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <&i2c9m3_xfer>; + + fs15xx_pa_34: pa@34 { + compatible = "foursemi,fs15xx"; + reg = <0x34>; + status = "okay"; + }; + + fs15xx_pa_35: pa@35 { + compatible = "foursemi,fs15xx"; + reg = <0x35>; + status = "okay"; + }; + + fs15xx_pa_36: pa@36 { + compatible = "foursemi,fs15xx"; + reg = <0x36>; + status = "okay"; + }; + + fs15xx_pa_37: pa@37 { + compatible = "foursemi,fs15xx"; + reg = <0x37>; + status = "okay"; + }; +}; + +&iep { + status = "okay"; +}; + +&iep_mmu { + status = "okay"; +}; + +&jpegd { + status = "okay"; +}; + +&jpege { + status = "okay"; +}; + +&jpeg_mmu { + status = "okay"; +}; + +&mipidcphy0 { + status = "okay"; +}; + +&mpp_srv { + status = "okay"; +}; + +&pcie0 { + reset-gpios = <&gpio1 RK_PC1 GPIO_ACTIVE_HIGH>; + rockchip,skip-scan-in-resume; + pinctrl-names = "default"; + pinctrl-0 = <&wifi_poweren_gpio>; + status = "disabled"; +}; + +&pinctrl { + + wifi{ + wifi_power_en: wifi_power_en { + rockchip,pins = <0 RK_PB5 RK_FUNC_GPIO &pcfg_pull_none>; + }; + + wifi_host_wake_irq: wifi_host_wake_irq { + rockchip,pins = <0 RK_PB0 RK_FUNC_GPIO &pcfg_pull_none>; + }; + + wifi_chip_wake_irq: wifi_chip_wake_irq { + rockchip,pins = <1 RK_PC7 RK_FUNC_GPIO &pcfg_pull_none>; + }; + }; + + charger { + charger_ok: charger_ok { + rockchip,pins = + <0 RK_PD2 RK_FUNC_GPIO &pcfg_pull_up>, + <0 RK_PD3 RK_FUNC_GPIO &pcfg_pull_up>; + }; + }; + + headphone { + hp_det: hp-det { + rockchip,pins = <4 RK_PA4 RK_FUNC_GPIO &pcfg_pull_up>; + }; + }; + + lcd { + lcd_rst_gpio: lcd-rst-gpio { + rockchip,pins = <2 RK_PB4 RK_FUNC_GPIO &pcfg_pull_none>; + }; + + + lcd_enable_gpio: lcd-enable-gpio { + rockchip,pins = <1 RK_PC6 RK_FUNC_GPIO &pcfg_pull_none>; + }; + }; + + pmic { + /omit-if-no-ref/ + pmic_int: pmic-int { + rockchip,pins = + <0 RK_PA6 0 &pcfg_pull_up>; + }; + + /omit-if-no-ref/ + soc_slppin_gpio: soc-slppin-gpio { + rockchip,pins = + <0 RK_PA3 0 &pcfg_output_low>; + }; + + /omit-if-no-ref/ + soc_slppin_slp: soc-slppin-slp { + rockchip,pins = + <0 RK_PA3 9 &pcfg_pull_none>; + }; + }; + + touch { + touch_gpio: touch-gpio { + rockchip,pins = + <0 RK_PC5 RK_FUNC_GPIO &pcfg_pull_down>, + <0 RK_PC6 RK_FUNC_GPIO &pcfg_pull_none>; + }; + }; + + sensor { + sensor_gpio: sensor-gpio { + rockchip,pins = <0 RK_PC7 RK_FUNC_GPIO &pcfg_pull_none>; + }; + }; + + usb { + usbc0_int: usbc0-int { + rockchip,pins = <0 RK_PD1 RK_FUNC_GPIO &pcfg_pull_up>; + }; + }; + + wireless-bluetooth { + uart4_gpios: uart4-gpios { + rockchip,pins = <1 RK_PC2 RK_FUNC_GPIO &pcfg_pull_none>; + }; + }; + + wireless-wlan { + wifi_poweren_gpio: wifi-poweren-gpio { + rockchip,pins = <1 RK_PC6 RK_FUNC_GPIO &pcfg_pull_up>; + }; + }; +}; + +&pwm0_2ch_1 { + status = "okay"; +}; + +&pwm1_6ch_0 { + status = "okay"; +}; + +&pwm1_6ch_2 { + status = "okay"; +}; + +&rga2_core0 { + status = "okay"; +}; + +&rga2_core0_mmu { + status = "okay"; +}; + +&rga2_core1 { + status = "okay"; +}; + +&rga2_core1_mmu { + status = "okay"; +}; + +&rknpu { + rknpu-supply = <&vdd_npu_s0>; + status = "okay"; +}; + +&rknpu_mmu { + status = "okay"; +}; + +&rkvenc_ccu { + status = "okay"; +}; + +&rkvenc0 { + status = "okay"; +}; + +&rkvenc0_mmu { + status = "okay"; +}; + +&rkvenc1 { + status = "okay"; +}; + +&rkvenc1_mmu { + status = "okay"; + +}; + +&rkvdec { + status = "okay"; +}; + +&rkvdec_mmu { + status = "okay"; +}; + +&rockchip_suspend { + status = "okay"; + rockchip,sleep-debug-en = <1>; + + rockchip,sleep-mode-config = < + (0 + | RKPM_SLP_ARMOFF_LOGOFF + | RKPM_SLP_PMU_PMUALIVE_32K + | RKPM_SLP_PMU_DIS_OSC + | RKPM_SLP_32K_EXT + ) + >; + rockchip,sleep-io-ret-config = < + (0 + | RKPM_VCCIO3_RET_EN + ) + >; +}; + +&route_dsi { + status = "okay"; + connect = <&vp0_out_dsi>; +}; + +&sai1 { + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <&sai1m0_lrck + &sai1m0_sclk + &sai1m0_sdi0 + &sai1m0_sdo0>; +}; + +&saradc { + status = "okay"; + vref-supply = <&vcca_1v8_s0>; +}; + +&sdhci { + bus-width = <8>; + no-sdio; + no-sd; + non-removable; + max-frequency = <200000000>; + mmc-hs400-1_8v; + mmc-hs400-enhanced-strobe; + full-pwr-cycle-in-suspend; + status = "disabled"; +}; + +&sdio { + max-frequency = <150000000>; + no-sd; + no-mmc; + bus-width = <4>; + disable-wp; + cap-sd-highspeed; + cap-sdio-irq; + keep-power-in-suspend; + mmc-pwrseq = <&sdio_pwrseq>; + non-removable; + pinctrl-names = "default"; + pinctrl-0 = <&sdmmc1m0_bus4 &sdmmc1m0_clk &sdmmc1m0_cmd>; + sd-uhs-sdr104; + status = "okay"; +}; + +&sdmmc { + max-frequency = <200000000>; + no-sdio; + no-mmc; + bus-width = <4>; + cap-mmc-highspeed; + cap-sd-highspeed; + disable-wp; + sd-uhs-sdr104; + vmmc-supply = <&vcc3v3_sd_s0>; + vqmmc-supply = <&vccio_sd_s0>; + status = "okay"; +}; + +&spdif_tx3 { + status = "okay"; +}; + +&tsadc { + status = "okay"; +}; + +&uart4 { + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <&uart4m1_xfer &uart4m1_ctsn>; +}; + +&u2phy0 { + status = "okay"; +}; + +&u2phy0_otg { + status = "okay"; + rockchip,typec-vbus-det; +}; + +&u2phy1 { + status = "disabled"; +}; + +&ufs { + vcc-supply = <&vcc_ufs_s0>; + vccq-supply = <&vcc1v2_ufs_vccq_s0>; + vccq2-supply = <&vcc1v8_ufs_vccq2_s0>; + reset-gpios = <&gpio4 RK_PD0 GPIO_ACTIVE_HIGH>; + status = "okay"; +}; + +&usbdp_phy { + status = "okay"; + orientation-switch; + svid = <0xff01>; + sbu1-dc-gpios = <&gpio4 RK_PC4 GPIO_ACTIVE_HIGH>; + sbu2-dc-gpios = <&gpio4 RK_PC5 GPIO_ACTIVE_HIGH>; + + port { + #address-cells = <1>; + #size-cells = <0>; + + usbdp_phy_orientation_switch: endpoint@0 { + reg = <0>; + remote-endpoint = <&usbc0_orien_sw>; + }; + + usbdp_phy_dp_altmode_mux: endpoint@1 { + reg = <1>; + remote-endpoint = <&dp_altmode_mux>; + }; + }; +}; + +&usbdp_phy_dp { + status = "okay"; + max-link-rate = <5400>; +}; + +&usbdp_phy_u3 { + status = "okay"; +}; + +&usb_drd0_dwc3 { + status = "okay"; + dr_mode = "otg"; + usb-role-switch; + port { + usb_drd0_role_switch: endpoint { + remote-endpoint = <&usbc0_role_sw>; + }; + }; +}; + +&vdpp { + status = "okay"; +}; + +&vop { + status = "okay"; + vop-supply = <&vdd_logic_s0>; +}; + +&vop_mmu { + status = "okay"; +}; + From 2b9745aa758af55517f206326127c1ee1321898c Mon Sep 17 00:00:00 2001 From: Binyuan Lan Date: Sat, 11 Oct 2025 15:46:46 +0800 Subject: [PATCH 35/40] power: supply: sc89601_charger: fix the abnormal display of the charging icon chrg_status register 0x08 is volatile. Signed-off-by: Binyuan Lan Change-Id: Ia569391b2eee3f8bfac0c40cb08991b341702115 --- drivers/power/supply/sc89601_charger.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/power/supply/sc89601_charger.c b/drivers/power/supply/sc89601_charger.c index c5d680c29cfb..a404aa57711f 100644 --- a/drivers/power/supply/sc89601_charger.c +++ b/drivers/power/supply/sc89601_charger.c @@ -106,7 +106,7 @@ static const struct regmap_access_table sc89601_writeable_regs = { static const struct regmap_range sc89601_volatile_reg_ranges[] = { regmap_reg_range(0x00, 0x00), regmap_reg_range(0x02, 0x02), - regmap_reg_range(0x09, 0x09), + regmap_reg_range(0x08, 0x09), regmap_reg_range(0x0b, 0x0b), regmap_reg_range(0x0c, 0x0c), regmap_reg_range(0x0d, 0x14), From 594bcd5a6c6650f7c60c452905428829e7e2ccee Mon Sep 17 00:00:00 2001 From: Shengfei Xu Date: Sat, 11 Oct 2025 14:37:41 +0800 Subject: [PATCH 36/40] arm64: dts: rockchip: rv1126b-evb: Add the regulator-settling-time-up-us configuration Add the regulator-settling-time-up-us configuration in the PWM regulator to ensure sufficient time for the voltage to reach a stable state during the rising phase. Signed-off-by: Shengfei Xu Change-Id: I2ec7255931f22c1f8c46e41fac34b2c215e9abf3 --- arch/arm64/boot/dts/rockchip/rv1126b-evb1-v10.dtsi | 1 + arch/arm64/boot/dts/rockchip/rv1126b-evb2-v10.dtsi | 3 +++ arch/arm64/boot/dts/rockchip/rv1126b-evb3-v10.dts | 3 +++ arch/arm64/boot/dts/rockchip/rv1126b-evb4-v10.dts | 1 + 4 files changed, 8 insertions(+) diff --git a/arch/arm64/boot/dts/rockchip/rv1126b-evb1-v10.dtsi b/arch/arm64/boot/dts/rockchip/rv1126b-evb1-v10.dtsi index 971f67e0ccab..c177b787c2e9 100644 --- a/arch/arm64/boot/dts/rockchip/rv1126b-evb1-v10.dtsi +++ b/arch/arm64/boot/dts/rockchip/rv1126b-evb1-v10.dtsi @@ -100,6 +100,7 @@ regulator-init-microvolt = <950000>; regulator-min-microvolt = <750000>; regulator-max-microvolt = <1100000>; + regulator-settling-time-up-us = <250>; regulator-always-on; regulator-boot-on; enable-gpios = <&gpio0 RK_PA3 GPIO_ACTIVE_HIGH>; diff --git a/arch/arm64/boot/dts/rockchip/rv1126b-evb2-v10.dtsi b/arch/arm64/boot/dts/rockchip/rv1126b-evb2-v10.dtsi index db9d53a31e65..f8603e865191 100644 --- a/arch/arm64/boot/dts/rockchip/rv1126b-evb2-v10.dtsi +++ b/arch/arm64/boot/dts/rockchip/rv1126b-evb2-v10.dtsi @@ -179,6 +179,7 @@ regulator-init-microvolt = <905000>; regulator-min-microvolt = <810000>; regulator-max-microvolt = <1006000>; + regulator-settling-time-up-us = <250>; regulator-always-on; regulator-boot-on; pwm-supply = <&vccsys_stb>; @@ -192,6 +193,7 @@ regulator-init-microvolt = <950000>; regulator-min-microvolt = <800000>; regulator-max-microvolt = <1150000>; + regulator-settling-time-up-us = <250>; regulator-always-on; regulator-boot-on; pwm-supply = <&vccsys_stb>; @@ -205,6 +207,7 @@ regulator-init-microvolt = <950000>; regulator-min-microvolt = <800000>; regulator-max-microvolt = <1100000>; + regulator-settling-time-up-us = <250>; regulator-always-on; regulator-boot-on; pwm-supply = <&vccsys_stb>; diff --git a/arch/arm64/boot/dts/rockchip/rv1126b-evb3-v10.dts b/arch/arm64/boot/dts/rockchip/rv1126b-evb3-v10.dts index 503e4ba33b52..53de70d052b1 100644 --- a/arch/arm64/boot/dts/rockchip/rv1126b-evb3-v10.dts +++ b/arch/arm64/boot/dts/rockchip/rv1126b-evb3-v10.dts @@ -166,6 +166,7 @@ regulator-init-microvolt = <905000>; regulator-min-microvolt = <810000>; regulator-max-microvolt = <1006000>; + regulator-settling-time-up-us = <250>; regulator-always-on; regulator-boot-on; pwm-supply = <&vccsys_stb>; @@ -179,6 +180,7 @@ regulator-init-microvolt = <950000>; regulator-min-microvolt = <750000>; regulator-max-microvolt = <1100000>; + regulator-settling-time-up-us = <250>; regulator-always-on; regulator-boot-on; pwm-supply = <&vccsys_stb>; @@ -192,6 +194,7 @@ regulator-init-microvolt = <950000>; regulator-min-microvolt = <750000>; regulator-max-microvolt = <1100000>; + regulator-settling-time-up-us = <250>; regulator-always-on; regulator-boot-on; pwm-supply = <&vccsys_stb>; diff --git a/arch/arm64/boot/dts/rockchip/rv1126b-evb4-v10.dts b/arch/arm64/boot/dts/rockchip/rv1126b-evb4-v10.dts index 2dcec24ddb52..be9fb9d30118 100644 --- a/arch/arm64/boot/dts/rockchip/rv1126b-evb4-v10.dts +++ b/arch/arm64/boot/dts/rockchip/rv1126b-evb4-v10.dts @@ -103,6 +103,7 @@ regulator-init-microvolt = <950000>; regulator-min-microvolt = <750000>; regulator-max-microvolt = <1100000>; + regulator-settling-time-up-us = <250>; regulator-always-on; regulator-boot-on; enable-gpios = <&gpio0 RK_PA3 GPIO_ACTIVE_HIGH>; From 8fee3005f36ace17813f6df3df2121b099040ecf Mon Sep 17 00:00:00 2001 From: Frank Wang Date: Thu, 9 Oct 2025 17:32:46 +0800 Subject: [PATCH 37/40] mailbox: rockchip: add version and lock register support As of Mailbox Version 2.2.0, a version register and a channel lock function have been added, and this change is intended to provide support for these features. Signed-off-by: Frank Wang Change-Id: Ie4778dc5860fbb7f2f55c36a4c4f1b6fc97b1c99 --- drivers/mailbox/rockchip-mailbox.c | 55 +++++++++++++++++++++++++++--- 1 file changed, 50 insertions(+), 5 deletions(-) diff --git a/drivers/mailbox/rockchip-mailbox.c b/drivers/mailbox/rockchip-mailbox.c index 4dd6963d82a5..e2bcdb056d19 100644 --- a/drivers/mailbox/rockchip-mailbox.c +++ b/drivers/mailbox/rockchip-mailbox.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #define MAILBOX_A2B_INTEN 0x00 @@ -28,11 +29,16 @@ #define MAILBOX_V2_A2B_STATUS MAILBOX_A2B_STATUS #define MAILBOX_V2_A2B_CMD 0x08 #define MAILBOX_V2_A2B_DAT 0x0c +#define MAILBOX_V2_A2B_LOCK 0x20 #define MAILBOX_V2_B2A_INTEN 0x10 #define MAILBOX_V2_B2A_STATUS 0x14 #define MAILBOX_V2_B2A_CMD 0x18 #define MAILBOX_V2_B2A_DAT 0x1c +#define MAILBOX_V2_B2A_LOCK 0x30 + +#define MAILBOX_V2_VERSION 0x40 +#define MAILBOX_V2_VERSION_MASK GENMASK(31, 16) #define MAILBOX_V2_TRIGGER_SHIFT 8 #define MAILBOX_V2_TRIGGER_MASK BIT(8) @@ -45,6 +51,11 @@ #define MAILBOX_V2_STATUS_RX_DONE BIT(1) #define MAILBOX_V2_STATUS_MASK GENMASK(1, 0) +#define MAILBOX_VERSION_1_0_0 0x100U +#define MAILBOX_VERSION_2_0_0 0x200U +#define MAILBOX_VERSION_2_1_0 0x210U +#define MAILBOX_VERSION_2_2_0 0x220U + #define MAILBOX_POLLING_MS 5 /* default polling interval 5ms */ #define BIT_WRITEABLE_SHIFT 16 @@ -53,14 +64,17 @@ struct rockchip_mbox_reg { u32 tx_sts; u32 tx_cmd; u32 tx_dat; + u32 tx_lock; u32 rx_int; u32 rx_sts; u32 rx_cmd; u32 rx_dat; + u32 rx_lock; }; struct rockchip_mbox_data { int num_chans; + u32 version; struct rockchip_mbox_reg reg_a2b; struct rockchip_mbox_reg reg_b2a; const struct mbox_chan_ops *ops; @@ -78,6 +92,7 @@ struct rockchip_mbox { void __iomem *mbox_base; spinlock_t cfg_lock; /* Serialise access to the register */ unsigned char trigger_method; /* 0 = write cmd, 1 = write cmd first, then write data */ + u32 version; struct rockchip_mbox_msg *msg; const struct rockchip_mbox_reg *reg; @@ -181,17 +196,27 @@ static irqreturn_t rockchip_mbox_irq(int irq, void *dev_id) return IRQ_HANDLED; } +static bool rockchip_mbox_v2_is_busy(struct rockchip_mbox *mb) +{ + u32 status; + + if (mb->version < MAILBOX_VERSION_2_2_0) + status = readl_relaxed(mb->mbox_base + mb->reg->tx_sts) & MAILBOX_V2_STATUS_TX_DONE; + else + status = readl_relaxed(mb->mbox_base + mb->reg->tx_lock); + + return !!status; +} + static int rockchip_mbox_v2_send_data(struct mbox_chan *chan, void *data) { struct rockchip_mbox *mb = dev_get_drvdata(chan->mbox->dev); struct rockchip_mbox_msg *msg = data; - u32 status; if (!msg) return -EINVAL; - status = readl_relaxed(mb->mbox_base + mb->reg->tx_sts); - if (status & MAILBOX_V2_STATUS_TX_DONE) { + if (rockchip_mbox_v2_is_busy(mb)) { dev_err(mb->mbox.dev, "The mailbox is busy\n"); return -EBUSY; } @@ -325,20 +350,26 @@ EXPORT_SYMBOL_GPL(rockchip_mbox_read_msg); static const struct rockchip_mbox_data rk3368_drv_data = { .num_chans = 4, + .version = MAILBOX_VERSION_1_0_0, .ops = &rockchip_mbox_chan_ops, .irq_func = rockchip_mbox_irq, }; static const struct rockchip_mbox_data rk3576_drv_data = { .num_chans = 1, + .version = MAILBOX_VERSION_2_0_0, .reg_a2b = { MAILBOX_V2_A2B_INTEN, MAILBOX_V2_A2B_STATUS, MAILBOX_V2_A2B_CMD, MAILBOX_V2_A2B_DAT, + MAILBOX_V2_A2B_LOCK, MAILBOX_V2_B2A_INTEN, MAILBOX_V2_B2A_STATUS, - MAILBOX_V2_B2A_CMD, MAILBOX_V2_B2A_DAT }, + MAILBOX_V2_B2A_CMD, MAILBOX_V2_B2A_DAT, + MAILBOX_V2_B2A_LOCK }, .reg_b2a = { MAILBOX_V2_B2A_INTEN, MAILBOX_V2_B2A_STATUS, MAILBOX_V2_B2A_CMD, MAILBOX_V2_B2A_DAT, + MAILBOX_V2_B2A_LOCK, MAILBOX_V2_A2B_INTEN, MAILBOX_V2_A2B_STATUS, - MAILBOX_V2_A2B_CMD, MAILBOX_V2_A2B_DAT }, + MAILBOX_V2_A2B_CMD, MAILBOX_V2_A2B_DAT, + MAILBOX_V2_A2B_LOCK }, .ops = &rockchip_mbox_v2_chan_ops, .irq_func = rockchip_mbox_v2_irq, }; @@ -447,6 +478,13 @@ static int rockchip_mbox_probe(struct platform_device *pdev) if (IS_ERR(mb->mbox_base)) return PTR_ERR(mb->mbox_base); + if (drv_data->version != MAILBOX_VERSION_1_0_0) + mb->version = FIELD_GET(MAILBOX_V2_VERSION_MASK, + readl_relaxed(mb->mbox_base + MAILBOX_V2_VERSION)); + + if (!mb->version) + mb->version = drv_data->version; + mb->pclk = devm_clk_get(&pdev->dev, "pclk_mailbox"); if (IS_ERR(mb->pclk)) { ret = PTR_ERR(mb->pclk); @@ -503,6 +541,13 @@ static int rockchip_mbox_probe(struct platform_device *pdev) enable_irq_wake(mb->chans[i].irq); } + dev_info(&pdev->dev, "version: 0x%04x, tx_dir: %s, tx_done: %s, poll_period: %u, fast_mode: %s\n", + mb->version, + mb->reg == &drv_data->reg_b2a ? "B2A" : "A2B", + mb->mbox.txdone_irq ? "irq" : mb->mbox.txdone_poll ? "poll" : "ack", + mb->mbox.txpoll_period, + str_yes_no(!mb->trigger_method)); + return 0; disable_clk: From c5d3bacad72040134496ff9c6b5476fa6b89649f Mon Sep 17 00:00:00 2001 From: Frank Wang Date: Thu, 9 Oct 2025 17:35:29 +0800 Subject: [PATCH 38/40] mailbox: rockchip: add get properties helper This helper will be responsible for reading and parsing our properties. No functional changes in this patch, cleanup only. Signed-off-by: Frank Wang Change-Id: I8476a5f4d3e78f90d9749fd949ff5287eb400558 --- drivers/mailbox/rockchip-mailbox.c | 119 ++++++++++++++++------------- 1 file changed, 64 insertions(+), 55 deletions(-) diff --git a/drivers/mailbox/rockchip-mailbox.c b/drivers/mailbox/rockchip-mailbox.c index e2bcdb056d19..3455e35d421d 100644 --- a/drivers/mailbox/rockchip-mailbox.c +++ b/drivers/mailbox/rockchip-mailbox.c @@ -381,6 +381,69 @@ static const struct of_device_id rockchip_mbox_of_match[] = { }; MODULE_DEVICE_TABLE(of, rockchip_mbox_of_match); +static void rockchip_mbox_get_properties(struct rockchip_mbox *mb, + const struct rockchip_mbox_data *drv_data) +{ + struct device *dev = mb->mbox.dev; + u32 txpoll_period; + int ret; + + if (device_property_present(dev, "rockchip,tx-direction-b2a")) + mb->reg = &drv_data->reg_b2a; + else + mb->reg = &drv_data->reg_a2b; + + /* + * rockchip,txdone-ack: the mailbox client uses its own ACK to check + * TX_DONE, and call mbox_client_txdone() API to schedule tx_tick. + * rockchip,txdone-irq: the feature only support from RK3506, the ISR + * function call mbox_chan_txdone() API to schedule tx_tick. + * txdone_poll is default for all the platform, it cooperates with + * "rockchip,txpoll-period-ms" or "rockchip,txpoll-period-us" + * periodically call last_tx_done() to check TX_DONE by the hrtimer + * in mailbox framework. + */ + if (device_property_present(dev, "rockchip,txdone-ack")) { + mb->mbox.txdone_irq = false; + mb->mbox.txdone_poll = false; + } else if (device_property_present(dev, "rockchip,txdone-irq")) { + mb->mbox.txdone_irq = true; + } else { + mb->mbox.txdone_poll = true; + if (IS_REACHABLE(CONFIG_MAILBOX_POLL_PERIOD_US)) { + ret = device_property_read_u32(dev, + "rockchip,txpoll-period-us", + &txpoll_period); + if (!ret) { + mb->mbox.txpoll_period = txpoll_period; + } else { + ret = device_property_read_u32(dev, + "rockchip,txpoll-period-ms", + &txpoll_period); + mb->mbox.txpoll_period = !ret ? txpoll_period : MAILBOX_POLLING_MS; + mb->mbox.txpoll_period *= 1000U; /* Convert to us */ + } + } else { + ret = device_property_read_u32(dev, + "rockchip,txpoll-period-ms", + &txpoll_period); + mb->mbox.txpoll_period = !ret ? txpoll_period : MAILBOX_POLLING_MS; + } + } + + if (device_property_present(dev, "rockchip,enable-cmd-trigger")) + mb->trigger_method = 0; + else + mb->trigger_method = 1; + + if (drv_data->version != MAILBOX_VERSION_1_0_0) + mb->version = FIELD_GET(MAILBOX_V2_VERSION_MASK, + readl_relaxed(mb->mbox_base + MAILBOX_V2_VERSION)); + + if (!mb->version) + mb->version = drv_data->version; +} + static int rockchip_mbox_probe(struct platform_device *pdev) { struct rockchip_mbox *mb; @@ -388,7 +451,6 @@ static int rockchip_mbox_probe(struct platform_device *pdev) const struct rockchip_mbox_data *drv_data; struct resource *res; int ret, irq, i; - u32 txpoll_period; if (!pdev->dev.of_node) return -ENODEV; @@ -422,54 +484,6 @@ static int rockchip_mbox_probe(struct platform_device *pdev) mb->mbox.ops = drv_data->ops; spin_lock_init(&mb->cfg_lock); - if (device_property_present(&pdev->dev, "rockchip,tx-direction-b2a")) - mb->reg = &drv_data->reg_b2a; - else - mb->reg = &drv_data->reg_a2b; - - /* - * rockchip,txdone-ack: the mailbox client uses its own ACK to check - * TX_DONE, and call mbox_client_txdone() API to schedule tx_tick. - * rockchip,txdone-irq: the feature only support from RK3506, the ISR - * function call mbox_chan_txdone() API to schedule tx_tick. - * txdone_poll is default for all the platform, it cooperates with - * "rockchip,txpoll-period-ms" or "rockchip,txpoll-period-us" - * periodically call last_tx_done() to check TX_DONE by the hrtimer - * in mailbox framework. - */ - if (device_property_present(&pdev->dev, "rockchip,txdone-ack")) { - mb->mbox.txdone_irq = false; - mb->mbox.txdone_poll = false; - } else if (device_property_present(&pdev->dev, "rockchip,txdone-irq")) { - mb->mbox.txdone_irq = true; - } else { - mb->mbox.txdone_poll = true; - if (IS_REACHABLE(CONFIG_MAILBOX_POLL_PERIOD_US)) { - ret = device_property_read_u32(&pdev->dev, - "rockchip,txpoll-period-us", - &txpoll_period); - if (!ret) { - mb->mbox.txpoll_period = txpoll_period; - } else { - ret = device_property_read_u32(&pdev->dev, - "rockchip,txpoll-period-ms", - &txpoll_period); - mb->mbox.txpoll_period = !ret ? txpoll_period : MAILBOX_POLLING_MS; - mb->mbox.txpoll_period *= 1000U; /* Convert to us */ - } - } else { - ret = device_property_read_u32(&pdev->dev, - "rockchip,txpoll-period-ms", - &txpoll_period); - mb->mbox.txpoll_period = !ret ? txpoll_period : MAILBOX_POLLING_MS; - } - } - - if (device_property_present(&pdev->dev, "rockchip,enable-cmd-trigger")) - mb->trigger_method = 0; - else - mb->trigger_method = 1; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!res) return -ENODEV; @@ -478,12 +492,7 @@ static int rockchip_mbox_probe(struct platform_device *pdev) if (IS_ERR(mb->mbox_base)) return PTR_ERR(mb->mbox_base); - if (drv_data->version != MAILBOX_VERSION_1_0_0) - mb->version = FIELD_GET(MAILBOX_V2_VERSION_MASK, - readl_relaxed(mb->mbox_base + MAILBOX_V2_VERSION)); - - if (!mb->version) - mb->version = drv_data->version; + rockchip_mbox_get_properties(mb, drv_data); mb->pclk = devm_clk_get(&pdev->dev, "pclk_mailbox"); if (IS_ERR(mb->pclk)) { From 34fd19547b7b45c37d39d508637d45007524fcac Mon Sep 17 00:00:00 2001 From: Frank Wang Date: Sat, 11 Oct 2025 14:18:41 +0800 Subject: [PATCH 39/40] dt-bindings: hwlock: rockchip: Add the maximum user count property Set the maximum user count via the "rockchip,hwlock-max-user" property to indicate the maximum number of users supported by this IP. Signed-off-by: Frank Wang Change-Id: I7dff4c813346db94642ed5b36191af0a1c0e5041 --- .../devicetree/bindings/hwlock/rockchip-hwspinlock.txt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/hwlock/rockchip-hwspinlock.txt b/Documentation/devicetree/bindings/hwlock/rockchip-hwspinlock.txt index 4520b26cdebc..900ee94a1f08 100644 --- a/Documentation/devicetree/bindings/hwlock/rockchip-hwspinlock.txt +++ b/Documentation/devicetree/bindings/hwlock/rockchip-hwspinlock.txt @@ -13,7 +13,9 @@ Required properties : - rockchip,hwlock-num-locks :number of hwlocks provided by this device. Optional properties : -- rockchip,hwlock-user-id : Set hwlock user id (4 bit, default is 0x01). +- rockchip,hwlock-user-id : Set hwlock user id (default is 0x01). +- rockchip,hwlock-max-user : Set the maximum hwlock user count supported + by the IP (default is 0x0F). Please look at the generic hwlock binding for usage information for consumers, "Documentation/devicetree/bindings/hwlock/hwlock.txt" From fbdb94a0c7bddcf16d5e01588e5d0aed65ae43f2 Mon Sep 17 00:00:00 2001 From: Frank Wang Date: Sat, 11 Oct 2025 11:35:30 +0800 Subject: [PATCH 40/40] hwspinlock: rockchip: Add maximum user count config Since the new IP has expanded the maximum hwlock user count to 6 bits, this adds configuring the maximum hwlock user count via dtsi/dts to support the feature. Signed-off-by: Frank Wang Change-Id: I6e59bb22984e6ee5c9d31099266778c0e42350bf --- drivers/hwspinlock/rockchip_hwspinlock.c | 35 +++++++++++++++--------- 1 file changed, 22 insertions(+), 13 deletions(-) diff --git a/drivers/hwspinlock/rockchip_hwspinlock.c b/drivers/hwspinlock/rockchip_hwspinlock.c index f570ac260de8..615787ccffeb 100644 --- a/drivers/hwspinlock/rockchip_hwspinlock.c +++ b/drivers/hwspinlock/rockchip_hwspinlock.c @@ -14,6 +14,8 @@ struct rockchip_hwspinlock { void __iomem *io_base; + u32 user_id; + u32 user_id_mask; struct hwspinlock_device bank; }; @@ -22,35 +24,35 @@ struct rockchip_hwspinlock { /* Hardware spinlock register offsets */ #define HWSPINLOCK_OFFSET(x) (0x4 * (x)) -#define HWSPINLOCK_ID_MASK 0x0F -#define HWLOCK_DEFAULT_USER 0x01 - -static u32 hwlock_user_id; +#define HWLOCK_DEFAULT_USER 0x01 +#define HWLOCK_DEFAULT_USER_ID_MASK 0x0F static int rockchip_hwspinlock_trylock(struct hwspinlock *lock) { + struct rockchip_hwspinlock *hwlock = dev_get_drvdata(lock->bank->dev); void __iomem *lock_addr = lock->priv; - writel(hwlock_user_id, lock_addr); + writel(hwlock->user_id, lock_addr); /* * Get only first 4 bits and compare to HWSPINLOCK_OWNER_ID, * if equal, we attempt to acquire the lock, otherwise, * someone else has it. */ - return (hwlock_user_id == (readl(lock_addr) & HWSPINLOCK_ID_MASK)); + return (hwlock->user_id == (readl(lock_addr) & hwlock->user_id_mask)); } static void rockchip_hwspinlock_unlock(struct hwspinlock *lock) { + struct rockchip_hwspinlock *hwlock = dev_get_drvdata(lock->bank->dev); void __iomem *lock_addr = lock->priv; - u32 lock_owner = readl(lock_addr) & HWSPINLOCK_ID_MASK; + u32 lock_owner = readl(lock_addr) & hwlock->user_id_mask; - if (lock_owner != hwlock_user_id) { + if (lock_owner != hwlock->user_id) { dev_warn(lock->bank->dev, "WARNING: against user %u release a lock held by %u\n", - hwlock_user_id, lock_owner); + hwlock->user_id, lock_owner); return; } @@ -85,11 +87,18 @@ static int rockchip_hwspinlock_probe(struct platform_device *pdev) if (IS_ERR(hwspin->io_base)) return PTR_ERR(hwspin->io_base); + ret = device_property_read_u32(&pdev->dev, "rockchip,hwlock-max-user", + &hwspin->user_id_mask); + if (ret || !hwspin->user_id_mask) + hwspin->user_id_mask = HWLOCK_DEFAULT_USER_ID_MASK; + ret = device_property_read_u32(&pdev->dev, "rockchip,hwlock-user-id", - &hwlock_user_id); - if (ret || !hwlock_user_id || hwlock_user_id > HWSPINLOCK_ID_MASK) - hwlock_user_id = HWLOCK_DEFAULT_USER; - dev_info(&pdev->dev, "hwlock user id %u, locks %u\n", hwlock_user_id, num_locks); + &hwspin->user_id); + if (ret || !hwspin->user_id || hwspin->user_id > hwspin->user_id_mask) + hwspin->user_id = HWLOCK_DEFAULT_USER; + + dev_info(&pdev->dev, "hwlock user id %u, locks %u, maximum user %u\n", + hwspin->user_id, num_locks, hwspin->user_id_mask); for (idx = 0; idx < num_locks; idx++) { hwlock = &hwspin->bank.lock[idx];