From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-11.2 required=3.0 tests=BAYES_00,DKIMWL_WL_HIGH, DKIM_SIGNED,DKIM_VALID,HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_PATCH, MAILING_LIST_MULTI,SIGNED_OFF_BY,SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED, USER_AGENT_SANE_2 autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 908C9C2D0A3 for ; Mon, 16 Nov 2020 16:45:21 +0000 (UTC) Received: from merlin.infradead.org (merlin.infradead.org [205.233.59.134]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 1FBA320E65 for ; Mon, 16 Nov 2020 16:45:21 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=lists.infradead.org header.i=@lists.infradead.org header.b="n38Azn/S"; dkim=fail reason="signature verification failed" (1024-bit key) header.d=calian.com header.i=@calian.com header.b="lqnPPVBB" DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 1FBA320E65 Authentication-Results: mail.kernel.org; dmarc=fail (p=quarantine dis=none) header.from=calian.com Authentication-Results: mail.kernel.org; spf=none smtp.mailfrom=linux-arm-kernel-bounces+linux-arm-kernel=archiver.kernel.org@lists.infradead.org DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=merlin.20170209; h=Sender:Content-Transfer-Encoding: Content-Type:Cc:List-Subscribe:List-Help:List-Post:List-Archive: List-Unsubscribe:List-Id:MIME-Version:Content-ID:In-Reply-To:References: Message-ID:Date:Subject:To:From:Reply-To:Content-Description:Resent-Date: Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:List-Owner; bh=fR3GUxLKWWPRXpDvHroGPuaGbC6TmUWF+fuwVJRn0pY=; b=n38Azn/SdDuPtP9htY2C+PxMq F4BTKs2ppY7RmF2e+nIzpcYfApOTF01D0i0p1FAbAR5t35zdfhQ04HmkNJcm2kQMREN/z7vifK3rG P+BBGIfzDBsjaHnAMdIk9TKce9LdyUCWiVKODYNzMcdlSmGNFl//Czk34qi8yS9KeWHjeOuzhZylr 3sVJw97GFiIMHajMRRHhiPjWxiYp7d4HKtKiapkwBo+ial3VXCLLkYXZABtVXoVLp+twvCWjoPIkT 0EOhkmtELcKkniQTn0WfqHhOW6tOPu8BXQ3orjD0ZY+v7uP7ORNvhEQ9OPSKZ35j3PD+1JryAHGKY g+0wZ5lxA==; Received: from localhost ([::1] helo=merlin.infradead.org) by merlin.infradead.org with esmtp (Exim 4.92.3 #3 (Red Hat Linux)) id 1kehcW-0001MF-F6; Mon, 16 Nov 2020 16:44:48 +0000 Received: from mail-eopbgr670061.outbound.protection.outlook.com ([40.107.67.61] helo=CAN01-TO1-obe.outbound.protection.outlook.com) by merlin.infradead.org with esmtps (Exim 4.92.3 #3 (Red Hat Linux)) id 1kehcT-0001L4-Ac for linux-arm-kernel@lists.infradead.org; Mon, 16 Nov 2020 16:44:47 +0000 ARC-Seal: i=1; a=rsa-sha256; s=arcselector9901; d=microsoft.com; cv=none; b=Mx1eXerlA4KfN2nNGJeCVfUfmeepmTNVWyoA1eW1mg8GuyZpjW2t0M7325vryBdulKOGJ8hRDkaS5vn+eoc3TSdqGMSbk5BvwPf79UK7LOJcwCUtQOIM7/ScVUKp9Ee7A+2Z+m5I6AaKgYA1PsQ1cWwnl8R1d3PbLJaqj2GBvP900bJ8+J/se7KAGGwKtXyv516AQME0tivKZ/KfM43TMc6wWtIR55f5drXPXT7Mf2Gww/YQwk96WBW6RczGlHt2/TGl6lgc+JhhdH7734Uie7BFmFw+lwFPLRiSRPNY3VmBXSnVSMahnFFwnxh899/+WY7pttnSNnZZVk3yCLVoLQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector9901; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=0XsBTZl51Kww8qVua1XbUQQEQ9RB77iMklvXCqKGG8g=; b=oQZtw5v9ioYJlzaPksBA2AoHL7v00r9+gDaBr/KvTaCoVYvf5nsotm6PQOnva40V+7aOCb+svIq4/y6I1jS3xn2r/CPMISV0yw99b7Ugfm97i/7mnVGMNJiDMwbnszb1P1WO7AwDh/DFqM33zoHzdIbWqJDedh8qyLfpkp/u5BRhng9n+4uc5Xsooq3+Q0C4W6nRpnm4NKArYtV62RZSfLGMUjChNock89952HFFtZJTDtP7+kGjTnueaDgHPSAeNgy86m4OFayzK1TTPHP2aXE8Fj2kzBSF09WI6b7KA3f/R8nZ6QMfJHuhQijDkY3iSlQLCT7UE6j27nsAxQH4zQ== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass smtp.mailfrom=calian.com; dmarc=pass action=none header.from=calian.com; dkim=pass header.d=calian.com; arc=none DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=calian.com; s=selector1; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=0XsBTZl51Kww8qVua1XbUQQEQ9RB77iMklvXCqKGG8g=; b=lqnPPVBBHP/XxkZc74zoopf7KZNCg36dDn5CFifb80HdVGHQvXN5nDU/cMEWuuoJRtux3Fpw0BgBxl6uUbaKajY1j7wRuQvN5cE0HUJOu7Mg/F4pwxW0kZZWDGwLwTES3czXQLA8mFLu7zXVVpYue3WwFVeLj4mtpoG03P++84A= Received: from YT1PR01MB3546.CANPRD01.PROD.OUTLOOK.COM (2603:10b6:b01:f::20) by YTBPR01MB3984.CANPRD01.PROD.OUTLOOK.COM (2603:10b6:b01:1f::17) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.3564.28; Mon, 16 Nov 2020 16:44:43 +0000 Received: from YT1PR01MB3546.CANPRD01.PROD.OUTLOOK.COM ([fe80::dd1e:eba1:8e76:470b]) by YT1PR01MB3546.CANPRD01.PROD.OUTLOOK.COM ([fe80::dd1e:eba1:8e76:470b%7]) with mapi id 15.20.3564.028; Mon, 16 Nov 2020 16:44:43 +0000 From: Robert Hancock To: "sgoud@xilinx.com" , "shubhrajyoti.datta@xilinx.com" , "michal.simek@xilinx.com" , "srinivas.neeli@xilinx.com" , "linus.walleij@linaro.org" , "bgolaszewski@baylibre.com" Subject: Re: [LINUX PATCH V3 5/9] gpio: gpio-xilinx: Add interrupt support Thread-Topic: [LINUX PATCH V3 5/9] gpio: gpio-xilinx: Add interrupt support Thread-Index: AQHWuRcSNrAXwns7Ck68t7CQbk2jpKnK/WIA Date: Mon, 16 Nov 2020 16:44:42 +0000 Message-ID: References: <1605201148-4508-1-git-send-email-srinivas.neeli@xilinx.com> <1605201148-4508-6-git-send-email-srinivas.neeli@xilinx.com> In-Reply-To: <1605201148-4508-6-git-send-email-srinivas.neeli@xilinx.com> Accept-Language: en-CA, en-US Content-Language: en-US X-MS-Has-Attach: X-MS-TNEF-Correlator: x-mailer: Evolution 3.28.5 (3.28.5-12.el8) authentication-results: xilinx.com; dkim=none (message not signed) header.d=none;xilinx.com; dmarc=none action=none header.from=calian.com; x-originating-ip: [204.83.154.189] x-ms-publictraffictype: Email x-ms-office365-filtering-correlation-id: 9ea6ac6b-bfad-4348-7f82-08d88a4eeb2a x-ms-traffictypediagnostic: YTBPR01MB3984: x-microsoft-antispam-prvs: x-ms-oob-tlc-oobclassifiers: OLM:7691; x-ms-exchange-senderadcheck: 1 x-microsoft-antispam: BCL:0; x-microsoft-antispam-message-info: tVjgvs78jJ5hGPydIXy+kXJ3jnKAsEuwAb5rJ4c7pwJ4TNRqSPhptk7IlIQNkVTfZLJtfAav2r042ExhdPNPpaQnYNJ7U/zVgl/P0ZKbLooIL3MdwwKW3/InUKf268OY06QRHdBo535YgMtcdZpJLmw/EuLhoJAHBQNdQYRLJjx8aiI/8vEjeemtGZppNkPzflj5mIQgnEGEXtvglcvat7UyFuknxAt0HZQw5h4lmjKDdVzPaMSDR1QwarWtsdjkk/K/jXt1PdRajNUJTHL+6pqSpzfwRxPcNcfSWnhBdX9blqKWGYatvzsn9PhzIacHTodFj+1Y9mi007vGoRKSQwVZZFlTMF6taTDFxXZ2cdy65KvqfN8H36kh+sHVhdrQj8n3VzsI4IFcZkKz+ENgChs7YV0sDzPiNu7X5To67aY3D9z3FbGD0z5TQSyUO53Py0SnJl3vS9bl+9vjqgJjyzSViaWBlns/lWNYINeGros= x-forefront-antispam-report: CIP:255.255.255.255; CTRY:; LANG:en; SCL:1; SRV:; IPV:NLI; SFV:NSPM; H:YT1PR01MB3546.CANPRD01.PROD.OUTLOOK.COM; PTR:; CAT:NONE; SFS:(4636009)(366004)(39850400004)(376002)(346002)(396003)(136003)(83380400001)(6512007)(66476007)(64756008)(66556008)(66446008)(36756003)(71200400001)(66946007)(316002)(8676002)(4326008)(6486002)(8936002)(15974865002)(76116006)(4001150100001)(30864003)(26005)(2906002)(6506007)(5660300002)(110136005)(54906003)(44832011)(478600001)(86362001)(186003)(7416002)(2616005)(99106002)(18886075002); DIR:OUT; SFP:1101; x-ms-exchange-antispam-messagedata: +psZZRlx3AzSJdCvejzzpehhneaRs4wvxFTo3yI1oA/IzrVpyeTk2NjhURkHb8RURcIlPBgYeNB/4tXXz4gAk0C54RJmmSbl2gMTJEebSDn8JvnMDD5ZfwSPNqV5VYxtCT+sSyIvn87nRUSCXiTgPVWzEh+V79jOGqKEZKhQzBitr+/JSlUqf2wn30hBAlht+lqyb+0OrZD/0k5J5swRFXtmZxnDFbWHhwVB3WHr4oHqK8aEYSdlwrIfG4kEdPnoEgLwVa5ozObrvqBArCw+9rinM7INrGb28Rq72w/oK188Q0bP3D7cDibNEb+7jsrY1V1uf3nCDwI5iKuuH0eh/r6zRGVKAOqLMsr3kSsZXGqt349zBONPXgAy7ZFBRFH4S8NxxcfLa3reG3q3GtyLTTkMBtLSA8ckl5BglxQ9m9EXCN9aRoYUdT5WMKz/peZ2pGcFCHt7K3Pn+v1RsG88aID3QZnl9McD+/QVQ6KZtw/9htd1saVwzztRLOHM48AXi8Rc8DDtZ5jEQP92/eFJjNxFiIgyxkczV3feHh8nkwPjFlXN3TsSwd2q75NQ8lrXRb4nF6A39E/gLJcqwVMqxxWZkQnC+5cNUEvxVKFP2uf47BVGhSilsE9HqjVtxMQbTLHEv3DSB9/OUhgep9gw/A== x-ms-exchange-transport-forked: True Content-ID: <9CA31D80D8C587429860D14EDBEEDFCE@CANPRD01.PROD.OUTLOOK.COM> MIME-Version: 1.0 X-OriginatorOrg: calian.com X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-AuthSource: YT1PR01MB3546.CANPRD01.PROD.OUTLOOK.COM X-MS-Exchange-CrossTenant-Network-Message-Id: 9ea6ac6b-bfad-4348-7f82-08d88a4eeb2a X-MS-Exchange-CrossTenant-originalarrivaltime: 16 Nov 2020 16:44:42.9638 (UTC) X-MS-Exchange-CrossTenant-fromentityheader: Hosted X-MS-Exchange-CrossTenant-id: 23b57807-562f-49ad-92c4-3bb0f07a1fdf X-MS-Exchange-CrossTenant-mailboxtype: HOSTED X-MS-Exchange-CrossTenant-userprincipalname: NBkSJ2mhs5xwKG0mB2/T1ZtlkxpDY1djUX+GbfqOogT8vRfO84XfwzDmAXiKUXMQIdVK785ql73LV0pTAXazB0D4VyKeQzxNDpGpdkmeIcE= X-MS-Exchange-Transport-CrossTenantHeadersStamped: YTBPR01MB3984 X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20201116_114445_706528_3C92AFE1 X-CRM114-Status: GOOD ( 30.62 ) X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: "linux-gpio@vger.kernel.org" , "linux-kernel@vger.kernel.org" , "linux-arm-kernel@lists.infradead.org" , "git@xilinx.com" Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+linux-arm-kernel=archiver.kernel.org@lists.infradead.org On Thu, 2020-11-12 at 22:42 +0530, Srinivas Neeli wrote: > Adds interrupt support to the Xilinx GPIO driver so that rising and > falling edge line events can be supported. Since interrupt support is > an optional feature in the Xilinx IP, the driver continues to support > devices which have no interrupt provided. > > Signed-off-by: Robert Hancock > Signed-off-by: Shubhrajyoti Datta > Signed-off-by: Srinivas Neeli > --- > Chnages in V3: > -Created separate patch for Clock changes and runtime resume > and suspend. > -Updated minor review comments. > > Changes in V2: > -Added check for return value of platform_get_irq() API. > -Updated code to support rising edge and falling edge. > -Added xgpio_xlate() API to support switch. > -Added MAINTAINERS fragment > --- > drivers/gpio/Kconfig | 2 + > drivers/gpio/gpio-xilinx.c | 242 > ++++++++++++++++++++++++++++++++++++++++++++- > 2 files changed, 240 insertions(+), 4 deletions(-) > > diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig > index 5d4de5cd6759..cf4959891eab 100644 > --- a/drivers/gpio/Kconfig > +++ b/drivers/gpio/Kconfig > @@ -677,6 +677,8 @@ config GPIO_XGENE_SB > > config GPIO_XILINX > tristate "Xilinx GPIO support" > + select GPIOLIB_IRQCHIP > + depends on OF_GPIO This OF_GPIO dependency was previously removed - is this required? It appears the code is now setting of_gpio_n_cells but I am not sure if this is necessary or helpful since the other of_gpio functions are not used. > help > Say yes here to support the Xilinx FPGA GPIO device > > diff --git a/drivers/gpio/gpio-xilinx.c b/drivers/gpio/gpio-xilinx.c > index 69bdf1910215..855550a06ded 100644 > --- a/drivers/gpio/gpio-xilinx.c > +++ b/drivers/gpio/gpio-xilinx.c > @@ -10,9 +10,12 @@ > #include > #include > #include > +#include > #include > +#include > #include > #include > +#include > #include > #include > > @@ -22,6 +25,11 @@ > > #define XGPIO_CHANNEL_OFFSET 0x8 > > +#define XGPIO_GIER_OFFSET 0x11c /* Global Interrupt Enable */ > +#define XGPIO_GIER_IE BIT(31) > +#define XGPIO_IPISR_OFFSET 0x120 /* IP Interrupt Status */ > +#define XGPIO_IPIER_OFFSET 0x128 /* IP Interrupt Enable */ > + > /* Read/Write access to the GPIO registers */ > #if defined(CONFIG_ARCH_ZYNQ) || defined(CONFIG_X86) > # define xgpio_readreg(offset) readl(offset) > @@ -36,9 +44,14 @@ > * @gc: GPIO chip > * @regs: register block > * @gpio_width: GPIO width for every channel > - * @gpio_state: GPIO state shadow register > + * @gpio_state: GPIO write state shadow register > + * @gpio_last_irq_read: GPIO read state register from last interrupt > * @gpio_dir: GPIO direction shadow register > * @gpio_lock: Lock used for synchronization > + * @irq: IRQ used by GPIO device > + * @irq_enable: GPIO IRQ enable/disable bitfield > + * @irq_rising_edge: GPIO IRQ rising edge enable/disable bitfield > + * @irq_falling_edge: GPIO IRQ falling edge enable/disable bitfield > * @clk: clock resource for this driver > */ > struct xgpio_instance { > @@ -46,8 +59,13 @@ struct xgpio_instance { > void __iomem *regs; > unsigned int gpio_width[2]; > u32 gpio_state[2]; > + u32 gpio_last_irq_read[2]; > u32 gpio_dir[2]; > spinlock_t gpio_lock; /* For serializing operations */ > + int irq; > + u32 irq_enable[2]; > + u32 irq_rising_edge[2]; > + u32 irq_falling_edge[2]; > struct clk *clk; > }; > > @@ -258,6 +276,183 @@ static void xgpio_save_regs(struct > xgpio_instance *chip) > } > > /** > + * xgpio_irq_ack - Acknowledge a child GPIO interrupt. > + * @irq_data: per IRQ and chip data passed down to chip functions > + * This currently does nothing, but irq_ack is unconditionally > called by > + * handle_edge_irq and therefore must be defined. > + */ > +static void xgpio_irq_ack(struct irq_data *irq_data) > +{ > +} > + > +/** > + * xgpio_irq_mask - Write the specified signal of the GPIO device. > + * @irq_data: per IRQ and chip data passed down to chip functions > + */ > +static void xgpio_irq_mask(struct irq_data *irq_data) > +{ > + unsigned long flags; > + struct xgpio_instance *chip = > irq_data_get_irq_chip_data(irq_data); > + int irq_offset = irqd_to_hwirq(irq_data); > + int index = xgpio_index(chip, irq_offset); > + int offset = xgpio_offset(chip, irq_offset); > + > + spin_lock_irqsave(&chip->gpio_lock, flags); > + > + chip->irq_enable[index] &= ~BIT(offset); > + > + if (!chip->irq_enable[index]) { > + /* Disable per channel interrupt */ > + u32 temp = xgpio_readreg(chip->regs + > XGPIO_IPIER_OFFSET); > + > + temp &= ~BIT(index); > + xgpio_writereg(chip->regs + XGPIO_IPIER_OFFSET, temp); > + } > + spin_unlock_irqrestore(&chip->gpio_lock, flags); > +} > + > +/** > + * xgpio_irq_unmask - Write the specified signal of the GPIO device. > + * @irq_data: per IRQ and chip data passed down to chip functions > + */ > +static void xgpio_irq_unmask(struct irq_data *irq_data) > +{ > + unsigned long flags; > + struct xgpio_instance *chip = > irq_data_get_irq_chip_data(irq_data); > + int irq_offset = irqd_to_hwirq(irq_data); > + int index = xgpio_index(chip, irq_offset); > + int offset = xgpio_offset(chip, irq_offset); > + u32 old_enable = chip->irq_enable[index]; > + > + spin_lock_irqsave(&chip->gpio_lock, flags); > + > + chip->irq_enable[index] |= BIT(offset); > + > + if (!old_enable) { > + /* Clear any existing per-channel interrupts */ > + u32 val = xgpio_readreg(chip->regs + > XGPIO_IPISR_OFFSET) & > + BIT(index); > + > + if (val) > + xgpio_writereg(chip->regs + XGPIO_IPISR_OFFSET, > val); > + > + /* Update GPIO IRQ read data before enabling > interrupt*/ > + val = xgpio_readreg(chip->regs + XGPIO_DATA_OFFSET + > + index * XGPIO_CHANNEL_OFFSET); > + chip->gpio_last_irq_read[index] = val; > + > + /* Enable per channel interrupt */ > + val = xgpio_readreg(chip->regs + XGPIO_IPIER_OFFSET); > + val |= BIT(index); > + xgpio_writereg(chip->regs + XGPIO_IPIER_OFFSET, val); > + } > + > + spin_unlock_irqrestore(&chip->gpio_lock, flags); > +} > + > +/** > + * xgpio_set_irq_type - Write the specified signal of the GPIO > device. > + * @irq_data: Per IRQ and chip data passed down to chip functions > + * @type: Interrupt type that is to be set for the gpio pin > + * > + * Return: > + * 0 if interrupt type is supported otherwise -EINVAL > + */ > +static int xgpio_set_irq_type(struct irq_data *irq_data, unsigned > int type) > +{ > + struct xgpio_instance *chip = > irq_data_get_irq_chip_data(irq_data); > + int irq_offset = irqd_to_hwirq(irq_data); > + int index = xgpio_index(chip, irq_offset); > + int offset = xgpio_offset(chip, irq_offset); > + > + /* > + * The Xilinx GPIO hardware provides a single interrupt status > + * indication for any state change in a given GPIO channel > (bank). > + * Therefore, only rising edge or falling edge triggers are > + * supported. > + */ > + switch (type & IRQ_TYPE_SENSE_MASK) { > + case IRQ_TYPE_EDGE_BOTH: > + chip->irq_rising_edge[index] |= BIT(offset); > + chip->irq_falling_edge[index] |= BIT(offset); > + break; > + case IRQ_TYPE_EDGE_RISING: > + chip->irq_rising_edge[index] |= BIT(offset); > + chip->irq_falling_edge[index] &= ~BIT(offset); > + break; > + case IRQ_TYPE_EDGE_FALLING: > + chip->irq_rising_edge[index] &= ~BIT(offset); > + chip->irq_falling_edge[index] |= BIT(offset); > + break; > + default: > + return -EINVAL; > + } > + > + irq_set_handler_locked(irq_data, handle_edge_irq); > + return 0; > +} > + > +static struct irq_chip xgpio_irqchip = { > + .name = "gpio-xilinx", > + .irq_ack = xgpio_irq_ack, > + .irq_mask = xgpio_irq_mask, > + .irq_unmask = xgpio_irq_unmask, > + .irq_set_type = xgpio_set_irq_type, > +}; > + > +/** > + * xgpio_irqhandler - Gpio interrupt service routine > + * @desc: Pointer to interrupt description > + */ > +static void xgpio_irqhandler(struct irq_desc *desc) > +{ > + struct xgpio_instance *chip = irq_desc_get_handler_data(desc); > + struct irq_chip *irqchip = irq_desc_get_chip(desc); > + u32 num_channels = chip->gpio_width[1] ? 2 : 1; > + u32 offset = 0, index; > + u32 status = xgpio_readreg(chip->regs + XGPIO_IPISR_OFFSET); > + > + xgpio_writereg(chip->regs + XGPIO_IPISR_OFFSET, status); > + > + chained_irq_enter(irqchip, desc); > + for (index = 0; index < num_channels; index++) { > + if ((status & BIT(index))) { > + unsigned long rising_events, falling_events, > all_events; > + unsigned long flags; > + u32 data, bit; > + unsigned int irq; > + > + spin_lock_irqsave(&chip->gpio_lock, flags); > + data = xgpio_readreg(chip->regs + > XGPIO_DATA_OFFSET + > + index * > XGPIO_CHANNEL_OFFSET); > + rising_events = data & > + ~chip- > >gpio_last_irq_read[index] & > + chip->irq_enable[index] & > + chip->irq_rising_edge[index]; > + falling_events = ~data & > + chip- > >gpio_last_irq_read[index] & > + chip->irq_enable[index] & > + chip->irq_falling_edge[index]; > + dev_dbg(chip->gc.parent, > + "IRQ chan %u rising 0x%lx falling > 0x%lx\n", > + index, rising_events, falling_events); > + all_events = rising_events | falling_events; > + chip->gpio_last_irq_read[index] = data; > + spin_unlock_irqrestore(&chip->gpio_lock, > flags); > + > + for_each_set_bit(bit, &all_events, 32) { > + irq = irq_find_mapping(chip- > >gc.irq.domain, > + offset + bit); > + generic_handle_irq(irq); > + } > + } > + offset += chip->gpio_width[index]; > + } > + > + chained_irq_exit(irqchip, desc); > +} > + > +/** > * xgpio_of_probe - Probe method for the GPIO device. > * @pdev: pointer to the platform device > * > @@ -270,7 +465,10 @@ static int xgpio_probe(struct platform_device > *pdev) > struct xgpio_instance *chip; > int status = 0; > struct device_node *np = pdev->dev.of_node; > - u32 is_dual; > + u32 is_dual = 0; > + u32 cells = 2; > + struct gpio_irq_chip *girq; > + u32 temp; > > chip = devm_kzalloc(&pdev->dev, sizeof(*chip), GFP_KERNEL); > if (!chip) > @@ -285,6 +483,10 @@ static int xgpio_probe(struct platform_device > *pdev) > if (of_property_read_u32(np, "xlnx,tri-default", &chip- > >gpio_dir[0])) > chip->gpio_dir[0] = 0xFFFFFFFF; > > + /* Update cells with gpio-cells value */ > + if (of_property_read_u32(np, "#gpio-cells", &cells)) > + dev_dbg(&pdev->dev, "Missing gpio-cells property\n"); > + > /* > * Check device node and parent device node for device width > * and assume default width of 32 > @@ -321,6 +523,7 @@ static int xgpio_probe(struct platform_device > *pdev) > chip->gc.parent = &pdev->dev; > chip->gc.direction_input = xgpio_dir_in; > chip->gc.direction_output = xgpio_dir_out; > + chip->gc.of_gpio_n_cells = cells; > chip->gc.get = xgpio_get; > chip->gc.set = xgpio_set; > chip->gc.set_multiple = xgpio_set_multiple; > @@ -348,14 +551,45 @@ static int xgpio_probe(struct platform_device > *pdev) > > xgpio_save_regs(chip); > > + chip->irq = platform_get_irq_optional(pdev, 0); > + if (chip->irq <= 0) > + goto skip_irq; > + > + /* Disable per-channel interrupts */ > + xgpio_writereg(chip->regs + XGPIO_IPIER_OFFSET, 0); > + /* Clear any existing per-channel interrupts */ > + temp = xgpio_readreg(chip->regs + XGPIO_IPISR_OFFSET); > + xgpio_writereg(chip->regs + XGPIO_IPISR_OFFSET, temp); > + /* Enable global interrupts */ > + xgpio_writereg(chip->regs + XGPIO_GIER_OFFSET, XGPIO_GIER_IE); > + > + girq = &chip->gc.irq; > + girq->chip = &xgpio_irqchip; > + girq->parent_handler = xgpio_irqhandler; > + girq->num_parents = 1; > + girq->parents = devm_kcalloc(&pdev->dev, 1, > + sizeof(*girq->parents), > + GFP_KERNEL); > + if (!girq->parents) { > + status = -ENOMEM; > + goto err_unprepare_clk; > + } > + girq->parents[0] = chip->irq; > + girq->default_type = IRQ_TYPE_NONE; > + girq->handler = handle_bad_irq; > + > +skip_irq: > status = devm_gpiochip_add_data(&pdev->dev, &chip->gc, chip); > if (status) { > dev_err(&pdev->dev, "failed to add GPIO chip\n"); > - clk_disable_unprepare(chip->clk); > - return status; > + goto err_unprepare_clk; > } > > return 0; > + > +err_unprepare_clk: > + clk_disable_unprepare(chip->clk); > + return status; > } > > static const struct of_device_id xgpio_of_match[] = { -- Robert Hancock Senior Hardware Designer, Calian Advanced Technologies www.calian.com _______________________________________________ linux-arm-kernel mailing list linux-arm-kernel@lists.infradead.org http://lists.infradead.org/mailman/listinfo/linux-arm-kernel