PageRenderTime 38ms CodeModel.GetById 14ms app.highlight 21ms RepoModel.GetById 0ms app.codeStats 0ms

/drivers/hwmon/m_adcproc.c

https://bitbucket.org/cresqo/cm7-p500-kernel
C | 474 lines | 387 code | 39 blank | 48 comment | 43 complexity | 96ad4dceebbd7daee89d7e7cc52a8ab2 MD5 | raw file
Possible License(s): LGPL-2.0, AGPL-1.0, GPL-2.0
  1/* Copyright (c) 2010, Code Aurora Forum. All rights reserved.
  2 *
  3 * This program is free software; you can redistribute it and/or modify
  4 * it under the terms of the GNU General Public License version 2 and
  5 * only version 2 as published by the Free Software Foundation.
  6 *
  7 * This program is distributed in the hope that it will be useful,
  8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 10 * GNU General Public License for more details.
 11 *
 12 * You should have received a copy of the GNU General Public License
 13 * along with this program; if not, write to the Free Software
 14 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
 15 * 02110-1301, USA.
 16 */
 17
 18#include <linux/kernel.h>
 19
 20#include <linux/m_adc.h>
 21
 22#define KELVINMIL_DEGMIL	273160
 23
 24static const struct adc_map_pt adcmap_batttherm[] = {
 25	{2020,	-30},
 26	{1923,	-20},
 27	{1796,	-10},
 28	{1640,	  0},
 29	{1459,	 10},
 30	{1260,	 20},
 31	{1159,	 25},
 32	{1059,	 30},
 33	{871,	 40},
 34	{706,	 50},
 35	{567,	 60},
 36	{453,	 70},
 37	{364,	 80}
 38};
 39
 40static const struct adc_map_pt adcmap_msmtherm[] = {
 41	{2150,	-30},
 42	{2107,	-20},
 43	{2037,	-10},
 44	{1929,	  0},
 45	{1776,	 10},
 46	{1579,	 20},
 47	{1467,	 25},
 48	{1349,	 30},
 49	{1108,	 40},
 50	{878,	 50},
 51	{677,	 60},
 52	{513,	 70},
 53	{385,	 80},
 54	{287,	 90},
 55	{215,	100},
 56	{186,	110},
 57	{107,	120}
 58};
 59
 60static const struct adc_map_pt adcmap_ntcg104ef104fb[] = {
 61	{696483,	-40960},
 62	{649148,	-39936},
 63	{605368,	-38912},
 64	{564809,	-37888},
 65	{527215,	-36864},
 66	{492322,	-35840},
 67	{460007,	-34816},
 68	{429982,	-33792},
 69	{402099,	-32768},
 70	{376192,	-31744},
 71	{352075,	-30720},
 72	{329714,	-29696},
 73	{308876,	-28672},
 74	{289480,	-27648},
 75	{271417,	-26624},
 76	{254574,	-25600},
 77	{238903,	-24576},
 78	{224276,	-23552},
 79	{210631,	-22528},
 80	{197896,	-21504},
 81	{186007,	-20480},
 82	{174899,	-19456},
 83	{164521,	-18432},
 84	{154818,	-17408},
 85	{145744,	-16384},
 86	{137265,	-15360},
 87	{129307,	-14336},
 88	{121866,	-13312},
 89	{114896,	-12288},
 90	{108365,	-11264},
 91	{102252,	-10240},
 92	{96499,		-9216},
 93	{91111,		-8192},
 94	{86055,		-7168},
 95	{81308,		-6144},
 96	{76857,		-5120},
 97	{72660,		-4096},
 98	{68722,		-3072},
 99	{65020,		-2048},
100	{61538,		-1024},
101	{58261,		0},
102	{55177,		1024},
103	{52274,		2048},
104	{49538,		3072},
105	{46962,		4096},
106	{44531,		5120},
107	{42243,		6144},
108	{40083,		7168},
109	{38045,		8192},
110	{36122,		9216},
111	{34308,		10240},
112	{32592,		11264},
113	{30972,		12288},
114	{29442,		13312},
115	{27995,		14336},
116	{26624,		15360},
117	{25333,		16384},
118	{24109,		17408},
119	{22951,		18432},
120	{21854,		19456},
121	{20807,		20480},
122	{19831,		21504},
123	{18899,		22528},
124	{18016,		23552},
125	{17178,		24576},
126	{16384,		25600},
127	{15631,		26624},
128	{14916,		27648},
129	{14237,		28672},
130	{13593,		29696},
131	{12976,		30720},
132	{12400,		31744},
133	{11848,		32768},
134	{11324,		33792},
135	{10825,		34816},
136	{10354,		35840},
137	{9900,		36864},
138	{9471,		37888},
139	{9062,		38912},
140	{8674,		39936},
141	{8306,		40960},
142	{7951,		41984},
143	{7616,		43008},
144	{7296,		44032},
145	{6991,		45056},
146	{6701,		46080},
147	{6424,		47104},
148	{6160,		48128},
149	{5908,		49152},
150	{5667,		50176},
151	{5439,		51200},
152	{5219,		52224},
153	{5010,		53248},
154	{4810,		54272},
155	{4619,		55296},
156	{4440,		56320},
157	{4263,		57344},
158	{4097,		58368},
159	{3938,		59392},
160	{3785,		60416},
161	{3637,		61440},
162	{3501,		62464},
163	{3368,		63488},
164	{3240,		64512},
165	{3118,		65536},
166	{2998,		66560},
167	{2889,		67584},
168	{2782,		68608},
169	{2680,		69632},
170	{2581,		70656},
171	{2490,		71680},
172	{2397,		72704},
173	{2310,		73728},
174	{2227,		74752},
175	{2147,		75776},
176	{2064,		76800},
177	{1998,		77824},
178	{1927,		78848},
179	{1860,		79872},
180	{1795,		80896},
181	{1736,		81920},
182	{1673,		82944},
183	{1615,		83968},
184	{1560,		84992},
185	{1507,		86016},
186	{1456,		87040},
187	{1407,		88064},
188	{1360,		89088},
189	{1314,		90112},
190	{1271,		91136},
191	{1228,		92160},
192	{1189,		93184},
193	{1150,		94208},
194	{1112,		95232},
195	{1076,		96256},
196	{1042,		97280},
197	{1008,		98304},
198	{976,		99328},
199	{945,		100352},
200	{915,		101376},
201	{886,		102400},
202	{859,		103424},
203	{832,		104448},
204	{807,		105472},
205	{782,		106496},
206	{756,		107520},
207	{735,		108544},
208	{712,		109568},
209	{691,		110592},
210	{670,		111616},
211	{650,		112640},
212	{631,		113664},
213	{612,		114688},
214	{594,		115712},
215	{577,		116736},
216	{560,		117760},
217	{544,		118784},
218	{528,		119808},
219	{513,		120832},
220	{498,		121856},
221	{483,		122880},
222	{470,		123904},
223	{457,		124928},
224	{444,		125952},
225	{431,		126976},
226	{419,		128000}
227};
228
229static int32_t
230	adc_map_linear(const struct adc_map_pt *pts,
231		uint32_t tablesize, int32_t input, int64_t *output)
232{
233	bool descending = 1;
234	uint32_t i = 0;
235
236	if ((pts == NULL) || (output == NULL))
237		return -EINVAL;
238
239	/* Check if table is descending or ascending */
240	if (tablesize > 1) {
241		if (pts[0].x < pts[1].x)
242			descending = 0;
243	}
244
245	while (i < tablesize) {
246		if ((descending == 1) && (pts[i].x < input)) {
247			/* table entry is less than measured
248				value and table is descending, stop */
249			break;
250		} else if ((descending == 0) &&
251				(pts[i].x > input)) {
252			/* table entry is greater than measured
253				value and table is ascending, stop */
254			break;
255		} else
256			i++;
257	}
258
259	if (i == 0)
260		*output = pts[0].y;
261	else if (i == tablesize)
262		*output = pts[tablesize-1].y;
263	else {
264	/* result is between search_index and search_index-1 */
265	/* interpolate linearly */
266	*output = (((int32_t) ((pts[i].y - pts[i-1].y)*
267			(input - pts[i-1].x))/
268			(pts[i].x - pts[i-1].x))+
269			pts[i-1].y);
270	}
271
272	return 0;
273}
274
275int32_t scale_default(int32_t adc_code,
276				const struct adc_properties *adc_properties,
277				const struct chan_properties *chan_properties,
278				struct adc_chan_result *adc_chan_result)
279{
280	bool negative_rawfromoffset = 0;
281	int32_t rawfromoffset = adc_code - chan_properties->adc_graph->offset;
282
283	if (!chan_properties->gain_numerator ||
284		!chan_properties->gain_denominator)
285		return -EINVAL;
286
287	adc_chan_result->adc_code = adc_code;
288	if (rawfromoffset < 0) {
289		if (adc_properties->bipolar) {
290			rawfromoffset = (rawfromoffset ^ -1) +  1;
291			negative_rawfromoffset = 1;
292		} else
293			rawfromoffset = 0;
294	}
295
296	if (rawfromoffset >= 1 << adc_properties->bitresolution)
297		rawfromoffset = (1 << adc_properties->bitresolution) - 1;
298
299	adc_chan_result->measurement = (int64_t)rawfromoffset*
300					chan_properties->adc_graph->dx*
301					chan_properties->gain_denominator;
302
303	/* do_div only perform positive integer division! */
304	do_div(adc_chan_result->measurement, chan_properties->adc_graph->dy*
305					chan_properties->gain_numerator);
306
307	if (negative_rawfromoffset)
308		adc_chan_result->measurement =
309		(adc_chan_result->measurement ^ -1) + 1;
310
311	/* Note: adc_chan_result->measurement is in the unit of
312	 * adc_properties.adc_reference. For generic channel processing,
313	 * channel measurement is a scale/ratio relative to the adc
314	 * reference input */
315	adc_chan_result->physical = (int32_t) adc_chan_result->measurement;
316
317	return 0;
318}
319
320int32_t scale_batt_therm(int32_t adc_code,
321				const struct adc_properties *adc_properties,
322				const struct chan_properties *chan_properties,
323				struct adc_chan_result *adc_chan_result)
324{
325	scale_default(adc_code, adc_properties, chan_properties,
326			adc_chan_result);
327	/* convert mV ---> degC using the table */
328	return adc_map_linear(
329			adcmap_batttherm,
330			sizeof(adcmap_batttherm)/sizeof(adcmap_batttherm[0]),
331			adc_chan_result->physical,
332			&adc_chan_result->physical);
333}
334
335int32_t scale_msm_therm(int32_t adc_code,
336		const struct adc_properties *adc_properties,
337		const struct chan_properties *chan_properties,
338		struct adc_chan_result *adc_chan_result)
339{
340	scale_default(adc_code, adc_properties, chan_properties,
341			adc_chan_result);
342	/* convert mV ---> degC using the table */
343	return adc_map_linear(
344			adcmap_msmtherm,
345			sizeof(adcmap_msmtherm)/sizeof(adcmap_msmtherm[0]),
346			adc_chan_result->physical,
347			&adc_chan_result->physical);
348}
349
350int32_t scale_pmic_therm(int32_t adc_code,
351				const struct adc_properties *adc_properties,
352				const struct chan_properties *chan_properties,
353				struct adc_chan_result *adc_chan_result)
354{
355	/* 2mV/K */
356	int32_t rawfromoffset = adc_code - chan_properties->adc_graph->offset;
357
358	if (!chan_properties->gain_numerator ||
359		!chan_properties->gain_denominator)
360		return -EINVAL;
361
362	adc_chan_result->adc_code = adc_code;
363	if (rawfromoffset > 0) {
364		if (rawfromoffset >= 1 << adc_properties->bitresolution)
365			rawfromoffset = (1 << adc_properties->bitresolution)
366									- 1;
367		adc_chan_result->measurement = (int64_t)rawfromoffset*
368					chan_properties->adc_graph->dx*
369					chan_properties->gain_denominator*1000;
370		do_div(adc_chan_result->measurement,
371			chan_properties->adc_graph->dy*
372			chan_properties->gain_numerator*2);
373	} else {
374		adc_chan_result->measurement = 0;
375	}
376	/* Note: adc_chan_result->measurement is in the unit of
377		adc_properties.adc_reference */
378	adc_chan_result->physical = (int32_t)adc_chan_result->measurement;
379	/* Change to .001 deg C */
380	adc_chan_result->physical -= KELVINMIL_DEGMIL;
381	adc_chan_result->measurement <<= 1;
382
383	return 0;
384}
385
386/* Scales the ADC code to 0.001 degrees C using the map
387 * table for the XO thermistor.
388 */
389int32_t tdkntcgtherm(int32_t adc_code,
390			const struct adc_properties *adc_properties,
391			const struct chan_properties *chan_properties,
392			struct adc_chan_result *adc_chan_result)
393{
394	int32_t offset = chan_properties->adc_graph->offset,
395		dy = chan_properties->adc_graph->dy,
396		dx = chan_properties->adc_graph->dx,
397		fullscale_calibrated_adc_code;
398
399	uint32_t rt_r25;
400	uint32_t num1, num2, denom;
401
402	adc_chan_result->adc_code = adc_code;
403	fullscale_calibrated_adc_code = dy + offset;
404	/* The above is a short cut in math that would reduce a lot of
405	   computation whereas the below expression
406		(adc_properties->adc_reference*dy+dx*offset+(dx>>1))/dx
407	   is a more generic formula when the 2 reference voltages are
408	   different than 0 and full scale voltage. */
409
410	if ((dy == 0) || (dx == 0) ||
411			(offset >= fullscale_calibrated_adc_code)) {
412		return -EINVAL;
413	} else {
414		if (adc_code >= fullscale_calibrated_adc_code) {
415			rt_r25 = (uint32_t)-1;
416		} else if (adc_code <= offset) {
417			rt_r25 = 0;
418		} else {
419	/* The formula used is (adc_code of current reading - offset)/
420	 * (the calibrated fullscale adc code - adc_code of current reading).
421	 * For this channel, at this time, chan_properties->gain_numerator =
422	 * chan_properties->gain_denominator = 1, so no need to incorporate
423	 * into the formula even though we could and multiply/divide by 1
424	 * which yields the same result but expensive on computation. */
425		num1 = (adc_code - offset) << 14;
426		num2 = (fullscale_calibrated_adc_code - adc_code) >> 1;
427		denom = fullscale_calibrated_adc_code - adc_code;
428
429			if ((int)denom <= 0)
430				rt_r25 = 0x7FFFFFFF;
431			else
432				rt_r25 = (num1 + num2) / denom;
433		}
434
435		if (rt_r25 > 0x7FFFFFFF)
436			rt_r25 = 0x7FFFFFFF;
437
438		adc_map_linear(adcmap_ntcg104ef104fb,
439		sizeof(adcmap_ntcg104ef104fb)/sizeof(adcmap_ntcg104ef104fb[0]),
440		(int32_t)rt_r25, &adc_chan_result->physical);
441	}
442
443	return 0;
444}
445
446int32_t scale_xtern_chgr_cur(int32_t adc_code,
447			const struct adc_properties *adc_properties,
448			const struct chan_properties *chan_properties,
449			struct adc_chan_result *adc_chan_result)
450{
451	int32_t rawfromoffset = adc_code - chan_properties->adc_graph->offset;
452
453	if (!chan_properties->gain_numerator ||
454		!chan_properties->gain_denominator)
455		return -EINVAL;
456
457	adc_chan_result->adc_code = adc_code;
458	if (rawfromoffset > 0) {
459		if (rawfromoffset >= 1 << adc_properties->bitresolution)
460			rawfromoffset = (1 << adc_properties->bitresolution)
461									- 1;
462		adc_chan_result->measurement = ((int64_t)rawfromoffset << 1)*
463						chan_properties->adc_graph->dx*
464					chan_properties->gain_denominator;
465		do_div(adc_chan_result->measurement,
466					chan_properties->adc_graph->dy*
467					chan_properties->gain_numerator);
468	} else {
469		adc_chan_result->measurement = 0;
470	}
471	adc_chan_result->physical = (int32_t) adc_chan_result->measurement;
472
473	return 0;
474}