Commit 958a2106f5af62d47e3b522ef4bbf3c13185dfb1

Authored by Nandor Han
Committed by Stefano Babic
1 parent 8d9bde0dbb

rtc: adding RX8010SJ rtc driver

Add a new driver for RX8010SJ rtc chip. The driver implements both
formats of U-Boot driver model.

Signed-off-by: Nandor Han <nandor.han@ge.com>
Signed-off-by: Martyn Welch <martyn.welch@collabora.co.uk>
Signed-off-by: Sebastian Reichel <sebastian.reichel@collabora.co.uk>

Showing 3 changed files with 385 additions and 0 deletions Side-by-side Diff

... ... @@ -30,6 +30,12 @@
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_RX8010SJ
  34 + bool "Enable RX8010SJ driver"
  35 + depends on DM_RTC
  36 + help
  37 + Support for Epson RX8010SJ Real Time Clock devices.
  38 +
33 39 config RTC_S35392A
34 40 bool "Enable S35392A driver"
35 41 select BITREVERSE
drivers/rtc/Makefile
... ... @@ -48,6 +48,7 @@
48 48 obj-$(CONFIG_RTC_RS5C372A) += rs5c372.o
49 49 obj-$(CONFIG_RTC_RV3029) += rv3029.o
50 50 obj-$(CONFIG_RTC_RX8025) += rx8025.o
  51 +obj-$(CONFIG_RTC_RX8010SJ) += rx8010sj.o
51 52 obj-$(CONFIG_RTC_S3C24X0) += s3c24x0_rtc.o
52 53 obj-$(CONFIG_RTC_S35392A) += s35392a.o
53 54 obj-$(CONFIG_SANDBOX) += sandbox_rtc.o
drivers/rtc/rx8010sj.c
  1 +/*
  2 + * Epson RX8010 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 +
  19 +#include <command.h>
  20 +#include <common.h>
  21 +#include <dm.h>
  22 +#include <i2c.h>
  23 +#include <rtc.h>
  24 +
  25 +/*---------------------------------------------------------------------*/
  26 +/* #undef DEBUG_RTC */
  27 +
  28 +#ifdef DEBUG_RTC
  29 +#define DEBUGR(fmt, args...) printf(fmt, ##args)
  30 +#else
  31 +#define DEBUGR(fmt, args...)
  32 +#endif
  33 +/*---------------------------------------------------------------------*/
  34 +
  35 +#ifndef CONFIG_SYS_I2C_RTC_ADDR
  36 +# define CONFIG_SYS_I2C_RTC_ADDR 0x32
  37 +#endif
  38 +
  39 +/*
  40 + * RTC register addresses
  41 + */
  42 +#define RX8010_SEC 0x10
  43 +#define RX8010_MIN 0x11
  44 +#define RX8010_HOUR 0x12
  45 +#define RX8010_WDAY 0x13
  46 +#define RX8010_MDAY 0x14
  47 +#define RX8010_MONTH 0x15
  48 +#define RX8010_YEAR 0x16
  49 +#define RX8010_YEAR 0x16
  50 +#define RX8010_RESV17 0x17
  51 +#define RX8010_ALMIN 0x18
  52 +#define RX8010_ALHOUR 0x19
  53 +#define RX8010_ALWDAY 0x1A
  54 +#define RX8010_TCOUNT0 0x1B
  55 +#define RX8010_TCOUNT1 0x1C
  56 +#define RX8010_EXT 0x1D
  57 +#define RX8010_FLAG 0x1E
  58 +#define RX8010_CTRL 0x1F
  59 +/* 0x20 to 0x2F are user registers */
  60 +#define RX8010_RESV30 0x30
  61 +#define RX8010_RESV31 0x32
  62 +#define RX8010_IRQ 0x32
  63 +
  64 +#define RX8010_EXT_WADA BIT(3)
  65 +
  66 +#define RX8010_FLAG_VLF BIT(1)
  67 +#define RX8010_FLAG_AF BIT(3)
  68 +#define RX8010_FLAG_TF BIT(4)
  69 +#define RX8010_FLAG_UF BIT(5)
  70 +
  71 +#define RX8010_CTRL_AIE BIT(3)
  72 +#define RX8010_CTRL_UIE BIT(5)
  73 +#define RX8010_CTRL_STOP BIT(6)
  74 +#define RX8010_CTRL_TEST BIT(7)
  75 +
  76 +#define RX8010_ALARM_AE BIT(7)
  77 +
  78 +#ifdef CONFIG_DM_RTC
  79 +
  80 +#define DEV_TYPE struct udevice
  81 +
  82 +#else
  83 +
  84 +/* Local udevice */
  85 +struct ludevice {
  86 + u8 chip;
  87 +};
  88 +
  89 +#define DEV_TYPE struct ludevice
  90 +
  91 +#endif
  92 +
  93 +static int rx8010sj_rtc_read8(DEV_TYPE *dev, unsigned int reg)
  94 +{
  95 + u8 val;
  96 + int ret;
  97 +
  98 +#ifdef CONFIG_DM_RTC
  99 + ret = dm_i2c_read(dev, reg, &val, sizeof(val));
  100 +#else
  101 + ret = i2c_read(dev->chip, reg, 1, &val, 1);
  102 +#endif
  103 +
  104 + return ret < 0 ? ret : val;
  105 +}
  106 +
  107 +static int rx8010sj_rtc_write8(DEV_TYPE *dev, unsigned int reg, int val)
  108 +{
  109 + int ret;
  110 + u8 lval = val;
  111 +
  112 +#ifdef CONFIG_DM_RTC
  113 + ret = dm_i2c_write(dev, reg, &lval, 1);
  114 +#else
  115 + ret = i2c_write(dev->chip, reg, 1, &lval, 1);
  116 +#endif
  117 +
  118 + return ret < 0 ? ret : 0;
  119 +}
  120 +
  121 +static int validate_time(const struct rtc_time *tm)
  122 +{
  123 + if ((tm->tm_year < 2000) || (tm->tm_year > 2099))
  124 + return -EINVAL;
  125 +
  126 + if ((tm->tm_mon < 1) || (tm->tm_mon > 12))
  127 + return -EINVAL;
  128 +
  129 + if ((tm->tm_mday < 1) || (tm->tm_mday > 31))
  130 + return -EINVAL;
  131 +
  132 + if ((tm->tm_wday < 0) || (tm->tm_wday > 6))
  133 + return -EINVAL;
  134 +
  135 + if ((tm->tm_hour < 0) || (tm->tm_hour > 23))
  136 + return -EINVAL;
  137 +
  138 + if ((tm->tm_min < 0) || (tm->tm_min > 59))
  139 + return -EINVAL;
  140 +
  141 + if ((tm->tm_sec < 0) || (tm->tm_sec > 59))
  142 + return -EINVAL;
  143 +
  144 + return 0;
  145 +}
  146 +
  147 +void rx8010sj_rtc_init(DEV_TYPE *dev)
  148 +{
  149 + u8 ctrl[2];
  150 + int need_clear = 0, ret = 0;
  151 +
  152 + /* Initialize reserved registers as specified in datasheet */
  153 + ret = rx8010sj_rtc_write8(dev, RX8010_RESV17, 0xD8);
  154 + if (ret < 0)
  155 + goto error;
  156 +
  157 + ret = rx8010sj_rtc_write8(dev, RX8010_RESV30, 0x00);
  158 + if (ret < 0)
  159 + goto error;
  160 +
  161 + ret = rx8010sj_rtc_write8(dev, RX8010_RESV31, 0x08);
  162 + if (ret < 0)
  163 + goto error;
  164 +
  165 + ret = rx8010sj_rtc_write8(dev, RX8010_IRQ, 0x00);
  166 + if (ret < 0)
  167 + goto error;
  168 +
  169 + for (int i = 0; i < 2; i++) {
  170 + ret = rx8010sj_rtc_read8(dev, RX8010_FLAG + i);
  171 + if (ret < 0)
  172 + goto error;
  173 +
  174 + ctrl[i] = ret;
  175 + }
  176 +
  177 + if (ctrl[0] & RX8010_FLAG_VLF)
  178 + printf("RTC low voltage detected\n");
  179 +
  180 + if (ctrl[0] & RX8010_FLAG_AF) {
  181 + printf("Alarm was detected\n");
  182 + need_clear = 1;
  183 + }
  184 +
  185 + if (ctrl[0] & RX8010_FLAG_TF)
  186 + need_clear = 1;
  187 +
  188 + if (ctrl[0] & RX8010_FLAG_UF)
  189 + need_clear = 1;
  190 +
  191 + if (need_clear) {
  192 + ctrl[0] &= ~(RX8010_FLAG_AF | RX8010_FLAG_TF | RX8010_FLAG_UF);
  193 + ret = rx8010sj_rtc_write8(dev, RX8010_FLAG, ctrl[0]);
  194 + if (ret < 0)
  195 + goto error;
  196 + }
  197 +
  198 + return;
  199 +
  200 +error:
  201 + printf("Error rtc init.\n");
  202 +}
  203 +
  204 +/* Get the current time from the RTC */
  205 +static int rx8010sj_rtc_get(DEV_TYPE *dev, struct rtc_time *tmp)
  206 +{
  207 + u8 date[7];
  208 + int flagreg;
  209 + int ret;
  210 +
  211 + flagreg = rx8010sj_rtc_read8(dev, RX8010_FLAG);
  212 + if (flagreg < 0) {
  213 + DEBUGR("Error reading from RTC. err: %d\n", flagreg);
  214 + return -EIO;
  215 + }
  216 +
  217 + if (flagreg & RX8010_FLAG_VLF) {
  218 + DEBUGR("RTC low voltage detected\n");
  219 + return -EINVAL;
  220 + }
  221 +
  222 + for (int i = 0; i < 7; i++) {
  223 + ret = rx8010sj_rtc_read8(dev, RX8010_SEC + i);
  224 + if (ret < 0) {
  225 + DEBUGR("Error reading from RTC. err: %d\n", ret);
  226 + return -EIO;
  227 + }
  228 + date[i] = ret;
  229 + }
  230 +
  231 + tmp->tm_sec = bcd2bin(date[RX8010_SEC - RX8010_SEC] & 0x7f);
  232 + tmp->tm_min = bcd2bin(date[RX8010_MIN - RX8010_SEC] & 0x7f);
  233 + tmp->tm_hour = bcd2bin(date[RX8010_HOUR - RX8010_SEC] & 0x3f);
  234 + tmp->tm_mday = bcd2bin(date[RX8010_MDAY - RX8010_SEC] & 0x3f);
  235 + tmp->tm_mon = bcd2bin(date[RX8010_MONTH - RX8010_SEC] & 0x1f);
  236 + tmp->tm_year = bcd2bin(date[RX8010_YEAR - RX8010_SEC]) + 2000;
  237 + tmp->tm_wday = 0;
  238 + tmp->tm_yday = 0;
  239 + tmp->tm_isdst = 0;
  240 +
  241 + DEBUGR("Get DATE: %4d-%02d-%02d (wday=%d) TIME: %2d:%02d:%02d\n",
  242 + tmp->tm_year, tmp->tm_mon, tmp->tm_mday, tmp->tm_wday,
  243 + tmp->tm_hour, tmp->tm_min, tmp->tm_sec);
  244 +
  245 + return 0;
  246 +}
  247 +
  248 +/* Set the RTC */
  249 +static int rx8010sj_rtc_set(DEV_TYPE *dev, const struct rtc_time *tm)
  250 +{
  251 + u8 date[7];
  252 + int ctrl, flagreg;
  253 + int ret;
  254 +
  255 + ret = validate_time(tm);
  256 + if (ret < 0)
  257 + return -EINVAL;
  258 +
  259 + /* set STOP bit before changing clock/calendar */
  260 + ctrl = rx8010sj_rtc_read8(dev, RX8010_CTRL);
  261 + if (ctrl < 0)
  262 + return ctrl;
  263 + ret = rx8010sj_rtc_write8(dev, RX8010_CTRL, ctrl | RX8010_CTRL_STOP);
  264 + if (ret < 0)
  265 + return ret;
  266 +
  267 + date[RX8010_SEC - RX8010_SEC] = bin2bcd(tm->tm_sec);
  268 + date[RX8010_MIN - RX8010_SEC] = bin2bcd(tm->tm_min);
  269 + date[RX8010_HOUR - RX8010_SEC] = bin2bcd(tm->tm_hour);
  270 + date[RX8010_MDAY - RX8010_SEC] = bin2bcd(tm->tm_mday);
  271 + date[RX8010_MONTH - RX8010_SEC] = bin2bcd(tm->tm_mon);
  272 + date[RX8010_YEAR - RX8010_SEC] = bin2bcd(tm->tm_year - 2000);
  273 + date[RX8010_WDAY - RX8010_SEC] = bin2bcd(tm->tm_wday);
  274 +
  275 + for (int i = 0; i < 7; i++) {
  276 + ret = rx8010sj_rtc_write8(dev, RX8010_SEC + i, date[i]);
  277 + if (ret < 0) {
  278 + DEBUGR("Error writing to RTC. err: %d\n", ret);
  279 + return -EIO;
  280 + }
  281 + }
  282 +
  283 + /* clear STOP bit after changing clock/calendar */
  284 + ctrl = rx8010sj_rtc_read8(dev, RX8010_CTRL);
  285 + if (ctrl < 0)
  286 + return ctrl;
  287 +
  288 + ret = rx8010sj_rtc_write8(dev, RX8010_CTRL, ctrl & ~RX8010_CTRL_STOP);
  289 + if (ret < 0)
  290 + return ret;
  291 +
  292 + flagreg = rx8010sj_rtc_read8(dev, RX8010_FLAG);
  293 + if (flagreg < 0)
  294 + return flagreg;
  295 +
  296 + if (flagreg & RX8010_FLAG_VLF)
  297 + ret = rx8010sj_rtc_write8(dev, RX8010_FLAG,
  298 + flagreg & ~RX8010_FLAG_VLF);
  299 +
  300 + return 0;
  301 +}
  302 +
  303 +/* Reset the RTC. */
  304 +static int rx8010sj_rtc_reset(DEV_TYPE *dev)
  305 +{
  306 + /* Not needed */
  307 + return 0;
  308 +}
  309 +
  310 +#ifndef CONFIG_DM_RTC
  311 +
  312 +int rtc_get(struct rtc_time *tm)
  313 +{
  314 + struct ludevice dev = {
  315 + .chip = CONFIG_SYS_I2C_RTC_ADDR,
  316 + };
  317 +
  318 + return rx8010sj_rtc_get(&dev, tm);
  319 +}
  320 +
  321 +int rtc_set(struct rtc_time *tm)
  322 +{
  323 + struct ludevice dev = {
  324 + .chip = CONFIG_SYS_I2C_RTC_ADDR,
  325 + };
  326 +
  327 + return rx8010sj_rtc_set(&dev, tm);
  328 +}
  329 +
  330 +void rtc_reset(void)
  331 +{
  332 + struct ludevice dev = {
  333 + .chip = CONFIG_SYS_I2C_RTC_ADDR,
  334 + };
  335 +
  336 + rx8010sj_rtc_reset(&dev);
  337 +}
  338 +
  339 +void rtc_init(void)
  340 +{
  341 + struct ludevice dev = {
  342 + .chip = CONFIG_SYS_I2C_RTC_ADDR,
  343 + };
  344 +
  345 + rx8010sj_rtc_init(&dev);
  346 +}
  347 +
  348 +#else
  349 +
  350 +static int rx8010sj_probe(struct udevice *dev)
  351 +{
  352 + rx8010sj_rtc_init(&dev);
  353 +
  354 + return 0;
  355 +}
  356 +
  357 +static const struct rtc_ops rx8010sj_rtc_ops = {
  358 + .get = rx8010sj_rtc_get,
  359 + .set = rx8010sj_rtc_set,
  360 + .read8 = rx8010sj_rtc_read8,
  361 + .write8 = rx8010sj_rtc_write8,
  362 + .reset = rx8010sj_rtc_reset,
  363 +};
  364 +
  365 +static const struct udevice_id rx8010sj_rtc_ids[] = {
  366 + { .compatible = "epson,rx8010sj-rtc" },
  367 + { }
  368 +};
  369 +
  370 +U_BOOT_DRIVER(rx8010sj_rtc) = {
  371 + .name = "rx8010sj_rtc",
  372 + .id = UCLASS_RTC,
  373 + .probe = rx8010sj_probe,
  374 + .of_match = rx8010sj_rtc_ids,
  375 + .ops = &rx8010sj_rtc_ops,
  376 +};
  377 +
  378 +#endif