diff options
author | Sebastian Reichel <sre@kernel.org> | 2017-04-13 19:41:45 -0400 |
---|---|---|
committer | Sebastian Reichel <sre@kernel.org> | 2017-04-13 19:41:45 -0400 |
commit | ddaa00ee63e184d86d3963ce3014ae04a6a4fce2 (patch) | |
tree | a82fdd1f6b9bb070e3ca8a6ab03cf2c1a420e4d0 | |
parent | 61489b0f9fa835cd2fef67ae26790cdf64b6b1c7 (diff) | |
parent | 815429b39d94c64f6d05eed9e7c1a9bdfdd5bd70 (diff) |
Merge remote-tracking branch 'chanwoo-extcon/ib-extcon-4.12' into psy-next
-rw-r--r-- | drivers/extcon/devres.c | 61 | ||||
-rw-r--r-- | drivers/extcon/extcon.c | 66 | ||||
-rw-r--r-- | drivers/extcon/extcon.h | 3 | ||||
-rw-r--r-- | include/linux/extcon.h | 21 |
4 files changed, 146 insertions, 5 deletions
diff --git a/drivers/extcon/devres.c b/drivers/extcon/devres.c index b40eb1805927..186fd735eb28 100644 --- a/drivers/extcon/devres.c +++ b/drivers/extcon/devres.c | |||
@@ -50,6 +50,13 @@ static void devm_extcon_dev_notifier_unreg(struct device *dev, void *res) | |||
50 | extcon_unregister_notifier(this->edev, this->id, this->nb); | 50 | extcon_unregister_notifier(this->edev, this->id, this->nb); |
51 | } | 51 | } |
52 | 52 | ||
53 | static void devm_extcon_dev_notifier_all_unreg(struct device *dev, void *res) | ||
54 | { | ||
55 | struct extcon_dev_notifier_devres *this = res; | ||
56 | |||
57 | extcon_unregister_notifier_all(this->edev, this->nb); | ||
58 | } | ||
59 | |||
53 | /** | 60 | /** |
54 | * devm_extcon_dev_allocate - Allocate managed extcon device | 61 | * devm_extcon_dev_allocate - Allocate managed extcon device |
55 | * @dev: device owning the extcon device being created | 62 | * @dev: device owning the extcon device being created |
@@ -214,3 +221,57 @@ void devm_extcon_unregister_notifier(struct device *dev, | |||
214 | devm_extcon_dev_match, edev)); | 221 | devm_extcon_dev_match, edev)); |
215 | } | 222 | } |
216 | EXPORT_SYMBOL(devm_extcon_unregister_notifier); | 223 | EXPORT_SYMBOL(devm_extcon_unregister_notifier); |
224 | |||
225 | /** | ||
226 | * devm_extcon_register_notifier_all() | ||
227 | * - Resource-managed extcon_register_notifier_all() | ||
228 | * @dev: device to allocate extcon device | ||
229 | * @edev: the extcon device that has the external connecotr. | ||
230 | * @nb: a notifier block to be registered. | ||
231 | * | ||
232 | * This function manages automatically the notifier of extcon device using | ||
233 | * device resource management and simplify the control of unregistering | ||
234 | * the notifier of extcon device. To get more information, refer that function. | ||
235 | * | ||
236 | * Returns 0 if success or negaive error number if failure. | ||
237 | */ | ||
238 | int devm_extcon_register_notifier_all(struct device *dev, struct extcon_dev *edev, | ||
239 | struct notifier_block *nb) | ||
240 | { | ||
241 | struct extcon_dev_notifier_devres *ptr; | ||
242 | int ret; | ||
243 | |||
244 | ptr = devres_alloc(devm_extcon_dev_notifier_all_unreg, sizeof(*ptr), | ||
245 | GFP_KERNEL); | ||
246 | if (!ptr) | ||
247 | return -ENOMEM; | ||
248 | |||
249 | ret = extcon_register_notifier_all(edev, nb); | ||
250 | if (ret) { | ||
251 | devres_free(ptr); | ||
252 | return ret; | ||
253 | } | ||
254 | |||
255 | ptr->edev = edev; | ||
256 | ptr->nb = nb; | ||
257 | devres_add(dev, ptr); | ||
258 | |||
259 | return 0; | ||
260 | } | ||
261 | EXPORT_SYMBOL(devm_extcon_register_notifier_all); | ||
262 | |||
263 | /** | ||
264 | * devm_extcon_unregister_notifier_all() | ||
265 | * - Resource-managed extcon_unregister_notifier_all() | ||
266 | * @dev: device to allocate extcon device | ||
267 | * @edev: the extcon device that has the external connecotr. | ||
268 | * @nb: a notifier block to be registered. | ||
269 | */ | ||
270 | void devm_extcon_unregister_notifier_all(struct device *dev, | ||
271 | struct extcon_dev *edev, | ||
272 | struct notifier_block *nb) | ||
273 | { | ||
274 | WARN_ON(devres_release(dev, devm_extcon_dev_notifier_all_unreg, | ||
275 | devm_extcon_dev_match, edev)); | ||
276 | } | ||
277 | EXPORT_SYMBOL(devm_extcon_unregister_notifier_all); | ||
diff --git a/drivers/extcon/extcon.c b/drivers/extcon/extcon.c index 09ac5e70c2f3..e7750545469f 100644 --- a/drivers/extcon/extcon.c +++ b/drivers/extcon/extcon.c | |||
@@ -448,8 +448,19 @@ int extcon_sync(struct extcon_dev *edev, unsigned int id) | |||
448 | spin_lock_irqsave(&edev->lock, flags); | 448 | spin_lock_irqsave(&edev->lock, flags); |
449 | 449 | ||
450 | state = !!(edev->state & BIT(index)); | 450 | state = !!(edev->state & BIT(index)); |
451 | |||
452 | /* | ||
453 | * Call functions in a raw notifier chain for the specific one | ||
454 | * external connector. | ||
455 | */ | ||
451 | raw_notifier_call_chain(&edev->nh[index], state, edev); | 456 | raw_notifier_call_chain(&edev->nh[index], state, edev); |
452 | 457 | ||
458 | /* | ||
459 | * Call functions in a raw notifier chain for the all supported | ||
460 | * external connectors. | ||
461 | */ | ||
462 | raw_notifier_call_chain(&edev->nh_all, state, edev); | ||
463 | |||
453 | /* This could be in interrupt handler */ | 464 | /* This could be in interrupt handler */ |
454 | prop_buf = (char *)get_zeroed_page(GFP_ATOMIC); | 465 | prop_buf = (char *)get_zeroed_page(GFP_ATOMIC); |
455 | if (!prop_buf) { | 466 | if (!prop_buf) { |
@@ -954,6 +965,59 @@ int extcon_unregister_notifier(struct extcon_dev *edev, unsigned int id, | |||
954 | } | 965 | } |
955 | EXPORT_SYMBOL_GPL(extcon_unregister_notifier); | 966 | EXPORT_SYMBOL_GPL(extcon_unregister_notifier); |
956 | 967 | ||
968 | /** | ||
969 | * extcon_register_notifier_all() - Register a notifier block for all connectors | ||
970 | * @edev: the extcon device that has the external connecotr. | ||
971 | * @nb: a notifier block to be registered. | ||
972 | * | ||
973 | * This fucntion registers a notifier block in order to receive the state | ||
974 | * change of all supported external connectors from extcon device. | ||
975 | * And The second parameter given to the callback of nb (val) is | ||
976 | * the current state and third parameter is the edev pointer. | ||
977 | * | ||
978 | * Returns 0 if success or error number if fail | ||
979 | */ | ||
980 | int extcon_register_notifier_all(struct extcon_dev *edev, | ||
981 | struct notifier_block *nb) | ||
982 | { | ||
983 | unsigned long flags; | ||
984 | int ret; | ||
985 | |||
986 | if (!edev || !nb) | ||
987 | return -EINVAL; | ||
988 | |||
989 | spin_lock_irqsave(&edev->lock, flags); | ||
990 | ret = raw_notifier_chain_register(&edev->nh_all, nb); | ||
991 | spin_unlock_irqrestore(&edev->lock, flags); | ||
992 | |||
993 | return ret; | ||
994 | } | ||
995 | EXPORT_SYMBOL_GPL(extcon_register_notifier_all); | ||
996 | |||
997 | /** | ||
998 | * extcon_unregister_notifier_all() - Unregister a notifier block from extcon. | ||
999 | * @edev: the extcon device that has the external connecotr. | ||
1000 | * @nb: a notifier block to be registered. | ||
1001 | * | ||
1002 | * Returns 0 if success or error number if fail | ||
1003 | */ | ||
1004 | int extcon_unregister_notifier_all(struct extcon_dev *edev, | ||
1005 | struct notifier_block *nb) | ||
1006 | { | ||
1007 | unsigned long flags; | ||
1008 | int ret; | ||
1009 | |||
1010 | if (!edev || !nb) | ||
1011 | return -EINVAL; | ||
1012 | |||
1013 | spin_lock_irqsave(&edev->lock, flags); | ||
1014 | ret = raw_notifier_chain_unregister(&edev->nh_all, nb); | ||
1015 | spin_unlock_irqrestore(&edev->lock, flags); | ||
1016 | |||
1017 | return ret; | ||
1018 | } | ||
1019 | EXPORT_SYMBOL_GPL(extcon_unregister_notifier_all); | ||
1020 | |||
957 | static struct attribute *extcon_attrs[] = { | 1021 | static struct attribute *extcon_attrs[] = { |
958 | &dev_attr_state.attr, | 1022 | &dev_attr_state.attr, |
959 | &dev_attr_name.attr, | 1023 | &dev_attr_name.attr, |
@@ -1212,6 +1276,8 @@ int extcon_dev_register(struct extcon_dev *edev) | |||
1212 | for (index = 0; index < edev->max_supported; index++) | 1276 | for (index = 0; index < edev->max_supported; index++) |
1213 | RAW_INIT_NOTIFIER_HEAD(&edev->nh[index]); | 1277 | RAW_INIT_NOTIFIER_HEAD(&edev->nh[index]); |
1214 | 1278 | ||
1279 | RAW_INIT_NOTIFIER_HEAD(&edev->nh_all); | ||
1280 | |||
1215 | dev_set_drvdata(&edev->dev, edev); | 1281 | dev_set_drvdata(&edev->dev, edev); |
1216 | edev->state = 0; | 1282 | edev->state = 0; |
1217 | 1283 | ||
diff --git a/drivers/extcon/extcon.h b/drivers/extcon/extcon.h index 993ddccafe11..dddddcfa0587 100644 --- a/drivers/extcon/extcon.h +++ b/drivers/extcon/extcon.h | |||
@@ -21,6 +21,8 @@ | |||
21 | * @dev: Device of this extcon. | 21 | * @dev: Device of this extcon. |
22 | * @state: Attach/detach state of this extcon. Do not provide at | 22 | * @state: Attach/detach state of this extcon. Do not provide at |
23 | * register-time. | 23 | * register-time. |
24 | * @nh_all: Notifier for the state change events for all supported | ||
25 | * external connectors from this extcon. | ||
24 | * @nh: Notifier for the state change events from this extcon | 26 | * @nh: Notifier for the state change events from this extcon |
25 | * @entry: To support list of extcon devices so that users can | 27 | * @entry: To support list of extcon devices so that users can |
26 | * search for extcon devices based on the extcon name. | 28 | * search for extcon devices based on the extcon name. |
@@ -43,6 +45,7 @@ struct extcon_dev { | |||
43 | 45 | ||
44 | /* Internal data. Please do not set. */ | 46 | /* Internal data. Please do not set. */ |
45 | struct device dev; | 47 | struct device dev; |
48 | struct raw_notifier_head nh_all; | ||
46 | struct raw_notifier_head *nh; | 49 | struct raw_notifier_head *nh; |
47 | struct list_head entry; | 50 | struct list_head entry; |
48 | int max_supported; | 51 | int max_supported; |
diff --git a/include/linux/extcon.h b/include/linux/extcon.h index 7010fb01a81a..7e206a9f88db 100644 --- a/include/linux/extcon.h +++ b/include/linux/extcon.h | |||
@@ -236,11 +236,11 @@ extern int extcon_set_property_capability(struct extcon_dev *edev, | |||
236 | unsigned int id, unsigned int prop); | 236 | unsigned int id, unsigned int prop); |
237 | 237 | ||
238 | /* | 238 | /* |
239 | * Following APIs are to monitor every action of a notifier. | 239 | * Following APIs are to monitor the status change of the external connectors. |
240 | * Registrar gets notified for every external port of a connection device. | 240 | * extcon_register_notifier(*edev, id, *nb) : Register a notifier block |
241 | * Probably this could be used to debug an action of notifier; however, | 241 | * for specific external connector of the extcon. |
242 | * we do not recommend to use this for normal 'notifiee' device drivers who | 242 | * extcon_register_notifier_all(*edev, *nb) : Register a notifier block |
243 | * want to be notified by a specific external port of the notifier. | 243 | * for all supported external connectors of the extcon. |
244 | */ | 244 | */ |
245 | extern int extcon_register_notifier(struct extcon_dev *edev, unsigned int id, | 245 | extern int extcon_register_notifier(struct extcon_dev *edev, unsigned int id, |
246 | struct notifier_block *nb); | 246 | struct notifier_block *nb); |
@@ -253,6 +253,17 @@ extern void devm_extcon_unregister_notifier(struct device *dev, | |||
253 | struct extcon_dev *edev, unsigned int id, | 253 | struct extcon_dev *edev, unsigned int id, |
254 | struct notifier_block *nb); | 254 | struct notifier_block *nb); |
255 | 255 | ||
256 | extern int extcon_register_notifier_all(struct extcon_dev *edev, | ||
257 | struct notifier_block *nb); | ||
258 | extern int extcon_unregister_notifier_all(struct extcon_dev *edev, | ||
259 | struct notifier_block *nb); | ||
260 | extern int devm_extcon_register_notifier_all(struct device *dev, | ||
261 | struct extcon_dev *edev, | ||
262 | struct notifier_block *nb); | ||
263 | extern void devm_extcon_unregister_notifier_all(struct device *dev, | ||
264 | struct extcon_dev *edev, | ||
265 | struct notifier_block *nb); | ||
266 | |||
256 | /* | 267 | /* |
257 | * Following API get the extcon device from devicetree. | 268 | * Following API get the extcon device from devicetree. |
258 | * This function use phandle of devicetree to get extcon device directly. | 269 | * This function use phandle of devicetree to get extcon device directly. |