809 lines
25 KiB
C
809 lines
25 KiB
C
// SPDX-License-Identifier: GPL-2.0
|
|
/*
|
|
* Copyright (c) 2021 MediaTek Inc.
|
|
*/
|
|
|
|
#include <linux/interrupt.h>
|
|
#include <linux/mfd/core.h>
|
|
#include <linux/mfd/mt6363/core.h>
|
|
#include <linux/mfd/mt6363/registers.h>
|
|
#include <linux/mfd/mt6368/core.h>
|
|
#include <linux/mfd/mt6368/registers.h>
|
|
#include <linux/mfd/mt6369/core.h>
|
|
#include <linux/mfd/mt6369/registers.h>
|
|
#include <linux/mfd/mt6373/core.h>
|
|
#include <linux/mfd/mt6373/registers.h>
|
|
#include <linux/mfd/mt6377/core.h>
|
|
#include <linux/mfd/mt6377/registers.h>
|
|
#include <linux/module.h>
|
|
#include <linux/mutex.h>
|
|
#include <linux/of_device.h>
|
|
#include <linux/of_irq.h>
|
|
#include <linux/regmap.h>
|
|
#include <linux/spmi.h>
|
|
|
|
#define MTK_SPMI_PMIC_REG_WIDTH 8
|
|
#define PMIC_SWCID 0xB
|
|
#define RCS_INT_DONE 0x41B
|
|
|
|
struct irq_top_t {
|
|
int hwirq_base;
|
|
unsigned int num_int_regs;
|
|
unsigned int en_reg;
|
|
unsigned int en_reg_shift;
|
|
unsigned int sta_reg;
|
|
unsigned int sta_reg_shift;
|
|
unsigned int top_offset;
|
|
};
|
|
|
|
struct mtk_spmi_pmic_data {
|
|
const struct mfd_cell *cells;
|
|
int cell_size;
|
|
unsigned int num_top;
|
|
unsigned int num_pmic_irqs;
|
|
unsigned short top_int_status_reg;
|
|
struct irq_top_t *pmic_ints;
|
|
};
|
|
|
|
struct pmic_core {
|
|
struct device *dev;
|
|
struct spmi_device *sdev;
|
|
struct regmap *regmap;
|
|
u16 chip_id;
|
|
int irq;
|
|
bool *enable_hwirq;
|
|
bool *cache_hwirq;
|
|
struct mutex irqlock;
|
|
struct irq_domain *irq_domain;
|
|
const struct mtk_spmi_pmic_data *chip_data;
|
|
};
|
|
|
|
static const struct resource mt6363_regulators_resources[] = {
|
|
DEFINE_RES_IRQ_NAMED(MT6363_IRQ_VCN15_OC, "VCN15"),
|
|
DEFINE_RES_IRQ_NAMED(MT6363_IRQ_VCN13_OC, "VCN13"),
|
|
DEFINE_RES_IRQ_NAMED(MT6363_IRQ_VRF09_OC, "VRF09"),
|
|
DEFINE_RES_IRQ_NAMED(MT6363_IRQ_VRF12_OC, "VRF12"),
|
|
DEFINE_RES_IRQ_NAMED(MT6363_IRQ_VRF13_OC, "VRF13"),
|
|
DEFINE_RES_IRQ_NAMED(MT6363_IRQ_VRF18_OC, "VRF18"),
|
|
DEFINE_RES_IRQ_NAMED(MT6363_IRQ_VRFIO18_OC, "VRFIO18"),
|
|
DEFINE_RES_IRQ_NAMED(MT6363_IRQ_VSRAM_MDFE_OC, "VSRAM_MDFE"),
|
|
DEFINE_RES_IRQ_NAMED(MT6363_IRQ_VTREF18_OC, "VTREF18"),
|
|
DEFINE_RES_IRQ_NAMED(MT6363_IRQ_VSRAM_APU_OC, "VSRAM_APU"),
|
|
DEFINE_RES_IRQ_NAMED(MT6363_IRQ_VAUX18_OC, "VAUX18"),
|
|
DEFINE_RES_IRQ_NAMED(MT6363_IRQ_VEMC_OC, "VEMC"),
|
|
DEFINE_RES_IRQ_NAMED(MT6363_IRQ_VUFS12_OC, "VUFS12"),
|
|
DEFINE_RES_IRQ_NAMED(MT6363_IRQ_VUFS18_OC, "VUFS18"),
|
|
DEFINE_RES_IRQ_NAMED(MT6363_IRQ_VIO18_OC, "VIO18"),
|
|
DEFINE_RES_IRQ_NAMED(MT6363_IRQ_VIO075_OC, "VIO075"),
|
|
DEFINE_RES_IRQ_NAMED(MT6363_IRQ_VA12_1_OC, "VA12_1"),
|
|
DEFINE_RES_IRQ_NAMED(MT6363_IRQ_VA12_2_OC, "VA12_2"),
|
|
DEFINE_RES_IRQ_NAMED(MT6363_IRQ_VA15_OC, "VA15"),
|
|
DEFINE_RES_IRQ_NAMED(MT6363_IRQ_VM18_OC, "VM18"),
|
|
};
|
|
|
|
static const struct resource mt6363_keys_resources[] = {
|
|
DEFINE_RES_IRQ(MT6363_IRQ_PWRKEY),
|
|
DEFINE_RES_IRQ(MT6363_IRQ_HOMEKEY),
|
|
DEFINE_RES_IRQ(MT6363_IRQ_PWRKEY_R),
|
|
DEFINE_RES_IRQ(MT6363_IRQ_HOMEKEY_R),
|
|
};
|
|
|
|
static const struct resource mt6363_lvsys_notify_resources[] = {
|
|
/* MT6363 LVSYS interrupt name is contrary,
|
|
* we name LVSYS_R to MT6363_IRQ_NI_LVSYS_INT_FALLING;
|
|
* LVSYS_F to MT6363_IRQ_NI_LVSYS_INT_RISING
|
|
*/
|
|
DEFINE_RES_IRQ_NAMED(MT6363_IRQ_NI_LVSYS_INT_FALLING, "LVSYS_R"),
|
|
DEFINE_RES_IRQ_NAMED(MT6363_IRQ_NI_LVSYS_INT_RISING, "LVSYS_F"),
|
|
};
|
|
|
|
static const struct resource mt6377_keys_resources[] = {
|
|
DEFINE_RES_IRQ(MT6377_IRQ_PWRKEY),
|
|
DEFINE_RES_IRQ(MT6377_IRQ_HOMEKEY),
|
|
DEFINE_RES_IRQ(MT6377_IRQ_PWRKEY_R),
|
|
DEFINE_RES_IRQ(MT6377_IRQ_HOMEKEY_R),
|
|
};
|
|
|
|
static const struct resource mt6373_regulators_resources[] = {
|
|
DEFINE_RES_IRQ_NAMED(MT6373_IRQ_VUSB_OC, "VUSB"),
|
|
DEFINE_RES_IRQ_NAMED(MT6373_IRQ_VAUX18_OC, "VAUX18"),
|
|
DEFINE_RES_IRQ_NAMED(MT6373_IRQ_VRF13_AIF_OC, "VRF13_AIF"),
|
|
DEFINE_RES_IRQ_NAMED(MT6373_IRQ_VRF18_AIF_OC, "VRF18_AIF"),
|
|
DEFINE_RES_IRQ_NAMED(MT6373_IRQ_VRFIO18_AIF_OC, "VRFIO18_AIF"),
|
|
DEFINE_RES_IRQ_NAMED(MT6373_IRQ_VCN33_1_OC, "VCN33_1"),
|
|
DEFINE_RES_IRQ_NAMED(MT6373_IRQ_VCN33_2_OC, "VCN33_2"),
|
|
DEFINE_RES_IRQ_NAMED(MT6373_IRQ_VCN33_3_OC, "VCN33_3"),
|
|
DEFINE_RES_IRQ_NAMED(MT6373_IRQ_VCN18IO_OC, "VCN18IO"),
|
|
DEFINE_RES_IRQ_NAMED(MT6373_IRQ_VRF09_AIF_OC, "VRF09_AIF"),
|
|
DEFINE_RES_IRQ_NAMED(MT6373_IRQ_VRF12_AIF_OC, "VRF12_AIF"),
|
|
DEFINE_RES_IRQ_NAMED(MT6373_IRQ_VANT18_OC, "VANT18"),
|
|
DEFINE_RES_IRQ_NAMED(MT6373_IRQ_VSRAM_DIGRF_AIF_OC, "VSRAM_DIGRF_AIF"),
|
|
DEFINE_RES_IRQ_NAMED(MT6373_IRQ_VEFUSE_OC, "VEFUSE"),
|
|
DEFINE_RES_IRQ_NAMED(MT6373_IRQ_VMCH_OC, "VMCH"),
|
|
DEFINE_RES_IRQ_NAMED(MT6373_IRQ_VMC_OC, "VMC"),
|
|
DEFINE_RES_IRQ_NAMED(MT6373_IRQ_VIBR_OC, "VIBR"),
|
|
DEFINE_RES_IRQ_NAMED(MT6373_IRQ_VIO28_OC, "VIO28"),
|
|
DEFINE_RES_IRQ_NAMED(MT6373_IRQ_VFP_OC, "VFP"),
|
|
DEFINE_RES_IRQ_NAMED(MT6373_IRQ_VTP_OC, "VTP"),
|
|
};
|
|
|
|
static const struct resource mt6368_accdet_resources[] = {
|
|
DEFINE_RES_IRQ_NAMED(MT6368_IRQ_ACCDET, "ACCDET_IRQ"),
|
|
DEFINE_RES_IRQ_NAMED(MT6368_IRQ_ACCDET_EINT0, "ACCDET_EINT0"),
|
|
DEFINE_RES_IRQ_NAMED(MT6368_IRQ_ACCDET_EINT1, "ACCDET_EINT1"),
|
|
};
|
|
|
|
static const struct resource mt6368_regulators_resources[] = {
|
|
DEFINE_RES_IRQ_NAMED(MT6368_IRQ_VPA_OC, "VPA"),
|
|
DEFINE_RES_IRQ_NAMED(MT6368_IRQ_VUSB_OC, "VUSB"),
|
|
DEFINE_RES_IRQ_NAMED(MT6368_IRQ_VAUX18_OC, "VAUX18"),
|
|
DEFINE_RES_IRQ_NAMED(MT6368_IRQ_VRF13_AIF_OC, "VRF13_AIF"),
|
|
DEFINE_RES_IRQ_NAMED(MT6368_IRQ_VRF18_AIF_OC, "VRF18_AIF"),
|
|
DEFINE_RES_IRQ_NAMED(MT6368_IRQ_VANT18_OC, "VANT18"),
|
|
DEFINE_RES_IRQ_NAMED(MT6368_IRQ_VIBR_OC, "VIBR"),
|
|
DEFINE_RES_IRQ_NAMED(MT6368_IRQ_VIO28_OC, "VIO28"),
|
|
DEFINE_RES_IRQ_NAMED(MT6368_IRQ_VFP_OC, "VFP"),
|
|
DEFINE_RES_IRQ_NAMED(MT6368_IRQ_VTP_OC, "VTP"),
|
|
DEFINE_RES_IRQ_NAMED(MT6368_IRQ_VMCH_OC, "VMCH"),
|
|
DEFINE_RES_IRQ_NAMED(MT6368_IRQ_VMC_OC, "VMC"),
|
|
DEFINE_RES_IRQ_NAMED(MT6368_IRQ_VCN33_1_OC, "VCN33_1"),
|
|
DEFINE_RES_IRQ_NAMED(MT6368_IRQ_VCN33_2_OC, "VCN33_2"),
|
|
DEFINE_RES_IRQ_NAMED(MT6368_IRQ_VEFUSE_OC, "VEFUSE"),
|
|
};
|
|
|
|
static const struct resource mt6369_accdet_resources[] = {
|
|
DEFINE_RES_IRQ_NAMED(MT6369_IRQ_ACCDET, "ACCDET_IRQ"),
|
|
DEFINE_RES_IRQ_NAMED(MT6369_IRQ_ACCDET_EINT0, "ACCDET_EINT0"),
|
|
DEFINE_RES_IRQ_NAMED(MT6369_IRQ_ACCDET_EINT1, "ACCDET_EINT1"),
|
|
};
|
|
|
|
static const struct resource mt6369_regulators_resources[] = {
|
|
DEFINE_RES_IRQ_NAMED(MT6369_IRQ_VPA_OC, "VPA"),
|
|
DEFINE_RES_IRQ_NAMED(MT6369_IRQ_VIBR_OC, "VIBR"),
|
|
DEFINE_RES_IRQ_NAMED(MT6369_IRQ_VIO28_OC, "VIO28"),
|
|
DEFINE_RES_IRQ_NAMED(MT6369_IRQ_VFP_OC, "VFP"),
|
|
DEFINE_RES_IRQ_NAMED(MT6369_IRQ_VTP_OC, "VTP"),
|
|
DEFINE_RES_IRQ_NAMED(MT6369_IRQ_VUSB_OC, "VUSB"),
|
|
DEFINE_RES_IRQ_NAMED(MT6369_IRQ_VAUD28_OC, "VAUD28"),
|
|
DEFINE_RES_IRQ_NAMED(MT6369_IRQ_VCN33_1_OC, "VCN33_1"),
|
|
DEFINE_RES_IRQ_NAMED(MT6369_IRQ_VCN33_2_OC, "VCN33_2"),
|
|
DEFINE_RES_IRQ_NAMED(MT6369_IRQ_VEFUSE_OC, "VEFUSE"),
|
|
DEFINE_RES_IRQ_NAMED(MT6369_IRQ_VMCH_OC, "VMCH"),
|
|
DEFINE_RES_IRQ_NAMED(MT6369_IRQ_VMC_OC, "VMC"),
|
|
DEFINE_RES_IRQ_NAMED(MT6369_IRQ_VANT18_OC, "VANT18"),
|
|
DEFINE_RES_IRQ_NAMED(MT6369_IRQ_VAUX18_OC, "VAUX18"),
|
|
};
|
|
|
|
static const struct resource mt6377_accdet_resources[] = {
|
|
DEFINE_RES_IRQ_NAMED(MT6377_IRQ_ACCDET, "ACCDET_IRQ"),
|
|
DEFINE_RES_IRQ_NAMED(MT6377_IRQ_ACCDET_EINT0, "ACCDET_EINT0"),
|
|
DEFINE_RES_IRQ_NAMED(MT6377_IRQ_ACCDET_EINT1, "ACCDET_EINT1"),
|
|
};
|
|
|
|
static const struct resource mt6377_regulators_resources[] = {
|
|
DEFINE_RES_IRQ_NAMED(MT6377_IRQ_VPA_OC, "VPA"),
|
|
DEFINE_RES_IRQ_NAMED(MT6377_IRQ_VA12_OC, "VA12"),
|
|
DEFINE_RES_IRQ_NAMED(MT6377_IRQ_VAUD18_OC, "VAUD18"),
|
|
DEFINE_RES_IRQ_NAMED(MT6377_IRQ_VAUD28_OC, "VAUD28"),
|
|
DEFINE_RES_IRQ_NAMED(MT6377_IRQ_VAUX18_OC, "VAUX18"),
|
|
DEFINE_RES_IRQ_NAMED(MT6377_IRQ_VBIF28_OC, "VBIF28"),
|
|
DEFINE_RES_IRQ_NAMED(MT6377_IRQ_VCN33_1_OC, "VCN33_1"),
|
|
DEFINE_RES_IRQ_NAMED(MT6377_IRQ_VCN33_2_OC, "VCN33_2"),
|
|
DEFINE_RES_IRQ_NAMED(MT6377_IRQ_VCN18_OC, "VCN18"),
|
|
DEFINE_RES_IRQ_NAMED(MT6377_IRQ_VRFCK_OC, "VRFCK"),
|
|
DEFINE_RES_IRQ_NAMED(MT6377_IRQ_VBBCK_OC, "VBBCK"),
|
|
DEFINE_RES_IRQ_NAMED(MT6377_IRQ_VXO22_OC, "VXO22"),
|
|
DEFINE_RES_IRQ_NAMED(MT6377_IRQ_VM18_OC, "VM18"),
|
|
DEFINE_RES_IRQ_NAMED(MT6377_IRQ_VEFUSE_OC, "VEFUSE"),
|
|
DEFINE_RES_IRQ_NAMED(MT6377_IRQ_VEMC_OC, "VEMC"),
|
|
DEFINE_RES_IRQ_NAMED(MT6377_IRQ_VUFS_OC, "VUFS"),
|
|
DEFINE_RES_IRQ_NAMED(MT6377_IRQ_VIO18_OC, "VIO18"),
|
|
DEFINE_RES_IRQ_NAMED(MT6377_IRQ_VSRAM_MD_OC, "VSRAM_MD"),
|
|
DEFINE_RES_IRQ_NAMED(MT6377_IRQ_VRF18_OC, "VRF18"),
|
|
DEFINE_RES_IRQ_NAMED(MT6377_IRQ_VRF12_OC, "VRF12"),
|
|
DEFINE_RES_IRQ_NAMED(MT6377_IRQ_VRF09_OC, "VRF09"),
|
|
DEFINE_RES_IRQ_NAMED(MT6377_IRQ_VRFVA12_OC, "VRFVA12"),
|
|
DEFINE_RES_IRQ_NAMED(MT6377_IRQ_VRFIO18_OC, "VRFIO18"),
|
|
DEFINE_RES_IRQ_NAMED(MT6377_IRQ_VMCH_OC, "VMCH"),
|
|
DEFINE_RES_IRQ_NAMED(MT6377_IRQ_VMC_OC, "VMC"),
|
|
DEFINE_RES_IRQ_NAMED(MT6377_IRQ_VUSB_OC, "VUSB"),
|
|
DEFINE_RES_IRQ_NAMED(MT6377_IRQ_VIBR_OC, "VIBR"),
|
|
DEFINE_RES_IRQ_NAMED(MT6377_IRQ_VIO28_OC, "VIO28"),
|
|
DEFINE_RES_IRQ_NAMED(MT6377_IRQ_VFP_OC, "VFP"),
|
|
DEFINE_RES_IRQ_NAMED(MT6377_IRQ_VTP_OC, "VTP"),
|
|
};
|
|
|
|
static const struct resource mt6377_battery_oc_resources[] = {
|
|
DEFINE_RES_IRQ_NAMED(MT6377_IRQ_FG_CUR_H, "fg_cur_h"),
|
|
DEFINE_RES_IRQ_NAMED(MT6377_IRQ_FG_CUR_L, "fg_cur_l"),
|
|
};
|
|
|
|
static const struct resource mt6377_lbat_service_resources[] = {
|
|
DEFINE_RES_IRQ_NAMED(MT6377_IRQ_BAT_H, "bat_h"),
|
|
DEFINE_RES_IRQ_NAMED(MT6377_IRQ_BAT_L, "bat_l"),
|
|
};
|
|
|
|
static const struct resource mt6377_rtc_resources[] = {
|
|
DEFINE_RES_IRQ(MT6377_IRQ_RTC),
|
|
};
|
|
|
|
static const struct resource mt6377_gauge_resources[] = {
|
|
DEFINE_RES_IRQ_NAMED(MT6377_IRQ_FG_BAT_H, "COULOMB_H"),
|
|
DEFINE_RES_IRQ_NAMED(MT6377_IRQ_FG_BAT_L, "COULOMB_L"),
|
|
DEFINE_RES_IRQ_NAMED(MT6377_IRQ_BAT2_H, "VBAT_H"),
|
|
DEFINE_RES_IRQ_NAMED(MT6377_IRQ_BAT2_L, "VBAT_L"),
|
|
DEFINE_RES_IRQ_NAMED(MT6377_IRQ_NAG_C_DLTV, "NAFG"),
|
|
DEFINE_RES_IRQ_NAMED(MT6377_IRQ_BATON_BAT_OUT, "BAT_OUT"),
|
|
DEFINE_RES_IRQ_NAMED(MT6377_IRQ_FG_ZCV, "ZCV"),
|
|
DEFINE_RES_IRQ_NAMED(MT6377_IRQ_FG_N_CHARGE_L, "FG_N_CHARGE_L"),
|
|
DEFINE_RES_IRQ_NAMED(MT6377_IRQ_FG_IAVG_H, "FG_IAVG_H"),
|
|
DEFINE_RES_IRQ_NAMED(MT6377_IRQ_FG_IAVG_L, "FG_IAVG_L"),
|
|
DEFINE_RES_IRQ_NAMED(MT6377_IRQ_BAT_TEMP_H, "BAT_TMP_H"),
|
|
DEFINE_RES_IRQ_NAMED(MT6377_IRQ_BAT_TEMP_L, "BAT_TMP_L"),
|
|
};
|
|
|
|
static const struct mfd_cell mt6363_devs[] = {
|
|
{
|
|
.name = "mt6363-auxadc",
|
|
.of_compatible = "mediatek,mt6363-auxadc",
|
|
}, {
|
|
.name = "mtk-dynamic-loading-throttling",
|
|
.of_compatible = "mediatek,mt6363-dynamic_loading_throttling",
|
|
}, {
|
|
.name = "mt6363-efuse",
|
|
.of_compatible = "mediatek,mt6363-efuse",
|
|
}, {
|
|
.name = "mt6363-regulator",
|
|
.num_resources = ARRAY_SIZE(mt6363_regulators_resources),
|
|
.resources = mt6363_regulators_resources,
|
|
}, {
|
|
.name = "mt-pmic",
|
|
.of_compatible = "mediatek,spmi-pmic-debug",
|
|
}, {
|
|
.name = "mtk-pmic-keys",
|
|
.num_resources = ARRAY_SIZE(mt6363_keys_resources),
|
|
.resources = mt6363_keys_resources,
|
|
.of_compatible = "mediatek,mt6363-keys"
|
|
}, {
|
|
.name = "mt6363-consys",
|
|
.of_compatible = "mediatek,mt6363-consys",
|
|
}, {
|
|
.name = "mt6363-lvsys-notify",
|
|
.num_resources = ARRAY_SIZE(mt6363_lvsys_notify_resources),
|
|
.resources = mt6363_lvsys_notify_resources,
|
|
.of_compatible = "mediatek,mt6363-lvsys-notify",
|
|
},
|
|
};
|
|
|
|
static const struct mfd_cell mt6368_devs[] = {
|
|
{
|
|
.name = "second-pmic",
|
|
.of_compatible = "mediatek,spmi-pmic-debug",
|
|
}, {
|
|
.name = "mt6368-accdet",
|
|
.of_compatible = "mediatek,mt6368-accdet",
|
|
.num_resources = ARRAY_SIZE(mt6368_accdet_resources),
|
|
.resources = mt6368_accdet_resources,
|
|
}, {
|
|
.name = "mt6368-regulator",
|
|
.num_resources = ARRAY_SIZE(mt6368_regulators_resources),
|
|
.resources = mt6368_regulators_resources,
|
|
}, {
|
|
.name = "mt6368-auxadc",
|
|
.of_compatible = "mediatek,mt6368-auxadc",
|
|
}, {
|
|
.name = "mt6368-efuse",
|
|
.of_compatible = "mediatek,mt6368-efuse",
|
|
}, {
|
|
.name = "mt6368-consys",
|
|
.of_compatible = "mediatek,mt6368-consys",
|
|
}, {
|
|
.name = "mt6368-sound",
|
|
.of_compatible = "mediatek,mt6368-sound",
|
|
},
|
|
};
|
|
|
|
static const struct mfd_cell mt6369_devs[] = {
|
|
{
|
|
.name = "second-pmic",
|
|
.of_compatible = "mediatek,spmi-pmic-debug",
|
|
}, {
|
|
.name = "mt6369-accdet",
|
|
.of_compatible = "mediatek,mt6369-accdet",
|
|
.num_resources = ARRAY_SIZE(mt6369_accdet_resources),
|
|
.resources = mt6369_accdet_resources,
|
|
}, {
|
|
.name = "mt6369-regulator",
|
|
.num_resources = ARRAY_SIZE(mt6369_regulators_resources),
|
|
.resources = mt6369_regulators_resources,
|
|
}, {
|
|
.name = "mt6369-auxadc",
|
|
.of_compatible = "mediatek,mt6368-auxadc",
|
|
}, {
|
|
.name = "mt6369-efuse",
|
|
.of_compatible = "mediatek,mt6373-efuse",
|
|
}, {
|
|
.name = "mt6369-consys",
|
|
.of_compatible = "mediatek,mt6369-consys",
|
|
}, {
|
|
.name = "mt6369-sound",
|
|
.of_compatible = "mediatek,mt6369-sound",
|
|
},
|
|
};
|
|
|
|
static const struct mfd_cell mt6373_devs[] = {
|
|
{
|
|
.name = "second-pmic",
|
|
.of_compatible = "mediatek,spmi-pmic-debug",
|
|
}, {
|
|
.name = "mt6373-regulator",
|
|
.num_resources = ARRAY_SIZE(mt6373_regulators_resources),
|
|
.resources = mt6373_regulators_resources,
|
|
}, {
|
|
.name = "mt6373-auxadc",
|
|
.of_compatible = "mediatek,mt6373-auxadc",
|
|
}, {
|
|
.name = "mt6373-efuse",
|
|
.of_compatible = "mediatek,mt6373-efuse",
|
|
}, {
|
|
.name = "mt6373-consys",
|
|
.of_compatible = "mediatek,mt6373-consys",
|
|
}, {
|
|
.name = "mt6373-pinctrl",
|
|
.of_compatible = "mediatek,mt6373-pinctrl",
|
|
},
|
|
};
|
|
|
|
static const struct mfd_cell mt6377_devs[] = {
|
|
{
|
|
.name = "mt6377-auxadc",
|
|
.of_compatible = "mediatek,mt6377-auxadc",
|
|
}, {
|
|
.name = "mt6377-accdet",
|
|
.of_compatible = "mediatek,mt6377-accdet",
|
|
.num_resources = ARRAY_SIZE(mt6377_accdet_resources),
|
|
.resources = mt6377_accdet_resources,
|
|
}, {
|
|
.name = "mt6377-clock-buffer",
|
|
.of_compatible = "mediatek,clock_buffer",
|
|
}, {
|
|
.name = "mtk-battery-oc-throttling",
|
|
.of_compatible = "mediatek,mt6377-battery_oc_throttling",
|
|
.num_resources = ARRAY_SIZE(mt6377_battery_oc_resources),
|
|
.resources = mt6377_battery_oc_resources,
|
|
}, {
|
|
.name = "mtk-dynamic-loading-throttling",
|
|
.of_compatible = "mediatek,mt6377-dynamic_loading_throttling",
|
|
}, {
|
|
.name = "mtk-lbat-service",
|
|
.of_compatible = "mediatek,mt6377-lbat-service",
|
|
.num_resources = ARRAY_SIZE(mt6377_lbat_service_resources),
|
|
.resources = mt6377_lbat_service_resources,
|
|
}, {
|
|
.name = "mt6377-efuse",
|
|
.of_compatible = "mediatek,mt6377-efuse",
|
|
}, {
|
|
.name = "mt6377-consys",
|
|
.of_compatible = "mediatek,mt6377-consys",
|
|
}, {
|
|
.name = "mt6377-regulator",
|
|
.num_resources = ARRAY_SIZE(mt6377_regulators_resources),
|
|
.resources = mt6377_regulators_resources,
|
|
}, {
|
|
.name = "mtk-pmic-keys",
|
|
.num_resources = ARRAY_SIZE(mt6377_keys_resources),
|
|
.resources = mt6377_keys_resources,
|
|
.of_compatible = "mediatek,mt6377-keys"
|
|
}, {
|
|
.name = "mt6377-gauge",
|
|
.num_resources = ARRAY_SIZE(mt6377_gauge_resources),
|
|
.resources = mt6377_gauge_resources,
|
|
.of_compatible = "mediatek,mt6377-gauge",
|
|
}, {
|
|
.name = "mt-pmic",
|
|
.of_compatible = "mediatek,spmi-pmic-debug",
|
|
}, {
|
|
.name = "mt6377-sound",
|
|
.of_compatible = "mediatek,mt6377-sound",
|
|
}, {
|
|
.name = "mt6377-rtc",
|
|
.num_resources = ARRAY_SIZE(mt6377_rtc_resources),
|
|
.resources = mt6377_rtc_resources,
|
|
.of_compatible = "mediatek,mt6377-rtc",
|
|
},
|
|
};
|
|
|
|
static struct irq_top_t mt6363_ints[] = {
|
|
MT6363_TOP_GEN(BUCK),
|
|
MT6363_TOP_GEN(LDO),
|
|
MT6363_TOP_GEN(PSC),
|
|
MT6363_TOP_GEN(MISC),
|
|
MT6363_TOP_GEN(HK),
|
|
MT6363_TOP_GEN(BM),
|
|
};
|
|
|
|
static struct irq_top_t mt6368_ints[] = {
|
|
MT6368_TOP_GEN(BUCK),
|
|
MT6368_TOP_GEN(LDO),
|
|
MT6368_TOP_GEN(MISC),
|
|
MT6368_TOP_GEN(AUD),
|
|
};
|
|
|
|
static struct irq_top_t mt6369_ints[] = {
|
|
MT6369_TOP_GEN(BUCK),
|
|
MT6369_TOP_GEN(LDO),
|
|
MT6369_TOP_GEN(MISC),
|
|
MT6369_TOP_GEN(HK),
|
|
MT6369_TOP_GEN(AUD),
|
|
};
|
|
|
|
static struct irq_top_t mt6373_ints[] = {
|
|
MT6373_TOP_GEN(BUCK),
|
|
MT6373_TOP_GEN(LDO),
|
|
MT6373_TOP_GEN(MISC),
|
|
};
|
|
|
|
static struct irq_top_t mt6377_ints[] = {
|
|
MT6377_TOP_GEN(BUCK),
|
|
MT6377_TOP_GEN(LDO),
|
|
MT6377_TOP_GEN(PSC),
|
|
MT6377_TOP_GEN(MISC),
|
|
MT6377_TOP_GEN(HK),
|
|
MT6377_TOP_GEN(SCK),
|
|
MT6377_TOP_GEN(BM),
|
|
MT6377_TOP_GEN(AUD),
|
|
};
|
|
|
|
static const struct mtk_spmi_pmic_data common_data = {
|
|
.num_pmic_irqs = 0,
|
|
};
|
|
|
|
static const struct mtk_spmi_pmic_data mt6363_data = {
|
|
.cells = mt6363_devs,
|
|
.cell_size = ARRAY_SIZE(mt6363_devs),
|
|
.num_top = ARRAY_SIZE(mt6363_ints),
|
|
.num_pmic_irqs = MT6363_IRQ_NR,
|
|
.top_int_status_reg = MT6363_TOP_INT_STATUS1,
|
|
.pmic_ints = mt6363_ints,
|
|
};
|
|
|
|
static const struct mtk_spmi_pmic_data mt6368_data = {
|
|
.cells = mt6368_devs,
|
|
.cell_size = ARRAY_SIZE(mt6368_devs),
|
|
.num_top = ARRAY_SIZE(mt6368_ints),
|
|
.num_pmic_irqs = MT6368_IRQ_NR,
|
|
.top_int_status_reg = MT6368_TOP_INT_STATUS1,
|
|
.pmic_ints = mt6368_ints,
|
|
};
|
|
|
|
static const struct mtk_spmi_pmic_data mt6369_data = {
|
|
.cells = mt6369_devs,
|
|
.cell_size = ARRAY_SIZE(mt6369_devs),
|
|
.num_top = ARRAY_SIZE(mt6369_ints),
|
|
.num_pmic_irqs = MT6369_IRQ_NR,
|
|
.top_int_status_reg = MT6369_TOP_INT_STATUS1,
|
|
.pmic_ints = mt6369_ints,
|
|
};
|
|
|
|
static const struct mtk_spmi_pmic_data mt6373_data = {
|
|
.cells = mt6373_devs,
|
|
.cell_size = ARRAY_SIZE(mt6373_devs),
|
|
.num_top = ARRAY_SIZE(mt6373_ints),
|
|
.num_pmic_irqs = MT6373_IRQ_NR,
|
|
.top_int_status_reg = MT6373_TOP_INT_STATUS1,
|
|
.pmic_ints = mt6373_ints,
|
|
};
|
|
|
|
static const struct mtk_spmi_pmic_data mt6377_data = {
|
|
.cells = mt6377_devs,
|
|
.cell_size = ARRAY_SIZE(mt6377_devs),
|
|
.num_top = ARRAY_SIZE(mt6377_ints),
|
|
.num_pmic_irqs = MT6377_IRQ_NR,
|
|
.top_int_status_reg = MT6377_TOP_INT_STATUS1,
|
|
.pmic_ints = mt6377_ints,
|
|
};
|
|
|
|
static void mtk_spmi_pmic_irq_enable(struct irq_data *data)
|
|
{
|
|
unsigned int hwirq = irqd_to_hwirq(data);
|
|
struct pmic_core *core = irq_data_get_irq_chip_data(data);
|
|
|
|
core->enable_hwirq[hwirq] = true;
|
|
}
|
|
|
|
static void mtk_spmi_pmic_irq_disable(struct irq_data *data)
|
|
{
|
|
unsigned int hwirq = irqd_to_hwirq(data);
|
|
struct pmic_core *core = irq_data_get_irq_chip_data(data);
|
|
|
|
core->enable_hwirq[hwirq] = false;
|
|
}
|
|
|
|
static void mtk_spmi_pmic_irq_lock(struct irq_data *data)
|
|
{
|
|
struct pmic_core *core = irq_data_get_irq_chip_data(data);
|
|
|
|
mutex_lock(&core->irqlock);
|
|
}
|
|
|
|
static void mtk_spmi_pmic_irq_sync_unlock(struct irq_data *data)
|
|
{
|
|
unsigned int i, top_gp, gp_offset, en_reg, int_regs, shift;
|
|
struct irq_top_t *pmic_int;
|
|
struct pmic_core *core = irq_data_get_irq_chip_data(data);
|
|
const struct mtk_spmi_pmic_data *chip_data = core->chip_data;
|
|
|
|
for (i = 0; i < chip_data->num_pmic_irqs; i++) {
|
|
if (core->enable_hwirq[i] == core->cache_hwirq[i])
|
|
continue;
|
|
|
|
/* Find out the IRQ group */
|
|
top_gp = 0;
|
|
while ((top_gp + 1) < chip_data->num_top &&
|
|
i >= chip_data->pmic_ints[top_gp + 1].hwirq_base)
|
|
top_gp++;
|
|
|
|
pmic_int = &(chip_data->pmic_ints[top_gp]);
|
|
/* Find the IRQ registers */
|
|
gp_offset = i - pmic_int->hwirq_base;
|
|
int_regs = gp_offset / MTK_SPMI_PMIC_REG_WIDTH;
|
|
shift = gp_offset % MTK_SPMI_PMIC_REG_WIDTH;
|
|
en_reg = pmic_int->en_reg + (pmic_int->en_reg_shift * int_regs);
|
|
|
|
regmap_update_bits(core->regmap, en_reg, BIT(shift),
|
|
core->enable_hwirq[i] << shift);
|
|
core->cache_hwirq[i] = core->enable_hwirq[i];
|
|
}
|
|
mutex_unlock(&core->irqlock);
|
|
}
|
|
|
|
static struct irq_chip mtk_spmi_pmic_irq_chip = {
|
|
.name = "spmi-pmic-irq",
|
|
.flags = IRQCHIP_SKIP_SET_WAKE,
|
|
.irq_enable = mtk_spmi_pmic_irq_enable,
|
|
.irq_disable = mtk_spmi_pmic_irq_disable,
|
|
.irq_bus_lock = mtk_spmi_pmic_irq_lock,
|
|
.irq_bus_sync_unlock = mtk_spmi_pmic_irq_sync_unlock,
|
|
};
|
|
|
|
static void mtk_spmi_pmic_irq_sp_handler(struct pmic_core *core,
|
|
unsigned int top_gp)
|
|
{
|
|
unsigned int irq_status = 0, sta_reg, status;
|
|
unsigned int hwirq, virq;
|
|
int ret, i, j;
|
|
struct irq_top_t *pmic_int;
|
|
const struct mtk_spmi_pmic_data *chip_data = core->chip_data;
|
|
|
|
for (i = 0; i < chip_data->pmic_ints[top_gp].num_int_regs; i++) {
|
|
pmic_int = &(chip_data->pmic_ints[top_gp]);
|
|
sta_reg = pmic_int->sta_reg + (pmic_int->sta_reg_shift * i);
|
|
|
|
ret = regmap_read(core->regmap, sta_reg, &irq_status);
|
|
if (ret) {
|
|
dev_err(core->dev,
|
|
"Failed to read irq status: %d\n", ret);
|
|
return;
|
|
}
|
|
|
|
if (!irq_status)
|
|
continue;
|
|
|
|
status = irq_status;
|
|
do {
|
|
j = __ffs(status);
|
|
|
|
hwirq = pmic_int->hwirq_base + MTK_SPMI_PMIC_REG_WIDTH * i + j;
|
|
|
|
virq = irq_find_mapping(core->irq_domain, hwirq);
|
|
dev_info(core->dev, "[%x]Reg[0x%x]=0x%x,hwirq=%d\n",
|
|
core->chip_id, sta_reg, irq_status, hwirq);
|
|
if (virq)
|
|
handle_nested_irq(virq);
|
|
|
|
status &= ~BIT(j);
|
|
} while (status);
|
|
|
|
regmap_write(core->regmap, sta_reg, irq_status);
|
|
}
|
|
}
|
|
|
|
static irqreturn_t mtk_spmi_pmic_irq_handler(int irq, void *data)
|
|
{
|
|
int ret;
|
|
unsigned int bit, i, top_irq_status = 0;
|
|
struct pmic_core *core = data;
|
|
const struct mtk_spmi_pmic_data *chip_data = core->chip_data;
|
|
|
|
ret = regmap_read(core->regmap, chip_data->top_int_status_reg,
|
|
&top_irq_status);
|
|
if (ret) {
|
|
dev_err(core->dev,
|
|
"Failed to read status from the device, ret=%d\n", ret);
|
|
return IRQ_NONE;
|
|
}
|
|
|
|
dev_info(core->dev, "top_irq_sts:0x%x\n", top_irq_status);
|
|
for (i = 0; i < chip_data->num_top; i++) {
|
|
bit = BIT(chip_data->pmic_ints[i].top_offset);
|
|
if (top_irq_status & bit) {
|
|
mtk_spmi_pmic_irq_sp_handler(core, i);
|
|
if (!top_irq_status)
|
|
break;
|
|
}
|
|
}
|
|
|
|
ret = regmap_write(core->regmap, RCS_INT_DONE, 1);
|
|
if (ret) {
|
|
dev_err(core->dev,
|
|
"Failed to clear RCS flag, ret=%d\n", ret);
|
|
return IRQ_NONE;
|
|
}
|
|
|
|
return IRQ_HANDLED;
|
|
}
|
|
|
|
static int mtk_spmi_pmic_irq_domain_map(struct irq_domain *d, unsigned int irq,
|
|
irq_hw_number_t hw)
|
|
{
|
|
struct pmic_core *core = d->host_data;
|
|
|
|
irq_set_chip_data(irq, core);
|
|
irq_set_chip_and_handler(irq, &mtk_spmi_pmic_irq_chip,
|
|
handle_level_irq);
|
|
irq_set_nested_thread(irq, 1);
|
|
irq_set_noprobe(irq);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static const struct irq_domain_ops pmic_irq_domain_ops = {
|
|
.map = mtk_spmi_pmic_irq_domain_map,
|
|
.xlate = irq_domain_xlate_twocell,
|
|
};
|
|
|
|
static int mtk_spmi_pmic_irq_init(struct pmic_core *core)
|
|
{
|
|
int i, j, ret;
|
|
unsigned int en_reg, sta_reg;
|
|
const struct mtk_spmi_pmic_data *chip_data = core->chip_data;
|
|
|
|
mutex_init(&core->irqlock);
|
|
core->enable_hwirq = devm_kcalloc(core->dev,
|
|
chip_data->num_pmic_irqs,
|
|
sizeof(bool), GFP_KERNEL);
|
|
if (!core->enable_hwirq)
|
|
return -ENOMEM;
|
|
|
|
core->cache_hwirq = devm_kcalloc(core->dev,
|
|
chip_data->num_pmic_irqs,
|
|
sizeof(bool), GFP_KERNEL);
|
|
if (!core->cache_hwirq)
|
|
return -ENOMEM;
|
|
|
|
/* Disable all interrupt for initializing */
|
|
for (i = 0; i < chip_data->num_top; i++) {
|
|
for (j = 0; j < chip_data->pmic_ints[i].num_int_regs; j++) {
|
|
en_reg = chip_data->pmic_ints[i].en_reg +
|
|
chip_data->pmic_ints[i].en_reg_shift * j;
|
|
regmap_write(core->regmap, en_reg, 0);
|
|
sta_reg = chip_data->pmic_ints[i].sta_reg +
|
|
chip_data->pmic_ints[i].sta_reg_shift * j;
|
|
regmap_write(core->regmap, sta_reg, 0xFF);
|
|
}
|
|
}
|
|
regmap_write(core->regmap, RCS_INT_DONE, 1);
|
|
|
|
core->irq_domain = irq_domain_add_linear(core->dev->of_node,
|
|
chip_data->num_pmic_irqs,
|
|
&pmic_irq_domain_ops,
|
|
core);
|
|
if (!core->irq_domain) {
|
|
dev_err(core->dev, "Could not create IRQ domain\n");
|
|
return -ENODEV;
|
|
}
|
|
|
|
ret = devm_request_threaded_irq(core->dev, core->irq, NULL,
|
|
mtk_spmi_pmic_irq_handler, IRQF_ONESHOT,
|
|
mtk_spmi_pmic_irq_chip.name, core);
|
|
if (ret) {
|
|
dev_err(core->dev, "Failed to register IRQ=%d, ret=%d\n",
|
|
core->irq, ret);
|
|
return ret;
|
|
}
|
|
|
|
enable_irq_wake(core->irq);
|
|
return ret;
|
|
}
|
|
|
|
static const struct regmap_config spmi_regmap_config = {
|
|
.reg_bits = 16,
|
|
.val_bits = 8,
|
|
.max_register = 0xffff,
|
|
.fast_io = true,
|
|
};
|
|
|
|
static int mtk_spmi_pmic_probe(struct spmi_device *sdev)
|
|
{
|
|
int ret;
|
|
unsigned int id;
|
|
struct device_node *np = sdev->dev.of_node;
|
|
struct pmic_core *core;
|
|
const struct mtk_spmi_pmic_data *chip_data;
|
|
|
|
core = devm_kzalloc(&sdev->dev, sizeof(*core), GFP_KERNEL);
|
|
if (!core)
|
|
return -ENOMEM;
|
|
|
|
core->sdev = sdev;
|
|
core->dev = &sdev->dev;
|
|
chip_data = (struct mtk_spmi_pmic_data *)of_device_get_match_data(&sdev->dev);
|
|
if (!chip_data)
|
|
return -ENODEV;
|
|
|
|
core->chip_data = chip_data;
|
|
core->regmap = devm_regmap_init_spmi_ext(sdev, &spmi_regmap_config);
|
|
if (IS_ERR(core->regmap))
|
|
return PTR_ERR(core->regmap);
|
|
ret = regmap_read(core->regmap, PMIC_SWCID, &id);
|
|
if (ret) {
|
|
dev_err(&sdev->dev, "Failed to read chip id: %d\n", ret);
|
|
return ret;
|
|
}
|
|
|
|
core->chip_id = id;
|
|
|
|
if (chip_data->num_pmic_irqs) {
|
|
core->irq = of_irq_get(np, 0);
|
|
if (core->irq < 0)
|
|
dev_err(&sdev->dev, "Failed to get irq(%d)\n", core->irq);
|
|
|
|
ret = mtk_spmi_pmic_irq_init(core);
|
|
if (ret)
|
|
dev_err(&sdev->dev, "IRQ_init failed(%d)\n", core->irq);
|
|
|
|
ret = devm_mfd_add_devices(&sdev->dev, -1, chip_data->cells,
|
|
chip_data->cell_size, NULL, 0,
|
|
core->irq_domain);
|
|
if (ret)
|
|
irq_domain_remove(core->irq_domain);
|
|
} else
|
|
ret = devm_of_platform_populate(&sdev->dev);
|
|
if (ret) {
|
|
dev_err(&sdev->dev, "Failed to add child devices: %d\n", ret);
|
|
return ret;
|
|
}
|
|
|
|
device_init_wakeup(&sdev->dev, true);
|
|
|
|
dev_info(&sdev->dev, "probe chip id=0x%x done\n", core->chip_id);
|
|
|
|
return ret;
|
|
}
|
|
|
|
static const struct of_device_id mtk_spmi_pmic_of_match[] = {
|
|
{ .compatible = "mediatek,mt6315", .data = &common_data, },
|
|
{ .compatible = "mediatek,mt6319", .data = &common_data, },
|
|
{ .compatible = "mediatek,mt6363", .data = &mt6363_data, },
|
|
{ .compatible = "mediatek,mt6368", .data = &mt6368_data, },
|
|
{ .compatible = "mediatek,mt6369", .data = &mt6369_data, },
|
|
{ .compatible = "mediatek,mt6373", .data = &mt6373_data, },
|
|
{ .compatible = "mediatek,mt6377", .data = &mt6377_data, },
|
|
{ }
|
|
};
|
|
MODULE_DEVICE_TABLE(of, mtk_spmi_pmic_of_match);
|
|
|
|
static struct spmi_driver mtk_spmi_pmic_driver = {
|
|
.driver = {
|
|
.name = "mtk-spmi-pmic",
|
|
.of_match_table = of_match_ptr(mtk_spmi_pmic_of_match),
|
|
},
|
|
.probe = mtk_spmi_pmic_probe,
|
|
};
|
|
module_spmi_driver(mtk_spmi_pmic_driver);
|
|
|
|
MODULE_DESCRIPTION("Mediatek SPMI PMIC driver");
|
|
MODULE_ALIAS("spmi:spmi-pmic");
|
|
MODULE_LICENSE("GPL v2");
|
|
MODULE_AUTHOR("Argus Lin <argus.lin@mediatek.com>");
|
|
MODULE_AUTHOR("Jeter Chen <jeter.chen@mediatek.com>");
|