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