From patchwork Mon Aug 27 20:15:51 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Linus Walleij X-Patchwork-Id: 145217 Delivered-To: patch@linaro.org Received: by 2002:a2e:1648:0:0:0:0:0 with SMTP id 8-v6csp358556ljw; Mon, 27 Aug 2018 13:15:58 -0700 (PDT) X-Google-Smtp-Source: ANB0VdZc5XRfNmUUybZomNkd/ExSpVUdUuWhje6In9YQv/fR/xikExgvCHrlZ6+axpmdKNFKSYVE X-Received: by 2002:a63:c807:: with SMTP id z7-v6mr13198402pgg.77.1535400958677; Mon, 27 Aug 2018 13:15:58 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1535400958; cv=none; d=google.com; s=arc-20160816; b=Tey80XxIpApfbNeDEZLnyVVwp/LfFN+8JXJLGP4rywBCxy/JOQIrckF2W/6UknqtHN 7tHUWSsjmzKqv1H1k8KpJ3Whh+7+BL5XsTtfQ3g9OlNhFB4XKacfuo+BP6W6IlKN+HP4 AYPQzQqmbDdR6SsblBfCwmuCy3qKJQRZaYQCsio4L6+5G11gSeQeVSVtx74TVBh2DUv1 hyBd3pqh4viRY047I7bNmYLfbTLdYacVo0oVotqEd+KuMS/5ZjBmN+kX+MK8n1I5FQvC fhNAWRbPgnk1w5VSiGUSu7V8mR5K7aBoM2ics4wYnLduqQEeCbbOHSC2q3uZ8ZtwCv4r jpLg== 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=XMcJhHnMLBCOWw/8y/MR/AExu5eyWDChkwXCqnMwgsE=; b=tfrePJ9os6hzJmIaI1TMKjoqdOG7sn3Tq44Bk8vF6zTYz5LD8taQGLQ86gE3aWA3j8 KBcbjg4YLyr93ET5aQmm3Ou9fDkjmBhzHxnRg1+AmjNEFdTxgCB58neReGsuN2iFVnGi tg7SNoBLcOCYT8xz25tcfsdaxtd+Z+ppLWGd34UYLVjRzxJJdMq6TLmCo1SQNn27jBJL OtAOFkrUUHkn5UJmJIdMu+sQgy1iy3dhhL1P+4L+gs3Jn3nCpdI4kspFEmsjGEowArfM Aaf68M0abJbKiReSoVyHS5dbdJbgWV939lb6zG+GBOuofNv2iB08yA4EILoGL5z3qpov 9Xjg== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@linaro.org header.s=google header.b=S+48Pr5D; 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 f5-v6si155040plf.411.2018.08.27.13.15.58; Mon, 27 Aug 2018 13:15:58 -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=S+48Pr5D; 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 S1727172AbeH1AEF (ORCPT + 5 others); Mon, 27 Aug 2018 20:04:05 -0400 Received: from mail-lf1-f67.google.com ([209.85.167.67]:37640 "EHLO mail-lf1-f67.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727013AbeH1AEF (ORCPT ); Mon, 27 Aug 2018 20:04:05 -0400 Received: by mail-lf1-f67.google.com with SMTP id j8-v6so203124lfb.4 for ; Mon, 27 Aug 2018 13:15: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; bh=XMcJhHnMLBCOWw/8y/MR/AExu5eyWDChkwXCqnMwgsE=; b=S+48Pr5DKMOPXYhPpNi6nyOVqWfgMXCnWPaJdIOfLXnNYTO84oyk6+c78pw1VTk0t1 yxBZI57EHFpbZrH3g/wzFDqvNbhk299QByBz0dyDEgcyaEAUv3NJ0azVg9cEZy/Q/VQJ oHywi1vYAWrA5/SWhylSl984k+QyPaCidP0dU= 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=XMcJhHnMLBCOWw/8y/MR/AExu5eyWDChkwXCqnMwgsE=; b=Al9v3Opju8eAGrDU2VssDL9tC3G55p5TFCyqzI9zHoLfSXlq6CAaU/SI64yjjZu4XZ 9LUHz1KMZH3pCCgExLn4IC5v0LmU5WzalcqVpF+ezruxZWJj8nukiDLc3ZvtOnz9qL1T DTOvf8zjhPjJplEBj5ocmiyh5qWP2hFX9IG8WYBusUY+1645rkDEYZbwYhnMCVkERU2S V27geW3qlEP0i395KEek9PK4tz9CcWGR/dOxvLBuhuOYHOWnF/0Bs8AsyU2146OzASRX VtBmbnDK+vsDrKEzy/5DVrRDCtdapj4KU9QWl97wSQ1Yw98XL8NV85uQAtA04U0Ln0Wn r3dQ== X-Gm-Message-State: APzg51AKhXKopvVQ5kJkuc4FS7WKNjy0NVaIbTuCbNTniFZHupWSN2ii vzw3KmXwHhn2WBbQto7s1tV28A== X-Received: by 2002:a19:1591:: with SMTP id 17-v6mr8999982lfv.141.1535400955822; Mon, 27 Aug 2018 13:15:55 -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 x8-v6sm24818lji.53.2018.08.27.13.15.53 (version=TLS1_2 cipher=ECDHE-RSA-CHACHA20-POLY1305 bits=256/256); Mon, 27 Aug 2018 13:15:54 -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 v2] gpio: ftgpio: Support debounce timer Date: Mon, 27 Aug 2018 22:15:51 +0200 Message-Id: <20180827201551.16012-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 --- ChangeLog v1->v2: - Fix up a unchecked line in writing default zero to debounce enable. --- 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 f548bc92e1d1..95f578804b0e 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; @@ -214,6 +281,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; @@ -223,6 +294,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(0x0, g->base + GPIO_DEBOUNCE_EN); + ret = gpiochip_irqchip_add(&g->gc, &ftgpio_gpio_irqchip, 0, handle_bad_irq, IRQ_TYPE_NONE);