18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Intel Bay Trail Crystal Cove PMIC operation region driver 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 2014 Intel Corporation. All rights reserved. 68c2ecf20Sopenharmony_ci */ 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci#include <linux/acpi.h> 98c2ecf20Sopenharmony_ci#include <linux/init.h> 108c2ecf20Sopenharmony_ci#include <linux/mfd/intel_soc_pmic.h> 118c2ecf20Sopenharmony_ci#include <linux/platform_device.h> 128c2ecf20Sopenharmony_ci#include <linux/regmap.h> 138c2ecf20Sopenharmony_ci#include "intel_pmic.h" 148c2ecf20Sopenharmony_ci 158c2ecf20Sopenharmony_ci#define PWR_SOURCE_SELECT BIT(1) 168c2ecf20Sopenharmony_ci 178c2ecf20Sopenharmony_ci#define PMIC_A0LOCK_REG 0xc5 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_cistatic struct pmic_table power_table[] = { 208c2ecf20Sopenharmony_ci/* { 218c2ecf20Sopenharmony_ci .address = 0x00, 228c2ecf20Sopenharmony_ci .reg = ??, 238c2ecf20Sopenharmony_ci .bit = ??, 248c2ecf20Sopenharmony_ci }, ** VSYS */ 258c2ecf20Sopenharmony_ci { 268c2ecf20Sopenharmony_ci .address = 0x04, 278c2ecf20Sopenharmony_ci .reg = 0x63, 288c2ecf20Sopenharmony_ci .bit = 0x00, 298c2ecf20Sopenharmony_ci }, /* SYSX -> VSYS_SX */ 308c2ecf20Sopenharmony_ci { 318c2ecf20Sopenharmony_ci .address = 0x08, 328c2ecf20Sopenharmony_ci .reg = 0x62, 338c2ecf20Sopenharmony_ci .bit = 0x00, 348c2ecf20Sopenharmony_ci }, /* SYSU -> VSYS_U */ 358c2ecf20Sopenharmony_ci { 368c2ecf20Sopenharmony_ci .address = 0x0c, 378c2ecf20Sopenharmony_ci .reg = 0x64, 388c2ecf20Sopenharmony_ci .bit = 0x00, 398c2ecf20Sopenharmony_ci }, /* SYSS -> VSYS_S */ 408c2ecf20Sopenharmony_ci { 418c2ecf20Sopenharmony_ci .address = 0x10, 428c2ecf20Sopenharmony_ci .reg = 0x6a, 438c2ecf20Sopenharmony_ci .bit = 0x00, 448c2ecf20Sopenharmony_ci }, /* V50S -> V5P0S */ 458c2ecf20Sopenharmony_ci { 468c2ecf20Sopenharmony_ci .address = 0x14, 478c2ecf20Sopenharmony_ci .reg = 0x6b, 488c2ecf20Sopenharmony_ci .bit = 0x00, 498c2ecf20Sopenharmony_ci }, /* HOST -> VHOST, USB2/3 host */ 508c2ecf20Sopenharmony_ci { 518c2ecf20Sopenharmony_ci .address = 0x18, 528c2ecf20Sopenharmony_ci .reg = 0x6c, 538c2ecf20Sopenharmony_ci .bit = 0x00, 548c2ecf20Sopenharmony_ci }, /* VBUS -> VBUS, USB2/3 OTG */ 558c2ecf20Sopenharmony_ci { 568c2ecf20Sopenharmony_ci .address = 0x1c, 578c2ecf20Sopenharmony_ci .reg = 0x6d, 588c2ecf20Sopenharmony_ci .bit = 0x00, 598c2ecf20Sopenharmony_ci }, /* HDMI -> VHDMI */ 608c2ecf20Sopenharmony_ci/* { 618c2ecf20Sopenharmony_ci .address = 0x20, 628c2ecf20Sopenharmony_ci .reg = ??, 638c2ecf20Sopenharmony_ci .bit = ??, 648c2ecf20Sopenharmony_ci }, ** S285 */ 658c2ecf20Sopenharmony_ci { 668c2ecf20Sopenharmony_ci .address = 0x24, 678c2ecf20Sopenharmony_ci .reg = 0x66, 688c2ecf20Sopenharmony_ci .bit = 0x00, 698c2ecf20Sopenharmony_ci }, /* X285 -> V2P85SX, camera */ 708c2ecf20Sopenharmony_ci/* { 718c2ecf20Sopenharmony_ci .address = 0x28, 728c2ecf20Sopenharmony_ci .reg = ??, 738c2ecf20Sopenharmony_ci .bit = ??, 748c2ecf20Sopenharmony_ci }, ** V33A */ 758c2ecf20Sopenharmony_ci { 768c2ecf20Sopenharmony_ci .address = 0x2c, 778c2ecf20Sopenharmony_ci .reg = 0x69, 788c2ecf20Sopenharmony_ci .bit = 0x00, 798c2ecf20Sopenharmony_ci }, /* V33S -> V3P3S, display/ssd/audio */ 808c2ecf20Sopenharmony_ci { 818c2ecf20Sopenharmony_ci .address = 0x30, 828c2ecf20Sopenharmony_ci .reg = 0x68, 838c2ecf20Sopenharmony_ci .bit = 0x00, 848c2ecf20Sopenharmony_ci }, /* V33U -> V3P3U, SDIO wifi&bt */ 858c2ecf20Sopenharmony_ci/* { 868c2ecf20Sopenharmony_ci .address = 0x34 .. 0x40, 878c2ecf20Sopenharmony_ci .reg = ??, 888c2ecf20Sopenharmony_ci .bit = ??, 898c2ecf20Sopenharmony_ci }, ** V33I, V18A, REFQ, V12A */ 908c2ecf20Sopenharmony_ci { 918c2ecf20Sopenharmony_ci .address = 0x44, 928c2ecf20Sopenharmony_ci .reg = 0x5c, 938c2ecf20Sopenharmony_ci .bit = 0x00, 948c2ecf20Sopenharmony_ci }, /* V18S -> V1P8S, SOC/USB PHY/SIM */ 958c2ecf20Sopenharmony_ci { 968c2ecf20Sopenharmony_ci .address = 0x48, 978c2ecf20Sopenharmony_ci .reg = 0x5d, 988c2ecf20Sopenharmony_ci .bit = 0x00, 998c2ecf20Sopenharmony_ci }, /* V18X -> V1P8SX, eMMC/camara/audio */ 1008c2ecf20Sopenharmony_ci { 1018c2ecf20Sopenharmony_ci .address = 0x4c, 1028c2ecf20Sopenharmony_ci .reg = 0x5b, 1038c2ecf20Sopenharmony_ci .bit = 0x00, 1048c2ecf20Sopenharmony_ci }, /* V18U -> V1P8U, LPDDR */ 1058c2ecf20Sopenharmony_ci { 1068c2ecf20Sopenharmony_ci .address = 0x50, 1078c2ecf20Sopenharmony_ci .reg = 0x61, 1088c2ecf20Sopenharmony_ci .bit = 0x00, 1098c2ecf20Sopenharmony_ci }, /* V12X -> V1P2SX, SOC SFR */ 1108c2ecf20Sopenharmony_ci { 1118c2ecf20Sopenharmony_ci .address = 0x54, 1128c2ecf20Sopenharmony_ci .reg = 0x60, 1138c2ecf20Sopenharmony_ci .bit = 0x00, 1148c2ecf20Sopenharmony_ci }, /* V12S -> V1P2S, MIPI */ 1158c2ecf20Sopenharmony_ci/* { 1168c2ecf20Sopenharmony_ci .address = 0x58, 1178c2ecf20Sopenharmony_ci .reg = ??, 1188c2ecf20Sopenharmony_ci .bit = ??, 1198c2ecf20Sopenharmony_ci }, ** V10A */ 1208c2ecf20Sopenharmony_ci { 1218c2ecf20Sopenharmony_ci .address = 0x5c, 1228c2ecf20Sopenharmony_ci .reg = 0x56, 1238c2ecf20Sopenharmony_ci .bit = 0x00, 1248c2ecf20Sopenharmony_ci }, /* V10S -> V1P0S, SOC GFX */ 1258c2ecf20Sopenharmony_ci { 1268c2ecf20Sopenharmony_ci .address = 0x60, 1278c2ecf20Sopenharmony_ci .reg = 0x57, 1288c2ecf20Sopenharmony_ci .bit = 0x00, 1298c2ecf20Sopenharmony_ci }, /* V10X -> V1P0SX, SOC display/DDR IO/PCIe */ 1308c2ecf20Sopenharmony_ci { 1318c2ecf20Sopenharmony_ci .address = 0x64, 1328c2ecf20Sopenharmony_ci .reg = 0x59, 1338c2ecf20Sopenharmony_ci .bit = 0x00, 1348c2ecf20Sopenharmony_ci }, /* V105 -> V1P05S, L2 SRAM */ 1358c2ecf20Sopenharmony_ci}; 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_cistatic struct pmic_table thermal_table[] = { 1388c2ecf20Sopenharmony_ci { 1398c2ecf20Sopenharmony_ci .address = 0x00, 1408c2ecf20Sopenharmony_ci .reg = 0x75 1418c2ecf20Sopenharmony_ci }, 1428c2ecf20Sopenharmony_ci { 1438c2ecf20Sopenharmony_ci .address = 0x04, 1448c2ecf20Sopenharmony_ci .reg = 0x95 1458c2ecf20Sopenharmony_ci }, 1468c2ecf20Sopenharmony_ci { 1478c2ecf20Sopenharmony_ci .address = 0x08, 1488c2ecf20Sopenharmony_ci .reg = 0x97 1498c2ecf20Sopenharmony_ci }, 1508c2ecf20Sopenharmony_ci { 1518c2ecf20Sopenharmony_ci .address = 0x0c, 1528c2ecf20Sopenharmony_ci .reg = 0x77 1538c2ecf20Sopenharmony_ci }, 1548c2ecf20Sopenharmony_ci { 1558c2ecf20Sopenharmony_ci .address = 0x10, 1568c2ecf20Sopenharmony_ci .reg = 0x9a 1578c2ecf20Sopenharmony_ci }, 1588c2ecf20Sopenharmony_ci { 1598c2ecf20Sopenharmony_ci .address = 0x14, 1608c2ecf20Sopenharmony_ci .reg = 0x9c 1618c2ecf20Sopenharmony_ci }, 1628c2ecf20Sopenharmony_ci { 1638c2ecf20Sopenharmony_ci .address = 0x18, 1648c2ecf20Sopenharmony_ci .reg = 0x79 1658c2ecf20Sopenharmony_ci }, 1668c2ecf20Sopenharmony_ci { 1678c2ecf20Sopenharmony_ci .address = 0x1c, 1688c2ecf20Sopenharmony_ci .reg = 0x9f 1698c2ecf20Sopenharmony_ci }, 1708c2ecf20Sopenharmony_ci { 1718c2ecf20Sopenharmony_ci .address = 0x20, 1728c2ecf20Sopenharmony_ci .reg = 0xa1 1738c2ecf20Sopenharmony_ci }, 1748c2ecf20Sopenharmony_ci { 1758c2ecf20Sopenharmony_ci .address = 0x48, 1768c2ecf20Sopenharmony_ci .reg = 0x94 1778c2ecf20Sopenharmony_ci }, 1788c2ecf20Sopenharmony_ci { 1798c2ecf20Sopenharmony_ci .address = 0x4c, 1808c2ecf20Sopenharmony_ci .reg = 0x99 1818c2ecf20Sopenharmony_ci }, 1828c2ecf20Sopenharmony_ci { 1838c2ecf20Sopenharmony_ci .address = 0x50, 1848c2ecf20Sopenharmony_ci .reg = 0x9e 1858c2ecf20Sopenharmony_ci }, 1868c2ecf20Sopenharmony_ci}; 1878c2ecf20Sopenharmony_ci 1888c2ecf20Sopenharmony_cistatic int intel_crc_pmic_get_power(struct regmap *regmap, int reg, 1898c2ecf20Sopenharmony_ci int bit, u64 *value) 1908c2ecf20Sopenharmony_ci{ 1918c2ecf20Sopenharmony_ci int data; 1928c2ecf20Sopenharmony_ci 1938c2ecf20Sopenharmony_ci if (regmap_read(regmap, reg, &data)) 1948c2ecf20Sopenharmony_ci return -EIO; 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_ci *value = (data & PWR_SOURCE_SELECT) && (data & BIT(bit)) ? 1 : 0; 1978c2ecf20Sopenharmony_ci return 0; 1988c2ecf20Sopenharmony_ci} 1998c2ecf20Sopenharmony_ci 2008c2ecf20Sopenharmony_cistatic int intel_crc_pmic_update_power(struct regmap *regmap, int reg, 2018c2ecf20Sopenharmony_ci int bit, bool on) 2028c2ecf20Sopenharmony_ci{ 2038c2ecf20Sopenharmony_ci int data; 2048c2ecf20Sopenharmony_ci 2058c2ecf20Sopenharmony_ci if (regmap_read(regmap, reg, &data)) 2068c2ecf20Sopenharmony_ci return -EIO; 2078c2ecf20Sopenharmony_ci 2088c2ecf20Sopenharmony_ci if (on) { 2098c2ecf20Sopenharmony_ci data |= PWR_SOURCE_SELECT | BIT(bit); 2108c2ecf20Sopenharmony_ci } else { 2118c2ecf20Sopenharmony_ci data &= ~BIT(bit); 2128c2ecf20Sopenharmony_ci data |= PWR_SOURCE_SELECT; 2138c2ecf20Sopenharmony_ci } 2148c2ecf20Sopenharmony_ci 2158c2ecf20Sopenharmony_ci if (regmap_write(regmap, reg, data)) 2168c2ecf20Sopenharmony_ci return -EIO; 2178c2ecf20Sopenharmony_ci return 0; 2188c2ecf20Sopenharmony_ci} 2198c2ecf20Sopenharmony_ci 2208c2ecf20Sopenharmony_cistatic int intel_crc_pmic_get_raw_temp(struct regmap *regmap, int reg) 2218c2ecf20Sopenharmony_ci{ 2228c2ecf20Sopenharmony_ci int temp_l, temp_h; 2238c2ecf20Sopenharmony_ci 2248c2ecf20Sopenharmony_ci /* 2258c2ecf20Sopenharmony_ci * Raw temperature value is 10bits: 8bits in reg 2268c2ecf20Sopenharmony_ci * and 2bits in reg-1: bit0,1 2278c2ecf20Sopenharmony_ci */ 2288c2ecf20Sopenharmony_ci if (regmap_read(regmap, reg, &temp_l) || 2298c2ecf20Sopenharmony_ci regmap_read(regmap, reg - 1, &temp_h)) 2308c2ecf20Sopenharmony_ci return -EIO; 2318c2ecf20Sopenharmony_ci 2328c2ecf20Sopenharmony_ci return temp_l | (temp_h & 0x3) << 8; 2338c2ecf20Sopenharmony_ci} 2348c2ecf20Sopenharmony_ci 2358c2ecf20Sopenharmony_cistatic int intel_crc_pmic_update_aux(struct regmap *regmap, int reg, int raw) 2368c2ecf20Sopenharmony_ci{ 2378c2ecf20Sopenharmony_ci return regmap_write(regmap, reg, raw) || 2388c2ecf20Sopenharmony_ci regmap_update_bits(regmap, reg - 1, 0x3, raw >> 8) ? -EIO : 0; 2398c2ecf20Sopenharmony_ci} 2408c2ecf20Sopenharmony_ci 2418c2ecf20Sopenharmony_cistatic int intel_crc_pmic_get_policy(struct regmap *regmap, 2428c2ecf20Sopenharmony_ci int reg, int bit, u64 *value) 2438c2ecf20Sopenharmony_ci{ 2448c2ecf20Sopenharmony_ci int pen; 2458c2ecf20Sopenharmony_ci 2468c2ecf20Sopenharmony_ci if (regmap_read(regmap, reg, &pen)) 2478c2ecf20Sopenharmony_ci return -EIO; 2488c2ecf20Sopenharmony_ci *value = pen >> 7; 2498c2ecf20Sopenharmony_ci return 0; 2508c2ecf20Sopenharmony_ci} 2518c2ecf20Sopenharmony_ci 2528c2ecf20Sopenharmony_cistatic int intel_crc_pmic_update_policy(struct regmap *regmap, 2538c2ecf20Sopenharmony_ci int reg, int bit, int enable) 2548c2ecf20Sopenharmony_ci{ 2558c2ecf20Sopenharmony_ci int alert0; 2568c2ecf20Sopenharmony_ci 2578c2ecf20Sopenharmony_ci /* Update to policy enable bit requires unlocking a0lock */ 2588c2ecf20Sopenharmony_ci if (regmap_read(regmap, PMIC_A0LOCK_REG, &alert0)) 2598c2ecf20Sopenharmony_ci return -EIO; 2608c2ecf20Sopenharmony_ci 2618c2ecf20Sopenharmony_ci if (regmap_update_bits(regmap, PMIC_A0LOCK_REG, 0x01, 0)) 2628c2ecf20Sopenharmony_ci return -EIO; 2638c2ecf20Sopenharmony_ci 2648c2ecf20Sopenharmony_ci if (regmap_update_bits(regmap, reg, 0x80, enable << 7)) 2658c2ecf20Sopenharmony_ci return -EIO; 2668c2ecf20Sopenharmony_ci 2678c2ecf20Sopenharmony_ci /* restore alert0 */ 2688c2ecf20Sopenharmony_ci if (regmap_write(regmap, PMIC_A0LOCK_REG, alert0)) 2698c2ecf20Sopenharmony_ci return -EIO; 2708c2ecf20Sopenharmony_ci 2718c2ecf20Sopenharmony_ci return 0; 2728c2ecf20Sopenharmony_ci} 2738c2ecf20Sopenharmony_ci 2748c2ecf20Sopenharmony_cistatic struct intel_pmic_opregion_data intel_crc_pmic_opregion_data = { 2758c2ecf20Sopenharmony_ci .get_power = intel_crc_pmic_get_power, 2768c2ecf20Sopenharmony_ci .update_power = intel_crc_pmic_update_power, 2778c2ecf20Sopenharmony_ci .get_raw_temp = intel_crc_pmic_get_raw_temp, 2788c2ecf20Sopenharmony_ci .update_aux = intel_crc_pmic_update_aux, 2798c2ecf20Sopenharmony_ci .get_policy = intel_crc_pmic_get_policy, 2808c2ecf20Sopenharmony_ci .update_policy = intel_crc_pmic_update_policy, 2818c2ecf20Sopenharmony_ci .power_table = power_table, 2828c2ecf20Sopenharmony_ci .power_table_count= ARRAY_SIZE(power_table), 2838c2ecf20Sopenharmony_ci .thermal_table = thermal_table, 2848c2ecf20Sopenharmony_ci .thermal_table_count = ARRAY_SIZE(thermal_table), 2858c2ecf20Sopenharmony_ci}; 2868c2ecf20Sopenharmony_ci 2878c2ecf20Sopenharmony_cistatic int intel_crc_pmic_opregion_probe(struct platform_device *pdev) 2888c2ecf20Sopenharmony_ci{ 2898c2ecf20Sopenharmony_ci struct intel_soc_pmic *pmic = dev_get_drvdata(pdev->dev.parent); 2908c2ecf20Sopenharmony_ci return intel_pmic_install_opregion_handler(&pdev->dev, 2918c2ecf20Sopenharmony_ci ACPI_HANDLE(pdev->dev.parent), pmic->regmap, 2928c2ecf20Sopenharmony_ci &intel_crc_pmic_opregion_data); 2938c2ecf20Sopenharmony_ci} 2948c2ecf20Sopenharmony_ci 2958c2ecf20Sopenharmony_cistatic struct platform_driver intel_crc_pmic_opregion_driver = { 2968c2ecf20Sopenharmony_ci .probe = intel_crc_pmic_opregion_probe, 2978c2ecf20Sopenharmony_ci .driver = { 2988c2ecf20Sopenharmony_ci .name = "byt_crystal_cove_pmic", 2998c2ecf20Sopenharmony_ci }, 3008c2ecf20Sopenharmony_ci}; 3018c2ecf20Sopenharmony_cibuiltin_platform_driver(intel_crc_pmic_opregion_driver); 302