Blame view

drivers/hwmon/ntc_thermistor.c 14.3 KB
f22aaaa70   Donggeun Kim   hwmon: Driver for...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
  /*
   * ntc_thermistor.c - NTC Thermistors
   *
   *  Copyright (C) 2010 Samsung Electronics
   *  MyungJoo Ham <myungjoo.ham@samsung.com>
   *
   * This program is free software; you can redistribute it and/or modify
   * it under the terms of the GNU General Public License as published by
   * the Free Software Foundation; either version 2 of the License, or
   * (at your option) any later version.
   *
   * This program is distributed in the hope that it will be useful,
   * but WITHOUT ANY WARRANTY; without even the implied warranty of
   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   * GNU General Public License for more details.
   *
   * You should have received a copy of the GNU General Public License
   * along with this program; if not, write to the Free Software
   * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
   *
   */
  
  #include <linux/slab.h>
  #include <linux/module.h>
  #include <linux/pm_runtime.h>
  #include <linux/math64.h>
  #include <linux/platform_device.h>
  #include <linux/err.h>
9e8269de1   Naveen Krishna Chatradhi   hwmon: (ntc_therm...
29
30
  #include <linux/of.h>
  #include <linux/of_device.h>
f22aaaa70   Donggeun Kim   hwmon: Driver for...
31
32
  
  #include <linux/platform_data/ntc_thermistor.h>
9e8269de1   Naveen Krishna Chatradhi   hwmon: (ntc_therm...
33
34
35
36
  #include <linux/iio/iio.h>
  #include <linux/iio/machine.h>
  #include <linux/iio/driver.h>
  #include <linux/iio/consumer.h>
f22aaaa70   Donggeun Kim   hwmon: Driver for...
37
38
39
40
  #include <linux/hwmon.h>
  #include <linux/hwmon-sysfs.h>
  
  struct ntc_compensation {
088ce2ac9   Guenter Roeck   hwmon: Fix CamelC...
41
  	int		temp_c;
f22aaaa70   Donggeun Kim   hwmon: Driver for...
42
43
  	unsigned int	ohm;
  };
9e8269de1   Naveen Krishna Chatradhi   hwmon: (ntc_therm...
44
45
46
47
48
49
50
51
  static const struct platform_device_id ntc_thermistor_id[] = {
  	{ "ncp15wb473", TYPE_NCPXXWB473 },
  	{ "ncp18wb473", TYPE_NCPXXWB473 },
  	{ "ncp21wb473", TYPE_NCPXXWB473 },
  	{ "ncp03wb473", TYPE_NCPXXWB473 },
  	{ "ncp15wl333", TYPE_NCPXXWL333 },
  	{ },
  };
f22aaaa70   Donggeun Kim   hwmon: Driver for...
52
53
54
55
56
57
  /*
   * A compensation table should be sorted by the values of .ohm
   * in descending order.
   * The following compensation tables are from the specification of Murata NTC
   * Thermistors Datasheet
   */
4626dcff7   Sachin Kamat   hwmon: (ntc_therm...
58
  static const struct ntc_compensation ncpXXwb473[] = {
088ce2ac9   Guenter Roeck   hwmon: Fix CamelC...
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
  	{ .temp_c	= -40, .ohm	= 1747920 },
  	{ .temp_c	= -35, .ohm	= 1245428 },
  	{ .temp_c	= -30, .ohm	= 898485 },
  	{ .temp_c	= -25, .ohm	= 655802 },
  	{ .temp_c	= -20, .ohm	= 483954 },
  	{ .temp_c	= -15, .ohm	= 360850 },
  	{ .temp_c	= -10, .ohm	= 271697 },
  	{ .temp_c	= -5, .ohm	= 206463 },
  	{ .temp_c	= 0, .ohm	= 158214 },
  	{ .temp_c	= 5, .ohm	= 122259 },
  	{ .temp_c	= 10, .ohm	= 95227 },
  	{ .temp_c	= 15, .ohm	= 74730 },
  	{ .temp_c	= 20, .ohm	= 59065 },
  	{ .temp_c	= 25, .ohm	= 47000 },
  	{ .temp_c	= 30, .ohm	= 37643 },
  	{ .temp_c	= 35, .ohm	= 30334 },
  	{ .temp_c	= 40, .ohm	= 24591 },
  	{ .temp_c	= 45, .ohm	= 20048 },
  	{ .temp_c	= 50, .ohm	= 16433 },
  	{ .temp_c	= 55, .ohm	= 13539 },
  	{ .temp_c	= 60, .ohm	= 11209 },
  	{ .temp_c	= 65, .ohm	= 9328 },
  	{ .temp_c	= 70, .ohm	= 7798 },
  	{ .temp_c	= 75, .ohm	= 6544 },
  	{ .temp_c	= 80, .ohm	= 5518 },
  	{ .temp_c	= 85, .ohm	= 4674 },
  	{ .temp_c	= 90, .ohm	= 3972 },
  	{ .temp_c	= 95, .ohm	= 3388 },
  	{ .temp_c	= 100, .ohm	= 2902 },
  	{ .temp_c	= 105, .ohm	= 2494 },
  	{ .temp_c	= 110, .ohm	= 2150 },
  	{ .temp_c	= 115, .ohm	= 1860 },
  	{ .temp_c	= 120, .ohm	= 1615 },
  	{ .temp_c	= 125, .ohm	= 1406 },
f22aaaa70   Donggeun Kim   hwmon: Driver for...
93
  };
4626dcff7   Sachin Kamat   hwmon: (ntc_therm...
94
  static const struct ntc_compensation ncpXXwl333[] = {
088ce2ac9   Guenter Roeck   hwmon: Fix CamelC...
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
  	{ .temp_c	= -40, .ohm	= 1610154 },
  	{ .temp_c	= -35, .ohm	= 1130850 },
  	{ .temp_c	= -30, .ohm	= 802609 },
  	{ .temp_c	= -25, .ohm	= 575385 },
  	{ .temp_c	= -20, .ohm	= 416464 },
  	{ .temp_c	= -15, .ohm	= 304219 },
  	{ .temp_c	= -10, .ohm	= 224193 },
  	{ .temp_c	= -5, .ohm	= 166623 },
  	{ .temp_c	= 0, .ohm	= 124850 },
  	{ .temp_c	= 5, .ohm	= 94287 },
  	{ .temp_c	= 10, .ohm	= 71747 },
  	{ .temp_c	= 15, .ohm	= 54996 },
  	{ .temp_c	= 20, .ohm	= 42455 },
  	{ .temp_c	= 25, .ohm	= 33000 },
  	{ .temp_c	= 30, .ohm	= 25822 },
  	{ .temp_c	= 35, .ohm	= 20335 },
  	{ .temp_c	= 40, .ohm	= 16115 },
  	{ .temp_c	= 45, .ohm	= 12849 },
  	{ .temp_c	= 50, .ohm	= 10306 },
  	{ .temp_c	= 55, .ohm	= 8314 },
  	{ .temp_c	= 60, .ohm	= 6746 },
  	{ .temp_c	= 65, .ohm	= 5503 },
  	{ .temp_c	= 70, .ohm	= 4513 },
  	{ .temp_c	= 75, .ohm	= 3721 },
  	{ .temp_c	= 80, .ohm	= 3084 },
  	{ .temp_c	= 85, .ohm	= 2569 },
  	{ .temp_c	= 90, .ohm	= 2151 },
  	{ .temp_c	= 95, .ohm	= 1809 },
  	{ .temp_c	= 100, .ohm	= 1529 },
  	{ .temp_c	= 105, .ohm	= 1299 },
  	{ .temp_c	= 110, .ohm	= 1108 },
  	{ .temp_c	= 115, .ohm	= 949 },
  	{ .temp_c	= 120, .ohm	= 817 },
  	{ .temp_c	= 125, .ohm	= 707 },
f22aaaa70   Donggeun Kim   hwmon: Driver for...
129
130
131
132
133
134
135
136
137
138
  };
  
  struct ntc_data {
  	struct device *hwmon_dev;
  	struct ntc_thermistor_platform_data *pdata;
  	const struct ntc_compensation *comp;
  	struct device *dev;
  	int n_comp;
  	char name[PLATFORM_NAME_SIZE];
  };
9e8269de1   Naveen Krishna Chatradhi   hwmon: (ntc_therm...
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
  #ifdef CONFIG_OF
  static int ntc_adc_iio_read(struct ntc_thermistor_platform_data *pdata)
  {
  	struct iio_channel *channel = pdata->chan;
  	unsigned int result;
  	int val, ret;
  
  	ret = iio_read_channel_raw(channel, &val);
  	if (ret < 0) {
  		pr_err("read channel() error: %d
  ", ret);
  		return ret;
  	}
  
  	/* unit: mV */
088ce2ac9   Guenter Roeck   hwmon: Fix CamelC...
154
  	result = pdata->pullup_uv * val;
9e8269de1   Naveen Krishna Chatradhi   hwmon: (ntc_therm...
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
  	result >>= 12;
  
  	return result;
  }
  
  static const struct of_device_id ntc_match[] = {
  	{ .compatible = "ntc,ncp15wb473",
  		.data = &ntc_thermistor_id[TYPE_NCPXXWB473] },
  	{ .compatible = "ntc,ncp18wb473",
  		.data = &ntc_thermistor_id[TYPE_NCPXXWB473] },
  	{ .compatible = "ntc,ncp21wb473",
  		.data = &ntc_thermistor_id[TYPE_NCPXXWB473] },
  	{ .compatible = "ntc,ncp03wb473",
  		.data = &ntc_thermistor_id[TYPE_NCPXXWB473] },
  	{ .compatible = "ntc,ncp15wl333",
  		.data = &ntc_thermistor_id[TYPE_NCPXXWL333] },
  	{ },
  };
  MODULE_DEVICE_TABLE(of, ntc_match);
  
  static struct ntc_thermistor_platform_data *
  ntc_thermistor_parse_dt(struct platform_device *pdev)
  {
  	struct iio_channel *chan;
  	struct device_node *np = pdev->dev.of_node;
  	struct ntc_thermistor_platform_data *pdata;
  
  	if (!np)
  		return NULL;
  
  	pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
  	if (!pdata)
  		return ERR_PTR(-ENOMEM);
  
  	chan = iio_channel_get(&pdev->dev, NULL);
  	if (IS_ERR(chan))
  		return ERR_CAST(chan);
088ce2ac9   Guenter Roeck   hwmon: Fix CamelC...
192
  	if (of_property_read_u32(np, "pullup-uv", &pdata->pullup_uv))
9e8269de1   Naveen Krishna Chatradhi   hwmon: (ntc_therm...
193
194
195
196
197
198
199
200
201
202
203
204
  		return ERR_PTR(-ENODEV);
  	if (of_property_read_u32(np, "pullup-ohm", &pdata->pullup_ohm))
  		return ERR_PTR(-ENODEV);
  	if (of_property_read_u32(np, "pulldown-ohm", &pdata->pulldown_ohm))
  		return ERR_PTR(-ENODEV);
  
  	if (of_find_property(np, "connected-positive", NULL))
  		pdata->connect = NTC_CONNECTED_POSITIVE;
  	else /* status change should be possible if not always on. */
  		pdata->connect = NTC_CONNECTED_GROUND;
  
  	pdata->chan = chan;
088ce2ac9   Guenter Roeck   hwmon: Fix CamelC...
205
  	pdata->read_uv = ntc_adc_iio_read;
9e8269de1   Naveen Krishna Chatradhi   hwmon: (ntc_therm...
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
  
  	return pdata;
  }
  static void ntc_iio_channel_release(struct ntc_thermistor_platform_data *pdata)
  {
  	if (pdata->chan)
  		iio_channel_release(pdata->chan);
  }
  #else
  static struct ntc_thermistor_platform_data *
  ntc_thermistor_parse_dt(struct platform_device *pdev)
  {
  	return NULL;
  }
  
  static void ntc_iio_channel_release(struct ntc_thermistor_platform_data *pdata)
  { }
  #endif
f22aaaa70   Donggeun Kim   hwmon: Driver for...
224
225
226
227
228
229
230
231
  static inline u64 div64_u64_safe(u64 dividend, u64 divisor)
  {
  	if (divisor == 0 && dividend == 0)
  		return 0;
  	if (divisor == 0)
  		return UINT_MAX;
  	return div64_u64(dividend, divisor);
  }
088ce2ac9   Guenter Roeck   hwmon: Fix CamelC...
232
  static int get_ohm_of_thermistor(struct ntc_data *data, unsigned int uv)
f22aaaa70   Donggeun Kim   hwmon: Driver for...
233
234
  {
  	struct ntc_thermistor_platform_data *pdata = data->pdata;
088ce2ac9   Guenter Roeck   hwmon: Fix CamelC...
235
236
237
238
239
  	u64 mv = uv / 1000;
  	u64 pmv = pdata->pullup_uv / 1000;
  	u64 n, puo, pdo;
  	puo = pdata->pullup_ohm;
  	pdo = pdata->pulldown_ohm;
f22aaaa70   Donggeun Kim   hwmon: Driver for...
240

088ce2ac9   Guenter Roeck   hwmon: Fix CamelC...
241
  	if (mv == 0) {
f22aaaa70   Donggeun Kim   hwmon: Driver for...
242
  		if (pdata->connect == NTC_CONNECTED_POSITIVE)
dbe43a627   Guenter Roeck   hwmon: (ntc_therm...
243
  			return INT_MAX;
f22aaaa70   Donggeun Kim   hwmon: Driver for...
244
245
  		return 0;
  	}
088ce2ac9   Guenter Roeck   hwmon: Fix CamelC...
246
  	if (mv >= pmv)
f22aaaa70   Donggeun Kim   hwmon: Driver for...
247
  		return (pdata->connect == NTC_CONNECTED_POSITIVE) ?
dbe43a627   Guenter Roeck   hwmon: (ntc_therm...
248
  			0 : INT_MAX;
f22aaaa70   Donggeun Kim   hwmon: Driver for...
249

088ce2ac9   Guenter Roeck   hwmon: Fix CamelC...
250
251
252
253
  	if (pdata->connect == NTC_CONNECTED_POSITIVE && puo == 0)
  		n = div64_u64_safe(pdo * (pmv - mv), mv);
  	else if (pdata->connect == NTC_CONNECTED_GROUND && pdo == 0)
  		n = div64_u64_safe(puo * mv, pmv - mv);
f22aaaa70   Donggeun Kim   hwmon: Driver for...
254
  	else if (pdata->connect == NTC_CONNECTED_POSITIVE)
088ce2ac9   Guenter Roeck   hwmon: Fix CamelC...
255
256
  		n = div64_u64_safe(pdo * puo * (pmv - mv),
  				puo * mv - pdo * (pmv - mv));
f22aaaa70   Donggeun Kim   hwmon: Driver for...
257
  	else
088ce2ac9   Guenter Roeck   hwmon: Fix CamelC...
258
  		n = div64_u64_safe(pdo * puo * mv, pdo * (pmv - mv) - puo * mv);
f22aaaa70   Donggeun Kim   hwmon: Driver for...
259

088ce2ac9   Guenter Roeck   hwmon: Fix CamelC...
260
261
262
  	if (n > INT_MAX)
  		n = INT_MAX;
  	return n;
f22aaaa70   Donggeun Kim   hwmon: Driver for...
263
  }
dbe43a627   Guenter Roeck   hwmon: (ntc_therm...
264
265
  static void lookup_comp(struct ntc_data *data, unsigned int ohm,
  			int *i_low, int *i_high)
f22aaaa70   Donggeun Kim   hwmon: Driver for...
266
  {
dbe43a627   Guenter Roeck   hwmon: (ntc_therm...
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
  	int start, end, mid;
  
  	/*
  	 * Handle special cases: Resistance is higher than or equal to
  	 * resistance in first table entry, or resistance is lower or equal
  	 * to resistance in last table entry.
  	 * In these cases, return i_low == i_high, either pointing to the
  	 * beginning or to the end of the table depending on the condition.
  	 */
  	if (ohm >= data->comp[0].ohm) {
  		*i_low = 0;
  		*i_high = 0;
  		return;
  	}
  	if (ohm <= data->comp[data->n_comp - 1].ohm) {
  		*i_low = data->n_comp - 1;
  		*i_high = data->n_comp - 1;
  		return;
  	}
f22aaaa70   Donggeun Kim   hwmon: Driver for...
286
287
288
289
  
  	/* Do a binary search on compensation table */
  	start = 0;
  	end = data->n_comp;
dbe43a627   Guenter Roeck   hwmon: (ntc_therm...
290
  	while (start < end) {
f22aaaa70   Donggeun Kim   hwmon: Driver for...
291
  		mid = start + (end - start) / 2;
dbe43a627   Guenter Roeck   hwmon: (ntc_therm...
292
293
294
295
296
297
298
299
300
301
  		/*
  		 * start <= mid < end
  		 * data->comp[start].ohm > ohm >= data->comp[end].ohm
  		 *
  		 * We could check for "ohm == data->comp[mid].ohm" here, but
  		 * that is a quite unlikely condition, and we would have to
  		 * check again after updating start. Check it at the end instead
  		 * for simplicity.
  		 */
  		if (ohm >= data->comp[mid].ohm) {
f22aaaa70   Donggeun Kim   hwmon: Driver for...
302
  			end = mid;
f22aaaa70   Donggeun Kim   hwmon: Driver for...
303
  		} else {
dbe43a627   Guenter Roeck   hwmon: (ntc_therm...
304
305
306
307
308
309
310
311
312
  			start = mid + 1;
  			/*
  			 * ohm >= data->comp[start].ohm might be true here,
  			 * since we set start to mid + 1. In that case, we are
  			 * done. We could keep going, but the condition is quite
  			 * likely to occur, so it is worth checking for it.
  			 */
  			if (ohm >= data->comp[start].ohm)
  				end = start;
f22aaaa70   Donggeun Kim   hwmon: Driver for...
313
  		}
dbe43a627   Guenter Roeck   hwmon: (ntc_therm...
314
315
316
317
  		/*
  		 * start <= end
  		 * data->comp[start].ohm >= ohm >= data->comp[end].ohm
  		 */
f22aaaa70   Donggeun Kim   hwmon: Driver for...
318
  	}
dbe43a627   Guenter Roeck   hwmon: (ntc_therm...
319
320
321
322
323
324
325
326
327
  	/*
  	 * start == end
  	 * ohm >= data->comp[end].ohm
  	 */
  	*i_low = end;
  	if (ohm == data->comp[end].ohm)
  		*i_high = end;
  	else
  		*i_high = end - 1;
f22aaaa70   Donggeun Kim   hwmon: Driver for...
328
  }
088ce2ac9   Guenter Roeck   hwmon: Fix CamelC...
329
  static int get_temp_mc(struct ntc_data *data, unsigned int ohm)
f22aaaa70   Donggeun Kim   hwmon: Driver for...
330
331
  {
  	int low, high;
dbe43a627   Guenter Roeck   hwmon: (ntc_therm...
332
  	int temp;
f22aaaa70   Donggeun Kim   hwmon: Driver for...
333

dbe43a627   Guenter Roeck   hwmon: (ntc_therm...
334
335
  	lookup_comp(data, ohm, &low, &high);
  	if (low == high) {
f22aaaa70   Donggeun Kim   hwmon: Driver for...
336
  		/* Unable to use linear approximation */
088ce2ac9   Guenter Roeck   hwmon: Fix CamelC...
337
  		temp = data->comp[low].temp_c * 1000;
f22aaaa70   Donggeun Kim   hwmon: Driver for...
338
  	} else {
088ce2ac9   Guenter Roeck   hwmon: Fix CamelC...
339
340
  		temp = data->comp[low].temp_c * 1000 +
  			((data->comp[high].temp_c - data->comp[low].temp_c) *
f22aaaa70   Donggeun Kim   hwmon: Driver for...
341
342
343
  			 1000 * ((int)ohm - (int)data->comp[low].ohm)) /
  			((int)data->comp[high].ohm - (int)data->comp[low].ohm);
  	}
dbe43a627   Guenter Roeck   hwmon: (ntc_therm...
344
  	return temp;
f22aaaa70   Donggeun Kim   hwmon: Driver for...
345
  }
dbe43a627   Guenter Roeck   hwmon: (ntc_therm...
346
  static int ntc_thermistor_get_ohm(struct ntc_data *data)
f22aaaa70   Donggeun Kim   hwmon: Driver for...
347
  {
088ce2ac9   Guenter Roeck   hwmon: Fix CamelC...
348
  	int read_uv;
f22aaaa70   Donggeun Kim   hwmon: Driver for...
349

dbe43a627   Guenter Roeck   hwmon: (ntc_therm...
350
351
  	if (data->pdata->read_ohm)
  		return data->pdata->read_ohm();
f22aaaa70   Donggeun Kim   hwmon: Driver for...
352

088ce2ac9   Guenter Roeck   hwmon: Fix CamelC...
353
354
355
356
357
  	if (data->pdata->read_uv) {
  		read_uv = data->pdata->read_uv(data->pdata);
  		if (read_uv < 0)
  			return read_uv;
  		return get_ohm_of_thermistor(data, read_uv);
f22aaaa70   Donggeun Kim   hwmon: Driver for...
358
  	}
dbe43a627   Guenter Roeck   hwmon: (ntc_therm...
359
  	return -EINVAL;
f22aaaa70   Donggeun Kim   hwmon: Driver for...
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
  }
  
  static ssize_t ntc_show_name(struct device *dev,
  		struct device_attribute *attr, char *buf)
  {
  	struct ntc_data *data = dev_get_drvdata(dev);
  
  	return sprintf(buf, "%s
  ", data->name);
  }
  
  static ssize_t ntc_show_type(struct device *dev,
  		struct device_attribute *attr, char *buf)
  {
  	return sprintf(buf, "4
  ");
  }
  
  static ssize_t ntc_show_temp(struct device *dev,
  		struct device_attribute *attr, char *buf)
  {
  	struct ntc_data *data = dev_get_drvdata(dev);
dbe43a627   Guenter Roeck   hwmon: (ntc_therm...
382
383
384
385
386
  	int ohm;
  
  	ohm = ntc_thermistor_get_ohm(data);
  	if (ohm < 0)
  		return ohm;
f22aaaa70   Donggeun Kim   hwmon: Driver for...
387

088ce2ac9   Guenter Roeck   hwmon: Fix CamelC...
388
389
  	return sprintf(buf, "%d
  ", get_temp_mc(data, ohm));
f22aaaa70   Donggeun Kim   hwmon: Driver for...
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
  }
  
  static SENSOR_DEVICE_ATTR(temp1_type, S_IRUGO, ntc_show_type, NULL, 0);
  static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, ntc_show_temp, NULL, 0);
  static DEVICE_ATTR(name, S_IRUGO, ntc_show_name, NULL);
  
  static struct attribute *ntc_attributes[] = {
  	&dev_attr_name.attr,
  	&sensor_dev_attr_temp1_type.dev_attr.attr,
  	&sensor_dev_attr_temp1_input.dev_attr.attr,
  	NULL,
  };
  
  static const struct attribute_group ntc_attr_group = {
  	.attrs = ntc_attributes,
  };
6c931ae1c   Bill Pemberton   hwmon: remove use...
406
  static int ntc_thermistor_probe(struct platform_device *pdev)
f22aaaa70   Donggeun Kim   hwmon: Driver for...
407
  {
9e8269de1   Naveen Krishna Chatradhi   hwmon: (ntc_therm...
408
409
410
411
  	const struct of_device_id *of_id =
  			of_match_device(of_match_ptr(ntc_match), &pdev->dev);
  	const struct platform_device_id *pdev_id;
  	struct ntc_thermistor_platform_data *pdata;
f22aaaa70   Donggeun Kim   hwmon: Driver for...
412
  	struct ntc_data *data;
9e8269de1   Naveen Krishna Chatradhi   hwmon: (ntc_therm...
413
414
415
416
417
418
419
  	int ret;
  
  	pdata = ntc_thermistor_parse_dt(pdev);
  	if (IS_ERR(pdata))
  		return PTR_ERR(pdata);
  	else if (pdata == NULL)
  		pdata = pdev->dev.platform_data;
f22aaaa70   Donggeun Kim   hwmon: Driver for...
420
421
422
423
424
425
426
427
  
  	if (!pdata) {
  		dev_err(&pdev->dev, "No platform init data supplied.
  ");
  		return -ENODEV;
  	}
  
  	/* Either one of the two is required. */
088ce2ac9   Guenter Roeck   hwmon: Fix CamelC...
428
  	if (!pdata->read_uv && !pdata->read_ohm) {
a7871def6   Guenter Roeck   hwmon: (ntc_therm...
429
  		dev_err(&pdev->dev,
088ce2ac9   Guenter Roeck   hwmon: Fix CamelC...
430
431
  			"Both read_uv and read_ohm missing. Need either one of the two.
  ");
f22aaaa70   Donggeun Kim   hwmon: Driver for...
432
433
  		return -EINVAL;
  	}
088ce2ac9   Guenter Roeck   hwmon: Fix CamelC...
434
  	if (pdata->read_uv && pdata->read_ohm) {
a7871def6   Guenter Roeck   hwmon: (ntc_therm...
435
  		dev_warn(&pdev->dev,
088ce2ac9   Guenter Roeck   hwmon: Fix CamelC...
436
437
438
  			 "Only one of read_uv and read_ohm is needed; ignoring read_uv.
  ");
  		pdata->read_uv = NULL;
f22aaaa70   Donggeun Kim   hwmon: Driver for...
439
  	}
088ce2ac9   Guenter Roeck   hwmon: Fix CamelC...
440
  	if (pdata->read_uv && (pdata->pullup_uv == 0 ||
f22aaaa70   Donggeun Kim   hwmon: Driver for...
441
442
443
444
445
446
  				(pdata->pullup_ohm == 0 && pdata->connect ==
  				 NTC_CONNECTED_GROUND) ||
  				(pdata->pulldown_ohm == 0 && pdata->connect ==
  				 NTC_CONNECTED_POSITIVE) ||
  				(pdata->connect != NTC_CONNECTED_POSITIVE &&
  				 pdata->connect != NTC_CONNECTED_GROUND))) {
a7871def6   Guenter Roeck   hwmon: (ntc_therm...
447
  		dev_err(&pdev->dev,
088ce2ac9   Guenter Roeck   hwmon: Fix CamelC...
448
449
  			"Required data to use read_uv not supplied.
  ");
f22aaaa70   Donggeun Kim   hwmon: Driver for...
450
451
  		return -EINVAL;
  	}
41141e64e   Guenter Roeck   hwmon: (ntc_therm...
452
  	data = devm_kzalloc(&pdev->dev, sizeof(struct ntc_data), GFP_KERNEL);
f22aaaa70   Donggeun Kim   hwmon: Driver for...
453
454
  	if (!data)
  		return -ENOMEM;
9e8269de1   Naveen Krishna Chatradhi   hwmon: (ntc_therm...
455
  	pdev_id = of_id ? of_id->data : platform_get_device_id(pdev);
f22aaaa70   Donggeun Kim   hwmon: Driver for...
456
457
  	data->dev = &pdev->dev;
  	data->pdata = pdata;
9e8269de1   Naveen Krishna Chatradhi   hwmon: (ntc_therm...
458
  	strlcpy(data->name, pdev_id->name, sizeof(data->name));
f22aaaa70   Donggeun Kim   hwmon: Driver for...
459

9e8269de1   Naveen Krishna Chatradhi   hwmon: (ntc_therm...
460
  	switch (pdev_id->driver_data) {
f22aaaa70   Donggeun Kim   hwmon: Driver for...
461
462
463
464
465
466
467
468
469
470
471
  	case TYPE_NCPXXWB473:
  		data->comp = ncpXXwb473;
  		data->n_comp = ARRAY_SIZE(ncpXXwb473);
  		break;
  	case TYPE_NCPXXWL333:
  		data->comp = ncpXXwl333;
  		data->n_comp = ARRAY_SIZE(ncpXXwl333);
  		break;
  	default:
  		dev_err(&pdev->dev, "Unknown device type: %lu(%s)
  ",
9e8269de1   Naveen Krishna Chatradhi   hwmon: (ntc_therm...
472
  				pdev_id->driver_data, pdev_id->name);
41141e64e   Guenter Roeck   hwmon: (ntc_therm...
473
  		return -EINVAL;
f22aaaa70   Donggeun Kim   hwmon: Driver for...
474
475
476
477
478
479
480
481
  	}
  
  	platform_set_drvdata(pdev, data);
  
  	ret = sysfs_create_group(&data->dev->kobj, &ntc_attr_group);
  	if (ret) {
  		dev_err(data->dev, "unable to create sysfs files
  ");
41141e64e   Guenter Roeck   hwmon: (ntc_therm...
482
  		return ret;
f22aaaa70   Donggeun Kim   hwmon: Driver for...
483
484
485
  	}
  
  	data->hwmon_dev = hwmon_device_register(data->dev);
425d24768   Guenter Roeck   hwmon: (ntc_therm...
486
  	if (IS_ERR(data->hwmon_dev)) {
f22aaaa70   Donggeun Kim   hwmon: Driver for...
487
488
  		dev_err(data->dev, "unable to register as hwmon device.
  ");
425d24768   Guenter Roeck   hwmon: (ntc_therm...
489
  		ret = PTR_ERR(data->hwmon_dev);
f22aaaa70   Donggeun Kim   hwmon: Driver for...
490
491
  		goto err_after_sysfs;
  	}
9e8269de1   Naveen Krishna Chatradhi   hwmon: (ntc_therm...
492
493
494
  	dev_info(&pdev->dev, "Thermistor type: %s successfully probed.
  ",
  								pdev->name);
f22aaaa70   Donggeun Kim   hwmon: Driver for...
495
496
497
  	return 0;
  err_after_sysfs:
  	sysfs_remove_group(&data->dev->kobj, &ntc_attr_group);
9e8269de1   Naveen Krishna Chatradhi   hwmon: (ntc_therm...
498
  	ntc_iio_channel_release(pdata);
f22aaaa70   Donggeun Kim   hwmon: Driver for...
499
500
  	return ret;
  }
281dfd0b6   Bill Pemberton   hwmon: remove use...
501
  static int ntc_thermistor_remove(struct platform_device *pdev)
f22aaaa70   Donggeun Kim   hwmon: Driver for...
502
503
  {
  	struct ntc_data *data = platform_get_drvdata(pdev);
9e8269de1   Naveen Krishna Chatradhi   hwmon: (ntc_therm...
504
  	struct ntc_thermistor_platform_data *pdata = data->pdata;
f22aaaa70   Donggeun Kim   hwmon: Driver for...
505
506
507
  
  	hwmon_device_unregister(data->hwmon_dev);
  	sysfs_remove_group(&data->dev->kobj, &ntc_attr_group);
9e8269de1   Naveen Krishna Chatradhi   hwmon: (ntc_therm...
508
  	ntc_iio_channel_release(pdata);
f22aaaa70   Donggeun Kim   hwmon: Driver for...
509
  	platform_set_drvdata(pdev, NULL);
f22aaaa70   Donggeun Kim   hwmon: Driver for...
510
511
  	return 0;
  }
f22aaaa70   Donggeun Kim   hwmon: Driver for...
512
513
514
515
  static struct platform_driver ntc_thermistor_driver = {
  	.driver = {
  		.name = "ntc-thermistor",
  		.owner = THIS_MODULE,
9e8269de1   Naveen Krishna Chatradhi   hwmon: (ntc_therm...
516
  		.of_match_table = of_match_ptr(ntc_match),
f22aaaa70   Donggeun Kim   hwmon: Driver for...
517
518
  	},
  	.probe = ntc_thermistor_probe,
9e5e9b7a9   Bill Pemberton   hwmon: remove use...
519
  	.remove = ntc_thermistor_remove,
f22aaaa70   Donggeun Kim   hwmon: Driver for...
520
521
  	.id_table = ntc_thermistor_id,
  };
25a236a5d   Axel Lin   hwmon: convert dr...
522
  module_platform_driver(ntc_thermistor_driver);
f22aaaa70   Donggeun Kim   hwmon: Driver for...
523
524
525
526
527
  
  MODULE_DESCRIPTION("NTC Thermistor Driver");
  MODULE_AUTHOR("MyungJoo Ham <myungjoo.ham@samsung.com>");
  MODULE_LICENSE("GPL");
  MODULE_ALIAS("platform:ntc-thermistor");