1 /* 2 * intel_pmic_xpower.c - XPower AXP288 PMIC operation region driver 3 * 4 * Copyright (C) 2014 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/init.h> 17 #include <linux/acpi.h> 18 #include <linux/mfd/axp20x.h> 19 #include <linux/regmap.h> 20 #include <linux/platform_device.h> 21 #include "intel_pmic.h" 22 23 #define XPOWER_GPADC_LOW 0x5b 24 #define XPOWER_GPI1_CTRL 0x92 25 26 #define GPI1_LDO_MASK GENMASK(2, 0) 27 #define GPI1_LDO_ON (3 << 0) 28 #define GPI1_LDO_OFF (4 << 0) 29 30 static struct pmic_table power_table[] = { 31 { 32 .address = 0x00, 33 .reg = 0x13, 34 .bit = 0x05, 35 }, /* ALD1 */ 36 { 37 .address = 0x04, 38 .reg = 0x13, 39 .bit = 0x06, 40 }, /* ALD2 */ 41 { 42 .address = 0x08, 43 .reg = 0x13, 44 .bit = 0x07, 45 }, /* ALD3 */ 46 { 47 .address = 0x0c, 48 .reg = 0x12, 49 .bit = 0x03, 50 }, /* DLD1 */ 51 { 52 .address = 0x10, 53 .reg = 0x12, 54 .bit = 0x04, 55 }, /* DLD2 */ 56 { 57 .address = 0x14, 58 .reg = 0x12, 59 .bit = 0x05, 60 }, /* DLD3 */ 61 { 62 .address = 0x18, 63 .reg = 0x12, 64 .bit = 0x06, 65 }, /* DLD4 */ 66 { 67 .address = 0x1c, 68 .reg = 0x12, 69 .bit = 0x00, 70 }, /* ELD1 */ 71 { 72 .address = 0x20, 73 .reg = 0x12, 74 .bit = 0x01, 75 }, /* ELD2 */ 76 { 77 .address = 0x24, 78 .reg = 0x12, 79 .bit = 0x02, 80 }, /* ELD3 */ 81 { 82 .address = 0x28, 83 .reg = 0x13, 84 .bit = 0x02, 85 }, /* FLD1 */ 86 { 87 .address = 0x2c, 88 .reg = 0x13, 89 .bit = 0x03, 90 }, /* FLD2 */ 91 { 92 .address = 0x30, 93 .reg = 0x13, 94 .bit = 0x04, 95 }, /* FLD3 */ 96 { 97 .address = 0x34, 98 .reg = 0x10, 99 .bit = 0x03, 100 }, /* BUC1 */ 101 { 102 .address = 0x38, 103 .reg = 0x10, 104 .bit = 0x06, 105 }, /* BUC2 */ 106 { 107 .address = 0x3c, 108 .reg = 0x10, 109 .bit = 0x05, 110 }, /* BUC3 */ 111 { 112 .address = 0x40, 113 .reg = 0x10, 114 .bit = 0x04, 115 }, /* BUC4 */ 116 { 117 .address = 0x44, 118 .reg = 0x10, 119 .bit = 0x01, 120 }, /* BUC5 */ 121 { 122 .address = 0x48, 123 .reg = 0x10, 124 .bit = 0x00 125 }, /* BUC6 */ 126 { 127 .address = 0x4c, 128 .reg = 0x92, 129 }, /* GPI1 */ 130 }; 131 132 /* TMP0 - TMP5 are the same, all from GPADC */ 133 static struct pmic_table thermal_table[] = { 134 { 135 .address = 0x00, 136 .reg = XPOWER_GPADC_LOW 137 }, 138 { 139 .address = 0x0c, 140 .reg = XPOWER_GPADC_LOW 141 }, 142 { 143 .address = 0x18, 144 .reg = XPOWER_GPADC_LOW 145 }, 146 { 147 .address = 0x24, 148 .reg = XPOWER_GPADC_LOW 149 }, 150 { 151 .address = 0x30, 152 .reg = XPOWER_GPADC_LOW 153 }, 154 { 155 .address = 0x3c, 156 .reg = XPOWER_GPADC_LOW 157 }, 158 }; 159 160 static int intel_xpower_pmic_get_power(struct regmap *regmap, int reg, 161 int bit, u64 *value) 162 { 163 int data; 164 165 if (regmap_read(regmap, reg, &data)) 166 return -EIO; 167 168 /* GPIO1 LDO regulator needs special handling */ 169 if (reg == XPOWER_GPI1_CTRL) 170 *value = ((data & GPI1_LDO_MASK) == GPI1_LDO_ON); 171 else 172 *value = (data & BIT(bit)) ? 1 : 0; 173 174 return 0; 175 } 176 177 static int intel_xpower_pmic_update_power(struct regmap *regmap, int reg, 178 int bit, bool on) 179 { 180 int data; 181 182 /* GPIO1 LDO regulator needs special handling */ 183 if (reg == XPOWER_GPI1_CTRL) 184 return regmap_update_bits(regmap, reg, GPI1_LDO_MASK, 185 on ? GPI1_LDO_ON : GPI1_LDO_OFF); 186 187 if (regmap_read(regmap, reg, &data)) 188 return -EIO; 189 190 if (on) 191 data |= BIT(bit); 192 else 193 data &= ~BIT(bit); 194 195 if (regmap_write(regmap, reg, data)) 196 return -EIO; 197 198 return 0; 199 } 200 201 /** 202 * intel_xpower_pmic_get_raw_temp(): Get raw temperature reading from the PMIC 203 * 204 * @regmap: regmap of the PMIC device 205 * @reg: register to get the reading 206 * 207 * Return a positive value on success, errno on failure. 208 */ 209 static int intel_xpower_pmic_get_raw_temp(struct regmap *regmap, int reg) 210 { 211 u8 buf[2]; 212 213 if (regmap_bulk_read(regmap, AXP288_GP_ADC_H, buf, 2)) 214 return -EIO; 215 216 return (buf[0] << 4) + ((buf[1] >> 4) & 0x0F); 217 } 218 219 static struct intel_pmic_opregion_data intel_xpower_pmic_opregion_data = { 220 .get_power = intel_xpower_pmic_get_power, 221 .update_power = intel_xpower_pmic_update_power, 222 .get_raw_temp = intel_xpower_pmic_get_raw_temp, 223 .power_table = power_table, 224 .power_table_count = ARRAY_SIZE(power_table), 225 .thermal_table = thermal_table, 226 .thermal_table_count = ARRAY_SIZE(thermal_table), 227 }; 228 229 static acpi_status intel_xpower_pmic_gpio_handler(u32 function, 230 acpi_physical_address address, u32 bit_width, u64 *value, 231 void *handler_context, void *region_context) 232 { 233 return AE_OK; 234 } 235 236 static int intel_xpower_pmic_opregion_probe(struct platform_device *pdev) 237 { 238 struct device *parent = pdev->dev.parent; 239 struct axp20x_dev *axp20x = dev_get_drvdata(parent); 240 acpi_status status; 241 int result; 242 243 status = acpi_install_address_space_handler(ACPI_HANDLE(parent), 244 ACPI_ADR_SPACE_GPIO, intel_xpower_pmic_gpio_handler, 245 NULL, NULL); 246 if (ACPI_FAILURE(status)) 247 return -ENODEV; 248 249 result = intel_pmic_install_opregion_handler(&pdev->dev, 250 ACPI_HANDLE(parent), axp20x->regmap, 251 &intel_xpower_pmic_opregion_data); 252 if (result) 253 acpi_remove_address_space_handler(ACPI_HANDLE(parent), 254 ACPI_ADR_SPACE_GPIO, 255 intel_xpower_pmic_gpio_handler); 256 257 return result; 258 } 259 260 static struct platform_driver intel_xpower_pmic_opregion_driver = { 261 .probe = intel_xpower_pmic_opregion_probe, 262 .driver = { 263 .name = "axp288_pmic_acpi", 264 }, 265 }; 266 267 static int __init intel_xpower_pmic_opregion_driver_init(void) 268 { 269 return platform_driver_register(&intel_xpower_pmic_opregion_driver); 270 } 271 device_initcall(intel_xpower_pmic_opregion_driver_init); 272