18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * dme1737.c - Driver for the SMSC DME1737, Asus A8000, SMSC SCH311x, SCH5027,
48c2ecf20Sopenharmony_ci *             and SCH5127 Super-I/O chips integrated hardware monitoring
58c2ecf20Sopenharmony_ci *             features.
68c2ecf20Sopenharmony_ci * Copyright (c) 2007, 2008, 2009, 2010 Juerg Haefliger <juergh@gmail.com>
78c2ecf20Sopenharmony_ci *
88c2ecf20Sopenharmony_ci * This driver is an I2C/ISA hybrid, meaning that it uses the I2C bus to access
98c2ecf20Sopenharmony_ci * the chip registers if a DME1737, A8000, or SCH5027 is found and the ISA bus
108c2ecf20Sopenharmony_ci * if a SCH311x or SCH5127 chip is found. Both types of chips have very
118c2ecf20Sopenharmony_ci * similar hardware monitoring capabilities but differ in the way they can be
128c2ecf20Sopenharmony_ci * accessed.
138c2ecf20Sopenharmony_ci */
148c2ecf20Sopenharmony_ci
158c2ecf20Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
168c2ecf20Sopenharmony_ci
178c2ecf20Sopenharmony_ci#include <linux/module.h>
188c2ecf20Sopenharmony_ci#include <linux/init.h>
198c2ecf20Sopenharmony_ci#include <linux/slab.h>
208c2ecf20Sopenharmony_ci#include <linux/jiffies.h>
218c2ecf20Sopenharmony_ci#include <linux/i2c.h>
228c2ecf20Sopenharmony_ci#include <linux/platform_device.h>
238c2ecf20Sopenharmony_ci#include <linux/hwmon.h>
248c2ecf20Sopenharmony_ci#include <linux/hwmon-sysfs.h>
258c2ecf20Sopenharmony_ci#include <linux/hwmon-vid.h>
268c2ecf20Sopenharmony_ci#include <linux/err.h>
278c2ecf20Sopenharmony_ci#include <linux/mutex.h>
288c2ecf20Sopenharmony_ci#include <linux/acpi.h>
298c2ecf20Sopenharmony_ci#include <linux/io.h>
308c2ecf20Sopenharmony_ci
318c2ecf20Sopenharmony_ci/* ISA device, if found */
328c2ecf20Sopenharmony_cistatic struct platform_device *pdev;
338c2ecf20Sopenharmony_ci
348c2ecf20Sopenharmony_ci/* Module load parameters */
358c2ecf20Sopenharmony_cistatic bool force_start;
368c2ecf20Sopenharmony_cimodule_param(force_start, bool, 0);
378c2ecf20Sopenharmony_ciMODULE_PARM_DESC(force_start, "Force the chip to start monitoring inputs");
388c2ecf20Sopenharmony_ci
398c2ecf20Sopenharmony_cistatic unsigned short force_id;
408c2ecf20Sopenharmony_cimodule_param(force_id, ushort, 0);
418c2ecf20Sopenharmony_ciMODULE_PARM_DESC(force_id, "Override the detected device ID");
428c2ecf20Sopenharmony_ci
438c2ecf20Sopenharmony_cistatic bool probe_all_addr;
448c2ecf20Sopenharmony_cimodule_param(probe_all_addr, bool, 0);
458c2ecf20Sopenharmony_ciMODULE_PARM_DESC(probe_all_addr,
468c2ecf20Sopenharmony_ci		 "Include probing of non-standard LPC addresses");
478c2ecf20Sopenharmony_ci
488c2ecf20Sopenharmony_ci/* Addresses to scan */
498c2ecf20Sopenharmony_cistatic const unsigned short normal_i2c[] = {0x2c, 0x2d, 0x2e, I2C_CLIENT_END};
508c2ecf20Sopenharmony_ci
518c2ecf20Sopenharmony_cienum chips { dme1737, sch5027, sch311x, sch5127 };
528c2ecf20Sopenharmony_ci
538c2ecf20Sopenharmony_ci#define	DO_REPORT "Please report to the driver maintainer."
548c2ecf20Sopenharmony_ci
558c2ecf20Sopenharmony_ci/* ---------------------------------------------------------------------
568c2ecf20Sopenharmony_ci * Registers
578c2ecf20Sopenharmony_ci *
588c2ecf20Sopenharmony_ci * The sensors are defined as follows:
598c2ecf20Sopenharmony_ci *
608c2ecf20Sopenharmony_ci * Voltages                          Temperatures
618c2ecf20Sopenharmony_ci * --------                          ------------
628c2ecf20Sopenharmony_ci * in0   +5VTR (+5V stdby)           temp1   Remote diode 1
638c2ecf20Sopenharmony_ci * in1   Vccp  (proc core)           temp2   Internal temp
648c2ecf20Sopenharmony_ci * in2   VCC   (internal +3.3V)      temp3   Remote diode 2
658c2ecf20Sopenharmony_ci * in3   +5V
668c2ecf20Sopenharmony_ci * in4   +12V
678c2ecf20Sopenharmony_ci * in5   VTR   (+3.3V stby)
688c2ecf20Sopenharmony_ci * in6   Vbat
698c2ecf20Sopenharmony_ci * in7   Vtrip (sch5127 only)
708c2ecf20Sopenharmony_ci *
718c2ecf20Sopenharmony_ci * --------------------------------------------------------------------- */
728c2ecf20Sopenharmony_ci
738c2ecf20Sopenharmony_ci/* Voltages (in) numbered 0-7 (ix) */
748c2ecf20Sopenharmony_ci#define DME1737_REG_IN(ix)		((ix) < 5 ? 0x20 + (ix) : \
758c2ecf20Sopenharmony_ci					 (ix) < 7 ? 0x94 + (ix) : \
768c2ecf20Sopenharmony_ci						    0x1f)
778c2ecf20Sopenharmony_ci#define DME1737_REG_IN_MIN(ix)		((ix) < 5 ? 0x44 + (ix) * 2 \
788c2ecf20Sopenharmony_ci						  : 0x91 + (ix) * 2)
798c2ecf20Sopenharmony_ci#define DME1737_REG_IN_MAX(ix)		((ix) < 5 ? 0x45 + (ix) * 2 \
808c2ecf20Sopenharmony_ci						  : 0x92 + (ix) * 2)
818c2ecf20Sopenharmony_ci
828c2ecf20Sopenharmony_ci/* Temperatures (temp) numbered 0-2 (ix) */
838c2ecf20Sopenharmony_ci#define DME1737_REG_TEMP(ix)		(0x25 + (ix))
848c2ecf20Sopenharmony_ci#define DME1737_REG_TEMP_MIN(ix)	(0x4e + (ix) * 2)
858c2ecf20Sopenharmony_ci#define DME1737_REG_TEMP_MAX(ix)	(0x4f + (ix) * 2)
868c2ecf20Sopenharmony_ci#define DME1737_REG_TEMP_OFFSET(ix)	((ix) == 0 ? 0x1f \
878c2ecf20Sopenharmony_ci						   : 0x1c + (ix))
888c2ecf20Sopenharmony_ci
898c2ecf20Sopenharmony_ci/*
908c2ecf20Sopenharmony_ci * Voltage and temperature LSBs
918c2ecf20Sopenharmony_ci * The LSBs (4 bits each) are stored in 5 registers with the following layouts:
928c2ecf20Sopenharmony_ci *    IN_TEMP_LSB(0) = [in5, in6]
938c2ecf20Sopenharmony_ci *    IN_TEMP_LSB(1) = [temp3, temp1]
948c2ecf20Sopenharmony_ci *    IN_TEMP_LSB(2) = [in4, temp2]
958c2ecf20Sopenharmony_ci *    IN_TEMP_LSB(3) = [in3, in0]
968c2ecf20Sopenharmony_ci *    IN_TEMP_LSB(4) = [in2, in1]
978c2ecf20Sopenharmony_ci *    IN_TEMP_LSB(5) = [res, in7]
988c2ecf20Sopenharmony_ci */
998c2ecf20Sopenharmony_ci#define DME1737_REG_IN_TEMP_LSB(ix)	(0x84 + (ix))
1008c2ecf20Sopenharmony_cistatic const u8 DME1737_REG_IN_LSB[] = {3, 4, 4, 3, 2, 0, 0, 5};
1018c2ecf20Sopenharmony_cistatic const u8 DME1737_REG_IN_LSB_SHL[] = {4, 4, 0, 0, 0, 0, 4, 4};
1028c2ecf20Sopenharmony_cistatic const u8 DME1737_REG_TEMP_LSB[] = {1, 2, 1};
1038c2ecf20Sopenharmony_cistatic const u8 DME1737_REG_TEMP_LSB_SHL[] = {4, 4, 0};
1048c2ecf20Sopenharmony_ci
1058c2ecf20Sopenharmony_ci/* Fans numbered 0-5 (ix) */
1068c2ecf20Sopenharmony_ci#define DME1737_REG_FAN(ix)		((ix) < 4 ? 0x28 + (ix) * 2 \
1078c2ecf20Sopenharmony_ci						  : 0xa1 + (ix) * 2)
1088c2ecf20Sopenharmony_ci#define DME1737_REG_FAN_MIN(ix)		((ix) < 4 ? 0x54 + (ix) * 2 \
1098c2ecf20Sopenharmony_ci						  : 0xa5 + (ix) * 2)
1108c2ecf20Sopenharmony_ci#define DME1737_REG_FAN_OPT(ix)		((ix) < 4 ? 0x90 + (ix) \
1118c2ecf20Sopenharmony_ci						  : 0xb2 + (ix))
1128c2ecf20Sopenharmony_ci#define DME1737_REG_FAN_MAX(ix)		(0xb4 + (ix)) /* only for fan[4-5] */
1138c2ecf20Sopenharmony_ci
1148c2ecf20Sopenharmony_ci/* PWMs numbered 0-2, 4-5 (ix) */
1158c2ecf20Sopenharmony_ci#define DME1737_REG_PWM(ix)		((ix) < 3 ? 0x30 + (ix) \
1168c2ecf20Sopenharmony_ci						  : 0xa1 + (ix))
1178c2ecf20Sopenharmony_ci#define DME1737_REG_PWM_CONFIG(ix)	(0x5c + (ix)) /* only for pwm[0-2] */
1188c2ecf20Sopenharmony_ci#define DME1737_REG_PWM_MIN(ix)		(0x64 + (ix)) /* only for pwm[0-2] */
1198c2ecf20Sopenharmony_ci#define DME1737_REG_PWM_FREQ(ix)	((ix) < 3 ? 0x5f + (ix) \
1208c2ecf20Sopenharmony_ci						  : 0xa3 + (ix))
1218c2ecf20Sopenharmony_ci/*
1228c2ecf20Sopenharmony_ci * The layout of the ramp rate registers is different from the other pwm
1238c2ecf20Sopenharmony_ci * registers. The bits for the 3 PWMs are stored in 2 registers:
1248c2ecf20Sopenharmony_ci *    PWM_RR(0) = [OFF3, OFF2,  OFF1,  RES,   RR1E, RR1-2, RR1-1, RR1-0]
1258c2ecf20Sopenharmony_ci *    PWM_RR(1) = [RR2E, RR2-2, RR2-1, RR2-0, RR3E, RR3-2, RR3-1, RR3-0]
1268c2ecf20Sopenharmony_ci */
1278c2ecf20Sopenharmony_ci#define DME1737_REG_PWM_RR(ix)		(0x62 + (ix)) /* only for pwm[0-2] */
1288c2ecf20Sopenharmony_ci
1298c2ecf20Sopenharmony_ci/* Thermal zones 0-2 */
1308c2ecf20Sopenharmony_ci#define DME1737_REG_ZONE_LOW(ix)	(0x67 + (ix))
1318c2ecf20Sopenharmony_ci#define DME1737_REG_ZONE_ABS(ix)	(0x6a + (ix))
1328c2ecf20Sopenharmony_ci/*
1338c2ecf20Sopenharmony_ci * The layout of the hysteresis registers is different from the other zone
1348c2ecf20Sopenharmony_ci * registers. The bits for the 3 zones are stored in 2 registers:
1358c2ecf20Sopenharmony_ci *    ZONE_HYST(0) = [H1-3,  H1-2,  H1-1, H1-0, H2-3, H2-2, H2-1, H2-0]
1368c2ecf20Sopenharmony_ci *    ZONE_HYST(1) = [H3-3,  H3-2,  H3-1, H3-0, RES,  RES,  RES,  RES]
1378c2ecf20Sopenharmony_ci */
1388c2ecf20Sopenharmony_ci#define DME1737_REG_ZONE_HYST(ix)	(0x6d + (ix))
1398c2ecf20Sopenharmony_ci
1408c2ecf20Sopenharmony_ci/*
1418c2ecf20Sopenharmony_ci * Alarm registers and bit mapping
1428c2ecf20Sopenharmony_ci * The 3 8-bit alarm registers will be concatenated to a single 32-bit
1438c2ecf20Sopenharmony_ci * alarm value [0, ALARM3, ALARM2, ALARM1].
1448c2ecf20Sopenharmony_ci */
1458c2ecf20Sopenharmony_ci#define DME1737_REG_ALARM1		0x41
1468c2ecf20Sopenharmony_ci#define DME1737_REG_ALARM2		0x42
1478c2ecf20Sopenharmony_ci#define DME1737_REG_ALARM3		0x83
1488c2ecf20Sopenharmony_cistatic const u8 DME1737_BIT_ALARM_IN[] = {0, 1, 2, 3, 8, 16, 17, 18};
1498c2ecf20Sopenharmony_cistatic const u8 DME1737_BIT_ALARM_TEMP[] = {4, 5, 6};
1508c2ecf20Sopenharmony_cistatic const u8 DME1737_BIT_ALARM_FAN[] = {10, 11, 12, 13, 22, 23};
1518c2ecf20Sopenharmony_ci
1528c2ecf20Sopenharmony_ci/* Miscellaneous registers */
1538c2ecf20Sopenharmony_ci#define DME1737_REG_DEVICE		0x3d
1548c2ecf20Sopenharmony_ci#define DME1737_REG_COMPANY		0x3e
1558c2ecf20Sopenharmony_ci#define DME1737_REG_VERSTEP		0x3f
1568c2ecf20Sopenharmony_ci#define DME1737_REG_CONFIG		0x40
1578c2ecf20Sopenharmony_ci#define DME1737_REG_CONFIG2		0x7f
1588c2ecf20Sopenharmony_ci#define DME1737_REG_VID			0x43
1598c2ecf20Sopenharmony_ci#define DME1737_REG_TACH_PWM		0x81
1608c2ecf20Sopenharmony_ci
1618c2ecf20Sopenharmony_ci/* ---------------------------------------------------------------------
1628c2ecf20Sopenharmony_ci * Misc defines
1638c2ecf20Sopenharmony_ci * --------------------------------------------------------------------- */
1648c2ecf20Sopenharmony_ci
1658c2ecf20Sopenharmony_ci/* Chip identification */
1668c2ecf20Sopenharmony_ci#define DME1737_COMPANY_SMSC	0x5c
1678c2ecf20Sopenharmony_ci#define DME1737_VERSTEP		0x88
1688c2ecf20Sopenharmony_ci#define DME1737_VERSTEP_MASK	0xf8
1698c2ecf20Sopenharmony_ci#define SCH311X_DEVICE		0x8c
1708c2ecf20Sopenharmony_ci#define SCH5027_VERSTEP		0x69
1718c2ecf20Sopenharmony_ci#define SCH5127_DEVICE		0x8e
1728c2ecf20Sopenharmony_ci
1738c2ecf20Sopenharmony_ci/* Device ID values (global configuration register index 0x20) */
1748c2ecf20Sopenharmony_ci#define DME1737_ID_1	0x77
1758c2ecf20Sopenharmony_ci#define DME1737_ID_2	0x78
1768c2ecf20Sopenharmony_ci#define SCH3112_ID	0x7c
1778c2ecf20Sopenharmony_ci#define SCH3114_ID	0x7d
1788c2ecf20Sopenharmony_ci#define SCH3116_ID	0x7f
1798c2ecf20Sopenharmony_ci#define SCH5027_ID	0x89
1808c2ecf20Sopenharmony_ci#define SCH5127_ID	0x86
1818c2ecf20Sopenharmony_ci
1828c2ecf20Sopenharmony_ci/* Length of ISA address segment */
1838c2ecf20Sopenharmony_ci#define DME1737_EXTENT	2
1848c2ecf20Sopenharmony_ci
1858c2ecf20Sopenharmony_ci/* chip-dependent features */
1868c2ecf20Sopenharmony_ci#define HAS_TEMP_OFFSET		(1 << 0)		/* bit 0 */
1878c2ecf20Sopenharmony_ci#define HAS_VID			(1 << 1)		/* bit 1 */
1888c2ecf20Sopenharmony_ci#define HAS_ZONE3		(1 << 2)		/* bit 2 */
1898c2ecf20Sopenharmony_ci#define HAS_ZONE_HYST		(1 << 3)		/* bit 3 */
1908c2ecf20Sopenharmony_ci#define HAS_PWM_MIN		(1 << 4)		/* bit 4 */
1918c2ecf20Sopenharmony_ci#define HAS_FAN(ix)		(1 << ((ix) + 5))	/* bits 5-10 */
1928c2ecf20Sopenharmony_ci#define HAS_PWM(ix)		(1 << ((ix) + 11))	/* bits 11-16 */
1938c2ecf20Sopenharmony_ci#define HAS_IN7			(1 << 17)		/* bit 17 */
1948c2ecf20Sopenharmony_ci
1958c2ecf20Sopenharmony_ci/* ---------------------------------------------------------------------
1968c2ecf20Sopenharmony_ci * Data structures and manipulation thereof
1978c2ecf20Sopenharmony_ci * --------------------------------------------------------------------- */
1988c2ecf20Sopenharmony_ci
1998c2ecf20Sopenharmony_cistruct dme1737_data {
2008c2ecf20Sopenharmony_ci	struct i2c_client *client;	/* for I2C devices only */
2018c2ecf20Sopenharmony_ci	struct device *hwmon_dev;
2028c2ecf20Sopenharmony_ci	const char *name;
2038c2ecf20Sopenharmony_ci	unsigned int addr;		/* for ISA devices only */
2048c2ecf20Sopenharmony_ci
2058c2ecf20Sopenharmony_ci	struct mutex update_lock;
2068c2ecf20Sopenharmony_ci	int valid;			/* !=0 if following fields are valid */
2078c2ecf20Sopenharmony_ci	unsigned long last_update;	/* in jiffies */
2088c2ecf20Sopenharmony_ci	unsigned long last_vbat;	/* in jiffies */
2098c2ecf20Sopenharmony_ci	enum chips type;
2108c2ecf20Sopenharmony_ci	const int *in_nominal;		/* pointer to IN_NOMINAL array */
2118c2ecf20Sopenharmony_ci
2128c2ecf20Sopenharmony_ci	u8 vid;
2138c2ecf20Sopenharmony_ci	u8 pwm_rr_en;
2148c2ecf20Sopenharmony_ci	u32 has_features;
2158c2ecf20Sopenharmony_ci
2168c2ecf20Sopenharmony_ci	/* Register values */
2178c2ecf20Sopenharmony_ci	u16 in[8];
2188c2ecf20Sopenharmony_ci	u8  in_min[8];
2198c2ecf20Sopenharmony_ci	u8  in_max[8];
2208c2ecf20Sopenharmony_ci	s16 temp[3];
2218c2ecf20Sopenharmony_ci	s8  temp_min[3];
2228c2ecf20Sopenharmony_ci	s8  temp_max[3];
2238c2ecf20Sopenharmony_ci	s8  temp_offset[3];
2248c2ecf20Sopenharmony_ci	u8  config;
2258c2ecf20Sopenharmony_ci	u8  config2;
2268c2ecf20Sopenharmony_ci	u8  vrm;
2278c2ecf20Sopenharmony_ci	u16 fan[6];
2288c2ecf20Sopenharmony_ci	u16 fan_min[6];
2298c2ecf20Sopenharmony_ci	u8  fan_max[2];
2308c2ecf20Sopenharmony_ci	u8  fan_opt[6];
2318c2ecf20Sopenharmony_ci	u8  pwm[6];
2328c2ecf20Sopenharmony_ci	u8  pwm_min[3];
2338c2ecf20Sopenharmony_ci	u8  pwm_config[3];
2348c2ecf20Sopenharmony_ci	u8  pwm_acz[3];
2358c2ecf20Sopenharmony_ci	u8  pwm_freq[6];
2368c2ecf20Sopenharmony_ci	u8  pwm_rr[2];
2378c2ecf20Sopenharmony_ci	s8  zone_low[3];
2388c2ecf20Sopenharmony_ci	s8  zone_abs[3];
2398c2ecf20Sopenharmony_ci	u8  zone_hyst[2];
2408c2ecf20Sopenharmony_ci	u32 alarms;
2418c2ecf20Sopenharmony_ci};
2428c2ecf20Sopenharmony_ci
2438c2ecf20Sopenharmony_ci/* Nominal voltage values */
2448c2ecf20Sopenharmony_cistatic const int IN_NOMINAL_DME1737[] = {5000, 2250, 3300, 5000, 12000, 3300,
2458c2ecf20Sopenharmony_ci					 3300};
2468c2ecf20Sopenharmony_cistatic const int IN_NOMINAL_SCH311x[] = {2500, 1500, 3300, 5000, 12000, 3300,
2478c2ecf20Sopenharmony_ci					 3300};
2488c2ecf20Sopenharmony_cistatic const int IN_NOMINAL_SCH5027[] = {5000, 2250, 3300, 1125, 1125, 3300,
2498c2ecf20Sopenharmony_ci					 3300};
2508c2ecf20Sopenharmony_cistatic const int IN_NOMINAL_SCH5127[] = {2500, 2250, 3300, 1125, 1125, 3300,
2518c2ecf20Sopenharmony_ci					 3300, 1500};
2528c2ecf20Sopenharmony_ci#define IN_NOMINAL(type)	((type) == sch311x ? IN_NOMINAL_SCH311x : \
2538c2ecf20Sopenharmony_ci				 (type) == sch5027 ? IN_NOMINAL_SCH5027 : \
2548c2ecf20Sopenharmony_ci				 (type) == sch5127 ? IN_NOMINAL_SCH5127 : \
2558c2ecf20Sopenharmony_ci				 IN_NOMINAL_DME1737)
2568c2ecf20Sopenharmony_ci
2578c2ecf20Sopenharmony_ci/*
2588c2ecf20Sopenharmony_ci * Voltage input
2598c2ecf20Sopenharmony_ci * Voltage inputs have 16 bits resolution, limit values have 8 bits
2608c2ecf20Sopenharmony_ci * resolution.
2618c2ecf20Sopenharmony_ci */
2628c2ecf20Sopenharmony_cistatic inline int IN_FROM_REG(int reg, int nominal, int res)
2638c2ecf20Sopenharmony_ci{
2648c2ecf20Sopenharmony_ci	return (reg * nominal + (3 << (res - 3))) / (3 << (res - 2));
2658c2ecf20Sopenharmony_ci}
2668c2ecf20Sopenharmony_ci
2678c2ecf20Sopenharmony_cistatic inline int IN_TO_REG(long val, int nominal)
2688c2ecf20Sopenharmony_ci{
2698c2ecf20Sopenharmony_ci	val = clamp_val(val, 0, 255 * nominal / 192);
2708c2ecf20Sopenharmony_ci	return DIV_ROUND_CLOSEST(val * 192, nominal);
2718c2ecf20Sopenharmony_ci}
2728c2ecf20Sopenharmony_ci
2738c2ecf20Sopenharmony_ci/*
2748c2ecf20Sopenharmony_ci * Temperature input
2758c2ecf20Sopenharmony_ci * The register values represent temperatures in 2's complement notation from
2768c2ecf20Sopenharmony_ci * -127 degrees C to +127 degrees C. Temp inputs have 16 bits resolution, limit
2778c2ecf20Sopenharmony_ci * values have 8 bits resolution.
2788c2ecf20Sopenharmony_ci */
2798c2ecf20Sopenharmony_cistatic inline int TEMP_FROM_REG(int reg, int res)
2808c2ecf20Sopenharmony_ci{
2818c2ecf20Sopenharmony_ci	return (reg * 1000) >> (res - 8);
2828c2ecf20Sopenharmony_ci}
2838c2ecf20Sopenharmony_ci
2848c2ecf20Sopenharmony_cistatic inline int TEMP_TO_REG(long val)
2858c2ecf20Sopenharmony_ci{
2868c2ecf20Sopenharmony_ci	val = clamp_val(val, -128000, 127000);
2878c2ecf20Sopenharmony_ci	return DIV_ROUND_CLOSEST(val, 1000);
2888c2ecf20Sopenharmony_ci}
2898c2ecf20Sopenharmony_ci
2908c2ecf20Sopenharmony_ci/* Temperature range */
2918c2ecf20Sopenharmony_cistatic const int TEMP_RANGE[] = {2000, 2500, 3333, 4000, 5000, 6666, 8000,
2928c2ecf20Sopenharmony_ci				 10000, 13333, 16000, 20000, 26666, 32000,
2938c2ecf20Sopenharmony_ci				 40000, 53333, 80000};
2948c2ecf20Sopenharmony_ci
2958c2ecf20Sopenharmony_cistatic inline int TEMP_RANGE_FROM_REG(int reg)
2968c2ecf20Sopenharmony_ci{
2978c2ecf20Sopenharmony_ci	return TEMP_RANGE[(reg >> 4) & 0x0f];
2988c2ecf20Sopenharmony_ci}
2998c2ecf20Sopenharmony_ci
3008c2ecf20Sopenharmony_cistatic int TEMP_RANGE_TO_REG(long val, int reg)
3018c2ecf20Sopenharmony_ci{
3028c2ecf20Sopenharmony_ci	int i;
3038c2ecf20Sopenharmony_ci
3048c2ecf20Sopenharmony_ci	for (i = 15; i > 0; i--) {
3058c2ecf20Sopenharmony_ci		if (val > (TEMP_RANGE[i] + TEMP_RANGE[i - 1] + 1) / 2)
3068c2ecf20Sopenharmony_ci			break;
3078c2ecf20Sopenharmony_ci	}
3088c2ecf20Sopenharmony_ci
3098c2ecf20Sopenharmony_ci	return (reg & 0x0f) | (i << 4);
3108c2ecf20Sopenharmony_ci}
3118c2ecf20Sopenharmony_ci
3128c2ecf20Sopenharmony_ci/*
3138c2ecf20Sopenharmony_ci * Temperature hysteresis
3148c2ecf20Sopenharmony_ci * Register layout:
3158c2ecf20Sopenharmony_ci *    reg[0] = [H1-3, H1-2, H1-1, H1-0, H2-3, H2-2, H2-1, H2-0]
3168c2ecf20Sopenharmony_ci *    reg[1] = [H3-3, H3-2, H3-1, H3-0, xxxx, xxxx, xxxx, xxxx]
3178c2ecf20Sopenharmony_ci */
3188c2ecf20Sopenharmony_cistatic inline int TEMP_HYST_FROM_REG(int reg, int ix)
3198c2ecf20Sopenharmony_ci{
3208c2ecf20Sopenharmony_ci	return (((ix == 1) ? reg : reg >> 4) & 0x0f) * 1000;
3218c2ecf20Sopenharmony_ci}
3228c2ecf20Sopenharmony_ci
3238c2ecf20Sopenharmony_cistatic inline int TEMP_HYST_TO_REG(int temp, long hyst, int ix, int reg)
3248c2ecf20Sopenharmony_ci{
3258c2ecf20Sopenharmony_ci	hyst = clamp_val(hyst, temp - 15000, temp);
3268c2ecf20Sopenharmony_ci	hyst = DIV_ROUND_CLOSEST(temp - hyst, 1000);
3278c2ecf20Sopenharmony_ci
3288c2ecf20Sopenharmony_ci	return (ix == 1) ? (reg & 0xf0) | hyst : (reg & 0x0f) | (hyst << 4);
3298c2ecf20Sopenharmony_ci}
3308c2ecf20Sopenharmony_ci
3318c2ecf20Sopenharmony_ci/* Fan input RPM */
3328c2ecf20Sopenharmony_cistatic inline int FAN_FROM_REG(int reg, int tpc)
3338c2ecf20Sopenharmony_ci{
3348c2ecf20Sopenharmony_ci	if (tpc)
3358c2ecf20Sopenharmony_ci		return tpc * reg;
3368c2ecf20Sopenharmony_ci	else
3378c2ecf20Sopenharmony_ci		return (reg == 0 || reg == 0xffff) ? 0 : 90000 * 60 / reg;
3388c2ecf20Sopenharmony_ci}
3398c2ecf20Sopenharmony_ci
3408c2ecf20Sopenharmony_cistatic inline int FAN_TO_REG(long val, int tpc)
3418c2ecf20Sopenharmony_ci{
3428c2ecf20Sopenharmony_ci	if (tpc) {
3438c2ecf20Sopenharmony_ci		return clamp_val(val / tpc, 0, 0xffff);
3448c2ecf20Sopenharmony_ci	} else {
3458c2ecf20Sopenharmony_ci		return (val <= 0) ? 0xffff :
3468c2ecf20Sopenharmony_ci			clamp_val(90000 * 60 / val, 0, 0xfffe);
3478c2ecf20Sopenharmony_ci	}
3488c2ecf20Sopenharmony_ci}
3498c2ecf20Sopenharmony_ci
3508c2ecf20Sopenharmony_ci/*
3518c2ecf20Sopenharmony_ci * Fan TPC (tach pulse count)
3528c2ecf20Sopenharmony_ci * Converts a register value to a TPC multiplier or returns 0 if the tachometer
3538c2ecf20Sopenharmony_ci * is configured in legacy (non-tpc) mode
3548c2ecf20Sopenharmony_ci */
3558c2ecf20Sopenharmony_cistatic inline int FAN_TPC_FROM_REG(int reg)
3568c2ecf20Sopenharmony_ci{
3578c2ecf20Sopenharmony_ci	return (reg & 0x20) ? 0 : 60 >> (reg & 0x03);
3588c2ecf20Sopenharmony_ci}
3598c2ecf20Sopenharmony_ci
3608c2ecf20Sopenharmony_ci/*
3618c2ecf20Sopenharmony_ci * Fan type
3628c2ecf20Sopenharmony_ci * The type of a fan is expressed in number of pulses-per-revolution that it
3638c2ecf20Sopenharmony_ci * emits
3648c2ecf20Sopenharmony_ci */
3658c2ecf20Sopenharmony_cistatic inline int FAN_TYPE_FROM_REG(int reg)
3668c2ecf20Sopenharmony_ci{
3678c2ecf20Sopenharmony_ci	int edge = (reg >> 1) & 0x03;
3688c2ecf20Sopenharmony_ci
3698c2ecf20Sopenharmony_ci	return (edge > 0) ? 1 << (edge - 1) : 0;
3708c2ecf20Sopenharmony_ci}
3718c2ecf20Sopenharmony_ci
3728c2ecf20Sopenharmony_cistatic inline int FAN_TYPE_TO_REG(long val, int reg)
3738c2ecf20Sopenharmony_ci{
3748c2ecf20Sopenharmony_ci	int edge = (val == 4) ? 3 : val;
3758c2ecf20Sopenharmony_ci
3768c2ecf20Sopenharmony_ci	return (reg & 0xf9) | (edge << 1);
3778c2ecf20Sopenharmony_ci}
3788c2ecf20Sopenharmony_ci
3798c2ecf20Sopenharmony_ci/* Fan max RPM */
3808c2ecf20Sopenharmony_cistatic const int FAN_MAX[] = {0x54, 0x38, 0x2a, 0x21, 0x1c, 0x18, 0x15, 0x12,
3818c2ecf20Sopenharmony_ci			      0x11, 0x0f, 0x0e};
3828c2ecf20Sopenharmony_ci
3838c2ecf20Sopenharmony_cistatic int FAN_MAX_FROM_REG(int reg)
3848c2ecf20Sopenharmony_ci{
3858c2ecf20Sopenharmony_ci	int i;
3868c2ecf20Sopenharmony_ci
3878c2ecf20Sopenharmony_ci	for (i = 10; i > 0; i--) {
3888c2ecf20Sopenharmony_ci		if (reg == FAN_MAX[i])
3898c2ecf20Sopenharmony_ci			break;
3908c2ecf20Sopenharmony_ci	}
3918c2ecf20Sopenharmony_ci
3928c2ecf20Sopenharmony_ci	return 1000 + i * 500;
3938c2ecf20Sopenharmony_ci}
3948c2ecf20Sopenharmony_ci
3958c2ecf20Sopenharmony_cistatic int FAN_MAX_TO_REG(long val)
3968c2ecf20Sopenharmony_ci{
3978c2ecf20Sopenharmony_ci	int i;
3988c2ecf20Sopenharmony_ci
3998c2ecf20Sopenharmony_ci	for (i = 10; i > 0; i--) {
4008c2ecf20Sopenharmony_ci		if (val > (1000 + (i - 1) * 500))
4018c2ecf20Sopenharmony_ci			break;
4028c2ecf20Sopenharmony_ci	}
4038c2ecf20Sopenharmony_ci
4048c2ecf20Sopenharmony_ci	return FAN_MAX[i];
4058c2ecf20Sopenharmony_ci}
4068c2ecf20Sopenharmony_ci
4078c2ecf20Sopenharmony_ci/*
4088c2ecf20Sopenharmony_ci * PWM enable
4098c2ecf20Sopenharmony_ci * Register to enable mapping:
4108c2ecf20Sopenharmony_ci * 000:  2  fan on zone 1 auto
4118c2ecf20Sopenharmony_ci * 001:  2  fan on zone 2 auto
4128c2ecf20Sopenharmony_ci * 010:  2  fan on zone 3 auto
4138c2ecf20Sopenharmony_ci * 011:  0  fan full on
4148c2ecf20Sopenharmony_ci * 100: -1  fan disabled
4158c2ecf20Sopenharmony_ci * 101:  2  fan on hottest of zones 2,3 auto
4168c2ecf20Sopenharmony_ci * 110:  2  fan on hottest of zones 1,2,3 auto
4178c2ecf20Sopenharmony_ci * 111:  1  fan in manual mode
4188c2ecf20Sopenharmony_ci */
4198c2ecf20Sopenharmony_cistatic inline int PWM_EN_FROM_REG(int reg)
4208c2ecf20Sopenharmony_ci{
4218c2ecf20Sopenharmony_ci	static const int en[] = {2, 2, 2, 0, -1, 2, 2, 1};
4228c2ecf20Sopenharmony_ci
4238c2ecf20Sopenharmony_ci	return en[(reg >> 5) & 0x07];
4248c2ecf20Sopenharmony_ci}
4258c2ecf20Sopenharmony_ci
4268c2ecf20Sopenharmony_cistatic inline int PWM_EN_TO_REG(int val, int reg)
4278c2ecf20Sopenharmony_ci{
4288c2ecf20Sopenharmony_ci	int en = (val == 1) ? 7 : 3;
4298c2ecf20Sopenharmony_ci
4308c2ecf20Sopenharmony_ci	return (reg & 0x1f) | ((en & 0x07) << 5);
4318c2ecf20Sopenharmony_ci}
4328c2ecf20Sopenharmony_ci
4338c2ecf20Sopenharmony_ci/*
4348c2ecf20Sopenharmony_ci * PWM auto channels zone
4358c2ecf20Sopenharmony_ci * Register to auto channels zone mapping (ACZ is a bitfield with bit x
4368c2ecf20Sopenharmony_ci * corresponding to zone x+1):
4378c2ecf20Sopenharmony_ci * 000: 001  fan on zone 1 auto
4388c2ecf20Sopenharmony_ci * 001: 010  fan on zone 2 auto
4398c2ecf20Sopenharmony_ci * 010: 100  fan on zone 3 auto
4408c2ecf20Sopenharmony_ci * 011: 000  fan full on
4418c2ecf20Sopenharmony_ci * 100: 000  fan disabled
4428c2ecf20Sopenharmony_ci * 101: 110  fan on hottest of zones 2,3 auto
4438c2ecf20Sopenharmony_ci * 110: 111  fan on hottest of zones 1,2,3 auto
4448c2ecf20Sopenharmony_ci * 111: 000  fan in manual mode
4458c2ecf20Sopenharmony_ci */
4468c2ecf20Sopenharmony_cistatic inline int PWM_ACZ_FROM_REG(int reg)
4478c2ecf20Sopenharmony_ci{
4488c2ecf20Sopenharmony_ci	static const int acz[] = {1, 2, 4, 0, 0, 6, 7, 0};
4498c2ecf20Sopenharmony_ci
4508c2ecf20Sopenharmony_ci	return acz[(reg >> 5) & 0x07];
4518c2ecf20Sopenharmony_ci}
4528c2ecf20Sopenharmony_ci
4538c2ecf20Sopenharmony_cistatic inline int PWM_ACZ_TO_REG(long val, int reg)
4548c2ecf20Sopenharmony_ci{
4558c2ecf20Sopenharmony_ci	int acz = (val == 4) ? 2 : val - 1;
4568c2ecf20Sopenharmony_ci
4578c2ecf20Sopenharmony_ci	return (reg & 0x1f) | ((acz & 0x07) << 5);
4588c2ecf20Sopenharmony_ci}
4598c2ecf20Sopenharmony_ci
4608c2ecf20Sopenharmony_ci/* PWM frequency */
4618c2ecf20Sopenharmony_cistatic const int PWM_FREQ[] = {11, 15, 22, 29, 35, 44, 59, 88,
4628c2ecf20Sopenharmony_ci			       15000, 20000, 30000, 25000, 0, 0, 0, 0};
4638c2ecf20Sopenharmony_ci
4648c2ecf20Sopenharmony_cistatic inline int PWM_FREQ_FROM_REG(int reg)
4658c2ecf20Sopenharmony_ci{
4668c2ecf20Sopenharmony_ci	return PWM_FREQ[reg & 0x0f];
4678c2ecf20Sopenharmony_ci}
4688c2ecf20Sopenharmony_ci
4698c2ecf20Sopenharmony_cistatic int PWM_FREQ_TO_REG(long val, int reg)
4708c2ecf20Sopenharmony_ci{
4718c2ecf20Sopenharmony_ci	int i;
4728c2ecf20Sopenharmony_ci
4738c2ecf20Sopenharmony_ci	/* the first two cases are special - stupid chip design! */
4748c2ecf20Sopenharmony_ci	if (val > 27500) {
4758c2ecf20Sopenharmony_ci		i = 10;
4768c2ecf20Sopenharmony_ci	} else if (val > 22500) {
4778c2ecf20Sopenharmony_ci		i = 11;
4788c2ecf20Sopenharmony_ci	} else {
4798c2ecf20Sopenharmony_ci		for (i = 9; i > 0; i--) {
4808c2ecf20Sopenharmony_ci			if (val > (PWM_FREQ[i] + PWM_FREQ[i - 1] + 1) / 2)
4818c2ecf20Sopenharmony_ci				break;
4828c2ecf20Sopenharmony_ci		}
4838c2ecf20Sopenharmony_ci	}
4848c2ecf20Sopenharmony_ci
4858c2ecf20Sopenharmony_ci	return (reg & 0xf0) | i;
4868c2ecf20Sopenharmony_ci}
4878c2ecf20Sopenharmony_ci
4888c2ecf20Sopenharmony_ci/*
4898c2ecf20Sopenharmony_ci * PWM ramp rate
4908c2ecf20Sopenharmony_ci * Register layout:
4918c2ecf20Sopenharmony_ci *    reg[0] = [OFF3,  OFF2,  OFF1,  RES,   RR1-E, RR1-2, RR1-1, RR1-0]
4928c2ecf20Sopenharmony_ci *    reg[1] = [RR2-E, RR2-2, RR2-1, RR2-0, RR3-E, RR3-2, RR3-1, RR3-0]
4938c2ecf20Sopenharmony_ci */
4948c2ecf20Sopenharmony_cistatic const u8 PWM_RR[] = {206, 104, 69, 41, 26, 18, 10, 5};
4958c2ecf20Sopenharmony_ci
4968c2ecf20Sopenharmony_cistatic inline int PWM_RR_FROM_REG(int reg, int ix)
4978c2ecf20Sopenharmony_ci{
4988c2ecf20Sopenharmony_ci	int rr = (ix == 1) ? reg >> 4 : reg;
4998c2ecf20Sopenharmony_ci
5008c2ecf20Sopenharmony_ci	return (rr & 0x08) ? PWM_RR[rr & 0x07] : 0;
5018c2ecf20Sopenharmony_ci}
5028c2ecf20Sopenharmony_ci
5038c2ecf20Sopenharmony_cistatic int PWM_RR_TO_REG(long val, int ix, int reg)
5048c2ecf20Sopenharmony_ci{
5058c2ecf20Sopenharmony_ci	int i;
5068c2ecf20Sopenharmony_ci
5078c2ecf20Sopenharmony_ci	for (i = 0; i < 7; i++) {
5088c2ecf20Sopenharmony_ci		if (val > (PWM_RR[i] + PWM_RR[i + 1] + 1) / 2)
5098c2ecf20Sopenharmony_ci			break;
5108c2ecf20Sopenharmony_ci	}
5118c2ecf20Sopenharmony_ci
5128c2ecf20Sopenharmony_ci	return (ix == 1) ? (reg & 0x8f) | (i << 4) : (reg & 0xf8) | i;
5138c2ecf20Sopenharmony_ci}
5148c2ecf20Sopenharmony_ci
5158c2ecf20Sopenharmony_ci/* PWM ramp rate enable */
5168c2ecf20Sopenharmony_cistatic inline int PWM_RR_EN_FROM_REG(int reg, int ix)
5178c2ecf20Sopenharmony_ci{
5188c2ecf20Sopenharmony_ci	return PWM_RR_FROM_REG(reg, ix) ? 1 : 0;
5198c2ecf20Sopenharmony_ci}
5208c2ecf20Sopenharmony_ci
5218c2ecf20Sopenharmony_cistatic inline int PWM_RR_EN_TO_REG(long val, int ix, int reg)
5228c2ecf20Sopenharmony_ci{
5238c2ecf20Sopenharmony_ci	int en = (ix == 1) ? 0x80 : 0x08;
5248c2ecf20Sopenharmony_ci
5258c2ecf20Sopenharmony_ci	return val ? reg | en : reg & ~en;
5268c2ecf20Sopenharmony_ci}
5278c2ecf20Sopenharmony_ci
5288c2ecf20Sopenharmony_ci/*
5298c2ecf20Sopenharmony_ci * PWM min/off
5308c2ecf20Sopenharmony_ci * The PWM min/off bits are part of the PMW ramp rate register 0 (see above for
5318c2ecf20Sopenharmony_ci * the register layout).
5328c2ecf20Sopenharmony_ci */
5338c2ecf20Sopenharmony_cistatic inline int PWM_OFF_FROM_REG(int reg, int ix)
5348c2ecf20Sopenharmony_ci{
5358c2ecf20Sopenharmony_ci	return (reg >> (ix + 5)) & 0x01;
5368c2ecf20Sopenharmony_ci}
5378c2ecf20Sopenharmony_ci
5388c2ecf20Sopenharmony_cistatic inline int PWM_OFF_TO_REG(int val, int ix, int reg)
5398c2ecf20Sopenharmony_ci{
5408c2ecf20Sopenharmony_ci	return (reg & ~(1 << (ix + 5))) | ((val & 0x01) << (ix + 5));
5418c2ecf20Sopenharmony_ci}
5428c2ecf20Sopenharmony_ci
5438c2ecf20Sopenharmony_ci/* ---------------------------------------------------------------------
5448c2ecf20Sopenharmony_ci * Device I/O access
5458c2ecf20Sopenharmony_ci *
5468c2ecf20Sopenharmony_ci * ISA access is performed through an index/data register pair and needs to
5478c2ecf20Sopenharmony_ci * be protected by a mutex during runtime (not required for initialization).
5488c2ecf20Sopenharmony_ci * We use data->update_lock for this and need to ensure that we acquire it
5498c2ecf20Sopenharmony_ci * before calling dme1737_read or dme1737_write.
5508c2ecf20Sopenharmony_ci * --------------------------------------------------------------------- */
5518c2ecf20Sopenharmony_ci
5528c2ecf20Sopenharmony_cistatic u8 dme1737_read(const struct dme1737_data *data, u8 reg)
5538c2ecf20Sopenharmony_ci{
5548c2ecf20Sopenharmony_ci	struct i2c_client *client = data->client;
5558c2ecf20Sopenharmony_ci	s32 val;
5568c2ecf20Sopenharmony_ci
5578c2ecf20Sopenharmony_ci	if (client) { /* I2C device */
5588c2ecf20Sopenharmony_ci		val = i2c_smbus_read_byte_data(client, reg);
5598c2ecf20Sopenharmony_ci
5608c2ecf20Sopenharmony_ci		if (val < 0) {
5618c2ecf20Sopenharmony_ci			dev_warn(&client->dev,
5628c2ecf20Sopenharmony_ci				 "Read from register 0x%02x failed! %s\n",
5638c2ecf20Sopenharmony_ci				 reg, DO_REPORT);
5648c2ecf20Sopenharmony_ci		}
5658c2ecf20Sopenharmony_ci	} else { /* ISA device */
5668c2ecf20Sopenharmony_ci		outb(reg, data->addr);
5678c2ecf20Sopenharmony_ci		val = inb(data->addr + 1);
5688c2ecf20Sopenharmony_ci	}
5698c2ecf20Sopenharmony_ci
5708c2ecf20Sopenharmony_ci	return val;
5718c2ecf20Sopenharmony_ci}
5728c2ecf20Sopenharmony_ci
5738c2ecf20Sopenharmony_cistatic s32 dme1737_write(const struct dme1737_data *data, u8 reg, u8 val)
5748c2ecf20Sopenharmony_ci{
5758c2ecf20Sopenharmony_ci	struct i2c_client *client = data->client;
5768c2ecf20Sopenharmony_ci	s32 res = 0;
5778c2ecf20Sopenharmony_ci
5788c2ecf20Sopenharmony_ci	if (client) { /* I2C device */
5798c2ecf20Sopenharmony_ci		res = i2c_smbus_write_byte_data(client, reg, val);
5808c2ecf20Sopenharmony_ci
5818c2ecf20Sopenharmony_ci		if (res < 0) {
5828c2ecf20Sopenharmony_ci			dev_warn(&client->dev,
5838c2ecf20Sopenharmony_ci				 "Write to register 0x%02x failed! %s\n",
5848c2ecf20Sopenharmony_ci				 reg, DO_REPORT);
5858c2ecf20Sopenharmony_ci		}
5868c2ecf20Sopenharmony_ci	} else { /* ISA device */
5878c2ecf20Sopenharmony_ci		outb(reg, data->addr);
5888c2ecf20Sopenharmony_ci		outb(val, data->addr + 1);
5898c2ecf20Sopenharmony_ci	}
5908c2ecf20Sopenharmony_ci
5918c2ecf20Sopenharmony_ci	return res;
5928c2ecf20Sopenharmony_ci}
5938c2ecf20Sopenharmony_ci
5948c2ecf20Sopenharmony_cistatic struct dme1737_data *dme1737_update_device(struct device *dev)
5958c2ecf20Sopenharmony_ci{
5968c2ecf20Sopenharmony_ci	struct dme1737_data *data = dev_get_drvdata(dev);
5978c2ecf20Sopenharmony_ci	int ix;
5988c2ecf20Sopenharmony_ci	u8 lsb[6];
5998c2ecf20Sopenharmony_ci
6008c2ecf20Sopenharmony_ci	mutex_lock(&data->update_lock);
6018c2ecf20Sopenharmony_ci
6028c2ecf20Sopenharmony_ci	/* Enable a Vbat monitoring cycle every 10 mins */
6038c2ecf20Sopenharmony_ci	if (time_after(jiffies, data->last_vbat + 600 * HZ) || !data->valid) {
6048c2ecf20Sopenharmony_ci		dme1737_write(data, DME1737_REG_CONFIG, dme1737_read(data,
6058c2ecf20Sopenharmony_ci						DME1737_REG_CONFIG) | 0x10);
6068c2ecf20Sopenharmony_ci		data->last_vbat = jiffies;
6078c2ecf20Sopenharmony_ci	}
6088c2ecf20Sopenharmony_ci
6098c2ecf20Sopenharmony_ci	/* Sample register contents every 1 sec */
6108c2ecf20Sopenharmony_ci	if (time_after(jiffies, data->last_update + HZ) || !data->valid) {
6118c2ecf20Sopenharmony_ci		if (data->has_features & HAS_VID) {
6128c2ecf20Sopenharmony_ci			data->vid = dme1737_read(data, DME1737_REG_VID) &
6138c2ecf20Sopenharmony_ci				0x3f;
6148c2ecf20Sopenharmony_ci		}
6158c2ecf20Sopenharmony_ci
6168c2ecf20Sopenharmony_ci		/* In (voltage) registers */
6178c2ecf20Sopenharmony_ci		for (ix = 0; ix < ARRAY_SIZE(data->in); ix++) {
6188c2ecf20Sopenharmony_ci			/*
6198c2ecf20Sopenharmony_ci			 * Voltage inputs are stored as 16 bit values even
6208c2ecf20Sopenharmony_ci			 * though they have only 12 bits resolution. This is
6218c2ecf20Sopenharmony_ci			 * to make it consistent with the temp inputs.
6228c2ecf20Sopenharmony_ci			 */
6238c2ecf20Sopenharmony_ci			if (ix == 7 && !(data->has_features & HAS_IN7))
6248c2ecf20Sopenharmony_ci				continue;
6258c2ecf20Sopenharmony_ci			data->in[ix] = dme1737_read(data,
6268c2ecf20Sopenharmony_ci					DME1737_REG_IN(ix)) << 8;
6278c2ecf20Sopenharmony_ci			data->in_min[ix] = dme1737_read(data,
6288c2ecf20Sopenharmony_ci					DME1737_REG_IN_MIN(ix));
6298c2ecf20Sopenharmony_ci			data->in_max[ix] = dme1737_read(data,
6308c2ecf20Sopenharmony_ci					DME1737_REG_IN_MAX(ix));
6318c2ecf20Sopenharmony_ci		}
6328c2ecf20Sopenharmony_ci
6338c2ecf20Sopenharmony_ci		/* Temp registers */
6348c2ecf20Sopenharmony_ci		for (ix = 0; ix < ARRAY_SIZE(data->temp); ix++) {
6358c2ecf20Sopenharmony_ci			/*
6368c2ecf20Sopenharmony_ci			 * Temp inputs are stored as 16 bit values even
6378c2ecf20Sopenharmony_ci			 * though they have only 12 bits resolution. This is
6388c2ecf20Sopenharmony_ci			 * to take advantage of implicit conversions between
6398c2ecf20Sopenharmony_ci			 * register values (2's complement) and temp values
6408c2ecf20Sopenharmony_ci			 * (signed decimal).
6418c2ecf20Sopenharmony_ci			 */
6428c2ecf20Sopenharmony_ci			data->temp[ix] = dme1737_read(data,
6438c2ecf20Sopenharmony_ci					DME1737_REG_TEMP(ix)) << 8;
6448c2ecf20Sopenharmony_ci			data->temp_min[ix] = dme1737_read(data,
6458c2ecf20Sopenharmony_ci					DME1737_REG_TEMP_MIN(ix));
6468c2ecf20Sopenharmony_ci			data->temp_max[ix] = dme1737_read(data,
6478c2ecf20Sopenharmony_ci					DME1737_REG_TEMP_MAX(ix));
6488c2ecf20Sopenharmony_ci			if (data->has_features & HAS_TEMP_OFFSET) {
6498c2ecf20Sopenharmony_ci				data->temp_offset[ix] = dme1737_read(data,
6508c2ecf20Sopenharmony_ci						DME1737_REG_TEMP_OFFSET(ix));
6518c2ecf20Sopenharmony_ci			}
6528c2ecf20Sopenharmony_ci		}
6538c2ecf20Sopenharmony_ci
6548c2ecf20Sopenharmony_ci		/*
6558c2ecf20Sopenharmony_ci		 * In and temp LSB registers
6568c2ecf20Sopenharmony_ci		 * The LSBs are latched when the MSBs are read, so the order in
6578c2ecf20Sopenharmony_ci		 * which the registers are read (MSB first, then LSB) is
6588c2ecf20Sopenharmony_ci		 * important!
6598c2ecf20Sopenharmony_ci		 */
6608c2ecf20Sopenharmony_ci		for (ix = 0; ix < ARRAY_SIZE(lsb); ix++) {
6618c2ecf20Sopenharmony_ci			if (ix == 5 && !(data->has_features & HAS_IN7))
6628c2ecf20Sopenharmony_ci				continue;
6638c2ecf20Sopenharmony_ci			lsb[ix] = dme1737_read(data,
6648c2ecf20Sopenharmony_ci					DME1737_REG_IN_TEMP_LSB(ix));
6658c2ecf20Sopenharmony_ci		}
6668c2ecf20Sopenharmony_ci		for (ix = 0; ix < ARRAY_SIZE(data->in); ix++) {
6678c2ecf20Sopenharmony_ci			if (ix == 7 && !(data->has_features & HAS_IN7))
6688c2ecf20Sopenharmony_ci				continue;
6698c2ecf20Sopenharmony_ci			data->in[ix] |= (lsb[DME1737_REG_IN_LSB[ix]] <<
6708c2ecf20Sopenharmony_ci					DME1737_REG_IN_LSB_SHL[ix]) & 0xf0;
6718c2ecf20Sopenharmony_ci		}
6728c2ecf20Sopenharmony_ci		for (ix = 0; ix < ARRAY_SIZE(data->temp); ix++) {
6738c2ecf20Sopenharmony_ci			data->temp[ix] |= (lsb[DME1737_REG_TEMP_LSB[ix]] <<
6748c2ecf20Sopenharmony_ci					DME1737_REG_TEMP_LSB_SHL[ix]) & 0xf0;
6758c2ecf20Sopenharmony_ci		}
6768c2ecf20Sopenharmony_ci
6778c2ecf20Sopenharmony_ci		/* Fan registers */
6788c2ecf20Sopenharmony_ci		for (ix = 0; ix < ARRAY_SIZE(data->fan); ix++) {
6798c2ecf20Sopenharmony_ci			/*
6808c2ecf20Sopenharmony_ci			 * Skip reading registers if optional fans are not
6818c2ecf20Sopenharmony_ci			 * present
6828c2ecf20Sopenharmony_ci			 */
6838c2ecf20Sopenharmony_ci			if (!(data->has_features & HAS_FAN(ix)))
6848c2ecf20Sopenharmony_ci				continue;
6858c2ecf20Sopenharmony_ci			data->fan[ix] = dme1737_read(data,
6868c2ecf20Sopenharmony_ci					DME1737_REG_FAN(ix));
6878c2ecf20Sopenharmony_ci			data->fan[ix] |= dme1737_read(data,
6888c2ecf20Sopenharmony_ci					DME1737_REG_FAN(ix) + 1) << 8;
6898c2ecf20Sopenharmony_ci			data->fan_min[ix] = dme1737_read(data,
6908c2ecf20Sopenharmony_ci					DME1737_REG_FAN_MIN(ix));
6918c2ecf20Sopenharmony_ci			data->fan_min[ix] |= dme1737_read(data,
6928c2ecf20Sopenharmony_ci					DME1737_REG_FAN_MIN(ix) + 1) << 8;
6938c2ecf20Sopenharmony_ci			data->fan_opt[ix] = dme1737_read(data,
6948c2ecf20Sopenharmony_ci					DME1737_REG_FAN_OPT(ix));
6958c2ecf20Sopenharmony_ci			/* fan_max exists only for fan[5-6] */
6968c2ecf20Sopenharmony_ci			if (ix > 3) {
6978c2ecf20Sopenharmony_ci				data->fan_max[ix - 4] = dme1737_read(data,
6988c2ecf20Sopenharmony_ci					DME1737_REG_FAN_MAX(ix));
6998c2ecf20Sopenharmony_ci			}
7008c2ecf20Sopenharmony_ci		}
7018c2ecf20Sopenharmony_ci
7028c2ecf20Sopenharmony_ci		/* PWM registers */
7038c2ecf20Sopenharmony_ci		for (ix = 0; ix < ARRAY_SIZE(data->pwm); ix++) {
7048c2ecf20Sopenharmony_ci			/*
7058c2ecf20Sopenharmony_ci			 * Skip reading registers if optional PWMs are not
7068c2ecf20Sopenharmony_ci			 * present
7078c2ecf20Sopenharmony_ci			 */
7088c2ecf20Sopenharmony_ci			if (!(data->has_features & HAS_PWM(ix)))
7098c2ecf20Sopenharmony_ci				continue;
7108c2ecf20Sopenharmony_ci			data->pwm[ix] = dme1737_read(data,
7118c2ecf20Sopenharmony_ci					DME1737_REG_PWM(ix));
7128c2ecf20Sopenharmony_ci			data->pwm_freq[ix] = dme1737_read(data,
7138c2ecf20Sopenharmony_ci					DME1737_REG_PWM_FREQ(ix));
7148c2ecf20Sopenharmony_ci			/* pwm_config and pwm_min exist only for pwm[1-3] */
7158c2ecf20Sopenharmony_ci			if (ix < 3) {
7168c2ecf20Sopenharmony_ci				data->pwm_config[ix] = dme1737_read(data,
7178c2ecf20Sopenharmony_ci						DME1737_REG_PWM_CONFIG(ix));
7188c2ecf20Sopenharmony_ci				data->pwm_min[ix] = dme1737_read(data,
7198c2ecf20Sopenharmony_ci						DME1737_REG_PWM_MIN(ix));
7208c2ecf20Sopenharmony_ci			}
7218c2ecf20Sopenharmony_ci		}
7228c2ecf20Sopenharmony_ci		for (ix = 0; ix < ARRAY_SIZE(data->pwm_rr); ix++) {
7238c2ecf20Sopenharmony_ci			data->pwm_rr[ix] = dme1737_read(data,
7248c2ecf20Sopenharmony_ci						DME1737_REG_PWM_RR(ix));
7258c2ecf20Sopenharmony_ci		}
7268c2ecf20Sopenharmony_ci
7278c2ecf20Sopenharmony_ci		/* Thermal zone registers */
7288c2ecf20Sopenharmony_ci		for (ix = 0; ix < ARRAY_SIZE(data->zone_low); ix++) {
7298c2ecf20Sopenharmony_ci			/* Skip reading registers if zone3 is not present */
7308c2ecf20Sopenharmony_ci			if ((ix == 2) && !(data->has_features & HAS_ZONE3))
7318c2ecf20Sopenharmony_ci				continue;
7328c2ecf20Sopenharmony_ci			/* sch5127 zone2 registers are special */
7338c2ecf20Sopenharmony_ci			if ((ix == 1) && (data->type == sch5127)) {
7348c2ecf20Sopenharmony_ci				data->zone_low[1] = dme1737_read(data,
7358c2ecf20Sopenharmony_ci						DME1737_REG_ZONE_LOW(2));
7368c2ecf20Sopenharmony_ci				data->zone_abs[1] = dme1737_read(data,
7378c2ecf20Sopenharmony_ci						DME1737_REG_ZONE_ABS(2));
7388c2ecf20Sopenharmony_ci			} else {
7398c2ecf20Sopenharmony_ci				data->zone_low[ix] = dme1737_read(data,
7408c2ecf20Sopenharmony_ci						DME1737_REG_ZONE_LOW(ix));
7418c2ecf20Sopenharmony_ci				data->zone_abs[ix] = dme1737_read(data,
7428c2ecf20Sopenharmony_ci						DME1737_REG_ZONE_ABS(ix));
7438c2ecf20Sopenharmony_ci			}
7448c2ecf20Sopenharmony_ci		}
7458c2ecf20Sopenharmony_ci		if (data->has_features & HAS_ZONE_HYST) {
7468c2ecf20Sopenharmony_ci			for (ix = 0; ix < ARRAY_SIZE(data->zone_hyst); ix++) {
7478c2ecf20Sopenharmony_ci				data->zone_hyst[ix] = dme1737_read(data,
7488c2ecf20Sopenharmony_ci						DME1737_REG_ZONE_HYST(ix));
7498c2ecf20Sopenharmony_ci			}
7508c2ecf20Sopenharmony_ci		}
7518c2ecf20Sopenharmony_ci
7528c2ecf20Sopenharmony_ci		/* Alarm registers */
7538c2ecf20Sopenharmony_ci		data->alarms = dme1737_read(data,
7548c2ecf20Sopenharmony_ci						DME1737_REG_ALARM1);
7558c2ecf20Sopenharmony_ci		/*
7568c2ecf20Sopenharmony_ci		 * Bit 7 tells us if the other alarm registers are non-zero and
7578c2ecf20Sopenharmony_ci		 * therefore also need to be read
7588c2ecf20Sopenharmony_ci		 */
7598c2ecf20Sopenharmony_ci		if (data->alarms & 0x80) {
7608c2ecf20Sopenharmony_ci			data->alarms |= dme1737_read(data,
7618c2ecf20Sopenharmony_ci						DME1737_REG_ALARM2) << 8;
7628c2ecf20Sopenharmony_ci			data->alarms |= dme1737_read(data,
7638c2ecf20Sopenharmony_ci						DME1737_REG_ALARM3) << 16;
7648c2ecf20Sopenharmony_ci		}
7658c2ecf20Sopenharmony_ci
7668c2ecf20Sopenharmony_ci		/*
7678c2ecf20Sopenharmony_ci		 * The ISA chips require explicit clearing of alarm bits.
7688c2ecf20Sopenharmony_ci		 * Don't worry, an alarm will come back if the condition
7698c2ecf20Sopenharmony_ci		 * that causes it still exists
7708c2ecf20Sopenharmony_ci		 */
7718c2ecf20Sopenharmony_ci		if (!data->client) {
7728c2ecf20Sopenharmony_ci			if (data->alarms & 0xff0000)
7738c2ecf20Sopenharmony_ci				dme1737_write(data, DME1737_REG_ALARM3, 0xff);
7748c2ecf20Sopenharmony_ci			if (data->alarms & 0xff00)
7758c2ecf20Sopenharmony_ci				dme1737_write(data, DME1737_REG_ALARM2, 0xff);
7768c2ecf20Sopenharmony_ci			if (data->alarms & 0xff)
7778c2ecf20Sopenharmony_ci				dme1737_write(data, DME1737_REG_ALARM1, 0xff);
7788c2ecf20Sopenharmony_ci		}
7798c2ecf20Sopenharmony_ci
7808c2ecf20Sopenharmony_ci		data->last_update = jiffies;
7818c2ecf20Sopenharmony_ci		data->valid = 1;
7828c2ecf20Sopenharmony_ci	}
7838c2ecf20Sopenharmony_ci
7848c2ecf20Sopenharmony_ci	mutex_unlock(&data->update_lock);
7858c2ecf20Sopenharmony_ci
7868c2ecf20Sopenharmony_ci	return data;
7878c2ecf20Sopenharmony_ci}
7888c2ecf20Sopenharmony_ci
7898c2ecf20Sopenharmony_ci/* ---------------------------------------------------------------------
7908c2ecf20Sopenharmony_ci * Voltage sysfs attributes
7918c2ecf20Sopenharmony_ci * ix = [0-7]
7928c2ecf20Sopenharmony_ci * --------------------------------------------------------------------- */
7938c2ecf20Sopenharmony_ci
7948c2ecf20Sopenharmony_ci#define SYS_IN_INPUT	0
7958c2ecf20Sopenharmony_ci#define SYS_IN_MIN	1
7968c2ecf20Sopenharmony_ci#define SYS_IN_MAX	2
7978c2ecf20Sopenharmony_ci#define SYS_IN_ALARM	3
7988c2ecf20Sopenharmony_ci
7998c2ecf20Sopenharmony_cistatic ssize_t show_in(struct device *dev, struct device_attribute *attr,
8008c2ecf20Sopenharmony_ci		       char *buf)
8018c2ecf20Sopenharmony_ci{
8028c2ecf20Sopenharmony_ci	struct dme1737_data *data = dme1737_update_device(dev);
8038c2ecf20Sopenharmony_ci	struct sensor_device_attribute_2
8048c2ecf20Sopenharmony_ci		*sensor_attr_2 = to_sensor_dev_attr_2(attr);
8058c2ecf20Sopenharmony_ci	int ix = sensor_attr_2->index;
8068c2ecf20Sopenharmony_ci	int fn = sensor_attr_2->nr;
8078c2ecf20Sopenharmony_ci	int res;
8088c2ecf20Sopenharmony_ci
8098c2ecf20Sopenharmony_ci	switch (fn) {
8108c2ecf20Sopenharmony_ci	case SYS_IN_INPUT:
8118c2ecf20Sopenharmony_ci		res = IN_FROM_REG(data->in[ix], data->in_nominal[ix], 16);
8128c2ecf20Sopenharmony_ci		break;
8138c2ecf20Sopenharmony_ci	case SYS_IN_MIN:
8148c2ecf20Sopenharmony_ci		res = IN_FROM_REG(data->in_min[ix], data->in_nominal[ix], 8);
8158c2ecf20Sopenharmony_ci		break;
8168c2ecf20Sopenharmony_ci	case SYS_IN_MAX:
8178c2ecf20Sopenharmony_ci		res = IN_FROM_REG(data->in_max[ix], data->in_nominal[ix], 8);
8188c2ecf20Sopenharmony_ci		break;
8198c2ecf20Sopenharmony_ci	case SYS_IN_ALARM:
8208c2ecf20Sopenharmony_ci		res = (data->alarms >> DME1737_BIT_ALARM_IN[ix]) & 0x01;
8218c2ecf20Sopenharmony_ci		break;
8228c2ecf20Sopenharmony_ci	default:
8238c2ecf20Sopenharmony_ci		res = 0;
8248c2ecf20Sopenharmony_ci		dev_dbg(dev, "Unknown function %d.\n", fn);
8258c2ecf20Sopenharmony_ci	}
8268c2ecf20Sopenharmony_ci
8278c2ecf20Sopenharmony_ci	return sprintf(buf, "%d\n", res);
8288c2ecf20Sopenharmony_ci}
8298c2ecf20Sopenharmony_ci
8308c2ecf20Sopenharmony_cistatic ssize_t set_in(struct device *dev, struct device_attribute *attr,
8318c2ecf20Sopenharmony_ci		      const char *buf, size_t count)
8328c2ecf20Sopenharmony_ci{
8338c2ecf20Sopenharmony_ci	struct dme1737_data *data = dev_get_drvdata(dev);
8348c2ecf20Sopenharmony_ci	struct sensor_device_attribute_2
8358c2ecf20Sopenharmony_ci		*sensor_attr_2 = to_sensor_dev_attr_2(attr);
8368c2ecf20Sopenharmony_ci	int ix = sensor_attr_2->index;
8378c2ecf20Sopenharmony_ci	int fn = sensor_attr_2->nr;
8388c2ecf20Sopenharmony_ci	long val;
8398c2ecf20Sopenharmony_ci	int err;
8408c2ecf20Sopenharmony_ci
8418c2ecf20Sopenharmony_ci	err = kstrtol(buf, 10, &val);
8428c2ecf20Sopenharmony_ci	if (err)
8438c2ecf20Sopenharmony_ci		return err;
8448c2ecf20Sopenharmony_ci
8458c2ecf20Sopenharmony_ci	mutex_lock(&data->update_lock);
8468c2ecf20Sopenharmony_ci	switch (fn) {
8478c2ecf20Sopenharmony_ci	case SYS_IN_MIN:
8488c2ecf20Sopenharmony_ci		data->in_min[ix] = IN_TO_REG(val, data->in_nominal[ix]);
8498c2ecf20Sopenharmony_ci		dme1737_write(data, DME1737_REG_IN_MIN(ix),
8508c2ecf20Sopenharmony_ci			      data->in_min[ix]);
8518c2ecf20Sopenharmony_ci		break;
8528c2ecf20Sopenharmony_ci	case SYS_IN_MAX:
8538c2ecf20Sopenharmony_ci		data->in_max[ix] = IN_TO_REG(val, data->in_nominal[ix]);
8548c2ecf20Sopenharmony_ci		dme1737_write(data, DME1737_REG_IN_MAX(ix),
8558c2ecf20Sopenharmony_ci			      data->in_max[ix]);
8568c2ecf20Sopenharmony_ci		break;
8578c2ecf20Sopenharmony_ci	default:
8588c2ecf20Sopenharmony_ci		dev_dbg(dev, "Unknown function %d.\n", fn);
8598c2ecf20Sopenharmony_ci	}
8608c2ecf20Sopenharmony_ci	mutex_unlock(&data->update_lock);
8618c2ecf20Sopenharmony_ci
8628c2ecf20Sopenharmony_ci	return count;
8638c2ecf20Sopenharmony_ci}
8648c2ecf20Sopenharmony_ci
8658c2ecf20Sopenharmony_ci/* ---------------------------------------------------------------------
8668c2ecf20Sopenharmony_ci * Temperature sysfs attributes
8678c2ecf20Sopenharmony_ci * ix = [0-2]
8688c2ecf20Sopenharmony_ci * --------------------------------------------------------------------- */
8698c2ecf20Sopenharmony_ci
8708c2ecf20Sopenharmony_ci#define SYS_TEMP_INPUT			0
8718c2ecf20Sopenharmony_ci#define SYS_TEMP_MIN			1
8728c2ecf20Sopenharmony_ci#define SYS_TEMP_MAX			2
8738c2ecf20Sopenharmony_ci#define SYS_TEMP_OFFSET			3
8748c2ecf20Sopenharmony_ci#define SYS_TEMP_ALARM			4
8758c2ecf20Sopenharmony_ci#define SYS_TEMP_FAULT			5
8768c2ecf20Sopenharmony_ci
8778c2ecf20Sopenharmony_cistatic ssize_t show_temp(struct device *dev, struct device_attribute *attr,
8788c2ecf20Sopenharmony_ci			 char *buf)
8798c2ecf20Sopenharmony_ci{
8808c2ecf20Sopenharmony_ci	struct dme1737_data *data = dme1737_update_device(dev);
8818c2ecf20Sopenharmony_ci	struct sensor_device_attribute_2
8828c2ecf20Sopenharmony_ci		*sensor_attr_2 = to_sensor_dev_attr_2(attr);
8838c2ecf20Sopenharmony_ci	int ix = sensor_attr_2->index;
8848c2ecf20Sopenharmony_ci	int fn = sensor_attr_2->nr;
8858c2ecf20Sopenharmony_ci	int res;
8868c2ecf20Sopenharmony_ci
8878c2ecf20Sopenharmony_ci	switch (fn) {
8888c2ecf20Sopenharmony_ci	case SYS_TEMP_INPUT:
8898c2ecf20Sopenharmony_ci		res = TEMP_FROM_REG(data->temp[ix], 16);
8908c2ecf20Sopenharmony_ci		break;
8918c2ecf20Sopenharmony_ci	case SYS_TEMP_MIN:
8928c2ecf20Sopenharmony_ci		res = TEMP_FROM_REG(data->temp_min[ix], 8);
8938c2ecf20Sopenharmony_ci		break;
8948c2ecf20Sopenharmony_ci	case SYS_TEMP_MAX:
8958c2ecf20Sopenharmony_ci		res = TEMP_FROM_REG(data->temp_max[ix], 8);
8968c2ecf20Sopenharmony_ci		break;
8978c2ecf20Sopenharmony_ci	case SYS_TEMP_OFFSET:
8988c2ecf20Sopenharmony_ci		res = TEMP_FROM_REG(data->temp_offset[ix], 8);
8998c2ecf20Sopenharmony_ci		break;
9008c2ecf20Sopenharmony_ci	case SYS_TEMP_ALARM:
9018c2ecf20Sopenharmony_ci		res = (data->alarms >> DME1737_BIT_ALARM_TEMP[ix]) & 0x01;
9028c2ecf20Sopenharmony_ci		break;
9038c2ecf20Sopenharmony_ci	case SYS_TEMP_FAULT:
9048c2ecf20Sopenharmony_ci		res = (((u16)data->temp[ix] & 0xff00) == 0x8000);
9058c2ecf20Sopenharmony_ci		break;
9068c2ecf20Sopenharmony_ci	default:
9078c2ecf20Sopenharmony_ci		res = 0;
9088c2ecf20Sopenharmony_ci		dev_dbg(dev, "Unknown function %d.\n", fn);
9098c2ecf20Sopenharmony_ci	}
9108c2ecf20Sopenharmony_ci
9118c2ecf20Sopenharmony_ci	return sprintf(buf, "%d\n", res);
9128c2ecf20Sopenharmony_ci}
9138c2ecf20Sopenharmony_ci
9148c2ecf20Sopenharmony_cistatic ssize_t set_temp(struct device *dev, struct device_attribute *attr,
9158c2ecf20Sopenharmony_ci			const char *buf, size_t count)
9168c2ecf20Sopenharmony_ci{
9178c2ecf20Sopenharmony_ci	struct dme1737_data *data = dev_get_drvdata(dev);
9188c2ecf20Sopenharmony_ci	struct sensor_device_attribute_2
9198c2ecf20Sopenharmony_ci		*sensor_attr_2 = to_sensor_dev_attr_2(attr);
9208c2ecf20Sopenharmony_ci	int ix = sensor_attr_2->index;
9218c2ecf20Sopenharmony_ci	int fn = sensor_attr_2->nr;
9228c2ecf20Sopenharmony_ci	long val;
9238c2ecf20Sopenharmony_ci	int err;
9248c2ecf20Sopenharmony_ci
9258c2ecf20Sopenharmony_ci	err = kstrtol(buf, 10, &val);
9268c2ecf20Sopenharmony_ci	if (err)
9278c2ecf20Sopenharmony_ci		return err;
9288c2ecf20Sopenharmony_ci
9298c2ecf20Sopenharmony_ci	mutex_lock(&data->update_lock);
9308c2ecf20Sopenharmony_ci	switch (fn) {
9318c2ecf20Sopenharmony_ci	case SYS_TEMP_MIN:
9328c2ecf20Sopenharmony_ci		data->temp_min[ix] = TEMP_TO_REG(val);
9338c2ecf20Sopenharmony_ci		dme1737_write(data, DME1737_REG_TEMP_MIN(ix),
9348c2ecf20Sopenharmony_ci			      data->temp_min[ix]);
9358c2ecf20Sopenharmony_ci		break;
9368c2ecf20Sopenharmony_ci	case SYS_TEMP_MAX:
9378c2ecf20Sopenharmony_ci		data->temp_max[ix] = TEMP_TO_REG(val);
9388c2ecf20Sopenharmony_ci		dme1737_write(data, DME1737_REG_TEMP_MAX(ix),
9398c2ecf20Sopenharmony_ci			      data->temp_max[ix]);
9408c2ecf20Sopenharmony_ci		break;
9418c2ecf20Sopenharmony_ci	case SYS_TEMP_OFFSET:
9428c2ecf20Sopenharmony_ci		data->temp_offset[ix] = TEMP_TO_REG(val);
9438c2ecf20Sopenharmony_ci		dme1737_write(data, DME1737_REG_TEMP_OFFSET(ix),
9448c2ecf20Sopenharmony_ci			      data->temp_offset[ix]);
9458c2ecf20Sopenharmony_ci		break;
9468c2ecf20Sopenharmony_ci	default:
9478c2ecf20Sopenharmony_ci		dev_dbg(dev, "Unknown function %d.\n", fn);
9488c2ecf20Sopenharmony_ci	}
9498c2ecf20Sopenharmony_ci	mutex_unlock(&data->update_lock);
9508c2ecf20Sopenharmony_ci
9518c2ecf20Sopenharmony_ci	return count;
9528c2ecf20Sopenharmony_ci}
9538c2ecf20Sopenharmony_ci
9548c2ecf20Sopenharmony_ci/* ---------------------------------------------------------------------
9558c2ecf20Sopenharmony_ci * Zone sysfs attributes
9568c2ecf20Sopenharmony_ci * ix = [0-2]
9578c2ecf20Sopenharmony_ci * --------------------------------------------------------------------- */
9588c2ecf20Sopenharmony_ci
9598c2ecf20Sopenharmony_ci#define SYS_ZONE_AUTO_CHANNELS_TEMP	0
9608c2ecf20Sopenharmony_ci#define SYS_ZONE_AUTO_POINT1_TEMP_HYST	1
9618c2ecf20Sopenharmony_ci#define SYS_ZONE_AUTO_POINT1_TEMP	2
9628c2ecf20Sopenharmony_ci#define SYS_ZONE_AUTO_POINT2_TEMP	3
9638c2ecf20Sopenharmony_ci#define SYS_ZONE_AUTO_POINT3_TEMP	4
9648c2ecf20Sopenharmony_ci
9658c2ecf20Sopenharmony_cistatic ssize_t show_zone(struct device *dev, struct device_attribute *attr,
9668c2ecf20Sopenharmony_ci			 char *buf)
9678c2ecf20Sopenharmony_ci{
9688c2ecf20Sopenharmony_ci	struct dme1737_data *data = dme1737_update_device(dev);
9698c2ecf20Sopenharmony_ci	struct sensor_device_attribute_2
9708c2ecf20Sopenharmony_ci		*sensor_attr_2 = to_sensor_dev_attr_2(attr);
9718c2ecf20Sopenharmony_ci	int ix = sensor_attr_2->index;
9728c2ecf20Sopenharmony_ci	int fn = sensor_attr_2->nr;
9738c2ecf20Sopenharmony_ci	int res;
9748c2ecf20Sopenharmony_ci
9758c2ecf20Sopenharmony_ci	switch (fn) {
9768c2ecf20Sopenharmony_ci	case SYS_ZONE_AUTO_CHANNELS_TEMP:
9778c2ecf20Sopenharmony_ci		/* check config2 for non-standard temp-to-zone mapping */
9788c2ecf20Sopenharmony_ci		if ((ix == 1) && (data->config2 & 0x02))
9798c2ecf20Sopenharmony_ci			res = 4;
9808c2ecf20Sopenharmony_ci		else
9818c2ecf20Sopenharmony_ci			res = 1 << ix;
9828c2ecf20Sopenharmony_ci		break;
9838c2ecf20Sopenharmony_ci	case SYS_ZONE_AUTO_POINT1_TEMP_HYST:
9848c2ecf20Sopenharmony_ci		res = TEMP_FROM_REG(data->zone_low[ix], 8) -
9858c2ecf20Sopenharmony_ci		      TEMP_HYST_FROM_REG(data->zone_hyst[ix == 2], ix);
9868c2ecf20Sopenharmony_ci		break;
9878c2ecf20Sopenharmony_ci	case SYS_ZONE_AUTO_POINT1_TEMP:
9888c2ecf20Sopenharmony_ci		res = TEMP_FROM_REG(data->zone_low[ix], 8);
9898c2ecf20Sopenharmony_ci		break;
9908c2ecf20Sopenharmony_ci	case SYS_ZONE_AUTO_POINT2_TEMP:
9918c2ecf20Sopenharmony_ci		/* pwm_freq holds the temp range bits in the upper nibble */
9928c2ecf20Sopenharmony_ci		res = TEMP_FROM_REG(data->zone_low[ix], 8) +
9938c2ecf20Sopenharmony_ci		      TEMP_RANGE_FROM_REG(data->pwm_freq[ix]);
9948c2ecf20Sopenharmony_ci		break;
9958c2ecf20Sopenharmony_ci	case SYS_ZONE_AUTO_POINT3_TEMP:
9968c2ecf20Sopenharmony_ci		res = TEMP_FROM_REG(data->zone_abs[ix], 8);
9978c2ecf20Sopenharmony_ci		break;
9988c2ecf20Sopenharmony_ci	default:
9998c2ecf20Sopenharmony_ci		res = 0;
10008c2ecf20Sopenharmony_ci		dev_dbg(dev, "Unknown function %d.\n", fn);
10018c2ecf20Sopenharmony_ci	}
10028c2ecf20Sopenharmony_ci
10038c2ecf20Sopenharmony_ci	return sprintf(buf, "%d\n", res);
10048c2ecf20Sopenharmony_ci}
10058c2ecf20Sopenharmony_ci
10068c2ecf20Sopenharmony_cistatic ssize_t set_zone(struct device *dev, struct device_attribute *attr,
10078c2ecf20Sopenharmony_ci			const char *buf, size_t count)
10088c2ecf20Sopenharmony_ci{
10098c2ecf20Sopenharmony_ci	struct dme1737_data *data = dev_get_drvdata(dev);
10108c2ecf20Sopenharmony_ci	struct sensor_device_attribute_2
10118c2ecf20Sopenharmony_ci		*sensor_attr_2 = to_sensor_dev_attr_2(attr);
10128c2ecf20Sopenharmony_ci	int ix = sensor_attr_2->index;
10138c2ecf20Sopenharmony_ci	int fn = sensor_attr_2->nr;
10148c2ecf20Sopenharmony_ci	long val;
10158c2ecf20Sopenharmony_ci	int temp;
10168c2ecf20Sopenharmony_ci	int err;
10178c2ecf20Sopenharmony_ci	u8 reg;
10188c2ecf20Sopenharmony_ci
10198c2ecf20Sopenharmony_ci	err = kstrtol(buf, 10, &val);
10208c2ecf20Sopenharmony_ci	if (err)
10218c2ecf20Sopenharmony_ci		return err;
10228c2ecf20Sopenharmony_ci
10238c2ecf20Sopenharmony_ci	mutex_lock(&data->update_lock);
10248c2ecf20Sopenharmony_ci	switch (fn) {
10258c2ecf20Sopenharmony_ci	case SYS_ZONE_AUTO_POINT1_TEMP_HYST:
10268c2ecf20Sopenharmony_ci		/* Refresh the cache */
10278c2ecf20Sopenharmony_ci		data->zone_low[ix] = dme1737_read(data,
10288c2ecf20Sopenharmony_ci						  DME1737_REG_ZONE_LOW(ix));
10298c2ecf20Sopenharmony_ci		/* Modify the temp hyst value */
10308c2ecf20Sopenharmony_ci		temp = TEMP_FROM_REG(data->zone_low[ix], 8);
10318c2ecf20Sopenharmony_ci		reg = dme1737_read(data, DME1737_REG_ZONE_HYST(ix == 2));
10328c2ecf20Sopenharmony_ci		data->zone_hyst[ix == 2] = TEMP_HYST_TO_REG(temp, val, ix, reg);
10338c2ecf20Sopenharmony_ci		dme1737_write(data, DME1737_REG_ZONE_HYST(ix == 2),
10348c2ecf20Sopenharmony_ci			      data->zone_hyst[ix == 2]);
10358c2ecf20Sopenharmony_ci		break;
10368c2ecf20Sopenharmony_ci	case SYS_ZONE_AUTO_POINT1_TEMP:
10378c2ecf20Sopenharmony_ci		data->zone_low[ix] = TEMP_TO_REG(val);
10388c2ecf20Sopenharmony_ci		dme1737_write(data, DME1737_REG_ZONE_LOW(ix),
10398c2ecf20Sopenharmony_ci			      data->zone_low[ix]);
10408c2ecf20Sopenharmony_ci		break;
10418c2ecf20Sopenharmony_ci	case SYS_ZONE_AUTO_POINT2_TEMP:
10428c2ecf20Sopenharmony_ci		/* Refresh the cache */
10438c2ecf20Sopenharmony_ci		data->zone_low[ix] = dme1737_read(data,
10448c2ecf20Sopenharmony_ci						  DME1737_REG_ZONE_LOW(ix));
10458c2ecf20Sopenharmony_ci		/*
10468c2ecf20Sopenharmony_ci		 * Modify the temp range value (which is stored in the upper
10478c2ecf20Sopenharmony_ci		 * nibble of the pwm_freq register)
10488c2ecf20Sopenharmony_ci		 */
10498c2ecf20Sopenharmony_ci		temp = TEMP_FROM_REG(data->zone_low[ix], 8);
10508c2ecf20Sopenharmony_ci		val = clamp_val(val, temp, temp + 80000);
10518c2ecf20Sopenharmony_ci		reg = dme1737_read(data, DME1737_REG_PWM_FREQ(ix));
10528c2ecf20Sopenharmony_ci		data->pwm_freq[ix] = TEMP_RANGE_TO_REG(val - temp, reg);
10538c2ecf20Sopenharmony_ci		dme1737_write(data, DME1737_REG_PWM_FREQ(ix),
10548c2ecf20Sopenharmony_ci			      data->pwm_freq[ix]);
10558c2ecf20Sopenharmony_ci		break;
10568c2ecf20Sopenharmony_ci	case SYS_ZONE_AUTO_POINT3_TEMP:
10578c2ecf20Sopenharmony_ci		data->zone_abs[ix] = TEMP_TO_REG(val);
10588c2ecf20Sopenharmony_ci		dme1737_write(data, DME1737_REG_ZONE_ABS(ix),
10598c2ecf20Sopenharmony_ci			      data->zone_abs[ix]);
10608c2ecf20Sopenharmony_ci		break;
10618c2ecf20Sopenharmony_ci	default:
10628c2ecf20Sopenharmony_ci		dev_dbg(dev, "Unknown function %d.\n", fn);
10638c2ecf20Sopenharmony_ci	}
10648c2ecf20Sopenharmony_ci	mutex_unlock(&data->update_lock);
10658c2ecf20Sopenharmony_ci
10668c2ecf20Sopenharmony_ci	return count;
10678c2ecf20Sopenharmony_ci}
10688c2ecf20Sopenharmony_ci
10698c2ecf20Sopenharmony_ci/* ---------------------------------------------------------------------
10708c2ecf20Sopenharmony_ci * Fan sysfs attributes
10718c2ecf20Sopenharmony_ci * ix = [0-5]
10728c2ecf20Sopenharmony_ci * --------------------------------------------------------------------- */
10738c2ecf20Sopenharmony_ci
10748c2ecf20Sopenharmony_ci#define SYS_FAN_INPUT	0
10758c2ecf20Sopenharmony_ci#define SYS_FAN_MIN	1
10768c2ecf20Sopenharmony_ci#define SYS_FAN_MAX	2
10778c2ecf20Sopenharmony_ci#define SYS_FAN_ALARM	3
10788c2ecf20Sopenharmony_ci#define SYS_FAN_TYPE	4
10798c2ecf20Sopenharmony_ci
10808c2ecf20Sopenharmony_cistatic ssize_t show_fan(struct device *dev, struct device_attribute *attr,
10818c2ecf20Sopenharmony_ci			char *buf)
10828c2ecf20Sopenharmony_ci{
10838c2ecf20Sopenharmony_ci	struct dme1737_data *data = dme1737_update_device(dev);
10848c2ecf20Sopenharmony_ci	struct sensor_device_attribute_2
10858c2ecf20Sopenharmony_ci		*sensor_attr_2 = to_sensor_dev_attr_2(attr);
10868c2ecf20Sopenharmony_ci	int ix = sensor_attr_2->index;
10878c2ecf20Sopenharmony_ci	int fn = sensor_attr_2->nr;
10888c2ecf20Sopenharmony_ci	int res;
10898c2ecf20Sopenharmony_ci
10908c2ecf20Sopenharmony_ci	switch (fn) {
10918c2ecf20Sopenharmony_ci	case SYS_FAN_INPUT:
10928c2ecf20Sopenharmony_ci		res = FAN_FROM_REG(data->fan[ix],
10938c2ecf20Sopenharmony_ci				   ix < 4 ? 0 :
10948c2ecf20Sopenharmony_ci				   FAN_TPC_FROM_REG(data->fan_opt[ix]));
10958c2ecf20Sopenharmony_ci		break;
10968c2ecf20Sopenharmony_ci	case SYS_FAN_MIN:
10978c2ecf20Sopenharmony_ci		res = FAN_FROM_REG(data->fan_min[ix],
10988c2ecf20Sopenharmony_ci				   ix < 4 ? 0 :
10998c2ecf20Sopenharmony_ci				   FAN_TPC_FROM_REG(data->fan_opt[ix]));
11008c2ecf20Sopenharmony_ci		break;
11018c2ecf20Sopenharmony_ci	case SYS_FAN_MAX:
11028c2ecf20Sopenharmony_ci		/* only valid for fan[5-6] */
11038c2ecf20Sopenharmony_ci		res = FAN_MAX_FROM_REG(data->fan_max[ix - 4]);
11048c2ecf20Sopenharmony_ci		break;
11058c2ecf20Sopenharmony_ci	case SYS_FAN_ALARM:
11068c2ecf20Sopenharmony_ci		res = (data->alarms >> DME1737_BIT_ALARM_FAN[ix]) & 0x01;
11078c2ecf20Sopenharmony_ci		break;
11088c2ecf20Sopenharmony_ci	case SYS_FAN_TYPE:
11098c2ecf20Sopenharmony_ci		/* only valid for fan[1-4] */
11108c2ecf20Sopenharmony_ci		res = FAN_TYPE_FROM_REG(data->fan_opt[ix]);
11118c2ecf20Sopenharmony_ci		break;
11128c2ecf20Sopenharmony_ci	default:
11138c2ecf20Sopenharmony_ci		res = 0;
11148c2ecf20Sopenharmony_ci		dev_dbg(dev, "Unknown function %d.\n", fn);
11158c2ecf20Sopenharmony_ci	}
11168c2ecf20Sopenharmony_ci
11178c2ecf20Sopenharmony_ci	return sprintf(buf, "%d\n", res);
11188c2ecf20Sopenharmony_ci}
11198c2ecf20Sopenharmony_ci
11208c2ecf20Sopenharmony_cistatic ssize_t set_fan(struct device *dev, struct device_attribute *attr,
11218c2ecf20Sopenharmony_ci		       const char *buf, size_t count)
11228c2ecf20Sopenharmony_ci{
11238c2ecf20Sopenharmony_ci	struct dme1737_data *data = dev_get_drvdata(dev);
11248c2ecf20Sopenharmony_ci	struct sensor_device_attribute_2
11258c2ecf20Sopenharmony_ci		*sensor_attr_2 = to_sensor_dev_attr_2(attr);
11268c2ecf20Sopenharmony_ci	int ix = sensor_attr_2->index;
11278c2ecf20Sopenharmony_ci	int fn = sensor_attr_2->nr;
11288c2ecf20Sopenharmony_ci	long val;
11298c2ecf20Sopenharmony_ci	int err;
11308c2ecf20Sopenharmony_ci
11318c2ecf20Sopenharmony_ci	err = kstrtol(buf, 10, &val);
11328c2ecf20Sopenharmony_ci	if (err)
11338c2ecf20Sopenharmony_ci		return err;
11348c2ecf20Sopenharmony_ci
11358c2ecf20Sopenharmony_ci	mutex_lock(&data->update_lock);
11368c2ecf20Sopenharmony_ci	switch (fn) {
11378c2ecf20Sopenharmony_ci	case SYS_FAN_MIN:
11388c2ecf20Sopenharmony_ci		if (ix < 4) {
11398c2ecf20Sopenharmony_ci			data->fan_min[ix] = FAN_TO_REG(val, 0);
11408c2ecf20Sopenharmony_ci		} else {
11418c2ecf20Sopenharmony_ci			/* Refresh the cache */
11428c2ecf20Sopenharmony_ci			data->fan_opt[ix] = dme1737_read(data,
11438c2ecf20Sopenharmony_ci						DME1737_REG_FAN_OPT(ix));
11448c2ecf20Sopenharmony_ci			/* Modify the fan min value */
11458c2ecf20Sopenharmony_ci			data->fan_min[ix] = FAN_TO_REG(val,
11468c2ecf20Sopenharmony_ci					FAN_TPC_FROM_REG(data->fan_opt[ix]));
11478c2ecf20Sopenharmony_ci		}
11488c2ecf20Sopenharmony_ci		dme1737_write(data, DME1737_REG_FAN_MIN(ix),
11498c2ecf20Sopenharmony_ci			      data->fan_min[ix] & 0xff);
11508c2ecf20Sopenharmony_ci		dme1737_write(data, DME1737_REG_FAN_MIN(ix) + 1,
11518c2ecf20Sopenharmony_ci			      data->fan_min[ix] >> 8);
11528c2ecf20Sopenharmony_ci		break;
11538c2ecf20Sopenharmony_ci	case SYS_FAN_MAX:
11548c2ecf20Sopenharmony_ci		/* Only valid for fan[5-6] */
11558c2ecf20Sopenharmony_ci		data->fan_max[ix - 4] = FAN_MAX_TO_REG(val);
11568c2ecf20Sopenharmony_ci		dme1737_write(data, DME1737_REG_FAN_MAX(ix),
11578c2ecf20Sopenharmony_ci			      data->fan_max[ix - 4]);
11588c2ecf20Sopenharmony_ci		break;
11598c2ecf20Sopenharmony_ci	case SYS_FAN_TYPE:
11608c2ecf20Sopenharmony_ci		/* Only valid for fan[1-4] */
11618c2ecf20Sopenharmony_ci		if (!(val == 1 || val == 2 || val == 4)) {
11628c2ecf20Sopenharmony_ci			count = -EINVAL;
11638c2ecf20Sopenharmony_ci			dev_warn(dev,
11648c2ecf20Sopenharmony_ci				 "Fan type value %ld not supported. Choose one of 1, 2, or 4.\n",
11658c2ecf20Sopenharmony_ci				 val);
11668c2ecf20Sopenharmony_ci			goto exit;
11678c2ecf20Sopenharmony_ci		}
11688c2ecf20Sopenharmony_ci		data->fan_opt[ix] = FAN_TYPE_TO_REG(val, dme1737_read(data,
11698c2ecf20Sopenharmony_ci					DME1737_REG_FAN_OPT(ix)));
11708c2ecf20Sopenharmony_ci		dme1737_write(data, DME1737_REG_FAN_OPT(ix),
11718c2ecf20Sopenharmony_ci			      data->fan_opt[ix]);
11728c2ecf20Sopenharmony_ci		break;
11738c2ecf20Sopenharmony_ci	default:
11748c2ecf20Sopenharmony_ci		dev_dbg(dev, "Unknown function %d.\n", fn);
11758c2ecf20Sopenharmony_ci	}
11768c2ecf20Sopenharmony_ciexit:
11778c2ecf20Sopenharmony_ci	mutex_unlock(&data->update_lock);
11788c2ecf20Sopenharmony_ci
11798c2ecf20Sopenharmony_ci	return count;
11808c2ecf20Sopenharmony_ci}
11818c2ecf20Sopenharmony_ci
11828c2ecf20Sopenharmony_ci/* ---------------------------------------------------------------------
11838c2ecf20Sopenharmony_ci * PWM sysfs attributes
11848c2ecf20Sopenharmony_ci * ix = [0-4]
11858c2ecf20Sopenharmony_ci * --------------------------------------------------------------------- */
11868c2ecf20Sopenharmony_ci
11878c2ecf20Sopenharmony_ci#define SYS_PWM				0
11888c2ecf20Sopenharmony_ci#define SYS_PWM_FREQ			1
11898c2ecf20Sopenharmony_ci#define SYS_PWM_ENABLE			2
11908c2ecf20Sopenharmony_ci#define SYS_PWM_RAMP_RATE		3
11918c2ecf20Sopenharmony_ci#define SYS_PWM_AUTO_CHANNELS_ZONE	4
11928c2ecf20Sopenharmony_ci#define SYS_PWM_AUTO_PWM_MIN		5
11938c2ecf20Sopenharmony_ci#define SYS_PWM_AUTO_POINT1_PWM		6
11948c2ecf20Sopenharmony_ci#define SYS_PWM_AUTO_POINT2_PWM		7
11958c2ecf20Sopenharmony_ci
11968c2ecf20Sopenharmony_cistatic ssize_t show_pwm(struct device *dev, struct device_attribute *attr,
11978c2ecf20Sopenharmony_ci			char *buf)
11988c2ecf20Sopenharmony_ci{
11998c2ecf20Sopenharmony_ci	struct dme1737_data *data = dme1737_update_device(dev);
12008c2ecf20Sopenharmony_ci	struct sensor_device_attribute_2
12018c2ecf20Sopenharmony_ci		*sensor_attr_2 = to_sensor_dev_attr_2(attr);
12028c2ecf20Sopenharmony_ci	int ix = sensor_attr_2->index;
12038c2ecf20Sopenharmony_ci	int fn = sensor_attr_2->nr;
12048c2ecf20Sopenharmony_ci	int res;
12058c2ecf20Sopenharmony_ci
12068c2ecf20Sopenharmony_ci	switch (fn) {
12078c2ecf20Sopenharmony_ci	case SYS_PWM:
12088c2ecf20Sopenharmony_ci		if (PWM_EN_FROM_REG(data->pwm_config[ix]) == 0)
12098c2ecf20Sopenharmony_ci			res = 255;
12108c2ecf20Sopenharmony_ci		else
12118c2ecf20Sopenharmony_ci			res = data->pwm[ix];
12128c2ecf20Sopenharmony_ci		break;
12138c2ecf20Sopenharmony_ci	case SYS_PWM_FREQ:
12148c2ecf20Sopenharmony_ci		res = PWM_FREQ_FROM_REG(data->pwm_freq[ix]);
12158c2ecf20Sopenharmony_ci		break;
12168c2ecf20Sopenharmony_ci	case SYS_PWM_ENABLE:
12178c2ecf20Sopenharmony_ci		if (ix >= 3)
12188c2ecf20Sopenharmony_ci			res = 1; /* pwm[5-6] hard-wired to manual mode */
12198c2ecf20Sopenharmony_ci		else
12208c2ecf20Sopenharmony_ci			res = PWM_EN_FROM_REG(data->pwm_config[ix]);
12218c2ecf20Sopenharmony_ci		break;
12228c2ecf20Sopenharmony_ci	case SYS_PWM_RAMP_RATE:
12238c2ecf20Sopenharmony_ci		/* Only valid for pwm[1-3] */
12248c2ecf20Sopenharmony_ci		res = PWM_RR_FROM_REG(data->pwm_rr[ix > 0], ix);
12258c2ecf20Sopenharmony_ci		break;
12268c2ecf20Sopenharmony_ci	case SYS_PWM_AUTO_CHANNELS_ZONE:
12278c2ecf20Sopenharmony_ci		/* Only valid for pwm[1-3] */
12288c2ecf20Sopenharmony_ci		if (PWM_EN_FROM_REG(data->pwm_config[ix]) == 2)
12298c2ecf20Sopenharmony_ci			res = PWM_ACZ_FROM_REG(data->pwm_config[ix]);
12308c2ecf20Sopenharmony_ci		else
12318c2ecf20Sopenharmony_ci			res = data->pwm_acz[ix];
12328c2ecf20Sopenharmony_ci		break;
12338c2ecf20Sopenharmony_ci	case SYS_PWM_AUTO_PWM_MIN:
12348c2ecf20Sopenharmony_ci		/* Only valid for pwm[1-3] */
12358c2ecf20Sopenharmony_ci		if (PWM_OFF_FROM_REG(data->pwm_rr[0], ix))
12368c2ecf20Sopenharmony_ci			res = data->pwm_min[ix];
12378c2ecf20Sopenharmony_ci		else
12388c2ecf20Sopenharmony_ci			res = 0;
12398c2ecf20Sopenharmony_ci		break;
12408c2ecf20Sopenharmony_ci	case SYS_PWM_AUTO_POINT1_PWM:
12418c2ecf20Sopenharmony_ci		/* Only valid for pwm[1-3] */
12428c2ecf20Sopenharmony_ci		res = data->pwm_min[ix];
12438c2ecf20Sopenharmony_ci		break;
12448c2ecf20Sopenharmony_ci	case SYS_PWM_AUTO_POINT2_PWM:
12458c2ecf20Sopenharmony_ci		/* Only valid for pwm[1-3] */
12468c2ecf20Sopenharmony_ci		res = 255; /* hard-wired */
12478c2ecf20Sopenharmony_ci		break;
12488c2ecf20Sopenharmony_ci	default:
12498c2ecf20Sopenharmony_ci		res = 0;
12508c2ecf20Sopenharmony_ci		dev_dbg(dev, "Unknown function %d.\n", fn);
12518c2ecf20Sopenharmony_ci	}
12528c2ecf20Sopenharmony_ci
12538c2ecf20Sopenharmony_ci	return sprintf(buf, "%d\n", res);
12548c2ecf20Sopenharmony_ci}
12558c2ecf20Sopenharmony_ci
12568c2ecf20Sopenharmony_cistatic struct attribute *dme1737_pwm_chmod_attr[];
12578c2ecf20Sopenharmony_cistatic void dme1737_chmod_file(struct device*, struct attribute*, umode_t);
12588c2ecf20Sopenharmony_ci
12598c2ecf20Sopenharmony_cistatic ssize_t set_pwm(struct device *dev, struct device_attribute *attr,
12608c2ecf20Sopenharmony_ci		       const char *buf, size_t count)
12618c2ecf20Sopenharmony_ci{
12628c2ecf20Sopenharmony_ci	struct dme1737_data *data = dev_get_drvdata(dev);
12638c2ecf20Sopenharmony_ci	struct sensor_device_attribute_2
12648c2ecf20Sopenharmony_ci		*sensor_attr_2 = to_sensor_dev_attr_2(attr);
12658c2ecf20Sopenharmony_ci	int ix = sensor_attr_2->index;
12668c2ecf20Sopenharmony_ci	int fn = sensor_attr_2->nr;
12678c2ecf20Sopenharmony_ci	long val;
12688c2ecf20Sopenharmony_ci	int err;
12698c2ecf20Sopenharmony_ci
12708c2ecf20Sopenharmony_ci	err = kstrtol(buf, 10, &val);
12718c2ecf20Sopenharmony_ci	if (err)
12728c2ecf20Sopenharmony_ci		return err;
12738c2ecf20Sopenharmony_ci
12748c2ecf20Sopenharmony_ci	mutex_lock(&data->update_lock);
12758c2ecf20Sopenharmony_ci	switch (fn) {
12768c2ecf20Sopenharmony_ci	case SYS_PWM:
12778c2ecf20Sopenharmony_ci		data->pwm[ix] = clamp_val(val, 0, 255);
12788c2ecf20Sopenharmony_ci		dme1737_write(data, DME1737_REG_PWM(ix), data->pwm[ix]);
12798c2ecf20Sopenharmony_ci		break;
12808c2ecf20Sopenharmony_ci	case SYS_PWM_FREQ:
12818c2ecf20Sopenharmony_ci		data->pwm_freq[ix] = PWM_FREQ_TO_REG(val, dme1737_read(data,
12828c2ecf20Sopenharmony_ci						DME1737_REG_PWM_FREQ(ix)));
12838c2ecf20Sopenharmony_ci		dme1737_write(data, DME1737_REG_PWM_FREQ(ix),
12848c2ecf20Sopenharmony_ci			      data->pwm_freq[ix]);
12858c2ecf20Sopenharmony_ci		break;
12868c2ecf20Sopenharmony_ci	case SYS_PWM_ENABLE:
12878c2ecf20Sopenharmony_ci		/* Only valid for pwm[1-3] */
12888c2ecf20Sopenharmony_ci		if (val < 0 || val > 2) {
12898c2ecf20Sopenharmony_ci			count = -EINVAL;
12908c2ecf20Sopenharmony_ci			dev_warn(dev,
12918c2ecf20Sopenharmony_ci				 "PWM enable %ld not supported. Choose one of 0, 1, or 2.\n",
12928c2ecf20Sopenharmony_ci				 val);
12938c2ecf20Sopenharmony_ci			goto exit;
12948c2ecf20Sopenharmony_ci		}
12958c2ecf20Sopenharmony_ci		/* Refresh the cache */
12968c2ecf20Sopenharmony_ci		data->pwm_config[ix] = dme1737_read(data,
12978c2ecf20Sopenharmony_ci						DME1737_REG_PWM_CONFIG(ix));
12988c2ecf20Sopenharmony_ci		if (val == PWM_EN_FROM_REG(data->pwm_config[ix])) {
12998c2ecf20Sopenharmony_ci			/* Bail out if no change */
13008c2ecf20Sopenharmony_ci			goto exit;
13018c2ecf20Sopenharmony_ci		}
13028c2ecf20Sopenharmony_ci		/* Do some housekeeping if we are currently in auto mode */
13038c2ecf20Sopenharmony_ci		if (PWM_EN_FROM_REG(data->pwm_config[ix]) == 2) {
13048c2ecf20Sopenharmony_ci			/* Save the current zone channel assignment */
13058c2ecf20Sopenharmony_ci			data->pwm_acz[ix] = PWM_ACZ_FROM_REG(
13068c2ecf20Sopenharmony_ci							data->pwm_config[ix]);
13078c2ecf20Sopenharmony_ci			/* Save the current ramp rate state and disable it */
13088c2ecf20Sopenharmony_ci			data->pwm_rr[ix > 0] = dme1737_read(data,
13098c2ecf20Sopenharmony_ci						DME1737_REG_PWM_RR(ix > 0));
13108c2ecf20Sopenharmony_ci			data->pwm_rr_en &= ~(1 << ix);
13118c2ecf20Sopenharmony_ci			if (PWM_RR_EN_FROM_REG(data->pwm_rr[ix > 0], ix)) {
13128c2ecf20Sopenharmony_ci				data->pwm_rr_en |= (1 << ix);
13138c2ecf20Sopenharmony_ci				data->pwm_rr[ix > 0] = PWM_RR_EN_TO_REG(0, ix,
13148c2ecf20Sopenharmony_ci							data->pwm_rr[ix > 0]);
13158c2ecf20Sopenharmony_ci				dme1737_write(data,
13168c2ecf20Sopenharmony_ci					      DME1737_REG_PWM_RR(ix > 0),
13178c2ecf20Sopenharmony_ci					      data->pwm_rr[ix > 0]);
13188c2ecf20Sopenharmony_ci			}
13198c2ecf20Sopenharmony_ci		}
13208c2ecf20Sopenharmony_ci		/* Set the new PWM mode */
13218c2ecf20Sopenharmony_ci		switch (val) {
13228c2ecf20Sopenharmony_ci		case 0:
13238c2ecf20Sopenharmony_ci			/* Change permissions of pwm[ix] to read-only */
13248c2ecf20Sopenharmony_ci			dme1737_chmod_file(dev, dme1737_pwm_chmod_attr[ix],
13258c2ecf20Sopenharmony_ci					   S_IRUGO);
13268c2ecf20Sopenharmony_ci			/* Turn fan fully on */
13278c2ecf20Sopenharmony_ci			data->pwm_config[ix] = PWM_EN_TO_REG(0,
13288c2ecf20Sopenharmony_ci							data->pwm_config[ix]);
13298c2ecf20Sopenharmony_ci			dme1737_write(data, DME1737_REG_PWM_CONFIG(ix),
13308c2ecf20Sopenharmony_ci				      data->pwm_config[ix]);
13318c2ecf20Sopenharmony_ci			break;
13328c2ecf20Sopenharmony_ci		case 1:
13338c2ecf20Sopenharmony_ci			/* Turn on manual mode */
13348c2ecf20Sopenharmony_ci			data->pwm_config[ix] = PWM_EN_TO_REG(1,
13358c2ecf20Sopenharmony_ci							data->pwm_config[ix]);
13368c2ecf20Sopenharmony_ci			dme1737_write(data, DME1737_REG_PWM_CONFIG(ix),
13378c2ecf20Sopenharmony_ci				      data->pwm_config[ix]);
13388c2ecf20Sopenharmony_ci			/* Change permissions of pwm[ix] to read-writeable */
13398c2ecf20Sopenharmony_ci			dme1737_chmod_file(dev, dme1737_pwm_chmod_attr[ix],
13408c2ecf20Sopenharmony_ci					   S_IRUGO | S_IWUSR);
13418c2ecf20Sopenharmony_ci			break;
13428c2ecf20Sopenharmony_ci		case 2:
13438c2ecf20Sopenharmony_ci			/* Change permissions of pwm[ix] to read-only */
13448c2ecf20Sopenharmony_ci			dme1737_chmod_file(dev, dme1737_pwm_chmod_attr[ix],
13458c2ecf20Sopenharmony_ci					   S_IRUGO);
13468c2ecf20Sopenharmony_ci			/*
13478c2ecf20Sopenharmony_ci			 * Turn on auto mode using the saved zone channel
13488c2ecf20Sopenharmony_ci			 * assignment
13498c2ecf20Sopenharmony_ci			 */
13508c2ecf20Sopenharmony_ci			data->pwm_config[ix] = PWM_ACZ_TO_REG(
13518c2ecf20Sopenharmony_ci							data->pwm_acz[ix],
13528c2ecf20Sopenharmony_ci							data->pwm_config[ix]);
13538c2ecf20Sopenharmony_ci			dme1737_write(data, DME1737_REG_PWM_CONFIG(ix),
13548c2ecf20Sopenharmony_ci				      data->pwm_config[ix]);
13558c2ecf20Sopenharmony_ci			/* Enable PWM ramp rate if previously enabled */
13568c2ecf20Sopenharmony_ci			if (data->pwm_rr_en & (1 << ix)) {
13578c2ecf20Sopenharmony_ci				data->pwm_rr[ix > 0] = PWM_RR_EN_TO_REG(1, ix,
13588c2ecf20Sopenharmony_ci						dme1737_read(data,
13598c2ecf20Sopenharmony_ci						DME1737_REG_PWM_RR(ix > 0)));
13608c2ecf20Sopenharmony_ci				dme1737_write(data,
13618c2ecf20Sopenharmony_ci					      DME1737_REG_PWM_RR(ix > 0),
13628c2ecf20Sopenharmony_ci					      data->pwm_rr[ix > 0]);
13638c2ecf20Sopenharmony_ci			}
13648c2ecf20Sopenharmony_ci			break;
13658c2ecf20Sopenharmony_ci		}
13668c2ecf20Sopenharmony_ci		break;
13678c2ecf20Sopenharmony_ci	case SYS_PWM_RAMP_RATE:
13688c2ecf20Sopenharmony_ci		/* Only valid for pwm[1-3] */
13698c2ecf20Sopenharmony_ci		/* Refresh the cache */
13708c2ecf20Sopenharmony_ci		data->pwm_config[ix] = dme1737_read(data,
13718c2ecf20Sopenharmony_ci						DME1737_REG_PWM_CONFIG(ix));
13728c2ecf20Sopenharmony_ci		data->pwm_rr[ix > 0] = dme1737_read(data,
13738c2ecf20Sopenharmony_ci						DME1737_REG_PWM_RR(ix > 0));
13748c2ecf20Sopenharmony_ci		/* Set the ramp rate value */
13758c2ecf20Sopenharmony_ci		if (val > 0) {
13768c2ecf20Sopenharmony_ci			data->pwm_rr[ix > 0] = PWM_RR_TO_REG(val, ix,
13778c2ecf20Sopenharmony_ci							data->pwm_rr[ix > 0]);
13788c2ecf20Sopenharmony_ci		}
13798c2ecf20Sopenharmony_ci		/*
13808c2ecf20Sopenharmony_ci		 * Enable/disable the feature only if the associated PWM
13818c2ecf20Sopenharmony_ci		 * output is in automatic mode.
13828c2ecf20Sopenharmony_ci		 */
13838c2ecf20Sopenharmony_ci		if (PWM_EN_FROM_REG(data->pwm_config[ix]) == 2) {
13848c2ecf20Sopenharmony_ci			data->pwm_rr[ix > 0] = PWM_RR_EN_TO_REG(val > 0, ix,
13858c2ecf20Sopenharmony_ci							data->pwm_rr[ix > 0]);
13868c2ecf20Sopenharmony_ci		}
13878c2ecf20Sopenharmony_ci		dme1737_write(data, DME1737_REG_PWM_RR(ix > 0),
13888c2ecf20Sopenharmony_ci			      data->pwm_rr[ix > 0]);
13898c2ecf20Sopenharmony_ci		break;
13908c2ecf20Sopenharmony_ci	case SYS_PWM_AUTO_CHANNELS_ZONE:
13918c2ecf20Sopenharmony_ci		/* Only valid for pwm[1-3] */
13928c2ecf20Sopenharmony_ci		if (!(val == 1 || val == 2 || val == 4 ||
13938c2ecf20Sopenharmony_ci		      val == 6 || val == 7)) {
13948c2ecf20Sopenharmony_ci			count = -EINVAL;
13958c2ecf20Sopenharmony_ci			dev_warn(dev,
13968c2ecf20Sopenharmony_ci				 "PWM auto channels zone %ld not supported. Choose one of 1, 2, 4, 6, "
13978c2ecf20Sopenharmony_ci				 "or 7.\n", val);
13988c2ecf20Sopenharmony_ci			goto exit;
13998c2ecf20Sopenharmony_ci		}
14008c2ecf20Sopenharmony_ci		/* Refresh the cache */
14018c2ecf20Sopenharmony_ci		data->pwm_config[ix] = dme1737_read(data,
14028c2ecf20Sopenharmony_ci						DME1737_REG_PWM_CONFIG(ix));
14038c2ecf20Sopenharmony_ci		if (PWM_EN_FROM_REG(data->pwm_config[ix]) == 2) {
14048c2ecf20Sopenharmony_ci			/*
14058c2ecf20Sopenharmony_ci			 * PWM is already in auto mode so update the temp
14068c2ecf20Sopenharmony_ci			 * channel assignment
14078c2ecf20Sopenharmony_ci			 */
14088c2ecf20Sopenharmony_ci			data->pwm_config[ix] = PWM_ACZ_TO_REG(val,
14098c2ecf20Sopenharmony_ci						data->pwm_config[ix]);
14108c2ecf20Sopenharmony_ci			dme1737_write(data, DME1737_REG_PWM_CONFIG(ix),
14118c2ecf20Sopenharmony_ci				      data->pwm_config[ix]);
14128c2ecf20Sopenharmony_ci		} else {
14138c2ecf20Sopenharmony_ci			/*
14148c2ecf20Sopenharmony_ci			 * PWM is not in auto mode so we save the temp
14158c2ecf20Sopenharmony_ci			 * channel assignment for later use
14168c2ecf20Sopenharmony_ci			 */
14178c2ecf20Sopenharmony_ci			data->pwm_acz[ix] = val;
14188c2ecf20Sopenharmony_ci		}
14198c2ecf20Sopenharmony_ci		break;
14208c2ecf20Sopenharmony_ci	case SYS_PWM_AUTO_PWM_MIN:
14218c2ecf20Sopenharmony_ci		/* Only valid for pwm[1-3] */
14228c2ecf20Sopenharmony_ci		/* Refresh the cache */
14238c2ecf20Sopenharmony_ci		data->pwm_min[ix] = dme1737_read(data,
14248c2ecf20Sopenharmony_ci						DME1737_REG_PWM_MIN(ix));
14258c2ecf20Sopenharmony_ci		/*
14268c2ecf20Sopenharmony_ci		 * There are only 2 values supported for the auto_pwm_min
14278c2ecf20Sopenharmony_ci		 * value: 0 or auto_point1_pwm. So if the temperature drops
14288c2ecf20Sopenharmony_ci		 * below the auto_point1_temp_hyst value, the fan either turns
14298c2ecf20Sopenharmony_ci		 * off or runs at auto_point1_pwm duty-cycle.
14308c2ecf20Sopenharmony_ci		 */
14318c2ecf20Sopenharmony_ci		if (val > ((data->pwm_min[ix] + 1) / 2)) {
14328c2ecf20Sopenharmony_ci			data->pwm_rr[0] = PWM_OFF_TO_REG(1, ix,
14338c2ecf20Sopenharmony_ci						dme1737_read(data,
14348c2ecf20Sopenharmony_ci						DME1737_REG_PWM_RR(0)));
14358c2ecf20Sopenharmony_ci		} else {
14368c2ecf20Sopenharmony_ci			data->pwm_rr[0] = PWM_OFF_TO_REG(0, ix,
14378c2ecf20Sopenharmony_ci						dme1737_read(data,
14388c2ecf20Sopenharmony_ci						DME1737_REG_PWM_RR(0)));
14398c2ecf20Sopenharmony_ci		}
14408c2ecf20Sopenharmony_ci		dme1737_write(data, DME1737_REG_PWM_RR(0),
14418c2ecf20Sopenharmony_ci			      data->pwm_rr[0]);
14428c2ecf20Sopenharmony_ci		break;
14438c2ecf20Sopenharmony_ci	case SYS_PWM_AUTO_POINT1_PWM:
14448c2ecf20Sopenharmony_ci		/* Only valid for pwm[1-3] */
14458c2ecf20Sopenharmony_ci		data->pwm_min[ix] = clamp_val(val, 0, 255);
14468c2ecf20Sopenharmony_ci		dme1737_write(data, DME1737_REG_PWM_MIN(ix),
14478c2ecf20Sopenharmony_ci			      data->pwm_min[ix]);
14488c2ecf20Sopenharmony_ci		break;
14498c2ecf20Sopenharmony_ci	default:
14508c2ecf20Sopenharmony_ci		dev_dbg(dev, "Unknown function %d.\n", fn);
14518c2ecf20Sopenharmony_ci	}
14528c2ecf20Sopenharmony_ciexit:
14538c2ecf20Sopenharmony_ci	mutex_unlock(&data->update_lock);
14548c2ecf20Sopenharmony_ci
14558c2ecf20Sopenharmony_ci	return count;
14568c2ecf20Sopenharmony_ci}
14578c2ecf20Sopenharmony_ci
14588c2ecf20Sopenharmony_ci/* ---------------------------------------------------------------------
14598c2ecf20Sopenharmony_ci * Miscellaneous sysfs attributes
14608c2ecf20Sopenharmony_ci * --------------------------------------------------------------------- */
14618c2ecf20Sopenharmony_ci
14628c2ecf20Sopenharmony_cistatic ssize_t vrm_show(struct device *dev, struct device_attribute *attr,
14638c2ecf20Sopenharmony_ci			char *buf)
14648c2ecf20Sopenharmony_ci{
14658c2ecf20Sopenharmony_ci	struct i2c_client *client = to_i2c_client(dev);
14668c2ecf20Sopenharmony_ci	struct dme1737_data *data = i2c_get_clientdata(client);
14678c2ecf20Sopenharmony_ci
14688c2ecf20Sopenharmony_ci	return sprintf(buf, "%d\n", data->vrm);
14698c2ecf20Sopenharmony_ci}
14708c2ecf20Sopenharmony_ci
14718c2ecf20Sopenharmony_cistatic ssize_t vrm_store(struct device *dev, struct device_attribute *attr,
14728c2ecf20Sopenharmony_ci			 const char *buf, size_t count)
14738c2ecf20Sopenharmony_ci{
14748c2ecf20Sopenharmony_ci	struct dme1737_data *data = dev_get_drvdata(dev);
14758c2ecf20Sopenharmony_ci	unsigned long val;
14768c2ecf20Sopenharmony_ci	int err;
14778c2ecf20Sopenharmony_ci
14788c2ecf20Sopenharmony_ci	err = kstrtoul(buf, 10, &val);
14798c2ecf20Sopenharmony_ci	if (err)
14808c2ecf20Sopenharmony_ci		return err;
14818c2ecf20Sopenharmony_ci
14828c2ecf20Sopenharmony_ci	if (val > 255)
14838c2ecf20Sopenharmony_ci		return -EINVAL;
14848c2ecf20Sopenharmony_ci
14858c2ecf20Sopenharmony_ci	data->vrm = val;
14868c2ecf20Sopenharmony_ci	return count;
14878c2ecf20Sopenharmony_ci}
14888c2ecf20Sopenharmony_ci
14898c2ecf20Sopenharmony_cistatic ssize_t cpu0_vid_show(struct device *dev,
14908c2ecf20Sopenharmony_ci			     struct device_attribute *attr, char *buf)
14918c2ecf20Sopenharmony_ci{
14928c2ecf20Sopenharmony_ci	struct dme1737_data *data = dme1737_update_device(dev);
14938c2ecf20Sopenharmony_ci
14948c2ecf20Sopenharmony_ci	return sprintf(buf, "%d\n", vid_from_reg(data->vid, data->vrm));
14958c2ecf20Sopenharmony_ci}
14968c2ecf20Sopenharmony_ci
14978c2ecf20Sopenharmony_cistatic ssize_t name_show(struct device *dev, struct device_attribute *attr,
14988c2ecf20Sopenharmony_ci			 char *buf)
14998c2ecf20Sopenharmony_ci{
15008c2ecf20Sopenharmony_ci	struct dme1737_data *data = dev_get_drvdata(dev);
15018c2ecf20Sopenharmony_ci
15028c2ecf20Sopenharmony_ci	return sprintf(buf, "%s\n", data->name);
15038c2ecf20Sopenharmony_ci}
15048c2ecf20Sopenharmony_ci
15058c2ecf20Sopenharmony_ci/* ---------------------------------------------------------------------
15068c2ecf20Sopenharmony_ci * Sysfs device attribute defines and structs
15078c2ecf20Sopenharmony_ci * --------------------------------------------------------------------- */
15088c2ecf20Sopenharmony_ci
15098c2ecf20Sopenharmony_ci/* Voltages 0-7 */
15108c2ecf20Sopenharmony_ci
15118c2ecf20Sopenharmony_ci#define SENSOR_DEVICE_ATTR_IN(ix) \
15128c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2(in##ix##_input, S_IRUGO, \
15138c2ecf20Sopenharmony_ci	show_in, NULL, SYS_IN_INPUT, ix); \
15148c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2(in##ix##_min, S_IRUGO | S_IWUSR, \
15158c2ecf20Sopenharmony_ci	show_in, set_in, SYS_IN_MIN, ix); \
15168c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2(in##ix##_max, S_IRUGO | S_IWUSR, \
15178c2ecf20Sopenharmony_ci	show_in, set_in, SYS_IN_MAX, ix); \
15188c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2(in##ix##_alarm, S_IRUGO, \
15198c2ecf20Sopenharmony_ci	show_in, NULL, SYS_IN_ALARM, ix)
15208c2ecf20Sopenharmony_ci
15218c2ecf20Sopenharmony_ciSENSOR_DEVICE_ATTR_IN(0);
15228c2ecf20Sopenharmony_ciSENSOR_DEVICE_ATTR_IN(1);
15238c2ecf20Sopenharmony_ciSENSOR_DEVICE_ATTR_IN(2);
15248c2ecf20Sopenharmony_ciSENSOR_DEVICE_ATTR_IN(3);
15258c2ecf20Sopenharmony_ciSENSOR_DEVICE_ATTR_IN(4);
15268c2ecf20Sopenharmony_ciSENSOR_DEVICE_ATTR_IN(5);
15278c2ecf20Sopenharmony_ciSENSOR_DEVICE_ATTR_IN(6);
15288c2ecf20Sopenharmony_ciSENSOR_DEVICE_ATTR_IN(7);
15298c2ecf20Sopenharmony_ci
15308c2ecf20Sopenharmony_ci/* Temperatures 1-3 */
15318c2ecf20Sopenharmony_ci
15328c2ecf20Sopenharmony_ci#define SENSOR_DEVICE_ATTR_TEMP(ix) \
15338c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2(temp##ix##_input, S_IRUGO, \
15348c2ecf20Sopenharmony_ci	show_temp, NULL, SYS_TEMP_INPUT, ix-1); \
15358c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2(temp##ix##_min, S_IRUGO | S_IWUSR, \
15368c2ecf20Sopenharmony_ci	show_temp, set_temp, SYS_TEMP_MIN, ix-1); \
15378c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2(temp##ix##_max, S_IRUGO | S_IWUSR, \
15388c2ecf20Sopenharmony_ci	show_temp, set_temp, SYS_TEMP_MAX, ix-1); \
15398c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2(temp##ix##_offset, S_IRUGO, \
15408c2ecf20Sopenharmony_ci	show_temp, set_temp, SYS_TEMP_OFFSET, ix-1); \
15418c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2(temp##ix##_alarm, S_IRUGO, \
15428c2ecf20Sopenharmony_ci	show_temp, NULL, SYS_TEMP_ALARM, ix-1); \
15438c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2(temp##ix##_fault, S_IRUGO, \
15448c2ecf20Sopenharmony_ci	show_temp, NULL, SYS_TEMP_FAULT, ix-1)
15458c2ecf20Sopenharmony_ci
15468c2ecf20Sopenharmony_ciSENSOR_DEVICE_ATTR_TEMP(1);
15478c2ecf20Sopenharmony_ciSENSOR_DEVICE_ATTR_TEMP(2);
15488c2ecf20Sopenharmony_ciSENSOR_DEVICE_ATTR_TEMP(3);
15498c2ecf20Sopenharmony_ci
15508c2ecf20Sopenharmony_ci/* Zones 1-3 */
15518c2ecf20Sopenharmony_ci
15528c2ecf20Sopenharmony_ci#define SENSOR_DEVICE_ATTR_ZONE(ix) \
15538c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2(zone##ix##_auto_channels_temp, S_IRUGO, \
15548c2ecf20Sopenharmony_ci	show_zone, NULL, SYS_ZONE_AUTO_CHANNELS_TEMP, ix-1); \
15558c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2(zone##ix##_auto_point1_temp_hyst, S_IRUGO, \
15568c2ecf20Sopenharmony_ci	show_zone, set_zone, SYS_ZONE_AUTO_POINT1_TEMP_HYST, ix-1); \
15578c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2(zone##ix##_auto_point1_temp, S_IRUGO, \
15588c2ecf20Sopenharmony_ci	show_zone, set_zone, SYS_ZONE_AUTO_POINT1_TEMP, ix-1); \
15598c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2(zone##ix##_auto_point2_temp, S_IRUGO, \
15608c2ecf20Sopenharmony_ci	show_zone, set_zone, SYS_ZONE_AUTO_POINT2_TEMP, ix-1); \
15618c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2(zone##ix##_auto_point3_temp, S_IRUGO, \
15628c2ecf20Sopenharmony_ci	show_zone, set_zone, SYS_ZONE_AUTO_POINT3_TEMP, ix-1)
15638c2ecf20Sopenharmony_ci
15648c2ecf20Sopenharmony_ciSENSOR_DEVICE_ATTR_ZONE(1);
15658c2ecf20Sopenharmony_ciSENSOR_DEVICE_ATTR_ZONE(2);
15668c2ecf20Sopenharmony_ciSENSOR_DEVICE_ATTR_ZONE(3);
15678c2ecf20Sopenharmony_ci
15688c2ecf20Sopenharmony_ci/* Fans 1-4 */
15698c2ecf20Sopenharmony_ci
15708c2ecf20Sopenharmony_ci#define SENSOR_DEVICE_ATTR_FAN_1TO4(ix) \
15718c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2(fan##ix##_input, S_IRUGO, \
15728c2ecf20Sopenharmony_ci	show_fan, NULL, SYS_FAN_INPUT, ix-1); \
15738c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2(fan##ix##_min, S_IRUGO | S_IWUSR, \
15748c2ecf20Sopenharmony_ci	show_fan, set_fan, SYS_FAN_MIN, ix-1); \
15758c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2(fan##ix##_alarm, S_IRUGO, \
15768c2ecf20Sopenharmony_ci	show_fan, NULL, SYS_FAN_ALARM, ix-1); \
15778c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2(fan##ix##_type, S_IRUGO | S_IWUSR, \
15788c2ecf20Sopenharmony_ci	show_fan, set_fan, SYS_FAN_TYPE, ix-1)
15798c2ecf20Sopenharmony_ci
15808c2ecf20Sopenharmony_ciSENSOR_DEVICE_ATTR_FAN_1TO4(1);
15818c2ecf20Sopenharmony_ciSENSOR_DEVICE_ATTR_FAN_1TO4(2);
15828c2ecf20Sopenharmony_ciSENSOR_DEVICE_ATTR_FAN_1TO4(3);
15838c2ecf20Sopenharmony_ciSENSOR_DEVICE_ATTR_FAN_1TO4(4);
15848c2ecf20Sopenharmony_ci
15858c2ecf20Sopenharmony_ci/* Fans 5-6 */
15868c2ecf20Sopenharmony_ci
15878c2ecf20Sopenharmony_ci#define SENSOR_DEVICE_ATTR_FAN_5TO6(ix) \
15888c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2(fan##ix##_input, S_IRUGO, \
15898c2ecf20Sopenharmony_ci	show_fan, NULL, SYS_FAN_INPUT, ix-1); \
15908c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2(fan##ix##_min, S_IRUGO | S_IWUSR, \
15918c2ecf20Sopenharmony_ci	show_fan, set_fan, SYS_FAN_MIN, ix-1); \
15928c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2(fan##ix##_alarm, S_IRUGO, \
15938c2ecf20Sopenharmony_ci	show_fan, NULL, SYS_FAN_ALARM, ix-1); \
15948c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2(fan##ix##_max, S_IRUGO | S_IWUSR, \
15958c2ecf20Sopenharmony_ci	show_fan, set_fan, SYS_FAN_MAX, ix-1)
15968c2ecf20Sopenharmony_ci
15978c2ecf20Sopenharmony_ciSENSOR_DEVICE_ATTR_FAN_5TO6(5);
15988c2ecf20Sopenharmony_ciSENSOR_DEVICE_ATTR_FAN_5TO6(6);
15998c2ecf20Sopenharmony_ci
16008c2ecf20Sopenharmony_ci/* PWMs 1-3 */
16018c2ecf20Sopenharmony_ci
16028c2ecf20Sopenharmony_ci#define SENSOR_DEVICE_ATTR_PWM_1TO3(ix) \
16038c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2(pwm##ix, S_IRUGO, \
16048c2ecf20Sopenharmony_ci	show_pwm, set_pwm, SYS_PWM, ix-1); \
16058c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2(pwm##ix##_freq, S_IRUGO, \
16068c2ecf20Sopenharmony_ci	show_pwm, set_pwm, SYS_PWM_FREQ, ix-1); \
16078c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2(pwm##ix##_enable, S_IRUGO, \
16088c2ecf20Sopenharmony_ci	show_pwm, set_pwm, SYS_PWM_ENABLE, ix-1); \
16098c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2(pwm##ix##_ramp_rate, S_IRUGO, \
16108c2ecf20Sopenharmony_ci	show_pwm, set_pwm, SYS_PWM_RAMP_RATE, ix-1); \
16118c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2(pwm##ix##_auto_channels_zone, S_IRUGO, \
16128c2ecf20Sopenharmony_ci	show_pwm, set_pwm, SYS_PWM_AUTO_CHANNELS_ZONE, ix-1); \
16138c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2(pwm##ix##_auto_pwm_min, S_IRUGO, \
16148c2ecf20Sopenharmony_ci	show_pwm, set_pwm, SYS_PWM_AUTO_PWM_MIN, ix-1); \
16158c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2(pwm##ix##_auto_point1_pwm, S_IRUGO, \
16168c2ecf20Sopenharmony_ci	show_pwm, set_pwm, SYS_PWM_AUTO_POINT1_PWM, ix-1); \
16178c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2(pwm##ix##_auto_point2_pwm, S_IRUGO, \
16188c2ecf20Sopenharmony_ci	show_pwm, NULL, SYS_PWM_AUTO_POINT2_PWM, ix-1)
16198c2ecf20Sopenharmony_ci
16208c2ecf20Sopenharmony_ciSENSOR_DEVICE_ATTR_PWM_1TO3(1);
16218c2ecf20Sopenharmony_ciSENSOR_DEVICE_ATTR_PWM_1TO3(2);
16228c2ecf20Sopenharmony_ciSENSOR_DEVICE_ATTR_PWM_1TO3(3);
16238c2ecf20Sopenharmony_ci
16248c2ecf20Sopenharmony_ci/* PWMs 5-6 */
16258c2ecf20Sopenharmony_ci
16268c2ecf20Sopenharmony_ci#define SENSOR_DEVICE_ATTR_PWM_5TO6(ix) \
16278c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2(pwm##ix, S_IRUGO, \
16288c2ecf20Sopenharmony_ci	show_pwm, set_pwm, SYS_PWM, ix-1); \
16298c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2(pwm##ix##_freq, S_IRUGO, \
16308c2ecf20Sopenharmony_ci	show_pwm, set_pwm, SYS_PWM_FREQ, ix-1); \
16318c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2(pwm##ix##_enable, S_IRUGO, \
16328c2ecf20Sopenharmony_ci	show_pwm, NULL, SYS_PWM_ENABLE, ix-1)
16338c2ecf20Sopenharmony_ci
16348c2ecf20Sopenharmony_ciSENSOR_DEVICE_ATTR_PWM_5TO6(5);
16358c2ecf20Sopenharmony_ciSENSOR_DEVICE_ATTR_PWM_5TO6(6);
16368c2ecf20Sopenharmony_ci
16378c2ecf20Sopenharmony_ci/* Misc */
16388c2ecf20Sopenharmony_ci
16398c2ecf20Sopenharmony_cistatic DEVICE_ATTR_RW(vrm);
16408c2ecf20Sopenharmony_cistatic DEVICE_ATTR_RO(cpu0_vid);
16418c2ecf20Sopenharmony_cistatic DEVICE_ATTR_RO(name);   /* for ISA devices */
16428c2ecf20Sopenharmony_ci
16438c2ecf20Sopenharmony_ci/*
16448c2ecf20Sopenharmony_ci * This struct holds all the attributes that are always present and need to be
16458c2ecf20Sopenharmony_ci * created unconditionally. The attributes that need modification of their
16468c2ecf20Sopenharmony_ci * permissions are created read-only and write permissions are added or removed
16478c2ecf20Sopenharmony_ci * on the fly when required
16488c2ecf20Sopenharmony_ci */
16498c2ecf20Sopenharmony_cistatic struct attribute *dme1737_attr[] = {
16508c2ecf20Sopenharmony_ci	/* Voltages */
16518c2ecf20Sopenharmony_ci	&sensor_dev_attr_in0_input.dev_attr.attr,
16528c2ecf20Sopenharmony_ci	&sensor_dev_attr_in0_min.dev_attr.attr,
16538c2ecf20Sopenharmony_ci	&sensor_dev_attr_in0_max.dev_attr.attr,
16548c2ecf20Sopenharmony_ci	&sensor_dev_attr_in0_alarm.dev_attr.attr,
16558c2ecf20Sopenharmony_ci	&sensor_dev_attr_in1_input.dev_attr.attr,
16568c2ecf20Sopenharmony_ci	&sensor_dev_attr_in1_min.dev_attr.attr,
16578c2ecf20Sopenharmony_ci	&sensor_dev_attr_in1_max.dev_attr.attr,
16588c2ecf20Sopenharmony_ci	&sensor_dev_attr_in1_alarm.dev_attr.attr,
16598c2ecf20Sopenharmony_ci	&sensor_dev_attr_in2_input.dev_attr.attr,
16608c2ecf20Sopenharmony_ci	&sensor_dev_attr_in2_min.dev_attr.attr,
16618c2ecf20Sopenharmony_ci	&sensor_dev_attr_in2_max.dev_attr.attr,
16628c2ecf20Sopenharmony_ci	&sensor_dev_attr_in2_alarm.dev_attr.attr,
16638c2ecf20Sopenharmony_ci	&sensor_dev_attr_in3_input.dev_attr.attr,
16648c2ecf20Sopenharmony_ci	&sensor_dev_attr_in3_min.dev_attr.attr,
16658c2ecf20Sopenharmony_ci	&sensor_dev_attr_in3_max.dev_attr.attr,
16668c2ecf20Sopenharmony_ci	&sensor_dev_attr_in3_alarm.dev_attr.attr,
16678c2ecf20Sopenharmony_ci	&sensor_dev_attr_in4_input.dev_attr.attr,
16688c2ecf20Sopenharmony_ci	&sensor_dev_attr_in4_min.dev_attr.attr,
16698c2ecf20Sopenharmony_ci	&sensor_dev_attr_in4_max.dev_attr.attr,
16708c2ecf20Sopenharmony_ci	&sensor_dev_attr_in4_alarm.dev_attr.attr,
16718c2ecf20Sopenharmony_ci	&sensor_dev_attr_in5_input.dev_attr.attr,
16728c2ecf20Sopenharmony_ci	&sensor_dev_attr_in5_min.dev_attr.attr,
16738c2ecf20Sopenharmony_ci	&sensor_dev_attr_in5_max.dev_attr.attr,
16748c2ecf20Sopenharmony_ci	&sensor_dev_attr_in5_alarm.dev_attr.attr,
16758c2ecf20Sopenharmony_ci	&sensor_dev_attr_in6_input.dev_attr.attr,
16768c2ecf20Sopenharmony_ci	&sensor_dev_attr_in6_min.dev_attr.attr,
16778c2ecf20Sopenharmony_ci	&sensor_dev_attr_in6_max.dev_attr.attr,
16788c2ecf20Sopenharmony_ci	&sensor_dev_attr_in6_alarm.dev_attr.attr,
16798c2ecf20Sopenharmony_ci	/* Temperatures */
16808c2ecf20Sopenharmony_ci	&sensor_dev_attr_temp1_input.dev_attr.attr,
16818c2ecf20Sopenharmony_ci	&sensor_dev_attr_temp1_min.dev_attr.attr,
16828c2ecf20Sopenharmony_ci	&sensor_dev_attr_temp1_max.dev_attr.attr,
16838c2ecf20Sopenharmony_ci	&sensor_dev_attr_temp1_alarm.dev_attr.attr,
16848c2ecf20Sopenharmony_ci	&sensor_dev_attr_temp1_fault.dev_attr.attr,
16858c2ecf20Sopenharmony_ci	&sensor_dev_attr_temp2_input.dev_attr.attr,
16868c2ecf20Sopenharmony_ci	&sensor_dev_attr_temp2_min.dev_attr.attr,
16878c2ecf20Sopenharmony_ci	&sensor_dev_attr_temp2_max.dev_attr.attr,
16888c2ecf20Sopenharmony_ci	&sensor_dev_attr_temp2_alarm.dev_attr.attr,
16898c2ecf20Sopenharmony_ci	&sensor_dev_attr_temp2_fault.dev_attr.attr,
16908c2ecf20Sopenharmony_ci	&sensor_dev_attr_temp3_input.dev_attr.attr,
16918c2ecf20Sopenharmony_ci	&sensor_dev_attr_temp3_min.dev_attr.attr,
16928c2ecf20Sopenharmony_ci	&sensor_dev_attr_temp3_max.dev_attr.attr,
16938c2ecf20Sopenharmony_ci	&sensor_dev_attr_temp3_alarm.dev_attr.attr,
16948c2ecf20Sopenharmony_ci	&sensor_dev_attr_temp3_fault.dev_attr.attr,
16958c2ecf20Sopenharmony_ci	/* Zones */
16968c2ecf20Sopenharmony_ci	&sensor_dev_attr_zone1_auto_point1_temp.dev_attr.attr,
16978c2ecf20Sopenharmony_ci	&sensor_dev_attr_zone1_auto_point2_temp.dev_attr.attr,
16988c2ecf20Sopenharmony_ci	&sensor_dev_attr_zone1_auto_point3_temp.dev_attr.attr,
16998c2ecf20Sopenharmony_ci	&sensor_dev_attr_zone1_auto_channels_temp.dev_attr.attr,
17008c2ecf20Sopenharmony_ci	&sensor_dev_attr_zone2_auto_point1_temp.dev_attr.attr,
17018c2ecf20Sopenharmony_ci	&sensor_dev_attr_zone2_auto_point2_temp.dev_attr.attr,
17028c2ecf20Sopenharmony_ci	&sensor_dev_attr_zone2_auto_point3_temp.dev_attr.attr,
17038c2ecf20Sopenharmony_ci	&sensor_dev_attr_zone2_auto_channels_temp.dev_attr.attr,
17048c2ecf20Sopenharmony_ci	NULL
17058c2ecf20Sopenharmony_ci};
17068c2ecf20Sopenharmony_ci
17078c2ecf20Sopenharmony_cistatic const struct attribute_group dme1737_group = {
17088c2ecf20Sopenharmony_ci	.attrs = dme1737_attr,
17098c2ecf20Sopenharmony_ci};
17108c2ecf20Sopenharmony_ci
17118c2ecf20Sopenharmony_ci/*
17128c2ecf20Sopenharmony_ci * The following struct holds temp offset attributes, which are not available
17138c2ecf20Sopenharmony_ci * in all chips. The following chips support them:
17148c2ecf20Sopenharmony_ci * DME1737, SCH311x
17158c2ecf20Sopenharmony_ci */
17168c2ecf20Sopenharmony_cistatic struct attribute *dme1737_temp_offset_attr[] = {
17178c2ecf20Sopenharmony_ci	&sensor_dev_attr_temp1_offset.dev_attr.attr,
17188c2ecf20Sopenharmony_ci	&sensor_dev_attr_temp2_offset.dev_attr.attr,
17198c2ecf20Sopenharmony_ci	&sensor_dev_attr_temp3_offset.dev_attr.attr,
17208c2ecf20Sopenharmony_ci	NULL
17218c2ecf20Sopenharmony_ci};
17228c2ecf20Sopenharmony_ci
17238c2ecf20Sopenharmony_cistatic const struct attribute_group dme1737_temp_offset_group = {
17248c2ecf20Sopenharmony_ci	.attrs = dme1737_temp_offset_attr,
17258c2ecf20Sopenharmony_ci};
17268c2ecf20Sopenharmony_ci
17278c2ecf20Sopenharmony_ci/*
17288c2ecf20Sopenharmony_ci * The following struct holds VID related attributes, which are not available
17298c2ecf20Sopenharmony_ci * in all chips. The following chips support them:
17308c2ecf20Sopenharmony_ci * DME1737
17318c2ecf20Sopenharmony_ci */
17328c2ecf20Sopenharmony_cistatic struct attribute *dme1737_vid_attr[] = {
17338c2ecf20Sopenharmony_ci	&dev_attr_vrm.attr,
17348c2ecf20Sopenharmony_ci	&dev_attr_cpu0_vid.attr,
17358c2ecf20Sopenharmony_ci	NULL
17368c2ecf20Sopenharmony_ci};
17378c2ecf20Sopenharmony_ci
17388c2ecf20Sopenharmony_cistatic const struct attribute_group dme1737_vid_group = {
17398c2ecf20Sopenharmony_ci	.attrs = dme1737_vid_attr,
17408c2ecf20Sopenharmony_ci};
17418c2ecf20Sopenharmony_ci
17428c2ecf20Sopenharmony_ci/*
17438c2ecf20Sopenharmony_ci * The following struct holds temp zone 3 related attributes, which are not
17448c2ecf20Sopenharmony_ci * available in all chips. The following chips support them:
17458c2ecf20Sopenharmony_ci * DME1737, SCH311x, SCH5027
17468c2ecf20Sopenharmony_ci */
17478c2ecf20Sopenharmony_cistatic struct attribute *dme1737_zone3_attr[] = {
17488c2ecf20Sopenharmony_ci	&sensor_dev_attr_zone3_auto_point1_temp.dev_attr.attr,
17498c2ecf20Sopenharmony_ci	&sensor_dev_attr_zone3_auto_point2_temp.dev_attr.attr,
17508c2ecf20Sopenharmony_ci	&sensor_dev_attr_zone3_auto_point3_temp.dev_attr.attr,
17518c2ecf20Sopenharmony_ci	&sensor_dev_attr_zone3_auto_channels_temp.dev_attr.attr,
17528c2ecf20Sopenharmony_ci	NULL
17538c2ecf20Sopenharmony_ci};
17548c2ecf20Sopenharmony_ci
17558c2ecf20Sopenharmony_cistatic const struct attribute_group dme1737_zone3_group = {
17568c2ecf20Sopenharmony_ci	.attrs = dme1737_zone3_attr,
17578c2ecf20Sopenharmony_ci};
17588c2ecf20Sopenharmony_ci
17598c2ecf20Sopenharmony_ci
17608c2ecf20Sopenharmony_ci/*
17618c2ecf20Sopenharmony_ci * The following struct holds temp zone hysteresis related attributes, which
17628c2ecf20Sopenharmony_ci * are not available in all chips. The following chips support them:
17638c2ecf20Sopenharmony_ci * DME1737, SCH311x
17648c2ecf20Sopenharmony_ci */
17658c2ecf20Sopenharmony_cistatic struct attribute *dme1737_zone_hyst_attr[] = {
17668c2ecf20Sopenharmony_ci	&sensor_dev_attr_zone1_auto_point1_temp_hyst.dev_attr.attr,
17678c2ecf20Sopenharmony_ci	&sensor_dev_attr_zone2_auto_point1_temp_hyst.dev_attr.attr,
17688c2ecf20Sopenharmony_ci	&sensor_dev_attr_zone3_auto_point1_temp_hyst.dev_attr.attr,
17698c2ecf20Sopenharmony_ci	NULL
17708c2ecf20Sopenharmony_ci};
17718c2ecf20Sopenharmony_ci
17728c2ecf20Sopenharmony_cistatic const struct attribute_group dme1737_zone_hyst_group = {
17738c2ecf20Sopenharmony_ci	.attrs = dme1737_zone_hyst_attr,
17748c2ecf20Sopenharmony_ci};
17758c2ecf20Sopenharmony_ci
17768c2ecf20Sopenharmony_ci/*
17778c2ecf20Sopenharmony_ci * The following struct holds voltage in7 related attributes, which
17788c2ecf20Sopenharmony_ci * are not available in all chips. The following chips support them:
17798c2ecf20Sopenharmony_ci * SCH5127
17808c2ecf20Sopenharmony_ci */
17818c2ecf20Sopenharmony_cistatic struct attribute *dme1737_in7_attr[] = {
17828c2ecf20Sopenharmony_ci	&sensor_dev_attr_in7_input.dev_attr.attr,
17838c2ecf20Sopenharmony_ci	&sensor_dev_attr_in7_min.dev_attr.attr,
17848c2ecf20Sopenharmony_ci	&sensor_dev_attr_in7_max.dev_attr.attr,
17858c2ecf20Sopenharmony_ci	&sensor_dev_attr_in7_alarm.dev_attr.attr,
17868c2ecf20Sopenharmony_ci	NULL
17878c2ecf20Sopenharmony_ci};
17888c2ecf20Sopenharmony_ci
17898c2ecf20Sopenharmony_cistatic const struct attribute_group dme1737_in7_group = {
17908c2ecf20Sopenharmony_ci	.attrs = dme1737_in7_attr,
17918c2ecf20Sopenharmony_ci};
17928c2ecf20Sopenharmony_ci
17938c2ecf20Sopenharmony_ci/*
17948c2ecf20Sopenharmony_ci * The following structs hold the PWM attributes, some of which are optional.
17958c2ecf20Sopenharmony_ci * Their creation depends on the chip configuration which is determined during
17968c2ecf20Sopenharmony_ci * module load.
17978c2ecf20Sopenharmony_ci */
17988c2ecf20Sopenharmony_cistatic struct attribute *dme1737_pwm1_attr[] = {
17998c2ecf20Sopenharmony_ci	&sensor_dev_attr_pwm1.dev_attr.attr,
18008c2ecf20Sopenharmony_ci	&sensor_dev_attr_pwm1_freq.dev_attr.attr,
18018c2ecf20Sopenharmony_ci	&sensor_dev_attr_pwm1_enable.dev_attr.attr,
18028c2ecf20Sopenharmony_ci	&sensor_dev_attr_pwm1_ramp_rate.dev_attr.attr,
18038c2ecf20Sopenharmony_ci	&sensor_dev_attr_pwm1_auto_channels_zone.dev_attr.attr,
18048c2ecf20Sopenharmony_ci	&sensor_dev_attr_pwm1_auto_point1_pwm.dev_attr.attr,
18058c2ecf20Sopenharmony_ci	&sensor_dev_attr_pwm1_auto_point2_pwm.dev_attr.attr,
18068c2ecf20Sopenharmony_ci	NULL
18078c2ecf20Sopenharmony_ci};
18088c2ecf20Sopenharmony_cistatic struct attribute *dme1737_pwm2_attr[] = {
18098c2ecf20Sopenharmony_ci	&sensor_dev_attr_pwm2.dev_attr.attr,
18108c2ecf20Sopenharmony_ci	&sensor_dev_attr_pwm2_freq.dev_attr.attr,
18118c2ecf20Sopenharmony_ci	&sensor_dev_attr_pwm2_enable.dev_attr.attr,
18128c2ecf20Sopenharmony_ci	&sensor_dev_attr_pwm2_ramp_rate.dev_attr.attr,
18138c2ecf20Sopenharmony_ci	&sensor_dev_attr_pwm2_auto_channels_zone.dev_attr.attr,
18148c2ecf20Sopenharmony_ci	&sensor_dev_attr_pwm2_auto_point1_pwm.dev_attr.attr,
18158c2ecf20Sopenharmony_ci	&sensor_dev_attr_pwm2_auto_point2_pwm.dev_attr.attr,
18168c2ecf20Sopenharmony_ci	NULL
18178c2ecf20Sopenharmony_ci};
18188c2ecf20Sopenharmony_cistatic struct attribute *dme1737_pwm3_attr[] = {
18198c2ecf20Sopenharmony_ci	&sensor_dev_attr_pwm3.dev_attr.attr,
18208c2ecf20Sopenharmony_ci	&sensor_dev_attr_pwm3_freq.dev_attr.attr,
18218c2ecf20Sopenharmony_ci	&sensor_dev_attr_pwm3_enable.dev_attr.attr,
18228c2ecf20Sopenharmony_ci	&sensor_dev_attr_pwm3_ramp_rate.dev_attr.attr,
18238c2ecf20Sopenharmony_ci	&sensor_dev_attr_pwm3_auto_channels_zone.dev_attr.attr,
18248c2ecf20Sopenharmony_ci	&sensor_dev_attr_pwm3_auto_point1_pwm.dev_attr.attr,
18258c2ecf20Sopenharmony_ci	&sensor_dev_attr_pwm3_auto_point2_pwm.dev_attr.attr,
18268c2ecf20Sopenharmony_ci	NULL
18278c2ecf20Sopenharmony_ci};
18288c2ecf20Sopenharmony_cistatic struct attribute *dme1737_pwm5_attr[] = {
18298c2ecf20Sopenharmony_ci	&sensor_dev_attr_pwm5.dev_attr.attr,
18308c2ecf20Sopenharmony_ci	&sensor_dev_attr_pwm5_freq.dev_attr.attr,
18318c2ecf20Sopenharmony_ci	&sensor_dev_attr_pwm5_enable.dev_attr.attr,
18328c2ecf20Sopenharmony_ci	NULL
18338c2ecf20Sopenharmony_ci};
18348c2ecf20Sopenharmony_cistatic struct attribute *dme1737_pwm6_attr[] = {
18358c2ecf20Sopenharmony_ci	&sensor_dev_attr_pwm6.dev_attr.attr,
18368c2ecf20Sopenharmony_ci	&sensor_dev_attr_pwm6_freq.dev_attr.attr,
18378c2ecf20Sopenharmony_ci	&sensor_dev_attr_pwm6_enable.dev_attr.attr,
18388c2ecf20Sopenharmony_ci	NULL
18398c2ecf20Sopenharmony_ci};
18408c2ecf20Sopenharmony_ci
18418c2ecf20Sopenharmony_cistatic const struct attribute_group dme1737_pwm_group[] = {
18428c2ecf20Sopenharmony_ci	{ .attrs = dme1737_pwm1_attr },
18438c2ecf20Sopenharmony_ci	{ .attrs = dme1737_pwm2_attr },
18448c2ecf20Sopenharmony_ci	{ .attrs = dme1737_pwm3_attr },
18458c2ecf20Sopenharmony_ci	{ .attrs = NULL },
18468c2ecf20Sopenharmony_ci	{ .attrs = dme1737_pwm5_attr },
18478c2ecf20Sopenharmony_ci	{ .attrs = dme1737_pwm6_attr },
18488c2ecf20Sopenharmony_ci};
18498c2ecf20Sopenharmony_ci
18508c2ecf20Sopenharmony_ci/*
18518c2ecf20Sopenharmony_ci * The following struct holds auto PWM min attributes, which are not available
18528c2ecf20Sopenharmony_ci * in all chips. Their creation depends on the chip type which is determined
18538c2ecf20Sopenharmony_ci * during module load.
18548c2ecf20Sopenharmony_ci */
18558c2ecf20Sopenharmony_cistatic struct attribute *dme1737_auto_pwm_min_attr[] = {
18568c2ecf20Sopenharmony_ci	&sensor_dev_attr_pwm1_auto_pwm_min.dev_attr.attr,
18578c2ecf20Sopenharmony_ci	&sensor_dev_attr_pwm2_auto_pwm_min.dev_attr.attr,
18588c2ecf20Sopenharmony_ci	&sensor_dev_attr_pwm3_auto_pwm_min.dev_attr.attr,
18598c2ecf20Sopenharmony_ci};
18608c2ecf20Sopenharmony_ci
18618c2ecf20Sopenharmony_ci/*
18628c2ecf20Sopenharmony_ci * The following structs hold the fan attributes, some of which are optional.
18638c2ecf20Sopenharmony_ci * Their creation depends on the chip configuration which is determined during
18648c2ecf20Sopenharmony_ci * module load.
18658c2ecf20Sopenharmony_ci */
18668c2ecf20Sopenharmony_cistatic struct attribute *dme1737_fan1_attr[] = {
18678c2ecf20Sopenharmony_ci	&sensor_dev_attr_fan1_input.dev_attr.attr,
18688c2ecf20Sopenharmony_ci	&sensor_dev_attr_fan1_min.dev_attr.attr,
18698c2ecf20Sopenharmony_ci	&sensor_dev_attr_fan1_alarm.dev_attr.attr,
18708c2ecf20Sopenharmony_ci	&sensor_dev_attr_fan1_type.dev_attr.attr,
18718c2ecf20Sopenharmony_ci	NULL
18728c2ecf20Sopenharmony_ci};
18738c2ecf20Sopenharmony_cistatic struct attribute *dme1737_fan2_attr[] = {
18748c2ecf20Sopenharmony_ci	&sensor_dev_attr_fan2_input.dev_attr.attr,
18758c2ecf20Sopenharmony_ci	&sensor_dev_attr_fan2_min.dev_attr.attr,
18768c2ecf20Sopenharmony_ci	&sensor_dev_attr_fan2_alarm.dev_attr.attr,
18778c2ecf20Sopenharmony_ci	&sensor_dev_attr_fan2_type.dev_attr.attr,
18788c2ecf20Sopenharmony_ci	NULL
18798c2ecf20Sopenharmony_ci};
18808c2ecf20Sopenharmony_cistatic struct attribute *dme1737_fan3_attr[] = {
18818c2ecf20Sopenharmony_ci	&sensor_dev_attr_fan3_input.dev_attr.attr,
18828c2ecf20Sopenharmony_ci	&sensor_dev_attr_fan3_min.dev_attr.attr,
18838c2ecf20Sopenharmony_ci	&sensor_dev_attr_fan3_alarm.dev_attr.attr,
18848c2ecf20Sopenharmony_ci	&sensor_dev_attr_fan3_type.dev_attr.attr,
18858c2ecf20Sopenharmony_ci	NULL
18868c2ecf20Sopenharmony_ci};
18878c2ecf20Sopenharmony_cistatic struct attribute *dme1737_fan4_attr[] = {
18888c2ecf20Sopenharmony_ci	&sensor_dev_attr_fan4_input.dev_attr.attr,
18898c2ecf20Sopenharmony_ci	&sensor_dev_attr_fan4_min.dev_attr.attr,
18908c2ecf20Sopenharmony_ci	&sensor_dev_attr_fan4_alarm.dev_attr.attr,
18918c2ecf20Sopenharmony_ci	&sensor_dev_attr_fan4_type.dev_attr.attr,
18928c2ecf20Sopenharmony_ci	NULL
18938c2ecf20Sopenharmony_ci};
18948c2ecf20Sopenharmony_cistatic struct attribute *dme1737_fan5_attr[] = {
18958c2ecf20Sopenharmony_ci	&sensor_dev_attr_fan5_input.dev_attr.attr,
18968c2ecf20Sopenharmony_ci	&sensor_dev_attr_fan5_min.dev_attr.attr,
18978c2ecf20Sopenharmony_ci	&sensor_dev_attr_fan5_alarm.dev_attr.attr,
18988c2ecf20Sopenharmony_ci	&sensor_dev_attr_fan5_max.dev_attr.attr,
18998c2ecf20Sopenharmony_ci	NULL
19008c2ecf20Sopenharmony_ci};
19018c2ecf20Sopenharmony_cistatic struct attribute *dme1737_fan6_attr[] = {
19028c2ecf20Sopenharmony_ci	&sensor_dev_attr_fan6_input.dev_attr.attr,
19038c2ecf20Sopenharmony_ci	&sensor_dev_attr_fan6_min.dev_attr.attr,
19048c2ecf20Sopenharmony_ci	&sensor_dev_attr_fan6_alarm.dev_attr.attr,
19058c2ecf20Sopenharmony_ci	&sensor_dev_attr_fan6_max.dev_attr.attr,
19068c2ecf20Sopenharmony_ci	NULL
19078c2ecf20Sopenharmony_ci};
19088c2ecf20Sopenharmony_ci
19098c2ecf20Sopenharmony_cistatic const struct attribute_group dme1737_fan_group[] = {
19108c2ecf20Sopenharmony_ci	{ .attrs = dme1737_fan1_attr },
19118c2ecf20Sopenharmony_ci	{ .attrs = dme1737_fan2_attr },
19128c2ecf20Sopenharmony_ci	{ .attrs = dme1737_fan3_attr },
19138c2ecf20Sopenharmony_ci	{ .attrs = dme1737_fan4_attr },
19148c2ecf20Sopenharmony_ci	{ .attrs = dme1737_fan5_attr },
19158c2ecf20Sopenharmony_ci	{ .attrs = dme1737_fan6_attr },
19168c2ecf20Sopenharmony_ci};
19178c2ecf20Sopenharmony_ci
19188c2ecf20Sopenharmony_ci/*
19198c2ecf20Sopenharmony_ci * The permissions of the following zone attributes are changed to read-
19208c2ecf20Sopenharmony_ci * writeable if the chip is *not* locked. Otherwise they stay read-only.
19218c2ecf20Sopenharmony_ci */
19228c2ecf20Sopenharmony_cistatic struct attribute *dme1737_zone_chmod_attr[] = {
19238c2ecf20Sopenharmony_ci	&sensor_dev_attr_zone1_auto_point1_temp.dev_attr.attr,
19248c2ecf20Sopenharmony_ci	&sensor_dev_attr_zone1_auto_point2_temp.dev_attr.attr,
19258c2ecf20Sopenharmony_ci	&sensor_dev_attr_zone1_auto_point3_temp.dev_attr.attr,
19268c2ecf20Sopenharmony_ci	&sensor_dev_attr_zone2_auto_point1_temp.dev_attr.attr,
19278c2ecf20Sopenharmony_ci	&sensor_dev_attr_zone2_auto_point2_temp.dev_attr.attr,
19288c2ecf20Sopenharmony_ci	&sensor_dev_attr_zone2_auto_point3_temp.dev_attr.attr,
19298c2ecf20Sopenharmony_ci	NULL
19308c2ecf20Sopenharmony_ci};
19318c2ecf20Sopenharmony_ci
19328c2ecf20Sopenharmony_cistatic const struct attribute_group dme1737_zone_chmod_group = {
19338c2ecf20Sopenharmony_ci	.attrs = dme1737_zone_chmod_attr,
19348c2ecf20Sopenharmony_ci};
19358c2ecf20Sopenharmony_ci
19368c2ecf20Sopenharmony_ci
19378c2ecf20Sopenharmony_ci/*
19388c2ecf20Sopenharmony_ci * The permissions of the following zone 3 attributes are changed to read-
19398c2ecf20Sopenharmony_ci * writeable if the chip is *not* locked. Otherwise they stay read-only.
19408c2ecf20Sopenharmony_ci */
19418c2ecf20Sopenharmony_cistatic struct attribute *dme1737_zone3_chmod_attr[] = {
19428c2ecf20Sopenharmony_ci	&sensor_dev_attr_zone3_auto_point1_temp.dev_attr.attr,
19438c2ecf20Sopenharmony_ci	&sensor_dev_attr_zone3_auto_point2_temp.dev_attr.attr,
19448c2ecf20Sopenharmony_ci	&sensor_dev_attr_zone3_auto_point3_temp.dev_attr.attr,
19458c2ecf20Sopenharmony_ci	NULL
19468c2ecf20Sopenharmony_ci};
19478c2ecf20Sopenharmony_ci
19488c2ecf20Sopenharmony_cistatic const struct attribute_group dme1737_zone3_chmod_group = {
19498c2ecf20Sopenharmony_ci	.attrs = dme1737_zone3_chmod_attr,
19508c2ecf20Sopenharmony_ci};
19518c2ecf20Sopenharmony_ci
19528c2ecf20Sopenharmony_ci/*
19538c2ecf20Sopenharmony_ci * The permissions of the following PWM attributes are changed to read-
19548c2ecf20Sopenharmony_ci * writeable if the chip is *not* locked and the respective PWM is available.
19558c2ecf20Sopenharmony_ci * Otherwise they stay read-only.
19568c2ecf20Sopenharmony_ci */
19578c2ecf20Sopenharmony_cistatic struct attribute *dme1737_pwm1_chmod_attr[] = {
19588c2ecf20Sopenharmony_ci	&sensor_dev_attr_pwm1_freq.dev_attr.attr,
19598c2ecf20Sopenharmony_ci	&sensor_dev_attr_pwm1_enable.dev_attr.attr,
19608c2ecf20Sopenharmony_ci	&sensor_dev_attr_pwm1_ramp_rate.dev_attr.attr,
19618c2ecf20Sopenharmony_ci	&sensor_dev_attr_pwm1_auto_channels_zone.dev_attr.attr,
19628c2ecf20Sopenharmony_ci	&sensor_dev_attr_pwm1_auto_point1_pwm.dev_attr.attr,
19638c2ecf20Sopenharmony_ci	NULL
19648c2ecf20Sopenharmony_ci};
19658c2ecf20Sopenharmony_cistatic struct attribute *dme1737_pwm2_chmod_attr[] = {
19668c2ecf20Sopenharmony_ci	&sensor_dev_attr_pwm2_freq.dev_attr.attr,
19678c2ecf20Sopenharmony_ci	&sensor_dev_attr_pwm2_enable.dev_attr.attr,
19688c2ecf20Sopenharmony_ci	&sensor_dev_attr_pwm2_ramp_rate.dev_attr.attr,
19698c2ecf20Sopenharmony_ci	&sensor_dev_attr_pwm2_auto_channels_zone.dev_attr.attr,
19708c2ecf20Sopenharmony_ci	&sensor_dev_attr_pwm2_auto_point1_pwm.dev_attr.attr,
19718c2ecf20Sopenharmony_ci	NULL
19728c2ecf20Sopenharmony_ci};
19738c2ecf20Sopenharmony_cistatic struct attribute *dme1737_pwm3_chmod_attr[] = {
19748c2ecf20Sopenharmony_ci	&sensor_dev_attr_pwm3_freq.dev_attr.attr,
19758c2ecf20Sopenharmony_ci	&sensor_dev_attr_pwm3_enable.dev_attr.attr,
19768c2ecf20Sopenharmony_ci	&sensor_dev_attr_pwm3_ramp_rate.dev_attr.attr,
19778c2ecf20Sopenharmony_ci	&sensor_dev_attr_pwm3_auto_channels_zone.dev_attr.attr,
19788c2ecf20Sopenharmony_ci	&sensor_dev_attr_pwm3_auto_point1_pwm.dev_attr.attr,
19798c2ecf20Sopenharmony_ci	NULL
19808c2ecf20Sopenharmony_ci};
19818c2ecf20Sopenharmony_cistatic struct attribute *dme1737_pwm5_chmod_attr[] = {
19828c2ecf20Sopenharmony_ci	&sensor_dev_attr_pwm5.dev_attr.attr,
19838c2ecf20Sopenharmony_ci	&sensor_dev_attr_pwm5_freq.dev_attr.attr,
19848c2ecf20Sopenharmony_ci	NULL
19858c2ecf20Sopenharmony_ci};
19868c2ecf20Sopenharmony_cistatic struct attribute *dme1737_pwm6_chmod_attr[] = {
19878c2ecf20Sopenharmony_ci	&sensor_dev_attr_pwm6.dev_attr.attr,
19888c2ecf20Sopenharmony_ci	&sensor_dev_attr_pwm6_freq.dev_attr.attr,
19898c2ecf20Sopenharmony_ci	NULL
19908c2ecf20Sopenharmony_ci};
19918c2ecf20Sopenharmony_ci
19928c2ecf20Sopenharmony_cistatic const struct attribute_group dme1737_pwm_chmod_group[] = {
19938c2ecf20Sopenharmony_ci	{ .attrs = dme1737_pwm1_chmod_attr },
19948c2ecf20Sopenharmony_ci	{ .attrs = dme1737_pwm2_chmod_attr },
19958c2ecf20Sopenharmony_ci	{ .attrs = dme1737_pwm3_chmod_attr },
19968c2ecf20Sopenharmony_ci	{ .attrs = NULL },
19978c2ecf20Sopenharmony_ci	{ .attrs = dme1737_pwm5_chmod_attr },
19988c2ecf20Sopenharmony_ci	{ .attrs = dme1737_pwm6_chmod_attr },
19998c2ecf20Sopenharmony_ci};
20008c2ecf20Sopenharmony_ci
20018c2ecf20Sopenharmony_ci/*
20028c2ecf20Sopenharmony_ci * Pwm[1-3] are read-writeable if the associated pwm is in manual mode and the
20038c2ecf20Sopenharmony_ci * chip is not locked. Otherwise they are read-only.
20048c2ecf20Sopenharmony_ci */
20058c2ecf20Sopenharmony_cistatic struct attribute *dme1737_pwm_chmod_attr[] = {
20068c2ecf20Sopenharmony_ci	&sensor_dev_attr_pwm1.dev_attr.attr,
20078c2ecf20Sopenharmony_ci	&sensor_dev_attr_pwm2.dev_attr.attr,
20088c2ecf20Sopenharmony_ci	&sensor_dev_attr_pwm3.dev_attr.attr,
20098c2ecf20Sopenharmony_ci};
20108c2ecf20Sopenharmony_ci
20118c2ecf20Sopenharmony_ci/* ---------------------------------------------------------------------
20128c2ecf20Sopenharmony_ci * Super-IO functions
20138c2ecf20Sopenharmony_ci * --------------------------------------------------------------------- */
20148c2ecf20Sopenharmony_ci
20158c2ecf20Sopenharmony_cistatic inline void dme1737_sio_enter(int sio_cip)
20168c2ecf20Sopenharmony_ci{
20178c2ecf20Sopenharmony_ci	outb(0x55, sio_cip);
20188c2ecf20Sopenharmony_ci}
20198c2ecf20Sopenharmony_ci
20208c2ecf20Sopenharmony_cistatic inline void dme1737_sio_exit(int sio_cip)
20218c2ecf20Sopenharmony_ci{
20228c2ecf20Sopenharmony_ci	outb(0xaa, sio_cip);
20238c2ecf20Sopenharmony_ci}
20248c2ecf20Sopenharmony_ci
20258c2ecf20Sopenharmony_cistatic inline int dme1737_sio_inb(int sio_cip, int reg)
20268c2ecf20Sopenharmony_ci{
20278c2ecf20Sopenharmony_ci	outb(reg, sio_cip);
20288c2ecf20Sopenharmony_ci	return inb(sio_cip + 1);
20298c2ecf20Sopenharmony_ci}
20308c2ecf20Sopenharmony_ci
20318c2ecf20Sopenharmony_cistatic inline void dme1737_sio_outb(int sio_cip, int reg, int val)
20328c2ecf20Sopenharmony_ci{
20338c2ecf20Sopenharmony_ci	outb(reg, sio_cip);
20348c2ecf20Sopenharmony_ci	outb(val, sio_cip + 1);
20358c2ecf20Sopenharmony_ci}
20368c2ecf20Sopenharmony_ci
20378c2ecf20Sopenharmony_ci/* ---------------------------------------------------------------------
20388c2ecf20Sopenharmony_ci * Device initialization
20398c2ecf20Sopenharmony_ci * --------------------------------------------------------------------- */
20408c2ecf20Sopenharmony_ci
20418c2ecf20Sopenharmony_cistatic int dme1737_i2c_get_features(int, struct dme1737_data*);
20428c2ecf20Sopenharmony_ci
20438c2ecf20Sopenharmony_cistatic void dme1737_chmod_file(struct device *dev,
20448c2ecf20Sopenharmony_ci			       struct attribute *attr, umode_t mode)
20458c2ecf20Sopenharmony_ci{
20468c2ecf20Sopenharmony_ci	if (sysfs_chmod_file(&dev->kobj, attr, mode)) {
20478c2ecf20Sopenharmony_ci		dev_warn(dev, "Failed to change permissions of %s.\n",
20488c2ecf20Sopenharmony_ci			 attr->name);
20498c2ecf20Sopenharmony_ci	}
20508c2ecf20Sopenharmony_ci}
20518c2ecf20Sopenharmony_ci
20528c2ecf20Sopenharmony_cistatic void dme1737_chmod_group(struct device *dev,
20538c2ecf20Sopenharmony_ci				const struct attribute_group *group,
20548c2ecf20Sopenharmony_ci				umode_t mode)
20558c2ecf20Sopenharmony_ci{
20568c2ecf20Sopenharmony_ci	struct attribute **attr;
20578c2ecf20Sopenharmony_ci
20588c2ecf20Sopenharmony_ci	for (attr = group->attrs; *attr; attr++)
20598c2ecf20Sopenharmony_ci		dme1737_chmod_file(dev, *attr, mode);
20608c2ecf20Sopenharmony_ci}
20618c2ecf20Sopenharmony_ci
20628c2ecf20Sopenharmony_cistatic void dme1737_remove_files(struct device *dev)
20638c2ecf20Sopenharmony_ci{
20648c2ecf20Sopenharmony_ci	struct dme1737_data *data = dev_get_drvdata(dev);
20658c2ecf20Sopenharmony_ci	int ix;
20668c2ecf20Sopenharmony_ci
20678c2ecf20Sopenharmony_ci	for (ix = 0; ix < ARRAY_SIZE(dme1737_fan_group); ix++) {
20688c2ecf20Sopenharmony_ci		if (data->has_features & HAS_FAN(ix)) {
20698c2ecf20Sopenharmony_ci			sysfs_remove_group(&dev->kobj,
20708c2ecf20Sopenharmony_ci					   &dme1737_fan_group[ix]);
20718c2ecf20Sopenharmony_ci		}
20728c2ecf20Sopenharmony_ci	}
20738c2ecf20Sopenharmony_ci
20748c2ecf20Sopenharmony_ci	for (ix = 0; ix < ARRAY_SIZE(dme1737_pwm_group); ix++) {
20758c2ecf20Sopenharmony_ci		if (data->has_features & HAS_PWM(ix)) {
20768c2ecf20Sopenharmony_ci			sysfs_remove_group(&dev->kobj,
20778c2ecf20Sopenharmony_ci					   &dme1737_pwm_group[ix]);
20788c2ecf20Sopenharmony_ci			if ((data->has_features & HAS_PWM_MIN) && ix < 3) {
20798c2ecf20Sopenharmony_ci				sysfs_remove_file(&dev->kobj,
20808c2ecf20Sopenharmony_ci						dme1737_auto_pwm_min_attr[ix]);
20818c2ecf20Sopenharmony_ci			}
20828c2ecf20Sopenharmony_ci		}
20838c2ecf20Sopenharmony_ci	}
20848c2ecf20Sopenharmony_ci
20858c2ecf20Sopenharmony_ci	if (data->has_features & HAS_TEMP_OFFSET)
20868c2ecf20Sopenharmony_ci		sysfs_remove_group(&dev->kobj, &dme1737_temp_offset_group);
20878c2ecf20Sopenharmony_ci	if (data->has_features & HAS_VID)
20888c2ecf20Sopenharmony_ci		sysfs_remove_group(&dev->kobj, &dme1737_vid_group);
20898c2ecf20Sopenharmony_ci	if (data->has_features & HAS_ZONE3)
20908c2ecf20Sopenharmony_ci		sysfs_remove_group(&dev->kobj, &dme1737_zone3_group);
20918c2ecf20Sopenharmony_ci	if (data->has_features & HAS_ZONE_HYST)
20928c2ecf20Sopenharmony_ci		sysfs_remove_group(&dev->kobj, &dme1737_zone_hyst_group);
20938c2ecf20Sopenharmony_ci	if (data->has_features & HAS_IN7)
20948c2ecf20Sopenharmony_ci		sysfs_remove_group(&dev->kobj, &dme1737_in7_group);
20958c2ecf20Sopenharmony_ci	sysfs_remove_group(&dev->kobj, &dme1737_group);
20968c2ecf20Sopenharmony_ci
20978c2ecf20Sopenharmony_ci	if (!data->client)
20988c2ecf20Sopenharmony_ci		sysfs_remove_file(&dev->kobj, &dev_attr_name.attr);
20998c2ecf20Sopenharmony_ci}
21008c2ecf20Sopenharmony_ci
21018c2ecf20Sopenharmony_cistatic int dme1737_create_files(struct device *dev)
21028c2ecf20Sopenharmony_ci{
21038c2ecf20Sopenharmony_ci	struct dme1737_data *data = dev_get_drvdata(dev);
21048c2ecf20Sopenharmony_ci	int err, ix;
21058c2ecf20Sopenharmony_ci
21068c2ecf20Sopenharmony_ci	/* Create a name attribute for ISA devices */
21078c2ecf20Sopenharmony_ci	if (!data->client) {
21088c2ecf20Sopenharmony_ci		err = sysfs_create_file(&dev->kobj, &dev_attr_name.attr);
21098c2ecf20Sopenharmony_ci		if (err)
21108c2ecf20Sopenharmony_ci			goto exit;
21118c2ecf20Sopenharmony_ci	}
21128c2ecf20Sopenharmony_ci
21138c2ecf20Sopenharmony_ci	/* Create standard sysfs attributes */
21148c2ecf20Sopenharmony_ci	err = sysfs_create_group(&dev->kobj, &dme1737_group);
21158c2ecf20Sopenharmony_ci	if (err)
21168c2ecf20Sopenharmony_ci		goto exit_remove;
21178c2ecf20Sopenharmony_ci
21188c2ecf20Sopenharmony_ci	/* Create chip-dependent sysfs attributes */
21198c2ecf20Sopenharmony_ci	if (data->has_features & HAS_TEMP_OFFSET) {
21208c2ecf20Sopenharmony_ci		err = sysfs_create_group(&dev->kobj,
21218c2ecf20Sopenharmony_ci					 &dme1737_temp_offset_group);
21228c2ecf20Sopenharmony_ci		if (err)
21238c2ecf20Sopenharmony_ci			goto exit_remove;
21248c2ecf20Sopenharmony_ci	}
21258c2ecf20Sopenharmony_ci	if (data->has_features & HAS_VID) {
21268c2ecf20Sopenharmony_ci		err = sysfs_create_group(&dev->kobj, &dme1737_vid_group);
21278c2ecf20Sopenharmony_ci		if (err)
21288c2ecf20Sopenharmony_ci			goto exit_remove;
21298c2ecf20Sopenharmony_ci	}
21308c2ecf20Sopenharmony_ci	if (data->has_features & HAS_ZONE3) {
21318c2ecf20Sopenharmony_ci		err = sysfs_create_group(&dev->kobj, &dme1737_zone3_group);
21328c2ecf20Sopenharmony_ci		if (err)
21338c2ecf20Sopenharmony_ci			goto exit_remove;
21348c2ecf20Sopenharmony_ci	}
21358c2ecf20Sopenharmony_ci	if (data->has_features & HAS_ZONE_HYST) {
21368c2ecf20Sopenharmony_ci		err = sysfs_create_group(&dev->kobj, &dme1737_zone_hyst_group);
21378c2ecf20Sopenharmony_ci		if (err)
21388c2ecf20Sopenharmony_ci			goto exit_remove;
21398c2ecf20Sopenharmony_ci	}
21408c2ecf20Sopenharmony_ci	if (data->has_features & HAS_IN7) {
21418c2ecf20Sopenharmony_ci		err = sysfs_create_group(&dev->kobj, &dme1737_in7_group);
21428c2ecf20Sopenharmony_ci		if (err)
21438c2ecf20Sopenharmony_ci			goto exit_remove;
21448c2ecf20Sopenharmony_ci	}
21458c2ecf20Sopenharmony_ci
21468c2ecf20Sopenharmony_ci	/* Create fan sysfs attributes */
21478c2ecf20Sopenharmony_ci	for (ix = 0; ix < ARRAY_SIZE(dme1737_fan_group); ix++) {
21488c2ecf20Sopenharmony_ci		if (data->has_features & HAS_FAN(ix)) {
21498c2ecf20Sopenharmony_ci			err = sysfs_create_group(&dev->kobj,
21508c2ecf20Sopenharmony_ci						 &dme1737_fan_group[ix]);
21518c2ecf20Sopenharmony_ci			if (err)
21528c2ecf20Sopenharmony_ci				goto exit_remove;
21538c2ecf20Sopenharmony_ci		}
21548c2ecf20Sopenharmony_ci	}
21558c2ecf20Sopenharmony_ci
21568c2ecf20Sopenharmony_ci	/* Create PWM sysfs attributes */
21578c2ecf20Sopenharmony_ci	for (ix = 0; ix < ARRAY_SIZE(dme1737_pwm_group); ix++) {
21588c2ecf20Sopenharmony_ci		if (data->has_features & HAS_PWM(ix)) {
21598c2ecf20Sopenharmony_ci			err = sysfs_create_group(&dev->kobj,
21608c2ecf20Sopenharmony_ci						 &dme1737_pwm_group[ix]);
21618c2ecf20Sopenharmony_ci			if (err)
21628c2ecf20Sopenharmony_ci				goto exit_remove;
21638c2ecf20Sopenharmony_ci			if ((data->has_features & HAS_PWM_MIN) && (ix < 3)) {
21648c2ecf20Sopenharmony_ci				err = sysfs_create_file(&dev->kobj,
21658c2ecf20Sopenharmony_ci						dme1737_auto_pwm_min_attr[ix]);
21668c2ecf20Sopenharmony_ci				if (err)
21678c2ecf20Sopenharmony_ci					goto exit_remove;
21688c2ecf20Sopenharmony_ci			}
21698c2ecf20Sopenharmony_ci		}
21708c2ecf20Sopenharmony_ci	}
21718c2ecf20Sopenharmony_ci
21728c2ecf20Sopenharmony_ci	/*
21738c2ecf20Sopenharmony_ci	 * Inform if the device is locked. Otherwise change the permissions of
21748c2ecf20Sopenharmony_ci	 * selected attributes from read-only to read-writeable.
21758c2ecf20Sopenharmony_ci	 */
21768c2ecf20Sopenharmony_ci	if (data->config & 0x02) {
21778c2ecf20Sopenharmony_ci		dev_info(dev,
21788c2ecf20Sopenharmony_ci			 "Device is locked. Some attributes will be read-only.\n");
21798c2ecf20Sopenharmony_ci	} else {
21808c2ecf20Sopenharmony_ci		/* Change permissions of zone sysfs attributes */
21818c2ecf20Sopenharmony_ci		dme1737_chmod_group(dev, &dme1737_zone_chmod_group,
21828c2ecf20Sopenharmony_ci				    S_IRUGO | S_IWUSR);
21838c2ecf20Sopenharmony_ci
21848c2ecf20Sopenharmony_ci		/* Change permissions of chip-dependent sysfs attributes */
21858c2ecf20Sopenharmony_ci		if (data->has_features & HAS_TEMP_OFFSET) {
21868c2ecf20Sopenharmony_ci			dme1737_chmod_group(dev, &dme1737_temp_offset_group,
21878c2ecf20Sopenharmony_ci					    S_IRUGO | S_IWUSR);
21888c2ecf20Sopenharmony_ci		}
21898c2ecf20Sopenharmony_ci		if (data->has_features & HAS_ZONE3) {
21908c2ecf20Sopenharmony_ci			dme1737_chmod_group(dev, &dme1737_zone3_chmod_group,
21918c2ecf20Sopenharmony_ci					    S_IRUGO | S_IWUSR);
21928c2ecf20Sopenharmony_ci		}
21938c2ecf20Sopenharmony_ci		if (data->has_features & HAS_ZONE_HYST) {
21948c2ecf20Sopenharmony_ci			dme1737_chmod_group(dev, &dme1737_zone_hyst_group,
21958c2ecf20Sopenharmony_ci					    S_IRUGO | S_IWUSR);
21968c2ecf20Sopenharmony_ci		}
21978c2ecf20Sopenharmony_ci
21988c2ecf20Sopenharmony_ci		/* Change permissions of PWM sysfs attributes */
21998c2ecf20Sopenharmony_ci		for (ix = 0; ix < ARRAY_SIZE(dme1737_pwm_chmod_group); ix++) {
22008c2ecf20Sopenharmony_ci			if (data->has_features & HAS_PWM(ix)) {
22018c2ecf20Sopenharmony_ci				dme1737_chmod_group(dev,
22028c2ecf20Sopenharmony_ci						&dme1737_pwm_chmod_group[ix],
22038c2ecf20Sopenharmony_ci						S_IRUGO | S_IWUSR);
22048c2ecf20Sopenharmony_ci				if ((data->has_features & HAS_PWM_MIN) &&
22058c2ecf20Sopenharmony_ci				    ix < 3) {
22068c2ecf20Sopenharmony_ci					dme1737_chmod_file(dev,
22078c2ecf20Sopenharmony_ci						dme1737_auto_pwm_min_attr[ix],
22088c2ecf20Sopenharmony_ci						S_IRUGO | S_IWUSR);
22098c2ecf20Sopenharmony_ci				}
22108c2ecf20Sopenharmony_ci			}
22118c2ecf20Sopenharmony_ci		}
22128c2ecf20Sopenharmony_ci
22138c2ecf20Sopenharmony_ci		/* Change permissions of pwm[1-3] if in manual mode */
22148c2ecf20Sopenharmony_ci		for (ix = 0; ix < 3; ix++) {
22158c2ecf20Sopenharmony_ci			if ((data->has_features & HAS_PWM(ix)) &&
22168c2ecf20Sopenharmony_ci			    (PWM_EN_FROM_REG(data->pwm_config[ix]) == 1)) {
22178c2ecf20Sopenharmony_ci				dme1737_chmod_file(dev,
22188c2ecf20Sopenharmony_ci						dme1737_pwm_chmod_attr[ix],
22198c2ecf20Sopenharmony_ci						S_IRUGO | S_IWUSR);
22208c2ecf20Sopenharmony_ci			}
22218c2ecf20Sopenharmony_ci		}
22228c2ecf20Sopenharmony_ci	}
22238c2ecf20Sopenharmony_ci
22248c2ecf20Sopenharmony_ci	return 0;
22258c2ecf20Sopenharmony_ci
22268c2ecf20Sopenharmony_ciexit_remove:
22278c2ecf20Sopenharmony_ci	dme1737_remove_files(dev);
22288c2ecf20Sopenharmony_ciexit:
22298c2ecf20Sopenharmony_ci	return err;
22308c2ecf20Sopenharmony_ci}
22318c2ecf20Sopenharmony_ci
22328c2ecf20Sopenharmony_cistatic int dme1737_init_device(struct device *dev)
22338c2ecf20Sopenharmony_ci{
22348c2ecf20Sopenharmony_ci	struct dme1737_data *data = dev_get_drvdata(dev);
22358c2ecf20Sopenharmony_ci	struct i2c_client *client = data->client;
22368c2ecf20Sopenharmony_ci	int ix;
22378c2ecf20Sopenharmony_ci	u8 reg;
22388c2ecf20Sopenharmony_ci
22398c2ecf20Sopenharmony_ci	/* Point to the right nominal voltages array */
22408c2ecf20Sopenharmony_ci	data->in_nominal = IN_NOMINAL(data->type);
22418c2ecf20Sopenharmony_ci
22428c2ecf20Sopenharmony_ci	data->config = dme1737_read(data, DME1737_REG_CONFIG);
22438c2ecf20Sopenharmony_ci	/* Inform if part is not monitoring/started */
22448c2ecf20Sopenharmony_ci	if (!(data->config & 0x01)) {
22458c2ecf20Sopenharmony_ci		if (!force_start) {
22468c2ecf20Sopenharmony_ci			dev_err(dev,
22478c2ecf20Sopenharmony_ci				"Device is not monitoring. Use the force_start load parameter to override.\n");
22488c2ecf20Sopenharmony_ci			return -EFAULT;
22498c2ecf20Sopenharmony_ci		}
22508c2ecf20Sopenharmony_ci
22518c2ecf20Sopenharmony_ci		/* Force monitoring */
22528c2ecf20Sopenharmony_ci		data->config |= 0x01;
22538c2ecf20Sopenharmony_ci		dme1737_write(data, DME1737_REG_CONFIG, data->config);
22548c2ecf20Sopenharmony_ci	}
22558c2ecf20Sopenharmony_ci	/* Inform if part is not ready */
22568c2ecf20Sopenharmony_ci	if (!(data->config & 0x04)) {
22578c2ecf20Sopenharmony_ci		dev_err(dev, "Device is not ready.\n");
22588c2ecf20Sopenharmony_ci		return -EFAULT;
22598c2ecf20Sopenharmony_ci	}
22608c2ecf20Sopenharmony_ci
22618c2ecf20Sopenharmony_ci	/*
22628c2ecf20Sopenharmony_ci	 * Determine which optional fan and pwm features are enabled (only
22638c2ecf20Sopenharmony_ci	 * valid for I2C devices)
22648c2ecf20Sopenharmony_ci	 */
22658c2ecf20Sopenharmony_ci	if (client) {   /* I2C chip */
22668c2ecf20Sopenharmony_ci		data->config2 = dme1737_read(data, DME1737_REG_CONFIG2);
22678c2ecf20Sopenharmony_ci		/* Check if optional fan3 input is enabled */
22688c2ecf20Sopenharmony_ci		if (data->config2 & 0x04)
22698c2ecf20Sopenharmony_ci			data->has_features |= HAS_FAN(2);
22708c2ecf20Sopenharmony_ci
22718c2ecf20Sopenharmony_ci		/*
22728c2ecf20Sopenharmony_ci		 * Fan4 and pwm3 are only available if the client's I2C address
22738c2ecf20Sopenharmony_ci		 * is the default 0x2e. Otherwise the I/Os associated with
22748c2ecf20Sopenharmony_ci		 * these functions are used for addr enable/select.
22758c2ecf20Sopenharmony_ci		 */
22768c2ecf20Sopenharmony_ci		if (client->addr == 0x2e)
22778c2ecf20Sopenharmony_ci			data->has_features |= HAS_FAN(3) | HAS_PWM(2);
22788c2ecf20Sopenharmony_ci
22798c2ecf20Sopenharmony_ci		/*
22808c2ecf20Sopenharmony_ci		 * Determine which of the optional fan[5-6] and pwm[5-6]
22818c2ecf20Sopenharmony_ci		 * features are enabled. For this, we need to query the runtime
22828c2ecf20Sopenharmony_ci		 * registers through the Super-IO LPC interface. Try both
22838c2ecf20Sopenharmony_ci		 * config ports 0x2e and 0x4e.
22848c2ecf20Sopenharmony_ci		 */
22858c2ecf20Sopenharmony_ci		if (dme1737_i2c_get_features(0x2e, data) &&
22868c2ecf20Sopenharmony_ci		    dme1737_i2c_get_features(0x4e, data)) {
22878c2ecf20Sopenharmony_ci			dev_warn(dev,
22888c2ecf20Sopenharmony_ci				 "Failed to query Super-IO for optional features.\n");
22898c2ecf20Sopenharmony_ci		}
22908c2ecf20Sopenharmony_ci	}
22918c2ecf20Sopenharmony_ci
22928c2ecf20Sopenharmony_ci	/* Fan[1-2] and pwm[1-2] are present in all chips */
22938c2ecf20Sopenharmony_ci	data->has_features |= HAS_FAN(0) | HAS_FAN(1) | HAS_PWM(0) | HAS_PWM(1);
22948c2ecf20Sopenharmony_ci
22958c2ecf20Sopenharmony_ci	/* Chip-dependent features */
22968c2ecf20Sopenharmony_ci	switch (data->type) {
22978c2ecf20Sopenharmony_ci	case dme1737:
22988c2ecf20Sopenharmony_ci		data->has_features |= HAS_TEMP_OFFSET | HAS_VID | HAS_ZONE3 |
22998c2ecf20Sopenharmony_ci			HAS_ZONE_HYST | HAS_PWM_MIN;
23008c2ecf20Sopenharmony_ci		break;
23018c2ecf20Sopenharmony_ci	case sch311x:
23028c2ecf20Sopenharmony_ci		data->has_features |= HAS_TEMP_OFFSET | HAS_ZONE3 |
23038c2ecf20Sopenharmony_ci			HAS_ZONE_HYST | HAS_PWM_MIN | HAS_FAN(2) | HAS_PWM(2);
23048c2ecf20Sopenharmony_ci		break;
23058c2ecf20Sopenharmony_ci	case sch5027:
23068c2ecf20Sopenharmony_ci		data->has_features |= HAS_ZONE3;
23078c2ecf20Sopenharmony_ci		break;
23088c2ecf20Sopenharmony_ci	case sch5127:
23098c2ecf20Sopenharmony_ci		data->has_features |= HAS_FAN(2) | HAS_PWM(2) | HAS_IN7;
23108c2ecf20Sopenharmony_ci		break;
23118c2ecf20Sopenharmony_ci	default:
23128c2ecf20Sopenharmony_ci		break;
23138c2ecf20Sopenharmony_ci	}
23148c2ecf20Sopenharmony_ci
23158c2ecf20Sopenharmony_ci	dev_info(dev,
23168c2ecf20Sopenharmony_ci		 "Optional features: pwm3=%s, pwm5=%s, pwm6=%s, fan3=%s, fan4=%s, fan5=%s, fan6=%s.\n",
23178c2ecf20Sopenharmony_ci		 (data->has_features & HAS_PWM(2)) ? "yes" : "no",
23188c2ecf20Sopenharmony_ci		 (data->has_features & HAS_PWM(4)) ? "yes" : "no",
23198c2ecf20Sopenharmony_ci		 (data->has_features & HAS_PWM(5)) ? "yes" : "no",
23208c2ecf20Sopenharmony_ci		 (data->has_features & HAS_FAN(2)) ? "yes" : "no",
23218c2ecf20Sopenharmony_ci		 (data->has_features & HAS_FAN(3)) ? "yes" : "no",
23228c2ecf20Sopenharmony_ci		 (data->has_features & HAS_FAN(4)) ? "yes" : "no",
23238c2ecf20Sopenharmony_ci		 (data->has_features & HAS_FAN(5)) ? "yes" : "no");
23248c2ecf20Sopenharmony_ci
23258c2ecf20Sopenharmony_ci	reg = dme1737_read(data, DME1737_REG_TACH_PWM);
23268c2ecf20Sopenharmony_ci	/* Inform if fan-to-pwm mapping differs from the default */
23278c2ecf20Sopenharmony_ci	if (client && reg != 0xa4) {   /* I2C chip */
23288c2ecf20Sopenharmony_ci		dev_warn(dev,
23298c2ecf20Sopenharmony_ci			 "Non-standard fan to pwm mapping: fan1->pwm%d, fan2->pwm%d, fan3->pwm%d, fan4->pwm%d. %s\n",
23308c2ecf20Sopenharmony_ci			 (reg & 0x03) + 1, ((reg >> 2) & 0x03) + 1,
23318c2ecf20Sopenharmony_ci			 ((reg >> 4) & 0x03) + 1, ((reg >> 6) & 0x03) + 1,
23328c2ecf20Sopenharmony_ci			 DO_REPORT);
23338c2ecf20Sopenharmony_ci	} else if (!client && reg != 0x24) {   /* ISA chip */
23348c2ecf20Sopenharmony_ci		dev_warn(dev,
23358c2ecf20Sopenharmony_ci			 "Non-standard fan to pwm mapping: fan1->pwm%d, fan2->pwm%d, fan3->pwm%d. %s\n",
23368c2ecf20Sopenharmony_ci			 (reg & 0x03) + 1, ((reg >> 2) & 0x03) + 1,
23378c2ecf20Sopenharmony_ci			 ((reg >> 4) & 0x03) + 1, DO_REPORT);
23388c2ecf20Sopenharmony_ci	}
23398c2ecf20Sopenharmony_ci
23408c2ecf20Sopenharmony_ci	/*
23418c2ecf20Sopenharmony_ci	 * Switch pwm[1-3] to manual mode if they are currently disabled and
23428c2ecf20Sopenharmony_ci	 * set the duty-cycles to 0% (which is identical to the PWMs being
23438c2ecf20Sopenharmony_ci	 * disabled).
23448c2ecf20Sopenharmony_ci	 */
23458c2ecf20Sopenharmony_ci	if (!(data->config & 0x02)) {
23468c2ecf20Sopenharmony_ci		for (ix = 0; ix < 3; ix++) {
23478c2ecf20Sopenharmony_ci			data->pwm_config[ix] = dme1737_read(data,
23488c2ecf20Sopenharmony_ci						DME1737_REG_PWM_CONFIG(ix));
23498c2ecf20Sopenharmony_ci			if ((data->has_features & HAS_PWM(ix)) &&
23508c2ecf20Sopenharmony_ci			    (PWM_EN_FROM_REG(data->pwm_config[ix]) == -1)) {
23518c2ecf20Sopenharmony_ci				dev_info(dev,
23528c2ecf20Sopenharmony_ci					 "Switching pwm%d to manual mode.\n",
23538c2ecf20Sopenharmony_ci					 ix + 1);
23548c2ecf20Sopenharmony_ci				data->pwm_config[ix] = PWM_EN_TO_REG(1,
23558c2ecf20Sopenharmony_ci							data->pwm_config[ix]);
23568c2ecf20Sopenharmony_ci				dme1737_write(data, DME1737_REG_PWM(ix), 0);
23578c2ecf20Sopenharmony_ci				dme1737_write(data,
23588c2ecf20Sopenharmony_ci					      DME1737_REG_PWM_CONFIG(ix),
23598c2ecf20Sopenharmony_ci					      data->pwm_config[ix]);
23608c2ecf20Sopenharmony_ci			}
23618c2ecf20Sopenharmony_ci		}
23628c2ecf20Sopenharmony_ci	}
23638c2ecf20Sopenharmony_ci
23648c2ecf20Sopenharmony_ci	/* Initialize the default PWM auto channels zone (acz) assignments */
23658c2ecf20Sopenharmony_ci	data->pwm_acz[0] = 1;	/* pwm1 -> zone1 */
23668c2ecf20Sopenharmony_ci	data->pwm_acz[1] = 2;	/* pwm2 -> zone2 */
23678c2ecf20Sopenharmony_ci	data->pwm_acz[2] = 4;	/* pwm3 -> zone3 */
23688c2ecf20Sopenharmony_ci
23698c2ecf20Sopenharmony_ci	/* Set VRM */
23708c2ecf20Sopenharmony_ci	if (data->has_features & HAS_VID)
23718c2ecf20Sopenharmony_ci		data->vrm = vid_which_vrm();
23728c2ecf20Sopenharmony_ci
23738c2ecf20Sopenharmony_ci	return 0;
23748c2ecf20Sopenharmony_ci}
23758c2ecf20Sopenharmony_ci
23768c2ecf20Sopenharmony_ci/* ---------------------------------------------------------------------
23778c2ecf20Sopenharmony_ci * I2C device detection and registration
23788c2ecf20Sopenharmony_ci * --------------------------------------------------------------------- */
23798c2ecf20Sopenharmony_ci
23808c2ecf20Sopenharmony_cistatic struct i2c_driver dme1737_i2c_driver;
23818c2ecf20Sopenharmony_ci
23828c2ecf20Sopenharmony_cistatic int dme1737_i2c_get_features(int sio_cip, struct dme1737_data *data)
23838c2ecf20Sopenharmony_ci{
23848c2ecf20Sopenharmony_ci	int err = 0, reg;
23858c2ecf20Sopenharmony_ci	u16 addr;
23868c2ecf20Sopenharmony_ci
23878c2ecf20Sopenharmony_ci	dme1737_sio_enter(sio_cip);
23888c2ecf20Sopenharmony_ci
23898c2ecf20Sopenharmony_ci	/*
23908c2ecf20Sopenharmony_ci	 * Check device ID
23918c2ecf20Sopenharmony_ci	 * We currently know about two kinds of DME1737 and SCH5027.
23928c2ecf20Sopenharmony_ci	 */
23938c2ecf20Sopenharmony_ci	reg = force_id ? force_id : dme1737_sio_inb(sio_cip, 0x20);
23948c2ecf20Sopenharmony_ci	if (!(reg == DME1737_ID_1 || reg == DME1737_ID_2 ||
23958c2ecf20Sopenharmony_ci	      reg == SCH5027_ID)) {
23968c2ecf20Sopenharmony_ci		err = -ENODEV;
23978c2ecf20Sopenharmony_ci		goto exit;
23988c2ecf20Sopenharmony_ci	}
23998c2ecf20Sopenharmony_ci
24008c2ecf20Sopenharmony_ci	/* Select logical device A (runtime registers) */
24018c2ecf20Sopenharmony_ci	dme1737_sio_outb(sio_cip, 0x07, 0x0a);
24028c2ecf20Sopenharmony_ci
24038c2ecf20Sopenharmony_ci	/* Get the base address of the runtime registers */
24048c2ecf20Sopenharmony_ci	addr = (dme1737_sio_inb(sio_cip, 0x60) << 8) |
24058c2ecf20Sopenharmony_ci		dme1737_sio_inb(sio_cip, 0x61);
24068c2ecf20Sopenharmony_ci	if (!addr) {
24078c2ecf20Sopenharmony_ci		err = -ENODEV;
24088c2ecf20Sopenharmony_ci		goto exit;
24098c2ecf20Sopenharmony_ci	}
24108c2ecf20Sopenharmony_ci
24118c2ecf20Sopenharmony_ci	/*
24128c2ecf20Sopenharmony_ci	 * Read the runtime registers to determine which optional features
24138c2ecf20Sopenharmony_ci	 * are enabled and available. Bits [3:2] of registers 0x43-0x46 are set
24148c2ecf20Sopenharmony_ci	 * to '10' if the respective feature is enabled.
24158c2ecf20Sopenharmony_ci	 */
24168c2ecf20Sopenharmony_ci	if ((inb(addr + 0x43) & 0x0c) == 0x08) /* fan6 */
24178c2ecf20Sopenharmony_ci		data->has_features |= HAS_FAN(5);
24188c2ecf20Sopenharmony_ci	if ((inb(addr + 0x44) & 0x0c) == 0x08) /* pwm6 */
24198c2ecf20Sopenharmony_ci		data->has_features |= HAS_PWM(5);
24208c2ecf20Sopenharmony_ci	if ((inb(addr + 0x45) & 0x0c) == 0x08) /* fan5 */
24218c2ecf20Sopenharmony_ci		data->has_features |= HAS_FAN(4);
24228c2ecf20Sopenharmony_ci	if ((inb(addr + 0x46) & 0x0c) == 0x08) /* pwm5 */
24238c2ecf20Sopenharmony_ci		data->has_features |= HAS_PWM(4);
24248c2ecf20Sopenharmony_ci
24258c2ecf20Sopenharmony_ciexit:
24268c2ecf20Sopenharmony_ci	dme1737_sio_exit(sio_cip);
24278c2ecf20Sopenharmony_ci
24288c2ecf20Sopenharmony_ci	return err;
24298c2ecf20Sopenharmony_ci}
24308c2ecf20Sopenharmony_ci
24318c2ecf20Sopenharmony_ci/* Return 0 if detection is successful, -ENODEV otherwise */
24328c2ecf20Sopenharmony_cistatic int dme1737_i2c_detect(struct i2c_client *client,
24338c2ecf20Sopenharmony_ci			      struct i2c_board_info *info)
24348c2ecf20Sopenharmony_ci{
24358c2ecf20Sopenharmony_ci	struct i2c_adapter *adapter = client->adapter;
24368c2ecf20Sopenharmony_ci	struct device *dev = &adapter->dev;
24378c2ecf20Sopenharmony_ci	u8 company, verstep = 0;
24388c2ecf20Sopenharmony_ci	const char *name;
24398c2ecf20Sopenharmony_ci
24408c2ecf20Sopenharmony_ci	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
24418c2ecf20Sopenharmony_ci		return -ENODEV;
24428c2ecf20Sopenharmony_ci
24438c2ecf20Sopenharmony_ci	company = i2c_smbus_read_byte_data(client, DME1737_REG_COMPANY);
24448c2ecf20Sopenharmony_ci	verstep = i2c_smbus_read_byte_data(client, DME1737_REG_VERSTEP);
24458c2ecf20Sopenharmony_ci
24468c2ecf20Sopenharmony_ci	if (company == DME1737_COMPANY_SMSC &&
24478c2ecf20Sopenharmony_ci	    verstep == SCH5027_VERSTEP) {
24488c2ecf20Sopenharmony_ci		name = "sch5027";
24498c2ecf20Sopenharmony_ci	} else if (company == DME1737_COMPANY_SMSC &&
24508c2ecf20Sopenharmony_ci		   (verstep & DME1737_VERSTEP_MASK) == DME1737_VERSTEP) {
24518c2ecf20Sopenharmony_ci		name = "dme1737";
24528c2ecf20Sopenharmony_ci	} else {
24538c2ecf20Sopenharmony_ci		return -ENODEV;
24548c2ecf20Sopenharmony_ci	}
24558c2ecf20Sopenharmony_ci
24568c2ecf20Sopenharmony_ci	dev_info(dev, "Found a %s chip at 0x%02x (rev 0x%02x).\n",
24578c2ecf20Sopenharmony_ci		 verstep == SCH5027_VERSTEP ? "SCH5027" : "DME1737",
24588c2ecf20Sopenharmony_ci		 client->addr, verstep);
24598c2ecf20Sopenharmony_ci	strlcpy(info->type, name, I2C_NAME_SIZE);
24608c2ecf20Sopenharmony_ci
24618c2ecf20Sopenharmony_ci	return 0;
24628c2ecf20Sopenharmony_ci}
24638c2ecf20Sopenharmony_ci
24648c2ecf20Sopenharmony_cistatic const struct i2c_device_id dme1737_id[];
24658c2ecf20Sopenharmony_ci
24668c2ecf20Sopenharmony_cistatic int dme1737_i2c_probe(struct i2c_client *client)
24678c2ecf20Sopenharmony_ci{
24688c2ecf20Sopenharmony_ci	struct dme1737_data *data;
24698c2ecf20Sopenharmony_ci	struct device *dev = &client->dev;
24708c2ecf20Sopenharmony_ci	int err;
24718c2ecf20Sopenharmony_ci
24728c2ecf20Sopenharmony_ci	data = devm_kzalloc(dev, sizeof(struct dme1737_data), GFP_KERNEL);
24738c2ecf20Sopenharmony_ci	if (!data)
24748c2ecf20Sopenharmony_ci		return -ENOMEM;
24758c2ecf20Sopenharmony_ci
24768c2ecf20Sopenharmony_ci	i2c_set_clientdata(client, data);
24778c2ecf20Sopenharmony_ci	data->type = i2c_match_id(dme1737_id, client)->driver_data;
24788c2ecf20Sopenharmony_ci	data->client = client;
24798c2ecf20Sopenharmony_ci	data->name = client->name;
24808c2ecf20Sopenharmony_ci	mutex_init(&data->update_lock);
24818c2ecf20Sopenharmony_ci
24828c2ecf20Sopenharmony_ci	/* Initialize the DME1737 chip */
24838c2ecf20Sopenharmony_ci	err = dme1737_init_device(dev);
24848c2ecf20Sopenharmony_ci	if (err) {
24858c2ecf20Sopenharmony_ci		dev_err(dev, "Failed to initialize device.\n");
24868c2ecf20Sopenharmony_ci		return err;
24878c2ecf20Sopenharmony_ci	}
24888c2ecf20Sopenharmony_ci
24898c2ecf20Sopenharmony_ci	/* Create sysfs files */
24908c2ecf20Sopenharmony_ci	err = dme1737_create_files(dev);
24918c2ecf20Sopenharmony_ci	if (err) {
24928c2ecf20Sopenharmony_ci		dev_err(dev, "Failed to create sysfs files.\n");
24938c2ecf20Sopenharmony_ci		return err;
24948c2ecf20Sopenharmony_ci	}
24958c2ecf20Sopenharmony_ci
24968c2ecf20Sopenharmony_ci	/* Register device */
24978c2ecf20Sopenharmony_ci	data->hwmon_dev = hwmon_device_register(dev);
24988c2ecf20Sopenharmony_ci	if (IS_ERR(data->hwmon_dev)) {
24998c2ecf20Sopenharmony_ci		dev_err(dev, "Failed to register device.\n");
25008c2ecf20Sopenharmony_ci		err = PTR_ERR(data->hwmon_dev);
25018c2ecf20Sopenharmony_ci		goto exit_remove;
25028c2ecf20Sopenharmony_ci	}
25038c2ecf20Sopenharmony_ci
25048c2ecf20Sopenharmony_ci	return 0;
25058c2ecf20Sopenharmony_ci
25068c2ecf20Sopenharmony_ciexit_remove:
25078c2ecf20Sopenharmony_ci	dme1737_remove_files(dev);
25088c2ecf20Sopenharmony_ci	return err;
25098c2ecf20Sopenharmony_ci}
25108c2ecf20Sopenharmony_ci
25118c2ecf20Sopenharmony_cistatic int dme1737_i2c_remove(struct i2c_client *client)
25128c2ecf20Sopenharmony_ci{
25138c2ecf20Sopenharmony_ci	struct dme1737_data *data = i2c_get_clientdata(client);
25148c2ecf20Sopenharmony_ci
25158c2ecf20Sopenharmony_ci	hwmon_device_unregister(data->hwmon_dev);
25168c2ecf20Sopenharmony_ci	dme1737_remove_files(&client->dev);
25178c2ecf20Sopenharmony_ci
25188c2ecf20Sopenharmony_ci	return 0;
25198c2ecf20Sopenharmony_ci}
25208c2ecf20Sopenharmony_ci
25218c2ecf20Sopenharmony_cistatic const struct i2c_device_id dme1737_id[] = {
25228c2ecf20Sopenharmony_ci	{ "dme1737", dme1737 },
25238c2ecf20Sopenharmony_ci	{ "sch5027", sch5027 },
25248c2ecf20Sopenharmony_ci	{ }
25258c2ecf20Sopenharmony_ci};
25268c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(i2c, dme1737_id);
25278c2ecf20Sopenharmony_ci
25288c2ecf20Sopenharmony_cistatic struct i2c_driver dme1737_i2c_driver = {
25298c2ecf20Sopenharmony_ci	.class = I2C_CLASS_HWMON,
25308c2ecf20Sopenharmony_ci	.driver = {
25318c2ecf20Sopenharmony_ci		.name = "dme1737",
25328c2ecf20Sopenharmony_ci	},
25338c2ecf20Sopenharmony_ci	.probe_new = dme1737_i2c_probe,
25348c2ecf20Sopenharmony_ci	.remove = dme1737_i2c_remove,
25358c2ecf20Sopenharmony_ci	.id_table = dme1737_id,
25368c2ecf20Sopenharmony_ci	.detect = dme1737_i2c_detect,
25378c2ecf20Sopenharmony_ci	.address_list = normal_i2c,
25388c2ecf20Sopenharmony_ci};
25398c2ecf20Sopenharmony_ci
25408c2ecf20Sopenharmony_ci/* ---------------------------------------------------------------------
25418c2ecf20Sopenharmony_ci * ISA device detection and registration
25428c2ecf20Sopenharmony_ci * --------------------------------------------------------------------- */
25438c2ecf20Sopenharmony_ci
25448c2ecf20Sopenharmony_cistatic int __init dme1737_isa_detect(int sio_cip, unsigned short *addr)
25458c2ecf20Sopenharmony_ci{
25468c2ecf20Sopenharmony_ci	int err = 0, reg;
25478c2ecf20Sopenharmony_ci	unsigned short base_addr;
25488c2ecf20Sopenharmony_ci
25498c2ecf20Sopenharmony_ci	dme1737_sio_enter(sio_cip);
25508c2ecf20Sopenharmony_ci
25518c2ecf20Sopenharmony_ci	/*
25528c2ecf20Sopenharmony_ci	 * Check device ID
25538c2ecf20Sopenharmony_ci	 * We currently know about SCH3112, SCH3114, SCH3116, and SCH5127
25548c2ecf20Sopenharmony_ci	 */
25558c2ecf20Sopenharmony_ci	reg = force_id ? force_id : dme1737_sio_inb(sio_cip, 0x20);
25568c2ecf20Sopenharmony_ci	if (!(reg == SCH3112_ID || reg == SCH3114_ID || reg == SCH3116_ID ||
25578c2ecf20Sopenharmony_ci	      reg == SCH5127_ID)) {
25588c2ecf20Sopenharmony_ci		err = -ENODEV;
25598c2ecf20Sopenharmony_ci		goto exit;
25608c2ecf20Sopenharmony_ci	}
25618c2ecf20Sopenharmony_ci
25628c2ecf20Sopenharmony_ci	/* Select logical device A (runtime registers) */
25638c2ecf20Sopenharmony_ci	dme1737_sio_outb(sio_cip, 0x07, 0x0a);
25648c2ecf20Sopenharmony_ci
25658c2ecf20Sopenharmony_ci	/* Get the base address of the runtime registers */
25668c2ecf20Sopenharmony_ci	base_addr = (dme1737_sio_inb(sio_cip, 0x60) << 8) |
25678c2ecf20Sopenharmony_ci		     dme1737_sio_inb(sio_cip, 0x61);
25688c2ecf20Sopenharmony_ci	if (!base_addr) {
25698c2ecf20Sopenharmony_ci		pr_err("Base address not set\n");
25708c2ecf20Sopenharmony_ci		err = -ENODEV;
25718c2ecf20Sopenharmony_ci		goto exit;
25728c2ecf20Sopenharmony_ci	}
25738c2ecf20Sopenharmony_ci
25748c2ecf20Sopenharmony_ci	/*
25758c2ecf20Sopenharmony_ci	 * Access to the hwmon registers is through an index/data register
25768c2ecf20Sopenharmony_ci	 * pair located at offset 0x70/0x71.
25778c2ecf20Sopenharmony_ci	 */
25788c2ecf20Sopenharmony_ci	*addr = base_addr + 0x70;
25798c2ecf20Sopenharmony_ci
25808c2ecf20Sopenharmony_ciexit:
25818c2ecf20Sopenharmony_ci	dme1737_sio_exit(sio_cip);
25828c2ecf20Sopenharmony_ci	return err;
25838c2ecf20Sopenharmony_ci}
25848c2ecf20Sopenharmony_ci
25858c2ecf20Sopenharmony_cistatic int __init dme1737_isa_device_add(unsigned short addr)
25868c2ecf20Sopenharmony_ci{
25878c2ecf20Sopenharmony_ci	struct resource res = {
25888c2ecf20Sopenharmony_ci		.start	= addr,
25898c2ecf20Sopenharmony_ci		.end	= addr + DME1737_EXTENT - 1,
25908c2ecf20Sopenharmony_ci		.name	= "dme1737",
25918c2ecf20Sopenharmony_ci		.flags	= IORESOURCE_IO,
25928c2ecf20Sopenharmony_ci	};
25938c2ecf20Sopenharmony_ci	int err;
25948c2ecf20Sopenharmony_ci
25958c2ecf20Sopenharmony_ci	err = acpi_check_resource_conflict(&res);
25968c2ecf20Sopenharmony_ci	if (err)
25978c2ecf20Sopenharmony_ci		goto exit;
25988c2ecf20Sopenharmony_ci
25998c2ecf20Sopenharmony_ci	pdev = platform_device_alloc("dme1737", addr);
26008c2ecf20Sopenharmony_ci	if (!pdev) {
26018c2ecf20Sopenharmony_ci		pr_err("Failed to allocate device\n");
26028c2ecf20Sopenharmony_ci		err = -ENOMEM;
26038c2ecf20Sopenharmony_ci		goto exit;
26048c2ecf20Sopenharmony_ci	}
26058c2ecf20Sopenharmony_ci
26068c2ecf20Sopenharmony_ci	err = platform_device_add_resources(pdev, &res, 1);
26078c2ecf20Sopenharmony_ci	if (err) {
26088c2ecf20Sopenharmony_ci		pr_err("Failed to add device resource (err = %d)\n", err);
26098c2ecf20Sopenharmony_ci		goto exit_device_put;
26108c2ecf20Sopenharmony_ci	}
26118c2ecf20Sopenharmony_ci
26128c2ecf20Sopenharmony_ci	err = platform_device_add(pdev);
26138c2ecf20Sopenharmony_ci	if (err) {
26148c2ecf20Sopenharmony_ci		pr_err("Failed to add device (err = %d)\n", err);
26158c2ecf20Sopenharmony_ci		goto exit_device_put;
26168c2ecf20Sopenharmony_ci	}
26178c2ecf20Sopenharmony_ci
26188c2ecf20Sopenharmony_ci	return 0;
26198c2ecf20Sopenharmony_ci
26208c2ecf20Sopenharmony_ciexit_device_put:
26218c2ecf20Sopenharmony_ci	platform_device_put(pdev);
26228c2ecf20Sopenharmony_ci	pdev = NULL;
26238c2ecf20Sopenharmony_ciexit:
26248c2ecf20Sopenharmony_ci	return err;
26258c2ecf20Sopenharmony_ci}
26268c2ecf20Sopenharmony_ci
26278c2ecf20Sopenharmony_cistatic int dme1737_isa_probe(struct platform_device *pdev)
26288c2ecf20Sopenharmony_ci{
26298c2ecf20Sopenharmony_ci	u8 company, device;
26308c2ecf20Sopenharmony_ci	struct resource *res;
26318c2ecf20Sopenharmony_ci	struct dme1737_data *data;
26328c2ecf20Sopenharmony_ci	struct device *dev = &pdev->dev;
26338c2ecf20Sopenharmony_ci	int err;
26348c2ecf20Sopenharmony_ci
26358c2ecf20Sopenharmony_ci	res = platform_get_resource(pdev, IORESOURCE_IO, 0);
26368c2ecf20Sopenharmony_ci	if (!devm_request_region(dev, res->start, DME1737_EXTENT, "dme1737")) {
26378c2ecf20Sopenharmony_ci		dev_err(dev, "Failed to request region 0x%04x-0x%04x.\n",
26388c2ecf20Sopenharmony_ci			(unsigned short)res->start,
26398c2ecf20Sopenharmony_ci			(unsigned short)res->start + DME1737_EXTENT - 1);
26408c2ecf20Sopenharmony_ci		return -EBUSY;
26418c2ecf20Sopenharmony_ci	}
26428c2ecf20Sopenharmony_ci
26438c2ecf20Sopenharmony_ci	data = devm_kzalloc(dev, sizeof(struct dme1737_data), GFP_KERNEL);
26448c2ecf20Sopenharmony_ci	if (!data)
26458c2ecf20Sopenharmony_ci		return -ENOMEM;
26468c2ecf20Sopenharmony_ci
26478c2ecf20Sopenharmony_ci	data->addr = res->start;
26488c2ecf20Sopenharmony_ci	platform_set_drvdata(pdev, data);
26498c2ecf20Sopenharmony_ci
26508c2ecf20Sopenharmony_ci	/* Skip chip detection if module is loaded with force_id parameter */
26518c2ecf20Sopenharmony_ci	switch (force_id) {
26528c2ecf20Sopenharmony_ci	case SCH3112_ID:
26538c2ecf20Sopenharmony_ci	case SCH3114_ID:
26548c2ecf20Sopenharmony_ci	case SCH3116_ID:
26558c2ecf20Sopenharmony_ci		data->type = sch311x;
26568c2ecf20Sopenharmony_ci		break;
26578c2ecf20Sopenharmony_ci	case SCH5127_ID:
26588c2ecf20Sopenharmony_ci		data->type = sch5127;
26598c2ecf20Sopenharmony_ci		break;
26608c2ecf20Sopenharmony_ci	default:
26618c2ecf20Sopenharmony_ci		company = dme1737_read(data, DME1737_REG_COMPANY);
26628c2ecf20Sopenharmony_ci		device = dme1737_read(data, DME1737_REG_DEVICE);
26638c2ecf20Sopenharmony_ci
26648c2ecf20Sopenharmony_ci		if ((company == DME1737_COMPANY_SMSC) &&
26658c2ecf20Sopenharmony_ci		    (device == SCH311X_DEVICE)) {
26668c2ecf20Sopenharmony_ci			data->type = sch311x;
26678c2ecf20Sopenharmony_ci		} else if ((company == DME1737_COMPANY_SMSC) &&
26688c2ecf20Sopenharmony_ci			   (device == SCH5127_DEVICE)) {
26698c2ecf20Sopenharmony_ci			data->type = sch5127;
26708c2ecf20Sopenharmony_ci		} else {
26718c2ecf20Sopenharmony_ci			return -ENODEV;
26728c2ecf20Sopenharmony_ci		}
26738c2ecf20Sopenharmony_ci	}
26748c2ecf20Sopenharmony_ci
26758c2ecf20Sopenharmony_ci	if (data->type == sch5127)
26768c2ecf20Sopenharmony_ci		data->name = "sch5127";
26778c2ecf20Sopenharmony_ci	else
26788c2ecf20Sopenharmony_ci		data->name = "sch311x";
26798c2ecf20Sopenharmony_ci
26808c2ecf20Sopenharmony_ci	/* Initialize the mutex */
26818c2ecf20Sopenharmony_ci	mutex_init(&data->update_lock);
26828c2ecf20Sopenharmony_ci
26838c2ecf20Sopenharmony_ci	dev_info(dev, "Found a %s chip at 0x%04x\n",
26848c2ecf20Sopenharmony_ci		 data->type == sch5127 ? "SCH5127" : "SCH311x", data->addr);
26858c2ecf20Sopenharmony_ci
26868c2ecf20Sopenharmony_ci	/* Initialize the chip */
26878c2ecf20Sopenharmony_ci	err = dme1737_init_device(dev);
26888c2ecf20Sopenharmony_ci	if (err) {
26898c2ecf20Sopenharmony_ci		dev_err(dev, "Failed to initialize device.\n");
26908c2ecf20Sopenharmony_ci		return err;
26918c2ecf20Sopenharmony_ci	}
26928c2ecf20Sopenharmony_ci
26938c2ecf20Sopenharmony_ci	/* Create sysfs files */
26948c2ecf20Sopenharmony_ci	err = dme1737_create_files(dev);
26958c2ecf20Sopenharmony_ci	if (err) {
26968c2ecf20Sopenharmony_ci		dev_err(dev, "Failed to create sysfs files.\n");
26978c2ecf20Sopenharmony_ci		return err;
26988c2ecf20Sopenharmony_ci	}
26998c2ecf20Sopenharmony_ci
27008c2ecf20Sopenharmony_ci	/* Register device */
27018c2ecf20Sopenharmony_ci	data->hwmon_dev = hwmon_device_register(dev);
27028c2ecf20Sopenharmony_ci	if (IS_ERR(data->hwmon_dev)) {
27038c2ecf20Sopenharmony_ci		dev_err(dev, "Failed to register device.\n");
27048c2ecf20Sopenharmony_ci		err = PTR_ERR(data->hwmon_dev);
27058c2ecf20Sopenharmony_ci		goto exit_remove_files;
27068c2ecf20Sopenharmony_ci	}
27078c2ecf20Sopenharmony_ci
27088c2ecf20Sopenharmony_ci	return 0;
27098c2ecf20Sopenharmony_ci
27108c2ecf20Sopenharmony_ciexit_remove_files:
27118c2ecf20Sopenharmony_ci	dme1737_remove_files(dev);
27128c2ecf20Sopenharmony_ci	return err;
27138c2ecf20Sopenharmony_ci}
27148c2ecf20Sopenharmony_ci
27158c2ecf20Sopenharmony_cistatic int dme1737_isa_remove(struct platform_device *pdev)
27168c2ecf20Sopenharmony_ci{
27178c2ecf20Sopenharmony_ci	struct dme1737_data *data = platform_get_drvdata(pdev);
27188c2ecf20Sopenharmony_ci
27198c2ecf20Sopenharmony_ci	hwmon_device_unregister(data->hwmon_dev);
27208c2ecf20Sopenharmony_ci	dme1737_remove_files(&pdev->dev);
27218c2ecf20Sopenharmony_ci
27228c2ecf20Sopenharmony_ci	return 0;
27238c2ecf20Sopenharmony_ci}
27248c2ecf20Sopenharmony_ci
27258c2ecf20Sopenharmony_cistatic struct platform_driver dme1737_isa_driver = {
27268c2ecf20Sopenharmony_ci	.driver = {
27278c2ecf20Sopenharmony_ci		.name = "dme1737",
27288c2ecf20Sopenharmony_ci	},
27298c2ecf20Sopenharmony_ci	.probe = dme1737_isa_probe,
27308c2ecf20Sopenharmony_ci	.remove = dme1737_isa_remove,
27318c2ecf20Sopenharmony_ci};
27328c2ecf20Sopenharmony_ci
27338c2ecf20Sopenharmony_ci/* ---------------------------------------------------------------------
27348c2ecf20Sopenharmony_ci * Module initialization and cleanup
27358c2ecf20Sopenharmony_ci * --------------------------------------------------------------------- */
27368c2ecf20Sopenharmony_ci
27378c2ecf20Sopenharmony_cistatic int __init dme1737_init(void)
27388c2ecf20Sopenharmony_ci{
27398c2ecf20Sopenharmony_ci	int err;
27408c2ecf20Sopenharmony_ci	unsigned short addr;
27418c2ecf20Sopenharmony_ci
27428c2ecf20Sopenharmony_ci	err = i2c_add_driver(&dme1737_i2c_driver);
27438c2ecf20Sopenharmony_ci	if (err)
27448c2ecf20Sopenharmony_ci		goto exit;
27458c2ecf20Sopenharmony_ci
27468c2ecf20Sopenharmony_ci	if (dme1737_isa_detect(0x2e, &addr) &&
27478c2ecf20Sopenharmony_ci	    dme1737_isa_detect(0x4e, &addr) &&
27488c2ecf20Sopenharmony_ci	    (!probe_all_addr ||
27498c2ecf20Sopenharmony_ci	     (dme1737_isa_detect(0x162e, &addr) &&
27508c2ecf20Sopenharmony_ci	      dme1737_isa_detect(0x164e, &addr)))) {
27518c2ecf20Sopenharmony_ci		/* Return 0 if we didn't find an ISA device */
27528c2ecf20Sopenharmony_ci		return 0;
27538c2ecf20Sopenharmony_ci	}
27548c2ecf20Sopenharmony_ci
27558c2ecf20Sopenharmony_ci	err = platform_driver_register(&dme1737_isa_driver);
27568c2ecf20Sopenharmony_ci	if (err)
27578c2ecf20Sopenharmony_ci		goto exit_del_i2c_driver;
27588c2ecf20Sopenharmony_ci
27598c2ecf20Sopenharmony_ci	/* Sets global pdev as a side effect */
27608c2ecf20Sopenharmony_ci	err = dme1737_isa_device_add(addr);
27618c2ecf20Sopenharmony_ci	if (err)
27628c2ecf20Sopenharmony_ci		goto exit_del_isa_driver;
27638c2ecf20Sopenharmony_ci
27648c2ecf20Sopenharmony_ci	return 0;
27658c2ecf20Sopenharmony_ci
27668c2ecf20Sopenharmony_ciexit_del_isa_driver:
27678c2ecf20Sopenharmony_ci	platform_driver_unregister(&dme1737_isa_driver);
27688c2ecf20Sopenharmony_ciexit_del_i2c_driver:
27698c2ecf20Sopenharmony_ci	i2c_del_driver(&dme1737_i2c_driver);
27708c2ecf20Sopenharmony_ciexit:
27718c2ecf20Sopenharmony_ci	return err;
27728c2ecf20Sopenharmony_ci}
27738c2ecf20Sopenharmony_ci
27748c2ecf20Sopenharmony_cistatic void __exit dme1737_exit(void)
27758c2ecf20Sopenharmony_ci{
27768c2ecf20Sopenharmony_ci	if (pdev) {
27778c2ecf20Sopenharmony_ci		platform_device_unregister(pdev);
27788c2ecf20Sopenharmony_ci		platform_driver_unregister(&dme1737_isa_driver);
27798c2ecf20Sopenharmony_ci	}
27808c2ecf20Sopenharmony_ci
27818c2ecf20Sopenharmony_ci	i2c_del_driver(&dme1737_i2c_driver);
27828c2ecf20Sopenharmony_ci}
27838c2ecf20Sopenharmony_ci
27848c2ecf20Sopenharmony_ciMODULE_AUTHOR("Juerg Haefliger <juergh@gmail.com>");
27858c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("DME1737 sensors");
27868c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL");
27878c2ecf20Sopenharmony_ci
27888c2ecf20Sopenharmony_cimodule_init(dme1737_init);
27898c2ecf20Sopenharmony_cimodule_exit(dme1737_exit);
2790