diff options
author | Tom Rini <trini@konsulko.com> | 2023-11-02 10:12:33 -0400 |
---|---|---|
committer | Tom Rini <trini@konsulko.com> | 2023-11-02 10:12:33 -0400 |
commit | 07fe79c93c5caba181f37844ca95fbda4db3f613 (patch) | |
tree | 9766b3de49837bae1d4ea6c6b69fc33710333fd2 /drivers/bootcount/bootcount_dm_i2c.c | |
parent | b0c391ce0c01064a96711965e22f5d745e73edc3 (diff) | |
parent | 5b6ee512ceb8d990e010646c4fe7b8a3633fad68 (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.c | 102 |
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, +}; |