Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

phy: phy-twl4030-usb: fix denied runtime access

When runtime is not enabled, pm_runtime_get_sync() returns -EACCESS,
the counter will be incremented but the resume callback not called,
so enumeration and charging will not start properly.
To avoid that happen, disable irq on suspend and recheck on resume.

Practically this happens when the device is woken up from suspend by
plugging in usb.

Signed-off-by: Andreas Kemnade <andreas@kemnade.info>
Signed-off-by: Kishon Vijay Abraham I <kishon@ti.com>

authored by

Andreas Kemnade and committed by
Kishon Vijay Abraham I
6c7103aa 979b519c

+29
+29
drivers/phy/ti/phy-twl4030-usb.c
··· 144 144 #define PMBR1 0x0D 145 145 #define GPIO_USB_4PIN_ULPI_2430C (3 << 0) 146 146 147 + static irqreturn_t twl4030_usb_irq(int irq, void *_twl); 147 148 /* 148 149 * If VBUS is valid or ID is ground, then we know a 149 150 * cable is present and we need to be runtime-enabled ··· 394 393 pwr |= PHY_PWR_PHYPWD; 395 394 396 395 WARN_ON(twl4030_usb_write_verify(twl, PHY_PWR_CTRL, pwr) < 0); 396 + } 397 + 398 + static int __maybe_unused twl4030_usb_suspend(struct device *dev) 399 + { 400 + struct twl4030_usb *twl = dev_get_drvdata(dev); 401 + 402 + /* 403 + * we need enabled runtime on resume, 404 + * so turn irq off here, so we do not get it early 405 + * note: wakeup on usb plug works independently of this 406 + */ 407 + dev_dbg(twl->dev, "%s\n", __func__); 408 + disable_irq(twl->irq); 409 + 410 + return 0; 411 + } 412 + 413 + static int __maybe_unused twl4030_usb_resume(struct device *dev) 414 + { 415 + struct twl4030_usb *twl = dev_get_drvdata(dev); 416 + 417 + dev_dbg(twl->dev, "%s\n", __func__); 418 + enable_irq(twl->irq); 419 + /* check whether cable status changed */ 420 + twl4030_usb_irq(0, twl); 421 + 422 + return 0; 397 423 } 398 424 399 425 static int __maybe_unused twl4030_usb_runtime_suspend(struct device *dev) ··· 683 655 static const struct dev_pm_ops twl4030_usb_pm_ops = { 684 656 SET_RUNTIME_PM_OPS(twl4030_usb_runtime_suspend, 685 657 twl4030_usb_runtime_resume, NULL) 658 + SET_SYSTEM_SLEEP_PM_OPS(twl4030_usb_suspend, twl4030_usb_resume) 686 659 }; 687 660 688 661 static int twl4030_usb_probe(struct platform_device *pdev)