Lines Matching +full:rk3288 +full:- +full:usb +full:- +full:phy

1 // SPDX-License-Identifier: GPL-2.0-only
3 * Rockchip usb PHY driver
5 * Copyright (C) 2014 Yunzhi Li <lyz@rock-chips.com>
10 #include <linux/clk-provider.h>
18 #include <linux/phy/phy.h>
40 /* bits present on rk3188 and rk3288 phys */
74 struct phy *phy; member
80 static int rockchip_usb_phy_power(struct rockchip_usb_phy *phy, in rockchip_usb_phy_power() argument
85 return regmap_write(phy->base->reg_base, phy->reg_offset, val); in rockchip_usb_phy_power()
96 struct rockchip_usb_phy *phy = container_of(hw, in rockchip_usb_phy480m_disable() local
100 if (phy->vbus) in rockchip_usb_phy480m_disable()
101 regulator_disable(phy->vbus); in rockchip_usb_phy480m_disable()
103 /* Power down usb phy analog blocks by set siddq 1 */ in rockchip_usb_phy480m_disable()
104 rockchip_usb_phy_power(phy, 1); in rockchip_usb_phy480m_disable()
109 struct rockchip_usb_phy *phy = container_of(hw, in rockchip_usb_phy480m_enable() local
113 /* Power up usb phy analog blocks by set siddq 0 */ in rockchip_usb_phy480m_enable()
114 return rockchip_usb_phy_power(phy, 0); in rockchip_usb_phy480m_enable()
119 struct rockchip_usb_phy *phy = container_of(hw, in rockchip_usb_phy480m_is_enabled() local
125 ret = regmap_read(phy->base->reg_base, phy->reg_offset, &val); in rockchip_usb_phy480m_is_enabled()
139 static int rockchip_usb_phy_power_off(struct phy *_phy) in rockchip_usb_phy_power_off()
141 struct rockchip_usb_phy *phy = phy_get_drvdata(_phy); in rockchip_usb_phy_power_off() local
143 if (phy->uart_enabled) in rockchip_usb_phy_power_off()
144 return -EBUSY; in rockchip_usb_phy_power_off()
146 clk_disable_unprepare(phy->clk480m); in rockchip_usb_phy_power_off()
151 static int rockchip_usb_phy_power_on(struct phy *_phy) in rockchip_usb_phy_power_on()
153 struct rockchip_usb_phy *phy = phy_get_drvdata(_phy); in rockchip_usb_phy_power_on() local
155 if (phy->uart_enabled) in rockchip_usb_phy_power_on()
156 return -EBUSY; in rockchip_usb_phy_power_on()
158 if (phy->vbus) { in rockchip_usb_phy_power_on()
161 ret = regulator_enable(phy->vbus); in rockchip_usb_phy_power_on()
166 return clk_prepare_enable(phy->clk480m); in rockchip_usb_phy_power_on()
169 static int rockchip_usb_phy_reset(struct phy *_phy) in rockchip_usb_phy_reset()
171 struct rockchip_usb_phy *phy = phy_get_drvdata(_phy); in rockchip_usb_phy_reset() local
173 if (phy->reset) { in rockchip_usb_phy_reset()
174 reset_control_assert(phy->reset); in rockchip_usb_phy_reset()
176 reset_control_deassert(phy->reset); in rockchip_usb_phy_reset()
193 if (!rk_phy->uart_enabled) { in rockchip_usb_phy_action()
194 of_clk_del_provider(rk_phy->np); in rockchip_usb_phy_action()
195 clk_unregister(rk_phy->clk480m); in rockchip_usb_phy_action()
198 if (rk_phy->clk) in rockchip_usb_phy_action()
199 clk_put(rk_phy->clk); in rockchip_usb_phy_action()
211 rk_phy = devm_kzalloc(base->dev, sizeof(*rk_phy), GFP_KERNEL); in rockchip_usb_phy_init()
213 return -ENOMEM; in rockchip_usb_phy_init()
215 rk_phy->base = base; in rockchip_usb_phy_init()
216 rk_phy->np = child; in rockchip_usb_phy_init()
219 dev_err(base->dev, "missing reg property in node %pOFn\n", in rockchip_usb_phy_init()
221 return -EINVAL; in rockchip_usb_phy_init()
224 rk_phy->reset = of_reset_control_get(child, "phy-reset"); in rockchip_usb_phy_init()
225 if (IS_ERR(rk_phy->reset)) in rockchip_usb_phy_init()
226 rk_phy->reset = NULL; in rockchip_usb_phy_init()
228 rk_phy->reg_offset = reg_offset; in rockchip_usb_phy_init()
230 rk_phy->clk = of_clk_get_by_name(child, "phyclk"); in rockchip_usb_phy_init()
231 if (IS_ERR(rk_phy->clk)) in rockchip_usb_phy_init()
232 rk_phy->clk = NULL; in rockchip_usb_phy_init()
236 while (base->pdata->phys[i].reg) { in rockchip_usb_phy_init()
237 if (base->pdata->phys[i].reg == reg_offset) { in rockchip_usb_phy_init()
238 init.name = base->pdata->phys[i].pll_name; in rockchip_usb_phy_init()
245 dev_err(base->dev, "phy data not found\n"); in rockchip_usb_phy_init()
246 return -EINVAL; in rockchip_usb_phy_init()
249 if (enable_usb_uart && base->pdata->usb_uart_phy == i) { in rockchip_usb_phy_init()
250 dev_dbg(base->dev, "phy%d used as uart output\n", i); in rockchip_usb_phy_init()
251 rk_phy->uart_enabled = true; in rockchip_usb_phy_init()
253 if (rk_phy->clk) { in rockchip_usb_phy_init()
254 clk_name = __clk_get_name(rk_phy->clk); in rockchip_usb_phy_init()
265 rk_phy->clk480m_hw.init = &init; in rockchip_usb_phy_init()
267 rk_phy->clk480m = clk_register(base->dev, &rk_phy->clk480m_hw); in rockchip_usb_phy_init()
268 if (IS_ERR(rk_phy->clk480m)) { in rockchip_usb_phy_init()
269 err = PTR_ERR(rk_phy->clk480m); in rockchip_usb_phy_init()
274 rk_phy->clk480m); in rockchip_usb_phy_init()
279 err = devm_add_action_or_reset(base->dev, rockchip_usb_phy_action, in rockchip_usb_phy_init()
284 rk_phy->phy = devm_phy_create(base->dev, child, &ops); in rockchip_usb_phy_init()
285 if (IS_ERR(rk_phy->phy)) { in rockchip_usb_phy_init()
286 dev_err(base->dev, "failed to create PHY\n"); in rockchip_usb_phy_init()
287 return PTR_ERR(rk_phy->phy); in rockchip_usb_phy_init()
289 phy_set_drvdata(rk_phy->phy, rk_phy); in rockchip_usb_phy_init()
291 rk_phy->vbus = devm_regulator_get_optional(&rk_phy->phy->dev, "vbus"); in rockchip_usb_phy_init()
292 if (IS_ERR(rk_phy->vbus)) { in rockchip_usb_phy_init()
293 if (PTR_ERR(rk_phy->vbus) == -EPROBE_DEFER) in rockchip_usb_phy_init()
294 return PTR_ERR(rk_phy->vbus); in rockchip_usb_phy_init()
295 rk_phy->vbus = NULL; in rockchip_usb_phy_init()
299 * When acting as uart-pipe, just keep clock on otherwise in rockchip_usb_phy_init()
300 * only power up usb phy when it use, so disable it when init in rockchip_usb_phy_init()
302 if (rk_phy->uart_enabled) in rockchip_usb_phy_init()
303 return clk_prepare_enable(rk_phy->clk); in rockchip_usb_phy_init()
308 if (!rk_phy->uart_enabled) in rockchip_usb_phy_init()
309 clk_unregister(rk_phy->clk480m); in rockchip_usb_phy_init()
311 if (rk_phy->clk) in rockchip_usb_phy_init()
312 clk_put(rk_phy->clk); in rockchip_usb_phy_init()
327 int regoffs = pdata->phys[pdata->usb_uart_phy].reg; in rockchip_init_usb_uart_common()
334 * Also disable the analog phy components to save power. in rockchip_init_usb_uart_common()
371 * Enable the bypass of uart2 data through the otg usb phy.
372 * See description of rk3288-variant for details.
410 * Enable the bypass of uart2 data through the otg usb phy.
413 * 2. Disable the pull-up resistance on the D+ line by setting
417 * 4. Place the USB PHY in Suspend mode by setting SUSPENDM0 to 1’b0.
458 struct device *dev = &pdev->dev; in rockchip_usb_phy_probe()
467 return -ENOMEM; in rockchip_usb_phy_probe()
469 match = of_match_device(dev->driver->of_match_table, dev); in rockchip_usb_phy_probe()
470 if (!match || !match->data) { in rockchip_usb_phy_probe()
471 dev_err(dev, "missing phy data\n"); in rockchip_usb_phy_probe()
472 return -EINVAL; in rockchip_usb_phy_probe()
475 phy_base->pdata = match->data; in rockchip_usb_phy_probe()
477 phy_base->dev = dev; in rockchip_usb_phy_probe()
478 phy_base->reg_base = ERR_PTR(-ENODEV); in rockchip_usb_phy_probe()
479 if (dev->parent && dev->parent->of_node) in rockchip_usb_phy_probe()
480 phy_base->reg_base = syscon_node_to_regmap( in rockchip_usb_phy_probe()
481 dev->parent->of_node); in rockchip_usb_phy_probe()
482 if (IS_ERR(phy_base->reg_base)) in rockchip_usb_phy_probe()
483 phy_base->reg_base = syscon_regmap_lookup_by_phandle( in rockchip_usb_phy_probe()
484 dev->of_node, "rockchip,grf"); in rockchip_usb_phy_probe()
485 if (IS_ERR(phy_base->reg_base)) { in rockchip_usb_phy_probe()
486 dev_err(&pdev->dev, "Missing rockchip,grf property\n"); in rockchip_usb_phy_probe()
487 return PTR_ERR(phy_base->reg_base); in rockchip_usb_phy_probe()
490 for_each_available_child_of_node(dev->of_node, child) { in rockchip_usb_phy_probe()
503 { .compatible = "rockchip,rk3066a-usb-phy", .data = &rk3066a_pdata },
504 { .compatible = "rockchip,rk3188-usb-phy", .data = &rk3188_pdata },
505 { .compatible = "rockchip,rk3288-usb-phy", .data = &rk3288_pdata },
514 .name = "rockchip-usb-phy",
537 return -ENOTSUPP; in rockchip_init_usb_uart()
540 pr_debug("%s: using settings for %s\n", __func__, match->compatible); in rockchip_init_usb_uart()
541 data = match->data; in rockchip_init_usb_uart()
543 if (!data->init_usb_uart) { in rockchip_init_usb_uart()
544 pr_err("%s: usb-uart not available on %s\n", in rockchip_init_usb_uart()
545 __func__, match->compatible); in rockchip_init_usb_uart()
546 return -ENOTSUPP; in rockchip_init_usb_uart()
549 grf = ERR_PTR(-ENODEV); in rockchip_init_usb_uart()
550 if (np->parent) in rockchip_init_usb_uart()
551 grf = syscon_node_to_regmap(np->parent); in rockchip_init_usb_uart()
560 ret = data->init_usb_uart(grf, data); in rockchip_init_usb_uart()
579 MODULE_AUTHOR("Yunzhi Li <lyz@rock-chips.com>");
580 MODULE_DESCRIPTION("Rockchip USB 2.0 PHY driver");