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
parent
3b4900abbe
commit
4879c1b867
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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");
|
|
@ -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
|
||||
|
|
|
@ -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
|
@ -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;
|
||||
}
|
|
@ -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__ */
|
||||
|
|
@ -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
|
||||
};
|
||||
|
|
|
@ -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_ */
|
|
@ -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:
|
||||
|
|
Loading…
Reference in New Issue