usb_phy::notifier is already used by various PHY drivers (including phy_generic) to report VBUS status changes and its usage conflicts with charger current limit changes reporting. Fix that by introducing a second notifier that is dedicated to usb charger notifications. Add usb_charger_XXX_notifier functions. Fix charger drivers that currently (ab)use usb_XXX_notifier() to use the new API. Fixes: a9081a008f84 ("usb: phy: Add USB charger support") Signed-off-by: Ivaylo Dimitrov <ivo.g.dimitrov.75@xxxxxxxxx> --- drivers/power/supply/sc2731_charger.c | 4 ++-- drivers/power/supply/wm831x_power.c | 7 ++++--- drivers/usb/phy/phy.c | 7 +++++-- include/linux/usb/phy.h | 14 ++++++++++++++ 4 files changed, 25 insertions(+), 7 deletions(-) diff --git a/drivers/power/supply/sc2731_charger.c b/drivers/power/supply/sc2731_charger.c index 9ac17cf..e3fa0e2 100644 --- a/drivers/power/supply/sc2731_charger.c +++ b/drivers/power/supply/sc2731_charger.c @@ -500,7 +500,7 @@ static int sc2731_charger_probe(struct platform_device *pdev) } info->usb_notify.notifier_call = sc2731_charger_usb_change; - ret = usb_register_notifier(info->usb_phy, &info->usb_notify); + ret = usb_charger_register_notifier(info->usb_phy, &info->usb_notify); if (ret) { dev_err(&pdev->dev, "failed to register notifier: %d\n", ret); return ret; @@ -515,7 +515,7 @@ static int sc2731_charger_remove(struct platform_device *pdev) { struct sc2731_charger_info *info = platform_get_drvdata(pdev); - usb_unregister_notifier(info->usb_phy, &info->usb_notify); + usb_charger_unregister_notifier(info->usb_phy, &info->usb_notify); return 0; } diff --git a/drivers/power/supply/wm831x_power.c b/drivers/power/supply/wm831x_power.c index 82e3106..0744167 100644 --- a/drivers/power/supply/wm831x_power.c +++ b/drivers/power/supply/wm831x_power.c @@ -650,7 +650,8 @@ static int wm831x_power_probe(struct platform_device *pdev) switch (ret) { case 0: power->usb_notify.notifier_call = wm831x_usb_limit_change; - ret = usb_register_notifier(power->usb_phy, &power->usb_notify); + ret = usb_charger_register_notifier(power->usb_phy, + &power->usb_notify); if (ret) { dev_err(&pdev->dev, "Failed to register notifier: %d\n", ret); @@ -701,8 +702,8 @@ static int wm831x_power_remove(struct platform_device *pdev) int irq, i; if (wm831x_power->usb_phy) { - usb_unregister_notifier(wm831x_power->usb_phy, - &wm831x_power->usb_notify); + usb_charger_unregister_notifier(wm831x_power->usb_phy, + &wm831x_power->usb_notify); } for (i = 0; i < ARRAY_SIZE(wm831x_bat_irqs); i++) { diff --git a/drivers/usb/phy/phy.c b/drivers/usb/phy/phy.c index 1b24492..6b8bf05 100644 --- a/drivers/usb/phy/phy.c +++ b/drivers/usb/phy/phy.c @@ -129,12 +129,13 @@ static void usb_phy_notify_charger_work(struct work_struct *work) case USB_CHARGER_PRESENT: usb_phy_get_charger_current(usb_phy, &min, &max); - atomic_notifier_call_chain(&usb_phy->notifier, max, usb_phy); + atomic_notifier_call_chain(&usb_phy->chg_notifier, max, + usb_phy); break; case USB_CHARGER_ABSENT: usb_phy_set_default_current(usb_phy); - atomic_notifier_call_chain(&usb_phy->notifier, 0, usb_phy); + atomic_notifier_call_chain(&usb_phy->chg_notifier, 0, usb_phy); break; default: dev_warn(usb_phy->dev, "Unknown USB charger state: %d\n", @@ -678,6 +679,7 @@ int usb_add_phy(struct usb_phy *x, enum usb_phy_type type) return ret; ATOMIC_INIT_NOTIFIER_HEAD(&x->notifier); + ATOMIC_INIT_NOTIFIER_HEAD(&x->chg_notifier); spin_lock_irqsave(&phy_lock, flags); @@ -730,6 +732,7 @@ int usb_add_phy_dev(struct usb_phy *x) x->dev->type = &usb_phy_dev_type; ATOMIC_INIT_NOTIFIER_HEAD(&x->notifier); + ATOMIC_INIT_NOTIFIER_HEAD(&x->chg_notifier); spin_lock_irqsave(&phy_lock, flags); list_add_tail(&x->head, &phy_list); diff --git a/include/linux/usb/phy.h b/include/linux/usb/phy.h index e4de6bc..23db554 100644 --- a/include/linux/usb/phy.h +++ b/include/linux/usb/phy.h @@ -111,6 +111,7 @@ struct usb_phy { enum usb_charger_state chg_state; struct usb_charger_current chg_cur; struct work_struct chg_work; + struct atomic_notifier_head chg_notifier; /* for notification of usb_phy_events */ struct atomic_notifier_head notifier; @@ -347,6 +348,19 @@ static inline void usb_phy_set_charger_state(struct usb_phy *usb_phy, atomic_notifier_chain_unregister(&x->notifier, nb); } +/* notifiers */ +static inline int +usb_charger_register_notifier(struct usb_phy *x, struct notifier_block *nb) +{ + return atomic_notifier_chain_register(&x->chg_notifier, nb); +} + +static inline void +usb_charger_unregister_notifier(struct usb_phy *x, struct notifier_block *nb) +{ + atomic_notifier_chain_unregister(&x->chg_notifier, nb); +} + static inline const char *usb_phy_type_string(enum usb_phy_type type) { switch (type) { -- 1.9.1