18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * phy-uniphier-usb3hs.c - HS-PHY driver for Socionext UniPhier USB3 controller 48c2ecf20Sopenharmony_ci * Copyright 2015-2018 Socionext Inc. 58c2ecf20Sopenharmony_ci * Author: 68c2ecf20Sopenharmony_ci * Kunihiko Hayashi <hayashi.kunihiko@socionext.com> 78c2ecf20Sopenharmony_ci * Contributors: 88c2ecf20Sopenharmony_ci * Motoya Tanigawa <tanigawa.motoya@socionext.com> 98c2ecf20Sopenharmony_ci * Masami Hiramatsu <masami.hiramatsu@linaro.org> 108c2ecf20Sopenharmony_ci */ 118c2ecf20Sopenharmony_ci 128c2ecf20Sopenharmony_ci#include <linux/bitfield.h> 138c2ecf20Sopenharmony_ci#include <linux/bitops.h> 148c2ecf20Sopenharmony_ci#include <linux/clk.h> 158c2ecf20Sopenharmony_ci#include <linux/io.h> 168c2ecf20Sopenharmony_ci#include <linux/module.h> 178c2ecf20Sopenharmony_ci#include <linux/nvmem-consumer.h> 188c2ecf20Sopenharmony_ci#include <linux/of.h> 198c2ecf20Sopenharmony_ci#include <linux/of_platform.h> 208c2ecf20Sopenharmony_ci#include <linux/phy/phy.h> 218c2ecf20Sopenharmony_ci#include <linux/platform_device.h> 228c2ecf20Sopenharmony_ci#include <linux/regulator/consumer.h> 238c2ecf20Sopenharmony_ci#include <linux/reset.h> 248c2ecf20Sopenharmony_ci#include <linux/slab.h> 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_ci#define HSPHY_CFG0 0x0 278c2ecf20Sopenharmony_ci#define HSPHY_CFG0_HS_I_MASK GENMASK(31, 28) 288c2ecf20Sopenharmony_ci#define HSPHY_CFG0_HSDISC_MASK GENMASK(27, 26) 298c2ecf20Sopenharmony_ci#define HSPHY_CFG0_SWING_MASK GENMASK(17, 16) 308c2ecf20Sopenharmony_ci#define HSPHY_CFG0_SEL_T_MASK GENMASK(15, 12) 318c2ecf20Sopenharmony_ci#define HSPHY_CFG0_RTERM_MASK GENMASK(7, 6) 328c2ecf20Sopenharmony_ci#define HSPHY_CFG0_TRIMMASK (HSPHY_CFG0_HS_I_MASK \ 338c2ecf20Sopenharmony_ci | HSPHY_CFG0_SEL_T_MASK \ 348c2ecf20Sopenharmony_ci | HSPHY_CFG0_RTERM_MASK) 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_ci#define HSPHY_CFG1 0x4 378c2ecf20Sopenharmony_ci#define HSPHY_CFG1_DAT_EN BIT(29) 388c2ecf20Sopenharmony_ci#define HSPHY_CFG1_ADR_EN BIT(28) 398c2ecf20Sopenharmony_ci#define HSPHY_CFG1_ADR_MASK GENMASK(27, 16) 408c2ecf20Sopenharmony_ci#define HSPHY_CFG1_DAT_MASK GENMASK(23, 16) 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_ci#define PHY_F(regno, msb, lsb) { (regno), (msb), (lsb) } 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_ci#define RX_CHK_SYNC PHY_F(0, 5, 5) /* RX sync mode */ 458c2ecf20Sopenharmony_ci#define RX_SYNC_SEL PHY_F(1, 1, 0) /* RX sync length */ 468c2ecf20Sopenharmony_ci#define LS_SLEW PHY_F(10, 6, 6) /* LS mode slew rate */ 478c2ecf20Sopenharmony_ci#define FS_LS_DRV PHY_F(10, 5, 5) /* FS/LS slew rate */ 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_ci#define MAX_PHY_PARAMS 4 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_cistruct uniphier_u3hsphy_param { 528c2ecf20Sopenharmony_ci struct { 538c2ecf20Sopenharmony_ci int reg_no; 548c2ecf20Sopenharmony_ci int msb; 558c2ecf20Sopenharmony_ci int lsb; 568c2ecf20Sopenharmony_ci } field; 578c2ecf20Sopenharmony_ci u8 value; 588c2ecf20Sopenharmony_ci}; 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_cistruct uniphier_u3hsphy_trim_param { 618c2ecf20Sopenharmony_ci unsigned int rterm; 628c2ecf20Sopenharmony_ci unsigned int sel_t; 638c2ecf20Sopenharmony_ci unsigned int hs_i; 648c2ecf20Sopenharmony_ci}; 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_ci#define trim_param_is_valid(p) ((p)->rterm || (p)->sel_t || (p)->hs_i) 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_cistruct uniphier_u3hsphy_priv { 698c2ecf20Sopenharmony_ci struct device *dev; 708c2ecf20Sopenharmony_ci void __iomem *base; 718c2ecf20Sopenharmony_ci struct clk *clk, *clk_parent, *clk_ext, *clk_parent_gio; 728c2ecf20Sopenharmony_ci struct reset_control *rst, *rst_parent, *rst_parent_gio; 738c2ecf20Sopenharmony_ci struct regulator *vbus; 748c2ecf20Sopenharmony_ci const struct uniphier_u3hsphy_soc_data *data; 758c2ecf20Sopenharmony_ci}; 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_cistruct uniphier_u3hsphy_soc_data { 788c2ecf20Sopenharmony_ci bool is_legacy; 798c2ecf20Sopenharmony_ci int nparams; 808c2ecf20Sopenharmony_ci const struct uniphier_u3hsphy_param param[MAX_PHY_PARAMS]; 818c2ecf20Sopenharmony_ci u32 config0; 828c2ecf20Sopenharmony_ci u32 config1; 838c2ecf20Sopenharmony_ci void (*trim_func)(struct uniphier_u3hsphy_priv *priv, u32 *pconfig, 848c2ecf20Sopenharmony_ci struct uniphier_u3hsphy_trim_param *pt); 858c2ecf20Sopenharmony_ci}; 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_cistatic void uniphier_u3hsphy_trim_ld20(struct uniphier_u3hsphy_priv *priv, 888c2ecf20Sopenharmony_ci u32 *pconfig, 898c2ecf20Sopenharmony_ci struct uniphier_u3hsphy_trim_param *pt) 908c2ecf20Sopenharmony_ci{ 918c2ecf20Sopenharmony_ci *pconfig &= ~HSPHY_CFG0_RTERM_MASK; 928c2ecf20Sopenharmony_ci *pconfig |= FIELD_PREP(HSPHY_CFG0_RTERM_MASK, pt->rterm); 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_ci *pconfig &= ~HSPHY_CFG0_SEL_T_MASK; 958c2ecf20Sopenharmony_ci *pconfig |= FIELD_PREP(HSPHY_CFG0_SEL_T_MASK, pt->sel_t); 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_ci *pconfig &= ~HSPHY_CFG0_HS_I_MASK; 988c2ecf20Sopenharmony_ci *pconfig |= FIELD_PREP(HSPHY_CFG0_HS_I_MASK, pt->hs_i); 998c2ecf20Sopenharmony_ci} 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_cistatic int uniphier_u3hsphy_get_nvparam(struct uniphier_u3hsphy_priv *priv, 1028c2ecf20Sopenharmony_ci const char *name, unsigned int *val) 1038c2ecf20Sopenharmony_ci{ 1048c2ecf20Sopenharmony_ci struct nvmem_cell *cell; 1058c2ecf20Sopenharmony_ci u8 *buf; 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_ci cell = devm_nvmem_cell_get(priv->dev, name); 1088c2ecf20Sopenharmony_ci if (IS_ERR(cell)) 1098c2ecf20Sopenharmony_ci return PTR_ERR(cell); 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_ci buf = nvmem_cell_read(cell, NULL); 1128c2ecf20Sopenharmony_ci if (IS_ERR(buf)) 1138c2ecf20Sopenharmony_ci return PTR_ERR(buf); 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_ci *val = *buf; 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_ci kfree(buf); 1188c2ecf20Sopenharmony_ci 1198c2ecf20Sopenharmony_ci return 0; 1208c2ecf20Sopenharmony_ci} 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_cistatic int uniphier_u3hsphy_get_nvparams(struct uniphier_u3hsphy_priv *priv, 1238c2ecf20Sopenharmony_ci struct uniphier_u3hsphy_trim_param *pt) 1248c2ecf20Sopenharmony_ci{ 1258c2ecf20Sopenharmony_ci int ret; 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_ci ret = uniphier_u3hsphy_get_nvparam(priv, "rterm", &pt->rterm); 1288c2ecf20Sopenharmony_ci if (ret) 1298c2ecf20Sopenharmony_ci return ret; 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_ci ret = uniphier_u3hsphy_get_nvparam(priv, "sel_t", &pt->sel_t); 1328c2ecf20Sopenharmony_ci if (ret) 1338c2ecf20Sopenharmony_ci return ret; 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_ci ret = uniphier_u3hsphy_get_nvparam(priv, "hs_i", &pt->hs_i); 1368c2ecf20Sopenharmony_ci if (ret) 1378c2ecf20Sopenharmony_ci return ret; 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_ci return 0; 1408c2ecf20Sopenharmony_ci} 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_cistatic int uniphier_u3hsphy_update_config(struct uniphier_u3hsphy_priv *priv, 1438c2ecf20Sopenharmony_ci u32 *pconfig) 1448c2ecf20Sopenharmony_ci{ 1458c2ecf20Sopenharmony_ci struct uniphier_u3hsphy_trim_param trim; 1468c2ecf20Sopenharmony_ci int ret, trimmed = 0; 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_ci if (priv->data->trim_func) { 1498c2ecf20Sopenharmony_ci ret = uniphier_u3hsphy_get_nvparams(priv, &trim); 1508c2ecf20Sopenharmony_ci if (ret == -EPROBE_DEFER) 1518c2ecf20Sopenharmony_ci return ret; 1528c2ecf20Sopenharmony_ci 1538c2ecf20Sopenharmony_ci /* 1548c2ecf20Sopenharmony_ci * call trim_func only when trimming parameters that aren't 1558c2ecf20Sopenharmony_ci * all-zero can be acquired. All-zero parameters mean nothing 1568c2ecf20Sopenharmony_ci * has been written to nvmem. 1578c2ecf20Sopenharmony_ci */ 1588c2ecf20Sopenharmony_ci if (!ret && trim_param_is_valid(&trim)) { 1598c2ecf20Sopenharmony_ci priv->data->trim_func(priv, pconfig, &trim); 1608c2ecf20Sopenharmony_ci trimmed = 1; 1618c2ecf20Sopenharmony_ci } else { 1628c2ecf20Sopenharmony_ci dev_dbg(priv->dev, "can't get parameter from nvmem\n"); 1638c2ecf20Sopenharmony_ci } 1648c2ecf20Sopenharmony_ci } 1658c2ecf20Sopenharmony_ci 1668c2ecf20Sopenharmony_ci /* use default parameters without trimming values */ 1678c2ecf20Sopenharmony_ci if (!trimmed) { 1688c2ecf20Sopenharmony_ci *pconfig &= ~HSPHY_CFG0_HSDISC_MASK; 1698c2ecf20Sopenharmony_ci *pconfig |= FIELD_PREP(HSPHY_CFG0_HSDISC_MASK, 3); 1708c2ecf20Sopenharmony_ci } 1718c2ecf20Sopenharmony_ci 1728c2ecf20Sopenharmony_ci return 0; 1738c2ecf20Sopenharmony_ci} 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_cistatic void uniphier_u3hsphy_set_param(struct uniphier_u3hsphy_priv *priv, 1768c2ecf20Sopenharmony_ci const struct uniphier_u3hsphy_param *p) 1778c2ecf20Sopenharmony_ci{ 1788c2ecf20Sopenharmony_ci u32 val; 1798c2ecf20Sopenharmony_ci u32 field_mask = GENMASK(p->field.msb, p->field.lsb); 1808c2ecf20Sopenharmony_ci u8 data; 1818c2ecf20Sopenharmony_ci 1828c2ecf20Sopenharmony_ci val = readl(priv->base + HSPHY_CFG1); 1838c2ecf20Sopenharmony_ci val &= ~HSPHY_CFG1_ADR_MASK; 1848c2ecf20Sopenharmony_ci val |= FIELD_PREP(HSPHY_CFG1_ADR_MASK, p->field.reg_no) 1858c2ecf20Sopenharmony_ci | HSPHY_CFG1_ADR_EN; 1868c2ecf20Sopenharmony_ci writel(val, priv->base + HSPHY_CFG1); 1878c2ecf20Sopenharmony_ci 1888c2ecf20Sopenharmony_ci val = readl(priv->base + HSPHY_CFG1); 1898c2ecf20Sopenharmony_ci val &= ~HSPHY_CFG1_ADR_EN; 1908c2ecf20Sopenharmony_ci writel(val, priv->base + HSPHY_CFG1); 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_ci val = readl(priv->base + HSPHY_CFG1); 1938c2ecf20Sopenharmony_ci val &= ~FIELD_PREP(HSPHY_CFG1_DAT_MASK, field_mask); 1948c2ecf20Sopenharmony_ci data = field_mask & (p->value << p->field.lsb); 1958c2ecf20Sopenharmony_ci val |= FIELD_PREP(HSPHY_CFG1_DAT_MASK, data) | HSPHY_CFG1_DAT_EN; 1968c2ecf20Sopenharmony_ci writel(val, priv->base + HSPHY_CFG1); 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_ci val = readl(priv->base + HSPHY_CFG1); 1998c2ecf20Sopenharmony_ci val &= ~HSPHY_CFG1_DAT_EN; 2008c2ecf20Sopenharmony_ci writel(val, priv->base + HSPHY_CFG1); 2018c2ecf20Sopenharmony_ci} 2028c2ecf20Sopenharmony_ci 2038c2ecf20Sopenharmony_cistatic int uniphier_u3hsphy_power_on(struct phy *phy) 2048c2ecf20Sopenharmony_ci{ 2058c2ecf20Sopenharmony_ci struct uniphier_u3hsphy_priv *priv = phy_get_drvdata(phy); 2068c2ecf20Sopenharmony_ci int ret; 2078c2ecf20Sopenharmony_ci 2088c2ecf20Sopenharmony_ci ret = clk_prepare_enable(priv->clk_ext); 2098c2ecf20Sopenharmony_ci if (ret) 2108c2ecf20Sopenharmony_ci return ret; 2118c2ecf20Sopenharmony_ci 2128c2ecf20Sopenharmony_ci ret = clk_prepare_enable(priv->clk); 2138c2ecf20Sopenharmony_ci if (ret) 2148c2ecf20Sopenharmony_ci goto out_clk_ext_disable; 2158c2ecf20Sopenharmony_ci 2168c2ecf20Sopenharmony_ci ret = reset_control_deassert(priv->rst); 2178c2ecf20Sopenharmony_ci if (ret) 2188c2ecf20Sopenharmony_ci goto out_clk_disable; 2198c2ecf20Sopenharmony_ci 2208c2ecf20Sopenharmony_ci if (priv->vbus) { 2218c2ecf20Sopenharmony_ci ret = regulator_enable(priv->vbus); 2228c2ecf20Sopenharmony_ci if (ret) 2238c2ecf20Sopenharmony_ci goto out_rst_assert; 2248c2ecf20Sopenharmony_ci } 2258c2ecf20Sopenharmony_ci 2268c2ecf20Sopenharmony_ci return 0; 2278c2ecf20Sopenharmony_ci 2288c2ecf20Sopenharmony_ciout_rst_assert: 2298c2ecf20Sopenharmony_ci reset_control_assert(priv->rst); 2308c2ecf20Sopenharmony_ciout_clk_disable: 2318c2ecf20Sopenharmony_ci clk_disable_unprepare(priv->clk); 2328c2ecf20Sopenharmony_ciout_clk_ext_disable: 2338c2ecf20Sopenharmony_ci clk_disable_unprepare(priv->clk_ext); 2348c2ecf20Sopenharmony_ci 2358c2ecf20Sopenharmony_ci return ret; 2368c2ecf20Sopenharmony_ci} 2378c2ecf20Sopenharmony_ci 2388c2ecf20Sopenharmony_cistatic int uniphier_u3hsphy_power_off(struct phy *phy) 2398c2ecf20Sopenharmony_ci{ 2408c2ecf20Sopenharmony_ci struct uniphier_u3hsphy_priv *priv = phy_get_drvdata(phy); 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_ci if (priv->vbus) 2438c2ecf20Sopenharmony_ci regulator_disable(priv->vbus); 2448c2ecf20Sopenharmony_ci 2458c2ecf20Sopenharmony_ci reset_control_assert(priv->rst); 2468c2ecf20Sopenharmony_ci clk_disable_unprepare(priv->clk); 2478c2ecf20Sopenharmony_ci clk_disable_unprepare(priv->clk_ext); 2488c2ecf20Sopenharmony_ci 2498c2ecf20Sopenharmony_ci return 0; 2508c2ecf20Sopenharmony_ci} 2518c2ecf20Sopenharmony_ci 2528c2ecf20Sopenharmony_cistatic int uniphier_u3hsphy_init(struct phy *phy) 2538c2ecf20Sopenharmony_ci{ 2548c2ecf20Sopenharmony_ci struct uniphier_u3hsphy_priv *priv = phy_get_drvdata(phy); 2558c2ecf20Sopenharmony_ci u32 config0, config1; 2568c2ecf20Sopenharmony_ci int i, ret; 2578c2ecf20Sopenharmony_ci 2588c2ecf20Sopenharmony_ci ret = clk_prepare_enable(priv->clk_parent); 2598c2ecf20Sopenharmony_ci if (ret) 2608c2ecf20Sopenharmony_ci return ret; 2618c2ecf20Sopenharmony_ci 2628c2ecf20Sopenharmony_ci ret = clk_prepare_enable(priv->clk_parent_gio); 2638c2ecf20Sopenharmony_ci if (ret) 2648c2ecf20Sopenharmony_ci goto out_clk_disable; 2658c2ecf20Sopenharmony_ci 2668c2ecf20Sopenharmony_ci ret = reset_control_deassert(priv->rst_parent); 2678c2ecf20Sopenharmony_ci if (ret) 2688c2ecf20Sopenharmony_ci goto out_clk_gio_disable; 2698c2ecf20Sopenharmony_ci 2708c2ecf20Sopenharmony_ci ret = reset_control_deassert(priv->rst_parent_gio); 2718c2ecf20Sopenharmony_ci if (ret) 2728c2ecf20Sopenharmony_ci goto out_rst_assert; 2738c2ecf20Sopenharmony_ci 2748c2ecf20Sopenharmony_ci if ((priv->data->is_legacy) 2758c2ecf20Sopenharmony_ci || (!priv->data->config0 && !priv->data->config1)) 2768c2ecf20Sopenharmony_ci return 0; 2778c2ecf20Sopenharmony_ci 2788c2ecf20Sopenharmony_ci config0 = priv->data->config0; 2798c2ecf20Sopenharmony_ci config1 = priv->data->config1; 2808c2ecf20Sopenharmony_ci 2818c2ecf20Sopenharmony_ci ret = uniphier_u3hsphy_update_config(priv, &config0); 2828c2ecf20Sopenharmony_ci if (ret) 2838c2ecf20Sopenharmony_ci goto out_rst_assert; 2848c2ecf20Sopenharmony_ci 2858c2ecf20Sopenharmony_ci writel(config0, priv->base + HSPHY_CFG0); 2868c2ecf20Sopenharmony_ci writel(config1, priv->base + HSPHY_CFG1); 2878c2ecf20Sopenharmony_ci 2888c2ecf20Sopenharmony_ci for (i = 0; i < priv->data->nparams; i++) 2898c2ecf20Sopenharmony_ci uniphier_u3hsphy_set_param(priv, &priv->data->param[i]); 2908c2ecf20Sopenharmony_ci 2918c2ecf20Sopenharmony_ci return 0; 2928c2ecf20Sopenharmony_ci 2938c2ecf20Sopenharmony_ciout_rst_assert: 2948c2ecf20Sopenharmony_ci reset_control_assert(priv->rst_parent); 2958c2ecf20Sopenharmony_ciout_clk_gio_disable: 2968c2ecf20Sopenharmony_ci clk_disable_unprepare(priv->clk_parent_gio); 2978c2ecf20Sopenharmony_ciout_clk_disable: 2988c2ecf20Sopenharmony_ci clk_disable_unprepare(priv->clk_parent); 2998c2ecf20Sopenharmony_ci 3008c2ecf20Sopenharmony_ci return ret; 3018c2ecf20Sopenharmony_ci} 3028c2ecf20Sopenharmony_ci 3038c2ecf20Sopenharmony_cistatic int uniphier_u3hsphy_exit(struct phy *phy) 3048c2ecf20Sopenharmony_ci{ 3058c2ecf20Sopenharmony_ci struct uniphier_u3hsphy_priv *priv = phy_get_drvdata(phy); 3068c2ecf20Sopenharmony_ci 3078c2ecf20Sopenharmony_ci reset_control_assert(priv->rst_parent_gio); 3088c2ecf20Sopenharmony_ci reset_control_assert(priv->rst_parent); 3098c2ecf20Sopenharmony_ci clk_disable_unprepare(priv->clk_parent_gio); 3108c2ecf20Sopenharmony_ci clk_disable_unprepare(priv->clk_parent); 3118c2ecf20Sopenharmony_ci 3128c2ecf20Sopenharmony_ci return 0; 3138c2ecf20Sopenharmony_ci} 3148c2ecf20Sopenharmony_ci 3158c2ecf20Sopenharmony_cistatic const struct phy_ops uniphier_u3hsphy_ops = { 3168c2ecf20Sopenharmony_ci .init = uniphier_u3hsphy_init, 3178c2ecf20Sopenharmony_ci .exit = uniphier_u3hsphy_exit, 3188c2ecf20Sopenharmony_ci .power_on = uniphier_u3hsphy_power_on, 3198c2ecf20Sopenharmony_ci .power_off = uniphier_u3hsphy_power_off, 3208c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 3218c2ecf20Sopenharmony_ci}; 3228c2ecf20Sopenharmony_ci 3238c2ecf20Sopenharmony_cistatic int uniphier_u3hsphy_probe(struct platform_device *pdev) 3248c2ecf20Sopenharmony_ci{ 3258c2ecf20Sopenharmony_ci struct device *dev = &pdev->dev; 3268c2ecf20Sopenharmony_ci struct uniphier_u3hsphy_priv *priv; 3278c2ecf20Sopenharmony_ci struct phy_provider *phy_provider; 3288c2ecf20Sopenharmony_ci struct phy *phy; 3298c2ecf20Sopenharmony_ci 3308c2ecf20Sopenharmony_ci priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); 3318c2ecf20Sopenharmony_ci if (!priv) 3328c2ecf20Sopenharmony_ci return -ENOMEM; 3338c2ecf20Sopenharmony_ci 3348c2ecf20Sopenharmony_ci priv->dev = dev; 3358c2ecf20Sopenharmony_ci priv->data = of_device_get_match_data(dev); 3368c2ecf20Sopenharmony_ci if (WARN_ON(!priv->data || 3378c2ecf20Sopenharmony_ci priv->data->nparams > MAX_PHY_PARAMS)) 3388c2ecf20Sopenharmony_ci return -EINVAL; 3398c2ecf20Sopenharmony_ci 3408c2ecf20Sopenharmony_ci priv->base = devm_platform_ioremap_resource(pdev, 0); 3418c2ecf20Sopenharmony_ci if (IS_ERR(priv->base)) 3428c2ecf20Sopenharmony_ci return PTR_ERR(priv->base); 3438c2ecf20Sopenharmony_ci 3448c2ecf20Sopenharmony_ci if (!priv->data->is_legacy) { 3458c2ecf20Sopenharmony_ci priv->clk = devm_clk_get(dev, "phy"); 3468c2ecf20Sopenharmony_ci if (IS_ERR(priv->clk)) 3478c2ecf20Sopenharmony_ci return PTR_ERR(priv->clk); 3488c2ecf20Sopenharmony_ci 3498c2ecf20Sopenharmony_ci priv->clk_ext = devm_clk_get_optional(dev, "phy-ext"); 3508c2ecf20Sopenharmony_ci if (IS_ERR(priv->clk_ext)) 3518c2ecf20Sopenharmony_ci return PTR_ERR(priv->clk_ext); 3528c2ecf20Sopenharmony_ci 3538c2ecf20Sopenharmony_ci priv->rst = devm_reset_control_get_shared(dev, "phy"); 3548c2ecf20Sopenharmony_ci if (IS_ERR(priv->rst)) 3558c2ecf20Sopenharmony_ci return PTR_ERR(priv->rst); 3568c2ecf20Sopenharmony_ci 3578c2ecf20Sopenharmony_ci } else { 3588c2ecf20Sopenharmony_ci priv->clk_parent_gio = devm_clk_get(dev, "gio"); 3598c2ecf20Sopenharmony_ci if (IS_ERR(priv->clk_parent_gio)) 3608c2ecf20Sopenharmony_ci return PTR_ERR(priv->clk_parent_gio); 3618c2ecf20Sopenharmony_ci 3628c2ecf20Sopenharmony_ci priv->rst_parent_gio = 3638c2ecf20Sopenharmony_ci devm_reset_control_get_shared(dev, "gio"); 3648c2ecf20Sopenharmony_ci if (IS_ERR(priv->rst_parent_gio)) 3658c2ecf20Sopenharmony_ci return PTR_ERR(priv->rst_parent_gio); 3668c2ecf20Sopenharmony_ci } 3678c2ecf20Sopenharmony_ci 3688c2ecf20Sopenharmony_ci priv->clk_parent = devm_clk_get(dev, "link"); 3698c2ecf20Sopenharmony_ci if (IS_ERR(priv->clk_parent)) 3708c2ecf20Sopenharmony_ci return PTR_ERR(priv->clk_parent); 3718c2ecf20Sopenharmony_ci 3728c2ecf20Sopenharmony_ci priv->rst_parent = devm_reset_control_get_shared(dev, "link"); 3738c2ecf20Sopenharmony_ci if (IS_ERR(priv->rst_parent)) 3748c2ecf20Sopenharmony_ci return PTR_ERR(priv->rst_parent); 3758c2ecf20Sopenharmony_ci 3768c2ecf20Sopenharmony_ci priv->vbus = devm_regulator_get_optional(dev, "vbus"); 3778c2ecf20Sopenharmony_ci if (IS_ERR(priv->vbus)) { 3788c2ecf20Sopenharmony_ci if (PTR_ERR(priv->vbus) == -EPROBE_DEFER) 3798c2ecf20Sopenharmony_ci return PTR_ERR(priv->vbus); 3808c2ecf20Sopenharmony_ci priv->vbus = NULL; 3818c2ecf20Sopenharmony_ci } 3828c2ecf20Sopenharmony_ci 3838c2ecf20Sopenharmony_ci phy = devm_phy_create(dev, dev->of_node, &uniphier_u3hsphy_ops); 3848c2ecf20Sopenharmony_ci if (IS_ERR(phy)) 3858c2ecf20Sopenharmony_ci return PTR_ERR(phy); 3868c2ecf20Sopenharmony_ci 3878c2ecf20Sopenharmony_ci phy_set_drvdata(phy, priv); 3888c2ecf20Sopenharmony_ci phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate); 3898c2ecf20Sopenharmony_ci 3908c2ecf20Sopenharmony_ci return PTR_ERR_OR_ZERO(phy_provider); 3918c2ecf20Sopenharmony_ci} 3928c2ecf20Sopenharmony_ci 3938c2ecf20Sopenharmony_cistatic const struct uniphier_u3hsphy_soc_data uniphier_pro5_data = { 3948c2ecf20Sopenharmony_ci .is_legacy = true, 3958c2ecf20Sopenharmony_ci .nparams = 0, 3968c2ecf20Sopenharmony_ci}; 3978c2ecf20Sopenharmony_ci 3988c2ecf20Sopenharmony_cistatic const struct uniphier_u3hsphy_soc_data uniphier_pxs2_data = { 3998c2ecf20Sopenharmony_ci .is_legacy = false, 4008c2ecf20Sopenharmony_ci .nparams = 2, 4018c2ecf20Sopenharmony_ci .param = { 4028c2ecf20Sopenharmony_ci { RX_CHK_SYNC, 1 }, 4038c2ecf20Sopenharmony_ci { RX_SYNC_SEL, 1 }, 4048c2ecf20Sopenharmony_ci }, 4058c2ecf20Sopenharmony_ci}; 4068c2ecf20Sopenharmony_ci 4078c2ecf20Sopenharmony_cistatic const struct uniphier_u3hsphy_soc_data uniphier_ld20_data = { 4088c2ecf20Sopenharmony_ci .is_legacy = false, 4098c2ecf20Sopenharmony_ci .nparams = 4, 4108c2ecf20Sopenharmony_ci .param = { 4118c2ecf20Sopenharmony_ci { RX_CHK_SYNC, 1 }, 4128c2ecf20Sopenharmony_ci { RX_SYNC_SEL, 1 }, 4138c2ecf20Sopenharmony_ci { LS_SLEW, 1 }, 4148c2ecf20Sopenharmony_ci { FS_LS_DRV, 1 }, 4158c2ecf20Sopenharmony_ci }, 4168c2ecf20Sopenharmony_ci .trim_func = uniphier_u3hsphy_trim_ld20, 4178c2ecf20Sopenharmony_ci .config0 = 0x92316680, 4188c2ecf20Sopenharmony_ci .config1 = 0x00000106, 4198c2ecf20Sopenharmony_ci}; 4208c2ecf20Sopenharmony_ci 4218c2ecf20Sopenharmony_cistatic const struct uniphier_u3hsphy_soc_data uniphier_pxs3_data = { 4228c2ecf20Sopenharmony_ci .is_legacy = false, 4238c2ecf20Sopenharmony_ci .nparams = 2, 4248c2ecf20Sopenharmony_ci .param = { 4258c2ecf20Sopenharmony_ci { RX_CHK_SYNC, 1 }, 4268c2ecf20Sopenharmony_ci { RX_SYNC_SEL, 1 }, 4278c2ecf20Sopenharmony_ci }, 4288c2ecf20Sopenharmony_ci .trim_func = uniphier_u3hsphy_trim_ld20, 4298c2ecf20Sopenharmony_ci .config0 = 0x92316680, 4308c2ecf20Sopenharmony_ci .config1 = 0x00000106, 4318c2ecf20Sopenharmony_ci}; 4328c2ecf20Sopenharmony_ci 4338c2ecf20Sopenharmony_cistatic const struct of_device_id uniphier_u3hsphy_match[] = { 4348c2ecf20Sopenharmony_ci { 4358c2ecf20Sopenharmony_ci .compatible = "socionext,uniphier-pro5-usb3-hsphy", 4368c2ecf20Sopenharmony_ci .data = &uniphier_pro5_data, 4378c2ecf20Sopenharmony_ci }, 4388c2ecf20Sopenharmony_ci { 4398c2ecf20Sopenharmony_ci .compatible = "socionext,uniphier-pxs2-usb3-hsphy", 4408c2ecf20Sopenharmony_ci .data = &uniphier_pxs2_data, 4418c2ecf20Sopenharmony_ci }, 4428c2ecf20Sopenharmony_ci { 4438c2ecf20Sopenharmony_ci .compatible = "socionext,uniphier-ld20-usb3-hsphy", 4448c2ecf20Sopenharmony_ci .data = &uniphier_ld20_data, 4458c2ecf20Sopenharmony_ci }, 4468c2ecf20Sopenharmony_ci { 4478c2ecf20Sopenharmony_ci .compatible = "socionext,uniphier-pxs3-usb3-hsphy", 4488c2ecf20Sopenharmony_ci .data = &uniphier_pxs3_data, 4498c2ecf20Sopenharmony_ci }, 4508c2ecf20Sopenharmony_ci { /* sentinel */ } 4518c2ecf20Sopenharmony_ci}; 4528c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, uniphier_u3hsphy_match); 4538c2ecf20Sopenharmony_ci 4548c2ecf20Sopenharmony_cistatic struct platform_driver uniphier_u3hsphy_driver = { 4558c2ecf20Sopenharmony_ci .probe = uniphier_u3hsphy_probe, 4568c2ecf20Sopenharmony_ci .driver = { 4578c2ecf20Sopenharmony_ci .name = "uniphier-usb3-hsphy", 4588c2ecf20Sopenharmony_ci .of_match_table = uniphier_u3hsphy_match, 4598c2ecf20Sopenharmony_ci }, 4608c2ecf20Sopenharmony_ci}; 4618c2ecf20Sopenharmony_ci 4628c2ecf20Sopenharmony_cimodule_platform_driver(uniphier_u3hsphy_driver); 4638c2ecf20Sopenharmony_ci 4648c2ecf20Sopenharmony_ciMODULE_AUTHOR("Kunihiko Hayashi <hayashi.kunihiko@socionext.com>"); 4658c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("UniPhier HS-PHY driver for USB3 controller"); 4668c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2"); 467