1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * IMG Pistachio USB PHY driver 4 * 5 * Copyright (C) 2015 Google, Inc. 6 */ 7 8 #include <linux/clk.h> 9 #include <linux/delay.h> 10 #include <linux/io.h> 11 #include <linux/kernel.h> 12 #include <linux/mfd/syscon.h> 13 #include <linux/module.h> 14 #include <linux/of.h> 15 #include <linux/phy/phy.h> 16 #include <linux/platform_device.h> 17 #include <linux/regmap.h> 18 19 #include <dt-bindings/phy/phy-pistachio-usb.h> 20 21 #define USB_PHY_CONTROL1 0x04 22 #define USB_PHY_CONTROL1_FSEL_SHIFT 2 23 #define USB_PHY_CONTROL1_FSEL_MASK 0x7 24 25 #define USB_PHY_STRAP_CONTROL 0x10 26 #define USB_PHY_STRAP_CONTROL_REFCLK_SHIFT 4 27 #define USB_PHY_STRAP_CONTROL_REFCLK_MASK 0x3 28 29 #define USB_PHY_STATUS 0x14 30 #define USB_PHY_STATUS_RX_PHY_CLK BIT(9) 31 #define USB_PHY_STATUS_RX_UTMI_CLK BIT(8) 32 #define USB_PHY_STATUS_VBUS_FAULT BIT(7) 33 34 struct pistachio_usb_phy { 35 struct device *dev; 36 struct regmap *cr_top; 37 struct clk *phy_clk; 38 unsigned int refclk; 39 }; 40 41 static const unsigned long fsel_rate_map[] = { 42 9600000, 43 10000000, 44 12000000, 45 19200000, 46 20000000, 47 24000000, 48 0, 49 50000000, 50 }; 51 52 static int pistachio_usb_phy_power_on(struct phy *phy) 53 { 54 struct pistachio_usb_phy *p_phy = phy_get_drvdata(phy); 55 unsigned long timeout, rate; 56 unsigned int i; 57 int ret; 58 59 ret = clk_prepare_enable(p_phy->phy_clk); 60 if (ret < 0) { 61 dev_err(p_phy->dev, "Failed to enable PHY clock: %d\n", ret); 62 return ret; 63 } 64 65 regmap_update_bits(p_phy->cr_top, USB_PHY_STRAP_CONTROL, 66 USB_PHY_STRAP_CONTROL_REFCLK_MASK << 67 USB_PHY_STRAP_CONTROL_REFCLK_SHIFT, 68 p_phy->refclk << USB_PHY_STRAP_CONTROL_REFCLK_SHIFT); 69 70 rate = clk_get_rate(p_phy->phy_clk); 71 if (p_phy->refclk == REFCLK_XO_CRYSTAL && rate != 12000000) { 72 dev_err(p_phy->dev, "Unsupported rate for XO crystal: %ld\n", 73 rate); 74 ret = -EINVAL; 75 goto disable_clk; 76 } 77 78 for (i = 0; i < ARRAY_SIZE(fsel_rate_map); i++) { 79 if (rate == fsel_rate_map[i]) 80 break; 81 } 82 if (i == ARRAY_SIZE(fsel_rate_map)) { 83 dev_err(p_phy->dev, "Unsupported clock rate: %lu\n", rate); 84 ret = -EINVAL; 85 goto disable_clk; 86 } 87 88 regmap_update_bits(p_phy->cr_top, USB_PHY_CONTROL1, 89 USB_PHY_CONTROL1_FSEL_MASK << 90 USB_PHY_CONTROL1_FSEL_SHIFT, 91 i << USB_PHY_CONTROL1_FSEL_SHIFT); 92 93 timeout = jiffies + msecs_to_jiffies(200); 94 while (time_before(jiffies, timeout)) { 95 unsigned int val; 96 97 regmap_read(p_phy->cr_top, USB_PHY_STATUS, &val); 98 if (val & USB_PHY_STATUS_VBUS_FAULT) { 99 dev_err(p_phy->dev, "VBUS fault detected\n"); 100 ret = -EIO; 101 goto disable_clk; 102 } 103 if ((val & USB_PHY_STATUS_RX_PHY_CLK) && 104 (val & USB_PHY_STATUS_RX_UTMI_CLK)) 105 return 0; 106 usleep_range(1000, 1500); 107 } 108 109 dev_err(p_phy->dev, "Timed out waiting for PHY to power on\n"); 110 ret = -ETIMEDOUT; 111 112 disable_clk: 113 clk_disable_unprepare(p_phy->phy_clk); 114 return ret; 115 } 116 117 static int pistachio_usb_phy_power_off(struct phy *phy) 118 { 119 struct pistachio_usb_phy *p_phy = phy_get_drvdata(phy); 120 121 clk_disable_unprepare(p_phy->phy_clk); 122 123 return 0; 124 } 125 126 static const struct phy_ops pistachio_usb_phy_ops = { 127 .power_on = pistachio_usb_phy_power_on, 128 .power_off = pistachio_usb_phy_power_off, 129 .owner = THIS_MODULE, 130 }; 131 132 static int pistachio_usb_phy_probe(struct platform_device *pdev) 133 { 134 struct pistachio_usb_phy *p_phy; 135 struct phy_provider *provider; 136 struct phy *phy; 137 int ret; 138 139 p_phy = devm_kzalloc(&pdev->dev, sizeof(*p_phy), GFP_KERNEL); 140 if (!p_phy) 141 return -ENOMEM; 142 p_phy->dev = &pdev->dev; 143 platform_set_drvdata(pdev, p_phy); 144 145 p_phy->cr_top = syscon_regmap_lookup_by_phandle(p_phy->dev->of_node, 146 "img,cr-top"); 147 if (IS_ERR(p_phy->cr_top)) { 148 dev_err(p_phy->dev, "Failed to get CR_TOP registers: %ld\n", 149 PTR_ERR(p_phy->cr_top)); 150 return PTR_ERR(p_phy->cr_top); 151 } 152 153 p_phy->phy_clk = devm_clk_get(p_phy->dev, "usb_phy"); 154 if (IS_ERR(p_phy->phy_clk)) { 155 dev_err(p_phy->dev, "Failed to get usb_phy clock: %ld\n", 156 PTR_ERR(p_phy->phy_clk)); 157 return PTR_ERR(p_phy->phy_clk); 158 } 159 160 ret = of_property_read_u32(p_phy->dev->of_node, "img,refclk", 161 &p_phy->refclk); 162 if (ret < 0) { 163 dev_err(p_phy->dev, "No reference clock selector specified\n"); 164 return ret; 165 } 166 167 phy = devm_phy_create(p_phy->dev, NULL, &pistachio_usb_phy_ops); 168 if (IS_ERR(phy)) { 169 dev_err(p_phy->dev, "Failed to create PHY: %ld\n", 170 PTR_ERR(phy)); 171 return PTR_ERR(phy); 172 } 173 phy_set_drvdata(phy, p_phy); 174 175 provider = devm_of_phy_provider_register(p_phy->dev, 176 of_phy_simple_xlate); 177 if (IS_ERR(provider)) { 178 dev_err(p_phy->dev, "Failed to register PHY provider: %ld\n", 179 PTR_ERR(provider)); 180 return PTR_ERR(provider); 181 } 182 183 return 0; 184 } 185 186 static const struct of_device_id pistachio_usb_phy_of_match[] = { 187 { .compatible = "img,pistachio-usb-phy", }, 188 { }, 189 }; 190 MODULE_DEVICE_TABLE(of, pistachio_usb_phy_of_match); 191 192 static struct platform_driver pistachio_usb_phy_driver = { 193 .probe = pistachio_usb_phy_probe, 194 .driver = { 195 .name = "pistachio-usb-phy", 196 .of_match_table = pistachio_usb_phy_of_match, 197 }, 198 }; 199 module_platform_driver(pistachio_usb_phy_driver); 200 201 MODULE_AUTHOR("Andrew Bresticker <abrestic@chromium.org>"); 202 MODULE_DESCRIPTION("IMG Pistachio USB2.0 PHY driver"); 203 MODULE_LICENSE("GPL v2"); 204