Re: [PATCH v2 5/9] mfd: Add support for the MediaTek MT6358 PMIC
From: Claire Chang <hidden>
Date: 2019-03-15 07:25:49
On Fri, Mar 15, 2019 at 3:10 PM Nicolas Boichat [off-list ref] wrote:
+Claire Chang who found some issue with this patch. On Mon, Mar 11, 2019 at 11:48 AM Hsin-Hsiung Wang [off-list ref] wrote:quoted
This adds support for the MediaTek MT6358 PMIC. This is a multifunction device with the following sub modules: - Regulator - RTC - Codec - Interrupt It is interfaced to the host controller using SPI interface by a proprietary hardware called PMIC wrapper or pwrap. MT6358 MFD is a child device of the pwrap. Signed-off-by: Hsin-Hsiung Wang <redacted> --- drivers/mfd/Makefile | 2 +- drivers/mfd/mt6358-irq.c | 236 +++++ drivers/mfd/mt6397-core.c | 63 +- include/linux/mfd/mt6358/core.h | 158 +++ include/linux/mfd/mt6358/registers.h | 1926++++++++++++++++++++++++++++++++++quoted
include/linux/mfd/mt6397/core.h | 3 + 6 files changed, 2386 insertions(+), 2 deletions(-) create mode 100644 drivers/mfd/mt6358-irq.c create mode 100644 include/linux/mfd/mt6358/core.h create mode 100644 include/linux/mfd/mt6358/registers.hdiff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile index 088e249..50be021 100644 --- a/drivers/mfd/Makefile +++ b/drivers/mfd/Makefile@@ -230,7 +230,7 @@ obj-$(CONFIG_INTEL_SOC_PMIC) +=intel-soc-pmic.oquoted
obj-$(CONFIG_INTEL_SOC_PMIC_BXTWC) += intel_soc_pmic_bxtwc.o obj-$(CONFIG_INTEL_SOC_PMIC_CHTWC) += intel_soc_pmic_chtwc.o obj-$(CONFIG_INTEL_SOC_PMIC_CHTDC_TI) += intel_soc_pmic_chtdc_ti.o -obj-$(CONFIG_MFD_MT6397) += mt6397-core.o mt6397-irq.o +obj-$(CONFIG_MFD_MT6397) += mt6397-core.o mt6397-irq.omt6358-irq.oquoted
obj-$(CONFIG_MFD_ALTERA_A10SR) += altera-a10sr.o obj-$(CONFIG_MFD_SUN4I_GPADC) += sun4i-gpadc.odiff --git a/drivers/mfd/mt6358-irq.c b/drivers/mfd/mt6358-irq.c new file mode 100644 index 0000000..2941d87 --- /dev/null +++ b/drivers/mfd/mt6358-irq.c@@ -0,0 +1,236 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// Copyright (c) 2019 MediaTek Inc. + +#include <linux/interrupt.h> +#include <linux/mfd/mt6358/core.h> +#include <linux/mfd/mt6358/registers.h> +#include <linux/mfd/mt6397/core.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/of_device.h> +#include <linux/of_irq.h> +#include <linux/platform_device.h> +#include <linux/regmap.h> + +static struct irq_top_t mt6358_ints[] = { + MT6358_TOP_GEN(BUCK), + MT6358_TOP_GEN(LDO), + MT6358_TOP_GEN(PSC), + MT6358_TOP_GEN(SCK), + MT6358_TOP_GEN(BM), + MT6358_TOP_GEN(HK), + MT6358_TOP_GEN(AUD), + MT6358_TOP_GEN(MISC), +}; + +static int parsing_hwirq_to_top_group(unsigned int hwirq) +{ + int top_group; + + for (top_group = 1; top_group < ARRAY_SIZE(mt6358_ints);top_group++) {quoted
+ if (mt6358_ints[top_group].hwirq_base > hwirq) { + top_group--; + break; + } + } + return top_group; +} + +static void pmic_irq_enable(struct irq_data *data) +{ + unsigned int hwirq = irqd_to_hwirq(data); + struct mt6397_chip *chip = irq_data_get_irq_chip_data(data); + struct pmic_irq_data *irqd = chip->irq_data; + + irqd->enable_hwirq[hwirq] = true; +} + +static void pmic_irq_disable(struct irq_data *data) +{ + unsigned int hwirq = irqd_to_hwirq(data); + struct mt6397_chip *chip = irq_data_get_irq_chip_data(data); + struct pmic_irq_data *irqd = chip->irq_data; + + irqd->enable_hwirq[hwirq] = false; +} + +static void pmic_irq_lock(struct irq_data *data) +{ + struct mt6397_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, top_gp, en_reg, int_regs, shift; + struct mt6397_chip *chip = irq_data_get_irq_chip_data(data); + struct pmic_irq_data *irqd = chip->irq_data; + + for (i = 0; i < irqd->num_pmic_irqs; i++) { + if (irqd->enable_hwirq[i] == + irqd->cache_hwirq[i]) + continue; + + top_gp = parsing_hwirq_to_top_group(i); + int_regs = mt6358_ints[top_gp].num_int_bits /MT6358_REG_WIDTH;quoted
+ en_reg = mt6358_ints[top_gp].en_reg + + mt6358_ints[top_gp].en_reg_shift * int_regs; + shift = (i - mt6358_ints[top_gp].hwirq_base) %MT6358_REG_WIDTH;quoted
+ regmap_update_bits(chip->regmap, en_reg, BIT(shift), + irqd->enable_hwirq[i] << shift); + irqd->cache_hwirq[i] = irqd->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 mt6358_irq_chip = { + .name = "mt6358-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, +};
Should we also add .irq_set_wake just like mt6397-irq.c? Without .irq_set_wake, we will have unbalanced IRQ wake disable issue during suspend/resume.
quoted
+ +static void mt6358_irq_sp_handler(struct mt6397_chip *chip, + unsigned int top_gp) +{ + unsigned int sta_reg, irq_status; + unsigned int hwirq, virq; + int ret, i, j; + + for (i = 0; i < mt6358_ints[top_gp].num_int_regs; i++) { + sta_reg = mt6358_ints[top_gp].sta_reg + + mt6358_ints[top_gp].sta_reg_shift * i; + ret = regmap_read(chip->regmap, sta_reg, &irq_status); + if (ret) { + dev_err(chip->dev, + "Failed to read irq status: %d\n", ret); + return; + } + + if (!irq_status) + continue; + + for (j = 0; j < MT6358_REG_WIDTH ; j++) { + if ((irq_status & BIT(j)) == 0) + continue; + hwirq = mt6358_ints[top_gp].hwirq_base + + MT6358_REG_WIDTH * i + j; + virq = irq_find_mapping(chip->irq_domain, hwirq); + if (virq) + handle_nested_irq(virq); + } + + regmap_write(chip->regmap, sta_reg, irq_status); + } +} + +static irqreturn_t mt6358_irq_handler(int irq, void *data) +{ + struct mt6397_chip *chip = data; + struct pmic_irq_data *mt6358_irq_data = chip->irq_data; + unsigned int top_irq_status; + unsigned int i; + int ret; + + ret = regmap_read(chip->regmap, + mt6358_irq_data->top_int_status_reg, + &top_irq_status); + if (ret) { + dev_err(chip->dev, "Can't read TOP_INT_STATUS ret=%d\n",ret);quoted
+ return IRQ_NONE; + } + + for (i = 0; i < mt6358_irq_data->num_top; i++) { + if (top_irq_status & BIT(mt6358_ints[i].top_offset)) + mt6358_irq_sp_handler(chip, i); + } + + return IRQ_HANDLED; +} + +static int pmic_irq_domain_map(struct irq_domain *d, unsigned int irq, + irq_hw_number_t hw) +{ + struct mt6397_chip *mt6397 = d->host_data; + + irq_set_chip_data(irq, mt6397); + irq_set_chip_and_handler(irq, &mt6358_irq_chip,handle_level_irq);quoted
+ irq_set_nested_thread(irq, 1); + irq_set_noprobe(irq); + + return 0; +} + +static const struct irq_domain_ops mt6358_irq_domain_ops = { + .map = pmic_irq_domain_map, + .xlate = irq_domain_xlate_twocell, +}; + +int mt6358_irq_init(struct mt6397_chip *chip) +{ + int i, j, ret; + struct pmic_irq_data *irqd; + + irqd = devm_kzalloc(chip->dev, sizeof(struct pmic_irq_data *), + GFP_KERNEL); + if (!irqd) + return -ENOMEM; + + chip->irq_data = irqd; + + mutex_init(&chip->irqlock); + irqd->top_int_status_reg = MT6358_TOP_INT_STATUS0; + irqd->num_pmic_irqs = MT6358_IRQ_NR; + irqd->num_top = ARRAY_SIZE(mt6358_ints); + + irqd->enable_hwirq = devm_kcalloc(chip->dev, + irqd->num_pmic_irqs, + sizeof(bool), + GFP_KERNEL); + if (!irqd->enable_hwirq) + return -ENOMEM; + + irqd->cache_hwirq = devm_kcalloc(chip->dev, + irqd->num_pmic_irqs, + sizeof(bool), + GFP_KERNEL); + if (!irqd->cache_hwirq) + return -ENOMEM; + + /* Disable all interrupt for initializing */ + for (i = 0; i < irqd->num_top; i++) { + for (j = 0; j < mt6358_ints[i].num_int_regs; j++) + regmap_write(chip->regmap, + mt6358_ints[i].en_reg + + mt6358_ints[i].en_reg_shift * j, 0); + } + + chip->irq_domain = irq_domain_add_linear(chip->dev->of_node, + irqd->num_pmic_irqs, + &mt6358_irq_domain_ops,chip);quoted
+ if (!chip->irq_domain) { + dev_err(chip->dev, "could not create irq domain\n"); + return -ENODEV; + } + + ret = devm_request_threaded_irq(chip->dev, chip->irq, NULL, + mt6358_irq_handler, IRQF_ONESHOT, + mt6358_irq_chip.name, chip); + if (ret) { + dev_err(chip->dev, "failed to register irq=%d; err:%d\n",quoted
+ chip->irq, ret); + return ret; + } + + enable_irq_wake(chip->irq); + return ret; +}diff --git a/drivers/mfd/mt6397-core.c b/drivers/mfd/mt6397-core.c index 53f1edc..9ef14f9 100644 --- a/drivers/mfd/mt6397-core.c +++ b/drivers/mfd/mt6397-core.c@@ -18,12 +18,36 @@ #include <linux/regmap.h> #include <linux/mfd/core.h> #include <linux/mfd/mt6323/core.h> +#include <linux/mfd/mt6358/core.h> #include <linux/mfd/mt6397/core.h> #include <linux/mfd/mt6323/registers.h> +#include <linux/mfd/mt6358/registers.h> #include <linux/mfd/mt6397/registers.h> +#define MT6358_RTC_BASE 0x0588 +#define MT6358_RTC_SIZE 0x3c +#define MT6358_RTC_WRTGR_OFFSET 0x3a #define MT6397_RTC_BASE 0xe000 #define MT6397_RTC_SIZE 0x3e +#define MT6397_RTC_WRTGR_OFFSET 0x3c + +static const struct resource mt6358_rtc_resources[] = { + { + .start = MT6358_RTC_BASE, + .end = MT6358_RTC_BASE + MT6358_RTC_SIZE, + .flags = IORESOURCE_MEM, + }, + { + .start = MT6358_IRQ_RTC, + .end = MT6358_IRQ_RTC, + .flags = IORESOURCE_IRQ, + }, + { + .start = MT6358_RTC_WRTGR_OFFSET, + .end = MT6358_RTC_WRTGR_OFFSET, + .flags = IORESOURCE_REG, + }, +}; static const struct resource mt6397_rtc_resources[] = { {@@ -36,6 +60,11 @@ .end = MT6397_IRQ_RTC, .flags = IORESOURCE_IRQ, }, + { + .start = MT6397_RTC_WRTGR_OFFSET, + .end = MT6397_RTC_WRTGR_OFFSET, + .flags = IORESOURCE_REG, + }, }; static const struct resource mt6323_keys_resources[] = {@@ -63,6 +92,21 @@ }, }; +static const struct mfd_cell mt6358_devs[] = { + { + .name = "mt6358-regulator", + .of_compatible = "mediatek,mt6358-regulator" + }, { + .name = "mt6397-rtc", + .num_resources = ARRAY_SIZE(mt6358_rtc_resources), + .resources = mt6358_rtc_resources, + .of_compatible = "mediatek,mt6358-rtc", + }, { + .name = "mt6358-sound", + .of_compatible = "mediatek,mt6358-sound" + }, +}; + static const struct mfd_cell mt6397_devs[] = { { .name = "mt6397-rtc",@@ -97,6 +141,10 @@ struct chip_data { .cid_addr = MT6323_CID, }; +static const struct chip_data mt6358_core = { + .cid_addr = MT6358_SWCID, +}; + static const struct chip_data mt6397_core = { .cid_addr = MT6397_CID, };@@ -140,7 +188,11 @@ static int mt6397_probe(struct platform_device*pdev)quoted
if (pmic->irq <= 0) return pmic->irq; - ret = mt6397_irq_init(pmic); + if (pmic->chip_id == MT6358_CHIP_ID) + ret = mt6358_irq_init(pmic); + else + ret = mt6397_irq_init(pmic); + if (ret) return ret;@@ -151,6 +203,12 @@ static int mt6397_probe(struct platform_device*pdev)quoted
0, pmic->irq_domain); break; + case MT6358_CHIP_ID: + ret = devm_mfd_add_devices(&pdev->dev, -1, mt6358_devs, + ARRAY_SIZE(mt6358_devs), NULL, + 0, pmic->irq_domain); + break; + case MT6391_CHIP_ID: case MT6397_CHIP_ID: ret = devm_mfd_add_devices(&pdev->dev, -1, mt6397_devs,@@ -177,6 +235,9 @@ static int mt6397_probe(struct platform_device *pdev) .compatible = "mediatek,mt6323", .data = &mt6323_core, }, { + .compatible = "mediatek,mt6358", + .data = &mt6358_core, + }, { .compatible = "mediatek,mt6397", .data = &mt6397_core, }, {diff --git a/include/linux/mfd/mt6358/core.hb/include/linux/mfd/mt6358/core.hquoted
new file mode 100644 index 0000000..ce9e08a--- /dev/null +++ b/include/linux/mfd/mt6358/core.h@@ -0,0 +1,158 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2019 MediaTek Inc. + */ + +#ifndef __MFD_MT6358_CORE_H__ +#define __MFD_MT6358_CORE_H__ + +#define MT6358_REG_WIDTH 16 + +struct irq_top_t { + int hwirq_base; + unsigned int num_int_regs; + unsigned int num_int_bits; + unsigned int en_reg; + unsigned int en_reg_shift; + unsigned int sta_reg; + unsigned int sta_reg_shift; + unsigned int top_offset; +}; + +struct pmic_irq_data { + unsigned int num_top; + unsigned int num_pmic_irqs; + unsigned short top_int_status_reg; + bool *enable_hwirq; + bool *cache_hwirq; +}; + +enum mt6358_irq_top_status_shift { + MT6358_BUCK_TOP = 0, + MT6358_LDO_TOP, + MT6358_PSC_TOP, + MT6358_SCK_TOP, + MT6358_BM_TOP, + MT6358_HK_TOP, + MT6358_AUD_TOP, + MT6358_MISC_TOP, +}; + +enum mt6358_irq_numbers { + MT6358_IRQ_VPROC11_OC = 0, + MT6358_IRQ_VPROC12_OC, + MT6358_IRQ_VCORE_OC, + MT6358_IRQ_VGPU_OC, + MT6358_IRQ_VMODEM_OC, + MT6358_IRQ_VDRAM1_OC, + MT6358_IRQ_VS1_OC, + MT6358_IRQ_VS2_OC, + MT6358_IRQ_VPA_OC, + MT6358_IRQ_VCORE_PREOC, + MT6358_IRQ_VFE28_OC = 16, + MT6358_IRQ_VXO22_OC, + MT6358_IRQ_VRF18_OC, + MT6358_IRQ_VRF12_OC, + MT6358_IRQ_VEFUSE_OC, + MT6358_IRQ_VCN33_OC, + MT6358_IRQ_VCN28_OC, + MT6358_IRQ_VCN18_OC, + MT6358_IRQ_VCAMA1_OC, + MT6358_IRQ_VCAMA2_OC, + MT6358_IRQ_VCAMD_OC, + MT6358_IRQ_VCAMIO_OC, + MT6358_IRQ_VLDO28_OC, + MT6358_IRQ_VA12_OC, + MT6358_IRQ_VAUX18_OC, + MT6358_IRQ_VAUD28_OC, + MT6358_IRQ_VIO28_OC, + MT6358_IRQ_VIO18_OC, + MT6358_IRQ_VSRAM_PROC11_OC, + MT6358_IRQ_VSRAM_PROC12_OC, + MT6358_IRQ_VSRAM_OTHERS_OC, + MT6358_IRQ_VSRAM_GPU_OC, + MT6358_IRQ_VDRAM2_OC, + MT6358_IRQ_VMC_OC, + MT6358_IRQ_VMCH_OC, + MT6358_IRQ_VEMC_OC, + MT6358_IRQ_VSIM1_OC, + MT6358_IRQ_VSIM2_OC, + MT6358_IRQ_VIBR_OC, + MT6358_IRQ_VUSB_OC, + MT6358_IRQ_VBIF28_OC, + MT6358_IRQ_PWRKEY = 48, + MT6358_IRQ_HOMEKEY, + MT6358_IRQ_PWRKEY_R, + MT6358_IRQ_HOMEKEY_R, + MT6358_IRQ_NI_LBAT_INT, + MT6358_IRQ_CHRDET, + MT6358_IRQ_CHRDET_EDGE, + MT6358_IRQ_VCDT_HV_DET, + MT6358_IRQ_RTC = 64, + MT6358_IRQ_FG_BAT0_H = 80, + MT6358_IRQ_FG_BAT0_L, + MT6358_IRQ_FG_CUR_H, + MT6358_IRQ_FG_CUR_L, + MT6358_IRQ_FG_ZCV, + MT6358_IRQ_FG_BAT1_H, + MT6358_IRQ_FG_BAT1_L, + MT6358_IRQ_FG_N_CHARGE_L, + MT6358_IRQ_FG_IAVG_H, + MT6358_IRQ_FG_IAVG_L, + MT6358_IRQ_FG_TIME_H, + MT6358_IRQ_FG_DISCHARGE, + MT6358_IRQ_FG_CHARGE, + MT6358_IRQ_BATON_LV = 96, + MT6358_IRQ_BATON_HT, + MT6358_IRQ_BATON_BAT_IN, + MT6358_IRQ_BATON_BAT_OUT, + MT6358_IRQ_BIF, + MT6358_IRQ_BAT_H = 112, + MT6358_IRQ_BAT_L, + MT6358_IRQ_BAT2_H, + MT6358_IRQ_BAT2_L, + MT6358_IRQ_BAT_TEMP_H, + MT6358_IRQ_BAT_TEMP_L, + MT6358_IRQ_AUXADC_IMP, + MT6358_IRQ_NAG_C_DLTV, + MT6358_IRQ_AUDIO = 128, + MT6358_IRQ_ACCDET = 133, + MT6358_IRQ_ACCDET_EINT0, + MT6358_IRQ_ACCDET_EINT1, + MT6358_IRQ_SPI_CMD_ALERT = 144, + MT6358_IRQ_NR, +}; + +#define MT6358_IRQ_BUCK_BASE MT6358_IRQ_VPROC11_OC +#define MT6358_IRQ_LDO_BASE MT6358_IRQ_VFE28_OC +#define MT6358_IRQ_PSC_BASE MT6358_IRQ_PWRKEY +#define MT6358_IRQ_SCK_BASE MT6358_IRQ_RTC +#define MT6358_IRQ_BM_BASE MT6358_IRQ_FG_BAT0_H +#define MT6358_IRQ_HK_BASE MT6358_IRQ_BAT_H +#define MT6358_IRQ_AUD_BASE MT6358_IRQ_AUDIO +#define MT6358_IRQ_MISC_BASE MT6358_IRQ_SPI_CMD_ALERT + +#define MT6358_IRQ_BUCK_BITS (MT6358_IRQ_VCORE_PREOC -MT6358_IRQ_BUCK_BASE + 1)quoted
+#define MT6358_IRQ_LDO_BITS (MT6358_IRQ_VBIF28_OC - MT6358_IRQ_LDO_BASE+ 1)quoted
+#define MT6358_IRQ_PSC_BITS (MT6358_IRQ_VCDT_HV_DET -MT6358_IRQ_PSC_BASE + 1)quoted
+#define MT6358_IRQ_SCK_BITS (MT6358_IRQ_RTC - MT6358_IRQ_SCK_BASE + 1) +#define MT6358_IRQ_BM_BITS (MT6358_IRQ_BIF - MT6358_IRQ_BM_BASE + 1) +#define MT6358_IRQ_HK_BITS (MT6358_IRQ_NAG_C_DLTV - MT6358_IRQ_HK_BASE+ 1)quoted
+#define MT6358_IRQ_AUD_BITS (MT6358_IRQ_ACCDET_EINT1 -MT6358_IRQ_AUD_BASE + 1)quoted
+#define MT6358_IRQ_MISC_BITS \ + (MT6358_IRQ_SPI_CMD_ALERT - MT6358_IRQ_MISC_BASE + 1) + +#define MT6358_TOP_GEN(sp) \ +{ \ + .hwirq_base = MT6358_IRQ_##sp##_BASE, \ + .num_int_regs = \ + (MT6358_IRQ_##sp##_BITS / MT6358_REG_WIDTH) + 1, \ + .num_int_bits = MT6358_IRQ_##sp##_BITS, \ + .en_reg = MT6358_##sp##_TOP_INT_CON0, \ + .en_reg_shift = 0x6, \ + .sta_reg = MT6358_##sp##_TOP_INT_STATUS0, \ + .sta_reg_shift = 0x2, \ + .top_offset = MT6358_##sp##_TOP, \ +} + +#endif /* __MFD_MT6358_CORE_H__ */