xref: /linux/drivers/phy/socionext/phy-uniphier-usb3hs.c (revision 03ab8e6297acd1bc0eedaa050e2a1635c576fd11)
15ab43d0fSKunihiko Hayashi // SPDX-License-Identifier: GPL-2.0
25ab43d0fSKunihiko Hayashi /*
35ab43d0fSKunihiko Hayashi  * phy-uniphier-usb3hs.c - HS-PHY driver for Socionext UniPhier USB3 controller
45ab43d0fSKunihiko Hayashi  * Copyright 2015-2018 Socionext Inc.
55ab43d0fSKunihiko Hayashi  * Author:
65ab43d0fSKunihiko Hayashi  *      Kunihiko Hayashi <hayashi.kunihiko@socionext.com>
75ab43d0fSKunihiko Hayashi  * Contributors:
85ab43d0fSKunihiko Hayashi  *      Motoya Tanigawa <tanigawa.motoya@socionext.com>
95ab43d0fSKunihiko Hayashi  *      Masami Hiramatsu <masami.hiramatsu@linaro.org>
105ab43d0fSKunihiko Hayashi  */
115ab43d0fSKunihiko Hayashi 
125ab43d0fSKunihiko Hayashi #include <linux/bitfield.h>
135ab43d0fSKunihiko Hayashi #include <linux/bitops.h>
145ab43d0fSKunihiko Hayashi #include <linux/clk.h>
155ab43d0fSKunihiko Hayashi #include <linux/io.h>
165ab43d0fSKunihiko Hayashi #include <linux/module.h>
175ab43d0fSKunihiko Hayashi #include <linux/nvmem-consumer.h>
185ab43d0fSKunihiko Hayashi #include <linux/of.h>
195ab43d0fSKunihiko Hayashi #include <linux/of_platform.h>
205ab43d0fSKunihiko Hayashi #include <linux/phy/phy.h>
215ab43d0fSKunihiko Hayashi #include <linux/platform_device.h>
225ab43d0fSKunihiko Hayashi #include <linux/regulator/consumer.h>
235ab43d0fSKunihiko Hayashi #include <linux/reset.h>
245ab43d0fSKunihiko Hayashi #include <linux/slab.h>
255ab43d0fSKunihiko Hayashi 
265ab43d0fSKunihiko Hayashi #define HSPHY_CFG0		0x0
275ab43d0fSKunihiko Hayashi #define HSPHY_CFG0_HS_I_MASK	GENMASK(31, 28)
285ab43d0fSKunihiko Hayashi #define HSPHY_CFG0_HSDISC_MASK	GENMASK(27, 26)
295ab43d0fSKunihiko Hayashi #define HSPHY_CFG0_SWING_MASK	GENMASK(17, 16)
305ab43d0fSKunihiko Hayashi #define HSPHY_CFG0_SEL_T_MASK	GENMASK(15, 12)
315ab43d0fSKunihiko Hayashi #define HSPHY_CFG0_RTERM_MASK	GENMASK(7, 6)
325ab43d0fSKunihiko Hayashi #define HSPHY_CFG0_TRIMMASK	(HSPHY_CFG0_HS_I_MASK \
335ab43d0fSKunihiko Hayashi 				 | HSPHY_CFG0_SEL_T_MASK \
345ab43d0fSKunihiko Hayashi 				 | HSPHY_CFG0_RTERM_MASK)
355ab43d0fSKunihiko Hayashi 
365ab43d0fSKunihiko Hayashi #define HSPHY_CFG1		0x4
375ab43d0fSKunihiko Hayashi #define HSPHY_CFG1_DAT_EN	BIT(29)
385ab43d0fSKunihiko Hayashi #define HSPHY_CFG1_ADR_EN	BIT(28)
395ab43d0fSKunihiko Hayashi #define HSPHY_CFG1_ADR_MASK	GENMASK(27, 16)
405ab43d0fSKunihiko Hayashi #define HSPHY_CFG1_DAT_MASK	GENMASK(23, 16)
415ab43d0fSKunihiko Hayashi 
425ab43d0fSKunihiko Hayashi #define PHY_F(regno, msb, lsb) { (regno), (msb), (lsb) }
435ab43d0fSKunihiko Hayashi 
4425858c52SKunihiko Hayashi #define RX_CHK_SYNC	PHY_F(0, 5, 5)	/* RX sync mode */
4525858c52SKunihiko Hayashi #define RX_SYNC_SEL	PHY_F(1, 1, 0)	/* RX sync length */
465ab43d0fSKunihiko Hayashi #define LS_SLEW		PHY_F(10, 6, 6)	/* LS mode slew rate */
475ab43d0fSKunihiko Hayashi #define FS_LS_DRV	PHY_F(10, 5, 5)	/* FS/LS slew rate */
485ab43d0fSKunihiko Hayashi 
4925858c52SKunihiko Hayashi #define MAX_PHY_PARAMS	4
505ab43d0fSKunihiko Hayashi 
515ab43d0fSKunihiko Hayashi struct uniphier_u3hsphy_param {
525ab43d0fSKunihiko Hayashi 	struct {
535ab43d0fSKunihiko Hayashi 		int reg_no;
545ab43d0fSKunihiko Hayashi 		int msb;
555ab43d0fSKunihiko Hayashi 		int lsb;
565ab43d0fSKunihiko Hayashi 	} field;
575ab43d0fSKunihiko Hayashi 	u8 value;
585ab43d0fSKunihiko Hayashi };
595ab43d0fSKunihiko Hayashi 
605ab43d0fSKunihiko Hayashi struct uniphier_u3hsphy_trim_param {
615ab43d0fSKunihiko Hayashi 	unsigned int rterm;
625ab43d0fSKunihiko Hayashi 	unsigned int sel_t;
635ab43d0fSKunihiko Hayashi 	unsigned int hs_i;
645ab43d0fSKunihiko Hayashi };
655ab43d0fSKunihiko Hayashi 
665ab43d0fSKunihiko Hayashi #define trim_param_is_valid(p)	((p)->rterm || (p)->sel_t || (p)->hs_i)
675ab43d0fSKunihiko Hayashi 
685ab43d0fSKunihiko Hayashi struct uniphier_u3hsphy_priv {
695ab43d0fSKunihiko Hayashi 	struct device *dev;
705ab43d0fSKunihiko Hayashi 	void __iomem *base;
71e68c2a8aSKunihiko Hayashi 	struct clk *clk, *clk_parent, *clk_ext, *clk_parent_gio;
72e68c2a8aSKunihiko Hayashi 	struct reset_control *rst, *rst_parent, *rst_parent_gio;
735ab43d0fSKunihiko Hayashi 	struct regulator *vbus;
745ab43d0fSKunihiko Hayashi 	const struct uniphier_u3hsphy_soc_data *data;
755ab43d0fSKunihiko Hayashi };
765ab43d0fSKunihiko Hayashi 
775ab43d0fSKunihiko Hayashi struct uniphier_u3hsphy_soc_data {
78e68c2a8aSKunihiko Hayashi 	bool is_legacy;
795ab43d0fSKunihiko Hayashi 	int nparams;
805ab43d0fSKunihiko Hayashi 	const struct uniphier_u3hsphy_param param[MAX_PHY_PARAMS];
815ab43d0fSKunihiko Hayashi 	u32 config0;
825ab43d0fSKunihiko Hayashi 	u32 config1;
835ab43d0fSKunihiko Hayashi 	void (*trim_func)(struct uniphier_u3hsphy_priv *priv, u32 *pconfig,
845ab43d0fSKunihiko Hayashi 			  struct uniphier_u3hsphy_trim_param *pt);
855ab43d0fSKunihiko Hayashi };
865ab43d0fSKunihiko Hayashi 
uniphier_u3hsphy_trim_ld20(struct uniphier_u3hsphy_priv * priv,u32 * pconfig,struct uniphier_u3hsphy_trim_param * pt)875ab43d0fSKunihiko Hayashi static void uniphier_u3hsphy_trim_ld20(struct uniphier_u3hsphy_priv *priv,
885ab43d0fSKunihiko Hayashi 				       u32 *pconfig,
895ab43d0fSKunihiko Hayashi 				       struct uniphier_u3hsphy_trim_param *pt)
905ab43d0fSKunihiko Hayashi {
915ab43d0fSKunihiko Hayashi 	*pconfig &= ~HSPHY_CFG0_RTERM_MASK;
925ab43d0fSKunihiko Hayashi 	*pconfig |= FIELD_PREP(HSPHY_CFG0_RTERM_MASK, pt->rterm);
935ab43d0fSKunihiko Hayashi 
945ab43d0fSKunihiko Hayashi 	*pconfig &= ~HSPHY_CFG0_SEL_T_MASK;
955ab43d0fSKunihiko Hayashi 	*pconfig |= FIELD_PREP(HSPHY_CFG0_SEL_T_MASK, pt->sel_t);
965ab43d0fSKunihiko Hayashi 
975ab43d0fSKunihiko Hayashi 	*pconfig &= ~HSPHY_CFG0_HS_I_MASK;
985ab43d0fSKunihiko Hayashi 	*pconfig |= FIELD_PREP(HSPHY_CFG0_HS_I_MASK,  pt->hs_i);
995ab43d0fSKunihiko Hayashi }
1005ab43d0fSKunihiko Hayashi 
uniphier_u3hsphy_get_nvparam(struct uniphier_u3hsphy_priv * priv,const char * name,unsigned int * val)1015ab43d0fSKunihiko Hayashi static int uniphier_u3hsphy_get_nvparam(struct uniphier_u3hsphy_priv *priv,
1025ab43d0fSKunihiko Hayashi 					const char *name, unsigned int *val)
1035ab43d0fSKunihiko Hayashi {
1045ab43d0fSKunihiko Hayashi 	struct nvmem_cell *cell;
1055ab43d0fSKunihiko Hayashi 	u8 *buf;
1065ab43d0fSKunihiko Hayashi 
1075ab43d0fSKunihiko Hayashi 	cell = devm_nvmem_cell_get(priv->dev, name);
1085ab43d0fSKunihiko Hayashi 	if (IS_ERR(cell))
1095ab43d0fSKunihiko Hayashi 		return PTR_ERR(cell);
1105ab43d0fSKunihiko Hayashi 
1115ab43d0fSKunihiko Hayashi 	buf = nvmem_cell_read(cell, NULL);
1125ab43d0fSKunihiko Hayashi 	if (IS_ERR(buf))
1135ab43d0fSKunihiko Hayashi 		return PTR_ERR(buf);
1145ab43d0fSKunihiko Hayashi 
1155ab43d0fSKunihiko Hayashi 	*val = *buf;
1165ab43d0fSKunihiko Hayashi 
1175ab43d0fSKunihiko Hayashi 	kfree(buf);
1185ab43d0fSKunihiko Hayashi 
1195ab43d0fSKunihiko Hayashi 	return 0;
1205ab43d0fSKunihiko Hayashi }
1215ab43d0fSKunihiko Hayashi 
uniphier_u3hsphy_get_nvparams(struct uniphier_u3hsphy_priv * priv,struct uniphier_u3hsphy_trim_param * pt)1225ab43d0fSKunihiko Hayashi static int uniphier_u3hsphy_get_nvparams(struct uniphier_u3hsphy_priv *priv,
1235ab43d0fSKunihiko Hayashi 					 struct uniphier_u3hsphy_trim_param *pt)
1245ab43d0fSKunihiko Hayashi {
1255ab43d0fSKunihiko Hayashi 	int ret;
1265ab43d0fSKunihiko Hayashi 
1275ab43d0fSKunihiko Hayashi 	ret = uniphier_u3hsphy_get_nvparam(priv, "rterm", &pt->rterm);
1285ab43d0fSKunihiko Hayashi 	if (ret)
1295ab43d0fSKunihiko Hayashi 		return ret;
1305ab43d0fSKunihiko Hayashi 
1315ab43d0fSKunihiko Hayashi 	ret = uniphier_u3hsphy_get_nvparam(priv, "sel_t", &pt->sel_t);
1325ab43d0fSKunihiko Hayashi 	if (ret)
1335ab43d0fSKunihiko Hayashi 		return ret;
1345ab43d0fSKunihiko Hayashi 
1355ab43d0fSKunihiko Hayashi 	ret = uniphier_u3hsphy_get_nvparam(priv, "hs_i", &pt->hs_i);
1365ab43d0fSKunihiko Hayashi 	if (ret)
1375ab43d0fSKunihiko Hayashi 		return ret;
1385ab43d0fSKunihiko Hayashi 
1395ab43d0fSKunihiko Hayashi 	return 0;
1405ab43d0fSKunihiko Hayashi }
1415ab43d0fSKunihiko Hayashi 
uniphier_u3hsphy_update_config(struct uniphier_u3hsphy_priv * priv,u32 * pconfig)1425ab43d0fSKunihiko Hayashi static int uniphier_u3hsphy_update_config(struct uniphier_u3hsphy_priv *priv,
1435ab43d0fSKunihiko Hayashi 					  u32 *pconfig)
1445ab43d0fSKunihiko Hayashi {
1455ab43d0fSKunihiko Hayashi 	struct uniphier_u3hsphy_trim_param trim;
1465ab43d0fSKunihiko Hayashi 	int ret, trimmed = 0;
1475ab43d0fSKunihiko Hayashi 
1485ab43d0fSKunihiko Hayashi 	if (priv->data->trim_func) {
1495ab43d0fSKunihiko Hayashi 		ret = uniphier_u3hsphy_get_nvparams(priv, &trim);
1505ab43d0fSKunihiko Hayashi 		if (ret == -EPROBE_DEFER)
1515ab43d0fSKunihiko Hayashi 			return ret;
1525ab43d0fSKunihiko Hayashi 
1535ab43d0fSKunihiko Hayashi 		/*
1545ab43d0fSKunihiko Hayashi 		 * call trim_func only when trimming parameters that aren't
1555ab43d0fSKunihiko Hayashi 		 * all-zero can be acquired. All-zero parameters mean nothing
1565ab43d0fSKunihiko Hayashi 		 * has been written to nvmem.
1575ab43d0fSKunihiko Hayashi 		 */
1585ab43d0fSKunihiko Hayashi 		if (!ret && trim_param_is_valid(&trim)) {
1595ab43d0fSKunihiko Hayashi 			priv->data->trim_func(priv, pconfig, &trim);
1605ab43d0fSKunihiko Hayashi 			trimmed = 1;
1615ab43d0fSKunihiko Hayashi 		} else {
1625ab43d0fSKunihiko Hayashi 			dev_dbg(priv->dev, "can't get parameter from nvmem\n");
1635ab43d0fSKunihiko Hayashi 		}
1645ab43d0fSKunihiko Hayashi 	}
1655ab43d0fSKunihiko Hayashi 
1665ab43d0fSKunihiko Hayashi 	/* use default parameters without trimming values */
1675ab43d0fSKunihiko Hayashi 	if (!trimmed) {
1685ab43d0fSKunihiko Hayashi 		*pconfig &= ~HSPHY_CFG0_HSDISC_MASK;
1695ab43d0fSKunihiko Hayashi 		*pconfig |= FIELD_PREP(HSPHY_CFG0_HSDISC_MASK, 3);
1705ab43d0fSKunihiko Hayashi 	}
1715ab43d0fSKunihiko Hayashi 
1725ab43d0fSKunihiko Hayashi 	return 0;
1735ab43d0fSKunihiko Hayashi }
1745ab43d0fSKunihiko Hayashi 
uniphier_u3hsphy_set_param(struct uniphier_u3hsphy_priv * priv,const struct uniphier_u3hsphy_param * p)1755ab43d0fSKunihiko Hayashi static void uniphier_u3hsphy_set_param(struct uniphier_u3hsphy_priv *priv,
1765ab43d0fSKunihiko Hayashi 				       const struct uniphier_u3hsphy_param *p)
1775ab43d0fSKunihiko Hayashi {
1785ab43d0fSKunihiko Hayashi 	u32 val;
1795ab43d0fSKunihiko Hayashi 	u32 field_mask = GENMASK(p->field.msb, p->field.lsb);
1805ab43d0fSKunihiko Hayashi 	u8 data;
1815ab43d0fSKunihiko Hayashi 
1825ab43d0fSKunihiko Hayashi 	val = readl(priv->base + HSPHY_CFG1);
1835ab43d0fSKunihiko Hayashi 	val &= ~HSPHY_CFG1_ADR_MASK;
1845ab43d0fSKunihiko Hayashi 	val |= FIELD_PREP(HSPHY_CFG1_ADR_MASK, p->field.reg_no)
1855ab43d0fSKunihiko Hayashi 		| HSPHY_CFG1_ADR_EN;
1865ab43d0fSKunihiko Hayashi 	writel(val, priv->base + HSPHY_CFG1);
1875ab43d0fSKunihiko Hayashi 
1885ab43d0fSKunihiko Hayashi 	val = readl(priv->base + HSPHY_CFG1);
1895ab43d0fSKunihiko Hayashi 	val &= ~HSPHY_CFG1_ADR_EN;
1905ab43d0fSKunihiko Hayashi 	writel(val, priv->base + HSPHY_CFG1);
1915ab43d0fSKunihiko Hayashi 
1925ab43d0fSKunihiko Hayashi 	val = readl(priv->base + HSPHY_CFG1);
1935ab43d0fSKunihiko Hayashi 	val &= ~FIELD_PREP(HSPHY_CFG1_DAT_MASK, field_mask);
1945ab43d0fSKunihiko Hayashi 	data = field_mask & (p->value << p->field.lsb);
1955ab43d0fSKunihiko Hayashi 	val |=  FIELD_PREP(HSPHY_CFG1_DAT_MASK, data) | HSPHY_CFG1_DAT_EN;
1965ab43d0fSKunihiko Hayashi 	writel(val, priv->base + HSPHY_CFG1);
1975ab43d0fSKunihiko Hayashi 
1985ab43d0fSKunihiko Hayashi 	val = readl(priv->base + HSPHY_CFG1);
1995ab43d0fSKunihiko Hayashi 	val &= ~HSPHY_CFG1_DAT_EN;
2005ab43d0fSKunihiko Hayashi 	writel(val, priv->base + HSPHY_CFG1);
2015ab43d0fSKunihiko Hayashi }
2025ab43d0fSKunihiko Hayashi 
uniphier_u3hsphy_power_on(struct phy * phy)2035ab43d0fSKunihiko Hayashi static int uniphier_u3hsphy_power_on(struct phy *phy)
2045ab43d0fSKunihiko Hayashi {
2055ab43d0fSKunihiko Hayashi 	struct uniphier_u3hsphy_priv *priv = phy_get_drvdata(phy);
2065ab43d0fSKunihiko Hayashi 	int ret;
2075ab43d0fSKunihiko Hayashi 
2085ab43d0fSKunihiko Hayashi 	ret = clk_prepare_enable(priv->clk_ext);
2095ab43d0fSKunihiko Hayashi 	if (ret)
2105ab43d0fSKunihiko Hayashi 		return ret;
2115ab43d0fSKunihiko Hayashi 
2125ab43d0fSKunihiko Hayashi 	ret = clk_prepare_enable(priv->clk);
2135ab43d0fSKunihiko Hayashi 	if (ret)
2145ab43d0fSKunihiko Hayashi 		goto out_clk_ext_disable;
2155ab43d0fSKunihiko Hayashi 
2165ab43d0fSKunihiko Hayashi 	ret = reset_control_deassert(priv->rst);
2175ab43d0fSKunihiko Hayashi 	if (ret)
2185ab43d0fSKunihiko Hayashi 		goto out_clk_disable;
2195ab43d0fSKunihiko Hayashi 
2205ab43d0fSKunihiko Hayashi 	if (priv->vbus) {
2215ab43d0fSKunihiko Hayashi 		ret = regulator_enable(priv->vbus);
2225ab43d0fSKunihiko Hayashi 		if (ret)
2235ab43d0fSKunihiko Hayashi 			goto out_rst_assert;
2245ab43d0fSKunihiko Hayashi 	}
2255ab43d0fSKunihiko Hayashi 
2265ab43d0fSKunihiko Hayashi 	return 0;
2275ab43d0fSKunihiko Hayashi 
2285ab43d0fSKunihiko Hayashi out_rst_assert:
2295ab43d0fSKunihiko Hayashi 	reset_control_assert(priv->rst);
2305ab43d0fSKunihiko Hayashi out_clk_disable:
2315ab43d0fSKunihiko Hayashi 	clk_disable_unprepare(priv->clk);
2325ab43d0fSKunihiko Hayashi out_clk_ext_disable:
2335ab43d0fSKunihiko Hayashi 	clk_disable_unprepare(priv->clk_ext);
2345ab43d0fSKunihiko Hayashi 
2355ab43d0fSKunihiko Hayashi 	return ret;
2365ab43d0fSKunihiko Hayashi }
2375ab43d0fSKunihiko Hayashi 
uniphier_u3hsphy_power_off(struct phy * phy)2385ab43d0fSKunihiko Hayashi static int uniphier_u3hsphy_power_off(struct phy *phy)
2395ab43d0fSKunihiko Hayashi {
2405ab43d0fSKunihiko Hayashi 	struct uniphier_u3hsphy_priv *priv = phy_get_drvdata(phy);
2415ab43d0fSKunihiko Hayashi 
2425ab43d0fSKunihiko Hayashi 	if (priv->vbus)
2435ab43d0fSKunihiko Hayashi 		regulator_disable(priv->vbus);
2445ab43d0fSKunihiko Hayashi 
2455ab43d0fSKunihiko Hayashi 	reset_control_assert(priv->rst);
2465ab43d0fSKunihiko Hayashi 	clk_disable_unprepare(priv->clk);
2475ab43d0fSKunihiko Hayashi 	clk_disable_unprepare(priv->clk_ext);
2485ab43d0fSKunihiko Hayashi 
2495ab43d0fSKunihiko Hayashi 	return 0;
2505ab43d0fSKunihiko Hayashi }
2515ab43d0fSKunihiko Hayashi 
uniphier_u3hsphy_init(struct phy * phy)2525ab43d0fSKunihiko Hayashi static int uniphier_u3hsphy_init(struct phy *phy)
2535ab43d0fSKunihiko Hayashi {
2545ab43d0fSKunihiko Hayashi 	struct uniphier_u3hsphy_priv *priv = phy_get_drvdata(phy);
2555ab43d0fSKunihiko Hayashi 	u32 config0, config1;
2565ab43d0fSKunihiko Hayashi 	int i, ret;
2575ab43d0fSKunihiko Hayashi 
2585ab43d0fSKunihiko Hayashi 	ret = clk_prepare_enable(priv->clk_parent);
2595ab43d0fSKunihiko Hayashi 	if (ret)
2605ab43d0fSKunihiko Hayashi 		return ret;
2615ab43d0fSKunihiko Hayashi 
262e68c2a8aSKunihiko Hayashi 	ret = clk_prepare_enable(priv->clk_parent_gio);
2635ab43d0fSKunihiko Hayashi 	if (ret)
2645ab43d0fSKunihiko Hayashi 		goto out_clk_disable;
2655ab43d0fSKunihiko Hayashi 
266e68c2a8aSKunihiko Hayashi 	ret = reset_control_deassert(priv->rst_parent);
267e68c2a8aSKunihiko Hayashi 	if (ret)
268e68c2a8aSKunihiko Hayashi 		goto out_clk_gio_disable;
269e68c2a8aSKunihiko Hayashi 
270e68c2a8aSKunihiko Hayashi 	ret = reset_control_deassert(priv->rst_parent_gio);
271e68c2a8aSKunihiko Hayashi 	if (ret)
272e68c2a8aSKunihiko Hayashi 		goto out_rst_assert;
273e68c2a8aSKunihiko Hayashi 
274e68c2a8aSKunihiko Hayashi 	if ((priv->data->is_legacy)
275e68c2a8aSKunihiko Hayashi 	    || (!priv->data->config0 && !priv->data->config1))
2765ab43d0fSKunihiko Hayashi 		return 0;
2775ab43d0fSKunihiko Hayashi 
2785ab43d0fSKunihiko Hayashi 	config0 = priv->data->config0;
2795ab43d0fSKunihiko Hayashi 	config1 = priv->data->config1;
2805ab43d0fSKunihiko Hayashi 
2815ab43d0fSKunihiko Hayashi 	ret = uniphier_u3hsphy_update_config(priv, &config0);
2825ab43d0fSKunihiko Hayashi 	if (ret)
2835ab43d0fSKunihiko Hayashi 		goto out_rst_assert;
2845ab43d0fSKunihiko Hayashi 
2855ab43d0fSKunihiko Hayashi 	writel(config0, priv->base + HSPHY_CFG0);
2865ab43d0fSKunihiko Hayashi 	writel(config1, priv->base + HSPHY_CFG1);
2875ab43d0fSKunihiko Hayashi 
2885ab43d0fSKunihiko Hayashi 	for (i = 0; i < priv->data->nparams; i++)
2895ab43d0fSKunihiko Hayashi 		uniphier_u3hsphy_set_param(priv, &priv->data->param[i]);
2905ab43d0fSKunihiko Hayashi 
2915ab43d0fSKunihiko Hayashi 	return 0;
2925ab43d0fSKunihiko Hayashi 
2935ab43d0fSKunihiko Hayashi out_rst_assert:
2945ab43d0fSKunihiko Hayashi 	reset_control_assert(priv->rst_parent);
295e68c2a8aSKunihiko Hayashi out_clk_gio_disable:
296e68c2a8aSKunihiko Hayashi 	clk_disable_unprepare(priv->clk_parent_gio);
2975ab43d0fSKunihiko Hayashi out_clk_disable:
2985ab43d0fSKunihiko Hayashi 	clk_disable_unprepare(priv->clk_parent);
2995ab43d0fSKunihiko Hayashi 
3005ab43d0fSKunihiko Hayashi 	return ret;
3015ab43d0fSKunihiko Hayashi }
3025ab43d0fSKunihiko Hayashi 
uniphier_u3hsphy_exit(struct phy * phy)3035ab43d0fSKunihiko Hayashi static int uniphier_u3hsphy_exit(struct phy *phy)
3045ab43d0fSKunihiko Hayashi {
3055ab43d0fSKunihiko Hayashi 	struct uniphier_u3hsphy_priv *priv = phy_get_drvdata(phy);
3065ab43d0fSKunihiko Hayashi 
307e68c2a8aSKunihiko Hayashi 	reset_control_assert(priv->rst_parent_gio);
3085ab43d0fSKunihiko Hayashi 	reset_control_assert(priv->rst_parent);
309e68c2a8aSKunihiko Hayashi 	clk_disable_unprepare(priv->clk_parent_gio);
3105ab43d0fSKunihiko Hayashi 	clk_disable_unprepare(priv->clk_parent);
3115ab43d0fSKunihiko Hayashi 
3125ab43d0fSKunihiko Hayashi 	return 0;
3135ab43d0fSKunihiko Hayashi }
3145ab43d0fSKunihiko Hayashi 
3155ab43d0fSKunihiko Hayashi static const struct phy_ops uniphier_u3hsphy_ops = {
3165ab43d0fSKunihiko Hayashi 	.init           = uniphier_u3hsphy_init,
3175ab43d0fSKunihiko Hayashi 	.exit           = uniphier_u3hsphy_exit,
3185ab43d0fSKunihiko Hayashi 	.power_on       = uniphier_u3hsphy_power_on,
3195ab43d0fSKunihiko Hayashi 	.power_off      = uniphier_u3hsphy_power_off,
3205ab43d0fSKunihiko Hayashi 	.owner          = THIS_MODULE,
3215ab43d0fSKunihiko Hayashi };
3225ab43d0fSKunihiko Hayashi 
uniphier_u3hsphy_probe(struct platform_device * pdev)3235ab43d0fSKunihiko Hayashi static int uniphier_u3hsphy_probe(struct platform_device *pdev)
3245ab43d0fSKunihiko Hayashi {
3255ab43d0fSKunihiko Hayashi 	struct device *dev = &pdev->dev;
3265ab43d0fSKunihiko Hayashi 	struct uniphier_u3hsphy_priv *priv;
3275ab43d0fSKunihiko Hayashi 	struct phy_provider *phy_provider;
3285ab43d0fSKunihiko Hayashi 	struct phy *phy;
3295ab43d0fSKunihiko Hayashi 
3305ab43d0fSKunihiko Hayashi 	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
3315ab43d0fSKunihiko Hayashi 	if (!priv)
3325ab43d0fSKunihiko Hayashi 		return -ENOMEM;
3335ab43d0fSKunihiko Hayashi 
3345ab43d0fSKunihiko Hayashi 	priv->dev = dev;
3355ab43d0fSKunihiko Hayashi 	priv->data = of_device_get_match_data(dev);
3365ab43d0fSKunihiko Hayashi 	if (WARN_ON(!priv->data ||
3375ab43d0fSKunihiko Hayashi 		    priv->data->nparams > MAX_PHY_PARAMS))
3385ab43d0fSKunihiko Hayashi 		return -EINVAL;
3395ab43d0fSKunihiko Hayashi 
34040d76346SKunihiko Hayashi 	priv->base = devm_platform_ioremap_resource(pdev, 0);
3415ab43d0fSKunihiko Hayashi 	if (IS_ERR(priv->base))
3425ab43d0fSKunihiko Hayashi 		return PTR_ERR(priv->base);
3435ab43d0fSKunihiko Hayashi 
344e68c2a8aSKunihiko Hayashi 	if (!priv->data->is_legacy) {
3455ab43d0fSKunihiko Hayashi 		priv->clk = devm_clk_get(dev, "phy");
3465ab43d0fSKunihiko Hayashi 		if (IS_ERR(priv->clk))
3475ab43d0fSKunihiko Hayashi 			return PTR_ERR(priv->clk);
3485ab43d0fSKunihiko Hayashi 
349752d31a3SChunfeng Yun 		priv->clk_ext = devm_clk_get_optional(dev, "phy-ext");
350752d31a3SChunfeng Yun 		if (IS_ERR(priv->clk_ext))
3515ab43d0fSKunihiko Hayashi 			return PTR_ERR(priv->clk_ext);
3525ab43d0fSKunihiko Hayashi 
3535ab43d0fSKunihiko Hayashi 		priv->rst = devm_reset_control_get_shared(dev, "phy");
3545ab43d0fSKunihiko Hayashi 		if (IS_ERR(priv->rst))
3555ab43d0fSKunihiko Hayashi 			return PTR_ERR(priv->rst);
3565ab43d0fSKunihiko Hayashi 
357e68c2a8aSKunihiko Hayashi 	} else {
358e68c2a8aSKunihiko Hayashi 		priv->clk_parent_gio = devm_clk_get(dev, "gio");
359e68c2a8aSKunihiko Hayashi 		if (IS_ERR(priv->clk_parent_gio))
360e68c2a8aSKunihiko Hayashi 			return PTR_ERR(priv->clk_parent_gio);
361e68c2a8aSKunihiko Hayashi 
362e68c2a8aSKunihiko Hayashi 		priv->rst_parent_gio =
363e68c2a8aSKunihiko Hayashi 			devm_reset_control_get_shared(dev, "gio");
364e68c2a8aSKunihiko Hayashi 		if (IS_ERR(priv->rst_parent_gio))
365e68c2a8aSKunihiko Hayashi 			return PTR_ERR(priv->rst_parent_gio);
366e68c2a8aSKunihiko Hayashi 	}
367e68c2a8aSKunihiko Hayashi 
368e68c2a8aSKunihiko Hayashi 	priv->clk_parent = devm_clk_get(dev, "link");
369e68c2a8aSKunihiko Hayashi 	if (IS_ERR(priv->clk_parent))
370e68c2a8aSKunihiko Hayashi 		return PTR_ERR(priv->clk_parent);
371e68c2a8aSKunihiko Hayashi 
3725ab43d0fSKunihiko Hayashi 	priv->rst_parent = devm_reset_control_get_shared(dev, "link");
3735ab43d0fSKunihiko Hayashi 	if (IS_ERR(priv->rst_parent))
3745ab43d0fSKunihiko Hayashi 		return PTR_ERR(priv->rst_parent);
3755ab43d0fSKunihiko Hayashi 
3765ab43d0fSKunihiko Hayashi 	priv->vbus = devm_regulator_get_optional(dev, "vbus");
3775ab43d0fSKunihiko Hayashi 	if (IS_ERR(priv->vbus)) {
3785ab43d0fSKunihiko Hayashi 		if (PTR_ERR(priv->vbus) == -EPROBE_DEFER)
3795ab43d0fSKunihiko Hayashi 			return PTR_ERR(priv->vbus);
3805ab43d0fSKunihiko Hayashi 		priv->vbus = NULL;
3815ab43d0fSKunihiko Hayashi 	}
3825ab43d0fSKunihiko Hayashi 
3835ab43d0fSKunihiko Hayashi 	phy = devm_phy_create(dev, dev->of_node, &uniphier_u3hsphy_ops);
3845ab43d0fSKunihiko Hayashi 	if (IS_ERR(phy))
3855ab43d0fSKunihiko Hayashi 		return PTR_ERR(phy);
3865ab43d0fSKunihiko Hayashi 
3875ab43d0fSKunihiko Hayashi 	phy_set_drvdata(phy, priv);
3885ab43d0fSKunihiko Hayashi 	phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
3895ab43d0fSKunihiko Hayashi 
3905ab43d0fSKunihiko Hayashi 	return PTR_ERR_OR_ZERO(phy_provider);
3915ab43d0fSKunihiko Hayashi }
3925ab43d0fSKunihiko Hayashi 
393e68c2a8aSKunihiko Hayashi static const struct uniphier_u3hsphy_soc_data uniphier_pro5_data = {
394e68c2a8aSKunihiko Hayashi 	.is_legacy = true,
395e68c2a8aSKunihiko Hayashi 	.nparams = 0,
396e68c2a8aSKunihiko Hayashi };
397e68c2a8aSKunihiko Hayashi 
3985ab43d0fSKunihiko Hayashi static const struct uniphier_u3hsphy_soc_data uniphier_pxs2_data = {
399e68c2a8aSKunihiko Hayashi 	.is_legacy = false,
40025858c52SKunihiko Hayashi 	.nparams = 2,
40125858c52SKunihiko Hayashi 	.param = {
40225858c52SKunihiko Hayashi 		{ RX_CHK_SYNC, 1 },
40325858c52SKunihiko Hayashi 		{ RX_SYNC_SEL, 1 },
40425858c52SKunihiko Hayashi 	},
4055ab43d0fSKunihiko Hayashi };
4065ab43d0fSKunihiko Hayashi 
4075ab43d0fSKunihiko Hayashi static const struct uniphier_u3hsphy_soc_data uniphier_ld20_data = {
408e68c2a8aSKunihiko Hayashi 	.is_legacy = false,
40925858c52SKunihiko Hayashi 	.nparams = 4,
4105ab43d0fSKunihiko Hayashi 	.param = {
41125858c52SKunihiko Hayashi 		{ RX_CHK_SYNC, 1 },
41225858c52SKunihiko Hayashi 		{ RX_SYNC_SEL, 1 },
4135ab43d0fSKunihiko Hayashi 		{ LS_SLEW, 1 },
4145ab43d0fSKunihiko Hayashi 		{ FS_LS_DRV, 1 },
4155ab43d0fSKunihiko Hayashi 	},
4165ab43d0fSKunihiko Hayashi 	.trim_func = uniphier_u3hsphy_trim_ld20,
4175ab43d0fSKunihiko Hayashi 	.config0 = 0x92316680,
4185ab43d0fSKunihiko Hayashi 	.config1 = 0x00000106,
4195ab43d0fSKunihiko Hayashi };
4205ab43d0fSKunihiko Hayashi 
4215ab43d0fSKunihiko Hayashi static const struct uniphier_u3hsphy_soc_data uniphier_pxs3_data = {
422e68c2a8aSKunihiko Hayashi 	.is_legacy = false,
42325858c52SKunihiko Hayashi 	.nparams = 2,
42425858c52SKunihiko Hayashi 	.param = {
42525858c52SKunihiko Hayashi 		{ RX_CHK_SYNC, 1 },
42625858c52SKunihiko Hayashi 		{ RX_SYNC_SEL, 1 },
42725858c52SKunihiko Hayashi 	},
4285ab43d0fSKunihiko Hayashi 	.trim_func = uniphier_u3hsphy_trim_ld20,
4295ab43d0fSKunihiko Hayashi 	.config0 = 0x92316680,
4305ab43d0fSKunihiko Hayashi 	.config1 = 0x00000106,
4315ab43d0fSKunihiko Hayashi };
4325ab43d0fSKunihiko Hayashi 
4335ab43d0fSKunihiko Hayashi static const struct of_device_id uniphier_u3hsphy_match[] = {
4345ab43d0fSKunihiko Hayashi 	{
435e68c2a8aSKunihiko Hayashi 		.compatible = "socionext,uniphier-pro5-usb3-hsphy",
436e68c2a8aSKunihiko Hayashi 		.data = &uniphier_pro5_data,
437e68c2a8aSKunihiko Hayashi 	},
438e68c2a8aSKunihiko Hayashi 	{
4395ab43d0fSKunihiko Hayashi 		.compatible = "socionext,uniphier-pxs2-usb3-hsphy",
4405ab43d0fSKunihiko Hayashi 		.data = &uniphier_pxs2_data,
4415ab43d0fSKunihiko Hayashi 	},
4425ab43d0fSKunihiko Hayashi 	{
4435ab43d0fSKunihiko Hayashi 		.compatible = "socionext,uniphier-ld20-usb3-hsphy",
4445ab43d0fSKunihiko Hayashi 		.data = &uniphier_ld20_data,
4455ab43d0fSKunihiko Hayashi 	},
4465ab43d0fSKunihiko Hayashi 	{
4475ab43d0fSKunihiko Hayashi 		.compatible = "socionext,uniphier-pxs3-usb3-hsphy",
4485ab43d0fSKunihiko Hayashi 		.data = &uniphier_pxs3_data,
4495ab43d0fSKunihiko Hayashi 	},
450*877e8d28SKunihiko Hayashi 	{
451*877e8d28SKunihiko Hayashi 		.compatible = "socionext,uniphier-nx1-usb3-hsphy",
452*877e8d28SKunihiko Hayashi 		.data = &uniphier_pxs3_data,
453*877e8d28SKunihiko Hayashi 	},
4545ab43d0fSKunihiko Hayashi 	{ /* sentinel */ }
4555ab43d0fSKunihiko Hayashi };
4565ab43d0fSKunihiko Hayashi MODULE_DEVICE_TABLE(of, uniphier_u3hsphy_match);
4575ab43d0fSKunihiko Hayashi 
4585ab43d0fSKunihiko Hayashi static struct platform_driver uniphier_u3hsphy_driver = {
4595ab43d0fSKunihiko Hayashi 	.probe = uniphier_u3hsphy_probe,
4605ab43d0fSKunihiko Hayashi 	.driver	= {
4615ab43d0fSKunihiko Hayashi 		.name = "uniphier-usb3-hsphy",
4625ab43d0fSKunihiko Hayashi 		.of_match_table	= uniphier_u3hsphy_match,
4635ab43d0fSKunihiko Hayashi 	},
4645ab43d0fSKunihiko Hayashi };
4655ab43d0fSKunihiko Hayashi 
4665ab43d0fSKunihiko Hayashi module_platform_driver(uniphier_u3hsphy_driver);
4675ab43d0fSKunihiko Hayashi 
4685ab43d0fSKunihiko Hayashi MODULE_AUTHOR("Kunihiko Hayashi <hayashi.kunihiko@socionext.com>");
4695ab43d0fSKunihiko Hayashi MODULE_DESCRIPTION("UniPhier HS-PHY driver for USB3 controller");
4705ab43d0fSKunihiko Hayashi MODULE_LICENSE("GPL v2");
471