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