Commit 149c077b4bd746eca2eeb241e55456eb4882b259

Authored by Donggeun Kim
Committed by Anton Vorontsov
1 parent 7c4509b4cd

power_supply: Add charger driver for MAX8997/8966

MAX8997/8966 chip is a multi-function device which includes
PMIC, RTC, Fuel Gauge, MUIC, Haptic, Flash control, and
Battery charging control.
The driver for it is located at drivers/mfd.

This patch supports battery charging control of MAX8997/8966 chip and
provides power supply class information to userspace.

Signed-off-by: Donggeun Kim <dg77.kim@samsung.com>
Signed-off-by: MyungJoo Ham <myungjoo.ham@samsung.com>
Signed-off-by: KyungMin Park <kyungmin.park@samsung.com>
Acked-by: Samuel Ortiz <sameo@linux.intel.com>
Signed-off-by: Anton Vorontsov <cbouatmailru@gmail.com>

Showing 4 changed files with 220 additions and 1 deletions Side-by-side Diff

drivers/power/Kconfig
... ... @@ -228,5 +228,12 @@
228 228 This driver can be build as a module. If so, the module will be
229 229 called gpio-charger.
230 230  
  231 +config CHARGER_MAX8997
  232 + tristate "Maxim MAX8997/MAX8966 PMIC battery charger driver"
  233 + depends on MFD_MAX8997 && REGULATOR_MAX8997
  234 + help
  235 + Say Y to enable support for the battery charger control sysfs and
  236 + platform data of MAX8997/LP3974 PMICs.
  237 +
231 238 endif # POWER_SUPPLY
drivers/power/Makefile
... ... @@ -35,4 +35,5 @@
35 35 obj-$(CONFIG_CHARGER_MAX8903) += max8903_charger.o
36 36 obj-$(CONFIG_CHARGER_TWL4030) += twl4030_charger.o
37 37 obj-$(CONFIG_CHARGER_GPIO) += gpio-charger.o
  38 +obj-$(CONFIG_CHARGER_MAX8997) += max8997_charger.o
drivers/power/max8997_charger.c
  1 +/*
  2 + * max8997_charger.c - Power supply consumer driver for the Maxim 8997/8966
  3 + *
  4 + * Copyright (C) 2011 Samsung Electronics
  5 + * MyungJoo Ham <myungjoo.ham@samsung.com>
  6 + *
  7 + * This program is free software; you can redistribute it and/or modify
  8 + * it under the terms of the GNU General Public License as published by
  9 + * the Free Software Foundation; either version 2 of the License, or
  10 + * (at your option) any later version.
  11 + *
  12 + * This program is distributed in the hope that it will be useful,
  13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15 + * GNU General Public License for more details.
  16 + *
  17 + * You should have received a copy of the GNU General Public License
  18 + * along with this program; if not, write to the Free Software
  19 + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  20 + */
  21 +
  22 +#include <linux/err.h>
  23 +#include <linux/slab.h>
  24 +#include <linux/platform_device.h>
  25 +#include <linux/power_supply.h>
  26 +#include <linux/mfd/max8997.h>
  27 +#include <linux/mfd/max8997-private.h>
  28 +
  29 +struct charger_data {
  30 + struct device *dev;
  31 + struct max8997_dev *iodev;
  32 + struct power_supply battery;
  33 +};
  34 +
  35 +static enum power_supply_property max8997_battery_props[] = {
  36 + POWER_SUPPLY_PROP_STATUS, /* "FULL" or "NOT FULL" only. */
  37 + POWER_SUPPLY_PROP_PRESENT, /* the presence of battery */
  38 + POWER_SUPPLY_PROP_ONLINE, /* charger is active or not */
  39 +};
  40 +
  41 +/* Note that the charger control is done by a current regulator "CHARGER" */
  42 +static int max8997_battery_get_property(struct power_supply *psy,
  43 + enum power_supply_property psp,
  44 + union power_supply_propval *val)
  45 +{
  46 + struct charger_data *charger = container_of(psy,
  47 + struct charger_data, battery);
  48 + struct i2c_client *i2c = charger->iodev->i2c;
  49 + int ret;
  50 + u8 reg;
  51 +
  52 + switch (psp) {
  53 + case POWER_SUPPLY_PROP_STATUS:
  54 + val->intval = 0;
  55 + ret = max8997_read_reg(i2c, MAX8997_REG_STATUS4, &reg);
  56 + if (ret)
  57 + return ret;
  58 + if ((reg & (1 << 0)) == 0x1)
  59 + val->intval = POWER_SUPPLY_STATUS_FULL;
  60 +
  61 + break;
  62 + case POWER_SUPPLY_PROP_PRESENT:
  63 + val->intval = 0;
  64 + ret = max8997_read_reg(i2c, MAX8997_REG_STATUS4, &reg);
  65 + if (ret)
  66 + return ret;
  67 + if ((reg & (1 << 2)) == 0x0)
  68 + val->intval = 1;
  69 +
  70 + break;
  71 + case POWER_SUPPLY_PROP_ONLINE:
  72 + val->intval = 0;
  73 + ret = max8997_read_reg(i2c, MAX8997_REG_STATUS4, &reg);
  74 + if (ret)
  75 + return ret;
  76 + /* DCINOK */
  77 + if (reg & (1 << 1))
  78 + val->intval = 1;
  79 +
  80 + break;
  81 + default:
  82 + return -EINVAL;
  83 + }
  84 +
  85 + return 0;
  86 +}
  87 +
  88 +static __devinit int max8997_battery_probe(struct platform_device *pdev)
  89 +{
  90 + int ret = 0;
  91 + struct charger_data *charger;
  92 + struct max8997_dev *iodev = dev_get_drvdata(pdev->dev.parent);
  93 + struct max8997_platform_data *pdata = dev_get_platdata(iodev->dev);
  94 +
  95 + if (!pdata)
  96 + return -EINVAL;
  97 +
  98 + if (pdata->eoc_mA) {
  99 + u8 val = (pdata->eoc_mA - 50) / 10;
  100 + if (val < 0)
  101 + val = 0;
  102 + if (val > 0xf)
  103 + val = 0xf;
  104 +
  105 + ret = max8997_update_reg(iodev->i2c,
  106 + MAX8997_REG_MBCCTRL5, val, 0xf);
  107 + if (ret < 0) {
  108 + dev_err(&pdev->dev, "Cannot use i2c bus.\n");
  109 + return ret;
  110 + }
  111 + }
  112 +
  113 + switch (pdata->timeout) {
  114 + case 5:
  115 + ret = max8997_update_reg(iodev->i2c, MAX8997_REG_MBCCTRL1,
  116 + 0x2 << 4, 0x7 << 4);
  117 + break;
  118 + case 6:
  119 + ret = max8997_update_reg(iodev->i2c, MAX8997_REG_MBCCTRL1,
  120 + 0x3 << 4, 0x7 << 4);
  121 + break;
  122 + case 7:
  123 + ret = max8997_update_reg(iodev->i2c, MAX8997_REG_MBCCTRL1,
  124 + 0x4 << 4, 0x7 << 4);
  125 + break;
  126 + case 0:
  127 + ret = max8997_update_reg(iodev->i2c, MAX8997_REG_MBCCTRL1,
  128 + 0x7 << 4, 0x7 << 4);
  129 + break;
  130 + default:
  131 + dev_err(&pdev->dev, "incorrect timeout value (%d)\n",
  132 + pdata->timeout);
  133 + return -EINVAL;
  134 + }
  135 + if (ret < 0) {
  136 + dev_err(&pdev->dev, "Cannot use i2c bus.\n");
  137 + return ret;
  138 + }
  139 +
  140 + charger = kzalloc(sizeof(struct charger_data), GFP_KERNEL);
  141 + if (charger == NULL) {
  142 + dev_err(&pdev->dev, "Cannot allocate memory.\n");
  143 + return -ENOMEM;
  144 + }
  145 +
  146 + platform_set_drvdata(pdev, charger);
  147 +
  148 + charger->battery.name = "max8997_pmic";
  149 + charger->battery.type = POWER_SUPPLY_TYPE_BATTERY;
  150 + charger->battery.get_property = max8997_battery_get_property;
  151 + charger->battery.properties = max8997_battery_props;
  152 + charger->battery.num_properties = ARRAY_SIZE(max8997_battery_props);
  153 +
  154 + charger->dev = &pdev->dev;
  155 + charger->iodev = iodev;
  156 +
  157 + ret = power_supply_register(&pdev->dev, &charger->battery);
  158 + if (ret) {
  159 + dev_err(&pdev->dev, "failed: power supply register\n");
  160 + goto err;
  161 + }
  162 +
  163 + return 0;
  164 +err:
  165 + kfree(charger);
  166 + return ret;
  167 +}
  168 +
  169 +static int __devexit max8997_battery_remove(struct platform_device *pdev)
  170 +{
  171 + struct charger_data *charger = platform_get_drvdata(pdev);
  172 +
  173 + power_supply_unregister(&charger->battery);
  174 + kfree(charger);
  175 + return 0;
  176 +}
  177 +
  178 +static const struct platform_device_id max8997_battery_id[] = {
  179 + { "max8997-battery", 0 },
  180 +};
  181 +
  182 +static struct platform_driver max8997_battery_driver = {
  183 + .driver = {
  184 + .name = "max8997-battery",
  185 + .owner = THIS_MODULE,
  186 + },
  187 + .probe = max8997_battery_probe,
  188 + .remove = __devexit_p(max8997_battery_remove),
  189 + .id_table = max8997_battery_id,
  190 +};
  191 +
  192 +static int __init max8997_battery_init(void)
  193 +{
  194 + return platform_driver_register(&max8997_battery_driver);
  195 +}
  196 +subsys_initcall(max8997_battery_init);
  197 +
  198 +static void __exit max8997_battery_cleanup(void)
  199 +{
  200 + platform_driver_unregister(&max8997_battery_driver);
  201 +}
  202 +module_exit(max8997_battery_cleanup);
  203 +
  204 +MODULE_DESCRIPTION("MAXIM 8997/8966 battery control driver");
  205 +MODULE_AUTHOR("MyungJoo Ham <myungjoo.ham@samsung.com>");
  206 +MODULE_LICENSE("GPL");
include/linux/mfd/max8997.h
... ... @@ -107,11 +107,16 @@
107 107 unsigned int buck5_voltage[8];
108 108 bool buck5_gpiodvs;
109 109  
  110 + /* ---- Charger control ---- */
  111 + /* eoc stands for 'end of charge' */
  112 + int eoc_mA; /* 50 ~ 200mA by 10mA step */
  113 + /* charge Full Timeout */
  114 + int timeout; /* 0 (no timeout), 5, 6, 7 hours */
  115 +
110 116 /* MUIC: Not implemented */
111 117 /* HAPTIC: Not implemented */
112 118 /* RTC: Not implemented */
113 119 /* Flash: Not implemented */
114   - /* Charger control: Not implemented */
115 120 };
116 121  
117 122 #endif /* __LINUX_MFD_MAX8998_H */