Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  * HWMON Driver for Dialog DA9052
0004  *
0005  * Copyright(c) 2012 Dialog Semiconductor Ltd.
0006  *
0007  * Author: David Dajun Chen <dchen@diasemi.com>
0008  */
0009 
0010 #include <linux/err.h>
0011 #include <linux/hwmon.h>
0012 #include <linux/hwmon-sysfs.h>
0013 #include <linux/init.h>
0014 #include <linux/kernel.h>
0015 #include <linux/module.h>
0016 #include <linux/slab.h>
0017 #include <linux/platform_device.h>
0018 #include <linux/property.h>
0019 
0020 #include <linux/mfd/da9052/da9052.h>
0021 #include <linux/mfd/da9052/reg.h>
0022 #include <linux/regulator/consumer.h>
0023 
0024 struct da9052_hwmon {
0025     struct da9052       *da9052;
0026     struct mutex        hwmon_lock;
0027     bool            tsi_as_adc;
0028     int         tsiref_mv;
0029     struct regulator    *tsiref;
0030     struct completion   tsidone;
0031 };
0032 
0033 static const char * const input_names[] = {
0034     [DA9052_ADC_VDDOUT] =   "VDDOUT",
0035     [DA9052_ADC_ICH]    =   "CHARGING CURRENT",
0036     [DA9052_ADC_TBAT]   =   "BATTERY TEMP",
0037     [DA9052_ADC_VBAT]   =   "BATTERY VOLTAGE",
0038     [DA9052_ADC_IN4]    =   "ADC IN4",
0039     [DA9052_ADC_IN5]    =   "ADC IN5",
0040     [DA9052_ADC_IN6]    =   "ADC IN6",
0041     [DA9052_ADC_TSI_XP] =   "ADC TS X+",
0042     [DA9052_ADC_TSI_YP] =   "ADC TS Y+",
0043     [DA9052_ADC_TSI_XN] =   "ADC TS X-",
0044     [DA9052_ADC_TSI_YN] =   "ADC TS Y-",
0045     [DA9052_ADC_TJUNC]  =   "BATTERY JUNCTION TEMP",
0046     [DA9052_ADC_VBBAT]  =   "BACK-UP BATTERY VOLTAGE",
0047 };
0048 
0049 /* Conversion function for VDDOUT and VBAT */
0050 static inline int volt_reg_to_mv(int value)
0051 {
0052     return DIV_ROUND_CLOSEST(value * 2000, 1023) + 2500;
0053 }
0054 
0055 /* Conversion function for ADC channels 4, 5 and 6 */
0056 static inline int input_reg_to_mv(int value)
0057 {
0058     return DIV_ROUND_CLOSEST(value * 2500, 1023);
0059 }
0060 
0061 /* Conversion function for VBBAT */
0062 static inline int vbbat_reg_to_mv(int value)
0063 {
0064     return DIV_ROUND_CLOSEST(value * 5000, 1023);
0065 }
0066 
0067 static inline int input_tsireg_to_mv(struct da9052_hwmon *hwmon, int value)
0068 {
0069     return DIV_ROUND_CLOSEST(value * hwmon->tsiref_mv, 1023);
0070 }
0071 
0072 static inline int da9052_enable_vddout_channel(struct da9052 *da9052)
0073 {
0074     return da9052_reg_update(da9052, DA9052_ADC_CONT_REG,
0075                  DA9052_ADCCONT_AUTOVDDEN,
0076                  DA9052_ADCCONT_AUTOVDDEN);
0077 }
0078 
0079 static inline int da9052_disable_vddout_channel(struct da9052 *da9052)
0080 {
0081     return da9052_reg_update(da9052, DA9052_ADC_CONT_REG,
0082                  DA9052_ADCCONT_AUTOVDDEN, 0);
0083 }
0084 
0085 static ssize_t da9052_vddout_show(struct device *dev,
0086                   struct device_attribute *devattr, char *buf)
0087 {
0088     struct da9052_hwmon *hwmon = dev_get_drvdata(dev);
0089     int ret, vdd;
0090 
0091     mutex_lock(&hwmon->hwmon_lock);
0092 
0093     ret = da9052_enable_vddout_channel(hwmon->da9052);
0094     if (ret < 0)
0095         goto hwmon_err;
0096 
0097     vdd = da9052_reg_read(hwmon->da9052, DA9052_VDD_RES_REG);
0098     if (vdd < 0) {
0099         ret = vdd;
0100         goto hwmon_err_release;
0101     }
0102 
0103     ret = da9052_disable_vddout_channel(hwmon->da9052);
0104     if (ret < 0)
0105         goto hwmon_err;
0106 
0107     mutex_unlock(&hwmon->hwmon_lock);
0108     return sprintf(buf, "%d\n", volt_reg_to_mv(vdd));
0109 
0110 hwmon_err_release:
0111     da9052_disable_vddout_channel(hwmon->da9052);
0112 hwmon_err:
0113     mutex_unlock(&hwmon->hwmon_lock);
0114     return ret;
0115 }
0116 
0117 static ssize_t da9052_ich_show(struct device *dev,
0118                    struct device_attribute *devattr, char *buf)
0119 {
0120     struct da9052_hwmon *hwmon = dev_get_drvdata(dev);
0121     int ret;
0122 
0123     ret = da9052_reg_read(hwmon->da9052, DA9052_ICHG_AV_REG);
0124     if (ret < 0)
0125         return ret;
0126 
0127     /* Equivalent to 3.9mA/bit in register ICHG_AV */
0128     return sprintf(buf, "%d\n", DIV_ROUND_CLOSEST(ret * 39, 10));
0129 }
0130 
0131 static ssize_t da9052_tbat_show(struct device *dev,
0132                 struct device_attribute *devattr, char *buf)
0133 {
0134     struct da9052_hwmon *hwmon = dev_get_drvdata(dev);
0135 
0136     return sprintf(buf, "%d\n", da9052_adc_read_temp(hwmon->da9052));
0137 }
0138 
0139 static ssize_t da9052_vbat_show(struct device *dev,
0140                 struct device_attribute *devattr, char *buf)
0141 {
0142     struct da9052_hwmon *hwmon = dev_get_drvdata(dev);
0143     int ret;
0144 
0145     ret = da9052_adc_manual_read(hwmon->da9052, DA9052_ADC_VBAT);
0146     if (ret < 0)
0147         return ret;
0148 
0149     return sprintf(buf, "%d\n", volt_reg_to_mv(ret));
0150 }
0151 
0152 static ssize_t da9052_misc_channel_show(struct device *dev,
0153                     struct device_attribute *devattr,
0154                     char *buf)
0155 {
0156     struct da9052_hwmon *hwmon = dev_get_drvdata(dev);
0157     int channel = to_sensor_dev_attr(devattr)->index;
0158     int ret;
0159 
0160     ret = da9052_adc_manual_read(hwmon->da9052, channel);
0161     if (ret < 0)
0162         return ret;
0163 
0164     return sprintf(buf, "%d\n", input_reg_to_mv(ret));
0165 }
0166 
0167 static int da9052_request_tsi_read(struct da9052_hwmon *hwmon, int channel)
0168 {
0169     u8 val = DA9052_TSICONTB_TSIMAN;
0170 
0171     switch (channel) {
0172     case DA9052_ADC_TSI_XP:
0173         val |= DA9052_TSICONTB_TSIMUX_XP;
0174         break;
0175     case DA9052_ADC_TSI_YP:
0176         val |= DA9052_TSICONTB_TSIMUX_YP;
0177         break;
0178     case DA9052_ADC_TSI_XN:
0179         val |= DA9052_TSICONTB_TSIMUX_XN;
0180         break;
0181     case DA9052_ADC_TSI_YN:
0182         val |= DA9052_TSICONTB_TSIMUX_YN;
0183         break;
0184     }
0185 
0186     return da9052_reg_write(hwmon->da9052, DA9052_TSI_CONT_B_REG, val);
0187 }
0188 
0189 static int da9052_get_tsi_result(struct da9052_hwmon *hwmon, int channel)
0190 {
0191     u8 regs[3];
0192     int msb, lsb, err;
0193 
0194     /* block read to avoid separation of MSB and LSB */
0195     err = da9052_group_read(hwmon->da9052, DA9052_TSI_X_MSB_REG,
0196                 ARRAY_SIZE(regs), regs);
0197     if (err)
0198         return err;
0199 
0200     switch (channel) {
0201     case DA9052_ADC_TSI_XP:
0202     case DA9052_ADC_TSI_XN:
0203         msb = regs[0] << DA9052_TSILSB_TSIXL_BITS;
0204         lsb = regs[2] & DA9052_TSILSB_TSIXL;
0205         lsb >>= DA9052_TSILSB_TSIXL_SHIFT;
0206         break;
0207     case DA9052_ADC_TSI_YP:
0208     case DA9052_ADC_TSI_YN:
0209         msb = regs[1] << DA9052_TSILSB_TSIYL_BITS;
0210         lsb = regs[2] & DA9052_TSILSB_TSIYL;
0211         lsb >>= DA9052_TSILSB_TSIYL_SHIFT;
0212         break;
0213     default:
0214         return -EINVAL;
0215     }
0216 
0217     return msb | lsb;
0218 }
0219 
0220 
0221 static ssize_t __da9052_read_tsi(struct device *dev, int channel)
0222 {
0223     struct da9052_hwmon *hwmon = dev_get_drvdata(dev);
0224     int ret;
0225 
0226     reinit_completion(&hwmon->tsidone);
0227 
0228     ret = da9052_request_tsi_read(hwmon, channel);
0229     if (ret < 0)
0230         return ret;
0231 
0232     /* Wait for an conversion done interrupt */
0233     if (!wait_for_completion_timeout(&hwmon->tsidone,
0234                      msecs_to_jiffies(500)))
0235         return -ETIMEDOUT;
0236 
0237     return da9052_get_tsi_result(hwmon, channel);
0238 }
0239 
0240 static ssize_t da9052_tsi_show(struct device *dev,
0241                    struct device_attribute *devattr, char *buf)
0242 {
0243     struct da9052_hwmon *hwmon = dev_get_drvdata(dev);
0244     int channel = to_sensor_dev_attr(devattr)->index;
0245     int ret;
0246 
0247     mutex_lock(&hwmon->da9052->auxadc_lock);
0248     ret = __da9052_read_tsi(dev, channel);
0249     mutex_unlock(&hwmon->da9052->auxadc_lock);
0250 
0251     if (ret < 0)
0252         return ret;
0253     else
0254         return sprintf(buf, "%d\n", input_tsireg_to_mv(hwmon, ret));
0255 }
0256 
0257 static ssize_t da9052_tjunc_show(struct device *dev,
0258                  struct device_attribute *devattr, char *buf)
0259 {
0260     struct da9052_hwmon *hwmon = dev_get_drvdata(dev);
0261     int tjunc;
0262     int toffset;
0263 
0264     tjunc = da9052_reg_read(hwmon->da9052, DA9052_TJUNC_RES_REG);
0265     if (tjunc < 0)
0266         return tjunc;
0267 
0268     toffset = da9052_reg_read(hwmon->da9052, DA9052_T_OFFSET_REG);
0269     if (toffset < 0)
0270         return toffset;
0271 
0272     /*
0273      * Degrees celsius = 1.708 * (TJUNC_RES - T_OFFSET) - 108.8
0274      * T_OFFSET is a trim value used to improve accuracy of the result
0275      */
0276     return sprintf(buf, "%d\n", 1708 * (tjunc - toffset) - 108800);
0277 }
0278 
0279 static ssize_t da9052_vbbat_show(struct device *dev,
0280                  struct device_attribute *devattr, char *buf)
0281 {
0282     struct da9052_hwmon *hwmon = dev_get_drvdata(dev);
0283     int ret;
0284 
0285     ret = da9052_adc_manual_read(hwmon->da9052, DA9052_ADC_VBBAT);
0286     if (ret < 0)
0287         return ret;
0288 
0289     return sprintf(buf, "%d\n", vbbat_reg_to_mv(ret));
0290 }
0291 
0292 static ssize_t label_show(struct device *dev,
0293               struct device_attribute *devattr, char *buf)
0294 {
0295     return sprintf(buf, "%s\n",
0296                input_names[to_sensor_dev_attr(devattr)->index]);
0297 }
0298 
0299 static umode_t da9052_channel_is_visible(struct kobject *kobj,
0300                      struct attribute *attr, int index)
0301 {
0302     struct device *dev = kobj_to_dev(kobj);
0303     struct da9052_hwmon *hwmon = dev_get_drvdata(dev);
0304     struct device_attribute *dattr = container_of(attr,
0305                 struct device_attribute, attr);
0306     struct sensor_device_attribute *sattr = to_sensor_dev_attr(dattr);
0307 
0308     if (!hwmon->tsi_as_adc) {
0309         switch (sattr->index) {
0310         case DA9052_ADC_TSI_XP:
0311         case DA9052_ADC_TSI_YP:
0312         case DA9052_ADC_TSI_XN:
0313         case DA9052_ADC_TSI_YN:
0314             return 0;
0315         }
0316     }
0317 
0318     return attr->mode;
0319 }
0320 
0321 static SENSOR_DEVICE_ATTR_RO(in0_input, da9052_vddout, DA9052_ADC_VDDOUT);
0322 static SENSOR_DEVICE_ATTR_RO(in0_label, label, DA9052_ADC_VDDOUT);
0323 static SENSOR_DEVICE_ATTR_RO(in3_input, da9052_vbat, DA9052_ADC_VBAT);
0324 static SENSOR_DEVICE_ATTR_RO(in3_label, label, DA9052_ADC_VBAT);
0325 static SENSOR_DEVICE_ATTR_RO(in4_input, da9052_misc_channel, DA9052_ADC_IN4);
0326 static SENSOR_DEVICE_ATTR_RO(in4_label, label, DA9052_ADC_IN4);
0327 static SENSOR_DEVICE_ATTR_RO(in5_input, da9052_misc_channel, DA9052_ADC_IN5);
0328 static SENSOR_DEVICE_ATTR_RO(in5_label, label, DA9052_ADC_IN5);
0329 static SENSOR_DEVICE_ATTR_RO(in6_input, da9052_misc_channel, DA9052_ADC_IN6);
0330 static SENSOR_DEVICE_ATTR_RO(in6_label, label, DA9052_ADC_IN6);
0331 static SENSOR_DEVICE_ATTR_RO(in9_input, da9052_vbbat, DA9052_ADC_VBBAT);
0332 static SENSOR_DEVICE_ATTR_RO(in9_label, label, DA9052_ADC_VBBAT);
0333 
0334 static SENSOR_DEVICE_ATTR_RO(in70_input, da9052_tsi, DA9052_ADC_TSI_XP);
0335 static SENSOR_DEVICE_ATTR_RO(in70_label, label, DA9052_ADC_TSI_XP);
0336 static SENSOR_DEVICE_ATTR_RO(in71_input, da9052_tsi, DA9052_ADC_TSI_XN);
0337 static SENSOR_DEVICE_ATTR_RO(in71_label, label, DA9052_ADC_TSI_XN);
0338 static SENSOR_DEVICE_ATTR_RO(in72_input, da9052_tsi, DA9052_ADC_TSI_YP);
0339 static SENSOR_DEVICE_ATTR_RO(in72_label, label, DA9052_ADC_TSI_YP);
0340 static SENSOR_DEVICE_ATTR_RO(in73_input, da9052_tsi, DA9052_ADC_TSI_YN);
0341 static SENSOR_DEVICE_ATTR_RO(in73_label, label, DA9052_ADC_TSI_YN);
0342 
0343 static SENSOR_DEVICE_ATTR_RO(curr1_input, da9052_ich, DA9052_ADC_ICH);
0344 static SENSOR_DEVICE_ATTR_RO(curr1_label, label, DA9052_ADC_ICH);
0345 
0346 static SENSOR_DEVICE_ATTR_RO(temp2_input, da9052_tbat, DA9052_ADC_TBAT);
0347 static SENSOR_DEVICE_ATTR_RO(temp2_label, label, DA9052_ADC_TBAT);
0348 static SENSOR_DEVICE_ATTR_RO(temp8_input, da9052_tjunc, DA9052_ADC_TJUNC);
0349 static SENSOR_DEVICE_ATTR_RO(temp8_label, label, DA9052_ADC_TJUNC);
0350 
0351 static struct attribute *da9052_attrs[] = {
0352     &sensor_dev_attr_in0_input.dev_attr.attr,
0353     &sensor_dev_attr_in0_label.dev_attr.attr,
0354     &sensor_dev_attr_in3_input.dev_attr.attr,
0355     &sensor_dev_attr_in3_label.dev_attr.attr,
0356     &sensor_dev_attr_in4_input.dev_attr.attr,
0357     &sensor_dev_attr_in4_label.dev_attr.attr,
0358     &sensor_dev_attr_in5_input.dev_attr.attr,
0359     &sensor_dev_attr_in5_label.dev_attr.attr,
0360     &sensor_dev_attr_in6_input.dev_attr.attr,
0361     &sensor_dev_attr_in6_label.dev_attr.attr,
0362     &sensor_dev_attr_in70_input.dev_attr.attr,
0363     &sensor_dev_attr_in70_label.dev_attr.attr,
0364     &sensor_dev_attr_in71_input.dev_attr.attr,
0365     &sensor_dev_attr_in71_label.dev_attr.attr,
0366     &sensor_dev_attr_in72_input.dev_attr.attr,
0367     &sensor_dev_attr_in72_label.dev_attr.attr,
0368     &sensor_dev_attr_in73_input.dev_attr.attr,
0369     &sensor_dev_attr_in73_label.dev_attr.attr,
0370     &sensor_dev_attr_in9_input.dev_attr.attr,
0371     &sensor_dev_attr_in9_label.dev_attr.attr,
0372     &sensor_dev_attr_curr1_input.dev_attr.attr,
0373     &sensor_dev_attr_curr1_label.dev_attr.attr,
0374     &sensor_dev_attr_temp2_input.dev_attr.attr,
0375     &sensor_dev_attr_temp2_label.dev_attr.attr,
0376     &sensor_dev_attr_temp8_input.dev_attr.attr,
0377     &sensor_dev_attr_temp8_label.dev_attr.attr,
0378     NULL
0379 };
0380 
0381 static const struct attribute_group da9052_group = {
0382     .attrs = da9052_attrs,
0383     .is_visible = da9052_channel_is_visible,
0384 };
0385 __ATTRIBUTE_GROUPS(da9052);
0386 
0387 static irqreturn_t da9052_tsi_datardy_irq(int irq, void *data)
0388 {
0389     struct da9052_hwmon *hwmon = data;
0390 
0391     complete(&hwmon->tsidone);
0392     return IRQ_HANDLED;
0393 }
0394 
0395 static int da9052_hwmon_probe(struct platform_device *pdev)
0396 {
0397     struct device *dev = &pdev->dev;
0398     struct da9052_hwmon *hwmon;
0399     struct device *hwmon_dev;
0400     int err;
0401 
0402     hwmon = devm_kzalloc(dev, sizeof(struct da9052_hwmon), GFP_KERNEL);
0403     if (!hwmon)
0404         return -ENOMEM;
0405 
0406     platform_set_drvdata(pdev, hwmon);
0407 
0408     mutex_init(&hwmon->hwmon_lock);
0409     hwmon->da9052 = dev_get_drvdata(pdev->dev.parent);
0410 
0411     init_completion(&hwmon->tsidone);
0412 
0413     hwmon->tsi_as_adc =
0414         device_property_read_bool(pdev->dev.parent, "dlg,tsi-as-adc");
0415 
0416     if (hwmon->tsi_as_adc) {
0417         hwmon->tsiref = devm_regulator_get(pdev->dev.parent, "tsiref");
0418         if (IS_ERR(hwmon->tsiref)) {
0419             err = PTR_ERR(hwmon->tsiref);
0420             dev_err(&pdev->dev, "failed to get tsiref: %d", err);
0421             return err;
0422         }
0423 
0424         err = regulator_enable(hwmon->tsiref);
0425         if (err)
0426             return err;
0427 
0428         hwmon->tsiref_mv = regulator_get_voltage(hwmon->tsiref);
0429         if (hwmon->tsiref_mv < 0) {
0430             err = hwmon->tsiref_mv;
0431             goto exit_regulator;
0432         }
0433 
0434         /* convert from microvolt (DT) to millivolt (hwmon) */
0435         hwmon->tsiref_mv /= 1000;
0436 
0437         /* TSIREF limits from datasheet */
0438         if (hwmon->tsiref_mv < 1800 || hwmon->tsiref_mv > 2600) {
0439             dev_err(hwmon->da9052->dev, "invalid TSIREF voltage: %d",
0440                 hwmon->tsiref_mv);
0441             err = -ENXIO;
0442             goto exit_regulator;
0443         }
0444 
0445         /* disable touchscreen features */
0446         da9052_reg_write(hwmon->da9052, DA9052_TSI_CONT_A_REG, 0x00);
0447 
0448         /* Sample every 1ms */
0449         da9052_reg_update(hwmon->da9052, DA9052_ADC_CONT_REG,
0450                       DA9052_ADCCONT_ADCMODE,
0451                       DA9052_ADCCONT_ADCMODE);
0452 
0453         err = da9052_request_irq(hwmon->da9052, DA9052_IRQ_TSIREADY,
0454                      "tsiready-irq", da9052_tsi_datardy_irq,
0455                      hwmon);
0456         if (err) {
0457             dev_err(&pdev->dev, "Failed to register TSIRDY IRQ: %d",
0458                 err);
0459             goto exit_regulator;
0460         }
0461     }
0462 
0463     hwmon_dev = devm_hwmon_device_register_with_groups(dev, "da9052",
0464                                hwmon,
0465                                da9052_groups);
0466     err = PTR_ERR_OR_ZERO(hwmon_dev);
0467     if (err)
0468         goto exit_irq;
0469 
0470     return 0;
0471 
0472 exit_irq:
0473     if (hwmon->tsi_as_adc)
0474         da9052_free_irq(hwmon->da9052, DA9052_IRQ_TSIREADY, hwmon);
0475 exit_regulator:
0476     if (hwmon->tsiref)
0477         regulator_disable(hwmon->tsiref);
0478 
0479     return err;
0480 }
0481 
0482 static int da9052_hwmon_remove(struct platform_device *pdev)
0483 {
0484     struct da9052_hwmon *hwmon = platform_get_drvdata(pdev);
0485 
0486     if (hwmon->tsi_as_adc) {
0487         da9052_free_irq(hwmon->da9052, DA9052_IRQ_TSIREADY, hwmon);
0488         regulator_disable(hwmon->tsiref);
0489     }
0490 
0491     return 0;
0492 }
0493 
0494 static struct platform_driver da9052_hwmon_driver = {
0495     .probe = da9052_hwmon_probe,
0496     .remove = da9052_hwmon_remove,
0497     .driver = {
0498         .name = "da9052-hwmon",
0499     },
0500 };
0501 
0502 module_platform_driver(da9052_hwmon_driver);
0503 
0504 MODULE_AUTHOR("David Dajun Chen <dchen@diasemi.com>");
0505 MODULE_DESCRIPTION("DA9052 HWMON driver");
0506 MODULE_LICENSE("GPL");
0507 MODULE_ALIAS("platform:da9052-hwmon");