aboutsummaryrefslogtreecommitdiff
path: root/drivers/bootcount/bootcount_dm_i2c.c
diff options
context:
space:
mode:
authorTom Rini <trini@konsulko.com>2023-11-02 10:12:33 -0400
committerTom Rini <trini@konsulko.com>2023-11-02 10:12:33 -0400
commit07fe79c93c5caba181f37844ca95fbda4db3f613 (patch)
tree9766b3de49837bae1d4ea6c6b69fc33710333fd2 /drivers/bootcount/bootcount_dm_i2c.c
parentb0c391ce0c01064a96711965e22f5d745e73edc3 (diff)
parent5b6ee512ceb8d990e010646c4fe7b8a3633fad68 (diff)
Merge tag 'i2cfixes-for-v2024-01-rc2' of https://source.denx.de/u-boot/custodians/u-boot-i2c
i2c updates for v2024.01-rc2 - nuvoton: support standard/fast/fast plus mode - bootcount: remove legacy i2c driver and implement DM based version Bugfixes: - designware_i2c: adjust timing calculation SPL probing failed on the StarFive VisionFive 2 board Heinrich fixed this, by syncing timing calculation with linux implementation.
Diffstat (limited to 'drivers/bootcount/bootcount_dm_i2c.c')
-rw-r--r--drivers/bootcount/bootcount_dm_i2c.c102
1 files changed, 102 insertions, 0 deletions
diff --git a/drivers/bootcount/bootcount_dm_i2c.c b/drivers/bootcount/bootcount_dm_i2c.c
new file mode 100644
index 0000000000..e27034cbeb
--- /dev/null
+++ b/drivers/bootcount/bootcount_dm_i2c.c
@@ -0,0 +1,102 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * (C) Copyright 2023
+ * Philip Richard Oberfichtner <pro@denx.de>
+ *
+ * Based on previous work from Heiko Schocher (legacy bootcount_i2c.c driver)
+ */
+
+#include <bootcount.h>
+#include <dm.h>
+#include <i2c.h>
+
+#define BC_MAGIC 0x55
+
+struct bootcount_i2c_priv {
+ struct udevice *bcdev;
+ unsigned int offset;
+};
+
+static int bootcount_i2c_set(struct udevice *dev, const u32 val)
+{
+ int ret;
+ struct bootcount_i2c_priv *priv = dev_get_priv(dev);
+
+ ret = dm_i2c_reg_write(priv->bcdev, priv->offset, BC_MAGIC);
+ if (ret < 0)
+ goto err_exit;
+
+ ret = dm_i2c_reg_write(priv->bcdev, priv->offset + 1, val & 0xff);
+ if (ret < 0)
+ goto err_exit;
+
+ return 0;
+
+err_exit:
+ log_debug("%s: Error writing to I2C device (%d)\n", __func__, ret);
+ return ret;
+}
+
+static int bootcount_i2c_get(struct udevice *dev, u32 *val)
+{
+ int ret;
+ struct bootcount_i2c_priv *priv = dev_get_priv(dev);
+
+ ret = dm_i2c_reg_read(priv->bcdev, priv->offset);
+ if (ret < 0)
+ goto err_exit;
+
+ if ((ret & 0xff) != BC_MAGIC) {
+ log_debug("%s: Invalid Magic, reset bootcounter.\n", __func__);
+ *val = 0;
+ return bootcount_i2c_set(dev, 0);
+ }
+
+ ret = dm_i2c_reg_read(priv->bcdev, priv->offset + 1);
+ if (ret < 0)
+ goto err_exit;
+
+ *val = ret;
+ return 0;
+
+err_exit:
+ log_debug("%s: Error reading from I2C device (%d)\n", __func__, ret);
+ return ret;
+}
+
+static int bootcount_i2c_probe(struct udevice *dev)
+{
+ struct bootcount_i2c_priv *priv = dev_get_priv(dev);
+ int ret;
+
+ ret = dev_read_u32(dev, "offset", &priv->offset);
+ if (ret)
+ goto exit;
+
+ ret = i2c_get_chip_by_phandle(dev, "i2cbcdev", &priv->bcdev);
+
+exit:
+ if (ret)
+ log_debug("%s failed, ret = %d\n", __func__, ret);
+
+ return ret;
+}
+
+static const struct bootcount_ops bootcount_i2c_ops = {
+ .get = bootcount_i2c_get,
+ .set = bootcount_i2c_set,
+};
+
+static const struct udevice_id bootcount_i2c_ids[] = {
+ { .compatible = "u-boot,bootcount-i2c" },
+ { }
+};
+
+U_BOOT_DRIVER(bootcount_i2c) = {
+ .name = "bootcount-i2c",
+ .id = UCLASS_BOOTCOUNT,
+ .priv_auto = sizeof(struct bootcount_i2c_priv),
+ .probe = bootcount_i2c_probe,
+ .of_match = bootcount_i2c_ids,
+ .ops = &bootcount_i2c_ops,
+};