304 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * Intel Bay Trail Crystal Cove PMIC operation region driver4 *5 * Copyright (C) 2014 Intel Corporation. All rights reserved.6 */7 8#include <linux/acpi.h>9#include <linux/init.h>10#include <linux/mfd/intel_soc_pmic.h>11#include <linux/platform_device.h>12#include <linux/regmap.h>13#include "intel_pmic.h"14 15#define PWR_SOURCE_SELECT BIT(1)16 17#define PMIC_A0LOCK_REG 0xc518 19static const struct pmic_table power_table[] = {20/* {21 .address = 0x00,22 .reg = ??,23 .bit = ??,24 }, ** VSYS */25 {26 .address = 0x04,27 .reg = 0x63,28 .bit = 0x00,29 }, /* SYSX -> VSYS_SX */30 {31 .address = 0x08,32 .reg = 0x62,33 .bit = 0x00,34 }, /* SYSU -> VSYS_U */35 {36 .address = 0x0c,37 .reg = 0x64,38 .bit = 0x00,39 }, /* SYSS -> VSYS_S */40 {41 .address = 0x10,42 .reg = 0x6a,43 .bit = 0x00,44 }, /* V50S -> V5P0S */45 {46 .address = 0x14,47 .reg = 0x6b,48 .bit = 0x00,49 }, /* HOST -> VHOST, USB2/3 host */50 {51 .address = 0x18,52 .reg = 0x6c,53 .bit = 0x00,54 }, /* VBUS -> VBUS, USB2/3 OTG */55 {56 .address = 0x1c,57 .reg = 0x6d,58 .bit = 0x00,59 }, /* HDMI -> VHDMI */60/* {61 .address = 0x20,62 .reg = ??,63 .bit = ??,64 }, ** S285 */65 {66 .address = 0x24,67 .reg = 0x66,68 .bit = 0x00,69 }, /* X285 -> V2P85SX, camera */70/* {71 .address = 0x28,72 .reg = ??,73 .bit = ??,74 }, ** V33A */75 {76 .address = 0x2c,77 .reg = 0x69,78 .bit = 0x00,79 }, /* V33S -> V3P3S, display/ssd/audio */80 {81 .address = 0x30,82 .reg = 0x68,83 .bit = 0x00,84 }, /* V33U -> V3P3U, SDIO wifi&bt */85/* {86 .address = 0x34 .. 0x40,87 .reg = ??,88 .bit = ??,89 }, ** V33I, V18A, REFQ, V12A */90 {91 .address = 0x44,92 .reg = 0x5c,93 .bit = 0x00,94 }, /* V18S -> V1P8S, SOC/USB PHY/SIM */95 {96 .address = 0x48,97 .reg = 0x5d,98 .bit = 0x00,99 }, /* V18X -> V1P8SX, eMMC/camara/audio */100 {101 .address = 0x4c,102 .reg = 0x5b,103 .bit = 0x00,104 }, /* V18U -> V1P8U, LPDDR */105 {106 .address = 0x50,107 .reg = 0x61,108 .bit = 0x00,109 }, /* V12X -> V1P2SX, SOC SFR */110 {111 .address = 0x54,112 .reg = 0x60,113 .bit = 0x00,114 }, /* V12S -> V1P2S, MIPI */115/* {116 .address = 0x58,117 .reg = ??,118 .bit = ??,119 }, ** V10A */120 {121 .address = 0x5c,122 .reg = 0x56,123 .bit = 0x00,124 }, /* V10S -> V1P0S, SOC GFX */125 {126 .address = 0x60,127 .reg = 0x57,128 .bit = 0x00,129 }, /* V10X -> V1P0SX, SOC display/DDR IO/PCIe */130 {131 .address = 0x64,132 .reg = 0x59,133 .bit = 0x00,134 }, /* V105 -> V1P05S, L2 SRAM */135};136 137static const struct pmic_table thermal_table[] = {138 {139 .address = 0x00,140 .reg = 0x75141 },142 {143 .address = 0x04,144 .reg = 0x95145 },146 {147 .address = 0x08,148 .reg = 0x97149 },150 {151 .address = 0x0c,152 .reg = 0x77153 },154 {155 .address = 0x10,156 .reg = 0x9a157 },158 {159 .address = 0x14,160 .reg = 0x9c161 },162 {163 .address = 0x18,164 .reg = 0x79165 },166 {167 .address = 0x1c,168 .reg = 0x9f169 },170 {171 .address = 0x20,172 .reg = 0xa1173 },174 {175 .address = 0x48,176 .reg = 0x94177 },178 {179 .address = 0x4c,180 .reg = 0x99181 },182 {183 .address = 0x50,184 .reg = 0x9e185 },186};187 188static int intel_crc_pmic_get_power(struct regmap *regmap, int reg,189 int bit, u64 *value)190{191 int data;192 193 if (regmap_read(regmap, reg, &data))194 return -EIO;195 196 *value = (data & PWR_SOURCE_SELECT) && (data & BIT(bit)) ? 1 : 0;197 return 0;198}199 200static int intel_crc_pmic_update_power(struct regmap *regmap, int reg,201 int bit, bool on)202{203 int data;204 205 if (regmap_read(regmap, reg, &data))206 return -EIO;207 208 if (on) {209 data |= PWR_SOURCE_SELECT | BIT(bit);210 } else {211 data &= ~BIT(bit);212 data |= PWR_SOURCE_SELECT;213 }214 215 if (regmap_write(regmap, reg, data))216 return -EIO;217 return 0;218}219 220static int intel_crc_pmic_get_raw_temp(struct regmap *regmap, int reg)221{222 int temp_l, temp_h;223 224 /*225 * Raw temperature value is 10bits: 8bits in reg226 * and 2bits in reg-1: bit0,1227 */228 if (regmap_read(regmap, reg, &temp_l) ||229 regmap_read(regmap, reg - 1, &temp_h))230 return -EIO;231 232 return temp_l | (temp_h & 0x3) << 8;233}234 235static int intel_crc_pmic_update_aux(struct regmap *regmap, int reg, int raw)236{237 return regmap_write(regmap, reg, raw) ||238 regmap_update_bits(regmap, reg - 1, 0x3, raw >> 8) ? -EIO : 0;239}240 241static int intel_crc_pmic_get_policy(struct regmap *regmap,242 int reg, int bit, u64 *value)243{244 int pen;245 246 if (regmap_read(regmap, reg, &pen))247 return -EIO;248 *value = pen >> 7;249 return 0;250}251 252static int intel_crc_pmic_update_policy(struct regmap *regmap,253 int reg, int bit, int enable)254{255 int alert0;256 257 /* Update to policy enable bit requires unlocking a0lock */258 if (regmap_read(regmap, PMIC_A0LOCK_REG, &alert0))259 return -EIO;260 261 if (regmap_update_bits(regmap, PMIC_A0LOCK_REG, 0x01, 0))262 return -EIO;263 264 if (regmap_update_bits(regmap, reg, 0x80, enable << 7))265 return -EIO;266 267 /* restore alert0 */268 if (regmap_write(regmap, PMIC_A0LOCK_REG, alert0))269 return -EIO;270 271 return 0;272}273 274static const struct intel_pmic_opregion_data intel_crc_pmic_opregion_data = {275 .get_power = intel_crc_pmic_get_power,276 .update_power = intel_crc_pmic_update_power,277 .get_raw_temp = intel_crc_pmic_get_raw_temp,278 .update_aux = intel_crc_pmic_update_aux,279 .get_policy = intel_crc_pmic_get_policy,280 .update_policy = intel_crc_pmic_update_policy,281 .lpat_raw_to_temp = acpi_lpat_raw_to_temp,282 .power_table = power_table,283 .power_table_count= ARRAY_SIZE(power_table),284 .thermal_table = thermal_table,285 .thermal_table_count = ARRAY_SIZE(thermal_table),286 .pmic_i2c_address = 0x6e,287};288 289static int intel_crc_pmic_opregion_probe(struct platform_device *pdev)290{291 struct intel_soc_pmic *pmic = dev_get_drvdata(pdev->dev.parent);292 return intel_pmic_install_opregion_handler(&pdev->dev,293 ACPI_HANDLE(pdev->dev.parent), pmic->regmap,294 &intel_crc_pmic_opregion_data);295}296 297static struct platform_driver intel_crc_pmic_opregion_driver = {298 .probe = intel_crc_pmic_opregion_probe,299 .driver = {300 .name = "byt_crystal_cove_pmic",301 },302};303builtin_platform_driver(intel_crc_pmic_opregion_driver);304