diff options
author | Tom Rini | 2018-12-01 14:17:27 -0500 |
---|---|---|
committer | Tom Rini | 2018-12-01 14:17:27 -0500 |
commit | c1d6e0bbfdb50f9041a42bd4ce3af809a09ff7d1 (patch) | |
tree | 052ddae11bfb52b2355e8a933906ee3ade41036a /drivers/rtc | |
parent | 172e3c11901229f0fb88317ac73a47d944a74f46 (diff) | |
parent | 17e5f3a4265cf372c4e09d7d3fd09fa54ef413cb (diff) |
Merge tag 'for-master-20181130' of git://git.denx.de/u-boot-rockchip
Improvements:
- RK3188 USB-UART functionality
- errors triggering a hard-stop in SPL on the RK3399 are reported
- Rockchip RV1108 (SoC) support
- MicroCrystal RV3029 (RTC) DM driver
Fixes:
- RK3188 early UART setup
- limit SD-card frequency to 40MHz on the RK3399-Q7
- MIPI fixes
- RK3399 CPUB clock initialisation
Diffstat (limited to 'drivers/rtc')
-rw-r--r-- | drivers/rtc/Kconfig | 10 | ||||
-rw-r--r-- | drivers/rtc/rv3029.c | 580 |
2 files changed, 453 insertions, 137 deletions
diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index bcc01b135e5..6038b43230d 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig @@ -60,6 +60,16 @@ config RTC_ISL1208 This driver supports reading and writing the RTC/calendar and detects total power failures. +config RTC_RV3029 + bool "Enable RV3029 driver" + depends on DM_RTC + help + The MicroCrystal RV3029 is a I2C Real Time Clock (RTC) with 8-byte + battery-backed SRAM. + + This driver supports reading and writing the RTC/calendar and the + battery-baced SRAM section. + config RTC_RX8010SJ bool "Enable RX8010SJ driver" depends on DM_RTC diff --git a/drivers/rtc/rv3029.c b/drivers/rtc/rv3029.c index dd4d0607a8f..38acb9c9924 100644 --- a/drivers/rtc/rv3029.c +++ b/drivers/rtc/rv3029.c @@ -1,189 +1,495 @@ // SPDX-License-Identifier: GPL-2.0+ /* - * (C) Copyright 2010 - * Heiko Schocher, DENX Software Engineering, hs@denx.de + * (C) Copyright 2018 Theobroma Systems Design und Consulting GmbH + * + * Based on a the Linux rtc-rv3029c2.c driver written by: + * Gregory Hermant <gregory.hermant@calao-systems.com> + * Michael Buesch <m@bues.ch> */ + #include <common.h> #include <command.h> +#include <dm.h> #include <i2c.h> #include <rtc.h> -#define RTC_RV3029_CTRL1 0x00 -#define RTC_RV3029_CTRL1_EERE (1 << 3) - -#define RTC_RV3029_CTRL_STATUS 0x03 -#define RTC_RV3029_CTRLS_EEBUSY (1 << 7) +#define RTC_RV3029_PAGE_LEN 7 -#define RTC_RV3029_CTRL_RESET 0x04 -#define RTC_RV3029_CTRL_SYS_R (1 << 4) +/* control section */ +#define RV3029_ONOFF_CTRL 0x00 +#define RV3029_ONOFF_CTRL_WE BIT(0) +#define RV3029_ONOFF_CTRL_TE BIT(1) +#define RV3029_ONOFF_CTRL_TAR BIT(2) +#define RV3029_ONOFF_CTRL_EERE BIT(3) +#define RV3029_ONOFF_CTRL_SRON BIT(4) +#define RV3029_ONOFF_CTRL_TD0 BIT(5) +#define RV3029_ONOFF_CTRL_TD1 BIT(6) +#define RV3029_ONOFF_CTRL_CLKINT BIT(7) +#define RV3029_IRQ_CTRL 0x01 +#define RV3029_IRQ_CTRL_AIE BIT(0) +#define RV3029_IRQ_CTRL_TIE BIT(1) +#define RV3029_IRQ_CTRL_V1IE BIT(2) +#define RV3029_IRQ_CTRL_V2IE BIT(3) +#define RV3029_IRQ_CTRL_SRIE BIT(4) +#define RV3029_IRQ_FLAGS 0x02 +#define RV3029_IRQ_FLAGS_AF BIT(0) +#define RV3029_IRQ_FLAGS_TF BIT(1) +#define RV3029_IRQ_FLAGS_V1IF BIT(2) +#define RV3029_IRQ_FLAGS_V2IF BIT(3) +#define RV3029_IRQ_FLAGS_SRF BIT(4) +#define RV3029_STATUS 0x03 +#define RV3029_STATUS_VLOW1 BIT(2) +#define RV3029_STATUS_VLOW2 BIT(3) +#define RV3029_STATUS_SR BIT(4) +#define RV3029_STATUS_PON BIT(5) +#define RV3029_STATUS_EEBUSY BIT(7) +#define RV3029_RST_CTRL 0x04 +#define RV3029_RST_CTRL_SYSR BIT(4) +#define RV3029_CONTROL_SECTION_LEN 0x05 -#define RTC_RV3029_CLOCK_PAGE 0x08 -#define RTC_RV3029_PAGE_LEN 7 +/* watch section */ +#define RV3029_W_SEC 0x08 +#define RV3029_W_MINUTES 0x09 +#define RV3029_W_HOURS 0x0A +#define RV3029_REG_HR_12_24 BIT(6) /* 24h/12h mode */ +#define RV3029_REG_HR_PM BIT(5) /* PM/AM bit in 12h mode */ +#define RV3029_W_DATE 0x0B +#define RV3029_W_DAYS 0x0C +#define RV3029_W_MONTHS 0x0D +#define RV3029_W_YEARS 0x0E -#define RV3029C2_W_SECONDS 0x00 -#define RV3029C2_W_MINUTES 0x01 -#define RV3029C2_W_HOURS 0x02 -#define RV3029C2_W_DATE 0x03 -#define RV3029C2_W_DAYS 0x04 -#define RV3029C2_W_MONTHS 0x05 -#define RV3029C2_W_YEARS 0x06 +/* eeprom control section */ +#define RV3029_CONTROL_E2P_EECTRL 0x30 +#define RV3029_TRICKLE_1K BIT(4) /* 1.5K resistance */ +#define RV3029_TRICKLE_5K BIT(5) /* 5K resistance */ +#define RV3029_TRICKLE_20K BIT(6) /* 20K resistance */ +#define RV3029_TRICKLE_80K BIT(7) /* 80K resistance */ +#define RV3029_TRICKLE_MASK (RV3029_TRICKLE_1K |\ + RV3029_TRICKLE_5K |\ + RV3029_TRICKLE_20K |\ + RV3029_TRICKLE_80K) +#define RV3029_TRICKLE_SHIFT 4 -#define RV3029C2_REG_HR_12_24 (1 << 6) /* 24h/12h mode */ -#define RV3029C2_REG_HR_PM (1 << 5) /* PM/AM bit in 12h mode */ -#define RTC_RV3029_EEPROM_CTRL 0x30 -#define RTC_RV3029_TRICKLE_1K (1 << 4) -#define RTC_RV3029_TRICKLE_5K (1 << 5) -#define RTC_RV3029_TRICKLE_20K (1 << 6) -#define RTC_RV3029_TRICKLE_80K (1 << 7) - -int rtc_get( struct rtc_time *tmp ) +static int rv3029_rtc_get(struct udevice *dev, struct rtc_time *tm) { - int ret; - unsigned char buf[RTC_RV3029_PAGE_LEN]; + u8 regs[RTC_RV3029_PAGE_LEN]; + int ret; - ret = i2c_read(CONFIG_SYS_I2C_RTC_ADDR, RTC_RV3029_CLOCK_PAGE, 1, buf, \ - RTC_RV3029_PAGE_LEN); - if (ret) { + ret = dm_i2c_read(dev, RV3029_W_SEC, regs, sizeof(regs)); + if (ret < 0) { printf("%s: error reading RTC: %x\n", __func__, ret); - return -1; + return -EIO; + } + + tm->tm_sec = bcd2bin(regs[RV3029_W_SEC - RV3029_W_SEC]); + tm->tm_min = bcd2bin(regs[RV3029_W_MINUTES - RV3029_W_SEC]); + + /* HR field has a more complex interpretation */ + { + const u8 _hr = regs[RV3029_W_HOURS - RV3029_W_SEC]; + + if (_hr & RV3029_REG_HR_12_24) { + /* 12h format */ + tm->tm_hour = bcd2bin(_hr & 0x1f); + if (_hr & RV3029_REG_HR_PM) /* PM flag set */ + tm->tm_hour += 12; + } else { + /* 24h format */ + tm->tm_hour = bcd2bin(_hr & 0x3f); + } } - tmp->tm_sec = bcd2bin( buf[RV3029C2_W_SECONDS] & 0x7f); - tmp->tm_min = bcd2bin( buf[RV3029C2_W_MINUTES] & 0x7f); - if (buf[RV3029C2_W_HOURS] & RV3029C2_REG_HR_12_24) { - /* 12h format */ - tmp->tm_hour = bcd2bin(buf[RV3029C2_W_HOURS] & 0x1f); - if (buf[RV3029C2_W_HOURS] & RV3029C2_REG_HR_PM) - /* PM flag set */ - tmp->tm_hour += 12; - } else - tmp->tm_hour = bcd2bin(buf[RV3029C2_W_HOURS] & 0x3f); - - tmp->tm_mday = bcd2bin( buf[RV3029C2_W_DATE] & 0x3F ); - tmp->tm_mon = bcd2bin( buf[RV3029C2_W_MONTHS] & 0x1F ); - tmp->tm_wday = bcd2bin( buf[RV3029C2_W_DAYS] & 0x07 ); + + tm->tm_mday = bcd2bin(regs[RV3029_W_DATE - RV3029_W_SEC]); + tm->tm_mon = bcd2bin(regs[RV3029_W_MONTHS - RV3029_W_SEC]) - 1; /* RTC supports only years > 1999 */ - tmp->tm_year = bcd2bin( buf[RV3029C2_W_YEARS]) + 2000; - tmp->tm_yday = 0; - tmp->tm_isdst = 0; + tm->tm_year = bcd2bin(regs[RV3029_W_YEARS - RV3029_W_SEC]) + 2000; + tm->tm_wday = bcd2bin(regs[RV3029_W_DAYS - RV3029_W_SEC]) - 1; + + tm->tm_yday = 0; + tm->tm_isdst = 0; - debug( "Get DATE: %4d-%02d-%02d (wday=%d) TIME: %2d:%02d:%02d\n", - tmp->tm_year, tmp->tm_mon, tmp->tm_mday, tmp->tm_wday, - tmp->tm_hour, tmp->tm_min, tmp->tm_sec ); + debug("%s: %4d-%02d-%02d (wday=%d) %2d:%02d:%02d\n", + __func__, tm->tm_year, tm->tm_mon, tm->tm_mday, + tm->tm_wday, tm->tm_hour, tm->tm_min, tm->tm_sec); return 0; } -int rtc_set( struct rtc_time *tmp ) +static int rv3029_rtc_set(struct udevice *dev, const struct rtc_time *tm) { - int ret; - unsigned char buf[RTC_RV3029_PAGE_LEN]; + u8 regs[RTC_RV3029_PAGE_LEN]; + + debug("%s: %4d-%02d-%02d (wday=%d( %2d:%02d:%02d\n", + __func__, tm->tm_year, tm->tm_mon, tm->tm_mday, + tm->tm_wday, tm->tm_hour, tm->tm_min, tm->tm_sec); - debug( "Set DATE: %4d-%02d-%02d (wday=%d) TIME: %2d:%02d:%02d\n", - tmp->tm_year, tmp->tm_mon, tmp->tm_mday, tmp->tm_wday, - tmp->tm_hour, tmp->tm_min, tmp->tm_sec); - if (tmp->tm_year < 2000) { - printf("RTC: year %d < 2000 not possible\n", tmp->tm_year); - return -1; + if (tm->tm_year < 2000) { + printf("%s: year %d (before 2000) not supported\n", + __func__, tm->tm_year); + return -EINVAL; } - buf[RV3029C2_W_SECONDS] = bin2bcd(tmp->tm_sec); - buf[RV3029C2_W_MINUTES] = bin2bcd(tmp->tm_min); - buf[RV3029C2_W_HOURS] = bin2bcd(tmp->tm_hour); - /* set 24h format */ - buf[RV3029C2_W_HOURS] &= ~RV3029C2_REG_HR_12_24; - buf[RV3029C2_W_DATE] = bin2bcd(tmp->tm_mday); - buf[RV3029C2_W_DAYS] = bin2bcd(tmp->tm_wday); - buf[RV3029C2_W_MONTHS] = bin2bcd(tmp->tm_mon); - tmp->tm_year -= 2000; - buf[RV3029C2_W_YEARS] = bin2bcd(tmp->tm_year); - ret = i2c_write(CONFIG_SYS_I2C_RTC_ADDR, RTC_RV3029_CLOCK_PAGE, 1, - buf, RTC_RV3029_PAGE_LEN); - - /* give the RTC some time to update */ - udelay(1000); - return ret; + + regs[RV3029_W_SEC - RV3029_W_SEC] = bin2bcd(tm->tm_sec); + regs[RV3029_W_MINUTES - RV3029_W_SEC] = bin2bcd(tm->tm_min); + regs[RV3029_W_HOURS - RV3029_W_SEC] = bin2bcd(tm->tm_hour); + regs[RV3029_W_DATE - RV3029_W_SEC] = bin2bcd(tm->tm_mday); + regs[RV3029_W_MONTHS - RV3029_W_SEC] = bin2bcd(tm->tm_mon + 1); + regs[RV3029_W_DAYS - RV3029_W_SEC] = bin2bcd(tm->tm_wday + 1) & 0x7; + regs[RV3029_W_YEARS - RV3029_W_SEC] = bin2bcd(tm->tm_year - 2000); + + return dm_i2c_write(dev, RV3029_W_SEC, regs, sizeof(regs)); } -/* sets EERE-Bit (automatic EEPROM refresh) */ -static void set_eere_bit(int state) +static int rv3029_rtc_reset(struct udevice *dev) { - unsigned char reg_ctrl1; + u8 ctrl = RV3029_RST_CTRL_SYSR; + unsigned long start; + const unsigned long timeout_ms = 10000; + int ret; - (void)i2c_read(CONFIG_SYS_I2C_RTC_ADDR, RTC_RV3029_CTRL1, 1, - ®_ctrl1, 1); + /* trigger the system-reset */ + ret = dm_i2c_write(dev, RV3029_RST_CTRL, &ctrl, 1); + if (ret < 0) + return -EIO; - if (state) - reg_ctrl1 |= RTC_RV3029_CTRL1_EERE; - else - reg_ctrl1 &= (~RTC_RV3029_CTRL1_EERE); + /* wait for the system-reset to complete */ + start = get_timer(0); + do { + if (get_timer(start) > timeout_ms) + return -ETIMEDOUT; - (void)i2c_write(CONFIG_SYS_I2C_RTC_ADDR, RTC_RV3029_CTRL1, 1, - ®_ctrl1, 1); + ret = dm_i2c_read(dev, RV3029_RST_CTRL, &ctrl, 1); + if (ret < 0) + return -EIO; + } while (ctrl & RV3029_RST_CTRL_SYSR); + + return 0; } -/* waits until EEPROM page is no longer busy (times out after 10ms*loops) */ -static int wait_eebusy(int loops) +static int rv3029_rtc_read8(struct udevice *dev, unsigned int reg) { - int i; - unsigned char ctrl_status; + u8 data; + int ret; + + ret = dm_i2c_read(dev, reg, &data, sizeof(data)); + return ret < 0 ? ret : data; +} - for (i = 0; i < loops; i++) { - (void)i2c_read(CONFIG_SYS_I2C_RTC_ADDR, RTC_RV3029_CTRL_STATUS, - 1, &ctrl_status, 1); +static int rv3029_rtc_write8(struct udevice *dev, unsigned int reg, int val) +{ + u8 data = val; + + return dm_i2c_write(dev, reg, &data, 1); +} + +#if defined(OF_CONTROL) +static int rv3029_get_sr(struct udevice *dev, u8 *buf) +{ + int ret = dm_i2c_read(dev, RV3029_STATUS, buf, 1); + + if (ret < 0) + return -EIO; + + dev_dbg(dev, "status = 0x%.2x (%d)\n", buf[0], buf[0]); + return 0; +} - if ((ctrl_status & RTC_RV3029_CTRLS_EEBUSY) == 0) +static int rv3029_set_sr(struct udevice *dev, u8 val) +{ + int ret; + + ret = dm_i2c_read(dev, RV3029_STATUS, &val, 1); + if (ret < 0) + return -EIO; + + dev_dbg(dev, "status = 0x%.2x (%d)\n", val, val); + return 0; +} + +static int rv3029_eeprom_busywait(struct udevice *dev) +{ + int i, ret; + u8 sr; + + for (i = 100; i > 0; i--) { + ret = rv3029_get_sr(dev, &sr); + if (ret < 0) + break; + if (!(sr & RV3029_STATUS_EEBUSY)) break; udelay(10000); } - return i; + if (i <= 0) { + dev_err(dev, "EEPROM busy wait timeout.\n"); + return -ETIMEDOUT; + } + + return ret; } -void rtc_reset (void) +static int rv3029_update_bits(struct udevice *dev, u8 reg, u8 mask, u8 set) { - unsigned char buf[RTC_RV3029_PAGE_LEN]; + u8 buf; + int ret; - buf[0] = RTC_RV3029_CTRL_SYS_R; - (void)i2c_write(CONFIG_SYS_I2C_RTC_ADDR, RTC_RV3029_CTRL_RESET, 1, - buf, 1); + ret = dm_i2c_read(dev, reg, &buf, 1); + if (ret < 0) + return ret; -#if defined(CONFIG_SYS_RV3029_TCR) - /* - * because EEPROM_CTRL register is in EEPROM page it is necessary to - * disable automatic EEPROM refresh and check if EEPROM is busy - * before EEPORM_CTRL register may be accessed - */ - set_eere_bit(0); - wait_eebusy(100); - /* read current trickle charger setting */ - (void)i2c_read(CONFIG_SYS_I2C_RTC_ADDR, RTC_RV3029_EEPROM_CTRL, - 1, buf, 1); - /* enable automatic EEPROM refresh again */ - set_eere_bit(1); + if ((buf & mask) == (set && mask)) + return 0; - /* - * to minimize EEPROM access write trickle charger setting only if it - * differs from current value - */ - if ((buf[0] & 0xF0) != CONFIG_SYS_RV3029_TCR) { - buf[0] = (buf[0] & 0x0F) | CONFIG_SYS_RV3029_TCR; - /* - * write trickle charger setting (disable autom. EEPROM - * refresh and wait until EEPROM is idle) - */ - set_eere_bit(0); - wait_eebusy(100); - (void)i2c_write(CONFIG_SYS_I2C_RTC_ADDR, - RTC_RV3029_EEPROM_CTRL, 1, buf, 1); - /* - * it is necessary to wait 10ms before EEBUSY-Bit may be read - * (this is not documented in the data sheet yet, but the - * manufacturer recommends it) + buf = (buf & ~mask) | (set & mask); + ret = dm_i2c_read(dev, reg, &buf, 1); + if (ret < 0) + return ret; + + return 0; +} + +static int rv3029_eeprom_exit(struct udevice *dev) +{ + /* Re-enable eeprom refresh */ + return rv3029_update_bits(dev, RV3029_ONOFF_CTRL, + RV3029_ONOFF_CTRL_EERE, + RV3029_ONOFF_CTRL_EERE); +} + +static int rv3029_eeprom_enter(struct udevice *dev) +{ + int ret; + u8 sr; + + /* Check whether we are in the allowed voltage range. */ + ret = rv3029_get_sr(dev, &sr); + if (ret < 0) + return ret; + if (sr & (RV3029_STATUS_VLOW1 | RV3029_STATUS_VLOW2)) { + /* We clear the bits and retry once just in case + * we had a brown out in early startup. */ + sr &= ~RV3029_STATUS_VLOW1; + sr &= ~RV3029_STATUS_VLOW2; + ret = rv3029_set_sr(dev, sr); + if (ret < 0) + return ret; udelay(10000); - /* wait until EEPROM write access is finished */ - wait_eebusy(100); - set_eere_bit(1); + ret = rv3029_get_sr(dev, &sr); + if (ret < 0) + return ret; + if (sr & (RV3029_STATUS_VLOW1 | RV3029_STATUS_VLOW2)) { + dev_err(dev, "Supply voltage is too low to safely access the EEPROM.\n"); + return -ENODEV; + } + } + + /* Disable eeprom refresh. */ + ret = rv3029_update_bits(dev, + RV3029_ONOFF_CTRL, RV3029_ONOFF_CTRL_EERE, 0); + if (ret < 0) + return ret; + + /* Wait for any previous eeprom accesses to finish. */ + ret = rv3029_eeprom_busywait(dev); + if (ret < 0) + rv3029_eeprom_exit(dev); + + return ret; +} + +static int rv3029_eeprom_read(struct udevice *dev, u8 reg, + u8 buf[], size_t len) +{ + int ret, err; + + err = rv3029_eeprom_enter(dev); + if (err < 0) + return err; + + ret = dm_i2c_read(dev, reg, buf, len); + + err = rv3029_eeprom_exit(dev); + if (err < 0) + return err; + + return ret; +} + +static int rv3029_eeprom_write(struct udevice *dev, u8 reg, + u8 const buf[], size_t len) +{ + int ret; + size_t i; + u8 tmp; + + ret = rv3029_eeprom_enter(dev); + if (ret < 0) + return ret; + + for (i = 0; i < len; i++, reg++) { + ret = dm_i2c_read(dev, reg, &tmp, 1); + if (ret < 0) + break; + if (tmp != buf[i]) { + ret = dm_i2c_write(dev, reg, &buf[i], 1); + if (ret < 0) + break; + } + ret = rv3029_eeprom_busywait(dev); + if (ret < 0) + break; } + + ret = rv3029_eeprom_exit(dev); + if (ret < 0) + return ret; + + return 0; +} + +static int rv3029_eeprom_update_bits(struct udevice *dev, + u8 reg, u8 mask, u8 set) +{ + u8 buf; + int ret; + + ret = rv3029_eeprom_read(dev, reg, &buf, 1); + if (ret < 0) + return ret; + + /* + * If the EEPROM already reads the correct bitpattern, we don't need + * to update it. + */ + if ((buf & mask) == (set & mask)) + return 0; + + buf = (buf & ~mask) | (set & mask); + ret = rv3029_eeprom_write(dev, reg, &buf, 1); + if (ret < 0) + return ret; + + return 0; +} + +static void rv3029_trickle_config(struct udevice *dev) +{ + static const struct rv3029_trickle_tab_elem { + u32 r; /* resistance in ohms */ + u8 conf; /* trickle config bits */ + } rv3029_trickle_tab[] = { + { + .r = 1076, + .conf = RV3029_TRICKLE_1K | RV3029_TRICKLE_5K | + RV3029_TRICKLE_20K | RV3029_TRICKLE_80K, + }, { + .r = 1091, + .conf = RV3029_TRICKLE_1K | RV3029_TRICKLE_5K | + RV3029_TRICKLE_20K, + }, { + .r = 1137, + .conf = RV3029_TRICKLE_1K | RV3029_TRICKLE_5K | + RV3029_TRICKLE_80K, + }, { + .r = 1154, + .conf = RV3029_TRICKLE_1K | RV3029_TRICKLE_5K, + }, { + .r = 1371, + .conf = RV3029_TRICKLE_1K | RV3029_TRICKLE_20K | + RV3029_TRICKLE_80K, + }, { + .r = 1395, + .conf = RV3029_TRICKLE_1K | RV3029_TRICKLE_20K, + }, { + .r = 1472, + .conf = RV3029_TRICKLE_1K | RV3029_TRICKLE_80K, + }, { + .r = 1500, + .conf = RV3029_TRICKLE_1K, + }, { + .r = 3810, + .conf = RV3029_TRICKLE_5K | RV3029_TRICKLE_20K | + RV3029_TRICKLE_80K, + }, { + .r = 4000, + .conf = RV3029_TRICKLE_5K | RV3029_TRICKLE_20K, + }, { + .r = 4706, + .conf = RV3029_TRICKLE_5K | RV3029_TRICKLE_80K, + }, { + .r = 5000, + .conf = RV3029_TRICKLE_5K, + }, { + .r = 16000, + .conf = RV3029_TRICKLE_20K | RV3029_TRICKLE_80K, + }, { + .r = 20000, + .conf = RV3029_TRICKLE_20K, + }, { + .r = 80000, + .conf = RV3029_TRICKLE_80K, + }, + }; + int err; + u32 ohms; + u8 trickle_set_bits = 0; + + /* Configure the trickle charger. */ + err = dev_read_u32(dev, "trickle-resistor-ohms", &ohms); + + if (!err) { + /* Find trickle-charger config */ + for (int i = 0; i < ARRAY_SIZE(rv3029_trickle_tab); i++) + if (rv3029_trickle_tab[i].r >= ohms) { + dev_dbg(dev, "trickle charger at %d ohms\n", + rv3029_trickle_tab[i].r); + trickle_set_bits = rv3029_trickle_tab[i].conf; + break; + } + } + + dev_dbg(dev, "trickle charger config 0x%x\n", trickle_set_bits); + err = rv3029_eeprom_update_bits(dev, RV3029_CONTROL_E2P_EECTRL, + RV3029_TRICKLE_MASK, + trickle_set_bits); + if (err < 0) + dev_dbg(dev, "failed to update trickle charger\n"); +} +#else +static inline void rv3029_trickle_config(struct udevice *dev) +{ +} #endif + +static int rv3029_probe(struct udevice *dev) +{ + i2c_set_chip_flags(dev, DM_I2C_CHIP_RD_ADDRESS | + DM_I2C_CHIP_WR_ADDRESS); + + rv3029_trickle_config(dev); + return 0; } + +static const struct rtc_ops rv3029_rtc_ops = { + .get = rv3029_rtc_get, + .set = rv3029_rtc_set, + .read8 = rv3029_rtc_read8, + .write8 = rv3029_rtc_write8, + .reset = rv3029_rtc_reset, +}; + +static const struct udevice_id rv3029_rtc_ids[] = { + { .compatible = "mc,rv3029" }, + { .compatible = "mc,rv3029c2" }, + { } +}; + +U_BOOT_DRIVER(rtc_rv3029) = { + .name = "rtc-rv3029", + .id = UCLASS_RTC, + .probe = rv3029_probe, + .of_match = rv3029_rtc_ids, + .ops = &rv3029_rtc_ops, +}; |