blob: fd187a81c16f4d45087bdb7f1d30ef2b5f6eb386 [file] [log] [blame] [edit]
// 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/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 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 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",
},
};
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-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 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 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 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, },
{ }
};
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>");