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 if you say yes here you get support for the PCA9450
Power Management chips. 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" menu "Multimedia Capabilities Port drivers"
depends on ARCH_SA1100 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_STMFX) += stmfx.o
obj-$(CONFIG_MFD_PCA9450) += pca9450.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 */