From nobody Fri Sep 2 01:44:05 2022 X-Original-To: dev-commits-src-all@mlmmj.nyi.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mlmmj.nyi.freebsd.org (Postfix) with ESMTP id 4MJggT3P0gz4bNQp; Fri, 2 Sep 2022 01:44:05 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org [IPv6:2610:1c1:1:606c::19:3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256 client-signature RSA-PSS (4096 bits) client-digest SHA256) (Client CN "mxrelay.nyi.freebsd.org", Issuer "R3" (verified OK)) by mx1.freebsd.org (Postfix) with ESMTPS id 4MJggT2rw2z4Ql4; Fri, 2 Sep 2022 01:44:05 +0000 (UTC) (envelope-from git@FreeBSD.org) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1662083045; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=8HiaVSB1yrWegH6iO09Lr3+lcP0HNiAR8+oTLjayKNk=; b=FMnPVFvfXDuOl0zJN//xwfdFvCn1dRNr7mrNcxuNVkAromKlfJJNeSjRnsITf31EgDLCbP JhpxTG8wk402SDTAW4WPNHWuyy3IqoMXiePkKYBgBEAF8XQqrSo1QWha5S4GQWp3NZ6FWg Nk1eVJWzVTQoXH+sNGi5zOqvejBTQxVLwEJDl+2RzIpU1C8FC8BDnR5tZku7z/Y7JDBQnm mp2UIbky45N7rfkt6GuqaSKj6AEBGqpw2FHS4bYn0f+tH4rL7o5VhWuqCUPLoFdcHdfBj1 Tz0prwBJBI0wla431xhuMUD1fvi6p8N96SZQibkBHGcLGc1xebdjjVh7fT8w2g== Received: from gitrepo.freebsd.org (gitrepo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:5]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (Client did not present a certificate) by mxrelay.nyi.freebsd.org (Postfix) with ESMTPS id 4MJggT1bRDzg0R; Fri, 2 Sep 2022 01:44:05 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from gitrepo.freebsd.org ([127.0.1.44]) by gitrepo.freebsd.org (8.16.1/8.16.1) with ESMTP id 2821i57R038087; Fri, 2 Sep 2022 01:44:05 GMT (envelope-from git@gitrepo.freebsd.org) Received: (from git@localhost) by gitrepo.freebsd.org (8.16.1/8.16.1/Submit) id 2821i5w2038086; Fri, 2 Sep 2022 01:44:05 GMT (envelope-from git) Date: Fri, 2 Sep 2022 01:44:05 GMT Message-Id: <202209020144.2821i5w2038086@gitrepo.freebsd.org> To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org From: "Bjoern A. Zeeb" Subject: git: 2486b446db82 - main - ds1307: add support for the EPSON RX-8035SA I2C RTC List-Id: Commit messages for all branches of the src repository List-Archive: https://lists.freebsd.org/archives/dev-commits-src-all List-Help: List-Post: List-Subscribe: List-Unsubscribe: Sender: owner-dev-commits-src-all@freebsd.org X-BeenThere: dev-commits-src-all@freebsd.org MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit X-Git-Committer: bz X-Git-Repository: src X-Git-Refname: refs/heads/main X-Git-Reftype: branch X-Git-Commit: 2486b446db8270a7d6dc7f3c6df0a88c4745b527 Auto-Submitted: auto-generated ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1662083045; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=8HiaVSB1yrWegH6iO09Lr3+lcP0HNiAR8+oTLjayKNk=; b=rH1bufi8VsuH1jXCJufOKC41l5sfWmSS+s3tD7vh2GwIcpvK7zmmq5jl36hyRk4XguStVq bYnM0cXUwHjeU2lBg52b3eqwx31oY1MqR5uZBYgZkJrVMdQ8BWnzJFmvt3Ur5VuT9l9Gy8 EY8RkW5MJnszuMJaWykdKowi4ZVxCQawdXJ6v/25hqC2wW8B8wKSMYhXHdMUMN5tWArVCe qJ5vZjPDkfxLS68bKmsygtHkt0GcWRsDKiGbVjHhj4zH+rD9sbs5CP8HoOkIshx09fnAS3 8OgV28e4IrNJdNS1DORVlQn9YJjLDeyWnXIGfLe5nGQMhW+3wbLmKE9QCwyRvg== ARC-Seal: i=1; s=dkim; d=freebsd.org; t=1662083045; a=rsa-sha256; cv=none; b=bzn7UmNykk6/DrWzadHpzVXAT7LOXIywFwAXuVg8P8WeN1Db487he8x3JPP9tL4HspXeRT 6R6tDIjk1r5wxeYS1pYlrbc4gzrmWLdHT63BlEmYd/RYujRmz/bnIYz3HqdKBG2q4oAyjv gh0uIm23O+IHf6A/UQ/XVITj4qFe8CPzykleIK7wQ8+nTV+FoPNzeqtGp3aeIKV4QWjkiX 1EoMU07ufnNncgkzOGyu+D70EW7Mvs3siR7y/JE5lJrNkmVrrJO3gNEtdl7C58Es+4tEIf lGue9LSehul3aAfgpJ78tFwtscth5y1DVxfsUDbLdN3mkU3aJ6ACeTVO0L1ptQ== ARC-Authentication-Results: i=1; mx1.freebsd.org; none X-ThisMailContainsUnwantedMimeParts: N The branch main has been updated by bz: URL: https://cgit.FreeBSD.org/src/commit/?id=2486b446db8270a7d6dc7f3c6df0a88c4745b527 commit 2486b446db8270a7d6dc7f3c6df0a88c4745b527 Author: Mathew McBride AuthorDate: 2022-07-23 00:29:16 +0000 Commit: Bjoern A. Zeeb CommitDate: 2022-09-02 00:51:42 +0000 ds1307: add support for the EPSON RX-8035SA I2C RTC The EPSON RX-8035SA I2C RTC has a similar time register layout to the ds1307 family, with some minor differences in bit positions, polarity and control registers. Further generalize ds1307 to make it easier to add more compatible chips and add support for the EPSON RX-8035SA. MFC after: 6 days Sponsored by: Traverse Technologies Differential Revision: https://reviews.freebsd.org/D35837 --- sys/dev/iicbus/ds1307.c | 264 +++++++++++++++++++++++++++++++++++---------- sys/dev/iicbus/ds1307reg.h | 6 ++ 2 files changed, 215 insertions(+), 55 deletions(-) diff --git a/sys/dev/iicbus/ds1307.c b/sys/dev/iicbus/ds1307.c index 2ba712400fe4..e14f10631fd5 100644 --- a/sys/dev/iicbus/ds1307.c +++ b/sys/dev/iicbus/ds1307.c @@ -1,5 +1,6 @@ /*- * Copyright (c) 2015 Luiz Otavio O Souza + * Copyright (c) 2022 Mathew McBride * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -54,23 +55,31 @@ __FBSDID("$FreeBSD$"); #include "clock_if.h" #include "iicbus_if.h" +enum { + TYPE_DS1307, + TYPE_MAXIM1307, + TYPE_MICROCHIP_MCP7491X, + TYPE_EPSON_RX8035, + TYPE_COUNT +}; + struct ds1307_softc { - device_t sc_dev; - struct intr_config_hook - enum_hook; - uint8_t sc_ctrl; - bool sc_mcp7941x; - bool sc_use_ampm; + device_t sc_dev; + struct intr_config_hook enum_hook; + uint32_t chiptype; + uint8_t sc_ctrl; + bool sc_use_ampm; }; static void ds1307_start(void *); #ifdef FDT static const struct ofw_compat_data ds1307_compat_data[] = { - {"dallas,ds1307", (uintptr_t)"Dallas DS1307 RTC"}, - {"maxim,ds1307", (uintptr_t)"Maxim DS1307 RTC"}, - {"microchip,mcp7941x", (uintptr_t)"Microchip MCP7941x RTC"}, - { NULL, 0 } + {"dallas,ds1307", TYPE_DS1307}, + {"maxim,ds1307", TYPE_MAXIM1307}, + {"microchip,mcp7941x", TYPE_MICROCHIP_MCP7491X}, + {"epson,rx8035", TYPE_EPSON_RX8035}, + { NULL, 0 } }; #endif @@ -96,7 +105,8 @@ ds1307_ctrl_read(struct ds1307_softc *sc) sc->sc_ctrl = 0; error = ds1307_read1(sc->sc_dev, DS1307_CONTROL, &sc->sc_ctrl); if (error) { - device_printf(sc->sc_dev, "cannot read from RTC.\n"); + device_printf(sc->sc_dev, "%s: cannot read from RTC: %d\n", + __func__, error); return (error); } @@ -112,7 +122,8 @@ ds1307_ctrl_write(struct ds1307_softc *sc) ctrl = sc->sc_ctrl & DS1307_CTRL_MASK; error = ds1307_write1(sc->sc_dev, DS1307_CONTROL, ctrl); if (error != 0) - device_printf(sc->sc_dev, "cannot write to RTC.\n"); + device_printf(sc->sc_dev, "%s: cannot write to RTC: %d\n", + __func__, error); return (error); } @@ -127,7 +138,7 @@ ds1307_sqwe_sysctl(SYSCTL_HANDLER_ARGS) error = ds1307_ctrl_read(sc); if (error != 0) return (error); - if (sc->sc_mcp7941x) + if (sc->chiptype == TYPE_MICROCHIP_MCP7491X) sqwe_bit = MCP7941X_CTRL_SQWE; else sqwe_bit = DS1307_CTRL_SQWE; @@ -216,11 +227,29 @@ ds1307_probe(device_t dev) return (ENXIO); compat = ofw_bus_search_compatible(dev, ds1307_compat_data); - if (compat->ocd_str != NULL) { - device_set_desc(dev, (const char *)compat->ocd_data); - return (BUS_PROBE_DEFAULT); + if (compat->ocd_str == NULL) + return (ENXIO); + + switch(compat->ocd_data) { + case TYPE_DS1307: + device_set_desc(dev, "Dallas DS1307"); + break; + case TYPE_MAXIM1307: + device_set_desc(dev, "Maxim DS1307"); + break; + case TYPE_MICROCHIP_MCP7491X: + device_set_desc(dev, "Microchip MCP7491X"); + break; + case TYPE_EPSON_RX8035: + device_set_desc(dev, "Epson RX-8035"); + break; + default: + device_set_desc(dev, "Unknown DS1307-like device"); + break; } + return (BUS_PROBE_DEFAULT); #endif + device_set_desc(dev, "Maxim DS1307 RTC"); return (BUS_PROBE_NOWILDCARD); } @@ -228,16 +257,23 @@ ds1307_probe(device_t dev) static int ds1307_attach(device_t dev) { +#ifdef FDT + const struct ofw_compat_data *compat; +#endif struct ds1307_softc *sc; sc = device_get_softc(dev); sc->sc_dev = dev; sc->enum_hook.ich_func = ds1307_start; sc->enum_hook.ich_arg = dev; - #ifdef FDT - if (ofw_bus_is_compatible(dev, "microchip,mcp7941x")) - sc->sc_mcp7941x = 1; + compat = ofw_bus_search_compatible(dev, ds1307_compat_data); + sc->chiptype = compat->ocd_data; + /* Unify the chiptypes to DS1307 where possible. */ + if (sc->chiptype == TYPE_MAXIM1307) + sc->chiptype = TYPE_DS1307; +#else + sc->chiptype = TYPE_DS1307; #endif /* @@ -258,6 +294,110 @@ ds1307_detach(device_t dev) return (0); } +static bool +is_epson_time_valid(struct ds1307_softc *sc) +{ + device_t dev; + int error; + uint8_t ctrl2; + + dev = sc->sc_dev; + + /* + * The RX-8035 single register read is non-standard + * Refer to section 8.9.5 of the RX-8035 application manual: + * "I2C bus basic transfer format", under "Standard Read Method". + * Basically, register to read goes into the top 4 bits. + */ + error = ds1307_read1(dev, (RX8035_CTRL_2 << 4), &ctrl2); + if (error) { + device_printf(dev, "%s cannot read Control 2 register: %d\n", + __func__, error); + return (false); + } + + if (ctrl2 & RX8035_CTRL_2_XSTP) { + device_printf(dev, "Oscillation stop detected (ctrl2=%#02x)\n", + ctrl2); + return (false); + } + + /* + * Power on reset (PON) generally implies oscillation stop, + * but catch it as well to be sure. + */ + if (ctrl2 & RX8035_CTRL_2_PON) { + device_printf(dev, "Power-on reset detected (ctrl2=%#02x)\n", + ctrl2); + return (false); + } + + return (true); +} + +static int +mark_epson_time_valid(struct ds1307_softc *sc) +{ + device_t dev; + int error; + uint8_t ctrl2; + uint8_t control_mask; + + dev = sc->sc_dev; + + error = ds1307_read1(dev, (RX8035_CTRL_2 << 4), &ctrl2); + if (error) { + device_printf(dev, "%s cannot read Control 2 register: %d\n", + __func__, error); + return (false); + } + + control_mask = (RX8035_CTRL_2_PON | RX8035_CTRL_2_XSTP | RX8035_CTRL_2_VDET); + ctrl2 = ctrl2 & ~(control_mask); + + error = ds1307_write1(dev, (RX8035_CTRL_2 << 4), ctrl2); + if (error) { + device_printf(dev, "%s cannot write to Control 2 register: %d\n", + __func__, error); + return (false); + } + return (true); +} + +static bool is_dev_time_valid(struct ds1307_softc *sc) +{ + device_t dev; + int error; + uint8_t osc_en; + uint8_t secs; + + /* Epson RTCs have different control/status registers. */ + if (sc->chiptype == TYPE_EPSON_RX8035) + return (is_epson_time_valid(sc)); + + dev = sc->sc_dev; + /* Check if the oscillator is disabled. */ + error = ds1307_read1(dev, DS1307_SECS, &secs); + if (error) { + device_printf(dev, "%s: cannot read from RTC: %d\n", + __func__, error); + return (false); + } + + switch (sc->chiptype) { + case TYPE_MICROCHIP_MCP7491X: + osc_en = 0x80; + break; + default: + osc_en = 0x00; + break; + } + if (((secs & DS1307_SECS_CH) ^ osc_en) != 0) + return (false); + + return (true); +} + static void ds1307_start(void *xdev) { @@ -266,33 +406,28 @@ ds1307_start(void *xdev) struct sysctl_ctx_list *ctx; struct sysctl_oid *tree_node; struct sysctl_oid_list *tree; - uint8_t secs; - uint8_t osc_en; dev = (device_t)xdev; sc = device_get_softc(dev); - ctx = device_get_sysctl_ctx(dev); - tree_node = device_get_sysctl_tree(dev); - tree = SYSCTL_CHILDREN(tree_node); config_intrhook_disestablish(&sc->enum_hook); - /* Check if the oscillator is disabled. */ - if (ds1307_read1(sc->sc_dev, DS1307_SECS, &secs) != 0) { - device_printf(sc->sc_dev, "cannot read from RTC.\n"); - return; - } - if (sc->sc_mcp7941x) - osc_en = 0x80; - else - osc_en = 0x00; - - if (((secs & DS1307_SECS_CH) ^ osc_en) != 0) { - device_printf(sc->sc_dev, + if (!is_dev_time_valid(sc)) + device_printf(dev, "WARNING: RTC clock stopped, check the battery.\n"); - } - /* Configuration parameters. */ + /* + * Configuration parameters: + * square wave output cannot be changed or inhibited on the RX-8035, + * so don't present the sysctls there. + */ + if (sc->chiptype == TYPE_EPSON_RX8035) + goto skip_sysctl; + + ctx = device_get_sysctl_ctx(dev); + tree_node = device_get_sysctl_tree(dev); + tree = SYSCTL_CHILDREN(tree_node); + SYSCTL_ADD_PROC(ctx, tree, OID_AUTO, "sqwe", CTLFLAG_RW | CTLTYPE_UINT | CTLFLAG_MPSAFE, sc, 0, ds1307_sqwe_sysctl, "IU", "DS1307 square-wave enable"); @@ -303,6 +438,7 @@ ds1307_start(void *xdev) SYSCTL_ADD_PROC(ctx, tree, OID_AUTO, "sqw_out", CTLFLAG_RW | CTLTYPE_UINT | CTLFLAG_MPSAFE, sc, 0, ds1307_sqw_out_sysctl, "IU", "DS1307 square-wave output state"); +skip_sysctl: /* * Register as a clock with 1 second resolution. Schedule the @@ -316,30 +452,36 @@ ds1307_start(void *xdev) static int ds1307_gettime(device_t dev, struct timespec *ts) { - int error; struct bcd_clocktime bct; struct ds1307_softc *sc; - uint8_t data[7], hourmask, st_mask; + int error; + uint8_t data[7], hourmask, ampm_mode; sc = device_get_softc(dev); error = iicdev_readfrom(sc->sc_dev, DS1307_SECS, data, sizeof(data), IIC_INTRWAIT); if (error != 0) { - device_printf(dev, "cannot read from RTC.\n"); + device_printf(dev, "%s: cannot read from RTC: %d\n", + __func__, error); return (error); } - /* If the clock halted, we don't have good data. */ - if (sc->sc_mcp7941x) - st_mask = 0x80; - else - st_mask = 0x00; - - if (((data[DS1307_SECS] & DS1307_SECS_CH) ^ st_mask) != 0) + if (!is_dev_time_valid(sc)) { + device_printf(dev, "Device time not valid.\n"); return (EINVAL); + } - /* If chip is in AM/PM mode remember that. */ - if (data[DS1307_HOUR] & DS1307_HOUR_USE_AMPM) { + /* + * If the chip is in AM/PM mode remember that. + * The EPSON uses a 1 to signify 24 hour mode, while the DS uses a 0, + * in slighly different positions. + */ + if (sc->chiptype == TYPE_EPSON_RX8035) + ampm_mode = !(data[DS1307_HOUR] & RX8035_HOUR_USE_24); + else + ampm_mode = data[DS1307_HOUR] & DS1307_HOUR_USE_AMPM; + + if (ampm_mode) { sc->sc_use_ampm = true; hourmask = DS1307_HOUR_MASK_12HR; } else @@ -377,12 +519,19 @@ ds1307_settime(device_t dev, struct timespec *ts) clock_ts_to_bcd(ts, &bct, sc->sc_use_ampm); clock_dbgprint_bcd(sc->sc_dev, CLOCK_DBG_WRITE, &bct); - /* If the chip is in AM/PM mode, adjust hour and set flags as needed. */ + /* + * If the chip is in AM/PM mode, adjust hour and set flags as needed. + * The AM/PM bit polarity and position is different on the EPSON. + */ if (sc->sc_use_ampm) { - pmflags = DS1307_HOUR_USE_AMPM; + pmflags = (sc->chiptype != TYPE_EPSON_RX8035) ? + DS1307_HOUR_USE_AMPM : 0; if (bct.ispm) pmflags |= DS1307_HOUR_IS_PM; - } else + + } else if (sc->chiptype == TYPE_EPSON_RX8035) + pmflags = RX8035_HOUR_USE_24; + else pmflags = 0; data[DS1307_SECS] = bct.sec; @@ -392,18 +541,23 @@ ds1307_settime(device_t dev, struct timespec *ts) data[DS1307_WEEKDAY] = bct.dow; data[DS1307_MONTH] = bct.mon; data[DS1307_YEAR] = bct.year & 0xff; - if (sc->sc_mcp7941x) { + if (sc->chiptype == TYPE_MICROCHIP_MCP7491X) { data[DS1307_SECS] |= MCP7941X_SECS_ST; data[DS1307_WEEKDAY] |= MCP7941X_WEEKDAY_VBATEN; year = bcd2bin(bct.year >> 8) * 100 + bcd2bin(bct.year & 0xff); if ((year % 4 == 0 && year % 100 != 0) || year % 400 == 0) data[DS1307_MONTH] |= MCP7941X_MONTH_LPYR; } + /* Write the time back to RTC. */ error = iicdev_writeto(sc->sc_dev, DS1307_SECS, data, sizeof(data), IIC_INTRWAIT); if (error != 0) - device_printf(dev, "cannot write to RTC.\n"); + device_printf(dev, "%s: cannot write to RTC: %d\n", + __func__, error); + + if (sc->chiptype == TYPE_EPSON_RX8035) + error = mark_epson_time_valid(sc); return (error); } diff --git a/sys/dev/iicbus/ds1307reg.h b/sys/dev/iicbus/ds1307reg.h index f2763a5e0cd3..e4f7979c97da 100644 --- a/sys/dev/iicbus/ds1307reg.h +++ b/sys/dev/iicbus/ds1307reg.h @@ -44,6 +44,7 @@ #define DS1307_HOUR_MASK_24HR 0x3f #define DS1307_HOUR_IS_PM 0x20 #define DS1307_HOUR_USE_AMPM 0x40 +#define RX8035_HOUR_USE_24 0x80 #define DS1307_WEEKDAY 0x03 #define MCP7941X_WEEKDAY_VBATEN 0x08 #define DS1307_WEEKDAY_MASK 0x07 @@ -63,4 +64,9 @@ #define DS1307_CTRL_RS_MASK (DS1307_CTRL_RS1 | DS1307_CTRL_RS0) #define DS1307_CTRL_MASK 0x93 +#define RX8035_CTRL_2 0x0F +#define RX8035_CTRL_2_PON (1 << 4) +#define RX8035_CTRL_2_XSTP (1 << 5) +#define RX8035_CTRL_2_VDET (1 << 6) + #endif /* _DS1307REG_H_ */