From patchwork Tue Sep 18 07:35:25 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Eugen Hristev X-Patchwork-Id: 146878 Delivered-To: patch@linaro.org Received: by 2002:a2e:1648:0:0:0:0:0 with SMTP id 8-v6csp4706475ljw; Tue, 18 Sep 2018 00:43:11 -0700 (PDT) X-Google-Smtp-Source: ANB0VdbuIAOqqA49MJuzZfRqwwflJoTeKPL0UJi5X+V4ufcMLiFFkWFkRgeaSkyKvbs+3d88zdU8 X-Received: by 2002:a50:908d:: with SMTP id c13-v6mr49635928eda.179.1537256591878; Tue, 18 Sep 2018 00:43:11 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1537256591; cv=none; d=google.com; s=arc-20160816; b=gSqX+3scm6L5KYO7rjZymPrZTTv3E/trADbfwY1zpejPG5eTwHDrIuOXGSKWBjahj/ KTwqGxHdCifX1ahqhcOZmlsThYfB3/W2ibvJwVhz5TdRcyWSWuXIfMNZANZd6elt/99X vY8+cIG39Vg4rqSFkx3u9txFz1ztaS+SYekGTupGXsYs2yHtaedoq11YfVgtgvh1KSf8 XLBU7ZbFPx7jraTlfocPr5iwHksZcmoT1IdJfUMbSHD9URcE8R2Bt/WUP8iPF2G5Auch 6pLouP7tQ1q+PiPKL3yiiWbrrWFCfGylE3XtajgWrt9EzcdeFRknom2AOTsDsp0t6Mdq ylyg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=sender:errors-to:content-transfer-encoding:list-subscribe:list-help :list-post:list-archive:list-unsubscribe:list-id:precedence:subject :cc:mime-version:references:in-reply-to:message-id:date:to:from; bh=9FxhycG3YLCwexShhc+gLz9TgQepWM/BNE49tF79RnI=; b=SgC0I4Kw2/EM98tRSJiwOg+S3x851IdfUwNRg2GqfikmXzZOF77xKdBlxyKa/JUNm3 e2CzMOwp7Aoputb9gjy/7jd8UEle7yMbqdbD/vU2KLr5un0LqdNw96TE75Iwk1TVrIoB jwYgIPeZIsIJoQPDGKfPSRcC7NIE0rkycm/zYLa5wQpaJFmoeYmvAb0Dk2XBu3NKYFO5 OJMQOdRv1QCYiuLCboceo6ybAwHTKVCg1+RpYIJzRry+VMljav/f/2kimVt/Vt9yVm7U M/Y+T5s6vLPdg1PC7M/LTC95mNeixg5dQr/hEQZZRSJyssRZCTGev2PfBQAL5U6VjkM1 amyA== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: best guess record for domain of u-boot-bounces@lists.denx.de designates 81.169.180.215 as permitted sender) smtp.mailfrom=u-boot-bounces@lists.denx.de Return-Path: Received: from lists.denx.de (dione.denx.de. [81.169.180.215]) by mx.google.com with ESMTP id k46-v6si342699edb.231.2018.09.18.00.43.09; Tue, 18 Sep 2018 00:43:11 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of u-boot-bounces@lists.denx.de designates 81.169.180.215 as permitted sender) client-ip=81.169.180.215; Authentication-Results: mx.google.com; spf=pass (google.com: best guess record for domain of u-boot-bounces@lists.denx.de designates 81.169.180.215 as permitted sender) smtp.mailfrom=u-boot-bounces@lists.denx.de Received: by lists.denx.de (Postfix, from userid 105) id 45CDDC21EC2; Tue, 18 Sep 2018 07:41:55 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on lists.denx.de X-Spam-Level: X-Spam-Status: No, score=0.0 required=5.0 tests=none autolearn=unavailable autolearn_force=no version=3.4.0 Received: from lists.denx.de (localhost [IPv6:::1]) by lists.denx.de (Postfix) with ESMTP id E945AC21E7D; Tue, 18 Sep 2018 07:40:34 +0000 (UTC) Received: by lists.denx.de (Postfix, from userid 105) id D0326C21E12; Tue, 18 Sep 2018 07:40:31 +0000 (UTC) Received: from esa2.microchip.iphmx.com (esa2.microchip.iphmx.com [68.232.149.84]) by lists.denx.de (Postfix) with ESMTPS id 0BAEDC21D65 for ; Tue, 18 Sep 2018 07:40:28 +0000 (UTC) X-IronPort-AV: E=Sophos;i="5.53,389,1531810800"; d="scan'208";a="20067712" Received: from smtpout.microchip.com (HELO email.microchip.com) ([198.175.253.82]) by esa2.microchip.iphmx.com with ESMTP/TLS/DHE-RSA-AES256-SHA; 18 Sep 2018 00:40:25 -0700 Received: from eh-station.mchp-main.com (10.10.76.4) by chn-sv-exch06.mchp-main.com (10.10.76.107) with Microsoft SMTP Server id 14.3.352.0; Tue, 18 Sep 2018 00:40:25 -0700 From: Eugen Hristev To: , Date: Tue, 18 Sep 2018 10:35:25 +0300 Message-ID: <1537256157-18001-3-git-send-email-eugen.hristev@microchip.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1537256157-18001-1-git-send-email-eugen.hristev@microchip.com> References: <1537256157-18001-1-git-send-email-eugen.hristev@microchip.com> MIME-Version: 1.0 Cc: maxime.ripard@bootlin.com, Maxime Ripard , nicolas.ferre@microchip.com Subject: [U-Boot] [PATCH v4 02/34] w1: Add 1-Wire gpio driver X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.18 Precedence: list List-Id: U-Boot discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: u-boot-bounces@lists.denx.de Sender: "U-Boot" From: Maxime Ripard Add a bus driver for bitbanging a 1-Wire bus over a GPIO. Signed-off-by: Maxime Ripard [eugen.hristev@microchip.com: fixed some issues] Signed-off-by: Eugen Hristev --- drivers/w1/Kconfig | 7 ++ drivers/w1/Makefile | 2 + drivers/w1/w1-gpio.c | 176 +++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 185 insertions(+) create mode 100644 drivers/w1/w1-gpio.c diff --git a/drivers/w1/Kconfig b/drivers/w1/Kconfig index 64b27c6..d6e0457 100644 --- a/drivers/w1/Kconfig +++ b/drivers/w1/Kconfig @@ -13,6 +13,13 @@ config W1 if W1 +config W1_GPIO + bool "Enable 1-wire GPIO bitbanging" + default no + depends on DM_GPIO + help + Emulate a 1-wire bus using a GPIO. + endif endmenu diff --git a/drivers/w1/Makefile b/drivers/w1/Makefile index f81693b..7fd8697 100644 --- a/drivers/w1/Makefile +++ b/drivers/w1/Makefile @@ -1 +1,3 @@ obj-$(CONFIG_W1) += w1-uclass.o + +obj-$(CONFIG_W1_GPIO) += w1-gpio.o diff --git a/drivers/w1/w1-gpio.c b/drivers/w1/w1-gpio.c new file mode 100644 index 0000000..5e5d6b3 --- /dev/null +++ b/drivers/w1/w1-gpio.c @@ -0,0 +1,176 @@ +/* SPDX-License-Identifier: GPL-2.0+ + * + * Copyright (c) 2015 Free Electrons + * Copyright (c) 2015 NextThing Co + * + * Maxime Ripard + * + */ + +#include +#include +#include + +#include + +#define W1_TIMING_A 6 +#define W1_TIMING_B 64 +#define W1_TIMING_C 60 +#define W1_TIMING_D 10 +#define W1_TIMING_E 9 +#define W1_TIMING_F 55 +#define W1_TIMING_G 0 +#define W1_TIMING_H 480 +#define W1_TIMING_I 70 +#define W1_TIMING_J 410 + +struct w1_gpio_pdata { + struct gpio_desc gpio; + u64 search_id; +}; + +static bool w1_gpio_read_bit(struct udevice *dev) +{ + struct w1_gpio_pdata *pdata = dev_get_platdata(dev); + int val; + + dm_gpio_set_dir_flags(&pdata->gpio, GPIOD_IS_OUT); + udelay(W1_TIMING_A); + + dm_gpio_set_dir_flags(&pdata->gpio, GPIOD_IS_IN); + udelay(W1_TIMING_E); + + val = dm_gpio_get_value(&pdata->gpio); + if (val < 0) + debug("error in retrieving GPIO value"); + udelay(W1_TIMING_F); + + return val; +} + +static u8 w1_gpio_read_byte(struct udevice *dev) +{ + int i; + u8 ret = 0; + + for (i = 0; i < 8; ++i) + ret |= (w1_gpio_read_bit(dev) ? 1 : 0) << i; + + return ret; +} + +static void w1_gpio_write_bit(struct udevice *dev, bool bit) +{ + struct w1_gpio_pdata *pdata = dev_get_platdata(dev); + + dm_gpio_set_dir_flags(&pdata->gpio, GPIOD_IS_OUT); + + bit ? udelay(W1_TIMING_A) : udelay(W1_TIMING_C); + + dm_gpio_set_value(&pdata->gpio, 1); + + bit ? udelay(W1_TIMING_B) : udelay(W1_TIMING_D); +} + +static void w1_gpio_write_byte(struct udevice *dev, u8 byte) +{ + int i; + + for (i = 0; i < 8; ++i) + w1_gpio_write_bit(dev, (byte >> i) & 0x1); +} + +static bool w1_gpio_reset(struct udevice *dev) +{ + struct w1_gpio_pdata *pdata = dev_get_platdata(dev); + int val; + + /* initiate the reset pulse. first we must pull the bus to low */ + dm_gpio_set_dir_flags(&pdata->gpio, GPIOD_IS_OUT | GPIOD_IS_OUT_ACTIVE); + udelay(W1_TIMING_G); + + dm_gpio_set_value(&pdata->gpio, 0); + /* wait for the specified time with the bus kept low */ + udelay(W1_TIMING_H); + + /* now we must read the presence pulse */ + dm_gpio_set_dir_flags(&pdata->gpio, GPIOD_IS_IN); + udelay(W1_TIMING_I); + + val = dm_gpio_get_value(&pdata->gpio); + if (val < 0) + debug("error in retrieving GPIO value"); + + /* if nobody pulled the bus down , it means nobody is on the bus */ + if (val != 0) + return 1; + /* we have the bus pulled down, let's wait for the specified presence time */ + udelay(W1_TIMING_J); + + /* read again, the other end should leave the bus free */ + val = dm_gpio_get_value(&pdata->gpio); + if (val < 0) + debug("error in retrieving GPIO value"); + + /* bus is not going up again, so we have an error */ + if (val != 1) + return 1; + + /* all good, presence detected */ + return 0; +} + +static u8 w1_gpio_triplet(struct udevice *dev, bool bdir) +{ + u8 id_bit = w1_gpio_read_bit(dev); + u8 comp_bit = w1_gpio_read_bit(dev); + u8 retval; + + if (id_bit && comp_bit) + return 0x03; /* error */ + + if (!id_bit && !comp_bit) { + /* Both bits are valid, take the direction given */ + retval = bdir ? 0x04 : 0; + } else { + /* Only one bit is valid, take that direction */ + bdir = id_bit; + retval = id_bit ? 0x05 : 0x02; + } + + w1_gpio_write_bit(dev, bdir); + return retval; +} + +static const struct w1_ops w1_gpio_ops = { + .read_byte = w1_gpio_read_byte, + .reset = w1_gpio_reset, + .triplet = w1_gpio_triplet, + .write_byte = w1_gpio_write_byte, +}; + +static int w1_gpio_ofdata_to_platdata(struct udevice *dev) +{ + struct w1_gpio_pdata *pdata = dev_get_platdata(dev); + int ret; + + ret = gpio_request_by_name(dev, "gpios", 0, &pdata->gpio, 0); + if (ret < 0) + printf("Error claiming GPIO %d\n", ret); + + return ret; +}; + +static const struct udevice_id w1_gpio_id[] = { + { "w1-gpio", 0 }, + { }, +}; + +U_BOOT_DRIVER(w1_gpio_drv) = { + .id = UCLASS_W1, + .name = "w1_gpio_drv", + .of_match = w1_gpio_id, + .ofdata_to_platdata = w1_gpio_ofdata_to_platdata, + .ops = &w1_gpio_ops, + .platdata_auto_alloc_size = sizeof(struct w1_gpio_pdata), +};