Commit 1b4e677f authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'hwmon-for-v5.5-rc8' of...

Merge tag 'hwmon-for-v5.5-rc8' of git://git.kernel.org/pub/scm/linux/kernel/git/groeck/linux-staging

Pull hwmon fixes from Guenter Roeck:

 - In hwmon core, do not use the hwmon parent device for device managed
   memory allocations, since parent device lifetime may not match hwmon
   device lifetime.

 - Fix discrepancy between read and write values in adt7475 driver.

 - Fix alarms and voltage limits in nct7802 driver.

* tag 'hwmon-for-v5.5-rc8' of git://git.kernel.org/pub/scm/linux/kernel/git/groeck/linux-staging:
  hwmon: (core) Do not use device managed functions for memory allocations
  hwmon: (adt7475) Make volt2reg return same reg as reg2volt input
  hwmon: (nct7802) Fix non-working alarm on voltages
  hwmon: (nct7802) Fix voltage limits to wrong registers
parents dbab40bd 3bf8bdcf
...@@ -294,9 +294,10 @@ static inline u16 volt2reg(int channel, long volt, u8 bypass_attn) ...@@ -294,9 +294,10 @@ static inline u16 volt2reg(int channel, long volt, u8 bypass_attn)
long reg; long reg;
if (bypass_attn & (1 << channel)) if (bypass_attn & (1 << channel))
reg = (volt * 1024) / 2250; reg = DIV_ROUND_CLOSEST(volt * 1024, 2250);
else else
reg = (volt * r[1] * 1024) / ((r[0] + r[1]) * 2250); reg = DIV_ROUND_CLOSEST(volt * r[1] * 1024,
(r[0] + r[1]) * 2250);
return clamp_val(reg, 0, 1023) & (0xff << 2); return clamp_val(reg, 0, 1023) & (0xff << 2);
} }
......
...@@ -51,6 +51,7 @@ struct hwmon_device_attribute { ...@@ -51,6 +51,7 @@ struct hwmon_device_attribute {
#define to_hwmon_attr(d) \ #define to_hwmon_attr(d) \
container_of(d, struct hwmon_device_attribute, dev_attr) container_of(d, struct hwmon_device_attribute, dev_attr)
#define to_dev_attr(a) container_of(a, struct device_attribute, attr)
/* /*
* Thermal zone information * Thermal zone information
...@@ -58,7 +59,7 @@ struct hwmon_device_attribute { ...@@ -58,7 +59,7 @@ struct hwmon_device_attribute {
* also provides the sensor index. * also provides the sensor index.
*/ */
struct hwmon_thermal_data { struct hwmon_thermal_data {
struct hwmon_device *hwdev; /* Reference to hwmon device */ struct device *dev; /* Reference to hwmon device */
int index; /* sensor index */ int index; /* sensor index */
}; };
...@@ -95,9 +96,27 @@ static const struct attribute_group *hwmon_dev_attr_groups[] = { ...@@ -95,9 +96,27 @@ static const struct attribute_group *hwmon_dev_attr_groups[] = {
NULL NULL
}; };
static void hwmon_free_attrs(struct attribute **attrs)
{
int i;
for (i = 0; attrs[i]; i++) {
struct device_attribute *dattr = to_dev_attr(attrs[i]);
struct hwmon_device_attribute *hattr = to_hwmon_attr(dattr);
kfree(hattr);
}
kfree(attrs);
}
static void hwmon_dev_release(struct device *dev) static void hwmon_dev_release(struct device *dev)
{ {
kfree(to_hwmon_device(dev)); struct hwmon_device *hwdev = to_hwmon_device(dev);
if (hwdev->group.attrs)
hwmon_free_attrs(hwdev->group.attrs);
kfree(hwdev->groups);
kfree(hwdev);
} }
static struct class hwmon_class = { static struct class hwmon_class = {
...@@ -119,11 +138,11 @@ static DEFINE_IDA(hwmon_ida); ...@@ -119,11 +138,11 @@ static DEFINE_IDA(hwmon_ida);
static int hwmon_thermal_get_temp(void *data, int *temp) static int hwmon_thermal_get_temp(void *data, int *temp)
{ {
struct hwmon_thermal_data *tdata = data; struct hwmon_thermal_data *tdata = data;
struct hwmon_device *hwdev = tdata->hwdev; struct hwmon_device *hwdev = to_hwmon_device(tdata->dev);
int ret; int ret;
long t; long t;
ret = hwdev->chip->ops->read(&hwdev->dev, hwmon_temp, hwmon_temp_input, ret = hwdev->chip->ops->read(tdata->dev, hwmon_temp, hwmon_temp_input,
tdata->index, &t); tdata->index, &t);
if (ret < 0) if (ret < 0)
return ret; return ret;
...@@ -137,8 +156,7 @@ static const struct thermal_zone_of_device_ops hwmon_thermal_ops = { ...@@ -137,8 +156,7 @@ static const struct thermal_zone_of_device_ops hwmon_thermal_ops = {
.get_temp = hwmon_thermal_get_temp, .get_temp = hwmon_thermal_get_temp,
}; };
static int hwmon_thermal_add_sensor(struct device *dev, static int hwmon_thermal_add_sensor(struct device *dev, int index)
struct hwmon_device *hwdev, int index)
{ {
struct hwmon_thermal_data *tdata; struct hwmon_thermal_data *tdata;
struct thermal_zone_device *tzd; struct thermal_zone_device *tzd;
...@@ -147,10 +165,10 @@ static int hwmon_thermal_add_sensor(struct device *dev, ...@@ -147,10 +165,10 @@ static int hwmon_thermal_add_sensor(struct device *dev,
if (!tdata) if (!tdata)
return -ENOMEM; return -ENOMEM;
tdata->hwdev = hwdev; tdata->dev = dev;
tdata->index = index; tdata->index = index;
tzd = devm_thermal_zone_of_sensor_register(&hwdev->dev, index, tdata, tzd = devm_thermal_zone_of_sensor_register(dev, index, tdata,
&hwmon_thermal_ops); &hwmon_thermal_ops);
/* /*
* If CONFIG_THERMAL_OF is disabled, this returns -ENODEV, * If CONFIG_THERMAL_OF is disabled, this returns -ENODEV,
...@@ -162,8 +180,7 @@ static int hwmon_thermal_add_sensor(struct device *dev, ...@@ -162,8 +180,7 @@ static int hwmon_thermal_add_sensor(struct device *dev,
return 0; return 0;
} }
#else #else
static int hwmon_thermal_add_sensor(struct device *dev, static int hwmon_thermal_add_sensor(struct device *dev, int index)
struct hwmon_device *hwdev, int index)
{ {
return 0; return 0;
} }
...@@ -250,8 +267,7 @@ static bool is_string_attr(enum hwmon_sensor_types type, u32 attr) ...@@ -250,8 +267,7 @@ static bool is_string_attr(enum hwmon_sensor_types type, u32 attr)
(type == hwmon_fan && attr == hwmon_fan_label); (type == hwmon_fan && attr == hwmon_fan_label);
} }
static struct attribute *hwmon_genattr(struct device *dev, static struct attribute *hwmon_genattr(const void *drvdata,
const void *drvdata,
enum hwmon_sensor_types type, enum hwmon_sensor_types type,
u32 attr, u32 attr,
int index, int index,
...@@ -279,7 +295,7 @@ static struct attribute *hwmon_genattr(struct device *dev, ...@@ -279,7 +295,7 @@ static struct attribute *hwmon_genattr(struct device *dev,
if ((mode & 0222) && !ops->write) if ((mode & 0222) && !ops->write)
return ERR_PTR(-EINVAL); return ERR_PTR(-EINVAL);
hattr = devm_kzalloc(dev, sizeof(*hattr), GFP_KERNEL); hattr = kzalloc(sizeof(*hattr), GFP_KERNEL);
if (!hattr) if (!hattr)
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
...@@ -492,8 +508,7 @@ static int hwmon_num_channel_attrs(const struct hwmon_channel_info *info) ...@@ -492,8 +508,7 @@ static int hwmon_num_channel_attrs(const struct hwmon_channel_info *info)
return n; return n;
} }
static int hwmon_genattrs(struct device *dev, static int hwmon_genattrs(const void *drvdata,
const void *drvdata,
struct attribute **attrs, struct attribute **attrs,
const struct hwmon_ops *ops, const struct hwmon_ops *ops,
const struct hwmon_channel_info *info) const struct hwmon_channel_info *info)
...@@ -519,7 +534,7 @@ static int hwmon_genattrs(struct device *dev, ...@@ -519,7 +534,7 @@ static int hwmon_genattrs(struct device *dev,
attr_mask &= ~BIT(attr); attr_mask &= ~BIT(attr);
if (attr >= template_size) if (attr >= template_size)
return -EINVAL; return -EINVAL;
a = hwmon_genattr(dev, drvdata, info->type, attr, i, a = hwmon_genattr(drvdata, info->type, attr, i,
templates[attr], ops); templates[attr], ops);
if (IS_ERR(a)) { if (IS_ERR(a)) {
if (PTR_ERR(a) != -ENOENT) if (PTR_ERR(a) != -ENOENT)
...@@ -533,8 +548,7 @@ static int hwmon_genattrs(struct device *dev, ...@@ -533,8 +548,7 @@ static int hwmon_genattrs(struct device *dev,
} }
static struct attribute ** static struct attribute **
__hwmon_create_attrs(struct device *dev, const void *drvdata, __hwmon_create_attrs(const void *drvdata, const struct hwmon_chip_info *chip)
const struct hwmon_chip_info *chip)
{ {
int ret, i, aindex = 0, nattrs = 0; int ret, i, aindex = 0, nattrs = 0;
struct attribute **attrs; struct attribute **attrs;
...@@ -545,15 +559,17 @@ __hwmon_create_attrs(struct device *dev, const void *drvdata, ...@@ -545,15 +559,17 @@ __hwmon_create_attrs(struct device *dev, const void *drvdata,
if (nattrs == 0) if (nattrs == 0)
return ERR_PTR(-EINVAL); return ERR_PTR(-EINVAL);
attrs = devm_kcalloc(dev, nattrs + 1, sizeof(*attrs), GFP_KERNEL); attrs = kcalloc(nattrs + 1, sizeof(*attrs), GFP_KERNEL);
if (!attrs) if (!attrs)
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
for (i = 0; chip->info[i]; i++) { for (i = 0; chip->info[i]; i++) {
ret = hwmon_genattrs(dev, drvdata, &attrs[aindex], chip->ops, ret = hwmon_genattrs(drvdata, &attrs[aindex], chip->ops,
chip->info[i]); chip->info[i]);
if (ret < 0) if (ret < 0) {
hwmon_free_attrs(attrs);
return ERR_PTR(ret); return ERR_PTR(ret);
}
aindex += ret; aindex += ret;
} }
...@@ -595,14 +611,13 @@ __hwmon_device_register(struct device *dev, const char *name, void *drvdata, ...@@ -595,14 +611,13 @@ __hwmon_device_register(struct device *dev, const char *name, void *drvdata,
for (i = 0; groups[i]; i++) for (i = 0; groups[i]; i++)
ngroups++; ngroups++;
hwdev->groups = devm_kcalloc(dev, ngroups, sizeof(*groups), hwdev->groups = kcalloc(ngroups, sizeof(*groups), GFP_KERNEL);
GFP_KERNEL);
if (!hwdev->groups) { if (!hwdev->groups) {
err = -ENOMEM; err = -ENOMEM;
goto free_hwmon; goto free_hwmon;
} }
attrs = __hwmon_create_attrs(dev, drvdata, chip); attrs = __hwmon_create_attrs(drvdata, chip);
if (IS_ERR(attrs)) { if (IS_ERR(attrs)) {
err = PTR_ERR(attrs); err = PTR_ERR(attrs);
goto free_hwmon; goto free_hwmon;
...@@ -647,8 +662,7 @@ __hwmon_device_register(struct device *dev, const char *name, void *drvdata, ...@@ -647,8 +662,7 @@ __hwmon_device_register(struct device *dev, const char *name, void *drvdata,
hwmon_temp_input, j)) hwmon_temp_input, j))
continue; continue;
if (info[i]->config[j] & HWMON_T_INPUT) { if (info[i]->config[j] & HWMON_T_INPUT) {
err = hwmon_thermal_add_sensor(dev, err = hwmon_thermal_add_sensor(hdev, j);
hwdev, j);
if (err) { if (err) {
device_unregister(hdev); device_unregister(hdev);
/* /*
...@@ -667,7 +681,7 @@ __hwmon_device_register(struct device *dev, const char *name, void *drvdata, ...@@ -667,7 +681,7 @@ __hwmon_device_register(struct device *dev, const char *name, void *drvdata,
return hdev; return hdev;
free_hwmon: free_hwmon:
kfree(hwdev); hwmon_dev_release(hdev);
ida_remove: ida_remove:
ida_simple_remove(&hwmon_ida, id); ida_simple_remove(&hwmon_ida, id);
return ERR_PTR(err); return ERR_PTR(err);
......
...@@ -23,8 +23,8 @@ ...@@ -23,8 +23,8 @@
static const u8 REG_VOLTAGE[5] = { 0x09, 0x0a, 0x0c, 0x0d, 0x0e }; static const u8 REG_VOLTAGE[5] = { 0x09, 0x0a, 0x0c, 0x0d, 0x0e };
static const u8 REG_VOLTAGE_LIMIT_LSB[2][5] = { static const u8 REG_VOLTAGE_LIMIT_LSB[2][5] = {
{ 0x40, 0x00, 0x42, 0x44, 0x46 }, { 0x46, 0x00, 0x40, 0x42, 0x44 },
{ 0x3f, 0x00, 0x41, 0x43, 0x45 }, { 0x45, 0x00, 0x3f, 0x41, 0x43 },
}; };
static const u8 REG_VOLTAGE_LIMIT_MSB[5] = { 0x48, 0x00, 0x47, 0x47, 0x48 }; static const u8 REG_VOLTAGE_LIMIT_MSB[5] = { 0x48, 0x00, 0x47, 0x47, 0x48 };
...@@ -58,6 +58,8 @@ static const u8 REG_VOLTAGE_LIMIT_MSB_SHIFT[2][5] = { ...@@ -58,6 +58,8 @@ static const u8 REG_VOLTAGE_LIMIT_MSB_SHIFT[2][5] = {
struct nct7802_data { struct nct7802_data {
struct regmap *regmap; struct regmap *regmap;
struct mutex access_lock; /* for multi-byte read and write operations */ struct mutex access_lock; /* for multi-byte read and write operations */
u8 in_status;
struct mutex in_alarm_lock;
}; };
static ssize_t temp_type_show(struct device *dev, static ssize_t temp_type_show(struct device *dev,
...@@ -368,6 +370,66 @@ static ssize_t in_store(struct device *dev, struct device_attribute *attr, ...@@ -368,6 +370,66 @@ static ssize_t in_store(struct device *dev, struct device_attribute *attr,
return err ? : count; return err ? : count;
} }
static ssize_t in_alarm_show(struct device *dev, struct device_attribute *attr,
char *buf)
{
struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
struct nct7802_data *data = dev_get_drvdata(dev);
int volt, min, max, ret;
unsigned int val;
mutex_lock(&data->in_alarm_lock);
/*
* The SMI Voltage status register is the only register giving a status
* for voltages. A bit is set for each input crossing a threshold, in
* both direction, but the "inside" or "outside" limits info is not
* available. Also this register is cleared on read.
* Note: this is not explicitly spelled out in the datasheet, but
* from experiment.
* To deal with this we use a status cache with one validity bit and
* one status bit for each input. Validity is cleared at startup and
* each time the register reports a change, and the status is processed
* by software based on current input value and limits.
*/
ret = regmap_read(data->regmap, 0x1e, &val); /* SMI Voltage status */
if (ret < 0)
goto abort;
/* invalidate cached status for all inputs crossing a threshold */
data->in_status &= ~((val & 0x0f) << 4);
/* if cached status for requested input is invalid, update it */
if (!(data->in_status & (0x10 << sattr->index))) {
ret = nct7802_read_voltage(data, sattr->nr, 0);
if (ret < 0)
goto abort;
volt = ret;
ret = nct7802_read_voltage(data, sattr->nr, 1);
if (ret < 0)
goto abort;
min = ret;
ret = nct7802_read_voltage(data, sattr->nr, 2);
if (ret < 0)
goto abort;
max = ret;
if (volt < min || volt > max)
data->in_status |= (1 << sattr->index);
else
data->in_status &= ~(1 << sattr->index);
data->in_status |= 0x10 << sattr->index;
}
ret = sprintf(buf, "%u\n", !!(data->in_status & (1 << sattr->index)));
abort:
mutex_unlock(&data->in_alarm_lock);
return ret;
}
static ssize_t temp_show(struct device *dev, struct device_attribute *attr, static ssize_t temp_show(struct device *dev, struct device_attribute *attr,
char *buf) char *buf)
{ {
...@@ -660,7 +722,7 @@ static const struct attribute_group nct7802_temp_group = { ...@@ -660,7 +722,7 @@ static const struct attribute_group nct7802_temp_group = {
static SENSOR_DEVICE_ATTR_2_RO(in0_input, in, 0, 0); static SENSOR_DEVICE_ATTR_2_RO(in0_input, in, 0, 0);
static SENSOR_DEVICE_ATTR_2_RW(in0_min, in, 0, 1); static SENSOR_DEVICE_ATTR_2_RW(in0_min, in, 0, 1);
static SENSOR_DEVICE_ATTR_2_RW(in0_max, in, 0, 2); static SENSOR_DEVICE_ATTR_2_RW(in0_max, in, 0, 2);
static SENSOR_DEVICE_ATTR_2_RO(in0_alarm, alarm, 0x1e, 3); static SENSOR_DEVICE_ATTR_2_RO(in0_alarm, in_alarm, 0, 3);
static SENSOR_DEVICE_ATTR_2_RW(in0_beep, beep, 0x5a, 3); static SENSOR_DEVICE_ATTR_2_RW(in0_beep, beep, 0x5a, 3);
static SENSOR_DEVICE_ATTR_2_RO(in1_input, in, 1, 0); static SENSOR_DEVICE_ATTR_2_RO(in1_input, in, 1, 0);
...@@ -668,19 +730,19 @@ static SENSOR_DEVICE_ATTR_2_RO(in1_input, in, 1, 0); ...@@ -668,19 +730,19 @@ static SENSOR_DEVICE_ATTR_2_RO(in1_input, in, 1, 0);
static SENSOR_DEVICE_ATTR_2_RO(in2_input, in, 2, 0); static SENSOR_DEVICE_ATTR_2_RO(in2_input, in, 2, 0);
static SENSOR_DEVICE_ATTR_2_RW(in2_min, in, 2, 1); static SENSOR_DEVICE_ATTR_2_RW(in2_min, in, 2, 1);
static SENSOR_DEVICE_ATTR_2_RW(in2_max, in, 2, 2); static SENSOR_DEVICE_ATTR_2_RW(in2_max, in, 2, 2);
static SENSOR_DEVICE_ATTR_2_RO(in2_alarm, alarm, 0x1e, 0); static SENSOR_DEVICE_ATTR_2_RO(in2_alarm, in_alarm, 2, 0);
static SENSOR_DEVICE_ATTR_2_RW(in2_beep, beep, 0x5a, 0); static SENSOR_DEVICE_ATTR_2_RW(in2_beep, beep, 0x5a, 0);
static SENSOR_DEVICE_ATTR_2_RO(in3_input, in, 3, 0); static SENSOR_DEVICE_ATTR_2_RO(in3_input, in, 3, 0);
static SENSOR_DEVICE_ATTR_2_RW(in3_min, in, 3, 1); static SENSOR_DEVICE_ATTR_2_RW(in3_min, in, 3, 1);
static SENSOR_DEVICE_ATTR_2_RW(in3_max, in, 3, 2); static SENSOR_DEVICE_ATTR_2_RW(in3_max, in, 3, 2);
static SENSOR_DEVICE_ATTR_2_RO(in3_alarm, alarm, 0x1e, 1); static SENSOR_DEVICE_ATTR_2_RO(in3_alarm, in_alarm, 3, 1);
static SENSOR_DEVICE_ATTR_2_RW(in3_beep, beep, 0x5a, 1); static SENSOR_DEVICE_ATTR_2_RW(in3_beep, beep, 0x5a, 1);
static SENSOR_DEVICE_ATTR_2_RO(in4_input, in, 4, 0); static SENSOR_DEVICE_ATTR_2_RO(in4_input, in, 4, 0);
static SENSOR_DEVICE_ATTR_2_RW(in4_min, in, 4, 1); static SENSOR_DEVICE_ATTR_2_RW(in4_min, in, 4, 1);
static SENSOR_DEVICE_ATTR_2_RW(in4_max, in, 4, 2); static SENSOR_DEVICE_ATTR_2_RW(in4_max, in, 4, 2);
static SENSOR_DEVICE_ATTR_2_RO(in4_alarm, alarm, 0x1e, 2); static SENSOR_DEVICE_ATTR_2_RO(in4_alarm, in_alarm, 4, 2);
static SENSOR_DEVICE_ATTR_2_RW(in4_beep, beep, 0x5a, 2); static SENSOR_DEVICE_ATTR_2_RW(in4_beep, beep, 0x5a, 2);
static struct attribute *nct7802_in_attrs[] = { static struct attribute *nct7802_in_attrs[] = {
...@@ -1011,6 +1073,7 @@ static int nct7802_probe(struct i2c_client *client, ...@@ -1011,6 +1073,7 @@ static int nct7802_probe(struct i2c_client *client,
return PTR_ERR(data->regmap); return PTR_ERR(data->regmap);
mutex_init(&data->access_lock); mutex_init(&data->access_lock);
mutex_init(&data->in_alarm_lock);
ret = nct7802_init_chip(data); ret = nct7802_init_chip(data);
if (ret < 0) if (ret < 0)
......
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