Commit 92b8d272 authored by Akira Shimahara's avatar Akira Shimahara Committed by Greg Kroah-Hartman

w1_therm: adding code comments and code reordering

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: default avatarAkira Shimahara <akira215corp@gmail.com>
Link: https://lore.kernel.org/r/20200511203535.409599-1-akira215corp@gmail.comSigned-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 691e0f2c
...@@ -25,7 +25,8 @@ ...@@ -25,7 +25,8 @@
#define W1_THERM_DS1825 0x3B #define W1_THERM_DS1825 0x3B
#define W1_THERM_DS28EA00 0x42 #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 * 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 * current to do a temperature conversion. If it is enabled parasite powered
* devices have a better chance of getting the current required. * devices have a better chance of getting the current required.
...@@ -41,42 +42,55 @@ ...@@ -41,42 +42,55 @@
static int w1_strong_pullup = 1; static int w1_strong_pullup = 1;
module_param_named(strong_pullup, w1_strong_pullup, int, 0); 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 { struct w1_therm_family_data {
uint8_t rom[9]; uint8_t rom[9];
atomic_t refcnt; 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 { struct therm_info {
u8 rom[9]; u8 rom[9];
u8 crc; u8 crc;
u8 verdict; u8 verdict;
}; };
/* return the address of the refcnt in the family data */ /* Sysfs interface declaration */
#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;
}
static ssize_t w1_slave_show(struct device *device, static ssize_t w1_slave_show(struct device *device,
struct device_attribute *attr, char *buf); struct device_attribute *attr, char *buf);
...@@ -87,9 +101,35 @@ static ssize_t w1_slave_store(struct device *device, ...@@ -87,9 +101,35 @@ static ssize_t w1_slave_store(struct device *device,
static ssize_t w1_seq_show(struct device *device, static ssize_t w1_seq_show(struct device *device,
struct device_attribute *attr, char *buf); struct device_attribute *attr, char *buf);
/* Attributes declarations */
static DEVICE_ATTR_RW(w1_slave); static DEVICE_ATTR_RW(w1_slave);
static DEVICE_ATTR_RO(w1_seq); 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[] = { static struct attribute *w1_therm_attrs[] = {
&dev_attr_w1_slave.attr, &dev_attr_w1_slave.attr,
NULL, NULL,
...@@ -101,6 +141,8 @@ static struct attribute *w1_ds28ea00_attrs[] = { ...@@ -101,6 +141,8 @@ static struct attribute *w1_ds28ea00_attrs[] = {
NULL, NULL,
}; };
/* Attribute groups */
ATTRIBUTE_GROUPS(w1_therm); ATTRIBUTE_GROUPS(w1_therm);
ATTRIBUTE_GROUPS(w1_ds28ea00); ATTRIBUTE_GROUPS(w1_ds28ea00);
...@@ -154,6 +196,8 @@ static const struct hwmon_chip_info w1_chip_info = { ...@@ -154,6 +196,8 @@ static const struct hwmon_chip_info w1_chip_info = {
#define W1_CHIPINFO NULL #define W1_CHIPINFO NULL
#endif #endif
/* Family operations */
static struct w1_family_ops w1_therm_fops = { static struct w1_family_ops w1_therm_fops = {
.add_slave = w1_therm_add_slave, .add_slave = w1_therm_add_slave,
.remove_slave = w1_therm_remove_slave, .remove_slave = w1_therm_remove_slave,
...@@ -168,6 +212,8 @@ static struct w1_family_ops w1_ds28ea00_fops = { ...@@ -168,6 +212,8 @@ static struct w1_family_ops w1_ds28ea00_fops = {
.chip_info = W1_CHIPINFO, .chip_info = W1_CHIPINFO,
}; };
/* Family binding operations struct */
static struct w1_family w1_therm_family_DS18S20 = { static struct w1_family w1_therm_family_DS18S20 = {
.fid = W1_THERM_DS18S20, .fid = W1_THERM_DS18S20,
.fops = &w1_therm_fops, .fops = &w1_therm_fops,
...@@ -193,138 +239,18 @@ static struct w1_family w1_therm_family_DS1825 = { ...@@ -193,138 +239,18 @@ static struct w1_family w1_therm_family_DS1825 = {
.fops = &w1_therm_fops, .fops = &w1_therm_fops,
}; };
struct w1_therm_family_converter { /* Device dependent func */
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);
};
/* write configuration to eeprom */ /* write configuration to eeprom */
static inline int w1_therm_eeprom(struct device *device); 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 */ /* DS18S20 does not feature configuration register */
static inline int w1_DS18S20_precision(struct device *device, int val) static inline int w1_DS18S20_precision(struct device *device, int val)
{ {
return 0; return 0;
} }
/* Set precision for conversion */
static inline int w1_DS18B20_precision(struct device *device, int val) static inline int w1_DS18B20_precision(struct device *device, int val)
{ {
struct w1_slave *sl = dev_to_w1_slave(device); struct w1_slave *sl = dev_to_w1_slave(device);
...@@ -407,6 +333,14 @@ static inline int w1_DS18B20_precision(struct device *device, int val) ...@@ -407,6 +333,14 @@ static inline int w1_DS18B20_precision(struct device *device, int val)
return ret; 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]) static inline int w1_DS18B20_convert_temp(u8 rom[9])
{ {
s16 t = le16_to_cpup((__le16 *)rom); s16 t = le16_to_cpup((__le16 *)rom);
...@@ -414,6 +348,14 @@ static inline int w1_DS18B20_convert_temp(u8 rom[9]) ...@@ -414,6 +348,14 @@ static inline int w1_DS18B20_convert_temp(u8 rom[9])
return t*1000/16; 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]) static inline int w1_DS18S20_convert_temp(u8 rom[9])
{ {
int t, h; int t, h;
...@@ -434,6 +376,53 @@ static inline int w1_DS18S20_convert_temp(u8 rom[9]) ...@@ -434,6 +376,53 @@ static inline int w1_DS18S20_convert_temp(u8 rom[9])
return t; 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) static inline int w1_convert_temp(u8 rom[9], u8 fid)
{ {
int i; int i;
...@@ -445,31 +434,32 @@ static inline int w1_convert_temp(u8 rom[9], u8 fid) ...@@ -445,31 +434,32 @@ static inline int w1_convert_temp(u8 rom[9], u8 fid)
return 0; return 0;
} }
static ssize_t w1_slave_store(struct device *device, /* Interface Functions */
struct device_attribute *attr, const char *buf,
size_t size) static int w1_therm_add_slave(struct w1_slave *sl)
{ {
int val, ret; sl->family_data = kzalloc(sizeof(struct w1_therm_family_data),
struct w1_slave *sl = dev_to_w1_slave(device); GFP_KERNEL);
int i; if (!sl->family_data)
return -ENOMEM;
atomic_set(THERM_REFCNT(sl->family_data), 1);
return 0;
}
ret = kstrtoint(buf, 0, &val); static void w1_therm_remove_slave(struct w1_slave *sl)
if (ret) {
return ret; int refcnt = atomic_sub_return(1, THERM_REFCNT(sl->family_data));
for (i = 0; i < ARRAY_SIZE(w1_therm_families); ++i) { while (refcnt) {
if (w1_therm_families[i].f->fid == sl->family->fid) { msleep(1000);
/* zero value indicates to write current configuration to eeprom */ refcnt = atomic_read(THERM_REFCNT(sl->family_data));
if (val == 0)
ret = w1_therm_families[i].eeprom(device);
else
ret = w1_therm_families[i].precision(device, val);
break;
}
} }
return ret ? : size; kfree(sl->family_data);
sl->family_data = NULL;
} }
/* Hardware Functions */
static ssize_t read_therm(struct device *device, static ssize_t read_therm(struct device *device,
struct w1_slave *sl, struct therm_info *info) struct w1_slave *sl, struct therm_info *info)
{ {
...@@ -564,6 +554,81 @@ static ssize_t read_therm(struct device *device, ...@@ -564,6 +554,81 @@ static ssize_t read_therm(struct device *device,
return ret; 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, static ssize_t w1_slave_show(struct device *device,
struct device_attribute *attr, char *buf) struct device_attribute *attr, char *buf)
{ {
...@@ -597,6 +662,32 @@ static ssize_t w1_slave_show(struct device *device, ...@@ -597,6 +662,32 @@ static ssize_t w1_slave_show(struct device *device,
return ret; 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) #if IS_REACHABLE(CONFIG_HWMON)
static int w1_read_temp(struct device *device, u32 attr, int channel, static int w1_read_temp(struct device *device, u32 attr, int channel,
long *val) long *val)
...@@ -666,7 +757,7 @@ static ssize_t w1_seq_show(struct device *device, ...@@ -666,7 +757,7 @@ static ssize_t w1_seq_show(struct device *device,
if (ack != W1_42_SUCCESS_CONFIRM_BYTE) if (ack != W1_42_SUCCESS_CONFIRM_BYTE)
goto error; 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++) { for (i = 0; i <= 64; i++) {
if (w1_reset_bus(sl->master)) if (w1_reset_bus(sl->master))
goto error; goto error;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment