blob: e27034cbeb0d2588e9d060739d319e5ae5034c7f [file] [log] [blame]
Philip Richard Oberfichtnerf451e802023-10-31 08:38:48 +01001// SPDX-License-Identifier: GPL-2.0+
2/*
3 * (C) Copyright 2023
4 * Philip Richard Oberfichtner <pro@denx.de>
5 *
6 * Based on previous work from Heiko Schocher (legacy bootcount_i2c.c driver)
7 */
8
9#include <bootcount.h>
10#include <dm.h>
11#include <i2c.h>
12
13#define BC_MAGIC 0x55
14
15struct bootcount_i2c_priv {
16 struct udevice *bcdev;
17 unsigned int offset;
18};
19
20static int bootcount_i2c_set(struct udevice *dev, const u32 val)
21{
22 int ret;
23 struct bootcount_i2c_priv *priv = dev_get_priv(dev);
24
25 ret = dm_i2c_reg_write(priv->bcdev, priv->offset, BC_MAGIC);
26 if (ret < 0)
27 goto err_exit;
28
29 ret = dm_i2c_reg_write(priv->bcdev, priv->offset + 1, val & 0xff);
30 if (ret < 0)
31 goto err_exit;
32
33 return 0;
34
35err_exit:
36 log_debug("%s: Error writing to I2C device (%d)\n", __func__, ret);
37 return ret;
38}
39
40static int bootcount_i2c_get(struct udevice *dev, u32 *val)
41{
42 int ret;
43 struct bootcount_i2c_priv *priv = dev_get_priv(dev);
44
45 ret = dm_i2c_reg_read(priv->bcdev, priv->offset);
46 if (ret < 0)
47 goto err_exit;
48
49 if ((ret & 0xff) != BC_MAGIC) {
50 log_debug("%s: Invalid Magic, reset bootcounter.\n", __func__);
51 *val = 0;
52 return bootcount_i2c_set(dev, 0);
53 }
54
55 ret = dm_i2c_reg_read(priv->bcdev, priv->offset + 1);
56 if (ret < 0)
57 goto err_exit;
58
59 *val = ret;
60 return 0;
61
62err_exit:
63 log_debug("%s: Error reading from I2C device (%d)\n", __func__, ret);
64 return ret;
65}
66
67static int bootcount_i2c_probe(struct udevice *dev)
68{
69 struct bootcount_i2c_priv *priv = dev_get_priv(dev);
70 int ret;
71
72 ret = dev_read_u32(dev, "offset", &priv->offset);
73 if (ret)
74 goto exit;
75
76 ret = i2c_get_chip_by_phandle(dev, "i2cbcdev", &priv->bcdev);
77
78exit:
79 if (ret)
80 log_debug("%s failed, ret = %d\n", __func__, ret);
81
82 return ret;
83}
84
85static const struct bootcount_ops bootcount_i2c_ops = {
86 .get = bootcount_i2c_get,
87 .set = bootcount_i2c_set,
88};
89
90static const struct udevice_id bootcount_i2c_ids[] = {
91 { .compatible = "u-boot,bootcount-i2c" },
92 { }
93};
94
95U_BOOT_DRIVER(bootcount_i2c) = {
96 .name = "bootcount-i2c",
97 .id = UCLASS_BOOTCOUNT,
98 .priv_auto = sizeof(struct bootcount_i2c_priv),
99 .probe = bootcount_i2c_probe,
100 .of_match = bootcount_i2c_ids,
101 .ops = &bootcount_i2c_ops,
102};