linux/drivers/hwmon/da9052-hwmon.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-or-later
   2/*
   3 * HWMON Driver for Dialog DA9052
   4 *
   5 * Copyright(c) 2012 Dialog Semiconductor Ltd.
   6 *
   7 * Author: David Dajun Chen <dchen@diasemi.com>
   8 */
   9
  10#include <linux/err.h>
  11#include <linux/hwmon.h>
  12#include <linux/hwmon-sysfs.h>
  13#include <linux/init.h>
  14#include <linux/kernel.h>
  15#include <linux/module.h>
  16#include <linux/slab.h>
  17#include <linux/platform_device.h>
  18#include <linux/property.h>
  19
  20#include <linux/mfd/da9052/da9052.h>
  21#include <linux/mfd/da9052/reg.h>
  22#include <linux/regulator/consumer.h>
  23
  24struct da9052_hwmon {
  25        struct da9052           *da9052;
  26        struct mutex            hwmon_lock;
  27        bool                    tsi_as_adc;
  28        int                     tsiref_mv;
  29        struct regulator        *tsiref;
  30        struct completion       tsidone;
  31};
  32
  33static const char * const input_names[] = {
  34        [DA9052_ADC_VDDOUT]     =       "VDDOUT",
  35        [DA9052_ADC_ICH]        =       "CHARGING CURRENT",
  36        [DA9052_ADC_TBAT]       =       "BATTERY TEMP",
  37        [DA9052_ADC_VBAT]       =       "BATTERY VOLTAGE",
  38        [DA9052_ADC_IN4]        =       "ADC IN4",
  39        [DA9052_ADC_IN5]        =       "ADC IN5",
  40        [DA9052_ADC_IN6]        =       "ADC IN6",
  41        [DA9052_ADC_TSI_XP]     =       "ADC TS X+",
  42        [DA9052_ADC_TSI_YP]     =       "ADC TS Y+",
  43        [DA9052_ADC_TSI_XN]     =       "ADC TS X-",
  44        [DA9052_ADC_TSI_YN]     =       "ADC TS Y-",
  45        [DA9052_ADC_TJUNC]      =       "BATTERY JUNCTION TEMP",
  46        [DA9052_ADC_VBBAT]      =       "BACK-UP BATTERY VOLTAGE",
  47};
  48
  49/* Conversion function for VDDOUT and VBAT */
  50static inline int volt_reg_to_mv(int value)
  51{
  52        return DIV_ROUND_CLOSEST(value * 2000, 1023) + 2500;
  53}
  54
  55/* Conversion function for ADC channels 4, 5 and 6 */
  56static inline int input_reg_to_mv(int value)
  57{
  58        return DIV_ROUND_CLOSEST(value * 2500, 1023);
  59}
  60
  61/* Conversion function for VBBAT */
  62static inline int vbbat_reg_to_mv(int value)
  63{
  64        return DIV_ROUND_CLOSEST(value * 5000, 1023);
  65}
  66
  67static inline int input_tsireg_to_mv(struct da9052_hwmon *hwmon, int value)
  68{
  69        return DIV_ROUND_CLOSEST(value * hwmon->tsiref_mv, 1023);
  70}
  71
  72static inline int da9052_enable_vddout_channel(struct da9052 *da9052)
  73{
  74        return da9052_reg_update(da9052, DA9052_ADC_CONT_REG,
  75                                 DA9052_ADCCONT_AUTOVDDEN,
  76                                 DA9052_ADCCONT_AUTOVDDEN);
  77}
  78
  79static inline int da9052_disable_vddout_channel(struct da9052 *da9052)
  80{
  81        return da9052_reg_update(da9052, DA9052_ADC_CONT_REG,
  82                                 DA9052_ADCCONT_AUTOVDDEN, 0);
  83}
  84
  85static ssize_t da9052_vddout_show(struct device *dev,
  86                                  struct device_attribute *devattr, char *buf)
  87{
  88        struct da9052_hwmon *hwmon = dev_get_drvdata(dev);
  89        int ret, vdd;
  90
  91        mutex_lock(&hwmon->hwmon_lock);
  92
  93        ret = da9052_enable_vddout_channel(hwmon->da9052);
  94        if (ret < 0)
  95                goto hwmon_err;
  96
  97        vdd = da9052_reg_read(hwmon->da9052, DA9052_VDD_RES_REG);
  98        if (vdd < 0) {
  99                ret = vdd;
 100                goto hwmon_err_release;
 101        }
 102
 103        ret = da9052_disable_vddout_channel(hwmon->da9052);
 104        if (ret < 0)
 105                goto hwmon_err;
 106
 107        mutex_unlock(&hwmon->hwmon_lock);
 108        return sprintf(buf, "%d\n", volt_reg_to_mv(vdd));
 109
 110hwmon_err_release:
 111        da9052_disable_vddout_channel(hwmon->da9052);
 112hwmon_err:
 113        mutex_unlock(&hwmon->hwmon_lock);
 114        return ret;
 115}
 116
 117static ssize_t da9052_ich_show(struct device *dev,
 118                               struct device_attribute *devattr, char *buf)
 119{
 120        struct da9052_hwmon *hwmon = dev_get_drvdata(dev);
 121        int ret;
 122
 123        ret = da9052_reg_read(hwmon->da9052, DA9052_ICHG_AV_REG);
 124        if (ret < 0)
 125                return ret;
 126
 127        /* Equivalent to 3.9mA/bit in register ICHG_AV */
 128        return sprintf(buf, "%d\n", DIV_ROUND_CLOSEST(ret * 39, 10));
 129}
 130
 131static ssize_t da9052_tbat_show(struct device *dev,
 132                                struct device_attribute *devattr, char *buf)
 133{
 134        struct da9052_hwmon *hwmon = dev_get_drvdata(dev);
 135
 136        return sprintf(buf, "%d\n", da9052_adc_read_temp(hwmon->da9052));
 137}
 138
 139static ssize_t da9052_vbat_show(struct device *dev,
 140                                struct device_attribute *devattr, char *buf)
 141{
 142        struct da9052_hwmon *hwmon = dev_get_drvdata(dev);
 143        int ret;
 144
 145        ret = da9052_adc_manual_read(hwmon->da9052, DA9052_ADC_VBAT);
 146        if (ret < 0)
 147                return ret;
 148
 149        return sprintf(buf, "%d\n", volt_reg_to_mv(ret));
 150}
 151
 152static ssize_t da9052_misc_channel_show(struct device *dev,
 153                                        struct device_attribute *devattr,
 154                                        char *buf)
 155{
 156        struct da9052_hwmon *hwmon = dev_get_drvdata(dev);
 157        int channel = to_sensor_dev_attr(devattr)->index;
 158        int ret;
 159
 160        ret = da9052_adc_manual_read(hwmon->da9052, channel);
 161        if (ret < 0)
 162                return ret;
 163
 164        return sprintf(buf, "%d\n", input_reg_to_mv(ret));
 165}
 166
 167static int da9052_request_tsi_read(struct da9052_hwmon *hwmon, int channel)
 168{
 169        u8 val = DA9052_TSICONTB_TSIMAN;
 170
 171        switch (channel) {
 172        case DA9052_ADC_TSI_XP:
 173                val |= DA9052_TSICONTB_TSIMUX_XP;
 174                break;
 175        case DA9052_ADC_TSI_YP:
 176                val |= DA9052_TSICONTB_TSIMUX_YP;
 177                break;
 178        case DA9052_ADC_TSI_XN:
 179                val |= DA9052_TSICONTB_TSIMUX_XN;
 180                break;
 181        case DA9052_ADC_TSI_YN:
 182                val |= DA9052_TSICONTB_TSIMUX_YN;
 183                break;
 184        }
 185
 186        return da9052_reg_write(hwmon->da9052, DA9052_TSI_CONT_B_REG, val);
 187}
 188
 189static int da9052_get_tsi_result(struct da9052_hwmon *hwmon, int channel)
 190{
 191        u8 regs[3];
 192        int msb, lsb, err;
 193
 194        /* block read to avoid separation of MSB and LSB */
 195        err = da9052_group_read(hwmon->da9052, DA9052_TSI_X_MSB_REG,
 196                                ARRAY_SIZE(regs), regs);
 197        if (err)
 198                return err;
 199
 200        switch (channel) {
 201        case DA9052_ADC_TSI_XP:
 202        case DA9052_ADC_TSI_XN:
 203                msb = regs[0] << DA9052_TSILSB_TSIXL_BITS;
 204                lsb = regs[2] & DA9052_TSILSB_TSIXL;
 205                lsb >>= DA9052_TSILSB_TSIXL_SHIFT;
 206                break;
 207        case DA9052_ADC_TSI_YP:
 208        case DA9052_ADC_TSI_YN:
 209                msb = regs[1] << DA9052_TSILSB_TSIYL_BITS;
 210                lsb = regs[2] & DA9052_TSILSB_TSIYL;
 211                lsb >>= DA9052_TSILSB_TSIYL_SHIFT;
 212                break;
 213        default:
 214                return -EINVAL;
 215        }
 216
 217        return msb | lsb;
 218}
 219
 220
 221static ssize_t __da9052_read_tsi(struct device *dev, int channel)
 222{
 223        struct da9052_hwmon *hwmon = dev_get_drvdata(dev);
 224        int ret;
 225
 226        reinit_completion(&hwmon->tsidone);
 227
 228        ret = da9052_request_tsi_read(hwmon, channel);
 229        if (ret < 0)
 230                return ret;
 231
 232        /* Wait for an conversion done interrupt */
 233        if (!wait_for_completion_timeout(&hwmon->tsidone,
 234                                         msecs_to_jiffies(500)))
 235                return -ETIMEDOUT;
 236
 237        return da9052_get_tsi_result(hwmon, channel);
 238}
 239
 240static ssize_t da9052_tsi_show(struct device *dev,
 241                               struct device_attribute *devattr, char *buf)
 242{
 243        struct da9052_hwmon *hwmon = dev_get_drvdata(dev);
 244        int channel = to_sensor_dev_attr(devattr)->index;
 245        int ret;
 246
 247        mutex_lock(&hwmon->hwmon_lock);
 248        ret = __da9052_read_tsi(dev, channel);
 249        mutex_unlock(&hwmon->hwmon_lock);
 250
 251        if (ret < 0)
 252                return ret;
 253        else
 254                return sprintf(buf, "%d\n", input_tsireg_to_mv(hwmon, ret));
 255}
 256
 257static ssize_t da9052_tjunc_show(struct device *dev,
 258                                 struct device_attribute *devattr, char *buf)
 259{
 260        struct da9052_hwmon *hwmon = dev_get_drvdata(dev);
 261        int tjunc;
 262        int toffset;
 263
 264        tjunc = da9052_reg_read(hwmon->da9052, DA9052_TJUNC_RES_REG);
 265        if (tjunc < 0)
 266                return tjunc;
 267
 268        toffset = da9052_reg_read(hwmon->da9052, DA9052_T_OFFSET_REG);
 269        if (toffset < 0)
 270                return toffset;
 271
 272        /*
 273         * Degrees celsius = 1.708 * (TJUNC_RES - T_OFFSET) - 108.8
 274         * T_OFFSET is a trim value used to improve accuracy of the result
 275         */
 276        return sprintf(buf, "%d\n", 1708 * (tjunc - toffset) - 108800);
 277}
 278
 279static ssize_t da9052_vbbat_show(struct device *dev,
 280                                 struct device_attribute *devattr, char *buf)
 281{
 282        struct da9052_hwmon *hwmon = dev_get_drvdata(dev);
 283        int ret;
 284
 285        ret = da9052_adc_manual_read(hwmon->da9052, DA9052_ADC_VBBAT);
 286        if (ret < 0)
 287                return ret;
 288
 289        return sprintf(buf, "%d\n", vbbat_reg_to_mv(ret));
 290}
 291
 292static ssize_t label_show(struct device *dev,
 293                          struct device_attribute *devattr, char *buf)
 294{
 295        return sprintf(buf, "%s\n",
 296                       input_names[to_sensor_dev_attr(devattr)->index]);
 297}
 298
 299static umode_t da9052_channel_is_visible(struct kobject *kobj,
 300                                         struct attribute *attr, int index)
 301{
 302        struct device *dev = container_of(kobj, struct device, kobj);
 303        struct da9052_hwmon *hwmon = dev_get_drvdata(dev);
 304        struct device_attribute *dattr = container_of(attr,
 305                                struct device_attribute, attr);
 306        struct sensor_device_attribute *sattr = to_sensor_dev_attr(dattr);
 307
 308        if (!hwmon->tsi_as_adc) {
 309                switch (sattr->index) {
 310                case DA9052_ADC_TSI_XP:
 311                case DA9052_ADC_TSI_YP:
 312                case DA9052_ADC_TSI_XN:
 313                case DA9052_ADC_TSI_YN:
 314                        return 0;
 315                }
 316        }
 317
 318        return attr->mode;
 319}
 320
 321static SENSOR_DEVICE_ATTR_RO(in0_input, da9052_vddout, DA9052_ADC_VDDOUT);
 322static SENSOR_DEVICE_ATTR_RO(in0_label, label, DA9052_ADC_VDDOUT);
 323static SENSOR_DEVICE_ATTR_RO(in3_input, da9052_vbat, DA9052_ADC_VBAT);
 324static SENSOR_DEVICE_ATTR_RO(in3_label, label, DA9052_ADC_VBAT);
 325static SENSOR_DEVICE_ATTR_RO(in4_input, da9052_misc_channel, DA9052_ADC_IN4);
 326static SENSOR_DEVICE_ATTR_RO(in4_label, label, DA9052_ADC_IN4);
 327static SENSOR_DEVICE_ATTR_RO(in5_input, da9052_misc_channel, DA9052_ADC_IN5);
 328static SENSOR_DEVICE_ATTR_RO(in5_label, label, DA9052_ADC_IN5);
 329static SENSOR_DEVICE_ATTR_RO(in6_input, da9052_misc_channel, DA9052_ADC_IN6);
 330static SENSOR_DEVICE_ATTR_RO(in6_label, label, DA9052_ADC_IN6);
 331static SENSOR_DEVICE_ATTR_RO(in9_input, da9052_vbbat, DA9052_ADC_VBBAT);
 332static SENSOR_DEVICE_ATTR_RO(in9_label, label, DA9052_ADC_VBBAT);
 333
 334static SENSOR_DEVICE_ATTR_RO(in70_input, da9052_tsi, DA9052_ADC_TSI_XP);
 335static SENSOR_DEVICE_ATTR_RO(in70_label, label, DA9052_ADC_TSI_XP);
 336static SENSOR_DEVICE_ATTR_RO(in71_input, da9052_tsi, DA9052_ADC_TSI_XN);
 337static SENSOR_DEVICE_ATTR_RO(in71_label, label, DA9052_ADC_TSI_XN);
 338static SENSOR_DEVICE_ATTR_RO(in72_input, da9052_tsi, DA9052_ADC_TSI_YP);
 339static SENSOR_DEVICE_ATTR_RO(in72_label, label, DA9052_ADC_TSI_YP);
 340static SENSOR_DEVICE_ATTR_RO(in73_input, da9052_tsi, DA9052_ADC_TSI_YN);
 341static SENSOR_DEVICE_ATTR_RO(in73_label, label, DA9052_ADC_TSI_YN);
 342
 343static SENSOR_DEVICE_ATTR_RO(curr1_input, da9052_ich, DA9052_ADC_ICH);
 344static SENSOR_DEVICE_ATTR_RO(curr1_label, label, DA9052_ADC_ICH);
 345
 346static SENSOR_DEVICE_ATTR_RO(temp2_input, da9052_tbat, DA9052_ADC_TBAT);
 347static SENSOR_DEVICE_ATTR_RO(temp2_label, label, DA9052_ADC_TBAT);
 348static SENSOR_DEVICE_ATTR_RO(temp8_input, da9052_tjunc, DA9052_ADC_TJUNC);
 349static SENSOR_DEVICE_ATTR_RO(temp8_label, label, DA9052_ADC_TJUNC);
 350
 351static struct attribute *da9052_attrs[] = {
 352        &sensor_dev_attr_in0_input.dev_attr.attr,
 353        &sensor_dev_attr_in0_label.dev_attr.attr,
 354        &sensor_dev_attr_in3_input.dev_attr.attr,
 355        &sensor_dev_attr_in3_label.dev_attr.attr,
 356        &sensor_dev_attr_in4_input.dev_attr.attr,
 357        &sensor_dev_attr_in4_label.dev_attr.attr,
 358        &sensor_dev_attr_in5_input.dev_attr.attr,
 359        &sensor_dev_attr_in5_label.dev_attr.attr,
 360        &sensor_dev_attr_in6_input.dev_attr.attr,
 361        &sensor_dev_attr_in6_label.dev_attr.attr,
 362        &sensor_dev_attr_in70_input.dev_attr.attr,
 363        &sensor_dev_attr_in70_label.dev_attr.attr,
 364        &sensor_dev_attr_in71_input.dev_attr.attr,
 365        &sensor_dev_attr_in71_label.dev_attr.attr,
 366        &sensor_dev_attr_in72_input.dev_attr.attr,
 367        &sensor_dev_attr_in72_label.dev_attr.attr,
 368        &sensor_dev_attr_in73_input.dev_attr.attr,
 369        &sensor_dev_attr_in73_label.dev_attr.attr,
 370        &sensor_dev_attr_in9_input.dev_attr.attr,
 371        &sensor_dev_attr_in9_label.dev_attr.attr,
 372        &sensor_dev_attr_curr1_input.dev_attr.attr,
 373        &sensor_dev_attr_curr1_label.dev_attr.attr,
 374        &sensor_dev_attr_temp2_input.dev_attr.attr,
 375        &sensor_dev_attr_temp2_label.dev_attr.attr,
 376        &sensor_dev_attr_temp8_input.dev_attr.attr,
 377        &sensor_dev_attr_temp8_label.dev_attr.attr,
 378        NULL
 379};
 380
 381static const struct attribute_group da9052_group = {
 382        .attrs = da9052_attrs,
 383        .is_visible = da9052_channel_is_visible,
 384};
 385__ATTRIBUTE_GROUPS(da9052);
 386
 387static irqreturn_t da9052_tsi_datardy_irq(int irq, void *data)
 388{
 389        struct da9052_hwmon *hwmon = data;
 390
 391        complete(&hwmon->tsidone);
 392        return IRQ_HANDLED;
 393}
 394
 395static int da9052_hwmon_probe(struct platform_device *pdev)
 396{
 397        struct device *dev = &pdev->dev;
 398        struct da9052_hwmon *hwmon;
 399        struct device *hwmon_dev;
 400        int err;
 401
 402        hwmon = devm_kzalloc(dev, sizeof(struct da9052_hwmon), GFP_KERNEL);
 403        if (!hwmon)
 404                return -ENOMEM;
 405
 406        platform_set_drvdata(pdev, hwmon);
 407
 408        mutex_init(&hwmon->hwmon_lock);
 409        hwmon->da9052 = dev_get_drvdata(pdev->dev.parent);
 410
 411        init_completion(&hwmon->tsidone);
 412
 413        hwmon->tsi_as_adc =
 414                device_property_read_bool(pdev->dev.parent, "dlg,tsi-as-adc");
 415
 416        if (hwmon->tsi_as_adc) {
 417                hwmon->tsiref = devm_regulator_get(pdev->dev.parent, "tsiref");
 418                if (IS_ERR(hwmon->tsiref)) {
 419                        err = PTR_ERR(hwmon->tsiref);
 420                        dev_err(&pdev->dev, "failed to get tsiref: %d", err);
 421                        return err;
 422                }
 423
 424                err = regulator_enable(hwmon->tsiref);
 425                if (err)
 426                        return err;
 427
 428                hwmon->tsiref_mv = regulator_get_voltage(hwmon->tsiref);
 429                if (hwmon->tsiref_mv < 0) {
 430                        err = hwmon->tsiref_mv;
 431                        goto exit_regulator;
 432                }
 433
 434                /* convert from microvolt (DT) to millivolt (hwmon) */
 435                hwmon->tsiref_mv /= 1000;
 436
 437                /* TSIREF limits from datasheet */
 438                if (hwmon->tsiref_mv < 1800 || hwmon->tsiref_mv > 2600) {
 439                        dev_err(hwmon->da9052->dev, "invalid TSIREF voltage: %d",
 440                                hwmon->tsiref_mv);
 441                        err = -ENXIO;
 442                        goto exit_regulator;
 443                }
 444
 445                /* disable touchscreen features */
 446                da9052_reg_write(hwmon->da9052, DA9052_TSI_CONT_A_REG, 0x00);
 447
 448                /* Sample every 1ms */
 449                da9052_reg_update(hwmon->da9052, DA9052_ADC_CONT_REG,
 450                                          DA9052_ADCCONT_ADCMODE,
 451                                          DA9052_ADCCONT_ADCMODE);
 452
 453                err = da9052_request_irq(hwmon->da9052, DA9052_IRQ_TSIREADY,
 454                                         "tsiready-irq", da9052_tsi_datardy_irq,
 455                                         hwmon);
 456                if (err) {
 457                        dev_err(&pdev->dev, "Failed to register TSIRDY IRQ: %d",
 458                                err);
 459                        goto exit_regulator;
 460                }
 461        }
 462
 463        hwmon_dev = devm_hwmon_device_register_with_groups(dev, "da9052",
 464                                                           hwmon,
 465                                                           da9052_groups);
 466        err = PTR_ERR_OR_ZERO(hwmon_dev);
 467        if (err)
 468                goto exit_irq;
 469
 470        return 0;
 471
 472exit_irq:
 473        if (hwmon->tsi_as_adc)
 474                da9052_free_irq(hwmon->da9052, DA9052_IRQ_TSIREADY, hwmon);
 475exit_regulator:
 476        if (hwmon->tsiref)
 477                regulator_disable(hwmon->tsiref);
 478
 479        return err;
 480}
 481
 482static int da9052_hwmon_remove(struct platform_device *pdev)
 483{
 484        struct da9052_hwmon *hwmon = platform_get_drvdata(pdev);
 485
 486        if (hwmon->tsi_as_adc) {
 487                da9052_free_irq(hwmon->da9052, DA9052_IRQ_TSIREADY, hwmon);
 488                regulator_disable(hwmon->tsiref);
 489        }
 490
 491        return 0;
 492}
 493
 494static struct platform_driver da9052_hwmon_driver = {
 495        .probe = da9052_hwmon_probe,
 496        .remove = da9052_hwmon_remove,
 497        .driver = {
 498                .name = "da9052-hwmon",
 499        },
 500};
 501
 502module_platform_driver(da9052_hwmon_driver);
 503
 504MODULE_AUTHOR("David Dajun Chen <dchen@diasemi.com>");
 505MODULE_DESCRIPTION("DA9052 HWMON driver");
 506MODULE_LICENSE("GPL");
 507MODULE_ALIAS("platform:da9052-hwmon");
 508