From patchwork Tue Mar 16 17:54:58 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?b?VsOhY2xhdiBLdWJlcm7DoXQ=?= X-Patchwork-Id: 12143415 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-13.9 required=3.0 tests=BAYES_00, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,UNWANTED_LANGUAGE_BODY, URIBL_BLOCKED,USER_AGENT_GIT autolearn=unavailable autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id A1157C433E0 for ; Tue, 16 Mar 2021 17:56:56 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 6A10365101 for ; Tue, 16 Mar 2021 17:56:56 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S236044AbhCPR4Y (ORCPT ); Tue, 16 Mar 2021 13:56:24 -0400 Received: from mail-ed1-f52.google.com ([209.85.208.52]:38752 "EHLO mail-ed1-f52.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231919AbhCPRzz (ORCPT ); Tue, 16 Mar 2021 13:55:55 -0400 Received: by mail-ed1-f52.google.com with SMTP id h13so22607595eds.5; Tue, 16 Mar 2021 10:55:54 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:mime-version :content-transfer-encoding; bh=WwY0jENGZ8w9LCap3uvWftM+Im9MAgWDuvj+CVzZHJY=; b=BC13zEOpOWfsUiKynpwCr7feK73cpFNWPgJ6Ou3550yzo9HF0dHoQDh0CBrDLTFVFn 2zrMGC0xCD3LnAcg8KhM7wDTIn29LjFad+1eBrXajzjBt+sjlOIp8ldT2JfqhT3AgBLh bWXQkIKPv+STK5QhHafqwnlXsOmIPYn2JXLTJwy4SNemygPmRsvUSmp1bcTDwNX1+oqi y7eesl9zvhnMxVCfy8CHab5z2AZw/+F1j5ez/rzRrvWc+fbb6KDWgwbWfmsBHHiz1MLG hLSbHzfLby1AFRiqQGA9yTq73wH/68vQ3/boDC8sDd6io+wlr7jQIV7dGETts4gtM+bL 9tug== X-Gm-Message-State: AOAM530GzXAK0oVPu4yW5qC9gYSN4YwcY92/d5XvQivOwsLelZOoTqLR 6iC5Jd24znjbg+eFD/4Kg2w= X-Google-Smtp-Source: ABdhPJzlXQaIHxU4eVzKOQYzPOIYeCyc+rmX+fJKstmslZsqNj2K/ry+wuq6D4qmOP2cPIvGkcaCHw== X-Received: by 2002:a05:6402:704:: with SMTP id w4mr39026341edx.175.1615917353528; Tue, 16 Mar 2021 10:55:53 -0700 (PDT) Received: from localhost ([2a02:8308:387:c900:a7b5:b859:9449:c07b]) by smtp.gmail.com with ESMTPSA id b6sm9630201ejb.8.2021.03.16.10.55.52 (version=TLS1_3 cipher=TLS_AES_128_GCM_SHA256 bits=128/128); Tue, 16 Mar 2021 10:55:53 -0700 (PDT) From: =?utf-8?b?VsOhY2xhdiBLdWJlcm7DoXQ=?= Cc: =?utf-8?b?VsOhY2xhdiBLdWJlcm7DoXQ=?= , Jean Delvare , Guenter Roeck , Jonathan Corbet , linux-hwmon@vger.kernel.org, linux-doc@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [PATCH v2 1/5] hwmon: (max31790) Rework to use regmap Date: Tue, 16 Mar 2021 18:54:58 +0100 Message-Id: <20210316175503.1003051-1-kubernat@cesnet.cz> X-Mailer: git-send-email 2.30.2 MIME-Version: 1.0 To: unlisted-recipients:; (no To-header on input) Precedence: bulk List-ID: X-Mailing-List: linux-hwmon@vger.kernel.org Converting the driver to use regmap makes it more generic. It also makes it a lot easier to debug through debugfs. Signed-off-by: Václav Kubernát Reported-by: kernel test robot Reported-by: Dan Carpenter --- drivers/hwmon/Kconfig | 1 + drivers/hwmon/max31790.c | 318 ++++++++++++++++++++------------------- 2 files changed, 163 insertions(+), 156 deletions(-) diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig index 54f04e61fb83..c2ec57672c4e 100644 --- a/drivers/hwmon/Kconfig +++ b/drivers/hwmon/Kconfig @@ -1092,6 +1092,7 @@ config SENSORS_MAX6697 config SENSORS_MAX31790 tristate "Maxim MAX31790 sensor chip" depends on I2C + select REGMAP_I2C help If you say yes here you get support for 6-Channel PWM-Output Fan RPM Controller. diff --git a/drivers/hwmon/max31790.c b/drivers/hwmon/max31790.c index 86e6c71db685..4e5add567890 100644 --- a/drivers/hwmon/max31790.c +++ b/drivers/hwmon/max31790.c @@ -12,6 +12,7 @@ #include #include #include +#include #include /* MAX31790 registers */ @@ -46,92 +47,49 @@ #define NR_CHANNEL 6 +#define MAX31790_REG_USER_BYTE_67 0x67 + +#define BULK_TO_U16(msb, lsb) (((msb) << 8) + (lsb)) +#define U16_MSB(num) (((num) & 0xFF00) >> 8) +#define U16_LSB(num) ((num) & 0x00FF) + +static const struct regmap_range max31790_ro_range = { + .range_min = MAX31790_REG_TACH_COUNT(0), + .range_max = MAX31790_REG_PWMOUT(0) - 1, +}; + +static const struct regmap_access_table max31790_wr_table = { + .no_ranges = &max31790_ro_range, + .n_no_ranges = 1, +}; + +static const struct regmap_range max31790_volatile_ranges[] = { + regmap_reg_range(MAX31790_REG_TACH_COUNT(0), MAX31790_REG_TACH_COUNT(12)), + regmap_reg_range(MAX31790_REG_FAN_FAULT_STATUS2, MAX31790_REG_FAN_FAULT_STATUS1), +}; + +static const struct regmap_access_table max31790_volatile_table = { + .no_ranges = max31790_volatile_ranges, + .n_no_ranges = 2, + .n_yes_ranges = 0 +}; + +static const struct regmap_config max31790_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + .reg_stride = 1, + .max_register = MAX31790_REG_USER_BYTE_67, + .wr_table = &max31790_wr_table, + .volatile_table = &max31790_volatile_table +}; + /* * Client data (each client gets its own) */ struct max31790_data { - struct i2c_client *client; - struct mutex update_lock; - bool valid; /* zero until following fields are valid */ - unsigned long last_updated; /* in jiffies */ - - /* register values */ - u8 fan_config[NR_CHANNEL]; - u8 fan_dynamics[NR_CHANNEL]; - u16 fault_status; - u16 tach[NR_CHANNEL * 2]; - u16 pwm[NR_CHANNEL]; - u16 target_count[NR_CHANNEL]; + struct regmap *regmap; }; -static struct max31790_data *max31790_update_device(struct device *dev) -{ - struct max31790_data *data = dev_get_drvdata(dev); - struct i2c_client *client = data->client; - struct max31790_data *ret = data; - int i; - int rv; - - mutex_lock(&data->update_lock); - - if (time_after(jiffies, data->last_updated + HZ) || !data->valid) { - rv = i2c_smbus_read_byte_data(client, - MAX31790_REG_FAN_FAULT_STATUS1); - if (rv < 0) - goto abort; - data->fault_status = rv & 0x3F; - - rv = i2c_smbus_read_byte_data(client, - MAX31790_REG_FAN_FAULT_STATUS2); - if (rv < 0) - goto abort; - data->fault_status |= (rv & 0x3F) << 6; - - for (i = 0; i < NR_CHANNEL; i++) { - rv = i2c_smbus_read_word_swapped(client, - MAX31790_REG_TACH_COUNT(i)); - if (rv < 0) - goto abort; - data->tach[i] = rv; - - if (data->fan_config[i] - & MAX31790_FAN_CFG_TACH_INPUT) { - rv = i2c_smbus_read_word_swapped(client, - MAX31790_REG_TACH_COUNT(NR_CHANNEL - + i)); - if (rv < 0) - goto abort; - data->tach[NR_CHANNEL + i] = rv; - } else { - rv = i2c_smbus_read_word_swapped(client, - MAX31790_REG_PWMOUT(i)); - if (rv < 0) - goto abort; - data->pwm[i] = rv; - - rv = i2c_smbus_read_word_swapped(client, - MAX31790_REG_TARGET_COUNT(i)); - if (rv < 0) - goto abort; - data->target_count[i] = rv; - } - } - - data->last_updated = jiffies; - data->valid = true; - } - goto done; - -abort: - data->valid = false; - ret = ERR_PTR(rv); - -done: - mutex_unlock(&data->update_lock); - - return ret; -} - static const u8 tach_period[8] = { 1, 2, 4, 8, 16, 32, 32, 32 }; static u8 get_tach_period(u8 fan_dynamics) @@ -159,28 +117,89 @@ static u8 bits_for_tach_period(int rpm) return bits; } +static int read_reg_byte(struct regmap *regmap, u8 reg) +{ + int rv; + int val; + + rv = regmap_read(regmap, reg, &val); + + if (rv < 0) + return rv; + + return val; +} + +static int read_reg_word(struct regmap *regmap, u8 reg) +{ + int rv; + u8 val_bulk[2]; + + rv = regmap_bulk_read(regmap, reg, val_bulk, 2); + if (rv < 0) + return rv; + + return BULK_TO_U16(val_bulk[0], val_bulk[1]); +} + +static int write_reg_word(struct regmap *regmap, u8 reg, u16 val) +{ + u8 bulk_val[2]; + + bulk_val[0] = U16_MSB(val); + bulk_val[1] = U16_LSB(val); + + return regmap_bulk_write(regmap, reg, bulk_val, 2); +} + static int max31790_read_fan(struct device *dev, u32 attr, int channel, long *val) { - struct max31790_data *data = max31790_update_device(dev); - int sr, rpm; + struct max31790_data *data = dev_get_drvdata(dev); + struct regmap *regmap = data->regmap; + int rpm, dynamics, tach, fault; if (IS_ERR(data)) return PTR_ERR(data); switch (attr) { case hwmon_fan_input: - sr = get_tach_period(data->fan_dynamics[channel]); - rpm = RPM_FROM_REG(data->tach[channel], sr); + dynamics = read_reg_byte(regmap, MAX31790_REG_FAN_DYNAMICS(channel)); + if (dynamics < 0) + return dynamics; + + tach = read_reg_word(regmap, MAX31790_REG_TACH_COUNT(channel)); + if (tach < 0) + return tach; + + rpm = RPM_FROM_REG(tach, get_tach_period(dynamics)); *val = rpm; return 0; case hwmon_fan_target: - sr = get_tach_period(data->fan_dynamics[channel]); - rpm = RPM_FROM_REG(data->target_count[channel], sr); + dynamics = read_reg_byte(regmap, MAX31790_REG_FAN_DYNAMICS(channel)); + if (dynamics < 0) + return dynamics; + + tach = read_reg_word(regmap, MAX31790_REG_TARGET_COUNT(channel)); + if (tach < 0) + return tach; + + rpm = RPM_FROM_REG(tach, get_tach_period(dynamics)); *val = rpm; return 0; case hwmon_fan_fault: - *val = !!(data->fault_status & (1 << channel)); + if (channel > 6) + fault = read_reg_byte(regmap, MAX31790_REG_FAN_FAULT_STATUS2); + else + fault = read_reg_byte(regmap, MAX31790_REG_FAN_FAULT_STATUS1); + + if (fault < 0) + return fault; + + if (channel > 6) + *val = !!(fault & (1 << (channel - 6))); + else + *val = !!(fault & (1 << channel)); return 0; default: return -EOPNOTSUPP; @@ -191,52 +210,58 @@ static int max31790_write_fan(struct device *dev, u32 attr, int channel, long val) { struct max31790_data *data = dev_get_drvdata(dev); - struct i2c_client *client = data->client; + struct regmap *regmap = data->regmap; int target_count; int err = 0; u8 bits; int sr; - - mutex_lock(&data->update_lock); + int fan_dynamics; switch (attr) { case hwmon_fan_target: val = clamp_val(val, FAN_RPM_MIN, FAN_RPM_MAX); bits = bits_for_tach_period(val); - data->fan_dynamics[channel] = - ((data->fan_dynamics[channel] & + fan_dynamics = read_reg_byte(regmap, MAX31790_REG_FAN_DYNAMICS(channel)); + + if (fan_dynamics < 0) + return fan_dynamics; + + fan_dynamics = + ((fan_dynamics & ~MAX31790_FAN_DYN_SR_MASK) | (bits << MAX31790_FAN_DYN_SR_SHIFT)); - err = i2c_smbus_write_byte_data(client, - MAX31790_REG_FAN_DYNAMICS(channel), - data->fan_dynamics[channel]); + err = regmap_write(regmap, + MAX31790_REG_FAN_DYNAMICS(channel), + fan_dynamics); if (err < 0) break; - sr = get_tach_period(data->fan_dynamics[channel]); + sr = get_tach_period(fan_dynamics); target_count = RPM_TO_REG(val, sr); target_count = clamp_val(target_count, 0x1, 0x7FF); - data->target_count[channel] = target_count << 5; + target_count = target_count << 5; - err = i2c_smbus_write_word_swapped(client, - MAX31790_REG_TARGET_COUNT(channel), - data->target_count[channel]); + err = write_reg_word(regmap, + MAX31790_REG_TARGET_COUNT(channel), + target_count); break; default: err = -EOPNOTSUPP; break; } - mutex_unlock(&data->update_lock); - return err; } static umode_t max31790_fan_is_visible(const void *_data, u32 attr, int channel) { const struct max31790_data *data = _data; - u8 fan_config = data->fan_config[channel % NR_CHANNEL]; + struct regmap *regmap = data->regmap; + u8 fan_config = read_reg_byte(regmap, MAX31790_REG_FAN_CONFIG(channel % NR_CHANNEL)); + + if (fan_config < 0) + return 0; switch (attr) { case hwmon_fan_input: @@ -258,22 +283,29 @@ static umode_t max31790_fan_is_visible(const void *_data, u32 attr, int channel) static int max31790_read_pwm(struct device *dev, u32 attr, int channel, long *val) { - struct max31790_data *data = max31790_update_device(dev); - u8 fan_config; + struct max31790_data *data = dev_get_drvdata(dev); + struct regmap *regmap = data->regmap; + int read; if (IS_ERR(data)) return PTR_ERR(data); - fan_config = data->fan_config[channel]; - switch (attr) { case hwmon_pwm_input: - *val = data->pwm[channel] >> 8; + read = read_reg_word(regmap, MAX31790_REG_PWMOUT(channel)); + if (read < 0) + return read; + + *val = read >> 8; return 0; case hwmon_pwm_enable: - if (fan_config & MAX31790_FAN_CFG_RPM_MODE) + read = read_reg_byte(regmap, MAX31790_REG_FAN_CONFIG(channel)); + if (read < 0) + return read; + + if (read & MAX31790_FAN_CFG_RPM_MODE) *val = 2; - else if (fan_config & MAX31790_FAN_CFG_TACH_INPUT_EN) + else if (read & MAX31790_FAN_CFG_TACH_INPUT_EN) *val = 1; else *val = 0; @@ -287,25 +319,24 @@ static int max31790_write_pwm(struct device *dev, u32 attr, int channel, long val) { struct max31790_data *data = dev_get_drvdata(dev); - struct i2c_client *client = data->client; + struct regmap *regmap = data->regmap; u8 fan_config; int err = 0; - mutex_lock(&data->update_lock); - switch (attr) { case hwmon_pwm_input: if (val < 0 || val > 255) { err = -EINVAL; break; } - data->pwm[channel] = val << 8; - err = i2c_smbus_write_word_swapped(client, - MAX31790_REG_PWMOUT(channel), - data->pwm[channel]); + err = write_reg_word(regmap, MAX31790_REG_PWMOUT(channel), val << 8); break; case hwmon_pwm_enable: - fan_config = data->fan_config[channel]; + fan_config = read_reg_byte(regmap, MAX31790_REG_FAN_CONFIG(channel % NR_CHANNEL)); + + if (fan_config < 0) + return fan_config; + if (val == 0) { fan_config &= ~(MAX31790_FAN_CFG_TACH_INPUT_EN | MAX31790_FAN_CFG_RPM_MODE); @@ -320,25 +351,26 @@ static int max31790_write_pwm(struct device *dev, u32 attr, int channel, err = -EINVAL; break; } - data->fan_config[channel] = fan_config; - err = i2c_smbus_write_byte_data(client, - MAX31790_REG_FAN_CONFIG(channel), - fan_config); + err = regmap_write(regmap, + MAX31790_REG_FAN_CONFIG(channel), + fan_config); break; default: err = -EOPNOTSUPP; break; } - mutex_unlock(&data->update_lock); - return err; } static umode_t max31790_pwm_is_visible(const void *_data, u32 attr, int channel) { const struct max31790_data *data = _data; - u8 fan_config = data->fan_config[channel]; + struct regmap *regmap = data->regmap; + u8 fan_config = read_reg_byte(regmap, MAX31790_REG_FAN_CONFIG(channel % NR_CHANNEL)); + + if (fan_config < 0) + return 0; switch (attr) { case hwmon_pwm_input: @@ -426,35 +458,12 @@ static const struct hwmon_chip_info max31790_chip_info = { .info = max31790_info, }; -static int max31790_init_client(struct i2c_client *client, - struct max31790_data *data) -{ - int i, rv; - - for (i = 0; i < NR_CHANNEL; i++) { - rv = i2c_smbus_read_byte_data(client, - MAX31790_REG_FAN_CONFIG(i)); - if (rv < 0) - return rv; - data->fan_config[i] = rv; - - rv = i2c_smbus_read_byte_data(client, - MAX31790_REG_FAN_DYNAMICS(i)); - if (rv < 0) - return rv; - data->fan_dynamics[i] = rv; - } - - return 0; -} - static int max31790_probe(struct i2c_client *client) { struct i2c_adapter *adapter = client->adapter; struct device *dev = &client->dev; struct max31790_data *data; struct device *hwmon_dev; - int err; if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA)) @@ -464,15 +473,12 @@ static int max31790_probe(struct i2c_client *client) if (!data) return -ENOMEM; - data->client = client; - mutex_init(&data->update_lock); + data->regmap = devm_regmap_init_i2c(client, &max31790_regmap_config); - /* - * Initialize the max31790 chip - */ - err = max31790_init_client(client, data); - if (err) - return err; + if (IS_ERR(data->regmap)) { + dev_err(dev, "failed to allocate register map\n"); + return PTR_ERR(data->regmap); + } hwmon_dev = devm_hwmon_device_register_with_info(dev, client->name, data, From patchwork Tue Mar 16 17:54:59 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?b?VsOhY2xhdiBLdWJlcm7DoXQ=?= X-Patchwork-Id: 12143417 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-16.8 required=3.0 tests=BAYES_00, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED,USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 69790C433E6 for ; Tue, 16 Mar 2021 17:57:29 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 3FD3365104 for ; Tue, 16 Mar 2021 17:57:29 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S239455AbhCPR45 (ORCPT ); Tue, 16 Mar 2021 13:56:57 -0400 Received: from mail-ej1-f42.google.com ([209.85.218.42]:36643 "EHLO mail-ej1-f42.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S239458AbhCPR4A (ORCPT ); Tue, 16 Mar 2021 13:56:00 -0400 Received: by mail-ej1-f42.google.com with SMTP id e19so73739504ejt.3; Tue, 16 Mar 2021 10:55:59 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=tJ7F8vBoziNG6fSK7dLbSv5ntc0CUAXmmoXNPgdj2OA=; b=YY8Ft2rMn8as5G5m6o7gHsFY3i66PbHqMhqb2h7eWUBgF4x8v2deFtB36PELYUHtI0 QdejqW3L7RjnV9LldN6IQav1SB05MJhgACKL74L/zHnlKViVqxuPEsVwOaOKjtPabAmb Tvx0dyxWgRJX7tjuoB0tcuXvyXI/T1iOZQs9yivWcKw5CzTFE+8n9B6+rXe9qiFnKS7v IArJKsWz4/ukAJigBoSFdWabassWW0/RPQfIavx1axAKZJ8Ldn3jo9i6+poP9wx4RO5X R3L7Y88+2PQ33pwjBeg/oMZ/aEm1Q36r+NZ2n/TKgDT/opJMB+Tc3nlMedmgGr95uHBC /adw== X-Gm-Message-State: AOAM531sn7fv5A+em9JHcgR3BoPVx9qEkcDqkftXoBxDnbrMQB1IVe1r y1GGcpnG16vHS1bdMVmrDzA= X-Google-Smtp-Source: ABdhPJz7U/CmGDXcf4fafuOzJintHWY0JC5Av9g5boMOJeQXFco/IKDixTQRys1GJI2FLLH2hkKwYA== X-Received: by 2002:a17:907:75d9:: with SMTP id jl25mr30487352ejc.452.1615917358914; Tue, 16 Mar 2021 10:55:58 -0700 (PDT) Received: from localhost ([2a02:8308:387:c900:a7b5:b859:9449:c07b]) by smtp.gmail.com with ESMTPSA id v11sm10944459eds.14.2021.03.16.10.55.57 (version=TLS1_3 cipher=TLS_AES_128_GCM_SHA256 bits=128/128); Tue, 16 Mar 2021 10:55:58 -0700 (PDT) From: =?utf-8?b?VsOhY2xhdiBLdWJlcm7DoXQ=?= Cc: =?utf-8?b?VsOhY2xhdiBLdWJlcm7DoXQ=?= , Jean Delvare , Guenter Roeck , Jonathan Corbet , linux-hwmon@vger.kernel.org, linux-doc@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [PATCH v2 2/5] hwmon: (max31790) Fix and split pwm*_enable Date: Tue, 16 Mar 2021 18:54:59 +0100 Message-Id: <20210316175503.1003051-2-kubernat@cesnet.cz> X-Mailer: git-send-email 2.30.2 In-Reply-To: <20210316175503.1003051-1-kubernat@cesnet.cz> References: <20210316175503.1003051-1-kubernat@cesnet.cz> MIME-Version: 1.0 To: unlisted-recipients:; (no To-header on input) Precedence: bulk List-ID: X-Mailing-List: linux-hwmon@vger.kernel.org In the old code, pwm*_enable does two things. Firstly, it sets whether the chip should run in PWM or RPM mode. Secondly, it tells the chip whether it should monitor fan RPM. However, these two settings aren't tied together, so they shouldn't be set with a single value. In the new code, fan*_enable now controls fan RPM monitoring (pwm*_enable no longer controls that). According to the sysfs hwmon documentation, pwm*_enable has three possible values, 0 for "no control / full-speed", 1 for manual mode, and 2+ for automatic. The old code works fine for 1 and 2, but 0 only differs from 1 in that it just turns off fan speed monitoring. The chip actually does have a way to turn off fan controls (and only monitor), but what that does is that it sets PWM to 0% duty cycle (which is the opposite to full-speed) AND it also turns off fan speed monitoring. Because of this, I implemented the 0 value by setting PWM mode to 100%. This method does come with a problem: it is impossible to differentiate between full-speed and PWM mode just from the values on the chip. The new code solves this by saving a value indicating whether we're in full-speed mode. This value is initialized to 0, so full-speed mode won't persist across reboots. These two changes are closely connected together, mainly because the detection of the pwm*_enable value depended on whether fan speed monitoring is enabled (which is now controlled as written in the first paragraph). Signed-off-by: Václav Kubernát --- Documentation/hwmon/max31790.rst | 8 ++- drivers/hwmon/max31790.c | 105 ++++++++++++++++++++++--------- 2 files changed, 82 insertions(+), 31 deletions(-) diff --git a/Documentation/hwmon/max31790.rst b/Documentation/hwmon/max31790.rst index f301385d8cef..8979c8a02cd1 100644 --- a/Documentation/hwmon/max31790.rst +++ b/Documentation/hwmon/max31790.rst @@ -34,10 +34,12 @@ also be configured to serve as tachometer inputs. Sysfs entries ------------- -================== === ======================================================= +================== === ============================================================= +fan[1-12]_enable RW enable fan speed monitoring fan[1-12]_input RO fan tachometer speed in RPM fan[1-12]_fault RO fan experienced fault fan[1-6]_target RW desired fan speed in RPM -pwm[1-6]_enable RW regulator mode, 0=disabled, 1=manual mode, 2=rpm mode +pwm[1-6]_enable RW regulator mode, 0=full speed, 1=manual (pwm) mode, 2=rpm mode + setting rpm mode sets fan*_enable to 1 pwm[1-6] RW fan target duty cycle (0-255) -================== === ======================================================= +================== === ============================================================= diff --git a/drivers/hwmon/max31790.c b/drivers/hwmon/max31790.c index 4e5add567890..d16b77472cc1 100644 --- a/drivers/hwmon/max31790.c +++ b/drivers/hwmon/max31790.c @@ -39,6 +39,7 @@ #define FAN_RPM_MIN 120 #define FAN_RPM_MAX 7864320 +#define MAX_PWM 0XFF80 #define RPM_FROM_REG(reg, sr) (((reg) >> 4) ? \ ((60 * (sr) * 8192) / ((reg) >> 4)) : \ @@ -88,6 +89,9 @@ static const struct regmap_config max31790_regmap_config = { */ struct max31790_data { struct regmap *regmap; + + struct mutex update_lock; /* for full_speed */ + bool full_speed[NR_CHANNEL]; }; static const u8 tach_period[8] = { 1, 2, 4, 8, 16, 32, 32, 32 }; @@ -157,7 +161,7 @@ static int max31790_read_fan(struct device *dev, u32 attr, int channel, { struct max31790_data *data = dev_get_drvdata(dev); struct regmap *regmap = data->regmap; - int rpm, dynamics, tach, fault; + int rpm, dynamics, tach, fault, cfg; if (IS_ERR(data)) return PTR_ERR(data); @@ -201,6 +205,13 @@ static int max31790_read_fan(struct device *dev, u32 attr, int channel, else *val = !!(fault & (1 << channel)); return 0; + case hwmon_fan_enable: + cfg = read_reg_byte(regmap, MAX31790_REG_FAN_CONFIG(channel)); + if (cfg < 0) + return cfg; + + *val = !!(cfg & MAX31790_FAN_CFG_TACH_INPUT_EN); + return 0; default: return -EOPNOTSUPP; } @@ -215,7 +226,7 @@ static int max31790_write_fan(struct device *dev, u32 attr, int channel, int err = 0; u8 bits; int sr; - int fan_dynamics; + int fan_dynamics, cfg; switch (attr) { case hwmon_fan_target: @@ -246,6 +257,14 @@ static int max31790_write_fan(struct device *dev, u32 attr, int channel, MAX31790_REG_TARGET_COUNT(channel), target_count); break; + case hwmon_fan_enable: + cfg = read_reg_byte(regmap, MAX31790_REG_FAN_CONFIG(channel)); + if (val == 0) + cfg &= ~MAX31790_FAN_CFG_TACH_INPUT_EN; + else + cfg |= MAX31790_FAN_CFG_TACH_INPUT_EN; + err = regmap_write(regmap, MAX31790_REG_FAN_CONFIG(channel), cfg); + break; default: err = -EOPNOTSUPP; break; @@ -275,6 +294,11 @@ static umode_t max31790_fan_is_visible(const void *_data, u32 attr, int channel) !(fan_config & MAX31790_FAN_CFG_TACH_INPUT)) return 0644; return 0; + case hwmon_fan_enable: + if (channel < NR_CHANNEL || + (fan_config & MAX31790_FAN_CFG_TACH_INPUT)) + return 0644; + return 0; default: return 0; } @@ -303,12 +327,14 @@ static int max31790_read_pwm(struct device *dev, u32 attr, int channel, if (read < 0) return read; - if (read & MAX31790_FAN_CFG_RPM_MODE) + mutex_lock(&data->update_lock); + if (data->full_speed[channel]) + *val = 0; + else if (read & MAX31790_FAN_CFG_RPM_MODE) *val = 2; - else if (read & MAX31790_FAN_CFG_TACH_INPUT_EN) + else *val = 1; - else - *val = 0; + mutex_unlock(&data->update_lock); return 0; default: return -EOPNOTSUPP; @@ -325,10 +351,13 @@ static int max31790_write_pwm(struct device *dev, u32 attr, int channel, switch (attr) { case hwmon_pwm_input: - if (val < 0 || val > 255) { + mutex_lock(&data->update_lock); + if (data->full_speed[channel] || val < 0 || val > 255) { err = -EINVAL; break; } + mutex_unlock(&data->update_lock); + err = write_reg_word(regmap, MAX31790_REG_PWMOUT(channel), val << 8); break; case hwmon_pwm_enable: @@ -337,20 +366,35 @@ static int max31790_write_pwm(struct device *dev, u32 attr, int channel, if (fan_config < 0) return fan_config; - if (val == 0) { - fan_config &= ~(MAX31790_FAN_CFG_TACH_INPUT_EN | - MAX31790_FAN_CFG_RPM_MODE); - } else if (val == 1) { - fan_config = (fan_config | - MAX31790_FAN_CFG_TACH_INPUT_EN) & - ~MAX31790_FAN_CFG_RPM_MODE; + if (val == 0 || val == 1) { + fan_config &= ~MAX31790_FAN_CFG_RPM_MODE; } else if (val == 2) { - fan_config |= MAX31790_FAN_CFG_TACH_INPUT_EN | - MAX31790_FAN_CFG_RPM_MODE; + fan_config |= MAX31790_FAN_CFG_RPM_MODE; } else { err = -EINVAL; break; } + + /* + * The chip sets PWM to zero when using its "monitor only" mode + * and 0 means full speed. + */ + mutex_lock(&data->update_lock); + if (val == 0) { + data->full_speed[channel] = true; + err = write_reg_word(regmap, MAX31790_REG_PWMOUT(channel), MAX_PWM); + } else { + data->full_speed[channel] = false; + } + mutex_unlock(&data->update_lock); + + /* + * RPM mode implies enabled TACH input, so enable it in RPM + * mode. + */ + if (val == 2) + fan_config |= MAX31790_FAN_CFG_TACH_INPUT_EN; + err = regmap_write(regmap, MAX31790_REG_FAN_CONFIG(channel), fan_config); @@ -425,18 +469,18 @@ static umode_t max31790_is_visible(const void *data, static const struct hwmon_channel_info *max31790_info[] = { HWMON_CHANNEL_INFO(fan, - HWMON_F_INPUT | HWMON_F_TARGET | HWMON_F_FAULT, - HWMON_F_INPUT | HWMON_F_TARGET | HWMON_F_FAULT, - HWMON_F_INPUT | HWMON_F_TARGET | HWMON_F_FAULT, - HWMON_F_INPUT | HWMON_F_TARGET | HWMON_F_FAULT, - HWMON_F_INPUT | HWMON_F_TARGET | HWMON_F_FAULT, - HWMON_F_INPUT | HWMON_F_TARGET | HWMON_F_FAULT, - HWMON_F_INPUT | HWMON_F_FAULT, - HWMON_F_INPUT | HWMON_F_FAULT, - HWMON_F_INPUT | HWMON_F_FAULT, - HWMON_F_INPUT | HWMON_F_FAULT, - HWMON_F_INPUT | HWMON_F_FAULT, - HWMON_F_INPUT | HWMON_F_FAULT), + HWMON_F_ENABLE | HWMON_F_INPUT | HWMON_F_TARGET | HWMON_F_FAULT, + HWMON_F_ENABLE | HWMON_F_INPUT | HWMON_F_TARGET | HWMON_F_FAULT, + HWMON_F_ENABLE | HWMON_F_INPUT | HWMON_F_TARGET | HWMON_F_FAULT, + HWMON_F_ENABLE | HWMON_F_INPUT | HWMON_F_TARGET | HWMON_F_FAULT, + HWMON_F_ENABLE | HWMON_F_INPUT | HWMON_F_TARGET | HWMON_F_FAULT, + HWMON_F_ENABLE | HWMON_F_INPUT | HWMON_F_TARGET | HWMON_F_FAULT, + HWMON_F_ENABLE | HWMON_F_INPUT | HWMON_F_FAULT, + HWMON_F_ENABLE | HWMON_F_INPUT | HWMON_F_FAULT, + HWMON_F_ENABLE | HWMON_F_INPUT | HWMON_F_FAULT, + HWMON_F_ENABLE | HWMON_F_INPUT | HWMON_F_FAULT, + HWMON_F_ENABLE | HWMON_F_INPUT | HWMON_F_FAULT, + HWMON_F_ENABLE | HWMON_F_INPUT | HWMON_F_FAULT), HWMON_CHANNEL_INFO(pwm, HWMON_PWM_INPUT | HWMON_PWM_ENABLE, HWMON_PWM_INPUT | HWMON_PWM_ENABLE, @@ -464,6 +508,7 @@ static int max31790_probe(struct i2c_client *client) struct device *dev = &client->dev; struct max31790_data *data; struct device *hwmon_dev; + int i; if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA)) @@ -473,6 +518,10 @@ static int max31790_probe(struct i2c_client *client) if (!data) return -ENOMEM; + mutex_init(&data->update_lock); + for (i = 0; i < NR_CHANNEL; i++) + data->full_speed[i] = false; + data->regmap = devm_regmap_init_i2c(client, &max31790_regmap_config); if (IS_ERR(data->regmap)) { From patchwork Tue Mar 16 17:55:00 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?b?VsOhY2xhdiBLdWJlcm7DoXQ=?= X-Patchwork-Id: 12143419 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-16.8 required=3.0 tests=BAYES_00, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED,USER_AGENT_GIT autolearn=unavailable autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 8D05EC433E9 for ; Tue, 16 Mar 2021 17:57:29 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 567CF65101 for ; Tue, 16 Mar 2021 17:57:29 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S239418AbhCPR5A (ORCPT ); Tue, 16 Mar 2021 13:57:00 -0400 Received: from mail-ed1-f50.google.com ([209.85.208.50]:33481 "EHLO mail-ed1-f50.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S239421AbhCPR4C (ORCPT ); Tue, 16 Mar 2021 13:56:02 -0400 Received: by mail-ed1-f50.google.com with SMTP id w18so22636640edc.0; Tue, 16 Mar 2021 10:56:01 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=dhzMvhiTeUNm1PtC49X5tx+hF0dpKCDPQdt6GK/mu68=; b=P3mT30tQgW4yJbZmSLDhH3SAF7KoykyysC+dbmKwHgSTU7saPQHZVvYMDK5GoVrAdN ve9jZg/pfCfc8CvWvaoq+MCVd1lpNQpbFhMNZo5Dcw0eJH6Rs0VXAVrCx2ZqspdNoPEv 0n/7WaBed9Kc9SmUnGboZ+dIZV/HXEhY6a+2QjRyD3Wb+2Yfc6YwQlYuXcz1230f2wrK EchGggjYcrHWHoT64ygMpiStJIz73/iEOXFWP3B8Sb4RnKRvZf8IG2+MKS38uDmIDHXW 5CC6Z8q3PTMxqg5pOLSuYFRu9rg4kdRgGDkCgvqUC7+ypffw+4PxEPoA6t4pjxa/N7fP HPYQ== X-Gm-Message-State: AOAM533KwmK7yxmMxXM0L36lfLaE4F7Z9W8AUXMik182BWOREAjDqAKN btkj7/Ejy+VX9TS++CrMgKjpQIGCRB3579xS X-Google-Smtp-Source: ABdhPJxXJOr1skPYOBW1yTHna0zlwFs5nnPutmIZWuhvhDZibqhXJ9lVIiYL7k059Wz5+4aH5KOpwA== X-Received: by 2002:a05:6402:35c8:: with SMTP id z8mr37488035edc.341.1615917360910; Tue, 16 Mar 2021 10:56:00 -0700 (PDT) Received: from localhost ([2a02:8308:387:c900:a7b5:b859:9449:c07b]) by smtp.gmail.com with ESMTPSA id h8sm5154982ede.25.2021.03.16.10.56.00 (version=TLS1_3 cipher=TLS_AES_128_GCM_SHA256 bits=128/128); Tue, 16 Mar 2021 10:56:00 -0700 (PDT) From: =?utf-8?b?VsOhY2xhdiBLdWJlcm7DoXQ=?= Cc: =?utf-8?b?VsOhY2xhdiBLdWJlcm7DoXQ=?= , Jean Delvare , Guenter Roeck , Jonathan Corbet , linux-hwmon@vger.kernel.org, linux-doc@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [PATCH v2 3/5] hwmon: (max31790) Show 0 RPM/fault when input disabled Date: Tue, 16 Mar 2021 18:55:00 +0100 Message-Id: <20210316175503.1003051-3-kubernat@cesnet.cz> X-Mailer: git-send-email 2.30.2 In-Reply-To: <20210316175503.1003051-1-kubernat@cesnet.cz> References: <20210316175503.1003051-1-kubernat@cesnet.cz> MIME-Version: 1.0 To: unlisted-recipients:; (no To-header on input) Precedence: bulk List-ID: X-Mailing-List: linux-hwmon@vger.kernel.org When fan speed input is disabled, it makes no sense to show values in fan*_input and fan*_fault. Signed-off-by: Václav Kubernát --- drivers/hwmon/max31790.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/drivers/hwmon/max31790.c b/drivers/hwmon/max31790.c index d16b77472cc1..7b47797db471 100644 --- a/drivers/hwmon/max31790.c +++ b/drivers/hwmon/max31790.c @@ -168,6 +168,13 @@ static int max31790_read_fan(struct device *dev, u32 attr, int channel, switch (attr) { case hwmon_fan_input: + cfg = read_reg_byte(regmap, MAX31790_REG_FAN_CONFIG(channel)); + if (cfg < 0) + return cfg; + + if (!(cfg & MAX31790_FAN_CFG_TACH_INPUT_EN)) + return -ENODATA; + dynamics = read_reg_byte(regmap, MAX31790_REG_FAN_DYNAMICS(channel)); if (dynamics < 0) return dynamics; @@ -192,6 +199,15 @@ static int max31790_read_fan(struct device *dev, u32 attr, int channel, *val = rpm; return 0; case hwmon_fan_fault: + cfg = read_reg_byte(regmap, MAX31790_REG_FAN_CONFIG(channel)); + if (cfg < 0) + return cfg; + + if (!(cfg & MAX31790_FAN_CFG_TACH_INPUT_EN)) { + *val = 0; + return 0; + } + if (channel > 6) fault = read_reg_byte(regmap, MAX31790_REG_FAN_FAULT_STATUS2); else From patchwork Tue Mar 16 17:55:01 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?b?VsOhY2xhdiBLdWJlcm7DoXQ=?= X-Patchwork-Id: 12143423 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-16.8 required=3.0 tests=BAYES_00, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED,USER_AGENT_GIT autolearn=unavailable autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 57BBFC43332 for ; Tue, 16 Mar 2021 17:57:31 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 3472565120 for ; Tue, 16 Mar 2021 17:57:31 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S239479AbhCPR5D (ORCPT ); Tue, 16 Mar 2021 13:57:03 -0400 Received: from mail-ej1-f42.google.com ([209.85.218.42]:41947 "EHLO mail-ej1-f42.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S239462AbhCPR4E (ORCPT ); Tue, 16 Mar 2021 13:56:04 -0400 Received: by mail-ej1-f42.google.com with SMTP id lr13so73713436ejb.8; Tue, 16 Mar 2021 10:56:03 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=3edIuyjq57ahTfo6TpK7NVyellwm078SD4itITOhAD8=; b=s6tTE+QYKRUkM6j8xl33XGvzsFZbgzxl9cDnDpQm1TGFeXTdqUIFpAFPtHZPvCjE11 pYAjv2sFR/iVWitjU2BPYMIh1eYabwmbGLY2yp2UO3/TOburC6ykX009Zz3qPXUqROeJ URP142sjcx+6hbSw6UkzJzL+1U+dRLJkkCNkqzMXWOE5n1kwFpbkU2aFY+pjF9XRLlFi wFo9ZsGZfUte1jA8Jr6lrFX5zgMtd+wz7P2+J88nLPVqQVYiYcmn7HJUMeL8rm77ezcz foEAU6h9/jOE3HEOtsJ911XEDJWHvR/Vbcrz5WI1VoymGQSRiTXY4+tFvMFYYsHY2YPs 087g== X-Gm-Message-State: AOAM533PCTyq66RC7II9f2jbO+62kRlZhoI/a92yS68NJzQaRsU67N2E MvVU6aevn+TJdTaBG9yUY9c= X-Google-Smtp-Source: ABdhPJw61/Q89NJaWXxCxEGc1bTkaFK4RxpWZJW72oFFH+I596OhbyQG+BTqvOg4HB2Qvge8CRxbHQ== X-Received: by 2002:a17:906:d8d3:: with SMTP id re19mr31266952ejb.440.1615917362966; Tue, 16 Mar 2021 10:56:02 -0700 (PDT) Received: from localhost ([2a02:8308:387:c900:a7b5:b859:9449:c07b]) by smtp.gmail.com with ESMTPSA id p9sm10538828eds.66.2021.03.16.10.56.02 (version=TLS1_3 cipher=TLS_AES_128_GCM_SHA256 bits=128/128); Tue, 16 Mar 2021 10:56:02 -0700 (PDT) From: =?utf-8?b?VsOhY2xhdiBLdWJlcm7DoXQ=?= Cc: =?utf-8?b?VsOhY2xhdiBLdWJlcm7DoXQ=?= , Jean Delvare , Guenter Roeck , Jonathan Corbet , linux-hwmon@vger.kernel.org, linux-doc@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [PATCH v2 4/5] hwmon: (max31790) Allow setting fan*_div Date: Tue, 16 Mar 2021 18:55:01 +0100 Message-Id: <20210316175503.1003051-4-kubernat@cesnet.cz> X-Mailer: git-send-email 2.30.2 In-Reply-To: <20210316175503.1003051-1-kubernat@cesnet.cz> References: <20210316175503.1003051-1-kubernat@cesnet.cz> MIME-Version: 1.0 To: unlisted-recipients:; (no To-header on input) Precedence: bulk List-ID: X-Mailing-List: linux-hwmon@vger.kernel.org Right now, the divisor (which determines the speed range) is only set when in RPM mode. However, the speed range also affects the input RPM, which means, to get more accurate readings, this speed range needs to be set. Signed-off-by: Václav Kubernát --- Documentation/hwmon/max31790.rst | 1 + drivers/hwmon/max31790.c | 79 +++++++++++++++++++++++++++----- 2 files changed, 68 insertions(+), 12 deletions(-) diff --git a/Documentation/hwmon/max31790.rst b/Documentation/hwmon/max31790.rst index 8979c8a02cd1..2979addeac8f 100644 --- a/Documentation/hwmon/max31790.rst +++ b/Documentation/hwmon/max31790.rst @@ -38,6 +38,7 @@ Sysfs entries fan[1-12]_enable RW enable fan speed monitoring fan[1-12]_input RO fan tachometer speed in RPM fan[1-12]_fault RO fan experienced fault +fan[1-12]_div RW set the measurable speed range, not available in RPM mode fan[1-6]_target RW desired fan speed in RPM pwm[1-6]_enable RW regulator mode, 0=full speed, 1=manual (pwm) mode, 2=rpm mode setting rpm mode sets fan*_enable to 1 diff --git a/drivers/hwmon/max31790.c b/drivers/hwmon/max31790.c index 7b47797db471..235a71bbff84 100644 --- a/drivers/hwmon/max31790.c +++ b/drivers/hwmon/max31790.c @@ -156,6 +156,26 @@ static int write_reg_word(struct regmap *regmap, u8 reg, u16 val) return regmap_bulk_write(regmap, reg, bulk_val, 2); } +static int bits_for_speed_range(long speed_range) +{ + switch (speed_range) { + case 1: + return 0x0; + case 2: + return 0x1; + case 4: + return 0x2; + case 8: + return 0x3; + case 16: + return 0x4; + case 32: + return 0x5; + default: + return -1; + } +} + static int max31790_read_fan(struct device *dev, u32 attr, int channel, long *val) { @@ -228,6 +248,13 @@ static int max31790_read_fan(struct device *dev, u32 attr, int channel, *val = !!(cfg & MAX31790_FAN_CFG_TACH_INPUT_EN); return 0; + case hwmon_fan_div: + cfg = read_reg_byte(regmap, MAX31790_REG_FAN_CONFIG(channel)); + if (cfg < 0) + return cfg; + + *val = get_tach_period(cfg); + return 0; default: return -EOPNOTSUPP; } @@ -281,6 +308,33 @@ static int max31790_write_fan(struct device *dev, u32 attr, int channel, cfg |= MAX31790_FAN_CFG_TACH_INPUT_EN; err = regmap_write(regmap, MAX31790_REG_FAN_CONFIG(channel), cfg); break; + case hwmon_fan_div: + cfg = read_reg_byte(regmap, MAX31790_REG_FAN_CONFIG(channel)); + if (cfg < 0) + return cfg; + + if (cfg & MAX31790_FAN_CFG_RPM_MODE) { + err = -EINVAL; + break; + } + sr = bits_for_speed_range(val); + if (sr < 0) { + err = -EINVAL; + break; + } + + fan_dynamics = read_reg_byte(regmap, MAX31790_REG_FAN_DYNAMICS(channel)); + + if (fan_dynamics < 0) + return fan_dynamics; + + fan_dynamics = ((fan_dynamics & + ~MAX31790_FAN_DYN_SR_MASK) | + (sr << MAX31790_FAN_DYN_SR_SHIFT)); + err = regmap_write(regmap, + MAX31790_REG_FAN_DYNAMICS(channel), + fan_dynamics); + break; default: err = -EOPNOTSUPP; break; @@ -311,6 +365,7 @@ static umode_t max31790_fan_is_visible(const void *_data, u32 attr, int channel) return 0644; return 0; case hwmon_fan_enable: + case hwmon_fan_div: if (channel < NR_CHANNEL || (fan_config & MAX31790_FAN_CFG_TACH_INPUT)) return 0644; @@ -485,18 +540,18 @@ static umode_t max31790_is_visible(const void *data, static const struct hwmon_channel_info *max31790_info[] = { HWMON_CHANNEL_INFO(fan, - HWMON_F_ENABLE | HWMON_F_INPUT | HWMON_F_TARGET | HWMON_F_FAULT, - HWMON_F_ENABLE | HWMON_F_INPUT | HWMON_F_TARGET | HWMON_F_FAULT, - HWMON_F_ENABLE | HWMON_F_INPUT | HWMON_F_TARGET | HWMON_F_FAULT, - HWMON_F_ENABLE | HWMON_F_INPUT | HWMON_F_TARGET | HWMON_F_FAULT, - HWMON_F_ENABLE | HWMON_F_INPUT | HWMON_F_TARGET | HWMON_F_FAULT, - HWMON_F_ENABLE | HWMON_F_INPUT | HWMON_F_TARGET | HWMON_F_FAULT, - HWMON_F_ENABLE | HWMON_F_INPUT | HWMON_F_FAULT, - HWMON_F_ENABLE | HWMON_F_INPUT | HWMON_F_FAULT, - HWMON_F_ENABLE | HWMON_F_INPUT | HWMON_F_FAULT, - HWMON_F_ENABLE | HWMON_F_INPUT | HWMON_F_FAULT, - HWMON_F_ENABLE | HWMON_F_INPUT | HWMON_F_FAULT, - HWMON_F_ENABLE | HWMON_F_INPUT | HWMON_F_FAULT), + HWMON_F_DIV | HWMON_F_ENABLE | HWMON_F_INPUT | HWMON_F_TARGET | HWMON_F_FAULT, + HWMON_F_DIV | HWMON_F_ENABLE | HWMON_F_INPUT | HWMON_F_TARGET | HWMON_F_FAULT, + HWMON_F_DIV | HWMON_F_ENABLE | HWMON_F_INPUT | HWMON_F_TARGET | HWMON_F_FAULT, + HWMON_F_DIV | HWMON_F_ENABLE | HWMON_F_INPUT | HWMON_F_TARGET | HWMON_F_FAULT, + HWMON_F_DIV | HWMON_F_ENABLE | HWMON_F_INPUT | HWMON_F_TARGET | HWMON_F_FAULT, + HWMON_F_DIV | HWMON_F_ENABLE | HWMON_F_INPUT | HWMON_F_TARGET | HWMON_F_FAULT, + HWMON_F_DIV | HWMON_F_ENABLE | HWMON_F_INPUT | HWMON_F_FAULT, + HWMON_F_DIV | HWMON_F_ENABLE | HWMON_F_INPUT | HWMON_F_FAULT, + HWMON_F_DIV | HWMON_F_ENABLE | HWMON_F_INPUT | HWMON_F_FAULT, + HWMON_F_DIV | HWMON_F_ENABLE | HWMON_F_INPUT | HWMON_F_FAULT, + HWMON_F_DIV | HWMON_F_ENABLE | HWMON_F_INPUT | HWMON_F_FAULT, + HWMON_F_DIV | HWMON_F_ENABLE | HWMON_F_INPUT | HWMON_F_FAULT), HWMON_CHANNEL_INFO(pwm, HWMON_PWM_INPUT | HWMON_PWM_ENABLE, HWMON_PWM_INPUT | HWMON_PWM_ENABLE, From patchwork Tue Mar 16 17:55:02 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?b?VsOhY2xhdiBLdWJlcm7DoXQ=?= X-Patchwork-Id: 12143421 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-16.8 required=3.0 tests=BAYES_00, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED,USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 305C9C4332B for ; Tue, 16 Mar 2021 17:57:31 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 08BC46512E for ; Tue, 16 Mar 2021 17:57:31 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S239485AbhCPR5E (ORCPT ); Tue, 16 Mar 2021 13:57:04 -0400 Received: from mail-ej1-f43.google.com ([209.85.218.43]:32912 "EHLO mail-ej1-f43.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S236097AbhCPR4G (ORCPT ); Tue, 16 Mar 2021 13:56:06 -0400 Received: by mail-ej1-f43.google.com with SMTP id jt13so73712640ejb.0; Tue, 16 Mar 2021 10:56:05 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=vY2V+uyPZYUFi1y4IUX19nPs6rR9J3Tb7jFOivds7Lw=; b=S8qm0QlU42Y1FFD7itHAI8uJ8bW9BJIy0KtVm0hl6sgJWqMHLG6AimqOrBFKczYSIg jRzQqU7enGZqAdJKaEsqat6TToVR81ZbqYQ4bsT50UsMZDMPJx3Xwy+Su44RdXONNXjw mPyolGBenIXWcm8TnZ26yIAEY4uIqfRsnRHlvGIKOgXncfDiFZPQ/uc2jYs3ezP/veeC Qno6M/G5HFHcV7lOQr96KAIw/YZb/oiGV+lhctiA7AaqDTuvcpJJ12oxACnFtexsY+Dz zOZAne+SKT+z8TECJhNP1Q3q6W49BAIQwAAt+okm0q8/+5zUBaYKn1YwmUKK/FpKkPNr o0lQ== X-Gm-Message-State: AOAM531FWDaFuWX/ppjI4oy6xbeW56qR0jecLf3A2qMO4ES7vbKgscrT IBWweVzO6zCarl2Ov+QFs2k= X-Google-Smtp-Source: ABdhPJyqpgQnFPJPRAW/6JN4+pTj+vJtCDYYBR2exl1eEWr35NhcruFJGLCH7m31sRtC49vNjGGB+g== X-Received: by 2002:a17:906:d71:: with SMTP id s17mr31847965ejh.126.1615917364950; Tue, 16 Mar 2021 10:56:04 -0700 (PDT) Received: from localhost ([2a02:8308:387:c900:a7b5:b859:9449:c07b]) by smtp.gmail.com with ESMTPSA id r19sm10912390edp.52.2021.03.16.10.56.04 (version=TLS1_3 cipher=TLS_AES_128_GCM_SHA256 bits=128/128); Tue, 16 Mar 2021 10:56:04 -0700 (PDT) From: =?utf-8?b?VsOhY2xhdiBLdWJlcm7DoXQ=?= Cc: =?utf-8?b?VsOhY2xhdiBLdWJlcm7DoXQ=?= , Jean Delvare , Guenter Roeck , Jonathan Corbet , linux-hwmon@vger.kernel.org, linux-doc@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [PATCH v2 5/5] hwmon: (max31790) Update documentation Date: Tue, 16 Mar 2021 18:55:02 +0100 Message-Id: <20210316175503.1003051-5-kubernat@cesnet.cz> X-Mailer: git-send-email 2.30.2 In-Reply-To: <20210316175503.1003051-1-kubernat@cesnet.cz> References: <20210316175503.1003051-1-kubernat@cesnet.cz> MIME-Version: 1.0 To: unlisted-recipients:; (no To-header on input) Precedence: bulk List-ID: X-Mailing-List: linux-hwmon@vger.kernel.org The conditions for fan fault and its connection to the PWM mode are now documented. The pwm_rate_of_change and fan_window are now mentioned. According to our testing with Sunon PF36281BX-000U-S99, these values are crucial in how RPM mode works and how long it takes for the RPM to stabilize. For example, setting 5000 RPM (the fan goes up to 23000), the pwm_rate_of_change needed to be changed to the lowest possible value, otherwise the chip would just go from pwm 0 to pwm 60 back and forth and never achieving 5000 RPM (and also signaling fan fault). Based on this testing, we found out that the pwm_rate_of_change and fan_window values need to be changed manually by the user, based on the user's exact fan configuration. Signed-off-by: Václav Kubernát --- Documentation/hwmon/max31790.rst | 41 +++++++++++++++++++++++++++++++- 1 file changed, 40 insertions(+), 1 deletion(-) diff --git a/Documentation/hwmon/max31790.rst b/Documentation/hwmon/max31790.rst index 2979addeac8f..6056b67c3a95 100644 --- a/Documentation/hwmon/max31790.rst +++ b/Documentation/hwmon/max31790.rst @@ -30,6 +30,44 @@ monitoring and control of fan RPM as well as detection of fan failure. Six pins are dedicated tachometer inputs. Any of the six PWM outputs can also be configured to serve as tachometer inputs. +About pwm[1-6]_enable +--------------------- +0 - full-speed + The chip doesn't have a specific way to set "full speed", so setting + pwm[1-6]_enable to 0 is just "set PWM mode with 255 duty cycle". +1 - PWM mode + Fan speed is controlled by writing a value to pwm[1-6]. +2 - RPM mode + Fan speed is controlled by writing a value to fan[1-6]_target. + +About fan[1-6]_fault +-------------------- +In PWM (or full-speed) mode, if the input RPM goes below what is set +in fan[1-6]_target, fan[1-6]_fault gets set to 1. In other words, +fan[1-6]_target works as the minimum input RPM before a fan fault goes off. + +In RPM mode, fan fault is set when the fan spins "too slowly" (exact +conditions are in the datasheet). RPM mode depends on four variables: + target_speed: This is set by fan[1-6]_target. + speed_range: This is set automatically when setting target_speed + or manually by fan[1-12]_div. + pwm_rate_of_change: NOT set by the driver. + fan_window: NOT set by the driver. + +The last two values are not set by the driver, because there's no generic way to +compute them. You should set them manually through i2c (in the bootloader for +example). Check the datasheet for details. + +The fan fault value latches, to reset it, set a value to pwm[1-6] +or fan[1-6]_target. + +About fan[1-12]_div +------------------- +This value affects the measurable range of the chip. The driver sets this value +automatically in RPM based on fan[1-6]_target. In PWM mode, you should set this +value manually based on the details from the datasheet. Setting the speed range +is disabled while in RPM mode to prevent overwriting the automatically +calculated value. Sysfs entries ------------- @@ -39,7 +77,8 @@ fan[1-12]_enable RW enable fan speed monitoring fan[1-12]_input RO fan tachometer speed in RPM fan[1-12]_fault RO fan experienced fault fan[1-12]_div RW set the measurable speed range, not available in RPM mode -fan[1-6]_target RW desired fan speed in RPM +fan[1-6]_target RW RPM mode = desired fan speed + PWM mode = minimum fan speed until fault pwm[1-6]_enable RW regulator mode, 0=full speed, 1=manual (pwm) mode, 2=rpm mode setting rpm mode sets fan*_enable to 1 pwm[1-6] RW fan target duty cycle (0-255)