126c7e05aSAndy Shevchenko // SPDX-License-Identifier: GPL-2.0
27cf0a66fSZhu, Lejun /*
326c7e05aSAndy Shevchenko  * Device access for Crystal Cove PMIC
47cf0a66fSZhu, Lejun  *
503f271b0SAndy Shevchenko  * Copyright (C) 2012-2014, 2022 Intel Corporation. All rights reserved.
67cf0a66fSZhu, Lejun  *
77cf0a66fSZhu, Lejun  * Author: Yang, Bin <bin.yang@intel.com>
87cf0a66fSZhu, Lejun  * Author: Zhu, Lejun <lejun.zhu@linux.intel.com>
97cf0a66fSZhu, Lejun  */
107cf0a66fSZhu, Lejun 
115a30b210SAndy Shevchenko #include <linux/i2c.h>
127cf0a66fSZhu, Lejun #include <linux/interrupt.h>
1309c4e702SAndy Shevchenko #include <linux/mod_devicetable.h>
145a30b210SAndy Shevchenko #include <linux/module.h>
1551eeee8eSAndy Shevchenko #include <linux/mfd/core.h>
167cf0a66fSZhu, Lejun #include <linux/mfd/intel_soc_pmic.h>
175a30b210SAndy Shevchenko #include <linux/platform_data/x86/soc.h>
185a30b210SAndy Shevchenko #include <linux/pwm.h>
195a30b210SAndy Shevchenko #include <linux/regmap.h>
207cf0a66fSZhu, Lejun 
217cf0a66fSZhu, Lejun #define CRYSTAL_COVE_MAX_REGISTER	0xC6
227cf0a66fSZhu, Lejun 
237cf0a66fSZhu, Lejun #define CRYSTAL_COVE_REG_IRQLVL1	0x02
247cf0a66fSZhu, Lejun #define CRYSTAL_COVE_REG_MIRQLVL1	0x0E
257cf0a66fSZhu, Lejun 
267cf0a66fSZhu, Lejun #define CRYSTAL_COVE_IRQ_PWRSRC		0
277cf0a66fSZhu, Lejun #define CRYSTAL_COVE_IRQ_THRM		1
287cf0a66fSZhu, Lejun #define CRYSTAL_COVE_IRQ_BCU		2
297cf0a66fSZhu, Lejun #define CRYSTAL_COVE_IRQ_ADC		3
307cf0a66fSZhu, Lejun #define CRYSTAL_COVE_IRQ_CHGR		4
317cf0a66fSZhu, Lejun #define CRYSTAL_COVE_IRQ_GPIO		5
327cf0a66fSZhu, Lejun #define CRYSTAL_COVE_IRQ_VHDMIOCP	6
337cf0a66fSZhu, Lejun 
34bf4cceb6SRikard Falkeborn static const struct resource pwrsrc_resources[] = {
350ce8ea71SAndy Shevchenko 	DEFINE_RES_IRQ_NAMED(CRYSTAL_COVE_IRQ_PWRSRC, "PWRSRC"),
367cf0a66fSZhu, Lejun };
377cf0a66fSZhu, Lejun 
38bf4cceb6SRikard Falkeborn static const struct resource thermal_resources[] = {
390ce8ea71SAndy Shevchenko 	DEFINE_RES_IRQ_NAMED(CRYSTAL_COVE_IRQ_THRM, "THERMAL"),
407cf0a66fSZhu, Lejun };
417cf0a66fSZhu, Lejun 
42bf4cceb6SRikard Falkeborn static const struct resource bcu_resources[] = {
430ce8ea71SAndy Shevchenko 	DEFINE_RES_IRQ_NAMED(CRYSTAL_COVE_IRQ_BCU, "BCU"),
447cf0a66fSZhu, Lejun };
457cf0a66fSZhu, Lejun 
464946d58dSHans de Goede static const struct resource adc_resources[] = {
474946d58dSHans de Goede 	DEFINE_RES_IRQ_NAMED(CRYSTAL_COVE_IRQ_ADC, "ADC"),
484946d58dSHans de Goede };
494946d58dSHans de Goede 
5050904e9bSHans de Goede static const struct resource charger_resources[] = {
5150904e9bSHans de Goede 	DEFINE_RES_IRQ_NAMED(CRYSTAL_COVE_IRQ_CHGR, "CHGR"),
5250904e9bSHans de Goede };
5350904e9bSHans de Goede 
544946d58dSHans de Goede static const struct resource gpio_resources[] = {
554946d58dSHans de Goede 	DEFINE_RES_IRQ_NAMED(CRYSTAL_COVE_IRQ_GPIO, "GPIO"),
564946d58dSHans de Goede };
574946d58dSHans de Goede 
584d9ed62aSHans de Goede static struct mfd_cell crystal_cove_byt_dev[] = {
597cf0a66fSZhu, Lejun 	{
607cf0a66fSZhu, Lejun 		.name = "crystal_cove_pwrsrc",
617cf0a66fSZhu, Lejun 		.num_resources = ARRAY_SIZE(pwrsrc_resources),
627cf0a66fSZhu, Lejun 		.resources = pwrsrc_resources,
637cf0a66fSZhu, Lejun 	},
647cf0a66fSZhu, Lejun 	{
657cf0a66fSZhu, Lejun 		.name = "crystal_cove_thermal",
667cf0a66fSZhu, Lejun 		.num_resources = ARRAY_SIZE(thermal_resources),
677cf0a66fSZhu, Lejun 		.resources = thermal_resources,
687cf0a66fSZhu, Lejun 	},
697cf0a66fSZhu, Lejun 	{
707cf0a66fSZhu, Lejun 		.name = "crystal_cove_bcu",
717cf0a66fSZhu, Lejun 		.num_resources = ARRAY_SIZE(bcu_resources),
727cf0a66fSZhu, Lejun 		.resources = bcu_resources,
737cf0a66fSZhu, Lejun 	},
747cf0a66fSZhu, Lejun 	{
754946d58dSHans de Goede 		.name = "crystal_cove_adc",
764946d58dSHans de Goede 		.num_resources = ARRAY_SIZE(adc_resources),
774946d58dSHans de Goede 		.resources = adc_resources,
784946d58dSHans de Goede 	},
794946d58dSHans de Goede 	{
8050904e9bSHans de Goede 		.name = "crystal_cove_charger",
8150904e9bSHans de Goede 		.num_resources = ARRAY_SIZE(charger_resources),
8250904e9bSHans de Goede 		.resources = charger_resources,
8350904e9bSHans de Goede 	},
8450904e9bSHans de Goede 	{
857cf0a66fSZhu, Lejun 		.name = "crystal_cove_gpio",
867cf0a66fSZhu, Lejun 		.num_resources = ARRAY_SIZE(gpio_resources),
877cf0a66fSZhu, Lejun 		.resources = gpio_resources,
887cf0a66fSZhu, Lejun 	},
89b1eea857SAaron Lu 	{
90ed852cdeSHans de Goede 		.name = "byt_crystal_cove_pmic",
91b1eea857SAaron Lu 	},
923d5e10ecSShobhit Kumar 	{
933d5e10ecSShobhit Kumar 		.name = "crystal_cove_pwm",
943d5e10ecSShobhit Kumar 	},
957cf0a66fSZhu, Lejun };
967cf0a66fSZhu, Lejun 
974d9ed62aSHans de Goede static struct mfd_cell crystal_cove_cht_dev[] = {
984d9ed62aSHans de Goede 	{
994d9ed62aSHans de Goede 		.name = "crystal_cove_gpio",
1004d9ed62aSHans de Goede 		.num_resources = ARRAY_SIZE(gpio_resources),
1014d9ed62aSHans de Goede 		.resources = gpio_resources,
1024d9ed62aSHans de Goede 	},
1034d9ed62aSHans de Goede 	{
10436f1b26bSHans de Goede 		.name = "cht_crystal_cove_pmic",
10536f1b26bSHans de Goede 	},
10636f1b26bSHans de Goede 	{
1074d9ed62aSHans de Goede 		.name = "crystal_cove_pwm",
1084d9ed62aSHans de Goede 	},
1094d9ed62aSHans de Goede };
1104d9ed62aSHans de Goede 
111172cb301SKrzysztof Kozlowski static const struct regmap_config crystal_cove_regmap_config = {
1127cf0a66fSZhu, Lejun 	.reg_bits = 8,
1137cf0a66fSZhu, Lejun 	.val_bits = 8,
1147cf0a66fSZhu, Lejun 
1157cf0a66fSZhu, Lejun 	.max_register = CRYSTAL_COVE_MAX_REGISTER,
1167cf0a66fSZhu, Lejun 	.cache_type = REGCACHE_NONE,
1177cf0a66fSZhu, Lejun };
1187cf0a66fSZhu, Lejun 
1197cf0a66fSZhu, Lejun static const struct regmap_irq crystal_cove_irqs[] = {
1208bd2d03eSAndy Shevchenko 	REGMAP_IRQ_REG(CRYSTAL_COVE_IRQ_PWRSRC, 0, BIT(CRYSTAL_COVE_IRQ_PWRSRC)),
1218bd2d03eSAndy Shevchenko 	REGMAP_IRQ_REG(CRYSTAL_COVE_IRQ_THRM, 0, BIT(CRYSTAL_COVE_IRQ_THRM)),
1228bd2d03eSAndy Shevchenko 	REGMAP_IRQ_REG(CRYSTAL_COVE_IRQ_BCU, 0, BIT(CRYSTAL_COVE_IRQ_BCU)),
1238bd2d03eSAndy Shevchenko 	REGMAP_IRQ_REG(CRYSTAL_COVE_IRQ_ADC, 0, BIT(CRYSTAL_COVE_IRQ_ADC)),
1248bd2d03eSAndy Shevchenko 	REGMAP_IRQ_REG(CRYSTAL_COVE_IRQ_CHGR, 0, BIT(CRYSTAL_COVE_IRQ_CHGR)),
1258bd2d03eSAndy Shevchenko 	REGMAP_IRQ_REG(CRYSTAL_COVE_IRQ_GPIO, 0, BIT(CRYSTAL_COVE_IRQ_GPIO)),
1268bd2d03eSAndy Shevchenko 	REGMAP_IRQ_REG(CRYSTAL_COVE_IRQ_VHDMIOCP, 0, BIT(CRYSTAL_COVE_IRQ_VHDMIOCP)),
1277cf0a66fSZhu, Lejun };
1287cf0a66fSZhu, Lejun 
1297ce7b26fSKrzysztof Kozlowski static const struct regmap_irq_chip crystal_cove_irq_chip = {
1307cf0a66fSZhu, Lejun 	.name = "Crystal Cove",
1317cf0a66fSZhu, Lejun 	.irqs = crystal_cove_irqs,
1327cf0a66fSZhu, Lejun 	.num_irqs = ARRAY_SIZE(crystal_cove_irqs),
1337cf0a66fSZhu, Lejun 	.num_regs = 1,
1347cf0a66fSZhu, Lejun 	.status_base = CRYSTAL_COVE_REG_IRQLVL1,
1357cf0a66fSZhu, Lejun 	.mask_base = CRYSTAL_COVE_REG_MIRQLVL1,
1367cf0a66fSZhu, Lejun };
1377cf0a66fSZhu, Lejun 
1385a30b210SAndy Shevchenko /* PWM consumed by the Intel GFX */
1395a30b210SAndy Shevchenko static struct pwm_lookup crc_pwm_lookup[] = {
1405a30b210SAndy Shevchenko 	PWM_LOOKUP("crystal_cove_pwm", 0, "0000:00:02.0", "pwm_pmic_backlight", 0, PWM_POLARITY_NORMAL),
1415a30b210SAndy Shevchenko };
1425a30b210SAndy Shevchenko 
14339c8980cSAndy Shevchenko struct crystal_cove_config {
1445a30b210SAndy Shevchenko 	unsigned long irq_flags;
1455a30b210SAndy Shevchenko 	struct mfd_cell *cell_dev;
1465a30b210SAndy Shevchenko 	int n_cell_devs;
1475a30b210SAndy Shevchenko 	const struct regmap_config *regmap_config;
1485a30b210SAndy Shevchenko 	const struct regmap_irq_chip *irq_chip;
1495a30b210SAndy Shevchenko };
1505a30b210SAndy Shevchenko 
15139c8980cSAndy Shevchenko static const struct crystal_cove_config crystal_cove_config_byt_crc = {
1527cf0a66fSZhu, Lejun 	.irq_flags = IRQF_TRIGGER_RISING,
1534d9ed62aSHans de Goede 	.cell_dev = crystal_cove_byt_dev,
1544d9ed62aSHans de Goede 	.n_cell_devs = ARRAY_SIZE(crystal_cove_byt_dev),
1554d9ed62aSHans de Goede 	.regmap_config = &crystal_cove_regmap_config,
1564d9ed62aSHans de Goede 	.irq_chip = &crystal_cove_irq_chip,
1574d9ed62aSHans de Goede };
1584d9ed62aSHans de Goede 
15939c8980cSAndy Shevchenko static const struct crystal_cove_config crystal_cove_config_cht_crc = {
1604d9ed62aSHans de Goede 	.irq_flags = IRQF_TRIGGER_RISING,
1614d9ed62aSHans de Goede 	.cell_dev = crystal_cove_cht_dev,
1624d9ed62aSHans de Goede 	.n_cell_devs = ARRAY_SIZE(crystal_cove_cht_dev),
1637cf0a66fSZhu, Lejun 	.regmap_config = &crystal_cove_regmap_config,
1647cf0a66fSZhu, Lejun 	.irq_chip = &crystal_cove_irq_chip,
1657cf0a66fSZhu, Lejun };
1665a30b210SAndy Shevchenko 
crystal_cove_i2c_probe(struct i2c_client * i2c)16739c8980cSAndy Shevchenko static int crystal_cove_i2c_probe(struct i2c_client *i2c)
1685a30b210SAndy Shevchenko {
16939c8980cSAndy Shevchenko 	const struct crystal_cove_config *config;
1705a30b210SAndy Shevchenko 	struct device *dev = &i2c->dev;
1715a30b210SAndy Shevchenko 	struct intel_soc_pmic *pmic;
1725a30b210SAndy Shevchenko 	int ret;
1735a30b210SAndy Shevchenko 
1745a30b210SAndy Shevchenko 	if (soc_intel_is_byt())
17539c8980cSAndy Shevchenko 		config = &crystal_cove_config_byt_crc;
1765a30b210SAndy Shevchenko 	else
17739c8980cSAndy Shevchenko 		config = &crystal_cove_config_cht_crc;
1785a30b210SAndy Shevchenko 
1795a30b210SAndy Shevchenko 	pmic = devm_kzalloc(dev, sizeof(*pmic), GFP_KERNEL);
1805a30b210SAndy Shevchenko 	if (!pmic)
1815a30b210SAndy Shevchenko 		return -ENOMEM;
1825a30b210SAndy Shevchenko 
1834b74ec58SAndy Shevchenko 	i2c_set_clientdata(i2c, pmic);
1845a30b210SAndy Shevchenko 
1855a30b210SAndy Shevchenko 	pmic->regmap = devm_regmap_init_i2c(i2c, config->regmap_config);
1865a30b210SAndy Shevchenko 	if (IS_ERR(pmic->regmap))
1875a30b210SAndy Shevchenko 		return PTR_ERR(pmic->regmap);
1885a30b210SAndy Shevchenko 
1895a30b210SAndy Shevchenko 	pmic->irq = i2c->irq;
1905a30b210SAndy Shevchenko 
191cae02b7aSAndy Shevchenko 	ret = devm_regmap_add_irq_chip(dev, pmic->regmap, pmic->irq,
1925a30b210SAndy Shevchenko 				       config->irq_flags | IRQF_ONESHOT,
193cae02b7aSAndy Shevchenko 				       0, config->irq_chip, &pmic->irq_chip_data);
1945a30b210SAndy Shevchenko 	if (ret)
1955a30b210SAndy Shevchenko 		return ret;
1965a30b210SAndy Shevchenko 
1975a30b210SAndy Shevchenko 	ret = enable_irq_wake(pmic->irq);
1985a30b210SAndy Shevchenko 	if (ret)
1995a30b210SAndy Shevchenko 		dev_warn(dev, "Can't enable IRQ as wake source: %d\n", ret);
2005a30b210SAndy Shevchenko 
2015a30b210SAndy Shevchenko 	/* Add lookup table for crc-pwm */
2025a30b210SAndy Shevchenko 	pwm_add_table(crc_pwm_lookup, ARRAY_SIZE(crc_pwm_lookup));
2035a30b210SAndy Shevchenko 
2045a30b210SAndy Shevchenko 	/* To distuingish this domain from the GPIO/charger's irqchip domains */
2055a30b210SAndy Shevchenko 	irq_domain_update_bus_token(regmap_irq_get_domain(pmic->irq_chip_data),
2065a30b210SAndy Shevchenko 				    DOMAIN_BUS_NEXUS);
2075a30b210SAndy Shevchenko 
208cae02b7aSAndy Shevchenko 	ret = mfd_add_devices(dev, PLATFORM_DEVID_NONE, config->cell_dev,
2095a30b210SAndy Shevchenko 			      config->n_cell_devs, NULL, 0,
2105a30b210SAndy Shevchenko 			      regmap_irq_get_domain(pmic->irq_chip_data));
2115a30b210SAndy Shevchenko 	if (ret)
2125a30b210SAndy Shevchenko 		pwm_remove_table(crc_pwm_lookup, ARRAY_SIZE(crc_pwm_lookup));
213cae02b7aSAndy Shevchenko 
2145a30b210SAndy Shevchenko 	return ret;
2155a30b210SAndy Shevchenko }
2165a30b210SAndy Shevchenko 
crystal_cove_i2c_remove(struct i2c_client * i2c)217ae955959SLinus Torvalds static void crystal_cove_i2c_remove(struct i2c_client *i2c)
2185a30b210SAndy Shevchenko {
2195a30b210SAndy Shevchenko 	/* remove crc-pwm lookup table */
2205a30b210SAndy Shevchenko 	pwm_remove_table(crc_pwm_lookup, ARRAY_SIZE(crc_pwm_lookup));
2215a30b210SAndy Shevchenko 
2225a30b210SAndy Shevchenko 	mfd_remove_devices(&i2c->dev);
2235a30b210SAndy Shevchenko }
2245a30b210SAndy Shevchenko 
crystal_cove_shutdown(struct i2c_client * i2c)22539c8980cSAndy Shevchenko static void crystal_cove_shutdown(struct i2c_client *i2c)
2265a30b210SAndy Shevchenko {
2274b74ec58SAndy Shevchenko 	struct intel_soc_pmic *pmic = i2c_get_clientdata(i2c);
2285a30b210SAndy Shevchenko 
2295a30b210SAndy Shevchenko 	disable_irq(pmic->irq);
2305a30b210SAndy Shevchenko 
2315a30b210SAndy Shevchenko 	return;
2325a30b210SAndy Shevchenko }
2335a30b210SAndy Shevchenko 
crystal_cove_suspend(struct device * dev)23439c8980cSAndy Shevchenko static int crystal_cove_suspend(struct device *dev)
2355a30b210SAndy Shevchenko {
2365a30b210SAndy Shevchenko 	struct intel_soc_pmic *pmic = dev_get_drvdata(dev);
2375a30b210SAndy Shevchenko 
2385a30b210SAndy Shevchenko 	disable_irq(pmic->irq);
2395a30b210SAndy Shevchenko 
2405a30b210SAndy Shevchenko 	return 0;
2415a30b210SAndy Shevchenko }
2425a30b210SAndy Shevchenko 
crystal_cove_resume(struct device * dev)24339c8980cSAndy Shevchenko static int crystal_cove_resume(struct device *dev)
2445a30b210SAndy Shevchenko {
2455a30b210SAndy Shevchenko 	struct intel_soc_pmic *pmic = dev_get_drvdata(dev);
2465a30b210SAndy Shevchenko 
2475a30b210SAndy Shevchenko 	enable_irq(pmic->irq);
2485a30b210SAndy Shevchenko 
2495a30b210SAndy Shevchenko 	return 0;
2505a30b210SAndy Shevchenko }
2515a30b210SAndy Shevchenko 
25239c8980cSAndy Shevchenko static DEFINE_SIMPLE_DEV_PM_OPS(crystal_cove_pm_ops, crystal_cove_suspend, crystal_cove_resume);
2535a30b210SAndy Shevchenko 
25439c8980cSAndy Shevchenko static const struct acpi_device_id crystal_cove_acpi_match[] = {
2555a30b210SAndy Shevchenko 	{ "INT33FD" },
2565a30b210SAndy Shevchenko 	{ },
2575a30b210SAndy Shevchenko };
25839c8980cSAndy Shevchenko MODULE_DEVICE_TABLE(acpi, crystal_cove_acpi_match);
2595a30b210SAndy Shevchenko 
26039c8980cSAndy Shevchenko static struct i2c_driver crystal_cove_i2c_driver = {
2615a30b210SAndy Shevchenko 	.driver = {
26239c8980cSAndy Shevchenko 		.name = "crystal_cove_i2c",
263e1efbc8eSAndy Shevchenko 		.pm = pm_sleep_ptr(&crystal_cove_pm_ops),
26439c8980cSAndy Shevchenko 		.acpi_match_table = crystal_cove_acpi_match,
2655a30b210SAndy Shevchenko 	},
266*9816d859SUwe Kleine-König 	.probe = crystal_cove_i2c_probe,
26739c8980cSAndy Shevchenko 	.remove = crystal_cove_i2c_remove,
26839c8980cSAndy Shevchenko 	.shutdown = crystal_cove_shutdown,
2695a30b210SAndy Shevchenko };
2705a30b210SAndy Shevchenko 
27139c8980cSAndy Shevchenko module_i2c_driver(crystal_cove_i2c_driver);
2725a30b210SAndy Shevchenko 
2735a30b210SAndy Shevchenko MODULE_DESCRIPTION("I2C driver for Intel SoC PMIC");
2745a30b210SAndy Shevchenko MODULE_AUTHOR("Yang, Bin <bin.yang@intel.com>");
2755a30b210SAndy Shevchenko MODULE_AUTHOR("Zhu, Lejun <lejun.zhu@linux.intel.com>");
276