xref: /linux/drivers/phy/rockchip/phy-rockchip-dphy-rx0.c (revision a1c613ae4c322ddd58d5a8539dbfba2a0380a8c0)
137abc181SEzequiel Garcia // SPDX-License-Identifier: (GPL-2.0+ OR MIT)
237abc181SEzequiel Garcia /*
337abc181SEzequiel Garcia  * Rockchip MIPI Synopsys DPHY RX0 driver
437abc181SEzequiel Garcia  *
537abc181SEzequiel Garcia  * Copyright (C) 2019 Collabora, Ltd.
637abc181SEzequiel Garcia  *
737abc181SEzequiel Garcia  * Based on:
837abc181SEzequiel Garcia  *
937abc181SEzequiel Garcia  * drivers/media/platform/rockchip/isp1/mipi_dphy_sy.c
1037abc181SEzequiel Garcia  * in https://chromium.googlesource.com/chromiumos/third_party/kernel,
1137abc181SEzequiel Garcia  * chromeos-4.4 branch.
1237abc181SEzequiel Garcia  *
1337abc181SEzequiel Garcia  * Copyright (C) 2017 Fuzhou Rockchip Electronics Co., Ltd.
1437abc181SEzequiel Garcia  *   Jacob Chen <jacob2.chen@rock-chips.com>
1537abc181SEzequiel Garcia  *   Shunqian Zheng <zhengsq@rock-chips.com>
1637abc181SEzequiel Garcia  */
1737abc181SEzequiel Garcia 
1837abc181SEzequiel Garcia #include <linux/clk.h>
19488e3f52STomasz Figa #include <linux/delay.h>
2037abc181SEzequiel Garcia #include <linux/io.h>
2137abc181SEzequiel Garcia #include <linux/mfd/syscon.h>
2237abc181SEzequiel Garcia #include <linux/module.h>
2337abc181SEzequiel Garcia #include <linux/of.h>
2437abc181SEzequiel Garcia #include <linux/phy/phy.h>
2537abc181SEzequiel Garcia #include <linux/phy/phy-mipi-dphy.h>
2637abc181SEzequiel Garcia #include <linux/platform_device.h>
2737abc181SEzequiel Garcia #include <linux/regmap.h>
2837abc181SEzequiel Garcia 
2937abc181SEzequiel Garcia #define RK3399_GRF_SOC_CON9		0x6224
3037abc181SEzequiel Garcia #define RK3399_GRF_SOC_CON21		0x6254
3137abc181SEzequiel Garcia #define RK3399_GRF_SOC_CON22		0x6258
3237abc181SEzequiel Garcia #define RK3399_GRF_SOC_CON23		0x625c
3337abc181SEzequiel Garcia #define RK3399_GRF_SOC_CON24		0x6260
3437abc181SEzequiel Garcia #define RK3399_GRF_SOC_CON25		0x6264
3537abc181SEzequiel Garcia #define RK3399_GRF_SOC_STATUS1		0xe2a4
3637abc181SEzequiel Garcia 
3737abc181SEzequiel Garcia #define CLOCK_LANE_HS_RX_CONTROL	0x34
3837abc181SEzequiel Garcia #define LANE0_HS_RX_CONTROL		0x44
3937abc181SEzequiel Garcia #define LANE1_HS_RX_CONTROL		0x54
4037abc181SEzequiel Garcia #define LANE2_HS_RX_CONTROL		0x84
4137abc181SEzequiel Garcia #define LANE3_HS_RX_CONTROL		0x94
4237abc181SEzequiel Garcia #define LANES_THS_SETTLE_CONTROL	0x75
4337abc181SEzequiel Garcia #define THS_SETTLE_COUNTER_THRESHOLD	0x04
4437abc181SEzequiel Garcia 
4537abc181SEzequiel Garcia struct hsfreq_range {
4637abc181SEzequiel Garcia 	u16 range_h;
4737abc181SEzequiel Garcia 	u8 cfg_bit;
4837abc181SEzequiel Garcia };
4937abc181SEzequiel Garcia 
5037abc181SEzequiel Garcia static const struct hsfreq_range rk3399_mipidphy_hsfreq_ranges[] = {
5137abc181SEzequiel Garcia 	{   89, 0x00 }, {   99, 0x10 }, {  109, 0x20 }, {  129, 0x01 },
5237abc181SEzequiel Garcia 	{  139, 0x11 }, {  149, 0x21 }, {  169, 0x02 }, {  179, 0x12 },
5337abc181SEzequiel Garcia 	{  199, 0x22 }, {  219, 0x03 }, {  239, 0x13 }, {  249, 0x23 },
5437abc181SEzequiel Garcia 	{  269, 0x04 }, {  299, 0x14 }, {  329, 0x05 }, {  359, 0x15 },
5537abc181SEzequiel Garcia 	{  399, 0x25 }, {  449, 0x06 }, {  499, 0x16 }, {  549, 0x07 },
5637abc181SEzequiel Garcia 	{  599, 0x17 }, {  649, 0x08 }, {  699, 0x18 }, {  749, 0x09 },
5737abc181SEzequiel Garcia 	{  799, 0x19 }, {  849, 0x29 }, {  899, 0x39 }, {  949, 0x0a },
5837abc181SEzequiel Garcia 	{  999, 0x1a }, { 1049, 0x2a }, { 1099, 0x3a }, { 1149, 0x0b },
5937abc181SEzequiel Garcia 	{ 1199, 0x1b }, { 1249, 0x2b }, { 1299, 0x3b }, { 1349, 0x0c },
6037abc181SEzequiel Garcia 	{ 1399, 0x1c }, { 1449, 0x2c }, { 1500, 0x3c }
6137abc181SEzequiel Garcia };
6237abc181SEzequiel Garcia 
6337abc181SEzequiel Garcia static const char * const rk3399_mipidphy_clks[] = {
6437abc181SEzequiel Garcia 	"dphy-ref",
6537abc181SEzequiel Garcia 	"dphy-cfg",
6637abc181SEzequiel Garcia 	"grf",
6737abc181SEzequiel Garcia };
6837abc181SEzequiel Garcia 
6937abc181SEzequiel Garcia enum dphy_reg_id {
7037abc181SEzequiel Garcia 	GRF_DPHY_RX0_TURNDISABLE = 0,
7137abc181SEzequiel Garcia 	GRF_DPHY_RX0_FORCERXMODE,
7237abc181SEzequiel Garcia 	GRF_DPHY_RX0_FORCETXSTOPMODE,
7337abc181SEzequiel Garcia 	GRF_DPHY_RX0_ENABLE,
7437abc181SEzequiel Garcia 	GRF_DPHY_RX0_TESTCLR,
7537abc181SEzequiel Garcia 	GRF_DPHY_RX0_TESTCLK,
7637abc181SEzequiel Garcia 	GRF_DPHY_RX0_TESTEN,
7737abc181SEzequiel Garcia 	GRF_DPHY_RX0_TESTDIN,
7837abc181SEzequiel Garcia 	GRF_DPHY_RX0_TURNREQUEST,
7937abc181SEzequiel Garcia 	GRF_DPHY_RX0_TESTDOUT,
8037abc181SEzequiel Garcia 	GRF_DPHY_TX0_TURNDISABLE,
8137abc181SEzequiel Garcia 	GRF_DPHY_TX0_FORCERXMODE,
8237abc181SEzequiel Garcia 	GRF_DPHY_TX0_FORCETXSTOPMODE,
8337abc181SEzequiel Garcia 	GRF_DPHY_TX0_TURNREQUEST,
8437abc181SEzequiel Garcia 	GRF_DPHY_TX1RX1_TURNDISABLE,
8537abc181SEzequiel Garcia 	GRF_DPHY_TX1RX1_FORCERXMODE,
8637abc181SEzequiel Garcia 	GRF_DPHY_TX1RX1_FORCETXSTOPMODE,
8737abc181SEzequiel Garcia 	GRF_DPHY_TX1RX1_ENABLE,
8837abc181SEzequiel Garcia 	GRF_DPHY_TX1RX1_MASTERSLAVEZ,
8937abc181SEzequiel Garcia 	GRF_DPHY_TX1RX1_BASEDIR,
9037abc181SEzequiel Garcia 	GRF_DPHY_TX1RX1_ENABLECLK,
9137abc181SEzequiel Garcia 	GRF_DPHY_TX1RX1_TURNREQUEST,
9237abc181SEzequiel Garcia 	GRF_DPHY_RX1_SRC_SEL,
9337abc181SEzequiel Garcia 	/* rk3288 only */
9437abc181SEzequiel Garcia 	GRF_CON_DISABLE_ISP,
9537abc181SEzequiel Garcia 	GRF_CON_ISP_DPHY_SEL,
9637abc181SEzequiel Garcia 	GRF_DSI_CSI_TESTBUS_SEL,
9737abc181SEzequiel Garcia 	GRF_DVP_V18SEL,
9837abc181SEzequiel Garcia 	/* below is for rk3399 only */
9937abc181SEzequiel Garcia 	GRF_DPHY_RX0_CLK_INV_SEL,
10037abc181SEzequiel Garcia 	GRF_DPHY_RX1_CLK_INV_SEL,
10137abc181SEzequiel Garcia };
10237abc181SEzequiel Garcia 
10337abc181SEzequiel Garcia struct dphy_reg {
10437abc181SEzequiel Garcia 	u16 offset;
10537abc181SEzequiel Garcia 	u8 mask;
10637abc181SEzequiel Garcia 	u8 shift;
10737abc181SEzequiel Garcia };
10837abc181SEzequiel Garcia 
10937abc181SEzequiel Garcia #define PHY_REG(_offset, _width, _shift) \
11037abc181SEzequiel Garcia 	{ .offset = _offset, .mask = BIT(_width) - 1, .shift = _shift, }
11137abc181SEzequiel Garcia 
11237abc181SEzequiel Garcia static const struct dphy_reg rk3399_grf_dphy_regs[] = {
11337abc181SEzequiel Garcia 	[GRF_DPHY_RX0_TURNREQUEST] = PHY_REG(RK3399_GRF_SOC_CON9, 4, 0),
11437abc181SEzequiel Garcia 	[GRF_DPHY_RX0_CLK_INV_SEL] = PHY_REG(RK3399_GRF_SOC_CON9, 1, 10),
11537abc181SEzequiel Garcia 	[GRF_DPHY_RX1_CLK_INV_SEL] = PHY_REG(RK3399_GRF_SOC_CON9, 1, 11),
11637abc181SEzequiel Garcia 	[GRF_DPHY_RX0_ENABLE] = PHY_REG(RK3399_GRF_SOC_CON21, 4, 0),
11737abc181SEzequiel Garcia 	[GRF_DPHY_RX0_FORCERXMODE] = PHY_REG(RK3399_GRF_SOC_CON21, 4, 4),
11837abc181SEzequiel Garcia 	[GRF_DPHY_RX0_FORCETXSTOPMODE] = PHY_REG(RK3399_GRF_SOC_CON21, 4, 8),
11937abc181SEzequiel Garcia 	[GRF_DPHY_RX0_TURNDISABLE] = PHY_REG(RK3399_GRF_SOC_CON21, 4, 12),
12037abc181SEzequiel Garcia 	[GRF_DPHY_TX0_FORCERXMODE] = PHY_REG(RK3399_GRF_SOC_CON22, 4, 0),
12137abc181SEzequiel Garcia 	[GRF_DPHY_TX0_FORCETXSTOPMODE] = PHY_REG(RK3399_GRF_SOC_CON22, 4, 4),
12237abc181SEzequiel Garcia 	[GRF_DPHY_TX0_TURNDISABLE] = PHY_REG(RK3399_GRF_SOC_CON22, 4, 8),
12337abc181SEzequiel Garcia 	[GRF_DPHY_TX0_TURNREQUEST] = PHY_REG(RK3399_GRF_SOC_CON22, 4, 12),
12437abc181SEzequiel Garcia 	[GRF_DPHY_TX1RX1_ENABLE] = PHY_REG(RK3399_GRF_SOC_CON23, 4, 0),
12537abc181SEzequiel Garcia 	[GRF_DPHY_TX1RX1_FORCERXMODE] = PHY_REG(RK3399_GRF_SOC_CON23, 4, 4),
12637abc181SEzequiel Garcia 	[GRF_DPHY_TX1RX1_FORCETXSTOPMODE] = PHY_REG(RK3399_GRF_SOC_CON23, 4, 8),
12737abc181SEzequiel Garcia 	[GRF_DPHY_TX1RX1_TURNDISABLE] = PHY_REG(RK3399_GRF_SOC_CON23, 4, 12),
12837abc181SEzequiel Garcia 	[GRF_DPHY_TX1RX1_TURNREQUEST] = PHY_REG(RK3399_GRF_SOC_CON24, 4, 0),
12937abc181SEzequiel Garcia 	[GRF_DPHY_RX1_SRC_SEL] = PHY_REG(RK3399_GRF_SOC_CON24, 1, 4),
13037abc181SEzequiel Garcia 	[GRF_DPHY_TX1RX1_BASEDIR] = PHY_REG(RK3399_GRF_SOC_CON24, 1, 5),
13137abc181SEzequiel Garcia 	[GRF_DPHY_TX1RX1_ENABLECLK] = PHY_REG(RK3399_GRF_SOC_CON24, 1, 6),
13237abc181SEzequiel Garcia 	[GRF_DPHY_TX1RX1_MASTERSLAVEZ] = PHY_REG(RK3399_GRF_SOC_CON24, 1, 7),
13337abc181SEzequiel Garcia 	[GRF_DPHY_RX0_TESTDIN] = PHY_REG(RK3399_GRF_SOC_CON25, 8, 0),
13437abc181SEzequiel Garcia 	[GRF_DPHY_RX0_TESTEN] = PHY_REG(RK3399_GRF_SOC_CON25, 1, 8),
13537abc181SEzequiel Garcia 	[GRF_DPHY_RX0_TESTCLK] = PHY_REG(RK3399_GRF_SOC_CON25, 1, 9),
13637abc181SEzequiel Garcia 	[GRF_DPHY_RX0_TESTCLR] = PHY_REG(RK3399_GRF_SOC_CON25, 1, 10),
13737abc181SEzequiel Garcia 	[GRF_DPHY_RX0_TESTDOUT] = PHY_REG(RK3399_GRF_SOC_STATUS1, 8, 0),
13837abc181SEzequiel Garcia };
13937abc181SEzequiel Garcia 
14037abc181SEzequiel Garcia struct rk_dphy_drv_data {
14137abc181SEzequiel Garcia 	const char * const *clks;
14237abc181SEzequiel Garcia 	unsigned int num_clks;
14337abc181SEzequiel Garcia 	const struct hsfreq_range *hsfreq_ranges;
14437abc181SEzequiel Garcia 	unsigned int num_hsfreq_ranges;
14537abc181SEzequiel Garcia 	const struct dphy_reg *regs;
14637abc181SEzequiel Garcia };
14737abc181SEzequiel Garcia 
14837abc181SEzequiel Garcia struct rk_dphy {
14937abc181SEzequiel Garcia 	struct device *dev;
15037abc181SEzequiel Garcia 	struct regmap *grf;
15137abc181SEzequiel Garcia 	struct clk_bulk_data *clks;
15237abc181SEzequiel Garcia 
15337abc181SEzequiel Garcia 	const struct rk_dphy_drv_data *drv_data;
15437abc181SEzequiel Garcia 	struct phy_configure_opts_mipi_dphy config;
15537abc181SEzequiel Garcia 
15637abc181SEzequiel Garcia 	u8 hsfreq;
15737abc181SEzequiel Garcia };
15837abc181SEzequiel Garcia 
rk_dphy_write_grf(struct rk_dphy * priv,unsigned int index,u8 value)15937abc181SEzequiel Garcia static inline void rk_dphy_write_grf(struct rk_dphy *priv,
16037abc181SEzequiel Garcia 				     unsigned int index, u8 value)
16137abc181SEzequiel Garcia {
16237abc181SEzequiel Garcia 	const struct dphy_reg *reg = &priv->drv_data->regs[index];
16337abc181SEzequiel Garcia 	/* Update high word */
16437abc181SEzequiel Garcia 	unsigned int val = (value << reg->shift) |
16537abc181SEzequiel Garcia 			   (reg->mask << (reg->shift + 16));
16637abc181SEzequiel Garcia 
16737abc181SEzequiel Garcia 	if (WARN_ON(!reg->offset))
16837abc181SEzequiel Garcia 		return;
16937abc181SEzequiel Garcia 	regmap_write(priv->grf, reg->offset, val);
17037abc181SEzequiel Garcia }
17137abc181SEzequiel Garcia 
rk_dphy_write(struct rk_dphy * priv,u8 test_code,u8 test_data)17237abc181SEzequiel Garcia static void rk_dphy_write(struct rk_dphy *priv, u8 test_code, u8 test_data)
17337abc181SEzequiel Garcia {
17437abc181SEzequiel Garcia 	rk_dphy_write_grf(priv, GRF_DPHY_RX0_TESTDIN, test_code);
17537abc181SEzequiel Garcia 	rk_dphy_write_grf(priv, GRF_DPHY_RX0_TESTEN, 1);
17637abc181SEzequiel Garcia 	/*
17737abc181SEzequiel Garcia 	 * With the falling edge on TESTCLK, the TESTDIN[7:0] signal content
17837abc181SEzequiel Garcia 	 * is latched internally as the current test code. Test data is
17937abc181SEzequiel Garcia 	 * programmed internally by rising edge on TESTCLK.
18037abc181SEzequiel Garcia 	 * This code assumes that TESTCLK is already 1.
18137abc181SEzequiel Garcia 	 */
18237abc181SEzequiel Garcia 	rk_dphy_write_grf(priv, GRF_DPHY_RX0_TESTCLK, 0);
18337abc181SEzequiel Garcia 	rk_dphy_write_grf(priv, GRF_DPHY_RX0_TESTEN, 0);
18437abc181SEzequiel Garcia 	rk_dphy_write_grf(priv, GRF_DPHY_RX0_TESTDIN, test_data);
18537abc181SEzequiel Garcia 	rk_dphy_write_grf(priv, GRF_DPHY_RX0_TESTCLK, 1);
18637abc181SEzequiel Garcia }
18737abc181SEzequiel Garcia 
rk_dphy_enable(struct rk_dphy * priv)18837abc181SEzequiel Garcia static void rk_dphy_enable(struct rk_dphy *priv)
18937abc181SEzequiel Garcia {
19037abc181SEzequiel Garcia 	rk_dphy_write_grf(priv, GRF_DPHY_RX0_FORCERXMODE, 0);
19137abc181SEzequiel Garcia 	rk_dphy_write_grf(priv, GRF_DPHY_RX0_FORCETXSTOPMODE, 0);
19237abc181SEzequiel Garcia 
19337abc181SEzequiel Garcia 	/* Disable lane turn around, which is ignored in receive mode */
19437abc181SEzequiel Garcia 	rk_dphy_write_grf(priv, GRF_DPHY_RX0_TURNREQUEST, 0);
19537abc181SEzequiel Garcia 	rk_dphy_write_grf(priv, GRF_DPHY_RX0_TURNDISABLE, 0xf);
19637abc181SEzequiel Garcia 
19737abc181SEzequiel Garcia 	rk_dphy_write_grf(priv, GRF_DPHY_RX0_ENABLE,
19837abc181SEzequiel Garcia 			  GENMASK(priv->config.lanes - 1, 0));
19937abc181SEzequiel Garcia 
20037abc181SEzequiel Garcia 	/* dphy start */
20137abc181SEzequiel Garcia 	rk_dphy_write_grf(priv, GRF_DPHY_RX0_TESTCLK, 1);
20237abc181SEzequiel Garcia 	rk_dphy_write_grf(priv, GRF_DPHY_RX0_TESTCLR, 1);
20337abc181SEzequiel Garcia 	usleep_range(100, 150);
20437abc181SEzequiel Garcia 	rk_dphy_write_grf(priv, GRF_DPHY_RX0_TESTCLR, 0);
20537abc181SEzequiel Garcia 	usleep_range(100, 150);
20637abc181SEzequiel Garcia 
20737abc181SEzequiel Garcia 	/* set clock lane */
20837abc181SEzequiel Garcia 	/* HS hsfreq_range & lane 0  settle bypass */
20937abc181SEzequiel Garcia 	rk_dphy_write(priv, CLOCK_LANE_HS_RX_CONTROL, 0);
21037abc181SEzequiel Garcia 	/* HS RX Control of lane0 */
21137abc181SEzequiel Garcia 	rk_dphy_write(priv, LANE0_HS_RX_CONTROL, priv->hsfreq << 1);
21237abc181SEzequiel Garcia 	/* HS RX Control of lane1 */
21337abc181SEzequiel Garcia 	rk_dphy_write(priv, LANE1_HS_RX_CONTROL, priv->hsfreq << 1);
21437abc181SEzequiel Garcia 	/* HS RX Control of lane2 */
21537abc181SEzequiel Garcia 	rk_dphy_write(priv, LANE2_HS_RX_CONTROL, priv->hsfreq << 1);
21637abc181SEzequiel Garcia 	/* HS RX Control of lane3 */
21737abc181SEzequiel Garcia 	rk_dphy_write(priv, LANE3_HS_RX_CONTROL, priv->hsfreq << 1);
21837abc181SEzequiel Garcia 	/* HS RX Data Lanes Settle State Time Control */
21937abc181SEzequiel Garcia 	rk_dphy_write(priv, LANES_THS_SETTLE_CONTROL,
22037abc181SEzequiel Garcia 		      THS_SETTLE_COUNTER_THRESHOLD);
22137abc181SEzequiel Garcia 
22237abc181SEzequiel Garcia 	/* Normal operation */
22337abc181SEzequiel Garcia 	rk_dphy_write(priv, 0x0, 0);
22437abc181SEzequiel Garcia }
22537abc181SEzequiel Garcia 
rk_dphy_configure(struct phy * phy,union phy_configure_opts * opts)22637abc181SEzequiel Garcia static int rk_dphy_configure(struct phy *phy, union phy_configure_opts *opts)
22737abc181SEzequiel Garcia {
22837abc181SEzequiel Garcia 	struct rk_dphy *priv = phy_get_drvdata(phy);
22937abc181SEzequiel Garcia 	const struct rk_dphy_drv_data *drv_data = priv->drv_data;
23037abc181SEzequiel Garcia 	struct phy_configure_opts_mipi_dphy *config = &opts->mipi_dphy;
23137abc181SEzequiel Garcia 	unsigned int hsfreq = 0;
23237abc181SEzequiel Garcia 	unsigned int i;
23337abc181SEzequiel Garcia 	u64 data_rate_mbps;
23437abc181SEzequiel Garcia 	int ret;
23537abc181SEzequiel Garcia 
23637abc181SEzequiel Garcia 	/* pass with phy_mipi_dphy_get_default_config (with pixel rate?) */
23737abc181SEzequiel Garcia 	ret = phy_mipi_dphy_config_validate(config);
23837abc181SEzequiel Garcia 	if (ret)
23937abc181SEzequiel Garcia 		return ret;
24037abc181SEzequiel Garcia 
24137abc181SEzequiel Garcia 	data_rate_mbps = div_u64(config->hs_clk_rate, 1000 * 1000);
24237abc181SEzequiel Garcia 
24337abc181SEzequiel Garcia 	dev_dbg(priv->dev, "lanes %d - data_rate_mbps %llu\n",
24437abc181SEzequiel Garcia 		config->lanes, data_rate_mbps);
24537abc181SEzequiel Garcia 	for (i = 0; i < drv_data->num_hsfreq_ranges; i++) {
24637abc181SEzequiel Garcia 		if (drv_data->hsfreq_ranges[i].range_h >= data_rate_mbps) {
24737abc181SEzequiel Garcia 			hsfreq = drv_data->hsfreq_ranges[i].cfg_bit;
24837abc181SEzequiel Garcia 			break;
24937abc181SEzequiel Garcia 		}
25037abc181SEzequiel Garcia 	}
25137abc181SEzequiel Garcia 	if (!hsfreq)
25237abc181SEzequiel Garcia 		return -EINVAL;
25337abc181SEzequiel Garcia 
25437abc181SEzequiel Garcia 	priv->hsfreq = hsfreq;
25537abc181SEzequiel Garcia 	priv->config = *config;
25637abc181SEzequiel Garcia 	return 0;
25737abc181SEzequiel Garcia }
25837abc181SEzequiel Garcia 
rk_dphy_power_on(struct phy * phy)25937abc181SEzequiel Garcia static int rk_dphy_power_on(struct phy *phy)
26037abc181SEzequiel Garcia {
26137abc181SEzequiel Garcia 	struct rk_dphy *priv = phy_get_drvdata(phy);
26237abc181SEzequiel Garcia 	int ret;
26337abc181SEzequiel Garcia 
26437abc181SEzequiel Garcia 	ret = clk_bulk_enable(priv->drv_data->num_clks, priv->clks);
26537abc181SEzequiel Garcia 	if (ret)
26637abc181SEzequiel Garcia 		return ret;
26737abc181SEzequiel Garcia 
26837abc181SEzequiel Garcia 	rk_dphy_enable(priv);
26937abc181SEzequiel Garcia 
27037abc181SEzequiel Garcia 	return 0;
27137abc181SEzequiel Garcia }
27237abc181SEzequiel Garcia 
rk_dphy_power_off(struct phy * phy)27337abc181SEzequiel Garcia static int rk_dphy_power_off(struct phy *phy)
27437abc181SEzequiel Garcia {
27537abc181SEzequiel Garcia 	struct rk_dphy *priv = phy_get_drvdata(phy);
27637abc181SEzequiel Garcia 
27737abc181SEzequiel Garcia 	rk_dphy_write_grf(priv, GRF_DPHY_RX0_ENABLE, 0);
27837abc181SEzequiel Garcia 	clk_bulk_disable(priv->drv_data->num_clks, priv->clks);
27937abc181SEzequiel Garcia 	return 0;
28037abc181SEzequiel Garcia }
28137abc181SEzequiel Garcia 
rk_dphy_init(struct phy * phy)28237abc181SEzequiel Garcia static int rk_dphy_init(struct phy *phy)
28337abc181SEzequiel Garcia {
28437abc181SEzequiel Garcia 	struct rk_dphy *priv = phy_get_drvdata(phy);
28537abc181SEzequiel Garcia 
28637abc181SEzequiel Garcia 	return clk_bulk_prepare(priv->drv_data->num_clks, priv->clks);
28737abc181SEzequiel Garcia }
28837abc181SEzequiel Garcia 
rk_dphy_exit(struct phy * phy)28937abc181SEzequiel Garcia static int rk_dphy_exit(struct phy *phy)
29037abc181SEzequiel Garcia {
29137abc181SEzequiel Garcia 	struct rk_dphy *priv = phy_get_drvdata(phy);
29237abc181SEzequiel Garcia 
29337abc181SEzequiel Garcia 	clk_bulk_unprepare(priv->drv_data->num_clks, priv->clks);
29437abc181SEzequiel Garcia 	return 0;
29537abc181SEzequiel Garcia }
29637abc181SEzequiel Garcia 
29737abc181SEzequiel Garcia static const struct phy_ops rk_dphy_ops = {
29837abc181SEzequiel Garcia 	.power_on	= rk_dphy_power_on,
29937abc181SEzequiel Garcia 	.power_off	= rk_dphy_power_off,
30037abc181SEzequiel Garcia 	.init		= rk_dphy_init,
30137abc181SEzequiel Garcia 	.exit		= rk_dphy_exit,
30237abc181SEzequiel Garcia 	.configure	= rk_dphy_configure,
30337abc181SEzequiel Garcia 	.owner		= THIS_MODULE,
30437abc181SEzequiel Garcia };
30537abc181SEzequiel Garcia 
30637abc181SEzequiel Garcia static const struct rk_dphy_drv_data rk3399_mipidphy_drv_data = {
30737abc181SEzequiel Garcia 	.clks = rk3399_mipidphy_clks,
30837abc181SEzequiel Garcia 	.num_clks = ARRAY_SIZE(rk3399_mipidphy_clks),
30937abc181SEzequiel Garcia 	.hsfreq_ranges = rk3399_mipidphy_hsfreq_ranges,
31037abc181SEzequiel Garcia 	.num_hsfreq_ranges = ARRAY_SIZE(rk3399_mipidphy_hsfreq_ranges),
31137abc181SEzequiel Garcia 	.regs = rk3399_grf_dphy_regs,
31237abc181SEzequiel Garcia };
31337abc181SEzequiel Garcia 
31437abc181SEzequiel Garcia static const struct of_device_id rk_dphy_dt_ids[] = {
31537abc181SEzequiel Garcia 	{
31637abc181SEzequiel Garcia 		.compatible = "rockchip,rk3399-mipi-dphy-rx0",
31737abc181SEzequiel Garcia 		.data = &rk3399_mipidphy_drv_data,
31837abc181SEzequiel Garcia 	},
31937abc181SEzequiel Garcia 	{}
32037abc181SEzequiel Garcia };
32137abc181SEzequiel Garcia MODULE_DEVICE_TABLE(of, rk_dphy_dt_ids);
32237abc181SEzequiel Garcia 
rk_dphy_probe(struct platform_device * pdev)32337abc181SEzequiel Garcia static int rk_dphy_probe(struct platform_device *pdev)
32437abc181SEzequiel Garcia {
32537abc181SEzequiel Garcia 	struct device *dev = &pdev->dev;
32637abc181SEzequiel Garcia 	struct device_node *np = dev->of_node;
32737abc181SEzequiel Garcia 	const struct rk_dphy_drv_data *drv_data;
32837abc181SEzequiel Garcia 	struct phy_provider *phy_provider;
32937abc181SEzequiel Garcia 	struct rk_dphy *priv;
33037abc181SEzequiel Garcia 	struct phy *phy;
33137abc181SEzequiel Garcia 	unsigned int i;
33237abc181SEzequiel Garcia 	int ret;
33337abc181SEzequiel Garcia 
33437abc181SEzequiel Garcia 	if (!dev->parent || !dev->parent->of_node)
33537abc181SEzequiel Garcia 		return -ENODEV;
33637abc181SEzequiel Garcia 
33737abc181SEzequiel Garcia 	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
33837abc181SEzequiel Garcia 	if (!priv)
33937abc181SEzequiel Garcia 		return -ENOMEM;
34037abc181SEzequiel Garcia 	priv->dev = dev;
34137abc181SEzequiel Garcia 
34237abc181SEzequiel Garcia 	priv->grf = syscon_node_to_regmap(dev->parent->of_node);
34337abc181SEzequiel Garcia 	if (IS_ERR(priv->grf)) {
34437abc181SEzequiel Garcia 		dev_err(dev, "Can't find GRF syscon\n");
34537abc181SEzequiel Garcia 		return -ENODEV;
34637abc181SEzequiel Garcia 	}
34737abc181SEzequiel Garcia 
348*3eb836dfSMinghao Chi (CGEL ZTE) 	drv_data = of_device_get_match_data(dev);
34937abc181SEzequiel Garcia 	priv->drv_data = drv_data;
35037abc181SEzequiel Garcia 	priv->clks = devm_kcalloc(&pdev->dev, drv_data->num_clks,
35137abc181SEzequiel Garcia 				  sizeof(*priv->clks), GFP_KERNEL);
35237abc181SEzequiel Garcia 	if (!priv->clks)
35337abc181SEzequiel Garcia 		return -ENOMEM;
35437abc181SEzequiel Garcia 	for (i = 0; i < drv_data->num_clks; i++)
35537abc181SEzequiel Garcia 		priv->clks[i].id = drv_data->clks[i];
35637abc181SEzequiel Garcia 	ret = devm_clk_bulk_get(&pdev->dev, drv_data->num_clks, priv->clks);
35737abc181SEzequiel Garcia 	if (ret)
35837abc181SEzequiel Garcia 		return ret;
35937abc181SEzequiel Garcia 
36037abc181SEzequiel Garcia 	phy = devm_phy_create(dev, np, &rk_dphy_ops);
36137abc181SEzequiel Garcia 	if (IS_ERR(phy)) {
36237abc181SEzequiel Garcia 		dev_err(dev, "failed to create phy\n");
36337abc181SEzequiel Garcia 		return PTR_ERR(phy);
36437abc181SEzequiel Garcia 	}
36537abc181SEzequiel Garcia 	phy_set_drvdata(phy, priv);
36637abc181SEzequiel Garcia 
36737abc181SEzequiel Garcia 	phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
36837abc181SEzequiel Garcia 
36937abc181SEzequiel Garcia 	return PTR_ERR_OR_ZERO(phy_provider);
37037abc181SEzequiel Garcia }
37137abc181SEzequiel Garcia 
37237abc181SEzequiel Garcia static struct platform_driver rk_dphy_driver = {
37337abc181SEzequiel Garcia 	.probe = rk_dphy_probe,
37437abc181SEzequiel Garcia 	.driver = {
37537abc181SEzequiel Garcia 		.name	= "rockchip-mipi-dphy-rx0",
37637abc181SEzequiel Garcia 		.of_match_table = rk_dphy_dt_ids,
37737abc181SEzequiel Garcia 	},
37837abc181SEzequiel Garcia };
37937abc181SEzequiel Garcia module_platform_driver(rk_dphy_driver);
38037abc181SEzequiel Garcia 
38137abc181SEzequiel Garcia MODULE_AUTHOR("Ezequiel Garcia <ezequiel@collabora.com>");
38237abc181SEzequiel Garcia MODULE_DESCRIPTION("Rockchip MIPI Synopsys DPHY RX0 driver");
38337abc181SEzequiel Garcia MODULE_LICENSE("Dual MIT/GPL");
384