From: Jason Yang <jason98166@gmail.com>
To: Vinod Koul <vkoul@kernel.org>,
Neil Armstrong <neil.armstrong@linaro.org>,
Manivannan Sadhasivam <mani@kernel.org>,
Rob Herring <robh@kernel.org>,
Krzysztof Kozlowski <krzk+dt@kernel.org>,
Conor Dooley <conor+dt@kernel.org>,
Heiko Stuebner <heiko@sntech.de>,
Guochun Huang <hero.huang@rock-chips.com>,
Philipp Zabel <p.zabel@pengutronix.de>
Cc: Michael Riesch <michael.riesch@collabora.com>,
Sebastian Reichel <sebastian.reichel@collabora.com>,
Bryan O'Donoghue <bryan.odonoghue@linaro.org>,
linux-phy@lists.infradead.org, devicetree@vger.kernel.org,
linux-arm-kernel@lists.infradead.org,
linux-rockchip@lists.infradead.org,
linux-kernel@vger.kernel.org, Jason Yang <jason98166@gmail.com>
Subject: [PATCH v6 8/9] phy: rockchip-samsung-dcphy: Add MIPI D-PHY receiver support
Date: Tue, 10 Nov 2026 16:18:11 +0800 [thread overview]
Message-ID: <20261110-dcphy-rx-v1-v6-8-d681ba20b36a@gmail.com> (raw)
In-Reply-To: <20261110-dcphy-rx-v1-v6-0-d681ba20b36a@gmail.com>
Add the receiver half of the block, so a MIPI CSI-2 camera can use the
same PHY that already drives a MIPI DSI output on RK3588. It follows the
receiver start-up sequence in the RK3588 TRM [1]. The HS-RX settle values
come from the RK3588 vendor kernel.
The initial deskew calibration that the D-PHY specification asks for
above 1.5 Gbps is not implemented; the vendor kernel programs it from
RK3576 onwards only. Data rates above 4.5 Gbps, the end of the settle
table, are rejected at configure time.
Tested on RK3588 with an IMX219 on the receiver and a DSI panel on the
transmitter of the same PHY.
[1] RK3588 TRM: sections 22.6.3 (start-up sequence, step 3 for
slave-only use) and 22.6.4.3 (worked receiver example)
Signed-off-by: Jason Yang <jason98166@gmail.com>
---
drivers/phy/rockchip/phy-rockchip-samsung-dcphy.c | 388 ++++++++++++++++++++++
1 file changed, 388 insertions(+)
diff --git a/drivers/phy/rockchip/phy-rockchip-samsung-dcphy.c b/drivers/phy/rockchip/phy-rockchip-samsung-dcphy.c
index e8e229fc4856..ee72bc397628 100644
--- a/drivers/phy/rockchip/phy-rockchip-samsung-dcphy.c
+++ b/drivers/phy/rockchip/phy-rockchip-samsung-dcphy.c
@@ -244,6 +244,70 @@
#define T_TA_GET(x) FIELD_PREP(GENMASK(7, 4), x)
#define T_TA_GO(x) FIELD_PREP(GENMASK(3, 0), x)
+#define DPHY_SC_GNR_CON0 0x0b00
+#define DPHY_SC_GNR_CON1 0x0b04
+#define DPHY_SC_ANA_CON1 0x0b0c
+#define HS_RX_LS_650UA BIT(15)
+#define HS_RX_AMP2_500UA FIELD_PREP(GENMASK(14, 13), 0)
+#define HS_RX_AMP1_700UA FIELD_PREP(GENMASK(12, 11), 0)
+#define DPHY_SC_ANA_CON2 0x0b10
+#define HS_TERM_SW(x) FIELD_PREP(GENMASK(2, 0), x)
+#define HS_TERM_96_6OHM HS_TERM_SW(2)
+#define DPHY_SC_ANA_CON3 0x0b14
+#define ULPS_HYS_SW_DPHY(x) FIELD_PREP(GENMASK(10, 8), x)
+#define ULPS_HYS_104MV ULPS_HYS_SW_DPHY(6)
+#define DPHY_SC_TIME_CON0 0x0b30
+#define T_CLK_SETTLE(x) FIELD_PREP(GENMASK(7, 0), x)
+#define T_CLK_MISS(x) FIELD_PREP(GENMASK(11, 8), x)
+#define COMBO_SD0_GNR_CON0 0x0c00
+#define COMBO_SD0_GNR_CON1 0x0c04
+#define COMBO_SD0_ANA_CON1 0x0c0c
+#define COMBO_SD0_ANA_CON2 0x0c10
+#define SKEW_DLYSEL(x) FIELD_PREP(GENMASK(9, 8), x)
+#define RX_TERM_SW(x) FIELD_PREP(GENMASK(2, 0), x)
+#define RX_TERM_96_6OHM RX_TERM_SW(2)
+#define COMBO_SD0_ANA_CON3 0x0c14
+#define SEL_ESCPOL BIT(11)
+#define LP_HYS_SW(x) FIELD_PREP(GENMASK(5, 4), x)
+#define LP_HYS_100MV LP_HYS_SW(3)
+#define COMBO_SD0_ANA_CON7 0x0c24
+#define CLK_DBL_CTRL(x) FIELD_PREP(GENMASK(7, 6), x)
+#define COMBO_SD0_TIME_CON0 0x0c30
+#define T_HS_SETTLE_MASK GENMASK(7, 0)
+#define T_HS_SETTLE(x) FIELD_PREP(T_HS_SETTLE_MASK, x)
+#define SETTLE_CLK_SEL BIT(8)
+#define COMBO_SD0_TIME_CON1 0x0c34
+#define T_ERR_SOT_SYNC_MASK GENMASK(7, 0)
+#define T_ERR_SOT_SYNC(x) FIELD_PREP(T_ERR_SOT_SYNC_MASK, x)
+#define COMBO_SD0_DESKEW_CON2 0x0c48
+#define SKEW_CAL_CLK_COARSE_SET(x) FIELD_PREP(GENMASK(4, 0), x)
+#define COMBO_SD1_GNR_CON0 0x0d00
+#define COMBO_SD1_GNR_CON1 0x0d04
+#define COMBO_SD1_ANA_CON1 0x0d0c
+#define COMBO_SD1_ANA_CON2 0x0d10
+#define COMBO_SD1_ANA_CON3 0x0d14
+#define COMBO_SD1_ANA_CON7 0x0d24
+#define COMBO_SD1_TIME_CON0 0x0d30
+#define COMBO_SD1_TIME_CON1 0x0d34
+#define COMBO_SD1_DESKEW_CON2 0x0d48
+#define COMBO_SD2_GNR_CON0 0x0e00
+#define COMBO_SD2_GNR_CON1 0x0e04
+#define COMBO_SD2_ANA_CON1 0x0e0c
+#define COMBO_SD2_ANA_CON2 0x0e10
+#define COMBO_SD2_ANA_CON3 0x0e14
+#define COMBO_SD2_ANA_CON7 0x0e24
+#define COMBO_SD2_TIME_CON0 0x0e30
+#define COMBO_SD2_TIME_CON1 0x0e34
+#define COMBO_SD2_DESKEW_CON2 0x0e48
+#define DPHY_SD3_GNR_CON0 0x0f00
+#define DPHY_SD3_GNR_CON1 0x0f04
+#define DPHY_SD3_ANA_CON1 0x0f0c
+#define DPHY_SD3_ANA_CON2 0x0f10
+#define DPHY_SD3_ANA_CON3 0x0f14
+#define DPHY_SD3_TIME_CON0 0x0f30
+#define DPHY_SD3_TIME_CON1 0x0f34
+#define DPHY_SD3_DESKEW_CON2 0x0f48
+
/* MIPI_CDPHY_GRF registers */
#define MIPI_DCPHY_GRF_CON0 0x0000
#define S_CPHY_MODE FIELD_PREP_WM16(BIT(3), 1)
@@ -283,6 +347,8 @@ struct samsung_mipi_dcphy_plat_data {
struct samsung_mipi_phy {
struct phy *phy;
unsigned int lanes;
+ unsigned long long hs_clk_rate;
+ u16 hsfreq_cfg;
};
struct samsung_mipi_dcphy {
@@ -296,6 +362,7 @@ struct samsung_mipi_dcphy {
struct reset_control *apb_rst;
struct reset_control *grf_apb_rst;
struct samsung_mipi_phy tx;
+ struct samsung_mipi_phy rx;
u8 type;
bool legacy_mismatch;
@@ -978,6 +1045,228 @@ struct samsung_mipi_dphy_timing samsung_mipi_dphy_timing_table[] = {
{ 80, 2, 0, 0, 28, 5, 0, 22, 2, 0, 5},
};
+struct samsung_mipi_dphy_rx_hsfreq_range {
+ u32 range_h_mbps;
+ u16 cfg_bit;
+};
+
+/*
+ * HS-RX settle values taken from the rk3588 vendor kernel; the TRM
+ * defers the per-rate values to its Supplement Guide. SETTLE_CLK_SEL
+ * is read-only in the TRM but the vendor kernel has always written it.
+ */
+static const struct samsung_mipi_dphy_rx_hsfreq_range
+samsung_mipi_dphy_rx_hsfreq_ranges[] = {
+ { 80, 0x105 }, { 100, 0x106 }, { 120, 0x107 }, { 140, 0x108 },
+ { 160, 0x109 }, { 180, 0x10a }, { 200, 0x10b }, { 220, 0x10c },
+ { 240, 0x10d }, { 270, 0x10e }, { 290, 0x10f }, { 310, 0x110 },
+ { 330, 0x111 }, { 350, 0x112 }, { 370, 0x113 }, { 390, 0x114 },
+ { 410, 0x115 }, { 430, 0x116 }, { 450, 0x117 }, { 470, 0x118 },
+ { 490, 0x119 }, { 510, 0x11a }, { 540, 0x11b }, { 560, 0x11c },
+ { 580, 0x11d }, { 600, 0x11e }, { 620, 0x11f }, { 640, 0x120 },
+ { 660, 0x121 }, { 680, 0x122 }, { 700, 0x123 }, { 720, 0x124 },
+ { 740, 0x125 }, { 760, 0x126 }, { 790, 0x127 }, { 810, 0x128 },
+ { 830, 0x129 }, { 850, 0x12a }, { 870, 0x12b }, { 890, 0x12c },
+ { 910, 0x12d }, { 930, 0x12e }, { 950, 0x12f }, { 970, 0x130 },
+ { 990, 0x131 }, { 1010, 0x132 }, { 1030, 0x133 }, { 1060, 0x134 },
+ { 1080, 0x135 }, { 1100, 0x136 }, { 1120, 0x137 }, { 1140, 0x138 },
+ { 1160, 0x139 }, { 1180, 0x13a }, { 1200, 0x13b }, { 1220, 0x13c },
+ { 1240, 0x13d }, { 1260, 0x13e }, { 1280, 0x13f }, { 1310, 0x140 },
+ { 1330, 0x141 }, { 1350, 0x142 }, { 1370, 0x143 }, { 1390, 0x144 },
+ { 1410, 0x145 }, { 1430, 0x146 }, { 1450, 0x147 }, { 1470, 0x148 },
+ { 1490, 0x149 }, { 1580, 0x007 }, { 1740, 0x008 }, { 1910, 0x009 },
+ { 2070, 0x00a }, { 2240, 0x00b }, { 2410, 0x00c }, { 2570, 0x00d },
+ { 2740, 0x00e }, { 2910, 0x00f }, { 3070, 0x010 }, { 3240, 0x011 },
+ { 3410, 0x012 }, { 3570, 0x013 }, { 3740, 0x014 }, { 3890, 0x015 },
+ { 4070, 0x016 }, { 4240, 0x017 }, { 4400, 0x018 }, { 4500, 0x019 },
+};
+
+static const u32 rx_data_lane_gnr_con0[] = {
+ COMBO_SD0_GNR_CON0, COMBO_SD1_GNR_CON0,
+ COMBO_SD2_GNR_CON0, DPHY_SD3_GNR_CON0,
+};
+
+static const u32 rx_data_lane_gnr_con1[] = {
+ COMBO_SD0_GNR_CON1, COMBO_SD1_GNR_CON1,
+ COMBO_SD2_GNR_CON1, DPHY_SD3_GNR_CON1,
+};
+
+static const u32 rx_lane_time_con0[] = {
+ COMBO_SD0_TIME_CON0, COMBO_SD1_TIME_CON0,
+ COMBO_SD2_TIME_CON0, DPHY_SD3_TIME_CON0,
+};
+
+static const u32 rx_lane_time_con1[] = {
+ COMBO_SD0_TIME_CON1, COMBO_SD1_TIME_CON1,
+ COMBO_SD2_TIME_CON1, DPHY_SD3_TIME_CON1,
+};
+
+static int samsung_mipi_dphy_rx_lookup_hsfreq(u32 lane_mbps, u16 *cfg_bit)
+{
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(samsung_mipi_dphy_rx_hsfreq_ranges); i++) {
+ if (lane_mbps <= samsung_mipi_dphy_rx_hsfreq_ranges[i].range_h_mbps) {
+ *cfg_bit = samsung_mipi_dphy_rx_hsfreq_ranges[i].cfg_bit;
+ return 0;
+ }
+ }
+
+ return -ERANGE;
+}
+
+static u32 samsung_mipi_dphy_rx_data_lane_dlysel(u32 lane_mbps)
+{
+ if (lane_mbps < 1500)
+ return 0;
+ if (lane_mbps < 2000)
+ return SKEW_DLYSEL(3);
+ if (lane_mbps < 3000)
+ return SKEW_DLYSEL(2);
+ if (lane_mbps < 4000)
+ return SKEW_DLYSEL(1);
+ return 0;
+}
+
+/*
+ * RX analog tuning values from the vendor kernel; data lane 0 differs
+ * from the other lanes on purpose, as in the vendor receive profile.
+ */
+static void samsung_mipi_dphy_rx_config_common(struct samsung_mipi_dcphy *samsung)
+{
+ struct samsung_mipi_phy *rx = &samsung->rx;
+ u32 lane_mbps = div64_ul(rx->hs_clk_rate, USEC_PER_SEC);
+ u32 dlysel = samsung_mipi_dphy_rx_data_lane_dlysel(lane_mbps);
+ u32 ana_con1_common = HS_RX_LS_650UA | HS_RX_AMP2_500UA |
+ HS_RX_AMP1_700UA;
+ u32 ana_con2_common = dlysel | RX_TERM_96_6OHM;
+
+ regmap_write(samsung->regmap, DPHY_SC_ANA_CON1, ana_con1_common);
+ regmap_write(samsung->regmap, DPHY_SC_ANA_CON2, HS_TERM_96_6OHM);
+ regmap_write(samsung->regmap, DPHY_SC_ANA_CON3, ULPS_HYS_104MV);
+
+ regmap_write(samsung->regmap, COMBO_SD0_ANA_CON1, ana_con1_common);
+ regmap_write(samsung->regmap, COMBO_SD0_ANA_CON2, ana_con2_common);
+ regmap_write(samsung->regmap, COMBO_SD0_ANA_CON3,
+ ULPS_HYS_104MV | LP_HYS_100MV | SEL_ESCPOL);
+ regmap_write(samsung->regmap, COMBO_SD0_ANA_CON7, CLK_DBL_CTRL(1));
+ regmap_write(samsung->regmap, COMBO_SD0_DESKEW_CON2,
+ SKEW_CAL_CLK_COARSE_SET(0));
+
+ if (rx->lanes > 1) {
+ regmap_write(samsung->regmap, COMBO_SD1_ANA_CON1,
+ ana_con1_common);
+ regmap_write(samsung->regmap, COMBO_SD1_ANA_CON2,
+ ana_con2_common);
+ regmap_write(samsung->regmap, COMBO_SD1_ANA_CON3,
+ ULPS_HYS_104MV);
+ regmap_write(samsung->regmap, COMBO_SD1_ANA_CON7,
+ CLK_DBL_CTRL(1));
+ regmap_write(samsung->regmap, COMBO_SD1_DESKEW_CON2,
+ SKEW_CAL_CLK_COARSE_SET(3));
+ }
+
+ if (rx->lanes > 2) {
+ regmap_write(samsung->regmap, COMBO_SD2_ANA_CON1,
+ ana_con1_common);
+ regmap_write(samsung->regmap, COMBO_SD2_ANA_CON2,
+ ana_con2_common);
+ regmap_write(samsung->regmap, COMBO_SD2_ANA_CON3,
+ ULPS_HYS_104MV);
+ regmap_write(samsung->regmap, COMBO_SD2_ANA_CON7,
+ CLK_DBL_CTRL(1));
+ regmap_write(samsung->regmap, COMBO_SD2_DESKEW_CON2,
+ SKEW_CAL_CLK_COARSE_SET(3));
+ }
+
+ if (rx->lanes > 3) {
+ regmap_write(samsung->regmap, DPHY_SD3_ANA_CON1,
+ ana_con1_common);
+ regmap_write(samsung->regmap, DPHY_SD3_ANA_CON2,
+ ana_con2_common);
+ regmap_write(samsung->regmap, DPHY_SD3_ANA_CON3,
+ ULPS_HYS_104MV);
+ regmap_write(samsung->regmap, DPHY_SD3_DESKEW_CON2,
+ SKEW_CAL_CLK_COARSE_SET(3));
+ }
+}
+
+static void samsung_mipi_dphy_rx_config_settle(struct samsung_mipi_dcphy *samsung)
+{
+ struct samsung_mipi_phy *rx = &samsung->rx;
+ u16 cfg_bit = rx->hsfreq_cfg;
+ unsigned int i;
+
+ /*
+ * Clock-lane settle keeps the value of the TRM 2.5 Gbps receiver
+ * example at every rate, as Samsung's own Exynos driver for this
+ * PHY does.
+ */
+ regmap_write(samsung->regmap, DPHY_SC_TIME_CON0,
+ T_CLK_SETTLE(0x01) | T_CLK_MISS(0x03));
+
+ for (i = 0; i < rx->lanes; i++) {
+ regmap_update_bits(samsung->regmap, rx_lane_time_con0[i],
+ T_HS_SETTLE_MASK | SETTLE_CLK_SEL, cfg_bit);
+ regmap_update_bits(samsung->regmap, rx_lane_time_con1[i],
+ T_ERR_SOT_SYNC_MASK, T_ERR_SOT_SYNC(0x03));
+ }
+}
+
+static void samsung_mipi_dphy_rx_lane_disable(struct samsung_mipi_dcphy *samsung)
+{
+ struct samsung_mipi_phy *rx = &samsung->rx;
+ unsigned int i;
+
+ regmap_update_bits(samsung->regmap, DPHY_SC_GNR_CON0, PHY_ENABLE, 0);
+ for (i = 0; i < rx->lanes; i++)
+ regmap_update_bits(samsung->regmap, rx_data_lane_gnr_con0[i],
+ PHY_ENABLE, 0);
+}
+
+static int samsung_mipi_dphy_rx_lane_enable(struct samsung_mipi_dcphy *samsung)
+{
+ struct samsung_mipi_phy *rx = &samsung->rx;
+ unsigned int i;
+ u32 sts;
+ int ret;
+
+ regmap_write(samsung->regmap, DPHY_SC_GNR_CON1, T_PHY_READY(0x1450));
+ regmap_update_bits(samsung->regmap, DPHY_SC_GNR_CON0,
+ PHY_ENABLE, PHY_ENABLE);
+
+ for (i = 0; i < rx->lanes; i++) {
+ regmap_write(samsung->regmap, rx_data_lane_gnr_con1[i],
+ T_PHY_READY(0x1450));
+ regmap_update_bits(samsung->regmap, rx_data_lane_gnr_con0[i],
+ PHY_ENABLE, PHY_ENABLE);
+ }
+
+ ret = regmap_read_poll_timeout(samsung->regmap, DPHY_SC_GNR_CON0,
+ sts, sts & PHY_READY, 200, 4000);
+ if (ret) {
+ dev_err(samsung->dev, "RX clock lane not ready\n");
+ goto err_lane_disable;
+ }
+
+ for (i = 0; i < rx->lanes; i++) {
+ ret = regmap_read_poll_timeout(samsung->regmap,
+ rx_data_lane_gnr_con0[i],
+ sts, sts & PHY_READY,
+ 200, 2000);
+ if (ret) {
+ dev_err(samsung->dev, "RX data lane %u not ready\n", i);
+ goto err_lane_disable;
+ }
+ }
+
+ return 0;
+
+err_lane_disable:
+ samsung_mipi_dphy_rx_lane_disable(samsung);
+ return ret;
+}
+
static void samsung_mipi_dcphy_bias_block_enable(struct samsung_mipi_dcphy *samsung)
{
regmap_write(samsung->regmap, BIAS_CON0, I_DEV_DIV_6 | I_RES_100_2UA);
@@ -994,6 +1283,40 @@ static void samsung_mipi_dcphy_bias_block_enable(struct samsung_mipi_dcphy *sams
I_MUX_SEL_MASK, I_MUX_400MV);
}
+static int samsung_mipi_dphy_rx_power_on(struct samsung_mipi_dcphy *samsung)
+{
+ struct samsung_mipi_phy *rx = &samsung->rx;
+ int ret;
+
+ if (!rx->hs_clk_rate || !rx->lanes)
+ return -EINVAL;
+
+ reset_control_assert(samsung->s_phy_rst);
+
+ samsung_mipi_dphy_rx_config_common(samsung);
+ samsung_mipi_dphy_rx_config_settle(samsung);
+
+ ret = samsung_mipi_dphy_rx_lane_enable(samsung);
+
+ reset_control_deassert(samsung->s_phy_rst);
+
+ return ret;
+}
+
+static int samsung_mipi_dphy_rx_power_off(struct samsung_mipi_dcphy *samsung)
+{
+ reset_control_assert(samsung->s_phy_rst);
+
+ samsung_mipi_dphy_rx_lane_disable(samsung);
+
+ reset_control_deassert(samsung->s_phy_rst);
+
+ /* Delay from the vendor kernel; the TRM has no teardown sequence. */
+ usleep_range(500, 1000);
+
+ return 0;
+}
+
static void samsung_mipi_dphy_tx_lane_enable(struct samsung_mipi_dcphy *samsung)
{
regmap_write(samsung->regmap, DPHY_MC_GNR_CON1, T_PHY_READY(0x2000));
@@ -1526,6 +1849,53 @@ static int samsung_mipi_dcphy_exit(struct phy *phy)
return 0;
}
+static int samsung_mipi_dcphy_rx_configure(struct phy *phy,
+ union phy_configure_opts *opts)
+{
+ struct samsung_mipi_dcphy *samsung = phy_get_drvdata(phy);
+ struct samsung_mipi_phy *rx = &samsung->rx;
+ u32 lane_mbps = div64_ul(opts->mipi_dphy.hs_clk_rate, USEC_PER_SEC);
+ int ret;
+
+ ret = samsung_mipi_dphy_rx_lookup_hsfreq(lane_mbps, &rx->hsfreq_cfg);
+ if (ret) {
+ dev_err(samsung->dev, "unsupported RX data rate %u Mbps\n",
+ lane_mbps);
+ return ret;
+ }
+
+ rx->lanes = opts->mipi_dphy.lanes > 4 ? 4 : opts->mipi_dphy.lanes;
+ rx->hs_clk_rate = opts->mipi_dphy.hs_clk_rate;
+
+ return 0;
+}
+
+static int samsung_mipi_dcphy_rx_power_on(struct phy *phy)
+{
+ struct samsung_mipi_dcphy *samsung = phy_get_drvdata(phy);
+
+ switch (samsung->type) {
+ case PHY_TYPE_DPHY:
+ return samsung_mipi_dphy_rx_power_on(samsung);
+ default:
+ /* CPHY part to be implemented later */
+ return -EOPNOTSUPP;
+ }
+}
+
+static int samsung_mipi_dcphy_rx_power_off(struct phy *phy)
+{
+ struct samsung_mipi_dcphy *samsung = phy_get_drvdata(phy);
+
+ switch (samsung->type) {
+ case PHY_TYPE_DPHY:
+ return samsung_mipi_dphy_rx_power_off(samsung);
+ default:
+ /* CPHY part to be implemented later */
+ return -EOPNOTSUPP;
+ }
+}
+
static const struct phy_ops samsung_mipi_dcphy_tx_ops = {
.configure = samsung_mipi_dcphy_tx_configure,
.power_on = samsung_mipi_dcphy_tx_power_on,
@@ -1535,6 +1905,15 @@ static const struct phy_ops samsung_mipi_dcphy_tx_ops = {
.owner = THIS_MODULE,
};
+static const struct phy_ops samsung_mipi_dcphy_rx_ops = {
+ .configure = samsung_mipi_dcphy_rx_configure,
+ .power_on = samsung_mipi_dcphy_rx_power_on,
+ .power_off = samsung_mipi_dcphy_rx_power_off,
+ .init = samsung_mipi_dcphy_init,
+ .exit = samsung_mipi_dcphy_exit,
+ .owner = THIS_MODULE,
+};
+
static const struct regmap_config samsung_mipi_dcphy_regmap_config = {
.name = "dcphy",
.reg_bits = 32,
@@ -1556,6 +1935,8 @@ static struct phy *samsung_mipi_dcphy_xlate(struct device *dev,
switch (args->args[0]) {
case PHY_DIRECTION_TX:
return samsung->tx.phy;
+ case PHY_DIRECTION_RX:
+ return samsung->rx.phy;
case PHY_TYPE_DPHY:
case PHY_TYPE_CPHY:
if (args->args[0] != samsung->type) {
@@ -1649,6 +2030,13 @@ static int samsung_mipi_dcphy_probe(struct platform_device *pdev)
phy_set_drvdata(samsung->tx.phy, samsung);
+ samsung->rx.phy = devm_phy_create(dev, NULL, &samsung_mipi_dcphy_rx_ops);
+ if (IS_ERR(samsung->rx.phy))
+ return dev_err_probe(dev, PTR_ERR(samsung->rx.phy),
+ "Failed to create MIPI DC-PHY receiver\n");
+
+ phy_set_drvdata(samsung->rx.phy, samsung);
+
phy_provider = devm_of_phy_provider_register(dev, samsung_mipi_dcphy_xlate);
if (IS_ERR(phy_provider))
return dev_err_probe(dev, PTR_ERR(phy_provider),
--
2.43.0
next prev parent reply other threads:[~2026-11-10 8:18 UTC|newest]
Thread overview: 10+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-11-10 8:18 [PATCH v6 0/9] phy: rockchip-samsung-dcphy: Add the MIPI D-PHY receiver Jason Yang
2026-11-10 8:18 ` [PATCH v6 1/9] dt-bindings: phy: Add PHY_DIRECTION_TX/RX definitions Jason Yang
2026-11-10 8:18 ` [PATCH v6 2/9] dt-bindings: phy: rockchip,rk3588-mipi-dcphy: Select TX or RX, add phy-type Jason Yang
2026-11-10 8:18 ` [PATCH v6 3/9] phy: rockchip-samsung-dcphy: Unwind power-on on PLL lock failure Jason Yang
2026-11-10 8:18 ` [PATCH v6 4/9] phy: rockchip-samsung-dcphy: Always write the rate-dependent registers Jason Yang
2026-11-10 8:18 ` [PATCH v6 5/9] phy: rockchip-samsung-dcphy: Move block-level setup to runtime resume Jason Yang
2026-11-10 8:18 ` [PATCH v6 6/9] phy: rockchip-samsung-dcphy: Name the transmitter helpers and ops Jason Yang
2026-11-10 8:18 ` [PATCH v6 7/9] phy: rockchip-samsung-dcphy: Support the new phy-type and direction binding Jason Yang
2026-11-10 8:18 ` Jason Yang [this message]
2026-11-10 8:18 ` [PATCH v6 9/9] arm64: dts: rockchip: add the dcphy mipi csi-2 receiver nodes to rk3588 Jason Yang
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20261110-dcphy-rx-v1-v6-8-d681ba20b36a@gmail.com \
--to=jason98166@gmail.com \
--cc=bryan.odonoghue@linaro.org \
--cc=conor+dt@kernel.org \
--cc=devicetree@vger.kernel.org \
--cc=heiko@sntech.de \
--cc=hero.huang@rock-chips.com \
--cc=krzk+dt@kernel.org \
--cc=linux-arm-kernel@lists.infradead.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-phy@lists.infradead.org \
--cc=linux-rockchip@lists.infradead.org \
--cc=mani@kernel.org \
--cc=michael.riesch@collabora.com \
--cc=neil.armstrong@linaro.org \
--cc=p.zabel@pengutronix.de \
--cc=robh@kernel.org \
--cc=sebastian.reichel@collabora.com \
--cc=vkoul@kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®