From patchwork Fri Nov 11 01:55:50 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: William Breathitt Gray X-Patchwork-Id: 19277 Return-Path: Delivered-To: ouuuleilei@gmail.com Received: by 2002:a5d:6687:0:0:0:0:0 with SMTP id l7csp1492867wru; Sat, 12 Nov 2022 17:10:53 -0800 (PST) X-Google-Smtp-Source: AA0mqf7L933+sn4NFp+7PiFYCvEjtZkM8uLBJXfmOMEMO6cbJjBCRClVPOzqoCvXaI4wDWgL4zj/ X-Received: by 2002:a17:906:54cf:b0:78a:d075:98d8 with SMTP id c15-20020a17090654cf00b0078ad07598d8mr6495354ejp.324.1668301853222; Sat, 12 Nov 2022 17:10:53 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1668301853; cv=none; d=google.com; s=arc-20160816; b=HKWC66GRy4/pIyP3bK5Hbb5BjfOAT7plXTcYt4dNCcsPgJK1JKTLPeHK4GZSZ+Tk/x BiEn8E+QXcz1MXyWXvbaboaqc8fIeJfbMR6flOZQzQNSXUV/GvmLnZai2Ijv4og/fGbQ 3IEKc/vFM9eNvRGawv+YxFB6t7trzw6ucysqDhC+s6fO9eGq+FYryiAp2PbLt5VeL8GP PEOUuoc6NHHtYSYSXdMWhrOkOceoiSfGrvRFSgISDtSM5eLI0VLUOaEhUR95mmHmqPJ/ vrHNVhPVEFOB0aQJn+aLKbkEglIlwODyfrZsR6lISS0USFBUlFFfLXA3Khv3+4hphbed OU2Q== 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 :references:in-reply-to:message-id:date:subject:cc:to:from :dkim-signature; bh=y2DT+DwYAGhQmBgm02Hatyz4IgqEc7zsVJLAJJN9Ri0=; b=CshItBO0esYvXLHChrBYgX6L9XuQCjI0qawPV3OXLChyBJ901WEg8TChGu2LcjLxG9 +gLUNB8DtUN6WNAPrWbrTpI2j0NFDNJG7XHCLtRNHD7VfnZ5V/U6kxj6xdOciqVtFSBp Orh8J+is0OSN33IViDU9/oxSbhYr/M1BXApfmgKR8asLrW34U6AQuXw4JOIFiA6FV9kz abczrrhhL6Sl/5OLbhSJkfxwQf4wBjrasft83V8bXXo8/GxBa/8VA22QTq/wpUWb6VcG GD32AbFWkLqtDBFZ+/X8eJDZWRDwU3yAFXVNHkW8/OQQ858wMS9sV1FznY38F9JIPoWi 8U0Q== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@linaro.org header.s=google header.b=NazLy5nz; 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=linaro.org Received: from out1.vger.email (out1.vger.email. [2620:137:e000::1:20]) by mx.google.com with ESMTP id nc7-20020a1709071c0700b007adc0d5ad94si6616965ejc.938.2022.11.12.17.10.29; Sat, 12 Nov 2022 17:10:53 -0800 (PST) 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=@linaro.org header.s=google header.b=NazLy5nz; 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=linaro.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S235136AbiKMBJs (ORCPT + 99 others); Sat, 12 Nov 2022 20:09:48 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:37174 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S235106AbiKMBJp (ORCPT ); Sat, 12 Nov 2022 20:09:45 -0500 Received: from mail-qk1-x729.google.com (mail-qk1-x729.google.com [IPv6:2607:f8b0:4864:20::729]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 186CB13F1D for ; Sat, 12 Nov 2022 17:09:45 -0800 (PST) Received: by mail-qk1-x729.google.com with SMTP id x18so5520256qki.4 for ; Sat, 12 Nov 2022 17:09:45 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=y2DT+DwYAGhQmBgm02Hatyz4IgqEc7zsVJLAJJN9Ri0=; b=NazLy5nzQlgW+6kjijqavW5qe2KAD2TLi2xDnZLX97WjnB444i4AJ0eTOg+ljoaaiB 4lhtqnfPwkdxNwPG+6gwN11mYQQCgoS1EgMxx1FgsvDq2wwQa4i+OeYxo0tA9baVeFIb f4M5v59OxUwG8cfhj//NxZOBqvFY4HxfnikrswndKvkqJr7KId7IeNcPnskg+Chffz3U CMTqI+decenIEgYGwLZ937ilUJbsSht0rkGXtHofnmatZ2NoYOAkO9lIOH/J6qNt0qE7 B46c3vEK0IWR/CjPOZS3BHVs/XGcF1g2eBRqP/79G+89/L/jfrwDIdD/VuNWkh2vDnjt sFYQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; 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=y2DT+DwYAGhQmBgm02Hatyz4IgqEc7zsVJLAJJN9Ri0=; b=n0CzMM7uUYEU09o/UOB58kTMZa6Nexoi13ZwIyCIIYronV6pr9awVH5sZjOwvnz7il wFjhwkSw00NfzPkkPJb7emD4DyuHOY//4L2IPdyVD2hxZ+tJenS/iSRpwgKjjGaRP5L3 NvhJaMzv9IvorqOIRsCCR1tPJDQCN3J37zs69iFqYXzIiNj+9CBpcE/faeCa1hxxpvLj HqWtV6/84863cXHT2U2BNJ8ySQ4D/odLVHhtn6epFFfwFm7zta1S0PHs9QtLcV9mlo9I Vxl/HEKrMnyLFN/kQKyD3PHa4tUnew20WPIHKemtUAOYAFlDi18nIol3q7wXNBU6RUNb tVnA== X-Gm-Message-State: ANoB5pkg4xxCFKJehRY9zuoBU25nJ9wJEkcGwIwCRPm9nEnBvjnlIGrd zRjDU4zEqYD65RXEwBUf43oa+A== X-Received: by 2002:a37:6c83:0:b0:6fa:19a4:ab6f with SMTP id h125-20020a376c83000000b006fa19a4ab6fmr6719620qkc.759.1668301784203; Sat, 12 Nov 2022 17:09:44 -0800 (PST) Received: from fedora.attlocal.net (69-109-179-158.lightspeed.dybhfl.sbcglobal.net. [69.109.179.158]) by smtp.gmail.com with ESMTPSA id t6-20020a05622a180600b00343057845f7sm3552498qtc.20.2022.11.12.17.09.42 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sat, 12 Nov 2022 17:09:43 -0800 (PST) From: William Breathitt Gray To: linus.walleij@linaro.org, brgl@bgdev.pl Cc: andriy.shevchenko@linux.intel.com, linux-gpio@vger.kernel.org, linux-kernel@vger.kernel.org, michael@walle.cc, broonie@kernel.org, William Breathitt Gray Subject: [PATCH v2 1/4] gpio: regmap: Always set gpio_chip get_direction Date: Thu, 10 Nov 2022 20:55:50 -0500 Message-Id: <1805d1ddb5bbce8e86164e66421ddde481cce4f9.1668129763.git.william.gray@linaro.org> X-Mailer: git-send-email 2.38.1 In-Reply-To: References: MIME-Version: 1.0 X-Spam-Status: No, score=-0.8 required=5.0 tests=BAYES_00,DATE_IN_PAST_24_48, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,RCVD_IN_DNSWL_NONE, SPF_HELO_NONE,SPF_PASS autolearn=no 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?1749341284189291906?= X-GMAIL-MSGID: =?utf-8?q?1749341284189291906?= If you only have reg_dat_base set, then it is input-only; if you only have reg_set_base set, then it is output-only. Thus, we can always set gpio_chip get_direction to gpio_regmap_get_direction and return GPIO_LINE_DIRECTION_IN/GPIO_LINE_DIRECTION_OUT given the respective register base addresses configuration. Signed-off-by: William Breathitt Gray Reviewed-by: Andy Shevchenko Acked-by: Michael Walle --- drivers/gpio/gpio-regmap.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/gpio/gpio-regmap.c b/drivers/gpio/gpio-regmap.c index 6383136cbe59..f907c9c19fce 100644 --- a/drivers/gpio/gpio-regmap.c +++ b/drivers/gpio/gpio-regmap.c @@ -111,6 +111,11 @@ static int gpio_regmap_get_direction(struct gpio_chip *chip, unsigned int base, val, reg, mask; int invert, ret; + if (gpio->reg_dat_base && !gpio->reg_set_base) + return GPIO_LINE_DIRECTION_IN; + if (gpio->reg_set_base && !gpio->reg_dat_base) + return GPIO_LINE_DIRECTION_OUT; + if (gpio->reg_dir_out_base) { base = gpio_regmap_addr(gpio->reg_dir_out_base); invert = 0; @@ -265,8 +270,8 @@ struct gpio_regmap *gpio_regmap_register(const struct gpio_regmap_config *config else if (gpio->reg_set_base) chip->set = gpio_regmap_set; + chip->get_direction = gpio_regmap_get_direction; if (gpio->reg_dir_in_base || gpio->reg_dir_out_base) { - chip->get_direction = gpio_regmap_get_direction; chip->direction_input = gpio_regmap_direction_input; chip->direction_output = gpio_regmap_direction_output; } From patchwork Fri Nov 11 01:55:51 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: William Breathitt Gray X-Patchwork-Id: 19278 Return-Path: Delivered-To: ouuuleilei@gmail.com Received: by 2002:a5d:6687:0:0:0:0:0 with SMTP id l7csp1492870wru; Sat, 12 Nov 2022 17:10:54 -0800 (PST) X-Google-Smtp-Source: AA0mqf51TtXmhpr5lCqnphVlrYp7Fe9KWGzDwS0sSti7EKM/ynahiVNOw8nZiqUXMrvq6dxOcMyq X-Received: by 2002:a17:906:2659:b0:78d:c155:56b2 with SMTP id i25-20020a170906265900b0078dc15556b2mr6371696ejc.291.1668301854424; Sat, 12 Nov 2022 17:10:54 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1668301854; cv=none; d=google.com; s=arc-20160816; b=BsNpPuOkaKDlm5EN6Vm3w0Z+4W6Iof8lqVNk5eFiA4D3qmNE3TDE7fzNpLmqRYUBzq RumECV5bOxxpmpp0t5CrLdwuDnUSRhNU34LR9D4mKHj4BDgUQwqqgp5LGvg/iHrhc8bd yFzIwIn5PpRzbuqrkNrzTPzcGcWgC20gd0fZHQbM/9RHUe/DhsYUEf4CZ4/xI/ziJLBs Ug44zMdfNK+dbR9lCPdHWPvk0JRpNW3RbuHgRcCnQQhwJ9oqn1bjYQKwzcuBJ7KgO6BL UhsnhVPZjLUq+s5YfqLFVnb+0j0Ov+04QlH0miVf377EBmsAXvMMpwJI2Q5K1yE+n5Kd pwFw== 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 :references:in-reply-to:message-id:date:subject:cc:to:from :dkim-signature; bh=aGoGlg9PvY2E8Ynkgg/9d00Wg7JTF+kYvlV8sa6lfGc=; b=omTD/B6F7C0RsCPUkbs6i3+T13IrElt922So71MLrlj+RfXe2CuBUS7uP1x4vhujx1 pD0fXG2DpoZTkIh0NGvwIU+WCrRur1zauRFlnQgCHHIpmeYquYdohnnmKcxLHBT9HsSS kITPcdOdCW/pz+C2ZhDu2DVgOyivSD90aGcrvXhqwATfQn9Mn97ipEScafI4f5WrJo+H pHWZtbi+fyhgqxKxxGQFYXqvWMk9cso8FtRBh3ShbIBEWEjmdi5oNqasxa9noY7yQpaP XcWdpxMMRs6SaroCtKmMbZ19tPKPup8jQhVgrXmEgPIXq+CKMcvrK6MDVGl+omgLQyaW IPig== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@linaro.org header.s=google header.b=u2g3PubV; 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=linaro.org Received: from out1.vger.email (out1.vger.email. [2620:137:e000::1:20]) by mx.google.com with ESMTP id hq6-20020a1709073f0600b007ade82b9e73si6678154ejc.757.2022.11.12.17.10.31; Sat, 12 Nov 2022 17:10:54 -0800 (PST) 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=@linaro.org header.s=google header.b=u2g3PubV; 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=linaro.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S235152AbiKMBJy (ORCPT + 99 others); Sat, 12 Nov 2022 20:09:54 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:37204 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S235127AbiKMBJs (ORCPT ); Sat, 12 Nov 2022 20:09:48 -0500 Received: from mail-qt1-x82f.google.com (mail-qt1-x82f.google.com [IPv6:2607:f8b0:4864:20::82f]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id E23FA13F26 for ; Sat, 12 Nov 2022 17:09:46 -0800 (PST) Received: by mail-qt1-x82f.google.com with SMTP id jr19so5032263qtb.7 for ; Sat, 12 Nov 2022 17:09:46 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=aGoGlg9PvY2E8Ynkgg/9d00Wg7JTF+kYvlV8sa6lfGc=; b=u2g3PubVHJwCPJno4Iyyr4YIRiDzJp32ZRILY32qbklBibNGwxd5SmTktC06/28jKE KFb94skj8xcv7b/1m/orF0238XBdOkv6eir0/czpxR2E3RYroBu6d4HcaOm+Ea6GQAwr MS4cFhq02sceqBO/+cH8oNRNfkPLjdO9idRYNNBqZOlpB1odN/j2MEYxpdQ5BvhMlGPm KR7EN+loYFRamHbEJ82vwrCWw5b4fDIuITxaFYL/ty8h2Vl/b/SvY7gYd4mglQLoe3Vc sBaapRTgT2pvdOCLiSwtLtvGe1XbugIu52HIY9HfaTzlcRvFJ0tDPodJGnoGMiDbDZ6C 3ogg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; 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=aGoGlg9PvY2E8Ynkgg/9d00Wg7JTF+kYvlV8sa6lfGc=; b=DtNtJkfxrQE1pkZIVE91WxL5lSAz0n0oG1Oj7a1MswI7wfLR2vtD48oy6PTpeuBhd4 JKM/QbNfv0QQLkU65eAgTlmnQshzPezW0AUUpnmrTGlnQI6thnUcilGe+g2cR7rBzD7G kwKjTfc2DIgnxy0SQY+Wbbkjr2317B4ympptFtz4KtA6bl20Tb7DZzDqgWRozOLUs6S5 93xPShEDdG7qSTbOv9sDd4WLX+wW4r+aQo4gVfgesSBB4Jo8UOopUSnNjs/SGt1EtkcR dtwp5QXAHL5L5hYDIs10F7F+XhLhDtk9Jbolt27718F7PNJz40MTN+sHQMeR7Fns0gYr e01Q== X-Gm-Message-State: ANoB5plvaWYMi7/xY0WIskb65wz9A3j5K+IcENU9ksLmtaPx0Wl8Th5c e00dVAJF1iOh63Y5EwrsQIXAtQ== X-Received: by 2002:ac8:4d9a:0:b0:39c:d479:b1d9 with SMTP id a26-20020ac84d9a000000b0039cd479b1d9mr7058653qtw.612.1668301786034; Sat, 12 Nov 2022 17:09:46 -0800 (PST) Received: from fedora.attlocal.net (69-109-179-158.lightspeed.dybhfl.sbcglobal.net. [69.109.179.158]) by smtp.gmail.com with ESMTPSA id t6-20020a05622a180600b00343057845f7sm3552498qtc.20.2022.11.12.17.09.44 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sat, 12 Nov 2022 17:09:45 -0800 (PST) From: William Breathitt Gray To: linus.walleij@linaro.org, brgl@bgdev.pl Cc: andriy.shevchenko@linux.intel.com, linux-gpio@vger.kernel.org, linux-kernel@vger.kernel.org, michael@walle.cc, broonie@kernel.org, William Breathitt Gray Subject: [PATCH v2 2/4] regmap-irq: Add handle_mask_sync() callback Date: Thu, 10 Nov 2022 20:55:51 -0500 Message-Id: <53e9e89cc9d7e9c20cbdfc13b360dcb43d07f832.1668129763.git.william.gray@linaro.org> X-Mailer: git-send-email 2.38.1 In-Reply-To: References: MIME-Version: 1.0 X-Spam-Status: No, score=-0.8 required=5.0 tests=BAYES_00,DATE_IN_PAST_24_48, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,RCVD_IN_DNSWL_NONE, SPF_HELO_NONE,SPF_PASS autolearn=no 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?1749341285151985391?= X-GMAIL-MSGID: =?utf-8?q?1749341285151985391?= Provide a public callback handle_mask_sync() that drivers can use when they have more complex IRQ masking logic. The default implementation is regmap_irq_handle_mask_sync(), used if the chip doesn't provide its own callback. Signed-off-by: William Breathitt Gray --- drivers/base/regmap/regmap-irq.c | 44 ++++++++++++++++++++++---------- include/linux/regmap.h | 5 ++++ 2 files changed, 36 insertions(+), 13 deletions(-) diff --git a/drivers/base/regmap/regmap-irq.c b/drivers/base/regmap/regmap-irq.c index 4ef9488d05cd..968681fa8d09 100644 --- a/drivers/base/regmap/regmap-irq.c +++ b/drivers/base/regmap/regmap-irq.c @@ -115,12 +115,20 @@ static void regmap_irq_sync_unlock(struct irq_data *data) */ for (i = 0; i < d->chip->num_regs; i++) { if (d->mask_base) { - reg = d->get_irq_reg(d, d->mask_base, i); - ret = regmap_update_bits(d->map, reg, - d->mask_buf_def[i], d->mask_buf[i]); - if (ret) - dev_err(d->map->dev, "Failed to sync masks in %x\n", - reg); + if (d->chip->handle_mask_sync) + d->chip->handle_mask_sync(d->map, i, + d->mask_buf_def[i], + d->mask_buf[i], + d->chip->irq_drv_data); + else { + reg = d->get_irq_reg(d, d->mask_base, i); + ret = regmap_update_bits(d->map, reg, + d->mask_buf_def[i], + d->mask_buf[i]); + if (ret) + dev_err(d->map->dev, "Failed to sync masks in %x\n", + reg); + } } if (d->unmask_base) { @@ -917,13 +925,23 @@ int regmap_add_irq_chip_fwnode(struct fwnode_handle *fwnode, d->mask_buf[i] = d->mask_buf_def[i]; if (d->mask_base) { - reg = d->get_irq_reg(d, d->mask_base, i); - ret = regmap_update_bits(d->map, reg, - d->mask_buf_def[i], d->mask_buf[i]); - if (ret) { - dev_err(map->dev, "Failed to set masks in 0x%x: %d\n", - reg, ret); - goto err_alloc; + if (chip->handle_mask_sync) { + ret = chip->handle_mask_sync(d->map, i, + d->mask_buf_def[i], + d->mask_buf[i], + chip->irq_drv_data); + if (ret) + goto err_alloc; + } else { + reg = d->get_irq_reg(d, d->mask_base, i); + ret = regmap_update_bits(d->map, reg, + d->mask_buf_def[i], + d->mask_buf[i]); + if (ret) { + dev_err(map->dev, "Failed to set masks in 0x%x: %d\n", + reg, ret); + goto err_alloc; + } } } diff --git a/include/linux/regmap.h b/include/linux/regmap.h index ca3434dca3a0..62ede456af99 100644 --- a/include/linux/regmap.h +++ b/include/linux/regmap.h @@ -1542,6 +1542,8 @@ struct regmap_irq_chip_data; * before regmap_irq_handler process the interrupts. * @handle_post_irq: Driver specific callback to handle interrupt from device * after handling the interrupts in regmap_irq_handler(). + * @handle_mask_sync: Callback used to handle IRQ mask syncs. The index will be + * in the range [0, num_regs[ * @set_type_virt: Driver specific callback to extend regmap_irq_set_type() * and configure virt regs. Deprecated, use @set_type_config * callback and config registers instead. @@ -1603,6 +1605,9 @@ struct regmap_irq_chip { int (*handle_pre_irq)(void *irq_drv_data); int (*handle_post_irq)(void *irq_drv_data); + int (*handle_mask_sync)(struct regmap *map, int index, + unsigned int mask_buf_def, + unsigned int mask_buf, void *irq_drv_data); int (*set_type_virt)(unsigned int **buf, unsigned int type, unsigned long hwirq, int reg); int (*set_type_config)(unsigned int **buf, unsigned int type, From patchwork Fri Nov 11 01:55:52 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: William Breathitt Gray X-Patchwork-Id: 19279 Return-Path: Delivered-To: ouuuleilei@gmail.com Received: by 2002:a5d:6687:0:0:0:0:0 with SMTP id l7csp1492913wru; Sat, 12 Nov 2022 17:11:04 -0800 (PST) X-Google-Smtp-Source: AA0mqf5vLb24HmDstRAPyv1SA9bWxJuUftSUHHUfVtLyML7A06rtAkliyIGg4Pd0oIOLHqDg2+sB X-Received: by 2002:a17:906:ae52:b0:7ad:4a55:5e19 with SMTP id lf18-20020a170906ae5200b007ad4a555e19mr6568509ejb.65.1668301864067; Sat, 12 Nov 2022 17:11:04 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1668301864; cv=none; d=google.com; s=arc-20160816; b=gZCuTCALzlx5+ZBTWPcGlOPHYTwt+fSyVP6Wvtr87jlB+STDfY2v7K5lj5Mw/Ot2lu FzMyZiZnlgEyAzfv34TymjthRzIKu6N48Qs2FshGwMbMm4cKZAVPgsRndVDA8o7I7opf Us3CK4eMgCTCxYPtP4V8XFexHAs/BRDNBHbCRN4YsKZvwOrN4SIak75Z7JfCPaCzm8kJ 38Recn4BSlgDJBgj+XQNnbrJX3JKZykiWiQjqAKkVu/scuB0+jXOHuQjy0GFBGyj9NV7 7IcGIQzGe5HRcN5QNX3lZbmOmBYH3ER47YYpSYdA4gBz1pi6zVd5AwDi8aBDpli0/AcG Prbw== 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 :references:in-reply-to:message-id:date:subject:cc:to:from :dkim-signature; bh=SCizZ3AFWVpYxg+w13MO/OuiqXytWKoIVvBigEvt7tw=; b=ON0MIDkYerwxwDQNdABhLZY9pvjvKM7DPGiaUST7mdcyNuuwFZXL60hRj6GXmTxUs5 z3BWYQDvlpZg2bG7zmZNKtrXr3tD/NCpzMWH3RolGMi6hzAOqG5X2vi4M/vE0GTijqKf Kl2NevAodjuHDxXv5z8aexnZEfGwu93U0SmahT9ymS1LxkuUlKZ8jvj2nWPgxQD10z2F qPCMZcWZk35IbNIIKNlcKnhNlCHAsyn7u0R6ipRZeTlVFAGL9Cy8J69Ny07WSmOA+Ckw VIEmdjCHbRbaWGj0mTZ3+nVupyA0B5+rlNCO2QKw7tvlsOi9/CbXZwZYQnLckQxxkFWc xGtg== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@linaro.org header.s=google header.b=EKH9vUsq; 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=linaro.org Received: from out1.vger.email (out1.vger.email. [2620:137:e000::1:20]) by mx.google.com with ESMTP id q26-20020a50cc9a000000b0045c3f6adb7csi5643692edi.215.2022.11.12.17.10.40; Sat, 12 Nov 2022 17:11:04 -0800 (PST) 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=@linaro.org header.s=google header.b=EKH9vUsq; 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=linaro.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S235164AbiKMBJ5 (ORCPT + 99 others); Sat, 12 Nov 2022 20:09:57 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:37244 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S235143AbiKMBJu (ORCPT ); Sat, 12 Nov 2022 20:09:50 -0500 Received: from mail-qt1-x832.google.com (mail-qt1-x832.google.com [IPv6:2607:f8b0:4864:20::832]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 964ED140AC for ; Sat, 12 Nov 2022 17:09:48 -0800 (PST) Received: by mail-qt1-x832.google.com with SMTP id s4so5040008qtx.6 for ; Sat, 12 Nov 2022 17:09:48 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=SCizZ3AFWVpYxg+w13MO/OuiqXytWKoIVvBigEvt7tw=; b=EKH9vUsqp3DsMCowyBU3FA8yho1/0Q13WFf3iaZeFdmandcyTAsE88bkrj1TmLPyY2 IZb4ykeiKrp1L005OBx1UkcCAL+rX4z8WPkJT4ZK1cTGsPKIbH2f0sCu5jy/uG5+027F af9N0kPfBScck88ImMRn08ypxw9Wv8RacYR/TmNywx+Dhdn216fSdU0v0zHvkIYRVHI+ KsC6Pp/rlV9SbDUG00JCCwW+wUCp2+hDjB1vcJCcmC0zrANU0Z8iMt2ceUQgDD3Db71i fQQj2OFtCgUfcMHGQZ3qrvV/NjGJ7aX5wCX8XwBCFgmz3ULJ5M9zfKrKBEs6SgLMKWk+ bYqA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; 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=SCizZ3AFWVpYxg+w13MO/OuiqXytWKoIVvBigEvt7tw=; b=t5jMmVc8XhP3rgA8J58P7r+Ep9W3cg8ZL2Opk7tRiPqB//dUO391Cv90d1v/pNwxvW cBDXobFiZfpwSEs8MY8w+7By2IzZY3Qg1DRyineFrGTv2Ex7QVZs2ZIfj4b4bInsP8Rx wbTD/e3NehYjiJNYYMPSTgrsOXWxk82vyuMXHFv7kJ5cUkekqyRqoJdXIKjP3IbqwkSE NQIe42Xt+XiXKwxtVjyg1fcsVGi4U/sLTwkfzecz+rVyS5is28M+eOufdaiGp7IDDK8E MPJVvmZ66DlCbU2kkuiPtSis6ycV7LJXCExvKx6YL+haOuAIKDGjalh2HTDwVBT797H3 MaTg== X-Gm-Message-State: ANoB5plV0YJHGt6MoN5O0+AjKLUoYhh/fNdoUSyKecffTREfAF3Slt5c vloGo3UKa2yqmCjf8VShgLUJUg== X-Received: by 2002:ac8:4e87:0:b0:3a5:6797:c57a with SMTP id 7-20020ac84e87000000b003a56797c57amr7222298qtp.34.1668301788207; Sat, 12 Nov 2022 17:09:48 -0800 (PST) Received: from fedora.attlocal.net (69-109-179-158.lightspeed.dybhfl.sbcglobal.net. [69.109.179.158]) by smtp.gmail.com with ESMTPSA id t6-20020a05622a180600b00343057845f7sm3552498qtc.20.2022.11.12.17.09.46 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sat, 12 Nov 2022 17:09:47 -0800 (PST) From: William Breathitt Gray To: linus.walleij@linaro.org, brgl@bgdev.pl Cc: andriy.shevchenko@linux.intel.com, linux-gpio@vger.kernel.org, linux-kernel@vger.kernel.org, michael@walle.cc, broonie@kernel.org, William Breathitt Gray Subject: [PATCH v2 3/4] gpio: 104-idi-48: Migrate to regmap API Date: Thu, 10 Nov 2022 20:55:52 -0500 Message-Id: <849f73b288185249880839791bfc49056ae36d50.1668129763.git.william.gray@linaro.org> X-Mailer: git-send-email 2.38.1 In-Reply-To: References: MIME-Version: 1.0 X-Spam-Status: No, score=-0.8 required=5.0 tests=BAYES_00,DATE_IN_PAST_24_48, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,RCVD_IN_DNSWL_NONE, SPF_HELO_NONE,SPF_PASS autolearn=no 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?1749341295753750408?= X-GMAIL-MSGID: =?utf-8?q?1749341295753750408?= The regmap API supports IO port accessors so we can take advantage of regmap abstractions rather than handling access to the device registers directly in the driver. Despite the underlying interface being based on i8255, it is simpler to use the gpio_regmap API directly because the 104-IDI-48 device features only input signals. Therefore, the dependence on the i8255 GPIO library is removed in this patch. Signed-off-by: William Breathitt Gray --- drivers/gpio/Kconfig | 3 +- drivers/gpio/gpio-104-idi-48.c | 329 ++++++++++----------------------- 2 files changed, 104 insertions(+), 228 deletions(-) diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index ec7cfd4f52b1..a9852782566d 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -871,7 +871,8 @@ config GPIO_104_IDI_48 depends on PC104 select ISA_BUS_API select GPIOLIB_IRQCHIP - select GPIO_I8255 + select REGMAP_IRQ + select GPIO_REGMAP help Enables GPIO support for the ACCES 104-IDI-48 family (104-IDI-48A, 104-IDI-48AC, 104-IDI-48B, 104-IDI-48BC). The base port addresses for diff --git a/drivers/gpio/gpio-104-idi-48.c b/drivers/gpio/gpio-104-idi-48.c index c5e231fde1af..120ae6d01f43 100644 --- a/drivers/gpio/gpio-104-idi-48.c +++ b/drivers/gpio/gpio-104-idi-48.c @@ -8,23 +8,18 @@ */ #include #include -#include -#include -#include -#include +#include +#include #include -#include +#include +#include #include #include #include #include -#include +#include #include -#include "gpio-i8255.h" - -MODULE_IMPORT_NS(I8255); - #define IDI_48_EXTENT 8 #define MAX_NUM_IDI_48 max_num_isa_dev(IDI_48_EXTENT) @@ -38,185 +33,82 @@ static unsigned int num_irq; module_param_hw_array(irq, uint, irq, &num_irq, 0); MODULE_PARM_DESC(irq, "ACCES 104-IDI-48 interrupt line numbers"); -/** - * struct idi_48_reg - device register structure - * @port0: Port 0 Inputs - * @unused: Unused - * @port1: Port 1 Inputs - * @irq: Read: IRQ Status Register/IRQ Clear - * Write: IRQ Enable/Disable - */ -struct idi_48_reg { - u8 port0[3]; - u8 unused; - u8 port1[3]; - u8 irq; -}; +#define IDI48_IRQ_REG 0x7 -/** - * struct idi_48_gpio - GPIO device private data structure - * @chip: instance of the gpio_chip - * @lock: synchronization lock to prevent I/O race conditions - * @irq_mask: input bits affected by interrupts - * @reg: I/O address offset for the device registers - * @cos_enb: Change-Of-State IRQ enable boundaries mask - */ -struct idi_48_gpio { - struct gpio_chip chip; - spinlock_t lock; - unsigned char irq_mask[6]; - struct idi_48_reg __iomem *reg; - unsigned char cos_enb; -}; - -static int idi_48_gpio_get_direction(struct gpio_chip *chip, unsigned int offset) +static int idi_48_reg_mask_xlate(struct gpio_regmap *gpio, unsigned int base, + unsigned int offset, unsigned int *reg, + unsigned int *mask) { - return GPIO_LINE_DIRECTION_IN; -} + const unsigned int line = offset % 8; + const unsigned int stride = offset / 8; + const unsigned int port = (stride / 3) * 4; + const unsigned int port_stride = stride % 3; -static int idi_48_gpio_direction_input(struct gpio_chip *chip, unsigned int offset) -{ - return 0; -} - -static int idi_48_gpio_get(struct gpio_chip *chip, unsigned int offset) -{ - struct idi_48_gpio *const idi48gpio = gpiochip_get_data(chip); - void __iomem *const ppi = idi48gpio->reg; - - return i8255_get(ppi, offset); -} - -static int idi_48_gpio_get_multiple(struct gpio_chip *chip, unsigned long *mask, - unsigned long *bits) -{ - struct idi_48_gpio *const idi48gpio = gpiochip_get_data(chip); - void __iomem *const ppi = idi48gpio->reg; - - i8255_get_multiple(ppi, mask, bits, chip->ngpio); + *reg = base + port + port_stride; + *mask = BIT(line); return 0; } -static void idi_48_irq_ack(struct irq_data *data) -{ -} - -static void idi_48_irq_mask(struct irq_data *data) -{ - struct gpio_chip *chip = irq_data_get_irq_chip_data(data); - struct idi_48_gpio *const idi48gpio = gpiochip_get_data(chip); - const unsigned int offset = irqd_to_hwirq(data); - const unsigned long boundary = offset / 8; - const unsigned long mask = BIT(offset % 8); - unsigned long flags; - - spin_lock_irqsave(&idi48gpio->lock, flags); - - idi48gpio->irq_mask[boundary] &= ~mask; - gpiochip_disable_irq(chip, offset); - - /* Exit early if there are still input lines with IRQ unmasked */ - if (idi48gpio->irq_mask[boundary]) - goto exit; - - idi48gpio->cos_enb &= ~BIT(boundary); - - iowrite8(idi48gpio->cos_enb, &idi48gpio->reg->irq); - -exit: - spin_unlock_irqrestore(&idi48gpio->lock, flags); -} - -static void idi_48_irq_unmask(struct irq_data *data) -{ - struct gpio_chip *chip = irq_data_get_irq_chip_data(data); - struct idi_48_gpio *const idi48gpio = gpiochip_get_data(chip); - const unsigned int offset = irqd_to_hwirq(data); - const unsigned long boundary = offset / 8; - const unsigned long mask = BIT(offset % 8); - unsigned int prev_irq_mask; - unsigned long flags; - - spin_lock_irqsave(&idi48gpio->lock, flags); - - prev_irq_mask = idi48gpio->irq_mask[boundary]; - - gpiochip_enable_irq(chip, offset); - idi48gpio->irq_mask[boundary] |= mask; - - /* Exit early if IRQ was already unmasked for this boundary */ - if (prev_irq_mask) - goto exit; - - idi48gpio->cos_enb |= BIT(boundary); - - iowrite8(idi48gpio->cos_enb, &idi48gpio->reg->irq); - -exit: - spin_unlock_irqrestore(&idi48gpio->lock, flags); -} - -static int idi_48_irq_set_type(struct irq_data *data, unsigned int flow_type) -{ - /* The only valid irq types are none and both-edges */ - if (flow_type != IRQ_TYPE_NONE && - (flow_type & IRQ_TYPE_EDGE_BOTH) != IRQ_TYPE_EDGE_BOTH) - return -EINVAL; - - return 0; -} - -static const struct irq_chip idi_48_irqchip = { - .name = "104-idi-48", - .irq_ack = idi_48_irq_ack, - .irq_mask = idi_48_irq_mask, - .irq_unmask = idi_48_irq_unmask, - .irq_set_type = idi_48_irq_set_type, - .flags = IRQCHIP_IMMUTABLE, - GPIOCHIP_IRQ_RESOURCE_HELPERS, +static const struct regmap_range idi_48_wr_ranges[] = { + regmap_reg_range(0x0, 0x6), +}; +static const struct regmap_range idi_48_rd_ranges[] = { + regmap_reg_range(0x0, 0x2), regmap_reg_range(0x4, 0x7), +}; +static const struct regmap_range idi_48_precious_ranges[] = { + regmap_reg_range(0x7, 0x7), +}; +static const struct regmap_access_table idi_48_wr_table = { + .no_ranges = idi_48_wr_ranges, + .n_no_ranges = ARRAY_SIZE(idi_48_wr_ranges), +}; +static const struct regmap_access_table idi_48_rd_table = { + .yes_ranges = idi_48_rd_ranges, + .n_yes_ranges = ARRAY_SIZE(idi_48_rd_ranges), +}; +static const struct regmap_access_table idi_48_precious_table = { + .yes_ranges = idi_48_precious_ranges, + .n_yes_ranges = ARRAY_SIZE(idi_48_precious_ranges), +}; +static const struct regmap_config idi48_regmap_config = { + .reg_bits = 8, + .reg_stride = 1, + .val_bits = 8, + .io_port = true, + .max_register = 0x6, + .wr_table = &idi_48_wr_table, + .rd_table = &idi_48_rd_table, + .precious_table = &idi_48_precious_table, }; - -static irqreturn_t idi_48_irq_handler(int irq, void *dev_id) -{ - struct idi_48_gpio *const idi48gpio = dev_id; - unsigned long cos_status; - unsigned long boundary; - unsigned long irq_mask; - unsigned long bit_num; - unsigned long gpio; - struct gpio_chip *const chip = &idi48gpio->chip; - - spin_lock(&idi48gpio->lock); - - cos_status = ioread8(&idi48gpio->reg->irq); - - /* IRQ Status (bit 6) is active low (0 = IRQ generated by device) */ - if (cos_status & BIT(6)) { - spin_unlock(&idi48gpio->lock); - return IRQ_NONE; - } - - /* Bit 0-5 indicate which Change-Of-State boundary triggered the IRQ */ - cos_status &= 0x3F; - - for_each_set_bit(boundary, &cos_status, 6) { - irq_mask = idi48gpio->irq_mask[boundary]; - - for_each_set_bit(bit_num, &irq_mask, 8) { - gpio = bit_num + boundary * 8; - - generic_handle_domain_irq(chip->irq.domain, - gpio); - } - } - - spin_unlock(&idi48gpio->lock); - - return IRQ_HANDLED; -} #define IDI48_NGPIO 48 + +#define IDI48_REGMAP_IRQ(_id) \ + [_id] = { \ + .mask = BIT((_id) / 8), \ + .type = { .types_supported = IRQ_TYPE_EDGE_BOTH, }, \ + } + +static const struct regmap_irq idi48_regmap_irqs[IDI48_NGPIO] = { + IDI48_REGMAP_IRQ(0), IDI48_REGMAP_IRQ(1), IDI48_REGMAP_IRQ(2), + IDI48_REGMAP_IRQ(3), IDI48_REGMAP_IRQ(4), IDI48_REGMAP_IRQ(5), + IDI48_REGMAP_IRQ(6), IDI48_REGMAP_IRQ(7), IDI48_REGMAP_IRQ(8), + IDI48_REGMAP_IRQ(9), IDI48_REGMAP_IRQ(10), IDI48_REGMAP_IRQ(11), + IDI48_REGMAP_IRQ(12), IDI48_REGMAP_IRQ(13), IDI48_REGMAP_IRQ(14), + IDI48_REGMAP_IRQ(15), IDI48_REGMAP_IRQ(16), IDI48_REGMAP_IRQ(17), + IDI48_REGMAP_IRQ(18), IDI48_REGMAP_IRQ(19), IDI48_REGMAP_IRQ(20), + IDI48_REGMAP_IRQ(21), IDI48_REGMAP_IRQ(22), IDI48_REGMAP_IRQ(23), + IDI48_REGMAP_IRQ(24), IDI48_REGMAP_IRQ(25), IDI48_REGMAP_IRQ(26), + IDI48_REGMAP_IRQ(27), IDI48_REGMAP_IRQ(28), IDI48_REGMAP_IRQ(29), + IDI48_REGMAP_IRQ(30), IDI48_REGMAP_IRQ(31), IDI48_REGMAP_IRQ(32), + IDI48_REGMAP_IRQ(33), IDI48_REGMAP_IRQ(34), IDI48_REGMAP_IRQ(35), + IDI48_REGMAP_IRQ(36), IDI48_REGMAP_IRQ(37), IDI48_REGMAP_IRQ(38), + IDI48_REGMAP_IRQ(39), IDI48_REGMAP_IRQ(40), IDI48_REGMAP_IRQ(41), + IDI48_REGMAP_IRQ(42), IDI48_REGMAP_IRQ(43), IDI48_REGMAP_IRQ(44), + IDI48_REGMAP_IRQ(45), IDI48_REGMAP_IRQ(46), IDI48_REGMAP_IRQ(47), +}; + static const char *idi48_names[IDI48_NGPIO] = { "Bit 0 A", "Bit 1 A", "Bit 2 A", "Bit 3 A", "Bit 4 A", "Bit 5 A", "Bit 6 A", "Bit 7 A", "Bit 8 A", "Bit 9 A", "Bit 10 A", "Bit 11 A", @@ -228,75 +120,58 @@ static const char *idi48_names[IDI48_NGPIO] = { "Bit 18 B", "Bit 19 B", "Bit 20 B", "Bit 21 B", "Bit 22 B", "Bit 23 B" }; -static int idi_48_irq_init_hw(struct gpio_chip *gc) -{ - struct idi_48_gpio *const idi48gpio = gpiochip_get_data(gc); - - /* Disable IRQ by default */ - iowrite8(0, &idi48gpio->reg->irq); - ioread8(&idi48gpio->reg->irq); - - return 0; -} - static int idi_48_probe(struct device *dev, unsigned int id) { - struct idi_48_gpio *idi48gpio; const char *const name = dev_name(dev); - struct gpio_irq_chip *girq; + struct gpio_regmap_config config = {0}; + void __iomem *regs; + struct regmap_irq_chip *chip; + struct regmap_irq_chip_data *chip_data; int err; - idi48gpio = devm_kzalloc(dev, sizeof(*idi48gpio), GFP_KERNEL); - if (!idi48gpio) - return -ENOMEM; - if (!devm_request_region(dev, base[id], IDI_48_EXTENT, name)) { dev_err(dev, "Unable to lock port addresses (0x%X-0x%X)\n", base[id], base[id] + IDI_48_EXTENT); return -EBUSY; } - idi48gpio->reg = devm_ioport_map(dev, base[id], IDI_48_EXTENT); - if (!idi48gpio->reg) + regs = devm_ioport_map(dev, base[id], IDI_48_EXTENT); + if (!regs) return -ENOMEM; - idi48gpio->chip.label = name; - idi48gpio->chip.parent = dev; - idi48gpio->chip.owner = THIS_MODULE; - idi48gpio->chip.base = -1; - idi48gpio->chip.ngpio = IDI48_NGPIO; - idi48gpio->chip.names = idi48_names; - idi48gpio->chip.get_direction = idi_48_gpio_get_direction; - idi48gpio->chip.direction_input = idi_48_gpio_direction_input; - idi48gpio->chip.get = idi_48_gpio_get; - idi48gpio->chip.get_multiple = idi_48_gpio_get_multiple; + config.regmap = devm_regmap_init_mmio(dev, regs, &idi48_regmap_config); + if (IS_ERR(config.regmap)) + return PTR_ERR(config.regmap); - girq = &idi48gpio->chip.irq; - gpio_irq_chip_set_chip(girq, &idi_48_irqchip); - /* This will let us handle the parent IRQ in the driver */ - girq->parent_handler = NULL; - girq->num_parents = 0; - girq->parents = NULL; - girq->default_type = IRQ_TYPE_NONE; - girq->handler = handle_edge_irq; - girq->init_hw = idi_48_irq_init_hw; + chip = devm_kzalloc(dev, sizeof(*chip), GFP_KERNEL); + if (!chip) + return -ENOMEM; - spin_lock_init(&idi48gpio->lock); + chip->name = name; + chip->status_base = IDI48_IRQ_REG; + chip->unmask_base = IDI48_IRQ_REG; + chip->clear_on_unmask = true; + chip->num_regs = 1; + chip->irqs = idi48_regmap_irqs; + chip->num_irqs = ARRAY_SIZE(idi48_regmap_irqs); + + err = devm_regmap_add_irq_chip(dev, config.regmap, irq[id], IRQF_SHARED, + 0, chip, &chip_data); - err = devm_gpiochip_add_data(dev, &idi48gpio->chip, idi48gpio); if (err) { - dev_err(dev, "GPIO registering failed (%d)\n", err); + dev_err(dev, "IRQ registration failed (%d)\n", err); return err; } - err = devm_request_irq(dev, irq[id], idi_48_irq_handler, IRQF_SHARED, - name, idi48gpio); - if (err) { - dev_err(dev, "IRQ handler registering failed (%d)\n", err); - return err; - } + config.parent = dev; + config.ngpio = IDI48_NGPIO; + config.names = idi48_names; + config.reg_dat_base = GPIO_REGMAP_ADDR(0x0); + config.ngpio_per_reg = 8; + config.reg_mask_xlate = idi_48_reg_mask_xlate; + config.irq_domain = regmap_irq_get_domain(chip_data); - return 0; + return PTR_ERR_OR_ZERO(devm_gpio_regmap_register(dev, &config)); } static struct isa_driver idi_48_driver = { From patchwork Fri Nov 11 01:55:53 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: William Breathitt Gray X-Patchwork-Id: 19280 Return-Path: Delivered-To: ouuuleilei@gmail.com Received: by 2002:a5d:6687:0:0:0:0:0 with SMTP id l7csp1493337wru; Sat, 12 Nov 2022 17:12:45 -0800 (PST) X-Google-Smtp-Source: AA0mqf6NieLiypuNv5pRfCUp9YMPj3RGrbj+DCloD1ts3tK5D1Z0AxelfLPDflKAV52xBzIZk0ri X-Received: by 2002:a17:906:48d7:b0:78d:cdce:bc52 with SMTP id d23-20020a17090648d700b0078dcdcebc52mr6595237ejt.469.1668301964809; Sat, 12 Nov 2022 17:12:44 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1668301964; cv=none; d=google.com; s=arc-20160816; b=S1/RDL7B74Of/Gn5Vike5+GuMRGp07O3gPSG/0DHRjvIvPbeIJCgCp/BMVYg9xMdtA imP31qq9QDY8YDDfiJGU6EGj2GzTkZNat/lo/WaMEvaYnSxaZk+I/YuqYNNEugB0GyKd p58nEzBniXtS3WvL1901g7j8oZDxmehM148yKdeeEo8soKvFytAUOpu9+XR78TBy7v7m k+sMNizHiPgTVsOaY93mYHo7frFoL3AG/IDWlILbCe0Zo2ljXgWZc3SL6bbPrMWEjI6U eAF39BDJrLUATEizBm0IR0JDx38yZVeD8Fx60AMGC26428Aj6MgEReVt39QWx/yCIhYz iGdA== 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 :references:in-reply-to:message-id:date:subject:cc:to:from :dkim-signature; bh=M/0JAbgjN2ElnKmRPhHAgembeeaVqiU36Slm+rVKp9k=; b=eGoM1q+Yjo6GiDxepOgDuSoVKu5Lzm4LJ2tXGjC1QTbyyvslVVj6MuhcLPME0y9Ntx smnzW7GPM/MGvC0vZvqv6jZHWyVMu5n4f8MJbn6vWwFuVU46PhvBp/cKId+bNv+Q3ILR 0BF5WnJuQt5+v9smBPMHDR4SgI1V/peUNi5KistTyJlO+qAU7oohGnlTgpFuDptsuELG 9+JWOy73oxbv+v0ED/sxxrtrGvXsI3Pfqp1IXvS0cLZCGpWDU72Hxnb7mKZQtFP57boG r3NSp2zE5lzgiZeeg8rsrEX5qWR6ZsUtDvynE+auuIcRCMxOwchNJ1H3+RJWYqNuyT0m uizA== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@linaro.org header.s=google header.b=ezo3S942; 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=linaro.org Received: from out1.vger.email (out1.vger.email. [2620:137:e000::1:20]) by mx.google.com with ESMTP id x3-20020aa7dac3000000b00465f6a9fbb3si5347633eds.155.2022.11.12.17.12.21; Sat, 12 Nov 2022 17:12:44 -0800 (PST) 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=@linaro.org header.s=google header.b=ezo3S942; 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=linaro.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S235167AbiKMBKD (ORCPT + 99 others); Sat, 12 Nov 2022 20:10:03 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:37242 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S235142AbiKMBJx (ORCPT ); Sat, 12 Nov 2022 20:09:53 -0500 Received: from mail-qt1-x832.google.com (mail-qt1-x832.google.com [IPv6:2607:f8b0:4864:20::832]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 053D213F41 for ; Sat, 12 Nov 2022 17:09:51 -0800 (PST) Received: by mail-qt1-x832.google.com with SMTP id s4so5040036qtx.6 for ; Sat, 12 Nov 2022 17:09:50 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=M/0JAbgjN2ElnKmRPhHAgembeeaVqiU36Slm+rVKp9k=; b=ezo3S942E9hVJBAs51k4EM965jR7Z6tdzr/GQLKiVjTNucafe52rtZzKwKP9qWu+fF ZiIIBmegw6ZGgNRm6banlMgBcutmT2jyKzlrVyolze6HTB68CfOqM3p27XYnQNNcbiyF 0R/5WEuKR8R4xH87S58avA/u7xwGMwcfs7odMX/g/NXmMG6PHUG8NIQ75dZWbTnqEkI+ hqWGOymdUK1uQ/sW1AwqqOqWw4ZQk3Aft8ZIva2rqXB+uItVbG9AWkZt5wD14MLHJfAr 0OTdKeYa7a1l1DEg25onVzmVcvFj9Dyy3oGWGLeqacevikMF1k4rM9Jy/Hg8wf83Upni GBVQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; 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=M/0JAbgjN2ElnKmRPhHAgembeeaVqiU36Slm+rVKp9k=; b=7ZgiYnGNfU8R943Yd7woEeFlLBbJ2XDIlmIQPn9FH7xLn20kNQ//z2OZwc8nyoO2lc M3P38nBX6Q/SUhx8Vnoe9ZgOC/X9SIHHC8+JnywisChy2wdEC5O7Jc3t9A+0HyYnrRGH IR/UcpTwAXFBxmsRbtNaExqtBCJEHlon9aXPxvHpTIE3KvnWAKF6aIpIVQUnU8TbiX1V dr1XJIcd7oAXaxfVsq2az7sNKu6dhS97+OLF9TGPt1ilerCFp3/qM9XArNTgPXvxF/Aq kg5rrTWM0lUN7PNwX8zKXuuuoZHTmp4DDVX1cJj7uv74GruMf8Q04qQD4zehfk4uK2i5 kCew== X-Gm-Message-State: ANoB5pmumyV/G6grBRl6sj1/6YOyhu3HorxecsSB457mPRo8ZrRNJtD8 x5R+8bpMronpuRA1sHDL0kafOg== X-Received: by 2002:ac8:140e:0:b0:398:5f25:649 with SMTP id k14-20020ac8140e000000b003985f250649mr7260742qtj.673.1668301790391; Sat, 12 Nov 2022 17:09:50 -0800 (PST) Received: from fedora.attlocal.net (69-109-179-158.lightspeed.dybhfl.sbcglobal.net. [69.109.179.158]) by smtp.gmail.com with ESMTPSA id t6-20020a05622a180600b00343057845f7sm3552498qtc.20.2022.11.12.17.09.48 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sat, 12 Nov 2022 17:09:49 -0800 (PST) From: William Breathitt Gray To: linus.walleij@linaro.org, brgl@bgdev.pl Cc: andriy.shevchenko@linux.intel.com, linux-gpio@vger.kernel.org, linux-kernel@vger.kernel.org, michael@walle.cc, broonie@kernel.org, William Breathitt Gray Subject: [PATCH v2 4/4] gpio: i8255: Migrate to regmap API Date: Thu, 10 Nov 2022 20:55:53 -0500 Message-Id: <61327a67cc308af413471a69a4810b2785e53e8e.1668129763.git.william.gray@linaro.org> X-Mailer: git-send-email 2.38.1 In-Reply-To: References: MIME-Version: 1.0 X-Spam-Status: No, score=-0.8 required=5.0 tests=BAYES_00,DATE_IN_PAST_24_48, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,RCVD_IN_DNSWL_NONE, SPF_HELO_NONE,SPF_PASS autolearn=no 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?1749341400859311227?= X-GMAIL-MSGID: =?utf-8?q?1749341400859311227?= The regmap API supports IO port accessors so we can take advantage of regmap abstractions rather than handling access to the device registers directly in the driver. The 104-dio-48e and gpio-mm modules depend on the i8255 library and are thus updated accordingly. By leveraging the gpio_regmap API, the i8255 library is reduced to simply a devm_i8255_regmap_register() function, a configuration structure struct i8255_regmap_config, and a helper macro i8255_volatile_regmap_range() provided to simplify volatile PPI register hinting for the regmap. Cc: Andy Shevchenko Signed-off-by: William Breathitt Gray --- drivers/gpio/Kconfig | 2 + drivers/gpio/gpio-104-dio-48e.c | 397 ++++++++++------------------- drivers/gpio/gpio-gpio-mm.c | 151 +++-------- drivers/gpio/gpio-i8255.c | 429 +++++++++++--------------------- drivers/gpio/gpio-i8255.h | 80 +++--- 5 files changed, 337 insertions(+), 722 deletions(-) rewrite drivers/gpio/gpio-i8255.c (89%) rewrite drivers/gpio/gpio-i8255.h (89%) diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index a9852782566d..7e1c89c4cb17 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -831,6 +831,7 @@ menu "Port-mapped I/O GPIO drivers" config GPIO_I8255 tristate + select GPIO_REGMAP help Enables support for the i8255 interface library functions. The i8255 interface library provides functions to facilitate communication with @@ -846,6 +847,7 @@ config GPIO_104_DIO_48E depends on PC104 select ISA_BUS_API select GPIOLIB_IRQCHIP + select REGMAP_IRQ select GPIO_I8255 help Enables GPIO support for the ACCES 104-DIO-48E series (104-DIO-48E, diff --git a/drivers/gpio/gpio-104-dio-48e.c b/drivers/gpio/gpio-104-dio-48e.c index 7b8829c8e423..b6905bc39303 100644 --- a/drivers/gpio/gpio-104-dio-48e.c +++ b/drivers/gpio/gpio-104-dio-48e.c @@ -8,17 +8,14 @@ */ #include #include -#include -#include -#include +#include #include -#include -#include +#include #include #include #include #include -#include +#include #include #include "gpio-i8255.h" @@ -38,212 +35,102 @@ static unsigned int num_irq; module_param_hw_array(irq, uint, irq, &num_irq, 0); MODULE_PARM_DESC(irq, "ACCES 104-DIO-48E interrupt line numbers"); +#define DIO48E_ENABLE_INTERRUPT 0xB +#define DIO48E_DISABLE_INTERRUPT DIO48E_ENABLE_INTERRUPT +#define DIO48E_CLEAR_INTERRUPT 0xF + #define DIO48E_NUM_PPI 2 -/** - * struct dio48e_reg - device register structure - * @ppi: Programmable Peripheral Interface groups - * @enable_buffer: Enable/Disable Buffer groups - * @unused1: Unused - * @enable_interrupt: Write: Enable Interrupt - * Read: Disable Interrupt - * @unused2: Unused - * @enable_counter: Write: Enable Counter/Timer Addressing - * Read: Disable Counter/Timer Addressing - * @unused3: Unused - * @clear_interrupt: Clear Interrupt - */ -struct dio48e_reg { - struct i8255 ppi[DIO48E_NUM_PPI]; - u8 enable_buffer[DIO48E_NUM_PPI]; - u8 unused1; - u8 enable_interrupt; - u8 unused2; - u8 enable_counter; - u8 unused3; - u8 clear_interrupt; +static const struct regmap_range dio48e_wr_ranges[] = { + regmap_reg_range(0x0, 0x9), regmap_reg_range(0xB, 0xB), + regmap_reg_range(0xD, 0xD), regmap_reg_range(0xF, 0xF), +}; +static const struct regmap_range dio48e_rd_ranges[] = { + regmap_reg_range(0x0, 0x2), regmap_reg_range(0x4, 0x6), + regmap_reg_range(0xB, 0xB), regmap_reg_range(0xD, 0xD), + regmap_reg_range(0xF, 0xF), +}; +static const struct regmap_range dio48e_volatile_ranges[] = { + i8255_volatile_regmap_range(0x0), i8255_volatile_regmap_range(0x4), + regmap_reg_range(0xB, 0xB), regmap_reg_range(0xD, 0xD), + regmap_reg_range(0xF, 0xF), +}; +static const struct regmap_range dio48e_precious_ranges[] = { + regmap_reg_range(0xB, 0xB), regmap_reg_range(0xD, 0xD), + regmap_reg_range(0xF, 0xF), +}; +static const struct regmap_access_table dio48e_wr_table = { + .yes_ranges = dio48e_wr_ranges, + .n_yes_ranges = ARRAY_SIZE(dio48e_wr_ranges), +}; +static const struct regmap_access_table dio48e_rd_table = { + .yes_ranges = dio48e_rd_ranges, + .n_yes_ranges = ARRAY_SIZE(dio48e_rd_ranges), +}; +static const struct regmap_access_table dio48e_volatile_table = { + .yes_ranges = dio48e_volatile_ranges, + .n_yes_ranges = ARRAY_SIZE(dio48e_volatile_ranges), +}; +static const struct regmap_access_table dio48e_precious_table = { + .yes_ranges = dio48e_precious_ranges, + .n_yes_ranges = ARRAY_SIZE(dio48e_precious_ranges), +}; +static const struct regmap_config dio48e_regmap_config = { + .reg_bits = 8, + .reg_stride = 1, + .val_bits = 8, + .io_port = true, + .max_register = 0xF, + .wr_table = &dio48e_wr_table, + .rd_table = &dio48e_rd_table, + .volatile_table = &dio48e_volatile_table, + .precious_table = &dio48e_precious_table, + .cache_type = REGCACHE_FLAT, }; -/** - * struct dio48e_gpio - GPIO device private data structure - * @chip: instance of the gpio_chip - * @ppi_state: PPI device states - * @lock: synchronization lock to prevent I/O race conditions - * @reg: I/O address offset for the device registers - * @irq_mask: I/O bits affected by interrupts - */ -struct dio48e_gpio { - struct gpio_chip chip; - struct i8255_state ppi_state[DIO48E_NUM_PPI]; - raw_spinlock_t lock; - struct dio48e_reg __iomem *reg; - unsigned char irq_mask; -}; - -static int dio48e_gpio_get_direction(struct gpio_chip *chip, unsigned int offset) -{ - struct dio48e_gpio *const dio48egpio = gpiochip_get_data(chip); - - if (i8255_get_direction(dio48egpio->ppi_state, offset)) - return GPIO_LINE_DIRECTION_IN; - - return GPIO_LINE_DIRECTION_OUT; -} - -static int dio48e_gpio_direction_input(struct gpio_chip *chip, unsigned int offset) -{ - struct dio48e_gpio *const dio48egpio = gpiochip_get_data(chip); - - i8255_direction_input(dio48egpio->reg->ppi, dio48egpio->ppi_state, - offset); - - return 0; -} - -static int dio48e_gpio_direction_output(struct gpio_chip *chip, unsigned int offset, - int value) -{ - struct dio48e_gpio *const dio48egpio = gpiochip_get_data(chip); - - i8255_direction_output(dio48egpio->reg->ppi, dio48egpio->ppi_state, - offset, value); - - return 0; -} - -static int dio48e_gpio_get(struct gpio_chip *chip, unsigned int offset) -{ - struct dio48e_gpio *const dio48egpio = gpiochip_get_data(chip); - - return i8255_get(dio48egpio->reg->ppi, offset); -} - -static int dio48e_gpio_get_multiple(struct gpio_chip *chip, unsigned long *mask, - unsigned long *bits) -{ - struct dio48e_gpio *const dio48egpio = gpiochip_get_data(chip); - - i8255_get_multiple(dio48egpio->reg->ppi, mask, bits, chip->ngpio); - - return 0; -} - -static void dio48e_gpio_set(struct gpio_chip *chip, unsigned int offset, int value) -{ - struct dio48e_gpio *const dio48egpio = gpiochip_get_data(chip); - - i8255_set(dio48egpio->reg->ppi, dio48egpio->ppi_state, offset, value); -} - -static void dio48e_gpio_set_multiple(struct gpio_chip *chip, - unsigned long *mask, unsigned long *bits) -{ - struct dio48e_gpio *const dio48egpio = gpiochip_get_data(chip); - - i8255_set_multiple(dio48egpio->reg->ppi, dio48egpio->ppi_state, mask, - bits, chip->ngpio); -} - -static void dio48e_irq_ack(struct irq_data *data) -{ -} - -static void dio48e_irq_mask(struct irq_data *data) -{ - struct gpio_chip *chip = irq_data_get_irq_chip_data(data); - struct dio48e_gpio *const dio48egpio = gpiochip_get_data(chip); - const unsigned long offset = irqd_to_hwirq(data); - unsigned long flags; - - /* only bit 3 on each respective Port C supports interrupts */ - if (offset != 19 && offset != 43) - return; - - raw_spin_lock_irqsave(&dio48egpio->lock, flags); - - if (offset == 19) - dio48egpio->irq_mask &= ~BIT(0); - else - dio48egpio->irq_mask &= ~BIT(1); - gpiochip_disable_irq(chip, offset); - - if (!dio48egpio->irq_mask) - /* disable interrupts */ - ioread8(&dio48egpio->reg->enable_interrupt); - - raw_spin_unlock_irqrestore(&dio48egpio->lock, flags); -} - -static void dio48e_irq_unmask(struct irq_data *data) -{ - struct gpio_chip *chip = irq_data_get_irq_chip_data(data); - struct dio48e_gpio *const dio48egpio = gpiochip_get_data(chip); - const unsigned long offset = irqd_to_hwirq(data); - unsigned long flags; - - /* only bit 3 on each respective Port C supports interrupts */ - if (offset != 19 && offset != 43) - return; - - raw_spin_lock_irqsave(&dio48egpio->lock, flags); - - if (!dio48egpio->irq_mask) { - /* enable interrupts */ - iowrite8(0x00, &dio48egpio->reg->clear_interrupt); - iowrite8(0x00, &dio48egpio->reg->enable_interrupt); +/* only bit 3 on each respective Port C supports interrupts */ +#define DIO48E_REGMAP_IRQ(_ppi) \ + [19 + (_ppi) * 24] = { \ + .mask = BIT(_ppi), \ + .type = { .types_supported = IRQ_TYPE_EDGE_RISING, }, \ } - gpiochip_enable_irq(chip, offset); - if (offset == 19) - dio48egpio->irq_mask |= BIT(0); - else - dio48egpio->irq_mask |= BIT(1); - - raw_spin_unlock_irqrestore(&dio48egpio->lock, flags); -} - -static int dio48e_irq_set_type(struct irq_data *data, unsigned int flow_type) -{ - const unsigned long offset = irqd_to_hwirq(data); - - /* only bit 3 on each respective Port C supports interrupts */ - if (offset != 19 && offset != 43) - return -EINVAL; - - if (flow_type != IRQ_TYPE_NONE && flow_type != IRQ_TYPE_EDGE_RISING) - return -EINVAL; - - return 0; -} - -static const struct irq_chip dio48e_irqchip = { - .name = "104-dio-48e", - .irq_ack = dio48e_irq_ack, - .irq_mask = dio48e_irq_mask, - .irq_unmask = dio48e_irq_unmask, - .irq_set_type = dio48e_irq_set_type, - .flags = IRQCHIP_IMMUTABLE, - GPIOCHIP_IRQ_RESOURCE_HELPERS, +static const struct regmap_irq dio48e_regmap_irqs[] = { + DIO48E_REGMAP_IRQ(0), DIO48E_REGMAP_IRQ(1), }; -static irqreturn_t dio48e_irq_handler(int irq, void *dev_id) +static int dio48e_handle_mask_sync(struct regmap *const map, const int index, + const unsigned int mask_buf_def, + const unsigned int mask_buf, + void *const irq_drv_data) { - struct dio48e_gpio *const dio48egpio = dev_id; - struct gpio_chip *const chip = &dio48egpio->chip; - const unsigned long irq_mask = dio48egpio->irq_mask; - unsigned long gpio; + unsigned int *const irq_mask = irq_drv_data; + const unsigned int prev_irq_mask = *irq_mask; + const bool mask_change = (mask_buf != prev_irq_mask); + const bool interrupts_disabled = (prev_irq_mask == mask_buf_def); + const bool all_masked = (mask_buf == mask_buf_def); + unsigned int val; + int err; - for_each_set_bit(gpio, &irq_mask, 2) - generic_handle_domain_irq(chip->irq.domain, - 19 + gpio*24); + /* exit early if no change */ + if (!mask_change) + return 0; - raw_spin_lock(&dio48egpio->lock); + *irq_mask = mask_buf; - iowrite8(0x00, &dio48egpio->reg->clear_interrupt); + if (interrupts_disabled) { + /* enable interrupts */ + err = regmap_write(map, DIO48E_ENABLE_INTERRUPT, 0x00); + if (err) + return err; + } else if (all_masked) { + /* disable interrupts */ + err = regmap_read(map, DIO48E_DISABLE_INTERRUPT, &val); + if (err) + return err; + } - raw_spin_unlock(&dio48egpio->lock); - - return IRQ_HANDLED; + return 0; } #define DIO48E_NGPIO 48 @@ -266,41 +153,17 @@ static const char *dio48e_names[DIO48E_NGPIO] = { "PPI Group 1 Port C 5", "PPI Group 1 Port C 6", "PPI Group 1 Port C 7" }; -static int dio48e_irq_init_hw(struct gpio_chip *gc) -{ - struct dio48e_gpio *const dio48egpio = gpiochip_get_data(gc); - - /* Disable IRQ by default */ - ioread8(&dio48egpio->reg->enable_interrupt); - - return 0; -} - -static void dio48e_init_ppi(struct i8255 __iomem *const ppi, - struct i8255_state *const ppi_state) -{ - const unsigned long ngpio = 24; - const unsigned long mask = GENMASK(ngpio - 1, 0); - const unsigned long bits = 0; - unsigned long i; - - /* Initialize all GPIO to output 0 */ - for (i = 0; i < DIO48E_NUM_PPI; i++) { - i8255_mode0_output(&ppi[i]); - i8255_set_multiple(&ppi[i], &ppi_state[i], &mask, &bits, ngpio); - } -} - static int dio48e_probe(struct device *dev, unsigned int id) { - struct dio48e_gpio *dio48egpio; const char *const name = dev_name(dev); - struct gpio_irq_chip *girq; + struct i8255_regmap_config config = {0}; + void __iomem *regs; + struct regmap *map; + unsigned int val; int err; - - dio48egpio = devm_kzalloc(dev, sizeof(*dio48egpio), GFP_KERNEL); - if (!dio48egpio) - return -ENOMEM; + struct regmap_irq_chip *chip; + unsigned int irq_mask; + struct regmap_irq_chip_data *chip_data; if (!devm_request_region(dev, base[id], DIO48E_EXTENT, name)) { dev_err(dev, "Unable to lock port addresses (0x%X-0x%X)\n", @@ -308,53 +171,55 @@ static int dio48e_probe(struct device *dev, unsigned int id) return -EBUSY; } - dio48egpio->reg = devm_ioport_map(dev, base[id], DIO48E_EXTENT); - if (!dio48egpio->reg) + regs = devm_ioport_map(dev, base[id], DIO48E_EXTENT); + if (!regs) return -ENOMEM; - dio48egpio->chip.label = name; - dio48egpio->chip.parent = dev; - dio48egpio->chip.owner = THIS_MODULE; - dio48egpio->chip.base = -1; - dio48egpio->chip.ngpio = DIO48E_NGPIO; - dio48egpio->chip.names = dio48e_names; - dio48egpio->chip.get_direction = dio48e_gpio_get_direction; - dio48egpio->chip.direction_input = dio48e_gpio_direction_input; - dio48egpio->chip.direction_output = dio48e_gpio_direction_output; - dio48egpio->chip.get = dio48e_gpio_get; - dio48egpio->chip.get_multiple = dio48e_gpio_get_multiple; - dio48egpio->chip.set = dio48e_gpio_set; - dio48egpio->chip.set_multiple = dio48e_gpio_set_multiple; + map = devm_regmap_init_mmio(dev, regs, &dio48e_regmap_config); + if (IS_ERR(map)) + return PTR_ERR(map); - girq = &dio48egpio->chip.irq; - gpio_irq_chip_set_chip(girq, &dio48e_irqchip); - /* This will let us handle the parent IRQ in the driver */ - girq->parent_handler = NULL; - girq->num_parents = 0; - girq->parents = NULL; - girq->default_type = IRQ_TYPE_NONE; - girq->handler = handle_edge_irq; - girq->init_hw = dio48e_irq_init_hw; + /* Initialize device interrupt state */ + err = regmap_read(map, DIO48E_DISABLE_INTERRUPT, &val); + if (err) + return err; + err = regmap_write(map, DIO48E_CLEAR_INTERRUPT, 0x00); + if (err) + return err; - raw_spin_lock_init(&dio48egpio->lock); + chip = devm_kzalloc(dev, sizeof(*chip), GFP_KERNEL); + if (!chip) + return -ENOMEM; - i8255_state_init(dio48egpio->ppi_state, DIO48E_NUM_PPI); - dio48e_init_ppi(dio48egpio->reg->ppi, dio48egpio->ppi_state); + chip->irq_drv_data = devm_kzalloc(dev, sizeof(irq_mask), GFP_KERNEL); + if (!chip->irq_drv_data) + return -ENOMEM; - err = devm_gpiochip_add_data(dev, &dio48egpio->chip, dio48egpio); + chip->name = name; + /* No IRQ status register so use CLEAR_INTERRUPT register instead */ + chip->status_base = DIO48E_CLEAR_INTERRUPT; + chip->mask_base = DIO48E_ENABLE_INTERRUPT; + chip->clear_on_unmask = true; + chip->status_invert = true; + chip->num_regs = 1; + chip->irqs = dio48e_regmap_irqs; + chip->num_irqs = ARRAY_SIZE(dio48e_regmap_irqs); + chip->handle_mask_sync = dio48e_handle_mask_sync; + + err = devm_regmap_add_irq_chip(dev, map, irq[id], 0, 0, chip, + &chip_data); if (err) { - dev_err(dev, "GPIO registering failed (%d)\n", err); + dev_err(dev, "IRQ registration failed (%d)\n", err); return err; } - err = devm_request_irq(dev, irq[id], dio48e_irq_handler, 0, name, - dio48egpio); - if (err) { - dev_err(dev, "IRQ handler registering failed (%d)\n", err); - return err; - } + config.parent = dev; + config.map = map; + config.num_ppi = DIO48E_NUM_PPI; + config.names = dio48e_names; + config.domain = regmap_irq_get_domain(chip_data); - return 0; + return devm_i8255_regmap_register(dev, &config); } static struct isa_driver dio48e_driver = { diff --git a/drivers/gpio/gpio-gpio-mm.c b/drivers/gpio/gpio-gpio-mm.c index 2689671b6b01..ba8847485660 100644 --- a/drivers/gpio/gpio-gpio-mm.c +++ b/drivers/gpio/gpio-gpio-mm.c @@ -8,13 +8,13 @@ */ #include #include -#include -#include #include #include #include #include #include +#include +#include #include "gpio-i8255.h" @@ -30,83 +30,22 @@ MODULE_PARM_DESC(base, "Diamond Systems GPIO-MM base addresses"); #define GPIOMM_NUM_PPI 2 -/** - * struct gpiomm_gpio - GPIO device private data structure - * @chip: instance of the gpio_chip - * @ppi_state: Programmable Peripheral Interface group states - * @ppi: Programmable Peripheral Interface groups - */ -struct gpiomm_gpio { - struct gpio_chip chip; - struct i8255_state ppi_state[GPIOMM_NUM_PPI]; - struct i8255 __iomem *ppi; +static const struct regmap_range gpiomm_volatile_ranges[] = { + i8255_volatile_regmap_range(0x0), i8255_volatile_regmap_range(0x4), +}; +static const struct regmap_access_table gpiomm_volatile_table = { + .yes_ranges = gpiomm_volatile_ranges, + .n_yes_ranges = ARRAY_SIZE(gpiomm_volatile_ranges), +}; +static const struct regmap_config gpiomm_regmap_config = { + .reg_bits = 8, + .reg_stride = 1, + .val_bits = 8, + .io_port = true, + .max_register = 0x7, + .volatile_table = &gpiomm_volatile_table, + .cache_type = REGCACHE_FLAT, }; - -static int gpiomm_gpio_get_direction(struct gpio_chip *chip, - unsigned int offset) -{ - struct gpiomm_gpio *const gpiommgpio = gpiochip_get_data(chip); - - if (i8255_get_direction(gpiommgpio->ppi_state, offset)) - return GPIO_LINE_DIRECTION_IN; - - return GPIO_LINE_DIRECTION_OUT; -} - -static int gpiomm_gpio_direction_input(struct gpio_chip *chip, - unsigned int offset) -{ - struct gpiomm_gpio *const gpiommgpio = gpiochip_get_data(chip); - - i8255_direction_input(gpiommgpio->ppi, gpiommgpio->ppi_state, offset); - - return 0; -} - -static int gpiomm_gpio_direction_output(struct gpio_chip *chip, - unsigned int offset, int value) -{ - struct gpiomm_gpio *const gpiommgpio = gpiochip_get_data(chip); - - i8255_direction_output(gpiommgpio->ppi, gpiommgpio->ppi_state, offset, - value); - - return 0; -} - -static int gpiomm_gpio_get(struct gpio_chip *chip, unsigned int offset) -{ - struct gpiomm_gpio *const gpiommgpio = gpiochip_get_data(chip); - - return i8255_get(gpiommgpio->ppi, offset); -} - -static int gpiomm_gpio_get_multiple(struct gpio_chip *chip, unsigned long *mask, - unsigned long *bits) -{ - struct gpiomm_gpio *const gpiommgpio = gpiochip_get_data(chip); - - i8255_get_multiple(gpiommgpio->ppi, mask, bits, chip->ngpio); - - return 0; -} - -static void gpiomm_gpio_set(struct gpio_chip *chip, unsigned int offset, - int value) -{ - struct gpiomm_gpio *const gpiommgpio = gpiochip_get_data(chip); - - i8255_set(gpiommgpio->ppi, gpiommgpio->ppi_state, offset, value); -} - -static void gpiomm_gpio_set_multiple(struct gpio_chip *chip, - unsigned long *mask, unsigned long *bits) -{ - struct gpiomm_gpio *const gpiommgpio = gpiochip_get_data(chip); - - i8255_set_multiple(gpiommgpio->ppi, gpiommgpio->ppi_state, mask, bits, - chip->ngpio); -} #define GPIOMM_NGPIO 48 static const char *gpiomm_names[GPIOMM_NGPIO] = { @@ -120,30 +59,11 @@ static const char *gpiomm_names[GPIOMM_NGPIO] = { "Port 2C2", "Port 2C3", "Port 2C4", "Port 2C5", "Port 2C6", "Port 2C7", }; -static void gpiomm_init_dio(struct i8255 __iomem *const ppi, - struct i8255_state *const ppi_state) -{ - const unsigned long ngpio = 24; - const unsigned long mask = GENMASK(ngpio - 1, 0); - const unsigned long bits = 0; - unsigned long i; - - /* Initialize all GPIO to output 0 */ - for (i = 0; i < GPIOMM_NUM_PPI; i++) { - i8255_mode0_output(&ppi[i]); - i8255_set_multiple(&ppi[i], &ppi_state[i], &mask, &bits, ngpio); - } -} - static int gpiomm_probe(struct device *dev, unsigned int id) { - struct gpiomm_gpio *gpiommgpio; const char *const name = dev_name(dev); - int err; - - gpiommgpio = devm_kzalloc(dev, sizeof(*gpiommgpio), GFP_KERNEL); - if (!gpiommgpio) - return -ENOMEM; + struct i8255_regmap_config config = {0}; + void __iomem *regs; if (!devm_request_region(dev, base[id], GPIOMM_EXTENT, name)) { dev_err(dev, "Unable to lock port addresses (0x%X-0x%X)\n", @@ -151,34 +71,19 @@ static int gpiomm_probe(struct device *dev, unsigned int id) return -EBUSY; } - gpiommgpio->ppi = devm_ioport_map(dev, base[id], GPIOMM_EXTENT); - if (!gpiommgpio->ppi) + regs = devm_ioport_map(dev, base[id], GPIOMM_EXTENT); + if (!regs) return -ENOMEM; - gpiommgpio->chip.label = name; - gpiommgpio->chip.parent = dev; - gpiommgpio->chip.owner = THIS_MODULE; - gpiommgpio->chip.base = -1; - gpiommgpio->chip.ngpio = GPIOMM_NGPIO; - gpiommgpio->chip.names = gpiomm_names; - gpiommgpio->chip.get_direction = gpiomm_gpio_get_direction; - gpiommgpio->chip.direction_input = gpiomm_gpio_direction_input; - gpiommgpio->chip.direction_output = gpiomm_gpio_direction_output; - gpiommgpio->chip.get = gpiomm_gpio_get; - gpiommgpio->chip.get_multiple = gpiomm_gpio_get_multiple; - gpiommgpio->chip.set = gpiomm_gpio_set; - gpiommgpio->chip.set_multiple = gpiomm_gpio_set_multiple; + config.map = devm_regmap_init_mmio(dev, regs, &gpiomm_regmap_config); + if (IS_ERR(config.map)) + return PTR_ERR(config.map); - i8255_state_init(gpiommgpio->ppi_state, GPIOMM_NUM_PPI); - gpiomm_init_dio(gpiommgpio->ppi, gpiommgpio->ppi_state); + config.parent = dev; + config.num_ppi = GPIOMM_NUM_PPI; + config.names = gpiomm_names; - err = devm_gpiochip_add_data(dev, &gpiommgpio->chip, gpiommgpio); - if (err) { - dev_err(dev, "GPIO registering failed (%d)\n", err); - return err; - } - - return 0; + return devm_i8255_regmap_register(dev, &config); } static struct isa_driver gpiomm_driver = { diff --git a/drivers/gpio/gpio-i8255.c b/drivers/gpio/gpio-i8255.c dissimilarity index 89% index 9b97db418df1..db6dab9aa1ef 100644 --- a/drivers/gpio/gpio-i8255.c +++ b/drivers/gpio/gpio-i8255.c @@ -1,287 +1,142 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * Intel 8255 Programmable Peripheral Interface - * Copyright (C) 2022 William Breathitt Gray - */ -#include -#include -#include -#include -#include -#include -#include - -#include "gpio-i8255.h" - -#define I8255_CONTROL_PORTC_LOWER_DIRECTION BIT(0) -#define I8255_CONTROL_PORTB_DIRECTION BIT(1) -#define I8255_CONTROL_PORTC_UPPER_DIRECTION BIT(3) -#define I8255_CONTROL_PORTA_DIRECTION BIT(4) -#define I8255_CONTROL_MODE_SET BIT(7) -#define I8255_PORTA 0 -#define I8255_PORTB 1 -#define I8255_PORTC 2 - -static int i8255_get_port(struct i8255 __iomem *const ppi, - const unsigned long io_port, const unsigned long mask) -{ - const unsigned long bank = io_port / 3; - const unsigned long ppi_port = io_port % 3; - - return ioread8(&ppi[bank].port[ppi_port]) & mask; -} - -static u8 i8255_direction_mask(const unsigned long offset) -{ - const unsigned long port_offset = offset % 8; - const unsigned long io_port = offset / 8; - const unsigned long ppi_port = io_port % 3; - - switch (ppi_port) { - case I8255_PORTA: - return I8255_CONTROL_PORTA_DIRECTION; - case I8255_PORTB: - return I8255_CONTROL_PORTB_DIRECTION; - case I8255_PORTC: - /* Port C can be configured by nibble */ - if (port_offset >= 4) - return I8255_CONTROL_PORTC_UPPER_DIRECTION; - return I8255_CONTROL_PORTC_LOWER_DIRECTION; - default: - /* Should never reach this path */ - return 0; - } -} - -static void i8255_set_port(struct i8255 __iomem *const ppi, - struct i8255_state *const state, - const unsigned long io_port, - const unsigned long mask, const unsigned long bits) -{ - const unsigned long bank = io_port / 3; - const unsigned long ppi_port = io_port % 3; - unsigned long flags; - unsigned long out_state; - - spin_lock_irqsave(&state[bank].lock, flags); - - out_state = ioread8(&ppi[bank].port[ppi_port]); - out_state = (out_state & ~mask) | (bits & mask); - iowrite8(out_state, &ppi[bank].port[ppi_port]); - - spin_unlock_irqrestore(&state[bank].lock, flags); -} - -/** - * i8255_direction_input - configure signal offset as input - * @ppi: Intel 8255 Programmable Peripheral Interface banks - * @state: devices states of the respective PPI banks - * @offset: signal offset to configure as input - * - * Configures a signal @offset as input for the respective Intel 8255 - * Programmable Peripheral Interface (@ppi) banks. The @state control_state - * values are updated to reflect the new configuration. - */ -void i8255_direction_input(struct i8255 __iomem *const ppi, - struct i8255_state *const state, - const unsigned long offset) -{ - const unsigned long io_port = offset / 8; - const unsigned long bank = io_port / 3; - unsigned long flags; - - spin_lock_irqsave(&state[bank].lock, flags); - - state[bank].control_state |= I8255_CONTROL_MODE_SET; - state[bank].control_state |= i8255_direction_mask(offset); - - iowrite8(state[bank].control_state, &ppi[bank].control); - - spin_unlock_irqrestore(&state[bank].lock, flags); -} -EXPORT_SYMBOL_NS_GPL(i8255_direction_input, I8255); - -/** - * i8255_direction_output - configure signal offset as output - * @ppi: Intel 8255 Programmable Peripheral Interface banks - * @state: devices states of the respective PPI banks - * @offset: signal offset to configure as output - * @value: signal value to output - * - * Configures a signal @offset as output for the respective Intel 8255 - * Programmable Peripheral Interface (@ppi) banks and sets the respective signal - * output to the desired @value. The @state control_state values are updated to - * reflect the new configuration. - */ -void i8255_direction_output(struct i8255 __iomem *const ppi, - struct i8255_state *const state, - const unsigned long offset, - const unsigned long value) -{ - const unsigned long io_port = offset / 8; - const unsigned long bank = io_port / 3; - unsigned long flags; - - spin_lock_irqsave(&state[bank].lock, flags); - - state[bank].control_state |= I8255_CONTROL_MODE_SET; - state[bank].control_state &= ~i8255_direction_mask(offset); - - iowrite8(state[bank].control_state, &ppi[bank].control); - - spin_unlock_irqrestore(&state[bank].lock, flags); - - i8255_set(ppi, state, offset, value); -} -EXPORT_SYMBOL_NS_GPL(i8255_direction_output, I8255); - -/** - * i8255_get - get signal value at signal offset - * @ppi: Intel 8255 Programmable Peripheral Interface banks - * @offset: offset of signal to get - * - * Returns the signal value (0=low, 1=high) for the signal at @offset for the - * respective Intel 8255 Programmable Peripheral Interface (@ppi) banks. - */ -int i8255_get(struct i8255 __iomem *const ppi, const unsigned long offset) -{ - const unsigned long io_port = offset / 8; - const unsigned long offset_mask = BIT(offset % 8); - - return !!i8255_get_port(ppi, io_port, offset_mask); -} -EXPORT_SYMBOL_NS_GPL(i8255_get, I8255); - -/** - * i8255_get_direction - get the I/O direction for a signal offset - * @state: devices states of the respective PPI banks - * @offset: offset of signal to get direction - * - * Returns the signal direction (0=output, 1=input) for the signal at @offset. - */ -int i8255_get_direction(const struct i8255_state *const state, - const unsigned long offset) -{ - const unsigned long io_port = offset / 8; - const unsigned long bank = io_port / 3; - - return !!(state[bank].control_state & i8255_direction_mask(offset)); -} -EXPORT_SYMBOL_NS_GPL(i8255_get_direction, I8255); - -/** - * i8255_get_multiple - get multiple signal values at multiple signal offsets - * @ppi: Intel 8255 Programmable Peripheral Interface banks - * @mask: mask of signals to get - * @bits: bitmap to store signal values - * @ngpio: number of GPIO signals of the respective PPI banks - * - * Stores in @bits the values (0=low, 1=high) for the signals defined by @mask - * for the respective Intel 8255 Programmable Peripheral Interface (@ppi) banks. - */ -void i8255_get_multiple(struct i8255 __iomem *const ppi, - const unsigned long *const mask, - unsigned long *const bits, const unsigned long ngpio) -{ - unsigned long offset; - unsigned long port_mask; - unsigned long io_port; - unsigned long port_state; - - bitmap_zero(bits, ngpio); - - for_each_set_clump8(offset, port_mask, mask, ngpio) { - io_port = offset / 8; - port_state = i8255_get_port(ppi, io_port, port_mask); - - bitmap_set_value8(bits, port_state, offset); - } -} -EXPORT_SYMBOL_NS_GPL(i8255_get_multiple, I8255); - -/** - * i8255_mode0_output - configure all PPI ports to MODE 0 output mode - * @ppi: Intel 8255 Programmable Peripheral Interface bank - * - * Configures all Intel 8255 Programmable Peripheral Interface (@ppi) ports to - * MODE 0 (Basic Input/Output) output mode. - */ -void i8255_mode0_output(struct i8255 __iomem *const ppi) -{ - iowrite8(I8255_CONTROL_MODE_SET, &ppi->control); -} -EXPORT_SYMBOL_NS_GPL(i8255_mode0_output, I8255); - -/** - * i8255_set - set signal value at signal offset - * @ppi: Intel 8255 Programmable Peripheral Interface banks - * @state: devices states of the respective PPI banks - * @offset: offset of signal to set - * @value: value of signal to set - * - * Assigns output @value for the signal at @offset for the respective Intel 8255 - * Programmable Peripheral Interface (@ppi) banks. - */ -void i8255_set(struct i8255 __iomem *const ppi, struct i8255_state *const state, - const unsigned long offset, const unsigned long value) -{ - const unsigned long io_port = offset / 8; - const unsigned long port_offset = offset % 8; - const unsigned long mask = BIT(port_offset); - const unsigned long bits = value << port_offset; - - i8255_set_port(ppi, state, io_port, mask, bits); -} -EXPORT_SYMBOL_NS_GPL(i8255_set, I8255); - -/** - * i8255_set_multiple - set signal values at multiple signal offsets - * @ppi: Intel 8255 Programmable Peripheral Interface banks - * @state: devices states of the respective PPI banks - * @mask: mask of signals to set - * @bits: bitmap of signal output values - * @ngpio: number of GPIO signals of the respective PPI banks - * - * Assigns output values defined by @bits for the signals defined by @mask for - * the respective Intel 8255 Programmable Peripheral Interface (@ppi) banks. - */ -void i8255_set_multiple(struct i8255 __iomem *const ppi, - struct i8255_state *const state, - const unsigned long *const mask, - const unsigned long *const bits, - const unsigned long ngpio) -{ - unsigned long offset; - unsigned long port_mask; - unsigned long io_port; - unsigned long value; - - for_each_set_clump8(offset, port_mask, mask, ngpio) { - io_port = offset / 8; - value = bitmap_get_value8(bits, offset); - i8255_set_port(ppi, state, io_port, port_mask, value); - } -} -EXPORT_SYMBOL_NS_GPL(i8255_set_multiple, I8255); - -/** - * i8255_state_init - initialize i8255_state structure - * @state: devices states of the respective PPI banks - * @nbanks: number of Intel 8255 Programmable Peripheral Interface banks - * - * Initializes the @state of each Intel 8255 Programmable Peripheral Interface - * bank for use in i8255 library functions. - */ -void i8255_state_init(struct i8255_state *const state, - const unsigned long nbanks) -{ - unsigned long bank; - - for (bank = 0; bank < nbanks; bank++) - spin_lock_init(&state[bank].lock); -} -EXPORT_SYMBOL_NS_GPL(i8255_state_init, I8255); - -MODULE_AUTHOR("William Breathitt Gray"); -MODULE_DESCRIPTION("Intel 8255 Programmable Peripheral Interface"); -MODULE_LICENSE("GPL"); +// SPDX-License-Identifier: GPL-2.0 +/* + * Intel 8255 Programmable Peripheral Interface + * Copyright (C) 2022 William Breathitt Gray + */ +#include +#include +#include +#include +#include +#include +#include +#include + +#include "gpio-i8255.h" + +#define I8255_NGPIO 24 +#define I8255_NGPIO_PER_REG 8 +#define I8255_CONTROL_PORTC_LOWER_DIRECTION BIT(0) +#define I8255_CONTROL_PORTB_DIRECTION BIT(1) +#define I8255_CONTROL_PORTC_UPPER_DIRECTION BIT(3) +#define I8255_CONTROL_PORTA_DIRECTION BIT(4) +#define I8255_CONTROL_MODE_SET BIT(7) +#define I8255_PORTA 0x0 +#define I8255_PORTB 0x1 +#define I8255_PORTC 0x2 +#define I8255_CONTROL 0x3 +#define I8255_REG_DAT_BASE I8255_PORTA +#define I8255_REG_DIR_IN_BASE I8255_CONTROL + +static int i8255_ppi_init(struct regmap *const map, const unsigned int base) +{ + int err; + + /* Configure all ports to MODE 0 output mode */ + err = regmap_write(map, base + I8255_CONTROL, I8255_CONTROL_MODE_SET); + if (err) + return err; + + /* Initialize all GPIO to output 0 */ + err = regmap_write(map, base + I8255_PORTA, 0x00); + if (err) + return err; + err = regmap_write(map, base + I8255_PORTB, 0x00); + if (err) + return err; + return regmap_write(map, base + I8255_PORTC, 0x00); +} + +static int i8255_direction_mask(const unsigned int offset) +{ + const unsigned int stride = offset / I8255_NGPIO_PER_REG; + const unsigned int line = offset % I8255_NGPIO_PER_REG; + + switch (stride) { + case I8255_PORTA: + return I8255_CONTROL_PORTA_DIRECTION; + case I8255_PORTB: + return I8255_CONTROL_PORTB_DIRECTION; + case I8255_PORTC: + /* Port C can be configured by nibble */ + if (line >= 4) + return I8255_CONTROL_PORTC_UPPER_DIRECTION; + return I8255_CONTROL_PORTC_LOWER_DIRECTION; + default: + /* Should never reach this path */ + return 0; + } +} + +static int i8255_reg_mask_xlate(struct gpio_regmap *gpio, unsigned int base, + unsigned int offset, unsigned int *reg, + unsigned int *mask) +{ + const unsigned int ppi = offset / I8255_NGPIO; + const unsigned int ppi_offset = offset % I8255_NGPIO; + const unsigned int stride = ppi_offset / I8255_NGPIO_PER_REG; + const unsigned int line = ppi_offset % I8255_NGPIO_PER_REG; + + switch (base) { + case I8255_REG_DAT_BASE: + *reg = base + stride + ppi * 4; + *mask = BIT(line); + return 0; + case I8255_REG_DIR_IN_BASE: + *reg = base + ppi * 4; + *mask = i8255_direction_mask(ppi_offset); + return 0; + default: + /* Should never reach this path */ + return -EINVAL; + } +} + +/** + * devm_i8255_regmap_register - Register an i8255 GPIO controller + * @dev: device that is registering this i8255 GPIO device + * @config: configuration for i8255_regmap_config + * + * Registers an Intel 8255 Programmable Peripheral Interface GPIO controller. + * Returns 0 on success and negative error number on failure. + */ +int devm_i8255_regmap_register(struct device *const dev, + const struct i8255_regmap_config *const config) +{ + struct gpio_regmap_config gpio_config = {0}; + unsigned long i; + int err; + + if (!config->parent) + return -EINVAL; + + if (!config->map) + return -EINVAL; + + if (!config->num_ppi) + return -EINVAL; + + for (i = 0; i < config->num_ppi; i++) { + err = i8255_ppi_init(config->map, i * 4); + if (err) + return err; + } + + gpio_config.parent = config->parent; + gpio_config.regmap = config->map; + gpio_config.ngpio = I8255_NGPIO * config->num_ppi; + gpio_config.names = config->names; + gpio_config.reg_dat_base = GPIO_REGMAP_ADDR(I8255_REG_DAT_BASE); + gpio_config.reg_set_base = GPIO_REGMAP_ADDR(I8255_REG_DAT_BASE); + gpio_config.reg_dir_in_base = GPIO_REGMAP_ADDR(I8255_REG_DIR_IN_BASE); + gpio_config.ngpio_per_reg = I8255_NGPIO_PER_REG; + gpio_config.irq_domain = config->domain; + gpio_config.reg_mask_xlate = i8255_reg_mask_xlate; + + return PTR_ERR_OR_ZERO(devm_gpio_regmap_register(dev, &gpio_config)); +} +EXPORT_SYMBOL_NS_GPL(devm_i8255_regmap_register, I8255); + +MODULE_AUTHOR("William Breathitt Gray"); +MODULE_DESCRIPTION("Intel 8255 Programmable Peripheral Interface"); +MODULE_LICENSE("GPL"); diff --git a/drivers/gpio/gpio-i8255.h b/drivers/gpio/gpio-i8255.h dissimilarity index 89% index d9084aae9446..ec12ef923dfc 100644 --- a/drivers/gpio/gpio-i8255.h +++ b/drivers/gpio/gpio-i8255.h @@ -1,46 +1,34 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* Copyright 2022 William Breathitt Gray */ -#ifndef _I8255_H_ -#define _I8255_H_ - -#include -#include - -/** - * struct i8255 - Intel 8255 register structure - * @port: Port A, B, and C - * @control: Control register - */ -struct i8255 { - u8 port[3]; - u8 control; -}; - -/** - * struct i8255_state - Intel 8255 state structure - * @lock: synchronization lock for accessing device state - * @control_state: Control register state - */ -struct i8255_state { - spinlock_t lock; - u8 control_state; -}; - -void i8255_direction_input(struct i8255 __iomem *ppi, struct i8255_state *state, - unsigned long offset); -void i8255_direction_output(struct i8255 __iomem *ppi, - struct i8255_state *state, unsigned long offset, - unsigned long value); -int i8255_get(struct i8255 __iomem *ppi, unsigned long offset); -int i8255_get_direction(const struct i8255_state *state, unsigned long offset); -void i8255_get_multiple(struct i8255 __iomem *ppi, const unsigned long *mask, - unsigned long *bits, unsigned long ngpio); -void i8255_mode0_output(struct i8255 __iomem *const ppi); -void i8255_set(struct i8255 __iomem *ppi, struct i8255_state *state, - unsigned long offset, unsigned long value); -void i8255_set_multiple(struct i8255 __iomem *ppi, struct i8255_state *state, - const unsigned long *mask, const unsigned long *bits, - unsigned long ngpio); -void i8255_state_init(struct i8255_state *const state, unsigned long nbanks); - -#endif /* _I8255_H_ */ +/* SPDX-License-Identifier: GPL-2.0 */ +/* Copyright 2022 William Breathitt Gray */ +#ifndef _I8255_H_ +#define _I8255_H_ + +#include +#include +#include + +/** + * struct i8255_regmap_config - Configuration for the register map of an i8255 + * @parent: parent device + * @map: regmap for the i8255 + * @num_ppi: number of i8255 Programmable Peripheral Interface + * @names: (optional) array of names for gpios + * @domain: (optional) IRQ domain if the controller is interrupt-capable + * + * Note: The regmap is expected to have cache enabled and i8255 control + * registers not marked as volatile. + */ +struct i8255_regmap_config { + struct device *parent; + struct regmap *map; + int num_ppi; + const char *const *names; + struct irq_domain *domain; +}; + +int devm_i8255_regmap_register(struct device *dev, + const struct i8255_regmap_config *config); + +#define i8255_volatile_regmap_range(_base) regmap_reg_range(_base, _base + 0x2) + +#endif /* _I8255_H_ */