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