Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * axp288_adc.c - X-Powers AXP288 PMIC ADC Driver
0004  *
0005  * Copyright (C) 2014 Intel Corporation
0006  *
0007  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
0008  */
0009 
0010 #include <linux/dmi.h>
0011 #include <linux/module.h>
0012 #include <linux/kernel.h>
0013 #include <linux/device.h>
0014 #include <linux/regmap.h>
0015 #include <linux/mfd/axp20x.h>
0016 #include <linux/platform_device.h>
0017 
0018 #include <linux/iio/iio.h>
0019 #include <linux/iio/machine.h>
0020 #include <linux/iio/driver.h>
0021 
0022 /*
0023  * This mask enables all ADCs except for the battery temp-sensor (TS), that is
0024  * left as-is to avoid breaking charging on devices without a temp-sensor.
0025  */
0026 #define AXP288_ADC_EN_MASK              0xF0
0027 #define AXP288_ADC_TS_ENABLE                0x01
0028 
0029 #define AXP288_ADC_TS_BIAS_MASK             GENMASK(5, 4)
0030 #define AXP288_ADC_TS_BIAS_20UA             (0 << 4)
0031 #define AXP288_ADC_TS_BIAS_40UA             (1 << 4)
0032 #define AXP288_ADC_TS_BIAS_60UA             (2 << 4)
0033 #define AXP288_ADC_TS_BIAS_80UA             (3 << 4)
0034 #define AXP288_ADC_TS_CURRENT_ON_OFF_MASK       GENMASK(1, 0)
0035 #define AXP288_ADC_TS_CURRENT_OFF           (0 << 0)
0036 #define AXP288_ADC_TS_CURRENT_ON_WHEN_CHARGING      (1 << 0)
0037 #define AXP288_ADC_TS_CURRENT_ON_ONDEMAND       (2 << 0)
0038 #define AXP288_ADC_TS_CURRENT_ON            (3 << 0)
0039 
0040 enum axp288_adc_id {
0041     AXP288_ADC_TS,
0042     AXP288_ADC_PMIC,
0043     AXP288_ADC_GP,
0044     AXP288_ADC_BATT_CHRG_I,
0045     AXP288_ADC_BATT_DISCHRG_I,
0046     AXP288_ADC_BATT_V,
0047     AXP288_ADC_NR_CHAN,
0048 };
0049 
0050 struct axp288_adc_info {
0051     int irq;
0052     struct regmap *regmap;
0053     bool ts_enabled;
0054 };
0055 
0056 static const struct iio_chan_spec axp288_adc_channels[] = {
0057     {
0058         .indexed = 1,
0059         .type = IIO_TEMP,
0060         .channel = 0,
0061         .address = AXP288_TS_ADC_H,
0062         .datasheet_name = "TS_PIN",
0063         .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
0064     }, {
0065         .indexed = 1,
0066         .type = IIO_TEMP,
0067         .channel = 1,
0068         .address = AXP288_PMIC_ADC_H,
0069         .datasheet_name = "PMIC_TEMP",
0070         .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
0071     }, {
0072         .indexed = 1,
0073         .type = IIO_TEMP,
0074         .channel = 2,
0075         .address = AXP288_GP_ADC_H,
0076         .datasheet_name = "GPADC",
0077         .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
0078     }, {
0079         .indexed = 1,
0080         .type = IIO_CURRENT,
0081         .channel = 3,
0082         .address = AXP20X_BATT_CHRG_I_H,
0083         .datasheet_name = "BATT_CHG_I",
0084         .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
0085     }, {
0086         .indexed = 1,
0087         .type = IIO_CURRENT,
0088         .channel = 4,
0089         .address = AXP20X_BATT_DISCHRG_I_H,
0090         .datasheet_name = "BATT_DISCHRG_I",
0091         .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
0092     }, {
0093         .indexed = 1,
0094         .type = IIO_VOLTAGE,
0095         .channel = 5,
0096         .address = AXP20X_BATT_V_H,
0097         .datasheet_name = "BATT_V",
0098         .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
0099     },
0100 };
0101 
0102 /* for consumer drivers */
0103 static struct iio_map axp288_adc_default_maps[] = {
0104     IIO_MAP("TS_PIN", "axp288-batt", "axp288-batt-temp"),
0105     IIO_MAP("PMIC_TEMP", "axp288-pmic", "axp288-pmic-temp"),
0106     IIO_MAP("GPADC", "axp288-gpadc", "axp288-system-temp"),
0107     IIO_MAP("BATT_CHG_I", "axp288-chrg", "axp288-chrg-curr"),
0108     IIO_MAP("BATT_DISCHRG_I", "axp288-chrg", "axp288-chrg-d-curr"),
0109     IIO_MAP("BATT_V", "axp288-batt", "axp288-batt-volt"),
0110     {},
0111 };
0112 
0113 static int axp288_adc_read_channel(int *val, unsigned long address,
0114                 struct regmap *regmap)
0115 {
0116     u8 buf[2];
0117 
0118     if (regmap_bulk_read(regmap, address, buf, 2))
0119         return -EIO;
0120     *val = (buf[0] << 4) + ((buf[1] >> 4) & 0x0F);
0121 
0122     return IIO_VAL_INT;
0123 }
0124 
0125 /*
0126  * The current-source used for the battery temp-sensor (TS) is shared
0127  * with the GPADC. For proper fuel-gauge and charger operation the TS
0128  * current-source needs to be permanently on. But to read the GPADC we
0129  * need to temporary switch the TS current-source to ondemand, so that
0130  * the GPADC can use it, otherwise we will always read an all 0 value.
0131  */
0132 static int axp288_adc_set_ts(struct axp288_adc_info *info,
0133                  unsigned int mode, unsigned long address)
0134 {
0135     int ret;
0136 
0137     /* No need to switch the current-source if the TS pin is disabled */
0138     if (!info->ts_enabled)
0139         return 0;
0140 
0141     /* Channels other than GPADC do not need the current source */
0142     if (address != AXP288_GP_ADC_H)
0143         return 0;
0144 
0145     ret = regmap_update_bits(info->regmap, AXP288_ADC_TS_PIN_CTRL,
0146                  AXP288_ADC_TS_CURRENT_ON_OFF_MASK, mode);
0147     if (ret)
0148         return ret;
0149 
0150     /* When switching to the GPADC pin give things some time to settle */
0151     if (mode == AXP288_ADC_TS_CURRENT_ON_ONDEMAND)
0152         usleep_range(6000, 10000);
0153 
0154     return 0;
0155 }
0156 
0157 static int axp288_adc_read_raw(struct iio_dev *indio_dev,
0158             struct iio_chan_spec const *chan,
0159             int *val, int *val2, long mask)
0160 {
0161     int ret;
0162     struct axp288_adc_info *info = iio_priv(indio_dev);
0163 
0164     mutex_lock(&indio_dev->mlock);
0165     switch (mask) {
0166     case IIO_CHAN_INFO_RAW:
0167         if (axp288_adc_set_ts(info, AXP288_ADC_TS_CURRENT_ON_ONDEMAND,
0168                     chan->address)) {
0169             dev_err(&indio_dev->dev, "GPADC mode\n");
0170             ret = -EINVAL;
0171             break;
0172         }
0173         ret = axp288_adc_read_channel(val, chan->address, info->regmap);
0174         if (axp288_adc_set_ts(info, AXP288_ADC_TS_CURRENT_ON,
0175                         chan->address))
0176             dev_err(&indio_dev->dev, "TS pin restore\n");
0177         break;
0178     default:
0179         ret = -EINVAL;
0180     }
0181     mutex_unlock(&indio_dev->mlock);
0182 
0183     return ret;
0184 }
0185 
0186 /*
0187  * We rely on the machine's firmware to correctly setup the TS pin bias current
0188  * at boot. This lists systems with broken fw where we need to set it ourselves.
0189  */
0190 static const struct dmi_system_id axp288_adc_ts_bias_override[] = {
0191     {
0192         /* Lenovo Ideapad 100S (11 inch) */
0193         .matches = {
0194           DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
0195           DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo ideapad 100S-11IBY"),
0196         },
0197         .driver_data = (void *)(uintptr_t)AXP288_ADC_TS_BIAS_80UA,
0198     },
0199     {
0200         /* Nuvision Solo 10 Draw */
0201         .matches = {
0202           DMI_MATCH(DMI_SYS_VENDOR, "TMAX"),
0203           DMI_MATCH(DMI_PRODUCT_NAME, "TM101W610L"),
0204         },
0205         .driver_data = (void *)(uintptr_t)AXP288_ADC_TS_BIAS_80UA,
0206     },
0207     {}
0208 };
0209 
0210 static int axp288_adc_initialize(struct axp288_adc_info *info)
0211 {
0212     const struct dmi_system_id *bias_override;
0213     int ret, adc_enable_val;
0214 
0215     bias_override = dmi_first_match(axp288_adc_ts_bias_override);
0216     if (bias_override) {
0217         ret = regmap_update_bits(info->regmap, AXP288_ADC_TS_PIN_CTRL,
0218                      AXP288_ADC_TS_BIAS_MASK,
0219                      (uintptr_t)bias_override->driver_data);
0220         if (ret)
0221             return ret;
0222     }
0223 
0224     /*
0225      * Determine if the TS pin is enabled and set the TS current-source
0226      * accordingly.
0227      */
0228     ret = regmap_read(info->regmap, AXP20X_ADC_EN1, &adc_enable_val);
0229     if (ret)
0230         return ret;
0231 
0232     if (adc_enable_val & AXP288_ADC_TS_ENABLE) {
0233         info->ts_enabled = true;
0234         ret = regmap_update_bits(info->regmap, AXP288_ADC_TS_PIN_CTRL,
0235                      AXP288_ADC_TS_CURRENT_ON_OFF_MASK,
0236                      AXP288_ADC_TS_CURRENT_ON);
0237     } else {
0238         info->ts_enabled = false;
0239         ret = regmap_update_bits(info->regmap, AXP288_ADC_TS_PIN_CTRL,
0240                      AXP288_ADC_TS_CURRENT_ON_OFF_MASK,
0241                      AXP288_ADC_TS_CURRENT_OFF);
0242     }
0243     if (ret)
0244         return ret;
0245 
0246     /* Turn on the ADC for all channels except TS, leave TS as is */
0247     return regmap_update_bits(info->regmap, AXP20X_ADC_EN1,
0248                   AXP288_ADC_EN_MASK, AXP288_ADC_EN_MASK);
0249 }
0250 
0251 static const struct iio_info axp288_adc_iio_info = {
0252     .read_raw = &axp288_adc_read_raw,
0253 };
0254 
0255 static int axp288_adc_probe(struct platform_device *pdev)
0256 {
0257     int ret;
0258     struct axp288_adc_info *info;
0259     struct iio_dev *indio_dev;
0260     struct axp20x_dev *axp20x = dev_get_drvdata(pdev->dev.parent);
0261 
0262     indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*info));
0263     if (!indio_dev)
0264         return -ENOMEM;
0265 
0266     info = iio_priv(indio_dev);
0267     info->irq = platform_get_irq(pdev, 0);
0268     if (info->irq < 0)
0269         return info->irq;
0270 
0271     info->regmap = axp20x->regmap;
0272     /*
0273      * Set ADC to enabled state at all time, including system suspend.
0274      * otherwise internal fuel gauge functionality may be affected.
0275      */
0276     ret = axp288_adc_initialize(info);
0277     if (ret) {
0278         dev_err(&pdev->dev, "unable to enable ADC device\n");
0279         return ret;
0280     }
0281 
0282     indio_dev->name = pdev->name;
0283     indio_dev->channels = axp288_adc_channels;
0284     indio_dev->num_channels = ARRAY_SIZE(axp288_adc_channels);
0285     indio_dev->info = &axp288_adc_iio_info;
0286     indio_dev->modes = INDIO_DIRECT_MODE;
0287 
0288     ret = devm_iio_map_array_register(&pdev->dev, indio_dev, axp288_adc_default_maps);
0289     if (ret < 0)
0290         return ret;
0291 
0292     return devm_iio_device_register(&pdev->dev, indio_dev);
0293 }
0294 
0295 static const struct platform_device_id axp288_adc_id_table[] = {
0296     { .name = "axp288_adc" },
0297     {},
0298 };
0299 
0300 static struct platform_driver axp288_adc_driver = {
0301     .probe = axp288_adc_probe,
0302     .id_table = axp288_adc_id_table,
0303     .driver = {
0304         .name = "axp288_adc",
0305     },
0306 };
0307 
0308 MODULE_DEVICE_TABLE(platform, axp288_adc_id_table);
0309 
0310 module_platform_driver(axp288_adc_driver);
0311 
0312 MODULE_AUTHOR("Jacob Pan <jacob.jun.pan@linux.intel.com>");
0313 MODULE_DESCRIPTION("X-Powers AXP288 ADC Driver");
0314 MODULE_LICENSE("GPL");