From patchwork Thu Jun 8 16:21:30 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Andy Shevchenko X-Patchwork-Id: 105039 Return-Path: Delivered-To: ouuuleilei@gmail.com Received: by 2002:a59:994d:0:b0:3d9:f83d:47d9 with SMTP id k13csp400578vqr; Thu, 8 Jun 2023 09:33:30 -0700 (PDT) X-Google-Smtp-Source: ACHHUZ4CPo903uooThjdFIWMpC3S9WQpIbF8D8O/F+FcFP+XIZnyaZs4kzBD9bDapJMLYiKX8HSD X-Received: by 2002:a17:90a:db95:b0:259:aa15:80e6 with SMTP id h21-20020a17090adb9500b00259aa1580e6mr7208739pjv.23.1686242010516; Thu, 08 Jun 2023 09:33:30 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1686242010; cv=none; d=google.com; s=arc-20160816; b=v7wtxoa4/kXui2lyhjeWyALO9qdAXZ8gHTMgrJBu06qF5fOeuCc7y+sehMEfVbaDN3 2GImkiwMk7WQFAcjTOuXAmRbsvqtRxRMJDIYPRhvIMwNoV76yUMAna7CCSyfb5rPSCjK ZXxfhV/yNNGzOaXeJidupeKTMznm8jAMlYjJECul0+rrcXAqhFWc9P9E/4w4iJkVEGnF CY3dM0UFTK9o9byJiOHu/b0UYtp2ER8QKhYOtKIeUZ3+jMrl2lGcpUWfSJSo5ZHBwZS1 lmqS7UMg6WT/fGyAIRFxRX+2ZG/5n86/BJig6I6L+0M9i8LM/llGb14McnwDqY/DvZyI +xFA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:content-transfer-encoding:mime-version :message-id:date:subject:cc:to:from:dkim-signature; bh=CguRzEWjCI7nIxORqVQBuHehcvBi6aI6lujJT4QlYKU=; b=qb1gL7+ziRmmNavNYZvhjKHCsKoBx7LShSRfzwYFgLQ4tGkeINC83wt5nZ/qr+J9fR lsPdp3t7PKOdiDZLhH8rFklNJkF6m0sq4WQp82tSyYeGA487VNaR3DuBHqAJrIXEGb3f 9hND1o9Ju6NpJATkqVplvIe4/Z6DO6bELxYHfjO4Z1vB4GNuRiOZ5Hr8uN45pnsylTqJ uE1ZQPZEBIH29irFZOYGVKjM9+VTm7Y/JGOq78JZ2aQ3SpNXQCuZUQBGN3MYXBSnSdhT EAk7jZmO6YtE0jEVTje2NFQg1KmXlYLrgXFT12okU8gA9ZvT+FVH1ZC+nbF8qv5GCdHh apEg== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@intel.com header.s=Intel header.b=ib3NjQA9; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=intel.com Received: from out1.vger.email (out1.vger.email. [2620:137:e000::1:20]) by mx.google.com with ESMTP id x16-20020a17090a789000b00253160141c7si2977477pjk.83.2023.06.08.09.33.18; Thu, 08 Jun 2023 09:33:30 -0700 (PDT) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) client-ip=2620:137:e000::1:20; Authentication-Results: mx.google.com; dkim=pass header.i=@intel.com header.s=Intel header.b=ib3NjQA9; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=intel.com Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S234539AbjFHQXb (ORCPT + 99 others); Thu, 8 Jun 2023 12:23:31 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:33388 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S234524AbjFHQXG (ORCPT ); Thu, 8 Jun 2023 12:23:06 -0400 Received: from mga01.intel.com (mga01.intel.com [192.55.52.88]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 869702D72; Thu, 8 Jun 2023 09:22:57 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1686241377; x=1717777377; h=from:to:cc:subject:date:message-id:mime-version: content-transfer-encoding; bh=0EWXB2OkiFb2hh+8AxZy+RiHPeZQVtYstodxAyYGW94=; b=ib3NjQA9e0047FXHvdxmTUdGmpTyIrzcTtSFt06oE3BaHwj0csg+bO+p 0eq/dBQAqZsi5Khnrvc5USVxIGdKP+zPmSrbfc6zIPqzZONoHMlCcAaxe tvqLiRmVZZttp89pyROkpeOJgBrf0mjTskSwOXY6GgE5OmmzGklzerVO/ cn08LblaUwGiHchoBVTjuvMhI0KXekufmDTZi0Z0jJYYVIbK3XhlIfYBO tZd25pUmpbymFbYQHXqQsiyjwc8htFbEy5w1WktnK0B7+5yf0BnIPgnpl 2Yg48r8puu8jx5blBQb3m8Sm9TNUqzeXJ+lUc9/8WXehU1rEMkjFGyIlI w==; X-IronPort-AV: E=McAfee;i="6600,9927,10735"; a="385701292" X-IronPort-AV: E=Sophos;i="6.00,227,1681196400"; d="scan'208";a="385701292" Received: from orsmga005.jf.intel.com ([10.7.209.41]) by fmsmga101.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 08 Jun 2023 09:21:29 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=McAfee;i="6600,9927,10735"; a="884252675" X-IronPort-AV: E=Sophos;i="6.00,227,1681196400"; d="scan'208";a="884252675" Received: from black.fi.intel.com ([10.237.72.28]) by orsmga005.jf.intel.com with ESMTP; 08 Jun 2023 09:21:26 -0700 Received: by black.fi.intel.com (Postfix, from userid 1003) id 45B8C1B4; Thu, 8 Jun 2023 19:21:33 +0300 (EEST) From: Andy Shevchenko To: Andy Shevchenko , linux-gpio@vger.kernel.org, linux-kernel@vger.kernel.org Cc: Geert Uytterhoeven , Linus Walleij , Bartosz Golaszewski , Andy Shevchenko , Alexander Stein Subject: [rfc, rft, PATCH v1 1/1] gpio: aggregator: Introduce delay support for individual output pins Date: Thu, 8 Jun 2023 19:21:30 +0300 Message-Id: <20230608162130.55015-1-andriy.shevchenko@linux.intel.com> X-Mailer: git-send-email 2.40.0.1.gaa8946217a0b MIME-Version: 1.0 X-Spam-Status: No, score=-4.3 required=5.0 tests=BAYES_00,DKIMWL_WL_HIGH, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_EF,RCVD_IN_DNSWL_MED, RCVD_IN_MSPIKE_H3,RCVD_IN_MSPIKE_WL,SPF_HELO_NONE,SPF_NONE, T_SCC_BODY_TEXT_LINE autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org X-getmail-retrieved-from-mailbox: =?utf-8?q?INBOX?= X-GMAIL-THRID: =?utf-8?q?1768152902008596083?= X-GMAIL-MSGID: =?utf-8?q?1768152902008596083?= The aggregator mode can also handle properties of the platform, that do not belong to the GPIO controller itself. One of such a property is signal delay line. Intdoduce support of it. Signed-off-by: Andy Shevchenko --- I don't like the idea of gpio-delay or similar. We have already GPIO aggregator that incorporates the GPIO proxy / forwarder functionality. This one is RFC because: 1) just compile tested; 2) has obvious issues with CONFIG_OF_GPIO; 3) contains ~5 patches in a single change for now; 4) requires additional work with blocking sysfs for this; 5) requires some DT bindings work; 6) ...whatever I forgot... Any comments are appreciated, and tests are esp. welcome! drivers/gpio/gpio-aggregator.c | 84 ++++++++++++++++++++++++++++++---- 1 file changed, 74 insertions(+), 10 deletions(-) diff --git a/drivers/gpio/gpio-aggregator.c b/drivers/gpio/gpio-aggregator.c index 20a686f12df7..802d123f0188 100644 --- a/drivers/gpio/gpio-aggregator.c +++ b/drivers/gpio/gpio-aggregator.c @@ -10,12 +10,14 @@ #include #include #include +#include #include #include #include #include #include #include +#include #include #include #include @@ -239,6 +241,11 @@ static void __exit gpio_aggregator_remove_all(void) * GPIO Forwarder */ +struct gpiochip_fwd_timing { + unsigned long ramp_up_us; + unsigned long ramp_down_us; +}; + struct gpiochip_fwd { struct gpio_chip chip; struct gpio_desc **descs; @@ -246,6 +253,7 @@ struct gpiochip_fwd { struct mutex mlock; /* protects tmp[] if can_sleep */ spinlock_t slock; /* protects tmp[] if !can_sleep */ }; + struct gpiochip_fwd_timing *delay_timings; unsigned long tmp[]; /* values and descs for multiple ops */ }; @@ -333,11 +341,28 @@ static int gpio_fwd_get_multiple_locked(struct gpio_chip *chip, static void gpio_fwd_set(struct gpio_chip *chip, unsigned int offset, int value) { struct gpiochip_fwd *fwd = gpiochip_get_data(chip); + const struct gpiochip_fwd_timing *delay_timings; + struct gpio_desc *desc = fwd->descs[offset]; + bool is_active_low = gpiod_is_active_low(desc); + bool ramp_up; - if (chip->can_sleep) - gpiod_set_value_cansleep(fwd->descs[offset], value); - else - gpiod_set_value(fwd->descs[offset], value); + delay_timings = &fwd->delay_timings[offset]; + ramp_up = (!is_active_low && value) || (is_active_low && !value); + if (chip->can_sleep) { + gpiod_set_value_cansleep(desc, value); + + if (ramp_up && delay_timings->ramp_up_us) + fsleep(delay_timings->ramp_up_us); + if (!ramp_up && delay_timings->ramp_down_us) + fsleep(delay_timings->ramp_down_us); + } else { + gpiod_set_value(desc, value); + + if (ramp_up && delay_timings->ramp_up_us) + udelay(delay_timings->ramp_up_us); + if (!ramp_up && delay_timings->ramp_down_us) + udelay(delay_timings->ramp_down_us); + } } static void gpio_fwd_set_multiple(struct gpiochip_fwd *fwd, unsigned long *mask, @@ -390,6 +415,28 @@ static int gpio_fwd_to_irq(struct gpio_chip *chip, unsigned int offset) return gpiod_to_irq(fwd->descs[offset]); } +static int gpiochip_fwd_delay_of_xlate(struct gpio_chip *chip, + const struct of_phandle_args *gpiospec, + u32 *flags) +{ + struct gpiochip_fwd *fwd = gpiochip_get_data(chip); + struct gpiochip_fwd_timing *timings; + u32 line; + + if (gpiospec->args_count != chip->of_gpio_n_cells) + return -EINVAL; + + line = gpiospec->args[0]; + if (line >= chip->ngpio) + return -EINVAL; + + timings = &fwd->delay_timings[line]; + timings->ramp_up_us = gpiospec->args[1]; + timings->ramp_down_us = gpiospec->args[2]; + + return line; +} + /** * gpiochip_fwd_create() - Create a new GPIO forwarder * @dev: Parent device pointer @@ -397,6 +444,7 @@ static int gpio_fwd_to_irq(struct gpio_chip *chip, unsigned int offset) * @descs: Array containing the GPIO descriptors to forward to. * This array must contain @ngpios entries, and must not be deallocated * before the forwarder has been destroyed again. + * @delay: True if the pins have an external delay line. * * This function creates a new gpiochip, which forwards all GPIO operations to * the passed GPIO descriptors. @@ -406,7 +454,8 @@ static int gpio_fwd_to_irq(struct gpio_chip *chip, unsigned int offset) */ static struct gpiochip_fwd *gpiochip_fwd_create(struct device *dev, unsigned int ngpios, - struct gpio_desc *descs[]) + struct gpio_desc *descs[], + bool delay) { const char *label = dev_name(dev); struct gpiochip_fwd *fwd; @@ -459,6 +508,17 @@ static struct gpiochip_fwd *gpiochip_fwd_create(struct device *dev, else spin_lock_init(&fwd->slock); + if (delay) { + fwd->delay_timings = devm_kcalloc(dev, ngpios, + sizeof(*fwd->delay_timings), + GFP_KERNEL); + if (!fwd->delay_timings) + return ERR_PTR(-ENOMEM); + + chip->of_xlate = gpiochip_fwd_delay_of_xlate; + chip->of_gpio_n_cells = 3; + } + error = devm_gpiochip_add_data(dev, chip, fwd); if (error) return ERR_PTR(error); @@ -476,6 +536,7 @@ static int gpio_aggregator_probe(struct platform_device *pdev) struct device *dev = &pdev->dev; struct gpio_desc **descs; struct gpiochip_fwd *fwd; + bool delay; int i, n; n = gpiod_count(dev, NULL); @@ -492,7 +553,9 @@ static int gpio_aggregator_probe(struct platform_device *pdev) return PTR_ERR(descs[i]); } - fwd = gpiochip_fwd_create(dev, n, descs); + delay = fwnode_device_is_compatible(dev_fwnode(dev), "gpio-delay"); + + fwd = gpiochip_fwd_create(dev, n, descs, delay); if (IS_ERR(fwd)) return PTR_ERR(fwd); @@ -500,23 +563,24 @@ static int gpio_aggregator_probe(struct platform_device *pdev) return 0; } -#ifdef CONFIG_OF static const struct of_device_id gpio_aggregator_dt_ids[] = { /* * Add GPIO-operated devices controlled from userspace below, - * or use "driver_override" in sysfs + * or use "driver_override" in sysfs. */ + { + .compatible = "gpio-delay", + }, {} }; MODULE_DEVICE_TABLE(of, gpio_aggregator_dt_ids); -#endif static struct platform_driver gpio_aggregator_driver = { .probe = gpio_aggregator_probe, .driver = { .name = DRV_NAME, .groups = gpio_aggregator_groups, - .of_match_table = of_match_ptr(gpio_aggregator_dt_ids), + .of_match_table = gpio_aggregator_dt_ids, }, };