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 / X90L */ 163 .driver_data = (void *)(long)INTEL_CHT_WC_LENOVO_YOGABOOK1, 164 .matches = { 165 DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Intel Corporation"), 166 DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "CHERRYVIEW D1 PLATFORM"), 167 DMI_EXACT_MATCH(DMI_PRODUCT_VERSION, "YETI-11"), 168 }, 169 }, { 170 /* Lenovo Yoga Book X91F / X91L */ 171 .driver_data = (void *)(long)INTEL_CHT_WC_LENOVO_YOGABOOK1, 172 .matches = { 173 /* Non exact match to match F + L versions */ 174 DMI_MATCH(DMI_PRODUCT_NAME, "Lenovo YB1-X91"), 175 }, 176 }, { 177 /* Lenovo Yoga Tab 3 Pro YT3-X90F */ 178 .driver_data = (void *)(long)INTEL_CHT_WC_LENOVO_YT3_X90, 179 .matches = { 180 DMI_MATCH(DMI_SYS_VENDOR, "Intel Corporation"), 181 DMI_MATCH(DMI_PRODUCT_VERSION, "Blade3-10A-001"), 182 }, 183 }, 184 { } 185 }; 186 187 static int cht_wc_probe(struct i2c_client *client) 188 { 189 struct device *dev = &client->dev; 190 const struct dmi_system_id *id; 191 struct intel_soc_pmic *pmic; 192 acpi_status status; 193 unsigned long long hrv; 194 int ret; 195 196 status = acpi_evaluate_integer(ACPI_HANDLE(dev), "_HRV", NULL, &hrv); 197 if (ACPI_FAILURE(status)) 198 return dev_err_probe(dev, -ENODEV, "Failed to get PMIC hardware revision\n"); 199 if (hrv != CHT_WC_HRV) 200 return dev_err_probe(dev, -ENODEV, "Invalid PMIC hardware revision: %llu\n", hrv); 201 202 if (client->irq < 0) 203 return dev_err_probe(dev, -EINVAL, "Invalid IRQ\n"); 204 205 pmic = devm_kzalloc(dev, sizeof(*pmic), GFP_KERNEL); 206 if (!pmic) 207 return -ENOMEM; 208 209 id = dmi_first_match(cht_wc_model_dmi_ids); 210 if (id) 211 pmic->cht_wc_model = (long)id->driver_data; 212 213 pmic->irq = client->irq; 214 pmic->dev = dev; 215 i2c_set_clientdata(client, pmic); 216 217 pmic->regmap = devm_regmap_init(dev, NULL, client, &cht_wc_regmap_cfg); 218 if (IS_ERR(pmic->regmap)) 219 return PTR_ERR(pmic->regmap); 220 221 ret = devm_regmap_add_irq_chip(dev, pmic->regmap, pmic->irq, 222 IRQF_ONESHOT | IRQF_SHARED, 0, 223 &cht_wc_regmap_irq_chip, 224 &pmic->irq_chip_data); 225 if (ret) 226 return ret; 227 228 return devm_mfd_add_devices(dev, PLATFORM_DEVID_NONE, 229 cht_wc_dev, ARRAY_SIZE(cht_wc_dev), NULL, 0, 230 regmap_irq_get_domain(pmic->irq_chip_data)); 231 } 232 233 static void cht_wc_shutdown(struct i2c_client *client) 234 { 235 struct intel_soc_pmic *pmic = i2c_get_clientdata(client); 236 237 disable_irq(pmic->irq); 238 } 239 240 static int cht_wc_suspend(struct device *dev) 241 { 242 struct intel_soc_pmic *pmic = dev_get_drvdata(dev); 243 244 disable_irq(pmic->irq); 245 246 return 0; 247 } 248 249 static int cht_wc_resume(struct device *dev) 250 { 251 struct intel_soc_pmic *pmic = dev_get_drvdata(dev); 252 253 enable_irq(pmic->irq); 254 255 return 0; 256 } 257 static DEFINE_SIMPLE_DEV_PM_OPS(cht_wc_pm_ops, cht_wc_suspend, cht_wc_resume); 258 259 static const struct i2c_device_id cht_wc_i2c_id[] = { 260 { } 261 }; 262 263 static const struct acpi_device_id cht_wc_acpi_ids[] = { 264 { "INT34D3", }, 265 { } 266 }; 267 268 static struct i2c_driver cht_wc_driver = { 269 .driver = { 270 .name = "CHT Whiskey Cove PMIC", 271 .pm = pm_sleep_ptr(&cht_wc_pm_ops), 272 .acpi_match_table = cht_wc_acpi_ids, 273 }, 274 .probe = cht_wc_probe, 275 .shutdown = cht_wc_shutdown, 276 .id_table = cht_wc_i2c_id, 277 }; 278 builtin_i2c_driver(cht_wc_driver); 279