uboot/drivers/power/pmic/stpmic1.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause
   2/*
   3 * Copyright (C) 2018, STMicroelectronics - All Rights Reserved
   4 */
   5
   6#include <common.h>
   7#include <dm.h>
   8#include <errno.h>
   9#include <i2c.h>
  10#include <misc.h>
  11#include <sysreset.h>
  12#include <time.h>
  13#include <dm/device.h>
  14#include <dm/lists.h>
  15#include <power/pmic.h>
  16#include <power/stpmic1.h>
  17
  18#define STPMIC1_NUM_OF_REGS 0x100
  19
  20#define STPMIC1_NVM_SIZE 8
  21#define STPMIC1_NVM_POLL_TIMEOUT 100000
  22#define STPMIC1_NVM_START_ADDRESS 0xf8
  23
  24enum pmic_nvm_op {
  25        SHADOW_READ,
  26        SHADOW_WRITE,
  27        NVM_READ,
  28        NVM_WRITE,
  29};
  30
  31#if CONFIG_IS_ENABLED(DM_REGULATOR)
  32static const struct pmic_child_info stpmic1_children_info[] = {
  33        { .prefix = "ldo", .driver = "stpmic1_ldo" },
  34        { .prefix = "buck", .driver = "stpmic1_buck" },
  35        { .prefix = "vref_ddr", .driver = "stpmic1_vref_ddr" },
  36        { .prefix = "pwr_sw", .driver = "stpmic1_pwr_sw" },
  37        { .prefix = "boost", .driver = "stpmic1_boost" },
  38        { },
  39};
  40#endif /* DM_REGULATOR */
  41
  42static int stpmic1_reg_count(struct udevice *dev)
  43{
  44        return STPMIC1_NUM_OF_REGS;
  45}
  46
  47static int stpmic1_write(struct udevice *dev, uint reg, const uint8_t *buff,
  48                         int len)
  49{
  50        int ret;
  51
  52        ret = dm_i2c_write(dev, reg, buff, len);
  53        if (ret)
  54                dev_err(dev, "%s: failed to write register %#x :%d",
  55                        __func__, reg, ret);
  56
  57        return ret;
  58}
  59
  60static int stpmic1_read(struct udevice *dev, uint reg, uint8_t *buff, int len)
  61{
  62        int ret;
  63
  64        ret = dm_i2c_read(dev, reg, buff, len);
  65        if (ret)
  66                dev_err(dev, "%s: failed to read register %#x : %d",
  67                        __func__, reg, ret);
  68
  69        return ret;
  70}
  71
  72static int stpmic1_bind(struct udevice *dev)
  73{
  74        int ret;
  75#if CONFIG_IS_ENABLED(DM_REGULATOR)
  76        ofnode regulators_node;
  77        int children;
  78
  79        regulators_node = dev_read_subnode(dev, "regulators");
  80        if (!ofnode_valid(regulators_node)) {
  81                dev_dbg(dev, "regulators subnode not found!");
  82                return -ENXIO;
  83        }
  84        dev_dbg(dev, "found regulators subnode\n");
  85
  86        children = pmic_bind_children(dev, regulators_node,
  87                                      stpmic1_children_info);
  88        if (!children)
  89                dev_dbg(dev, "no child found\n");
  90#endif /* DM_REGULATOR */
  91
  92        if (!IS_ENABLED(CONFIG_SPL_BUILD)) {
  93                ret = device_bind_driver(dev, "stpmic1-nvm",
  94                                         "stpmic1-nvm", NULL);
  95                if (ret)
  96                        return ret;
  97        }
  98
  99        if (CONFIG_IS_ENABLED(SYSRESET))
 100                return device_bind_driver(dev, "stpmic1-sysreset",
 101                                          "stpmic1-sysreset", NULL);
 102
 103        return 0;
 104}
 105
 106static struct dm_pmic_ops stpmic1_ops = {
 107        .reg_count = stpmic1_reg_count,
 108        .read = stpmic1_read,
 109        .write = stpmic1_write,
 110};
 111
 112static const struct udevice_id stpmic1_ids[] = {
 113        { .compatible = "st,stpmic1" },
 114        { }
 115};
 116
 117U_BOOT_DRIVER(pmic_stpmic1) = {
 118        .name = "stpmic1_pmic",
 119        .id = UCLASS_PMIC,
 120        .of_match = stpmic1_ids,
 121        .bind = stpmic1_bind,
 122        .ops = &stpmic1_ops,
 123};
 124
 125#ifndef CONFIG_SPL_BUILD
 126static int stpmic1_nvm_rw(struct udevice *dev, u8 addr, u8 *buf, int buf_len,
 127                          enum pmic_nvm_op op)
 128{
 129        unsigned long timeout;
 130        u8 cmd = STPMIC1_NVM_CMD_READ;
 131        int ret, len = buf_len;
 132
 133        if (addr < STPMIC1_NVM_START_ADDRESS)
 134                return -EACCES;
 135        if (addr + buf_len > STPMIC1_NVM_START_ADDRESS + STPMIC1_NVM_SIZE)
 136                len = STPMIC1_NVM_START_ADDRESS + STPMIC1_NVM_SIZE - addr;
 137
 138        if (op == SHADOW_READ) {
 139                ret = pmic_read(dev, addr, buf, len);
 140                if (ret < 0)
 141                        return ret;
 142                else
 143                        return len;
 144        }
 145
 146        if (op == SHADOW_WRITE) {
 147                ret = pmic_write(dev, addr, buf, len);
 148                if (ret < 0)
 149                        return ret;
 150                else
 151                        return len;
 152        }
 153
 154        if (op == NVM_WRITE) {
 155                cmd = STPMIC1_NVM_CMD_PROGRAM;
 156
 157                ret = pmic_write(dev, addr, buf, len);
 158                if (ret < 0)
 159                        return ret;
 160        }
 161
 162        ret = pmic_reg_read(dev, STPMIC1_NVM_CR);
 163        if (ret < 0)
 164                return ret;
 165
 166        ret = pmic_reg_write(dev, STPMIC1_NVM_CR, ret | cmd);
 167        if (ret < 0)
 168                return ret;
 169
 170        timeout = timer_get_us() + STPMIC1_NVM_POLL_TIMEOUT;
 171        for (;;) {
 172                ret = pmic_reg_read(dev, STPMIC1_NVM_SR);
 173                if (ret < 0)
 174                        return ret;
 175
 176                if (!(ret & STPMIC1_NVM_BUSY))
 177                        break;
 178
 179                if (time_after(timer_get_us(), timeout))
 180                        break;
 181        }
 182
 183        if (ret & STPMIC1_NVM_BUSY)
 184                return -ETIMEDOUT;
 185
 186        if (op == NVM_READ) {
 187                ret = pmic_read(dev, addr, buf, len);
 188                if (ret < 0)
 189                        return ret;
 190        }
 191
 192        return len;
 193}
 194
 195static int stpmic1_nvm_read(struct udevice *dev, int offset,
 196                            void *buf, int size)
 197{
 198        enum pmic_nvm_op op = NVM_READ;
 199
 200        if (offset < 0) {
 201                op = SHADOW_READ;
 202                offset = -offset;
 203        }
 204
 205        return stpmic1_nvm_rw(dev->parent, offset, buf, size, op);
 206}
 207
 208static int stpmic1_nvm_write(struct udevice *dev, int offset,
 209                             const void *buf, int size)
 210{
 211        enum pmic_nvm_op op = NVM_WRITE;
 212
 213        if (offset < 0) {
 214                op = SHADOW_WRITE;
 215                offset = -offset;
 216        }
 217
 218        return stpmic1_nvm_rw(dev->parent, offset, (void *)buf, size, op);
 219}
 220
 221static const struct misc_ops stpmic1_nvm_ops = {
 222        .read = stpmic1_nvm_read,
 223        .write = stpmic1_nvm_write,
 224};
 225
 226U_BOOT_DRIVER(stpmic1_nvm) = {
 227        .name = "stpmic1-nvm",
 228        .id = UCLASS_MISC,
 229        .ops = &stpmic1_nvm_ops,
 230};
 231#endif /* CONFIG_SPL_BUILD */
 232
 233#ifdef CONFIG_SYSRESET
 234static int stpmic1_sysreset_request(struct udevice *dev, enum sysreset_t type)
 235{
 236        struct udevice *pmic_dev = dev->parent;
 237        int ret;
 238
 239        if (type != SYSRESET_POWER && type != SYSRESET_POWER_OFF)
 240                return -EPROTONOSUPPORT;
 241
 242        ret = pmic_reg_read(pmic_dev, STPMIC1_MAIN_CR);
 243        if (ret < 0)
 244                return ret;
 245
 246        ret |= STPMIC1_SWOFF;
 247        ret &= ~STPMIC1_RREQ_EN;
 248        /* request Power Cycle */
 249        if (type == SYSRESET_POWER)
 250                ret |= STPMIC1_RREQ_EN;
 251
 252        ret = pmic_reg_write(pmic_dev, STPMIC1_MAIN_CR, ret);
 253        if (ret < 0)
 254                return ret;
 255
 256        return -EINPROGRESS;
 257}
 258
 259static struct sysreset_ops stpmic1_sysreset_ops = {
 260        .request = stpmic1_sysreset_request,
 261};
 262
 263U_BOOT_DRIVER(stpmic1_sysreset) = {
 264        .name = "stpmic1-sysreset",
 265        .id = UCLASS_SYSRESET,
 266        .ops = &stpmic1_sysreset_ops,
 267};
 268#endif
 269