Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0+
0002 //
0003 // max8997_charger.c - Power supply consumer driver for the Maxim 8997/8966
0004 //
0005 //  Copyright (C) 2011 Samsung Electronics
0006 //  MyungJoo Ham <myungjoo.ham@samsung.com>
0007 
0008 #include <linux/err.h>
0009 #include <linux/extcon.h>
0010 #include <linux/module.h>
0011 #include <linux/slab.h>
0012 #include <linux/platform_device.h>
0013 #include <linux/power_supply.h>
0014 #include <linux/mfd/max8997.h>
0015 #include <linux/mfd/max8997-private.h>
0016 #include <linux/regulator/consumer.h>
0017 #include <linux/devm-helpers.h>
0018 
0019 /* MAX8997_REG_STATUS4 */
0020 #define DCINOK_SHIFT        1
0021 #define DCINOK_MASK     (1 << DCINOK_SHIFT)
0022 #define DETBAT_SHIFT        2
0023 #define DETBAT_MASK     (1 << DETBAT_SHIFT)
0024 
0025 /* MAX8997_REG_MBCCTRL1 */
0026 #define TFCH_SHIFT      4
0027 #define TFCH_MASK       (7 << TFCH_SHIFT)
0028 
0029 /* MAX8997_REG_MBCCTRL5 */
0030 #define ITOPOFF_SHIFT       0
0031 #define ITOPOFF_MASK        (0xF << ITOPOFF_SHIFT)
0032 
0033 struct charger_data {
0034     struct device *dev;
0035     struct max8997_dev *iodev;
0036     struct power_supply *battery;
0037     struct regulator *reg;
0038     struct extcon_dev *edev;
0039     struct notifier_block extcon_nb;
0040     struct work_struct extcon_work;
0041 };
0042 
0043 static enum power_supply_property max8997_battery_props[] = {
0044     POWER_SUPPLY_PROP_STATUS, /* "FULL", "CHARGING" or "DISCHARGING". */
0045     POWER_SUPPLY_PROP_PRESENT, /* the presence of battery */
0046     POWER_SUPPLY_PROP_ONLINE, /* charger is active or not */
0047 };
0048 
0049 /* Note that the charger control is done by a current regulator "CHARGER" */
0050 static int max8997_battery_get_property(struct power_supply *psy,
0051         enum power_supply_property psp,
0052         union power_supply_propval *val)
0053 {
0054     struct charger_data *charger = power_supply_get_drvdata(psy);
0055     struct i2c_client *i2c = charger->iodev->i2c;
0056     int ret;
0057     u8 reg;
0058 
0059     switch (psp) {
0060     case POWER_SUPPLY_PROP_STATUS:
0061         val->intval = 0;
0062         ret = max8997_read_reg(i2c, MAX8997_REG_STATUS4, &reg);
0063         if (ret)
0064             return ret;
0065         if ((reg & (1 << 0)) == 0x1)
0066             val->intval = POWER_SUPPLY_STATUS_FULL;
0067         else if ((reg & DCINOK_MASK))
0068             val->intval = POWER_SUPPLY_STATUS_CHARGING;
0069         else
0070             val->intval = POWER_SUPPLY_STATUS_DISCHARGING;
0071 
0072         break;
0073     case POWER_SUPPLY_PROP_PRESENT:
0074         val->intval = 0;
0075         ret = max8997_read_reg(i2c, MAX8997_REG_STATUS4, &reg);
0076         if (ret)
0077             return ret;
0078         if ((reg & DETBAT_MASK) == 0x0)
0079             val->intval = 1;
0080 
0081         break;
0082     case POWER_SUPPLY_PROP_ONLINE:
0083         val->intval = 0;
0084         ret = max8997_read_reg(i2c, MAX8997_REG_STATUS4, &reg);
0085         if (ret)
0086             return ret;
0087         if (reg & DCINOK_MASK)
0088             val->intval = 1;
0089 
0090         break;
0091     default:
0092         return -EINVAL;
0093     }
0094 
0095     return 0;
0096 }
0097 
0098 static void max8997_battery_extcon_evt_worker(struct work_struct *work)
0099 {
0100     struct charger_data *charger =
0101         container_of(work, struct charger_data, extcon_work);
0102     struct extcon_dev *edev = charger->edev;
0103     int current_limit;
0104 
0105     if (extcon_get_state(edev, EXTCON_CHG_USB_SDP) > 0) {
0106         dev_dbg(charger->dev, "USB SDP charger is connected\n");
0107         current_limit = 450000;
0108     } else if (extcon_get_state(edev, EXTCON_CHG_USB_DCP) > 0) {
0109         dev_dbg(charger->dev, "USB DCP charger is connected\n");
0110         current_limit = 650000;
0111     } else if (extcon_get_state(edev, EXTCON_CHG_USB_FAST) > 0) {
0112         dev_dbg(charger->dev, "USB FAST charger is connected\n");
0113         current_limit = 650000;
0114     } else if (extcon_get_state(edev, EXTCON_CHG_USB_SLOW) > 0) {
0115         dev_dbg(charger->dev, "USB SLOW charger is connected\n");
0116         current_limit = 650000;
0117     } else if (extcon_get_state(edev, EXTCON_CHG_USB_CDP) > 0) {
0118         dev_dbg(charger->dev, "USB CDP charger is connected\n");
0119         current_limit = 650000;
0120     } else {
0121         dev_dbg(charger->dev, "USB charger is disconnected\n");
0122         current_limit = -1;
0123     }
0124 
0125     if (current_limit > 0) {
0126         int ret = regulator_set_current_limit(charger->reg, current_limit, current_limit);
0127 
0128         if (ret) {
0129             dev_err(charger->dev, "failed to set current limit: %d\n", ret);
0130             return;
0131         }
0132         ret = regulator_enable(charger->reg);
0133         if (ret)
0134             dev_err(charger->dev, "failed to enable regulator: %d\n", ret);
0135     } else {
0136         int ret  = regulator_disable(charger->reg);
0137 
0138         if (ret)
0139             dev_err(charger->dev, "failed to disable regulator: %d\n", ret);
0140     }
0141 }
0142 
0143 static int max8997_battery_extcon_evt(struct notifier_block *nb,
0144                 unsigned long event, void *param)
0145 {
0146     struct charger_data *charger =
0147         container_of(nb, struct charger_data, extcon_nb);
0148     schedule_work(&charger->extcon_work);
0149     return NOTIFY_OK;
0150 }
0151 
0152 static const struct power_supply_desc max8997_battery_desc = {
0153     .name       = "max8997_pmic",
0154     .type       = POWER_SUPPLY_TYPE_BATTERY,
0155     .get_property   = max8997_battery_get_property,
0156     .properties = max8997_battery_props,
0157     .num_properties = ARRAY_SIZE(max8997_battery_props),
0158 };
0159 
0160 static int max8997_battery_probe(struct platform_device *pdev)
0161 {
0162     int ret = 0;
0163     struct charger_data *charger;
0164     struct max8997_dev *iodev = dev_get_drvdata(pdev->dev.parent);
0165     struct device_node *np = pdev->dev.of_node;
0166     struct i2c_client *i2c = iodev->i2c;
0167     struct max8997_platform_data *pdata = iodev->pdata;
0168     struct power_supply_config psy_cfg = {};
0169 
0170     if (!pdata) {
0171         dev_err(&pdev->dev, "No platform data supplied.\n");
0172         return -EINVAL;
0173     }
0174 
0175     if (pdata->eoc_mA) {
0176         int val = (pdata->eoc_mA - 50) / 10;
0177         if (val < 0)
0178             val = 0;
0179         if (val > 0xf)
0180             val = 0xf;
0181 
0182         ret = max8997_update_reg(i2c, MAX8997_REG_MBCCTRL5,
0183                 val << ITOPOFF_SHIFT, ITOPOFF_MASK);
0184         if (ret < 0) {
0185             dev_err(&pdev->dev, "Cannot use i2c bus.\n");
0186             return ret;
0187         }
0188     }
0189     switch (pdata->timeout) {
0190     case 5:
0191         ret = max8997_update_reg(i2c, MAX8997_REG_MBCCTRL1,
0192                 0x2 << TFCH_SHIFT, TFCH_MASK);
0193         break;
0194     case 6:
0195         ret = max8997_update_reg(i2c, MAX8997_REG_MBCCTRL1,
0196                 0x3 << TFCH_SHIFT, TFCH_MASK);
0197         break;
0198     case 7:
0199         ret = max8997_update_reg(i2c, MAX8997_REG_MBCCTRL1,
0200                 0x4 << TFCH_SHIFT, TFCH_MASK);
0201         break;
0202     case 0:
0203         ret = max8997_update_reg(i2c, MAX8997_REG_MBCCTRL1,
0204                 0x7 << TFCH_SHIFT, TFCH_MASK);
0205         break;
0206     default:
0207         dev_err(&pdev->dev, "incorrect timeout value (%d)\n",
0208                 pdata->timeout);
0209         return -EINVAL;
0210     }
0211     if (ret < 0) {
0212         dev_err(&pdev->dev, "Cannot use i2c bus.\n");
0213         return ret;
0214     }
0215 
0216     charger = devm_kzalloc(&pdev->dev, sizeof(*charger), GFP_KERNEL);
0217     if (!charger)
0218         return -ENOMEM;
0219 
0220     platform_set_drvdata(pdev, charger);
0221 
0222     charger->dev = &pdev->dev;
0223     charger->iodev = iodev;
0224 
0225     psy_cfg.drv_data = charger;
0226 
0227     charger->battery = devm_power_supply_register(&pdev->dev,
0228                          &max8997_battery_desc,
0229                          &psy_cfg);
0230     if (IS_ERR(charger->battery)) {
0231         dev_err(&pdev->dev, "failed: power supply register\n");
0232         return PTR_ERR(charger->battery);
0233     }
0234 
0235     // grab regulator from parent device's node
0236     pdev->dev.of_node = iodev->dev->of_node;
0237     charger->reg = devm_regulator_get_optional(&pdev->dev, "charger");
0238     pdev->dev.of_node = np;
0239     if (IS_ERR(charger->reg)) {
0240         if (PTR_ERR(charger->reg) == -EPROBE_DEFER)
0241             return -EPROBE_DEFER;
0242         dev_info(&pdev->dev, "couldn't get charger regulator\n");
0243     }
0244     charger->edev = extcon_get_extcon_dev("max8997-muic");
0245     if (IS_ERR(charger->edev)) {
0246         dev_err_probe(charger->dev, PTR_ERR(charger->edev),
0247                   "couldn't get extcon device: max8997-muic\n");
0248         return PTR_ERR(charger->edev);
0249     }
0250 
0251     if (!IS_ERR(charger->reg) && !IS_ERR_OR_NULL(charger->edev)) {
0252         ret = devm_work_autocancel(&pdev->dev, &charger->extcon_work,
0253                        max8997_battery_extcon_evt_worker);
0254         if (ret) {
0255             dev_err(&pdev->dev, "failed to add extcon evt stop action: %d\n", ret);
0256             return ret;
0257         }
0258         charger->extcon_nb.notifier_call = max8997_battery_extcon_evt;
0259         ret = devm_extcon_register_notifier_all(&pdev->dev, charger->edev,
0260                             &charger->extcon_nb);
0261         if (ret) {
0262             dev_err(&pdev->dev, "failed to register extcon notifier\n");
0263             return ret;
0264         }
0265     }
0266 
0267     return 0;
0268 }
0269 
0270 static const struct platform_device_id max8997_battery_id[] = {
0271     { "max8997-battery", 0 },
0272     { }
0273 };
0274 MODULE_DEVICE_TABLE(platform, max8997_battery_id);
0275 
0276 static struct platform_driver max8997_battery_driver = {
0277     .driver = {
0278         .name = "max8997-battery",
0279     },
0280     .probe = max8997_battery_probe,
0281     .id_table = max8997_battery_id,
0282 };
0283 module_platform_driver(max8997_battery_driver);
0284 
0285 MODULE_DESCRIPTION("MAXIM 8997/8966 battery control driver");
0286 MODULE_AUTHOR("MyungJoo Ham <myungjoo.ham@samsung.com>");
0287 MODULE_LICENSE("GPL");