From nobody Thu May 2 12:39:17 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zohomail.com; spf=pass (zoho.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail(p=none dis=none) header.from=redhat.com Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1552832242800144.75383277568721; Sun, 17 Mar 2019 07:17:22 -0700 (PDT) Received: from localhost ([127.0.0.1]:56221 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1h5WbH-0004uk-OQ for importer@patchew.org; Sun, 17 Mar 2019 10:17:19 -0400 Received: from eggs.gnu.org ([209.51.188.92]:59155) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1h5WXC-0001pe-Ey for qemu-devel@nongnu.org; Sun, 17 Mar 2019 10:13:07 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1h5WUN-0006gh-SO for qemu-devel@nongnu.org; Sun, 17 Mar 2019 10:10:12 -0400 Received: from mx1.redhat.com ([209.132.183.28]:36976) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1h5WUM-0006dN-Ig; Sun, 17 Mar 2019 10:10:10 -0400 Received: from smtp.corp.redhat.com (int-mx06.intmail.prod.int.phx2.redhat.com [10.5.11.16]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id D933B3DE07; Sun, 17 Mar 2019 14:10:08 +0000 (UTC) Received: from localhost.localdomain (unknown [10.36.112.13]) by smtp.corp.redhat.com (Postfix) with ESMTP id 5088E5C28F; Sun, 17 Mar 2019 14:10:00 +0000 (UTC) From: Paolo Bonzini To: qemu-devel@nongnu.org Date: Sun, 17 Mar 2019 15:10:01 +0100 Message-Id: <20190317141001.3346-1-pbonzini@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.79 on 10.5.11.16 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.29]); Sun, 17 Mar 2019 14:10:09 +0000 (UTC) Content-Transfer-Encoding: quoted-printable X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] X-Received-From: 209.132.183.28 Subject: [Qemu-devel] [PATCH v2] nrf51_gpio: reflect pull-up/pull-down to IRQs X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: contrib@steffen-goertz.de, qemu-arm@nongnu.org, stefanha@redhat.com Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" Content-Type: text/plain; charset="utf-8" Some drivers do I2C bitbanging by keeping the output to 0 and flipping the GPIO direction between input and output (see for example in Linux gpio_set_open_drain_value_commit, in drivers/gpio/gpiolib.c). When the GPIO is set to input, the pull-up resistor brings the output to 1, while when the GPIO is set to output, the output driver brings the output to 0. Implement this for the nRF51 GPIO device model. First, if both input and output are floating, and there is a pull-up or pull-down resistor configured, do not just set s->in, but also make any devices listening on the output qemu_irq receive that value. Second, if the pin is driven both internally (output pin) and externally you don't get a short circuit if both sides drive the pin to the same value. Signed-off-by: Paolo Bonzini Acked-by: Stefan Hajnoczi --- v1->v2: fixed short circuit conditions, reordering the code accordi= ng to the schematic in the datasheet --- hw/gpio/nrf51_gpio.c | 64 +++++++++++++++++++++++++++----------------- 1 file changed, 39 insertions(+), 25 deletions(-) diff --git a/hw/gpio/nrf51_gpio.c b/hw/gpio/nrf51_gpio.c index 86e047d649..e061c58dd2 100644 --- a/hw/gpio/nrf51_gpio.c +++ b/hw/gpio/nrf51_gpio.c @@ -43,6 +43,17 @@ static bool is_connected(uint32_t config, uint32_t level) return state; } =20 +static int pull_value(uint32_t config) +{ + int pull =3D extract32(config, 2, 2); + if (pull =3D=3D NRF51_GPIO_PULLDOWN) { + return 0; + } else if (pull =3D=3D NRF51_GPIO_PULLUP) { + return 1; + } + return -1; +} + static void update_output_irq(NRF51GPIOState *s, size_t i, bool connected, bool level) { @@ -61,43 +72,46 @@ static void update_output_irq(NRF51GPIOState *s, size_t= i, =20 static void update_state(NRF51GPIOState *s) { - uint32_t pull; + int pull; size_t i; - bool connected_out, dir, connected_in, out, input; + bool connected_out, dir, connected_in, out, in, input; =20 for (i =3D 0; i < NRF51_GPIO_PINS; i++) { - pull =3D extract32(s->cnf[i], 2, 2); + pull =3D pull_value(s->cnf[i]); dir =3D extract32(s->cnf[i], 0, 1); connected_in =3D extract32(s->in_mask, i, 1); out =3D extract32(s->out, i, 1); + in =3D extract32(s->in, i, 1); input =3D !extract32(s->cnf[i], 1, 1); connected_out =3D is_connected(s->cnf[i], out) && dir; =20 - update_output_irq(s, i, connected_out, out); - - /* Pin both driven externally and internally */ - if (connected_out && connected_in) { - qemu_log_mask(LOG_GUEST_ERROR, "GPIO pin %zu short circuited\n= ", i); - } - - /* - * Input buffer disconnected from internal/external drives, so - * pull-up/pull-down becomes relevant - */ - if (!input || (input && !connected_in && !connected_out)) { - if (pull =3D=3D NRF51_GPIO_PULLDOWN) { - s->in =3D deposit32(s->in, i, 1, 0); - } else if (pull =3D=3D NRF51_GPIO_PULLUP) { - s->in =3D deposit32(s->in, i, 1, 1); + if (!input) { + if (pull >=3D 0) { + /* Input buffer disconnected from external drives */ + s->in =3D deposit32(s->in, i, 1, pull); + } + } else { + if (connected_out && connected_in && out !=3D in) { + /* Pin both driven externally and internally */ + qemu_log_mask(LOG_GUEST_ERROR, "GPIO pin %zu short circuit= ed\n", i); + } + if (!connected_in) { + /* + * Floating input: the output stimulates IN if connected, + * otherwise pull-up/pull-down resistors put a value on bo= th + * IN and OUT. + */ + if (pull >=3D 0 && !connected_out) { + connected_out =3D true; + out =3D pull; + } + if (connected_out) { + s->in =3D deposit32(s->in, i, 1, out); + } } } - - /* Self stimulation through internal output driver */ - if (connected_out && !connected_in && input) { - s->in =3D deposit32(s->in, i, 1, out); - } + update_output_irq(s, i, connected_out, out); } - } =20 /* --=20 2.20.1