diff options
author | Jiri Kosina <jkosina@suse.cz> | 2021-04-29 21:45:19 +0200 |
---|---|---|
committer | Jiri Kosina <jkosina@suse.cz> | 2021-04-29 21:45:19 +0200 |
commit | e50fedec822efc7b7090f95862b782d91ca8aec0 (patch) | |
tree | 22dd6b534d00a1f7fc3823f0d88e0d43547fc87b /drivers/w1 | |
parent | cfc9bdfb6ba76de84a9ed8ee75dc56903b505a78 (diff) | |
parent | 35a927f2848bd79586c6374ebb99e4207f3b0c7f (diff) |
Merge branch 'for-5.13/surface-system-aggregator-intergration' into for-linus
- Surface Aggregator Module support from Maximilian Luz
Diffstat (limited to 'drivers/w1')
-rw-r--r-- | drivers/w1/masters/ds2490.c | 25 | ||||
-rw-r--r-- | drivers/w1/slaves/w1_therm.c | 22 | ||||
-rw-r--r-- | drivers/w1/w1.c | 39 |
3 files changed, 66 insertions, 20 deletions
diff --git a/drivers/w1/masters/ds2490.c b/drivers/w1/masters/ds2490.c index e17c8f70dcd0..cd8821580f71 100644 --- a/drivers/w1/masters/ds2490.c +++ b/drivers/w1/masters/ds2490.c @@ -688,12 +688,22 @@ static void ds9490r_search(void *data, struct w1_master *master, * packet size. */ const size_t bufsize = 2 * 64; - u64 *buf; + u64 *buf, *found_ids; buf = kmalloc(bufsize, GFP_KERNEL); if (!buf) return; + /* + * We are holding the bus mutex during the scan, but adding devices via the + * callback needs the bus to be unlocked. So we queue up found ids here. + */ + found_ids = kmalloc_array(master->max_slave_count, sizeof(u64), GFP_KERNEL); + if (!found_ids) { + kfree(buf); + return; + } + mutex_lock(&master->bus_mutex); /* address to start searching at */ @@ -729,13 +739,13 @@ static void ds9490r_search(void *data, struct w1_master *master, if (err < 0) break; for (i = 0; i < err/8; ++i) { - ++found; - if (found <= search_limit) - callback(master, buf[i]); + found_ids[found++] = buf[i]; /* can't know if there will be a discrepancy * value after until the next id */ - if (found == search_limit) + if (found == search_limit) { master->search_id = buf[i]; + break; + } } } @@ -759,9 +769,14 @@ static void ds9490r_search(void *data, struct w1_master *master, master->max_slave_count); set_bit(W1_WARN_MAX_COUNT, &master->flags); } + search_out: mutex_unlock(&master->bus_mutex); kfree(buf); + + for (i = 0; i < found; i++) /* run callback for all queued up IDs */ + callback(master, found_ids[i]); + kfree(found_ids); } #if 0 diff --git a/drivers/w1/slaves/w1_therm.c b/drivers/w1/slaves/w1_therm.c index 3712b1e6dc71..976eea28f268 100644 --- a/drivers/w1/slaves/w1_therm.c +++ b/drivers/w1/slaves/w1_therm.c @@ -667,28 +667,24 @@ static inline int w1_DS18B20_get_resolution(struct w1_slave *sl) */ static inline int w1_DS18B20_convert_temp(u8 rom[9]) { - int t; - u32 bv; + u16 bv; + s16 t; + + /* 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) { - /* Signed 16-bit value to unsigned, cpu order */ - bv = le16_to_cpup((__le16 *)rom); - /* Insert two temperature bits from config register */ /* Avoid arithmetic shift of signed value */ bv = (bv << 2) | (rom[4] & 3); - - t = (int) sign_extend32(bv, 17); /* Degrees, lowest bit is 2^-6 */ - return (t*1000)/64; /* Millidegrees */ + t = (s16) bv; /* Degrees, lowest bit is 2^-6 */ + return (int)t * 1000 / 64; /* Sign-extend to int; millidegrees */ } - - t = (int)le16_to_cpup((__le16 *)rom); - return t*1000/16; + t = (s16)bv; /* Degrees, lowest bit is 2^-4 */ + return (int)t * 1000 / 16; /* Sign-extend to int; millidegrees */ } - - /** * w1_DS18S20_convert_temp() - temperature computation for DS18S20 * @rom: data read from device RAM (8 data bytes + 1 CRC byte) diff --git a/drivers/w1/w1.c b/drivers/w1/w1.c index 15a2ee32f116..f2ae2e563dc5 100644 --- a/drivers/w1/w1.c +++ b/drivers/w1/w1.c @@ -25,6 +25,8 @@ #include "w1_netlink.h" #define W1_FAMILY_DEFAULT 0 +#define W1_FAMILY_DS28E04 0x1C /* for crc quirk */ + static int w1_timeout = 10; module_param_named(timeout, w1_timeout, int, 0); @@ -913,11 +915,44 @@ void w1_reconnect_slaves(struct w1_family *f, int attach) mutex_unlock(&w1_mlock); } +static int w1_addr_crc_is_valid(struct w1_master *dev, u64 rn) +{ + u64 rn_le = cpu_to_le64(rn); + struct w1_reg_num *tmp = (struct w1_reg_num *)&rn; + u8 crc; + + crc = w1_calc_crc8((u8 *)&rn_le, 7); + + /* quirk: + * DS28E04 (1w eeprom) has strapping pins to change + * address, but will not update the crc. So normal rules + * for consistent w1 addresses are violated. We test + * with the 7 LSBs of the address forced high. + * + * (char*)&rn_le = { family, addr_lsb, ..., addr_msb, crc }. + */ + if (crc != tmp->crc && tmp->family == W1_FAMILY_DS28E04) { + u64 corr_le = rn_le; + + ((u8 *)&corr_le)[1] |= 0x7f; + crc = w1_calc_crc8((u8 *)&corr_le, 7); + + dev_info(&dev->dev, "DS28E04 crc workaround on %02x.%012llx.%02x\n", + tmp->family, (unsigned long long)tmp->id, tmp->crc); + } + + if (crc != tmp->crc) { + dev_dbg(&dev->dev, "w1 addr crc mismatch: %02x.%012llx.%02x != 0x%02x.\n", + tmp->family, (unsigned long long)tmp->id, tmp->crc, crc); + return 0; + } + return 1; +} + void w1_slave_found(struct w1_master *dev, u64 rn) { struct w1_slave *sl; struct w1_reg_num *tmp; - u64 rn_le = cpu_to_le64(rn); atomic_inc(&dev->refcnt); @@ -927,7 +962,7 @@ void w1_slave_found(struct w1_master *dev, u64 rn) if (sl) { set_bit(W1_SLAVE_ACTIVE, &sl->flags); } else { - if (rn && tmp->crc == w1_calc_crc8((u8 *)&rn_le, 7)) + if (rn && w1_addr_crc_is_valid(dev, rn)) w1_attach_slave_device(dev, tmp); } |