18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Copyright (c) 2016 Allwinnertech Co., Ltd.
48c2ecf20Sopenharmony_ci * Copyright (C) 2017-2018 Bootlin
58c2ecf20Sopenharmony_ci *
68c2ecf20Sopenharmony_ci * Maxime Ripard <maxime.ripard@free-electrons.com>
78c2ecf20Sopenharmony_ci */
88c2ecf20Sopenharmony_ci
98c2ecf20Sopenharmony_ci#include <linux/bitops.h>
108c2ecf20Sopenharmony_ci#include <linux/clk.h>
118c2ecf20Sopenharmony_ci#include <linux/module.h>
128c2ecf20Sopenharmony_ci#include <linux/of_address.h>
138c2ecf20Sopenharmony_ci#include <linux/platform_device.h>
148c2ecf20Sopenharmony_ci#include <linux/regmap.h>
158c2ecf20Sopenharmony_ci#include <linux/reset.h>
168c2ecf20Sopenharmony_ci
178c2ecf20Sopenharmony_ci#include <linux/phy/phy.h>
188c2ecf20Sopenharmony_ci#include <linux/phy/phy-mipi-dphy.h>
198c2ecf20Sopenharmony_ci
208c2ecf20Sopenharmony_ci#define SUN6I_DPHY_GCTL_REG		0x00
218c2ecf20Sopenharmony_ci#define SUN6I_DPHY_GCTL_LANE_NUM(n)		((((n) - 1) & 3) << 4)
228c2ecf20Sopenharmony_ci#define SUN6I_DPHY_GCTL_EN			BIT(0)
238c2ecf20Sopenharmony_ci
248c2ecf20Sopenharmony_ci#define SUN6I_DPHY_TX_CTL_REG		0x04
258c2ecf20Sopenharmony_ci#define SUN6I_DPHY_TX_CTL_HS_TX_CLK_CONT	BIT(28)
268c2ecf20Sopenharmony_ci
278c2ecf20Sopenharmony_ci#define SUN6I_DPHY_TX_TIME0_REG		0x10
288c2ecf20Sopenharmony_ci#define SUN6I_DPHY_TX_TIME0_HS_TRAIL(n)		(((n) & 0xff) << 24)
298c2ecf20Sopenharmony_ci#define SUN6I_DPHY_TX_TIME0_HS_PREPARE(n)	(((n) & 0xff) << 16)
308c2ecf20Sopenharmony_ci#define SUN6I_DPHY_TX_TIME0_LP_CLK_DIV(n)	((n) & 0xff)
318c2ecf20Sopenharmony_ci
328c2ecf20Sopenharmony_ci#define SUN6I_DPHY_TX_TIME1_REG		0x14
338c2ecf20Sopenharmony_ci#define SUN6I_DPHY_TX_TIME1_CLK_POST(n)		(((n) & 0xff) << 24)
348c2ecf20Sopenharmony_ci#define SUN6I_DPHY_TX_TIME1_CLK_PRE(n)		(((n) & 0xff) << 16)
358c2ecf20Sopenharmony_ci#define SUN6I_DPHY_TX_TIME1_CLK_ZERO(n)		(((n) & 0xff) << 8)
368c2ecf20Sopenharmony_ci#define SUN6I_DPHY_TX_TIME1_CLK_PREPARE(n)	((n) & 0xff)
378c2ecf20Sopenharmony_ci
388c2ecf20Sopenharmony_ci#define SUN6I_DPHY_TX_TIME2_REG		0x18
398c2ecf20Sopenharmony_ci#define SUN6I_DPHY_TX_TIME2_CLK_TRAIL(n)	((n) & 0xff)
408c2ecf20Sopenharmony_ci
418c2ecf20Sopenharmony_ci#define SUN6I_DPHY_TX_TIME3_REG		0x1c
428c2ecf20Sopenharmony_ci
438c2ecf20Sopenharmony_ci#define SUN6I_DPHY_TX_TIME4_REG		0x20
448c2ecf20Sopenharmony_ci#define SUN6I_DPHY_TX_TIME4_HS_TX_ANA1(n)	(((n) & 0xff) << 8)
458c2ecf20Sopenharmony_ci#define SUN6I_DPHY_TX_TIME4_HS_TX_ANA0(n)	((n) & 0xff)
468c2ecf20Sopenharmony_ci
478c2ecf20Sopenharmony_ci#define SUN6I_DPHY_ANA0_REG		0x4c
488c2ecf20Sopenharmony_ci#define SUN6I_DPHY_ANA0_REG_PWS			BIT(31)
498c2ecf20Sopenharmony_ci#define SUN6I_DPHY_ANA0_REG_DMPC		BIT(28)
508c2ecf20Sopenharmony_ci#define SUN6I_DPHY_ANA0_REG_DMPD(n)		(((n) & 0xf) << 24)
518c2ecf20Sopenharmony_ci#define SUN6I_DPHY_ANA0_REG_SLV(n)		(((n) & 7) << 12)
528c2ecf20Sopenharmony_ci#define SUN6I_DPHY_ANA0_REG_DEN(n)		(((n) & 0xf) << 8)
538c2ecf20Sopenharmony_ci
548c2ecf20Sopenharmony_ci#define SUN6I_DPHY_ANA1_REG		0x50
558c2ecf20Sopenharmony_ci#define SUN6I_DPHY_ANA1_REG_VTTMODE		BIT(31)
568c2ecf20Sopenharmony_ci#define SUN6I_DPHY_ANA1_REG_CSMPS(n)		(((n) & 3) << 28)
578c2ecf20Sopenharmony_ci#define SUN6I_DPHY_ANA1_REG_SVTT(n)		(((n) & 0xf) << 24)
588c2ecf20Sopenharmony_ci
598c2ecf20Sopenharmony_ci#define SUN6I_DPHY_ANA2_REG		0x54
608c2ecf20Sopenharmony_ci#define SUN6I_DPHY_ANA2_EN_P2S_CPU(n)		(((n) & 0xf) << 24)
618c2ecf20Sopenharmony_ci#define SUN6I_DPHY_ANA2_EN_P2S_CPU_MASK		GENMASK(27, 24)
628c2ecf20Sopenharmony_ci#define SUN6I_DPHY_ANA2_EN_CK_CPU		BIT(4)
638c2ecf20Sopenharmony_ci#define SUN6I_DPHY_ANA2_REG_ENIB		BIT(1)
648c2ecf20Sopenharmony_ci
658c2ecf20Sopenharmony_ci#define SUN6I_DPHY_ANA3_REG		0x58
668c2ecf20Sopenharmony_ci#define SUN6I_DPHY_ANA3_EN_VTTD(n)		(((n) & 0xf) << 28)
678c2ecf20Sopenharmony_ci#define SUN6I_DPHY_ANA3_EN_VTTD_MASK		GENMASK(31, 28)
688c2ecf20Sopenharmony_ci#define SUN6I_DPHY_ANA3_EN_VTTC			BIT(27)
698c2ecf20Sopenharmony_ci#define SUN6I_DPHY_ANA3_EN_DIV			BIT(26)
708c2ecf20Sopenharmony_ci#define SUN6I_DPHY_ANA3_EN_LDOC			BIT(25)
718c2ecf20Sopenharmony_ci#define SUN6I_DPHY_ANA3_EN_LDOD			BIT(24)
728c2ecf20Sopenharmony_ci#define SUN6I_DPHY_ANA3_EN_LDOR			BIT(18)
738c2ecf20Sopenharmony_ci
748c2ecf20Sopenharmony_ci#define SUN6I_DPHY_ANA4_REG		0x5c
758c2ecf20Sopenharmony_ci#define SUN6I_DPHY_ANA4_REG_DMPLVC		BIT(24)
768c2ecf20Sopenharmony_ci#define SUN6I_DPHY_ANA4_REG_DMPLVD(n)		(((n) & 0xf) << 20)
778c2ecf20Sopenharmony_ci#define SUN6I_DPHY_ANA4_REG_CKDV(n)		(((n) & 0x1f) << 12)
788c2ecf20Sopenharmony_ci#define SUN6I_DPHY_ANA4_REG_TMSC(n)		(((n) & 3) << 10)
798c2ecf20Sopenharmony_ci#define SUN6I_DPHY_ANA4_REG_TMSD(n)		(((n) & 3) << 8)
808c2ecf20Sopenharmony_ci#define SUN6I_DPHY_ANA4_REG_TXDNSC(n)		(((n) & 3) << 6)
818c2ecf20Sopenharmony_ci#define SUN6I_DPHY_ANA4_REG_TXDNSD(n)		(((n) & 3) << 4)
828c2ecf20Sopenharmony_ci#define SUN6I_DPHY_ANA4_REG_TXPUSC(n)		(((n) & 3) << 2)
838c2ecf20Sopenharmony_ci#define SUN6I_DPHY_ANA4_REG_TXPUSD(n)		((n) & 3)
848c2ecf20Sopenharmony_ci
858c2ecf20Sopenharmony_ci#define SUN6I_DPHY_DBG5_REG		0xf4
868c2ecf20Sopenharmony_ci
878c2ecf20Sopenharmony_cistruct sun6i_dphy {
888c2ecf20Sopenharmony_ci	struct clk				*bus_clk;
898c2ecf20Sopenharmony_ci	struct clk				*mod_clk;
908c2ecf20Sopenharmony_ci	struct regmap				*regs;
918c2ecf20Sopenharmony_ci	struct reset_control			*reset;
928c2ecf20Sopenharmony_ci
938c2ecf20Sopenharmony_ci	struct phy				*phy;
948c2ecf20Sopenharmony_ci	struct phy_configure_opts_mipi_dphy	config;
958c2ecf20Sopenharmony_ci};
968c2ecf20Sopenharmony_ci
978c2ecf20Sopenharmony_cistatic int sun6i_dphy_init(struct phy *phy)
988c2ecf20Sopenharmony_ci{
998c2ecf20Sopenharmony_ci	struct sun6i_dphy *dphy = phy_get_drvdata(phy);
1008c2ecf20Sopenharmony_ci
1018c2ecf20Sopenharmony_ci	reset_control_deassert(dphy->reset);
1028c2ecf20Sopenharmony_ci	clk_prepare_enable(dphy->mod_clk);
1038c2ecf20Sopenharmony_ci	clk_set_rate_exclusive(dphy->mod_clk, 150000000);
1048c2ecf20Sopenharmony_ci
1058c2ecf20Sopenharmony_ci	return 0;
1068c2ecf20Sopenharmony_ci}
1078c2ecf20Sopenharmony_ci
1088c2ecf20Sopenharmony_cistatic int sun6i_dphy_configure(struct phy *phy, union phy_configure_opts *opts)
1098c2ecf20Sopenharmony_ci{
1108c2ecf20Sopenharmony_ci	struct sun6i_dphy *dphy = phy_get_drvdata(phy);
1118c2ecf20Sopenharmony_ci	int ret;
1128c2ecf20Sopenharmony_ci
1138c2ecf20Sopenharmony_ci	ret = phy_mipi_dphy_config_validate(&opts->mipi_dphy);
1148c2ecf20Sopenharmony_ci	if (ret)
1158c2ecf20Sopenharmony_ci		return ret;
1168c2ecf20Sopenharmony_ci
1178c2ecf20Sopenharmony_ci	memcpy(&dphy->config, opts, sizeof(dphy->config));
1188c2ecf20Sopenharmony_ci
1198c2ecf20Sopenharmony_ci	return 0;
1208c2ecf20Sopenharmony_ci}
1218c2ecf20Sopenharmony_ci
1228c2ecf20Sopenharmony_cistatic int sun6i_dphy_power_on(struct phy *phy)
1238c2ecf20Sopenharmony_ci{
1248c2ecf20Sopenharmony_ci	struct sun6i_dphy *dphy = phy_get_drvdata(phy);
1258c2ecf20Sopenharmony_ci	u8 lanes_mask = GENMASK(dphy->config.lanes - 1, 0);
1268c2ecf20Sopenharmony_ci
1278c2ecf20Sopenharmony_ci	regmap_write(dphy->regs, SUN6I_DPHY_TX_CTL_REG,
1288c2ecf20Sopenharmony_ci		     SUN6I_DPHY_TX_CTL_HS_TX_CLK_CONT);
1298c2ecf20Sopenharmony_ci
1308c2ecf20Sopenharmony_ci	regmap_write(dphy->regs, SUN6I_DPHY_TX_TIME0_REG,
1318c2ecf20Sopenharmony_ci		     SUN6I_DPHY_TX_TIME0_LP_CLK_DIV(14) |
1328c2ecf20Sopenharmony_ci		     SUN6I_DPHY_TX_TIME0_HS_PREPARE(6) |
1338c2ecf20Sopenharmony_ci		     SUN6I_DPHY_TX_TIME0_HS_TRAIL(10));
1348c2ecf20Sopenharmony_ci
1358c2ecf20Sopenharmony_ci	regmap_write(dphy->regs, SUN6I_DPHY_TX_TIME1_REG,
1368c2ecf20Sopenharmony_ci		     SUN6I_DPHY_TX_TIME1_CLK_PREPARE(7) |
1378c2ecf20Sopenharmony_ci		     SUN6I_DPHY_TX_TIME1_CLK_ZERO(50) |
1388c2ecf20Sopenharmony_ci		     SUN6I_DPHY_TX_TIME1_CLK_PRE(3) |
1398c2ecf20Sopenharmony_ci		     SUN6I_DPHY_TX_TIME1_CLK_POST(10));
1408c2ecf20Sopenharmony_ci
1418c2ecf20Sopenharmony_ci	regmap_write(dphy->regs, SUN6I_DPHY_TX_TIME2_REG,
1428c2ecf20Sopenharmony_ci		     SUN6I_DPHY_TX_TIME2_CLK_TRAIL(30));
1438c2ecf20Sopenharmony_ci
1448c2ecf20Sopenharmony_ci	regmap_write(dphy->regs, SUN6I_DPHY_TX_TIME3_REG, 0);
1458c2ecf20Sopenharmony_ci
1468c2ecf20Sopenharmony_ci	regmap_write(dphy->regs, SUN6I_DPHY_TX_TIME4_REG,
1478c2ecf20Sopenharmony_ci		     SUN6I_DPHY_TX_TIME4_HS_TX_ANA0(3) |
1488c2ecf20Sopenharmony_ci		     SUN6I_DPHY_TX_TIME4_HS_TX_ANA1(3));
1498c2ecf20Sopenharmony_ci
1508c2ecf20Sopenharmony_ci	regmap_write(dphy->regs, SUN6I_DPHY_GCTL_REG,
1518c2ecf20Sopenharmony_ci		     SUN6I_DPHY_GCTL_LANE_NUM(dphy->config.lanes) |
1528c2ecf20Sopenharmony_ci		     SUN6I_DPHY_GCTL_EN);
1538c2ecf20Sopenharmony_ci
1548c2ecf20Sopenharmony_ci	regmap_write(dphy->regs, SUN6I_DPHY_ANA0_REG,
1558c2ecf20Sopenharmony_ci		     SUN6I_DPHY_ANA0_REG_PWS |
1568c2ecf20Sopenharmony_ci		     SUN6I_DPHY_ANA0_REG_DMPC |
1578c2ecf20Sopenharmony_ci		     SUN6I_DPHY_ANA0_REG_SLV(7) |
1588c2ecf20Sopenharmony_ci		     SUN6I_DPHY_ANA0_REG_DMPD(lanes_mask) |
1598c2ecf20Sopenharmony_ci		     SUN6I_DPHY_ANA0_REG_DEN(lanes_mask));
1608c2ecf20Sopenharmony_ci
1618c2ecf20Sopenharmony_ci	regmap_write(dphy->regs, SUN6I_DPHY_ANA1_REG,
1628c2ecf20Sopenharmony_ci		     SUN6I_DPHY_ANA1_REG_CSMPS(1) |
1638c2ecf20Sopenharmony_ci		     SUN6I_DPHY_ANA1_REG_SVTT(7));
1648c2ecf20Sopenharmony_ci
1658c2ecf20Sopenharmony_ci	regmap_write(dphy->regs, SUN6I_DPHY_ANA4_REG,
1668c2ecf20Sopenharmony_ci		     SUN6I_DPHY_ANA4_REG_CKDV(1) |
1678c2ecf20Sopenharmony_ci		     SUN6I_DPHY_ANA4_REG_TMSC(1) |
1688c2ecf20Sopenharmony_ci		     SUN6I_DPHY_ANA4_REG_TMSD(1) |
1698c2ecf20Sopenharmony_ci		     SUN6I_DPHY_ANA4_REG_TXDNSC(1) |
1708c2ecf20Sopenharmony_ci		     SUN6I_DPHY_ANA4_REG_TXDNSD(1) |
1718c2ecf20Sopenharmony_ci		     SUN6I_DPHY_ANA4_REG_TXPUSC(1) |
1728c2ecf20Sopenharmony_ci		     SUN6I_DPHY_ANA4_REG_TXPUSD(1) |
1738c2ecf20Sopenharmony_ci		     SUN6I_DPHY_ANA4_REG_DMPLVC |
1748c2ecf20Sopenharmony_ci		     SUN6I_DPHY_ANA4_REG_DMPLVD(lanes_mask));
1758c2ecf20Sopenharmony_ci
1768c2ecf20Sopenharmony_ci	regmap_write(dphy->regs, SUN6I_DPHY_ANA2_REG,
1778c2ecf20Sopenharmony_ci		     SUN6I_DPHY_ANA2_REG_ENIB);
1788c2ecf20Sopenharmony_ci	udelay(5);
1798c2ecf20Sopenharmony_ci
1808c2ecf20Sopenharmony_ci	regmap_write(dphy->regs, SUN6I_DPHY_ANA3_REG,
1818c2ecf20Sopenharmony_ci		     SUN6I_DPHY_ANA3_EN_LDOR |
1828c2ecf20Sopenharmony_ci		     SUN6I_DPHY_ANA3_EN_LDOC |
1838c2ecf20Sopenharmony_ci		     SUN6I_DPHY_ANA3_EN_LDOD);
1848c2ecf20Sopenharmony_ci	udelay(1);
1858c2ecf20Sopenharmony_ci
1868c2ecf20Sopenharmony_ci	regmap_update_bits(dphy->regs, SUN6I_DPHY_ANA3_REG,
1878c2ecf20Sopenharmony_ci			   SUN6I_DPHY_ANA3_EN_VTTC |
1888c2ecf20Sopenharmony_ci			   SUN6I_DPHY_ANA3_EN_VTTD_MASK,
1898c2ecf20Sopenharmony_ci			   SUN6I_DPHY_ANA3_EN_VTTC |
1908c2ecf20Sopenharmony_ci			   SUN6I_DPHY_ANA3_EN_VTTD(lanes_mask));
1918c2ecf20Sopenharmony_ci	udelay(1);
1928c2ecf20Sopenharmony_ci
1938c2ecf20Sopenharmony_ci	regmap_update_bits(dphy->regs, SUN6I_DPHY_ANA3_REG,
1948c2ecf20Sopenharmony_ci			   SUN6I_DPHY_ANA3_EN_DIV,
1958c2ecf20Sopenharmony_ci			   SUN6I_DPHY_ANA3_EN_DIV);
1968c2ecf20Sopenharmony_ci	udelay(1);
1978c2ecf20Sopenharmony_ci
1988c2ecf20Sopenharmony_ci	regmap_update_bits(dphy->regs, SUN6I_DPHY_ANA2_REG,
1998c2ecf20Sopenharmony_ci			   SUN6I_DPHY_ANA2_EN_CK_CPU,
2008c2ecf20Sopenharmony_ci			   SUN6I_DPHY_ANA2_EN_CK_CPU);
2018c2ecf20Sopenharmony_ci	udelay(1);
2028c2ecf20Sopenharmony_ci
2038c2ecf20Sopenharmony_ci	regmap_update_bits(dphy->regs, SUN6I_DPHY_ANA1_REG,
2048c2ecf20Sopenharmony_ci			   SUN6I_DPHY_ANA1_REG_VTTMODE,
2058c2ecf20Sopenharmony_ci			   SUN6I_DPHY_ANA1_REG_VTTMODE);
2068c2ecf20Sopenharmony_ci
2078c2ecf20Sopenharmony_ci	regmap_update_bits(dphy->regs, SUN6I_DPHY_ANA2_REG,
2088c2ecf20Sopenharmony_ci			   SUN6I_DPHY_ANA2_EN_P2S_CPU_MASK,
2098c2ecf20Sopenharmony_ci			   SUN6I_DPHY_ANA2_EN_P2S_CPU(lanes_mask));
2108c2ecf20Sopenharmony_ci
2118c2ecf20Sopenharmony_ci	return 0;
2128c2ecf20Sopenharmony_ci}
2138c2ecf20Sopenharmony_ci
2148c2ecf20Sopenharmony_cistatic int sun6i_dphy_power_off(struct phy *phy)
2158c2ecf20Sopenharmony_ci{
2168c2ecf20Sopenharmony_ci	struct sun6i_dphy *dphy = phy_get_drvdata(phy);
2178c2ecf20Sopenharmony_ci
2188c2ecf20Sopenharmony_ci	regmap_update_bits(dphy->regs, SUN6I_DPHY_ANA1_REG,
2198c2ecf20Sopenharmony_ci			   SUN6I_DPHY_ANA1_REG_VTTMODE, 0);
2208c2ecf20Sopenharmony_ci
2218c2ecf20Sopenharmony_ci	return 0;
2228c2ecf20Sopenharmony_ci}
2238c2ecf20Sopenharmony_ci
2248c2ecf20Sopenharmony_cistatic int sun6i_dphy_exit(struct phy *phy)
2258c2ecf20Sopenharmony_ci{
2268c2ecf20Sopenharmony_ci	struct sun6i_dphy *dphy = phy_get_drvdata(phy);
2278c2ecf20Sopenharmony_ci
2288c2ecf20Sopenharmony_ci	clk_rate_exclusive_put(dphy->mod_clk);
2298c2ecf20Sopenharmony_ci	clk_disable_unprepare(dphy->mod_clk);
2308c2ecf20Sopenharmony_ci	reset_control_assert(dphy->reset);
2318c2ecf20Sopenharmony_ci
2328c2ecf20Sopenharmony_ci	return 0;
2338c2ecf20Sopenharmony_ci}
2348c2ecf20Sopenharmony_ci
2358c2ecf20Sopenharmony_ci
2368c2ecf20Sopenharmony_cistatic const struct phy_ops sun6i_dphy_ops = {
2378c2ecf20Sopenharmony_ci	.configure	= sun6i_dphy_configure,
2388c2ecf20Sopenharmony_ci	.power_on	= sun6i_dphy_power_on,
2398c2ecf20Sopenharmony_ci	.power_off	= sun6i_dphy_power_off,
2408c2ecf20Sopenharmony_ci	.init		= sun6i_dphy_init,
2418c2ecf20Sopenharmony_ci	.exit		= sun6i_dphy_exit,
2428c2ecf20Sopenharmony_ci};
2438c2ecf20Sopenharmony_ci
2448c2ecf20Sopenharmony_cistatic const struct regmap_config sun6i_dphy_regmap_config = {
2458c2ecf20Sopenharmony_ci	.reg_bits	= 32,
2468c2ecf20Sopenharmony_ci	.val_bits	= 32,
2478c2ecf20Sopenharmony_ci	.reg_stride	= 4,
2488c2ecf20Sopenharmony_ci	.max_register	= SUN6I_DPHY_DBG5_REG,
2498c2ecf20Sopenharmony_ci	.name		= "mipi-dphy",
2508c2ecf20Sopenharmony_ci};
2518c2ecf20Sopenharmony_ci
2528c2ecf20Sopenharmony_cistatic int sun6i_dphy_probe(struct platform_device *pdev)
2538c2ecf20Sopenharmony_ci{
2548c2ecf20Sopenharmony_ci	struct phy_provider *phy_provider;
2558c2ecf20Sopenharmony_ci	struct sun6i_dphy *dphy;
2568c2ecf20Sopenharmony_ci	struct resource *res;
2578c2ecf20Sopenharmony_ci	void __iomem *regs;
2588c2ecf20Sopenharmony_ci
2598c2ecf20Sopenharmony_ci	dphy = devm_kzalloc(&pdev->dev, sizeof(*dphy), GFP_KERNEL);
2608c2ecf20Sopenharmony_ci	if (!dphy)
2618c2ecf20Sopenharmony_ci		return -ENOMEM;
2628c2ecf20Sopenharmony_ci
2638c2ecf20Sopenharmony_ci	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
2648c2ecf20Sopenharmony_ci	regs = devm_ioremap_resource(&pdev->dev, res);
2658c2ecf20Sopenharmony_ci	if (IS_ERR(regs)) {
2668c2ecf20Sopenharmony_ci		dev_err(&pdev->dev, "Couldn't map the DPHY encoder registers\n");
2678c2ecf20Sopenharmony_ci		return PTR_ERR(regs);
2688c2ecf20Sopenharmony_ci	}
2698c2ecf20Sopenharmony_ci
2708c2ecf20Sopenharmony_ci	dphy->regs = devm_regmap_init_mmio_clk(&pdev->dev, "bus",
2718c2ecf20Sopenharmony_ci					       regs, &sun6i_dphy_regmap_config);
2728c2ecf20Sopenharmony_ci	if (IS_ERR(dphy->regs)) {
2738c2ecf20Sopenharmony_ci		dev_err(&pdev->dev, "Couldn't create the DPHY encoder regmap\n");
2748c2ecf20Sopenharmony_ci		return PTR_ERR(dphy->regs);
2758c2ecf20Sopenharmony_ci	}
2768c2ecf20Sopenharmony_ci
2778c2ecf20Sopenharmony_ci	dphy->reset = devm_reset_control_get_shared(&pdev->dev, NULL);
2788c2ecf20Sopenharmony_ci	if (IS_ERR(dphy->reset)) {
2798c2ecf20Sopenharmony_ci		dev_err(&pdev->dev, "Couldn't get our reset line\n");
2808c2ecf20Sopenharmony_ci		return PTR_ERR(dphy->reset);
2818c2ecf20Sopenharmony_ci	}
2828c2ecf20Sopenharmony_ci
2838c2ecf20Sopenharmony_ci	dphy->mod_clk = devm_clk_get(&pdev->dev, "mod");
2848c2ecf20Sopenharmony_ci	if (IS_ERR(dphy->mod_clk)) {
2858c2ecf20Sopenharmony_ci		dev_err(&pdev->dev, "Couldn't get the DPHY mod clock\n");
2868c2ecf20Sopenharmony_ci		return PTR_ERR(dphy->mod_clk);
2878c2ecf20Sopenharmony_ci	}
2888c2ecf20Sopenharmony_ci
2898c2ecf20Sopenharmony_ci	dphy->phy = devm_phy_create(&pdev->dev, NULL, &sun6i_dphy_ops);
2908c2ecf20Sopenharmony_ci	if (IS_ERR(dphy->phy)) {
2918c2ecf20Sopenharmony_ci		dev_err(&pdev->dev, "failed to create PHY\n");
2928c2ecf20Sopenharmony_ci		return PTR_ERR(dphy->phy);
2938c2ecf20Sopenharmony_ci	}
2948c2ecf20Sopenharmony_ci
2958c2ecf20Sopenharmony_ci	phy_set_drvdata(dphy->phy, dphy);
2968c2ecf20Sopenharmony_ci	phy_provider = devm_of_phy_provider_register(&pdev->dev, of_phy_simple_xlate);
2978c2ecf20Sopenharmony_ci
2988c2ecf20Sopenharmony_ci	return PTR_ERR_OR_ZERO(phy_provider);
2998c2ecf20Sopenharmony_ci}
3008c2ecf20Sopenharmony_ci
3018c2ecf20Sopenharmony_cistatic const struct of_device_id sun6i_dphy_of_table[] = {
3028c2ecf20Sopenharmony_ci	{ .compatible = "allwinner,sun6i-a31-mipi-dphy" },
3038c2ecf20Sopenharmony_ci	{ }
3048c2ecf20Sopenharmony_ci};
3058c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, sun6i_dphy_of_table);
3068c2ecf20Sopenharmony_ci
3078c2ecf20Sopenharmony_cistatic struct platform_driver sun6i_dphy_platform_driver = {
3088c2ecf20Sopenharmony_ci	.probe		= sun6i_dphy_probe,
3098c2ecf20Sopenharmony_ci	.driver		= {
3108c2ecf20Sopenharmony_ci		.name		= "sun6i-mipi-dphy",
3118c2ecf20Sopenharmony_ci		.of_match_table	= sun6i_dphy_of_table,
3128c2ecf20Sopenharmony_ci	},
3138c2ecf20Sopenharmony_ci};
3148c2ecf20Sopenharmony_cimodule_platform_driver(sun6i_dphy_platform_driver);
3158c2ecf20Sopenharmony_ci
3168c2ecf20Sopenharmony_ciMODULE_AUTHOR("Maxime Ripard <maxime.ripard@bootlin>");
3178c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Allwinner A31 MIPI D-PHY Driver");
3188c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL");
319