1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * XPower AXP288 PMIC operation region driver 4 * 5 * Copyright (C) 2014 Intel Corporation. All rights reserved. 6 */ 7 8 #include <linux/acpi.h> 9 #include <linux/init.h> 10 #include <linux/mfd/axp20x.h> 11 #include <linux/regmap.h> 12 #include <linux/platform_device.h> 13 #include <asm/iosf_mbi.h> 14 #include "intel_pmic.h" 15 16 #define XPOWER_GPADC_LOW 0x5b 17 #define XPOWER_GPI1_CTRL 0x92 18 19 #define GPI1_LDO_MASK GENMASK(2, 0) 20 #define GPI1_LDO_ON (3 << 0) 21 #define GPI1_LDO_OFF (4 << 0) 22 23 #define AXP288_ADC_TS_CURRENT_ON_OFF_MASK GENMASK(1, 0) 24 #define AXP288_ADC_TS_CURRENT_OFF (0 << 0) 25 #define AXP288_ADC_TS_CURRENT_ON_WHEN_CHARGING (1 << 0) 26 #define AXP288_ADC_TS_CURRENT_ON_ONDEMAND (2 << 0) 27 #define AXP288_ADC_TS_CURRENT_ON (3 << 0) 28 29 static struct pmic_table power_table[] = { 30 { 31 .address = 0x00, 32 .reg = 0x13, 33 .bit = 0x05, 34 }, /* ALD1 */ 35 { 36 .address = 0x04, 37 .reg = 0x13, 38 .bit = 0x06, 39 }, /* ALD2 */ 40 { 41 .address = 0x08, 42 .reg = 0x13, 43 .bit = 0x07, 44 }, /* ALD3 */ 45 { 46 .address = 0x0c, 47 .reg = 0x12, 48 .bit = 0x03, 49 }, /* DLD1 */ 50 { 51 .address = 0x10, 52 .reg = 0x12, 53 .bit = 0x04, 54 }, /* DLD2 */ 55 { 56 .address = 0x14, 57 .reg = 0x12, 58 .bit = 0x05, 59 }, /* DLD3 */ 60 { 61 .address = 0x18, 62 .reg = 0x12, 63 .bit = 0x06, 64 }, /* DLD4 */ 65 { 66 .address = 0x1c, 67 .reg = 0x12, 68 .bit = 0x00, 69 }, /* ELD1 */ 70 { 71 .address = 0x20, 72 .reg = 0x12, 73 .bit = 0x01, 74 }, /* ELD2 */ 75 { 76 .address = 0x24, 77 .reg = 0x12, 78 .bit = 0x02, 79 }, /* ELD3 */ 80 { 81 .address = 0x28, 82 .reg = 0x13, 83 .bit = 0x02, 84 }, /* FLD1 */ 85 { 86 .address = 0x2c, 87 .reg = 0x13, 88 .bit = 0x03, 89 }, /* FLD2 */ 90 { 91 .address = 0x30, 92 .reg = 0x13, 93 .bit = 0x04, 94 }, /* FLD3 */ 95 { 96 .address = 0x34, 97 .reg = 0x10, 98 .bit = 0x03, 99 }, /* BUC1 */ 100 { 101 .address = 0x38, 102 .reg = 0x10, 103 .bit = 0x06, 104 }, /* BUC2 */ 105 { 106 .address = 0x3c, 107 .reg = 0x10, 108 .bit = 0x05, 109 }, /* BUC3 */ 110 { 111 .address = 0x40, 112 .reg = 0x10, 113 .bit = 0x04, 114 }, /* BUC4 */ 115 { 116 .address = 0x44, 117 .reg = 0x10, 118 .bit = 0x01, 119 }, /* BUC5 */ 120 { 121 .address = 0x48, 122 .reg = 0x10, 123 .bit = 0x00 124 }, /* BUC6 */ 125 { 126 .address = 0x4c, 127 .reg = 0x92, 128 }, /* GPI1 */ 129 }; 130 131 /* TMP0 - TMP5 are the same, all from GPADC */ 132 static struct pmic_table thermal_table[] = { 133 { 134 .address = 0x00, 135 .reg = XPOWER_GPADC_LOW 136 }, 137 { 138 .address = 0x0c, 139 .reg = XPOWER_GPADC_LOW 140 }, 141 { 142 .address = 0x18, 143 .reg = XPOWER_GPADC_LOW 144 }, 145 { 146 .address = 0x24, 147 .reg = XPOWER_GPADC_LOW 148 }, 149 { 150 .address = 0x30, 151 .reg = XPOWER_GPADC_LOW 152 }, 153 { 154 .address = 0x3c, 155 .reg = XPOWER_GPADC_LOW 156 }, 157 }; 158 159 static int intel_xpower_pmic_get_power(struct regmap *regmap, int reg, 160 int bit, u64 *value) 161 { 162 int data; 163 164 if (regmap_read(regmap, reg, &data)) 165 return -EIO; 166 167 /* GPIO1 LDO regulator needs special handling */ 168 if (reg == XPOWER_GPI1_CTRL) 169 *value = ((data & GPI1_LDO_MASK) == GPI1_LDO_ON); 170 else 171 *value = (data & BIT(bit)) ? 1 : 0; 172 173 return 0; 174 } 175 176 static int intel_xpower_pmic_update_power(struct regmap *regmap, int reg, 177 int bit, bool on) 178 { 179 int data, ret; 180 181 ret = iosf_mbi_block_punit_i2c_access(); 182 if (ret) 183 return ret; 184 185 /* GPIO1 LDO regulator needs special handling */ 186 if (reg == XPOWER_GPI1_CTRL) { 187 ret = regmap_update_bits(regmap, reg, GPI1_LDO_MASK, 188 on ? GPI1_LDO_ON : GPI1_LDO_OFF); 189 goto out; 190 } 191 192 if (regmap_read(regmap, reg, &data)) { 193 ret = -EIO; 194 goto out; 195 } 196 197 if (on) 198 data |= BIT(bit); 199 else 200 data &= ~BIT(bit); 201 202 if (regmap_write(regmap, reg, data)) 203 ret = -EIO; 204 out: 205 iosf_mbi_unblock_punit_i2c_access(); 206 207 return ret; 208 } 209 210 /** 211 * intel_xpower_pmic_get_raw_temp(): Get raw temperature reading from the PMIC 212 * 213 * @regmap: regmap of the PMIC device 214 * @reg: register to get the reading 215 * 216 * Return a positive value on success, errno on failure. 217 */ 218 static int intel_xpower_pmic_get_raw_temp(struct regmap *regmap, int reg) 219 { 220 int ret, adc_ts_pin_ctrl; 221 u8 buf[2]; 222 223 /* 224 * The current-source used for the battery temp-sensor (TS) is shared 225 * with the GPADC. For proper fuel-gauge and charger operation the TS 226 * current-source needs to be permanently on. But to read the GPADC we 227 * need to temporary switch the TS current-source to ondemand, so that 228 * the GPADC can use it, otherwise we will always read an all 0 value. 229 * 230 * Note that the switching from on to on-ondemand is not necessary 231 * when the TS current-source is off (this happens on devices which 232 * do not use the TS-pin). 233 */ 234 ret = regmap_read(regmap, AXP288_ADC_TS_PIN_CTRL, &adc_ts_pin_ctrl); 235 if (ret) 236 return ret; 237 238 if (adc_ts_pin_ctrl & AXP288_ADC_TS_CURRENT_ON_OFF_MASK) { 239 /* 240 * AXP288_ADC_TS_PIN_CTRL reads are cached by the regmap, so 241 * this does to a single I2C-transfer, and thus there is no 242 * need to explicitly call iosf_mbi_block_punit_i2c_access(). 243 */ 244 ret = regmap_update_bits(regmap, AXP288_ADC_TS_PIN_CTRL, 245 AXP288_ADC_TS_CURRENT_ON_OFF_MASK, 246 AXP288_ADC_TS_CURRENT_ON_ONDEMAND); 247 if (ret) 248 return ret; 249 250 /* Wait a bit after switching the current-source */ 251 usleep_range(6000, 10000); 252 } 253 254 ret = iosf_mbi_block_punit_i2c_access(); 255 if (ret) 256 return ret; 257 258 ret = regmap_bulk_read(regmap, AXP288_GP_ADC_H, buf, 2); 259 if (ret == 0) 260 ret = (buf[0] << 4) + ((buf[1] >> 4) & 0x0f); 261 262 if (adc_ts_pin_ctrl & AXP288_ADC_TS_CURRENT_ON_OFF_MASK) { 263 regmap_update_bits(regmap, AXP288_ADC_TS_PIN_CTRL, 264 AXP288_ADC_TS_CURRENT_ON_OFF_MASK, 265 AXP288_ADC_TS_CURRENT_ON); 266 } 267 268 iosf_mbi_unblock_punit_i2c_access(); 269 270 return ret; 271 } 272 273 static int intel_xpower_exec_mipi_pmic_seq_element(struct regmap *regmap, 274 u16 i2c_address, u32 reg_address, 275 u32 value, u32 mask) 276 { 277 int ret; 278 279 if (i2c_address != 0x34) { 280 pr_err("%s: Unexpected i2c-addr: 0x%02x (reg-addr 0x%x value 0x%x mask 0x%x)\n", 281 __func__, i2c_address, reg_address, value, mask); 282 return -ENXIO; 283 } 284 285 ret = iosf_mbi_block_punit_i2c_access(); 286 if (ret) 287 return ret; 288 289 ret = regmap_update_bits(regmap, reg_address, mask, value); 290 291 iosf_mbi_unblock_punit_i2c_access(); 292 293 return ret; 294 } 295 296 static struct intel_pmic_opregion_data intel_xpower_pmic_opregion_data = { 297 .get_power = intel_xpower_pmic_get_power, 298 .update_power = intel_xpower_pmic_update_power, 299 .get_raw_temp = intel_xpower_pmic_get_raw_temp, 300 .exec_mipi_pmic_seq_element = intel_xpower_exec_mipi_pmic_seq_element, 301 .power_table = power_table, 302 .power_table_count = ARRAY_SIZE(power_table), 303 .thermal_table = thermal_table, 304 .thermal_table_count = ARRAY_SIZE(thermal_table), 305 .pmic_i2c_address = 0x34, 306 }; 307 308 static acpi_status intel_xpower_pmic_gpio_handler(u32 function, 309 acpi_physical_address address, u32 bit_width, u64 *value, 310 void *handler_context, void *region_context) 311 { 312 return AE_OK; 313 } 314 315 static int intel_xpower_pmic_opregion_probe(struct platform_device *pdev) 316 { 317 struct device *parent = pdev->dev.parent; 318 struct axp20x_dev *axp20x = dev_get_drvdata(parent); 319 acpi_status status; 320 int result; 321 322 status = acpi_install_address_space_handler(ACPI_HANDLE(parent), 323 ACPI_ADR_SPACE_GPIO, intel_xpower_pmic_gpio_handler, 324 NULL, NULL); 325 if (ACPI_FAILURE(status)) 326 return -ENODEV; 327 328 result = intel_pmic_install_opregion_handler(&pdev->dev, 329 ACPI_HANDLE(parent), axp20x->regmap, 330 &intel_xpower_pmic_opregion_data); 331 if (result) 332 acpi_remove_address_space_handler(ACPI_HANDLE(parent), 333 ACPI_ADR_SPACE_GPIO, 334 intel_xpower_pmic_gpio_handler); 335 336 return result; 337 } 338 339 static struct platform_driver intel_xpower_pmic_opregion_driver = { 340 .probe = intel_xpower_pmic_opregion_probe, 341 .driver = { 342 .name = "axp288_pmic_acpi", 343 }, 344 }; 345 builtin_platform_driver(intel_xpower_pmic_opregion_driver); 346