diff options
author | Kishon Vijay Abraham I <kishon@ti.com> | 2012-06-22 07:32:46 -0400 |
---|---|---|
committer | Felipe Balbi <balbi@ti.com> | 2012-06-25 07:05:35 -0400 |
commit | 662dca54ca67c92b7aa14b9a2ec54acacf33ce45 (patch) | |
tree | 80c77434b1c4d33ce4e7db56f284c9ae65e16a8d /drivers/usb/otg | |
parent | 721002ec1dd55a52425455826af49cf8853b2d4f (diff) |
usb: otg: support for multiple transceivers by a single controller
Add a linked list for keeping multiple PHY instances with different
types so that we can have separate USB2 and USB3 PHYs on one single
board. _get_phy_ has been changed so that the controller gets
the transceiver by type. _remove_phy_ has been added to let the phy
be removed from the phy list.
Signed-off-by: Kishon Vijay Abraham I <kishon@ti.com>
Signed-off-by: Felipe Balbi <balbi@ti.com>
Diffstat (limited to 'drivers/usb/otg')
-rw-r--r-- | drivers/usb/otg/ab8500-usb.c | 4 | ||||
-rw-r--r-- | drivers/usb/otg/fsl_otg.c | 6 | ||||
-rw-r--r-- | drivers/usb/otg/gpio_vbus.c | 4 | ||||
-rw-r--r-- | drivers/usb/otg/isp1301_omap.c | 4 | ||||
-rw-r--r-- | drivers/usb/otg/msm_otg.c | 4 | ||||
-rw-r--r-- | drivers/usb/otg/mv_otg.c | 6 | ||||
-rw-r--r-- | drivers/usb/otg/nop-usb-xceiv.c | 4 | ||||
-rw-r--r-- | drivers/usb/otg/otg.c | 96 | ||||
-rw-r--r-- | drivers/usb/otg/twl4030-usb.c | 2 | ||||
-rw-r--r-- | drivers/usb/otg/twl6030-usb.c | 2 |
10 files changed, 102 insertions, 30 deletions
diff --git a/drivers/usb/otg/ab8500-usb.c b/drivers/usb/otg/ab8500-usb.c index 672e28c81437..ae8ad561f083 100644 --- a/drivers/usb/otg/ab8500-usb.c +++ b/drivers/usb/otg/ab8500-usb.c | |||
@@ -529,7 +529,7 @@ static int __devinit ab8500_usb_probe(struct platform_device *pdev) | |||
529 | if (err < 0) | 529 | if (err < 0) |
530 | goto fail0; | 530 | goto fail0; |
531 | 531 | ||
532 | err = usb_add_phy(&ab->phy); | 532 | err = usb_add_phy(&ab->phy, USB_PHY_TYPE_USB2); |
533 | if (err) { | 533 | if (err) { |
534 | dev_err(&pdev->dev, "Can't register transceiver\n"); | 534 | dev_err(&pdev->dev, "Can't register transceiver\n"); |
535 | goto fail1; | 535 | goto fail1; |
@@ -556,7 +556,7 @@ static int __devexit ab8500_usb_remove(struct platform_device *pdev) | |||
556 | 556 | ||
557 | cancel_work_sync(&ab->phy_dis_work); | 557 | cancel_work_sync(&ab->phy_dis_work); |
558 | 558 | ||
559 | usb_add_phy(NULL); | 559 | usb_remove_phy(&ab->phy); |
560 | 560 | ||
561 | ab8500_usb_host_phy_dis(ab); | 561 | ab8500_usb_host_phy_dis(ab); |
562 | ab8500_usb_peri_phy_dis(ab); | 562 | ab8500_usb_peri_phy_dis(ab); |
diff --git a/drivers/usb/otg/fsl_otg.c b/drivers/usb/otg/fsl_otg.c index 73561edd81de..23c798cb2d7f 100644 --- a/drivers/usb/otg/fsl_otg.c +++ b/drivers/usb/otg/fsl_otg.c | |||
@@ -806,7 +806,7 @@ static int fsl_otg_conf(struct platform_device *pdev) | |||
806 | fsl_otg_dev = fsl_otg_tc; | 806 | fsl_otg_dev = fsl_otg_tc; |
807 | 807 | ||
808 | /* Store the otg transceiver */ | 808 | /* Store the otg transceiver */ |
809 | status = usb_add_phy(&fsl_otg_tc->phy); | 809 | status = usb_add_phy(&fsl_otg_tc->phy, USB_PHY_TYPE_USB2); |
810 | if (status) { | 810 | if (status) { |
811 | pr_warn(FSL_OTG_NAME ": unable to register OTG transceiver.\n"); | 811 | pr_warn(FSL_OTG_NAME ": unable to register OTG transceiver.\n"); |
812 | goto err; | 812 | goto err; |
@@ -824,7 +824,7 @@ err: | |||
824 | int usb_otg_start(struct platform_device *pdev) | 824 | int usb_otg_start(struct platform_device *pdev) |
825 | { | 825 | { |
826 | struct fsl_otg *p_otg; | 826 | struct fsl_otg *p_otg; |
827 | struct usb_phy *otg_trans = usb_get_phy(); | 827 | struct usb_phy *otg_trans = usb_get_phy(USB_PHY_TYPE_USB2); |
828 | struct otg_fsm *fsm; | 828 | struct otg_fsm *fsm; |
829 | int status; | 829 | int status; |
830 | struct resource *res; | 830 | struct resource *res; |
@@ -1134,7 +1134,7 @@ static int __devexit fsl_otg_remove(struct platform_device *pdev) | |||
1134 | { | 1134 | { |
1135 | struct fsl_usb2_platform_data *pdata = pdev->dev.platform_data; | 1135 | struct fsl_usb2_platform_data *pdata = pdev->dev.platform_data; |
1136 | 1136 | ||
1137 | usb_add_phy(NULL); | 1137 | usb_remove_phy(&fsl_otg_dev->phy); |
1138 | free_irq(fsl_otg_dev->irq, fsl_otg_dev); | 1138 | free_irq(fsl_otg_dev->irq, fsl_otg_dev); |
1139 | 1139 | ||
1140 | iounmap((void *)usb_dr_regs); | 1140 | iounmap((void *)usb_dr_regs); |
diff --git a/drivers/usb/otg/gpio_vbus.c b/drivers/usb/otg/gpio_vbus.c index 9b3c264cdb56..a67ffe22179a 100644 --- a/drivers/usb/otg/gpio_vbus.c +++ b/drivers/usb/otg/gpio_vbus.c | |||
@@ -320,7 +320,7 @@ static int __init gpio_vbus_probe(struct platform_device *pdev) | |||
320 | } | 320 | } |
321 | 321 | ||
322 | /* only active when a gadget is registered */ | 322 | /* only active when a gadget is registered */ |
323 | err = usb_add_phy(&gpio_vbus->phy); | 323 | err = usb_add_phy(&gpio_vbus->phy, USB_PHY_TYPE_USB2); |
324 | if (err) { | 324 | if (err) { |
325 | dev_err(&pdev->dev, "can't register transceiver, err: %d\n", | 325 | dev_err(&pdev->dev, "can't register transceiver, err: %d\n", |
326 | err); | 326 | err); |
@@ -354,7 +354,7 @@ static int __exit gpio_vbus_remove(struct platform_device *pdev) | |||
354 | cancel_delayed_work_sync(&gpio_vbus->work); | 354 | cancel_delayed_work_sync(&gpio_vbus->work); |
355 | regulator_put(gpio_vbus->vbus_draw); | 355 | regulator_put(gpio_vbus->vbus_draw); |
356 | 356 | ||
357 | usb_add_phy(NULL); | 357 | usb_remove_phy(&gpio_vbus->phy); |
358 | 358 | ||
359 | free_irq(gpio_vbus->irq, pdev); | 359 | free_irq(gpio_vbus->irq, pdev); |
360 | if (gpio_is_valid(pdata->gpio_pullup)) | 360 | if (gpio_is_valid(pdata->gpio_pullup)) |
diff --git a/drivers/usb/otg/isp1301_omap.c b/drivers/usb/otg/isp1301_omap.c index b74df3fec56f..75cea4ab0985 100644 --- a/drivers/usb/otg/isp1301_omap.c +++ b/drivers/usb/otg/isp1301_omap.c | |||
@@ -1611,7 +1611,7 @@ isp1301_probe(struct i2c_client *i2c, const struct i2c_device_id *id) | |||
1611 | dev_dbg(&i2c->dev, "scheduled timer, %d min\n", TIMER_MINUTES); | 1611 | dev_dbg(&i2c->dev, "scheduled timer, %d min\n", TIMER_MINUTES); |
1612 | #endif | 1612 | #endif |
1613 | 1613 | ||
1614 | status = usb_add_phy(&isp->phy); | 1614 | status = usb_add_phy(&isp->phy, USB_PHY_TYPE_USB2); |
1615 | if (status < 0) | 1615 | if (status < 0) |
1616 | dev_err(&i2c->dev, "can't register transceiver, %d\n", | 1616 | dev_err(&i2c->dev, "can't register transceiver, %d\n", |
1617 | status); | 1617 | status); |
@@ -1650,7 +1650,7 @@ subsys_initcall(isp_init); | |||
1650 | static void __exit isp_exit(void) | 1650 | static void __exit isp_exit(void) |
1651 | { | 1651 | { |
1652 | if (the_transceiver) | 1652 | if (the_transceiver) |
1653 | usb_add_phy(NULL); | 1653 | usb_remove_phy(&the_transceiver->phy); |
1654 | i2c_del_driver(&isp1301_driver); | 1654 | i2c_del_driver(&isp1301_driver); |
1655 | } | 1655 | } |
1656 | module_exit(isp_exit); | 1656 | module_exit(isp_exit); |
diff --git a/drivers/usb/otg/msm_otg.c b/drivers/usb/otg/msm_otg.c index dd606c010035..9f5fc906041a 100644 --- a/drivers/usb/otg/msm_otg.c +++ b/drivers/usb/otg/msm_otg.c | |||
@@ -1555,7 +1555,7 @@ static int __init msm_otg_probe(struct platform_device *pdev) | |||
1555 | phy->otg->set_host = msm_otg_set_host; | 1555 | phy->otg->set_host = msm_otg_set_host; |
1556 | phy->otg->set_peripheral = msm_otg_set_peripheral; | 1556 | phy->otg->set_peripheral = msm_otg_set_peripheral; |
1557 | 1557 | ||
1558 | ret = usb_add_phy(&motg->phy); | 1558 | ret = usb_add_phy(&motg->phy, USB_PHY_TYPE_USB2); |
1559 | if (ret) { | 1559 | if (ret) { |
1560 | dev_err(&pdev->dev, "usb_add_phy failed\n"); | 1560 | dev_err(&pdev->dev, "usb_add_phy failed\n"); |
1561 | goto free_irq; | 1561 | goto free_irq; |
@@ -1624,7 +1624,7 @@ static int __devexit msm_otg_remove(struct platform_device *pdev) | |||
1624 | device_init_wakeup(&pdev->dev, 0); | 1624 | device_init_wakeup(&pdev->dev, 0); |
1625 | pm_runtime_disable(&pdev->dev); | 1625 | pm_runtime_disable(&pdev->dev); |
1626 | 1626 | ||
1627 | usb_add_phy(NULL); | 1627 | usb_remove_phy(phy); |
1628 | free_irq(motg->irq, motg); | 1628 | free_irq(motg->irq, motg); |
1629 | 1629 | ||
1630 | /* | 1630 | /* |
diff --git a/drivers/usb/otg/mv_otg.c b/drivers/usb/otg/mv_otg.c index 18e90fe1fbd1..3f124e8f5792 100644 --- a/drivers/usb/otg/mv_otg.c +++ b/drivers/usb/otg/mv_otg.c | |||
@@ -690,7 +690,7 @@ int mv_otg_remove(struct platform_device *pdev) | |||
690 | for (clk_i = 0; clk_i <= mvotg->clknum; clk_i++) | 690 | for (clk_i = 0; clk_i <= mvotg->clknum; clk_i++) |
691 | clk_put(mvotg->clk[clk_i]); | 691 | clk_put(mvotg->clk[clk_i]); |
692 | 692 | ||
693 | usb_add_phy(NULL); | 693 | usb_remove_phy(&mvotg->phy); |
694 | platform_set_drvdata(pdev, NULL); | 694 | platform_set_drvdata(pdev, NULL); |
695 | 695 | ||
696 | kfree(mvotg->phy.otg); | 696 | kfree(mvotg->phy.otg); |
@@ -853,7 +853,7 @@ static int mv_otg_probe(struct platform_device *pdev) | |||
853 | goto err_disable_clk; | 853 | goto err_disable_clk; |
854 | } | 854 | } |
855 | 855 | ||
856 | retval = usb_add_phy(&mvotg->phy); | 856 | retval = usb_add_phy(&mvotg->phy, USB_PHY_TYPE_USB2); |
857 | if (retval < 0) { | 857 | if (retval < 0) { |
858 | dev_err(&pdev->dev, "can't register transceiver, %d\n", | 858 | dev_err(&pdev->dev, "can't register transceiver, %d\n", |
859 | retval); | 859 | retval); |
@@ -880,7 +880,7 @@ static int mv_otg_probe(struct platform_device *pdev) | |||
880 | return 0; | 880 | return 0; |
881 | 881 | ||
882 | err_set_transceiver: | 882 | err_set_transceiver: |
883 | usb_add_phy(NULL); | 883 | usb_remove_phy(&mvotg->phy); |
884 | err_free_irq: | 884 | err_free_irq: |
885 | free_irq(mvotg->irq, mvotg); | 885 | free_irq(mvotg->irq, mvotg); |
886 | err_disable_clk: | 886 | err_disable_clk: |
diff --git a/drivers/usb/otg/nop-usb-xceiv.c b/drivers/usb/otg/nop-usb-xceiv.c index 33000dae7200..803f958f4133 100644 --- a/drivers/usb/otg/nop-usb-xceiv.c +++ b/drivers/usb/otg/nop-usb-xceiv.c | |||
@@ -117,7 +117,7 @@ static int __devinit nop_usb_xceiv_probe(struct platform_device *pdev) | |||
117 | nop->phy.otg->set_host = nop_set_host; | 117 | nop->phy.otg->set_host = nop_set_host; |
118 | nop->phy.otg->set_peripheral = nop_set_peripheral; | 118 | nop->phy.otg->set_peripheral = nop_set_peripheral; |
119 | 119 | ||
120 | err = usb_add_phy(&nop->phy); | 120 | err = usb_add_phy(&nop->phy, USB_PHY_TYPE_USB2); |
121 | if (err) { | 121 | if (err) { |
122 | dev_err(&pdev->dev, "can't register transceiver, err: %d\n", | 122 | dev_err(&pdev->dev, "can't register transceiver, err: %d\n", |
123 | err); | 123 | err); |
@@ -139,7 +139,7 @@ static int __devexit nop_usb_xceiv_remove(struct platform_device *pdev) | |||
139 | { | 139 | { |
140 | struct nop_usb_xceiv *nop = platform_get_drvdata(pdev); | 140 | struct nop_usb_xceiv *nop = platform_get_drvdata(pdev); |
141 | 141 | ||
142 | usb_add_phy(NULL); | 142 | usb_remove_phy(&nop->phy); |
143 | 143 | ||
144 | platform_set_drvdata(pdev, NULL); | 144 | platform_set_drvdata(pdev, NULL); |
145 | kfree(nop->phy.otg); | 145 | kfree(nop->phy.otg); |
diff --git a/drivers/usb/otg/otg.c b/drivers/usb/otg/otg.c index 300a995cfdbe..a23065820ead 100644 --- a/drivers/usb/otg/otg.c +++ b/drivers/usb/otg/otg.c | |||
@@ -11,14 +11,32 @@ | |||
11 | 11 | ||
12 | #include <linux/kernel.h> | 12 | #include <linux/kernel.h> |
13 | #include <linux/export.h> | 13 | #include <linux/export.h> |
14 | #include <linux/err.h> | ||
14 | #include <linux/device.h> | 15 | #include <linux/device.h> |
15 | 16 | ||
16 | #include <linux/usb/otg.h> | 17 | #include <linux/usb/otg.h> |
17 | 18 | ||
18 | static struct usb_phy *phy; | 19 | static LIST_HEAD(phy_list); |
20 | static DEFINE_SPINLOCK(phy_lock); | ||
21 | |||
22 | static struct usb_phy *__usb_find_phy(struct list_head *list, | ||
23 | enum usb_phy_type type) | ||
24 | { | ||
25 | struct usb_phy *phy = NULL; | ||
26 | |||
27 | list_for_each_entry(phy, list, head) { | ||
28 | if (phy->type != type) | ||
29 | continue; | ||
30 | |||
31 | return phy; | ||
32 | } | ||
33 | |||
34 | return ERR_PTR(-ENODEV); | ||
35 | } | ||
19 | 36 | ||
20 | /** | 37 | /** |
21 | * usb_get_phy - find the (single) USB PHY | 38 | * usb_get_phy - find the USB PHY |
39 | * @type - the type of the phy the controller requires | ||
22 | * | 40 | * |
23 | * Returns the phy driver, after getting a refcount to it; or | 41 | * Returns the phy driver, after getting a refcount to it; or |
24 | * null if there is no such phy. The caller is responsible for | 42 | * null if there is no such phy. The caller is responsible for |
@@ -26,16 +44,30 @@ static struct usb_phy *phy; | |||
26 | * | 44 | * |
27 | * For use by USB host and peripheral drivers. | 45 | * For use by USB host and peripheral drivers. |
28 | */ | 46 | */ |
29 | struct usb_phy *usb_get_phy(void) | 47 | struct usb_phy *usb_get_phy(enum usb_phy_type type) |
30 | { | 48 | { |
31 | if (phy) | 49 | struct usb_phy *phy = NULL; |
32 | get_device(phy->dev); | 50 | unsigned long flags; |
51 | |||
52 | spin_lock_irqsave(&phy_lock, flags); | ||
53 | |||
54 | phy = __usb_find_phy(&phy_list, type); | ||
55 | if (IS_ERR(phy)) { | ||
56 | pr_err("unable to find transceiver of type %s\n", | ||
57 | usb_phy_type_string(type)); | ||
58 | return phy; | ||
59 | } | ||
60 | |||
61 | get_device(phy->dev); | ||
62 | |||
63 | spin_unlock_irqrestore(&phy_lock, flags); | ||
64 | |||
33 | return phy; | 65 | return phy; |
34 | } | 66 | } |
35 | EXPORT_SYMBOL(usb_get_phy); | 67 | EXPORT_SYMBOL(usb_get_phy); |
36 | 68 | ||
37 | /** | 69 | /** |
38 | * usb_put_phy - release the (single) USB PHY | 70 | * usb_put_phy - release the USB PHY |
39 | * @x: the phy returned by usb_get_phy() | 71 | * @x: the phy returned by usb_get_phy() |
40 | * | 72 | * |
41 | * Releases a refcount the caller received from usb_get_phy(). | 73 | * Releases a refcount the caller received from usb_get_phy(). |
@@ -50,22 +82,62 @@ void usb_put_phy(struct usb_phy *x) | |||
50 | EXPORT_SYMBOL(usb_put_phy); | 82 | EXPORT_SYMBOL(usb_put_phy); |
51 | 83 | ||
52 | /** | 84 | /** |
53 | * usb_add_phy - declare the (single) USB PHY | 85 | * usb_add_phy - declare the USB PHY |
54 | * @x: the USB phy to be used; or NULL | 86 | * @x: the USB phy to be used; or NULL |
87 | * @type - the type of this PHY | ||
55 | * | 88 | * |
56 | * This call is exclusively for use by phy drivers, which | 89 | * This call is exclusively for use by phy drivers, which |
57 | * coordinate the activities of drivers for host and peripheral | 90 | * coordinate the activities of drivers for host and peripheral |
58 | * controllers, and in some cases for VBUS current regulation. | 91 | * controllers, and in some cases for VBUS current regulation. |
59 | */ | 92 | */ |
60 | int usb_add_phy(struct usb_phy *x) | 93 | int usb_add_phy(struct usb_phy *x, enum usb_phy_type type) |
61 | { | 94 | { |
62 | if (phy && x) | 95 | int ret = 0; |
63 | return -EBUSY; | 96 | unsigned long flags; |
64 | phy = x; | 97 | struct usb_phy *phy; |
65 | return 0; | 98 | |
99 | if (x && x->type != USB_PHY_TYPE_UNDEFINED) { | ||
100 | dev_err(x->dev, "not accepting initialized PHY %s\n", x->label); | ||
101 | return -EINVAL; | ||
102 | } | ||
103 | |||
104 | spin_lock_irqsave(&phy_lock, flags); | ||
105 | |||
106 | list_for_each_entry(phy, &phy_list, head) { | ||
107 | if (phy->type == type) { | ||
108 | ret = -EBUSY; | ||
109 | dev_err(x->dev, "transceiver type %s already exists\n", | ||
110 | usb_phy_type_string(type)); | ||
111 | goto out; | ||
112 | } | ||
113 | } | ||
114 | |||
115 | x->type = type; | ||
116 | list_add_tail(&x->head, &phy_list); | ||
117 | |||
118 | out: | ||
119 | spin_unlock_irqrestore(&phy_lock, flags); | ||
120 | return ret; | ||
66 | } | 121 | } |
67 | EXPORT_SYMBOL(usb_add_phy); | 122 | EXPORT_SYMBOL(usb_add_phy); |
68 | 123 | ||
124 | /** | ||
125 | * usb_remove_phy - remove the OTG PHY | ||
126 | * @x: the USB OTG PHY to be removed; | ||
127 | * | ||
128 | * This reverts the effects of usb_add_phy | ||
129 | */ | ||
130 | void usb_remove_phy(struct usb_phy *x) | ||
131 | { | ||
132 | unsigned long flags; | ||
133 | |||
134 | spin_lock_irqsave(&phy_lock, flags); | ||
135 | if (x) | ||
136 | list_del(&x->head); | ||
137 | spin_unlock_irqrestore(&phy_lock, flags); | ||
138 | } | ||
139 | EXPORT_SYMBOL(usb_remove_phy); | ||
140 | |||
69 | const char *otg_state_string(enum usb_otg_state state) | 141 | const char *otg_state_string(enum usb_otg_state state) |
70 | { | 142 | { |
71 | switch (state) { | 143 | switch (state) { |
diff --git a/drivers/usb/otg/twl4030-usb.c b/drivers/usb/otg/twl4030-usb.c index 01022c891e26..25a09fabbe35 100644 --- a/drivers/usb/otg/twl4030-usb.c +++ b/drivers/usb/otg/twl4030-usb.c | |||
@@ -633,7 +633,7 @@ static int __devinit twl4030_usb_probe(struct platform_device *pdev) | |||
633 | kfree(twl); | 633 | kfree(twl); |
634 | return err; | 634 | return err; |
635 | } | 635 | } |
636 | usb_add_phy(&twl->phy); | 636 | usb_add_phy(&twl->phy, USB_PHY_TYPE_USB2); |
637 | 637 | ||
638 | platform_set_drvdata(pdev, twl); | 638 | platform_set_drvdata(pdev, twl); |
639 | if (device_create_file(&pdev->dev, &dev_attr_vbus)) | 639 | if (device_create_file(&pdev->dev, &dev_attr_vbus)) |
diff --git a/drivers/usb/otg/twl6030-usb.c b/drivers/usb/otg/twl6030-usb.c index a8be20878eb9..dbee00aea755 100644 --- a/drivers/usb/otg/twl6030-usb.c +++ b/drivers/usb/otg/twl6030-usb.c | |||
@@ -443,7 +443,7 @@ static int __devinit twl6030_usb_probe(struct platform_device *pdev) | |||
443 | kfree(twl); | 443 | kfree(twl); |
444 | return err; | 444 | return err; |
445 | } | 445 | } |
446 | usb_add_phy(&twl->phy); | 446 | usb_add_phy(&twl->phy, USB_PHY_TYPE_USB2); |
447 | 447 | ||
448 | platform_set_drvdata(pdev, twl); | 448 | platform_set_drvdata(pdev, twl); |
449 | if (device_create_file(&pdev->dev, &dev_attr_vbus)) | 449 | if (device_create_file(&pdev->dev, &dev_attr_vbus)) |