#define CPCAP_REG_BPEOL_BIT_BATTDETEN  BIT(1)  /* Enable battery detect */
 #define CPCAP_REG_BPEOL_BIT_EOLSEL     BIT(0)  /* BPDET = 0, EOL = 1 */
 
+/*
+ * Register bit defines for CPCAP_REG_CCC1. These seem similar to the twl6030
+ * coulomb counter registers rather than the mc13892 registers. Both twl6030
+ * and mc13892 set bits 2 and 1 to reset and clear registers. But mc13892
+ * sets bit 0 to start the coulomb counter while twl6030 sets bit 0 to stop
+ * the coulomb counter like cpcap does. So for now, we use the twl6030 style
+ * naming for the registers.
+ */
+#define CPCAP_REG_CCC1_ACTIVE_MODE1    BIT(4)  /* Update rate */
+#define CPCAP_REG_CCC1_ACTIVE_MODE0    BIT(3)  /* Update rate */
+#define CPCAP_REG_CCC1_AUTOCLEAR       BIT(2)  /* Resets sample registers */
+#define CPCAP_REG_CCC1_CAL_EN          BIT(1)  /* Clears after write in 1s */
+#define CPCAP_REG_CCC1_PAUSE           BIT(0)  /* Stop counters, allow write */
+#define CPCAP_REG_CCC1_RESET_MASK      (CPCAP_REG_CCC1_AUTOCLEAR | \
+                                        CPCAP_REG_CCC1_CAL_EN)
+
+#define CPCAP_REG_CCCC2_RATE1          BIT(5)
+#define CPCAP_REG_CCCC2_RATE0          BIT(4)
+#define CPCAP_REG_CCCC2_ENABLE         BIT(3)
+
 #define CPCAP_BATTERY_CC_SAMPLE_PERIOD_MS      250
 
 enum {
 
 enum cpcap_battery_irq_action {
        CPCAP_BATTERY_IRQ_ACTION_NONE,
+       CPCAP_BATTERY_IRQ_ACTION_CC_CAL_DONE,
        CPCAP_BATTERY_IRQ_ACTION_BATTERY_LOW,
        CPCAP_BATTERY_IRQ_ACTION_POWEROFF,
 };
 };
 
 struct cpcap_battery_config {
-       int ccm;
        int cd_factor;
        struct power_supply_info info;
        struct power_supply_battery_info bat;
        latest = cpcap_battery_latest(ddata);
 
        switch (d->action) {
+       case CPCAP_BATTERY_IRQ_ACTION_CC_CAL_DONE:
+               dev_info(ddata->dev, "Coulomb counter calibration done\n");
+               break;
        case CPCAP_BATTERY_IRQ_ACTION_BATTERY_LOW:
                if (latest->current_ua >= 0)
                        dev_warn(ddata->dev, "Battery low at %imV!\n",
        d->name = name;
        d->irq = irq;
 
-       if (!strncmp(name, "lowbph", 6))
+       if (!strncmp(name, "cccal", 5))
+               d->action = CPCAP_BATTERY_IRQ_ACTION_CC_CAL_DONE;
+       else if (!strncmp(name, "lowbph", 6))
                d->action = CPCAP_BATTERY_IRQ_ACTION_BATTERY_LOW;
        else if (!strncmp(name, "lowbpl", 6))
                d->action = CPCAP_BATTERY_IRQ_ACTION_POWEROFF;
                        return error;
        }
 
+       /* Enable calibration interrupt if already available in dts */
+       cpcap_battery_init_irq(pdev, ddata, "cccal");
+
        /* Enable low battery interrupts for 3.3V high and 3.1V low */
        error = regmap_update_bits(ddata->reg, CPCAP_REG_BPEOL,
                                   0xffff,
        return error;
 }
 
+/* Calibrate coulomb counter */
+static int cpcap_battery_calibrate(struct cpcap_battery_ddata *ddata)
+{
+       int error, ccc1, value;
+       unsigned long timeout;
+
+       error = regmap_read(ddata->reg, CPCAP_REG_CCC1, &ccc1);
+       if (error)
+               return error;
+
+       timeout = jiffies + msecs_to_jiffies(6000);
+
+       /* Start calibration */
+       error = regmap_update_bits(ddata->reg, CPCAP_REG_CCC1,
+                                  0xffff,
+                                  CPCAP_REG_CCC1_CAL_EN);
+       if (error)
+               goto restore;
+
+       while (time_before(jiffies, timeout)) {
+               error = regmap_read(ddata->reg, CPCAP_REG_CCC1, &value);
+               if (error)
+                       goto restore;
+
+               if (!(value & CPCAP_REG_CCC1_CAL_EN))
+                       break;
+
+               error = regmap_read(ddata->reg, CPCAP_REG_CCM, &value);
+               if (error)
+                       goto restore;
+
+               msleep(300);
+       }
+
+       /* Read calibration offset from CCM */
+       error = regmap_read(ddata->reg, CPCAP_REG_CCM, &value);
+       if (error)
+               goto restore;
+
+       dev_info(ddata->dev, "calibration done: 0x%04x\n", value);
+
+restore:
+       if (error)
+               dev_err(ddata->dev, "%s: error %i\n", __func__, error);
+
+       error = regmap_update_bits(ddata->reg, CPCAP_REG_CCC1,
+                                  0xffff, ccc1);
+       if (error)
+               dev_err(ddata->dev, "%s: restore error %i\n",
+                       __func__, error);
+
+       return error;
+}
+
 /*
  * Based on the values from Motorola mapphone Linux kernel. In the
  * the Motorola mapphone Linux kernel tree the value for pm_cd_factor
  * at 3078000. The device will die around 2743000.
  */
 static const struct cpcap_battery_config cpcap_battery_default_data = {
-       .ccm = 0x3ff,
        .cd_factor = 0x3cc,
        .info.technology = POWER_SUPPLY_TECHNOLOGY_LION,
        .info.voltage_max_design = 4351000,
 
        platform_set_drvdata(pdev, ddata);
 
-       error = regmap_update_bits(ddata->reg, CPCAP_REG_CCM,
-                                  0xffff, ddata->config.ccm);
-       if (error)
-               return error;
-
        error = cpcap_battery_init_interrupts(pdev, ddata);
        if (error)
                return error;
 
        atomic_set(&ddata->active, 1);
 
+       error = cpcap_battery_calibrate(ddata);
+       if (error)
+               return error;
+
        return 0;
 }