126c7e05aSAndy Shevchenko // SPDX-License-Identifier: GPL-2.0 239d047c0SQipeng Zha /* 339d047c0SQipeng Zha * MFD core driver for Intel Broxton Whiskey Cove PMIC 439d047c0SQipeng Zha * 539d047c0SQipeng Zha * Copyright (C) 2015 Intel Corporation. All rights reserved. 639d047c0SQipeng Zha */ 739d047c0SQipeng Zha 839d047c0SQipeng Zha #include <linux/acpi.h> 939d047c0SQipeng Zha #include <linux/delay.h> 1051eeee8eSAndy Shevchenko #include <linux/err.h> 1139d047c0SQipeng Zha #include <linux/interrupt.h> 1239d047c0SQipeng Zha #include <linux/kernel.h> 1339d047c0SQipeng Zha #include <linux/mfd/core.h> 14f1e34ad8SAndy Shevchenko #include <linux/mfd/intel_soc_pmic.h> 150c227c51SAndy Shevchenko #include <linux/mfd/intel_soc_pmic_bxtwc.h> 1651eeee8eSAndy Shevchenko #include <linux/module.h> 1751eeee8eSAndy Shevchenko 184181bc8fSMika Westerberg #include <asm/intel_scu_ipc.h> 1939d047c0SQipeng Zha 2039d047c0SQipeng Zha /* PMIC device registers */ 2139d047c0SQipeng Zha #define REG_ADDR_MASK 0xFF00 2239d047c0SQipeng Zha #define REG_ADDR_SHIFT 8 2339d047c0SQipeng Zha #define REG_OFFSET_MASK 0xFF 2439d047c0SQipeng Zha 2539d047c0SQipeng Zha /* Interrupt Status Registers */ 2639d047c0SQipeng Zha #define BXTWC_IRQLVL1 0x4E02 2739d047c0SQipeng Zha 289f8ddee1SAndy Shevchenko #define BXTWC_PWRBTNIRQ 0x4E03 2939d047c0SQipeng Zha #define BXTWC_THRM0IRQ 0x4E04 3039d047c0SQipeng Zha #define BXTWC_THRM1IRQ 0x4E05 3139d047c0SQipeng Zha #define BXTWC_THRM2IRQ 0x4E06 3239d047c0SQipeng Zha #define BXTWC_BCUIRQ 0x4E07 3339d047c0SQipeng Zha #define BXTWC_ADCIRQ 0x4E08 3439d047c0SQipeng Zha #define BXTWC_CHGR0IRQ 0x4E09 3539d047c0SQipeng Zha #define BXTWC_CHGR1IRQ 0x4E0A 3639d047c0SQipeng Zha #define BXTWC_GPIOIRQ0 0x4E0B 3739d047c0SQipeng Zha #define BXTWC_GPIOIRQ1 0x4E0C 3839d047c0SQipeng Zha #define BXTWC_CRITIRQ 0x4E0D 39957ae509SNilesh Bacchewar #define BXTWC_TMUIRQ 0x4FB6 4039d047c0SQipeng Zha 4139d047c0SQipeng Zha /* Interrupt MASK Registers */ 4239d047c0SQipeng Zha #define BXTWC_MIRQLVL1 0x4E0E 439c6235c8SBin Gao #define BXTWC_MIRQLVL1_MCHGR BIT(5) 449c6235c8SBin Gao 459f8ddee1SAndy Shevchenko #define BXTWC_MPWRBTNIRQ 0x4E0F 4639d047c0SQipeng Zha #define BXTWC_MTHRM0IRQ 0x4E12 4739d047c0SQipeng Zha #define BXTWC_MTHRM1IRQ 0x4E13 4839d047c0SQipeng Zha #define BXTWC_MTHRM2IRQ 0x4E14 4939d047c0SQipeng Zha #define BXTWC_MBCUIRQ 0x4E15 5039d047c0SQipeng Zha #define BXTWC_MADCIRQ 0x4E16 5139d047c0SQipeng Zha #define BXTWC_MCHGR0IRQ 0x4E17 5239d047c0SQipeng Zha #define BXTWC_MCHGR1IRQ 0x4E18 5339d047c0SQipeng Zha #define BXTWC_MGPIO0IRQ 0x4E19 5439d047c0SQipeng Zha #define BXTWC_MGPIO1IRQ 0x4E1A 5539d047c0SQipeng Zha #define BXTWC_MCRITIRQ 0x4E1B 56957ae509SNilesh Bacchewar #define BXTWC_MTMUIRQ 0x4FB7 5739d047c0SQipeng Zha 5839d047c0SQipeng Zha /* Whiskey Cove PMIC share same ACPI ID between different platforms */ 5939d047c0SQipeng Zha #define BROXTON_PMIC_WC_HRV 4 6039d047c0SQipeng Zha 614181bc8fSMika Westerberg #define PMC_PMIC_ACCESS 0xFF 624181bc8fSMika Westerberg #define PMC_PMIC_READ 0x0 634181bc8fSMika Westerberg #define PMC_PMIC_WRITE 0x1 644181bc8fSMika Westerberg 6539d047c0SQipeng Zha enum bxtwc_irqs { 6639d047c0SQipeng Zha BXTWC_PWRBTN_LVL1_IRQ = 0, 6739d047c0SQipeng Zha BXTWC_TMU_LVL1_IRQ, 6839d047c0SQipeng Zha BXTWC_THRM_LVL1_IRQ, 6939d047c0SQipeng Zha BXTWC_BCU_LVL1_IRQ, 7039d047c0SQipeng Zha BXTWC_ADC_LVL1_IRQ, 7139d047c0SQipeng Zha BXTWC_CHGR_LVL1_IRQ, 7239d047c0SQipeng Zha BXTWC_GPIO_LVL1_IRQ, 7339d047c0SQipeng Zha BXTWC_CRIT_LVL1_IRQ, 749f8ddee1SAndy Shevchenko }; 7539d047c0SQipeng Zha 769f8ddee1SAndy Shevchenko enum bxtwc_irqs_pwrbtn { 779f8ddee1SAndy Shevchenko BXTWC_PWRBTN_IRQ = 0, 789f8ddee1SAndy Shevchenko BXTWC_UIBTN_IRQ, 7939d047c0SQipeng Zha }; 8039d047c0SQipeng Zha 8157129044SKuppuswamy Sathyanarayanan enum bxtwc_irqs_bcu { 82c4949630SKuppuswamy Sathyanarayanan BXTWC_BCU_IRQ = 0, 8357129044SKuppuswamy Sathyanarayanan }; 8457129044SKuppuswamy Sathyanarayanan 8557129044SKuppuswamy Sathyanarayanan enum bxtwc_irqs_adc { 8657129044SKuppuswamy Sathyanarayanan BXTWC_ADC_IRQ = 0, 8757129044SKuppuswamy Sathyanarayanan }; 8857129044SKuppuswamy Sathyanarayanan 8957129044SKuppuswamy Sathyanarayanan enum bxtwc_irqs_chgr { 9057129044SKuppuswamy Sathyanarayanan BXTWC_USBC_IRQ = 0, 9139d047c0SQipeng Zha BXTWC_CHGR0_IRQ, 9239d047c0SQipeng Zha BXTWC_CHGR1_IRQ, 934533d855SKuppuswamy Sathyanarayanan }; 944533d855SKuppuswamy Sathyanarayanan 954533d855SKuppuswamy Sathyanarayanan enum bxtwc_irqs_tmu { 964533d855SKuppuswamy Sathyanarayanan BXTWC_TMU_IRQ = 0, 9739d047c0SQipeng Zha }; 9839d047c0SQipeng Zha 9957129044SKuppuswamy Sathyanarayanan enum bxtwc_irqs_crit { 10057129044SKuppuswamy Sathyanarayanan BXTWC_CRIT_IRQ = 0, 10157129044SKuppuswamy Sathyanarayanan }; 10257129044SKuppuswamy Sathyanarayanan 10339d047c0SQipeng Zha static const struct regmap_irq bxtwc_regmap_irqs[] = { 10439d047c0SQipeng Zha REGMAP_IRQ_REG(BXTWC_PWRBTN_LVL1_IRQ, 0, BIT(0)), 10539d047c0SQipeng Zha REGMAP_IRQ_REG(BXTWC_TMU_LVL1_IRQ, 0, BIT(1)), 10639d047c0SQipeng Zha REGMAP_IRQ_REG(BXTWC_THRM_LVL1_IRQ, 0, BIT(2)), 10739d047c0SQipeng Zha REGMAP_IRQ_REG(BXTWC_BCU_LVL1_IRQ, 0, BIT(3)), 10839d047c0SQipeng Zha REGMAP_IRQ_REG(BXTWC_ADC_LVL1_IRQ, 0, BIT(4)), 10939d047c0SQipeng Zha REGMAP_IRQ_REG(BXTWC_CHGR_LVL1_IRQ, 0, BIT(5)), 11039d047c0SQipeng Zha REGMAP_IRQ_REG(BXTWC_GPIO_LVL1_IRQ, 0, BIT(6)), 11139d047c0SQipeng Zha REGMAP_IRQ_REG(BXTWC_CRIT_LVL1_IRQ, 0, BIT(7)), 1129f8ddee1SAndy Shevchenko }; 1139f8ddee1SAndy Shevchenko 1149f8ddee1SAndy Shevchenko static const struct regmap_irq bxtwc_regmap_irqs_pwrbtn[] = { 1159f8ddee1SAndy Shevchenko REGMAP_IRQ_REG(BXTWC_PWRBTN_IRQ, 0, 0x01), 11639d047c0SQipeng Zha }; 11739d047c0SQipeng Zha 11857129044SKuppuswamy Sathyanarayanan static const struct regmap_irq bxtwc_regmap_irqs_bcu[] = { 119c4949630SKuppuswamy Sathyanarayanan REGMAP_IRQ_REG(BXTWC_BCU_IRQ, 0, 0x1f), 12057129044SKuppuswamy Sathyanarayanan }; 12157129044SKuppuswamy Sathyanarayanan 12257129044SKuppuswamy Sathyanarayanan static const struct regmap_irq bxtwc_regmap_irqs_adc[] = { 12357129044SKuppuswamy Sathyanarayanan REGMAP_IRQ_REG(BXTWC_ADC_IRQ, 0, 0xff), 12457129044SKuppuswamy Sathyanarayanan }; 12557129044SKuppuswamy Sathyanarayanan 12657129044SKuppuswamy Sathyanarayanan static const struct regmap_irq bxtwc_regmap_irqs_chgr[] = { 1279f8ddee1SAndy Shevchenko REGMAP_IRQ_REG(BXTWC_USBC_IRQ, 0, 0x20), 12857129044SKuppuswamy Sathyanarayanan REGMAP_IRQ_REG(BXTWC_CHGR0_IRQ, 0, 0x1f), 12957129044SKuppuswamy Sathyanarayanan REGMAP_IRQ_REG(BXTWC_CHGR1_IRQ, 1, 0x1f), 13039d047c0SQipeng Zha }; 13139d047c0SQipeng Zha 132957ae509SNilesh Bacchewar static const struct regmap_irq bxtwc_regmap_irqs_tmu[] = { 133957ae509SNilesh Bacchewar REGMAP_IRQ_REG(BXTWC_TMU_IRQ, 0, 0x06), 134957ae509SNilesh Bacchewar }; 135957ae509SNilesh Bacchewar 13657129044SKuppuswamy Sathyanarayanan static const struct regmap_irq bxtwc_regmap_irqs_crit[] = { 13757129044SKuppuswamy Sathyanarayanan REGMAP_IRQ_REG(BXTWC_CRIT_IRQ, 0, 0x03), 13857129044SKuppuswamy Sathyanarayanan }; 13957129044SKuppuswamy Sathyanarayanan 14039d047c0SQipeng Zha static struct regmap_irq_chip bxtwc_regmap_irq_chip = { 14139d047c0SQipeng Zha .name = "bxtwc_irq_chip", 14239d047c0SQipeng Zha .status_base = BXTWC_IRQLVL1, 14339d047c0SQipeng Zha .mask_base = BXTWC_MIRQLVL1, 14439d047c0SQipeng Zha .irqs = bxtwc_regmap_irqs, 14539d047c0SQipeng Zha .num_irqs = ARRAY_SIZE(bxtwc_regmap_irqs), 1469f8ddee1SAndy Shevchenko .num_regs = 1, 1479f8ddee1SAndy Shevchenko }; 1489f8ddee1SAndy Shevchenko 1499f8ddee1SAndy Shevchenko static struct regmap_irq_chip bxtwc_regmap_irq_chip_pwrbtn = { 1509f8ddee1SAndy Shevchenko .name = "bxtwc_irq_chip_pwrbtn", 1519f8ddee1SAndy Shevchenko .status_base = BXTWC_PWRBTNIRQ, 1529f8ddee1SAndy Shevchenko .mask_base = BXTWC_MPWRBTNIRQ, 1539f8ddee1SAndy Shevchenko .irqs = bxtwc_regmap_irqs_pwrbtn, 1549f8ddee1SAndy Shevchenko .num_irqs = ARRAY_SIZE(bxtwc_regmap_irqs_pwrbtn), 1559f8ddee1SAndy Shevchenko .num_regs = 1, 15639d047c0SQipeng Zha }; 15739d047c0SQipeng Zha 158957ae509SNilesh Bacchewar static struct regmap_irq_chip bxtwc_regmap_irq_chip_tmu = { 159957ae509SNilesh Bacchewar .name = "bxtwc_irq_chip_tmu", 160957ae509SNilesh Bacchewar .status_base = BXTWC_TMUIRQ, 161957ae509SNilesh Bacchewar .mask_base = BXTWC_MTMUIRQ, 162957ae509SNilesh Bacchewar .irqs = bxtwc_regmap_irqs_tmu, 163957ae509SNilesh Bacchewar .num_irqs = ARRAY_SIZE(bxtwc_regmap_irqs_tmu), 164957ae509SNilesh Bacchewar .num_regs = 1, 165957ae509SNilesh Bacchewar }; 166957ae509SNilesh Bacchewar 16757129044SKuppuswamy Sathyanarayanan static struct regmap_irq_chip bxtwc_regmap_irq_chip_bcu = { 16857129044SKuppuswamy Sathyanarayanan .name = "bxtwc_irq_chip_bcu", 16957129044SKuppuswamy Sathyanarayanan .status_base = BXTWC_BCUIRQ, 17057129044SKuppuswamy Sathyanarayanan .mask_base = BXTWC_MBCUIRQ, 17157129044SKuppuswamy Sathyanarayanan .irqs = bxtwc_regmap_irqs_bcu, 17257129044SKuppuswamy Sathyanarayanan .num_irqs = ARRAY_SIZE(bxtwc_regmap_irqs_bcu), 17357129044SKuppuswamy Sathyanarayanan .num_regs = 1, 17457129044SKuppuswamy Sathyanarayanan }; 17557129044SKuppuswamy Sathyanarayanan 17657129044SKuppuswamy Sathyanarayanan static struct regmap_irq_chip bxtwc_regmap_irq_chip_adc = { 17757129044SKuppuswamy Sathyanarayanan .name = "bxtwc_irq_chip_adc", 17857129044SKuppuswamy Sathyanarayanan .status_base = BXTWC_ADCIRQ, 17957129044SKuppuswamy Sathyanarayanan .mask_base = BXTWC_MADCIRQ, 18057129044SKuppuswamy Sathyanarayanan .irqs = bxtwc_regmap_irqs_adc, 18157129044SKuppuswamy Sathyanarayanan .num_irqs = ARRAY_SIZE(bxtwc_regmap_irqs_adc), 18257129044SKuppuswamy Sathyanarayanan .num_regs = 1, 18357129044SKuppuswamy Sathyanarayanan }; 18457129044SKuppuswamy Sathyanarayanan 18557129044SKuppuswamy Sathyanarayanan static struct regmap_irq_chip bxtwc_regmap_irq_chip_chgr = { 18657129044SKuppuswamy Sathyanarayanan .name = "bxtwc_irq_chip_chgr", 18757129044SKuppuswamy Sathyanarayanan .status_base = BXTWC_CHGR0IRQ, 18857129044SKuppuswamy Sathyanarayanan .mask_base = BXTWC_MCHGR0IRQ, 18957129044SKuppuswamy Sathyanarayanan .irqs = bxtwc_regmap_irqs_chgr, 19057129044SKuppuswamy Sathyanarayanan .num_irqs = ARRAY_SIZE(bxtwc_regmap_irqs_chgr), 19157129044SKuppuswamy Sathyanarayanan .num_regs = 2, 19257129044SKuppuswamy Sathyanarayanan }; 19357129044SKuppuswamy Sathyanarayanan 19457129044SKuppuswamy Sathyanarayanan static struct regmap_irq_chip bxtwc_regmap_irq_chip_crit = { 19557129044SKuppuswamy Sathyanarayanan .name = "bxtwc_irq_chip_crit", 19657129044SKuppuswamy Sathyanarayanan .status_base = BXTWC_CRITIRQ, 19757129044SKuppuswamy Sathyanarayanan .mask_base = BXTWC_MCRITIRQ, 19857129044SKuppuswamy Sathyanarayanan .irqs = bxtwc_regmap_irqs_crit, 19957129044SKuppuswamy Sathyanarayanan .num_irqs = ARRAY_SIZE(bxtwc_regmap_irqs_crit), 20057129044SKuppuswamy Sathyanarayanan .num_regs = 1, 20157129044SKuppuswamy Sathyanarayanan }; 20257129044SKuppuswamy Sathyanarayanan 203bf4cceb6SRikard Falkeborn static const struct resource gpio_resources[] = { 204a1d28c59SKuppuswamy Sathyanarayanan DEFINE_RES_IRQ_NAMED(BXTWC_GPIO_LVL1_IRQ, "GPIO"), 20539d047c0SQipeng Zha }; 20639d047c0SQipeng Zha 207bf4cceb6SRikard Falkeborn static const struct resource adc_resources[] = { 20839d047c0SQipeng Zha DEFINE_RES_IRQ_NAMED(BXTWC_ADC_IRQ, "ADC"), 20939d047c0SQipeng Zha }; 21039d047c0SQipeng Zha 211bf4cceb6SRikard Falkeborn static const struct resource usbc_resources[] = { 21296007020SHeikki Krogerus DEFINE_RES_IRQ(BXTWC_USBC_IRQ), 2139c6235c8SBin Gao }; 2149c6235c8SBin Gao 215bf4cceb6SRikard Falkeborn static const struct resource charger_resources[] = { 21639d047c0SQipeng Zha DEFINE_RES_IRQ_NAMED(BXTWC_CHGR0_IRQ, "CHARGER"), 21739d047c0SQipeng Zha DEFINE_RES_IRQ_NAMED(BXTWC_CHGR1_IRQ, "CHARGER1"), 21839d047c0SQipeng Zha }; 21939d047c0SQipeng Zha 220bf4cceb6SRikard Falkeborn static const struct resource thermal_resources[] = { 221c4949630SKuppuswamy Sathyanarayanan DEFINE_RES_IRQ(BXTWC_THRM_LVL1_IRQ), 22239d047c0SQipeng Zha }; 22339d047c0SQipeng Zha 224bf4cceb6SRikard Falkeborn static const struct resource bcu_resources[] = { 22539d047c0SQipeng Zha DEFINE_RES_IRQ_NAMED(BXTWC_BCU_IRQ, "BCU"), 22639d047c0SQipeng Zha }; 22739d047c0SQipeng Zha 228bf4cceb6SRikard Falkeborn static const struct resource tmu_resources[] = { 229957ae509SNilesh Bacchewar DEFINE_RES_IRQ_NAMED(BXTWC_TMU_IRQ, "TMU"), 230957ae509SNilesh Bacchewar }; 231957ae509SNilesh Bacchewar 23239d047c0SQipeng Zha static struct mfd_cell bxt_wc_dev[] = { 23339d047c0SQipeng Zha { 23439d047c0SQipeng Zha .name = "bxt_wcove_gpadc", 23539d047c0SQipeng Zha .num_resources = ARRAY_SIZE(adc_resources), 23639d047c0SQipeng Zha .resources = adc_resources, 23739d047c0SQipeng Zha }, 23839d047c0SQipeng Zha { 23939d047c0SQipeng Zha .name = "bxt_wcove_thermal", 24039d047c0SQipeng Zha .num_resources = ARRAY_SIZE(thermal_resources), 24139d047c0SQipeng Zha .resources = thermal_resources, 24239d047c0SQipeng Zha }, 24339d047c0SQipeng Zha { 2449c6235c8SBin Gao .name = "bxt_wcove_usbc", 2459c6235c8SBin Gao .num_resources = ARRAY_SIZE(usbc_resources), 2469c6235c8SBin Gao .resources = usbc_resources, 2479c6235c8SBin Gao }, 2489c6235c8SBin Gao { 24939d047c0SQipeng Zha .name = "bxt_wcove_ext_charger", 25039d047c0SQipeng Zha .num_resources = ARRAY_SIZE(charger_resources), 25139d047c0SQipeng Zha .resources = charger_resources, 25239d047c0SQipeng Zha }, 25339d047c0SQipeng Zha { 25439d047c0SQipeng Zha .name = "bxt_wcove_bcu", 25539d047c0SQipeng Zha .num_resources = ARRAY_SIZE(bcu_resources), 25639d047c0SQipeng Zha .resources = bcu_resources, 25739d047c0SQipeng Zha }, 25839d047c0SQipeng Zha { 259957ae509SNilesh Bacchewar .name = "bxt_wcove_tmu", 260957ae509SNilesh Bacchewar .num_resources = ARRAY_SIZE(tmu_resources), 261957ae509SNilesh Bacchewar .resources = tmu_resources, 262957ae509SNilesh Bacchewar }, 263957ae509SNilesh Bacchewar 264957ae509SNilesh Bacchewar { 26539d047c0SQipeng Zha .name = "bxt_wcove_gpio", 26639d047c0SQipeng Zha .num_resources = ARRAY_SIZE(gpio_resources), 26739d047c0SQipeng Zha .resources = gpio_resources, 26839d047c0SQipeng Zha }, 26939d047c0SQipeng Zha { 27039d047c0SQipeng Zha .name = "bxt_wcove_region", 27139d047c0SQipeng Zha }, 27239d047c0SQipeng Zha }; 27339d047c0SQipeng Zha 27439d047c0SQipeng Zha static int regmap_ipc_byte_reg_read(void *context, unsigned int reg, 27539d047c0SQipeng Zha unsigned int *val) 27639d047c0SQipeng Zha { 27739d047c0SQipeng Zha int ret; 27839d047c0SQipeng Zha int i2c_addr; 27939d047c0SQipeng Zha u8 ipc_in[2]; 28039d047c0SQipeng Zha u8 ipc_out[4]; 28139d047c0SQipeng Zha struct intel_soc_pmic *pmic = context; 28239d047c0SQipeng Zha 283b4ccc4d2SKuppuswamy Sathyanarayanan if (!pmic) 284b4ccc4d2SKuppuswamy Sathyanarayanan return -EINVAL; 285b4ccc4d2SKuppuswamy Sathyanarayanan 28639d047c0SQipeng Zha if (reg & REG_ADDR_MASK) 28739d047c0SQipeng Zha i2c_addr = (reg & REG_ADDR_MASK) >> REG_ADDR_SHIFT; 288b4ccc4d2SKuppuswamy Sathyanarayanan else 28939d047c0SQipeng Zha i2c_addr = BXTWC_DEVICE1_ADDR; 290b4ccc4d2SKuppuswamy Sathyanarayanan 29139d047c0SQipeng Zha reg &= REG_OFFSET_MASK; 29239d047c0SQipeng Zha 29339d047c0SQipeng Zha ipc_in[0] = reg; 29439d047c0SQipeng Zha ipc_in[1] = i2c_addr; 2954181bc8fSMika Westerberg ret = intel_scu_ipc_dev_command(pmic->scu, PMC_PMIC_ACCESS, 2964181bc8fSMika Westerberg PMC_PMIC_READ, ipc_in, sizeof(ipc_in), 2974181bc8fSMika Westerberg ipc_out, sizeof(ipc_out)); 2984181bc8fSMika Westerberg if (ret) 29939d047c0SQipeng Zha return ret; 3004181bc8fSMika Westerberg 30139d047c0SQipeng Zha *val = ipc_out[0]; 30239d047c0SQipeng Zha 30339d047c0SQipeng Zha return 0; 30439d047c0SQipeng Zha } 30539d047c0SQipeng Zha 30639d047c0SQipeng Zha static int regmap_ipc_byte_reg_write(void *context, unsigned int reg, 30739d047c0SQipeng Zha unsigned int val) 30839d047c0SQipeng Zha { 30939d047c0SQipeng Zha int i2c_addr; 31039d047c0SQipeng Zha u8 ipc_in[3]; 31139d047c0SQipeng Zha struct intel_soc_pmic *pmic = context; 31239d047c0SQipeng Zha 313b4ccc4d2SKuppuswamy Sathyanarayanan if (!pmic) 314b4ccc4d2SKuppuswamy Sathyanarayanan return -EINVAL; 315b4ccc4d2SKuppuswamy Sathyanarayanan 31639d047c0SQipeng Zha if (reg & REG_ADDR_MASK) 31739d047c0SQipeng Zha i2c_addr = (reg & REG_ADDR_MASK) >> REG_ADDR_SHIFT; 318b4ccc4d2SKuppuswamy Sathyanarayanan else 31939d047c0SQipeng Zha i2c_addr = BXTWC_DEVICE1_ADDR; 320b4ccc4d2SKuppuswamy Sathyanarayanan 32139d047c0SQipeng Zha reg &= REG_OFFSET_MASK; 32239d047c0SQipeng Zha 32339d047c0SQipeng Zha ipc_in[0] = reg; 32439d047c0SQipeng Zha ipc_in[1] = i2c_addr; 32539d047c0SQipeng Zha ipc_in[2] = val; 3264181bc8fSMika Westerberg return intel_scu_ipc_dev_command(pmic->scu, PMC_PMIC_ACCESS, 3274181bc8fSMika Westerberg PMC_PMIC_WRITE, ipc_in, sizeof(ipc_in), 3284181bc8fSMika Westerberg NULL, 0); 32939d047c0SQipeng Zha } 33039d047c0SQipeng Zha 33139d047c0SQipeng Zha /* sysfs interfaces to r/w PMIC registers, required by initial script */ 33239d047c0SQipeng Zha static unsigned long bxtwc_reg_addr; 3335089e34fSZhen Lei static ssize_t addr_show(struct device *dev, 33439d047c0SQipeng Zha struct device_attribute *attr, char *buf) 33539d047c0SQipeng Zha { 33639d047c0SQipeng Zha return sprintf(buf, "0x%lx\n", bxtwc_reg_addr); 33739d047c0SQipeng Zha } 33839d047c0SQipeng Zha 3395089e34fSZhen Lei static ssize_t addr_store(struct device *dev, 34039d047c0SQipeng Zha struct device_attribute *attr, const char *buf, size_t count) 34139d047c0SQipeng Zha { 34251899522SAndy Shevchenko int ret; 34351899522SAndy Shevchenko 34451899522SAndy Shevchenko ret = kstrtoul(buf, 0, &bxtwc_reg_addr); 34551899522SAndy Shevchenko if (ret) 34651899522SAndy Shevchenko return ret; 34751899522SAndy Shevchenko 34839d047c0SQipeng Zha return (ssize_t)count; 34939d047c0SQipeng Zha } 35039d047c0SQipeng Zha 3515089e34fSZhen Lei static ssize_t val_show(struct device *dev, 35239d047c0SQipeng Zha struct device_attribute *attr, char *buf) 35339d047c0SQipeng Zha { 35439d047c0SQipeng Zha int ret; 35539d047c0SQipeng Zha unsigned int val; 35639d047c0SQipeng Zha struct intel_soc_pmic *pmic = dev_get_drvdata(dev); 35739d047c0SQipeng Zha 35839d047c0SQipeng Zha ret = regmap_read(pmic->regmap, bxtwc_reg_addr, &val); 35951899522SAndy Shevchenko if (ret) { 36039d047c0SQipeng Zha dev_err(dev, "Failed to read 0x%lx\n", bxtwc_reg_addr); 36151899522SAndy Shevchenko return ret; 36239d047c0SQipeng Zha } 36339d047c0SQipeng Zha 36439d047c0SQipeng Zha return sprintf(buf, "0x%02x\n", val); 36539d047c0SQipeng Zha } 36639d047c0SQipeng Zha 3675089e34fSZhen Lei static ssize_t val_store(struct device *dev, 36839d047c0SQipeng Zha struct device_attribute *attr, const char *buf, size_t count) 36939d047c0SQipeng Zha { 37039d047c0SQipeng Zha int ret; 37139d047c0SQipeng Zha unsigned int val; 37239d047c0SQipeng Zha struct intel_soc_pmic *pmic = dev_get_drvdata(dev); 37339d047c0SQipeng Zha 374f3a654c5SDan Carpenter ret = kstrtouint(buf, 0, &val); 375f3a654c5SDan Carpenter if (ret) 376f3a654c5SDan Carpenter return ret; 37739d047c0SQipeng Zha 37839d047c0SQipeng Zha ret = regmap_write(pmic->regmap, bxtwc_reg_addr, val); 37939d047c0SQipeng Zha if (ret) { 38039d047c0SQipeng Zha dev_err(dev, "Failed to write value 0x%02x to address 0x%lx", 38139d047c0SQipeng Zha val, bxtwc_reg_addr); 38251899522SAndy Shevchenko return ret; 38339d047c0SQipeng Zha } 38439d047c0SQipeng Zha return count; 38539d047c0SQipeng Zha } 38639d047c0SQipeng Zha 3875089e34fSZhen Lei static DEVICE_ATTR_ADMIN_RW(addr); 3885089e34fSZhen Lei static DEVICE_ATTR_ADMIN_RW(val); 38939d047c0SQipeng Zha static struct attribute *bxtwc_attrs[] = { 39039d047c0SQipeng Zha &dev_attr_addr.attr, 39139d047c0SQipeng Zha &dev_attr_val.attr, 39239d047c0SQipeng Zha NULL 39339d047c0SQipeng Zha }; 39439d047c0SQipeng Zha 39539d047c0SQipeng Zha static const struct attribute_group bxtwc_group = { 39639d047c0SQipeng Zha .attrs = bxtwc_attrs, 39739d047c0SQipeng Zha }; 39839d047c0SQipeng Zha 399929a4d28SAndy Shevchenko static const struct attribute_group *bxtwc_groups[] = { 400929a4d28SAndy Shevchenko &bxtwc_group, 401929a4d28SAndy Shevchenko NULL 402929a4d28SAndy Shevchenko }; 403929a4d28SAndy Shevchenko 40439d047c0SQipeng Zha static const struct regmap_config bxtwc_regmap_config = { 40539d047c0SQipeng Zha .reg_bits = 16, 40639d047c0SQipeng Zha .val_bits = 8, 40739d047c0SQipeng Zha .reg_write = regmap_ipc_byte_reg_write, 40839d047c0SQipeng Zha .reg_read = regmap_ipc_byte_reg_read, 40939d047c0SQipeng Zha }; 41039d047c0SQipeng Zha 41157129044SKuppuswamy Sathyanarayanan static int bxtwc_add_chained_irq_chip(struct intel_soc_pmic *pmic, 41257129044SKuppuswamy Sathyanarayanan struct regmap_irq_chip_data *pdata, 41357129044SKuppuswamy Sathyanarayanan int pirq, int irq_flags, 41457129044SKuppuswamy Sathyanarayanan const struct regmap_irq_chip *chip, 41557129044SKuppuswamy Sathyanarayanan struct regmap_irq_chip_data **data) 41657129044SKuppuswamy Sathyanarayanan { 41757129044SKuppuswamy Sathyanarayanan int irq; 41857129044SKuppuswamy Sathyanarayanan 41957129044SKuppuswamy Sathyanarayanan irq = regmap_irq_get_virq(pdata, pirq); 42057129044SKuppuswamy Sathyanarayanan if (irq < 0) { 42157129044SKuppuswamy Sathyanarayanan dev_err(pmic->dev, 42257129044SKuppuswamy Sathyanarayanan "Failed to get parent vIRQ(%d) for chip %s, ret:%d\n", 42357129044SKuppuswamy Sathyanarayanan pirq, chip->name, irq); 42457129044SKuppuswamy Sathyanarayanan return irq; 42557129044SKuppuswamy Sathyanarayanan } 42657129044SKuppuswamy Sathyanarayanan 42757129044SKuppuswamy Sathyanarayanan return devm_regmap_add_irq_chip(pmic->dev, pmic->regmap, irq, irq_flags, 42857129044SKuppuswamy Sathyanarayanan 0, chip, data); 42957129044SKuppuswamy Sathyanarayanan } 43057129044SKuppuswamy Sathyanarayanan 43139d047c0SQipeng Zha static int bxtwc_probe(struct platform_device *pdev) 43239d047c0SQipeng Zha { 43339d047c0SQipeng Zha int ret; 43439d047c0SQipeng Zha acpi_handle handle; 43539d047c0SQipeng Zha acpi_status status; 43639d047c0SQipeng Zha unsigned long long hrv; 43739d047c0SQipeng Zha struct intel_soc_pmic *pmic; 43839d047c0SQipeng Zha 43939d047c0SQipeng Zha handle = ACPI_HANDLE(&pdev->dev); 44039d047c0SQipeng Zha status = acpi_evaluate_integer(handle, "_HRV", NULL, &hrv); 44139d047c0SQipeng Zha if (ACPI_FAILURE(status)) { 44239d047c0SQipeng Zha dev_err(&pdev->dev, "Failed to get PMIC hardware revision\n"); 44339d047c0SQipeng Zha return -ENODEV; 44439d047c0SQipeng Zha } 44539d047c0SQipeng Zha if (hrv != BROXTON_PMIC_WC_HRV) { 44639d047c0SQipeng Zha dev_err(&pdev->dev, "Invalid PMIC hardware revision: %llu\n", 44739d047c0SQipeng Zha hrv); 44839d047c0SQipeng Zha return -ENODEV; 44939d047c0SQipeng Zha } 45039d047c0SQipeng Zha 45139d047c0SQipeng Zha pmic = devm_kzalloc(&pdev->dev, sizeof(*pmic), GFP_KERNEL); 45239d047c0SQipeng Zha if (!pmic) 45339d047c0SQipeng Zha return -ENOMEM; 45439d047c0SQipeng Zha 45539d047c0SQipeng Zha ret = platform_get_irq(pdev, 0); 456802d9bd4SStephen Boyd if (ret < 0) 45739d047c0SQipeng Zha return ret; 45839d047c0SQipeng Zha pmic->irq = ret; 45939d047c0SQipeng Zha 460*2790a70cSAndy Shevchenko platform_set_drvdata(pdev, pmic); 46139d047c0SQipeng Zha pmic->dev = &pdev->dev; 46239d047c0SQipeng Zha 4634181bc8fSMika Westerberg pmic->scu = devm_intel_scu_ipc_dev_get(&pdev->dev); 4644181bc8fSMika Westerberg if (!pmic->scu) 4654181bc8fSMika Westerberg return -EPROBE_DEFER; 4664181bc8fSMika Westerberg 46739d047c0SQipeng Zha pmic->regmap = devm_regmap_init(&pdev->dev, NULL, pmic, 46839d047c0SQipeng Zha &bxtwc_regmap_config); 46939d047c0SQipeng Zha if (IS_ERR(pmic->regmap)) { 47039d047c0SQipeng Zha ret = PTR_ERR(pmic->regmap); 47139d047c0SQipeng Zha dev_err(&pdev->dev, "Failed to initialise regmap: %d\n", ret); 47239d047c0SQipeng Zha return ret; 47339d047c0SQipeng Zha } 47439d047c0SQipeng Zha 4755131f072SKuppuswamy Sathyanarayanan ret = devm_regmap_add_irq_chip(&pdev->dev, pmic->regmap, pmic->irq, 47639d047c0SQipeng Zha IRQF_ONESHOT | IRQF_SHARED, 47739d047c0SQipeng Zha 0, &bxtwc_regmap_irq_chip, 47839d047c0SQipeng Zha &pmic->irq_chip_data); 47939d047c0SQipeng Zha if (ret) { 48039d047c0SQipeng Zha dev_err(&pdev->dev, "Failed to add IRQ chip\n"); 48139d047c0SQipeng Zha return ret; 48239d047c0SQipeng Zha } 48339d047c0SQipeng Zha 48457129044SKuppuswamy Sathyanarayanan ret = bxtwc_add_chained_irq_chip(pmic, pmic->irq_chip_data, 4859f8ddee1SAndy Shevchenko BXTWC_PWRBTN_LVL1_IRQ, 4869f8ddee1SAndy Shevchenko IRQF_ONESHOT, 4879f8ddee1SAndy Shevchenko &bxtwc_regmap_irq_chip_pwrbtn, 4889f8ddee1SAndy Shevchenko &pmic->irq_chip_data_pwrbtn); 4899f8ddee1SAndy Shevchenko if (ret) { 4909f8ddee1SAndy Shevchenko dev_err(&pdev->dev, "Failed to add PWRBTN IRQ chip\n"); 4919f8ddee1SAndy Shevchenko return ret; 4929f8ddee1SAndy Shevchenko } 4939f8ddee1SAndy Shevchenko 4949f8ddee1SAndy Shevchenko ret = bxtwc_add_chained_irq_chip(pmic, pmic->irq_chip_data, 49557129044SKuppuswamy Sathyanarayanan BXTWC_TMU_LVL1_IRQ, 49657129044SKuppuswamy Sathyanarayanan IRQF_ONESHOT, 49757129044SKuppuswamy Sathyanarayanan &bxtwc_regmap_irq_chip_tmu, 498957ae509SNilesh Bacchewar &pmic->irq_chip_data_tmu); 499957ae509SNilesh Bacchewar if (ret) { 500957ae509SNilesh Bacchewar dev_err(&pdev->dev, "Failed to add TMU IRQ chip\n"); 5015131f072SKuppuswamy Sathyanarayanan return ret; 502957ae509SNilesh Bacchewar } 503957ae509SNilesh Bacchewar 50457129044SKuppuswamy Sathyanarayanan /* Add chained IRQ handler for BCU IRQs */ 50557129044SKuppuswamy Sathyanarayanan ret = bxtwc_add_chained_irq_chip(pmic, pmic->irq_chip_data, 50657129044SKuppuswamy Sathyanarayanan BXTWC_BCU_LVL1_IRQ, 50757129044SKuppuswamy Sathyanarayanan IRQF_ONESHOT, 50857129044SKuppuswamy Sathyanarayanan &bxtwc_regmap_irq_chip_bcu, 50957129044SKuppuswamy Sathyanarayanan &pmic->irq_chip_data_bcu); 51057129044SKuppuswamy Sathyanarayanan 51157129044SKuppuswamy Sathyanarayanan 51257129044SKuppuswamy Sathyanarayanan if (ret) { 51357129044SKuppuswamy Sathyanarayanan dev_err(&pdev->dev, "Failed to add BUC IRQ chip\n"); 51457129044SKuppuswamy Sathyanarayanan return ret; 51557129044SKuppuswamy Sathyanarayanan } 51657129044SKuppuswamy Sathyanarayanan 51757129044SKuppuswamy Sathyanarayanan /* Add chained IRQ handler for ADC IRQs */ 51857129044SKuppuswamy Sathyanarayanan ret = bxtwc_add_chained_irq_chip(pmic, pmic->irq_chip_data, 51957129044SKuppuswamy Sathyanarayanan BXTWC_ADC_LVL1_IRQ, 52057129044SKuppuswamy Sathyanarayanan IRQF_ONESHOT, 52157129044SKuppuswamy Sathyanarayanan &bxtwc_regmap_irq_chip_adc, 52257129044SKuppuswamy Sathyanarayanan &pmic->irq_chip_data_adc); 52357129044SKuppuswamy Sathyanarayanan 52457129044SKuppuswamy Sathyanarayanan 52557129044SKuppuswamy Sathyanarayanan if (ret) { 52657129044SKuppuswamy Sathyanarayanan dev_err(&pdev->dev, "Failed to add ADC IRQ chip\n"); 52757129044SKuppuswamy Sathyanarayanan return ret; 52857129044SKuppuswamy Sathyanarayanan } 52957129044SKuppuswamy Sathyanarayanan 53057129044SKuppuswamy Sathyanarayanan /* Add chained IRQ handler for CHGR IRQs */ 53157129044SKuppuswamy Sathyanarayanan ret = bxtwc_add_chained_irq_chip(pmic, pmic->irq_chip_data, 53257129044SKuppuswamy Sathyanarayanan BXTWC_CHGR_LVL1_IRQ, 53357129044SKuppuswamy Sathyanarayanan IRQF_ONESHOT, 53457129044SKuppuswamy Sathyanarayanan &bxtwc_regmap_irq_chip_chgr, 53557129044SKuppuswamy Sathyanarayanan &pmic->irq_chip_data_chgr); 53657129044SKuppuswamy Sathyanarayanan 53757129044SKuppuswamy Sathyanarayanan 53857129044SKuppuswamy Sathyanarayanan if (ret) { 53957129044SKuppuswamy Sathyanarayanan dev_err(&pdev->dev, "Failed to add CHGR IRQ chip\n"); 54057129044SKuppuswamy Sathyanarayanan return ret; 54157129044SKuppuswamy Sathyanarayanan } 54257129044SKuppuswamy Sathyanarayanan 54357129044SKuppuswamy Sathyanarayanan /* Add chained IRQ handler for CRIT IRQs */ 54457129044SKuppuswamy Sathyanarayanan ret = bxtwc_add_chained_irq_chip(pmic, pmic->irq_chip_data, 54557129044SKuppuswamy Sathyanarayanan BXTWC_CRIT_LVL1_IRQ, 54657129044SKuppuswamy Sathyanarayanan IRQF_ONESHOT, 54757129044SKuppuswamy Sathyanarayanan &bxtwc_regmap_irq_chip_crit, 54857129044SKuppuswamy Sathyanarayanan &pmic->irq_chip_data_crit); 54957129044SKuppuswamy Sathyanarayanan 55057129044SKuppuswamy Sathyanarayanan 55157129044SKuppuswamy Sathyanarayanan if (ret) { 55257129044SKuppuswamy Sathyanarayanan dev_err(&pdev->dev, "Failed to add CRIT IRQ chip\n"); 55357129044SKuppuswamy Sathyanarayanan return ret; 55457129044SKuppuswamy Sathyanarayanan } 55557129044SKuppuswamy Sathyanarayanan 5565131f072SKuppuswamy Sathyanarayanan ret = devm_mfd_add_devices(&pdev->dev, PLATFORM_DEVID_NONE, bxt_wc_dev, 5575131f072SKuppuswamy Sathyanarayanan ARRAY_SIZE(bxt_wc_dev), NULL, 0, NULL); 55839d047c0SQipeng Zha if (ret) { 55939d047c0SQipeng Zha dev_err(&pdev->dev, "Failed to add devices\n"); 5605131f072SKuppuswamy Sathyanarayanan return ret; 56139d047c0SQipeng Zha } 56239d047c0SQipeng Zha 5639c6235c8SBin Gao /* 5649c6235c8SBin Gao * There is known hw bug. Upon reset BIT 5 of register 5659c6235c8SBin Gao * BXTWC_CHGR_LVL1_IRQ is 0 which is the expected value. However, 5669c6235c8SBin Gao * later it's set to 1(masked) automatically by hardware. So we 5679c6235c8SBin Gao * have the software workaround here to unmaksed it in order to let 5689c6235c8SBin Gao * charger interrutp work. 5699c6235c8SBin Gao */ 570929a4d28SAndy Shevchenko regmap_update_bits(pmic->regmap, BXTWC_MIRQLVL1, BXTWC_MIRQLVL1_MCHGR, 0); 57139d047c0SQipeng Zha 57239d047c0SQipeng Zha return 0; 57339d047c0SQipeng Zha } 57439d047c0SQipeng Zha 57539d047c0SQipeng Zha static void bxtwc_shutdown(struct platform_device *pdev) 57639d047c0SQipeng Zha { 577*2790a70cSAndy Shevchenko struct intel_soc_pmic *pmic = platform_get_drvdata(pdev); 57839d047c0SQipeng Zha 57939d047c0SQipeng Zha disable_irq(pmic->irq); 58039d047c0SQipeng Zha } 58139d047c0SQipeng Zha 58239d047c0SQipeng Zha #ifdef CONFIG_PM_SLEEP 58339d047c0SQipeng Zha static int bxtwc_suspend(struct device *dev) 58439d047c0SQipeng Zha { 58539d047c0SQipeng Zha struct intel_soc_pmic *pmic = dev_get_drvdata(dev); 58639d047c0SQipeng Zha 58739d047c0SQipeng Zha disable_irq(pmic->irq); 58839d047c0SQipeng Zha 58939d047c0SQipeng Zha return 0; 59039d047c0SQipeng Zha } 59139d047c0SQipeng Zha 59239d047c0SQipeng Zha static int bxtwc_resume(struct device *dev) 59339d047c0SQipeng Zha { 59439d047c0SQipeng Zha struct intel_soc_pmic *pmic = dev_get_drvdata(dev); 59539d047c0SQipeng Zha 59639d047c0SQipeng Zha enable_irq(pmic->irq); 59739d047c0SQipeng Zha return 0; 59839d047c0SQipeng Zha } 59939d047c0SQipeng Zha #endif 60039d047c0SQipeng Zha static SIMPLE_DEV_PM_OPS(bxtwc_pm_ops, bxtwc_suspend, bxtwc_resume); 60139d047c0SQipeng Zha 60239d047c0SQipeng Zha static const struct acpi_device_id bxtwc_acpi_ids[] = { 60339d047c0SQipeng Zha { "INT34D3", }, 60439d047c0SQipeng Zha { } 60539d047c0SQipeng Zha }; 606f57576e7SWei Yongjun MODULE_DEVICE_TABLE(acpi, bxtwc_acpi_ids); 60739d047c0SQipeng Zha 60839d047c0SQipeng Zha static struct platform_driver bxtwc_driver = { 60939d047c0SQipeng Zha .probe = bxtwc_probe, 61039d047c0SQipeng Zha .shutdown = bxtwc_shutdown, 61139d047c0SQipeng Zha .driver = { 61239d047c0SQipeng Zha .name = "BXTWC PMIC", 61339d047c0SQipeng Zha .pm = &bxtwc_pm_ops, 61439d047c0SQipeng Zha .acpi_match_table = ACPI_PTR(bxtwc_acpi_ids), 615929a4d28SAndy Shevchenko .dev_groups = bxtwc_groups, 61639d047c0SQipeng Zha }, 61739d047c0SQipeng Zha }; 61839d047c0SQipeng Zha 61939d047c0SQipeng Zha module_platform_driver(bxtwc_driver); 62039d047c0SQipeng Zha 62139d047c0SQipeng Zha MODULE_LICENSE("GPL v2"); 62239d047c0SQipeng Zha MODULE_AUTHOR("Qipeng Zha<qipeng.zha@intel.com>"); 623