18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Amlogic G12A USB3 + PCIE Combo PHY driver 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 2017 Amlogic, Inc. All rights reserved 68c2ecf20Sopenharmony_ci * Copyright (C) 2019 BayLibre, SAS 78c2ecf20Sopenharmony_ci * Author: Neil Armstrong <narmstrong@baylibre.com> 88c2ecf20Sopenharmony_ci */ 98c2ecf20Sopenharmony_ci 108c2ecf20Sopenharmony_ci#include <linux/bitfield.h> 118c2ecf20Sopenharmony_ci#include <linux/bitops.h> 128c2ecf20Sopenharmony_ci#include <linux/clk.h> 138c2ecf20Sopenharmony_ci#include <linux/module.h> 148c2ecf20Sopenharmony_ci#include <linux/of_device.h> 158c2ecf20Sopenharmony_ci#include <linux/phy/phy.h> 168c2ecf20Sopenharmony_ci#include <linux/regmap.h> 178c2ecf20Sopenharmony_ci#include <linux/reset.h> 188c2ecf20Sopenharmony_ci#include <linux/platform_device.h> 198c2ecf20Sopenharmony_ci#include <dt-bindings/phy/phy.h> 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_ci#define PHY_R0 0x00 228c2ecf20Sopenharmony_ci #define PHY_R0_PCIE_POWER_STATE GENMASK(4, 0) 238c2ecf20Sopenharmony_ci #define PHY_R0_PCIE_USB3_SWITCH GENMASK(6, 5) 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_ci#define PHY_R1 0x04 268c2ecf20Sopenharmony_ci #define PHY_R1_PHY_TX1_TERM_OFFSET GENMASK(4, 0) 278c2ecf20Sopenharmony_ci #define PHY_R1_PHY_TX0_TERM_OFFSET GENMASK(9, 5) 288c2ecf20Sopenharmony_ci #define PHY_R1_PHY_RX1_EQ GENMASK(12, 10) 298c2ecf20Sopenharmony_ci #define PHY_R1_PHY_RX0_EQ GENMASK(15, 13) 308c2ecf20Sopenharmony_ci #define PHY_R1_PHY_LOS_LEVEL GENMASK(20, 16) 318c2ecf20Sopenharmony_ci #define PHY_R1_PHY_LOS_BIAS GENMASK(23, 21) 328c2ecf20Sopenharmony_ci #define PHY_R1_PHY_REF_CLKDIV2 BIT(24) 338c2ecf20Sopenharmony_ci #define PHY_R1_PHY_MPLL_MULTIPLIER GENMASK(31, 25) 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_ci#define PHY_R2 0x08 368c2ecf20Sopenharmony_ci #define PHY_R2_PCS_TX_DEEMPH_GEN2_6DB GENMASK(5, 0) 378c2ecf20Sopenharmony_ci #define PHY_R2_PCS_TX_DEEMPH_GEN2_3P5DB GENMASK(11, 6) 388c2ecf20Sopenharmony_ci #define PHY_R2_PCS_TX_DEEMPH_GEN1 GENMASK(17, 12) 398c2ecf20Sopenharmony_ci #define PHY_R2_PHY_TX_VBOOST_LVL GENMASK(20, 18) 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_ci#define PHY_R4 0x10 428c2ecf20Sopenharmony_ci #define PHY_R4_PHY_CR_WRITE BIT(0) 438c2ecf20Sopenharmony_ci #define PHY_R4_PHY_CR_READ BIT(1) 448c2ecf20Sopenharmony_ci #define PHY_R4_PHY_CR_DATA_IN GENMASK(17, 2) 458c2ecf20Sopenharmony_ci #define PHY_R4_PHY_CR_CAP_DATA BIT(18) 468c2ecf20Sopenharmony_ci #define PHY_R4_PHY_CR_CAP_ADDR BIT(19) 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_ci#define PHY_R5 0x14 498c2ecf20Sopenharmony_ci #define PHY_R5_PHY_CR_DATA_OUT GENMASK(15, 0) 508c2ecf20Sopenharmony_ci #define PHY_R5_PHY_CR_ACK BIT(16) 518c2ecf20Sopenharmony_ci #define PHY_R5_PHY_BS_OUT BIT(17) 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_ci#define PCIE_RESET_DELAY 500 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_cistruct phy_g12a_usb3_pcie_priv { 568c2ecf20Sopenharmony_ci struct regmap *regmap; 578c2ecf20Sopenharmony_ci struct regmap *regmap_cr; 588c2ecf20Sopenharmony_ci struct clk *clk_ref; 598c2ecf20Sopenharmony_ci struct reset_control *reset; 608c2ecf20Sopenharmony_ci struct phy *phy; 618c2ecf20Sopenharmony_ci unsigned int mode; 628c2ecf20Sopenharmony_ci}; 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_cistatic const struct regmap_config phy_g12a_usb3_pcie_regmap_conf = { 658c2ecf20Sopenharmony_ci .reg_bits = 8, 668c2ecf20Sopenharmony_ci .val_bits = 32, 678c2ecf20Sopenharmony_ci .reg_stride = 4, 688c2ecf20Sopenharmony_ci .max_register = PHY_R5, 698c2ecf20Sopenharmony_ci}; 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_cistatic int phy_g12a_usb3_pcie_cr_bus_addr(struct phy_g12a_usb3_pcie_priv *priv, 728c2ecf20Sopenharmony_ci unsigned int addr) 738c2ecf20Sopenharmony_ci{ 748c2ecf20Sopenharmony_ci unsigned int val, reg; 758c2ecf20Sopenharmony_ci int ret; 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_ci reg = FIELD_PREP(PHY_R4_PHY_CR_DATA_IN, addr); 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_ci regmap_write(priv->regmap, PHY_R4, reg); 808c2ecf20Sopenharmony_ci regmap_write(priv->regmap, PHY_R4, reg); 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_ci regmap_write(priv->regmap, PHY_R4, reg | PHY_R4_PHY_CR_CAP_ADDR); 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_ci ret = regmap_read_poll_timeout(priv->regmap, PHY_R5, val, 858c2ecf20Sopenharmony_ci (val & PHY_R5_PHY_CR_ACK), 868c2ecf20Sopenharmony_ci 5, 1000); 878c2ecf20Sopenharmony_ci if (ret) 888c2ecf20Sopenharmony_ci return ret; 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_ci regmap_write(priv->regmap, PHY_R4, reg); 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_ci ret = regmap_read_poll_timeout(priv->regmap, PHY_R5, val, 938c2ecf20Sopenharmony_ci !(val & PHY_R5_PHY_CR_ACK), 948c2ecf20Sopenharmony_ci 5, 1000); 958c2ecf20Sopenharmony_ci if (ret) 968c2ecf20Sopenharmony_ci return ret; 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_ci return 0; 998c2ecf20Sopenharmony_ci} 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_cistatic int phy_g12a_usb3_pcie_cr_bus_read(void *context, unsigned int addr, 1028c2ecf20Sopenharmony_ci unsigned int *data) 1038c2ecf20Sopenharmony_ci{ 1048c2ecf20Sopenharmony_ci struct phy_g12a_usb3_pcie_priv *priv = context; 1058c2ecf20Sopenharmony_ci unsigned int val; 1068c2ecf20Sopenharmony_ci int ret; 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_ci ret = phy_g12a_usb3_pcie_cr_bus_addr(priv, addr); 1098c2ecf20Sopenharmony_ci if (ret) 1108c2ecf20Sopenharmony_ci return ret; 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_ci regmap_write(priv->regmap, PHY_R4, 0); 1138c2ecf20Sopenharmony_ci regmap_write(priv->regmap, PHY_R4, PHY_R4_PHY_CR_READ); 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_ci ret = regmap_read_poll_timeout(priv->regmap, PHY_R5, val, 1168c2ecf20Sopenharmony_ci (val & PHY_R5_PHY_CR_ACK), 1178c2ecf20Sopenharmony_ci 5, 1000); 1188c2ecf20Sopenharmony_ci if (ret) 1198c2ecf20Sopenharmony_ci return ret; 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_ci *data = FIELD_GET(PHY_R5_PHY_CR_DATA_OUT, val); 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_ci regmap_write(priv->regmap, PHY_R4, 0); 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_ci ret = regmap_read_poll_timeout(priv->regmap, PHY_R5, val, 1268c2ecf20Sopenharmony_ci !(val & PHY_R5_PHY_CR_ACK), 1278c2ecf20Sopenharmony_ci 5, 1000); 1288c2ecf20Sopenharmony_ci if (ret) 1298c2ecf20Sopenharmony_ci return ret; 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_ci return 0; 1328c2ecf20Sopenharmony_ci} 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_cistatic int phy_g12a_usb3_pcie_cr_bus_write(void *context, unsigned int addr, 1358c2ecf20Sopenharmony_ci unsigned int data) 1368c2ecf20Sopenharmony_ci{ 1378c2ecf20Sopenharmony_ci struct phy_g12a_usb3_pcie_priv *priv = context; 1388c2ecf20Sopenharmony_ci unsigned int val, reg; 1398c2ecf20Sopenharmony_ci int ret; 1408c2ecf20Sopenharmony_ci 1418c2ecf20Sopenharmony_ci ret = phy_g12a_usb3_pcie_cr_bus_addr(priv, addr); 1428c2ecf20Sopenharmony_ci if (ret) 1438c2ecf20Sopenharmony_ci return ret; 1448c2ecf20Sopenharmony_ci 1458c2ecf20Sopenharmony_ci reg = FIELD_PREP(PHY_R4_PHY_CR_DATA_IN, data); 1468c2ecf20Sopenharmony_ci 1478c2ecf20Sopenharmony_ci regmap_write(priv->regmap, PHY_R4, reg); 1488c2ecf20Sopenharmony_ci regmap_write(priv->regmap, PHY_R4, reg); 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_ci regmap_write(priv->regmap, PHY_R4, reg | PHY_R4_PHY_CR_CAP_DATA); 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_ci ret = regmap_read_poll_timeout(priv->regmap, PHY_R5, val, 1538c2ecf20Sopenharmony_ci (val & PHY_R5_PHY_CR_ACK), 1548c2ecf20Sopenharmony_ci 5, 1000); 1558c2ecf20Sopenharmony_ci if (ret) 1568c2ecf20Sopenharmony_ci return ret; 1578c2ecf20Sopenharmony_ci 1588c2ecf20Sopenharmony_ci regmap_write(priv->regmap, PHY_R4, reg); 1598c2ecf20Sopenharmony_ci 1608c2ecf20Sopenharmony_ci ret = regmap_read_poll_timeout(priv->regmap, PHY_R5, val, 1618c2ecf20Sopenharmony_ci (val & PHY_R5_PHY_CR_ACK) == 0, 1628c2ecf20Sopenharmony_ci 5, 1000); 1638c2ecf20Sopenharmony_ci if (ret) 1648c2ecf20Sopenharmony_ci return ret; 1658c2ecf20Sopenharmony_ci 1668c2ecf20Sopenharmony_ci regmap_write(priv->regmap, PHY_R4, reg); 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_ci regmap_write(priv->regmap, PHY_R4, reg | PHY_R4_PHY_CR_WRITE); 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_ci ret = regmap_read_poll_timeout(priv->regmap, PHY_R5, val, 1718c2ecf20Sopenharmony_ci (val & PHY_R5_PHY_CR_ACK), 1728c2ecf20Sopenharmony_ci 5, 1000); 1738c2ecf20Sopenharmony_ci if (ret) 1748c2ecf20Sopenharmony_ci return ret; 1758c2ecf20Sopenharmony_ci 1768c2ecf20Sopenharmony_ci regmap_write(priv->regmap, PHY_R4, reg); 1778c2ecf20Sopenharmony_ci 1788c2ecf20Sopenharmony_ci ret = regmap_read_poll_timeout(priv->regmap, PHY_R5, val, 1798c2ecf20Sopenharmony_ci (val & PHY_R5_PHY_CR_ACK) == 0, 1808c2ecf20Sopenharmony_ci 5, 1000); 1818c2ecf20Sopenharmony_ci if (ret) 1828c2ecf20Sopenharmony_ci return ret; 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_ci return 0; 1858c2ecf20Sopenharmony_ci} 1868c2ecf20Sopenharmony_ci 1878c2ecf20Sopenharmony_cistatic const struct regmap_config phy_g12a_usb3_pcie_cr_regmap_conf = { 1888c2ecf20Sopenharmony_ci .reg_bits = 16, 1898c2ecf20Sopenharmony_ci .val_bits = 16, 1908c2ecf20Sopenharmony_ci .reg_read = phy_g12a_usb3_pcie_cr_bus_read, 1918c2ecf20Sopenharmony_ci .reg_write = phy_g12a_usb3_pcie_cr_bus_write, 1928c2ecf20Sopenharmony_ci .max_register = 0xffff, 1938c2ecf20Sopenharmony_ci .disable_locking = true, 1948c2ecf20Sopenharmony_ci}; 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_cistatic int phy_g12a_usb3_init(struct phy *phy) 1978c2ecf20Sopenharmony_ci{ 1988c2ecf20Sopenharmony_ci struct phy_g12a_usb3_pcie_priv *priv = phy_get_drvdata(phy); 1998c2ecf20Sopenharmony_ci int data, ret; 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_ci ret = reset_control_reset(priv->reset); 2028c2ecf20Sopenharmony_ci if (ret) 2038c2ecf20Sopenharmony_ci return ret; 2048c2ecf20Sopenharmony_ci 2058c2ecf20Sopenharmony_ci /* Switch PHY to USB3 */ 2068c2ecf20Sopenharmony_ci /* TODO figure out how to handle when PCIe was set in the bootloader */ 2078c2ecf20Sopenharmony_ci regmap_update_bits(priv->regmap, PHY_R0, 2088c2ecf20Sopenharmony_ci PHY_R0_PCIE_USB3_SWITCH, 2098c2ecf20Sopenharmony_ci PHY_R0_PCIE_USB3_SWITCH); 2108c2ecf20Sopenharmony_ci 2118c2ecf20Sopenharmony_ci /* 2128c2ecf20Sopenharmony_ci * WORKAROUND: There is SSPHY suspend bug due to 2138c2ecf20Sopenharmony_ci * which USB enumerates 2148c2ecf20Sopenharmony_ci * in HS mode instead of SS mode. Workaround it by asserting 2158c2ecf20Sopenharmony_ci * LANE0.TX_ALT_BLOCK.EN_ALT_BUS to enable TX to use alt bus 2168c2ecf20Sopenharmony_ci * mode 2178c2ecf20Sopenharmony_ci */ 2188c2ecf20Sopenharmony_ci ret = regmap_update_bits(priv->regmap_cr, 0x102d, BIT(7), BIT(7)); 2198c2ecf20Sopenharmony_ci if (ret) 2208c2ecf20Sopenharmony_ci return ret; 2218c2ecf20Sopenharmony_ci 2228c2ecf20Sopenharmony_ci ret = regmap_update_bits(priv->regmap_cr, 0x1010, 0xff0, 20); 2238c2ecf20Sopenharmony_ci if (ret) 2248c2ecf20Sopenharmony_ci return ret; 2258c2ecf20Sopenharmony_ci 2268c2ecf20Sopenharmony_ci /* 2278c2ecf20Sopenharmony_ci * Fix RX Equalization setting as follows 2288c2ecf20Sopenharmony_ci * LANE0.RX_OVRD_IN_HI. RX_EQ_EN set to 0 2298c2ecf20Sopenharmony_ci * LANE0.RX_OVRD_IN_HI.RX_EQ_EN_OVRD set to 1 2308c2ecf20Sopenharmony_ci * LANE0.RX_OVRD_IN_HI.RX_EQ set to 3 2318c2ecf20Sopenharmony_ci * LANE0.RX_OVRD_IN_HI.RX_EQ_OVRD set to 1 2328c2ecf20Sopenharmony_ci */ 2338c2ecf20Sopenharmony_ci ret = regmap_read(priv->regmap_cr, 0x1006, &data); 2348c2ecf20Sopenharmony_ci if (ret) 2358c2ecf20Sopenharmony_ci return ret; 2368c2ecf20Sopenharmony_ci 2378c2ecf20Sopenharmony_ci data &= ~BIT(6); 2388c2ecf20Sopenharmony_ci data |= BIT(7); 2398c2ecf20Sopenharmony_ci data &= ~(0x7 << 8); 2408c2ecf20Sopenharmony_ci data |= (0x3 << 8); 2418c2ecf20Sopenharmony_ci data |= (1 << 11); 2428c2ecf20Sopenharmony_ci ret = regmap_write(priv->regmap_cr, 0x1006, data); 2438c2ecf20Sopenharmony_ci if (ret) 2448c2ecf20Sopenharmony_ci return ret; 2458c2ecf20Sopenharmony_ci 2468c2ecf20Sopenharmony_ci /* 2478c2ecf20Sopenharmony_ci * Set EQ and TX launch amplitudes as follows 2488c2ecf20Sopenharmony_ci * LANE0.TX_OVRD_DRV_LO.PREEMPH set to 22 2498c2ecf20Sopenharmony_ci * LANE0.TX_OVRD_DRV_LO.AMPLITUDE set to 127 2508c2ecf20Sopenharmony_ci * LANE0.TX_OVRD_DRV_LO.EN set to 1. 2518c2ecf20Sopenharmony_ci */ 2528c2ecf20Sopenharmony_ci ret = regmap_read(priv->regmap_cr, 0x1002, &data); 2538c2ecf20Sopenharmony_ci if (ret) 2548c2ecf20Sopenharmony_ci return ret; 2558c2ecf20Sopenharmony_ci 2568c2ecf20Sopenharmony_ci data &= ~0x3f80; 2578c2ecf20Sopenharmony_ci data |= (0x16 << 7); 2588c2ecf20Sopenharmony_ci data &= ~0x7f; 2598c2ecf20Sopenharmony_ci data |= (0x7f | BIT(14)); 2608c2ecf20Sopenharmony_ci ret = regmap_write(priv->regmap_cr, 0x1002, data); 2618c2ecf20Sopenharmony_ci if (ret) 2628c2ecf20Sopenharmony_ci return ret; 2638c2ecf20Sopenharmony_ci 2648c2ecf20Sopenharmony_ci /* MPLL_LOOP_CTL.PROP_CNTRL = 8 */ 2658c2ecf20Sopenharmony_ci ret = regmap_update_bits(priv->regmap_cr, 0x30, 0xf << 4, 8 << 4); 2668c2ecf20Sopenharmony_ci if (ret) 2678c2ecf20Sopenharmony_ci return ret; 2688c2ecf20Sopenharmony_ci 2698c2ecf20Sopenharmony_ci regmap_update_bits(priv->regmap, PHY_R2, 2708c2ecf20Sopenharmony_ci PHY_R2_PHY_TX_VBOOST_LVL, 2718c2ecf20Sopenharmony_ci FIELD_PREP(PHY_R2_PHY_TX_VBOOST_LVL, 0x4)); 2728c2ecf20Sopenharmony_ci 2738c2ecf20Sopenharmony_ci regmap_update_bits(priv->regmap, PHY_R1, 2748c2ecf20Sopenharmony_ci PHY_R1_PHY_LOS_BIAS | PHY_R1_PHY_LOS_LEVEL, 2758c2ecf20Sopenharmony_ci FIELD_PREP(PHY_R1_PHY_LOS_BIAS, 4) | 2768c2ecf20Sopenharmony_ci FIELD_PREP(PHY_R1_PHY_LOS_LEVEL, 9)); 2778c2ecf20Sopenharmony_ci 2788c2ecf20Sopenharmony_ci return 0; 2798c2ecf20Sopenharmony_ci} 2808c2ecf20Sopenharmony_ci 2818c2ecf20Sopenharmony_cistatic int phy_g12a_usb3_pcie_power_on(struct phy *phy) 2828c2ecf20Sopenharmony_ci{ 2838c2ecf20Sopenharmony_ci struct phy_g12a_usb3_pcie_priv *priv = phy_get_drvdata(phy); 2848c2ecf20Sopenharmony_ci 2858c2ecf20Sopenharmony_ci if (priv->mode == PHY_TYPE_USB3) 2868c2ecf20Sopenharmony_ci return 0; 2878c2ecf20Sopenharmony_ci 2888c2ecf20Sopenharmony_ci regmap_update_bits(priv->regmap, PHY_R0, 2898c2ecf20Sopenharmony_ci PHY_R0_PCIE_POWER_STATE, 2908c2ecf20Sopenharmony_ci FIELD_PREP(PHY_R0_PCIE_POWER_STATE, 0x1c)); 2918c2ecf20Sopenharmony_ci 2928c2ecf20Sopenharmony_ci return 0; 2938c2ecf20Sopenharmony_ci} 2948c2ecf20Sopenharmony_ci 2958c2ecf20Sopenharmony_cistatic int phy_g12a_usb3_pcie_power_off(struct phy *phy) 2968c2ecf20Sopenharmony_ci{ 2978c2ecf20Sopenharmony_ci struct phy_g12a_usb3_pcie_priv *priv = phy_get_drvdata(phy); 2988c2ecf20Sopenharmony_ci 2998c2ecf20Sopenharmony_ci if (priv->mode == PHY_TYPE_USB3) 3008c2ecf20Sopenharmony_ci return 0; 3018c2ecf20Sopenharmony_ci 3028c2ecf20Sopenharmony_ci regmap_update_bits(priv->regmap, PHY_R0, 3038c2ecf20Sopenharmony_ci PHY_R0_PCIE_POWER_STATE, 3048c2ecf20Sopenharmony_ci FIELD_PREP(PHY_R0_PCIE_POWER_STATE, 0x1d)); 3058c2ecf20Sopenharmony_ci 3068c2ecf20Sopenharmony_ci return 0; 3078c2ecf20Sopenharmony_ci} 3088c2ecf20Sopenharmony_ci 3098c2ecf20Sopenharmony_cistatic int phy_g12a_usb3_pcie_reset(struct phy *phy) 3108c2ecf20Sopenharmony_ci{ 3118c2ecf20Sopenharmony_ci struct phy_g12a_usb3_pcie_priv *priv = phy_get_drvdata(phy); 3128c2ecf20Sopenharmony_ci int ret; 3138c2ecf20Sopenharmony_ci 3148c2ecf20Sopenharmony_ci if (priv->mode == PHY_TYPE_USB3) 3158c2ecf20Sopenharmony_ci return 0; 3168c2ecf20Sopenharmony_ci 3178c2ecf20Sopenharmony_ci ret = reset_control_assert(priv->reset); 3188c2ecf20Sopenharmony_ci if (ret) 3198c2ecf20Sopenharmony_ci return ret; 3208c2ecf20Sopenharmony_ci 3218c2ecf20Sopenharmony_ci udelay(PCIE_RESET_DELAY); 3228c2ecf20Sopenharmony_ci 3238c2ecf20Sopenharmony_ci ret = reset_control_deassert(priv->reset); 3248c2ecf20Sopenharmony_ci if (ret) 3258c2ecf20Sopenharmony_ci return ret; 3268c2ecf20Sopenharmony_ci 3278c2ecf20Sopenharmony_ci udelay(PCIE_RESET_DELAY); 3288c2ecf20Sopenharmony_ci 3298c2ecf20Sopenharmony_ci return 0; 3308c2ecf20Sopenharmony_ci} 3318c2ecf20Sopenharmony_ci 3328c2ecf20Sopenharmony_cistatic int phy_g12a_usb3_pcie_init(struct phy *phy) 3338c2ecf20Sopenharmony_ci{ 3348c2ecf20Sopenharmony_ci struct phy_g12a_usb3_pcie_priv *priv = phy_get_drvdata(phy); 3358c2ecf20Sopenharmony_ci 3368c2ecf20Sopenharmony_ci if (priv->mode == PHY_TYPE_USB3) 3378c2ecf20Sopenharmony_ci return phy_g12a_usb3_init(phy); 3388c2ecf20Sopenharmony_ci 3398c2ecf20Sopenharmony_ci return 0; 3408c2ecf20Sopenharmony_ci} 3418c2ecf20Sopenharmony_ci 3428c2ecf20Sopenharmony_cistatic int phy_g12a_usb3_pcie_exit(struct phy *phy) 3438c2ecf20Sopenharmony_ci{ 3448c2ecf20Sopenharmony_ci struct phy_g12a_usb3_pcie_priv *priv = phy_get_drvdata(phy); 3458c2ecf20Sopenharmony_ci 3468c2ecf20Sopenharmony_ci if (priv->mode == PHY_TYPE_USB3) 3478c2ecf20Sopenharmony_ci return reset_control_reset(priv->reset); 3488c2ecf20Sopenharmony_ci 3498c2ecf20Sopenharmony_ci return 0; 3508c2ecf20Sopenharmony_ci} 3518c2ecf20Sopenharmony_ci 3528c2ecf20Sopenharmony_cistatic struct phy *phy_g12a_usb3_pcie_xlate(struct device *dev, 3538c2ecf20Sopenharmony_ci struct of_phandle_args *args) 3548c2ecf20Sopenharmony_ci{ 3558c2ecf20Sopenharmony_ci struct phy_g12a_usb3_pcie_priv *priv = dev_get_drvdata(dev); 3568c2ecf20Sopenharmony_ci unsigned int mode; 3578c2ecf20Sopenharmony_ci 3588c2ecf20Sopenharmony_ci if (args->args_count < 1) { 3598c2ecf20Sopenharmony_ci dev_err(dev, "invalid number of arguments\n"); 3608c2ecf20Sopenharmony_ci return ERR_PTR(-EINVAL); 3618c2ecf20Sopenharmony_ci } 3628c2ecf20Sopenharmony_ci 3638c2ecf20Sopenharmony_ci mode = args->args[0]; 3648c2ecf20Sopenharmony_ci 3658c2ecf20Sopenharmony_ci if (mode != PHY_TYPE_USB3 && mode != PHY_TYPE_PCIE) { 3668c2ecf20Sopenharmony_ci dev_err(dev, "invalid phy mode select argument\n"); 3678c2ecf20Sopenharmony_ci return ERR_PTR(-EINVAL); 3688c2ecf20Sopenharmony_ci } 3698c2ecf20Sopenharmony_ci 3708c2ecf20Sopenharmony_ci priv->mode = mode; 3718c2ecf20Sopenharmony_ci 3728c2ecf20Sopenharmony_ci return priv->phy; 3738c2ecf20Sopenharmony_ci} 3748c2ecf20Sopenharmony_ci 3758c2ecf20Sopenharmony_cistatic const struct phy_ops phy_g12a_usb3_pcie_ops = { 3768c2ecf20Sopenharmony_ci .init = phy_g12a_usb3_pcie_init, 3778c2ecf20Sopenharmony_ci .exit = phy_g12a_usb3_pcie_exit, 3788c2ecf20Sopenharmony_ci .power_on = phy_g12a_usb3_pcie_power_on, 3798c2ecf20Sopenharmony_ci .power_off = phy_g12a_usb3_pcie_power_off, 3808c2ecf20Sopenharmony_ci .reset = phy_g12a_usb3_pcie_reset, 3818c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 3828c2ecf20Sopenharmony_ci}; 3838c2ecf20Sopenharmony_ci 3848c2ecf20Sopenharmony_cistatic int phy_g12a_usb3_pcie_probe(struct platform_device *pdev) 3858c2ecf20Sopenharmony_ci{ 3868c2ecf20Sopenharmony_ci struct device *dev = &pdev->dev; 3878c2ecf20Sopenharmony_ci struct device_node *np = dev->of_node; 3888c2ecf20Sopenharmony_ci struct phy_g12a_usb3_pcie_priv *priv; 3898c2ecf20Sopenharmony_ci struct resource *res; 3908c2ecf20Sopenharmony_ci struct phy_provider *phy_provider; 3918c2ecf20Sopenharmony_ci void __iomem *base; 3928c2ecf20Sopenharmony_ci int ret; 3938c2ecf20Sopenharmony_ci 3948c2ecf20Sopenharmony_ci priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); 3958c2ecf20Sopenharmony_ci if (!priv) 3968c2ecf20Sopenharmony_ci return -ENOMEM; 3978c2ecf20Sopenharmony_ci 3988c2ecf20Sopenharmony_ci res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 3998c2ecf20Sopenharmony_ci base = devm_ioremap_resource(dev, res); 4008c2ecf20Sopenharmony_ci if (IS_ERR(base)) 4018c2ecf20Sopenharmony_ci return PTR_ERR(base); 4028c2ecf20Sopenharmony_ci 4038c2ecf20Sopenharmony_ci priv->regmap = devm_regmap_init_mmio(dev, base, 4048c2ecf20Sopenharmony_ci &phy_g12a_usb3_pcie_regmap_conf); 4058c2ecf20Sopenharmony_ci if (IS_ERR(priv->regmap)) 4068c2ecf20Sopenharmony_ci return PTR_ERR(priv->regmap); 4078c2ecf20Sopenharmony_ci 4088c2ecf20Sopenharmony_ci priv->regmap_cr = devm_regmap_init(dev, NULL, priv, 4098c2ecf20Sopenharmony_ci &phy_g12a_usb3_pcie_cr_regmap_conf); 4108c2ecf20Sopenharmony_ci if (IS_ERR(priv->regmap_cr)) 4118c2ecf20Sopenharmony_ci return PTR_ERR(priv->regmap_cr); 4128c2ecf20Sopenharmony_ci 4138c2ecf20Sopenharmony_ci priv->clk_ref = devm_clk_get(dev, "ref_clk"); 4148c2ecf20Sopenharmony_ci if (IS_ERR(priv->clk_ref)) 4158c2ecf20Sopenharmony_ci return PTR_ERR(priv->clk_ref); 4168c2ecf20Sopenharmony_ci 4178c2ecf20Sopenharmony_ci ret = clk_prepare_enable(priv->clk_ref); 4188c2ecf20Sopenharmony_ci if (ret) 4198c2ecf20Sopenharmony_ci goto err_disable_clk_ref; 4208c2ecf20Sopenharmony_ci 4218c2ecf20Sopenharmony_ci priv->reset = devm_reset_control_array_get(dev, false, false); 4228c2ecf20Sopenharmony_ci if (IS_ERR(priv->reset)) 4238c2ecf20Sopenharmony_ci return PTR_ERR(priv->reset); 4248c2ecf20Sopenharmony_ci 4258c2ecf20Sopenharmony_ci priv->phy = devm_phy_create(dev, np, &phy_g12a_usb3_pcie_ops); 4268c2ecf20Sopenharmony_ci if (IS_ERR(priv->phy)) { 4278c2ecf20Sopenharmony_ci ret = PTR_ERR(priv->phy); 4288c2ecf20Sopenharmony_ci if (ret != -EPROBE_DEFER) 4298c2ecf20Sopenharmony_ci dev_err(dev, "failed to create PHY\n"); 4308c2ecf20Sopenharmony_ci 4318c2ecf20Sopenharmony_ci return ret; 4328c2ecf20Sopenharmony_ci } 4338c2ecf20Sopenharmony_ci 4348c2ecf20Sopenharmony_ci phy_set_drvdata(priv->phy, priv); 4358c2ecf20Sopenharmony_ci dev_set_drvdata(dev, priv); 4368c2ecf20Sopenharmony_ci 4378c2ecf20Sopenharmony_ci phy_provider = devm_of_phy_provider_register(dev, 4388c2ecf20Sopenharmony_ci phy_g12a_usb3_pcie_xlate); 4398c2ecf20Sopenharmony_ci 4408c2ecf20Sopenharmony_ci return PTR_ERR_OR_ZERO(phy_provider); 4418c2ecf20Sopenharmony_ci 4428c2ecf20Sopenharmony_cierr_disable_clk_ref: 4438c2ecf20Sopenharmony_ci clk_disable_unprepare(priv->clk_ref); 4448c2ecf20Sopenharmony_ci 4458c2ecf20Sopenharmony_ci return ret; 4468c2ecf20Sopenharmony_ci} 4478c2ecf20Sopenharmony_ci 4488c2ecf20Sopenharmony_cistatic const struct of_device_id phy_g12a_usb3_pcie_of_match[] = { 4498c2ecf20Sopenharmony_ci { .compatible = "amlogic,g12a-usb3-pcie-phy", }, 4508c2ecf20Sopenharmony_ci { }, 4518c2ecf20Sopenharmony_ci}; 4528c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, phy_g12a_usb3_pcie_of_match); 4538c2ecf20Sopenharmony_ci 4548c2ecf20Sopenharmony_cistatic struct platform_driver phy_g12a_usb3_pcie_driver = { 4558c2ecf20Sopenharmony_ci .probe = phy_g12a_usb3_pcie_probe, 4568c2ecf20Sopenharmony_ci .driver = { 4578c2ecf20Sopenharmony_ci .name = "phy-g12a-usb3-pcie", 4588c2ecf20Sopenharmony_ci .of_match_table = phy_g12a_usb3_pcie_of_match, 4598c2ecf20Sopenharmony_ci }, 4608c2ecf20Sopenharmony_ci}; 4618c2ecf20Sopenharmony_cimodule_platform_driver(phy_g12a_usb3_pcie_driver); 4628c2ecf20Sopenharmony_ci 4638c2ecf20Sopenharmony_ciMODULE_AUTHOR("Neil Armstrong <narmstrong@baylibre.com>"); 4648c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Amlogic G12A USB3 + PCIE Combo PHY driver"); 4658c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2"); 466