From patchwork Tue Nov 12 08:39:38 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Nandor Han X-Patchwork-Id: 1193369 X-Patchwork-Delegate: trini@ti.com Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=none (no SPF record) smtp.mailfrom=lists.denx.de (client-ip=81.169.180.215; helo=lists.denx.de; envelope-from=u-boot-bounces@lists.denx.de; receiver=) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=vaisala.com Authentication-Results: ozlabs.org; dkim=fail reason="signature verification failed" (1024-bit key; unprotected) header.d=vaisala.com header.i=@vaisala.com header.b="cN9TDkOw"; dkim-atps=neutral Received: from lists.denx.de (dione.denx.de [81.169.180.215]) by ozlabs.org (Postfix) with ESMTP id 47C1QB0fblz9sP4 for ; Tue, 12 Nov 2019 19:39:46 +1100 (AEDT) Received: by lists.denx.de (Postfix, from userid 105) id C2A1EC21E62; Tue, 12 Nov 2019 08:39:44 +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=RCVD_IN_MSPIKE_H2, SPF_HELO_PASS, T_DKIM_INVALID 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 61E45C21C8B; Tue, 12 Nov 2019 08:39:41 +0000 (UTC) Received: by lists.denx.de (Postfix, from userid 105) id 4B8DEC21C8B; Tue, 12 Nov 2019 08:39:40 +0000 (UTC) Received: from EUR02-HE1-obe.outbound.protection.outlook.com (mail-eopbgr10086.outbound.protection.outlook.com [40.107.1.86]) by lists.denx.de (Postfix) with ESMTPS id 7A7CCC21C2C for ; Tue, 12 Nov 2019 08:39:39 +0000 (UTC) ARC-Seal: i=1; a=rsa-sha256; s=arcselector9901; d=microsoft.com; cv=none; b=XSY11e9NmJG26JP/br6KtQQGqTPY4cFX5f/Hl1+wwfTYJ/ze00kfELNF/b0ZAMKavl08twnfdwuVjZTRswLT9CC8StsgZs7Yxsmx2O4gEnl/v0jC7jHMfH5dLm2FxBka80jtE05XhOmw8BYP+JKM7+lC8YEZTu7DqcNddwAy/RNR65/CJTDdqwzatJRGiuiYSS2/rtOYagGeEFuhJ+C19MPsoLxFbOSzjEMYITXNIn9mU0Bm0g1COKveuONbe6viGQSAcsGXNAEKgX+Ai303oJT4W+7hGn7QLlo4lGZvJ9Sxd38dRSgbVUsrlolEAWN7L6Xp4KngMQI2HkxCECvrsQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector9901; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=GcNNPPHEXwDH3qFCRLO91TbvQKEo78lnZDjkfP2Nbxw=; b=Py7C3AH8s5nAD7b1mVjnIUKGhm38QEi8z0BA1VpkdUzzOLRgAWdtxz5e5ym5wv0k0H8P0BUGRaImvBsum7kRBPUexWGKy+YulIS9I7cs74LCnmjwQwvl/zi+orr5obiP3po6sodCQ1YZVDwdE7q3y9eXQuuTHz+38/LckQMUigMtFp4H1OHPF3xkuR+qI4KRFE9tT7StiAFRMoTbxFsr9Ijqq0jU75giky0oQxxvRH0D1wubv5nPxp0KADdchzM8AX1yg/nTLt7THMd7Ahm4tCpi5tH8AyOSTcPwlkGnDXMasdS3EKEfa7xsTh8n1HpHzt5s7Jbr3zO/9CfiFqaVhA== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass smtp.mailfrom=vaisala.com; dmarc=pass action=none header.from=vaisala.com; dkim=pass header.d=vaisala.com; arc=none DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=vaisala.com; s=selector2; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=GcNNPPHEXwDH3qFCRLO91TbvQKEo78lnZDjkfP2Nbxw=; b=cN9TDkOwF38t6xRoWdBKepT0MuRuIoDYTTzptiRr4O6lKrMdafFs8MgciWmgpWVi9hT9/lrXKu6lNhUe/u2wIL2lH1rD3nFnuNCFImjvR0lazSn25Mmh236w5s6qxf3djCkpaKcNjCysJp0bjv1QzTQPBgAZkxJA9WBrNXfB35Y= Received: from AM6PR06MB6263.eurprd06.prod.outlook.com (20.179.247.144) by AM6PR06MB6102.eurprd06.prod.outlook.com (10.255.168.83) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.2430.20; Tue, 12 Nov 2019 08:39:38 +0000 Received: from AM6PR06MB6263.eurprd06.prod.outlook.com ([fe80::b027:3f98:12c7:613a]) by AM6PR06MB6263.eurprd06.prod.outlook.com ([fe80::b027:3f98:12c7:613a%2]) with mapi id 15.20.2430.027; Tue, 12 Nov 2019 08:39:38 +0000 From: Han Nandor To: "u-boot@lists.denx.de" Thread-Topic: [PATCH] rtc: add support for DS3232 device Thread-Index: AQHVmTS3eq9vxIQkxkiEr6/ADHgKuA== Date: Tue, 12 Nov 2019 08:39:38 +0000 Message-ID: <20191112083922.22683-1-nandor.han@vaisala.com> Accept-Language: en-US Content-Language: en-US X-MS-Has-Attach: X-MS-TNEF-Correlator: x-clientproxiedby: PR0P264CA0132.FRAP264.PROD.OUTLOOK.COM (2603:10a6:100:1a::24) To AM6PR06MB6263.eurprd06.prod.outlook.com (2603:10a6:20b:ff::16) authentication-results: spf=none (sender IP is ) smtp.mailfrom=nandor.han@vaisala.com; x-ms-exchange-messagesentrepresentingtype: 1 x-mailer: git-send-email 2.20.1 x-originating-ip: [193.143.230.131] x-ms-publictraffictype: Email x-ms-office365-filtering-correlation-id: 3adf805c-15a9-4866-b811-08d7674bda58 x-ms-traffictypediagnostic: AM6PR06MB6102: x-ms-exchange-purlcount: 1 x-ms-exchange-transport-forked: True x-microsoft-antispam-prvs: x-tenant-id: 6d7393e0-41f5-4c2e-9b12-4c2be5da5c57 x-ms-oob-tlc-oobclassifiers: OLM:4502; x-forefront-prvs: 021975AE46 x-forefront-antispam-report: SFV:NSPM; SFS:(10009020)(366004)(346002)(376002)(396003)(39850400004)(136003)(189003)(199004)(305945005)(5660300002)(6306002)(2906002)(256004)(86362001)(50226002)(14444005)(7736002)(81156014)(81166006)(36756003)(66066001)(8676002)(8936002)(4326008)(2501003)(6916009)(107886003)(71200400001)(71190400001)(99286004)(6512007)(2351001)(478600001)(3846002)(6116002)(64756008)(476003)(26005)(2616005)(486006)(102836004)(6436002)(6486002)(386003)(25786009)(316002)(6506007)(186003)(14454004)(52116002)(1076003)(66946007)(66476007)(5640700003)(66556008)(66446008); DIR:OUT; SFP:1101; SCL:1; SRVR:AM6PR06MB6102; H:AM6PR06MB6263.eurprd06.prod.outlook.com; FPR:; SPF:None; LANG:en; PTR:InfoNoRecords; MX:1; A:1; received-spf: None (protection.outlook.com: vaisala.com does not designate permitted sender hosts) x-ms-exchange-senderadcheck: 1 x-microsoft-antispam: BCL:0; x-microsoft-antispam-message-info: XdbAbHGDnr7mk9RIWZiRJc8fqCBgx8N1vPlxQ9nYPRMgiNSd6BSXit66BKgEg1CyZQdVcqkYLbc0ps/bwdd+GTwxGoHl5xwsPUscqpKCsaPYonpfWWM0I98FfaBjE3dFMplAh0TVAO18O495H8DHn4aQZ7XasNgjJr7bLZZXk900VprnfG8DSig8wWGL8BTmarYxz4vZGlb1tSWVvXs7gwSciYkLcqIKj6okgZ4tBgaWPnPPCqDBogBO4K2p9ebYS81RoyySYI88A8AbVObl1OmsQRNCCh4fTTWpCtrKy0LlC4/pSaM+tho69N7aBKvLq8R7WUSBDsUi65LkS1bhBYnUgfyCYGWvnmQPggXSWpnLzfOeRH+6+az/pa0XF2MdqQFbc0ISRwdCTf0NroUFSPzMfD787w0G91Zm5LUWU12+PYQmDnnGJ3Qlt8TBZcIFmJH4XCPYVzeDrxzzjyEk+NuDLqkqn7acPCvaPP7svh4= MIME-Version: 1.0 X-OriginatorOrg: vaisala.com X-MS-Exchange-CrossTenant-Network-Message-Id: 3adf805c-15a9-4866-b811-08d7674bda58 X-MS-Exchange-CrossTenant-originalarrivaltime: 12 Nov 2019 08:39:38.1409 (UTC) X-MS-Exchange-CrossTenant-fromentityheader: Hosted X-MS-Exchange-CrossTenant-id: 6d7393e0-41f5-4c2e-9b12-4c2be5da5c57 X-MS-Exchange-CrossTenant-mailboxtype: HOSTED X-MS-Exchange-CrossTenant-userprincipalname: YvhxROPRVipt72DEGPemY1OdbzH4jbEQ1TvVnh3vUvj96l1cR29wWCLF5GeK1gQ7nnn6r7pwJojq/IiDckQ8XQ== X-MS-Exchange-Transport-CrossTenantHeadersStamped: AM6PR06MB6102 Subject: [U-Boot] [PATCH] rtc: add support for DS3232 device 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" DS3232 is an i2c RTC with 236 bytes of battery-backed SRAM. Add an RTC driver for DS3232 device, which provides time and date support. Also read and write functions are provided, which can be used to access the SRAM memory. Signed-off-by: Nandor Han --- Notes: Description ---------- Add support for RTC DS3232 device. Testing ------ 1. Check that date/time can be reset: PASS U-Boot> date reset Reset RTC... Date: 2000-01-01 (Saturday) Time: 0:00:00 2. Check that setting the date/time is successful: PASS U-Boot> date 040114012019.00 Date: 2019-04-01 (Monday) Time: 14:01:00 3. Check that getting the date/time is successful: PASS U-Boot> date Date: 2019-04-01 (Monday) Time: 14:01:58 4. Verify that the date configured in U-Boot is the same read in Kernel. doc/device-tree-bindings/rtc/ds3232.txt | 15 ++ drivers/rtc/Kconfig | 8 + drivers/rtc/Makefile | 1 + drivers/rtc/ds3232.c | 274 ++++++++++++++++++++++++ 4 files changed, 298 insertions(+) create mode 100644 doc/device-tree-bindings/rtc/ds3232.txt create mode 100644 drivers/rtc/ds3232.c diff --git a/doc/device-tree-bindings/rtc/ds3232.txt b/doc/device-tree-bindings/rtc/ds3232.txt new file mode 100644 index 0000000000..254b7bc3c3 --- /dev/null +++ b/doc/device-tree-bindings/rtc/ds3232.txt @@ -0,0 +1,15 @@ +DS3232 Real-Time Clock with SRAM + +The RTC driver provides time and date functionality. Also read and write +functions are provided that can be used to access the SRAM memory. + +Required properties: +- compatible : should contain "dallas,ds3232" +- reg : the I2C RTC address + +Example: + +rtc@68 { + compatible = "dallas,ds3232"; + reg = <0x68>; +}; diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index 8778cc7b26..a82f79bf16 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig @@ -54,6 +54,14 @@ config RTC_DS1307 Support for Dallas Semiconductor (now Maxim) DS1307 and DS1338/9 and compatible Real Time Clock devices. +config RTC_DS3232 + bool "Enable DS3232 driver" + depends on DM_RTC + depends on DM_I2C + help + Support for Dallas Semiconductor (now Maxim) DS3232 compatible + Real Time Clock devices. + config RTC_ISL1208 bool "Enable ISL1208 driver" depends on DM_RTC diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile index f97a669982..e89de73b11 100644 --- a/drivers/rtc/Makefile +++ b/drivers/rtc/Makefile @@ -22,6 +22,7 @@ obj-$(CONFIG_RTC_DS1556) += ds1556.o obj-$(CONFIG_RTC_DS164x) += ds164x.o obj-$(CONFIG_RTC_DS174x) += ds174x.o obj-$(CONFIG_RTC_DS3231) += ds3231.o +obj-$(CONFIG_RTC_DS3232) += ds3232.o obj-$(CONFIG_RTC_FTRTC010) += ftrtc010.o obj-$(CONFIG_SANDBOX) += i2c_rtc_emul.o obj-$(CONFIG_RTC_IMXDI) += imxdi.o diff --git a/drivers/rtc/ds3232.c b/drivers/rtc/ds3232.c new file mode 100644 index 0000000000..09a106aa4e --- /dev/null +++ b/drivers/rtc/ds3232.c @@ -0,0 +1,274 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * (C) Copyright 2019, Vaisala Oyj + */ + +#include +#include +#include +#include +#include + +/* + * RTC register addresses + */ +#define RTC_SEC_REG_ADDR 0x00 +#define RTC_MIN_REG_ADDR 0x01 +#define RTC_HR_REG_ADDR 0x02 +#define RTC_DAY_REG_ADDR 0x03 +#define RTC_DATE_REG_ADDR 0x04 +#define RTC_MON_REG_ADDR 0x05 +#define RTC_YR_REG_ADDR 0x06 +#define RTC_CTL_REG_ADDR 0x0e +#define RTC_STAT_REG_ADDR 0x0f +#define RTC_TEST_REG_ADDR 0x13 + +/* + * RTC control register bits + */ +#define RTC_CTL_BIT_A1IE BIT(0) /* Alarm 1 interrupt enable */ +#define RTC_CTL_BIT_A2IE BIT(1) /* Alarm 2 interrupt enable */ +#define RTC_CTL_BIT_INTCN BIT(2) /* Interrupt control */ +#define RTC_CTL_BIT_DOSC BIT(7) /* Disable Oscillator */ + +/* + * RTC status register bits + */ +#define RTC_STAT_BIT_A1F BIT(0) /* Alarm 1 flag */ +#define RTC_STAT_BIT_A2F BIT(1) /* Alarm 2 flag */ +#define RTC_STAT_BIT_EN32KHZ BIT(3) /* Enable 32KHz Output */ +#define RTC_STAT_BIT_BB32KHZ BIT(6) /* Battery backed 32KHz Output */ +#define RTC_STAT_BIT_OSF BIT(7) /* Oscillator stop flag */ + +/* + * RTC test register bits + */ +#define RTC_TEST_BIT_SWRST BIT(7) /* Software reset */ + +#define RTC_DATE_TIME_REG_SIZE 7 +#define RTC_SRAM_START 0x14 +#define RTC_SRAM_END 0xFF +#define RTC_SRAM_SIZE 236 + +struct ds3232_priv_data { + u8 max_register; + u8 sram_start; + int sram_size; +}; + +static int ds3232_rtc_read8(struct udevice *dev, unsigned int reg) +{ + int ret; + u8 buf; + struct ds3232_priv_data *priv_data; + + priv_data = dev_get_priv(dev); + if (!priv_data) + return -EINVAL; + + if (reg > priv_data->max_register) + return -EINVAL; + + ret = dm_i2c_read(dev, reg, &buf, sizeof(buf)); + if (ret < 0) + return ret; + + return buf; +} + +static int ds3232_rtc_write8(struct udevice *dev, unsigned int reg, int val) +{ + u8 buf = (u8)val; + struct ds3232_priv_data *priv_data; + + priv_data = dev_get_priv(dev); + if (!priv_data) + return -EINVAL; + + if (reg > priv_data->max_register) + return -EINVAL; + + return dm_i2c_write(dev, reg, &buf, sizeof(buf)); +} + +static int reset_sram(struct udevice *dev) +{ + int ret, sram_end, reg; + struct ds3232_priv_data *priv_data; + + priv_data = dev_get_priv(dev); + if (!priv_data) + return -EINVAL; + + sram_end = priv_data->sram_start + priv_data->sram_size; + + for (reg = priv_data->sram_start; reg < sram_end; reg++) { + ret = ds3232_rtc_write8(dev, reg, 0x00); + if (ret < 0) + return ret; + } + + return 0; +} + +static int verify_osc(struct udevice *dev) +{ + int ret, rtc_status; + + ret = ds3232_rtc_read8(dev, RTC_STAT_REG_ADDR); + if (ret < 0) + return ret; + + rtc_status = ret; + + if (rtc_status & RTC_STAT_BIT_OSF) { + dev_warn(dev, + "oscillator discontinuity flagged, time unreliable\n"); + /* + * In case OSC was off we cannot trust the SRAM data anymore. + * Reset it to 0x00. + */ + ret = reset_sram(dev); + if (ret < 0) + return ret; + } + + return 0; +} + +static int ds3232_rtc_set(struct udevice *dev, const struct rtc_time *tm) +{ + u8 buf[RTC_DATE_TIME_REG_SIZE]; + u8 is_century; + + if (tm->tm_year < 1900 || tm->tm_year > 2099) + dev_warn(dev, "WARNING: year should be between 1900 and 2099!\n"); + + is_century = (tm->tm_year >= 2000) ? 0x80 : 0; + + buf[RTC_SEC_REG_ADDR] = bin2bcd(tm->tm_sec); + buf[RTC_MIN_REG_ADDR] = bin2bcd(tm->tm_min); + buf[RTC_HR_REG_ADDR] = bin2bcd(tm->tm_hour); + buf[RTC_DAY_REG_ADDR] = bin2bcd(tm->tm_wday + 1); + buf[RTC_DATE_REG_ADDR] = bin2bcd(tm->tm_mday); + buf[RTC_MON_REG_ADDR] = bin2bcd(tm->tm_mon) | is_century; + buf[RTC_YR_REG_ADDR] = bin2bcd(tm->tm_year % 100); + + return dm_i2c_write(dev, 0, buf, sizeof(buf)); +} + +static int ds3232_rtc_get(struct udevice *dev, struct rtc_time *tm) +{ + int ret; + u8 buf[RTC_DATE_TIME_REG_SIZE]; + u8 is_twelve_hr; + u8 is_pm; + u8 is_century; + + ret = verify_osc(dev); + if (ret < 0) + return ret; + + ret = dm_i2c_read(dev, 0, buf, sizeof(buf)); + if (ret < 0) + return ret; + + /* Extract additional information for AM/PM and century */ + is_twelve_hr = buf[RTC_HR_REG_ADDR] & 0x40; + is_pm = buf[RTC_HR_REG_ADDR] & 0x20; + is_century = buf[RTC_MON_REG_ADDR] & 0x80; + + tm->tm_sec = bcd2bin(buf[RTC_SEC_REG_ADDR] & 0x7F); + tm->tm_min = bcd2bin(buf[RTC_MIN_REG_ADDR] & 0x7F); + + if (is_twelve_hr) + tm->tm_hour = bcd2bin(buf[RTC_HR_REG_ADDR] & 0x1F) + + (is_pm ? 12 : 0); + else + tm->tm_hour = bcd2bin(buf[RTC_HR_REG_ADDR]); + + tm->tm_wday = bcd2bin((buf[RTC_DAY_REG_ADDR] & 0x07) - 1); + tm->tm_mday = bcd2bin(buf[RTC_DATE_REG_ADDR] & 0x3F); + tm->tm_mon = bcd2bin((buf[RTC_MON_REG_ADDR] & 0x7F)); + tm->tm_year = bcd2bin(buf[RTC_YR_REG_ADDR]) + + (is_century ? 2000 : 1900); + tm->tm_yday = 0; + tm->tm_isdst = 0; + + return 0; +} + +static int ds3232_rtc_reset(struct udevice *dev) +{ + int ret; + + ret = reset_sram(dev); + if (ret < 0) + return ret; + + /* + * From datasheet + * (https://datasheets.maximintegrated.com/en/ds/DS3232M.pdf): + * + * The device reset occurs during the normal acknowledge time slot + * following the receipt of the data byte carrying that + * SWRST instruction a NACK occurs due to the resetting action. + * + * Therefore we don't verify the result of I2C write operation since it + * will fail due the NACK. + */ + ds3232_rtc_write8(dev, RTC_TEST_REG_ADDR, RTC_TEST_BIT_SWRST); + + return 0; +} + +static int ds3232_probe(struct udevice *dev) +{ + int rtc_status; + int ret; + struct ds3232_priv_data *priv_data; + + priv_data = dev_get_priv(dev); + if (!priv_data) + return -EINVAL; + + priv_data->sram_start = RTC_SRAM_START; + priv_data->max_register = RTC_SRAM_END; + priv_data->sram_size = RTC_SRAM_SIZE; + + ret = ds3232_rtc_read8(dev, RTC_STAT_REG_ADDR); + if (ret < 0) + return ret; + + rtc_status = ret; + + ret = verify_osc(dev); + if (ret < 0) + return ret; + + rtc_status &= ~(RTC_STAT_BIT_OSF | RTC_STAT_BIT_A1F | RTC_STAT_BIT_A2F); + + return ds3232_rtc_write8(dev, RTC_STAT_REG_ADDR, rtc_status); +} + +static const struct rtc_ops ds3232_rtc_ops = { + .get = ds3232_rtc_get, + .set = ds3232_rtc_set, + .reset = ds3232_rtc_reset, + .read8 = ds3232_rtc_read8, + .write8 = ds3232_rtc_write8 +}; + +static const struct udevice_id ds3232_rtc_ids[] = { + { .compatible = "dallas,ds3232" }, + { } +}; + +U_BOOT_DRIVER(rtc_ds3232) = { + .name = "rtc-ds3232", + .id = UCLASS_RTC, + .probe = ds3232_probe, + .of_match = ds3232_rtc_ids, + .ops = &ds3232_rtc_ops, + .priv_auto_alloc_size = sizeof(struct ds3232_priv_data), +};