Add qemu 2.4.0
[kvmfornfv.git] / qemu / roms / u-boot / drivers / power / fuel_gauge / fg_max17042.c
diff --git a/qemu/roms/u-boot/drivers/power/fuel_gauge/fg_max17042.c b/qemu/roms/u-boot/drivers/power/fuel_gauge/fg_max17042.c
new file mode 100644 (file)
index 0000000..154ca6a
--- /dev/null
@@ -0,0 +1,286 @@
+/*
+ *  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;
+}