// SPDX-License-Identifier: GPL-2.0-only1/*2* drivers/extcon/devres.c - EXTCON device's resource management3*4* Copyright (C) 2016 Samsung Electronics5* Author: Chanwoo Choi <[email protected]>6*/78#include "extcon.h"910static int devm_extcon_dev_match(struct device *dev, void *res, void *data)11{12struct extcon_dev **r = res;1314if (WARN_ON(!r || !*r))15return 0;1617return *r == data;18}1920static void devm_extcon_dev_release(struct device *dev, void *res)21{22extcon_dev_free(*(struct extcon_dev **)res);23}242526static void devm_extcon_dev_unreg(struct device *dev, void *res)27{28extcon_dev_unregister(*(struct extcon_dev **)res);29}3031struct extcon_dev_notifier_devres {32struct extcon_dev *edev;33unsigned int id;34struct notifier_block *nb;35};3637static void devm_extcon_dev_notifier_unreg(struct device *dev, void *res)38{39struct extcon_dev_notifier_devres *this = res;4041extcon_unregister_notifier(this->edev, this->id, this->nb);42}4344static void devm_extcon_dev_notifier_all_unreg(struct device *dev, void *res)45{46struct extcon_dev_notifier_devres *this = res;4748extcon_unregister_notifier_all(this->edev, this->nb);49}5051/**52* devm_extcon_dev_allocate - Allocate managed extcon device53* @dev: the device owning the extcon device being created54* @supported_cable: the array of the supported external connectors55* ending with EXTCON_NONE.56*57* This function manages automatically the memory of extcon device using device58* resource management and simplify the control of freeing the memory of extcon59* device.60*61* Returns the pointer memory of allocated extcon_dev if success62* or ERR_PTR(err) if fail63*/64struct extcon_dev *devm_extcon_dev_allocate(struct device *dev,65const unsigned int *supported_cable)66{67struct extcon_dev **ptr, *edev;6869ptr = devres_alloc(devm_extcon_dev_release, sizeof(*ptr), GFP_KERNEL);70if (!ptr)71return ERR_PTR(-ENOMEM);7273edev = extcon_dev_allocate(supported_cable);74if (IS_ERR(edev)) {75devres_free(ptr);76return edev;77}7879edev->dev.parent = dev;8081*ptr = edev;82devres_add(dev, ptr);8384return edev;85}86EXPORT_SYMBOL_GPL(devm_extcon_dev_allocate);8788/**89* devm_extcon_dev_free() - Resource-managed extcon_dev_unregister()90* @dev: the device owning the extcon device being created91* @edev: the extcon device to be freed92*93* Free the memory that is allocated with devm_extcon_dev_allocate()94* function.95*/96void devm_extcon_dev_free(struct device *dev, struct extcon_dev *edev)97{98WARN_ON(devres_release(dev, devm_extcon_dev_release,99devm_extcon_dev_match, edev));100}101EXPORT_SYMBOL_GPL(devm_extcon_dev_free);102103/**104* devm_extcon_dev_register() - Resource-managed extcon_dev_register()105* @dev: the device owning the extcon device being created106* @edev: the extcon device to be registered107*108* this function, that extcon device is automatically unregistered on driver109* detach. Internally this function calls extcon_dev_register() function.110* To get more information, refer that function.111*112* If extcon device is registered with this function and the device needs to be113* unregistered separately, devm_extcon_dev_unregister() should be used.114*115* Returns 0 if success or negaive error number if failure.116*/117int devm_extcon_dev_register(struct device *dev, struct extcon_dev *edev)118{119struct extcon_dev **ptr;120int ret;121122ptr = devres_alloc(devm_extcon_dev_unreg, sizeof(*ptr), GFP_KERNEL);123if (!ptr)124return -ENOMEM;125126ret = extcon_dev_register(edev);127if (ret) {128devres_free(ptr);129return ret;130}131132*ptr = edev;133devres_add(dev, ptr);134135return 0;136}137EXPORT_SYMBOL_GPL(devm_extcon_dev_register);138139/**140* devm_extcon_dev_unregister() - Resource-managed extcon_dev_unregister()141* @dev: the device owning the extcon device being created142* @edev: the extcon device to unregistered143*144* Unregister extcon device that is registered with devm_extcon_dev_register()145* function.146*/147void devm_extcon_dev_unregister(struct device *dev, struct extcon_dev *edev)148{149WARN_ON(devres_release(dev, devm_extcon_dev_unreg,150devm_extcon_dev_match, edev));151}152EXPORT_SYMBOL_GPL(devm_extcon_dev_unregister);153154/**155* devm_extcon_register_notifier() - Resource-managed extcon_register_notifier()156* @dev: the device owning the extcon device being created157* @edev: the extcon device158* @id: the unique id among the extcon enumeration159* @nb: a notifier block to be registered160*161* This function manages automatically the notifier of extcon device using162* device resource management and simplify the control of unregistering163* the notifier of extcon device.164*165* Note that the second parameter given to the callback of nb (val) is166* "old_state", not the current state. The current state can be retrieved167* by looking at the third pameter (edev pointer)'s state value.168*169* Returns 0 if success or negaive error number if failure.170*/171int devm_extcon_register_notifier(struct device *dev, struct extcon_dev *edev,172unsigned int id, struct notifier_block *nb)173{174struct extcon_dev_notifier_devres *ptr;175int ret;176177ptr = devres_alloc(devm_extcon_dev_notifier_unreg, sizeof(*ptr),178GFP_KERNEL);179if (!ptr)180return -ENOMEM;181182ret = extcon_register_notifier(edev, id, nb);183if (ret) {184devres_free(ptr);185return ret;186}187188ptr->edev = edev;189ptr->id = id;190ptr->nb = nb;191devres_add(dev, ptr);192193return 0;194}195EXPORT_SYMBOL(devm_extcon_register_notifier);196197/**198* devm_extcon_unregister_notifier()199* - Resource-managed extcon_unregister_notifier()200* @dev: the device owning the extcon device being created201* @edev: the extcon device202* @id: the unique id among the extcon enumeration203* @nb: a notifier block to be registered204*/205void devm_extcon_unregister_notifier(struct device *dev,206struct extcon_dev *edev, unsigned int id,207struct notifier_block *nb)208{209WARN_ON(devres_release(dev, devm_extcon_dev_notifier_unreg,210devm_extcon_dev_match, edev));211}212EXPORT_SYMBOL(devm_extcon_unregister_notifier);213214/**215* devm_extcon_register_notifier_all()216* - Resource-managed extcon_register_notifier_all()217* @dev: the device owning the extcon device being created218* @edev: the extcon device219* @nb: a notifier block to be registered220*221* This function manages automatically the notifier of extcon device using222* device resource management and simplify the control of unregistering223* the notifier of extcon device. To get more information, refer that function.224*225* Returns 0 if success or negaive error number if failure.226*/227int devm_extcon_register_notifier_all(struct device *dev, struct extcon_dev *edev,228struct notifier_block *nb)229{230struct extcon_dev_notifier_devres *ptr;231int ret;232233ptr = devres_alloc(devm_extcon_dev_notifier_all_unreg, sizeof(*ptr),234GFP_KERNEL);235if (!ptr)236return -ENOMEM;237238ret = extcon_register_notifier_all(edev, nb);239if (ret) {240devres_free(ptr);241return ret;242}243244ptr->edev = edev;245ptr->nb = nb;246devres_add(dev, ptr);247248return 0;249}250EXPORT_SYMBOL(devm_extcon_register_notifier_all);251252/**253* devm_extcon_unregister_notifier_all()254* - Resource-managed extcon_unregister_notifier_all()255* @dev: the device owning the extcon device being created256* @edev: the extcon device257* @nb: a notifier block to be registered258*/259void devm_extcon_unregister_notifier_all(struct device *dev,260struct extcon_dev *edev,261struct notifier_block *nb)262{263WARN_ON(devres_release(dev, devm_extcon_dev_notifier_all_unreg,264devm_extcon_dev_match, edev));265}266EXPORT_SYMBOL(devm_extcon_unregister_notifier_all);267268269