aboutsummaryrefslogtreecommitdiffstats
path: root/target/linux/bcm27xx/patches-5.4/950-0770-w1_therm-adding-eeprom-sysfs-entry.patch
diff options
context:
space:
mode:
authorÁlvaro Fernández Rojas <noltari@gmail.com>2021-02-18 18:04:33 +0100
committerÁlvaro Fernández Rojas <noltari@gmail.com>2021-02-18 23:42:32 +0100
commitf07e572f6447465d8938679533d604e402b0f066 (patch)
treecb333bd2a67e59e7c07659514850a0fd55fc825e /target/linux/bcm27xx/patches-5.4/950-0770-w1_therm-adding-eeprom-sysfs-entry.patch
parent5d3a6fd970619dfc55f8259035c3027d7613a2a6 (diff)
downloadupstream-f07e572f6447465d8938679533d604e402b0f066.tar.gz
upstream-f07e572f6447465d8938679533d604e402b0f066.tar.bz2
upstream-f07e572f6447465d8938679533d604e402b0f066.zip
bcm27xx: import latest patches from the RPi foundation
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>
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.patch372
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,