linux/drivers/hwmon/ntc_thermistor.c
<<
>>
Prefs
   1/*
   2 * ntc_thermistor.c - NTC Thermistors
   3 *
   4 *  Copyright (C) 2010 Samsung Electronics
   5 *  MyungJoo Ham <myungjoo.ham@samsung.com>
   6 *
   7 * This program is free software; you can redistribute it and/or modify
   8 * it under the terms of the GNU General Public License as published by
   9 * the Free Software Foundation; either version 2 of the License, or
  10 * (at your option) any later version.
  11 *
  12 * This program is distributed in the hope that it will be useful,
  13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  15 * GNU General Public License for more details.
  16 *
  17 * You should have received a copy of the GNU General Public License
  18 * along with this program; if not, write to the Free Software
  19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  20 *
  21 */
  22
  23#include <linux/slab.h>
  24#include <linux/module.h>
  25#include <linux/pm_runtime.h>
  26#include <linux/math64.h>
  27#include <linux/platform_device.h>
  28#include <linux/err.h>
  29#include <linux/of.h>
  30#include <linux/of_device.h>
  31
  32#include <linux/platform_data/ntc_thermistor.h>
  33
  34#include <linux/iio/iio.h>
  35#include <linux/iio/machine.h>
  36#include <linux/iio/driver.h>
  37#include <linux/iio/consumer.h>
  38
  39#include <linux/hwmon.h>
  40#include <linux/hwmon-sysfs.h>
  41#include <linux/thermal.h>
  42
  43struct ntc_compensation {
  44        int             temp_c;
  45        unsigned int    ohm;
  46};
  47
  48/* Order matters, ntc_match references the entries by index */
  49static const struct platform_device_id ntc_thermistor_id[] = {
  50        { "ncp15wb473", TYPE_NCPXXWB473 },
  51        { "ncp18wb473", TYPE_NCPXXWB473 },
  52        { "ncp21wb473", TYPE_NCPXXWB473 },
  53        { "ncp03wb473", TYPE_NCPXXWB473 },
  54        { "ncp15wl333", TYPE_NCPXXWL333 },
  55        { "b57330v2103", TYPE_B57330V2103},
  56        { "ncp03wf104", TYPE_NCPXXWF104 },
  57        { "ncp15xh103", TYPE_NCPXXXH103 },
  58        { },
  59};
  60
  61/*
  62 * A compensation table should be sorted by the values of .ohm
  63 * in descending order.
  64 * The following compensation tables are from the specification of Murata NTC
  65 * Thermistors Datasheet
  66 */
  67static const struct ntc_compensation ncpXXwb473[] = {
  68        { .temp_c       = -40, .ohm     = 1747920 },
  69        { .temp_c       = -35, .ohm     = 1245428 },
  70        { .temp_c       = -30, .ohm     = 898485 },
  71        { .temp_c       = -25, .ohm     = 655802 },
  72        { .temp_c       = -20, .ohm     = 483954 },
  73        { .temp_c       = -15, .ohm     = 360850 },
  74        { .temp_c       = -10, .ohm     = 271697 },
  75        { .temp_c       = -5, .ohm      = 206463 },
  76        { .temp_c       = 0, .ohm       = 158214 },
  77        { .temp_c       = 5, .ohm       = 122259 },
  78        { .temp_c       = 10, .ohm      = 95227 },
  79        { .temp_c       = 15, .ohm      = 74730 },
  80        { .temp_c       = 20, .ohm      = 59065 },
  81        { .temp_c       = 25, .ohm      = 47000 },
  82        { .temp_c       = 30, .ohm      = 37643 },
  83        { .temp_c       = 35, .ohm      = 30334 },
  84        { .temp_c       = 40, .ohm      = 24591 },
  85        { .temp_c       = 45, .ohm      = 20048 },
  86        { .temp_c       = 50, .ohm      = 16433 },
  87        { .temp_c       = 55, .ohm      = 13539 },
  88        { .temp_c       = 60, .ohm      = 11209 },
  89        { .temp_c       = 65, .ohm      = 9328 },
  90        { .temp_c       = 70, .ohm      = 7798 },
  91        { .temp_c       = 75, .ohm      = 6544 },
  92        { .temp_c       = 80, .ohm      = 5518 },
  93        { .temp_c       = 85, .ohm      = 4674 },
  94        { .temp_c       = 90, .ohm      = 3972 },
  95        { .temp_c       = 95, .ohm      = 3388 },
  96        { .temp_c       = 100, .ohm     = 2902 },
  97        { .temp_c       = 105, .ohm     = 2494 },
  98        { .temp_c       = 110, .ohm     = 2150 },
  99        { .temp_c       = 115, .ohm     = 1860 },
 100        { .temp_c       = 120, .ohm     = 1615 },
 101        { .temp_c       = 125, .ohm     = 1406 },
 102};
 103static const struct ntc_compensation ncpXXwl333[] = {
 104        { .temp_c       = -40, .ohm     = 1610154 },
 105        { .temp_c       = -35, .ohm     = 1130850 },
 106        { .temp_c       = -30, .ohm     = 802609 },
 107        { .temp_c       = -25, .ohm     = 575385 },
 108        { .temp_c       = -20, .ohm     = 416464 },
 109        { .temp_c       = -15, .ohm     = 304219 },
 110        { .temp_c       = -10, .ohm     = 224193 },
 111        { .temp_c       = -5, .ohm      = 166623 },
 112        { .temp_c       = 0, .ohm       = 124850 },
 113        { .temp_c       = 5, .ohm       = 94287 },
 114        { .temp_c       = 10, .ohm      = 71747 },
 115        { .temp_c       = 15, .ohm      = 54996 },
 116        { .temp_c       = 20, .ohm      = 42455 },
 117        { .temp_c       = 25, .ohm      = 33000 },
 118        { .temp_c       = 30, .ohm      = 25822 },
 119        { .temp_c       = 35, .ohm      = 20335 },
 120        { .temp_c       = 40, .ohm      = 16115 },
 121        { .temp_c       = 45, .ohm      = 12849 },
 122        { .temp_c       = 50, .ohm      = 10306 },
 123        { .temp_c       = 55, .ohm      = 8314 },
 124        { .temp_c       = 60, .ohm      = 6746 },
 125        { .temp_c       = 65, .ohm      = 5503 },
 126        { .temp_c       = 70, .ohm      = 4513 },
 127        { .temp_c       = 75, .ohm      = 3721 },
 128        { .temp_c       = 80, .ohm      = 3084 },
 129        { .temp_c       = 85, .ohm      = 2569 },
 130        { .temp_c       = 90, .ohm      = 2151 },
 131        { .temp_c       = 95, .ohm      = 1809 },
 132        { .temp_c       = 100, .ohm     = 1529 },
 133        { .temp_c       = 105, .ohm     = 1299 },
 134        { .temp_c       = 110, .ohm     = 1108 },
 135        { .temp_c       = 115, .ohm     = 949 },
 136        { .temp_c       = 120, .ohm     = 817 },
 137        { .temp_c       = 125, .ohm     = 707 },
 138};
 139
 140static const struct ntc_compensation ncpXXwf104[] = {
 141        { .temp_c       = -40, .ohm     = 4397119 },
 142        { .temp_c       = -35, .ohm     = 3088599 },
 143        { .temp_c       = -30, .ohm     = 2197225 },
 144        { .temp_c       = -25, .ohm     = 1581881 },
 145        { .temp_c       = -20, .ohm     = 1151037 },
 146        { .temp_c       = -15, .ohm     = 846579 },
 147        { .temp_c       = -10, .ohm     = 628988 },
 148        { .temp_c       = -5, .ohm      = 471632 },
 149        { .temp_c       = 0, .ohm       = 357012 },
 150        { .temp_c       = 5, .ohm       = 272500 },
 151        { .temp_c       = 10, .ohm      = 209710 },
 152        { .temp_c       = 15, .ohm      = 162651 },
 153        { .temp_c       = 20, .ohm      = 127080 },
 154        { .temp_c       = 25, .ohm      = 100000 },
 155        { .temp_c       = 30, .ohm      = 79222 },
 156        { .temp_c       = 35, .ohm      = 63167 },
 157        { .temp_c       = 40, .ohm      = 50677 },
 158        { .temp_c       = 45, .ohm      = 40904 },
 159        { .temp_c       = 50, .ohm      = 33195 },
 160        { .temp_c       = 55, .ohm      = 27091 },
 161        { .temp_c       = 60, .ohm      = 22224 },
 162        { .temp_c       = 65, .ohm      = 18323 },
 163        { .temp_c       = 70, .ohm      = 15184 },
 164        { .temp_c       = 75, .ohm      = 12635 },
 165        { .temp_c       = 80, .ohm      = 10566 },
 166        { .temp_c       = 85, .ohm      = 8873 },
 167        { .temp_c       = 90, .ohm      = 7481 },
 168        { .temp_c       = 95, .ohm      = 6337 },
 169        { .temp_c       = 100, .ohm     = 5384 },
 170        { .temp_c       = 105, .ohm     = 4594 },
 171        { .temp_c       = 110, .ohm     = 3934 },
 172        { .temp_c       = 115, .ohm     = 3380 },
 173        { .temp_c       = 120, .ohm     = 2916 },
 174        { .temp_c       = 125, .ohm     = 2522 },
 175};
 176
 177static const struct ntc_compensation ncpXXxh103[] = {
 178        { .temp_c       = -40, .ohm     = 247565 },
 179        { .temp_c       = -35, .ohm     = 181742 },
 180        { .temp_c       = -30, .ohm     = 135128 },
 181        { .temp_c       = -25, .ohm     = 101678 },
 182        { .temp_c       = -20, .ohm     = 77373 },
 183        { .temp_c       = -15, .ohm     = 59504 },
 184        { .temp_c       = -10, .ohm     = 46222 },
 185        { .temp_c       = -5, .ohm      = 36244 },
 186        { .temp_c       = 0, .ohm       = 28674 },
 187        { .temp_c       = 5, .ohm       = 22878 },
 188        { .temp_c       = 10, .ohm      = 18399 },
 189        { .temp_c       = 15, .ohm      = 14910 },
 190        { .temp_c       = 20, .ohm      = 12169 },
 191        { .temp_c       = 25, .ohm      = 10000 },
 192        { .temp_c       = 30, .ohm      = 8271 },
 193        { .temp_c       = 35, .ohm      = 6883 },
 194        { .temp_c       = 40, .ohm      = 5762 },
 195        { .temp_c       = 45, .ohm      = 4851 },
 196        { .temp_c       = 50, .ohm      = 4105 },
 197        { .temp_c       = 55, .ohm      = 3492 },
 198        { .temp_c       = 60, .ohm      = 2985 },
 199        { .temp_c       = 65, .ohm      = 2563 },
 200        { .temp_c       = 70, .ohm      = 2211 },
 201        { .temp_c       = 75, .ohm      = 1915 },
 202        { .temp_c       = 80, .ohm      = 1666 },
 203        { .temp_c       = 85, .ohm      = 1454 },
 204        { .temp_c       = 90, .ohm      = 1275 },
 205        { .temp_c       = 95, .ohm      = 1121 },
 206        { .temp_c       = 100, .ohm     = 990 },
 207        { .temp_c       = 105, .ohm     = 876 },
 208        { .temp_c       = 110, .ohm     = 779 },
 209        { .temp_c       = 115, .ohm     = 694 },
 210        { .temp_c       = 120, .ohm     = 620 },
 211        { .temp_c       = 125, .ohm     = 556 },
 212};
 213
 214/*
 215 * The following compensation table is from the specification of EPCOS NTC
 216 * Thermistors Datasheet
 217 */
 218static const struct ntc_compensation b57330v2103[] = {
 219        { .temp_c       = -40, .ohm     = 190030 },
 220        { .temp_c       = -35, .ohm     = 145360 },
 221        { .temp_c       = -30, .ohm     = 112060 },
 222        { .temp_c       = -25, .ohm     = 87041 },
 223        { .temp_c       = -20, .ohm     = 68104 },
 224        { .temp_c       = -15, .ohm     = 53665 },
 225        { .temp_c       = -10, .ohm     = 42576 },
 226        { .temp_c       = -5, .ohm      = 34001 },
 227        { .temp_c       = 0, .ohm       = 27326 },
 228        { .temp_c       = 5, .ohm       = 22096 },
 229        { .temp_c       = 10, .ohm      = 17973 },
 230        { .temp_c       = 15, .ohm      = 14703 },
 231        { .temp_c       = 20, .ohm      = 12090 },
 232        { .temp_c       = 25, .ohm      = 10000 },
 233        { .temp_c       = 30, .ohm      = 8311 },
 234        { .temp_c       = 35, .ohm      = 6941 },
 235        { .temp_c       = 40, .ohm      = 5825 },
 236        { .temp_c       = 45, .ohm      = 4911 },
 237        { .temp_c       = 50, .ohm      = 4158 },
 238        { .temp_c       = 55, .ohm      = 3536 },
 239        { .temp_c       = 60, .ohm      = 3019 },
 240        { .temp_c       = 65, .ohm      = 2588 },
 241        { .temp_c       = 70, .ohm      = 2227 },
 242        { .temp_c       = 75, .ohm      = 1924 },
 243        { .temp_c       = 80, .ohm      = 1668 },
 244        { .temp_c       = 85, .ohm      = 1451 },
 245        { .temp_c       = 90, .ohm      = 1266 },
 246        { .temp_c       = 95, .ohm      = 1108 },
 247        { .temp_c       = 100, .ohm     = 973 },
 248        { .temp_c       = 105, .ohm     = 857 },
 249        { .temp_c       = 110, .ohm     = 757 },
 250        { .temp_c       = 115, .ohm     = 671 },
 251        { .temp_c       = 120, .ohm     = 596 },
 252        { .temp_c       = 125, .ohm     = 531 },
 253};
 254
 255struct ntc_data {
 256        struct ntc_thermistor_platform_data *pdata;
 257        const struct ntc_compensation *comp;
 258        int n_comp;
 259};
 260
 261#if defined(CONFIG_OF) && IS_ENABLED(CONFIG_IIO)
 262static int ntc_adc_iio_read(struct ntc_thermistor_platform_data *pdata)
 263{
 264        struct iio_channel *channel = pdata->chan;
 265        int raw, uv, ret;
 266
 267        ret = iio_read_channel_raw(channel, &raw);
 268        if (ret < 0) {
 269                pr_err("read channel() error: %d\n", ret);
 270                return ret;
 271        }
 272
 273        ret = iio_convert_raw_to_processed(channel, raw, &uv, 1000);
 274        if (ret < 0) {
 275                /* Assume 12 bit ADC with vref at pullup_uv */
 276                uv = (pdata->pullup_uv * (s64)raw) >> 12;
 277        }
 278
 279        return uv;
 280}
 281
 282static const struct of_device_id ntc_match[] = {
 283        { .compatible = "murata,ncp15wb473",
 284                .data = &ntc_thermistor_id[0] },
 285        { .compatible = "murata,ncp18wb473",
 286                .data = &ntc_thermistor_id[1] },
 287        { .compatible = "murata,ncp21wb473",
 288                .data = &ntc_thermistor_id[2] },
 289        { .compatible = "murata,ncp03wb473",
 290                .data = &ntc_thermistor_id[3] },
 291        { .compatible = "murata,ncp15wl333",
 292                .data = &ntc_thermistor_id[4] },
 293        { .compatible = "epcos,b57330v2103",
 294                .data = &ntc_thermistor_id[5]},
 295        { .compatible = "murata,ncp03wf104",
 296                .data = &ntc_thermistor_id[6] },
 297        { .compatible = "murata,ncp15xh103",
 298                .data = &ntc_thermistor_id[7] },
 299
 300        /* Usage of vendor name "ntc" is deprecated */
 301        { .compatible = "ntc,ncp15wb473",
 302                .data = &ntc_thermistor_id[0] },
 303        { .compatible = "ntc,ncp18wb473",
 304                .data = &ntc_thermistor_id[1] },
 305        { .compatible = "ntc,ncp21wb473",
 306                .data = &ntc_thermistor_id[2] },
 307        { .compatible = "ntc,ncp03wb473",
 308                .data = &ntc_thermistor_id[3] },
 309        { .compatible = "ntc,ncp15wl333",
 310                .data = &ntc_thermistor_id[4] },
 311        { },
 312};
 313MODULE_DEVICE_TABLE(of, ntc_match);
 314
 315static struct ntc_thermistor_platform_data *
 316ntc_thermistor_parse_dt(struct device *dev)
 317{
 318        struct iio_channel *chan;
 319        enum iio_chan_type type;
 320        struct device_node *np = dev->of_node;
 321        struct ntc_thermistor_platform_data *pdata;
 322        int ret;
 323
 324        if (!np)
 325                return NULL;
 326
 327        pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
 328        if (!pdata)
 329                return ERR_PTR(-ENOMEM);
 330
 331        chan = devm_iio_channel_get(dev, NULL);
 332        if (IS_ERR(chan))
 333                return ERR_CAST(chan);
 334
 335        ret = iio_get_channel_type(chan, &type);
 336        if (ret < 0)
 337                return ERR_PTR(ret);
 338
 339        if (type != IIO_VOLTAGE)
 340                return ERR_PTR(-EINVAL);
 341
 342        if (of_property_read_u32(np, "pullup-uv", &pdata->pullup_uv))
 343                return ERR_PTR(-ENODEV);
 344        if (of_property_read_u32(np, "pullup-ohm", &pdata->pullup_ohm))
 345                return ERR_PTR(-ENODEV);
 346        if (of_property_read_u32(np, "pulldown-ohm", &pdata->pulldown_ohm))
 347                return ERR_PTR(-ENODEV);
 348
 349        if (of_find_property(np, "connected-positive", NULL))
 350                pdata->connect = NTC_CONNECTED_POSITIVE;
 351        else /* status change should be possible if not always on. */
 352                pdata->connect = NTC_CONNECTED_GROUND;
 353
 354        pdata->chan = chan;
 355        pdata->read_uv = ntc_adc_iio_read;
 356
 357        return pdata;
 358}
 359#else
 360static struct ntc_thermistor_platform_data *
 361ntc_thermistor_parse_dt(struct device *dev)
 362{
 363        return NULL;
 364}
 365
 366#define ntc_match       NULL
 367
 368#endif
 369
 370static inline u64 div64_u64_safe(u64 dividend, u64 divisor)
 371{
 372        if (divisor == 0 && dividend == 0)
 373                return 0;
 374        if (divisor == 0)
 375                return UINT_MAX;
 376        return div64_u64(dividend, divisor);
 377}
 378
 379static int get_ohm_of_thermistor(struct ntc_data *data, unsigned int uv)
 380{
 381        struct ntc_thermistor_platform_data *pdata = data->pdata;
 382        u32 puv = pdata->pullup_uv;
 383        u64 n, puo, pdo;
 384        puo = pdata->pullup_ohm;
 385        pdo = pdata->pulldown_ohm;
 386
 387        if (uv == 0)
 388                return (pdata->connect == NTC_CONNECTED_POSITIVE) ?
 389                        INT_MAX : 0;
 390        if (uv >= puv)
 391                return (pdata->connect == NTC_CONNECTED_POSITIVE) ?
 392                        0 : INT_MAX;
 393
 394        if (pdata->connect == NTC_CONNECTED_POSITIVE && puo == 0)
 395                n = div_u64(pdo * (puv - uv), uv);
 396        else if (pdata->connect == NTC_CONNECTED_GROUND && pdo == 0)
 397                n = div_u64(puo * uv, puv - uv);
 398        else if (pdata->connect == NTC_CONNECTED_POSITIVE)
 399                n = div64_u64_safe(pdo * puo * (puv - uv),
 400                                puo * uv - pdo * (puv - uv));
 401        else
 402                n = div64_u64_safe(pdo * puo * uv, pdo * (puv - uv) - puo * uv);
 403
 404        if (n > INT_MAX)
 405                n = INT_MAX;
 406        return n;
 407}
 408
 409static void lookup_comp(struct ntc_data *data, unsigned int ohm,
 410                        int *i_low, int *i_high)
 411{
 412        int start, end, mid;
 413
 414        /*
 415         * Handle special cases: Resistance is higher than or equal to
 416         * resistance in first table entry, or resistance is lower or equal
 417         * to resistance in last table entry.
 418         * In these cases, return i_low == i_high, either pointing to the
 419         * beginning or to the end of the table depending on the condition.
 420         */
 421        if (ohm >= data->comp[0].ohm) {
 422                *i_low = 0;
 423                *i_high = 0;
 424                return;
 425        }
 426        if (ohm <= data->comp[data->n_comp - 1].ohm) {
 427                *i_low = data->n_comp - 1;
 428                *i_high = data->n_comp - 1;
 429                return;
 430        }
 431
 432        /* Do a binary search on compensation table */
 433        start = 0;
 434        end = data->n_comp;
 435        while (start < end) {
 436                mid = start + (end - start) / 2;
 437                /*
 438                 * start <= mid < end
 439                 * data->comp[start].ohm > ohm >= data->comp[end].ohm
 440                 *
 441                 * We could check for "ohm == data->comp[mid].ohm" here, but
 442                 * that is a quite unlikely condition, and we would have to
 443                 * check again after updating start. Check it at the end instead
 444                 * for simplicity.
 445                 */
 446                if (ohm >= data->comp[mid].ohm) {
 447                        end = mid;
 448                } else {
 449                        start = mid + 1;
 450                        /*
 451                         * ohm >= data->comp[start].ohm might be true here,
 452                         * since we set start to mid + 1. In that case, we are
 453                         * done. We could keep going, but the condition is quite
 454                         * likely to occur, so it is worth checking for it.
 455                         */
 456                        if (ohm >= data->comp[start].ohm)
 457                                end = start;
 458                }
 459                /*
 460                 * start <= end
 461                 * data->comp[start].ohm >= ohm >= data->comp[end].ohm
 462                 */
 463        }
 464        /*
 465         * start == end
 466         * ohm >= data->comp[end].ohm
 467         */
 468        *i_low = end;
 469        if (ohm == data->comp[end].ohm)
 470                *i_high = end;
 471        else
 472                *i_high = end - 1;
 473}
 474
 475static int get_temp_mc(struct ntc_data *data, unsigned int ohm)
 476{
 477        int low, high;
 478        int temp;
 479
 480        lookup_comp(data, ohm, &low, &high);
 481        if (low == high) {
 482                /* Unable to use linear approximation */
 483                temp = data->comp[low].temp_c * 1000;
 484        } else {
 485                temp = data->comp[low].temp_c * 1000 +
 486                        ((data->comp[high].temp_c - data->comp[low].temp_c) *
 487                         1000 * ((int)ohm - (int)data->comp[low].ohm)) /
 488                        ((int)data->comp[high].ohm - (int)data->comp[low].ohm);
 489        }
 490        return temp;
 491}
 492
 493static int ntc_thermistor_get_ohm(struct ntc_data *data)
 494{
 495        int read_uv;
 496
 497        if (data->pdata->read_ohm)
 498                return data->pdata->read_ohm();
 499
 500        if (data->pdata->read_uv) {
 501                read_uv = data->pdata->read_uv(data->pdata);
 502                if (read_uv < 0)
 503                        return read_uv;
 504                return get_ohm_of_thermistor(data, read_uv);
 505        }
 506        return -EINVAL;
 507}
 508
 509static int ntc_read_temp(void *data, int *temp)
 510{
 511        int ohm;
 512
 513        ohm = ntc_thermistor_get_ohm(data);
 514        if (ohm < 0)
 515                return ohm;
 516
 517        *temp = get_temp_mc(data, ohm);
 518
 519        return 0;
 520}
 521
 522static ssize_t ntc_show_type(struct device *dev,
 523                struct device_attribute *attr, char *buf)
 524{
 525        return sprintf(buf, "4\n");
 526}
 527
 528static ssize_t ntc_show_temp(struct device *dev,
 529                struct device_attribute *attr, char *buf)
 530{
 531        struct ntc_data *data = dev_get_drvdata(dev);
 532        int ohm;
 533
 534        ohm = ntc_thermistor_get_ohm(data);
 535        if (ohm < 0)
 536                return ohm;
 537
 538        return sprintf(buf, "%d\n", get_temp_mc(data, ohm));
 539}
 540
 541static SENSOR_DEVICE_ATTR(temp1_type, S_IRUGO, ntc_show_type, NULL, 0);
 542static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, ntc_show_temp, NULL, 0);
 543
 544static struct attribute *ntc_attrs[] = {
 545        &sensor_dev_attr_temp1_type.dev_attr.attr,
 546        &sensor_dev_attr_temp1_input.dev_attr.attr,
 547        NULL,
 548};
 549ATTRIBUTE_GROUPS(ntc);
 550
 551static const struct thermal_zone_of_device_ops ntc_of_thermal_ops = {
 552        .get_temp = ntc_read_temp,
 553};
 554
 555static int ntc_thermistor_probe(struct platform_device *pdev)
 556{
 557        struct thermal_zone_device *tz;
 558        struct device *dev = &pdev->dev;
 559        const struct of_device_id *of_id =
 560                        of_match_device(of_match_ptr(ntc_match), dev);
 561        const struct platform_device_id *pdev_id;
 562        struct ntc_thermistor_platform_data *pdata;
 563        struct device *hwmon_dev;
 564        struct ntc_data *data;
 565
 566        pdata = ntc_thermistor_parse_dt(dev);
 567        if (IS_ERR(pdata))
 568                return PTR_ERR(pdata);
 569        else if (pdata == NULL)
 570                pdata = dev_get_platdata(dev);
 571
 572        if (!pdata) {
 573                dev_err(dev, "No platform init data supplied.\n");
 574                return -ENODEV;
 575        }
 576
 577        /* Either one of the two is required. */
 578        if (!pdata->read_uv && !pdata->read_ohm) {
 579                dev_err(dev,
 580                        "Both read_uv and read_ohm missing. Need either one of the two.\n");
 581                return -EINVAL;
 582        }
 583
 584        if (pdata->read_uv && pdata->read_ohm) {
 585                dev_warn(dev,
 586                         "Only one of read_uv and read_ohm is needed; ignoring read_uv.\n");
 587                pdata->read_uv = NULL;
 588        }
 589
 590        if (pdata->read_uv && (pdata->pullup_uv == 0 ||
 591                                (pdata->pullup_ohm == 0 && pdata->connect ==
 592                                 NTC_CONNECTED_GROUND) ||
 593                                (pdata->pulldown_ohm == 0 && pdata->connect ==
 594                                 NTC_CONNECTED_POSITIVE) ||
 595                                (pdata->connect != NTC_CONNECTED_POSITIVE &&
 596                                 pdata->connect != NTC_CONNECTED_GROUND))) {
 597                dev_err(dev, "Required data to use read_uv not supplied.\n");
 598                return -EINVAL;
 599        }
 600
 601        data = devm_kzalloc(dev, sizeof(struct ntc_data), GFP_KERNEL);
 602        if (!data)
 603                return -ENOMEM;
 604
 605        pdev_id = of_id ? of_id->data : platform_get_device_id(pdev);
 606
 607        data->pdata = pdata;
 608
 609        switch (pdev_id->driver_data) {
 610        case TYPE_NCPXXWB473:
 611                data->comp = ncpXXwb473;
 612                data->n_comp = ARRAY_SIZE(ncpXXwb473);
 613                break;
 614        case TYPE_NCPXXWL333:
 615                data->comp = ncpXXwl333;
 616                data->n_comp = ARRAY_SIZE(ncpXXwl333);
 617                break;
 618        case TYPE_B57330V2103:
 619                data->comp = b57330v2103;
 620                data->n_comp = ARRAY_SIZE(b57330v2103);
 621                break;
 622        case TYPE_NCPXXWF104:
 623                data->comp = ncpXXwf104;
 624                data->n_comp = ARRAY_SIZE(ncpXXwf104);
 625                break;
 626        case TYPE_NCPXXXH103:
 627                data->comp = ncpXXxh103;
 628                data->n_comp = ARRAY_SIZE(ncpXXxh103);
 629                break;
 630        default:
 631                dev_err(dev, "Unknown device type: %lu(%s)\n",
 632                                pdev_id->driver_data, pdev_id->name);
 633                return -EINVAL;
 634        }
 635
 636        hwmon_dev = devm_hwmon_device_register_with_groups(dev, pdev_id->name,
 637                                                           data, ntc_groups);
 638        if (IS_ERR(hwmon_dev)) {
 639                dev_err(dev, "unable to register as hwmon device.\n");
 640                return PTR_ERR(hwmon_dev);
 641        }
 642
 643        dev_info(dev, "Thermistor type: %s successfully probed.\n",
 644                 pdev_id->name);
 645
 646        tz = devm_thermal_zone_of_sensor_register(dev, 0, data,
 647                                                  &ntc_of_thermal_ops);
 648        if (IS_ERR(tz))
 649                dev_dbg(dev, "Failed to register to thermal fw.\n");
 650
 651        return 0;
 652}
 653
 654static struct platform_driver ntc_thermistor_driver = {
 655        .driver = {
 656                .name = "ntc-thermistor",
 657                .of_match_table = of_match_ptr(ntc_match),
 658        },
 659        .probe = ntc_thermistor_probe,
 660        .id_table = ntc_thermistor_id,
 661};
 662
 663module_platform_driver(ntc_thermistor_driver);
 664
 665MODULE_DESCRIPTION("NTC Thermistor Driver");
 666MODULE_AUTHOR("MyungJoo Ham <myungjoo.ham@samsung.com>");
 667MODULE_LICENSE("GPL");
 668MODULE_ALIAS("platform:ntc-thermistor");
 669