From patchwork Thu Oct 26 14:48:04 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Martyn Welch X-Patchwork-Id: 830777 X-Patchwork-Delegate: sbabic@denx.de Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=none (mailfrom) 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; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.b="ckIGPVBM"; dkim-atps=neutral Received: from lists.denx.de (dione.denx.de [81.169.180.215]) by ozlabs.org (Postfix) with ESMTP id 3yN9w92Nxjz9t7D for ; Fri, 27 Oct 2017 02:31:37 +1100 (AEDT) Received: by lists.denx.de (Postfix, from userid 105) id DDF58C21DB2; Thu, 26 Oct 2017 15:29:45 +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, 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 E0113C21E18; Thu, 26 Oct 2017 15:25:34 +0000 (UTC) Received: by lists.denx.de (Postfix, from userid 105) id 509A4C21C73; Thu, 26 Oct 2017 14:48:18 +0000 (UTC) Received: from mail-wr0-f195.google.com (mail-wr0-f195.google.com [209.85.128.195]) by lists.denx.de (Postfix) with ESMTPS id 803ACC21C35 for ; Thu, 26 Oct 2017 14:48:14 +0000 (UTC) Received: by mail-wr0-f195.google.com with SMTP id w105so3452526wrc.0 for ; Thu, 26 Oct 2017 07:48:14 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=sender:from:to:cc:subject:date:message-id:in-reply-to:references; bh=js93oq/Hh3DqUjr6R1IhFF2pzbqvwaAr2B3aaI8JPEA=; b=ckIGPVBMdL+dGqYRe4wEsX12kjx7ONxKC2snHum56npHewSyCxglu9ev7pKU+n3JF4 b/leiszyh/8BXbg4S6L2xZT79b4/CwiPksP/F/typLc8jGQupC4cxLFYIKjBGsYJeLjP qL9C0I/T5P0S92QmLXlbjyqoAdC6zTsD8PrzmknoJ7YnUFbpzylfiI3McsbuSJiZGH2c 9h1Bd1ROD7EjkycbS9ncEUZ4AAXik2Ha9wk2o6oChXuA71zdbFN1fmQcFeUpQdnAoMIL Asd/hBnZegISMA9L9aBOM42B1KaN6okVl5Fy0kggPo5Jt0kzFGviJn/k3sq2DHUbUgbE 7jYA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:sender:from:to:cc:subject:date:message-id :in-reply-to:references; bh=js93oq/Hh3DqUjr6R1IhFF2pzbqvwaAr2B3aaI8JPEA=; b=UDOPl4yq/gTbUBPYFaPMl2GHDjiM7C6jHSXe5kEQYBC+bkd6zUUHE5DoYdklN4BTlB 5K6BLusqd9q1BBMn91UWHVNmNph37uwh78IvzP3EZa6+nbu9mLm98BVRIXJV/n3Q0MQw Zam9Jgc/tCUpCt8wfd2sFTWUBV7a9rJuMC4s7QG7lXoTSemeNShcjMOyIAGmnX0WZjDf CvlY62OrPXXsoPvdQmtrZs/Bo/kefZp1+KYglxmSSuOySUeQNt/8PZChO+3nYxSYthFV D3dv/bgNiH0U9SJmiQIx6RHCkd33SGaYumckjgXs7gixN4caSwqAt00jbUMxyYvB1O5g 8iLA== X-Gm-Message-State: AMCzsaWmws8ASs3ZqX30ku933O17rI/NWvZFsHN0T6oKuHBCU2+Aak2t EabtGpX7CxDc7FIW3dxFGbH20A== X-Google-Smtp-Source: ABhQp+TODfP43dCpy/vzocjJigTdnEAOAviR0gppIcgWw+exh4JzNZX0Wm7XJQAw6uMVgnDVuWJejA== X-Received: by 10.223.134.14 with SMTP id 14mr5615309wrv.148.1509029293771; Thu, 26 Oct 2017 07:48:13 -0700 (PDT) Received: from hades (host86-162-171-239.range86-162.btcentralplus.com. [86.162.171.239]) by smtp.gmail.com with ESMTPSA id j27sm4765134wrd.42.2017.10.26.07.48.10 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Thu, 26 Oct 2017 07:48:10 -0700 (PDT) Received: from martyn by hades with local (Exim 4.84_2) (envelope-from ) id 1e7jS5-00073n-2D; Thu, 26 Oct 2017 15:48:09 +0100 From: Martyn Welch To: u-boot@lists.denx.de Date: Thu, 26 Oct 2017 15:48:04 +0100 Message-Id: <1509029285-27071-7-git-send-email-martyn@welchs.me.uk> X-Mailer: git-send-email 2.1.4 In-Reply-To: <1509029285-27071-1-git-send-email-martyn@welchs.me.uk> References: <1509029285-27071-1-git-send-email-martyn@welchs.me.uk> X-Mailman-Approved-At: Thu, 26 Oct 2017 15:25:27 +0000 Cc: Martyn Welch , Martyn Welch , Nandor Han Subject: [U-Boot] [PATCH 6/7] rtc: add support for s35392a 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: , MIME-Version: 1.0 Errors-To: u-boot-bounces@lists.denx.de Sender: "U-Boot" From: Nandor Han Add support for S35392A RTC. The driver supports both U-Boot driver models. Signed-off-by: Nandor Han Signed-off-by: Martyn Welch Cc: Heiko Schocher Signed-off-by: Martyn Welch --- drivers/rtc/Kconfig | 6 + drivers/rtc/Makefile | 1 + drivers/rtc/s35392a.c | 360 ++++++++++++++++++++++++++++++++++++++++++++++++++ lib/Kconfig | 3 + 4 files changed, 370 insertions(+) create mode 100644 drivers/rtc/s35392a.c diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index d06130c7..2964bb2 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig @@ -30,4 +30,10 @@ config RTC_DS1307 Support for Dallas Semiconductor (now Maxim) DS1307 and DS1338/9 and compatible Real Time Clock devices. +config RTC_S35392A + bool "Enable S35392A driver" + select BITREVERSE + help + Enable s35392a driver which provides rtc get and set function. + endmenu diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile index 003e31a..7a8f97a 100644 --- a/drivers/rtc/Makefile +++ b/drivers/rtc/Makefile @@ -49,5 +49,6 @@ obj-$(CONFIG_RTC_RS5C372A) += rs5c372.o obj-$(CONFIG_RTC_RV3029) += rv3029.o obj-$(CONFIG_RTC_RX8025) += rx8025.o obj-$(CONFIG_RTC_S3C24X0) += s3c24x0_rtc.o +obj-$(CONFIG_RTC_S35392A) += s35392a.o obj-$(CONFIG_SANDBOX) += sandbox_rtc.o obj-$(CONFIG_RTC_X1205) += x1205.o diff --git a/drivers/rtc/s35392a.c b/drivers/rtc/s35392a.c new file mode 100644 index 0000000..0aa7865 --- /dev/null +++ b/drivers/rtc/s35392a.c @@ -0,0 +1,360 @@ +/* + * SII Semiconductor Corporation S35392A RTC driver. + * + * Copyright (c) 2017, General Electric Company + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * SPDX-License-Identifier: GPL-2.0 + */ + + +#include +#include +#include +#include +#include +#include + +#define S35390A_CMD_STATUS1 0x30 +#define S35390A_CMD_STATUS2 0x31 +#define S35390A_CMD_TIME1 0x32 +#define S35390A_CMD_TIME2 0x33 +#define S35390A_CMD_INT2_REG1 0x35 + +#define S35390A_BYTE_YEAR 0 +#define S35390A_BYTE_MONTH 1 +#define S35390A_BYTE_DAY 2 +#define S35390A_BYTE_WDAY 3 +#define S35390A_BYTE_HOURS 4 +#define S35390A_BYTE_MINS 5 +#define S35390A_BYTE_SECS 6 + +/* flags for STATUS1 */ +#define S35390A_FLAG_POC 0x01 +#define S35390A_FLAG_BLD 0x02 +#define S35390A_FLAG_INT2 0x04 +#define S35390A_FLAG_24H 0x40 +#define S35390A_FLAG_RESET 0x80 + +/* If either BLD or POC is set, then the chip has lost power long enough for + * the time value to become invalid. */ +#define S35390A_LOW_VOLTAGE (S35390A_FLAG_POC | S35390A_FLAG_BLD) + +/*---------------------------------------------------------------------*/ +#undef DEBUG_RTC + +#ifdef DEBUG_RTC +#define DEBUGR(fmt,args...) printf(fmt ,##args) +#else +#define DEBUGR(fmt,args...) +#endif +/*---------------------------------------------------------------------*/ + +#ifdef CONFIG_DM_RTC +#define DEV_TYPE struct udevice + +#else +/* Local udevice */ +struct ludevice { + u8 chip; +}; +#define DEV_TYPE struct ludevice +struct ludevice dev; + +#endif + +#define msleep(a) udelay(a * 1000) + +int lowvoltage = 0; + +static int s35392a_rtc_reset(DEV_TYPE *dev); + +static int s35392a_rtc_read(DEV_TYPE *dev, u8 reg, u8* buf, int len) +{ + int ret; + +#ifdef CONFIG_DM_RTC + /* TODO: we need to tweak the chip address to reg */ + ret = dm_i2c_read(dev, 0, buf, len); +#else + (void)dev; + ret = i2c_read(reg, 0, -1, buf, len); +#endif + + return ret; +} + +static int s35392a_rtc_write(DEV_TYPE *dev, u8 reg, u8* buf, int len) +{ + int ret; + +#ifdef CONFIG_DM_RTC + /* TODO: we need to tweak the chip address to reg */ + ret = dm_i2c_write(dev, 0, buf, 1); +#else + (void)dev; + ret = i2c_write(reg, 0, 0, buf, len); +#endif + + return ret; +} + +static int s35392a_rtc_read8(DEV_TYPE *dev, unsigned int reg) +{ + u8 val; + int ret; + + ret = s35392a_rtc_read(dev, reg, &val, sizeof(val)); + return ret < 0 ? ret : val; +} + +static int s35392a_rtc_write8(DEV_TYPE *dev, unsigned int reg, int val) +{ + int ret; + u8 lval = val; + + ret = s35392a_rtc_write(dev, reg, &lval, sizeof(lval)); + return ret < 0 ? ret : 0; +} + +static int validate_time(const struct rtc_time *tm) +{ + if ((tm->tm_year < 2000) || (tm->tm_year > 2099)) + return -EINVAL; + + if ((tm->tm_mon < 1) || (tm->tm_mon > 12)) + return -EINVAL; + + if ((tm->tm_mday < 1) || (tm->tm_mday > 31)) + return -EINVAL; + + if ((tm->tm_wday < 0) || (tm->tm_wday > 6)) + return -EINVAL; + + if ((tm->tm_hour < 0) || (tm->tm_hour > 23)) + return -EINVAL; + + if ((tm->tm_min < 0) || (tm->tm_min > 59)) + return -EINVAL; + + if ((tm->tm_sec < 0) || (tm->tm_sec > 59)) + return -EINVAL; + + return 0; +} + +void s35392a_rtc_init(DEV_TYPE *dev) +{ + int status = s35392a_rtc_read8(dev, S35390A_CMD_STATUS1); + if (status < 0) + goto error; + + DEBUGR("init: S35390A_CMD_STATUS1: 0x%x\n", status); + + lowvoltage = status & S35390A_LOW_VOLTAGE ? 1 : 0; + + if (status & S35390A_FLAG_POC) + /* + * Do not communicate for 0.5 seconds since the power-on + * detection circuit is in operation. + */ + msleep(500); + + else if (!lowvoltage) + /* + * If both POC and BLD are unset everything is fine. + */ + return; + + if(lowvoltage) + printf("RTC low voltage detected\n"); + + if (!s35392a_rtc_reset(dev)) + return; + +error: + printf("Error RTC init. \n"); +} + +/* Get the current time from the RTC */ +static int s35392a_rtc_get(DEV_TYPE *dev, struct rtc_time *tm) +{ + u8 date[7]; + int ret, i; + + if (lowvoltage) { + DEBUGR("RTC low voltage detected\n"); + return -EINVAL; + } + + ret = s35392a_rtc_read(dev, S35390A_CMD_TIME1, date, sizeof(date)); + if (ret < 0) { + DEBUGR("Error reading date from RTC\n"); + return -EIO; + } + + /* This chip returns the bits of each byte in reverse order */ + for (i = 0; i < 7; ++i) + date[i] = bitrev8(date[i]); + + tm->tm_sec = bcd2bin(date[S35390A_BYTE_SECS]); + tm->tm_min = bcd2bin(date[S35390A_BYTE_MINS]); + tm->tm_hour = bcd2bin(date[S35390A_BYTE_HOURS] & ~S35390A_FLAG_24H); + tm->tm_wday = bcd2bin(date[S35390A_BYTE_WDAY]); + tm->tm_mday = bcd2bin(date[S35390A_BYTE_DAY]); + tm->tm_mon = bcd2bin(date[S35390A_BYTE_MONTH]); + tm->tm_year = bcd2bin(date[S35390A_BYTE_YEAR]) + 2000; + + DEBUGR ("Get DATE: %4d-%02d-%02d (wday=%d) TIME: %2d:%02d:%02d\n", + tm->tm_year, tm->tm_mon, tm->tm_mday, tm->tm_wday, + tm->tm_hour, tm->tm_min, tm->tm_sec); + + return 0; +} + +/* Set the RTC */ +static int s35392a_rtc_set(DEV_TYPE *dev, const struct rtc_time *tm) +{ + int i, ret; + int status; + u8 date[7]; + + DEBUGR ("Set DATE: %4d-%02d-%02d (wday=%d) TIME: %2d:%02d:%02d\n", + tm->tm_year, tm->tm_mon, tm->tm_mday, tm->tm_wday, + tm->tm_hour, tm->tm_min, tm->tm_sec); + + ret = validate_time(tm); + if (ret < 0) + return -EINVAL; + + /* We support only 24h mode */ + ret = s35392a_rtc_read8(dev, S35390A_CMD_STATUS1); + if (ret < 0) + return -EIO; + status = ret; + + ret = s35392a_rtc_write8(dev, S35390A_CMD_STATUS1, status | S35390A_FLAG_24H); + if (ret < 0) + return -EIO; + + date[S35390A_BYTE_YEAR] = bin2bcd(tm->tm_year - 2000); + date[S35390A_BYTE_MONTH] = bin2bcd(tm->tm_mon ); + date[S35390A_BYTE_DAY] = bin2bcd(tm->tm_mday); + date[S35390A_BYTE_WDAY] = bin2bcd(tm->tm_wday); + date[S35390A_BYTE_HOURS] = bin2bcd(tm->tm_hour); + date[S35390A_BYTE_MINS] = bin2bcd(tm->tm_min); + date[S35390A_BYTE_SECS] = bin2bcd(tm->tm_sec); + + /* This chip expects the bits of each byte to be in reverse order */ + for (i = 0; i < 7; ++i) + date[i] = bitrev8(date[i]); + + ret = s35392a_rtc_write(dev, S35390A_CMD_TIME1, date, sizeof(date)); + if (ret < 0) { + DEBUGR("Error writing date to RTC\n"); + return -EIO; + } + + /* Now we have time. Reset the low voltage status */ + lowvoltage = 0; + + return 0; +} + +/* Reset the RTC. */ +static int s35392a_rtc_reset(DEV_TYPE *dev) +{ + int buf; + int ret; + unsigned initcount = 0; + + buf = S35390A_FLAG_RESET; + +initialize: + ret = s35392a_rtc_write8(dev, S35390A_CMD_STATUS1, buf); + if (ret < 0) + return -EIO; + + ret = s35392a_rtc_read8(dev, S35390A_CMD_STATUS1); + if (ret < 0) + return -EIO; + buf = ret; + + if (!lowvoltage) + lowvoltage = buf & S35390A_LOW_VOLTAGE ? 1 : 0; + + if (buf & S35390A_LOW_VOLTAGE) { + /* Try up to five times to reset the chip */ + if (initcount < 5) { + ++initcount; + goto initialize; + } else + return -EIO; + } + + return 0; +} + +#ifndef CONFIG_DM_RTC + +int rtc_get(struct rtc_time * tm) +{ + return s35392a_rtc_get(&dev, tm); +} + +int rtc_set(struct rtc_time * tm) +{ + return s35392a_rtc_set(&dev, tm); +} + +void rtc_reset(void) +{ + s35392a_rtc_reset(&dev); +} + +void rtc_init(void) +{ + s35392a_rtc_init(&dev); +} + +#else + +static int s35392a_probe(struct udevice *dev) +{ + s35392a_rtc_init(dev); + return 0; +} + +static const struct rtc_ops s35392a_rtc_ops = { + .get = s35392a_rtc_get, + .set = s35392a_rtc_set, + .read8 = s35392a_rtc_read8, + .write8 = s35392a_rtc_write8, + .reset = s35392a_rtc_reset, +}; + +static const struct udevice_id s35392a_rtc_ids[] = { + { .compatible = "sii,s35392a-rtc" }, + { } +}; + +U_BOOT_DRIVER(s35392a_rtc) = { + .name = "s35392a_rtc", + .id = UCLASS_RTC, + .probe = s35392a_probe, + .of_match = s35392a_rtc_ids, + .ops = &s35392a_rtc_ops, +}; + +#endif diff --git a/lib/Kconfig b/lib/Kconfig index 18663ba..f447c53 100644 --- a/lib/Kconfig +++ b/lib/Kconfig @@ -80,6 +80,9 @@ config TPL_TINY_MEMSET config RBTREE bool +config BITREVERSE + bool "Bit reverse library from Linux" + source lib/dhry/Kconfig menu "Security support"