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