bcm2708: boot tested on RPi B+ v1.2
bcm2709: boot tested on RPi 3B v1.2 and RPi 4B v1.1 4G
bcm2710: boot tested on RPi 3B v1.2
bcm2711: boot tested on RPi 4B v1.1 4G
Signed-off-by: Álvaro Fernández Rojas <noltari@gmail.com>
(cherry-picked from commit f07e572f64)
		
	
		
			
				
	
	
		
			581 lines
		
	
	
		
			15 KiB
		
	
	
	
		
			Diff
		
	
	
	
	
	
			
		
		
	
	
			581 lines
		
	
	
		
			15 KiB
		
	
	
	
		
			Diff
		
	
	
	
	
	
From 7c49e87acd0412ff1fb2490c4ac6fcb5471afd9b Mon Sep 17 00:00:00 2001
 | 
						|
From: Akira Shimahara <akira215corp@gmail.com>
 | 
						|
Date: Mon, 11 May 2020 22:35:35 +0200
 | 
						|
Subject: [PATCH] w1_therm: adding code comments and code reordering
 | 
						|
 | 
						|
commit 92b8d2724464bc1d2e735a84c0da5741dce33485 upstream.
 | 
						|
 | 
						|
Adding code comments to split code in dedicated parts. After the global
 | 
						|
declarations (defines, macros and function declarations), code is organized
 | 
						|
as follow :
 | 
						|
 - Device and family dependent structures and functions
 | 
						|
 - Interfaces functions
 | 
						|
 - Helpers functions
 | 
						|
 - Hardware functions
 | 
						|
 - Sysfs interface functions
 | 
						|
 | 
						|
Signed-off-by: Akira Shimahara <akira215corp@gmail.com>
 | 
						|
Link: https://lore.kernel.org/r/20200511203535.409599-1-akira215corp@gmail.com
 | 
						|
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
 | 
						|
---
 | 
						|
 drivers/w1/slaves/w1_therm.c | 427 +++++++++++++++++++++--------------
 | 
						|
 1 file changed, 259 insertions(+), 168 deletions(-)
 | 
						|
 | 
						|
--- a/drivers/w1/slaves/w1_therm.c
 | 
						|
+++ b/drivers/w1/slaves/w1_therm.c
 | 
						|
@@ -25,7 +25,8 @@
 | 
						|
 #define W1_THERM_DS1825		0x3B
 | 
						|
 #define W1_THERM_DS28EA00	0x42
 | 
						|
 
 | 
						|
-/* Allow the strong pullup to be disabled, but default to enabled.
 | 
						|
+/*
 | 
						|
+ * Allow the strong pullup to be disabled, but default to enabled.
 | 
						|
  * If it was disabled a parasite powered device might not get the require
 | 
						|
  * current to do a temperature conversion.  If it is enabled parasite powered
 | 
						|
  * devices have a better chance of getting the current required.
 | 
						|
@@ -41,42 +42,55 @@
 | 
						|
 static int w1_strong_pullup = 1;
 | 
						|
 module_param_named(strong_pullup, w1_strong_pullup, int, 0);
 | 
						|
 
 | 
						|
+/* Helpers Macros */
 | 
						|
+
 | 
						|
+/* return the address of the refcnt in the family data */
 | 
						|
+#define THERM_REFCNT(family_data) \
 | 
						|
+	(&((struct w1_therm_family_data *)family_data)->refcnt)
 | 
						|
+
 | 
						|
+/* Structs definition */
 | 
						|
+
 | 
						|
+/**
 | 
						|
+ * struct w1_therm_family_converter - bind device specific functions
 | 
						|
+ * @broken: flag for non-registred families
 | 
						|
+ * @reserved: not used here
 | 
						|
+ * @f: pointer to the device binding structure
 | 
						|
+ * @convert: pointer to the device conversion function
 | 
						|
+ * @precision: pointer to the device precision function
 | 
						|
+ * @eeprom: pointer to eeprom function
 | 
						|
+ */
 | 
						|
+struct w1_therm_family_converter {
 | 
						|
+	u8		broken;
 | 
						|
+	u16		reserved;
 | 
						|
+	struct w1_family	*f;
 | 
						|
+	int		(*convert)(u8 rom[9]);
 | 
						|
+	int		(*precision)(struct device *device, int val);
 | 
						|
+	int		(*eeprom)(struct device *device);
 | 
						|
+};
 | 
						|
+
 | 
						|
+/**
 | 
						|
+ * struct w1_therm_family_data - device data
 | 
						|
+ * @rom: ROM device id (64bit Lasered ROM code + 1 CRC byte)
 | 
						|
+ * @refcnt: ref count
 | 
						|
+ */
 | 
						|
 struct w1_therm_family_data {
 | 
						|
 	uint8_t rom[9];
 | 
						|
 	atomic_t refcnt;
 | 
						|
 };
 | 
						|
 
 | 
						|
+/**
 | 
						|
+ * struct therm_info - store temperature reading
 | 
						|
+ * @rom: read device data (8 data bytes + 1 CRC byte)
 | 
						|
+ * @crc: computed crc from rom
 | 
						|
+ * @verdict: 1 crc checked, 0 crc not matching
 | 
						|
+ */
 | 
						|
 struct therm_info {
 | 
						|
 	u8 rom[9];
 | 
						|
 	u8 crc;
 | 
						|
 	u8 verdict;
 | 
						|
 };
 | 
						|
 
 | 
						|
-/* return the address of the refcnt in the family data */
 | 
						|
-#define THERM_REFCNT(family_data) \
 | 
						|
-	(&((struct w1_therm_family_data *)family_data)->refcnt)
 | 
						|
-
 | 
						|
-static int w1_therm_add_slave(struct w1_slave *sl)
 | 
						|
-{
 | 
						|
-	sl->family_data = kzalloc(sizeof(struct w1_therm_family_data),
 | 
						|
-		GFP_KERNEL);
 | 
						|
-	if (!sl->family_data)
 | 
						|
-		return -ENOMEM;
 | 
						|
-	atomic_set(THERM_REFCNT(sl->family_data), 1);
 | 
						|
-	return 0;
 | 
						|
-}
 | 
						|
-
 | 
						|
-static void w1_therm_remove_slave(struct w1_slave *sl)
 | 
						|
-{
 | 
						|
-	int refcnt = atomic_sub_return(1, THERM_REFCNT(sl->family_data));
 | 
						|
-
 | 
						|
-	while (refcnt) {
 | 
						|
-		msleep(1000);
 | 
						|
-		refcnt = atomic_read(THERM_REFCNT(sl->family_data));
 | 
						|
-	}
 | 
						|
-	kfree(sl->family_data);
 | 
						|
-	sl->family_data = NULL;
 | 
						|
-}
 | 
						|
+/* Sysfs interface declaration */
 | 
						|
 
 | 
						|
 static ssize_t w1_slave_show(struct device *device,
 | 
						|
 	struct device_attribute *attr, char *buf);
 | 
						|
@@ -87,9 +101,35 @@ static ssize_t w1_slave_store(struct dev
 | 
						|
 static ssize_t w1_seq_show(struct device *device,
 | 
						|
 	struct device_attribute *attr, char *buf);
 | 
						|
 
 | 
						|
+/* Attributes declarations */
 | 
						|
+
 | 
						|
 static DEVICE_ATTR_RW(w1_slave);
 | 
						|
 static DEVICE_ATTR_RO(w1_seq);
 | 
						|
 
 | 
						|
+/* Interface Functions declaration */
 | 
						|
+
 | 
						|
+/**
 | 
						|
+ * w1_therm_add_slave() - Called when a new slave is discovered
 | 
						|
+ * @sl: slave just discovered by the master.
 | 
						|
+ *
 | 
						|
+ * Called by the master when the slave is discovered on the bus. Used to
 | 
						|
+ * initialize slave state before the beginning of any communication.
 | 
						|
+ *
 | 
						|
+ * Return: 0 - If success, negative kernel code otherwise
 | 
						|
+ */
 | 
						|
+static int w1_therm_add_slave(struct w1_slave *sl);
 | 
						|
+
 | 
						|
+/**
 | 
						|
+ * w1_therm_remove_slave() - Called when a slave is removed
 | 
						|
+ * @sl: slave to be removed.
 | 
						|
+ *
 | 
						|
+ * Called by the master when the slave is considered not to be on the bus
 | 
						|
+ * anymore. Used to free memory.
 | 
						|
+ */
 | 
						|
+static void w1_therm_remove_slave(struct w1_slave *sl);
 | 
						|
+
 | 
						|
+/* Family attributes */
 | 
						|
+
 | 
						|
 static struct attribute *w1_therm_attrs[] = {
 | 
						|
 	&dev_attr_w1_slave.attr,
 | 
						|
 	NULL,
 | 
						|
@@ -101,6 +141,8 @@ static struct attribute *w1_ds28ea00_att
 | 
						|
 	NULL,
 | 
						|
 };
 | 
						|
 
 | 
						|
+/* Attribute groups */
 | 
						|
+
 | 
						|
 ATTRIBUTE_GROUPS(w1_therm);
 | 
						|
 ATTRIBUTE_GROUPS(w1_ds28ea00);
 | 
						|
 
 | 
						|
@@ -154,6 +196,8 @@ static const struct hwmon_chip_info w1_c
 | 
						|
 #define W1_CHIPINFO	NULL
 | 
						|
 #endif
 | 
						|
 
 | 
						|
+/* Family operations */
 | 
						|
+
 | 
						|
 static struct w1_family_ops w1_therm_fops = {
 | 
						|
 	.add_slave	= w1_therm_add_slave,
 | 
						|
 	.remove_slave	= w1_therm_remove_slave,
 | 
						|
@@ -168,6 +212,8 @@ static struct w1_family_ops w1_ds28ea00_
 | 
						|
 	.chip_info	= W1_CHIPINFO,
 | 
						|
 };
 | 
						|
 
 | 
						|
+/* Family binding operations struct */
 | 
						|
+
 | 
						|
 static struct w1_family w1_therm_family_DS18S20 = {
 | 
						|
 	.fid = W1_THERM_DS18S20,
 | 
						|
 	.fops = &w1_therm_fops,
 | 
						|
@@ -193,138 +239,18 @@ static struct w1_family w1_therm_family_
 | 
						|
 	.fops = &w1_therm_fops,
 | 
						|
 };
 | 
						|
 
 | 
						|
-struct w1_therm_family_converter {
 | 
						|
-	u8			broken;
 | 
						|
-	u16			reserved;
 | 
						|
-	struct w1_family	*f;
 | 
						|
-	int			(*convert)(u8 rom[9]);
 | 
						|
-	int			(*precision)(struct device *device, int val);
 | 
						|
-	int			(*eeprom)(struct device *device);
 | 
						|
-};
 | 
						|
+/* Device dependent func */
 | 
						|
 
 | 
						|
 /* write configuration to eeprom */
 | 
						|
 static inline int w1_therm_eeprom(struct device *device);
 | 
						|
 
 | 
						|
-/* Set precision for conversion */
 | 
						|
-static inline int w1_DS18B20_precision(struct device *device, int val);
 | 
						|
-static inline int w1_DS18S20_precision(struct device *device, int val);
 | 
						|
-
 | 
						|
-/* The return value is millidegrees Centigrade. */
 | 
						|
-static inline int w1_DS18B20_convert_temp(u8 rom[9]);
 | 
						|
-static inline int w1_DS18S20_convert_temp(u8 rom[9]);
 | 
						|
-
 | 
						|
-static struct w1_therm_family_converter w1_therm_families[] = {
 | 
						|
-	{
 | 
						|
-		.f		= &w1_therm_family_DS18S20,
 | 
						|
-		.convert	= w1_DS18S20_convert_temp,
 | 
						|
-		.precision	= w1_DS18S20_precision,
 | 
						|
-		.eeprom		= w1_therm_eeprom
 | 
						|
-	},
 | 
						|
-	{
 | 
						|
-		.f		= &w1_therm_family_DS1822,
 | 
						|
-		.convert	= w1_DS18B20_convert_temp,
 | 
						|
-		.precision	= w1_DS18S20_precision,
 | 
						|
-		.eeprom		= w1_therm_eeprom
 | 
						|
-	},
 | 
						|
-	{
 | 
						|
-		.f		= &w1_therm_family_DS18B20,
 | 
						|
-		.convert	= w1_DS18B20_convert_temp,
 | 
						|
-		.precision	= w1_DS18B20_precision,
 | 
						|
-		.eeprom		= w1_therm_eeprom
 | 
						|
-	},
 | 
						|
-	{
 | 
						|
-		.f		= &w1_therm_family_DS28EA00,
 | 
						|
-		.convert	= w1_DS18B20_convert_temp,
 | 
						|
-		.precision	= w1_DS18S20_precision,
 | 
						|
-		.eeprom		= w1_therm_eeprom
 | 
						|
-	},
 | 
						|
-	{
 | 
						|
-		.f		= &w1_therm_family_DS1825,
 | 
						|
-		.convert	= w1_DS18B20_convert_temp,
 | 
						|
-		.precision	= w1_DS18S20_precision,
 | 
						|
-		.eeprom		= w1_therm_eeprom
 | 
						|
-	}
 | 
						|
-};
 | 
						|
-
 | 
						|
-static inline int w1_therm_eeprom(struct device *device)
 | 
						|
-{
 | 
						|
-	struct w1_slave *sl = dev_to_w1_slave(device);
 | 
						|
-	struct w1_master *dev = sl->master;
 | 
						|
-	u8 rom[9], external_power;
 | 
						|
-	int ret, max_trying = 10;
 | 
						|
-	u8 *family_data = sl->family_data;
 | 
						|
-
 | 
						|
-	if (!sl->family_data) {
 | 
						|
-		ret = -ENODEV;
 | 
						|
-		goto error;
 | 
						|
-	}
 | 
						|
-
 | 
						|
-	/* prevent the slave from going away in sleep */
 | 
						|
-	atomic_inc(THERM_REFCNT(family_data));
 | 
						|
-
 | 
						|
-	ret = mutex_lock_interruptible(&dev->bus_mutex);
 | 
						|
-	if (ret != 0)
 | 
						|
-		goto dec_refcnt;
 | 
						|
-
 | 
						|
-	memset(rom, 0, sizeof(rom));
 | 
						|
-
 | 
						|
-	while (max_trying--) {
 | 
						|
-		if (!w1_reset_select_slave(sl)) {
 | 
						|
-			unsigned int tm = 10;
 | 
						|
-			unsigned long sleep_rem;
 | 
						|
-
 | 
						|
-			/* check if in parasite mode */
 | 
						|
-			w1_write_8(dev, W1_READ_PSUPPLY);
 | 
						|
-			external_power = w1_read_8(dev);
 | 
						|
-
 | 
						|
-			if (w1_reset_select_slave(sl))
 | 
						|
-				continue;
 | 
						|
-
 | 
						|
-			/* 10ms strong pullup/delay after the copy command */
 | 
						|
-			if (w1_strong_pullup == 2 ||
 | 
						|
-			    (!external_power && w1_strong_pullup))
 | 
						|
-				w1_next_pullup(dev, tm);
 | 
						|
-
 | 
						|
-			w1_write_8(dev, W1_COPY_SCRATCHPAD);
 | 
						|
-
 | 
						|
-			if (external_power) {
 | 
						|
-				mutex_unlock(&dev->bus_mutex);
 | 
						|
-
 | 
						|
-				sleep_rem = msleep_interruptible(tm);
 | 
						|
-				if (sleep_rem != 0) {
 | 
						|
-					ret = -EINTR;
 | 
						|
-					goto dec_refcnt;
 | 
						|
-				}
 | 
						|
-
 | 
						|
-				ret = mutex_lock_interruptible(&dev->bus_mutex);
 | 
						|
-				if (ret != 0)
 | 
						|
-					goto dec_refcnt;
 | 
						|
-			} else if (!w1_strong_pullup) {
 | 
						|
-				sleep_rem = msleep_interruptible(tm);
 | 
						|
-				if (sleep_rem != 0) {
 | 
						|
-					ret = -EINTR;
 | 
						|
-					goto mt_unlock;
 | 
						|
-				}
 | 
						|
-			}
 | 
						|
-
 | 
						|
-			break;
 | 
						|
-		}
 | 
						|
-	}
 | 
						|
-
 | 
						|
-mt_unlock:
 | 
						|
-	mutex_unlock(&dev->bus_mutex);
 | 
						|
-dec_refcnt:
 | 
						|
-	atomic_dec(THERM_REFCNT(family_data));
 | 
						|
-error:
 | 
						|
-	return ret;
 | 
						|
-}
 | 
						|
-
 | 
						|
 /* DS18S20 does not feature configuration register */
 | 
						|
 static inline int w1_DS18S20_precision(struct device *device, int val)
 | 
						|
 {
 | 
						|
 	return 0;
 | 
						|
 }
 | 
						|
 
 | 
						|
+/* Set precision for conversion */
 | 
						|
 static inline int w1_DS18B20_precision(struct device *device, int val)
 | 
						|
 {
 | 
						|
 	struct w1_slave *sl = dev_to_w1_slave(device);
 | 
						|
@@ -407,6 +333,14 @@ error:
 | 
						|
 	return ret;
 | 
						|
 }
 | 
						|
 
 | 
						|
+/**
 | 
						|
+ * w1_DS18B20_convert_temp() - temperature computation for DS18B20
 | 
						|
+ * @rom: data read from device RAM (8 data bytes + 1 CRC byte)
 | 
						|
+ *
 | 
						|
+ * Can be called for any DS18B20 compliant device.
 | 
						|
+ *
 | 
						|
+ * Return: value in millidegrees Celsius.
 | 
						|
+ */
 | 
						|
 static inline int w1_DS18B20_convert_temp(u8 rom[9])
 | 
						|
 {
 | 
						|
 	s16 t = le16_to_cpup((__le16 *)rom);
 | 
						|
@@ -414,6 +348,14 @@ static inline int w1_DS18B20_convert_tem
 | 
						|
 	return t*1000/16;
 | 
						|
 }
 | 
						|
 
 | 
						|
+/**
 | 
						|
+ * w1_DS18S20_convert_temp() - temperature computation for DS18S20
 | 
						|
+ * @rom: data read from device RAM (8 data bytes + 1 CRC byte)
 | 
						|
+ *
 | 
						|
+ * Can be called for any DS18S20 compliant device.
 | 
						|
+ *
 | 
						|
+ * Return: value in millidegrees Celsius.
 | 
						|
+ */
 | 
						|
 static inline int w1_DS18S20_convert_temp(u8 rom[9])
 | 
						|
 {
 | 
						|
 	int t, h;
 | 
						|
@@ -434,6 +376,53 @@ static inline int w1_DS18S20_convert_tem
 | 
						|
 	return t;
 | 
						|
 }
 | 
						|
 
 | 
						|
+/* Device capability description */
 | 
						|
+
 | 
						|
+static struct w1_therm_family_converter w1_therm_families[] = {
 | 
						|
+	{
 | 
						|
+		.f		= &w1_therm_family_DS18S20,
 | 
						|
+		.convert	= w1_DS18S20_convert_temp,
 | 
						|
+		.precision	= w1_DS18S20_precision,
 | 
						|
+		.eeprom		= w1_therm_eeprom
 | 
						|
+	},
 | 
						|
+	{
 | 
						|
+		.f		= &w1_therm_family_DS1822,
 | 
						|
+		.convert	= w1_DS18B20_convert_temp,
 | 
						|
+		.precision	= w1_DS18S20_precision,
 | 
						|
+		.eeprom		= w1_therm_eeprom
 | 
						|
+	},
 | 
						|
+	{
 | 
						|
+		.f		= &w1_therm_family_DS18B20,
 | 
						|
+		.convert	= w1_DS18B20_convert_temp,
 | 
						|
+		.precision	= w1_DS18B20_precision,
 | 
						|
+		.eeprom		= w1_therm_eeprom
 | 
						|
+	},
 | 
						|
+	{
 | 
						|
+		.f		= &w1_therm_family_DS28EA00,
 | 
						|
+		.convert	= w1_DS18B20_convert_temp,
 | 
						|
+		.precision	= w1_DS18S20_precision,
 | 
						|
+		.eeprom		= w1_therm_eeprom
 | 
						|
+	},
 | 
						|
+	{
 | 
						|
+		.f		= &w1_therm_family_DS1825,
 | 
						|
+		.convert	= w1_DS18B20_convert_temp,
 | 
						|
+		.precision	= w1_DS18S20_precision,
 | 
						|
+		.eeprom		= w1_therm_eeprom
 | 
						|
+	}
 | 
						|
+};
 | 
						|
+
 | 
						|
+/* Helpers Functions */
 | 
						|
+
 | 
						|
+/**
 | 
						|
+ * w1_convert_temp() - temperature conversion binding function
 | 
						|
+ * @rom: data read from device RAM (8 data bytes + 1 CRC byte)
 | 
						|
+ * @fid: device family id
 | 
						|
+ *
 | 
						|
+ * The function call the temperature computation function according to
 | 
						|
+ * device family.
 | 
						|
+ *
 | 
						|
+ * Return: value in millidegrees Celsius.
 | 
						|
+ */
 | 
						|
 static inline int w1_convert_temp(u8 rom[9], u8 fid)
 | 
						|
 {
 | 
						|
 	int i;
 | 
						|
@@ -445,31 +434,32 @@ static inline int w1_convert_temp(u8 rom
 | 
						|
 	return 0;
 | 
						|
 }
 | 
						|
 
 | 
						|
-static ssize_t w1_slave_store(struct device *device,
 | 
						|
-			      struct device_attribute *attr, const char *buf,
 | 
						|
-			      size_t size)
 | 
						|
+/* Interface Functions */
 | 
						|
+
 | 
						|
+static int w1_therm_add_slave(struct w1_slave *sl)
 | 
						|
 {
 | 
						|
-	int val, ret;
 | 
						|
-	struct w1_slave *sl = dev_to_w1_slave(device);
 | 
						|
-	int i;
 | 
						|
+	sl->family_data = kzalloc(sizeof(struct w1_therm_family_data),
 | 
						|
+		GFP_KERNEL);
 | 
						|
+	if (!sl->family_data)
 | 
						|
+		return -ENOMEM;
 | 
						|
+	atomic_set(THERM_REFCNT(sl->family_data), 1);
 | 
						|
+	return 0;
 | 
						|
+}
 | 
						|
 
 | 
						|
-	ret = kstrtoint(buf, 0, &val);
 | 
						|
-	if (ret)
 | 
						|
-		return ret;
 | 
						|
+static void w1_therm_remove_slave(struct w1_slave *sl)
 | 
						|
+{
 | 
						|
+	int refcnt = atomic_sub_return(1, THERM_REFCNT(sl->family_data));
 | 
						|
 
 | 
						|
-	for (i = 0; i < ARRAY_SIZE(w1_therm_families); ++i) {
 | 
						|
-		if (w1_therm_families[i].f->fid == sl->family->fid) {
 | 
						|
-			/* zero value indicates to write current configuration to eeprom */
 | 
						|
-			if (val == 0)
 | 
						|
-				ret = w1_therm_families[i].eeprom(device);
 | 
						|
-			else
 | 
						|
-				ret = w1_therm_families[i].precision(device, val);
 | 
						|
-			break;
 | 
						|
-		}
 | 
						|
+	while (refcnt) {
 | 
						|
+		msleep(1000);
 | 
						|
+		refcnt = atomic_read(THERM_REFCNT(sl->family_data));
 | 
						|
 	}
 | 
						|
-	return ret ? : size;
 | 
						|
+	kfree(sl->family_data);
 | 
						|
+	sl->family_data = NULL;
 | 
						|
 }
 | 
						|
 
 | 
						|
+/* Hardware Functions */
 | 
						|
+
 | 
						|
 static ssize_t read_therm(struct device *device,
 | 
						|
 			  struct w1_slave *sl, struct therm_info *info)
 | 
						|
 {
 | 
						|
@@ -564,6 +554,81 @@ error:
 | 
						|
 	return ret;
 | 
						|
 }
 | 
						|
 
 | 
						|
+static inline int w1_therm_eeprom(struct device *device)
 | 
						|
+{
 | 
						|
+	struct w1_slave *sl = dev_to_w1_slave(device);
 | 
						|
+	struct w1_master *dev = sl->master;
 | 
						|
+	u8 rom[9], external_power;
 | 
						|
+	int ret, max_trying = 10;
 | 
						|
+	u8 *family_data = sl->family_data;
 | 
						|
+
 | 
						|
+	if (!sl->family_data) {
 | 
						|
+		ret = -ENODEV;
 | 
						|
+		goto error;
 | 
						|
+	}
 | 
						|
+
 | 
						|
+	/* prevent the slave from going away in sleep */
 | 
						|
+	atomic_inc(THERM_REFCNT(family_data));
 | 
						|
+
 | 
						|
+	ret = mutex_lock_interruptible(&dev->bus_mutex);
 | 
						|
+	if (ret != 0)
 | 
						|
+		goto dec_refcnt;
 | 
						|
+
 | 
						|
+	memset(rom, 0, sizeof(rom));
 | 
						|
+
 | 
						|
+	while (max_trying--) {
 | 
						|
+		if (!w1_reset_select_slave(sl)) {
 | 
						|
+			unsigned int tm = 10;
 | 
						|
+			unsigned long sleep_rem;
 | 
						|
+
 | 
						|
+			/* check if in parasite mode */
 | 
						|
+			w1_write_8(dev, W1_READ_PSUPPLY);
 | 
						|
+			external_power = w1_read_8(dev);
 | 
						|
+
 | 
						|
+			if (w1_reset_select_slave(sl))
 | 
						|
+				continue;
 | 
						|
+
 | 
						|
+			/* 10ms strong pullup/delay after the copy command */
 | 
						|
+			if (w1_strong_pullup == 2 ||
 | 
						|
+			    (!external_power && w1_strong_pullup))
 | 
						|
+				w1_next_pullup(dev, tm);
 | 
						|
+
 | 
						|
+			w1_write_8(dev, W1_COPY_SCRATCHPAD);
 | 
						|
+
 | 
						|
+			if (external_power) {
 | 
						|
+				mutex_unlock(&dev->bus_mutex);
 | 
						|
+
 | 
						|
+				sleep_rem = msleep_interruptible(tm);
 | 
						|
+				if (sleep_rem != 0) {
 | 
						|
+					ret = -EINTR;
 | 
						|
+					goto dec_refcnt;
 | 
						|
+				}
 | 
						|
+
 | 
						|
+				ret = mutex_lock_interruptible(&dev->bus_mutex);
 | 
						|
+				if (ret != 0)
 | 
						|
+					goto dec_refcnt;
 | 
						|
+			} else if (!w1_strong_pullup) {
 | 
						|
+				sleep_rem = msleep_interruptible(tm);
 | 
						|
+				if (sleep_rem != 0) {
 | 
						|
+					ret = -EINTR;
 | 
						|
+					goto mt_unlock;
 | 
						|
+				}
 | 
						|
+			}
 | 
						|
+
 | 
						|
+			break;
 | 
						|
+		}
 | 
						|
+	}
 | 
						|
+
 | 
						|
+mt_unlock:
 | 
						|
+	mutex_unlock(&dev->bus_mutex);
 | 
						|
+dec_refcnt:
 | 
						|
+	atomic_dec(THERM_REFCNT(family_data));
 | 
						|
+error:
 | 
						|
+	return ret;
 | 
						|
+}
 | 
						|
+
 | 
						|
+/* Sysfs Interface definition */
 | 
						|
+
 | 
						|
 static ssize_t w1_slave_show(struct device *device,
 | 
						|
 			     struct device_attribute *attr, char *buf)
 | 
						|
 {
 | 
						|
@@ -597,6 +662,32 @@ static ssize_t w1_slave_show(struct devi
 | 
						|
 	return ret;
 | 
						|
 }
 | 
						|
 
 | 
						|
+static ssize_t w1_slave_store(struct device *device,
 | 
						|
+			      struct device_attribute *attr, const char *buf,
 | 
						|
+			      size_t size)
 | 
						|
+{
 | 
						|
+	int val, ret;
 | 
						|
+	struct w1_slave *sl = dev_to_w1_slave(device);
 | 
						|
+	int i;
 | 
						|
+
 | 
						|
+	ret = kstrtoint(buf, 0, &val);
 | 
						|
+	if (ret)
 | 
						|
+		return ret;
 | 
						|
+
 | 
						|
+	for (i = 0; i < ARRAY_SIZE(w1_therm_families); ++i) {
 | 
						|
+		if (w1_therm_families[i].f->fid == sl->family->fid) {
 | 
						|
+	/* zero value indicates to write current configuration to eeprom */
 | 
						|
+			if (val == 0)
 | 
						|
+				ret = w1_therm_families[i].eeprom(device);
 | 
						|
+			else
 | 
						|
+				ret = w1_therm_families[i].precision(device,
 | 
						|
+									val);
 | 
						|
+			break;
 | 
						|
+		}
 | 
						|
+	}
 | 
						|
+	return ret ? : size;
 | 
						|
+}
 | 
						|
+
 | 
						|
 #if IS_REACHABLE(CONFIG_HWMON)
 | 
						|
 static int w1_read_temp(struct device *device, u32 attr, int channel,
 | 
						|
 			long *val)
 | 
						|
@@ -666,7 +757,7 @@ static ssize_t w1_seq_show(struct device
 | 
						|
 	if (ack != W1_42_SUCCESS_CONFIRM_BYTE)
 | 
						|
 		goto error;
 | 
						|
 
 | 
						|
-	/* In case the bus fails to send 0xFF, limit*/
 | 
						|
+	/* In case the bus fails to send 0xFF, limit */
 | 
						|
 	for (i = 0; i <= 64; i++) {
 | 
						|
 		if (w1_reset_bus(sl->master))
 | 
						|
 			goto error;
 |