diff --git a/drivers/extcon/extcon.c b/drivers/extcon/extcon.c index af83ad58819c..16503ab10a79 100644 --- a/drivers/extcon/extcon.c +++ b/drivers/extcon/extcon.c @@ -486,6 +486,21 @@ int extcon_sync(struct extcon_dev *edev, unsigned int id) } EXPORT_SYMBOL_GPL(extcon_sync); +int extcon_blocking_sync(struct extcon_dev *edev, unsigned int id, bool val) +{ + int index; + + if (!edev) + return -EINVAL; + + index = find_cable_index_by_id(edev, id); + if (index < 0) + return index; + + return blocking_notifier_call_chain(&edev->bnh[index], val, edev); +} +EXPORT_SYMBOL(extcon_blocking_sync); + /** * extcon_get_state() - Get the state of an external connector. * @edev: the extcon device @@ -924,6 +939,38 @@ int extcon_register_notifier(struct extcon_dev *edev, unsigned int id, } EXPORT_SYMBOL_GPL(extcon_register_notifier); +int extcon_register_blocking_notifier(struct extcon_dev *edev, unsigned int id, + struct notifier_block *nb) +{ + int idx = -EINVAL; + + if (!edev || !nb) + return -EINVAL; + + idx = find_cable_index_by_id(edev, id); + if (idx < 0) + return idx; + + return blocking_notifier_chain_register(&edev->bnh[idx], nb); +} +EXPORT_SYMBOL(extcon_register_blocking_notifier); + +int extcon_unregister_blocking_notifier(struct extcon_dev *edev, + unsigned int id, struct notifier_block *nb) +{ + int idx; + + if (!edev || !nb) + return -EINVAL; + + idx = find_cable_index_by_id(edev, id); + if (idx < 0) + return idx; + + return blocking_notifier_chain_unregister(&edev->bnh[idx], nb); +} +EXPORT_SYMBOL(extcon_unregister_blocking_notifier); + /** * extcon_unregister_notifier() - Unregister a notifier block from the extcon. * @edev: the extcon device @@ -1258,6 +1305,13 @@ int extcon_dev_register(struct extcon_dev *edev) goto err_dev; } + edev->bnh = devm_kzalloc(&edev->dev, + sizeof(*edev->bnh) * edev->max_supported, GFP_KERNEL); + if (!edev->bnh) { + ret = -ENOMEM; + goto err_dev; + } + for (index = 0; index < edev->max_supported; index++) RAW_INIT_NOTIFIER_HEAD(&edev->nh[index]); diff --git a/drivers/extcon/extcon.h b/drivers/extcon/extcon.h index 93b5e0306966..5b200dd37e43 100644 --- a/drivers/extcon/extcon.h +++ b/drivers/extcon/extcon.h @@ -48,6 +48,7 @@ struct extcon_dev { struct device dev; struct raw_notifier_head nh_all; struct raw_notifier_head *nh; + struct blocking_notifier_head *bnh; struct list_head entry; int max_supported; spinlock_t lock; /* could be called by irq handler */ diff --git a/include/linux/extcon.h b/include/linux/extcon.h index 7f033b1ea568..783b8627d039 100644 --- a/include/linux/extcon.h +++ b/include/linux/extcon.h @@ -208,6 +208,10 @@ extern int extcon_register_notifier(struct extcon_dev *edev, unsigned int id, struct notifier_block *nb); extern int extcon_unregister_notifier(struct extcon_dev *edev, unsigned int id, struct notifier_block *nb); +extern int extcon_register_blocking_notifier(struct extcon_dev *edev, + unsigned int id, struct notifier_block *nb); +extern int extcon_unregister_blocking_notifier(struct extcon_dev *edev, + unsigned int id, struct notifier_block *nb); extern int devm_extcon_register_notifier(struct device *dev, struct extcon_dev *edev, unsigned int id, struct notifier_block *nb); @@ -237,6 +241,8 @@ extern struct extcon_dev *extcon_get_edev_by_phandle(struct device *dev, /* Following API get the name of extcon device. */ extern const char *extcon_get_edev_name(struct extcon_dev *edev); +extern int extcon_blocking_sync(struct extcon_dev *edev, unsigned int id, + bool val); #else /* CONFIG_EXTCON */ static inline int extcon_get_state(struct extcon_dev *edev, unsigned int id) { @@ -268,6 +274,20 @@ static inline int extcon_unregister_notifier(struct extcon_dev *edev, return 0; } +static inline int extcon_register_blocking_notifier(struct extcon_dev *edev, + unsigned int id, + struct notifier_block *nb) +{ + return 0; +} + +static inline int extcon_unregister_blocking_notifier(struct extcon_dev *edev, + unsigned int id, + struct notifier_block *nb) +{ + return 0; +} + static inline int devm_extcon_register_notifier(struct device *dev, struct extcon_dev *edev, unsigned int id, struct notifier_block *nb)