Loading...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 | // SPDX-License-Identifier: GPL-2.0+ /* * Copyright (C) 2018-2022 Denx Software Engineering GmbH * Heiko Schocher <hs@denx.de> * Philip Oberfichtner <pro@denx.de> * * A bootcount driver using the registers MEMA - MEMD on the PFUZE100. * This works only, if the PMIC is not connected to a battery. */ #include <bootcount.h> #include <dm.h> #include <power/pmic.h> #include <power/pfuze100_pmic.h> DECLARE_GLOBAL_DATA_PTR; #define PFUZE_BC_MAGIC 0xdead struct bootcount_pmic_priv { struct udevice *pmic; }; static int pfuze100_get_magic(struct udevice *dev, u32 *magic) { int ret; ret = pmic_reg_read(dev, PFUZE100_MEMA); if (ret < 0) return ret; *magic = ret; ret = pmic_reg_read(dev, PFUZE100_MEMB); if (ret < 0) return ret; *magic += ret << 8; return 0; } static int pfuze100_set_magic(struct udevice *dev) { int ret; ret = pmic_reg_write(dev, PFUZE100_MEMA, PFUZE_BC_MAGIC & 0xff); if (ret) return ret; ret = pmic_reg_write(dev, PFUZE100_MEMB, (PFUZE_BC_MAGIC >> 8) & 0xff); return ret; } static int pfuze100_get_value(struct udevice *dev, u32 *a) { int ret; ret = pmic_reg_read(dev, PFUZE100_MEMC); if (ret < 0) return ret; *a = ret; ret = pmic_reg_read(dev, PFUZE100_MEMD); if (ret < 0) return ret; *a += ret << 8; return 0; } static int pfuze100_set_value(struct udevice *dev, u32 val) { int ret; ret = pmic_reg_write(dev, PFUZE100_MEMC, val & 0xff); if (ret) return ret; ret = pmic_reg_write(dev, PFUZE100_MEMD, (val >> 8) & 0xff); return ret; } static int bootcount_pmic_set(struct udevice *dev, const u32 a) { struct bootcount_pmic_priv *priv = dev_get_priv(dev); if (pfuze100_set_magic(priv->pmic)) { debug("%s: writing magic failed\n", __func__); return -EIO; } if (pfuze100_set_value(priv->pmic, a)) { debug("%s: writing value failed\n", __func__); return -EIO; } return 0; } static int bootcount_pmic_get(struct udevice *dev, u32 *a) { struct bootcount_pmic_priv *priv = dev_get_priv(dev); u32 magic; if (pfuze100_get_magic(priv->pmic, &magic)) { debug("%s: reading magic failed\n", __func__); return -EIO; } if (magic != PFUZE_BC_MAGIC) { *a = 0; return 0; } if (pfuze100_get_value(priv->pmic, a)) { debug("%s: reading value failed\n", __func__); return -EIO; } return 0; } static int bootcount_pmic_probe(struct udevice *dev) { struct ofnode_phandle_args phandle_args; struct bootcount_pmic_priv *priv = dev_get_priv(dev); struct udevice *pmic; if (dev_read_phandle_with_args(dev, "pmic", NULL, 0, 0, &phandle_args)) { debug("%s: pmic backing device not specified\n", dev->name); return -ENOENT; } if (uclass_get_device_by_ofnode(UCLASS_PMIC, phandle_args.node, &pmic)) { debug("%s: could not get backing device\n", dev->name); return -ENODEV; } priv->pmic = pmic; return 0; } static const struct bootcount_ops bootcount_pmic_ops = { .get = bootcount_pmic_get, .set = bootcount_pmic_set, }; static const struct udevice_id bootcount_pmic_ids[] = { { .compatible = "u-boot,bootcount-pmic" }, { } }; U_BOOT_DRIVER(bootcount_pmic) = { .name = "bootcount-pmic", .id = UCLASS_BOOTCOUNT, .priv_auto = sizeof(struct bootcount_pmic_priv), .probe = bootcount_pmic_probe, .of_match = bootcount_pmic_ids, .ops = &bootcount_pmic_ops, }; |