^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0+
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) //
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) // max8998_charger.c - Power supply consumer driver for the Maxim 8998/LP3974
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) //
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) // Copyright (C) 2009-2010 Samsung Electronics
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) // MyungJoo Ham <myungjoo.ham@samsung.com>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) #include <linux/err.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) #include <linux/mod_devicetable.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) #include <linux/slab.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) #include <linux/platform_device.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #include <linux/power_supply.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) #include <linux/mfd/max8998.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) #include <linux/mfd/max8998-private.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) struct max8998_battery_data {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) struct device *dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) struct max8998_dev *iodev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) struct power_supply *battery;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) static enum power_supply_property max8998_battery_props[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) POWER_SUPPLY_PROP_PRESENT, /* the presence of battery */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) POWER_SUPPLY_PROP_ONLINE, /* charger is active or not */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) POWER_SUPPLY_PROP_STATUS, /* charger is charging/discharging/full */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) /* Note that the charger control is done by a current regulator "CHARGER" */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) static int max8998_battery_get_property(struct power_supply *psy,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) enum power_supply_property psp,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) union power_supply_propval *val)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) struct max8998_battery_data *max8998 = power_supply_get_drvdata(psy);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) struct i2c_client *i2c = max8998->iodev->i2c;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) u8 reg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) switch (psp) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) case POWER_SUPPLY_PROP_PRESENT:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) ret = max8998_read_reg(i2c, MAX8998_REG_STATUS2, ®);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) if (reg & (1 << 4))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) val->intval = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) val->intval = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) case POWER_SUPPLY_PROP_ONLINE:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) ret = max8998_read_reg(i2c, MAX8998_REG_STATUS2, ®);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) if (reg & (1 << 5))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) val->intval = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) val->intval = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) case POWER_SUPPLY_PROP_STATUS:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) ret = max8998_read_reg(i2c, MAX8998_REG_STATUS2, ®);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) if (!(reg & (1 << 5))) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) val->intval = POWER_SUPPLY_STATUS_DISCHARGING;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) if (reg & (1 << 6))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) val->intval = POWER_SUPPLY_STATUS_FULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) else if (reg & (1 << 3))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) val->intval = POWER_SUPPLY_STATUS_CHARGING;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) static const struct power_supply_desc max8998_battery_desc = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) .name = "max8998_pmic",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) .type = POWER_SUPPLY_TYPE_BATTERY,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) .get_property = max8998_battery_get_property,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) .properties = max8998_battery_props,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) .num_properties = ARRAY_SIZE(max8998_battery_props),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) static int max8998_battery_probe(struct platform_device *pdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) struct max8998_dev *iodev = dev_get_drvdata(pdev->dev.parent);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) struct max8998_platform_data *pdata = iodev->pdata;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) struct power_supply_config psy_cfg = {};
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) struct max8998_battery_data *max8998;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) struct i2c_client *i2c;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) int ret = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) if (!pdata) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) dev_err(pdev->dev.parent, "No platform init data supplied\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) max8998 = devm_kzalloc(&pdev->dev, sizeof(struct max8998_battery_data),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) if (!max8998)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) max8998->dev = &pdev->dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) max8998->iodev = iodev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) platform_set_drvdata(pdev, max8998);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) i2c = max8998->iodev->i2c;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) /* Setup "End of Charge" */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) /* If EOC value equals 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) * remain value set from bootloader or default value */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) if (pdata->eoc >= 10 && pdata->eoc <= 45) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) max8998_update_reg(i2c, MAX8998_REG_CHGR1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) (pdata->eoc / 5 - 2) << 5, 0x7 << 5);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) } else if (pdata->eoc == 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) dev_dbg(max8998->dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) "EOC value not set: leave it unchanged.\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) dev_err(max8998->dev, "Invalid EOC value\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) /* Setup Charge Restart Level */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) switch (pdata->restart) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) case 100:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) max8998_update_reg(i2c, MAX8998_REG_CHGR1, 0x1 << 3, 0x3 << 3);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) case 150:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) max8998_update_reg(i2c, MAX8998_REG_CHGR1, 0x0 << 3, 0x3 << 3);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) case 200:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) max8998_update_reg(i2c, MAX8998_REG_CHGR1, 0x2 << 3, 0x3 << 3);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) case -1:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) max8998_update_reg(i2c, MAX8998_REG_CHGR1, 0x3 << 3, 0x3 << 3);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) case 0:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) dev_dbg(max8998->dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) "Restart Level not set: leave it unchanged.\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) dev_err(max8998->dev, "Invalid Restart Level\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) /* Setup Charge Full Timeout */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) switch (pdata->timeout) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) case 5:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) max8998_update_reg(i2c, MAX8998_REG_CHGR2, 0x0 << 4, 0x3 << 4);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) case 6:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) max8998_update_reg(i2c, MAX8998_REG_CHGR2, 0x1 << 4, 0x3 << 4);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) case 7:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) max8998_update_reg(i2c, MAX8998_REG_CHGR2, 0x2 << 4, 0x3 << 4);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) case -1:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) max8998_update_reg(i2c, MAX8998_REG_CHGR2, 0x3 << 4, 0x3 << 4);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) case 0:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) dev_dbg(max8998->dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) "Full Timeout not set: leave it unchanged.\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) dev_err(max8998->dev, "Invalid Full Timeout value\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) psy_cfg.drv_data = max8998;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) max8998->battery = devm_power_supply_register(max8998->dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) &max8998_battery_desc,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) &psy_cfg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) if (IS_ERR(max8998->battery)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) ret = PTR_ERR(max8998->battery);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) dev_err(max8998->dev, "failed: power supply register: %d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) ret);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) static const struct platform_device_id max8998_battery_id[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) { "max8998-battery", TYPE_MAX8998 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) { }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) static struct platform_driver max8998_battery_driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) .driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) .name = "max8998-battery",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) .probe = max8998_battery_probe,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) .id_table = max8998_battery_id,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) module_platform_driver(max8998_battery_driver);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) MODULE_DESCRIPTION("MAXIM 8998 battery control driver");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) MODULE_AUTHOR("MyungJoo Ham <myungjoo.ham@samsung.com>");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) MODULE_LICENSE("GPL");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) MODULE_ALIAS("platform:max8998-battery");