brintos

brintos / linux-shallow public Read only

0
0
Text · 7.2 KiB · 876d017 Raw
278 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * Device access for Crystal Cove PMIC4 *5 * Copyright (C) 2012-2014, 2022 Intel Corporation. All rights reserved.6 *7 * Author: Yang, Bin <bin.yang@intel.com>8 * Author: Zhu, Lejun <lejun.zhu@linux.intel.com>9 */10 11#include <linux/i2c.h>12#include <linux/interrupt.h>13#include <linux/mod_devicetable.h>14#include <linux/module.h>15#include <linux/mfd/core.h>16#include <linux/mfd/intel_soc_pmic.h>17#include <linux/platform_data/x86/soc.h>18#include <linux/pwm.h>19#include <linux/regmap.h>20 21#define CRYSTAL_COVE_MAX_REGISTER	0xC622 23#define CRYSTAL_COVE_REG_IRQLVL1	0x0224#define CRYSTAL_COVE_REG_MIRQLVL1	0x0E25 26#define CRYSTAL_COVE_IRQ_PWRSRC		027#define CRYSTAL_COVE_IRQ_THRM		128#define CRYSTAL_COVE_IRQ_BCU		229#define CRYSTAL_COVE_IRQ_ADC		330#define CRYSTAL_COVE_IRQ_CHGR		431#define CRYSTAL_COVE_IRQ_GPIO		532#define CRYSTAL_COVE_IRQ_VHDMIOCP	633 34static const struct resource pwrsrc_resources[] = {35	DEFINE_RES_IRQ_NAMED(CRYSTAL_COVE_IRQ_PWRSRC, "PWRSRC"),36};37 38static const struct resource thermal_resources[] = {39	DEFINE_RES_IRQ_NAMED(CRYSTAL_COVE_IRQ_THRM, "THERMAL"),40};41 42static const struct resource bcu_resources[] = {43	DEFINE_RES_IRQ_NAMED(CRYSTAL_COVE_IRQ_BCU, "BCU"),44};45 46static const struct resource adc_resources[] = {47	DEFINE_RES_IRQ_NAMED(CRYSTAL_COVE_IRQ_ADC, "ADC"),48};49 50static const struct resource charger_resources[] = {51	DEFINE_RES_IRQ_NAMED(CRYSTAL_COVE_IRQ_CHGR, "CHGR"),52};53 54static const struct resource gpio_resources[] = {55	DEFINE_RES_IRQ_NAMED(CRYSTAL_COVE_IRQ_GPIO, "GPIO"),56};57 58static struct mfd_cell crystal_cove_byt_dev[] = {59	{60		.name = "crystal_cove_pwrsrc",61		.num_resources = ARRAY_SIZE(pwrsrc_resources),62		.resources = pwrsrc_resources,63	},64	{65		.name = "crystal_cove_thermal",66		.num_resources = ARRAY_SIZE(thermal_resources),67		.resources = thermal_resources,68	},69	{70		.name = "crystal_cove_bcu",71		.num_resources = ARRAY_SIZE(bcu_resources),72		.resources = bcu_resources,73	},74	{75		.name = "crystal_cove_adc",76		.num_resources = ARRAY_SIZE(adc_resources),77		.resources = adc_resources,78	},79	{80		.name = "crystal_cove_charger",81		.num_resources = ARRAY_SIZE(charger_resources),82		.resources = charger_resources,83	},84	{85		.name = "crystal_cove_gpio",86		.num_resources = ARRAY_SIZE(gpio_resources),87		.resources = gpio_resources,88	},89	{90		.name = "byt_crystal_cove_pmic",91	},92	{93		.name = "crystal_cove_pwm",94	},95};96 97static struct mfd_cell crystal_cove_cht_dev[] = {98	{99		.name = "crystal_cove_gpio",100		.num_resources = ARRAY_SIZE(gpio_resources),101		.resources = gpio_resources,102	},103	{104		.name = "cht_crystal_cove_pmic",105	},106	{107		.name = "crystal_cove_pwm",108	},109};110 111static const struct regmap_config crystal_cove_regmap_config = {112	.reg_bits = 8,113	.val_bits = 8,114 115	.max_register = CRYSTAL_COVE_MAX_REGISTER,116	.cache_type = REGCACHE_NONE,117};118 119static const struct regmap_irq crystal_cove_irqs[] = {120	REGMAP_IRQ_REG(CRYSTAL_COVE_IRQ_PWRSRC, 0, BIT(CRYSTAL_COVE_IRQ_PWRSRC)),121	REGMAP_IRQ_REG(CRYSTAL_COVE_IRQ_THRM, 0, BIT(CRYSTAL_COVE_IRQ_THRM)),122	REGMAP_IRQ_REG(CRYSTAL_COVE_IRQ_BCU, 0, BIT(CRYSTAL_COVE_IRQ_BCU)),123	REGMAP_IRQ_REG(CRYSTAL_COVE_IRQ_ADC, 0, BIT(CRYSTAL_COVE_IRQ_ADC)),124	REGMAP_IRQ_REG(CRYSTAL_COVE_IRQ_CHGR, 0, BIT(CRYSTAL_COVE_IRQ_CHGR)),125	REGMAP_IRQ_REG(CRYSTAL_COVE_IRQ_GPIO, 0, BIT(CRYSTAL_COVE_IRQ_GPIO)),126	REGMAP_IRQ_REG(CRYSTAL_COVE_IRQ_VHDMIOCP, 0, BIT(CRYSTAL_COVE_IRQ_VHDMIOCP)),127};128 129static const struct regmap_irq_chip crystal_cove_irq_chip = {130	.name = "Crystal Cove",131	.irqs = crystal_cove_irqs,132	.num_irqs = ARRAY_SIZE(crystal_cove_irqs),133	.num_regs = 1,134	.status_base = CRYSTAL_COVE_REG_IRQLVL1,135	.mask_base = CRYSTAL_COVE_REG_MIRQLVL1,136};137 138/* PWM consumed by the Intel GFX */139static struct pwm_lookup crc_pwm_lookup[] = {140	PWM_LOOKUP_WITH_MODULE("crystal_cove_pwm", 0, "0000:00:02.0",141			       "pwm_pmic_backlight", 0, PWM_POLARITY_NORMAL,142			       "pwm-crc"),143};144 145struct crystal_cove_config {146	unsigned long irq_flags;147	struct mfd_cell *cell_dev;148	int n_cell_devs;149	const struct regmap_config *regmap_config;150	const struct regmap_irq_chip *irq_chip;151};152 153static const struct crystal_cove_config crystal_cove_config_byt_crc = {154	.irq_flags = IRQF_TRIGGER_RISING,155	.cell_dev = crystal_cove_byt_dev,156	.n_cell_devs = ARRAY_SIZE(crystal_cove_byt_dev),157	.regmap_config = &crystal_cove_regmap_config,158	.irq_chip = &crystal_cove_irq_chip,159};160 161static const struct crystal_cove_config crystal_cove_config_cht_crc = {162	.irq_flags = IRQF_TRIGGER_RISING,163	.cell_dev = crystal_cove_cht_dev,164	.n_cell_devs = ARRAY_SIZE(crystal_cove_cht_dev),165	.regmap_config = &crystal_cove_regmap_config,166	.irq_chip = &crystal_cove_irq_chip,167};168 169static int crystal_cove_i2c_probe(struct i2c_client *i2c)170{171	const struct crystal_cove_config *config;172	struct device *dev = &i2c->dev;173	struct intel_soc_pmic *pmic;174	int ret;175 176	if (soc_intel_is_byt())177		config = &crystal_cove_config_byt_crc;178	else179		config = &crystal_cove_config_cht_crc;180 181	pmic = devm_kzalloc(dev, sizeof(*pmic), GFP_KERNEL);182	if (!pmic)183		return -ENOMEM;184 185	i2c_set_clientdata(i2c, pmic);186 187	pmic->regmap = devm_regmap_init_i2c(i2c, config->regmap_config);188	if (IS_ERR(pmic->regmap))189		return PTR_ERR(pmic->regmap);190 191	pmic->irq = i2c->irq;192 193	ret = devm_regmap_add_irq_chip(dev, pmic->regmap, pmic->irq,194				       config->irq_flags | IRQF_ONESHOT,195				       0, config->irq_chip, &pmic->irq_chip_data);196	if (ret)197		return ret;198 199	ret = enable_irq_wake(pmic->irq);200	if (ret)201		dev_warn(dev, "Can't enable IRQ as wake source: %d\n", ret);202 203	/* Add lookup table for crc-pwm */204	pwm_add_table(crc_pwm_lookup, ARRAY_SIZE(crc_pwm_lookup));205 206	/* To distuingish this domain from the GPIO/charger's irqchip domains */207	irq_domain_update_bus_token(regmap_irq_get_domain(pmic->irq_chip_data),208				    DOMAIN_BUS_NEXUS);209 210	ret = mfd_add_devices(dev, PLATFORM_DEVID_NONE, config->cell_dev,211			      config->n_cell_devs, NULL, 0,212			      regmap_irq_get_domain(pmic->irq_chip_data));213	if (ret)214		pwm_remove_table(crc_pwm_lookup, ARRAY_SIZE(crc_pwm_lookup));215 216	return ret;217}218 219static void crystal_cove_i2c_remove(struct i2c_client *i2c)220{221	/* remove crc-pwm lookup table */222	pwm_remove_table(crc_pwm_lookup, ARRAY_SIZE(crc_pwm_lookup));223 224	mfd_remove_devices(&i2c->dev);225}226 227static void crystal_cove_shutdown(struct i2c_client *i2c)228{229	struct intel_soc_pmic *pmic = i2c_get_clientdata(i2c);230 231	disable_irq(pmic->irq);232 233	return;234}235 236static int crystal_cove_suspend(struct device *dev)237{238	struct intel_soc_pmic *pmic = dev_get_drvdata(dev);239 240	disable_irq(pmic->irq);241 242	return 0;243}244 245static int crystal_cove_resume(struct device *dev)246{247	struct intel_soc_pmic *pmic = dev_get_drvdata(dev);248 249	enable_irq(pmic->irq);250 251	return 0;252}253 254static DEFINE_SIMPLE_DEV_PM_OPS(crystal_cove_pm_ops, crystal_cove_suspend, crystal_cove_resume);255 256static const struct acpi_device_id crystal_cove_acpi_match[] = {257	{ "INT33FD" },258	{ },259};260MODULE_DEVICE_TABLE(acpi, crystal_cove_acpi_match);261 262static struct i2c_driver crystal_cove_i2c_driver = {263	.driver = {264		.name = "crystal_cove_i2c",265		.pm = pm_sleep_ptr(&crystal_cove_pm_ops),266		.acpi_match_table = crystal_cove_acpi_match,267	},268	.probe = crystal_cove_i2c_probe,269	.remove = crystal_cove_i2c_remove,270	.shutdown = crystal_cove_shutdown,271};272 273module_i2c_driver(crystal_cove_i2c_driver);274 275MODULE_DESCRIPTION("I2C driver for Intel SoC PMIC");276MODULE_AUTHOR("Yang, Bin <bin.yang@intel.com>");277MODULE_AUTHOR("Zhu, Lejun <lejun.zhu@linux.intel.com>");278