From nobody Sat Apr 18 07:34: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 AD12DC433EF for ; Mon, 18 Jul 2022 20:57:03 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S236031AbiGRU5C (ORCPT ); Mon, 18 Jul 2022 16:57:02 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:55506 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S235905AbiGRU45 (ORCPT ); Mon, 18 Jul 2022 16:56:57 -0400 Received: from mail-oa1-x2f.google.com (mail-oa1-x2f.google.com [IPv6:2001:4860:4864:20::2f]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id B0B8031205 for ; Mon, 18 Jul 2022 13:56:56 -0700 (PDT) Received: by mail-oa1-x2f.google.com with SMTP id 586e51a60fabf-f2a4c51c45so27131460fac.9 for ; Mon, 18 Jul 2022 13:56:56 -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=qfhCdMOpsZoe01uOCKadmeubmrq3AS2AtKChm9Mm2Ew=; b=nq0xkd3Y0t9z3/7aqVnNs8Q/iP9VTHNx7BhH1ihKGcxJa3slrXcgvE7iRrc42sn0Iv mOu0SlHdkq6/p+Tq21ihBKTifGNxWiXQRSg7FBQmzZ1Qz4b7HZvppj4MuKBmDsQ4tUKn +gKnhSG4+2GWzvypbOQ0Zk1dOjcCpI7jbVlHHC9QEghMqXIGVxE+CWXBorzIxJ4GZ0LJ UeqblyBZyT5xg5DMLC8zN88cOI/hLuuAT+n5DL4m5Gjqb/sbO+5ZfwJISpPPYFB4MIXH KkoOR2pm2yOQqRTpJU2L68Ru3g9N2xCHqqpWePykANE25IuPVbOF/xKT1YiM38/Bwtuw b8wA== 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=qfhCdMOpsZoe01uOCKadmeubmrq3AS2AtKChm9Mm2Ew=; b=iJu6lzTki59dTl2uqHWHR6ADMwWR1b5q/VNwKMLjaQj7QDFHxfOn8M3hmjQgfJY12H M5bRG0F31MPMnVmbeY5Y/+Mc83Sf5bL/WaT1+svNtllam8YKk8p4RShJGEM1qjHdZq37 g4SChmn+sr08DVoM4Ayc2Cn9a+Z4gmH/fIVM/XePH9c5P49ns0arPKyIWK+mdy2RsKYU HD7ArNCZKm2fulKl7G5UosKal62Tdf614tgqy2GFvbeBuY2ZlaKBjNvSFVi7KMOuHDub fvFgyoaXGaTyRvCxi2K2uXxEnP+EHdo/kC8wOzx8yZq9blQy8qzJHOTPpxkpkfmp9Edb eNAA== X-Gm-Message-State: AJIora+wzOWKYhmXDP+LNOaPllv2q14NO7C9xl/j7LwJB9pYXpxuZBl8 Rso2+v5piDhV9M3sFavp7qVPCzvNYSEcXw== X-Google-Smtp-Source: AGRyM1vLc+vUMpjJrssv8DKr2V/17AypM+F+rC+VE4q9z13NZ+9/h2HFqlpIOfSrQ+X0+mPJ3iEKOQ== X-Received: by 2002:a05:6808:11c4:b0:2f9:ccd6:15a4 with SMTP id p4-20020a05680811c400b002f9ccd615a4mr14080154oiv.219.1658177815983; Mon, 18 Jul 2022 13:56:55 -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 l8-20020a4ab2c8000000b0035eb4e5a6cbsm5252065ooo.33.2022.07.18.13.56.55 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 18 Jul 2022 13:56:55 -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 , Paul Demetrotion Subject: [PATCH v3 1/6] gpio: ws16c48: Implement and utilize register structures Date: Fri, 15 Jul 2022 14:52:23 -0400 Message-Id: <50564d55e42fa64f3dbb895850761e4d152ae8ad.1657907849.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 Reviewed-by: Linus Walleij --- Changes in v3: None 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 From nobody Sat Apr 18 07:34: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 CA011C43334 for ; Mon, 18 Jul 2022 20:57:09 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S236090AbiGRU5I (ORCPT ); Mon, 18 Jul 2022 16:57:08 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:55524 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S235949AbiGRU46 (ORCPT ); Mon, 18 Jul 2022 16:56:58 -0400 Received: from mail-ot1-x32a.google.com (mail-ot1-x32a.google.com [IPv6:2607:f8b0:4864:20::32a]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id A66BB313BB for ; Mon, 18 Jul 2022 13:56:57 -0700 (PDT) Received: by mail-ot1-x32a.google.com with SMTP id a14-20020a0568300b8e00b0061c4e3eb52aso10241929otv.3 for ; Mon, 18 Jul 2022 13:56:57 -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=a4L7/kdAQx0CYbP83idet13SiXPOxhI3VQ1cN7+nTHk=; b=UnmbP+2cXKdojWTFkTV87NOKheCioCpOkEkRAbmUGe2MY//Vg6m4G0JjBtUS9fxwgQ Kp67tPeG8iALYKx1ypNJK3oopL91wI59XWdw6lFyA29OxSb/gPdSh5DTjT2Ewps//mg6 JtdxP6aZA+LB60UrxU9Ph4GjmHGlaQqoesuKu7lDg6ck096kO+VLhYrx5dRBJGqf8foN lHBSXdduTohoOk6kAYLArbr5qzTHG50ucrioD8Uc3VMJsfcGf8xHMAWd0JNr/eKe17BP vgpFU7CSJV7SpZX7BAdppXclI/SJP/3Vb8fDlJdqt19Tuf4f9XNxYwYP4DF+VY6voYM0 snMA== 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=a4L7/kdAQx0CYbP83idet13SiXPOxhI3VQ1cN7+nTHk=; b=3l5FApQTCCk0dc/JgHEtSBBP2cT/A8VuPBtnNW1hLPonLtIRAkDsgHmI67jB9zS1kU JlWckQNXjX4yUPBisB7Y3N4iiriugJKThF5EpA+18tG7TXwvkh5UOIwYsu5/MLRt3hlL VxuJmq8z2mz328ipHTeXQLPJpw8TyOoHt2U/QGhlzRW9ul2GfTcB2TVGjAjkwgZTKqWr mlTlI+u8YviIfBCjzwpzVAaGHaCTggQyeQJ0EiSdBR2LYRDIU7+s3H/X+OiGMKIuXXqi 1hPhAOiPuAm5VCUAE4mm29f9lBXlALGow4h03mVwN537Gq/xRbdJy5cbJuPeSodEHwhQ tIIQ== X-Gm-Message-State: AJIora8HmSroqtwX5rRePOTe8S3IWL6jo8Qy/FQamWeBqOaKY1Hhw4wl ERACVFro9HYHn1gHb/SyFcKlVw== X-Google-Smtp-Source: AGRyM1vCDrrxgcxhBydiMZUvF1bctsK5QN2ykIvL61qu99VZxsxMcX/PsJN3pn02LZhzr5PDLqeU2g== X-Received: by 2002:a05:6830:16c8:b0:61c:a083:8a70 with SMTP id l8-20020a05683016c800b0061ca0838a70mr3141366otr.163.1658177816873; Mon, 18 Jul 2022 13:56:56 -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 l8-20020a4ab2c8000000b0035eb4e5a6cbsm5252065ooo.33.2022.07.18.13.56.56 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 18 Jul 2022 13:56:56 -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 v3 2/6] gpio: 104-idio-16: Implement and utilize register structures Date: Fri, 15 Jul 2022 14:52:24 -0400 Message-Id: <86e5390472d40a93f8c1f2e08cd796158421ed1e.1657907849.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 Reviewed-by: Linus Walleij --- Changes in v3: None 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 Sat Apr 18 07:34: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 1A5C8C43334 for ; Mon, 18 Jul 2022 20:57:13 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S236150AbiGRU5K (ORCPT ); Mon, 18 Jul 2022 16:57:10 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:55584 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S236001AbiGRU5A (ORCPT ); Mon, 18 Jul 2022 16:57:00 -0400 Received: from mail-ot1-x32c.google.com (mail-ot1-x32c.google.com [IPv6:2607:f8b0:4864:20::32c]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 95F2C326C5 for ; Mon, 18 Jul 2022 13:56:58 -0700 (PDT) Received: by mail-ot1-x32c.google.com with SMTP id r22-20020a056830419600b0061c6edc5dcfso10199576otu.12 for ; Mon, 18 Jul 2022 13:56:58 -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=tgfjbTgtl1dCbXPRs9I+NiSr15sxa3t9DE28+0ROZqs=; b=PFqbMz+GrYV4yNTUfe7rQQPASOEb3SNbicX5qCBmjndPs05i64yGcXwYNlLOQcJeDd TTqYXE2yTb1AyKgbHZZ+D+0kYTn0wQLRgwTiusY6gZLGco2q9LBUXylS8nTc4SzHWwqS RWutROyv65sCU3cbEJaxt4otmShzZCQDjwd8dzi2U1uVVll759HImyLKuwHqd8QzwLsB l+6Zy3zAcdjNEb5At3ng0pdIShcZ3n+WpostBFSa7XuskffVw8Qbi/FdmyZDeSVFu4L0 KhbCcrpECE6VRZCVvL4DjNeDs6uZt6q4qA2r94z1bcYWcVg7ZLAhiRR5Evtsl0c8o3jk zwIQ== 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=tgfjbTgtl1dCbXPRs9I+NiSr15sxa3t9DE28+0ROZqs=; b=fpqhps/4cswZIWhcLHd1/F9ka6nyp4Kn11uoicmaIeS2LsVQCtoHvyO4URKB0Wl4xu /fx1W6LewTrOWUKIaogNqqQ/m/7uji+y9mgn+wKKZ/7DMeo/0gGD/+YTy6OMLTfN1FI3 QMbQu6DVcDdCjdkzHc6e3jtCz02Qsa/54Vd/AzlrxEBlVsX4bD7JlVUtx59YSZWyd/rk YMg5t6YUa9VrkgUNDaApmvF44EzqjqRvacNxrCaJjeCTAnPGu5ggtBplm+pJ4LKDCPLj pVM+5HZx+IiN/F2jqM7WiMlkd1V7W1cy2DrLKE3ALIeSCgthO0QHB1terPDFq+n5ryjU 6YOA== X-Gm-Message-State: AJIora9Z2BdJk8jNxoDQwumd5DaODZ7C2Wr3SIVVm9SOqNIQ93FCoAwY ILzP1LkqdwXMkJU+YY4kYCsz8w== X-Google-Smtp-Source: AGRyM1tijNYbc38ZTwokknOjSY8nY52EyzX3TWJIy9v0jdr9auENCRkffYW4XEOJa6av1HYTE1YFpw== X-Received: by 2002:a9d:4d89:0:b0:61c:a0cf:7426 with SMTP id u9-20020a9d4d89000000b0061ca0cf7426mr3093569otk.248.1658177817739; Mon, 18 Jul 2022 13:56:57 -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 l8-20020a4ab2c8000000b0035eb4e5a6cbsm5252065ooo.33.2022.07.18.13.56.57 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 18 Jul 2022 13:56:57 -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 , Andy Shevchenko , Fred Eckert , John Hentges , Jay Dolan Subject: [PATCH v3 3/6] gpio: i8255: Introduce the Intel 8255 interface library module Date: Fri, 15 Jul 2022 14:52:25 -0400 Message-Id: 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 library functions providing support for interfaces compatible with the venerable Intel 8255 Programmable Peripheral Interface (PPI). The Intel 8255 PPI first appeared in the early 1970s, initially for the Intel 8080 and later appearing in the original IBM-PC. The popularity of the original Intel 8255 chip led to many subsequent variants and clones of the interface in various chips and integrated circuits. Although still popular, interfaces compatible with the Intel 8255 PPI are nowdays typically found embedded in larger VLSI processing chips and FPGA components rather than as discrete ICs. A CONFIG_GPIO_I8255 Kconfig option is introduced by this patch. Modules wanting access to these i8255 library functions should select this Kconfig option, and import the I8255 symbol namespace. Tested-by: Fred Eckert Cc: John Hentges Cc: Jay Dolan Signed-off-by: William Breathitt Gray Reviewed-by: Linus Walleij --- Changes in v3: - Updated contact information in MAINTAINERS - Added help text for GPIO_I8255 Kconfig option - Move include/linux/gpio/i8255.h to drivers/gpio/gpio-i8255.h - Include "gpio-i8255.h" instead of - Include linux/types.h instead of linux/compiler_types.h - Add underscores for *PORTC_LOWER* and *PORTC_UPPER* defines - Move (offset % 8) expression to the local definition block of i8255_direction_mask() as port_offset const near the io_port definition; this should help optimize assembly instructions on some architectures - Implement an opaque i8255_state struct to organize and access i8255 device states; this replaces the control_state array passed to various i8255 library functions in previous patchsets - Implement and provide a i8255_state_init() function to initialize the i8255_state struct for a consumer - Use a spinlock within i8255 library functions to protect access to i8255 states and synchronize I/O operations; a spinlock is used so that these functions may be used within an interrupt context - Export the i8255 library symbols within a new I8255 namespace MAINTAINERS | 6 + drivers/gpio/Kconfig | 10 ++ drivers/gpio/Makefile | 1 + drivers/gpio/gpio-i8255.c | 292 ++++++++++++++++++++++++++++++++++++++ drivers/gpio/gpio-i8255.h | 47 ++++++ 5 files changed, 356 insertions(+) create mode 100644 drivers/gpio/gpio-i8255.c create mode 100644 drivers/gpio/gpio-i8255.h diff --git a/MAINTAINERS b/MAINTAINERS index a6d3bd9d2a8d..cca3059639e6 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..4074a41008a8 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -829,6 +829,16 @@ endmenu menu "Port-mapped I/O GPIO drivers" depends on X86 # Unconditional I/O space access =20 +config GPIO_I8255 + tristate + help + Enables support for the i8255 interface library functions. The i8255 + interface library provides functions to facilitate communication with + interfaces compatible with the venerable Intel 8255 Programmable + Peripheral Interface (PPI). The Intel 8255 PPI chip was first released + in the early 1970s but compatible interfaces are nowadays typically + found embedded in larger VLSI processing chips and FPGA components. + 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..4bde56475fa5 --- /dev/null +++ b/drivers/gpio/gpio-i8255.c @@ -0,0 +1,292 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Intel 8255 Programmable Peripheral Interface + * Copyright (C) 2022 William Breathitt Gray + */ +#include +#include +#include +#include +#include +#include +#include + +#include "gpio-i8255.h" + +#define I8255_CONTROL_PORTC_LOWER_DIRECTION BIT(0) +#define I8255_CONTROL_PORTB_DIRECTION BIT(1) +#define I8255_CONTROL_PORTC_UPPER_DIRECTION BIT(3) +#define I8255_CONTROL_PORTA_DIRECTION BIT(4) +#define I8255_CONTROL_MODE_SET BIT(7) +#define I8255_PORTA 0 +#define I8255_PORTB 1 +#define I8255_PORTC 2 + +static int i8255_get_port(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 port_offset =3D offset % 8; + 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 (port_offset > 3) + return I8255_CONTROL_PORTC_UPPER_DIRECTION; + return I8255_CONTROL_PORTC_LOWER_DIRECTION; + default: + /* Should never reach this path */ + return 0; + } +} + +static void i8255_set_port(struct i8255 __iomem *const ppi, + struct i8255_state *const state, + const unsigned long io_port, + const unsigned long 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 flags; + unsigned long out_state; + + spin_lock_irqsave(&state[group].lock, flags); + + 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]); + + spin_unlock_irqrestore(&state[group].lock, flags); +} + +/** + * i8255_direction_input - configure signal offset as input + * @ppi: Intel 8255 Programmable Peripheral Interface groups + * @state: devices 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 @state control_sta= te + * values are updated to reflect the new configuration. + */ +void i8255_direction_input(struct i8255 __iomem *const ppi, + struct i8255_state *const state, + const unsigned long offset) +{ + const unsigned long io_port =3D offset / 8; + const unsigned long group =3D io_port / 3; + unsigned long flags; + + spin_lock_irqsave(&state[group].lock, flags); + + state[group].control_state |=3D I8255_CONTROL_MODE_SET; + state[group].control_state |=3D i8255_direction_mask(offset); + + iowrite8(state[group].control_state, &ppi[group].control); + + spin_unlock_irqrestore(&state[group].lock, flags); +} +EXPORT_SYMBOL_NS_GPL(i8255_direction_input, I8255); + +/** + * i8255_direction_output - configure signal offset as output + * @ppi: Intel 8255 Programmable Peripheral Interface groups + * @state: devices states of the respective PPI 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 @state control_state values are + * updated to reflect the new configuration. + */ +void i8255_direction_output(struct i8255 __iomem *const ppi, + struct i8255_state *const state, + const unsigned long offset, + const unsigned long value) +{ + const unsigned long io_port =3D offset / 8; + const unsigned long group =3D io_port / 3; + unsigned long flags; + + spin_lock_irqsave(&state[group].lock, flags); + + state[group].control_state |=3D I8255_CONTROL_MODE_SET; + state[group].control_state &=3D ~i8255_direction_mask(offset); + + iowrite8(state[group].control_state, &ppi[group].control); + + spin_unlock_irqrestore(&state[group].lock, flags); + + i8255_set(ppi, state, offset, value); +} +EXPORT_SYMBOL_NS_GPL(i8255_direction_output, I8255); + +/** + * i8255_get - get signal value at signal offset + * @ppi: Intel 8255 Programmable Peripheral Interface 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_NS_GPL(i8255_get, I8255); + +/** + * i8255_get_direction - get the I/O direction for a signal offset + * @state: devices 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 struct i8255_state *const state, + const unsigned long offset) +{ + const unsigned long io_port =3D offset / 8; + const unsigned long group =3D io_port / 3; + + return !!(state[group].control_state & i8255_direction_mask(offset)); +} +EXPORT_SYMBOL_NS_GPL(i8255_get_direction, I8255); + +/** + * 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_NS_GPL(i8255_get_multiple, I8255); + +/** + * 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_NS_GPL(i8255_mode0_output, I8255); + +/** + * i8255_set - set signal value at signal offset + * @ppi: Intel 8255 Programmable Peripheral Interface groups + * @state: devices states of the respective PPI 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, struct i8255_state *const = state, + 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, state, io_port, offset_mask, bit_mask); +} +EXPORT_SYMBOL_NS_GPL(i8255_set, I8255); + +/** + * i8255_set_multiple - set signal values at multiple signal offsets + * @ppi: Intel 8255 Programmable Peripheral Interface groups + * @state: devices states of the respective PPI 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, + struct i8255_state *const state, + 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, state, io_port, gpio_mask, bit_mask); + } +} +EXPORT_SYMBOL_NS_GPL(i8255_set_multiple, I8255); + +/** + * i8255_state_init - initialize i8255_state structure + * @state: devices states of the respective PPI groups + * @ngroups: number of Intel 8255 Programmable Peripheral Interface groups + * + * Initializes the @state of each Intel 8255 Programmable Peripheral Inter= face + * group for use in i8255 library functions. + */ +void i8255_state_init(struct i8255_state *const state, + const unsigned long ngroups) +{ + unsigned long group; + + for (group =3D 0; group < ngroups; group++) + spin_lock_init(&state[group].lock); +} +EXPORT_SYMBOL_NS_GPL(i8255_state_init, I8255); + +MODULE_AUTHOR("William Breathitt Gray"); +MODULE_DESCRIPTION("Intel 8255 Programmable Peripheral Interface"); +MODULE_LICENSE("GPL"); diff --git a/drivers/gpio/gpio-i8255.h b/drivers/gpio/gpio-i8255.h new file mode 100644 index 000000000000..b2bfe0ecb301 --- /dev/null +++ b/drivers/gpio/gpio-i8255.h @@ -0,0 +1,47 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* Copyright 2022 William Breathitt Gray */ +#ifndef _I8255_H_ +#define _I8255_H_ + +#include +#include + +/** + * struct i8255 - Intel 8255 register structure + * @port: Port A, B, and C + * @control: Control register + */ +struct i8255 { + u8 port[3]; + u8 control; +}; + +/** + * struct i8255_state - Intel 8255 state structure + * @lock: synchronization lock for accessing device state + * @control_state: Control register state + */ +struct i8255_state { + spinlock_t lock; + u8 control_state; +}; + +void i8255_direction_input(struct i8255 __iomem *ppi, struct i8255_state *= state, + unsigned long offset); +void i8255_direction_output(struct i8255 __iomem *ppi, + struct i8255_state *state, unsigned long offset, + unsigned long value); +int i8255_get(const struct i8255 __iomem *ppi, unsigned long offset); +int i8255_get_direction(const struct i8255_state *state, unsigned long off= set); +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, struct i8255_state *state, + unsigned long offset, unsigned long value); +void i8255_set_multiple(struct i8255 __iomem *ppi, struct i8255_state *sta= te, + const unsigned long *mask, const unsigned long *bits, + unsigned long ngpio); +void i8255_state_init(struct i8255_state *const state, unsigned long ngrou= ps); + +#endif /* _I8255_H_ */ --=20 2.36.1 From nobody Sat Apr 18 07:34: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 EA584C43334 for ; Mon, 18 Jul 2022 20:57:16 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S236160AbiGRU5O (ORCPT ); Mon, 18 Jul 2022 16:57:14 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:55678 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S236051AbiGRU5C (ORCPT ); Mon, 18 Jul 2022 16:57:02 -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 84EC2326F6 for ; Mon, 18 Jul 2022 13:56:59 -0700 (PDT) Received: by mail-ot1-x32e.google.com with SMTP id o16-20020a9d4110000000b0061cac66bd6dso1766483ote.11 for ; Mon, 18 Jul 2022 13:56:59 -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=WAI7bZNVOd+8D2vU7qNqox3N5coYfVI5Ydgq3BWeIGw=; b=Tg/BeWGAQptGtCuceNodPfghsat5H+rWTWzV0SAKXuysM2TAUiVEcg+VpOjz5AJ2gu 9Ai60pg7RrMN7iL9PJcInrjtO7e5yB3plSYLCph/g11+R9/e5UfVsHKpG5IFWphAoTyT oA0X76zqgPxqbGWOseHiARPjR77vJz01Fg5zq+NsYX7wwWKZcNDJ1028+MS8Zs99JAId 3NkV1W/5b3kTbn4YdPttHUFioRmqLmJaMeYIOTLMx6+LN9wLHvHlnF+KPZzlmzNPy7D4 dBcayoO2o8qKisGCLJE22lUuNbtXO5PcwdeH45VWo1wn71rx/QhYQb7zp0Mn7JKkDZCN ApiQ== 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=WAI7bZNVOd+8D2vU7qNqox3N5coYfVI5Ydgq3BWeIGw=; b=d49vaHjKNnph1WxN5EIW4nEbGg9mljtFlhyWwQHpj7nar3zLjtYrLAUupE+vOmbfUh gMdPJH8Gd5Hsw9SFdPEEmIU1zKgWIbBsr7iCS5oUxQyBP7wSITTE5Wsyvqb9qkD4GwjC ZVuSOHxpqBgJisQE+93Wf6JOprWMr1fAbijH8b+NrG/LeDyQJJ7/5q+6V3jyrhsMwyOf 2LTgXdQQetr1hpjG0izxW3u11QfQwzehvkmOkiWjiXNe97nQaq9lFOllNviaehII2Y00 m3tIdwAlLTGxZuH0wnMHV0x8IWRLUMWtC73x6r8qerLtNhPB4p+tI2EfrWMsCzgbUcsr 4QnA== X-Gm-Message-State: AJIora8SzWTtdCSV+sLAgNo9J2XunxHIF4PYHhat6UQrlKjI4B3jj5nl cnSsxBjj74Cc46OIC8NNeQvwjw== X-Google-Smtp-Source: AGRyM1sa4OY7zIRja7Ho1sfzwMTOiFo5IMFSiwDhiD/ga1j2xqP/ZacBHcZurrMWC5L3sq0Ix4o8Kg== X-Received: by 2002:a9d:32a:0:b0:61c:7b4b:d854 with SMTP id 39-20020a9d032a000000b0061c7b4bd854mr9340701otv.362.1658177818616; Mon, 18 Jul 2022 13:56:58 -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 l8-20020a4ab2c8000000b0035eb4e5a6cbsm5252065ooo.33.2022.07.18.13.56.57 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 18 Jul 2022 13:56:58 -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 v3 4/6] gpio: 104-dio-48e: Implement and utilize register structures Date: Fri, 15 Jul 2022 14:52:26 -0400 Message-Id: <20b1465664f93172e2143c5ce5890d4532d0f9b5.1657907849.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 Reviewed-by: Linus Walleij --- Changes in v3: - Include "gpio-i8255.h" instead of - Import I8255 symbol namespace - Define DIO48E_NUM_PPI as the number of PPI (2) - Utilize i8255_state struct; replaces 'control_state' with 'ppi_state' - Call i8255_state_init() to initialize 'ppi_state' drivers/gpio/Kconfig | 1 + drivers/gpio/gpio-104-dio-48e.c | 248 ++++++++++---------------------- 2 files changed, 75 insertions(+), 174 deletions(-) diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index 4074a41008a8..1d4529c39dc6 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -844,6 +844,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..a6f54430c5b6 100644 --- a/drivers/gpio/gpio-104-dio-48e.c +++ b/drivers/gpio/gpio-104-dio-48e.c @@ -6,7 +6,7 @@ * This driver supports the following ACCES devices: 104-DIO-48E and * 104-DIO-24E. */ -#include +#include #include #include #include @@ -20,6 +20,11 @@ #include #include #include +#include + +#include "gpio-i8255.h" + +MODULE_IMPORT_NS(I8255); =20 #define DIO48E_EXTENT 16 #define MAX_NUM_DIO48E max_num_isa_dev(DIO48E_EXTENT) @@ -33,34 +38,54 @@ 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 +#define DIO48E_NUM_PPI 2 + +/** + * struct dio48e_reg - device register structure + * @ppi: Programmable Peripheral Interface groups + * @enable_buffer: Enable/Disable Buffer groups + * @unused1: Unused + * @enable_interrupt: Write: Enable Interrupt + * Read: Disable Interrupt + * @unused2: Unused + * @enable_counter: Write: Enable Counter/Timer Addressing + * Read: Disable Counter/Timer Addressing + * @unused3: Unused + * @clear_interrupt: Clear Interrupt + */ +struct dio48e_reg { + struct i8255 ppi[DIO48E_NUM_PPI]; + u8 enable_buffer[DIO48E_NUM_PPI]; + u8 unused1; + u8 enable_interrupt; + u8 unused2; + u8 enable_counter; + u8 unused3; + u8 clear_interrupt; +}; + /** * 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 + * @ppi_state: PPI device states + * @lock: synchronization lock to prevent I/O race conditions + * @reg: I/O address offset for the device registers + * @irq_mask: I/O bits affected by interrupts */ struct dio48e_gpio { struct gpio_chip chip; - unsigned char io_state[6]; - unsigned char out_state[6]; - unsigned char control[2]; + struct i8255_state ppi_state[DIO48E_NUM_PPI]; 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->ppi_state, offset)) + return GPIO_LINE_DIRECTION_IN; =20 return GPIO_LINE_DIRECTION_OUT; } @@ -68,38 +93,9 @@ static int dio48e_gpio_get_direction(struct gpio_chip *c= hip, 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; - - 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); - - raw_spin_unlock_irqrestore(&dio48egpio->lock, flags); + i8255_direction_input(dio48egpio->reg->ppi, dio48egpio->ppi_state, + offset); =20 return 0; } @@ -108,48 +104,9 @@ static int dio48e_gpio_direction_output(struct gpio_ch= ip *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; - - raw_spin_lock_irqsave(&dio48egpio->lock, flags); - - /* 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; =20 - 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); - - raw_spin_unlock_irqrestore(&dio48egpio->lock, flags); + i8255_direction_output(dio48egpio->reg->ppi, dio48egpio->ppi_state, + offset, value); =20 return 0; } @@ -157,47 +114,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); =20 - /* ensure that GPIO is set for input */ - if (!(dio48egpio->io_state[port] & mask)) { - raw_spin_unlock_irqrestore(&dio48egpio->lock, flags); - return -EINVAL; - } - - 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; =20 - /* 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 =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,49 +131,17 @@ 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); - - if (value) - dio48egpio->out_state[port] |=3D mask; - else - dio48egpio->out_state[port] &=3D ~mask; - - iowrite8(dio48egpio->out_state[port], dio48egpio->base + out_port); - - raw_spin_unlock_irqrestore(&dio48egpio->lock, flags); + i8255_set(dio48egpio->reg->ppi, dio48egpio->ppi_state, offset, value); } =20 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; - - 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); =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); - - raw_spin_unlock_irqrestore(&dio48egpio->lock, flags); - } + i8255_set_multiple(dio48egpio->reg->ppi, dio48egpio->ppi_state, mask, + bits, chip->ngpio); } =20 static void dio48e_irq_ack(struct irq_data *data) @@ -274,7 +168,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 +188,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 +235,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 +267,26 @@ 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, + struct i8255_state *const ppi_state) +{ + 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 < DIO48E_NUM_PPI; i++) { + i8255_mode0_output(&ppi[i]); + i8255_set_multiple(&ppi[i], &ppi_state[i], &mask, &bits, ngpio); + } +} + static int dio48e_probe(struct device *dev, unsigned int id) { struct dio48e_gpio *dio48egpio; @@ -395,8 +304,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 +334,8 @@ 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); + i8255_state_init(dio48egpio->ppi_state, DIO48E_NUM_PPI); + dio48e_init_ppi(dio48egpio->reg->ppi, dio48egpio->ppi_state); =20 err =3D devm_gpiochip_add_data(dev, &dio48egpio->chip, dio48egpio); if (err) { --=20 2.36.1 From nobody Sat Apr 18 07:34: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 C6612C43334 for ; Mon, 18 Jul 2022 20:57:19 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S236086AbiGRU5S (ORCPT ); Mon, 18 Jul 2022 16:57:18 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:55690 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S235983AbiGRU5D (ORCPT ); Mon, 18 Jul 2022 16:57:03 -0400 Received: from mail-ot1-x32b.google.com (mail-ot1-x32b.google.com [IPv6:2607:f8b0:4864:20::32b]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 3B63C32B82 for ; Mon, 18 Jul 2022 13:57:00 -0700 (PDT) Received: by mail-ot1-x32b.google.com with SMTP id l9-20020a056830268900b006054381dd35so10234029otu.4 for ; Mon, 18 Jul 2022 13:57:00 -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=BguhXpMM+bZOyQ8uv1giPWb1tgh33TeNy2eh10Br27A=; b=An8lC8KfY06PYa1RYp4mbjKfj0VonTQ6ApbL99AYyiYT7Vnx1YQyEW0za0mQMgLrMm AeRpEfc/qW2KV2Z2rwl0Ba1URVJywnNZxUMhdNJ7bEPNu7ODEnzl4FaSGdBDKNo+I/84 cvhK2fttexFfQRZB7BYtY501FMmhYpq0ayFqHuLXgYvHjfhFHF3c/zOtBJ29nGds674H 9onUBYD20iVc84ljkocmYdk2ks+gO8SCVc+0zlttHT6gUZzm+oyOAexB8NsepmXZaTMe MaSIK65qoZ5NztCKlnXjCH/ltXfTea9c4/IhGuWJog6L4f84CfZGtq1IGrwadzxJxr6P hkeQ== 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=BguhXpMM+bZOyQ8uv1giPWb1tgh33TeNy2eh10Br27A=; b=iy1F1xrE1cCNB8Q11ZMidY/kLQ3gyvXL+527eTb1WO8OEDvSLV/KzM52A9/nDqbr+e gujAiDWH58F0ZN1rkHCzy2S/pD4BO+lnxkt8TLvY0Eo32RC8x4mQr1ZTkn7/otPSwr0V ZWrpTyIZ1ZkVmz8EsZSqS6mcQG7ewOo2MuqAHFDAQ4OJn+UDSEhS5kcWhaTabujPZCzH xtFAfliBIC1P47cLHeOgHBY3keUum9LvNcltNhxE8ALVP1+bd+4PB0Dz5yDYwwK2ZyrV uthrPW/dPXR1mK1G0ZvD5nTyUfFooZQ6V4iGOUW7NbwppLCxWZB4PhAJEUauQWitYG3A hTJA== X-Gm-Message-State: AJIora8oWiJlOnDCtsQuNKzdBd3HQejJxWBoejq43U/XWuAcCzoLPGph r1tsrbrjeaetbCjEFPwSBEbLlg== X-Google-Smtp-Source: AGRyM1v2qj1xxNiiv3R+F6Gxia9t/N/x49Yw5ZzYzY/xYyGBpQ75JZuuJ/VfwKJUhUPqPwrOe5f17w== X-Received: by 2002:a05:6830:1e31:b0:61c:ac69:94ce with SMTP id t17-20020a0568301e3100b0061cac6994cemr1559544otr.282.1658177819445; Mon, 18 Jul 2022 13:56:59 -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 l8-20020a4ab2c8000000b0035eb4e5a6cbsm5252065ooo.33.2022.07.18.13.56.58 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 18 Jul 2022 13:56:59 -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 v3 5/6] gpio: 104-idi-48: Implement and utilize register structures Date: Fri, 15 Jul 2022 14:52:27 -0400 Message-Id: <300ea3f4c4b1ebc0ef934875fdefe9402ab1e9a4.1657907849.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 Reviewed-by: Linus Walleij --- Changes in v3: - Include "gpio-i8255.h" instead of - Import I8255 symbol namespace - Consolidate 'lock' and 'ack_lock' into a single spinlock 'lock' synchronizing I/O as well as protecting irq_mask states drivers/gpio/Kconfig | 1 + drivers/gpio/gpio-104-idi-48.c | 141 ++++++++++++++------------------- 2 files changed, 60 insertions(+), 82 deletions(-) diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index 1d4529c39dc6..253a03ee3fa4 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -868,6 +868,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..380ab1221a66 100644 --- a/drivers/gpio/gpio-104-idi-48.c +++ b/drivers/gpio/gpio-104-idi-48.c @@ -6,7 +6,6 @@ * This driver supports the following ACCES devices: 104-IDI-48A, * 104-IDI-48AC, 104-IDI-48B, and 104-IDI-48BC. */ -#include #include #include #include @@ -20,6 +19,11 @@ #include #include #include +#include + +#include "gpio-i8255.h" + +MODULE_IMPORT_NS(I8255); =20 #define IDI_48_EXTENT 8 #define MAX_NUM_IDI_48 max_num_isa_dev(IDI_48_EXTENT) @@ -33,21 +37,34 @@ 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 { struct gpio_chip chip; - raw_spinlock_t lock; - spinlock_t ack_lock; + spinlock_t lock; unsigned char irq_mask[6]; - void __iomem *base; + struct idi_48_reg __iomem *reg; unsigned char cos_enb; }; =20 @@ -64,42 +81,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); - - return !!(ioread8(port_addr) & mask); - } + const void __iomem *const ppi =3D idi48gpio->reg; =20 - /* 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 +106,24 @@ 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; + spin_lock_irqsave(&idi48gpio->lock, flags); =20 - if (!idi48gpio->irq_mask[boundary]) { - idi48gpio->cos_enb &=3D ~BIT(boundary); + idi48gpio->irq_mask[boundary] &=3D ~mask; =20 - raw_spin_lock_irqsave(&idi48gpio->lock, flags); + /* Exit early if there are still input lines with IRQ unmasked */ + if (idi48gpio->irq_mask[boundary]) + goto exit; =20 - iowrite8(idi48gpio->cos_enb, idi48gpio->base + 7); + idi48gpio->cos_enb &=3D ~BIT(boundary); =20 - raw_spin_unlock_irqrestore(&idi48gpio->lock, flags); - } + iowrite8(idi48gpio->cos_enb, &idi48gpio->reg->irq); =20 - return; - } +exit: + spin_unlock_irqrestore(&idi48gpio->lock, flags); } =20 static void idi_48_irq_unmask(struct irq_data *data) @@ -144,32 +131,27 @@ 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]; + spin_lock_irqsave(&idi48gpio->lock, flags); =20 - 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) + goto exit; =20 - iowrite8(idi48gpio->cos_enb, idi48gpio->base + 7); + idi48gpio->cos_enb |=3D BIT(boundary); =20 - raw_spin_unlock_irqrestore(&idi48gpio->lock, flags); - } + iowrite8(idi48gpio->cos_enb, &idi48gpio->reg->irq); =20 - return; - } +exit: + spin_unlock_irqrestore(&idi48gpio->lock, flags); } =20 static int idi_48_irq_set_type(struct irq_data *data, unsigned flow_type) @@ -200,17 +182,13 @@ static irqreturn_t idi_48_irq_handler(int irq, void *= dev_id) unsigned long gpio; struct gpio_chip *const chip =3D &idi48gpio->chip; =20 - spin_lock(&idi48gpio->ack_lock); - - raw_spin_lock(&idi48gpio->lock); - - cos_status =3D ioread8(idi48gpio->base + 7); + spin_lock(&idi48gpio->lock); =20 - raw_spin_unlock(&idi48gpio->lock); + cos_status =3D ioread8(&idi48gpio->reg->irq); =20 /* IRQ Status (bit 6) is active low (0 =3D IRQ generated by device) */ if (cos_status & BIT(6)) { - spin_unlock(&idi48gpio->ack_lock); + spin_unlock(&idi48gpio->lock); return IRQ_NONE; } =20 @@ -228,7 +206,7 @@ static irqreturn_t idi_48_irq_handler(int irq, void *de= v_id) } } =20 - spin_unlock(&idi48gpio->ack_lock); + spin_unlock(&idi48gpio->lock); =20 return IRQ_HANDLED; } @@ -250,8 +228,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 +251,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; @@ -298,8 +276,7 @@ static int idi_48_probe(struct device *dev, unsigned in= t id) girq->handler =3D handle_edge_irq; girq->init_hw =3D idi_48_irq_init_hw; =20 - raw_spin_lock_init(&idi48gpio->lock); - spin_lock_init(&idi48gpio->ack_lock); + spin_lock_init(&idi48gpio->lock); =20 err =3D devm_gpiochip_add_data(dev, &idi48gpio->chip, idi48gpio); if (err) { --=20 2.36.1 From nobody Sat Apr 18 07:34: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 7F520C433EF for ; Mon, 18 Jul 2022 20:57:23 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S236181AbiGRU5V (ORCPT ); Mon, 18 Jul 2022 16:57:21 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:55696 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S235905AbiGRU5D (ORCPT ); Mon, 18 Jul 2022 16:57:03 -0400 Received: from mail-ot1-x336.google.com (mail-ot1-x336.google.com [IPv6:2607:f8b0:4864:20::336]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 98BFB32B89 for ; Mon, 18 Jul 2022 13:57:00 -0700 (PDT) Received: by mail-ot1-x336.google.com with SMTP id g19-20020a9d1293000000b0061c7bfda5dfso9879974otg.1 for ; Mon, 18 Jul 2022 13:57:00 -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=MaL6nUZp1qnzFg5lPX4aXiHwyJgQQ7FQ0456bzIqrd4=; b=FjumPJRgFY5eeB5lGRtrx/X4WGR/RNXvsyxCmxHJGjWmWxjxX43Oy0h9WpbVs/G9Or ++LnnUzMDM8N8WiAPGWENuyv5Ge8ng3s0C9MIWQJBIwePOUDvymCk63MTBmkp4IAkg/j hF+eXYwEDIKVMRvbLEPtf3Cn1mQJhUImeG0A/Cacpl5VwDjJKp0cDJw+hX+5yIcoFNw9 DfGEGZ3qecfcqrN2NDwhv1m0FYtpyNlvIMRajW0azcLEgmC/dqMQFkyOByA2Z0UsnNi2 X7NY6L9CjaaV2eaWXNI7uXUX57pTXfHIfJ1+F560d5GcQzkUlB5F1+uYxnkzbcG9kMIV u4Ng== 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=MaL6nUZp1qnzFg5lPX4aXiHwyJgQQ7FQ0456bzIqrd4=; b=w5Dt4V75vILZ3I41JuKk+k2oVt6k72cCAXduBXIis4R5jSxNmDw6eRXl/7+h5bxGxb lmDlDb0Kcj1+GOtXC2lTPY/nXRtiCRvA0AW3igsBhp6jLYCMDhJH2QxuxRD75zlCIEXG Iunsqxro4m5EwHnoDQBXyceP2gifnvWZd2RG96IG/tIxRgNqywpQnVzRBq8/VrA9BnaZ rXshuBp32AZ32VvYiuTJvdsSxHNzBPdyTY4osWaoVWKo/MY/XChu4yjucfZbVCAdvn2f q1OJx6UvuvmGd75bzewkIoXuYd6phq5MRL439lqxNFQl/Njts4+DhnG9YAk0eEpJoVE7 QDdw== X-Gm-Message-State: AJIora9saDfAR78TUN9VcAGbSmiGwdoCon06aqVN0zEtyxr1bQyfnYIw rBPZ4H66dQnVX3jfWuQ9F2+swA== X-Google-Smtp-Source: AGRyM1v3ju4pWLaLyB7J9v+/Op4/p9RZ3pLizVgSCnsZE/a78N8riyvlWvFOIZs2qlRWVbAqriefDg== X-Received: by 2002:a9d:5a05:0:b0:61c:32a3:f402 with SMTP id v5-20020a9d5a05000000b0061c32a3f402mr11582713oth.107.1658177820213; Mon, 18 Jul 2022 13:57:00 -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 l8-20020a4ab2c8000000b0035eb4e5a6cbsm5252065ooo.33.2022.07.18.13.56.59 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 18 Jul 2022 13:57:00 -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 Subject: [PATCH v3 6/6] gpio: gpio-mm: Implement and utilize register structures Date: Fri, 15 Jul 2022 14:52:28 -0400 Message-Id: <124fb6518c06db7ac5c6032c8d4fe429611ac3ed.1657907849.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 Signed-off-by: William Breathitt Gray Reviewed-by: Linus Walleij --- Changes in v3: - Include "gpio-i8255.h" instead of - Import I8255 symbol namespace - Define GPIOMM_NUM_PPI as the number of PPI (2) - Utilize i8255_state struct; replaces 'control_state' and 'lock' with 'ppi_state' - Call i8255_state_init() to initialize 'ppi_state' drivers/gpio/Kconfig | 1 + drivers/gpio/gpio-gpio-mm.c | 202 +++++++----------------------------- 2 files changed, 41 insertions(+), 162 deletions(-) diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index 253a03ee3fa4..5202e3b6f2c6 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -889,6 +889,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..75b3ceeddbaf 100644 --- a/drivers/gpio/gpio-gpio-mm.c +++ b/drivers/gpio/gpio-gpio-mm.c @@ -6,7 +6,7 @@ * This driver supports the following Diamond Systems devices: GPIO-MM and * GPIO-MM-12. */ -#include +#include #include #include #include @@ -17,7 +17,10 @@ #include #include #include -#include + +#include "gpio-i8255.h" + +MODULE_IMPORT_NS(I8255); =20 #define GPIOMM_EXTENT 8 #define MAX_NUM_GPIOMM max_num_isa_dev(GPIOMM_EXTENT) @@ -27,32 +30,26 @@ 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"); =20 +#define GPIOMM_NUM_PPI 2 + /** * 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 + * @ppi_state: Programmable Peripheral Interface group states + * @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]; - spinlock_t lock; - void __iomem *base; + struct i8255_state ppi_state[GPIOMM_NUM_PPI]; + 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->ppi_state, offset)) return GPIO_LINE_DIRECTION_IN; =20 return GPIO_LINE_DIRECTION_OUT; @@ -62,35 +59,8 @@ 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; - - spin_lock_irqsave(&gpiommgpio->lock, flags); - - /* 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); - } =20 - control =3D BIT(7) | gpiommgpio->control[control_port]; - iowrite8(control, gpiommgpio->base + 3 + control_port*4); - - spin_unlock_irqrestore(&gpiommgpio->lock, flags); + i8255_direction_input(gpiommgpio->ppi, gpiommgpio->ppi_state, offset); =20 return 0; } @@ -99,44 +69,9 @@ static int gpiomm_gpio_direction_output(struct gpio_chip= *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; - - spin_lock_irqsave(&gpiommgpio->lock, flags); - - /* 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); =20 - iowrite8(gpiommgpio->out_state[io_port], gpiommgpio->base + out_port); - - spin_unlock_irqrestore(&gpiommgpio->lock, flags); + i8255_direction_output(gpiommgpio->ppi, gpiommgpio->ppi_state, offset, + value); =20 return 0; } @@ -144,47 +79,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,49 +97,17 @@ static void gpiomm_gpio_set(struct gpio_chip *chip, un= signed 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; - - spin_lock_irqsave(&gpiommgpio->lock, flags); - - if (value) - gpiommgpio->out_state[port] |=3D mask; - else - gpiommgpio->out_state[port] &=3D ~mask; - - iowrite8(gpiommgpio->out_state[port], gpiommgpio->base + out_port); =20 - spin_unlock_irqrestore(&gpiommgpio->lock, flags); + i8255_set(gpiommgpio->ppi, gpiommgpio->ppi_state, offset, value); } =20 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; - - 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); =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); - - spin_unlock_irqrestore(&gpiommgpio->lock, flags); - } + i8255_set_multiple(gpiommgpio->ppi, gpiommgpio->ppi_state, mask, bits, + chip->ngpio); } =20 #define GPIOMM_NGPIO 48 @@ -250,6 +122,21 @@ 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, + struct i8255_state *const ppi_state) +{ + 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 < GPIOMM_NUM_PPI; i++) { + i8255_mode0_output(&ppi[i]); + i8255_set_multiple(&ppi[i], &ppi_state[i], &mask, &bits, ngpio); + } +} + static int gpiomm_probe(struct device *dev, unsigned int id) { struct gpiomm_gpio *gpiommgpio; @@ -266,8 +153,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; @@ -284,7 +171,8 @@ static int gpiomm_probe(struct device *dev, unsigned in= t id) gpiommgpio->chip.set =3D gpiomm_gpio_set; gpiommgpio->chip.set_multiple =3D gpiomm_gpio_set_multiple; =20 - spin_lock_init(&gpiommgpio->lock); + i8255_state_init(gpiommgpio->ppi_state, GPIOMM_NUM_PPI); + gpiomm_init_dio(gpiommgpio->ppi, gpiommgpio->ppi_state); =20 err =3D devm_gpiochip_add_data(dev, &gpiommgpio->chip, gpiommgpio); if (err) { @@ -292,16 +180,6 @@ 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); - return 0; } =20 --=20 2.36.1