18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Intel CHT Whiskey Cove PMIC operation region driver
48c2ecf20Sopenharmony_ci * Copyright (C) 2017 Hans de Goede <hdegoede@redhat.com>
58c2ecf20Sopenharmony_ci *
68c2ecf20Sopenharmony_ci * Based on various non upstream patches to support the CHT Whiskey Cove PMIC:
78c2ecf20Sopenharmony_ci * Copyright (C) 2013-2015 Intel Corporation. All rights reserved.
88c2ecf20Sopenharmony_ci */
98c2ecf20Sopenharmony_ci
108c2ecf20Sopenharmony_ci#include <linux/acpi.h>
118c2ecf20Sopenharmony_ci#include <linux/init.h>
128c2ecf20Sopenharmony_ci#include <linux/mfd/intel_soc_pmic.h>
138c2ecf20Sopenharmony_ci#include <linux/platform_device.h>
148c2ecf20Sopenharmony_ci#include <linux/regmap.h>
158c2ecf20Sopenharmony_ci#include "intel_pmic.h"
168c2ecf20Sopenharmony_ci
178c2ecf20Sopenharmony_ci#define CHT_WC_V1P05A_CTRL		0x6e3b
188c2ecf20Sopenharmony_ci#define CHT_WC_V1P15_CTRL		0x6e3c
198c2ecf20Sopenharmony_ci#define CHT_WC_V1P05A_VSEL		0x6e3d
208c2ecf20Sopenharmony_ci#define CHT_WC_V1P15_VSEL		0x6e3e
218c2ecf20Sopenharmony_ci#define CHT_WC_V1P8A_CTRL		0x6e56
228c2ecf20Sopenharmony_ci#define CHT_WC_V1P8SX_CTRL		0x6e57
238c2ecf20Sopenharmony_ci#define CHT_WC_VDDQ_CTRL		0x6e58
248c2ecf20Sopenharmony_ci#define CHT_WC_V1P2A_CTRL		0x6e59
258c2ecf20Sopenharmony_ci#define CHT_WC_V1P2SX_CTRL		0x6e5a
268c2ecf20Sopenharmony_ci#define CHT_WC_V1P8A_VSEL		0x6e5b
278c2ecf20Sopenharmony_ci#define CHT_WC_VDDQ_VSEL		0x6e5c
288c2ecf20Sopenharmony_ci#define CHT_WC_V2P8SX_CTRL		0x6e5d
298c2ecf20Sopenharmony_ci#define CHT_WC_V3P3A_CTRL		0x6e5e
308c2ecf20Sopenharmony_ci#define CHT_WC_V3P3SD_CTRL		0x6e5f
318c2ecf20Sopenharmony_ci#define CHT_WC_VSDIO_CTRL		0x6e67
328c2ecf20Sopenharmony_ci#define CHT_WC_V3P3A_VSEL		0x6e68
338c2ecf20Sopenharmony_ci#define CHT_WC_VPROG1A_CTRL		0x6e90
348c2ecf20Sopenharmony_ci#define CHT_WC_VPROG1B_CTRL		0x6e91
358c2ecf20Sopenharmony_ci#define CHT_WC_VPROG1F_CTRL		0x6e95
368c2ecf20Sopenharmony_ci#define CHT_WC_VPROG2D_CTRL		0x6e99
378c2ecf20Sopenharmony_ci#define CHT_WC_VPROG3A_CTRL		0x6e9a
388c2ecf20Sopenharmony_ci#define CHT_WC_VPROG3B_CTRL		0x6e9b
398c2ecf20Sopenharmony_ci#define CHT_WC_VPROG4A_CTRL		0x6e9c
408c2ecf20Sopenharmony_ci#define CHT_WC_VPROG4B_CTRL		0x6e9d
418c2ecf20Sopenharmony_ci#define CHT_WC_VPROG4C_CTRL		0x6e9e
428c2ecf20Sopenharmony_ci#define CHT_WC_VPROG4D_CTRL		0x6e9f
438c2ecf20Sopenharmony_ci#define CHT_WC_VPROG5A_CTRL		0x6ea0
448c2ecf20Sopenharmony_ci#define CHT_WC_VPROG5B_CTRL		0x6ea1
458c2ecf20Sopenharmony_ci#define CHT_WC_VPROG6A_CTRL		0x6ea2
468c2ecf20Sopenharmony_ci#define CHT_WC_VPROG6B_CTRL		0x6ea3
478c2ecf20Sopenharmony_ci#define CHT_WC_VPROG1A_VSEL		0x6ec0
488c2ecf20Sopenharmony_ci#define CHT_WC_VPROG1B_VSEL		0x6ec1
498c2ecf20Sopenharmony_ci#define CHT_WC_V1P8SX_VSEL		0x6ec2
508c2ecf20Sopenharmony_ci#define CHT_WC_V1P2SX_VSEL		0x6ec3
518c2ecf20Sopenharmony_ci#define CHT_WC_V1P2A_VSEL		0x6ec4
528c2ecf20Sopenharmony_ci#define CHT_WC_VPROG1F_VSEL		0x6ec5
538c2ecf20Sopenharmony_ci#define CHT_WC_VSDIO_VSEL		0x6ec6
548c2ecf20Sopenharmony_ci#define CHT_WC_V2P8SX_VSEL		0x6ec7
558c2ecf20Sopenharmony_ci#define CHT_WC_V3P3SD_VSEL		0x6ec8
568c2ecf20Sopenharmony_ci#define CHT_WC_VPROG2D_VSEL		0x6ec9
578c2ecf20Sopenharmony_ci#define CHT_WC_VPROG3A_VSEL		0x6eca
588c2ecf20Sopenharmony_ci#define CHT_WC_VPROG3B_VSEL		0x6ecb
598c2ecf20Sopenharmony_ci#define CHT_WC_VPROG4A_VSEL		0x6ecc
608c2ecf20Sopenharmony_ci#define CHT_WC_VPROG4B_VSEL		0x6ecd
618c2ecf20Sopenharmony_ci#define CHT_WC_VPROG4C_VSEL		0x6ece
628c2ecf20Sopenharmony_ci#define CHT_WC_VPROG4D_VSEL		0x6ecf
638c2ecf20Sopenharmony_ci#define CHT_WC_VPROG5A_VSEL		0x6ed0
648c2ecf20Sopenharmony_ci#define CHT_WC_VPROG5B_VSEL		0x6ed1
658c2ecf20Sopenharmony_ci#define CHT_WC_VPROG6A_VSEL		0x6ed2
668c2ecf20Sopenharmony_ci#define CHT_WC_VPROG6B_VSEL		0x6ed3
678c2ecf20Sopenharmony_ci
688c2ecf20Sopenharmony_ci/*
698c2ecf20Sopenharmony_ci * Regulator support is based on the non upstream patch:
708c2ecf20Sopenharmony_ci * "regulator: whiskey_cove: implements Whiskey Cove pmic VRF support"
718c2ecf20Sopenharmony_ci * https://github.com/intel-aero/meta-intel-aero/blob/master/recipes-kernel/linux/linux-yocto/0019-regulator-whiskey_cove-implements-WhiskeyCove-pmic-V.patch
728c2ecf20Sopenharmony_ci */
738c2ecf20Sopenharmony_cistatic struct pmic_table power_table[] = {
748c2ecf20Sopenharmony_ci	{
758c2ecf20Sopenharmony_ci		.address = 0x0,
768c2ecf20Sopenharmony_ci		.reg = CHT_WC_V1P8A_CTRL,
778c2ecf20Sopenharmony_ci		.bit = 0x01,
788c2ecf20Sopenharmony_ci	}, /* V18A */
798c2ecf20Sopenharmony_ci	{
808c2ecf20Sopenharmony_ci		.address = 0x04,
818c2ecf20Sopenharmony_ci		.reg = CHT_WC_V1P8SX_CTRL,
828c2ecf20Sopenharmony_ci		.bit = 0x07,
838c2ecf20Sopenharmony_ci	}, /* V18X */
848c2ecf20Sopenharmony_ci	{
858c2ecf20Sopenharmony_ci		.address = 0x08,
868c2ecf20Sopenharmony_ci		.reg = CHT_WC_VDDQ_CTRL,
878c2ecf20Sopenharmony_ci		.bit = 0x01,
888c2ecf20Sopenharmony_ci	}, /* VDDQ */
898c2ecf20Sopenharmony_ci	{
908c2ecf20Sopenharmony_ci		.address = 0x0c,
918c2ecf20Sopenharmony_ci		.reg = CHT_WC_V1P2A_CTRL,
928c2ecf20Sopenharmony_ci		.bit = 0x07,
938c2ecf20Sopenharmony_ci	}, /* V12A */
948c2ecf20Sopenharmony_ci	{
958c2ecf20Sopenharmony_ci		.address = 0x10,
968c2ecf20Sopenharmony_ci		.reg = CHT_WC_V1P2SX_CTRL,
978c2ecf20Sopenharmony_ci		.bit = 0x07,
988c2ecf20Sopenharmony_ci	}, /* V12X */
998c2ecf20Sopenharmony_ci	{
1008c2ecf20Sopenharmony_ci		.address = 0x14,
1018c2ecf20Sopenharmony_ci		.reg = CHT_WC_V2P8SX_CTRL,
1028c2ecf20Sopenharmony_ci		.bit = 0x07,
1038c2ecf20Sopenharmony_ci	}, /* V28X */
1048c2ecf20Sopenharmony_ci	{
1058c2ecf20Sopenharmony_ci		.address = 0x18,
1068c2ecf20Sopenharmony_ci		.reg = CHT_WC_V3P3A_CTRL,
1078c2ecf20Sopenharmony_ci		.bit = 0x01,
1088c2ecf20Sopenharmony_ci	}, /* V33A */
1098c2ecf20Sopenharmony_ci	{
1108c2ecf20Sopenharmony_ci		.address = 0x1c,
1118c2ecf20Sopenharmony_ci		.reg = CHT_WC_V3P3SD_CTRL,
1128c2ecf20Sopenharmony_ci		.bit = 0x07,
1138c2ecf20Sopenharmony_ci	}, /* V3SD */
1148c2ecf20Sopenharmony_ci	{
1158c2ecf20Sopenharmony_ci		.address = 0x20,
1168c2ecf20Sopenharmony_ci		.reg = CHT_WC_VSDIO_CTRL,
1178c2ecf20Sopenharmony_ci		.bit = 0x07,
1188c2ecf20Sopenharmony_ci	}, /* VSD */
1198c2ecf20Sopenharmony_ci/*	{
1208c2ecf20Sopenharmony_ci		.address = 0x24,
1218c2ecf20Sopenharmony_ci		.reg = ??,
1228c2ecf20Sopenharmony_ci		.bit = ??,
1238c2ecf20Sopenharmony_ci	}, ** VSW2 */
1248c2ecf20Sopenharmony_ci/*	{
1258c2ecf20Sopenharmony_ci		.address = 0x28,
1268c2ecf20Sopenharmony_ci		.reg = ??,
1278c2ecf20Sopenharmony_ci		.bit = ??,
1288c2ecf20Sopenharmony_ci	}, ** VSW1 */
1298c2ecf20Sopenharmony_ci/*	{
1308c2ecf20Sopenharmony_ci		.address = 0x2c,
1318c2ecf20Sopenharmony_ci		.reg = ??,
1328c2ecf20Sopenharmony_ci		.bit = ??,
1338c2ecf20Sopenharmony_ci	}, ** VUPY */
1348c2ecf20Sopenharmony_ci/*	{
1358c2ecf20Sopenharmony_ci		.address = 0x30,
1368c2ecf20Sopenharmony_ci		.reg = ??,
1378c2ecf20Sopenharmony_ci		.bit = ??,
1388c2ecf20Sopenharmony_ci	}, ** VRSO */
1398c2ecf20Sopenharmony_ci	{
1408c2ecf20Sopenharmony_ci		.address = 0x34,
1418c2ecf20Sopenharmony_ci		.reg = CHT_WC_VPROG1A_CTRL,
1428c2ecf20Sopenharmony_ci		.bit = 0x07,
1438c2ecf20Sopenharmony_ci	}, /* VP1A */
1448c2ecf20Sopenharmony_ci	{
1458c2ecf20Sopenharmony_ci		.address = 0x38,
1468c2ecf20Sopenharmony_ci		.reg = CHT_WC_VPROG1B_CTRL,
1478c2ecf20Sopenharmony_ci		.bit = 0x07,
1488c2ecf20Sopenharmony_ci	}, /* VP1B */
1498c2ecf20Sopenharmony_ci	{
1508c2ecf20Sopenharmony_ci		.address = 0x3c,
1518c2ecf20Sopenharmony_ci		.reg = CHT_WC_VPROG1F_CTRL,
1528c2ecf20Sopenharmony_ci		.bit = 0x07,
1538c2ecf20Sopenharmony_ci	}, /* VP1F */
1548c2ecf20Sopenharmony_ci	{
1558c2ecf20Sopenharmony_ci		.address = 0x40,
1568c2ecf20Sopenharmony_ci		.reg = CHT_WC_VPROG2D_CTRL,
1578c2ecf20Sopenharmony_ci		.bit = 0x07,
1588c2ecf20Sopenharmony_ci	}, /* VP2D */
1598c2ecf20Sopenharmony_ci	{
1608c2ecf20Sopenharmony_ci		.address = 0x44,
1618c2ecf20Sopenharmony_ci		.reg = CHT_WC_VPROG3A_CTRL,
1628c2ecf20Sopenharmony_ci		.bit = 0x07,
1638c2ecf20Sopenharmony_ci	}, /* VP3A */
1648c2ecf20Sopenharmony_ci	{
1658c2ecf20Sopenharmony_ci		.address = 0x48,
1668c2ecf20Sopenharmony_ci		.reg = CHT_WC_VPROG3B_CTRL,
1678c2ecf20Sopenharmony_ci		.bit = 0x07,
1688c2ecf20Sopenharmony_ci	}, /* VP3B */
1698c2ecf20Sopenharmony_ci	{
1708c2ecf20Sopenharmony_ci		.address = 0x4c,
1718c2ecf20Sopenharmony_ci		.reg = CHT_WC_VPROG4A_CTRL,
1728c2ecf20Sopenharmony_ci		.bit = 0x07,
1738c2ecf20Sopenharmony_ci	}, /* VP4A */
1748c2ecf20Sopenharmony_ci	{
1758c2ecf20Sopenharmony_ci		.address = 0x50,
1768c2ecf20Sopenharmony_ci		.reg = CHT_WC_VPROG4B_CTRL,
1778c2ecf20Sopenharmony_ci		.bit = 0x07,
1788c2ecf20Sopenharmony_ci	}, /* VP4B */
1798c2ecf20Sopenharmony_ci	{
1808c2ecf20Sopenharmony_ci		.address = 0x54,
1818c2ecf20Sopenharmony_ci		.reg = CHT_WC_VPROG4C_CTRL,
1828c2ecf20Sopenharmony_ci		.bit = 0x07,
1838c2ecf20Sopenharmony_ci	}, /* VP4C */
1848c2ecf20Sopenharmony_ci	{
1858c2ecf20Sopenharmony_ci		.address = 0x58,
1868c2ecf20Sopenharmony_ci		.reg = CHT_WC_VPROG4D_CTRL,
1878c2ecf20Sopenharmony_ci		.bit = 0x07,
1888c2ecf20Sopenharmony_ci	}, /* VP4D */
1898c2ecf20Sopenharmony_ci	{
1908c2ecf20Sopenharmony_ci		.address = 0x5c,
1918c2ecf20Sopenharmony_ci		.reg = CHT_WC_VPROG5A_CTRL,
1928c2ecf20Sopenharmony_ci		.bit = 0x07,
1938c2ecf20Sopenharmony_ci	}, /* VP5A */
1948c2ecf20Sopenharmony_ci	{
1958c2ecf20Sopenharmony_ci		.address = 0x60,
1968c2ecf20Sopenharmony_ci		.reg = CHT_WC_VPROG5B_CTRL,
1978c2ecf20Sopenharmony_ci		.bit = 0x07,
1988c2ecf20Sopenharmony_ci	}, /* VP5B */
1998c2ecf20Sopenharmony_ci	{
2008c2ecf20Sopenharmony_ci		.address = 0x64,
2018c2ecf20Sopenharmony_ci		.reg = CHT_WC_VPROG6A_CTRL,
2028c2ecf20Sopenharmony_ci		.bit = 0x07,
2038c2ecf20Sopenharmony_ci	}, /* VP6A */
2048c2ecf20Sopenharmony_ci	{
2058c2ecf20Sopenharmony_ci		.address = 0x68,
2068c2ecf20Sopenharmony_ci		.reg = CHT_WC_VPROG6B_CTRL,
2078c2ecf20Sopenharmony_ci		.bit = 0x07,
2088c2ecf20Sopenharmony_ci	}, /* VP6B */
2098c2ecf20Sopenharmony_ci/*	{
2108c2ecf20Sopenharmony_ci		.address = 0x6c,
2118c2ecf20Sopenharmony_ci		.reg = ??,
2128c2ecf20Sopenharmony_ci		.bit = ??,
2138c2ecf20Sopenharmony_ci	}  ** VP7A */
2148c2ecf20Sopenharmony_ci};
2158c2ecf20Sopenharmony_ci
2168c2ecf20Sopenharmony_cistatic int intel_cht_wc_pmic_get_power(struct regmap *regmap, int reg,
2178c2ecf20Sopenharmony_ci		int bit, u64 *value)
2188c2ecf20Sopenharmony_ci{
2198c2ecf20Sopenharmony_ci	int data;
2208c2ecf20Sopenharmony_ci
2218c2ecf20Sopenharmony_ci	if (regmap_read(regmap, reg, &data))
2228c2ecf20Sopenharmony_ci		return -EIO;
2238c2ecf20Sopenharmony_ci
2248c2ecf20Sopenharmony_ci	*value = (data & bit) ? 1 : 0;
2258c2ecf20Sopenharmony_ci	return 0;
2268c2ecf20Sopenharmony_ci}
2278c2ecf20Sopenharmony_ci
2288c2ecf20Sopenharmony_cistatic int intel_cht_wc_pmic_update_power(struct regmap *regmap, int reg,
2298c2ecf20Sopenharmony_ci		int bitmask, bool on)
2308c2ecf20Sopenharmony_ci{
2318c2ecf20Sopenharmony_ci	return regmap_update_bits(regmap, reg, bitmask, on ? 1 : 0);
2328c2ecf20Sopenharmony_ci}
2338c2ecf20Sopenharmony_ci
2348c2ecf20Sopenharmony_cistatic int intel_cht_wc_exec_mipi_pmic_seq_element(struct regmap *regmap,
2358c2ecf20Sopenharmony_ci						   u16 i2c_client_address,
2368c2ecf20Sopenharmony_ci						   u32 reg_address,
2378c2ecf20Sopenharmony_ci						   u32 value, u32 mask)
2388c2ecf20Sopenharmony_ci{
2398c2ecf20Sopenharmony_ci	u32 address;
2408c2ecf20Sopenharmony_ci
2418c2ecf20Sopenharmony_ci	if (i2c_client_address > 0xff || reg_address > 0xff) {
2428c2ecf20Sopenharmony_ci		pr_warn("%s warning addresses too big client 0x%x reg 0x%x\n",
2438c2ecf20Sopenharmony_ci			__func__, i2c_client_address, reg_address);
2448c2ecf20Sopenharmony_ci		return -ERANGE;
2458c2ecf20Sopenharmony_ci	}
2468c2ecf20Sopenharmony_ci
2478c2ecf20Sopenharmony_ci	address = (i2c_client_address << 8) | reg_address;
2488c2ecf20Sopenharmony_ci
2498c2ecf20Sopenharmony_ci	return regmap_update_bits(regmap, address, mask, value);
2508c2ecf20Sopenharmony_ci}
2518c2ecf20Sopenharmony_ci
2528c2ecf20Sopenharmony_ci/*
2538c2ecf20Sopenharmony_ci * The thermal table and ops are empty, we do not support the Thermal opregion
2548c2ecf20Sopenharmony_ci * (DPTF) due to lacking documentation.
2558c2ecf20Sopenharmony_ci */
2568c2ecf20Sopenharmony_cistatic struct intel_pmic_opregion_data intel_cht_wc_pmic_opregion_data = {
2578c2ecf20Sopenharmony_ci	.get_power		= intel_cht_wc_pmic_get_power,
2588c2ecf20Sopenharmony_ci	.update_power		= intel_cht_wc_pmic_update_power,
2598c2ecf20Sopenharmony_ci	.exec_mipi_pmic_seq_element = intel_cht_wc_exec_mipi_pmic_seq_element,
2608c2ecf20Sopenharmony_ci	.power_table		= power_table,
2618c2ecf20Sopenharmony_ci	.power_table_count	= ARRAY_SIZE(power_table),
2628c2ecf20Sopenharmony_ci};
2638c2ecf20Sopenharmony_ci
2648c2ecf20Sopenharmony_cistatic int intel_cht_wc_pmic_opregion_probe(struct platform_device *pdev)
2658c2ecf20Sopenharmony_ci{
2668c2ecf20Sopenharmony_ci	struct intel_soc_pmic *pmic = dev_get_drvdata(pdev->dev.parent);
2678c2ecf20Sopenharmony_ci
2688c2ecf20Sopenharmony_ci	return intel_pmic_install_opregion_handler(&pdev->dev,
2698c2ecf20Sopenharmony_ci			ACPI_HANDLE(pdev->dev.parent),
2708c2ecf20Sopenharmony_ci			pmic->regmap,
2718c2ecf20Sopenharmony_ci			&intel_cht_wc_pmic_opregion_data);
2728c2ecf20Sopenharmony_ci}
2738c2ecf20Sopenharmony_ci
2748c2ecf20Sopenharmony_cistatic const struct platform_device_id cht_wc_opregion_id_table[] = {
2758c2ecf20Sopenharmony_ci	{ .name = "cht_wcove_region" },
2768c2ecf20Sopenharmony_ci	{},
2778c2ecf20Sopenharmony_ci};
2788c2ecf20Sopenharmony_ci
2798c2ecf20Sopenharmony_cistatic struct platform_driver intel_cht_wc_pmic_opregion_driver = {
2808c2ecf20Sopenharmony_ci	.probe = intel_cht_wc_pmic_opregion_probe,
2818c2ecf20Sopenharmony_ci	.driver = {
2828c2ecf20Sopenharmony_ci		.name = "cht_whiskey_cove_pmic",
2838c2ecf20Sopenharmony_ci	},
2848c2ecf20Sopenharmony_ci	.id_table = cht_wc_opregion_id_table,
2858c2ecf20Sopenharmony_ci};
2868c2ecf20Sopenharmony_cibuiltin_platform_driver(intel_cht_wc_pmic_opregion_driver);
287