blob: d8bd184efd0bb59819bb66166068f69f852b4a13 [file]
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (C) 2021 MediaTek Inc.
*
* Author: Zhiyong Tao <zhiyong.tao@mediatek.com>
*
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/err.h>
#include <linux/kernel.h>
#include <linux/i2c.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_device.h>
#include <linux/of_gpio.h>
#include <linux/of_irq.h>
#include <linux/device.h>
#include <linux/gpio.h>
#include <linux/gpio/consumer.h>
#include <linux/pinctrl/consumer.h>
#include <linux/gpio.h>
#include <linux/version.h>
#include <linux/interrupt.h>
#include <linux/regulator/driver.h>
#include <linux/regulator/of_regulator.h>
#include <linux/regulator/machine.h>
#include <linux/regmap.h>
#include <linux/debugfs.h>
#include <linux/uaccess.h>
/*
* For development
* Remove version after driver is verified and ready to upstream
*/
#define MT6395_DRV_VERSION "1.0.4"
#define MT6395_PRODUCT_ID 0x00
#define MT6395_MANUFACTURE_ID 0x01
#define MT6395_REVISION_NUMBER 0x02
#define MT6395_PG_INFO 0x03
#define MT6395_UV_INFO 0x04
#define MT6395_OV_INFO 0x05
#define MT6395_CH1_VID 0x06
#define MT6395_CH1_SLEEP_VID 0x07
#define MT6395_INTERNAL_ENABLE 0x08
#define MT6395_BUCK_MODE_CTRL 0x09
#define MT6395_PROTECTION_MODE 0x0A
#define MT6395_WDOG_RST_CTRL 0x0B
#define MT6395_SLEEP_MODE_CTRL 0x0C
#define MT6395_SEQUENCE_CONFIG 0x0D
#define MT6395_CH1_TIME_CONFIG 0x0E
#define MT6395_CH2_TIME_CONFIG 0x0F
#define MT6395_CH3_TIME_CONFIG 0x10
#define MT6395_CH4_TIME_CONFIG 0x11
#define MT6395_CH5_TIME_CONFIG 0x12
#define MT6395_EXEN1_TIME_CONFIG 0x13
#define MT6395_RST_DLY_TIME 0x1C
#define MT6395_INT_ENABLE 0x1D
#define MT6395_INT_STATUS 0x1E
#define MT6395_DISCHG_CTRL 0x1F
#define MT6395_CH2_VOLT_OFFSET 0x20
#define MT6395_SLEW_RATE_CTRL 0x45
#define MT6395_CH1_ENABLE_MASK BIT(1)
#define MT6395_CH2_ENABLE_MASK BIT(2)
#define MT6395_CH3_ENABLE_MASK BIT(3)
#define MT6395_CH4_ENABLE_MASK BIT(4)
#define MT6395_CH5_ENABLE_MASK BIT(5)
#define MT6395_CH1_MODE_MASK BIT(1)
#define MT6395_CH2_MODE_MASK BIT(2)
#define MT6395_CH3_MODE_MASK BIT(3)
#define MT6395_CH4_MODE_MASK BIT(4)
#define MT6395_SLEEP_MODE_MASK BIT(0)
#define MT6395_SLEEP_CTRL_MASK BIT(7)
#define MT6395_INT_STATUS_MASK 0x61
#define MT6395_CH1_SLEW_RATE_MASK 0xC0
#define MT6395_CH1_SLEW_RATE_SHFT 6
enum mt6395_regulator {
MT6395_RG_BUCK1 = 0,
MT6395_RG_BUCK2,
MT6395_RG_BUCK3,
MT6395_RG_BUCK4,
MT6395_RG_BUCK_MAX,
MT6395_RG_LDO1 = MT6395_RG_BUCK_MAX,
MT6395_RG_MAX,
};
#define mt6395_buck1_id MT6395_RG_BUCK1
#define mt6395_buck1_min_uV 600000
#define mt6395_buck1_uV_step 6250
#define mt6395_buck1_n_voltages 127
#define mt6395_buck1_vsel_reg MT6395_CH1_VID
#define mt6395_buck1_vsel_mask 0x7F
#define mt6395_buck1_enable_reg MT6395_INTERNAL_ENABLE
#define mt6395_buck1_enable_mask MT6395_CH1_ENABLE_MASK
#define mt6395_buck1_linear_min_sel 0
#define mt6395_buck2_id MT6395_RG_BUCK2
#define mt6395_buck2_fixed_uV 1100000
#define mt6395_buck2_enable_reg MT6395_INTERNAL_ENABLE
#define mt6395_buck2_enable_mask MT6395_CH2_ENABLE_MASK
#define mt6395_buck3_id MT6395_RG_BUCK3
#define mt6395_buck3_fixed_uV 1800000
#define mt6395_buck3_enable_reg MT6395_INTERNAL_ENABLE
#define mt6395_buck3_enable_mask MT6395_CH3_ENABLE_MASK
#define mt6395_buck4_id MT6395_RG_BUCK4
#define mt6395_buck4_fixed_uV 3300000
#define mt6395_buck4_enable_reg MT6395_INTERNAL_ENABLE
#define mt6395_buck4_enable_mask MT6395_CH4_ENABLE_MASK
#define mt6395_ldo1_id MT6395_RG_LDO1
#define mt6395_ldo1_fixed_uV 1200000
#define mt6395_ldo1_enable_reg MT6395_INTERNAL_ENABLE
#define mt6395_ldo1_enable_mask MT6395_CH5_ENABLE_MASK
struct mt6395_chip;
struct mt6395_regulator_drvdata {
struct regulator_desc rdesc;
};
#ifdef CONFIG_DEBUG_FS
enum mt6395_dbg_node {
MT6395_DBG_REGS,
MT6395_DBG_REGADDR,
MT6395_DBG_DATA,
MT6395_DBG_MAX,
};
static const char * const mt6395_dentry_name[] = {
"regs", "reg_addr", "data",
};
struct mt6395_dbg_info {
struct mt6395_chip *chip;
enum mt6395_dbg_node node;
};
static u8 mt6395_regaddr[] = {
MT6395_PRODUCT_ID,
MT6395_MANUFACTURE_ID,
MT6395_REVISION_NUMBER,
MT6395_PG_INFO,
MT6395_UV_INFO,
MT6395_OV_INFO,
MT6395_CH1_VID,
MT6395_CH1_SLEEP_VID,
MT6395_INTERNAL_ENABLE,
MT6395_BUCK_MODE_CTRL,
MT6395_PROTECTION_MODE,
MT6395_WDOG_RST_CTRL,
MT6395_SLEEP_MODE_CTRL,
MT6395_SEQUENCE_CONFIG,
MT6395_CH1_TIME_CONFIG,
MT6395_CH2_TIME_CONFIG,
MT6395_CH3_TIME_CONFIG,
MT6395_CH4_TIME_CONFIG,
MT6395_CH5_TIME_CONFIG,
MT6395_EXEN1_TIME_CONFIG,
MT6395_RST_DLY_TIME,
MT6395_INT_ENABLE,
MT6395_INT_STATUS,
MT6395_DISCHG_CTRL,
MT6395_CH2_VOLT_OFFSET,
MT6395_SLEW_RATE_CTRL,
};
#endif /* CONFIG_DEBUG_FS */
struct mt6395_chip {
struct device *dev;
struct regmap *regmap;
struct i2c_client *client;
struct gpio_desc *irq_gpio;
int irq;
struct mutex io_lock;
#ifdef CONFIG_DEBUG_FS
struct mt6395_dbg_info dbg_info[MT6395_DBG_MAX];
struct dentry *dbg_dir;
struct dentry *dbg_entry[MT6395_DBG_MAX];
u8 dbg_regaddr;
#endif /* CONFIG_DEBUG_FS */
};
#ifdef CONFIG_KPD_PWRKEY_USE_PMIC
extern void kpd_pwrkey_pmic_handler(unsigned long pressed);
#endif
#define RW_SYNC_WITH_MCU
#ifdef RW_SYNC_WITH_MCU
#define PMIC_SYNC_S (0x0010BC00 + 0x02F8) /* 190 */
#define OFFS_MCU 0 /* 190 */
#define OFFS_KR 4 /* 191 */
#define csram_read(offs) __raw_readl(csram_base + (offs))
#define csram_write(offs, val) __raw_writel(val, csram_base + (offs))
static void __iomem *csram_base;
#endif
static int __regmap_write_bits(struct regmap *map, unsigned int reg,
unsigned int mask, unsigned int val)
{
int ret = 0;
#ifdef RW_SYNC_WITH_MCU
int flag = 0;
do {
flag = csram_read(OFFS_MCU);
if (flag == 0) {
csram_write(OFFS_KR, 1);
udelay(20);
break;
}
} while (flag);
ret = regmap_write_bits(map, reg, mask, val);
csram_write(OFFS_KR, 0);
#else
ret = regmap_write_bits(map, reg, mask, val);
#endif
return ret;
}
static int __regmap_write(struct regmap *map,
unsigned int reg, unsigned int val)
{
int ret = 0;
#ifdef RW_SYNC_WITH_MCU
int flag = 0;
do {
flag = csram_read(OFFS_MCU);
if (flag == 0) {
csram_write(OFFS_KR, 1);
udelay(20);
break;
}
} while (flag);
ret = regmap_write(map, reg, val);
csram_write(OFFS_KR, 0);
#else
ret = regmap_write(map, reg, val);
#endif
return ret;
}
static int __regmap_read(struct regmap *map,
unsigned int reg, unsigned int *val)
{
int ret = 0;
#ifdef RW_SYNC_WITH_MCU
int flag = 0;
do {
flag = csram_read(OFFS_MCU);
if (flag == 0) {
csram_write(OFFS_KR, 1);
udelay(20);
break;
}
pr_info("[%s] wait\n", __func__);
} while (flag);
ret = regmap_read(map, reg, val);
csram_write(OFFS_KR, 0);
#else
ret = regmap_read(map, reg, val);
#endif
return ret;
}
#ifdef CONFIG_DEBUG_FS
static int mt6395_regs_show(struct mt6395_chip *chip, struct seq_file *s)
{
int ret = 0, i = 0;
u32 data = 0;
for (i = 0; i < ARRAY_SIZE(mt6395_regaddr); i++) {
ret = __regmap_read(chip->regmap, mt6395_regaddr[i], &data);
if (ret < 0)
continue;
seq_printf(s, "reg0x%02X=0x%02X\n", mt6395_regaddr[i], data);
}
return 0;
}
static int mt6395_regaddr_show(struct mt6395_chip *chip, struct seq_file *s)
{
seq_printf(s, "0x%02X\n", chip->dbg_regaddr);
return 0;
}
static int mt6395_data_show(struct mt6395_chip *chip, struct seq_file *s)
{
int ret = 0;
u32 data = 0;
ret = __regmap_read(chip->regmap, chip->dbg_regaddr, &data);
if (ret < 0)
return ret;
seq_printf(s, "reg0x%02X=0x%02X\n", chip->dbg_regaddr, data);
return 0;
}
static int mt6395_dbg_show(struct seq_file *s, void *v)
{
int ret = 0;
struct mt6395_dbg_info *dinfo = s->private;
struct mt6395_chip *chip = dinfo->chip;
switch (dinfo->node) {
case MT6395_DBG_REGS:
ret = mt6395_regs_show(chip, s);
break;
case MT6395_DBG_REGADDR:
ret = mt6395_regaddr_show(chip, s);
break;
case MT6395_DBG_DATA:
ret = mt6395_data_show(chip, s);
break;
default:
ret = -EINVAL;
break;
}
return ret;
}
static int mt6395_dbg_open(struct inode *inode, struct file *file)
{
if (file->f_mode & FMODE_READ)
return single_open(file, mt6395_dbg_show, inode->i_private);
file->private_data = inode->i_private;
return 0;
}
static int mt6395_dbg_extract_param(const char *buf, u8 *param)
{
char token[5];
long value = 0;
if (buf[0] != '0' || (buf[1] != 'x' && buf[1] != 'X'))
return -EINVAL;
memcpy(token, buf, 5);
if (kstrtoul(token, 16, &value) != 0)
return -EINVAL;
*param = value;
return 0;
}
static bool mt6395_is_regaddr_valid(u8 regaddr)
{
int i;
for (i = 0; i < ARRAY_SIZE(mt6395_regaddr); i++) {
if (mt6395_regaddr[i] == regaddr)
return true;
}
return false;
}
static ssize_t mt6395_dbg_write(struct file *file, const char __user *ubuf,
size_t count, loff_t *ppos)
{
int ret;
struct mt6395_dbg_info *dinfo = file->private_data;
struct mt6395_chip *chip = dinfo->chip;
char lbuf[5];
u8 param = 0;
if (count != 5)
return -EFAULT;
ret = copy_from_user(lbuf, ubuf, count);
if (ret)
return -EFAULT;
lbuf[count - 1] = '\0';
switch (dinfo->node) {
case MT6395_DBG_REGADDR:
ret = mt6395_dbg_extract_param(lbuf, &param);
if (ret < 0) {
dev_info(chip->dev, "%s get regaddr fail\n", __func__);
goto out;
}
if (!mt6395_is_regaddr_valid(param))
return -EINVAL;
chip->dbg_regaddr = param;
break;
case MT6395_DBG_DATA:
ret = mt6395_dbg_extract_param(lbuf, &param);
if (ret < 0) {
dev_info(chip->dev, "%s get data fail\n", __func__);
goto out;
}
ret = __regmap_write(chip->regmap, chip->dbg_regaddr, param);
if (ret < 0)
dev_info(chip->dev, "%s write data fail\n", __func__);
break;
default:
ret = -EINVAL;
break;
}
out:
return ret < 0 ? ret : count;
}
static int mt6395_dbg_release(struct inode *inode, struct file *file)
{
if (file->f_mode & FMODE_READ)
return single_release(inode, file);
return 0;
}
static const struct file_operations mt6395_dbg_ops = {
.open = mt6395_dbg_open,
.llseek = seq_lseek,
.read = seq_read,
.write = mt6395_dbg_write,
.release = mt6395_dbg_release,
};
static int mt6395_init_debugfs(struct mt6395_chip *chip)
{
int i, len, size;
char *dirname;
struct mt6395_dbg_info *dinfo;
len = strlen(dev_name(chip->dev));
dirname = devm_kzalloc(chip->dev, len + 8, GFP_KERNEL);
if (!dirname)
return -ENOMEM;
size = snprintf(dirname, len + 8, "mt6395-%s", dev_name(chip->dev));
if (size < 0 || (unsigned int)size >= (unsigned int)(len + 8)) {
pr_info("exported device name length %i >= %u or < 0", size,
(unsigned int)(len + 8));
return -EPERM;
}
chip->dbg_dir = debugfs_create_dir(dirname, NULL);
if (!chip->dbg_dir)
return -ENOMEM;
for (i = 0; i < MT6395_DBG_MAX; i++) {
dinfo = &chip->dbg_info[i];
dinfo->chip = chip;
dinfo->node = i;
chip->dbg_entry[i] = debugfs_create_file(mt6395_dentry_name[i],
S_IFREG | 0444,
chip->dbg_dir, dinfo,
&mt6395_dbg_ops);
}
return 0;
}
static void mt6395_uninit_debugfs(struct mt6395_chip *chip)
{
debugfs_remove_recursive(chip->dbg_dir);
}
#else
static int mt6395_init_debugfs(struct mt6395_chip *chip)
{
return 0;
}
static int mt6395_uninit_debugfs(struct mt6395_chip *chip)
{
return 0;
}
#endif /* CONFIG_DEBUG_FS */
static const u8 mt6395_buck_mode_mask[MT6395_RG_BUCK_MAX] = {
MT6395_CH1_MODE_MASK, MT6395_CH2_MODE_MASK, MT6395_CH3_MODE_MASK,
MT6395_CH4_MODE_MASK,
};
static bool mt6395_volatile_reg(struct device *dev, unsigned int reg)
{
if (reg == MT6395_INT_STATUS)
return true;
return false;
}
static const struct regmap_config mt6395_regmap_config = {
.reg_bits = 8,
.val_bits = 8,
.max_register = 0x45,
.cache_type = REGCACHE_NONE,
.volatile_reg = mt6395_volatile_reg,
};
static inline bool mt6395_is_buck(int rid)
{
if (rid >= MT6395_RG_BUCK1 && rid <= MT6395_RG_BUCK4)
return true;
return false;
}
static int mt6395_regulator_get_status(struct regulator_dev *rdev)
{
int ret = 0;
u32 regval = 0;
struct mt6395_regulator_drvdata *drvdata = rdev_get_drvdata(rdev);
struct regulator_desc *rdesc = &drvdata->rdesc;
ret = __regmap_read(rdev->regmap, rdesc->enable_reg, &regval);
if (ret < 0) {
dev_info(&rdev->dev, "%s get enable status fail(%d)\n",
__func__, ret);
return ret;
}
return (regval & rdesc->enable_mask) ? REGULATOR_STATUS_ON :
REGULATOR_STATUS_OFF;
}
static inline int mt6395_set_pwm_mode(struct regulator_dev *rdev, int rid,
bool pwm)
{
u8 mask = mt6395_buck_mode_mask[rid];
u8 val = pwm ? mask : 0;
return regmap_update_bits(rdev->regmap, MT6395_BUCK_MODE_CTRL, mask,
val);
}
static inline int mt6395_set_standby_mode(struct regulator_dev *rdev,
bool standby)
{
u8 val = standby ? MT6395_SLEEP_MODE_MASK : 0;
return regmap_update_bits(rdev->regmap, MT6395_SLEEP_MODE_CTRL,
MT6395_SLEEP_MODE_MASK, val);
}
static int mt6395_regulator_set_mode(struct regulator_dev *rdev,
unsigned int mode)
{
int ret;
struct mt6395_regulator_drvdata *drvdata = rdev_get_drvdata(rdev);
struct regulator_desc *rdesc = &drvdata->rdesc;
int rid = rdesc->id;
switch (mode) {
case REGULATOR_MODE_FAST:
if (!mt6395_is_buck(rid))
return -EINVAL;
ret = mt6395_set_pwm_mode(rdev, rid, true);
break;
case REGULATOR_MODE_NORMAL:
if (mt6395_is_buck(rid)) {
ret = mt6395_set_pwm_mode(rdev, rid, false);
if (ret < 0)
return ret;
}
ret = mt6395_set_standby_mode(rdev, false);
break;
case REGULATOR_MODE_STANDBY:
ret = mt6395_set_standby_mode(rdev, true);
break;
default:
return -EINVAL;
}
return ret;
}
/*
* Even though the return type is unsigned int,
* regulator framework returns negative value when it fails
*/
static unsigned int mt6395_regulator_get_mode(struct regulator_dev *rdev)
{
int ret = 0;
struct mt6395_regulator_drvdata *drvdata = rdev_get_drvdata(rdev);
struct regulator_desc *rdesc = &drvdata->rdesc;
int rid = rdesc->id;
u32 regval = 0;
ret = __regmap_read(rdev->regmap, MT6395_SLEEP_MODE_CTRL, &regval);
if (ret < 0)
return ret;
if (regval & MT6395_SLEEP_MODE_MASK)
return REGULATOR_MODE_STANDBY;
if (!mt6395_is_buck(rid))
return REGULATOR_MODE_NORMAL;
ret = __regmap_read(rdev->regmap, MT6395_BUCK_MODE_CTRL, &regval);
if (ret < 0)
return ret;
if (regval & mt6395_buck_mode_mask[rid])
return REGULATOR_MODE_FAST;
return REGULATOR_MODE_NORMAL;
}
static const u8 mt6395_ramp_delay_regval[] = {
0x03, 0x02, 0x01, 0x00
};
static int mt6395_regulator_set_ramp_delay(struct regulator_dev *rdev,
int ramp_delay)
{
u8 regval = 0;
if (ramp_delay < 0)
return -EINVAL;
if (ramp_delay < 5000)
ramp_delay = 5000;
else if (ramp_delay > 20000)
ramp_delay = 20000;
/*
* (ramp delay + (step - 1000) - step) / step
* (ramp delay - 1000) / step
*/
regval = (ramp_delay - 1000) / 5000;
/* map ramp delay to register value */
regval = mt6395_ramp_delay_regval[regval];
return regmap_update_bits(rdev->regmap, MT6395_SLEW_RATE_CTRL,
MT6395_CH1_SLEW_RATE_MASK,
regval << MT6395_CH1_SLEW_RATE_SHFT);
}
static int mt6395_get_voltage_sel(struct regulator_dev *rdev)
{
int ret = 0;
u32 regval = 0;
struct mt6395_regulator_drvdata *drvdata = rdev_get_drvdata(rdev);
struct regulator_desc *rdesc = &drvdata->rdesc;
ret = __regmap_read(rdev->regmap, rdesc->vsel_reg, &regval);
if (ret < 0) {
dev_info(&rdev->dev, "%s get volt fail(%d)\n", __func__, ret);
return ret;
}
regval &= rdev->desc->vsel_mask;
regval >>= ffs(rdev->desc->vsel_mask) - 1;
return regval;
}
/* Modifiable regulator */
static const struct regulator_ops mt6395_regulator_ops = {
.list_voltage = regulator_list_voltage_linear,
.enable = regulator_enable_regmap,
.disable = regulator_disable_regmap,
.is_enabled = regulator_is_enabled_regmap,
.set_voltage_sel = regulator_set_voltage_sel_regmap,
.get_voltage_sel = mt6395_get_voltage_sel,
.set_mode = mt6395_regulator_set_mode,
.get_mode = mt6395_regulator_get_mode,
.get_status = mt6395_regulator_get_status,
.set_ramp_delay = mt6395_regulator_set_ramp_delay,
.set_voltage_time_sel = regulator_set_voltage_time_sel,
};
/* Fixed regulator */
static const struct regulator_ops mt6395_fixed_regulator_ops = {
.enable = regulator_enable_regmap,
.disable = regulator_disable_regmap,
.is_enabled = regulator_is_enabled_regmap,
.set_mode = mt6395_regulator_set_mode,
.get_mode = mt6395_regulator_get_mode,
.get_status = mt6395_regulator_get_status,
};
#define MT6395_REGULATOR_LINEAR(_name, _match) \
{ \
.rdesc = { \
.name = #_name, \
.of_match = #_match, \
.ops = &mt6395_regulator_ops, \
.type = REGULATOR_VOLTAGE, \
.id = _name##_id, \
.owner = THIS_MODULE, \
.n_voltages = _name##_n_voltages, \
.linear_min_sel = _name##_linear_min_sel, \
.min_uV = _name##_min_uV, \
.uV_step = _name##_uV_step, \
.vsel_reg = _name##_vsel_reg, \
.vsel_mask = _name##_vsel_mask, \
.enable_reg = _name##_enable_reg, \
.enable_mask = _name##_enable_mask, \
.enable_val = _name##_enable_mask, \
.disable_val = 0, \
}, \
}
#define MT6395_REGULATOR_FIXED(_name, _match) \
{ \
.rdesc = { \
.name = #_name, \
.of_match = #_match, \
.ops = &mt6395_fixed_regulator_ops, \
.type = REGULATOR_VOLTAGE, \
.id = _name##_id, \
.owner = THIS_MODULE, \
.n_voltages = 1, \
.fixed_uV = _name##_fixed_uV, \
.enable_reg = _name##_enable_reg, \
.enable_mask = _name##_enable_mask, \
.enable_val = _name##_enable_mask, \
.disable_val = 0, \
}, \
}
static struct mt6395_regulator_drvdata
mt6395_regulator_drvdata_tbl[MT6395_RG_MAX] = {
MT6395_REGULATOR_LINEAR(mt6395_buck1, mt6395_buck1),
MT6395_REGULATOR_FIXED(mt6395_buck2, mt6395_buck2),
MT6395_REGULATOR_FIXED(mt6395_buck3, mt6395_buck3),
MT6395_REGULATOR_FIXED(mt6395_buck4, mt6395_buck4),
MT6395_REGULATOR_FIXED(mt6395_ldo1, mt6395_ldo1),
};
static int mt6395_register_regulator(struct mt6395_chip *chip)
{
int ret, i;
struct device_node *np = chip->dev->of_node;
struct device_node *chd_np;
struct regulator_desc *rdesc;
struct regulator_config rcfg = {};
struct regulator_init_data *init_data;
struct regulator_dev *rdev;
struct mt6395_regulator_drvdata *drvdata;
struct regulation_constraints *constraints;
for (i = 0; i < MT6395_RG_MAX; i++) {
drvdata = &mt6395_regulator_drvdata_tbl[i];
rdesc = &drvdata->rdesc;
chd_np = of_get_child_by_name(np, rdesc->name);
if (!chd_np)
continue;
init_data = of_get_regulator_init_data(chip->dev, chd_np,
rdesc);
if (!init_data)
continue;
rcfg.init_data = init_data;
rcfg.dev = chip->dev;
rcfg.regmap = chip->regmap;
rcfg.driver_data = drvdata;
rcfg.of_node = chd_np;
rdev = devm_regulator_register(chip->dev, rdesc, &rcfg);
if (IS_ERR(rdev)) {
ret = PTR_ERR(rdev);
dev_info(chip->dev, "%s register %s fail(%d)\n",
__func__, rdesc->name, ret);
return ret;
}
constraints = rdev->constraints;
constraints->valid_modes_mask |= REGULATOR_MODE_NORMAL |
REGULATOR_MODE_STANDBY |
REGULATOR_MODE_FAST;
constraints->valid_ops_mask |= REGULATOR_CHANGE_MODE;
}
return 0;
}
static int mt6395_hotdie_irq_handler(struct mt6395_chip *chip)
{
return 0;
}
static int mt6395_pwrkey_release_irq_handler(struct mt6395_chip *chip)
{
#ifdef CONFIG_KPD_PWRKEY_USE_PMIC
kpd_pwrkey_pmic_handler(0);
#endif
return 0;
}
static int mt6395_pwrkey_press_irq_handler(struct mt6395_chip *chip)
{
#ifdef CONFIG_KPD_PWRKEY_USE_PMIC
kpd_pwrkey_pmic_handler(1);
#endif
return 0;
}
struct irq_mapping_tbl {
const char *name;
int (*hdlr)(struct mt6395_chip *chip);
int num;
};
#define MT6395_IRQ_MAPPING(_name, _num) \
{.name = #_name, .hdlr = mt6395_##_name##_irq_handler, .num = _num}
static const struct irq_mapping_tbl mt6395_irq_mapping_tbl[] = {
MT6395_IRQ_MAPPING(hotdie, 0),
MT6395_IRQ_MAPPING(pwrkey_press, 6),
MT6395_IRQ_MAPPING(pwrkey_release, 5),
};
static int __mt6395_irq_handler(struct mt6395_chip *chip)
{
int i = 0, ret = 0;
u32 event = 0, mask = 0;
ret = __regmap_read(chip->regmap, MT6395_INT_STATUS, &event);
if (ret < 0)
goto err;
ret = __regmap_read(chip->regmap, MT6395_INT_ENABLE, &mask);
if (ret < 0)
goto err;
ret = __regmap_write_bits(chip->regmap, MT6395_INT_STATUS,
MT6395_INT_STATUS_MASK, event);
if (ret < 0)
goto err;
event &= mask;
for (i = 0; i < ARRAY_SIZE(mt6395_irq_mapping_tbl); i++) {
if (event & BIT(mt6395_irq_mapping_tbl[i].num))
mt6395_irq_mapping_tbl[i].hdlr(chip);
}
err:
return ret;
}
static irqreturn_t mt6395_irq_handler(int irq, void *data)
{
int ret;
struct mt6395_chip *chip = (struct mt6395_chip *)data;
do {
ret = __mt6395_irq_handler(chip);
if (ret < 0)
dev_info(chip->dev, "%s handle irq fail(%d)\n",
__func__, ret);
ret = gpiod_get_value(chip->irq_gpio);
if (ret < 0)
dev_info(chip->dev, "%s get irq gpio status fail(%d)\n",
__func__, ret);
} while (ret == 0);
return IRQ_HANDLED;
}
static int mt6395_register_irq(struct mt6395_chip *chip)
{
int ret, len;
char *name;
/* Mask & clear all events */
regmap_update_bits(chip->regmap, MT6395_INT_ENABLE,
MT6395_INT_STATUS_MASK, 0x00);
__regmap_write_bits(chip->regmap, MT6395_INT_STATUS,
MT6395_INT_STATUS_MASK, MT6395_INT_STATUS_MASK);
chip->irq_gpio = devm_gpiod_get(chip->dev, "mt6395,irq", GPIOD_IN);
if (IS_ERR(chip->irq_gpio))
return PTR_ERR(chip->irq_gpio);
chip->irq = gpiod_to_irq(chip->irq_gpio);
len = strlen(dev_name(chip->dev));
name = devm_kzalloc(chip->dev, len + 5, GFP_KERNEL);
if (!name)
return -ENOMEM;
snprintf(name, len + 5, "%s_irq", dev_name(chip->dev));
/* Request threaded IRQ */
ret = devm_request_threaded_irq(chip->dev, chip->irq, NULL,
mt6395_irq_handler,
IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
name, chip);
if (ret < 0) {
dev_info(chip->dev, "%s request thread irq fail\n", __func__);
return ret;
}
device_init_wakeup(chip->dev, true);
return 0;
}
static int mt6395_init_irq(struct mt6395_chip *chip)
{
u8 mask = MT6395_INT_STATUS_MASK;
return regmap_update_bits(chip->regmap, MT6395_INT_ENABLE,
MT6395_INT_STATUS_MASK, mask);
}
static int mt6395_i2c_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
int ret = 0;
struct mt6395_chip *chip;
dev_info(&client->dev, "%s %s\n", __func__, MT6395_DRV_VERSION);
#ifdef RW_SYNC_WITH_MCU
csram_base = ioremap(PMIC_SYNC_S, 8);
if (csram_base == NULL) {
dev_info(&client->dev, "[%s] ioremap failed\n", __func__);
return -ENOMEM;
}
csram_write(OFFS_KR, 0);
#endif
chip = devm_kzalloc(&client->dev, sizeof(*chip), GFP_KERNEL);
if (!chip)
return -ENOMEM;
chip->regmap = devm_regmap_init_i2c(client, &mt6395_regmap_config);
if (IS_ERR(chip->regmap))
return PTR_ERR(chip->regmap);
mutex_init(&chip->io_lock);
chip->client = client;
chip->dev = &client->dev;
i2c_set_clientdata(client, chip);
ret = mt6395_register_regulator(chip);
if (ret < 0)
goto err;
ret = mt6395_register_irq(chip);
if (ret < 0)
goto err;
ret = mt6395_init_debugfs(chip);
if (ret < 0)
dev_info(chip->dev, "%s init debugfs fail\n", __func__);
ret = mt6395_init_irq(chip);
if (ret < 0)
goto err;
dev_info(chip->dev, "%s successfully\n", __func__);
return 0;
err:
return ret;
}
static int mt6395_remove(struct i2c_client *client)
{
struct mt6395_chip *chip = i2c_get_clientdata(client);
if (chip)
mt6395_uninit_debugfs(chip);
return 0;
}
static int mt6395_suspend(struct device *dev)
{
struct mt6395_chip *chip = dev_get_drvdata(dev);
if (device_may_wakeup(dev))
enable_irq_wake(chip->irq);
return 0;
}
static int mt6395_resume(struct device *dev)
{
struct mt6395_chip *chip = dev_get_drvdata(dev);
if (device_may_wakeup(dev))
disable_irq_wake(chip->irq);
return 0;
}
static SIMPLE_DEV_PM_OPS(mt6395_pm_ops, mt6395_suspend, mt6395_resume);
static const struct of_device_id mt6395_match_table[] = {
{ .compatible = "mediatek,mt6395-regulator", },
{},
};
MODULE_DEVICE_TABLE(of, mt6395_match_table);
static const struct i2c_device_id mt6395_dev_id[] = {
{"mt6395-regulator", 0},
{},
};
MODULE_DEVICE_TABLE(i2c, mt6395_dev_id);
static struct i2c_driver mt6395_i2c_driver = {
.driver = {
.name = "mt6395-regulator",
.owner = THIS_MODULE,
.of_match_table = of_match_ptr(mt6395_match_table),
.pm = &mt6395_pm_ops,
},
.probe = mt6395_i2c_probe,
.remove = mt6395_remove,
.id_table = mt6395_dev_id,
};
module_i2c_driver(mt6395_i2c_driver);
MODULE_LICENSE("GPL v2");
MODULE_AUTHOR("ShuFan Lee <shufan_lee@richtek.com>");
MODULE_DESCRIPTION("Regulator driver for MT6395");