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 additional drivers must be enabled in order to use the functionality
of the device. 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 config MFD_MT6397
tristate "MediaTek MT6397 PMIC Support" tristate "MediaTek MT6397 PMIC Support"
select MFD_CORE 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_MAX8925) += max8925.o
obj-$(CONFIG_MFD_MAX8997) += max8997.o max8997-irq.o obj-$(CONFIG_MFD_MAX8997) += max8997.o max8997-irq.o
obj-$(CONFIG_MFD_MAX8998) += max8998.o max8998-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 pcf50633-objs := pcf50633-core.o pcf50633-irq.o
obj-$(CONFIG_MFD_PCF50633) += pcf50633.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 Say Y here to enable support for the MAX17211/MAX17215 standalone
battery gas-gauge. 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 config BATTERY_Z2
tristate "Z2 battery driver" tristate "Z2 battery driver"
depends on I2C && MACH_ZIPIT2 depends on I2C && MACH_ZIPIT2
@ -549,6 +563,13 @@ config CHARGER_MAX8998
Say Y to enable support for the battery charger control sysfs and Say Y to enable support for the battery charger control sysfs and
platform data of MAX8998/LP3974 PMICs. 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 config CHARGER_QCOM_SMBB
tristate "Qualcomm Switch-Mode Battery Charger and Boost" tristate "Qualcomm Switch-Mode Battery Charger and Boost"
depends on MFD_SPMI_PMIC || COMPILE_TEST 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_MAX17040) += max17040_battery.o
obj-$(CONFIG_BATTERY_MAX17042) += max17042_battery.o obj-$(CONFIG_BATTERY_MAX17042) += max17042_battery.o
obj-$(CONFIG_BATTERY_MAX1721X) += max1721x_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_Z2) += z2_battery.o
obj-$(CONFIG_BATTERY_RT5033) += rt5033_battery.o obj-$(CONFIG_BATTERY_RT5033) += rt5033_battery.o
obj-$(CONFIG_CHARGER_RT9455) += rt9455_charger.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_MAX77693) += max77693_charger.o
obj-$(CONFIG_CHARGER_MAX8997) += max8997_charger.o obj-$(CONFIG_CHARGER_MAX8997) += max8997_charger.o
obj-$(CONFIG_CHARGER_MAX8998) += max8998_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_QCOM_SMBB) += qcom_smbb.o
obj-$(CONFIG_CHARGER_BQ2415X) += bq2415x_charger.o obj-$(CONFIG_CHARGER_BQ2415X) += bq2415x_charger.o
obj-$(CONFIG_CHARGER_BQ24190) += bq24190_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_UCS1002) += ucs1002_power.o
obj-$(CONFIG_CHARGER_BD70528) += bd70528-charger.o obj-$(CONFIG_CHARGER_BD70528) += bd70528-charger.o
obj-$(CONFIG_CHARGER_WILCO) += wilco-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, 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 { enum max170xx_chip_type {
MAXIM_DEVICE_TYPE_UNKNOWN = 0, MAXIM_DEVICE_TYPE_UNKNOWN = 0,
MAXIM_DEVICE_TYPE_MAX17042, MAXIM_DEVICE_TYPE_MAX17042,
MAXIM_DEVICE_TYPE_MAX17047, MAXIM_DEVICE_TYPE_MAX17047,
MAXIM_DEVICE_TYPE_MAX17050, MAXIM_DEVICE_TYPE_MAX17050,
MAXIM_DEVICE_TYPE_MAX77818,
MAXIM_DEVICE_TYPE_NUM 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, 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 { enum power_supply_property {
/* Properties of type `int' */ /* Properties of type `int' */
POWER_SUPPLY_PROP_STATUS = 0, POWER_SUPPLY_PROP_STATUS = 0,
@ -113,6 +122,7 @@ enum power_supply_property {
POWER_SUPPLY_PROP_VOLTAGE_OCV, POWER_SUPPLY_PROP_VOLTAGE_OCV,
POWER_SUPPLY_PROP_VOLTAGE_BOOT, POWER_SUPPLY_PROP_VOLTAGE_BOOT,
POWER_SUPPLY_PROP_CURRENT_MAX, POWER_SUPPLY_PROP_CURRENT_MAX,
POWER_SUPPLY_PROP_CURRENT_MAX2,
POWER_SUPPLY_PROP_CURRENT_NOW, POWER_SUPPLY_PROP_CURRENT_NOW,
POWER_SUPPLY_PROP_CURRENT_AVG, POWER_SUPPLY_PROP_CURRENT_AVG,
POWER_SUPPLY_PROP_CURRENT_BOOT, POWER_SUPPLY_PROP_CURRENT_BOOT,
@ -171,6 +181,11 @@ enum power_supply_property {
/* MAX77818 specific mode of operation (OTG supply/charger) */ /* MAX77818 specific mode of operation (OTG supply/charger) */
POWER_SUPPLY_PROP_CHARGER_MODE, 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 { 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:
case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX: case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX:
case POWER_SUPPLY_PROP_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_NOW:
case POWER_SUPPLY_PROP_CURRENT_AVG: case POWER_SUPPLY_PROP_CURRENT_AVG:
case POWER_SUPPLY_PROP_CURRENT_BOOT: case POWER_SUPPLY_PROP_CURRENT_BOOT: