Commit da5337a61cd41f3bfbaee5b78ba58676bd288073

Authored by Nandor Han
Committed by Stefano Babic
1 parent f31dac4e6e

rtc: add support for s35392a

Add support for S35392A RTC. The driver supports both U-Boot driver
models.

Signed-off-by: Nandor Han <nandor.han@ge.com>
Signed-off-by: Martyn Welch <martyn.welch@collabora.co.uk>
Cc: Heiko Schocher <hs@denx.de>

Showing 4 changed files with 375 additions and 0 deletions Side-by-side Diff

... ... @@ -30,5 +30,11 @@
30 30 Support for Dallas Semiconductor (now Maxim) DS1307 and DS1338/9 and
31 31 compatible Real Time Clock devices.
32 32  
  33 +config RTC_S35392A
  34 + bool "Enable S35392A driver"
  35 + select BITREVERSE
  36 + help
  37 + Enable s35392a driver which provides rtc get and set function.
  38 +
33 39 endmenu
drivers/rtc/Makefile
... ... @@ -49,6 +49,7 @@
49 49 obj-$(CONFIG_RTC_RV3029) += rv3029.o
50 50 obj-$(CONFIG_RTC_RX8025) += rx8025.o
51 51 obj-$(CONFIG_RTC_S3C24X0) += s3c24x0_rtc.o
  52 +obj-$(CONFIG_RTC_S35392A) += s35392a.o
52 53 obj-$(CONFIG_SANDBOX) += sandbox_rtc.o
53 54 obj-$(CONFIG_RTC_X1205) += x1205.o
drivers/rtc/s35392a.c
  1 +/*
  2 + * SII Semiconductor Corporation S35392A RTC driver.
  3 + *
  4 + * Copyright (c) 2017, General Electric Company
  5 + *
  6 + * This program is free software; you can redistribute it and/or modify it
  7 + * under the terms and conditions of the GNU General Public License,
  8 + * version 2, as published by the Free Software Foundation.
  9 + *
  10 + * This program is distributed in the hope it will be useful, but WITHOUT
  11 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  12 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
  13 + * more details.
  14 + *
  15 + * You should have received a copy of the GNU General Public License
  16 + * along with this program. If not, see <http://www.gnu.org/licenses/>.
  17 + *
  18 + * SPDX-License-Identifier: GPL-2.0
  19 + */
  20 +
  21 +#include <command.h>
  22 +#include <common.h>
  23 +#include <dm.h>
  24 +#include <i2c.h>
  25 +#include <linux/bitrev.h>
  26 +#include <rtc.h>
  27 +
  28 +#define S35390A_CMD_STATUS1 0x30
  29 +#define S35390A_CMD_STATUS2 0x31
  30 +#define S35390A_CMD_TIME1 0x32
  31 +#define S35390A_CMD_TIME2 0x33
  32 +#define S35390A_CMD_INT2_REG1 0x35
  33 +
  34 +#define S35390A_BYTE_YEAR 0
  35 +#define S35390A_BYTE_MONTH 1
  36 +#define S35390A_BYTE_DAY 2
  37 +#define S35390A_BYTE_WDAY 3
  38 +#define S35390A_BYTE_HOURS 4
  39 +#define S35390A_BYTE_MINS 5
  40 +#define S35390A_BYTE_SECS 6
  41 +
  42 +/* flags for STATUS1 */
  43 +#define S35390A_FLAG_POC 0x01
  44 +#define S35390A_FLAG_BLD 0x02
  45 +#define S35390A_FLAG_INT2 0x04
  46 +#define S35390A_FLAG_24H 0x40
  47 +#define S35390A_FLAG_RESET 0x80
  48 +
  49 +/*
  50 + * If either BLD or POC is set, then the chip has lost power long enough for
  51 + * the time value to become invalid.
  52 + */
  53 +#define S35390A_LOW_VOLTAGE (S35390A_FLAG_POC | S35390A_FLAG_BLD)
  54 +
  55 +/*---------------------------------------------------------------------*/
  56 +#undef DEBUG_RTC
  57 +
  58 +#ifdef DEBUG_RTC
  59 +#define DEBUGR(fmt, args...) printf(fmt, ##args)
  60 +#else
  61 +#define DEBUGR(fmt, args...)
  62 +#endif
  63 +/*---------------------------------------------------------------------*/
  64 +
  65 +#ifdef CONFIG_DM_RTC
  66 +#define DEV_TYPE struct udevice
  67 +#else
  68 +/* Local udevice */
  69 +struct ludevice {
  70 + u8 chip;
  71 +};
  72 +
  73 +#define DEV_TYPE struct ludevice
  74 +struct ludevice dev;
  75 +
  76 +#endif
  77 +
  78 +#define msleep(a) udelay(a * 1000)
  79 +
  80 +int lowvoltage;
  81 +
  82 +static int s35392a_rtc_reset(DEV_TYPE *dev);
  83 +
  84 +static int s35392a_rtc_read(DEV_TYPE *dev, u8 reg, u8 *buf, int len)
  85 +{
  86 + int ret;
  87 +
  88 +#ifdef CONFIG_DM_RTC
  89 + /* TODO: we need to tweak the chip address to reg */
  90 + ret = dm_i2c_read(dev, 0, buf, len);
  91 +#else
  92 + (void)dev;
  93 + ret = i2c_read(reg, 0, -1, buf, len);
  94 +#endif
  95 +
  96 + return ret;
  97 +}
  98 +
  99 +static int s35392a_rtc_write(DEV_TYPE *dev, u8 reg, u8 *buf, int len)
  100 +{
  101 + int ret;
  102 +
  103 +#ifdef CONFIG_DM_RTC
  104 + /* TODO: we need to tweak the chip address to reg */
  105 + ret = dm_i2c_write(dev, 0, buf, 1);
  106 +#else
  107 + (void)dev;
  108 + ret = i2c_write(reg, 0, 0, buf, len);
  109 +#endif
  110 +
  111 + return ret;
  112 +}
  113 +
  114 +static int s35392a_rtc_read8(DEV_TYPE *dev, unsigned int reg)
  115 +{
  116 + u8 val;
  117 + int ret;
  118 +
  119 + ret = s35392a_rtc_read(dev, reg, &val, sizeof(val));
  120 + return ret < 0 ? ret : val;
  121 +}
  122 +
  123 +static int s35392a_rtc_write8(DEV_TYPE *dev, unsigned int reg, int val)
  124 +{
  125 + int ret;
  126 + u8 lval = val;
  127 +
  128 + ret = s35392a_rtc_write(dev, reg, &lval, sizeof(lval));
  129 + return ret < 0 ? ret : 0;
  130 +}
  131 +
  132 +static int validate_time(const struct rtc_time *tm)
  133 +{
  134 + if ((tm->tm_year < 2000) || (tm->tm_year > 2099))
  135 + return -EINVAL;
  136 +
  137 + if ((tm->tm_mon < 1) || (tm->tm_mon > 12))
  138 + return -EINVAL;
  139 +
  140 + if ((tm->tm_mday < 1) || (tm->tm_mday > 31))
  141 + return -EINVAL;
  142 +
  143 + if ((tm->tm_wday < 0) || (tm->tm_wday > 6))
  144 + return -EINVAL;
  145 +
  146 + if ((tm->tm_hour < 0) || (tm->tm_hour > 23))
  147 + return -EINVAL;
  148 +
  149 + if ((tm->tm_min < 0) || (tm->tm_min > 59))
  150 + return -EINVAL;
  151 +
  152 + if ((tm->tm_sec < 0) || (tm->tm_sec > 59))
  153 + return -EINVAL;
  154 +
  155 + return 0;
  156 +}
  157 +
  158 +void s35392a_rtc_init(DEV_TYPE *dev)
  159 +{
  160 + int status;
  161 +
  162 + status = s35392a_rtc_read8(dev, S35390A_CMD_STATUS1);
  163 + if (status < 0)
  164 + goto error;
  165 +
  166 + DEBUGR("init: S35390A_CMD_STATUS1: 0x%x\n", status);
  167 +
  168 + lowvoltage = status & S35390A_LOW_VOLTAGE ? 1 : 0;
  169 +
  170 + if (status & S35390A_FLAG_POC)
  171 + /*
  172 + * Do not communicate for 0.5 seconds since the power-on
  173 + * detection circuit is in operation.
  174 + */
  175 + msleep(500);
  176 +
  177 + else if (!lowvoltage)
  178 + /*
  179 + * If both POC and BLD are unset everything is fine.
  180 + */
  181 + return;
  182 +
  183 + if (lowvoltage)
  184 + printf("RTC low voltage detected\n");
  185 +
  186 + if (!s35392a_rtc_reset(dev))
  187 + return;
  188 +
  189 +error:
  190 + printf("Error RTC init.\n");
  191 +}
  192 +
  193 +/* Get the current time from the RTC */
  194 +static int s35392a_rtc_get(DEV_TYPE *dev, struct rtc_time *tm)
  195 +{
  196 + u8 date[7];
  197 + int ret, i;
  198 +
  199 + if (lowvoltage) {
  200 + DEBUGR("RTC low voltage detected\n");
  201 + return -EINVAL;
  202 + }
  203 +
  204 + ret = s35392a_rtc_read(dev, S35390A_CMD_TIME1, date, sizeof(date));
  205 + if (ret < 0) {
  206 + DEBUGR("Error reading date from RTC\n");
  207 + return -EIO;
  208 + }
  209 +
  210 + /* This chip returns the bits of each byte in reverse order */
  211 + for (i = 0; i < 7; ++i)
  212 + date[i] = bitrev8(date[i]);
  213 +
  214 + tm->tm_sec = bcd2bin(date[S35390A_BYTE_SECS]);
  215 + tm->tm_min = bcd2bin(date[S35390A_BYTE_MINS]);
  216 + tm->tm_hour = bcd2bin(date[S35390A_BYTE_HOURS] & ~S35390A_FLAG_24H);
  217 + tm->tm_wday = bcd2bin(date[S35390A_BYTE_WDAY]);
  218 + tm->tm_mday = bcd2bin(date[S35390A_BYTE_DAY]);
  219 + tm->tm_mon = bcd2bin(date[S35390A_BYTE_MONTH]);
  220 + tm->tm_year = bcd2bin(date[S35390A_BYTE_YEAR]) + 2000;
  221 +
  222 + DEBUGR("Get DATE: %4d-%02d-%02d (wday=%d) TIME: %2d:%02d:%02d\n",
  223 + tm->tm_year, tm->tm_mon, tm->tm_mday, tm->tm_wday,
  224 + tm->tm_hour, tm->tm_min, tm->tm_sec);
  225 +
  226 + return 0;
  227 +}
  228 +
  229 +/* Set the RTC */
  230 +static int s35392a_rtc_set(DEV_TYPE *dev, const struct rtc_time *tm)
  231 +{
  232 + int i, ret;
  233 + int status;
  234 + u8 date[7];
  235 +
  236 + DEBUGR("Set DATE: %4d-%02d-%02d (wday=%d) TIME: %2d:%02d:%02d\n",
  237 + tm->tm_year, tm->tm_mon, tm->tm_mday, tm->tm_wday,
  238 + tm->tm_hour, tm->tm_min, tm->tm_sec);
  239 +
  240 + ret = validate_time(tm);
  241 + if (ret < 0)
  242 + return -EINVAL;
  243 +
  244 + /* We support only 24h mode */
  245 + ret = s35392a_rtc_read8(dev, S35390A_CMD_STATUS1);
  246 + if (ret < 0)
  247 + return -EIO;
  248 + status = ret;
  249 +
  250 + ret = s35392a_rtc_write8(dev, S35390A_CMD_STATUS1,
  251 + status | S35390A_FLAG_24H);
  252 + if (ret < 0)
  253 + return -EIO;
  254 +
  255 + date[S35390A_BYTE_YEAR] = bin2bcd(tm->tm_year - 2000);
  256 + date[S35390A_BYTE_MONTH] = bin2bcd(tm->tm_mon);
  257 + date[S35390A_BYTE_DAY] = bin2bcd(tm->tm_mday);
  258 + date[S35390A_BYTE_WDAY] = bin2bcd(tm->tm_wday);
  259 + date[S35390A_BYTE_HOURS] = bin2bcd(tm->tm_hour);
  260 + date[S35390A_BYTE_MINS] = bin2bcd(tm->tm_min);
  261 + date[S35390A_BYTE_SECS] = bin2bcd(tm->tm_sec);
  262 +
  263 + /* This chip expects the bits of each byte to be in reverse order */
  264 + for (i = 0; i < 7; ++i)
  265 + date[i] = bitrev8(date[i]);
  266 +
  267 + ret = s35392a_rtc_write(dev, S35390A_CMD_TIME1, date, sizeof(date));
  268 + if (ret < 0) {
  269 + DEBUGR("Error writing date to RTC\n");
  270 + return -EIO;
  271 + }
  272 +
  273 + /* Now we have time. Reset the low voltage status */
  274 + lowvoltage = 0;
  275 +
  276 + return 0;
  277 +}
  278 +
  279 +/* Reset the RTC. */
  280 +static int s35392a_rtc_reset(DEV_TYPE *dev)
  281 +{
  282 + int buf;
  283 + int ret;
  284 + unsigned int initcount = 0;
  285 +
  286 + buf = S35390A_FLAG_RESET;
  287 +
  288 +initialize:
  289 + ret = s35392a_rtc_write8(dev, S35390A_CMD_STATUS1, buf);
  290 + if (ret < 0)
  291 + return -EIO;
  292 +
  293 + ret = s35392a_rtc_read8(dev, S35390A_CMD_STATUS1);
  294 + if (ret < 0)
  295 + return -EIO;
  296 + buf = ret;
  297 +
  298 + if (!lowvoltage)
  299 + lowvoltage = buf & S35390A_LOW_VOLTAGE ? 1 : 0;
  300 +
  301 + if (buf & S35390A_LOW_VOLTAGE) {
  302 + /* Try up to five times to reset the chip */
  303 + if (initcount < 5) {
  304 + ++initcount;
  305 + goto initialize;
  306 + } else {
  307 + return -EIO;
  308 + }
  309 + }
  310 +
  311 + return 0;
  312 +}
  313 +
  314 +#ifndef CONFIG_DM_RTC
  315 +
  316 +int rtc_get(struct rtc_time *tm)
  317 +{
  318 + return s35392a_rtc_get(&dev, tm);
  319 +}
  320 +
  321 +int rtc_set(struct rtc_time *tm)
  322 +{
  323 + return s35392a_rtc_set(&dev, tm);
  324 +}
  325 +
  326 +void rtc_reset(void)
  327 +{
  328 + s35392a_rtc_reset(&dev);
  329 +}
  330 +
  331 +void rtc_init(void)
  332 +{
  333 + s35392a_rtc_init(&dev);
  334 +}
  335 +
  336 +#else
  337 +
  338 +static int s35392a_probe(struct udevice *dev)
  339 +{
  340 + s35392a_rtc_init(dev);
  341 + return 0;
  342 +}
  343 +
  344 +static const struct rtc_ops s35392a_rtc_ops = {
  345 + .get = s35392a_rtc_get,
  346 + .set = s35392a_rtc_set,
  347 + .read8 = s35392a_rtc_read8,
  348 + .write8 = s35392a_rtc_write8,
  349 + .reset = s35392a_rtc_reset,
  350 +};
  351 +
  352 +static const struct udevice_id s35392a_rtc_ids[] = {
  353 + { .compatible = "sii,s35392a-rtc" },
  354 + { }
  355 +};
  356 +
  357 +U_BOOT_DRIVER(s35392a_rtc) = {
  358 + .name = "s35392a_rtc",
  359 + .id = UCLASS_RTC,
  360 + .probe = s35392a_probe,
  361 + .of_match = s35392a_rtc_ids,
  362 + .ops = &s35392a_rtc_ops,
  363 +};
  364 +
  365 +#endif
... ... @@ -80,6 +80,9 @@
80 80 config RBTREE
81 81 bool
82 82  
  83 +config BITREVERSE
  84 + bool "Bit reverse library from Linux"
  85 +
83 86 source lib/dhry/Kconfig
84 87  
85 88 menu "Security support"