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_PIN_GPADC 0xf2 24 #define AXP288_ADC_TS_PIN_ON 0xf3 25 26 static struct pmic_table power_table[] = { 27 { 28 .address = 0x00, 29 .reg = 0x13, 30 .bit = 0x05, 31 }, /* ALD1 */ 32 { 33 .address = 0x04, 34 .reg = 0x13, 35 .bit = 0x06, 36 }, /* ALD2 */ 37 { 38 .address = 0x08, 39 .reg = 0x13, 40 .bit = 0x07, 41 }, /* ALD3 */ 42 { 43 .address = 0x0c, 44 .reg = 0x12, 45 .bit = 0x03, 46 }, /* DLD1 */ 47 { 48 .address = 0x10, 49 .reg = 0x12, 50 .bit = 0x04, 51 }, /* DLD2 */ 52 { 53 .address = 0x14, 54 .reg = 0x12, 55 .bit = 0x05, 56 }, /* DLD3 */ 57 { 58 .address = 0x18, 59 .reg = 0x12, 60 .bit = 0x06, 61 }, /* DLD4 */ 62 { 63 .address = 0x1c, 64 .reg = 0x12, 65 .bit = 0x00, 66 }, /* ELD1 */ 67 { 68 .address = 0x20, 69 .reg = 0x12, 70 .bit = 0x01, 71 }, /* ELD2 */ 72 { 73 .address = 0x24, 74 .reg = 0x12, 75 .bit = 0x02, 76 }, /* ELD3 */ 77 { 78 .address = 0x28, 79 .reg = 0x13, 80 .bit = 0x02, 81 }, /* FLD1 */ 82 { 83 .address = 0x2c, 84 .reg = 0x13, 85 .bit = 0x03, 86 }, /* FLD2 */ 87 { 88 .address = 0x30, 89 .reg = 0x13, 90 .bit = 0x04, 91 }, /* FLD3 */ 92 { 93 .address = 0x34, 94 .reg = 0x10, 95 .bit = 0x03, 96 }, /* BUC1 */ 97 { 98 .address = 0x38, 99 .reg = 0x10, 100 .bit = 0x06, 101 }, /* BUC2 */ 102 { 103 .address = 0x3c, 104 .reg = 0x10, 105 .bit = 0x05, 106 }, /* BUC3 */ 107 { 108 .address = 0x40, 109 .reg = 0x10, 110 .bit = 0x04, 111 }, /* BUC4 */ 112 { 113 .address = 0x44, 114 .reg = 0x10, 115 .bit = 0x01, 116 }, /* BUC5 */ 117 { 118 .address = 0x48, 119 .reg = 0x10, 120 .bit = 0x00 121 }, /* BUC6 */ 122 { 123 .address = 0x4c, 124 .reg = 0x92, 125 }, /* GPI1 */ 126 }; 127 128 /* TMP0 - TMP5 are the same, all from GPADC */ 129 static struct pmic_table thermal_table[] = { 130 { 131 .address = 0x00, 132 .reg = XPOWER_GPADC_LOW 133 }, 134 { 135 .address = 0x0c, 136 .reg = XPOWER_GPADC_LOW 137 }, 138 { 139 .address = 0x18, 140 .reg = XPOWER_GPADC_LOW 141 }, 142 { 143 .address = 0x24, 144 .reg = XPOWER_GPADC_LOW 145 }, 146 { 147 .address = 0x30, 148 .reg = XPOWER_GPADC_LOW 149 }, 150 { 151 .address = 0x3c, 152 .reg = XPOWER_GPADC_LOW 153 }, 154 }; 155 156 static int intel_xpower_pmic_get_power(struct regmap *regmap, int reg, 157 int bit, u64 *value) 158 { 159 int data; 160 161 if (regmap_read(regmap, reg, &data)) 162 return -EIO; 163 164 /* GPIO1 LDO regulator needs special handling */ 165 if (reg == XPOWER_GPI1_CTRL) 166 *value = ((data & GPI1_LDO_MASK) == GPI1_LDO_ON); 167 else 168 *value = (data & BIT(bit)) ? 1 : 0; 169 170 return 0; 171 } 172 173 static int intel_xpower_pmic_update_power(struct regmap *regmap, int reg, 174 int bit, bool on) 175 { 176 int data, ret; 177 178 /* GPIO1 LDO regulator needs special handling */ 179 if (reg == XPOWER_GPI1_CTRL) 180 return regmap_update_bits(regmap, reg, GPI1_LDO_MASK, 181 on ? GPI1_LDO_ON : GPI1_LDO_OFF); 182 183 ret = iosf_mbi_block_punit_i2c_access(); 184 if (ret) 185 return ret; 186 187 if (regmap_read(regmap, reg, &data)) { 188 ret = -EIO; 189 goto out; 190 } 191 192 if (on) 193 data |= BIT(bit); 194 else 195 data &= ~BIT(bit); 196 197 if (regmap_write(regmap, reg, data)) 198 ret = -EIO; 199 out: 200 iosf_mbi_unblock_punit_i2c_access(); 201 202 return ret; 203 } 204 205 /** 206 * intel_xpower_pmic_get_raw_temp(): Get raw temperature reading from the PMIC 207 * 208 * @regmap: regmap of the PMIC device 209 * @reg: register to get the reading 210 * 211 * Return a positive value on success, errno on failure. 212 */ 213 static int intel_xpower_pmic_get_raw_temp(struct regmap *regmap, int reg) 214 { 215 u8 buf[2]; 216 int ret; 217 218 ret = regmap_write(regmap, AXP288_ADC_TS_PIN_CTRL, 219 AXP288_ADC_TS_PIN_GPADC); 220 if (ret) 221 return ret; 222 223 /* After switching to the GPADC pin give things some time to settle */ 224 usleep_range(6000, 10000); 225 226 ret = regmap_bulk_read(regmap, AXP288_GP_ADC_H, buf, 2); 227 if (ret == 0) 228 ret = (buf[0] << 4) + ((buf[1] >> 4) & 0x0f); 229 230 regmap_write(regmap, AXP288_ADC_TS_PIN_CTRL, AXP288_ADC_TS_PIN_ON); 231 232 return ret; 233 } 234 235 static struct intel_pmic_opregion_data intel_xpower_pmic_opregion_data = { 236 .get_power = intel_xpower_pmic_get_power, 237 .update_power = intel_xpower_pmic_update_power, 238 .get_raw_temp = intel_xpower_pmic_get_raw_temp, 239 .power_table = power_table, 240 .power_table_count = ARRAY_SIZE(power_table), 241 .thermal_table = thermal_table, 242 .thermal_table_count = ARRAY_SIZE(thermal_table), 243 }; 244 245 static acpi_status intel_xpower_pmic_gpio_handler(u32 function, 246 acpi_physical_address address, u32 bit_width, u64 *value, 247 void *handler_context, void *region_context) 248 { 249 return AE_OK; 250 } 251 252 static int intel_xpower_pmic_opregion_probe(struct platform_device *pdev) 253 { 254 struct device *parent = pdev->dev.parent; 255 struct axp20x_dev *axp20x = dev_get_drvdata(parent); 256 acpi_status status; 257 int result; 258 259 status = acpi_install_address_space_handler(ACPI_HANDLE(parent), 260 ACPI_ADR_SPACE_GPIO, intel_xpower_pmic_gpio_handler, 261 NULL, NULL); 262 if (ACPI_FAILURE(status)) 263 return -ENODEV; 264 265 result = intel_pmic_install_opregion_handler(&pdev->dev, 266 ACPI_HANDLE(parent), axp20x->regmap, 267 &intel_xpower_pmic_opregion_data); 268 if (result) 269 acpi_remove_address_space_handler(ACPI_HANDLE(parent), 270 ACPI_ADR_SPACE_GPIO, 271 intel_xpower_pmic_gpio_handler); 272 273 return result; 274 } 275 276 static struct platform_driver intel_xpower_pmic_opregion_driver = { 277 .probe = intel_xpower_pmic_opregion_probe, 278 .driver = { 279 .name = "axp288_pmic_acpi", 280 }, 281 }; 282 builtin_platform_driver(intel_xpower_pmic_opregion_driver); 283