diff options
Diffstat (limited to 'drivers/usb/otg/twl6030-usb.c')
-rw-r--r-- | drivers/usb/otg/twl6030-usb.c | 56 |
1 files changed, 33 insertions, 23 deletions
diff --git a/drivers/usb/otg/twl6030-usb.c b/drivers/usb/otg/twl6030-usb.c index 28f770103640..8a91b4b832a1 100644 --- a/drivers/usb/otg/twl6030-usb.c +++ b/drivers/usb/otg/twl6030-usb.c | |||
@@ -149,7 +149,6 @@ static int twl6030_set_phy_clk(struct otg_transceiver *x, int on) | |||
149 | 149 | ||
150 | static int twl6030_phy_init(struct otg_transceiver *x) | 150 | static int twl6030_phy_init(struct otg_transceiver *x) |
151 | { | 151 | { |
152 | u8 hw_state; | ||
153 | struct twl6030_usb *twl; | 152 | struct twl6030_usb *twl; |
154 | struct device *dev; | 153 | struct device *dev; |
155 | struct twl4030_usb_data *pdata; | 154 | struct twl4030_usb_data *pdata; |
@@ -158,11 +157,7 @@ static int twl6030_phy_init(struct otg_transceiver *x) | |||
158 | dev = twl->dev; | 157 | dev = twl->dev; |
159 | pdata = dev->platform_data; | 158 | pdata = dev->platform_data; |
160 | 159 | ||
161 | regulator_enable(twl->usb3v3); | 160 | if (twl->linkstat == USB_EVENT_ID) |
162 | |||
163 | hw_state = twl6030_readb(twl, TWL6030_MODULE_ID0, STS_HW_CONDITIONS); | ||
164 | |||
165 | if (hw_state & STS_USB_ID) | ||
166 | pdata->phy_power(twl->dev, 1, 1); | 161 | pdata->phy_power(twl->dev, 1, 1); |
167 | else | 162 | else |
168 | pdata->phy_power(twl->dev, 0, 1); | 163 | pdata->phy_power(twl->dev, 0, 1); |
@@ -180,7 +175,17 @@ static void twl6030_phy_shutdown(struct otg_transceiver *x) | |||
180 | dev = twl->dev; | 175 | dev = twl->dev; |
181 | pdata = dev->platform_data; | 176 | pdata = dev->platform_data; |
182 | pdata->phy_power(twl->dev, 0, 0); | 177 | pdata->phy_power(twl->dev, 0, 0); |
183 | regulator_disable(twl->usb3v3); | 178 | } |
179 | |||
180 | static int twl6030_phy_suspend(struct otg_transceiver *x, int suspend) | ||
181 | { | ||
182 | struct twl6030_usb *twl = xceiv_to_twl(x); | ||
183 | struct device *dev = twl->dev; | ||
184 | struct twl4030_usb_data *pdata = dev->platform_data; | ||
185 | |||
186 | pdata->phy_suspend(dev, suspend); | ||
187 | |||
188 | return 0; | ||
184 | } | 189 | } |
185 | 190 | ||
186 | static int twl6030_usb_ldo_init(struct twl6030_usb *twl) | 191 | static int twl6030_usb_ldo_init(struct twl6030_usb *twl) |
@@ -199,16 +204,6 @@ static int twl6030_usb_ldo_init(struct twl6030_usb *twl) | |||
199 | if (IS_ERR(twl->usb3v3)) | 204 | if (IS_ERR(twl->usb3v3)) |
200 | return -ENODEV; | 205 | return -ENODEV; |
201 | 206 | ||
202 | regulator_enable(twl->usb3v3); | ||
203 | |||
204 | /* Program the VUSB_CFG_TRANS for ACTIVE state. */ | ||
205 | twl6030_writeb(twl, TWL_MODULE_PM_RECEIVER, 0x3F, | ||
206 | VUSB_CFG_TRANS); | ||
207 | |||
208 | /* Program the VUSB_CFG_STATE register to ON on all groups. */ | ||
209 | twl6030_writeb(twl, TWL_MODULE_PM_RECEIVER, 0xE1, | ||
210 | VUSB_CFG_STATE); | ||
211 | |||
212 | /* Program the USB_VBUS_CTRL_SET and set VBUS_ACT_COMP bit */ | 207 | /* Program the USB_VBUS_CTRL_SET and set VBUS_ACT_COMP bit */ |
213 | twl6030_writeb(twl, TWL_MODULE_USB, 0x4, USB_VBUS_CTRL_SET); | 208 | twl6030_writeb(twl, TWL_MODULE_USB, 0x4, USB_VBUS_CTRL_SET); |
214 | 209 | ||
@@ -261,16 +256,25 @@ static irqreturn_t twl6030_usb_irq(int irq, void *_twl) | |||
261 | CONTROLLER_STAT1); | 256 | CONTROLLER_STAT1); |
262 | if (!(hw_state & STS_USB_ID)) { | 257 | if (!(hw_state & STS_USB_ID)) { |
263 | if (vbus_state & VBUS_DET) { | 258 | if (vbus_state & VBUS_DET) { |
259 | regulator_enable(twl->usb3v3); | ||
260 | twl->asleep = 1; | ||
264 | status = USB_EVENT_VBUS; | 261 | status = USB_EVENT_VBUS; |
265 | twl->otg.default_a = false; | 262 | twl->otg.default_a = false; |
266 | twl->otg.state = OTG_STATE_B_IDLE; | 263 | twl->otg.state = OTG_STATE_B_IDLE; |
264 | twl->linkstat = status; | ||
265 | twl->otg.last_event = status; | ||
266 | atomic_notifier_call_chain(&twl->otg.notifier, | ||
267 | status, twl->otg.gadget); | ||
267 | } else { | 268 | } else { |
268 | status = USB_EVENT_NONE; | 269 | status = USB_EVENT_NONE; |
269 | } | ||
270 | if (status >= 0) { | ||
271 | twl->linkstat = status; | 270 | twl->linkstat = status; |
272 | blocking_notifier_call_chain(&twl->otg.notifier, | 271 | twl->otg.last_event = status; |
272 | atomic_notifier_call_chain(&twl->otg.notifier, | ||
273 | status, twl->otg.gadget); | 273 | status, twl->otg.gadget); |
274 | if (twl->asleep) { | ||
275 | regulator_disable(twl->usb3v3); | ||
276 | twl->asleep = 0; | ||
277 | } | ||
274 | } | 278 | } |
275 | } | 279 | } |
276 | sysfs_notify(&twl->dev->kobj, NULL, "vbus"); | 280 | sysfs_notify(&twl->dev->kobj, NULL, "vbus"); |
@@ -288,13 +292,17 @@ static irqreturn_t twl6030_usbotg_irq(int irq, void *_twl) | |||
288 | 292 | ||
289 | if (hw_state & STS_USB_ID) { | 293 | if (hw_state & STS_USB_ID) { |
290 | 294 | ||
295 | regulator_enable(twl->usb3v3); | ||
296 | twl->asleep = 1; | ||
291 | twl6030_writeb(twl, TWL_MODULE_USB, USB_ID_INT_EN_HI_CLR, 0x1); | 297 | twl6030_writeb(twl, TWL_MODULE_USB, USB_ID_INT_EN_HI_CLR, 0x1); |
292 | twl6030_writeb(twl, TWL_MODULE_USB, USB_ID_INT_EN_HI_SET, | 298 | twl6030_writeb(twl, TWL_MODULE_USB, USB_ID_INT_EN_HI_SET, |
293 | 0x10); | 299 | 0x10); |
294 | status = USB_EVENT_ID; | 300 | status = USB_EVENT_ID; |
295 | twl->otg.default_a = true; | 301 | twl->otg.default_a = true; |
296 | twl->otg.state = OTG_STATE_A_IDLE; | 302 | twl->otg.state = OTG_STATE_A_IDLE; |
297 | blocking_notifier_call_chain(&twl->otg.notifier, status, | 303 | twl->linkstat = status; |
304 | twl->otg.last_event = status; | ||
305 | atomic_notifier_call_chain(&twl->otg.notifier, status, | ||
298 | twl->otg.gadget); | 306 | twl->otg.gadget); |
299 | } else { | 307 | } else { |
300 | twl6030_writeb(twl, TWL_MODULE_USB, USB_ID_INT_EN_HI_CLR, | 308 | twl6030_writeb(twl, TWL_MODULE_USB, USB_ID_INT_EN_HI_CLR, |
@@ -303,7 +311,6 @@ static irqreturn_t twl6030_usbotg_irq(int irq, void *_twl) | |||
303 | 0x1); | 311 | 0x1); |
304 | } | 312 | } |
305 | twl6030_writeb(twl, TWL_MODULE_USB, USB_ID_INT_LATCH_CLR, status); | 313 | twl6030_writeb(twl, TWL_MODULE_USB, USB_ID_INT_LATCH_CLR, status); |
306 | twl->linkstat = status; | ||
307 | 314 | ||
308 | return IRQ_HANDLED; | 315 | return IRQ_HANDLED; |
309 | } | 316 | } |
@@ -395,6 +402,7 @@ static int __devinit twl6030_usb_probe(struct platform_device *pdev) | |||
395 | twl->otg.set_vbus = twl6030_set_vbus; | 402 | twl->otg.set_vbus = twl6030_set_vbus; |
396 | twl->otg.init = twl6030_phy_init; | 403 | twl->otg.init = twl6030_phy_init; |
397 | twl->otg.shutdown = twl6030_phy_shutdown; | 404 | twl->otg.shutdown = twl6030_phy_shutdown; |
405 | twl->otg.set_suspend = twl6030_phy_suspend; | ||
398 | 406 | ||
399 | /* init spinlock for workqueue */ | 407 | /* init spinlock for workqueue */ |
400 | spin_lock_init(&twl->lock); | 408 | spin_lock_init(&twl->lock); |
@@ -411,7 +419,7 @@ static int __devinit twl6030_usb_probe(struct platform_device *pdev) | |||
411 | if (device_create_file(&pdev->dev, &dev_attr_vbus)) | 419 | if (device_create_file(&pdev->dev, &dev_attr_vbus)) |
412 | dev_warn(&pdev->dev, "could not create sysfs file\n"); | 420 | dev_warn(&pdev->dev, "could not create sysfs file\n"); |
413 | 421 | ||
414 | BLOCKING_INIT_NOTIFIER_HEAD(&twl->otg.notifier); | 422 | ATOMIC_INIT_NOTIFIER_HEAD(&twl->otg.notifier); |
415 | 423 | ||
416 | twl->irq_enabled = true; | 424 | twl->irq_enabled = true; |
417 | status = request_threaded_irq(twl->irq1, NULL, twl6030_usbotg_irq, | 425 | status = request_threaded_irq(twl->irq1, NULL, twl6030_usbotg_irq, |
@@ -437,7 +445,9 @@ static int __devinit twl6030_usb_probe(struct platform_device *pdev) | |||
437 | return status; | 445 | return status; |
438 | } | 446 | } |
439 | 447 | ||
448 | twl->asleep = 0; | ||
440 | pdata->phy_init(dev); | 449 | pdata->phy_init(dev); |
450 | twl6030_phy_suspend(&twl->otg, 0); | ||
441 | twl6030_enable_irq(&twl->otg); | 451 | twl6030_enable_irq(&twl->otg); |
442 | dev_info(&pdev->dev, "Initialized TWL6030 USB module\n"); | 452 | dev_info(&pdev->dev, "Initialized TWL6030 USB module\n"); |
443 | 453 | ||