1 /* 2 * intel_pmic.c - Intel PMIC operation region driver 3 * 4 * Copyright (C) 2014 Intel Corporation. All rights reserved. 5 * 6 * This program is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU General Public License version 8 * 2 as published by the Free Software Foundation. 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 */ 15 16 #include <linux/export.h> 17 #include <linux/acpi.h> 18 #include <linux/mfd/intel_soc_pmic.h> 19 #include <linux/regmap.h> 20 #include <acpi/acpi_lpat.h> 21 #include "intel_pmic.h" 22 23 #define PMIC_POWER_OPREGION_ID 0x8d 24 #define PMIC_THERMAL_OPREGION_ID 0x8c 25 #define PMIC_REGS_OPREGION_ID 0x8f 26 27 struct intel_pmic_regs_handler_ctx { 28 unsigned int val; 29 u16 addr; 30 }; 31 32 struct intel_pmic_opregion { 33 struct mutex lock; 34 struct acpi_lpat_conversion_table *lpat_table; 35 struct regmap *regmap; 36 struct intel_pmic_opregion_data *data; 37 struct intel_pmic_regs_handler_ctx ctx; 38 }; 39 40 static struct intel_pmic_opregion *intel_pmic_opregion; 41 42 static int pmic_get_reg_bit(int address, struct pmic_table *table, 43 int count, int *reg, int *bit) 44 { 45 int i; 46 47 for (i = 0; i < count; i++) { 48 if (table[i].address == address) { 49 *reg = table[i].reg; 50 if (bit) 51 *bit = table[i].bit; 52 return 0; 53 } 54 } 55 return -ENOENT; 56 } 57 58 static acpi_status intel_pmic_power_handler(u32 function, 59 acpi_physical_address address, u32 bits, u64 *value64, 60 void *handler_context, void *region_context) 61 { 62 struct intel_pmic_opregion *opregion = region_context; 63 struct regmap *regmap = opregion->regmap; 64 struct intel_pmic_opregion_data *d = opregion->data; 65 int reg, bit, result; 66 67 if (bits != 32 || !value64) 68 return AE_BAD_PARAMETER; 69 70 if (function == ACPI_WRITE && !(*value64 == 0 || *value64 == 1)) 71 return AE_BAD_PARAMETER; 72 73 result = pmic_get_reg_bit(address, d->power_table, 74 d->power_table_count, ®, &bit); 75 if (result == -ENOENT) 76 return AE_BAD_PARAMETER; 77 78 mutex_lock(&opregion->lock); 79 80 result = function == ACPI_READ ? 81 d->get_power(regmap, reg, bit, value64) : 82 d->update_power(regmap, reg, bit, *value64 == 1); 83 84 mutex_unlock(&opregion->lock); 85 86 return result ? AE_ERROR : AE_OK; 87 } 88 89 static int pmic_read_temp(struct intel_pmic_opregion *opregion, 90 int reg, u64 *value) 91 { 92 int raw_temp, temp; 93 94 if (!opregion->data->get_raw_temp) 95 return -ENXIO; 96 97 raw_temp = opregion->data->get_raw_temp(opregion->regmap, reg); 98 if (raw_temp < 0) 99 return raw_temp; 100 101 if (!opregion->lpat_table) { 102 *value = raw_temp; 103 return 0; 104 } 105 106 temp = acpi_lpat_raw_to_temp(opregion->lpat_table, raw_temp); 107 if (temp < 0) 108 return temp; 109 110 *value = temp; 111 return 0; 112 } 113 114 static int pmic_thermal_temp(struct intel_pmic_opregion *opregion, int reg, 115 u32 function, u64 *value) 116 { 117 return function == ACPI_READ ? 118 pmic_read_temp(opregion, reg, value) : -EINVAL; 119 } 120 121 static int pmic_thermal_aux(struct intel_pmic_opregion *opregion, int reg, 122 u32 function, u64 *value) 123 { 124 int raw_temp; 125 126 if (function == ACPI_READ) 127 return pmic_read_temp(opregion, reg, value); 128 129 if (!opregion->data->update_aux) 130 return -ENXIO; 131 132 if (opregion->lpat_table) { 133 raw_temp = acpi_lpat_temp_to_raw(opregion->lpat_table, *value); 134 if (raw_temp < 0) 135 return raw_temp; 136 } else { 137 raw_temp = *value; 138 } 139 140 return opregion->data->update_aux(opregion->regmap, reg, raw_temp); 141 } 142 143 static int pmic_thermal_pen(struct intel_pmic_opregion *opregion, int reg, 144 int bit, u32 function, u64 *value) 145 { 146 struct intel_pmic_opregion_data *d = opregion->data; 147 struct regmap *regmap = opregion->regmap; 148 149 if (!d->get_policy || !d->update_policy) 150 return -ENXIO; 151 152 if (function == ACPI_READ) 153 return d->get_policy(regmap, reg, bit, value); 154 155 if (*value != 0 && *value != 1) 156 return -EINVAL; 157 158 return d->update_policy(regmap, reg, bit, *value); 159 } 160 161 static bool pmic_thermal_is_temp(int address) 162 { 163 return (address <= 0x3c) && !(address % 12); 164 } 165 166 static bool pmic_thermal_is_aux(int address) 167 { 168 return (address >= 4 && address <= 0x40 && !((address - 4) % 12)) || 169 (address >= 8 && address <= 0x44 && !((address - 8) % 12)); 170 } 171 172 static bool pmic_thermal_is_pen(int address) 173 { 174 return address >= 0x48 && address <= 0x5c; 175 } 176 177 static acpi_status intel_pmic_thermal_handler(u32 function, 178 acpi_physical_address address, u32 bits, u64 *value64, 179 void *handler_context, void *region_context) 180 { 181 struct intel_pmic_opregion *opregion = region_context; 182 struct intel_pmic_opregion_data *d = opregion->data; 183 int reg, bit, result; 184 185 if (bits != 32 || !value64) 186 return AE_BAD_PARAMETER; 187 188 result = pmic_get_reg_bit(address, d->thermal_table, 189 d->thermal_table_count, ®, &bit); 190 if (result == -ENOENT) 191 return AE_BAD_PARAMETER; 192 193 mutex_lock(&opregion->lock); 194 195 if (pmic_thermal_is_temp(address)) 196 result = pmic_thermal_temp(opregion, reg, function, value64); 197 else if (pmic_thermal_is_aux(address)) 198 result = pmic_thermal_aux(opregion, reg, function, value64); 199 else if (pmic_thermal_is_pen(address)) 200 result = pmic_thermal_pen(opregion, reg, bit, 201 function, value64); 202 else 203 result = -EINVAL; 204 205 mutex_unlock(&opregion->lock); 206 207 if (result < 0) { 208 if (result == -EINVAL) 209 return AE_BAD_PARAMETER; 210 else 211 return AE_ERROR; 212 } 213 214 return AE_OK; 215 } 216 217 static acpi_status intel_pmic_regs_handler(u32 function, 218 acpi_physical_address address, u32 bits, u64 *value64, 219 void *handler_context, void *region_context) 220 { 221 struct intel_pmic_opregion *opregion = region_context; 222 int result = 0; 223 224 switch (address) { 225 case 0: 226 return AE_OK; 227 case 1: 228 opregion->ctx.addr |= (*value64 & 0xff) << 8; 229 return AE_OK; 230 case 2: 231 opregion->ctx.addr |= *value64 & 0xff; 232 return AE_OK; 233 case 3: 234 opregion->ctx.val = *value64 & 0xff; 235 return AE_OK; 236 case 4: 237 if (*value64) { 238 result = regmap_write(opregion->regmap, opregion->ctx.addr, 239 opregion->ctx.val); 240 } else { 241 result = regmap_read(opregion->regmap, opregion->ctx.addr, 242 &opregion->ctx.val); 243 if (result == 0) 244 *value64 = opregion->ctx.val; 245 } 246 memset(&opregion->ctx, 0x00, sizeof(opregion->ctx)); 247 } 248 249 if (result < 0) { 250 if (result == -EINVAL) 251 return AE_BAD_PARAMETER; 252 else 253 return AE_ERROR; 254 } 255 256 return AE_OK; 257 } 258 259 int intel_pmic_install_opregion_handler(struct device *dev, acpi_handle handle, 260 struct regmap *regmap, 261 struct intel_pmic_opregion_data *d) 262 { 263 acpi_status status; 264 struct intel_pmic_opregion *opregion; 265 int ret; 266 267 if (!dev || !regmap || !d) 268 return -EINVAL; 269 270 if (!handle) 271 return -ENODEV; 272 273 opregion = devm_kzalloc(dev, sizeof(*opregion), GFP_KERNEL); 274 if (!opregion) 275 return -ENOMEM; 276 277 mutex_init(&opregion->lock); 278 opregion->regmap = regmap; 279 opregion->lpat_table = acpi_lpat_get_conversion_table(handle); 280 281 status = acpi_install_address_space_handler(handle, 282 PMIC_POWER_OPREGION_ID, 283 intel_pmic_power_handler, 284 NULL, opregion); 285 if (ACPI_FAILURE(status)) { 286 ret = -ENODEV; 287 goto out_error; 288 } 289 290 status = acpi_install_address_space_handler(handle, 291 PMIC_THERMAL_OPREGION_ID, 292 intel_pmic_thermal_handler, 293 NULL, opregion); 294 if (ACPI_FAILURE(status)) { 295 acpi_remove_address_space_handler(handle, PMIC_POWER_OPREGION_ID, 296 intel_pmic_power_handler); 297 ret = -ENODEV; 298 goto out_remove_power_handler; 299 } 300 301 status = acpi_install_address_space_handler(handle, 302 PMIC_REGS_OPREGION_ID, intel_pmic_regs_handler, NULL, 303 opregion); 304 if (ACPI_FAILURE(status)) { 305 ret = -ENODEV; 306 goto out_remove_thermal_handler; 307 } 308 309 opregion->data = d; 310 intel_pmic_opregion = opregion; 311 return 0; 312 313 out_remove_thermal_handler: 314 acpi_remove_address_space_handler(handle, PMIC_THERMAL_OPREGION_ID, 315 intel_pmic_thermal_handler); 316 317 out_remove_power_handler: 318 acpi_remove_address_space_handler(handle, PMIC_POWER_OPREGION_ID, 319 intel_pmic_power_handler); 320 321 out_error: 322 acpi_lpat_free_conversion_table(opregion->lpat_table); 323 return ret; 324 } 325 EXPORT_SYMBOL_GPL(intel_pmic_install_opregion_handler); 326 327 /** 328 * intel_soc_pmic_exec_mipi_pmic_seq_element - Execute PMIC MIPI sequence 329 * @i2c_address: I2C client address for the PMIC 330 * @reg_address: PMIC register address 331 * @value: New value for the register bits to change 332 * @mask: Mask indicating which register bits to change 333 * 334 * DSI LCD panels describe an initialization sequence in the i915 VBT (Video 335 * BIOS Tables) using so called MIPI sequences. One possible element in these 336 * sequences is a PMIC specific element of 15 bytes. 337 * 338 * This function executes these PMIC specific elements sending the embedded 339 * commands to the PMIC. 340 * 341 * Return 0 on success, < 0 on failure. 342 */ 343 int intel_soc_pmic_exec_mipi_pmic_seq_element(u16 i2c_address, u32 reg_address, 344 u32 value, u32 mask) 345 { 346 struct intel_pmic_opregion_data *d; 347 int ret; 348 349 if (!intel_pmic_opregion) { 350 pr_warn("%s: No PMIC registered\n", __func__); 351 return -ENXIO; 352 } 353 354 d = intel_pmic_opregion->data; 355 356 mutex_lock(&intel_pmic_opregion->lock); 357 358 if (d->exec_mipi_pmic_seq_element) { 359 ret = d->exec_mipi_pmic_seq_element(intel_pmic_opregion->regmap, 360 i2c_address, reg_address, 361 value, mask); 362 } else if (d->pmic_i2c_address) { 363 if (i2c_address == d->pmic_i2c_address) { 364 ret = regmap_update_bits(intel_pmic_opregion->regmap, 365 reg_address, mask, value); 366 } else { 367 pr_err("%s: Unexpected i2c-addr: 0x%02x (reg-addr 0x%x value 0x%x mask 0x%x)\n", 368 __func__, i2c_address, reg_address, value, mask); 369 ret = -ENXIO; 370 } 371 } else { 372 pr_warn("%s: Not implemented\n", __func__); 373 pr_warn("%s: i2c-addr: 0x%x reg-addr 0x%x value 0x%x mask 0x%x\n", 374 __func__, i2c_address, reg_address, value, mask); 375 ret = -EOPNOTSUPP; 376 } 377 378 mutex_unlock(&intel_pmic_opregion->lock); 379 380 return ret; 381 } 382 EXPORT_SYMBOL_GPL(intel_soc_pmic_exec_mipi_pmic_seq_element); 383