Dear Guenter, Thank you for your comments, Guenter Roeck <linux@xxxxxxxxxxxx> 於 2024年12月10日 週二 下午11:58寫道: > > On Tue, Dec 10, 2024 at 06:45:23PM +0800, Ming Yu wrote: > > This driver supports Hardware monitor functionality for NCT6694 MFD > > device based on USB interface. > > > > Signed-off-by: Ming Yu <tmyu0@xxxxxxxxxxx> > > checkpatch: > > WARNING: From:/Signed-off-by: email address mismatch: 'From: Ming Yu <a0282524688@xxxxxxxxx>' != 'Signed-off-by: Ming Yu <tmyu0@xxxxxxxxxxx>' > Fix it in v4. ... > > +static inline long in_from_reg(u8 reg) > > +{ > > + return reg * 16; > > +} > > + > > +static inline u8 in_to_reg(long val) > > +{ > > + if (val <= 0) > > + return 0; > > This is pointless since the calling code already clamps the value to [0, 2032]. > Drop it in v4. > > + return val / 16; > > DIV_ROUND_CLOSEST() ? > Fix it in v4. > > +} > > + > > +static inline long temp_from_reg(u8 reg) > > +{ > > + return reg * 1000; > > This always returns a positive value, even though the temperature is > supposed to be signed. More on that below. > I will modify the return value to (sign_extend32(reg, 7) * 1000) in v4. > > +} > > + > > +static inline u8 temp_to_reg(long val) > > +{ > > + return val / 1000; > > DIV_ROUND_CLOSEST() ? > Fix it in v4. > > +} ... > > +static int nct6694_in_read(struct device *dev, u32 attr, int channel, > > + long *val) > > +{ > > + struct nct6694_hwmon_data *data = dev_get_drvdata(dev); > > + unsigned char vin_en; > > + int ret; > > + > > + guard(mutex)(&data->lock); > > + > > + switch (attr) { > > + case hwmon_in_enable: > > + vin_en = data->hwmon_en[NCT6694_VIN_EN(channel / 8)]; > > + *val = !!(vin_en & BIT(channel % 8)) ? 1 : 0; > > Drop "? 1 : 0" > Drop it in v4. > > + > > + return 0; > > + case hwmon_in_input: > > + ret = nct6694_read_msg(data->nct6694, NCT6694_RPT_MOD, > > + NCT6694_VIN_IDX(channel), 1, > > + data->xmit_buf); > > I am curious: Since the received data length is not returned, and the > expected minimum length is not passed to nct6694_read_msg(), the driver > has no means to check if the received data actually includes the expected > values at the expected index. That doesn't matter here, but some of the > returned data is located far into the buffer. Is it indeed not necessary > for the driver to check if the received data is actually as long as > expected ? > The fourth parameter is expected length of nct6694_read_msg(), which in this case is 1. I will add the data length validation code for handling the response_header in both nct6694_read_msg() and nct6694_write_msg() in the next patch. > > + if (ret) > > + return ret; ... > > +static int nct6694_temp_read(struct device *dev, u32 attr, int channel, > > + long *val) > > +{ > > + struct nct6694_hwmon_data *data = dev_get_drvdata(dev); > > + unsigned char temp_en, temp_hyst; > > + int ret, int_part, frac_part; > > + signed char temp_max; > > + > > + guard(mutex)(&data->lock); > > + > > + switch (attr) { > > + case hwmon_temp_enable: > > + temp_en = data->hwmon_en[NCT6694_TIN_EN(channel / 8)]; > > + *val = !!(temp_en & BIT(channel % 8)) ? 1 : 0; > > Drop "? 1 : 0" > Drop it in v4. > > + > > + return 0; > > + case hwmon_temp_input: > > + ret = nct6694_read_msg(data->nct6694, NCT6694_RPT_MOD, > > + NCT6694_TIN_IDX(channel), 2, > > + data->xmit_buf); > > + if (ret) > > + return ret; > > + > > + int_part = sign_extend32(data->xmit_buf[0], 7); > > + frac_part = FIELD_GET(NCT6694_LSB_REG_MASK, data->xmit_buf[1]); > > + if (int_part < 0) > > + *val = (int_part + 1) * 1000 - (8 - frac_part) * 125; > > + else > > + *val = int_part * 1000 + frac_part * 125; > > + > > + return 0; > > + case hwmon_temp_max: > > + ret = nct6694_read_msg(data->nct6694, NCT6694_HWMON_MOD, > > + NCT6694_HWMON_CMD2_OFFSET, > > + NCT6694_HWMON_CMD2_LEN, > > + data->xmit_buf); > > + if (ret) > > + return ret; > > + > > + *val = temp_from_reg(data->xmit_buf[NCT6694_TIN_HL(channel)]); > > + > > If the value in NCT6694_TIN_HL() is signed, this will return a large positive > value instead. > Understood! I will fix it in v4. > > + return 0; > > + case hwmon_temp_max_hyst: > > + ret = nct6694_read_msg(data->nct6694, NCT6694_HWMON_MOD, > > + NCT6694_HWMON_CMD2_OFFSET, > > + NCT6694_HWMON_CMD2_LEN, > > + data->xmit_buf); > > + if (ret) > > + return ret; > > + > > + temp_max = (signed char)data->xmit_buf[NCT6694_TIN_HL(channel)]; > > + temp_hyst = FIELD_GET(NCT6694_TIN_HYST_MASK, > > + data->xmit_buf[NCT6694_TIN_HYST(channel)]); > > + if (temp_max < 0) > > This suggests that the temperature limit is signed, suggesting in turn that > temp_from_reg() is wrong. > Understood! I will fix it in v4. > > + *val = temp_from_reg(temp_max + temp_hyst); > > + else > > + *val = temp_from_reg(temp_max - temp_hyst); > > + > > + return 0; > > + case hwmon_temp_max_alarm: > > + ret = nct6694_read_msg(data->nct6694, NCT6694_RPT_MOD, > > + NCT6694_TIN_STS(channel / 8), 1, > > + data->xmit_buf); > > + if (ret) > > + return ret; > > + > > + *val = !!(data->xmit_buf[0] & BIT(channel % 8)); > > + > > + return 0; > > + default: > > + return -EOPNOTSUPP; > > + } > > +} > > + > > +static int nct6694_fan_read(struct device *dev, u32 attr, int channel, > > + long *val) > > +{ > > + struct nct6694_hwmon_data *data = dev_get_drvdata(dev); > > + unsigned char fanin_en; > > + int ret; > > + > > + guard(mutex)(&data->lock); > > + > > + switch (attr) { > > + case hwmon_fan_enable: > > + fanin_en = data->hwmon_en[NCT6694_FIN_EN(channel / 8)]; > > + *val = !!(fanin_en & BIT(channel % 8)) ? 1 : 0; > > Drop "? 1 : 0" > Drop it in v4. > > + > > + return 0; > > + case hwmon_fan_input: > > + ret = nct6694_read_msg(data->nct6694, NCT6694_RPT_MOD, > > + NCT6694_FIN_IDX(channel), 2, > > + data->xmit_buf); > > + if (ret) > > + return ret; > > + > > + *val = (data->xmit_buf[1] | > > + (data->xmit_buf[0] << 8)) & 0xFFFF; > > The "& 0xffff" is pointless. > Fix it in v4. > > + > > + return 0; > > + case hwmon_fan_min: > > + ret = nct6694_read_msg(data->nct6694, NCT6694_HWMON_MOD, > > + NCT6694_HWMON_CMD2_OFFSET, > > + NCT6694_HWMON_CMD2_LEN, > > + data->xmit_buf); > > + if (ret) > > + return ret; > > + > > + *val = (data->xmit_buf[NCT6694_FIN_LL(channel)] | > > + data->xmit_buf[NCT6694_FIN_HL(channel)] << 8) & 0xFFFF; > > Same here. > Fix it in v4. > > + > > + return 0; > > + case hwmon_fan_min_alarm: > > + ret = nct6694_read_msg(data->nct6694, NCT6694_RPT_MOD, > > + NCT6694_FIN_STS(channel / 8), > > + 1, data->xmit_buf); > > + if (ret) > > + return ret; > > + > > + *val = !!(data->xmit_buf[0] & BIT(channel % 8)); > > + > > + return 0; > > + default: > > + return -EOPNOTSUPP; > > + } > > +} > > + > > +static int nct6694_pwm_read(struct device *dev, u32 attr, int channel, > > + long *val) > > +{ > > + struct nct6694_hwmon_data *data = dev_get_drvdata(dev); > > + unsigned char pwm_en; > > + int ret; > > + > > + guard(mutex)(&data->lock); > > + > > + switch (attr) { > > + case hwmon_pwm_enable: > > + pwm_en = data->hwmon_en[NCT6694_PWM_EN(channel / 8)]; > > + *val = !!(pwm_en & BIT(channel % 8)) ? 1 : 0; > > Drop "? 1 : 0". > Drop it in v4. > > + ... > > + case hwmon_temp_max_hyst: > > + ret = nct6694_read_msg(data->nct6694, NCT6694_HWMON_MOD, > > + NCT6694_HWMON_CMD2_OFFSET, > > + NCT6694_HWMON_CMD2_LEN, > > + data->xmit_buf); > > + > > + val = clamp_val(val, -127000, 127000); > > + temp_max = (signed char)data->xmit_buf[NCT6694_TIN_HL(channel)]; > > + temp_hyst = (temp_max < 0) ? (temp_max + val / 1000) : > > + (temp_max - val / 1000); > > DIV_ROUND_CLOSEST() ? > Fix it in v4. > > + temp_hyst = clamp_val(temp_hyst, 0, 7); > > + data->xmit_buf[NCT6694_TIN_HYST(channel)] = > > + (data->xmit_buf[NCT6694_TIN_HYST(channel)] & ~NCT6694_TIN_HYST_MASK) | > > + FIELD_PREP(NCT6694_TIN_HYST_MASK, temp_hyst); > > + ... > > + > > +static int nct6694_hwmon_init(struct nct6694_hwmon_data *data) > > +{ > > + int ret; > > + > > + guard(mutex)(&data->lock); > > + > > Not significant, but this is unnecessary because the function is only > called once from probe. > Understood! I will drop it in the next patch. > > + /* ... > > +static int nct6694_hwmon_probe(struct platform_device *pdev) > > +{ > > + struct nct6694_hwmon_data *data; > > + struct nct6694 *nct6694 = dev_get_drvdata(pdev->dev.parent); > > + struct device *hwmon_dev; > > + int ret; > > + > > + data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL); > > + if (!data) > > + return -ENOMEM; > > + > > + data->xmit_buf = devm_kcalloc(&pdev->dev, NCT6694_MAX_PACKET_SZ, > > + sizeof(unsigned char), GFP_KERNEL); > > Wondering ... why not just devm_kzalloc(..,. NCT6694_MAX_PACKET_SZ, ...) ? > sizeof(unsigned char) is always 1, after all. > Okay, I'll fix it. > > + if (!data->xmit_buf) > > + return -ENOMEM; > > + > > + data->nct6694 = nct6694; > > + mutex_init(&data->lock); > > + platform_set_drvdata(pdev, data); > > This is unnecessary unless I am missing something. > Drop it in v4. > > + > > + ret = nct6694_hwmon_init(data); > > + if (ret) > > + return ret; > > + > > + /* Register hwmon device to HWMON framework */ > > + hwmon_dev = devm_hwmon_device_register_with_info(&pdev->dev, > > + "nct6694", data, > > + &nct6694_chip_info, > > + NULL); > > + return PTR_ERR_OR_ZERO(hwmon_dev); > > +} > > + > > +static struct platform_driver nct6694_hwmon_driver = { > > + .driver = { > > + .name = "nct6694-hwmon", > > + }, > > + .probe = nct6694_hwmon_probe, > > +}; > > + > > +module_platform_driver(nct6694_hwmon_driver); > > + > > +MODULE_DESCRIPTION("USB-HWMON driver for NCT6694"); > > +MODULE_AUTHOR("Ming Yu <tmyu0@xxxxxxxxxxx>"); > > +MODULE_LICENSE("GPL"); > > +MODULE_ALIAS("platform:nct6694-hwmon"); > > -- > > 2.34.1 > > > > Best regards, Ming