[PATCH 2/2] bootcount: Add driver model I2C driver
Heiko Schocher
hs at denx.de
Fri Oct 13 13:28:47 CEST 2023
Hello Philip,
On 13.10.23 11:43, Philip Richard Oberfichtner wrote:
> This adds a generic I2C bootcounter adhering to driver model to replace
> the previously removed legacy implementation.
>
> There is no change in functionality, it can be used on any I2C device.
> The device tree configuration may look like this for example:
>
> bootcount {
> compatible = "u-boot,bootcount-i2c";
> i2c-bus = <&i2c1>;
> address = <0x52>;
Hmm.. do we really need this here with DTS. Why not using a phandle
to a real i2c device? Something like this for example:
i2cbcdev = &i2c_rtc;
with
&i2c1 {
i2c_rtc: rtc at 68 {
[...]
and so there is no need for knowing the bus and address ...
> offset = <0x11>;
> };
>
> Signed-off-by: Philip Richard Oberfichtner <pro at denx.de>
> ---
> drivers/bootcount/Kconfig | 10 +++
> drivers/bootcount/Makefile | 1 +
> drivers/bootcount/bootcount_dm_i2c.c | 126 +++++++++++++++++++++++++++
> 3 files changed, 137 insertions(+)
> create mode 100644 drivers/bootcount/bootcount_dm_i2c.c
>
> diff --git a/drivers/bootcount/Kconfig b/drivers/bootcount/Kconfig
> index 7a2548ace2..1cf1de2b6d 100644
> --- a/drivers/bootcount/Kconfig
> +++ b/drivers/bootcount/Kconfig
> @@ -109,6 +109,16 @@ config DM_BOOTCOUNT_RTC
> Accesses to the backing store are performed using the write16
> and read16 ops of DM RTC devices.
>
> +config DM_BOOTCOUNT_I2C
> + bool "Driver Model boot counter on I2C device"
> + depends on DM_I2C
> + help
> + Enable support for the bootcounter on a generic i2c device, like a
> + RTC or PMIC. This requires an 'i2c-bus', the i2c chip 'address' and
> + the 'offset' to read to and write from. All of the three settings are
> + defined as device tree properties using the "u-boot,bootcount-i2c"
> + compatible string.
> +
> config DM_BOOTCOUNT_I2C_EEPROM
> bool "Support i2c eeprom devices as a backing store for bootcount"
> depends on I2C_EEPROM
> diff --git a/drivers/bootcount/Makefile b/drivers/bootcount/Makefile
> index d6d2389c16..e7771f5b36 100644
> --- a/drivers/bootcount/Makefile
> +++ b/drivers/bootcount/Makefile
> @@ -13,5 +13,6 @@ obj-$(CONFIG_DM_BOOTCOUNT) += bootcount-uclass.o
> obj-$(CONFIG_DM_BOOTCOUNT_PMIC_PFUZE100) += pmic_pfuze100.o
> obj-$(CONFIG_DM_BOOTCOUNT_RTC) += rtc.o
> obj-$(CONFIG_DM_BOOTCOUNT_I2C_EEPROM) += i2c-eeprom.o
> +obj-$(CONFIG_DM_BOOTCOUNT_I2C) += bootcount_dm_i2c.o
> obj-$(CONFIG_DM_BOOTCOUNT_SPI_FLASH) += spi-flash.o
> obj-$(CONFIG_DM_BOOTCOUNT_SYSCON) += bootcount_syscon.o
> diff --git a/drivers/bootcount/bootcount_dm_i2c.c b/drivers/bootcount/bootcount_dm_i2c.c
> new file mode 100644
> index 0000000000..227641f77e
> --- /dev/null
> +++ b/drivers/bootcount/bootcount_dm_i2c.c
> @@ -0,0 +1,126 @@
> +// SPDX-License-Identifier: GPL-2.0+
> +/*
> + * (C) Copyright 2023
> + * Philip Richard Oberfichtner <pro at denx.de>
> + *
> + * Based on previous work from Heiko Schocher (legacy bootcount_i2c.c driver)
> + */
> +
> +#include <bootcount.h>
> +#include <common.h>
> +#include <dm.h>
> +#include <i2c.h>
> +
> +#define BC_MAGIC 0x55
> +
> +struct bootcount_i2c_priv {
> + struct udevice *chip;
may rename chip to i2cbcdev or 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->chip, priv->offset, BC_MAGIC);
> + if (ret < 0)
> + goto err_exit;
> +
> + ret = dm_i2c_reg_write(priv->chip, 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->chip, 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->chip, 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);
> + struct ofnode_phandle_args phandle_args;
> + struct udevice *bus;
> + unsigned int addr;
> + int ret;
> +
> + ret = dev_read_u32(dev, "offset", &priv->offset);
> + if (ret) {
> + log_debug("%s: Unable to get offset\n", __func__);
> + return ret;
> + }
> +
> + ret = dev_read_u32(dev, "address", &addr);
> + if (ret) {
> + log_debug("%s: Unable to get chip address\n", __func__);
> + return ret;
> + }
> +
> + ret = dev_read_phandle_with_args(dev, "i2c-bus", NULL, 0, 0, &phandle_args);
> + if (ret) {
> + log_debug("%s: Unable to get phandle\n", __func__);
> + return ret;
> + }
> +
> + ret = uclass_get_device_by_ofnode(UCLASS_I2C, phandle_args.node, &bus);
> + if (ret) {
> + log_debug("%s: Unable to get i2c bus\n", __func__);
> + return ret;
> + }
> +
> + ret = i2c_get_chip(bus, addr, 1, &priv->chip);
> + if (ret) {
> + log_debug("%s: Unable to get i2c chip\n", __func__);
> + return ret;
> + }
when you use a phandle, you can replace the part from reading "offset"
with this:
uclass_get_device_by_phandle(UCLASS_I2C, dev, "i2cbcdev", &priv->bcdev);
of course plus error checking...
> +
> + return 0;
> +}
> +
> +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,
> +};
>
bye,
Heiko
--
DENX Software Engineering GmbH, Managing Director: Erika Unter
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
Phone: +49-8142-66989-52 Fax: +49-8142-66989-80 Email: hs at denx.de
More information about the U-Boot
mailing list