From patchwork Thu Jul 19 09:57:49 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Eugen Hristev X-Patchwork-Id: 142332 Delivered-To: patch@linaro.org Received: by 2002:a2e:9754:0:0:0:0:0 with SMTP id f20-v6csp1543206ljj; Thu, 19 Jul 2018 03:03:30 -0700 (PDT) X-Google-Smtp-Source: AAOMgpfIvGFt/Ft1/hMHAOFgAsCgE/wfw5EJd0soBf3qlocDraUzfBeLN+keoIBh5VBC96tjI7b2 X-Received: by 2002:a50:a93c:: with SMTP id l57-v6mr9966677edc.229.1531994610849; Thu, 19 Jul 2018 03:03:30 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1531994610; cv=none; d=google.com; s=arc-20160816; b=x5zLcY+xPC+WrMp3iRM3dyQzi7ArV5b4KiPAMfxPZDzN2b3ZLwx6tCCucLQoYbqJgc uKYr/SXgaNhK2H+71WSrCXKrH8doOM15vnYYc/kODzh8ze2kIKOuMQNhDnRy3SRwyXvQ 6cLfjSHtrZgzLsl8kZ6+NkAYvljjXI19RNx5NL3ZF2BDH+UrFFRURDlxFuT6H+OjULuV Wn8QsX801i/6ZJxZf/57L8bQsCRbVBePRQxoGjZpjOycDdldtC1Owi5j75kDnkTAGNWa P8yRLbkYWt7phSxygbcT4UjzJTtdd8dsKEy0vQ6xnKRwpTD6rFRgeg23MC6UnIiQ+p2J Fehg== 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 :arc-authentication-results; bh=fEE2p3+0RuZvHY1cKiI1BY5pfPvI4F7kIJkH/wq4qpM=; b=qPYgtn8RhYFZNSrZSQoWPgh3HQ7pqlYEtY8p9sgDo2vpJJuJtnDcfdRQF7AYdhWT7T TD+7Pf9+NNBtCYZN82CCNMF34rNa+XEazTcwaesq5oV+6L+H4gvnITLNqReMJpkQ4lBu kV17ngRzgrcIdog9lionTvp/yw9JI3WCMpcxJpqlKEPMwE87+2+5wW5QUIKMCEDjMFfe E2wnN8CAZarpKpmjA57tq+6N7Gkga+sL6UDGSz8XNy3G0jm408vJFvIs3P1qiyl23j8W hcbC2eUmugY8VVwqsb2/oljItnDfFXiu1QhDrLRnPYfXk8mRJR0s4EeVZ0fmwfAKG/SF Rg8A== 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 d4-v6si3656205edq.426.2018.07.19.03.03.30; Thu, 19 Jul 2018 03:03:30 -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 64285C21FD4; Thu, 19 Jul 2018 10:03:05 +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 E2D74C21E88; Thu, 19 Jul 2018 10:02:45 +0000 (UTC) Received: by lists.denx.de (Postfix, from userid 105) id 9F9DFC21E88; Thu, 19 Jul 2018 10:02:40 +0000 (UTC) Received: from esa4.microchip.iphmx.com (esa4.microchip.iphmx.com [68.232.154.123]) by lists.denx.de (Postfix) with ESMTPS id 7FACCC21C27 for ; Thu, 19 Jul 2018 10:02:37 +0000 (UTC) X-IronPort-AV: E=Sophos;i="5.51,374,1526367600"; d="scan'208";a="16185309" Received: from smtpout.microchip.com (HELO email.microchip.com) ([198.175.253.82]) by esa4.microchip.iphmx.com with ESMTP/TLS/DHE-RSA-AES256-SHA; 19 Jul 2018 03:02:35 -0700 Received: from eh-station.mchp-main.com (10.10.76.4) by chn-sv-exch07.mchp-main.com (10.10.76.108) with Microsoft SMTP Server id 14.3.352.0; Thu, 19 Jul 2018 03:02:34 -0700 From: Eugen Hristev To: Date: Thu, 19 Jul 2018 12:57:49 +0300 Message-ID: <1531994288-19423-2-git-send-email-eugen.hristev@microchip.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1531994288-19423-1-git-send-email-eugen.hristev@microchip.com> References: <1531994288-19423-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 01/20] w1: Add 1-Wire uclass 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 We might want to use 1-Wire devices connected on boards such as EEPROMs in U-Boot. Provide a framework to be able to do that. Signed-off-by: Maxime Ripard [eugen.hristev@microchip.com: fixed small issues and rebased] Signed-off-by: Eugen Hristev --- drivers/Kconfig | 2 + drivers/Makefile | 1 + drivers/w1/Kconfig | 18 ++++ drivers/w1/Makefile | 1 + drivers/w1/w1-uclass.c | 268 +++++++++++++++++++++++++++++++++++++++++++++++++ include/dm/uclass-id.h | 1 + include/w1.h | 48 +++++++++ 7 files changed, 339 insertions(+) create mode 040000 drivers/w1 create mode 100644 drivers/w1/Kconfig create mode 100644 drivers/w1/Makefile create mode 100644 drivers/w1/w1-uclass.c create mode 100644 include/w1.h diff --git a/drivers/Kconfig b/drivers/Kconfig index 9e21b28..2cae829 100644 --- a/drivers/Kconfig +++ b/drivers/Kconfig @@ -102,6 +102,8 @@ source "drivers/usb/Kconfig" source "drivers/video/Kconfig" +source "drivers/w1/Kconfig" + source "drivers/watchdog/Kconfig" config PHYS_TO_BUS diff --git a/drivers/Makefile b/drivers/Makefile index a213ea9..728380b 100644 --- a/drivers/Makefile +++ b/drivers/Makefile @@ -101,6 +101,7 @@ obj-y += input/ obj-y += soc/ obj-$(CONFIG_REMOTEPROC) += remoteproc/ obj-y += thermal/ +obj-$(CONFIG_W1) += w1/ obj-$(CONFIG_MACH_PIC32) += ddr/microchip/ endif diff --git a/drivers/w1/Kconfig b/drivers/w1/Kconfig new file mode 100644 index 0000000..64b27c6 --- /dev/null +++ b/drivers/w1/Kconfig @@ -0,0 +1,18 @@ +# +# W1 subsystem configuration +# + +menu "1-Wire support" + +config W1 + bool "Enable 1-wire controllers support" + default no + depends on DM + help + Support for the Dallas 1-Wire bus. + +if W1 + +endif + +endmenu diff --git a/drivers/w1/Makefile b/drivers/w1/Makefile new file mode 100644 index 0000000..f81693b --- /dev/null +++ b/drivers/w1/Makefile @@ -0,0 +1 @@ +obj-$(CONFIG_W1) += w1-uclass.o diff --git a/drivers/w1/w1-uclass.c b/drivers/w1/w1-uclass.c new file mode 100644 index 0000000..cfddda3 --- /dev/null +++ b/drivers/w1/w1-uclass.c @@ -0,0 +1,268 @@ +/* SPDX-License-Identifier: GPL-2.0+ + * + * Copyright (c) 2015 Free Electrons + * Copyright (c) 2015 NextThing Co. + * + * Maxime Ripard + * + */ + +#include +#include +#include + +#include + +#define W1_MATCH_ROM 0x55 +#define W1_SKIP_ROM 0xcc +#define W1_SEARCH 0xf0 + +int w1_init(void); + +struct w1_bus { + u64 search_id; +}; + +struct w1_device { + u64 id; +}; + +static int w1_new_device(struct udevice *bus, u64 id) +{ + struct w1_driver_entry *start, *entry; + int n_ents, ret = -ENODEV; + u8 family = id & 0xff; + + debug("%s: Detected new device 0x%llx (family 0x%x)\n", + bus->name, id, family); + + start = ll_entry_start(struct w1_driver_entry, w1_driver_entry); + n_ents = ll_entry_count(struct w1_driver_entry, w1_driver_entry); + + for (entry = start; entry != start + n_ents; entry++) { + const struct driver *drv; + struct w1_device *w1; + struct udevice *dev; + + if (entry->family != family) + continue; + + drv = entry->driver; + ret = device_bind(bus, drv, drv->name, NULL, -1, + &dev); + if (ret) + goto error; + + debug("%s: Match found: %s\n", __func__, drv->name); + + w1 = dev_get_parent_platdata(dev); + w1->id = id; + + return 0; + } + +error: + debug("%s: No matches found: error %d\n", __func__, ret); + return ret; +} + +static int w1_enumerate(struct udevice *bus) +{ + const struct w1_ops *ops = device_get_ops(bus); + struct w1_bus *w1 = dev_get_uclass_priv(bus); + u64 last_rn, rn = w1->search_id, tmp64; + bool last_device = false; + int search_bit, desc_bit = 64; + int last_zero = -1; + u8 triplet_ret = 0; + int i; + + if (!ops->reset || !ops->write_byte || !ops->triplet) + return -ENOSYS; + + while (!last_device) { + last_rn = rn; + rn = 0; + + /* + * Reset bus and all 1-wire device state machines + * so they can respond to our requests. + * + * Return 0 - device(s) present, 1 - no devices present. + */ + if (ops->reset(bus)) { + debug("%s: No devices present on the wire.\n", + __func__); + break; + } + + /* Start the search */ + ops->write_byte(bus, W1_SEARCH); + for (i = 0; i < 64; ++i) { + /* Determine the direction/search bit */ + if (i == desc_bit) + /* took the 0 path last time, so take the 1 path */ + search_bit = 1; + else if (i > desc_bit) + /* take the 0 path on the next branch */ + search_bit = 0; + else + search_bit = ((last_rn >> i) & 0x1); + + /* Read two bits and write one bit */ + triplet_ret = ops->triplet(bus, search_bit); + + /* quit if no device responded */ + if ((triplet_ret & 0x03) == 0x03) + break; + + /* If both directions were valid, and we took the 0 path... */ + if (triplet_ret == 0) + last_zero = i; + + /* extract the direction taken & update the device number */ + tmp64 = (triplet_ret >> 2); + rn |= (tmp64 << i); + } + + /* last device or error, aborting here */ + if ((triplet_ret & 0x03) == 0x03) + last_device = true; + + if ((triplet_ret & 0x03) != 0x03) { + if (desc_bit == last_zero || last_zero < 0) { + last_device = 1; + w1->search_id = 0; + } else { + w1->search_id = rn; + } + desc_bit = last_zero; + + w1_new_device(bus, rn); + } + } + + return 0; +} + +int w1_get_bus(int busnum, struct udevice **busp) +{ + int ret; + + w1_init(); + + ret = uclass_get_device_by_seq(UCLASS_W1, busnum, busp); + if (ret) { + debug("Cannot find w1 bus %d\n", busnum); + return ret; + } + + return 0; +} + +u8 w1_get_device_family(struct udevice *dev) +{ + struct w1_device *w1 = dev_get_parent_platdata(dev); + + return w1->id & 0xff; +} + +int w1_reset_select(struct udevice *dev) +{ + struct w1_device *w1 = dev_get_parent_platdata(dev); + struct udevice *bus = dev_get_parent(dev); + const struct w1_ops *ops = device_get_ops(bus); + int i; + + if (!ops->reset || !ops->write_byte) + return -ENOSYS; + + ops->reset(bus); + + ops->write_byte(bus, W1_MATCH_ROM); + + for (i = 0; i < sizeof(w1->id); i++) + ops->write_byte(bus, (w1->id >> (i * 8)) & 0xff); + + return 0; +} + +int w1_read_byte(struct udevice *dev) +{ + struct udevice *bus = dev_get_parent(dev); + const struct w1_ops *ops = device_get_ops(bus); + + if (!ops->read_byte) + return -ENOSYS; + + return ops->read_byte(bus); +} + +int w1_read_buf(struct udevice *dev, u8 *buf, unsigned int count) +{ + int i, ret; + + for (i = 0; i < count; i++) { + ret = w1_read_byte(dev); + if (ret < 0) + return ret; + + buf[i] = ret & 0xff; + } + + return 0; +} + +int w1_write_byte(struct udevice *dev, u8 byte) +{ + struct udevice *bus = dev_get_parent(dev); + const struct w1_ops *ops = device_get_ops(bus); + + if (!ops->write_byte) + return -ENOSYS; + + ops->write_byte(bus, byte); + + return 0; +} + +static int w1_post_probe(struct udevice *bus) +{ + w1_enumerate(bus); + + return 0; +} + +int w1_init(void) +{ + struct udevice *bus; + struct uclass *uc; + int ret; + + ret = uclass_get(UCLASS_W1, &uc); + if (ret) + return ret; + + uclass_foreach_dev(bus, uc) { + ret = device_probe(bus); + if (ret == -ENODEV) { /* No such device. */ + printf("W1 controller not available.\n"); + continue; + } + + if (ret) { /* Other error. */ + printf("W1 controller probe failed, error %d\n", ret); + continue; + } + } + return 0; +} + +UCLASS_DRIVER(w1) = { + .name = "w1", + .id = UCLASS_W1, + .flags = DM_UC_FLAG_SEQ_ALIAS, + .per_device_auto_alloc_size = sizeof(struct w1_bus), + .per_child_platdata_auto_alloc_size = sizeof(struct w1_device), + .post_probe = w1_post_probe, +}; diff --git a/include/dm/uclass-id.h b/include/dm/uclass-id.h index d7f9df3..8eca9dc 100644 --- a/include/dm/uclass-id.h +++ b/include/dm/uclass-id.h @@ -89,6 +89,7 @@ enum uclass_id { UCLASS_VIDEO, /* Video or LCD device */ UCLASS_VIDEO_BRIDGE, /* Video bridge, e.g. DisplayPort to LVDS */ UCLASS_VIDEO_CONSOLE, /* Text console driver for video device */ + UCLASS_W1, /* Dallas 1-Wire bus */ UCLASS_WDT, /* Watchdot Timer driver */ UCLASS_COUNT, diff --git a/include/w1.h b/include/w1.h new file mode 100644 index 0000000..1ca1740 --- /dev/null +++ b/include/w1.h @@ -0,0 +1,48 @@ +/* SPDX-License-Identifier: GPL-2.0+ + * + * Copyright (c) 2015 Free Electrons + * Copyright (c) 2015 NextThing Co + * + */ + +#ifndef __W1_H +#define __W1_H + +#include + +#define W1_FAMILY_DS24B33 0x23 +#define W1_FAMILY_DS2431 0x2d + +/** + * struct w1_driver_entry - Matches a driver to its w1 family + * @driver: Driver to use + * @family: W1 family handled by this driver + */ +struct w1_driver_entry { + struct driver *driver; + u8 family; +}; + +#define U_BOOT_W1_DEVICE(__name, __family) \ + ll_entry_declare(struct w1_driver_entry, __name, w1_driver_entry) = { \ + .driver = llsym(struct driver, __name, driver), \ + .family = __family, \ + } + +struct w1_ops { + u8 (*read_byte)(struct udevice *dev); + bool (*reset)(struct udevice *dev); + u8 (*triplet)(struct udevice *dev, bool bdir); + void (*write_byte)(struct udevice *dev, u8 byte); +}; + +int w1_get_bus(int busnum, struct udevice **busp); +u8 w1_get_device_family(struct udevice *dev); + +int w1_read_buf(struct udevice *dev, u8 *buf, unsigned int count); +int w1_read_byte(struct udevice *dev); +int w1_reset_select(struct udevice *dev); +int w1_write_buf(struct udevice *dev, u8 *buf, unsigned int count); +int w1_write_byte(struct udevice *dev, u8 byte); + +#endif