root/drivers/acpi/pmic/intel_pmic_xpower.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. intel_xpower_pmic_get_power
  2. intel_xpower_pmic_update_power
  3. intel_xpower_pmic_get_raw_temp
  4. intel_xpower_pmic_gpio_handler
  5. intel_xpower_pmic_opregion_probe

   1 // SPDX-License-Identifier: GPL-2.0
   2 /*
   3  * XPower AXP288 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/axp20x.h>
  11 #include <linux/regmap.h>
  12 #include <linux/platform_device.h>
  13 #include <asm/iosf_mbi.h>
  14 #include "intel_pmic.h"
  15 
  16 #define XPOWER_GPADC_LOW        0x5b
  17 #define XPOWER_GPI1_CTRL        0x92
  18 
  19 #define GPI1_LDO_MASK           GENMASK(2, 0)
  20 #define GPI1_LDO_ON             (3 << 0)
  21 #define GPI1_LDO_OFF            (4 << 0)
  22 
  23 #define AXP288_ADC_TS_CURRENT_ON_OFF_MASK               GENMASK(1, 0)
  24 #define AXP288_ADC_TS_CURRENT_OFF                       (0 << 0)
  25 #define AXP288_ADC_TS_CURRENT_ON_WHEN_CHARGING          (1 << 0)
  26 #define AXP288_ADC_TS_CURRENT_ON_ONDEMAND               (2 << 0)
  27 #define AXP288_ADC_TS_CURRENT_ON                        (3 << 0)
  28 
  29 static struct pmic_table power_table[] = {
  30         {
  31                 .address = 0x00,
  32                 .reg = 0x13,
  33                 .bit = 0x05,
  34         }, /* ALD1 */
  35         {
  36                 .address = 0x04,
  37                 .reg = 0x13,
  38                 .bit = 0x06,
  39         }, /* ALD2 */
  40         {
  41                 .address = 0x08,
  42                 .reg = 0x13,
  43                 .bit = 0x07,
  44         }, /* ALD3 */
  45         {
  46                 .address = 0x0c,
  47                 .reg = 0x12,
  48                 .bit = 0x03,
  49         }, /* DLD1 */
  50         {
  51                 .address = 0x10,
  52                 .reg = 0x12,
  53                 .bit = 0x04,
  54         }, /* DLD2 */
  55         {
  56                 .address = 0x14,
  57                 .reg = 0x12,
  58                 .bit = 0x05,
  59         }, /* DLD3 */
  60         {
  61                 .address = 0x18,
  62                 .reg = 0x12,
  63                 .bit = 0x06,
  64         }, /* DLD4 */
  65         {
  66                 .address = 0x1c,
  67                 .reg = 0x12,
  68                 .bit = 0x00,
  69         }, /* ELD1 */
  70         {
  71                 .address = 0x20,
  72                 .reg = 0x12,
  73                 .bit = 0x01,
  74         }, /* ELD2 */
  75         {
  76                 .address = 0x24,
  77                 .reg = 0x12,
  78                 .bit = 0x02,
  79         }, /* ELD3 */
  80         {
  81                 .address = 0x28,
  82                 .reg = 0x13,
  83                 .bit = 0x02,
  84         }, /* FLD1 */
  85         {
  86                 .address = 0x2c,
  87                 .reg = 0x13,
  88                 .bit = 0x03,
  89         }, /* FLD2 */
  90         {
  91                 .address = 0x30,
  92                 .reg = 0x13,
  93                 .bit = 0x04,
  94         }, /* FLD3 */
  95         {
  96                 .address = 0x34,
  97                 .reg = 0x10,
  98                 .bit = 0x03,
  99         }, /* BUC1 */
 100         {
 101                 .address = 0x38,
 102                 .reg = 0x10,
 103                 .bit = 0x06,
 104         }, /* BUC2 */
 105         {
 106                 .address = 0x3c,
 107                 .reg = 0x10,
 108                 .bit = 0x05,
 109         }, /* BUC3 */
 110         {
 111                 .address = 0x40,
 112                 .reg = 0x10,
 113                 .bit = 0x04,
 114         }, /* BUC4 */
 115         {
 116                 .address = 0x44,
 117                 .reg = 0x10,
 118                 .bit = 0x01,
 119         }, /* BUC5 */
 120         {
 121                 .address = 0x48,
 122                 .reg = 0x10,
 123                 .bit = 0x00
 124         }, /* BUC6 */
 125         {
 126                 .address = 0x4c,
 127                 .reg = 0x92,
 128         }, /* GPI1 */
 129 };
 130 
 131 /* TMP0 - TMP5 are the same, all from GPADC */
 132 static struct pmic_table thermal_table[] = {
 133         {
 134                 .address = 0x00,
 135                 .reg = XPOWER_GPADC_LOW
 136         },
 137         {
 138                 .address = 0x0c,
 139                 .reg = XPOWER_GPADC_LOW
 140         },
 141         {
 142                 .address = 0x18,
 143                 .reg = XPOWER_GPADC_LOW
 144         },
 145         {
 146                 .address = 0x24,
 147                 .reg = XPOWER_GPADC_LOW
 148         },
 149         {
 150                 .address = 0x30,
 151                 .reg = XPOWER_GPADC_LOW
 152         },
 153         {
 154                 .address = 0x3c,
 155                 .reg = XPOWER_GPADC_LOW
 156         },
 157 };
 158 
 159 static int intel_xpower_pmic_get_power(struct regmap *regmap, int reg,
 160                                        int bit, u64 *value)
 161 {
 162         int data;
 163 
 164         if (regmap_read(regmap, reg, &data))
 165                 return -EIO;
 166 
 167         /* GPIO1 LDO regulator needs special handling */
 168         if (reg == XPOWER_GPI1_CTRL)
 169                 *value = ((data & GPI1_LDO_MASK) == GPI1_LDO_ON);
 170         else
 171                 *value = (data & BIT(bit)) ? 1 : 0;
 172 
 173         return 0;
 174 }
 175 
 176 static int intel_xpower_pmic_update_power(struct regmap *regmap, int reg,
 177                                           int bit, bool on)
 178 {
 179         int data, ret;
 180 
 181         /* GPIO1 LDO regulator needs special handling */
 182         if (reg == XPOWER_GPI1_CTRL)
 183                 return regmap_update_bits(regmap, reg, GPI1_LDO_MASK,
 184                                           on ? GPI1_LDO_ON : GPI1_LDO_OFF);
 185 
 186         ret = iosf_mbi_block_punit_i2c_access();
 187         if (ret)
 188                 return ret;
 189 
 190         if (regmap_read(regmap, reg, &data)) {
 191                 ret = -EIO;
 192                 goto out;
 193         }
 194 
 195         if (on)
 196                 data |= BIT(bit);
 197         else
 198                 data &= ~BIT(bit);
 199 
 200         if (regmap_write(regmap, reg, data))
 201                 ret = -EIO;
 202 out:
 203         iosf_mbi_unblock_punit_i2c_access();
 204 
 205         return ret;
 206 }
 207 
 208 /**
 209  * intel_xpower_pmic_get_raw_temp(): Get raw temperature reading from the PMIC
 210  *
 211  * @regmap: regmap of the PMIC device
 212  * @reg: register to get the reading
 213  *
 214  * Return a positive value on success, errno on failure.
 215  */
 216 static int intel_xpower_pmic_get_raw_temp(struct regmap *regmap, int reg)
 217 {
 218         int ret, adc_ts_pin_ctrl;
 219         u8 buf[2];
 220 
 221         /*
 222          * The current-source used for the battery temp-sensor (TS) is shared
 223          * with the GPADC. For proper fuel-gauge and charger operation the TS
 224          * current-source needs to be permanently on. But to read the GPADC we
 225          * need to temporary switch the TS current-source to ondemand, so that
 226          * the GPADC can use it, otherwise we will always read an all 0 value.
 227          *
 228          * Note that the switching from on to on-ondemand is not necessary
 229          * when the TS current-source is off (this happens on devices which
 230          * do not use the TS-pin).
 231          */
 232         ret = regmap_read(regmap, AXP288_ADC_TS_PIN_CTRL, &adc_ts_pin_ctrl);
 233         if (ret)
 234                 return ret;
 235 
 236         if (adc_ts_pin_ctrl & AXP288_ADC_TS_CURRENT_ON_OFF_MASK) {
 237                 ret = regmap_update_bits(regmap, AXP288_ADC_TS_PIN_CTRL,
 238                                          AXP288_ADC_TS_CURRENT_ON_OFF_MASK,
 239                                          AXP288_ADC_TS_CURRENT_ON_ONDEMAND);
 240                 if (ret)
 241                         return ret;
 242 
 243                 /* Wait a bit after switching the current-source */
 244                 usleep_range(6000, 10000);
 245         }
 246 
 247         ret = regmap_bulk_read(regmap, AXP288_GP_ADC_H, buf, 2);
 248         if (ret == 0)
 249                 ret = (buf[0] << 4) + ((buf[1] >> 4) & 0x0f);
 250 
 251         if (adc_ts_pin_ctrl & AXP288_ADC_TS_CURRENT_ON_OFF_MASK) {
 252                 regmap_update_bits(regmap, AXP288_ADC_TS_PIN_CTRL,
 253                                    AXP288_ADC_TS_CURRENT_ON_OFF_MASK,
 254                                    AXP288_ADC_TS_CURRENT_ON);
 255         }
 256 
 257         return ret;
 258 }
 259 
 260 static struct intel_pmic_opregion_data intel_xpower_pmic_opregion_data = {
 261         .get_power = intel_xpower_pmic_get_power,
 262         .update_power = intel_xpower_pmic_update_power,
 263         .get_raw_temp = intel_xpower_pmic_get_raw_temp,
 264         .power_table = power_table,
 265         .power_table_count = ARRAY_SIZE(power_table),
 266         .thermal_table = thermal_table,
 267         .thermal_table_count = ARRAY_SIZE(thermal_table),
 268         .pmic_i2c_address = 0x34,
 269 };
 270 
 271 static acpi_status intel_xpower_pmic_gpio_handler(u32 function,
 272                 acpi_physical_address address, u32 bit_width, u64 *value,
 273                 void *handler_context, void *region_context)
 274 {
 275         return AE_OK;
 276 }
 277 
 278 static int intel_xpower_pmic_opregion_probe(struct platform_device *pdev)
 279 {
 280         struct device *parent = pdev->dev.parent;
 281         struct axp20x_dev *axp20x = dev_get_drvdata(parent);
 282         acpi_status status;
 283         int result;
 284 
 285         status = acpi_install_address_space_handler(ACPI_HANDLE(parent),
 286                         ACPI_ADR_SPACE_GPIO, intel_xpower_pmic_gpio_handler,
 287                         NULL, NULL);
 288         if (ACPI_FAILURE(status))
 289                 return -ENODEV;
 290 
 291         result = intel_pmic_install_opregion_handler(&pdev->dev,
 292                                         ACPI_HANDLE(parent), axp20x->regmap,
 293                                         &intel_xpower_pmic_opregion_data);
 294         if (result)
 295                 acpi_remove_address_space_handler(ACPI_HANDLE(parent),
 296                                                   ACPI_ADR_SPACE_GPIO,
 297                                                   intel_xpower_pmic_gpio_handler);
 298 
 299         return result;
 300 }
 301 
 302 static struct platform_driver intel_xpower_pmic_opregion_driver = {
 303         .probe = intel_xpower_pmic_opregion_probe,
 304         .driver = {
 305                 .name = "axp288_pmic_acpi",
 306         },
 307 };
 308 builtin_platform_driver(intel_xpower_pmic_opregion_driver);

/* [<][>][^][v][top][bottom][index][help] */