ntc_thermistor.c 18 KB

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