mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-07-22 03:27:30 -04:00
Merge tag 'hwmon-for-v7.2-rc5' of git://git.kernel.org/pub/scm/linux/kernel/git/groeck/linux-staging
Pull hwmon fixes from Guenter Roeck: - asus-ec-sensors: Add missed handle for ENOMEM, fix EC read intervals, and fix looping over banks while reading from EC - occ: validate poll response sensor blocks - pmbus/max34440: Block unsupported VIN and IIN limit registers - nzxt-kraken3, nzxt-smart2: gigabyte_waterforce, corsair-cpro, corsair-psu: Stop device IO before calling hid_hw_stop * tag 'hwmon-for-v7.2-rc5' of git://git.kernel.org/pub/scm/linux/kernel/git/groeck/linux-staging: hwmon: occ: validate poll response sensor blocks hwmon: (asus-ec-sensors) add missed handle for ENOMEM hwmon: (asus-ec-sensors) fix EC read intervals hwmon: (asus-ec-sensors) fix looping over banks while reading from EC hwmon: (pmbus/max34440) block unsupported VIN and IIN limit registers hwmon: (nzxt-kraken3) Stop device IO before calling hid_hw_stop hwmon: (nzxt-smart2) Stop device IO before calling hid_hw_stop hwmon: (gigabyte_waterforce) Stop device IO before calling hid_hw_stop hwmon: (corsair-cpro) Stop device IO before calling hid_hw_stop hwmon: (corsair-psu) Stop device IO before calling hid_hw_stop
This commit is contained in:
@@ -1009,7 +1009,7 @@ struct ec_sensors_data {
|
||||
/* sorted list of unique register banks */
|
||||
u8 banks[ASUS_EC_MAX_BANK + 1];
|
||||
/* in jiffies */
|
||||
unsigned long last_updated;
|
||||
u64 next_update;
|
||||
struct lock_data lock_data;
|
||||
/* number of board EC sensors */
|
||||
u8 nr_sensors;
|
||||
@@ -1189,7 +1189,7 @@ static int asus_ec_block_read(const struct device *dev,
|
||||
}
|
||||
for (ireg = 0; ireg < ec->nr_registers; ireg++) {
|
||||
reg_bank = register_bank(ec->registers[ireg]);
|
||||
if (reg_bank < bank) {
|
||||
if (reg_bank != bank) {
|
||||
continue;
|
||||
}
|
||||
ec_read(register_index(ec->registers[ireg]),
|
||||
@@ -1278,13 +1278,12 @@ static int get_cached_value_or_update(const struct device *dev,
|
||||
int sensor_index,
|
||||
struct ec_sensors_data *state, s32 *value)
|
||||
{
|
||||
if (time_after(jiffies, state->last_updated + HZ)) {
|
||||
if (time_after64(get_jiffies_64(), state->next_update)) {
|
||||
if (update_ec_sensors(dev, state)) {
|
||||
dev_err(dev, "update_ec_sensors() failure\n");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
state->last_updated = jiffies;
|
||||
state->next_update = get_jiffies_64() + HZ;
|
||||
}
|
||||
|
||||
*value = state->sensors[sensor_index].cached_value;
|
||||
@@ -1402,6 +1401,7 @@ static int asus_ec_probe(struct platform_device *pdev)
|
||||
if (!ec_data)
|
||||
return -ENOMEM;
|
||||
|
||||
ec_data->next_update = INITIAL_JIFFIES;
|
||||
dev_set_drvdata(dev, ec_data);
|
||||
ec_data->board_info = pboard_info;
|
||||
|
||||
@@ -1495,9 +1495,11 @@ static int asus_ec_probe(struct platform_device *pdev)
|
||||
if (!nr_count[type])
|
||||
continue;
|
||||
|
||||
asus_ec_hwmon_add_chan_info(asus_ec_hwmon_chan, dev,
|
||||
nr_count[type], type,
|
||||
hwmon_attributes[type]);
|
||||
status = asus_ec_hwmon_add_chan_info(asus_ec_hwmon_chan, dev,
|
||||
nr_count[type], type,
|
||||
hwmon_attributes[type]);
|
||||
if (status)
|
||||
return status;
|
||||
*ptr_asus_ec_ci++ = asus_ec_hwmon_chan++;
|
||||
}
|
||||
|
||||
|
||||
@@ -645,6 +645,7 @@ static int ccp_probe(struct hid_device *hdev, const struct hid_device_id *id)
|
||||
|
||||
out_hw_close:
|
||||
hid_hw_close(hdev);
|
||||
hid_device_io_stop(hdev);
|
||||
out_hw_stop:
|
||||
hid_hw_stop(hdev);
|
||||
return ret;
|
||||
|
||||
@@ -822,6 +822,7 @@ static int corsairpsu_probe(struct hid_device *hdev, const struct hid_device_id
|
||||
|
||||
fail_and_close:
|
||||
hid_hw_close(hdev);
|
||||
hid_device_io_stop(hdev);
|
||||
fail_and_stop:
|
||||
hid_hw_stop(hdev);
|
||||
return ret;
|
||||
|
||||
@@ -371,13 +371,15 @@ static int waterforce_probe(struct hid_device *hdev, const struct hid_device_id
|
||||
if (IS_ERR(priv->hwmon_dev)) {
|
||||
ret = PTR_ERR(priv->hwmon_dev);
|
||||
hid_err(hdev, "hwmon registration failed with %d\n", ret);
|
||||
goto fail_and_close;
|
||||
goto fail_and_io_stop;
|
||||
}
|
||||
|
||||
waterforce_debugfs_init(priv);
|
||||
|
||||
return 0;
|
||||
|
||||
fail_and_io_stop:
|
||||
hid_device_io_stop(hdev);
|
||||
fail_and_close:
|
||||
hid_hw_close(hdev);
|
||||
fail_and_stop:
|
||||
|
||||
@@ -948,7 +948,7 @@ static int kraken3_probe(struct hid_device *hdev, const struct hid_device_id *id
|
||||
ret = kraken3_init_device(hdev);
|
||||
if (ret < 0) {
|
||||
hid_err(hdev, "device init failed with %d\n", ret);
|
||||
goto fail_and_close;
|
||||
goto fail_and_stop_io;
|
||||
}
|
||||
|
||||
ret = kraken3_get_fw_ver(hdev);
|
||||
@@ -960,13 +960,15 @@ static int kraken3_probe(struct hid_device *hdev, const struct hid_device_id *id
|
||||
if (IS_ERR(priv->hwmon_dev)) {
|
||||
ret = PTR_ERR(priv->hwmon_dev);
|
||||
hid_err(hdev, "hwmon registration failed with %d\n", ret);
|
||||
goto fail_and_close;
|
||||
goto fail_and_stop_io;
|
||||
}
|
||||
|
||||
kraken3_debugfs_init(priv, device_name);
|
||||
|
||||
return 0;
|
||||
|
||||
fail_and_stop_io:
|
||||
hid_device_io_stop(hdev);
|
||||
fail_and_close:
|
||||
hid_hw_close(hdev);
|
||||
fail_and_stop:
|
||||
|
||||
@@ -768,7 +768,7 @@ static int nzxt_smart2_hid_probe(struct hid_device *hdev,
|
||||
|
||||
out_hw_close:
|
||||
hid_hw_close(hdev);
|
||||
|
||||
hid_device_io_stop(hdev);
|
||||
out_hw_stop:
|
||||
hid_hw_stop(hdev);
|
||||
return ret;
|
||||
|
||||
@@ -1052,32 +1052,49 @@ static int occ_setup_sensor_attrs(struct occ *occ)
|
||||
}
|
||||
|
||||
/* only need to do this once at startup, as OCC won't change sensors on us */
|
||||
static void occ_parse_poll_response(struct occ *occ)
|
||||
static int occ_parse_poll_response(struct occ *occ)
|
||||
{
|
||||
unsigned int i, old_offset, offset = 0, size = 0;
|
||||
u16 data_length;
|
||||
struct occ_sensor *sensor;
|
||||
struct occ_sensors *sensors = &occ->sensors;
|
||||
struct occ_sensors parsed = {};
|
||||
struct occ_sensors *sensors = &parsed;
|
||||
struct occ_response *resp = &occ->resp;
|
||||
struct occ_poll_response *poll =
|
||||
(struct occ_poll_response *)&resp->data[0];
|
||||
struct occ_poll_response_header *header = &poll->header;
|
||||
struct occ_sensor_data_block *block = &poll->block;
|
||||
|
||||
data_length = get_unaligned_be16(&resp->data_length);
|
||||
if (data_length < sizeof(*header) || data_length > OCC_RESP_DATA_BYTES) {
|
||||
dev_err(occ->bus_dev, "invalid OCC poll response length %u\n",
|
||||
data_length);
|
||||
return -EMSGSIZE;
|
||||
}
|
||||
|
||||
dev_info(occ->bus_dev, "OCC found, code level: %.16s\n",
|
||||
header->occ_code_level);
|
||||
|
||||
for (i = 0; i < header->num_sensor_data_blocks; ++i) {
|
||||
block = (struct occ_sensor_data_block *)((u8 *)block + offset);
|
||||
if (size + sizeof(*header) + sizeof(block->header) >
|
||||
data_length) {
|
||||
dev_err(occ->bus_dev,
|
||||
"truncated OCC sensor block header\n");
|
||||
return -EMSGSIZE;
|
||||
}
|
||||
|
||||
old_offset = offset;
|
||||
offset = (block->header.num_sensors *
|
||||
block->header.sensor_length) + sizeof(block->header);
|
||||
size += offset;
|
||||
|
||||
/* validate all the length/size fields */
|
||||
if ((size + sizeof(*header)) >= OCC_RESP_DATA_BYTES) {
|
||||
dev_warn(occ->bus_dev, "exceeded response buffer\n");
|
||||
return;
|
||||
if (size + sizeof(*header) + offset > data_length) {
|
||||
dev_err(occ->bus_dev,
|
||||
"exceeded OCC poll response length\n");
|
||||
return -EMSGSIZE;
|
||||
}
|
||||
size += offset;
|
||||
|
||||
dev_dbg(occ->bus_dev, " %04x..%04x: %.4s (%d sensors)\n",
|
||||
old_offset, offset - 1, block->header.eye_catcher,
|
||||
@@ -1107,6 +1124,9 @@ static void occ_parse_poll_response(struct occ *occ)
|
||||
|
||||
dev_dbg(occ->bus_dev, "Max resp size: %u+%zd=%zd\n", size,
|
||||
sizeof(*header), size + sizeof(*header));
|
||||
occ->sensors = parsed;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int occ_active(struct occ *occ, bool active)
|
||||
@@ -1138,10 +1158,12 @@ int occ_active(struct occ *occ, bool active)
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
occ->active = true;
|
||||
occ->next_update = jiffies + OCC_UPDATE_FREQUENCY;
|
||||
occ_parse_poll_response(occ);
|
||||
rc = occ_parse_poll_response(occ);
|
||||
if (rc)
|
||||
goto unlock;
|
||||
|
||||
occ->active = true;
|
||||
rc = occ_setup_sensor_attrs(occ);
|
||||
if (rc) {
|
||||
dev_err(occ->bus_dev,
|
||||
|
||||
@@ -88,6 +88,33 @@ static int max34440_read_word_data(struct i2c_client *client, int page,
|
||||
ret = pmbus_read_word_data(client, page, phase,
|
||||
data->iout_oc_warn_limit);
|
||||
break;
|
||||
case PMBUS_VIN_OV_FAULT_LIMIT:
|
||||
case PMBUS_VIN_OV_WARN_LIMIT:
|
||||
case PMBUS_VIN_UV_WARN_LIMIT:
|
||||
case PMBUS_VIN_UV_FAULT_LIMIT:
|
||||
case PMBUS_MFR_VIN_MIN:
|
||||
case PMBUS_MFR_VIN_MAX:
|
||||
case PMBUS_IIN_OC_WARN_LIMIT:
|
||||
case PMBUS_IIN_OC_FAULT_LIMIT:
|
||||
case PMBUS_MFR_IIN_MAX:
|
||||
case PMBUS_MFR_VOUT_MIN:
|
||||
case PMBUS_MFR_VOUT_MAX:
|
||||
case PMBUS_IOUT_UC_FAULT_LIMIT:
|
||||
case PMBUS_MFR_IOUT_MAX:
|
||||
case PMBUS_UT_WARN_LIMIT:
|
||||
case PMBUS_UT_FAULT_LIMIT:
|
||||
case PMBUS_MFR_MAX_TEMP_1:
|
||||
/*
|
||||
* MAX34451/ADPM family do not support VIN/IIN limit registers,
|
||||
* manufacturer-specific min/max registers, or undercurrent/
|
||||
* undertemperature fault limits. Accessing these triggers CML
|
||||
* error and asserts ALERT.
|
||||
*/
|
||||
if (data->id == max34451 || data->id == adpm12160 ||
|
||||
data->id == adpm12200 || data->id == adpm12250)
|
||||
return -ENXIO;
|
||||
ret = -ENODATA;
|
||||
break;
|
||||
case PMBUS_VIRT_READ_VOUT_MIN:
|
||||
ret = pmbus_read_word_data(client, page, phase,
|
||||
MAX34440_MFR_VOUT_MIN);
|
||||
@@ -244,6 +271,51 @@ static int max34440_read_byte_data(struct i2c_client *client, int page, int reg)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int max34451_read_byte_data(struct i2c_client *client, int page, int reg)
|
||||
{
|
||||
const struct pmbus_driver_info *info = pmbus_get_driver_info(client);
|
||||
const struct max34440_data *data = to_max34440_data(info);
|
||||
|
||||
switch (reg) {
|
||||
case PMBUS_STATUS_BYTE:
|
||||
case PMBUS_STATUS_OTHER:
|
||||
/*
|
||||
* MAX34451/ADPM family do not support STATUS_BYTE or
|
||||
* STATUS_OTHER registers. Accessing them triggers CML
|
||||
* error and asserts ALERT.
|
||||
*/
|
||||
if (data->id == max34451 || data->id == adpm12160 ||
|
||||
data->id == adpm12200 || data->id == adpm12250)
|
||||
return -ENXIO;
|
||||
return -ENODATA;
|
||||
default:
|
||||
return -ENODATA;
|
||||
}
|
||||
}
|
||||
|
||||
static int max34451_write_byte_data(struct i2c_client *client, int page,
|
||||
int reg, u8 byte)
|
||||
{
|
||||
const struct pmbus_driver_info *info = pmbus_get_driver_info(client);
|
||||
const struct max34440_data *data = to_max34440_data(info);
|
||||
|
||||
switch (reg) {
|
||||
case PMBUS_STATUS_BYTE:
|
||||
case PMBUS_STATUS_OTHER:
|
||||
/*
|
||||
* MAX34451/ADPM family do not support STATUS_BYTE or
|
||||
* STATUS_OTHER registers. Writing to them triggers CML
|
||||
* error and asserts ALERT.
|
||||
*/
|
||||
if (data->id == max34451 || data->id == adpm12160 ||
|
||||
data->id == adpm12200 || data->id == adpm12250)
|
||||
return -ENXIO;
|
||||
return -ENODATA;
|
||||
default:
|
||||
return -ENODATA;
|
||||
}
|
||||
}
|
||||
|
||||
static int max34451_set_supported_funcs(struct i2c_client *client,
|
||||
struct max34440_data *data)
|
||||
{
|
||||
@@ -363,7 +435,9 @@ static struct pmbus_driver_info max34440_info[] = {
|
||||
.func[9] = PMBUS_HAVE_VIN | PMBUS_HAVE_STATUS_INPUT,
|
||||
.func[10] = PMBUS_HAVE_IIN | PMBUS_HAVE_STATUS_INPUT,
|
||||
.func[18] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP,
|
||||
.read_byte_data = max34451_read_byte_data,
|
||||
.read_word_data = max34440_read_word_data,
|
||||
.write_byte_data = max34451_write_byte_data,
|
||||
.write_word_data = max34440_write_word_data,
|
||||
},
|
||||
[adpm12200] = {
|
||||
@@ -399,7 +473,9 @@ static struct pmbus_driver_info max34440_info[] = {
|
||||
.func[10] = PMBUS_HAVE_IIN | PMBUS_HAVE_STATUS_INPUT,
|
||||
.func[14] = PMBUS_HAVE_IOUT,
|
||||
.func[18] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP,
|
||||
.read_byte_data = max34451_read_byte_data,
|
||||
.read_word_data = max34440_read_word_data,
|
||||
.write_byte_data = max34451_write_byte_data,
|
||||
.write_word_data = max34440_write_word_data,
|
||||
},
|
||||
[adpm12250] = {
|
||||
@@ -433,7 +509,9 @@ static struct pmbus_driver_info max34440_info[] = {
|
||||
.func[10] = PMBUS_HAVE_IIN | PMBUS_HAVE_STATUS_INPUT,
|
||||
.func[14] = PMBUS_HAVE_IOUT,
|
||||
.func[18] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP,
|
||||
.read_byte_data = max34451_read_byte_data,
|
||||
.read_word_data = max34440_read_word_data,
|
||||
.write_byte_data = max34451_write_byte_data,
|
||||
.write_word_data = max34440_write_word_data,
|
||||
},
|
||||
[max34440] = {
|
||||
@@ -581,7 +659,9 @@ static struct pmbus_driver_info max34440_info[] = {
|
||||
.func[18] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP,
|
||||
.func[19] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP,
|
||||
.func[20] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP,
|
||||
.read_byte_data = max34451_read_byte_data,
|
||||
.read_word_data = max34440_read_word_data,
|
||||
.write_byte_data = max34451_write_byte_data,
|
||||
.write_word_data = max34440_write_word_data,
|
||||
.page_change_delay = MAX34440_PAGE_CHANGE_DELAY,
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user