diff options
author | Tom Cherry <tcherry@nvidia.com> | 2011-01-05 11:51:13 -0800 |
---|---|---|
committer | Dan Willemsen <dwillemsen@nvidia.com> | 2011-11-30 21:43:08 -0800 |
commit | 88a2475142fe6044acb50781a44e368782622af8 (patch) | |
tree | b5397122c9a6fc6a21eb4efe5ee50e8d6dd257f6 | |
parent | 0e5eec3307ce47cb03f9405b1c227b400611b24b (diff) |
max8907c Charger Driver
max8907c Charger Driver from maxim plus nvidia modifications
Integration from http://git-master/r/#change,15043
Original-Change-Id: I8143fee9c99b43ad1089613236410dc8ad5bbca0
Reviewed-on: http://git-master/r/16134
Tested-by: Thomas Cherry <tcherry@nvidia.com>
Reviewed-by: Sachin Nikam <snikam@nvidia.com>
Reviewed-by: Bharat Nihalani <bnihalani@nvidia.com>
Rebase-Id: R14961f2b240e4d3019836231b1be9e719b5f478b
-rw-r--r-- | drivers/power/Kconfig | 7 | ||||
-rw-r--r-- | drivers/power/Makefile | 1 | ||||
-rw-r--r-- | drivers/power/max8907c-charger.c | 228 | ||||
-rw-r--r-- | include/linux/power/max8907c-charger.h | 64 |
4 files changed, 300 insertions, 0 deletions
diff --git a/drivers/power/Kconfig b/drivers/power/Kconfig index 57de051a74b3..c12421d688d7 100644 --- a/drivers/power/Kconfig +++ b/drivers/power/Kconfig @@ -36,6 +36,13 @@ config MAX8925_POWER Say Y here to enable support for the battery charger in the Maxim MAX8925 PMIC. +config MAX8907C_CHARGER + tristate "MAX8907c charger support" + depends on MFD_MAX8907C + help + Say Y here to enable support for the charger in the Maxim + MAX8907c PMIC. + config WM831X_BACKUP tristate "WM831X backup battery charger support" depends on MFD_WM831X diff --git a/drivers/power/Makefile b/drivers/power/Makefile index b4af13dd8b66..72124bbf6776 100644 --- a/drivers/power/Makefile +++ b/drivers/power/Makefile @@ -38,3 +38,4 @@ obj-$(CONFIG_CHARGER_TWL4030) += twl4030_charger.o obj-$(CONFIG_CHARGER_GPIO) += gpio-charger.o obj-$(CONFIG_CHARGER_MAX8997) += max8997_charger.o obj-$(CONFIG_CHARGER_MAX8998) += max8998_charger.o +obj-$(CONFIG_MAX8907C_CHARGER) += max8907c-charger.o diff --git a/drivers/power/max8907c-charger.c b/drivers/power/max8907c-charger.c new file mode 100644 index 000000000000..64855c589b15 --- /dev/null +++ b/drivers/power/max8907c-charger.c @@ -0,0 +1,228 @@ +/* + * Battery driver for Maxim MAX8907C + * + * Copyright (c) 2011, NVIDIA Corporation. + * Copyright (C) 2010 Gyungoh Yoo <jack.yoo@maxim-ic.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include <linux/module.h> +#include <linux/err.h> +#include <linux/interrupt.h> +#include <linux/platform_device.h> +#include <linux/power_supply.h> +#include <linux/mfd/max8907c.h> +#include <linux/power/max8907c-charger.h> +#include <linux/slab.h> + +struct max8907c_charger { + struct max8907c_charger_pdata *pdata; + struct max8907c *chip; + struct i2c_client *i2c; + int online; +}; + +static void max8907c_set_charger(struct max8907c_charger *charger) +{ + struct max8907c_charger_pdata *pdata = charger->pdata; + int ret; + if (charger->online) { + ret = max8907c_reg_write(charger->i2c, MAX8907C_REG_CHG_CNTL1, + (pdata->topoff_threshold << 5) | + (pdata->restart_hysteresis << 3) | + (pdata->fast_charging_current)); + if (unlikely(ret != 0)) + pr_err("Failed to set CHG_CNTL1: %d\n", ret); + + ret = max8907c_set_bits(charger->i2c, MAX8907C_REG_CHG_CNTL2, + 0x30, pdata->fast_charger_time << 4); + if (unlikely(ret != 0)) + pr_err("Failed to set CHG_CNTL2: %d\n", ret); + } else { + ret = max8907c_set_bits(charger->i2c, MAX8907C_REG_CHG_CNTL1, 0x80, 0x1); + if (unlikely(ret != 0)) + pr_err("Failed to set CHG_CNTL1: %d\n", ret); + } +} + +static irqreturn_t max8907c_charger_isr(int irq, void *dev_id) +{ + struct max8907c_charger *charger = dev_id; + struct max8907c *chip = charger->chip; + + switch (irq - chip->irq_base) { + case MAX8907C_IRQ_VCHG_DC_R: + charger->online = 1; + max8907c_set_charger(charger); + break; + case MAX8907C_IRQ_VCHG_DC_F: + charger->online = 0; + max8907c_set_charger(charger); + break; + } + + return IRQ_HANDLED; +} + +static int max8907c_charger_get_property(struct power_supply *psy, + enum power_supply_property psp, + union power_supply_propval *val) +{ + const static int types[] = { + POWER_SUPPLY_CHARGE_TYPE_TRICKLE, + POWER_SUPPLY_CHARGE_TYPE_FAST, + POWER_SUPPLY_CHARGE_TYPE_FAST, + POWER_SUPPLY_CHARGE_TYPE_NONE, + }; + int ret = -ENODEV; + int status; + + struct max8907c_charger *charger = dev_get_drvdata(psy->dev->parent); + + switch (psp) { + case POWER_SUPPLY_PROP_ONLINE: + val->intval = charger->online; + ret = 0; + break; + + case POWER_SUPPLY_PROP_STATUS: + /* Get charger status from CHG_EN_STAT */ + status = max8907c_reg_read(charger->i2c, MAX8907C_REG_CHG_STAT); + val->intval = ((status & 0x10) == 0x10) ? + POWER_SUPPLY_STATUS_CHARGING : + POWER_SUPPLY_STATUS_NOT_CHARGING; + ret = 0; + break; + + case POWER_SUPPLY_PROP_CHARGE_TYPE: + /* Get charging type from CHG_MODE */ + status = max8907c_reg_read(charger->i2c, MAX8907C_REG_CHG_STAT); + val->intval = types[(status & 0x0C) >> 2]; + ret = 0; + break; + + default: + val->intval = 0; + ret = -EINVAL; + break; + } + return ret; +} + +static enum power_supply_property max8907c_charger_props[] = { + POWER_SUPPLY_PROP_ONLINE, + POWER_SUPPLY_PROP_STATUS, + POWER_SUPPLY_PROP_CHARGE_TYPE, +}; + +static struct power_supply max8907c_charger_ps = { + .name = "charger", + .type = POWER_SUPPLY_TYPE_MAINS, + .properties = max8907c_charger_props, + .num_properties = ARRAY_SIZE(max8907c_charger_props), + .get_property = max8907c_charger_get_property, +}; + +static __devinit int max8907c_charger_probe(struct platform_device *pdev) +{ + struct max8907c_charger_pdata *pdata = pdev->dev.platform_data; + struct max8907c_charger *charger = 0; + struct max8907c *chip = dev_get_drvdata(pdev->dev.parent); + int ret; + + charger = kzalloc(sizeof(*charger), GFP_KERNEL); + if (!charger) + return -ENOMEM; + + charger->pdata = pdata; + charger->online = 0; + charger->chip = chip; + charger->i2c = chip->i2c_power; + + platform_set_drvdata(pdev, charger); + + ret = max8907c_reg_read(charger->i2c, MAX8907C_REG_CHG_STAT); + if (ret & (1 << 7)) { + charger->online = 1; + max8907c_set_charger(charger); + } + + ret = request_threaded_irq(chip->irq_base + MAX8907C_IRQ_VCHG_DC_F, NULL, + max8907c_charger_isr, IRQF_ONESHOT, + "power-remove", charger); + if (unlikely(ret < 0)) { + pr_debug("max8907c: failed to request IRQ %X\n", ret); + goto out; + } + + ret = request_threaded_irq(chip->irq_base + MAX8907C_IRQ_VCHG_DC_R, NULL, + max8907c_charger_isr, IRQF_ONESHOT, + "power-insert", charger); + if (unlikely(ret < 0)) { + pr_debug("max8907c: failed to request IRQ %X\n", ret); + goto out1; + } + + + ret = power_supply_register(&pdev->dev, &max8907c_charger_ps); + if (unlikely(ret != 0)) { + pr_err("Failed to register max8907c_charger driver: %d\n", ret); + goto out2; + } + + return 0; +out2: + free_irq(chip->irq_base + MAX8907C_IRQ_VCHG_DC_R, charger); +out1: + free_irq(chip->irq_base + MAX8907C_IRQ_VCHG_DC_F, charger); +out: + kfree(charger); + return ret; +} + +static __devexit int max8907c_charger_remove(struct platform_device *pdev) +{ + struct max8907c_charger *charger = platform_get_drvdata(pdev); + struct max8907c *chip = charger->chip; + int ret; + + ret = max8907c_reg_write(charger->i2c, MAX8907C_REG_CHG_IRQ1_MASK, 0xFF); + if (unlikely(ret != 0)) { + pr_err("Failed to set IRQ1_MASK: %d\n", ret); + goto out; + } + + free_irq(chip->irq_base + MAX8907C_IRQ_VCHG_DC_R, charger); + free_irq(chip->irq_base + MAX8907C_IRQ_VCHG_DC_F, charger); + power_supply_unregister(&max8907c_charger_ps); +out: + kfree(charger); + return 0; +} + +static struct platform_driver max8907c_charger_driver = { + .probe = max8907c_charger_probe, + .remove = __devexit_p(max8907c_charger_remove), + .driver = { + .name = "max8907c-charger", + }, +}; + +static int __init max8907c_charger_init(void) +{ + return platform_driver_register(&max8907c_charger_driver); +} +module_init(max8907c_charger_init); + +static void __exit max8907c_charger_exit(void) +{ + platform_driver_unregister(&max8907c_charger_driver); +} +module_exit(max8907c_charger_exit); + +MODULE_DESCRIPTION("Charger driver for MAX8907C"); +MODULE_AUTHOR("Gyungoh Yoo <jack.yoo@maxim-ic.com>"); +MODULE_LICENSE("GPL"); diff --git a/include/linux/power/max8907c-charger.h b/include/linux/power/max8907c-charger.h new file mode 100644 index 000000000000..2cebad768b0d --- /dev/null +++ b/include/linux/power/max8907c-charger.h @@ -0,0 +1,64 @@ +/* linux/power/max8907c-charger.h + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef __LINUX_MAX8907C_CHARGER_H +#define __LINUX_MAX8907C_CHARGER_H + +/* interrupt */ +#define MAX8907C_VCHG_OVP (1 << 0) +#define MAX8907C_VCHG_F (1 << 1) +#define MAX8907C_VCHG_R (1 << 2) +#define MAX8907C_THM_OK_R (1 << 8) +#define MAX8907C_THM_OK_F (1 << 9) +#define MAX8907C_MBATTLOW_F (1 << 10) +#define MAX8907C_MBATTLOW_R (1 << 11) +#define MAX8907C_CHG_RST (1 << 12) +#define MAX8907C_CHG_DONE (1 << 13) +#define MAX8907C_CHG_TOPOFF (1 << 14) +#define MAX8907C_CHK_TMR_FAULT (1 << 15) + +enum max8907c_charger_topoff_threshold { + MAX8907C_TOPOFF_5PERCENT = 0x00, + MAX8907C_TOPOFF_10PERCENT = 0x01, + MAX8907C_TOPOFF_15PERCENT = 0x02, + MAX8907C_TOPOFF_20PERCENT = 0x03, +}; + +enum max8907c_charger_restart_hysteresis { + MAX8907C_RESTART_100MV = 0x00, + MAX8907C_RESTART_150MV = 0x01, + MAX8907C_RESTART_200MV = 0x02, + MAX8907C_RESTART_FLOAT = 0x03, +}; + +enum max8907c_fast_charging_current { + MAX8907C_FASTCHARGE_90MA = 0x00, + MAX8907C_FASTCHARGE_300MA = 0x01, + MAX8907C_FASTCHARGE_460MA = 0x02, + MAX8907C_FASTCHARGE_600MA = 0x03, + MAX8907C_FASTCHARGE_700MA = 0x04, + MAX8907C_FASTCHARGE_800MA = 0x05, + MAX8907C_FASTCHARGE_900MA = 0x06, + MAX8907C_FASTCHARGE_1000MA = 0x07, +}; + +enum max8907c_fast_charger_time { + MAX8907C_FCHARGE_TM_8H = 0x00, + MAX8907C_FCHARGE_TM_12H = 0x01, + MAX8907C_FCHARGE_TM_16H = 0x02, + MAX8907C_FCHARGE_TM_OFF = 0x03, +}; + +struct max8907c_charger_pdata { + int irq; + enum max8907c_charger_topoff_threshold topoff_threshold; + enum max8907c_charger_restart_hysteresis restart_hysteresis; + enum max8907c_charger_restart_hysteresis fast_charging_current; + enum max8907c_fast_charger_time fast_charger_time; +}; + +#endif |