[ALPS05014853] PMIC: MT6315 Regulator porting

[Detail]
gpufreq_init_pmic: cannot get VGPU since mt6315
is not ready. This patch back port the regulator
from q0 to r0.

MTK-Commit-Id: 0946f1cfe55003ba9bcf76211182129957d9cc05

Change-Id: I93e3bc034a03abe545556a8615e3cae19179e9a7
Signed-off-by: Juju Sung <juju.sung@mediatek.com>
CR-Id: ALPS05014853
Feature: [Module]Kernel Maintenance
This commit is contained in:
Juju Sung
2020-04-23 18:16:00 +08:00
parent 92b88d868c
commit 188933e28f
9 changed files with 1843 additions and 8 deletions

View File

@@ -771,6 +771,18 @@ config MFD_MT6358
accessing the device; additional drivers must be enabled in order
to use the functionality of the device.
config MFD_MT6362
tristate "MT6362 SPMI PMIC"
depends on OF
depends on SPMI
select REGMAP_SPMI
select REGMAP_IRQ
help
This enables support for the Mediatek SPMI PMICs.
These PMICs are currently used with the Mediatek series of
SoCs. Note, that this will only be useful paired with descriptions
of the independent functions as children nodes in the device tree.
config MT6358_MISC
tristate "MediaTek MT6358 MISC FUNCTIONS Support"
depends on MFD_MT6358

View File

@@ -550,6 +550,15 @@ config REGULATOR_MT6311
This driver supports the control of different power rails of device
through regulator interface.
config REGULATOR_MT6315
tristate "MediaTek MT6315 PMIC"
depends on MTK_MFD_SPMI_PMIC
help
Say y here to select this option to enable the power regulator of
MediaTek MT6315 PMIC.
This driver supports the control of different power rails of device
through regulator interface.
config REGULATOR_MT6323
tristate "MediaTek MT6323 PMIC"
depends on MFD_MT6397
@@ -586,6 +595,16 @@ config REGULATOR_MT6359P
This driver supports the control of different power rails of device
through regulator interface.
config REGULATOR_MT6362
tristate "MT6362 SPMI Regulator driver"
depends on MFD_MT6362
help
Say yes here to have support for the MT6362 Regulator
Include six BUCKs and seven LDOs.
The driver can also be build as a module.
If so, the module will be called mt6362_regulator
config REGULATOR_MT6380
tristate "MediaTek MT6380 PMIC"
depends on MTK_PMIC_WRAP

View File

@@ -3,6 +3,9 @@
# Makefile for regulator drivers.
#
ifeq ($(CONFIG_MTK_GCOV_KERNEL),y)
GCOV_PROFILE_mt6359p-regulator.o := y
endif
obj-$(CONFIG_REGULATOR) += core.o dummy.o fixed-helper.o helpers.o devres.o
obj-$(CONFIG_OF) += of_regulator.o
@@ -72,10 +75,12 @@ obj-$(CONFIG_REGULATOR_MC13783) += mc13783-regulator.o
obj-$(CONFIG_REGULATOR_MC13892) += mc13892-regulator.o
obj-$(CONFIG_REGULATOR_MC13XXX_CORE) += mc13xxx-regulator-core.o
obj-$(CONFIG_REGULATOR_MT6311) += mt6311-regulator.o
obj-$(CONFIG_REGULATOR_MT6315) += mt6315-regulator.o mt6315-misc.o
obj-$(CONFIG_REGULATOR_MT6323) += mt6323-regulator.o
obj-$(CONFIG_REGULATOR_MT6358) += mt6358-regulator.o
obj-$(CONFIG_REGULATOR_MT6359) += mt6359-regulator.o
obj-$(CONFIG_REGULATOR_MT6359P) += mt6359p-regulator.o
obj-$(CONFIG_REGULATOR_MT6362) += mt6362-regulator.o
obj-$(CONFIG_REGULATOR_MT6380) += mt6380-regulator.o
obj-$(CONFIG_REGULATOR_MT6392) += mt6392-regulator.o
obj-$(CONFIG_REGULATOR_MT6397) += mt6397-regulator.o

View File

@@ -0,0 +1,391 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (c) 2019 MediaTek Inc.
*/
#include <linux/mfd/mt6315/registers.h>
#include <linux/pmif.h>
#include <linux/regmap.h>
#include <linux/regulator/consumer.h>
#include <linux/regulator/mt6315-misc.h>
#include <linux/regulator/mt6315-regulator.h>
#define LP_INIT_SETTING_VERIFIED 1
#define MT6315_DECL_CHIP(_mid, _saddr)\
{ \
.master_idx = _mid, \
.slave_addr = _saddr, \
.regmap = NULL, \
}
static struct mt6315_misc mt6315_misc[] = {
#if defined(CONFIG_MACH_MT6885) || defined(CONFIG_MACH_MT6873)
MT6315_DECL_CHIP(SPMI_MASTER_0, MT6315_SLAVE_ID_6),
MT6315_DECL_CHIP(SPMI_MASTER_0, MT6315_SLAVE_ID_7),
MT6315_DECL_CHIP(SPMI_MASTER_0, MT6315_SLAVE_ID_3),
#elif defined(CONFIG_MACH_MT6853)
MT6315_DECL_CHIP(SPMI_MASTER_0, MT6315_SLAVE_ID_3),
#endif
};
static struct mt6315_misc *mt6315_find_chip_sid(u32 sid)
{
int i;
for (i = 0; i < ARRAY_SIZE(mt6315_misc); i++) {
if (mt6315_misc[i].slave_addr == sid)
return &mt6315_misc[i];
}
return NULL;
}
static unsigned int g_vmodem_vosel;
static unsigned int g_vnr_vosel;
static unsigned int g_vsram_md_vosel;
static void mt6315_S3_default_vosel(void)
{
struct mt6315_misc *mt6315;
struct regmap *regmap;
mt6315 = mt6315_find_chip_sid(MT6315_SLAVE_ID_3);
if (!mt6315) {
pr_info("%s MT6315S3 not ready.\n", __func__);
return;
}
regmap = mt6315->regmap;
if (!regmap) {
pr_info("%s null regmap.\n", __func__);
return;
}
if (g_vmodem_vosel != 0) {
#if defined(CONFIG_MACH_MT6885) || defined(CONFIG_MACH_MT6873)
regmap_write(regmap, MT6315_PMIC_RG_BUCK_VBUCK1_VOSEL_ADDR,
g_vmodem_vosel);
regmap_write(regmap, MT6315_PMIC_RG_BUCK_VBUCK3_VOSEL_ADDR,
g_vnr_vosel);
regmap_write(regmap, MT6315_PMIC_RG_BUCK_VBUCK4_VOSEL_ADDR,
g_vsram_md_vosel);
#elif defined(CONFIG_MACH_MT6853)
regmap_write(regmap, MT6315_PMIC_RG_BUCK_VBUCK1_VOSEL_ADDR,
g_vmodem_vosel);
regmap_write(regmap, MT6315_PMIC_RG_BUCK_VBUCK4_VOSEL_ADDR,
g_vsram_md_vosel);
#endif
pr_info("[%s] set vmodem=0x%x, vnr=0x%x, vsram_md=0x%x\n"
, __func__, g_vmodem_vosel, g_vnr_vosel,
g_vsram_md_vosel);
} else {
#if defined(CONFIG_MACH_MT6885) || defined(CONFIG_MACH_MT6873)
regmap_read(regmap, MT6315_PMIC_DA_VBUCK1_VOSEL_ADDR,
&g_vmodem_vosel);
regmap_read(regmap, MT6315_PMIC_DA_VBUCK3_VOSEL_ADDR,
&g_vnr_vosel);
regmap_read(regmap, MT6315_PMIC_DA_VBUCK4_VOSEL_ADDR,
&g_vsram_md_vosel);
#elif defined(CONFIG_MACH_MT6853)
regmap_read(regmap, MT6315_PMIC_DA_VBUCK1_VOSEL_ADDR,
&g_vmodem_vosel);
g_vnr_vosel = g_vmodem_vosel;
regmap_read(regmap, MT6315_PMIC_DA_VBUCK4_VOSEL_ADDR,
&g_vsram_md_vosel);
#endif
pr_info("[%s] record vmodem=0x%x, vnr=0x%x, vsram_md=0x%x\n"
, __func__, g_vmodem_vosel, g_vnr_vosel,
g_vsram_md_vosel);
}
}
void mt6315_vmd1_pmic_setting_on(void)
{
/* Reset VMODEM/VNR/VSRAM_MD default voltage */
mt6315_S3_default_vosel();
}
static int is_mt6315_S3_exist(void)
{
int ret = 0;
struct regulator *reg;
reg = regulator_get_optional(NULL, "3_vbuck1");
if (IS_ERR(reg))
return 0;
if (regulator_is_enabled(reg))
ret = 1;
regulator_put(reg);
return ret;
}
static int is_mt6315_S6_exist(void)
{
int ret = 0;
struct regulator *reg;
reg = regulator_get_optional(NULL, "6_vbuck1");
if (IS_ERR(reg))
return 0;
if (regulator_is_enabled(reg))
ret = 1;
regulator_put(reg);
return ret;
}
static int is_mt6315_S7_exist(void)
{
int ret = 0;
struct regulator *reg;
reg = regulator_get_optional(NULL, "7_vbuck1");
if (IS_ERR(reg))
return 0;
if (regulator_is_enabled(reg))
ret = 1;
regulator_put(reg);
return ret;
}
int is_mt6315_exist(void)
{
#if defined(CONFIG_MACH_MT6885) || defined(CONFIG_MACH_MT6873)
pr_info("%s S3:%d S6:%d S7:%d\n", __func__, is_mt6315_S3_exist()
, is_mt6315_S6_exist(), is_mt6315_S7_exist());
if (is_mt6315_S3_exist() && is_mt6315_S6_exist() &&
is_mt6315_S7_exist())
return 1;
#elif defined(CONFIG_MACH_MT6853)
pr_info("%s S3:%d\n", __func__, is_mt6315_S3_exist());
return is_mt6315_S3_exist();
#endif
return 0;
}
#if LP_INIT_SETTING_VERIFIED
static void mt6315_vbuck1_lp_setting(struct regmap *regmap,
enum MT6315_BUCK_EN_USER user, unsigned char mode,
unsigned char en, unsigned char cfg)
{
if (user == MT6315_SRCLKEN0) {
regmap_update_bits(regmap,
MT6315_PMIC_RG_BUCK_VBUCK1_HW0_OP_MODE_ADDR,
0x1 << MT6315_PMIC_RG_BUCK_VBUCK1_HW0_OP_MODE_SHIFT,
mode << MT6315_PMIC_RG_BUCK_VBUCK1_HW0_OP_MODE_SHIFT);
regmap_update_bits(regmap,
MT6315_PMIC_RG_BUCK_VBUCK1_HW0_OP_EN_ADDR,
0x1 << MT6315_PMIC_RG_BUCK_VBUCK1_HW0_OP_EN_SHIFT,
en << MT6315_PMIC_RG_BUCK_VBUCK1_HW0_OP_EN_SHIFT);
regmap_update_bits(regmap,
MT6315_PMIC_RG_BUCK_VBUCK1_HW0_OP_CFG_ADDR,
0x1 << MT6315_PMIC_RG_BUCK_VBUCK1_HW0_OP_CFG_SHIFT,
cfg << MT6315_PMIC_RG_BUCK_VBUCK1_HW0_OP_CFG_SHIFT);
} else {
pr_info("%s non support user control(%d).\n", __func__, user);
}
}
static void mt6315_vbuck2_lp_setting(struct regmap *regmap,
enum MT6315_BUCK_EN_USER user, unsigned char mode,
unsigned char en, unsigned char cfg)
{
if (user == MT6315_SRCLKEN0) {
regmap_update_bits(regmap,
MT6315_PMIC_RG_BUCK_VBUCK2_HW0_OP_MODE_ADDR,
0x1 << MT6315_PMIC_RG_BUCK_VBUCK2_HW0_OP_MODE_SHIFT,
mode << MT6315_PMIC_RG_BUCK_VBUCK2_HW0_OP_MODE_SHIFT);
regmap_update_bits(regmap,
MT6315_PMIC_RG_BUCK_VBUCK2_HW0_OP_EN_ADDR,
0x1 << MT6315_PMIC_RG_BUCK_VBUCK2_HW0_OP_EN_SHIFT,
en << MT6315_PMIC_RG_BUCK_VBUCK2_HW0_OP_EN_SHIFT);
regmap_update_bits(regmap,
MT6315_PMIC_RG_BUCK_VBUCK2_HW0_OP_CFG_ADDR,
0x1 << MT6315_PMIC_RG_BUCK_VBUCK2_HW0_OP_CFG_SHIFT,
cfg << MT6315_PMIC_RG_BUCK_VBUCK2_HW0_OP_CFG_SHIFT);
} else {
pr_info("%s non support user control(%d).\n", __func__, user);
}
}
static void mt6315_vbuck3_lp_setting(struct regmap *regmap,
enum MT6315_BUCK_EN_USER user, unsigned char mode,
unsigned char en, unsigned char cfg)
{
if (user == MT6315_SRCLKEN0) {
regmap_update_bits(regmap,
MT6315_PMIC_RG_BUCK_VBUCK3_HW0_OP_MODE_ADDR,
0x1 << MT6315_PMIC_RG_BUCK_VBUCK3_HW0_OP_MODE_SHIFT,
mode << MT6315_PMIC_RG_BUCK_VBUCK3_HW0_OP_MODE_SHIFT);
regmap_update_bits(regmap,
MT6315_PMIC_RG_BUCK_VBUCK3_HW0_OP_EN_ADDR,
0x1 << MT6315_PMIC_RG_BUCK_VBUCK3_HW0_OP_EN_SHIFT,
en << MT6315_PMIC_RG_BUCK_VBUCK3_HW0_OP_EN_SHIFT);
regmap_update_bits(regmap,
MT6315_PMIC_RG_BUCK_VBUCK3_HW0_OP_CFG_ADDR,
0x1 << MT6315_PMIC_RG_BUCK_VBUCK3_HW0_OP_CFG_SHIFT,
cfg << MT6315_PMIC_RG_BUCK_VBUCK3_HW0_OP_CFG_SHIFT);
} else {
pr_info("%s non support user control(%d).\n", __func__, user);
}
}
static void mt6315_vbuck4_lp_setting(struct regmap *regmap,
enum MT6315_BUCK_EN_USER user, unsigned char mode,
unsigned char en, unsigned char cfg)
{
if (user == MT6315_SRCLKEN0) {
regmap_update_bits(regmap,
MT6315_PMIC_RG_BUCK_VBUCK4_HW0_OP_MODE_ADDR,
0x1 << MT6315_PMIC_RG_BUCK_VBUCK4_HW0_OP_MODE_SHIFT,
mode << MT6315_PMIC_RG_BUCK_VBUCK4_HW0_OP_MODE_SHIFT);
regmap_update_bits(regmap,
MT6315_PMIC_RG_BUCK_VBUCK4_HW0_OP_EN_ADDR,
0x1 << MT6315_PMIC_RG_BUCK_VBUCK4_HW0_OP_EN_SHIFT,
en << MT6315_PMIC_RG_BUCK_VBUCK4_HW0_OP_EN_SHIFT);
regmap_update_bits(regmap,
MT6315_PMIC_RG_BUCK_VBUCK4_HW0_OP_CFG_ADDR,
0x1 << MT6315_PMIC_RG_BUCK_VBUCK4_HW0_OP_CFG_SHIFT,
cfg << MT6315_PMIC_RG_BUCK_VBUCK4_HW0_OP_CFG_SHIFT);
} else {
pr_info("%s non support user control(%d).\n", __func__, user);
}
}
static void mt6315_lp_set(unsigned char slave_id, unsigned char buck_id,
enum MT6315_BUCK_EN_USER user, unsigned char op_mode,
unsigned char op_en, unsigned char op_cfg)
{
struct mt6315_misc *mt6315;
struct regmap *regmap;
mt6315 = mt6315_find_chip_sid(slave_id);
if (!mt6315) {
pr_info("%s MT6315S%d not ready\n", __func__, slave_id);
return;
}
regmap = mt6315->regmap;
if (!regmap) {
pr_info("%s null regmap.\n", __func__);
return;
}
if (buck_id == 1)
mt6315_vbuck1_lp_setting(regmap, user, op_mode, op_en, op_cfg);
else if (buck_id == 2)
mt6315_vbuck2_lp_setting(regmap, user, op_mode, op_en, op_cfg);
else if (buck_id == 3)
mt6315_vbuck3_lp_setting(regmap, user, op_mode, op_en, op_cfg);
else if (buck_id == 4)
mt6315_vbuck4_lp_setting(regmap, user, op_mode, op_en, op_cfg);
else
pr_info("%s invalid buck_id=%d.\n", __func__, buck_id);
}
/* enable VDIG18 SRCLKEN low power mode */
static void mt6315_vdig18_hw_op_set(unsigned char slave_id, unsigned char en)
{
struct mt6315_misc *mt6315;
struct regmap *regmap;
mt6315 = mt6315_find_chip_sid(slave_id);
if (!mt6315) {
pr_info("%s MT6315S%d not ready\n", __func__, slave_id);
return;
}
regmap = mt6315->regmap;
if (!regmap) {
pr_info("%s null regmap.\n", __func__);
return;
}
regmap_write(regmap, MT6315_PMIC_DIG_WPK_KEY_H_ADDR, 0x63);
regmap_write(regmap, MT6315_PMIC_DIG_WPK_KEY_ADDR, 0x15);
regmap_update_bits(regmap,
MT6315_PMIC_RG_LDO_VDIG18_HW_OP_EN_ADDR,
0x1 << MT6315_PMIC_RG_LDO_VDIG18_HW_OP_EN_SHIFT,
en << MT6315_PMIC_RG_LDO_VDIG18_HW_OP_EN_SHIFT);
regmap_write(regmap, MT6315_PMIC_DIG_WPK_KEY_ADDR, 0x0);
regmap_write(regmap, MT6315_PMIC_DIG_WPK_KEY_H_ADDR, 0x0);
}
#endif /* End of LP_INIT_SETTING_VERIFIED */
static void mt6315_S3_lp_initial_setting(void)
{
#if LP_INIT_SETTING_VERIFIED
#if defined(CONFIG_MACH_MT6885) || defined(CONFIG_MACH_MT6873)
mt6315_vdig18_hw_op_set(MT6315_SLAVE_ID_3, 1);
/* vmodem/vnr/vsram_md */
mt6315_lp_set(MT6315_SLAVE_ID_3, 1, MT6315_SRCLKEN0, 1, 1, HW_LP);
mt6315_lp_set(MT6315_SLAVE_ID_3, 3, MT6315_SRCLKEN0, 1, 1, HW_LP);
mt6315_lp_set(MT6315_SLAVE_ID_3, 4, MT6315_SRCLKEN0, 1, 1, HW_LP);
#elif defined(CONFIG_MACH_MT6853)
mt6315_vdig18_hw_op_set(MT6315_SLAVE_ID_3, 1);
/* vmodem/vpu/vsram_md */
mt6315_lp_set(MT6315_SLAVE_ID_3, 1, MT6315_SRCLKEN0, 1, 1, HW_LP);
mt6315_lp_set(MT6315_SLAVE_ID_3, 3, MT6315_SRCLKEN0, 1, 1, HW_LP);
mt6315_lp_set(MT6315_SLAVE_ID_3, 4, MT6315_SRCLKEN0, 1, 1, HW_LP);
#endif
#endif
}
static void mt6315_S6_lp_initial_setting(void)
{
#if LP_INIT_SETTING_VERIFIED
#if defined(CONFIG_MACH_MT6885) || defined(CONFIG_MACH_MT6873)
mt6315_vdig18_hw_op_set(MT6315_SLAVE_ID_6, 1);
#endif
#endif
}
static void mt6315_S7_lp_initial_setting(void)
{
#if LP_INIT_SETTING_VERIFIED
#if defined(CONFIG_MACH_MT6885)
mt6315_vdig18_hw_op_set(MT6315_SLAVE_ID_7, 1);
/* vsram_core */
mt6315_lp_set(MT6315_SLAVE_ID_7, 3, MT6315_SRCLKEN0, 1, 1, HW_LP);
#elif defined(CONFIG_MACH_MT6873)
mt6315_vdig18_hw_op_set(MT6315_SLAVE_ID_7, 1);
#endif
#endif
}
static void mt6315_misc_initial_setting(u32 sid)
{
switch (sid) {
case MT6315_SLAVE_ID_3:
mt6315_S3_lp_initial_setting();
mt6315_S3_default_vosel();
break;
case MT6315_SLAVE_ID_6:
mt6315_S6_lp_initial_setting();
break;
case MT6315_SLAVE_ID_7:
mt6315_S7_lp_initial_setting();
break;
default:
pr_info("unsupported chip sid: %d\n", sid);
return;
}
}
void mt6315_misc_init(u32 sid, struct regmap *regmap)
{
struct mt6315_misc *mt6315;
mt6315 = mt6315_find_chip_sid(sid);
if (mt6315)
mt6315->regmap = regmap;
mt6315_misc_initial_setting(sid);
pr_info("%s sid=%d done\n", __func__, sid);
}

View File

@@ -0,0 +1,779 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (c) 2019 MediaTek Inc.
*/
#include <linux/interrupt.h>
#include <linux/mfd/mt6315/registers.h>
#include <linux/module.h>
#include <linux/of_device.h>
#include <linux/of_irq.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
#include <linux/regulator/driver.h>
#include <linux/regulator/machine.h>
#include <linux/regulator/mt6315-misc.h>
#include <linux/regulator/mt6315-regulator.h>
#include <linux/regulator/of_regulator.h>
#define MT6315_REG_WIDTH 8
#define MT6315_BUCK_MODE_AUTO 0
#define MT6315_BUCK_MODE_FORCE_PWM 1
#define MT6315_BUCK_MODE_NORMAL 0
#define MT6315_BUCK_MODE_LP 2
/*
* MT6315 irqs' information
*/
enum mt6315_irq_numbers {
MT6315_IRQ_VBUCK1_OC = 0,
MT6315_IRQ_VBUCK2_OC,
MT6315_IRQ_VBUCK3_OC,
MT6315_IRQ_VBUCK4_OC,
MT6315_IRQ_TEMP_BACK_110D,
MT6315_IRQ_TEMP_OVER_125D,
MT6315_IRQ_RCS0,
MT6315_IRQ_RCS1,
MT6315_IRQ_NR,
};
struct pmic_irq_data {
//unsigned int num_top;
unsigned int num_pmic_irqs;
unsigned int reg_width;
//unsigned short top_int_status_reg;
unsigned int *enable_hwirq;
unsigned int *cache_hwirq;
//struct irq_top_t *pmic_ints;
unsigned int en_reg;
unsigned int sta_reg;
};
/*
* MT6315 regulators' information
*
* @desc: standard fields of regulator description.
* @da_reg: for query status of regulators.
* @qi: Mask for query enable signal status of regulators.
* @modeset_reg: for operating AUTO/PWM mode register.
* @modeset_mask: MASK for operating modeset register.
*/
struct mt6315_regulator_info {
struct regulator_desc desc;
struct regulation_constraints constraints;
u32 da_vsel_reg;
u32 da_vsel_mask;
u32 da_vsel_shift;
u32 da_reg;
u32 qi;
u32 modeset_reg;
u32 modeset_mask;
u32 lp_mode_reg;
u32 lp_mode_mask;
u32 lp_mode_shift;
};
/*
* MTK regulators' init data
*
* @id: chip slave id
* @size: num of regulators
* @regulator_info: regulator info.
*/
struct mt_regulator_init_data {
u32 id;
u32 size;
struct mt6315_regulator_info *regulator_info;
};
struct mt6315_chip {
struct device *dev;
struct regmap *regmap;
int irq;
struct irq_domain *irq_domain;
struct mutex irqlock;
void *irq_data;
struct mutex lock;
u32 reg_value;
u32 slave_id;
};
/* MT6315 irqs function */
static void pmic_irq_enable(struct irq_data *data)
{
unsigned int hwirq = irqd_to_hwirq(data);
struct mt6315_chip *chip = irq_data_get_irq_chip_data(data);
struct pmic_irq_data *irq_data = chip->irq_data;
irq_data->enable_hwirq[hwirq] = 1;
}
static void pmic_irq_disable(struct irq_data *data)
{
unsigned int hwirq = irqd_to_hwirq(data);
struct mt6315_chip *chip = irq_data_get_irq_chip_data(data);
struct pmic_irq_data *irq_data = chip->irq_data;
irq_data->enable_hwirq[hwirq] = 0;
}
static void pmic_irq_lock(struct irq_data *data)
{
struct mt6315_chip *chip = irq_data_get_irq_chip_data(data);
mutex_lock(&chip->irqlock);
}
static void pmic_irq_sync_unlock(struct irq_data *data)
{
unsigned int i, en_reg, shift;
struct mt6315_chip *chip = irq_data_get_irq_chip_data(data);
struct pmic_irq_data *irq_data = chip->irq_data;
for (i = 0; i < irq_data->num_pmic_irqs; i++) {
if (irq_data->enable_hwirq[i] ==
irq_data->cache_hwirq[i])
continue;
en_reg = irq_data->en_reg;
shift = i % irq_data->reg_width;
regmap_update_bits(chip->regmap, en_reg, 0x1 << shift,
irq_data->enable_hwirq[i] << shift);
irq_data->cache_hwirq[i] = irq_data->enable_hwirq[i];
}
mutex_unlock(&chip->irqlock);
}
static int pmic_irq_set_type(struct irq_data *data, unsigned int type)
{
return 0;
}
static struct irq_chip mt6315_irq_chip = {
.name = "mt6315-irq",
.irq_enable = pmic_irq_enable,
.irq_disable = pmic_irq_disable,
.irq_bus_lock = pmic_irq_lock,
.irq_bus_sync_unlock = pmic_irq_sync_unlock,
.irq_set_type = pmic_irq_set_type,
};
static irqreturn_t mt6315_irq_handler(int irq, void *data)
{
struct mt6315_chip *chip = data;
struct pmic_irq_data *irq_data = chip->irq_data;
unsigned int int_status = 0;
unsigned int hwirq, virq;
int ret;
ret = regmap_read(chip->regmap,
irq_data->sta_reg,
&int_status);
if (ret) {
dev_notice(chip->dev, "Can't read INT_STATUS ret=%d\n", ret);
return IRQ_NONE;
}
for (hwirq = 0; hwirq < MT6315_REG_WIDTH ; hwirq++) {
if ((int_status & BIT(hwirq)) == 0)
continue;
virq = irq_find_mapping(chip->irq_domain, hwirq);
dev_info(chip->dev,
"Reg[0x%x]=0x%x,hwirq=%d,type=%d\n",
irq_data->sta_reg, int_status, hwirq,
irq_get_trigger_type(virq));
if (virq)
handle_nested_irq(virq);
}
regmap_write(chip->regmap, irq_data->sta_reg, int_status);
return IRQ_HANDLED;
}
static int pmic_irq_domain_map(struct irq_domain *d, unsigned int irq,
irq_hw_number_t hw)
{
struct mt6315_chip *chip = d->host_data;
irq_set_chip_data(irq, chip);
irq_set_chip_and_handler(irq, &mt6315_irq_chip, handle_level_irq);
irq_set_nested_thread(irq, 1);
irq_set_noprobe(irq);
return 0;
}
static const struct irq_domain_ops mt6315_irq_domain_ops = {
.map = pmic_irq_domain_map,
.xlate = irq_domain_xlate_twocell,
};
static int mt6315_irq_init(struct mt6315_chip *chip)
{
int i, ret;
struct pmic_irq_data *irq_data;
if (chip->irq <= 0) {
dev_notice(chip->dev, "bypass %s", __func__);
return 0;
}
irq_data = devm_kzalloc(chip->dev, sizeof(struct pmic_irq_data),
GFP_KERNEL);
if (!irq_data)
return -ENOMEM;
chip->irq_data = irq_data;
mutex_init(&chip->irqlock);
irq_data->num_pmic_irqs = MT6315_IRQ_NR;
irq_data->reg_width = MT6315_REG_WIDTH;
irq_data->en_reg = MT6315_PMIC_RG_INT_EN_VBUCK1_OC_ADDR;
irq_data->sta_reg = MT6315_PMIC_RG_INT_STATUS_VBUCK1_OC_ADDR;
irq_data->enable_hwirq = devm_kcalloc(chip->dev,
irq_data->num_pmic_irqs,
sizeof(unsigned int),
GFP_KERNEL);
if (!irq_data->enable_hwirq)
return -ENOMEM;
irq_data->cache_hwirq = devm_kcalloc(chip->dev,
irq_data->num_pmic_irqs,
sizeof(unsigned int),
GFP_KERNEL);
if (!irq_data->cache_hwirq)
return -ENOMEM;
/* Disable all interrupt for initializing */
for (i = 0; i < irq_data->num_pmic_irqs; i++)
regmap_write(chip->regmap, irq_data->en_reg, 0);
chip->irq_domain = irq_domain_add_linear(chip->dev->of_node,
irq_data->num_pmic_irqs,
&mt6315_irq_domain_ops, chip);
if (!chip->irq_domain) {
dev_notice(chip->dev, "could not create irq domain\n");
return -ENODEV;
}
ret = devm_request_threaded_irq(chip->dev, chip->irq, NULL,
mt6315_irq_handler, IRQF_ONESHOT,
dev_name(chip->dev), chip);
if (ret) {
dev_notice(chip->dev, "failed to register irq=%d; err: %d\n",
chip->irq, ret);
return ret;
}
enable_irq_wake(chip->irq);
return ret;
}
#define MT_BUCK_EN (REGULATOR_CHANGE_STATUS)
#define MT_BUCK_VOL (REGULATOR_CHANGE_VOLTAGE)
#define MT_BUCK_VOL_EN (REGULATOR_CHANGE_STATUS | \
REGULATOR_CHANGE_VOLTAGE)
#define MT_BUCK_VOL_EN_MODE (REGULATOR_CHANGE_STATUS | \
REGULATOR_CHANGE_VOLTAGE | \
REGULATOR_CHANGE_MODE)
#define MT_BUCK(match, _name, min, max, step, volt_ranges, _bid, mode, \
_modeset_mask) \
[MT6315_ID_##_name] = { \
.desc = { \
.name = #_name, \
.of_match = of_match_ptr(match), \
.ops = &mt6315_volt_range_ops, \
.type = REGULATOR_VOLTAGE, \
.id = MT6315_ID_##_name, \
.owner = THIS_MODULE, \
.uV_step = (step), \
.linear_min_sel = (0x30), \
.n_voltages = (max) / (step) + 1, \
.min_uV = (min), \
.linear_ranges = volt_ranges, \
.n_linear_ranges = ARRAY_SIZE(volt_ranges), \
.vsel_reg = MT6315_PMIC_RG_BUCK_VBUCK##_bid##_VOSEL_ADDR,\
.vsel_mask = \
(MT6315_PMIC_RG_BUCK_VBUCK##_bid##_VOSEL_MASK << \
MT6315_PMIC_RG_BUCK_VBUCK##_bid##_VOSEL_SHIFT), \
.enable_reg = MT6315_PMIC_RG_BUCK_VBUCK##_bid##_EN_ADDR,\
.enable_mask = BIT(MT6315_PMIC_RG_BUCK_VBUCK##_bid##_EN_SHIFT),\
}, \
.constraints = { \
.valid_ops_mask = (mode), \
.valid_modes_mask = \
(REGULATOR_MODE_NORMAL | \
REGULATOR_MODE_FAST | \
REGULATOR_MODE_IDLE), \
}, \
.da_vsel_reg = MT6315_PMIC_DA_VBUCK##_bid##_VOSEL_ADDR, \
.da_vsel_mask = MT6315_PMIC_DA_VBUCK##_bid##_VOSEL_MASK, \
.da_vsel_shift = MT6315_PMIC_DA_VBUCK##_bid##_VOSEL_SHIFT, \
.da_reg = MT6315_PMIC_DA_VBUCK##_bid##_EN_ADDR, \
.qi = BIT(0), \
.lp_mode_reg = MT6315_PMIC_RG_BUCK_VBUCK##_bid##_LP_ADDR, \
.lp_mode_mask = BIT(MT6315_PMIC_RG_BUCK_VBUCK##_bid##_LP_SHIFT),\
.lp_mode_shift = MT6315_PMIC_RG_BUCK_VBUCK##_bid##_LP_SHIFT, \
.modeset_reg = MT6315_PMIC_RG_VBUCK##_bid##_FCCM_ADDR, \
.modeset_mask = _modeset_mask, \
}
static const struct regulator_linear_range mt_volt_range1[] = {
REGULATOR_LINEAR_RANGE(300000, 0x30, 0xbf, 6250),
};
static int mt6315_regulator_disable(struct regulator_dev *rdev)
{
int ret = 0;
if (rdev->use_count == 0) {
dev_notice(&rdev->dev, "%s:%s should not be disable.(use_count=0)\n"
, __func__
, rdev->desc->name);
ret = -1;
} else {
ret = regulator_disable_regmap(rdev);
}
return ret;
}
static int mt6315_regulator_get_voltage_sel(struct regulator_dev *rdev)
{
struct mt6315_regulator_info *info = rdev_get_drvdata(rdev);
int ret = 0, regval = 0;
ret = regmap_read(rdev->regmap, info->da_vsel_reg, &regval);
if (ret != 0) {
dev_notice(&rdev->dev,
"Failed to get mt6315 regulator voltage: %d\n", ret);
return ret;
}
ret = (regval >> info->da_vsel_shift) & info->da_vsel_mask;
return ret;
}
static unsigned int mt6315_regulator_get_mode(struct regulator_dev *rdev)
{
struct mt6315_regulator_info *info = rdev_get_drvdata(rdev);
int ret = 0, regval = 0;
ret = regmap_read(rdev->regmap, info->modeset_reg, &regval);
if (ret != 0) {
dev_notice(&rdev->dev,
"Failed to get mt6315 buck mode: %d\n", ret);
return ret;
}
if ((regval & info->modeset_mask) == info->modeset_mask)
return REGULATOR_MODE_FAST;
ret = regmap_read(rdev->regmap, info->lp_mode_reg, &regval);
if (ret != 0) {
dev_notice(&rdev->dev,
"Failed to get mt6315 buck lp mode: %d\n", ret);
return ret;
}
if (regval & info->lp_mode_mask)
return REGULATOR_MODE_IDLE;
else
return REGULATOR_MODE_NORMAL;
}
static int mt6315_regulator_set_mode(struct regulator_dev *rdev,
unsigned int mode)
{
struct mt6315_regulator_info *info = rdev_get_drvdata(rdev);
int ret = 0, val;
int curr_mode;
curr_mode = mt6315_regulator_get_mode(rdev);
switch (mode) {
case REGULATOR_MODE_FAST:
if (curr_mode == REGULATOR_MODE_IDLE) {
WARN_ON(1);
dev_notice(&rdev->dev,
"BUCK %s is LP mode, can't FPWM\n",
rdev->desc->name);
return -EIO;
}
ret = regmap_update_bits(rdev->regmap,
info->modeset_reg,
info->modeset_mask,
info->modeset_mask);
break;
case REGULATOR_MODE_NORMAL:
if (curr_mode == REGULATOR_MODE_FAST) {
ret = regmap_update_bits(rdev->regmap,
info->modeset_reg,
info->modeset_mask,
0);
} else if (curr_mode == REGULATOR_MODE_IDLE) {
val = MT6315_BUCK_MODE_NORMAL;
val <<= info->lp_mode_shift;
ret = regmap_update_bits(rdev->regmap,
info->lp_mode_reg,
info->lp_mode_mask,
val);
udelay(100);
}
break;
case REGULATOR_MODE_IDLE:
if (curr_mode == REGULATOR_MODE_FAST) {
WARN_ON(1);
dev_notice(&rdev->dev,
"BUCK %s is FPWM mode, can't enter LP\n",
rdev->desc->name);
return -EIO;
}
val = MT6315_BUCK_MODE_LP >> 1;
val <<= info->lp_mode_shift;
ret = regmap_update_bits(rdev->regmap,
info->lp_mode_reg,
info->lp_mode_mask,
val);
break;
default:
ret = -EINVAL;
goto err_mode;
}
err_mode:
if (ret != 0) {
dev_notice(&rdev->dev,
"Failed to set mt6315 buck mode: %d\n", ret);
return ret;
}
return 0;
}
static int mt6315_get_status(struct regulator_dev *rdev)
{
int ret = 0;
u32 regval = 0;
struct mt6315_regulator_info *info = rdev_get_drvdata(rdev);
ret = regmap_read(rdev->regmap, info->da_reg, &regval);
if (ret != 0) {
dev_notice(&rdev->dev, "Failed to get enable reg: %d\n", ret);
return ret;
}
return (regval & info->qi) ? REGULATOR_STATUS_ON : REGULATOR_STATUS_OFF;
}
static const struct regulator_ops mt6315_volt_range_ops = {
.list_voltage = regulator_list_voltage_linear_range,
.map_voltage = regulator_map_voltage_linear_range,
.set_voltage_sel = regulator_set_voltage_sel_regmap,
.get_voltage_sel = mt6315_regulator_get_voltage_sel,
.set_voltage_time_sel = regulator_set_voltage_time_sel,
.enable = regulator_enable_regmap,
.disable = mt6315_regulator_disable,
.is_enabled = regulator_is_enabled_regmap,
.get_status = mt6315_get_status,
.set_mode = mt6315_regulator_set_mode,
.get_mode = mt6315_regulator_get_mode,
};
/* The array is indexed by id(MT6315_ID_SID_XXX) */
static struct mt6315_regulator_info mt6315_6_regulators[] = {
MT_BUCK("6_vbuck1", 6_VBUCK1, 300000, 1193750, 6250,
mt_volt_range1, 1, MT_BUCK_VOL_EN_MODE, 0xB),
MT_BUCK("6_vbuck3", 6_VBUCK3, 300000, 1193750, 6250,
mt_volt_range1, 3, MT_BUCK_VOL_EN_MODE, 0x4),
};
static struct mt6315_regulator_info mt6315_7_regulators[] = {
#if defined(CONFIG_MACH_MT6885)
MT_BUCK("7_vbuck1", 7_VBUCK1, 300000, 1193750, 6250,
mt_volt_range1, 1, MT_BUCK_VOL_EN_MODE, 0xB),
#elif defined(CONFIG_MACH_MT6873)
MT_BUCK("7_vbuck1", 7_VBUCK1, 300000, 1193750, 6250,
mt_volt_range1, 1, MT_BUCK_VOL_EN_MODE, 0x3),
#endif
MT_BUCK("7_vbuck3", 7_VBUCK3, 300000, 1193750, 6250,
mt_volt_range1, 3, MT_BUCK_VOL_EN, 0x4),
};
static struct mt6315_regulator_info mt6315_3_regulators[] = {
MT_BUCK("3_vbuck1", 3_VBUCK1, 300000, 1193750, 6250,
mt_volt_range1, 1, MT_BUCK_VOL_EN, 0x3),
MT_BUCK("3_vbuck3", 3_VBUCK3, 300000, 1193750, 6250,
mt_volt_range1, 3, MT_BUCK_VOL_EN, 0x4),
MT_BUCK("3_vbuck4", 3_VBUCK4, 300000, 1193750, 6250,
mt_volt_range1, 4, MT_BUCK_VOL_EN, 0x8),
};
static const struct mt_regulator_init_data mt6315_6_regulator_init_data = {
.id = MT6315_SLAVE_ID_6,
.size = MT6315_ID_6_MAX,
.regulator_info = &mt6315_6_regulators[0],
};
static const struct mt_regulator_init_data mt6315_7_regulator_init_data = {
.id = MT6315_SLAVE_ID_7,
.size = MT6315_ID_7_MAX,
.regulator_info = &mt6315_7_regulators[0],
};
static const struct mt_regulator_init_data mt6315_3_regulator_init_data = {
.id = MT6315_SLAVE_ID_3,
.size = MT6315_ID_3_MAX,
.regulator_info = &mt6315_3_regulators[0],
};
static const struct of_device_id mt6315_of_match[] = {
{
.compatible = "mediatek,mt6315_6-regulator",
.data = &mt6315_6_regulator_init_data,
}, {
.compatible = "mediatek,mt6315_7-regulator",
.data = &mt6315_7_regulator_init_data,
}, {
.compatible = "mediatek,mt6315_3-regulator",
.data = &mt6315_3_regulator_init_data,
}, {
/* sentinel */
},
};
MODULE_DEVICE_TABLE(of, mt6315_of_match);
static ssize_t extbuck_access_show(struct device *dev,
struct device_attribute *attr,
char *buf)
{
struct mt6315_chip *chip = dev_get_drvdata(dev);
pr_info("[%s] 0x%x\n", __func__, chip->reg_value);
return sprintf(buf, "0x%x\n", chip->reg_value);
}
static ssize_t extbuck_access_store(struct device *dev,
struct device_attribute *attr,
const char *buf,
size_t size)
{
struct mt6315_chip *chip;
int ret = 0;
char *pvalue = NULL, *addr, *val;
unsigned int sid = 0;
unsigned int reg_val = 0;
unsigned int reg_adr = 0;
if (dev) {
chip = dev_get_drvdata(dev);
if (!chip)
return -ENODEV;
} else
return -ENODEV;
if (buf != NULL && size != 0) {
pr_info("[%s] size is %d, buf is %s\n", __func__,
(int)size, buf);
pvalue = (char *)buf;
addr = strsep(&pvalue, " ");
val = strsep(&pvalue, " ");
sid = chip->slave_id;
if (addr)
ret = kstrtou32(addr, 16, (unsigned int *)&reg_adr);
if (val) {
ret = kstrtou32(val, 16, (unsigned int *)&reg_val);
pr_info("write MT6315_S%d Reg[0x%x] to 0x%x!\n",
sid, reg_adr, reg_val);
ret = regmap_write(chip->regmap, reg_adr, reg_val);
} else {
mutex_lock(&chip->lock);
ret = regmap_read(chip->regmap,
reg_adr, &chip->reg_value);
mutex_unlock(&chip->lock);
pr_info("read MT6315_S%d Reg[0x%x]=0x%x!\n",
sid, reg_adr, chip->reg_value);
}
}
return size;
}
static DEVICE_ATTR_RW(extbuck_access);
/*
* PMIC dump record register log
*/
static ssize_t dump_rec_pmic_show(struct device *dev,
struct device_attribute *attr,
char *buf)
{
struct mt6315_chip *chip;
unsigned int rdata0 = 0, rdata1 = 0, rdata2 = 0, rdata3 = 0;
unsigned int offset, sid;
int ret, log_size = 0;
if (dev) {
chip = dev_get_drvdata(dev);
if (!chip)
return -ENODEV;
} else
return -ENODEV;
sid = chip->slave_id;
ret = regmap_read(chip->regmap, MT6315_SPMI_DEBUG_CMD0, &rdata0);
log_size += sprintf(buf + log_size, "slvid:%d DBG. Last cmd idx:%d\n",
sid, (((rdata0 & 0xc) >> 2) + 3) % 4);
/* log sequence, idx 0->1->2->3->0 */
for (offset = MT6315_SPMI_DEBUG_ADDR0;
offset <= MT6315_SPMI_DEBUG_ADDR3; offset += 4) {
ret = regmap_read(chip->regmap, offset, &rdata0);
ret = regmap_read(chip->regmap, offset + 1, &rdata1);
ret = regmap_read(chip->regmap, offset + 2, &rdata2);
ret = regmap_read(chip->regmap, offset + 3, &rdata3);
log_size += sprintf(buf + log_size,
"Idx:%d slvid:%d Type:0x%x, [0x%x]=0x%x\n",
(offset - MT6315_SPMI_DEBUG_ADDR0) / 4,
sid, (rdata3 & 0x3),
(rdata1 << 0x8) | rdata0, rdata2);
}
pr_info("\n[SPMISLV] %s", buf);
return log_size;
}
static DEVICE_ATTR_RO(dump_rec_pmic);
static int mt6315_regulator_probe(struct platform_device *pdev)
{
const struct of_device_id *of_id;
struct device *dev = &pdev->dev;
struct regmap *regmap;
struct mt6315_regulator_info *mt_regulators;
struct mt_regulator_init_data *regulator_init_data;
struct mt6315_chip *chip;
struct regulator_config config = {};
struct regulator_dev *rdev;
struct regulation_constraints *c;
int i = 0, ret = 0;
u32 reg_value = 0;
regmap = dev_get_regmap(dev->parent, NULL);
if (!regmap)
return -ENODEV;
chip = devm_kzalloc(&pdev->dev, sizeof(struct mt6315_chip),
GFP_KERNEL);
if (!chip)
return -ENOMEM;
of_id = of_match_device(mt6315_of_match, &pdev->dev);
if (!of_id || !of_id->data)
return -ENODEV;
regulator_init_data = (struct mt_regulator_init_data *)of_id->data;
mt_regulators = regulator_init_data->regulator_info;
chip->slave_id = regulator_init_data->id;
chip->dev = &pdev->dev;
chip->regmap = regmap;
chip->irq = platform_get_irq(pdev, 0);
if (chip->irq <= 0) {
dev_notice(&pdev->dev,
"failed to get platform irq, ret=%d", chip->irq);
}
mutex_init(&chip->lock);
platform_set_drvdata(pdev, chip);
/* Read chip revision to update constraints */
if (regmap_read(regmap, MT6315_SWCID_H, &reg_value) < 0) {
dev_notice(&pdev->dev, "Failed to read Chip ID\n");
return -EIO;
}
dev_info(&pdev->dev, "Chip ID = 0x%x\n", reg_value);
for (i = 0; i < regulator_init_data->size; i++) {
config.dev = &pdev->dev;
config.driver_data = (mt_regulators + i);
config.regmap = regmap;
rdev = devm_regulator_register(&pdev->dev,
&(mt_regulators + i)->desc, &config);
if (IS_ERR(rdev)) {
dev_notice(&pdev->dev, "failed to register %s\n",
(mt_regulators + i)->desc.name);
continue;
}
c = rdev->constraints;
c->valid_ops_mask |=
(mt_regulators + i)->constraints.valid_ops_mask;
c->valid_modes_mask |=
(mt_regulators + i)->constraints.valid_modes_mask;
}
ret = mt6315_irq_init(chip);
if (ret)
return ret;
mt6315_misc_init(regulator_init_data->id, regmap);
/* Create sysfs entry */
ret = device_create_file(&pdev->dev, &dev_attr_extbuck_access);
if (ret)
dev_notice(&pdev->dev, "failed to create regs access file\n");
ret = device_create_file(&pdev->dev, &dev_attr_dump_rec_pmic);
if (ret)
dev_notice(&pdev->dev, "failed to create regs record file\n");
return 0;
}
static void mt6315_regulator_shutdown(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct regmap *regmap;
int ret = 0;
dev_info(&pdev->dev, "%s\n", __func__);
regmap = dev_get_regmap(dev->parent, NULL);
if (!regmap) {
dev_notice(&pdev->dev, "%s: invalid regmap.\n", __func__);
return;
}
ret |= regmap_write(regmap, MT6315_PMIC_TMA_KEY_H_ADDR, 0x9C);
ret |= regmap_write(regmap, MT6315_PMIC_TMA_KEY_ADDR, 0xEA);
ret |= regmap_update_bits(regmap,
MT6315_PMIC_RG_TOP2_RSV2_ADDR,
0x1 << 0, 0x1 << 0);
ret |= regmap_write(regmap, MT6315_PMIC_TMA_KEY_ADDR, 0);
ret |= regmap_write(regmap, MT6315_PMIC_TMA_KEY_H_ADDR, 0);
if (ret < 0) {
dev_notice(&pdev->dev, "%s: enable power off sequence failed.\n"
, __func__);
return;
}
}
static int mt6315_regulator_remove(struct platform_device *pdev)
{
device_remove_file(&pdev->dev, &dev_attr_extbuck_access);
return 0;
}
static struct platform_driver mt6315_regulator_driver = {
.driver = {
.name = "mt6315-regulator",
.of_match_table = of_match_ptr(mt6315_of_match),
},
.probe = mt6315_regulator_probe,
.shutdown = mt6315_regulator_shutdown,
.remove = mt6315_regulator_remove,
};
module_platform_driver(mt6315_regulator_driver);
MODULE_AUTHOR("Wen Su <wen.su@mediatek.com>");
MODULE_DESCRIPTION("Mediatek MT6315 regulator driver");
MODULE_LICENSE("GPL v2");
MODULE_ALIAS("platform:mt6315-regulator");

View File

@@ -12,6 +12,7 @@
* GNU General Public License for more details.
*/
#include <linux/interrupt.h>
#include <linux/module.h>
#include <linux/of_device.h>
#include <linux/platform_device.h>
@@ -28,6 +29,8 @@
#define MT6359_BUCK_MODE_NORMAL 0
#define MT6359_BUCK_MODE_LP 1
#define DEF_OC_IRQ_ENABLE_DELAY_MS 10
/*
* MT6359 regulators' information
*
@@ -40,6 +43,9 @@
* @modeset_shift: SHIFT for operating modeset register.
*/
struct mt6359_regulator_info {
int irq;
int oc_irq_enable_delay_ms;
struct delayed_work oc_work;
struct regulator_desc desc;
struct regulation_constraints constraints;
u32 da_vsel_reg;
@@ -1273,6 +1279,48 @@ static const struct of_device_id mt6359_of_match[] = {
};
MODULE_DEVICE_TABLE(of, mt6359_of_match);
static void mt6359_oc_irq_enable_work(struct work_struct *work)
{
struct delayed_work *dwork = to_delayed_work(work);
struct mt6359_regulator_info *info
= container_of(dwork, struct mt6359_regulator_info, oc_work);
enable_irq(info->irq);
}
static irqreturn_t mt6359_oc_irq(int irq, void *data)
{
struct regulator_dev *rdev = (struct regulator_dev *)data;
struct mt6359_regulator_info *info = rdev_get_drvdata(rdev);
disable_irq_nosync(info->irq);
if (!regulator_is_enabled_regmap(rdev))
goto delayed_enable;
mutex_lock(&rdev->mutex);
regulator_notifier_call_chain(rdev, REGULATOR_EVENT_OVER_CURRENT,
NULL);
mutex_unlock(&rdev->mutex);
delayed_enable:
schedule_delayed_work(&info->oc_work,
msecs_to_jiffies(info->oc_irq_enable_delay_ms));
return IRQ_HANDLED;
}
static int mt6359_of_parse_cb(struct device_node *np,
const struct regulator_desc *desc,
struct regulator_config *config)
{
int ret;
struct mt6359_regulator_info *info = config->driver_data;
ret = of_property_read_u32(np, "mediatek,oc-irq-enable-delay-ms",
&info->oc_irq_enable_delay_ms);
if (ret || !info->oc_irq_enable_delay_ms)
info->oc_irq_enable_delay_ms = DEF_OC_IRQ_ENABLE_DELAY_MS;
return 0;
}
static int mt6359_regulator_probe(struct platform_device *pdev)
{
const struct of_device_id *of_id;
@@ -1282,7 +1330,7 @@ static int mt6359_regulator_probe(struct platform_device *pdev)
struct regulator_config config = {};
struct regulator_dev *rdev;
struct regulation_constraints *c;
int i;
int i, ret;
u32 reg_value = 0;
of_id = of_match_device(mt6359_of_match, &pdev->dev);
@@ -1292,29 +1340,49 @@ static int mt6359_regulator_probe(struct platform_device *pdev)
mt_regulators = regulator_init_data->regulator_info;
/* Read PMIC chip revision to update constraints and voltage table */
if (regmap_read(mt6358->regmap, MT6359_SWCID, &reg_value) < 0) {
if (regmap_read(mt6358->regmap,
regulator_init_data->id, &reg_value) < 0) {
dev_notice(&pdev->dev, "Failed to read Chip ID\n");
return -EIO;
}
dev_info(&pdev->dev, "Chip ID = 0x%x\n", reg_value);
for (i = 0; i < regulator_init_data->size; i++) {
for (i = 0; i < regulator_init_data->size; i++, mt_regulators++) {
mt_regulators->desc.of_parse_cb = mt6359_of_parse_cb;
config.dev = &pdev->dev;
config.driver_data = (mt_regulators + i);
config.driver_data = mt_regulators;
config.regmap = mt6358->regmap;
rdev = devm_regulator_register(&pdev->dev,
&(mt_regulators + i)->desc, &config);
&mt_regulators->desc, &config);
if (IS_ERR(rdev)) {
dev_notice(&pdev->dev, "failed to register %s\n",
(mt_regulators + i)->desc.name);
mt_regulators->desc.name);
return PTR_ERR(rdev);
}
c = rdev->constraints;
c->valid_ops_mask |=
(mt_regulators + i)->constraints.valid_ops_mask;
mt_regulators->constraints.valid_ops_mask;
c->valid_modes_mask |=
(mt_regulators + i)->constraints.valid_modes_mask;
mt_regulators->constraints.valid_modes_mask;
mt_regulators->irq =
platform_get_irq_byname(pdev,
mt_regulators->desc.name);
if (mt_regulators->irq < 0)
continue;
ret = devm_request_threaded_irq(&pdev->dev, mt_regulators->irq,
NULL, mt6359_oc_irq,
IRQF_TRIGGER_HIGH,
mt_regulators->desc.name,
rdev);
if (ret) {
dev_notice(&pdev->dev, "Failed to request IRQ:%s,%d",
mt_regulators->desc.name, ret);
continue;
}
INIT_DELAYED_WORK(&mt_regulators->oc_work,
mt6359_oc_irq_enable_work);
}
return 0;

View File

@@ -0,0 +1,495 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (c) 2019 MediaTek Inc.
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/of_irq.h>
#include <linux/regmap.h>
#include <linux/platform_device.h>
#include <linux/regulator/driver.h>
#include <linux/interrupt.h>
#include <dt-bindings/mfd/mt6362.h>
#define MT6362_REG_BUCK1_SEQOFFDLY (0x107)
#define MT6362_POFF_SEQ_MAX 9
/* Set sub-pmic buck1/2/3/4/5/6&ldo7/6/4 power off seuqence */
static const u8 def_pwr_off_seq[MT6362_POFF_SEQ_MAX] = {
0x24, 0x24, 0x04, 0x22, 0x00, 0x00, 0x00, 0x02, 0x04,
};
enum {
MT6362_IDX_BUCK1 = 0,
MT6362_IDX_BUCK2,
MT6362_IDX_BUCK3,
MT6362_IDX_BUCK4,
MT6362_IDX_BUCK5,
MT6362_IDX_BUCK6,
MT6362_IDX_LDO1,
MT6362_IDX_LDO2,
MT6362_IDX_LDO3,
MT6362_IDX_LDO4,
MT6362_IDX_LDO5,
MT6362_IDX_LDO6,
MT6362_IDX_LDO7,
MT6362_IDX_MAX,
};
#define MT6362_VOL_REGMASK (0xff)
#define MT6362_VOL_MAX (256)
#define LDOVOL_OFFSET (0xA)
#define LDOENA_OFFSET (0x6)
#define LDOADE_OFFSET (0x9)
#define LDOMOD_OFFSET (0x6)
#define MT6362_LDOENA_REGMASK BIT(7)
#define MT6362_LDOMOD_REGMASK BIT(6)
#define MT6362_LDOADE_REGMASK BIT(2)
#define MT6362_LDO1_BASE (0x310)
#define MT6362_LDO2_BASE (0x320)
#define MT6362_LDO3_BASE (0x330)
#define MT6362_LDO4_BASE (0x140)
#define MT6362_LDO5_BASE (0x350)
#define MT6362_LDO6_BASE (0x130)
#define MT6362_LDO7_BASE (0x120)
#define MT6362_LDOVOL_REGADDR(_id) (MT6362_LDO##_id##_BASE + LDOVOL_OFFSET)
#define MT6362_LDOENA_REGADDR(_id) (MT6362_LDO##_id##_BASE + LDOENA_OFFSET)
#define MT6362_LDOADE_REGADDR(_id) (MT6362_LDO##_id##_BASE + LDOADE_OFFSET)
#define MT6362_LDOMOD_REGADDR(_id) (MT6362_LDO##_id##_BASE + LDOMOD_OFFSET)
#define MT6362_BUCKVOL_REGBASE (0x70C)
#define MT6362_BUCKVOL_REGADDR(_id) (MT6362_BUCKVOL_REGBASE + _id - 1)
#define MT6362_BUCKENA_REGADDR (0x700)
#define MT6362_BUCKMOD_REGADDR (0x706)
#define MT6362_VOLFBD2_MASK BIT(7)
#define MT6362_DEFAULT_BUCKSTEP (6250)
#define MT6362_VOLFBD2_BUCKSTEP (8333)
struct mt6362_regulator_desc {
struct regulator_desc desc;
unsigned int mode_reg;
unsigned int mode_mask;
};
struct mt6362_regulator_irqt {
const char *name;
irq_handler_t irqh;
};
struct mt6362_regulator_data {
struct device *dev;
struct regmap *regmap;
u8 pwr_off_seq[MT6362_POFF_SEQ_MAX];
};
static int mt6362_enable_poweroff_sequence(struct mt6362_regulator_data *data)
{
int i, ret;
dev_dbg(data->dev, "%s\n", __func__);
for (i = 0; i < MT6362_POFF_SEQ_MAX; i++) {
ret = regmap_write(data->regmap,
MT6362_REG_BUCK1_SEQOFFDLY + i,
data->pwr_off_seq[i]);
if (ret < 0) {
dev_notice(data->dev, "%s: set buck(%d) fail\n",
__func__, i);
return ret;
}
}
return ret;
}
static int mt6362_general_set_active_discharge(struct regulator_dev *rdev,
bool enable)
{
const struct regulator_desc *desc = rdev->desc;
if (!desc->active_discharge_reg)
return 0;
return regulator_set_active_discharge_regmap(rdev, enable);
}
static int mt6362_general_set_mode(struct regulator_dev *rdev,
unsigned int mode)
{
struct mt6362_regulator_desc *mdesc =
(struct mt6362_regulator_desc *)rdev->desc;
int ret;
switch (mode) {
case REGULATOR_MODE_NORMAL:
ret = regmap_update_bits(rdev->regmap, mdesc->mode_reg,
mdesc->mode_mask, 0);
break;
case REGULATOR_MODE_IDLE:
ret = regmap_update_bits(rdev->regmap, mdesc->mode_reg,
mdesc->mode_mask, mdesc->mode_mask);
break;
default:
ret = -EINVAL;
}
return ret ? : 0;
}
static unsigned int mt6362_general_get_mode(struct regulator_dev *rdev)
{
struct mt6362_regulator_desc *mdesc =
(struct mt6362_regulator_desc *)rdev->desc;
unsigned int val = 0;
int ret;
ret = regmap_read(rdev->regmap, mdesc->mode_reg, &val);
if (ret)
return 0;
if (val & mdesc->mode_mask)
return REGULATOR_MODE_IDLE;
return REGULATOR_MODE_NORMAL;
}
static unsigned int mt6362_general_of_map_mode(unsigned int mode)
{
switch (mode) {
case MT6362_REGULATOR_MODE_LP:
return REGULATOR_MODE_IDLE;
case MT6362_REGULATOR_MODE_NORMAL:
return REGULATOR_MODE_NORMAL;
default:
return REGULATOR_MODE_INVALID;
}
}
static const struct regulator_ops mt6362_ldo_regulator_ops = {
.list_voltage = regulator_list_voltage_linear_range,
.set_voltage_sel = regulator_set_voltage_sel_regmap,
.get_voltage_sel = regulator_get_voltage_sel_regmap,
.enable = regulator_enable_regmap,
.disable = regulator_disable_regmap,
.is_enabled = regulator_is_enabled_regmap,
.set_active_discharge = mt6362_general_set_active_discharge,
.set_mode = mt6362_general_set_mode,
.get_mode = mt6362_general_get_mode,
};
static const struct regulator_ops mt6362_buck_regulator_ops = {
.list_voltage = regulator_list_voltage_linear,
.set_voltage_sel = regulator_set_voltage_sel_regmap,
.get_voltage_sel = regulator_get_voltage_sel_regmap,
.enable = regulator_enable_regmap,
.disable = regulator_disable_regmap,
.is_enabled = regulator_is_enabled_regmap,
.set_active_discharge = mt6362_general_set_active_discharge,
.set_mode = mt6362_general_set_mode,
.get_mode = mt6362_general_get_mode,
};
static const struct regulator_linear_range lvldo_ranges[] = {
REGULATOR_LINEAR_RANGE(500000, 0x00, 0x0a, 10000),
REGULATOR_LINEAR_RANGE(600000, 0x0b, 0x0f, 0),
REGULATOR_LINEAR_RANGE(600000, 0x10, 0x1a, 10000),
REGULATOR_LINEAR_RANGE(700000, 0x1b, 0x1f, 0),
REGULATOR_LINEAR_RANGE(700000, 0x20, 0x2a, 10000),
REGULATOR_LINEAR_RANGE(800000, 0x2b, 0x2f, 0),
REGULATOR_LINEAR_RANGE(800000, 0x30, 0x3a, 10000),
REGULATOR_LINEAR_RANGE(900000, 0x3b, 0x3f, 0),
REGULATOR_LINEAR_RANGE(900000, 0x40, 0x4a, 10000),
REGULATOR_LINEAR_RANGE(1000000, 0x4b, 0x4f, 0),
REGULATOR_LINEAR_RANGE(1000000, 0x50, 0x5a, 10000),
REGULATOR_LINEAR_RANGE(1100000, 0x5b, 0x5f, 0),
REGULATOR_LINEAR_RANGE(1100000, 0x60, 0x6a, 10000),
REGULATOR_LINEAR_RANGE(1200000, 0x6b, 0x6f, 0),
REGULATOR_LINEAR_RANGE(1200000, 0x70, 0x7a, 10000),
REGULATOR_LINEAR_RANGE(1300000, 0x7b, 0x7f, 0),
REGULATOR_LINEAR_RANGE(1300000, 0x80, 0x8a, 10000),
REGULATOR_LINEAR_RANGE(1400000, 0x8b, 0x8f, 0),
REGULATOR_LINEAR_RANGE(1400000, 0x90, 0x9a, 10000),
REGULATOR_LINEAR_RANGE(1500000, 0x9b, 0x9f, 0),
REGULATOR_LINEAR_RANGE(1500000, 0xa0, 0xaa, 10000),
REGULATOR_LINEAR_RANGE(1600000, 0xab, 0xaf, 0),
REGULATOR_LINEAR_RANGE(1600000, 0xb0, 0xba, 10000),
REGULATOR_LINEAR_RANGE(1700000, 0xbb, 0xbf, 0),
REGULATOR_LINEAR_RANGE(1700000, 0xc0, 0xca, 10000),
REGULATOR_LINEAR_RANGE(1800000, 0xcb, 0xcf, 0),
REGULATOR_LINEAR_RANGE(1800000, 0xd0, 0xda, 10000),
REGULATOR_LINEAR_RANGE(1900000, 0xdb, 0xdf, 0),
REGULATOR_LINEAR_RANGE(1900000, 0xe0, 0xea, 10000),
REGULATOR_LINEAR_RANGE(2000000, 0xeb, 0xef, 0),
REGULATOR_LINEAR_RANGE(2000000, 0xf0, 0xfa, 10000),
REGULATOR_LINEAR_RANGE(2100000, 0xfb, 0xff, 0),
};
static const struct regulator_linear_range hvldo_ranges[] = {
REGULATOR_LINEAR_RANGE(1200000, 0x00, 0x0a, 10000),
REGULATOR_LINEAR_RANGE(1300000, 0x0b, 0x0f, 0),
REGULATOR_LINEAR_RANGE(1300000, 0x10, 0x1a, 10000),
REGULATOR_LINEAR_RANGE(1400000, 0x1b, 0x1f, 0),
REGULATOR_LINEAR_RANGE(1500000, 0x20, 0x2a, 10000),
REGULATOR_LINEAR_RANGE(1600000, 0x2b, 0x2f, 0),
REGULATOR_LINEAR_RANGE(1700000, 0x30, 0x3a, 10000),
REGULATOR_LINEAR_RANGE(1800000, 0x3b, 0x3f, 0),
REGULATOR_LINEAR_RANGE(1800000, 0x40, 0x4a, 10000),
REGULATOR_LINEAR_RANGE(1900000, 0x4b, 0x4f, 0),
REGULATOR_LINEAR_RANGE(2000000, 0x50, 0x5a, 10000),
REGULATOR_LINEAR_RANGE(2100000, 0x5b, 0x5f, 0),
REGULATOR_LINEAR_RANGE(2100000, 0x60, 0x6a, 10000),
REGULATOR_LINEAR_RANGE(2200000, 0x6b, 0x6f, 0),
REGULATOR_LINEAR_RANGE(2500000, 0x70, 0x7a, 10000),
REGULATOR_LINEAR_RANGE(2600000, 0x7b, 0x7f, 0),
REGULATOR_LINEAR_RANGE(2700000, 0x80, 0x8a, 10000),
REGULATOR_LINEAR_RANGE(2800000, 0x8b, 0x8f, 0),
REGULATOR_LINEAR_RANGE(2800000, 0x90, 0x9a, 10000),
REGULATOR_LINEAR_RANGE(2900000, 0x9b, 0x9f, 0),
REGULATOR_LINEAR_RANGE(2900000, 0xa0, 0xaa, 10000),
REGULATOR_LINEAR_RANGE(3000000, 0xab, 0xaf, 0),
REGULATOR_LINEAR_RANGE(3000000, 0xb0, 0xba, 10000),
REGULATOR_LINEAR_RANGE(3100000, 0xbb, 0xbf, 0),
REGULATOR_LINEAR_RANGE(3100000, 0xc0, 0xca, 10000),
REGULATOR_LINEAR_RANGE(3200000, 0xcb, 0xcf, 0),
REGULATOR_LINEAR_RANGE(3300000, 0xd0, 0xda, 10000),
REGULATOR_LINEAR_RANGE(3400000, 0xdb, 0xdf, 0),
REGULATOR_LINEAR_RANGE(3400000, 0xe0, 0xea, 10000),
REGULATOR_LINEAR_RANGE(3500000, 0xeb, 0xef, 0),
REGULATOR_LINEAR_RANGE(3500000, 0xf0, 0xfa, 10000),
REGULATOR_LINEAR_RANGE(3600000, 0xfb, 0xff, 0),
};
#define MT6362_LDO_DESC(_id, _type, _supply_name) \
{\
.desc = {\
.ops = &mt6362_ldo_regulator_ops,\
.name = "mt6362-ldo" #_id,\
.supply_name = _supply_name,\
.of_match = "ldo" #_id,\
.id = MT6362_IDX_LDO##_id,\
.type = REGULATOR_VOLTAGE,\
.owner = THIS_MODULE,\
.n_voltages = MT6362_VOL_MAX,\
.linear_ranges = _type##ldo_ranges,\
.n_linear_ranges = ARRAY_SIZE(_type##ldo_ranges),\
.vsel_reg = MT6362_LDOVOL_REGADDR(_id),\
.vsel_mask = MT6362_VOL_REGMASK,\
.enable_reg = MT6362_LDOENA_REGADDR(_id),\
.enable_mask = MT6362_LDOENA_REGMASK,\
.active_discharge_reg = MT6362_LDOADE_REGADDR(_id),\
.active_discharge_mask = MT6362_LDOADE_REGMASK,\
.active_discharge_on = MT6362_LDOADE_REGMASK,\
.of_map_mode = mt6362_general_of_map_mode,\
},\
.mode_reg = MT6362_LDOMOD_REGADDR(_id),\
.mode_mask = MT6362_LDOMOD_REGMASK,\
}
#define MT6362_BUCK_DESC(_id) \
{\
.desc = {\
.ops = &mt6362_buck_regulator_ops,\
.name = "mt6362-buck" #_id,\
.of_match = "buck" #_id,\
.id = MT6362_IDX_BUCK##_id,\
.type = REGULATOR_VOLTAGE,\
.owner = THIS_MODULE,\
.uV_step = MT6362_DEFAULT_BUCKSTEP,\
.n_voltages = MT6362_VOL_MAX,\
.vsel_reg = MT6362_BUCKVOL_REGADDR(_id),\
.vsel_mask = MT6362_VOL_REGMASK,\
.enable_reg = MT6362_BUCKENA_REGADDR,\
.enable_mask = BIT(_id),\
.of_map_mode = mt6362_general_of_map_mode,\
},\
.mode_reg = MT6362_BUCKMOD_REGADDR,\
.mode_mask = BIT(_id),\
}
static struct mt6362_regulator_desc mtreg_descs[MT6362_IDX_MAX] = {
MT6362_BUCK_DESC(1),
MT6362_BUCK_DESC(2),
MT6362_BUCK_DESC(3),
MT6362_BUCK_DESC(4),
MT6362_BUCK_DESC(5),
MT6362_BUCK_DESC(6),
MT6362_LDO_DESC(1, hv, NULL),
MT6362_LDO_DESC(2, hv, NULL),
MT6362_LDO_DESC(3, hv, NULL),
MT6362_LDO_DESC(4, hv, NULL),
MT6362_LDO_DESC(5, hv, NULL),
MT6362_LDO_DESC(6, lv, "mt6362-buck3"),
MT6362_LDO_DESC(7, lv, "mt6362-buck3"),
};
#define MT6362_REGULATOR_IRQH(_name, _event) \
static irqreturn_t mt6362_##_name##_irq_handler(int irq, void *data)\
{\
struct regulator_dev *rdev = data;\
struct device *dev = rdev_get_dev(rdev);\
dev_warn(dev, "%s: id = %d\n", __func__, rdev_get_id(rdev));\
regulator_notifier_call_chain(rdev, _event, NULL);\
return IRQ_HANDLED;\
}
MT6362_REGULATOR_IRQH(oc_evt, REGULATOR_EVENT_OVER_CURRENT)
MT6362_REGULATOR_IRQH(pgb_evt, REGULATOR_EVENT_FAIL)
#define MT6362_IRQ_DECLARE(_name) \
{\
.name = #_name,\
.irqh = mt6362_##_name##_irq_handler,\
}
static const struct mt6362_regulator_irqt irqts[] = {
MT6362_IRQ_DECLARE(oc_evt),
MT6362_IRQ_DECLARE(pgb_evt),
};
static int mt6362_regulator_irq_register(struct regulator_dev *rdev)
{
struct device *dev = rdev_get_dev(rdev);
struct device_node *np = dev->of_node;
int i, irq, rv;
for (i = 0; i < ARRAY_SIZE(irqts); i++) {
irq = of_irq_get_byname(np, irqts[i].name);
if (irq <= 0)
continue;
rv = devm_request_threaded_irq(dev->parent, irq, NULL,
irqts[i].irqh, 0, NULL, rdev);
if (rv)
return rv;
}
return 0;
}
static int mt6362_reconfigure_voltage_step(struct mt6362_regulator_data *data,
struct regulator_desc *desc)
{
const unsigned int buck_fbd2_regs[] = {
0x29b, 0x2a3, 0x2ab, 0x2b3, 0x2d1, 0x2d9
};
unsigned int val;
int rv;
if (desc->id >= MT6362_IDX_BUCK1 && desc->id <= MT6362_IDX_BUCK6) {
rv = regmap_read(data->regmap, buck_fbd2_regs[desc->id], &val);
if (rv)
return rv;
if (val & MT6362_VOLFBD2_MASK)
desc->uV_step = MT6362_VOLFBD2_BUCKSTEP;
}
return 0;
}
static int mt6362_parse_dt_data(struct device *dev,
struct mt6362_regulator_data *data)
{
struct device_node *np = dev->of_node;
int ret;
memcpy(data->pwr_off_seq, &def_pwr_off_seq, MT6362_POFF_SEQ_MAX);
ret = of_property_read_u8_array(np, "pwr_off_seq", data->pwr_off_seq,
MT6362_POFF_SEQ_MAX);
if (ret)
dev_notice(dev, "%s: undefine pwr_off_seq\n", __func__);
return ret;
}
static int mt6362_regulator_probe(struct platform_device *pdev)
{
struct mt6362_regulator_data *data;
struct regulator_config config;
struct regulator_dev *rdev;
int i, rv;
data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
if (!data)
return -ENOMEM;
rv = mt6362_parse_dt_data(&pdev->dev, data);
if (rv < 0) {
dev_err(&pdev->dev, "parse dt fail\n");
return rv;
}
data->dev = &pdev->dev;
data->regmap = dev_get_regmap(pdev->dev.parent, NULL);
if (!data->regmap) {
dev_err(&pdev->dev, "failed to allocate regmap\n");
return -ENODEV;
}
config.dev = &pdev->dev;
config.driver_data = data;
config.regmap = data->regmap;
for (i = 0; i < MT6362_IDX_MAX; i++) {
struct mt6362_regulator_desc *mt_desc;
mt_desc = mtreg_descs + i;
rv = mt6362_reconfigure_voltage_step(data, &mt_desc->desc);
if (rv)
return rv;
rdev = devm_regulator_register(&pdev->dev,
&mt_desc->desc, &config);
if (IS_ERR(rdev)) {
dev_err(&pdev->dev,
"failed to register [%d] regulator\n", i);
return PTR_ERR(rdev);
}
rv = mt6362_regulator_irq_register(rdev);
if (rv) {
dev_err(&pdev->dev,
"failed to register [%d] regulator irq\n", i);
return rv;
}
}
platform_set_drvdata(pdev, data);
return 0;
}
static void mt6362_shutdown(struct platform_device *pdev)
{
struct mt6362_regulator_data *data = platform_get_drvdata(pdev);
int ret;
dev_dbg(data->dev, "%s\n", __func__);
if (data == NULL)
return;
ret = mt6362_enable_poweroff_sequence(data);
if (ret < 0)
dev_notice(data->dev,
"%s: enable power off sequence fail\n", __func__);
}
static const struct of_device_id __maybe_unused mt6362_regulator_ofid_tbls[] = {
{ .compatible = "mediatek,mt6362-regulator", },
{ },
};
MODULE_DEVICE_TABLE(of, mt6362_regulator_ofid_tbls);
static struct platform_driver mt6362_regulator_driver = {
.driver = {
.name = "mt6362-regulator",
.of_match_table = of_match_ptr(mt6362_regulator_ofid_tbls),
},
.probe = mt6362_regulator_probe,
.shutdown = mt6362_shutdown,
};
module_platform_driver(mt6362_regulator_driver);
MODULE_AUTHOR("ChiYuan Huang <cy_huang@richtek.com>");
MODULE_DESCRIPTION("MT6362 SPMI Regulator Driver");
MODULE_LICENSE("GPL");
MODULE_VERSION("1.0.0");

View File

@@ -0,0 +1,34 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (c) 2019 MediaTek Inc.
*/
#ifndef __LINUX_REGULATOR_MT6315_MISC_H
#define __LINUX_REGULATOR_MT6315_MISC_H
#define HW_OFF 0
#define HW_LP 1
struct mt6315_misc {
uint8_t master_idx;
uint8_t slave_addr;
struct regmap *regmap;
};
enum MT6315_BUCK_EN_USER {
MT6315_SRCLKEN0,
MT6315_SRCLKEN1,
MT6315_SRCLKEN2,
MT6315_SRCLKEN3,
MT6315_SRCLKEN4,
MT6315_SRCLKEN5,
MT6315_SRCLKEN6,
MT6315_SRCLKEN7,
MT6315_SW,
};
extern void mt6315_vmd1_pmic_setting_on(void);
extern int is_mt6315_exist(void);
extern void mt6315_misc_init(u32 sid, struct regmap *regmap);
#endif /* __LINUX_REGULATOR_MT6315_MISC_H */

View File

@@ -0,0 +1,32 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (c) 2019 MediaTek Inc.
*/
#ifndef __LINUX_REGULATOR_MT6315_H
#define __LINUX_REGULATOR_MT6315_H
#define MT6315_SLAVE_ID_3 3
#define MT6315_SLAVE_ID_6 6
#define MT6315_SLAVE_ID_7 7
enum {
MT6315_ID_6_VBUCK1 = 0,
MT6315_ID_6_VBUCK3,
MT6315_ID_6_MAX,
};
enum {
MT6315_ID_7_VBUCK1 = 0,
MT6315_ID_7_VBUCK3,
MT6315_ID_7_MAX,
};
enum {
MT6315_ID_3_VBUCK1 = 0,
MT6315_ID_3_VBUCK3,
MT6315_ID_3_VBUCK4,
MT6315_ID_3_MAX,
};
#endif /* __LINUX_REGULATOR_MT6315_H */