linux/drivers/power/supply/max8997_charger.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2//
   3// max8997_charger.c - Power supply consumer driver for the Maxim 8997/8966
   4//
   5//  Copyright (C) 2011 Samsung Electronics
   6//  MyungJoo Ham <myungjoo.ham@samsung.com>
   7
   8#include <linux/err.h>
   9#include <linux/module.h>
  10#include <linux/slab.h>
  11#include <linux/platform_device.h>
  12#include <linux/power_supply.h>
  13#include <linux/mfd/max8997.h>
  14#include <linux/mfd/max8997-private.h>
  15
  16struct charger_data {
  17        struct device *dev;
  18        struct max8997_dev *iodev;
  19        struct power_supply *battery;
  20};
  21
  22static enum power_supply_property max8997_battery_props[] = {
  23        POWER_SUPPLY_PROP_STATUS, /* "FULL" or "NOT FULL" only. */
  24        POWER_SUPPLY_PROP_PRESENT, /* the presence of battery */
  25        POWER_SUPPLY_PROP_ONLINE, /* charger is active or not */
  26};
  27
  28/* Note that the charger control is done by a current regulator "CHARGER" */
  29static int max8997_battery_get_property(struct power_supply *psy,
  30                enum power_supply_property psp,
  31                union power_supply_propval *val)
  32{
  33        struct charger_data *charger = power_supply_get_drvdata(psy);
  34        struct i2c_client *i2c = charger->iodev->i2c;
  35        int ret;
  36        u8 reg;
  37
  38        switch (psp) {
  39        case POWER_SUPPLY_PROP_STATUS:
  40                val->intval = 0;
  41                ret = max8997_read_reg(i2c, MAX8997_REG_STATUS4, &reg);
  42                if (ret)
  43                        return ret;
  44                if ((reg & (1 << 0)) == 0x1)
  45                        val->intval = POWER_SUPPLY_STATUS_FULL;
  46
  47                break;
  48        case POWER_SUPPLY_PROP_PRESENT:
  49                val->intval = 0;
  50                ret = max8997_read_reg(i2c, MAX8997_REG_STATUS4, &reg);
  51                if (ret)
  52                        return ret;
  53                if ((reg & (1 << 2)) == 0x0)
  54                        val->intval = 1;
  55
  56                break;
  57        case POWER_SUPPLY_PROP_ONLINE:
  58                val->intval = 0;
  59                ret = max8997_read_reg(i2c, MAX8997_REG_STATUS4, &reg);
  60                if (ret)
  61                        return ret;
  62                /* DCINOK */
  63                if (reg & (1 << 1))
  64                        val->intval = 1;
  65
  66                break;
  67        default:
  68                return -EINVAL;
  69        }
  70
  71        return 0;
  72}
  73
  74static const struct power_supply_desc max8997_battery_desc = {
  75        .name           = "max8997_pmic",
  76        .type           = POWER_SUPPLY_TYPE_BATTERY,
  77        .get_property   = max8997_battery_get_property,
  78        .properties     = max8997_battery_props,
  79        .num_properties = ARRAY_SIZE(max8997_battery_props),
  80};
  81
  82static int max8997_battery_probe(struct platform_device *pdev)
  83{
  84        int ret = 0;
  85        struct charger_data *charger;
  86        struct max8997_dev *iodev = dev_get_drvdata(pdev->dev.parent);
  87        struct max8997_platform_data *pdata = dev_get_platdata(iodev->dev);
  88        struct power_supply_config psy_cfg = {};
  89
  90        if (!pdata)
  91                return -EINVAL;
  92
  93        if (pdata->eoc_mA) {
  94                int val = (pdata->eoc_mA - 50) / 10;
  95                if (val < 0)
  96                        val = 0;
  97                if (val > 0xf)
  98                        val = 0xf;
  99
 100                ret = max8997_update_reg(iodev->i2c,
 101                                MAX8997_REG_MBCCTRL5, val, 0xf);
 102                if (ret < 0) {
 103                        dev_err(&pdev->dev, "Cannot use i2c bus.\n");
 104                        return ret;
 105                }
 106        }
 107
 108        switch (pdata->timeout) {
 109        case 5:
 110                ret = max8997_update_reg(iodev->i2c, MAX8997_REG_MBCCTRL1,
 111                                0x2 << 4, 0x7 << 4);
 112                break;
 113        case 6:
 114                ret = max8997_update_reg(iodev->i2c, MAX8997_REG_MBCCTRL1,
 115                                0x3 << 4, 0x7 << 4);
 116                break;
 117        case 7:
 118                ret = max8997_update_reg(iodev->i2c, MAX8997_REG_MBCCTRL1,
 119                                0x4 << 4, 0x7 << 4);
 120                break;
 121        case 0:
 122                ret = max8997_update_reg(iodev->i2c, MAX8997_REG_MBCCTRL1,
 123                                0x7 << 4, 0x7 << 4);
 124                break;
 125        default:
 126                dev_err(&pdev->dev, "incorrect timeout value (%d)\n",
 127                                pdata->timeout);
 128                return -EINVAL;
 129        }
 130        if (ret < 0) {
 131                dev_err(&pdev->dev, "Cannot use i2c bus.\n");
 132                return ret;
 133        }
 134
 135        charger = devm_kzalloc(&pdev->dev, sizeof(*charger), GFP_KERNEL);
 136        if (!charger)
 137                return -ENOMEM;
 138
 139        platform_set_drvdata(pdev, charger);
 140
 141
 142        charger->dev = &pdev->dev;
 143        charger->iodev = iodev;
 144
 145        psy_cfg.drv_data = charger;
 146
 147        charger->battery = devm_power_supply_register(&pdev->dev,
 148                                                 &max8997_battery_desc,
 149                                                 &psy_cfg);
 150        if (IS_ERR(charger->battery)) {
 151                dev_err(&pdev->dev, "failed: power supply register\n");
 152                return PTR_ERR(charger->battery);
 153        }
 154
 155        return 0;
 156}
 157
 158static const struct platform_device_id max8997_battery_id[] = {
 159        { "max8997-battery", 0 },
 160        { }
 161};
 162MODULE_DEVICE_TABLE(platform, max8997_battery_id);
 163
 164static struct platform_driver max8997_battery_driver = {
 165        .driver = {
 166                .name = "max8997-battery",
 167        },
 168        .probe = max8997_battery_probe,
 169        .id_table = max8997_battery_id,
 170};
 171
 172static int __init max8997_battery_init(void)
 173{
 174        return platform_driver_register(&max8997_battery_driver);
 175}
 176subsys_initcall(max8997_battery_init);
 177
 178static void __exit max8997_battery_cleanup(void)
 179{
 180        platform_driver_unregister(&max8997_battery_driver);
 181}
 182module_exit(max8997_battery_cleanup);
 183
 184MODULE_DESCRIPTION("MAXIM 8997/8966 battery control driver");
 185MODULE_AUTHOR("MyungJoo Ham <myungjoo.ham@samsung.com>");
 186MODULE_LICENSE("GPL");
 187