1
0
Fork 0

hwmon: (ntc_thermistor) Optimize and fix build warning

The following build warning is seen in some configurations:

drivers/hwmon/ntc_thermistor.c: In function 'ntc_show_temp':
drivers/hwmon/ntc_thermistor.c:293: warning: 'temp' may be used uninitialized in this function

Fix the problem by re-arranging the code to overload return values with error
codes, and by avoiding error returns whenever possible.

Specifically,

Simplify lookup_comp() to not return an error. Instead, return i_low == i_high
if there is an exact match, or if the ohm value is outside the lookup table
range.

Modify get_temp_mC() to not return an error. Since it only returns an error
after lookup_comp() returned an error, this is quite straightforward after above
change.

Separate ntc_thermistor_read() into a function to read the resistor value (which
can return an error), and the call to get_temp_mC() which doesn't. Call the
functions directly from ntc_show_temp().

Code was tested using a test program, comparing the result of the old and new
versions of get_temp_mC() for resistor values between 0 and 2,000,000 ohm.

As a side effect, this patch reduces code size by approximately 400 bytes on
x86_64.

Signed-off-by: Guenter Roeck <guenter.roeck@ericsson.com>
Cc: Donggeun Kim <dg77.kim@samsung.com>
Reviewed-by: Robert Coulson <robert.coulson@ericsson.com>
hifive-unleashed-5.1
Guenter Roeck 2012-04-22 20:58:51 -07:00
parent 425d247680
commit dbe43a6276
1 changed files with 79 additions and 83 deletions

View File

@ -134,8 +134,7 @@ static inline u64 div64_u64_safe(u64 dividend, u64 divisor)
return div64_u64(dividend, divisor);
}
static unsigned int get_ohm_of_thermistor(struct ntc_data *data,
unsigned int uV)
static int get_ohm_of_thermistor(struct ntc_data *data, unsigned int uV)
{
struct ntc_thermistor_platform_data *pdata = data->pdata;
u64 mV = uV / 1000;
@ -146,12 +145,12 @@ static unsigned int get_ohm_of_thermistor(struct ntc_data *data,
if (mV == 0) {
if (pdata->connect == NTC_CONNECTED_POSITIVE)
return UINT_MAX;
return INT_MAX;
return 0;
}
if (mV >= pmV)
return (pdata->connect == NTC_CONNECTED_POSITIVE) ?
0 : UINT_MAX;
0 : INT_MAX;
if (pdata->connect == NTC_CONNECTED_POSITIVE && puO == 0)
N = div64_u64_safe(pdO * (pmV - mV), mV);
@ -163,113 +162,109 @@ static unsigned int get_ohm_of_thermistor(struct ntc_data *data,
else
N = div64_u64_safe(pdO * puO * mV, pdO * (pmV - mV) - puO * mV);
return (unsigned int) N;
if (N > INT_MAX)
N = INT_MAX;
return N;
}
static int lookup_comp(struct ntc_data *data,
unsigned int ohm, int *i_low, int *i_high)
static void lookup_comp(struct ntc_data *data, unsigned int ohm,
int *i_low, int *i_high)
{
int start, end, mid = -1;
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;
}
/* Do a binary search on compensation table */
start = 0;
end = data->n_comp;
while (end > start) {
while (start < end) {
mid = start + (end - start) / 2;
if (data->comp[mid].ohm < ohm)
/*
* 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) {
end = mid;
else if (data->comp[mid].ohm > ohm)
} else {
start = mid + 1;
else
break;
}
if (mid == 0) {
if (data->comp[mid].ohm > ohm) {
*i_high = mid;
*i_low = mid + 1;
return 0;
} else {
*i_low = mid;
*i_high = -1;
return -EINVAL;
/*
* 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;
}
/*
* start <= end
* data->comp[start].ohm >= ohm >= data->comp[end].ohm
*/
}
if (mid == (data->n_comp - 1)) {
if (data->comp[mid].ohm <= ohm) {
*i_low = mid;
*i_high = mid - 1;
return 0;
} else {
*i_low = -1;
*i_high = mid;
return -EINVAL;
}
}
if (data->comp[mid].ohm <= ohm) {
*i_low = mid;
*i_high = mid - 1;
} else {
*i_low = mid + 1;
*i_high = mid;
}
return 0;
/*
* start == end
* ohm >= data->comp[end].ohm
*/
*i_low = end;
if (ohm == data->comp[end].ohm)
*i_high = end;
else
*i_high = end - 1;
}
static int get_temp_mC(struct ntc_data *data, unsigned int ohm, int *temp)
static int get_temp_mC(struct ntc_data *data, unsigned int ohm)
{
int low, high;
int ret;
int temp;
ret = lookup_comp(data, ohm, &low, &high);
if (ret) {
lookup_comp(data, ohm, &low, &high);
if (low == high) {
/* Unable to use linear approximation */
if (low != -1)
*temp = data->comp[low].temp_C * 1000;
else if (high != -1)
*temp = data->comp[high].temp_C * 1000;
else
return ret;
temp = data->comp[low].temp_C * 1000;
} else {
*temp = data->comp[low].temp_C * 1000 +
temp = data->comp[low].temp_C * 1000 +
((data->comp[high].temp_C - data->comp[low].temp_C) *
1000 * ((int)ohm - (int)data->comp[low].ohm)) /
((int)data->comp[high].ohm - (int)data->comp[low].ohm);
}
return 0;
return temp;
}
static int ntc_thermistor_read(struct ntc_data *data, int *temp)
static int ntc_thermistor_get_ohm(struct ntc_data *data)
{
int ret;
int read_ohm, read_uV;
unsigned int ohm = 0;
int read_uV;
if (data->pdata->read_ohm) {
read_ohm = data->pdata->read_ohm();
if (read_ohm < 0)
return read_ohm;
ohm = (unsigned int)read_ohm;
}
if (data->pdata->read_ohm)
return data->pdata->read_ohm();
if (data->pdata->read_uV) {
read_uV = data->pdata->read_uV();
if (read_uV < 0)
return read_uV;
ohm = get_ohm_of_thermistor(data, (unsigned int)read_uV);
return get_ohm_of_thermistor(data, read_uV);
}
ret = get_temp_mC(data, ohm, temp);
if (ret) {
dev_dbg(data->dev, "Sensor reading function not available.\n");
return ret;
}
return 0;
return -EINVAL;
}
static ssize_t ntc_show_name(struct device *dev,
@ -290,12 +285,13 @@ static ssize_t ntc_show_temp(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct ntc_data *data = dev_get_drvdata(dev);
int temp, ret;
int ohm;
ret = ntc_thermistor_read(data, &temp);
if (ret)
return ret;
return sprintf(buf, "%d\n", temp);
ohm = ntc_thermistor_get_ohm(data);
if (ohm < 0)
return ohm;
return sprintf(buf, "%d\n", get_temp_mC(data, ohm));
}
static SENSOR_DEVICE_ATTR(temp1_type, S_IRUGO, ntc_show_type, NULL, 0);