From nobody Sun Apr 19 02:19:41 2026 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 76C86C43334 for ; Thu, 7 Jul 2022 23:16:21 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S236766AbiGGXQT (ORCPT ); Thu, 7 Jul 2022 19:16:19 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:58180 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S236354AbiGGXQS (ORCPT ); Thu, 7 Jul 2022 19:16:18 -0400 Received: from mail-oa1-x31.google.com (mail-oa1-x31.google.com [IPv6:2001:4860:4864:20::31]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id BE719675BA for ; Thu, 7 Jul 2022 16:16:16 -0700 (PDT) Received: by mail-oa1-x31.google.com with SMTP id 586e51a60fabf-10be0d7476aso20376993fac.2 for ; Thu, 07 Jul 2022 16:16:16 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=ael3to+pQw5kcMQjn9uyLd/aGdcqjP4ufwXWigGWHxA=; b=HyeCcX6zfK6ju/UZMlCfR3G3aJWHIFLO/qUunbC7r3xRAQHFGUyLqpXRPpgHA6v4BB TIAI4+U2VgOA5hJvi5+hVzLwlTur0Dif/cOWQoMaBoulErlejKxcJP3drjVKAR9+qnAz T6Rvw8z7ZcZLkHrSyFToTMAzoIeT+ubDoO9qpoYCBgv3wp6ua5hX0sXsaLpAWM33d4pQ QdBGm1oGDDBDc0fwxLOthSdHqmvLvFOhgqD0hjYuJya8uGefPHzxtxcO4yl3FvU40Wc2 ZQJz08Xlq1uO5a7eFt+VEPWotaxCtuOMcUV4ZagZoaQxpA7/mXVqwtYBXHXhty/v6spm PrYA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=ael3to+pQw5kcMQjn9uyLd/aGdcqjP4ufwXWigGWHxA=; b=eO7LTi1dWivYOmZji24afGZOu9Q2U3hwXg4QOZXyi6DfGYwL+8tBVRuoFN6ZoMYjmO U9kXY/EaiajJi4OS7r54Ab5JN64zJbo44oDzCP6hOuf3AoCBiVYWrv7v0aVciuTAseKL nWERvEWsT/CAVsMf9XQkPnI0kudJmtAH3xpV0iO/S2iGzJ+9Dkah5qZ+XmH4jgZCOknW 9zVuudH4iC2xoiGH/lNtTIGRu32ufbhd33/yBYt7N+4HOAKxJimm2Dl/Rv7qF5Gt7ATX OQsu7TMre+FQ7GV0rcIfIPOum6PJqCZMiSoJ1teDbemopyLvLApKDMJ9mMg9RnRzh1cb 9thQ== X-Gm-Message-State: AJIora+7E3JcypmjeVgrNNha8+ZtTobOAsBK5HrBnF8moNvtgNtiLd3O 8Wr6F7g4tWvkVQagmkV1gDpGoA== X-Google-Smtp-Source: AGRyM1tlNmSH+B4wMw15/nh8eWfTqZLqfQBVqo7VMlmTROC9pe6veZ5fGU6Xoj6Mey5fT0e79FhFvQ== X-Received: by 2002:a05:6871:611:b0:10c:4bc0:88b9 with SMTP id w17-20020a056871061100b0010c4bc088b9mr228790oan.81.1657235775988; Thu, 07 Jul 2022 16:16:15 -0700 (PDT) Received: from fedora.attlocal.net (69-109-179-158.lightspeed.dybhfl.sbcglobal.net. [69.109.179.158]) by smtp.gmail.com with ESMTPSA id cg10-20020a056830630a00b006190efaf118sm2177606otb.66.2022.07.07.16.16.15 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 07 Jul 2022 16:16:15 -0700 (PDT) From: William Breathitt Gray To: linus.walleij@linaro.org, brgl@bgdev.pl Cc: linux-gpio@vger.kernel.org, linux-kernel@vger.kernel.org, William Breathitt Gray , Fred Eckert , John Hentges , Jay Dolan Subject: [PATCH v2 1/6] gpio: i8255: Introduce the i8255 module Date: Thu, 7 Jul 2022 14:10:03 -0400 Message-Id: <6be749842a4ad629c8697101f170dc7e425ae082.1657216200.git.william.gray@linaro.org> X-Mailer: git-send-email 2.36.1 In-Reply-To: References: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" Exposes consumer functions providing support for Intel 8255 Programmable Peripheral Interface devices. A CONFIG_GPIO_I8255 Kconfig option is introduced; modules wanting access to these functions should select this Kconfig option. Tested-by: Fred Eckert Cc: John Hentges Cc: Jay Dolan Signed-off-by: William Breathitt Gray --- MAINTAINERS | 6 + drivers/gpio/Kconfig | 3 + drivers/gpio/Makefile | 1 + drivers/gpio/gpio-i8255.c | 249 +++++++++++++++++++++++++++++++++++++ include/linux/gpio/i8255.h | 34 +++++ 5 files changed, 293 insertions(+) create mode 100644 drivers/gpio/gpio-i8255.c create mode 100644 include/linux/gpio/i8255.h diff --git a/MAINTAINERS b/MAINTAINERS index a6d3bd9d2a8d..c4ae792a8a43 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -9799,6 +9799,12 @@ L: linux-fbdev@vger.kernel.org S: Maintained F: drivers/video/fbdev/i810/ =20 +INTEL 8255 GPIO DRIVER +M: William Breathitt Gray +L: linux-gpio@vger.kernel.org +S: Maintained +F: drivers/gpio/gpio-i8255.c + INTEL ASoC DRIVERS M: Cezary Rojewski M: Pierre-Louis Bossart diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index b01961999ced..5cbe93330213 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -829,6 +829,9 @@ endmenu menu "Port-mapped I/O GPIO drivers" depends on X86 # Unconditional I/O space access =20 +config GPIO_I8255 + tristate + config GPIO_104_DIO_48E tristate "ACCES 104-DIO-48E GPIO support" depends on PC104 diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile index 14352f6dfe8e..06057e127949 100644 --- a/drivers/gpio/Makefile +++ b/drivers/gpio/Makefile @@ -67,6 +67,7 @@ obj-$(CONFIG_GPIO_GW_PLD) +=3D gpio-gw-pld.o obj-$(CONFIG_GPIO_HISI) +=3D gpio-hisi.o obj-$(CONFIG_GPIO_HLWD) +=3D gpio-hlwd.o obj-$(CONFIG_HTC_EGPIO) +=3D gpio-htc-egpio.o +obj-$(CONFIG_GPIO_I8255) +=3D gpio-i8255.o obj-$(CONFIG_GPIO_ICH) +=3D gpio-ich.o obj-$(CONFIG_GPIO_IDT3243X) +=3D gpio-idt3243x.o obj-$(CONFIG_GPIO_IOP) +=3D gpio-iop.o diff --git a/drivers/gpio/gpio-i8255.c b/drivers/gpio/gpio-i8255.c new file mode 100644 index 000000000000..ef43312015f4 --- /dev/null +++ b/drivers/gpio/gpio-i8255.c @@ -0,0 +1,249 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Intel 8255 Programmable Peripheral Interface + * Copyright (C) 2022 William Breathitt Gray + */ +#include +#include +#include +#include +#include +#include +#include + +#define I8255_CONTROL_PORTCLOWER_DIRECTION BIT(0) +#define I8255_CONTROL_PORTB_DIRECTION BIT(1) +#define I8255_CONTROL_PORTCUPPER_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(const struct i8255 __iomem *const ppi, + const unsigned long io_port, const unsigned long mask) +{ + const unsigned long group =3D io_port / 3; + const unsigned long ppi_port =3D io_port % 3; + + return ioread8(&ppi[group].port[ppi_port]) & mask; +} + +static u8 i8255_direction_mask(const unsigned long offset) +{ + const unsigned long io_port =3D offset / 8; + const unsigned long ppi_port =3D 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 (offset % 8 > 3) + return I8255_CONTROL_PORTCUPPER_DIRECTION; + return I8255_CONTROL_PORTCLOWER_DIRECTION; + default: + /* Should never reach this path */ + return 0; + } +} + +static void i8255_set_port(struct i8255 __iomem *const ppi, + const unsigned long io_port, + const unsigned long io_mask, + const unsigned long bit_mask) +{ + const unsigned long group =3D io_port / 3; + const unsigned long ppi_port =3D io_port % 3; + unsigned long out_state; + + out_state =3D ioread8(&ppi[group].port[ppi_port]); + out_state &=3D ~io_mask; + out_state |=3D bit_mask; + + iowrite8(out_state, &ppi[group].port[ppi_port]); +} + +/** + * i8255_direction_input - configure signal offset as input + * @ppi: Intel 8255 Programmable Peripheral Interface groups + * @control_state: control register states of the respective PPI groups + * @offset: signal offset to configure as input + * + * Configures a signal @offset as input for the respective Intel 8255 + * Programmable Peripheral Interface (@ppi) groups. The @control_state val= ues + * are updated to reflect the new configuration. + */ +void i8255_direction_input(struct i8255 __iomem *const ppi, + u8 *const control_state, const unsigned long offset) +{ + const unsigned long io_port =3D offset / 8; + const unsigned long group =3D io_port / 3; + + control_state[group] |=3D I8255_CONTROL_MODE_SET; + control_state[group] |=3D i8255_direction_mask(offset); + + iowrite8(control_state[group], &ppi[group].control); +} +EXPORT_SYMBOL_GPL(i8255_direction_input); + +/** + * i8255_direction_output - configure signal offset as output + * @control_state: control register states of the respective PPI groups + * @ppi: Intel 8255 Programmable Peripheral Interface groups + * @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) groups and sets the respective + * signal output to the desired @value. The @control_state values are upda= ted to + * reflect the new configuration. + */ +void i8255_direction_output(struct i8255 __iomem *const ppi, + u8 *const control_state, const unsigned long offset, + const unsigned long value) +{ + const unsigned long io_port =3D offset / 8; + const unsigned long group =3D io_port / 3; + + control_state[group] |=3D I8255_CONTROL_MODE_SET; + control_state[group] &=3D ~i8255_direction_mask(offset); + + iowrite8(control_state[group], &ppi[group].control); + i8255_set(ppi, offset, value); +} +EXPORT_SYMBOL_GPL(i8255_direction_output); + +/** + * i8255_get - get signal value at signal offset + * @ppi: Intel 8255 Programmable Peripheral Interface groups + * @offset: offset of signal to get + * + * Returns the signal value (0=3Dlow, 1=3Dhigh) for the signal at @offset = for the + * respective Intel 8255 Programmable Peripheral Interface (@ppi) groups. + */ +int i8255_get(const struct i8255 __iomem *const ppi, const unsigned long o= ffset) +{ + const unsigned long io_port =3D offset / 8; + const unsigned long offset_mask =3D BIT(offset % 8); + + return !!i8255_get_port(ppi, io_port, offset_mask); +} +EXPORT_SYMBOL_GPL(i8255_get); + +/** + * i8255_get_direction - get the I/O direction for a signal offset + * @control_state: control register states of the respective PPI groups + * @offset: offset of signal to get direction + * + * Returns the signal direction (0=3Doutput, 1=3Dinput) for the signal at = @offset. + * groups. + */ +int i8255_get_direction(const u8 *const control_state, + const unsigned long offset) +{ + const unsigned long io_port =3D offset / 8; + const unsigned long group =3D io_port / 3; + + return !!(control_state[group] & i8255_direction_mask(offset)); +} +EXPORT_SYMBOL_GPL(i8255_get_direction); + +/** + * i8255_get_multiple - get multiple signal values at multiple signal offs= ets + * @ppi: Intel 8255 Programmable Peripheral Interface groups + * @mask: mask of signals to get + * @bits: bitmap to store signal values + * @ngpio: number of GPIO signals of the respective PPI groups + * + * Stores in @bits the values (0=3Dlow, 1=3Dhigh) for the signals defined = by @mask + * for the respective Intel 8255 Programmable Peripheral Interface (@ppi) + * groups. + */ +void i8255_get_multiple(const struct i8255 __iomem *const ppi, + const unsigned long *const mask, + unsigned long *const bits, const unsigned long ngpio) +{ + unsigned long offset; + unsigned long gpio_mask; + unsigned long io_port; + unsigned long port_state; + + bitmap_zero(bits, ngpio); + + for_each_set_clump8(offset, gpio_mask, mask, ngpio) { + io_port =3D offset / 8; + port_state =3D i8255_get_port(ppi, io_port, gpio_mask); + + bitmap_set_value8(bits, port_state, offset); + } +} +EXPORT_SYMBOL_GPL(i8255_get_multiple); + +/** + * i8255_mode0_output - configure all PPI ports to MODE 0 output mode + * @ppi: Intel 8255 Programmable Peripheral Interface group + * + * Configures all Intel 8255 Programmable Peripheral Interface (@ppi) port= s 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_GPL(i8255_mode0_output); + +/** + * i8255_set - set signal value at signal offset + * @ppi: Intel 8255 Programmable Peripheral Interface groups + * @offset: offset of signal to set + * @value: value of signal to set + * + * Assigns output @value for the signal at @offset for the respective Inte= l 8255 + * Programmable Peripheral Interface (@ppi) groups. + */ +void i8255_set(struct i8255 __iomem *const ppi, const unsigned long offset, + const unsigned long value) +{ + const unsigned long io_port =3D offset / 8; + const unsigned long port_offset =3D offset % 8; + const unsigned long offset_mask =3D BIT(port_offset); + const unsigned long bit_mask =3D value << port_offset; + + i8255_set_port(ppi, io_port, offset_mask, bit_mask); +} +EXPORT_SYMBOL_GPL(i8255_set); + +/** + * i8255_set_multiple - set signal values at multiple signal offsets + * @ppi: Intel 8255 Programmable Peripheral Interface groups + * @mask: mask of signals to set + * @bits: bitmap of signal output values + * @ngpio: number of GPIO signals of the respective PPI groups + * + * Assigns output values defined by @bits for the signals defined by @mask= for + * the respective Intel 8255 Programmable Peripheral Interface (@ppi) grou= ps. + */ +void i8255_set_multiple(struct i8255 __iomem *const ppi, + const unsigned long *const mask, + const unsigned long *const bits, + const unsigned long ngpio) +{ + unsigned long offset; + unsigned long gpio_mask; + unsigned long bit_mask; + unsigned long io_port; + + for_each_set_clump8(offset, gpio_mask, mask, ngpio) { + bit_mask =3D bitmap_get_value8(bits, offset) & gpio_mask; + io_port =3D offset / 8; + i8255_set_port(ppi, io_port, gpio_mask, bit_mask); + } +} +EXPORT_SYMBOL_GPL(i8255_set_multiple); + +MODULE_AUTHOR("William Breathitt Gray"); +MODULE_DESCRIPTION("Intel 8255 Programmable Peripheral Interface"); +MODULE_LICENSE("GPL"); diff --git a/include/linux/gpio/i8255.h b/include/linux/gpio/i8255.h new file mode 100644 index 000000000000..7ddcf7fcd1dd --- /dev/null +++ b/include/linux/gpio/i8255.h @@ -0,0 +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; +}; + +void i8255_direction_input(struct i8255 __iomem *ppi, u8 *control_state, + unsigned long offset); +void i8255_direction_output(struct i8255 __iomem *ppi, u8 *control_state, + unsigned long offset, unsigned long value); +int i8255_get(const struct i8255 __iomem *ppi, unsigned long offset); +int i8255_get_direction(const u8 *control_state, unsigned long offset); +void i8255_get_multiple(const 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, unsigned long offset, + unsigned long value); +void i8255_set_multiple(struct i8255 __iomem *ppi, const unsigned long *ma= sk, + const unsigned long *bits, unsigned long ngpio); + +#endif /* _I8255_H_ */ --=20 2.36.1 From nobody Sun Apr 19 02:19:41 2026 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 6894DC43334 for ; Thu, 7 Jul 2022 23:16:24 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S236898AbiGGXQW (ORCPT ); Thu, 7 Jul 2022 19:16:22 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:58200 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S236089AbiGGXQT (ORCPT ); Thu, 7 Jul 2022 19:16:19 -0400 Received: from mail-oa1-x29.google.com (mail-oa1-x29.google.com [IPv6:2001:4860:4864:20::29]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 900E7675B6 for ; Thu, 7 Jul 2022 16:16:17 -0700 (PDT) Received: by mail-oa1-x29.google.com with SMTP id 586e51a60fabf-10c0d96953fso13644974fac.0 for ; Thu, 07 Jul 2022 16:16:17 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=d/Pb3b9iq5ouKUw5SoagUHZIMdxbCTv5dMFA6mF6+0s=; b=GPRkQvDtbh0Q+qFT4lJstnsZrpZVfE7Fug7R22wnT2Nz547tj5WWrJLS7ea1pRJ5vm 7yzJYStQkqTSlKFtxForRQo7LH1osjKk9tVgx16UIronBOfQrsWfreHSDqOWrtBZIcBT QDbc6FVqR9ml4zMHd+kSUgx4fExxTOheNit6ey1bakaCufYZgD5HRJ6QNf+nRLgClH6B B3POWwUKSZhvnZY+d8FsD4CiSo8lGuydDFaOU8cLpIDb69W5Vv9rkxpAkT0amJlS+fGs J+hG0l5BwJXnf94KqMdHaWM8PLfDAPDp3fAqtnwzrjob7fhxiBn7tK+VlPjYFo5Tb9fH 8ieA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=d/Pb3b9iq5ouKUw5SoagUHZIMdxbCTv5dMFA6mF6+0s=; b=sdQepSXjN5LT/DsfAPyhHmW1aKcz1QoLHbF0EYxkevH1KyVAVeeslLvFhguSpcgQIF jIgAqHp3FabKXc2j7A1iJ+sSf9xSrCgnPlzBymBBUoiSnCPAE/vaD0K1ZnzCRvQMcW60 CizmzdqUwSh/ieUxHtvm/qiBBZMAskXobaMUwAY+ppzqHDrv97lHrHJ4nJYrB3YUmmeo SOwJ9ERDOMwUprm9ALe0NsuIN5+krkcD073NL7bvLeOtMSiy7Zi6VjNumpE/dU3FZGkc stqoItKUyGiB0n/V1x36Ii8G5dF0PGhk7fQMkvlCoIZPyLjq6k/Me1ylDC6Rs5Fto/hB 8ojQ== X-Gm-Message-State: AJIora/Azbo2mcOnXWIPCGBRbrPpQxYn8Wi2InJWtF5/J9b2CFIuvDuY 4DI/JpDuFhl/x8w9S5sxdnkOlBDz+yLpgglb X-Google-Smtp-Source: AGRyM1t1VZdbybprqCVI6BeITv+UBQgl8xz2bMmhnEZtvNnH8M7e7zgTTxP1X+Gd0z/s0csYaj8XJw== X-Received: by 2002:a05:6870:f603:b0:101:a202:42b2 with SMTP id ek3-20020a056870f60300b00101a20242b2mr4239960oab.221.1657235776878; Thu, 07 Jul 2022 16:16:16 -0700 (PDT) Received: from fedora.attlocal.net (69-109-179-158.lightspeed.dybhfl.sbcglobal.net. [69.109.179.158]) by smtp.gmail.com with ESMTPSA id cg10-20020a056830630a00b006190efaf118sm2177606otb.66.2022.07.07.16.16.16 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 07 Jul 2022 16:16:16 -0700 (PDT) From: William Breathitt Gray To: linus.walleij@linaro.org, brgl@bgdev.pl Cc: linux-gpio@vger.kernel.org, linux-kernel@vger.kernel.org, William Breathitt Gray , John Hentges , Jay Dolan Subject: [PATCH v2 2/6] gpio: 104-dio-48e: Implement and utilize register structures Date: Thu, 7 Jul 2022 14:10:04 -0400 Message-Id: <719ac333791525d3304e195478b0900c374daa4a.1657216200.git.william.gray@linaro.org> X-Mailer: git-send-email 2.36.1 In-Reply-To: References: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" Reduce magic numbers and improve code readability by implementing and utilizing named register data structures. The 104-DIO-48E device features an Intel 8255 compatible GPIO interface, so the i8255 GPIO module is selected and utilized as well. Cc: John Hentges Cc: Jay Dolan Signed-off-by: William Breathitt Gray --- drivers/gpio/Kconfig | 1 + drivers/gpio/gpio-104-dio-48e.c | 224 ++++++++++---------------------- 2 files changed, 69 insertions(+), 156 deletions(-) diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index 5cbe93330213..31546969f66a 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -837,6 +837,7 @@ config GPIO_104_DIO_48E depends on PC104 select ISA_BUS_API select GPIOLIB_IRQCHIP + select GPIO_I8255 help Enables GPIO support for the ACCES 104-DIO-48E series (104-DIO-48E, 104-DIO-24E). The base port addresses for the devices may be diff --git a/drivers/gpio/gpio-104-dio-48e.c b/drivers/gpio/gpio-104-dio-48= e.c index f118ad9bcd33..dab1fb44f295 100644 --- a/drivers/gpio/gpio-104-dio-48e.c +++ b/drivers/gpio/gpio-104-dio-48e.c @@ -6,11 +6,12 @@ * This driver supports the following ACCES devices: 104-DIO-48E and * 104-DIO-24E. */ -#include +#include #include #include #include #include +#include #include #include #include @@ -20,6 +21,7 @@ #include #include #include +#include =20 #define DIO48E_EXTENT 16 #define MAX_NUM_DIO48E max_num_isa_dev(DIO48E_EXTENT) @@ -33,34 +35,52 @@ static unsigned int irq[MAX_NUM_DIO48E]; module_param_hw_array(irq, uint, irq, NULL, 0); MODULE_PARM_DESC(irq, "ACCES 104-DIO-48E interrupt line numbers"); =20 +/** + * 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[2]; + u8 enable_buffer[2]; + u8 unused1; + u8 enable_interrupt; + u8 unused2; + u8 enable_counter; + u8 unused3; + u8 clear_interrupt; +}; + /** * struct dio48e_gpio - GPIO device private data structure - * @chip: instance of the gpio_chip - * @io_state: bit I/O state (whether bit is set to input or output) - * @out_state: output bits state - * @control: Control registers state - * @lock: synchronization lock to prevent I/O race conditions - * @base: base port address of the GPIO device - * @irq_mask: I/O bits affected by interrupts + * @chip: instance of the gpio_chip + * @control_state: Control registers state + * @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; - unsigned char io_state[6]; - unsigned char out_state[6]; - unsigned char control[2]; + u8 control_state[2]; raw_spinlock_t lock; - void __iomem *base; + struct dio48e_reg __iomem *reg; unsigned char irq_mask; }; =20 static int dio48e_gpio_get_direction(struct gpio_chip *chip, unsigned int = offset) { struct dio48e_gpio *const dio48egpio =3D gpiochip_get_data(chip); - const unsigned int port =3D offset / 8; - const unsigned int mask =3D BIT(offset % 8); =20 - if (dio48egpio->io_state[port] & mask) - return GPIO_LINE_DIRECTION_IN; + if (i8255_get_direction(dio48egpio->control_state, offset)) + return GPIO_LINE_DIRECTION_IN; =20 return GPIO_LINE_DIRECTION_OUT; } @@ -68,36 +88,12 @@ static int dio48e_gpio_get_direction(struct gpio_chip *= chip, unsigned int offset static int dio48e_gpio_direction_input(struct gpio_chip *chip, unsigned in= t offset) { struct dio48e_gpio *const dio48egpio =3D gpiochip_get_data(chip); - const unsigned int io_port =3D offset / 8; - const unsigned int control_port =3D io_port / 3; - void __iomem *const control_addr =3D dio48egpio->base + 3 + control_port = * 4; unsigned long flags; - unsigned int control; =20 raw_spin_lock_irqsave(&dio48egpio->lock, flags); =20 - /* Check if configuring Port C */ - if (io_port =3D=3D 2 || io_port =3D=3D 5) { - /* Port C can be configured by nibble */ - if (offset % 8 > 3) { - dio48egpio->io_state[io_port] |=3D 0xF0; - dio48egpio->control[control_port] |=3D BIT(3); - } else { - dio48egpio->io_state[io_port] |=3D 0x0F; - dio48egpio->control[control_port] |=3D BIT(0); - } - } else { - dio48egpio->io_state[io_port] |=3D 0xFF; - if (io_port =3D=3D 0 || io_port =3D=3D 3) - dio48egpio->control[control_port] |=3D BIT(4); - else - dio48egpio->control[control_port] |=3D BIT(1); - } - - control =3D BIT(7) | dio48egpio->control[control_port]; - iowrite8(control, control_addr); - control &=3D ~BIT(7); - iowrite8(control, control_addr); + i8255_direction_input(dio48egpio->reg->ppi, dio48egpio->control_state, + offset); =20 raw_spin_unlock_irqrestore(&dio48egpio->lock, flags); =20 @@ -108,46 +104,12 @@ static int dio48e_gpio_direction_output(struct gpio_c= hip *chip, unsigned int off int value) { struct dio48e_gpio *const dio48egpio =3D gpiochip_get_data(chip); - const unsigned int io_port =3D offset / 8; - const unsigned int control_port =3D io_port / 3; - const unsigned int mask =3D BIT(offset % 8); - void __iomem *const control_addr =3D dio48egpio->base + 3 + control_port = * 4; - const unsigned int out_port =3D (io_port > 2) ? io_port + 1 : io_port; unsigned long flags; - unsigned int control; =20 raw_spin_lock_irqsave(&dio48egpio->lock, flags); =20 - /* Check if configuring Port C */ - if (io_port =3D=3D 2 || io_port =3D=3D 5) { - /* Port C can be configured by nibble */ - if (offset % 8 > 3) { - dio48egpio->io_state[io_port] &=3D 0x0F; - dio48egpio->control[control_port] &=3D ~BIT(3); - } else { - dio48egpio->io_state[io_port] &=3D 0xF0; - dio48egpio->control[control_port] &=3D ~BIT(0); - } - } else { - dio48egpio->io_state[io_port] &=3D 0x00; - if (io_port =3D=3D 0 || io_port =3D=3D 3) - dio48egpio->control[control_port] &=3D ~BIT(4); - else - dio48egpio->control[control_port] &=3D ~BIT(1); - } - - if (value) - dio48egpio->out_state[io_port] |=3D mask; - else - dio48egpio->out_state[io_port] &=3D ~mask; - - control =3D BIT(7) | dio48egpio->control[control_port]; - iowrite8(control, control_addr); - - iowrite8(dio48egpio->out_state[io_port], dio48egpio->base + out_port); - - control &=3D ~BIT(7); - iowrite8(control, control_addr); + i8255_direction_output(dio48egpio->reg->ppi, dio48egpio->control_state, + offset, value); =20 raw_spin_unlock_irqrestore(&dio48egpio->lock, flags); =20 @@ -157,47 +119,16 @@ static int dio48e_gpio_direction_output(struct gpio_c= hip *chip, unsigned int off static int dio48e_gpio_get(struct gpio_chip *chip, unsigned int offset) { struct dio48e_gpio *const dio48egpio =3D gpiochip_get_data(chip); - const unsigned int port =3D offset / 8; - const unsigned int mask =3D BIT(offset % 8); - const unsigned int in_port =3D (port > 2) ? port + 1 : port; - unsigned long flags; - unsigned int port_state; - - raw_spin_lock_irqsave(&dio48egpio->lock, flags); - - /* ensure that GPIO is set for input */ - if (!(dio48egpio->io_state[port] & mask)) { - raw_spin_unlock_irqrestore(&dio48egpio->lock, flags); - return -EINVAL; - } =20 - port_state =3D ioread8(dio48egpio->base + in_port); - - raw_spin_unlock_irqrestore(&dio48egpio->lock, flags); - - return !!(port_state & mask); + return i8255_get(dio48egpio->reg->ppi, offset); } =20 -static const size_t ports[] =3D { 0, 1, 2, 4, 5, 6 }; - static int dio48e_gpio_get_multiple(struct gpio_chip *chip, unsigned long = *mask, unsigned long *bits) { struct dio48e_gpio *const dio48egpio =3D gpiochip_get_data(chip); - unsigned long offset; - unsigned long gpio_mask; - void __iomem *port_addr; - unsigned long port_state; - - /* clear bits array to a clean slate */ - bitmap_zero(bits, chip->ngpio); =20 - for_each_set_clump8(offset, gpio_mask, mask, ARRAY_SIZE(ports) * 8) { - port_addr =3D dio48egpio->base + ports[offset / 8]; - port_state =3D ioread8(port_addr) & gpio_mask; - - bitmap_set_value8(bits, port_state, offset); - } + i8255_get_multiple(dio48egpio->reg->ppi, mask, bits, chip->ngpio); =20 return 0; } @@ -205,19 +136,11 @@ static int dio48e_gpio_get_multiple(struct gpio_chip = *chip, unsigned long *mask, static void dio48e_gpio_set(struct gpio_chip *chip, unsigned int offset, i= nt value) { struct dio48e_gpio *const dio48egpio =3D gpiochip_get_data(chip); - const unsigned int port =3D offset / 8; - const unsigned int mask =3D BIT(offset % 8); - const unsigned int out_port =3D (port > 2) ? port + 1 : port; unsigned long flags; =20 raw_spin_lock_irqsave(&dio48egpio->lock, flags); =20 - if (value) - dio48egpio->out_state[port] |=3D mask; - else - dio48egpio->out_state[port] &=3D ~mask; - - iowrite8(dio48egpio->out_state[port], dio48egpio->base + out_port); + i8255_set(dio48egpio->reg->ppi, offset, value); =20 raw_spin_unlock_irqrestore(&dio48egpio->lock, flags); } @@ -226,28 +149,13 @@ static void dio48e_gpio_set_multiple(struct gpio_chip= *chip, unsigned long *mask, unsigned long *bits) { struct dio48e_gpio *const dio48egpio =3D gpiochip_get_data(chip); - unsigned long offset; - unsigned long gpio_mask; - size_t index; - void __iomem *port_addr; - unsigned long bitmask; unsigned long flags; =20 - for_each_set_clump8(offset, gpio_mask, mask, ARRAY_SIZE(ports) * 8) { - index =3D offset / 8; - port_addr =3D dio48egpio->base + ports[index]; - - bitmask =3D bitmap_get_value8(bits, offset) & gpio_mask; - - raw_spin_lock_irqsave(&dio48egpio->lock, flags); + raw_spin_lock_irqsave(&dio48egpio->lock, flags); =20 - /* update output state data and set device gpio register */ - dio48egpio->out_state[index] &=3D ~gpio_mask; - dio48egpio->out_state[index] |=3D bitmask; - iowrite8(dio48egpio->out_state[index], port_addr); + i8255_set_multiple(dio48egpio->reg->ppi, mask, bits, chip->ngpio); =20 - raw_spin_unlock_irqrestore(&dio48egpio->lock, flags); - } + raw_spin_unlock_irqrestore(&dio48egpio->lock, flags); } =20 static void dio48e_irq_ack(struct irq_data *data) @@ -274,7 +182,7 @@ static void dio48e_irq_mask(struct irq_data *data) =20 if (!dio48egpio->irq_mask) /* disable interrupts */ - ioread8(dio48egpio->base + 0xB); + ioread8(&dio48egpio->reg->enable_interrupt); =20 raw_spin_unlock_irqrestore(&dio48egpio->lock, flags); } @@ -294,8 +202,8 @@ static void dio48e_irq_unmask(struct irq_data *data) =20 if (!dio48egpio->irq_mask) { /* enable interrupts */ - iowrite8(0x00, dio48egpio->base + 0xF); - iowrite8(0x00, dio48egpio->base + 0xB); + iowrite8(0x00, &dio48egpio->reg->clear_interrupt); + iowrite8(0x00, &dio48egpio->reg->enable_interrupt); } =20 if (offset =3D=3D 19) @@ -341,7 +249,7 @@ static irqreturn_t dio48e_irq_handler(int irq, void *de= v_id) =20 raw_spin_lock(&dio48egpio->lock); =20 - iowrite8(0x00, dio48egpio->base + 0xF); + iowrite8(0x00, &dio48egpio->reg->clear_interrupt); =20 raw_spin_unlock(&dio48egpio->lock); =20 @@ -373,11 +281,25 @@ static int dio48e_irq_init_hw(struct gpio_chip *gc) struct dio48e_gpio *const dio48egpio =3D gpiochip_get_data(gc); =20 /* Disable IRQ by default */ - ioread8(dio48egpio->base + 0xB); + ioread8(&dio48egpio->reg->enable_interrupt); =20 return 0; } =20 +static void dio48e_init_ppi(struct i8255 __iomem *const ppi) +{ + const unsigned long ngpio =3D 24; + const unsigned long mask =3D GENMASK(ngpio - 1, 0); + const unsigned long bits =3D 0; + unsigned long i; + + /* Initialize all GPIO to output 0 */ + for (i =3D 0; i < 2; i++) { + i8255_mode0_output(&ppi[i]); + i8255_set_multiple(&ppi[i], &mask, &bits, ngpio); + } +} + static int dio48e_probe(struct device *dev, unsigned int id) { struct dio48e_gpio *dio48egpio; @@ -395,8 +317,8 @@ static int dio48e_probe(struct device *dev, unsigned in= t id) return -EBUSY; } =20 - dio48egpio->base =3D devm_ioport_map(dev, base[id], DIO48E_EXTENT); - if (!dio48egpio->base) + dio48egpio->reg =3D devm_ioport_map(dev, base[id], DIO48E_EXTENT); + if (!dio48egpio->reg) return -ENOMEM; =20 dio48egpio->chip.label =3D name; @@ -425,17 +347,7 @@ static int dio48e_probe(struct device *dev, unsigned i= nt id) =20 raw_spin_lock_init(&dio48egpio->lock); =20 - /* initialize all GPIO as output */ - iowrite8(0x80, dio48egpio->base + 3); - iowrite8(0x00, dio48egpio->base); - iowrite8(0x00, dio48egpio->base + 1); - iowrite8(0x00, dio48egpio->base + 2); - iowrite8(0x00, dio48egpio->base + 3); - iowrite8(0x80, dio48egpio->base + 7); - iowrite8(0x00, dio48egpio->base + 4); - iowrite8(0x00, dio48egpio->base + 5); - iowrite8(0x00, dio48egpio->base + 6); - iowrite8(0x00, dio48egpio->base + 7); + dio48e_init_ppi(dio48egpio->reg->ppi); =20 err =3D devm_gpiochip_add_data(dev, &dio48egpio->chip, dio48egpio); if (err) { --=20 2.36.1 From nobody Sun Apr 19 02:19:41 2026 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 2D203C43334 for ; Thu, 7 Jul 2022 23:16:27 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S236917AbiGGXQZ (ORCPT ); Thu, 7 Jul 2022 19:16:25 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:58240 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S236800AbiGGXQT (ORCPT ); Thu, 7 Jul 2022 19:16:19 -0400 Received: from mail-oa1-x2d.google.com (mail-oa1-x2d.google.com [IPv6:2001:4860:4864:20::2d]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 617E4675B4 for ; Thu, 7 Jul 2022 16:16:18 -0700 (PDT) Received: by mail-oa1-x2d.google.com with SMTP id 586e51a60fabf-f2a4c51c45so27231741fac.9 for ; Thu, 07 Jul 2022 16:16:18 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=S4fvya9qVEYx2ENN6AM5NhnuLR4II7vSeVqvvYlfIvg=; b=M2+SG47nS9M/dDCrbAC7nobT3jBS6tjydumDAh1rT0zKXdN6uv7dyilcTaCEEb1IbH /a0+YmuQpXVBvIXW3BgjAg1qzqRw2q5Ep0aYp2AqdnFghqYt3MwnSldQPdEpTTmzPkIw H4DkJTqbqOfBimIEwRa6u5fM9IwhY8Xb2XANmpk94z6ejHoymSr/1O/wM1Cmb1C+8L1n tDFV27gsDh2PNOuKwmLi+rufZjzIG+6n5YBcZo0PgiwCnSh3kBReVBasE0uNvp1cG6Xw 2tFawMYR69AeAagZnQylt4kh5Q/LHhIm6Xpa3NUTm8d635FMKdqoub79iv7GXxTnWkdO tAHQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=S4fvya9qVEYx2ENN6AM5NhnuLR4II7vSeVqvvYlfIvg=; b=c2A9uVLxJbRUwB83swhavIqQzusd9+G1MKMnuv4IQ7RIssu3V1ZwJknF/vFrzihl+r CaP3lrJPFVyzh9oCMXIOzkS64FXNa1biJrjZZ2EIc2tj+9ACLvZ3FJcGGhjd+cAv1o33 NhP6kUfj05rpCzakK3Lt6cFFpoAp8o6x7bazRuW8ZLIxAuwFSIjiH9lN4P2JDgzHeA7o 23+W50FZK1ViL2Wgx3PVq67Ln2mVGdazaJiVNwKfdkLjKIKfla71AxvzI5nfP9JtCX5V 73DcvIN74aPJ4pVneEKtcLKaGbzKmJOXrXQ+XqVEQn3wO2C0XBjehbgaZD4eWEQ9ESjb fGyQ== X-Gm-Message-State: AJIora+hzUV7IJIx7m+1EVdwh67S0tQdsuVHLHZffcLAtdwz/dMJwwMH 4O1BEcHrIWynW3A/jLVBS8HvD8REd5ifyIjt X-Google-Smtp-Source: AGRyM1tIF/4SgPIy80RniO9hlz0g67NTLH5CCYBIhdQ8hgfMwqGdLzjyiOXHCXkfVRWRBis63VwlmA== X-Received: by 2002:a05:6870:b60e:b0:e9:35aa:3cb8 with SMTP id cm14-20020a056870b60e00b000e935aa3cb8mr203724oab.249.1657235777740; Thu, 07 Jul 2022 16:16:17 -0700 (PDT) Received: from fedora.attlocal.net (69-109-179-158.lightspeed.dybhfl.sbcglobal.net. [69.109.179.158]) by smtp.gmail.com with ESMTPSA id cg10-20020a056830630a00b006190efaf118sm2177606otb.66.2022.07.07.16.16.17 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 07 Jul 2022 16:16:17 -0700 (PDT) From: William Breathitt Gray To: linus.walleij@linaro.org, brgl@bgdev.pl Cc: linux-gpio@vger.kernel.org, linux-kernel@vger.kernel.org, William Breathitt Gray , John Hentges , Jay Dolan Subject: [PATCH v2 3/6] gpio: 104-idi-48: Implement and utilize register structures Date: Thu, 7 Jul 2022 14:10:05 -0400 Message-Id: <29278ba7d6b22c295fce8dcfe162553ed719bac7.1657216200.git.william.gray@linaro.org> X-Mailer: git-send-email 2.36.1 In-Reply-To: References: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" Reduce magic numbers and improve code readability by implementing and utilizing named register data structures. The 104-IDI-48 device features an Intel 8255 compatible GPIO interface, so the i8255 GPIO module is selected and utilized as well. Cc: John Hentges Cc: Jay Dolan Signed-off-by: William Breathitt Gray --- drivers/gpio/Kconfig | 1 + drivers/gpio/gpio-104-idi-48.c | 123 +++++++++++++-------------------- 2 files changed, 50 insertions(+), 74 deletions(-) diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index 31546969f66a..0ae818d548bb 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -861,6 +861,7 @@ config GPIO_104_IDI_48 depends on PC104 select ISA_BUS_API select GPIOLIB_IRQCHIP + select GPIO_I8255 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 9521ece3ebef..7c8ae95237e6 100644 --- a/drivers/gpio/gpio-104-idi-48.c +++ b/drivers/gpio/gpio-104-idi-48.c @@ -6,11 +6,11 @@ * This driver supports the following ACCES devices: 104-IDI-48A, * 104-IDI-48AC, 104-IDI-48B, and 104-IDI-48BC. */ -#include #include #include #include #include +#include #include #include #include @@ -20,6 +20,7 @@ #include #include #include +#include =20 #define IDI_48_EXTENT 8 #define MAX_NUM_IDI_48 max_num_isa_dev(IDI_48_EXTENT) @@ -33,13 +34,28 @@ static unsigned int irq[MAX_NUM_IDI_48]; module_param_hw_array(irq, uint, irq, NULL, 0); MODULE_PARM_DESC(irq, "ACCES 104-IDI-48 interrupt line numbers"); =20 +/** + * 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; +}; + /** * struct idi_48_gpio - GPIO device private data structure * @chip: instance of the gpio_chip * @lock: synchronization lock to prevent I/O race conditions * @ack_lock: synchronization lock to prevent IRQ handler race conditions * @irq_mask: input bits affected by interrupts - * @base: base port address of the GPIO device + * @reg: I/O address offset for the device registers * @cos_enb: Change-Of-State IRQ enable boundaries mask */ struct idi_48_gpio { @@ -47,7 +63,7 @@ struct idi_48_gpio { raw_spinlock_t lock; spinlock_t ack_lock; unsigned char irq_mask[6]; - void __iomem *base; + struct idi_48_reg __iomem *reg; unsigned char cos_enb; }; =20 @@ -64,42 +80,18 @@ static int idi_48_gpio_direction_input(struct gpio_chip= *chip, unsigned offset) static int idi_48_gpio_get(struct gpio_chip *chip, unsigned offset) { struct idi_48_gpio *const idi48gpio =3D gpiochip_get_data(chip); - unsigned i; - static const unsigned int register_offset[6] =3D { 0, 1, 2, 4, 5, 6 }; - void __iomem *port_addr; - unsigned mask; - - for (i =3D 0; i < 48; i +=3D 8) - if (offset < i + 8) { - port_addr =3D idi48gpio->base + register_offset[i / 8]; - mask =3D BIT(offset - i); + const void __iomem *const ppi =3D idi48gpio->reg; =20 - return !!(ioread8(port_addr) & mask); - } - - /* The following line should never execute since offset < 48 */ - return 0; + return i8255_get(ppi, offset); } =20 static int idi_48_gpio_get_multiple(struct gpio_chip *chip, unsigned long = *mask, unsigned long *bits) { struct idi_48_gpio *const idi48gpio =3D gpiochip_get_data(chip); - unsigned long offset; - unsigned long gpio_mask; - static const size_t ports[] =3D { 0, 1, 2, 4, 5, 6 }; - void __iomem *port_addr; - unsigned long port_state; - - /* clear bits array to a clean slate */ - bitmap_zero(bits, chip->ngpio); + const void __iomem *const ppi =3D idi48gpio->reg; =20 - for_each_set_clump8(offset, gpio_mask, mask, ARRAY_SIZE(ports) * 8) { - port_addr =3D idi48gpio->base + ports[offset / 8]; - port_state =3D ioread8(port_addr) & gpio_mask; - - bitmap_set_value8(bits, port_state, offset); - } + i8255_get_multiple(ppi, mask, bits, chip->ngpio); =20 return 0; } @@ -113,30 +105,21 @@ static void idi_48_irq_mask(struct irq_data *data) struct gpio_chip *chip =3D irq_data_get_irq_chip_data(data); struct idi_48_gpio *const idi48gpio =3D gpiochip_get_data(chip); const unsigned offset =3D irqd_to_hwirq(data); - unsigned i; - unsigned mask; - unsigned boundary; + const unsigned long boundary =3D offset / 8; + const unsigned long mask =3D BIT(offset % 8); unsigned long flags; =20 - for (i =3D 0; i < 48; i +=3D 8) - if (offset < i + 8) { - mask =3D BIT(offset - i); - boundary =3D i / 8; - - idi48gpio->irq_mask[boundary] &=3D ~mask; - - if (!idi48gpio->irq_mask[boundary]) { - idi48gpio->cos_enb &=3D ~BIT(boundary); - - raw_spin_lock_irqsave(&idi48gpio->lock, flags); + idi48gpio->irq_mask[boundary] &=3D ~mask; =20 - iowrite8(idi48gpio->cos_enb, idi48gpio->base + 7); + /* Exit early if there are still input lines with IRQ unmasked */ + if (idi48gpio->irq_mask[boundary]) + return; =20 - raw_spin_unlock_irqrestore(&idi48gpio->lock, flags); - } + idi48gpio->cos_enb &=3D ~BIT(boundary); =20 - return; - } + raw_spin_lock_irqsave(&idi48gpio->lock, flags); + iowrite8(idi48gpio->cos_enb, &idi48gpio->reg->irq); + raw_spin_unlock_irqrestore(&idi48gpio->lock, flags); } =20 static void idi_48_irq_unmask(struct irq_data *data) @@ -144,32 +127,24 @@ static void idi_48_irq_unmask(struct irq_data *data) struct gpio_chip *chip =3D irq_data_get_irq_chip_data(data); struct idi_48_gpio *const idi48gpio =3D gpiochip_get_data(chip); const unsigned offset =3D irqd_to_hwirq(data); - unsigned i; - unsigned mask; - unsigned boundary; + const unsigned long boundary =3D offset / 8; + const unsigned long mask =3D BIT(offset % 8); unsigned prev_irq_mask; unsigned long flags; =20 - for (i =3D 0; i < 48; i +=3D 8) - if (offset < i + 8) { - mask =3D BIT(offset - i); - boundary =3D i / 8; - prev_irq_mask =3D idi48gpio->irq_mask[boundary]; - - idi48gpio->irq_mask[boundary] |=3D mask; + prev_irq_mask =3D idi48gpio->irq_mask[boundary]; =20 - if (!prev_irq_mask) { - idi48gpio->cos_enb |=3D BIT(boundary); + idi48gpio->irq_mask[boundary] |=3D mask; =20 - raw_spin_lock_irqsave(&idi48gpio->lock, flags); + /* Exit early if IRQ was already unmasked for this boundary */ + if (prev_irq_mask) + return; =20 - iowrite8(idi48gpio->cos_enb, idi48gpio->base + 7); + idi48gpio->cos_enb |=3D BIT(boundary); =20 - raw_spin_unlock_irqrestore(&idi48gpio->lock, flags); - } - - return; - } + raw_spin_lock_irqsave(&idi48gpio->lock, flags); + iowrite8(idi48gpio->cos_enb, &idi48gpio->reg->irq); + raw_spin_unlock_irqrestore(&idi48gpio->lock, flags); } =20 static int idi_48_irq_set_type(struct irq_data *data, unsigned flow_type) @@ -204,7 +179,7 @@ static irqreturn_t idi_48_irq_handler(int irq, void *de= v_id) =20 raw_spin_lock(&idi48gpio->lock); =20 - cos_status =3D ioread8(idi48gpio->base + 7); + cos_status =3D ioread8(&idi48gpio->reg->irq); =20 raw_spin_unlock(&idi48gpio->lock); =20 @@ -250,8 +225,8 @@ static int idi_48_irq_init_hw(struct gpio_chip *gc) struct idi_48_gpio *const idi48gpio =3D gpiochip_get_data(gc); =20 /* Disable IRQ by default */ - iowrite8(0, idi48gpio->base + 7); - ioread8(idi48gpio->base + 7); + iowrite8(0, &idi48gpio->reg->irq); + ioread8(&idi48gpio->reg->irq); =20 return 0; } @@ -273,8 +248,8 @@ static int idi_48_probe(struct device *dev, unsigned in= t id) return -EBUSY; } =20 - idi48gpio->base =3D devm_ioport_map(dev, base[id], IDI_48_EXTENT); - if (!idi48gpio->base) + idi48gpio->reg =3D devm_ioport_map(dev, base[id], IDI_48_EXTENT); + if (!idi48gpio->reg) return -ENOMEM; =20 idi48gpio->chip.label =3D name; --=20 2.36.1 From nobody Sun Apr 19 02:19:41 2026 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id D14A7C433EF for ; Thu, 7 Jul 2022 23:16:42 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S236929AbiGGXQk (ORCPT ); Thu, 7 Jul 2022 19:16:40 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:58292 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S236887AbiGGXQV (ORCPT ); Thu, 7 Jul 2022 19:16:21 -0400 Received: from mail-oa1-x36.google.com (mail-oa1-x36.google.com [IPv6:2001:4860:4864:20::36]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 45854675AC for ; Thu, 7 Jul 2022 16:16:19 -0700 (PDT) Received: by mail-oa1-x36.google.com with SMTP id 586e51a60fabf-10bffc214ffso16548030fac.1 for ; Thu, 07 Jul 2022 16:16:19 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=fjvbHRrPgO0OHIXtBUt12TCrI5NuVCxsdmni+NXCTQg=; b=Y6jpyAv/t4HTC3nx1cZP6WPJj4R+BpV6GFSDJ5wViTsdK3HvLvOcl0bC6+5aSMx+l1 GZ916o+WylbiUPzLB/EkPowUZiglFn+GAjEQ9NTkat9ltt6nKnwKjmPWkPnFfAXM2SvS 5O7pIWZBe0ceDhlPi/iGgzdYbC6nxu1G4RGeXHcze7xX+qnxnpTWNPMSWqLMR2kLMt5S yDFQr2t6LelfY4NJynIohZvtYPd00KU8dp/QZfbxYa/ly7dZJ7qS8Y5Iqlyr2180cOie nF28ib8M0vW1dvh8N3LfsqlL2lVkqxc82b9D7C/98yGDOkgjd98f55bAwqBmAFQ+vS55 nWJA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=fjvbHRrPgO0OHIXtBUt12TCrI5NuVCxsdmni+NXCTQg=; b=leViLvOAITkKcAcRv6qmlxMuMHp97EPW474x8G3K7u5aCwb+o89LbEH0T95WXD+MD+ VLcBMtIpTFiEpeDGA3dq9wlJZMQopYD29+m0MYETmaYs5vImaZobRUYpGMbBBj6VpLlf GzPKPjAQWEMiEleK9LM/xHHXsWLi2La6Ut72qcDYw1nghryiBhUHVqDfpNR3M3jvWGhR VNkxmLmut00cjPOlqkxogx/RYboqPYTYjRcOvrthpZ++zh1TziUk06EXokbwtnLcWWDK xVAXhWtOsRt/GFtvM66CrkhKWauTueN+KRRKqbeRGcZpRYpT6rPiS03sxp8eGpKK7Wc9 BOiw== X-Gm-Message-State: AJIora8cdNnM1CTy5z/M8eb9n+tY8yjePC7WHLD3Faq5Pckpk5tmJ0qe +5RjIn8OLTORBATucnxVdPXYuQ== X-Google-Smtp-Source: AGRyM1ueSZlZFeXOHSgxDgr/CJ73K1HQll+ixQ78PpQi54/X3X844iEGwpkWreEUhfPkn2ajqodqww== X-Received: by 2002:a05:6870:2403:b0:10b:f512:a5b4 with SMTP id n3-20020a056870240300b0010bf512a5b4mr226064oap.164.1657235778541; Thu, 07 Jul 2022 16:16:18 -0700 (PDT) Received: from fedora.attlocal.net (69-109-179-158.lightspeed.dybhfl.sbcglobal.net. [69.109.179.158]) by smtp.gmail.com with ESMTPSA id cg10-20020a056830630a00b006190efaf118sm2177606otb.66.2022.07.07.16.16.17 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 07 Jul 2022 16:16:18 -0700 (PDT) From: William Breathitt Gray To: linus.walleij@linaro.org, brgl@bgdev.pl Cc: linux-gpio@vger.kernel.org, linux-kernel@vger.kernel.org, William Breathitt Gray , Fred Eckert , John Hentges , Jay Dolan Subject: [PATCH v2 4/6] gpio: gpio-mm: Implement and utilize register structures Date: Thu, 7 Jul 2022 14:10:06 -0400 Message-Id: <4073fb96bdc35024cb661699800c4cb5e8cf0e5f.1657216200.git.william.gray@linaro.org> X-Mailer: git-send-email 2.36.1 In-Reply-To: References: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" Reduce magic numbers and improve code readability by implementing and utilizing named register data structures. The GPIO-MM device features an Intel 8255 compatible GPIO interface, so the i8255 GPIO module is selected and utilized as well. Tested-by: Fred Eckert Cc: John Hentges Cc: Jay Dolan Signed-off-by: William Breathitt Gray --- drivers/gpio/Kconfig | 1 + drivers/gpio/gpio-gpio-mm.c | 177 ++++++++---------------------------- 2 files changed, 38 insertions(+), 140 deletions(-) diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index 0ae818d548bb..20b118b3dd8a 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -882,6 +882,7 @@ config GPIO_GPIO_MM tristate "Diamond Systems GPIO-MM GPIO support" depends on PC104 select ISA_BUS_API + select GPIO_I8255 help Enables GPIO support for the Diamond Systems GPIO-MM and GPIO-MM-12. =20 diff --git a/drivers/gpio/gpio-gpio-mm.c b/drivers/gpio/gpio-gpio-mm.c index 097a06463d01..4bbf4e03f436 100644 --- a/drivers/gpio/gpio-gpio-mm.c +++ b/drivers/gpio/gpio-gpio-mm.c @@ -6,11 +6,12 @@ * This driver supports the following Diamond Systems devices: GPIO-MM and * GPIO-MM-12. */ -#include +#include #include #include #include #include +#include #include #include #include @@ -18,6 +19,7 @@ #include #include #include +#include =20 #define GPIOMM_EXTENT 8 #define MAX_NUM_GPIOMM max_num_isa_dev(GPIOMM_EXTENT) @@ -29,30 +31,24 @@ MODULE_PARM_DESC(base, "Diamond Systems GPIO-MM base ad= dresses"); =20 /** * struct gpiomm_gpio - GPIO device private data structure - * @chip: instance of the gpio_chip - * @io_state: bit I/O state (whether bit is set to input or output) - * @out_state: output bits state - * @control: Control registers state - * @lock: synchronization lock to prevent I/O race conditions - * @base: base port address of the GPIO device + * @chip: instance of the gpio_chip + * @control_state: Control registers state + * @lock: synchronization lock to prevent I/O race conditions + * @ppi: Programmable Peripheral Interface groups */ struct gpiomm_gpio { struct gpio_chip chip; - unsigned char io_state[6]; - unsigned char out_state[6]; - unsigned char control[2]; + u8 control_state[2]; spinlock_t lock; - void __iomem *base; + struct i8255 __iomem *ppi; }; =20 static int gpiomm_gpio_get_direction(struct gpio_chip *chip, unsigned int offset) { struct gpiomm_gpio *const gpiommgpio =3D gpiochip_get_data(chip); - const unsigned int port =3D offset / 8; - const unsigned int mask =3D BIT(offset % 8); =20 - if (gpiommgpio->io_state[port] & mask) + if (i8255_get_direction(gpiommgpio->control_state, offset)) return GPIO_LINE_DIRECTION_IN; =20 return GPIO_LINE_DIRECTION_OUT; @@ -62,33 +58,12 @@ static int gpiomm_gpio_direction_input(struct gpio_chip= *chip, unsigned int offset) { struct gpiomm_gpio *const gpiommgpio =3D gpiochip_get_data(chip); - const unsigned int io_port =3D offset / 8; - const unsigned int control_port =3D io_port / 3; unsigned long flags; - unsigned int control; =20 spin_lock_irqsave(&gpiommgpio->lock, flags); =20 - /* Check if configuring Port C */ - if (io_port =3D=3D 2 || io_port =3D=3D 5) { - /* Port C can be configured by nibble */ - if (offset % 8 > 3) { - gpiommgpio->io_state[io_port] |=3D 0xF0; - gpiommgpio->control[control_port] |=3D BIT(3); - } else { - gpiommgpio->io_state[io_port] |=3D 0x0F; - gpiommgpio->control[control_port] |=3D BIT(0); - } - } else { - gpiommgpio->io_state[io_port] |=3D 0xFF; - if (io_port =3D=3D 0 || io_port =3D=3D 3) - gpiommgpio->control[control_port] |=3D BIT(4); - else - gpiommgpio->control[control_port] |=3D BIT(1); - } - - control =3D BIT(7) | gpiommgpio->control[control_port]; - iowrite8(control, gpiommgpio->base + 3 + control_port*4); + i8255_direction_input(gpiommgpio->ppi, gpiommgpio->control_state, + offset); =20 spin_unlock_irqrestore(&gpiommgpio->lock, flags); =20 @@ -99,42 +74,12 @@ static int gpiomm_gpio_direction_output(struct gpio_chi= p *chip, unsigned int offset, int value) { struct gpiomm_gpio *const gpiommgpio =3D gpiochip_get_data(chip); - const unsigned int io_port =3D offset / 8; - const unsigned int control_port =3D io_port / 3; - const unsigned int mask =3D BIT(offset % 8); - const unsigned int out_port =3D (io_port > 2) ? io_port + 1 : io_port; unsigned long flags; - unsigned int control; =20 spin_lock_irqsave(&gpiommgpio->lock, flags); =20 - /* Check if configuring Port C */ - if (io_port =3D=3D 2 || io_port =3D=3D 5) { - /* Port C can be configured by nibble */ - if (offset % 8 > 3) { - gpiommgpio->io_state[io_port] &=3D 0x0F; - gpiommgpio->control[control_port] &=3D ~BIT(3); - } else { - gpiommgpio->io_state[io_port] &=3D 0xF0; - gpiommgpio->control[control_port] &=3D ~BIT(0); - } - } else { - gpiommgpio->io_state[io_port] &=3D 0x00; - if (io_port =3D=3D 0 || io_port =3D=3D 3) - gpiommgpio->control[control_port] &=3D ~BIT(4); - else - gpiommgpio->control[control_port] &=3D ~BIT(1); - } - - if (value) - gpiommgpio->out_state[io_port] |=3D mask; - else - gpiommgpio->out_state[io_port] &=3D ~mask; - - control =3D BIT(7) | gpiommgpio->control[control_port]; - iowrite8(control, gpiommgpio->base + 3 + control_port*4); - - iowrite8(gpiommgpio->out_state[io_port], gpiommgpio->base + out_port); + i8255_direction_output(gpiommgpio->ppi, gpiommgpio->control_state, + offset, value); =20 spin_unlock_irqrestore(&gpiommgpio->lock, flags); =20 @@ -144,47 +89,16 @@ static int gpiomm_gpio_direction_output(struct gpio_ch= ip *chip, static int gpiomm_gpio_get(struct gpio_chip *chip, unsigned int offset) { struct gpiomm_gpio *const gpiommgpio =3D gpiochip_get_data(chip); - const unsigned int port =3D offset / 8; - const unsigned int mask =3D BIT(offset % 8); - const unsigned int in_port =3D (port > 2) ? port + 1 : port; - unsigned long flags; - unsigned int port_state; - - spin_lock_irqsave(&gpiommgpio->lock, flags); - - /* ensure that GPIO is set for input */ - if (!(gpiommgpio->io_state[port] & mask)) { - spin_unlock_irqrestore(&gpiommgpio->lock, flags); - return -EINVAL; - } - - port_state =3D ioread8(gpiommgpio->base + in_port); - - spin_unlock_irqrestore(&gpiommgpio->lock, flags); =20 - return !!(port_state & mask); + return i8255_get(gpiommgpio->ppi, offset); } =20 -static const size_t ports[] =3D { 0, 1, 2, 4, 5, 6 }; - static int gpiomm_gpio_get_multiple(struct gpio_chip *chip, unsigned long = *mask, unsigned long *bits) { struct gpiomm_gpio *const gpiommgpio =3D gpiochip_get_data(chip); - unsigned long offset; - unsigned long gpio_mask; - void __iomem *port_addr; - unsigned long port_state; - - /* clear bits array to a clean slate */ - bitmap_zero(bits, chip->ngpio); =20 - for_each_set_clump8(offset, gpio_mask, mask, ARRAY_SIZE(ports) * 8) { - port_addr =3D gpiommgpio->base + ports[offset / 8]; - port_state =3D ioread8(port_addr) & gpio_mask; - - bitmap_set_value8(bits, port_state, offset); - } + i8255_get_multiple(gpiommgpio->ppi, mask, bits, chip->ngpio); =20 return 0; } @@ -193,19 +107,11 @@ static void gpiomm_gpio_set(struct gpio_chip *chip, u= nsigned int offset, int value) { struct gpiomm_gpio *const gpiommgpio =3D gpiochip_get_data(chip); - const unsigned int port =3D offset / 8; - const unsigned int mask =3D BIT(offset % 8); - const unsigned int out_port =3D (port > 2) ? port + 1 : port; unsigned long flags; =20 spin_lock_irqsave(&gpiommgpio->lock, flags); =20 - if (value) - gpiommgpio->out_state[port] |=3D mask; - else - gpiommgpio->out_state[port] &=3D ~mask; - - iowrite8(gpiommgpio->out_state[port], gpiommgpio->base + out_port); + i8255_set(gpiommgpio->ppi, offset, value); =20 spin_unlock_irqrestore(&gpiommgpio->lock, flags); } @@ -214,28 +120,13 @@ static void gpiomm_gpio_set_multiple(struct gpio_chip= *chip, unsigned long *mask, unsigned long *bits) { struct gpiomm_gpio *const gpiommgpio =3D gpiochip_get_data(chip); - unsigned long offset; - unsigned long gpio_mask; - size_t index; - void __iomem *port_addr; - unsigned long bitmask; unsigned long flags; =20 - for_each_set_clump8(offset, gpio_mask, mask, ARRAY_SIZE(ports) * 8) { - index =3D offset / 8; - port_addr =3D gpiommgpio->base + ports[index]; - - bitmask =3D bitmap_get_value8(bits, offset) & gpio_mask; - - spin_lock_irqsave(&gpiommgpio->lock, flags); + spin_lock_irqsave(&gpiommgpio->lock, flags); =20 - /* update output state data and set device gpio register */ - gpiommgpio->out_state[index] &=3D ~gpio_mask; - gpiommgpio->out_state[index] |=3D bitmask; - iowrite8(gpiommgpio->out_state[index], port_addr); + i8255_set_multiple(gpiommgpio->ppi, mask, bits, chip->ngpio); =20 - spin_unlock_irqrestore(&gpiommgpio->lock, flags); - } + spin_unlock_irqrestore(&gpiommgpio->lock, flags); } =20 #define GPIOMM_NGPIO 48 @@ -250,6 +141,20 @@ static const char *gpiomm_names[GPIOMM_NGPIO] =3D { "Port 2C2", "Port 2C3", "Port 2C4", "Port 2C5", "Port 2C6", "Port 2C7", }; =20 +static void gpiomm_init_dio(struct i8255 __iomem *const ppi) +{ + const unsigned long ngpio =3D 24; + const unsigned long mask =3D GENMASK(ngpio - 1, 0); + const unsigned long bits =3D 0; + unsigned long i; + + /* Initialize all GPIO to output 0 */ + for (i =3D 0; i < 2; i++) { + i8255_mode0_output(&ppi[i]); + i8255_set_multiple(&ppi[i], &mask, &bits, ngpio); + } +} + static int gpiomm_probe(struct device *dev, unsigned int id) { struct gpiomm_gpio *gpiommgpio; @@ -266,8 +171,8 @@ static int gpiomm_probe(struct device *dev, unsigned in= t id) return -EBUSY; } =20 - gpiommgpio->base =3D devm_ioport_map(dev, base[id], GPIOMM_EXTENT); - if (!gpiommgpio->base) + gpiommgpio->ppi =3D devm_ioport_map(dev, base[id], GPIOMM_EXTENT); + if (!gpiommgpio->ppi) return -ENOMEM; =20 gpiommgpio->chip.label =3D name; @@ -292,15 +197,7 @@ static int gpiomm_probe(struct device *dev, unsigned i= nt id) return err; } =20 - /* initialize all GPIO as output */ - iowrite8(0x80, gpiommgpio->base + 3); - iowrite8(0x00, gpiommgpio->base); - iowrite8(0x00, gpiommgpio->base + 1); - iowrite8(0x00, gpiommgpio->base + 2); - iowrite8(0x80, gpiommgpio->base + 7); - iowrite8(0x00, gpiommgpio->base + 4); - iowrite8(0x00, gpiommgpio->base + 5); - iowrite8(0x00, gpiommgpio->base + 6); + gpiomm_init_dio(gpiommgpio->ppi); =20 return 0; } --=20 2.36.1 From nobody Sun Apr 19 02:19:41 2026 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id ED300CCA480 for ; Thu, 7 Jul 2022 23:16:38 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S236870AbiGGXQh (ORCPT ); Thu, 7 Jul 2022 19:16:37 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:58266 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S236890AbiGGXQV (ORCPT ); Thu, 7 Jul 2022 19:16:21 -0400 Received: from mail-oa1-x29.google.com (mail-oa1-x29.google.com [IPv6:2001:4860:4864:20::29]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 36C8E6B257 for ; Thu, 7 Jul 2022 16:16:20 -0700 (PDT) Received: by mail-oa1-x29.google.com with SMTP id 586e51a60fabf-10bffc214ffso16548057fac.1 for ; Thu, 07 Jul 2022 16:16:20 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=gucdXtUT30blOlPna+akHLKgmTi4R2YhWK3Bmyso2+M=; b=qFODspyZ2RgF5y5eeKbqD6V2YSybgyiIjWiWJigjUi4vfDP3PuhA7lUygnTCMVbiwK Ybi3JhVu+6nVvU5hOhVEIpaK5eRcQ8HAHUnQTJte7mo0hNhcjUIq+y4V+Qe6vN+H6Ov0 xy8MKngZ1QgdbUiF21ETbntWmz/za+2nYScArulXoZN/QIT4Hfb0hLaBNEzrwFEKatOC FKGpVmvBvTTbej3DTzRiuwt6vkcVKHR6/czTb61FUVdD/vWf1L/J1hj8PHQIC4B94QpL AZY3IY8cJ+35hELpyiVJfE2C6TpWZtB473lRlj/fVxJtanmud6cdUQ1w0du8ezDtWCLQ ZLrQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=gucdXtUT30blOlPna+akHLKgmTi4R2YhWK3Bmyso2+M=; b=uaHVtpqjnfwbcFp3b4YAkfNFY+OIZ030PanVc8afffx7vHPEkdf0CBYX5FECmpvAq4 HEBE7WHsjJSUmZWKUvU4BxAikikTTKyorxkGnGHDng9mZM3vFbMpxG/LRCs7zVMzpS6a sWZqlhxqqcwrdKYwx7qk19Os951RnpS2LHaQSJClNL3gY+XBB1CQc65MzPIrvLI0c63S 6mHe81boS8leZvJOka/9smXvexJu4YpBDdx70YySec7qGJVkcBMhCVD0NzL2Ic46DreS G83XfkwVp0QrhPQGQcBZnqirXY+qta1rz8KU7JNNHBY+/qIKFfqZQ3HpvO6CA/pbUEhu BRjQ== X-Gm-Message-State: AJIora9u/sNOG6FUcio4W+5epER6gX4AYWOdsP6vEu7KldiddieL7bUC YkYUWZZf9Ncyn7Cc/700qI6chA== X-Google-Smtp-Source: AGRyM1uHNyPzTalMNMcPVsh8LU9hrR0XjW/u1+3I9feblmJfAakbAAm8g+UzL8J2P4Frx1d4aa8bSQ== X-Received: by 2002:a05:6870:41c3:b0:10c:529c:3844 with SMTP id z3-20020a05687041c300b0010c529c3844mr231725oac.0.1657235779435; Thu, 07 Jul 2022 16:16:19 -0700 (PDT) Received: from fedora.attlocal.net (69-109-179-158.lightspeed.dybhfl.sbcglobal.net. [69.109.179.158]) by smtp.gmail.com with ESMTPSA id cg10-20020a056830630a00b006190efaf118sm2177606otb.66.2022.07.07.16.16.18 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 07 Jul 2022 16:16:19 -0700 (PDT) From: William Breathitt Gray To: linus.walleij@linaro.org, brgl@bgdev.pl Cc: linux-gpio@vger.kernel.org, linux-kernel@vger.kernel.org, William Breathitt Gray , Fred Eckert , John Hentges , Jay Dolan Subject: [PATCH v2 5/6] gpio: 104-idio-16: Implement and utilize register structures Date: Thu, 7 Jul 2022 14:10:07 -0400 Message-Id: <542a96e3c808c43efc2c4daade0008d4373f55af.1657216200.git.william.gray@linaro.org> X-Mailer: git-send-email 2.36.1 In-Reply-To: References: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" Reduce magic numbers and improve code readability by implementing and utilizing named register data structures. Tested-by: Fred Eckert Cc: John Hentges Cc: Jay Dolan Signed-off-by: William Breathitt Gray --- drivers/gpio/gpio-104-idio-16.c | 58 +++++++++++++++++++++++---------- 1 file changed, 41 insertions(+), 17 deletions(-) diff --git a/drivers/gpio/gpio-104-idio-16.c b/drivers/gpio/gpio-104-idio-1= 6.c index 45f7ad8573e1..2f8e295f5541 100644 --- a/drivers/gpio/gpio-104-idio-16.c +++ b/drivers/gpio/gpio-104-idio-16.c @@ -19,6 +19,7 @@ #include #include #include +#include =20 #define IDIO_16_EXTENT 8 #define MAX_NUM_IDIO_16 max_num_isa_dev(IDIO_16_EXTENT) @@ -32,19 +33,42 @@ static unsigned int irq[MAX_NUM_IDIO_16]; module_param_hw_array(irq, uint, irq, NULL, 0); MODULE_PARM_DESC(irq, "ACCES 104-IDIO-16 interrupt line numbers"); =20 +/** + * struct idio_16_reg - device registers structure + * @out0_7: Read: N/A + * Write: FET Drive Outputs 0-7 + * @in0_7: Read: Isolated Inputs 0-7 + * Write: Clear Interrupt + * @irq_ctl: Read: Enable IRQ + * Write: Disable IRQ + * @unused: N/A + * @out8_15: Read: N/A + * Write: FET Drive Outputs 8-15 + * @in8_15: Read: Isolated Inputs 8-15 + * Write: N/A + */ +struct idio_16_reg { + u8 out0_7; + u8 in0_7; + u8 irq_ctl; + u8 unused; + u8 out8_15; + u8 in8_15; +}; + /** * struct idio_16_gpio - GPIO device private data structure * @chip: instance of the gpio_chip * @lock: synchronization lock to prevent I/O race conditions * @irq_mask: I/O bits affected by interrupts - * @base: base port address of the GPIO device + * @reg: I/O address offset for the device registers * @out_state: output bits state */ struct idio_16_gpio { struct gpio_chip chip; raw_spinlock_t lock; unsigned long irq_mask; - void __iomem *base; + struct idio_16_reg __iomem *reg; unsigned int out_state; }; =20 @@ -79,9 +103,9 @@ static int idio_16_gpio_get(struct gpio_chip *chip, unsi= gned int offset) return -EINVAL; =20 if (offset < 24) - return !!(ioread8(idio16gpio->base + 1) & mask); + return !!(ioread8(&idio16gpio->reg->in0_7) & mask); =20 - return !!(ioread8(idio16gpio->base + 5) & (mask>>8)); + return !!(ioread8(&idio16gpio->reg->in8_15) & (mask>>8)); } =20 static int idio_16_gpio_get_multiple(struct gpio_chip *chip, @@ -91,9 +115,9 @@ static int idio_16_gpio_get_multiple(struct gpio_chip *c= hip, =20 *bits =3D 0; if (*mask & GENMASK(23, 16)) - *bits |=3D (unsigned long)ioread8(idio16gpio->base + 1) << 16; + *bits |=3D (unsigned long)ioread8(&idio16gpio->reg->in0_7) << 16; if (*mask & GENMASK(31, 24)) - *bits |=3D (unsigned long)ioread8(idio16gpio->base + 5) << 24; + *bits |=3D (unsigned long)ioread8(&idio16gpio->reg->in8_15) << 24; =20 return 0; } @@ -116,9 +140,9 @@ static void idio_16_gpio_set(struct gpio_chip *chip, un= signed int offset, idio16gpio->out_state &=3D ~mask; =20 if (offset > 7) - iowrite8(idio16gpio->out_state >> 8, idio16gpio->base + 4); + iowrite8(idio16gpio->out_state >> 8, &idio16gpio->reg->out8_15); else - iowrite8(idio16gpio->out_state, idio16gpio->base); + iowrite8(idio16gpio->out_state, &idio16gpio->reg->out0_7); =20 raw_spin_unlock_irqrestore(&idio16gpio->lock, flags); } @@ -135,9 +159,9 @@ static void idio_16_gpio_set_multiple(struct gpio_chip = *chip, idio16gpio->out_state |=3D *mask & *bits; =20 if (*mask & 0xFF) - iowrite8(idio16gpio->out_state, idio16gpio->base); + iowrite8(idio16gpio->out_state, &idio16gpio->reg->out0_7); if ((*mask >> 8) & 0xFF) - iowrite8(idio16gpio->out_state >> 8, idio16gpio->base + 4); + iowrite8(idio16gpio->out_state >> 8, &idio16gpio->reg->out8_15); =20 raw_spin_unlock_irqrestore(&idio16gpio->lock, flags); } @@ -158,7 +182,7 @@ static void idio_16_irq_mask(struct irq_data *data) if (!idio16gpio->irq_mask) { raw_spin_lock_irqsave(&idio16gpio->lock, flags); =20 - iowrite8(0, idio16gpio->base + 2); + iowrite8(0, &idio16gpio->reg->irq_ctl); =20 raw_spin_unlock_irqrestore(&idio16gpio->lock, flags); } @@ -177,7 +201,7 @@ static void idio_16_irq_unmask(struct irq_data *data) if (!prev_irq_mask) { raw_spin_lock_irqsave(&idio16gpio->lock, flags); =20 - ioread8(idio16gpio->base + 2); + ioread8(&idio16gpio->reg->irq_ctl); =20 raw_spin_unlock_irqrestore(&idio16gpio->lock, flags); } @@ -212,7 +236,7 @@ static irqreturn_t idio_16_irq_handler(int irq, void *d= ev_id) =20 raw_spin_lock(&idio16gpio->lock); =20 - iowrite8(0, idio16gpio->base + 1); + iowrite8(0, &idio16gpio->reg->in0_7); =20 raw_spin_unlock(&idio16gpio->lock); =20 @@ -232,8 +256,8 @@ static int idio_16_irq_init_hw(struct gpio_chip *gc) struct idio_16_gpio *const idio16gpio =3D gpiochip_get_data(gc); =20 /* Disable IRQ by default */ - iowrite8(0, idio16gpio->base + 2); - iowrite8(0, idio16gpio->base + 1); + iowrite8(0, &idio16gpio->reg->irq_ctl); + iowrite8(0, &idio16gpio->reg->in0_7); =20 return 0; } @@ -255,8 +279,8 @@ static int idio_16_probe(struct device *dev, unsigned i= nt id) return -EBUSY; } =20 - idio16gpio->base =3D devm_ioport_map(dev, base[id], IDIO_16_EXTENT); - if (!idio16gpio->base) + idio16gpio->reg =3D devm_ioport_map(dev, base[id], IDIO_16_EXTENT); + if (!idio16gpio->reg) return -ENOMEM; =20 idio16gpio->chip.label =3D name; --=20 2.36.1 From nobody Sun Apr 19 02:19:41 2026 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 55ACAC433EF for ; Thu, 7 Jul 2022 23:16:45 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S236938AbiGGXQo (ORCPT ); Thu, 7 Jul 2022 19:16:44 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:58322 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S236897AbiGGXQW (ORCPT ); Thu, 7 Jul 2022 19:16:22 -0400 Received: from mail-oa1-x36.google.com (mail-oa1-x36.google.com [IPv6:2001:4860:4864:20::36]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 1D946675B3 for ; Thu, 7 Jul 2022 16:16:21 -0700 (PDT) Received: by mail-oa1-x36.google.com with SMTP id 586e51a60fabf-10bffc214ffso16548112fac.1 for ; Thu, 07 Jul 2022 16:16:21 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=XpnakdCCOjDxEeliMe2U41zkyBdJcHLmJvfSH3h8a+c=; b=eisAi3hpEbcwCMasIMlhFwH7QV7wRq4VFv8UJytMpHk4TtKNLLm0q2viwIn99xPGuM R3D8aIz0hLgCiQFvv2YF2DBfeDPoRom5qkHYIn3/ij2uKZZqxJfErKLH0FE1kFiinuJc bocF6jLyBoh4pZGqkkxzuHQdQ5QwrPnafMirW2GPSgceM24D+gc/Pn18xzHsz37Ksoq0 z6MXkR1fdI7Dw1siob3LpAzvjKgYYWYKOR1GfF8dQ9gN1PimAimdnGFyGnQZk3WanGFW 8urZ2zDJK0GSmeDRQg/mX+K8GQ6e8hil9ErdAXRxNeTagGV71Nk6WZPY769y/ER56vju 1h7g== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=XpnakdCCOjDxEeliMe2U41zkyBdJcHLmJvfSH3h8a+c=; b=qIeKrbuG3rkfe5ff0w7Yzo1oSNhHpGnVxd6CbEhRs4GyJnzENKnLAdlwmxzGGsQusJ 0xxgZWQlUrM7isqfjl9yryUVMeOfKD6Wnw2iM2c4Jq0BDciCiDGw42QLEB6w5/5cY4Sx JAAgSmCdJeRgpHiSslLSKIEtzK0Jk/VfZWjrGyW2SxVv4eywYUcC7AQkPTp3YAvK1qUm 7FCVBP1t8nRdH5EHzrI4YloxwOAwGb38+qcoDiUOFJi5RCevsCr6nb5n60QqpsTSu9PW zTu6cs5dv7N02M5j7NJJhpWnInYwQ7NNaqP7CJrpo3Ea9AmPIUt8+NEzh6X8smpbJNy0 +lvw== X-Gm-Message-State: AJIora8/B3sL02sMnSo0PcoVMG+Ul0cgTLGjLIRKTKyDOJ2gGJHtzMfB KtFHuuY1D3oqEz9N752/rPGFlw== X-Google-Smtp-Source: AGRyM1uCTmmwxCqu/MjYv15jBwkbfz9gBTuh3nuLle5SKYQh/KQf8wzXj+0hPnQ95VKVmUvSkHwZ5Q== X-Received: by 2002:a05:6871:14a:b0:10c:5005:a6b1 with SMTP id z10-20020a056871014a00b0010c5005a6b1mr219231oab.191.1657235780815; Thu, 07 Jul 2022 16:16:20 -0700 (PDT) Received: from fedora.attlocal.net (69-109-179-158.lightspeed.dybhfl.sbcglobal.net. [69.109.179.158]) by smtp.gmail.com with ESMTPSA id cg10-20020a056830630a00b006190efaf118sm2177606otb.66.2022.07.07.16.16.20 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 07 Jul 2022 16:16:20 -0700 (PDT) From: William Breathitt Gray To: linus.walleij@linaro.org, brgl@bgdev.pl Cc: linux-gpio@vger.kernel.org, linux-kernel@vger.kernel.org, William Breathitt Gray , techsupport@winsystems.com, Paul Demetrotion Subject: [PATCH v2 6/6] gpio: ws16c48: Implement and utilize register structures Date: Thu, 7 Jul 2022 14:10:08 -0400 Message-Id: <8d05cfc343479b7085a64e0188ae9b7d97c8614b.1657216200.git.william.gray@linaro.org> X-Mailer: git-send-email 2.36.1 In-Reply-To: References: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" Reduce magic numbers and improve code readability by implementing and utilizing named register data structures. Cc: Paul Demetrotion Signed-off-by: William Breathitt Gray --- drivers/gpio/gpio-ws16c48.c | 119 +++++++++++++++++++++++++----------- 1 file changed, 84 insertions(+), 35 deletions(-) diff --git a/drivers/gpio/gpio-ws16c48.c b/drivers/gpio/gpio-ws16c48.c index 5078631d8014..663d4491b90f 100644 --- a/drivers/gpio/gpio-ws16c48.c +++ b/drivers/gpio/gpio-ws16c48.c @@ -17,8 +17,9 @@ #include #include #include +#include =20 -#define WS16C48_EXTENT 16 +#define WS16C48_EXTENT 10 #define MAX_NUM_WS16C48 max_num_isa_dev(WS16C48_EXTENT) =20 static unsigned int base[MAX_NUM_WS16C48]; @@ -30,6 +31,20 @@ static unsigned int irq[MAX_NUM_WS16C48]; module_param_hw_array(irq, uint, irq, NULL, 0); MODULE_PARM_DESC(irq, "WinSystems WS16C48 interrupt line numbers"); =20 +/** + * struct ws16c48_reg - device register structure + * @port: Port 0 through 5 I/O + * @int_pending: Interrupt Pending + * @page_lock: Register page (Bits 7-6) and I/O port lock (Bits 5-0) + * @pol_enab_int_id: Interrupt polarity, enable, and ID + */ +struct ws16c48_reg { + u8 port[6]; + u8 int_pending; + u8 page_lock; + u8 pol_enab_int_id[3]; +}; + /** * struct ws16c48_gpio - GPIO device private data structure * @chip: instance of the gpio_chip @@ -38,7 +53,7 @@ MODULE_PARM_DESC(irq, "WinSystems WS16C48 interrupt line = numbers"); * @lock: synchronization lock to prevent I/O race conditions * @irq_mask: I/O bits affected by interrupts * @flow_mask: IRQ flow type mask for the respective I/O bits - * @base: base port address of the GPIO device + * @reg: I/O address offset for the device registers */ struct ws16c48_gpio { struct gpio_chip chip; @@ -47,7 +62,7 @@ struct ws16c48_gpio { raw_spinlock_t lock; unsigned long irq_mask; unsigned long flow_mask; - void __iomem *base; + struct ws16c48_reg __iomem *reg; }; =20 static int ws16c48_gpio_get_direction(struct gpio_chip *chip, unsigned off= set) @@ -73,7 +88,7 @@ static int ws16c48_gpio_direction_input(struct gpio_chip = *chip, unsigned offset) =20 ws16c48gpio->io_state[port] |=3D mask; ws16c48gpio->out_state[port] &=3D ~mask; - iowrite8(ws16c48gpio->out_state[port], ws16c48gpio->base + port); + iowrite8(ws16c48gpio->out_state[port], ws16c48gpio->reg->port + port); =20 raw_spin_unlock_irqrestore(&ws16c48gpio->lock, flags); =20 @@ -95,7 +110,7 @@ static int ws16c48_gpio_direction_output(struct gpio_chi= p *chip, ws16c48gpio->out_state[port] |=3D mask; else ws16c48gpio->out_state[port] &=3D ~mask; - iowrite8(ws16c48gpio->out_state[port], ws16c48gpio->base + port); + iowrite8(ws16c48gpio->out_state[port], ws16c48gpio->reg->port + port); =20 raw_spin_unlock_irqrestore(&ws16c48gpio->lock, flags); =20 @@ -118,7 +133,7 @@ static int ws16c48_gpio_get(struct gpio_chip *chip, uns= igned offset) return -EINVAL; } =20 - port_state =3D ioread8(ws16c48gpio->base + port); + port_state =3D ioread8(ws16c48gpio->reg->port + port); =20 raw_spin_unlock_irqrestore(&ws16c48gpio->lock, flags); =20 @@ -131,14 +146,16 @@ static int ws16c48_gpio_get_multiple(struct gpio_chip= *chip, struct ws16c48_gpio *const ws16c48gpio =3D gpiochip_get_data(chip); unsigned long offset; unsigned long gpio_mask; - void __iomem *port_addr; + size_t index; + u8 __iomem *port_addr; unsigned long port_state; =20 /* clear bits array to a clean slate */ bitmap_zero(bits, chip->ngpio); =20 for_each_set_clump8(offset, gpio_mask, mask, chip->ngpio) { - port_addr =3D ws16c48gpio->base + offset / 8; + index =3D offset / 8; + port_addr =3D ws16c48gpio->reg->port + index; port_state =3D ioread8(port_addr) & gpio_mask; =20 bitmap_set_value8(bits, port_state, offset); @@ -166,7 +183,7 @@ static void ws16c48_gpio_set(struct gpio_chip *chip, un= signed offset, int value) ws16c48gpio->out_state[port] |=3D mask; else ws16c48gpio->out_state[port] &=3D ~mask; - iowrite8(ws16c48gpio->out_state[port], ws16c48gpio->base + port); + iowrite8(ws16c48gpio->out_state[port], ws16c48gpio->reg->port + port); =20 raw_spin_unlock_irqrestore(&ws16c48gpio->lock, flags); } @@ -178,13 +195,13 @@ static void ws16c48_gpio_set_multiple(struct gpio_chi= p *chip, unsigned long offset; unsigned long gpio_mask; size_t index; - void __iomem *port_addr; + u8 __iomem *port_addr; unsigned long bitmask; unsigned long flags; =20 for_each_set_clump8(offset, gpio_mask, mask, chip->ngpio) { index =3D offset / 8; - port_addr =3D ws16c48gpio->base + index; + port_addr =3D ws16c48gpio->reg->port + index; =20 /* mask out GPIO configured for input */ gpio_mask &=3D ~ws16c48gpio->io_state[index]; @@ -219,10 +236,15 @@ static void ws16c48_irq_ack(struct irq_data *data) =20 port_state =3D ws16c48gpio->irq_mask >> (8*port); =20 - iowrite8(0x80, ws16c48gpio->base + 7); - iowrite8(port_state & ~mask, ws16c48gpio->base + 8 + port); - iowrite8(port_state | mask, ws16c48gpio->base + 8 + port); - iowrite8(0xC0, ws16c48gpio->base + 7); + /* Select Register Page 2; Unlock all I/O ports */ + iowrite8(0x80, &ws16c48gpio->reg->page_lock); + + /* Clear pending interrupt */ + iowrite8(port_state & ~mask, ws16c48gpio->reg->pol_enab_int_id + port); + iowrite8(port_state | mask, ws16c48gpio->reg->pol_enab_int_id + port); + + /* Select Register Page 3; Unlock all I/O ports */ + iowrite8(0xC0, &ws16c48gpio->reg->page_lock); =20 raw_spin_unlock_irqrestore(&ws16c48gpio->lock, flags); } @@ -235,6 +257,7 @@ static void ws16c48_irq_mask(struct irq_data *data) const unsigned long mask =3D BIT(offset); const unsigned port =3D offset / 8; unsigned long flags; + unsigned long port_state; =20 /* only the first 3 ports support interrupts */ if (port > 2) @@ -243,10 +266,16 @@ static void ws16c48_irq_mask(struct irq_data *data) raw_spin_lock_irqsave(&ws16c48gpio->lock, flags); =20 ws16c48gpio->irq_mask &=3D ~mask; + port_state =3D ws16c48gpio->irq_mask >> (8 * port); + + /* Select Register Page 2; Unlock all I/O ports */ + iowrite8(0x80, &ws16c48gpio->reg->page_lock); =20 - iowrite8(0x80, ws16c48gpio->base + 7); - iowrite8(ws16c48gpio->irq_mask >> (8*port), ws16c48gpio->base + 8 + port); - iowrite8(0xC0, ws16c48gpio->base + 7); + /* Disable interrupt */ + iowrite8(port_state, ws16c48gpio->reg->pol_enab_int_id + port); + + /* Select Register Page 3; Unlock all I/O ports */ + iowrite8(0xC0, &ws16c48gpio->reg->page_lock); =20 raw_spin_unlock_irqrestore(&ws16c48gpio->lock, flags); } @@ -259,6 +288,7 @@ static void ws16c48_irq_unmask(struct irq_data *data) const unsigned long mask =3D BIT(offset); const unsigned port =3D offset / 8; unsigned long flags; + unsigned long port_state; =20 /* only the first 3 ports support interrupts */ if (port > 2) @@ -267,10 +297,16 @@ static void ws16c48_irq_unmask(struct irq_data *data) raw_spin_lock_irqsave(&ws16c48gpio->lock, flags); =20 ws16c48gpio->irq_mask |=3D mask; + port_state =3D ws16c48gpio->irq_mask >> (8 * port); + + /* Select Register Page 2; Unlock all I/O ports */ + iowrite8(0x80, &ws16c48gpio->reg->page_lock); =20 - iowrite8(0x80, ws16c48gpio->base + 7); - iowrite8(ws16c48gpio->irq_mask >> (8*port), ws16c48gpio->base + 8 + port); - iowrite8(0xC0, ws16c48gpio->base + 7); + /* Enable interrupt */ + iowrite8(port_state, ws16c48gpio->reg->pol_enab_int_id + port); + + /* Select Register Page 3; Unlock all I/O ports */ + iowrite8(0xC0, &ws16c48gpio->reg->page_lock); =20 raw_spin_unlock_irqrestore(&ws16c48gpio->lock, flags); } @@ -283,6 +319,7 @@ static int ws16c48_irq_set_type(struct irq_data *data, = unsigned flow_type) const unsigned long mask =3D BIT(offset); const unsigned port =3D offset / 8; unsigned long flags; + unsigned long port_state; =20 /* only the first 3 ports support interrupts */ if (port > 2) @@ -304,9 +341,16 @@ static int ws16c48_irq_set_type(struct irq_data *data,= unsigned flow_type) return -EINVAL; } =20 - iowrite8(0x40, ws16c48gpio->base + 7); - iowrite8(ws16c48gpio->flow_mask >> (8*port), ws16c48gpio->base + 8 + port= ); - iowrite8(0xC0, ws16c48gpio->base + 7); + port_state =3D ws16c48gpio->flow_mask >> (8 * port); + + /* Select Register Page 1; Unlock all I/O ports */ + iowrite8(0x40, &ws16c48gpio->reg->page_lock); + + /* Set interrupt polarity */ + iowrite8(port_state, ws16c48gpio->reg->pol_enab_int_id + port); + + /* Select Register Page 3; Unlock all I/O ports */ + iowrite8(0xC0, &ws16c48gpio->reg->page_lock); =20 raw_spin_unlock_irqrestore(&ws16c48gpio->lock, flags); =20 @@ -325,25 +369,26 @@ static irqreturn_t ws16c48_irq_handler(int irq, void = *dev_id) { struct ws16c48_gpio *const ws16c48gpio =3D dev_id; struct gpio_chip *const chip =3D &ws16c48gpio->chip; + struct ws16c48_reg __iomem *const reg =3D ws16c48gpio->reg; unsigned long int_pending; unsigned long port; unsigned long int_id; unsigned long gpio; =20 - int_pending =3D ioread8(ws16c48gpio->base + 6) & 0x7; + int_pending =3D ioread8(®->int_pending) & 0x7; if (!int_pending) return IRQ_NONE; =20 /* loop until all pending interrupts are handled */ do { for_each_set_bit(port, &int_pending, 3) { - int_id =3D ioread8(ws16c48gpio->base + 8 + port); + int_id =3D ioread8(reg->pol_enab_int_id + port); for_each_set_bit(gpio, &int_id, 8) generic_handle_domain_irq(chip->irq.domain, gpio + 8*port); } =20 - int_pending =3D ioread8(ws16c48gpio->base + 6) & 0x7; + int_pending =3D ioread8(®->int_pending) & 0x7; } while (int_pending); =20 return IRQ_HANDLED; @@ -369,12 +414,16 @@ static int ws16c48_irq_init_hw(struct gpio_chip *gc) { struct ws16c48_gpio *const ws16c48gpio =3D gpiochip_get_data(gc); =20 - /* Disable IRQ by default */ - iowrite8(0x80, ws16c48gpio->base + 7); - iowrite8(0, ws16c48gpio->base + 8); - iowrite8(0, ws16c48gpio->base + 9); - iowrite8(0, ws16c48gpio->base + 10); - iowrite8(0xC0, ws16c48gpio->base + 7); + /* Select Register Page 2; Unlock all I/O ports */ + iowrite8(0x80, &ws16c48gpio->reg->page_lock); + + /* Disable interrupts for all lines */ + iowrite8(0, &ws16c48gpio->reg->pol_enab_int_id[0]); + iowrite8(0, &ws16c48gpio->reg->pol_enab_int_id[1]); + iowrite8(0, &ws16c48gpio->reg->pol_enab_int_id[2]); + + /* Select Register Page 3; Unlock all I/O ports */ + iowrite8(0xC0, &ws16c48gpio->reg->page_lock); =20 return 0; } @@ -396,8 +445,8 @@ static int ws16c48_probe(struct device *dev, unsigned i= nt id) return -EBUSY; } =20 - ws16c48gpio->base =3D devm_ioport_map(dev, base[id], WS16C48_EXTENT); - if (!ws16c48gpio->base) + ws16c48gpio->reg =3D devm_ioport_map(dev, base[id], WS16C48_EXTENT); + if (!ws16c48gpio->reg) return -ENOMEM; =20 ws16c48gpio->chip.label =3D name; --=20 2.36.1