162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Intel Bay Trail Crystal Cove PMIC operation region driver 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 2014 Intel Corporation. All rights reserved. 662306a36Sopenharmony_ci */ 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci#include <linux/acpi.h> 962306a36Sopenharmony_ci#include <linux/init.h> 1062306a36Sopenharmony_ci#include <linux/mfd/intel_soc_pmic.h> 1162306a36Sopenharmony_ci#include <linux/platform_device.h> 1262306a36Sopenharmony_ci#include <linux/regmap.h> 1362306a36Sopenharmony_ci#include "intel_pmic.h" 1462306a36Sopenharmony_ci 1562306a36Sopenharmony_ci#define PWR_SOURCE_SELECT BIT(1) 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_ci#define PMIC_A0LOCK_REG 0xc5 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_cistatic struct pmic_table power_table[] = { 2062306a36Sopenharmony_ci/* { 2162306a36Sopenharmony_ci .address = 0x00, 2262306a36Sopenharmony_ci .reg = ??, 2362306a36Sopenharmony_ci .bit = ??, 2462306a36Sopenharmony_ci }, ** VSYS */ 2562306a36Sopenharmony_ci { 2662306a36Sopenharmony_ci .address = 0x04, 2762306a36Sopenharmony_ci .reg = 0x63, 2862306a36Sopenharmony_ci .bit = 0x00, 2962306a36Sopenharmony_ci }, /* SYSX -> VSYS_SX */ 3062306a36Sopenharmony_ci { 3162306a36Sopenharmony_ci .address = 0x08, 3262306a36Sopenharmony_ci .reg = 0x62, 3362306a36Sopenharmony_ci .bit = 0x00, 3462306a36Sopenharmony_ci }, /* SYSU -> VSYS_U */ 3562306a36Sopenharmony_ci { 3662306a36Sopenharmony_ci .address = 0x0c, 3762306a36Sopenharmony_ci .reg = 0x64, 3862306a36Sopenharmony_ci .bit = 0x00, 3962306a36Sopenharmony_ci }, /* SYSS -> VSYS_S */ 4062306a36Sopenharmony_ci { 4162306a36Sopenharmony_ci .address = 0x10, 4262306a36Sopenharmony_ci .reg = 0x6a, 4362306a36Sopenharmony_ci .bit = 0x00, 4462306a36Sopenharmony_ci }, /* V50S -> V5P0S */ 4562306a36Sopenharmony_ci { 4662306a36Sopenharmony_ci .address = 0x14, 4762306a36Sopenharmony_ci .reg = 0x6b, 4862306a36Sopenharmony_ci .bit = 0x00, 4962306a36Sopenharmony_ci }, /* HOST -> VHOST, USB2/3 host */ 5062306a36Sopenharmony_ci { 5162306a36Sopenharmony_ci .address = 0x18, 5262306a36Sopenharmony_ci .reg = 0x6c, 5362306a36Sopenharmony_ci .bit = 0x00, 5462306a36Sopenharmony_ci }, /* VBUS -> VBUS, USB2/3 OTG */ 5562306a36Sopenharmony_ci { 5662306a36Sopenharmony_ci .address = 0x1c, 5762306a36Sopenharmony_ci .reg = 0x6d, 5862306a36Sopenharmony_ci .bit = 0x00, 5962306a36Sopenharmony_ci }, /* HDMI -> VHDMI */ 6062306a36Sopenharmony_ci/* { 6162306a36Sopenharmony_ci .address = 0x20, 6262306a36Sopenharmony_ci .reg = ??, 6362306a36Sopenharmony_ci .bit = ??, 6462306a36Sopenharmony_ci }, ** S285 */ 6562306a36Sopenharmony_ci { 6662306a36Sopenharmony_ci .address = 0x24, 6762306a36Sopenharmony_ci .reg = 0x66, 6862306a36Sopenharmony_ci .bit = 0x00, 6962306a36Sopenharmony_ci }, /* X285 -> V2P85SX, camera */ 7062306a36Sopenharmony_ci/* { 7162306a36Sopenharmony_ci .address = 0x28, 7262306a36Sopenharmony_ci .reg = ??, 7362306a36Sopenharmony_ci .bit = ??, 7462306a36Sopenharmony_ci }, ** V33A */ 7562306a36Sopenharmony_ci { 7662306a36Sopenharmony_ci .address = 0x2c, 7762306a36Sopenharmony_ci .reg = 0x69, 7862306a36Sopenharmony_ci .bit = 0x00, 7962306a36Sopenharmony_ci }, /* V33S -> V3P3S, display/ssd/audio */ 8062306a36Sopenharmony_ci { 8162306a36Sopenharmony_ci .address = 0x30, 8262306a36Sopenharmony_ci .reg = 0x68, 8362306a36Sopenharmony_ci .bit = 0x00, 8462306a36Sopenharmony_ci }, /* V33U -> V3P3U, SDIO wifi&bt */ 8562306a36Sopenharmony_ci/* { 8662306a36Sopenharmony_ci .address = 0x34 .. 0x40, 8762306a36Sopenharmony_ci .reg = ??, 8862306a36Sopenharmony_ci .bit = ??, 8962306a36Sopenharmony_ci }, ** V33I, V18A, REFQ, V12A */ 9062306a36Sopenharmony_ci { 9162306a36Sopenharmony_ci .address = 0x44, 9262306a36Sopenharmony_ci .reg = 0x5c, 9362306a36Sopenharmony_ci .bit = 0x00, 9462306a36Sopenharmony_ci }, /* V18S -> V1P8S, SOC/USB PHY/SIM */ 9562306a36Sopenharmony_ci { 9662306a36Sopenharmony_ci .address = 0x48, 9762306a36Sopenharmony_ci .reg = 0x5d, 9862306a36Sopenharmony_ci .bit = 0x00, 9962306a36Sopenharmony_ci }, /* V18X -> V1P8SX, eMMC/camara/audio */ 10062306a36Sopenharmony_ci { 10162306a36Sopenharmony_ci .address = 0x4c, 10262306a36Sopenharmony_ci .reg = 0x5b, 10362306a36Sopenharmony_ci .bit = 0x00, 10462306a36Sopenharmony_ci }, /* V18U -> V1P8U, LPDDR */ 10562306a36Sopenharmony_ci { 10662306a36Sopenharmony_ci .address = 0x50, 10762306a36Sopenharmony_ci .reg = 0x61, 10862306a36Sopenharmony_ci .bit = 0x00, 10962306a36Sopenharmony_ci }, /* V12X -> V1P2SX, SOC SFR */ 11062306a36Sopenharmony_ci { 11162306a36Sopenharmony_ci .address = 0x54, 11262306a36Sopenharmony_ci .reg = 0x60, 11362306a36Sopenharmony_ci .bit = 0x00, 11462306a36Sopenharmony_ci }, /* V12S -> V1P2S, MIPI */ 11562306a36Sopenharmony_ci/* { 11662306a36Sopenharmony_ci .address = 0x58, 11762306a36Sopenharmony_ci .reg = ??, 11862306a36Sopenharmony_ci .bit = ??, 11962306a36Sopenharmony_ci }, ** V10A */ 12062306a36Sopenharmony_ci { 12162306a36Sopenharmony_ci .address = 0x5c, 12262306a36Sopenharmony_ci .reg = 0x56, 12362306a36Sopenharmony_ci .bit = 0x00, 12462306a36Sopenharmony_ci }, /* V10S -> V1P0S, SOC GFX */ 12562306a36Sopenharmony_ci { 12662306a36Sopenharmony_ci .address = 0x60, 12762306a36Sopenharmony_ci .reg = 0x57, 12862306a36Sopenharmony_ci .bit = 0x00, 12962306a36Sopenharmony_ci }, /* V10X -> V1P0SX, SOC display/DDR IO/PCIe */ 13062306a36Sopenharmony_ci { 13162306a36Sopenharmony_ci .address = 0x64, 13262306a36Sopenharmony_ci .reg = 0x59, 13362306a36Sopenharmony_ci .bit = 0x00, 13462306a36Sopenharmony_ci }, /* V105 -> V1P05S, L2 SRAM */ 13562306a36Sopenharmony_ci}; 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_cistatic struct pmic_table thermal_table[] = { 13862306a36Sopenharmony_ci { 13962306a36Sopenharmony_ci .address = 0x00, 14062306a36Sopenharmony_ci .reg = 0x75 14162306a36Sopenharmony_ci }, 14262306a36Sopenharmony_ci { 14362306a36Sopenharmony_ci .address = 0x04, 14462306a36Sopenharmony_ci .reg = 0x95 14562306a36Sopenharmony_ci }, 14662306a36Sopenharmony_ci { 14762306a36Sopenharmony_ci .address = 0x08, 14862306a36Sopenharmony_ci .reg = 0x97 14962306a36Sopenharmony_ci }, 15062306a36Sopenharmony_ci { 15162306a36Sopenharmony_ci .address = 0x0c, 15262306a36Sopenharmony_ci .reg = 0x77 15362306a36Sopenharmony_ci }, 15462306a36Sopenharmony_ci { 15562306a36Sopenharmony_ci .address = 0x10, 15662306a36Sopenharmony_ci .reg = 0x9a 15762306a36Sopenharmony_ci }, 15862306a36Sopenharmony_ci { 15962306a36Sopenharmony_ci .address = 0x14, 16062306a36Sopenharmony_ci .reg = 0x9c 16162306a36Sopenharmony_ci }, 16262306a36Sopenharmony_ci { 16362306a36Sopenharmony_ci .address = 0x18, 16462306a36Sopenharmony_ci .reg = 0x79 16562306a36Sopenharmony_ci }, 16662306a36Sopenharmony_ci { 16762306a36Sopenharmony_ci .address = 0x1c, 16862306a36Sopenharmony_ci .reg = 0x9f 16962306a36Sopenharmony_ci }, 17062306a36Sopenharmony_ci { 17162306a36Sopenharmony_ci .address = 0x20, 17262306a36Sopenharmony_ci .reg = 0xa1 17362306a36Sopenharmony_ci }, 17462306a36Sopenharmony_ci { 17562306a36Sopenharmony_ci .address = 0x48, 17662306a36Sopenharmony_ci .reg = 0x94 17762306a36Sopenharmony_ci }, 17862306a36Sopenharmony_ci { 17962306a36Sopenharmony_ci .address = 0x4c, 18062306a36Sopenharmony_ci .reg = 0x99 18162306a36Sopenharmony_ci }, 18262306a36Sopenharmony_ci { 18362306a36Sopenharmony_ci .address = 0x50, 18462306a36Sopenharmony_ci .reg = 0x9e 18562306a36Sopenharmony_ci }, 18662306a36Sopenharmony_ci}; 18762306a36Sopenharmony_ci 18862306a36Sopenharmony_cistatic int intel_crc_pmic_get_power(struct regmap *regmap, int reg, 18962306a36Sopenharmony_ci int bit, u64 *value) 19062306a36Sopenharmony_ci{ 19162306a36Sopenharmony_ci int data; 19262306a36Sopenharmony_ci 19362306a36Sopenharmony_ci if (regmap_read(regmap, reg, &data)) 19462306a36Sopenharmony_ci return -EIO; 19562306a36Sopenharmony_ci 19662306a36Sopenharmony_ci *value = (data & PWR_SOURCE_SELECT) && (data & BIT(bit)) ? 1 : 0; 19762306a36Sopenharmony_ci return 0; 19862306a36Sopenharmony_ci} 19962306a36Sopenharmony_ci 20062306a36Sopenharmony_cistatic int intel_crc_pmic_update_power(struct regmap *regmap, int reg, 20162306a36Sopenharmony_ci int bit, bool on) 20262306a36Sopenharmony_ci{ 20362306a36Sopenharmony_ci int data; 20462306a36Sopenharmony_ci 20562306a36Sopenharmony_ci if (regmap_read(regmap, reg, &data)) 20662306a36Sopenharmony_ci return -EIO; 20762306a36Sopenharmony_ci 20862306a36Sopenharmony_ci if (on) { 20962306a36Sopenharmony_ci data |= PWR_SOURCE_SELECT | BIT(bit); 21062306a36Sopenharmony_ci } else { 21162306a36Sopenharmony_ci data &= ~BIT(bit); 21262306a36Sopenharmony_ci data |= PWR_SOURCE_SELECT; 21362306a36Sopenharmony_ci } 21462306a36Sopenharmony_ci 21562306a36Sopenharmony_ci if (regmap_write(regmap, reg, data)) 21662306a36Sopenharmony_ci return -EIO; 21762306a36Sopenharmony_ci return 0; 21862306a36Sopenharmony_ci} 21962306a36Sopenharmony_ci 22062306a36Sopenharmony_cistatic int intel_crc_pmic_get_raw_temp(struct regmap *regmap, int reg) 22162306a36Sopenharmony_ci{ 22262306a36Sopenharmony_ci int temp_l, temp_h; 22362306a36Sopenharmony_ci 22462306a36Sopenharmony_ci /* 22562306a36Sopenharmony_ci * Raw temperature value is 10bits: 8bits in reg 22662306a36Sopenharmony_ci * and 2bits in reg-1: bit0,1 22762306a36Sopenharmony_ci */ 22862306a36Sopenharmony_ci if (regmap_read(regmap, reg, &temp_l) || 22962306a36Sopenharmony_ci regmap_read(regmap, reg - 1, &temp_h)) 23062306a36Sopenharmony_ci return -EIO; 23162306a36Sopenharmony_ci 23262306a36Sopenharmony_ci return temp_l | (temp_h & 0x3) << 8; 23362306a36Sopenharmony_ci} 23462306a36Sopenharmony_ci 23562306a36Sopenharmony_cistatic int intel_crc_pmic_update_aux(struct regmap *regmap, int reg, int raw) 23662306a36Sopenharmony_ci{ 23762306a36Sopenharmony_ci return regmap_write(regmap, reg, raw) || 23862306a36Sopenharmony_ci regmap_update_bits(regmap, reg - 1, 0x3, raw >> 8) ? -EIO : 0; 23962306a36Sopenharmony_ci} 24062306a36Sopenharmony_ci 24162306a36Sopenharmony_cistatic int intel_crc_pmic_get_policy(struct regmap *regmap, 24262306a36Sopenharmony_ci int reg, int bit, u64 *value) 24362306a36Sopenharmony_ci{ 24462306a36Sopenharmony_ci int pen; 24562306a36Sopenharmony_ci 24662306a36Sopenharmony_ci if (regmap_read(regmap, reg, &pen)) 24762306a36Sopenharmony_ci return -EIO; 24862306a36Sopenharmony_ci *value = pen >> 7; 24962306a36Sopenharmony_ci return 0; 25062306a36Sopenharmony_ci} 25162306a36Sopenharmony_ci 25262306a36Sopenharmony_cistatic int intel_crc_pmic_update_policy(struct regmap *regmap, 25362306a36Sopenharmony_ci int reg, int bit, int enable) 25462306a36Sopenharmony_ci{ 25562306a36Sopenharmony_ci int alert0; 25662306a36Sopenharmony_ci 25762306a36Sopenharmony_ci /* Update to policy enable bit requires unlocking a0lock */ 25862306a36Sopenharmony_ci if (regmap_read(regmap, PMIC_A0LOCK_REG, &alert0)) 25962306a36Sopenharmony_ci return -EIO; 26062306a36Sopenharmony_ci 26162306a36Sopenharmony_ci if (regmap_update_bits(regmap, PMIC_A0LOCK_REG, 0x01, 0)) 26262306a36Sopenharmony_ci return -EIO; 26362306a36Sopenharmony_ci 26462306a36Sopenharmony_ci if (regmap_update_bits(regmap, reg, 0x80, enable << 7)) 26562306a36Sopenharmony_ci return -EIO; 26662306a36Sopenharmony_ci 26762306a36Sopenharmony_ci /* restore alert0 */ 26862306a36Sopenharmony_ci if (regmap_write(regmap, PMIC_A0LOCK_REG, alert0)) 26962306a36Sopenharmony_ci return -EIO; 27062306a36Sopenharmony_ci 27162306a36Sopenharmony_ci return 0; 27262306a36Sopenharmony_ci} 27362306a36Sopenharmony_ci 27462306a36Sopenharmony_cistatic const struct intel_pmic_opregion_data intel_crc_pmic_opregion_data = { 27562306a36Sopenharmony_ci .get_power = intel_crc_pmic_get_power, 27662306a36Sopenharmony_ci .update_power = intel_crc_pmic_update_power, 27762306a36Sopenharmony_ci .get_raw_temp = intel_crc_pmic_get_raw_temp, 27862306a36Sopenharmony_ci .update_aux = intel_crc_pmic_update_aux, 27962306a36Sopenharmony_ci .get_policy = intel_crc_pmic_get_policy, 28062306a36Sopenharmony_ci .update_policy = intel_crc_pmic_update_policy, 28162306a36Sopenharmony_ci .lpat_raw_to_temp = acpi_lpat_raw_to_temp, 28262306a36Sopenharmony_ci .power_table = power_table, 28362306a36Sopenharmony_ci .power_table_count= ARRAY_SIZE(power_table), 28462306a36Sopenharmony_ci .thermal_table = thermal_table, 28562306a36Sopenharmony_ci .thermal_table_count = ARRAY_SIZE(thermal_table), 28662306a36Sopenharmony_ci .pmic_i2c_address = 0x6e, 28762306a36Sopenharmony_ci}; 28862306a36Sopenharmony_ci 28962306a36Sopenharmony_cistatic int intel_crc_pmic_opregion_probe(struct platform_device *pdev) 29062306a36Sopenharmony_ci{ 29162306a36Sopenharmony_ci struct intel_soc_pmic *pmic = dev_get_drvdata(pdev->dev.parent); 29262306a36Sopenharmony_ci return intel_pmic_install_opregion_handler(&pdev->dev, 29362306a36Sopenharmony_ci ACPI_HANDLE(pdev->dev.parent), pmic->regmap, 29462306a36Sopenharmony_ci &intel_crc_pmic_opregion_data); 29562306a36Sopenharmony_ci} 29662306a36Sopenharmony_ci 29762306a36Sopenharmony_cistatic struct platform_driver intel_crc_pmic_opregion_driver = { 29862306a36Sopenharmony_ci .probe = intel_crc_pmic_opregion_probe, 29962306a36Sopenharmony_ci .driver = { 30062306a36Sopenharmony_ci .name = "byt_crystal_cove_pmic", 30162306a36Sopenharmony_ci }, 30262306a36Sopenharmony_ci}; 30362306a36Sopenharmony_cibuiltin_platform_driver(intel_crc_pmic_opregion_driver); 304