intel_pmic_xpower.c (8305B)
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 29static 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 */ 132static 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 159static 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 176static 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; 204out: 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 */ 218static 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 273static 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 296static int intel_xpower_lpat_raw_to_temp(struct acpi_lpat_conversion_table *lpat_table, 297 int raw) 298{ 299 struct acpi_lpat first = lpat_table->lpat[0]; 300 struct acpi_lpat last = lpat_table->lpat[lpat_table->lpat_count - 1]; 301 302 /* 303 * Some LPAT tables in the ACPI Device for the AXP288 PMIC for some 304 * reason only describe a small temperature range, e.g. 27° - 37° 305 * Celcius. Resulting in errors when the tablet is idle in a cool room. 306 * 307 * To avoid these errors clamp the raw value to be inside the LPAT. 308 */ 309 if (first.raw < last.raw) 310 raw = clamp(raw, first.raw, last.raw); 311 else 312 raw = clamp(raw, last.raw, first.raw); 313 314 return acpi_lpat_raw_to_temp(lpat_table, raw); 315} 316 317static const struct intel_pmic_opregion_data intel_xpower_pmic_opregion_data = { 318 .get_power = intel_xpower_pmic_get_power, 319 .update_power = intel_xpower_pmic_update_power, 320 .get_raw_temp = intel_xpower_pmic_get_raw_temp, 321 .exec_mipi_pmic_seq_element = intel_xpower_exec_mipi_pmic_seq_element, 322 .lpat_raw_to_temp = intel_xpower_lpat_raw_to_temp, 323 .power_table = power_table, 324 .power_table_count = ARRAY_SIZE(power_table), 325 .thermal_table = thermal_table, 326 .thermal_table_count = ARRAY_SIZE(thermal_table), 327 .pmic_i2c_address = 0x34, 328}; 329 330static acpi_status intel_xpower_pmic_gpio_handler(u32 function, 331 acpi_physical_address address, u32 bit_width, u64 *value, 332 void *handler_context, void *region_context) 333{ 334 return AE_OK; 335} 336 337static int intel_xpower_pmic_opregion_probe(struct platform_device *pdev) 338{ 339 struct device *parent = pdev->dev.parent; 340 struct axp20x_dev *axp20x = dev_get_drvdata(parent); 341 acpi_status status; 342 int result; 343 344 status = acpi_install_address_space_handler(ACPI_HANDLE(parent), 345 ACPI_ADR_SPACE_GPIO, intel_xpower_pmic_gpio_handler, 346 NULL, NULL); 347 if (ACPI_FAILURE(status)) 348 return -ENODEV; 349 350 result = intel_pmic_install_opregion_handler(&pdev->dev, 351 ACPI_HANDLE(parent), axp20x->regmap, 352 &intel_xpower_pmic_opregion_data); 353 if (result) 354 acpi_remove_address_space_handler(ACPI_HANDLE(parent), 355 ACPI_ADR_SPACE_GPIO, 356 intel_xpower_pmic_gpio_handler); 357 358 return result; 359} 360 361static struct platform_driver intel_xpower_pmic_opregion_driver = { 362 .probe = intel_xpower_pmic_opregion_probe, 363 .driver = { 364 .name = "axp288_pmic_acpi", 365 }, 366}; 367builtin_platform_driver(intel_xpower_pmic_opregion_driver);