summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/block/blk-uclass.c14
-rw-r--r--drivers/core/regmap.c42
-rw-r--r--drivers/i2c/Kconfig2
-rw-r--r--drivers/mmc/Kconfig9
-rw-r--r--drivers/mmc/Makefile2
-rw-r--r--drivers/mmc/am654_sdhci.c333
-rw-r--r--drivers/mmc/k3_arsan_sdhci.c109
-rw-r--r--drivers/mmc/sdhci.c50
-rw-r--r--drivers/mmc/xenon_sdhci.c4
-rw-r--r--drivers/mmc/zynq_sdhci.c45
-rw-r--r--drivers/pci_endpoint/sandbox-pci_ep.c5
-rw-r--r--drivers/power/regulator/Kconfig12
-rw-r--r--drivers/power/regulator/Makefile1
-rw-r--r--drivers/power/regulator/fixed.c75
-rw-r--r--drivers/power/regulator/gpio-regulator.c18
-rw-r--r--drivers/power/regulator/regulator_common.c80
-rw-r--r--drivers/power/regulator/regulator_common.h27
-rw-r--r--drivers/rtc/ds3231.c107
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