uboot/drivers/power/fuel_gauge/fg_max17042.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 *  Copyright (C) 2012 Samsung Electronics
   4 *  Lukasz Majewski <l.majewski@samsung.com>
   5 */
   6
   7#include <common.h>
   8#include <power/pmic.h>
   9#include <power/max17042_fg.h>
  10#include <i2c.h>
  11#include <power/max8997_pmic.h>
  12#include <power/power_chrg.h>
  13#include <power/battery.h>
  14#include <power/fg_battery_cell_params.h>
  15#include <errno.h>
  16
  17static int fg_write_regs(struct pmic *p, u8 addr, u16 *data, int num)
  18{
  19        int ret = 0;
  20        int i;
  21
  22        for (i = 0; i < num; i++, addr++) {
  23                ret = pmic_reg_write(p, addr, *(data + i));
  24                if (ret)
  25                        return ret;
  26        }
  27
  28        return 0;
  29}
  30
  31static int fg_read_regs(struct pmic *p, u8 addr, u16 *data, int num)
  32{
  33        unsigned int dat;
  34        int ret = 0;
  35        int i;
  36
  37        for (i = 0; i < num; i++, addr++) {
  38                ret = pmic_reg_read(p, addr, &dat);
  39                if (ret)
  40                        return ret;
  41
  42                *(data + i) = (u16)dat;
  43        }
  44
  45        return 0;
  46}
  47
  48static int fg_write_and_verify(struct pmic *p, u8 addr, u16 data)
  49{
  50        unsigned int val = data;
  51        int ret = 0;
  52
  53        ret |= pmic_reg_write(p, addr, val);
  54        ret |= pmic_reg_read(p, addr, &val);
  55
  56        if (ret)
  57                return ret;
  58
  59        if (((u16) val) == data)
  60                return 0;
  61
  62        return -1;
  63}
  64
  65static void por_fuelgauge_init(struct pmic *p)
  66{
  67        u16 r_data0[16], r_data1[16], r_data2[16];
  68        u32 rewrite_count = 5;
  69        u32 check_count;
  70        u32 lock_count;
  71        u32 i = 0;
  72        u32 val;
  73        s32 ret = 0;
  74        char *status_msg;
  75
  76        /* Delay 500 ms */
  77        mdelay(500);
  78        /* Initilize Configuration */
  79        pmic_reg_write(p, MAX17042_CONFIG, 0x2310);
  80
  81rewrite_model:
  82        check_count = 5;
  83        lock_count = 5;
  84
  85        if (!rewrite_count--) {
  86                status_msg = "init failed!";
  87                goto error;
  88        }
  89
  90        /* Unlock Model Access */
  91        pmic_reg_write(p, MAX17042_MLOCKReg1, MODEL_UNLOCK1);
  92        pmic_reg_write(p, MAX17042_MLOCKReg2, MODEL_UNLOCK2);
  93
  94        /* Write/Read/Verify the Custom Model */
  95        ret = fg_write_regs(p, MAX17042_MODEL1, cell_character0,
  96                             ARRAY_SIZE(cell_character0));
  97        if (ret)
  98                goto rewrite_model;
  99
 100        ret = fg_write_regs(p, MAX17042_MODEL2, cell_character1,
 101                             ARRAY_SIZE(cell_character1));
 102        if (ret)
 103                goto rewrite_model;
 104
 105        ret = fg_write_regs(p, MAX17042_MODEL3, cell_character2,
 106                             ARRAY_SIZE(cell_character2));
 107        if (ret)
 108                goto rewrite_model;
 109
 110check_model:
 111        if (!check_count--) {
 112                if (rewrite_count)
 113                        goto rewrite_model;
 114                else
 115                        status_msg = "check failed!";
 116
 117                goto error;
 118        }
 119
 120        ret = fg_read_regs(p, MAX17042_MODEL1, r_data0, ARRAY_SIZE(r_data0));
 121        if (ret)
 122                goto check_model;
 123
 124        ret = fg_read_regs(p, MAX17042_MODEL2, r_data1, ARRAY_SIZE(r_data1));
 125        if (ret)
 126                goto check_model;
 127
 128        ret = fg_read_regs(p, MAX17042_MODEL3, r_data2, ARRAY_SIZE(r_data2));
 129        if (ret)
 130                goto check_model;
 131
 132        for (i = 0; i < 16; i++) {
 133                if ((cell_character0[i] != r_data0[i])
 134                    || (cell_character1[i] != r_data1[i])
 135                    || (cell_character2[i] != r_data2[i]))
 136                        goto rewrite_model;
 137                }
 138
 139lock_model:
 140        if (!lock_count--) {
 141                if (rewrite_count)
 142                        goto rewrite_model;
 143                else
 144                        status_msg = "lock failed!";
 145
 146                goto error;
 147        }
 148
 149        /* Lock model access */
 150        pmic_reg_write(p, MAX17042_MLOCKReg1, MODEL_LOCK1);
 151        pmic_reg_write(p, MAX17042_MLOCKReg2, MODEL_LOCK2);
 152
 153        /* Verify the model access is locked */
 154        ret = fg_read_regs(p, MAX17042_MODEL1, r_data0, ARRAY_SIZE(r_data0));
 155        if (ret)
 156                goto lock_model;
 157
 158        ret = fg_read_regs(p, MAX17042_MODEL2, r_data1, ARRAY_SIZE(r_data1));
 159        if (ret)
 160                goto lock_model;
 161
 162        ret = fg_read_regs(p, MAX17042_MODEL3, r_data2, ARRAY_SIZE(r_data2));
 163        if (ret)
 164                goto lock_model;
 165
 166        for (i = 0; i < ARRAY_SIZE(r_data0); i++) {
 167                /* Check if model locked */
 168                if (r_data0[i] || r_data1[i] || r_data2[i])
 169                        goto lock_model;
 170        }
 171
 172        /* Write Custom Parameters */
 173        fg_write_and_verify(p, MAX17042_RCOMP0, RCOMP0);
 174        fg_write_and_verify(p, MAX17042_TEMPCO, TempCo);
 175
 176        /* Delay at least 350mS */
 177        mdelay(350);
 178
 179        /* Initialization Complete */
 180        pmic_reg_read(p, MAX17042_STATUS, &val);
 181        /* Write and Verify Status with POR bit Cleared */
 182        fg_write_and_verify(p, MAX17042_STATUS, val & ~MAX17042_POR);
 183
 184        /* Delay at least 350 ms */
 185        mdelay(350);
 186
 187        status_msg = "OK!";
 188error:
 189        debug("%s: model init status: %s\n", p->name, status_msg);
 190        return;
 191}
 192
 193static int power_update_battery(struct pmic *p, struct pmic *bat)
 194{
 195        struct power_battery *pb = bat->pbat;
 196        unsigned int val;
 197        int ret = 0;
 198
 199        if (pmic_probe(p)) {
 200                puts("Can't find max17042 fuel gauge\n");
 201                return -ENODEV;
 202        }
 203
 204        ret |= pmic_reg_read(p, MAX17042_VFSOC, &val);
 205        pb->bat->state_of_chrg = (val >> 8);
 206
 207        pmic_reg_read(p, MAX17042_VCELL, &val);
 208        debug("vfsoc: 0x%x\n", val);
 209        pb->bat->voltage_uV = ((val & 0xFFUL) >> 3) + ((val & 0xFF00) >> 3);
 210        pb->bat->voltage_uV = (pb->bat->voltage_uV * 625);
 211
 212        pmic_reg_read(p, 0x05, &val);
 213        pb->bat->capacity = val >> 2;
 214
 215        return ret;
 216}
 217
 218static int power_check_battery(struct pmic *p, struct pmic *bat)
 219{
 220        struct power_battery *pb = bat->pbat;
 221        unsigned int val;
 222        int ret = 0;
 223
 224        if (pmic_probe(p)) {
 225                puts("Can't find max17042 fuel gauge\n");
 226                return -ENODEV;
 227        }
 228
 229        ret |= pmic_reg_read(p, MAX17042_STATUS, &val);
 230        debug("fg status: 0x%x\n", val);
 231
 232        if (val & MAX17042_POR)
 233                por_fuelgauge_init(p);
 234
 235        ret |= pmic_reg_read(p, MAX17042_VERSION, &val);
 236        pb->bat->version = val;
 237
 238        power_update_battery(p, bat);
 239        debug("fg ver: 0x%x\n", pb->bat->version);
 240        printf("BAT: state_of_charge(SOC):%d%%\n",
 241               pb->bat->state_of_chrg);
 242
 243        printf("     voltage: %d.%6.6d [V] (expected to be %d [mAh])\n",
 244               pb->bat->voltage_uV / 1000000,
 245               pb->bat->voltage_uV % 1000000,
 246               pb->bat->capacity);
 247
 248        if (pb->bat->voltage_uV > 3850000)
 249                pb->bat->state = EXT_SOURCE;
 250        else if (pb->bat->voltage_uV < 3600000 || pb->bat->state_of_chrg < 5)
 251                pb->bat->state = CHARGE;
 252        else
 253                pb->bat->state = NORMAL;
 254
 255        return ret;
 256}
 257
 258static struct power_fg power_fg_ops = {
 259        .fg_battery_check = power_check_battery,
 260        .fg_battery_update = power_update_battery,
 261};
 262
 263int power_fg_init(unsigned char bus)
 264{
 265        static const char name[] = "MAX17042_FG";
 266        struct pmic *p = pmic_alloc();
 267
 268        if (!p) {
 269                printf("%s: POWER allocation error!\n", __func__);
 270                return -ENOMEM;
 271        }
 272
 273        debug("Board Fuel Gauge init\n");
 274
 275        p->name = name;
 276        p->interface = PMIC_I2C;
 277        p->number_of_regs = FG_NUM_OF_REGS;
 278        p->hw.i2c.addr = MAX17042_I2C_ADDR;
 279        p->hw.i2c.tx_num = 2;
 280        p->sensor_byte_order = PMIC_SENSOR_BYTE_ORDER_BIG;
 281        p->bus = bus;
 282
 283        p->fg = &power_fg_ops;
 284        return 0;
 285}
 286