/* Bits in sysfs "features" value */ #define W1_THERM_CHECK_RESULT 1/* Enable conversion success check */ #define W1_THERM_POLL_COMPLETION 2/* Poll for conversion completion */ #define W1_THERM_FEATURES_MASK 3/* All values mask */
/* Poll period in milliseconds. Should be less then a shortest operation on the device */ #define W1_POLL_PERIOD 32 #define W1_POLL_CONVERT_TEMP 2000/* Timeout for W1_CONVERT_TEMP, ms */ #define W1_POLL_RECALL_EEPROM 500/* Timeout for W1_RECALL_EEPROM, ms*/
/* Masks for resolution functions, work with all devices */ /* Bit mask for config register for all devices, bits 7,6,5 */ #define W1_THERM_RESOLUTION_MASK 0xE0 /* Bit offset of resolution in config register for all devices */ #define W1_THERM_RESOLUTION_SHIFT 5 /* Bit offset of resolution in config register for all devices */ #define W1_THERM_RESOLUTION_SHIFT 5 /* Add this to bit value to get resolution */ #define W1_THERM_RESOLUTION_MIN 9 /* Maximum allowed value */ #define W1_THERM_RESOLUTION_MAX 14
/* Write data in the device RAM */
ret = w1_DS18B20_write_data(sl, info.rom + 2); if (ret) return ret;
/* Have to read back the resolution to verify an actual value *GX20MH01andDS18B20areindistinguishablebyfamilynumber,butresolutionsdiffer *SomeDS18B20clonesdon'tsupportresolutionchange
*/
ret = read_scratchpad(sl, &info2); if (ret) /* Scratchpad read fail */ return ret;
if ((info2.rom[4] & W1_THERM_RESOLUTION_MASK) == (info.rom[4] & W1_THERM_RESOLUTION_MASK)) return0;
/* Resolution verify error */ return -EIO;
}
staticinlineint w1_DS18B20_get_resolution(struct w1_slave *sl)
{ int ret; int resolution; struct therm_info info;
ret = read_scratchpad(sl, &info);
if (ret) return ret;
resolution = ((info.rom[4] & W1_THERM_RESOLUTION_MASK) >> W1_THERM_RESOLUTION_SHIFT)
+ W1_THERM_RESOLUTION_MIN; /* GX20MH01 has one special case: *>=14means14bitswhengettingresolutionfrombitvalue. *MAX31850deliversfixed15andhas14bits. *Otherdeviceshavenomorethen12bits.
*/ if (resolution > W1_THERM_RESOLUTION_MAX)
resolution = W1_THERM_RESOLUTION_MAX;
/* Signed 16-bit value to unsigned, cpu order */
bv = le16_to_cpup((__le16 *)rom);
/* Config register bit R2 = 1 - GX20MH01 in 13 or 14 bit resolution mode */ if (rom[4] & 0x80) { /* Insert two temperature bits from config register */ /* Avoid arithmetic shift of signed value */
bv = (bv << 2) | (rom[4] & 3);
t = (s16) bv; /* Degrees, lowest bit is 2^-6 */ return (int)t * 1000 / 64; /* Sign-extend to int; millidegrees */
}
t = (s16)bv; /* Degrees, lowest bit is 2^-4 */ return (int)t * 1000 / 16; /* Sign-extend to int; millidegrees */
}
for (i = 0; i < ARRAY_SIZE(w1_therm_families); ++i) { if (w1_therm_families[i].f->fid == sl->family->fid) {
ret = &w1_therm_families[i]; break;
}
} return ret;
}
/* try to acquire the mutex, if not, sleep retry_delay before retry) */ while (mutex_lock_interruptible(lock) != 0 && max_trying > 0) { unsignedlong sleep_rem;
sleep_rem = msleep_interruptible(W1_THERM_RETRY_DELAY); if (!sleep_rem)
max_trying--;
}
if (!max_trying) returnfalse; /* Didn't acquire the bus mutex */
returntrue;
}
/** *check_family_data()-Checkiffamilydataandspecificfunctionsarepresent *@sl:W1devicedata * *Return:0-OK,negativevalue-error
*/ staticint check_family_data(struct w1_slave *sl)
{ if ((!sl->family_data) || (!SLAVE_SPECIFIC_FUNC(sl))) {
dev_info(&sl->dev, "%s: Device is not supported by the driver\n", __func__); return -EINVAL; /* No device family */
} return0;
}
dev_info(&sl->dev, "%s: Device not supported by the driver\n", __func__);
return0; /* No device family */
}
/** *int_to_short()-Safecastingofinttoshort * *@i:integertobeconvertedtoshort * *Deviceregisteruse1bytetostoresignedinteger. *Thishelperfunctionconverttheintinasignedshort, *usingthemin/maxvaluesthatdevicecanmeasureaslimits. *min/maxvaluesaredefinedbymacro. * *Return:ashortintherangeofmin/maxvalue
*/ staticinline s8 int_to_short(int i)
{ /* Prepare to cast to short by eliminating out of range values */
i = clamp(i, MIN_TEMP, MAX_TEMP); return (s8) i;
}
/* Get a pointer to the device specific function struct */
sl_family_conv = device_family(sl); if (!sl_family_conv) {
kfree(sl->family_data); return -ENODEV;
} /* save this pointer to the device structure */
SLAVE_SPECIFIC_FUNC(sl) = sl_family_conv;
if (bulk_read_support(sl)) { /* *addthesysentrytotriggerbulk_read *atmasterlevelonlythe1sttime
*/ if (!bulk_read_device_counter) { int err = device_create_file(&sl->master->dev,
&dev_attr_therm_bulk_read);
if (err)
dev_warn(&sl->dev, "%s: Device has been added, but bulk read is unavailable. err=%d\n",
__func__, err);
} /* Increment the counter */
bulk_read_device_counter++;
}
/* Getting the power mode of the device {external, parasite} */
SLAVE_POWERMODE(sl) = read_powermode(sl);
if (SLAVE_POWERMODE(sl) < 0) { /* no error returned as device has been added */
dev_warn(&sl->dev, "%s: Device has been added, but power_mode may be corrupted. err=%d\n",
__func__, SLAVE_POWERMODE(sl));
}
/* Getting the resolution of the device */ if (SLAVE_SPECIFIC_FUNC(sl)->get_resolution) {
SLAVE_RESOLUTION(sl) =
SLAVE_SPECIFIC_FUNC(sl)->get_resolution(sl); if (SLAVE_RESOLUTION(sl) < 0) { /* no error returned as device has been added */
dev_warn(&sl->dev, "%s:Device has been added, but resolution may be corrupted. err=%d\n",
__func__, SLAVE_RESOLUTION(sl));
}
}
/* Finally initialize convert_triggered flag */
SLAVE_CONVERT_TRIGGERED(sl) = 0;
return0;
}
staticvoid w1_therm_remove_slave(struct w1_slave *sl)
{ int refcnt = atomic_sub_return(1, THERM_REFCNT(sl->family_data));
if (bulk_read_support(sl)) {
bulk_read_device_counter--; /* Delete the entry if no more device support the feature */ if (!bulk_read_device_counter)
device_remove_file(&sl->master->dev,
&dev_attr_therm_bulk_read);
}
/* Safe version of reset_select_slave - avoid using the one in w_io.c */ staticint reset_select_slave(struct w1_slave *sl)
{
u8 match[9] = { W1_MATCH_ROM, };
u64 rn = le64_to_cpu(*((u64 *)&sl->reg_num));
if (strong_pullup) {
pr_info("%s: Measure with strong_pullup is not supported.\n", __func__); return -EINVAL;
}
memset(info->rom, 0, sizeof(info->rom));
/* prevent the slave from going away in sleep */
atomic_inc(THERM_REFCNT(sl->family_data));
if (!bus_mutex_lock(&dev_master->bus_mutex)) {
ret = -EAGAIN; /* Didn't acquire the mutex */ goto dec_refcnt;
}
while (max_trying-- && ret) { /* ret should be 0 */
info->verdict = 0;
info->crc = 0; /* safe version to select slave */ if (!reset_select_slave(sl)) { int j_start, j_end;
/*no device need pullup */
w1_write_8(dev_master, W1_CONVERT_TEMP);
j_start = jiffies;
ret = w1_poll_completion(dev_master, W1_POLL_CONVERT_TEMP); if (ret) {
dev_dbg(&sl->dev, "%s: Timeout\n", __func__); goto mt_unlock;
}
j_end = jiffies; /* 1.2x increase for variation and changes over temperature range */
*conv_time = jiffies_to_msecs(j_end-j_start)*12/10;
pr_debug("W1 Measure complete, conv_time = %d, HZ=%d.\n",
*conv_time, HZ); if (*conv_time <= CONV_TIME_MEASURE) {
ret = -EIO; goto mt_unlock;
}
mutex_unlock(&dev_master->bus_mutex);
ret = read_scratchpad(sl, info); goto dec_refcnt;
}
staticint write_scratchpad(struct w1_slave *sl, const u8 *data, u8 nb_bytes)
{ struct w1_master *dev_master = sl->master; int max_trying = W1_THERM_MAX_TRY; int ret = -ENODEV;
if (!sl->family_data) goto error;
/* prevent the slave from going away in sleep */
atomic_inc(THERM_REFCNT(sl->family_data));
if (!bus_mutex_lock(&dev_master->bus_mutex)) {
ret = -EAGAIN; /* Didn't acquire the mutex */ goto dec_refcnt;
}
while (max_trying-- && ret) { /* ret should be 0 */ /* safe version to select slave */ if (!reset_select_slave(sl)) {
w1_write_8(dev_master, W1_WRITE_SCRATCHPAD);
w1_write_block(dev_master, data, nb_bytes);
ret = 0;
}
}
mutex_unlock(&dev_master->bus_mutex);
staticint read_powermode(struct w1_slave *sl)
{ struct w1_master *dev_master = sl->master; int max_trying = W1_THERM_MAX_TRY; int ret = -ENODEV;
if (!sl->family_data) goto error;
/* prevent the slave from going away in sleep */
atomic_inc(THERM_REFCNT(sl->family_data));
if (!bus_mutex_lock(&dev_master->bus_mutex)) {
ret = -EAGAIN; /* Didn't acquire the mutex */ goto dec_refcnt;
}
while ((max_trying--) && (ret < 0)) { /* safe version to select slave */ if (!reset_select_slave(sl)) {
w1_write_8(dev_master, W1_READ_PSUPPLY); /* *Emitareadtimeslotandreadonlyonebit, *1isexternallypowered, *0isparasitepowered
*/
ret = w1_touch_bit(dev_master, 1); /* ret should be either 1 either 0 */
}
}
mutex_unlock(&dev_master->bus_mutex);
staticint trigger_bulk_read(struct w1_master *dev_master)
{ struct w1_slave *sl = NULL; /* used to iterate through slaves */ int max_trying = W1_THERM_MAX_TRY; int t_conv = 0; int ret = -ENODEV; bool strong_pullup = false;
/* *Checkwhetherthereareparasitepowereddeviceonthebus, *andcomputedurationofconversionforthesedevices *sowecanapplyastrongpullupifrequired
*/
list_for_each_entry(sl, &dev_master->slist, w1_slave_entry) { if (!sl->family_data) goto error; if (bulk_read_support(sl)) { int t_cur = conversion_time(sl);
/* *t_convisthemaxconversiontimerequiredonthebus *Ifits0,nodevicesupportthebulkreadfeature
*/ if (!t_conv) goto error;
if (!bus_mutex_lock(&dev_master->bus_mutex)) {
ret = -EAGAIN; /* Didn't acquire the mutex */ goto error;
}
while ((max_trying--) && (ret < 0)) { /* ret should be either 0 */
if (!w1_reset_bus(dev_master)) { /* Just reset the bus */ unsignedlong sleep_rem;
w1_write_8(dev_master, W1_SKIP_ROM);
if (strong_pullup) /* Apply pullup if required */
w1_next_pullup(dev_master, t_conv);
w1_write_8(dev_master, W1_CONVERT_TEMP);
/* set a flag to instruct that converT pending */
list_for_each_entry(sl,
&dev_master->slist, w1_slave_entry) { if (bulk_read_support(sl))
SLAVE_CONVERT_TRIGGERED(sl) = -1;
}
if (strong_pullup) { /* some device need pullup */
sleep_rem = msleep_interruptible(t_conv); if (sleep_rem != 0) {
ret = -EINTR; goto mt_unlock;
}
mutex_unlock(&dev_master->bus_mutex);
} else {
mutex_unlock(&dev_master->bus_mutex);
sleep_rem = msleep_interruptible(t_conv); if (sleep_rem != 0) {
ret = -EINTR; goto set_flag;
}
}
ret = 0; goto set_flag;
}
}
mt_unlock:
mutex_unlock(&dev_master->bus_mutex);
set_flag: /* set a flag to register convsersion is done */
list_for_each_entry(sl, &dev_master->slist, w1_slave_entry) { if (bulk_read_support(sl))
SLAVE_CONVERT_TRIGGERED(sl) = 1;
}
error: return ret;
}
ret = kstrtoint(buf, 10, &val); /* converting user entry to int */
if (ret) { /* conversion error */
dev_info(device, "%s: conversion error. err= %d\n", __func__, ret); return size; /* return size to avoid call back again */
}
if ((!sl->family_data) || (!SLAVE_SPECIFIC_FUNC(sl))) {
dev_info(device, "%s: Device not supported by the driver\n", __func__); return size; /* No device family */
}
if (val == 0) /* val=0 : trigger a EEPROM save */
ret = copy_scratchpad(sl); else { if (SLAVE_SPECIFIC_FUNC(sl)->set_resolution)
ret = SLAVE_SPECIFIC_FUNC(sl)->set_resolution(sl, val);
}
if (ret) {
dev_warn(device, "%s: Set resolution - error %d\n", __func__, ret); /* Propagate error to userspace */ return ret;
}
SLAVE_RESOLUTION(sl) = val; /* Reset the conversion time to default - it depends on resolution */
SLAVE_CONV_TIME_OVERRIDE(sl) = CONV_TIME_DEFAULT;
if ((!sl->family_data) || (!SLAVE_SPECIFIC_FUNC(sl))) {
dev_info(device, "%s: Device not supported by the driver\n", __func__); return0; /* No device family */
}
if (bulk_read_support(sl)) { if (SLAVE_CONVERT_TRIGGERED(sl) < 0) {
dev_dbg(device, "%s: Conversion in progress, retry later\n",
__func__); return0;
} elseif (SLAVE_CONVERT_TRIGGERED(sl) > 0) { /* A bulk read has been issued, read the device RAM */
ret = read_scratchpad(sl, &info);
SLAVE_CONVERT_TRIGGERED(sl) = 0;
} else
ret = convert_t(sl, &info);
} else
ret = convert_t(sl, &info);
if (ret < 0) {
dev_dbg(device, "%s: Temperature data may be corrupted. err=%d\n",
__func__, ret); return0;
}
if ((!sl->family_data) || (!SLAVE_SPECIFIC_FUNC(sl))) {
dev_info(device, "%s: Device not supported by the driver\n", __func__); return0; /* No device family */
}
/* get the correct function depending on the device */
SLAVE_RESOLUTION(sl) = SLAVE_SPECIFIC_FUNC(sl)->get_resolution(sl); if (SLAVE_RESOLUTION(sl) < 0) {
dev_dbg(device, "%s: Resolution may be corrupted. err=%d\n",
__func__, SLAVE_RESOLUTION(sl));
}
static ssize_t resolution_store(struct device *device, struct device_attribute *attr, constchar *buf, size_t size)
{ struct w1_slave *sl = dev_to_w1_slave(device); int val; int ret = 0;
ret = kstrtoint(buf, 10, &val); /* converting user entry to int */
if (ret) { /* conversion error */
dev_info(device, "%s: conversion error. err= %d\n", __func__, ret); return size; /* return size to avoid call back again */
}
if ((!sl->family_data) || (!SLAVE_SPECIFIC_FUNC(sl))) {
dev_info(device, "%s: Device not supported by the driver\n", __func__); return size; /* No device family */
}
/* get the correct function depending on the device */
ret = SLAVE_SPECIFIC_FUNC(sl)->set_resolution(sl, val);
if (ret) return ret;
SLAVE_RESOLUTION(sl) = val; /* Reset the conversion time to default because it depends on resolution */
SLAVE_CONV_TIME_OVERRIDE(sl) = CONV_TIME_DEFAULT;
/* Write data in the device RAM */ if (!SLAVE_SPECIFIC_FUNC(sl)) {
dev_info(device, "%s: Device not supported by the driver %d\n",
__func__, -ENODEV); goto free_m;
}
ret = SLAVE_SPECIFIC_FUNC(sl)->write_data(sl, new_config_register); if (ret)
dev_info(device, "%s: error writing to the slave device %d\n",
__func__, ret);
if ((!sl->family_data) || (!SLAVE_SPECIFIC_FUNC(sl))) {
dev_info(device, "%s: Device is not supported by the driver\n", __func__); return0; /* No device family */
} return sprintf(buf, "%d\n", conversion_time(sl));
}
if ((!sl->family_data) || (!SLAVE_SPECIFIC_FUNC(sl))) {
dev_info(device, "%s: Device not supported by the driver\n", __func__); return0; /* No device family */
} return sprintf(buf, "%u\n", SLAVE_FEATURES(sl));
}
mutex_lock(&sl->master->bus_mutex); /* Place all devices in CHAIN state */ if (w1_reset_bus(sl->master)) goto error;
w1_write_8(sl->master, W1_SKIP_ROM);
w1_write_8(sl->master, W1_42_CHAIN);
w1_write_8(sl->master, W1_42_CHAIN_ON);
w1_write_8(sl->master, W1_42_CHAIN_ON_INV);
msleep(sl->master->pullup_duration);
/* check for acknowledgment */
ack = w1_read_8(sl->master); if (ack != W1_42_SUCCESS_CONFIRM_BYTE) goto error;
/* In case the bus fails to send 0xFF, limit */ for (i = 0; i <= 64; i++) { if (w1_reset_bus(sl->master)) goto error;
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.