18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * max31790.c - Part of lm_sensors, Linux kernel modules for hardware
48c2ecf20Sopenharmony_ci *             monitoring.
58c2ecf20Sopenharmony_ci *
68c2ecf20Sopenharmony_ci * (C) 2015 by Il Han <corone.il.han@gmail.com>
78c2ecf20Sopenharmony_ci */
88c2ecf20Sopenharmony_ci
98c2ecf20Sopenharmony_ci#include <linux/err.h>
108c2ecf20Sopenharmony_ci#include <linux/hwmon.h>
118c2ecf20Sopenharmony_ci#include <linux/i2c.h>
128c2ecf20Sopenharmony_ci#include <linux/init.h>
138c2ecf20Sopenharmony_ci#include <linux/jiffies.h>
148c2ecf20Sopenharmony_ci#include <linux/module.h>
158c2ecf20Sopenharmony_ci#include <linux/slab.h>
168c2ecf20Sopenharmony_ci
178c2ecf20Sopenharmony_ci/* MAX31790 registers */
188c2ecf20Sopenharmony_ci#define MAX31790_REG_GLOBAL_CONFIG	0x00
198c2ecf20Sopenharmony_ci#define MAX31790_REG_FAN_CONFIG(ch)	(0x02 + (ch))
208c2ecf20Sopenharmony_ci#define MAX31790_REG_FAN_DYNAMICS(ch)	(0x08 + (ch))
218c2ecf20Sopenharmony_ci#define MAX31790_REG_FAN_FAULT_STATUS2	0x10
228c2ecf20Sopenharmony_ci#define MAX31790_REG_FAN_FAULT_STATUS1	0x11
238c2ecf20Sopenharmony_ci#define MAX31790_REG_TACH_COUNT(ch)	(0x18 + (ch) * 2)
248c2ecf20Sopenharmony_ci#define MAX31790_REG_PWM_DUTY_CYCLE(ch)	(0x30 + (ch) * 2)
258c2ecf20Sopenharmony_ci#define MAX31790_REG_PWMOUT(ch)		(0x40 + (ch) * 2)
268c2ecf20Sopenharmony_ci#define MAX31790_REG_TARGET_COUNT(ch)	(0x50 + (ch) * 2)
278c2ecf20Sopenharmony_ci
288c2ecf20Sopenharmony_ci/* Fan Config register bits */
298c2ecf20Sopenharmony_ci#define MAX31790_FAN_CFG_RPM_MODE	0x80
308c2ecf20Sopenharmony_ci#define MAX31790_FAN_CFG_CTRL_MON	0x10
318c2ecf20Sopenharmony_ci#define MAX31790_FAN_CFG_TACH_INPUT_EN	0x08
328c2ecf20Sopenharmony_ci#define MAX31790_FAN_CFG_TACH_INPUT	0x01
338c2ecf20Sopenharmony_ci
348c2ecf20Sopenharmony_ci/* Fan Dynamics register bits */
358c2ecf20Sopenharmony_ci#define MAX31790_FAN_DYN_SR_SHIFT	5
368c2ecf20Sopenharmony_ci#define MAX31790_FAN_DYN_SR_MASK	0xE0
378c2ecf20Sopenharmony_ci#define SR_FROM_REG(reg)		(((reg) & MAX31790_FAN_DYN_SR_MASK) \
388c2ecf20Sopenharmony_ci					 >> MAX31790_FAN_DYN_SR_SHIFT)
398c2ecf20Sopenharmony_ci
408c2ecf20Sopenharmony_ci#define FAN_RPM_MIN			120
418c2ecf20Sopenharmony_ci#define FAN_RPM_MAX			7864320
428c2ecf20Sopenharmony_ci
438c2ecf20Sopenharmony_ci#define RPM_FROM_REG(reg, sr)		(((reg) >> 4) ? \
448c2ecf20Sopenharmony_ci					 ((60 * (sr) * 8192) / ((reg) >> 4)) : \
458c2ecf20Sopenharmony_ci					 FAN_RPM_MAX)
468c2ecf20Sopenharmony_ci#define RPM_TO_REG(rpm, sr)		((60 * (sr) * 8192) / ((rpm) * 2))
478c2ecf20Sopenharmony_ci
488c2ecf20Sopenharmony_ci#define NR_CHANNEL			6
498c2ecf20Sopenharmony_ci
508c2ecf20Sopenharmony_ci/*
518c2ecf20Sopenharmony_ci * Client data (each client gets its own)
528c2ecf20Sopenharmony_ci */
538c2ecf20Sopenharmony_cistruct max31790_data {
548c2ecf20Sopenharmony_ci	struct i2c_client *client;
558c2ecf20Sopenharmony_ci	struct mutex update_lock;
568c2ecf20Sopenharmony_ci	bool valid; /* zero until following fields are valid */
578c2ecf20Sopenharmony_ci	unsigned long last_updated; /* in jiffies */
588c2ecf20Sopenharmony_ci
598c2ecf20Sopenharmony_ci	/* register values */
608c2ecf20Sopenharmony_ci	u8 fan_config[NR_CHANNEL];
618c2ecf20Sopenharmony_ci	u8 fan_dynamics[NR_CHANNEL];
628c2ecf20Sopenharmony_ci	u16 fault_status;
638c2ecf20Sopenharmony_ci	u16 tach[NR_CHANNEL * 2];
648c2ecf20Sopenharmony_ci	u16 pwm[NR_CHANNEL];
658c2ecf20Sopenharmony_ci	u16 target_count[NR_CHANNEL];
668c2ecf20Sopenharmony_ci};
678c2ecf20Sopenharmony_ci
688c2ecf20Sopenharmony_cistatic struct max31790_data *max31790_update_device(struct device *dev)
698c2ecf20Sopenharmony_ci{
708c2ecf20Sopenharmony_ci	struct max31790_data *data = dev_get_drvdata(dev);
718c2ecf20Sopenharmony_ci	struct i2c_client *client = data->client;
728c2ecf20Sopenharmony_ci	struct max31790_data *ret = data;
738c2ecf20Sopenharmony_ci	int i;
748c2ecf20Sopenharmony_ci	int rv;
758c2ecf20Sopenharmony_ci
768c2ecf20Sopenharmony_ci	mutex_lock(&data->update_lock);
778c2ecf20Sopenharmony_ci
788c2ecf20Sopenharmony_ci	if (time_after(jiffies, data->last_updated + HZ) || !data->valid) {
798c2ecf20Sopenharmony_ci		rv = i2c_smbus_read_byte_data(client,
808c2ecf20Sopenharmony_ci				MAX31790_REG_FAN_FAULT_STATUS1);
818c2ecf20Sopenharmony_ci		if (rv < 0)
828c2ecf20Sopenharmony_ci			goto abort;
838c2ecf20Sopenharmony_ci		data->fault_status = rv & 0x3F;
848c2ecf20Sopenharmony_ci
858c2ecf20Sopenharmony_ci		rv = i2c_smbus_read_byte_data(client,
868c2ecf20Sopenharmony_ci				MAX31790_REG_FAN_FAULT_STATUS2);
878c2ecf20Sopenharmony_ci		if (rv < 0)
888c2ecf20Sopenharmony_ci			goto abort;
898c2ecf20Sopenharmony_ci		data->fault_status |= (rv & 0x3F) << 6;
908c2ecf20Sopenharmony_ci
918c2ecf20Sopenharmony_ci		for (i = 0; i < NR_CHANNEL; i++) {
928c2ecf20Sopenharmony_ci			rv = i2c_smbus_read_word_swapped(client,
938c2ecf20Sopenharmony_ci					MAX31790_REG_TACH_COUNT(i));
948c2ecf20Sopenharmony_ci			if (rv < 0)
958c2ecf20Sopenharmony_ci				goto abort;
968c2ecf20Sopenharmony_ci			data->tach[i] = rv;
978c2ecf20Sopenharmony_ci
988c2ecf20Sopenharmony_ci			if (data->fan_config[i]
998c2ecf20Sopenharmony_ci			    & MAX31790_FAN_CFG_TACH_INPUT) {
1008c2ecf20Sopenharmony_ci				rv = i2c_smbus_read_word_swapped(client,
1018c2ecf20Sopenharmony_ci					MAX31790_REG_TACH_COUNT(NR_CHANNEL
1028c2ecf20Sopenharmony_ci								+ i));
1038c2ecf20Sopenharmony_ci				if (rv < 0)
1048c2ecf20Sopenharmony_ci					goto abort;
1058c2ecf20Sopenharmony_ci				data->tach[NR_CHANNEL + i] = rv;
1068c2ecf20Sopenharmony_ci			} else {
1078c2ecf20Sopenharmony_ci				rv = i2c_smbus_read_word_swapped(client,
1088c2ecf20Sopenharmony_ci						MAX31790_REG_PWM_DUTY_CYCLE(i));
1098c2ecf20Sopenharmony_ci				if (rv < 0)
1108c2ecf20Sopenharmony_ci					goto abort;
1118c2ecf20Sopenharmony_ci				data->pwm[i] = rv;
1128c2ecf20Sopenharmony_ci
1138c2ecf20Sopenharmony_ci				rv = i2c_smbus_read_word_swapped(client,
1148c2ecf20Sopenharmony_ci						MAX31790_REG_TARGET_COUNT(i));
1158c2ecf20Sopenharmony_ci				if (rv < 0)
1168c2ecf20Sopenharmony_ci					goto abort;
1178c2ecf20Sopenharmony_ci				data->target_count[i] = rv;
1188c2ecf20Sopenharmony_ci			}
1198c2ecf20Sopenharmony_ci		}
1208c2ecf20Sopenharmony_ci
1218c2ecf20Sopenharmony_ci		data->last_updated = jiffies;
1228c2ecf20Sopenharmony_ci		data->valid = true;
1238c2ecf20Sopenharmony_ci	}
1248c2ecf20Sopenharmony_ci	goto done;
1258c2ecf20Sopenharmony_ci
1268c2ecf20Sopenharmony_ciabort:
1278c2ecf20Sopenharmony_ci	data->valid = false;
1288c2ecf20Sopenharmony_ci	ret = ERR_PTR(rv);
1298c2ecf20Sopenharmony_ci
1308c2ecf20Sopenharmony_cidone:
1318c2ecf20Sopenharmony_ci	mutex_unlock(&data->update_lock);
1328c2ecf20Sopenharmony_ci
1338c2ecf20Sopenharmony_ci	return ret;
1348c2ecf20Sopenharmony_ci}
1358c2ecf20Sopenharmony_ci
1368c2ecf20Sopenharmony_cistatic const u8 tach_period[8] = { 1, 2, 4, 8, 16, 32, 32, 32 };
1378c2ecf20Sopenharmony_ci
1388c2ecf20Sopenharmony_cistatic u8 get_tach_period(u8 fan_dynamics)
1398c2ecf20Sopenharmony_ci{
1408c2ecf20Sopenharmony_ci	return tach_period[SR_FROM_REG(fan_dynamics)];
1418c2ecf20Sopenharmony_ci}
1428c2ecf20Sopenharmony_ci
1438c2ecf20Sopenharmony_cistatic u8 bits_for_tach_period(int rpm)
1448c2ecf20Sopenharmony_ci{
1458c2ecf20Sopenharmony_ci	u8 bits;
1468c2ecf20Sopenharmony_ci
1478c2ecf20Sopenharmony_ci	if (rpm < 500)
1488c2ecf20Sopenharmony_ci		bits = 0x0;
1498c2ecf20Sopenharmony_ci	else if (rpm < 1000)
1508c2ecf20Sopenharmony_ci		bits = 0x1;
1518c2ecf20Sopenharmony_ci	else if (rpm < 2000)
1528c2ecf20Sopenharmony_ci		bits = 0x2;
1538c2ecf20Sopenharmony_ci	else if (rpm < 4000)
1548c2ecf20Sopenharmony_ci		bits = 0x3;
1558c2ecf20Sopenharmony_ci	else if (rpm < 8000)
1568c2ecf20Sopenharmony_ci		bits = 0x4;
1578c2ecf20Sopenharmony_ci	else
1588c2ecf20Sopenharmony_ci		bits = 0x5;
1598c2ecf20Sopenharmony_ci
1608c2ecf20Sopenharmony_ci	return bits;
1618c2ecf20Sopenharmony_ci}
1628c2ecf20Sopenharmony_ci
1638c2ecf20Sopenharmony_cistatic int max31790_read_fan(struct device *dev, u32 attr, int channel,
1648c2ecf20Sopenharmony_ci			     long *val)
1658c2ecf20Sopenharmony_ci{
1668c2ecf20Sopenharmony_ci	struct max31790_data *data = max31790_update_device(dev);
1678c2ecf20Sopenharmony_ci	int sr, rpm;
1688c2ecf20Sopenharmony_ci
1698c2ecf20Sopenharmony_ci	if (IS_ERR(data))
1708c2ecf20Sopenharmony_ci		return PTR_ERR(data);
1718c2ecf20Sopenharmony_ci
1728c2ecf20Sopenharmony_ci	switch (attr) {
1738c2ecf20Sopenharmony_ci	case hwmon_fan_input:
1748c2ecf20Sopenharmony_ci		sr = get_tach_period(data->fan_dynamics[channel % NR_CHANNEL]);
1758c2ecf20Sopenharmony_ci		rpm = RPM_FROM_REG(data->tach[channel], sr);
1768c2ecf20Sopenharmony_ci		*val = rpm;
1778c2ecf20Sopenharmony_ci		return 0;
1788c2ecf20Sopenharmony_ci	case hwmon_fan_target:
1798c2ecf20Sopenharmony_ci		sr = get_tach_period(data->fan_dynamics[channel]);
1808c2ecf20Sopenharmony_ci		rpm = RPM_FROM_REG(data->target_count[channel], sr);
1818c2ecf20Sopenharmony_ci		*val = rpm;
1828c2ecf20Sopenharmony_ci		return 0;
1838c2ecf20Sopenharmony_ci	case hwmon_fan_fault:
1848c2ecf20Sopenharmony_ci		*val = !!(data->fault_status & (1 << channel));
1858c2ecf20Sopenharmony_ci		return 0;
1868c2ecf20Sopenharmony_ci	default:
1878c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
1888c2ecf20Sopenharmony_ci	}
1898c2ecf20Sopenharmony_ci}
1908c2ecf20Sopenharmony_ci
1918c2ecf20Sopenharmony_cistatic int max31790_write_fan(struct device *dev, u32 attr, int channel,
1928c2ecf20Sopenharmony_ci			      long val)
1938c2ecf20Sopenharmony_ci{
1948c2ecf20Sopenharmony_ci	struct max31790_data *data = dev_get_drvdata(dev);
1958c2ecf20Sopenharmony_ci	struct i2c_client *client = data->client;
1968c2ecf20Sopenharmony_ci	int target_count;
1978c2ecf20Sopenharmony_ci	int err = 0;
1988c2ecf20Sopenharmony_ci	u8 bits;
1998c2ecf20Sopenharmony_ci	int sr;
2008c2ecf20Sopenharmony_ci
2018c2ecf20Sopenharmony_ci	mutex_lock(&data->update_lock);
2028c2ecf20Sopenharmony_ci
2038c2ecf20Sopenharmony_ci	switch (attr) {
2048c2ecf20Sopenharmony_ci	case hwmon_fan_target:
2058c2ecf20Sopenharmony_ci		val = clamp_val(val, FAN_RPM_MIN, FAN_RPM_MAX);
2068c2ecf20Sopenharmony_ci		bits = bits_for_tach_period(val);
2078c2ecf20Sopenharmony_ci		data->fan_dynamics[channel] =
2088c2ecf20Sopenharmony_ci			((data->fan_dynamics[channel] &
2098c2ecf20Sopenharmony_ci			  ~MAX31790_FAN_DYN_SR_MASK) |
2108c2ecf20Sopenharmony_ci			 (bits << MAX31790_FAN_DYN_SR_SHIFT));
2118c2ecf20Sopenharmony_ci		err = i2c_smbus_write_byte_data(client,
2128c2ecf20Sopenharmony_ci					MAX31790_REG_FAN_DYNAMICS(channel),
2138c2ecf20Sopenharmony_ci					data->fan_dynamics[channel]);
2148c2ecf20Sopenharmony_ci		if (err < 0)
2158c2ecf20Sopenharmony_ci			break;
2168c2ecf20Sopenharmony_ci
2178c2ecf20Sopenharmony_ci		sr = get_tach_period(data->fan_dynamics[channel]);
2188c2ecf20Sopenharmony_ci		target_count = RPM_TO_REG(val, sr);
2198c2ecf20Sopenharmony_ci		target_count = clamp_val(target_count, 0x1, 0x7FF);
2208c2ecf20Sopenharmony_ci
2218c2ecf20Sopenharmony_ci		data->target_count[channel] = target_count << 5;
2228c2ecf20Sopenharmony_ci
2238c2ecf20Sopenharmony_ci		err = i2c_smbus_write_word_swapped(client,
2248c2ecf20Sopenharmony_ci					MAX31790_REG_TARGET_COUNT(channel),
2258c2ecf20Sopenharmony_ci					data->target_count[channel]);
2268c2ecf20Sopenharmony_ci		break;
2278c2ecf20Sopenharmony_ci	default:
2288c2ecf20Sopenharmony_ci		err = -EOPNOTSUPP;
2298c2ecf20Sopenharmony_ci		break;
2308c2ecf20Sopenharmony_ci	}
2318c2ecf20Sopenharmony_ci
2328c2ecf20Sopenharmony_ci	mutex_unlock(&data->update_lock);
2338c2ecf20Sopenharmony_ci
2348c2ecf20Sopenharmony_ci	return err;
2358c2ecf20Sopenharmony_ci}
2368c2ecf20Sopenharmony_ci
2378c2ecf20Sopenharmony_cistatic umode_t max31790_fan_is_visible(const void *_data, u32 attr, int channel)
2388c2ecf20Sopenharmony_ci{
2398c2ecf20Sopenharmony_ci	const struct max31790_data *data = _data;
2408c2ecf20Sopenharmony_ci	u8 fan_config = data->fan_config[channel % NR_CHANNEL];
2418c2ecf20Sopenharmony_ci
2428c2ecf20Sopenharmony_ci	switch (attr) {
2438c2ecf20Sopenharmony_ci	case hwmon_fan_input:
2448c2ecf20Sopenharmony_ci	case hwmon_fan_fault:
2458c2ecf20Sopenharmony_ci		if (channel < NR_CHANNEL ||
2468c2ecf20Sopenharmony_ci		    (fan_config & MAX31790_FAN_CFG_TACH_INPUT))
2478c2ecf20Sopenharmony_ci			return 0444;
2488c2ecf20Sopenharmony_ci		return 0;
2498c2ecf20Sopenharmony_ci	case hwmon_fan_target:
2508c2ecf20Sopenharmony_ci		if (channel < NR_CHANNEL &&
2518c2ecf20Sopenharmony_ci		    !(fan_config & MAX31790_FAN_CFG_TACH_INPUT))
2528c2ecf20Sopenharmony_ci			return 0644;
2538c2ecf20Sopenharmony_ci		return 0;
2548c2ecf20Sopenharmony_ci	default:
2558c2ecf20Sopenharmony_ci		return 0;
2568c2ecf20Sopenharmony_ci	}
2578c2ecf20Sopenharmony_ci}
2588c2ecf20Sopenharmony_ci
2598c2ecf20Sopenharmony_cistatic int max31790_read_pwm(struct device *dev, u32 attr, int channel,
2608c2ecf20Sopenharmony_ci			     long *val)
2618c2ecf20Sopenharmony_ci{
2628c2ecf20Sopenharmony_ci	struct max31790_data *data = max31790_update_device(dev);
2638c2ecf20Sopenharmony_ci	u8 fan_config;
2648c2ecf20Sopenharmony_ci
2658c2ecf20Sopenharmony_ci	if (IS_ERR(data))
2668c2ecf20Sopenharmony_ci		return PTR_ERR(data);
2678c2ecf20Sopenharmony_ci
2688c2ecf20Sopenharmony_ci	fan_config = data->fan_config[channel];
2698c2ecf20Sopenharmony_ci
2708c2ecf20Sopenharmony_ci	switch (attr) {
2718c2ecf20Sopenharmony_ci	case hwmon_pwm_input:
2728c2ecf20Sopenharmony_ci		*val = data->pwm[channel] >> 8;
2738c2ecf20Sopenharmony_ci		return 0;
2748c2ecf20Sopenharmony_ci	case hwmon_pwm_enable:
2758c2ecf20Sopenharmony_ci		if (fan_config & MAX31790_FAN_CFG_CTRL_MON)
2768c2ecf20Sopenharmony_ci			*val = 0;
2778c2ecf20Sopenharmony_ci		else if (fan_config & MAX31790_FAN_CFG_RPM_MODE)
2788c2ecf20Sopenharmony_ci			*val = 2;
2798c2ecf20Sopenharmony_ci		else
2808c2ecf20Sopenharmony_ci			*val = 1;
2818c2ecf20Sopenharmony_ci		return 0;
2828c2ecf20Sopenharmony_ci	default:
2838c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
2848c2ecf20Sopenharmony_ci	}
2858c2ecf20Sopenharmony_ci}
2868c2ecf20Sopenharmony_ci
2878c2ecf20Sopenharmony_cistatic int max31790_write_pwm(struct device *dev, u32 attr, int channel,
2888c2ecf20Sopenharmony_ci			      long val)
2898c2ecf20Sopenharmony_ci{
2908c2ecf20Sopenharmony_ci	struct max31790_data *data = dev_get_drvdata(dev);
2918c2ecf20Sopenharmony_ci	struct i2c_client *client = data->client;
2928c2ecf20Sopenharmony_ci	u8 fan_config;
2938c2ecf20Sopenharmony_ci	int err = 0;
2948c2ecf20Sopenharmony_ci
2958c2ecf20Sopenharmony_ci	mutex_lock(&data->update_lock);
2968c2ecf20Sopenharmony_ci
2978c2ecf20Sopenharmony_ci	switch (attr) {
2988c2ecf20Sopenharmony_ci	case hwmon_pwm_input:
2998c2ecf20Sopenharmony_ci		if (val < 0 || val > 255) {
3008c2ecf20Sopenharmony_ci			err = -EINVAL;
3018c2ecf20Sopenharmony_ci			break;
3028c2ecf20Sopenharmony_ci		}
3038c2ecf20Sopenharmony_ci		data->valid = false;
3048c2ecf20Sopenharmony_ci		err = i2c_smbus_write_word_swapped(client,
3058c2ecf20Sopenharmony_ci						   MAX31790_REG_PWMOUT(channel),
3068c2ecf20Sopenharmony_ci						   val << 8);
3078c2ecf20Sopenharmony_ci		break;
3088c2ecf20Sopenharmony_ci	case hwmon_pwm_enable:
3098c2ecf20Sopenharmony_ci		fan_config = data->fan_config[channel];
3108c2ecf20Sopenharmony_ci		if (val == 0) {
3118c2ecf20Sopenharmony_ci			fan_config |= MAX31790_FAN_CFG_CTRL_MON;
3128c2ecf20Sopenharmony_ci			/*
3138c2ecf20Sopenharmony_ci			 * Disable RPM mode; otherwise disabling fan speed
3148c2ecf20Sopenharmony_ci			 * monitoring is not possible.
3158c2ecf20Sopenharmony_ci			 */
3168c2ecf20Sopenharmony_ci			fan_config &= ~MAX31790_FAN_CFG_RPM_MODE;
3178c2ecf20Sopenharmony_ci		} else if (val == 1) {
3188c2ecf20Sopenharmony_ci			fan_config &= ~(MAX31790_FAN_CFG_CTRL_MON | MAX31790_FAN_CFG_RPM_MODE);
3198c2ecf20Sopenharmony_ci		} else if (val == 2) {
3208c2ecf20Sopenharmony_ci			fan_config &= ~MAX31790_FAN_CFG_CTRL_MON;
3218c2ecf20Sopenharmony_ci			/*
3228c2ecf20Sopenharmony_ci			 * The chip sets MAX31790_FAN_CFG_TACH_INPUT_EN on its
3238c2ecf20Sopenharmony_ci			 * own if MAX31790_FAN_CFG_RPM_MODE is set.
3248c2ecf20Sopenharmony_ci			 * Do it here as well to reflect the actual register
3258c2ecf20Sopenharmony_ci			 * value in the cache.
3268c2ecf20Sopenharmony_ci			 */
3278c2ecf20Sopenharmony_ci			fan_config |= (MAX31790_FAN_CFG_RPM_MODE | MAX31790_FAN_CFG_TACH_INPUT_EN);
3288c2ecf20Sopenharmony_ci		} else {
3298c2ecf20Sopenharmony_ci			err = -EINVAL;
3308c2ecf20Sopenharmony_ci			break;
3318c2ecf20Sopenharmony_ci		}
3328c2ecf20Sopenharmony_ci		if (fan_config != data->fan_config[channel]) {
3338c2ecf20Sopenharmony_ci			err = i2c_smbus_write_byte_data(client, MAX31790_REG_FAN_CONFIG(channel),
3348c2ecf20Sopenharmony_ci							fan_config);
3358c2ecf20Sopenharmony_ci			if (!err)
3368c2ecf20Sopenharmony_ci				data->fan_config[channel] = fan_config;
3378c2ecf20Sopenharmony_ci		}
3388c2ecf20Sopenharmony_ci		break;
3398c2ecf20Sopenharmony_ci	default:
3408c2ecf20Sopenharmony_ci		err = -EOPNOTSUPP;
3418c2ecf20Sopenharmony_ci		break;
3428c2ecf20Sopenharmony_ci	}
3438c2ecf20Sopenharmony_ci
3448c2ecf20Sopenharmony_ci	mutex_unlock(&data->update_lock);
3458c2ecf20Sopenharmony_ci
3468c2ecf20Sopenharmony_ci	return err;
3478c2ecf20Sopenharmony_ci}
3488c2ecf20Sopenharmony_ci
3498c2ecf20Sopenharmony_cistatic umode_t max31790_pwm_is_visible(const void *_data, u32 attr, int channel)
3508c2ecf20Sopenharmony_ci{
3518c2ecf20Sopenharmony_ci	const struct max31790_data *data = _data;
3528c2ecf20Sopenharmony_ci	u8 fan_config = data->fan_config[channel];
3538c2ecf20Sopenharmony_ci
3548c2ecf20Sopenharmony_ci	switch (attr) {
3558c2ecf20Sopenharmony_ci	case hwmon_pwm_input:
3568c2ecf20Sopenharmony_ci	case hwmon_pwm_enable:
3578c2ecf20Sopenharmony_ci		if (!(fan_config & MAX31790_FAN_CFG_TACH_INPUT))
3588c2ecf20Sopenharmony_ci			return 0644;
3598c2ecf20Sopenharmony_ci		return 0;
3608c2ecf20Sopenharmony_ci	default:
3618c2ecf20Sopenharmony_ci		return 0;
3628c2ecf20Sopenharmony_ci	}
3638c2ecf20Sopenharmony_ci}
3648c2ecf20Sopenharmony_ci
3658c2ecf20Sopenharmony_cistatic int max31790_read(struct device *dev, enum hwmon_sensor_types type,
3668c2ecf20Sopenharmony_ci			 u32 attr, int channel, long *val)
3678c2ecf20Sopenharmony_ci{
3688c2ecf20Sopenharmony_ci	switch (type) {
3698c2ecf20Sopenharmony_ci	case hwmon_fan:
3708c2ecf20Sopenharmony_ci		return max31790_read_fan(dev, attr, channel, val);
3718c2ecf20Sopenharmony_ci	case hwmon_pwm:
3728c2ecf20Sopenharmony_ci		return max31790_read_pwm(dev, attr, channel, val);
3738c2ecf20Sopenharmony_ci	default:
3748c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
3758c2ecf20Sopenharmony_ci	}
3768c2ecf20Sopenharmony_ci}
3778c2ecf20Sopenharmony_ci
3788c2ecf20Sopenharmony_cistatic int max31790_write(struct device *dev, enum hwmon_sensor_types type,
3798c2ecf20Sopenharmony_ci			  u32 attr, int channel, long val)
3808c2ecf20Sopenharmony_ci{
3818c2ecf20Sopenharmony_ci	switch (type) {
3828c2ecf20Sopenharmony_ci	case hwmon_fan:
3838c2ecf20Sopenharmony_ci		return max31790_write_fan(dev, attr, channel, val);
3848c2ecf20Sopenharmony_ci	case hwmon_pwm:
3858c2ecf20Sopenharmony_ci		return max31790_write_pwm(dev, attr, channel, val);
3868c2ecf20Sopenharmony_ci	default:
3878c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
3888c2ecf20Sopenharmony_ci	}
3898c2ecf20Sopenharmony_ci}
3908c2ecf20Sopenharmony_ci
3918c2ecf20Sopenharmony_cistatic umode_t max31790_is_visible(const void *data,
3928c2ecf20Sopenharmony_ci				   enum hwmon_sensor_types type,
3938c2ecf20Sopenharmony_ci				   u32 attr, int channel)
3948c2ecf20Sopenharmony_ci{
3958c2ecf20Sopenharmony_ci	switch (type) {
3968c2ecf20Sopenharmony_ci	case hwmon_fan:
3978c2ecf20Sopenharmony_ci		return max31790_fan_is_visible(data, attr, channel);
3988c2ecf20Sopenharmony_ci	case hwmon_pwm:
3998c2ecf20Sopenharmony_ci		return max31790_pwm_is_visible(data, attr, channel);
4008c2ecf20Sopenharmony_ci	default:
4018c2ecf20Sopenharmony_ci		return 0;
4028c2ecf20Sopenharmony_ci	}
4038c2ecf20Sopenharmony_ci}
4048c2ecf20Sopenharmony_ci
4058c2ecf20Sopenharmony_cistatic const struct hwmon_channel_info *max31790_info[] = {
4068c2ecf20Sopenharmony_ci	HWMON_CHANNEL_INFO(fan,
4078c2ecf20Sopenharmony_ci			   HWMON_F_INPUT | HWMON_F_TARGET | HWMON_F_FAULT,
4088c2ecf20Sopenharmony_ci			   HWMON_F_INPUT | HWMON_F_TARGET | HWMON_F_FAULT,
4098c2ecf20Sopenharmony_ci			   HWMON_F_INPUT | HWMON_F_TARGET | HWMON_F_FAULT,
4108c2ecf20Sopenharmony_ci			   HWMON_F_INPUT | HWMON_F_TARGET | HWMON_F_FAULT,
4118c2ecf20Sopenharmony_ci			   HWMON_F_INPUT | HWMON_F_TARGET | HWMON_F_FAULT,
4128c2ecf20Sopenharmony_ci			   HWMON_F_INPUT | HWMON_F_TARGET | HWMON_F_FAULT,
4138c2ecf20Sopenharmony_ci			   HWMON_F_INPUT | HWMON_F_FAULT,
4148c2ecf20Sopenharmony_ci			   HWMON_F_INPUT | HWMON_F_FAULT,
4158c2ecf20Sopenharmony_ci			   HWMON_F_INPUT | HWMON_F_FAULT,
4168c2ecf20Sopenharmony_ci			   HWMON_F_INPUT | HWMON_F_FAULT,
4178c2ecf20Sopenharmony_ci			   HWMON_F_INPUT | HWMON_F_FAULT,
4188c2ecf20Sopenharmony_ci			   HWMON_F_INPUT | HWMON_F_FAULT),
4198c2ecf20Sopenharmony_ci	HWMON_CHANNEL_INFO(pwm,
4208c2ecf20Sopenharmony_ci			   HWMON_PWM_INPUT | HWMON_PWM_ENABLE,
4218c2ecf20Sopenharmony_ci			   HWMON_PWM_INPUT | HWMON_PWM_ENABLE,
4228c2ecf20Sopenharmony_ci			   HWMON_PWM_INPUT | HWMON_PWM_ENABLE,
4238c2ecf20Sopenharmony_ci			   HWMON_PWM_INPUT | HWMON_PWM_ENABLE,
4248c2ecf20Sopenharmony_ci			   HWMON_PWM_INPUT | HWMON_PWM_ENABLE,
4258c2ecf20Sopenharmony_ci			   HWMON_PWM_INPUT | HWMON_PWM_ENABLE),
4268c2ecf20Sopenharmony_ci	NULL
4278c2ecf20Sopenharmony_ci};
4288c2ecf20Sopenharmony_ci
4298c2ecf20Sopenharmony_cistatic const struct hwmon_ops max31790_hwmon_ops = {
4308c2ecf20Sopenharmony_ci	.is_visible = max31790_is_visible,
4318c2ecf20Sopenharmony_ci	.read = max31790_read,
4328c2ecf20Sopenharmony_ci	.write = max31790_write,
4338c2ecf20Sopenharmony_ci};
4348c2ecf20Sopenharmony_ci
4358c2ecf20Sopenharmony_cistatic const struct hwmon_chip_info max31790_chip_info = {
4368c2ecf20Sopenharmony_ci	.ops = &max31790_hwmon_ops,
4378c2ecf20Sopenharmony_ci	.info = max31790_info,
4388c2ecf20Sopenharmony_ci};
4398c2ecf20Sopenharmony_ci
4408c2ecf20Sopenharmony_cistatic int max31790_init_client(struct i2c_client *client,
4418c2ecf20Sopenharmony_ci				struct max31790_data *data)
4428c2ecf20Sopenharmony_ci{
4438c2ecf20Sopenharmony_ci	int i, rv;
4448c2ecf20Sopenharmony_ci
4458c2ecf20Sopenharmony_ci	for (i = 0; i < NR_CHANNEL; i++) {
4468c2ecf20Sopenharmony_ci		rv = i2c_smbus_read_byte_data(client,
4478c2ecf20Sopenharmony_ci				MAX31790_REG_FAN_CONFIG(i));
4488c2ecf20Sopenharmony_ci		if (rv < 0)
4498c2ecf20Sopenharmony_ci			return rv;
4508c2ecf20Sopenharmony_ci		data->fan_config[i] = rv;
4518c2ecf20Sopenharmony_ci
4528c2ecf20Sopenharmony_ci		rv = i2c_smbus_read_byte_data(client,
4538c2ecf20Sopenharmony_ci				MAX31790_REG_FAN_DYNAMICS(i));
4548c2ecf20Sopenharmony_ci		if (rv < 0)
4558c2ecf20Sopenharmony_ci			return rv;
4568c2ecf20Sopenharmony_ci		data->fan_dynamics[i] = rv;
4578c2ecf20Sopenharmony_ci	}
4588c2ecf20Sopenharmony_ci
4598c2ecf20Sopenharmony_ci	return 0;
4608c2ecf20Sopenharmony_ci}
4618c2ecf20Sopenharmony_ci
4628c2ecf20Sopenharmony_cistatic int max31790_probe(struct i2c_client *client)
4638c2ecf20Sopenharmony_ci{
4648c2ecf20Sopenharmony_ci	struct i2c_adapter *adapter = client->adapter;
4658c2ecf20Sopenharmony_ci	struct device *dev = &client->dev;
4668c2ecf20Sopenharmony_ci	struct max31790_data *data;
4678c2ecf20Sopenharmony_ci	struct device *hwmon_dev;
4688c2ecf20Sopenharmony_ci	int err;
4698c2ecf20Sopenharmony_ci
4708c2ecf20Sopenharmony_ci	if (!i2c_check_functionality(adapter,
4718c2ecf20Sopenharmony_ci			I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA))
4728c2ecf20Sopenharmony_ci		return -ENODEV;
4738c2ecf20Sopenharmony_ci
4748c2ecf20Sopenharmony_ci	data = devm_kzalloc(dev, sizeof(struct max31790_data), GFP_KERNEL);
4758c2ecf20Sopenharmony_ci	if (!data)
4768c2ecf20Sopenharmony_ci		return -ENOMEM;
4778c2ecf20Sopenharmony_ci
4788c2ecf20Sopenharmony_ci	data->client = client;
4798c2ecf20Sopenharmony_ci	mutex_init(&data->update_lock);
4808c2ecf20Sopenharmony_ci
4818c2ecf20Sopenharmony_ci	/*
4828c2ecf20Sopenharmony_ci	 * Initialize the max31790 chip
4838c2ecf20Sopenharmony_ci	 */
4848c2ecf20Sopenharmony_ci	err = max31790_init_client(client, data);
4858c2ecf20Sopenharmony_ci	if (err)
4868c2ecf20Sopenharmony_ci		return err;
4878c2ecf20Sopenharmony_ci
4888c2ecf20Sopenharmony_ci	hwmon_dev = devm_hwmon_device_register_with_info(dev, client->name,
4898c2ecf20Sopenharmony_ci							 data,
4908c2ecf20Sopenharmony_ci							 &max31790_chip_info,
4918c2ecf20Sopenharmony_ci							 NULL);
4928c2ecf20Sopenharmony_ci
4938c2ecf20Sopenharmony_ci	return PTR_ERR_OR_ZERO(hwmon_dev);
4948c2ecf20Sopenharmony_ci}
4958c2ecf20Sopenharmony_ci
4968c2ecf20Sopenharmony_cistatic const struct i2c_device_id max31790_id[] = {
4978c2ecf20Sopenharmony_ci	{ "max31790", 0 },
4988c2ecf20Sopenharmony_ci	{ }
4998c2ecf20Sopenharmony_ci};
5008c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(i2c, max31790_id);
5018c2ecf20Sopenharmony_ci
5028c2ecf20Sopenharmony_cistatic struct i2c_driver max31790_driver = {
5038c2ecf20Sopenharmony_ci	.class		= I2C_CLASS_HWMON,
5048c2ecf20Sopenharmony_ci	.probe_new	= max31790_probe,
5058c2ecf20Sopenharmony_ci	.driver = {
5068c2ecf20Sopenharmony_ci		.name	= "max31790",
5078c2ecf20Sopenharmony_ci	},
5088c2ecf20Sopenharmony_ci	.id_table	= max31790_id,
5098c2ecf20Sopenharmony_ci};
5108c2ecf20Sopenharmony_ci
5118c2ecf20Sopenharmony_cimodule_i2c_driver(max31790_driver);
5128c2ecf20Sopenharmony_ci
5138c2ecf20Sopenharmony_ciMODULE_AUTHOR("Il Han <corone.il.han@gmail.com>");
5148c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("MAX31790 sensor driver");
5158c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL");
516