126c7e05aSAndy Shevchenko // SPDX-License-Identifier: GPL-2.0 239d047c0SQipeng Zha /* 339d047c0SQipeng Zha * MFD core driver for Intel Broxton Whiskey Cove PMIC 439d047c0SQipeng Zha * 50ff590a3SAndy Shevchenko * Copyright (C) 2015-2017, 2022 Intel Corporation. All rights reserved. 639d047c0SQipeng Zha */ 739d047c0SQipeng Zha 839d047c0SQipeng Zha #include <linux/acpi.h> 9f801556aSAndy Shevchenko #include <linux/bits.h> 1039d047c0SQipeng Zha #include <linux/delay.h> 1151eeee8eSAndy Shevchenko #include <linux/err.h> 1239d047c0SQipeng Zha #include <linux/interrupt.h> 1339d047c0SQipeng Zha #include <linux/kernel.h> 1439d047c0SQipeng Zha #include <linux/mfd/core.h> 15f1e34ad8SAndy Shevchenko #include <linux/mfd/intel_soc_pmic.h> 160c227c51SAndy Shevchenko #include <linux/mfd/intel_soc_pmic_bxtwc.h> 1751eeee8eSAndy Shevchenko #include <linux/module.h> 1851eeee8eSAndy Shevchenko 194181bc8fSMika Westerberg #include <asm/intel_scu_ipc.h> 2039d047c0SQipeng Zha 2139d047c0SQipeng Zha /* PMIC device registers */ 22f801556aSAndy Shevchenko #define REG_ADDR_MASK GENMASK(15, 8) 2339d047c0SQipeng Zha #define REG_ADDR_SHIFT 8 24f801556aSAndy Shevchenko #define REG_OFFSET_MASK GENMASK(7, 0) 2539d047c0SQipeng Zha 2639d047c0SQipeng Zha /* Interrupt Status Registers */ 2739d047c0SQipeng Zha #define BXTWC_IRQLVL1 0x4E02 2839d047c0SQipeng Zha 299f8ddee1SAndy Shevchenko #define BXTWC_PWRBTNIRQ 0x4E03 3039d047c0SQipeng Zha #define BXTWC_THRM0IRQ 0x4E04 3139d047c0SQipeng Zha #define BXTWC_THRM1IRQ 0x4E05 3239d047c0SQipeng Zha #define BXTWC_THRM2IRQ 0x4E06 3339d047c0SQipeng Zha #define BXTWC_BCUIRQ 0x4E07 3439d047c0SQipeng Zha #define BXTWC_ADCIRQ 0x4E08 3539d047c0SQipeng Zha #define BXTWC_CHGR0IRQ 0x4E09 3639d047c0SQipeng Zha #define BXTWC_CHGR1IRQ 0x4E0A 3739d047c0SQipeng Zha #define BXTWC_GPIOIRQ0 0x4E0B 3839d047c0SQipeng Zha #define BXTWC_GPIOIRQ1 0x4E0C 3939d047c0SQipeng Zha #define BXTWC_CRITIRQ 0x4E0D 40957ae509SNilesh Bacchewar #define BXTWC_TMUIRQ 0x4FB6 4139d047c0SQipeng Zha 4239d047c0SQipeng Zha /* Interrupt MASK Registers */ 4339d047c0SQipeng Zha #define BXTWC_MIRQLVL1 0x4E0E 449c6235c8SBin Gao #define BXTWC_MIRQLVL1_MCHGR BIT(5) 459c6235c8SBin Gao 469f8ddee1SAndy Shevchenko #define BXTWC_MPWRBTNIRQ 0x4E0F 4739d047c0SQipeng Zha #define BXTWC_MTHRM0IRQ 0x4E12 4839d047c0SQipeng Zha #define BXTWC_MTHRM1IRQ 0x4E13 4939d047c0SQipeng Zha #define BXTWC_MTHRM2IRQ 0x4E14 5039d047c0SQipeng Zha #define BXTWC_MBCUIRQ 0x4E15 5139d047c0SQipeng Zha #define BXTWC_MADCIRQ 0x4E16 5239d047c0SQipeng Zha #define BXTWC_MCHGR0IRQ 0x4E17 5339d047c0SQipeng Zha #define BXTWC_MCHGR1IRQ 0x4E18 5439d047c0SQipeng Zha #define BXTWC_MGPIO0IRQ 0x4E19 5539d047c0SQipeng Zha #define BXTWC_MGPIO1IRQ 0x4E1A 5639d047c0SQipeng Zha #define BXTWC_MCRITIRQ 0x4E1B 57957ae509SNilesh Bacchewar #define BXTWC_MTMUIRQ 0x4FB7 5839d047c0SQipeng Zha 5939d047c0SQipeng Zha /* Whiskey Cove PMIC share same ACPI ID between different platforms */ 6039d047c0SQipeng Zha #define BROXTON_PMIC_WC_HRV 4 6139d047c0SQipeng Zha 624181bc8fSMika Westerberg #define PMC_PMIC_ACCESS 0xFF 634181bc8fSMika Westerberg #define PMC_PMIC_READ 0x0 644181bc8fSMika Westerberg #define PMC_PMIC_WRITE 0x1 654181bc8fSMika Westerberg 6639d047c0SQipeng Zha enum bxtwc_irqs { 6739d047c0SQipeng Zha BXTWC_PWRBTN_LVL1_IRQ = 0, 6839d047c0SQipeng Zha BXTWC_TMU_LVL1_IRQ, 6939d047c0SQipeng Zha BXTWC_THRM_LVL1_IRQ, 7039d047c0SQipeng Zha BXTWC_BCU_LVL1_IRQ, 7139d047c0SQipeng Zha BXTWC_ADC_LVL1_IRQ, 7239d047c0SQipeng Zha BXTWC_CHGR_LVL1_IRQ, 7339d047c0SQipeng Zha BXTWC_GPIO_LVL1_IRQ, 7439d047c0SQipeng Zha BXTWC_CRIT_LVL1_IRQ, 759f8ddee1SAndy Shevchenko }; 7639d047c0SQipeng Zha 779f8ddee1SAndy Shevchenko enum bxtwc_irqs_pwrbtn { 789f8ddee1SAndy Shevchenko BXTWC_PWRBTN_IRQ = 0, 799f8ddee1SAndy Shevchenko BXTWC_UIBTN_IRQ, 8039d047c0SQipeng Zha }; 8139d047c0SQipeng Zha 8257129044SKuppuswamy Sathyanarayanan enum bxtwc_irqs_bcu { 83c4949630SKuppuswamy Sathyanarayanan BXTWC_BCU_IRQ = 0, 8457129044SKuppuswamy Sathyanarayanan }; 8557129044SKuppuswamy Sathyanarayanan 8657129044SKuppuswamy Sathyanarayanan enum bxtwc_irqs_adc { 8757129044SKuppuswamy Sathyanarayanan BXTWC_ADC_IRQ = 0, 8857129044SKuppuswamy Sathyanarayanan }; 8957129044SKuppuswamy Sathyanarayanan 9057129044SKuppuswamy Sathyanarayanan enum bxtwc_irqs_chgr { 9157129044SKuppuswamy Sathyanarayanan BXTWC_USBC_IRQ = 0, 9239d047c0SQipeng Zha BXTWC_CHGR0_IRQ, 9339d047c0SQipeng Zha BXTWC_CHGR1_IRQ, 944533d855SKuppuswamy Sathyanarayanan }; 954533d855SKuppuswamy Sathyanarayanan 964533d855SKuppuswamy Sathyanarayanan enum bxtwc_irqs_tmu { 974533d855SKuppuswamy Sathyanarayanan BXTWC_TMU_IRQ = 0, 9839d047c0SQipeng Zha }; 9939d047c0SQipeng Zha 10057129044SKuppuswamy Sathyanarayanan enum bxtwc_irqs_crit { 10157129044SKuppuswamy Sathyanarayanan BXTWC_CRIT_IRQ = 0, 10257129044SKuppuswamy Sathyanarayanan }; 10357129044SKuppuswamy Sathyanarayanan 10439d047c0SQipeng Zha static const struct regmap_irq bxtwc_regmap_irqs[] = { 10539d047c0SQipeng Zha REGMAP_IRQ_REG(BXTWC_PWRBTN_LVL1_IRQ, 0, BIT(0)), 10639d047c0SQipeng Zha REGMAP_IRQ_REG(BXTWC_TMU_LVL1_IRQ, 0, BIT(1)), 10739d047c0SQipeng Zha REGMAP_IRQ_REG(BXTWC_THRM_LVL1_IRQ, 0, BIT(2)), 10839d047c0SQipeng Zha REGMAP_IRQ_REG(BXTWC_BCU_LVL1_IRQ, 0, BIT(3)), 10939d047c0SQipeng Zha REGMAP_IRQ_REG(BXTWC_ADC_LVL1_IRQ, 0, BIT(4)), 11039d047c0SQipeng Zha REGMAP_IRQ_REG(BXTWC_CHGR_LVL1_IRQ, 0, BIT(5)), 11139d047c0SQipeng Zha REGMAP_IRQ_REG(BXTWC_GPIO_LVL1_IRQ, 0, BIT(6)), 11239d047c0SQipeng Zha REGMAP_IRQ_REG(BXTWC_CRIT_LVL1_IRQ, 0, BIT(7)), 1139f8ddee1SAndy Shevchenko }; 1149f8ddee1SAndy Shevchenko 1159f8ddee1SAndy Shevchenko static const struct regmap_irq bxtwc_regmap_irqs_pwrbtn[] = { 116f801556aSAndy Shevchenko REGMAP_IRQ_REG(BXTWC_PWRBTN_IRQ, 0, BIT(0)), 11739d047c0SQipeng Zha }; 11839d047c0SQipeng Zha 11957129044SKuppuswamy Sathyanarayanan static const struct regmap_irq bxtwc_regmap_irqs_bcu[] = { 120f801556aSAndy Shevchenko REGMAP_IRQ_REG(BXTWC_BCU_IRQ, 0, GENMASK(4, 0)), 12157129044SKuppuswamy Sathyanarayanan }; 12257129044SKuppuswamy Sathyanarayanan 12357129044SKuppuswamy Sathyanarayanan static const struct regmap_irq bxtwc_regmap_irqs_adc[] = { 124f801556aSAndy Shevchenko REGMAP_IRQ_REG(BXTWC_ADC_IRQ, 0, GENMASK(7, 0)), 12557129044SKuppuswamy Sathyanarayanan }; 12657129044SKuppuswamy Sathyanarayanan 12757129044SKuppuswamy Sathyanarayanan static const struct regmap_irq bxtwc_regmap_irqs_chgr[] = { 128f801556aSAndy Shevchenko REGMAP_IRQ_REG(BXTWC_USBC_IRQ, 0, BIT(5)), 129f801556aSAndy Shevchenko REGMAP_IRQ_REG(BXTWC_CHGR0_IRQ, 0, GENMASK(4, 0)), 130f801556aSAndy Shevchenko REGMAP_IRQ_REG(BXTWC_CHGR1_IRQ, 1, GENMASK(4, 0)), 13139d047c0SQipeng Zha }; 13239d047c0SQipeng Zha 133957ae509SNilesh Bacchewar static const struct regmap_irq bxtwc_regmap_irqs_tmu[] = { 134f801556aSAndy Shevchenko REGMAP_IRQ_REG(BXTWC_TMU_IRQ, 0, GENMASK(2, 1)), 135957ae509SNilesh Bacchewar }; 136957ae509SNilesh Bacchewar 13757129044SKuppuswamy Sathyanarayanan static const struct regmap_irq bxtwc_regmap_irqs_crit[] = { 138f801556aSAndy Shevchenko REGMAP_IRQ_REG(BXTWC_CRIT_IRQ, 0, GENMASK(1, 0)), 13957129044SKuppuswamy Sathyanarayanan }; 14057129044SKuppuswamy Sathyanarayanan 141*a3cf8bafSJavier Carrasco static const struct regmap_irq_chip bxtwc_regmap_irq_chip = { 14239d047c0SQipeng Zha .name = "bxtwc_irq_chip", 14339d047c0SQipeng Zha .status_base = BXTWC_IRQLVL1, 14439d047c0SQipeng Zha .mask_base = BXTWC_MIRQLVL1, 14539d047c0SQipeng Zha .irqs = bxtwc_regmap_irqs, 14639d047c0SQipeng Zha .num_irqs = ARRAY_SIZE(bxtwc_regmap_irqs), 1479f8ddee1SAndy Shevchenko .num_regs = 1, 1489f8ddee1SAndy Shevchenko }; 1499f8ddee1SAndy Shevchenko 150*a3cf8bafSJavier Carrasco static const struct regmap_irq_chip bxtwc_regmap_irq_chip_pwrbtn = { 1519f8ddee1SAndy Shevchenko .name = "bxtwc_irq_chip_pwrbtn", 1529f8ddee1SAndy Shevchenko .status_base = BXTWC_PWRBTNIRQ, 1539f8ddee1SAndy Shevchenko .mask_base = BXTWC_MPWRBTNIRQ, 1549f8ddee1SAndy Shevchenko .irqs = bxtwc_regmap_irqs_pwrbtn, 1559f8ddee1SAndy Shevchenko .num_irqs = ARRAY_SIZE(bxtwc_regmap_irqs_pwrbtn), 1569f8ddee1SAndy Shevchenko .num_regs = 1, 15739d047c0SQipeng Zha }; 15839d047c0SQipeng Zha 159*a3cf8bafSJavier Carrasco static const struct regmap_irq_chip bxtwc_regmap_irq_chip_tmu = { 160957ae509SNilesh Bacchewar .name = "bxtwc_irq_chip_tmu", 161957ae509SNilesh Bacchewar .status_base = BXTWC_TMUIRQ, 162957ae509SNilesh Bacchewar .mask_base = BXTWC_MTMUIRQ, 163957ae509SNilesh Bacchewar .irqs = bxtwc_regmap_irqs_tmu, 164957ae509SNilesh Bacchewar .num_irqs = ARRAY_SIZE(bxtwc_regmap_irqs_tmu), 165957ae509SNilesh Bacchewar .num_regs = 1, 166957ae509SNilesh Bacchewar }; 167957ae509SNilesh Bacchewar 168*a3cf8bafSJavier Carrasco static const struct regmap_irq_chip bxtwc_regmap_irq_chip_bcu = { 16957129044SKuppuswamy Sathyanarayanan .name = "bxtwc_irq_chip_bcu", 17057129044SKuppuswamy Sathyanarayanan .status_base = BXTWC_BCUIRQ, 17157129044SKuppuswamy Sathyanarayanan .mask_base = BXTWC_MBCUIRQ, 17257129044SKuppuswamy Sathyanarayanan .irqs = bxtwc_regmap_irqs_bcu, 17357129044SKuppuswamy Sathyanarayanan .num_irqs = ARRAY_SIZE(bxtwc_regmap_irqs_bcu), 17457129044SKuppuswamy Sathyanarayanan .num_regs = 1, 17557129044SKuppuswamy Sathyanarayanan }; 17657129044SKuppuswamy Sathyanarayanan 177*a3cf8bafSJavier Carrasco static const struct regmap_irq_chip bxtwc_regmap_irq_chip_adc = { 17857129044SKuppuswamy Sathyanarayanan .name = "bxtwc_irq_chip_adc", 17957129044SKuppuswamy Sathyanarayanan .status_base = BXTWC_ADCIRQ, 18057129044SKuppuswamy Sathyanarayanan .mask_base = BXTWC_MADCIRQ, 18157129044SKuppuswamy Sathyanarayanan .irqs = bxtwc_regmap_irqs_adc, 18257129044SKuppuswamy Sathyanarayanan .num_irqs = ARRAY_SIZE(bxtwc_regmap_irqs_adc), 18357129044SKuppuswamy Sathyanarayanan .num_regs = 1, 18457129044SKuppuswamy Sathyanarayanan }; 18557129044SKuppuswamy Sathyanarayanan 186*a3cf8bafSJavier Carrasco static const struct regmap_irq_chip bxtwc_regmap_irq_chip_chgr = { 18757129044SKuppuswamy Sathyanarayanan .name = "bxtwc_irq_chip_chgr", 18857129044SKuppuswamy Sathyanarayanan .status_base = BXTWC_CHGR0IRQ, 18957129044SKuppuswamy Sathyanarayanan .mask_base = BXTWC_MCHGR0IRQ, 19057129044SKuppuswamy Sathyanarayanan .irqs = bxtwc_regmap_irqs_chgr, 19157129044SKuppuswamy Sathyanarayanan .num_irqs = ARRAY_SIZE(bxtwc_regmap_irqs_chgr), 19257129044SKuppuswamy Sathyanarayanan .num_regs = 2, 19357129044SKuppuswamy Sathyanarayanan }; 19457129044SKuppuswamy Sathyanarayanan 195*a3cf8bafSJavier Carrasco static const struct regmap_irq_chip bxtwc_regmap_irq_chip_crit = { 19657129044SKuppuswamy Sathyanarayanan .name = "bxtwc_irq_chip_crit", 19757129044SKuppuswamy Sathyanarayanan .status_base = BXTWC_CRITIRQ, 19857129044SKuppuswamy Sathyanarayanan .mask_base = BXTWC_MCRITIRQ, 19957129044SKuppuswamy Sathyanarayanan .irqs = bxtwc_regmap_irqs_crit, 20057129044SKuppuswamy Sathyanarayanan .num_irqs = ARRAY_SIZE(bxtwc_regmap_irqs_crit), 20157129044SKuppuswamy Sathyanarayanan .num_regs = 1, 20257129044SKuppuswamy Sathyanarayanan }; 20357129044SKuppuswamy Sathyanarayanan 204bf4cceb6SRikard Falkeborn static const struct resource gpio_resources[] = { 205a1d28c59SKuppuswamy Sathyanarayanan DEFINE_RES_IRQ_NAMED(BXTWC_GPIO_LVL1_IRQ, "GPIO"), 20639d047c0SQipeng Zha }; 20739d047c0SQipeng Zha 208bf4cceb6SRikard Falkeborn static const struct resource adc_resources[] = { 20939d047c0SQipeng Zha DEFINE_RES_IRQ_NAMED(BXTWC_ADC_IRQ, "ADC"), 21039d047c0SQipeng Zha }; 21139d047c0SQipeng Zha 212bf4cceb6SRikard Falkeborn static const struct resource usbc_resources[] = { 21396007020SHeikki Krogerus DEFINE_RES_IRQ(BXTWC_USBC_IRQ), 2149c6235c8SBin Gao }; 2159c6235c8SBin Gao 216bf4cceb6SRikard Falkeborn static const struct resource charger_resources[] = { 21739d047c0SQipeng Zha DEFINE_RES_IRQ_NAMED(BXTWC_CHGR0_IRQ, "CHARGER"), 21839d047c0SQipeng Zha DEFINE_RES_IRQ_NAMED(BXTWC_CHGR1_IRQ, "CHARGER1"), 21939d047c0SQipeng Zha }; 22039d047c0SQipeng Zha 221bf4cceb6SRikard Falkeborn static const struct resource thermal_resources[] = { 222c4949630SKuppuswamy Sathyanarayanan DEFINE_RES_IRQ(BXTWC_THRM_LVL1_IRQ), 22339d047c0SQipeng Zha }; 22439d047c0SQipeng Zha 225bf4cceb6SRikard Falkeborn static const struct resource bcu_resources[] = { 22639d047c0SQipeng Zha DEFINE_RES_IRQ_NAMED(BXTWC_BCU_IRQ, "BCU"), 22739d047c0SQipeng Zha }; 22839d047c0SQipeng Zha 229bf4cceb6SRikard Falkeborn static const struct resource tmu_resources[] = { 230957ae509SNilesh Bacchewar DEFINE_RES_IRQ_NAMED(BXTWC_TMU_IRQ, "TMU"), 231957ae509SNilesh Bacchewar }; 232957ae509SNilesh Bacchewar 23339d047c0SQipeng Zha static struct mfd_cell bxt_wc_dev[] = { 23439d047c0SQipeng Zha { 23539d047c0SQipeng Zha .name = "bxt_wcove_gpadc", 23639d047c0SQipeng Zha .num_resources = ARRAY_SIZE(adc_resources), 23739d047c0SQipeng Zha .resources = adc_resources, 23839d047c0SQipeng Zha }, 23939d047c0SQipeng Zha { 24039d047c0SQipeng Zha .name = "bxt_wcove_thermal", 24139d047c0SQipeng Zha .num_resources = ARRAY_SIZE(thermal_resources), 24239d047c0SQipeng Zha .resources = thermal_resources, 24339d047c0SQipeng Zha }, 24439d047c0SQipeng Zha { 2459c6235c8SBin Gao .name = "bxt_wcove_usbc", 2469c6235c8SBin Gao .num_resources = ARRAY_SIZE(usbc_resources), 2479c6235c8SBin Gao .resources = usbc_resources, 2489c6235c8SBin Gao }, 2499c6235c8SBin Gao { 25039d047c0SQipeng Zha .name = "bxt_wcove_ext_charger", 25139d047c0SQipeng Zha .num_resources = ARRAY_SIZE(charger_resources), 25239d047c0SQipeng Zha .resources = charger_resources, 25339d047c0SQipeng Zha }, 25439d047c0SQipeng Zha { 25539d047c0SQipeng Zha .name = "bxt_wcove_bcu", 25639d047c0SQipeng Zha .num_resources = ARRAY_SIZE(bcu_resources), 25739d047c0SQipeng Zha .resources = bcu_resources, 25839d047c0SQipeng Zha }, 25939d047c0SQipeng Zha { 260957ae509SNilesh Bacchewar .name = "bxt_wcove_tmu", 261957ae509SNilesh Bacchewar .num_resources = ARRAY_SIZE(tmu_resources), 262957ae509SNilesh Bacchewar .resources = tmu_resources, 263957ae509SNilesh Bacchewar }, 264957ae509SNilesh Bacchewar 265957ae509SNilesh Bacchewar { 26639d047c0SQipeng Zha .name = "bxt_wcove_gpio", 26739d047c0SQipeng Zha .num_resources = ARRAY_SIZE(gpio_resources), 26839d047c0SQipeng Zha .resources = gpio_resources, 26939d047c0SQipeng Zha }, 27039d047c0SQipeng Zha { 27139d047c0SQipeng Zha .name = "bxt_wcove_region", 27239d047c0SQipeng Zha }, 27339d047c0SQipeng Zha }; 27439d047c0SQipeng Zha 27539d047c0SQipeng Zha static int regmap_ipc_byte_reg_read(void *context, unsigned int reg, 27639d047c0SQipeng Zha unsigned int *val) 27739d047c0SQipeng Zha { 27839d047c0SQipeng Zha int ret; 27939d047c0SQipeng Zha int i2c_addr; 28039d047c0SQipeng Zha u8 ipc_in[2]; 28139d047c0SQipeng Zha u8 ipc_out[4]; 28239d047c0SQipeng Zha struct intel_soc_pmic *pmic = context; 28339d047c0SQipeng Zha 284b4ccc4d2SKuppuswamy Sathyanarayanan if (!pmic) 285b4ccc4d2SKuppuswamy Sathyanarayanan return -EINVAL; 286b4ccc4d2SKuppuswamy Sathyanarayanan 28739d047c0SQipeng Zha if (reg & REG_ADDR_MASK) 28839d047c0SQipeng Zha i2c_addr = (reg & REG_ADDR_MASK) >> REG_ADDR_SHIFT; 289b4ccc4d2SKuppuswamy Sathyanarayanan else 29039d047c0SQipeng Zha i2c_addr = BXTWC_DEVICE1_ADDR; 291b4ccc4d2SKuppuswamy Sathyanarayanan 29239d047c0SQipeng Zha reg &= REG_OFFSET_MASK; 29339d047c0SQipeng Zha 29439d047c0SQipeng Zha ipc_in[0] = reg; 29539d047c0SQipeng Zha ipc_in[1] = i2c_addr; 2964181bc8fSMika Westerberg ret = intel_scu_ipc_dev_command(pmic->scu, PMC_PMIC_ACCESS, 2974181bc8fSMika Westerberg PMC_PMIC_READ, ipc_in, sizeof(ipc_in), 2984181bc8fSMika Westerberg ipc_out, sizeof(ipc_out)); 2994181bc8fSMika Westerberg if (ret) 30039d047c0SQipeng Zha return ret; 3014181bc8fSMika Westerberg 30239d047c0SQipeng Zha *val = ipc_out[0]; 30339d047c0SQipeng Zha 30439d047c0SQipeng Zha return 0; 30539d047c0SQipeng Zha } 30639d047c0SQipeng Zha 30739d047c0SQipeng Zha static int regmap_ipc_byte_reg_write(void *context, unsigned int reg, 30839d047c0SQipeng Zha unsigned int val) 30939d047c0SQipeng Zha { 31039d047c0SQipeng Zha int i2c_addr; 31139d047c0SQipeng Zha u8 ipc_in[3]; 31239d047c0SQipeng Zha struct intel_soc_pmic *pmic = context; 31339d047c0SQipeng Zha 314b4ccc4d2SKuppuswamy Sathyanarayanan if (!pmic) 315b4ccc4d2SKuppuswamy Sathyanarayanan return -EINVAL; 316b4ccc4d2SKuppuswamy Sathyanarayanan 31739d047c0SQipeng Zha if (reg & REG_ADDR_MASK) 31839d047c0SQipeng Zha i2c_addr = (reg & REG_ADDR_MASK) >> REG_ADDR_SHIFT; 319b4ccc4d2SKuppuswamy Sathyanarayanan else 32039d047c0SQipeng Zha i2c_addr = BXTWC_DEVICE1_ADDR; 321b4ccc4d2SKuppuswamy Sathyanarayanan 32239d047c0SQipeng Zha reg &= REG_OFFSET_MASK; 32339d047c0SQipeng Zha 32439d047c0SQipeng Zha ipc_in[0] = reg; 32539d047c0SQipeng Zha ipc_in[1] = i2c_addr; 32639d047c0SQipeng Zha ipc_in[2] = val; 3274181bc8fSMika Westerberg return intel_scu_ipc_dev_command(pmic->scu, PMC_PMIC_ACCESS, 3284181bc8fSMika Westerberg PMC_PMIC_WRITE, ipc_in, sizeof(ipc_in), 3294181bc8fSMika Westerberg NULL, 0); 33039d047c0SQipeng Zha } 33139d047c0SQipeng Zha 33239d047c0SQipeng Zha /* sysfs interfaces to r/w PMIC registers, required by initial script */ 33339d047c0SQipeng Zha static unsigned long bxtwc_reg_addr; 3345089e34fSZhen Lei static ssize_t addr_show(struct device *dev, 33539d047c0SQipeng Zha struct device_attribute *attr, char *buf) 33639d047c0SQipeng Zha { 33786da8be3SAndy Shevchenko return sysfs_emit(buf, "0x%lx\n", bxtwc_reg_addr); 33839d047c0SQipeng Zha } 33939d047c0SQipeng Zha 3405089e34fSZhen Lei static ssize_t addr_store(struct device *dev, 34139d047c0SQipeng Zha struct device_attribute *attr, const char *buf, size_t count) 34239d047c0SQipeng Zha { 34351899522SAndy Shevchenko int ret; 34451899522SAndy Shevchenko 34551899522SAndy Shevchenko ret = kstrtoul(buf, 0, &bxtwc_reg_addr); 34651899522SAndy Shevchenko if (ret) 34751899522SAndy Shevchenko return ret; 34851899522SAndy Shevchenko 3497c06d478SAndy Shevchenko return count; 35039d047c0SQipeng Zha } 35139d047c0SQipeng Zha 3525089e34fSZhen Lei static ssize_t val_show(struct device *dev, 35339d047c0SQipeng Zha struct device_attribute *attr, char *buf) 35439d047c0SQipeng Zha { 35539d047c0SQipeng Zha int ret; 35639d047c0SQipeng Zha unsigned int val; 35739d047c0SQipeng Zha struct intel_soc_pmic *pmic = dev_get_drvdata(dev); 35839d047c0SQipeng Zha 35939d047c0SQipeng Zha ret = regmap_read(pmic->regmap, bxtwc_reg_addr, &val); 36051899522SAndy Shevchenko if (ret) { 36139d047c0SQipeng Zha dev_err(dev, "Failed to read 0x%lx\n", bxtwc_reg_addr); 36251899522SAndy Shevchenko return ret; 36339d047c0SQipeng Zha } 36439d047c0SQipeng Zha 36586da8be3SAndy Shevchenko return sysfs_emit(buf, "0x%02x\n", val); 36639d047c0SQipeng Zha } 36739d047c0SQipeng Zha 3685089e34fSZhen Lei static ssize_t val_store(struct device *dev, 36939d047c0SQipeng Zha struct device_attribute *attr, const char *buf, size_t count) 37039d047c0SQipeng Zha { 37139d047c0SQipeng Zha int ret; 37239d047c0SQipeng Zha unsigned int val; 37339d047c0SQipeng Zha struct intel_soc_pmic *pmic = dev_get_drvdata(dev); 37439d047c0SQipeng Zha 375f3a654c5SDan Carpenter ret = kstrtouint(buf, 0, &val); 376f3a654c5SDan Carpenter if (ret) 377f3a654c5SDan Carpenter return ret; 37839d047c0SQipeng Zha 37939d047c0SQipeng Zha ret = regmap_write(pmic->regmap, bxtwc_reg_addr, val); 38039d047c0SQipeng Zha if (ret) { 38139d047c0SQipeng Zha dev_err(dev, "Failed to write value 0x%02x to address 0x%lx", 38239d047c0SQipeng Zha val, bxtwc_reg_addr); 38351899522SAndy Shevchenko return ret; 38439d047c0SQipeng Zha } 38539d047c0SQipeng Zha return count; 38639d047c0SQipeng Zha } 38739d047c0SQipeng Zha 3885089e34fSZhen Lei static DEVICE_ATTR_ADMIN_RW(addr); 3895089e34fSZhen Lei static DEVICE_ATTR_ADMIN_RW(val); 39039d047c0SQipeng Zha static struct attribute *bxtwc_attrs[] = { 39139d047c0SQipeng Zha &dev_attr_addr.attr, 39239d047c0SQipeng Zha &dev_attr_val.attr, 39339d047c0SQipeng Zha NULL 39439d047c0SQipeng Zha }; 39539d047c0SQipeng Zha 39639d047c0SQipeng Zha static const struct attribute_group bxtwc_group = { 39739d047c0SQipeng Zha .attrs = bxtwc_attrs, 39839d047c0SQipeng Zha }; 39939d047c0SQipeng Zha 400929a4d28SAndy Shevchenko static const struct attribute_group *bxtwc_groups[] = { 401929a4d28SAndy Shevchenko &bxtwc_group, 402929a4d28SAndy Shevchenko NULL 403929a4d28SAndy Shevchenko }; 404929a4d28SAndy Shevchenko 40539d047c0SQipeng Zha static const struct regmap_config bxtwc_regmap_config = { 40639d047c0SQipeng Zha .reg_bits = 16, 40739d047c0SQipeng Zha .val_bits = 8, 40839d047c0SQipeng Zha .reg_write = regmap_ipc_byte_reg_write, 40939d047c0SQipeng Zha .reg_read = regmap_ipc_byte_reg_read, 41039d047c0SQipeng Zha }; 41139d047c0SQipeng Zha 41257129044SKuppuswamy Sathyanarayanan static int bxtwc_add_chained_irq_chip(struct intel_soc_pmic *pmic, 41357129044SKuppuswamy Sathyanarayanan struct regmap_irq_chip_data *pdata, 41457129044SKuppuswamy Sathyanarayanan int pirq, int irq_flags, 41557129044SKuppuswamy Sathyanarayanan const struct regmap_irq_chip *chip, 41657129044SKuppuswamy Sathyanarayanan struct regmap_irq_chip_data **data) 41757129044SKuppuswamy Sathyanarayanan { 41857129044SKuppuswamy Sathyanarayanan int irq; 41957129044SKuppuswamy Sathyanarayanan 42057129044SKuppuswamy Sathyanarayanan irq = regmap_irq_get_virq(pdata, pirq); 421d30e2c30SAndy Shevchenko if (irq < 0) 422d30e2c30SAndy Shevchenko return dev_err_probe(pmic->dev, irq, "Failed to get parent vIRQ(%d) for chip %s\n", 423d30e2c30SAndy Shevchenko pirq, chip->name); 42457129044SKuppuswamy Sathyanarayanan 42557129044SKuppuswamy Sathyanarayanan return devm_regmap_add_irq_chip(pmic->dev, pmic->regmap, irq, irq_flags, 42657129044SKuppuswamy Sathyanarayanan 0, chip, data); 42757129044SKuppuswamy Sathyanarayanan } 42857129044SKuppuswamy Sathyanarayanan 42939d047c0SQipeng Zha static int bxtwc_probe(struct platform_device *pdev) 43039d047c0SQipeng Zha { 431d30e2c30SAndy Shevchenko struct device *dev = &pdev->dev; 43239d047c0SQipeng Zha int ret; 43339d047c0SQipeng Zha acpi_status status; 43439d047c0SQipeng Zha unsigned long long hrv; 43539d047c0SQipeng Zha struct intel_soc_pmic *pmic; 43639d047c0SQipeng Zha 437ba3ea04aSAndy Shevchenko status = acpi_evaluate_integer(ACPI_HANDLE(dev), "_HRV", NULL, &hrv); 438d30e2c30SAndy Shevchenko if (ACPI_FAILURE(status)) 439d30e2c30SAndy Shevchenko return dev_err_probe(dev, -ENODEV, "Failed to get PMIC hardware revision\n"); 440d30e2c30SAndy Shevchenko if (hrv != BROXTON_PMIC_WC_HRV) 441d30e2c30SAndy Shevchenko return dev_err_probe(dev, -ENODEV, "Invalid PMIC hardware revision: %llu\n", hrv); 44239d047c0SQipeng Zha 443ba3ea04aSAndy Shevchenko pmic = devm_kzalloc(dev, sizeof(*pmic), GFP_KERNEL); 44439d047c0SQipeng Zha if (!pmic) 44539d047c0SQipeng Zha return -ENOMEM; 44639d047c0SQipeng Zha 44739d047c0SQipeng Zha ret = platform_get_irq(pdev, 0); 448802d9bd4SStephen Boyd if (ret < 0) 44939d047c0SQipeng Zha return ret; 45039d047c0SQipeng Zha pmic->irq = ret; 45139d047c0SQipeng Zha 4522790a70cSAndy Shevchenko platform_set_drvdata(pdev, pmic); 453ba3ea04aSAndy Shevchenko pmic->dev = dev; 45439d047c0SQipeng Zha 455ba3ea04aSAndy Shevchenko pmic->scu = devm_intel_scu_ipc_dev_get(dev); 4564181bc8fSMika Westerberg if (!pmic->scu) 4574181bc8fSMika Westerberg return -EPROBE_DEFER; 4584181bc8fSMika Westerberg 459ba3ea04aSAndy Shevchenko pmic->regmap = devm_regmap_init(dev, NULL, pmic, &bxtwc_regmap_config); 460d30e2c30SAndy Shevchenko if (IS_ERR(pmic->regmap)) 461d30e2c30SAndy Shevchenko return dev_err_probe(dev, PTR_ERR(pmic->regmap), "Failed to initialise regmap\n"); 46239d047c0SQipeng Zha 463ba3ea04aSAndy Shevchenko ret = devm_regmap_add_irq_chip(dev, pmic->regmap, pmic->irq, 46439d047c0SQipeng Zha IRQF_ONESHOT | IRQF_SHARED, 46539d047c0SQipeng Zha 0, &bxtwc_regmap_irq_chip, 46639d047c0SQipeng Zha &pmic->irq_chip_data); 467d30e2c30SAndy Shevchenko if (ret) 468d30e2c30SAndy Shevchenko return dev_err_probe(dev, ret, "Failed to add IRQ chip\n"); 46939d047c0SQipeng Zha 47057129044SKuppuswamy Sathyanarayanan ret = bxtwc_add_chained_irq_chip(pmic, pmic->irq_chip_data, 4719f8ddee1SAndy Shevchenko BXTWC_PWRBTN_LVL1_IRQ, 4729f8ddee1SAndy Shevchenko IRQF_ONESHOT, 4739f8ddee1SAndy Shevchenko &bxtwc_regmap_irq_chip_pwrbtn, 4749f8ddee1SAndy Shevchenko &pmic->irq_chip_data_pwrbtn); 475d30e2c30SAndy Shevchenko if (ret) 476d30e2c30SAndy Shevchenko return dev_err_probe(dev, ret, "Failed to add PWRBTN IRQ chip\n"); 4779f8ddee1SAndy Shevchenko 4789f8ddee1SAndy Shevchenko ret = bxtwc_add_chained_irq_chip(pmic, pmic->irq_chip_data, 47957129044SKuppuswamy Sathyanarayanan BXTWC_TMU_LVL1_IRQ, 48057129044SKuppuswamy Sathyanarayanan IRQF_ONESHOT, 48157129044SKuppuswamy Sathyanarayanan &bxtwc_regmap_irq_chip_tmu, 482957ae509SNilesh Bacchewar &pmic->irq_chip_data_tmu); 483d30e2c30SAndy Shevchenko if (ret) 484d30e2c30SAndy Shevchenko return dev_err_probe(dev, ret, "Failed to add TMU IRQ chip\n"); 485957ae509SNilesh Bacchewar 48657129044SKuppuswamy Sathyanarayanan /* Add chained IRQ handler for BCU IRQs */ 48757129044SKuppuswamy Sathyanarayanan ret = bxtwc_add_chained_irq_chip(pmic, pmic->irq_chip_data, 48857129044SKuppuswamy Sathyanarayanan BXTWC_BCU_LVL1_IRQ, 48957129044SKuppuswamy Sathyanarayanan IRQF_ONESHOT, 49057129044SKuppuswamy Sathyanarayanan &bxtwc_regmap_irq_chip_bcu, 49157129044SKuppuswamy Sathyanarayanan &pmic->irq_chip_data_bcu); 492d30e2c30SAndy Shevchenko if (ret) 493d30e2c30SAndy Shevchenko return dev_err_probe(dev, ret, "Failed to add BUC IRQ chip\n"); 49457129044SKuppuswamy Sathyanarayanan 49557129044SKuppuswamy Sathyanarayanan /* Add chained IRQ handler for ADC IRQs */ 49657129044SKuppuswamy Sathyanarayanan ret = bxtwc_add_chained_irq_chip(pmic, pmic->irq_chip_data, 49757129044SKuppuswamy Sathyanarayanan BXTWC_ADC_LVL1_IRQ, 49857129044SKuppuswamy Sathyanarayanan IRQF_ONESHOT, 49957129044SKuppuswamy Sathyanarayanan &bxtwc_regmap_irq_chip_adc, 50057129044SKuppuswamy Sathyanarayanan &pmic->irq_chip_data_adc); 501d30e2c30SAndy Shevchenko if (ret) 502d30e2c30SAndy Shevchenko return dev_err_probe(dev, ret, "Failed to add ADC IRQ chip\n"); 50357129044SKuppuswamy Sathyanarayanan 50457129044SKuppuswamy Sathyanarayanan /* Add chained IRQ handler for CHGR IRQs */ 50557129044SKuppuswamy Sathyanarayanan ret = bxtwc_add_chained_irq_chip(pmic, pmic->irq_chip_data, 50657129044SKuppuswamy Sathyanarayanan BXTWC_CHGR_LVL1_IRQ, 50757129044SKuppuswamy Sathyanarayanan IRQF_ONESHOT, 50857129044SKuppuswamy Sathyanarayanan &bxtwc_regmap_irq_chip_chgr, 50957129044SKuppuswamy Sathyanarayanan &pmic->irq_chip_data_chgr); 510d30e2c30SAndy Shevchenko if (ret) 511d30e2c30SAndy Shevchenko return dev_err_probe(dev, ret, "Failed to add CHGR IRQ chip\n"); 51257129044SKuppuswamy Sathyanarayanan 51357129044SKuppuswamy Sathyanarayanan /* Add chained IRQ handler for CRIT IRQs */ 51457129044SKuppuswamy Sathyanarayanan ret = bxtwc_add_chained_irq_chip(pmic, pmic->irq_chip_data, 51557129044SKuppuswamy Sathyanarayanan BXTWC_CRIT_LVL1_IRQ, 51657129044SKuppuswamy Sathyanarayanan IRQF_ONESHOT, 51757129044SKuppuswamy Sathyanarayanan &bxtwc_regmap_irq_chip_crit, 51857129044SKuppuswamy Sathyanarayanan &pmic->irq_chip_data_crit); 519d30e2c30SAndy Shevchenko if (ret) 520d30e2c30SAndy Shevchenko return dev_err_probe(dev, ret, "Failed to add CRIT IRQ chip\n"); 52157129044SKuppuswamy Sathyanarayanan 522ba3ea04aSAndy Shevchenko ret = devm_mfd_add_devices(dev, PLATFORM_DEVID_NONE, bxt_wc_dev, ARRAY_SIZE(bxt_wc_dev), 523ba3ea04aSAndy Shevchenko NULL, 0, NULL); 524d30e2c30SAndy Shevchenko if (ret) 525d30e2c30SAndy Shevchenko return dev_err_probe(dev, ret, "Failed to add devices\n"); 52639d047c0SQipeng Zha 5279c6235c8SBin Gao /* 5280ff590a3SAndy Shevchenko * There is a known H/W bug. Upon reset, BIT 5 of register 5299c6235c8SBin Gao * BXTWC_CHGR_LVL1_IRQ is 0 which is the expected value. However, 5309c6235c8SBin Gao * later it's set to 1(masked) automatically by hardware. So we 5310ff590a3SAndy Shevchenko * place the software workaround here to unmask it again in order 5320ff590a3SAndy Shevchenko * to re-enable the charger interrupt. 5339c6235c8SBin Gao */ 534929a4d28SAndy Shevchenko regmap_update_bits(pmic->regmap, BXTWC_MIRQLVL1, BXTWC_MIRQLVL1_MCHGR, 0); 53539d047c0SQipeng Zha 53639d047c0SQipeng Zha return 0; 53739d047c0SQipeng Zha } 53839d047c0SQipeng Zha 53939d047c0SQipeng Zha static void bxtwc_shutdown(struct platform_device *pdev) 54039d047c0SQipeng Zha { 5412790a70cSAndy Shevchenko struct intel_soc_pmic *pmic = platform_get_drvdata(pdev); 54239d047c0SQipeng Zha 54339d047c0SQipeng Zha disable_irq(pmic->irq); 54439d047c0SQipeng Zha } 54539d047c0SQipeng Zha 54639d047c0SQipeng Zha static int bxtwc_suspend(struct device *dev) 54739d047c0SQipeng Zha { 54839d047c0SQipeng Zha struct intel_soc_pmic *pmic = dev_get_drvdata(dev); 54939d047c0SQipeng Zha 55039d047c0SQipeng Zha disable_irq(pmic->irq); 55139d047c0SQipeng Zha 55239d047c0SQipeng Zha return 0; 55339d047c0SQipeng Zha } 55439d047c0SQipeng Zha 55539d047c0SQipeng Zha static int bxtwc_resume(struct device *dev) 55639d047c0SQipeng Zha { 55739d047c0SQipeng Zha struct intel_soc_pmic *pmic = dev_get_drvdata(dev); 55839d047c0SQipeng Zha 55939d047c0SQipeng Zha enable_irq(pmic->irq); 56039d047c0SQipeng Zha return 0; 56139d047c0SQipeng Zha } 56205879b12SAndy Shevchenko 56305879b12SAndy Shevchenko static DEFINE_SIMPLE_DEV_PM_OPS(bxtwc_pm_ops, bxtwc_suspend, bxtwc_resume); 56439d047c0SQipeng Zha 56539d047c0SQipeng Zha static const struct acpi_device_id bxtwc_acpi_ids[] = { 56639d047c0SQipeng Zha { "INT34D3", }, 56739d047c0SQipeng Zha { } 56839d047c0SQipeng Zha }; 569f57576e7SWei Yongjun MODULE_DEVICE_TABLE(acpi, bxtwc_acpi_ids); 57039d047c0SQipeng Zha 57139d047c0SQipeng Zha static struct platform_driver bxtwc_driver = { 57239d047c0SQipeng Zha .probe = bxtwc_probe, 57339d047c0SQipeng Zha .shutdown = bxtwc_shutdown, 57439d047c0SQipeng Zha .driver = { 57539d047c0SQipeng Zha .name = "BXTWC PMIC", 57605879b12SAndy Shevchenko .pm = pm_sleep_ptr(&bxtwc_pm_ops), 577cd58c840SAndy Shevchenko .acpi_match_table = bxtwc_acpi_ids, 578929a4d28SAndy Shevchenko .dev_groups = bxtwc_groups, 57939d047c0SQipeng Zha }, 58039d047c0SQipeng Zha }; 58139d047c0SQipeng Zha 58239d047c0SQipeng Zha module_platform_driver(bxtwc_driver); 58339d047c0SQipeng Zha 5845fed47abSJeff Johnson MODULE_DESCRIPTION("Intel Broxton Whiskey Cove PMIC MFD core driver"); 58539d047c0SQipeng Zha MODULE_LICENSE("GPL v2"); 58639d047c0SQipeng Zha MODULE_AUTHOR("Qipeng Zha <qipeng.zha@intel.com>"); 587