0001
0002
0003
0004
0005
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
0024
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
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
0127
0128
0129
0130
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
0138 if (!info->ts_enabled)
0139 return 0;
0140
0141
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
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
0188
0189
0190 static const struct dmi_system_id axp288_adc_ts_bias_override[] = {
0191 {
0192
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
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
0226
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
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
0274
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");