123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286 |
- /*
- * Copyright (C) 2012 Samsung Electronics
- * Lukasz Majewski <l.majewski@samsung.com>
- *
- * SPDX-License-Identifier: GPL-2.0+
- */
- #include <common.h>
- #include <power/pmic.h>
- #include <power/max17042_fg.h>
- #include <i2c.h>
- #include <power/max8997_pmic.h>
- #include <power/power_chrg.h>
- #include <power/battery.h>
- #include <power/fg_battery_cell_params.h>
- #include <errno.h>
- static int fg_write_regs(struct pmic *p, u8 addr, u16 *data, int num)
- {
- int ret = 0;
- int i;
- for (i = 0; i < num; i++, addr++) {
- ret = pmic_reg_write(p, addr, *(data + i));
- if (ret)
- return ret;
- }
- return 0;
- }
- static int fg_read_regs(struct pmic *p, u8 addr, u16 *data, int num)
- {
- unsigned int dat;
- int ret = 0;
- int i;
- for (i = 0; i < num; i++, addr++) {
- ret = pmic_reg_read(p, addr, &dat);
- if (ret)
- return ret;
- *(data + i) = (u16)dat;
- }
- return 0;
- }
- static int fg_write_and_verify(struct pmic *p, u8 addr, u16 data)
- {
- unsigned int val = data;
- int ret = 0;
- ret |= pmic_reg_write(p, addr, val);
- ret |= pmic_reg_read(p, addr, &val);
- if (ret)
- return ret;
- if (((u16) val) == data)
- return 0;
- return -1;
- }
- static void por_fuelgauge_init(struct pmic *p)
- {
- u16 r_data0[16], r_data1[16], r_data2[16];
- u32 rewrite_count = 5;
- u32 check_count;
- u32 lock_count;
- u32 i = 0;
- u32 val;
- s32 ret = 0;
- char *status_msg;
- /* Delay 500 ms */
- mdelay(500);
- /* Initilize Configuration */
- pmic_reg_write(p, MAX17042_CONFIG, 0x2310);
- rewrite_model:
- check_count = 5;
- lock_count = 5;
- if (!rewrite_count--) {
- status_msg = "init failed!";
- goto error;
- }
- /* Unlock Model Access */
- pmic_reg_write(p, MAX17042_MLOCKReg1, MODEL_UNLOCK1);
- pmic_reg_write(p, MAX17042_MLOCKReg2, MODEL_UNLOCK2);
- /* Write/Read/Verify the Custom Model */
- ret = fg_write_regs(p, MAX17042_MODEL1, cell_character0,
- ARRAY_SIZE(cell_character0));
- if (ret)
- goto rewrite_model;
- ret = fg_write_regs(p, MAX17042_MODEL2, cell_character1,
- ARRAY_SIZE(cell_character1));
- if (ret)
- goto rewrite_model;
- ret = fg_write_regs(p, MAX17042_MODEL3, cell_character2,
- ARRAY_SIZE(cell_character2));
- if (ret)
- goto rewrite_model;
- check_model:
- if (!check_count--) {
- if (rewrite_count)
- goto rewrite_model;
- else
- status_msg = "check failed!";
- goto error;
- }
- ret = fg_read_regs(p, MAX17042_MODEL1, r_data0, ARRAY_SIZE(r_data0));
- if (ret)
- goto check_model;
- ret = fg_read_regs(p, MAX17042_MODEL2, r_data1, ARRAY_SIZE(r_data1));
- if (ret)
- goto check_model;
- ret = fg_read_regs(p, MAX17042_MODEL3, r_data2, ARRAY_SIZE(r_data2));
- if (ret)
- goto check_model;
- for (i = 0; i < 16; i++) {
- if ((cell_character0[i] != r_data0[i])
- || (cell_character1[i] != r_data1[i])
- || (cell_character2[i] != r_data2[i]))
- goto rewrite_model;
- }
- lock_model:
- if (!lock_count--) {
- if (rewrite_count)
- goto rewrite_model;
- else
- status_msg = "lock failed!";
- goto error;
- }
- /* Lock model access */
- pmic_reg_write(p, MAX17042_MLOCKReg1, MODEL_LOCK1);
- pmic_reg_write(p, MAX17042_MLOCKReg2, MODEL_LOCK2);
- /* Verify the model access is locked */
- ret = fg_read_regs(p, MAX17042_MODEL1, r_data0, ARRAY_SIZE(r_data0));
- if (ret)
- goto lock_model;
- ret = fg_read_regs(p, MAX17042_MODEL2, r_data1, ARRAY_SIZE(r_data1));
- if (ret)
- goto lock_model;
- ret = fg_read_regs(p, MAX17042_MODEL3, r_data2, ARRAY_SIZE(r_data2));
- if (ret)
- goto lock_model;
- for (i = 0; i < ARRAY_SIZE(r_data0); i++) {
- /* Check if model locked */
- if (r_data0[i] || r_data1[i] || r_data2[i])
- goto lock_model;
- }
- /* Write Custom Parameters */
- fg_write_and_verify(p, MAX17042_RCOMP0, RCOMP0);
- fg_write_and_verify(p, MAX17042_TEMPCO, TempCo);
- /* Delay at least 350mS */
- mdelay(350);
- /* Initialization Complete */
- pmic_reg_read(p, MAX17042_STATUS, &val);
- /* Write and Verify Status with POR bit Cleared */
- fg_write_and_verify(p, MAX17042_STATUS, val & ~MAX17042_POR);
- /* Delay at least 350 ms */
- mdelay(350);
- status_msg = "OK!";
- error:
- debug("%s: model init status: %s\n", p->name, status_msg);
- return;
- }
- static int power_update_battery(struct pmic *p, struct pmic *bat)
- {
- struct power_battery *pb = bat->pbat;
- unsigned int val;
- int ret = 0;
- if (pmic_probe(p)) {
- puts("Can't find max17042 fuel gauge\n");
- return -1;
- }
- ret |= pmic_reg_read(p, MAX17042_VFSOC, &val);
- pb->bat->state_of_chrg = (val >> 8);
- pmic_reg_read(p, MAX17042_VCELL, &val);
- debug("vfsoc: 0x%x\n", val);
- pb->bat->voltage_uV = ((val & 0xFFUL) >> 3) + ((val & 0xFF00) >> 3);
- pb->bat->voltage_uV = (pb->bat->voltage_uV * 625);
- pmic_reg_read(p, 0x05, &val);
- pb->bat->capacity = val >> 2;
- return ret;
- }
- static int power_check_battery(struct pmic *p, struct pmic *bat)
- {
- struct power_battery *pb = bat->pbat;
- unsigned int val;
- int ret = 0;
- if (pmic_probe(p)) {
- puts("Can't find max17042 fuel gauge\n");
- return -1;
- }
- ret |= pmic_reg_read(p, MAX17042_STATUS, &val);
- debug("fg status: 0x%x\n", val);
- if (val & MAX17042_POR)
- por_fuelgauge_init(p);
- ret |= pmic_reg_read(p, MAX17042_VERSION, &val);
- pb->bat->version = val;
- power_update_battery(p, bat);
- debug("fg ver: 0x%x\n", pb->bat->version);
- printf("BAT: state_of_charge(SOC):%d%%\n",
- pb->bat->state_of_chrg);
- printf(" voltage: %d.%6.6d [V] (expected to be %d [mAh])\n",
- pb->bat->voltage_uV / 1000000,
- pb->bat->voltage_uV % 1000000,
- pb->bat->capacity);
- if (pb->bat->voltage_uV > 3850000)
- pb->bat->state = EXT_SOURCE;
- else if (pb->bat->voltage_uV < 3600000 || pb->bat->state_of_chrg < 5)
- pb->bat->state = CHARGE;
- else
- pb->bat->state = NORMAL;
- return ret;
- }
- static struct power_fg power_fg_ops = {
- .fg_battery_check = power_check_battery,
- .fg_battery_update = power_update_battery,
- };
- int power_fg_init(unsigned char bus)
- {
- static const char name[] = "MAX17042_FG";
- struct pmic *p = pmic_alloc();
- if (!p) {
- printf("%s: POWER allocation error!\n", __func__);
- return -ENOMEM;
- }
- debug("Board Fuel Gauge init\n");
- p->name = name;
- p->interface = PMIC_I2C;
- p->number_of_regs = FG_NUM_OF_REGS;
- p->hw.i2c.addr = MAX17042_I2C_ADDR;
- p->hw.i2c.tx_num = 2;
- p->sensor_byte_order = PMIC_SENSOR_BYTE_ORDER_BIG;
- p->bus = bus;
- p->fg = &power_fg_ops;
- return 0;
- }
|