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>
16 #include <linux/phy/phy.h>
39 /* bits present on rk3188 and rk3288 phys */
73 struct phy *phy; member
79 static int rockchip_usb_phy_power(struct rockchip_usb_phy *phy, in rockchip_usb_phy_power() argument
84 return regmap_write(phy->base->reg_base, phy->reg_offset, val); in rockchip_usb_phy_power()
95 struct rockchip_usb_phy *phy = container_of(hw, in rockchip_usb_phy480m_disable() local
99 if (phy->vbus) in rockchip_usb_phy480m_disable()
100 regulator_disable(phy->vbus); in rockchip_usb_phy480m_disable()
102 /* Power down usb phy analog blocks by set siddq 1 */ in rockchip_usb_phy480m_disable()
103 rockchip_usb_phy_power(phy, 1); in rockchip_usb_phy480m_disable()
108 struct rockchip_usb_phy *phy = container_of(hw, in rockchip_usb_phy480m_enable() local
112 /* Power up usb phy analog blocks by set siddq 0 */ in rockchip_usb_phy480m_enable()
113 return rockchip_usb_phy_power(phy, 0); in rockchip_usb_phy480m_enable()
118 struct rockchip_usb_phy *phy = container_of(hw, in rockchip_usb_phy480m_is_enabled() local
124 ret = regmap_read(phy->base->reg_base, phy->reg_offset, &val); in rockchip_usb_phy480m_is_enabled()
138 static int rockchip_usb_phy_power_off(struct phy *_phy) in rockchip_usb_phy_power_off()
140 struct rockchip_usb_phy *phy = phy_get_drvdata(_phy); in rockchip_usb_phy_power_off() local
142 if (phy->uart_enabled) in rockchip_usb_phy_power_off()
143 return -EBUSY; in rockchip_usb_phy_power_off()
145 clk_disable_unprepare(phy->clk480m); in rockchip_usb_phy_power_off()
150 static int rockchip_usb_phy_power_on(struct phy *_phy) in rockchip_usb_phy_power_on()
152 struct rockchip_usb_phy *phy = phy_get_drvdata(_phy); in rockchip_usb_phy_power_on() local
154 if (phy->uart_enabled) in rockchip_usb_phy_power_on()
155 return -EBUSY; in rockchip_usb_phy_power_on()
157 if (phy->vbus) { in rockchip_usb_phy_power_on()
160 ret = regulator_enable(phy->vbus); in rockchip_usb_phy_power_on()
165 return clk_prepare_enable(phy->clk480m); in rockchip_usb_phy_power_on()
168 static int rockchip_usb_phy_reset(struct phy *_phy) in rockchip_usb_phy_reset()
170 struct rockchip_usb_phy *phy = phy_get_drvdata(_phy); in rockchip_usb_phy_reset() local
172 if (phy->reset) { in rockchip_usb_phy_reset()
173 reset_control_assert(phy->reset); in rockchip_usb_phy_reset()
175 reset_control_deassert(phy->reset); in rockchip_usb_phy_reset()
192 if (!rk_phy->uart_enabled) { in rockchip_usb_phy_action()
193 of_clk_del_provider(rk_phy->np); in rockchip_usb_phy_action()
194 clk_unregister(rk_phy->clk480m); in rockchip_usb_phy_action()
197 if (rk_phy->clk) in rockchip_usb_phy_action()
198 clk_put(rk_phy->clk); in rockchip_usb_phy_action()
210 rk_phy = devm_kzalloc(base->dev, sizeof(*rk_phy), GFP_KERNEL); in rockchip_usb_phy_init()
212 return -ENOMEM; in rockchip_usb_phy_init()
214 rk_phy->base = base; in rockchip_usb_phy_init()
215 rk_phy->np = child; in rockchip_usb_phy_init()
218 dev_err(base->dev, "missing reg property in node %pOFn\n", in rockchip_usb_phy_init()
220 return -EINVAL; in rockchip_usb_phy_init()
223 rk_phy->reset = of_reset_control_get(child, "phy-reset"); in rockchip_usb_phy_init()
224 if (IS_ERR(rk_phy->reset)) in rockchip_usb_phy_init()
225 rk_phy->reset = NULL; in rockchip_usb_phy_init()
227 rk_phy->reg_offset = reg_offset; in rockchip_usb_phy_init()
229 rk_phy->clk = of_clk_get_by_name(child, "phyclk"); in rockchip_usb_phy_init()
230 if (IS_ERR(rk_phy->clk)) in rockchip_usb_phy_init()
231 rk_phy->clk = NULL; in rockchip_usb_phy_init()
235 while (base->pdata->phys[i].reg) { in rockchip_usb_phy_init()
236 if (base->pdata->phys[i].reg == reg_offset) { in rockchip_usb_phy_init()
237 init.name = base->pdata->phys[i].pll_name; in rockchip_usb_phy_init()
244 dev_err(base->dev, "phy data not found\n"); in rockchip_usb_phy_init()
245 return -EINVAL; in rockchip_usb_phy_init()
248 if (enable_usb_uart && base->pdata->usb_uart_phy == i) { in rockchip_usb_phy_init()
249 dev_dbg(base->dev, "phy%d used as uart output\n", i); in rockchip_usb_phy_init()
250 rk_phy->uart_enabled = true; in rockchip_usb_phy_init()
252 if (rk_phy->clk) { in rockchip_usb_phy_init()
253 clk_name = __clk_get_name(rk_phy->clk); in rockchip_usb_phy_init()
264 rk_phy->clk480m_hw.init = &init; in rockchip_usb_phy_init()
266 rk_phy->clk480m = clk_register(base->dev, &rk_phy->clk480m_hw); in rockchip_usb_phy_init()
267 if (IS_ERR(rk_phy->clk480m)) { in rockchip_usb_phy_init()
268 err = PTR_ERR(rk_phy->clk480m); in rockchip_usb_phy_init()
273 rk_phy->clk480m); in rockchip_usb_phy_init()
278 err = devm_add_action_or_reset(base->dev, rockchip_usb_phy_action, in rockchip_usb_phy_init()
283 rk_phy->phy = devm_phy_create(base->dev, child, &ops); in rockchip_usb_phy_init()
284 if (IS_ERR(rk_phy->phy)) { in rockchip_usb_phy_init()
285 dev_err(base->dev, "failed to create PHY\n"); in rockchip_usb_phy_init()
286 return PTR_ERR(rk_phy->phy); in rockchip_usb_phy_init()
288 phy_set_drvdata(rk_phy->phy, rk_phy); in rockchip_usb_phy_init()
290 rk_phy->vbus = devm_regulator_get_optional(&rk_phy->phy->dev, "vbus"); in rockchip_usb_phy_init()
291 if (IS_ERR(rk_phy->vbus)) { in rockchip_usb_phy_init()
292 if (PTR_ERR(rk_phy->vbus) == -EPROBE_DEFER) in rockchip_usb_phy_init()
293 return PTR_ERR(rk_phy->vbus); in rockchip_usb_phy_init()
294 rk_phy->vbus = NULL; in rockchip_usb_phy_init()
298 * When acting as uart-pipe, just keep clock on otherwise in rockchip_usb_phy_init()
299 * only power up usb phy when it use, so disable it when init in rockchip_usb_phy_init()
301 if (rk_phy->uart_enabled) in rockchip_usb_phy_init()
302 return clk_prepare_enable(rk_phy->clk); in rockchip_usb_phy_init()
307 if (!rk_phy->uart_enabled) in rockchip_usb_phy_init()
308 clk_unregister(rk_phy->clk480m); in rockchip_usb_phy_init()
310 if (rk_phy->clk) in rockchip_usb_phy_init()
311 clk_put(rk_phy->clk); in rockchip_usb_phy_init()
326 int regoffs = pdata->phys[pdata->usb_uart_phy].reg; in rockchip_init_usb_uart_common()
333 * Also disable the analog phy components to save power. in rockchip_init_usb_uart_common()
370 * Enable the bypass of uart2 data through the otg usb phy.
371 * See description of rk3288-variant for details.
409 * Enable the bypass of uart2 data through the otg usb phy.
412 * 2. Disable the pull-up resistance on the D+ line by setting
416 * 4. Place the USB PHY in Suspend mode by setting SUSPENDM0 to 1’b0.
457 struct device *dev = &pdev->dev; in rockchip_usb_phy_probe()
465 return -ENOMEM; in rockchip_usb_phy_probe()
467 phy_base->pdata = device_get_match_data(dev); in rockchip_usb_phy_probe()
468 if (!phy_base->pdata) { in rockchip_usb_phy_probe()
469 dev_err(dev, "missing phy data\n"); in rockchip_usb_phy_probe()
470 return -EINVAL; in rockchip_usb_phy_probe()
473 phy_base->dev = dev; in rockchip_usb_phy_probe()
474 phy_base->reg_base = ERR_PTR(-ENODEV); in rockchip_usb_phy_probe()
475 if (dev->parent && dev->parent->of_node) in rockchip_usb_phy_probe()
476 phy_base->reg_base = syscon_node_to_regmap( in rockchip_usb_phy_probe()
477 dev->parent->of_node); in rockchip_usb_phy_probe()
478 if (IS_ERR(phy_base->reg_base)) in rockchip_usb_phy_probe()
479 phy_base->reg_base = syscon_regmap_lookup_by_phandle( in rockchip_usb_phy_probe()
480 dev->of_node, "rockchip,grf"); in rockchip_usb_phy_probe()
481 if (IS_ERR(phy_base->reg_base)) { in rockchip_usb_phy_probe()
482 dev_err(&pdev->dev, "Missing rockchip,grf property\n"); in rockchip_usb_phy_probe()
483 return PTR_ERR(phy_base->reg_base); in rockchip_usb_phy_probe()
486 for_each_available_child_of_node(dev->of_node, child) { in rockchip_usb_phy_probe()
499 { .compatible = "rockchip,rk3066a-usb-phy", .data = &rk3066a_pdata },
500 { .compatible = "rockchip,rk3188-usb-phy", .data = &rk3188_pdata },
501 { .compatible = "rockchip,rk3288-usb-phy", .data = &rk3288_pdata },
510 .name = "rockchip-usb-phy",
533 return -ENOTSUPP; in rockchip_init_usb_uart()
536 pr_debug("%s: using settings for %s\n", __func__, match->compatible); in rockchip_init_usb_uart()
537 data = match->data; in rockchip_init_usb_uart()
539 if (!data->init_usb_uart) { in rockchip_init_usb_uart()
540 pr_err("%s: usb-uart not available on %s\n", in rockchip_init_usb_uart()
541 __func__, match->compatible); in rockchip_init_usb_uart()
542 return -ENOTSUPP; in rockchip_init_usb_uart()
545 grf = ERR_PTR(-ENODEV); in rockchip_init_usb_uart()
546 if (np->parent) in rockchip_init_usb_uart()
547 grf = syscon_node_to_regmap(np->parent); in rockchip_init_usb_uart()
556 ret = data->init_usb_uart(grf, data); in rockchip_init_usb_uart()
575 MODULE_AUTHOR("Yunzhi Li <lyz@rock-chips.com>");
576 MODULE_DESCRIPTION("Rockchip USB 2.0 PHY driver");