1
0
Fork 0

rM2: Copy the rM2 max77818 driver

Copy the rM2 zero-sugar branch
(https://github.com/reMarkable/linux/tree/zero-sugar) to the new kernel.

Signed-off-by: Alistair Francis <alistair@alistair23.me>
5.4-rM2-2.2.x-imx-deep-sleep
Alistair Francis 2021-02-07 09:44:01 -08:00
parent 3b4900abbe
commit 4879c1b867
12 changed files with 3863 additions and 0 deletions

View File

@ -878,6 +878,17 @@ config MFD_MAX8998
additional drivers must be enabled in order to use the functionality
of the device.
config MFD_MAX77818
bool "Maxim Semiconductor MAX77818 REGULATOR/CHARGER/FUEL-GAUGE Support"
depends on I2C=y
select BATTERY_MAX77818_UTILS
select MFD_CORE
select IRW_DOMAIN
help
Say yes here to add support for Maxime Semiconductor MAX77818 device.
The device has a regulator part, a charger part and a fuel-gauge part
which may be enabled as required (power management devices).
config MFD_MT6397
tristate "MediaTek MT6397 PMIC Support"
select MFD_CORE

View File

@ -171,6 +171,7 @@ max8925-objs := max8925-core.o max8925-i2c.o
obj-$(CONFIG_MFD_MAX8925) += max8925.o
obj-$(CONFIG_MFD_MAX8997) += max8997.o max8997-irq.o
obj-$(CONFIG_MFD_MAX8998) += max8998.o max8998-irq.o
obj-$(CONFIG_MFD_MAX77818) += max77818.o
pcf50633-objs := pcf50633-core.o pcf50633-irq.o
obj-$(CONFIG_MFD_PCF50633) += pcf50633.o

View File

@ -0,0 +1,376 @@
/*
* Maxim MAX77818 MFD Core
*
* Copyright (C) 2014 Maxim Integrated Product
*
* Copyright (C) 2019 reMarkable AS - http://www.remarkable.com/
*
* Author: Steinar Bakkemo <steinar.bakkemo@remarkable.com>
* Author: Shawn Guo <shawn.guo@linaro.org>
* Author: Lars Ivar Miljeteig <lars.ivar.miljeteig@remarkable.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation version 2.
*
* This program is distributed "as is" WITHOUT ANY WARRANTY of any
* kind, whether express or implied; without even the implied warranty
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* This driver is based on max77843.c
*/
#include <linux/kernel.h>
#include <linux/version.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/err.h>
#include <linux/slab.h>
#include <linux/mutex.h>
#include <linux/interrupt.h>
#include <linux/i2c.h>
#include <linux/regmap.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/of_gpio.h>
#include <linux/of_irq.h>
#include <linux/irq.h>
#include <linux/gpio.h>
#include <linux/pm_runtime.h>
#include <linux/mfd/core.h>
#include <linux/mfd/max77818/max77818.h>
#include <linux/power/max17042_battery.h>
#include <linux/power/max77818_battery_utils.h>
#define I2C_ADDR_PMIC (0xcc >> 1) /* PMIC (CLOGIC/SAFELDOs) */
#define I2C_ADDR_CHARGER (0xd2 >> 1) /* Charger */
#define I2C_ADDR_FUEL_GAUGE (0x6c >> 1) /* Fuel Gauge */
#define REG_PMICID 0x20
#define REG_PMICREV 0x21
static int max77818_chg_handle_pre_irq(void *irq_drv_data)
{
struct max77818_dev *max77818_dev = (struct max77818_dev*) irq_drv_data;
bool restore_state = 0;
int ret = 0;
if (!max77818_dev) {
printk("%s: No driver data, unable to disable FGCC\n", __func__);
return -EINVAL;
}
ret = MAX77818_START_NON_FGCC_OP(
max77818_dev,
restore_state,
"Disabling FGCC before handling charger interrupt");
if (ret)
dev_err(max77818_dev->dev,
"Failed to disable FGCC\n");
return ret;
}
static int max77818_chg_handle_post_irq(void *irq_drv_data)
{
struct max77818_dev *max77818_dev = (struct max77818_dev*) irq_drv_data;
bool restore_state = 1;
int ret = 0;
if (!max77818_dev) {
printk("%s: No driver data, unable to disable FGCC\n", __func__);
return -EINVAL;
}
ret = MAX77818_FINISH_NON_FGCC_OP(
max77818_dev,
restore_state,
"Enabling FGCC after handling charger interrupt");
if (ret)
dev_err(max77818_dev->dev,
"Failed to enable FGCC\n");
return ret;
}
static const struct regmap_config max77818_regmap_config = {
.reg_bits = 8,
.val_bits = 8,
.cache_type = REGCACHE_NONE,
};
static const struct regmap_config max77818_regmap_config_fg = {
.reg_bits = 8,
.val_bits = 16,
.cache_type = REGCACHE_NONE,
.val_format_endian = REGMAP_ENDIAN_NATIVE,
};
/* Declare Interrupt */
static const struct regmap_irq max77818_intsrc_irqs[] = {
{ .reg_offset = 0, .mask = BIT_CHGR_INT, },
{ .reg_offset = 0, .mask = BIT_FG_INT, },
{ .reg_offset = 0, .mask = BIT_SYS_INT, },
};
static const struct regmap_irq_chip max77818_intsrc_irq_chip = {
.name = "max77818 intsrc",
.status_base = REG_INTSRC,
.mask_base = REG_INTSRCMASK,
.num_regs = 1,
.irqs = max77818_intsrc_irqs,
.num_irqs = ARRAY_SIZE(max77818_intsrc_irqs),
};
static const struct regmap_irq max77818_sys_irqs[] = {
{ .reg_offset = 0, .mask = BIT_SYSUVLO_INT, },
{ .reg_offset = 0, .mask = BIT_SYSOVLO_INT, },
{ .reg_offset = 0, .mask = BIT_TSHDN_INT, },
{ .reg_offset = 0, .mask = BIT_TM_INT, },
};
static const struct regmap_irq_chip max77818_sys_irq_chip = {
.name = "max77818 system",
.status_base = REG_SYSINTSRC,
.mask_base = REG_SYSINTMASK,
.num_regs = 1,
.irqs = max77818_sys_irqs,
.num_irqs = ARRAY_SIZE(max77818_sys_irqs),
};
static const struct regmap_irq max77818_chg_irqs[] = {
{ .reg_offset = 0, .mask = BIT_CHG_BYP_I, },
{ .reg_offset = 0, .mask = BIT_CHG_BATP_I, },
{ .reg_offset = 0, .mask = BIT_CHG_BAT_I, },
{ .reg_offset = 0, .mask = BIT_CHG_CHG_I, },
{ .reg_offset = 0, .mask = BIT_CHG_WCIN_I, },
{ .reg_offset = 0, .mask = BIT_CHG_CHGIN_I, },
{ .reg_offset = 0, .mask = BIT_CHG_AICL_I, },
};
static struct regmap_irq_chip max77818_chg_irq_chip = {
.name = "max77818 chg",
.status_base = REG_CHARGER_INT,
.mask_base = REG_CHARGER_INT_MASK,
.num_regs = 1,
.irqs = max77818_chg_irqs,
.num_irqs = ARRAY_SIZE(max77818_chg_irqs),
.handle_pre_irq = max77818_chg_handle_pre_irq,
.handle_post_irq = max77818_chg_handle_post_irq,
};
static struct mfd_cell max77818_devices[] = {
{
.name = MAX77818_REGULATOR_NAME,
.of_compatible = "maxim,"MAX77818_REGULATOR_NAME,
}, {
.name = MAX77818_CHARGER_NAME,
.of_compatible = "maxim,"MAX77818_CHARGER_NAME,
}, {
.name = MAX77818_FUELGAUGE_NAME,
.of_compatible = "maxim,"MAX77818_FUELGAUGE_NAME,
},
};
static int max77818_i2c_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct max77818_dev *me;
u32 chip_id, chip_rev;
int ret;
me = devm_kzalloc(&client->dev, sizeof(*me), GFP_KERNEL);
if (!me)
return -ENOMEM;
i2c_set_clientdata(client, me);
mutex_init(&me->lock);
me->dev = &client->dev;
me->irq = client->irq;
me->pmic = client;
me->regmap_pmic = devm_regmap_init_i2c(client, &max77818_regmap_config);
if (IS_ERR(me->regmap_pmic)) {
ret = PTR_ERR(me->regmap_pmic);
dev_err(me->dev, "failed to initialize PMIC regmap: %d\n", ret);
return ret;
}
ret = regmap_read(me->regmap_pmic, REG_PMICID, &chip_id);
if (ret < 0) {
dev_err(me->dev, "failed to read chip id: %d\n", ret);
return ret;
} else {
regmap_read(me->regmap_pmic, REG_PMICREV, &chip_rev);
dev_info(me->dev, "device ID: 0x%x, REV: 0x%x\n",
chip_id, chip_rev);
}
me->chg = i2c_new_dummy(client->adapter, I2C_ADDR_CHARGER);
if (!me->chg) {
dev_err(me->dev, "failed to allocate I2C device for CHG\n");
return ret;
}
i2c_set_clientdata(me->chg, me);
me->fg = i2c_new_dummy(client->adapter, I2C_ADDR_FUEL_GAUGE);
if (!me->fg) {
dev_err(me->dev, "failed to allocate I2C device for FG\n");
goto unreg_chg;
}
i2c_set_clientdata(me->fg, me);
me->regmap_chg = devm_regmap_init_i2c(me->chg, &max77818_regmap_config);
if (IS_ERR_OR_NULL(me->regmap_chg)) {
ret = PTR_ERR(me->regmap_chg);
dev_warn(me->dev, "failed to initialize CHG regmap: %d\n", ret);
goto unreg_fg;
}
me->regmap_fg= devm_regmap_init_i2c(me->fg, &max77818_regmap_config_fg);
if (IS_ERR_OR_NULL(me->regmap_fg)) {
ret = PTR_ERR(me->regmap_fg);
dev_err(me->dev, "failed to initialize FG regmap: %d\n", ret);
goto unreg_fg;
}
/* Disable all interrupt source */
regmap_write(me->regmap_pmic, REG_INTSRCMASK, 0xff);
/* Register overall interrupt source (sys, fg, chg) */
ret = regmap_add_irq_chip(me->regmap_pmic, me->irq,
IRQF_ONESHOT | IRQF_SHARED, 0,
&max77818_intsrc_irq_chip, &me->irqc_intsrc);
if (ret) {
dev_err(me->dev, "failed to add intsrc irq chip: %d\n", ret);
goto unreg_fg;
}
/* Register system chip irq */
ret = regmap_add_irq_chip(me->regmap_pmic, me->irq,
IRQF_ONESHOT | IRQF_SHARED, 0,
&max77818_sys_irq_chip, &me->irqc_sys);
if (ret) {
dev_err(me->dev, "failed to add system irq chip: %d\n", ret);
goto del_irqc_intsrc;
}
/* Register charger chip irq */
max77818_chg_irq_chip.irq_drv_data = me;
ret = MAX77818_DO_NON_FGCC_OP(
me,
regmap_add_irq_chip(me->regmap_chg,
me->irq,
IRQF_ONESHOT | IRQF_SHARED,
0,
&max77818_chg_irq_chip,
&me->irqc_chg),
"adding charger chip irq\n");
if (ret) {
dev_warn(me->dev, "failed to add chg irq chip: %d\n", ret);
goto del_irqc_sys;
}
pm_runtime_set_active(me->dev);
ret = mfd_add_devices(me->dev, -1, max77818_devices,
ARRAY_SIZE(max77818_devices), NULL, 0, NULL);
if (ret < 0) {
dev_err(me->dev, "failed to add mfd devices: %d\n", ret);
goto del_irqc_chg;
}
device_init_wakeup(me->dev, true);
return 0;
del_irqc_chg:
regmap_del_irq_chip(me->irq, me->irqc_chg);
del_irqc_sys:
regmap_del_irq_chip(me->irq, me->irqc_sys);
del_irqc_intsrc:
regmap_del_irq_chip(me->irq, me->irqc_intsrc);
unreg_fg:
i2c_unregister_device(me->fg);
unreg_chg:
i2c_unregister_device(me->chg);
return ret;
}
static int max77818_i2c_remove(struct i2c_client *client)
{
struct max77818_dev *me = i2c_get_clientdata(client);
mfd_remove_devices(me->dev);
regmap_del_irq_chip(me->irq, me->irqc_chg);
regmap_del_irq_chip(me->irq, me->irqc_sys);
regmap_del_irq_chip(me->irq, me->irqc_intsrc);
i2c_unregister_device(me->fg);
if (me->chg) {
i2c_unregister_device(me->chg);
}
return 0;
}
static int max77818_suspend(struct device *dev)
{
struct i2c_client *i2c = to_i2c_client(dev);
struct max77818_dev *me = i2c_get_clientdata(i2c);
if (device_may_wakeup(dev)) {
enable_irq_wake(me->irq);
disable_irq(me->irq);
}
return 0;
}
static int max77818_resume(struct device *dev)
{
struct i2c_client *i2c = to_i2c_client(dev);
struct max77818_dev *me = i2c_get_clientdata(i2c);
if (device_may_wakeup(dev)) {
disable_irq_wake(me->irq);
enable_irq(me->irq);
}
return 0;
}
static SIMPLE_DEV_PM_OPS(max77818_pm, max77818_suspend, max77818_resume);
static struct of_device_id max77818_of_id[] = {
{ .compatible = "maxim,max77818" },
{ },
};
MODULE_DEVICE_TABLE(of, max77818_of_id);
static const struct i2c_device_id max77818_i2c_id[] = {
{ "max77818" },
{ },
};
MODULE_DEVICE_TABLE(i2c, max77818_i2c_id);
static struct i2c_driver max77818_i2c_driver = {
.driver = {
.name = "max77818",
.pm = &max77818_pm,
.of_match_table = max77818_of_id,
},
.probe = max77818_i2c_probe,
.remove = max77818_i2c_remove,
.id_table = max77818_i2c_id,
};
module_i2c_driver(max77818_i2c_driver);
MODULE_DESCRIPTION("MAX77818 MFD Driver");
MODULE_LICENSE("GPL v2");

View File

@ -386,6 +386,20 @@ config BATTERY_MAX1721X
Say Y here to enable support for the MAX17211/MAX17215 standalone
battery gas-gauge.
config BATTERY_MAX77818_UTILS
tristate "Maxime MAX77818 Fuel Gauge common/external functions"
help
This is automatically selected when the MAX77818 MFD driver is
selected, due to required Max77818 Fuel Gauge device access during
initiation of the MFD device.
.
config BATTERY_MAX77818
tristate "Maxime MAX77818 Fuel Gauge"
depends on I2C
depends on MFD_MAX77818
help
Say Y yo enable support for Maxime MAX77818 battery fuel-gauge device (part of MAX77818 multi-function reg/chrg/fg device)
config BATTERY_Z2
tristate "Z2 battery driver"
depends on I2C && MACH_ZIPIT2
@ -549,6 +563,13 @@ config CHARGER_MAX8998
Say Y to enable support for the battery charger control sysfs and
platform data of MAX8998/LP3974 PMICs.
config CHARGER_MAX77818
tristate "Maxime MAX77818 battery charger driver"
depends on I2C
depends on MFD_MAX77818
help
Say Y yo enable support for Maxime MAX77818 charger device (part of MAX77818 multi-function reg/chrg/fg device)
config CHARGER_QCOM_SMBB
tristate "Qualcomm Switch-Mode Battery Charger and Boost"
depends on MFD_SPMI_PMIC || COMPILE_TEST

View File

@ -51,6 +51,7 @@ obj-$(CONFIG_BATTERY_DA9150) += da9150-fg.o
obj-$(CONFIG_BATTERY_MAX17040) += max17040_battery.o
obj-$(CONFIG_BATTERY_MAX17042) += max17042_battery.o
obj-$(CONFIG_BATTERY_MAX1721X) += max1721x_battery.o
obj-$(CONFIG_BATTERY_MAX77818) += max77818_battery.o
obj-$(CONFIG_BATTERY_Z2) += z2_battery.o
obj-$(CONFIG_BATTERY_RT5033) += rt5033_battery.o
obj-$(CONFIG_CHARGER_RT9455) += rt9455_charger.o
@ -76,6 +77,7 @@ obj-$(CONFIG_CHARGER_MAX77650) += max77650-charger.o
obj-$(CONFIG_CHARGER_MAX77693) += max77693_charger.o
obj-$(CONFIG_CHARGER_MAX8997) += max8997_charger.o
obj-$(CONFIG_CHARGER_MAX8998) += max8998_charger.o
obj-$(CONFIG_CHARGER_MAX77818) += max77818-charger.o
obj-$(CONFIG_CHARGER_QCOM_SMBB) += qcom_smbb.o
obj-$(CONFIG_CHARGER_BQ2415X) += bq2415x_charger.o
obj-$(CONFIG_CHARGER_BQ24190) += bq24190_charger.o
@ -93,3 +95,4 @@ obj-$(CONFIG_FUEL_GAUGE_SC27XX) += sc27xx_fuel_gauge.o
obj-$(CONFIG_CHARGER_UCS1002) += ucs1002_power.o
obj-$(CONFIG_CHARGER_BD70528) += bd70528-charger.o
obj-$(CONFIG_CHARGER_WILCO) += wilco-charger.o
obj-$(CONFIG_BATTERY_MAX77818_UTILS) += max77818_battery_utils.o

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,74 @@
/*
* Maxim MAX77818 Battery Utils
*
* Copyright (C) 2019 reMarkable AS - http://www.remarkable.com/
*
* Author: Steinar Bakkemo <steinar.bakkemo@remarkable.com>
* Author: Shawn Guo <shawn.guo@linaro.org>
* Author: Lars Ivar Miljeteig <lars.ivar.miljeteig@remarkable.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation version 2.
*
* This program is distributed "as is" WITHOUT ANY WARRANTY of any
* kind, whether express or implied; without even the implied warranty
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*/
#include <linux/power/max77818_battery_utils.h>
#include <linux/power/max17042_battery.h>
#include <linux/device.h>
#include <linux/regmap.h>
/* Config register bits */
#define CONFIG_FGCC_BIT (1 << 11)
/* Parameter to be given from command line in order to tune the delay introduced after
* clearing the FGCC bit before forwarding requests to the charger driver */
static int post_fgcc_change_delay_us = 100000;
/* DO NOT CALL DIRECTLY !!
*
* ONLY TO _BE CALLED FROM MAX77818_DO_NON_FGCC_OP macro */
int max77818_utils_set_fgcc_mode(struct max77818_dev *max77818_dev,
bool enabled,
bool *cur_mode)
{
unsigned int read_data;
int ret;
if (cur_mode) {
ret = regmap_read(max77818_dev->regmap_fg,
MAX17042_CONFIG, &read_data);
if (ret) {
dev_err(max77818_dev->dev,
"Failed to read CONFIG register\n");
return ret;
}
*cur_mode = (read_data & CONFIG_FGCC_BIT);
}
dev_dbg(max77818_dev->dev, "Turning %s FGCC\n", enabled ? "on" : "off");
ret = regmap_update_bits(max77818_dev->regmap_fg,
MAX17042_CONFIG,
CONFIG_FGCC_BIT,
enabled ? CONFIG_FGCC_BIT : 0x0000);
if (ret) {
dev_err(max77818_dev->dev,
"Failed to %s FGCC bit in CONFIG register\n",
enabled ? "set" : "clear");
return ret;
}
dev_dbg(max77818_dev->dev,
"Waiting %d us after FGCC mode change..\n",
post_fgcc_change_delay_us);
usleep_range(post_fgcc_change_delay_us, post_fgcc_change_delay_us + 100000);
return 0;
}

View File

@ -0,0 +1,108 @@
/*
* MAX77818 Driver Core
*
* Copyright (C) 2014 Maxim Integrated
* TaiEup Kim <clark.kim@maximintegrated.com>
*
* Copyright and License statement to be determined with Customer.
* GNU Public License version 2 requires software code to be
* publically open source if the code is to be statically linked with
* the Linux kernel binary object.
*/
#include <linux/mutex.h>
#ifndef __MAX77818_MFD_H__
#define __MAX77818_MFD_H__
#define MAX77818_REGULATOR_NAME "max77818-regulator"
#define MAX77818_CHARGER_NAME "max77818-charger"
#define MAX77818_FUELGAUGE_NAME "max77818-fuelgauge"
#define REG_INTSRC 0x22
#define REG_INTSRCMASK 0x23
#define BIT_CHGR_INT BIT (0)
#define BIT_FG_INT BIT (1)
#define BIT_SYS_INT BIT (2)
#define REG_SYSINTSRC 0x24
#define REG_SYSINTMASK 0x26
#define BIT_SYSUVLO_INT BIT (0)
#define BIT_SYSOVLO_INT BIT (1)
#define BIT_TSHDN_INT BIT (2)
#define BIT_TM_INT BIT (7)
#define REG_CHARGER_INT 0xB0
#define REG_CHARGER_INT_MASK 0xB1
#define BIT_CHG_BYP_I BIT (0)
#define BIT_CHG_BATP_I BIT (2)
#define BIT_CHG_BAT_I BIT (3)
#define BIT_CHG_CHG_I BIT (4)
#define BIT_CHG_WCIN_I BIT (5)
#define BIT_CHG_CHGIN_I BIT (6)
#define BIT_CHG_AICL_I BIT (7)
/* Chip Interrupts */
enum {
MAX77818_CHGR_INT = 0,
MAX77818_FG_INT,
MAX77818_SYS_INT,
MAX77818_SYS_IRQ_START,
MAX77818_SYS_IRQ_UVLO = MAX77818_SYS_IRQ_START,
MAX77818_SYS_IRQ_OVLO,
MAX77818_SYS_IRQ_TSHDN,
MAX77818_SYS_IRQ_TM,
MAX77818_CHG_IRQ_START,
MAX77818_CHG_IRQ_BYP_I = MAX77818_CHG_IRQ_START,
MAX77818_CHG_IRQ_BATP_I,
MAX77818_CHG_IRQ_BAT_I,
MAX77818_CHG_IRQ_CHG_I,
MAX77818_CHG_IRQ_WCIN_I,
MAX77818_CHG_IRQ_CHGIN_I,
MAX77818_CHG_IRQ_AICL_I,
MAX77818_NUM_OF_INTS,
};
enum {
SYS_IRQ_UVLO = 0,
SYS_IRQ_OVLO,
SYS_IRQ_TSHDN,
SYS_IRQ_TM,
CHG_IRQ_BYP_I = 0,
CHG_IRQ_BATP_I,
CHG_IRQ_BAT_I,
CHG_IRQ_CHG_I,
CHG_IRQ_WCIN_I,
CHG_IRQ_CHGIN_I,
CHG_IRQ_AICL_I,
FG_IRQ_ALERT = 0,
};
struct max77818_dev {
struct device *dev;
int irq;
struct regmap_irq_chip_data *irqc_intsrc;
struct regmap_irq_chip_data *irqc_sys;
struct regmap_irq_chip_data *irqc_chg;
struct i2c_client *pmic;
struct i2c_client *chg;
struct i2c_client *fg;
struct regmap *regmap_pmic;
struct regmap *regmap_chg;
struct regmap *regmap_fg;
struct mutex lock;
};
#endif /* !__MAX77818_MFD_H__ */

View File

@ -120,11 +120,32 @@ enum max17047_register {
MAX17047_QRTbl30 = 0x42,
};
/* Registers specific to max77818 */
enum max77818_register {
MAX77818_TTF = 0x20,
MAX77818_ConvgCfg = 0x49,
MAX77818_TALRT_Th2 = 0xB2,
MAX77818_TCURVE = 0xB9,
MAX77818_Config2 = 0xBB,
MAX77818_ChargeState0 = 0xD1,
MAX77818_ChargeState1 = 0xD2,
MAX77818_ChargeState2 = 0xD3,
MAX77818_ChargeState3 = 0xD4,
MAX77818_ChargeState4 = 0xD5,
MAX77818_ChargeState5 = 0xD6,
MAX77818_ChargeState6 = 0xD7,
MAX77818_ChargeState7 = 0xD8,
MAX77818_JEITA_Volt = 0xD9,
MAX77818_JEITA_Curr = 0xDA,
MAX77818_SmartChgCfg = 0xDB,
};
enum max170xx_chip_type {
MAXIM_DEVICE_TYPE_UNKNOWN = 0,
MAXIM_DEVICE_TYPE_MAX17042,
MAXIM_DEVICE_TYPE_MAX17047,
MAXIM_DEVICE_TYPE_MAX17050,
MAXIM_DEVICE_TYPE_MAX77818,
MAXIM_DEVICE_TYPE_NUM
};

View File

@ -0,0 +1,168 @@
/*
* Maxim MAX77818 Battery Utils
*
* Copyright (C) 2019 reMarkable AS - http://www.remarkable.com/
*
* Author: Steinar Bakkemo <steinar.bakkemo@remarkable.com>
* Author: Shawn Guo <shawn.guo@linaro.org>
* Author: Lars Ivar Miljeteig <lars.ivar.miljeteig@remarkable.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation version 2.
*
* This program is distributed "as is" WITHOUT ANY WARRANTY of any
* kind, whether express or implied; without even the implied warranty
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*/
#ifndef __MAX17818_BATTERY_UTILS_H_
#define __MAX17818_BATTERY_UTILS_H_
#include <linux/mfd/max77818/max77818.h>
/* Exported function required for modules external to the max77818_battery
* module to be able to use the MAX77818_DO_NON_FGCC_OP macrov*/
int max77818_utils_set_fgcc_mode(struct max77818_dev *max77818_dev,
bool enabled,
bool *cur_mode);
/* Magic to enable optional macro param */
#define VARGS_(_10, _9, _8, _7, _6, _5, _4, _3, _2, _1, N, ...) N
#define VARGS(...) VARGS_(__VA_ARGS__, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0)
#define CONCAT_(a, b) a##b
#define CONCAT(a, b) CONCAT_(a, b)
/* Common macro to be user from any context having access to the common
* max77818 struct defined in the max77818 MDF driver */
#define MAX77818_START_NON_FGCC_OP_3(max77818_dev, fgcc_restore_state, op_description) ( \
{ \
int ret = 0; \
bool restore_state = 0; \
\
if (!max77818_dev) { \
printk("%s: max77818_dev is NULL in MAX77818_DO_NON_FGCC_OP\n", __func__); \
ret = -EINVAL; \
} \
else { \
dev_dbg(max77818_dev->dev, op_description); \
\
dev_dbg(max77818_dev->dev, "Applying lock\n"); \
mutex_lock(&max77818_dev->lock); \
\
dev_dbg(max77818_dev->dev, "Clearing FGCC mode\n"); \
ret = max77818_utils_set_fgcc_mode(max77818_dev, \
false, \
&restore_state); \
if (ret) { \
dev_err(max77818_dev->dev, \
"Failed to clear FGCC bit in CONFIG register\n"); \
} \
else { \
fgcc_restore_state = restore_state; \
} \
\
/* UNLOCKING IS DONE IN MAX77818_FINISH_NON_FGCC_OP */ \
} \
ret; \
})
#define MAX77818_START_NON_FGCC_OP_2(max77818_dev, fgcc_restore_state) MAX77818_START_NON_FGCC_OP_3(max77818_dev, fgcc_restore_state, "")
#define MAX77818_START_NON_FGCC_OP(...) ( CONCAT(MAX77818_START_NON_FGCC_OP_, VARGS(__VA_ARGS__))(__VA_ARGS__) )
/* Common macro to be user from any context having access to the common
* max77818 struct defined in the max77818 MDF driver */
#define MAX77818_FINISH_NON_FGCC_OP_3(max77818_dev, fgcc_restore_state, op_description) ( \
{ \
int ret = 0; \
\
if (!max77818_dev) { \
printk("%s: max77818_dev is NULL in MAX77818_DO_NON_FGCC_OP\n", __func__); \
ret = -EINVAL; \
} \
else { \
dev_dbg(max77818_dev->dev, op_description); \
\
if (fgcc_restore_state) { \
dev_dbg(max77818_dev->dev, "Restoring FGCC mode\n"); \
\
ret = max77818_utils_set_fgcc_mode(max77818_dev, \
true, \
NULL); \
if (ret) { \
dev_err(max77818_dev->dev, \
"Failed to set FGCC bit in CONFIG register\n"); \
} \
} \
else { \
dev_dbg(max77818_dev->dev, \
"Leaving FGCC bit as it were (OFF)\n"); \
} \
dev_dbg(max77818_dev->dev, "Releasing lock\n"); \
mutex_unlock(&max77818_dev->lock); \
} \
ret; \
})
#define MAX77818_FINISH_NON_FGCC_OP_2(max77818_dev, fgcc_restore_state) MAX77818_FINISH_NON_FGCC_OP_3(max77818_dev, fgcc_restore_state, "")
#define MAX77818_FINISH_NON_FGCC_OP(...) ( CONCAT(MAX77818_FINISH_NON_FGCC_OP_, VARGS(__VA_ARGS__))(__VA_ARGS__) )
/* Common macro to be used from any context having access to the common
* max77818 struct defined in the max77818 MFD driver */
#define MAX77818_DO_NON_FGCC_OP_3(max77818_dev, op, op_description) ( \
{ \
int ret = 0; \
bool restore_state = 0; \
\
if (!max77818_dev) { \
printk("%s: max77818_dev is NULL in MAX77818_DO_NON_FGCC_OP\n", __func__); \
ret = -EINVAL; \
} \
else { \
dev_dbg(max77818_dev->dev, "Applying lock\n"); \
mutex_lock(&max77818_dev->lock); \
\
dev_dbg(max77818_dev->dev, "Clearing FGCC mode\n"); \
\
ret = max77818_utils_set_fgcc_mode(max77818_dev, \
false, \
&restore_state); \
if (ret) { \
dev_err(max77818_dev->dev, \
"Failed to clear FGCC bit in CONFIG register\n"); \
} \
else { \
dev_dbg(max77818_dev->dev, op_description); \
ret = op; \
\
if (ret) { \
dev_err(max77818_dev->dev, \
"Failed to read charger mode from charger driver\n"); \
} \
else { \
if (restore_state) { \
dev_dbg(max77818_dev->dev, "Restoring FGCC mode\n"); \
\
ret = max77818_utils_set_fgcc_mode( \
max77818_dev, true, NULL); \
if (ret) { \
dev_err(max77818_dev->dev, \
"Failed to set FGCC bit in CONFIG register\n"); \
} \
} \
else { \
dev_dbg(max77818_dev->dev, \
"Leaving FGCC bit as it were (OFF)\n"); \
} \
} \
} \
dev_dbg(max77818_dev->dev, "Releasing lock\n"); \
mutex_unlock(&max77818_dev->lock); \
} \
ret; \
})
#define MAX77818_DO_NON_FGCC_OP_2(max77818_dev, op) MAX77818_DO_NON_FGCC_OP_3(max77818_dev, op, "")
#define MAX77818_DO_NON_FGCC_OP(...) ( CONCAT(MAX77818_DO_NON_FGCC_OP_, VARGS(__VA_ARGS__))(__VA_ARGS__) )
#endif /* __MAX17818_BATTERY_UTILS_H_ */

View File

@ -94,6 +94,15 @@ enum {
POWER_SUPPLY_MODE_ALL_OFF,
};
enum {
POWER_SUPPLY_STATUS_EX_NOT_CONNECTED = 0,
POWER_SUPPLY_STATUS_EX_POGO_CONNECTED,
POWER_SUPPLY_STATUS_EX_USB_C_CONNECTED,
POWER_SUPPLY_STATUS_EX_BOTH_CONNECTED,
POWER_SUPPLY_STATUS_EX_CHANGING,
POWER_SUPPLY_STATUS_EX_UNKNOWN,
};
enum power_supply_property {
/* Properties of type `int' */
POWER_SUPPLY_PROP_STATUS = 0,
@ -113,6 +122,7 @@ enum power_supply_property {
POWER_SUPPLY_PROP_VOLTAGE_OCV,
POWER_SUPPLY_PROP_VOLTAGE_BOOT,
POWER_SUPPLY_PROP_CURRENT_MAX,
POWER_SUPPLY_PROP_CURRENT_MAX2,
POWER_SUPPLY_PROP_CURRENT_NOW,
POWER_SUPPLY_PROP_CURRENT_AVG,
POWER_SUPPLY_PROP_CURRENT_BOOT,
@ -171,6 +181,11 @@ enum power_supply_property {
/* MAX77818 specific mode of operation (OTG supply/charger) */
POWER_SUPPLY_PROP_CHARGER_MODE,
/* MAX77818-charger specific property to get extended charger status indicating
* which of the two charger inputs are connected
*/
POWER_SUPPLY_PROP_STATUS_EX,
};
enum power_supply_type {
@ -452,6 +467,7 @@ static inline bool power_supply_is_amp_property(enum power_supply_property psp)
case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT:
case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX:
case POWER_SUPPLY_PROP_CURRENT_MAX:
case POWER_SUPPLY_PROP_CURRENT_MAX2:
case POWER_SUPPLY_PROP_CURRENT_NOW:
case POWER_SUPPLY_PROP_CURRENT_AVG:
case POWER_SUPPLY_PROP_CURRENT_BOOT: