Export 1-wire thermal sensors as hwmon device
Subsystems (2)
v5 cover Export 1-wire thermal sensors as hwmon device
Hi Greg,
Please pull in this patchset into the tree. Thanks!
Summary of what this patchset does:
Our board has 4 DS18B20 1-wire temperature sensors. Each 1-wire bus and the sensor under it is already configured against the Linux 1-wire driver (called w1). They have a sysfs file(e.g. /sys/bus/w1/devices/w1_bus_master1/28-000007704f4c/w1_slave) which, when read, runs code to read the temperature. We'd like the temperatures to show up in hwmon, so that the BMC IPMI sensor plumbing can forward those to host.
This patchset is based on linux mainline version v4.10.
Tested:
Yes; On a board with 4 DS18B20 1-wire temperature sensors:
root@zaius:/sys/class/hwmon# ls hwmon0 hwmon1 hwmon2 hwmon3 hwmon4 hwmon5 root@zaius:/sys/class/hwmon# cd hwmon0 root@zaius:/sys/class/hwmon/hwmon0# ls device name subsystem temp1_input uevent root@zaius:/sys/class/hwmon/hwmon0# cat temp1_input 24500 root@zaius:/sys/class/hwmon/hwmon0# cd .. root@zaius:/sys/class/hwmon# cd hwmon1 root@zaius:/sys/class/hwmon/hwmon1# cat temp1_input 26562 root@zaius:/sys/class/hwmon/hwmon1# cd .. root@zaius:/sys/class/hwmon# cd hwmon2 root@zaius:/sys/class/hwmon/hwmon2# cat temp1_input 27250 root@zaius:/sys/class/hwmon/hwmon2# cd .. root@zaius:/sys/class/hwmon# cd hwmon3 root@zaius:/sys/class/hwmon/hwmon3# cat temp1_input 22250 root@zaius:/sys/class/hwmon/hwmon3#
Jaghathiswari Rankappagounder Natarajan (3):
drivers: w1: add hwmon support structures
drivers: w1: refactor w1_slave_show to make the temp reading
functionality separate
drivers: w1: add hwmon temp support for w1_therm
drivers/w1/slaves/w1_therm.c | 164 +++++++++++++++++++++++++++++++++++-------- drivers/w1/w1.c | 18 ++++- drivers/w1/w1.h | 2 + drivers/w1/w1_family.h | 2 + 4 files changed, 156 insertions(+), 30 deletions(-)
--
2.13.2.932.g7449e964c-goog
PATCH v5 1/3 drivers: w1: add hwmon support structures
This patch has changes to w1.h/w1.c/w1_family.h generic files to add (optional) hwmon support structures.
---
v2
- made changes to support hwmon_device_register_with_info mentioned by Guenter.
v3
- used IS_REACHABLE(CONFIG_HWMON).
- removed hwmon device first before removing slave.
v4
- moved && to be in the previous line.
drivers/w1/w1.c | 18 +++++++++++++++++- drivers/w1/w1.h | 2 ++ drivers/w1/w1_family.h | 2 ++ 3 files changed, 21 insertions(+), 1 deletion(-)
drivers/w1/w1.c +17 -1
@@ -32,6 +32,7 @@#include <linux/sched.h> #include <linux/kthread.h> #include <linux/freezer.h> +#include <linux/hwmon.h> #include <linux/atomic.h>
@@ -659,9 +660,24 @@ static int w1_family_notify(unsigned long action, struct w1_slave *sl)return err; } } - +if (IS_REACHABLE (CONFIG_HWMON ) && fops->chip_info) { +struct device *hwmon + =hwmon_device_register_with_info (&sl->dev, +"w1_slave_temp" , sl, + fops->chip_info, +NULL ); +if (IS_ERR (hwmon)) { +dev_warn (&sl->dev, +"could not create hwmon device\n" ); + }else { + sl->hwmon = hwmon; + } + }break ;case BUS_NOTIFY_DEL_DEVICE : +if (IS_REACHABLE (CONFIG_HWMON ) && fops->chip_info && + sl->hwmon) +hwmon_device_unregister (sl->hwmon);if (fops->remove_slave) sl->family->fops->remove_slave (sl);if (fops->groups)
drivers/w1/w1.h +2 -0
@@ -83,6 +83,7 @@ struct w1_reg_num* @family: module for device family type * @family_data: pointer for use by the family module * @dev: kernel device identifier +* @hwmon: pointer to hwmon device * */ struct w1_slave
@@ -99,6 +100,7 @@ struct w1_slavestruct w1_family *family;void *family_data;struct device dev; +struct device *hwmon; };typedef void (*w1_slave_found_callback )(struct w1_master *,u64 );
drivers/w1/w1_family.h +2 -0
@@ -55,12 +55,14 @@ struct w1_slave;* @add_slave: add_slave * @remove_slave: remove_slave * @groups: sysfs group +* @chip_info: pointer to struct hwmon_chip_info */ struct w1_family_ops {int (* add_slave)(struct w1_slave *);void (* remove_slave)(struct w1_slave *);const struct attribute_group **groups; +const struct hwmon_chip_info *chip_info; };/**
--
2.13.2.932.g7449e964c-goog
Re: [PATCH linux v5 1/3] drivers: w1: add hwmon support structures
Quoted 6 lines · Jaghathiswari Rankappagounder Natarajan
This patch has changes to
w1.h/w1.c/w1_family.hgeneric files to add (optional) hwmon support structures.Acked-by Evgeniy Polyakov <[email protected]>Acked-by Guenter Roeck <[email protected]>
This patch series doesn't apply against my char-misc git tree at all (use the char-misc-next branch). Can you please rebase it and resend?
thanks,
greg k-h
PATCH v5 2/3 drivers: w1: refactor w1_slave_show to make the temp reading functionality separate
In reply to Jaghathiswari Rankappagounder NatarajanInside the w1_slave_show function refactor the code to read the temp into a separate function.
---
v2
- made changes to support hwmon_device_register_with_info mentioned by Guenter.
v3
- used IS_REACHABLE(CONFIG_HWMON).
- removed hwmon device first before removing slave.
v4
- moved && to be in the previous line.
drivers/w1/slaves/w1_therm.c | 82 +++++++++++++++++++++++++++----------------- 1 file changed, 51 insertions(+), 31 deletions(-)
drivers/w1/slaves/w1_therm.c +51 -31
@@ -64,6 +64,12 @@ struct w1_therm_family_data {atomic_t refcnt; }; +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)
@@ -427,33 +433,31 @@ static ssize_t w1_slave_store(struct device *device,return ret ? : size; } -static ssize_t w1_slave_show (struct device *device, -struct device_attribute *attr,char *buf) +static ssize_t read_therm (struct device *device, +struct w1_slave *sl,struct therm_info *info) { -struct w1_slave *sl =dev_to_w1_slave (device);struct w1_master *dev = sl->master; -u8 rom[9 ], crc, verdict, external_power; -int i, ret, max_trying =10 ; -ssize_t c =PAGE_SIZE ; +u8 external_power; +int ret, max_trying =10 ;u8 *family_data = sl->family_data; ret =mutex_lock_interruptible (&dev->bus_mutex);if (ret !=0 ) - goto post_unlock; + goto error; -if (!sl->family_data) { +if (!family_data) { ret = -ENODEV ; - goto pre_unlock; + goto mt_unlock; }/* prevent the slave from going away in sleep */ atomic_inc (THERM_REFCNT (family_data)); -memset (rom,0 ,sizeof (rom)); +memset (info->rom,0 ,sizeof (info->rom));while (max_trying--) { - verdict =0 ; - crc =0 ; + info->verdict =0 ; + info->crc =0 ;if (!w1_reset_select_slave (sl)) {int count =0 ;
@@ -479,47 +483,69 @@ static ssize_t w1_slave_show(struct device *device, sleep_rem =msleep_interruptible (tm);if (sleep_rem !=0 ) { ret = -EINTR ; - goto post_unlock; + goto dec_refcnt; } ret =mutex_lock_interruptible (&dev->bus_mutex);if (ret !=0 ) - goto post_unlock; + goto dec_refcnt; }else if (!w1_strong_pullup) { sleep_rem =msleep_interruptible (tm);if (sleep_rem !=0 ) { ret = -EINTR ; - goto pre_unlock; + goto dec_refcnt; } }if (!w1_reset_select_slave (sl)) {w1_write_8 (dev,W1_READ_SCRATCHPAD ); - count =w1_read_block (dev, rom,9 ); + count =w1_read_block (dev, info->rom,9 );if (count !=9 ) {dev_warn (device,"w1_read_block() " "returned %u instead of 9.\n" , count); } - crc =w1_calc_crc8 (rom,8 ); + info->crc =w1_calc_crc8 (info->rom,8 ); -if (rom[8 ] == crc) - verdict =1 ; +if (info->rom[8 ] == info->crc) + info->verdict =1 ; } } -if (verdict) +if (info->verdict)break ; } +dec_refcnt: +atomic_dec (THERM_REFCNT (family_data)); +mt_unlock: +mutex_unlock (&dev->bus_mutex); +error: +return ret; +} + +static ssize_t w1_slave_show (struct device *device, +struct device_attribute *attr,char *buf) +{ +struct w1_slave *sl =dev_to_w1_slave (device); +struct therm_info info; +u8 *family_data = sl->family_data; +int ret, i; +ssize_t c =PAGE_SIZE ; +u8 fid = sl->family->fid; + + ret =read_therm (device, sl, &info); +if (ret) +return ret; +for (i =0 ; i <9 ; ++i) - c -=snprintf (buf +PAGE_SIZE - c, c,"%02x " , rom[i]); + c -=snprintf (buf +PAGE_SIZE - c, c,"%02x " , info.rom[i]); c -=snprintf (buf +PAGE_SIZE - c, c,": crc=%02x %s\n" , - crc, (verdict) ?"YES" :"NO" ); -if (verdict) -memcpy (family_data, rom,sizeof (rom)); + info.crc, (info.verdict) ?"YES" :"NO" ); +if (info.verdict) +memcpy (family_data, info.rom,sizeof (info.rom));else dev_warn (device,"Read failed CRC check\n" );
@@ -528,14 +554,8 @@ static ssize_t w1_slave_show(struct device *device, ((u8 *)family_data)[i]); c -=snprintf (buf +PAGE_SIZE - c, c,"t=%d\n" , -w1_convert_temp (rom, sl->family->fid)); +w1_convert_temp (info.rom, fid)); ret =PAGE_SIZE - c; - -pre_unlock: -mutex_unlock (&dev->bus_mutex); - -post_unlock: -atomic_dec (THERM_REFCNT (family_data));return ret; }
--
2.13.2.932.g7449e964c-goog
PATCH v5 3/3 drivers: w1: add hwmon temp support for w1_therm
In reply to Jaghathiswari Rankappagounder NatarajanThis change adds hwmon temp support for w1_therm.
---
v2
- make changes to support hwmon_device_register_with_info mentioned by Guenter.
v3
- used IS_REACHABLE()
- rearranged the code to not require forward declarations
- used family_data
- incremented the reference count with the bus mutex locked
- corrected indentation
- removed dev_warn message
- simplified returning mode
- removed write function
v4
- used W1_CHIP_INFO
- corrected formatting
drivers/w1/slaves/w1_therm.c | 86 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 86 insertions(+)
drivers/w1/slaves/w1_therm.c +86 -0
@@ -29,6 +29,7 @@#include <linux/types.h> #include <linux/slab.h> #include <linux/delay.h> +#include <linux/hwmon.h> #include "../w1.h" #include "../w1_int.h"
@@ -118,19 +119,72 @@ static struct attribute *w1_ds28ea00_attrs[] = { &dev_attr_w1_seq.attr,NULL , }; +ATTRIBUTE_GROUPS (w1_therm);ATTRIBUTE_GROUPS (w1_ds28ea00); +#if IS_REACHABLE (CONFIG_HWMON ) +static int w1_read_temp (struct device *dev,u32 attr,int channel, +long *val); + +static umode_t w1_is_visible (const void *_data,enum hwmon_sensor_types type, +u32 attr,int channel) +{ +return attr == hwmon_temp_input ?0444 :0 ; +} + +static int w1_read (struct device *dev,enum hwmon_sensor_types type, +u32 attr,int channel,long *val) +{ +switch (type) { +case hwmon_temp: +return w1_read_temp (dev, attr, channel, val); +default : +return -EOPNOTSUPP ; + } +} + +static const u32 w1_temp_config[] = { +HWMON_T_INPUT , +0 +}; + +static const struct hwmon_channel_info w1_temp = { + .type = hwmon_temp, + .config = w1_temp_config, +}; + +static const struct hwmon_channel_info *w1_info[] = { + &w1_temp, +NULL +}; + +static const struct hwmon_ops w1_hwmon_ops = { + .is_visible = w1_is_visible, + .read = w1_read, +}; + +static const struct hwmon_chip_info w1_chip_info = { + .ops = &w1_hwmon_ops, + .info = w1_info, +}; +#define W1_CHIPINFO (&w1_chip_info) +#else +#define W1_CHIPINFO NULL +#endif +static struct w1_family_ops w1_therm_fops = { .add_slave = w1_therm_add_slave, .remove_slave = w1_therm_remove_slave, .groups = w1_therm_groups, + .chip_info =W1_CHIPINFO , };static struct w1_family_ops w1_ds28ea00_fops = { .add_slave = w1_therm_add_slave, .remove_slave = w1_therm_remove_slave, .groups = w1_ds28ea00_groups, + .chip_info =W1_CHIPINFO , }; static struct w1_family w1_therm_family_DS18S20 = {
@@ -559,6 +613,38 @@ static ssize_t w1_slave_show(struct device *device,return ret; } +#if IS_REACHABLE (CONFIG_HWMON ) +static int w1_read_temp (struct device *device,u32 attr,int channel, +long *val) +{ +struct w1_slave *sl =dev_get_drvdata (device); +struct therm_info info; +u8 fid = sl->family->fid; +int ret; + +switch (attr) { +case hwmon_temp_input: + ret =read_therm (device, sl, &info); +if (ret) +return ret; + +if (!info.verdict) { + ret = -EIO ; +return ret; + } + + *val =w1_convert_temp (info.rom, fid); + ret =0 ; +break ; +default : + ret = -EOPNOTSUPP ; +break ; + } + +return ret; +} +#endif +#define W1_42_CHAIN 0x99#define W1_42_CHAIN_OFF 0x3C#define W1_42_CHAIN_OFF_INV 0xC3
--
2.13.2.932.g7449e964c-goog
Hi
18.07.2017, 02:09, "Jaghathiswari Rankappagounder Natarajan" <[email protected]>:
Quoted 2 lines
Hi Greg,
Please pull in this patchset into the tree. Thanks!
Here is a patchset, is it visible in your mailbox? If so, please pull it into your tree.
Quoted 48 lines
Summary of what this patchset does:
Our board has 4 DS18B20 1-wire temperature sensors. Each 1-wire bus and the sensor under it is already configured against the Linux 1-wire driver (called w1). They have a sysfs file(e.g.
/sys/bus/w1/devices/w1_bus_master1/28-000007704f4c/w1_slave) which, when read, runs code to read the temperature. We'd like the temperatures to show up in hwmon, so that the BMC IPMI sensor plumbing can forward those to host.This patchset is based on linux mainline version v4.10.
Tested:
Yes; On a board with 4 DS18B20 1-wire temperature sensors:root@zaius:/sys/class/hwmon# ls hwmon0 hwmon1 hwmon2 hwmon3 hwmon4 hwmon5 root@zaius:/sys/class/hwmon# cd hwmon0 root@zaius:/sys/class/hwmon/hwmon0# ls device name subsystem temp1_input uevent root@zaius:/sys/class/hwmon/hwmon0# cat temp1_input 24500 root@zaius:/sys/class/hwmon/hwmon0# cd .. root@zaius:/sys/class/hwmon# cd hwmon1 root@zaius:/sys/class/hwmon/hwmon1# cat temp1_input 26562 root@zaius:/sys/class/hwmon/hwmon1# cd .. root@zaius:/sys/class/hwmon# cd hwmon2 root@zaius:/sys/class/hwmon/hwmon2# cat temp1_input 27250 root@zaius:/sys/class/hwmon/hwmon2# cd .. root@zaius:/sys/class/hwmon# cd hwmon3 root@zaius:/sys/class/hwmon/hwmon3# cat temp1_input 22250 root@zaius:/sys/class/hwmon/hwmon3#Jaghathiswari Rankappagounder Natarajan (3):
drivers: w1: add hwmon support structures
drivers: w1: refactorw1_slave_showto make the temp reading functionality separate
drivers: w1: add hwmon temp support forw1_thermdrivers/w1/slaves/w1_therm.c | 164 +++++++++++++++++++++++++++++++++++--------
drivers/w1/w1.c| 18 ++++-
drivers/w1/w1.h | 2 +
drivers/w1/w1_family.h | 2 +4 files changed, 156 insertions(+), 30 deletions(-)--
2.13.2.932.g7449e964c-goog