18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * f75375s.c - driver for the Fintek F75375/SP, F75373 and
48c2ecf20Sopenharmony_ci *             F75387SG/RG hardware monitoring features
58c2ecf20Sopenharmony_ci * Copyright (C) 2006-2007  Riku Voipio
68c2ecf20Sopenharmony_ci *
78c2ecf20Sopenharmony_ci * Datasheets available at:
88c2ecf20Sopenharmony_ci *
98c2ecf20Sopenharmony_ci * f75375:
108c2ecf20Sopenharmony_ci * http://www.fintek.com.tw/files/productfiles/F75375_V026P.pdf
118c2ecf20Sopenharmony_ci *
128c2ecf20Sopenharmony_ci * f75373:
138c2ecf20Sopenharmony_ci * http://www.fintek.com.tw/files/productfiles/F75373_V025P.pdf
148c2ecf20Sopenharmony_ci *
158c2ecf20Sopenharmony_ci * f75387:
168c2ecf20Sopenharmony_ci * http://www.fintek.com.tw/files/productfiles/F75387_V027P.pdf
178c2ecf20Sopenharmony_ci */
188c2ecf20Sopenharmony_ci
198c2ecf20Sopenharmony_ci#include <linux/module.h>
208c2ecf20Sopenharmony_ci#include <linux/jiffies.h>
218c2ecf20Sopenharmony_ci#include <linux/hwmon.h>
228c2ecf20Sopenharmony_ci#include <linux/hwmon-sysfs.h>
238c2ecf20Sopenharmony_ci#include <linux/i2c.h>
248c2ecf20Sopenharmony_ci#include <linux/err.h>
258c2ecf20Sopenharmony_ci#include <linux/mutex.h>
268c2ecf20Sopenharmony_ci#include <linux/f75375s.h>
278c2ecf20Sopenharmony_ci#include <linux/slab.h>
288c2ecf20Sopenharmony_ci
298c2ecf20Sopenharmony_ci/* Addresses to scan */
308c2ecf20Sopenharmony_cistatic const unsigned short normal_i2c[] = { 0x2d, 0x2e, I2C_CLIENT_END };
318c2ecf20Sopenharmony_ci
328c2ecf20Sopenharmony_cienum chips { f75373, f75375, f75387 };
338c2ecf20Sopenharmony_ci
348c2ecf20Sopenharmony_ci/* Fintek F75375 registers  */
358c2ecf20Sopenharmony_ci#define F75375_REG_CONFIG0		0x0
368c2ecf20Sopenharmony_ci#define F75375_REG_CONFIG1		0x1
378c2ecf20Sopenharmony_ci#define F75375_REG_CONFIG2		0x2
388c2ecf20Sopenharmony_ci#define F75375_REG_CONFIG3		0x3
398c2ecf20Sopenharmony_ci#define F75375_REG_ADDR			0x4
408c2ecf20Sopenharmony_ci#define F75375_REG_INTR			0x31
418c2ecf20Sopenharmony_ci#define F75375_CHIP_ID			0x5A
428c2ecf20Sopenharmony_ci#define F75375_REG_VERSION		0x5C
438c2ecf20Sopenharmony_ci#define F75375_REG_VENDOR		0x5D
448c2ecf20Sopenharmony_ci#define F75375_REG_FAN_TIMER		0x60
458c2ecf20Sopenharmony_ci
468c2ecf20Sopenharmony_ci#define F75375_REG_VOLT(nr)		(0x10 + (nr))
478c2ecf20Sopenharmony_ci#define F75375_REG_VOLT_HIGH(nr)	(0x20 + (nr) * 2)
488c2ecf20Sopenharmony_ci#define F75375_REG_VOLT_LOW(nr)		(0x21 + (nr) * 2)
498c2ecf20Sopenharmony_ci
508c2ecf20Sopenharmony_ci#define F75375_REG_TEMP(nr)		(0x14 + (nr))
518c2ecf20Sopenharmony_ci#define F75387_REG_TEMP11_LSB(nr)	(0x1a + (nr))
528c2ecf20Sopenharmony_ci#define F75375_REG_TEMP_HIGH(nr)	(0x28 + (nr) * 2)
538c2ecf20Sopenharmony_ci#define F75375_REG_TEMP_HYST(nr)	(0x29 + (nr) * 2)
548c2ecf20Sopenharmony_ci
558c2ecf20Sopenharmony_ci#define F75375_REG_FAN(nr)		(0x16 + (nr) * 2)
568c2ecf20Sopenharmony_ci#define F75375_REG_FAN_MIN(nr)		(0x2C + (nr) * 2)
578c2ecf20Sopenharmony_ci#define F75375_REG_FAN_FULL(nr)		(0x70 + (nr) * 0x10)
588c2ecf20Sopenharmony_ci#define F75375_REG_FAN_PWM_DUTY(nr)	(0x76 + (nr) * 0x10)
598c2ecf20Sopenharmony_ci#define F75375_REG_FAN_PWM_CLOCK(nr)	(0x7D + (nr) * 0x10)
608c2ecf20Sopenharmony_ci
618c2ecf20Sopenharmony_ci#define F75375_REG_FAN_EXP(nr)		(0x74 + (nr) * 0x10)
628c2ecf20Sopenharmony_ci#define F75375_REG_FAN_B_TEMP(nr, step)	((0xA0 + (nr) * 0x10) + (step))
638c2ecf20Sopenharmony_ci#define F75375_REG_FAN_B_SPEED(nr, step) \
648c2ecf20Sopenharmony_ci	((0xA5 + (nr) * 0x10) + (step) * 2)
658c2ecf20Sopenharmony_ci
668c2ecf20Sopenharmony_ci#define F75375_REG_PWM1_RAISE_DUTY	0x69
678c2ecf20Sopenharmony_ci#define F75375_REG_PWM2_RAISE_DUTY	0x6A
688c2ecf20Sopenharmony_ci#define F75375_REG_PWM1_DROP_DUTY	0x6B
698c2ecf20Sopenharmony_ci#define F75375_REG_PWM2_DROP_DUTY	0x6C
708c2ecf20Sopenharmony_ci
718c2ecf20Sopenharmony_ci#define F75375_FAN_CTRL_LINEAR(nr)	(4 + nr)
728c2ecf20Sopenharmony_ci#define F75387_FAN_CTRL_LINEAR(nr)	(1 + ((nr) * 4))
738c2ecf20Sopenharmony_ci#define FAN_CTRL_MODE(nr)		(4 + ((nr) * 2))
748c2ecf20Sopenharmony_ci#define F75387_FAN_DUTY_MODE(nr)	(2 + ((nr) * 4))
758c2ecf20Sopenharmony_ci#define F75387_FAN_MANU_MODE(nr)	((nr) * 4)
768c2ecf20Sopenharmony_ci
778c2ecf20Sopenharmony_ci/*
788c2ecf20Sopenharmony_ci * Data structures and manipulation thereof
798c2ecf20Sopenharmony_ci */
808c2ecf20Sopenharmony_ci
818c2ecf20Sopenharmony_cistruct f75375_data {
828c2ecf20Sopenharmony_ci	unsigned short addr;
838c2ecf20Sopenharmony_ci	struct device *hwmon_dev;
848c2ecf20Sopenharmony_ci
858c2ecf20Sopenharmony_ci	const char *name;
868c2ecf20Sopenharmony_ci	int kind;
878c2ecf20Sopenharmony_ci	struct mutex update_lock; /* protect register access */
888c2ecf20Sopenharmony_ci	char valid;
898c2ecf20Sopenharmony_ci	unsigned long last_updated;	/* In jiffies */
908c2ecf20Sopenharmony_ci	unsigned long last_limits;	/* In jiffies */
918c2ecf20Sopenharmony_ci
928c2ecf20Sopenharmony_ci	/* Register values */
938c2ecf20Sopenharmony_ci	u8 in[4];
948c2ecf20Sopenharmony_ci	u8 in_max[4];
958c2ecf20Sopenharmony_ci	u8 in_min[4];
968c2ecf20Sopenharmony_ci	u16 fan[2];
978c2ecf20Sopenharmony_ci	u16 fan_min[2];
988c2ecf20Sopenharmony_ci	u16 fan_max[2];
998c2ecf20Sopenharmony_ci	u16 fan_target[2];
1008c2ecf20Sopenharmony_ci	u8 fan_timer;
1018c2ecf20Sopenharmony_ci	u8 pwm[2];
1028c2ecf20Sopenharmony_ci	u8 pwm_mode[2];
1038c2ecf20Sopenharmony_ci	u8 pwm_enable[2];
1048c2ecf20Sopenharmony_ci	/*
1058c2ecf20Sopenharmony_ci	 * f75387: For remote temperature reading, it uses signed 11-bit
1068c2ecf20Sopenharmony_ci	 * values with LSB = 0.125 degree Celsius, left-justified in 16-bit
1078c2ecf20Sopenharmony_ci	 * registers. For original 8-bit temp readings, the LSB just is 0.
1088c2ecf20Sopenharmony_ci	 */
1098c2ecf20Sopenharmony_ci	s16 temp11[2];
1108c2ecf20Sopenharmony_ci	s8 temp_high[2];
1118c2ecf20Sopenharmony_ci	s8 temp_max_hyst[2];
1128c2ecf20Sopenharmony_ci};
1138c2ecf20Sopenharmony_ci
1148c2ecf20Sopenharmony_cistatic int f75375_detect(struct i2c_client *client,
1158c2ecf20Sopenharmony_ci			 struct i2c_board_info *info);
1168c2ecf20Sopenharmony_cistatic int f75375_probe(struct i2c_client *client);
1178c2ecf20Sopenharmony_cistatic int f75375_remove(struct i2c_client *client);
1188c2ecf20Sopenharmony_ci
1198c2ecf20Sopenharmony_cistatic const struct i2c_device_id f75375_id[] = {
1208c2ecf20Sopenharmony_ci	{ "f75373", f75373 },
1218c2ecf20Sopenharmony_ci	{ "f75375", f75375 },
1228c2ecf20Sopenharmony_ci	{ "f75387", f75387 },
1238c2ecf20Sopenharmony_ci	{ }
1248c2ecf20Sopenharmony_ci};
1258c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(i2c, f75375_id);
1268c2ecf20Sopenharmony_ci
1278c2ecf20Sopenharmony_cistatic struct i2c_driver f75375_driver = {
1288c2ecf20Sopenharmony_ci	.class = I2C_CLASS_HWMON,
1298c2ecf20Sopenharmony_ci	.driver = {
1308c2ecf20Sopenharmony_ci		.name = "f75375",
1318c2ecf20Sopenharmony_ci	},
1328c2ecf20Sopenharmony_ci	.probe_new = f75375_probe,
1338c2ecf20Sopenharmony_ci	.remove = f75375_remove,
1348c2ecf20Sopenharmony_ci	.id_table = f75375_id,
1358c2ecf20Sopenharmony_ci	.detect = f75375_detect,
1368c2ecf20Sopenharmony_ci	.address_list = normal_i2c,
1378c2ecf20Sopenharmony_ci};
1388c2ecf20Sopenharmony_ci
1398c2ecf20Sopenharmony_cistatic inline int f75375_read8(struct i2c_client *client, u8 reg)
1408c2ecf20Sopenharmony_ci{
1418c2ecf20Sopenharmony_ci	return i2c_smbus_read_byte_data(client, reg);
1428c2ecf20Sopenharmony_ci}
1438c2ecf20Sopenharmony_ci
1448c2ecf20Sopenharmony_ci/* in most cases, should be called while holding update_lock */
1458c2ecf20Sopenharmony_cistatic inline u16 f75375_read16(struct i2c_client *client, u8 reg)
1468c2ecf20Sopenharmony_ci{
1478c2ecf20Sopenharmony_ci	return (i2c_smbus_read_byte_data(client, reg) << 8)
1488c2ecf20Sopenharmony_ci		| i2c_smbus_read_byte_data(client, reg + 1);
1498c2ecf20Sopenharmony_ci}
1508c2ecf20Sopenharmony_ci
1518c2ecf20Sopenharmony_cistatic inline void f75375_write8(struct i2c_client *client, u8 reg,
1528c2ecf20Sopenharmony_ci		u8 value)
1538c2ecf20Sopenharmony_ci{
1548c2ecf20Sopenharmony_ci	i2c_smbus_write_byte_data(client, reg, value);
1558c2ecf20Sopenharmony_ci}
1568c2ecf20Sopenharmony_ci
1578c2ecf20Sopenharmony_cistatic inline void f75375_write16(struct i2c_client *client, u8 reg,
1588c2ecf20Sopenharmony_ci		u16 value)
1598c2ecf20Sopenharmony_ci{
1608c2ecf20Sopenharmony_ci	int err = i2c_smbus_write_byte_data(client, reg, (value >> 8));
1618c2ecf20Sopenharmony_ci	if (err)
1628c2ecf20Sopenharmony_ci		return;
1638c2ecf20Sopenharmony_ci	i2c_smbus_write_byte_data(client, reg + 1, (value & 0xFF));
1648c2ecf20Sopenharmony_ci}
1658c2ecf20Sopenharmony_ci
1668c2ecf20Sopenharmony_cistatic void f75375_write_pwm(struct i2c_client *client, int nr)
1678c2ecf20Sopenharmony_ci{
1688c2ecf20Sopenharmony_ci	struct f75375_data *data = i2c_get_clientdata(client);
1698c2ecf20Sopenharmony_ci	if (data->kind == f75387)
1708c2ecf20Sopenharmony_ci		f75375_write16(client, F75375_REG_FAN_EXP(nr), data->pwm[nr]);
1718c2ecf20Sopenharmony_ci	else
1728c2ecf20Sopenharmony_ci		f75375_write8(client, F75375_REG_FAN_PWM_DUTY(nr),
1738c2ecf20Sopenharmony_ci			      data->pwm[nr]);
1748c2ecf20Sopenharmony_ci}
1758c2ecf20Sopenharmony_ci
1768c2ecf20Sopenharmony_cistatic struct f75375_data *f75375_update_device(struct device *dev)
1778c2ecf20Sopenharmony_ci{
1788c2ecf20Sopenharmony_ci	struct i2c_client *client = to_i2c_client(dev);
1798c2ecf20Sopenharmony_ci	struct f75375_data *data = i2c_get_clientdata(client);
1808c2ecf20Sopenharmony_ci	int nr;
1818c2ecf20Sopenharmony_ci
1828c2ecf20Sopenharmony_ci	mutex_lock(&data->update_lock);
1838c2ecf20Sopenharmony_ci
1848c2ecf20Sopenharmony_ci	/* Limit registers cache is refreshed after 60 seconds */
1858c2ecf20Sopenharmony_ci	if (time_after(jiffies, data->last_limits + 60 * HZ)
1868c2ecf20Sopenharmony_ci		|| !data->valid) {
1878c2ecf20Sopenharmony_ci		for (nr = 0; nr < 2; nr++) {
1888c2ecf20Sopenharmony_ci			data->temp_high[nr] =
1898c2ecf20Sopenharmony_ci				f75375_read8(client, F75375_REG_TEMP_HIGH(nr));
1908c2ecf20Sopenharmony_ci			data->temp_max_hyst[nr] =
1918c2ecf20Sopenharmony_ci				f75375_read8(client, F75375_REG_TEMP_HYST(nr));
1928c2ecf20Sopenharmony_ci			data->fan_max[nr] =
1938c2ecf20Sopenharmony_ci				f75375_read16(client, F75375_REG_FAN_FULL(nr));
1948c2ecf20Sopenharmony_ci			data->fan_min[nr] =
1958c2ecf20Sopenharmony_ci				f75375_read16(client, F75375_REG_FAN_MIN(nr));
1968c2ecf20Sopenharmony_ci			data->fan_target[nr] =
1978c2ecf20Sopenharmony_ci				f75375_read16(client, F75375_REG_FAN_EXP(nr));
1988c2ecf20Sopenharmony_ci		}
1998c2ecf20Sopenharmony_ci		for (nr = 0; nr < 4; nr++) {
2008c2ecf20Sopenharmony_ci			data->in_max[nr] =
2018c2ecf20Sopenharmony_ci				f75375_read8(client, F75375_REG_VOLT_HIGH(nr));
2028c2ecf20Sopenharmony_ci			data->in_min[nr] =
2038c2ecf20Sopenharmony_ci				f75375_read8(client, F75375_REG_VOLT_LOW(nr));
2048c2ecf20Sopenharmony_ci		}
2058c2ecf20Sopenharmony_ci		data->fan_timer = f75375_read8(client, F75375_REG_FAN_TIMER);
2068c2ecf20Sopenharmony_ci		data->last_limits = jiffies;
2078c2ecf20Sopenharmony_ci	}
2088c2ecf20Sopenharmony_ci
2098c2ecf20Sopenharmony_ci	/* Measurement registers cache is refreshed after 2 second */
2108c2ecf20Sopenharmony_ci	if (time_after(jiffies, data->last_updated + 2 * HZ)
2118c2ecf20Sopenharmony_ci		|| !data->valid) {
2128c2ecf20Sopenharmony_ci		for (nr = 0; nr < 2; nr++) {
2138c2ecf20Sopenharmony_ci			data->pwm[nr] =	f75375_read8(client,
2148c2ecf20Sopenharmony_ci				F75375_REG_FAN_PWM_DUTY(nr));
2158c2ecf20Sopenharmony_ci			/* assign MSB, therefore shift it by 8 bits */
2168c2ecf20Sopenharmony_ci			data->temp11[nr] =
2178c2ecf20Sopenharmony_ci				f75375_read8(client, F75375_REG_TEMP(nr)) << 8;
2188c2ecf20Sopenharmony_ci			if (data->kind == f75387)
2198c2ecf20Sopenharmony_ci				/* merge F75387's temperature LSB (11-bit) */
2208c2ecf20Sopenharmony_ci				data->temp11[nr] |=
2218c2ecf20Sopenharmony_ci					f75375_read8(client,
2228c2ecf20Sopenharmony_ci						     F75387_REG_TEMP11_LSB(nr));
2238c2ecf20Sopenharmony_ci			data->fan[nr] =
2248c2ecf20Sopenharmony_ci				f75375_read16(client, F75375_REG_FAN(nr));
2258c2ecf20Sopenharmony_ci		}
2268c2ecf20Sopenharmony_ci		for (nr = 0; nr < 4; nr++)
2278c2ecf20Sopenharmony_ci			data->in[nr] =
2288c2ecf20Sopenharmony_ci				f75375_read8(client, F75375_REG_VOLT(nr));
2298c2ecf20Sopenharmony_ci
2308c2ecf20Sopenharmony_ci		data->last_updated = jiffies;
2318c2ecf20Sopenharmony_ci		data->valid = 1;
2328c2ecf20Sopenharmony_ci	}
2338c2ecf20Sopenharmony_ci
2348c2ecf20Sopenharmony_ci	mutex_unlock(&data->update_lock);
2358c2ecf20Sopenharmony_ci	return data;
2368c2ecf20Sopenharmony_ci}
2378c2ecf20Sopenharmony_ci
2388c2ecf20Sopenharmony_cistatic inline u16 rpm_from_reg(u16 reg)
2398c2ecf20Sopenharmony_ci{
2408c2ecf20Sopenharmony_ci	if (reg == 0 || reg == 0xffff)
2418c2ecf20Sopenharmony_ci		return 0;
2428c2ecf20Sopenharmony_ci	return 1500000 / reg;
2438c2ecf20Sopenharmony_ci}
2448c2ecf20Sopenharmony_ci
2458c2ecf20Sopenharmony_cistatic inline u16 rpm_to_reg(int rpm)
2468c2ecf20Sopenharmony_ci{
2478c2ecf20Sopenharmony_ci	if (rpm < 367 || rpm > 0xffff)
2488c2ecf20Sopenharmony_ci		return 0xffff;
2498c2ecf20Sopenharmony_ci	return 1500000 / rpm;
2508c2ecf20Sopenharmony_ci}
2518c2ecf20Sopenharmony_ci
2528c2ecf20Sopenharmony_cistatic bool duty_mode_enabled(u8 pwm_enable)
2538c2ecf20Sopenharmony_ci{
2548c2ecf20Sopenharmony_ci	switch (pwm_enable) {
2558c2ecf20Sopenharmony_ci	case 0: /* Manual, duty mode (full speed) */
2568c2ecf20Sopenharmony_ci	case 1: /* Manual, duty mode */
2578c2ecf20Sopenharmony_ci	case 4: /* Auto, duty mode */
2588c2ecf20Sopenharmony_ci		return true;
2598c2ecf20Sopenharmony_ci	case 2: /* Auto, speed mode */
2608c2ecf20Sopenharmony_ci	case 3: /* Manual, speed mode */
2618c2ecf20Sopenharmony_ci		return false;
2628c2ecf20Sopenharmony_ci	default:
2638c2ecf20Sopenharmony_ci		WARN(1, "Unexpected pwm_enable value %d\n", pwm_enable);
2648c2ecf20Sopenharmony_ci		return true;
2658c2ecf20Sopenharmony_ci	}
2668c2ecf20Sopenharmony_ci}
2678c2ecf20Sopenharmony_ci
2688c2ecf20Sopenharmony_cistatic bool auto_mode_enabled(u8 pwm_enable)
2698c2ecf20Sopenharmony_ci{
2708c2ecf20Sopenharmony_ci	switch (pwm_enable) {
2718c2ecf20Sopenharmony_ci	case 0: /* Manual, duty mode (full speed) */
2728c2ecf20Sopenharmony_ci	case 1: /* Manual, duty mode */
2738c2ecf20Sopenharmony_ci	case 3: /* Manual, speed mode */
2748c2ecf20Sopenharmony_ci		return false;
2758c2ecf20Sopenharmony_ci	case 2: /* Auto, speed mode */
2768c2ecf20Sopenharmony_ci	case 4: /* Auto, duty mode */
2778c2ecf20Sopenharmony_ci		return true;
2788c2ecf20Sopenharmony_ci	default:
2798c2ecf20Sopenharmony_ci		WARN(1, "Unexpected pwm_enable value %d\n", pwm_enable);
2808c2ecf20Sopenharmony_ci		return false;
2818c2ecf20Sopenharmony_ci	}
2828c2ecf20Sopenharmony_ci}
2838c2ecf20Sopenharmony_ci
2848c2ecf20Sopenharmony_cistatic ssize_t set_fan_min(struct device *dev, struct device_attribute *attr,
2858c2ecf20Sopenharmony_ci		const char *buf, size_t count)
2868c2ecf20Sopenharmony_ci{
2878c2ecf20Sopenharmony_ci	int nr = to_sensor_dev_attr(attr)->index;
2888c2ecf20Sopenharmony_ci	struct i2c_client *client = to_i2c_client(dev);
2898c2ecf20Sopenharmony_ci	struct f75375_data *data = i2c_get_clientdata(client);
2908c2ecf20Sopenharmony_ci	unsigned long val;
2918c2ecf20Sopenharmony_ci	int err;
2928c2ecf20Sopenharmony_ci
2938c2ecf20Sopenharmony_ci	err = kstrtoul(buf, 10, &val);
2948c2ecf20Sopenharmony_ci	if (err < 0)
2958c2ecf20Sopenharmony_ci		return err;
2968c2ecf20Sopenharmony_ci
2978c2ecf20Sopenharmony_ci	mutex_lock(&data->update_lock);
2988c2ecf20Sopenharmony_ci	data->fan_min[nr] = rpm_to_reg(val);
2998c2ecf20Sopenharmony_ci	f75375_write16(client, F75375_REG_FAN_MIN(nr), data->fan_min[nr]);
3008c2ecf20Sopenharmony_ci	mutex_unlock(&data->update_lock);
3018c2ecf20Sopenharmony_ci	return count;
3028c2ecf20Sopenharmony_ci}
3038c2ecf20Sopenharmony_ci
3048c2ecf20Sopenharmony_cistatic ssize_t set_fan_target(struct device *dev, struct device_attribute *attr,
3058c2ecf20Sopenharmony_ci		const char *buf, size_t count)
3068c2ecf20Sopenharmony_ci{
3078c2ecf20Sopenharmony_ci	int nr = to_sensor_dev_attr(attr)->index;
3088c2ecf20Sopenharmony_ci	struct i2c_client *client = to_i2c_client(dev);
3098c2ecf20Sopenharmony_ci	struct f75375_data *data = i2c_get_clientdata(client);
3108c2ecf20Sopenharmony_ci	unsigned long val;
3118c2ecf20Sopenharmony_ci	int err;
3128c2ecf20Sopenharmony_ci
3138c2ecf20Sopenharmony_ci	err = kstrtoul(buf, 10, &val);
3148c2ecf20Sopenharmony_ci	if (err < 0)
3158c2ecf20Sopenharmony_ci		return err;
3168c2ecf20Sopenharmony_ci
3178c2ecf20Sopenharmony_ci	if (auto_mode_enabled(data->pwm_enable[nr]))
3188c2ecf20Sopenharmony_ci		return -EINVAL;
3198c2ecf20Sopenharmony_ci	if (data->kind == f75387 && duty_mode_enabled(data->pwm_enable[nr]))
3208c2ecf20Sopenharmony_ci		return -EINVAL;
3218c2ecf20Sopenharmony_ci
3228c2ecf20Sopenharmony_ci	mutex_lock(&data->update_lock);
3238c2ecf20Sopenharmony_ci	data->fan_target[nr] = rpm_to_reg(val);
3248c2ecf20Sopenharmony_ci	f75375_write16(client, F75375_REG_FAN_EXP(nr), data->fan_target[nr]);
3258c2ecf20Sopenharmony_ci	mutex_unlock(&data->update_lock);
3268c2ecf20Sopenharmony_ci	return count;
3278c2ecf20Sopenharmony_ci}
3288c2ecf20Sopenharmony_ci
3298c2ecf20Sopenharmony_cistatic ssize_t set_pwm(struct device *dev, struct device_attribute *attr,
3308c2ecf20Sopenharmony_ci		const char *buf, size_t count)
3318c2ecf20Sopenharmony_ci{
3328c2ecf20Sopenharmony_ci	int nr = to_sensor_dev_attr(attr)->index;
3338c2ecf20Sopenharmony_ci	struct i2c_client *client = to_i2c_client(dev);
3348c2ecf20Sopenharmony_ci	struct f75375_data *data = i2c_get_clientdata(client);
3358c2ecf20Sopenharmony_ci	unsigned long val;
3368c2ecf20Sopenharmony_ci	int err;
3378c2ecf20Sopenharmony_ci
3388c2ecf20Sopenharmony_ci	err = kstrtoul(buf, 10, &val);
3398c2ecf20Sopenharmony_ci	if (err < 0)
3408c2ecf20Sopenharmony_ci		return err;
3418c2ecf20Sopenharmony_ci
3428c2ecf20Sopenharmony_ci	if (auto_mode_enabled(data->pwm_enable[nr]) ||
3438c2ecf20Sopenharmony_ci	    !duty_mode_enabled(data->pwm_enable[nr]))
3448c2ecf20Sopenharmony_ci		return -EINVAL;
3458c2ecf20Sopenharmony_ci
3468c2ecf20Sopenharmony_ci	mutex_lock(&data->update_lock);
3478c2ecf20Sopenharmony_ci	data->pwm[nr] = clamp_val(val, 0, 255);
3488c2ecf20Sopenharmony_ci	f75375_write_pwm(client, nr);
3498c2ecf20Sopenharmony_ci	mutex_unlock(&data->update_lock);
3508c2ecf20Sopenharmony_ci	return count;
3518c2ecf20Sopenharmony_ci}
3528c2ecf20Sopenharmony_ci
3538c2ecf20Sopenharmony_cistatic ssize_t show_pwm_enable(struct device *dev, struct device_attribute
3548c2ecf20Sopenharmony_ci		*attr, char *buf)
3558c2ecf20Sopenharmony_ci{
3568c2ecf20Sopenharmony_ci	int nr = to_sensor_dev_attr(attr)->index;
3578c2ecf20Sopenharmony_ci	struct f75375_data *data = f75375_update_device(dev);
3588c2ecf20Sopenharmony_ci	return sprintf(buf, "%d\n", data->pwm_enable[nr]);
3598c2ecf20Sopenharmony_ci}
3608c2ecf20Sopenharmony_ci
3618c2ecf20Sopenharmony_cistatic int set_pwm_enable_direct(struct i2c_client *client, int nr, int val)
3628c2ecf20Sopenharmony_ci{
3638c2ecf20Sopenharmony_ci	struct f75375_data *data = i2c_get_clientdata(client);
3648c2ecf20Sopenharmony_ci	u8 fanmode;
3658c2ecf20Sopenharmony_ci
3668c2ecf20Sopenharmony_ci	if (val < 0 || val > 4)
3678c2ecf20Sopenharmony_ci		return -EINVAL;
3688c2ecf20Sopenharmony_ci
3698c2ecf20Sopenharmony_ci	fanmode = f75375_read8(client, F75375_REG_FAN_TIMER);
3708c2ecf20Sopenharmony_ci	if (data->kind == f75387) {
3718c2ecf20Sopenharmony_ci		/* For now, deny dangerous toggling of duty mode */
3728c2ecf20Sopenharmony_ci		if (duty_mode_enabled(data->pwm_enable[nr]) !=
3738c2ecf20Sopenharmony_ci				duty_mode_enabled(val))
3748c2ecf20Sopenharmony_ci			return -EOPNOTSUPP;
3758c2ecf20Sopenharmony_ci		/* clear each fanX_mode bit before setting them properly */
3768c2ecf20Sopenharmony_ci		fanmode &= ~(1 << F75387_FAN_DUTY_MODE(nr));
3778c2ecf20Sopenharmony_ci		fanmode &= ~(1 << F75387_FAN_MANU_MODE(nr));
3788c2ecf20Sopenharmony_ci		switch (val) {
3798c2ecf20Sopenharmony_ci		case 0: /* full speed */
3808c2ecf20Sopenharmony_ci			fanmode |= (1 << F75387_FAN_MANU_MODE(nr));
3818c2ecf20Sopenharmony_ci			fanmode |= (1 << F75387_FAN_DUTY_MODE(nr));
3828c2ecf20Sopenharmony_ci			data->pwm[nr] = 255;
3838c2ecf20Sopenharmony_ci			break;
3848c2ecf20Sopenharmony_ci		case 1: /* PWM */
3858c2ecf20Sopenharmony_ci			fanmode  |= (1 << F75387_FAN_MANU_MODE(nr));
3868c2ecf20Sopenharmony_ci			fanmode  |= (1 << F75387_FAN_DUTY_MODE(nr));
3878c2ecf20Sopenharmony_ci			break;
3888c2ecf20Sopenharmony_ci		case 2: /* Automatic, speed mode */
3898c2ecf20Sopenharmony_ci			break;
3908c2ecf20Sopenharmony_ci		case 3: /* fan speed */
3918c2ecf20Sopenharmony_ci			fanmode |= (1 << F75387_FAN_MANU_MODE(nr));
3928c2ecf20Sopenharmony_ci			break;
3938c2ecf20Sopenharmony_ci		case 4: /* Automatic, pwm */
3948c2ecf20Sopenharmony_ci			fanmode |= (1 << F75387_FAN_DUTY_MODE(nr));
3958c2ecf20Sopenharmony_ci			break;
3968c2ecf20Sopenharmony_ci		}
3978c2ecf20Sopenharmony_ci	} else {
3988c2ecf20Sopenharmony_ci		/* clear each fanX_mode bit before setting them properly */
3998c2ecf20Sopenharmony_ci		fanmode &= ~(3 << FAN_CTRL_MODE(nr));
4008c2ecf20Sopenharmony_ci		switch (val) {
4018c2ecf20Sopenharmony_ci		case 0: /* full speed */
4028c2ecf20Sopenharmony_ci			fanmode  |= (3 << FAN_CTRL_MODE(nr));
4038c2ecf20Sopenharmony_ci			data->pwm[nr] = 255;
4048c2ecf20Sopenharmony_ci			break;
4058c2ecf20Sopenharmony_ci		case 1: /* PWM */
4068c2ecf20Sopenharmony_ci			fanmode  |= (3 << FAN_CTRL_MODE(nr));
4078c2ecf20Sopenharmony_ci			break;
4088c2ecf20Sopenharmony_ci		case 2: /* AUTOMATIC*/
4098c2ecf20Sopenharmony_ci			fanmode  |= (1 << FAN_CTRL_MODE(nr));
4108c2ecf20Sopenharmony_ci			break;
4118c2ecf20Sopenharmony_ci		case 3: /* fan speed */
4128c2ecf20Sopenharmony_ci			break;
4138c2ecf20Sopenharmony_ci		case 4: /* Automatic pwm */
4148c2ecf20Sopenharmony_ci			return -EINVAL;
4158c2ecf20Sopenharmony_ci		}
4168c2ecf20Sopenharmony_ci	}
4178c2ecf20Sopenharmony_ci
4188c2ecf20Sopenharmony_ci	f75375_write8(client, F75375_REG_FAN_TIMER, fanmode);
4198c2ecf20Sopenharmony_ci	data->pwm_enable[nr] = val;
4208c2ecf20Sopenharmony_ci	if (val == 0)
4218c2ecf20Sopenharmony_ci		f75375_write_pwm(client, nr);
4228c2ecf20Sopenharmony_ci	return 0;
4238c2ecf20Sopenharmony_ci}
4248c2ecf20Sopenharmony_ci
4258c2ecf20Sopenharmony_cistatic ssize_t set_pwm_enable(struct device *dev, struct device_attribute *attr,
4268c2ecf20Sopenharmony_ci		const char *buf, size_t count)
4278c2ecf20Sopenharmony_ci{
4288c2ecf20Sopenharmony_ci	int nr = to_sensor_dev_attr(attr)->index;
4298c2ecf20Sopenharmony_ci	struct i2c_client *client = to_i2c_client(dev);
4308c2ecf20Sopenharmony_ci	struct f75375_data *data = i2c_get_clientdata(client);
4318c2ecf20Sopenharmony_ci	unsigned long val;
4328c2ecf20Sopenharmony_ci	int err;
4338c2ecf20Sopenharmony_ci
4348c2ecf20Sopenharmony_ci	err = kstrtoul(buf, 10, &val);
4358c2ecf20Sopenharmony_ci	if (err < 0)
4368c2ecf20Sopenharmony_ci		return err;
4378c2ecf20Sopenharmony_ci
4388c2ecf20Sopenharmony_ci	mutex_lock(&data->update_lock);
4398c2ecf20Sopenharmony_ci	err = set_pwm_enable_direct(client, nr, val);
4408c2ecf20Sopenharmony_ci	mutex_unlock(&data->update_lock);
4418c2ecf20Sopenharmony_ci	return err ? err : count;
4428c2ecf20Sopenharmony_ci}
4438c2ecf20Sopenharmony_ci
4448c2ecf20Sopenharmony_cistatic ssize_t set_pwm_mode(struct device *dev, struct device_attribute *attr,
4458c2ecf20Sopenharmony_ci		const char *buf, size_t count)
4468c2ecf20Sopenharmony_ci{
4478c2ecf20Sopenharmony_ci	int nr = to_sensor_dev_attr(attr)->index;
4488c2ecf20Sopenharmony_ci	struct i2c_client *client = to_i2c_client(dev);
4498c2ecf20Sopenharmony_ci	struct f75375_data *data = i2c_get_clientdata(client);
4508c2ecf20Sopenharmony_ci	unsigned long val;
4518c2ecf20Sopenharmony_ci	int err;
4528c2ecf20Sopenharmony_ci	u8 conf;
4538c2ecf20Sopenharmony_ci	char reg, ctrl;
4548c2ecf20Sopenharmony_ci
4558c2ecf20Sopenharmony_ci	err = kstrtoul(buf, 10, &val);
4568c2ecf20Sopenharmony_ci	if (err < 0)
4578c2ecf20Sopenharmony_ci		return err;
4588c2ecf20Sopenharmony_ci
4598c2ecf20Sopenharmony_ci	if (!(val == 0 || val == 1))
4608c2ecf20Sopenharmony_ci		return -EINVAL;
4618c2ecf20Sopenharmony_ci
4628c2ecf20Sopenharmony_ci	/* F75373 does not support DC (linear voltage) fan control mode */
4638c2ecf20Sopenharmony_ci	if (data->kind == f75373 && val == 0)
4648c2ecf20Sopenharmony_ci		return -EINVAL;
4658c2ecf20Sopenharmony_ci
4668c2ecf20Sopenharmony_ci	/* take care for different registers */
4678c2ecf20Sopenharmony_ci	if (data->kind == f75387) {
4688c2ecf20Sopenharmony_ci		reg = F75375_REG_FAN_TIMER;
4698c2ecf20Sopenharmony_ci		ctrl = F75387_FAN_CTRL_LINEAR(nr);
4708c2ecf20Sopenharmony_ci	} else {
4718c2ecf20Sopenharmony_ci		reg = F75375_REG_CONFIG1;
4728c2ecf20Sopenharmony_ci		ctrl = F75375_FAN_CTRL_LINEAR(nr);
4738c2ecf20Sopenharmony_ci	}
4748c2ecf20Sopenharmony_ci
4758c2ecf20Sopenharmony_ci	mutex_lock(&data->update_lock);
4768c2ecf20Sopenharmony_ci	conf = f75375_read8(client, reg);
4778c2ecf20Sopenharmony_ci	conf &= ~(1 << ctrl);
4788c2ecf20Sopenharmony_ci
4798c2ecf20Sopenharmony_ci	if (val == 0)
4808c2ecf20Sopenharmony_ci		conf |= (1 << ctrl);
4818c2ecf20Sopenharmony_ci
4828c2ecf20Sopenharmony_ci	f75375_write8(client, reg, conf);
4838c2ecf20Sopenharmony_ci	data->pwm_mode[nr] = val;
4848c2ecf20Sopenharmony_ci	mutex_unlock(&data->update_lock);
4858c2ecf20Sopenharmony_ci	return count;
4868c2ecf20Sopenharmony_ci}
4878c2ecf20Sopenharmony_ci
4888c2ecf20Sopenharmony_cistatic ssize_t show_pwm(struct device *dev, struct device_attribute
4898c2ecf20Sopenharmony_ci		*attr, char *buf)
4908c2ecf20Sopenharmony_ci{
4918c2ecf20Sopenharmony_ci	int nr = to_sensor_dev_attr(attr)->index;
4928c2ecf20Sopenharmony_ci	struct f75375_data *data = f75375_update_device(dev);
4938c2ecf20Sopenharmony_ci	return sprintf(buf, "%d\n", data->pwm[nr]);
4948c2ecf20Sopenharmony_ci}
4958c2ecf20Sopenharmony_ci
4968c2ecf20Sopenharmony_cistatic ssize_t show_pwm_mode(struct device *dev, struct device_attribute
4978c2ecf20Sopenharmony_ci		*attr, char *buf)
4988c2ecf20Sopenharmony_ci{
4998c2ecf20Sopenharmony_ci	int nr = to_sensor_dev_attr(attr)->index;
5008c2ecf20Sopenharmony_ci	struct f75375_data *data = f75375_update_device(dev);
5018c2ecf20Sopenharmony_ci	return sprintf(buf, "%d\n", data->pwm_mode[nr]);
5028c2ecf20Sopenharmony_ci}
5038c2ecf20Sopenharmony_ci
5048c2ecf20Sopenharmony_ci#define VOLT_FROM_REG(val) ((val) * 8)
5058c2ecf20Sopenharmony_ci#define VOLT_TO_REG(val) ((val) / 8)
5068c2ecf20Sopenharmony_ci
5078c2ecf20Sopenharmony_cistatic ssize_t show_in(struct device *dev, struct device_attribute *attr,
5088c2ecf20Sopenharmony_ci		char *buf)
5098c2ecf20Sopenharmony_ci{
5108c2ecf20Sopenharmony_ci	int nr = to_sensor_dev_attr(attr)->index;
5118c2ecf20Sopenharmony_ci	struct f75375_data *data = f75375_update_device(dev);
5128c2ecf20Sopenharmony_ci	return sprintf(buf, "%d\n", VOLT_FROM_REG(data->in[nr]));
5138c2ecf20Sopenharmony_ci}
5148c2ecf20Sopenharmony_ci
5158c2ecf20Sopenharmony_cistatic ssize_t show_in_max(struct device *dev, struct device_attribute *attr,
5168c2ecf20Sopenharmony_ci		char *buf)
5178c2ecf20Sopenharmony_ci{
5188c2ecf20Sopenharmony_ci	int nr = to_sensor_dev_attr(attr)->index;
5198c2ecf20Sopenharmony_ci	struct f75375_data *data = f75375_update_device(dev);
5208c2ecf20Sopenharmony_ci	return sprintf(buf, "%d\n", VOLT_FROM_REG(data->in_max[nr]));
5218c2ecf20Sopenharmony_ci}
5228c2ecf20Sopenharmony_ci
5238c2ecf20Sopenharmony_cistatic ssize_t show_in_min(struct device *dev, struct device_attribute *attr,
5248c2ecf20Sopenharmony_ci		char *buf)
5258c2ecf20Sopenharmony_ci{
5268c2ecf20Sopenharmony_ci	int nr = to_sensor_dev_attr(attr)->index;
5278c2ecf20Sopenharmony_ci	struct f75375_data *data = f75375_update_device(dev);
5288c2ecf20Sopenharmony_ci	return sprintf(buf, "%d\n", VOLT_FROM_REG(data->in_min[nr]));
5298c2ecf20Sopenharmony_ci}
5308c2ecf20Sopenharmony_ci
5318c2ecf20Sopenharmony_cistatic ssize_t set_in_max(struct device *dev, struct device_attribute *attr,
5328c2ecf20Sopenharmony_ci		const char *buf, size_t count)
5338c2ecf20Sopenharmony_ci{
5348c2ecf20Sopenharmony_ci	int nr = to_sensor_dev_attr(attr)->index;
5358c2ecf20Sopenharmony_ci	struct i2c_client *client = to_i2c_client(dev);
5368c2ecf20Sopenharmony_ci	struct f75375_data *data = i2c_get_clientdata(client);
5378c2ecf20Sopenharmony_ci	unsigned long val;
5388c2ecf20Sopenharmony_ci	int err;
5398c2ecf20Sopenharmony_ci
5408c2ecf20Sopenharmony_ci	err = kstrtoul(buf, 10, &val);
5418c2ecf20Sopenharmony_ci	if (err < 0)
5428c2ecf20Sopenharmony_ci		return err;
5438c2ecf20Sopenharmony_ci
5448c2ecf20Sopenharmony_ci	val = clamp_val(VOLT_TO_REG(val), 0, 0xff);
5458c2ecf20Sopenharmony_ci	mutex_lock(&data->update_lock);
5468c2ecf20Sopenharmony_ci	data->in_max[nr] = val;
5478c2ecf20Sopenharmony_ci	f75375_write8(client, F75375_REG_VOLT_HIGH(nr), data->in_max[nr]);
5488c2ecf20Sopenharmony_ci	mutex_unlock(&data->update_lock);
5498c2ecf20Sopenharmony_ci	return count;
5508c2ecf20Sopenharmony_ci}
5518c2ecf20Sopenharmony_ci
5528c2ecf20Sopenharmony_cistatic ssize_t set_in_min(struct device *dev, struct device_attribute *attr,
5538c2ecf20Sopenharmony_ci		const char *buf, size_t count)
5548c2ecf20Sopenharmony_ci{
5558c2ecf20Sopenharmony_ci	int nr = to_sensor_dev_attr(attr)->index;
5568c2ecf20Sopenharmony_ci	struct i2c_client *client = to_i2c_client(dev);
5578c2ecf20Sopenharmony_ci	struct f75375_data *data = i2c_get_clientdata(client);
5588c2ecf20Sopenharmony_ci	unsigned long val;
5598c2ecf20Sopenharmony_ci	int err;
5608c2ecf20Sopenharmony_ci
5618c2ecf20Sopenharmony_ci	err = kstrtoul(buf, 10, &val);
5628c2ecf20Sopenharmony_ci	if (err < 0)
5638c2ecf20Sopenharmony_ci		return err;
5648c2ecf20Sopenharmony_ci
5658c2ecf20Sopenharmony_ci	val = clamp_val(VOLT_TO_REG(val), 0, 0xff);
5668c2ecf20Sopenharmony_ci	mutex_lock(&data->update_lock);
5678c2ecf20Sopenharmony_ci	data->in_min[nr] = val;
5688c2ecf20Sopenharmony_ci	f75375_write8(client, F75375_REG_VOLT_LOW(nr), data->in_min[nr]);
5698c2ecf20Sopenharmony_ci	mutex_unlock(&data->update_lock);
5708c2ecf20Sopenharmony_ci	return count;
5718c2ecf20Sopenharmony_ci}
5728c2ecf20Sopenharmony_ci#define TEMP_FROM_REG(val) ((val) * 1000)
5738c2ecf20Sopenharmony_ci#define TEMP_TO_REG(val) ((val) / 1000)
5748c2ecf20Sopenharmony_ci#define TEMP11_FROM_REG(reg)	((reg) / 32 * 125)
5758c2ecf20Sopenharmony_ci
5768c2ecf20Sopenharmony_cistatic ssize_t show_temp11(struct device *dev, struct device_attribute *attr,
5778c2ecf20Sopenharmony_ci		char *buf)
5788c2ecf20Sopenharmony_ci{
5798c2ecf20Sopenharmony_ci	int nr = to_sensor_dev_attr(attr)->index;
5808c2ecf20Sopenharmony_ci	struct f75375_data *data = f75375_update_device(dev);
5818c2ecf20Sopenharmony_ci	return sprintf(buf, "%d\n", TEMP11_FROM_REG(data->temp11[nr]));
5828c2ecf20Sopenharmony_ci}
5838c2ecf20Sopenharmony_ci
5848c2ecf20Sopenharmony_cistatic ssize_t show_temp_max(struct device *dev, struct device_attribute *attr,
5858c2ecf20Sopenharmony_ci		char *buf)
5868c2ecf20Sopenharmony_ci{
5878c2ecf20Sopenharmony_ci	int nr = to_sensor_dev_attr(attr)->index;
5888c2ecf20Sopenharmony_ci	struct f75375_data *data = f75375_update_device(dev);
5898c2ecf20Sopenharmony_ci	return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_high[nr]));
5908c2ecf20Sopenharmony_ci}
5918c2ecf20Sopenharmony_ci
5928c2ecf20Sopenharmony_cistatic ssize_t show_temp_max_hyst(struct device *dev,
5938c2ecf20Sopenharmony_ci		struct device_attribute *attr, char *buf)
5948c2ecf20Sopenharmony_ci{
5958c2ecf20Sopenharmony_ci	int nr = to_sensor_dev_attr(attr)->index;
5968c2ecf20Sopenharmony_ci	struct f75375_data *data = f75375_update_device(dev);
5978c2ecf20Sopenharmony_ci	return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_max_hyst[nr]));
5988c2ecf20Sopenharmony_ci}
5998c2ecf20Sopenharmony_ci
6008c2ecf20Sopenharmony_cistatic ssize_t set_temp_max(struct device *dev, struct device_attribute *attr,
6018c2ecf20Sopenharmony_ci		const char *buf, size_t count)
6028c2ecf20Sopenharmony_ci{
6038c2ecf20Sopenharmony_ci	int nr = to_sensor_dev_attr(attr)->index;
6048c2ecf20Sopenharmony_ci	struct i2c_client *client = to_i2c_client(dev);
6058c2ecf20Sopenharmony_ci	struct f75375_data *data = i2c_get_clientdata(client);
6068c2ecf20Sopenharmony_ci	unsigned long val;
6078c2ecf20Sopenharmony_ci	int err;
6088c2ecf20Sopenharmony_ci
6098c2ecf20Sopenharmony_ci	err = kstrtoul(buf, 10, &val);
6108c2ecf20Sopenharmony_ci	if (err < 0)
6118c2ecf20Sopenharmony_ci		return err;
6128c2ecf20Sopenharmony_ci
6138c2ecf20Sopenharmony_ci	val = clamp_val(TEMP_TO_REG(val), 0, 127);
6148c2ecf20Sopenharmony_ci	mutex_lock(&data->update_lock);
6158c2ecf20Sopenharmony_ci	data->temp_high[nr] = val;
6168c2ecf20Sopenharmony_ci	f75375_write8(client, F75375_REG_TEMP_HIGH(nr), data->temp_high[nr]);
6178c2ecf20Sopenharmony_ci	mutex_unlock(&data->update_lock);
6188c2ecf20Sopenharmony_ci	return count;
6198c2ecf20Sopenharmony_ci}
6208c2ecf20Sopenharmony_ci
6218c2ecf20Sopenharmony_cistatic ssize_t set_temp_max_hyst(struct device *dev,
6228c2ecf20Sopenharmony_ci	struct device_attribute *attr, const char *buf, size_t count)
6238c2ecf20Sopenharmony_ci{
6248c2ecf20Sopenharmony_ci	int nr = to_sensor_dev_attr(attr)->index;
6258c2ecf20Sopenharmony_ci	struct i2c_client *client = to_i2c_client(dev);
6268c2ecf20Sopenharmony_ci	struct f75375_data *data = i2c_get_clientdata(client);
6278c2ecf20Sopenharmony_ci	unsigned long val;
6288c2ecf20Sopenharmony_ci	int err;
6298c2ecf20Sopenharmony_ci
6308c2ecf20Sopenharmony_ci	err = kstrtoul(buf, 10, &val);
6318c2ecf20Sopenharmony_ci	if (err < 0)
6328c2ecf20Sopenharmony_ci		return err;
6338c2ecf20Sopenharmony_ci
6348c2ecf20Sopenharmony_ci	val = clamp_val(TEMP_TO_REG(val), 0, 127);
6358c2ecf20Sopenharmony_ci	mutex_lock(&data->update_lock);
6368c2ecf20Sopenharmony_ci	data->temp_max_hyst[nr] = val;
6378c2ecf20Sopenharmony_ci	f75375_write8(client, F75375_REG_TEMP_HYST(nr),
6388c2ecf20Sopenharmony_ci		data->temp_max_hyst[nr]);
6398c2ecf20Sopenharmony_ci	mutex_unlock(&data->update_lock);
6408c2ecf20Sopenharmony_ci	return count;
6418c2ecf20Sopenharmony_ci}
6428c2ecf20Sopenharmony_ci
6438c2ecf20Sopenharmony_ci#define show_fan(thing) \
6448c2ecf20Sopenharmony_cistatic ssize_t show_##thing(struct device *dev, struct device_attribute *attr, \
6458c2ecf20Sopenharmony_ci			char *buf)\
6468c2ecf20Sopenharmony_ci{\
6478c2ecf20Sopenharmony_ci	int nr = to_sensor_dev_attr(attr)->index;\
6488c2ecf20Sopenharmony_ci	struct f75375_data *data = f75375_update_device(dev); \
6498c2ecf20Sopenharmony_ci	return sprintf(buf, "%d\n", rpm_from_reg(data->thing[nr])); \
6508c2ecf20Sopenharmony_ci}
6518c2ecf20Sopenharmony_ci
6528c2ecf20Sopenharmony_cishow_fan(fan);
6538c2ecf20Sopenharmony_cishow_fan(fan_min);
6548c2ecf20Sopenharmony_cishow_fan(fan_max);
6558c2ecf20Sopenharmony_cishow_fan(fan_target);
6568c2ecf20Sopenharmony_ci
6578c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR(in0_input, S_IRUGO, show_in, NULL, 0);
6588c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR(in0_max, S_IRUGO|S_IWUSR,
6598c2ecf20Sopenharmony_ci	show_in_max, set_in_max, 0);
6608c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR(in0_min, S_IRUGO|S_IWUSR,
6618c2ecf20Sopenharmony_ci	show_in_min, set_in_min, 0);
6628c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR(in1_input, S_IRUGO, show_in, NULL, 1);
6638c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR(in1_max, S_IRUGO|S_IWUSR,
6648c2ecf20Sopenharmony_ci	show_in_max, set_in_max, 1);
6658c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR(in1_min, S_IRUGO|S_IWUSR,
6668c2ecf20Sopenharmony_ci	show_in_min, set_in_min, 1);
6678c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR(in2_input, S_IRUGO, show_in, NULL, 2);
6688c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR(in2_max, S_IRUGO|S_IWUSR,
6698c2ecf20Sopenharmony_ci	show_in_max, set_in_max, 2);
6708c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR(in2_min, S_IRUGO|S_IWUSR,
6718c2ecf20Sopenharmony_ci	show_in_min, set_in_min, 2);
6728c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR(in3_input, S_IRUGO, show_in, NULL, 3);
6738c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR(in3_max, S_IRUGO|S_IWUSR,
6748c2ecf20Sopenharmony_ci	show_in_max, set_in_max, 3);
6758c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR(in3_min, S_IRUGO|S_IWUSR,
6768c2ecf20Sopenharmony_ci	show_in_min, set_in_min, 3);
6778c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_temp11, NULL, 0);
6788c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR(temp1_max_hyst, S_IRUGO|S_IWUSR,
6798c2ecf20Sopenharmony_ci	show_temp_max_hyst, set_temp_max_hyst, 0);
6808c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR(temp1_max, S_IRUGO|S_IWUSR,
6818c2ecf20Sopenharmony_ci	show_temp_max, set_temp_max, 0);
6828c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO, show_temp11, NULL, 1);
6838c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR(temp2_max_hyst, S_IRUGO|S_IWUSR,
6848c2ecf20Sopenharmony_ci	show_temp_max_hyst, set_temp_max_hyst, 1);
6858c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR(temp2_max, S_IRUGO|S_IWUSR,
6868c2ecf20Sopenharmony_ci	show_temp_max, set_temp_max, 1);
6878c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR(fan1_input, S_IRUGO, show_fan, NULL, 0);
6888c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR(fan1_max, S_IRUGO, show_fan_max, NULL, 0);
6898c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR(fan1_min, S_IRUGO|S_IWUSR,
6908c2ecf20Sopenharmony_ci	show_fan_min, set_fan_min, 0);
6918c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR(fan1_target, S_IRUGO|S_IWUSR,
6928c2ecf20Sopenharmony_ci	show_fan_target, set_fan_target, 0);
6938c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR(fan2_input, S_IRUGO, show_fan, NULL, 1);
6948c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR(fan2_max, S_IRUGO, show_fan_max, NULL, 1);
6958c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR(fan2_min, S_IRUGO|S_IWUSR,
6968c2ecf20Sopenharmony_ci	show_fan_min, set_fan_min, 1);
6978c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR(fan2_target, S_IRUGO|S_IWUSR,
6988c2ecf20Sopenharmony_ci	show_fan_target, set_fan_target, 1);
6998c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR(pwm1, S_IRUGO|S_IWUSR,
7008c2ecf20Sopenharmony_ci	show_pwm, set_pwm, 0);
7018c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR(pwm1_enable, S_IRUGO|S_IWUSR,
7028c2ecf20Sopenharmony_ci	show_pwm_enable, set_pwm_enable, 0);
7038c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR(pwm1_mode, S_IRUGO,
7048c2ecf20Sopenharmony_ci	show_pwm_mode, set_pwm_mode, 0);
7058c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR(pwm2, S_IRUGO | S_IWUSR,
7068c2ecf20Sopenharmony_ci	show_pwm, set_pwm, 1);
7078c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR(pwm2_enable, S_IRUGO|S_IWUSR,
7088c2ecf20Sopenharmony_ci	show_pwm_enable, set_pwm_enable, 1);
7098c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR(pwm2_mode, S_IRUGO,
7108c2ecf20Sopenharmony_ci	show_pwm_mode, set_pwm_mode, 1);
7118c2ecf20Sopenharmony_ci
7128c2ecf20Sopenharmony_cistatic struct attribute *f75375_attributes[] = {
7138c2ecf20Sopenharmony_ci	&sensor_dev_attr_temp1_input.dev_attr.attr,
7148c2ecf20Sopenharmony_ci	&sensor_dev_attr_temp1_max.dev_attr.attr,
7158c2ecf20Sopenharmony_ci	&sensor_dev_attr_temp1_max_hyst.dev_attr.attr,
7168c2ecf20Sopenharmony_ci	&sensor_dev_attr_temp2_input.dev_attr.attr,
7178c2ecf20Sopenharmony_ci	&sensor_dev_attr_temp2_max.dev_attr.attr,
7188c2ecf20Sopenharmony_ci	&sensor_dev_attr_temp2_max_hyst.dev_attr.attr,
7198c2ecf20Sopenharmony_ci	&sensor_dev_attr_fan1_input.dev_attr.attr,
7208c2ecf20Sopenharmony_ci	&sensor_dev_attr_fan1_max.dev_attr.attr,
7218c2ecf20Sopenharmony_ci	&sensor_dev_attr_fan1_min.dev_attr.attr,
7228c2ecf20Sopenharmony_ci	&sensor_dev_attr_fan1_target.dev_attr.attr,
7238c2ecf20Sopenharmony_ci	&sensor_dev_attr_fan2_input.dev_attr.attr,
7248c2ecf20Sopenharmony_ci	&sensor_dev_attr_fan2_max.dev_attr.attr,
7258c2ecf20Sopenharmony_ci	&sensor_dev_attr_fan2_min.dev_attr.attr,
7268c2ecf20Sopenharmony_ci	&sensor_dev_attr_fan2_target.dev_attr.attr,
7278c2ecf20Sopenharmony_ci	&sensor_dev_attr_pwm1.dev_attr.attr,
7288c2ecf20Sopenharmony_ci	&sensor_dev_attr_pwm1_enable.dev_attr.attr,
7298c2ecf20Sopenharmony_ci	&sensor_dev_attr_pwm1_mode.dev_attr.attr,
7308c2ecf20Sopenharmony_ci	&sensor_dev_attr_pwm2.dev_attr.attr,
7318c2ecf20Sopenharmony_ci	&sensor_dev_attr_pwm2_enable.dev_attr.attr,
7328c2ecf20Sopenharmony_ci	&sensor_dev_attr_pwm2_mode.dev_attr.attr,
7338c2ecf20Sopenharmony_ci	&sensor_dev_attr_in0_input.dev_attr.attr,
7348c2ecf20Sopenharmony_ci	&sensor_dev_attr_in0_max.dev_attr.attr,
7358c2ecf20Sopenharmony_ci	&sensor_dev_attr_in0_min.dev_attr.attr,
7368c2ecf20Sopenharmony_ci	&sensor_dev_attr_in1_input.dev_attr.attr,
7378c2ecf20Sopenharmony_ci	&sensor_dev_attr_in1_max.dev_attr.attr,
7388c2ecf20Sopenharmony_ci	&sensor_dev_attr_in1_min.dev_attr.attr,
7398c2ecf20Sopenharmony_ci	&sensor_dev_attr_in2_input.dev_attr.attr,
7408c2ecf20Sopenharmony_ci	&sensor_dev_attr_in2_max.dev_attr.attr,
7418c2ecf20Sopenharmony_ci	&sensor_dev_attr_in2_min.dev_attr.attr,
7428c2ecf20Sopenharmony_ci	&sensor_dev_attr_in3_input.dev_attr.attr,
7438c2ecf20Sopenharmony_ci	&sensor_dev_attr_in3_max.dev_attr.attr,
7448c2ecf20Sopenharmony_ci	&sensor_dev_attr_in3_min.dev_attr.attr,
7458c2ecf20Sopenharmony_ci	NULL
7468c2ecf20Sopenharmony_ci};
7478c2ecf20Sopenharmony_ci
7488c2ecf20Sopenharmony_cistatic const struct attribute_group f75375_group = {
7498c2ecf20Sopenharmony_ci	.attrs = f75375_attributes,
7508c2ecf20Sopenharmony_ci};
7518c2ecf20Sopenharmony_ci
7528c2ecf20Sopenharmony_cistatic void f75375_init(struct i2c_client *client, struct f75375_data *data,
7538c2ecf20Sopenharmony_ci		struct f75375s_platform_data *f75375s_pdata)
7548c2ecf20Sopenharmony_ci{
7558c2ecf20Sopenharmony_ci	int nr;
7568c2ecf20Sopenharmony_ci
7578c2ecf20Sopenharmony_ci	if (!f75375s_pdata) {
7588c2ecf20Sopenharmony_ci		u8 conf, mode;
7598c2ecf20Sopenharmony_ci		int nr;
7608c2ecf20Sopenharmony_ci
7618c2ecf20Sopenharmony_ci		conf = f75375_read8(client, F75375_REG_CONFIG1);
7628c2ecf20Sopenharmony_ci		mode = f75375_read8(client, F75375_REG_FAN_TIMER);
7638c2ecf20Sopenharmony_ci		for (nr = 0; nr < 2; nr++) {
7648c2ecf20Sopenharmony_ci			if (data->kind == f75387) {
7658c2ecf20Sopenharmony_ci				bool manu, duty;
7668c2ecf20Sopenharmony_ci
7678c2ecf20Sopenharmony_ci				if (!(mode & (1 << F75387_FAN_CTRL_LINEAR(nr))))
7688c2ecf20Sopenharmony_ci					data->pwm_mode[nr] = 1;
7698c2ecf20Sopenharmony_ci
7708c2ecf20Sopenharmony_ci				manu = ((mode >> F75387_FAN_MANU_MODE(nr)) & 1);
7718c2ecf20Sopenharmony_ci				duty = ((mode >> F75387_FAN_DUTY_MODE(nr)) & 1);
7728c2ecf20Sopenharmony_ci				if (!manu && duty)
7738c2ecf20Sopenharmony_ci					/* auto, pwm */
7748c2ecf20Sopenharmony_ci					data->pwm_enable[nr] = 4;
7758c2ecf20Sopenharmony_ci				else if (manu && !duty)
7768c2ecf20Sopenharmony_ci					/* manual, speed */
7778c2ecf20Sopenharmony_ci					data->pwm_enable[nr] = 3;
7788c2ecf20Sopenharmony_ci				else if (!manu && !duty)
7798c2ecf20Sopenharmony_ci					/* automatic, speed */
7808c2ecf20Sopenharmony_ci					data->pwm_enable[nr] = 2;
7818c2ecf20Sopenharmony_ci				else
7828c2ecf20Sopenharmony_ci					/* manual, pwm */
7838c2ecf20Sopenharmony_ci					data->pwm_enable[nr] = 1;
7848c2ecf20Sopenharmony_ci			} else {
7858c2ecf20Sopenharmony_ci				if (!(conf & (1 << F75375_FAN_CTRL_LINEAR(nr))))
7868c2ecf20Sopenharmony_ci					data->pwm_mode[nr] = 1;
7878c2ecf20Sopenharmony_ci
7888c2ecf20Sopenharmony_ci				switch ((mode >> FAN_CTRL_MODE(nr)) & 3) {
7898c2ecf20Sopenharmony_ci				case 0:		/* speed */
7908c2ecf20Sopenharmony_ci					data->pwm_enable[nr] = 3;
7918c2ecf20Sopenharmony_ci					break;
7928c2ecf20Sopenharmony_ci				case 1:		/* automatic */
7938c2ecf20Sopenharmony_ci					data->pwm_enable[nr] = 2;
7948c2ecf20Sopenharmony_ci					break;
7958c2ecf20Sopenharmony_ci				default:	/* manual */
7968c2ecf20Sopenharmony_ci					data->pwm_enable[nr] = 1;
7978c2ecf20Sopenharmony_ci					break;
7988c2ecf20Sopenharmony_ci				}
7998c2ecf20Sopenharmony_ci			}
8008c2ecf20Sopenharmony_ci		}
8018c2ecf20Sopenharmony_ci		return;
8028c2ecf20Sopenharmony_ci	}
8038c2ecf20Sopenharmony_ci
8048c2ecf20Sopenharmony_ci	set_pwm_enable_direct(client, 0, f75375s_pdata->pwm_enable[0]);
8058c2ecf20Sopenharmony_ci	set_pwm_enable_direct(client, 1, f75375s_pdata->pwm_enable[1]);
8068c2ecf20Sopenharmony_ci	for (nr = 0; nr < 2; nr++) {
8078c2ecf20Sopenharmony_ci		if (auto_mode_enabled(f75375s_pdata->pwm_enable[nr]) ||
8088c2ecf20Sopenharmony_ci		    !duty_mode_enabled(f75375s_pdata->pwm_enable[nr]))
8098c2ecf20Sopenharmony_ci			continue;
8108c2ecf20Sopenharmony_ci		data->pwm[nr] = clamp_val(f75375s_pdata->pwm[nr], 0, 255);
8118c2ecf20Sopenharmony_ci		f75375_write_pwm(client, nr);
8128c2ecf20Sopenharmony_ci	}
8138c2ecf20Sopenharmony_ci
8148c2ecf20Sopenharmony_ci}
8158c2ecf20Sopenharmony_ci
8168c2ecf20Sopenharmony_cistatic int f75375_probe(struct i2c_client *client)
8178c2ecf20Sopenharmony_ci{
8188c2ecf20Sopenharmony_ci	struct f75375_data *data;
8198c2ecf20Sopenharmony_ci	struct f75375s_platform_data *f75375s_pdata =
8208c2ecf20Sopenharmony_ci			dev_get_platdata(&client->dev);
8218c2ecf20Sopenharmony_ci	int err;
8228c2ecf20Sopenharmony_ci
8238c2ecf20Sopenharmony_ci	if (!i2c_check_functionality(client->adapter,
8248c2ecf20Sopenharmony_ci				I2C_FUNC_SMBUS_BYTE_DATA))
8258c2ecf20Sopenharmony_ci		return -EIO;
8268c2ecf20Sopenharmony_ci	data = devm_kzalloc(&client->dev, sizeof(struct f75375_data),
8278c2ecf20Sopenharmony_ci			    GFP_KERNEL);
8288c2ecf20Sopenharmony_ci	if (!data)
8298c2ecf20Sopenharmony_ci		return -ENOMEM;
8308c2ecf20Sopenharmony_ci
8318c2ecf20Sopenharmony_ci	i2c_set_clientdata(client, data);
8328c2ecf20Sopenharmony_ci	mutex_init(&data->update_lock);
8338c2ecf20Sopenharmony_ci	data->kind = i2c_match_id(f75375_id, client)->driver_data;
8348c2ecf20Sopenharmony_ci
8358c2ecf20Sopenharmony_ci	err = sysfs_create_group(&client->dev.kobj, &f75375_group);
8368c2ecf20Sopenharmony_ci	if (err)
8378c2ecf20Sopenharmony_ci		return err;
8388c2ecf20Sopenharmony_ci
8398c2ecf20Sopenharmony_ci	if (data->kind != f75373) {
8408c2ecf20Sopenharmony_ci		err = sysfs_chmod_file(&client->dev.kobj,
8418c2ecf20Sopenharmony_ci			&sensor_dev_attr_pwm1_mode.dev_attr.attr,
8428c2ecf20Sopenharmony_ci			S_IRUGO | S_IWUSR);
8438c2ecf20Sopenharmony_ci		if (err)
8448c2ecf20Sopenharmony_ci			goto exit_remove;
8458c2ecf20Sopenharmony_ci		err = sysfs_chmod_file(&client->dev.kobj,
8468c2ecf20Sopenharmony_ci			&sensor_dev_attr_pwm2_mode.dev_attr.attr,
8478c2ecf20Sopenharmony_ci			S_IRUGO | S_IWUSR);
8488c2ecf20Sopenharmony_ci		if (err)
8498c2ecf20Sopenharmony_ci			goto exit_remove;
8508c2ecf20Sopenharmony_ci	}
8518c2ecf20Sopenharmony_ci
8528c2ecf20Sopenharmony_ci	data->hwmon_dev = hwmon_device_register(&client->dev);
8538c2ecf20Sopenharmony_ci	if (IS_ERR(data->hwmon_dev)) {
8548c2ecf20Sopenharmony_ci		err = PTR_ERR(data->hwmon_dev);
8558c2ecf20Sopenharmony_ci		goto exit_remove;
8568c2ecf20Sopenharmony_ci	}
8578c2ecf20Sopenharmony_ci
8588c2ecf20Sopenharmony_ci	f75375_init(client, data, f75375s_pdata);
8598c2ecf20Sopenharmony_ci
8608c2ecf20Sopenharmony_ci	return 0;
8618c2ecf20Sopenharmony_ci
8628c2ecf20Sopenharmony_ciexit_remove:
8638c2ecf20Sopenharmony_ci	sysfs_remove_group(&client->dev.kobj, &f75375_group);
8648c2ecf20Sopenharmony_ci	return err;
8658c2ecf20Sopenharmony_ci}
8668c2ecf20Sopenharmony_ci
8678c2ecf20Sopenharmony_cistatic int f75375_remove(struct i2c_client *client)
8688c2ecf20Sopenharmony_ci{
8698c2ecf20Sopenharmony_ci	struct f75375_data *data = i2c_get_clientdata(client);
8708c2ecf20Sopenharmony_ci	hwmon_device_unregister(data->hwmon_dev);
8718c2ecf20Sopenharmony_ci	sysfs_remove_group(&client->dev.kobj, &f75375_group);
8728c2ecf20Sopenharmony_ci	return 0;
8738c2ecf20Sopenharmony_ci}
8748c2ecf20Sopenharmony_ci
8758c2ecf20Sopenharmony_ci/* Return 0 if detection is successful, -ENODEV otherwise */
8768c2ecf20Sopenharmony_cistatic int f75375_detect(struct i2c_client *client,
8778c2ecf20Sopenharmony_ci			 struct i2c_board_info *info)
8788c2ecf20Sopenharmony_ci{
8798c2ecf20Sopenharmony_ci	struct i2c_adapter *adapter = client->adapter;
8808c2ecf20Sopenharmony_ci	u16 vendid, chipid;
8818c2ecf20Sopenharmony_ci	u8 version;
8828c2ecf20Sopenharmony_ci	const char *name;
8838c2ecf20Sopenharmony_ci
8848c2ecf20Sopenharmony_ci	vendid = f75375_read16(client, F75375_REG_VENDOR);
8858c2ecf20Sopenharmony_ci	chipid = f75375_read16(client, F75375_CHIP_ID);
8868c2ecf20Sopenharmony_ci	if (vendid != 0x1934)
8878c2ecf20Sopenharmony_ci		return -ENODEV;
8888c2ecf20Sopenharmony_ci
8898c2ecf20Sopenharmony_ci	if (chipid == 0x0306)
8908c2ecf20Sopenharmony_ci		name = "f75375";
8918c2ecf20Sopenharmony_ci	else if (chipid == 0x0204)
8928c2ecf20Sopenharmony_ci		name = "f75373";
8938c2ecf20Sopenharmony_ci	else if (chipid == 0x0410)
8948c2ecf20Sopenharmony_ci		name = "f75387";
8958c2ecf20Sopenharmony_ci	else
8968c2ecf20Sopenharmony_ci		return -ENODEV;
8978c2ecf20Sopenharmony_ci
8988c2ecf20Sopenharmony_ci	version = f75375_read8(client, F75375_REG_VERSION);
8998c2ecf20Sopenharmony_ci	dev_info(&adapter->dev, "found %s version: %02X\n", name, version);
9008c2ecf20Sopenharmony_ci	strlcpy(info->type, name, I2C_NAME_SIZE);
9018c2ecf20Sopenharmony_ci
9028c2ecf20Sopenharmony_ci	return 0;
9038c2ecf20Sopenharmony_ci}
9048c2ecf20Sopenharmony_ci
9058c2ecf20Sopenharmony_cimodule_i2c_driver(f75375_driver);
9068c2ecf20Sopenharmony_ci
9078c2ecf20Sopenharmony_ciMODULE_AUTHOR("Riku Voipio");
9088c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL");
9098c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("F75373/F75375/F75387 hardware monitoring driver");
910