diff options
Diffstat (limited to 'drivers/usb/phy/phy-am335x.c')
-rw-r--r-- | drivers/usb/phy/phy-am335x.c | 99 |
1 files changed, 99 insertions, 0 deletions
diff --git a/drivers/usb/phy/phy-am335x.c b/drivers/usb/phy/phy-am335x.c new file mode 100644 index 000000000000..c4d614d1f173 --- /dev/null +++ b/drivers/usb/phy/phy-am335x.c | |||
@@ -0,0 +1,99 @@ | |||
1 | #include <linux/module.h> | ||
2 | #include <linux/platform_device.h> | ||
3 | #include <linux/dma-mapping.h> | ||
4 | #include <linux/usb/otg.h> | ||
5 | #include <linux/usb/usb_phy_gen_xceiv.h> | ||
6 | #include <linux/slab.h> | ||
7 | #include <linux/clk.h> | ||
8 | #include <linux/regulator/consumer.h> | ||
9 | #include <linux/of.h> | ||
10 | #include <linux/of_address.h> | ||
11 | |||
12 | #include "am35x-phy-control.h" | ||
13 | #include "phy-generic.h" | ||
14 | |||
15 | struct am335x_phy { | ||
16 | struct usb_phy_gen_xceiv usb_phy_gen; | ||
17 | struct phy_control *phy_ctrl; | ||
18 | int id; | ||
19 | }; | ||
20 | |||
21 | static int am335x_init(struct usb_phy *phy) | ||
22 | { | ||
23 | struct am335x_phy *am_phy = dev_get_drvdata(phy->dev); | ||
24 | |||
25 | phy_ctrl_power(am_phy->phy_ctrl, am_phy->id, true); | ||
26 | return 0; | ||
27 | } | ||
28 | |||
29 | static void am335x_shutdown(struct usb_phy *phy) | ||
30 | { | ||
31 | struct am335x_phy *am_phy = dev_get_drvdata(phy->dev); | ||
32 | |||
33 | phy_ctrl_power(am_phy->phy_ctrl, am_phy->id, false); | ||
34 | } | ||
35 | |||
36 | static int am335x_phy_probe(struct platform_device *pdev) | ||
37 | { | ||
38 | struct am335x_phy *am_phy; | ||
39 | struct device *dev = &pdev->dev; | ||
40 | int ret; | ||
41 | |||
42 | am_phy = devm_kzalloc(dev, sizeof(*am_phy), GFP_KERNEL); | ||
43 | if (!am_phy) | ||
44 | return -ENOMEM; | ||
45 | |||
46 | am_phy->phy_ctrl = am335x_get_phy_control(dev); | ||
47 | if (!am_phy->phy_ctrl) | ||
48 | return -EPROBE_DEFER; | ||
49 | am_phy->id = of_alias_get_id(pdev->dev.of_node, "phy"); | ||
50 | if (am_phy->id < 0) { | ||
51 | dev_err(&pdev->dev, "Missing PHY id: %d\n", am_phy->id); | ||
52 | return am_phy->id; | ||
53 | } | ||
54 | |||
55 | ret = usb_phy_gen_create_phy(dev, &am_phy->usb_phy_gen, | ||
56 | USB_PHY_TYPE_USB2, 0, false, false); | ||
57 | if (ret) | ||
58 | return ret; | ||
59 | |||
60 | ret = usb_add_phy_dev(&am_phy->usb_phy_gen.phy); | ||
61 | if (ret) | ||
62 | goto err_add; | ||
63 | am_phy->usb_phy_gen.phy.init = am335x_init; | ||
64 | am_phy->usb_phy_gen.phy.shutdown = am335x_shutdown; | ||
65 | |||
66 | platform_set_drvdata(pdev, am_phy); | ||
67 | return 0; | ||
68 | |||
69 | err_add: | ||
70 | usb_phy_gen_cleanup_phy(&am_phy->usb_phy_gen); | ||
71 | return ret; | ||
72 | } | ||
73 | |||
74 | static int am335x_phy_remove(struct platform_device *pdev) | ||
75 | { | ||
76 | struct am335x_phy *am_phy = platform_get_drvdata(pdev); | ||
77 | |||
78 | usb_remove_phy(&am_phy->usb_phy_gen.phy); | ||
79 | return 0; | ||
80 | } | ||
81 | |||
82 | static const struct of_device_id am335x_phy_ids[] = { | ||
83 | { .compatible = "ti,am335x-usb-phy" }, | ||
84 | { } | ||
85 | }; | ||
86 | MODULE_DEVICE_TABLE(of, am335x_phy_ids); | ||
87 | |||
88 | static struct platform_driver am335x_phy_driver = { | ||
89 | .probe = am335x_phy_probe, | ||
90 | .remove = am335x_phy_remove, | ||
91 | .driver = { | ||
92 | .name = "am335x-phy-driver", | ||
93 | .owner = THIS_MODULE, | ||
94 | .of_match_table = of_match_ptr(am335x_phy_ids), | ||
95 | }, | ||
96 | }; | ||
97 | |||
98 | module_platform_driver(am335x_phy_driver); | ||
99 | MODULE_LICENSE("GPL v2"); | ||