From patchwork Mon Feb 3 03:12:05 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Koichiro Den X-Patchwork-Id: 863486 Received: from smtp-relay-internal-0.canonical.com (smtp-relay-internal-0.canonical.com [185.125.188.122]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 3D67874BED for ; Mon, 3 Feb 2025 03:12:38 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=185.125.188.122 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1738552360; cv=none; b=c/hLS/A+i0JpahUFq1RRwMxQ2tkq2mprQn8fOUzp7hvoT6V1SfzjnufEfheMx5NJjnWiS8y3bRRkNNkJ2t7ByZNXnsMeFchZkADgQzhHhsO5NlIQRPk5RB/xG2d4NrGnrdo6IjLjDwMUTROJM1lzThUoOriZoivY0NvFTJF6Pd4= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1738552360; c=relaxed/simple; bh=y0YJLkVr4lVblj2gbRQrUKDMiSqBTtuSw0y0f3bXkyk=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=shINRsoYfyoBVhzHqgv96+HcIj1k64Ch/S5WghoqwVfFbc+HrBMky8aYuPAyb9ZRkg8zTcZ7BwgIOlxYx0VEOj9PlFkripUVqbBiHPT2A9MO+ndSql2i7OcXPRxIbWLpoSFIbKrGoDeYc7A4jRjSj38I1IdGwzx5Av1FcCZBfwg= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=canonical.com; spf=pass smtp.mailfrom=canonical.com; dkim=pass (2048-bit key) header.d=canonical.com header.i=@canonical.com header.b=AfNfLCRI; arc=none smtp.client-ip=185.125.188.122 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=canonical.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=canonical.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=canonical.com header.i=@canonical.com header.b="AfNfLCRI" Received: from mail-pj1-f72.google.com (mail-pj1-f72.google.com [209.85.216.72]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by smtp-relay-internal-0.canonical.com (Postfix) with ESMTPS id 957C43FA50 for ; Mon, 3 Feb 2025 03:12:36 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=canonical.com; s=20210705; t=1738552356; bh=qUPyy33QFnrdvY5sunjgPIPG/eZET6IBKhxsbizwt04=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=AfNfLCRIkGhdoMnoFl+H4r1H++fFdHITd4BJa+ed+5plsiHCsQ5mCyB5FtU53ls1a LC0pngP634bhaDIcFt4syWSg7waSHFJyIyYhRv3xuPW9EEHSWZeoSM9vS+0KvnQyWl qdxqFjPW0/SWZwkjZ4ihNwr/eTFokFJryhbUrSsd8XgfDbCZiUCtdD7IWBCHqdY46h kIrPdBKmvvn70Bo695vzDud94mVHkjC3ADKTAhQyzIMc3+V7VoknFZjoEkBdCErpHn XTr6hjjMYHztEaSZCGSKsEzZ5T595qsPFzK6SfxUsr+k/SUc1mI2sNwb1UXlJbwN47 +VHFM1exnS9EQ== Received: by mail-pj1-f72.google.com with SMTP id 98e67ed59e1d1-2f81a0d0a18so7582050a91.3 for ; Sun, 02 Feb 2025 19:12:36 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1738552355; x=1739157155; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=qUPyy33QFnrdvY5sunjgPIPG/eZET6IBKhxsbizwt04=; b=EbiIGM78WHtC3Qp0JFQVb67B5HN8rQwH70O+ONvijwskiG0eXwZItTbfdztUy7yiYT dhQ3SMuPctP2u3cf2QaBvJkr9UgQ3KUWJvjkBxL/EK8x4bhlfkh4tUbVZaG3+x3ppFbe YkYm69rtEW4QNg+kPT/JYapX+8Y9596WoeF77o4zNeXkk+CvqcJnvHNSiZsFJecqCBhL yrxwPzogCFFGMpWFJALm/nXPqhq1uCxu/UjaPc3oJYjrWDlX4DweaB80iCxjY6qKw8S5 lZsvxT2DDwIy4TJYRRQTzYLY3RkkO07GtPksAbNpMYowqAEZ5EIxTaTImWhdCz3h8hvt Td2Q== X-Gm-Message-State: AOJu0YzpFNil/qqtXQk2uts+0cXS9KmI5xqXG3uPxtsvkvmCnAdZ7sPE GJo0qk6Gg0qoeKJUbmHrTMRnXiVHnV7ueesl8p1x6w+dUUvJbUVg07lWZ8fYFJK7yUCrNi6GbSv 1slStyv+ulDS9wSJMHaOL24dYgXgJapvSgo+BVUjI6/0C9WS28+Gu0dAefBi+YzI6YiR20aR3OX sTTEZiVT4= X-Gm-Gg: ASbGncuijbe46eDZaEbwF3xgOagssx+saiZYYWB+LJvDiRqRORFK27kuxh+dPoZ0gAh PGB3B5fCjGmCMo012YpgtA/40ztrW6P6bO80wd6CGP+nPuATMno8iLVb0KykDDSWpeNfsx6q1un CWJvgJ8Ja0BnVh8WAghmDAIq6KVdtLGypu/T36XL6OepJV/5OYro+08Ysh5UPZbQIqrHfzfSypB oMPXkBecimOqydaw9ajou38wmGcbz0H2srFGY+35sU+oHvsRkToezR3gFVmxEy4xN4EPJ1Str8n X0GY X-Received: by 2002:a17:90b:2b86:b0:2ea:aa56:499 with SMTP id 98e67ed59e1d1-2f83abb3548mr28072777a91.1.1738552354889; Sun, 02 Feb 2025 19:12:34 -0800 (PST) X-Google-Smtp-Source: AGHT+IG3pcG4hSigJFHaXRsDFTRJ6jhVQnd3BgFFQCwgFd5IgOQFhGQLmWOHFqimErndki3gBBYNTw== X-Received: by 2002:a17:90b:2b86:b0:2ea:aa56:499 with SMTP id 98e67ed59e1d1-2f83abb3548mr28072747a91.1.1738552354219; Sun, 02 Feb 2025 19:12:34 -0800 (PST) Received: from z790sl.. ([240f:74:7be:1:33e1:5e62:5b35:92b]) by smtp.gmail.com with ESMTPSA id d9443c01a7336-21de3300253sm65809075ad.162.2025.02.02.19.12.31 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sun, 02 Feb 2025 19:12:33 -0800 (PST) From: Koichiro Den To: linux-gpio@vger.kernel.org Cc: brgl@bgdev.pl, geert+renesas@glider.be, linus.walleij@linaro.org, maciej.borzecki@canonical.com, linux-kernel@vger.kernel.org Subject: [PATCH v2 02/10] gpio: aggregator: introduce basic configfs interface Date: Mon, 3 Feb 2025 12:12:05 +0900 Message-ID: <20250203031213.399914-3-koichiro.den@canonical.com> X-Mailer: git-send-email 2.45.2 In-Reply-To: <20250203031213.399914-1-koichiro.den@canonical.com> References: <20250203031213.399914-1-koichiro.den@canonical.com> Precedence: bulk X-Mailing-List: linux-gpio@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 The existing sysfs 'new_device' interface has several limitations: * No way to determine when GPIO aggregator creation is complete. * No way to retrieve errors when creating a GPIO aggregator. * No way to trace a GPIO line of an aggregator back to its corresponding physical device. * The 'new_device' echo does not indicate which virtual gpiochip was created. * No way to assign names to GPIO lines exported through an aggregator. Introduce the new configfs interface for gpio-aggregator to address these limitations. It provides a more streamlined, modern, and extensible configuration method. For backward compatibility, the 'new_device' interface and its behaviour is retained for now. This commit implements minimal functionalities: /config/gpio-aggregator// /config/gpio-aggregator//live /config/gpio-aggregator/// /config/gpio-aggregator///key /config/gpio-aggregator///offset Basic setup flow is: 1. Create a directory for a GPIO aggregator. 2. Create subdirectories for each line you want to instantiate. 3. In each line directory, configure the key and offset. The key/offset semantics are as follows: * If offset is >= 0: - key specifies the name of the chip this GPIO belongs to - offset specifies the line offset within that chip. * If offset is <0: - key needs to specify the GPIO line name. 4. Return to the aggregator's root directory and write '1' to the live attribute. For example, the command in the existing kernel doc: echo 'e6052000.gpio 19 e6050000.gpio 20-21' > new_device is equivalent to: mkdir /sys/kernel/config/gpio-aggregator/ # Change to name of your choice (e.g. "aggr0") cd /sys/kernel/config/gpio-aggregator/ mkdir line0 line1 line2 # Only "line" naming allowed. echo e6052000.gpio > line0/key echo 19 > line0/offset echo e6050000.gpio > line1/key echo 20 > line1/offset echo e6050000.gpio > line2/key echo 21 > line2/offset echo 1 > live Signed-off-by: Koichiro Den --- drivers/gpio/gpio-aggregator.c | 549 ++++++++++++++++++++++++++++++++- 1 file changed, 548 insertions(+), 1 deletion(-) diff --git a/drivers/gpio/gpio-aggregator.c b/drivers/gpio/gpio-aggregator.c index 570cd1ff8cc2..c63cf3067ce7 100644 --- a/drivers/gpio/gpio-aggregator.c +++ b/drivers/gpio/gpio-aggregator.c @@ -9,10 +9,14 @@ #include #include +#include +#include #include #include #include #include +#include +#include #include #include #include @@ -34,11 +38,39 @@ */ struct gpio_aggregator { + struct config_group group; struct gpiod_lookup_table *lookups; struct platform_device *pdev; + struct mutex lock; + int id; + + /* Synchronize with probe */ + struct notifier_block bus_notifier; + struct completion probe_completion; + bool driver_bound; + + /* List of gpio_aggregator_line. Always added in order */ + struct list_head list_head; + char args[]; }; +struct gpio_aggregator_line { + struct config_group group; + struct gpio_aggregator *parent; + struct list_head entry; + + /* Line index within the aggregator device */ + int idx; + + /* GPIO chip label or line name */ + char *key; + /* Can be negative to indicate lookup by line name */ + int offset; + + enum gpio_lookup_flags flags; +}; + static DEFINE_MUTEX(gpio_aggregator_lock); /* protects idr */ static DEFINE_IDR(gpio_aggregator_idr); @@ -61,6 +93,97 @@ static int aggr_add_gpio(struct gpio_aggregator *aggr, const char *key, return 0; } +static int aggr_notifier_call(struct notifier_block *nb, unsigned long action, + void *data) +{ + struct gpio_aggregator *aggr; + struct device *dev = data; + + aggr = container_of(nb, struct gpio_aggregator, bus_notifier); + if (!device_match_name(dev, aggr->lookups->dev_id)) + return NOTIFY_DONE; + + switch (action) { + case BUS_NOTIFY_BOUND_DRIVER: + aggr->driver_bound = true; + break; + case BUS_NOTIFY_DRIVER_NOT_BOUND: + aggr->driver_bound = false; + break; + default: + return NOTIFY_DONE; + } + + complete(&aggr->probe_completion); + return NOTIFY_OK; +} + +static bool aggr_is_active(struct gpio_aggregator *aggr) +{ + lockdep_assert_held(&aggr->lock); + + return !!aggr->pdev && platform_get_drvdata(aggr->pdev); +} + +static size_t aggr_count_lines(struct gpio_aggregator *aggr) +{ + lockdep_assert_held(&aggr->lock); + + return list_count_nodes(&aggr->list_head); +} + +static struct gpio_aggregator_line *aggr_line_alloc( + struct gpio_aggregator *parent, int idx, char *key, int offset) +{ + struct gpio_aggregator_line *line; + + line = kzalloc(sizeof(*line), GFP_KERNEL); + if (!line) + return ERR_PTR(-ENOMEM); + + if (key) { + line->key = kstrdup(key, GFP_KERNEL); + if (!line->key) { + kfree(line); + return ERR_PTR(-ENOMEM); + } + } + + line->flags = GPIO_LOOKUP_FLAGS_DEFAULT; + line->parent = parent; + line->idx = idx; + line->offset = offset; + INIT_LIST_HEAD(&line->entry); + + return line; +} + +static void aggr_line_add(struct gpio_aggregator *aggr, + struct gpio_aggregator_line *line) +{ + struct gpio_aggregator_line *tmp; + + lockdep_assert_held(&aggr->lock); + + list_for_each_entry(tmp, &aggr->list_head, entry) { + if (WARN_ON(tmp->idx == line->idx)) + return; + if (tmp->idx > line->idx) { + list_add_tail(&line->entry, &tmp->entry); + return; + } + } + list_add_tail(&line->entry, &aggr->list_head); +} + +static void aggr_line_del(struct gpio_aggregator *aggr, + struct gpio_aggregator_line *line) +{ + lockdep_assert_held(&aggr->lock); + + list_del(&line->entry); +} + /* * GPIO Forwarder @@ -385,6 +508,411 @@ static struct gpiochip_fwd *gpiochip_fwd_create(struct device *dev, } +/* + * Configfs interface + */ + +static struct gpio_aggregator * +to_gpio_aggregator(struct config_item *item) +{ + struct config_group *group = to_config_group(item); + + return container_of(group, struct gpio_aggregator, group); +} + +static struct gpio_aggregator_line * +to_gpio_aggregator_line(struct config_item *item) +{ + struct config_group *group = to_config_group(item); + + return container_of(group, struct gpio_aggregator_line, group); +} + +static int aggr_activate(struct gpio_aggregator *aggr) +{ + struct platform_device_info pdevinfo; + struct gpio_aggregator_line *line; + struct platform_device *pdev; + unsigned int n = 0; + int ret = 0; + + if (aggr_count_lines(aggr) == 0) + return -EINVAL; + + aggr->lookups = kzalloc(struct_size(aggr->lookups, table, 1), + GFP_KERNEL); + if (!aggr->lookups) + return -ENOMEM; + + memset(&pdevinfo, 0, sizeof(pdevinfo)); + pdevinfo.name = DRV_NAME; + pdevinfo.id = aggr->id; + + /* The list is always sorted as new elements are inserted in order. */ + list_for_each_entry(line, &aggr->list_head, entry) { + /* + * - Either GPIO chip label or line name must be configured + * (i.e. line->key must be non-NULL) + * - Line directories must be named with sequential numeric + * suffixes starting from 0. (i.e. ./line0, ./line1, ...) + */ + if (!line->key || line->idx != n) { + ret = -EINVAL; + goto err_remove_lookups; + } + + if (line->offset < 0) + ret = aggr_add_gpio(aggr, line->key, U16_MAX, &n); + else + ret = aggr_add_gpio(aggr, line->key, line->offset, &n); + if (ret) + goto err_remove_lookups; + } + + aggr->lookups->dev_id = kasprintf(GFP_KERNEL, "%s.%d", DRV_NAME, aggr->id); + if (!aggr->lookups->dev_id) { + ret = -ENOMEM; + goto err_remove_lookups; + } + + gpiod_add_lookup_table(aggr->lookups); + + reinit_completion(&aggr->probe_completion); + aggr->driver_bound = false; + aggr->bus_notifier.notifier_call = aggr_notifier_call; + bus_register_notifier(&platform_bus_type, &aggr->bus_notifier); + + pdev = platform_device_register_full(&pdevinfo); + if (IS_ERR(pdev)) { + ret = PTR_ERR(pdev); + bus_unregister_notifier(&platform_bus_type, &aggr->bus_notifier); + goto err_remove_lookup_table; + } + + wait_for_completion(&aggr->probe_completion); + bus_unregister_notifier(&platform_bus_type, &aggr->bus_notifier); + + if (!aggr->driver_bound) { + ret = -ENXIO; + goto err_unregister_pdev; + } + + aggr->pdev = pdev; + return 0; + +err_unregister_pdev: + platform_device_unregister(pdev); +err_remove_lookup_table: + kfree(aggr->lookups->dev_id); + gpiod_remove_lookup_table(aggr->lookups); +err_remove_lookups: + kfree(aggr->lookups); + + return ret; +} + +static void aggr_deactivate(struct gpio_aggregator *aggr) +{ + platform_device_unregister(aggr->pdev); + gpiod_remove_lookup_table(aggr->lookups); + kfree(aggr->lookups->dev_id); + kfree(aggr->lookups); + aggr->pdev = NULL; +} + +static void aggr_lockup_configfs(struct gpio_aggregator *aggr, bool lock) +{ + struct configfs_subsystem *subsys = aggr->group.cg_subsys; + struct gpio_aggregator_line *line; + + /* + * The device only needs to depend on leaf lines. This is + * sufficient to lock up all the configfs entries that the + * instantiated, alive device depends on. + */ + list_for_each_entry(line, &aggr->list_head, entry) { + if (lock) + WARN_ON(configfs_depend_item_unlocked( + subsys, &line->group.cg_item)); + else + configfs_undepend_item_unlocked( + &line->group.cg_item); + } +} + +static ssize_t +gpio_aggr_line_key_show(struct config_item *item, char *page) +{ + struct gpio_aggregator_line *line = to_gpio_aggregator_line(item); + struct gpio_aggregator *aggr = line->parent; + + guard(mutex)(&aggr->lock); + + return sprintf(page, "%s\n", line->key ?: ""); +} + +static ssize_t +gpio_aggr_line_key_store(struct config_item *item, const char *page, + size_t count) +{ + struct gpio_aggregator_line *line = to_gpio_aggregator_line(item); + struct gpio_aggregator *aggr = line->parent; + + char *key __free(kfree) = kstrndup(skip_spaces(page), count, + GFP_KERNEL); + if (!key) + return -ENOMEM; + + strim(key); + + guard(mutex)(&aggr->lock); + + if (aggr_is_active(aggr)) + return -EBUSY; + + kfree(line->key); + line->key = no_free_ptr(key); + + return count; +} + +CONFIGFS_ATTR(gpio_aggr_line_, key); + +static ssize_t +gpio_aggr_line_offset_show(struct config_item *item, char *page) +{ + struct gpio_aggregator_line *line = to_gpio_aggregator_line(item); + struct gpio_aggregator *aggr = line->parent; + unsigned int offset; + + scoped_guard(mutex, &aggr->lock) + offset = line->offset; + + return sprintf(page, "%d\n", offset); +} + +static ssize_t +gpio_aggr_line_offset_store(struct config_item *item, const char *page, + size_t count) +{ + struct gpio_aggregator_line *line = to_gpio_aggregator_line(item); + struct gpio_aggregator *aggr = line->parent; + int offset, ret; + + ret = kstrtoint(page, 0, &offset); + if (ret) + return ret; + + /* + * Negative number here means: 'key' represents a line name to lookup. + * Non-negative means: 'key' represents the label of the chip with + * the 'offset' value representing the line within that chip. + * + * GPIOLIB uses the U16_MAX value to indicate lookup by line name so + * the greatest offset we can accept is (U16_MAX - 1). + */ + if (offset > (U16_MAX - 1)) + return -EINVAL; + + guard(mutex)(&aggr->lock); + + if (aggr_is_active(aggr)) + return -EBUSY; + + line->offset = offset; + + return count; +} + +CONFIGFS_ATTR(gpio_aggr_line_, offset); + +static struct configfs_attribute *gpio_aggr_line_attrs[] = { + &gpio_aggr_line_attr_key, + &gpio_aggr_line_attr_offset, + NULL +}; + +static ssize_t +gpio_aggr_device_live_show(struct config_item *item, char *page) +{ + struct gpio_aggregator *aggr = to_gpio_aggregator(item); + bool active; + + scoped_guard(mutex, &aggr->lock) + active = aggr_is_active(aggr); + + return sprintf(page, "%c\n", active ? '1' : '0'); +} + +static ssize_t +gpio_aggr_device_live_store(struct config_item *item, const char *page, + size_t count) +{ + struct gpio_aggregator *aggr = to_gpio_aggregator(item); + int ret = 0; + bool live; + + ret = kstrtobool(page, &live); + if (ret) + return ret; + + if (live) + aggr_lockup_configfs(aggr, true); + + scoped_guard(mutex, &aggr->lock) { + if (live == aggr_is_active(aggr)) + ret = -EPERM; + else if (live) + ret = aggr_activate(aggr); + else + aggr_deactivate(aggr); + } + + /* + * Undepend is required only if device disablement (live == 0) + * succeeds or if device enablement (live == 1) fails. + */ + if (live == !!ret) + aggr_lockup_configfs(aggr, false); + + return ret ?: count; +} + +CONFIGFS_ATTR(gpio_aggr_device_, live); + +static struct configfs_attribute *gpio_aggr_device_attrs[] = { + &gpio_aggr_device_attr_live, + NULL +}; + +static void +gpio_aggr_line_release(struct config_item *item) +{ + struct gpio_aggregator_line *line = to_gpio_aggregator_line(item); + struct gpio_aggregator *aggr = line->parent; + + guard(mutex)(&aggr->lock); + + aggr_line_del(aggr, line); + kfree(line->key); + kfree(line); +} + +static struct configfs_item_operations gpio_aggr_line_item_ops = { + .release = gpio_aggr_line_release, +}; + +static const struct config_item_type gpio_aggr_line_type = { + .ct_item_ops = &gpio_aggr_line_item_ops, + .ct_attrs = gpio_aggr_line_attrs, + .ct_owner = THIS_MODULE, +}; + +static void gpio_aggr_device_release(struct config_item *item) +{ + struct gpio_aggregator *aggr = to_gpio_aggregator(item); + + guard(mutex)(&aggr->lock); + + if (aggr_is_active(aggr)) + aggr_deactivate(aggr); + + mutex_destroy(&aggr->lock); + idr_remove(&gpio_aggregator_idr, aggr->id); + kfree(aggr); +} + +static struct configfs_item_operations gpio_aggr_device_item_ops = { + .release = gpio_aggr_device_release, +}; + +static struct config_group * +gpio_aggr_device_make_group(struct config_group *group, const char *name) +{ + struct gpio_aggregator *aggr = to_gpio_aggregator(&group->cg_item); + struct gpio_aggregator_line *line; + unsigned int idx; + int ret, nchar; + + ret = sscanf(name, "line%u%n", &idx, &nchar); + if (ret != 1 || nchar != strlen(name)) + return ERR_PTR(-EINVAL); + + guard(mutex)(&aggr->lock); + + if (aggr_is_active(aggr)) + return ERR_PTR(-EBUSY); + + list_for_each_entry(line, &aggr->list_head, entry) + if (line->idx == idx) + return ERR_PTR(-EINVAL); + + line = aggr_line_alloc(aggr, idx, NULL, -1); + if (!line) + return ERR_PTR(-ENOMEM); + + config_group_init_type_name(&line->group, name, &gpio_aggr_line_type); + + aggr_line_add(aggr, line); + + return &line->group; +} + +static struct configfs_group_operations gpio_aggr_device_group_ops = { + .make_group = gpio_aggr_device_make_group, +}; + +static const struct config_item_type gpio_aggr_device_type = { + .ct_group_ops = &gpio_aggr_device_group_ops, + .ct_item_ops = &gpio_aggr_device_item_ops, + .ct_attrs = gpio_aggr_device_attrs, + .ct_owner = THIS_MODULE, +}; + +static struct config_group * +gpio_aggr_make_group(struct config_group *group, const char *name) +{ + /* arg space is unneeded */ + struct gpio_aggregator *aggr = kzalloc(sizeof(*aggr), GFP_KERNEL); + if (!aggr) + return ERR_PTR(-ENOMEM); + + mutex_lock(&gpio_aggregator_lock); + aggr->id = idr_alloc(&gpio_aggregator_idr, aggr, 0, 0, GFP_KERNEL); + mutex_unlock(&gpio_aggregator_lock); + + if (aggr->id < 0) { + kfree(aggr); + return ERR_PTR(aggr->id); + } + + INIT_LIST_HEAD(&aggr->list_head); + mutex_init(&aggr->lock); + config_group_init_type_name(&aggr->group, name, &gpio_aggr_device_type); + init_completion(&aggr->probe_completion); + + return &aggr->group; +} + +static struct configfs_group_operations gpio_aggr_group_ops = { + .make_group = gpio_aggr_make_group, +}; + +static const struct config_item_type gpio_aggr_type = { + .ct_group_ops = &gpio_aggr_group_ops, + .ct_owner = THIS_MODULE, +}; + +static struct configfs_subsystem gpio_aggr_subsys = { + .su_group = { + .cg_item = { + .ci_namebuf = DRV_NAME, + .ci_type = &gpio_aggr_type, + }, + }, +}; + + /* * Sysfs interface */ @@ -622,12 +1150,31 @@ static void __exit gpio_aggregator_remove_all(void) static int __init gpio_aggregator_init(void) { - return platform_driver_register(&gpio_aggregator_driver); + int ret = 0; + + ret = platform_driver_register(&gpio_aggregator_driver); + if (ret) { + pr_err("Failed to register the platform driver: %d\n", ret); + return ret; + } + + config_group_init(&gpio_aggr_subsys.su_group); + mutex_init(&gpio_aggr_subsys.su_mutex); + ret = configfs_register_subsystem(&gpio_aggr_subsys); + if (ret) { + pr_err("Failed to register the '%s' configfs subsystem: %d\n", + gpio_aggr_subsys.su_group.cg_item.ci_namebuf, ret); + mutex_destroy(&gpio_aggr_subsys.su_mutex); + platform_driver_unregister(&gpio_aggregator_driver); + } + + return ret; } module_init(gpio_aggregator_init); static void __exit gpio_aggregator_exit(void) { + configfs_unregister_subsystem(&gpio_aggr_subsys); gpio_aggregator_remove_all(); platform_driver_unregister(&gpio_aggregator_driver); } From patchwork Mon Feb 3 03:12:07 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Koichiro Den X-Patchwork-Id: 863485 Received: from smtp-relay-internal-1.canonical.com (smtp-relay-internal-1.canonical.com [185.125.188.123]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id BF02413B787 for ; Mon, 3 Feb 2025 03:12:43 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=185.125.188.123 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1738552365; cv=none; b=r9b0v825KcN1tI5CPKq2g1qbhn5wtMvE552lZWDzYSSDeP+l2QiYxLZz3IZ7EJiRFmVfJK8rFY1GGWHPEvGQsOJA6YkyoSmj3CDSiDJcx1wtc7loY42H/jPzOKmgiz6rT7uNsKuMQ7GX95irDIW6PdVsCrSUfgzekEWJya+shfI= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1738552365; c=relaxed/simple; bh=D5T5KJKLkNqZuunpZaQz66egOgmq3gUBykVLiVCskVA=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=Y3I6LNiK/Bapt6rzMoQ6fHzlaOAZxC67Ng0vUU0/XtuqavwT7ZAwb5xM3qS/yQKYTn5MZkyxlntI0L3fl5oRgXNL+Hyd2iLLxtQl0XQNRtpxuFD/J0prfXAokxheGjcCWlN4Yu1sx2nUqYgd/HYf1anED+JXWmlU9xxmGbwNT0E= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=canonical.com; spf=pass smtp.mailfrom=canonical.com; dkim=pass (2048-bit key) header.d=canonical.com header.i=@canonical.com header.b=YMOmdPZx; arc=none smtp.client-ip=185.125.188.123 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=canonical.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=canonical.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=canonical.com header.i=@canonical.com header.b="YMOmdPZx" Received: from mail-pl1-f199.google.com (mail-pl1-f199.google.com [209.85.214.199]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by smtp-relay-internal-1.canonical.com (Postfix) with ESMTPS id D5BC33F296 for ; Mon, 3 Feb 2025 03:12:41 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=canonical.com; s=20210705; t=1738552361; bh=CmjoqfiwFmGpVKgL8na+qeTrK73yJ3NuCGJzYY0C8p0=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=YMOmdPZx5KBFEKDyXoudCMJ2AIM8SAyyTfLHeocMwTtC3daFlUzCAkL9KUGl/ejsA kmYQ1WINeCH0M03j639LahZGdrWOKGG7o79usD7B3uXmRLV0RFPnC9ALeQDXgcEUXp OF9/przXHgb4Kb9Bp7s6x6fJIyrRtpb4ZFC3B/orOWYxac1KZqS4xSL66RiuZqR9/q Trw5LOZU9Rhq2vPEf/TJcJj99PnlC+d2fIQCrOoV/BVIwTCp/pEwt+PAPKpHY1uIj7 jXjXlDeBdBPy9LysVcoHSDU3COtmN9ufXRi/hKEu2tcpC+o8aTnU53f2udnUpj7FqV te+6g5uO4jD5g== Received: by mail-pl1-f199.google.com with SMTP id d9443c01a7336-21648ddd461so83226885ad.0 for ; Sun, 02 Feb 2025 19:12:41 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1738552360; x=1739157160; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=CmjoqfiwFmGpVKgL8na+qeTrK73yJ3NuCGJzYY0C8p0=; b=FUGvGjfb6TrYL4p8JyP0p7G2CYEKBjDFBvxEL7s68T/JF7+ctaO/8t+dwsPXFJfaS2 Esvto2v4fN3/dZ17ys8evGIrfKXWfp2HOM6UA9anV/cnNVuTmX4GuoU5a4waRBulHMhi rg6m5Y2fekyVjAbiD1Oy2EOUYfHljc/kToF7mWn/4au4Od0mpt/4lRnWPjbbYy5KpK8x 42e2cUKde5aq1g1+pHjN1b92O2rYcrVg6f1k3CfHKpeG9VL/vDDpKMOdfWAaJCtagZzf zliBXMndkl7hVgjBTujd/SkT+D3vRB4FWX8ESX1vXENzfDK4KSSJBi8SCblqmVoj7ctb VDcg== X-Gm-Message-State: AOJu0YwMaXeY31lrvMhZg6R6OAtNjRlruiLXyuv/2syKtAUD+Rsf4m/H e6N+jzyFF9fPRWttJ7GxQtRIkpSNf3ZpPkRpNUbUJQQLWFd2u54KKlAS3F+IKmZjPyR6F460vvt /x9o2O2Ke/RLNIwCHHW8oaFwScF85cJvaEqlpDNSToNj/jUU2RmiMTW4twMPRtqWI8b/5/5SAjz BoSjqtExw= X-Gm-Gg: ASbGncsjy8zqi4xV1B/dZ7z7BiBCVSVrL2diBzk+TQArARc4RLQAH3RYEtafGEILnQR vog9S7D0eaSqRGAgQieWrvdoYCQ+lCpj2xFJaMIO/77ghJEZHLRP01z12Eqnosmcfc2IaV5Ti6C Zn8SegogCXsLeQ70sZ/rhSdwxdBhxUeBETzcs1v19RD6ZLq6Vbi3QHjrQ7Emod6/V14ZWupjDmB mpBjm/hyWdCQIHnu/mpzw1GO9P1DY5iwEcnbP9In2tTeRfwaavT4hUnaE+ykGuSnDCEb3qZuHns cSh0 X-Received: by 2002:a17:903:32c4:b0:216:1543:195e with SMTP id d9443c01a7336-21dd7c46c41mr327607085ad.5.1738552360008; Sun, 02 Feb 2025 19:12:40 -0800 (PST) X-Google-Smtp-Source: AGHT+IHp+COZgI0atxnqhzoQqDdxpFJFFAFhiXjT571bA8VSq+NYsAvBWHh/9zdb8p4Q4G2jzbXzBA== X-Received: by 2002:a17:903:32c4:b0:216:1543:195e with SMTP id d9443c01a7336-21dd7c46c41mr327606845ad.5.1738552359688; Sun, 02 Feb 2025 19:12:39 -0800 (PST) Received: from z790sl.. ([240f:74:7be:1:33e1:5e62:5b35:92b]) by smtp.gmail.com with ESMTPSA id d9443c01a7336-21de3300253sm65809075ad.162.2025.02.02.19.12.37 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sun, 02 Feb 2025 19:12:39 -0800 (PST) From: Koichiro Den To: linux-gpio@vger.kernel.org Cc: brgl@bgdev.pl, geert+renesas@glider.be, linus.walleij@linaro.org, maciej.borzecki@canonical.com, linux-kernel@vger.kernel.org Subject: [PATCH v2 04/10] gpio: aggregator: add read-write 'name' attribute Date: Mon, 3 Feb 2025 12:12:07 +0900 Message-ID: <20250203031213.399914-5-koichiro.den@canonical.com> X-Mailer: git-send-email 2.45.2 In-Reply-To: <20250203031213.399914-1-koichiro.den@canonical.com> References: <20250203031213.399914-1-koichiro.den@canonical.com> Precedence: bulk X-Mailing-List: linux-gpio@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Previously, there is no way to assign names to GPIO lines exported through an aggregator. Allow users to set custom line names via a 'name' attribute. Signed-off-by: Koichiro Den --- drivers/gpio/gpio-aggregator.c | 42 ++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/drivers/gpio/gpio-aggregator.c b/drivers/gpio/gpio-aggregator.c index 76d3a8677308..3263d99bfe69 100644 --- a/drivers/gpio/gpio-aggregator.c +++ b/drivers/gpio/gpio-aggregator.c @@ -63,6 +63,8 @@ struct gpio_aggregator_line { /* Line index within the aggregator device */ int idx; + /* Custom name for the virtual line */ + char *name; /* GPIO chip label or line name */ char *key; /* Can be negative to indicate lookup by line name */ @@ -678,6 +680,44 @@ gpio_aggr_line_key_store(struct config_item *item, const char *page, CONFIGFS_ATTR(gpio_aggr_line_, key); +static ssize_t +gpio_aggr_line_name_show(struct config_item *item, char *page) +{ + struct gpio_aggregator_line *line = to_gpio_aggregator_line(item); + struct gpio_aggregator *aggr = line->parent; + + guard(mutex)(&aggr->lock); + + return sprintf(page, "%s\n", line->name ?: ""); +} + +static ssize_t +gpio_aggr_line_name_store(struct config_item *item, const char *page, + size_t count) +{ + struct gpio_aggregator_line *line = to_gpio_aggregator_line(item); + struct gpio_aggregator *aggr = line->parent; + + char *name __free(kfree) = kstrndup(skip_spaces(page), count, + GFP_KERNEL); + if (!name) + return -ENOMEM; + + strim(name); + + guard(mutex)(&aggr->lock); + + if (aggr_is_active(aggr)) + return -EBUSY; + + kfree(line->name); + line->name = no_free_ptr(name); + + return count; +} + +CONFIGFS_ATTR(gpio_aggr_line_, name); + static ssize_t gpio_aggr_line_offset_show(struct config_item *item, char *page) { @@ -728,6 +768,7 @@ CONFIGFS_ATTR(gpio_aggr_line_, offset); static struct configfs_attribute *gpio_aggr_line_attrs[] = { &gpio_aggr_line_attr_key, + &gpio_aggr_line_attr_name, &gpio_aggr_line_attr_offset, NULL }; @@ -813,6 +854,7 @@ gpio_aggr_line_release(struct config_item *item) aggr_line_del(aggr, line); kfree(line->key); + kfree(line->name); kfree(line); } From patchwork Mon Feb 3 03:12:09 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Koichiro Den X-Patchwork-Id: 863484 Received: from smtp-relay-internal-0.canonical.com (smtp-relay-internal-0.canonical.com [185.125.188.122]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 1A5BB19938D for ; Mon, 3 Feb 2025 03:12:48 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=185.125.188.122 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1738552370; cv=none; b=eYd/K4ac065yzcNl5V4kJfHDig/T9Zo7SVNO4i0l4ul8G7vQHD/QOjG5U0z7POfQ2t7LGqgSBx5ZAPSlSHnET4yJsHrynKDCQgBLmr8U42YDL7JT27ebEfV/YJ8L3g94JCndSwk72zX+ZnjTDaeJ/rpsa+cERDOhHvOyQL8JHMc= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1738552370; c=relaxed/simple; bh=xUaAXI8fxS5jnD6rs8+ieKbRO/Ilyx8EwwFvd0xi7HQ=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=PFw3FboXPcn2LcI5tfJJZIOxtIb7Ch6MXDtb0lBNdx/SZed/v9oMWpWQv2cqpuwaodyjOX9a2wxAOZbkO0qX85cpDwBisjS2XFyn7gs1Xzn5hIfiodHFBW8A/1MIk1xOHziucGGhsSCq94gIJCDHQD5zkCVG8XnSJXI29oCUuNM= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=canonical.com; spf=pass smtp.mailfrom=canonical.com; dkim=pass (2048-bit key) header.d=canonical.com header.i=@canonical.com header.b=FTwHTZBu; arc=none smtp.client-ip=185.125.188.122 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=canonical.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=canonical.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=canonical.com header.i=@canonical.com header.b="FTwHTZBu" Received: from mail-pl1-f199.google.com (mail-pl1-f199.google.com [209.85.214.199]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by smtp-relay-internal-0.canonical.com (Postfix) with ESMTPS id C8A5D3FA55 for ; Mon, 3 Feb 2025 03:12:46 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=canonical.com; s=20210705; t=1738552366; bh=LIuVEkc8rnRPhn+h/+NDwPhAevSLWZ5xYAHN11UW6Cw=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=FTwHTZBuhp0Me9o+b17Fn+pE86cJ62H5v5TNAen6uIhTWs2TLsjXa0sPQNuib+nPN jljtvNU2DI7EloyeYws7cAup/A5IXBILQzFKHm9l8Q/VDxZU1oeEwfDnqQxWHXgHLL cYnPkMONeGC0OAvoqYWI7tSDAYyinEistnjLz3aqwgDs/Uer6I12UgmExI48x8X9or PN/GQVRNuZo1jCu/jxk4ztQlw594KmC+LobgVSb1BQ2XOHaBfKMANX9dI7LF5Bxoyh kwNXQn/i8ktmPa4vsGDOPaPsQ6qWNHkC0YxejFkkES4WyguCysB29Gzc1AzYv/S/v5 Df6BHELd51J1w== Received: by mail-pl1-f199.google.com with SMTP id d9443c01a7336-216717543b7so32354395ad.0 for ; Sun, 02 Feb 2025 19:12:46 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1738552365; x=1739157165; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=LIuVEkc8rnRPhn+h/+NDwPhAevSLWZ5xYAHN11UW6Cw=; b=eM+Z8lY8Rn+SIXbcK1ukCr4ixO2JegtM8lRaKNNq/IfLv9M4NJU7leYLFGZW9mCZTi m4UOlESoFE3+ttKVkQKQZWq0VPCuUEKciARN2l5oElrH2JE8LNM+9fQlP0D1lprQH77b FYRGVkTlYvkYE+vBynyGY1vRkgWCQauT+TVj2xJYzio0oVlp6Z+KipYYPixRxfMvUDuv ltZOf3flNNBAc7JCcfI0YqiYt1oZfc2mlz2wWR3qrdnzlcUZ+f8BNl7+rtIYgxUd8RNO Tejj/UFjzhVx1Clp2N4dXeOAahHiurVuBn/NMKUOA95BuNB9Z2Qry1QKkYDOGoYEBGs7 lt5A== X-Gm-Message-State: AOJu0YyHH45t06bNbkcOZkNlq56ubuvvVrcObJ3GcfCwnxIhm0mqicrd WciGhQA9SV7+s37am0lh8ThmrcLgFC2PZ90t3zEd7czpW/cKgbgyvj/AScz0oidkizU7nKRqyAj sP2Euj5FxE44SYXAnNd1LEjtoHgbjDW1Of50mTienANycvpYWf/GxxYAZ7fih3QA5uMqaUervhf uRLQcQDXI= X-Gm-Gg: ASbGncuWpHo0iftQjbdf/07hIvt65fmPz7FcZ7Aso5N+bTB2EPP5I5ajDBPJru5HPpu gem1dCVoIzw8XKG4YIV8vqES60OwkFmMf8HRbmJIkkeH9+32xgn8wMvO4YdWzZ7o3o1E7dT63q4 21rn+GCTnfeTkUKq4fsulifgj+9Dj5hyyX3nElMoVWq5NUoQi0WMYN+dnlS61zZbeHkLmDJFk4E zVljxFSfBExk2Sm3mwYMZIJ3R6kHxNmajUMT12GIWdPZFlWgkkQH8XGE4ed0DHnLfG15PqBLqQx XGeG X-Received: by 2002:a17:902:d504:b0:216:4e9f:4ec9 with SMTP id d9443c01a7336-21dd7dcb178mr370336815ad.38.1738552365212; Sun, 02 Feb 2025 19:12:45 -0800 (PST) X-Google-Smtp-Source: AGHT+IGJZzJYjztg3YXA5nCzi8TiQrALpMwbavZ1V1gbQ1oxOD5vRmSN40RhAZTUtR00mhvxtHxEpw== X-Received: by 2002:a17:902:d504:b0:216:4e9f:4ec9 with SMTP id d9443c01a7336-21dd7dcb178mr370336465ad.38.1738552364906; Sun, 02 Feb 2025 19:12:44 -0800 (PST) Received: from z790sl.. ([240f:74:7be:1:33e1:5e62:5b35:92b]) by smtp.gmail.com with ESMTPSA id d9443c01a7336-21de3300253sm65809075ad.162.2025.02.02.19.12.42 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sun, 02 Feb 2025 19:12:44 -0800 (PST) From: Koichiro Den To: linux-gpio@vger.kernel.org Cc: brgl@bgdev.pl, geert+renesas@glider.be, linus.walleij@linaro.org, maciej.borzecki@canonical.com, linux-kernel@vger.kernel.org Subject: [PATCH v2 06/10] gpio: aggregator: rename 'name' to 'key' in aggr_parse() Date: Mon, 3 Feb 2025 12:12:09 +0900 Message-ID: <20250203031213.399914-7-koichiro.den@canonical.com> X-Mailer: git-send-email 2.45.2 In-Reply-To: <20250203031213.399914-1-koichiro.den@canonical.com> References: <20250203031213.399914-1-koichiro.den@canonical.com> Precedence: bulk X-Mailing-List: linux-gpio@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Rename the local variable 'name' in aggr_parse() to 'key' because struct gpio_aggregator_line now uses the 'name' field for the custom line name and the local variable actually represents a 'key'. This change prepares for the next but one commit. No functional change. Signed-off-by: Koichiro Den --- drivers/gpio/gpio-aggregator.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/gpio/gpio-aggregator.c b/drivers/gpio/gpio-aggregator.c index 268b9b580ada..123906c821b1 100644 --- a/drivers/gpio/gpio-aggregator.c +++ b/drivers/gpio/gpio-aggregator.c @@ -1044,7 +1044,7 @@ static struct configfs_subsystem gpio_aggr_subsys = { static int aggr_parse(struct gpio_aggregator *aggr) { char *args = skip_spaces(aggr->args); - char *name, *offsets, *p; + char *key, *offsets, *p; unsigned int i, n = 0; int error = 0; @@ -1053,18 +1053,18 @@ static int aggr_parse(struct gpio_aggregator *aggr) if (!bitmap) return -ENOMEM; - args = next_arg(args, &name, &p); + args = next_arg(args, &key, &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); + error = aggr_add_gpio(aggr, key, U16_MAX, &n); if (error) return error; - name = offsets; + key = offsets; continue; } @@ -1076,12 +1076,12 @@ static int aggr_parse(struct gpio_aggregator *aggr) } for_each_set_bit(i, bitmap, AGGREGATOR_MAX_GPIOS) { - error = aggr_add_gpio(aggr, name, i, &n); + error = aggr_add_gpio(aggr, key, i, &n); if (error) return error; } - args = next_arg(args, &name, &p); + args = next_arg(args, &key, &p); } if (!n) { From patchwork Mon Feb 3 03:12:11 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Koichiro Den X-Patchwork-Id: 863483 Received: from smtp-relay-internal-0.canonical.com (smtp-relay-internal-0.canonical.com [185.125.188.122]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 889631D88A6 for ; Mon, 3 Feb 2025 03:12:54 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=185.125.188.122 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1738552376; cv=none; b=pqPegxP3/LZCJqiX4q/Afxgp1eqwVR4buOnELDoVltnDNZclMhYfqXqP2uK1PifRphLX6V/wsCUr+p05MQM3i9m4lINf0KW5oT0AWhmk3hc98i7NWu3itfjS/rTaAaKQiJLTkMbxwGNXBLIBHtQWlLB5BiDnHzZ4Qz4mY7uudX8= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1738552376; c=relaxed/simple; bh=U6fEqHsDuUdsVMOe9L1E9vnzvA8Wve4zCELAh2CEfW0=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=reZmkawxSfB4HHru5lcFELv7705oVcgcAfO/k2hK1RZy96VKedm0F63bT8G4sFWd7saw2WUOz4IOdvmCUFP/2wLc9OXqmvQrD3cvWPUyiJR7pOafaK/+NCFApk9UcwEPe1b4Z9LVKStrCDaZCkHTXq0+j8OoYOSirm0CYbsolEA= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=canonical.com; spf=pass smtp.mailfrom=canonical.com; dkim=pass (2048-bit key) header.d=canonical.com header.i=@canonical.com header.b=eblDfehz; arc=none smtp.client-ip=185.125.188.122 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=canonical.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=canonical.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=canonical.com header.i=@canonical.com header.b="eblDfehz" Received: from mail-pl1-f200.google.com (mail-pl1-f200.google.com [209.85.214.200]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by smtp-relay-internal-0.canonical.com (Postfix) with ESMTPS id 09A863F887 for ; Mon, 3 Feb 2025 03:12:53 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=canonical.com; s=20210705; t=1738552373; bh=eQvDT9I6qIi3KEVVJ1wodCSAHDsDnsDQuR6xWwKwDIM=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=eblDfehz4aaYaoDJ9wUxjarN6Z1q0tkOlOEnW05hRNg/r7Y3/ZdUiRdD1h5ep53K5 LSrwRpf/QHjUGoab/fX475qqQvTWLiUZFBo+3G53fcSxodnHE1h+QS3Mg5BB9u9Fuk tAlcXOgnq7Ea/tNwRIHWP7v/TGQ8O8s+4pZLQ/ghh/T3hso6NguUfPwJsOTlvYYLPx rSgTLc1AQ/l15noKG85ugZtTp2XdMyt2XcYb2iYucpBhyggVVSziXo6WZ2GswmW9ga /8PdgfgBev/SSveze+rabVz8c4zDzM73XgW3B1an8SeOky65aj5w7lteS/6T58vHJZ Uc4yLjAB0t/cw== Received: by mail-pl1-f200.google.com with SMTP id d9443c01a7336-21648c8601cso71528215ad.2 for ; Sun, 02 Feb 2025 19:12:52 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1738552371; x=1739157171; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=eQvDT9I6qIi3KEVVJ1wodCSAHDsDnsDQuR6xWwKwDIM=; b=FAxTN1+DjKV4S/4CZBHF4xhCgLdv39Ac9CrFRlIThLit6cEIx4P1b3ymU6tZ58Gv2H X4sXwO3JzRJ+JZ2ZzX/qLbPIlMIC1vryOrYMHkGzjtb8BVOpTIuER3GUD88Iy9f+d/H4 j8ewh1V9084dBAbzp5bcx48xfCn16bioSjQIgmFdjucwmee3eOVIyeMyi3BICTlLP7uP FSIF0fe89biMXUuxthq0t68Y3JWnh+7GWnqtyKjFCMvj8Dz8/3CRaJmZ1y3+VBbxL7Y7 8PUbH5oN/T4Q6FbIqEY2XpKKWn+RuZBF6hX+AF8ySEr35JKVdBnEzhscoqAyaeedzOrp 9Opg== X-Gm-Message-State: AOJu0Yx8Nm2nX3xq9hx9g1/Z39Lr6u/3Ix191Awb78P3R0blJPqlnl05 m13uvoHrzHLkRB9/95DbHsw1as4JvNmeNB5nu5vWfL5KEyEF8GJcaQLakDexpOVcK0GZJbmvI3Z MEBxyHSEicKvd6SZ1315Bvc24l6mjNfVvTfdplv19zYPZxEnocZ0C3/sM3ibzaYPMDhTxw72h32 rE2GzrVO8= X-Gm-Gg: ASbGncuiGnfyL4G9DwjRNLpHkcYY0Y2+5X63erVHBvbY91aMN/Jkt8wj7JTa6LiHkwJ zBeHO4xVzbxgIJFPmUNZ0470ZdzC57S5AVBgbfEFJ7BJoTeH7gyC22Nm029vJduxEDQxE6LCzzw m6PBYZtCy1itAYTWWKumQWlEH9UMGfT6On0wPbHTmjMVFfaeDtogCQU3kPrCjwkb8zAxA1n5Vfs Nf6Pp5LBkPfZmSkDnaNJIfCbgZ4+YQNV36YkwIkGNpZl6QkYAC7gB1GQCFr3jCFOzHmZcY/Eiyn bbin X-Received: by 2002:a17:902:e84b:b0:215:b087:5d62 with SMTP id d9443c01a7336-21dd7deec73mr329853495ad.36.1738552371130; Sun, 02 Feb 2025 19:12:51 -0800 (PST) X-Google-Smtp-Source: AGHT+IGZwxZJDa9lhc3DtX2c9/0Y/XXsToTPF3wSKg/veEbtxBCWuGSeuvImIo4eqsvLkLd/6lyQiw== X-Received: by 2002:a17:902:e84b:b0:215:b087:5d62 with SMTP id d9443c01a7336-21dd7deec73mr329853145ad.36.1738552370682; Sun, 02 Feb 2025 19:12:50 -0800 (PST) Received: from z790sl.. ([240f:74:7be:1:33e1:5e62:5b35:92b]) by smtp.gmail.com with ESMTPSA id d9443c01a7336-21de3300253sm65809075ad.162.2025.02.02.19.12.48 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sun, 02 Feb 2025 19:12:50 -0800 (PST) From: Koichiro Den To: linux-gpio@vger.kernel.org Cc: brgl@bgdev.pl, geert+renesas@glider.be, linus.walleij@linaro.org, maciej.borzecki@canonical.com, linux-kernel@vger.kernel.org Subject: [PATCH v2 08/10] gpio: aggregator: expoose aggregator created via legacy sysfs to configfs Date: Mon, 3 Feb 2025 12:12:11 +0900 Message-ID: <20250203031213.399914-9-koichiro.den@canonical.com> X-Mailer: git-send-email 2.45.2 In-Reply-To: <20250203031213.399914-1-koichiro.den@canonical.com> References: <20250203031213.399914-1-koichiro.den@canonical.com> Precedence: bulk X-Mailing-List: linux-gpio@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Expose settings for aggregators created using the sysfs 'new_device' interface to configfs. Once written to 'new_device', an "_auto." path appears in the configfs regardless of whether the probe succeeds. Consequently, users can no longer use that prefix for custom GPIO aggregator names. The 'live' attribute changes to 1 when the probe succeeds and the GPIO forwarder is instantiated. Note that the aggregator device created via sysfs is asynchrnous, i.e. writing into 'new_device' returns without waiting for probe completion, and the probe may succeed, fail, or eventually succeed via deferred probe. Thus, the 'live' attribute may change from 0 to 1 asynchronously without notice. So, editting key/offset/name while it's waiting for deferred probe is prohibited. The configfs auto-generation relies on create_default_group(), which inherently prohibits rmdir(2). To align with the limitation, this commit also prohibits mkdir(2) for them. When users want to change the number of lines for an aggregator initialized via 'new_device', they need to tear down the device using 'delete_device' and reconfigure it from scratch. This does not break previous behaviour; users of legacy sysfs interface simply gain additional almost read-only configfs exposure. Still, users can write into 'live' attribute to toggle the device unless it's waiting for deferred probe. So once probe succeeds, they can deactivate it in the same manner as the devices initialized via configfs. Signed-off-by: Koichiro Den --- drivers/gpio/gpio-aggregator.c | 174 +++++++++++++++++++++++++++++---- 1 file changed, 157 insertions(+), 17 deletions(-) diff --git a/drivers/gpio/gpio-aggregator.c b/drivers/gpio/gpio-aggregator.c index d5fd9fe58164..e101b78ad524 100644 --- a/drivers/gpio/gpio-aggregator.c +++ b/drivers/gpio/gpio-aggregator.c @@ -32,6 +32,7 @@ #include #define AGGREGATOR_MAX_GPIOS 512 +#define AGGREGATOR_LEGACY_PREFIX "_auto" /* * GPIO Aggregator sysfs interface @@ -52,6 +53,8 @@ struct gpio_aggregator { /* List of gpio_aggregator_line. Always added in order */ struct list_head list_head; + /* used by legacy sysfs interface only */ + bool init_via_sysfs; char args[]; }; @@ -73,6 +76,10 @@ struct gpio_aggregator_line { enum gpio_lookup_flags flags; }; +struct gpio_aggregator_pdev_meta { + bool init_via_sysfs; +}; + static DEFINE_MUTEX(gpio_aggregator_lock); /* protects idr */ static DEFINE_IDR(gpio_aggregator_idr); @@ -127,6 +134,14 @@ static bool aggr_is_active(struct gpio_aggregator *aggr) return !!aggr->pdev && platform_get_drvdata(aggr->pdev); } +/* Only aggregators created via legacy sysfs can be "activating". */ +static bool aggr_is_activating(struct gpio_aggregator *aggr) +{ + lockdep_assert_held(&aggr->lock); + + return !!aggr->pdev && !platform_get_drvdata(aggr->pdev); +} + static size_t aggr_count_lines(struct gpio_aggregator *aggr) { lockdep_assert_held(&aggr->lock); @@ -186,6 +201,25 @@ static void aggr_line_del(struct gpio_aggregator *aggr, list_del(&line->entry); } +static void aggr_unregister_lines(struct gpio_aggregator *aggr) +{ + struct gpio_aggregator_line *line; + + list_for_each_entry(line, &aggr->list_head, entry) + configfs_unregister_group(&line->group); +} + +static void aggr_free_lines(struct gpio_aggregator *aggr) +{ + struct gpio_aggregator_line *line, *tmp; + + list_for_each_entry_safe(line, tmp, &aggr->list_head, entry) { + aggr_line_del(aggr, line); + kfree(line->key); + kfree(line); + } +} + /* * GPIO Forwarder @@ -447,6 +481,7 @@ static int gpiochip_fwd_line_names(struct device *dev, const char **names, int l * This array must contain @ngpios entries, and must not be deallocated * before the forwarder has been destroyed again. * @features: Bitwise ORed features as defined with FWD_FEATURE_*. + * @init_via_sysfs: True if the creation is done via legacy sysfs interface. * * This function creates a new gpiochip, which forwards all GPIO operations to * the passed GPIO descriptors. @@ -457,7 +492,8 @@ static int gpiochip_fwd_line_names(struct device *dev, const char **names, int l static struct gpiochip_fwd *gpiochip_fwd_create(struct device *dev, unsigned int ngpios, struct gpio_desc *descs[], - unsigned long features) + unsigned long features, + bool init_via_sysfs) { const char *label = dev_name(dev); struct gpiochip_fwd *fwd; @@ -473,7 +509,7 @@ static struct gpiochip_fwd *gpiochip_fwd_create(struct device *dev, chip = &fwd->chip; - if (!dev_of_node(dev)) { + if (!dev_of_node(dev) && !init_via_sysfs) { line_names = devm_kcalloc(dev, sizeof(*line_names), ngpios, GFP_KERNEL); if (!line_names) return ERR_PTR(-ENOMEM); @@ -516,7 +552,7 @@ static struct gpiochip_fwd *gpiochip_fwd_create(struct device *dev, chip->ngpio = ngpios; fwd->descs = descs; - if (!dev_of_node(dev)) + if (!dev_of_node(dev) && !init_via_sysfs) chip->names = line_names; if (chip->can_sleep) @@ -734,7 +770,7 @@ gpio_aggr_line_key_store(struct config_item *item, const char *page, guard(mutex)(&aggr->lock); - if (aggr_is_active(aggr)) + if (aggr_is_activating(aggr) || aggr_is_active(aggr)) return -EBUSY; kfree(line->key); @@ -772,7 +808,7 @@ gpio_aggr_line_name_store(struct config_item *item, const char *page, guard(mutex)(&aggr->lock); - if (aggr_is_active(aggr)) + if (aggr_is_activating(aggr) || aggr_is_active(aggr)) return -EBUSY; kfree(line->name); @@ -821,7 +857,7 @@ gpio_aggr_line_offset_store(struct config_item *item, const char *page, guard(mutex)(&aggr->lock); - if (aggr_is_active(aggr)) + if (aggr_is_activating(aggr) || aggr_is_active(aggr)) return -EBUSY; line->offset = offset; @@ -879,11 +915,12 @@ gpio_aggr_device_live_store(struct config_item *item, const char *page, if (ret) return ret; - if (live) + if (live && !aggr->init_via_sysfs) aggr_lockup_configfs(aggr, true); scoped_guard(mutex, &aggr->lock) { - if (live == aggr_is_active(aggr)) + if (aggr_is_activating(aggr) || + (live == aggr_is_active(aggr))) ret = -EPERM; else if (live) ret = aggr_activate(aggr); @@ -895,7 +932,7 @@ gpio_aggr_device_live_store(struct config_item *item, const char *page, * Undepend is required only if device disablement (live == 0) * succeeds or if device enablement (live == 1) fails. */ - if (live == !!ret) + if (live == !!ret && !aggr->init_via_sysfs) aggr_lockup_configfs(aggr, false); return ret ?: count; @@ -963,6 +1000,15 @@ gpio_aggr_device_make_group(struct config_group *group, const char *name) if (ret != 1 || nchar != strlen(name)) return ERR_PTR(-EINVAL); + if (aggr->init_via_sysfs) + /* + * Aggregators created via legacy sysfs interface are exposed as + * default groups, which means rmdir(2) is prohibited for them. + * For simplicity, and to avoid confusion, we also prohibit + * mkdir(2). + */ + return ERR_PTR(-EPERM); + guard(mutex)(&aggr->lock); if (aggr_is_active(aggr)) @@ -1002,6 +1048,14 @@ gpio_aggr_make_group(struct config_group *group, const char *name) if (!aggr) return ERR_PTR(-ENOMEM); + /* + * "_auto" prefix is reserved for auto-generated config group + * for devices create via legacy sysfs interface. + */ + if (strncmp(name, AGGREGATOR_LEGACY_PREFIX, + sizeof(AGGREGATOR_LEGACY_PREFIX)) == 0) + return ERR_PTR(-EINVAL); + mutex_lock(&gpio_aggregator_lock); aggr->id = idr_alloc(&gpio_aggregator_idr, aggr, 0, 0, GFP_KERNEL); mutex_unlock(&gpio_aggregator_lock); @@ -1044,6 +1098,8 @@ static struct configfs_subsystem gpio_aggr_subsys = { static int aggr_parse(struct gpio_aggregator *aggr) { char *args = skip_spaces(aggr->args); + struct gpio_aggregator_line *line; + char name[CONFIGFS_ITEM_NAME_LEN]; char *key, *offsets, *p; unsigned int i, n = 0; int error = 0; @@ -1055,14 +1111,29 @@ static int aggr_parse(struct gpio_aggregator *aggr) args = next_arg(args, &key, &p); while (*args) { + scnprintf(name, CONFIGFS_ITEM_NAME_LEN, "line%u", n); + args = next_arg(args, &offsets, &p); p = get_options(offsets, 0, &error); if (error == 0 || *p) { /* Named GPIO line */ + line = aggr_line_alloc(aggr, n, key, -1); + if (!line) { + error = -ENOMEM; + goto err; + } + config_group_init_type_name(&line->group, name, + &gpio_aggr_line_type); + error = configfs_register_group(&aggr->group, + &line->group); + if (error) + goto err; + aggr_line_add(aggr, line); + error = aggr_add_gpio(aggr, key, U16_MAX, &n); if (error) - return error; + goto err; key = offsets; continue; @@ -1076,9 +1147,22 @@ static int aggr_parse(struct gpio_aggregator *aggr) } for_each_set_bit(i, bitmap, AGGREGATOR_MAX_GPIOS) { + line = aggr_line_alloc(aggr, n, key, i); + if (!line) { + error = -ENOMEM; + goto err; + } + config_group_init_type_name(&line->group, name, + &gpio_aggr_line_type); + error = configfs_register_group(&aggr->group, + &line->group); + if (error) + goto err; + aggr_line_add(aggr, line); + error = aggr_add_gpio(aggr, key, i, &n); if (error) - return error; + goto err; } args = next_arg(args, &key, &p); @@ -1086,21 +1170,35 @@ static int aggr_parse(struct gpio_aggregator *aggr) if (!n) { pr_err("No GPIOs specified\n"); - return -EINVAL; + goto err; } return 0; + +err: + aggr_unregister_lines(aggr); + aggr_free_lines(aggr); + return error; } static void aggr_free(struct gpio_aggregator *aggr) { - aggr_deactivate(aggr); + if (aggr_is_active(aggr)) + aggr_deactivate(aggr); + + aggr_unregister_lines(aggr); + aggr_free_lines(aggr); + configfs_unregister_group(&aggr->group); + mutex_destroy(&aggr->lock); + idr_remove(&gpio_aggregator_idr, aggr->id); kfree(aggr); } static ssize_t new_device_store(struct device_driver *driver, const char *buf, size_t count) { + struct gpio_aggregator_pdev_meta meta; + char name[CONFIGFS_ITEM_NAME_LEN]; struct gpio_aggregator *aggr; struct platform_device *pdev; int res, id; @@ -1112,6 +1210,7 @@ static ssize_t new_device_store(struct device_driver *driver, const char *buf, memcpy(aggr->args, buf, count + 1); + aggr->init_via_sysfs = true; aggr->lookups = kzalloc(struct_size(aggr->lookups, table, 1), GFP_KERNEL); if (!aggr->lookups) { @@ -1128,10 +1227,22 @@ static ssize_t new_device_store(struct device_driver *driver, const char *buf, goto free_table; } + scnprintf(name, CONFIGFS_ITEM_NAME_LEN, + "%s.%d", AGGREGATOR_LEGACY_PREFIX, id); + INIT_LIST_HEAD(&aggr->list_head); + mutex_init(&aggr->lock); + config_group_init_type_name(&aggr->group, name, &gpio_aggr_device_type); + init_completion(&aggr->probe_completion); + + /* Expose to configfs */ + res = configfs_register_group(&gpio_aggr_subsys.su_group, &aggr->group); + if (res) + goto remove_idr; + aggr->lookups->dev_id = kasprintf(GFP_KERNEL, "%s.%d", DRV_NAME, id); if (!aggr->lookups->dev_id) { res = -ENOMEM; - goto remove_idr; + goto unregister_group; } res = aggr_parse(aggr); @@ -1140,7 +1251,9 @@ static ssize_t new_device_store(struct device_driver *driver, const char *buf, gpiod_add_lookup_table(aggr->lookups); - pdev = platform_device_register_simple(DRV_NAME, id, NULL, 0); + meta.init_via_sysfs = true; + + pdev = platform_device_register_data(NULL, DRV_NAME, id, &meta, sizeof(meta)); if (IS_ERR(pdev)) { res = PTR_ERR(pdev); goto remove_table; @@ -1153,6 +1266,8 @@ static ssize_t new_device_store(struct device_driver *driver, const char *buf, gpiod_remove_lookup_table(aggr->lookups); free_dev_id: kfree(aggr->lookups->dev_id); +unregister_group: + configfs_unregister_group(&aggr->group); remove_idr: mutex_lock(&gpio_aggregator_lock); idr_remove(&gpio_aggregator_idr, id); @@ -1205,7 +1320,9 @@ ATTRIBUTE_GROUPS(gpio_aggregator); static int gpio_aggregator_probe(struct platform_device *pdev) { + struct gpio_aggregator_pdev_meta *meta; struct device *dev = &pdev->dev; + bool init_via_sysfs = false; struct gpio_desc **descs; struct gpiochip_fwd *fwd; unsigned long features; @@ -1219,6 +1336,10 @@ static int gpio_aggregator_probe(struct platform_device *pdev) if (!descs) return -ENOMEM; + meta = dev_get_platdata(&pdev->dev); + if (meta && meta->init_via_sysfs) + init_via_sysfs = true; + for (i = 0; i < n; i++) { descs[i] = devm_gpiod_get_index(dev, NULL, i, GPIOD_ASIS); if (IS_ERR(descs[i])) @@ -1226,7 +1347,7 @@ static int gpio_aggregator_probe(struct platform_device *pdev) } features = (uintptr_t)device_get_match_data(dev); - fwd = gpiochip_fwd_create(dev, n, descs, features); + fwd = gpiochip_fwd_create(dev, n, descs, features, init_via_sysfs); if (IS_ERR(fwd)) return PTR_ERR(fwd); @@ -1258,7 +1379,26 @@ static struct platform_driver gpio_aggregator_driver = { static int __exit gpio_aggregator_idr_remove(int id, void *p, void *data) { - aggr_free(p); + /* + * There should be no aggregator created via configfs, as their + * presence would prevent module unloading. + */ + struct gpio_aggregator *aggr = (struct gpio_aggregator *)p; + + /* + * For aggregators created via legacy sysfs, some may have been + * deactivated via configfs or may be pending a deferred probe. + * In either case, they need to be deactivated. + */ + if (aggr_is_activating(aggr) || aggr_is_active(aggr)) + aggr_deactivate(aggr); + + /* + * No need to call aggr_unregister_lines() since + * configfs_unregister_subsystem() has already been invoked. + */ + aggr_free_lines(aggr); + kfree(aggr); return 0; } From patchwork Mon Feb 3 03:12:13 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Koichiro Den X-Patchwork-Id: 863482 Received: from smtp-relay-internal-1.canonical.com (smtp-relay-internal-1.canonical.com [185.125.188.123]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 817E31DC075 for ; Mon, 3 Feb 2025 03:12:59 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=185.125.188.123 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1738552381; cv=none; b=UwsZJZerAIzSmUx2w0ARmHAXmSZ1PZE+lt4U0rnQXx7gtNuLTgiXH09OLk0sDYm1lK1HkWW6jATHpCMcfNKs/3KPgsdVOTeDooQPs0P9gMFauOESkJSdN7DFdCuPEOr1HOPvSCDHg74wCcob8iNK5QcuiSyoiXsaIm1t8uF7IMc= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1738552381; c=relaxed/simple; bh=Vqk19K2G5OkkvB0lmlmp+qiCv2ThpYOqqX/LCVhB150=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=CxnNXe4eOwi1arJlo7UYaejac89BI4o6SPWSve+Ja/5FpU/fQ6tA9AB3fn9n3AqlZG9YrQ4XNDv5ImK+3exHqLpVWZlA4CjrnyDXyUQn1O6ZHTSQ6Dl+vn/y1+rcpZqjpUaD19sgnyuwU9wkWoTF79iXTrwTsBBKOuCtZIzHqzA= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=canonical.com; spf=pass smtp.mailfrom=canonical.com; dkim=pass (2048-bit key) header.d=canonical.com header.i=@canonical.com header.b=F5M/t3xL; arc=none smtp.client-ip=185.125.188.123 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=canonical.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=canonical.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=canonical.com header.i=@canonical.com header.b="F5M/t3xL" Received: from mail-pl1-f199.google.com (mail-pl1-f199.google.com [209.85.214.199]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by smtp-relay-internal-1.canonical.com (Postfix) with ESMTPS id 4326F3F29D for ; Mon, 3 Feb 2025 03:12:58 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=canonical.com; s=20210705; t=1738552378; bh=XeAXiTNaWKC5ny0m9ZhKc05Lq+fQXFbLlYp1VOJLKnk=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=F5M/t3xLWy+VqRaTGXxrNtjGXsFYvs1jYEiAgNS+fsu+9l8tlf9h+mmuz+D3EJW5b A2BtyP40NxQUjDFnJaURGdpS0F2skIsRgDjT55VrHUjy2gBgdJ1IaijY0MKmRg5VUj txkY4oYX70m+yY/QG5qVyoKq0LxN0GXR+ta/mtHsicmnZBLQ9FeVvIUsT3cAAB/1fm V39YDJeHJjv0phjhCe4/E1Jm6bVUHdL3Sb1uKWrKDPfk0YLq8pg4QHC8+Tj1eqBejt UOwK5f30i6fobwrge4pKWSEHvi1LFurcQgFfvc1cTTGVISFEcvMu/VHPNaDNCcPKG7 LvH88XQgCorDQ== Received: by mail-pl1-f199.google.com with SMTP id d9443c01a7336-21638389f63so64754255ad.1 for ; Sun, 02 Feb 2025 19:12:58 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1738552376; x=1739157176; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=XeAXiTNaWKC5ny0m9ZhKc05Lq+fQXFbLlYp1VOJLKnk=; b=lUW+Jn6XMkG4VGC7T/V7QslhGF0I/LKkwAvxCl+OjJbzOu4SxJWcJdOQEEbY8Vq7Su BGjrXWDsQ3j79OC46VVoChmRV5ZCZFKhAGqjRyf9L7HMh7dO/FMqJyopdcu7wWFkriZH QrSh2Foipc3SpOAeo1J9cnZJi+0cSYsyfUMT9wDNwAOSyW2Js47UOy8zlarXKE3ZTrfk dy4EbMt3LJWMmsiFrmPuzjSgi5xwZDCMmzgZPjS1EH6dl9a/5xrYZ0XpSrhd4aUEClM5 1YNkHxZPEWNg5vUao5bqub33xe0VomZpz9VQ9ddopYMMZ/+pDG4admMF3G64hVCoOEdq pkAg== X-Gm-Message-State: AOJu0YxGnF6JJRYGrjelheOygUa+B9fsy30KiUsk7gBu3BRN4QJ7juDQ Ut3KkE00ZSQlK7dghnPYTamguKqrxmXyQxRolBOrGJDYYXZOFf0NPwjTcCecQN+/9cD3CPa4bug sY25qwY9lMEPNqeYXbkfT1/RhZ8ZxBtwLMJSs3DrN/rMuZkOjl33cfKjvJ7qfasYpwKfZPgh/1n LLPzxFwrk= X-Gm-Gg: ASbGncu3OkVKaB4XJdYlBGRxRlDO/PYPdME81iXDSHmErjzBjD8PJJTs6pEdzsZ+VCw cn26Y1V0t0DWY9Ayvw/Um0en3hPKrO4htqkOsDAlhQQzIsIrsPmApNedtAC8URK5HoFJUHc1YnR GaVPMs9jGr6f3KB6bZX4umFw/YeEeY0PcjNGHloTHKdBD7aWRmfyb0aJ9JRzuNxxiiY6+/yPO+3 87fzSu/pUwg9gARu6ZnvtMSQT1ANiUXb9dYwMsVteH0GDWh3Lj5VJlxgYhGjhG8bVft5o3wSfz2 4EeR X-Received: by 2002:a17:903:287:b0:215:cbbf:8926 with SMTP id d9443c01a7336-21dd7dddeabmr350239795ad.35.1738552376677; Sun, 02 Feb 2025 19:12:56 -0800 (PST) X-Google-Smtp-Source: AGHT+IEW85KdLcUDRiEGLjEV+sTd+bF/5MEuJ3Hn6OGahCN/cydQSnjK+aCn0zLmryY81e4Gjuewlw== X-Received: by 2002:a17:903:287:b0:215:cbbf:8926 with SMTP id d9443c01a7336-21dd7dddeabmr350239495ad.35.1738552376297; Sun, 02 Feb 2025 19:12:56 -0800 (PST) Received: from z790sl.. ([240f:74:7be:1:33e1:5e62:5b35:92b]) by smtp.gmail.com with ESMTPSA id d9443c01a7336-21de3300253sm65809075ad.162.2025.02.02.19.12.54 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sun, 02 Feb 2025 19:12:56 -0800 (PST) From: Koichiro Den To: linux-gpio@vger.kernel.org Cc: brgl@bgdev.pl, geert+renesas@glider.be, linus.walleij@linaro.org, maciej.borzecki@canonical.com, linux-kernel@vger.kernel.org Subject: [PATCH v2 10/10] Documentation: gpio: document configfs interface for gpio-aggregator Date: Mon, 3 Feb 2025 12:12:13 +0900 Message-ID: <20250203031213.399914-11-koichiro.den@canonical.com> X-Mailer: git-send-email 2.45.2 In-Reply-To: <20250203031213.399914-1-koichiro.den@canonical.com> References: <20250203031213.399914-1-koichiro.den@canonical.com> Precedence: bulk X-Mailing-List: linux-gpio@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Add documentation for the newly added configfs-based interface for GPIO aggregator. Signed-off-by: Koichiro Den --- .../admin-guide/gpio/gpio-aggregator.rst | 93 +++++++++++++++++++ 1 file changed, 93 insertions(+) diff --git a/Documentation/admin-guide/gpio/gpio-aggregator.rst b/Documentation/admin-guide/gpio/gpio-aggregator.rst index 5cd1e7221756..e753f3dc4ae6 100644 --- a/Documentation/admin-guide/gpio/gpio-aggregator.rst +++ b/Documentation/admin-guide/gpio/gpio-aggregator.rst @@ -69,6 +69,99 @@ write-only attribute files in sysfs. $ echo gpio-aggregator.0 > delete_device +Aggregating GPIOs using Configfs +-------------------------------- + +**Group:** ``/config/gpio-aggregator`` + + This is the root directory of the gpio-aggregator configfs tree. + +**Group:** ``/config/gpio-aggregator/`` + + This directory represents a GPIO aggregator device. You can assign any + name to ```` (e.g., ``agg0``), except names starting with + ``_auto`` prefix, which are reserved for auto-generated configfs + entries corresponding to devices created via Sysfs. + +**Attribute:** ``/config/gpio-aggregator//live`` + + The ``live`` attribute allows to trigger the actual creation of the device + once it's fully configured. The accepted values are: ``1`` to enable the + virtual device and ``0`` to disable and tear it down. + +**Attribute:** ``/config/gpio-aggregator//dev_name`` + + The read-only ``dev_name`` attribute exposes the name of the device as it + will appear in the system on the platform bus (e.g. ``gpio-aggregator.0``). + This is useful for identifying a character device for the newly created + aggregator. If it's ``gpio-aggregator.0``, + ``/sys/devices/platform/gpio-aggregator.0/gpiochipX`` path tells you that the + GPIO device id is ``X``. + +You must create subdirectories for each virtual line you want to +instantiate, named exactly as ``line0``, ``line1``, ..., ``lineY``, when +you want to instantiate ``Y+1`` (Y >= 0) lines. Configure all lines before +activating the device by setting ``live`` to 1. + +**Group:** ``/config/gpio-aggregator///`` + + This directory represents a GPIO line to include in the aggregator. + +**Attribute:** ``/config/gpio-aggregator///key`` + +**Attribute:** ``/config/gpio-aggregator///offset`` + + If ``offset`` is >= 0: + * ``key`` specifies the name of the chip this GPIO belongs to + * ``offset`` specifies the line offset within that chip. + If ``offset`` is <0: + * ``key`` needs to specify the GPIO line name. + +**Attribute:** ``/config/gpio-aggregator///name`` + + The ``name`` attribute sets a custom name for lineY. If left unset, the + line will remain unnamed. + +Once the configuration is done, the ``'live'`` attribute must be set to 1 +in order to instantiate the aggregator device. It can be set back to 0 to +destroy the virtual device. The module will synchronously wait for the new +aggregator device to be successfully probed and if this doesn't happen, writing +to ``'live'`` will result in an error. This is a different behaviour from the +case when you create it using sysfs ``new_device`` interface. + +.. note:: + + For aggregators created via Sysfs, the configfs entries are + auto-generated and appear as ``/config/gpio-aggregator/_auto./``. You + cannot add or remove line directories with mkdir(2)/rmdir(2). To modify + lines, you must use the "delete_device" interface to tear down the + existing device and reconfigure it from scratch. However, you can still + toggle the aggregator with the ``live`` attribute and adjust the + ``key``, ``offset``, and ``name`` attributes for each line when ``live`` + is set to 0 by hand (i.e. it's not waiting for deferred probe). + +Sample configuration commands +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. code-block:: sh + + # Create a directory for an aggregator device + $ mkdir /sys/kernel/config/gpio-aggregator/agg0 + + # Configure each line + $ mkdir /sys/kernel/config/gpio-aggregator/agg0/line0 + $ echo gpiochip0 > /sys/kernel/config/gpio-aggregator/agg0/line0/key + $ echo 6 > /sys/kernel/config/gpio-aggregator/agg0/line0/offset + $ echo test0 > /sys/kernel/config/gpio-aggregator/agg0/line0/name + $ mkdir /sys/kernel/config/gpio-aggregator/agg0/line1 + $ echo gpiochip0 > /sys/kernel/config/gpio-aggregator/agg0/line1/key + $ echo 7 > /sys/kernel/config/gpio-aggregator/agg0/line1/offset + $ echo test1 > /sys/kernel/config/gpio-aggregator/agg0/line1/name + + # Activate the aggregator device + $ echo 1 > /sys/kernel/config/gpio-aggregator/agg0/live + + Generic GPIO Driver -------------------