6db4831e98
Android 14
552 lines
14 KiB
C
552 lines
14 KiB
C
/* SPDX-License-Identifier: GPL-2.0 */
|
|
/*
|
|
* Copyright (c) 2021 MediaTek Inc.
|
|
*/
|
|
|
|
#include <linux/module.h>
|
|
#include <linux/kernel.h>
|
|
#include <linux/err.h>
|
|
#include <linux/i2c.h>
|
|
#include <linux/version.h>
|
|
#include <linux/slab.h>
|
|
#include <linux/of_device.h>
|
|
#include <linux/regulator/driver.h>
|
|
#include <linux/regulator/machine.h>
|
|
#include <linux/regulator/of_regulator.h>
|
|
#ifdef CONFIG_RT_REGMAP
|
|
#include <mt-plat/rt-regmap.h>
|
|
#endif /* CONFIG_RT_REGMAP */
|
|
#include "mt6691-regulator.h"
|
|
|
|
|
|
struct regulator_chip {
|
|
struct regulator_desc desc;
|
|
unsigned char vol_reg;
|
|
unsigned char vol_mask;
|
|
unsigned char mode_reg;
|
|
unsigned char mode_bit;
|
|
unsigned char enable_reg;
|
|
unsigned char enable_bit;
|
|
};
|
|
|
|
/*
|
|
* Exported API
|
|
*/
|
|
static int g_is_mt6691_exist;
|
|
|
|
int is_mt6691_exist(void)
|
|
{
|
|
#if defined(MT6691_IS_EXIST_NAME)
|
|
struct regulator *reg;
|
|
|
|
reg = regulator_get(NULL, MT6691_IS_EXIST_NAME);
|
|
pr_info("%s: regulator_get=%s\n", __func__, MT6691_IS_EXIST_NAME);
|
|
if (reg == NULL)
|
|
return 0;
|
|
regulator_put(reg);
|
|
return 1;
|
|
#else
|
|
pr_notice("g_is_mt6691_exist=%d\n", g_is_mt6691_exist);
|
|
return g_is_mt6691_exist;
|
|
#endif
|
|
}
|
|
|
|
static int mt6691_read_device(void *client, u32 addr,
|
|
int len, void *dst)
|
|
{
|
|
struct i2c_client *i2c = (struct i2c_client *)client;
|
|
|
|
return i2c_smbus_read_i2c_block_data(i2c, addr, len, dst);
|
|
}
|
|
|
|
static int mt6691_write_device(void *client, u32 addr,
|
|
int len, const void *src)
|
|
{
|
|
struct i2c_client *i2c = (struct i2c_client *)client;
|
|
|
|
return i2c_smbus_write_i2c_block_data(i2c, addr, len, src);
|
|
}
|
|
|
|
#ifdef CONFIG_RT_REGMAP
|
|
RT_REG_DECL(MT6691_REG_VSEL0, 1, RT_WBITS_WR_ONCE, {});
|
|
RT_REG_DECL(MT6691_REG_VSEL1, 1, RT_WBITS_WR_ONCE, {});
|
|
RT_REG_DECL(MT6691_REG_CTRL1, 1, RT_WBITS_WR_ONCE, {});
|
|
RT_REG_DECL(MT6691_REG_ID1, 1, RT_VOLATILE, {});
|
|
RT_REG_DECL(MT6691_REG_ID2, 1, RT_VOLATILE, {});
|
|
RT_REG_DECL(MT6691_REG_MONITOR, 1, RT_VOLATILE, {});
|
|
RT_REG_DECL(MT6691_REG_CTRL2, 1, RT_VOLATILE, {});
|
|
RT_REG_DECL(MT6691_REG_CTRL3, 1, RT_WBITS_WR_ONCE, {});
|
|
RT_REG_DECL(MT6691_REG_CTRL4, 1, RT_WBITS_WR_ONCE, {});
|
|
|
|
static const rt_register_map_t mt6691_regmap[] = {
|
|
RT_REG(MT6691_REG_VSEL0),
|
|
RT_REG(MT6691_REG_VSEL1),
|
|
RT_REG(MT6691_REG_CTRL1),
|
|
RT_REG(MT6691_REG_ID1),
|
|
RT_REG(MT6691_REG_ID2),
|
|
RT_REG(MT6691_REG_MONITOR),
|
|
RT_REG(MT6691_REG_CTRL2),
|
|
RT_REG(MT6691_REG_CTRL3),
|
|
RT_REG(MT6691_REG_CTRL4),
|
|
};
|
|
|
|
static struct rt_regmap_fops mt6691_regmap_fops = {
|
|
.read_device = mt6691_read_device,
|
|
.write_device = mt6691_write_device,
|
|
};
|
|
#endif /* CONFIG_RT_REGMAP */
|
|
|
|
int mt6691_read_byte(void *client,
|
|
uint32_t addr, uint32_t *val)
|
|
{
|
|
int ret = 0;
|
|
struct i2c_client *i2c = (struct i2c_client *)client;
|
|
|
|
ret = mt6691_read_device(i2c, addr, 1, val);
|
|
if (ret < 0)
|
|
pr_notice("%s read 0x%02x fail\n", __func__, addr);
|
|
return ret;
|
|
}
|
|
|
|
int mt6691_write_byte(void *client, uint32_t addr, uint32_t value)
|
|
{
|
|
int ret = 0;
|
|
struct i2c_client *i2c = (struct i2c_client *)client;
|
|
|
|
ret = mt6691_write_device(i2c, addr, 1, &value);
|
|
if (ret < 0)
|
|
pr_notice("%s write 0x%02x fail\n", __func__, addr);
|
|
return ret;
|
|
}
|
|
|
|
int mt6691_assign_bit(void *client, uint32_t reg, int32_t mask, uint32_t data)
|
|
{
|
|
struct i2c_client *i2c = (struct i2c_client *)client;
|
|
struct mt6691_regulator_info *ri = i2c_get_clientdata(i2c);
|
|
unsigned char tmp = 0;
|
|
uint32_t regval = 0;
|
|
int ret = 0;
|
|
|
|
mutex_lock(&ri->io_lock);
|
|
ret = mt6691_read_byte(i2c, reg, ®val);
|
|
if (ret < 0) {
|
|
pr_notice("%s read fail reg0x%02x data0x%02x\n",
|
|
__func__, reg, data);
|
|
goto OUT_ASSIGN;
|
|
}
|
|
|
|
tmp = ((regval & 0xff) & ~mask);
|
|
tmp |= (data & mask);
|
|
ret = mt6691_write_byte(i2c, reg, tmp);
|
|
if (ret < 0)
|
|
pr_notice("%s write fail reg0x%02x data0x%02x\n",
|
|
__func__, reg, tmp);
|
|
OUT_ASSIGN:
|
|
mutex_unlock(&ri->io_lock);
|
|
return ret;
|
|
}
|
|
|
|
#define mt6691_set_bit(i2c, reg, mask) \
|
|
mt6691_assign_bit(i2c, reg, mask, mask)
|
|
#define mt6691_clr_bit(i2c, reg, mask) \
|
|
mt6691_assign_bit(i2c, reg, mask, 0x00)
|
|
|
|
static int mt6691_regmap_init(struct mt6691_regulator_info *info)
|
|
{
|
|
#ifdef CONFIG_RT_REGMAP
|
|
info->regmap_props = devm_kzalloc(info->dev,
|
|
sizeof(struct rt_regmap_properties), GFP_KERNEL);
|
|
|
|
info->regmap_props->name = info->reg_chip->desc.name;
|
|
info->regmap_props->aliases = info->reg_chip->desc.name;
|
|
info->regmap_props->register_num = ARRAY_SIZE(mt6691_regmap);
|
|
info->regmap_props->rm = mt6691_regmap;
|
|
info->regmap_props->rt_regmap_mode = RT_CACHE_WR_THROUGH;
|
|
|
|
info->regmap_dev = rt_regmap_device_register(info->regmap_props,
|
|
&mt6691_regmap_fops, info->dev, info->i2c, info);
|
|
if (!info->regmap_dev)
|
|
return -EINVAL;
|
|
#endif /* CONFIG_RT_REGMAP */
|
|
return 0;
|
|
}
|
|
|
|
static int mt6691_set_voltage(struct regulator_dev *rdev,
|
|
int min_uV, int max_uV, unsigned int *selector)
|
|
{
|
|
struct mt6691_regulator_info *info = rdev_get_drvdata(rdev);
|
|
|
|
if (min_uV < 1300000)
|
|
*selector = (min_uV - 300000) / 5000;
|
|
else
|
|
*selector = (min_uV - 1300000) / 10000 + 200;
|
|
|
|
if (*selector > 255)
|
|
*selector = 255;
|
|
return mt6691_write_byte(info->i2c,
|
|
info->reg_chip->vol_reg, *selector);
|
|
}
|
|
|
|
static int mt6691_get_voltage(struct regulator_dev *rdev)
|
|
{
|
|
struct mt6691_regulator_info *info = rdev_get_drvdata(rdev);
|
|
int ret;
|
|
uint32_t reg_val = 0;
|
|
|
|
ret = mt6691_read_byte(info->i2c, info->reg_chip->vol_reg, ®_val);
|
|
if (ret < 0) {
|
|
pr_notice("%s read voltage fail\n", __func__);
|
|
return ret;
|
|
}
|
|
|
|
if (reg_val > 200)
|
|
return 1300000 + (reg_val - 200) * 10000;
|
|
return 300000 + reg_val * 5000;
|
|
}
|
|
|
|
static int hl7593_set_voltage(struct regulator_dev *rdev,
|
|
int min_uV, int max_uV, unsigned int *selector)
|
|
{
|
|
struct mt6691_regulator_info *info = rdev_get_drvdata(rdev);
|
|
|
|
*selector = (min_uV - 600000) / 6250;
|
|
|
|
return mt6691_assign_bit(info->i2c, info->reg_chip->vol_reg,
|
|
info->reg_chip->vol_mask, *selector);
|
|
}
|
|
|
|
static int hl7593_get_voltage(struct regulator_dev *rdev)
|
|
{
|
|
struct mt6691_regulator_info *info = rdev_get_drvdata(rdev);
|
|
int ret;
|
|
uint32_t reg_val = 0;
|
|
|
|
ret = mt6691_read_byte(info->i2c, info->reg_chip->vol_reg, ®_val);
|
|
if (ret < 0) {
|
|
pr_notice("%s read voltage fail\n", __func__);
|
|
return ret;
|
|
}
|
|
|
|
reg_val &= info->reg_chip->vol_mask;
|
|
return 600000 + reg_val * 6250;
|
|
}
|
|
|
|
static int mt6691_set_mode(struct regulator_dev *rdev, unsigned int mode)
|
|
{
|
|
struct mt6691_regulator_info *info = rdev_get_drvdata(rdev);
|
|
int ret;
|
|
|
|
switch (mode) {
|
|
case REGULATOR_MODE_FAST: /* force pwm mode */
|
|
ret = mt6691_set_bit(info->i2c, info->reg_chip->mode_reg,
|
|
info->reg_chip->mode_bit);
|
|
break;
|
|
case REGULATOR_MODE_NORMAL:
|
|
default:
|
|
ret = mt6691_clr_bit(info->i2c, info->reg_chip->mode_reg,
|
|
info->reg_chip->mode_bit);
|
|
break;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
static unsigned int mt6691_get_mode(struct regulator_dev *rdev)
|
|
{
|
|
struct mt6691_regulator_info *info = rdev_get_drvdata(rdev);
|
|
int ret;
|
|
uint32_t regval = 0;
|
|
|
|
ret = mt6691_read_byte(info->i2c, info->reg_chip->mode_reg, ®val);
|
|
if (ret < 0) {
|
|
pr_notice("%s read mode fail\n", __func__);
|
|
return ret;
|
|
}
|
|
|
|
if (regval & info->reg_chip->mode_bit)
|
|
return REGULATOR_MODE_FAST;
|
|
return REGULATOR_MODE_NORMAL;
|
|
}
|
|
|
|
static int mt6691_enable(struct regulator_dev *rdev)
|
|
{
|
|
struct mt6691_regulator_info *info = rdev_get_drvdata(rdev);
|
|
|
|
return mt6691_set_bit(info->i2c, info->reg_chip->enable_reg,
|
|
info->reg_chip->enable_bit);
|
|
}
|
|
|
|
static int mt6691_disable(struct regulator_dev *rdev)
|
|
{
|
|
struct mt6691_regulator_info *info = rdev_get_drvdata(rdev);
|
|
|
|
if (rdev->use_count == 0) {
|
|
pr_info("ext_buck should not be disable (use_count=%d)\n"
|
|
, rdev->use_count);
|
|
return -1;
|
|
}
|
|
return mt6691_clr_bit(info->i2c, info->reg_chip->enable_reg,
|
|
info->reg_chip->enable_bit);
|
|
}
|
|
|
|
static int mt6691_is_enabled(struct regulator_dev *rdev)
|
|
{
|
|
struct mt6691_regulator_info *info = rdev_get_drvdata(rdev);
|
|
int ret;
|
|
uint32_t reg_val;
|
|
|
|
ret = mt6691_read_byte(info->i2c, info->reg_chip->enable_reg, ®_val);
|
|
if (ret < 0)
|
|
return ret;
|
|
|
|
return (reg_val & info->reg_chip->enable_bit) ? 1 : 0;
|
|
}
|
|
|
|
static struct regulator_ops mt6691_regulator_ops = {
|
|
.set_voltage = mt6691_set_voltage,
|
|
.get_voltage = mt6691_get_voltage,
|
|
.set_mode = mt6691_set_mode,
|
|
.get_mode = mt6691_get_mode,
|
|
.enable = mt6691_enable,
|
|
.disable = mt6691_disable,
|
|
.is_enabled = mt6691_is_enabled,
|
|
};
|
|
|
|
static struct regulator_ops hl7593_regulator_ops = {
|
|
.set_voltage = hl7593_set_voltage,
|
|
.get_voltage = hl7593_get_voltage,
|
|
.set_mode = mt6691_set_mode,
|
|
.get_mode = mt6691_get_mode,
|
|
.enable = mt6691_enable,
|
|
.disable = mt6691_disable,
|
|
.is_enabled = mt6691_is_enabled,
|
|
};
|
|
|
|
#define REG_CHIP(_id, _vsel) \
|
|
{ \
|
|
.desc = { \
|
|
.id = _id, \
|
|
.name = "mt6691_buck"#_id, \
|
|
.n_voltages = 201, \
|
|
.ops = &mt6691_regulator_ops, \
|
|
.type = REGULATOR_VOLTAGE, \
|
|
.owner = THIS_MODULE, \
|
|
}, \
|
|
.vol_reg = MT6691_REG_VSEL##_vsel, \
|
|
.vol_mask = 0xFF, \
|
|
.mode_reg = MT6691_CTRL_1, \
|
|
.mode_bit = (1 << _vsel), \
|
|
.enable_reg = MT6691_REG_CTRL2, \
|
|
.enable_bit = (1 << _vsel), \
|
|
}
|
|
|
|
#define HL7593_REG_CHIP(_id, _vsel) \
|
|
{ \
|
|
.desc = { \
|
|
.id = _id, \
|
|
.name = "hl7593_buck"#_id, \
|
|
.n_voltages = 128, \
|
|
.ops = &hl7593_regulator_ops, \
|
|
.type = REGULATOR_VOLTAGE, \
|
|
.owner = THIS_MODULE, \
|
|
}, \
|
|
.vol_reg = MT6691_REG_VSEL##_vsel, \
|
|
.vol_mask = 0x7F, \
|
|
.mode_reg = MT6691_CTRL_1, \
|
|
.mode_bit = (1 << _vsel), \
|
|
.enable_reg = MT6691_REG_VSEL##_vsel, \
|
|
.enable_bit = (1 << 7), \
|
|
}
|
|
|
|
static struct regulator_chip mt6691_datas[] = {
|
|
REG_CHIP(0, 0), /* VDD2 1.125V */
|
|
REG_CHIP(1, 1), /* VDDQ 0.6V */
|
|
REG_CHIP(2, 0), /* VMDDR 0.75V */
|
|
REG_CHIP(3, 0), /* VUFS12 1.225V */
|
|
HL7593_REG_CHIP(2, 0), /* VMDDR 0.75V */
|
|
HL7593_REG_CHIP(3, 0), /* VUFS12 1.2V */
|
|
};
|
|
|
|
struct regulator_dev *mt6691_regulator_register(
|
|
const struct regulator_desc *desc,
|
|
struct device *dev,
|
|
struct regulator_init_data *init_data,
|
|
void *driver_data)
|
|
{
|
|
struct regulator_config config = {
|
|
.dev = dev,
|
|
.init_data = init_data,
|
|
.driver_data = driver_data,
|
|
.of_node = dev->of_node,
|
|
};
|
|
return regulator_register(desc, &config);
|
|
}
|
|
|
|
static int mt6691_i2c_probe(struct i2c_client *i2c,
|
|
const struct i2c_device_id *id)
|
|
{
|
|
struct mt6691_regulator_info *info;
|
|
struct regulator_init_data *init_data = NULL;
|
|
int ret;
|
|
|
|
switch (i2c->addr) {
|
|
case 0x50: /* MT6691ZXP */
|
|
case 0x57: /* MT6691OOP */
|
|
case 0x51: /* MT6691SVP */
|
|
case 0x56: /* MT6691OTP */
|
|
break;
|
|
default:
|
|
dev_info(&i2c->dev, "%s invalid Slave Addr\n", __func__);
|
|
return -ENODEV;
|
|
}
|
|
|
|
info = devm_kzalloc(&i2c->dev,
|
|
sizeof(struct mt6691_regulator_info), GFP_KERNEL);
|
|
if (!info)
|
|
return -ENOMEM;
|
|
|
|
init_data = of_get_regulator_init_data(&i2c->dev, i2c->dev.of_node,
|
|
NULL);
|
|
if (init_data) {
|
|
dev_info(&i2c->dev,
|
|
"regulator_name = %s, min_uV =%d, max_uV = %d\n",
|
|
init_data->constraints.name,
|
|
init_data->constraints.min_uV,
|
|
init_data->constraints.max_uV);
|
|
} else {
|
|
dev_info(&i2c->dev, "%s: no init data\n", __func__);
|
|
return -EINVAL;
|
|
}
|
|
|
|
info->i2c = i2c;
|
|
info->dev = &i2c->dev;
|
|
info->reg_chip = of_device_get_match_data(&i2c->dev);
|
|
mutex_init(&info->io_lock);
|
|
|
|
i2c_set_clientdata(i2c, info);
|
|
|
|
#if 0
|
|
g_is_mt6691_exist = 1;
|
|
if (mt6691_read_byte(info->i2c, MT6691_REG_MONITOR, &ret) >= 0)
|
|
g_is_mt6691_exist &= 1;
|
|
else
|
|
g_is_mt6691_exist &= 0;
|
|
dev_info(&i2c->dev, "i2c_slv=0x%x ret=0x%x g_is_mt6691_exist=%d\n",
|
|
i2c->addr, ret, g_is_mt6691_exist);
|
|
return 0;
|
|
#else
|
|
info->regulator = mt6691_regulator_register(&info->reg_chip->desc,
|
|
&i2c->dev,
|
|
init_data,
|
|
info);
|
|
|
|
if (IS_ERR(info->regulator)) {
|
|
switch (i2c->addr) {
|
|
case 0x51: /* MT6691SVP */
|
|
i2c->addr = 0x61; /* HL7593WL0A */
|
|
info->reg_chip = &mt6691_datas[4];
|
|
break;
|
|
case 0x56: /* MT6691OTP */
|
|
i2c->addr = 0x60; /* HL7593WL07 */
|
|
info->reg_chip = &mt6691_datas[5];
|
|
break;
|
|
default:
|
|
pr_notice("mt6691 register regulator fail\n");
|
|
return -EINVAL;
|
|
}
|
|
info->regulator =
|
|
mt6691_regulator_register(&info->reg_chip->desc,
|
|
&i2c->dev,
|
|
init_data,
|
|
info);
|
|
if (IS_ERR(info->regulator)) {
|
|
pr_notice("mt6691 register regulator fail\n");
|
|
return -EINVAL;
|
|
}
|
|
}
|
|
g_is_mt6691_exist = 1;
|
|
|
|
info->regulator->constraints->valid_modes_mask |=
|
|
(REGULATOR_MODE_NORMAL|REGULATOR_MODE_FAST);
|
|
info->regulator->constraints->valid_ops_mask |=
|
|
REGULATOR_CHANGE_MODE;
|
|
|
|
ret = mt6691_regmap_init(info);
|
|
if (ret < 0) {
|
|
dev_info(&i2c->dev, "%s mt6691 regmap init fail\n", __func__);
|
|
return -EINVAL;
|
|
}
|
|
|
|
pr_info("%s Successfully\n", __func__);
|
|
|
|
return 0;
|
|
#endif
|
|
}
|
|
|
|
static int mt6691_i2c_remove(struct i2c_client *i2c)
|
|
{
|
|
struct mt6691_regulator_info *info = i2c_get_clientdata(i2c);
|
|
|
|
if (info) {
|
|
regulator_unregister(info->regulator);
|
|
#ifdef CONFIG_RT_REGMAP
|
|
rt_regmap_device_unregister(info->regmap_dev);
|
|
#endif /* CONFIG_RT_REGMAP */
|
|
mutex_destroy(&info->io_lock);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/* Must reserve one empty object at the end */
|
|
static const struct of_device_id rt_match_table[] = {
|
|
{ /* VDD2=1.125V (0x57) */
|
|
.compatible = MT6691_CMPT_STR_0,
|
|
.data = &mt6691_datas[0],
|
|
}, { /* VDDQ=1.125V (0x57) */
|
|
.compatible = MT6691_CMPT_STR_1,
|
|
.data = &mt6691_datas[1],
|
|
}, { /* VMDDR=0.75V (0x51) */
|
|
.compatible = MT6691_CMPT_STR_2,
|
|
.data = &mt6691_datas[2],
|
|
}, { /* VUFS12=1.225V (0x56) */
|
|
.compatible = "mediatek,ext_buck_vufs12",
|
|
.data = &mt6691_datas[3],
|
|
}, {
|
|
/* Sentinel */
|
|
},
|
|
};
|
|
|
|
static const struct i2c_device_id rt_dev_id[] = {
|
|
{"mt6691", 0},
|
|
{ },
|
|
};
|
|
|
|
static struct i2c_driver mt6691_i2c_driver = {
|
|
.driver = {
|
|
.name = "mt6691",
|
|
.owner = THIS_MODULE,
|
|
.of_match_table = rt_match_table,
|
|
},
|
|
.probe = mt6691_i2c_probe,
|
|
.remove = mt6691_i2c_remove,
|
|
.id_table = rt_dev_id,
|
|
};
|
|
|
|
static int __init mt6691_i2c_init(void)
|
|
{
|
|
pr_info("%s\n", __func__);
|
|
return i2c_add_driver(&mt6691_i2c_driver);
|
|
}
|
|
subsys_initcall(mt6691_i2c_init);
|
|
|
|
static void __exit mt6691_i2c_exit(void)
|
|
{
|
|
i2c_del_driver(&mt6691_i2c_driver);
|
|
}
|
|
module_exit(mt6691_i2c_exit);
|
|
|
|
MODULE_LICENSE("GPL");
|
|
MODULE_AUTHOR("Jeff Chang <jeff_chang@richtek.com>");
|
|
MODULE_VERSION(MT6691_DRV_VERSION);
|
|
MODULE_DESCRIPTION("Regulator driver for MT6691");
|