diff options
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-19 07:17:21 +0100 |
commit | 62b7f5931c54e96fca56dd8761b0e466d355c881 (patch) | |
tree | 1258b392752379833a075df006c2f6d7ac4be51d /target/linux/bcm27xx/patches-5.4/950-0768-w1_therm-adding-ext_power-sysfs-entry.patch | |
parent | 76d1168d0d4b9d76e2ad78c0fc6b255561deb284 (diff) | |
download | upstream-62b7f5931c54e96fca56dd8761b0e466d355c881.tar.gz upstream-62b7f5931c54e96fca56dd8761b0e466d355c881.tar.bz2 upstream-62b7f5931c54e96fca56dd8761b0e466d355c881.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>
(cherry-picked from commit f07e572f64)
Diffstat (limited to 'target/linux/bcm27xx/patches-5.4/950-0768-w1_therm-adding-ext_power-sysfs-entry.patch')
-rw-r--r-- | target/linux/bcm27xx/patches-5.4/950-0768-w1_therm-adding-ext_power-sysfs-entry.patch | 293 |
1 files changed, 293 insertions, 0 deletions
diff --git a/target/linux/bcm27xx/patches-5.4/950-0768-w1_therm-adding-ext_power-sysfs-entry.patch b/target/linux/bcm27xx/patches-5.4/950-0768-w1_therm-adding-ext_power-sysfs-entry.patch new file mode 100644 index 0000000000..b2e8195b64 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0768-w1_therm-adding-ext_power-sysfs-entry.patch @@ -0,0 +1,293 @@ +From 5737e27d3c5e2f743421e68f926c05e8581ae21f Mon Sep 17 00:00:00 2001 +From: Akira Shimahara <akira215corp@gmail.com> +Date: Mon, 11 May 2020 22:36:50 +0200 +Subject: [PATCH] w1_therm: adding ext_power sysfs entry + +commit b7bb6ca17a90f47c2fe2848531b5bbaf27a65ba7 upstream. + +Adding ext_power sysfs entry (RO). Return the power status of the device: + - 0: device parasite powered + - 1: device externally powered + - xx: xx is kernel error + +The power status of each device is check when the device is +discover by the bus master, in 'w1_therm_add_slave(struct w1_slave *)'. +The status is stored in the device structure w1_therm_family_data so +that the driver always knows the power state of each device, which could +be used later to determine the required strong pull up to apply on the +line. + +The power status is re evaluate each time the sysfs ext_power read by +a user. + +The hardware function 'read_powermode(struct w1_slave *sl)' act just as +per device specifications, sending W1_READ_PSUPPLY command on the bus, +and issue a read time slot, reading only one bit. + +A helper function 'bool bus_mutex_lock(struct mutex *lock)' is introduced. +It try to aquire the bus mutex several times (W1_THERM_MAX_TRY), waiting +W1_THERM_RETRY_DELAY between two attempt. + +Updating Documentation/ABI/testing/sysfs-driver-w1_therm accordingly. + +Signed-off-by: Akira Shimahara <akira215corp@gmail.com> +Link: https://lore.kernel.org/r/20200511203650.410439-1-akira215corp@gmail.com +Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> +--- + .../ABI/testing/sysfs-driver-w1_therm | 29 ++++ + drivers/w1/slaves/w1_therm.c | 137 ++++++++++++++++++ + 2 files changed, 166 insertions(+) + create mode 100644 Documentation/ABI/testing/sysfs-driver-w1_therm + +--- /dev/null ++++ b/Documentation/ABI/testing/sysfs-driver-w1_therm +@@ -0,0 +1,29 @@ ++What: /sys/bus/w1/devices/.../ext_power ++Date: May 2020 ++Contact: Akira Shimahara <akira215corp@gmail.com> ++Description: ++ (RO) return the power status by asking the device ++ * '0': device parasite powered ++ * '1': device externally powered ++ * '-xx': xx is kernel error when reading power status ++Users: any user space application which wants to communicate with ++ w1_term device ++ ++ ++What: /sys/bus/w1/devices/.../w1_slave ++Date: May 2020 ++Contact: Akira Shimahara <akira215corp@gmail.com> ++Description: ++ (RW) return the temperature in 1/1000 degC. ++ *read*: return 2 lines with the hexa output data sent on the ++ bus, return the CRC check and temperature in 1/1000 degC ++ *write* : ++ * '0' : save the 2 or 3 bytes to the device EEPROM ++ (i.e. TH, TL and config register) ++ * '9..12' : set the device resolution in RAM ++ (if supported) ++ * Anything else: do nothing ++ refer to Documentation/w1/slaves/w1_therm.rst for detailed ++ information. ++Users: any user space application which wants to communicate with ++ w1_term device +\ No newline at end of file +--- a/drivers/w1/slaves/w1_therm.c ++++ b/drivers/w1/slaves/w1_therm.c +@@ -43,8 +43,21 @@ + static int w1_strong_pullup = 1; + module_param_named(strong_pullup, w1_strong_pullup, int, 0); + ++/* Nb of try for an operation */ ++#define W1_THERM_MAX_TRY 5 ++ ++/* ms delay to retry bus mutex */ ++#define W1_THERM_RETRY_DELAY 20 ++ + /* Helpers Macros */ + ++/* ++ * return the power mode of the sl slave : 1-ext, 0-parasite, <0 unknown ++ * always test family data existence before using this macro ++ */ ++#define SLAVE_POWERMODE(sl) \ ++ (((struct w1_therm_family_data *)(sl->family_data))->external_powered) ++ + /* return the address of the refcnt in the family data */ + #define THERM_REFCNT(family_data) \ + (&((struct w1_therm_family_data *)family_data)->refcnt) +@@ -73,10 +86,14 @@ struct w1_therm_family_converter { + * struct w1_therm_family_data - device data + * @rom: ROM device id (64bit Lasered ROM code + 1 CRC byte) + * @refcnt: ref count ++ * @external_powered: 1 device powered externally, ++ * 0 device parasite powered, ++ * -x error or undefined + */ + struct w1_therm_family_data { + uint8_t rom[9]; + atomic_t refcnt; ++ int external_powered; + }; + + /** +@@ -109,6 +126,20 @@ struct therm_info { + */ + static int reset_select_slave(struct w1_slave *sl); + ++/** ++ * read_powermode() - Query the power mode of the slave ++ * @sl: slave to retrieve the power mode ++ * ++ * Ask the device to get its power mode (external or parasite) ++ * and store the power status in the &struct w1_therm_family_data. ++ * ++ * Return: ++ * * 0 parasite powered device ++ * * 1 externally powered device ++ * * <0 kernel error code ++ */ ++static int read_powermode(struct w1_slave *sl); ++ + /* Sysfs interface declaration */ + + static ssize_t w1_slave_show(struct device *device, +@@ -120,10 +151,14 @@ static ssize_t w1_slave_store(struct dev + static ssize_t w1_seq_show(struct device *device, + struct device_attribute *attr, char *buf); + ++static ssize_t ext_power_show(struct device *device, ++ struct device_attribute *attr, char *buf); ++ + /* Attributes declarations */ + + static DEVICE_ATTR_RW(w1_slave); + static DEVICE_ATTR_RO(w1_seq); ++static DEVICE_ATTR_RO(ext_power); + + /* Interface Functions declaration */ + +@@ -151,12 +186,14 @@ static void w1_therm_remove_slave(struct + + static struct attribute *w1_therm_attrs[] = { + &dev_attr_w1_slave.attr, ++ &dev_attr_ext_power.attr, + NULL, + }; + + static struct attribute *w1_ds28ea00_attrs[] = { + &dev_attr_w1_slave.attr, + &dev_attr_w1_seq.attr, ++ &dev_attr_ext_power.attr, + NULL, + }; + +@@ -433,6 +470,34 @@ static struct w1_therm_family_converter + /* Helpers Functions */ + + /** ++ * bus_mutex_lock() - Acquire the mutex ++ * @lock: w1 bus mutex to acquire ++ * ++ * It try to acquire the mutex W1_THERM_MAX_TRY times and wait ++ * W1_THERM_RETRY_DELAY between 2 attempts. ++ * ++ * Return: true is mutex is acquired and lock, false otherwise ++ */ ++static inline bool bus_mutex_lock(struct mutex *lock) ++{ ++ int max_trying = W1_THERM_MAX_TRY; ++ ++ /* try to acquire the mutex, if not, sleep retry_delay before retry) */ ++ while (mutex_lock_interruptible(lock) != 0 && max_trying > 0) { ++ unsigned long sleep_rem; ++ ++ sleep_rem = msleep_interruptible(W1_THERM_RETRY_DELAY); ++ if (!sleep_rem) ++ max_trying--; ++ } ++ ++ if (!max_trying) ++ return false; /* Didn't acquire the bus mutex */ ++ ++ return true; ++} ++ ++/** + * w1_convert_temp() - temperature conversion binding function + * @rom: data read from device RAM (8 data bytes + 1 CRC byte) + * @fid: device family id +@@ -461,7 +526,19 @@ static int w1_therm_add_slave(struct w1_ + GFP_KERNEL); + if (!sl->family_data) + return -ENOMEM; ++ + atomic_set(THERM_REFCNT(sl->family_data), 1); ++ ++ /* 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)); ++ } ++ + return 0; + } + +@@ -661,6 +738,44 @@ error: + return ret; + } + ++static int 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); ++ /* ++ * Emit a read time slot and read only one bit, ++ * 1 is externally powered, ++ * 0 is parasite powered ++ */ ++ ret = w1_touch_bit(dev_master, 1); ++ /* ret should be either 1 either 0 */ ++ } ++ } ++ mutex_unlock(&dev_master->bus_mutex); ++ ++dec_refcnt: ++ atomic_dec(THERM_REFCNT(sl->family_data)); ++error: ++ return ret; ++} ++ + /* Sysfs Interface definition */ + + static ssize_t w1_slave_show(struct device *device, +@@ -722,6 +837,28 @@ static ssize_t w1_slave_store(struct dev + return ret ? : size; + } + ++static ssize_t ext_power_show(struct device *device, ++ struct device_attribute *attr, char *buf) ++{ ++ struct w1_slave *sl = dev_to_w1_slave(device); ++ ++ if (!sl->family_data) { ++ dev_info(device, ++ "%s: Device not supported by the driver\n", __func__); ++ return 0; /* No device family */ ++ } ++ ++ /* Getting the power mode of the device {external, parasite} */ ++ SLAVE_POWERMODE(sl) = read_powermode(sl); ++ ++ if (SLAVE_POWERMODE(sl) < 0) { ++ dev_dbg(device, ++ "%s: Power_mode may be corrupted. err=%d\n", ++ __func__, SLAVE_POWERMODE(sl)); ++ } ++ return sprintf(buf, "%d\n", SLAVE_POWERMODE(sl)); ++} ++ + #if IS_REACHABLE(CONFIG_HWMON) + static int w1_read_temp(struct device *device, u32 attr, int channel, + long *val) |