diff options
Diffstat (limited to 'target/linux/bcm27xx/patches-5.4/950-0770-w1_therm-adding-eeprom-sysfs-entry.patch')
-rw-r--r-- | target/linux/bcm27xx/patches-5.4/950-0770-w1_therm-adding-eeprom-sysfs-entry.patch | 372 |
1 files changed, 372 insertions, 0 deletions
diff --git a/target/linux/bcm27xx/patches-5.4/950-0770-w1_therm-adding-eeprom-sysfs-entry.patch b/target/linux/bcm27xx/patches-5.4/950-0770-w1_therm-adding-eeprom-sysfs-entry.patch new file mode 100644 index 0000000000..58467a00c3 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0770-w1_therm-adding-eeprom-sysfs-entry.patch @@ -0,0 +1,372 @@ +From 855a8d82506c7c2428e13beebe8dbf7739ea6176 Mon Sep 17 00:00:00 2001 +From: Akira Shimahara <akira215corp@gmail.com> +Date: Mon, 11 May 2020 22:37:25 +0200 +Subject: [PATCH] w1_therm: adding eeprom sysfs entry + +commit 45d457a4cf24455eefd076a01a3d86414fc2ff1e upstream. + +The driver implement 2 hardware functions to access device RAM: + * copy_scratchpad + * recall_scratchpad +They act according to device specifications. + +As EEPROM operations are not device dependent (all w1_therm can perform +EEPROM read/write operation following the same protocol), it is removed +from device families structures. + +Updating Documentation/ABI/testing/sysfs-driver-w1_therm accordingly. + +Signed-off-by: Akira Shimahara <akira215corp@gmail.com> +Link: https://lore.kernel.org/r/20200511203725.410844-1-akira215corp@gmail.com +Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> +--- + .../ABI/testing/sysfs-driver-w1_therm | 14 ++ + drivers/w1/slaves/w1_therm.c | 175 ++++++++++++------ + 2 files changed, 132 insertions(+), 57 deletions(-) + +--- a/Documentation/ABI/testing/sysfs-driver-w1_therm ++++ b/Documentation/ABI/testing/sysfs-driver-w1_therm +@@ -1,3 +1,17 @@ ++What: /sys/bus/w1/devices/.../eeprom ++Date: May 2020 ++Contact: Akira Shimahara <akira215corp@gmail.com> ++Description: ++ (WO) writing that file will either trigger a save of the ++ device data to its embedded EEPROM, either restore data ++ embedded in device EEPROM. Be aware that devices support ++ limited EEPROM writing cycles (typical 50k) ++ * 'save': save device RAM to EEPROM ++ * 'restore': restore EEPROM data in device RAM ++Users: any user space application which wants to communicate with ++ w1_term device ++ ++ + What: /sys/bus/w1/devices/.../ext_power + Date: May 2020 + Contact: Akira Shimahara <akira215corp@gmail.com> +--- a/drivers/w1/slaves/w1_therm.c ++++ b/drivers/w1/slaves/w1_therm.c +@@ -43,12 +43,21 @@ + static int w1_strong_pullup = 1; + module_param_named(strong_pullup, w1_strong_pullup, int, 0); + ++/* This command should be in public header w1.h but is not */ ++#define W1_RECALL_EEPROM 0xB8 ++ + /* Nb of try for an operation */ + #define W1_THERM_MAX_TRY 5 + + /* ms delay to retry bus mutex */ + #define W1_THERM_RETRY_DELAY 20 + ++/* delay in ms to write in EEPROM */ ++#define W1_THERM_EEPROM_WRITE_DELAY 10 ++ ++#define EEPROM_CMD_WRITE "save" /* cmd for write eeprom sysfs */ ++#define EEPROM_CMD_READ "restore" /* cmd for read eeprom sysfs */ ++ + /* Helpers Macros */ + + /* +@@ -86,7 +95,6 @@ module_param_named(strong_pullup, w1_str + * @convert: pointer to the device conversion function + * @set_resolution: pointer to the device set_resolution function + * @get_resolution: pointer to the device get_resolution function +- * @eeprom: pointer to eeprom function + */ + struct w1_therm_family_converter { + u8 broken; +@@ -95,7 +103,6 @@ struct w1_therm_family_converter { + int (*convert)(u8 rom[9]); + int (*set_resolution)(struct w1_slave *sl, int val); + int (*get_resolution)(struct w1_slave *sl); +- int (*eeprom)(struct device *device); + }; + + /** +@@ -166,6 +173,22 @@ static int read_scratchpad(struct w1_sla + static int write_scratchpad(struct w1_slave *sl, const u8 *data, u8 nb_bytes); + + /** ++ * copy_scratchpad() - Copy the content of scratchpad in device EEPROM ++ * @sl: slave involved ++ * ++ * Return: 0 if success, -kernel error code otherwise ++ */ ++static int copy_scratchpad(struct w1_slave *sl); ++ ++/** ++ * recall_eeprom() - Restore EEPROM data to device RAM ++ * @sl: slave involved ++ * ++ * Return: 0 if success, -kernel error code otherwise ++ */ ++static int recall_eeprom(struct w1_slave *sl); ++ ++/** + * read_powermode() - Query the power mode of the slave + * @sl: slave to retrieve the power mode + * +@@ -199,12 +222,16 @@ static ssize_t resolution_show(struct de + static ssize_t resolution_store(struct device *device, + struct device_attribute *attr, const char *buf, size_t size); + ++static ssize_t eeprom_store(struct device *device, ++ struct device_attribute *attr, const char *buf, size_t size); ++ + /* Attributes declarations */ + + static DEVICE_ATTR_RW(w1_slave); + static DEVICE_ATTR_RO(w1_seq); + static DEVICE_ATTR_RO(ext_power); + static DEVICE_ATTR_RW(resolution); ++static DEVICE_ATTR_WO(eeprom); + + /* Interface Functions declaration */ + +@@ -234,12 +261,14 @@ static struct attribute *w1_therm_attrs[ + &dev_attr_w1_slave.attr, + &dev_attr_ext_power.attr, + &dev_attr_resolution.attr, ++ &dev_attr_eeprom.attr, + NULL, + }; + + static struct attribute *w1_ds18s20_attrs[] = { + &dev_attr_w1_slave.attr, + &dev_attr_ext_power.attr, ++ &dev_attr_eeprom.attr, + NULL, + }; + +@@ -248,6 +277,7 @@ static struct attribute *w1_ds28ea00_att + &dev_attr_w1_seq.attr, + &dev_attr_ext_power.attr, + &dev_attr_resolution.attr, ++ &dev_attr_eeprom.attr, + NULL, + }; + +@@ -359,9 +389,6 @@ static struct w1_family w1_therm_family_ + + /* Device dependent func */ + +-/* write configuration to eeprom */ +-static inline int w1_therm_eeprom(struct device *device); +- + static inline int w1_DS18B20_write_data(struct w1_slave *sl, + const u8 *data) + { +@@ -477,35 +504,30 @@ static struct w1_therm_family_converter + .convert = w1_DS18S20_convert_temp, + .set_resolution = NULL, /* no config register */ + .get_resolution = NULL, /* no config register */ +- .eeprom = w1_therm_eeprom + }, + { + .f = &w1_therm_family_DS1822, + .convert = w1_DS18B20_convert_temp, + .set_resolution = w1_DS18B20_set_resolution, + .get_resolution = w1_DS18B20_get_resolution, +- .eeprom = w1_therm_eeprom + }, + { + .f = &w1_therm_family_DS18B20, + .convert = w1_DS18B20_convert_temp, + .set_resolution = w1_DS18B20_set_resolution, + .get_resolution = w1_DS18B20_get_resolution, +- .eeprom = w1_therm_eeprom + }, + { + .f = &w1_therm_family_DS28EA00, + .convert = w1_DS18B20_convert_temp, + .set_resolution = w1_DS18B20_set_resolution, + .get_resolution = w1_DS18B20_get_resolution, +- .eeprom = w1_therm_eeprom + }, + { + .f = &w1_therm_family_DS1825, + .convert = w1_DS18B20_convert_temp, + .set_resolution = w1_DS18B20_set_resolution, + .get_resolution = w1_DS18B20_get_resolution, +- .eeprom = w1_therm_eeprom + } + }; + +@@ -838,75 +860,94 @@ error: + return ret; + } + +-static inline int w1_therm_eeprom(struct device *device) ++static int copy_scratchpad(struct w1_slave *sl) + { +- 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; ++ struct w1_master *dev_master = sl->master; ++ int max_trying = W1_THERM_MAX_TRY; ++ int t_write, ret = -ENODEV; ++ bool strong_pullup; + +- if (!sl->family_data) { +- ret = -ENODEV; ++ if (!sl->family_data) + goto error; +- } ++ ++ t_write = W1_THERM_EEPROM_WRITE_DELAY; ++ strong_pullup = (w1_strong_pullup == 2 || ++ (!SLAVE_POWERMODE(sl) && ++ w1_strong_pullup)); + + /* prevent the slave from going away in sleep */ +- atomic_inc(THERM_REFCNT(family_data)); ++ atomic_inc(THERM_REFCNT(sl->family_data)); + +- ret = mutex_lock_interruptible(&dev->bus_mutex); +- if (ret != 0) ++ if (!bus_mutex_lock(&dev_master->bus_mutex)) { ++ ret = -EAGAIN; /* Didn't acquire the mutex */ + goto dec_refcnt; ++ } + +- memset(rom, 0, sizeof(rom)); +- +- while (max_trying--) { ++ while (max_trying-- && ret) { /* ret should be 0 */ ++ /* safe version to select slave */ + if (!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 (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); ++ /* 10ms strong pullup (or delay) after the convert */ ++ if (strong_pullup) ++ w1_next_pullup(dev_master, t_write); + +- sleep_rem = msleep_interruptible(tm); +- if (sleep_rem != 0) { +- ret = -EINTR; +- goto dec_refcnt; +- } ++ w1_write_8(dev_master, W1_COPY_SCRATCHPAD); + +- ret = mutex_lock_interruptible(&dev->bus_mutex); +- if (ret != 0) +- goto dec_refcnt; +- } else if (!w1_strong_pullup) { +- sleep_rem = msleep_interruptible(tm); ++ if (strong_pullup) { ++ sleep_rem = msleep_interruptible(t_write); + if (sleep_rem != 0) { + ret = -EINTR; + goto mt_unlock; + } + } +- +- break; ++ ret = 0; + } ++ + } + + mt_unlock: +- mutex_unlock(&dev->bus_mutex); ++ mutex_unlock(&dev_master->bus_mutex); + dec_refcnt: +- atomic_dec(THERM_REFCNT(family_data)); ++ atomic_dec(THERM_REFCNT(sl->family_data)); ++error: ++ return ret; ++} ++ ++static int recall_eeprom(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) { /* ret should be 0 */ ++ /* safe version to select slave */ ++ if (!reset_select_slave(sl)) { ++ ++ w1_write_8(dev_master, W1_RECALL_EEPROM); ++ ++ ret = 1; /* Slave will pull line to 0 */ ++ while (ret) ++ ret = 1 - w1_touch_bit(dev_master, 1); ++ } ++ ++ } ++ ++ mutex_unlock(&dev_master->bus_mutex); ++ ++dec_refcnt: ++ atomic_dec(THERM_REFCNT(sl->family_data)); + error: + return ret; + } +@@ -1006,7 +1047,7 @@ static ssize_t w1_slave_store(struct dev + } + + if (val == 0) /* val=0 : trigger a EEPROM save */ +- ret = SLAVE_SPECIFIC_FUNC(sl)->eeprom(device); ++ ret = copy_scratchpad(sl); + else { + if (SLAVE_SPECIFIC_FUNC(sl)->set_resolution) + ret = SLAVE_SPECIFIC_FUNC(sl)->set_resolution(sl, val); +@@ -1104,6 +1145,26 @@ static ssize_t resolution_store(struct d + + return size; + } ++ ++static ssize_t eeprom_store(struct device *device, ++ struct device_attribute *attr, const char *buf, size_t size) ++{ ++ struct w1_slave *sl = dev_to_w1_slave(device); ++ int ret = -EINVAL; /* Invalid argument */ ++ ++ if (size == sizeof(EEPROM_CMD_WRITE)) { ++ if (!strncmp(buf, EEPROM_CMD_WRITE, sizeof(EEPROM_CMD_WRITE)-1)) ++ ret = copy_scratchpad(sl); ++ } else if (size == sizeof(EEPROM_CMD_READ)) { ++ if (!strncmp(buf, EEPROM_CMD_READ, sizeof(EEPROM_CMD_READ)-1)) ++ ret = recall_eeprom(sl); ++ } ++ ++ if (ret) ++ dev_info(device, "%s: error in process %d\n", __func__, ret); ++ ++ return size; ++} + + #if IS_REACHABLE(CONFIG_HWMON) + static int w1_read_temp(struct device *device, u32 attr, int channel, |