1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Intel CHT Whiskey Cove PMIC operation region driver 4 * 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 0x6e3b 18 #define CHT_WC_V1P15_CTRL 0x6e3c 19 #define CHT_WC_V1P05A_VSEL 0x6e3d 20 #define CHT_WC_V1P15_VSEL 0x6e3e 21 #define CHT_WC_V1P8A_CTRL 0x6e56 22 #define CHT_WC_V1P8SX_CTRL 0x6e57 23 #define CHT_WC_VDDQ_CTRL 0x6e58 24 #define CHT_WC_V1P2A_CTRL 0x6e59 25 #define CHT_WC_V1P2SX_CTRL 0x6e5a 26 #define CHT_WC_V1P8A_VSEL 0x6e5b 27 #define CHT_WC_VDDQ_VSEL 0x6e5c 28 #define CHT_WC_V2P8SX_CTRL 0x6e5d 29 #define CHT_WC_V3P3A_CTRL 0x6e5e 30 #define CHT_WC_V3P3SD_CTRL 0x6e5f 31 #define CHT_WC_VSDIO_CTRL 0x6e67 32 #define CHT_WC_V3P3A_VSEL 0x6e68 33 #define CHT_WC_VPROG1A_CTRL 0x6e90 34 #define CHT_WC_VPROG1B_CTRL 0x6e91 35 #define CHT_WC_VPROG1F_CTRL 0x6e95 36 #define CHT_WC_VPROG2D_CTRL 0x6e99 37 #define CHT_WC_VPROG3A_CTRL 0x6e9a 38 #define CHT_WC_VPROG3B_CTRL 0x6e9b 39 #define CHT_WC_VPROG4A_CTRL 0x6e9c 40 #define CHT_WC_VPROG4B_CTRL 0x6e9d 41 #define CHT_WC_VPROG4C_CTRL 0x6e9e 42 #define CHT_WC_VPROG4D_CTRL 0x6e9f 43 #define CHT_WC_VPROG5A_CTRL 0x6ea0 44 #define CHT_WC_VPROG5B_CTRL 0x6ea1 45 #define CHT_WC_VPROG6A_CTRL 0x6ea2 46 #define CHT_WC_VPROG6B_CTRL 0x6ea3 47 #define CHT_WC_VPROG1A_VSEL 0x6ec0 48 #define CHT_WC_VPROG1B_VSEL 0x6ec1 49 #define CHT_WC_V1P8SX_VSEL 0x6ec2 50 #define CHT_WC_V1P2SX_VSEL 0x6ec3 51 #define CHT_WC_V1P2A_VSEL 0x6ec4 52 #define CHT_WC_VPROG1F_VSEL 0x6ec5 53 #define CHT_WC_VSDIO_VSEL 0x6ec6 54 #define CHT_WC_V2P8SX_VSEL 0x6ec7 55 #define CHT_WC_V3P3SD_VSEL 0x6ec8 56 #define CHT_WC_VPROG2D_VSEL 0x6ec9 57 #define CHT_WC_VPROG3A_VSEL 0x6eca 58 #define CHT_WC_VPROG3B_VSEL 0x6ecb 59 #define CHT_WC_VPROG4A_VSEL 0x6ecc 60 #define CHT_WC_VPROG4B_VSEL 0x6ecd 61 #define CHT_WC_VPROG4C_VSEL 0x6ece 62 #define CHT_WC_VPROG4D_VSEL 0x6ecf 63 #define CHT_WC_VPROG5A_VSEL 0x6ed0 64 #define CHT_WC_VPROG5B_VSEL 0x6ed1 65 #define CHT_WC_VPROG6A_VSEL 0x6ed2 66 #define CHT_WC_VPROG6B_VSEL 0x6ed3 67 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.patch 72 */ 73 static 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 216 static 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 228 static 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 234 static 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 opregion 255 * (DPTF) due to lacking documentation. 256 */ 257 static 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 266 static 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 276 static const struct platform_device_id cht_wc_opregion_id_table[] = { 277 { .name = "cht_wcove_region" }, 278 {}, 279 }; 280 281 static 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 }; 288 builtin_platform_driver(intel_cht_wc_pmic_opregion_driver); 289