xref: /linux/drivers/phy/socionext/phy-uniphier-usb3hs.c (revision e68c2a8a2f45cbe4a237b874f87ec14ae2dfa84c)
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 
445ab43d0fSKunihiko Hayashi #define LS_SLEW		PHY_F(10, 6, 6)	/* LS mode slew rate */
455ab43d0fSKunihiko Hayashi #define FS_LS_DRV	PHY_F(10, 5, 5)	/* FS/LS slew rate */
465ab43d0fSKunihiko Hayashi 
475ab43d0fSKunihiko Hayashi #define MAX_PHY_PARAMS	2
485ab43d0fSKunihiko Hayashi 
495ab43d0fSKunihiko Hayashi struct uniphier_u3hsphy_param {
505ab43d0fSKunihiko Hayashi 	struct {
515ab43d0fSKunihiko Hayashi 		int reg_no;
525ab43d0fSKunihiko Hayashi 		int msb;
535ab43d0fSKunihiko Hayashi 		int lsb;
545ab43d0fSKunihiko Hayashi 	} field;
555ab43d0fSKunihiko Hayashi 	u8 value;
565ab43d0fSKunihiko Hayashi };
575ab43d0fSKunihiko Hayashi 
585ab43d0fSKunihiko Hayashi struct uniphier_u3hsphy_trim_param {
595ab43d0fSKunihiko Hayashi 	unsigned int rterm;
605ab43d0fSKunihiko Hayashi 	unsigned int sel_t;
615ab43d0fSKunihiko Hayashi 	unsigned int hs_i;
625ab43d0fSKunihiko Hayashi };
635ab43d0fSKunihiko Hayashi 
645ab43d0fSKunihiko Hayashi #define trim_param_is_valid(p)	((p)->rterm || (p)->sel_t || (p)->hs_i)
655ab43d0fSKunihiko Hayashi 
665ab43d0fSKunihiko Hayashi struct uniphier_u3hsphy_priv {
675ab43d0fSKunihiko Hayashi 	struct device *dev;
685ab43d0fSKunihiko Hayashi 	void __iomem *base;
69*e68c2a8aSKunihiko Hayashi 	struct clk *clk, *clk_parent, *clk_ext, *clk_parent_gio;
70*e68c2a8aSKunihiko Hayashi 	struct reset_control *rst, *rst_parent, *rst_parent_gio;
715ab43d0fSKunihiko Hayashi 	struct regulator *vbus;
725ab43d0fSKunihiko Hayashi 	const struct uniphier_u3hsphy_soc_data *data;
735ab43d0fSKunihiko Hayashi };
745ab43d0fSKunihiko Hayashi 
755ab43d0fSKunihiko Hayashi struct uniphier_u3hsphy_soc_data {
76*e68c2a8aSKunihiko Hayashi 	bool is_legacy;
775ab43d0fSKunihiko Hayashi 	int nparams;
785ab43d0fSKunihiko Hayashi 	const struct uniphier_u3hsphy_param param[MAX_PHY_PARAMS];
795ab43d0fSKunihiko Hayashi 	u32 config0;
805ab43d0fSKunihiko Hayashi 	u32 config1;
815ab43d0fSKunihiko Hayashi 	void (*trim_func)(struct uniphier_u3hsphy_priv *priv, u32 *pconfig,
825ab43d0fSKunihiko Hayashi 			  struct uniphier_u3hsphy_trim_param *pt);
835ab43d0fSKunihiko Hayashi };
845ab43d0fSKunihiko Hayashi 
855ab43d0fSKunihiko Hayashi static void uniphier_u3hsphy_trim_ld20(struct uniphier_u3hsphy_priv *priv,
865ab43d0fSKunihiko Hayashi 				       u32 *pconfig,
875ab43d0fSKunihiko Hayashi 				       struct uniphier_u3hsphy_trim_param *pt)
885ab43d0fSKunihiko Hayashi {
895ab43d0fSKunihiko Hayashi 	*pconfig &= ~HSPHY_CFG0_RTERM_MASK;
905ab43d0fSKunihiko Hayashi 	*pconfig |= FIELD_PREP(HSPHY_CFG0_RTERM_MASK, pt->rterm);
915ab43d0fSKunihiko Hayashi 
925ab43d0fSKunihiko Hayashi 	*pconfig &= ~HSPHY_CFG0_SEL_T_MASK;
935ab43d0fSKunihiko Hayashi 	*pconfig |= FIELD_PREP(HSPHY_CFG0_SEL_T_MASK, pt->sel_t);
945ab43d0fSKunihiko Hayashi 
955ab43d0fSKunihiko Hayashi 	*pconfig &= ~HSPHY_CFG0_HS_I_MASK;
965ab43d0fSKunihiko Hayashi 	*pconfig |= FIELD_PREP(HSPHY_CFG0_HS_I_MASK,  pt->hs_i);
975ab43d0fSKunihiko Hayashi }
985ab43d0fSKunihiko Hayashi 
995ab43d0fSKunihiko Hayashi static int uniphier_u3hsphy_get_nvparam(struct uniphier_u3hsphy_priv *priv,
1005ab43d0fSKunihiko Hayashi 					const char *name, unsigned int *val)
1015ab43d0fSKunihiko Hayashi {
1025ab43d0fSKunihiko Hayashi 	struct nvmem_cell *cell;
1035ab43d0fSKunihiko Hayashi 	u8 *buf;
1045ab43d0fSKunihiko Hayashi 
1055ab43d0fSKunihiko Hayashi 	cell = devm_nvmem_cell_get(priv->dev, name);
1065ab43d0fSKunihiko Hayashi 	if (IS_ERR(cell))
1075ab43d0fSKunihiko Hayashi 		return PTR_ERR(cell);
1085ab43d0fSKunihiko Hayashi 
1095ab43d0fSKunihiko Hayashi 	buf = nvmem_cell_read(cell, NULL);
1105ab43d0fSKunihiko Hayashi 	if (IS_ERR(buf))
1115ab43d0fSKunihiko Hayashi 		return PTR_ERR(buf);
1125ab43d0fSKunihiko Hayashi 
1135ab43d0fSKunihiko Hayashi 	*val = *buf;
1145ab43d0fSKunihiko Hayashi 
1155ab43d0fSKunihiko Hayashi 	kfree(buf);
1165ab43d0fSKunihiko Hayashi 
1175ab43d0fSKunihiko Hayashi 	return 0;
1185ab43d0fSKunihiko Hayashi }
1195ab43d0fSKunihiko Hayashi 
1205ab43d0fSKunihiko Hayashi static int uniphier_u3hsphy_get_nvparams(struct uniphier_u3hsphy_priv *priv,
1215ab43d0fSKunihiko Hayashi 					 struct uniphier_u3hsphy_trim_param *pt)
1225ab43d0fSKunihiko Hayashi {
1235ab43d0fSKunihiko Hayashi 	int ret;
1245ab43d0fSKunihiko Hayashi 
1255ab43d0fSKunihiko Hayashi 	ret = uniphier_u3hsphy_get_nvparam(priv, "rterm", &pt->rterm);
1265ab43d0fSKunihiko Hayashi 	if (ret)
1275ab43d0fSKunihiko Hayashi 		return ret;
1285ab43d0fSKunihiko Hayashi 
1295ab43d0fSKunihiko Hayashi 	ret = uniphier_u3hsphy_get_nvparam(priv, "sel_t", &pt->sel_t);
1305ab43d0fSKunihiko Hayashi 	if (ret)
1315ab43d0fSKunihiko Hayashi 		return ret;
1325ab43d0fSKunihiko Hayashi 
1335ab43d0fSKunihiko Hayashi 	ret = uniphier_u3hsphy_get_nvparam(priv, "hs_i", &pt->hs_i);
1345ab43d0fSKunihiko Hayashi 	if (ret)
1355ab43d0fSKunihiko Hayashi 		return ret;
1365ab43d0fSKunihiko Hayashi 
1375ab43d0fSKunihiko Hayashi 	return 0;
1385ab43d0fSKunihiko Hayashi }
1395ab43d0fSKunihiko Hayashi 
1405ab43d0fSKunihiko Hayashi static int uniphier_u3hsphy_update_config(struct uniphier_u3hsphy_priv *priv,
1415ab43d0fSKunihiko Hayashi 					  u32 *pconfig)
1425ab43d0fSKunihiko Hayashi {
1435ab43d0fSKunihiko Hayashi 	struct uniphier_u3hsphy_trim_param trim;
1445ab43d0fSKunihiko Hayashi 	int ret, trimmed = 0;
1455ab43d0fSKunihiko Hayashi 
1465ab43d0fSKunihiko Hayashi 	if (priv->data->trim_func) {
1475ab43d0fSKunihiko Hayashi 		ret = uniphier_u3hsphy_get_nvparams(priv, &trim);
1485ab43d0fSKunihiko Hayashi 		if (ret == -EPROBE_DEFER)
1495ab43d0fSKunihiko Hayashi 			return ret;
1505ab43d0fSKunihiko Hayashi 
1515ab43d0fSKunihiko Hayashi 		/*
1525ab43d0fSKunihiko Hayashi 		 * call trim_func only when trimming parameters that aren't
1535ab43d0fSKunihiko Hayashi 		 * all-zero can be acquired. All-zero parameters mean nothing
1545ab43d0fSKunihiko Hayashi 		 * has been written to nvmem.
1555ab43d0fSKunihiko Hayashi 		 */
1565ab43d0fSKunihiko Hayashi 		if (!ret && trim_param_is_valid(&trim)) {
1575ab43d0fSKunihiko Hayashi 			priv->data->trim_func(priv, pconfig, &trim);
1585ab43d0fSKunihiko Hayashi 			trimmed = 1;
1595ab43d0fSKunihiko Hayashi 		} else {
1605ab43d0fSKunihiko Hayashi 			dev_dbg(priv->dev, "can't get parameter from nvmem\n");
1615ab43d0fSKunihiko Hayashi 		}
1625ab43d0fSKunihiko Hayashi 	}
1635ab43d0fSKunihiko Hayashi 
1645ab43d0fSKunihiko Hayashi 	/* use default parameters without trimming values */
1655ab43d0fSKunihiko Hayashi 	if (!trimmed) {
1665ab43d0fSKunihiko Hayashi 		*pconfig &= ~HSPHY_CFG0_HSDISC_MASK;
1675ab43d0fSKunihiko Hayashi 		*pconfig |= FIELD_PREP(HSPHY_CFG0_HSDISC_MASK, 3);
1685ab43d0fSKunihiko Hayashi 	}
1695ab43d0fSKunihiko Hayashi 
1705ab43d0fSKunihiko Hayashi 	return 0;
1715ab43d0fSKunihiko Hayashi }
1725ab43d0fSKunihiko Hayashi 
1735ab43d0fSKunihiko Hayashi static void uniphier_u3hsphy_set_param(struct uniphier_u3hsphy_priv *priv,
1745ab43d0fSKunihiko Hayashi 				       const struct uniphier_u3hsphy_param *p)
1755ab43d0fSKunihiko Hayashi {
1765ab43d0fSKunihiko Hayashi 	u32 val;
1775ab43d0fSKunihiko Hayashi 	u32 field_mask = GENMASK(p->field.msb, p->field.lsb);
1785ab43d0fSKunihiko Hayashi 	u8 data;
1795ab43d0fSKunihiko Hayashi 
1805ab43d0fSKunihiko Hayashi 	val = readl(priv->base + HSPHY_CFG1);
1815ab43d0fSKunihiko Hayashi 	val &= ~HSPHY_CFG1_ADR_MASK;
1825ab43d0fSKunihiko Hayashi 	val |= FIELD_PREP(HSPHY_CFG1_ADR_MASK, p->field.reg_no)
1835ab43d0fSKunihiko Hayashi 		| HSPHY_CFG1_ADR_EN;
1845ab43d0fSKunihiko Hayashi 	writel(val, priv->base + HSPHY_CFG1);
1855ab43d0fSKunihiko Hayashi 
1865ab43d0fSKunihiko Hayashi 	val = readl(priv->base + HSPHY_CFG1);
1875ab43d0fSKunihiko Hayashi 	val &= ~HSPHY_CFG1_ADR_EN;
1885ab43d0fSKunihiko Hayashi 	writel(val, priv->base + HSPHY_CFG1);
1895ab43d0fSKunihiko Hayashi 
1905ab43d0fSKunihiko Hayashi 	val = readl(priv->base + HSPHY_CFG1);
1915ab43d0fSKunihiko Hayashi 	val &= ~FIELD_PREP(HSPHY_CFG1_DAT_MASK, field_mask);
1925ab43d0fSKunihiko Hayashi 	data = field_mask & (p->value << p->field.lsb);
1935ab43d0fSKunihiko Hayashi 	val |=  FIELD_PREP(HSPHY_CFG1_DAT_MASK, data) | HSPHY_CFG1_DAT_EN;
1945ab43d0fSKunihiko Hayashi 	writel(val, priv->base + HSPHY_CFG1);
1955ab43d0fSKunihiko Hayashi 
1965ab43d0fSKunihiko Hayashi 	val = readl(priv->base + HSPHY_CFG1);
1975ab43d0fSKunihiko Hayashi 	val &= ~HSPHY_CFG1_DAT_EN;
1985ab43d0fSKunihiko Hayashi 	writel(val, priv->base + HSPHY_CFG1);
1995ab43d0fSKunihiko Hayashi }
2005ab43d0fSKunihiko Hayashi 
2015ab43d0fSKunihiko Hayashi static int uniphier_u3hsphy_power_on(struct phy *phy)
2025ab43d0fSKunihiko Hayashi {
2035ab43d0fSKunihiko Hayashi 	struct uniphier_u3hsphy_priv *priv = phy_get_drvdata(phy);
2045ab43d0fSKunihiko Hayashi 	int ret;
2055ab43d0fSKunihiko Hayashi 
2065ab43d0fSKunihiko Hayashi 	ret = clk_prepare_enable(priv->clk_ext);
2075ab43d0fSKunihiko Hayashi 	if (ret)
2085ab43d0fSKunihiko Hayashi 		return ret;
2095ab43d0fSKunihiko Hayashi 
2105ab43d0fSKunihiko Hayashi 	ret = clk_prepare_enable(priv->clk);
2115ab43d0fSKunihiko Hayashi 	if (ret)
2125ab43d0fSKunihiko Hayashi 		goto out_clk_ext_disable;
2135ab43d0fSKunihiko Hayashi 
2145ab43d0fSKunihiko Hayashi 	ret = reset_control_deassert(priv->rst);
2155ab43d0fSKunihiko Hayashi 	if (ret)
2165ab43d0fSKunihiko Hayashi 		goto out_clk_disable;
2175ab43d0fSKunihiko Hayashi 
2185ab43d0fSKunihiko Hayashi 	if (priv->vbus) {
2195ab43d0fSKunihiko Hayashi 		ret = regulator_enable(priv->vbus);
2205ab43d0fSKunihiko Hayashi 		if (ret)
2215ab43d0fSKunihiko Hayashi 			goto out_rst_assert;
2225ab43d0fSKunihiko Hayashi 	}
2235ab43d0fSKunihiko Hayashi 
2245ab43d0fSKunihiko Hayashi 	return 0;
2255ab43d0fSKunihiko Hayashi 
2265ab43d0fSKunihiko Hayashi out_rst_assert:
2275ab43d0fSKunihiko Hayashi 	reset_control_assert(priv->rst);
2285ab43d0fSKunihiko Hayashi out_clk_disable:
2295ab43d0fSKunihiko Hayashi 	clk_disable_unprepare(priv->clk);
2305ab43d0fSKunihiko Hayashi out_clk_ext_disable:
2315ab43d0fSKunihiko Hayashi 	clk_disable_unprepare(priv->clk_ext);
2325ab43d0fSKunihiko Hayashi 
2335ab43d0fSKunihiko Hayashi 	return ret;
2345ab43d0fSKunihiko Hayashi }
2355ab43d0fSKunihiko Hayashi 
2365ab43d0fSKunihiko Hayashi static int uniphier_u3hsphy_power_off(struct phy *phy)
2375ab43d0fSKunihiko Hayashi {
2385ab43d0fSKunihiko Hayashi 	struct uniphier_u3hsphy_priv *priv = phy_get_drvdata(phy);
2395ab43d0fSKunihiko Hayashi 
2405ab43d0fSKunihiko Hayashi 	if (priv->vbus)
2415ab43d0fSKunihiko Hayashi 		regulator_disable(priv->vbus);
2425ab43d0fSKunihiko Hayashi 
2435ab43d0fSKunihiko Hayashi 	reset_control_assert(priv->rst);
2445ab43d0fSKunihiko Hayashi 	clk_disable_unprepare(priv->clk);
2455ab43d0fSKunihiko Hayashi 	clk_disable_unprepare(priv->clk_ext);
2465ab43d0fSKunihiko Hayashi 
2475ab43d0fSKunihiko Hayashi 	return 0;
2485ab43d0fSKunihiko Hayashi }
2495ab43d0fSKunihiko Hayashi 
2505ab43d0fSKunihiko Hayashi static int uniphier_u3hsphy_init(struct phy *phy)
2515ab43d0fSKunihiko Hayashi {
2525ab43d0fSKunihiko Hayashi 	struct uniphier_u3hsphy_priv *priv = phy_get_drvdata(phy);
2535ab43d0fSKunihiko Hayashi 	u32 config0, config1;
2545ab43d0fSKunihiko Hayashi 	int i, ret;
2555ab43d0fSKunihiko Hayashi 
2565ab43d0fSKunihiko Hayashi 	ret = clk_prepare_enable(priv->clk_parent);
2575ab43d0fSKunihiko Hayashi 	if (ret)
2585ab43d0fSKunihiko Hayashi 		return ret;
2595ab43d0fSKunihiko Hayashi 
260*e68c2a8aSKunihiko Hayashi 	ret = clk_prepare_enable(priv->clk_parent_gio);
2615ab43d0fSKunihiko Hayashi 	if (ret)
2625ab43d0fSKunihiko Hayashi 		goto out_clk_disable;
2635ab43d0fSKunihiko Hayashi 
264*e68c2a8aSKunihiko Hayashi 	ret = reset_control_deassert(priv->rst_parent);
265*e68c2a8aSKunihiko Hayashi 	if (ret)
266*e68c2a8aSKunihiko Hayashi 		goto out_clk_gio_disable;
267*e68c2a8aSKunihiko Hayashi 
268*e68c2a8aSKunihiko Hayashi 	ret = reset_control_deassert(priv->rst_parent_gio);
269*e68c2a8aSKunihiko Hayashi 	if (ret)
270*e68c2a8aSKunihiko Hayashi 		goto out_rst_assert;
271*e68c2a8aSKunihiko Hayashi 
272*e68c2a8aSKunihiko Hayashi 	if ((priv->data->is_legacy)
273*e68c2a8aSKunihiko Hayashi 	    || (!priv->data->config0 && !priv->data->config1))
2745ab43d0fSKunihiko Hayashi 		return 0;
2755ab43d0fSKunihiko Hayashi 
2765ab43d0fSKunihiko Hayashi 	config0 = priv->data->config0;
2775ab43d0fSKunihiko Hayashi 	config1 = priv->data->config1;
2785ab43d0fSKunihiko Hayashi 
2795ab43d0fSKunihiko Hayashi 	ret = uniphier_u3hsphy_update_config(priv, &config0);
2805ab43d0fSKunihiko Hayashi 	if (ret)
2815ab43d0fSKunihiko Hayashi 		goto out_rst_assert;
2825ab43d0fSKunihiko Hayashi 
2835ab43d0fSKunihiko Hayashi 	writel(config0, priv->base + HSPHY_CFG0);
2845ab43d0fSKunihiko Hayashi 	writel(config1, priv->base + HSPHY_CFG1);
2855ab43d0fSKunihiko Hayashi 
2865ab43d0fSKunihiko Hayashi 	for (i = 0; i < priv->data->nparams; i++)
2875ab43d0fSKunihiko Hayashi 		uniphier_u3hsphy_set_param(priv, &priv->data->param[i]);
2885ab43d0fSKunihiko Hayashi 
2895ab43d0fSKunihiko Hayashi 	return 0;
2905ab43d0fSKunihiko Hayashi 
2915ab43d0fSKunihiko Hayashi out_rst_assert:
2925ab43d0fSKunihiko Hayashi 	reset_control_assert(priv->rst_parent);
293*e68c2a8aSKunihiko Hayashi out_clk_gio_disable:
294*e68c2a8aSKunihiko Hayashi 	clk_disable_unprepare(priv->clk_parent_gio);
2955ab43d0fSKunihiko Hayashi out_clk_disable:
2965ab43d0fSKunihiko Hayashi 	clk_disable_unprepare(priv->clk_parent);
2975ab43d0fSKunihiko Hayashi 
2985ab43d0fSKunihiko Hayashi 	return ret;
2995ab43d0fSKunihiko Hayashi }
3005ab43d0fSKunihiko Hayashi 
3015ab43d0fSKunihiko Hayashi static int uniphier_u3hsphy_exit(struct phy *phy)
3025ab43d0fSKunihiko Hayashi {
3035ab43d0fSKunihiko Hayashi 	struct uniphier_u3hsphy_priv *priv = phy_get_drvdata(phy);
3045ab43d0fSKunihiko Hayashi 
305*e68c2a8aSKunihiko Hayashi 	reset_control_assert(priv->rst_parent_gio);
3065ab43d0fSKunihiko Hayashi 	reset_control_assert(priv->rst_parent);
307*e68c2a8aSKunihiko Hayashi 	clk_disable_unprepare(priv->clk_parent_gio);
3085ab43d0fSKunihiko Hayashi 	clk_disable_unprepare(priv->clk_parent);
3095ab43d0fSKunihiko Hayashi 
3105ab43d0fSKunihiko Hayashi 	return 0;
3115ab43d0fSKunihiko Hayashi }
3125ab43d0fSKunihiko Hayashi 
3135ab43d0fSKunihiko Hayashi static const struct phy_ops uniphier_u3hsphy_ops = {
3145ab43d0fSKunihiko Hayashi 	.init           = uniphier_u3hsphy_init,
3155ab43d0fSKunihiko Hayashi 	.exit           = uniphier_u3hsphy_exit,
3165ab43d0fSKunihiko Hayashi 	.power_on       = uniphier_u3hsphy_power_on,
3175ab43d0fSKunihiko Hayashi 	.power_off      = uniphier_u3hsphy_power_off,
3185ab43d0fSKunihiko Hayashi 	.owner          = THIS_MODULE,
3195ab43d0fSKunihiko Hayashi };
3205ab43d0fSKunihiko Hayashi 
3215ab43d0fSKunihiko Hayashi static int uniphier_u3hsphy_probe(struct platform_device *pdev)
3225ab43d0fSKunihiko Hayashi {
3235ab43d0fSKunihiko Hayashi 	struct device *dev = &pdev->dev;
3245ab43d0fSKunihiko Hayashi 	struct uniphier_u3hsphy_priv *priv;
3255ab43d0fSKunihiko Hayashi 	struct phy_provider *phy_provider;
3265ab43d0fSKunihiko Hayashi 	struct phy *phy;
3275ab43d0fSKunihiko Hayashi 
3285ab43d0fSKunihiko Hayashi 	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
3295ab43d0fSKunihiko Hayashi 	if (!priv)
3305ab43d0fSKunihiko Hayashi 		return -ENOMEM;
3315ab43d0fSKunihiko Hayashi 
3325ab43d0fSKunihiko Hayashi 	priv->dev = dev;
3335ab43d0fSKunihiko Hayashi 	priv->data = of_device_get_match_data(dev);
3345ab43d0fSKunihiko Hayashi 	if (WARN_ON(!priv->data ||
3355ab43d0fSKunihiko Hayashi 		    priv->data->nparams > MAX_PHY_PARAMS))
3365ab43d0fSKunihiko Hayashi 		return -EINVAL;
3375ab43d0fSKunihiko Hayashi 
33840d76346SKunihiko Hayashi 	priv->base = devm_platform_ioremap_resource(pdev, 0);
3395ab43d0fSKunihiko Hayashi 	if (IS_ERR(priv->base))
3405ab43d0fSKunihiko Hayashi 		return PTR_ERR(priv->base);
3415ab43d0fSKunihiko Hayashi 
342*e68c2a8aSKunihiko Hayashi 	if (!priv->data->is_legacy) {
3435ab43d0fSKunihiko Hayashi 		priv->clk = devm_clk_get(dev, "phy");
3445ab43d0fSKunihiko Hayashi 		if (IS_ERR(priv->clk))
3455ab43d0fSKunihiko Hayashi 			return PTR_ERR(priv->clk);
3465ab43d0fSKunihiko Hayashi 
347752d31a3SChunfeng Yun 		priv->clk_ext = devm_clk_get_optional(dev, "phy-ext");
348752d31a3SChunfeng Yun 		if (IS_ERR(priv->clk_ext))
3495ab43d0fSKunihiko Hayashi 			return PTR_ERR(priv->clk_ext);
3505ab43d0fSKunihiko Hayashi 
3515ab43d0fSKunihiko Hayashi 		priv->rst = devm_reset_control_get_shared(dev, "phy");
3525ab43d0fSKunihiko Hayashi 		if (IS_ERR(priv->rst))
3535ab43d0fSKunihiko Hayashi 			return PTR_ERR(priv->rst);
3545ab43d0fSKunihiko Hayashi 
355*e68c2a8aSKunihiko Hayashi 	} else {
356*e68c2a8aSKunihiko Hayashi 		priv->clk_parent_gio = devm_clk_get(dev, "gio");
357*e68c2a8aSKunihiko Hayashi 		if (IS_ERR(priv->clk_parent_gio))
358*e68c2a8aSKunihiko Hayashi 			return PTR_ERR(priv->clk_parent_gio);
359*e68c2a8aSKunihiko Hayashi 
360*e68c2a8aSKunihiko Hayashi 		priv->rst_parent_gio =
361*e68c2a8aSKunihiko Hayashi 			devm_reset_control_get_shared(dev, "gio");
362*e68c2a8aSKunihiko Hayashi 		if (IS_ERR(priv->rst_parent_gio))
363*e68c2a8aSKunihiko Hayashi 			return PTR_ERR(priv->rst_parent_gio);
364*e68c2a8aSKunihiko Hayashi 	}
365*e68c2a8aSKunihiko Hayashi 
366*e68c2a8aSKunihiko Hayashi 	priv->clk_parent = devm_clk_get(dev, "link");
367*e68c2a8aSKunihiko Hayashi 	if (IS_ERR(priv->clk_parent))
368*e68c2a8aSKunihiko Hayashi 		return PTR_ERR(priv->clk_parent);
369*e68c2a8aSKunihiko Hayashi 
3705ab43d0fSKunihiko Hayashi 	priv->rst_parent = devm_reset_control_get_shared(dev, "link");
3715ab43d0fSKunihiko Hayashi 	if (IS_ERR(priv->rst_parent))
3725ab43d0fSKunihiko Hayashi 		return PTR_ERR(priv->rst_parent);
3735ab43d0fSKunihiko Hayashi 
3745ab43d0fSKunihiko Hayashi 	priv->vbus = devm_regulator_get_optional(dev, "vbus");
3755ab43d0fSKunihiko Hayashi 	if (IS_ERR(priv->vbus)) {
3765ab43d0fSKunihiko Hayashi 		if (PTR_ERR(priv->vbus) == -EPROBE_DEFER)
3775ab43d0fSKunihiko Hayashi 			return PTR_ERR(priv->vbus);
3785ab43d0fSKunihiko Hayashi 		priv->vbus = NULL;
3795ab43d0fSKunihiko Hayashi 	}
3805ab43d0fSKunihiko Hayashi 
3815ab43d0fSKunihiko Hayashi 	phy = devm_phy_create(dev, dev->of_node, &uniphier_u3hsphy_ops);
3825ab43d0fSKunihiko Hayashi 	if (IS_ERR(phy))
3835ab43d0fSKunihiko Hayashi 		return PTR_ERR(phy);
3845ab43d0fSKunihiko Hayashi 
3855ab43d0fSKunihiko Hayashi 	phy_set_drvdata(phy, priv);
3865ab43d0fSKunihiko Hayashi 	phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
3875ab43d0fSKunihiko Hayashi 
3885ab43d0fSKunihiko Hayashi 	return PTR_ERR_OR_ZERO(phy_provider);
3895ab43d0fSKunihiko Hayashi }
3905ab43d0fSKunihiko Hayashi 
391*e68c2a8aSKunihiko Hayashi static const struct uniphier_u3hsphy_soc_data uniphier_pro5_data = {
392*e68c2a8aSKunihiko Hayashi 	.is_legacy = true,
393*e68c2a8aSKunihiko Hayashi 	.nparams = 0,
394*e68c2a8aSKunihiko Hayashi };
395*e68c2a8aSKunihiko Hayashi 
3965ab43d0fSKunihiko Hayashi static const struct uniphier_u3hsphy_soc_data uniphier_pxs2_data = {
397*e68c2a8aSKunihiko Hayashi 	.is_legacy = false,
3985ab43d0fSKunihiko Hayashi 	.nparams = 0,
3995ab43d0fSKunihiko Hayashi };
4005ab43d0fSKunihiko Hayashi 
4015ab43d0fSKunihiko Hayashi static const struct uniphier_u3hsphy_soc_data uniphier_ld20_data = {
402*e68c2a8aSKunihiko Hayashi 	.is_legacy = false,
4035ab43d0fSKunihiko Hayashi 	.nparams = 2,
4045ab43d0fSKunihiko Hayashi 	.param = {
4055ab43d0fSKunihiko Hayashi 		{ LS_SLEW, 1 },
4065ab43d0fSKunihiko Hayashi 		{ FS_LS_DRV, 1 },
4075ab43d0fSKunihiko Hayashi 	},
4085ab43d0fSKunihiko Hayashi 	.trim_func = uniphier_u3hsphy_trim_ld20,
4095ab43d0fSKunihiko Hayashi 	.config0 = 0x92316680,
4105ab43d0fSKunihiko Hayashi 	.config1 = 0x00000106,
4115ab43d0fSKunihiko Hayashi };
4125ab43d0fSKunihiko Hayashi 
4135ab43d0fSKunihiko Hayashi static const struct uniphier_u3hsphy_soc_data uniphier_pxs3_data = {
414*e68c2a8aSKunihiko Hayashi 	.is_legacy = false,
4155ab43d0fSKunihiko Hayashi 	.nparams = 0,
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 of_device_id uniphier_u3hsphy_match[] = {
4225ab43d0fSKunihiko Hayashi 	{
423*e68c2a8aSKunihiko Hayashi 		.compatible = "socionext,uniphier-pro5-usb3-hsphy",
424*e68c2a8aSKunihiko Hayashi 		.data = &uniphier_pro5_data,
425*e68c2a8aSKunihiko Hayashi 	},
426*e68c2a8aSKunihiko Hayashi 	{
4275ab43d0fSKunihiko Hayashi 		.compatible = "socionext,uniphier-pxs2-usb3-hsphy",
4285ab43d0fSKunihiko Hayashi 		.data = &uniphier_pxs2_data,
4295ab43d0fSKunihiko Hayashi 	},
4305ab43d0fSKunihiko Hayashi 	{
4315ab43d0fSKunihiko Hayashi 		.compatible = "socionext,uniphier-ld20-usb3-hsphy",
4325ab43d0fSKunihiko Hayashi 		.data = &uniphier_ld20_data,
4335ab43d0fSKunihiko Hayashi 	},
4345ab43d0fSKunihiko Hayashi 	{
4355ab43d0fSKunihiko Hayashi 		.compatible = "socionext,uniphier-pxs3-usb3-hsphy",
4365ab43d0fSKunihiko Hayashi 		.data = &uniphier_pxs3_data,
4375ab43d0fSKunihiko Hayashi 	},
4385ab43d0fSKunihiko Hayashi 	{ /* sentinel */ }
4395ab43d0fSKunihiko Hayashi };
4405ab43d0fSKunihiko Hayashi MODULE_DEVICE_TABLE(of, uniphier_u3hsphy_match);
4415ab43d0fSKunihiko Hayashi 
4425ab43d0fSKunihiko Hayashi static struct platform_driver uniphier_u3hsphy_driver = {
4435ab43d0fSKunihiko Hayashi 	.probe = uniphier_u3hsphy_probe,
4445ab43d0fSKunihiko Hayashi 	.driver	= {
4455ab43d0fSKunihiko Hayashi 		.name = "uniphier-usb3-hsphy",
4465ab43d0fSKunihiko Hayashi 		.of_match_table	= uniphier_u3hsphy_match,
4475ab43d0fSKunihiko Hayashi 	},
4485ab43d0fSKunihiko Hayashi };
4495ab43d0fSKunihiko Hayashi 
4505ab43d0fSKunihiko Hayashi module_platform_driver(uniphier_u3hsphy_driver);
4515ab43d0fSKunihiko Hayashi 
4525ab43d0fSKunihiko Hayashi MODULE_AUTHOR("Kunihiko Hayashi <hayashi.kunihiko@socionext.com>");
4535ab43d0fSKunihiko Hayashi MODULE_DESCRIPTION("UniPhier HS-PHY driver for USB3 controller");
4545ab43d0fSKunihiko Hayashi MODULE_LICENSE("GPL v2");
455