uboot/drivers/rtc/rv3029.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 * (C) Copyright 2018 Theobroma Systems Design und Consulting GmbH
   4 *
   5 * Based on a the Linux rtc-rv3029c2.c driver written by:
   6 *   Gregory Hermant <gregory.hermant@calao-systems.com>
   7 *   Michael Buesch <m@bues.ch>
   8 */
   9
  10#include <common.h>
  11#include <command.h>
  12#include <dm.h>
  13#include <i2c.h>
  14#include <rtc.h>
  15
  16#define RTC_RV3029_PAGE_LEN             7
  17
  18/* control section */
  19#define RV3029_ONOFF_CTRL               0x00
  20#define RV3029_ONOFF_CTRL_WE            BIT(0)
  21#define RV3029_ONOFF_CTRL_TE            BIT(1)
  22#define RV3029_ONOFF_CTRL_TAR           BIT(2)
  23#define RV3029_ONOFF_CTRL_EERE          BIT(3)
  24#define RV3029_ONOFF_CTRL_SRON          BIT(4)
  25#define RV3029_ONOFF_CTRL_TD0           BIT(5)
  26#define RV3029_ONOFF_CTRL_TD1           BIT(6)
  27#define RV3029_ONOFF_CTRL_CLKINT        BIT(7)
  28#define RV3029_IRQ_CTRL                 0x01
  29#define RV3029_IRQ_CTRL_AIE             BIT(0)
  30#define RV3029_IRQ_CTRL_TIE             BIT(1)
  31#define RV3029_IRQ_CTRL_V1IE            BIT(2)
  32#define RV3029_IRQ_CTRL_V2IE            BIT(3)
  33#define RV3029_IRQ_CTRL_SRIE            BIT(4)
  34#define RV3029_IRQ_FLAGS                0x02
  35#define RV3029_IRQ_FLAGS_AF             BIT(0)
  36#define RV3029_IRQ_FLAGS_TF             BIT(1)
  37#define RV3029_IRQ_FLAGS_V1IF           BIT(2)
  38#define RV3029_IRQ_FLAGS_V2IF           BIT(3)
  39#define RV3029_IRQ_FLAGS_SRF            BIT(4)
  40#define RV3029_STATUS                   0x03
  41#define RV3029_STATUS_VLOW1             BIT(2)
  42#define RV3029_STATUS_VLOW2             BIT(3)
  43#define RV3029_STATUS_SR                BIT(4)
  44#define RV3029_STATUS_PON               BIT(5)
  45#define RV3029_STATUS_EEBUSY            BIT(7)
  46#define RV3029_RST_CTRL                 0x04
  47#define RV3029_RST_CTRL_SYSR            BIT(4)
  48#define RV3029_CONTROL_SECTION_LEN      0x05
  49
  50/* watch section */
  51#define RV3029_W_SEC                    0x08
  52#define RV3029_W_MINUTES                0x09
  53#define RV3029_W_HOURS                  0x0A
  54#define RV3029_REG_HR_12_24             BIT(6) /* 24h/12h mode */
  55#define RV3029_REG_HR_PM                BIT(5) /* PM/AM bit in 12h mode */
  56#define RV3029_W_DATE                   0x0B
  57#define RV3029_W_DAYS                   0x0C
  58#define RV3029_W_MONTHS                 0x0D
  59#define RV3029_W_YEARS                  0x0E
  60
  61/* eeprom control section */
  62#define RV3029_CONTROL_E2P_EECTRL       0x30
  63#define RV3029_TRICKLE_1K               BIT(4) /* 1.5K resistance */
  64#define RV3029_TRICKLE_5K               BIT(5) /* 5K   resistance */
  65#define RV3029_TRICKLE_20K              BIT(6) /* 20K  resistance */
  66#define RV3029_TRICKLE_80K              BIT(7) /* 80K  resistance */
  67#define RV3029_TRICKLE_MASK             (RV3029_TRICKLE_1K |\
  68                                         RV3029_TRICKLE_5K |\
  69                                         RV3029_TRICKLE_20K |\
  70                                         RV3029_TRICKLE_80K)
  71#define RV3029_TRICKLE_SHIFT            4
  72
  73
  74static int rv3029_rtc_get(struct udevice *dev, struct rtc_time *tm)
  75{
  76        u8 regs[RTC_RV3029_PAGE_LEN];
  77        int ret;
  78
  79        ret = dm_i2c_read(dev, RV3029_W_SEC, regs, sizeof(regs));
  80        if (ret < 0) {
  81                printf("%s: error reading RTC: %x\n", __func__, ret);
  82                return -EIO;
  83        }
  84
  85        tm->tm_sec = bcd2bin(regs[RV3029_W_SEC - RV3029_W_SEC]);
  86        tm->tm_min = bcd2bin(regs[RV3029_W_MINUTES - RV3029_W_SEC]);
  87
  88        /* HR field has a more complex interpretation */
  89        {
  90                const u8 _hr = regs[RV3029_W_HOURS - RV3029_W_SEC];
  91
  92                if (_hr & RV3029_REG_HR_12_24) {
  93                        /* 12h format */
  94                        tm->tm_hour = bcd2bin(_hr & 0x1f);
  95                        if (_hr & RV3029_REG_HR_PM)     /* PM flag set */
  96                                tm->tm_hour += 12;
  97                } else {
  98                        /* 24h format */
  99                        tm->tm_hour = bcd2bin(_hr & 0x3f);
 100                }
 101        }
 102
 103        tm->tm_mday = bcd2bin(regs[RV3029_W_DATE - RV3029_W_SEC]);
 104        tm->tm_mon = bcd2bin(regs[RV3029_W_MONTHS - RV3029_W_SEC]) - 1;
 105        /* RTC supports only years > 1999 */
 106        tm->tm_year = bcd2bin(regs[RV3029_W_YEARS - RV3029_W_SEC]) + 2000;
 107        tm->tm_wday = bcd2bin(regs[RV3029_W_DAYS - RV3029_W_SEC]) - 1;
 108
 109        tm->tm_yday = 0;
 110        tm->tm_isdst = 0;
 111
 112        debug("%s: %4d-%02d-%02d (wday=%d) %2d:%02d:%02d\n",
 113              __func__, tm->tm_year, tm->tm_mon, tm->tm_mday,
 114              tm->tm_wday, tm->tm_hour, tm->tm_min, tm->tm_sec);
 115
 116        return 0;
 117}
 118
 119static int rv3029_rtc_set(struct udevice *dev, const struct rtc_time *tm)
 120{
 121        u8 regs[RTC_RV3029_PAGE_LEN];
 122
 123        debug("%s: %4d-%02d-%02d (wday=%d( %2d:%02d:%02d\n",
 124              __func__, tm->tm_year, tm->tm_mon, tm->tm_mday,
 125              tm->tm_wday, tm->tm_hour, tm->tm_min, tm->tm_sec);
 126
 127
 128        if (tm->tm_year < 2000) {
 129                printf("%s: year %d (before 2000) not supported\n",
 130                       __func__, tm->tm_year);
 131                return -EINVAL;
 132        }
 133
 134        regs[RV3029_W_SEC - RV3029_W_SEC] = bin2bcd(tm->tm_sec);
 135        regs[RV3029_W_MINUTES - RV3029_W_SEC] = bin2bcd(tm->tm_min);
 136        regs[RV3029_W_HOURS - RV3029_W_SEC] = bin2bcd(tm->tm_hour);
 137        regs[RV3029_W_DATE - RV3029_W_SEC] = bin2bcd(tm->tm_mday);
 138        regs[RV3029_W_MONTHS - RV3029_W_SEC] = bin2bcd(tm->tm_mon + 1);
 139        regs[RV3029_W_DAYS - RV3029_W_SEC] = bin2bcd(tm->tm_wday + 1) & 0x7;
 140        regs[RV3029_W_YEARS - RV3029_W_SEC] = bin2bcd(tm->tm_year - 2000);
 141
 142        return dm_i2c_write(dev, RV3029_W_SEC, regs, sizeof(regs));
 143}
 144
 145static int rv3029_rtc_reset(struct udevice *dev)
 146{
 147        u8 ctrl = RV3029_RST_CTRL_SYSR;
 148        unsigned long start;
 149        const unsigned long timeout_ms = 10000;
 150        int ret;
 151
 152        /* trigger the system-reset */
 153        ret = dm_i2c_write(dev, RV3029_RST_CTRL, &ctrl, 1);
 154        if (ret < 0)
 155                return -EIO;
 156
 157        /* wait for the system-reset to complete */
 158        start = get_timer(0);
 159        do {
 160                if (get_timer(start) > timeout_ms)
 161                        return -ETIMEDOUT;
 162
 163                ret = dm_i2c_read(dev, RV3029_RST_CTRL, &ctrl, 1);
 164                if (ret < 0)
 165                        return -EIO;
 166        } while (ctrl & RV3029_RST_CTRL_SYSR);
 167
 168        return 0;
 169}
 170
 171static int rv3029_rtc_read8(struct udevice *dev, unsigned int reg)
 172{
 173        u8 data;
 174        int ret;
 175
 176        ret = dm_i2c_read(dev, reg, &data, sizeof(data));
 177        return ret < 0 ? ret : data;
 178}
 179
 180static int rv3029_rtc_write8(struct udevice *dev, unsigned int reg, int val)
 181{
 182        u8 data = val;
 183
 184        return dm_i2c_write(dev, reg, &data, 1);
 185}
 186
 187#if defined(OF_CONTROL)
 188static int rv3029_get_sr(struct udevice *dev, u8 *buf)
 189{
 190        int ret = dm_i2c_read(dev, RV3029_STATUS, buf, 1);
 191
 192        if (ret < 0)
 193                return -EIO;
 194
 195        dev_dbg(dev, "status = 0x%.2x (%d)\n", buf[0], buf[0]);
 196        return 0;
 197}
 198
 199static int rv3029_set_sr(struct udevice *dev, u8 val)
 200{
 201        int ret;
 202
 203        ret = dm_i2c_read(dev, RV3029_STATUS, &val, 1);
 204        if (ret < 0)
 205                return -EIO;
 206
 207        dev_dbg(dev, "status = 0x%.2x (%d)\n", val, val);
 208        return 0;
 209}
 210
 211static int rv3029_eeprom_busywait(struct udevice *dev)
 212{
 213        int i, ret;
 214        u8 sr;
 215
 216        for (i = 100; i > 0; i--) {
 217                ret = rv3029_get_sr(dev, &sr);
 218                if (ret < 0)
 219                        break;
 220                if (!(sr & RV3029_STATUS_EEBUSY))
 221                        break;
 222                udelay(10000);
 223        }
 224        if (i <= 0) {
 225                dev_err(dev, "EEPROM busy wait timeout.\n");
 226                return -ETIMEDOUT;
 227        }
 228
 229        return ret;
 230}
 231
 232static int rv3029_update_bits(struct udevice *dev, u8 reg, u8 mask, u8 set)
 233{
 234        u8 buf;
 235        int ret;
 236
 237        ret = dm_i2c_read(dev, reg, &buf, 1);
 238        if (ret < 0)
 239                return ret;
 240
 241        if ((buf & mask) == (set && mask))
 242                return 0;
 243
 244        buf = (buf & ~mask) | (set & mask);
 245        ret = dm_i2c_read(dev, reg, &buf, 1);
 246        if (ret < 0)
 247                return ret;
 248
 249        return 0;
 250}
 251
 252static int rv3029_eeprom_exit(struct udevice *dev)
 253{
 254        /* Re-enable eeprom refresh */
 255        return rv3029_update_bits(dev, RV3029_ONOFF_CTRL,
 256                                  RV3029_ONOFF_CTRL_EERE,
 257                                  RV3029_ONOFF_CTRL_EERE);
 258}
 259
 260static int rv3029_eeprom_enter(struct udevice *dev)
 261{
 262        int ret;
 263        u8 sr;
 264
 265        /* Check whether we are in the allowed voltage range. */
 266        ret = rv3029_get_sr(dev, &sr);
 267        if (ret < 0)
 268                return ret;
 269        if (sr & (RV3029_STATUS_VLOW1 | RV3029_STATUS_VLOW2)) {
 270                /* We clear the bits and retry once just in case
 271                 * we had a brown out in early startup.
 272                 */
 273                sr &= ~RV3029_STATUS_VLOW1;
 274                sr &= ~RV3029_STATUS_VLOW2;
 275                ret = rv3029_set_sr(dev, sr);
 276                if (ret < 0)
 277                        return ret;
 278                udelay(10000);
 279                ret = rv3029_get_sr(dev, &sr);
 280                if (ret < 0)
 281                        return ret;
 282                if (sr & (RV3029_STATUS_VLOW1 | RV3029_STATUS_VLOW2)) {
 283                        dev_err(dev, "Supply voltage is too low to safely access the EEPROM.\n");
 284                        return -ENODEV;
 285                }
 286        }
 287
 288        /* Disable eeprom refresh. */
 289        ret = rv3029_update_bits(dev,
 290                                 RV3029_ONOFF_CTRL, RV3029_ONOFF_CTRL_EERE, 0);
 291        if (ret < 0)
 292                return ret;
 293
 294        /* Wait for any previous eeprom accesses to finish. */
 295        ret = rv3029_eeprom_busywait(dev);
 296        if (ret < 0)
 297                rv3029_eeprom_exit(dev);
 298
 299        return ret;
 300}
 301
 302static int rv3029_eeprom_read(struct udevice *dev, u8 reg,
 303                              u8 buf[], size_t len)
 304{
 305        int ret, err;
 306
 307        err = rv3029_eeprom_enter(dev);
 308        if (err < 0)
 309                return err;
 310
 311        ret = dm_i2c_read(dev, reg, buf, len);
 312
 313        err = rv3029_eeprom_exit(dev);
 314        if (err < 0)
 315                return err;
 316
 317        return ret;
 318}
 319
 320static int rv3029_eeprom_write(struct udevice *dev, u8 reg,
 321                               u8 const buf[], size_t len)
 322{
 323        int ret;
 324        size_t i;
 325        u8 tmp;
 326
 327        ret = rv3029_eeprom_enter(dev);
 328        if (ret < 0)
 329                return ret;
 330
 331        for (i = 0; i < len; i++, reg++) {
 332                ret = dm_i2c_read(dev, reg, &tmp, 1);
 333                if (ret < 0)
 334                        break;
 335                if (tmp != buf[i]) {
 336                        ret = dm_i2c_write(dev, reg, &buf[i], 1);
 337                        if (ret < 0)
 338                                break;
 339                }
 340                ret = rv3029_eeprom_busywait(dev);
 341                if (ret < 0)
 342                        break;
 343        }
 344
 345        ret = rv3029_eeprom_exit(dev);
 346        if (ret < 0)
 347                return ret;
 348
 349        return 0;
 350}
 351
 352static int rv3029_eeprom_update_bits(struct udevice *dev,
 353                                     u8 reg, u8 mask, u8 set)
 354{
 355        u8 buf;
 356        int ret;
 357
 358        ret = rv3029_eeprom_read(dev, reg, &buf, 1);
 359        if (ret < 0)
 360                return ret;
 361
 362        /*
 363         * If the EEPROM already reads the correct bitpattern, we don't need
 364         * to update it.
 365         */
 366        if ((buf & mask) == (set & mask))
 367                return 0;
 368
 369        buf = (buf & ~mask) | (set & mask);
 370        ret = rv3029_eeprom_write(dev, reg, &buf, 1);
 371        if (ret < 0)
 372                return ret;
 373
 374        return 0;
 375}
 376
 377static void rv3029_trickle_config(struct udevice *dev)
 378{
 379        static const struct rv3029_trickle_tab_elem {
 380                u32 r;          /* resistance in ohms */
 381                u8 conf;        /* trickle config bits */
 382        } rv3029_trickle_tab[] = {
 383                {
 384                        .r      = 1076,
 385                        .conf   = RV3029_TRICKLE_1K | RV3029_TRICKLE_5K |
 386                                  RV3029_TRICKLE_20K | RV3029_TRICKLE_80K,
 387                }, {
 388                        .r      = 1091,
 389                        .conf   = RV3029_TRICKLE_1K | RV3029_TRICKLE_5K |
 390                                  RV3029_TRICKLE_20K,
 391                }, {
 392                        .r      = 1137,
 393                        .conf   = RV3029_TRICKLE_1K | RV3029_TRICKLE_5K |
 394                                  RV3029_TRICKLE_80K,
 395                }, {
 396                        .r      = 1154,
 397                        .conf   = RV3029_TRICKLE_1K | RV3029_TRICKLE_5K,
 398                }, {
 399                        .r      = 1371,
 400                        .conf   = RV3029_TRICKLE_1K | RV3029_TRICKLE_20K |
 401                                  RV3029_TRICKLE_80K,
 402                }, {
 403                        .r      = 1395,
 404                        .conf   = RV3029_TRICKLE_1K | RV3029_TRICKLE_20K,
 405                }, {
 406                        .r      = 1472,
 407                        .conf   = RV3029_TRICKLE_1K | RV3029_TRICKLE_80K,
 408                }, {
 409                        .r      = 1500,
 410                        .conf   = RV3029_TRICKLE_1K,
 411                }, {
 412                        .r      = 3810,
 413                        .conf   = RV3029_TRICKLE_5K | RV3029_TRICKLE_20K |
 414                                  RV3029_TRICKLE_80K,
 415                }, {
 416                        .r      = 4000,
 417                        .conf   = RV3029_TRICKLE_5K | RV3029_TRICKLE_20K,
 418                }, {
 419                        .r      = 4706,
 420                        .conf   = RV3029_TRICKLE_5K | RV3029_TRICKLE_80K,
 421                }, {
 422                        .r      = 5000,
 423                        .conf   = RV3029_TRICKLE_5K,
 424                }, {
 425                        .r      = 16000,
 426                        .conf   = RV3029_TRICKLE_20K | RV3029_TRICKLE_80K,
 427                }, {
 428                        .r      = 20000,
 429                        .conf   = RV3029_TRICKLE_20K,
 430                }, {
 431                        .r      = 80000,
 432                        .conf   = RV3029_TRICKLE_80K,
 433                },
 434        };
 435        int err;
 436        u32 ohms;
 437        u8 trickle_set_bits = 0;
 438
 439        /* Configure the trickle charger. */
 440        err = dev_read_u32(dev, "trickle-resistor-ohms", &ohms);
 441
 442        if (!err) {
 443                /* Find trickle-charger config */
 444                for (int i = 0; i < ARRAY_SIZE(rv3029_trickle_tab); i++)
 445                        if (rv3029_trickle_tab[i].r >= ohms) {
 446                                dev_dbg(dev, "trickle charger at %d ohms\n",
 447                                        rv3029_trickle_tab[i].r);
 448                                trickle_set_bits = rv3029_trickle_tab[i].conf;
 449                                break;
 450                        }
 451        }
 452
 453        dev_dbg(dev, "trickle charger config 0x%x\n", trickle_set_bits);
 454        err = rv3029_eeprom_update_bits(dev, RV3029_CONTROL_E2P_EECTRL,
 455                                        RV3029_TRICKLE_MASK,
 456                                        trickle_set_bits);
 457        if (err < 0)
 458                dev_dbg(dev, "failed to update trickle charger\n");
 459}
 460#else
 461static inline void rv3029_trickle_config(struct udevice *dev)
 462{
 463}
 464#endif
 465
 466static int rv3029_probe(struct udevice *dev)
 467{
 468        i2c_set_chip_flags(dev, DM_I2C_CHIP_RD_ADDRESS |
 469                                DM_I2C_CHIP_WR_ADDRESS);
 470
 471        rv3029_trickle_config(dev);
 472        return 0;
 473}
 474
 475static const struct rtc_ops rv3029_rtc_ops = {
 476        .get = rv3029_rtc_get,
 477        .set = rv3029_rtc_set,
 478        .read8 = rv3029_rtc_read8,
 479        .write8 = rv3029_rtc_write8,
 480        .reset = rv3029_rtc_reset,
 481};
 482
 483static const struct udevice_id rv3029_rtc_ids[] = {
 484        { .compatible = "mc,rv3029" },
 485        { .compatible = "mc,rv3029c2" },
 486        { }
 487};
 488
 489U_BOOT_DRIVER(rtc_rv3029) = {
 490        .name   = "rtc-rv3029",
 491        .id     = UCLASS_RTC,
 492        .probe  = rv3029_probe,
 493        .of_match = rv3029_rtc_ids,
 494        .ops    = &rv3029_rtc_ops,
 495};
 496