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