From patchwork Sun Aug 26 11:03:29 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Linus Walleij X-Patchwork-Id: 145134 Delivered-To: patch@linaro.org Received: by 2002:a2e:1648:0:0:0:0:0 with SMTP id 8-v6csp3078820ljw; Sun, 26 Aug 2018 04:03:36 -0700 (PDT) X-Google-Smtp-Source: ANB0VdaTFFjLJw7ehnpzy41FjNvDm0M88l5C4vYmEwktoh+4vJqvKTgqMZBWPzpmhYkh0pNuDYKd X-Received: by 2002:a63:1866:: with SMTP id 38-v6mr8305599pgy.313.1535281416384; Sun, 26 Aug 2018 04:03:36 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1535281416; cv=none; d=google.com; s=arc-20160816; b=Lcu8Kv7izRJBpbw8zaSnwA66VRd3tmDP+Sv4WgGt8Qf3QGU7Amp4BC9ihx4jw7Dg/M yaOI2TlKMxBUt+Baqm/Mn1hMR9lTWdmWSfJTL6XE+7hxpuQT+WqZ/l4T1CytF/upVOx+ yTN0ooQZOsfJWD/MMVGDZw8yeSeoztCnC47jOf4w2E1/xSn8a2zlAmA5NP57Gun3Xyci Dn9vTD1+HI6WqeTcMYzr9cHiclPmSBT6g8DhtcdyuvB2CNRP5Yv/iqRG/lv+vxgyLA3n eS+Umxs7XnUeLUbnEaRHWEo04gwmmie83MtIQ02CuyUtKHdbaG/ZpQP6jkpTHK55YEmP 0eYg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:message-id:date:subject:cc:to:from :dkim-signature:arc-authentication-results; bh=sPfeoUA2/PuDJTk+m7dzAZUmI6BlXQyU2SBh15Y+Ewk=; b=S0YFEOANPn1brWVQY5DVnFVkRWCDhtl+17bNcAovx+/6nLv149IPSv0PCkgh0th1BQ tofOz2FwxziXF/xUjA/rErjPjKFoz1PAirBS/dNTzghsCvmBrqZljdnQMjbaiitCC1sR REcSn7sg7xTRDYPaSFdlc9IC0i/FjmK9ixlEoGyquj+9K2UZQ+bEniFSUCL1o9stsa+g BO9uRlGImpDHCcmx+VxU/DOLPGkKPBTjUa/gQpVMoZFcWVDklqh1rnqGCdMhHSAaDx/w 6AvZZyugD9IhEV7npLDS3JTVTYvLF6/AikkQ6hKZ16uI8Srucx7LJ05uKvwZtQAPiL1/ h/6g== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@linaro.org header.s=google header.b=jWxp9WSx; spf=pass (google.com: best guess record for domain of linux-gpio-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-gpio-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linaro.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id e39-v6si11916259plg.386.2018.08.26.04.03.36; Sun, 26 Aug 2018 04:03:36 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of linux-gpio-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; dkim=pass header.i=@linaro.org header.s=google header.b=jWxp9WSx; spf=pass (google.com: best guess record for domain of linux-gpio-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-gpio-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linaro.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726542AbeHZOpt (ORCPT + 5 others); Sun, 26 Aug 2018 10:45:49 -0400 Received: from mail-lf1-f65.google.com ([209.85.167.65]:44412 "EHLO mail-lf1-f65.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726415AbeHZOpt (ORCPT ); Sun, 26 Aug 2018 10:45:49 -0400 Received: by mail-lf1-f65.google.com with SMTP id g6-v6so9756068lfb.11 for ; Sun, 26 Aug 2018 04:03:34 -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; bh=sPfeoUA2/PuDJTk+m7dzAZUmI6BlXQyU2SBh15Y+Ewk=; b=jWxp9WSxaqoXzyX6//ZT8m3ihJexCwsIw59IGALEz8It6QIXC6b6XQKrKCBMmLU4vC jNUi+P9ngqk0xo0oiDD6gb3wDKFvttNNf5V4b4eqvfpyFS4n82PXrrEelftLizLkqgzP ahugTQuSHa4hWTLJMa4QJXLyRRtjB9h8ZgLLI= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id; bh=sPfeoUA2/PuDJTk+m7dzAZUmI6BlXQyU2SBh15Y+Ewk=; b=G2x0h0RnHx15Q1gmDMEAcg9IY1NWRqa8nRFhRdk+Rj8V6Qu6fayuj4gvt02NMFwVMi Qq1hC0QwYdZx2vDqUANl4XgT1lm0alPTYL0p8rbXq99U00e71ipTq3Xup2oJhqupFktB 3CFrBJ2Vc2HNDHV40uA2sLkGDFSPLKxvY2Etnv8St28Q7TsdcbmEOxt/u22RA8UV7hrc HmHsS1XpZM1wi+JSGxqfuTRMQdls0kbuO2y+FfJWvsQqjcvMUgjPDIw/VY4m1GsV2Mv2 /eencTTO0BuEOZUp/PNPAMe0R5FH8aPmFNygbkFNRrxQZqpdvpxMV79RNIcZP7pc/boW p1tg== X-Gm-Message-State: APzg51A1Qx6o1kKRtOUJuLWtF7Obq4NS2EJL8LPQkK6u++mGw3kmh9s7 nzKvIc581pNxKbwQdtW7hlDsow== X-Received: by 2002:a19:d095:: with SMTP id h143-v6mr5687916lfg.16.1535281413183; Sun, 26 Aug 2018 04:03:33 -0700 (PDT) Received: from localhost.bredbandsbolaget (c-ae7b71d5.014-348-6c756e10.bbcust.telenor.se. [213.113.123.174]) by smtp.gmail.com with ESMTPSA id g16-v6sm2157289lje.1.2018.08.26.04.03.31 (version=TLS1_2 cipher=ECDHE-RSA-CHACHA20-POLY1305 bits=256/256); Sun, 26 Aug 2018 04:03:32 -0700 (PDT) From: Linus Walleij To: Hans Ulli Kroll , Florian Fainelli , Jonas Jensen Cc: linux-arm-kernel@lists.infradead.org, linux-gpio@vger.kernel.org, Linus Walleij Subject: [PATCH 2/2] gpio: ftgpio: Support debounce timer Date: Sun, 26 Aug 2018 13:03:29 +0200 Message-Id: <20180826110329.17778-1-linus.walleij@linaro.org> X-Mailer: git-send-email 2.17.1 Sender: linux-gpio-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-gpio@vger.kernel.org The FTGPIO010 has a debounce timer or rather prescaler that will affect interrupts fireing off the block. We can support this to get proper debounce on e.g. keypresses. Since the same prescaler is used across all GPIO lines of the silicon block, we need to bail out if the prescaler is already set and in use by another line. If the prescaler is already set to what we need, fine, we reuse it. This happens more often than not when the same debounce time is set for several GPIO keys, so we support that usecase easily with this code. Signed-off-by: Linus Walleij --- drivers/gpio/gpio-ftgpio010.c | 74 +++++++++++++++++++++++++++++++++++ 1 file changed, 74 insertions(+) -- 2.17.1 diff --git a/drivers/gpio/gpio-ftgpio010.c b/drivers/gpio/gpio-ftgpio010.c index c26feab143a3..3645607440b5 100644 --- a/drivers/gpio/gpio-ftgpio010.c +++ b/drivers/gpio/gpio-ftgpio010.c @@ -161,6 +161,73 @@ static void ftgpio_gpio_irq_handler(struct irq_desc *desc) chained_irq_exit(irqchip, desc); } +static int ftgpio_gpio_set_config(struct gpio_chip *gc, unsigned int offset, + unsigned long config) +{ + enum pin_config_param param = pinconf_to_config_param(config); + u32 arg = pinconf_to_config_argument(config); + struct ftgpio_gpio *g = gpiochip_get_data(gc); + unsigned long pclk_freq; + u32 deb_div; + u32 val; + + if (param != PIN_CONFIG_INPUT_DEBOUNCE) + return -ENOTSUPP; + + /* + * Debounce only works if interrupts are enabled. The manual + * states that if PCLK is 66 MHz, and this is set to 0x7D0, then + * PCLK is divided down to 33 kHz for the debounce timer. 0x7D0 is + * 2000 decimal, so what they mean is simply that the PCLK is + * divided by this value. + * + * As we get a debounce setting in microseconds, we calculate the + * desired period time and see if we can get a suitable debounce + * time. + */ + pclk_freq = clk_get_rate(g->clk); + deb_div = DIV_ROUND_CLOSEST(pclk_freq, arg); + + /* This register is only 24 bits wide */ + if (deb_div > (1 << 24)) + return -ENOTSUPP; + + dev_dbg(g->dev, "prescale divisor: %08x, resulting frequency %lu Hz\n", + deb_div, (pclk_freq/deb_div)); + + val = readl(g->base + GPIO_DEBOUNCE_PRESCALE); + if (val == deb_div) { + /* + * The debounce timer happens to already be set to the + * desireable value, what a coincidence! We can just enable + * debounce on this GPIO line and return. This happens more + * often than you think, for example when all GPIO keys + * on a system are requesting the same debounce interval. + */ + val = readl(g->base + GPIO_DEBOUNCE_EN); + val |= BIT(offset); + writel(val, g->base + GPIO_DEBOUNCE_EN); + return 0; + } + + val = readl(g->base + GPIO_DEBOUNCE_EN); + if (val) { + /* + * Oh no! Someone is already using the debounce with + * another setting than what we need. Bummer. + */ + return -ENOTSUPP; + } + + /* First come, first serve */ + writel(deb_div, g->base + GPIO_DEBOUNCE_PRESCALE); + /* Enable debounce */ + val |= BIT(offset); + writel(val, g->base + GPIO_DEBOUNCE_EN); + + return 0; +} + static int ftgpio_gpio_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; @@ -208,6 +275,10 @@ static int ftgpio_gpio_probe(struct platform_device *pdev) g->gc.owner = THIS_MODULE; /* ngpio is set by bgpio_init() */ + /* We need a silicon clock to do debounce */ + if (!IS_ERR(g->clk)) + g->gc.set_config = ftgpio_gpio_set_config; + ret = devm_gpiochip_add_data(dev, &g->gc, g); if (ret) goto dis_clk; @@ -217,6 +288,9 @@ static int ftgpio_gpio_probe(struct platform_device *pdev) writel(0x0, g->base + GPIO_INT_MASK); writel(~0x0, g->base + GPIO_INT_CLR); + /* Clear any use of debounce */ + writel(val, g->base + GPIO_DEBOUNCE_EN); + ret = gpiochip_irqchip_add(&g->gc, &ftgpio_gpio_irqchip, 0, handle_bad_irq, IRQ_TYPE_NONE);