aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/musb/ux500.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/usb/musb/ux500.c')
-rw-r--r--drivers/usb/musb/ux500.c106
1 files changed, 106 insertions, 0 deletions
diff --git a/drivers/usb/musb/ux500.c b/drivers/usb/musb/ux500.c
index 13a392913769..2c80004e0a83 100644
--- a/drivers/usb/musb/ux500.c
+++ b/drivers/usb/musb/ux500.c
@@ -26,6 +26,7 @@
26#include <linux/err.h> 26#include <linux/err.h>
27#include <linux/io.h> 27#include <linux/io.h>
28#include <linux/platform_device.h> 28#include <linux/platform_device.h>
29#include <linux/usb/musb-ux500.h>
29 30
30#include "musb_core.h" 31#include "musb_core.h"
31 32
@@ -36,6 +37,98 @@ struct ux500_glue {
36}; 37};
37#define glue_to_musb(g) platform_get_drvdata(g->musb) 38#define glue_to_musb(g) platform_get_drvdata(g->musb)
38 39
40static void ux500_musb_set_vbus(struct musb *musb, int is_on)
41{
42 u8 devctl;
43 unsigned long timeout = jiffies + msecs_to_jiffies(1000);
44 /* HDRC controls CPEN, but beware current surges during device
45 * connect. They can trigger transient overcurrent conditions
46 * that must be ignored.
47 */
48
49 devctl = musb_readb(musb->mregs, MUSB_DEVCTL);
50
51 if (is_on) {
52 if (musb->xceiv->state == OTG_STATE_A_IDLE) {
53 /* start the session */
54 devctl |= MUSB_DEVCTL_SESSION;
55 musb_writeb(musb->mregs, MUSB_DEVCTL, devctl);
56 /*
57 * Wait for the musb to set as A device to enable the
58 * VBUS
59 */
60 while (musb_readb(musb->mregs, MUSB_DEVCTL) & 0x80) {
61
62 if (time_after(jiffies, timeout)) {
63 dev_err(musb->controller,
64 "configured as A device timeout");
65 break;
66 }
67 }
68
69 } else {
70 musb->is_active = 1;
71 musb->xceiv->otg->default_a = 1;
72 musb->xceiv->state = OTG_STATE_A_WAIT_VRISE;
73 devctl |= MUSB_DEVCTL_SESSION;
74 MUSB_HST_MODE(musb);
75 }
76 } else {
77 musb->is_active = 0;
78
79 /* NOTE: we're skipping A_WAIT_VFALL -> A_IDLE and jumping
80 * right to B_IDLE...
81 */
82 musb->xceiv->otg->default_a = 0;
83 devctl &= ~MUSB_DEVCTL_SESSION;
84 MUSB_DEV_MODE(musb);
85 }
86 musb_writeb(musb->mregs, MUSB_DEVCTL, devctl);
87
88 /*
89 * Devctl values will be updated after vbus goes below
90 * session_valid. The time taken depends on the capacitance
91 * on VBUS line. The max discharge time can be upto 1 sec
92 * as per the spec. Typically on our platform, it is 200ms
93 */
94 if (!is_on)
95 mdelay(200);
96
97 dev_dbg(musb->controller, "VBUS %s, devctl %02x\n",
98 usb_otg_state_string(musb->xceiv->state),
99 musb_readb(musb->mregs, MUSB_DEVCTL));
100}
101
102static int musb_otg_notifications(struct notifier_block *nb,
103 unsigned long event, void *unused)
104{
105 struct musb *musb = container_of(nb, struct musb, nb);
106
107 dev_dbg(musb->controller, "musb_otg_notifications %ld %s\n",
108 event, usb_otg_state_string(musb->xceiv->state));
109
110 switch (event) {
111 case UX500_MUSB_ID:
112 dev_dbg(musb->controller, "ID GND\n");
113 ux500_musb_set_vbus(musb, 1);
114 break;
115 case UX500_MUSB_VBUS:
116 dev_dbg(musb->controller, "VBUS Connect\n");
117 break;
118 case UX500_MUSB_NONE:
119 dev_dbg(musb->controller, "VBUS Disconnect\n");
120 if (is_host_active(musb))
121 ux500_musb_set_vbus(musb, 0);
122 else
123 musb->xceiv->state = OTG_STATE_B_IDLE;
124 break;
125 default:
126 dev_dbg(musb->controller, "ID float\n");
127 return NOTIFY_DONE;
128 }
129 return NOTIFY_OK;
130}
131
39static irqreturn_t ux500_musb_interrupt(int irq, void *__hci) 132static irqreturn_t ux500_musb_interrupt(int irq, void *__hci)
40{ 133{
41 unsigned long flags; 134 unsigned long flags;
@@ -58,12 +151,21 @@ static irqreturn_t ux500_musb_interrupt(int irq, void *__hci)
58 151
59static int ux500_musb_init(struct musb *musb) 152static int ux500_musb_init(struct musb *musb)
60{ 153{
154 int status;
155
61 musb->xceiv = usb_get_phy(USB_PHY_TYPE_USB2); 156 musb->xceiv = usb_get_phy(USB_PHY_TYPE_USB2);
62 if (IS_ERR_OR_NULL(musb->xceiv)) { 157 if (IS_ERR_OR_NULL(musb->xceiv)) {
63 pr_err("HS USB OTG: no transceiver configured\n"); 158 pr_err("HS USB OTG: no transceiver configured\n");
64 return -EPROBE_DEFER; 159 return -EPROBE_DEFER;
65 } 160 }
66 161
162 musb->nb.notifier_call = musb_otg_notifications;
163 status = usb_register_notifier(musb->xceiv, &musb->nb);
164 if (status < 0) {
165 dev_dbg(musb->controller, "notification register failed\n");
166 return status;
167 }
168
67 musb->isr = ux500_musb_interrupt; 169 musb->isr = ux500_musb_interrupt;
68 170
69 return 0; 171 return 0;
@@ -71,6 +173,8 @@ static int ux500_musb_init(struct musb *musb)
71 173
72static int ux500_musb_exit(struct musb *musb) 174static int ux500_musb_exit(struct musb *musb)
73{ 175{
176 usb_unregister_notifier(musb->xceiv, &musb->nb);
177
74 usb_put_phy(musb->xceiv); 178 usb_put_phy(musb->xceiv);
75 179
76 return 0; 180 return 0;
@@ -79,6 +183,8 @@ static int ux500_musb_exit(struct musb *musb)
79static const struct musb_platform_ops ux500_ops = { 183static const struct musb_platform_ops ux500_ops = {
80 .init = ux500_musb_init, 184 .init = ux500_musb_init,
81 .exit = ux500_musb_exit, 185 .exit = ux500_musb_exit,
186
187 .set_vbus = ux500_musb_set_vbus,
82}; 188};
83 189
84static int ux500_probe(struct platform_device *pdev) 190static int ux500_probe(struct platform_device *pdev)