uboot/drivers/power/pmic/pmic_tps65218.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 * (C) Copyright 2011-2013
   4 * Texas Instruments, <www.ti.com>
   5 */
   6
   7#include <common.h>
   8#include <i2c.h>
   9#include <linux/errno.h>
  10#include <power/pmic.h>
  11#include <power/tps65218.h>
  12
  13#if !CONFIG_IS_ENABLED(DM_I2C)
  14int tps65218_reg_read(uchar dest_reg, uchar *dest_val)
  15{
  16        uchar read_val;
  17        int ret;
  18
  19        ret = i2c_read(TPS65218_CHIP_PM, dest_reg, 1, &read_val, 1);
  20        if (ret)
  21                return ret;
  22
  23        *dest_val = read_val;
  24
  25        return 0;
  26}
  27
  28/**
  29 *  tps65218_reg_write() - Generic function that can write a TPS65218 PMIC
  30 *                         register or bit field regardless of protection
  31 *                         level.
  32 *
  33 *  @prot_level:           Register password protection.  Use
  34 *                         TPS65218_PROT_LEVEL_NONE,
  35 *                         TPS65218_PROT_LEVEL_1 or TPS65218_PROT_LEVEL_2
  36 *  @dest_reg:             Register address to write.
  37 *  @dest_val:             Value to write.
  38 *  @mask:                 Bit mask (8 bits) to be applied.  Function will only
  39 *                         change bits that are set in the bit mask.
  40 *
  41 *  @return:               0 for success, not 0 on failure, as per the i2c API
  42 */
  43int tps65218_reg_write(uchar prot_level, uchar dest_reg, uchar dest_val,
  44                       uchar mask)
  45{
  46        uchar read_val;
  47        uchar xor_reg;
  48        int ret;
  49
  50        /*
  51         * If we are affecting only a bit field, read dest_reg and apply the
  52         * mask
  53         */
  54        if (mask != TPS65218_MASK_ALL_BITS) {
  55                ret = i2c_read(TPS65218_CHIP_PM, dest_reg, 1, &read_val, 1);
  56                if (ret)
  57                        return ret;
  58                read_val &= (~mask);
  59                read_val |= (dest_val & mask);
  60                dest_val = read_val;
  61        }
  62
  63        if (prot_level > 0) {
  64                xor_reg = dest_reg ^ TPS65218_PASSWORD_UNLOCK;
  65                ret = i2c_write(TPS65218_CHIP_PM, TPS65218_PASSWORD, 1,
  66                                &xor_reg, 1);
  67                if (ret)
  68                        return ret;
  69        }
  70
  71        ret = i2c_write(TPS65218_CHIP_PM, dest_reg, 1, &dest_val, 1);
  72        if (ret)
  73                return ret;
  74
  75        if (prot_level == TPS65218_PROT_LEVEL_2) {
  76                ret = i2c_write(TPS65218_CHIP_PM, TPS65218_PASSWORD, 1,
  77                                &xor_reg, 1);
  78                if (ret)
  79                        return ret;
  80
  81                ret = i2c_write(TPS65218_CHIP_PM, dest_reg, 1, &dest_val, 1);
  82                if (ret)
  83                        return ret;
  84        }
  85
  86        return 0;
  87}
  88#else
  89struct udevice *tps65218_dev __section(".data") = NULL;
  90
  91int tps65218_reg_read(uchar dest_reg, uchar *dest_val)
  92{
  93        uchar read_val;
  94        int ret;
  95
  96        if (!tps65218_dev)
  97                return -ENODEV;
  98
  99        ret = dm_i2c_read(tps65218_dev, dest_reg,  &read_val, 1);
 100        if (ret)
 101                return ret;
 102
 103        *dest_val = read_val;
 104
 105        return 0;
 106}
 107
 108int tps65218_reg_write(uchar prot_level, uchar dest_reg, uchar dest_val,
 109                       uchar mask)
 110{
 111        uchar read_val;
 112        uchar xor_reg;
 113        int ret;
 114
 115        if (!tps65218_dev)
 116                return -ENODEV;
 117
 118        /*
 119         * If we are affecting only a bit field, read dest_reg and apply the
 120         * mask
 121         */
 122        if (mask != TPS65218_MASK_ALL_BITS) {
 123                ret = dm_i2c_read(tps65218_dev, dest_reg, &read_val, 1);
 124                if (ret)
 125                        return ret;
 126
 127                read_val &= (~mask);
 128                read_val |= (dest_val & mask);
 129                dest_val = read_val;
 130        }
 131
 132        if (prot_level > 0) {
 133                xor_reg = dest_reg ^ TPS65218_PASSWORD_UNLOCK;
 134                ret = dm_i2c_write(tps65218_dev, TPS65218_PASSWORD, &xor_reg,
 135                                   1);
 136                if (ret)
 137                        return ret;
 138        }
 139
 140        ret = dm_i2c_write(tps65218_dev, dest_reg, &dest_val, 1);
 141        if (ret)
 142                return ret;
 143
 144        if (prot_level == TPS65218_PROT_LEVEL_2) {
 145                ret = dm_i2c_write(tps65218_dev, TPS65218_PASSWORD, &xor_reg,
 146                                   1);
 147                if (ret)
 148                        return ret;
 149
 150                ret = dm_i2c_write(tps65218_dev, dest_reg, &dest_val, 1);
 151                if (ret)
 152                        return ret;
 153        }
 154
 155        return 0;
 156}
 157#endif
 158
 159/**
 160 * tps65218_voltage_update() - Function to change a voltage level, as this
 161 *                             is a multi-step process.
 162 * @dc_cntrl_reg:              DC voltage control register to change.
 163 * @volt_sel:                  New value for the voltage register
 164 * @return:                    0 for success, not 0 on failure.
 165 */
 166int tps65218_voltage_update(uchar dc_cntrl_reg, uchar volt_sel)
 167{
 168        if ((dc_cntrl_reg != TPS65218_DCDC1) &&
 169            (dc_cntrl_reg != TPS65218_DCDC2) &&
 170            (dc_cntrl_reg != TPS65218_DCDC3))
 171                return 1;
 172
 173        /* set voltage level */
 174        if (tps65218_reg_write(TPS65218_PROT_LEVEL_2, dc_cntrl_reg, volt_sel,
 175                               TPS65218_DCDC_VSEL_MASK))
 176                return 1;
 177
 178        /* set GO bit to initiate voltage transition */
 179        if (tps65218_reg_write(TPS65218_PROT_LEVEL_2, TPS65218_SLEW,
 180                               TPS65218_DCDC_GO, TPS65218_DCDC_GO))
 181                return 1;
 182
 183        return 0;
 184}
 185
 186/**
 187 * tps65218_toggle_fseal() - Perform the sequence that toggles the FSEAL bit.
 188 *
 189 * @return:                  0 on success, -EBADE if the sequence was broken
 190 */
 191int tps65218_toggle_fseal(void)
 192{
 193        if (tps65218_reg_write(TPS65218_PROT_LEVEL_NONE, TPS65218_PASSWORD,
 194                               0xb1, TPS65218_MASK_ALL_BITS))
 195                return -EBADE;
 196
 197        if (tps65218_reg_write(TPS65218_PROT_LEVEL_NONE, TPS65218_PASSWORD,
 198                               0xfe, TPS65218_MASK_ALL_BITS))
 199                return -EBADE;
 200
 201        if (tps65218_reg_write(TPS65218_PROT_LEVEL_NONE, TPS65218_PASSWORD,
 202                               0xa3, TPS65218_MASK_ALL_BITS))
 203                return -EBADE;
 204
 205        return 0;
 206}
 207
 208/**
 209 * tps65218_lock_fseal() - Perform the sequence that locks the FSEAL bit to 1.
 210 *
 211 * The FSEAL bit prevents the PMIC from turning off DCDC5 and DCDC6. It can be
 212 * toggled at most 3 times: 0->1, 1->0, and finally 0->1. After the third switch
 213 * its value is locked and can only be reset by powering off the PMIC entirely.
 214 *
 215 * @return:                0 on success, -EBADE if the sequence was broken
 216 */
 217int tps65218_lock_fseal(void)
 218{
 219        int i;
 220
 221        for (i = 0; i < 3; i++)
 222                if (tps65218_toggle_fseal())
 223                        return -EBADE;
 224
 225        return 0;
 226}
 227
 228#if !CONFIG_IS_ENABLED(DM_I2C)
 229int power_tps65218_init(unsigned char bus)
 230{
 231        static const char name[] = "TPS65218_PMIC";
 232        struct pmic *p = pmic_alloc();
 233
 234        if (!p) {
 235                printf("%s: POWER allocation error!\n", __func__);
 236                return -ENOMEM;
 237        }
 238
 239        p->name = name;
 240        p->interface = PMIC_I2C;
 241        p->number_of_regs = TPS65218_PMIC_NUM_OF_REGS;
 242        p->hw.i2c.addr = TPS65218_CHIP_PM;
 243        p->hw.i2c.tx_num = 1;
 244        p->bus = bus;
 245
 246        return 0;
 247}
 248#else
 249int power_tps65218_init(unsigned char bus)
 250{
 251        struct udevice *dev = NULL;
 252        int rc;
 253
 254        rc = i2c_get_chip_for_busnum(bus, TPS65218_CHIP_PM, 1, &dev);
 255        if (rc)
 256                return rc;
 257        tps65218_dev = dev;
 258        return 0;
 259}
 260#endif
 261