126c7e05aSAndy Shevchenko // SPDX-License-Identifier: GPL-2.0 2de85d79fSHans de Goede /* 3de85d79fSHans de Goede * MFD core driver for Intel Cherrytrail Whiskey Cove PMIC 4de85d79fSHans de Goede * 5de85d79fSHans de Goede * Copyright (C) 2017 Hans de Goede <hdegoede@redhat.com> 6de85d79fSHans de Goede * 7de85d79fSHans de Goede * Based on various non upstream patches to support the CHT Whiskey Cove PMIC: 8de85d79fSHans de Goede * Copyright (C) 2013-2015 Intel Corporation. All rights reserved. 9de85d79fSHans de Goede */ 10de85d79fSHans de Goede 11de85d79fSHans de Goede #include <linux/acpi.h> 12de85d79fSHans de Goede #include <linux/delay.h> 13de85d79fSHans de Goede #include <linux/err.h> 14de85d79fSHans de Goede #include <linux/i2c.h> 15de85d79fSHans de Goede #include <linux/interrupt.h> 16de85d79fSHans de Goede #include <linux/kernel.h> 17de85d79fSHans de Goede #include <linux/mfd/core.h> 18de85d79fSHans de Goede #include <linux/mfd/intel_soc_pmic.h> 19de85d79fSHans de Goede #include <linux/regmap.h> 20de85d79fSHans de Goede 21de85d79fSHans de Goede /* PMIC device registers */ 22de85d79fSHans de Goede #define REG_OFFSET_MASK GENMASK(7, 0) 23de85d79fSHans de Goede #define REG_ADDR_MASK GENMASK(15, 8) 24de85d79fSHans de Goede #define REG_ADDR_SHIFT 8 25de85d79fSHans de Goede 26de85d79fSHans de Goede #define CHT_WC_IRQLVL1 0x6e02 27de85d79fSHans de Goede #define CHT_WC_IRQLVL1_MASK 0x6e0e 28de85d79fSHans de Goede 29de85d79fSHans de Goede /* Whiskey Cove PMIC share same ACPI ID between different platforms */ 30de85d79fSHans de Goede #define CHT_WC_HRV 3 31de85d79fSHans de Goede 32de85d79fSHans de Goede /* Level 1 IRQs (level 2 IRQs are handled in the child device drivers) */ 33de85d79fSHans de Goede enum { 34de85d79fSHans de Goede CHT_WC_PWRSRC_IRQ = 0, 35de85d79fSHans de Goede CHT_WC_THRM_IRQ, 36de85d79fSHans de Goede CHT_WC_BCU_IRQ, 37de85d79fSHans de Goede CHT_WC_ADC_IRQ, 38de85d79fSHans de Goede CHT_WC_EXT_CHGR_IRQ, 39de85d79fSHans de Goede CHT_WC_GPIO_IRQ, 40de85d79fSHans de Goede /* There is no irq 6 */ 41de85d79fSHans de Goede CHT_WC_CRIT_IRQ = 7, 42de85d79fSHans de Goede }; 43de85d79fSHans de Goede 44de85d79fSHans de Goede static struct resource cht_wc_pwrsrc_resources[] = { 45de85d79fSHans de Goede DEFINE_RES_IRQ(CHT_WC_PWRSRC_IRQ), 46de85d79fSHans de Goede }; 47de85d79fSHans de Goede 48de85d79fSHans de Goede static struct resource cht_wc_ext_charger_resources[] = { 49de85d79fSHans de Goede DEFINE_RES_IRQ(CHT_WC_EXT_CHGR_IRQ), 50de85d79fSHans de Goede }; 51de85d79fSHans de Goede 52de85d79fSHans de Goede static struct mfd_cell cht_wc_dev[] = { 53de85d79fSHans de Goede { 54de85d79fSHans de Goede .name = "cht_wcove_pwrsrc", 55de85d79fSHans de Goede .num_resources = ARRAY_SIZE(cht_wc_pwrsrc_resources), 56de85d79fSHans de Goede .resources = cht_wc_pwrsrc_resources, 57de85d79fSHans de Goede }, { 58de85d79fSHans de Goede .name = "cht_wcove_ext_chgr", 59de85d79fSHans de Goede .num_resources = ARRAY_SIZE(cht_wc_ext_charger_resources), 60de85d79fSHans de Goede .resources = cht_wc_ext_charger_resources, 61de85d79fSHans de Goede }, 62de85d79fSHans de Goede { .name = "cht_wcove_region", }, 63236c765dSYauhen Kharuzhy { .name = "cht_wcove_leds", }, 64de85d79fSHans de Goede }; 65de85d79fSHans de Goede 66de85d79fSHans de Goede /* 67de85d79fSHans de Goede * The CHT Whiskey Cove covers multiple I2C addresses, with a 1 Byte 68de85d79fSHans de Goede * register address space per I2C address, so we use 16 bit register 69de85d79fSHans de Goede * addresses where the high 8 bits contain the I2C client address. 70de85d79fSHans de Goede */ 71de85d79fSHans de Goede static int cht_wc_byte_reg_read(void *context, unsigned int reg, 72de85d79fSHans de Goede unsigned int *val) 73de85d79fSHans de Goede { 74de85d79fSHans de Goede struct i2c_client *client = context; 75de85d79fSHans de Goede int ret, orig_addr = client->addr; 76de85d79fSHans de Goede 77de85d79fSHans de Goede if (!(reg & REG_ADDR_MASK)) { 78de85d79fSHans de Goede dev_err(&client->dev, "Error I2C address not specified\n"); 79de85d79fSHans de Goede return -EINVAL; 80de85d79fSHans de Goede } 81de85d79fSHans de Goede 82de85d79fSHans de Goede client->addr = (reg & REG_ADDR_MASK) >> REG_ADDR_SHIFT; 83de85d79fSHans de Goede ret = i2c_smbus_read_byte_data(client, reg & REG_OFFSET_MASK); 84de85d79fSHans de Goede client->addr = orig_addr; 85de85d79fSHans de Goede 86de85d79fSHans de Goede if (ret < 0) 87de85d79fSHans de Goede return ret; 88de85d79fSHans de Goede 89de85d79fSHans de Goede *val = ret; 90de85d79fSHans de Goede return 0; 91de85d79fSHans de Goede } 92de85d79fSHans de Goede 93de85d79fSHans de Goede static int cht_wc_byte_reg_write(void *context, unsigned int reg, 94de85d79fSHans de Goede unsigned int val) 95de85d79fSHans de Goede { 96de85d79fSHans de Goede struct i2c_client *client = context; 97de85d79fSHans de Goede int ret, orig_addr = client->addr; 98de85d79fSHans de Goede 99de85d79fSHans de Goede if (!(reg & REG_ADDR_MASK)) { 100de85d79fSHans de Goede dev_err(&client->dev, "Error I2C address not specified\n"); 101de85d79fSHans de Goede return -EINVAL; 102de85d79fSHans de Goede } 103de85d79fSHans de Goede 104de85d79fSHans de Goede client->addr = (reg & REG_ADDR_MASK) >> REG_ADDR_SHIFT; 105de85d79fSHans de Goede ret = i2c_smbus_write_byte_data(client, reg & REG_OFFSET_MASK, val); 106de85d79fSHans de Goede client->addr = orig_addr; 107de85d79fSHans de Goede 108de85d79fSHans de Goede return ret; 109de85d79fSHans de Goede } 110de85d79fSHans de Goede 111de85d79fSHans de Goede static const struct regmap_config cht_wc_regmap_cfg = { 112de85d79fSHans de Goede .reg_bits = 16, 113de85d79fSHans de Goede .val_bits = 8, 114de85d79fSHans de Goede .reg_write = cht_wc_byte_reg_write, 115de85d79fSHans de Goede .reg_read = cht_wc_byte_reg_read, 116de85d79fSHans de Goede }; 117de85d79fSHans de Goede 118de85d79fSHans de Goede static const struct regmap_irq cht_wc_regmap_irqs[] = { 119de85d79fSHans de Goede REGMAP_IRQ_REG(CHT_WC_PWRSRC_IRQ, 0, BIT(CHT_WC_PWRSRC_IRQ)), 120de85d79fSHans de Goede REGMAP_IRQ_REG(CHT_WC_THRM_IRQ, 0, BIT(CHT_WC_THRM_IRQ)), 121de85d79fSHans de Goede REGMAP_IRQ_REG(CHT_WC_BCU_IRQ, 0, BIT(CHT_WC_BCU_IRQ)), 122de85d79fSHans de Goede REGMAP_IRQ_REG(CHT_WC_ADC_IRQ, 0, BIT(CHT_WC_ADC_IRQ)), 123de85d79fSHans de Goede REGMAP_IRQ_REG(CHT_WC_EXT_CHGR_IRQ, 0, BIT(CHT_WC_EXT_CHGR_IRQ)), 124de85d79fSHans de Goede REGMAP_IRQ_REG(CHT_WC_GPIO_IRQ, 0, BIT(CHT_WC_GPIO_IRQ)), 125de85d79fSHans de Goede REGMAP_IRQ_REG(CHT_WC_CRIT_IRQ, 0, BIT(CHT_WC_CRIT_IRQ)), 126de85d79fSHans de Goede }; 127de85d79fSHans de Goede 128de85d79fSHans de Goede static const struct regmap_irq_chip cht_wc_regmap_irq_chip = { 129de85d79fSHans de Goede .name = "cht_wc_irq_chip", 130de85d79fSHans de Goede .status_base = CHT_WC_IRQLVL1, 131de85d79fSHans de Goede .mask_base = CHT_WC_IRQLVL1_MASK, 132de85d79fSHans de Goede .irqs = cht_wc_regmap_irqs, 133de85d79fSHans de Goede .num_irqs = ARRAY_SIZE(cht_wc_regmap_irqs), 134de85d79fSHans de Goede .num_regs = 1, 135de85d79fSHans de Goede }; 136de85d79fSHans de Goede 137de85d79fSHans de Goede static int cht_wc_probe(struct i2c_client *client) 138de85d79fSHans de Goede { 139de85d79fSHans de Goede struct device *dev = &client->dev; 140de85d79fSHans de Goede struct intel_soc_pmic *pmic; 141de85d79fSHans de Goede acpi_status status; 142de85d79fSHans de Goede unsigned long long hrv; 143de85d79fSHans de Goede int ret; 144de85d79fSHans de Goede 145de85d79fSHans de Goede status = acpi_evaluate_integer(ACPI_HANDLE(dev), "_HRV", NULL, &hrv); 146de85d79fSHans de Goede if (ACPI_FAILURE(status)) { 147de85d79fSHans de Goede dev_err(dev, "Failed to get PMIC hardware revision\n"); 148de85d79fSHans de Goede return -ENODEV; 149de85d79fSHans de Goede } 150de85d79fSHans de Goede if (hrv != CHT_WC_HRV) { 151de85d79fSHans de Goede dev_err(dev, "Invalid PMIC hardware revision: %llu\n", hrv); 152de85d79fSHans de Goede return -ENODEV; 153de85d79fSHans de Goede } 154de85d79fSHans de Goede if (client->irq < 0) { 155de85d79fSHans de Goede dev_err(dev, "Invalid IRQ\n"); 156de85d79fSHans de Goede return -EINVAL; 157de85d79fSHans de Goede } 158de85d79fSHans de Goede 159de85d79fSHans de Goede pmic = devm_kzalloc(dev, sizeof(*pmic), GFP_KERNEL); 160de85d79fSHans de Goede if (!pmic) 161de85d79fSHans de Goede return -ENOMEM; 162de85d79fSHans de Goede 163de85d79fSHans de Goede pmic->irq = client->irq; 164de85d79fSHans de Goede pmic->dev = dev; 165de85d79fSHans de Goede i2c_set_clientdata(client, pmic); 166de85d79fSHans de Goede 167de85d79fSHans de Goede pmic->regmap = devm_regmap_init(dev, NULL, client, &cht_wc_regmap_cfg); 168de85d79fSHans de Goede if (IS_ERR(pmic->regmap)) 169de85d79fSHans de Goede return PTR_ERR(pmic->regmap); 170de85d79fSHans de Goede 171de85d79fSHans de Goede ret = devm_regmap_add_irq_chip(dev, pmic->regmap, pmic->irq, 172de85d79fSHans de Goede IRQF_ONESHOT | IRQF_SHARED, 0, 173de85d79fSHans de Goede &cht_wc_regmap_irq_chip, 174de85d79fSHans de Goede &pmic->irq_chip_data); 175de85d79fSHans de Goede if (ret) 176de85d79fSHans de Goede return ret; 177de85d79fSHans de Goede 178de85d79fSHans de Goede return devm_mfd_add_devices(dev, PLATFORM_DEVID_NONE, 179de85d79fSHans de Goede cht_wc_dev, ARRAY_SIZE(cht_wc_dev), NULL, 0, 180de85d79fSHans de Goede regmap_irq_get_domain(pmic->irq_chip_data)); 181de85d79fSHans de Goede } 182de85d79fSHans de Goede 183de85d79fSHans de Goede static void cht_wc_shutdown(struct i2c_client *client) 184de85d79fSHans de Goede { 185de85d79fSHans de Goede struct intel_soc_pmic *pmic = i2c_get_clientdata(client); 186de85d79fSHans de Goede 187de85d79fSHans de Goede disable_irq(pmic->irq); 188de85d79fSHans de Goede } 189de85d79fSHans de Goede 190de85d79fSHans de Goede static int __maybe_unused cht_wc_suspend(struct device *dev) 191de85d79fSHans de Goede { 192de85d79fSHans de Goede struct intel_soc_pmic *pmic = dev_get_drvdata(dev); 193de85d79fSHans de Goede 194de85d79fSHans de Goede disable_irq(pmic->irq); 195de85d79fSHans de Goede 196de85d79fSHans de Goede return 0; 197de85d79fSHans de Goede } 198de85d79fSHans de Goede 199de85d79fSHans de Goede static int __maybe_unused cht_wc_resume(struct device *dev) 200de85d79fSHans de Goede { 201de85d79fSHans de Goede struct intel_soc_pmic *pmic = dev_get_drvdata(dev); 202de85d79fSHans de Goede 203de85d79fSHans de Goede enable_irq(pmic->irq); 204de85d79fSHans de Goede 205de85d79fSHans de Goede return 0; 206de85d79fSHans de Goede } 207de85d79fSHans de Goede static SIMPLE_DEV_PM_OPS(cht_wc_pm_ops, cht_wc_suspend, cht_wc_resume); 208de85d79fSHans de Goede 209de85d79fSHans de Goede static const struct i2c_device_id cht_wc_i2c_id[] = { 210de85d79fSHans de Goede { } 211de85d79fSHans de Goede }; 212de85d79fSHans de Goede 213de85d79fSHans de Goede static const struct acpi_device_id cht_wc_acpi_ids[] = { 214de85d79fSHans de Goede { "INT34D3", }, 215de85d79fSHans de Goede { } 216de85d79fSHans de Goede }; 217de85d79fSHans de Goede 218de85d79fSHans de Goede static struct i2c_driver cht_wc_driver = { 219de85d79fSHans de Goede .driver = { 220de85d79fSHans de Goede .name = "CHT Whiskey Cove PMIC", 221de85d79fSHans de Goede .pm = &cht_wc_pm_ops, 222de85d79fSHans de Goede .acpi_match_table = cht_wc_acpi_ids, 223de85d79fSHans de Goede }, 224de85d79fSHans de Goede .probe_new = cht_wc_probe, 225de85d79fSHans de Goede .shutdown = cht_wc_shutdown, 226de85d79fSHans de Goede .id_table = cht_wc_i2c_id, 227de85d79fSHans de Goede }; 228de85d79fSHans de Goede builtin_i2c_driver(cht_wc_driver); 229