289 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * Intel CHT Whiskey Cove PMIC operation region driver4 * Copyright (C) 2017 Hans de Goede <hdegoede@redhat.com>5 *6 * Based on various non upstream patches to support the CHT Whiskey Cove PMIC:7 * Copyright (C) 2013-2015 Intel Corporation. All rights reserved.8 */9 10#include <linux/acpi.h>11#include <linux/init.h>12#include <linux/mfd/intel_soc_pmic.h>13#include <linux/platform_device.h>14#include <linux/regmap.h>15#include "intel_pmic.h"16 17#define CHT_WC_V1P05A_CTRL 0x6e3b18#define CHT_WC_V1P15_CTRL 0x6e3c19#define CHT_WC_V1P05A_VSEL 0x6e3d20#define CHT_WC_V1P15_VSEL 0x6e3e21#define CHT_WC_V1P8A_CTRL 0x6e5622#define CHT_WC_V1P8SX_CTRL 0x6e5723#define CHT_WC_VDDQ_CTRL 0x6e5824#define CHT_WC_V1P2A_CTRL 0x6e5925#define CHT_WC_V1P2SX_CTRL 0x6e5a26#define CHT_WC_V1P8A_VSEL 0x6e5b27#define CHT_WC_VDDQ_VSEL 0x6e5c28#define CHT_WC_V2P8SX_CTRL 0x6e5d29#define CHT_WC_V3P3A_CTRL 0x6e5e30#define CHT_WC_V3P3SD_CTRL 0x6e5f31#define CHT_WC_VSDIO_CTRL 0x6e6732#define CHT_WC_V3P3A_VSEL 0x6e6833#define CHT_WC_VPROG1A_CTRL 0x6e9034#define CHT_WC_VPROG1B_CTRL 0x6e9135#define CHT_WC_VPROG1F_CTRL 0x6e9536#define CHT_WC_VPROG2D_CTRL 0x6e9937#define CHT_WC_VPROG3A_CTRL 0x6e9a38#define CHT_WC_VPROG3B_CTRL 0x6e9b39#define CHT_WC_VPROG4A_CTRL 0x6e9c40#define CHT_WC_VPROG4B_CTRL 0x6e9d41#define CHT_WC_VPROG4C_CTRL 0x6e9e42#define CHT_WC_VPROG4D_CTRL 0x6e9f43#define CHT_WC_VPROG5A_CTRL 0x6ea044#define CHT_WC_VPROG5B_CTRL 0x6ea145#define CHT_WC_VPROG6A_CTRL 0x6ea246#define CHT_WC_VPROG6B_CTRL 0x6ea347#define CHT_WC_VPROG1A_VSEL 0x6ec048#define CHT_WC_VPROG1B_VSEL 0x6ec149#define CHT_WC_V1P8SX_VSEL 0x6ec250#define CHT_WC_V1P2SX_VSEL 0x6ec351#define CHT_WC_V1P2A_VSEL 0x6ec452#define CHT_WC_VPROG1F_VSEL 0x6ec553#define CHT_WC_VSDIO_VSEL 0x6ec654#define CHT_WC_V2P8SX_VSEL 0x6ec755#define CHT_WC_V3P3SD_VSEL 0x6ec856#define CHT_WC_VPROG2D_VSEL 0x6ec957#define CHT_WC_VPROG3A_VSEL 0x6eca58#define CHT_WC_VPROG3B_VSEL 0x6ecb59#define CHT_WC_VPROG4A_VSEL 0x6ecc60#define CHT_WC_VPROG4B_VSEL 0x6ecd61#define CHT_WC_VPROG4C_VSEL 0x6ece62#define CHT_WC_VPROG4D_VSEL 0x6ecf63#define CHT_WC_VPROG5A_VSEL 0x6ed064#define CHT_WC_VPROG5B_VSEL 0x6ed165#define CHT_WC_VPROG6A_VSEL 0x6ed266#define CHT_WC_VPROG6B_VSEL 0x6ed367 68/*69 * Regulator support is based on the non upstream patch:70 * "regulator: whiskey_cove: implements Whiskey Cove pmic VRF support"71 * https://github.com/intel-aero/meta-intel-aero/blob/master/recipes-kernel/linux/linux-yocto/0019-regulator-whiskey_cove-implements-WhiskeyCove-pmic-V.patch72 */73static const struct pmic_table power_table[] = {74 {75 .address = 0x0,76 .reg = CHT_WC_V1P8A_CTRL,77 .bit = 0x01,78 }, /* V18A */79 {80 .address = 0x04,81 .reg = CHT_WC_V1P8SX_CTRL,82 .bit = 0x07,83 }, /* V18X */84 {85 .address = 0x08,86 .reg = CHT_WC_VDDQ_CTRL,87 .bit = 0x01,88 }, /* VDDQ */89 {90 .address = 0x0c,91 .reg = CHT_WC_V1P2A_CTRL,92 .bit = 0x07,93 }, /* V12A */94 {95 .address = 0x10,96 .reg = CHT_WC_V1P2SX_CTRL,97 .bit = 0x07,98 }, /* V12X */99 {100 .address = 0x14,101 .reg = CHT_WC_V2P8SX_CTRL,102 .bit = 0x07,103 }, /* V28X */104 {105 .address = 0x18,106 .reg = CHT_WC_V3P3A_CTRL,107 .bit = 0x01,108 }, /* V33A */109 {110 .address = 0x1c,111 .reg = CHT_WC_V3P3SD_CTRL,112 .bit = 0x07,113 }, /* V3SD */114 {115 .address = 0x20,116 .reg = CHT_WC_VSDIO_CTRL,117 .bit = 0x07,118 }, /* VSD */119/* {120 .address = 0x24,121 .reg = ??,122 .bit = ??,123 }, ** VSW2 */124/* {125 .address = 0x28,126 .reg = ??,127 .bit = ??,128 }, ** VSW1 */129/* {130 .address = 0x2c,131 .reg = ??,132 .bit = ??,133 }, ** VUPY */134/* {135 .address = 0x30,136 .reg = ??,137 .bit = ??,138 }, ** VRSO */139 {140 .address = 0x34,141 .reg = CHT_WC_VPROG1A_CTRL,142 .bit = 0x07,143 }, /* VP1A */144 {145 .address = 0x38,146 .reg = CHT_WC_VPROG1B_CTRL,147 .bit = 0x07,148 }, /* VP1B */149 {150 .address = 0x3c,151 .reg = CHT_WC_VPROG1F_CTRL,152 .bit = 0x07,153 }, /* VP1F */154 {155 .address = 0x40,156 .reg = CHT_WC_VPROG2D_CTRL,157 .bit = 0x07,158 }, /* VP2D */159 {160 .address = 0x44,161 .reg = CHT_WC_VPROG3A_CTRL,162 .bit = 0x07,163 }, /* VP3A */164 {165 .address = 0x48,166 .reg = CHT_WC_VPROG3B_CTRL,167 .bit = 0x07,168 }, /* VP3B */169 {170 .address = 0x4c,171 .reg = CHT_WC_VPROG4A_CTRL,172 .bit = 0x07,173 }, /* VP4A */174 {175 .address = 0x50,176 .reg = CHT_WC_VPROG4B_CTRL,177 .bit = 0x07,178 }, /* VP4B */179 {180 .address = 0x54,181 .reg = CHT_WC_VPROG4C_CTRL,182 .bit = 0x07,183 }, /* VP4C */184 {185 .address = 0x58,186 .reg = CHT_WC_VPROG4D_CTRL,187 .bit = 0x07,188 }, /* VP4D */189 {190 .address = 0x5c,191 .reg = CHT_WC_VPROG5A_CTRL,192 .bit = 0x07,193 }, /* VP5A */194 {195 .address = 0x60,196 .reg = CHT_WC_VPROG5B_CTRL,197 .bit = 0x07,198 }, /* VP5B */199 {200 .address = 0x64,201 .reg = CHT_WC_VPROG6A_CTRL,202 .bit = 0x07,203 }, /* VP6A */204 {205 .address = 0x68,206 .reg = CHT_WC_VPROG6B_CTRL,207 .bit = 0x07,208 }, /* VP6B */209/* {210 .address = 0x6c,211 .reg = ??,212 .bit = ??,213 } ** VP7A */214};215 216static int intel_cht_wc_pmic_get_power(struct regmap *regmap, int reg,217 int bit, u64 *value)218{219 int data;220 221 if (regmap_read(regmap, reg, &data))222 return -EIO;223 224 *value = (data & bit) ? 1 : 0;225 return 0;226}227 228static int intel_cht_wc_pmic_update_power(struct regmap *regmap, int reg,229 int bitmask, bool on)230{231 return regmap_update_bits(regmap, reg, bitmask, on ? 1 : 0);232}233 234static int intel_cht_wc_exec_mipi_pmic_seq_element(struct regmap *regmap,235 u16 i2c_client_address,236 u32 reg_address,237 u32 value, u32 mask)238{239 struct device *dev = regmap_get_device(regmap);240 u32 address;241 242 if (i2c_client_address > 0xff || reg_address > 0xff) {243 dev_warn(dev, "warning addresses too big client 0x%x reg 0x%x\n",244 i2c_client_address, reg_address);245 return -ERANGE;246 }247 248 address = (i2c_client_address << 8) | reg_address;249 250 return regmap_update_bits(regmap, address, mask, value);251}252 253/*254 * The thermal table and ops are empty, we do not support the Thermal opregion255 * (DPTF) due to lacking documentation.256 */257static const struct intel_pmic_opregion_data intel_cht_wc_pmic_opregion_data = {258 .get_power = intel_cht_wc_pmic_get_power,259 .update_power = intel_cht_wc_pmic_update_power,260 .exec_mipi_pmic_seq_element = intel_cht_wc_exec_mipi_pmic_seq_element,261 .lpat_raw_to_temp = acpi_lpat_raw_to_temp,262 .power_table = power_table,263 .power_table_count = ARRAY_SIZE(power_table),264};265 266static int intel_cht_wc_pmic_opregion_probe(struct platform_device *pdev)267{268 struct intel_soc_pmic *pmic = dev_get_drvdata(pdev->dev.parent);269 270 return intel_pmic_install_opregion_handler(&pdev->dev,271 ACPI_HANDLE(pdev->dev.parent),272 pmic->regmap,273 &intel_cht_wc_pmic_opregion_data);274}275 276static const struct platform_device_id cht_wc_opregion_id_table[] = {277 { .name = "cht_wcove_region" },278 {},279};280 281static struct platform_driver intel_cht_wc_pmic_opregion_driver = {282 .probe = intel_cht_wc_pmic_opregion_probe,283 .driver = {284 .name = "cht_whiskey_cove_pmic",285 },286 .id_table = cht_wc_opregion_id_table,287};288builtin_platform_driver(intel_cht_wc_pmic_opregion_driver);289