From patchwork Mon Jun 6 14:33:16 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: 579663 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 E8616C43334 for ; Mon, 6 Jun 2022 14:36:21 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S239917AbiFFOgU (ORCPT ); Mon, 6 Jun 2022 10:36:20 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:37802 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S239829AbiFFOgM (ORCPT ); Mon, 6 Jun 2022 10:36:12 -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 9799C12B006 for ; Mon, 6 Jun 2022 07:36:10 -0700 (PDT) Received: by mail-oa1-x29.google.com with SMTP id 586e51a60fabf-f314077115so19395135fac.1 for ; Mon, 06 Jun 2022 07:36:10 -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=VfTrAEC+8RIPbSv52tbPZfU+fEKDARXIrRMp1LlzURg=; b=PdVn8UAKMCpAesFj5BGFLpNp+aIwTXO4mG6N2TEYZLF5GNt3e2WbJFsJXOJhSpcnuG IZtlFZzIB8VZAICoqaLu59LLLQVlugx3X+ljocTiKocjhKWTzy47LVeM4N4wm4h2jO7T HV9RojTqb2zTHhmEtCv2z9QBcWd175TvygQmWF+hm15mPyDyqXjh6icIvnzK0tHMTajA SI7Rn+L6WSMUgZ5JgPu0wu3wMsZ3x/If1D19+1KuzDbelxufvoPa7t+dU+sXY1/2qSLi f8V+jGUS6rmxLks9JQQpJw7iMLSWjkZ2HdoeronDKf6egUAziKmcA/ARoozmDu1PpHxz XsBw== 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=VfTrAEC+8RIPbSv52tbPZfU+fEKDARXIrRMp1LlzURg=; b=GkR3D5XM3JrBj5d1XyxuZUHXQvsxszB1+TiFr4rnMJtQ88PeNenWQjgcvTZnTbkEGP +yKb0TKjcYnCRpX7LWVXxgvkXPc2/wVh9lR2ROcr6+/XfjT/TtADx7Hu3Bpl4dTEAFmC pmhznyCzjD2ef9Ptjaj9GBbwSDe9Lz5v129Zr8KAR0w6C4FOpO+IZZsyVuoMsBEK+Jhb NMzN7e17AuW+cAViSLpf89m76YgV1zIrlSN0KFFX6pK58J1WYvxDAESbrEXjnPNQEIE7 vy9SyFpns/IX9P7YW61qmDpYQlTGFoHKk7m1+kwBLCbNaIFnGjlLc9b6qqH24mJLpSdU yKjA== X-Gm-Message-State: AOAM533gxc7aXKpLf0gf17EfHTygJ35KrEAs17182Fa7K1+sweu1bK1+ Escz+wiBLb2GJwLVDrnHJepmxg== X-Google-Smtp-Source: ABdhPJxH6gbXCunuQbHxi/D/1wcisDJtuO5XeNd2Om3ppELl/Dy+KlzcX7HmvliSW/sqzxFIBpFZZA== X-Received: by 2002:a05:6870:c690:b0:f2:99d5:343e with SMTP id cv16-20020a056870c69000b000f299d5343emr31198250oab.136.1654526169955; Mon, 06 Jun 2022 07:36:09 -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 u13-20020a056871008d00b000f5d4e5b9a0sm6942791oaa.2.2022.06.06.07.36.09 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 06 Jun 2022 07:36:09 -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 Subject: [PATCH 1/5] gpio: 104-dio-48e: Implement and utilize register structures Date: Mon, 6 Jun 2022 10:33:16 -0400 Message-Id: <7d28ff3373d49d29b01765958ec322ce5ed0d4ff.1654525394.git.william.gray@linaro.org> X-Mailer: git-send-email 2.36.1 In-Reply-To: References: MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-gpio@vger.kernel.org Reduce magic numbers and improve code readability by implementing and utilizing named register data structures. Signed-off-by: William Breathitt Gray --- drivers/gpio/gpio-104-dio-48e.c | 157 +++++++++++++++++++++----------- 1 file changed, 106 insertions(+), 51 deletions(-) diff --git a/drivers/gpio/gpio-104-dio-48e.c b/drivers/gpio/gpio-104-dio-48e.c index f118ad9bcd33..e1c5759e0902 100644 --- a/drivers/gpio/gpio-104-dio-48e.c +++ b/drivers/gpio/gpio-104-dio-48e.c @@ -20,6 +20,7 @@ #include #include #include +#include #define DIO48E_EXTENT 16 #define MAX_NUM_DIO48E max_num_isa_dev(DIO48E_EXTENT) @@ -33,6 +34,40 @@ 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"); +/** + * struct i8255_reg - Intel 8255 register structure + * @port: Port A, B, and C + * @control: Control register + */ +struct i8255_reg { + u8 port[3]; + u8 control; +}; + +/** + * 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_reg 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 @@ -40,7 +75,7 @@ MODULE_PARM_DESC(irq, "ACCES 104-DIO-48E interrupt line numbers"); * @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 + * @reg: I/O address offset for the device registers * @irq_mask: I/O bits affected by interrupts */ struct dio48e_gpio { @@ -49,7 +84,7 @@ struct dio48e_gpio { unsigned char out_state[6]; unsigned char control[2]; raw_spinlock_t lock; - void __iomem *base; + struct dio48e_reg __iomem *reg; unsigned char irq_mask; }; @@ -69,32 +104,33 @@ static int dio48e_gpio_direction_input(struct gpio_chip *chip, unsigned int offs { struct dio48e_gpio *const dio48egpio = gpiochip_get_data(chip); const unsigned int io_port = offset / 8; - const unsigned int control_port = io_port / 3; - void __iomem *const control_addr = dio48egpio->base + 3 + control_port * 4; + const unsigned long group = io_port / 3; + const unsigned long port = io_port - (group * 3); + u8 __iomem *const control_addr = &dio48egpio->reg->ppi[group].control; unsigned long flags; unsigned int control; raw_spin_lock_irqsave(&dio48egpio->lock, flags); /* Check if configuring Port C */ - if (io_port == 2 || io_port == 5) { + if (port == 2) { /* Port C can be configured by nibble */ if (offset % 8 > 3) { dio48egpio->io_state[io_port] |= 0xF0; - dio48egpio->control[control_port] |= BIT(3); + dio48egpio->control[group] |= BIT(3); } else { dio48egpio->io_state[io_port] |= 0x0F; - dio48egpio->control[control_port] |= BIT(0); + dio48egpio->control[group] |= BIT(0); } } else { dio48egpio->io_state[io_port] |= 0xFF; - if (io_port == 0 || io_port == 3) - dio48egpio->control[control_port] |= BIT(4); + if (port == 0) + dio48egpio->control[group] |= BIT(4); else - dio48egpio->control[control_port] |= BIT(1); + dio48egpio->control[group] |= BIT(1); } - control = BIT(7) | dio48egpio->control[control_port]; + control = BIT(7) | dio48egpio->control[group]; iowrite8(control, control_addr); control &= ~BIT(7); iowrite8(control, control_addr); @@ -109,31 +145,33 @@ static int dio48e_gpio_direction_output(struct gpio_chip *chip, unsigned int off { struct dio48e_gpio *const dio48egpio = gpiochip_get_data(chip); const unsigned int io_port = offset / 8; - const unsigned int control_port = io_port / 3; + const unsigned long group = io_port / 3; + const unsigned long port = io_port - (group * 3); const unsigned int mask = BIT(offset % 8); - void __iomem *const control_addr = dio48egpio->base + 3 + control_port * 4; - const unsigned int out_port = (io_port > 2) ? io_port + 1 : io_port; + struct i8255_reg __iomem *const ppi = dio48egpio->reg->ppi + group; + u8 __iomem *const control_addr = &ppi->control; + u8 __iomem *const port_addr = ppi->port + port; unsigned long flags; unsigned int control; raw_spin_lock_irqsave(&dio48egpio->lock, flags); /* Check if configuring Port C */ - if (io_port == 2 || io_port == 5) { + if (port == 2) { /* Port C can be configured by nibble */ if (offset % 8 > 3) { dio48egpio->io_state[io_port] &= 0x0F; - dio48egpio->control[control_port] &= ~BIT(3); + dio48egpio->control[group] &= ~BIT(3); } else { dio48egpio->io_state[io_port] &= 0xF0; - dio48egpio->control[control_port] &= ~BIT(0); + dio48egpio->control[group] &= ~BIT(0); } } else { dio48egpio->io_state[io_port] &= 0x00; - if (io_port == 0 || io_port == 3) - dio48egpio->control[control_port] &= ~BIT(4); + if (port == 0) + dio48egpio->control[group] &= ~BIT(4); else - dio48egpio->control[control_port] &= ~BIT(1); + dio48egpio->control[group] &= ~BIT(1); } if (value) @@ -141,10 +179,10 @@ static int dio48e_gpio_direction_output(struct gpio_chip *chip, unsigned int off else dio48egpio->out_state[io_port] &= ~mask; - control = BIT(7) | dio48egpio->control[control_port]; + control = BIT(7) | dio48egpio->control[group]; iowrite8(control, control_addr); - iowrite8(dio48egpio->out_state[io_port], dio48egpio->base + out_port); + iowrite8(dio48egpio->out_state[io_port], port_addr); control &= ~BIT(7); iowrite8(control, control_addr); @@ -159,7 +197,8 @@ static int dio48e_gpio_get(struct gpio_chip *chip, unsigned int offset) struct dio48e_gpio *const dio48egpio = gpiochip_get_data(chip); const unsigned int port = offset / 8; const unsigned int mask = BIT(offset % 8); - const unsigned int in_port = (port > 2) ? port + 1 : port; + const unsigned long group = port / 3; + const unsigned long in_port = port - (group * 3); unsigned long flags; unsigned int port_state; @@ -171,29 +210,33 @@ static int dio48e_gpio_get(struct gpio_chip *chip, unsigned int offset) return -EINVAL; } - port_state = ioread8(dio48egpio->base + in_port); + port_state = ioread8(dio48egpio->reg->ppi[group].port + in_port); raw_spin_unlock_irqrestore(&dio48egpio->lock, flags); return !!(port_state & mask); } -static const size_t ports[] = { 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 = gpiochip_get_data(chip); unsigned long offset; unsigned long gpio_mask; - void __iomem *port_addr; + unsigned long port; + unsigned long group; + unsigned long in_port; + u8 __iomem *port_addr; unsigned long port_state; /* clear bits array to a clean slate */ bitmap_zero(bits, chip->ngpio); - for_each_set_clump8(offset, gpio_mask, mask, ARRAY_SIZE(ports) * 8) { - port_addr = dio48egpio->base + ports[offset / 8]; + for_each_set_clump8(offset, gpio_mask, mask, chip->ngpio) { + port = offset / 8; + group = port / 3; + in_port = port - (group * 3); + port_addr = dio48egpio->reg->ppi[group].port + in_port; port_state = ioread8(port_addr) & gpio_mask; bitmap_set_value8(bits, port_state, offset); @@ -207,7 +250,8 @@ static void dio48e_gpio_set(struct gpio_chip *chip, unsigned int offset, int val struct dio48e_gpio *const dio48egpio = gpiochip_get_data(chip); const unsigned int port = offset / 8; const unsigned int mask = BIT(offset % 8); - const unsigned int out_port = (port > 2) ? port + 1 : port; + const unsigned long group = port / 3; + const unsigned long out_port = port - (group * 3); unsigned long flags; raw_spin_lock_irqsave(&dio48egpio->lock, flags); @@ -217,7 +261,8 @@ static void dio48e_gpio_set(struct gpio_chip *chip, unsigned int offset, int val else dio48egpio->out_state[port] &= ~mask; - iowrite8(dio48egpio->out_state[port], dio48egpio->base + out_port); + iowrite8(dio48egpio->out_state[port], + dio48egpio->reg->ppi[group].port + out_port); raw_spin_unlock_irqrestore(&dio48egpio->lock, flags); } @@ -229,13 +274,17 @@ static void dio48e_gpio_set_multiple(struct gpio_chip *chip, unsigned long offset; unsigned long gpio_mask; size_t index; - void __iomem *port_addr; + size_t group; + size_t out_port; + u8 __iomem *port_addr; unsigned long bitmask; unsigned long flags; - for_each_set_clump8(offset, gpio_mask, mask, ARRAY_SIZE(ports) * 8) { + for_each_set_clump8(offset, gpio_mask, mask, chip->ngpio) { index = offset / 8; - port_addr = dio48egpio->base + ports[index]; + group = index / 3; + out_port = index - (group * 3); + port_addr = dio48egpio->reg->ppi[group].port + out_port; bitmask = bitmap_get_value8(bits, offset) & gpio_mask; @@ -274,7 +323,7 @@ static void dio48e_irq_mask(struct irq_data *data) if (!dio48egpio->irq_mask) /* disable interrupts */ - ioread8(dio48egpio->base + 0xB); + ioread8(&dio48egpio->reg->enable_interrupt); raw_spin_unlock_irqrestore(&dio48egpio->lock, flags); } @@ -294,8 +343,8 @@ static void dio48e_irq_unmask(struct irq_data *data) 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); } if (offset == 19) @@ -341,7 +390,7 @@ static irqreturn_t dio48e_irq_handler(int irq, void *dev_id) raw_spin_lock(&dio48egpio->lock); - iowrite8(0x00, dio48egpio->base + 0xF); + iowrite8(0x00, &dio48egpio->reg->clear_interrupt); raw_spin_unlock(&dio48egpio->lock); @@ -373,11 +422,25 @@ 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->base + 0xB); + ioread8(&dio48egpio->reg->enable_interrupt); return 0; } +static void dio48e_init_ppi(struct i8255_reg __iomem *const ppi) +{ + /* Activate Mode Set; set Mode 0 output mode for Port A, B, and C */ + iowrite8(0x80, &ppi->control); + + /* Initialize all GPIO to 0 */ + iowrite8(0x00, &ppi->port[0]); + iowrite8(0x00, &ppi->port[1]); + iowrite8(0x00, &ppi->port[2]); + + /* Deactivate Mode Set */ + iowrite8(0x00, &ppi->control); +} + static int dio48e_probe(struct device *dev, unsigned int id) { struct dio48e_gpio *dio48egpio; @@ -395,8 +458,8 @@ static int dio48e_probe(struct device *dev, unsigned int id) return -EBUSY; } - dio48egpio->base = devm_ioport_map(dev, base[id], DIO48E_EXTENT); - if (!dio48egpio->base) + dio48egpio->reg = devm_ioport_map(dev, base[id], DIO48E_EXTENT); + if (!dio48egpio->reg) return -ENOMEM; dio48egpio->chip.label = name; @@ -426,16 +489,8 @@ static int dio48e_probe(struct device *dev, unsigned int id) raw_spin_lock_init(&dio48egpio->lock); /* 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[0]); + dio48e_init_ppi(&dio48egpio->reg->ppi[1]); err = devm_gpiochip_add_data(dev, &dio48egpio->chip, dio48egpio); if (err) { From patchwork Mon Jun 6 14:33:17 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: 579661 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 077FACCA483 for ; Mon, 6 Jun 2022 14:36:27 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S239927AbiFFOgZ (ORCPT ); Mon, 6 Jun 2022 10:36:25 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:38460 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S239913AbiFFOgT (ORCPT ); Mon, 6 Jun 2022 10:36:19 -0400 Received: from mail-ot1-x330.google.com (mail-ot1-x330.google.com [IPv6:2607:f8b0:4864:20::330]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id D791212FEFB for ; Mon, 6 Jun 2022 07:36:11 -0700 (PDT) Received: by mail-ot1-x330.google.com with SMTP id r12-20020a056830448c00b0060aec7b7a54so10879082otv.5 for ; Mon, 06 Jun 2022 07:36:11 -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=D9soskDv6KXVPHCaTa4CNNvs92+O4+arQnAcZVRZbT0=; b=qBquZDqP7VN6yh7Mp0E/g0yyjt5kNSP8AK3EnE54P/q3yE3LlMoH2/TEmIg2UJQnWU /Fqmnmsrc3D+Ljh2XgbU8/RjSZg+lG58HAstpsi6q6hW4k8kqkq4Bc4LetEO5flXiTZ1 bV8to5CFT3LbggX0tH+FgaWAzs+KPxVsO29F7lwhHtUKEtmkJkcVtINQyAp67s9UuN2n 45cS26ygVyD9OZGNrb65rdSchWZxmSvBZEdHQ3uphO3uoYuq2sRzVJ9sINYPnT5KGvtr T0uYdpVF+UUK9X069Wmm2ynwH7Vmtx0vExFcopTEg9+8Pz8y5YkV2ihO32DMv9KJKoqb xPJw== 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=D9soskDv6KXVPHCaTa4CNNvs92+O4+arQnAcZVRZbT0=; b=cLGGUf2i8l/FRYdiRvM1ldUk92lEn8yUc7IYg0bjiPoxCEEdJgyMmzSfVmV5l6Wj0Y TxHYwJr1RTBipAT1oGkhS9kZMdQKDLvV8Fi4yVEFJrfuqUi6tZ6wijUsHL2itafrChjZ cpsf3mQ9Dpep5oGUgYUALaVTC7TRBOaJMOf5HGer9mJmXXqujBVI/VzW8eAgRAkb4Uug iMhf5j3wksnHQtPTr/YG6LedrCk/4mYsHb1sxGZJW7ikEKPV8UOvGu6N8xLkQxiAx2GJ UE+CUJebCM4FZkbXq5GexcmprhG+8YRA/Irp7fo6z1Xa9Rhi6u0Qw9B3nCrJI8xlKD1x fokw== X-Gm-Message-State: AOAM531Kc6z3xPGM8S5oSq6NYIX5300EjaOdTJGdNXajUHsRrn2Xbsaq 7mQTrwqkmGaGk9OSJtBiG2Lz+A== X-Google-Smtp-Source: ABdhPJz6P2zs40Kr7rXerX3QlSpEo4I+NPEWZJBS7kHMKTpI2K63060Uy3lUZZaayRlZWc6OnQM0og== X-Received: by 2002:a9d:129:0:b0:60b:23b5:1659 with SMTP id 38-20020a9d0129000000b0060b23b51659mr9942070otu.26.1654526170952; Mon, 06 Jun 2022 07:36:10 -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 u13-20020a056871008d00b000f5d4e5b9a0sm6942791oaa.2.2022.06.06.07.36.10 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 06 Jun 2022 07:36:10 -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 Subject: [PATCH 2/5] gpio: 104-idi-48: Implement and utilize register structures Date: Mon, 6 Jun 2022 10:33:17 -0400 Message-Id: <0a893282333f195a208aa8c9fa3f38e447452abd.1654525394.git.william.gray@linaro.org> X-Mailer: git-send-email 2.36.1 In-Reply-To: References: MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-gpio@vger.kernel.org Reduce magic numbers and improve code readability by implementing and utilizing named register data structures. Signed-off-by: William Breathitt Gray --- drivers/gpio/gpio-104-idi-48.c | 128 ++++++++++++++++----------------- 1 file changed, 63 insertions(+), 65 deletions(-) diff --git a/drivers/gpio/gpio-104-idi-48.c b/drivers/gpio/gpio-104-idi-48.c index 9521ece3ebef..1f8c556d9013 100644 --- a/drivers/gpio/gpio-104-idi-48.c +++ b/drivers/gpio/gpio-104-idi-48.c @@ -20,6 +20,7 @@ #include #include #include +#include #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"); +/** + * 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; }; @@ -64,39 +80,38 @@ 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 = gpiochip_get_data(chip); - unsigned i; - static const unsigned int register_offset[6] = { 0, 1, 2, 4, 5, 6 }; - void __iomem *port_addr; - unsigned mask; - - for (i = 0; i < 48; i += 8) - if (offset < i + 8) { - port_addr = idi48gpio->base + register_offset[i / 8]; - mask = BIT(offset - i); - - return !!(ioread8(port_addr) & mask); - } - - /* The following line should never execute since offset < 48 */ - return 0; + struct idi_48_reg __iomem *const reg = idi48gpio->reg; + const unsigned long boundary = offset / 8; + const unsigned long group = boundary / 3; + u8 __iomem *const port_addr = group ? reg->port1 : reg->port0; + const unsigned long in_port = boundary - (group * 3); + const unsigned long mask = BIT(offset % 8); + + return !!(ioread8(port_addr + in_port) & mask); } 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); + struct idi_48_reg __iomem *const reg = idi48gpio->reg; unsigned long offset; unsigned long gpio_mask; - static const size_t ports[] = { 0, 1, 2, 4, 5, 6 }; - void __iomem *port_addr; + unsigned long boundary; + unsigned long group; + unsigned long in_port; + u8 __iomem *port_addr; unsigned long port_state; /* clear bits array to a clean slate */ bitmap_zero(bits, chip->ngpio); - for_each_set_clump8(offset, gpio_mask, mask, ARRAY_SIZE(ports) * 8) { - port_addr = idi48gpio->base + ports[offset / 8]; - port_state = ioread8(port_addr) & gpio_mask; + for_each_set_clump8(offset, gpio_mask, mask, chip->ngpio) { + boundary = offset / 8; + group = boundary / 3; + port_addr = group ? reg->port1 : reg->port0; + in_port = boundary - (group * 3); + port_state = ioread8(port_addr + in_port) & gpio_mask; bitmap_set_value8(bits, port_state, offset); } @@ -113,30 +128,21 @@ 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 offset = irqd_to_hwirq(data); - unsigned i; - unsigned mask; - unsigned boundary; + const unsigned long boundary = offset / 8; + const unsigned long mask = BIT(offset % 8); unsigned long flags; - for (i = 0; i < 48; i += 8) - if (offset < i + 8) { - mask = BIT(offset - i); - boundary = i / 8; - - idi48gpio->irq_mask[boundary] &= ~mask; - - if (!idi48gpio->irq_mask[boundary]) { - idi48gpio->cos_enb &= ~BIT(boundary); - - raw_spin_lock_irqsave(&idi48gpio->lock, flags); + idi48gpio->irq_mask[boundary] &= ~mask; - iowrite8(idi48gpio->cos_enb, idi48gpio->base + 7); + /* Exit early if there are still input lines with IRQ unmasked */ + if (idi48gpio->irq_mask[boundary]) + return; - raw_spin_unlock_irqrestore(&idi48gpio->lock, flags); - } + idi48gpio->cos_enb &= ~BIT(boundary); - return; - } + raw_spin_lock_irqsave(&idi48gpio->lock, flags); + iowrite8(idi48gpio->cos_enb, &idi48gpio->reg->irq); + raw_spin_unlock_irqrestore(&idi48gpio->lock, flags); } static void idi_48_irq_unmask(struct irq_data *data) @@ -144,32 +150,24 @@ 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 offset = irqd_to_hwirq(data); - unsigned i; - unsigned mask; - unsigned boundary; + const unsigned long boundary = offset / 8; + const unsigned long mask = BIT(offset % 8); unsigned prev_irq_mask; unsigned long flags; - for (i = 0; i < 48; i += 8) - if (offset < i + 8) { - mask = BIT(offset - i); - boundary = i / 8; - prev_irq_mask = idi48gpio->irq_mask[boundary]; - - idi48gpio->irq_mask[boundary] |= mask; + prev_irq_mask = idi48gpio->irq_mask[boundary]; - if (!prev_irq_mask) { - idi48gpio->cos_enb |= BIT(boundary); + idi48gpio->irq_mask[boundary] |= mask; - raw_spin_lock_irqsave(&idi48gpio->lock, flags); + /* Exit early if IRQ was already unmasked for this boundary */ + if (prev_irq_mask) + return; - iowrite8(idi48gpio->cos_enb, idi48gpio->base + 7); + idi48gpio->cos_enb |= BIT(boundary); - 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); } static int idi_48_irq_set_type(struct irq_data *data, unsigned flow_type) @@ -204,7 +202,7 @@ static irqreturn_t idi_48_irq_handler(int irq, void *dev_id) raw_spin_lock(&idi48gpio->lock); - cos_status = ioread8(idi48gpio->base + 7); + cos_status = ioread8(&idi48gpio->reg->irq); raw_spin_unlock(&idi48gpio->lock); @@ -250,8 +248,8 @@ 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->base + 7); - ioread8(idi48gpio->base + 7); + iowrite8(0, &idi48gpio->reg->irq); + ioread8(&idi48gpio->reg->irq); return 0; } @@ -273,8 +271,8 @@ static int idi_48_probe(struct device *dev, unsigned int id) return -EBUSY; } - idi48gpio->base = devm_ioport_map(dev, base[id], IDI_48_EXTENT); - if (!idi48gpio->base) + idi48gpio->reg = devm_ioport_map(dev, base[id], IDI_48_EXTENT); + if (!idi48gpio->reg) return -ENOMEM; idi48gpio->chip.label = name; From patchwork Mon Jun 6 14:33:18 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: 579149 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 395F3C433EF for ; Mon, 6 Jun 2022 14:36:26 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S239809AbiFFOgX (ORCPT ); Mon, 6 Jun 2022 10:36:23 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:38462 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S239901AbiFFOgT (ORCPT ); Mon, 6 Jun 2022 10:36:19 -0400 Received: from mail-ot1-x334.google.com (mail-ot1-x334.google.com [IPv6:2607:f8b0:4864:20::334]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id C5529131F02 for ; Mon, 6 Jun 2022 07:36:12 -0700 (PDT) Received: by mail-ot1-x334.google.com with SMTP id e11-20020a9d6e0b000000b0060afcbafa80so10882650otr.3 for ; Mon, 06 Jun 2022 07:36:12 -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=Q2777MlCrWf6jryTiFZsDg5chGgCdhRgryHt5py+rzE=; b=diH8ZiHRZY9FdSSg+r7mCyQm4v39feHVxKCXY+sivbww1p9dhsxV3I0Baqr7+TeVyB irIbsOItz9rYAOnVKfXbV9utUyGnuxnVizZR8EYJYJKpaYfFug+W9+jXT6n1MjZPuWhh Q25u1XZj1vz6lp9Lc/N4vtrlskijlOh0rfAFtBrZrZpadx9i+3/L+TWzz418/sDJ4b1z knOFBRlOXeeavEYZY5KnvUIot+IuZOcyoNOzuahk8qVoca5uUPQrATdA0ha/2S/V5I0M QDov0776gS41vaqKgHOdkMP0q0S1cLW6nQXIBfshsiZcu67HACYKn+oJpywAxFg/TCGC F0bQ== 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=Q2777MlCrWf6jryTiFZsDg5chGgCdhRgryHt5py+rzE=; b=p7eZK6ACJGbrYpL9TSWTUqTfPzerYCrpoD8aUlpHw84izhPGsTfyoYvPTHXtJxgpfL 76hdnQneUnvzJDkkp6V86yLX4aLBAiaUO5g0Y3n0excokJl4tvg98Bx8Bj4CuHHLr/Zm hC6aMO/lZsxmRARLs8Pk2ug18qeKm0MmXJqYMcrOegUL1dugVsJvPEi3gy+m+17V6VL4 46KxlXRAV31oofFpyW2mWx0ReXfDq4hHzwIKGvdIA1P8zvy2ZGIiYAYIM1sLHus3sYKS auJy1BCE6Lmv9obcSMSGdn6S5YmCIKF9nie1Mvv6hk/IOPa3EKQnGOp0OtrGFq/wK9Bm Vk+g== X-Gm-Message-State: AOAM532uv3cem8dRn/eb50wTu20DV8p/R54r+PDZFfF2AUAHTfbjLcFW QnaOxTsQd5/aLd0Jj7f3eK2uOA== X-Google-Smtp-Source: ABdhPJwK6LANYJEn1qcfJ4u+9iQE0OOYcHswotmAQeDnQnoBMVzE/2VQEMs7e4dwb0BqvjEG9Ip3VA== X-Received: by 2002:a9d:6250:0:b0:60b:e6cf:4942 with SMTP id i16-20020a9d6250000000b0060be6cf4942mr5669186otk.278.1654526171894; Mon, 06 Jun 2022 07:36:11 -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 u13-20020a056871008d00b000f5d4e5b9a0sm6942791oaa.2.2022.06.06.07.36.11 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 06 Jun 2022 07:36:11 -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 Subject: [PATCH 3/5] gpio: 104-idio-16: Implement and utilize register structures Date: Mon, 6 Jun 2022 10:33:18 -0400 Message-Id: X-Mailer: git-send-email 2.36.1 In-Reply-To: References: MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-gpio@vger.kernel.org Reduce magic numbers and improve code readability by implementing and utilizing named register data structures. 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-16.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 #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"); +/** + * 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; }; @@ -79,9 +103,9 @@ static int idio_16_gpio_get(struct gpio_chip *chip, unsigned int offset) return -EINVAL; if (offset < 24) - return !!(ioread8(idio16gpio->base + 1) & mask); + return !!(ioread8(&idio16gpio->reg->in0_7) & mask); - return !!(ioread8(idio16gpio->base + 5) & (mask>>8)); + return !!(ioread8(&idio16gpio->reg->in8_15) & (mask>>8)); } 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 *chip, *bits = 0; if (*mask & GENMASK(23, 16)) - *bits |= (unsigned long)ioread8(idio16gpio->base + 1) << 16; + *bits |= (unsigned long)ioread8(&idio16gpio->reg->in0_7) << 16; if (*mask & GENMASK(31, 24)) - *bits |= (unsigned long)ioread8(idio16gpio->base + 5) << 24; + *bits |= (unsigned long)ioread8(&idio16gpio->reg->in8_15) << 24; return 0; } @@ -116,9 +140,9 @@ static void idio_16_gpio_set(struct gpio_chip *chip, unsigned int offset, idio16gpio->out_state &= ~mask; 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); 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 |= *mask & *bits; 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); 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); - iowrite8(0, idio16gpio->base + 2); + iowrite8(0, &idio16gpio->reg->irq_ctl); 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); - ioread8(idio16gpio->base + 2); + ioread8(&idio16gpio->reg->irq_ctl); raw_spin_unlock_irqrestore(&idio16gpio->lock, flags); } @@ -212,7 +236,7 @@ static irqreturn_t idio_16_irq_handler(int irq, void *dev_id) raw_spin_lock(&idio16gpio->lock); - iowrite8(0, idio16gpio->base + 1); + iowrite8(0, &idio16gpio->reg->in0_7); raw_spin_unlock(&idio16gpio->lock); @@ -232,8 +256,8 @@ static int idio_16_irq_init_hw(struct gpio_chip *gc) struct idio_16_gpio *const idio16gpio = gpiochip_get_data(gc); /* 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); return 0; } @@ -255,8 +279,8 @@ static int idio_16_probe(struct device *dev, unsigned int id) return -EBUSY; } - idio16gpio->base = devm_ioport_map(dev, base[id], IDIO_16_EXTENT); - if (!idio16gpio->base) + idio16gpio->reg = devm_ioport_map(dev, base[id], IDIO_16_EXTENT); + if (!idio16gpio->reg) return -ENOMEM; idio16gpio->chip.label = name; From patchwork Mon Jun 6 14:33:19 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: 579150 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 88FF7C433EF for ; Mon, 6 Jun 2022 14:36:23 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S239923AbiFFOgW (ORCPT ); Mon, 6 Jun 2022 10:36:22 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:38332 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S239832AbiFFOgV (ORCPT ); Mon, 6 Jun 2022 10:36:21 -0400 Received: from mail-ot1-x330.google.com (mail-ot1-x330.google.com [IPv6:2607:f8b0:4864:20::330]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 9081E13392C for ; Mon, 6 Jun 2022 07:36:13 -0700 (PDT) Received: by mail-ot1-x330.google.com with SMTP id r14-20020a056830418e00b0060b8da9ff75so10861935otu.11 for ; Mon, 06 Jun 2022 07:36:13 -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=7G/D0jrlvNgMc+Tde0XVhDy5Wvyd9twlgo7j0TICrRc=; b=niXsWsKtWaVclpeC3TuRqVL1gv/xiSdzbpfZBGPvo0JeRr1OVIO82F5WbhdFjcB//4 8By7sa2TDe1Bo0i1L7FUiFEurXjSReM/UKd30yUHG0AQNZd4wI8t/A9W78T04H4R1gbi VTgAvArN4LOqQO2k87PUZAiIyo9w98XM7MWQlvWNVno9wmPq6VaBtcMpBq7AOIuiw9nh Oyzh35dF666yIYgUnbeovalOS396uhlPO05sF+HMm55Zd+g+tMiungG0sGyVo5Itd/gL nidcFegF3kbBDl106IchsNJuUp+rfBXcHRQNxNn4KPGkO4yLipEd6Ottt09Jy2WclR4H o/KA== 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=7G/D0jrlvNgMc+Tde0XVhDy5Wvyd9twlgo7j0TICrRc=; b=4VXiMyKycVEvz+IFnfH0XSmww3CjjrtJIPvzwF631AszR2t8L8hkq+S/EbIwNotrpU 1qVk8kd5Eme9syaSUTkX3qyL5Go5aR/jmxh63IqqB034DZfW8kJrF0K0FV6+nlt19AFi DchRqauMPm25L68TOXW4EUMWWwRgMyvxV8/s+GfSISctRgyQrZ/FQCSUDq+M4wyh6L0e 3C67zaIkXY/2l6wuTy9wnW7JQ+AlCHMEOu2bcXODEdn62tpHVYtCC2TSgILG68zfqT/c x+8m6EUbMdhjWLm2DHv7DhxiNd69imwmy5j7G/i6t6wa+2aIpeqFL7L3LrBA9ZoSt9Fh cUmA== X-Gm-Message-State: AOAM532Glzk60T2R47uvK7t7upoBtsnZ7dp5ygzrpPzjMiia4m8rJxBT gGlskECevR8NNgQOi2IbpP3SqokNk850XA== X-Google-Smtp-Source: ABdhPJzkR5XFlreMYTBXKawn5WYoiJ7aAGM+h9awXDBuTc024Dti6K+voL1nOEzn8EhccycZHf8H6Q== X-Received: by 2002:a9d:4c6:0:b0:60b:537c:f4c1 with SMTP id 64-20020a9d04c6000000b0060b537cf4c1mr10492707otm.16.1654526172844; Mon, 06 Jun 2022 07:36:12 -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 u13-20020a056871008d00b000f5d4e5b9a0sm6942791oaa.2.2022.06.06.07.36.12 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 06 Jun 2022 07:36:12 -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 Subject: [PATCH 4/5] gpio: gpio-mm: Implement and utilize register structures Date: Mon, 6 Jun 2022 10:33:19 -0400 Message-Id: X-Mailer: git-send-email 2.36.1 In-Reply-To: References: MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-gpio@vger.kernel.org Reduce magic numbers and improve code readability by implementing and utilizing named register data structures. Signed-off-by: William Breathitt Gray --- drivers/gpio/gpio-gpio-mm.c | 116 ++++++++++++++++++++++-------------- 1 file changed, 72 insertions(+), 44 deletions(-) diff --git a/drivers/gpio/gpio-gpio-mm.c b/drivers/gpio/gpio-gpio-mm.c index 097a06463d01..8f67442b8715 100644 --- a/drivers/gpio/gpio-gpio-mm.c +++ b/drivers/gpio/gpio-gpio-mm.c @@ -27,6 +27,16 @@ static unsigned int num_gpiomm; module_param_hw_array(base, uint, ioport, &num_gpiomm, 0); MODULE_PARM_DESC(base, "Diamond Systems GPIO-MM base addresses"); +/** + * struct i8255_reg - Intel 8255 register structure + * @port: Port A, B, and C + * @control: Control register + */ +struct i8255_reg { + u8 port[3]; + u8 control; +}; + /** * struct gpiomm_gpio - GPIO device private data structure * @chip: instance of the gpio_chip @@ -34,7 +44,7 @@ MODULE_PARM_DESC(base, "Diamond Systems GPIO-MM base addresses"); * @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 + * @dio: Digital I/O register groups */ struct gpiomm_gpio { struct gpio_chip chip; @@ -42,7 +52,7 @@ struct gpiomm_gpio { unsigned char out_state[6]; unsigned char control[2]; spinlock_t lock; - void __iomem *base; + struct i8255_reg __iomem *dio; }; static int gpiomm_gpio_get_direction(struct gpio_chip *chip, @@ -63,32 +73,33 @@ static int gpiomm_gpio_direction_input(struct gpio_chip *chip, { struct gpiomm_gpio *const gpiommgpio = gpiochip_get_data(chip); const unsigned int io_port = offset / 8; - const unsigned int control_port = io_port / 3; + const unsigned long group = io_port / 3; + const unsigned long port = io_port - (group * 3); unsigned long flags; unsigned int control; spin_lock_irqsave(&gpiommgpio->lock, flags); /* Check if configuring Port C */ - if (io_port == 2 || io_port == 5) { + if (port == 2) { /* Port C can be configured by nibble */ if (offset % 8 > 3) { gpiommgpio->io_state[io_port] |= 0xF0; - gpiommgpio->control[control_port] |= BIT(3); + gpiommgpio->control[group] |= BIT(3); } else { gpiommgpio->io_state[io_port] |= 0x0F; - gpiommgpio->control[control_port] |= BIT(0); + gpiommgpio->control[group] |= BIT(0); } } else { gpiommgpio->io_state[io_port] |= 0xFF; - if (io_port == 0 || io_port == 3) - gpiommgpio->control[control_port] |= BIT(4); + if (port == 0) + gpiommgpio->control[group] |= BIT(4); else - gpiommgpio->control[control_port] |= BIT(1); + gpiommgpio->control[group] |= BIT(1); } - control = BIT(7) | gpiommgpio->control[control_port]; - iowrite8(control, gpiommgpio->base + 3 + control_port*4); + control = BIT(7) | gpiommgpio->control[group]; + iowrite8(control, &gpiommgpio->dio[group].control); spin_unlock_irqrestore(&gpiommgpio->lock, flags); @@ -100,30 +111,31 @@ static int gpiomm_gpio_direction_output(struct gpio_chip *chip, { struct gpiomm_gpio *const gpiommgpio = gpiochip_get_data(chip); const unsigned int io_port = offset / 8; - const unsigned int control_port = io_port / 3; + const unsigned long group = io_port / 3; + const unsigned long port = io_port - (group * 3); const unsigned int mask = BIT(offset % 8); - const unsigned int out_port = (io_port > 2) ? io_port + 1 : io_port; + struct i8255_reg __iomem *const dio = gpiommgpio->dio + group; unsigned long flags; unsigned int control; spin_lock_irqsave(&gpiommgpio->lock, flags); /* Check if configuring Port C */ - if (io_port == 2 || io_port == 5) { + if (port == 2) { /* Port C can be configured by nibble */ if (offset % 8 > 3) { gpiommgpio->io_state[io_port] &= 0x0F; - gpiommgpio->control[control_port] &= ~BIT(3); + gpiommgpio->control[group] &= ~BIT(3); } else { gpiommgpio->io_state[io_port] &= 0xF0; - gpiommgpio->control[control_port] &= ~BIT(0); + gpiommgpio->control[group] &= ~BIT(0); } } else { gpiommgpio->io_state[io_port] &= 0x00; - if (io_port == 0 || io_port == 3) - gpiommgpio->control[control_port] &= ~BIT(4); + if (port == 0) + gpiommgpio->control[group] &= ~BIT(4); else - gpiommgpio->control[control_port] &= ~BIT(1); + gpiommgpio->control[group] &= ~BIT(1); } if (value) @@ -131,10 +143,10 @@ static int gpiomm_gpio_direction_output(struct gpio_chip *chip, else gpiommgpio->out_state[io_port] &= ~mask; - control = BIT(7) | gpiommgpio->control[control_port]; - iowrite8(control, gpiommgpio->base + 3 + control_port*4); + control = BIT(7) | gpiommgpio->control[group]; + iowrite8(control, &dio->control); - iowrite8(gpiommgpio->out_state[io_port], gpiommgpio->base + out_port); + iowrite8(gpiommgpio->out_state[io_port], dio->port + port); spin_unlock_irqrestore(&gpiommgpio->lock, flags); @@ -146,7 +158,8 @@ static int gpiomm_gpio_get(struct gpio_chip *chip, unsigned int offset) struct gpiomm_gpio *const gpiommgpio = gpiochip_get_data(chip); const unsigned int port = offset / 8; const unsigned int mask = BIT(offset % 8); - const unsigned int in_port = (port > 2) ? port + 1 : port; + const unsigned long group = port / 3; + const unsigned long in_port = port - (group * 3); unsigned long flags; unsigned int port_state; @@ -158,29 +171,33 @@ static int gpiomm_gpio_get(struct gpio_chip *chip, unsigned int offset) return -EINVAL; } - port_state = ioread8(gpiommgpio->base + in_port); + port_state = ioread8(gpiommgpio->dio[group].port + in_port); spin_unlock_irqrestore(&gpiommgpio->lock, flags); return !!(port_state & mask); } -static const size_t ports[] = { 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 = gpiochip_get_data(chip); unsigned long offset; unsigned long gpio_mask; - void __iomem *port_addr; + unsigned long port; + unsigned long group; + unsigned long in_port; + u8 __iomem *port_addr; unsigned long port_state; /* clear bits array to a clean slate */ bitmap_zero(bits, chip->ngpio); - for_each_set_clump8(offset, gpio_mask, mask, ARRAY_SIZE(ports) * 8) { - port_addr = gpiommgpio->base + ports[offset / 8]; + for_each_set_clump8(offset, gpio_mask, mask, chip->ngpio) { + port = offset / 8; + group = port / 3; + in_port = port - (group * 3); + port_addr = gpiommgpio->dio[group].port + in_port; port_state = ioread8(port_addr) & gpio_mask; bitmap_set_value8(bits, port_state, offset); @@ -195,7 +212,8 @@ static void gpiomm_gpio_set(struct gpio_chip *chip, unsigned int offset, struct gpiomm_gpio *const gpiommgpio = gpiochip_get_data(chip); const unsigned int port = offset / 8; const unsigned int mask = BIT(offset % 8); - const unsigned int out_port = (port > 2) ? port + 1 : port; + const unsigned long group = port / 3; + const unsigned long out_port = port - (group * 3); unsigned long flags; spin_lock_irqsave(&gpiommgpio->lock, flags); @@ -205,7 +223,8 @@ static void gpiomm_gpio_set(struct gpio_chip *chip, unsigned int offset, else gpiommgpio->out_state[port] &= ~mask; - iowrite8(gpiommgpio->out_state[port], gpiommgpio->base + out_port); + iowrite8(gpiommgpio->out_state[port], + gpiommgpio->dio[group].port + out_port); spin_unlock_irqrestore(&gpiommgpio->lock, flags); } @@ -217,13 +236,17 @@ static void gpiomm_gpio_set_multiple(struct gpio_chip *chip, unsigned long offset; unsigned long gpio_mask; size_t index; - void __iomem *port_addr; + size_t group; + size_t out_port; + u8 __iomem *port_addr; unsigned long bitmask; unsigned long flags; - for_each_set_clump8(offset, gpio_mask, mask, ARRAY_SIZE(ports) * 8) { + for_each_set_clump8(offset, gpio_mask, mask, chip->ngpio) { index = offset / 8; - port_addr = gpiommgpio->base + ports[index]; + group = index / 3; + out_port = index - (group * 3); + port_addr = gpiommgpio->dio[group].port + out_port; bitmask = bitmap_get_value8(bits, offset) & gpio_mask; @@ -250,6 +273,17 @@ 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_reg __iomem *const dio) +{ + /* Activate Mode Set; set Mode 0 output mode for Port A, B, and C */ + iowrite8(0x80, &dio->control); + + /* Initialize all GPIO to 0 */ + iowrite8(0x00, &dio->port[0]); + iowrite8(0x00, &dio->port[1]); + iowrite8(0x00, &dio->port[2]); +} + static int gpiomm_probe(struct device *dev, unsigned int id) { struct gpiomm_gpio *gpiommgpio; @@ -266,8 +300,8 @@ static int gpiomm_probe(struct device *dev, unsigned int id) return -EBUSY; } - gpiommgpio->base = devm_ioport_map(dev, base[id], GPIOMM_EXTENT); - if (!gpiommgpio->base) + gpiommgpio->dio = devm_ioport_map(dev, base[id], GPIOMM_EXTENT); + if (!gpiommgpio->dio) return -ENOMEM; gpiommgpio->chip.label = name; @@ -293,14 +327,8 @@ static int gpiomm_probe(struct device *dev, unsigned int id) } /* 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->dio[0]); + gpiomm_init_dio(&gpiommgpio->dio[1]); return 0; } From patchwork Mon Jun 6 14:33:20 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: 579662 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 093AEC43334 for ; Mon, 6 Jun 2022 14:36:25 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S239943AbiFFOgX (ORCPT ); Mon, 6 Jun 2022 10:36:23 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:38392 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S239837AbiFFOgV (ORCPT ); Mon, 6 Jun 2022 10:36:21 -0400 Received: from mail-ot1-x32e.google.com (mail-ot1-x32e.google.com [IPv6:2607:f8b0:4864:20::32e]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 00E0A1339FB for ; Mon, 6 Jun 2022 07:36:14 -0700 (PDT) Received: by mail-ot1-x32e.google.com with SMTP id 61-20020a9d0bc3000000b0060b9bfcfe76so10874145oth.9 for ; Mon, 06 Jun 2022 07:36:14 -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=/Y0M6xu1GLZK7ZGrwULwxb7+/2I3xvkk3luUj/TCV1w=; b=vKVh+3cn1sqO6NjItSr8bIrjy5N6mODxNhLm7BkT42S6ggxLyfV4rUVJbuCJKgG6ux 10LO6VLEaEyKtgxi4xtzXcYwK/TtyzOYjPna7rCVZwSHpnRmIJXAenU0NYYGXMMENo5s Dy7oZb/r04kcnJuX9AlHFIeIMnuRi91XjS0uKmGSVrjsMo0HlwDJ37i5QoeowbHiSlT+ i+Z3uHg4F/HnPfW8SaxX8Hrwy+yc3GQ4oZxHIni8HcDOfj+0FFzUJC0RabmTs/c8o47j ztZ/6l/4cpQILHRsNnMhtPtz36xuCuODcZKwaVhohY0c88cfj9/yuGhtxcDNtqo89k1n TzQQ== 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=/Y0M6xu1GLZK7ZGrwULwxb7+/2I3xvkk3luUj/TCV1w=; b=dbUyBc9j28deSqYdPPKq+BXPnqmxY/UPrhUohOUzTDo7d2jqL/Esrnrs/DrW7O/dvH g8rlTfTJ3mqSX/OtUWa8oQ1rTli5UUWhrWat/a8OPJiDiooB6GTz5a6A2IQwxu/RCsU6 CnmfZ5xr/D7EcOHiE/o2UJ/LpNUXLROE5LY/78xTOm7TDDf/YmBE8BUIb6Q/z3Qt2+m+ yehwKtvCZm/eJKmyqqqkCyXSSnQ5nB82C/tjUHTOak6fHJbfzUr3lA6Cxaxd+5VwFEha UFPZ/skr+5H702opYcGJRPwlseQIf05DE3+6gFxdVUX2J/5OPMED9LB/tNy+r64vmN/O u7jw== X-Gm-Message-State: AOAM530WdQw4Rd2EO14iiFGCsUfggXdaeu1seORBsi60J+SyHU44NpBx shEOaYM53UM7SOyh3Rhu11LE5g== X-Google-Smtp-Source: ABdhPJw0Bv8CWzQuDCGPXI/7xIJd7fqqhe0U+v5fXafIjzmN+St0QQYWG4P8olpSVj+0p6AtjoHxKw== X-Received: by 2002:a05:6830:54d:b0:606:a7d6:f809 with SMTP id l13-20020a056830054d00b00606a7d6f809mr10494401otb.139.1654526174292; Mon, 06 Jun 2022 07:36:14 -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 u13-20020a056871008d00b000f5d4e5b9a0sm6942791oaa.2.2022.06.06.07.36.13 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 06 Jun 2022 07:36:13 -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 Subject: [PATCH 5/5] gpio: ws16c48: Implement and utilize register structures Date: Mon, 6 Jun 2022 10:33:20 -0400 Message-Id: <2991a4f1db1f12be499124e0059be23535894dad.1654525394.git.william.gray@linaro.org> X-Mailer: git-send-email 2.36.1 In-Reply-To: References: MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-gpio@vger.kernel.org Reduce magic numbers and improve code readability by implementing and utilizing named register data structures. 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 -#define WS16C48_EXTENT 16 +#define WS16C48_EXTENT 10 #define MAX_NUM_WS16C48 max_num_isa_dev(WS16C48_EXTENT) 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"); +/** + * 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; }; static int ws16c48_gpio_get_direction(struct gpio_chip *chip, unsigned offset) @@ -73,7 +88,7 @@ static int ws16c48_gpio_direction_input(struct gpio_chip *chip, unsigned offset) ws16c48gpio->io_state[port] |= mask; ws16c48gpio->out_state[port] &= ~mask; - iowrite8(ws16c48gpio->out_state[port], ws16c48gpio->base + port); + iowrite8(ws16c48gpio->out_state[port], ws16c48gpio->reg->port + port); raw_spin_unlock_irqrestore(&ws16c48gpio->lock, flags); @@ -95,7 +110,7 @@ static int ws16c48_gpio_direction_output(struct gpio_chip *chip, ws16c48gpio->out_state[port] |= mask; else ws16c48gpio->out_state[port] &= ~mask; - iowrite8(ws16c48gpio->out_state[port], ws16c48gpio->base + port); + iowrite8(ws16c48gpio->out_state[port], ws16c48gpio->reg->port + port); raw_spin_unlock_irqrestore(&ws16c48gpio->lock, flags); @@ -118,7 +133,7 @@ static int ws16c48_gpio_get(struct gpio_chip *chip, unsigned offset) return -EINVAL; } - port_state = ioread8(ws16c48gpio->base + port); + port_state = ioread8(ws16c48gpio->reg->port + port); raw_spin_unlock_irqrestore(&ws16c48gpio->lock, flags); @@ -131,14 +146,16 @@ static int ws16c48_gpio_get_multiple(struct gpio_chip *chip, struct ws16c48_gpio *const ws16c48gpio = 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; /* clear bits array to a clean slate */ bitmap_zero(bits, chip->ngpio); for_each_set_clump8(offset, gpio_mask, mask, chip->ngpio) { - port_addr = ws16c48gpio->base + offset / 8; + index = offset / 8; + port_addr = ws16c48gpio->reg->port + index; port_state = ioread8(port_addr) & gpio_mask; bitmap_set_value8(bits, port_state, offset); @@ -166,7 +183,7 @@ static void ws16c48_gpio_set(struct gpio_chip *chip, unsigned offset, int value) ws16c48gpio->out_state[port] |= mask; else ws16c48gpio->out_state[port] &= ~mask; - iowrite8(ws16c48gpio->out_state[port], ws16c48gpio->base + port); + iowrite8(ws16c48gpio->out_state[port], ws16c48gpio->reg->port + port); raw_spin_unlock_irqrestore(&ws16c48gpio->lock, flags); } @@ -178,13 +195,13 @@ static void ws16c48_gpio_set_multiple(struct gpio_chip *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; for_each_set_clump8(offset, gpio_mask, mask, chip->ngpio) { index = offset / 8; - port_addr = ws16c48gpio->base + index; + port_addr = ws16c48gpio->reg->port + index; /* mask out GPIO configured for input */ gpio_mask &= ~ws16c48gpio->io_state[index]; @@ -219,10 +236,15 @@ static void ws16c48_irq_ack(struct irq_data *data) port_state = ws16c48gpio->irq_mask >> (8*port); - 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); raw_spin_unlock_irqrestore(&ws16c48gpio->lock, flags); } @@ -235,6 +257,7 @@ static void ws16c48_irq_mask(struct irq_data *data) const unsigned long mask = BIT(offset); const unsigned port = offset / 8; unsigned long flags; + unsigned long port_state; /* 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); ws16c48gpio->irq_mask &= ~mask; + port_state = ws16c48gpio->irq_mask >> (8 * port); + + /* Select Register Page 2; Unlock all I/O ports */ + iowrite8(0x80, &ws16c48gpio->reg->page_lock); - 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); raw_spin_unlock_irqrestore(&ws16c48gpio->lock, flags); } @@ -259,6 +288,7 @@ static void ws16c48_irq_unmask(struct irq_data *data) const unsigned long mask = BIT(offset); const unsigned port = offset / 8; unsigned long flags; + unsigned long port_state; /* 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); ws16c48gpio->irq_mask |= mask; + port_state = ws16c48gpio->irq_mask >> (8 * port); + + /* Select Register Page 2; Unlock all I/O ports */ + iowrite8(0x80, &ws16c48gpio->reg->page_lock); - 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); 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 = BIT(offset); const unsigned port = offset / 8; unsigned long flags; + unsigned long port_state; /* 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; } - iowrite8(0x40, ws16c48gpio->base + 7); - iowrite8(ws16c48gpio->flow_mask >> (8*port), ws16c48gpio->base + 8 + port); - iowrite8(0xC0, ws16c48gpio->base + 7); + port_state = 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); raw_spin_unlock_irqrestore(&ws16c48gpio->lock, flags); @@ -325,25 +369,26 @@ static irqreturn_t ws16c48_irq_handler(int irq, void *dev_id) { struct ws16c48_gpio *const ws16c48gpio = dev_id; struct gpio_chip *const chip = &ws16c48gpio->chip; + struct ws16c48_reg __iomem *const reg = ws16c48gpio->reg; unsigned long int_pending; unsigned long port; unsigned long int_id; unsigned long gpio; - int_pending = ioread8(ws16c48gpio->base + 6) & 0x7; + int_pending = ioread8(®->int_pending) & 0x7; if (!int_pending) return IRQ_NONE; /* loop until all pending interrupts are handled */ do { for_each_set_bit(port, &int_pending, 3) { - int_id = ioread8(ws16c48gpio->base + 8 + port); + int_id = 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); } - int_pending = ioread8(ws16c48gpio->base + 6) & 0x7; + int_pending = ioread8(®->int_pending) & 0x7; } while (int_pending); return IRQ_HANDLED; @@ -369,12 +414,16 @@ static int ws16c48_irq_init_hw(struct gpio_chip *gc) { struct ws16c48_gpio *const ws16c48gpio = gpiochip_get_data(gc); - /* 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); return 0; } @@ -396,8 +445,8 @@ static int ws16c48_probe(struct device *dev, unsigned int id) return -EBUSY; } - ws16c48gpio->base = devm_ioport_map(dev, base[id], WS16C48_EXTENT); - if (!ws16c48gpio->base) + ws16c48gpio->reg = devm_ioport_map(dev, base[id], WS16C48_EXTENT); + if (!ws16c48gpio->reg) return -ENOMEM; ws16c48gpio->chip.label = name;