126c7e05aSAndy Shevchenko // SPDX-License-Identifier: GPL-2.0
239d047c0SQipeng Zha /*
339d047c0SQipeng Zha * MFD core driver for Intel Broxton Whiskey Cove PMIC
439d047c0SQipeng Zha *
5*0ff590a3SAndy 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
14139d047c0SQipeng Zha static 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
1509f8ddee1SAndy Shevchenko static 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
159957ae509SNilesh Bacchewar static 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
16857129044SKuppuswamy Sathyanarayanan static 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
17757129044SKuppuswamy Sathyanarayanan static 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
18657129044SKuppuswamy Sathyanarayanan static 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
19557129044SKuppuswamy Sathyanarayanan static 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
regmap_ipc_byte_reg_read(void * context,unsigned int reg,unsigned int * val)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
regmap_ipc_byte_reg_write(void * context,unsigned int reg,unsigned int val)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;
addr_show(struct device * dev,struct device_attribute * attr,char * buf)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
addr_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)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
val_show(struct device * dev,struct device_attribute * attr,char * buf)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
val_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)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
bxtwc_add_chained_irq_chip(struct intel_soc_pmic * pmic,struct regmap_irq_chip_data * pdata,int pirq,int irq_flags,const struct regmap_irq_chip * chip,struct regmap_irq_chip_data ** data)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
bxtwc_probe(struct platform_device * pdev)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 /*
528*0ff590a3SAndy 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
531*0ff590a3SAndy Shevchenko * place the software workaround here to unmask it again in order
532*0ff590a3SAndy 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
bxtwc_shutdown(struct platform_device * pdev)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
bxtwc_suspend(struct device * dev)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
bxtwc_resume(struct device * dev)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
58439d047c0SQipeng Zha MODULE_LICENSE("GPL v2");
58539d047c0SQipeng Zha MODULE_AUTHOR("Qipeng Zha <qipeng.zha@intel.com>");
586