gpio: aggregator: reorder functions to prepare for configfs introduction

Reorder functions in drivers/gpio/gpio-aggregator.c to prepare for the
configfs-based interface additions in subsequent commits. Arrange the
code so that the configfs implementations will appear above the existing
sysfs-specific code, since the latter will partly depend on the configfs
interface implementations when it starts to expose the settings to
configfs.

The order in drivers/gpio/gpio-aggregator.c will be as follows:

* Basic gpio_aggregator/gpio_aggregator_line representations
* Common utility functions
* GPIO Forwarder implementations
* Configfs interface implementations
* Sysfs interface implementations
* Platform device implementations
* Module init/exit implementations

This separate commit ensures a clean diff for the subsequent commits.

No functional change.

Reviewed-by: Geert Uytterhoeven <geert+renesas@glider.be>
Signed-off-by: Koichiro Den <koichiro.den@canonical.com>
Link: https://lore.kernel.org/r/20250407043019.4105613-2-koichiro.den@canonical.com
Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
This commit is contained in:
Koichiro Den 2025-04-07 13:30:11 +09:00 committed by Bartosz Golaszewski
parent dad3386b18
commit 7a56efeabf

View File

@ -61,194 +61,6 @@ static int aggr_add_gpio(struct gpio_aggregator *aggr, const char *key,
return 0;
}
static int aggr_parse(struct gpio_aggregator *aggr)
{
char *args = skip_spaces(aggr->args);
char *name, *offsets, *p;
unsigned int i, n = 0;
int error = 0;
unsigned long *bitmap __free(bitmap) =
bitmap_alloc(AGGREGATOR_MAX_GPIOS, GFP_KERNEL);
if (!bitmap)
return -ENOMEM;
args = next_arg(args, &name, &p);
while (*args) {
args = next_arg(args, &offsets, &p);
p = get_options(offsets, 0, &error);
if (error == 0 || *p) {
/* Named GPIO line */
error = aggr_add_gpio(aggr, name, U16_MAX, &n);
if (error)
return error;
name = offsets;
continue;
}
/* GPIO chip + offset(s) */
error = bitmap_parselist(offsets, bitmap, AGGREGATOR_MAX_GPIOS);
if (error) {
pr_err("Cannot parse %s: %d\n", offsets, error);
return error;
}
for_each_set_bit(i, bitmap, AGGREGATOR_MAX_GPIOS) {
error = aggr_add_gpio(aggr, name, i, &n);
if (error)
return error;
}
args = next_arg(args, &name, &p);
}
if (!n) {
pr_err("No GPIOs specified\n");
return -EINVAL;
}
return 0;
}
static ssize_t new_device_store(struct device_driver *driver, const char *buf,
size_t count)
{
struct gpio_aggregator *aggr;
struct platform_device *pdev;
int res, id;
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;
goto put_module;
}
memcpy(aggr->args, buf, count + 1);
aggr->lookups = kzalloc(struct_size(aggr->lookups, table, 1),
GFP_KERNEL);
if (!aggr->lookups) {
res = -ENOMEM;
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);
if (!aggr->lookups->dev_id) {
res = -ENOMEM;
goto remove_idr;
}
res = aggr_parse(aggr);
if (res)
goto free_dev_id;
gpiod_add_lookup_table(aggr->lookups);
pdev = platform_device_register_simple(DRV_NAME, id, NULL, 0);
if (IS_ERR(pdev)) {
res = PTR_ERR(pdev);
goto remove_table;
}
aggr->pdev = pdev;
module_put(THIS_MODULE);
return count;
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);
put_module:
module_put(THIS_MODULE);
return res;
}
static DRIVER_ATTR_WO(new_device);
static void gpio_aggregator_free(struct gpio_aggregator *aggr)
{
platform_device_unregister(aggr->pdev);
gpiod_remove_lookup_table(aggr->lookups);
kfree(aggr->lookups->dev_id);
kfree(aggr->lookups);
kfree(aggr);
}
static ssize_t delete_device_store(struct device_driver *driver,
const char *buf, size_t count)
{
struct gpio_aggregator *aggr;
unsigned int id;
int error;
if (!str_has_prefix(buf, DRV_NAME "."))
return -EINVAL;
error = kstrtouint(buf + strlen(DRV_NAME "."), 10, &id);
if (error)
return error;
if (!try_module_get(THIS_MODULE))
return -ENOENT;
mutex_lock(&gpio_aggregator_lock);
aggr = idr_remove(&gpio_aggregator_idr, id);
mutex_unlock(&gpio_aggregator_lock);
if (!aggr) {
module_put(THIS_MODULE);
return -ENOENT;
}
gpio_aggregator_free(aggr);
module_put(THIS_MODULE);
return count;
}
static DRIVER_ATTR_WO(delete_device);
static struct attribute *gpio_aggregator_attrs[] = {
&driver_attr_new_device.attr,
&driver_attr_delete_device.attr,
NULL
};
ATTRIBUTE_GROUPS(gpio_aggregator);
static int __exit gpio_aggregator_idr_remove(int id, void *p, void *data)
{
gpio_aggregator_free(p);
return 0;
}
static void __exit gpio_aggregator_remove_all(void)
{
mutex_lock(&gpio_aggregator_lock);
idr_for_each(&gpio_aggregator_idr, gpio_aggregator_idr_remove, NULL);
idr_destroy(&gpio_aggregator_idr);
mutex_unlock(&gpio_aggregator_lock);
}
/*
* GPIO Forwarder
@ -583,6 +395,184 @@ static struct gpiochip_fwd *gpiochip_fwd_create(struct device *dev,
}
/*
* Sysfs interface
*/
static int aggr_parse(struct gpio_aggregator *aggr)
{
char *args = skip_spaces(aggr->args);
char *name, *offsets, *p;
unsigned int i, n = 0;
int error = 0;
unsigned long *bitmap __free(bitmap) =
bitmap_alloc(AGGREGATOR_MAX_GPIOS, GFP_KERNEL);
if (!bitmap)
return -ENOMEM;
args = next_arg(args, &name, &p);
while (*args) {
args = next_arg(args, &offsets, &p);
p = get_options(offsets, 0, &error);
if (error == 0 || *p) {
/* Named GPIO line */
error = aggr_add_gpio(aggr, name, U16_MAX, &n);
if (error)
return error;
name = offsets;
continue;
}
/* GPIO chip + offset(s) */
error = bitmap_parselist(offsets, bitmap, AGGREGATOR_MAX_GPIOS);
if (error) {
pr_err("Cannot parse %s: %d\n", offsets, error);
return error;
}
for_each_set_bit(i, bitmap, AGGREGATOR_MAX_GPIOS) {
error = aggr_add_gpio(aggr, name, i, &n);
if (error)
return error;
}
args = next_arg(args, &name, &p);
}
if (!n) {
pr_err("No GPIOs specified\n");
return -EINVAL;
}
return 0;
}
static ssize_t new_device_store(struct device_driver *driver, const char *buf,
size_t count)
{
struct gpio_aggregator *aggr;
struct platform_device *pdev;
int res, id;
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;
goto put_module;
}
memcpy(aggr->args, buf, count + 1);
aggr->lookups = kzalloc(struct_size(aggr->lookups, table, 1),
GFP_KERNEL);
if (!aggr->lookups) {
res = -ENOMEM;
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);
if (!aggr->lookups->dev_id) {
res = -ENOMEM;
goto remove_idr;
}
res = aggr_parse(aggr);
if (res)
goto free_dev_id;
gpiod_add_lookup_table(aggr->lookups);
pdev = platform_device_register_simple(DRV_NAME, id, NULL, 0);
if (IS_ERR(pdev)) {
res = PTR_ERR(pdev);
goto remove_table;
}
aggr->pdev = pdev;
module_put(THIS_MODULE);
return count;
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);
put_module:
module_put(THIS_MODULE);
return res;
}
static DRIVER_ATTR_WO(new_device);
static void gpio_aggregator_free(struct gpio_aggregator *aggr)
{
platform_device_unregister(aggr->pdev);
gpiod_remove_lookup_table(aggr->lookups);
kfree(aggr->lookups->dev_id);
kfree(aggr->lookups);
kfree(aggr);
}
static ssize_t delete_device_store(struct device_driver *driver,
const char *buf, size_t count)
{
struct gpio_aggregator *aggr;
unsigned int id;
int error;
if (!str_has_prefix(buf, DRV_NAME "."))
return -EINVAL;
error = kstrtouint(buf + strlen(DRV_NAME "."), 10, &id);
if (error)
return error;
if (!try_module_get(THIS_MODULE))
return -ENOENT;
mutex_lock(&gpio_aggregator_lock);
aggr = idr_remove(&gpio_aggregator_idr, id);
mutex_unlock(&gpio_aggregator_lock);
if (!aggr) {
module_put(THIS_MODULE);
return -ENOENT;
}
gpio_aggregator_free(aggr);
module_put(THIS_MODULE);
return count;
}
static DRIVER_ATTR_WO(delete_device);
static struct attribute *gpio_aggregator_attrs[] = {
&driver_attr_new_device.attr,
&driver_attr_delete_device.attr,
NULL
};
ATTRIBUTE_GROUPS(gpio_aggregator);
/*
* GPIO Aggregator platform device
*/
@ -640,6 +630,20 @@ static struct platform_driver gpio_aggregator_driver = {
},
};
static int __exit gpio_aggregator_idr_remove(int id, void *p, void *data)
{
gpio_aggregator_free(p);
return 0;
}
static void __exit gpio_aggregator_remove_all(void)
{
mutex_lock(&gpio_aggregator_lock);
idr_for_each(&gpio_aggregator_idr, gpio_aggregator_idr_remove, NULL);
idr_destroy(&gpio_aggregator_idr);
mutex_unlock(&gpio_aggregator_lock);
}
static int __init gpio_aggregator_init(void)
{
return platform_driver_register(&gpio_aggregator_driver);