1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * MFD core driver for Intel Cherrytrail Whiskey Cove PMIC 4 * 5 * Copyright (C) 2017 Hans de Goede <hdegoede@redhat.com> 6 * 7 * Based on various non upstream patches to support the CHT Whiskey Cove PMIC: 8 * Copyright (C) 2013-2015 Intel Corporation. All rights reserved. 9 */ 10 11 #include <linux/acpi.h> 12 #include <linux/delay.h> 13 #include <linux/dmi.h> 14 #include <linux/err.h> 15 #include <linux/i2c.h> 16 #include <linux/interrupt.h> 17 #include <linux/kernel.h> 18 #include <linux/mfd/core.h> 19 #include <linux/mfd/intel_soc_pmic.h> 20 #include <linux/regmap.h> 21 22 /* PMIC device registers */ 23 #define REG_OFFSET_MASK GENMASK(7, 0) 24 #define REG_ADDR_MASK GENMASK(15, 8) 25 #define REG_ADDR_SHIFT 8 26 27 #define CHT_WC_IRQLVL1 0x6e02 28 #define CHT_WC_IRQLVL1_MASK 0x6e0e 29 30 /* Whiskey Cove PMIC share same ACPI ID between different platforms */ 31 #define CHT_WC_HRV 3 32 33 /* Level 1 IRQs (level 2 IRQs are handled in the child device drivers) */ 34 enum { 35 CHT_WC_PWRSRC_IRQ = 0, 36 CHT_WC_THRM_IRQ, 37 CHT_WC_BCU_IRQ, 38 CHT_WC_ADC_IRQ, 39 CHT_WC_EXT_CHGR_IRQ, 40 CHT_WC_GPIO_IRQ, 41 /* There is no irq 6 */ 42 CHT_WC_CRIT_IRQ = 7, 43 }; 44 45 static const struct resource cht_wc_pwrsrc_resources[] = { 46 DEFINE_RES_IRQ(CHT_WC_PWRSRC_IRQ), 47 }; 48 49 static const struct resource cht_wc_ext_charger_resources[] = { 50 DEFINE_RES_IRQ(CHT_WC_EXT_CHGR_IRQ), 51 }; 52 53 static struct mfd_cell cht_wc_dev[] = { 54 { 55 .name = "cht_wcove_pwrsrc", 56 .num_resources = ARRAY_SIZE(cht_wc_pwrsrc_resources), 57 .resources = cht_wc_pwrsrc_resources, 58 }, { 59 .name = "cht_wcove_ext_chgr", 60 .num_resources = ARRAY_SIZE(cht_wc_ext_charger_resources), 61 .resources = cht_wc_ext_charger_resources, 62 }, 63 { .name = "cht_wcove_region", }, 64 { .name = "cht_wcove_leds", }, 65 }; 66 67 /* 68 * The CHT Whiskey Cove covers multiple I2C addresses, with a 1 Byte 69 * register address space per I2C address, so we use 16 bit register 70 * addresses where the high 8 bits contain the I2C client address. 71 */ 72 static int cht_wc_byte_reg_read(void *context, unsigned int reg, 73 unsigned int *val) 74 { 75 struct i2c_client *client = context; 76 int ret, orig_addr = client->addr; 77 78 if (!(reg & REG_ADDR_MASK)) { 79 dev_err(&client->dev, "Error I2C address not specified\n"); 80 return -EINVAL; 81 } 82 83 client->addr = (reg & REG_ADDR_MASK) >> REG_ADDR_SHIFT; 84 ret = i2c_smbus_read_byte_data(client, reg & REG_OFFSET_MASK); 85 client->addr = orig_addr; 86 87 if (ret < 0) 88 return ret; 89 90 *val = ret; 91 return 0; 92 } 93 94 static int cht_wc_byte_reg_write(void *context, unsigned int reg, 95 unsigned int val) 96 { 97 struct i2c_client *client = context; 98 int ret, orig_addr = client->addr; 99 100 if (!(reg & REG_ADDR_MASK)) { 101 dev_err(&client->dev, "Error I2C address not specified\n"); 102 return -EINVAL; 103 } 104 105 client->addr = (reg & REG_ADDR_MASK) >> REG_ADDR_SHIFT; 106 ret = i2c_smbus_write_byte_data(client, reg & REG_OFFSET_MASK, val); 107 client->addr = orig_addr; 108 109 return ret; 110 } 111 112 static const struct regmap_config cht_wc_regmap_cfg = { 113 .reg_bits = 16, 114 .val_bits = 8, 115 .reg_write = cht_wc_byte_reg_write, 116 .reg_read = cht_wc_byte_reg_read, 117 }; 118 119 static const struct regmap_irq cht_wc_regmap_irqs[] = { 120 REGMAP_IRQ_REG(CHT_WC_PWRSRC_IRQ, 0, BIT(CHT_WC_PWRSRC_IRQ)), 121 REGMAP_IRQ_REG(CHT_WC_THRM_IRQ, 0, BIT(CHT_WC_THRM_IRQ)), 122 REGMAP_IRQ_REG(CHT_WC_BCU_IRQ, 0, BIT(CHT_WC_BCU_IRQ)), 123 REGMAP_IRQ_REG(CHT_WC_ADC_IRQ, 0, BIT(CHT_WC_ADC_IRQ)), 124 REGMAP_IRQ_REG(CHT_WC_EXT_CHGR_IRQ, 0, BIT(CHT_WC_EXT_CHGR_IRQ)), 125 REGMAP_IRQ_REG(CHT_WC_GPIO_IRQ, 0, BIT(CHT_WC_GPIO_IRQ)), 126 REGMAP_IRQ_REG(CHT_WC_CRIT_IRQ, 0, BIT(CHT_WC_CRIT_IRQ)), 127 }; 128 129 static const struct regmap_irq_chip cht_wc_regmap_irq_chip = { 130 .name = "cht_wc_irq_chip", 131 .status_base = CHT_WC_IRQLVL1, 132 .mask_base = CHT_WC_IRQLVL1_MASK, 133 .irqs = cht_wc_regmap_irqs, 134 .num_irqs = ARRAY_SIZE(cht_wc_regmap_irqs), 135 .num_regs = 1, 136 }; 137 138 static const struct dmi_system_id cht_wc_model_dmi_ids[] = { 139 { 140 /* GPD win / GPD pocket mini laptops */ 141 .driver_data = (void *)(long)INTEL_CHT_WC_GPD_WIN_POCKET, 142 /* 143 * This DMI match may not seem unique, but it is. In the 67000+ 144 * DMI decode dumps from linux-hardware.org only 116 have 145 * board_vendor set to "AMI Corporation" and of those 116 only 146 * the GPD win's and pocket's board_name is "Default string". 147 */ 148 .matches = { 149 DMI_EXACT_MATCH(DMI_BOARD_VENDOR, "AMI Corporation"), 150 DMI_EXACT_MATCH(DMI_BOARD_NAME, "Default string"), 151 DMI_EXACT_MATCH(DMI_BOARD_SERIAL, "Default string"), 152 DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Default string"), 153 }, 154 }, { 155 /* Xiaomi Mi Pad 2 */ 156 .driver_data = (void *)(long)INTEL_CHT_WC_XIAOMI_MIPAD2, 157 .matches = { 158 DMI_MATCH(DMI_SYS_VENDOR, "Xiaomi Inc"), 159 DMI_MATCH(DMI_PRODUCT_NAME, "Mipad2"), 160 }, 161 }, { 162 /* Lenovo Yoga Book X90F / X91F / X91L */ 163 .driver_data = (void *)(long)INTEL_CHT_WC_LENOVO_YOGABOOK1, 164 .matches = { 165 /* Non exact match to match all versions */ 166 DMI_MATCH(DMI_PRODUCT_NAME, "Lenovo YB1-X9"), 167 }, 168 }, { 169 /* Lenovo Yoga Tab 3 Pro YT3-X90F */ 170 .driver_data = (void *)(long)INTEL_CHT_WC_LENOVO_YT3_X90, 171 .matches = { 172 DMI_MATCH(DMI_SYS_VENDOR, "Intel Corporation"), 173 DMI_MATCH(DMI_PRODUCT_NAME, "CHERRYVIEW D1 PLATFORM"), 174 DMI_MATCH(DMI_PRODUCT_VERSION, "Blade3-10A-001"), 175 }, 176 }, 177 { } 178 }; 179 180 static int cht_wc_probe(struct i2c_client *client) 181 { 182 struct device *dev = &client->dev; 183 const struct dmi_system_id *id; 184 struct intel_soc_pmic *pmic; 185 acpi_status status; 186 unsigned long long hrv; 187 int ret; 188 189 status = acpi_evaluate_integer(ACPI_HANDLE(dev), "_HRV", NULL, &hrv); 190 if (ACPI_FAILURE(status)) 191 return dev_err_probe(dev, -ENODEV, "Failed to get PMIC hardware revision\n"); 192 if (hrv != CHT_WC_HRV) 193 return dev_err_probe(dev, -ENODEV, "Invalid PMIC hardware revision: %llu\n", hrv); 194 195 if (client->irq < 0) 196 return dev_err_probe(dev, -EINVAL, "Invalid IRQ\n"); 197 198 pmic = devm_kzalloc(dev, sizeof(*pmic), GFP_KERNEL); 199 if (!pmic) 200 return -ENOMEM; 201 202 id = dmi_first_match(cht_wc_model_dmi_ids); 203 if (id) 204 pmic->cht_wc_model = (long)id->driver_data; 205 206 pmic->irq = client->irq; 207 pmic->dev = dev; 208 i2c_set_clientdata(client, pmic); 209 210 pmic->regmap = devm_regmap_init(dev, NULL, client, &cht_wc_regmap_cfg); 211 if (IS_ERR(pmic->regmap)) 212 return PTR_ERR(pmic->regmap); 213 214 ret = devm_regmap_add_irq_chip(dev, pmic->regmap, pmic->irq, 215 IRQF_ONESHOT | IRQF_SHARED, 0, 216 &cht_wc_regmap_irq_chip, 217 &pmic->irq_chip_data); 218 if (ret) 219 return ret; 220 221 return devm_mfd_add_devices(dev, PLATFORM_DEVID_NONE, 222 cht_wc_dev, ARRAY_SIZE(cht_wc_dev), NULL, 0, 223 regmap_irq_get_domain(pmic->irq_chip_data)); 224 } 225 226 static void cht_wc_shutdown(struct i2c_client *client) 227 { 228 struct intel_soc_pmic *pmic = i2c_get_clientdata(client); 229 230 disable_irq(pmic->irq); 231 } 232 233 static int cht_wc_suspend(struct device *dev) 234 { 235 struct intel_soc_pmic *pmic = dev_get_drvdata(dev); 236 237 disable_irq(pmic->irq); 238 239 return 0; 240 } 241 242 static int cht_wc_resume(struct device *dev) 243 { 244 struct intel_soc_pmic *pmic = dev_get_drvdata(dev); 245 246 enable_irq(pmic->irq); 247 248 return 0; 249 } 250 static DEFINE_SIMPLE_DEV_PM_OPS(cht_wc_pm_ops, cht_wc_suspend, cht_wc_resume); 251 252 static const struct i2c_device_id cht_wc_i2c_id[] = { 253 { } 254 }; 255 256 static const struct acpi_device_id cht_wc_acpi_ids[] = { 257 { "INT34D3", }, 258 { } 259 }; 260 261 static struct i2c_driver cht_wc_driver = { 262 .driver = { 263 .name = "CHT Whiskey Cove PMIC", 264 .pm = pm_sleep_ptr(&cht_wc_pm_ops), 265 .acpi_match_table = cht_wc_acpi_ids, 266 }, 267 .probe_new = cht_wc_probe, 268 .shutdown = cht_wc_shutdown, 269 .id_table = cht_wc_i2c_id, 270 }; 271 builtin_i2c_driver(cht_wc_driver); 272