phy-hi6220-usb.c (3985B)
1// SPDX-License-Identifier: GPL-2.0-or-later 2/* 3 * Copyright (c) 2015 Linaro Ltd. 4 * Copyright (c) 2015 HiSilicon Limited. 5 */ 6 7#include <linux/mfd/syscon.h> 8#include <linux/module.h> 9#include <linux/platform_device.h> 10#include <linux/phy/phy.h> 11#include <linux/regmap.h> 12 13#define SC_PERIPH_CTRL4 0x00c 14 15#define CTRL4_PICO_SIDDQ BIT(6) 16#define CTRL4_PICO_OGDISABLE BIT(8) 17#define CTRL4_PICO_VBUSVLDEXT BIT(10) 18#define CTRL4_PICO_VBUSVLDEXTSEL BIT(11) 19#define CTRL4_OTG_PHY_SEL BIT(21) 20 21#define SC_PERIPH_CTRL5 0x010 22 23#define CTRL5_USBOTG_RES_SEL BIT(3) 24#define CTRL5_PICOPHY_ACAENB BIT(4) 25#define CTRL5_PICOPHY_BC_MODE BIT(5) 26#define CTRL5_PICOPHY_CHRGSEL BIT(6) 27#define CTRL5_PICOPHY_VDATSRCEND BIT(7) 28#define CTRL5_PICOPHY_VDATDETENB BIT(8) 29#define CTRL5_PICOPHY_DCDENB BIT(9) 30#define CTRL5_PICOPHY_IDDIG BIT(10) 31 32#define SC_PERIPH_CTRL8 0x018 33#define SC_PERIPH_RSTEN0 0x300 34#define SC_PERIPH_RSTDIS0 0x304 35 36#define RST0_USBOTG_BUS BIT(4) 37#define RST0_POR_PICOPHY BIT(5) 38#define RST0_USBOTG BIT(6) 39#define RST0_USBOTG_32K BIT(7) 40 41#define EYE_PATTERN_PARA 0x7053348c 42 43struct hi6220_priv { 44 struct regmap *reg; 45 struct device *dev; 46}; 47 48static void hi6220_phy_init(struct hi6220_priv *priv) 49{ 50 struct regmap *reg = priv->reg; 51 u32 val, mask; 52 53 val = RST0_USBOTG_BUS | RST0_POR_PICOPHY | 54 RST0_USBOTG | RST0_USBOTG_32K; 55 mask = val; 56 regmap_update_bits(reg, SC_PERIPH_RSTEN0, mask, val); 57 regmap_update_bits(reg, SC_PERIPH_RSTDIS0, mask, val); 58} 59 60static int hi6220_phy_setup(struct hi6220_priv *priv, bool on) 61{ 62 struct regmap *reg = priv->reg; 63 u32 val, mask; 64 int ret; 65 66 if (on) { 67 val = CTRL5_USBOTG_RES_SEL | CTRL5_PICOPHY_ACAENB; 68 mask = val | CTRL5_PICOPHY_BC_MODE; 69 ret = regmap_update_bits(reg, SC_PERIPH_CTRL5, mask, val); 70 if (ret) 71 goto out; 72 73 val = CTRL4_PICO_VBUSVLDEXT | CTRL4_PICO_VBUSVLDEXTSEL | 74 CTRL4_OTG_PHY_SEL; 75 mask = val | CTRL4_PICO_SIDDQ | CTRL4_PICO_OGDISABLE; 76 ret = regmap_update_bits(reg, SC_PERIPH_CTRL4, mask, val); 77 if (ret) 78 goto out; 79 80 ret = regmap_write(reg, SC_PERIPH_CTRL8, EYE_PATTERN_PARA); 81 if (ret) 82 goto out; 83 } else { 84 val = CTRL4_PICO_SIDDQ; 85 mask = val; 86 ret = regmap_update_bits(reg, SC_PERIPH_CTRL4, mask, val); 87 if (ret) 88 goto out; 89 } 90 91 return 0; 92out: 93 dev_err(priv->dev, "failed to setup phy ret: %d\n", ret); 94 return ret; 95} 96 97static int hi6220_phy_start(struct phy *phy) 98{ 99 struct hi6220_priv *priv = phy_get_drvdata(phy); 100 101 return hi6220_phy_setup(priv, true); 102} 103 104static int hi6220_phy_exit(struct phy *phy) 105{ 106 struct hi6220_priv *priv = phy_get_drvdata(phy); 107 108 return hi6220_phy_setup(priv, false); 109} 110 111static const struct phy_ops hi6220_phy_ops = { 112 .init = hi6220_phy_start, 113 .exit = hi6220_phy_exit, 114 .owner = THIS_MODULE, 115}; 116 117static int hi6220_phy_probe(struct platform_device *pdev) 118{ 119 struct phy_provider *phy_provider; 120 struct device *dev = &pdev->dev; 121 struct phy *phy; 122 struct hi6220_priv *priv; 123 124 priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); 125 if (!priv) 126 return -ENOMEM; 127 128 priv->dev = dev; 129 priv->reg = syscon_regmap_lookup_by_phandle(dev->of_node, 130 "hisilicon,peripheral-syscon"); 131 if (IS_ERR(priv->reg)) { 132 dev_err(dev, "no hisilicon,peripheral-syscon\n"); 133 return PTR_ERR(priv->reg); 134 } 135 136 hi6220_phy_init(priv); 137 138 phy = devm_phy_create(dev, NULL, &hi6220_phy_ops); 139 if (IS_ERR(phy)) 140 return PTR_ERR(phy); 141 142 phy_set_drvdata(phy, priv); 143 phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate); 144 return PTR_ERR_OR_ZERO(phy_provider); 145} 146 147static const struct of_device_id hi6220_phy_of_match[] = { 148 {.compatible = "hisilicon,hi6220-usb-phy",}, 149 { }, 150}; 151MODULE_DEVICE_TABLE(of, hi6220_phy_of_match); 152 153static struct platform_driver hi6220_phy_driver = { 154 .probe = hi6220_phy_probe, 155 .driver = { 156 .name = "hi6220-usb-phy", 157 .of_match_table = hi6220_phy_of_match, 158 } 159}; 160module_platform_driver(hi6220_phy_driver); 161 162MODULE_DESCRIPTION("HISILICON HI6220 USB PHY driver"); 163MODULE_ALIAS("platform:hi6220-usb-phy"); 164MODULE_LICENSE("GPL");