mirror of
https://github.com/torvalds/linux.git
synced 2026-06-02 03:24:19 +02:00
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:
parent
dad3386b18
commit
7a56efeabf
|
|
@ -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);
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user