1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Intel BXT WhiskeyCove PMIC operation region driver 4 * 5 * Copyright (C) 2015 Intel Corporation. All rights reserved. 6 */ 7 8 #include <linux/init.h> 9 #include <linux/acpi.h> 10 #include <linux/mfd/intel_soc_pmic.h> 11 #include <linux/regmap.h> 12 #include <linux/platform_device.h> 13 #include "intel_pmic.h" 14 15 #define WHISKEY_COVE_ALRT_HIGH_BIT_MASK 0x0F 16 #define WHISKEY_COVE_ADC_HIGH_BIT(x) (((x & 0x0F) << 8)) 17 #define WHISKEY_COVE_ADC_CURSRC(x) (((x & 0xF0) >> 4)) 18 #define VR_MODE_DISABLED 0 19 #define VR_MODE_AUTO BIT(0) 20 #define VR_MODE_NORMAL BIT(1) 21 #define VR_MODE_SWITCH BIT(2) 22 #define VR_MODE_ECO (BIT(0)|BIT(1)) 23 #define VSWITCH2_OUTPUT BIT(5) 24 #define VSWITCH1_OUTPUT BIT(4) 25 #define VUSBPHY_CHARGE BIT(1) 26 27 static struct pmic_table power_table[] = { 28 { 29 .address = 0x0, 30 .reg = 0x63, 31 .bit = VR_MODE_AUTO, 32 }, /* VDD1 -> VDD1CNT */ 33 { 34 .address = 0x04, 35 .reg = 0x65, 36 .bit = VR_MODE_AUTO, 37 }, /* VDD2 -> VDD2CNT */ 38 { 39 .address = 0x08, 40 .reg = 0x67, 41 .bit = VR_MODE_AUTO, 42 }, /* VDD3 -> VDD3CNT */ 43 { 44 .address = 0x0c, 45 .reg = 0x6d, 46 .bit = VR_MODE_AUTO, 47 }, /* VLFX -> VFLEXCNT */ 48 { 49 .address = 0x10, 50 .reg = 0x6f, 51 .bit = VR_MODE_NORMAL, 52 }, /* VP1A -> VPROG1ACNT */ 53 { 54 .address = 0x14, 55 .reg = 0x70, 56 .bit = VR_MODE_NORMAL, 57 }, /* VP1B -> VPROG1BCNT */ 58 { 59 .address = 0x18, 60 .reg = 0x71, 61 .bit = VR_MODE_NORMAL, 62 }, /* VP1C -> VPROG1CCNT */ 63 { 64 .address = 0x1c, 65 .reg = 0x72, 66 .bit = VR_MODE_NORMAL, 67 }, /* VP1D -> VPROG1DCNT */ 68 { 69 .address = 0x20, 70 .reg = 0x73, 71 .bit = VR_MODE_NORMAL, 72 }, /* VP2A -> VPROG2ACNT */ 73 { 74 .address = 0x24, 75 .reg = 0x74, 76 .bit = VR_MODE_NORMAL, 77 }, /* VP2B -> VPROG2BCNT */ 78 { 79 .address = 0x28, 80 .reg = 0x75, 81 .bit = VR_MODE_NORMAL, 82 }, /* VP2C -> VPROG2CCNT */ 83 { 84 .address = 0x2c, 85 .reg = 0x76, 86 .bit = VR_MODE_NORMAL, 87 }, /* VP3A -> VPROG3ACNT */ 88 { 89 .address = 0x30, 90 .reg = 0x77, 91 .bit = VR_MODE_NORMAL, 92 }, /* VP3B -> VPROG3BCNT */ 93 { 94 .address = 0x34, 95 .reg = 0x78, 96 .bit = VSWITCH2_OUTPUT, 97 }, /* VSW2 -> VLD0CNT Bit 5*/ 98 { 99 .address = 0x38, 100 .reg = 0x78, 101 .bit = VSWITCH1_OUTPUT, 102 }, /* VSW1 -> VLD0CNT Bit 4 */ 103 { 104 .address = 0x3c, 105 .reg = 0x78, 106 .bit = VUSBPHY_CHARGE, 107 }, /* VUPY -> VLDOCNT Bit 1 */ 108 { 109 .address = 0x40, 110 .reg = 0x7b, 111 .bit = VR_MODE_NORMAL, 112 }, /* VRSO -> VREFSOCCNT*/ 113 { 114 .address = 0x44, 115 .reg = 0xA0, 116 .bit = VR_MODE_NORMAL, 117 }, /* VP1E -> VPROG1ECNT */ 118 { 119 .address = 0x48, 120 .reg = 0xA1, 121 .bit = VR_MODE_NORMAL, 122 }, /* VP1F -> VPROG1FCNT */ 123 { 124 .address = 0x4c, 125 .reg = 0xA2, 126 .bit = VR_MODE_NORMAL, 127 }, /* VP2D -> VPROG2DCNT */ 128 { 129 .address = 0x50, 130 .reg = 0xA3, 131 .bit = VR_MODE_NORMAL, 132 }, /* VP4A -> VPROG4ACNT */ 133 { 134 .address = 0x54, 135 .reg = 0xA4, 136 .bit = VR_MODE_NORMAL, 137 }, /* VP4B -> VPROG4BCNT */ 138 { 139 .address = 0x58, 140 .reg = 0xA5, 141 .bit = VR_MODE_NORMAL, 142 }, /* VP4C -> VPROG4CCNT */ 143 { 144 .address = 0x5c, 145 .reg = 0xA6, 146 .bit = VR_MODE_NORMAL, 147 }, /* VP4D -> VPROG4DCNT */ 148 { 149 .address = 0x60, 150 .reg = 0xA7, 151 .bit = VR_MODE_NORMAL, 152 }, /* VP5A -> VPROG5ACNT */ 153 { 154 .address = 0x64, 155 .reg = 0xA8, 156 .bit = VR_MODE_NORMAL, 157 }, /* VP5B -> VPROG5BCNT */ 158 { 159 .address = 0x68, 160 .reg = 0xA9, 161 .bit = VR_MODE_NORMAL, 162 }, /* VP6A -> VPROG6ACNT */ 163 { 164 .address = 0x6c, 165 .reg = 0xAA, 166 .bit = VR_MODE_NORMAL, 167 }, /* VP6B -> VPROG6BCNT */ 168 { 169 .address = 0x70, 170 .reg = 0x36, 171 .bit = BIT(2), 172 }, /* SDWN_N -> MODEMCTRL Bit 2 */ 173 { 174 .address = 0x74, 175 .reg = 0x36, 176 .bit = BIT(0), 177 } /* MOFF -> MODEMCTRL Bit 0 */ 178 }; 179 180 static struct pmic_table thermal_table[] = { 181 { 182 .address = 0x00, 183 .reg = 0x4F39 184 }, 185 { 186 .address = 0x04, 187 .reg = 0x4F24 188 }, 189 { 190 .address = 0x08, 191 .reg = 0x4F26 192 }, 193 { 194 .address = 0x0c, 195 .reg = 0x4F3B 196 }, 197 { 198 .address = 0x10, 199 .reg = 0x4F28 200 }, 201 { 202 .address = 0x14, 203 .reg = 0x4F2A 204 }, 205 { 206 .address = 0x18, 207 .reg = 0x4F3D 208 }, 209 { 210 .address = 0x1c, 211 .reg = 0x4F2C 212 }, 213 { 214 .address = 0x20, 215 .reg = 0x4F2E 216 }, 217 { 218 .address = 0x24, 219 .reg = 0x4F3F 220 }, 221 { 222 .address = 0x28, 223 .reg = 0x4F30 224 }, 225 { 226 .address = 0x30, 227 .reg = 0x4F41 228 }, 229 { 230 .address = 0x34, 231 .reg = 0x4F32 232 }, 233 { 234 .address = 0x3c, 235 .reg = 0x4F43 236 }, 237 { 238 .address = 0x40, 239 .reg = 0x4F34 240 }, 241 { 242 .address = 0x48, 243 .reg = 0x4F6A, 244 .bit = 0, 245 }, 246 { 247 .address = 0x4C, 248 .reg = 0x4F6A, 249 .bit = 1 250 }, 251 { 252 .address = 0x50, 253 .reg = 0x4F6A, 254 .bit = 2 255 }, 256 { 257 .address = 0x54, 258 .reg = 0x4F6A, 259 .bit = 4 260 }, 261 { 262 .address = 0x58, 263 .reg = 0x4F6A, 264 .bit = 5 265 }, 266 { 267 .address = 0x5C, 268 .reg = 0x4F6A, 269 .bit = 3 270 }, 271 }; 272 273 static int intel_bxtwc_pmic_get_power(struct regmap *regmap, int reg, 274 int bit, u64 *value) 275 { 276 int data; 277 278 if (regmap_read(regmap, reg, &data)) 279 return -EIO; 280 281 *value = (data & bit) ? 1 : 0; 282 return 0; 283 } 284 285 static int intel_bxtwc_pmic_update_power(struct regmap *regmap, int reg, 286 int bit, bool on) 287 { 288 u8 val, mask = bit; 289 290 if (on) 291 val = 0xFF; 292 else 293 val = 0x0; 294 295 return regmap_update_bits(regmap, reg, mask, val); 296 } 297 298 static int intel_bxtwc_pmic_get_raw_temp(struct regmap *regmap, int reg) 299 { 300 unsigned int val, adc_val, reg_val; 301 u8 temp_l, temp_h, cursrc; 302 unsigned long rlsb; 303 static const unsigned long rlsb_array[] = { 304 0, 260420, 130210, 65100, 32550, 16280, 305 8140, 4070, 2030, 0, 260420, 130210 }; 306 307 if (regmap_read(regmap, reg, &val)) 308 return -EIO; 309 temp_l = (u8) val; 310 311 if (regmap_read(regmap, (reg - 1), &val)) 312 return -EIO; 313 temp_h = (u8) val; 314 315 reg_val = temp_l | WHISKEY_COVE_ADC_HIGH_BIT(temp_h); 316 cursrc = WHISKEY_COVE_ADC_CURSRC(temp_h); 317 rlsb = rlsb_array[cursrc]; 318 adc_val = reg_val * rlsb / 1000; 319 320 return adc_val; 321 } 322 323 static int 324 intel_bxtwc_pmic_update_aux(struct regmap *regmap, int reg, int raw) 325 { 326 u32 bsr_num; 327 u16 resi_val, count = 0, thrsh = 0; 328 u8 alrt_h, alrt_l, cursel = 0; 329 330 bsr_num = raw; 331 bsr_num /= (1 << 5); 332 333 count = fls(bsr_num) - 1; 334 335 cursel = clamp_t(s8, (count - 7), 0, 7); 336 thrsh = raw / (1 << (4 + cursel)); 337 338 resi_val = (cursel << 9) | thrsh; 339 alrt_h = (resi_val >> 8) & WHISKEY_COVE_ALRT_HIGH_BIT_MASK; 340 if (regmap_update_bits(regmap, 341 reg - 1, 342 WHISKEY_COVE_ALRT_HIGH_BIT_MASK, 343 alrt_h)) 344 return -EIO; 345 346 alrt_l = (u8)resi_val; 347 return regmap_write(regmap, reg, alrt_l); 348 } 349 350 static int 351 intel_bxtwc_pmic_get_policy(struct regmap *regmap, int reg, int bit, u64 *value) 352 { 353 u8 mask = BIT(bit); 354 unsigned int val; 355 356 if (regmap_read(regmap, reg, &val)) 357 return -EIO; 358 359 *value = (val & mask) >> bit; 360 return 0; 361 } 362 363 static int 364 intel_bxtwc_pmic_update_policy(struct regmap *regmap, 365 int reg, int bit, int enable) 366 { 367 u8 mask = BIT(bit), val = enable << bit; 368 369 return regmap_update_bits(regmap, reg, mask, val); 370 } 371 372 static struct intel_pmic_opregion_data intel_bxtwc_pmic_opregion_data = { 373 .get_power = intel_bxtwc_pmic_get_power, 374 .update_power = intel_bxtwc_pmic_update_power, 375 .get_raw_temp = intel_bxtwc_pmic_get_raw_temp, 376 .update_aux = intel_bxtwc_pmic_update_aux, 377 .get_policy = intel_bxtwc_pmic_get_policy, 378 .update_policy = intel_bxtwc_pmic_update_policy, 379 .power_table = power_table, 380 .power_table_count = ARRAY_SIZE(power_table), 381 .thermal_table = thermal_table, 382 .thermal_table_count = ARRAY_SIZE(thermal_table), 383 }; 384 385 static int intel_bxtwc_pmic_opregion_probe(struct platform_device *pdev) 386 { 387 struct intel_soc_pmic *pmic = dev_get_drvdata(pdev->dev.parent); 388 389 return intel_pmic_install_opregion_handler(&pdev->dev, 390 ACPI_HANDLE(pdev->dev.parent), 391 pmic->regmap, 392 &intel_bxtwc_pmic_opregion_data); 393 } 394 395 static const struct platform_device_id bxt_wc_opregion_id_table[] = { 396 { .name = "bxt_wcove_region" }, 397 {}, 398 }; 399 400 static struct platform_driver intel_bxtwc_pmic_opregion_driver = { 401 .probe = intel_bxtwc_pmic_opregion_probe, 402 .driver = { 403 .name = "bxt_whiskey_cove_pmic", 404 }, 405 .id_table = bxt_wc_opregion_id_table, 406 }; 407 builtin_platform_driver(intel_bxtwc_pmic_opregion_driver); 408