struct ntc_compensation { int temp_c; unsignedint ohm;
};
/* * Used as index in a zero-terminated array, holes not allowed so * that NTC_LAST is the first empty array entry.
*/ enum {
NTC_B57330V2103,
NTC_B57891S0103,
NTC_NCP03WB473,
NTC_NCP03WF104,
NTC_NCP15WB473,
NTC_NCP15WL333,
NTC_NCP15XH103,
NTC_NCP18WB473,
NTC_NCP21WB473,
NTC_SSG1404001221,
NTC_LAST,
};
/* * pullup_uV, pullup_ohm, pulldown_ohm, and connect are required. * * How to setup pullup_ohm, pulldown_ohm, and connect is * described at Documentation/hwmon/ntc_thermistor.rst * * pullup/down_ohm: 0 for infinite / not-connected * * chan: iio_channel pointer to communicate with the ADC which the * thermistor is using for conversion of the analog values.
*/ struct ntc_data { conststruct ntc_compensation *comp; int n_comp; unsignedint pullup_uv; unsignedint pullup_ohm; unsignedint pulldown_ohm; enum { NTC_CONNECTED_POSITIVE, NTC_CONNECTED_GROUND } connect; struct iio_channel *chan;
};
ret = iio_read_channel_processed_scale(channel, &uv, 1000); if (ret < 0) { int raw;
/* * This fallback uses a raw read and then * assumes the ADC is 12 bits, scaling with * a factor 1000 to get to microvolts.
*/
ret = iio_read_channel_raw(channel, &raw); if (ret < 0) {
pr_err("read channel() error: %d\n", ret); return ret;
}
ret = iio_convert_raw_to_processed(channel, raw, &uv, 1000); if (ret < 0) { /* Assume 12 bit ADC with vref at pullup_uv */
uv = (data->pullup_uv * (s64)raw) >> 12;
}
}
/* faulty adc value */ if (uv == 0 || uv >= puv) return -ENODATA;
if (data->connect == NTC_CONNECTED_POSITIVE && puo == 0)
n = div_u64(pdo * (puv - uv), uv); elseif (data->connect == NTC_CONNECTED_GROUND && pdo == 0)
n = div_u64(puo * uv, puv - uv); elseif (data->connect == NTC_CONNECTED_POSITIVE)
n = div64_u64_safe(pdo * puo * (puv - uv),
puo * uv - pdo * (puv - uv)); else
n = div64_u64_safe(pdo * puo * uv, pdo * (puv - uv) - puo * uv);
/* sensor out of bounds */ if (n > data->comp[0].ohm || n < data->comp[data->n_comp - 1].ohm) return -ENODATA;
return n;
}
staticvoid lookup_comp(struct ntc_data *data, unsignedint ohm, int *i_low, int *i_high)
{ 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 (start < end) {
mid = start + (end - start) / 2; /* * 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 {
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;
} /* * start <= end * data->comp[start].ohm >= ohm >= data->comp[end].ohm
*/
} /* * start == end * ohm >= data->comp[end].ohm
*/
*i_low = end; if (ohm == data->comp[end].ohm)
*i_high = end; else
*i_high = end - 1;
}
staticint get_temp_mc(struct ntc_data *data, unsignedint ohm)
{ int low, high; int temp;
lookup_comp(data, ohm, &low, &high); /* * First multiplying the table temperatures with 1000 to get to * millicentigrades (which is what we want) and then interpolating * will give the best precision.
*/
temp = fixp_linear_interpolate(data->comp[low].ohm,
data->comp[low].temp_c * 1000,
data->comp[high].ohm,
data->comp[high].temp_c * 1000,
ohm); return temp;
}
staticint ntc_thermistor_get_ohm(struct ntc_data *data)
{ int read_uv;
chan = devm_iio_channel_get(dev, NULL); if (IS_ERR(chan)) return PTR_ERR(chan);
ret = iio_get_channel_type(chan, &type); if (ret < 0) return ret;
if (type != IIO_VOLTAGE) return -EINVAL;
ret = device_property_read_u32(dev, "pullup-uv", &data->pullup_uv); if (ret) return dev_err_probe(dev, ret, "pullup-uv not specified\n");
ret = device_property_read_u32(dev, "pullup-ohm", &data->pullup_ohm); if (ret) return dev_err_probe(dev, ret, "pullup-ohm not specified\n");
ret = device_property_read_u32(dev, "pulldown-ohm", &data->pulldown_ohm); if (ret) return dev_err_probe(dev, ret, "pulldown-ohm not specified\n");
if (device_property_read_bool(dev, "connected-positive"))
data->connect = NTC_CONNECTED_POSITIVE; else/* status change should be possible if not always on. */
data->connect = NTC_CONNECTED_GROUND;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.