Lines Matching +full:usb +full:- +full:nop +full:- +full:xceiv

1 // SPDX-License-Identifier: GPL-2.0+
3 * NOP USB transceiver for all USB transceiver which are either built-in
4 * into USB IP or which are mostly autonomous.
10 * This provides a "nop" transceiver for PHYs which are
16 #include <linux/dma-mapping.h>
17 #include <linux/usb/gadget.h>
18 #include <linux/usb/otg.h>
19 #include <linux/usb/usb_phy_generic.h>
27 #include "phy-generic.h"
48 struct usb_phy_generic *nop = dev_get_drvdata(x->dev); in nop_set_suspend() local
52 if (!IS_ERR(nop->clk)) in nop_set_suspend()
53 clk_disable_unprepare(nop->clk); in nop_set_suspend()
54 if (!IS_ERR(nop->vcc) && !device_may_wakeup(x->dev)) in nop_set_suspend()
55 ret = regulator_disable(nop->vcc); in nop_set_suspend()
57 if (!IS_ERR(nop->vcc) && !device_may_wakeup(x->dev)) in nop_set_suspend()
58 ret = regulator_enable(nop->vcc); in nop_set_suspend()
59 if (!IS_ERR(nop->clk)) in nop_set_suspend()
60 clk_prepare_enable(nop->clk); in nop_set_suspend()
66 static void nop_reset(struct usb_phy_generic *nop) in nop_reset() argument
68 if (!nop->gpiod_reset) in nop_reset()
71 gpiod_set_value_cansleep(nop->gpiod_reset, 1); in nop_reset()
73 gpiod_set_value_cansleep(nop->gpiod_reset, 0); in nop_reset()
81 struct usb_phy_generic *nop = dev_get_drvdata(otg->usb_phy->dev); in nop_set_vbus() local
83 if (!nop->vbus_draw) in nop_set_vbus()
86 if (enable && !nop->vbus_draw_enabled) { in nop_set_vbus()
87 ret = regulator_enable(nop->vbus_draw); in nop_set_vbus()
89 nop->vbus_draw_enabled = false; in nop_set_vbus()
91 nop->vbus_draw_enabled = true; in nop_set_vbus()
93 } else if (!enable && nop->vbus_draw_enabled) { in nop_set_vbus()
94 ret = regulator_disable(nop->vbus_draw); in nop_set_vbus()
95 nop->vbus_draw_enabled = false; in nop_set_vbus()
103 struct usb_phy_generic *nop = data; in nop_gpio_vbus_thread() local
104 struct usb_otg *otg = nop->phy.otg; in nop_gpio_vbus_thread()
107 vbus = gpiod_get_value(nop->gpiod_vbus); in nop_gpio_vbus_thread()
108 if ((vbus ^ nop->vbus) == 0) in nop_gpio_vbus_thread()
110 nop->vbus = vbus; in nop_gpio_vbus_thread()
114 otg->state = OTG_STATE_B_PERIPHERAL; in nop_gpio_vbus_thread()
115 nop->phy.last_event = status; in nop_gpio_vbus_thread()
117 atomic_notifier_call_chain(&nop->phy.notifier, status, in nop_gpio_vbus_thread()
118 otg->gadget); in nop_gpio_vbus_thread()
121 otg->state = OTG_STATE_B_IDLE; in nop_gpio_vbus_thread()
122 nop->phy.last_event = status; in nop_gpio_vbus_thread()
124 atomic_notifier_call_chain(&nop->phy.notifier, status, in nop_gpio_vbus_thread()
125 otg->gadget); in nop_gpio_vbus_thread()
132 struct usb_phy_generic *nop = dev_get_drvdata(phy->dev); in usb_gen_phy_init() local
135 if (!IS_ERR(nop->vcc)) { in usb_gen_phy_init()
136 if (regulator_enable(nop->vcc)) in usb_gen_phy_init()
137 dev_err(phy->dev, "Failed to enable power\n"); in usb_gen_phy_init()
140 if (!IS_ERR(nop->clk)) { in usb_gen_phy_init()
141 ret = clk_prepare_enable(nop->clk); in usb_gen_phy_init()
146 nop_reset(nop); in usb_gen_phy_init()
154 struct usb_phy_generic *nop = dev_get_drvdata(phy->dev); in usb_gen_phy_shutdown() local
156 gpiod_set_value_cansleep(nop->gpiod_reset, 1); in usb_gen_phy_shutdown()
158 if (!IS_ERR(nop->clk)) in usb_gen_phy_shutdown()
159 clk_disable_unprepare(nop->clk); in usb_gen_phy_shutdown()
161 if (!IS_ERR(nop->vcc)) { in usb_gen_phy_shutdown()
162 if (regulator_disable(nop->vcc)) in usb_gen_phy_shutdown()
163 dev_err(phy->dev, "Failed to disable power\n"); in usb_gen_phy_shutdown()
171 return -ENODEV; in nop_set_peripheral()
174 otg->gadget = NULL; in nop_set_peripheral()
175 return -ENODEV; in nop_set_peripheral()
178 otg->gadget = gadget; in nop_set_peripheral()
179 if (otg->state == OTG_STATE_B_PERIPHERAL) in nop_set_peripheral()
180 atomic_notifier_call_chain(&otg->usb_phy->notifier, in nop_set_peripheral()
181 USB_EVENT_VBUS, otg->gadget); in nop_set_peripheral()
183 otg->state = OTG_STATE_B_IDLE; in nop_set_peripheral()
190 return -ENODEV; in nop_set_host()
193 otg->host = NULL; in nop_set_host()
194 return -ENODEV; in nop_set_host()
197 otg->host = host; in nop_set_host()
201 int usb_phy_gen_create_phy(struct device *dev, struct usb_phy_generic *nop) in usb_phy_gen_create_phy() argument
209 if (dev->of_node) { in usb_phy_gen_create_phy()
210 struct device_node *node = dev->of_node; in usb_phy_gen_create_phy()
212 if (of_property_read_u32(node, "clock-frequency", &clk_rate)) in usb_phy_gen_create_phy()
217 nop->gpiod_reset = devm_gpiod_get_optional(dev, "reset", in usb_phy_gen_create_phy()
219 err = PTR_ERR_OR_ZERO(nop->gpiod_reset); in usb_phy_gen_create_phy()
221 nop->gpiod_vbus = devm_gpiod_get_optional(dev, in usb_phy_gen_create_phy()
222 "vbus-detect", in usb_phy_gen_create_phy()
224 err = PTR_ERR_OR_ZERO(nop->gpiod_vbus); in usb_phy_gen_create_phy()
230 if (nop->gpiod_reset) in usb_phy_gen_create_phy()
231 gpiod_direction_output(nop->gpiod_reset, 1); in usb_phy_gen_create_phy()
233 nop->phy.otg = devm_kzalloc(dev, sizeof(*nop->phy.otg), in usb_phy_gen_create_phy()
235 if (!nop->phy.otg) in usb_phy_gen_create_phy()
236 return -ENOMEM; in usb_phy_gen_create_phy()
238 nop->clk = devm_clk_get(dev, "main_clk"); in usb_phy_gen_create_phy()
239 if (IS_ERR(nop->clk)) { in usb_phy_gen_create_phy()
241 PTR_ERR(nop->clk)); in usb_phy_gen_create_phy()
243 return PTR_ERR(nop->clk); in usb_phy_gen_create_phy()
246 if (!IS_ERR(nop->clk) && clk_rate) { in usb_phy_gen_create_phy()
247 err = clk_set_rate(nop->clk, clk_rate); in usb_phy_gen_create_phy()
254 nop->vcc = devm_regulator_get_optional(dev, "vcc"); in usb_phy_gen_create_phy()
255 if (IS_ERR(nop->vcc) && PTR_ERR(nop->vcc) != -ENODEV) in usb_phy_gen_create_phy()
256 return dev_err_probe(dev, PTR_ERR(nop->vcc), in usb_phy_gen_create_phy()
259 nop->vbus_draw = devm_regulator_get_exclusive(dev, "vbus"); in usb_phy_gen_create_phy()
260 if (PTR_ERR(nop->vbus_draw) == -ENODEV) in usb_phy_gen_create_phy()
261 nop->vbus_draw = NULL; in usb_phy_gen_create_phy()
262 if (IS_ERR(nop->vbus_draw)) in usb_phy_gen_create_phy()
263 return dev_err_probe(dev, PTR_ERR(nop->vbus_draw), in usb_phy_gen_create_phy()
266 nop->dev = dev; in usb_phy_gen_create_phy()
267 nop->phy.dev = nop->dev; in usb_phy_gen_create_phy()
268 nop->phy.label = "nop-xceiv"; in usb_phy_gen_create_phy()
269 nop->phy.set_suspend = nop_set_suspend; in usb_phy_gen_create_phy()
270 nop->phy.type = type; in usb_phy_gen_create_phy()
272 nop->phy.otg->state = OTG_STATE_UNDEFINED; in usb_phy_gen_create_phy()
273 nop->phy.otg->usb_phy = &nop->phy; in usb_phy_gen_create_phy()
274 nop->phy.otg->set_host = nop_set_host; in usb_phy_gen_create_phy()
275 nop->phy.otg->set_peripheral = nop_set_peripheral; in usb_phy_gen_create_phy()
276 nop->phy.otg->set_vbus = nop_set_vbus; in usb_phy_gen_create_phy()
284 struct device *dev = &pdev->dev; in usb_phy_generic_probe()
285 struct device_node *dn = dev->of_node; in usb_phy_generic_probe()
286 struct usb_phy_generic *nop; in usb_phy_generic_probe() local
289 nop = devm_kzalloc(dev, sizeof(*nop), GFP_KERNEL); in usb_phy_generic_probe()
290 if (!nop) in usb_phy_generic_probe()
291 return -ENOMEM; in usb_phy_generic_probe()
293 err = usb_phy_gen_create_phy(dev, nop); in usb_phy_generic_probe()
296 if (nop->gpiod_vbus) { in usb_phy_generic_probe()
297 err = devm_request_threaded_irq(&pdev->dev, in usb_phy_generic_probe()
298 gpiod_to_irq(nop->gpiod_vbus), in usb_phy_generic_probe()
301 nop); in usb_phy_generic_probe()
303 dev_err(&pdev->dev, "can't request irq %i, err: %d\n", in usb_phy_generic_probe()
304 gpiod_to_irq(nop->gpiod_vbus), err); in usb_phy_generic_probe()
307 nop->phy.otg->state = gpiod_get_value(nop->gpiod_vbus) ? in usb_phy_generic_probe()
311 nop->phy.init = usb_gen_phy_init; in usb_phy_generic_probe()
312 nop->phy.shutdown = usb_gen_phy_shutdown; in usb_phy_generic_probe()
314 err = usb_add_phy_dev(&nop->phy); in usb_phy_generic_probe()
316 dev_err(&pdev->dev, "can't register transceiver, err: %d\n", in usb_phy_generic_probe()
321 platform_set_drvdata(pdev, nop); in usb_phy_generic_probe()
323 device_set_wakeup_capable(&pdev->dev, in usb_phy_generic_probe()
324 of_property_read_bool(dn, "wakeup-source")); in usb_phy_generic_probe()
331 struct usb_phy_generic *nop = platform_get_drvdata(pdev); in usb_phy_generic_remove() local
333 usb_remove_phy(&nop->phy); in usb_phy_generic_remove()
335 if (nop->vbus_draw && nop->vbus_draw_enabled) in usb_phy_generic_remove()
336 regulator_disable(nop->vbus_draw); in usb_phy_generic_remove()
340 { .compatible = "usb-nop-xceiv" },
369 MODULE_DESCRIPTION("NOP USB Transceiver driver");