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