18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * intel_pmic.c - Intel PMIC operation region driver
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Copyright (C) 2014 Intel Corporation. All rights reserved.
68c2ecf20Sopenharmony_ci */
78c2ecf20Sopenharmony_ci
88c2ecf20Sopenharmony_ci#include <linux/export.h>
98c2ecf20Sopenharmony_ci#include <linux/acpi.h>
108c2ecf20Sopenharmony_ci#include <linux/mfd/intel_soc_pmic.h>
118c2ecf20Sopenharmony_ci#include <linux/regmap.h>
128c2ecf20Sopenharmony_ci#include <acpi/acpi_lpat.h>
138c2ecf20Sopenharmony_ci#include "intel_pmic.h"
148c2ecf20Sopenharmony_ci
158c2ecf20Sopenharmony_ci#define PMIC_POWER_OPREGION_ID		0x8d
168c2ecf20Sopenharmony_ci#define PMIC_THERMAL_OPREGION_ID	0x8c
178c2ecf20Sopenharmony_ci#define PMIC_REGS_OPREGION_ID		0x8f
188c2ecf20Sopenharmony_ci
198c2ecf20Sopenharmony_cistruct intel_pmic_regs_handler_ctx {
208c2ecf20Sopenharmony_ci	unsigned int val;
218c2ecf20Sopenharmony_ci	u16 addr;
228c2ecf20Sopenharmony_ci};
238c2ecf20Sopenharmony_ci
248c2ecf20Sopenharmony_cistruct intel_pmic_opregion {
258c2ecf20Sopenharmony_ci	struct mutex lock;
268c2ecf20Sopenharmony_ci	struct acpi_lpat_conversion_table *lpat_table;
278c2ecf20Sopenharmony_ci	struct regmap *regmap;
288c2ecf20Sopenharmony_ci	struct intel_pmic_opregion_data *data;
298c2ecf20Sopenharmony_ci	struct intel_pmic_regs_handler_ctx ctx;
308c2ecf20Sopenharmony_ci};
318c2ecf20Sopenharmony_ci
328c2ecf20Sopenharmony_cistatic struct intel_pmic_opregion *intel_pmic_opregion;
338c2ecf20Sopenharmony_ci
348c2ecf20Sopenharmony_cistatic int pmic_get_reg_bit(int address, struct pmic_table *table,
358c2ecf20Sopenharmony_ci			    int count, int *reg, int *bit)
368c2ecf20Sopenharmony_ci{
378c2ecf20Sopenharmony_ci	int i;
388c2ecf20Sopenharmony_ci
398c2ecf20Sopenharmony_ci	for (i = 0; i < count; i++) {
408c2ecf20Sopenharmony_ci		if (table[i].address == address) {
418c2ecf20Sopenharmony_ci			*reg = table[i].reg;
428c2ecf20Sopenharmony_ci			if (bit)
438c2ecf20Sopenharmony_ci				*bit = table[i].bit;
448c2ecf20Sopenharmony_ci			return 0;
458c2ecf20Sopenharmony_ci		}
468c2ecf20Sopenharmony_ci	}
478c2ecf20Sopenharmony_ci	return -ENOENT;
488c2ecf20Sopenharmony_ci}
498c2ecf20Sopenharmony_ci
508c2ecf20Sopenharmony_cistatic acpi_status intel_pmic_power_handler(u32 function,
518c2ecf20Sopenharmony_ci		acpi_physical_address address, u32 bits, u64 *value64,
528c2ecf20Sopenharmony_ci		void *handler_context, void *region_context)
538c2ecf20Sopenharmony_ci{
548c2ecf20Sopenharmony_ci	struct intel_pmic_opregion *opregion = region_context;
558c2ecf20Sopenharmony_ci	struct regmap *regmap = opregion->regmap;
568c2ecf20Sopenharmony_ci	struct intel_pmic_opregion_data *d = opregion->data;
578c2ecf20Sopenharmony_ci	int reg, bit, result;
588c2ecf20Sopenharmony_ci
598c2ecf20Sopenharmony_ci	if (bits != 32 || !value64)
608c2ecf20Sopenharmony_ci		return AE_BAD_PARAMETER;
618c2ecf20Sopenharmony_ci
628c2ecf20Sopenharmony_ci	if (function == ACPI_WRITE && !(*value64 == 0 || *value64 == 1))
638c2ecf20Sopenharmony_ci		return AE_BAD_PARAMETER;
648c2ecf20Sopenharmony_ci
658c2ecf20Sopenharmony_ci	result = pmic_get_reg_bit(address, d->power_table,
668c2ecf20Sopenharmony_ci				  d->power_table_count, &reg, &bit);
678c2ecf20Sopenharmony_ci	if (result == -ENOENT)
688c2ecf20Sopenharmony_ci		return AE_BAD_PARAMETER;
698c2ecf20Sopenharmony_ci
708c2ecf20Sopenharmony_ci	mutex_lock(&opregion->lock);
718c2ecf20Sopenharmony_ci
728c2ecf20Sopenharmony_ci	result = function == ACPI_READ ?
738c2ecf20Sopenharmony_ci		d->get_power(regmap, reg, bit, value64) :
748c2ecf20Sopenharmony_ci		d->update_power(regmap, reg, bit, *value64 == 1);
758c2ecf20Sopenharmony_ci
768c2ecf20Sopenharmony_ci	mutex_unlock(&opregion->lock);
778c2ecf20Sopenharmony_ci
788c2ecf20Sopenharmony_ci	return result ? AE_ERROR : AE_OK;
798c2ecf20Sopenharmony_ci}
808c2ecf20Sopenharmony_ci
818c2ecf20Sopenharmony_cistatic int pmic_read_temp(struct intel_pmic_opregion *opregion,
828c2ecf20Sopenharmony_ci			  int reg, u64 *value)
838c2ecf20Sopenharmony_ci{
848c2ecf20Sopenharmony_ci	int raw_temp, temp;
858c2ecf20Sopenharmony_ci
868c2ecf20Sopenharmony_ci	if (!opregion->data->get_raw_temp)
878c2ecf20Sopenharmony_ci		return -ENXIO;
888c2ecf20Sopenharmony_ci
898c2ecf20Sopenharmony_ci	raw_temp = opregion->data->get_raw_temp(opregion->regmap, reg);
908c2ecf20Sopenharmony_ci	if (raw_temp < 0)
918c2ecf20Sopenharmony_ci		return raw_temp;
928c2ecf20Sopenharmony_ci
938c2ecf20Sopenharmony_ci	if (!opregion->lpat_table) {
948c2ecf20Sopenharmony_ci		*value = raw_temp;
958c2ecf20Sopenharmony_ci		return 0;
968c2ecf20Sopenharmony_ci	}
978c2ecf20Sopenharmony_ci
988c2ecf20Sopenharmony_ci	temp = acpi_lpat_raw_to_temp(opregion->lpat_table, raw_temp);
998c2ecf20Sopenharmony_ci	if (temp < 0)
1008c2ecf20Sopenharmony_ci		return temp;
1018c2ecf20Sopenharmony_ci
1028c2ecf20Sopenharmony_ci	*value = temp;
1038c2ecf20Sopenharmony_ci	return 0;
1048c2ecf20Sopenharmony_ci}
1058c2ecf20Sopenharmony_ci
1068c2ecf20Sopenharmony_cistatic int pmic_thermal_temp(struct intel_pmic_opregion *opregion, int reg,
1078c2ecf20Sopenharmony_ci			     u32 function, u64 *value)
1088c2ecf20Sopenharmony_ci{
1098c2ecf20Sopenharmony_ci	return function == ACPI_READ ?
1108c2ecf20Sopenharmony_ci		pmic_read_temp(opregion, reg, value) : -EINVAL;
1118c2ecf20Sopenharmony_ci}
1128c2ecf20Sopenharmony_ci
1138c2ecf20Sopenharmony_cistatic int pmic_thermal_aux(struct intel_pmic_opregion *opregion, int reg,
1148c2ecf20Sopenharmony_ci			    u32 function, u64 *value)
1158c2ecf20Sopenharmony_ci{
1168c2ecf20Sopenharmony_ci	int raw_temp;
1178c2ecf20Sopenharmony_ci
1188c2ecf20Sopenharmony_ci	if (function == ACPI_READ)
1198c2ecf20Sopenharmony_ci		return pmic_read_temp(opregion, reg, value);
1208c2ecf20Sopenharmony_ci
1218c2ecf20Sopenharmony_ci	if (!opregion->data->update_aux)
1228c2ecf20Sopenharmony_ci		return -ENXIO;
1238c2ecf20Sopenharmony_ci
1248c2ecf20Sopenharmony_ci	if (opregion->lpat_table) {
1258c2ecf20Sopenharmony_ci		raw_temp = acpi_lpat_temp_to_raw(opregion->lpat_table, *value);
1268c2ecf20Sopenharmony_ci		if (raw_temp < 0)
1278c2ecf20Sopenharmony_ci			return raw_temp;
1288c2ecf20Sopenharmony_ci	} else {
1298c2ecf20Sopenharmony_ci		raw_temp = *value;
1308c2ecf20Sopenharmony_ci	}
1318c2ecf20Sopenharmony_ci
1328c2ecf20Sopenharmony_ci	return opregion->data->update_aux(opregion->regmap, reg, raw_temp);
1338c2ecf20Sopenharmony_ci}
1348c2ecf20Sopenharmony_ci
1358c2ecf20Sopenharmony_cistatic int pmic_thermal_pen(struct intel_pmic_opregion *opregion, int reg,
1368c2ecf20Sopenharmony_ci			    int bit, u32 function, u64 *value)
1378c2ecf20Sopenharmony_ci{
1388c2ecf20Sopenharmony_ci	struct intel_pmic_opregion_data *d = opregion->data;
1398c2ecf20Sopenharmony_ci	struct regmap *regmap = opregion->regmap;
1408c2ecf20Sopenharmony_ci
1418c2ecf20Sopenharmony_ci	if (!d->get_policy || !d->update_policy)
1428c2ecf20Sopenharmony_ci		return -ENXIO;
1438c2ecf20Sopenharmony_ci
1448c2ecf20Sopenharmony_ci	if (function == ACPI_READ)
1458c2ecf20Sopenharmony_ci		return d->get_policy(regmap, reg, bit, value);
1468c2ecf20Sopenharmony_ci
1478c2ecf20Sopenharmony_ci	if (*value != 0 && *value != 1)
1488c2ecf20Sopenharmony_ci		return -EINVAL;
1498c2ecf20Sopenharmony_ci
1508c2ecf20Sopenharmony_ci	return d->update_policy(regmap, reg, bit, *value);
1518c2ecf20Sopenharmony_ci}
1528c2ecf20Sopenharmony_ci
1538c2ecf20Sopenharmony_cistatic bool pmic_thermal_is_temp(int address)
1548c2ecf20Sopenharmony_ci{
1558c2ecf20Sopenharmony_ci	return (address <= 0x3c) && !(address % 12);
1568c2ecf20Sopenharmony_ci}
1578c2ecf20Sopenharmony_ci
1588c2ecf20Sopenharmony_cistatic bool pmic_thermal_is_aux(int address)
1598c2ecf20Sopenharmony_ci{
1608c2ecf20Sopenharmony_ci	return (address >= 4 && address <= 0x40 && !((address - 4) % 12)) ||
1618c2ecf20Sopenharmony_ci	       (address >= 8 && address <= 0x44 && !((address - 8) % 12));
1628c2ecf20Sopenharmony_ci}
1638c2ecf20Sopenharmony_ci
1648c2ecf20Sopenharmony_cistatic bool pmic_thermal_is_pen(int address)
1658c2ecf20Sopenharmony_ci{
1668c2ecf20Sopenharmony_ci	return address >= 0x48 && address <= 0x5c;
1678c2ecf20Sopenharmony_ci}
1688c2ecf20Sopenharmony_ci
1698c2ecf20Sopenharmony_cistatic acpi_status intel_pmic_thermal_handler(u32 function,
1708c2ecf20Sopenharmony_ci		acpi_physical_address address, u32 bits, u64 *value64,
1718c2ecf20Sopenharmony_ci		void *handler_context, void *region_context)
1728c2ecf20Sopenharmony_ci{
1738c2ecf20Sopenharmony_ci	struct intel_pmic_opregion *opregion = region_context;
1748c2ecf20Sopenharmony_ci	struct intel_pmic_opregion_data *d = opregion->data;
1758c2ecf20Sopenharmony_ci	int reg, bit, result;
1768c2ecf20Sopenharmony_ci
1778c2ecf20Sopenharmony_ci	if (bits != 32 || !value64)
1788c2ecf20Sopenharmony_ci		return AE_BAD_PARAMETER;
1798c2ecf20Sopenharmony_ci
1808c2ecf20Sopenharmony_ci	result = pmic_get_reg_bit(address, d->thermal_table,
1818c2ecf20Sopenharmony_ci				  d->thermal_table_count, &reg, &bit);
1828c2ecf20Sopenharmony_ci	if (result == -ENOENT)
1838c2ecf20Sopenharmony_ci		return AE_BAD_PARAMETER;
1848c2ecf20Sopenharmony_ci
1858c2ecf20Sopenharmony_ci	mutex_lock(&opregion->lock);
1868c2ecf20Sopenharmony_ci
1878c2ecf20Sopenharmony_ci	if (pmic_thermal_is_temp(address))
1888c2ecf20Sopenharmony_ci		result = pmic_thermal_temp(opregion, reg, function, value64);
1898c2ecf20Sopenharmony_ci	else if (pmic_thermal_is_aux(address))
1908c2ecf20Sopenharmony_ci		result = pmic_thermal_aux(opregion, reg, function, value64);
1918c2ecf20Sopenharmony_ci	else if (pmic_thermal_is_pen(address))
1928c2ecf20Sopenharmony_ci		result = pmic_thermal_pen(opregion, reg, bit,
1938c2ecf20Sopenharmony_ci						function, value64);
1948c2ecf20Sopenharmony_ci	else
1958c2ecf20Sopenharmony_ci		result = -EINVAL;
1968c2ecf20Sopenharmony_ci
1978c2ecf20Sopenharmony_ci	mutex_unlock(&opregion->lock);
1988c2ecf20Sopenharmony_ci
1998c2ecf20Sopenharmony_ci	if (result < 0) {
2008c2ecf20Sopenharmony_ci		if (result == -EINVAL)
2018c2ecf20Sopenharmony_ci			return AE_BAD_PARAMETER;
2028c2ecf20Sopenharmony_ci		else
2038c2ecf20Sopenharmony_ci			return AE_ERROR;
2048c2ecf20Sopenharmony_ci	}
2058c2ecf20Sopenharmony_ci
2068c2ecf20Sopenharmony_ci	return AE_OK;
2078c2ecf20Sopenharmony_ci}
2088c2ecf20Sopenharmony_ci
2098c2ecf20Sopenharmony_cistatic acpi_status intel_pmic_regs_handler(u32 function,
2108c2ecf20Sopenharmony_ci		acpi_physical_address address, u32 bits, u64 *value64,
2118c2ecf20Sopenharmony_ci		void *handler_context, void *region_context)
2128c2ecf20Sopenharmony_ci{
2138c2ecf20Sopenharmony_ci	struct intel_pmic_opregion *opregion = region_context;
2148c2ecf20Sopenharmony_ci	int result = -EINVAL;
2158c2ecf20Sopenharmony_ci
2168c2ecf20Sopenharmony_ci	if (function == ACPI_WRITE) {
2178c2ecf20Sopenharmony_ci		switch (address) {
2188c2ecf20Sopenharmony_ci		case 0:
2198c2ecf20Sopenharmony_ci			return AE_OK;
2208c2ecf20Sopenharmony_ci		case 1:
2218c2ecf20Sopenharmony_ci			opregion->ctx.addr |= (*value64 & 0xff) << 8;
2228c2ecf20Sopenharmony_ci			return AE_OK;
2238c2ecf20Sopenharmony_ci		case 2:
2248c2ecf20Sopenharmony_ci			opregion->ctx.addr |= *value64 & 0xff;
2258c2ecf20Sopenharmony_ci			return AE_OK;
2268c2ecf20Sopenharmony_ci		case 3:
2278c2ecf20Sopenharmony_ci			opregion->ctx.val = *value64 & 0xff;
2288c2ecf20Sopenharmony_ci			return AE_OK;
2298c2ecf20Sopenharmony_ci		case 4:
2308c2ecf20Sopenharmony_ci			if (*value64) {
2318c2ecf20Sopenharmony_ci				result = regmap_write(opregion->regmap, opregion->ctx.addr,
2328c2ecf20Sopenharmony_ci						      opregion->ctx.val);
2338c2ecf20Sopenharmony_ci			} else {
2348c2ecf20Sopenharmony_ci				result = regmap_read(opregion->regmap, opregion->ctx.addr,
2358c2ecf20Sopenharmony_ci						     &opregion->ctx.val);
2368c2ecf20Sopenharmony_ci			}
2378c2ecf20Sopenharmony_ci			opregion->ctx.addr = 0;
2388c2ecf20Sopenharmony_ci		}
2398c2ecf20Sopenharmony_ci	}
2408c2ecf20Sopenharmony_ci
2418c2ecf20Sopenharmony_ci	if (function == ACPI_READ && address == 3) {
2428c2ecf20Sopenharmony_ci		*value64 = opregion->ctx.val;
2438c2ecf20Sopenharmony_ci		return AE_OK;
2448c2ecf20Sopenharmony_ci	}
2458c2ecf20Sopenharmony_ci
2468c2ecf20Sopenharmony_ci	if (result < 0) {
2478c2ecf20Sopenharmony_ci		if (result == -EINVAL)
2488c2ecf20Sopenharmony_ci			return AE_BAD_PARAMETER;
2498c2ecf20Sopenharmony_ci		else
2508c2ecf20Sopenharmony_ci			return AE_ERROR;
2518c2ecf20Sopenharmony_ci	}
2528c2ecf20Sopenharmony_ci
2538c2ecf20Sopenharmony_ci	return AE_OK;
2548c2ecf20Sopenharmony_ci}
2558c2ecf20Sopenharmony_ci
2568c2ecf20Sopenharmony_ciint intel_pmic_install_opregion_handler(struct device *dev, acpi_handle handle,
2578c2ecf20Sopenharmony_ci					struct regmap *regmap,
2588c2ecf20Sopenharmony_ci					struct intel_pmic_opregion_data *d)
2598c2ecf20Sopenharmony_ci{
2608c2ecf20Sopenharmony_ci	acpi_status status = AE_OK;
2618c2ecf20Sopenharmony_ci	struct intel_pmic_opregion *opregion;
2628c2ecf20Sopenharmony_ci	int ret;
2638c2ecf20Sopenharmony_ci
2648c2ecf20Sopenharmony_ci	if (!dev || !regmap || !d)
2658c2ecf20Sopenharmony_ci		return -EINVAL;
2668c2ecf20Sopenharmony_ci
2678c2ecf20Sopenharmony_ci	if (!handle)
2688c2ecf20Sopenharmony_ci		return -ENODEV;
2698c2ecf20Sopenharmony_ci
2708c2ecf20Sopenharmony_ci	opregion = devm_kzalloc(dev, sizeof(*opregion), GFP_KERNEL);
2718c2ecf20Sopenharmony_ci	if (!opregion)
2728c2ecf20Sopenharmony_ci		return -ENOMEM;
2738c2ecf20Sopenharmony_ci
2748c2ecf20Sopenharmony_ci	mutex_init(&opregion->lock);
2758c2ecf20Sopenharmony_ci	opregion->regmap = regmap;
2768c2ecf20Sopenharmony_ci	opregion->lpat_table = acpi_lpat_get_conversion_table(handle);
2778c2ecf20Sopenharmony_ci
2788c2ecf20Sopenharmony_ci	if (d->power_table_count)
2798c2ecf20Sopenharmony_ci		status = acpi_install_address_space_handler(handle,
2808c2ecf20Sopenharmony_ci						    PMIC_POWER_OPREGION_ID,
2818c2ecf20Sopenharmony_ci						    intel_pmic_power_handler,
2828c2ecf20Sopenharmony_ci						    NULL, opregion);
2838c2ecf20Sopenharmony_ci	if (ACPI_FAILURE(status)) {
2848c2ecf20Sopenharmony_ci		ret = -ENODEV;
2858c2ecf20Sopenharmony_ci		goto out_error;
2868c2ecf20Sopenharmony_ci	}
2878c2ecf20Sopenharmony_ci
2888c2ecf20Sopenharmony_ci	if (d->thermal_table_count)
2898c2ecf20Sopenharmony_ci		status = acpi_install_address_space_handler(handle,
2908c2ecf20Sopenharmony_ci						    PMIC_THERMAL_OPREGION_ID,
2918c2ecf20Sopenharmony_ci						    intel_pmic_thermal_handler,
2928c2ecf20Sopenharmony_ci						    NULL, opregion);
2938c2ecf20Sopenharmony_ci	if (ACPI_FAILURE(status)) {
2948c2ecf20Sopenharmony_ci		ret = -ENODEV;
2958c2ecf20Sopenharmony_ci		goto out_remove_power_handler;
2968c2ecf20Sopenharmony_ci	}
2978c2ecf20Sopenharmony_ci
2988c2ecf20Sopenharmony_ci	status = acpi_install_address_space_handler(handle,
2998c2ecf20Sopenharmony_ci			PMIC_REGS_OPREGION_ID, intel_pmic_regs_handler, NULL,
3008c2ecf20Sopenharmony_ci			opregion);
3018c2ecf20Sopenharmony_ci	if (ACPI_FAILURE(status)) {
3028c2ecf20Sopenharmony_ci		ret = -ENODEV;
3038c2ecf20Sopenharmony_ci		goto out_remove_thermal_handler;
3048c2ecf20Sopenharmony_ci	}
3058c2ecf20Sopenharmony_ci
3068c2ecf20Sopenharmony_ci	opregion->data = d;
3078c2ecf20Sopenharmony_ci	intel_pmic_opregion = opregion;
3088c2ecf20Sopenharmony_ci	return 0;
3098c2ecf20Sopenharmony_ci
3108c2ecf20Sopenharmony_ciout_remove_thermal_handler:
3118c2ecf20Sopenharmony_ci	if (d->thermal_table_count)
3128c2ecf20Sopenharmony_ci		acpi_remove_address_space_handler(handle,
3138c2ecf20Sopenharmony_ci						  PMIC_THERMAL_OPREGION_ID,
3148c2ecf20Sopenharmony_ci						  intel_pmic_thermal_handler);
3158c2ecf20Sopenharmony_ci
3168c2ecf20Sopenharmony_ciout_remove_power_handler:
3178c2ecf20Sopenharmony_ci	if (d->power_table_count)
3188c2ecf20Sopenharmony_ci		acpi_remove_address_space_handler(handle,
3198c2ecf20Sopenharmony_ci						  PMIC_POWER_OPREGION_ID,
3208c2ecf20Sopenharmony_ci						  intel_pmic_power_handler);
3218c2ecf20Sopenharmony_ci
3228c2ecf20Sopenharmony_ciout_error:
3238c2ecf20Sopenharmony_ci	acpi_lpat_free_conversion_table(opregion->lpat_table);
3248c2ecf20Sopenharmony_ci	return ret;
3258c2ecf20Sopenharmony_ci}
3268c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(intel_pmic_install_opregion_handler);
3278c2ecf20Sopenharmony_ci
3288c2ecf20Sopenharmony_ci/**
3298c2ecf20Sopenharmony_ci * intel_soc_pmic_exec_mipi_pmic_seq_element - Execute PMIC MIPI sequence
3308c2ecf20Sopenharmony_ci * @i2c_address:  I2C client address for the PMIC
3318c2ecf20Sopenharmony_ci * @reg_address:  PMIC register address
3328c2ecf20Sopenharmony_ci * @value:        New value for the register bits to change
3338c2ecf20Sopenharmony_ci * @mask:         Mask indicating which register bits to change
3348c2ecf20Sopenharmony_ci *
3358c2ecf20Sopenharmony_ci * DSI LCD panels describe an initialization sequence in the i915 VBT (Video
3368c2ecf20Sopenharmony_ci * BIOS Tables) using so called MIPI sequences. One possible element in these
3378c2ecf20Sopenharmony_ci * sequences is a PMIC specific element of 15 bytes.
3388c2ecf20Sopenharmony_ci *
3398c2ecf20Sopenharmony_ci * This function executes these PMIC specific elements sending the embedded
3408c2ecf20Sopenharmony_ci * commands to the PMIC.
3418c2ecf20Sopenharmony_ci *
3428c2ecf20Sopenharmony_ci * Return 0 on success, < 0 on failure.
3438c2ecf20Sopenharmony_ci */
3448c2ecf20Sopenharmony_ciint intel_soc_pmic_exec_mipi_pmic_seq_element(u16 i2c_address, u32 reg_address,
3458c2ecf20Sopenharmony_ci					      u32 value, u32 mask)
3468c2ecf20Sopenharmony_ci{
3478c2ecf20Sopenharmony_ci	struct intel_pmic_opregion_data *d;
3488c2ecf20Sopenharmony_ci	int ret;
3498c2ecf20Sopenharmony_ci
3508c2ecf20Sopenharmony_ci	if (!intel_pmic_opregion) {
3518c2ecf20Sopenharmony_ci		pr_warn("%s: No PMIC registered\n", __func__);
3528c2ecf20Sopenharmony_ci		return -ENXIO;
3538c2ecf20Sopenharmony_ci	}
3548c2ecf20Sopenharmony_ci
3558c2ecf20Sopenharmony_ci	d = intel_pmic_opregion->data;
3568c2ecf20Sopenharmony_ci
3578c2ecf20Sopenharmony_ci	mutex_lock(&intel_pmic_opregion->lock);
3588c2ecf20Sopenharmony_ci
3598c2ecf20Sopenharmony_ci	if (d->exec_mipi_pmic_seq_element) {
3608c2ecf20Sopenharmony_ci		ret = d->exec_mipi_pmic_seq_element(intel_pmic_opregion->regmap,
3618c2ecf20Sopenharmony_ci						    i2c_address, reg_address,
3628c2ecf20Sopenharmony_ci						    value, mask);
3638c2ecf20Sopenharmony_ci	} else if (d->pmic_i2c_address) {
3648c2ecf20Sopenharmony_ci		if (i2c_address == d->pmic_i2c_address) {
3658c2ecf20Sopenharmony_ci			ret = regmap_update_bits(intel_pmic_opregion->regmap,
3668c2ecf20Sopenharmony_ci						 reg_address, mask, value);
3678c2ecf20Sopenharmony_ci		} else {
3688c2ecf20Sopenharmony_ci			pr_err("%s: Unexpected i2c-addr: 0x%02x (reg-addr 0x%x value 0x%x mask 0x%x)\n",
3698c2ecf20Sopenharmony_ci			       __func__, i2c_address, reg_address, value, mask);
3708c2ecf20Sopenharmony_ci			ret = -ENXIO;
3718c2ecf20Sopenharmony_ci		}
3728c2ecf20Sopenharmony_ci	} else {
3738c2ecf20Sopenharmony_ci		pr_warn("%s: Not implemented\n", __func__);
3748c2ecf20Sopenharmony_ci		pr_warn("%s: i2c-addr: 0x%x reg-addr 0x%x value 0x%x mask 0x%x\n",
3758c2ecf20Sopenharmony_ci			__func__, i2c_address, reg_address, value, mask);
3768c2ecf20Sopenharmony_ci		ret = -EOPNOTSUPP;
3778c2ecf20Sopenharmony_ci	}
3788c2ecf20Sopenharmony_ci
3798c2ecf20Sopenharmony_ci	mutex_unlock(&intel_pmic_opregion->lock);
3808c2ecf20Sopenharmony_ci
3818c2ecf20Sopenharmony_ci	return ret;
3828c2ecf20Sopenharmony_ci}
3838c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(intel_soc_pmic_exec_mipi_pmic_seq_element);
384