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