Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

phy: usb: sunxi: Introduce Allwinner A31 USB PHY support

The USB phy controller in the A31 differs mostly from the older controllers
because it has a clock dedicated for each phy, while the older ones were having
a single clock for all the phys.

Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
Reviewed-by: Hans de Goede <hdegoede@redhat.com>
Signed-off-by: Kishon Vijay Abraham I <kishon@ti.com>

authored by

Maxime Ripard and committed by
Kishon Vijay Abraham I
eadd4312 fecc2d78

+22 -11
+22 -11
drivers/phy/phy-sun4i-usb.c
··· 61 61 #define MAX_PHYS 3 62 62 63 63 struct sun4i_usb_phy_data { 64 - struct clk *clk; 65 64 void __iomem *base; 66 65 struct mutex mutex; 67 66 int num_phys; ··· 70 71 void __iomem *pmu; 71 72 struct regulator *vbus; 72 73 struct reset_control *reset; 74 + struct clk *clk; 73 75 int index; 74 76 } phys[MAX_PHYS]; 75 77 }; ··· 146 146 struct sun4i_usb_phy_data *data = to_sun4i_usb_phy_data(phy); 147 147 int ret; 148 148 149 - ret = clk_prepare_enable(data->clk); 149 + ret = clk_prepare_enable(phy->clk); 150 150 if (ret) 151 151 return ret; 152 152 153 153 ret = reset_control_deassert(phy->reset); 154 154 if (ret) { 155 - clk_disable_unprepare(data->clk); 155 + clk_disable_unprepare(phy->clk); 156 156 return ret; 157 157 } 158 158 ··· 170 170 static int sun4i_usb_phy_exit(struct phy *_phy) 171 171 { 172 172 struct sun4i_usb_phy *phy = phy_get_drvdata(_phy); 173 - struct sun4i_usb_phy_data *data = to_sun4i_usb_phy_data(phy); 174 173 175 174 sun4i_usb_phy_passby(phy, 0); 176 175 reset_control_assert(phy->reset); 177 - clk_disable_unprepare(data->clk); 176 + clk_disable_unprepare(phy->clk); 178 177 179 178 return 0; 180 179 } ··· 224 225 struct device *dev = &pdev->dev; 225 226 struct device_node *np = dev->of_node; 226 227 struct phy_provider *phy_provider; 228 + bool dedicated_clocks; 227 229 struct resource *res; 228 230 int i; 229 231 ··· 244 244 else 245 245 data->disc_thresh = 2; 246 246 247 + if (of_device_is_compatible(np, "allwinner,sun6i-a31-usb-phy")) 248 + dedicated_clocks = true; 249 + else 250 + dedicated_clocks = false; 251 + 247 252 res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "phy_ctrl"); 248 253 data->base = devm_ioremap_resource(dev, res); 249 254 if (IS_ERR(data->base)) 250 255 return PTR_ERR(data->base); 251 - 252 - data->clk = devm_clk_get(dev, "usb_phy"); 253 - if (IS_ERR(data->clk)) { 254 - dev_err(dev, "could not get usb_phy clock\n"); 255 - return PTR_ERR(data->clk); 256 - } 257 256 258 257 /* Skip 0, 0 is the phy for otg which is not yet supported. */ 259 258 for (i = 1; i < data->num_phys; i++) { ··· 265 266 if (PTR_ERR(phy->vbus) == -EPROBE_DEFER) 266 267 return -EPROBE_DEFER; 267 268 phy->vbus = NULL; 269 + } 270 + 271 + if (dedicated_clocks) 272 + snprintf(name, sizeof(name), "usb%d_phy", i); 273 + else 274 + strlcpy(name, "usb_phy", sizeof(name)); 275 + 276 + phy->clk = devm_clk_get(dev, name); 277 + if (IS_ERR(phy->clk)) { 278 + dev_err(dev, "failed to get clock %s\n", name); 279 + return PTR_ERR(phy->clk); 268 280 } 269 281 270 282 snprintf(name, sizeof(name), "usb%d_reset", i); ··· 315 305 static const struct of_device_id sun4i_usb_phy_of_match[] = { 316 306 { .compatible = "allwinner,sun4i-a10-usb-phy" }, 317 307 { .compatible = "allwinner,sun5i-a13-usb-phy" }, 308 + { .compatible = "allwinner,sun6i-a31-usb-phy" }, 318 309 { .compatible = "allwinner,sun7i-a20-usb-phy" }, 319 310 { }, 320 311 };