1
0
Fork 0

rM2: mfd: Copy the rM2 bd7181x 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:46:47 -08:00
parent 332b1bc1a9
commit 63323d8556
4 changed files with 1101 additions and 0 deletions

View File

@ -2018,6 +2018,14 @@ config MFD_PCA9450
if you say yes here you get support for the PCA9450
Power Management chips.
config MFD_BD7181X
bool "BD71815/BD71817 Power Management chip"
depends on I2C=y
select MFD_CORE
help
if you say yes here you get support for the BD71815/BD71817
Power Management chips.
menu "Multimedia Capabilities Port drivers"
depends on ARCH_SA1100

View File

@ -262,3 +262,4 @@ obj-$(CONFIG_MFD_ROHM_BD718XX) += rohm-bd718x7.o
obj-$(CONFIG_MFD_STMFX) += stmfx.o
obj-$(CONFIG_MFD_PCA9450) += pca9450.o
obj-$(CONFIG_MFD_BD7181X) += bd7181x.o

View File

@ -0,0 +1,491 @@
/*
* @file bd7181x.c -- RoHM BD7181X/BD71817 mfd driver
*
* 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; either version 2 of the License, or (at your
* option) any later version.
*
* @author: Tony Luo <luofc@embedinfo.com>
* Copyright 2014 Embest Technology Co. Ltd. Inc.
*/
#define DEBUG
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/i2c.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/irqdomain.h>
#include <linux/gpio.h>
#include <linux/regmap.h>
#include <linux/of_device.h>
#include <linux/of_gpio.h>
#include <linux/mfd/core.h>
#include <linux/mfd/bd7181x.h>
/** @brief bd7181x irq resource */
static struct resource rtc_resources[] = {
{
.start = BD7181X_IRQ_ALARM_12,
.end = BD7181X_IRQ_ALARM_12,
.flags = IORESOURCE_IRQ,
}
};
static struct resource power_resources[] = {
// irq# 0
{
.start = BD7181X_IRQ_DCIN_03,
.end = BD7181X_IRQ_DCIN_03,
.flags = IORESOURCE_IRQ,
},
// irq# 1
{
.start = BD7181X_IRQ_BAT_MON_08,
.end = BD7181X_IRQ_BAT_MON_08,
.flags = IORESOURCE_IRQ,
},
// irq# 2
{
.start = BD7181X_IRQ_TEMPERATURE_11,
.end = BD7181X_IRQ_TEMPERATURE_11,
.flags = IORESOURCE_IRQ,
}
};
/** @brief bd7181x multi function cells */
static struct mfd_cell bd7181x_mfd_cells[] = {
{
.name = "bd7181x-pmic",
},
{
.name = "bd7181x-power",
.num_resources = ARRAY_SIZE(power_resources),
.resources = &power_resources[0],
},
{
.name = "bd7181x-gpo",
},
{
.name = "bd7181x-rtc",
.num_resources = ARRAY_SIZE(rtc_resources),
.resources = &rtc_resources[0],
},
};
/** @brief bd7181x irqs */
static const struct regmap_irq bd7181x_irqs[] = {
[BD7181X_IRQ_BUCK_01] = {
.mask = BD7181X_INT_EN_01_BUCKAST_MASK,
.reg_offset = 1,
},
[BD7181X_IRQ_DCIN_02] = {
.mask = BD7181X_INT_EN_02_DCINAST_MASK,
.reg_offset = 2,
},
[BD7181X_IRQ_DCIN_03] = {
.mask = BD7181X_INT_EN_03_DCINAST_MASK,
.reg_offset = 3,
},
[BD7181X_IRQ_VSYS_04] = {
.mask = BD7181X_INT_EN_04_VSYSAST_MASK,
.reg_offset = 4,
},
[BD7181X_IRQ_CHARGE_05] = {
.mask = BD7181X_INT_EN_05_CHGAST_MASK,
.reg_offset = 5,
},
[BD7181X_IRQ_BAT_06] = {
.mask = BD7181X_INT_EN_06_BATAST_MASK,
.reg_offset = 6,
},
[BD7181X_IRQ_BAT_MON_07] = {
.mask = BD7181X_INT_EN_07_BMONAST_MASK,
.reg_offset = 7,
},
[BD7181X_IRQ_BAT_MON_08] = {
.mask = BD7181X_INT_EN_08_BMONAST_MASK,
.reg_offset = 8,
},
[BD7181X_IRQ_BAT_MON_09] = {
.mask = BD7181X_INT_EN_09_BMONAST_MASK,
.reg_offset = 9,
},
[BD7181X_IRQ_BAT_MON_10] = {
.mask = BD7181X_INT_EN_10_BMONAST_MASK,
.reg_offset = 10,
},
[BD7181X_IRQ_TEMPERATURE_11] = {
.mask = BD7181X_INT_EN_11_TMPAST_MASK,
.reg_offset = 11,
},
[BD7181X_IRQ_ALARM_12] = {
.mask = BD7181X_INT_EN_12_ALMAST_MASK,
.reg_offset = 12,
},
};
/** @brief bd7181x irq chip definition */
static struct regmap_irq_chip bd7181x_irq_chip = {
.name = "bd7181x",
.irqs = bd7181x_irqs,
.num_irqs = ARRAY_SIZE(bd7181x_irqs),
.num_regs = 13,
.irq_reg_stride = 1,
.status_base = BD7181X_REG_INT_STAT,
.mask_base = BD7181X_REG_INT_EN_01 - 1,
.mask_invert = true,
// .ack_base = BD7181X_REG_INT_STAT_00,
};
/** @brief bd7181x irq initialize
* @param bd7181x bd7181x device to init
* @param bdinfo platform init data
* @retval 0 probe success
* @retval negative error number
*/
static int bd7181x_irq_init(struct bd7181x *bd7181x, struct bd7181x_board* bdinfo) {
int irq;
int ret = 0;
if (!bdinfo) {
dev_warn(bd7181x->dev, "No interrupt support, no pdata\n");
return -EINVAL;
}
irq = gpio_to_irq(bdinfo->gpio_intr);
bd7181x->chip_irq = irq;
printk("bd7181x->chip_irq=%d \n", bd7181x->chip_irq);
ret = regmap_add_irq_chip(bd7181x->regmap, bd7181x->chip_irq,
IRQF_ONESHOT | IRQF_TRIGGER_FALLING, bdinfo->irq_base,
&bd7181x_irq_chip, &bd7181x->irq_data);
if (ret < 0) {
dev_warn(bd7181x->dev, "Failed to add irq_chip %d\n", ret);
}
return ret;
}
/** @brief bd7181x irq initialize
* @param bd7181x bd7181x device to init
* @retval 0 probe success
* @retval negative error number
*/
static int bd7181x_irq_exit(struct bd7181x *bd7181x)
{
if (bd7181x->chip_irq > 0)
regmap_del_irq_chip(bd7181x->chip_irq, bd7181x->irq_data);
return 0;
}
/** @brief check whether volatile register
* @param dev kernel device pointer
* @param reg register index
*/
static bool is_volatile_reg(struct device *dev, unsigned int reg)
{
// struct bd7181x *bd7181x = dev_get_drvdata(dev);
/*
* Caching all regulator registers.
*/
return true;
}
/** @brief regmap configures */
static const struct regmap_config bd7181x_regmap_config = {
.reg_bits = 8,
.val_bits = 8,
.volatile_reg = is_volatile_reg,
.max_register = BD7181X_MAX_REGISTER - 1,
.cache_type = REGCACHE_RBTREE,
};
#ifdef CONFIG_OF
static struct of_device_id bd7181x_of_match[] = {
{ .compatible = "rohm,bd71815", .data = (void *)0},
{ .compatible = "rohm,bd71817", .data = (void *)1},
{ },
};
MODULE_DEVICE_TABLE(of, bd7181x_of_match);
/** @brief parse device tree data of bd7181x
* @param client client object provided by system
* @param chip_id return chip id back to caller
* @return board initialize data
*/
static struct bd7181x_board *bd7181x_parse_dt(struct i2c_client *client,
int *chip_id)
{
struct device_node *np = client->dev.of_node;
struct bd7181x_board *board_info;
unsigned int prop;
const struct of_device_id *match;
int r = 0;
match = of_match_device(bd7181x_of_match, &client->dev);
if (!match) {
dev_err(&client->dev, "Failed to find matching dt id\n");
return NULL;
}
*chip_id = (int)match->data;
board_info = devm_kzalloc(&client->dev, sizeof(*board_info),
GFP_KERNEL);
if (!board_info) {
dev_err(&client->dev, "Failed to allocate pdata\n");
return NULL;
}
board_info->gpio_intr = of_get_named_gpio(np, "gpio_intr", 0);
if (!gpio_is_valid(board_info->gpio_intr)) {
dev_err(&client->dev, "no pmic intr pin available\n");
goto err_intr;
}
r = of_property_read_u32(np, "irq_base", &prop);
if (!r) {
board_info->irq_base = prop;
} else {
board_info->irq_base = -1;
}
return board_info;
err_intr:
devm_kfree(&client->dev, board_info);
return NULL;
}
#else
static inline
struct bd7181x_board *bd7181x_parse_dt(struct i2c_client *client,
int *chip_id)
{
return NULL;
}
#endif
static void bd7181x_hw_init(struct bd7181x *bd7181x)
{
/* Clear LPSR_MODE bit to get into SNVS state when PWRON goes low */
bd7181x_clear_bits(bd7181x, BD7181X_REG_PWRCTRL, BIT(4));
/* Change the default to turn off LDO3 in SNVS state */
bd7181x_clear_bits(bd7181x, BD7181X_REG_LDO_MODE2, BIT(7));
/* Turn off BUCK1 (VDD_ARM_1V1) in LPSR and SUSPEND mode */
bd7181x_clear_bits(bd7181x, BD7181X_REG_BUCK1_MODE, BIT(1) | BIT(0));
/* Turn off BUCK2 (VDD_SOC_1V0) in LPSR mode */
bd7181x_clear_bits(bd7181x, BD7181X_REG_BUCK2_MODE, BIT(1));
/* Keep BUCK3 (VDD_1V8) on in LPSR mode, as it supplies DDR VDD1 */
bd7181x_set_bits(bd7181x, BD7181X_REG_BUCK3_MODE, BIT(1));
/* Keep BUCK4 (VDD_DRAM_1V2) on in LPSR mode for DDR retention */
bd7181x_set_bits(bd7181x, BD7181X_REG_BUCK4_MODE, BIT(1));
/* Turn off BUCK5 (VDD_3V3) in LPSR mode */
bd7181x_clear_bits(bd7181x, BD7181X_REG_BUCK5_MODE, BIT(1));
/* Turn off LDO1_3V3 (NVCC_GPIO2) in LPSR mode */
bd7181x_clear_bits(bd7181x, BD7181X_REG_LDO_MODE1, BIT(5));
/*
* Keep LDO2_3V3 (NVCC_GPIO1) on in LPSR mode, as we have wakeup
* source from there.
*/
bd7181x_set_bits(bd7181x, BD7181X_REG_LDO_MODE2, BIT(1));
/* Turn off LDO3 (VDDA_USB_3P3) in SNVS, LPSR and SUSPEND mode */
bd7181x_clear_bits(bd7181x, BD7181X_REG_LDO_MODE2, BIT(7) | BIT(5) | BIT(4));
/* Turn off LDO4_3V3 (EPD screen) in LPSR and SUSPEND mode */
bd7181x_clear_bits(bd7181x, BD7181X_REG_LDO_MODE3, BIT(1) | BIT(0));
/* Turn off LDO5_1V8 (SD/MMC) in LPSR mode */
bd7181x_clear_bits(bd7181x, BD7181X_REG_LDO_MODE3, BIT(5));
/* Keep LDO_DVREF (LPDDR_VREF_0V6) on in LPSR mode */
bd7181x_set_bits(bd7181x, BD7181X_REG_LDO_MODE4, BIT(5));
/*
* Misc settings for a bit more power saving by disabling
* unneeded stuff.
*
* Set LDO4_REG_MODE bit to get LDO4 controlled by register than
* external pin (LDO4VEN).
*/
bd7181x_set_bits(bd7181x, BD7181X_REG_LDO_MODE1, BIT(3));
/* Enable OUT32K and have it in cmos mode */
bd7181x_set_bits(bd7181x, BD7181X_REG_OUT32K, BIT(1) | BIT(0));
/* Disable all charger stuff */
bd7181x_reg_write(bd7181x, BD7181X_REG_CHG_SET1, 0x0);
/* Disable charger thermal shutdown and battery detection */
bd7181x_clear_bits(bd7181x, BD7181X_REG_CHG_SET2, BIT(7) | BIT(4));
/* Disable LED lighting */
bd7181x_reg_write(bd7181x, BD7181X_REG_CHG_LED_1, 0x17);
/* Disable coulomb counter */
bd7181x_clear_bits(bd7181x, BD7181X_REG_CC_CTRL, BIT(6));
/* Disable Relax State detection */
bd7181x_clear_bits(bd7181x, BD7181X_REG_REX_CTRL_1, BIT(3));
}
/** @brief probe bd7181x device
* @param i2c client object provided by system
* @param id chip id
* @retval 0 probe success
* @retval negative error number
*/
static int bd7181x_i2c_probe(struct i2c_client *i2c,
const struct i2c_device_id *id)
{
struct bd7181x *bd7181x;
struct bd7181x_board *pmic_plat_data;
struct bd7181x_board *of_pmic_plat_data = NULL;
int chip_id = id->driver_data;
int ret = 0;
pmic_plat_data = dev_get_platdata(&i2c->dev);
if (!pmic_plat_data && i2c->dev.of_node) {
pmic_plat_data = bd7181x_parse_dt(i2c, &chip_id);
of_pmic_plat_data = pmic_plat_data;
}
if (!pmic_plat_data)
return -EINVAL;
bd7181x = kzalloc(sizeof(struct bd7181x), GFP_KERNEL);
if (bd7181x == NULL)
return -ENOMEM;
bd7181x->of_plat_data = of_pmic_plat_data;
i2c_set_clientdata(i2c, bd7181x);
bd7181x->dev = &i2c->dev;
bd7181x->i2c_client = i2c;
bd7181x->id = chip_id;
mutex_init(&bd7181x->io_mutex);
bd7181x->regmap = devm_regmap_init_i2c(i2c, &bd7181x_regmap_config);
if (IS_ERR(bd7181x->regmap)) {
ret = PTR_ERR(bd7181x->regmap);
dev_err(&i2c->dev, "regmap initialization failed: %d\n", ret);
return ret;
}
ret = bd7181x_reg_read(bd7181x, BD7181X_REG_DEVICE);
if(ret < 0) {
dev_err(bd7181x->dev, "%s(): Read BD7181X_REG_DEVICE failed!\n", __func__);
goto err;
}
dev_info(bd7181x->dev, "BD7181x: Device ID=0x%X\n", ret);
bd7181x_irq_init(bd7181x, of_pmic_plat_data);
ret = mfd_add_devices(bd7181x->dev, -1,
bd7181x_mfd_cells, ARRAY_SIZE(bd7181x_mfd_cells),
NULL, 0,
regmap_irq_get_domain(bd7181x->irq_data));
if (ret < 0)
goto err;
bd7181x_hw_init(bd7181x);
return ret;
err:
mfd_remove_devices(bd7181x->dev);
kfree(bd7181x);
return ret;
}
/** @brief remove bd7181x device
* @param i2c client object provided by system
* @return 0
*/
static int bd7181x_i2c_remove(struct i2c_client *i2c)
{
struct bd7181x *bd7181x = i2c_get_clientdata(i2c);
bd7181x_irq_exit(bd7181x);
mfd_remove_devices(bd7181x->dev);
kfree(bd7181x);
return 0;
}
static const struct i2c_device_id bd7181x_i2c_id[] = {
{ "bd71815", 0 },
{ "bd71817", 1 },
{ }
};
MODULE_DEVICE_TABLE(i2c, bd7181x_i2c_id);
static int bd7181x_suspend(struct device *dev)
{
struct i2c_client *i2c = to_i2c_client(dev);
struct bd7181x *bd7181x = i2c_get_clientdata(i2c);
/* Set LPSR_MODE bit to get into LPSR state when PWRON goes low */
bd7181x_set_bits(bd7181x, BD7181X_REG_PWRCTRL, BIT(4));
pinctrl_pm_select_sleep_state(dev);
return 0;
}
static int bd7181x_resume(struct device *dev)
{
struct i2c_client *i2c = to_i2c_client(dev);
struct bd7181x *bd7181x = i2c_get_clientdata(i2c);
pinctrl_pm_select_default_state(dev);
/* Flip LPSR_MODE setting back to SNVS state */
bd7181x_clear_bits(bd7181x, BD7181X_REG_PWRCTRL, BIT(4));
return 0;
}
SIMPLE_DEV_PM_OPS(bd7181x_pm_ops, bd7181x_suspend, bd7181x_resume);
static struct i2c_driver bd7181x_i2c_driver = {
.driver = {
.name = "bd7181x",
.owner = THIS_MODULE,
.of_match_table = of_match_ptr(bd7181x_of_match),
.pm = &bd7181x_pm_ops,
},
.probe = bd7181x_i2c_probe,
.remove = bd7181x_i2c_remove,
.id_table = bd7181x_i2c_id,
};
static int __init bd7181x_i2c_init(void)
{
return i2c_add_driver(&bd7181x_i2c_driver);
}
/* init early so consumer devices can complete system boot */
subsys_initcall(bd7181x_i2c_init);
static void __exit bd7181x_i2c_exit(void)
{
i2c_del_driver(&bd7181x_i2c_driver);
}
module_exit(bd7181x_i2c_exit);
MODULE_AUTHOR("Tony Luo <luofc@embest-tech.com>");
MODULE_AUTHOR("Peter Yang <yanglsh@embest-tech.com>");
MODULE_DESCRIPTION("BD71815/BD71817 chip multi-function driver");
MODULE_LICENSE("GPL");

View File

@ -0,0 +1,601 @@
/**
* @file bd7181x.h ROHM BD71815GW/BD71817GW header file
*
* Copyright 2014 Embest Technology Co. Ltd. Inc.
*
* 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; either version 2 of the License, or (at your
* option) any later version.
*
* @author yanglsh@embest-tech.com
*/
#ifndef __LINUX_MFD_BD7181X_H
#define __LINUX_MFD_BD7181X_H
#include <linux/regmap.h>
// LDO5VSEL_EQ_H
// define to 1 when LDO5VSEL connect to High
// define to 0 when LDO5VSEL connect to Low
#define LDO5VSEL_EQ_H 1
#ifndef LDO5VSEL_EQ_H
#error define LDO5VSEL_EQ_H to 1 when connect to High, to 0 when connect to Low
#else
#if LDO5VSEL_EQ_H == 1
#define BD7181X_REG_LDO5_VOLT BD7181X_REG_LDO5_VOLT_H
#elif LDO5VSEL_EQ_H == 0
#define BD7181X_REG_LDO5_VOLT BD7181X_REG_LDO5_VOLT_L
#else
#error Define LDO5VSEL_EQ_H only to 0 or 1
#endif
#endif
enum {
BD7181X_BUCK1 = 0,
BD7181X_BUCK2,
BD7181X_BUCK3,
BD7181X_BUCK4,
BD7181X_BUCK5,
// General Purpose
BD7181X_LDO1,
BD7181X_LDO2,
BD7181X_LDO3,
// LDOs for SD Card and SD Card Interface
BD7181X_LDO4,
BD7181X_LDO5,
// LDO for DDR Reference Voltage
BD7181X_LDODVREF,
// LDO for Secure Non-Volatile Storage
// BD7181X_LDOSNVS,
// LDO for Low-Power State Retention
BD7181X_LDOLPSR,
BD7181X_WLED,
BD7181X_REGULATOR_CNT,
};
#define BD7181X_SUPPLY_STATE_ENABLED 0x1
enum {
BD7181X_REG_DEVICE = 0,
BD7181X_REG_PWRCTRL,
BD7181X_REG_BUCK1_MODE,
BD7181X_REG_BUCK2_MODE,
BD7181X_REG_BUCK3_MODE,
BD7181X_REG_BUCK4_MODE,
BD7181X_REG_BUCK5_MODE,
BD7181X_REG_BUCK1_VOLT_H,
// 0x08
BD7181X_REG_BUCK1_VOLT_L,
BD7181X_REG_BUCK2_VOLT_H,
BD7181X_REG_BUCK2_VOLT_L,
BD7181X_REG_BUCK3_VOLT,
BD7181X_REG_BUCK4_VOLT,
BD7181X_REG_BUCK5_VOLT,
BD7181X_REG_LED_CTRL,
BD7181X_REG_LED_DIMM,
// 0x10
BD7181X_REG_LDO_MODE1,
BD7181X_REG_LDO_MODE2,
BD7181X_REG_LDO_MODE3,
BD7181X_REG_LDO_MODE4,
BD7181X_REG_LDO1_VOLT,
BD7181X_REG_LDO2_VOLT,
BD7181X_REG_LDO3_VOLT,
BD7181X_REG_LDO4_VOLT,
// 0x18
BD7181X_REG_LDO5_VOLT_H,
BD7181X_REG_LDO5_VOLT_L,
BD7181X_REG_BUCK_PD_DIS,
BD7181X_REG_LDO_PD_DIS,
BD7181X_REG_GPO,
BD7181X_REG_OUT32K,
BD7181X_REG_SEC,
BD7181X_REG_MIN,
// 0x20
BD7181X_REG_HOUR,
BD7181X_REG_WEEK,
BD7181X_REG_DAY,
BD7181X_REG_MONTH,
BD7181X_REG_YEAR,
BD7181X_REG_ALM0_SEC,
// 0x2C
BD7181X_REG_ALM1_SEC = 0x2C,
// 0x33
BD7181X_REG_ALM0_MASK = 0x33,
BD7181X_REG_ALM1_MASK,
BD7181X_REG_ALM2,
BD7181X_REG_TRIM,
BD7181X_REG_CONF,
// 0x38
BD7181X_REG_SYS_INIT,
BD7181X_REG_CHG_STATE,
BD7181X_REG_CHG_LAST_STATE,
BD7181X_REG_BAT_STAT,
BD7181X_REG_DCIN_STAT,
BD7181X_REG_VSYS_STAT,
BD7181X_REG_CHG_STAT,
BD7181X_REG_CHG_WDT_STAT,
// 0x40
BD7181X_REG_BAT_TEMP,
BD7181X_REG_IGNORE_0,
BD7181X_REG_INHIBIT_0,
BD7181X_REG_DCIN_CLPS,
BD7181X_REG_VSYS_REG,
BD7181X_REG_VSYS_MAX,
BD7181X_REG_VSYS_MIN,
BD7181X_REG_CHG_SET1,
// 0x48
BD7181X_REG_CHG_SET2,
BD7181X_REG_CHG_WDT_PRE,
BD7181X_REG_CHG_WDT_FST,
BD7181X_REG_CHG_IPRE,
BD7181X_REG_CHG_IFST,
BD7181X_REG_CHG_IFST_TERM,
BD7181X_REG_CHG_VPRE,
BD7181X_REG_CHG_VBAT_1,
// 0x50
BD7181X_REG_CHG_VBAT_2,
BD7181X_REG_CHG_VBAT_3,
BD7181X_REG_CHG_LED_1,
BD7181X_REG_VF_TH,
BD7181X_REG_BAT_SET_1,
BD7181X_REG_BAT_SET_2,
BD7181X_REG_BAT_SET_3,
BD7181X_REG_ALM_VBAT_TH_U,
// 0x58
BD7181X_REG_ALM_VBAT_TH_L,
BD7181X_REG_ALM_DCIN_TH,
BD7181X_REG_ALM_VSYS_TH,
BD7181X_REG_VM_IBAT_U,
BD7181X_REG_VM_IBAT_L,
BD7181X_REG_VM_VBAT_U,
BD7181X_REG_VM_VBAT_L,
BD7181X_REG_VM_BTMP,
// 0x60
BD7181X_REG_VM_VTH,
BD7181X_REG_VM_DCIN_U,
BD7181X_REG_VM_DCIN_L,
BD7181X_REG_VM_VSYS,
BD7181X_REG_VM_VF,
BD7181X_REG_VM_OCI_PRE_U,
BD7181X_REG_VM_OCI_PRE_L,
BD7181X_REG_VM_OCV_PRE_U,
// 0x68
BD7181X_REG_VM_OCV_PRE_L,
BD7181X_REG_VM_OCI_PST_U,
BD7181X_REG_VM_OCI_PST_L,
BD7181X_REG_VM_OCV_PST_U,
BD7181X_REG_VM_OCV_PST_L,
BD7181X_REG_VM_SA_VBAT_U,
BD7181X_REG_VM_SA_VBAT_L,
BD7181X_REG_VM_SA_IBAT_U,
// 0x70
BD7181X_REG_VM_SA_IBAT_L,
BD7181X_REG_CC_CTRL,
BD7181X_REG_CC_BATCAP1_TH_U,
BD7181X_REG_CC_BATCAP1_TH_L,
BD7181X_REG_CC_BATCAP2_TH_U,
BD7181X_REG_CC_BATCAP2_TH_L,
BD7181X_REG_CC_BATCAP3_TH_U,
BD7181X_REG_CC_BATCAP3_TH_L,
// 0x78
BD7181X_REG_CC_STAT,
BD7181X_REG_CC_CCNTD_3,
BD7181X_REG_CC_CCNTD_2,
BD7181X_REG_CC_CCNTD_1,
BD7181X_REG_CC_CCNTD_0,
BD7181X_REG_CC_CURCD_U,
BD7181X_REG_CC_CURCD_L,
BD7181X_REG_VM_OCUR_THR_1,
// 0x80
BD7181X_REG_VM_OCUR_DUR_1,
BD7181X_REG_VM_OCUR_THR_2,
BD7181X_REG_VM_OCUR_DUR_2,
BD7181X_REG_VM_OCUR_THR_3,
BD7181X_REG_VM_OCUR_DUR_3,
BD7181X_REG_VM_OCUR_MON,
BD7181X_REG_VM_BTMP_OV_THR,
BD7181X_REG_VM_BTMP_OV_DUR,
// 0x88
BD7181X_REG_VM_BTMP_LO_THR,
BD7181X_REG_VM_BTMP_LO_DUR,
BD7181X_REG_VM_BTMP_MON,
BD7181X_REG_INT_EN_01,
// 0x95
BD7181X_REG_INT_EN_11 = 0x95,
// 0x96
BD7181X_REG_INT_EN_12 = 0x96,
BD7181X_REG_INT_STAT,
// 0x98
BD7181X_REG_INT_STAT_01,
BD7181X_REG_INT_STAT_02,
BD7181X_REG_INT_STAT_03,
BD7181X_REG_INT_STAT_04,
BD7181X_REG_INT_STAT_05,
BD7181X_REG_INT_STAT_06,
BD7181X_REG_INT_STAT_07,
BD7181X_REG_INT_STAT_08,
// 0xA0
BD7181X_REG_INT_STAT_09,
BD7181X_REG_INT_STAT_10,
BD7181X_REG_INT_STAT_11,
BD7181X_REG_INT_STAT_12,
BD7181X_REG_INT_UPDATE,
// 0xC0
BD7181X_REG_VM_VSYS_U = 0xC0,
BD7181X_REG_VM_VSYS_L,
BD7181X_REG_VM_SA_VSYS_U,
BD7181X_REG_VM_SA_VSYS_L,
// 0xD0
BD7181X_REG_VM_SA_IBAT_MIN_U = 0xD0,
BD7181X_REG_VM_SA_IBAT_MIN_L,
BD7181X_REG_VM_SA_IBAT_MAX_U,
BD7181X_REG_VM_SA_IBAT_MAX_L,
BD7181X_REG_VM_SA_VBAT_MIN_U,
BD7181X_REG_VM_SA_VBAT_MIN_L,
BD7181X_REG_VM_SA_VBAT_MAX_U,
BD7181X_REG_VM_SA_VBAT_MAX_L,
BD7181X_REG_VM_SA_VSYS_MIN_U,
BD7181X_REG_VM_SA_VSYS_MIN_L,
BD7181X_REG_VM_SA_VSYS_MAX_U,
BD7181X_REG_VM_SA_VSYS_MAX_L,
BD7181X_REG_VM_SA_MINMAX_CLR,
// 0xE0
BD7181X_REG_REX_CCNTD_3 = 0xE0,
BD7181X_REG_REX_CCNTD_2,
BD7181X_REG_REX_CCNTD_1,
BD7181X_REG_REX_CCNTD_0,
BD7181X_REG_REX_SA_VBAT_U,
BD7181X_REG_REX_SA_VBAT_L,
BD7181X_REG_REX_CTRL_1,
BD7181X_REG_REX_CTRL_2,
BD7181X_REG_FULL_CCNTD_3,
BD7181X_REG_FULL_CCNTD_2,
BD7181X_REG_FULL_CCNTD_1,
BD7181X_REG_FULL_CCNTD_0,
BD7181X_REG_FULL_CTRL,
// 0xF0
BD7181X_REG_CCNTD_CHG_3 = 0xF0,
BD7181X_REG_CCNTD_CHG_2,
// 0xFE
BD7181X_REG_TEST_MODE = 0xFE,
BD7181X_MAX_REGISTER,
};
/* BD7181X_REG_BUCK1_MODE bits */
#define BUCK1_RAMPRATE_MASK 0xC0
#define BUCK1_RAMPRATE_10P00MV 0x0
#define BUCK1_RAMPRATE_5P00MV 0x1
#define BUCK1_RAMPRATE_2P50MV 0x2
#define BUCK1_RAMPRATE_1P25MV 0x3
/* BD7181X_REG_BUCK1_VOLT_H bits */
#define BUCK1_DVSSEL 0x80
#define BUCK1_STBY_DVS 0x40
#define BUCK1_H_MASK 0x3F
#define BUCK1_H_DEFAULT 0x14
/* BD7181X_REG_BUCK1_VOLT_L bits */
#define BUCK1_L_MASK 0x3F
#define BUCK1_L_DEFAULT 0x14
/* BD7181X_REG_BUCK2_VOLT_H bits */
#define BUCK2_DVSSEL 0x80
#define BUCK2_STBY_DVS 0x40
#define BUCK2_H_MASK 0x3F
#define BUCK2_H_DEFAULT 0x14
/* BD7181X_REG_BUCK2_VOLT_L bits */
#define BUCK2_L_MASK 0x3F
#define BUCK2_L_DEFAULT 0x14
/* BD7181X_REG_LDO1_CTRL bits */
#define LDO1_EN 0x01
#define LDO2_EN 0x02
#define LDO3_EN 0x04
#define DVREF_EN 0x08
#define VOSNVS_SW_EN 0x10
#define VOLT_MASK 0x3F
/* BD7181X_REG_OUT32K bits */
#define OUT32K_EN 0x01
#define OUT32K_MODE 0x02
/* BD7181X_REG_BAT_STAT bits */
#define BAT_DET 0x20
#define BAT_DET_OFFSET 5
#define BAT_DET_DONE 0x10
#define VBAT_OV 0x08
#define DBAT_DET 0x01
/* BD7181X_REG_VBUS_STAT bits */
#define VBUS_DET 0x01
#define BUCK1_RAMPRATE_10MV_US 0x0
#define BUCK1_RAMPRATE_5MV_US 0x1
#define BUCK1_RAMPRATE_2P5MV_US 0x2
#define BUCK1_RAMPRATE_1P25MV_US 0x3a
/* BD7181X_REG_ALM0_MASK bits */
#define A0_ONESEC 0x80
/* BD7181X_REG_INT_EN_00 bits */
#define ALMALE 0x1
/* BD7181X_REG_INT_STAT_03 bits */
#define DCIN_MON_DET 0x02
#define DCIN_MON_RES 0x01
#define POWERON_LONG 0x04
#define POWERON_MID 0x08
#define POWERON_SHORT 0x10
#define POWERON_PRESS 0x20
/* BD71805_REG_INT_STAT_08 bits */
#define VBAT_MON_DET 0x02
#define VBAT_MON_RES 0x01
/* BD71805_REG_INT_STAT_11 bits */
#define INT_STAT_11_VF_DET 0x80
#define INT_STAT_11_VF_RES 0x40
#define INT_STAT_11_VF125_DET 0x20
#define INT_STAT_11_VF125_RES 0x10
#define INT_STAT_11_OVTMP_DET 0x08
#define INT_STAT_11_OVTMP_RES 0x04
#define INT_STAT_11_LOTMP_DET 0x02
#define INT_STAT_11_LOTMP_RES 0x01
#define VBAT_MON_DET 0x02
#define VBAT_MON_RES 0x01
/* BD7181X_REG_PWRCTRL bits */
#define RESTARTEN 0x01
/* BD7181X_REG_GPO bits */
#define READY_FORCE_LOW 0x04
/* BD7181X_REG_CHG_SET1 bits */
#define CHG_EN 0x01
/* BD7181X interrupt masks */
enum {
BD7181X_INT_EN_01_BUCKAST_MASK = 0x0F,
BD7181X_INT_EN_02_DCINAST_MASK = 0x3E,
BD7181X_INT_EN_03_DCINAST_MASK = 0x3F,
BD7181X_INT_EN_04_VSYSAST_MASK = 0xCF,
BD7181X_INT_EN_05_CHGAST_MASK = 0xFC,
BD7181X_INT_EN_06_BATAST_MASK = 0xF3,
BD7181X_INT_EN_07_BMONAST_MASK = 0xFE,
BD7181X_INT_EN_08_BMONAST_MASK = 0x03,
BD7181X_INT_EN_09_BMONAST_MASK = 0x07,
BD7181X_INT_EN_10_BMONAST_MASK = 0x3F,
BD7181X_INT_EN_11_TMPAST_MASK = 0xFF,
BD7181X_INT_EN_12_ALMAST_MASK = 0x07,
};
/* BD7181X interrupt irqs */
enum {
BD7181X_IRQ_BUCK_01 = 0x0,
BD7181X_IRQ_DCIN_02,
BD7181X_IRQ_DCIN_03,
BD7181X_IRQ_VSYS_04,
BD7181X_IRQ_CHARGE_05,
BD7181X_IRQ_BAT_06,
BD7181X_IRQ_BAT_MON_07,
BD7181X_IRQ_BAT_MON_08,
BD7181X_IRQ_BAT_MON_09,
BD7181X_IRQ_BAT_MON_10,
BD7181X_IRQ_TEMPERATURE_11,
BD7181X_IRQ_ALARM_12,
};
/* BD7181X_REG_INT_EN_12 bits */
#define ALM0 0x1
/* BD7181X_REG_HOUR bits */
#define HOUR_24HOUR 0x80
/* BD7181X_REG_CC_CTRL bits */
#define CCNTRST 0x80
#define CCNTENB 0x40
#define CCCALIB 0x20
/* BD7181X_REG_CHG_SET1 bits */
#define WDT_AUTO 0x40
/* BD7181X_REG_CC_CURCD */
#define CURDIR_Discharging 0x8000
/* BD7181X_REG_VM_SA_IBAT */
#define IBAT_SA_DIR_Discharging 0x8000
/* BD7181X_REG_VM_SA_MINMAX_CLR bits */
#define VSYS_SA_MIN_CLR 0x10
#define VBAT_SA_MIN_CLR 0x01
/* BD7181X_REG_REX_CTRL_1 bits */
#define REX_CLR 0x10
/* BD7181X_REG_REX_CTRL_1 bits */
#define REX_PMU_STATE_MASK 0x04
/* BD7181X_REG_FULL_CTRL bits */
#define FULL_CLR 0x10
/* BD7181X_REG_LED_CTRL bits */
#define CHGDONE_LED_EN 0x10
/** @brief charge state enumuration */
enum CHG_STATE {
CHG_STATE_SUSPEND = 0x0, /**< suspend state */
CHG_STATE_TRICKLE_CHARGE, /**< trickle charge state */
CHG_STATE_PRE_CHARGE, /**< precharge state */
CHG_STATE_FAST_CHARGE, /**< fast charge state */
CHG_STATE_TOP_OFF, /**< top off state */
CHG_STATE_DONE, /**< charge complete */
};
/** @brief rtc or alarm registers structure */
struct bd7181x_rtc_alarm {
u8 sec;
u8 min;
u8 hour;
u8 week;
u8 day;
u8 month;
u8 year;
};
struct bd7181x;
/**
* @brief Board platform data may be used to initialize regulators.
*/
struct bd7181x_board {
struct regulator_init_data *init_data[BD7181X_REGULATOR_CNT];
/**< regulator initialize data */
int gpio_intr; /**< gpio connected to bd7181x INTB */
int irq_base; /**< bd7181x sub irqs base # */
};
/**
* @brief bd7181x sub-driver chip access routines
*/
struct bd7181x {
struct device *dev;
struct i2c_client *i2c_client;
struct regmap *regmap;
struct mutex io_mutex;
unsigned int id;
/* IRQ Handling */
int chip_irq; /**< bd7181x irq to host cpu */
struct regmap_irq_chip_data *irq_data;
/* Client devices */
struct bd7181x_pmic *pmic; /**< client device regulator */
struct bd7181x_power *power; /**< client device battery */
struct bd7181x_board *of_plat_data;
/**< Device node parsed board data */
};
static inline int bd7181x_chip_id(struct bd7181x *bd7181x)
{
return bd7181x->id;
}
/**
* @brief bd7181x_reg_read
* read single register's value of bd7181x
* @param bd7181x device to read
* @param reg register address
* @return register value if success
* error number if fail
*/
static inline int bd7181x_reg_read(struct bd7181x *bd7181x, u8 reg)
{
int r, val;
r = regmap_read(bd7181x->regmap, reg, &val);
if (r < 0) {
return r;
}
return val;
}
/**
* @brief bd7181x_reg_write
* write single register of bd7181x
* @param bd7181x device to write
* @param reg register address
* @param val value to write
* @retval 0 if success
* @retval negative error number if fail
*/
static inline int bd7181x_reg_write(struct bd7181x *bd7181x, u8 reg,
unsigned int val)
{
return regmap_write(bd7181x->regmap, reg, val);
}
/**
* @brief bd7181x_set_bits
* set bits in one register of bd7181x
* @param bd7181x device to read
* @param reg register address
* @param mask mask bits
* @retval 0 if success
* @retval negative error number if fail
*/
static inline int bd7181x_set_bits(struct bd7181x *bd7181x, u8 reg,
u8 mask)
{
return regmap_update_bits(bd7181x->regmap, reg, mask, mask);
}
/**
* @brief bd7181x_clear_bits
* clear bits in one register of bd7181x
* @param bd7181x device to read
* @param reg register address
* @param mask mask bits
* @retval 0 if success
* @retval negative error number if fail
*/
static inline int bd7181x_clear_bits(struct bd7181x *bd7181x, u8 reg,
u8 mask)
{
return regmap_update_bits(bd7181x->regmap, reg, mask, 0);
}
/**
* @brief bd7181x_update_bits
* update bits in one register of bd7181x
* @param bd7181x device to read
* @param reg register address
* @param mask mask bits
* @param val value to update
* @retval 0 if success
* @retval negative error number if fail
*/
static inline int bd7181x_update_bits(struct bd7181x *bd7181x, u8 reg,
u8 mask, u8 val)
{
return regmap_update_bits(bd7181x->regmap, reg, mask, val);
}
/**
* @brief bd7181x platform data type
*/
struct bd7181x_gpo_plat_data {
u32 mode; ///< gpo output mode
int gpio_base; ///< base gpio number in system
};
#define BD7181X_DBG0 0x0001
#define BD7181X_DBG1 0x0002
#define BD7181X_DBG2 0x0004
#define BD7181X_DBG3 0x0008
extern unsigned int bd7181x_debug_mask;
#define bd7181x_debug(debug, fmt, arg...) do { if(debug & bd7181x_debug_mask) printk("BD7181x:" fmt, ##arg);} while(0)
#endif /* __LINUX_MFD_BD7181X_H */