162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * w83627hf.c - Part of lm_sensors, Linux kernel modules for hardware 462306a36Sopenharmony_ci * monitoring 562306a36Sopenharmony_ci * Copyright (c) 1998 - 2003 Frodo Looijaard <frodol@dds.nl>, 662306a36Sopenharmony_ci * Philip Edelbrock <phil@netroedge.com>, 762306a36Sopenharmony_ci * and Mark Studebaker <mdsxyz123@yahoo.com> 862306a36Sopenharmony_ci * Ported to 2.6 by Bernhard C. Schrenk <clemy@clemy.org> 962306a36Sopenharmony_ci * Copyright (c) 2007 - 1012 Jean Delvare <jdelvare@suse.de> 1062306a36Sopenharmony_ci */ 1162306a36Sopenharmony_ci 1262306a36Sopenharmony_ci/* 1362306a36Sopenharmony_ci * Supports following chips: 1462306a36Sopenharmony_ci * 1562306a36Sopenharmony_ci * Chip #vin #fanin #pwm #temp wchipid vendid i2c ISA 1662306a36Sopenharmony_ci * w83627hf 9 3 2 3 0x20 0x5ca3 no yes(LPC) 1762306a36Sopenharmony_ci * w83627thf 7 3 3 3 0x90 0x5ca3 no yes(LPC) 1862306a36Sopenharmony_ci * w83637hf 7 3 3 3 0x80 0x5ca3 no yes(LPC) 1962306a36Sopenharmony_ci * w83687thf 7 3 3 3 0x90 0x5ca3 no yes(LPC) 2062306a36Sopenharmony_ci * w83697hf 8 2 2 2 0x60 0x5ca3 no yes(LPC) 2162306a36Sopenharmony_ci * 2262306a36Sopenharmony_ci * For other winbond chips, and for i2c support in the above chips, 2362306a36Sopenharmony_ci * use w83781d.c. 2462306a36Sopenharmony_ci * 2562306a36Sopenharmony_ci * Note: automatic ("cruise") fan control for 697, 637 & 627thf not 2662306a36Sopenharmony_ci * supported yet. 2762306a36Sopenharmony_ci */ 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_ci#include <linux/module.h> 3262306a36Sopenharmony_ci#include <linux/init.h> 3362306a36Sopenharmony_ci#include <linux/slab.h> 3462306a36Sopenharmony_ci#include <linux/jiffies.h> 3562306a36Sopenharmony_ci#include <linux/platform_device.h> 3662306a36Sopenharmony_ci#include <linux/hwmon.h> 3762306a36Sopenharmony_ci#include <linux/hwmon-sysfs.h> 3862306a36Sopenharmony_ci#include <linux/hwmon-vid.h> 3962306a36Sopenharmony_ci#include <linux/err.h> 4062306a36Sopenharmony_ci#include <linux/mutex.h> 4162306a36Sopenharmony_ci#include <linux/ioport.h> 4262306a36Sopenharmony_ci#include <linux/acpi.h> 4362306a36Sopenharmony_ci#include <linux/io.h> 4462306a36Sopenharmony_ci#include "lm75.h" 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_cistatic struct platform_device *pdev; 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_ci#define DRVNAME "w83627hf" 4962306a36Sopenharmony_cienum chips { w83627hf, w83627thf, w83697hf, w83637hf, w83687thf }; 5062306a36Sopenharmony_ci 5162306a36Sopenharmony_cistruct w83627hf_sio_data { 5262306a36Sopenharmony_ci enum chips type; 5362306a36Sopenharmony_ci int sioaddr; 5462306a36Sopenharmony_ci}; 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_cistatic u8 force_i2c = 0x1f; 5762306a36Sopenharmony_cimodule_param(force_i2c, byte, 0); 5862306a36Sopenharmony_ciMODULE_PARM_DESC(force_i2c, 5962306a36Sopenharmony_ci "Initialize the i2c address of the sensors"); 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_cistatic bool init = 1; 6262306a36Sopenharmony_cimodule_param(init, bool, 0); 6362306a36Sopenharmony_ciMODULE_PARM_DESC(init, "Set to zero to bypass chip initialization"); 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_cistatic unsigned short force_id; 6662306a36Sopenharmony_cimodule_param(force_id, ushort, 0); 6762306a36Sopenharmony_ciMODULE_PARM_DESC(force_id, "Override the detected device ID"); 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_ci/* modified from kernel/include/traps.c */ 7062306a36Sopenharmony_ci#define DEV 0x07 /* Register: Logical device select */ 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_ci/* logical device numbers for superio_select (below) */ 7362306a36Sopenharmony_ci#define W83627HF_LD_FDC 0x00 7462306a36Sopenharmony_ci#define W83627HF_LD_PRT 0x01 7562306a36Sopenharmony_ci#define W83627HF_LD_UART1 0x02 7662306a36Sopenharmony_ci#define W83627HF_LD_UART2 0x03 7762306a36Sopenharmony_ci#define W83627HF_LD_KBC 0x05 7862306a36Sopenharmony_ci#define W83627HF_LD_CIR 0x06 /* w83627hf only */ 7962306a36Sopenharmony_ci#define W83627HF_LD_GAME 0x07 8062306a36Sopenharmony_ci#define W83627HF_LD_MIDI 0x07 8162306a36Sopenharmony_ci#define W83627HF_LD_GPIO1 0x07 8262306a36Sopenharmony_ci#define W83627HF_LD_GPIO5 0x07 /* w83627thf only */ 8362306a36Sopenharmony_ci#define W83627HF_LD_GPIO2 0x08 8462306a36Sopenharmony_ci#define W83627HF_LD_GPIO3 0x09 8562306a36Sopenharmony_ci#define W83627HF_LD_GPIO4 0x09 /* w83627thf only */ 8662306a36Sopenharmony_ci#define W83627HF_LD_ACPI 0x0a 8762306a36Sopenharmony_ci#define W83627HF_LD_HWM 0x0b 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_ci#define DEVID 0x20 /* Register: Device ID */ 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_ci#define W83627THF_GPIO5_EN 0x30 /* w83627thf only */ 9262306a36Sopenharmony_ci#define W83627THF_GPIO5_IOSR 0xf3 /* w83627thf only */ 9362306a36Sopenharmony_ci#define W83627THF_GPIO5_DR 0xf4 /* w83627thf only */ 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_ci#define W83687THF_VID_EN 0x29 /* w83687thf only */ 9662306a36Sopenharmony_ci#define W83687THF_VID_CFG 0xF0 /* w83687thf only */ 9762306a36Sopenharmony_ci#define W83687THF_VID_DATA 0xF1 /* w83687thf only */ 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_cistatic inline void 10062306a36Sopenharmony_cisuperio_outb(struct w83627hf_sio_data *sio, int reg, int val) 10162306a36Sopenharmony_ci{ 10262306a36Sopenharmony_ci outb(reg, sio->sioaddr); 10362306a36Sopenharmony_ci outb(val, sio->sioaddr + 1); 10462306a36Sopenharmony_ci} 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_cistatic inline int 10762306a36Sopenharmony_cisuperio_inb(struct w83627hf_sio_data *sio, int reg) 10862306a36Sopenharmony_ci{ 10962306a36Sopenharmony_ci outb(reg, sio->sioaddr); 11062306a36Sopenharmony_ci return inb(sio->sioaddr + 1); 11162306a36Sopenharmony_ci} 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_cistatic inline void 11462306a36Sopenharmony_cisuperio_select(struct w83627hf_sio_data *sio, int ld) 11562306a36Sopenharmony_ci{ 11662306a36Sopenharmony_ci outb(DEV, sio->sioaddr); 11762306a36Sopenharmony_ci outb(ld, sio->sioaddr + 1); 11862306a36Sopenharmony_ci} 11962306a36Sopenharmony_ci 12062306a36Sopenharmony_cistatic inline int 12162306a36Sopenharmony_cisuperio_enter(struct w83627hf_sio_data *sio) 12262306a36Sopenharmony_ci{ 12362306a36Sopenharmony_ci if (!request_muxed_region(sio->sioaddr, 2, DRVNAME)) 12462306a36Sopenharmony_ci return -EBUSY; 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_ci outb(0x87, sio->sioaddr); 12762306a36Sopenharmony_ci outb(0x87, sio->sioaddr); 12862306a36Sopenharmony_ci 12962306a36Sopenharmony_ci return 0; 13062306a36Sopenharmony_ci} 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_cistatic inline void 13362306a36Sopenharmony_cisuperio_exit(struct w83627hf_sio_data *sio) 13462306a36Sopenharmony_ci{ 13562306a36Sopenharmony_ci outb(0xAA, sio->sioaddr); 13662306a36Sopenharmony_ci release_region(sio->sioaddr, 2); 13762306a36Sopenharmony_ci} 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_ci#define W627_DEVID 0x52 14062306a36Sopenharmony_ci#define W627THF_DEVID 0x82 14162306a36Sopenharmony_ci#define W697_DEVID 0x60 14262306a36Sopenharmony_ci#define W637_DEVID 0x70 14362306a36Sopenharmony_ci#define W687THF_DEVID 0x85 14462306a36Sopenharmony_ci#define WINB_ACT_REG 0x30 14562306a36Sopenharmony_ci#define WINB_BASE_REG 0x60 14662306a36Sopenharmony_ci/* Constants specified below */ 14762306a36Sopenharmony_ci 14862306a36Sopenharmony_ci/* Alignment of the base address */ 14962306a36Sopenharmony_ci#define WINB_ALIGNMENT ~7 15062306a36Sopenharmony_ci 15162306a36Sopenharmony_ci/* Offset & size of I/O region we are interested in */ 15262306a36Sopenharmony_ci#define WINB_REGION_OFFSET 5 15362306a36Sopenharmony_ci#define WINB_REGION_SIZE 2 15462306a36Sopenharmony_ci 15562306a36Sopenharmony_ci/* Where are the sensors address/data registers relative to the region offset */ 15662306a36Sopenharmony_ci#define W83781D_ADDR_REG_OFFSET 0 15762306a36Sopenharmony_ci#define W83781D_DATA_REG_OFFSET 1 15862306a36Sopenharmony_ci 15962306a36Sopenharmony_ci/* The W83781D registers */ 16062306a36Sopenharmony_ci/* The W83782D registers for nr=7,8 are in bank 5 */ 16162306a36Sopenharmony_ci#define W83781D_REG_IN_MAX(nr) ((nr < 7) ? (0x2b + (nr) * 2) : \ 16262306a36Sopenharmony_ci (0x554 + (((nr) - 7) * 2))) 16362306a36Sopenharmony_ci#define W83781D_REG_IN_MIN(nr) ((nr < 7) ? (0x2c + (nr) * 2) : \ 16462306a36Sopenharmony_ci (0x555 + (((nr) - 7) * 2))) 16562306a36Sopenharmony_ci#define W83781D_REG_IN(nr) ((nr < 7) ? (0x20 + (nr)) : \ 16662306a36Sopenharmony_ci (0x550 + (nr) - 7)) 16762306a36Sopenharmony_ci 16862306a36Sopenharmony_ci/* nr:0-2 for fans:1-3 */ 16962306a36Sopenharmony_ci#define W83627HF_REG_FAN_MIN(nr) (0x3b + (nr)) 17062306a36Sopenharmony_ci#define W83627HF_REG_FAN(nr) (0x28 + (nr)) 17162306a36Sopenharmony_ci 17262306a36Sopenharmony_ci#define W83627HF_REG_TEMP2_CONFIG 0x152 17362306a36Sopenharmony_ci#define W83627HF_REG_TEMP3_CONFIG 0x252 17462306a36Sopenharmony_ci/* these are zero-based, unlike config constants above */ 17562306a36Sopenharmony_cistatic const u16 w83627hf_reg_temp[] = { 0x27, 0x150, 0x250 }; 17662306a36Sopenharmony_cistatic const u16 w83627hf_reg_temp_hyst[] = { 0x3A, 0x153, 0x253 }; 17762306a36Sopenharmony_cistatic const u16 w83627hf_reg_temp_over[] = { 0x39, 0x155, 0x255 }; 17862306a36Sopenharmony_ci 17962306a36Sopenharmony_ci#define W83781D_REG_BANK 0x4E 18062306a36Sopenharmony_ci 18162306a36Sopenharmony_ci#define W83781D_REG_CONFIG 0x40 18262306a36Sopenharmony_ci#define W83781D_REG_ALARM1 0x459 18362306a36Sopenharmony_ci#define W83781D_REG_ALARM2 0x45A 18462306a36Sopenharmony_ci#define W83781D_REG_ALARM3 0x45B 18562306a36Sopenharmony_ci 18662306a36Sopenharmony_ci#define W83781D_REG_BEEP_CONFIG 0x4D 18762306a36Sopenharmony_ci#define W83781D_REG_BEEP_INTS1 0x56 18862306a36Sopenharmony_ci#define W83781D_REG_BEEP_INTS2 0x57 18962306a36Sopenharmony_ci#define W83781D_REG_BEEP_INTS3 0x453 19062306a36Sopenharmony_ci 19162306a36Sopenharmony_ci#define W83781D_REG_VID_FANDIV 0x47 19262306a36Sopenharmony_ci 19362306a36Sopenharmony_ci#define W83781D_REG_CHIPID 0x49 19462306a36Sopenharmony_ci#define W83781D_REG_WCHIPID 0x58 19562306a36Sopenharmony_ci#define W83781D_REG_CHIPMAN 0x4F 19662306a36Sopenharmony_ci#define W83781D_REG_PIN 0x4B 19762306a36Sopenharmony_ci 19862306a36Sopenharmony_ci#define W83781D_REG_VBAT 0x5D 19962306a36Sopenharmony_ci 20062306a36Sopenharmony_ci#define W83627HF_REG_PWM1 0x5A 20162306a36Sopenharmony_ci#define W83627HF_REG_PWM2 0x5B 20262306a36Sopenharmony_ci 20362306a36Sopenharmony_cistatic const u8 W83627THF_REG_PWM_ENABLE[] = { 20462306a36Sopenharmony_ci 0x04, /* FAN 1 mode */ 20562306a36Sopenharmony_ci 0x04, /* FAN 2 mode */ 20662306a36Sopenharmony_ci 0x12, /* FAN AUX mode */ 20762306a36Sopenharmony_ci}; 20862306a36Sopenharmony_cistatic const u8 W83627THF_PWM_ENABLE_SHIFT[] = { 2, 4, 1 }; 20962306a36Sopenharmony_ci 21062306a36Sopenharmony_ci#define W83627THF_REG_PWM1 0x01 /* 697HF/637HF/687THF too */ 21162306a36Sopenharmony_ci#define W83627THF_REG_PWM2 0x03 /* 697HF/637HF/687THF too */ 21262306a36Sopenharmony_ci#define W83627THF_REG_PWM3 0x11 /* 637HF/687THF too */ 21362306a36Sopenharmony_ci 21462306a36Sopenharmony_ci#define W83627THF_REG_VRM_OVT_CFG 0x18 /* 637HF/687THF too */ 21562306a36Sopenharmony_ci 21662306a36Sopenharmony_cistatic const u8 regpwm_627hf[] = { W83627HF_REG_PWM1, W83627HF_REG_PWM2 }; 21762306a36Sopenharmony_cistatic const u8 regpwm[] = { W83627THF_REG_PWM1, W83627THF_REG_PWM2, 21862306a36Sopenharmony_ci W83627THF_REG_PWM3 }; 21962306a36Sopenharmony_ci#define W836X7HF_REG_PWM(type, nr) (((type) == w83627hf) ? \ 22062306a36Sopenharmony_ci regpwm_627hf[nr] : regpwm[nr]) 22162306a36Sopenharmony_ci 22262306a36Sopenharmony_ci#define W83627HF_REG_PWM_FREQ 0x5C /* Only for the 627HF */ 22362306a36Sopenharmony_ci 22462306a36Sopenharmony_ci#define W83637HF_REG_PWM_FREQ1 0x00 /* 697HF/687THF too */ 22562306a36Sopenharmony_ci#define W83637HF_REG_PWM_FREQ2 0x02 /* 697HF/687THF too */ 22662306a36Sopenharmony_ci#define W83637HF_REG_PWM_FREQ3 0x10 /* 687THF too */ 22762306a36Sopenharmony_ci 22862306a36Sopenharmony_cistatic const u8 W83637HF_REG_PWM_FREQ[] = { W83637HF_REG_PWM_FREQ1, 22962306a36Sopenharmony_ci W83637HF_REG_PWM_FREQ2, 23062306a36Sopenharmony_ci W83637HF_REG_PWM_FREQ3 }; 23162306a36Sopenharmony_ci 23262306a36Sopenharmony_ci#define W83627HF_BASE_PWM_FREQ 46870 23362306a36Sopenharmony_ci 23462306a36Sopenharmony_ci#define W83781D_REG_I2C_ADDR 0x48 23562306a36Sopenharmony_ci#define W83781D_REG_I2C_SUBADDR 0x4A 23662306a36Sopenharmony_ci 23762306a36Sopenharmony_ci/* Sensor selection */ 23862306a36Sopenharmony_ci#define W83781D_REG_SCFG1 0x5D 23962306a36Sopenharmony_cistatic const u8 BIT_SCFG1[] = { 0x02, 0x04, 0x08 }; 24062306a36Sopenharmony_ci#define W83781D_REG_SCFG2 0x59 24162306a36Sopenharmony_cistatic const u8 BIT_SCFG2[] = { 0x10, 0x20, 0x40 }; 24262306a36Sopenharmony_ci#define W83781D_DEFAULT_BETA 3435 24362306a36Sopenharmony_ci 24462306a36Sopenharmony_ci/* 24562306a36Sopenharmony_ci * Conversions. Limit checking is only done on the TO_REG 24662306a36Sopenharmony_ci * variants. Note that you should be a bit careful with which arguments 24762306a36Sopenharmony_ci * these macros are called: arguments may be evaluated more than once. 24862306a36Sopenharmony_ci * Fixing this is just not worth it. 24962306a36Sopenharmony_ci */ 25062306a36Sopenharmony_ci#define IN_TO_REG(val) (clamp_val((((val) + 8) / 16), 0, 255)) 25162306a36Sopenharmony_ci#define IN_FROM_REG(val) ((val) * 16) 25262306a36Sopenharmony_ci 25362306a36Sopenharmony_cistatic inline u8 FAN_TO_REG(long rpm, int div) 25462306a36Sopenharmony_ci{ 25562306a36Sopenharmony_ci if (rpm == 0) 25662306a36Sopenharmony_ci return 255; 25762306a36Sopenharmony_ci rpm = clamp_val(rpm, 1, 1000000); 25862306a36Sopenharmony_ci return clamp_val((1350000 + rpm * div / 2) / (rpm * div), 1, 254); 25962306a36Sopenharmony_ci} 26062306a36Sopenharmony_ci 26162306a36Sopenharmony_ci#define TEMP_MIN (-128000) 26262306a36Sopenharmony_ci#define TEMP_MAX ( 127000) 26362306a36Sopenharmony_ci 26462306a36Sopenharmony_ci/* 26562306a36Sopenharmony_ci * TEMP: 0.001C/bit (-128C to +127C) 26662306a36Sopenharmony_ci * REG: 1C/bit, two's complement 26762306a36Sopenharmony_ci */ 26862306a36Sopenharmony_cistatic u8 TEMP_TO_REG(long temp) 26962306a36Sopenharmony_ci{ 27062306a36Sopenharmony_ci int ntemp = clamp_val(temp, TEMP_MIN, TEMP_MAX); 27162306a36Sopenharmony_ci ntemp += (ntemp < 0 ? -500 : 500); 27262306a36Sopenharmony_ci return (u8)(ntemp / 1000); 27362306a36Sopenharmony_ci} 27462306a36Sopenharmony_ci 27562306a36Sopenharmony_cistatic int TEMP_FROM_REG(u8 reg) 27662306a36Sopenharmony_ci{ 27762306a36Sopenharmony_ci return (s8)reg * 1000; 27862306a36Sopenharmony_ci} 27962306a36Sopenharmony_ci 28062306a36Sopenharmony_ci#define FAN_FROM_REG(val,div) ((val)==0?-1:(val)==255?0:1350000/((val)*(div))) 28162306a36Sopenharmony_ci 28262306a36Sopenharmony_ci#define PWM_TO_REG(val) (clamp_val((val), 0, 255)) 28362306a36Sopenharmony_ci 28462306a36Sopenharmony_cistatic inline unsigned long pwm_freq_from_reg_627hf(u8 reg) 28562306a36Sopenharmony_ci{ 28662306a36Sopenharmony_ci unsigned long freq; 28762306a36Sopenharmony_ci freq = W83627HF_BASE_PWM_FREQ >> reg; 28862306a36Sopenharmony_ci return freq; 28962306a36Sopenharmony_ci} 29062306a36Sopenharmony_cistatic inline u8 pwm_freq_to_reg_627hf(unsigned long val) 29162306a36Sopenharmony_ci{ 29262306a36Sopenharmony_ci u8 i; 29362306a36Sopenharmony_ci /* 29462306a36Sopenharmony_ci * Only 5 dividers (1 2 4 8 16) 29562306a36Sopenharmony_ci * Search for the nearest available frequency 29662306a36Sopenharmony_ci */ 29762306a36Sopenharmony_ci for (i = 0; i < 4; i++) { 29862306a36Sopenharmony_ci if (val > (((W83627HF_BASE_PWM_FREQ >> i) + 29962306a36Sopenharmony_ci (W83627HF_BASE_PWM_FREQ >> (i+1))) / 2)) 30062306a36Sopenharmony_ci break; 30162306a36Sopenharmony_ci } 30262306a36Sopenharmony_ci return i; 30362306a36Sopenharmony_ci} 30462306a36Sopenharmony_ci 30562306a36Sopenharmony_cistatic inline unsigned long pwm_freq_from_reg(u8 reg) 30662306a36Sopenharmony_ci{ 30762306a36Sopenharmony_ci /* Clock bit 8 -> 180 kHz or 24 MHz */ 30862306a36Sopenharmony_ci unsigned long clock = (reg & 0x80) ? 180000UL : 24000000UL; 30962306a36Sopenharmony_ci 31062306a36Sopenharmony_ci reg &= 0x7f; 31162306a36Sopenharmony_ci /* This should not happen but anyway... */ 31262306a36Sopenharmony_ci if (reg == 0) 31362306a36Sopenharmony_ci reg++; 31462306a36Sopenharmony_ci return clock / (reg << 8); 31562306a36Sopenharmony_ci} 31662306a36Sopenharmony_cistatic inline u8 pwm_freq_to_reg(unsigned long val) 31762306a36Sopenharmony_ci{ 31862306a36Sopenharmony_ci /* Minimum divider value is 0x01 and maximum is 0x7F */ 31962306a36Sopenharmony_ci if (val >= 93750) /* The highest we can do */ 32062306a36Sopenharmony_ci return 0x01; 32162306a36Sopenharmony_ci if (val >= 720) /* Use 24 MHz clock */ 32262306a36Sopenharmony_ci return 24000000UL / (val << 8); 32362306a36Sopenharmony_ci if (val < 6) /* The lowest we can do */ 32462306a36Sopenharmony_ci return 0xFF; 32562306a36Sopenharmony_ci else /* Use 180 kHz clock */ 32662306a36Sopenharmony_ci return 0x80 | (180000UL / (val << 8)); 32762306a36Sopenharmony_ci} 32862306a36Sopenharmony_ci 32962306a36Sopenharmony_ci#define BEEP_MASK_FROM_REG(val) ((val) & 0xff7fff) 33062306a36Sopenharmony_ci#define BEEP_MASK_TO_REG(val) ((val) & 0xff7fff) 33162306a36Sopenharmony_ci 33262306a36Sopenharmony_ci#define DIV_FROM_REG(val) (1 << (val)) 33362306a36Sopenharmony_ci 33462306a36Sopenharmony_cistatic inline u8 DIV_TO_REG(long val) 33562306a36Sopenharmony_ci{ 33662306a36Sopenharmony_ci int i; 33762306a36Sopenharmony_ci val = clamp_val(val, 1, 128) >> 1; 33862306a36Sopenharmony_ci for (i = 0; i < 7; i++) { 33962306a36Sopenharmony_ci if (val == 0) 34062306a36Sopenharmony_ci break; 34162306a36Sopenharmony_ci val >>= 1; 34262306a36Sopenharmony_ci } 34362306a36Sopenharmony_ci return (u8)i; 34462306a36Sopenharmony_ci} 34562306a36Sopenharmony_ci 34662306a36Sopenharmony_ci/* 34762306a36Sopenharmony_ci * For each registered chip, we need to keep some data in memory. 34862306a36Sopenharmony_ci * The structure is dynamically allocated. 34962306a36Sopenharmony_ci */ 35062306a36Sopenharmony_cistruct w83627hf_data { 35162306a36Sopenharmony_ci unsigned short addr; 35262306a36Sopenharmony_ci const char *name; 35362306a36Sopenharmony_ci struct device *hwmon_dev; 35462306a36Sopenharmony_ci struct mutex lock; 35562306a36Sopenharmony_ci enum chips type; 35662306a36Sopenharmony_ci 35762306a36Sopenharmony_ci struct mutex update_lock; 35862306a36Sopenharmony_ci bool valid; /* true if following fields are valid */ 35962306a36Sopenharmony_ci unsigned long last_updated; /* In jiffies */ 36062306a36Sopenharmony_ci 36162306a36Sopenharmony_ci u8 in[9]; /* Register value */ 36262306a36Sopenharmony_ci u8 in_max[9]; /* Register value */ 36362306a36Sopenharmony_ci u8 in_min[9]; /* Register value */ 36462306a36Sopenharmony_ci u8 fan[3]; /* Register value */ 36562306a36Sopenharmony_ci u8 fan_min[3]; /* Register value */ 36662306a36Sopenharmony_ci u16 temp[3]; /* Register value */ 36762306a36Sopenharmony_ci u16 temp_max[3]; /* Register value */ 36862306a36Sopenharmony_ci u16 temp_max_hyst[3]; /* Register value */ 36962306a36Sopenharmony_ci u8 fan_div[3]; /* Register encoding, shifted right */ 37062306a36Sopenharmony_ci u8 vid; /* Register encoding, combined */ 37162306a36Sopenharmony_ci u32 alarms; /* Register encoding, combined */ 37262306a36Sopenharmony_ci u32 beep_mask; /* Register encoding, combined */ 37362306a36Sopenharmony_ci u8 pwm[3]; /* Register value */ 37462306a36Sopenharmony_ci u8 pwm_enable[3]; /* 1 = manual 37562306a36Sopenharmony_ci * 2 = thermal cruise (also called SmartFan I) 37662306a36Sopenharmony_ci * 3 = fan speed cruise 37762306a36Sopenharmony_ci */ 37862306a36Sopenharmony_ci u8 pwm_freq[3]; /* Register value */ 37962306a36Sopenharmony_ci u16 sens[3]; /* 1 = pentium diode; 2 = 3904 diode; 38062306a36Sopenharmony_ci * 4 = thermistor 38162306a36Sopenharmony_ci */ 38262306a36Sopenharmony_ci u8 vrm; 38362306a36Sopenharmony_ci u8 vrm_ovt; /* Register value, 627THF/637HF/687THF only */ 38462306a36Sopenharmony_ci 38562306a36Sopenharmony_ci#ifdef CONFIG_PM 38662306a36Sopenharmony_ci /* Remember extra register values over suspend/resume */ 38762306a36Sopenharmony_ci u8 scfg1; 38862306a36Sopenharmony_ci u8 scfg2; 38962306a36Sopenharmony_ci#endif 39062306a36Sopenharmony_ci}; 39162306a36Sopenharmony_ci 39262306a36Sopenharmony_ci/* Registers 0x50-0x5f are banked */ 39362306a36Sopenharmony_cistatic inline void w83627hf_set_bank(struct w83627hf_data *data, u16 reg) 39462306a36Sopenharmony_ci{ 39562306a36Sopenharmony_ci if ((reg & 0x00f0) == 0x50) { 39662306a36Sopenharmony_ci outb_p(W83781D_REG_BANK, data->addr + W83781D_ADDR_REG_OFFSET); 39762306a36Sopenharmony_ci outb_p(reg >> 8, data->addr + W83781D_DATA_REG_OFFSET); 39862306a36Sopenharmony_ci } 39962306a36Sopenharmony_ci} 40062306a36Sopenharmony_ci 40162306a36Sopenharmony_ci/* Not strictly necessary, but play it safe for now */ 40262306a36Sopenharmony_cistatic inline void w83627hf_reset_bank(struct w83627hf_data *data, u16 reg) 40362306a36Sopenharmony_ci{ 40462306a36Sopenharmony_ci if (reg & 0xff00) { 40562306a36Sopenharmony_ci outb_p(W83781D_REG_BANK, data->addr + W83781D_ADDR_REG_OFFSET); 40662306a36Sopenharmony_ci outb_p(0, data->addr + W83781D_DATA_REG_OFFSET); 40762306a36Sopenharmony_ci } 40862306a36Sopenharmony_ci} 40962306a36Sopenharmony_ci 41062306a36Sopenharmony_cistatic int w83627hf_read_value(struct w83627hf_data *data, u16 reg) 41162306a36Sopenharmony_ci{ 41262306a36Sopenharmony_ci int res, word_sized; 41362306a36Sopenharmony_ci 41462306a36Sopenharmony_ci mutex_lock(&data->lock); 41562306a36Sopenharmony_ci word_sized = (((reg & 0xff00) == 0x100) 41662306a36Sopenharmony_ci || ((reg & 0xff00) == 0x200)) 41762306a36Sopenharmony_ci && (((reg & 0x00ff) == 0x50) 41862306a36Sopenharmony_ci || ((reg & 0x00ff) == 0x53) 41962306a36Sopenharmony_ci || ((reg & 0x00ff) == 0x55)); 42062306a36Sopenharmony_ci w83627hf_set_bank(data, reg); 42162306a36Sopenharmony_ci outb_p(reg & 0xff, data->addr + W83781D_ADDR_REG_OFFSET); 42262306a36Sopenharmony_ci res = inb_p(data->addr + W83781D_DATA_REG_OFFSET); 42362306a36Sopenharmony_ci if (word_sized) { 42462306a36Sopenharmony_ci outb_p((reg & 0xff) + 1, 42562306a36Sopenharmony_ci data->addr + W83781D_ADDR_REG_OFFSET); 42662306a36Sopenharmony_ci res = 42762306a36Sopenharmony_ci (res << 8) + inb_p(data->addr + 42862306a36Sopenharmony_ci W83781D_DATA_REG_OFFSET); 42962306a36Sopenharmony_ci } 43062306a36Sopenharmony_ci w83627hf_reset_bank(data, reg); 43162306a36Sopenharmony_ci mutex_unlock(&data->lock); 43262306a36Sopenharmony_ci return res; 43362306a36Sopenharmony_ci} 43462306a36Sopenharmony_ci 43562306a36Sopenharmony_cistatic int w83627hf_write_value(struct w83627hf_data *data, u16 reg, u16 value) 43662306a36Sopenharmony_ci{ 43762306a36Sopenharmony_ci int word_sized; 43862306a36Sopenharmony_ci 43962306a36Sopenharmony_ci mutex_lock(&data->lock); 44062306a36Sopenharmony_ci word_sized = (((reg & 0xff00) == 0x100) 44162306a36Sopenharmony_ci || ((reg & 0xff00) == 0x200)) 44262306a36Sopenharmony_ci && (((reg & 0x00ff) == 0x53) 44362306a36Sopenharmony_ci || ((reg & 0x00ff) == 0x55)); 44462306a36Sopenharmony_ci w83627hf_set_bank(data, reg); 44562306a36Sopenharmony_ci outb_p(reg & 0xff, data->addr + W83781D_ADDR_REG_OFFSET); 44662306a36Sopenharmony_ci if (word_sized) { 44762306a36Sopenharmony_ci outb_p(value >> 8, 44862306a36Sopenharmony_ci data->addr + W83781D_DATA_REG_OFFSET); 44962306a36Sopenharmony_ci outb_p((reg & 0xff) + 1, 45062306a36Sopenharmony_ci data->addr + W83781D_ADDR_REG_OFFSET); 45162306a36Sopenharmony_ci } 45262306a36Sopenharmony_ci outb_p(value & 0xff, 45362306a36Sopenharmony_ci data->addr + W83781D_DATA_REG_OFFSET); 45462306a36Sopenharmony_ci w83627hf_reset_bank(data, reg); 45562306a36Sopenharmony_ci mutex_unlock(&data->lock); 45662306a36Sopenharmony_ci return 0; 45762306a36Sopenharmony_ci} 45862306a36Sopenharmony_ci 45962306a36Sopenharmony_cistatic void w83627hf_update_fan_div(struct w83627hf_data *data) 46062306a36Sopenharmony_ci{ 46162306a36Sopenharmony_ci int reg; 46262306a36Sopenharmony_ci 46362306a36Sopenharmony_ci reg = w83627hf_read_value(data, W83781D_REG_VID_FANDIV); 46462306a36Sopenharmony_ci data->fan_div[0] = (reg >> 4) & 0x03; 46562306a36Sopenharmony_ci data->fan_div[1] = (reg >> 6) & 0x03; 46662306a36Sopenharmony_ci if (data->type != w83697hf) { 46762306a36Sopenharmony_ci data->fan_div[2] = (w83627hf_read_value(data, 46862306a36Sopenharmony_ci W83781D_REG_PIN) >> 6) & 0x03; 46962306a36Sopenharmony_ci } 47062306a36Sopenharmony_ci reg = w83627hf_read_value(data, W83781D_REG_VBAT); 47162306a36Sopenharmony_ci data->fan_div[0] |= (reg >> 3) & 0x04; 47262306a36Sopenharmony_ci data->fan_div[1] |= (reg >> 4) & 0x04; 47362306a36Sopenharmony_ci if (data->type != w83697hf) 47462306a36Sopenharmony_ci data->fan_div[2] |= (reg >> 5) & 0x04; 47562306a36Sopenharmony_ci} 47662306a36Sopenharmony_ci 47762306a36Sopenharmony_cistatic struct w83627hf_data *w83627hf_update_device(struct device *dev) 47862306a36Sopenharmony_ci{ 47962306a36Sopenharmony_ci struct w83627hf_data *data = dev_get_drvdata(dev); 48062306a36Sopenharmony_ci int i, num_temps = (data->type == w83697hf) ? 2 : 3; 48162306a36Sopenharmony_ci int num_pwms = (data->type == w83697hf) ? 2 : 3; 48262306a36Sopenharmony_ci 48362306a36Sopenharmony_ci mutex_lock(&data->update_lock); 48462306a36Sopenharmony_ci 48562306a36Sopenharmony_ci if (time_after(jiffies, data->last_updated + HZ + HZ / 2) 48662306a36Sopenharmony_ci || !data->valid) { 48762306a36Sopenharmony_ci for (i = 0; i <= 8; i++) { 48862306a36Sopenharmony_ci /* skip missing sensors */ 48962306a36Sopenharmony_ci if (((data->type == w83697hf) && (i == 1)) || 49062306a36Sopenharmony_ci ((data->type != w83627hf && data->type != w83697hf) 49162306a36Sopenharmony_ci && (i == 5 || i == 6))) 49262306a36Sopenharmony_ci continue; 49362306a36Sopenharmony_ci data->in[i] = 49462306a36Sopenharmony_ci w83627hf_read_value(data, W83781D_REG_IN(i)); 49562306a36Sopenharmony_ci data->in_min[i] = 49662306a36Sopenharmony_ci w83627hf_read_value(data, 49762306a36Sopenharmony_ci W83781D_REG_IN_MIN(i)); 49862306a36Sopenharmony_ci data->in_max[i] = 49962306a36Sopenharmony_ci w83627hf_read_value(data, 50062306a36Sopenharmony_ci W83781D_REG_IN_MAX(i)); 50162306a36Sopenharmony_ci } 50262306a36Sopenharmony_ci for (i = 0; i <= 2; i++) { 50362306a36Sopenharmony_ci data->fan[i] = 50462306a36Sopenharmony_ci w83627hf_read_value(data, W83627HF_REG_FAN(i)); 50562306a36Sopenharmony_ci data->fan_min[i] = 50662306a36Sopenharmony_ci w83627hf_read_value(data, 50762306a36Sopenharmony_ci W83627HF_REG_FAN_MIN(i)); 50862306a36Sopenharmony_ci } 50962306a36Sopenharmony_ci for (i = 0; i <= 2; i++) { 51062306a36Sopenharmony_ci u8 tmp = w83627hf_read_value(data, 51162306a36Sopenharmony_ci W836X7HF_REG_PWM(data->type, i)); 51262306a36Sopenharmony_ci /* bits 0-3 are reserved in 627THF */ 51362306a36Sopenharmony_ci if (data->type == w83627thf) 51462306a36Sopenharmony_ci tmp &= 0xf0; 51562306a36Sopenharmony_ci data->pwm[i] = tmp; 51662306a36Sopenharmony_ci if (i == 1 && 51762306a36Sopenharmony_ci (data->type == w83627hf || data->type == w83697hf)) 51862306a36Sopenharmony_ci break; 51962306a36Sopenharmony_ci } 52062306a36Sopenharmony_ci if (data->type == w83627hf) { 52162306a36Sopenharmony_ci u8 tmp = w83627hf_read_value(data, 52262306a36Sopenharmony_ci W83627HF_REG_PWM_FREQ); 52362306a36Sopenharmony_ci data->pwm_freq[0] = tmp & 0x07; 52462306a36Sopenharmony_ci data->pwm_freq[1] = (tmp >> 4) & 0x07; 52562306a36Sopenharmony_ci } else if (data->type != w83627thf) { 52662306a36Sopenharmony_ci for (i = 1; i <= 3; i++) { 52762306a36Sopenharmony_ci data->pwm_freq[i - 1] = 52862306a36Sopenharmony_ci w83627hf_read_value(data, 52962306a36Sopenharmony_ci W83637HF_REG_PWM_FREQ[i - 1]); 53062306a36Sopenharmony_ci if (i == 2 && (data->type == w83697hf)) 53162306a36Sopenharmony_ci break; 53262306a36Sopenharmony_ci } 53362306a36Sopenharmony_ci } 53462306a36Sopenharmony_ci if (data->type != w83627hf) { 53562306a36Sopenharmony_ci for (i = 0; i < num_pwms; i++) { 53662306a36Sopenharmony_ci u8 tmp = w83627hf_read_value(data, 53762306a36Sopenharmony_ci W83627THF_REG_PWM_ENABLE[i]); 53862306a36Sopenharmony_ci data->pwm_enable[i] = 53962306a36Sopenharmony_ci ((tmp >> W83627THF_PWM_ENABLE_SHIFT[i]) 54062306a36Sopenharmony_ci & 0x03) + 1; 54162306a36Sopenharmony_ci } 54262306a36Sopenharmony_ci } 54362306a36Sopenharmony_ci for (i = 0; i < num_temps; i++) { 54462306a36Sopenharmony_ci data->temp[i] = w83627hf_read_value( 54562306a36Sopenharmony_ci data, w83627hf_reg_temp[i]); 54662306a36Sopenharmony_ci data->temp_max[i] = w83627hf_read_value( 54762306a36Sopenharmony_ci data, w83627hf_reg_temp_over[i]); 54862306a36Sopenharmony_ci data->temp_max_hyst[i] = w83627hf_read_value( 54962306a36Sopenharmony_ci data, w83627hf_reg_temp_hyst[i]); 55062306a36Sopenharmony_ci } 55162306a36Sopenharmony_ci 55262306a36Sopenharmony_ci w83627hf_update_fan_div(data); 55362306a36Sopenharmony_ci 55462306a36Sopenharmony_ci data->alarms = 55562306a36Sopenharmony_ci w83627hf_read_value(data, W83781D_REG_ALARM1) | 55662306a36Sopenharmony_ci (w83627hf_read_value(data, W83781D_REG_ALARM2) << 8) | 55762306a36Sopenharmony_ci (w83627hf_read_value(data, W83781D_REG_ALARM3) << 16); 55862306a36Sopenharmony_ci i = w83627hf_read_value(data, W83781D_REG_BEEP_INTS2); 55962306a36Sopenharmony_ci data->beep_mask = (i << 8) | 56062306a36Sopenharmony_ci w83627hf_read_value(data, W83781D_REG_BEEP_INTS1) | 56162306a36Sopenharmony_ci w83627hf_read_value(data, W83781D_REG_BEEP_INTS3) << 16; 56262306a36Sopenharmony_ci data->last_updated = jiffies; 56362306a36Sopenharmony_ci data->valid = true; 56462306a36Sopenharmony_ci } 56562306a36Sopenharmony_ci 56662306a36Sopenharmony_ci mutex_unlock(&data->update_lock); 56762306a36Sopenharmony_ci 56862306a36Sopenharmony_ci return data; 56962306a36Sopenharmony_ci} 57062306a36Sopenharmony_ci 57162306a36Sopenharmony_ci#ifdef CONFIG_PM 57262306a36Sopenharmony_cistatic int w83627hf_suspend(struct device *dev) 57362306a36Sopenharmony_ci{ 57462306a36Sopenharmony_ci struct w83627hf_data *data = w83627hf_update_device(dev); 57562306a36Sopenharmony_ci 57662306a36Sopenharmony_ci mutex_lock(&data->update_lock); 57762306a36Sopenharmony_ci data->scfg1 = w83627hf_read_value(data, W83781D_REG_SCFG1); 57862306a36Sopenharmony_ci data->scfg2 = w83627hf_read_value(data, W83781D_REG_SCFG2); 57962306a36Sopenharmony_ci mutex_unlock(&data->update_lock); 58062306a36Sopenharmony_ci 58162306a36Sopenharmony_ci return 0; 58262306a36Sopenharmony_ci} 58362306a36Sopenharmony_ci 58462306a36Sopenharmony_cistatic int w83627hf_resume(struct device *dev) 58562306a36Sopenharmony_ci{ 58662306a36Sopenharmony_ci struct w83627hf_data *data = dev_get_drvdata(dev); 58762306a36Sopenharmony_ci int i, num_temps = (data->type == w83697hf) ? 2 : 3; 58862306a36Sopenharmony_ci 58962306a36Sopenharmony_ci /* Restore limits */ 59062306a36Sopenharmony_ci mutex_lock(&data->update_lock); 59162306a36Sopenharmony_ci for (i = 0; i <= 8; i++) { 59262306a36Sopenharmony_ci /* skip missing sensors */ 59362306a36Sopenharmony_ci if (((data->type == w83697hf) && (i == 1)) || 59462306a36Sopenharmony_ci ((data->type != w83627hf && data->type != w83697hf) 59562306a36Sopenharmony_ci && (i == 5 || i == 6))) 59662306a36Sopenharmony_ci continue; 59762306a36Sopenharmony_ci w83627hf_write_value(data, W83781D_REG_IN_MAX(i), 59862306a36Sopenharmony_ci data->in_max[i]); 59962306a36Sopenharmony_ci w83627hf_write_value(data, W83781D_REG_IN_MIN(i), 60062306a36Sopenharmony_ci data->in_min[i]); 60162306a36Sopenharmony_ci } 60262306a36Sopenharmony_ci for (i = 0; i <= 2; i++) 60362306a36Sopenharmony_ci w83627hf_write_value(data, W83627HF_REG_FAN_MIN(i), 60462306a36Sopenharmony_ci data->fan_min[i]); 60562306a36Sopenharmony_ci for (i = 0; i < num_temps; i++) { 60662306a36Sopenharmony_ci w83627hf_write_value(data, w83627hf_reg_temp_over[i], 60762306a36Sopenharmony_ci data->temp_max[i]); 60862306a36Sopenharmony_ci w83627hf_write_value(data, w83627hf_reg_temp_hyst[i], 60962306a36Sopenharmony_ci data->temp_max_hyst[i]); 61062306a36Sopenharmony_ci } 61162306a36Sopenharmony_ci 61262306a36Sopenharmony_ci /* Fixup BIOS bugs */ 61362306a36Sopenharmony_ci if (data->type == w83627thf || data->type == w83637hf || 61462306a36Sopenharmony_ci data->type == w83687thf) 61562306a36Sopenharmony_ci w83627hf_write_value(data, W83627THF_REG_VRM_OVT_CFG, 61662306a36Sopenharmony_ci data->vrm_ovt); 61762306a36Sopenharmony_ci w83627hf_write_value(data, W83781D_REG_SCFG1, data->scfg1); 61862306a36Sopenharmony_ci w83627hf_write_value(data, W83781D_REG_SCFG2, data->scfg2); 61962306a36Sopenharmony_ci 62062306a36Sopenharmony_ci /* Force re-reading all values */ 62162306a36Sopenharmony_ci data->valid = false; 62262306a36Sopenharmony_ci mutex_unlock(&data->update_lock); 62362306a36Sopenharmony_ci 62462306a36Sopenharmony_ci return 0; 62562306a36Sopenharmony_ci} 62662306a36Sopenharmony_ci 62762306a36Sopenharmony_cistatic const struct dev_pm_ops w83627hf_dev_pm_ops = { 62862306a36Sopenharmony_ci .suspend = w83627hf_suspend, 62962306a36Sopenharmony_ci .resume = w83627hf_resume, 63062306a36Sopenharmony_ci}; 63162306a36Sopenharmony_ci 63262306a36Sopenharmony_ci#define W83627HF_DEV_PM_OPS (&w83627hf_dev_pm_ops) 63362306a36Sopenharmony_ci#else 63462306a36Sopenharmony_ci#define W83627HF_DEV_PM_OPS NULL 63562306a36Sopenharmony_ci#endif /* CONFIG_PM */ 63662306a36Sopenharmony_ci 63762306a36Sopenharmony_cistatic int w83627thf_read_gpio5(struct platform_device *pdev) 63862306a36Sopenharmony_ci{ 63962306a36Sopenharmony_ci struct w83627hf_sio_data *sio_data = dev_get_platdata(&pdev->dev); 64062306a36Sopenharmony_ci int res = 0xff, sel; 64162306a36Sopenharmony_ci 64262306a36Sopenharmony_ci if (superio_enter(sio_data)) { 64362306a36Sopenharmony_ci /* 64462306a36Sopenharmony_ci * Some other driver reserved the address space for itself. 64562306a36Sopenharmony_ci * We don't want to fail driver instantiation because of that, 64662306a36Sopenharmony_ci * so display a warning and keep going. 64762306a36Sopenharmony_ci */ 64862306a36Sopenharmony_ci dev_warn(&pdev->dev, 64962306a36Sopenharmony_ci "Can not read VID data: Failed to enable SuperIO access\n"); 65062306a36Sopenharmony_ci return res; 65162306a36Sopenharmony_ci } 65262306a36Sopenharmony_ci 65362306a36Sopenharmony_ci superio_select(sio_data, W83627HF_LD_GPIO5); 65462306a36Sopenharmony_ci 65562306a36Sopenharmony_ci res = 0xff; 65662306a36Sopenharmony_ci 65762306a36Sopenharmony_ci /* Make sure these GPIO pins are enabled */ 65862306a36Sopenharmony_ci if (!(superio_inb(sio_data, W83627THF_GPIO5_EN) & (1<<3))) { 65962306a36Sopenharmony_ci dev_dbg(&pdev->dev, "GPIO5 disabled, no VID function\n"); 66062306a36Sopenharmony_ci goto exit; 66162306a36Sopenharmony_ci } 66262306a36Sopenharmony_ci 66362306a36Sopenharmony_ci /* 66462306a36Sopenharmony_ci * Make sure the pins are configured for input 66562306a36Sopenharmony_ci * There must be at least five (VRM 9), and possibly 6 (VRM 10) 66662306a36Sopenharmony_ci */ 66762306a36Sopenharmony_ci sel = superio_inb(sio_data, W83627THF_GPIO5_IOSR) & 0x3f; 66862306a36Sopenharmony_ci if ((sel & 0x1f) != 0x1f) { 66962306a36Sopenharmony_ci dev_dbg(&pdev->dev, "GPIO5 not configured for VID " 67062306a36Sopenharmony_ci "function\n"); 67162306a36Sopenharmony_ci goto exit; 67262306a36Sopenharmony_ci } 67362306a36Sopenharmony_ci 67462306a36Sopenharmony_ci dev_info(&pdev->dev, "Reading VID from GPIO5\n"); 67562306a36Sopenharmony_ci res = superio_inb(sio_data, W83627THF_GPIO5_DR) & sel; 67662306a36Sopenharmony_ci 67762306a36Sopenharmony_ciexit: 67862306a36Sopenharmony_ci superio_exit(sio_data); 67962306a36Sopenharmony_ci return res; 68062306a36Sopenharmony_ci} 68162306a36Sopenharmony_ci 68262306a36Sopenharmony_cistatic int w83687thf_read_vid(struct platform_device *pdev) 68362306a36Sopenharmony_ci{ 68462306a36Sopenharmony_ci struct w83627hf_sio_data *sio_data = dev_get_platdata(&pdev->dev); 68562306a36Sopenharmony_ci int res = 0xff; 68662306a36Sopenharmony_ci 68762306a36Sopenharmony_ci if (superio_enter(sio_data)) { 68862306a36Sopenharmony_ci /* 68962306a36Sopenharmony_ci * Some other driver reserved the address space for itself. 69062306a36Sopenharmony_ci * We don't want to fail driver instantiation because of that, 69162306a36Sopenharmony_ci * so display a warning and keep going. 69262306a36Sopenharmony_ci */ 69362306a36Sopenharmony_ci dev_warn(&pdev->dev, 69462306a36Sopenharmony_ci "Can not read VID data: Failed to enable SuperIO access\n"); 69562306a36Sopenharmony_ci return res; 69662306a36Sopenharmony_ci } 69762306a36Sopenharmony_ci 69862306a36Sopenharmony_ci superio_select(sio_data, W83627HF_LD_HWM); 69962306a36Sopenharmony_ci 70062306a36Sopenharmony_ci /* Make sure these GPIO pins are enabled */ 70162306a36Sopenharmony_ci if (!(superio_inb(sio_data, W83687THF_VID_EN) & (1 << 2))) { 70262306a36Sopenharmony_ci dev_dbg(&pdev->dev, "VID disabled, no VID function\n"); 70362306a36Sopenharmony_ci goto exit; 70462306a36Sopenharmony_ci } 70562306a36Sopenharmony_ci 70662306a36Sopenharmony_ci /* Make sure the pins are configured for input */ 70762306a36Sopenharmony_ci if (!(superio_inb(sio_data, W83687THF_VID_CFG) & (1 << 4))) { 70862306a36Sopenharmony_ci dev_dbg(&pdev->dev, "VID configured as output, " 70962306a36Sopenharmony_ci "no VID function\n"); 71062306a36Sopenharmony_ci goto exit; 71162306a36Sopenharmony_ci } 71262306a36Sopenharmony_ci 71362306a36Sopenharmony_ci res = superio_inb(sio_data, W83687THF_VID_DATA) & 0x3f; 71462306a36Sopenharmony_ci 71562306a36Sopenharmony_ciexit: 71662306a36Sopenharmony_ci superio_exit(sio_data); 71762306a36Sopenharmony_ci return res; 71862306a36Sopenharmony_ci} 71962306a36Sopenharmony_ci 72062306a36Sopenharmony_cistatic void w83627hf_init_device(struct platform_device *pdev) 72162306a36Sopenharmony_ci{ 72262306a36Sopenharmony_ci struct w83627hf_data *data = platform_get_drvdata(pdev); 72362306a36Sopenharmony_ci int i; 72462306a36Sopenharmony_ci enum chips type = data->type; 72562306a36Sopenharmony_ci u8 tmp; 72662306a36Sopenharmony_ci 72762306a36Sopenharmony_ci /* Minimize conflicts with other winbond i2c-only clients... */ 72862306a36Sopenharmony_ci /* disable i2c subclients... how to disable main i2c client?? */ 72962306a36Sopenharmony_ci /* force i2c address to relatively uncommon address */ 73062306a36Sopenharmony_ci if (type == w83627hf) { 73162306a36Sopenharmony_ci w83627hf_write_value(data, W83781D_REG_I2C_SUBADDR, 0x89); 73262306a36Sopenharmony_ci w83627hf_write_value(data, W83781D_REG_I2C_ADDR, force_i2c); 73362306a36Sopenharmony_ci } 73462306a36Sopenharmony_ci 73562306a36Sopenharmony_ci /* Read VID only once */ 73662306a36Sopenharmony_ci if (type == w83627hf || type == w83637hf) { 73762306a36Sopenharmony_ci int lo = w83627hf_read_value(data, W83781D_REG_VID_FANDIV); 73862306a36Sopenharmony_ci int hi = w83627hf_read_value(data, W83781D_REG_CHIPID); 73962306a36Sopenharmony_ci data->vid = (lo & 0x0f) | ((hi & 0x01) << 4); 74062306a36Sopenharmony_ci } else if (type == w83627thf) { 74162306a36Sopenharmony_ci data->vid = w83627thf_read_gpio5(pdev); 74262306a36Sopenharmony_ci } else if (type == w83687thf) { 74362306a36Sopenharmony_ci data->vid = w83687thf_read_vid(pdev); 74462306a36Sopenharmony_ci } 74562306a36Sopenharmony_ci 74662306a36Sopenharmony_ci /* Read VRM & OVT Config only once */ 74762306a36Sopenharmony_ci if (type == w83627thf || type == w83637hf || type == w83687thf) { 74862306a36Sopenharmony_ci data->vrm_ovt = 74962306a36Sopenharmony_ci w83627hf_read_value(data, W83627THF_REG_VRM_OVT_CFG); 75062306a36Sopenharmony_ci } 75162306a36Sopenharmony_ci 75262306a36Sopenharmony_ci tmp = w83627hf_read_value(data, W83781D_REG_SCFG1); 75362306a36Sopenharmony_ci for (i = 1; i <= 3; i++) { 75462306a36Sopenharmony_ci if (!(tmp & BIT_SCFG1[i - 1])) { 75562306a36Sopenharmony_ci data->sens[i - 1] = 4; 75662306a36Sopenharmony_ci } else { 75762306a36Sopenharmony_ci if (w83627hf_read_value 75862306a36Sopenharmony_ci (data, 75962306a36Sopenharmony_ci W83781D_REG_SCFG2) & BIT_SCFG2[i - 1]) 76062306a36Sopenharmony_ci data->sens[i - 1] = 1; 76162306a36Sopenharmony_ci else 76262306a36Sopenharmony_ci data->sens[i - 1] = 2; 76362306a36Sopenharmony_ci } 76462306a36Sopenharmony_ci if ((type == w83697hf) && (i == 2)) 76562306a36Sopenharmony_ci break; 76662306a36Sopenharmony_ci } 76762306a36Sopenharmony_ci 76862306a36Sopenharmony_ci if(init) { 76962306a36Sopenharmony_ci /* Enable temp2 */ 77062306a36Sopenharmony_ci tmp = w83627hf_read_value(data, W83627HF_REG_TEMP2_CONFIG); 77162306a36Sopenharmony_ci if (tmp & 0x01) { 77262306a36Sopenharmony_ci dev_warn(&pdev->dev, "Enabling temp2, readings " 77362306a36Sopenharmony_ci "might not make sense\n"); 77462306a36Sopenharmony_ci w83627hf_write_value(data, W83627HF_REG_TEMP2_CONFIG, 77562306a36Sopenharmony_ci tmp & 0xfe); 77662306a36Sopenharmony_ci } 77762306a36Sopenharmony_ci 77862306a36Sopenharmony_ci /* Enable temp3 */ 77962306a36Sopenharmony_ci if (type != w83697hf) { 78062306a36Sopenharmony_ci tmp = w83627hf_read_value(data, 78162306a36Sopenharmony_ci W83627HF_REG_TEMP3_CONFIG); 78262306a36Sopenharmony_ci if (tmp & 0x01) { 78362306a36Sopenharmony_ci dev_warn(&pdev->dev, "Enabling temp3, " 78462306a36Sopenharmony_ci "readings might not make sense\n"); 78562306a36Sopenharmony_ci w83627hf_write_value(data, 78662306a36Sopenharmony_ci W83627HF_REG_TEMP3_CONFIG, tmp & 0xfe); 78762306a36Sopenharmony_ci } 78862306a36Sopenharmony_ci } 78962306a36Sopenharmony_ci } 79062306a36Sopenharmony_ci 79162306a36Sopenharmony_ci /* Start monitoring */ 79262306a36Sopenharmony_ci w83627hf_write_value(data, W83781D_REG_CONFIG, 79362306a36Sopenharmony_ci (w83627hf_read_value(data, 79462306a36Sopenharmony_ci W83781D_REG_CONFIG) & 0xf7) 79562306a36Sopenharmony_ci | 0x01); 79662306a36Sopenharmony_ci 79762306a36Sopenharmony_ci /* Enable VBAT monitoring if needed */ 79862306a36Sopenharmony_ci tmp = w83627hf_read_value(data, W83781D_REG_VBAT); 79962306a36Sopenharmony_ci if (!(tmp & 0x01)) 80062306a36Sopenharmony_ci w83627hf_write_value(data, W83781D_REG_VBAT, tmp | 0x01); 80162306a36Sopenharmony_ci} 80262306a36Sopenharmony_ci 80362306a36Sopenharmony_ci/* use a different set of functions for in0 */ 80462306a36Sopenharmony_cistatic ssize_t show_in_0(struct w83627hf_data *data, char *buf, u8 reg) 80562306a36Sopenharmony_ci{ 80662306a36Sopenharmony_ci long in0; 80762306a36Sopenharmony_ci 80862306a36Sopenharmony_ci if ((data->vrm_ovt & 0x01) && 80962306a36Sopenharmony_ci (w83627thf == data->type || w83637hf == data->type 81062306a36Sopenharmony_ci || w83687thf == data->type)) 81162306a36Sopenharmony_ci 81262306a36Sopenharmony_ci /* use VRM9 calculation */ 81362306a36Sopenharmony_ci in0 = (long)((reg * 488 + 70000 + 50) / 100); 81462306a36Sopenharmony_ci else 81562306a36Sopenharmony_ci /* use VRM8 (standard) calculation */ 81662306a36Sopenharmony_ci in0 = (long)IN_FROM_REG(reg); 81762306a36Sopenharmony_ci 81862306a36Sopenharmony_ci return sprintf(buf,"%ld\n", in0); 81962306a36Sopenharmony_ci} 82062306a36Sopenharmony_ci 82162306a36Sopenharmony_cistatic ssize_t in0_input_show(struct device *dev, 82262306a36Sopenharmony_ci struct device_attribute *attr, char *buf) 82362306a36Sopenharmony_ci{ 82462306a36Sopenharmony_ci struct w83627hf_data *data = w83627hf_update_device(dev); 82562306a36Sopenharmony_ci return show_in_0(data, buf, data->in[0]); 82662306a36Sopenharmony_ci} 82762306a36Sopenharmony_cistatic DEVICE_ATTR_RO(in0_input); 82862306a36Sopenharmony_ci 82962306a36Sopenharmony_cistatic ssize_t in0_min_show(struct device *dev, struct device_attribute *attr, 83062306a36Sopenharmony_ci char *buf) 83162306a36Sopenharmony_ci{ 83262306a36Sopenharmony_ci struct w83627hf_data *data = w83627hf_update_device(dev); 83362306a36Sopenharmony_ci return show_in_0(data, buf, data->in_min[0]); 83462306a36Sopenharmony_ci} 83562306a36Sopenharmony_ci 83662306a36Sopenharmony_cistatic ssize_t in0_min_store(struct device *dev, 83762306a36Sopenharmony_ci struct device_attribute *attr, const char *buf, 83862306a36Sopenharmony_ci size_t count) 83962306a36Sopenharmony_ci{ 84062306a36Sopenharmony_ci struct w83627hf_data *data = dev_get_drvdata(dev); 84162306a36Sopenharmony_ci unsigned long val; 84262306a36Sopenharmony_ci int err; 84362306a36Sopenharmony_ci 84462306a36Sopenharmony_ci err = kstrtoul(buf, 10, &val); 84562306a36Sopenharmony_ci if (err) 84662306a36Sopenharmony_ci return err; 84762306a36Sopenharmony_ci 84862306a36Sopenharmony_ci mutex_lock(&data->update_lock); 84962306a36Sopenharmony_ci 85062306a36Sopenharmony_ci if ((data->vrm_ovt & 0x01) && 85162306a36Sopenharmony_ci (w83627thf == data->type || w83637hf == data->type 85262306a36Sopenharmony_ci || w83687thf == data->type)) 85362306a36Sopenharmony_ci 85462306a36Sopenharmony_ci /* use VRM9 calculation */ 85562306a36Sopenharmony_ci data->in_min[0] = 85662306a36Sopenharmony_ci clamp_val(((val * 100) - 70000 + 244) / 488, 0, 255); 85762306a36Sopenharmony_ci else 85862306a36Sopenharmony_ci /* use VRM8 (standard) calculation */ 85962306a36Sopenharmony_ci data->in_min[0] = IN_TO_REG(val); 86062306a36Sopenharmony_ci 86162306a36Sopenharmony_ci w83627hf_write_value(data, W83781D_REG_IN_MIN(0), data->in_min[0]); 86262306a36Sopenharmony_ci mutex_unlock(&data->update_lock); 86362306a36Sopenharmony_ci return count; 86462306a36Sopenharmony_ci} 86562306a36Sopenharmony_ci 86662306a36Sopenharmony_cistatic DEVICE_ATTR_RW(in0_min); 86762306a36Sopenharmony_ci 86862306a36Sopenharmony_cistatic ssize_t in0_max_show(struct device *dev, struct device_attribute *attr, 86962306a36Sopenharmony_ci char *buf) 87062306a36Sopenharmony_ci{ 87162306a36Sopenharmony_ci struct w83627hf_data *data = w83627hf_update_device(dev); 87262306a36Sopenharmony_ci return show_in_0(data, buf, data->in_max[0]); 87362306a36Sopenharmony_ci} 87462306a36Sopenharmony_ci 87562306a36Sopenharmony_cistatic ssize_t in0_max_store(struct device *dev, 87662306a36Sopenharmony_ci struct device_attribute *attr, const char *buf, 87762306a36Sopenharmony_ci size_t count) 87862306a36Sopenharmony_ci{ 87962306a36Sopenharmony_ci struct w83627hf_data *data = dev_get_drvdata(dev); 88062306a36Sopenharmony_ci unsigned long val; 88162306a36Sopenharmony_ci int err; 88262306a36Sopenharmony_ci 88362306a36Sopenharmony_ci err = kstrtoul(buf, 10, &val); 88462306a36Sopenharmony_ci if (err) 88562306a36Sopenharmony_ci return err; 88662306a36Sopenharmony_ci 88762306a36Sopenharmony_ci mutex_lock(&data->update_lock); 88862306a36Sopenharmony_ci 88962306a36Sopenharmony_ci if ((data->vrm_ovt & 0x01) && 89062306a36Sopenharmony_ci (w83627thf == data->type || w83637hf == data->type 89162306a36Sopenharmony_ci || w83687thf == data->type)) 89262306a36Sopenharmony_ci 89362306a36Sopenharmony_ci /* use VRM9 calculation */ 89462306a36Sopenharmony_ci data->in_max[0] = 89562306a36Sopenharmony_ci clamp_val(((val * 100) - 70000 + 244) / 488, 0, 255); 89662306a36Sopenharmony_ci else 89762306a36Sopenharmony_ci /* use VRM8 (standard) calculation */ 89862306a36Sopenharmony_ci data->in_max[0] = IN_TO_REG(val); 89962306a36Sopenharmony_ci 90062306a36Sopenharmony_ci w83627hf_write_value(data, W83781D_REG_IN_MAX(0), data->in_max[0]); 90162306a36Sopenharmony_ci mutex_unlock(&data->update_lock); 90262306a36Sopenharmony_ci return count; 90362306a36Sopenharmony_ci} 90462306a36Sopenharmony_ci 90562306a36Sopenharmony_cistatic DEVICE_ATTR_RW(in0_max); 90662306a36Sopenharmony_ci 90762306a36Sopenharmony_cistatic ssize_t 90862306a36Sopenharmony_cialarm_show(struct device *dev, struct device_attribute *attr, char *buf) 90962306a36Sopenharmony_ci{ 91062306a36Sopenharmony_ci struct w83627hf_data *data = w83627hf_update_device(dev); 91162306a36Sopenharmony_ci int bitnr = to_sensor_dev_attr(attr)->index; 91262306a36Sopenharmony_ci return sprintf(buf, "%u\n", (data->alarms >> bitnr) & 1); 91362306a36Sopenharmony_ci} 91462306a36Sopenharmony_ci 91562306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RO(in0_alarm, alarm, 0); 91662306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RO(in1_alarm, alarm, 1); 91762306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RO(in2_alarm, alarm, 2); 91862306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RO(in3_alarm, alarm, 3); 91962306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RO(in4_alarm, alarm, 8); 92062306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RO(in5_alarm, alarm, 9); 92162306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RO(in6_alarm, alarm, 10); 92262306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RO(in7_alarm, alarm, 16); 92362306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RO(in8_alarm, alarm, 17); 92462306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RO(fan1_alarm, alarm, 6); 92562306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RO(fan2_alarm, alarm, 7); 92662306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RO(fan3_alarm, alarm, 11); 92762306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RO(temp1_alarm, alarm, 4); 92862306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RO(temp2_alarm, alarm, 5); 92962306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RO(temp3_alarm, alarm, 13); 93062306a36Sopenharmony_ci 93162306a36Sopenharmony_cistatic ssize_t 93262306a36Sopenharmony_cibeep_show(struct device *dev, struct device_attribute *attr, char *buf) 93362306a36Sopenharmony_ci{ 93462306a36Sopenharmony_ci struct w83627hf_data *data = w83627hf_update_device(dev); 93562306a36Sopenharmony_ci int bitnr = to_sensor_dev_attr(attr)->index; 93662306a36Sopenharmony_ci return sprintf(buf, "%u\n", (data->beep_mask >> bitnr) & 1); 93762306a36Sopenharmony_ci} 93862306a36Sopenharmony_ci 93962306a36Sopenharmony_cistatic ssize_t 94062306a36Sopenharmony_cibeep_store(struct device *dev, struct device_attribute *attr, const char *buf, 94162306a36Sopenharmony_ci size_t count) 94262306a36Sopenharmony_ci{ 94362306a36Sopenharmony_ci struct w83627hf_data *data = dev_get_drvdata(dev); 94462306a36Sopenharmony_ci int bitnr = to_sensor_dev_attr(attr)->index; 94562306a36Sopenharmony_ci u8 reg; 94662306a36Sopenharmony_ci unsigned long bit; 94762306a36Sopenharmony_ci int err; 94862306a36Sopenharmony_ci 94962306a36Sopenharmony_ci err = kstrtoul(buf, 10, &bit); 95062306a36Sopenharmony_ci if (err) 95162306a36Sopenharmony_ci return err; 95262306a36Sopenharmony_ci 95362306a36Sopenharmony_ci if (bit & ~1) 95462306a36Sopenharmony_ci return -EINVAL; 95562306a36Sopenharmony_ci 95662306a36Sopenharmony_ci mutex_lock(&data->update_lock); 95762306a36Sopenharmony_ci if (bit) 95862306a36Sopenharmony_ci data->beep_mask |= (1 << bitnr); 95962306a36Sopenharmony_ci else 96062306a36Sopenharmony_ci data->beep_mask &= ~(1 << bitnr); 96162306a36Sopenharmony_ci 96262306a36Sopenharmony_ci if (bitnr < 8) { 96362306a36Sopenharmony_ci reg = w83627hf_read_value(data, W83781D_REG_BEEP_INTS1); 96462306a36Sopenharmony_ci if (bit) 96562306a36Sopenharmony_ci reg |= (1 << bitnr); 96662306a36Sopenharmony_ci else 96762306a36Sopenharmony_ci reg &= ~(1 << bitnr); 96862306a36Sopenharmony_ci w83627hf_write_value(data, W83781D_REG_BEEP_INTS1, reg); 96962306a36Sopenharmony_ci } else if (bitnr < 16) { 97062306a36Sopenharmony_ci reg = w83627hf_read_value(data, W83781D_REG_BEEP_INTS2); 97162306a36Sopenharmony_ci if (bit) 97262306a36Sopenharmony_ci reg |= (1 << (bitnr - 8)); 97362306a36Sopenharmony_ci else 97462306a36Sopenharmony_ci reg &= ~(1 << (bitnr - 8)); 97562306a36Sopenharmony_ci w83627hf_write_value(data, W83781D_REG_BEEP_INTS2, reg); 97662306a36Sopenharmony_ci } else { 97762306a36Sopenharmony_ci reg = w83627hf_read_value(data, W83781D_REG_BEEP_INTS3); 97862306a36Sopenharmony_ci if (bit) 97962306a36Sopenharmony_ci reg |= (1 << (bitnr - 16)); 98062306a36Sopenharmony_ci else 98162306a36Sopenharmony_ci reg &= ~(1 << (bitnr - 16)); 98262306a36Sopenharmony_ci w83627hf_write_value(data, W83781D_REG_BEEP_INTS3, reg); 98362306a36Sopenharmony_ci } 98462306a36Sopenharmony_ci mutex_unlock(&data->update_lock); 98562306a36Sopenharmony_ci 98662306a36Sopenharmony_ci return count; 98762306a36Sopenharmony_ci} 98862306a36Sopenharmony_ci 98962306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(in0_beep, beep, 0); 99062306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(in1_beep, beep, 1); 99162306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(in2_beep, beep, 2); 99262306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(in3_beep, beep, 3); 99362306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(in4_beep, beep, 8); 99462306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(in5_beep, beep, 9); 99562306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(in6_beep, beep, 10); 99662306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(in7_beep, beep, 16); 99762306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(in8_beep, beep, 17); 99862306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(fan1_beep, beep, 6); 99962306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(fan2_beep, beep, 7); 100062306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(fan3_beep, beep, 11); 100162306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(temp1_beep, beep, 4); 100262306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(temp2_beep, beep, 5); 100362306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(temp3_beep, beep, 13); 100462306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(beep_enable, beep, 15); 100562306a36Sopenharmony_ci 100662306a36Sopenharmony_cistatic ssize_t 100762306a36Sopenharmony_ciin_input_show(struct device *dev, struct device_attribute *devattr, char *buf) 100862306a36Sopenharmony_ci{ 100962306a36Sopenharmony_ci int nr = to_sensor_dev_attr(devattr)->index; 101062306a36Sopenharmony_ci struct w83627hf_data *data = w83627hf_update_device(dev); 101162306a36Sopenharmony_ci return sprintf(buf, "%ld\n", (long)IN_FROM_REG(data->in[nr])); 101262306a36Sopenharmony_ci} 101362306a36Sopenharmony_ci 101462306a36Sopenharmony_cistatic ssize_t 101562306a36Sopenharmony_ciin_min_show(struct device *dev, struct device_attribute *devattr, char *buf) 101662306a36Sopenharmony_ci{ 101762306a36Sopenharmony_ci int nr = to_sensor_dev_attr(devattr)->index; 101862306a36Sopenharmony_ci struct w83627hf_data *data = w83627hf_update_device(dev); 101962306a36Sopenharmony_ci return sprintf(buf, "%ld\n", (long)IN_FROM_REG(data->in_min[nr])); 102062306a36Sopenharmony_ci} 102162306a36Sopenharmony_ci 102262306a36Sopenharmony_cistatic ssize_t 102362306a36Sopenharmony_ciin_min_store(struct device *dev, struct device_attribute *devattr, 102462306a36Sopenharmony_ci const char *buf, size_t count) 102562306a36Sopenharmony_ci{ 102662306a36Sopenharmony_ci int nr = to_sensor_dev_attr(devattr)->index; 102762306a36Sopenharmony_ci struct w83627hf_data *data = dev_get_drvdata(dev); 102862306a36Sopenharmony_ci long val; 102962306a36Sopenharmony_ci int err; 103062306a36Sopenharmony_ci 103162306a36Sopenharmony_ci err = kstrtol(buf, 10, &val); 103262306a36Sopenharmony_ci if (err) 103362306a36Sopenharmony_ci return err; 103462306a36Sopenharmony_ci 103562306a36Sopenharmony_ci mutex_lock(&data->update_lock); 103662306a36Sopenharmony_ci data->in_min[nr] = IN_TO_REG(val); 103762306a36Sopenharmony_ci w83627hf_write_value(data, W83781D_REG_IN_MIN(nr), data->in_min[nr]); 103862306a36Sopenharmony_ci mutex_unlock(&data->update_lock); 103962306a36Sopenharmony_ci return count; 104062306a36Sopenharmony_ci} 104162306a36Sopenharmony_ci 104262306a36Sopenharmony_cistatic ssize_t 104362306a36Sopenharmony_ciin_max_show(struct device *dev, struct device_attribute *devattr, char *buf) 104462306a36Sopenharmony_ci{ 104562306a36Sopenharmony_ci int nr = to_sensor_dev_attr(devattr)->index; 104662306a36Sopenharmony_ci struct w83627hf_data *data = w83627hf_update_device(dev); 104762306a36Sopenharmony_ci return sprintf(buf, "%ld\n", (long)IN_FROM_REG(data->in_max[nr])); 104862306a36Sopenharmony_ci} 104962306a36Sopenharmony_ci 105062306a36Sopenharmony_cistatic ssize_t 105162306a36Sopenharmony_ciin_max_store(struct device *dev, struct device_attribute *devattr, 105262306a36Sopenharmony_ci const char *buf, size_t count) 105362306a36Sopenharmony_ci{ 105462306a36Sopenharmony_ci int nr = to_sensor_dev_attr(devattr)->index; 105562306a36Sopenharmony_ci struct w83627hf_data *data = dev_get_drvdata(dev); 105662306a36Sopenharmony_ci long val; 105762306a36Sopenharmony_ci int err; 105862306a36Sopenharmony_ci 105962306a36Sopenharmony_ci err = kstrtol(buf, 10, &val); 106062306a36Sopenharmony_ci if (err) 106162306a36Sopenharmony_ci return err; 106262306a36Sopenharmony_ci 106362306a36Sopenharmony_ci mutex_lock(&data->update_lock); 106462306a36Sopenharmony_ci data->in_max[nr] = IN_TO_REG(val); 106562306a36Sopenharmony_ci w83627hf_write_value(data, W83781D_REG_IN_MAX(nr), data->in_max[nr]); 106662306a36Sopenharmony_ci mutex_unlock(&data->update_lock); 106762306a36Sopenharmony_ci return count; 106862306a36Sopenharmony_ci} 106962306a36Sopenharmony_ci 107062306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RO(in1_input, in_input, 1); 107162306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(in1_min, in_min, 1); 107262306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(in1_max, in_max, 1); 107362306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RO(in2_input, in_input, 2); 107462306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(in2_min, in_min, 2); 107562306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(in2_max, in_max, 2); 107662306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RO(in3_input, in_input, 3); 107762306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(in3_min, in_min, 3); 107862306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(in3_max, in_max, 3); 107962306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RO(in4_input, in_input, 4); 108062306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(in4_min, in_min, 4); 108162306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(in4_max, in_max, 4); 108262306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RO(in5_input, in_input, 5); 108362306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(in5_min, in_min, 5); 108462306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(in5_max, in_max, 5); 108562306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RO(in6_input, in_input, 6); 108662306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(in6_min, in_min, 6); 108762306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(in6_max, in_max, 6); 108862306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RO(in7_input, in_input, 7); 108962306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(in7_min, in_min, 7); 109062306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(in7_max, in_max, 7); 109162306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RO(in8_input, in_input, 8); 109262306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(in8_min, in_min, 8); 109362306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(in8_max, in_max, 8); 109462306a36Sopenharmony_ci 109562306a36Sopenharmony_cistatic ssize_t 109662306a36Sopenharmony_cifan_input_show(struct device *dev, struct device_attribute *devattr, 109762306a36Sopenharmony_ci char *buf) 109862306a36Sopenharmony_ci{ 109962306a36Sopenharmony_ci int nr = to_sensor_dev_attr(devattr)->index; 110062306a36Sopenharmony_ci struct w83627hf_data *data = w83627hf_update_device(dev); 110162306a36Sopenharmony_ci return sprintf(buf, "%ld\n", FAN_FROM_REG(data->fan[nr], 110262306a36Sopenharmony_ci (long)DIV_FROM_REG(data->fan_div[nr]))); 110362306a36Sopenharmony_ci} 110462306a36Sopenharmony_ci 110562306a36Sopenharmony_cistatic ssize_t 110662306a36Sopenharmony_cifan_min_show(struct device *dev, struct device_attribute *devattr, char *buf) 110762306a36Sopenharmony_ci{ 110862306a36Sopenharmony_ci int nr = to_sensor_dev_attr(devattr)->index; 110962306a36Sopenharmony_ci struct w83627hf_data *data = w83627hf_update_device(dev); 111062306a36Sopenharmony_ci return sprintf(buf, "%ld\n", FAN_FROM_REG(data->fan_min[nr], 111162306a36Sopenharmony_ci (long)DIV_FROM_REG(data->fan_div[nr]))); 111262306a36Sopenharmony_ci} 111362306a36Sopenharmony_ci 111462306a36Sopenharmony_cistatic ssize_t 111562306a36Sopenharmony_cifan_min_store(struct device *dev, struct device_attribute *devattr, 111662306a36Sopenharmony_ci const char *buf, size_t count) 111762306a36Sopenharmony_ci{ 111862306a36Sopenharmony_ci int nr = to_sensor_dev_attr(devattr)->index; 111962306a36Sopenharmony_ci struct w83627hf_data *data = dev_get_drvdata(dev); 112062306a36Sopenharmony_ci unsigned long val; 112162306a36Sopenharmony_ci int err; 112262306a36Sopenharmony_ci 112362306a36Sopenharmony_ci err = kstrtoul(buf, 10, &val); 112462306a36Sopenharmony_ci if (err) 112562306a36Sopenharmony_ci return err; 112662306a36Sopenharmony_ci 112762306a36Sopenharmony_ci mutex_lock(&data->update_lock); 112862306a36Sopenharmony_ci data->fan_min[nr] = FAN_TO_REG(val, DIV_FROM_REG(data->fan_div[nr])); 112962306a36Sopenharmony_ci w83627hf_write_value(data, W83627HF_REG_FAN_MIN(nr), 113062306a36Sopenharmony_ci data->fan_min[nr]); 113162306a36Sopenharmony_ci 113262306a36Sopenharmony_ci mutex_unlock(&data->update_lock); 113362306a36Sopenharmony_ci return count; 113462306a36Sopenharmony_ci} 113562306a36Sopenharmony_ci 113662306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RO(fan1_input, fan_input, 0); 113762306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(fan1_min, fan_min, 0); 113862306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RO(fan2_input, fan_input, 1); 113962306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(fan2_min, fan_min, 1); 114062306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RO(fan3_input, fan_input, 2); 114162306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(fan3_min, fan_min, 2); 114262306a36Sopenharmony_ci 114362306a36Sopenharmony_cistatic ssize_t 114462306a36Sopenharmony_cifan_div_show(struct device *dev, struct device_attribute *devattr, char *buf) 114562306a36Sopenharmony_ci{ 114662306a36Sopenharmony_ci int nr = to_sensor_dev_attr(devattr)->index; 114762306a36Sopenharmony_ci struct w83627hf_data *data = w83627hf_update_device(dev); 114862306a36Sopenharmony_ci return sprintf(buf, "%ld\n", 114962306a36Sopenharmony_ci (long) DIV_FROM_REG(data->fan_div[nr])); 115062306a36Sopenharmony_ci} 115162306a36Sopenharmony_ci 115262306a36Sopenharmony_ci/* 115362306a36Sopenharmony_ci * Note: we save and restore the fan minimum here, because its value is 115462306a36Sopenharmony_ci * determined in part by the fan divisor. This follows the principle of 115562306a36Sopenharmony_ci * least surprise; the user doesn't expect the fan minimum to change just 115662306a36Sopenharmony_ci * because the divisor changed. 115762306a36Sopenharmony_ci */ 115862306a36Sopenharmony_cistatic ssize_t 115962306a36Sopenharmony_cifan_div_store(struct device *dev, struct device_attribute *devattr, 116062306a36Sopenharmony_ci const char *buf, size_t count) 116162306a36Sopenharmony_ci{ 116262306a36Sopenharmony_ci int nr = to_sensor_dev_attr(devattr)->index; 116362306a36Sopenharmony_ci struct w83627hf_data *data = dev_get_drvdata(dev); 116462306a36Sopenharmony_ci unsigned long min; 116562306a36Sopenharmony_ci u8 reg; 116662306a36Sopenharmony_ci unsigned long val; 116762306a36Sopenharmony_ci int err; 116862306a36Sopenharmony_ci 116962306a36Sopenharmony_ci err = kstrtoul(buf, 10, &val); 117062306a36Sopenharmony_ci if (err) 117162306a36Sopenharmony_ci return err; 117262306a36Sopenharmony_ci 117362306a36Sopenharmony_ci mutex_lock(&data->update_lock); 117462306a36Sopenharmony_ci 117562306a36Sopenharmony_ci /* Save fan_min */ 117662306a36Sopenharmony_ci min = FAN_FROM_REG(data->fan_min[nr], 117762306a36Sopenharmony_ci DIV_FROM_REG(data->fan_div[nr])); 117862306a36Sopenharmony_ci 117962306a36Sopenharmony_ci data->fan_div[nr] = DIV_TO_REG(val); 118062306a36Sopenharmony_ci 118162306a36Sopenharmony_ci reg = (w83627hf_read_value(data, nr==2 ? W83781D_REG_PIN : W83781D_REG_VID_FANDIV) 118262306a36Sopenharmony_ci & (nr==0 ? 0xcf : 0x3f)) 118362306a36Sopenharmony_ci | ((data->fan_div[nr] & 0x03) << (nr==0 ? 4 : 6)); 118462306a36Sopenharmony_ci w83627hf_write_value(data, nr==2 ? W83781D_REG_PIN : W83781D_REG_VID_FANDIV, reg); 118562306a36Sopenharmony_ci 118662306a36Sopenharmony_ci reg = (w83627hf_read_value(data, W83781D_REG_VBAT) 118762306a36Sopenharmony_ci & ~(1 << (5 + nr))) 118862306a36Sopenharmony_ci | ((data->fan_div[nr] & 0x04) << (3 + nr)); 118962306a36Sopenharmony_ci w83627hf_write_value(data, W83781D_REG_VBAT, reg); 119062306a36Sopenharmony_ci 119162306a36Sopenharmony_ci /* Restore fan_min */ 119262306a36Sopenharmony_ci data->fan_min[nr] = FAN_TO_REG(min, DIV_FROM_REG(data->fan_div[nr])); 119362306a36Sopenharmony_ci w83627hf_write_value(data, W83627HF_REG_FAN_MIN(nr), data->fan_min[nr]); 119462306a36Sopenharmony_ci 119562306a36Sopenharmony_ci mutex_unlock(&data->update_lock); 119662306a36Sopenharmony_ci return count; 119762306a36Sopenharmony_ci} 119862306a36Sopenharmony_ci 119962306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(fan1_div, fan_div, 0); 120062306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(fan2_div, fan_div, 1); 120162306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(fan3_div, fan_div, 2); 120262306a36Sopenharmony_ci 120362306a36Sopenharmony_cistatic ssize_t 120462306a36Sopenharmony_citemp_show(struct device *dev, struct device_attribute *devattr, char *buf) 120562306a36Sopenharmony_ci{ 120662306a36Sopenharmony_ci int nr = to_sensor_dev_attr(devattr)->index; 120762306a36Sopenharmony_ci struct w83627hf_data *data = w83627hf_update_device(dev); 120862306a36Sopenharmony_ci 120962306a36Sopenharmony_ci u16 tmp = data->temp[nr]; 121062306a36Sopenharmony_ci return sprintf(buf, "%ld\n", (nr) ? (long) LM75_TEMP_FROM_REG(tmp) 121162306a36Sopenharmony_ci : (long) TEMP_FROM_REG(tmp)); 121262306a36Sopenharmony_ci} 121362306a36Sopenharmony_ci 121462306a36Sopenharmony_cistatic ssize_t 121562306a36Sopenharmony_citemp_max_show(struct device *dev, struct device_attribute *devattr, char *buf) 121662306a36Sopenharmony_ci{ 121762306a36Sopenharmony_ci int nr = to_sensor_dev_attr(devattr)->index; 121862306a36Sopenharmony_ci struct w83627hf_data *data = w83627hf_update_device(dev); 121962306a36Sopenharmony_ci 122062306a36Sopenharmony_ci u16 tmp = data->temp_max[nr]; 122162306a36Sopenharmony_ci return sprintf(buf, "%ld\n", (nr) ? (long) LM75_TEMP_FROM_REG(tmp) 122262306a36Sopenharmony_ci : (long) TEMP_FROM_REG(tmp)); 122362306a36Sopenharmony_ci} 122462306a36Sopenharmony_ci 122562306a36Sopenharmony_cistatic ssize_t 122662306a36Sopenharmony_citemp_max_store(struct device *dev, struct device_attribute *devattr, 122762306a36Sopenharmony_ci const char *buf, size_t count) 122862306a36Sopenharmony_ci{ 122962306a36Sopenharmony_ci int nr = to_sensor_dev_attr(devattr)->index; 123062306a36Sopenharmony_ci struct w83627hf_data *data = dev_get_drvdata(dev); 123162306a36Sopenharmony_ci u16 tmp; 123262306a36Sopenharmony_ci long val; 123362306a36Sopenharmony_ci int err; 123462306a36Sopenharmony_ci 123562306a36Sopenharmony_ci err = kstrtol(buf, 10, &val); 123662306a36Sopenharmony_ci if (err) 123762306a36Sopenharmony_ci return err; 123862306a36Sopenharmony_ci 123962306a36Sopenharmony_ci tmp = (nr) ? LM75_TEMP_TO_REG(val) : TEMP_TO_REG(val); 124062306a36Sopenharmony_ci mutex_lock(&data->update_lock); 124162306a36Sopenharmony_ci data->temp_max[nr] = tmp; 124262306a36Sopenharmony_ci w83627hf_write_value(data, w83627hf_reg_temp_over[nr], tmp); 124362306a36Sopenharmony_ci mutex_unlock(&data->update_lock); 124462306a36Sopenharmony_ci return count; 124562306a36Sopenharmony_ci} 124662306a36Sopenharmony_ci 124762306a36Sopenharmony_cistatic ssize_t 124862306a36Sopenharmony_citemp_max_hyst_show(struct device *dev, struct device_attribute *devattr, 124962306a36Sopenharmony_ci char *buf) 125062306a36Sopenharmony_ci{ 125162306a36Sopenharmony_ci int nr = to_sensor_dev_attr(devattr)->index; 125262306a36Sopenharmony_ci struct w83627hf_data *data = w83627hf_update_device(dev); 125362306a36Sopenharmony_ci 125462306a36Sopenharmony_ci u16 tmp = data->temp_max_hyst[nr]; 125562306a36Sopenharmony_ci return sprintf(buf, "%ld\n", (nr) ? (long) LM75_TEMP_FROM_REG(tmp) 125662306a36Sopenharmony_ci : (long) TEMP_FROM_REG(tmp)); 125762306a36Sopenharmony_ci} 125862306a36Sopenharmony_ci 125962306a36Sopenharmony_cistatic ssize_t 126062306a36Sopenharmony_citemp_max_hyst_store(struct device *dev, struct device_attribute *devattr, 126162306a36Sopenharmony_ci const char *buf, size_t count) 126262306a36Sopenharmony_ci{ 126362306a36Sopenharmony_ci int nr = to_sensor_dev_attr(devattr)->index; 126462306a36Sopenharmony_ci struct w83627hf_data *data = dev_get_drvdata(dev); 126562306a36Sopenharmony_ci u16 tmp; 126662306a36Sopenharmony_ci long val; 126762306a36Sopenharmony_ci int err; 126862306a36Sopenharmony_ci 126962306a36Sopenharmony_ci err = kstrtol(buf, 10, &val); 127062306a36Sopenharmony_ci if (err) 127162306a36Sopenharmony_ci return err; 127262306a36Sopenharmony_ci 127362306a36Sopenharmony_ci tmp = (nr) ? LM75_TEMP_TO_REG(val) : TEMP_TO_REG(val); 127462306a36Sopenharmony_ci mutex_lock(&data->update_lock); 127562306a36Sopenharmony_ci data->temp_max_hyst[nr] = tmp; 127662306a36Sopenharmony_ci w83627hf_write_value(data, w83627hf_reg_temp_hyst[nr], tmp); 127762306a36Sopenharmony_ci mutex_unlock(&data->update_lock); 127862306a36Sopenharmony_ci return count; 127962306a36Sopenharmony_ci} 128062306a36Sopenharmony_ci 128162306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RO(temp1_input, temp, 0); 128262306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(temp1_max, temp_max, 0); 128362306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(temp1_max_hyst, temp_max_hyst, 0); 128462306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RO(temp2_input, temp, 1); 128562306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(temp2_max, temp_max, 1); 128662306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(temp2_max_hyst, temp_max_hyst, 1); 128762306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RO(temp3_input, temp, 2); 128862306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(temp3_max, temp_max, 2); 128962306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(temp3_max_hyst, temp_max_hyst, 2); 129062306a36Sopenharmony_ci 129162306a36Sopenharmony_cistatic ssize_t 129262306a36Sopenharmony_citemp_type_show(struct device *dev, struct device_attribute *devattr, 129362306a36Sopenharmony_ci char *buf) 129462306a36Sopenharmony_ci{ 129562306a36Sopenharmony_ci int nr = to_sensor_dev_attr(devattr)->index; 129662306a36Sopenharmony_ci struct w83627hf_data *data = w83627hf_update_device(dev); 129762306a36Sopenharmony_ci return sprintf(buf, "%ld\n", (long) data->sens[nr]); 129862306a36Sopenharmony_ci} 129962306a36Sopenharmony_ci 130062306a36Sopenharmony_cistatic ssize_t 130162306a36Sopenharmony_citemp_type_store(struct device *dev, struct device_attribute *devattr, 130262306a36Sopenharmony_ci const char *buf, size_t count) 130362306a36Sopenharmony_ci{ 130462306a36Sopenharmony_ci int nr = to_sensor_dev_attr(devattr)->index; 130562306a36Sopenharmony_ci struct w83627hf_data *data = dev_get_drvdata(dev); 130662306a36Sopenharmony_ci unsigned long val; 130762306a36Sopenharmony_ci u32 tmp; 130862306a36Sopenharmony_ci int err; 130962306a36Sopenharmony_ci 131062306a36Sopenharmony_ci err = kstrtoul(buf, 10, &val); 131162306a36Sopenharmony_ci if (err) 131262306a36Sopenharmony_ci return err; 131362306a36Sopenharmony_ci 131462306a36Sopenharmony_ci mutex_lock(&data->update_lock); 131562306a36Sopenharmony_ci 131662306a36Sopenharmony_ci switch (val) { 131762306a36Sopenharmony_ci case 1: /* PII/Celeron diode */ 131862306a36Sopenharmony_ci tmp = w83627hf_read_value(data, W83781D_REG_SCFG1); 131962306a36Sopenharmony_ci w83627hf_write_value(data, W83781D_REG_SCFG1, 132062306a36Sopenharmony_ci tmp | BIT_SCFG1[nr]); 132162306a36Sopenharmony_ci tmp = w83627hf_read_value(data, W83781D_REG_SCFG2); 132262306a36Sopenharmony_ci w83627hf_write_value(data, W83781D_REG_SCFG2, 132362306a36Sopenharmony_ci tmp | BIT_SCFG2[nr]); 132462306a36Sopenharmony_ci data->sens[nr] = val; 132562306a36Sopenharmony_ci break; 132662306a36Sopenharmony_ci case 2: /* 3904 */ 132762306a36Sopenharmony_ci tmp = w83627hf_read_value(data, W83781D_REG_SCFG1); 132862306a36Sopenharmony_ci w83627hf_write_value(data, W83781D_REG_SCFG1, 132962306a36Sopenharmony_ci tmp | BIT_SCFG1[nr]); 133062306a36Sopenharmony_ci tmp = w83627hf_read_value(data, W83781D_REG_SCFG2); 133162306a36Sopenharmony_ci w83627hf_write_value(data, W83781D_REG_SCFG2, 133262306a36Sopenharmony_ci tmp & ~BIT_SCFG2[nr]); 133362306a36Sopenharmony_ci data->sens[nr] = val; 133462306a36Sopenharmony_ci break; 133562306a36Sopenharmony_ci case W83781D_DEFAULT_BETA: 133662306a36Sopenharmony_ci dev_warn(dev, "Sensor type %d is deprecated, please use 4 " 133762306a36Sopenharmony_ci "instead\n", W83781D_DEFAULT_BETA); 133862306a36Sopenharmony_ci fallthrough; 133962306a36Sopenharmony_ci case 4: /* thermistor */ 134062306a36Sopenharmony_ci tmp = w83627hf_read_value(data, W83781D_REG_SCFG1); 134162306a36Sopenharmony_ci w83627hf_write_value(data, W83781D_REG_SCFG1, 134262306a36Sopenharmony_ci tmp & ~BIT_SCFG1[nr]); 134362306a36Sopenharmony_ci data->sens[nr] = val; 134462306a36Sopenharmony_ci break; 134562306a36Sopenharmony_ci default: 134662306a36Sopenharmony_ci dev_err(dev, 134762306a36Sopenharmony_ci "Invalid sensor type %ld; must be 1, 2, or 4\n", 134862306a36Sopenharmony_ci (long) val); 134962306a36Sopenharmony_ci break; 135062306a36Sopenharmony_ci } 135162306a36Sopenharmony_ci 135262306a36Sopenharmony_ci mutex_unlock(&data->update_lock); 135362306a36Sopenharmony_ci return count; 135462306a36Sopenharmony_ci} 135562306a36Sopenharmony_ci 135662306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(temp1_type, temp_type, 0); 135762306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(temp2_type, temp_type, 1); 135862306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(temp3_type, temp_type, 2); 135962306a36Sopenharmony_ci 136062306a36Sopenharmony_cistatic ssize_t 136162306a36Sopenharmony_cialarms_show(struct device *dev, struct device_attribute *attr, char *buf) 136262306a36Sopenharmony_ci{ 136362306a36Sopenharmony_ci struct w83627hf_data *data = w83627hf_update_device(dev); 136462306a36Sopenharmony_ci return sprintf(buf, "%ld\n", (long) data->alarms); 136562306a36Sopenharmony_ci} 136662306a36Sopenharmony_cistatic DEVICE_ATTR_RO(alarms); 136762306a36Sopenharmony_ci 136862306a36Sopenharmony_ci#define VIN_UNIT_ATTRS(_X_) \ 136962306a36Sopenharmony_ci &sensor_dev_attr_in##_X_##_input.dev_attr.attr, \ 137062306a36Sopenharmony_ci &sensor_dev_attr_in##_X_##_min.dev_attr.attr, \ 137162306a36Sopenharmony_ci &sensor_dev_attr_in##_X_##_max.dev_attr.attr, \ 137262306a36Sopenharmony_ci &sensor_dev_attr_in##_X_##_alarm.dev_attr.attr, \ 137362306a36Sopenharmony_ci &sensor_dev_attr_in##_X_##_beep.dev_attr.attr 137462306a36Sopenharmony_ci 137562306a36Sopenharmony_ci#define FAN_UNIT_ATTRS(_X_) \ 137662306a36Sopenharmony_ci &sensor_dev_attr_fan##_X_##_input.dev_attr.attr, \ 137762306a36Sopenharmony_ci &sensor_dev_attr_fan##_X_##_min.dev_attr.attr, \ 137862306a36Sopenharmony_ci &sensor_dev_attr_fan##_X_##_div.dev_attr.attr, \ 137962306a36Sopenharmony_ci &sensor_dev_attr_fan##_X_##_alarm.dev_attr.attr, \ 138062306a36Sopenharmony_ci &sensor_dev_attr_fan##_X_##_beep.dev_attr.attr 138162306a36Sopenharmony_ci 138262306a36Sopenharmony_ci#define TEMP_UNIT_ATTRS(_X_) \ 138362306a36Sopenharmony_ci &sensor_dev_attr_temp##_X_##_input.dev_attr.attr, \ 138462306a36Sopenharmony_ci &sensor_dev_attr_temp##_X_##_max.dev_attr.attr, \ 138562306a36Sopenharmony_ci &sensor_dev_attr_temp##_X_##_max_hyst.dev_attr.attr, \ 138662306a36Sopenharmony_ci &sensor_dev_attr_temp##_X_##_type.dev_attr.attr, \ 138762306a36Sopenharmony_ci &sensor_dev_attr_temp##_X_##_alarm.dev_attr.attr, \ 138862306a36Sopenharmony_ci &sensor_dev_attr_temp##_X_##_beep.dev_attr.attr 138962306a36Sopenharmony_ci 139062306a36Sopenharmony_cistatic ssize_t 139162306a36Sopenharmony_cibeep_mask_show(struct device *dev, struct device_attribute *attr, char *buf) 139262306a36Sopenharmony_ci{ 139362306a36Sopenharmony_ci struct w83627hf_data *data = w83627hf_update_device(dev); 139462306a36Sopenharmony_ci return sprintf(buf, "%ld\n", 139562306a36Sopenharmony_ci (long)BEEP_MASK_FROM_REG(data->beep_mask)); 139662306a36Sopenharmony_ci} 139762306a36Sopenharmony_ci 139862306a36Sopenharmony_cistatic ssize_t 139962306a36Sopenharmony_cibeep_mask_store(struct device *dev, struct device_attribute *attr, 140062306a36Sopenharmony_ci const char *buf, size_t count) 140162306a36Sopenharmony_ci{ 140262306a36Sopenharmony_ci struct w83627hf_data *data = dev_get_drvdata(dev); 140362306a36Sopenharmony_ci unsigned long val; 140462306a36Sopenharmony_ci int err; 140562306a36Sopenharmony_ci 140662306a36Sopenharmony_ci err = kstrtoul(buf, 10, &val); 140762306a36Sopenharmony_ci if (err) 140862306a36Sopenharmony_ci return err; 140962306a36Sopenharmony_ci 141062306a36Sopenharmony_ci mutex_lock(&data->update_lock); 141162306a36Sopenharmony_ci 141262306a36Sopenharmony_ci /* preserve beep enable */ 141362306a36Sopenharmony_ci data->beep_mask = (data->beep_mask & 0x8000) 141462306a36Sopenharmony_ci | BEEP_MASK_TO_REG(val); 141562306a36Sopenharmony_ci w83627hf_write_value(data, W83781D_REG_BEEP_INTS1, 141662306a36Sopenharmony_ci data->beep_mask & 0xff); 141762306a36Sopenharmony_ci w83627hf_write_value(data, W83781D_REG_BEEP_INTS3, 141862306a36Sopenharmony_ci ((data->beep_mask) >> 16) & 0xff); 141962306a36Sopenharmony_ci w83627hf_write_value(data, W83781D_REG_BEEP_INTS2, 142062306a36Sopenharmony_ci (data->beep_mask >> 8) & 0xff); 142162306a36Sopenharmony_ci 142262306a36Sopenharmony_ci mutex_unlock(&data->update_lock); 142362306a36Sopenharmony_ci return count; 142462306a36Sopenharmony_ci} 142562306a36Sopenharmony_ci 142662306a36Sopenharmony_cistatic DEVICE_ATTR_RW(beep_mask); 142762306a36Sopenharmony_ci 142862306a36Sopenharmony_cistatic ssize_t 142962306a36Sopenharmony_cipwm_show(struct device *dev, struct device_attribute *devattr, char *buf) 143062306a36Sopenharmony_ci{ 143162306a36Sopenharmony_ci int nr = to_sensor_dev_attr(devattr)->index; 143262306a36Sopenharmony_ci struct w83627hf_data *data = w83627hf_update_device(dev); 143362306a36Sopenharmony_ci return sprintf(buf, "%ld\n", (long) data->pwm[nr]); 143462306a36Sopenharmony_ci} 143562306a36Sopenharmony_ci 143662306a36Sopenharmony_cistatic ssize_t 143762306a36Sopenharmony_cipwm_store(struct device *dev, struct device_attribute *devattr, 143862306a36Sopenharmony_ci const char *buf, size_t count) 143962306a36Sopenharmony_ci{ 144062306a36Sopenharmony_ci int nr = to_sensor_dev_attr(devattr)->index; 144162306a36Sopenharmony_ci struct w83627hf_data *data = dev_get_drvdata(dev); 144262306a36Sopenharmony_ci unsigned long val; 144362306a36Sopenharmony_ci int err; 144462306a36Sopenharmony_ci 144562306a36Sopenharmony_ci err = kstrtoul(buf, 10, &val); 144662306a36Sopenharmony_ci if (err) 144762306a36Sopenharmony_ci return err; 144862306a36Sopenharmony_ci 144962306a36Sopenharmony_ci mutex_lock(&data->update_lock); 145062306a36Sopenharmony_ci 145162306a36Sopenharmony_ci if (data->type == w83627thf) { 145262306a36Sopenharmony_ci /* bits 0-3 are reserved in 627THF */ 145362306a36Sopenharmony_ci data->pwm[nr] = PWM_TO_REG(val) & 0xf0; 145462306a36Sopenharmony_ci w83627hf_write_value(data, 145562306a36Sopenharmony_ci W836X7HF_REG_PWM(data->type, nr), 145662306a36Sopenharmony_ci data->pwm[nr] | 145762306a36Sopenharmony_ci (w83627hf_read_value(data, 145862306a36Sopenharmony_ci W836X7HF_REG_PWM(data->type, nr)) & 0x0f)); 145962306a36Sopenharmony_ci } else { 146062306a36Sopenharmony_ci data->pwm[nr] = PWM_TO_REG(val); 146162306a36Sopenharmony_ci w83627hf_write_value(data, 146262306a36Sopenharmony_ci W836X7HF_REG_PWM(data->type, nr), 146362306a36Sopenharmony_ci data->pwm[nr]); 146462306a36Sopenharmony_ci } 146562306a36Sopenharmony_ci 146662306a36Sopenharmony_ci mutex_unlock(&data->update_lock); 146762306a36Sopenharmony_ci return count; 146862306a36Sopenharmony_ci} 146962306a36Sopenharmony_ci 147062306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(pwm1, pwm, 0); 147162306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(pwm2, pwm, 1); 147262306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(pwm3, pwm, 2); 147362306a36Sopenharmony_ci 147462306a36Sopenharmony_cistatic ssize_t 147562306a36Sopenharmony_ciname_show(struct device *dev, struct device_attribute *devattr, char *buf) 147662306a36Sopenharmony_ci{ 147762306a36Sopenharmony_ci struct w83627hf_data *data = dev_get_drvdata(dev); 147862306a36Sopenharmony_ci 147962306a36Sopenharmony_ci return sprintf(buf, "%s\n", data->name); 148062306a36Sopenharmony_ci} 148162306a36Sopenharmony_ci 148262306a36Sopenharmony_cistatic DEVICE_ATTR_RO(name); 148362306a36Sopenharmony_ci 148462306a36Sopenharmony_cistatic struct attribute *w83627hf_attributes[] = { 148562306a36Sopenharmony_ci &dev_attr_in0_input.attr, 148662306a36Sopenharmony_ci &dev_attr_in0_min.attr, 148762306a36Sopenharmony_ci &dev_attr_in0_max.attr, 148862306a36Sopenharmony_ci &sensor_dev_attr_in0_alarm.dev_attr.attr, 148962306a36Sopenharmony_ci &sensor_dev_attr_in0_beep.dev_attr.attr, 149062306a36Sopenharmony_ci VIN_UNIT_ATTRS(2), 149162306a36Sopenharmony_ci VIN_UNIT_ATTRS(3), 149262306a36Sopenharmony_ci VIN_UNIT_ATTRS(4), 149362306a36Sopenharmony_ci VIN_UNIT_ATTRS(7), 149462306a36Sopenharmony_ci VIN_UNIT_ATTRS(8), 149562306a36Sopenharmony_ci 149662306a36Sopenharmony_ci FAN_UNIT_ATTRS(1), 149762306a36Sopenharmony_ci FAN_UNIT_ATTRS(2), 149862306a36Sopenharmony_ci 149962306a36Sopenharmony_ci TEMP_UNIT_ATTRS(1), 150062306a36Sopenharmony_ci TEMP_UNIT_ATTRS(2), 150162306a36Sopenharmony_ci 150262306a36Sopenharmony_ci &dev_attr_alarms.attr, 150362306a36Sopenharmony_ci &sensor_dev_attr_beep_enable.dev_attr.attr, 150462306a36Sopenharmony_ci &dev_attr_beep_mask.attr, 150562306a36Sopenharmony_ci 150662306a36Sopenharmony_ci &sensor_dev_attr_pwm1.dev_attr.attr, 150762306a36Sopenharmony_ci &sensor_dev_attr_pwm2.dev_attr.attr, 150862306a36Sopenharmony_ci &dev_attr_name.attr, 150962306a36Sopenharmony_ci NULL 151062306a36Sopenharmony_ci}; 151162306a36Sopenharmony_ci 151262306a36Sopenharmony_cistatic const struct attribute_group w83627hf_group = { 151362306a36Sopenharmony_ci .attrs = w83627hf_attributes, 151462306a36Sopenharmony_ci}; 151562306a36Sopenharmony_ci 151662306a36Sopenharmony_cistatic ssize_t 151762306a36Sopenharmony_cipwm_freq_show(struct device *dev, struct device_attribute *devattr, char *buf) 151862306a36Sopenharmony_ci{ 151962306a36Sopenharmony_ci int nr = to_sensor_dev_attr(devattr)->index; 152062306a36Sopenharmony_ci struct w83627hf_data *data = w83627hf_update_device(dev); 152162306a36Sopenharmony_ci if (data->type == w83627hf) 152262306a36Sopenharmony_ci return sprintf(buf, "%ld\n", 152362306a36Sopenharmony_ci pwm_freq_from_reg_627hf(data->pwm_freq[nr])); 152462306a36Sopenharmony_ci else 152562306a36Sopenharmony_ci return sprintf(buf, "%ld\n", 152662306a36Sopenharmony_ci pwm_freq_from_reg(data->pwm_freq[nr])); 152762306a36Sopenharmony_ci} 152862306a36Sopenharmony_ci 152962306a36Sopenharmony_cistatic ssize_t 153062306a36Sopenharmony_cipwm_freq_store(struct device *dev, struct device_attribute *devattr, 153162306a36Sopenharmony_ci const char *buf, size_t count) 153262306a36Sopenharmony_ci{ 153362306a36Sopenharmony_ci int nr = to_sensor_dev_attr(devattr)->index; 153462306a36Sopenharmony_ci struct w83627hf_data *data = dev_get_drvdata(dev); 153562306a36Sopenharmony_ci static const u8 mask[]={0xF8, 0x8F}; 153662306a36Sopenharmony_ci unsigned long val; 153762306a36Sopenharmony_ci int err; 153862306a36Sopenharmony_ci 153962306a36Sopenharmony_ci err = kstrtoul(buf, 10, &val); 154062306a36Sopenharmony_ci if (err) 154162306a36Sopenharmony_ci return err; 154262306a36Sopenharmony_ci 154362306a36Sopenharmony_ci mutex_lock(&data->update_lock); 154462306a36Sopenharmony_ci 154562306a36Sopenharmony_ci if (data->type == w83627hf) { 154662306a36Sopenharmony_ci data->pwm_freq[nr] = pwm_freq_to_reg_627hf(val); 154762306a36Sopenharmony_ci w83627hf_write_value(data, W83627HF_REG_PWM_FREQ, 154862306a36Sopenharmony_ci (data->pwm_freq[nr] << (nr*4)) | 154962306a36Sopenharmony_ci (w83627hf_read_value(data, 155062306a36Sopenharmony_ci W83627HF_REG_PWM_FREQ) & mask[nr])); 155162306a36Sopenharmony_ci } else { 155262306a36Sopenharmony_ci data->pwm_freq[nr] = pwm_freq_to_reg(val); 155362306a36Sopenharmony_ci w83627hf_write_value(data, W83637HF_REG_PWM_FREQ[nr], 155462306a36Sopenharmony_ci data->pwm_freq[nr]); 155562306a36Sopenharmony_ci } 155662306a36Sopenharmony_ci 155762306a36Sopenharmony_ci mutex_unlock(&data->update_lock); 155862306a36Sopenharmony_ci return count; 155962306a36Sopenharmony_ci} 156062306a36Sopenharmony_ci 156162306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(pwm1_freq, pwm_freq, 0); 156262306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(pwm2_freq, pwm_freq, 1); 156362306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(pwm3_freq, pwm_freq, 2); 156462306a36Sopenharmony_ci 156562306a36Sopenharmony_cistatic ssize_t 156662306a36Sopenharmony_cicpu0_vid_show(struct device *dev, struct device_attribute *attr, char *buf) 156762306a36Sopenharmony_ci{ 156862306a36Sopenharmony_ci struct w83627hf_data *data = w83627hf_update_device(dev); 156962306a36Sopenharmony_ci return sprintf(buf, "%ld\n", (long) vid_from_reg(data->vid, data->vrm)); 157062306a36Sopenharmony_ci} 157162306a36Sopenharmony_ci 157262306a36Sopenharmony_cistatic DEVICE_ATTR_RO(cpu0_vid); 157362306a36Sopenharmony_ci 157462306a36Sopenharmony_cistatic ssize_t 157562306a36Sopenharmony_civrm_show(struct device *dev, struct device_attribute *attr, char *buf) 157662306a36Sopenharmony_ci{ 157762306a36Sopenharmony_ci struct w83627hf_data *data = dev_get_drvdata(dev); 157862306a36Sopenharmony_ci return sprintf(buf, "%ld\n", (long) data->vrm); 157962306a36Sopenharmony_ci} 158062306a36Sopenharmony_ci 158162306a36Sopenharmony_cistatic ssize_t 158262306a36Sopenharmony_civrm_store(struct device *dev, struct device_attribute *attr, const char *buf, 158362306a36Sopenharmony_ci size_t count) 158462306a36Sopenharmony_ci{ 158562306a36Sopenharmony_ci struct w83627hf_data *data = dev_get_drvdata(dev); 158662306a36Sopenharmony_ci unsigned long val; 158762306a36Sopenharmony_ci int err; 158862306a36Sopenharmony_ci 158962306a36Sopenharmony_ci err = kstrtoul(buf, 10, &val); 159062306a36Sopenharmony_ci if (err) 159162306a36Sopenharmony_ci return err; 159262306a36Sopenharmony_ci 159362306a36Sopenharmony_ci if (val > 255) 159462306a36Sopenharmony_ci return -EINVAL; 159562306a36Sopenharmony_ci data->vrm = val; 159662306a36Sopenharmony_ci 159762306a36Sopenharmony_ci return count; 159862306a36Sopenharmony_ci} 159962306a36Sopenharmony_ci 160062306a36Sopenharmony_cistatic DEVICE_ATTR_RW(vrm); 160162306a36Sopenharmony_ci 160262306a36Sopenharmony_cistatic ssize_t 160362306a36Sopenharmony_cipwm_enable_show(struct device *dev, struct device_attribute *devattr, 160462306a36Sopenharmony_ci char *buf) 160562306a36Sopenharmony_ci{ 160662306a36Sopenharmony_ci int nr = to_sensor_dev_attr(devattr)->index; 160762306a36Sopenharmony_ci struct w83627hf_data *data = w83627hf_update_device(dev); 160862306a36Sopenharmony_ci return sprintf(buf, "%d\n", data->pwm_enable[nr]); 160962306a36Sopenharmony_ci} 161062306a36Sopenharmony_ci 161162306a36Sopenharmony_cistatic ssize_t 161262306a36Sopenharmony_cipwm_enable_store(struct device *dev, struct device_attribute *devattr, 161362306a36Sopenharmony_ci const char *buf, size_t count) 161462306a36Sopenharmony_ci{ 161562306a36Sopenharmony_ci int nr = to_sensor_dev_attr(devattr)->index; 161662306a36Sopenharmony_ci struct w83627hf_data *data = dev_get_drvdata(dev); 161762306a36Sopenharmony_ci u8 reg; 161862306a36Sopenharmony_ci unsigned long val; 161962306a36Sopenharmony_ci int err; 162062306a36Sopenharmony_ci 162162306a36Sopenharmony_ci err = kstrtoul(buf, 10, &val); 162262306a36Sopenharmony_ci if (err) 162362306a36Sopenharmony_ci return err; 162462306a36Sopenharmony_ci 162562306a36Sopenharmony_ci if (!val || val > 3) /* modes 1, 2 and 3 are supported */ 162662306a36Sopenharmony_ci return -EINVAL; 162762306a36Sopenharmony_ci mutex_lock(&data->update_lock); 162862306a36Sopenharmony_ci data->pwm_enable[nr] = val; 162962306a36Sopenharmony_ci reg = w83627hf_read_value(data, W83627THF_REG_PWM_ENABLE[nr]); 163062306a36Sopenharmony_ci reg &= ~(0x03 << W83627THF_PWM_ENABLE_SHIFT[nr]); 163162306a36Sopenharmony_ci reg |= (val - 1) << W83627THF_PWM_ENABLE_SHIFT[nr]; 163262306a36Sopenharmony_ci w83627hf_write_value(data, W83627THF_REG_PWM_ENABLE[nr], reg); 163362306a36Sopenharmony_ci mutex_unlock(&data->update_lock); 163462306a36Sopenharmony_ci return count; 163562306a36Sopenharmony_ci} 163662306a36Sopenharmony_ci 163762306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(pwm1_enable, pwm_enable, 0); 163862306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(pwm2_enable, pwm_enable, 1); 163962306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(pwm3_enable, pwm_enable, 2); 164062306a36Sopenharmony_ci 164162306a36Sopenharmony_cistatic struct attribute *w83627hf_attributes_opt[] = { 164262306a36Sopenharmony_ci VIN_UNIT_ATTRS(1), 164362306a36Sopenharmony_ci VIN_UNIT_ATTRS(5), 164462306a36Sopenharmony_ci VIN_UNIT_ATTRS(6), 164562306a36Sopenharmony_ci 164662306a36Sopenharmony_ci FAN_UNIT_ATTRS(3), 164762306a36Sopenharmony_ci TEMP_UNIT_ATTRS(3), 164862306a36Sopenharmony_ci &sensor_dev_attr_pwm3.dev_attr.attr, 164962306a36Sopenharmony_ci 165062306a36Sopenharmony_ci &sensor_dev_attr_pwm1_freq.dev_attr.attr, 165162306a36Sopenharmony_ci &sensor_dev_attr_pwm2_freq.dev_attr.attr, 165262306a36Sopenharmony_ci &sensor_dev_attr_pwm3_freq.dev_attr.attr, 165362306a36Sopenharmony_ci 165462306a36Sopenharmony_ci &sensor_dev_attr_pwm1_enable.dev_attr.attr, 165562306a36Sopenharmony_ci &sensor_dev_attr_pwm2_enable.dev_attr.attr, 165662306a36Sopenharmony_ci &sensor_dev_attr_pwm3_enable.dev_attr.attr, 165762306a36Sopenharmony_ci 165862306a36Sopenharmony_ci NULL 165962306a36Sopenharmony_ci}; 166062306a36Sopenharmony_ci 166162306a36Sopenharmony_cistatic const struct attribute_group w83627hf_group_opt = { 166262306a36Sopenharmony_ci .attrs = w83627hf_attributes_opt, 166362306a36Sopenharmony_ci}; 166462306a36Sopenharmony_ci 166562306a36Sopenharmony_cistatic int w83627hf_probe(struct platform_device *pdev) 166662306a36Sopenharmony_ci{ 166762306a36Sopenharmony_ci struct device *dev = &pdev->dev; 166862306a36Sopenharmony_ci struct w83627hf_sio_data *sio_data = dev_get_platdata(dev); 166962306a36Sopenharmony_ci struct w83627hf_data *data; 167062306a36Sopenharmony_ci struct resource *res; 167162306a36Sopenharmony_ci int err, i; 167262306a36Sopenharmony_ci 167362306a36Sopenharmony_ci static const char *names[] = { 167462306a36Sopenharmony_ci "w83627hf", 167562306a36Sopenharmony_ci "w83627thf", 167662306a36Sopenharmony_ci "w83697hf", 167762306a36Sopenharmony_ci "w83637hf", 167862306a36Sopenharmony_ci "w83687thf", 167962306a36Sopenharmony_ci }; 168062306a36Sopenharmony_ci 168162306a36Sopenharmony_ci res = platform_get_resource(pdev, IORESOURCE_IO, 0); 168262306a36Sopenharmony_ci if (!devm_request_region(dev, res->start, WINB_REGION_SIZE, DRVNAME)) { 168362306a36Sopenharmony_ci dev_err(dev, "Failed to request region 0x%lx-0x%lx\n", 168462306a36Sopenharmony_ci (unsigned long)res->start, 168562306a36Sopenharmony_ci (unsigned long)(res->start + WINB_REGION_SIZE - 1)); 168662306a36Sopenharmony_ci return -EBUSY; 168762306a36Sopenharmony_ci } 168862306a36Sopenharmony_ci 168962306a36Sopenharmony_ci data = devm_kzalloc(dev, sizeof(struct w83627hf_data), GFP_KERNEL); 169062306a36Sopenharmony_ci if (!data) 169162306a36Sopenharmony_ci return -ENOMEM; 169262306a36Sopenharmony_ci 169362306a36Sopenharmony_ci data->addr = res->start; 169462306a36Sopenharmony_ci data->type = sio_data->type; 169562306a36Sopenharmony_ci data->name = names[sio_data->type]; 169662306a36Sopenharmony_ci mutex_init(&data->lock); 169762306a36Sopenharmony_ci mutex_init(&data->update_lock); 169862306a36Sopenharmony_ci platform_set_drvdata(pdev, data); 169962306a36Sopenharmony_ci 170062306a36Sopenharmony_ci /* Initialize the chip */ 170162306a36Sopenharmony_ci w83627hf_init_device(pdev); 170262306a36Sopenharmony_ci 170362306a36Sopenharmony_ci /* A few vars need to be filled upon startup */ 170462306a36Sopenharmony_ci for (i = 0; i <= 2; i++) 170562306a36Sopenharmony_ci data->fan_min[i] = w83627hf_read_value( 170662306a36Sopenharmony_ci data, W83627HF_REG_FAN_MIN(i)); 170762306a36Sopenharmony_ci w83627hf_update_fan_div(data); 170862306a36Sopenharmony_ci 170962306a36Sopenharmony_ci /* Register common device attributes */ 171062306a36Sopenharmony_ci err = sysfs_create_group(&dev->kobj, &w83627hf_group); 171162306a36Sopenharmony_ci if (err) 171262306a36Sopenharmony_ci return err; 171362306a36Sopenharmony_ci 171462306a36Sopenharmony_ci /* Register chip-specific device attributes */ 171562306a36Sopenharmony_ci if (data->type == w83627hf || data->type == w83697hf) 171662306a36Sopenharmony_ci if ((err = device_create_file(dev, 171762306a36Sopenharmony_ci &sensor_dev_attr_in5_input.dev_attr)) 171862306a36Sopenharmony_ci || (err = device_create_file(dev, 171962306a36Sopenharmony_ci &sensor_dev_attr_in5_min.dev_attr)) 172062306a36Sopenharmony_ci || (err = device_create_file(dev, 172162306a36Sopenharmony_ci &sensor_dev_attr_in5_max.dev_attr)) 172262306a36Sopenharmony_ci || (err = device_create_file(dev, 172362306a36Sopenharmony_ci &sensor_dev_attr_in5_alarm.dev_attr)) 172462306a36Sopenharmony_ci || (err = device_create_file(dev, 172562306a36Sopenharmony_ci &sensor_dev_attr_in5_beep.dev_attr)) 172662306a36Sopenharmony_ci || (err = device_create_file(dev, 172762306a36Sopenharmony_ci &sensor_dev_attr_in6_input.dev_attr)) 172862306a36Sopenharmony_ci || (err = device_create_file(dev, 172962306a36Sopenharmony_ci &sensor_dev_attr_in6_min.dev_attr)) 173062306a36Sopenharmony_ci || (err = device_create_file(dev, 173162306a36Sopenharmony_ci &sensor_dev_attr_in6_max.dev_attr)) 173262306a36Sopenharmony_ci || (err = device_create_file(dev, 173362306a36Sopenharmony_ci &sensor_dev_attr_in6_alarm.dev_attr)) 173462306a36Sopenharmony_ci || (err = device_create_file(dev, 173562306a36Sopenharmony_ci &sensor_dev_attr_in6_beep.dev_attr)) 173662306a36Sopenharmony_ci || (err = device_create_file(dev, 173762306a36Sopenharmony_ci &sensor_dev_attr_pwm1_freq.dev_attr)) 173862306a36Sopenharmony_ci || (err = device_create_file(dev, 173962306a36Sopenharmony_ci &sensor_dev_attr_pwm2_freq.dev_attr))) 174062306a36Sopenharmony_ci goto error; 174162306a36Sopenharmony_ci 174262306a36Sopenharmony_ci if (data->type != w83697hf) 174362306a36Sopenharmony_ci if ((err = device_create_file(dev, 174462306a36Sopenharmony_ci &sensor_dev_attr_in1_input.dev_attr)) 174562306a36Sopenharmony_ci || (err = device_create_file(dev, 174662306a36Sopenharmony_ci &sensor_dev_attr_in1_min.dev_attr)) 174762306a36Sopenharmony_ci || (err = device_create_file(dev, 174862306a36Sopenharmony_ci &sensor_dev_attr_in1_max.dev_attr)) 174962306a36Sopenharmony_ci || (err = device_create_file(dev, 175062306a36Sopenharmony_ci &sensor_dev_attr_in1_alarm.dev_attr)) 175162306a36Sopenharmony_ci || (err = device_create_file(dev, 175262306a36Sopenharmony_ci &sensor_dev_attr_in1_beep.dev_attr)) 175362306a36Sopenharmony_ci || (err = device_create_file(dev, 175462306a36Sopenharmony_ci &sensor_dev_attr_fan3_input.dev_attr)) 175562306a36Sopenharmony_ci || (err = device_create_file(dev, 175662306a36Sopenharmony_ci &sensor_dev_attr_fan3_min.dev_attr)) 175762306a36Sopenharmony_ci || (err = device_create_file(dev, 175862306a36Sopenharmony_ci &sensor_dev_attr_fan3_div.dev_attr)) 175962306a36Sopenharmony_ci || (err = device_create_file(dev, 176062306a36Sopenharmony_ci &sensor_dev_attr_fan3_alarm.dev_attr)) 176162306a36Sopenharmony_ci || (err = device_create_file(dev, 176262306a36Sopenharmony_ci &sensor_dev_attr_fan3_beep.dev_attr)) 176362306a36Sopenharmony_ci || (err = device_create_file(dev, 176462306a36Sopenharmony_ci &sensor_dev_attr_temp3_input.dev_attr)) 176562306a36Sopenharmony_ci || (err = device_create_file(dev, 176662306a36Sopenharmony_ci &sensor_dev_attr_temp3_max.dev_attr)) 176762306a36Sopenharmony_ci || (err = device_create_file(dev, 176862306a36Sopenharmony_ci &sensor_dev_attr_temp3_max_hyst.dev_attr)) 176962306a36Sopenharmony_ci || (err = device_create_file(dev, 177062306a36Sopenharmony_ci &sensor_dev_attr_temp3_alarm.dev_attr)) 177162306a36Sopenharmony_ci || (err = device_create_file(dev, 177262306a36Sopenharmony_ci &sensor_dev_attr_temp3_beep.dev_attr)) 177362306a36Sopenharmony_ci || (err = device_create_file(dev, 177462306a36Sopenharmony_ci &sensor_dev_attr_temp3_type.dev_attr))) 177562306a36Sopenharmony_ci goto error; 177662306a36Sopenharmony_ci 177762306a36Sopenharmony_ci if (data->type != w83697hf && data->vid != 0xff) { 177862306a36Sopenharmony_ci /* Convert VID to voltage based on VRM */ 177962306a36Sopenharmony_ci data->vrm = vid_which_vrm(); 178062306a36Sopenharmony_ci 178162306a36Sopenharmony_ci if ((err = device_create_file(dev, &dev_attr_cpu0_vid)) 178262306a36Sopenharmony_ci || (err = device_create_file(dev, &dev_attr_vrm))) 178362306a36Sopenharmony_ci goto error; 178462306a36Sopenharmony_ci } 178562306a36Sopenharmony_ci 178662306a36Sopenharmony_ci if (data->type == w83627thf || data->type == w83637hf 178762306a36Sopenharmony_ci || data->type == w83687thf) { 178862306a36Sopenharmony_ci err = device_create_file(dev, &sensor_dev_attr_pwm3.dev_attr); 178962306a36Sopenharmony_ci if (err) 179062306a36Sopenharmony_ci goto error; 179162306a36Sopenharmony_ci } 179262306a36Sopenharmony_ci 179362306a36Sopenharmony_ci if (data->type == w83637hf || data->type == w83687thf) 179462306a36Sopenharmony_ci if ((err = device_create_file(dev, 179562306a36Sopenharmony_ci &sensor_dev_attr_pwm1_freq.dev_attr)) 179662306a36Sopenharmony_ci || (err = device_create_file(dev, 179762306a36Sopenharmony_ci &sensor_dev_attr_pwm2_freq.dev_attr)) 179862306a36Sopenharmony_ci || (err = device_create_file(dev, 179962306a36Sopenharmony_ci &sensor_dev_attr_pwm3_freq.dev_attr))) 180062306a36Sopenharmony_ci goto error; 180162306a36Sopenharmony_ci 180262306a36Sopenharmony_ci if (data->type != w83627hf) 180362306a36Sopenharmony_ci if ((err = device_create_file(dev, 180462306a36Sopenharmony_ci &sensor_dev_attr_pwm1_enable.dev_attr)) 180562306a36Sopenharmony_ci || (err = device_create_file(dev, 180662306a36Sopenharmony_ci &sensor_dev_attr_pwm2_enable.dev_attr))) 180762306a36Sopenharmony_ci goto error; 180862306a36Sopenharmony_ci 180962306a36Sopenharmony_ci if (data->type == w83627thf || data->type == w83637hf 181062306a36Sopenharmony_ci || data->type == w83687thf) { 181162306a36Sopenharmony_ci err = device_create_file(dev, 181262306a36Sopenharmony_ci &sensor_dev_attr_pwm3_enable.dev_attr); 181362306a36Sopenharmony_ci if (err) 181462306a36Sopenharmony_ci goto error; 181562306a36Sopenharmony_ci } 181662306a36Sopenharmony_ci 181762306a36Sopenharmony_ci data->hwmon_dev = hwmon_device_register(dev); 181862306a36Sopenharmony_ci if (IS_ERR(data->hwmon_dev)) { 181962306a36Sopenharmony_ci err = PTR_ERR(data->hwmon_dev); 182062306a36Sopenharmony_ci goto error; 182162306a36Sopenharmony_ci } 182262306a36Sopenharmony_ci 182362306a36Sopenharmony_ci return 0; 182462306a36Sopenharmony_ci 182562306a36Sopenharmony_ci error: 182662306a36Sopenharmony_ci sysfs_remove_group(&dev->kobj, &w83627hf_group); 182762306a36Sopenharmony_ci sysfs_remove_group(&dev->kobj, &w83627hf_group_opt); 182862306a36Sopenharmony_ci return err; 182962306a36Sopenharmony_ci} 183062306a36Sopenharmony_ci 183162306a36Sopenharmony_cistatic int w83627hf_remove(struct platform_device *pdev) 183262306a36Sopenharmony_ci{ 183362306a36Sopenharmony_ci struct w83627hf_data *data = platform_get_drvdata(pdev); 183462306a36Sopenharmony_ci 183562306a36Sopenharmony_ci hwmon_device_unregister(data->hwmon_dev); 183662306a36Sopenharmony_ci 183762306a36Sopenharmony_ci sysfs_remove_group(&pdev->dev.kobj, &w83627hf_group); 183862306a36Sopenharmony_ci sysfs_remove_group(&pdev->dev.kobj, &w83627hf_group_opt); 183962306a36Sopenharmony_ci 184062306a36Sopenharmony_ci return 0; 184162306a36Sopenharmony_ci} 184262306a36Sopenharmony_ci 184362306a36Sopenharmony_cistatic struct platform_driver w83627hf_driver = { 184462306a36Sopenharmony_ci .driver = { 184562306a36Sopenharmony_ci .name = DRVNAME, 184662306a36Sopenharmony_ci .pm = W83627HF_DEV_PM_OPS, 184762306a36Sopenharmony_ci }, 184862306a36Sopenharmony_ci .probe = w83627hf_probe, 184962306a36Sopenharmony_ci .remove = w83627hf_remove, 185062306a36Sopenharmony_ci}; 185162306a36Sopenharmony_ci 185262306a36Sopenharmony_cistatic int __init w83627hf_find(int sioaddr, unsigned short *addr, 185362306a36Sopenharmony_ci struct w83627hf_sio_data *sio_data) 185462306a36Sopenharmony_ci{ 185562306a36Sopenharmony_ci int err; 185662306a36Sopenharmony_ci u16 val; 185762306a36Sopenharmony_ci 185862306a36Sopenharmony_ci static __initconst char *const names[] = { 185962306a36Sopenharmony_ci "W83627HF", 186062306a36Sopenharmony_ci "W83627THF", 186162306a36Sopenharmony_ci "W83697HF", 186262306a36Sopenharmony_ci "W83637HF", 186362306a36Sopenharmony_ci "W83687THF", 186462306a36Sopenharmony_ci }; 186562306a36Sopenharmony_ci 186662306a36Sopenharmony_ci sio_data->sioaddr = sioaddr; 186762306a36Sopenharmony_ci err = superio_enter(sio_data); 186862306a36Sopenharmony_ci if (err) 186962306a36Sopenharmony_ci return err; 187062306a36Sopenharmony_ci 187162306a36Sopenharmony_ci err = -ENODEV; 187262306a36Sopenharmony_ci val = force_id ? force_id : superio_inb(sio_data, DEVID); 187362306a36Sopenharmony_ci switch (val) { 187462306a36Sopenharmony_ci case W627_DEVID: 187562306a36Sopenharmony_ci sio_data->type = w83627hf; 187662306a36Sopenharmony_ci break; 187762306a36Sopenharmony_ci case W627THF_DEVID: 187862306a36Sopenharmony_ci sio_data->type = w83627thf; 187962306a36Sopenharmony_ci break; 188062306a36Sopenharmony_ci case W697_DEVID: 188162306a36Sopenharmony_ci sio_data->type = w83697hf; 188262306a36Sopenharmony_ci break; 188362306a36Sopenharmony_ci case W637_DEVID: 188462306a36Sopenharmony_ci sio_data->type = w83637hf; 188562306a36Sopenharmony_ci break; 188662306a36Sopenharmony_ci case W687THF_DEVID: 188762306a36Sopenharmony_ci sio_data->type = w83687thf; 188862306a36Sopenharmony_ci break; 188962306a36Sopenharmony_ci case 0xff: /* No device at all */ 189062306a36Sopenharmony_ci goto exit; 189162306a36Sopenharmony_ci default: 189262306a36Sopenharmony_ci pr_debug(DRVNAME ": Unsupported chip (DEVID=0x%02x)\n", val); 189362306a36Sopenharmony_ci goto exit; 189462306a36Sopenharmony_ci } 189562306a36Sopenharmony_ci 189662306a36Sopenharmony_ci superio_select(sio_data, W83627HF_LD_HWM); 189762306a36Sopenharmony_ci val = (superio_inb(sio_data, WINB_BASE_REG) << 8) | 189862306a36Sopenharmony_ci superio_inb(sio_data, WINB_BASE_REG + 1); 189962306a36Sopenharmony_ci *addr = val & WINB_ALIGNMENT; 190062306a36Sopenharmony_ci if (*addr == 0) { 190162306a36Sopenharmony_ci pr_warn("Base address not set, skipping\n"); 190262306a36Sopenharmony_ci goto exit; 190362306a36Sopenharmony_ci } 190462306a36Sopenharmony_ci 190562306a36Sopenharmony_ci val = superio_inb(sio_data, WINB_ACT_REG); 190662306a36Sopenharmony_ci if (!(val & 0x01)) { 190762306a36Sopenharmony_ci pr_warn("Enabling HWM logical device\n"); 190862306a36Sopenharmony_ci superio_outb(sio_data, WINB_ACT_REG, val | 0x01); 190962306a36Sopenharmony_ci } 191062306a36Sopenharmony_ci 191162306a36Sopenharmony_ci err = 0; 191262306a36Sopenharmony_ci pr_info(DRVNAME ": Found %s chip at %#x\n", 191362306a36Sopenharmony_ci names[sio_data->type], *addr); 191462306a36Sopenharmony_ci 191562306a36Sopenharmony_ci exit: 191662306a36Sopenharmony_ci superio_exit(sio_data); 191762306a36Sopenharmony_ci return err; 191862306a36Sopenharmony_ci} 191962306a36Sopenharmony_ci 192062306a36Sopenharmony_cistatic int __init w83627hf_device_add(unsigned short address, 192162306a36Sopenharmony_ci const struct w83627hf_sio_data *sio_data) 192262306a36Sopenharmony_ci{ 192362306a36Sopenharmony_ci struct resource res = { 192462306a36Sopenharmony_ci .start = address + WINB_REGION_OFFSET, 192562306a36Sopenharmony_ci .end = address + WINB_REGION_OFFSET + WINB_REGION_SIZE - 1, 192662306a36Sopenharmony_ci .name = DRVNAME, 192762306a36Sopenharmony_ci .flags = IORESOURCE_IO, 192862306a36Sopenharmony_ci }; 192962306a36Sopenharmony_ci int err; 193062306a36Sopenharmony_ci 193162306a36Sopenharmony_ci err = acpi_check_resource_conflict(&res); 193262306a36Sopenharmony_ci if (err) 193362306a36Sopenharmony_ci goto exit; 193462306a36Sopenharmony_ci 193562306a36Sopenharmony_ci pdev = platform_device_alloc(DRVNAME, address); 193662306a36Sopenharmony_ci if (!pdev) { 193762306a36Sopenharmony_ci err = -ENOMEM; 193862306a36Sopenharmony_ci pr_err("Device allocation failed\n"); 193962306a36Sopenharmony_ci goto exit; 194062306a36Sopenharmony_ci } 194162306a36Sopenharmony_ci 194262306a36Sopenharmony_ci err = platform_device_add_resources(pdev, &res, 1); 194362306a36Sopenharmony_ci if (err) { 194462306a36Sopenharmony_ci pr_err("Device resource addition failed (%d)\n", err); 194562306a36Sopenharmony_ci goto exit_device_put; 194662306a36Sopenharmony_ci } 194762306a36Sopenharmony_ci 194862306a36Sopenharmony_ci err = platform_device_add_data(pdev, sio_data, 194962306a36Sopenharmony_ci sizeof(struct w83627hf_sio_data)); 195062306a36Sopenharmony_ci if (err) { 195162306a36Sopenharmony_ci pr_err("Platform data allocation failed\n"); 195262306a36Sopenharmony_ci goto exit_device_put; 195362306a36Sopenharmony_ci } 195462306a36Sopenharmony_ci 195562306a36Sopenharmony_ci err = platform_device_add(pdev); 195662306a36Sopenharmony_ci if (err) { 195762306a36Sopenharmony_ci pr_err("Device addition failed (%d)\n", err); 195862306a36Sopenharmony_ci goto exit_device_put; 195962306a36Sopenharmony_ci } 196062306a36Sopenharmony_ci 196162306a36Sopenharmony_ci return 0; 196262306a36Sopenharmony_ci 196362306a36Sopenharmony_ciexit_device_put: 196462306a36Sopenharmony_ci platform_device_put(pdev); 196562306a36Sopenharmony_ciexit: 196662306a36Sopenharmony_ci return err; 196762306a36Sopenharmony_ci} 196862306a36Sopenharmony_ci 196962306a36Sopenharmony_cistatic int __init sensors_w83627hf_init(void) 197062306a36Sopenharmony_ci{ 197162306a36Sopenharmony_ci int err; 197262306a36Sopenharmony_ci unsigned short address; 197362306a36Sopenharmony_ci struct w83627hf_sio_data sio_data; 197462306a36Sopenharmony_ci 197562306a36Sopenharmony_ci if (w83627hf_find(0x2e, &address, &sio_data) 197662306a36Sopenharmony_ci && w83627hf_find(0x4e, &address, &sio_data)) 197762306a36Sopenharmony_ci return -ENODEV; 197862306a36Sopenharmony_ci 197962306a36Sopenharmony_ci err = platform_driver_register(&w83627hf_driver); 198062306a36Sopenharmony_ci if (err) 198162306a36Sopenharmony_ci goto exit; 198262306a36Sopenharmony_ci 198362306a36Sopenharmony_ci /* Sets global pdev as a side effect */ 198462306a36Sopenharmony_ci err = w83627hf_device_add(address, &sio_data); 198562306a36Sopenharmony_ci if (err) 198662306a36Sopenharmony_ci goto exit_driver; 198762306a36Sopenharmony_ci 198862306a36Sopenharmony_ci return 0; 198962306a36Sopenharmony_ci 199062306a36Sopenharmony_ciexit_driver: 199162306a36Sopenharmony_ci platform_driver_unregister(&w83627hf_driver); 199262306a36Sopenharmony_ciexit: 199362306a36Sopenharmony_ci return err; 199462306a36Sopenharmony_ci} 199562306a36Sopenharmony_ci 199662306a36Sopenharmony_cistatic void __exit sensors_w83627hf_exit(void) 199762306a36Sopenharmony_ci{ 199862306a36Sopenharmony_ci platform_device_unregister(pdev); 199962306a36Sopenharmony_ci platform_driver_unregister(&w83627hf_driver); 200062306a36Sopenharmony_ci} 200162306a36Sopenharmony_ci 200262306a36Sopenharmony_ciMODULE_AUTHOR("Frodo Looijaard <frodol@dds.nl>, " 200362306a36Sopenharmony_ci "Philip Edelbrock <phil@netroedge.com>, " 200462306a36Sopenharmony_ci "and Mark Studebaker <mdsxyz123@yahoo.com>"); 200562306a36Sopenharmony_ciMODULE_DESCRIPTION("W83627HF driver"); 200662306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 200762306a36Sopenharmony_ci 200862306a36Sopenharmony_cimodule_init(sensors_w83627hf_init); 200962306a36Sopenharmony_cimodule_exit(sensors_w83627hf_exit); 2010