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