diff options
author | Jonghwa Lee <jonghwa3.lee@samsung.com> | 2013-04-02 17:08:58 +0900 |
---|---|---|
committer | Chanho Park <chanho61.park@samsung.com> | 2014-11-18 11:42:58 +0900 |
commit | ff8bf393c78bbeadd92fab12584818623889c3c7 (patch) | |
tree | 721e89a1ab74fe0db160621373746d7ee5234cf2 /drivers/power | |
parent | 3c2953e5f11fb689b1a93119775fc33e4e8f7f1b (diff) | |
download | linux-3.10-ff8bf393c78bbeadd92fab12584818623889c3c7.tar.gz linux-3.10-ff8bf393c78bbeadd92fab12584818623889c3c7.tar.bz2 linux-3.10-ff8bf393c78bbeadd92fab12584818623889c3c7.zip |
power: max77693: Add max77693 charger dirver.
Signed-off-by: Jonghwa Lee <jonghwa3.lee@samsung.com>
Diffstat (limited to 'drivers/power')
-rw-r--r-- | drivers/power/Makefile | 2 | ||||
-rw-r--r-- | drivers/power/max77693_charger.c | 689 |
2 files changed, 691 insertions, 0 deletions
diff --git a/drivers/power/Makefile b/drivers/power/Makefile index 653bf6ceff3..a917c98181e 100644 --- a/drivers/power/Makefile +++ b/drivers/power/Makefile @@ -49,6 +49,8 @@ obj-$(CONFIG_CHARGER_GPIO) += gpio-charger.o obj-$(CONFIG_CHARGER_MANAGER) += charger-manager.o obj-$(CONFIG_CHARGER_MAX8997) += max8997_charger.o obj-$(CONFIG_CHARGER_MAX8998) += max8998_charger.o +obj-$(CONFIG_CHARGER_MAX77693) += max77693_charger.o +obj-y += max77693_charger.o obj-$(CONFIG_CHARGER_BQ2415X) += bq2415x_charger.o obj-$(CONFIG_POWER_AVS) += avs/ obj-$(CONFIG_CHARGER_SMB347) += smb347-charger.o diff --git a/drivers/power/max77693_charger.c b/drivers/power/max77693_charger.c new file mode 100644 index 00000000000..340aec036bf --- /dev/null +++ b/drivers/power/max77693_charger.c @@ -0,0 +1,689 @@ +/* + * max77693_charger.c + * + * Copyright (C) 2011 Samsung Electronics + * SangYoung Son <hello.son@samsung.com> + * + * Copyright (C) 2012 Samsung Electronics + * MyungJoo Ham <myungjoo.ham@samsung.com> + * + * Simplified hello.son's driver removing unnecessary features for + * charger-manager; supporting power-supply-class is the main role. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * "Input current" in the original driver is controlled by regulator + * "CHARGER". + * "Charge current" in the original driver is controlled by regulator + * "CHARGER_CC". + */ + +#include <linux/module.h> +#include <linux/init.h> +#include <linux/platform_device.h> +#include <linux/err.h> +#include <linux/i2c.h> +#include <linux/delay.h> +#include <linux/power_supply.h> +#include <linux/gpio.h> +#include <linux/irq.h> +#include <linux/interrupt.h> +#include <linux/slab.h> +#include <linux/mfd/max77693.h> +#include <linux/mfd/max77693-private.h> +#include <linux/power/charger-manager.h> +#include <linux/extcon.h> +#include <plat/gpio-cfg.h> + +/* MAX77693 Registers(defined @max77693-private.h) */ + +/* MAX77693_CHG_REG_CHG_INT */ +#define MAX77693_BYP_I (1 << 0) +#define MAX77693_THM_I (1 << 2) +#define MAX77693_BAT_I (1 << 3) +#define MAX77693_CHG_I (1 << 4) +#define MAX77693_CHGIN_I (1 << 6) + +/* MAX77693_CHG_REG_CHG_INT_MASK */ +#define MAX77693_BYP_IM (1 << 0) +#define MAX77693_THM_IM (1 << 2) +#define MAX77693_BAT_IM (1 << 3) +#define MAX77693_CHG_IM (1 << 4) +#define MAX77693_CHGIN_IM (1 << 6) + +/* MAX77693_CHG_REG_CHG_INT_OK */ +#define MAX77693_BYP_OK 0x01 +#define MAX77693_BYP_OK_SHIFT 0 +#define MAX77693_THM_OK 0x04 +#define MAX77693_THM_OK_SHIFT 2 +#define MAX77693_BAT_OK 0x08 +#define MAX77693_BAT_OK_SHIFT 3 +#define MAX77693_CHG_OK 0x10 +#define MAX77693_CHG_OK_SHIFT 4 +#define MAX77693_CHGIN_OK 0x40 +#define MAX77693_CHGIN_OK_SHIFT 6 +#define MAX77693_DETBAT 0x80 +#define MAX77693_DETBAT_SHIFT 7 + +/* MAX77693_CHG_REG_CHG_DTLS_00 */ +#define MAX77693_THM_DTLS 0x07 +#define MAX77693_THM_DTLS_SHIFT 0 +#define MAX77693_CHGIN_DTLS 0x60 +#define MAX77693_CHGIN_DTLS_SHIFT 5 + +/* MAX77693_CHG_REG_CHG_DTLS_01 */ +#define MAX77693_CHG_DTLS 0x0F +#define MAX77693_CHG_DTLS_SHIFT 0 +#define MAX77693_BAT_DTLS 0x70 +#define MAX77693_BAT_DTLS_SHIFT 4 + +/* MAX77693_CHG_REG_CHG_DTLS_02 */ +#define MAX77693_BYP_DTLS 0x0F +#define MAX77693_BYP_DTLS_SHIFT 0 +#define MAX77693_BYP_DTLS0 0x1 +#define MAX77693_BYP_DTLS1 0x2 +#define MAX77693_BYP_DTLS2 0x4 +#define MAX77693_BYP_DTLS3 0x8 + +/* MAX77693_CHG_REG_CHG_CNFG_00 */ +#define MAX77693_MODE_DEFAULT 0x04 +#define MAX77693_MODE_CHGR 0x01 +#define MAX77693_MODE_OTG 0x02 +#define MAX77693_MODE_BUCK 0x04 + +/* MAX77693_CHG_REG_CHG_CNFG_02 */ +#define MAX77693_CHG_CC 0x3F + +/* MAX77693_CHG_REG_CHG_CNFG_04 */ +#define MAX77693_CHG_MINVSYS_MASK 0xE0 +#define MAX77693_CHG_MINVSYS_SHIFT 5 +#define MAX77693_CHG_MINVSYS_3_6V 0x06 +#define MAX77693_CHG_CV_PRM_MASK 0x1F +#define MAX77693_CHG_CV_PRM_SHIFT 0 +#define MAX77693_CHG_CV_PRM_4_20V 0x16 +#define MAX77693_CHG_CV_PRM_4_35V 0x1D +#define MAX77693_CHG_CV_PRM_4_40V 0x1F + +/* MAX77693_CHG_REG_CHG_CNFG_06 */ +#define MAX77693_CHG_CHGPROT 0x0C +#define MAX77693_CHG_CHGPROT_SHIFT 2 +#define MAX77693_CHG_CHGPROT_UNLOCK 0x03 + +/* MAX77693_CHG_REG_CHG_CNFG_09 */ +#define MAX77693_CHG_CHGIN_LIM 0x7F + +/* MAX77693_MUIC_REG_CDETCTRL1 */ +#define MAX77693_CHGTYPMAN 0x02 +#define MAX77693_CHGTYPMAN_SHIFT 1 + +/* MAX77693_MUIC_REG_STATUS2 */ +#define MAX77693_VBVOLT 0x40 +#define MAX77693_VBVOLT_SHIFT 6 +#define MAX77693_DXOVP 0x20 +#define MAX77693_DXOVP_SHIFT 5 +#define MAX77693_CHGDETRUN 0x08 +#define MAX77693_CHGDETRUN_SHIFT 3 +#define MAX77693_CHGTYPE 0x07 +#define MAX77693_CHGTYPE_SHIFT 0 + +/* irq */ +#define IRQ_DEBOUNCE_TIME 20 /* msec */ + +/* charger unlock */ +#define CHG_UNLOCK_RETRY 10 +#define CHG_UNLOCK_DELAY 100 + +/* power stabe guarantee */ +#define STABLE_POWER_DELAY 500 + +/* charger type detection */ +#define DET_ERR_RETRY 5 +#define DET_ERR_DELAY 200 + +/* soft charging */ +#define SOFT_CHG_START_CURR 100 /* mA */ +#define SOFT_CHG_START_DUR 100 /* ms */ +#define SOFT_CHG_CURR_STEP 100 /* mA */ +#define SOFT_CHG_STEP_DUR 20 /* ms */ + +/* soft regulation */ +#define SW_REG_CURR_STEP_MA 100 +#define SW_REG_START_DELAY 500 +#define SW_REG_STEP_DELAY 100 + +struct max77693_charger_data { + struct max77693_dev *max77693; + + struct power_supply charger; + + /* mutex */ + struct mutex irq_lock; + struct mutex ops_lock; + + unsigned int charging_state; + unsigned int charging_type; + unsigned int battery_state; + unsigned int battery_present; + unsigned int cable_type; + unsigned int charging_current; + unsigned int vbus_state; + + int irq_bypass; + int irq_therm; + int irq_battery; + int irq_charge; + int irq_chargin; + + /* software regulation */ + bool soft_reg_state; + int soft_reg_current; + bool soft_reg_ing; + + /* unsufficient power */ + bool reg_loop_deted; + + struct max77693_charger_platform_data *charger_pdata; + + int irq; + u8 irq_reg; + int irq_cnt; +}; + +static int max77693_get_battery_present(struct max77693_charger_data *chg_data) +{ + struct regmap *rmap = chg_data->max77693->regmap; + u8 reg_data; + + max77693_read_reg(rmap, MAX77693_CHG_REG_CHG_INT_OK, ®_data); + reg_data = ((reg_data & MAX77693_DETBAT) >> MAX77693_DETBAT_SHIFT); + + return !reg_data; +} + +static int max77693_get_vbus_state(struct max77693_charger_data *chg_data) +{ + struct regmap *rmap = chg_data->max77693->regmap; + int state; + u8 reg_data; + + max77693_read_reg(rmap, MAX77693_CHG_REG_CHG_DETAILS_00, ®_data); + reg_data = ((reg_data & MAX77693_CHGIN_DTLS) >> + MAX77693_CHGIN_DTLS_SHIFT); + + switch (reg_data) { + case 0x00: + /* V chgin < UVLO */ + state = POWER_SUPPLY_HEALTH_UNSPEC_FAILURE; + break; + case 0x01: + /* V chgin < V batt + minimum threshold */ + state = POWER_SUPPLY_HEALTH_UNSPEC_FAILURE; + break; + case 0x02: + /* V chgin > OVLO */ + state = POWER_SUPPLY_HEALTH_OVERVOLTAGE; + break; + case 0x03: + state = POWER_SUPPLY_HEALTH_GOOD; + break; + default: + state = POWER_SUPPLY_HEALTH_UNKNOWN; + break; + } + + chg_data->vbus_state = state; + return state; +} + +static int max77693_get_charger_type(struct max77693_charger_data *chg_data) +{ + struct regmap *rmap = chg_data->max77693->regmap; + int state; + u8 reg_data; + + max77693_read_reg(rmap, MAX77693_CHG_REG_CHG_DETAILS_01, ®_data); + reg_data = ((reg_data & MAX77693_CHG_DTLS) >> MAX77693_CHG_DTLS_SHIFT); + + switch (reg_data) { + case 0x0: + state = POWER_SUPPLY_CHARGE_TYPE_TRICKLE; + break; + case 0x1: + case 0x2: + case 0x3: + state = POWER_SUPPLY_CHARGE_TYPE_FAST; + break; + case 0x4 ... 0x8: + case 0xA: + case 0xB: + state = POWER_SUPPLY_CHARGE_TYPE_NONE; + break; + default: + state = POWER_SUPPLY_CHARGE_TYPE_UNKNOWN; + break; + } + + chg_data->charging_type = state; + return state; +} + +static int max77693_get_charger_state(struct max77693_charger_data *chg_data) +{ + struct regmap *rmap = chg_data->max77693->regmap; + int state; + u8 reg_data; + + max77693_read_reg(rmap, MAX77693_CHG_REG_CHG_DETAILS_01, ®_data); + reg_data = ((reg_data & MAX77693_CHG_DTLS) >> MAX77693_CHG_DTLS_SHIFT); + switch (reg_data) { + case 0x0: + case 0x1: + case 0x2: + /* + * Note that whether to consider 0x3 as CHARGING or FULL + * is arguable. + * According to TN's standard 0x3 (TOP-OFF) should be + * "FULL". + * According to the strict semantics of "FULL", this is + * "CHARGING". + */ + case 0x3: + state = POWER_SUPPLY_STATUS_CHARGING; + break; + case 0x4: + state = POWER_SUPPLY_STATUS_FULL; + break; + case 0x5: + case 0x6: + case 0x7: + state = POWER_SUPPLY_STATUS_NOT_CHARGING; + break; + case 0x8: + case 0xA: + case 0xB: + state = POWER_SUPPLY_STATUS_DISCHARGING; + break; + default: + state = POWER_SUPPLY_STATUS_UNKNOWN; + break; + } + + chg_data->charging_state = state; + return state; +} + +static int max77693_get_online(struct max77693_charger_data *chg_data) +{ + struct regmap *rmap = chg_data->max77693->regmap; + u8 reg_data; + + max77693_read_reg(rmap, MAX77693_CHG_REG_CHG_INT_OK, ®_data); + return !!(reg_data & MAX77693_CHGIN_I); +} + +static int max77693_get_battery_health(struct max77693_charger_data *chg_data) +{ + struct regmap *rmap = chg_data->max77693->regmap; + int state; + bool low_bat = false; + u8 reg_data; + + max77693_read_reg(rmap, MAX77693_CHG_REG_CHG_DETAILS_01, ®_data); + reg_data = ((reg_data & MAX77693_BAT_DTLS) >> MAX77693_BAT_DTLS_SHIFT); + switch (reg_data) { + case 0x00: /* NO BATT */ + state = POWER_SUPPLY_HEALTH_DEAD; + break; + case 0x01: /* V Batt < Prequalification */ + low_bat = true; + state = POWER_SUPPLY_HEALTH_GOOD; + break; + case 0x02: /* Takes too much time to charge. Damaged battery? */ + state = POWER_SUPPLY_HEALTH_DEAD; + break; + case 0x03: /* V Batt > Good > Prequal */ + state = POWER_SUPPLY_HEALTH_GOOD; + break; + case 0x04: /* Good > V Batt > Prequal. Not good enough */ + low_bat = true; + state = POWER_SUPPLY_HEALTH_GOOD; + break; + case 0x05: /* V Batt > Overvoltage */ + state = POWER_SUPPLY_HEALTH_OVERVOLTAGE; + break; + case 0x06: /* I Batt > Overcurrent */ + state = POWER_SUPPLY_HEALTH_UNSPEC_FAILURE; + default: + state = POWER_SUPPLY_HEALTH_UNKNOWN; + break; + } + + if (state == POWER_SUPPLY_HEALTH_GOOD) + state = max77693_get_vbus_state(chg_data); + + /* Battery is healthy and fully-charged, but has low voltage? */ + if (state == POWER_SUPPLY_HEALTH_GOOD && low_bat && + max77693_get_charger_state(chg_data) == POWER_SUPPLY_STATUS_FULL) + state = POWER_SUPPLY_HEALTH_UNSPEC_FAILURE; + + chg_data->battery_state = state; + return state; +} + +static bool max77693_charger_unlock(struct max77693_charger_data *chg_data) +{ + struct regmap *rmap = chg_data->max77693->regmap; + u8 reg_data; + u8 chgprot; + int retry_cnt = 0; + bool need_init = false; + pr_debug("%s\n", __func__); + + max77693_read_reg(rmap, MAX77693_CHG_REG_CHG_CNFG_06, ®_data); + chgprot = ((reg_data & MAX77693_CHG_CHGPROT) >> + MAX77693_CHG_CHGPROT_SHIFT); + + if (chgprot == MAX77693_CHG_CHGPROT_UNLOCK) { + pr_debug("%s: unlocked state, return\n", __func__); + need_init = false; + goto unlock_finish; + } + + do { + max77693_write_reg(rmap, MAX77693_CHG_REG_CHG_CNFG_06, + (MAX77693_CHG_CHGPROT_UNLOCK << + MAX77693_CHG_CHGPROT_SHIFT)); + + max77693_read_reg(rmap, MAX77693_CHG_REG_CHG_CNFG_06, ®_data); + chgprot = ((reg_data & MAX77693_CHG_CHGPROT) >> + MAX77693_CHG_CHGPROT_SHIFT); + + if (chgprot != MAX77693_CHG_CHGPROT_UNLOCK) { + pr_err("%s: unlock err, chgprot(0x%x), retry(%d)\n", + __func__, chgprot, retry_cnt); + msleep(CHG_UNLOCK_DELAY); + } else { + pr_info("%s: unlock success, chgprot(0x%x)\n", + __func__, chgprot); + need_init = true; + break; + } + } while ((chgprot != MAX77693_CHG_CHGPROT_UNLOCK) && + (++retry_cnt < CHG_UNLOCK_RETRY)); + +unlock_finish: + return need_init; +} + +static void max77693_charger_reg_init(struct max77693_charger_data *chg_data) +{ + struct regmap *rmap = chg_data->max77693->regmap; + u8 reg_data; + + /* + * fast charge timer 10hrs + * restart threshold disable + * pre-qual charge enable(default) + */ + reg_data = (0x04 << 0) | (0x03 << 4); + max77693_write_reg(rmap, MAX77693_CHG_REG_CHG_CNFG_01, reg_data); + + /* + * charge current 466mA(default) + * otg current limit 900mA + */ + reg_data = (1 << 7); + max77693_write_reg(rmap, MAX77693_CHG_REG_CHG_CNFG_02, reg_data); + + /* + * top off current 100mA + * top off timer 0min + */ + reg_data = (0x00 << 0); /* 100mA */ + + reg_data |= (0x00 << 3); + max77693_write_reg(rmap, MAX77693_CHG_REG_CHG_CNFG_03, reg_data); + + /* + * cv voltage 4.2V or 4.35V + * MINVSYS 3.6V(default) + */ + reg_data &= (~MAX77693_CHG_MINVSYS_MASK); + reg_data |= (MAX77693_CHG_MINVSYS_3_6V << MAX77693_CHG_MINVSYS_SHIFT); + reg_data &= (~MAX77693_CHG_CV_PRM_MASK); +#if defined(CONFIG_MACH_M0) + if ((system_rev != 3) && (system_rev >= 1)) + reg_data |= (MAX77693_CHG_CV_PRM_4_35V << 0); + else + reg_data |= (MAX77693_CHG_CV_PRM_4_20V << 0); +#else /* C1, C2, M3, T0, ... */ + reg_data |= (MAX77693_CHG_CV_PRM_4_35V << 0); +#endif + + /* + * For GC1 Model, MINVSYS is 3.4V. + * For GC1 Model PRMV( Primary Charge Regn. Voltage) = 4.2V. + * Actual expected regulated voltage needs to be 4.2V but due to + * internal resistance and circuit deviation we might have to set the + * benchmark a bit higher sometimes. (4.225V now) + */ +#if defined(CONFIG_MACH_GC1) + reg_data &= (~MAX77693_CHG_CV_PRM_MASK); + reg_data |= (0x17 << MAX77693_CHG_CV_PRM_SHIFT); + reg_data &= (~MAX77693_CHG_MINVSYS_MASK); + reg_data |= (0x4 << MAX77693_CHG_MINVSYS_SHIFT); +#endif + max77693_write_reg(rmap, MAX77693_CHG_REG_CHG_CNFG_04, reg_data); + + /* VBYPSET 5V */ + reg_data = 0x50; + max77693_write_reg(rmap, MAX77693_CHG_REG_CHG_CNFG_11, reg_data); +} + +/* Support property from charger */ +static enum power_supply_property max77693_charger_props[] = { + POWER_SUPPLY_PROP_STATUS, + POWER_SUPPLY_PROP_CHARGE_TYPE, + POWER_SUPPLY_PROP_HEALTH, + POWER_SUPPLY_PROP_PRESENT, + POWER_SUPPLY_PROP_ONLINE, + POWER_SUPPLY_PROP_MODEL_NAME, + POWER_SUPPLY_PROP_MANUFACTURER, +}; + +static const char *model_name = "MAX77693"; +static const char *manufacturer = "Maxim Semiconductor"; +static int max77693_charger_get_property(struct power_supply *psy, + enum power_supply_property psp, + union power_supply_propval *val) +{ + struct max77693_charger_data *chg_data = container_of(psy, + struct max77693_charger_data, + charger); + int ret = 0; + + switch (psp) { + case POWER_SUPPLY_PROP_STATUS: + val->intval = max77693_get_charger_state(chg_data); + break; + case POWER_SUPPLY_PROP_CHARGE_TYPE: + val->intval = max77693_get_charger_type(chg_data); + break; + case POWER_SUPPLY_PROP_HEALTH: + val->intval = max77693_get_battery_health(chg_data); + break; + case POWER_SUPPLY_PROP_PRESENT: + val->intval = max77693_get_battery_present(chg_data); + break; + case POWER_SUPPLY_PROP_ONLINE: + val->intval = max77693_get_online(chg_data); + break; + case POWER_SUPPLY_PROP_MODEL_NAME: + val->strval = model_name; + break; + case POWER_SUPPLY_PROP_MANUFACTURER: + val->strval = manufacturer; + break; + default: + return -EINVAL; + } + /* + * TODO: support chaging type... + val->intval = max77693_get_cable_type(chg_data); + */ + + return ret; +} + +static void max77693_charger_initialize(struct max77693_charger_data *chg_data) +{ + struct max77693_charger_platform_data *charger_pdata = + chg_data->charger_pdata; + struct regmap *rmap = chg_data->max77693->regmap; + int i; + + for (i = 0; i < charger_pdata->num_init_data; i++) + max77693_write_reg(rmap, charger_pdata->init_data[i].addr, + charger_pdata->init_data[i].data); +} + +static int max77693_charger_probe(struct platform_device *pdev) +{ + struct max77693_charger_data *chg_data; + struct max77693_dev *max77693 = dev_get_drvdata(pdev->dev.parent); + struct max77693_platform_data *pdata = dev_get_platdata(max77693->dev); + int ret; + + pr_info("%s: charger init start\n", __func__); + + chg_data = devm_kzalloc(&pdev->dev, sizeof(struct max77693_charger_data), GFP_KERNEL); + if (!chg_data) + return -ENOMEM; + + platform_set_drvdata(pdev, chg_data); + chg_data->max77693 = max77693; + + mutex_init(&chg_data->irq_lock); + mutex_init(&chg_data->ops_lock); + + /* unlock charger setting protect */ + max77693_charger_unlock(chg_data); + + chg_data->charger_pdata = pdata->charger_data; + if (pdata->charger_data && pdata->charger_data->init_data) + max77693_charger_initialize(chg_data); + else + max77693_charger_reg_init(chg_data); + + chg_data->charger.name = "max77693-charger", + chg_data->charger.type = POWER_SUPPLY_TYPE_BATTERY, + chg_data->charger.properties = max77693_charger_props, + chg_data->charger.num_properties = ARRAY_SIZE(max77693_charger_props), + chg_data->charger.get_property = max77693_charger_get_property, + + ret = power_supply_register(&pdev->dev, &chg_data->charger); + if (ret) { + pr_err("%s: failed: power supply register\n", __func__); + goto err_kfree; + } + + return 0; + +err_kfree: + mutex_destroy(&chg_data->ops_lock); + mutex_destroy(&chg_data->irq_lock); + return ret; +} + +static int max77693_charger_remove(struct platform_device *pdev) +{ + struct max77693_charger_data *chg_data = platform_get_drvdata(pdev); + + mutex_destroy(&chg_data->ops_lock); + mutex_destroy(&chg_data->irq_lock); + + power_supply_unregister(&chg_data->charger); + + return 0; +} + +/* + * WORKAROUND: (test and remove w/ later MAX77693 chips) + * TODO: read chip revision and bypass this code if revision > ? + * Several interrupts occur while charging through TA. + * Suspended state cannot be maintained by the interrupts. + */ +static u8 saved_int_mask; +static int max77693_charger_suspend(struct device *dev) +{ + struct max77693_dev *max77693 = dev_get_drvdata(dev->parent); + u8 int_mask; + + /* Save the masking value */ + max77693_read_reg(max77693->regmap, + MAX77693_CHG_REG_CHG_INT_MASK, + &saved_int_mask); + + /* Mask all the interrupts related to charger */ + int_mask = 0xff; + max77693_write_reg(max77693->regmap, + MAX77693_CHG_REG_CHG_INT_MASK, + int_mask); + return 0; +} + +static int max77693_charger_resume(struct device *dev) +{ + struct max77693_dev *max77693 = dev_get_drvdata(dev->parent); + + /* Restore the saved masking value */ + max77693_write_reg(max77693->regmap, + MAX77693_CHG_REG_CHG_INT_MASK, + saved_int_mask); + return 0; +} + +static SIMPLE_DEV_PM_OPS(max77693_charger_pm_ops, max77693_charger_suspend, + max77693_charger_resume); + +#ifdef CONFIG_OF +static struct of_device_id max77693_charger_of_match[] __initconst = { + { .compatible = "samsung,max77693-charger", }, + { }, +}; +#endif + +static struct platform_driver max77693_charger_driver = { + .driver = { + .owner = THIS_MODULE, + .name = "max77693-charger", + .pm = &max77693_charger_pm_ops, + .of_match_table = of_match_ptr(max77693_charger_of_match), + }, + .probe = max77693_charger_probe, + .remove = max77693_charger_remove, +}; + +static int __init max77693_charger_init(void) +{ + return platform_driver_register(&max77693_charger_driver); +} + +static void __exit max77693_charger_exit(void) +{ + platform_driver_unregister(&max77693_charger_driver); +} + +module_init(max77693_charger_init); +module_exit(max77693_charger_exit); + +MODULE_AUTHOR("SangYoung Son <hello.son@samsung.com>"); +MODULE_DESCRIPTION("max77693 Charger driver"); +MODULE_LICENSE("GPL"); |