136077e16SNeil Armstrong // SPDX-License-Identifier: GPL-2.0 236077e16SNeil Armstrong /* 336077e16SNeil Armstrong * Amlogic G12A USB3 + PCIE Combo PHY driver 436077e16SNeil Armstrong * 536077e16SNeil Armstrong * Copyright (C) 2017 Amlogic, Inc. All rights reserved 636077e16SNeil Armstrong * Copyright (C) 2019 BayLibre, SAS 736077e16SNeil Armstrong * Author: Neil Armstrong <narmstrong@baylibre.com> 836077e16SNeil Armstrong */ 936077e16SNeil Armstrong 1036077e16SNeil Armstrong #include <linux/bitfield.h> 1136077e16SNeil Armstrong #include <linux/bitops.h> 1236077e16SNeil Armstrong #include <linux/clk.h> 1336077e16SNeil Armstrong #include <linux/module.h> 1436077e16SNeil Armstrong #include <linux/of_device.h> 1536077e16SNeil Armstrong #include <linux/phy/phy.h> 1636077e16SNeil Armstrong #include <linux/regmap.h> 1736077e16SNeil Armstrong #include <linux/reset.h> 1836077e16SNeil Armstrong #include <linux/platform_device.h> 1936077e16SNeil Armstrong #include <dt-bindings/phy/phy.h> 2036077e16SNeil Armstrong 2136077e16SNeil Armstrong #define PHY_R0 0x00 2236077e16SNeil Armstrong #define PHY_R0_PCIE_POWER_STATE GENMASK(4, 0) 2336077e16SNeil Armstrong #define PHY_R0_PCIE_USB3_SWITCH GENMASK(6, 5) 2436077e16SNeil Armstrong 2536077e16SNeil Armstrong #define PHY_R1 0x04 2636077e16SNeil Armstrong #define PHY_R1_PHY_TX1_TERM_OFFSET GENMASK(4, 0) 2736077e16SNeil Armstrong #define PHY_R1_PHY_TX0_TERM_OFFSET GENMASK(9, 5) 2836077e16SNeil Armstrong #define PHY_R1_PHY_RX1_EQ GENMASK(12, 10) 2936077e16SNeil Armstrong #define PHY_R1_PHY_RX0_EQ GENMASK(15, 13) 3036077e16SNeil Armstrong #define PHY_R1_PHY_LOS_LEVEL GENMASK(20, 16) 3136077e16SNeil Armstrong #define PHY_R1_PHY_LOS_BIAS GENMASK(23, 21) 3236077e16SNeil Armstrong #define PHY_R1_PHY_REF_CLKDIV2 BIT(24) 3336077e16SNeil Armstrong #define PHY_R1_PHY_MPLL_MULTIPLIER GENMASK(31, 25) 3436077e16SNeil Armstrong 3536077e16SNeil Armstrong #define PHY_R2 0x08 3636077e16SNeil Armstrong #define PHY_R2_PCS_TX_DEEMPH_GEN2_6DB GENMASK(5, 0) 3736077e16SNeil Armstrong #define PHY_R2_PCS_TX_DEEMPH_GEN2_3P5DB GENMASK(11, 6) 3836077e16SNeil Armstrong #define PHY_R2_PCS_TX_DEEMPH_GEN1 GENMASK(17, 12) 3936077e16SNeil Armstrong #define PHY_R2_PHY_TX_VBOOST_LVL GENMASK(20, 18) 4036077e16SNeil Armstrong 4136077e16SNeil Armstrong #define PHY_R4 0x10 4236077e16SNeil Armstrong #define PHY_R4_PHY_CR_WRITE BIT(0) 4336077e16SNeil Armstrong #define PHY_R4_PHY_CR_READ BIT(1) 4436077e16SNeil Armstrong #define PHY_R4_PHY_CR_DATA_IN GENMASK(17, 2) 4536077e16SNeil Armstrong #define PHY_R4_PHY_CR_CAP_DATA BIT(18) 4636077e16SNeil Armstrong #define PHY_R4_PHY_CR_CAP_ADDR BIT(19) 4736077e16SNeil Armstrong 4836077e16SNeil Armstrong #define PHY_R5 0x14 4936077e16SNeil Armstrong #define PHY_R5_PHY_CR_DATA_OUT GENMASK(15, 0) 5036077e16SNeil Armstrong #define PHY_R5_PHY_CR_ACK BIT(16) 5136077e16SNeil Armstrong #define PHY_R5_PHY_BS_OUT BIT(17) 5236077e16SNeil Armstrong 5363162725SNeil Armstrong #define PCIE_RESET_DELAY 500 5463162725SNeil Armstrong 5536077e16SNeil Armstrong struct phy_g12a_usb3_pcie_priv { 5636077e16SNeil Armstrong struct regmap *regmap; 5736077e16SNeil Armstrong struct regmap *regmap_cr; 5836077e16SNeil Armstrong struct clk *clk_ref; 5936077e16SNeil Armstrong struct reset_control *reset; 6036077e16SNeil Armstrong struct phy *phy; 6136077e16SNeil Armstrong unsigned int mode; 6236077e16SNeil Armstrong }; 6336077e16SNeil Armstrong 6436077e16SNeil Armstrong static const struct regmap_config phy_g12a_usb3_pcie_regmap_conf = { 6536077e16SNeil Armstrong .reg_bits = 8, 6636077e16SNeil Armstrong .val_bits = 32, 6736077e16SNeil Armstrong .reg_stride = 4, 6836077e16SNeil Armstrong .max_register = PHY_R5, 6936077e16SNeil Armstrong }; 7036077e16SNeil Armstrong 7136077e16SNeil Armstrong static int phy_g12a_usb3_pcie_cr_bus_addr(struct phy_g12a_usb3_pcie_priv *priv, 7236077e16SNeil Armstrong unsigned int addr) 7336077e16SNeil Armstrong { 7436077e16SNeil Armstrong unsigned int val, reg; 7536077e16SNeil Armstrong int ret; 7636077e16SNeil Armstrong 7736077e16SNeil Armstrong reg = FIELD_PREP(PHY_R4_PHY_CR_DATA_IN, addr); 7836077e16SNeil Armstrong 7936077e16SNeil Armstrong regmap_write(priv->regmap, PHY_R4, reg); 8036077e16SNeil Armstrong regmap_write(priv->regmap, PHY_R4, reg); 8136077e16SNeil Armstrong 8236077e16SNeil Armstrong regmap_write(priv->regmap, PHY_R4, reg | PHY_R4_PHY_CR_CAP_ADDR); 8336077e16SNeil Armstrong 8436077e16SNeil Armstrong ret = regmap_read_poll_timeout(priv->regmap, PHY_R5, val, 8536077e16SNeil Armstrong (val & PHY_R5_PHY_CR_ACK), 8636077e16SNeil Armstrong 5, 1000); 8736077e16SNeil Armstrong if (ret) 8836077e16SNeil Armstrong return ret; 8936077e16SNeil Armstrong 9036077e16SNeil Armstrong regmap_write(priv->regmap, PHY_R4, reg); 9136077e16SNeil Armstrong 9236077e16SNeil Armstrong ret = regmap_read_poll_timeout(priv->regmap, PHY_R5, val, 9336077e16SNeil Armstrong !(val & PHY_R5_PHY_CR_ACK), 9436077e16SNeil Armstrong 5, 1000); 9536077e16SNeil Armstrong if (ret) 9636077e16SNeil Armstrong return ret; 9736077e16SNeil Armstrong 9836077e16SNeil Armstrong return 0; 9936077e16SNeil Armstrong } 10036077e16SNeil Armstrong 10136077e16SNeil Armstrong static int phy_g12a_usb3_pcie_cr_bus_read(void *context, unsigned int addr, 10236077e16SNeil Armstrong unsigned int *data) 10336077e16SNeil Armstrong { 10436077e16SNeil Armstrong struct phy_g12a_usb3_pcie_priv *priv = context; 10536077e16SNeil Armstrong unsigned int val; 10636077e16SNeil Armstrong int ret; 10736077e16SNeil Armstrong 10836077e16SNeil Armstrong ret = phy_g12a_usb3_pcie_cr_bus_addr(priv, addr); 10936077e16SNeil Armstrong if (ret) 11036077e16SNeil Armstrong return ret; 11136077e16SNeil Armstrong 11236077e16SNeil Armstrong regmap_write(priv->regmap, PHY_R4, 0); 11336077e16SNeil Armstrong regmap_write(priv->regmap, PHY_R4, PHY_R4_PHY_CR_READ); 11436077e16SNeil Armstrong 11536077e16SNeil Armstrong ret = regmap_read_poll_timeout(priv->regmap, PHY_R5, val, 11636077e16SNeil Armstrong (val & PHY_R5_PHY_CR_ACK), 11736077e16SNeil Armstrong 5, 1000); 11836077e16SNeil Armstrong if (ret) 11936077e16SNeil Armstrong return ret; 12036077e16SNeil Armstrong 12136077e16SNeil Armstrong *data = FIELD_GET(PHY_R5_PHY_CR_DATA_OUT, val); 12236077e16SNeil Armstrong 12336077e16SNeil Armstrong regmap_write(priv->regmap, PHY_R4, 0); 12436077e16SNeil Armstrong 12536077e16SNeil Armstrong ret = regmap_read_poll_timeout(priv->regmap, PHY_R5, val, 12636077e16SNeil Armstrong !(val & PHY_R5_PHY_CR_ACK), 12736077e16SNeil Armstrong 5, 1000); 12836077e16SNeil Armstrong if (ret) 12936077e16SNeil Armstrong return ret; 13036077e16SNeil Armstrong 13136077e16SNeil Armstrong return 0; 13236077e16SNeil Armstrong } 13336077e16SNeil Armstrong 13436077e16SNeil Armstrong static int phy_g12a_usb3_pcie_cr_bus_write(void *context, unsigned int addr, 13536077e16SNeil Armstrong unsigned int data) 13636077e16SNeil Armstrong { 13736077e16SNeil Armstrong struct phy_g12a_usb3_pcie_priv *priv = context; 13836077e16SNeil Armstrong unsigned int val, reg; 13936077e16SNeil Armstrong int ret; 14036077e16SNeil Armstrong 14136077e16SNeil Armstrong ret = phy_g12a_usb3_pcie_cr_bus_addr(priv, addr); 14236077e16SNeil Armstrong if (ret) 14336077e16SNeil Armstrong return ret; 14436077e16SNeil Armstrong 14536077e16SNeil Armstrong reg = FIELD_PREP(PHY_R4_PHY_CR_DATA_IN, data); 14636077e16SNeil Armstrong 14736077e16SNeil Armstrong regmap_write(priv->regmap, PHY_R4, reg); 14836077e16SNeil Armstrong regmap_write(priv->regmap, PHY_R4, reg); 14936077e16SNeil Armstrong 15036077e16SNeil Armstrong regmap_write(priv->regmap, PHY_R4, reg | PHY_R4_PHY_CR_CAP_DATA); 15136077e16SNeil Armstrong 15236077e16SNeil Armstrong ret = regmap_read_poll_timeout(priv->regmap, PHY_R5, val, 15336077e16SNeil Armstrong (val & PHY_R5_PHY_CR_ACK), 15436077e16SNeil Armstrong 5, 1000); 15536077e16SNeil Armstrong if (ret) 15636077e16SNeil Armstrong return ret; 15736077e16SNeil Armstrong 15836077e16SNeil Armstrong regmap_write(priv->regmap, PHY_R4, reg); 15936077e16SNeil Armstrong 16036077e16SNeil Armstrong ret = regmap_read_poll_timeout(priv->regmap, PHY_R5, val, 16136077e16SNeil Armstrong (val & PHY_R5_PHY_CR_ACK) == 0, 16236077e16SNeil Armstrong 5, 1000); 16336077e16SNeil Armstrong if (ret) 16436077e16SNeil Armstrong return ret; 16536077e16SNeil Armstrong 16636077e16SNeil Armstrong regmap_write(priv->regmap, PHY_R4, reg); 16736077e16SNeil Armstrong 16836077e16SNeil Armstrong regmap_write(priv->regmap, PHY_R4, reg | PHY_R4_PHY_CR_WRITE); 16936077e16SNeil Armstrong 17036077e16SNeil Armstrong ret = regmap_read_poll_timeout(priv->regmap, PHY_R5, val, 17136077e16SNeil Armstrong (val & PHY_R5_PHY_CR_ACK), 17236077e16SNeil Armstrong 5, 1000); 17336077e16SNeil Armstrong if (ret) 17436077e16SNeil Armstrong return ret; 17536077e16SNeil Armstrong 17636077e16SNeil Armstrong regmap_write(priv->regmap, PHY_R4, reg); 17736077e16SNeil Armstrong 17836077e16SNeil Armstrong ret = regmap_read_poll_timeout(priv->regmap, PHY_R5, val, 17936077e16SNeil Armstrong (val & PHY_R5_PHY_CR_ACK) == 0, 18036077e16SNeil Armstrong 5, 1000); 18136077e16SNeil Armstrong if (ret) 18236077e16SNeil Armstrong return ret; 18336077e16SNeil Armstrong 18436077e16SNeil Armstrong return 0; 18536077e16SNeil Armstrong } 18636077e16SNeil Armstrong 18736077e16SNeil Armstrong static const struct regmap_config phy_g12a_usb3_pcie_cr_regmap_conf = { 18836077e16SNeil Armstrong .reg_bits = 16, 18936077e16SNeil Armstrong .val_bits = 16, 19036077e16SNeil Armstrong .reg_read = phy_g12a_usb3_pcie_cr_bus_read, 19136077e16SNeil Armstrong .reg_write = phy_g12a_usb3_pcie_cr_bus_write, 19236077e16SNeil Armstrong .max_register = 0xffff, 1935fc2aa3eSNeil Armstrong .disable_locking = true, 19436077e16SNeil Armstrong }; 19536077e16SNeil Armstrong 19636077e16SNeil Armstrong static int phy_g12a_usb3_init(struct phy *phy) 19736077e16SNeil Armstrong { 19836077e16SNeil Armstrong struct phy_g12a_usb3_pcie_priv *priv = phy_get_drvdata(phy); 19936077e16SNeil Armstrong int data, ret; 20036077e16SNeil Armstrong 20163162725SNeil Armstrong ret = reset_control_reset(priv->reset); 20263162725SNeil Armstrong if (ret) 20363162725SNeil Armstrong return ret; 20463162725SNeil Armstrong 20536077e16SNeil Armstrong /* Switch PHY to USB3 */ 20636077e16SNeil Armstrong /* TODO figure out how to handle when PCIe was set in the bootloader */ 20736077e16SNeil Armstrong regmap_update_bits(priv->regmap, PHY_R0, 20836077e16SNeil Armstrong PHY_R0_PCIE_USB3_SWITCH, 20936077e16SNeil Armstrong PHY_R0_PCIE_USB3_SWITCH); 21036077e16SNeil Armstrong 21136077e16SNeil Armstrong /* 21236077e16SNeil Armstrong * WORKAROUND: There is SSPHY suspend bug due to 21336077e16SNeil Armstrong * which USB enumerates 21436077e16SNeil Armstrong * in HS mode instead of SS mode. Workaround it by asserting 21536077e16SNeil Armstrong * LANE0.TX_ALT_BLOCK.EN_ALT_BUS to enable TX to use alt bus 21636077e16SNeil Armstrong * mode 21736077e16SNeil Armstrong */ 21836077e16SNeil Armstrong ret = regmap_update_bits(priv->regmap_cr, 0x102d, BIT(7), BIT(7)); 21936077e16SNeil Armstrong if (ret) 22036077e16SNeil Armstrong return ret; 22136077e16SNeil Armstrong 22236077e16SNeil Armstrong ret = regmap_update_bits(priv->regmap_cr, 0x1010, 0xff0, 20); 22336077e16SNeil Armstrong if (ret) 22436077e16SNeil Armstrong return ret; 22536077e16SNeil Armstrong 22636077e16SNeil Armstrong /* 22736077e16SNeil Armstrong * Fix RX Equalization setting as follows 22836077e16SNeil Armstrong * LANE0.RX_OVRD_IN_HI. RX_EQ_EN set to 0 22936077e16SNeil Armstrong * LANE0.RX_OVRD_IN_HI.RX_EQ_EN_OVRD set to 1 23036077e16SNeil Armstrong * LANE0.RX_OVRD_IN_HI.RX_EQ set to 3 23136077e16SNeil Armstrong * LANE0.RX_OVRD_IN_HI.RX_EQ_OVRD set to 1 23236077e16SNeil Armstrong */ 23336077e16SNeil Armstrong ret = regmap_read(priv->regmap_cr, 0x1006, &data); 23436077e16SNeil Armstrong if (ret) 23536077e16SNeil Armstrong return ret; 23636077e16SNeil Armstrong 23736077e16SNeil Armstrong data &= ~BIT(6); 23836077e16SNeil Armstrong data |= BIT(7); 23936077e16SNeil Armstrong data &= ~(0x7 << 8); 24036077e16SNeil Armstrong data |= (0x3 << 8); 24136077e16SNeil Armstrong data |= (1 << 11); 24236077e16SNeil Armstrong ret = regmap_write(priv->regmap_cr, 0x1006, data); 24336077e16SNeil Armstrong if (ret) 24436077e16SNeil Armstrong return ret; 24536077e16SNeil Armstrong 24636077e16SNeil Armstrong /* 24736077e16SNeil Armstrong * Set EQ and TX launch amplitudes as follows 24836077e16SNeil Armstrong * LANE0.TX_OVRD_DRV_LO.PREEMPH set to 22 24936077e16SNeil Armstrong * LANE0.TX_OVRD_DRV_LO.AMPLITUDE set to 127 25036077e16SNeil Armstrong * LANE0.TX_OVRD_DRV_LO.EN set to 1. 25136077e16SNeil Armstrong */ 25236077e16SNeil Armstrong ret = regmap_read(priv->regmap_cr, 0x1002, &data); 25336077e16SNeil Armstrong if (ret) 25436077e16SNeil Armstrong return ret; 25536077e16SNeil Armstrong 25636077e16SNeil Armstrong data &= ~0x3f80; 25736077e16SNeil Armstrong data |= (0x16 << 7); 25836077e16SNeil Armstrong data &= ~0x7f; 25936077e16SNeil Armstrong data |= (0x7f | BIT(14)); 26036077e16SNeil Armstrong ret = regmap_write(priv->regmap_cr, 0x1002, data); 26136077e16SNeil Armstrong if (ret) 26236077e16SNeil Armstrong return ret; 26336077e16SNeil Armstrong 26436077e16SNeil Armstrong /* MPLL_LOOP_CTL.PROP_CNTRL = 8 */ 26536077e16SNeil Armstrong ret = regmap_update_bits(priv->regmap_cr, 0x30, 0xf << 4, 8 << 4); 26636077e16SNeil Armstrong if (ret) 26736077e16SNeil Armstrong return ret; 26836077e16SNeil Armstrong 26936077e16SNeil Armstrong regmap_update_bits(priv->regmap, PHY_R2, 27036077e16SNeil Armstrong PHY_R2_PHY_TX_VBOOST_LVL, 27136077e16SNeil Armstrong FIELD_PREP(PHY_R2_PHY_TX_VBOOST_LVL, 0x4)); 27236077e16SNeil Armstrong 27336077e16SNeil Armstrong regmap_update_bits(priv->regmap, PHY_R1, 27436077e16SNeil Armstrong PHY_R1_PHY_LOS_BIAS | PHY_R1_PHY_LOS_LEVEL, 27536077e16SNeil Armstrong FIELD_PREP(PHY_R1_PHY_LOS_BIAS, 4) | 27636077e16SNeil Armstrong FIELD_PREP(PHY_R1_PHY_LOS_LEVEL, 9)); 27736077e16SNeil Armstrong 27836077e16SNeil Armstrong return 0; 27936077e16SNeil Armstrong } 28036077e16SNeil Armstrong 28163162725SNeil Armstrong static int phy_g12a_usb3_pcie_power_on(struct phy *phy) 28263162725SNeil Armstrong { 28363162725SNeil Armstrong struct phy_g12a_usb3_pcie_priv *priv = phy_get_drvdata(phy); 28463162725SNeil Armstrong 28563162725SNeil Armstrong if (priv->mode == PHY_TYPE_USB3) 28663162725SNeil Armstrong return 0; 28763162725SNeil Armstrong 28863162725SNeil Armstrong regmap_update_bits(priv->regmap, PHY_R0, 28963162725SNeil Armstrong PHY_R0_PCIE_POWER_STATE, 29063162725SNeil Armstrong FIELD_PREP(PHY_R0_PCIE_POWER_STATE, 0x1c)); 29163162725SNeil Armstrong 29263162725SNeil Armstrong return 0; 29363162725SNeil Armstrong } 29463162725SNeil Armstrong 29563162725SNeil Armstrong static int phy_g12a_usb3_pcie_power_off(struct phy *phy) 29663162725SNeil Armstrong { 29763162725SNeil Armstrong struct phy_g12a_usb3_pcie_priv *priv = phy_get_drvdata(phy); 29863162725SNeil Armstrong 29963162725SNeil Armstrong if (priv->mode == PHY_TYPE_USB3) 30063162725SNeil Armstrong return 0; 30163162725SNeil Armstrong 30263162725SNeil Armstrong regmap_update_bits(priv->regmap, PHY_R0, 30363162725SNeil Armstrong PHY_R0_PCIE_POWER_STATE, 30463162725SNeil Armstrong FIELD_PREP(PHY_R0_PCIE_POWER_STATE, 0x1d)); 30563162725SNeil Armstrong 30663162725SNeil Armstrong return 0; 30763162725SNeil Armstrong } 30863162725SNeil Armstrong 30963162725SNeil Armstrong static int phy_g12a_usb3_pcie_reset(struct phy *phy) 31036077e16SNeil Armstrong { 31136077e16SNeil Armstrong struct phy_g12a_usb3_pcie_priv *priv = phy_get_drvdata(phy); 31236077e16SNeil Armstrong int ret; 31336077e16SNeil Armstrong 31463162725SNeil Armstrong if (priv->mode == PHY_TYPE_USB3) 31563162725SNeil Armstrong return 0; 31663162725SNeil Armstrong 31763162725SNeil Armstrong ret = reset_control_assert(priv->reset); 31836077e16SNeil Armstrong if (ret) 31936077e16SNeil Armstrong return ret; 32036077e16SNeil Armstrong 32163162725SNeil Armstrong udelay(PCIE_RESET_DELAY); 32263162725SNeil Armstrong 32363162725SNeil Armstrong ret = reset_control_deassert(priv->reset); 32463162725SNeil Armstrong if (ret) 32563162725SNeil Armstrong return ret; 32663162725SNeil Armstrong 32763162725SNeil Armstrong udelay(PCIE_RESET_DELAY); 32863162725SNeil Armstrong 32963162725SNeil Armstrong return 0; 33063162725SNeil Armstrong } 33163162725SNeil Armstrong 33263162725SNeil Armstrong static int phy_g12a_usb3_pcie_init(struct phy *phy) 33363162725SNeil Armstrong { 33463162725SNeil Armstrong struct phy_g12a_usb3_pcie_priv *priv = phy_get_drvdata(phy); 33563162725SNeil Armstrong 33636077e16SNeil Armstrong if (priv->mode == PHY_TYPE_USB3) 33736077e16SNeil Armstrong return phy_g12a_usb3_init(phy); 33836077e16SNeil Armstrong 33936077e16SNeil Armstrong return 0; 34036077e16SNeil Armstrong } 34136077e16SNeil Armstrong 34236077e16SNeil Armstrong static int phy_g12a_usb3_pcie_exit(struct phy *phy) 34336077e16SNeil Armstrong { 34436077e16SNeil Armstrong struct phy_g12a_usb3_pcie_priv *priv = phy_get_drvdata(phy); 34536077e16SNeil Armstrong 34663162725SNeil Armstrong if (priv->mode == PHY_TYPE_USB3) 34736077e16SNeil Armstrong return reset_control_reset(priv->reset); 34863162725SNeil Armstrong 34963162725SNeil Armstrong return 0; 35036077e16SNeil Armstrong } 35136077e16SNeil Armstrong 35236077e16SNeil Armstrong static struct phy *phy_g12a_usb3_pcie_xlate(struct device *dev, 35336077e16SNeil Armstrong struct of_phandle_args *args) 35436077e16SNeil Armstrong { 35536077e16SNeil Armstrong struct phy_g12a_usb3_pcie_priv *priv = dev_get_drvdata(dev); 35636077e16SNeil Armstrong unsigned int mode; 35736077e16SNeil Armstrong 35836077e16SNeil Armstrong if (args->args_count < 1) { 35936077e16SNeil Armstrong dev_err(dev, "invalid number of arguments\n"); 36036077e16SNeil Armstrong return ERR_PTR(-EINVAL); 36136077e16SNeil Armstrong } 36236077e16SNeil Armstrong 36336077e16SNeil Armstrong mode = args->args[0]; 36436077e16SNeil Armstrong 36536077e16SNeil Armstrong if (mode != PHY_TYPE_USB3 && mode != PHY_TYPE_PCIE) { 36636077e16SNeil Armstrong dev_err(dev, "invalid phy mode select argument\n"); 36736077e16SNeil Armstrong return ERR_PTR(-EINVAL); 36836077e16SNeil Armstrong } 36936077e16SNeil Armstrong 37036077e16SNeil Armstrong priv->mode = mode; 37136077e16SNeil Armstrong 37236077e16SNeil Armstrong return priv->phy; 37336077e16SNeil Armstrong } 37436077e16SNeil Armstrong 37536077e16SNeil Armstrong static const struct phy_ops phy_g12a_usb3_pcie_ops = { 37636077e16SNeil Armstrong .init = phy_g12a_usb3_pcie_init, 37736077e16SNeil Armstrong .exit = phy_g12a_usb3_pcie_exit, 37863162725SNeil Armstrong .power_on = phy_g12a_usb3_pcie_power_on, 37963162725SNeil Armstrong .power_off = phy_g12a_usb3_pcie_power_off, 38063162725SNeil Armstrong .reset = phy_g12a_usb3_pcie_reset, 38136077e16SNeil Armstrong .owner = THIS_MODULE, 38236077e16SNeil Armstrong }; 38336077e16SNeil Armstrong 38436077e16SNeil Armstrong static int phy_g12a_usb3_pcie_probe(struct platform_device *pdev) 38536077e16SNeil Armstrong { 38636077e16SNeil Armstrong struct device *dev = &pdev->dev; 38736077e16SNeil Armstrong struct device_node *np = dev->of_node; 38836077e16SNeil Armstrong struct phy_g12a_usb3_pcie_priv *priv; 38936077e16SNeil Armstrong struct resource *res; 39036077e16SNeil Armstrong struct phy_provider *phy_provider; 39136077e16SNeil Armstrong void __iomem *base; 39236077e16SNeil Armstrong int ret; 39336077e16SNeil Armstrong 39436077e16SNeil Armstrong priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); 39536077e16SNeil Armstrong if (!priv) 39636077e16SNeil Armstrong return -ENOMEM; 39736077e16SNeil Armstrong 39836077e16SNeil Armstrong res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 39936077e16SNeil Armstrong base = devm_ioremap_resource(dev, res); 40036077e16SNeil Armstrong if (IS_ERR(base)) 40136077e16SNeil Armstrong return PTR_ERR(base); 40236077e16SNeil Armstrong 40336077e16SNeil Armstrong priv->regmap = devm_regmap_init_mmio(dev, base, 40436077e16SNeil Armstrong &phy_g12a_usb3_pcie_regmap_conf); 40536077e16SNeil Armstrong if (IS_ERR(priv->regmap)) 40636077e16SNeil Armstrong return PTR_ERR(priv->regmap); 40736077e16SNeil Armstrong 40836077e16SNeil Armstrong priv->regmap_cr = devm_regmap_init(dev, NULL, priv, 40936077e16SNeil Armstrong &phy_g12a_usb3_pcie_cr_regmap_conf); 41036077e16SNeil Armstrong if (IS_ERR(priv->regmap_cr)) 41136077e16SNeil Armstrong return PTR_ERR(priv->regmap_cr); 41236077e16SNeil Armstrong 41336077e16SNeil Armstrong priv->clk_ref = devm_clk_get(dev, "ref_clk"); 41436077e16SNeil Armstrong if (IS_ERR(priv->clk_ref)) 41536077e16SNeil Armstrong return PTR_ERR(priv->clk_ref); 41636077e16SNeil Armstrong 41736077e16SNeil Armstrong ret = clk_prepare_enable(priv->clk_ref); 41836077e16SNeil Armstrong if (ret) 41936077e16SNeil Armstrong goto err_disable_clk_ref; 42036077e16SNeil Armstrong 42136077e16SNeil Armstrong priv->reset = devm_reset_control_array_get(dev, false, false); 42236077e16SNeil Armstrong if (IS_ERR(priv->reset)) 42336077e16SNeil Armstrong return PTR_ERR(priv->reset); 42436077e16SNeil Armstrong 42536077e16SNeil Armstrong priv->phy = devm_phy_create(dev, np, &phy_g12a_usb3_pcie_ops); 42636077e16SNeil Armstrong if (IS_ERR(priv->phy)) { 42736077e16SNeil Armstrong ret = PTR_ERR(priv->phy); 42836077e16SNeil Armstrong if (ret != -EPROBE_DEFER) 42936077e16SNeil Armstrong dev_err(dev, "failed to create PHY\n"); 43036077e16SNeil Armstrong 43136077e16SNeil Armstrong return ret; 43236077e16SNeil Armstrong } 43336077e16SNeil Armstrong 43436077e16SNeil Armstrong phy_set_drvdata(priv->phy, priv); 43536077e16SNeil Armstrong dev_set_drvdata(dev, priv); 43636077e16SNeil Armstrong 43736077e16SNeil Armstrong phy_provider = devm_of_phy_provider_register(dev, 43836077e16SNeil Armstrong phy_g12a_usb3_pcie_xlate); 43936077e16SNeil Armstrong 44036077e16SNeil Armstrong return PTR_ERR_OR_ZERO(phy_provider); 44136077e16SNeil Armstrong 44236077e16SNeil Armstrong err_disable_clk_ref: 44336077e16SNeil Armstrong clk_disable_unprepare(priv->clk_ref); 44436077e16SNeil Armstrong 44536077e16SNeil Armstrong return ret; 44636077e16SNeil Armstrong } 44736077e16SNeil Armstrong 44836077e16SNeil Armstrong static const struct of_device_id phy_g12a_usb3_pcie_of_match[] = { 44936077e16SNeil Armstrong { .compatible = "amlogic,g12a-usb3-pcie-phy", }, 45036077e16SNeil Armstrong { }, 45136077e16SNeil Armstrong }; 45236077e16SNeil Armstrong MODULE_DEVICE_TABLE(of, phy_g12a_usb3_pcie_of_match); 45336077e16SNeil Armstrong 45436077e16SNeil Armstrong static struct platform_driver phy_g12a_usb3_pcie_driver = { 45536077e16SNeil Armstrong .probe = phy_g12a_usb3_pcie_probe, 45636077e16SNeil Armstrong .driver = { 45736077e16SNeil Armstrong .name = "phy-g12a-usb3-pcie", 45836077e16SNeil Armstrong .of_match_table = phy_g12a_usb3_pcie_of_match, 45936077e16SNeil Armstrong }, 46036077e16SNeil Armstrong }; 46136077e16SNeil Armstrong module_platform_driver(phy_g12a_usb3_pcie_driver); 46236077e16SNeil Armstrong 46336077e16SNeil Armstrong MODULE_AUTHOR("Neil Armstrong <narmstrong@baylibre.com>"); 46436077e16SNeil Armstrong MODULE_DESCRIPTION("Amlogic G12A USB3 + PCIE Combo PHY driver"); 46536077e16SNeil Armstrong MODULE_LICENSE("GPL v2"); 466