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);
420*d30e2c30SAndy Shevchenko 	if (irq < 0)
421*d30e2c30SAndy Shevchenko 		return dev_err_probe(pmic->dev, irq, "Failed to get parent vIRQ(%d) for chip %s\n",
422*d30e2c30SAndy Shevchenko 				     pirq, chip->name);
42357129044SKuppuswamy Sathyanarayanan 
42457129044SKuppuswamy Sathyanarayanan 	return devm_regmap_add_irq_chip(pmic->dev, pmic->regmap, irq, irq_flags,
42557129044SKuppuswamy Sathyanarayanan 					0, chip, data);
42657129044SKuppuswamy Sathyanarayanan }
42757129044SKuppuswamy Sathyanarayanan 
42839d047c0SQipeng Zha static int bxtwc_probe(struct platform_device *pdev)
42939d047c0SQipeng Zha {
430*d30e2c30SAndy Shevchenko 	struct device *dev = &pdev->dev;
43139d047c0SQipeng Zha 	int ret;
43239d047c0SQipeng Zha 	acpi_handle handle;
43339d047c0SQipeng Zha 	acpi_status status;
43439d047c0SQipeng Zha 	unsigned long long hrv;
43539d047c0SQipeng Zha 	struct intel_soc_pmic *pmic;
43639d047c0SQipeng Zha 
43739d047c0SQipeng Zha 	handle = ACPI_HANDLE(&pdev->dev);
43839d047c0SQipeng Zha 	status = acpi_evaluate_integer(handle, "_HRV", NULL, &hrv);
439*d30e2c30SAndy Shevchenko 	if (ACPI_FAILURE(status))
440*d30e2c30SAndy Shevchenko 		return dev_err_probe(dev, -ENODEV, "Failed to get PMIC hardware revision\n");
441*d30e2c30SAndy Shevchenko 	if (hrv != BROXTON_PMIC_WC_HRV)
442*d30e2c30SAndy Shevchenko 		return dev_err_probe(dev, -ENODEV, "Invalid PMIC hardware revision: %llu\n", hrv);
44339d047c0SQipeng Zha 
44439d047c0SQipeng Zha 	pmic = devm_kzalloc(&pdev->dev, sizeof(*pmic), GFP_KERNEL);
44539d047c0SQipeng Zha 	if (!pmic)
44639d047c0SQipeng Zha 		return -ENOMEM;
44739d047c0SQipeng Zha 
44839d047c0SQipeng Zha 	ret = platform_get_irq(pdev, 0);
449802d9bd4SStephen Boyd 	if (ret < 0)
45039d047c0SQipeng Zha 		return ret;
45139d047c0SQipeng Zha 	pmic->irq = ret;
45239d047c0SQipeng Zha 
4532790a70cSAndy Shevchenko 	platform_set_drvdata(pdev, pmic);
45439d047c0SQipeng Zha 	pmic->dev = &pdev->dev;
45539d047c0SQipeng Zha 
4564181bc8fSMika Westerberg 	pmic->scu = devm_intel_scu_ipc_dev_get(&pdev->dev);
4574181bc8fSMika Westerberg 	if (!pmic->scu)
4584181bc8fSMika Westerberg 		return -EPROBE_DEFER;
4594181bc8fSMika Westerberg 
46039d047c0SQipeng Zha 	pmic->regmap = devm_regmap_init(&pdev->dev, NULL, pmic,
46139d047c0SQipeng Zha 					&bxtwc_regmap_config);
462*d30e2c30SAndy Shevchenko 	if (IS_ERR(pmic->regmap))
463*d30e2c30SAndy Shevchenko 		return dev_err_probe(dev, PTR_ERR(pmic->regmap), "Failed to initialise regmap\n");
46439d047c0SQipeng Zha 
4655131f072SKuppuswamy Sathyanarayanan 	ret = devm_regmap_add_irq_chip(&pdev->dev, pmic->regmap, pmic->irq,
46639d047c0SQipeng Zha 				       IRQF_ONESHOT | IRQF_SHARED,
46739d047c0SQipeng Zha 				       0, &bxtwc_regmap_irq_chip,
46839d047c0SQipeng Zha 				       &pmic->irq_chip_data);
469*d30e2c30SAndy Shevchenko 	if (ret)
470*d30e2c30SAndy Shevchenko 		return dev_err_probe(dev, ret, "Failed to add IRQ chip\n");
47139d047c0SQipeng Zha 
47257129044SKuppuswamy Sathyanarayanan 	ret = bxtwc_add_chained_irq_chip(pmic, pmic->irq_chip_data,
4739f8ddee1SAndy Shevchenko 					 BXTWC_PWRBTN_LVL1_IRQ,
4749f8ddee1SAndy Shevchenko 					 IRQF_ONESHOT,
4759f8ddee1SAndy Shevchenko 					 &bxtwc_regmap_irq_chip_pwrbtn,
4769f8ddee1SAndy Shevchenko 					 &pmic->irq_chip_data_pwrbtn);
477*d30e2c30SAndy Shevchenko 	if (ret)
478*d30e2c30SAndy Shevchenko 		return dev_err_probe(dev, ret, "Failed to add PWRBTN IRQ chip\n");
4799f8ddee1SAndy Shevchenko 
4809f8ddee1SAndy Shevchenko 	ret = bxtwc_add_chained_irq_chip(pmic, pmic->irq_chip_data,
48157129044SKuppuswamy Sathyanarayanan 					 BXTWC_TMU_LVL1_IRQ,
48257129044SKuppuswamy Sathyanarayanan 					 IRQF_ONESHOT,
48357129044SKuppuswamy Sathyanarayanan 					 &bxtwc_regmap_irq_chip_tmu,
484957ae509SNilesh Bacchewar 					 &pmic->irq_chip_data_tmu);
485*d30e2c30SAndy Shevchenko 	if (ret)
486*d30e2c30SAndy Shevchenko 		return dev_err_probe(dev, ret, "Failed to add TMU IRQ chip\n");
487957ae509SNilesh Bacchewar 
48857129044SKuppuswamy Sathyanarayanan 	/* Add chained IRQ handler for BCU IRQs */
48957129044SKuppuswamy Sathyanarayanan 	ret = bxtwc_add_chained_irq_chip(pmic, pmic->irq_chip_data,
49057129044SKuppuswamy Sathyanarayanan 					 BXTWC_BCU_LVL1_IRQ,
49157129044SKuppuswamy Sathyanarayanan 					 IRQF_ONESHOT,
49257129044SKuppuswamy Sathyanarayanan 					 &bxtwc_regmap_irq_chip_bcu,
49357129044SKuppuswamy Sathyanarayanan 					 &pmic->irq_chip_data_bcu);
494*d30e2c30SAndy Shevchenko 	if (ret)
495*d30e2c30SAndy Shevchenko 		return dev_err_probe(dev, ret, "Failed to add BUC IRQ chip\n");
49657129044SKuppuswamy Sathyanarayanan 
49757129044SKuppuswamy Sathyanarayanan 	/* Add chained IRQ handler for ADC IRQs */
49857129044SKuppuswamy Sathyanarayanan 	ret = bxtwc_add_chained_irq_chip(pmic, pmic->irq_chip_data,
49957129044SKuppuswamy Sathyanarayanan 					 BXTWC_ADC_LVL1_IRQ,
50057129044SKuppuswamy Sathyanarayanan 					 IRQF_ONESHOT,
50157129044SKuppuswamy Sathyanarayanan 					 &bxtwc_regmap_irq_chip_adc,
50257129044SKuppuswamy Sathyanarayanan 					 &pmic->irq_chip_data_adc);
503*d30e2c30SAndy Shevchenko 	if (ret)
504*d30e2c30SAndy Shevchenko 		return dev_err_probe(dev, ret, "Failed to add ADC IRQ chip\n");
50557129044SKuppuswamy Sathyanarayanan 
50657129044SKuppuswamy Sathyanarayanan 	/* Add chained IRQ handler for CHGR IRQs */
50757129044SKuppuswamy Sathyanarayanan 	ret = bxtwc_add_chained_irq_chip(pmic, pmic->irq_chip_data,
50857129044SKuppuswamy Sathyanarayanan 					 BXTWC_CHGR_LVL1_IRQ,
50957129044SKuppuswamy Sathyanarayanan 					 IRQF_ONESHOT,
51057129044SKuppuswamy Sathyanarayanan 					 &bxtwc_regmap_irq_chip_chgr,
51157129044SKuppuswamy Sathyanarayanan 					 &pmic->irq_chip_data_chgr);
512*d30e2c30SAndy Shevchenko 	if (ret)
513*d30e2c30SAndy Shevchenko 		return dev_err_probe(dev, ret, "Failed to add CHGR IRQ chip\n");
51457129044SKuppuswamy Sathyanarayanan 
51557129044SKuppuswamy Sathyanarayanan 	/* Add chained IRQ handler for CRIT IRQs */
51657129044SKuppuswamy Sathyanarayanan 	ret = bxtwc_add_chained_irq_chip(pmic, pmic->irq_chip_data,
51757129044SKuppuswamy Sathyanarayanan 					 BXTWC_CRIT_LVL1_IRQ,
51857129044SKuppuswamy Sathyanarayanan 					 IRQF_ONESHOT,
51957129044SKuppuswamy Sathyanarayanan 					 &bxtwc_regmap_irq_chip_crit,
52057129044SKuppuswamy Sathyanarayanan 					 &pmic->irq_chip_data_crit);
521*d30e2c30SAndy Shevchenko 	if (ret)
522*d30e2c30SAndy Shevchenko 		return dev_err_probe(dev, ret, "Failed to add CRIT IRQ chip\n");
52357129044SKuppuswamy Sathyanarayanan 
5245131f072SKuppuswamy Sathyanarayanan 	ret = devm_mfd_add_devices(&pdev->dev, PLATFORM_DEVID_NONE, bxt_wc_dev,
5255131f072SKuppuswamy Sathyanarayanan 				   ARRAY_SIZE(bxt_wc_dev), NULL, 0, NULL);
526*d30e2c30SAndy Shevchenko 	if (ret)
527*d30e2c30SAndy Shevchenko 		return dev_err_probe(dev, ret, "Failed to add devices\n");
52839d047c0SQipeng Zha 
5299c6235c8SBin Gao 	/*
5309c6235c8SBin Gao 	 * There is known hw bug. Upon reset BIT 5 of register
5319c6235c8SBin Gao 	 * BXTWC_CHGR_LVL1_IRQ is 0 which is the expected value. However,
5329c6235c8SBin Gao 	 * later it's set to 1(masked) automatically by hardware. So we
5339c6235c8SBin Gao 	 * have the software workaround here to unmaksed it in order to let
5349c6235c8SBin Gao 	 * charger interrutp work.
5359c6235c8SBin Gao 	 */
536929a4d28SAndy Shevchenko 	regmap_update_bits(pmic->regmap, BXTWC_MIRQLVL1, BXTWC_MIRQLVL1_MCHGR, 0);
53739d047c0SQipeng Zha 
53839d047c0SQipeng Zha 	return 0;
53939d047c0SQipeng Zha }
54039d047c0SQipeng Zha 
54139d047c0SQipeng Zha static void bxtwc_shutdown(struct platform_device *pdev)
54239d047c0SQipeng Zha {
5432790a70cSAndy Shevchenko 	struct intel_soc_pmic *pmic = platform_get_drvdata(pdev);
54439d047c0SQipeng Zha 
54539d047c0SQipeng Zha 	disable_irq(pmic->irq);
54639d047c0SQipeng Zha }
54739d047c0SQipeng Zha 
54839d047c0SQipeng Zha #ifdef CONFIG_PM_SLEEP
54939d047c0SQipeng Zha static int bxtwc_suspend(struct device *dev)
55039d047c0SQipeng Zha {
55139d047c0SQipeng Zha 	struct intel_soc_pmic *pmic = dev_get_drvdata(dev);
55239d047c0SQipeng Zha 
55339d047c0SQipeng Zha 	disable_irq(pmic->irq);
55439d047c0SQipeng Zha 
55539d047c0SQipeng Zha 	return 0;
55639d047c0SQipeng Zha }
55739d047c0SQipeng Zha 
55839d047c0SQipeng Zha static int bxtwc_resume(struct device *dev)
55939d047c0SQipeng Zha {
56039d047c0SQipeng Zha 	struct intel_soc_pmic *pmic = dev_get_drvdata(dev);
56139d047c0SQipeng Zha 
56239d047c0SQipeng Zha 	enable_irq(pmic->irq);
56339d047c0SQipeng Zha 	return 0;
56439d047c0SQipeng Zha }
56539d047c0SQipeng Zha #endif
56639d047c0SQipeng Zha static SIMPLE_DEV_PM_OPS(bxtwc_pm_ops, bxtwc_suspend, bxtwc_resume);
56739d047c0SQipeng Zha 
56839d047c0SQipeng Zha static const struct acpi_device_id bxtwc_acpi_ids[] = {
56939d047c0SQipeng Zha 	{ "INT34D3", },
57039d047c0SQipeng Zha 	{ }
57139d047c0SQipeng Zha };
572f57576e7SWei Yongjun MODULE_DEVICE_TABLE(acpi, bxtwc_acpi_ids);
57339d047c0SQipeng Zha 
57439d047c0SQipeng Zha static struct platform_driver bxtwc_driver = {
57539d047c0SQipeng Zha 	.probe = bxtwc_probe,
57639d047c0SQipeng Zha 	.shutdown = bxtwc_shutdown,
57739d047c0SQipeng Zha 	.driver	= {
57839d047c0SQipeng Zha 		.name	= "BXTWC PMIC",
57939d047c0SQipeng Zha 		.pm     = &bxtwc_pm_ops,
58039d047c0SQipeng Zha 		.acpi_match_table = ACPI_PTR(bxtwc_acpi_ids),
581929a4d28SAndy Shevchenko 		.dev_groups = bxtwc_groups,
58239d047c0SQipeng Zha 	},
58339d047c0SQipeng Zha };
58439d047c0SQipeng Zha 
58539d047c0SQipeng Zha module_platform_driver(bxtwc_driver);
58639d047c0SQipeng Zha 
58739d047c0SQipeng Zha MODULE_LICENSE("GPL v2");
58839d047c0SQipeng Zha MODULE_AUTHOR("Qipeng Zha<qipeng.zha@intel.com>");
589