162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * dme1737.c - Driver for the SMSC DME1737, Asus A8000, SMSC SCH311x, SCH5027, 462306a36Sopenharmony_ci * and SCH5127 Super-I/O chips integrated hardware monitoring 562306a36Sopenharmony_ci * features. 662306a36Sopenharmony_ci * Copyright (c) 2007, 2008, 2009, 2010 Juerg Haefliger <juergh@gmail.com> 762306a36Sopenharmony_ci * 862306a36Sopenharmony_ci * This driver is an I2C/ISA hybrid, meaning that it uses the I2C bus to access 962306a36Sopenharmony_ci * the chip registers if a DME1737, A8000, or SCH5027 is found and the ISA bus 1062306a36Sopenharmony_ci * if a SCH311x or SCH5127 chip is found. Both types of chips have very 1162306a36Sopenharmony_ci * similar hardware monitoring capabilities but differ in the way they can be 1262306a36Sopenharmony_ci * accessed. 1362306a36Sopenharmony_ci */ 1462306a36Sopenharmony_ci 1562306a36Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_ci#include <linux/module.h> 1862306a36Sopenharmony_ci#include <linux/init.h> 1962306a36Sopenharmony_ci#include <linux/slab.h> 2062306a36Sopenharmony_ci#include <linux/jiffies.h> 2162306a36Sopenharmony_ci#include <linux/i2c.h> 2262306a36Sopenharmony_ci#include <linux/platform_device.h> 2362306a36Sopenharmony_ci#include <linux/hwmon.h> 2462306a36Sopenharmony_ci#include <linux/hwmon-sysfs.h> 2562306a36Sopenharmony_ci#include <linux/hwmon-vid.h> 2662306a36Sopenharmony_ci#include <linux/err.h> 2762306a36Sopenharmony_ci#include <linux/mutex.h> 2862306a36Sopenharmony_ci#include <linux/acpi.h> 2962306a36Sopenharmony_ci#include <linux/io.h> 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_ci/* ISA device, if found */ 3262306a36Sopenharmony_cistatic struct platform_device *pdev; 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_ci/* Module load parameters */ 3562306a36Sopenharmony_cistatic bool force_start; 3662306a36Sopenharmony_cimodule_param(force_start, bool, 0); 3762306a36Sopenharmony_ciMODULE_PARM_DESC(force_start, "Force the chip to start monitoring inputs"); 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_cistatic unsigned short force_id; 4062306a36Sopenharmony_cimodule_param(force_id, ushort, 0); 4162306a36Sopenharmony_ciMODULE_PARM_DESC(force_id, "Override the detected device ID"); 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_cistatic bool probe_all_addr; 4462306a36Sopenharmony_cimodule_param(probe_all_addr, bool, 0); 4562306a36Sopenharmony_ciMODULE_PARM_DESC(probe_all_addr, 4662306a36Sopenharmony_ci "Include probing of non-standard LPC addresses"); 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_ci/* Addresses to scan */ 4962306a36Sopenharmony_cistatic const unsigned short normal_i2c[] = {0x2c, 0x2d, 0x2e, I2C_CLIENT_END}; 5062306a36Sopenharmony_ci 5162306a36Sopenharmony_cienum chips { dme1737, sch5027, sch311x, sch5127 }; 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_ci#define DO_REPORT "Please report to the driver maintainer." 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_ci/* --------------------------------------------------------------------- 5662306a36Sopenharmony_ci * Registers 5762306a36Sopenharmony_ci * 5862306a36Sopenharmony_ci * The sensors are defined as follows: 5962306a36Sopenharmony_ci * 6062306a36Sopenharmony_ci * Voltages Temperatures 6162306a36Sopenharmony_ci * -------- ------------ 6262306a36Sopenharmony_ci * in0 +5VTR (+5V stdby) temp1 Remote diode 1 6362306a36Sopenharmony_ci * in1 Vccp (proc core) temp2 Internal temp 6462306a36Sopenharmony_ci * in2 VCC (internal +3.3V) temp3 Remote diode 2 6562306a36Sopenharmony_ci * in3 +5V 6662306a36Sopenharmony_ci * in4 +12V 6762306a36Sopenharmony_ci * in5 VTR (+3.3V stby) 6862306a36Sopenharmony_ci * in6 Vbat 6962306a36Sopenharmony_ci * in7 Vtrip (sch5127 only) 7062306a36Sopenharmony_ci * 7162306a36Sopenharmony_ci * --------------------------------------------------------------------- */ 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_ci/* Voltages (in) numbered 0-7 (ix) */ 7462306a36Sopenharmony_ci#define DME1737_REG_IN(ix) ((ix) < 5 ? 0x20 + (ix) : \ 7562306a36Sopenharmony_ci (ix) < 7 ? 0x94 + (ix) : \ 7662306a36Sopenharmony_ci 0x1f) 7762306a36Sopenharmony_ci#define DME1737_REG_IN_MIN(ix) ((ix) < 5 ? 0x44 + (ix) * 2 \ 7862306a36Sopenharmony_ci : 0x91 + (ix) * 2) 7962306a36Sopenharmony_ci#define DME1737_REG_IN_MAX(ix) ((ix) < 5 ? 0x45 + (ix) * 2 \ 8062306a36Sopenharmony_ci : 0x92 + (ix) * 2) 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_ci/* Temperatures (temp) numbered 0-2 (ix) */ 8362306a36Sopenharmony_ci#define DME1737_REG_TEMP(ix) (0x25 + (ix)) 8462306a36Sopenharmony_ci#define DME1737_REG_TEMP_MIN(ix) (0x4e + (ix) * 2) 8562306a36Sopenharmony_ci#define DME1737_REG_TEMP_MAX(ix) (0x4f + (ix) * 2) 8662306a36Sopenharmony_ci#define DME1737_REG_TEMP_OFFSET(ix) ((ix) == 0 ? 0x1f \ 8762306a36Sopenharmony_ci : 0x1c + (ix)) 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_ci/* 9062306a36Sopenharmony_ci * Voltage and temperature LSBs 9162306a36Sopenharmony_ci * The LSBs (4 bits each) are stored in 5 registers with the following layouts: 9262306a36Sopenharmony_ci * IN_TEMP_LSB(0) = [in5, in6] 9362306a36Sopenharmony_ci * IN_TEMP_LSB(1) = [temp3, temp1] 9462306a36Sopenharmony_ci * IN_TEMP_LSB(2) = [in4, temp2] 9562306a36Sopenharmony_ci * IN_TEMP_LSB(3) = [in3, in0] 9662306a36Sopenharmony_ci * IN_TEMP_LSB(4) = [in2, in1] 9762306a36Sopenharmony_ci * IN_TEMP_LSB(5) = [res, in7] 9862306a36Sopenharmony_ci */ 9962306a36Sopenharmony_ci#define DME1737_REG_IN_TEMP_LSB(ix) (0x84 + (ix)) 10062306a36Sopenharmony_cistatic const u8 DME1737_REG_IN_LSB[] = {3, 4, 4, 3, 2, 0, 0, 5}; 10162306a36Sopenharmony_cistatic const u8 DME1737_REG_IN_LSB_SHL[] = {4, 4, 0, 0, 0, 0, 4, 4}; 10262306a36Sopenharmony_cistatic const u8 DME1737_REG_TEMP_LSB[] = {1, 2, 1}; 10362306a36Sopenharmony_cistatic const u8 DME1737_REG_TEMP_LSB_SHL[] = {4, 4, 0}; 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_ci/* Fans numbered 0-5 (ix) */ 10662306a36Sopenharmony_ci#define DME1737_REG_FAN(ix) ((ix) < 4 ? 0x28 + (ix) * 2 \ 10762306a36Sopenharmony_ci : 0xa1 + (ix) * 2) 10862306a36Sopenharmony_ci#define DME1737_REG_FAN_MIN(ix) ((ix) < 4 ? 0x54 + (ix) * 2 \ 10962306a36Sopenharmony_ci : 0xa5 + (ix) * 2) 11062306a36Sopenharmony_ci#define DME1737_REG_FAN_OPT(ix) ((ix) < 4 ? 0x90 + (ix) \ 11162306a36Sopenharmony_ci : 0xb2 + (ix)) 11262306a36Sopenharmony_ci#define DME1737_REG_FAN_MAX(ix) (0xb4 + (ix)) /* only for fan[4-5] */ 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_ci/* PWMs numbered 0-2, 4-5 (ix) */ 11562306a36Sopenharmony_ci#define DME1737_REG_PWM(ix) ((ix) < 3 ? 0x30 + (ix) \ 11662306a36Sopenharmony_ci : 0xa1 + (ix)) 11762306a36Sopenharmony_ci#define DME1737_REG_PWM_CONFIG(ix) (0x5c + (ix)) /* only for pwm[0-2] */ 11862306a36Sopenharmony_ci#define DME1737_REG_PWM_MIN(ix) (0x64 + (ix)) /* only for pwm[0-2] */ 11962306a36Sopenharmony_ci#define DME1737_REG_PWM_FREQ(ix) ((ix) < 3 ? 0x5f + (ix) \ 12062306a36Sopenharmony_ci : 0xa3 + (ix)) 12162306a36Sopenharmony_ci/* 12262306a36Sopenharmony_ci * The layout of the ramp rate registers is different from the other pwm 12362306a36Sopenharmony_ci * registers. The bits for the 3 PWMs are stored in 2 registers: 12462306a36Sopenharmony_ci * PWM_RR(0) = [OFF3, OFF2, OFF1, RES, RR1E, RR1-2, RR1-1, RR1-0] 12562306a36Sopenharmony_ci * PWM_RR(1) = [RR2E, RR2-2, RR2-1, RR2-0, RR3E, RR3-2, RR3-1, RR3-0] 12662306a36Sopenharmony_ci */ 12762306a36Sopenharmony_ci#define DME1737_REG_PWM_RR(ix) (0x62 + (ix)) /* only for pwm[0-2] */ 12862306a36Sopenharmony_ci 12962306a36Sopenharmony_ci/* Thermal zones 0-2 */ 13062306a36Sopenharmony_ci#define DME1737_REG_ZONE_LOW(ix) (0x67 + (ix)) 13162306a36Sopenharmony_ci#define DME1737_REG_ZONE_ABS(ix) (0x6a + (ix)) 13262306a36Sopenharmony_ci/* 13362306a36Sopenharmony_ci * The layout of the hysteresis registers is different from the other zone 13462306a36Sopenharmony_ci * registers. The bits for the 3 zones are stored in 2 registers: 13562306a36Sopenharmony_ci * ZONE_HYST(0) = [H1-3, H1-2, H1-1, H1-0, H2-3, H2-2, H2-1, H2-0] 13662306a36Sopenharmony_ci * ZONE_HYST(1) = [H3-3, H3-2, H3-1, H3-0, RES, RES, RES, RES] 13762306a36Sopenharmony_ci */ 13862306a36Sopenharmony_ci#define DME1737_REG_ZONE_HYST(ix) (0x6d + (ix)) 13962306a36Sopenharmony_ci 14062306a36Sopenharmony_ci/* 14162306a36Sopenharmony_ci * Alarm registers and bit mapping 14262306a36Sopenharmony_ci * The 3 8-bit alarm registers will be concatenated to a single 32-bit 14362306a36Sopenharmony_ci * alarm value [0, ALARM3, ALARM2, ALARM1]. 14462306a36Sopenharmony_ci */ 14562306a36Sopenharmony_ci#define DME1737_REG_ALARM1 0x41 14662306a36Sopenharmony_ci#define DME1737_REG_ALARM2 0x42 14762306a36Sopenharmony_ci#define DME1737_REG_ALARM3 0x83 14862306a36Sopenharmony_cistatic const u8 DME1737_BIT_ALARM_IN[] = {0, 1, 2, 3, 8, 16, 17, 18}; 14962306a36Sopenharmony_cistatic const u8 DME1737_BIT_ALARM_TEMP[] = {4, 5, 6}; 15062306a36Sopenharmony_cistatic const u8 DME1737_BIT_ALARM_FAN[] = {10, 11, 12, 13, 22, 23}; 15162306a36Sopenharmony_ci 15262306a36Sopenharmony_ci/* Miscellaneous registers */ 15362306a36Sopenharmony_ci#define DME1737_REG_DEVICE 0x3d 15462306a36Sopenharmony_ci#define DME1737_REG_COMPANY 0x3e 15562306a36Sopenharmony_ci#define DME1737_REG_VERSTEP 0x3f 15662306a36Sopenharmony_ci#define DME1737_REG_CONFIG 0x40 15762306a36Sopenharmony_ci#define DME1737_REG_CONFIG2 0x7f 15862306a36Sopenharmony_ci#define DME1737_REG_VID 0x43 15962306a36Sopenharmony_ci#define DME1737_REG_TACH_PWM 0x81 16062306a36Sopenharmony_ci 16162306a36Sopenharmony_ci/* --------------------------------------------------------------------- 16262306a36Sopenharmony_ci * Misc defines 16362306a36Sopenharmony_ci * --------------------------------------------------------------------- */ 16462306a36Sopenharmony_ci 16562306a36Sopenharmony_ci/* Chip identification */ 16662306a36Sopenharmony_ci#define DME1737_COMPANY_SMSC 0x5c 16762306a36Sopenharmony_ci#define DME1737_VERSTEP 0x88 16862306a36Sopenharmony_ci#define DME1737_VERSTEP_MASK 0xf8 16962306a36Sopenharmony_ci#define SCH311X_DEVICE 0x8c 17062306a36Sopenharmony_ci#define SCH5027_VERSTEP 0x69 17162306a36Sopenharmony_ci#define SCH5127_DEVICE 0x8e 17262306a36Sopenharmony_ci 17362306a36Sopenharmony_ci/* Device ID values (global configuration register index 0x20) */ 17462306a36Sopenharmony_ci#define DME1737_ID_1 0x77 17562306a36Sopenharmony_ci#define DME1737_ID_2 0x78 17662306a36Sopenharmony_ci#define SCH3112_ID 0x7c 17762306a36Sopenharmony_ci#define SCH3114_ID 0x7d 17862306a36Sopenharmony_ci#define SCH3116_ID 0x7f 17962306a36Sopenharmony_ci#define SCH5027_ID 0x89 18062306a36Sopenharmony_ci#define SCH5127_ID 0x86 18162306a36Sopenharmony_ci 18262306a36Sopenharmony_ci/* Length of ISA address segment */ 18362306a36Sopenharmony_ci#define DME1737_EXTENT 2 18462306a36Sopenharmony_ci 18562306a36Sopenharmony_ci/* chip-dependent features */ 18662306a36Sopenharmony_ci#define HAS_TEMP_OFFSET (1 << 0) /* bit 0 */ 18762306a36Sopenharmony_ci#define HAS_VID (1 << 1) /* bit 1 */ 18862306a36Sopenharmony_ci#define HAS_ZONE3 (1 << 2) /* bit 2 */ 18962306a36Sopenharmony_ci#define HAS_ZONE_HYST (1 << 3) /* bit 3 */ 19062306a36Sopenharmony_ci#define HAS_PWM_MIN (1 << 4) /* bit 4 */ 19162306a36Sopenharmony_ci#define HAS_FAN(ix) (1 << ((ix) + 5)) /* bits 5-10 */ 19262306a36Sopenharmony_ci#define HAS_PWM(ix) (1 << ((ix) + 11)) /* bits 11-16 */ 19362306a36Sopenharmony_ci#define HAS_IN7 (1 << 17) /* bit 17 */ 19462306a36Sopenharmony_ci 19562306a36Sopenharmony_ci/* --------------------------------------------------------------------- 19662306a36Sopenharmony_ci * Data structures and manipulation thereof 19762306a36Sopenharmony_ci * --------------------------------------------------------------------- */ 19862306a36Sopenharmony_ci 19962306a36Sopenharmony_cistruct dme1737_data { 20062306a36Sopenharmony_ci struct i2c_client *client; /* for I2C devices only */ 20162306a36Sopenharmony_ci struct device *hwmon_dev; 20262306a36Sopenharmony_ci const char *name; 20362306a36Sopenharmony_ci unsigned int addr; /* for ISA devices only */ 20462306a36Sopenharmony_ci 20562306a36Sopenharmony_ci struct mutex update_lock; 20662306a36Sopenharmony_ci bool valid; /* true if following fields are valid */ 20762306a36Sopenharmony_ci unsigned long last_update; /* in jiffies */ 20862306a36Sopenharmony_ci unsigned long last_vbat; /* in jiffies */ 20962306a36Sopenharmony_ci enum chips type; 21062306a36Sopenharmony_ci const int *in_nominal; /* pointer to IN_NOMINAL array */ 21162306a36Sopenharmony_ci 21262306a36Sopenharmony_ci u8 vid; 21362306a36Sopenharmony_ci u8 pwm_rr_en; 21462306a36Sopenharmony_ci u32 has_features; 21562306a36Sopenharmony_ci 21662306a36Sopenharmony_ci /* Register values */ 21762306a36Sopenharmony_ci u16 in[8]; 21862306a36Sopenharmony_ci u8 in_min[8]; 21962306a36Sopenharmony_ci u8 in_max[8]; 22062306a36Sopenharmony_ci s16 temp[3]; 22162306a36Sopenharmony_ci s8 temp_min[3]; 22262306a36Sopenharmony_ci s8 temp_max[3]; 22362306a36Sopenharmony_ci s8 temp_offset[3]; 22462306a36Sopenharmony_ci u8 config; 22562306a36Sopenharmony_ci u8 config2; 22662306a36Sopenharmony_ci u8 vrm; 22762306a36Sopenharmony_ci u16 fan[6]; 22862306a36Sopenharmony_ci u16 fan_min[6]; 22962306a36Sopenharmony_ci u8 fan_max[2]; 23062306a36Sopenharmony_ci u8 fan_opt[6]; 23162306a36Sopenharmony_ci u8 pwm[6]; 23262306a36Sopenharmony_ci u8 pwm_min[3]; 23362306a36Sopenharmony_ci u8 pwm_config[3]; 23462306a36Sopenharmony_ci u8 pwm_acz[3]; 23562306a36Sopenharmony_ci u8 pwm_freq[6]; 23662306a36Sopenharmony_ci u8 pwm_rr[2]; 23762306a36Sopenharmony_ci s8 zone_low[3]; 23862306a36Sopenharmony_ci s8 zone_abs[3]; 23962306a36Sopenharmony_ci u8 zone_hyst[2]; 24062306a36Sopenharmony_ci u32 alarms; 24162306a36Sopenharmony_ci}; 24262306a36Sopenharmony_ci 24362306a36Sopenharmony_ci/* Nominal voltage values */ 24462306a36Sopenharmony_cistatic const int IN_NOMINAL_DME1737[] = {5000, 2250, 3300, 5000, 12000, 3300, 24562306a36Sopenharmony_ci 3300}; 24662306a36Sopenharmony_cistatic const int IN_NOMINAL_SCH311x[] = {2500, 1500, 3300, 5000, 12000, 3300, 24762306a36Sopenharmony_ci 3300}; 24862306a36Sopenharmony_cistatic const int IN_NOMINAL_SCH5027[] = {5000, 2250, 3300, 1125, 1125, 3300, 24962306a36Sopenharmony_ci 3300}; 25062306a36Sopenharmony_cistatic const int IN_NOMINAL_SCH5127[] = {2500, 2250, 3300, 1125, 1125, 3300, 25162306a36Sopenharmony_ci 3300, 1500}; 25262306a36Sopenharmony_ci#define IN_NOMINAL(type) ((type) == sch311x ? IN_NOMINAL_SCH311x : \ 25362306a36Sopenharmony_ci (type) == sch5027 ? IN_NOMINAL_SCH5027 : \ 25462306a36Sopenharmony_ci (type) == sch5127 ? IN_NOMINAL_SCH5127 : \ 25562306a36Sopenharmony_ci IN_NOMINAL_DME1737) 25662306a36Sopenharmony_ci 25762306a36Sopenharmony_ci/* 25862306a36Sopenharmony_ci * Voltage input 25962306a36Sopenharmony_ci * Voltage inputs have 16 bits resolution, limit values have 8 bits 26062306a36Sopenharmony_ci * resolution. 26162306a36Sopenharmony_ci */ 26262306a36Sopenharmony_cistatic inline int IN_FROM_REG(int reg, int nominal, int res) 26362306a36Sopenharmony_ci{ 26462306a36Sopenharmony_ci return (reg * nominal + (3 << (res - 3))) / (3 << (res - 2)); 26562306a36Sopenharmony_ci} 26662306a36Sopenharmony_ci 26762306a36Sopenharmony_cistatic inline int IN_TO_REG(long val, int nominal) 26862306a36Sopenharmony_ci{ 26962306a36Sopenharmony_ci val = clamp_val(val, 0, 255 * nominal / 192); 27062306a36Sopenharmony_ci return DIV_ROUND_CLOSEST(val * 192, nominal); 27162306a36Sopenharmony_ci} 27262306a36Sopenharmony_ci 27362306a36Sopenharmony_ci/* 27462306a36Sopenharmony_ci * Temperature input 27562306a36Sopenharmony_ci * The register values represent temperatures in 2's complement notation from 27662306a36Sopenharmony_ci * -127 degrees C to +127 degrees C. Temp inputs have 16 bits resolution, limit 27762306a36Sopenharmony_ci * values have 8 bits resolution. 27862306a36Sopenharmony_ci */ 27962306a36Sopenharmony_cistatic inline int TEMP_FROM_REG(int reg, int res) 28062306a36Sopenharmony_ci{ 28162306a36Sopenharmony_ci return (reg * 1000) >> (res - 8); 28262306a36Sopenharmony_ci} 28362306a36Sopenharmony_ci 28462306a36Sopenharmony_cistatic inline int TEMP_TO_REG(long val) 28562306a36Sopenharmony_ci{ 28662306a36Sopenharmony_ci val = clamp_val(val, -128000, 127000); 28762306a36Sopenharmony_ci return DIV_ROUND_CLOSEST(val, 1000); 28862306a36Sopenharmony_ci} 28962306a36Sopenharmony_ci 29062306a36Sopenharmony_ci/* Temperature range */ 29162306a36Sopenharmony_cistatic const int TEMP_RANGE[] = {2000, 2500, 3333, 4000, 5000, 6666, 8000, 29262306a36Sopenharmony_ci 10000, 13333, 16000, 20000, 26666, 32000, 29362306a36Sopenharmony_ci 40000, 53333, 80000}; 29462306a36Sopenharmony_ci 29562306a36Sopenharmony_cistatic inline int TEMP_RANGE_FROM_REG(int reg) 29662306a36Sopenharmony_ci{ 29762306a36Sopenharmony_ci return TEMP_RANGE[(reg >> 4) & 0x0f]; 29862306a36Sopenharmony_ci} 29962306a36Sopenharmony_ci 30062306a36Sopenharmony_cistatic int TEMP_RANGE_TO_REG(long val, int reg) 30162306a36Sopenharmony_ci{ 30262306a36Sopenharmony_ci int i; 30362306a36Sopenharmony_ci 30462306a36Sopenharmony_ci for (i = 15; i > 0; i--) { 30562306a36Sopenharmony_ci if (val > (TEMP_RANGE[i] + TEMP_RANGE[i - 1] + 1) / 2) 30662306a36Sopenharmony_ci break; 30762306a36Sopenharmony_ci } 30862306a36Sopenharmony_ci 30962306a36Sopenharmony_ci return (reg & 0x0f) | (i << 4); 31062306a36Sopenharmony_ci} 31162306a36Sopenharmony_ci 31262306a36Sopenharmony_ci/* 31362306a36Sopenharmony_ci * Temperature hysteresis 31462306a36Sopenharmony_ci * Register layout: 31562306a36Sopenharmony_ci * reg[0] = [H1-3, H1-2, H1-1, H1-0, H2-3, H2-2, H2-1, H2-0] 31662306a36Sopenharmony_ci * reg[1] = [H3-3, H3-2, H3-1, H3-0, xxxx, xxxx, xxxx, xxxx] 31762306a36Sopenharmony_ci */ 31862306a36Sopenharmony_cistatic inline int TEMP_HYST_FROM_REG(int reg, int ix) 31962306a36Sopenharmony_ci{ 32062306a36Sopenharmony_ci return (((ix == 1) ? reg : reg >> 4) & 0x0f) * 1000; 32162306a36Sopenharmony_ci} 32262306a36Sopenharmony_ci 32362306a36Sopenharmony_cistatic inline int TEMP_HYST_TO_REG(int temp, long hyst, int ix, int reg) 32462306a36Sopenharmony_ci{ 32562306a36Sopenharmony_ci hyst = clamp_val(hyst, temp - 15000, temp); 32662306a36Sopenharmony_ci hyst = DIV_ROUND_CLOSEST(temp - hyst, 1000); 32762306a36Sopenharmony_ci 32862306a36Sopenharmony_ci return (ix == 1) ? (reg & 0xf0) | hyst : (reg & 0x0f) | (hyst << 4); 32962306a36Sopenharmony_ci} 33062306a36Sopenharmony_ci 33162306a36Sopenharmony_ci/* Fan input RPM */ 33262306a36Sopenharmony_cistatic inline int FAN_FROM_REG(int reg, int tpc) 33362306a36Sopenharmony_ci{ 33462306a36Sopenharmony_ci if (tpc) 33562306a36Sopenharmony_ci return tpc * reg; 33662306a36Sopenharmony_ci else 33762306a36Sopenharmony_ci return (reg == 0 || reg == 0xffff) ? 0 : 90000 * 60 / reg; 33862306a36Sopenharmony_ci} 33962306a36Sopenharmony_ci 34062306a36Sopenharmony_cistatic inline int FAN_TO_REG(long val, int tpc) 34162306a36Sopenharmony_ci{ 34262306a36Sopenharmony_ci if (tpc) { 34362306a36Sopenharmony_ci return clamp_val(val / tpc, 0, 0xffff); 34462306a36Sopenharmony_ci } else { 34562306a36Sopenharmony_ci return (val <= 0) ? 0xffff : 34662306a36Sopenharmony_ci clamp_val(90000 * 60 / val, 0, 0xfffe); 34762306a36Sopenharmony_ci } 34862306a36Sopenharmony_ci} 34962306a36Sopenharmony_ci 35062306a36Sopenharmony_ci/* 35162306a36Sopenharmony_ci * Fan TPC (tach pulse count) 35262306a36Sopenharmony_ci * Converts a register value to a TPC multiplier or returns 0 if the tachometer 35362306a36Sopenharmony_ci * is configured in legacy (non-tpc) mode 35462306a36Sopenharmony_ci */ 35562306a36Sopenharmony_cistatic inline int FAN_TPC_FROM_REG(int reg) 35662306a36Sopenharmony_ci{ 35762306a36Sopenharmony_ci return (reg & 0x20) ? 0 : 60 >> (reg & 0x03); 35862306a36Sopenharmony_ci} 35962306a36Sopenharmony_ci 36062306a36Sopenharmony_ci/* 36162306a36Sopenharmony_ci * Fan type 36262306a36Sopenharmony_ci * The type of a fan is expressed in number of pulses-per-revolution that it 36362306a36Sopenharmony_ci * emits 36462306a36Sopenharmony_ci */ 36562306a36Sopenharmony_cistatic inline int FAN_TYPE_FROM_REG(int reg) 36662306a36Sopenharmony_ci{ 36762306a36Sopenharmony_ci int edge = (reg >> 1) & 0x03; 36862306a36Sopenharmony_ci 36962306a36Sopenharmony_ci return (edge > 0) ? 1 << (edge - 1) : 0; 37062306a36Sopenharmony_ci} 37162306a36Sopenharmony_ci 37262306a36Sopenharmony_cistatic inline int FAN_TYPE_TO_REG(long val, int reg) 37362306a36Sopenharmony_ci{ 37462306a36Sopenharmony_ci int edge = (val == 4) ? 3 : val; 37562306a36Sopenharmony_ci 37662306a36Sopenharmony_ci return (reg & 0xf9) | (edge << 1); 37762306a36Sopenharmony_ci} 37862306a36Sopenharmony_ci 37962306a36Sopenharmony_ci/* Fan max RPM */ 38062306a36Sopenharmony_cistatic const int FAN_MAX[] = {0x54, 0x38, 0x2a, 0x21, 0x1c, 0x18, 0x15, 0x12, 38162306a36Sopenharmony_ci 0x11, 0x0f, 0x0e}; 38262306a36Sopenharmony_ci 38362306a36Sopenharmony_cistatic int FAN_MAX_FROM_REG(int reg) 38462306a36Sopenharmony_ci{ 38562306a36Sopenharmony_ci int i; 38662306a36Sopenharmony_ci 38762306a36Sopenharmony_ci for (i = 10; i > 0; i--) { 38862306a36Sopenharmony_ci if (reg == FAN_MAX[i]) 38962306a36Sopenharmony_ci break; 39062306a36Sopenharmony_ci } 39162306a36Sopenharmony_ci 39262306a36Sopenharmony_ci return 1000 + i * 500; 39362306a36Sopenharmony_ci} 39462306a36Sopenharmony_ci 39562306a36Sopenharmony_cistatic int FAN_MAX_TO_REG(long val) 39662306a36Sopenharmony_ci{ 39762306a36Sopenharmony_ci int i; 39862306a36Sopenharmony_ci 39962306a36Sopenharmony_ci for (i = 10; i > 0; i--) { 40062306a36Sopenharmony_ci if (val > (1000 + (i - 1) * 500)) 40162306a36Sopenharmony_ci break; 40262306a36Sopenharmony_ci } 40362306a36Sopenharmony_ci 40462306a36Sopenharmony_ci return FAN_MAX[i]; 40562306a36Sopenharmony_ci} 40662306a36Sopenharmony_ci 40762306a36Sopenharmony_ci/* 40862306a36Sopenharmony_ci * PWM enable 40962306a36Sopenharmony_ci * Register to enable mapping: 41062306a36Sopenharmony_ci * 000: 2 fan on zone 1 auto 41162306a36Sopenharmony_ci * 001: 2 fan on zone 2 auto 41262306a36Sopenharmony_ci * 010: 2 fan on zone 3 auto 41362306a36Sopenharmony_ci * 011: 0 fan full on 41462306a36Sopenharmony_ci * 100: -1 fan disabled 41562306a36Sopenharmony_ci * 101: 2 fan on hottest of zones 2,3 auto 41662306a36Sopenharmony_ci * 110: 2 fan on hottest of zones 1,2,3 auto 41762306a36Sopenharmony_ci * 111: 1 fan in manual mode 41862306a36Sopenharmony_ci */ 41962306a36Sopenharmony_cistatic inline int PWM_EN_FROM_REG(int reg) 42062306a36Sopenharmony_ci{ 42162306a36Sopenharmony_ci static const int en[] = {2, 2, 2, 0, -1, 2, 2, 1}; 42262306a36Sopenharmony_ci 42362306a36Sopenharmony_ci return en[(reg >> 5) & 0x07]; 42462306a36Sopenharmony_ci} 42562306a36Sopenharmony_ci 42662306a36Sopenharmony_cistatic inline int PWM_EN_TO_REG(int val, int reg) 42762306a36Sopenharmony_ci{ 42862306a36Sopenharmony_ci int en = (val == 1) ? 7 : 3; 42962306a36Sopenharmony_ci 43062306a36Sopenharmony_ci return (reg & 0x1f) | ((en & 0x07) << 5); 43162306a36Sopenharmony_ci} 43262306a36Sopenharmony_ci 43362306a36Sopenharmony_ci/* 43462306a36Sopenharmony_ci * PWM auto channels zone 43562306a36Sopenharmony_ci * Register to auto channels zone mapping (ACZ is a bitfield with bit x 43662306a36Sopenharmony_ci * corresponding to zone x+1): 43762306a36Sopenharmony_ci * 000: 001 fan on zone 1 auto 43862306a36Sopenharmony_ci * 001: 010 fan on zone 2 auto 43962306a36Sopenharmony_ci * 010: 100 fan on zone 3 auto 44062306a36Sopenharmony_ci * 011: 000 fan full on 44162306a36Sopenharmony_ci * 100: 000 fan disabled 44262306a36Sopenharmony_ci * 101: 110 fan on hottest of zones 2,3 auto 44362306a36Sopenharmony_ci * 110: 111 fan on hottest of zones 1,2,3 auto 44462306a36Sopenharmony_ci * 111: 000 fan in manual mode 44562306a36Sopenharmony_ci */ 44662306a36Sopenharmony_cistatic inline int PWM_ACZ_FROM_REG(int reg) 44762306a36Sopenharmony_ci{ 44862306a36Sopenharmony_ci static const int acz[] = {1, 2, 4, 0, 0, 6, 7, 0}; 44962306a36Sopenharmony_ci 45062306a36Sopenharmony_ci return acz[(reg >> 5) & 0x07]; 45162306a36Sopenharmony_ci} 45262306a36Sopenharmony_ci 45362306a36Sopenharmony_cistatic inline int PWM_ACZ_TO_REG(long val, int reg) 45462306a36Sopenharmony_ci{ 45562306a36Sopenharmony_ci int acz = (val == 4) ? 2 : val - 1; 45662306a36Sopenharmony_ci 45762306a36Sopenharmony_ci return (reg & 0x1f) | ((acz & 0x07) << 5); 45862306a36Sopenharmony_ci} 45962306a36Sopenharmony_ci 46062306a36Sopenharmony_ci/* PWM frequency */ 46162306a36Sopenharmony_cistatic const int PWM_FREQ[] = {11, 15, 22, 29, 35, 44, 59, 88, 46262306a36Sopenharmony_ci 15000, 20000, 30000, 25000, 0, 0, 0, 0}; 46362306a36Sopenharmony_ci 46462306a36Sopenharmony_cistatic inline int PWM_FREQ_FROM_REG(int reg) 46562306a36Sopenharmony_ci{ 46662306a36Sopenharmony_ci return PWM_FREQ[reg & 0x0f]; 46762306a36Sopenharmony_ci} 46862306a36Sopenharmony_ci 46962306a36Sopenharmony_cistatic int PWM_FREQ_TO_REG(long val, int reg) 47062306a36Sopenharmony_ci{ 47162306a36Sopenharmony_ci int i; 47262306a36Sopenharmony_ci 47362306a36Sopenharmony_ci /* the first two cases are special - stupid chip design! */ 47462306a36Sopenharmony_ci if (val > 27500) { 47562306a36Sopenharmony_ci i = 10; 47662306a36Sopenharmony_ci } else if (val > 22500) { 47762306a36Sopenharmony_ci i = 11; 47862306a36Sopenharmony_ci } else { 47962306a36Sopenharmony_ci for (i = 9; i > 0; i--) { 48062306a36Sopenharmony_ci if (val > (PWM_FREQ[i] + PWM_FREQ[i - 1] + 1) / 2) 48162306a36Sopenharmony_ci break; 48262306a36Sopenharmony_ci } 48362306a36Sopenharmony_ci } 48462306a36Sopenharmony_ci 48562306a36Sopenharmony_ci return (reg & 0xf0) | i; 48662306a36Sopenharmony_ci} 48762306a36Sopenharmony_ci 48862306a36Sopenharmony_ci/* 48962306a36Sopenharmony_ci * PWM ramp rate 49062306a36Sopenharmony_ci * Register layout: 49162306a36Sopenharmony_ci * reg[0] = [OFF3, OFF2, OFF1, RES, RR1-E, RR1-2, RR1-1, RR1-0] 49262306a36Sopenharmony_ci * reg[1] = [RR2-E, RR2-2, RR2-1, RR2-0, RR3-E, RR3-2, RR3-1, RR3-0] 49362306a36Sopenharmony_ci */ 49462306a36Sopenharmony_cistatic const u8 PWM_RR[] = {206, 104, 69, 41, 26, 18, 10, 5}; 49562306a36Sopenharmony_ci 49662306a36Sopenharmony_cistatic inline int PWM_RR_FROM_REG(int reg, int ix) 49762306a36Sopenharmony_ci{ 49862306a36Sopenharmony_ci int rr = (ix == 1) ? reg >> 4 : reg; 49962306a36Sopenharmony_ci 50062306a36Sopenharmony_ci return (rr & 0x08) ? PWM_RR[rr & 0x07] : 0; 50162306a36Sopenharmony_ci} 50262306a36Sopenharmony_ci 50362306a36Sopenharmony_cistatic int PWM_RR_TO_REG(long val, int ix, int reg) 50462306a36Sopenharmony_ci{ 50562306a36Sopenharmony_ci int i; 50662306a36Sopenharmony_ci 50762306a36Sopenharmony_ci for (i = 0; i < 7; i++) { 50862306a36Sopenharmony_ci if (val > (PWM_RR[i] + PWM_RR[i + 1] + 1) / 2) 50962306a36Sopenharmony_ci break; 51062306a36Sopenharmony_ci } 51162306a36Sopenharmony_ci 51262306a36Sopenharmony_ci return (ix == 1) ? (reg & 0x8f) | (i << 4) : (reg & 0xf8) | i; 51362306a36Sopenharmony_ci} 51462306a36Sopenharmony_ci 51562306a36Sopenharmony_ci/* PWM ramp rate enable */ 51662306a36Sopenharmony_cistatic inline int PWM_RR_EN_FROM_REG(int reg, int ix) 51762306a36Sopenharmony_ci{ 51862306a36Sopenharmony_ci return PWM_RR_FROM_REG(reg, ix) ? 1 : 0; 51962306a36Sopenharmony_ci} 52062306a36Sopenharmony_ci 52162306a36Sopenharmony_cistatic inline int PWM_RR_EN_TO_REG(long val, int ix, int reg) 52262306a36Sopenharmony_ci{ 52362306a36Sopenharmony_ci int en = (ix == 1) ? 0x80 : 0x08; 52462306a36Sopenharmony_ci 52562306a36Sopenharmony_ci return val ? reg | en : reg & ~en; 52662306a36Sopenharmony_ci} 52762306a36Sopenharmony_ci 52862306a36Sopenharmony_ci/* 52962306a36Sopenharmony_ci * PWM min/off 53062306a36Sopenharmony_ci * The PWM min/off bits are part of the PMW ramp rate register 0 (see above for 53162306a36Sopenharmony_ci * the register layout). 53262306a36Sopenharmony_ci */ 53362306a36Sopenharmony_cistatic inline int PWM_OFF_FROM_REG(int reg, int ix) 53462306a36Sopenharmony_ci{ 53562306a36Sopenharmony_ci return (reg >> (ix + 5)) & 0x01; 53662306a36Sopenharmony_ci} 53762306a36Sopenharmony_ci 53862306a36Sopenharmony_cistatic inline int PWM_OFF_TO_REG(int val, int ix, int reg) 53962306a36Sopenharmony_ci{ 54062306a36Sopenharmony_ci return (reg & ~(1 << (ix + 5))) | ((val & 0x01) << (ix + 5)); 54162306a36Sopenharmony_ci} 54262306a36Sopenharmony_ci 54362306a36Sopenharmony_ci/* --------------------------------------------------------------------- 54462306a36Sopenharmony_ci * Device I/O access 54562306a36Sopenharmony_ci * 54662306a36Sopenharmony_ci * ISA access is performed through an index/data register pair and needs to 54762306a36Sopenharmony_ci * be protected by a mutex during runtime (not required for initialization). 54862306a36Sopenharmony_ci * We use data->update_lock for this and need to ensure that we acquire it 54962306a36Sopenharmony_ci * before calling dme1737_read or dme1737_write. 55062306a36Sopenharmony_ci * --------------------------------------------------------------------- */ 55162306a36Sopenharmony_ci 55262306a36Sopenharmony_cistatic u8 dme1737_read(const struct dme1737_data *data, u8 reg) 55362306a36Sopenharmony_ci{ 55462306a36Sopenharmony_ci struct i2c_client *client = data->client; 55562306a36Sopenharmony_ci s32 val; 55662306a36Sopenharmony_ci 55762306a36Sopenharmony_ci if (client) { /* I2C device */ 55862306a36Sopenharmony_ci val = i2c_smbus_read_byte_data(client, reg); 55962306a36Sopenharmony_ci 56062306a36Sopenharmony_ci if (val < 0) { 56162306a36Sopenharmony_ci dev_warn(&client->dev, 56262306a36Sopenharmony_ci "Read from register 0x%02x failed! %s\n", 56362306a36Sopenharmony_ci reg, DO_REPORT); 56462306a36Sopenharmony_ci } 56562306a36Sopenharmony_ci } else { /* ISA device */ 56662306a36Sopenharmony_ci outb(reg, data->addr); 56762306a36Sopenharmony_ci val = inb(data->addr + 1); 56862306a36Sopenharmony_ci } 56962306a36Sopenharmony_ci 57062306a36Sopenharmony_ci return val; 57162306a36Sopenharmony_ci} 57262306a36Sopenharmony_ci 57362306a36Sopenharmony_cistatic s32 dme1737_write(const struct dme1737_data *data, u8 reg, u8 val) 57462306a36Sopenharmony_ci{ 57562306a36Sopenharmony_ci struct i2c_client *client = data->client; 57662306a36Sopenharmony_ci s32 res = 0; 57762306a36Sopenharmony_ci 57862306a36Sopenharmony_ci if (client) { /* I2C device */ 57962306a36Sopenharmony_ci res = i2c_smbus_write_byte_data(client, reg, val); 58062306a36Sopenharmony_ci 58162306a36Sopenharmony_ci if (res < 0) { 58262306a36Sopenharmony_ci dev_warn(&client->dev, 58362306a36Sopenharmony_ci "Write to register 0x%02x failed! %s\n", 58462306a36Sopenharmony_ci reg, DO_REPORT); 58562306a36Sopenharmony_ci } 58662306a36Sopenharmony_ci } else { /* ISA device */ 58762306a36Sopenharmony_ci outb(reg, data->addr); 58862306a36Sopenharmony_ci outb(val, data->addr + 1); 58962306a36Sopenharmony_ci } 59062306a36Sopenharmony_ci 59162306a36Sopenharmony_ci return res; 59262306a36Sopenharmony_ci} 59362306a36Sopenharmony_ci 59462306a36Sopenharmony_cistatic struct dme1737_data *dme1737_update_device(struct device *dev) 59562306a36Sopenharmony_ci{ 59662306a36Sopenharmony_ci struct dme1737_data *data = dev_get_drvdata(dev); 59762306a36Sopenharmony_ci int ix; 59862306a36Sopenharmony_ci u8 lsb[6]; 59962306a36Sopenharmony_ci 60062306a36Sopenharmony_ci mutex_lock(&data->update_lock); 60162306a36Sopenharmony_ci 60262306a36Sopenharmony_ci /* Enable a Vbat monitoring cycle every 10 mins */ 60362306a36Sopenharmony_ci if (time_after(jiffies, data->last_vbat + 600 * HZ) || !data->valid) { 60462306a36Sopenharmony_ci dme1737_write(data, DME1737_REG_CONFIG, dme1737_read(data, 60562306a36Sopenharmony_ci DME1737_REG_CONFIG) | 0x10); 60662306a36Sopenharmony_ci data->last_vbat = jiffies; 60762306a36Sopenharmony_ci } 60862306a36Sopenharmony_ci 60962306a36Sopenharmony_ci /* Sample register contents every 1 sec */ 61062306a36Sopenharmony_ci if (time_after(jiffies, data->last_update + HZ) || !data->valid) { 61162306a36Sopenharmony_ci if (data->has_features & HAS_VID) { 61262306a36Sopenharmony_ci data->vid = dme1737_read(data, DME1737_REG_VID) & 61362306a36Sopenharmony_ci 0x3f; 61462306a36Sopenharmony_ci } 61562306a36Sopenharmony_ci 61662306a36Sopenharmony_ci /* In (voltage) registers */ 61762306a36Sopenharmony_ci for (ix = 0; ix < ARRAY_SIZE(data->in); ix++) { 61862306a36Sopenharmony_ci /* 61962306a36Sopenharmony_ci * Voltage inputs are stored as 16 bit values even 62062306a36Sopenharmony_ci * though they have only 12 bits resolution. This is 62162306a36Sopenharmony_ci * to make it consistent with the temp inputs. 62262306a36Sopenharmony_ci */ 62362306a36Sopenharmony_ci if (ix == 7 && !(data->has_features & HAS_IN7)) 62462306a36Sopenharmony_ci continue; 62562306a36Sopenharmony_ci data->in[ix] = dme1737_read(data, 62662306a36Sopenharmony_ci DME1737_REG_IN(ix)) << 8; 62762306a36Sopenharmony_ci data->in_min[ix] = dme1737_read(data, 62862306a36Sopenharmony_ci DME1737_REG_IN_MIN(ix)); 62962306a36Sopenharmony_ci data->in_max[ix] = dme1737_read(data, 63062306a36Sopenharmony_ci DME1737_REG_IN_MAX(ix)); 63162306a36Sopenharmony_ci } 63262306a36Sopenharmony_ci 63362306a36Sopenharmony_ci /* Temp registers */ 63462306a36Sopenharmony_ci for (ix = 0; ix < ARRAY_SIZE(data->temp); ix++) { 63562306a36Sopenharmony_ci /* 63662306a36Sopenharmony_ci * Temp inputs are stored as 16 bit values even 63762306a36Sopenharmony_ci * though they have only 12 bits resolution. This is 63862306a36Sopenharmony_ci * to take advantage of implicit conversions between 63962306a36Sopenharmony_ci * register values (2's complement) and temp values 64062306a36Sopenharmony_ci * (signed decimal). 64162306a36Sopenharmony_ci */ 64262306a36Sopenharmony_ci data->temp[ix] = dme1737_read(data, 64362306a36Sopenharmony_ci DME1737_REG_TEMP(ix)) << 8; 64462306a36Sopenharmony_ci data->temp_min[ix] = dme1737_read(data, 64562306a36Sopenharmony_ci DME1737_REG_TEMP_MIN(ix)); 64662306a36Sopenharmony_ci data->temp_max[ix] = dme1737_read(data, 64762306a36Sopenharmony_ci DME1737_REG_TEMP_MAX(ix)); 64862306a36Sopenharmony_ci if (data->has_features & HAS_TEMP_OFFSET) { 64962306a36Sopenharmony_ci data->temp_offset[ix] = dme1737_read(data, 65062306a36Sopenharmony_ci DME1737_REG_TEMP_OFFSET(ix)); 65162306a36Sopenharmony_ci } 65262306a36Sopenharmony_ci } 65362306a36Sopenharmony_ci 65462306a36Sopenharmony_ci /* 65562306a36Sopenharmony_ci * In and temp LSB registers 65662306a36Sopenharmony_ci * The LSBs are latched when the MSBs are read, so the order in 65762306a36Sopenharmony_ci * which the registers are read (MSB first, then LSB) is 65862306a36Sopenharmony_ci * important! 65962306a36Sopenharmony_ci */ 66062306a36Sopenharmony_ci for (ix = 0; ix < ARRAY_SIZE(lsb); ix++) { 66162306a36Sopenharmony_ci if (ix == 5 && !(data->has_features & HAS_IN7)) 66262306a36Sopenharmony_ci continue; 66362306a36Sopenharmony_ci lsb[ix] = dme1737_read(data, 66462306a36Sopenharmony_ci DME1737_REG_IN_TEMP_LSB(ix)); 66562306a36Sopenharmony_ci } 66662306a36Sopenharmony_ci for (ix = 0; ix < ARRAY_SIZE(data->in); ix++) { 66762306a36Sopenharmony_ci if (ix == 7 && !(data->has_features & HAS_IN7)) 66862306a36Sopenharmony_ci continue; 66962306a36Sopenharmony_ci data->in[ix] |= (lsb[DME1737_REG_IN_LSB[ix]] << 67062306a36Sopenharmony_ci DME1737_REG_IN_LSB_SHL[ix]) & 0xf0; 67162306a36Sopenharmony_ci } 67262306a36Sopenharmony_ci for (ix = 0; ix < ARRAY_SIZE(data->temp); ix++) { 67362306a36Sopenharmony_ci data->temp[ix] |= (lsb[DME1737_REG_TEMP_LSB[ix]] << 67462306a36Sopenharmony_ci DME1737_REG_TEMP_LSB_SHL[ix]) & 0xf0; 67562306a36Sopenharmony_ci } 67662306a36Sopenharmony_ci 67762306a36Sopenharmony_ci /* Fan registers */ 67862306a36Sopenharmony_ci for (ix = 0; ix < ARRAY_SIZE(data->fan); ix++) { 67962306a36Sopenharmony_ci /* 68062306a36Sopenharmony_ci * Skip reading registers if optional fans are not 68162306a36Sopenharmony_ci * present 68262306a36Sopenharmony_ci */ 68362306a36Sopenharmony_ci if (!(data->has_features & HAS_FAN(ix))) 68462306a36Sopenharmony_ci continue; 68562306a36Sopenharmony_ci data->fan[ix] = dme1737_read(data, 68662306a36Sopenharmony_ci DME1737_REG_FAN(ix)); 68762306a36Sopenharmony_ci data->fan[ix] |= dme1737_read(data, 68862306a36Sopenharmony_ci DME1737_REG_FAN(ix) + 1) << 8; 68962306a36Sopenharmony_ci data->fan_min[ix] = dme1737_read(data, 69062306a36Sopenharmony_ci DME1737_REG_FAN_MIN(ix)); 69162306a36Sopenharmony_ci data->fan_min[ix] |= dme1737_read(data, 69262306a36Sopenharmony_ci DME1737_REG_FAN_MIN(ix) + 1) << 8; 69362306a36Sopenharmony_ci data->fan_opt[ix] = dme1737_read(data, 69462306a36Sopenharmony_ci DME1737_REG_FAN_OPT(ix)); 69562306a36Sopenharmony_ci /* fan_max exists only for fan[5-6] */ 69662306a36Sopenharmony_ci if (ix > 3) { 69762306a36Sopenharmony_ci data->fan_max[ix - 4] = dme1737_read(data, 69862306a36Sopenharmony_ci DME1737_REG_FAN_MAX(ix)); 69962306a36Sopenharmony_ci } 70062306a36Sopenharmony_ci } 70162306a36Sopenharmony_ci 70262306a36Sopenharmony_ci /* PWM registers */ 70362306a36Sopenharmony_ci for (ix = 0; ix < ARRAY_SIZE(data->pwm); ix++) { 70462306a36Sopenharmony_ci /* 70562306a36Sopenharmony_ci * Skip reading registers if optional PWMs are not 70662306a36Sopenharmony_ci * present 70762306a36Sopenharmony_ci */ 70862306a36Sopenharmony_ci if (!(data->has_features & HAS_PWM(ix))) 70962306a36Sopenharmony_ci continue; 71062306a36Sopenharmony_ci data->pwm[ix] = dme1737_read(data, 71162306a36Sopenharmony_ci DME1737_REG_PWM(ix)); 71262306a36Sopenharmony_ci data->pwm_freq[ix] = dme1737_read(data, 71362306a36Sopenharmony_ci DME1737_REG_PWM_FREQ(ix)); 71462306a36Sopenharmony_ci /* pwm_config and pwm_min exist only for pwm[1-3] */ 71562306a36Sopenharmony_ci if (ix < 3) { 71662306a36Sopenharmony_ci data->pwm_config[ix] = dme1737_read(data, 71762306a36Sopenharmony_ci DME1737_REG_PWM_CONFIG(ix)); 71862306a36Sopenharmony_ci data->pwm_min[ix] = dme1737_read(data, 71962306a36Sopenharmony_ci DME1737_REG_PWM_MIN(ix)); 72062306a36Sopenharmony_ci } 72162306a36Sopenharmony_ci } 72262306a36Sopenharmony_ci for (ix = 0; ix < ARRAY_SIZE(data->pwm_rr); ix++) { 72362306a36Sopenharmony_ci data->pwm_rr[ix] = dme1737_read(data, 72462306a36Sopenharmony_ci DME1737_REG_PWM_RR(ix)); 72562306a36Sopenharmony_ci } 72662306a36Sopenharmony_ci 72762306a36Sopenharmony_ci /* Thermal zone registers */ 72862306a36Sopenharmony_ci for (ix = 0; ix < ARRAY_SIZE(data->zone_low); ix++) { 72962306a36Sopenharmony_ci /* Skip reading registers if zone3 is not present */ 73062306a36Sopenharmony_ci if ((ix == 2) && !(data->has_features & HAS_ZONE3)) 73162306a36Sopenharmony_ci continue; 73262306a36Sopenharmony_ci /* sch5127 zone2 registers are special */ 73362306a36Sopenharmony_ci if ((ix == 1) && (data->type == sch5127)) { 73462306a36Sopenharmony_ci data->zone_low[1] = dme1737_read(data, 73562306a36Sopenharmony_ci DME1737_REG_ZONE_LOW(2)); 73662306a36Sopenharmony_ci data->zone_abs[1] = dme1737_read(data, 73762306a36Sopenharmony_ci DME1737_REG_ZONE_ABS(2)); 73862306a36Sopenharmony_ci } else { 73962306a36Sopenharmony_ci data->zone_low[ix] = dme1737_read(data, 74062306a36Sopenharmony_ci DME1737_REG_ZONE_LOW(ix)); 74162306a36Sopenharmony_ci data->zone_abs[ix] = dme1737_read(data, 74262306a36Sopenharmony_ci DME1737_REG_ZONE_ABS(ix)); 74362306a36Sopenharmony_ci } 74462306a36Sopenharmony_ci } 74562306a36Sopenharmony_ci if (data->has_features & HAS_ZONE_HYST) { 74662306a36Sopenharmony_ci for (ix = 0; ix < ARRAY_SIZE(data->zone_hyst); ix++) { 74762306a36Sopenharmony_ci data->zone_hyst[ix] = dme1737_read(data, 74862306a36Sopenharmony_ci DME1737_REG_ZONE_HYST(ix)); 74962306a36Sopenharmony_ci } 75062306a36Sopenharmony_ci } 75162306a36Sopenharmony_ci 75262306a36Sopenharmony_ci /* Alarm registers */ 75362306a36Sopenharmony_ci data->alarms = dme1737_read(data, 75462306a36Sopenharmony_ci DME1737_REG_ALARM1); 75562306a36Sopenharmony_ci /* 75662306a36Sopenharmony_ci * Bit 7 tells us if the other alarm registers are non-zero and 75762306a36Sopenharmony_ci * therefore also need to be read 75862306a36Sopenharmony_ci */ 75962306a36Sopenharmony_ci if (data->alarms & 0x80) { 76062306a36Sopenharmony_ci data->alarms |= dme1737_read(data, 76162306a36Sopenharmony_ci DME1737_REG_ALARM2) << 8; 76262306a36Sopenharmony_ci data->alarms |= dme1737_read(data, 76362306a36Sopenharmony_ci DME1737_REG_ALARM3) << 16; 76462306a36Sopenharmony_ci } 76562306a36Sopenharmony_ci 76662306a36Sopenharmony_ci /* 76762306a36Sopenharmony_ci * The ISA chips require explicit clearing of alarm bits. 76862306a36Sopenharmony_ci * Don't worry, an alarm will come back if the condition 76962306a36Sopenharmony_ci * that causes it still exists 77062306a36Sopenharmony_ci */ 77162306a36Sopenharmony_ci if (!data->client) { 77262306a36Sopenharmony_ci if (data->alarms & 0xff0000) 77362306a36Sopenharmony_ci dme1737_write(data, DME1737_REG_ALARM3, 0xff); 77462306a36Sopenharmony_ci if (data->alarms & 0xff00) 77562306a36Sopenharmony_ci dme1737_write(data, DME1737_REG_ALARM2, 0xff); 77662306a36Sopenharmony_ci if (data->alarms & 0xff) 77762306a36Sopenharmony_ci dme1737_write(data, DME1737_REG_ALARM1, 0xff); 77862306a36Sopenharmony_ci } 77962306a36Sopenharmony_ci 78062306a36Sopenharmony_ci data->last_update = jiffies; 78162306a36Sopenharmony_ci data->valid = true; 78262306a36Sopenharmony_ci } 78362306a36Sopenharmony_ci 78462306a36Sopenharmony_ci mutex_unlock(&data->update_lock); 78562306a36Sopenharmony_ci 78662306a36Sopenharmony_ci return data; 78762306a36Sopenharmony_ci} 78862306a36Sopenharmony_ci 78962306a36Sopenharmony_ci/* --------------------------------------------------------------------- 79062306a36Sopenharmony_ci * Voltage sysfs attributes 79162306a36Sopenharmony_ci * ix = [0-7] 79262306a36Sopenharmony_ci * --------------------------------------------------------------------- */ 79362306a36Sopenharmony_ci 79462306a36Sopenharmony_ci#define SYS_IN_INPUT 0 79562306a36Sopenharmony_ci#define SYS_IN_MIN 1 79662306a36Sopenharmony_ci#define SYS_IN_MAX 2 79762306a36Sopenharmony_ci#define SYS_IN_ALARM 3 79862306a36Sopenharmony_ci 79962306a36Sopenharmony_cistatic ssize_t show_in(struct device *dev, struct device_attribute *attr, 80062306a36Sopenharmony_ci char *buf) 80162306a36Sopenharmony_ci{ 80262306a36Sopenharmony_ci struct dme1737_data *data = dme1737_update_device(dev); 80362306a36Sopenharmony_ci struct sensor_device_attribute_2 80462306a36Sopenharmony_ci *sensor_attr_2 = to_sensor_dev_attr_2(attr); 80562306a36Sopenharmony_ci int ix = sensor_attr_2->index; 80662306a36Sopenharmony_ci int fn = sensor_attr_2->nr; 80762306a36Sopenharmony_ci int res; 80862306a36Sopenharmony_ci 80962306a36Sopenharmony_ci switch (fn) { 81062306a36Sopenharmony_ci case SYS_IN_INPUT: 81162306a36Sopenharmony_ci res = IN_FROM_REG(data->in[ix], data->in_nominal[ix], 16); 81262306a36Sopenharmony_ci break; 81362306a36Sopenharmony_ci case SYS_IN_MIN: 81462306a36Sopenharmony_ci res = IN_FROM_REG(data->in_min[ix], data->in_nominal[ix], 8); 81562306a36Sopenharmony_ci break; 81662306a36Sopenharmony_ci case SYS_IN_MAX: 81762306a36Sopenharmony_ci res = IN_FROM_REG(data->in_max[ix], data->in_nominal[ix], 8); 81862306a36Sopenharmony_ci break; 81962306a36Sopenharmony_ci case SYS_IN_ALARM: 82062306a36Sopenharmony_ci res = (data->alarms >> DME1737_BIT_ALARM_IN[ix]) & 0x01; 82162306a36Sopenharmony_ci break; 82262306a36Sopenharmony_ci default: 82362306a36Sopenharmony_ci res = 0; 82462306a36Sopenharmony_ci dev_dbg(dev, "Unknown function %d.\n", fn); 82562306a36Sopenharmony_ci } 82662306a36Sopenharmony_ci 82762306a36Sopenharmony_ci return sprintf(buf, "%d\n", res); 82862306a36Sopenharmony_ci} 82962306a36Sopenharmony_ci 83062306a36Sopenharmony_cistatic ssize_t set_in(struct device *dev, struct device_attribute *attr, 83162306a36Sopenharmony_ci const char *buf, size_t count) 83262306a36Sopenharmony_ci{ 83362306a36Sopenharmony_ci struct dme1737_data *data = dev_get_drvdata(dev); 83462306a36Sopenharmony_ci struct sensor_device_attribute_2 83562306a36Sopenharmony_ci *sensor_attr_2 = to_sensor_dev_attr_2(attr); 83662306a36Sopenharmony_ci int ix = sensor_attr_2->index; 83762306a36Sopenharmony_ci int fn = sensor_attr_2->nr; 83862306a36Sopenharmony_ci long val; 83962306a36Sopenharmony_ci int err; 84062306a36Sopenharmony_ci 84162306a36Sopenharmony_ci err = kstrtol(buf, 10, &val); 84262306a36Sopenharmony_ci if (err) 84362306a36Sopenharmony_ci return err; 84462306a36Sopenharmony_ci 84562306a36Sopenharmony_ci mutex_lock(&data->update_lock); 84662306a36Sopenharmony_ci switch (fn) { 84762306a36Sopenharmony_ci case SYS_IN_MIN: 84862306a36Sopenharmony_ci data->in_min[ix] = IN_TO_REG(val, data->in_nominal[ix]); 84962306a36Sopenharmony_ci dme1737_write(data, DME1737_REG_IN_MIN(ix), 85062306a36Sopenharmony_ci data->in_min[ix]); 85162306a36Sopenharmony_ci break; 85262306a36Sopenharmony_ci case SYS_IN_MAX: 85362306a36Sopenharmony_ci data->in_max[ix] = IN_TO_REG(val, data->in_nominal[ix]); 85462306a36Sopenharmony_ci dme1737_write(data, DME1737_REG_IN_MAX(ix), 85562306a36Sopenharmony_ci data->in_max[ix]); 85662306a36Sopenharmony_ci break; 85762306a36Sopenharmony_ci default: 85862306a36Sopenharmony_ci dev_dbg(dev, "Unknown function %d.\n", fn); 85962306a36Sopenharmony_ci } 86062306a36Sopenharmony_ci mutex_unlock(&data->update_lock); 86162306a36Sopenharmony_ci 86262306a36Sopenharmony_ci return count; 86362306a36Sopenharmony_ci} 86462306a36Sopenharmony_ci 86562306a36Sopenharmony_ci/* --------------------------------------------------------------------- 86662306a36Sopenharmony_ci * Temperature sysfs attributes 86762306a36Sopenharmony_ci * ix = [0-2] 86862306a36Sopenharmony_ci * --------------------------------------------------------------------- */ 86962306a36Sopenharmony_ci 87062306a36Sopenharmony_ci#define SYS_TEMP_INPUT 0 87162306a36Sopenharmony_ci#define SYS_TEMP_MIN 1 87262306a36Sopenharmony_ci#define SYS_TEMP_MAX 2 87362306a36Sopenharmony_ci#define SYS_TEMP_OFFSET 3 87462306a36Sopenharmony_ci#define SYS_TEMP_ALARM 4 87562306a36Sopenharmony_ci#define SYS_TEMP_FAULT 5 87662306a36Sopenharmony_ci 87762306a36Sopenharmony_cistatic ssize_t show_temp(struct device *dev, struct device_attribute *attr, 87862306a36Sopenharmony_ci char *buf) 87962306a36Sopenharmony_ci{ 88062306a36Sopenharmony_ci struct dme1737_data *data = dme1737_update_device(dev); 88162306a36Sopenharmony_ci struct sensor_device_attribute_2 88262306a36Sopenharmony_ci *sensor_attr_2 = to_sensor_dev_attr_2(attr); 88362306a36Sopenharmony_ci int ix = sensor_attr_2->index; 88462306a36Sopenharmony_ci int fn = sensor_attr_2->nr; 88562306a36Sopenharmony_ci int res; 88662306a36Sopenharmony_ci 88762306a36Sopenharmony_ci switch (fn) { 88862306a36Sopenharmony_ci case SYS_TEMP_INPUT: 88962306a36Sopenharmony_ci res = TEMP_FROM_REG(data->temp[ix], 16); 89062306a36Sopenharmony_ci break; 89162306a36Sopenharmony_ci case SYS_TEMP_MIN: 89262306a36Sopenharmony_ci res = TEMP_FROM_REG(data->temp_min[ix], 8); 89362306a36Sopenharmony_ci break; 89462306a36Sopenharmony_ci case SYS_TEMP_MAX: 89562306a36Sopenharmony_ci res = TEMP_FROM_REG(data->temp_max[ix], 8); 89662306a36Sopenharmony_ci break; 89762306a36Sopenharmony_ci case SYS_TEMP_OFFSET: 89862306a36Sopenharmony_ci res = TEMP_FROM_REG(data->temp_offset[ix], 8); 89962306a36Sopenharmony_ci break; 90062306a36Sopenharmony_ci case SYS_TEMP_ALARM: 90162306a36Sopenharmony_ci res = (data->alarms >> DME1737_BIT_ALARM_TEMP[ix]) & 0x01; 90262306a36Sopenharmony_ci break; 90362306a36Sopenharmony_ci case SYS_TEMP_FAULT: 90462306a36Sopenharmony_ci res = (((u16)data->temp[ix] & 0xff00) == 0x8000); 90562306a36Sopenharmony_ci break; 90662306a36Sopenharmony_ci default: 90762306a36Sopenharmony_ci res = 0; 90862306a36Sopenharmony_ci dev_dbg(dev, "Unknown function %d.\n", fn); 90962306a36Sopenharmony_ci } 91062306a36Sopenharmony_ci 91162306a36Sopenharmony_ci return sprintf(buf, "%d\n", res); 91262306a36Sopenharmony_ci} 91362306a36Sopenharmony_ci 91462306a36Sopenharmony_cistatic ssize_t set_temp(struct device *dev, struct device_attribute *attr, 91562306a36Sopenharmony_ci const char *buf, size_t count) 91662306a36Sopenharmony_ci{ 91762306a36Sopenharmony_ci struct dme1737_data *data = dev_get_drvdata(dev); 91862306a36Sopenharmony_ci struct sensor_device_attribute_2 91962306a36Sopenharmony_ci *sensor_attr_2 = to_sensor_dev_attr_2(attr); 92062306a36Sopenharmony_ci int ix = sensor_attr_2->index; 92162306a36Sopenharmony_ci int fn = sensor_attr_2->nr; 92262306a36Sopenharmony_ci long val; 92362306a36Sopenharmony_ci int err; 92462306a36Sopenharmony_ci 92562306a36Sopenharmony_ci err = kstrtol(buf, 10, &val); 92662306a36Sopenharmony_ci if (err) 92762306a36Sopenharmony_ci return err; 92862306a36Sopenharmony_ci 92962306a36Sopenharmony_ci mutex_lock(&data->update_lock); 93062306a36Sopenharmony_ci switch (fn) { 93162306a36Sopenharmony_ci case SYS_TEMP_MIN: 93262306a36Sopenharmony_ci data->temp_min[ix] = TEMP_TO_REG(val); 93362306a36Sopenharmony_ci dme1737_write(data, DME1737_REG_TEMP_MIN(ix), 93462306a36Sopenharmony_ci data->temp_min[ix]); 93562306a36Sopenharmony_ci break; 93662306a36Sopenharmony_ci case SYS_TEMP_MAX: 93762306a36Sopenharmony_ci data->temp_max[ix] = TEMP_TO_REG(val); 93862306a36Sopenharmony_ci dme1737_write(data, DME1737_REG_TEMP_MAX(ix), 93962306a36Sopenharmony_ci data->temp_max[ix]); 94062306a36Sopenharmony_ci break; 94162306a36Sopenharmony_ci case SYS_TEMP_OFFSET: 94262306a36Sopenharmony_ci data->temp_offset[ix] = TEMP_TO_REG(val); 94362306a36Sopenharmony_ci dme1737_write(data, DME1737_REG_TEMP_OFFSET(ix), 94462306a36Sopenharmony_ci data->temp_offset[ix]); 94562306a36Sopenharmony_ci break; 94662306a36Sopenharmony_ci default: 94762306a36Sopenharmony_ci dev_dbg(dev, "Unknown function %d.\n", fn); 94862306a36Sopenharmony_ci } 94962306a36Sopenharmony_ci mutex_unlock(&data->update_lock); 95062306a36Sopenharmony_ci 95162306a36Sopenharmony_ci return count; 95262306a36Sopenharmony_ci} 95362306a36Sopenharmony_ci 95462306a36Sopenharmony_ci/* --------------------------------------------------------------------- 95562306a36Sopenharmony_ci * Zone sysfs attributes 95662306a36Sopenharmony_ci * ix = [0-2] 95762306a36Sopenharmony_ci * --------------------------------------------------------------------- */ 95862306a36Sopenharmony_ci 95962306a36Sopenharmony_ci#define SYS_ZONE_AUTO_CHANNELS_TEMP 0 96062306a36Sopenharmony_ci#define SYS_ZONE_AUTO_POINT1_TEMP_HYST 1 96162306a36Sopenharmony_ci#define SYS_ZONE_AUTO_POINT1_TEMP 2 96262306a36Sopenharmony_ci#define SYS_ZONE_AUTO_POINT2_TEMP 3 96362306a36Sopenharmony_ci#define SYS_ZONE_AUTO_POINT3_TEMP 4 96462306a36Sopenharmony_ci 96562306a36Sopenharmony_cistatic ssize_t show_zone(struct device *dev, struct device_attribute *attr, 96662306a36Sopenharmony_ci char *buf) 96762306a36Sopenharmony_ci{ 96862306a36Sopenharmony_ci struct dme1737_data *data = dme1737_update_device(dev); 96962306a36Sopenharmony_ci struct sensor_device_attribute_2 97062306a36Sopenharmony_ci *sensor_attr_2 = to_sensor_dev_attr_2(attr); 97162306a36Sopenharmony_ci int ix = sensor_attr_2->index; 97262306a36Sopenharmony_ci int fn = sensor_attr_2->nr; 97362306a36Sopenharmony_ci int res; 97462306a36Sopenharmony_ci 97562306a36Sopenharmony_ci switch (fn) { 97662306a36Sopenharmony_ci case SYS_ZONE_AUTO_CHANNELS_TEMP: 97762306a36Sopenharmony_ci /* check config2 for non-standard temp-to-zone mapping */ 97862306a36Sopenharmony_ci if ((ix == 1) && (data->config2 & 0x02)) 97962306a36Sopenharmony_ci res = 4; 98062306a36Sopenharmony_ci else 98162306a36Sopenharmony_ci res = 1 << ix; 98262306a36Sopenharmony_ci break; 98362306a36Sopenharmony_ci case SYS_ZONE_AUTO_POINT1_TEMP_HYST: 98462306a36Sopenharmony_ci res = TEMP_FROM_REG(data->zone_low[ix], 8) - 98562306a36Sopenharmony_ci TEMP_HYST_FROM_REG(data->zone_hyst[ix == 2], ix); 98662306a36Sopenharmony_ci break; 98762306a36Sopenharmony_ci case SYS_ZONE_AUTO_POINT1_TEMP: 98862306a36Sopenharmony_ci res = TEMP_FROM_REG(data->zone_low[ix], 8); 98962306a36Sopenharmony_ci break; 99062306a36Sopenharmony_ci case SYS_ZONE_AUTO_POINT2_TEMP: 99162306a36Sopenharmony_ci /* pwm_freq holds the temp range bits in the upper nibble */ 99262306a36Sopenharmony_ci res = TEMP_FROM_REG(data->zone_low[ix], 8) + 99362306a36Sopenharmony_ci TEMP_RANGE_FROM_REG(data->pwm_freq[ix]); 99462306a36Sopenharmony_ci break; 99562306a36Sopenharmony_ci case SYS_ZONE_AUTO_POINT3_TEMP: 99662306a36Sopenharmony_ci res = TEMP_FROM_REG(data->zone_abs[ix], 8); 99762306a36Sopenharmony_ci break; 99862306a36Sopenharmony_ci default: 99962306a36Sopenharmony_ci res = 0; 100062306a36Sopenharmony_ci dev_dbg(dev, "Unknown function %d.\n", fn); 100162306a36Sopenharmony_ci } 100262306a36Sopenharmony_ci 100362306a36Sopenharmony_ci return sprintf(buf, "%d\n", res); 100462306a36Sopenharmony_ci} 100562306a36Sopenharmony_ci 100662306a36Sopenharmony_cistatic ssize_t set_zone(struct device *dev, struct device_attribute *attr, 100762306a36Sopenharmony_ci const char *buf, size_t count) 100862306a36Sopenharmony_ci{ 100962306a36Sopenharmony_ci struct dme1737_data *data = dev_get_drvdata(dev); 101062306a36Sopenharmony_ci struct sensor_device_attribute_2 101162306a36Sopenharmony_ci *sensor_attr_2 = to_sensor_dev_attr_2(attr); 101262306a36Sopenharmony_ci int ix = sensor_attr_2->index; 101362306a36Sopenharmony_ci int fn = sensor_attr_2->nr; 101462306a36Sopenharmony_ci long val; 101562306a36Sopenharmony_ci int temp; 101662306a36Sopenharmony_ci int err; 101762306a36Sopenharmony_ci u8 reg; 101862306a36Sopenharmony_ci 101962306a36Sopenharmony_ci err = kstrtol(buf, 10, &val); 102062306a36Sopenharmony_ci if (err) 102162306a36Sopenharmony_ci return err; 102262306a36Sopenharmony_ci 102362306a36Sopenharmony_ci mutex_lock(&data->update_lock); 102462306a36Sopenharmony_ci switch (fn) { 102562306a36Sopenharmony_ci case SYS_ZONE_AUTO_POINT1_TEMP_HYST: 102662306a36Sopenharmony_ci /* Refresh the cache */ 102762306a36Sopenharmony_ci data->zone_low[ix] = dme1737_read(data, 102862306a36Sopenharmony_ci DME1737_REG_ZONE_LOW(ix)); 102962306a36Sopenharmony_ci /* Modify the temp hyst value */ 103062306a36Sopenharmony_ci temp = TEMP_FROM_REG(data->zone_low[ix], 8); 103162306a36Sopenharmony_ci reg = dme1737_read(data, DME1737_REG_ZONE_HYST(ix == 2)); 103262306a36Sopenharmony_ci data->zone_hyst[ix == 2] = TEMP_HYST_TO_REG(temp, val, ix, reg); 103362306a36Sopenharmony_ci dme1737_write(data, DME1737_REG_ZONE_HYST(ix == 2), 103462306a36Sopenharmony_ci data->zone_hyst[ix == 2]); 103562306a36Sopenharmony_ci break; 103662306a36Sopenharmony_ci case SYS_ZONE_AUTO_POINT1_TEMP: 103762306a36Sopenharmony_ci data->zone_low[ix] = TEMP_TO_REG(val); 103862306a36Sopenharmony_ci dme1737_write(data, DME1737_REG_ZONE_LOW(ix), 103962306a36Sopenharmony_ci data->zone_low[ix]); 104062306a36Sopenharmony_ci break; 104162306a36Sopenharmony_ci case SYS_ZONE_AUTO_POINT2_TEMP: 104262306a36Sopenharmony_ci /* Refresh the cache */ 104362306a36Sopenharmony_ci data->zone_low[ix] = dme1737_read(data, 104462306a36Sopenharmony_ci DME1737_REG_ZONE_LOW(ix)); 104562306a36Sopenharmony_ci /* 104662306a36Sopenharmony_ci * Modify the temp range value (which is stored in the upper 104762306a36Sopenharmony_ci * nibble of the pwm_freq register) 104862306a36Sopenharmony_ci */ 104962306a36Sopenharmony_ci temp = TEMP_FROM_REG(data->zone_low[ix], 8); 105062306a36Sopenharmony_ci val = clamp_val(val, temp, temp + 80000); 105162306a36Sopenharmony_ci reg = dme1737_read(data, DME1737_REG_PWM_FREQ(ix)); 105262306a36Sopenharmony_ci data->pwm_freq[ix] = TEMP_RANGE_TO_REG(val - temp, reg); 105362306a36Sopenharmony_ci dme1737_write(data, DME1737_REG_PWM_FREQ(ix), 105462306a36Sopenharmony_ci data->pwm_freq[ix]); 105562306a36Sopenharmony_ci break; 105662306a36Sopenharmony_ci case SYS_ZONE_AUTO_POINT3_TEMP: 105762306a36Sopenharmony_ci data->zone_abs[ix] = TEMP_TO_REG(val); 105862306a36Sopenharmony_ci dme1737_write(data, DME1737_REG_ZONE_ABS(ix), 105962306a36Sopenharmony_ci data->zone_abs[ix]); 106062306a36Sopenharmony_ci break; 106162306a36Sopenharmony_ci default: 106262306a36Sopenharmony_ci dev_dbg(dev, "Unknown function %d.\n", fn); 106362306a36Sopenharmony_ci } 106462306a36Sopenharmony_ci mutex_unlock(&data->update_lock); 106562306a36Sopenharmony_ci 106662306a36Sopenharmony_ci return count; 106762306a36Sopenharmony_ci} 106862306a36Sopenharmony_ci 106962306a36Sopenharmony_ci/* --------------------------------------------------------------------- 107062306a36Sopenharmony_ci * Fan sysfs attributes 107162306a36Sopenharmony_ci * ix = [0-5] 107262306a36Sopenharmony_ci * --------------------------------------------------------------------- */ 107362306a36Sopenharmony_ci 107462306a36Sopenharmony_ci#define SYS_FAN_INPUT 0 107562306a36Sopenharmony_ci#define SYS_FAN_MIN 1 107662306a36Sopenharmony_ci#define SYS_FAN_MAX 2 107762306a36Sopenharmony_ci#define SYS_FAN_ALARM 3 107862306a36Sopenharmony_ci#define SYS_FAN_TYPE 4 107962306a36Sopenharmony_ci 108062306a36Sopenharmony_cistatic ssize_t show_fan(struct device *dev, struct device_attribute *attr, 108162306a36Sopenharmony_ci char *buf) 108262306a36Sopenharmony_ci{ 108362306a36Sopenharmony_ci struct dme1737_data *data = dme1737_update_device(dev); 108462306a36Sopenharmony_ci struct sensor_device_attribute_2 108562306a36Sopenharmony_ci *sensor_attr_2 = to_sensor_dev_attr_2(attr); 108662306a36Sopenharmony_ci int ix = sensor_attr_2->index; 108762306a36Sopenharmony_ci int fn = sensor_attr_2->nr; 108862306a36Sopenharmony_ci int res; 108962306a36Sopenharmony_ci 109062306a36Sopenharmony_ci switch (fn) { 109162306a36Sopenharmony_ci case SYS_FAN_INPUT: 109262306a36Sopenharmony_ci res = FAN_FROM_REG(data->fan[ix], 109362306a36Sopenharmony_ci ix < 4 ? 0 : 109462306a36Sopenharmony_ci FAN_TPC_FROM_REG(data->fan_opt[ix])); 109562306a36Sopenharmony_ci break; 109662306a36Sopenharmony_ci case SYS_FAN_MIN: 109762306a36Sopenharmony_ci res = FAN_FROM_REG(data->fan_min[ix], 109862306a36Sopenharmony_ci ix < 4 ? 0 : 109962306a36Sopenharmony_ci FAN_TPC_FROM_REG(data->fan_opt[ix])); 110062306a36Sopenharmony_ci break; 110162306a36Sopenharmony_ci case SYS_FAN_MAX: 110262306a36Sopenharmony_ci /* only valid for fan[5-6] */ 110362306a36Sopenharmony_ci res = FAN_MAX_FROM_REG(data->fan_max[ix - 4]); 110462306a36Sopenharmony_ci break; 110562306a36Sopenharmony_ci case SYS_FAN_ALARM: 110662306a36Sopenharmony_ci res = (data->alarms >> DME1737_BIT_ALARM_FAN[ix]) & 0x01; 110762306a36Sopenharmony_ci break; 110862306a36Sopenharmony_ci case SYS_FAN_TYPE: 110962306a36Sopenharmony_ci /* only valid for fan[1-4] */ 111062306a36Sopenharmony_ci res = FAN_TYPE_FROM_REG(data->fan_opt[ix]); 111162306a36Sopenharmony_ci break; 111262306a36Sopenharmony_ci default: 111362306a36Sopenharmony_ci res = 0; 111462306a36Sopenharmony_ci dev_dbg(dev, "Unknown function %d.\n", fn); 111562306a36Sopenharmony_ci } 111662306a36Sopenharmony_ci 111762306a36Sopenharmony_ci return sprintf(buf, "%d\n", res); 111862306a36Sopenharmony_ci} 111962306a36Sopenharmony_ci 112062306a36Sopenharmony_cistatic ssize_t set_fan(struct device *dev, struct device_attribute *attr, 112162306a36Sopenharmony_ci const char *buf, size_t count) 112262306a36Sopenharmony_ci{ 112362306a36Sopenharmony_ci struct dme1737_data *data = dev_get_drvdata(dev); 112462306a36Sopenharmony_ci struct sensor_device_attribute_2 112562306a36Sopenharmony_ci *sensor_attr_2 = to_sensor_dev_attr_2(attr); 112662306a36Sopenharmony_ci int ix = sensor_attr_2->index; 112762306a36Sopenharmony_ci int fn = sensor_attr_2->nr; 112862306a36Sopenharmony_ci long val; 112962306a36Sopenharmony_ci int err; 113062306a36Sopenharmony_ci 113162306a36Sopenharmony_ci err = kstrtol(buf, 10, &val); 113262306a36Sopenharmony_ci if (err) 113362306a36Sopenharmony_ci return err; 113462306a36Sopenharmony_ci 113562306a36Sopenharmony_ci mutex_lock(&data->update_lock); 113662306a36Sopenharmony_ci switch (fn) { 113762306a36Sopenharmony_ci case SYS_FAN_MIN: 113862306a36Sopenharmony_ci if (ix < 4) { 113962306a36Sopenharmony_ci data->fan_min[ix] = FAN_TO_REG(val, 0); 114062306a36Sopenharmony_ci } else { 114162306a36Sopenharmony_ci /* Refresh the cache */ 114262306a36Sopenharmony_ci data->fan_opt[ix] = dme1737_read(data, 114362306a36Sopenharmony_ci DME1737_REG_FAN_OPT(ix)); 114462306a36Sopenharmony_ci /* Modify the fan min value */ 114562306a36Sopenharmony_ci data->fan_min[ix] = FAN_TO_REG(val, 114662306a36Sopenharmony_ci FAN_TPC_FROM_REG(data->fan_opt[ix])); 114762306a36Sopenharmony_ci } 114862306a36Sopenharmony_ci dme1737_write(data, DME1737_REG_FAN_MIN(ix), 114962306a36Sopenharmony_ci data->fan_min[ix] & 0xff); 115062306a36Sopenharmony_ci dme1737_write(data, DME1737_REG_FAN_MIN(ix) + 1, 115162306a36Sopenharmony_ci data->fan_min[ix] >> 8); 115262306a36Sopenharmony_ci break; 115362306a36Sopenharmony_ci case SYS_FAN_MAX: 115462306a36Sopenharmony_ci /* Only valid for fan[5-6] */ 115562306a36Sopenharmony_ci data->fan_max[ix - 4] = FAN_MAX_TO_REG(val); 115662306a36Sopenharmony_ci dme1737_write(data, DME1737_REG_FAN_MAX(ix), 115762306a36Sopenharmony_ci data->fan_max[ix - 4]); 115862306a36Sopenharmony_ci break; 115962306a36Sopenharmony_ci case SYS_FAN_TYPE: 116062306a36Sopenharmony_ci /* Only valid for fan[1-4] */ 116162306a36Sopenharmony_ci if (!(val == 1 || val == 2 || val == 4)) { 116262306a36Sopenharmony_ci count = -EINVAL; 116362306a36Sopenharmony_ci dev_warn(dev, 116462306a36Sopenharmony_ci "Fan type value %ld not supported. Choose one of 1, 2, or 4.\n", 116562306a36Sopenharmony_ci val); 116662306a36Sopenharmony_ci goto exit; 116762306a36Sopenharmony_ci } 116862306a36Sopenharmony_ci data->fan_opt[ix] = FAN_TYPE_TO_REG(val, dme1737_read(data, 116962306a36Sopenharmony_ci DME1737_REG_FAN_OPT(ix))); 117062306a36Sopenharmony_ci dme1737_write(data, DME1737_REG_FAN_OPT(ix), 117162306a36Sopenharmony_ci data->fan_opt[ix]); 117262306a36Sopenharmony_ci break; 117362306a36Sopenharmony_ci default: 117462306a36Sopenharmony_ci dev_dbg(dev, "Unknown function %d.\n", fn); 117562306a36Sopenharmony_ci } 117662306a36Sopenharmony_ciexit: 117762306a36Sopenharmony_ci mutex_unlock(&data->update_lock); 117862306a36Sopenharmony_ci 117962306a36Sopenharmony_ci return count; 118062306a36Sopenharmony_ci} 118162306a36Sopenharmony_ci 118262306a36Sopenharmony_ci/* --------------------------------------------------------------------- 118362306a36Sopenharmony_ci * PWM sysfs attributes 118462306a36Sopenharmony_ci * ix = [0-4] 118562306a36Sopenharmony_ci * --------------------------------------------------------------------- */ 118662306a36Sopenharmony_ci 118762306a36Sopenharmony_ci#define SYS_PWM 0 118862306a36Sopenharmony_ci#define SYS_PWM_FREQ 1 118962306a36Sopenharmony_ci#define SYS_PWM_ENABLE 2 119062306a36Sopenharmony_ci#define SYS_PWM_RAMP_RATE 3 119162306a36Sopenharmony_ci#define SYS_PWM_AUTO_CHANNELS_ZONE 4 119262306a36Sopenharmony_ci#define SYS_PWM_AUTO_PWM_MIN 5 119362306a36Sopenharmony_ci#define SYS_PWM_AUTO_POINT1_PWM 6 119462306a36Sopenharmony_ci#define SYS_PWM_AUTO_POINT2_PWM 7 119562306a36Sopenharmony_ci 119662306a36Sopenharmony_cistatic ssize_t show_pwm(struct device *dev, struct device_attribute *attr, 119762306a36Sopenharmony_ci char *buf) 119862306a36Sopenharmony_ci{ 119962306a36Sopenharmony_ci struct dme1737_data *data = dme1737_update_device(dev); 120062306a36Sopenharmony_ci struct sensor_device_attribute_2 120162306a36Sopenharmony_ci *sensor_attr_2 = to_sensor_dev_attr_2(attr); 120262306a36Sopenharmony_ci int ix = sensor_attr_2->index; 120362306a36Sopenharmony_ci int fn = sensor_attr_2->nr; 120462306a36Sopenharmony_ci int res; 120562306a36Sopenharmony_ci 120662306a36Sopenharmony_ci switch (fn) { 120762306a36Sopenharmony_ci case SYS_PWM: 120862306a36Sopenharmony_ci if (PWM_EN_FROM_REG(data->pwm_config[ix]) == 0) 120962306a36Sopenharmony_ci res = 255; 121062306a36Sopenharmony_ci else 121162306a36Sopenharmony_ci res = data->pwm[ix]; 121262306a36Sopenharmony_ci break; 121362306a36Sopenharmony_ci case SYS_PWM_FREQ: 121462306a36Sopenharmony_ci res = PWM_FREQ_FROM_REG(data->pwm_freq[ix]); 121562306a36Sopenharmony_ci break; 121662306a36Sopenharmony_ci case SYS_PWM_ENABLE: 121762306a36Sopenharmony_ci if (ix >= 3) 121862306a36Sopenharmony_ci res = 1; /* pwm[5-6] hard-wired to manual mode */ 121962306a36Sopenharmony_ci else 122062306a36Sopenharmony_ci res = PWM_EN_FROM_REG(data->pwm_config[ix]); 122162306a36Sopenharmony_ci break; 122262306a36Sopenharmony_ci case SYS_PWM_RAMP_RATE: 122362306a36Sopenharmony_ci /* Only valid for pwm[1-3] */ 122462306a36Sopenharmony_ci res = PWM_RR_FROM_REG(data->pwm_rr[ix > 0], ix); 122562306a36Sopenharmony_ci break; 122662306a36Sopenharmony_ci case SYS_PWM_AUTO_CHANNELS_ZONE: 122762306a36Sopenharmony_ci /* Only valid for pwm[1-3] */ 122862306a36Sopenharmony_ci if (PWM_EN_FROM_REG(data->pwm_config[ix]) == 2) 122962306a36Sopenharmony_ci res = PWM_ACZ_FROM_REG(data->pwm_config[ix]); 123062306a36Sopenharmony_ci else 123162306a36Sopenharmony_ci res = data->pwm_acz[ix]; 123262306a36Sopenharmony_ci break; 123362306a36Sopenharmony_ci case SYS_PWM_AUTO_PWM_MIN: 123462306a36Sopenharmony_ci /* Only valid for pwm[1-3] */ 123562306a36Sopenharmony_ci if (PWM_OFF_FROM_REG(data->pwm_rr[0], ix)) 123662306a36Sopenharmony_ci res = data->pwm_min[ix]; 123762306a36Sopenharmony_ci else 123862306a36Sopenharmony_ci res = 0; 123962306a36Sopenharmony_ci break; 124062306a36Sopenharmony_ci case SYS_PWM_AUTO_POINT1_PWM: 124162306a36Sopenharmony_ci /* Only valid for pwm[1-3] */ 124262306a36Sopenharmony_ci res = data->pwm_min[ix]; 124362306a36Sopenharmony_ci break; 124462306a36Sopenharmony_ci case SYS_PWM_AUTO_POINT2_PWM: 124562306a36Sopenharmony_ci /* Only valid for pwm[1-3] */ 124662306a36Sopenharmony_ci res = 255; /* hard-wired */ 124762306a36Sopenharmony_ci break; 124862306a36Sopenharmony_ci default: 124962306a36Sopenharmony_ci res = 0; 125062306a36Sopenharmony_ci dev_dbg(dev, "Unknown function %d.\n", fn); 125162306a36Sopenharmony_ci } 125262306a36Sopenharmony_ci 125362306a36Sopenharmony_ci return sprintf(buf, "%d\n", res); 125462306a36Sopenharmony_ci} 125562306a36Sopenharmony_ci 125662306a36Sopenharmony_cistatic struct attribute *dme1737_pwm_chmod_attr[]; 125762306a36Sopenharmony_cistatic void dme1737_chmod_file(struct device*, struct attribute*, umode_t); 125862306a36Sopenharmony_ci 125962306a36Sopenharmony_cistatic ssize_t set_pwm(struct device *dev, struct device_attribute *attr, 126062306a36Sopenharmony_ci const char *buf, size_t count) 126162306a36Sopenharmony_ci{ 126262306a36Sopenharmony_ci struct dme1737_data *data = dev_get_drvdata(dev); 126362306a36Sopenharmony_ci struct sensor_device_attribute_2 126462306a36Sopenharmony_ci *sensor_attr_2 = to_sensor_dev_attr_2(attr); 126562306a36Sopenharmony_ci int ix = sensor_attr_2->index; 126662306a36Sopenharmony_ci int fn = sensor_attr_2->nr; 126762306a36Sopenharmony_ci long val; 126862306a36Sopenharmony_ci int err; 126962306a36Sopenharmony_ci 127062306a36Sopenharmony_ci err = kstrtol(buf, 10, &val); 127162306a36Sopenharmony_ci if (err) 127262306a36Sopenharmony_ci return err; 127362306a36Sopenharmony_ci 127462306a36Sopenharmony_ci mutex_lock(&data->update_lock); 127562306a36Sopenharmony_ci switch (fn) { 127662306a36Sopenharmony_ci case SYS_PWM: 127762306a36Sopenharmony_ci data->pwm[ix] = clamp_val(val, 0, 255); 127862306a36Sopenharmony_ci dme1737_write(data, DME1737_REG_PWM(ix), data->pwm[ix]); 127962306a36Sopenharmony_ci break; 128062306a36Sopenharmony_ci case SYS_PWM_FREQ: 128162306a36Sopenharmony_ci data->pwm_freq[ix] = PWM_FREQ_TO_REG(val, dme1737_read(data, 128262306a36Sopenharmony_ci DME1737_REG_PWM_FREQ(ix))); 128362306a36Sopenharmony_ci dme1737_write(data, DME1737_REG_PWM_FREQ(ix), 128462306a36Sopenharmony_ci data->pwm_freq[ix]); 128562306a36Sopenharmony_ci break; 128662306a36Sopenharmony_ci case SYS_PWM_ENABLE: 128762306a36Sopenharmony_ci /* Only valid for pwm[1-3] */ 128862306a36Sopenharmony_ci if (val < 0 || val > 2) { 128962306a36Sopenharmony_ci count = -EINVAL; 129062306a36Sopenharmony_ci dev_warn(dev, 129162306a36Sopenharmony_ci "PWM enable %ld not supported. Choose one of 0, 1, or 2.\n", 129262306a36Sopenharmony_ci val); 129362306a36Sopenharmony_ci goto exit; 129462306a36Sopenharmony_ci } 129562306a36Sopenharmony_ci /* Refresh the cache */ 129662306a36Sopenharmony_ci data->pwm_config[ix] = dme1737_read(data, 129762306a36Sopenharmony_ci DME1737_REG_PWM_CONFIG(ix)); 129862306a36Sopenharmony_ci if (val == PWM_EN_FROM_REG(data->pwm_config[ix])) { 129962306a36Sopenharmony_ci /* Bail out if no change */ 130062306a36Sopenharmony_ci goto exit; 130162306a36Sopenharmony_ci } 130262306a36Sopenharmony_ci /* Do some housekeeping if we are currently in auto mode */ 130362306a36Sopenharmony_ci if (PWM_EN_FROM_REG(data->pwm_config[ix]) == 2) { 130462306a36Sopenharmony_ci /* Save the current zone channel assignment */ 130562306a36Sopenharmony_ci data->pwm_acz[ix] = PWM_ACZ_FROM_REG( 130662306a36Sopenharmony_ci data->pwm_config[ix]); 130762306a36Sopenharmony_ci /* Save the current ramp rate state and disable it */ 130862306a36Sopenharmony_ci data->pwm_rr[ix > 0] = dme1737_read(data, 130962306a36Sopenharmony_ci DME1737_REG_PWM_RR(ix > 0)); 131062306a36Sopenharmony_ci data->pwm_rr_en &= ~(1 << ix); 131162306a36Sopenharmony_ci if (PWM_RR_EN_FROM_REG(data->pwm_rr[ix > 0], ix)) { 131262306a36Sopenharmony_ci data->pwm_rr_en |= (1 << ix); 131362306a36Sopenharmony_ci data->pwm_rr[ix > 0] = PWM_RR_EN_TO_REG(0, ix, 131462306a36Sopenharmony_ci data->pwm_rr[ix > 0]); 131562306a36Sopenharmony_ci dme1737_write(data, 131662306a36Sopenharmony_ci DME1737_REG_PWM_RR(ix > 0), 131762306a36Sopenharmony_ci data->pwm_rr[ix > 0]); 131862306a36Sopenharmony_ci } 131962306a36Sopenharmony_ci } 132062306a36Sopenharmony_ci /* Set the new PWM mode */ 132162306a36Sopenharmony_ci switch (val) { 132262306a36Sopenharmony_ci case 0: 132362306a36Sopenharmony_ci /* Change permissions of pwm[ix] to read-only */ 132462306a36Sopenharmony_ci dme1737_chmod_file(dev, dme1737_pwm_chmod_attr[ix], 132562306a36Sopenharmony_ci S_IRUGO); 132662306a36Sopenharmony_ci /* Turn fan fully on */ 132762306a36Sopenharmony_ci data->pwm_config[ix] = PWM_EN_TO_REG(0, 132862306a36Sopenharmony_ci data->pwm_config[ix]); 132962306a36Sopenharmony_ci dme1737_write(data, DME1737_REG_PWM_CONFIG(ix), 133062306a36Sopenharmony_ci data->pwm_config[ix]); 133162306a36Sopenharmony_ci break; 133262306a36Sopenharmony_ci case 1: 133362306a36Sopenharmony_ci /* Turn on manual mode */ 133462306a36Sopenharmony_ci data->pwm_config[ix] = PWM_EN_TO_REG(1, 133562306a36Sopenharmony_ci data->pwm_config[ix]); 133662306a36Sopenharmony_ci dme1737_write(data, DME1737_REG_PWM_CONFIG(ix), 133762306a36Sopenharmony_ci data->pwm_config[ix]); 133862306a36Sopenharmony_ci /* Change permissions of pwm[ix] to read-writeable */ 133962306a36Sopenharmony_ci dme1737_chmod_file(dev, dme1737_pwm_chmod_attr[ix], 134062306a36Sopenharmony_ci S_IRUGO | S_IWUSR); 134162306a36Sopenharmony_ci break; 134262306a36Sopenharmony_ci case 2: 134362306a36Sopenharmony_ci /* Change permissions of pwm[ix] to read-only */ 134462306a36Sopenharmony_ci dme1737_chmod_file(dev, dme1737_pwm_chmod_attr[ix], 134562306a36Sopenharmony_ci S_IRUGO); 134662306a36Sopenharmony_ci /* 134762306a36Sopenharmony_ci * Turn on auto mode using the saved zone channel 134862306a36Sopenharmony_ci * assignment 134962306a36Sopenharmony_ci */ 135062306a36Sopenharmony_ci data->pwm_config[ix] = PWM_ACZ_TO_REG( 135162306a36Sopenharmony_ci data->pwm_acz[ix], 135262306a36Sopenharmony_ci data->pwm_config[ix]); 135362306a36Sopenharmony_ci dme1737_write(data, DME1737_REG_PWM_CONFIG(ix), 135462306a36Sopenharmony_ci data->pwm_config[ix]); 135562306a36Sopenharmony_ci /* Enable PWM ramp rate if previously enabled */ 135662306a36Sopenharmony_ci if (data->pwm_rr_en & (1 << ix)) { 135762306a36Sopenharmony_ci data->pwm_rr[ix > 0] = PWM_RR_EN_TO_REG(1, ix, 135862306a36Sopenharmony_ci dme1737_read(data, 135962306a36Sopenharmony_ci DME1737_REG_PWM_RR(ix > 0))); 136062306a36Sopenharmony_ci dme1737_write(data, 136162306a36Sopenharmony_ci DME1737_REG_PWM_RR(ix > 0), 136262306a36Sopenharmony_ci data->pwm_rr[ix > 0]); 136362306a36Sopenharmony_ci } 136462306a36Sopenharmony_ci break; 136562306a36Sopenharmony_ci } 136662306a36Sopenharmony_ci break; 136762306a36Sopenharmony_ci case SYS_PWM_RAMP_RATE: 136862306a36Sopenharmony_ci /* Only valid for pwm[1-3] */ 136962306a36Sopenharmony_ci /* Refresh the cache */ 137062306a36Sopenharmony_ci data->pwm_config[ix] = dme1737_read(data, 137162306a36Sopenharmony_ci DME1737_REG_PWM_CONFIG(ix)); 137262306a36Sopenharmony_ci data->pwm_rr[ix > 0] = dme1737_read(data, 137362306a36Sopenharmony_ci DME1737_REG_PWM_RR(ix > 0)); 137462306a36Sopenharmony_ci /* Set the ramp rate value */ 137562306a36Sopenharmony_ci if (val > 0) { 137662306a36Sopenharmony_ci data->pwm_rr[ix > 0] = PWM_RR_TO_REG(val, ix, 137762306a36Sopenharmony_ci data->pwm_rr[ix > 0]); 137862306a36Sopenharmony_ci } 137962306a36Sopenharmony_ci /* 138062306a36Sopenharmony_ci * Enable/disable the feature only if the associated PWM 138162306a36Sopenharmony_ci * output is in automatic mode. 138262306a36Sopenharmony_ci */ 138362306a36Sopenharmony_ci if (PWM_EN_FROM_REG(data->pwm_config[ix]) == 2) { 138462306a36Sopenharmony_ci data->pwm_rr[ix > 0] = PWM_RR_EN_TO_REG(val > 0, ix, 138562306a36Sopenharmony_ci data->pwm_rr[ix > 0]); 138662306a36Sopenharmony_ci } 138762306a36Sopenharmony_ci dme1737_write(data, DME1737_REG_PWM_RR(ix > 0), 138862306a36Sopenharmony_ci data->pwm_rr[ix > 0]); 138962306a36Sopenharmony_ci break; 139062306a36Sopenharmony_ci case SYS_PWM_AUTO_CHANNELS_ZONE: 139162306a36Sopenharmony_ci /* Only valid for pwm[1-3] */ 139262306a36Sopenharmony_ci if (!(val == 1 || val == 2 || val == 4 || 139362306a36Sopenharmony_ci val == 6 || val == 7)) { 139462306a36Sopenharmony_ci count = -EINVAL; 139562306a36Sopenharmony_ci dev_warn(dev, 139662306a36Sopenharmony_ci "PWM auto channels zone %ld not supported. Choose one of 1, 2, 4, 6, " 139762306a36Sopenharmony_ci "or 7.\n", val); 139862306a36Sopenharmony_ci goto exit; 139962306a36Sopenharmony_ci } 140062306a36Sopenharmony_ci /* Refresh the cache */ 140162306a36Sopenharmony_ci data->pwm_config[ix] = dme1737_read(data, 140262306a36Sopenharmony_ci DME1737_REG_PWM_CONFIG(ix)); 140362306a36Sopenharmony_ci if (PWM_EN_FROM_REG(data->pwm_config[ix]) == 2) { 140462306a36Sopenharmony_ci /* 140562306a36Sopenharmony_ci * PWM is already in auto mode so update the temp 140662306a36Sopenharmony_ci * channel assignment 140762306a36Sopenharmony_ci */ 140862306a36Sopenharmony_ci data->pwm_config[ix] = PWM_ACZ_TO_REG(val, 140962306a36Sopenharmony_ci data->pwm_config[ix]); 141062306a36Sopenharmony_ci dme1737_write(data, DME1737_REG_PWM_CONFIG(ix), 141162306a36Sopenharmony_ci data->pwm_config[ix]); 141262306a36Sopenharmony_ci } else { 141362306a36Sopenharmony_ci /* 141462306a36Sopenharmony_ci * PWM is not in auto mode so we save the temp 141562306a36Sopenharmony_ci * channel assignment for later use 141662306a36Sopenharmony_ci */ 141762306a36Sopenharmony_ci data->pwm_acz[ix] = val; 141862306a36Sopenharmony_ci } 141962306a36Sopenharmony_ci break; 142062306a36Sopenharmony_ci case SYS_PWM_AUTO_PWM_MIN: 142162306a36Sopenharmony_ci /* Only valid for pwm[1-3] */ 142262306a36Sopenharmony_ci /* Refresh the cache */ 142362306a36Sopenharmony_ci data->pwm_min[ix] = dme1737_read(data, 142462306a36Sopenharmony_ci DME1737_REG_PWM_MIN(ix)); 142562306a36Sopenharmony_ci /* 142662306a36Sopenharmony_ci * There are only 2 values supported for the auto_pwm_min 142762306a36Sopenharmony_ci * value: 0 or auto_point1_pwm. So if the temperature drops 142862306a36Sopenharmony_ci * below the auto_point1_temp_hyst value, the fan either turns 142962306a36Sopenharmony_ci * off or runs at auto_point1_pwm duty-cycle. 143062306a36Sopenharmony_ci */ 143162306a36Sopenharmony_ci if (val > ((data->pwm_min[ix] + 1) / 2)) { 143262306a36Sopenharmony_ci data->pwm_rr[0] = PWM_OFF_TO_REG(1, ix, 143362306a36Sopenharmony_ci dme1737_read(data, 143462306a36Sopenharmony_ci DME1737_REG_PWM_RR(0))); 143562306a36Sopenharmony_ci } else { 143662306a36Sopenharmony_ci data->pwm_rr[0] = PWM_OFF_TO_REG(0, ix, 143762306a36Sopenharmony_ci dme1737_read(data, 143862306a36Sopenharmony_ci DME1737_REG_PWM_RR(0))); 143962306a36Sopenharmony_ci } 144062306a36Sopenharmony_ci dme1737_write(data, DME1737_REG_PWM_RR(0), 144162306a36Sopenharmony_ci data->pwm_rr[0]); 144262306a36Sopenharmony_ci break; 144362306a36Sopenharmony_ci case SYS_PWM_AUTO_POINT1_PWM: 144462306a36Sopenharmony_ci /* Only valid for pwm[1-3] */ 144562306a36Sopenharmony_ci data->pwm_min[ix] = clamp_val(val, 0, 255); 144662306a36Sopenharmony_ci dme1737_write(data, DME1737_REG_PWM_MIN(ix), 144762306a36Sopenharmony_ci data->pwm_min[ix]); 144862306a36Sopenharmony_ci break; 144962306a36Sopenharmony_ci default: 145062306a36Sopenharmony_ci dev_dbg(dev, "Unknown function %d.\n", fn); 145162306a36Sopenharmony_ci } 145262306a36Sopenharmony_ciexit: 145362306a36Sopenharmony_ci mutex_unlock(&data->update_lock); 145462306a36Sopenharmony_ci 145562306a36Sopenharmony_ci return count; 145662306a36Sopenharmony_ci} 145762306a36Sopenharmony_ci 145862306a36Sopenharmony_ci/* --------------------------------------------------------------------- 145962306a36Sopenharmony_ci * Miscellaneous sysfs attributes 146062306a36Sopenharmony_ci * --------------------------------------------------------------------- */ 146162306a36Sopenharmony_ci 146262306a36Sopenharmony_cistatic ssize_t vrm_show(struct device *dev, struct device_attribute *attr, 146362306a36Sopenharmony_ci char *buf) 146462306a36Sopenharmony_ci{ 146562306a36Sopenharmony_ci struct i2c_client *client = to_i2c_client(dev); 146662306a36Sopenharmony_ci struct dme1737_data *data = i2c_get_clientdata(client); 146762306a36Sopenharmony_ci 146862306a36Sopenharmony_ci return sprintf(buf, "%d\n", data->vrm); 146962306a36Sopenharmony_ci} 147062306a36Sopenharmony_ci 147162306a36Sopenharmony_cistatic ssize_t vrm_store(struct device *dev, struct device_attribute *attr, 147262306a36Sopenharmony_ci const char *buf, size_t count) 147362306a36Sopenharmony_ci{ 147462306a36Sopenharmony_ci struct dme1737_data *data = dev_get_drvdata(dev); 147562306a36Sopenharmony_ci unsigned long val; 147662306a36Sopenharmony_ci int err; 147762306a36Sopenharmony_ci 147862306a36Sopenharmony_ci err = kstrtoul(buf, 10, &val); 147962306a36Sopenharmony_ci if (err) 148062306a36Sopenharmony_ci return err; 148162306a36Sopenharmony_ci 148262306a36Sopenharmony_ci if (val > 255) 148362306a36Sopenharmony_ci return -EINVAL; 148462306a36Sopenharmony_ci 148562306a36Sopenharmony_ci data->vrm = val; 148662306a36Sopenharmony_ci return count; 148762306a36Sopenharmony_ci} 148862306a36Sopenharmony_ci 148962306a36Sopenharmony_cistatic ssize_t cpu0_vid_show(struct device *dev, 149062306a36Sopenharmony_ci struct device_attribute *attr, char *buf) 149162306a36Sopenharmony_ci{ 149262306a36Sopenharmony_ci struct dme1737_data *data = dme1737_update_device(dev); 149362306a36Sopenharmony_ci 149462306a36Sopenharmony_ci return sprintf(buf, "%d\n", vid_from_reg(data->vid, data->vrm)); 149562306a36Sopenharmony_ci} 149662306a36Sopenharmony_ci 149762306a36Sopenharmony_cistatic ssize_t name_show(struct device *dev, struct device_attribute *attr, 149862306a36Sopenharmony_ci char *buf) 149962306a36Sopenharmony_ci{ 150062306a36Sopenharmony_ci struct dme1737_data *data = dev_get_drvdata(dev); 150162306a36Sopenharmony_ci 150262306a36Sopenharmony_ci return sprintf(buf, "%s\n", data->name); 150362306a36Sopenharmony_ci} 150462306a36Sopenharmony_ci 150562306a36Sopenharmony_ci/* --------------------------------------------------------------------- 150662306a36Sopenharmony_ci * Sysfs device attribute defines and structs 150762306a36Sopenharmony_ci * --------------------------------------------------------------------- */ 150862306a36Sopenharmony_ci 150962306a36Sopenharmony_ci/* Voltages 0-7 */ 151062306a36Sopenharmony_ci 151162306a36Sopenharmony_ci#define SENSOR_DEVICE_ATTR_IN(ix) \ 151262306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2(in##ix##_input, S_IRUGO, \ 151362306a36Sopenharmony_ci show_in, NULL, SYS_IN_INPUT, ix); \ 151462306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2(in##ix##_min, S_IRUGO | S_IWUSR, \ 151562306a36Sopenharmony_ci show_in, set_in, SYS_IN_MIN, ix); \ 151662306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2(in##ix##_max, S_IRUGO | S_IWUSR, \ 151762306a36Sopenharmony_ci show_in, set_in, SYS_IN_MAX, ix); \ 151862306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2(in##ix##_alarm, S_IRUGO, \ 151962306a36Sopenharmony_ci show_in, NULL, SYS_IN_ALARM, ix) 152062306a36Sopenharmony_ci 152162306a36Sopenharmony_ciSENSOR_DEVICE_ATTR_IN(0); 152262306a36Sopenharmony_ciSENSOR_DEVICE_ATTR_IN(1); 152362306a36Sopenharmony_ciSENSOR_DEVICE_ATTR_IN(2); 152462306a36Sopenharmony_ciSENSOR_DEVICE_ATTR_IN(3); 152562306a36Sopenharmony_ciSENSOR_DEVICE_ATTR_IN(4); 152662306a36Sopenharmony_ciSENSOR_DEVICE_ATTR_IN(5); 152762306a36Sopenharmony_ciSENSOR_DEVICE_ATTR_IN(6); 152862306a36Sopenharmony_ciSENSOR_DEVICE_ATTR_IN(7); 152962306a36Sopenharmony_ci 153062306a36Sopenharmony_ci/* Temperatures 1-3 */ 153162306a36Sopenharmony_ci 153262306a36Sopenharmony_ci#define SENSOR_DEVICE_ATTR_TEMP(ix) \ 153362306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2(temp##ix##_input, S_IRUGO, \ 153462306a36Sopenharmony_ci show_temp, NULL, SYS_TEMP_INPUT, ix-1); \ 153562306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2(temp##ix##_min, S_IRUGO | S_IWUSR, \ 153662306a36Sopenharmony_ci show_temp, set_temp, SYS_TEMP_MIN, ix-1); \ 153762306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2(temp##ix##_max, S_IRUGO | S_IWUSR, \ 153862306a36Sopenharmony_ci show_temp, set_temp, SYS_TEMP_MAX, ix-1); \ 153962306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2(temp##ix##_offset, S_IRUGO, \ 154062306a36Sopenharmony_ci show_temp, set_temp, SYS_TEMP_OFFSET, ix-1); \ 154162306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2(temp##ix##_alarm, S_IRUGO, \ 154262306a36Sopenharmony_ci show_temp, NULL, SYS_TEMP_ALARM, ix-1); \ 154362306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2(temp##ix##_fault, S_IRUGO, \ 154462306a36Sopenharmony_ci show_temp, NULL, SYS_TEMP_FAULT, ix-1) 154562306a36Sopenharmony_ci 154662306a36Sopenharmony_ciSENSOR_DEVICE_ATTR_TEMP(1); 154762306a36Sopenharmony_ciSENSOR_DEVICE_ATTR_TEMP(2); 154862306a36Sopenharmony_ciSENSOR_DEVICE_ATTR_TEMP(3); 154962306a36Sopenharmony_ci 155062306a36Sopenharmony_ci/* Zones 1-3 */ 155162306a36Sopenharmony_ci 155262306a36Sopenharmony_ci#define SENSOR_DEVICE_ATTR_ZONE(ix) \ 155362306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2(zone##ix##_auto_channels_temp, S_IRUGO, \ 155462306a36Sopenharmony_ci show_zone, NULL, SYS_ZONE_AUTO_CHANNELS_TEMP, ix-1); \ 155562306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2(zone##ix##_auto_point1_temp_hyst, S_IRUGO, \ 155662306a36Sopenharmony_ci show_zone, set_zone, SYS_ZONE_AUTO_POINT1_TEMP_HYST, ix-1); \ 155762306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2(zone##ix##_auto_point1_temp, S_IRUGO, \ 155862306a36Sopenharmony_ci show_zone, set_zone, SYS_ZONE_AUTO_POINT1_TEMP, ix-1); \ 155962306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2(zone##ix##_auto_point2_temp, S_IRUGO, \ 156062306a36Sopenharmony_ci show_zone, set_zone, SYS_ZONE_AUTO_POINT2_TEMP, ix-1); \ 156162306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2(zone##ix##_auto_point3_temp, S_IRUGO, \ 156262306a36Sopenharmony_ci show_zone, set_zone, SYS_ZONE_AUTO_POINT3_TEMP, ix-1) 156362306a36Sopenharmony_ci 156462306a36Sopenharmony_ciSENSOR_DEVICE_ATTR_ZONE(1); 156562306a36Sopenharmony_ciSENSOR_DEVICE_ATTR_ZONE(2); 156662306a36Sopenharmony_ciSENSOR_DEVICE_ATTR_ZONE(3); 156762306a36Sopenharmony_ci 156862306a36Sopenharmony_ci/* Fans 1-4 */ 156962306a36Sopenharmony_ci 157062306a36Sopenharmony_ci#define SENSOR_DEVICE_ATTR_FAN_1TO4(ix) \ 157162306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2(fan##ix##_input, S_IRUGO, \ 157262306a36Sopenharmony_ci show_fan, NULL, SYS_FAN_INPUT, ix-1); \ 157362306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2(fan##ix##_min, S_IRUGO | S_IWUSR, \ 157462306a36Sopenharmony_ci show_fan, set_fan, SYS_FAN_MIN, ix-1); \ 157562306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2(fan##ix##_alarm, S_IRUGO, \ 157662306a36Sopenharmony_ci show_fan, NULL, SYS_FAN_ALARM, ix-1); \ 157762306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2(fan##ix##_type, S_IRUGO | S_IWUSR, \ 157862306a36Sopenharmony_ci show_fan, set_fan, SYS_FAN_TYPE, ix-1) 157962306a36Sopenharmony_ci 158062306a36Sopenharmony_ciSENSOR_DEVICE_ATTR_FAN_1TO4(1); 158162306a36Sopenharmony_ciSENSOR_DEVICE_ATTR_FAN_1TO4(2); 158262306a36Sopenharmony_ciSENSOR_DEVICE_ATTR_FAN_1TO4(3); 158362306a36Sopenharmony_ciSENSOR_DEVICE_ATTR_FAN_1TO4(4); 158462306a36Sopenharmony_ci 158562306a36Sopenharmony_ci/* Fans 5-6 */ 158662306a36Sopenharmony_ci 158762306a36Sopenharmony_ci#define SENSOR_DEVICE_ATTR_FAN_5TO6(ix) \ 158862306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2(fan##ix##_input, S_IRUGO, \ 158962306a36Sopenharmony_ci show_fan, NULL, SYS_FAN_INPUT, ix-1); \ 159062306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2(fan##ix##_min, S_IRUGO | S_IWUSR, \ 159162306a36Sopenharmony_ci show_fan, set_fan, SYS_FAN_MIN, ix-1); \ 159262306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2(fan##ix##_alarm, S_IRUGO, \ 159362306a36Sopenharmony_ci show_fan, NULL, SYS_FAN_ALARM, ix-1); \ 159462306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2(fan##ix##_max, S_IRUGO | S_IWUSR, \ 159562306a36Sopenharmony_ci show_fan, set_fan, SYS_FAN_MAX, ix-1) 159662306a36Sopenharmony_ci 159762306a36Sopenharmony_ciSENSOR_DEVICE_ATTR_FAN_5TO6(5); 159862306a36Sopenharmony_ciSENSOR_DEVICE_ATTR_FAN_5TO6(6); 159962306a36Sopenharmony_ci 160062306a36Sopenharmony_ci/* PWMs 1-3 */ 160162306a36Sopenharmony_ci 160262306a36Sopenharmony_ci#define SENSOR_DEVICE_ATTR_PWM_1TO3(ix) \ 160362306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2(pwm##ix, S_IRUGO, \ 160462306a36Sopenharmony_ci show_pwm, set_pwm, SYS_PWM, ix-1); \ 160562306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2(pwm##ix##_freq, S_IRUGO, \ 160662306a36Sopenharmony_ci show_pwm, set_pwm, SYS_PWM_FREQ, ix-1); \ 160762306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2(pwm##ix##_enable, S_IRUGO, \ 160862306a36Sopenharmony_ci show_pwm, set_pwm, SYS_PWM_ENABLE, ix-1); \ 160962306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2(pwm##ix##_ramp_rate, S_IRUGO, \ 161062306a36Sopenharmony_ci show_pwm, set_pwm, SYS_PWM_RAMP_RATE, ix-1); \ 161162306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2(pwm##ix##_auto_channels_zone, S_IRUGO, \ 161262306a36Sopenharmony_ci show_pwm, set_pwm, SYS_PWM_AUTO_CHANNELS_ZONE, ix-1); \ 161362306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2(pwm##ix##_auto_pwm_min, S_IRUGO, \ 161462306a36Sopenharmony_ci show_pwm, set_pwm, SYS_PWM_AUTO_PWM_MIN, ix-1); \ 161562306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2(pwm##ix##_auto_point1_pwm, S_IRUGO, \ 161662306a36Sopenharmony_ci show_pwm, set_pwm, SYS_PWM_AUTO_POINT1_PWM, ix-1); \ 161762306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2(pwm##ix##_auto_point2_pwm, S_IRUGO, \ 161862306a36Sopenharmony_ci show_pwm, NULL, SYS_PWM_AUTO_POINT2_PWM, ix-1) 161962306a36Sopenharmony_ci 162062306a36Sopenharmony_ciSENSOR_DEVICE_ATTR_PWM_1TO3(1); 162162306a36Sopenharmony_ciSENSOR_DEVICE_ATTR_PWM_1TO3(2); 162262306a36Sopenharmony_ciSENSOR_DEVICE_ATTR_PWM_1TO3(3); 162362306a36Sopenharmony_ci 162462306a36Sopenharmony_ci/* PWMs 5-6 */ 162562306a36Sopenharmony_ci 162662306a36Sopenharmony_ci#define SENSOR_DEVICE_ATTR_PWM_5TO6(ix) \ 162762306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2(pwm##ix, S_IRUGO, \ 162862306a36Sopenharmony_ci show_pwm, set_pwm, SYS_PWM, ix-1); \ 162962306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2(pwm##ix##_freq, S_IRUGO, \ 163062306a36Sopenharmony_ci show_pwm, set_pwm, SYS_PWM_FREQ, ix-1); \ 163162306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2(pwm##ix##_enable, S_IRUGO, \ 163262306a36Sopenharmony_ci show_pwm, NULL, SYS_PWM_ENABLE, ix-1) 163362306a36Sopenharmony_ci 163462306a36Sopenharmony_ciSENSOR_DEVICE_ATTR_PWM_5TO6(5); 163562306a36Sopenharmony_ciSENSOR_DEVICE_ATTR_PWM_5TO6(6); 163662306a36Sopenharmony_ci 163762306a36Sopenharmony_ci/* Misc */ 163862306a36Sopenharmony_ci 163962306a36Sopenharmony_cistatic DEVICE_ATTR_RW(vrm); 164062306a36Sopenharmony_cistatic DEVICE_ATTR_RO(cpu0_vid); 164162306a36Sopenharmony_cistatic DEVICE_ATTR_RO(name); /* for ISA devices */ 164262306a36Sopenharmony_ci 164362306a36Sopenharmony_ci/* 164462306a36Sopenharmony_ci * This struct holds all the attributes that are always present and need to be 164562306a36Sopenharmony_ci * created unconditionally. The attributes that need modification of their 164662306a36Sopenharmony_ci * permissions are created read-only and write permissions are added or removed 164762306a36Sopenharmony_ci * on the fly when required 164862306a36Sopenharmony_ci */ 164962306a36Sopenharmony_cistatic struct attribute *dme1737_attr[] = { 165062306a36Sopenharmony_ci /* Voltages */ 165162306a36Sopenharmony_ci &sensor_dev_attr_in0_input.dev_attr.attr, 165262306a36Sopenharmony_ci &sensor_dev_attr_in0_min.dev_attr.attr, 165362306a36Sopenharmony_ci &sensor_dev_attr_in0_max.dev_attr.attr, 165462306a36Sopenharmony_ci &sensor_dev_attr_in0_alarm.dev_attr.attr, 165562306a36Sopenharmony_ci &sensor_dev_attr_in1_input.dev_attr.attr, 165662306a36Sopenharmony_ci &sensor_dev_attr_in1_min.dev_attr.attr, 165762306a36Sopenharmony_ci &sensor_dev_attr_in1_max.dev_attr.attr, 165862306a36Sopenharmony_ci &sensor_dev_attr_in1_alarm.dev_attr.attr, 165962306a36Sopenharmony_ci &sensor_dev_attr_in2_input.dev_attr.attr, 166062306a36Sopenharmony_ci &sensor_dev_attr_in2_min.dev_attr.attr, 166162306a36Sopenharmony_ci &sensor_dev_attr_in2_max.dev_attr.attr, 166262306a36Sopenharmony_ci &sensor_dev_attr_in2_alarm.dev_attr.attr, 166362306a36Sopenharmony_ci &sensor_dev_attr_in3_input.dev_attr.attr, 166462306a36Sopenharmony_ci &sensor_dev_attr_in3_min.dev_attr.attr, 166562306a36Sopenharmony_ci &sensor_dev_attr_in3_max.dev_attr.attr, 166662306a36Sopenharmony_ci &sensor_dev_attr_in3_alarm.dev_attr.attr, 166762306a36Sopenharmony_ci &sensor_dev_attr_in4_input.dev_attr.attr, 166862306a36Sopenharmony_ci &sensor_dev_attr_in4_min.dev_attr.attr, 166962306a36Sopenharmony_ci &sensor_dev_attr_in4_max.dev_attr.attr, 167062306a36Sopenharmony_ci &sensor_dev_attr_in4_alarm.dev_attr.attr, 167162306a36Sopenharmony_ci &sensor_dev_attr_in5_input.dev_attr.attr, 167262306a36Sopenharmony_ci &sensor_dev_attr_in5_min.dev_attr.attr, 167362306a36Sopenharmony_ci &sensor_dev_attr_in5_max.dev_attr.attr, 167462306a36Sopenharmony_ci &sensor_dev_attr_in5_alarm.dev_attr.attr, 167562306a36Sopenharmony_ci &sensor_dev_attr_in6_input.dev_attr.attr, 167662306a36Sopenharmony_ci &sensor_dev_attr_in6_min.dev_attr.attr, 167762306a36Sopenharmony_ci &sensor_dev_attr_in6_max.dev_attr.attr, 167862306a36Sopenharmony_ci &sensor_dev_attr_in6_alarm.dev_attr.attr, 167962306a36Sopenharmony_ci /* Temperatures */ 168062306a36Sopenharmony_ci &sensor_dev_attr_temp1_input.dev_attr.attr, 168162306a36Sopenharmony_ci &sensor_dev_attr_temp1_min.dev_attr.attr, 168262306a36Sopenharmony_ci &sensor_dev_attr_temp1_max.dev_attr.attr, 168362306a36Sopenharmony_ci &sensor_dev_attr_temp1_alarm.dev_attr.attr, 168462306a36Sopenharmony_ci &sensor_dev_attr_temp1_fault.dev_attr.attr, 168562306a36Sopenharmony_ci &sensor_dev_attr_temp2_input.dev_attr.attr, 168662306a36Sopenharmony_ci &sensor_dev_attr_temp2_min.dev_attr.attr, 168762306a36Sopenharmony_ci &sensor_dev_attr_temp2_max.dev_attr.attr, 168862306a36Sopenharmony_ci &sensor_dev_attr_temp2_alarm.dev_attr.attr, 168962306a36Sopenharmony_ci &sensor_dev_attr_temp2_fault.dev_attr.attr, 169062306a36Sopenharmony_ci &sensor_dev_attr_temp3_input.dev_attr.attr, 169162306a36Sopenharmony_ci &sensor_dev_attr_temp3_min.dev_attr.attr, 169262306a36Sopenharmony_ci &sensor_dev_attr_temp3_max.dev_attr.attr, 169362306a36Sopenharmony_ci &sensor_dev_attr_temp3_alarm.dev_attr.attr, 169462306a36Sopenharmony_ci &sensor_dev_attr_temp3_fault.dev_attr.attr, 169562306a36Sopenharmony_ci /* Zones */ 169662306a36Sopenharmony_ci &sensor_dev_attr_zone1_auto_point1_temp.dev_attr.attr, 169762306a36Sopenharmony_ci &sensor_dev_attr_zone1_auto_point2_temp.dev_attr.attr, 169862306a36Sopenharmony_ci &sensor_dev_attr_zone1_auto_point3_temp.dev_attr.attr, 169962306a36Sopenharmony_ci &sensor_dev_attr_zone1_auto_channels_temp.dev_attr.attr, 170062306a36Sopenharmony_ci &sensor_dev_attr_zone2_auto_point1_temp.dev_attr.attr, 170162306a36Sopenharmony_ci &sensor_dev_attr_zone2_auto_point2_temp.dev_attr.attr, 170262306a36Sopenharmony_ci &sensor_dev_attr_zone2_auto_point3_temp.dev_attr.attr, 170362306a36Sopenharmony_ci &sensor_dev_attr_zone2_auto_channels_temp.dev_attr.attr, 170462306a36Sopenharmony_ci NULL 170562306a36Sopenharmony_ci}; 170662306a36Sopenharmony_ci 170762306a36Sopenharmony_cistatic const struct attribute_group dme1737_group = { 170862306a36Sopenharmony_ci .attrs = dme1737_attr, 170962306a36Sopenharmony_ci}; 171062306a36Sopenharmony_ci 171162306a36Sopenharmony_ci/* 171262306a36Sopenharmony_ci * The following struct holds temp offset attributes, which are not available 171362306a36Sopenharmony_ci * in all chips. The following chips support them: 171462306a36Sopenharmony_ci * DME1737, SCH311x 171562306a36Sopenharmony_ci */ 171662306a36Sopenharmony_cistatic struct attribute *dme1737_temp_offset_attr[] = { 171762306a36Sopenharmony_ci &sensor_dev_attr_temp1_offset.dev_attr.attr, 171862306a36Sopenharmony_ci &sensor_dev_attr_temp2_offset.dev_attr.attr, 171962306a36Sopenharmony_ci &sensor_dev_attr_temp3_offset.dev_attr.attr, 172062306a36Sopenharmony_ci NULL 172162306a36Sopenharmony_ci}; 172262306a36Sopenharmony_ci 172362306a36Sopenharmony_cistatic const struct attribute_group dme1737_temp_offset_group = { 172462306a36Sopenharmony_ci .attrs = dme1737_temp_offset_attr, 172562306a36Sopenharmony_ci}; 172662306a36Sopenharmony_ci 172762306a36Sopenharmony_ci/* 172862306a36Sopenharmony_ci * The following struct holds VID related attributes, which are not available 172962306a36Sopenharmony_ci * in all chips. The following chips support them: 173062306a36Sopenharmony_ci * DME1737 173162306a36Sopenharmony_ci */ 173262306a36Sopenharmony_cistatic struct attribute *dme1737_vid_attr[] = { 173362306a36Sopenharmony_ci &dev_attr_vrm.attr, 173462306a36Sopenharmony_ci &dev_attr_cpu0_vid.attr, 173562306a36Sopenharmony_ci NULL 173662306a36Sopenharmony_ci}; 173762306a36Sopenharmony_ci 173862306a36Sopenharmony_cistatic const struct attribute_group dme1737_vid_group = { 173962306a36Sopenharmony_ci .attrs = dme1737_vid_attr, 174062306a36Sopenharmony_ci}; 174162306a36Sopenharmony_ci 174262306a36Sopenharmony_ci/* 174362306a36Sopenharmony_ci * The following struct holds temp zone 3 related attributes, which are not 174462306a36Sopenharmony_ci * available in all chips. The following chips support them: 174562306a36Sopenharmony_ci * DME1737, SCH311x, SCH5027 174662306a36Sopenharmony_ci */ 174762306a36Sopenharmony_cistatic struct attribute *dme1737_zone3_attr[] = { 174862306a36Sopenharmony_ci &sensor_dev_attr_zone3_auto_point1_temp.dev_attr.attr, 174962306a36Sopenharmony_ci &sensor_dev_attr_zone3_auto_point2_temp.dev_attr.attr, 175062306a36Sopenharmony_ci &sensor_dev_attr_zone3_auto_point3_temp.dev_attr.attr, 175162306a36Sopenharmony_ci &sensor_dev_attr_zone3_auto_channels_temp.dev_attr.attr, 175262306a36Sopenharmony_ci NULL 175362306a36Sopenharmony_ci}; 175462306a36Sopenharmony_ci 175562306a36Sopenharmony_cistatic const struct attribute_group dme1737_zone3_group = { 175662306a36Sopenharmony_ci .attrs = dme1737_zone3_attr, 175762306a36Sopenharmony_ci}; 175862306a36Sopenharmony_ci 175962306a36Sopenharmony_ci 176062306a36Sopenharmony_ci/* 176162306a36Sopenharmony_ci * The following struct holds temp zone hysteresis related attributes, which 176262306a36Sopenharmony_ci * are not available in all chips. The following chips support them: 176362306a36Sopenharmony_ci * DME1737, SCH311x 176462306a36Sopenharmony_ci */ 176562306a36Sopenharmony_cistatic struct attribute *dme1737_zone_hyst_attr[] = { 176662306a36Sopenharmony_ci &sensor_dev_attr_zone1_auto_point1_temp_hyst.dev_attr.attr, 176762306a36Sopenharmony_ci &sensor_dev_attr_zone2_auto_point1_temp_hyst.dev_attr.attr, 176862306a36Sopenharmony_ci &sensor_dev_attr_zone3_auto_point1_temp_hyst.dev_attr.attr, 176962306a36Sopenharmony_ci NULL 177062306a36Sopenharmony_ci}; 177162306a36Sopenharmony_ci 177262306a36Sopenharmony_cistatic const struct attribute_group dme1737_zone_hyst_group = { 177362306a36Sopenharmony_ci .attrs = dme1737_zone_hyst_attr, 177462306a36Sopenharmony_ci}; 177562306a36Sopenharmony_ci 177662306a36Sopenharmony_ci/* 177762306a36Sopenharmony_ci * The following struct holds voltage in7 related attributes, which 177862306a36Sopenharmony_ci * are not available in all chips. The following chips support them: 177962306a36Sopenharmony_ci * SCH5127 178062306a36Sopenharmony_ci */ 178162306a36Sopenharmony_cistatic struct attribute *dme1737_in7_attr[] = { 178262306a36Sopenharmony_ci &sensor_dev_attr_in7_input.dev_attr.attr, 178362306a36Sopenharmony_ci &sensor_dev_attr_in7_min.dev_attr.attr, 178462306a36Sopenharmony_ci &sensor_dev_attr_in7_max.dev_attr.attr, 178562306a36Sopenharmony_ci &sensor_dev_attr_in7_alarm.dev_attr.attr, 178662306a36Sopenharmony_ci NULL 178762306a36Sopenharmony_ci}; 178862306a36Sopenharmony_ci 178962306a36Sopenharmony_cistatic const struct attribute_group dme1737_in7_group = { 179062306a36Sopenharmony_ci .attrs = dme1737_in7_attr, 179162306a36Sopenharmony_ci}; 179262306a36Sopenharmony_ci 179362306a36Sopenharmony_ci/* 179462306a36Sopenharmony_ci * The following structs hold the PWM attributes, some of which are optional. 179562306a36Sopenharmony_ci * Their creation depends on the chip configuration which is determined during 179662306a36Sopenharmony_ci * module load. 179762306a36Sopenharmony_ci */ 179862306a36Sopenharmony_cistatic struct attribute *dme1737_pwm1_attr[] = { 179962306a36Sopenharmony_ci &sensor_dev_attr_pwm1.dev_attr.attr, 180062306a36Sopenharmony_ci &sensor_dev_attr_pwm1_freq.dev_attr.attr, 180162306a36Sopenharmony_ci &sensor_dev_attr_pwm1_enable.dev_attr.attr, 180262306a36Sopenharmony_ci &sensor_dev_attr_pwm1_ramp_rate.dev_attr.attr, 180362306a36Sopenharmony_ci &sensor_dev_attr_pwm1_auto_channels_zone.dev_attr.attr, 180462306a36Sopenharmony_ci &sensor_dev_attr_pwm1_auto_point1_pwm.dev_attr.attr, 180562306a36Sopenharmony_ci &sensor_dev_attr_pwm1_auto_point2_pwm.dev_attr.attr, 180662306a36Sopenharmony_ci NULL 180762306a36Sopenharmony_ci}; 180862306a36Sopenharmony_cistatic struct attribute *dme1737_pwm2_attr[] = { 180962306a36Sopenharmony_ci &sensor_dev_attr_pwm2.dev_attr.attr, 181062306a36Sopenharmony_ci &sensor_dev_attr_pwm2_freq.dev_attr.attr, 181162306a36Sopenharmony_ci &sensor_dev_attr_pwm2_enable.dev_attr.attr, 181262306a36Sopenharmony_ci &sensor_dev_attr_pwm2_ramp_rate.dev_attr.attr, 181362306a36Sopenharmony_ci &sensor_dev_attr_pwm2_auto_channels_zone.dev_attr.attr, 181462306a36Sopenharmony_ci &sensor_dev_attr_pwm2_auto_point1_pwm.dev_attr.attr, 181562306a36Sopenharmony_ci &sensor_dev_attr_pwm2_auto_point2_pwm.dev_attr.attr, 181662306a36Sopenharmony_ci NULL 181762306a36Sopenharmony_ci}; 181862306a36Sopenharmony_cistatic struct attribute *dme1737_pwm3_attr[] = { 181962306a36Sopenharmony_ci &sensor_dev_attr_pwm3.dev_attr.attr, 182062306a36Sopenharmony_ci &sensor_dev_attr_pwm3_freq.dev_attr.attr, 182162306a36Sopenharmony_ci &sensor_dev_attr_pwm3_enable.dev_attr.attr, 182262306a36Sopenharmony_ci &sensor_dev_attr_pwm3_ramp_rate.dev_attr.attr, 182362306a36Sopenharmony_ci &sensor_dev_attr_pwm3_auto_channels_zone.dev_attr.attr, 182462306a36Sopenharmony_ci &sensor_dev_attr_pwm3_auto_point1_pwm.dev_attr.attr, 182562306a36Sopenharmony_ci &sensor_dev_attr_pwm3_auto_point2_pwm.dev_attr.attr, 182662306a36Sopenharmony_ci NULL 182762306a36Sopenharmony_ci}; 182862306a36Sopenharmony_cistatic struct attribute *dme1737_pwm5_attr[] = { 182962306a36Sopenharmony_ci &sensor_dev_attr_pwm5.dev_attr.attr, 183062306a36Sopenharmony_ci &sensor_dev_attr_pwm5_freq.dev_attr.attr, 183162306a36Sopenharmony_ci &sensor_dev_attr_pwm5_enable.dev_attr.attr, 183262306a36Sopenharmony_ci NULL 183362306a36Sopenharmony_ci}; 183462306a36Sopenharmony_cistatic struct attribute *dme1737_pwm6_attr[] = { 183562306a36Sopenharmony_ci &sensor_dev_attr_pwm6.dev_attr.attr, 183662306a36Sopenharmony_ci &sensor_dev_attr_pwm6_freq.dev_attr.attr, 183762306a36Sopenharmony_ci &sensor_dev_attr_pwm6_enable.dev_attr.attr, 183862306a36Sopenharmony_ci NULL 183962306a36Sopenharmony_ci}; 184062306a36Sopenharmony_ci 184162306a36Sopenharmony_cistatic const struct attribute_group dme1737_pwm_group[] = { 184262306a36Sopenharmony_ci { .attrs = dme1737_pwm1_attr }, 184362306a36Sopenharmony_ci { .attrs = dme1737_pwm2_attr }, 184462306a36Sopenharmony_ci { .attrs = dme1737_pwm3_attr }, 184562306a36Sopenharmony_ci { .attrs = NULL }, 184662306a36Sopenharmony_ci { .attrs = dme1737_pwm5_attr }, 184762306a36Sopenharmony_ci { .attrs = dme1737_pwm6_attr }, 184862306a36Sopenharmony_ci}; 184962306a36Sopenharmony_ci 185062306a36Sopenharmony_ci/* 185162306a36Sopenharmony_ci * The following struct holds auto PWM min attributes, which are not available 185262306a36Sopenharmony_ci * in all chips. Their creation depends on the chip type which is determined 185362306a36Sopenharmony_ci * during module load. 185462306a36Sopenharmony_ci */ 185562306a36Sopenharmony_cistatic struct attribute *dme1737_auto_pwm_min_attr[] = { 185662306a36Sopenharmony_ci &sensor_dev_attr_pwm1_auto_pwm_min.dev_attr.attr, 185762306a36Sopenharmony_ci &sensor_dev_attr_pwm2_auto_pwm_min.dev_attr.attr, 185862306a36Sopenharmony_ci &sensor_dev_attr_pwm3_auto_pwm_min.dev_attr.attr, 185962306a36Sopenharmony_ci}; 186062306a36Sopenharmony_ci 186162306a36Sopenharmony_ci/* 186262306a36Sopenharmony_ci * The following structs hold the fan attributes, some of which are optional. 186362306a36Sopenharmony_ci * Their creation depends on the chip configuration which is determined during 186462306a36Sopenharmony_ci * module load. 186562306a36Sopenharmony_ci */ 186662306a36Sopenharmony_cistatic struct attribute *dme1737_fan1_attr[] = { 186762306a36Sopenharmony_ci &sensor_dev_attr_fan1_input.dev_attr.attr, 186862306a36Sopenharmony_ci &sensor_dev_attr_fan1_min.dev_attr.attr, 186962306a36Sopenharmony_ci &sensor_dev_attr_fan1_alarm.dev_attr.attr, 187062306a36Sopenharmony_ci &sensor_dev_attr_fan1_type.dev_attr.attr, 187162306a36Sopenharmony_ci NULL 187262306a36Sopenharmony_ci}; 187362306a36Sopenharmony_cistatic struct attribute *dme1737_fan2_attr[] = { 187462306a36Sopenharmony_ci &sensor_dev_attr_fan2_input.dev_attr.attr, 187562306a36Sopenharmony_ci &sensor_dev_attr_fan2_min.dev_attr.attr, 187662306a36Sopenharmony_ci &sensor_dev_attr_fan2_alarm.dev_attr.attr, 187762306a36Sopenharmony_ci &sensor_dev_attr_fan2_type.dev_attr.attr, 187862306a36Sopenharmony_ci NULL 187962306a36Sopenharmony_ci}; 188062306a36Sopenharmony_cistatic struct attribute *dme1737_fan3_attr[] = { 188162306a36Sopenharmony_ci &sensor_dev_attr_fan3_input.dev_attr.attr, 188262306a36Sopenharmony_ci &sensor_dev_attr_fan3_min.dev_attr.attr, 188362306a36Sopenharmony_ci &sensor_dev_attr_fan3_alarm.dev_attr.attr, 188462306a36Sopenharmony_ci &sensor_dev_attr_fan3_type.dev_attr.attr, 188562306a36Sopenharmony_ci NULL 188662306a36Sopenharmony_ci}; 188762306a36Sopenharmony_cistatic struct attribute *dme1737_fan4_attr[] = { 188862306a36Sopenharmony_ci &sensor_dev_attr_fan4_input.dev_attr.attr, 188962306a36Sopenharmony_ci &sensor_dev_attr_fan4_min.dev_attr.attr, 189062306a36Sopenharmony_ci &sensor_dev_attr_fan4_alarm.dev_attr.attr, 189162306a36Sopenharmony_ci &sensor_dev_attr_fan4_type.dev_attr.attr, 189262306a36Sopenharmony_ci NULL 189362306a36Sopenharmony_ci}; 189462306a36Sopenharmony_cistatic struct attribute *dme1737_fan5_attr[] = { 189562306a36Sopenharmony_ci &sensor_dev_attr_fan5_input.dev_attr.attr, 189662306a36Sopenharmony_ci &sensor_dev_attr_fan5_min.dev_attr.attr, 189762306a36Sopenharmony_ci &sensor_dev_attr_fan5_alarm.dev_attr.attr, 189862306a36Sopenharmony_ci &sensor_dev_attr_fan5_max.dev_attr.attr, 189962306a36Sopenharmony_ci NULL 190062306a36Sopenharmony_ci}; 190162306a36Sopenharmony_cistatic struct attribute *dme1737_fan6_attr[] = { 190262306a36Sopenharmony_ci &sensor_dev_attr_fan6_input.dev_attr.attr, 190362306a36Sopenharmony_ci &sensor_dev_attr_fan6_min.dev_attr.attr, 190462306a36Sopenharmony_ci &sensor_dev_attr_fan6_alarm.dev_attr.attr, 190562306a36Sopenharmony_ci &sensor_dev_attr_fan6_max.dev_attr.attr, 190662306a36Sopenharmony_ci NULL 190762306a36Sopenharmony_ci}; 190862306a36Sopenharmony_ci 190962306a36Sopenharmony_cistatic const struct attribute_group dme1737_fan_group[] = { 191062306a36Sopenharmony_ci { .attrs = dme1737_fan1_attr }, 191162306a36Sopenharmony_ci { .attrs = dme1737_fan2_attr }, 191262306a36Sopenharmony_ci { .attrs = dme1737_fan3_attr }, 191362306a36Sopenharmony_ci { .attrs = dme1737_fan4_attr }, 191462306a36Sopenharmony_ci { .attrs = dme1737_fan5_attr }, 191562306a36Sopenharmony_ci { .attrs = dme1737_fan6_attr }, 191662306a36Sopenharmony_ci}; 191762306a36Sopenharmony_ci 191862306a36Sopenharmony_ci/* 191962306a36Sopenharmony_ci * The permissions of the following zone attributes are changed to read- 192062306a36Sopenharmony_ci * writeable if the chip is *not* locked. Otherwise they stay read-only. 192162306a36Sopenharmony_ci */ 192262306a36Sopenharmony_cistatic struct attribute *dme1737_zone_chmod_attr[] = { 192362306a36Sopenharmony_ci &sensor_dev_attr_zone1_auto_point1_temp.dev_attr.attr, 192462306a36Sopenharmony_ci &sensor_dev_attr_zone1_auto_point2_temp.dev_attr.attr, 192562306a36Sopenharmony_ci &sensor_dev_attr_zone1_auto_point3_temp.dev_attr.attr, 192662306a36Sopenharmony_ci &sensor_dev_attr_zone2_auto_point1_temp.dev_attr.attr, 192762306a36Sopenharmony_ci &sensor_dev_attr_zone2_auto_point2_temp.dev_attr.attr, 192862306a36Sopenharmony_ci &sensor_dev_attr_zone2_auto_point3_temp.dev_attr.attr, 192962306a36Sopenharmony_ci NULL 193062306a36Sopenharmony_ci}; 193162306a36Sopenharmony_ci 193262306a36Sopenharmony_cistatic const struct attribute_group dme1737_zone_chmod_group = { 193362306a36Sopenharmony_ci .attrs = dme1737_zone_chmod_attr, 193462306a36Sopenharmony_ci}; 193562306a36Sopenharmony_ci 193662306a36Sopenharmony_ci 193762306a36Sopenharmony_ci/* 193862306a36Sopenharmony_ci * The permissions of the following zone 3 attributes are changed to read- 193962306a36Sopenharmony_ci * writeable if the chip is *not* locked. Otherwise they stay read-only. 194062306a36Sopenharmony_ci */ 194162306a36Sopenharmony_cistatic struct attribute *dme1737_zone3_chmod_attr[] = { 194262306a36Sopenharmony_ci &sensor_dev_attr_zone3_auto_point1_temp.dev_attr.attr, 194362306a36Sopenharmony_ci &sensor_dev_attr_zone3_auto_point2_temp.dev_attr.attr, 194462306a36Sopenharmony_ci &sensor_dev_attr_zone3_auto_point3_temp.dev_attr.attr, 194562306a36Sopenharmony_ci NULL 194662306a36Sopenharmony_ci}; 194762306a36Sopenharmony_ci 194862306a36Sopenharmony_cistatic const struct attribute_group dme1737_zone3_chmod_group = { 194962306a36Sopenharmony_ci .attrs = dme1737_zone3_chmod_attr, 195062306a36Sopenharmony_ci}; 195162306a36Sopenharmony_ci 195262306a36Sopenharmony_ci/* 195362306a36Sopenharmony_ci * The permissions of the following PWM attributes are changed to read- 195462306a36Sopenharmony_ci * writeable if the chip is *not* locked and the respective PWM is available. 195562306a36Sopenharmony_ci * Otherwise they stay read-only. 195662306a36Sopenharmony_ci */ 195762306a36Sopenharmony_cistatic struct attribute *dme1737_pwm1_chmod_attr[] = { 195862306a36Sopenharmony_ci &sensor_dev_attr_pwm1_freq.dev_attr.attr, 195962306a36Sopenharmony_ci &sensor_dev_attr_pwm1_enable.dev_attr.attr, 196062306a36Sopenharmony_ci &sensor_dev_attr_pwm1_ramp_rate.dev_attr.attr, 196162306a36Sopenharmony_ci &sensor_dev_attr_pwm1_auto_channels_zone.dev_attr.attr, 196262306a36Sopenharmony_ci &sensor_dev_attr_pwm1_auto_point1_pwm.dev_attr.attr, 196362306a36Sopenharmony_ci NULL 196462306a36Sopenharmony_ci}; 196562306a36Sopenharmony_cistatic struct attribute *dme1737_pwm2_chmod_attr[] = { 196662306a36Sopenharmony_ci &sensor_dev_attr_pwm2_freq.dev_attr.attr, 196762306a36Sopenharmony_ci &sensor_dev_attr_pwm2_enable.dev_attr.attr, 196862306a36Sopenharmony_ci &sensor_dev_attr_pwm2_ramp_rate.dev_attr.attr, 196962306a36Sopenharmony_ci &sensor_dev_attr_pwm2_auto_channels_zone.dev_attr.attr, 197062306a36Sopenharmony_ci &sensor_dev_attr_pwm2_auto_point1_pwm.dev_attr.attr, 197162306a36Sopenharmony_ci NULL 197262306a36Sopenharmony_ci}; 197362306a36Sopenharmony_cistatic struct attribute *dme1737_pwm3_chmod_attr[] = { 197462306a36Sopenharmony_ci &sensor_dev_attr_pwm3_freq.dev_attr.attr, 197562306a36Sopenharmony_ci &sensor_dev_attr_pwm3_enable.dev_attr.attr, 197662306a36Sopenharmony_ci &sensor_dev_attr_pwm3_ramp_rate.dev_attr.attr, 197762306a36Sopenharmony_ci &sensor_dev_attr_pwm3_auto_channels_zone.dev_attr.attr, 197862306a36Sopenharmony_ci &sensor_dev_attr_pwm3_auto_point1_pwm.dev_attr.attr, 197962306a36Sopenharmony_ci NULL 198062306a36Sopenharmony_ci}; 198162306a36Sopenharmony_cistatic struct attribute *dme1737_pwm5_chmod_attr[] = { 198262306a36Sopenharmony_ci &sensor_dev_attr_pwm5.dev_attr.attr, 198362306a36Sopenharmony_ci &sensor_dev_attr_pwm5_freq.dev_attr.attr, 198462306a36Sopenharmony_ci NULL 198562306a36Sopenharmony_ci}; 198662306a36Sopenharmony_cistatic struct attribute *dme1737_pwm6_chmod_attr[] = { 198762306a36Sopenharmony_ci &sensor_dev_attr_pwm6.dev_attr.attr, 198862306a36Sopenharmony_ci &sensor_dev_attr_pwm6_freq.dev_attr.attr, 198962306a36Sopenharmony_ci NULL 199062306a36Sopenharmony_ci}; 199162306a36Sopenharmony_ci 199262306a36Sopenharmony_cistatic const struct attribute_group dme1737_pwm_chmod_group[] = { 199362306a36Sopenharmony_ci { .attrs = dme1737_pwm1_chmod_attr }, 199462306a36Sopenharmony_ci { .attrs = dme1737_pwm2_chmod_attr }, 199562306a36Sopenharmony_ci { .attrs = dme1737_pwm3_chmod_attr }, 199662306a36Sopenharmony_ci { .attrs = NULL }, 199762306a36Sopenharmony_ci { .attrs = dme1737_pwm5_chmod_attr }, 199862306a36Sopenharmony_ci { .attrs = dme1737_pwm6_chmod_attr }, 199962306a36Sopenharmony_ci}; 200062306a36Sopenharmony_ci 200162306a36Sopenharmony_ci/* 200262306a36Sopenharmony_ci * Pwm[1-3] are read-writeable if the associated pwm is in manual mode and the 200362306a36Sopenharmony_ci * chip is not locked. Otherwise they are read-only. 200462306a36Sopenharmony_ci */ 200562306a36Sopenharmony_cistatic struct attribute *dme1737_pwm_chmod_attr[] = { 200662306a36Sopenharmony_ci &sensor_dev_attr_pwm1.dev_attr.attr, 200762306a36Sopenharmony_ci &sensor_dev_attr_pwm2.dev_attr.attr, 200862306a36Sopenharmony_ci &sensor_dev_attr_pwm3.dev_attr.attr, 200962306a36Sopenharmony_ci}; 201062306a36Sopenharmony_ci 201162306a36Sopenharmony_ci/* --------------------------------------------------------------------- 201262306a36Sopenharmony_ci * Super-IO functions 201362306a36Sopenharmony_ci * --------------------------------------------------------------------- */ 201462306a36Sopenharmony_ci 201562306a36Sopenharmony_cistatic inline void dme1737_sio_enter(int sio_cip) 201662306a36Sopenharmony_ci{ 201762306a36Sopenharmony_ci outb(0x55, sio_cip); 201862306a36Sopenharmony_ci} 201962306a36Sopenharmony_ci 202062306a36Sopenharmony_cistatic inline void dme1737_sio_exit(int sio_cip) 202162306a36Sopenharmony_ci{ 202262306a36Sopenharmony_ci outb(0xaa, sio_cip); 202362306a36Sopenharmony_ci} 202462306a36Sopenharmony_ci 202562306a36Sopenharmony_cistatic inline int dme1737_sio_inb(int sio_cip, int reg) 202662306a36Sopenharmony_ci{ 202762306a36Sopenharmony_ci outb(reg, sio_cip); 202862306a36Sopenharmony_ci return inb(sio_cip + 1); 202962306a36Sopenharmony_ci} 203062306a36Sopenharmony_ci 203162306a36Sopenharmony_cistatic inline void dme1737_sio_outb(int sio_cip, int reg, int val) 203262306a36Sopenharmony_ci{ 203362306a36Sopenharmony_ci outb(reg, sio_cip); 203462306a36Sopenharmony_ci outb(val, sio_cip + 1); 203562306a36Sopenharmony_ci} 203662306a36Sopenharmony_ci 203762306a36Sopenharmony_ci/* --------------------------------------------------------------------- 203862306a36Sopenharmony_ci * Device initialization 203962306a36Sopenharmony_ci * --------------------------------------------------------------------- */ 204062306a36Sopenharmony_ci 204162306a36Sopenharmony_cistatic int dme1737_i2c_get_features(int, struct dme1737_data*); 204262306a36Sopenharmony_ci 204362306a36Sopenharmony_cistatic void dme1737_chmod_file(struct device *dev, 204462306a36Sopenharmony_ci struct attribute *attr, umode_t mode) 204562306a36Sopenharmony_ci{ 204662306a36Sopenharmony_ci if (sysfs_chmod_file(&dev->kobj, attr, mode)) { 204762306a36Sopenharmony_ci dev_warn(dev, "Failed to change permissions of %s.\n", 204862306a36Sopenharmony_ci attr->name); 204962306a36Sopenharmony_ci } 205062306a36Sopenharmony_ci} 205162306a36Sopenharmony_ci 205262306a36Sopenharmony_cistatic void dme1737_chmod_group(struct device *dev, 205362306a36Sopenharmony_ci const struct attribute_group *group, 205462306a36Sopenharmony_ci umode_t mode) 205562306a36Sopenharmony_ci{ 205662306a36Sopenharmony_ci struct attribute **attr; 205762306a36Sopenharmony_ci 205862306a36Sopenharmony_ci for (attr = group->attrs; *attr; attr++) 205962306a36Sopenharmony_ci dme1737_chmod_file(dev, *attr, mode); 206062306a36Sopenharmony_ci} 206162306a36Sopenharmony_ci 206262306a36Sopenharmony_cistatic void dme1737_remove_files(struct device *dev) 206362306a36Sopenharmony_ci{ 206462306a36Sopenharmony_ci struct dme1737_data *data = dev_get_drvdata(dev); 206562306a36Sopenharmony_ci int ix; 206662306a36Sopenharmony_ci 206762306a36Sopenharmony_ci for (ix = 0; ix < ARRAY_SIZE(dme1737_fan_group); ix++) { 206862306a36Sopenharmony_ci if (data->has_features & HAS_FAN(ix)) { 206962306a36Sopenharmony_ci sysfs_remove_group(&dev->kobj, 207062306a36Sopenharmony_ci &dme1737_fan_group[ix]); 207162306a36Sopenharmony_ci } 207262306a36Sopenharmony_ci } 207362306a36Sopenharmony_ci 207462306a36Sopenharmony_ci for (ix = 0; ix < ARRAY_SIZE(dme1737_pwm_group); ix++) { 207562306a36Sopenharmony_ci if (data->has_features & HAS_PWM(ix)) { 207662306a36Sopenharmony_ci sysfs_remove_group(&dev->kobj, 207762306a36Sopenharmony_ci &dme1737_pwm_group[ix]); 207862306a36Sopenharmony_ci if ((data->has_features & HAS_PWM_MIN) && ix < 3) { 207962306a36Sopenharmony_ci sysfs_remove_file(&dev->kobj, 208062306a36Sopenharmony_ci dme1737_auto_pwm_min_attr[ix]); 208162306a36Sopenharmony_ci } 208262306a36Sopenharmony_ci } 208362306a36Sopenharmony_ci } 208462306a36Sopenharmony_ci 208562306a36Sopenharmony_ci if (data->has_features & HAS_TEMP_OFFSET) 208662306a36Sopenharmony_ci sysfs_remove_group(&dev->kobj, &dme1737_temp_offset_group); 208762306a36Sopenharmony_ci if (data->has_features & HAS_VID) 208862306a36Sopenharmony_ci sysfs_remove_group(&dev->kobj, &dme1737_vid_group); 208962306a36Sopenharmony_ci if (data->has_features & HAS_ZONE3) 209062306a36Sopenharmony_ci sysfs_remove_group(&dev->kobj, &dme1737_zone3_group); 209162306a36Sopenharmony_ci if (data->has_features & HAS_ZONE_HYST) 209262306a36Sopenharmony_ci sysfs_remove_group(&dev->kobj, &dme1737_zone_hyst_group); 209362306a36Sopenharmony_ci if (data->has_features & HAS_IN7) 209462306a36Sopenharmony_ci sysfs_remove_group(&dev->kobj, &dme1737_in7_group); 209562306a36Sopenharmony_ci sysfs_remove_group(&dev->kobj, &dme1737_group); 209662306a36Sopenharmony_ci 209762306a36Sopenharmony_ci if (!data->client) 209862306a36Sopenharmony_ci sysfs_remove_file(&dev->kobj, &dev_attr_name.attr); 209962306a36Sopenharmony_ci} 210062306a36Sopenharmony_ci 210162306a36Sopenharmony_cistatic int dme1737_create_files(struct device *dev) 210262306a36Sopenharmony_ci{ 210362306a36Sopenharmony_ci struct dme1737_data *data = dev_get_drvdata(dev); 210462306a36Sopenharmony_ci int err, ix; 210562306a36Sopenharmony_ci 210662306a36Sopenharmony_ci /* Create a name attribute for ISA devices */ 210762306a36Sopenharmony_ci if (!data->client) { 210862306a36Sopenharmony_ci err = sysfs_create_file(&dev->kobj, &dev_attr_name.attr); 210962306a36Sopenharmony_ci if (err) 211062306a36Sopenharmony_ci goto exit; 211162306a36Sopenharmony_ci } 211262306a36Sopenharmony_ci 211362306a36Sopenharmony_ci /* Create standard sysfs attributes */ 211462306a36Sopenharmony_ci err = sysfs_create_group(&dev->kobj, &dme1737_group); 211562306a36Sopenharmony_ci if (err) 211662306a36Sopenharmony_ci goto exit_remove; 211762306a36Sopenharmony_ci 211862306a36Sopenharmony_ci /* Create chip-dependent sysfs attributes */ 211962306a36Sopenharmony_ci if (data->has_features & HAS_TEMP_OFFSET) { 212062306a36Sopenharmony_ci err = sysfs_create_group(&dev->kobj, 212162306a36Sopenharmony_ci &dme1737_temp_offset_group); 212262306a36Sopenharmony_ci if (err) 212362306a36Sopenharmony_ci goto exit_remove; 212462306a36Sopenharmony_ci } 212562306a36Sopenharmony_ci if (data->has_features & HAS_VID) { 212662306a36Sopenharmony_ci err = sysfs_create_group(&dev->kobj, &dme1737_vid_group); 212762306a36Sopenharmony_ci if (err) 212862306a36Sopenharmony_ci goto exit_remove; 212962306a36Sopenharmony_ci } 213062306a36Sopenharmony_ci if (data->has_features & HAS_ZONE3) { 213162306a36Sopenharmony_ci err = sysfs_create_group(&dev->kobj, &dme1737_zone3_group); 213262306a36Sopenharmony_ci if (err) 213362306a36Sopenharmony_ci goto exit_remove; 213462306a36Sopenharmony_ci } 213562306a36Sopenharmony_ci if (data->has_features & HAS_ZONE_HYST) { 213662306a36Sopenharmony_ci err = sysfs_create_group(&dev->kobj, &dme1737_zone_hyst_group); 213762306a36Sopenharmony_ci if (err) 213862306a36Sopenharmony_ci goto exit_remove; 213962306a36Sopenharmony_ci } 214062306a36Sopenharmony_ci if (data->has_features & HAS_IN7) { 214162306a36Sopenharmony_ci err = sysfs_create_group(&dev->kobj, &dme1737_in7_group); 214262306a36Sopenharmony_ci if (err) 214362306a36Sopenharmony_ci goto exit_remove; 214462306a36Sopenharmony_ci } 214562306a36Sopenharmony_ci 214662306a36Sopenharmony_ci /* Create fan sysfs attributes */ 214762306a36Sopenharmony_ci for (ix = 0; ix < ARRAY_SIZE(dme1737_fan_group); ix++) { 214862306a36Sopenharmony_ci if (data->has_features & HAS_FAN(ix)) { 214962306a36Sopenharmony_ci err = sysfs_create_group(&dev->kobj, 215062306a36Sopenharmony_ci &dme1737_fan_group[ix]); 215162306a36Sopenharmony_ci if (err) 215262306a36Sopenharmony_ci goto exit_remove; 215362306a36Sopenharmony_ci } 215462306a36Sopenharmony_ci } 215562306a36Sopenharmony_ci 215662306a36Sopenharmony_ci /* Create PWM sysfs attributes */ 215762306a36Sopenharmony_ci for (ix = 0; ix < ARRAY_SIZE(dme1737_pwm_group); ix++) { 215862306a36Sopenharmony_ci if (data->has_features & HAS_PWM(ix)) { 215962306a36Sopenharmony_ci err = sysfs_create_group(&dev->kobj, 216062306a36Sopenharmony_ci &dme1737_pwm_group[ix]); 216162306a36Sopenharmony_ci if (err) 216262306a36Sopenharmony_ci goto exit_remove; 216362306a36Sopenharmony_ci if ((data->has_features & HAS_PWM_MIN) && (ix < 3)) { 216462306a36Sopenharmony_ci err = sysfs_create_file(&dev->kobj, 216562306a36Sopenharmony_ci dme1737_auto_pwm_min_attr[ix]); 216662306a36Sopenharmony_ci if (err) 216762306a36Sopenharmony_ci goto exit_remove; 216862306a36Sopenharmony_ci } 216962306a36Sopenharmony_ci } 217062306a36Sopenharmony_ci } 217162306a36Sopenharmony_ci 217262306a36Sopenharmony_ci /* 217362306a36Sopenharmony_ci * Inform if the device is locked. Otherwise change the permissions of 217462306a36Sopenharmony_ci * selected attributes from read-only to read-writeable. 217562306a36Sopenharmony_ci */ 217662306a36Sopenharmony_ci if (data->config & 0x02) { 217762306a36Sopenharmony_ci dev_info(dev, 217862306a36Sopenharmony_ci "Device is locked. Some attributes will be read-only.\n"); 217962306a36Sopenharmony_ci } else { 218062306a36Sopenharmony_ci /* Change permissions of zone sysfs attributes */ 218162306a36Sopenharmony_ci dme1737_chmod_group(dev, &dme1737_zone_chmod_group, 218262306a36Sopenharmony_ci S_IRUGO | S_IWUSR); 218362306a36Sopenharmony_ci 218462306a36Sopenharmony_ci /* Change permissions of chip-dependent sysfs attributes */ 218562306a36Sopenharmony_ci if (data->has_features & HAS_TEMP_OFFSET) { 218662306a36Sopenharmony_ci dme1737_chmod_group(dev, &dme1737_temp_offset_group, 218762306a36Sopenharmony_ci S_IRUGO | S_IWUSR); 218862306a36Sopenharmony_ci } 218962306a36Sopenharmony_ci if (data->has_features & HAS_ZONE3) { 219062306a36Sopenharmony_ci dme1737_chmod_group(dev, &dme1737_zone3_chmod_group, 219162306a36Sopenharmony_ci S_IRUGO | S_IWUSR); 219262306a36Sopenharmony_ci } 219362306a36Sopenharmony_ci if (data->has_features & HAS_ZONE_HYST) { 219462306a36Sopenharmony_ci dme1737_chmod_group(dev, &dme1737_zone_hyst_group, 219562306a36Sopenharmony_ci S_IRUGO | S_IWUSR); 219662306a36Sopenharmony_ci } 219762306a36Sopenharmony_ci 219862306a36Sopenharmony_ci /* Change permissions of PWM sysfs attributes */ 219962306a36Sopenharmony_ci for (ix = 0; ix < ARRAY_SIZE(dme1737_pwm_chmod_group); ix++) { 220062306a36Sopenharmony_ci if (data->has_features & HAS_PWM(ix)) { 220162306a36Sopenharmony_ci dme1737_chmod_group(dev, 220262306a36Sopenharmony_ci &dme1737_pwm_chmod_group[ix], 220362306a36Sopenharmony_ci S_IRUGO | S_IWUSR); 220462306a36Sopenharmony_ci if ((data->has_features & HAS_PWM_MIN) && 220562306a36Sopenharmony_ci ix < 3) { 220662306a36Sopenharmony_ci dme1737_chmod_file(dev, 220762306a36Sopenharmony_ci dme1737_auto_pwm_min_attr[ix], 220862306a36Sopenharmony_ci S_IRUGO | S_IWUSR); 220962306a36Sopenharmony_ci } 221062306a36Sopenharmony_ci } 221162306a36Sopenharmony_ci } 221262306a36Sopenharmony_ci 221362306a36Sopenharmony_ci /* Change permissions of pwm[1-3] if in manual mode */ 221462306a36Sopenharmony_ci for (ix = 0; ix < 3; ix++) { 221562306a36Sopenharmony_ci if ((data->has_features & HAS_PWM(ix)) && 221662306a36Sopenharmony_ci (PWM_EN_FROM_REG(data->pwm_config[ix]) == 1)) { 221762306a36Sopenharmony_ci dme1737_chmod_file(dev, 221862306a36Sopenharmony_ci dme1737_pwm_chmod_attr[ix], 221962306a36Sopenharmony_ci S_IRUGO | S_IWUSR); 222062306a36Sopenharmony_ci } 222162306a36Sopenharmony_ci } 222262306a36Sopenharmony_ci } 222362306a36Sopenharmony_ci 222462306a36Sopenharmony_ci return 0; 222562306a36Sopenharmony_ci 222662306a36Sopenharmony_ciexit_remove: 222762306a36Sopenharmony_ci dme1737_remove_files(dev); 222862306a36Sopenharmony_ciexit: 222962306a36Sopenharmony_ci return err; 223062306a36Sopenharmony_ci} 223162306a36Sopenharmony_ci 223262306a36Sopenharmony_cistatic int dme1737_init_device(struct device *dev) 223362306a36Sopenharmony_ci{ 223462306a36Sopenharmony_ci struct dme1737_data *data = dev_get_drvdata(dev); 223562306a36Sopenharmony_ci struct i2c_client *client = data->client; 223662306a36Sopenharmony_ci int ix; 223762306a36Sopenharmony_ci u8 reg; 223862306a36Sopenharmony_ci 223962306a36Sopenharmony_ci /* Point to the right nominal voltages array */ 224062306a36Sopenharmony_ci data->in_nominal = IN_NOMINAL(data->type); 224162306a36Sopenharmony_ci 224262306a36Sopenharmony_ci data->config = dme1737_read(data, DME1737_REG_CONFIG); 224362306a36Sopenharmony_ci /* Inform if part is not monitoring/started */ 224462306a36Sopenharmony_ci if (!(data->config & 0x01)) { 224562306a36Sopenharmony_ci if (!force_start) { 224662306a36Sopenharmony_ci dev_err(dev, 224762306a36Sopenharmony_ci "Device is not monitoring. Use the force_start load parameter to override.\n"); 224862306a36Sopenharmony_ci return -EFAULT; 224962306a36Sopenharmony_ci } 225062306a36Sopenharmony_ci 225162306a36Sopenharmony_ci /* Force monitoring */ 225262306a36Sopenharmony_ci data->config |= 0x01; 225362306a36Sopenharmony_ci dme1737_write(data, DME1737_REG_CONFIG, data->config); 225462306a36Sopenharmony_ci } 225562306a36Sopenharmony_ci /* Inform if part is not ready */ 225662306a36Sopenharmony_ci if (!(data->config & 0x04)) { 225762306a36Sopenharmony_ci dev_err(dev, "Device is not ready.\n"); 225862306a36Sopenharmony_ci return -EFAULT; 225962306a36Sopenharmony_ci } 226062306a36Sopenharmony_ci 226162306a36Sopenharmony_ci /* 226262306a36Sopenharmony_ci * Determine which optional fan and pwm features are enabled (only 226362306a36Sopenharmony_ci * valid for I2C devices) 226462306a36Sopenharmony_ci */ 226562306a36Sopenharmony_ci if (client) { /* I2C chip */ 226662306a36Sopenharmony_ci data->config2 = dme1737_read(data, DME1737_REG_CONFIG2); 226762306a36Sopenharmony_ci /* Check if optional fan3 input is enabled */ 226862306a36Sopenharmony_ci if (data->config2 & 0x04) 226962306a36Sopenharmony_ci data->has_features |= HAS_FAN(2); 227062306a36Sopenharmony_ci 227162306a36Sopenharmony_ci /* 227262306a36Sopenharmony_ci * Fan4 and pwm3 are only available if the client's I2C address 227362306a36Sopenharmony_ci * is the default 0x2e. Otherwise the I/Os associated with 227462306a36Sopenharmony_ci * these functions are used for addr enable/select. 227562306a36Sopenharmony_ci */ 227662306a36Sopenharmony_ci if (client->addr == 0x2e) 227762306a36Sopenharmony_ci data->has_features |= HAS_FAN(3) | HAS_PWM(2); 227862306a36Sopenharmony_ci 227962306a36Sopenharmony_ci /* 228062306a36Sopenharmony_ci * Determine which of the optional fan[5-6] and pwm[5-6] 228162306a36Sopenharmony_ci * features are enabled. For this, we need to query the runtime 228262306a36Sopenharmony_ci * registers through the Super-IO LPC interface. Try both 228362306a36Sopenharmony_ci * config ports 0x2e and 0x4e. 228462306a36Sopenharmony_ci */ 228562306a36Sopenharmony_ci if (dme1737_i2c_get_features(0x2e, data) && 228662306a36Sopenharmony_ci dme1737_i2c_get_features(0x4e, data)) { 228762306a36Sopenharmony_ci dev_warn(dev, 228862306a36Sopenharmony_ci "Failed to query Super-IO for optional features.\n"); 228962306a36Sopenharmony_ci } 229062306a36Sopenharmony_ci } 229162306a36Sopenharmony_ci 229262306a36Sopenharmony_ci /* Fan[1-2] and pwm[1-2] are present in all chips */ 229362306a36Sopenharmony_ci data->has_features |= HAS_FAN(0) | HAS_FAN(1) | HAS_PWM(0) | HAS_PWM(1); 229462306a36Sopenharmony_ci 229562306a36Sopenharmony_ci /* Chip-dependent features */ 229662306a36Sopenharmony_ci switch (data->type) { 229762306a36Sopenharmony_ci case dme1737: 229862306a36Sopenharmony_ci data->has_features |= HAS_TEMP_OFFSET | HAS_VID | HAS_ZONE3 | 229962306a36Sopenharmony_ci HAS_ZONE_HYST | HAS_PWM_MIN; 230062306a36Sopenharmony_ci break; 230162306a36Sopenharmony_ci case sch311x: 230262306a36Sopenharmony_ci data->has_features |= HAS_TEMP_OFFSET | HAS_ZONE3 | 230362306a36Sopenharmony_ci HAS_ZONE_HYST | HAS_PWM_MIN | HAS_FAN(2) | HAS_PWM(2); 230462306a36Sopenharmony_ci break; 230562306a36Sopenharmony_ci case sch5027: 230662306a36Sopenharmony_ci data->has_features |= HAS_ZONE3; 230762306a36Sopenharmony_ci break; 230862306a36Sopenharmony_ci case sch5127: 230962306a36Sopenharmony_ci data->has_features |= HAS_FAN(2) | HAS_PWM(2) | HAS_IN7; 231062306a36Sopenharmony_ci break; 231162306a36Sopenharmony_ci default: 231262306a36Sopenharmony_ci break; 231362306a36Sopenharmony_ci } 231462306a36Sopenharmony_ci 231562306a36Sopenharmony_ci dev_info(dev, 231662306a36Sopenharmony_ci "Optional features: pwm3=%s, pwm5=%s, pwm6=%s, fan3=%s, fan4=%s, fan5=%s, fan6=%s.\n", 231762306a36Sopenharmony_ci (data->has_features & HAS_PWM(2)) ? "yes" : "no", 231862306a36Sopenharmony_ci (data->has_features & HAS_PWM(4)) ? "yes" : "no", 231962306a36Sopenharmony_ci (data->has_features & HAS_PWM(5)) ? "yes" : "no", 232062306a36Sopenharmony_ci (data->has_features & HAS_FAN(2)) ? "yes" : "no", 232162306a36Sopenharmony_ci (data->has_features & HAS_FAN(3)) ? "yes" : "no", 232262306a36Sopenharmony_ci (data->has_features & HAS_FAN(4)) ? "yes" : "no", 232362306a36Sopenharmony_ci (data->has_features & HAS_FAN(5)) ? "yes" : "no"); 232462306a36Sopenharmony_ci 232562306a36Sopenharmony_ci reg = dme1737_read(data, DME1737_REG_TACH_PWM); 232662306a36Sopenharmony_ci /* Inform if fan-to-pwm mapping differs from the default */ 232762306a36Sopenharmony_ci if (client && reg != 0xa4) { /* I2C chip */ 232862306a36Sopenharmony_ci dev_warn(dev, 232962306a36Sopenharmony_ci "Non-standard fan to pwm mapping: fan1->pwm%d, fan2->pwm%d, fan3->pwm%d, fan4->pwm%d. %s\n", 233062306a36Sopenharmony_ci (reg & 0x03) + 1, ((reg >> 2) & 0x03) + 1, 233162306a36Sopenharmony_ci ((reg >> 4) & 0x03) + 1, ((reg >> 6) & 0x03) + 1, 233262306a36Sopenharmony_ci DO_REPORT); 233362306a36Sopenharmony_ci } else if (!client && reg != 0x24) { /* ISA chip */ 233462306a36Sopenharmony_ci dev_warn(dev, 233562306a36Sopenharmony_ci "Non-standard fan to pwm mapping: fan1->pwm%d, fan2->pwm%d, fan3->pwm%d. %s\n", 233662306a36Sopenharmony_ci (reg & 0x03) + 1, ((reg >> 2) & 0x03) + 1, 233762306a36Sopenharmony_ci ((reg >> 4) & 0x03) + 1, DO_REPORT); 233862306a36Sopenharmony_ci } 233962306a36Sopenharmony_ci 234062306a36Sopenharmony_ci /* 234162306a36Sopenharmony_ci * Switch pwm[1-3] to manual mode if they are currently disabled and 234262306a36Sopenharmony_ci * set the duty-cycles to 0% (which is identical to the PWMs being 234362306a36Sopenharmony_ci * disabled). 234462306a36Sopenharmony_ci */ 234562306a36Sopenharmony_ci if (!(data->config & 0x02)) { 234662306a36Sopenharmony_ci for (ix = 0; ix < 3; ix++) { 234762306a36Sopenharmony_ci data->pwm_config[ix] = dme1737_read(data, 234862306a36Sopenharmony_ci DME1737_REG_PWM_CONFIG(ix)); 234962306a36Sopenharmony_ci if ((data->has_features & HAS_PWM(ix)) && 235062306a36Sopenharmony_ci (PWM_EN_FROM_REG(data->pwm_config[ix]) == -1)) { 235162306a36Sopenharmony_ci dev_info(dev, 235262306a36Sopenharmony_ci "Switching pwm%d to manual mode.\n", 235362306a36Sopenharmony_ci ix + 1); 235462306a36Sopenharmony_ci data->pwm_config[ix] = PWM_EN_TO_REG(1, 235562306a36Sopenharmony_ci data->pwm_config[ix]); 235662306a36Sopenharmony_ci dme1737_write(data, DME1737_REG_PWM(ix), 0); 235762306a36Sopenharmony_ci dme1737_write(data, 235862306a36Sopenharmony_ci DME1737_REG_PWM_CONFIG(ix), 235962306a36Sopenharmony_ci data->pwm_config[ix]); 236062306a36Sopenharmony_ci } 236162306a36Sopenharmony_ci } 236262306a36Sopenharmony_ci } 236362306a36Sopenharmony_ci 236462306a36Sopenharmony_ci /* Initialize the default PWM auto channels zone (acz) assignments */ 236562306a36Sopenharmony_ci data->pwm_acz[0] = 1; /* pwm1 -> zone1 */ 236662306a36Sopenharmony_ci data->pwm_acz[1] = 2; /* pwm2 -> zone2 */ 236762306a36Sopenharmony_ci data->pwm_acz[2] = 4; /* pwm3 -> zone3 */ 236862306a36Sopenharmony_ci 236962306a36Sopenharmony_ci /* Set VRM */ 237062306a36Sopenharmony_ci if (data->has_features & HAS_VID) 237162306a36Sopenharmony_ci data->vrm = vid_which_vrm(); 237262306a36Sopenharmony_ci 237362306a36Sopenharmony_ci return 0; 237462306a36Sopenharmony_ci} 237562306a36Sopenharmony_ci 237662306a36Sopenharmony_ci/* --------------------------------------------------------------------- 237762306a36Sopenharmony_ci * I2C device detection and registration 237862306a36Sopenharmony_ci * --------------------------------------------------------------------- */ 237962306a36Sopenharmony_ci 238062306a36Sopenharmony_cistatic struct i2c_driver dme1737_i2c_driver; 238162306a36Sopenharmony_ci 238262306a36Sopenharmony_cistatic int dme1737_i2c_get_features(int sio_cip, struct dme1737_data *data) 238362306a36Sopenharmony_ci{ 238462306a36Sopenharmony_ci int err = 0, reg; 238562306a36Sopenharmony_ci u16 addr; 238662306a36Sopenharmony_ci 238762306a36Sopenharmony_ci dme1737_sio_enter(sio_cip); 238862306a36Sopenharmony_ci 238962306a36Sopenharmony_ci /* 239062306a36Sopenharmony_ci * Check device ID 239162306a36Sopenharmony_ci * We currently know about two kinds of DME1737 and SCH5027. 239262306a36Sopenharmony_ci */ 239362306a36Sopenharmony_ci reg = force_id ? force_id : dme1737_sio_inb(sio_cip, 0x20); 239462306a36Sopenharmony_ci if (!(reg == DME1737_ID_1 || reg == DME1737_ID_2 || 239562306a36Sopenharmony_ci reg == SCH5027_ID)) { 239662306a36Sopenharmony_ci err = -ENODEV; 239762306a36Sopenharmony_ci goto exit; 239862306a36Sopenharmony_ci } 239962306a36Sopenharmony_ci 240062306a36Sopenharmony_ci /* Select logical device A (runtime registers) */ 240162306a36Sopenharmony_ci dme1737_sio_outb(sio_cip, 0x07, 0x0a); 240262306a36Sopenharmony_ci 240362306a36Sopenharmony_ci /* Get the base address of the runtime registers */ 240462306a36Sopenharmony_ci addr = (dme1737_sio_inb(sio_cip, 0x60) << 8) | 240562306a36Sopenharmony_ci dme1737_sio_inb(sio_cip, 0x61); 240662306a36Sopenharmony_ci if (!addr) { 240762306a36Sopenharmony_ci err = -ENODEV; 240862306a36Sopenharmony_ci goto exit; 240962306a36Sopenharmony_ci } 241062306a36Sopenharmony_ci 241162306a36Sopenharmony_ci /* 241262306a36Sopenharmony_ci * Read the runtime registers to determine which optional features 241362306a36Sopenharmony_ci * are enabled and available. Bits [3:2] of registers 0x43-0x46 are set 241462306a36Sopenharmony_ci * to '10' if the respective feature is enabled. 241562306a36Sopenharmony_ci */ 241662306a36Sopenharmony_ci if ((inb(addr + 0x43) & 0x0c) == 0x08) /* fan6 */ 241762306a36Sopenharmony_ci data->has_features |= HAS_FAN(5); 241862306a36Sopenharmony_ci if ((inb(addr + 0x44) & 0x0c) == 0x08) /* pwm6 */ 241962306a36Sopenharmony_ci data->has_features |= HAS_PWM(5); 242062306a36Sopenharmony_ci if ((inb(addr + 0x45) & 0x0c) == 0x08) /* fan5 */ 242162306a36Sopenharmony_ci data->has_features |= HAS_FAN(4); 242262306a36Sopenharmony_ci if ((inb(addr + 0x46) & 0x0c) == 0x08) /* pwm5 */ 242362306a36Sopenharmony_ci data->has_features |= HAS_PWM(4); 242462306a36Sopenharmony_ci 242562306a36Sopenharmony_ciexit: 242662306a36Sopenharmony_ci dme1737_sio_exit(sio_cip); 242762306a36Sopenharmony_ci 242862306a36Sopenharmony_ci return err; 242962306a36Sopenharmony_ci} 243062306a36Sopenharmony_ci 243162306a36Sopenharmony_ci/* Return 0 if detection is successful, -ENODEV otherwise */ 243262306a36Sopenharmony_cistatic int dme1737_i2c_detect(struct i2c_client *client, 243362306a36Sopenharmony_ci struct i2c_board_info *info) 243462306a36Sopenharmony_ci{ 243562306a36Sopenharmony_ci struct i2c_adapter *adapter = client->adapter; 243662306a36Sopenharmony_ci struct device *dev = &adapter->dev; 243762306a36Sopenharmony_ci u8 company, verstep = 0; 243862306a36Sopenharmony_ci const char *name; 243962306a36Sopenharmony_ci 244062306a36Sopenharmony_ci if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) 244162306a36Sopenharmony_ci return -ENODEV; 244262306a36Sopenharmony_ci 244362306a36Sopenharmony_ci company = i2c_smbus_read_byte_data(client, DME1737_REG_COMPANY); 244462306a36Sopenharmony_ci verstep = i2c_smbus_read_byte_data(client, DME1737_REG_VERSTEP); 244562306a36Sopenharmony_ci 244662306a36Sopenharmony_ci if (company == DME1737_COMPANY_SMSC && 244762306a36Sopenharmony_ci verstep == SCH5027_VERSTEP) { 244862306a36Sopenharmony_ci name = "sch5027"; 244962306a36Sopenharmony_ci } else if (company == DME1737_COMPANY_SMSC && 245062306a36Sopenharmony_ci (verstep & DME1737_VERSTEP_MASK) == DME1737_VERSTEP) { 245162306a36Sopenharmony_ci name = "dme1737"; 245262306a36Sopenharmony_ci } else { 245362306a36Sopenharmony_ci return -ENODEV; 245462306a36Sopenharmony_ci } 245562306a36Sopenharmony_ci 245662306a36Sopenharmony_ci dev_info(dev, "Found a %s chip at 0x%02x (rev 0x%02x).\n", 245762306a36Sopenharmony_ci verstep == SCH5027_VERSTEP ? "SCH5027" : "DME1737", 245862306a36Sopenharmony_ci client->addr, verstep); 245962306a36Sopenharmony_ci strscpy(info->type, name, I2C_NAME_SIZE); 246062306a36Sopenharmony_ci 246162306a36Sopenharmony_ci return 0; 246262306a36Sopenharmony_ci} 246362306a36Sopenharmony_ci 246462306a36Sopenharmony_cistatic const struct i2c_device_id dme1737_id[]; 246562306a36Sopenharmony_ci 246662306a36Sopenharmony_cistatic int dme1737_i2c_probe(struct i2c_client *client) 246762306a36Sopenharmony_ci{ 246862306a36Sopenharmony_ci struct dme1737_data *data; 246962306a36Sopenharmony_ci struct device *dev = &client->dev; 247062306a36Sopenharmony_ci int err; 247162306a36Sopenharmony_ci 247262306a36Sopenharmony_ci data = devm_kzalloc(dev, sizeof(struct dme1737_data), GFP_KERNEL); 247362306a36Sopenharmony_ci if (!data) 247462306a36Sopenharmony_ci return -ENOMEM; 247562306a36Sopenharmony_ci 247662306a36Sopenharmony_ci i2c_set_clientdata(client, data); 247762306a36Sopenharmony_ci data->type = i2c_match_id(dme1737_id, client)->driver_data; 247862306a36Sopenharmony_ci data->client = client; 247962306a36Sopenharmony_ci data->name = client->name; 248062306a36Sopenharmony_ci mutex_init(&data->update_lock); 248162306a36Sopenharmony_ci 248262306a36Sopenharmony_ci /* Initialize the DME1737 chip */ 248362306a36Sopenharmony_ci err = dme1737_init_device(dev); 248462306a36Sopenharmony_ci if (err) { 248562306a36Sopenharmony_ci dev_err(dev, "Failed to initialize device.\n"); 248662306a36Sopenharmony_ci return err; 248762306a36Sopenharmony_ci } 248862306a36Sopenharmony_ci 248962306a36Sopenharmony_ci /* Create sysfs files */ 249062306a36Sopenharmony_ci err = dme1737_create_files(dev); 249162306a36Sopenharmony_ci if (err) { 249262306a36Sopenharmony_ci dev_err(dev, "Failed to create sysfs files.\n"); 249362306a36Sopenharmony_ci return err; 249462306a36Sopenharmony_ci } 249562306a36Sopenharmony_ci 249662306a36Sopenharmony_ci /* Register device */ 249762306a36Sopenharmony_ci data->hwmon_dev = hwmon_device_register(dev); 249862306a36Sopenharmony_ci if (IS_ERR(data->hwmon_dev)) { 249962306a36Sopenharmony_ci dev_err(dev, "Failed to register device.\n"); 250062306a36Sopenharmony_ci err = PTR_ERR(data->hwmon_dev); 250162306a36Sopenharmony_ci goto exit_remove; 250262306a36Sopenharmony_ci } 250362306a36Sopenharmony_ci 250462306a36Sopenharmony_ci return 0; 250562306a36Sopenharmony_ci 250662306a36Sopenharmony_ciexit_remove: 250762306a36Sopenharmony_ci dme1737_remove_files(dev); 250862306a36Sopenharmony_ci return err; 250962306a36Sopenharmony_ci} 251062306a36Sopenharmony_ci 251162306a36Sopenharmony_cistatic void dme1737_i2c_remove(struct i2c_client *client) 251262306a36Sopenharmony_ci{ 251362306a36Sopenharmony_ci struct dme1737_data *data = i2c_get_clientdata(client); 251462306a36Sopenharmony_ci 251562306a36Sopenharmony_ci hwmon_device_unregister(data->hwmon_dev); 251662306a36Sopenharmony_ci dme1737_remove_files(&client->dev); 251762306a36Sopenharmony_ci} 251862306a36Sopenharmony_ci 251962306a36Sopenharmony_cistatic const struct i2c_device_id dme1737_id[] = { 252062306a36Sopenharmony_ci { "dme1737", dme1737 }, 252162306a36Sopenharmony_ci { "sch5027", sch5027 }, 252262306a36Sopenharmony_ci { } 252362306a36Sopenharmony_ci}; 252462306a36Sopenharmony_ciMODULE_DEVICE_TABLE(i2c, dme1737_id); 252562306a36Sopenharmony_ci 252662306a36Sopenharmony_cistatic struct i2c_driver dme1737_i2c_driver = { 252762306a36Sopenharmony_ci .class = I2C_CLASS_HWMON, 252862306a36Sopenharmony_ci .driver = { 252962306a36Sopenharmony_ci .name = "dme1737", 253062306a36Sopenharmony_ci }, 253162306a36Sopenharmony_ci .probe = dme1737_i2c_probe, 253262306a36Sopenharmony_ci .remove = dme1737_i2c_remove, 253362306a36Sopenharmony_ci .id_table = dme1737_id, 253462306a36Sopenharmony_ci .detect = dme1737_i2c_detect, 253562306a36Sopenharmony_ci .address_list = normal_i2c, 253662306a36Sopenharmony_ci}; 253762306a36Sopenharmony_ci 253862306a36Sopenharmony_ci/* --------------------------------------------------------------------- 253962306a36Sopenharmony_ci * ISA device detection and registration 254062306a36Sopenharmony_ci * --------------------------------------------------------------------- */ 254162306a36Sopenharmony_ci 254262306a36Sopenharmony_cistatic int __init dme1737_isa_detect(int sio_cip, unsigned short *addr) 254362306a36Sopenharmony_ci{ 254462306a36Sopenharmony_ci int err = 0, reg; 254562306a36Sopenharmony_ci unsigned short base_addr; 254662306a36Sopenharmony_ci 254762306a36Sopenharmony_ci dme1737_sio_enter(sio_cip); 254862306a36Sopenharmony_ci 254962306a36Sopenharmony_ci /* 255062306a36Sopenharmony_ci * Check device ID 255162306a36Sopenharmony_ci * We currently know about SCH3112, SCH3114, SCH3116, and SCH5127 255262306a36Sopenharmony_ci */ 255362306a36Sopenharmony_ci reg = force_id ? force_id : dme1737_sio_inb(sio_cip, 0x20); 255462306a36Sopenharmony_ci if (!(reg == SCH3112_ID || reg == SCH3114_ID || reg == SCH3116_ID || 255562306a36Sopenharmony_ci reg == SCH5127_ID)) { 255662306a36Sopenharmony_ci err = -ENODEV; 255762306a36Sopenharmony_ci goto exit; 255862306a36Sopenharmony_ci } 255962306a36Sopenharmony_ci 256062306a36Sopenharmony_ci /* Select logical device A (runtime registers) */ 256162306a36Sopenharmony_ci dme1737_sio_outb(sio_cip, 0x07, 0x0a); 256262306a36Sopenharmony_ci 256362306a36Sopenharmony_ci /* Get the base address of the runtime registers */ 256462306a36Sopenharmony_ci base_addr = (dme1737_sio_inb(sio_cip, 0x60) << 8) | 256562306a36Sopenharmony_ci dme1737_sio_inb(sio_cip, 0x61); 256662306a36Sopenharmony_ci if (!base_addr) { 256762306a36Sopenharmony_ci pr_err("Base address not set\n"); 256862306a36Sopenharmony_ci err = -ENODEV; 256962306a36Sopenharmony_ci goto exit; 257062306a36Sopenharmony_ci } 257162306a36Sopenharmony_ci 257262306a36Sopenharmony_ci /* 257362306a36Sopenharmony_ci * Access to the hwmon registers is through an index/data register 257462306a36Sopenharmony_ci * pair located at offset 0x70/0x71. 257562306a36Sopenharmony_ci */ 257662306a36Sopenharmony_ci *addr = base_addr + 0x70; 257762306a36Sopenharmony_ci 257862306a36Sopenharmony_ciexit: 257962306a36Sopenharmony_ci dme1737_sio_exit(sio_cip); 258062306a36Sopenharmony_ci return err; 258162306a36Sopenharmony_ci} 258262306a36Sopenharmony_ci 258362306a36Sopenharmony_cistatic int __init dme1737_isa_device_add(unsigned short addr) 258462306a36Sopenharmony_ci{ 258562306a36Sopenharmony_ci struct resource res = { 258662306a36Sopenharmony_ci .start = addr, 258762306a36Sopenharmony_ci .end = addr + DME1737_EXTENT - 1, 258862306a36Sopenharmony_ci .name = "dme1737", 258962306a36Sopenharmony_ci .flags = IORESOURCE_IO, 259062306a36Sopenharmony_ci }; 259162306a36Sopenharmony_ci int err; 259262306a36Sopenharmony_ci 259362306a36Sopenharmony_ci err = acpi_check_resource_conflict(&res); 259462306a36Sopenharmony_ci if (err) 259562306a36Sopenharmony_ci goto exit; 259662306a36Sopenharmony_ci 259762306a36Sopenharmony_ci pdev = platform_device_alloc("dme1737", addr); 259862306a36Sopenharmony_ci if (!pdev) { 259962306a36Sopenharmony_ci pr_err("Failed to allocate device\n"); 260062306a36Sopenharmony_ci err = -ENOMEM; 260162306a36Sopenharmony_ci goto exit; 260262306a36Sopenharmony_ci } 260362306a36Sopenharmony_ci 260462306a36Sopenharmony_ci err = platform_device_add_resources(pdev, &res, 1); 260562306a36Sopenharmony_ci if (err) { 260662306a36Sopenharmony_ci pr_err("Failed to add device resource (err = %d)\n", err); 260762306a36Sopenharmony_ci goto exit_device_put; 260862306a36Sopenharmony_ci } 260962306a36Sopenharmony_ci 261062306a36Sopenharmony_ci err = platform_device_add(pdev); 261162306a36Sopenharmony_ci if (err) { 261262306a36Sopenharmony_ci pr_err("Failed to add device (err = %d)\n", err); 261362306a36Sopenharmony_ci goto exit_device_put; 261462306a36Sopenharmony_ci } 261562306a36Sopenharmony_ci 261662306a36Sopenharmony_ci return 0; 261762306a36Sopenharmony_ci 261862306a36Sopenharmony_ciexit_device_put: 261962306a36Sopenharmony_ci platform_device_put(pdev); 262062306a36Sopenharmony_ci pdev = NULL; 262162306a36Sopenharmony_ciexit: 262262306a36Sopenharmony_ci return err; 262362306a36Sopenharmony_ci} 262462306a36Sopenharmony_ci 262562306a36Sopenharmony_cistatic int dme1737_isa_probe(struct platform_device *pdev) 262662306a36Sopenharmony_ci{ 262762306a36Sopenharmony_ci u8 company, device; 262862306a36Sopenharmony_ci struct resource *res; 262962306a36Sopenharmony_ci struct dme1737_data *data; 263062306a36Sopenharmony_ci struct device *dev = &pdev->dev; 263162306a36Sopenharmony_ci int err; 263262306a36Sopenharmony_ci 263362306a36Sopenharmony_ci res = platform_get_resource(pdev, IORESOURCE_IO, 0); 263462306a36Sopenharmony_ci if (!devm_request_region(dev, res->start, DME1737_EXTENT, "dme1737")) { 263562306a36Sopenharmony_ci dev_err(dev, "Failed to request region 0x%04x-0x%04x.\n", 263662306a36Sopenharmony_ci (unsigned short)res->start, 263762306a36Sopenharmony_ci (unsigned short)res->start + DME1737_EXTENT - 1); 263862306a36Sopenharmony_ci return -EBUSY; 263962306a36Sopenharmony_ci } 264062306a36Sopenharmony_ci 264162306a36Sopenharmony_ci data = devm_kzalloc(dev, sizeof(struct dme1737_data), GFP_KERNEL); 264262306a36Sopenharmony_ci if (!data) 264362306a36Sopenharmony_ci return -ENOMEM; 264462306a36Sopenharmony_ci 264562306a36Sopenharmony_ci data->addr = res->start; 264662306a36Sopenharmony_ci platform_set_drvdata(pdev, data); 264762306a36Sopenharmony_ci 264862306a36Sopenharmony_ci /* Skip chip detection if module is loaded with force_id parameter */ 264962306a36Sopenharmony_ci switch (force_id) { 265062306a36Sopenharmony_ci case SCH3112_ID: 265162306a36Sopenharmony_ci case SCH3114_ID: 265262306a36Sopenharmony_ci case SCH3116_ID: 265362306a36Sopenharmony_ci data->type = sch311x; 265462306a36Sopenharmony_ci break; 265562306a36Sopenharmony_ci case SCH5127_ID: 265662306a36Sopenharmony_ci data->type = sch5127; 265762306a36Sopenharmony_ci break; 265862306a36Sopenharmony_ci default: 265962306a36Sopenharmony_ci company = dme1737_read(data, DME1737_REG_COMPANY); 266062306a36Sopenharmony_ci device = dme1737_read(data, DME1737_REG_DEVICE); 266162306a36Sopenharmony_ci 266262306a36Sopenharmony_ci if ((company == DME1737_COMPANY_SMSC) && 266362306a36Sopenharmony_ci (device == SCH311X_DEVICE)) { 266462306a36Sopenharmony_ci data->type = sch311x; 266562306a36Sopenharmony_ci } else if ((company == DME1737_COMPANY_SMSC) && 266662306a36Sopenharmony_ci (device == SCH5127_DEVICE)) { 266762306a36Sopenharmony_ci data->type = sch5127; 266862306a36Sopenharmony_ci } else { 266962306a36Sopenharmony_ci return -ENODEV; 267062306a36Sopenharmony_ci } 267162306a36Sopenharmony_ci } 267262306a36Sopenharmony_ci 267362306a36Sopenharmony_ci if (data->type == sch5127) 267462306a36Sopenharmony_ci data->name = "sch5127"; 267562306a36Sopenharmony_ci else 267662306a36Sopenharmony_ci data->name = "sch311x"; 267762306a36Sopenharmony_ci 267862306a36Sopenharmony_ci /* Initialize the mutex */ 267962306a36Sopenharmony_ci mutex_init(&data->update_lock); 268062306a36Sopenharmony_ci 268162306a36Sopenharmony_ci dev_info(dev, "Found a %s chip at 0x%04x\n", 268262306a36Sopenharmony_ci data->type == sch5127 ? "SCH5127" : "SCH311x", data->addr); 268362306a36Sopenharmony_ci 268462306a36Sopenharmony_ci /* Initialize the chip */ 268562306a36Sopenharmony_ci err = dme1737_init_device(dev); 268662306a36Sopenharmony_ci if (err) { 268762306a36Sopenharmony_ci dev_err(dev, "Failed to initialize device.\n"); 268862306a36Sopenharmony_ci return err; 268962306a36Sopenharmony_ci } 269062306a36Sopenharmony_ci 269162306a36Sopenharmony_ci /* Create sysfs files */ 269262306a36Sopenharmony_ci err = dme1737_create_files(dev); 269362306a36Sopenharmony_ci if (err) { 269462306a36Sopenharmony_ci dev_err(dev, "Failed to create sysfs files.\n"); 269562306a36Sopenharmony_ci return err; 269662306a36Sopenharmony_ci } 269762306a36Sopenharmony_ci 269862306a36Sopenharmony_ci /* Register device */ 269962306a36Sopenharmony_ci data->hwmon_dev = hwmon_device_register(dev); 270062306a36Sopenharmony_ci if (IS_ERR(data->hwmon_dev)) { 270162306a36Sopenharmony_ci dev_err(dev, "Failed to register device.\n"); 270262306a36Sopenharmony_ci err = PTR_ERR(data->hwmon_dev); 270362306a36Sopenharmony_ci goto exit_remove_files; 270462306a36Sopenharmony_ci } 270562306a36Sopenharmony_ci 270662306a36Sopenharmony_ci return 0; 270762306a36Sopenharmony_ci 270862306a36Sopenharmony_ciexit_remove_files: 270962306a36Sopenharmony_ci dme1737_remove_files(dev); 271062306a36Sopenharmony_ci return err; 271162306a36Sopenharmony_ci} 271262306a36Sopenharmony_ci 271362306a36Sopenharmony_cistatic int dme1737_isa_remove(struct platform_device *pdev) 271462306a36Sopenharmony_ci{ 271562306a36Sopenharmony_ci struct dme1737_data *data = platform_get_drvdata(pdev); 271662306a36Sopenharmony_ci 271762306a36Sopenharmony_ci hwmon_device_unregister(data->hwmon_dev); 271862306a36Sopenharmony_ci dme1737_remove_files(&pdev->dev); 271962306a36Sopenharmony_ci 272062306a36Sopenharmony_ci return 0; 272162306a36Sopenharmony_ci} 272262306a36Sopenharmony_ci 272362306a36Sopenharmony_cistatic struct platform_driver dme1737_isa_driver = { 272462306a36Sopenharmony_ci .driver = { 272562306a36Sopenharmony_ci .name = "dme1737", 272662306a36Sopenharmony_ci }, 272762306a36Sopenharmony_ci .probe = dme1737_isa_probe, 272862306a36Sopenharmony_ci .remove = dme1737_isa_remove, 272962306a36Sopenharmony_ci}; 273062306a36Sopenharmony_ci 273162306a36Sopenharmony_ci/* --------------------------------------------------------------------- 273262306a36Sopenharmony_ci * Module initialization and cleanup 273362306a36Sopenharmony_ci * --------------------------------------------------------------------- */ 273462306a36Sopenharmony_ci 273562306a36Sopenharmony_cistatic int __init dme1737_init(void) 273662306a36Sopenharmony_ci{ 273762306a36Sopenharmony_ci int err; 273862306a36Sopenharmony_ci unsigned short addr; 273962306a36Sopenharmony_ci 274062306a36Sopenharmony_ci err = i2c_add_driver(&dme1737_i2c_driver); 274162306a36Sopenharmony_ci if (err) 274262306a36Sopenharmony_ci goto exit; 274362306a36Sopenharmony_ci 274462306a36Sopenharmony_ci if (dme1737_isa_detect(0x2e, &addr) && 274562306a36Sopenharmony_ci dme1737_isa_detect(0x4e, &addr) && 274662306a36Sopenharmony_ci (!probe_all_addr || 274762306a36Sopenharmony_ci (dme1737_isa_detect(0x162e, &addr) && 274862306a36Sopenharmony_ci dme1737_isa_detect(0x164e, &addr)))) { 274962306a36Sopenharmony_ci /* Return 0 if we didn't find an ISA device */ 275062306a36Sopenharmony_ci return 0; 275162306a36Sopenharmony_ci } 275262306a36Sopenharmony_ci 275362306a36Sopenharmony_ci err = platform_driver_register(&dme1737_isa_driver); 275462306a36Sopenharmony_ci if (err) 275562306a36Sopenharmony_ci goto exit_del_i2c_driver; 275662306a36Sopenharmony_ci 275762306a36Sopenharmony_ci /* Sets global pdev as a side effect */ 275862306a36Sopenharmony_ci err = dme1737_isa_device_add(addr); 275962306a36Sopenharmony_ci if (err) 276062306a36Sopenharmony_ci goto exit_del_isa_driver; 276162306a36Sopenharmony_ci 276262306a36Sopenharmony_ci return 0; 276362306a36Sopenharmony_ci 276462306a36Sopenharmony_ciexit_del_isa_driver: 276562306a36Sopenharmony_ci platform_driver_unregister(&dme1737_isa_driver); 276662306a36Sopenharmony_ciexit_del_i2c_driver: 276762306a36Sopenharmony_ci i2c_del_driver(&dme1737_i2c_driver); 276862306a36Sopenharmony_ciexit: 276962306a36Sopenharmony_ci return err; 277062306a36Sopenharmony_ci} 277162306a36Sopenharmony_ci 277262306a36Sopenharmony_cistatic void __exit dme1737_exit(void) 277362306a36Sopenharmony_ci{ 277462306a36Sopenharmony_ci if (pdev) { 277562306a36Sopenharmony_ci platform_device_unregister(pdev); 277662306a36Sopenharmony_ci platform_driver_unregister(&dme1737_isa_driver); 277762306a36Sopenharmony_ci } 277862306a36Sopenharmony_ci 277962306a36Sopenharmony_ci i2c_del_driver(&dme1737_i2c_driver); 278062306a36Sopenharmony_ci} 278162306a36Sopenharmony_ci 278262306a36Sopenharmony_ciMODULE_AUTHOR("Juerg Haefliger <juergh@gmail.com>"); 278362306a36Sopenharmony_ciMODULE_DESCRIPTION("DME1737 sensors"); 278462306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 278562306a36Sopenharmony_ci 278662306a36Sopenharmony_cimodule_init(dme1737_init); 278762306a36Sopenharmony_cimodule_exit(dme1737_exit); 2788