gpio: aggregator: add gpio_aggregator_{alloc, free}()

BugLink: https://bugs.launchpad.net/bugs/2103496

Prepare for the upcoming configfs interface. These functions will be
used by both the existing sysfs interface and the new configfs
interface, reducing code duplication.

No functional change.

Signed-off-by: Koichiro Den<koichiro.den@canonical.com>
Link:https://lore.kernel.org/r/20250407043019.4105613-4-koichiro.den@canonical.com
Signed-off-by: Bartosz Golaszewski<bartosz.golaszewski@linaro.org>

(cherry picked from commit 88fe1d1a646b3b01dcc335c44e7b33ea510f620e linux-next)
Signed-off-by: Koichiro Den<koichiro.den@canonical.com>
Acked-by: Jacob Martin <jacob.martin@canonical.com>
Acked-by: Stefan Bader <stefan.bader@canonical.com>
Signed-off-by: Stefan Bader <stefan.bader@canonical.com>
This commit is contained in:
Koichiro Den
2025-04-15 08:13:00 +02:00
committed by Stefan Bader
parent 323f37aa5c
commit 22cbfca605
+36 -22
View File
@@ -36,12 +36,41 @@
struct gpio_aggregator {
struct gpiod_lookup_table *lookups;
struct platform_device *pdev;
int id;
char args[];
};
static DEFINE_MUTEX(gpio_aggregator_lock); /* protects idr */
static DEFINE_IDR(gpio_aggregator_idr);
static int gpio_aggregator_alloc(struct gpio_aggregator **aggr, size_t arg_size)
{
int ret;
struct gpio_aggregator *new __free(kfree) = kzalloc(
sizeof(*new) + arg_size, GFP_KERNEL);
if (!new)
return -ENOMEM;
scoped_guard(mutex, &gpio_aggregator_lock)
ret = idr_alloc(&gpio_aggregator_idr, new, 0, 0, GFP_KERNEL);
if (ret < 0)
return ret;
new->id = ret;
*aggr = no_free_ptr(new);
return 0;
}
static void gpio_aggregator_free(struct gpio_aggregator *aggr)
{
scoped_guard(mutex, &gpio_aggregator_lock)
idr_remove(&gpio_aggregator_idr, aggr->id);
kfree(aggr);
}
static int gpio_aggregator_add_gpio(struct gpio_aggregator *aggr,
const char *key, int hwnum, unsigned int *n)
{
@@ -444,17 +473,15 @@ static ssize_t gpio_aggregator_new_device_store(struct device_driver *driver,
{
struct gpio_aggregator *aggr;
struct platform_device *pdev;
int res, id;
int res;
if (!try_module_get(THIS_MODULE))
return -ENOENT;
/* kernfs guarantees string termination, so count + 1 is safe */
aggr = kzalloc(sizeof(*aggr) + count + 1, GFP_KERNEL);
if (!aggr) {
res = -ENOMEM;
res = gpio_aggregator_alloc(&aggr, count + 1);
if (res)
goto put_module;
}
memcpy(aggr->args, buf, count + 1);
@@ -465,19 +492,10 @@ static ssize_t gpio_aggregator_new_device_store(struct device_driver *driver,
goto free_ga;
}
mutex_lock(&gpio_aggregator_lock);
id = idr_alloc(&gpio_aggregator_idr, aggr, 0, 0, GFP_KERNEL);
mutex_unlock(&gpio_aggregator_lock);
if (id < 0) {
res = id;
goto free_table;
}
aggr->lookups->dev_id = kasprintf(GFP_KERNEL, "%s.%d", DRV_NAME, id);
aggr->lookups->dev_id = kasprintf(GFP_KERNEL, "%s.%d", DRV_NAME, aggr->id);
if (!aggr->lookups->dev_id) {
res = -ENOMEM;
goto remove_idr;
goto free_table;
}
res = gpio_aggregator_parse(aggr);
@@ -486,7 +504,7 @@ static ssize_t gpio_aggregator_new_device_store(struct device_driver *driver,
gpiod_add_lookup_table(aggr->lookups);
pdev = platform_device_register_simple(DRV_NAME, id, NULL, 0);
pdev = platform_device_register_simple(DRV_NAME, aggr->id, NULL, 0);
if (IS_ERR(pdev)) {
res = PTR_ERR(pdev);
goto remove_table;
@@ -500,14 +518,10 @@ remove_table:
gpiod_remove_lookup_table(aggr->lookups);
free_dev_id:
kfree(aggr->lookups->dev_id);
remove_idr:
mutex_lock(&gpio_aggregator_lock);
idr_remove(&gpio_aggregator_idr, id);
mutex_unlock(&gpio_aggregator_lock);
free_table:
kfree(aggr->lookups);
free_ga:
kfree(aggr);
gpio_aggregator_free(aggr);
put_module:
module_put(THIS_MODULE);
return res;