162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Intel CHT Whiskey Cove PMIC operation region driver
462306a36Sopenharmony_ci * Copyright (C) 2017 Hans de Goede <hdegoede@redhat.com>
562306a36Sopenharmony_ci *
662306a36Sopenharmony_ci * Based on various non upstream patches to support the CHT Whiskey Cove PMIC:
762306a36Sopenharmony_ci * Copyright (C) 2013-2015 Intel Corporation. All rights reserved.
862306a36Sopenharmony_ci */
962306a36Sopenharmony_ci
1062306a36Sopenharmony_ci#include <linux/acpi.h>
1162306a36Sopenharmony_ci#include <linux/init.h>
1262306a36Sopenharmony_ci#include <linux/mfd/intel_soc_pmic.h>
1362306a36Sopenharmony_ci#include <linux/platform_device.h>
1462306a36Sopenharmony_ci#include <linux/regmap.h>
1562306a36Sopenharmony_ci#include "intel_pmic.h"
1662306a36Sopenharmony_ci
1762306a36Sopenharmony_ci#define CHT_WC_V1P05A_CTRL		0x6e3b
1862306a36Sopenharmony_ci#define CHT_WC_V1P15_CTRL		0x6e3c
1962306a36Sopenharmony_ci#define CHT_WC_V1P05A_VSEL		0x6e3d
2062306a36Sopenharmony_ci#define CHT_WC_V1P15_VSEL		0x6e3e
2162306a36Sopenharmony_ci#define CHT_WC_V1P8A_CTRL		0x6e56
2262306a36Sopenharmony_ci#define CHT_WC_V1P8SX_CTRL		0x6e57
2362306a36Sopenharmony_ci#define CHT_WC_VDDQ_CTRL		0x6e58
2462306a36Sopenharmony_ci#define CHT_WC_V1P2A_CTRL		0x6e59
2562306a36Sopenharmony_ci#define CHT_WC_V1P2SX_CTRL		0x6e5a
2662306a36Sopenharmony_ci#define CHT_WC_V1P8A_VSEL		0x6e5b
2762306a36Sopenharmony_ci#define CHT_WC_VDDQ_VSEL		0x6e5c
2862306a36Sopenharmony_ci#define CHT_WC_V2P8SX_CTRL		0x6e5d
2962306a36Sopenharmony_ci#define CHT_WC_V3P3A_CTRL		0x6e5e
3062306a36Sopenharmony_ci#define CHT_WC_V3P3SD_CTRL		0x6e5f
3162306a36Sopenharmony_ci#define CHT_WC_VSDIO_CTRL		0x6e67
3262306a36Sopenharmony_ci#define CHT_WC_V3P3A_VSEL		0x6e68
3362306a36Sopenharmony_ci#define CHT_WC_VPROG1A_CTRL		0x6e90
3462306a36Sopenharmony_ci#define CHT_WC_VPROG1B_CTRL		0x6e91
3562306a36Sopenharmony_ci#define CHT_WC_VPROG1F_CTRL		0x6e95
3662306a36Sopenharmony_ci#define CHT_WC_VPROG2D_CTRL		0x6e99
3762306a36Sopenharmony_ci#define CHT_WC_VPROG3A_CTRL		0x6e9a
3862306a36Sopenharmony_ci#define CHT_WC_VPROG3B_CTRL		0x6e9b
3962306a36Sopenharmony_ci#define CHT_WC_VPROG4A_CTRL		0x6e9c
4062306a36Sopenharmony_ci#define CHT_WC_VPROG4B_CTRL		0x6e9d
4162306a36Sopenharmony_ci#define CHT_WC_VPROG4C_CTRL		0x6e9e
4262306a36Sopenharmony_ci#define CHT_WC_VPROG4D_CTRL		0x6e9f
4362306a36Sopenharmony_ci#define CHT_WC_VPROG5A_CTRL		0x6ea0
4462306a36Sopenharmony_ci#define CHT_WC_VPROG5B_CTRL		0x6ea1
4562306a36Sopenharmony_ci#define CHT_WC_VPROG6A_CTRL		0x6ea2
4662306a36Sopenharmony_ci#define CHT_WC_VPROG6B_CTRL		0x6ea3
4762306a36Sopenharmony_ci#define CHT_WC_VPROG1A_VSEL		0x6ec0
4862306a36Sopenharmony_ci#define CHT_WC_VPROG1B_VSEL		0x6ec1
4962306a36Sopenharmony_ci#define CHT_WC_V1P8SX_VSEL		0x6ec2
5062306a36Sopenharmony_ci#define CHT_WC_V1P2SX_VSEL		0x6ec3
5162306a36Sopenharmony_ci#define CHT_WC_V1P2A_VSEL		0x6ec4
5262306a36Sopenharmony_ci#define CHT_WC_VPROG1F_VSEL		0x6ec5
5362306a36Sopenharmony_ci#define CHT_WC_VSDIO_VSEL		0x6ec6
5462306a36Sopenharmony_ci#define CHT_WC_V2P8SX_VSEL		0x6ec7
5562306a36Sopenharmony_ci#define CHT_WC_V3P3SD_VSEL		0x6ec8
5662306a36Sopenharmony_ci#define CHT_WC_VPROG2D_VSEL		0x6ec9
5762306a36Sopenharmony_ci#define CHT_WC_VPROG3A_VSEL		0x6eca
5862306a36Sopenharmony_ci#define CHT_WC_VPROG3B_VSEL		0x6ecb
5962306a36Sopenharmony_ci#define CHT_WC_VPROG4A_VSEL		0x6ecc
6062306a36Sopenharmony_ci#define CHT_WC_VPROG4B_VSEL		0x6ecd
6162306a36Sopenharmony_ci#define CHT_WC_VPROG4C_VSEL		0x6ece
6262306a36Sopenharmony_ci#define CHT_WC_VPROG4D_VSEL		0x6ecf
6362306a36Sopenharmony_ci#define CHT_WC_VPROG5A_VSEL		0x6ed0
6462306a36Sopenharmony_ci#define CHT_WC_VPROG5B_VSEL		0x6ed1
6562306a36Sopenharmony_ci#define CHT_WC_VPROG6A_VSEL		0x6ed2
6662306a36Sopenharmony_ci#define CHT_WC_VPROG6B_VSEL		0x6ed3
6762306a36Sopenharmony_ci
6862306a36Sopenharmony_ci/*
6962306a36Sopenharmony_ci * Regulator support is based on the non upstream patch:
7062306a36Sopenharmony_ci * "regulator: whiskey_cove: implements Whiskey Cove pmic VRF support"
7162306a36Sopenharmony_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
7262306a36Sopenharmony_ci */
7362306a36Sopenharmony_cistatic struct pmic_table power_table[] = {
7462306a36Sopenharmony_ci	{
7562306a36Sopenharmony_ci		.address = 0x0,
7662306a36Sopenharmony_ci		.reg = CHT_WC_V1P8A_CTRL,
7762306a36Sopenharmony_ci		.bit = 0x01,
7862306a36Sopenharmony_ci	}, /* V18A */
7962306a36Sopenharmony_ci	{
8062306a36Sopenharmony_ci		.address = 0x04,
8162306a36Sopenharmony_ci		.reg = CHT_WC_V1P8SX_CTRL,
8262306a36Sopenharmony_ci		.bit = 0x07,
8362306a36Sopenharmony_ci	}, /* V18X */
8462306a36Sopenharmony_ci	{
8562306a36Sopenharmony_ci		.address = 0x08,
8662306a36Sopenharmony_ci		.reg = CHT_WC_VDDQ_CTRL,
8762306a36Sopenharmony_ci		.bit = 0x01,
8862306a36Sopenharmony_ci	}, /* VDDQ */
8962306a36Sopenharmony_ci	{
9062306a36Sopenharmony_ci		.address = 0x0c,
9162306a36Sopenharmony_ci		.reg = CHT_WC_V1P2A_CTRL,
9262306a36Sopenharmony_ci		.bit = 0x07,
9362306a36Sopenharmony_ci	}, /* V12A */
9462306a36Sopenharmony_ci	{
9562306a36Sopenharmony_ci		.address = 0x10,
9662306a36Sopenharmony_ci		.reg = CHT_WC_V1P2SX_CTRL,
9762306a36Sopenharmony_ci		.bit = 0x07,
9862306a36Sopenharmony_ci	}, /* V12X */
9962306a36Sopenharmony_ci	{
10062306a36Sopenharmony_ci		.address = 0x14,
10162306a36Sopenharmony_ci		.reg = CHT_WC_V2P8SX_CTRL,
10262306a36Sopenharmony_ci		.bit = 0x07,
10362306a36Sopenharmony_ci	}, /* V28X */
10462306a36Sopenharmony_ci	{
10562306a36Sopenharmony_ci		.address = 0x18,
10662306a36Sopenharmony_ci		.reg = CHT_WC_V3P3A_CTRL,
10762306a36Sopenharmony_ci		.bit = 0x01,
10862306a36Sopenharmony_ci	}, /* V33A */
10962306a36Sopenharmony_ci	{
11062306a36Sopenharmony_ci		.address = 0x1c,
11162306a36Sopenharmony_ci		.reg = CHT_WC_V3P3SD_CTRL,
11262306a36Sopenharmony_ci		.bit = 0x07,
11362306a36Sopenharmony_ci	}, /* V3SD */
11462306a36Sopenharmony_ci	{
11562306a36Sopenharmony_ci		.address = 0x20,
11662306a36Sopenharmony_ci		.reg = CHT_WC_VSDIO_CTRL,
11762306a36Sopenharmony_ci		.bit = 0x07,
11862306a36Sopenharmony_ci	}, /* VSD */
11962306a36Sopenharmony_ci/*	{
12062306a36Sopenharmony_ci		.address = 0x24,
12162306a36Sopenharmony_ci		.reg = ??,
12262306a36Sopenharmony_ci		.bit = ??,
12362306a36Sopenharmony_ci	}, ** VSW2 */
12462306a36Sopenharmony_ci/*	{
12562306a36Sopenharmony_ci		.address = 0x28,
12662306a36Sopenharmony_ci		.reg = ??,
12762306a36Sopenharmony_ci		.bit = ??,
12862306a36Sopenharmony_ci	}, ** VSW1 */
12962306a36Sopenharmony_ci/*	{
13062306a36Sopenharmony_ci		.address = 0x2c,
13162306a36Sopenharmony_ci		.reg = ??,
13262306a36Sopenharmony_ci		.bit = ??,
13362306a36Sopenharmony_ci	}, ** VUPY */
13462306a36Sopenharmony_ci/*	{
13562306a36Sopenharmony_ci		.address = 0x30,
13662306a36Sopenharmony_ci		.reg = ??,
13762306a36Sopenharmony_ci		.bit = ??,
13862306a36Sopenharmony_ci	}, ** VRSO */
13962306a36Sopenharmony_ci	{
14062306a36Sopenharmony_ci		.address = 0x34,
14162306a36Sopenharmony_ci		.reg = CHT_WC_VPROG1A_CTRL,
14262306a36Sopenharmony_ci		.bit = 0x07,
14362306a36Sopenharmony_ci	}, /* VP1A */
14462306a36Sopenharmony_ci	{
14562306a36Sopenharmony_ci		.address = 0x38,
14662306a36Sopenharmony_ci		.reg = CHT_WC_VPROG1B_CTRL,
14762306a36Sopenharmony_ci		.bit = 0x07,
14862306a36Sopenharmony_ci	}, /* VP1B */
14962306a36Sopenharmony_ci	{
15062306a36Sopenharmony_ci		.address = 0x3c,
15162306a36Sopenharmony_ci		.reg = CHT_WC_VPROG1F_CTRL,
15262306a36Sopenharmony_ci		.bit = 0x07,
15362306a36Sopenharmony_ci	}, /* VP1F */
15462306a36Sopenharmony_ci	{
15562306a36Sopenharmony_ci		.address = 0x40,
15662306a36Sopenharmony_ci		.reg = CHT_WC_VPROG2D_CTRL,
15762306a36Sopenharmony_ci		.bit = 0x07,
15862306a36Sopenharmony_ci	}, /* VP2D */
15962306a36Sopenharmony_ci	{
16062306a36Sopenharmony_ci		.address = 0x44,
16162306a36Sopenharmony_ci		.reg = CHT_WC_VPROG3A_CTRL,
16262306a36Sopenharmony_ci		.bit = 0x07,
16362306a36Sopenharmony_ci	}, /* VP3A */
16462306a36Sopenharmony_ci	{
16562306a36Sopenharmony_ci		.address = 0x48,
16662306a36Sopenharmony_ci		.reg = CHT_WC_VPROG3B_CTRL,
16762306a36Sopenharmony_ci		.bit = 0x07,
16862306a36Sopenharmony_ci	}, /* VP3B */
16962306a36Sopenharmony_ci	{
17062306a36Sopenharmony_ci		.address = 0x4c,
17162306a36Sopenharmony_ci		.reg = CHT_WC_VPROG4A_CTRL,
17262306a36Sopenharmony_ci		.bit = 0x07,
17362306a36Sopenharmony_ci	}, /* VP4A */
17462306a36Sopenharmony_ci	{
17562306a36Sopenharmony_ci		.address = 0x50,
17662306a36Sopenharmony_ci		.reg = CHT_WC_VPROG4B_CTRL,
17762306a36Sopenharmony_ci		.bit = 0x07,
17862306a36Sopenharmony_ci	}, /* VP4B */
17962306a36Sopenharmony_ci	{
18062306a36Sopenharmony_ci		.address = 0x54,
18162306a36Sopenharmony_ci		.reg = CHT_WC_VPROG4C_CTRL,
18262306a36Sopenharmony_ci		.bit = 0x07,
18362306a36Sopenharmony_ci	}, /* VP4C */
18462306a36Sopenharmony_ci	{
18562306a36Sopenharmony_ci		.address = 0x58,
18662306a36Sopenharmony_ci		.reg = CHT_WC_VPROG4D_CTRL,
18762306a36Sopenharmony_ci		.bit = 0x07,
18862306a36Sopenharmony_ci	}, /* VP4D */
18962306a36Sopenharmony_ci	{
19062306a36Sopenharmony_ci		.address = 0x5c,
19162306a36Sopenharmony_ci		.reg = CHT_WC_VPROG5A_CTRL,
19262306a36Sopenharmony_ci		.bit = 0x07,
19362306a36Sopenharmony_ci	}, /* VP5A */
19462306a36Sopenharmony_ci	{
19562306a36Sopenharmony_ci		.address = 0x60,
19662306a36Sopenharmony_ci		.reg = CHT_WC_VPROG5B_CTRL,
19762306a36Sopenharmony_ci		.bit = 0x07,
19862306a36Sopenharmony_ci	}, /* VP5B */
19962306a36Sopenharmony_ci	{
20062306a36Sopenharmony_ci		.address = 0x64,
20162306a36Sopenharmony_ci		.reg = CHT_WC_VPROG6A_CTRL,
20262306a36Sopenharmony_ci		.bit = 0x07,
20362306a36Sopenharmony_ci	}, /* VP6A */
20462306a36Sopenharmony_ci	{
20562306a36Sopenharmony_ci		.address = 0x68,
20662306a36Sopenharmony_ci		.reg = CHT_WC_VPROG6B_CTRL,
20762306a36Sopenharmony_ci		.bit = 0x07,
20862306a36Sopenharmony_ci	}, /* VP6B */
20962306a36Sopenharmony_ci/*	{
21062306a36Sopenharmony_ci		.address = 0x6c,
21162306a36Sopenharmony_ci		.reg = ??,
21262306a36Sopenharmony_ci		.bit = ??,
21362306a36Sopenharmony_ci	}  ** VP7A */
21462306a36Sopenharmony_ci};
21562306a36Sopenharmony_ci
21662306a36Sopenharmony_cistatic int intel_cht_wc_pmic_get_power(struct regmap *regmap, int reg,
21762306a36Sopenharmony_ci		int bit, u64 *value)
21862306a36Sopenharmony_ci{
21962306a36Sopenharmony_ci	int data;
22062306a36Sopenharmony_ci
22162306a36Sopenharmony_ci	if (regmap_read(regmap, reg, &data))
22262306a36Sopenharmony_ci		return -EIO;
22362306a36Sopenharmony_ci
22462306a36Sopenharmony_ci	*value = (data & bit) ? 1 : 0;
22562306a36Sopenharmony_ci	return 0;
22662306a36Sopenharmony_ci}
22762306a36Sopenharmony_ci
22862306a36Sopenharmony_cistatic int intel_cht_wc_pmic_update_power(struct regmap *regmap, int reg,
22962306a36Sopenharmony_ci		int bitmask, bool on)
23062306a36Sopenharmony_ci{
23162306a36Sopenharmony_ci	return regmap_update_bits(regmap, reg, bitmask, on ? 1 : 0);
23262306a36Sopenharmony_ci}
23362306a36Sopenharmony_ci
23462306a36Sopenharmony_cistatic int intel_cht_wc_exec_mipi_pmic_seq_element(struct regmap *regmap,
23562306a36Sopenharmony_ci						   u16 i2c_client_address,
23662306a36Sopenharmony_ci						   u32 reg_address,
23762306a36Sopenharmony_ci						   u32 value, u32 mask)
23862306a36Sopenharmony_ci{
23962306a36Sopenharmony_ci	u32 address;
24062306a36Sopenharmony_ci
24162306a36Sopenharmony_ci	if (i2c_client_address > 0xff || reg_address > 0xff) {
24262306a36Sopenharmony_ci		pr_warn("%s warning addresses too big client 0x%x reg 0x%x\n",
24362306a36Sopenharmony_ci			__func__, i2c_client_address, reg_address);
24462306a36Sopenharmony_ci		return -ERANGE;
24562306a36Sopenharmony_ci	}
24662306a36Sopenharmony_ci
24762306a36Sopenharmony_ci	address = (i2c_client_address << 8) | reg_address;
24862306a36Sopenharmony_ci
24962306a36Sopenharmony_ci	return regmap_update_bits(regmap, address, mask, value);
25062306a36Sopenharmony_ci}
25162306a36Sopenharmony_ci
25262306a36Sopenharmony_ci/*
25362306a36Sopenharmony_ci * The thermal table and ops are empty, we do not support the Thermal opregion
25462306a36Sopenharmony_ci * (DPTF) due to lacking documentation.
25562306a36Sopenharmony_ci */
25662306a36Sopenharmony_cistatic const struct intel_pmic_opregion_data intel_cht_wc_pmic_opregion_data = {
25762306a36Sopenharmony_ci	.get_power		= intel_cht_wc_pmic_get_power,
25862306a36Sopenharmony_ci	.update_power		= intel_cht_wc_pmic_update_power,
25962306a36Sopenharmony_ci	.exec_mipi_pmic_seq_element = intel_cht_wc_exec_mipi_pmic_seq_element,
26062306a36Sopenharmony_ci	.lpat_raw_to_temp	= acpi_lpat_raw_to_temp,
26162306a36Sopenharmony_ci	.power_table		= power_table,
26262306a36Sopenharmony_ci	.power_table_count	= ARRAY_SIZE(power_table),
26362306a36Sopenharmony_ci};
26462306a36Sopenharmony_ci
26562306a36Sopenharmony_cistatic int intel_cht_wc_pmic_opregion_probe(struct platform_device *pdev)
26662306a36Sopenharmony_ci{
26762306a36Sopenharmony_ci	struct intel_soc_pmic *pmic = dev_get_drvdata(pdev->dev.parent);
26862306a36Sopenharmony_ci
26962306a36Sopenharmony_ci	return intel_pmic_install_opregion_handler(&pdev->dev,
27062306a36Sopenharmony_ci			ACPI_HANDLE(pdev->dev.parent),
27162306a36Sopenharmony_ci			pmic->regmap,
27262306a36Sopenharmony_ci			&intel_cht_wc_pmic_opregion_data);
27362306a36Sopenharmony_ci}
27462306a36Sopenharmony_ci
27562306a36Sopenharmony_cistatic const struct platform_device_id cht_wc_opregion_id_table[] = {
27662306a36Sopenharmony_ci	{ .name = "cht_wcove_region" },
27762306a36Sopenharmony_ci	{},
27862306a36Sopenharmony_ci};
27962306a36Sopenharmony_ci
28062306a36Sopenharmony_cistatic struct platform_driver intel_cht_wc_pmic_opregion_driver = {
28162306a36Sopenharmony_ci	.probe = intel_cht_wc_pmic_opregion_probe,
28262306a36Sopenharmony_ci	.driver = {
28362306a36Sopenharmony_ci		.name = "cht_whiskey_cove_pmic",
28462306a36Sopenharmony_ci	},
28562306a36Sopenharmony_ci	.id_table = cht_wc_opregion_id_table,
28662306a36Sopenharmony_ci};
28762306a36Sopenharmony_cibuiltin_platform_driver(intel_cht_wc_pmic_opregion_driver);
288