Received: by 2002:ad5:474a:0:0:0:0:0 with SMTP id i10csp2610050imu; Sun, 13 Jan 2019 06:04:16 -0800 (PST) X-Google-Smtp-Source: ALg8bN5EAvOkVwZIpbJirVgu3boYM5Pob3y+hxb1VdsJK8gsuFUZ/KPtsZ/KJf3rcxjYmg8pIkgu X-Received: by 2002:a17:902:9b87:: with SMTP id y7mr22090975plp.336.1547388256747; Sun, 13 Jan 2019 06:04:16 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1547388256; cv=none; d=google.com; s=arc-20160816; b=s2Gv3Wy9xHTBSHDpjXF95sJY9GWT0YvMmf8lmTr+dxULKa1IwbdssBkwbGrUejLtML IR4HzLuaIin9ahQT0qlYrebx/9oJPetwk47rJIXAb6a0qu7EikHQTyDqL7JL/O38CAoG Fo56R3V8xLC9Exiqk8afmIAMY9v7QUls/VcmGdT8vHfqi8ABacDpXD8vDgcOXOyxCwE4 qSt1pRSObFNu3/jX6phxje/V+eIEWZWRJuaxaqmbqjMkgW0T4/nWU0hQgEIcpJWGWvbD NJiUSYjf3vM3rZEaWUpnvD2NamGVM6INe8tKkOrWNhuLxwUXTZHibllCED6iY9Rs774R fIYg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:content-transfer-encoding:mime-version :references:in-reply-to:message-id:date:subject:cc:to:from; bh=BO5WpVVhmxZWH9qKc1n+dtwXEmMrhIm6VK4I5/YXl7s=; b=Gch/ddc7TxBBGQCfC/DZC/EwiDqoWl4RTJS7QsdhDbBGQGEmsbvX0f+OqoMuWdUIBG tTaywK1VXd7TJe8yqdXVnEfLCUAmdDepWRqu/ngorbL5ngdYBamGC4CSoj/5x1SUojVi 8UT2+/NGb+Lmdcvox5I5F4y3SD7WIDo4Tj4UhFlb3c7WotUSPxrF/1giMzI+oI/2ECDQ XU0uhLxhh5MIHo8aL6AXjN9vqHhQu0/jogCD1TBI9AzGte4E9raM+mt0thop5W3cNJMN Ijracg3E+PpqxB/GsWurVHy+KWOb1nv43UhUHAj0zSaWZJUwp3ALueYQCV93HPJjoA9E TdvA== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id i5si18215035pfo.189.2019.01.13.06.03.29; Sun, 13 Jan 2019 06:04:16 -0800 (PST) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726699AbfAMOAA (ORCPT + 99 others); Sun, 13 Jan 2019 09:00:00 -0500 Received: from mout.gmx.net ([212.227.15.18]:48931 "EHLO mout.gmx.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726545AbfAMN7z (ORCPT ); Sun, 13 Jan 2019 08:59:55 -0500 Received: from longitude ([109.90.232.48]) by mail.gmx.com (mrgmx001 [212.227.17.190]) with ESMTPSA (Nemesis) id 0MMCFR-1gcvfZ234f-00846w; Sun, 13 Jan 2019 14:59:52 +0100 From: =?UTF-8?q?Jonathan=20Neusch=C3=A4fer?= To: linux-gpio@vger.kernel.org Cc: Linus Walleij , Bartosz Golaszewski , linux-kernel@vger.kernel.org, =?UTF-8?q?Jonathan=20Neusch=C3=A4fer?= Subject: [PATCH 1/2] gpio: hlwd: Add basic IRQ support Date: Sun, 13 Jan 2019 14:58:43 +0100 Message-Id: <20190113135844.13109-2-j.neuschaefer@gmx.net> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20190113135844.13109-1-j.neuschaefer@gmx.net> References: <20190113135844.13109-1-j.neuschaefer@gmx.net> MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-Provags-ID: V03:K1:OLv5vUU5MJKzcb1LR5FhLhF2S8EKHzw5Qwu/e+gkSk9GHxVXUOs aVh5aQY+YqFDYV7AeDFRFzcDUymO7MAe56ib+tZWXjhrUQkLR8aZ5koWEg4w7NPhfO56ARZ 1kqkUzpoQ/JU6BmK9MtfkLG6p562J0Yll4yC3Q5c9PQUbiJJblSLCHGcuG2eDZJZ7/P9qYh nb0LbDTZwDOWKNVvNiWNQ== X-Spam-Flag: NO X-UI-Out-Filterresults: notjunk:1;V03:K0:z7OpcWq79zE=:05xWvybGWfohRlDtFApukx 9w4n2v8H6kXyf+7rJs0PbWpu9EYax2N7USR+sryGvD/s6FXjb9T0p/k6zuibNZR+mvW+hiIDC nxNkM7y+IJS0igrwh9oo2j+r4x36g8zbrK7hvdaFoRIckArlDfPInEd4F2NJ81g8jrSkShnC3 Uumw0dHHcEvq9x/7jCpA6DxLU4lb+REfzEtnFTwAjIVjq57AtTrPhxWERe1IdcKpjWyp1+cQA Rwx2XhHVRnBonH+3MpHCiX1+OpXMUQmBDwmoG9g+3EcghM36tgNsG4eBZ7pLkuE4/tX/CbKoS HdtrkLzFsbIkIDjm3tHqq7YzuARysYMHWLHYS69AJmJXcYUIelaBaaec7Q6eKjmOwoYgPkFYT hfKrywhWxlOi1CQv8qTnq6OFrzfZ0mESN1RRLrEu95CdxIrl5GaO0YP7VZqkF1GMZMftDQl7K DEt4OjlhTQepMqv3jg48EJrRPeJ4VGQU7PSbkxEq1rB9E+dsXjatcHSQJf10z1+HBn3sVziho M2igLYD/w7GjwRhaS2rA8HMKEeGgvUSqV3bh3VMG8EqOQIKPtqJG1SQlVZlOEDv06RYxfMF8T /vAFR059EOwjEVd8GIgJcNpdu0v/OHTEklmjQlhkMaXlPGTHQ/v9Xt3GDYfDd/7pf8gr84Q71 l28nz1AFlA7u5JnXZ0ZTnN3eAz3Vrdrk507EjdpkqWg4IZCdPBzAKdfVK1E+/x+4Q+jTno8Qq lYdWSpFcvGTcgHWyxKXJN2eR1V/noY87efWdJvSBV43KccZjzaWAurSYsVyBPwEoAzxeLgrMt YKRfcl2heVp8xrDhDHr6La4s5Bp1js/d2ZPAuaoFhRuwxa7Sx8tYgp1Fi1B3+Gfq1RPHqwbhp vNnI3rCi3vSB3ZC7DDVPUrZ18X+aakZLzfOJPSCwUs1sDRvIC6d5GRQXVuKr+YatjRE1bteko zN+dAG1cxZg== Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org This patch implements level-triggered IRQs in the Hollywood GPIO driver. Edge triggered interrupts are not supported in this GPIO controller, so I moved their emulation into a separate patch. Signed-off-by: Jonathan Neuschäfer --- I'm not entirely sure about the locking, but lockdep doesn't complain. --- drivers/gpio/Kconfig | 1 + drivers/gpio/gpio-hlwd.c | 136 ++++++++++++++++++++++++++++++++++++++- 2 files changed, 136 insertions(+), 1 deletion(-) diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index b5a2845347ec..f77180dd87bd 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -258,6 +258,7 @@ config GPIO_HLWD tristate "Nintendo Wii (Hollywood) GPIO" depends on OF_GPIO select GPIO_GENERIC + select GPIOLIB_IRQCHIP help Select this to support the GPIO controller of the Nintendo Wii. diff --git a/drivers/gpio/gpio-hlwd.c b/drivers/gpio/gpio-hlwd.c index a63136a68ba3..9a93546f3d11 100644 --- a/drivers/gpio/gpio-hlwd.c +++ b/drivers/gpio/gpio-hlwd.c @@ -48,9 +48,107 @@ struct hlwd_gpio { struct gpio_chip gpioc; + struct irq_chip irqc; void __iomem *regs; + int irq; }; +static void hlwd_gpio_irqhandler(struct irq_desc *desc) +{ + struct hlwd_gpio *hlwd = + gpiochip_get_data(irq_desc_get_handler_data(desc)); + struct irq_chip *chip = irq_desc_get_chip(desc); + unsigned long flags; + unsigned long pending; + int hwirq; + + spin_lock_irqsave(&hlwd->gpioc.bgpio_lock, flags); + pending = hlwd->gpioc.read_reg(hlwd->regs + HW_GPIOB_INTFLAG); + pending &= hlwd->gpioc.read_reg(hlwd->regs + HW_GPIOB_INTMASK); + spin_unlock_irqrestore(&hlwd->gpioc.bgpio_lock, flags); + + chained_irq_enter(chip, desc); + + for_each_set_bit(hwirq, &pending, 32) { + int irq = irq_find_mapping(hlwd->gpioc.irq.domain, hwirq); + + generic_handle_irq(irq); + } + + chained_irq_exit(chip, desc); +} + +static void hlwd_gpio_irq_ack(struct irq_data *data) +{ + struct hlwd_gpio *hlwd = + gpiochip_get_data(irq_data_get_irq_chip_data(data)); + + hlwd->gpioc.write_reg(hlwd->regs + HW_GPIOB_INTFLAG, BIT(data->hwirq)); +} + +static void hlwd_gpio_irq_mask(struct irq_data *data) +{ + struct hlwd_gpio *hlwd = + gpiochip_get_data(irq_data_get_irq_chip_data(data)); + unsigned long flags; + u32 mask; + + spin_lock_irqsave(&hlwd->gpioc.bgpio_lock, flags); + mask = hlwd->gpioc.read_reg(hlwd->regs + HW_GPIOB_INTMASK); + mask &= ~BIT(data->hwirq); + hlwd->gpioc.write_reg(hlwd->regs + HW_GPIOB_INTMASK, mask); + spin_unlock_irqrestore(&hlwd->gpioc.bgpio_lock, flags); +} + +static void hlwd_gpio_irq_unmask(struct irq_data *data) +{ + struct hlwd_gpio *hlwd = + gpiochip_get_data(irq_data_get_irq_chip_data(data)); + unsigned long flags; + u32 mask; + + spin_lock_irqsave(&hlwd->gpioc.bgpio_lock, flags); + mask = hlwd->gpioc.read_reg(hlwd->regs + HW_GPIOB_INTMASK); + mask |= BIT(data->hwirq); + hlwd->gpioc.write_reg(hlwd->regs + HW_GPIOB_INTMASK, mask); + spin_unlock_irqrestore(&hlwd->gpioc.bgpio_lock, flags); +} + +static void hlwd_gpio_irq_enable(struct irq_data *data) +{ + hlwd_gpio_irq_ack(data); + hlwd_gpio_irq_unmask(data); +} + +static int hlwd_gpio_irq_set_type(struct irq_data *data, unsigned int flow_type) +{ + struct hlwd_gpio *hlwd = + gpiochip_get_data(irq_data_get_irq_chip_data(data)); + unsigned long flags; + u32 level; + + spin_lock_irqsave(&hlwd->gpioc.bgpio_lock, flags); + + switch (flow_type) { + case IRQ_TYPE_LEVEL_HIGH: + level = hlwd->gpioc.read_reg(hlwd->regs + HW_GPIOB_INTLVL); + level |= BIT(data->hwirq); + hlwd->gpioc.write_reg(hlwd->regs + HW_GPIOB_INTLVL, level); + break; + case IRQ_TYPE_LEVEL_LOW: + level = hlwd->gpioc.read_reg(hlwd->regs + HW_GPIOB_INTLVL); + level &= ~BIT(data->hwirq); + hlwd->gpioc.write_reg(hlwd->regs + HW_GPIOB_INTLVL, level); + break; + default: + spin_unlock_irqrestore(&hlwd->gpioc.bgpio_lock, flags); + return -EINVAL; + } + + spin_unlock_irqrestore(&hlwd->gpioc.bgpio_lock, flags); + return 0; +} + static int hlwd_gpio_probe(struct platform_device *pdev) { struct hlwd_gpio *hlwd; @@ -92,7 +190,43 @@ static int hlwd_gpio_probe(struct platform_device *pdev) ngpios = 32; hlwd->gpioc.ngpio = ngpios; - return devm_gpiochip_add_data(&pdev->dev, &hlwd->gpioc, hlwd); + res = devm_gpiochip_add_data(&pdev->dev, &hlwd->gpioc, hlwd); + if (res) + return res; + + /* Mask and ack all interrupts */ + iowrite32be(0, hlwd->regs + HW_GPIOB_INTMASK); + iowrite32be(0xffffffff, hlwd->regs + HW_GPIOB_INTFLAG); + + /* + * If this GPIO controller is not marked as an interrupt controller in + * the DT, return. + */ + if (!of_property_read_bool(pdev->dev.of_node, "interrupt-controller")) + return 0; + + hlwd->irq = platform_get_irq(pdev, 0); + if (hlwd->irq < 0) { + dev_info(&pdev->dev, "platform_get_irq returned %d\n", + hlwd->irq); + return hlwd->irq; + } + + hlwd->irqc.name = "GPIO"; + hlwd->irqc.irq_mask = hlwd_gpio_irq_mask; + hlwd->irqc.irq_unmask = hlwd_gpio_irq_unmask; + hlwd->irqc.irq_enable = hlwd_gpio_irq_enable; + hlwd->irqc.irq_set_type = hlwd_gpio_irq_set_type; + + res = gpiochip_irqchip_add(&hlwd->gpioc, &hlwd->irqc, 0, + handle_level_irq, IRQ_TYPE_NONE); + if (res) + return res; + + gpiochip_set_chained_irqchip(&hlwd->gpioc, &hlwd->irqc, + hlwd->irq, hlwd_gpio_irqhandler); + + return 0; } static const struct of_device_id hlwd_gpio_match[] = { -- 2.20.1