1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Intel Bay Trail Crystal Cove PMIC operation region driver 4 * 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 0xc5 18 19 static 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 137 static struct pmic_table thermal_table[] = { 138 { 139 .address = 0x00, 140 .reg = 0x75 141 }, 142 { 143 .address = 0x04, 144 .reg = 0x95 145 }, 146 { 147 .address = 0x08, 148 .reg = 0x97 149 }, 150 { 151 .address = 0x0c, 152 .reg = 0x77 153 }, 154 { 155 .address = 0x10, 156 .reg = 0x9a 157 }, 158 { 159 .address = 0x14, 160 .reg = 0x9c 161 }, 162 { 163 .address = 0x18, 164 .reg = 0x79 165 }, 166 { 167 .address = 0x1c, 168 .reg = 0x9f 169 }, 170 { 171 .address = 0x20, 172 .reg = 0xa1 173 }, 174 { 175 .address = 0x48, 176 .reg = 0x94 177 }, 178 { 179 .address = 0x4c, 180 .reg = 0x99 181 }, 182 { 183 .address = 0x50, 184 .reg = 0x9e 185 }, 186 }; 187 188 static 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 200 static 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 220 static 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 reg 226 * and 2bits in reg-1: bit0,1 227 */ 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 235 static 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 241 static 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 252 static 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 274 static 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 .power_table = power_table, 282 .power_table_count= ARRAY_SIZE(power_table), 283 .thermal_table = thermal_table, 284 .thermal_table_count = ARRAY_SIZE(thermal_table), 285 }; 286 287 static int intel_crc_pmic_opregion_probe(struct platform_device *pdev) 288 { 289 struct intel_soc_pmic *pmic = dev_get_drvdata(pdev->dev.parent); 290 return intel_pmic_install_opregion_handler(&pdev->dev, 291 ACPI_HANDLE(pdev->dev.parent), pmic->regmap, 292 &intel_crc_pmic_opregion_data); 293 } 294 295 static struct platform_driver intel_crc_pmic_opregion_driver = { 296 .probe = intel_crc_pmic_opregion_probe, 297 .driver = { 298 .name = "byt_crystal_cove_pmic", 299 }, 300 }; 301 builtin_platform_driver(intel_crc_pmic_opregion_driver); 302