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 device *hwmon_dev;
 257        struct ntc_thermistor_platform_data *pdata;
 258        const struct ntc_compensation *comp;
 259        struct device *dev;
 260        int n_comp;
 261        char name[PLATFORM_NAME_SIZE];
 262        struct thermal_zone_device *tz;
 263};
 264
 265#if defined(CONFIG_OF) && IS_ENABLED(CONFIG_IIO)
 266static int ntc_adc_iio_read(struct ntc_thermistor_platform_data *pdata)
 267{
 268        struct iio_channel *channel = pdata->chan;
 269        int raw, uv, ret;
 270
 271        ret = iio_read_channel_raw(channel, &raw);
 272        if (ret < 0) {
 273                pr_err("read channel() error: %d\n", ret);
 274                return ret;
 275        }
 276
 277        ret = iio_convert_raw_to_processed(channel, raw, &uv, 1000);
 278        if (ret < 0) {
 279                /* Assume 12 bit ADC with vref at pullup_uv */
 280                uv = (pdata->pullup_uv * (s64)raw) >> 12;
 281        }
 282
 283        return uv;
 284}
 285
 286static const struct of_device_id ntc_match[] = {
 287        { .compatible = "murata,ncp15wb473",
 288                .data = &ntc_thermistor_id[0] },
 289        { .compatible = "murata,ncp18wb473",
 290                .data = &ntc_thermistor_id[1] },
 291        { .compatible = "murata,ncp21wb473",
 292                .data = &ntc_thermistor_id[2] },
 293        { .compatible = "murata,ncp03wb473",
 294                .data = &ntc_thermistor_id[3] },
 295        { .compatible = "murata,ncp15wl333",
 296                .data = &ntc_thermistor_id[4] },
 297        { .compatible = "epcos,b57330v2103",
 298                .data = &ntc_thermistor_id[5]},
 299        { .compatible = "murata,ncp03wf104",
 300                .data = &ntc_thermistor_id[6] },
 301        { .compatible = "murata,ncp15xh103",
 302                .data = &ntc_thermistor_id[7] },
 303
 304        /* Usage of vendor name "ntc" is deprecated */
 305        { .compatible = "ntc,ncp15wb473",
 306                .data = &ntc_thermistor_id[0] },
 307        { .compatible = "ntc,ncp18wb473",
 308                .data = &ntc_thermistor_id[1] },
 309        { .compatible = "ntc,ncp21wb473",
 310                .data = &ntc_thermistor_id[2] },
 311        { .compatible = "ntc,ncp03wb473",
 312                .data = &ntc_thermistor_id[3] },
 313        { .compatible = "ntc,ncp15wl333",
 314                .data = &ntc_thermistor_id[4] },
 315        { },
 316};
 317MODULE_DEVICE_TABLE(of, ntc_match);
 318
 319static struct ntc_thermistor_platform_data *
 320ntc_thermistor_parse_dt(struct platform_device *pdev)
 321{
 322        struct iio_channel *chan;
 323        enum iio_chan_type type;
 324        struct device_node *np = pdev->dev.of_node;
 325        struct ntc_thermistor_platform_data *pdata;
 326        int ret;
 327
 328        if (!np)
 329                return NULL;
 330
 331        pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
 332        if (!pdata)
 333                return ERR_PTR(-ENOMEM);
 334
 335        chan = iio_channel_get(&pdev->dev, NULL);
 336        if (IS_ERR(chan))
 337                return ERR_CAST(chan);
 338
 339        ret = iio_get_channel_type(chan, &type);
 340        if (ret < 0)
 341                return ERR_PTR(ret);
 342
 343        if (type != IIO_VOLTAGE)
 344                return ERR_PTR(-EINVAL);
 345
 346        if (of_property_read_u32(np, "pullup-uv", &pdata->pullup_uv))
 347                return ERR_PTR(-ENODEV);
 348        if (of_property_read_u32(np, "pullup-ohm", &pdata->pullup_ohm))
 349                return ERR_PTR(-ENODEV);
 350        if (of_property_read_u32(np, "pulldown-ohm", &pdata->pulldown_ohm))
 351                return ERR_PTR(-ENODEV);
 352
 353        if (of_find_property(np, "connected-positive", NULL))
 354                pdata->connect = NTC_CONNECTED_POSITIVE;
 355        else /* status change should be possible if not always on. */
 356                pdata->connect = NTC_CONNECTED_GROUND;
 357
 358        pdata->chan = chan;
 359        pdata->read_uv = ntc_adc_iio_read;
 360
 361        return pdata;
 362}
 363static void ntc_iio_channel_release(struct ntc_thermistor_platform_data *pdata)
 364{
 365        if (pdata->chan)
 366                iio_channel_release(pdata->chan);
 367}
 368#else
 369static struct ntc_thermistor_platform_data *
 370ntc_thermistor_parse_dt(struct platform_device *pdev)
 371{
 372        return NULL;
 373}
 374
 375#define ntc_match       NULL
 376
 377static void ntc_iio_channel_release(struct ntc_thermistor_platform_data *pdata)
 378{ }
 379#endif
 380
 381static inline u64 div64_u64_safe(u64 dividend, u64 divisor)
 382{
 383        if (divisor == 0 && dividend == 0)
 384                return 0;
 385        if (divisor == 0)
 386                return UINT_MAX;
 387        return div64_u64(dividend, divisor);
 388}
 389
 390static int get_ohm_of_thermistor(struct ntc_data *data, unsigned int uv)
 391{
 392        struct ntc_thermistor_platform_data *pdata = data->pdata;
 393        u32 puv = pdata->pullup_uv;
 394        u64 n, puo, pdo;
 395        puo = pdata->pullup_ohm;
 396        pdo = pdata->pulldown_ohm;
 397
 398        if (uv == 0)
 399                return (pdata->connect == NTC_CONNECTED_POSITIVE) ?
 400                        INT_MAX : 0;
 401        if (uv >= puv)
 402                return (pdata->connect == NTC_CONNECTED_POSITIVE) ?
 403                        0 : INT_MAX;
 404
 405        if (pdata->connect == NTC_CONNECTED_POSITIVE && puo == 0)
 406                n = div_u64(pdo * (puv - uv), uv);
 407        else if (pdata->connect == NTC_CONNECTED_GROUND && pdo == 0)
 408                n = div_u64(puo * uv, puv - uv);
 409        else if (pdata->connect == NTC_CONNECTED_POSITIVE)
 410                n = div64_u64_safe(pdo * puo * (puv - uv),
 411                                puo * uv - pdo * (puv - uv));
 412        else
 413                n = div64_u64_safe(pdo * puo * uv, pdo * (puv - uv) - puo * uv);
 414
 415        if (n > INT_MAX)
 416                n = INT_MAX;
 417        return n;
 418}
 419
 420static void lookup_comp(struct ntc_data *data, unsigned int ohm,
 421                        int *i_low, int *i_high)
 422{
 423        int start, end, mid;
 424
 425        /*
 426         * Handle special cases: Resistance is higher than or equal to
 427         * resistance in first table entry, or resistance is lower or equal
 428         * to resistance in last table entry.
 429         * In these cases, return i_low == i_high, either pointing to the
 430         * beginning or to the end of the table depending on the condition.
 431         */
 432        if (ohm >= data->comp[0].ohm) {
 433                *i_low = 0;
 434                *i_high = 0;
 435                return;
 436        }
 437        if (ohm <= data->comp[data->n_comp - 1].ohm) {
 438                *i_low = data->n_comp - 1;
 439                *i_high = data->n_comp - 1;
 440                return;
 441        }
 442
 443        /* Do a binary search on compensation table */
 444        start = 0;
 445        end = data->n_comp;
 446        while (start < end) {
 447                mid = start + (end - start) / 2;
 448                /*
 449                 * start <= mid < end
 450                 * data->comp[start].ohm > ohm >= data->comp[end].ohm
 451                 *
 452                 * We could check for "ohm == data->comp[mid].ohm" here, but
 453                 * that is a quite unlikely condition, and we would have to
 454                 * check again after updating start. Check it at the end instead
 455                 * for simplicity.
 456                 */
 457                if (ohm >= data->comp[mid].ohm) {
 458                        end = mid;
 459                } else {
 460                        start = mid + 1;
 461                        /*
 462                         * ohm >= data->comp[start].ohm might be true here,
 463                         * since we set start to mid + 1. In that case, we are
 464                         * done. We could keep going, but the condition is quite
 465                         * likely to occur, so it is worth checking for it.
 466                         */
 467                        if (ohm >= data->comp[start].ohm)
 468                                end = start;
 469                }
 470                /*
 471                 * start <= end
 472                 * data->comp[start].ohm >= ohm >= data->comp[end].ohm
 473                 */
 474        }
 475        /*
 476         * start == end
 477         * ohm >= data->comp[end].ohm
 478         */
 479        *i_low = end;
 480        if (ohm == data->comp[end].ohm)
 481                *i_high = end;
 482        else
 483                *i_high = end - 1;
 484}
 485
 486static int get_temp_mc(struct ntc_data *data, unsigned int ohm)
 487{
 488        int low, high;
 489        int temp;
 490
 491        lookup_comp(data, ohm, &low, &high);
 492        if (low == high) {
 493                /* Unable to use linear approximation */
 494                temp = data->comp[low].temp_c * 1000;
 495        } else {
 496                temp = data->comp[low].temp_c * 1000 +
 497                        ((data->comp[high].temp_c - data->comp[low].temp_c) *
 498                         1000 * ((int)ohm - (int)data->comp[low].ohm)) /
 499                        ((int)data->comp[high].ohm - (int)data->comp[low].ohm);
 500        }
 501        return temp;
 502}
 503
 504static int ntc_thermistor_get_ohm(struct ntc_data *data)
 505{
 506        int read_uv;
 507
 508        if (data->pdata->read_ohm)
 509                return data->pdata->read_ohm();
 510
 511        if (data->pdata->read_uv) {
 512                read_uv = data->pdata->read_uv(data->pdata);
 513                if (read_uv < 0)
 514                        return read_uv;
 515                return get_ohm_of_thermistor(data, read_uv);
 516        }
 517        return -EINVAL;
 518}
 519
 520static int ntc_read_temp(void *dev, int *temp)
 521{
 522        struct ntc_data *data = dev_get_drvdata(dev);
 523        int ohm;
 524
 525        ohm = ntc_thermistor_get_ohm(data);
 526        if (ohm < 0)
 527                return ohm;
 528
 529        *temp = get_temp_mc(data, ohm);
 530
 531        return 0;
 532}
 533
 534static ssize_t ntc_show_name(struct device *dev,
 535                struct device_attribute *attr, char *buf)
 536{
 537        struct ntc_data *data = dev_get_drvdata(dev);
 538
 539        return sprintf(buf, "%s\n", data->name);
 540}
 541
 542static ssize_t ntc_show_type(struct device *dev,
 543                struct device_attribute *attr, char *buf)
 544{
 545        return sprintf(buf, "4\n");
 546}
 547
 548static ssize_t ntc_show_temp(struct device *dev,
 549                struct device_attribute *attr, char *buf)
 550{
 551        struct ntc_data *data = dev_get_drvdata(dev);
 552        int ohm;
 553
 554        ohm = ntc_thermistor_get_ohm(data);
 555        if (ohm < 0)
 556                return ohm;
 557
 558        return sprintf(buf, "%d\n", get_temp_mc(data, ohm));
 559}
 560
 561static SENSOR_DEVICE_ATTR(temp1_type, S_IRUGO, ntc_show_type, NULL, 0);
 562static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, ntc_show_temp, NULL, 0);
 563static DEVICE_ATTR(name, S_IRUGO, ntc_show_name, NULL);
 564
 565static struct attribute *ntc_attributes[] = {
 566        &dev_attr_name.attr,
 567        &sensor_dev_attr_temp1_type.dev_attr.attr,
 568        &sensor_dev_attr_temp1_input.dev_attr.attr,
 569        NULL,
 570};
 571
 572static const struct attribute_group ntc_attr_group = {
 573        .attrs = ntc_attributes,
 574};
 575
 576static const struct thermal_zone_of_device_ops ntc_of_thermal_ops = {
 577        .get_temp = ntc_read_temp,
 578};
 579
 580static int ntc_thermistor_probe(struct platform_device *pdev)
 581{
 582        const struct of_device_id *of_id =
 583                        of_match_device(of_match_ptr(ntc_match), &pdev->dev);
 584        const struct platform_device_id *pdev_id;
 585        struct ntc_thermistor_platform_data *pdata;
 586        struct ntc_data *data;
 587        int ret;
 588
 589        pdata = ntc_thermistor_parse_dt(pdev);
 590        if (IS_ERR(pdata))
 591                return PTR_ERR(pdata);
 592        else if (pdata == NULL)
 593                pdata = dev_get_platdata(&pdev->dev);
 594
 595        if (!pdata) {
 596                dev_err(&pdev->dev, "No platform init data supplied.\n");
 597                return -ENODEV;
 598        }
 599
 600        /* Either one of the two is required. */
 601        if (!pdata->read_uv && !pdata->read_ohm) {
 602                dev_err(&pdev->dev,
 603                        "Both read_uv and read_ohm missing. Need either one of the two.\n");
 604                return -EINVAL;
 605        }
 606
 607        if (pdata->read_uv && pdata->read_ohm) {
 608                dev_warn(&pdev->dev,
 609                         "Only one of read_uv and read_ohm is needed; ignoring read_uv.\n");
 610                pdata->read_uv = NULL;
 611        }
 612
 613        if (pdata->read_uv && (pdata->pullup_uv == 0 ||
 614                                (pdata->pullup_ohm == 0 && pdata->connect ==
 615                                 NTC_CONNECTED_GROUND) ||
 616                                (pdata->pulldown_ohm == 0 && pdata->connect ==
 617                                 NTC_CONNECTED_POSITIVE) ||
 618                                (pdata->connect != NTC_CONNECTED_POSITIVE &&
 619                                 pdata->connect != NTC_CONNECTED_GROUND))) {
 620                dev_err(&pdev->dev,
 621                        "Required data to use read_uv not supplied.\n");
 622                return -EINVAL;
 623        }
 624
 625        data = devm_kzalloc(&pdev->dev, sizeof(struct ntc_data), GFP_KERNEL);
 626        if (!data)
 627                return -ENOMEM;
 628
 629        pdev_id = of_id ? of_id->data : platform_get_device_id(pdev);
 630
 631        data->dev = &pdev->dev;
 632        data->pdata = pdata;
 633        strlcpy(data->name, pdev_id->name, sizeof(data->name));
 634
 635        switch (pdev_id->driver_data) {
 636        case TYPE_NCPXXWB473:
 637                data->comp = ncpXXwb473;
 638                data->n_comp = ARRAY_SIZE(ncpXXwb473);
 639                break;
 640        case TYPE_NCPXXWL333:
 641                data->comp = ncpXXwl333;
 642                data->n_comp = ARRAY_SIZE(ncpXXwl333);
 643                break;
 644        case TYPE_B57330V2103:
 645                data->comp = b57330v2103;
 646                data->n_comp = ARRAY_SIZE(b57330v2103);
 647                break;
 648        case TYPE_NCPXXWF104:
 649                data->comp = ncpXXwf104;
 650                data->n_comp = ARRAY_SIZE(ncpXXwf104);
 651                break;
 652        case TYPE_NCPXXXH103:
 653                data->comp = ncpXXxh103;
 654                data->n_comp = ARRAY_SIZE(ncpXXxh103);
 655                break;
 656        default:
 657                dev_err(&pdev->dev, "Unknown device type: %lu(%s)\n",
 658                                pdev_id->driver_data, pdev_id->name);
 659                return -EINVAL;
 660        }
 661
 662        platform_set_drvdata(pdev, data);
 663
 664        ret = sysfs_create_group(&data->dev->kobj, &ntc_attr_group);
 665        if (ret) {
 666                dev_err(data->dev, "unable to create sysfs files\n");
 667                return ret;
 668        }
 669
 670        data->hwmon_dev = hwmon_device_register(data->dev);
 671        if (IS_ERR(data->hwmon_dev)) {
 672                dev_err(data->dev, "unable to register as hwmon device.\n");
 673                ret = PTR_ERR(data->hwmon_dev);
 674                goto err_after_sysfs;
 675        }
 676
 677        dev_info(&pdev->dev, "Thermistor type: %s successfully probed.\n",
 678                                                                pdev_id->name);
 679
 680        data->tz = thermal_zone_of_sensor_register(data->dev, 0, data->dev,
 681                                                   &ntc_of_thermal_ops);
 682        if (IS_ERR(data->tz)) {
 683                dev_dbg(&pdev->dev, "Failed to register to thermal fw.\n");
 684                data->tz = NULL;
 685        }
 686
 687        return 0;
 688err_after_sysfs:
 689        sysfs_remove_group(&data->dev->kobj, &ntc_attr_group);
 690        ntc_iio_channel_release(pdata);
 691        return ret;
 692}
 693
 694static int ntc_thermistor_remove(struct platform_device *pdev)
 695{
 696        struct ntc_data *data = platform_get_drvdata(pdev);
 697        struct ntc_thermistor_platform_data *pdata = data->pdata;
 698
 699        hwmon_device_unregister(data->hwmon_dev);
 700        sysfs_remove_group(&data->dev->kobj, &ntc_attr_group);
 701        ntc_iio_channel_release(pdata);
 702
 703        thermal_zone_of_sensor_unregister(data->dev, data->tz);
 704
 705        return 0;
 706}
 707
 708static struct platform_driver ntc_thermistor_driver = {
 709        .driver = {
 710                .name = "ntc-thermistor",
 711                .of_match_table = of_match_ptr(ntc_match),
 712        },
 713        .probe = ntc_thermistor_probe,
 714        .remove = ntc_thermistor_remove,
 715        .id_table = ntc_thermistor_id,
 716};
 717
 718module_platform_driver(ntc_thermistor_driver);
 719
 720MODULE_DESCRIPTION("NTC Thermistor Driver");
 721MODULE_AUTHOR("MyungJoo Ham <myungjoo.ham@samsung.com>");
 722MODULE_LICENSE("GPL");
 723MODULE_ALIAS("platform:ntc-thermistor");
 724