cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

ntc_thermistor.c (20040B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/*
      3 * ntc_thermistor.c - NTC Thermistors
      4 *
      5 *  Copyright (C) 2010 Samsung Electronics
      6 *  MyungJoo Ham <myungjoo.ham@samsung.com>
      7 */
      8
      9#include <linux/slab.h>
     10#include <linux/module.h>
     11#include <linux/math64.h>
     12#include <linux/mod_devicetable.h>
     13#include <linux/platform_device.h>
     14#include <linux/property.h>
     15#include <linux/err.h>
     16#include <linux/fixp-arith.h>
     17#include <linux/iio/consumer.h>
     18#include <linux/hwmon.h>
     19
     20enum ntc_thermistor_type {
     21	TYPE_B57330V2103,
     22	TYPE_B57891S0103,
     23	TYPE_NCPXXWB473,
     24	TYPE_NCPXXWF104,
     25	TYPE_NCPXXWL333,
     26	TYPE_NCPXXXH103,
     27};
     28
     29struct ntc_compensation {
     30	int		temp_c;
     31	unsigned int	ohm;
     32};
     33
     34/*
     35 * Used as index in a zero-terminated array, holes not allowed so
     36 * that NTC_LAST is the first empty array entry.
     37 */
     38enum {
     39	NTC_B57330V2103,
     40	NTC_B57891S0103,
     41	NTC_NCP03WB473,
     42	NTC_NCP03WF104,
     43	NTC_NCP15WB473,
     44	NTC_NCP15WL333,
     45	NTC_NCP15XH103,
     46	NTC_NCP18WB473,
     47	NTC_NCP21WB473,
     48	NTC_SSG1404001221,
     49	NTC_LAST,
     50};
     51
     52static const struct platform_device_id ntc_thermistor_id[] = {
     53	[NTC_B57330V2103]     = { "b57330v2103",     TYPE_B57330V2103 },
     54	[NTC_B57891S0103]     = { "b57891s0103",     TYPE_B57891S0103 },
     55	[NTC_NCP03WB473]      = { "ncp03wb473",      TYPE_NCPXXWB473 },
     56	[NTC_NCP03WF104]      = { "ncp03wf104",      TYPE_NCPXXWF104 },
     57	[NTC_NCP15WB473]      = { "ncp15wb473",      TYPE_NCPXXWB473 },
     58	[NTC_NCP15WL333]      = { "ncp15wl333",      TYPE_NCPXXWL333 },
     59	[NTC_NCP15XH103]      = { "ncp15xh103",      TYPE_NCPXXXH103 },
     60	[NTC_NCP18WB473]      = { "ncp18wb473",      TYPE_NCPXXWB473 },
     61	[NTC_NCP21WB473]      = { "ncp21wb473",      TYPE_NCPXXWB473 },
     62	[NTC_SSG1404001221]   = { "ssg1404_001221",  TYPE_NCPXXWB473 },
     63	[NTC_LAST]            = { },
     64};
     65
     66/*
     67 * A compensation table should be sorted by the values of .ohm
     68 * in descending order.
     69 * The following compensation tables are from the specification of Murata NTC
     70 * Thermistors Datasheet
     71 */
     72static const struct ntc_compensation ncpXXwb473[] = {
     73	{ .temp_c	= -40, .ohm	= 1747920 },
     74	{ .temp_c	= -35, .ohm	= 1245428 },
     75	{ .temp_c	= -30, .ohm	= 898485 },
     76	{ .temp_c	= -25, .ohm	= 655802 },
     77	{ .temp_c	= -20, .ohm	= 483954 },
     78	{ .temp_c	= -15, .ohm	= 360850 },
     79	{ .temp_c	= -10, .ohm	= 271697 },
     80	{ .temp_c	= -5, .ohm	= 206463 },
     81	{ .temp_c	= 0, .ohm	= 158214 },
     82	{ .temp_c	= 5, .ohm	= 122259 },
     83	{ .temp_c	= 10, .ohm	= 95227 },
     84	{ .temp_c	= 15, .ohm	= 74730 },
     85	{ .temp_c	= 20, .ohm	= 59065 },
     86	{ .temp_c	= 25, .ohm	= 47000 },
     87	{ .temp_c	= 30, .ohm	= 37643 },
     88	{ .temp_c	= 35, .ohm	= 30334 },
     89	{ .temp_c	= 40, .ohm	= 24591 },
     90	{ .temp_c	= 45, .ohm	= 20048 },
     91	{ .temp_c	= 50, .ohm	= 16433 },
     92	{ .temp_c	= 55, .ohm	= 13539 },
     93	{ .temp_c	= 60, .ohm	= 11209 },
     94	{ .temp_c	= 65, .ohm	= 9328 },
     95	{ .temp_c	= 70, .ohm	= 7798 },
     96	{ .temp_c	= 75, .ohm	= 6544 },
     97	{ .temp_c	= 80, .ohm	= 5518 },
     98	{ .temp_c	= 85, .ohm	= 4674 },
     99	{ .temp_c	= 90, .ohm	= 3972 },
    100	{ .temp_c	= 95, .ohm	= 3388 },
    101	{ .temp_c	= 100, .ohm	= 2902 },
    102	{ .temp_c	= 105, .ohm	= 2494 },
    103	{ .temp_c	= 110, .ohm	= 2150 },
    104	{ .temp_c	= 115, .ohm	= 1860 },
    105	{ .temp_c	= 120, .ohm	= 1615 },
    106	{ .temp_c	= 125, .ohm	= 1406 },
    107};
    108static const struct ntc_compensation ncpXXwl333[] = {
    109	{ .temp_c	= -40, .ohm	= 1610154 },
    110	{ .temp_c	= -35, .ohm	= 1130850 },
    111	{ .temp_c	= -30, .ohm	= 802609 },
    112	{ .temp_c	= -25, .ohm	= 575385 },
    113	{ .temp_c	= -20, .ohm	= 416464 },
    114	{ .temp_c	= -15, .ohm	= 304219 },
    115	{ .temp_c	= -10, .ohm	= 224193 },
    116	{ .temp_c	= -5, .ohm	= 166623 },
    117	{ .temp_c	= 0, .ohm	= 124850 },
    118	{ .temp_c	= 5, .ohm	= 94287 },
    119	{ .temp_c	= 10, .ohm	= 71747 },
    120	{ .temp_c	= 15, .ohm	= 54996 },
    121	{ .temp_c	= 20, .ohm	= 42455 },
    122	{ .temp_c	= 25, .ohm	= 33000 },
    123	{ .temp_c	= 30, .ohm	= 25822 },
    124	{ .temp_c	= 35, .ohm	= 20335 },
    125	{ .temp_c	= 40, .ohm	= 16115 },
    126	{ .temp_c	= 45, .ohm	= 12849 },
    127	{ .temp_c	= 50, .ohm	= 10306 },
    128	{ .temp_c	= 55, .ohm	= 8314 },
    129	{ .temp_c	= 60, .ohm	= 6746 },
    130	{ .temp_c	= 65, .ohm	= 5503 },
    131	{ .temp_c	= 70, .ohm	= 4513 },
    132	{ .temp_c	= 75, .ohm	= 3721 },
    133	{ .temp_c	= 80, .ohm	= 3084 },
    134	{ .temp_c	= 85, .ohm	= 2569 },
    135	{ .temp_c	= 90, .ohm	= 2151 },
    136	{ .temp_c	= 95, .ohm	= 1809 },
    137	{ .temp_c	= 100, .ohm	= 1529 },
    138	{ .temp_c	= 105, .ohm	= 1299 },
    139	{ .temp_c	= 110, .ohm	= 1108 },
    140	{ .temp_c	= 115, .ohm	= 949 },
    141	{ .temp_c	= 120, .ohm	= 817 },
    142	{ .temp_c	= 125, .ohm	= 707 },
    143};
    144
    145static const struct ntc_compensation ncpXXwf104[] = {
    146	{ .temp_c	= -40, .ohm	= 4397119 },
    147	{ .temp_c	= -35, .ohm	= 3088599 },
    148	{ .temp_c	= -30, .ohm	= 2197225 },
    149	{ .temp_c	= -25, .ohm	= 1581881 },
    150	{ .temp_c	= -20, .ohm	= 1151037 },
    151	{ .temp_c	= -15, .ohm	= 846579 },
    152	{ .temp_c	= -10, .ohm	= 628988 },
    153	{ .temp_c	= -5, .ohm	= 471632 },
    154	{ .temp_c	= 0, .ohm	= 357012 },
    155	{ .temp_c	= 5, .ohm	= 272500 },
    156	{ .temp_c	= 10, .ohm	= 209710 },
    157	{ .temp_c	= 15, .ohm	= 162651 },
    158	{ .temp_c	= 20, .ohm	= 127080 },
    159	{ .temp_c	= 25, .ohm	= 100000 },
    160	{ .temp_c	= 30, .ohm	= 79222 },
    161	{ .temp_c	= 35, .ohm	= 63167 },
    162	{ .temp_c	= 40, .ohm	= 50677 },
    163	{ .temp_c	= 45, .ohm	= 40904 },
    164	{ .temp_c	= 50, .ohm	= 33195 },
    165	{ .temp_c	= 55, .ohm	= 27091 },
    166	{ .temp_c	= 60, .ohm	= 22224 },
    167	{ .temp_c	= 65, .ohm	= 18323 },
    168	{ .temp_c	= 70, .ohm	= 15184 },
    169	{ .temp_c	= 75, .ohm	= 12635 },
    170	{ .temp_c	= 80, .ohm	= 10566 },
    171	{ .temp_c	= 85, .ohm	= 8873 },
    172	{ .temp_c	= 90, .ohm	= 7481 },
    173	{ .temp_c	= 95, .ohm	= 6337 },
    174	{ .temp_c	= 100, .ohm	= 5384 },
    175	{ .temp_c	= 105, .ohm	= 4594 },
    176	{ .temp_c	= 110, .ohm	= 3934 },
    177	{ .temp_c	= 115, .ohm	= 3380 },
    178	{ .temp_c	= 120, .ohm	= 2916 },
    179	{ .temp_c	= 125, .ohm	= 2522 },
    180};
    181
    182static const struct ntc_compensation ncpXXxh103[] = {
    183	{ .temp_c	= -40, .ohm	= 247565 },
    184	{ .temp_c	= -35, .ohm	= 181742 },
    185	{ .temp_c	= -30, .ohm	= 135128 },
    186	{ .temp_c	= -25, .ohm	= 101678 },
    187	{ .temp_c	= -20, .ohm	= 77373 },
    188	{ .temp_c	= -15, .ohm	= 59504 },
    189	{ .temp_c	= -10, .ohm	= 46222 },
    190	{ .temp_c	= -5, .ohm	= 36244 },
    191	{ .temp_c	= 0, .ohm	= 28674 },
    192	{ .temp_c	= 5, .ohm	= 22878 },
    193	{ .temp_c	= 10, .ohm	= 18399 },
    194	{ .temp_c	= 15, .ohm	= 14910 },
    195	{ .temp_c	= 20, .ohm	= 12169 },
    196	{ .temp_c	= 25, .ohm	= 10000 },
    197	{ .temp_c	= 30, .ohm	= 8271 },
    198	{ .temp_c	= 35, .ohm	= 6883 },
    199	{ .temp_c	= 40, .ohm	= 5762 },
    200	{ .temp_c	= 45, .ohm	= 4851 },
    201	{ .temp_c	= 50, .ohm	= 4105 },
    202	{ .temp_c	= 55, .ohm	= 3492 },
    203	{ .temp_c	= 60, .ohm	= 2985 },
    204	{ .temp_c	= 65, .ohm	= 2563 },
    205	{ .temp_c	= 70, .ohm	= 2211 },
    206	{ .temp_c	= 75, .ohm	= 1915 },
    207	{ .temp_c	= 80, .ohm	= 1666 },
    208	{ .temp_c	= 85, .ohm	= 1454 },
    209	{ .temp_c	= 90, .ohm	= 1275 },
    210	{ .temp_c	= 95, .ohm	= 1121 },
    211	{ .temp_c	= 100, .ohm	= 990 },
    212	{ .temp_c	= 105, .ohm	= 876 },
    213	{ .temp_c	= 110, .ohm	= 779 },
    214	{ .temp_c	= 115, .ohm	= 694 },
    215	{ .temp_c	= 120, .ohm	= 620 },
    216	{ .temp_c	= 125, .ohm	= 556 },
    217};
    218
    219/*
    220 * The following compensation tables are from the specifications in EPCOS NTC
    221 * Thermistors Datasheets
    222 */
    223static const struct ntc_compensation b57330v2103[] = {
    224	{ .temp_c	= -40, .ohm	= 190030 },
    225	{ .temp_c	= -35, .ohm	= 145360 },
    226	{ .temp_c	= -30, .ohm	= 112060 },
    227	{ .temp_c	= -25, .ohm	= 87041 },
    228	{ .temp_c	= -20, .ohm	= 68104 },
    229	{ .temp_c	= -15, .ohm	= 53665 },
    230	{ .temp_c	= -10, .ohm	= 42576 },
    231	{ .temp_c	= -5, .ohm	= 34001 },
    232	{ .temp_c	= 0, .ohm	= 27326 },
    233	{ .temp_c	= 5, .ohm	= 22096 },
    234	{ .temp_c	= 10, .ohm	= 17973 },
    235	{ .temp_c	= 15, .ohm	= 14703 },
    236	{ .temp_c	= 20, .ohm	= 12090 },
    237	{ .temp_c	= 25, .ohm	= 10000 },
    238	{ .temp_c	= 30, .ohm	= 8311 },
    239	{ .temp_c	= 35, .ohm	= 6941 },
    240	{ .temp_c	= 40, .ohm	= 5825 },
    241	{ .temp_c	= 45, .ohm	= 4911 },
    242	{ .temp_c	= 50, .ohm	= 4158 },
    243	{ .temp_c	= 55, .ohm	= 3536 },
    244	{ .temp_c	= 60, .ohm	= 3019 },
    245	{ .temp_c	= 65, .ohm	= 2588 },
    246	{ .temp_c	= 70, .ohm	= 2227 },
    247	{ .temp_c	= 75, .ohm	= 1924 },
    248	{ .temp_c	= 80, .ohm	= 1668 },
    249	{ .temp_c	= 85, .ohm	= 1451 },
    250	{ .temp_c	= 90, .ohm	= 1266 },
    251	{ .temp_c	= 95, .ohm	= 1108 },
    252	{ .temp_c	= 100, .ohm	= 973 },
    253	{ .temp_c	= 105, .ohm	= 857 },
    254	{ .temp_c	= 110, .ohm	= 757 },
    255	{ .temp_c	= 115, .ohm	= 671 },
    256	{ .temp_c	= 120, .ohm	= 596 },
    257	{ .temp_c	= 125, .ohm	= 531 },
    258};
    259
    260static const struct ntc_compensation b57891s0103[] = {
    261	{ .temp_c	= -55.0, .ohm	= 878900 },
    262	{ .temp_c	= -50.0, .ohm	= 617590 },
    263	{ .temp_c	= -45.0, .ohm	= 439340 },
    264	{ .temp_c	= -40.0, .ohm	= 316180 },
    265	{ .temp_c	= -35.0, .ohm	= 230060 },
    266	{ .temp_c	= -30.0, .ohm	= 169150 },
    267	{ .temp_c	= -25.0, .ohm	= 125550 },
    268	{ .temp_c	= -20.0, .ohm	= 94143 },
    269	{ .temp_c	= -15.0, .ohm	= 71172 },
    270	{ .temp_c	= -10.0, .ohm	= 54308 },
    271	{ .temp_c	= -5.0, .ohm	= 41505 },
    272	{ .temp_c	= 0.0, .ohm	= 32014 },
    273	{ .temp_c	= 5.0, .ohm	= 25011 },
    274	{ .temp_c	= 10.0, .ohm	= 19691 },
    275	{ .temp_c	= 15.0, .ohm	= 15618 },
    276	{ .temp_c	= 20.0, .ohm	= 12474 },
    277	{ .temp_c	= 25.0, .ohm	= 10000 },
    278	{ .temp_c	= 30.0, .ohm	= 8080 },
    279	{ .temp_c	= 35.0, .ohm	= 6569 },
    280	{ .temp_c	= 40.0, .ohm	= 5372 },
    281	{ .temp_c	= 45.0, .ohm	= 4424 },
    282	{ .temp_c	= 50.0, .ohm	= 3661 },
    283	{ .temp_c	= 55.0, .ohm	= 3039 },
    284	{ .temp_c	= 60.0, .ohm	= 2536 },
    285	{ .temp_c	= 65.0, .ohm	= 2128 },
    286	{ .temp_c	= 70.0, .ohm	= 1794 },
    287	{ .temp_c	= 75.0, .ohm	= 1518 },
    288	{ .temp_c	= 80.0, .ohm	= 1290 },
    289	{ .temp_c	= 85.0, .ohm	= 1100 },
    290	{ .temp_c	= 90.0, .ohm	= 942 },
    291	{ .temp_c	= 95.0, .ohm	= 809 },
    292	{ .temp_c	= 100.0, .ohm	= 697 },
    293	{ .temp_c	= 105.0, .ohm	= 604 },
    294	{ .temp_c	= 110.0, .ohm	= 525 },
    295	{ .temp_c	= 115.0, .ohm	= 457 },
    296	{ .temp_c	= 120.0, .ohm	= 400 },
    297	{ .temp_c	= 125.0, .ohm	= 351 },
    298	{ .temp_c	= 130.0, .ohm	= 308 },
    299	{ .temp_c	= 135.0, .ohm	= 272 },
    300	{ .temp_c	= 140.0, .ohm	= 240 },
    301	{ .temp_c	= 145.0, .ohm	= 213 },
    302	{ .temp_c	= 150.0, .ohm	= 189 },
    303	{ .temp_c	= 155.0, .ohm	= 168 },
    304};
    305
    306struct ntc_type {
    307	const struct ntc_compensation *comp;
    308	int n_comp;
    309};
    310
    311#define NTC_TYPE(ntc, compensation) \
    312[(ntc)] = { .comp = (compensation), .n_comp = ARRAY_SIZE(compensation) }
    313
    314static const struct ntc_type ntc_type[] = {
    315	NTC_TYPE(TYPE_B57330V2103, b57330v2103),
    316	NTC_TYPE(TYPE_B57891S0103, b57891s0103),
    317	NTC_TYPE(TYPE_NCPXXWB473,  ncpXXwb473),
    318	NTC_TYPE(TYPE_NCPXXWF104,  ncpXXwf104),
    319	NTC_TYPE(TYPE_NCPXXWL333,  ncpXXwl333),
    320	NTC_TYPE(TYPE_NCPXXXH103,  ncpXXxh103),
    321};
    322
    323/*
    324 * pullup_uV, pullup_ohm, pulldown_ohm, and connect are required.
    325 *
    326 * How to setup pullup_ohm, pulldown_ohm, and connect is
    327 * described at Documentation/hwmon/ntc_thermistor.rst
    328 *
    329 * pullup/down_ohm: 0 for infinite / not-connected
    330 *
    331 * chan: iio_channel pointer to communicate with the ADC which the
    332 * thermistor is using for conversion of the analog values.
    333 */
    334struct ntc_data {
    335	const struct ntc_compensation *comp;
    336	int n_comp;
    337	unsigned int pullup_uv;
    338	unsigned int pullup_ohm;
    339	unsigned int pulldown_ohm;
    340	enum { NTC_CONNECTED_POSITIVE, NTC_CONNECTED_GROUND } connect;
    341	struct iio_channel *chan;
    342};
    343
    344static int ntc_adc_iio_read(struct ntc_data *data)
    345{
    346	struct iio_channel *channel = data->chan;
    347	int uv, ret;
    348
    349	ret = iio_read_channel_processed_scale(channel, &uv, 1000);
    350	if (ret < 0) {
    351		int raw;
    352
    353		/*
    354		 * This fallback uses a raw read and then
    355		 * assumes the ADC is 12 bits, scaling with
    356		 * a factor 1000 to get to microvolts.
    357		 */
    358		ret = iio_read_channel_raw(channel, &raw);
    359		if (ret < 0) {
    360			pr_err("read channel() error: %d\n", ret);
    361			return ret;
    362		}
    363		ret = iio_convert_raw_to_processed(channel, raw, &uv, 1000);
    364		if (ret < 0) {
    365			/* Assume 12 bit ADC with vref at pullup_uv */
    366			uv = (data->pullup_uv * (s64)raw) >> 12;
    367		}
    368	}
    369
    370	return uv;
    371}
    372
    373static inline u64 div64_u64_safe(u64 dividend, u64 divisor)
    374{
    375	if (divisor == 0 && dividend == 0)
    376		return 0;
    377	if (divisor == 0)
    378		return UINT_MAX;
    379	return div64_u64(dividend, divisor);
    380}
    381
    382static int get_ohm_of_thermistor(struct ntc_data *data, unsigned int uv)
    383{
    384	u32 puv = data->pullup_uv;
    385	u64 n, puo, pdo;
    386	puo = data->pullup_ohm;
    387	pdo = data->pulldown_ohm;
    388
    389	if (uv == 0)
    390		return (data->connect == NTC_CONNECTED_POSITIVE) ?
    391			INT_MAX : 0;
    392	if (uv >= puv)
    393		return (data->connect == NTC_CONNECTED_POSITIVE) ?
    394			0 : INT_MAX;
    395
    396	if (data->connect == NTC_CONNECTED_POSITIVE && puo == 0)
    397		n = div_u64(pdo * (puv - uv), uv);
    398	else if (data->connect == NTC_CONNECTED_GROUND && pdo == 0)
    399		n = div_u64(puo * uv, puv - uv);
    400	else if (data->connect == NTC_CONNECTED_POSITIVE)
    401		n = div64_u64_safe(pdo * puo * (puv - uv),
    402				puo * uv - pdo * (puv - uv));
    403	else
    404		n = div64_u64_safe(pdo * puo * uv, pdo * (puv - uv) - puo * uv);
    405
    406	if (n > INT_MAX)
    407		n = INT_MAX;
    408	return n;
    409}
    410
    411static void lookup_comp(struct ntc_data *data, unsigned int ohm,
    412			int *i_low, int *i_high)
    413{
    414	int start, end, mid;
    415
    416	/*
    417	 * Handle special cases: Resistance is higher than or equal to
    418	 * resistance in first table entry, or resistance is lower or equal
    419	 * to resistance in last table entry.
    420	 * In these cases, return i_low == i_high, either pointing to the
    421	 * beginning or to the end of the table depending on the condition.
    422	 */
    423	if (ohm >= data->comp[0].ohm) {
    424		*i_low = 0;
    425		*i_high = 0;
    426		return;
    427	}
    428	if (ohm <= data->comp[data->n_comp - 1].ohm) {
    429		*i_low = data->n_comp - 1;
    430		*i_high = data->n_comp - 1;
    431		return;
    432	}
    433
    434	/* Do a binary search on compensation table */
    435	start = 0;
    436	end = data->n_comp;
    437	while (start < end) {
    438		mid = start + (end - start) / 2;
    439		/*
    440		 * start <= mid < end
    441		 * data->comp[start].ohm > ohm >= data->comp[end].ohm
    442		 *
    443		 * We could check for "ohm == data->comp[mid].ohm" here, but
    444		 * that is a quite unlikely condition, and we would have to
    445		 * check again after updating start. Check it at the end instead
    446		 * for simplicity.
    447		 */
    448		if (ohm >= data->comp[mid].ohm) {
    449			end = mid;
    450		} else {
    451			start = mid + 1;
    452			/*
    453			 * ohm >= data->comp[start].ohm might be true here,
    454			 * since we set start to mid + 1. In that case, we are
    455			 * done. We could keep going, but the condition is quite
    456			 * likely to occur, so it is worth checking for it.
    457			 */
    458			if (ohm >= data->comp[start].ohm)
    459				end = start;
    460		}
    461		/*
    462		 * start <= end
    463		 * data->comp[start].ohm >= ohm >= data->comp[end].ohm
    464		 */
    465	}
    466	/*
    467	 * start == end
    468	 * ohm >= data->comp[end].ohm
    469	 */
    470	*i_low = end;
    471	if (ohm == data->comp[end].ohm)
    472		*i_high = end;
    473	else
    474		*i_high = end - 1;
    475}
    476
    477static int get_temp_mc(struct ntc_data *data, unsigned int ohm)
    478{
    479	int low, high;
    480	int temp;
    481
    482	lookup_comp(data, ohm, &low, &high);
    483	/*
    484	 * First multiplying the table temperatures with 1000 to get to
    485	 * millicentigrades (which is what we want) and then interpolating
    486	 * will give the best precision.
    487	 */
    488	temp = fixp_linear_interpolate(data->comp[low].ohm,
    489				       data->comp[low].temp_c * 1000,
    490				       data->comp[high].ohm,
    491				       data->comp[high].temp_c * 1000,
    492				       ohm);
    493	return temp;
    494}
    495
    496static int ntc_thermistor_get_ohm(struct ntc_data *data)
    497{
    498	int read_uv;
    499
    500	read_uv = ntc_adc_iio_read(data);
    501	if (read_uv < 0)
    502		return read_uv;
    503	return get_ohm_of_thermistor(data, read_uv);
    504}
    505
    506static int ntc_read(struct device *dev, enum hwmon_sensor_types type,
    507		    u32 attr, int channel, long *val)
    508{
    509	struct ntc_data *data = dev_get_drvdata(dev);
    510	int ohm;
    511
    512	switch (type) {
    513	case hwmon_temp:
    514		switch (attr) {
    515		case hwmon_temp_input:
    516			ohm = ntc_thermistor_get_ohm(data);
    517			if (ohm < 0)
    518				return ohm;
    519			*val = get_temp_mc(data, ohm);
    520			return 0;
    521		case hwmon_temp_type:
    522			*val = 4;
    523			return 0;
    524		default:
    525			break;
    526		}
    527		break;
    528	default:
    529		break;
    530	}
    531	return -EINVAL;
    532}
    533
    534static umode_t ntc_is_visible(const void *data, enum hwmon_sensor_types type,
    535			      u32 attr, int channel)
    536{
    537	if (type == hwmon_temp) {
    538		switch (attr) {
    539		case hwmon_temp_input:
    540		case hwmon_temp_type:
    541			return 0444;
    542		default:
    543			break;
    544		}
    545	}
    546	return 0;
    547}
    548
    549static const struct hwmon_channel_info *ntc_info[] = {
    550	HWMON_CHANNEL_INFO(chip, HWMON_C_REGISTER_TZ),
    551	HWMON_CHANNEL_INFO(temp, HWMON_T_INPUT | HWMON_T_TYPE),
    552	NULL
    553};
    554
    555static const struct hwmon_ops ntc_hwmon_ops = {
    556	.is_visible = ntc_is_visible,
    557	.read = ntc_read,
    558};
    559
    560static const struct hwmon_chip_info ntc_chip_info = {
    561	.ops = &ntc_hwmon_ops,
    562	.info = ntc_info,
    563};
    564
    565static int ntc_thermistor_parse_props(struct device *dev,
    566				      struct ntc_data *data)
    567{
    568	struct iio_channel *chan;
    569	enum iio_chan_type type;
    570	int ret;
    571
    572	chan = devm_iio_channel_get(dev, NULL);
    573	if (IS_ERR(chan))
    574		return PTR_ERR(chan);
    575
    576	ret = iio_get_channel_type(chan, &type);
    577	if (ret < 0)
    578		return ret;
    579
    580	if (type != IIO_VOLTAGE)
    581		return -EINVAL;
    582
    583	ret = device_property_read_u32(dev, "pullup-uv", &data->pullup_uv);
    584	if (ret)
    585		return dev_err_probe(dev,  ret, "pullup-uv not specified\n");
    586
    587	ret = device_property_read_u32(dev, "pullup-ohm", &data->pullup_ohm);
    588	if (ret)
    589		return dev_err_probe(dev,  ret, "pullup-ohm not specified\n");
    590
    591	ret = device_property_read_u32(dev, "pulldown-ohm", &data->pulldown_ohm);
    592	if (ret)
    593		return dev_err_probe(dev,  ret, "pulldown-ohm not specified\n");
    594
    595	if (device_property_read_bool(dev, "connected-positive"))
    596		data->connect = NTC_CONNECTED_POSITIVE;
    597	else /* status change should be possible if not always on. */
    598		data->connect = NTC_CONNECTED_GROUND;
    599
    600	data->chan = chan;
    601
    602	return 0;
    603}
    604
    605static int ntc_thermistor_probe(struct platform_device *pdev)
    606{
    607	struct device *dev = &pdev->dev;
    608	const struct platform_device_id *pdev_id;
    609	struct device *hwmon_dev;
    610	struct ntc_data *data;
    611	int ret;
    612
    613	data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
    614	if (!data)
    615		return -ENOMEM;
    616
    617	ret = ntc_thermistor_parse_props(dev, data);
    618	if (ret)
    619		return ret;
    620
    621	if (data->pullup_uv == 0 ||
    622	    (data->pullup_ohm == 0 && data->connect ==
    623	     NTC_CONNECTED_GROUND) ||
    624	    (data->pulldown_ohm == 0 && data->connect ==
    625	     NTC_CONNECTED_POSITIVE) ||
    626	    (data->connect != NTC_CONNECTED_POSITIVE &&
    627	     data->connect != NTC_CONNECTED_GROUND)) {
    628		dev_err(dev, "Required data to use NTC driver not supplied.\n");
    629		return -EINVAL;
    630	}
    631
    632	pdev_id = device_get_match_data(dev);
    633
    634	if (pdev_id->driver_data >= ARRAY_SIZE(ntc_type)) {
    635		dev_err(dev, "Unknown device type: %lu(%s)\n",
    636				pdev_id->driver_data, pdev_id->name);
    637		return -EINVAL;
    638	}
    639
    640	data->comp   = ntc_type[pdev_id->driver_data].comp;
    641	data->n_comp = ntc_type[pdev_id->driver_data].n_comp;
    642
    643	hwmon_dev = devm_hwmon_device_register_with_info(dev, pdev_id->name,
    644							 data, &ntc_chip_info,
    645							 NULL);
    646	if (IS_ERR(hwmon_dev)) {
    647		dev_err(dev, "unable to register as hwmon device.\n");
    648		return PTR_ERR(hwmon_dev);
    649	}
    650
    651	dev_info(dev, "Thermistor type: %s successfully probed.\n",
    652		 pdev_id->name);
    653
    654	return 0;
    655}
    656
    657static const struct of_device_id ntc_match[] = {
    658	{ .compatible = "epcos,b57330v2103",
    659		.data = &ntc_thermistor_id[NTC_B57330V2103]},
    660	{ .compatible = "epcos,b57891s0103",
    661		.data = &ntc_thermistor_id[NTC_B57891S0103] },
    662	{ .compatible = "murata,ncp03wb473",
    663		.data = &ntc_thermistor_id[NTC_NCP03WB473] },
    664	{ .compatible = "murata,ncp03wf104",
    665		.data = &ntc_thermistor_id[NTC_NCP03WF104] },
    666	{ .compatible = "murata,ncp15wb473",
    667		.data = &ntc_thermistor_id[NTC_NCP15WB473] },
    668	{ .compatible = "murata,ncp15wl333",
    669		.data = &ntc_thermistor_id[NTC_NCP15WL333] },
    670	{ .compatible = "murata,ncp15xh103",
    671		.data = &ntc_thermistor_id[NTC_NCP15XH103] },
    672	{ .compatible = "murata,ncp18wb473",
    673		.data = &ntc_thermistor_id[NTC_NCP18WB473] },
    674	{ .compatible = "murata,ncp21wb473",
    675		.data = &ntc_thermistor_id[NTC_NCP21WB473] },
    676	{ .compatible = "samsung,1404-001221",
    677		.data = &ntc_thermistor_id[NTC_SSG1404001221] },
    678
    679	/* Usage of vendor name "ntc" is deprecated */
    680	{ .compatible = "ntc,ncp03wb473",
    681		.data = &ntc_thermistor_id[NTC_NCP03WB473] },
    682	{ .compatible = "ntc,ncp15wb473",
    683		.data = &ntc_thermistor_id[NTC_NCP15WB473] },
    684	{ .compatible = "ntc,ncp15wl333",
    685		.data = &ntc_thermistor_id[NTC_NCP15WL333] },
    686	{ .compatible = "ntc,ncp18wb473",
    687		.data = &ntc_thermistor_id[NTC_NCP18WB473] },
    688	{ .compatible = "ntc,ncp21wb473",
    689		.data = &ntc_thermistor_id[NTC_NCP21WB473] },
    690	{ },
    691};
    692MODULE_DEVICE_TABLE(of, ntc_match);
    693
    694static struct platform_driver ntc_thermistor_driver = {
    695	.driver = {
    696		.name = "ntc-thermistor",
    697		.of_match_table = ntc_match,
    698	},
    699	.probe = ntc_thermistor_probe,
    700	.id_table = ntc_thermistor_id,
    701};
    702
    703module_platform_driver(ntc_thermistor_driver);
    704
    705MODULE_DESCRIPTION("NTC Thermistor Driver");
    706MODULE_AUTHOR("MyungJoo Ham <myungjoo.ham@samsung.com>");
    707MODULE_LICENSE("GPL");
    708MODULE_ALIAS("platform:ntc-thermistor");