162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 */ 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * devres.c - managed gpio resources 462306a36Sopenharmony_ci * This file is based on kernel/irq/devres.c 562306a36Sopenharmony_ci * 662306a36Sopenharmony_ci * Copyright (c) 2011 John Crispin <john@phrozen.org> 762306a36Sopenharmony_ci */ 862306a36Sopenharmony_ci 962306a36Sopenharmony_ci#include <linux/module.h> 1062306a36Sopenharmony_ci#include <linux/err.h> 1162306a36Sopenharmony_ci#include <linux/gpio.h> 1262306a36Sopenharmony_ci#include <linux/gpio/consumer.h> 1362306a36Sopenharmony_ci#include <linux/device.h> 1462306a36Sopenharmony_ci#include <linux/gfp.h> 1562306a36Sopenharmony_ci 1662306a36Sopenharmony_ci#include "gpiolib.h" 1762306a36Sopenharmony_ci 1862306a36Sopenharmony_cistatic void devm_gpiod_release(struct device *dev, void *res) 1962306a36Sopenharmony_ci{ 2062306a36Sopenharmony_ci struct gpio_desc **desc = res; 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_ci gpiod_put(*desc); 2362306a36Sopenharmony_ci} 2462306a36Sopenharmony_ci 2562306a36Sopenharmony_cistatic int devm_gpiod_match(struct device *dev, void *res, void *data) 2662306a36Sopenharmony_ci{ 2762306a36Sopenharmony_ci struct gpio_desc **this = res, **gpio = data; 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_ci return *this == *gpio; 3062306a36Sopenharmony_ci} 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_cistatic void devm_gpiod_release_array(struct device *dev, void *res) 3362306a36Sopenharmony_ci{ 3462306a36Sopenharmony_ci struct gpio_descs **descs = res; 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_ci gpiod_put_array(*descs); 3762306a36Sopenharmony_ci} 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_cistatic int devm_gpiod_match_array(struct device *dev, void *res, void *data) 4062306a36Sopenharmony_ci{ 4162306a36Sopenharmony_ci struct gpio_descs **this = res, **gpios = data; 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_ci return *this == *gpios; 4462306a36Sopenharmony_ci} 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_ci/** 4762306a36Sopenharmony_ci * devm_gpiod_get - Resource-managed gpiod_get() 4862306a36Sopenharmony_ci * @dev: GPIO consumer 4962306a36Sopenharmony_ci * @con_id: function within the GPIO consumer 5062306a36Sopenharmony_ci * @flags: optional GPIO initialization flags 5162306a36Sopenharmony_ci * 5262306a36Sopenharmony_ci * Managed gpiod_get(). GPIO descriptors returned from this function are 5362306a36Sopenharmony_ci * automatically disposed on driver detach. See gpiod_get() for detailed 5462306a36Sopenharmony_ci * information about behavior and return values. 5562306a36Sopenharmony_ci */ 5662306a36Sopenharmony_cistruct gpio_desc *__must_check devm_gpiod_get(struct device *dev, 5762306a36Sopenharmony_ci const char *con_id, 5862306a36Sopenharmony_ci enum gpiod_flags flags) 5962306a36Sopenharmony_ci{ 6062306a36Sopenharmony_ci return devm_gpiod_get_index(dev, con_id, 0, flags); 6162306a36Sopenharmony_ci} 6262306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(devm_gpiod_get); 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_ci/** 6562306a36Sopenharmony_ci * devm_gpiod_get_optional - Resource-managed gpiod_get_optional() 6662306a36Sopenharmony_ci * @dev: GPIO consumer 6762306a36Sopenharmony_ci * @con_id: function within the GPIO consumer 6862306a36Sopenharmony_ci * @flags: optional GPIO initialization flags 6962306a36Sopenharmony_ci * 7062306a36Sopenharmony_ci * Managed gpiod_get_optional(). GPIO descriptors returned from this function 7162306a36Sopenharmony_ci * are automatically disposed on driver detach. See gpiod_get_optional() for 7262306a36Sopenharmony_ci * detailed information about behavior and return values. 7362306a36Sopenharmony_ci */ 7462306a36Sopenharmony_cistruct gpio_desc *__must_check devm_gpiod_get_optional(struct device *dev, 7562306a36Sopenharmony_ci const char *con_id, 7662306a36Sopenharmony_ci enum gpiod_flags flags) 7762306a36Sopenharmony_ci{ 7862306a36Sopenharmony_ci return devm_gpiod_get_index_optional(dev, con_id, 0, flags); 7962306a36Sopenharmony_ci} 8062306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(devm_gpiod_get_optional); 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_ci/** 8362306a36Sopenharmony_ci * devm_gpiod_get_index - Resource-managed gpiod_get_index() 8462306a36Sopenharmony_ci * @dev: GPIO consumer 8562306a36Sopenharmony_ci * @con_id: function within the GPIO consumer 8662306a36Sopenharmony_ci * @idx: index of the GPIO to obtain in the consumer 8762306a36Sopenharmony_ci * @flags: optional GPIO initialization flags 8862306a36Sopenharmony_ci * 8962306a36Sopenharmony_ci * Managed gpiod_get_index(). GPIO descriptors returned from this function are 9062306a36Sopenharmony_ci * automatically disposed on driver detach. See gpiod_get_index() for detailed 9162306a36Sopenharmony_ci * information about behavior and return values. 9262306a36Sopenharmony_ci */ 9362306a36Sopenharmony_cistruct gpio_desc *__must_check devm_gpiod_get_index(struct device *dev, 9462306a36Sopenharmony_ci const char *con_id, 9562306a36Sopenharmony_ci unsigned int idx, 9662306a36Sopenharmony_ci enum gpiod_flags flags) 9762306a36Sopenharmony_ci{ 9862306a36Sopenharmony_ci struct gpio_desc **dr; 9962306a36Sopenharmony_ci struct gpio_desc *desc; 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_ci desc = gpiod_get_index(dev, con_id, idx, flags); 10262306a36Sopenharmony_ci if (IS_ERR(desc)) 10362306a36Sopenharmony_ci return desc; 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_ci /* 10662306a36Sopenharmony_ci * For non-exclusive GPIO descriptors, check if this descriptor is 10762306a36Sopenharmony_ci * already under resource management by this device. 10862306a36Sopenharmony_ci */ 10962306a36Sopenharmony_ci if (flags & GPIOD_FLAGS_BIT_NONEXCLUSIVE) { 11062306a36Sopenharmony_ci struct devres *dres; 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_ci dres = devres_find(dev, devm_gpiod_release, 11362306a36Sopenharmony_ci devm_gpiod_match, &desc); 11462306a36Sopenharmony_ci if (dres) 11562306a36Sopenharmony_ci return desc; 11662306a36Sopenharmony_ci } 11762306a36Sopenharmony_ci 11862306a36Sopenharmony_ci dr = devres_alloc(devm_gpiod_release, sizeof(struct gpio_desc *), 11962306a36Sopenharmony_ci GFP_KERNEL); 12062306a36Sopenharmony_ci if (!dr) { 12162306a36Sopenharmony_ci gpiod_put(desc); 12262306a36Sopenharmony_ci return ERR_PTR(-ENOMEM); 12362306a36Sopenharmony_ci } 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_ci *dr = desc; 12662306a36Sopenharmony_ci devres_add(dev, dr); 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_ci return desc; 12962306a36Sopenharmony_ci} 13062306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(devm_gpiod_get_index); 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_ci/** 13362306a36Sopenharmony_ci * devm_fwnode_gpiod_get_index - get a GPIO descriptor from a given node 13462306a36Sopenharmony_ci * @dev: GPIO consumer 13562306a36Sopenharmony_ci * @fwnode: firmware node containing GPIO reference 13662306a36Sopenharmony_ci * @con_id: function within the GPIO consumer 13762306a36Sopenharmony_ci * @index: index of the GPIO to obtain in the consumer 13862306a36Sopenharmony_ci * @flags: GPIO initialization flags 13962306a36Sopenharmony_ci * @label: label to attach to the requested GPIO 14062306a36Sopenharmony_ci * 14162306a36Sopenharmony_ci * GPIO descriptors returned from this function are automatically disposed on 14262306a36Sopenharmony_ci * driver detach. 14362306a36Sopenharmony_ci * 14462306a36Sopenharmony_ci * On successful request the GPIO pin is configured in accordance with 14562306a36Sopenharmony_ci * provided @flags. 14662306a36Sopenharmony_ci */ 14762306a36Sopenharmony_cistruct gpio_desc *devm_fwnode_gpiod_get_index(struct device *dev, 14862306a36Sopenharmony_ci struct fwnode_handle *fwnode, 14962306a36Sopenharmony_ci const char *con_id, int index, 15062306a36Sopenharmony_ci enum gpiod_flags flags, 15162306a36Sopenharmony_ci const char *label) 15262306a36Sopenharmony_ci{ 15362306a36Sopenharmony_ci struct gpio_desc **dr; 15462306a36Sopenharmony_ci struct gpio_desc *desc; 15562306a36Sopenharmony_ci 15662306a36Sopenharmony_ci dr = devres_alloc(devm_gpiod_release, sizeof(struct gpio_desc *), 15762306a36Sopenharmony_ci GFP_KERNEL); 15862306a36Sopenharmony_ci if (!dr) 15962306a36Sopenharmony_ci return ERR_PTR(-ENOMEM); 16062306a36Sopenharmony_ci 16162306a36Sopenharmony_ci desc = gpiod_find_and_request(dev, fwnode, con_id, index, flags, label, false); 16262306a36Sopenharmony_ci if (IS_ERR(desc)) { 16362306a36Sopenharmony_ci devres_free(dr); 16462306a36Sopenharmony_ci return desc; 16562306a36Sopenharmony_ci } 16662306a36Sopenharmony_ci 16762306a36Sopenharmony_ci *dr = desc; 16862306a36Sopenharmony_ci devres_add(dev, dr); 16962306a36Sopenharmony_ci 17062306a36Sopenharmony_ci return desc; 17162306a36Sopenharmony_ci} 17262306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(devm_fwnode_gpiod_get_index); 17362306a36Sopenharmony_ci 17462306a36Sopenharmony_ci/** 17562306a36Sopenharmony_ci * devm_gpiod_get_index_optional - Resource-managed gpiod_get_index_optional() 17662306a36Sopenharmony_ci * @dev: GPIO consumer 17762306a36Sopenharmony_ci * @con_id: function within the GPIO consumer 17862306a36Sopenharmony_ci * @index: index of the GPIO to obtain in the consumer 17962306a36Sopenharmony_ci * @flags: optional GPIO initialization flags 18062306a36Sopenharmony_ci * 18162306a36Sopenharmony_ci * Managed gpiod_get_index_optional(). GPIO descriptors returned from this 18262306a36Sopenharmony_ci * function are automatically disposed on driver detach. See 18362306a36Sopenharmony_ci * gpiod_get_index_optional() for detailed information about behavior and 18462306a36Sopenharmony_ci * return values. 18562306a36Sopenharmony_ci */ 18662306a36Sopenharmony_cistruct gpio_desc *__must_check devm_gpiod_get_index_optional(struct device *dev, 18762306a36Sopenharmony_ci const char *con_id, 18862306a36Sopenharmony_ci unsigned int index, 18962306a36Sopenharmony_ci enum gpiod_flags flags) 19062306a36Sopenharmony_ci{ 19162306a36Sopenharmony_ci struct gpio_desc *desc; 19262306a36Sopenharmony_ci 19362306a36Sopenharmony_ci desc = devm_gpiod_get_index(dev, con_id, index, flags); 19462306a36Sopenharmony_ci if (gpiod_not_found(desc)) 19562306a36Sopenharmony_ci return NULL; 19662306a36Sopenharmony_ci 19762306a36Sopenharmony_ci return desc; 19862306a36Sopenharmony_ci} 19962306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(devm_gpiod_get_index_optional); 20062306a36Sopenharmony_ci 20162306a36Sopenharmony_ci/** 20262306a36Sopenharmony_ci * devm_gpiod_get_array - Resource-managed gpiod_get_array() 20362306a36Sopenharmony_ci * @dev: GPIO consumer 20462306a36Sopenharmony_ci * @con_id: function within the GPIO consumer 20562306a36Sopenharmony_ci * @flags: optional GPIO initialization flags 20662306a36Sopenharmony_ci * 20762306a36Sopenharmony_ci * Managed gpiod_get_array(). GPIO descriptors returned from this function are 20862306a36Sopenharmony_ci * automatically disposed on driver detach. See gpiod_get_array() for detailed 20962306a36Sopenharmony_ci * information about behavior and return values. 21062306a36Sopenharmony_ci */ 21162306a36Sopenharmony_cistruct gpio_descs *__must_check devm_gpiod_get_array(struct device *dev, 21262306a36Sopenharmony_ci const char *con_id, 21362306a36Sopenharmony_ci enum gpiod_flags flags) 21462306a36Sopenharmony_ci{ 21562306a36Sopenharmony_ci struct gpio_descs **dr; 21662306a36Sopenharmony_ci struct gpio_descs *descs; 21762306a36Sopenharmony_ci 21862306a36Sopenharmony_ci dr = devres_alloc(devm_gpiod_release_array, 21962306a36Sopenharmony_ci sizeof(struct gpio_descs *), GFP_KERNEL); 22062306a36Sopenharmony_ci if (!dr) 22162306a36Sopenharmony_ci return ERR_PTR(-ENOMEM); 22262306a36Sopenharmony_ci 22362306a36Sopenharmony_ci descs = gpiod_get_array(dev, con_id, flags); 22462306a36Sopenharmony_ci if (IS_ERR(descs)) { 22562306a36Sopenharmony_ci devres_free(dr); 22662306a36Sopenharmony_ci return descs; 22762306a36Sopenharmony_ci } 22862306a36Sopenharmony_ci 22962306a36Sopenharmony_ci *dr = descs; 23062306a36Sopenharmony_ci devres_add(dev, dr); 23162306a36Sopenharmony_ci 23262306a36Sopenharmony_ci return descs; 23362306a36Sopenharmony_ci} 23462306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(devm_gpiod_get_array); 23562306a36Sopenharmony_ci 23662306a36Sopenharmony_ci/** 23762306a36Sopenharmony_ci * devm_gpiod_get_array_optional - Resource-managed gpiod_get_array_optional() 23862306a36Sopenharmony_ci * @dev: GPIO consumer 23962306a36Sopenharmony_ci * @con_id: function within the GPIO consumer 24062306a36Sopenharmony_ci * @flags: optional GPIO initialization flags 24162306a36Sopenharmony_ci * 24262306a36Sopenharmony_ci * Managed gpiod_get_array_optional(). GPIO descriptors returned from this 24362306a36Sopenharmony_ci * function are automatically disposed on driver detach. 24462306a36Sopenharmony_ci * See gpiod_get_array_optional() for detailed information about behavior and 24562306a36Sopenharmony_ci * return values. 24662306a36Sopenharmony_ci */ 24762306a36Sopenharmony_cistruct gpio_descs *__must_check 24862306a36Sopenharmony_cidevm_gpiod_get_array_optional(struct device *dev, const char *con_id, 24962306a36Sopenharmony_ci enum gpiod_flags flags) 25062306a36Sopenharmony_ci{ 25162306a36Sopenharmony_ci struct gpio_descs *descs; 25262306a36Sopenharmony_ci 25362306a36Sopenharmony_ci descs = devm_gpiod_get_array(dev, con_id, flags); 25462306a36Sopenharmony_ci if (gpiod_not_found(descs)) 25562306a36Sopenharmony_ci return NULL; 25662306a36Sopenharmony_ci 25762306a36Sopenharmony_ci return descs; 25862306a36Sopenharmony_ci} 25962306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(devm_gpiod_get_array_optional); 26062306a36Sopenharmony_ci 26162306a36Sopenharmony_ci/** 26262306a36Sopenharmony_ci * devm_gpiod_put - Resource-managed gpiod_put() 26362306a36Sopenharmony_ci * @dev: GPIO consumer 26462306a36Sopenharmony_ci * @desc: GPIO descriptor to dispose of 26562306a36Sopenharmony_ci * 26662306a36Sopenharmony_ci * Dispose of a GPIO descriptor obtained with devm_gpiod_get() or 26762306a36Sopenharmony_ci * devm_gpiod_get_index(). Normally this function will not be called as the GPIO 26862306a36Sopenharmony_ci * will be disposed of by the resource management code. 26962306a36Sopenharmony_ci */ 27062306a36Sopenharmony_civoid devm_gpiod_put(struct device *dev, struct gpio_desc *desc) 27162306a36Sopenharmony_ci{ 27262306a36Sopenharmony_ci WARN_ON(devres_release(dev, devm_gpiod_release, devm_gpiod_match, 27362306a36Sopenharmony_ci &desc)); 27462306a36Sopenharmony_ci} 27562306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(devm_gpiod_put); 27662306a36Sopenharmony_ci 27762306a36Sopenharmony_ci/** 27862306a36Sopenharmony_ci * devm_gpiod_unhinge - Remove resource management from a gpio descriptor 27962306a36Sopenharmony_ci * @dev: GPIO consumer 28062306a36Sopenharmony_ci * @desc: GPIO descriptor to remove resource management from 28162306a36Sopenharmony_ci * 28262306a36Sopenharmony_ci * Remove resource management from a GPIO descriptor. This is needed when 28362306a36Sopenharmony_ci * you want to hand over lifecycle management of a descriptor to another 28462306a36Sopenharmony_ci * mechanism. 28562306a36Sopenharmony_ci */ 28662306a36Sopenharmony_ci 28762306a36Sopenharmony_civoid devm_gpiod_unhinge(struct device *dev, struct gpio_desc *desc) 28862306a36Sopenharmony_ci{ 28962306a36Sopenharmony_ci int ret; 29062306a36Sopenharmony_ci 29162306a36Sopenharmony_ci if (IS_ERR_OR_NULL(desc)) 29262306a36Sopenharmony_ci return; 29362306a36Sopenharmony_ci ret = devres_destroy(dev, devm_gpiod_release, 29462306a36Sopenharmony_ci devm_gpiod_match, &desc); 29562306a36Sopenharmony_ci /* 29662306a36Sopenharmony_ci * If the GPIO descriptor is requested as nonexclusive, we 29762306a36Sopenharmony_ci * may call this function several times on the same descriptor 29862306a36Sopenharmony_ci * so it is OK if devres_destroy() returns -ENOENT. 29962306a36Sopenharmony_ci */ 30062306a36Sopenharmony_ci if (ret == -ENOENT) 30162306a36Sopenharmony_ci return; 30262306a36Sopenharmony_ci /* Anything else we should warn about */ 30362306a36Sopenharmony_ci WARN_ON(ret); 30462306a36Sopenharmony_ci} 30562306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(devm_gpiod_unhinge); 30662306a36Sopenharmony_ci 30762306a36Sopenharmony_ci/** 30862306a36Sopenharmony_ci * devm_gpiod_put_array - Resource-managed gpiod_put_array() 30962306a36Sopenharmony_ci * @dev: GPIO consumer 31062306a36Sopenharmony_ci * @descs: GPIO descriptor array to dispose of 31162306a36Sopenharmony_ci * 31262306a36Sopenharmony_ci * Dispose of an array of GPIO descriptors obtained with devm_gpiod_get_array(). 31362306a36Sopenharmony_ci * Normally this function will not be called as the GPIOs will be disposed of 31462306a36Sopenharmony_ci * by the resource management code. 31562306a36Sopenharmony_ci */ 31662306a36Sopenharmony_civoid devm_gpiod_put_array(struct device *dev, struct gpio_descs *descs) 31762306a36Sopenharmony_ci{ 31862306a36Sopenharmony_ci WARN_ON(devres_release(dev, devm_gpiod_release_array, 31962306a36Sopenharmony_ci devm_gpiod_match_array, &descs)); 32062306a36Sopenharmony_ci} 32162306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(devm_gpiod_put_array); 32262306a36Sopenharmony_ci 32362306a36Sopenharmony_cistatic void devm_gpio_release(struct device *dev, void *res) 32462306a36Sopenharmony_ci{ 32562306a36Sopenharmony_ci unsigned *gpio = res; 32662306a36Sopenharmony_ci 32762306a36Sopenharmony_ci gpio_free(*gpio); 32862306a36Sopenharmony_ci} 32962306a36Sopenharmony_ci 33062306a36Sopenharmony_ci/** 33162306a36Sopenharmony_ci * devm_gpio_request - request a GPIO for a managed device 33262306a36Sopenharmony_ci * @dev: device to request the GPIO for 33362306a36Sopenharmony_ci * @gpio: GPIO to allocate 33462306a36Sopenharmony_ci * @label: the name of the requested GPIO 33562306a36Sopenharmony_ci * 33662306a36Sopenharmony_ci * Except for the extra @dev argument, this function takes the 33762306a36Sopenharmony_ci * same arguments and performs the same function as 33862306a36Sopenharmony_ci * gpio_request(). GPIOs requested with this function will be 33962306a36Sopenharmony_ci * automatically freed on driver detach. 34062306a36Sopenharmony_ci */ 34162306a36Sopenharmony_ciint devm_gpio_request(struct device *dev, unsigned gpio, const char *label) 34262306a36Sopenharmony_ci{ 34362306a36Sopenharmony_ci unsigned *dr; 34462306a36Sopenharmony_ci int rc; 34562306a36Sopenharmony_ci 34662306a36Sopenharmony_ci dr = devres_alloc(devm_gpio_release, sizeof(unsigned), GFP_KERNEL); 34762306a36Sopenharmony_ci if (!dr) 34862306a36Sopenharmony_ci return -ENOMEM; 34962306a36Sopenharmony_ci 35062306a36Sopenharmony_ci rc = gpio_request(gpio, label); 35162306a36Sopenharmony_ci if (rc) { 35262306a36Sopenharmony_ci devres_free(dr); 35362306a36Sopenharmony_ci return rc; 35462306a36Sopenharmony_ci } 35562306a36Sopenharmony_ci 35662306a36Sopenharmony_ci *dr = gpio; 35762306a36Sopenharmony_ci devres_add(dev, dr); 35862306a36Sopenharmony_ci 35962306a36Sopenharmony_ci return 0; 36062306a36Sopenharmony_ci} 36162306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(devm_gpio_request); 36262306a36Sopenharmony_ci 36362306a36Sopenharmony_ci/** 36462306a36Sopenharmony_ci * devm_gpio_request_one - request a single GPIO with initial setup 36562306a36Sopenharmony_ci * @dev: device to request for 36662306a36Sopenharmony_ci * @gpio: the GPIO number 36762306a36Sopenharmony_ci * @flags: GPIO configuration as specified by GPIOF_* 36862306a36Sopenharmony_ci * @label: a literal description string of this GPIO 36962306a36Sopenharmony_ci */ 37062306a36Sopenharmony_ciint devm_gpio_request_one(struct device *dev, unsigned gpio, 37162306a36Sopenharmony_ci unsigned long flags, const char *label) 37262306a36Sopenharmony_ci{ 37362306a36Sopenharmony_ci unsigned *dr; 37462306a36Sopenharmony_ci int rc; 37562306a36Sopenharmony_ci 37662306a36Sopenharmony_ci dr = devres_alloc(devm_gpio_release, sizeof(unsigned), GFP_KERNEL); 37762306a36Sopenharmony_ci if (!dr) 37862306a36Sopenharmony_ci return -ENOMEM; 37962306a36Sopenharmony_ci 38062306a36Sopenharmony_ci rc = gpio_request_one(gpio, flags, label); 38162306a36Sopenharmony_ci if (rc) { 38262306a36Sopenharmony_ci devres_free(dr); 38362306a36Sopenharmony_ci return rc; 38462306a36Sopenharmony_ci } 38562306a36Sopenharmony_ci 38662306a36Sopenharmony_ci *dr = gpio; 38762306a36Sopenharmony_ci devres_add(dev, dr); 38862306a36Sopenharmony_ci 38962306a36Sopenharmony_ci return 0; 39062306a36Sopenharmony_ci} 39162306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(devm_gpio_request_one); 39262306a36Sopenharmony_ci 39362306a36Sopenharmony_cistatic void devm_gpio_chip_release(void *data) 39462306a36Sopenharmony_ci{ 39562306a36Sopenharmony_ci struct gpio_chip *gc = data; 39662306a36Sopenharmony_ci 39762306a36Sopenharmony_ci gpiochip_remove(gc); 39862306a36Sopenharmony_ci} 39962306a36Sopenharmony_ci 40062306a36Sopenharmony_ci/** 40162306a36Sopenharmony_ci * devm_gpiochip_add_data_with_key() - Resource managed gpiochip_add_data_with_key() 40262306a36Sopenharmony_ci * @dev: pointer to the device that gpio_chip belongs to. 40362306a36Sopenharmony_ci * @gc: the GPIO chip to register 40462306a36Sopenharmony_ci * @data: driver-private data associated with this chip 40562306a36Sopenharmony_ci * @lock_key: lockdep class for IRQ lock 40662306a36Sopenharmony_ci * @request_key: lockdep class for IRQ request 40762306a36Sopenharmony_ci * 40862306a36Sopenharmony_ci * Context: potentially before irqs will work 40962306a36Sopenharmony_ci * 41062306a36Sopenharmony_ci * The gpio chip automatically be released when the device is unbound. 41162306a36Sopenharmony_ci * 41262306a36Sopenharmony_ci * Returns: 41362306a36Sopenharmony_ci * A negative errno if the chip can't be registered, such as because the 41462306a36Sopenharmony_ci * gc->base is invalid or already associated with a different chip. 41562306a36Sopenharmony_ci * Otherwise it returns zero as a success code. 41662306a36Sopenharmony_ci */ 41762306a36Sopenharmony_ciint devm_gpiochip_add_data_with_key(struct device *dev, struct gpio_chip *gc, void *data, 41862306a36Sopenharmony_ci struct lock_class_key *lock_key, 41962306a36Sopenharmony_ci struct lock_class_key *request_key) 42062306a36Sopenharmony_ci{ 42162306a36Sopenharmony_ci int ret; 42262306a36Sopenharmony_ci 42362306a36Sopenharmony_ci ret = gpiochip_add_data_with_key(gc, data, lock_key, request_key); 42462306a36Sopenharmony_ci if (ret < 0) 42562306a36Sopenharmony_ci return ret; 42662306a36Sopenharmony_ci 42762306a36Sopenharmony_ci return devm_add_action_or_reset(dev, devm_gpio_chip_release, gc); 42862306a36Sopenharmony_ci} 42962306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(devm_gpiochip_add_data_with_key); 430