diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/Kconfig | 2 | ||||
-rw-r--r-- | drivers/bootcount/Kconfig | 58 | ||||
-rw-r--r-- | drivers/bootcount/Makefile | 1 | ||||
-rw-r--r-- | drivers/bootcount/bootcount_ext.c | 62 | ||||
-rw-r--r-- | drivers/clk/rockchip/clk_rk3399.c | 8 | ||||
-rw-r--r-- | drivers/i2c/mxc_i2c.c | 25 | ||||
-rw-r--r-- | drivers/pinctrl/nxp/pinctrl-imx6.c | 7 | ||||
-rw-r--r-- | drivers/pinctrl/rockchip/pinctrl_rk3399.c | 19 | ||||
-rw-r--r-- | drivers/pwm/pwm-imx-util.c | 2 | ||||
-rw-r--r-- | drivers/rtc/Kconfig | 6 | ||||
-rw-r--r-- | drivers/rtc/Makefile | 1 | ||||
-rw-r--r-- | drivers/rtc/s35392a.c | 365 |
12 files changed, 539 insertions, 17 deletions
diff --git a/drivers/Kconfig b/drivers/Kconfig index 613e60235d..c2e813f5ad 100644 --- a/drivers/Kconfig +++ b/drivers/Kconfig @@ -10,6 +10,8 @@ source "drivers/ata/Kconfig" source "drivers/block/Kconfig" +source "drivers/bootcount/Kconfig" + source "drivers/clk/Kconfig" source "drivers/cpu/Kconfig" diff --git a/drivers/bootcount/Kconfig b/drivers/bootcount/Kconfig new file mode 100644 index 0000000000..c9d627cce2 --- /dev/null +++ b/drivers/bootcount/Kconfig @@ -0,0 +1,58 @@ +# +# Boot count configuration +# + +menu "Boot count support" + +config BOOTCOUNT + bool "Enable Boot count support" + help + Enable boot count support, which provides the ability to store the + number of times the board has booted on a number of different + persistent storage mediums. + +if BOOTCOUNT + +config BOOTCOUNT_EXT + bool "Boot counter on EXT filesystem" + help + Add support for maintaining boot count in a file on an EXT + filesystem. + +if BOOTCOUNT_EXT + +config SYS_BOOTCOUNT_EXT_INTERFACE + string "Interface on which to find boot counter EXT filesystem" + default "mmc" + depends on BOOTCOUNT_EXT + help + Set the interface to use when locating the filesystem to use for the + boot counter. + +config SYS_BOOTCOUNT_EXT_DEVPART + string "Partition of the boot counter EXT filesystem" + default "0:1" + depends on BOOTCOUNT_EXT + help + Set the partition to use when locating the filesystem to use for the + boot counter. + +config SYS_BOOTCOUNT_EXT_NAME + string "Path and filename of the EXT filesystem based boot counter" + default "/boot/failures" + depends on BOOTCOUNT_EXT + help + Set the filename and path of the file used to store the boot counter. + +config SYS_BOOTCOUNT_ADDR + hex "RAM address used for reading and writing the boot counter" + default 0x7000A000 + depends on BOOTCOUNT_EXT + help + Set the address used for reading and writing the boot counter. + +endif + +endif + +endmenu diff --git a/drivers/bootcount/Makefile b/drivers/bootcount/Makefile index ed9659ad97..45445d24bf 100644 --- a/drivers/bootcount/Makefile +++ b/drivers/bootcount/Makefile @@ -9,3 +9,4 @@ obj-$(CONFIG_BOOTCOUNT_AM33XX) += bootcount_davinci.o obj-$(CONFIG_BOOTCOUNT_RAM) += bootcount_ram.o obj-$(CONFIG_BOOTCOUNT_ENV) += bootcount_env.o obj-$(CONFIG_BOOTCOUNT_I2C) += bootcount_i2c.o +obj-$(CONFIG_BOOTCOUNT_EXT) += bootcount_ext.o diff --git a/drivers/bootcount/bootcount_ext.c b/drivers/bootcount/bootcount_ext.c new file mode 100644 index 0000000000..e0dd21ba6a --- /dev/null +++ b/drivers/bootcount/bootcount_ext.c @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2017 General Electric Company. All rights reserved. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <bootcount.h> +#include <fs.h> +#include <mapmem.h> + +#define BC_MAGIC 0xbc + +void bootcount_store(ulong a) +{ + u8 *buf; + loff_t len; + int ret; + + if (fs_set_blk_dev(CONFIG_SYS_BOOTCOUNT_EXT_INTERFACE, + CONFIG_SYS_BOOTCOUNT_EXT_DEVPART, FS_TYPE_EXT)) { + puts("Error selecting device\n"); + return; + } + + buf = map_sysmem(CONFIG_SYS_BOOTCOUNT_ADDR, 2); + buf[0] = BC_MAGIC; + buf[1] = (a & 0xff); + unmap_sysmem(buf); + + ret = fs_write(CONFIG_SYS_BOOTCOUNT_EXT_NAME, + CONFIG_SYS_BOOTCOUNT_ADDR, 0, 2, &len); + if (ret != 0) + puts("Error storing bootcount\n"); +} + +ulong bootcount_load(void) +{ + u8 *buf; + loff_t len_read; + int ret; + + if (fs_set_blk_dev(CONFIG_SYS_BOOTCOUNT_EXT_INTERFACE, + CONFIG_SYS_BOOTCOUNT_EXT_DEVPART, FS_TYPE_EXT)) { + puts("Error selecting device\n"); + return 0; + } + + ret = fs_read(CONFIG_SYS_BOOTCOUNT_EXT_NAME, CONFIG_SYS_BOOTCOUNT_ADDR, + 0, 2, &len_read); + if (ret != 0 || len_read != 2) { + puts("Error loading bootcount\n"); + return 0; + } + + buf = map_sysmem(CONFIG_SYS_BOOTCOUNT_ADDR, 2); + if (buf[0] == BC_MAGIC) + ret = buf[1]; + + unmap_sysmem(buf); + + return ret; +} diff --git a/drivers/clk/rockchip/clk_rk3399.c b/drivers/clk/rockchip/clk_rk3399.c index e21d056efb..2e85ac7df2 100644 --- a/drivers/clk/rockchip/clk_rk3399.c +++ b/drivers/clk/rockchip/clk_rk3399.c @@ -569,11 +569,6 @@ static const struct spi_clkreg spi_clkregs[] = { .sel_shift = CLK_SPI5_PLL_SEL_SHIFT, }, }; -static inline u32 extract_bits(u32 val, unsigned width, unsigned shift) -{ - return (val >> shift) & ((1 << width) - 1); -} - static ulong rk3399_spi_get_clk(struct rk3399_cru *cru, ulong clk_id) { const struct spi_clkreg *spiclk = NULL; @@ -590,7 +585,8 @@ static ulong rk3399_spi_get_clk(struct rk3399_cru *cru, ulong clk_id) } val = readl(&cru->clksel_con[spiclk->reg]); - div = extract_bits(val, CLK_SPI_PLL_DIV_CON_WIDTH, spiclk->div_shift); + div = bitfield_extract(val, spiclk->div_shift, + CLK_SPI_PLL_DIV_CON_WIDTH); return DIV_TO_RATE(GPLL_HZ, div); } diff --git a/drivers/i2c/mxc_i2c.c b/drivers/i2c/mxc_i2c.c index abf1da2ae3..205274e947 100644 --- a/drivers/i2c/mxc_i2c.c +++ b/drivers/i2c/mxc_i2c.c @@ -317,16 +317,19 @@ static int i2c_init_transfer_(struct mxc_i2c_bus *i2c_bus, u8 chip, temp |= I2CR_MTX | I2CR_TX_NO_AK; writeb(temp, base + (I2CR << reg_shift)); - /* write slave address */ - ret = tx_byte(i2c_bus, chip << 1); - if (ret < 0) - return ret; - - while (alen--) { - ret = tx_byte(i2c_bus, (addr >> (alen * 8)) & 0xff); + if (alen >= 0) { + /* write slave address */ + ret = tx_byte(i2c_bus, chip << 1); if (ret < 0) return ret; + + while (alen--) { + ret = tx_byte(i2c_bus, (addr >> (alen * 8)) & 0xff); + if (ret < 0) + return ret; + } } + return 0; } @@ -537,9 +540,11 @@ static int bus_i2c_read(struct mxc_i2c_bus *i2c_bus, u8 chip, u32 addr, if (ret < 0) return ret; - temp = readb(base + (I2CR << reg_shift)); - temp |= I2CR_RSTA; - writeb(temp, base + (I2CR << reg_shift)); + if (alen >= 0) { + temp = readb(base + (I2CR << reg_shift)); + temp |= I2CR_RSTA; + writeb(temp, base + (I2CR << reg_shift)); + } ret = tx_byte(i2c_bus, (chip << 1) | 1); if (ret < 0) { diff --git a/drivers/pinctrl/nxp/pinctrl-imx6.c b/drivers/pinctrl/nxp/pinctrl-imx6.c index 0f767d9079..cac577b40b 100644 --- a/drivers/pinctrl/nxp/pinctrl-imx6.c +++ b/drivers/pinctrl/nxp/pinctrl-imx6.c @@ -13,6 +13,11 @@ static struct imx_pinctrl_soc_info imx6_pinctrl_soc_info; +/* FIXME Before reloaction, BSS is overlapped with DT area */ +static struct imx_pinctrl_soc_info imx6ul_pinctrl_soc_info = { + .flags = ZERO_OFFSET_VALID, +}; + static struct imx_pinctrl_soc_info imx6_snvs_pinctrl_soc_info = { .flags = ZERO_OFFSET_VALID, }; @@ -32,7 +37,7 @@ static const struct udevice_id imx6_pinctrl_match[] = { { .compatible = "fsl,imx6sll-iomuxc-snvs", .data = (ulong)&imx6_snvs_pinctrl_soc_info }, { .compatible = "fsl,imx6sll-iomuxc", .data = (ulong)&imx6_pinctrl_soc_info }, { .compatible = "fsl,imx6sx-iomuxc", .data = (ulong)&imx6_pinctrl_soc_info }, - { .compatible = "fsl,imx6ul-iomuxc", .data = (ulong)&imx6_pinctrl_soc_info }, + { .compatible = "fsl,imx6ul-iomuxc", .data = (ulong)&imx6ul_pinctrl_soc_info }, { .compatible = "fsl,imx6ull-iomuxc-snvs", .data = (ulong)&imx6_snvs_pinctrl_soc_info }, { /* sentinel */ } }; diff --git a/drivers/pinctrl/rockchip/pinctrl_rk3399.c b/drivers/pinctrl/rockchip/pinctrl_rk3399.c index cab268c7d6..19a7415522 100644 --- a/drivers/pinctrl/rockchip/pinctrl_rk3399.c +++ b/drivers/pinctrl/rockchip/pinctrl_rk3399.c @@ -70,11 +70,21 @@ static void pinctrl_rk3399_i2c_config(struct rk3399_grf_regs *grf, PMUGRF_GPIO1C0_SEL_MASK, PMUGRF_I2C0PMU_SCL << PMUGRF_GPIO1C0_SEL_SHIFT); break; + case PERIPH_ID_I2C8: + rk_clrsetreg(&pmugrf->gpio1c_iomux, + PMUGRF_GPIO1C4_SEL_MASK, + PMUGRF_I2C8PMU_SDA << PMUGRF_GPIO1C4_SEL_SHIFT); + rk_clrsetreg(&pmugrf->gpio1c_iomux, + PMUGRF_GPIO1C5_SEL_MASK, + PMUGRF_I2C8PMU_SCL << PMUGRF_GPIO1C5_SEL_SHIFT); + break; case PERIPH_ID_I2C1: case PERIPH_ID_I2C2: case PERIPH_ID_I2C3: case PERIPH_ID_I2C4: case PERIPH_ID_I2C5: + case PERIPH_ID_I2C6: + case PERIPH_ID_I2C7: default: debug("i2c id = %d iomux error!\n", i2c_id); break; @@ -301,6 +311,9 @@ static int rk3399_pinctrl_request(struct udevice *dev, int func, int flags) case PERIPH_ID_I2C3: case PERIPH_ID_I2C4: case PERIPH_ID_I2C5: + case PERIPH_ID_I2C6: + case PERIPH_ID_I2C7: + case PERIPH_ID_I2C8: pinctrl_rk3399_i2c_config(priv->grf, priv->pmugrf, func); break; case PERIPH_ID_SPI0: @@ -375,6 +388,12 @@ static int rk3399_pinctrl_get_periph_id(struct udevice *dev, return PERIPH_ID_I2C4; case 38: return PERIPH_ID_I2C5; + case 37: + return PERIPH_ID_I2C6; + case 36: + return PERIPH_ID_I2C7; + case 58: + return PERIPH_ID_I2C8; case 65: return PERIPH_ID_SDMMC1; #if CONFIG_IS_ENABLED(GMAC_ROCKCHIP) diff --git a/drivers/pwm/pwm-imx-util.c b/drivers/pwm/pwm-imx-util.c index 534dd8eece..97ac0c8fc0 100644 --- a/drivers/pwm/pwm-imx-util.c +++ b/drivers/pwm/pwm-imx-util.c @@ -23,10 +23,12 @@ struct pwm_regs *pwm_id_to_reg(int pwm_id) return (struct pwm_regs *)PWM1_BASE_ADDR; case 1: return (struct pwm_regs *)PWM2_BASE_ADDR; +#ifdef CONFIG_MX6 case 2: return (struct pwm_regs *)PWM3_BASE_ADDR; case 3: return (struct pwm_regs *)PWM4_BASE_ADDR; +#endif #ifdef CONFIG_MX6SX case 4: return (struct pwm_regs *)PWM5_BASE_ADDR; diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index d06130c7a2..2964bb2211 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 003e31aeba..7a8f97a05f 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 0000000000..9adcefc98d --- /dev/null +++ b/drivers/rtc/s35392a.c @@ -0,0 +1,365 @@ +/* + * 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 <http://www.gnu.org/licenses/>. + * + * SPDX-License-Identifier: GPL-2.0 + */ + +#include <command.h> +#include <common.h> +#include <dm.h> +#include <i2c.h> +#include <linux/bitrev.h> +#include <rtc.h> + +#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; + +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; + + 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 int 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 |