diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/block/blk-uclass.c | 14 | ||||
-rw-r--r-- | drivers/core/regmap.c | 42 | ||||
-rw-r--r-- | drivers/i2c/Kconfig | 2 | ||||
-rw-r--r-- | drivers/mmc/Kconfig | 9 | ||||
-rw-r--r-- | drivers/mmc/Makefile | 2 | ||||
-rw-r--r-- | drivers/mmc/am654_sdhci.c | 333 | ||||
-rw-r--r-- | drivers/mmc/k3_arsan_sdhci.c | 109 | ||||
-rw-r--r-- | drivers/mmc/sdhci.c | 50 | ||||
-rw-r--r-- | drivers/mmc/xenon_sdhci.c | 4 | ||||
-rw-r--r-- | drivers/mmc/zynq_sdhci.c | 45 | ||||
-rw-r--r-- | drivers/pci_endpoint/sandbox-pci_ep.c | 5 | ||||
-rw-r--r-- | drivers/power/regulator/Kconfig | 12 | ||||
-rw-r--r-- | drivers/power/regulator/Makefile | 1 | ||||
-rw-r--r-- | drivers/power/regulator/fixed.c | 75 | ||||
-rw-r--r-- | drivers/power/regulator/gpio-regulator.c | 18 | ||||
-rw-r--r-- | drivers/power/regulator/regulator_common.c | 80 | ||||
-rw-r--r-- | drivers/power/regulator/regulator_common.h | 27 | ||||
-rw-r--r-- | drivers/rtc/ds3231.c | 107 |
18 files changed, 702 insertions, 233 deletions
diff --git a/drivers/block/blk-uclass.c b/drivers/block/blk-uclass.c index baaf431e5e..c23b6682a6 100644 --- a/drivers/block/blk-uclass.c +++ b/drivers/block/blk-uclass.c @@ -208,7 +208,11 @@ int blk_select_hwpart_devnum(enum if_type if_type, int devnum, int hwpart) if (ret) return ret; - return blk_select_hwpart(dev, hwpart); + ret = blk_select_hwpart(dev, hwpart); + if (!ret) + blkcache_invalidate(if_type, devnum); + + return ret; } int blk_list_part(enum if_type if_type) @@ -348,7 +352,13 @@ int blk_select_hwpart(struct udevice *dev, int hwpart) int blk_dselect_hwpart(struct blk_desc *desc, int hwpart) { - return blk_select_hwpart(desc->bdev, hwpart); + int ret; + + ret = blk_select_hwpart(desc->bdev, hwpart); + if (!ret) + blkcache_invalidate(desc->if_type, desc->devnum); + + return ret; } int blk_first_device(int if_type, struct udevice **devp) diff --git a/drivers/core/regmap.c b/drivers/core/regmap.c index 5ef0f71c8b..d1d12eef38 100644 --- a/drivers/core/regmap.c +++ b/drivers/core/regmap.c @@ -108,6 +108,48 @@ static int init_range(ofnode node, struct regmap_range *range, int addr_len, return 0; } +int regmap_init_mem_index(ofnode node, struct regmap **mapp, int index) +{ + struct regmap *map; + int addr_len, size_len; + int ret; + + addr_len = ofnode_read_simple_addr_cells(ofnode_get_parent(node)); + if (addr_len < 0) { + debug("%s: Error while reading the addr length (ret = %d)\n", + ofnode_get_name(node), addr_len); + return addr_len; + } + + size_len = ofnode_read_simple_size_cells(ofnode_get_parent(node)); + if (size_len < 0) { + debug("%s: Error while reading the size length: (ret = %d)\n", + ofnode_get_name(node), size_len); + return size_len; + } + + map = regmap_alloc(1); + if (!map) + return -ENOMEM; + + ret = init_range(node, map->ranges, addr_len, size_len, index); + if (ret) + return ret; + + if (ofnode_read_bool(node, "little-endian")) + map->endianness = REGMAP_LITTLE_ENDIAN; + else if (ofnode_read_bool(node, "big-endian")) + map->endianness = REGMAP_BIG_ENDIAN; + else if (ofnode_read_bool(node, "native-endian")) + map->endianness = REGMAP_NATIVE_ENDIAN; + else /* Default: native endianness */ + map->endianness = REGMAP_NATIVE_ENDIAN; + + *mapp = map; + + return ret; +} + int regmap_init_mem(ofnode node, struct regmap **mapp) { struct regmap_range *range; diff --git a/drivers/i2c/Kconfig b/drivers/i2c/Kconfig index 095a9bc6a4..4772db3837 100644 --- a/drivers/i2c/Kconfig +++ b/drivers/i2c/Kconfig @@ -330,7 +330,7 @@ endif config SYS_I2C_OMAP24XX bool "TI OMAP2+ I2C driver" - depends on ARCH_OMAP2PLUS + depends on ARCH_OMAP2PLUS || ARCH_K3 help Add support for the OMAP2+ I2C driver. diff --git a/drivers/mmc/Kconfig b/drivers/mmc/Kconfig index 890ef358a0..4cdae41b59 100644 --- a/drivers/mmc/Kconfig +++ b/drivers/mmc/Kconfig @@ -468,14 +468,15 @@ config MMC_SDHCI_CADENCE If unsure, say N. -config MMC_SDHCI_K3_ARASAN - bool "Arasan SDHCI controller for TI's K3 based SoCs" +config MMC_SDHCI_AM654 + bool "SDHCI Controller on TI's Am654 devices" depends on ARCH_K3 depends on MMC_SDHCI depends on DM_MMC && OF_CONTROL && BLK + depends on REGMAP help - Support for Arasan SDHCI host controller on Texas Instruments' - K3 family based SoC platforms + Support for Secure Digital Host Controller Interface (SDHCI) + controllers present on TI's AM654 SOCs. config MMC_SDHCI_KONA bool "SDHCI support on Broadcom KONA platform" diff --git a/drivers/mmc/Makefile b/drivers/mmc/Makefile index 3c8c53a9e1..6cc018bb67 100644 --- a/drivers/mmc/Makefile +++ b/drivers/mmc/Makefile @@ -50,7 +50,7 @@ obj-$(CONFIG_MMC_SDHCI_ATMEL) += atmel_sdhci.o obj-$(CONFIG_MMC_SDHCI_BCM2835) += bcm2835_sdhci.o obj-$(CONFIG_MMC_SDHCI_BCMSTB) += bcmstb_sdhci.o obj-$(CONFIG_MMC_SDHCI_CADENCE) += sdhci-cadence.o -obj-$(CONFIG_MMC_SDHCI_K3_ARASAN) += k3_arsan_sdhci.o +obj-$(CONFIG_MMC_SDHCI_AM654) += am654_sdhci.o obj-$(CONFIG_MMC_SDHCI_KONA) += kona_sdhci.o obj-$(CONFIG_MMC_SDHCI_MSM) += msm_sdhci.o obj-$(CONFIG_MMC_SDHCI_MV) += mv_sdhci.o diff --git a/drivers/mmc/am654_sdhci.c b/drivers/mmc/am654_sdhci.c new file mode 100644 index 0000000000..fb0fb58070 --- /dev/null +++ b/drivers/mmc/am654_sdhci.c @@ -0,0 +1,333 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2018 Texas Instruments Incorporated - http://www.ti.com/ + * + * Texas Instruments' K3 SD Host Controller Interface + */ + +#include <clk.h> +#include <common.h> +#include <dm.h> +#include <malloc.h> +#include <power-domain.h> +#include <regmap.h> +#include <sdhci.h> + +/* CTL_CFG Registers */ +#define CTL_CFG_2 0x14 + +#define SLOTTYPE_MASK GENMASK(31, 30) +#define SLOTTYPE_EMBEDDED BIT(30) + +/* PHY Registers */ +#define PHY_CTRL1 0x100 +#define PHY_CTRL2 0x104 +#define PHY_CTRL3 0x108 +#define PHY_CTRL4 0x10C +#define PHY_CTRL5 0x110 +#define PHY_CTRL6 0x114 +#define PHY_STAT1 0x130 +#define PHY_STAT2 0x134 + +#define IOMUX_ENABLE_SHIFT 31 +#define IOMUX_ENABLE_MASK BIT(IOMUX_ENABLE_SHIFT) +#define OTAPDLYENA_SHIFT 20 +#define OTAPDLYENA_MASK BIT(OTAPDLYENA_SHIFT) +#define OTAPDLYSEL_SHIFT 12 +#define OTAPDLYSEL_MASK GENMASK(15, 12) +#define STRBSEL_SHIFT 24 +#define STRBSEL_MASK GENMASK(27, 24) +#define SEL50_SHIFT 8 +#define SEL50_MASK BIT(SEL50_SHIFT) +#define SEL100_SHIFT 9 +#define SEL100_MASK BIT(SEL100_SHIFT) +#define DLL_TRIM_ICP_SHIFT 4 +#define DLL_TRIM_ICP_MASK GENMASK(7, 4) +#define DR_TY_SHIFT 20 +#define DR_TY_MASK GENMASK(22, 20) +#define ENDLL_SHIFT 1 +#define ENDLL_MASK BIT(ENDLL_SHIFT) +#define DLLRDY_SHIFT 0 +#define DLLRDY_MASK BIT(DLLRDY_SHIFT) +#define PDB_SHIFT 0 +#define PDB_MASK BIT(PDB_SHIFT) +#define CALDONE_SHIFT 1 +#define CALDONE_MASK BIT(CALDONE_SHIFT) +#define RETRIM_SHIFT 17 +#define RETRIM_MASK BIT(RETRIM_SHIFT) + +#define DRIVER_STRENGTH_50_OHM 0x0 +#define DRIVER_STRENGTH_33_OHM 0x1 +#define DRIVER_STRENGTH_66_OHM 0x2 +#define DRIVER_STRENGTH_100_OHM 0x3 +#define DRIVER_STRENGTH_40_OHM 0x4 + +#define AM654_SDHCI_MIN_FREQ 400000 + +struct am654_sdhci_plat { + struct mmc_config cfg; + struct mmc mmc; + struct regmap *base; + bool non_removable; + u32 otap_del_sel; + u32 trm_icp; + u32 drv_strength; + bool dll_on; +}; + +static void am654_sdhci_set_control_reg(struct sdhci_host *host) +{ + struct mmc *mmc = (struct mmc *)host->mmc; + u32 reg; + + if (IS_SD(host->mmc) && + mmc->signal_voltage == MMC_SIGNAL_VOLTAGE_180) { + reg = sdhci_readw(host, SDHCI_HOST_CONTROL2); + reg |= SDHCI_CTRL_VDD_180; + sdhci_writew(host, reg, SDHCI_HOST_CONTROL2); + } + + sdhci_set_uhs_timing(host); +} + +static int am654_sdhci_set_ios_post(struct sdhci_host *host) +{ + struct udevice *dev = host->mmc->dev; + struct am654_sdhci_plat *plat = dev_get_platdata(dev); + unsigned int speed = host->mmc->clock; + int sel50, sel100; + u32 mask, val; + int ret; + + /* Reset SD Clock Enable */ + val = sdhci_readw(host, SDHCI_CLOCK_CONTROL); + val &= ~SDHCI_CLOCK_CARD_EN; + sdhci_writew(host, val, SDHCI_CLOCK_CONTROL); + + /* power off phy */ + if (plat->dll_on) { + regmap_update_bits(plat->base, PHY_CTRL1, ENDLL_MASK, 0); + + plat->dll_on = false; + } + + /* restart clock */ + sdhci_set_clock(host->mmc, speed); + + /* switch phy back on */ + if (speed > AM654_SDHCI_MIN_FREQ) { + mask = OTAPDLYENA_MASK | OTAPDLYSEL_MASK; + val = (1 << OTAPDLYENA_SHIFT) | + (plat->otap_del_sel << OTAPDLYSEL_SHIFT); + regmap_update_bits(plat->base, PHY_CTRL4, mask, val); + switch (speed) { + case 200000000: + sel50 = 0; + sel100 = 0; + break; + case 100000000: + sel50 = 0; + sel100 = 1; + break; + default: + sel50 = 1; + sel100 = 0; + } + + /* Configure PHY DLL frequency */ + mask = SEL50_MASK | SEL100_MASK; + val = (sel50 << SEL50_SHIFT) | (sel100 << SEL100_SHIFT); + regmap_update_bits(plat->base, PHY_CTRL5, mask, val); + + /* Enable DLL */ + regmap_update_bits(plat->base, PHY_CTRL1, ENDLL_MASK, + 0x1 << ENDLL_SHIFT); + /* + * Poll for DLL ready. Use a one second timeout. + * Works in all experiments done so far + */ + ret = regmap_read_poll_timeout(plat->base, PHY_STAT1, val, + val & DLLRDY_MASK, 1000, 1000000); + if (ret) + return ret; + + plat->dll_on = true; + } + + return 0; +} + +const struct sdhci_ops am654_sdhci_ops = { + .set_ios_post = &am654_sdhci_set_ios_post, + .set_control_reg = &am654_sdhci_set_control_reg, +}; + +int am654_sdhci_init(struct am654_sdhci_plat *plat) +{ + u32 ctl_cfg_2 = 0; + u32 mask, val; + int ret; + + /* Reset OTAP to default value */ + mask = OTAPDLYENA_MASK | OTAPDLYSEL_MASK; + regmap_update_bits(plat->base, PHY_CTRL4, mask, 0x0); + + regmap_read(plat->base, PHY_STAT1, &val); + if (~val & CALDONE_MASK) { + /* Calibrate IO lines */ + regmap_update_bits(plat->base, PHY_CTRL1, PDB_MASK, PDB_MASK); + ret = regmap_read_poll_timeout(plat->base, PHY_STAT1, val, + val & CALDONE_MASK, 1, 20); + if (ret) + return ret; + } + + /* Configure DLL TRIM */ + mask = DLL_TRIM_ICP_MASK; + val = plat->trm_icp << DLL_TRIM_ICP_SHIFT; + + /* Configure DLL driver strength */ + mask |= DR_TY_MASK; + val |= plat->drv_strength << DR_TY_SHIFT; + regmap_update_bits(plat->base, PHY_CTRL1, mask, val); + + /* Enable pins by setting IO mux to 0 */ + regmap_update_bits(plat->base, PHY_CTRL1, IOMUX_ENABLE_MASK, 0); + + /* Set slot type based on SD or eMMC */ + if (plat->non_removable) + ctl_cfg_2 = SLOTTYPE_EMBEDDED; + + regmap_update_bits(plat->base, CTL_CFG_2, SLOTTYPE_MASK, ctl_cfg_2); + + return 0; +} + +static int am654_sdhci_probe(struct udevice *dev) +{ + struct am654_sdhci_plat *plat = dev_get_platdata(dev); + struct mmc_uclass_priv *upriv = dev_get_uclass_priv(dev); + struct sdhci_host *host = dev_get_priv(dev); + struct mmc_config *cfg = &plat->cfg; + struct power_domain sdhci_pwrdmn; + struct clk clk; + unsigned long clock; + int ret; + + ret = power_domain_get_by_index(dev, &sdhci_pwrdmn, 0); + if (!ret) { + ret = power_domain_on(&sdhci_pwrdmn); + if (ret) { + dev_err(dev, "Power domain on failed (%d)\n", ret); + return ret; + } + } else if (ret != -ENOENT && ret != -ENODEV && ret != -ENOSYS) { + dev_err(dev, "failed to get power domain (%d)\n", ret); + return ret; + } + + ret = clk_get_by_index(dev, 0, &clk); + if (ret) { + dev_err(dev, "failed to get clock\n"); + return ret; + } + + clock = clk_get_rate(&clk); + if (IS_ERR_VALUE(clock)) { + dev_err(dev, "failed to get rate\n"); + return clock; + } + + host->max_clk = clock; + host->mmc = &plat->mmc; + host->mmc->dev = dev; + ret = sdhci_setup_cfg(cfg, host, cfg->f_max, + AM654_SDHCI_MIN_FREQ); + if (ret) + return ret; + host->ops = &am654_sdhci_ops; + host->mmc->priv = host; + upriv->mmc = host->mmc; + + regmap_init_mem_index(dev_ofnode(dev), &plat->base, 1); + + am654_sdhci_init(plat); + + return sdhci_probe(dev); +} + +static int am654_sdhci_ofdata_to_platdata(struct udevice *dev) +{ + struct am654_sdhci_plat *plat = dev_get_platdata(dev); + struct sdhci_host *host = dev_get_priv(dev); + struct mmc_config *cfg = &plat->cfg; + u32 drv_strength; + int ret; + + host->name = dev->name; + host->ioaddr = (void *)dev_read_addr(dev); + plat->non_removable = dev_read_bool(dev, "non-removable"); + + ret = dev_read_u32(dev, "ti,trm-icp", &plat->trm_icp); + if (ret) + return ret; + + ret = dev_read_u32(dev, "ti,otap-del-sel", &plat->otap_del_sel); + if (ret) + return ret; + + ret = dev_read_u32(dev, "ti,driver-strength-ohm", &drv_strength); + if (ret) + return ret; + + switch (drv_strength) { + case 50: + plat->drv_strength = DRIVER_STRENGTH_50_OHM; + break; + case 33: + plat->drv_strength = DRIVER_STRENGTH_33_OHM; + break; + case 66: + plat->drv_strength = DRIVER_STRENGTH_66_OHM; + break; + case 100: + plat->drv_strength = DRIVER_STRENGTH_100_OHM; + break; + case 40: + plat->drv_strength = DRIVER_STRENGTH_40_OHM; + break; + default: + dev_err(dev, "Invalid driver strength\n"); + return -EINVAL; + } + + ret = mmc_of_parse(dev, cfg); + if (ret) + return ret; + + return 0; +} + +static int am654_sdhci_bind(struct udevice *dev) +{ + struct am654_sdhci_plat *plat = dev_get_platdata(dev); + + return sdhci_bind(dev, &plat->mmc, &plat->cfg); +} + +static const struct udevice_id am654_sdhci_ids[] = { + { .compatible = "ti,am654-sdhci-5.1" }, + { } +}; + +U_BOOT_DRIVER(am654_sdhci_drv) = { + .name = "am654_sdhci", + .id = UCLASS_MMC, + .of_match = am654_sdhci_ids, + .ofdata_to_platdata = am654_sdhci_ofdata_to_platdata, + .ops = &sdhci_ops, + .bind = am654_sdhci_bind, + .probe = am654_sdhci_probe, + .priv_auto_alloc_size = sizeof(struct sdhci_host), + .platdata_auto_alloc_size = sizeof(struct am654_sdhci_plat), +}; diff --git a/drivers/mmc/k3_arsan_sdhci.c b/drivers/mmc/k3_arsan_sdhci.c deleted file mode 100644 index d5f2857382..0000000000 --- a/drivers/mmc/k3_arsan_sdhci.c +++ /dev/null @@ -1,109 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -/* - * Copyright (C) 2018 Texas Instruments Incorporated - http://www.ti.com/ - * - * Texas Instruments' K3 SD Host Controller Interface - */ - -#include <clk.h> -#include <common.h> -#include <dm.h> -#include <malloc.h> -#include <power-domain.h> -#include <sdhci.h> - -#define K3_ARASAN_SDHCI_MIN_FREQ 0 - -struct k3_arasan_sdhci_plat { - struct mmc_config cfg; - struct mmc mmc; - unsigned int f_max; -}; - -static int k3_arasan_sdhci_probe(struct udevice *dev) -{ - struct k3_arasan_sdhci_plat *plat = dev_get_platdata(dev); - struct mmc_uclass_priv *upriv = dev_get_uclass_priv(dev); - struct sdhci_host *host = dev_get_priv(dev); - struct power_domain sdhci_pwrdmn; - struct clk clk; - unsigned long clock; - int ret; - - ret = power_domain_get_by_index(dev, &sdhci_pwrdmn, 0); - if (ret) { - dev_err(dev, "failed to get power domain\n"); - return ret; - } - - ret = power_domain_on(&sdhci_pwrdmn); - if (ret) { - dev_err(dev, "Power domain on failed\n"); - return ret; - } - - ret = clk_get_by_index(dev, 0, &clk); - if (ret) { - dev_err(dev, "failed to get clock\n"); - return ret; - } - - clock = clk_get_rate(&clk); - if (IS_ERR_VALUE(clock)) { - dev_err(dev, "failed to get rate\n"); - return clock; - } - - host->quirks = SDHCI_QUIRK_WAIT_SEND_CMD | - SDHCI_QUIRK_BROKEN_R1B; - - host->max_clk = clock; - - ret = sdhci_setup_cfg(&plat->cfg, host, plat->f_max, - K3_ARASAN_SDHCI_MIN_FREQ); - host->mmc = &plat->mmc; - if (ret) - return ret; - host->mmc->priv = host; - host->mmc->dev = dev; - upriv->mmc = host->mmc; - - return sdhci_probe(dev); -} - -static int k3_arasan_sdhci_ofdata_to_platdata(struct udevice *dev) -{ - struct k3_arasan_sdhci_plat *plat = dev_get_platdata(dev); - struct sdhci_host *host = dev_get_priv(dev); - - host->name = dev->name; - host->ioaddr = (void *)dev_read_addr(dev); - host->bus_width = dev_read_u32_default(dev, "bus-width", 4); - plat->f_max = dev_read_u32_default(dev, "max-frequency", 0); - - return 0; -} - -static int k3_arasan_sdhci_bind(struct udevice *dev) -{ - struct k3_arasan_sdhci_plat *plat = dev_get_platdata(dev); - - return sdhci_bind(dev, &plat->mmc, &plat->cfg); -} - -static const struct udevice_id k3_arasan_sdhci_ids[] = { - { .compatible = "arasan,sdhci-5.1" }, - { } -}; - -U_BOOT_DRIVER(k3_arasan_sdhci_drv) = { - .name = "k3_arasan_sdhci", - .id = UCLASS_MMC, - .of_match = k3_arasan_sdhci_ids, - .ofdata_to_platdata = k3_arasan_sdhci_ofdata_to_platdata, - .ops = &sdhci_ops, - .bind = k3_arasan_sdhci_bind, - .probe = k3_arasan_sdhci_probe, - .priv_auto_alloc_size = sizeof(struct sdhci_host), - .platdata_auto_alloc_size = sizeof(struct k3_arasan_sdhci_plat), -}; diff --git a/drivers/mmc/sdhci.c b/drivers/mmc/sdhci.c index c4e88790bc..0a0770cc20 100644 --- a/drivers/mmc/sdhci.c +++ b/drivers/mmc/sdhci.c @@ -8,6 +8,7 @@ */ #include <common.h> +#include <dm.h> #include <errno.h> #include <malloc.h> #include <mmc.h> @@ -409,7 +410,7 @@ static int sdhci_execute_tuning(struct udevice *dev, uint opcode) return 0; } #endif -static int sdhci_set_clock(struct mmc *mmc, unsigned int clock) +int sdhci_set_clock(struct mmc *mmc, unsigned int clock) { struct sdhci_host *host = mmc->priv; unsigned int div, clk = 0, timeout; @@ -533,6 +534,34 @@ static void sdhci_set_power(struct sdhci_host *host, unsigned short power) sdhci_writeb(host, pwr, SDHCI_POWER_CONTROL); } +void sdhci_set_uhs_timing(struct sdhci_host *host) +{ + struct mmc *mmc = (struct mmc *)host->mmc; + u32 reg; + + reg = sdhci_readw(host, SDHCI_HOST_CONTROL2); + reg &= ~SDHCI_CTRL_UHS_MASK; + + switch (mmc->selected_mode) { + case UHS_SDR50: + case MMC_HS_52: + reg |= SDHCI_CTRL_UHS_SDR50; + break; + case UHS_DDR50: + case MMC_DDR_52: + reg |= SDHCI_CTRL_UHS_DDR50; + break; + case UHS_SDR104: + case MMC_HS_200: + reg |= SDHCI_CTRL_UHS_SDR104; + break; + default: + reg |= SDHCI_CTRL_UHS_SDR12; + } + + sdhci_writew(host, reg, SDHCI_HOST_CONTROL2); +} + #ifdef CONFIG_DM_MMC static int sdhci_set_ios(struct udevice *dev) { @@ -583,7 +612,7 @@ static int sdhci_set_ios(struct mmc *mmc) /* If available, call the driver specific "post" set_ios() function */ if (host->ops && host->ops->set_ios_post) - host->ops->set_ios_post(host); + return host->ops->set_ios_post(host); return 0; } @@ -681,8 +710,18 @@ int sdhci_setup_cfg(struct mmc_config *cfg, struct sdhci_host *host, u32 f_max, u32 f_min) { u32 caps, caps_1 = 0; +#if CONFIG_IS_ENABLED(DM_MMC) + u32 mask[2] = {0}; + int ret; + ret = dev_read_u32_array(host->mmc->dev, "sdhci-caps-mask", + mask, 2); + if (ret && ret != -1) + return ret; + caps = ~mask[1] & sdhci_readl(host, SDHCI_CAPABILITIES); +#else caps = sdhci_readl(host, SDHCI_CAPABILITIES); +#endif #ifdef CONFIG_MMC_SDHCI_SDMA if (!(caps & SDHCI_CAN_DO_SDMA)) { @@ -722,7 +761,11 @@ int sdhci_setup_cfg(struct mmc_config *cfg, struct sdhci_host *host, /* Check whether the clock multiplier is supported or not */ if (SDHCI_GET_VERSION(host) >= SDHCI_SPEC_300) { +#if CONFIG_IS_ENABLED(DM_MMC) + caps_1 = ~mask[0] & sdhci_readl(host, SDHCI_CAPABILITIES_1); +#else caps_1 = sdhci_readl(host, SDHCI_CAPABILITIES_1); +#endif host->clk_mul = (caps_1 & SDHCI_CLOCK_MUL_MASK) >> SDHCI_CLOCK_MUL_SHIFT; } @@ -779,9 +822,6 @@ int sdhci_setup_cfg(struct mmc_config *cfg, struct sdhci_host *host, cfg->host_caps &= ~MMC_MODE_HS_52MHz; } - if (SDHCI_GET_VERSION(host) >= SDHCI_SPEC_300) - caps_1 = sdhci_readl(host, SDHCI_CAPABILITIES_1); - if (!(cfg->voltages & MMC_VDD_165_195) || (host->quirks & SDHCI_QUIRK_NO_1_8_V)) caps_1 &= ~(SDHCI_SUPPORT_SDR104 | SDHCI_SUPPORT_SDR50 | diff --git a/drivers/mmc/xenon_sdhci.c b/drivers/mmc/xenon_sdhci.c index b576511338..829b75683b 100644 --- a/drivers/mmc/xenon_sdhci.c +++ b/drivers/mmc/xenon_sdhci.c @@ -326,7 +326,7 @@ static void xenon_mask_cmd_conflict_err(struct sdhci_host *host) } /* Platform specific function for post set_ios configuration */ -static void xenon_sdhci_set_ios_post(struct sdhci_host *host) +static int xenon_sdhci_set_ios_post(struct sdhci_host *host) { struct xenon_sdhci_priv *priv = host->mmc->priv; uint speed = host->mmc->tran_speed; @@ -364,6 +364,8 @@ static void xenon_sdhci_set_ios_post(struct sdhci_host *host) /* Re-init the PHY */ xenon_mmc_phy_set(host); + + return 0; } /* Install a driver specific handler for post set_ios configuration */ diff --git a/drivers/mmc/zynq_sdhci.c b/drivers/mmc/zynq_sdhci.c index 08023783de..c525084250 100644 --- a/drivers/mmc/zynq_sdhci.c +++ b/drivers/mmc/zynq_sdhci.c @@ -48,11 +48,6 @@ static const u8 mode2timing[] = { [MMC_HS_200] = MMC_HS200_BUS_SPEED, }; -#define SDHCI_HOST_CTRL2 0x3E -#define SDHCI_CTRL2_MODE_MASK 0x7 -#define SDHCI_18V_SIGNAL 0x8 -#define SDHCI_CTRL_EXEC_TUNING 0x0040 -#define SDHCI_CTRL_TUNED_CLK 0x80 #define SDHCI_TUNING_LOOP_COUNT 40 static void arasan_zynqmp_dll_reset(struct sdhci_host *host, u8 deviceid) @@ -99,9 +94,9 @@ static int arasan_sdhci_execute_tuning(struct mmc *mmc, u8 opcode) host = priv->host; deviceid = priv->deviceid; - ctrl = sdhci_readw(host, SDHCI_HOST_CTRL2); + ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2); ctrl |= SDHCI_CTRL_EXEC_TUNING; - sdhci_writew(host, ctrl, SDHCI_HOST_CTRL2); + sdhci_writew(host, ctrl, SDHCI_HOST_CONTROL2); mdelay(1); @@ -133,7 +128,7 @@ static int arasan_sdhci_execute_tuning(struct mmc *mmc, u8 opcode) sdhci_writew(host, SDHCI_TRNS_READ, SDHCI_TRANSFER_MODE); mmc_send_cmd(mmc, &cmd, NULL); - ctrl = sdhci_readw(host, SDHCI_HOST_CTRL2); + ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2); if (cmd.cmdidx == MMC_CMD_SEND_TUNING_BLOCK) udelay(1); @@ -142,7 +137,7 @@ static int arasan_sdhci_execute_tuning(struct mmc *mmc, u8 opcode) if (tuning_loop_counter < 0) { ctrl &= ~SDHCI_CTRL_TUNED_CLK; - sdhci_writel(host, ctrl, SDHCI_HOST_CTRL2); + sdhci_writel(host, ctrl, SDHCI_HOST_CONTROL2); } if (!(ctrl & SDHCI_CTRL_TUNED_CLK)) { @@ -184,36 +179,14 @@ static void arasan_sdhci_set_control_reg(struct sdhci_host *host) return; if (mmc->signal_voltage == MMC_SIGNAL_VOLTAGE_180) { - reg = sdhci_readw(host, SDHCI_HOST_CTRL2); - reg |= SDHCI_18V_SIGNAL; - sdhci_writew(host, reg, SDHCI_HOST_CTRL2); + reg = sdhci_readw(host, SDHCI_HOST_CONTROL2); + reg |= SDHCI_CTRL_VDD_180; + sdhci_writew(host, reg, SDHCI_HOST_CONTROL2); } if (mmc->selected_mode > SD_HS && - mmc->selected_mode <= UHS_DDR50) { - reg = sdhci_readw(host, SDHCI_HOST_CTRL2); - reg &= ~SDHCI_CTRL2_MODE_MASK; - switch (mmc->selected_mode) { - case UHS_SDR12: - reg |= UHS_SDR12_BUS_SPEED; - break; - case UHS_SDR25: - reg |= UHS_SDR25_BUS_SPEED; - break; - case UHS_SDR50: - reg |= UHS_SDR50_BUS_SPEED; - break; - case UHS_SDR104: - reg |= UHS_SDR104_BUS_SPEED; - break; - case UHS_DDR50: - reg |= UHS_DDR50_BUS_SPEED; - break; - default: - break; - } - sdhci_writew(host, reg, SDHCI_HOST_CTRL2); - } + mmc->selected_mode <= UHS_DDR50) + sdhci_set_uhs_timing(host); } #endif diff --git a/drivers/pci_endpoint/sandbox-pci_ep.c b/drivers/pci_endpoint/sandbox-pci_ep.c index 0258433d8f..8e05d5ba89 100644 --- a/drivers/pci_endpoint/sandbox-pci_ep.c +++ b/drivers/pci_endpoint/sandbox-pci_ep.c @@ -83,14 +83,11 @@ static int sandbox_read_bar(struct udevice *dev, uint fn, struct pci_bar *ep_bar, enum pci_barno barno) { struct sandbox_pci_ep_priv *priv = dev_get_priv(dev); - int bar_idx; if (fn > 0) return -ENODEV; - bar_idx = ep_bar->barno; - - memcpy(ep_bar, &priv->bars[bar_idx], sizeof(*ep_bar)); + memcpy(ep_bar, &priv->bars[barno], sizeof(*ep_bar)); return 0; } diff --git a/drivers/power/regulator/Kconfig b/drivers/power/regulator/Kconfig index 147e68d5c9..337e9e7471 100644 --- a/drivers/power/regulator/Kconfig +++ b/drivers/power/regulator/Kconfig @@ -92,9 +92,18 @@ config DM_REGULATOR_FAN53555 or switching the mode is not supported by this driver (at this time). +config DM_REGULATOR_COMMON + bool + depends on DM_REGULATOR + +config SPL_DM_REGULATOR_COMMON + bool + depends on DM_REGULATOR + config DM_REGULATOR_FIXED bool "Enable Driver Model for REGULATOR Fixed value" depends on DM_REGULATOR + select DM_REGULATOR_COMMON ---help--- This config enables implementation of driver-model regulator uclass features for fixed value regulators. The driver implements get/set api @@ -103,6 +112,7 @@ config DM_REGULATOR_FIXED config SPL_DM_REGULATOR_FIXED bool "Enable Driver Model for REGULATOR Fixed value in SPL" depends on DM_REGULATOR_FIXED + select SPL_DM_REGULATOR_COMMON ---help--- This config enables implementation of driver-model regulator uclass features for fixed value regulators in SPL. @@ -110,6 +120,7 @@ config SPL_DM_REGULATOR_FIXED config DM_REGULATOR_GPIO bool "Enable Driver Model for GPIO REGULATOR" depends on DM_REGULATOR && DM_GPIO + select DM_REGULATOR_COMMON ---help--- This config enables implementation of driver-model regulator uclass features for gpio regulators. The driver implements get/set for @@ -118,6 +129,7 @@ config DM_REGULATOR_GPIO config SPL_DM_REGULATOR_GPIO bool "Enable Driver Model for GPIO REGULATOR in SPL" depends on DM_REGULATOR_GPIO && SPL_GPIO_SUPPORT + select SPL_DM_REGULATOR_COMMON ---help--- This config enables implementation of driver-model regulator uclass features for gpio regulators in SPL. diff --git a/drivers/power/regulator/Makefile b/drivers/power/regulator/Makefile index 8c1506c88e..e728b73aee 100644 --- a/drivers/power/regulator/Makefile +++ b/drivers/power/regulator/Makefile @@ -11,6 +11,7 @@ obj-$(CONFIG_DM_REGULATOR_MAX77686) += max77686.o obj-$(CONFIG_$(SPL_)DM_PMIC_PFUZE100) += pfuze100.o obj-$(CONFIG_$(SPL_)REGULATOR_PWM) += pwm_regulator.o obj-$(CONFIG_$(SPL_)DM_REGULATOR_FAN53555) += fan53555.o +obj-$(CONFIG_$(SPL_)DM_REGULATOR_COMMON) += regulator_common.o obj-$(CONFIG_$(SPL_)DM_REGULATOR_FIXED) += fixed.o obj-$(CONFIG_$(SPL_)DM_REGULATOR_GPIO) += gpio-regulator.o obj-$(CONFIG_REGULATOR_RK8XX) += rk8xx.o diff --git a/drivers/power/regulator/fixed.c b/drivers/power/regulator/fixed.c index a99aa78310..763e671d54 100644 --- a/drivers/power/regulator/fixed.c +++ b/drivers/power/regulator/fixed.c @@ -5,56 +5,26 @@ * Przemyslaw Marczak <p.marczak@samsung.com> */ +#include "regulator_common.h" #include <common.h> #include <errno.h> #include <dm.h> -#include <i2c.h> -#include <asm/gpio.h> #include <power/pmic.h> #include <power/regulator.h> -struct fixed_regulator_platdata { - struct gpio_desc gpio; /* GPIO for regulator enable control */ - unsigned int startup_delay_us; - unsigned int off_on_delay_us; -}; - static int fixed_regulator_ofdata_to_platdata(struct udevice *dev) { struct dm_regulator_uclass_platdata *uc_pdata; - struct fixed_regulator_platdata *dev_pdata; - struct gpio_desc *gpio; - int flags = GPIOD_IS_OUT; - int ret; + struct regulator_common_platdata *dev_pdata; dev_pdata = dev_get_platdata(dev); uc_pdata = dev_get_uclass_platdata(dev); if (!uc_pdata) return -ENXIO; - /* Set type to fixed */ uc_pdata->type = REGULATOR_TYPE_FIXED; - if (dev_read_bool(dev, "enable-active-high")) - flags |= GPIOD_IS_OUT_ACTIVE; - - /* Get fixed regulator optional enable GPIO desc */ - gpio = &dev_pdata->gpio; - ret = gpio_request_by_name(dev, "gpio", 0, gpio, flags); - if (ret) { - debug("Fixed regulator optional enable GPIO - not found! Error: %d\n", - ret); - if (ret != -ENOENT) - return ret; - } - - /* Get optional ramp up delay */ - dev_pdata->startup_delay_us = dev_read_u32_default(dev, - "startup-delay-us", 0); - dev_pdata->off_on_delay_us = - dev_read_u32_default(dev, "u-boot,off-on-delay-us", 0); - - return 0; + return regulator_common_ofdata_to_platdata(dev, dev_pdata, "gpio"); } static int fixed_regulator_get_value(struct udevice *dev) @@ -91,45 +61,12 @@ static int fixed_regulator_get_current(struct udevice *dev) static int fixed_regulator_get_enable(struct udevice *dev) { - struct fixed_regulator_platdata *dev_pdata = dev_get_platdata(dev); - - /* Enable GPIO is optional */ - if (!dev_pdata->gpio.dev) - return true; - - return dm_gpio_get_value(&dev_pdata->gpio); + return regulator_common_get_enable(dev, dev_get_platdata(dev)); } static int fixed_regulator_set_enable(struct udevice *dev, bool enable) { - struct fixed_regulator_platdata *dev_pdata = dev_get_platdata(dev); - int ret; - - debug("%s: dev='%s', enable=%d, delay=%d, has_gpio=%d\n", __func__, - dev->name, enable, dev_pdata->startup_delay_us, - dm_gpio_is_valid(&dev_pdata->gpio)); - /* Enable GPIO is optional */ - if (!dm_gpio_is_valid(&dev_pdata->gpio)) { - if (!enable) - return -ENOSYS; - return 0; - } - - ret = dm_gpio_set_value(&dev_pdata->gpio, enable); - if (ret) { - pr_err("Can't set regulator : %s gpio to: %d\n", dev->name, - enable); - return ret; - } - - if (enable && dev_pdata->startup_delay_us) - udelay(dev_pdata->startup_delay_us); - debug("%s: done\n", __func__); - - if (!enable && dev_pdata->off_on_delay_us) - udelay(dev_pdata->off_on_delay_us); - - return 0; + return regulator_common_set_enable(dev, dev_get_platdata(dev), enable); } static const struct dm_regulator_ops fixed_regulator_ops = { @@ -150,5 +87,5 @@ U_BOOT_DRIVER(fixed_regulator) = { .ops = &fixed_regulator_ops, .of_match = fixed_regulator_ids, .ofdata_to_platdata = fixed_regulator_ofdata_to_platdata, - .platdata_auto_alloc_size = sizeof(struct fixed_regulator_platdata), + .platdata_auto_alloc_size = sizeof(struct regulator_common_platdata), }; diff --git a/drivers/power/regulator/gpio-regulator.c b/drivers/power/regulator/gpio-regulator.c index d18e5d8d2c..ec1dcb64b3 100644 --- a/drivers/power/regulator/gpio-regulator.c +++ b/drivers/power/regulator/gpio-regulator.c @@ -4,6 +4,7 @@ * Keerthy <j-keerthy@ti.com> */ +#include "regulator_common.h" #include <common.h> #include <fdtdec.h> #include <errno.h> @@ -18,6 +19,7 @@ DECLARE_GLOBAL_DATA_PTR; struct gpio_regulator_platdata { + struct regulator_common_platdata common; struct gpio_desc gpio; /* GPIO for regulator voltage control */ int states[GPIO_REGULATOR_MAX_STATES]; int voltages[GPIO_REGULATOR_MAX_STATES]; @@ -65,7 +67,7 @@ static int gpio_regulator_ofdata_to_platdata(struct udevice *dev) j++; } - return 0; + return regulator_common_ofdata_to_platdata(dev, &dev_pdata->common, "enable-gpios"); } static int gpio_regulator_get_value(struct udevice *dev) @@ -116,9 +118,23 @@ static int gpio_regulator_set_value(struct udevice *dev, int uV) return 0; } +static int gpio_regulator_get_enable(struct udevice *dev) +{ + struct gpio_regulator_platdata *dev_pdata = dev_get_platdata(dev); + return regulator_common_get_enable(dev, &dev_pdata->common); +} + +static int gpio_regulator_set_enable(struct udevice *dev, bool enable) +{ + struct gpio_regulator_platdata *dev_pdata = dev_get_platdata(dev); + return regulator_common_set_enable(dev, &dev_pdata->common, enable); +} + static const struct dm_regulator_ops gpio_regulator_ops = { .get_value = gpio_regulator_get_value, .set_value = gpio_regulator_set_value, + .get_enable = gpio_regulator_get_enable, + .set_enable = gpio_regulator_set_enable, }; static const struct udevice_id gpio_regulator_ids[] = { diff --git a/drivers/power/regulator/regulator_common.c b/drivers/power/regulator/regulator_common.c new file mode 100644 index 0000000000..3dabbe2a85 --- /dev/null +++ b/drivers/power/regulator/regulator_common.c @@ -0,0 +1,80 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2019 Disruptive Technologies Research AS + * Sven Schwermer <sven.svenschwermer@disruptive-technologies.com> + */ + +#include "regulator_common.h" +#include <common.h> +#include <power/regulator.h> + +int regulator_common_ofdata_to_platdata(struct udevice *dev, + struct regulator_common_platdata *dev_pdata, const char *enable_gpio_name) +{ + struct gpio_desc *gpio; + int flags = GPIOD_IS_OUT; + int ret; + + if (dev_read_bool(dev, "enable-active-high")) + flags |= GPIOD_IS_OUT_ACTIVE; + + /* Get optional enable GPIO desc */ + gpio = &dev_pdata->gpio; + ret = gpio_request_by_name(dev, enable_gpio_name, 0, gpio, flags); + if (ret) { + debug("Regulator '%s' optional enable GPIO - not found! Error: %d\n", + dev->name, ret); + if (ret != -ENOENT) + return ret; + } + + /* Get optional ramp up delay */ + dev_pdata->startup_delay_us = dev_read_u32_default(dev, + "startup-delay-us", 0); + dev_pdata->off_on_delay_us = + dev_read_u32_default(dev, "u-boot,off-on-delay-us", 0); + + return 0; +} + +int regulator_common_get_enable(const struct udevice *dev, + struct regulator_common_platdata *dev_pdata) +{ + /* Enable GPIO is optional */ + if (!dev_pdata->gpio.dev) + return true; + + return dm_gpio_get_value(&dev_pdata->gpio); +} + +int regulator_common_set_enable(const struct udevice *dev, + struct regulator_common_platdata *dev_pdata, bool enable) +{ + int ret; + + debug("%s: dev='%s', enable=%d, delay=%d, has_gpio=%d\n", __func__, + dev->name, enable, dev_pdata->startup_delay_us, + dm_gpio_is_valid(&dev_pdata->gpio)); + /* Enable GPIO is optional */ + if (!dm_gpio_is_valid(&dev_pdata->gpio)) { + if (!enable) + return -ENOSYS; + return 0; + } + + ret = dm_gpio_set_value(&dev_pdata->gpio, enable); + if (ret) { + pr_err("Can't set regulator : %s gpio to: %d\n", dev->name, + enable); + return ret; + } + + if (enable && dev_pdata->startup_delay_us) + udelay(dev_pdata->startup_delay_us); + debug("%s: done\n", __func__); + + if (!enable && dev_pdata->off_on_delay_us) + udelay(dev_pdata->off_on_delay_us); + + return 0; +} diff --git a/drivers/power/regulator/regulator_common.h b/drivers/power/regulator/regulator_common.h new file mode 100644 index 0000000000..18a525880a --- /dev/null +++ b/drivers/power/regulator/regulator_common.h @@ -0,0 +1,27 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2019 Disruptive Technologies Research AS + * Sven Schwermer <sven.svenschwermer@disruptive-technologies.com> + */ + +#ifndef _REGULATOR_COMMON_H +#define _REGULATOR_COMMON_H + +#include <common.h> +#include <asm/gpio.h> +#include <dm.h> + +struct regulator_common_platdata { + struct gpio_desc gpio; /* GPIO for regulator enable control */ + unsigned int startup_delay_us; + unsigned int off_on_delay_us; +}; + +int regulator_common_ofdata_to_platdata(struct udevice *dev, + struct regulator_common_platdata *dev_pdata, const char *enable_gpio_name); +int regulator_common_get_enable(const struct udevice *dev, + struct regulator_common_platdata *dev_pdata); +int regulator_common_set_enable(const struct udevice *dev, + struct regulator_common_platdata *dev_pdata, bool enable); + +#endif /* _REGULATOR_COMMON_H */ diff --git a/drivers/rtc/ds3231.c b/drivers/rtc/ds3231.c index 9352ff87a2..79b026af4b 100644 --- a/drivers/rtc/ds3231.c +++ b/drivers/rtc/ds3231.c @@ -2,6 +2,9 @@ /* * (C) Copyright 2006 * Markus Klotzbuecher, mk@denx.de + * + * (C) Copyright 2019 NXP + * Chuanhua Han <chuanhua.han@nxp.com> */ /* @@ -13,6 +16,7 @@ #include <common.h> #include <command.h> +#include <dm.h> #include <rtc.h> #include <i2c.h> @@ -50,6 +54,7 @@ #define RTC_STAT_BIT_EN32KHZ 0x8 /* Enable 32KHz Output */ +#if !CONFIG_IS_ENABLED(DM_RTC) static uchar rtc_read (uchar reg); static void rtc_write (uchar reg, uchar val); @@ -164,3 +169,105 @@ static void rtc_write (uchar reg, uchar val) { i2c_reg_write (CONFIG_SYS_I2C_RTC_ADDR, reg, val); } +#else +static int ds3231_rtc_get(struct udevice *dev, struct rtc_time *tmp) +{ + uchar sec, min, hour, mday, wday, mon_cent, year, status; + + status = dm_i2c_reg_read(dev, RTC_STAT_REG_ADDR); + sec = dm_i2c_reg_read(dev, RTC_SEC_REG_ADDR); + min = dm_i2c_reg_read(dev, RTC_MIN_REG_ADDR); + hour = dm_i2c_reg_read(dev, RTC_HR_REG_ADDR); + wday = dm_i2c_reg_read(dev, RTC_DAY_REG_ADDR); + mday = dm_i2c_reg_read(dev, RTC_DATE_REG_ADDR); + mon_cent = dm_i2c_reg_read(dev, RTC_MON_REG_ADDR); + year = dm_i2c_reg_read(dev, RTC_YR_REG_ADDR); + + if (status & RTC_STAT_BIT_OSF) { + printf("### Warning: RTC oscillator has stopped\n"); + /* clear the OSF flag */ + dm_i2c_reg_write(dev, RTC_STAT_REG_ADDR, + dm_i2c_reg_read(dev, RTC_STAT_REG_ADDR) + & ~RTC_STAT_BIT_OSF); + return -EINVAL; + } + + tmp->tm_sec = bcd2bin(sec & 0x7F); + tmp->tm_min = bcd2bin(min & 0x7F); + tmp->tm_hour = bcd2bin(hour & 0x3F); + tmp->tm_mday = bcd2bin(mday & 0x3F); + tmp->tm_mon = bcd2bin(mon_cent & 0x1F); + tmp->tm_year = bcd2bin(year) + ((mon_cent & 0x80) ? 2000 : 1900); + tmp->tm_wday = bcd2bin((wday - 1) & 0x07); + tmp->tm_yday = 0; + tmp->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); + + return 0; +} + +static int ds3231_rtc_set(struct udevice *dev, const struct rtc_time *tmp) +{ + uchar century; + + 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); + + dm_i2c_reg_write(dev, RTC_YR_REG_ADDR, bin2bcd(tmp->tm_year % 100)); + + century = (tmp->tm_year >= 2000) ? 0x80 : 0; + dm_i2c_reg_write(dev, RTC_MON_REG_ADDR, bin2bcd(tmp->tm_mon) | century); + + dm_i2c_reg_write(dev, RTC_DAY_REG_ADDR, bin2bcd(tmp->tm_wday + 1)); + dm_i2c_reg_write(dev, RTC_DATE_REG_ADDR, bin2bcd(tmp->tm_mday)); + dm_i2c_reg_write(dev, RTC_HR_REG_ADDR, bin2bcd(tmp->tm_hour)); + dm_i2c_reg_write(dev, RTC_MIN_REG_ADDR, bin2bcd(tmp->tm_min)); + dm_i2c_reg_write(dev, RTC_SEC_REG_ADDR, bin2bcd(tmp->tm_sec)); + + return 0; +} + +static int ds3231_rtc_reset(struct udevice *dev) +{ + int ret; + + ret = dm_i2c_reg_write(dev, RTC_CTL_REG_ADDR, + RTC_CTL_BIT_RS1 | RTC_CTL_BIT_RS2); + if (ret < 0) + return ret; + + return 0; +} + +static int ds3231_probe(struct udevice *dev) +{ + i2c_set_chip_flags(dev, DM_I2C_CHIP_RD_ADDRESS | + DM_I2C_CHIP_WR_ADDRESS); + + return 0; +} + +static const struct rtc_ops ds3231_rtc_ops = { + .get = ds3231_rtc_get, + .set = ds3231_rtc_set, + .reset = ds3231_rtc_reset, +}; + +static const struct udevice_id ds3231_rtc_ids[] = { + { .compatible = "dallas,ds3231" }, + { .compatible = "dallas,ds3232" }, + { } +}; + +U_BOOT_DRIVER(rtc_ds3231) = { + .name = "rtc-ds3231", + .id = UCLASS_RTC, + .probe = ds3231_probe, + .of_match = ds3231_rtc_ids, + .ops = &ds3231_rtc_ops, +}; +#endif |