16800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek/* 247efe8772f241c4be540355d90e38b79cc1092a4Guenter Roeck * w83793.c - Linux kernel driver for hardware monitoring 347efe8772f241c4be540355d90e38b79cc1092a4Guenter Roeck * Copyright (C) 2006 Winbond Electronics Corp. 447efe8772f241c4be540355d90e38b79cc1092a4Guenter Roeck * Yuan Mu 547efe8772f241c4be540355d90e38b79cc1092a4Guenter Roeck * Rudolf Marek <r.marek@assembler.cz> 647efe8772f241c4be540355d90e38b79cc1092a4Guenter Roeck * Copyright (C) 2009-2010 Sven Anders <anders@anduras.de>, ANDURAS AG. 747efe8772f241c4be540355d90e38b79cc1092a4Guenter Roeck * Watchdog driver part 847efe8772f241c4be540355d90e38b79cc1092a4Guenter Roeck * (Based partially on fschmd driver, 947efe8772f241c4be540355d90e38b79cc1092a4Guenter Roeck * Copyright 2007-2008 by Hans de Goede) 1047efe8772f241c4be540355d90e38b79cc1092a4Guenter Roeck * 1147efe8772f241c4be540355d90e38b79cc1092a4Guenter Roeck * This program is free software; you can redistribute it and/or modify 1247efe8772f241c4be540355d90e38b79cc1092a4Guenter Roeck * it under the terms of the GNU General Public License as published by 1347efe8772f241c4be540355d90e38b79cc1092a4Guenter Roeck * the Free Software Foundation - version 2. 1447efe8772f241c4be540355d90e38b79cc1092a4Guenter Roeck * 1547efe8772f241c4be540355d90e38b79cc1092a4Guenter Roeck * This program is distributed in the hope that it will be useful, 1647efe8772f241c4be540355d90e38b79cc1092a4Guenter Roeck * but WITHOUT ANY WARRANTY; without even the implied warranty of 1747efe8772f241c4be540355d90e38b79cc1092a4Guenter Roeck * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 1847efe8772f241c4be540355d90e38b79cc1092a4Guenter Roeck * GNU General Public License for more details. 1947efe8772f241c4be540355d90e38b79cc1092a4Guenter Roeck * 2047efe8772f241c4be540355d90e38b79cc1092a4Guenter Roeck * You should have received a copy of the GNU General Public License 2147efe8772f241c4be540355d90e38b79cc1092a4Guenter Roeck * along with this program; if not, write to the Free Software 2247efe8772f241c4be540355d90e38b79cc1092a4Guenter Roeck * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 2347efe8772f241c4be540355d90e38b79cc1092a4Guenter Roeck * 02110-1301 USA. 2447efe8772f241c4be540355d90e38b79cc1092a4Guenter Roeck */ 256800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek 266800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek/* 2747efe8772f241c4be540355d90e38b79cc1092a4Guenter Roeck * Supports following chips: 2847efe8772f241c4be540355d90e38b79cc1092a4Guenter Roeck * 2947efe8772f241c4be540355d90e38b79cc1092a4Guenter Roeck * Chip #vin #fanin #pwm #temp wchipid vendid i2c ISA 3047efe8772f241c4be540355d90e38b79cc1092a4Guenter Roeck * w83793 10 12 8 6 0x7b 0x5ca3 yes no 3147efe8772f241c4be540355d90e38b79cc1092a4Guenter Roeck */ 326800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek 336800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek#include <linux/module.h> 346800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek#include <linux/init.h> 356800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek#include <linux/slab.h> 366800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek#include <linux/i2c.h> 376800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek#include <linux/hwmon.h> 386800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek#include <linux/hwmon-vid.h> 396800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek#include <linux/hwmon-sysfs.h> 406800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek#include <linux/err.h> 416800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek#include <linux/mutex.h> 425852f9609d21794c45964129b03365883150a6d0Sven Anders#include <linux/fs.h> 435852f9609d21794c45964129b03365883150a6d0Sven Anders#include <linux/watchdog.h> 445852f9609d21794c45964129b03365883150a6d0Sven Anders#include <linux/miscdevice.h> 455852f9609d21794c45964129b03365883150a6d0Sven Anders#include <linux/uaccess.h> 465852f9609d21794c45964129b03365883150a6d0Sven Anders#include <linux/kref.h> 475852f9609d21794c45964129b03365883150a6d0Sven Anders#include <linux/notifier.h> 485852f9609d21794c45964129b03365883150a6d0Sven Anders#include <linux/reboot.h> 49dcd8f39230b9f724ba4f55f14ed2bb8119204385Jean Delvare#include <linux/jiffies.h> 505852f9609d21794c45964129b03365883150a6d0Sven Anders 515852f9609d21794c45964129b03365883150a6d0Sven Anders/* Default values */ 525852f9609d21794c45964129b03365883150a6d0Sven Anders#define WATCHDOG_TIMEOUT 2 /* 2 minute default timeout */ 536800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek 546800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek/* Addresses to scan */ 5525e9c86d5a6d82ea45eb680fc66bf73ac5e50dffMark M. Hoffmanstatic const unsigned short normal_i2c[] = { 0x2c, 0x2d, 0x2e, 0x2f, 5625e9c86d5a6d82ea45eb680fc66bf73ac5e50dffMark M. Hoffman I2C_CLIENT_END }; 576800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek 586800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek/* Insmod parameters */ 593aed198c35567e5a721f52c0bde23167867e6af6Jean Delvare 603aed198c35567e5a721f52c0bde23167867e6af6Jean Delvarestatic unsigned short force_subclients[4]; 613aed198c35567e5a721f52c0bde23167867e6af6Jean Delvaremodule_param_array(force_subclients, short, NULL, 0); 62b55f375725ff85aada394da488802b0a3cc99e88Guenter RoeckMODULE_PARM_DESC(force_subclients, 63b55f375725ff85aada394da488802b0a3cc99e88Guenter Roeck "List of subclient addresses: {bus, clientaddr, subclientaddr1, subclientaddr2}"); 646800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek 6590ab5ee94171b3e28de6bb42ee30b527014e0be7Rusty Russellstatic bool reset; 666800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marekmodule_param(reset, bool, 0); 676800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf MarekMODULE_PARM_DESC(reset, "Set to 1 to reset chip, not recommended"); 686800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek 695852f9609d21794c45964129b03365883150a6d0Sven Andersstatic int timeout = WATCHDOG_TIMEOUT; /* default timeout in minutes */ 705852f9609d21794c45964129b03365883150a6d0Sven Andersmodule_param(timeout, int, 0); 715852f9609d21794c45964129b03365883150a6d0Sven AndersMODULE_PARM_DESC(timeout, 725852f9609d21794c45964129b03365883150a6d0Sven Anders "Watchdog timeout in minutes. 2<= timeout <=255 (default=" 735852f9609d21794c45964129b03365883150a6d0Sven Anders __MODULE_STRING(WATCHDOG_TIMEOUT) ")"); 745852f9609d21794c45964129b03365883150a6d0Sven Anders 7586a1e1896c2710402e29a875d8d830244274244dWim Van Sebroeckstatic bool nowayout = WATCHDOG_NOWAYOUT; 7686a1e1896c2710402e29a875d8d830244274244dWim Van Sebroeckmodule_param(nowayout, bool, 0); 775852f9609d21794c45964129b03365883150a6d0Sven AndersMODULE_PARM_DESC(nowayout, 785852f9609d21794c45964129b03365883150a6d0Sven Anders "Watchdog cannot be stopped once started (default=" 795852f9609d21794c45964129b03365883150a6d0Sven Anders __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); 805852f9609d21794c45964129b03365883150a6d0Sven Anders 816800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek/* 8247efe8772f241c4be540355d90e38b79cc1092a4Guenter Roeck * Address 0x00, 0x0d, 0x0e, 0x0f in all three banks are reserved 8347efe8772f241c4be540355d90e38b79cc1092a4Guenter Roeck * as ID, Bank Select registers 8447efe8772f241c4be540355d90e38b79cc1092a4Guenter Roeck */ 856800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek#define W83793_REG_BANKSEL 0x00 866800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek#define W83793_REG_VENDORID 0x0d 876800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek#define W83793_REG_CHIPID 0x0e 886800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek#define W83793_REG_DEVICEID 0x0f 896800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek 906800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek#define W83793_REG_CONFIG 0x40 916800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek#define W83793_REG_MFC 0x58 926800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek#define W83793_REG_FANIN_CTRL 0x5c 936800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek#define W83793_REG_FANIN_SEL 0x5d 946800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek#define W83793_REG_I2C_ADDR 0x0b 956800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek#define W83793_REG_I2C_SUBADDR 0x0c 966800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek#define W83793_REG_VID_INA 0x05 976800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek#define W83793_REG_VID_INB 0x06 986800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek#define W83793_REG_VID_LATCHA 0x07 996800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek#define W83793_REG_VID_LATCHB 0x08 1006800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek#define W83793_REG_VID_CTRL 0x59 1016800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek 1025852f9609d21794c45964129b03365883150a6d0Sven Anders#define W83793_REG_WDT_LOCK 0x01 1035852f9609d21794c45964129b03365883150a6d0Sven Anders#define W83793_REG_WDT_ENABLE 0x02 1045852f9609d21794c45964129b03365883150a6d0Sven Anders#define W83793_REG_WDT_STATUS 0x03 1055852f9609d21794c45964129b03365883150a6d0Sven Anders#define W83793_REG_WDT_TIMEOUT 0x04 1065852f9609d21794c45964129b03365883150a6d0Sven Anders 1076800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marekstatic u16 W83793_REG_TEMP_MODE[2] = { 0x5e, 0x5f }; 1086800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek 1096800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek#define TEMP_READ 0 1106800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek#define TEMP_CRIT 1 1116800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek#define TEMP_CRIT_HYST 2 1126800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek#define TEMP_WARN 3 1136800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek#define TEMP_WARN_HYST 4 11447efe8772f241c4be540355d90e38b79cc1092a4Guenter Roeck/* 11547efe8772f241c4be540355d90e38b79cc1092a4Guenter Roeck * only crit and crit_hyst affect real-time alarm status 11647efe8772f241c4be540355d90e38b79cc1092a4Guenter Roeck * current crit crit_hyst warn warn_hyst 11747efe8772f241c4be540355d90e38b79cc1092a4Guenter Roeck */ 1186800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marekstatic u16 W83793_REG_TEMP[][5] = { 1196800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek {0x1c, 0x78, 0x79, 0x7a, 0x7b}, 1206800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek {0x1d, 0x7c, 0x7d, 0x7e, 0x7f}, 1216800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek {0x1e, 0x80, 0x81, 0x82, 0x83}, 1226800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek {0x1f, 0x84, 0x85, 0x86, 0x87}, 1236800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek {0x20, 0x88, 0x89, 0x8a, 0x8b}, 1246800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek {0x21, 0x8c, 0x8d, 0x8e, 0x8f}, 1256800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek}; 1266800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek 1276800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek#define W83793_REG_TEMP_LOW_BITS 0x22 1286800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek 1296800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek#define W83793_REG_BEEP(index) (0x53 + (index)) 1306800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek#define W83793_REG_ALARM(index) (0x4b + (index)) 1316800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek 1326800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek#define W83793_REG_CLR_CHASSIS 0x4a /* SMI MASK4 */ 1336800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek#define W83793_REG_IRQ_CTRL 0x50 1346800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek#define W83793_REG_OVT_CTRL 0x51 1356800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek#define W83793_REG_OVT_BEEP 0x52 1366800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek 1376800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek#define IN_READ 0 1386800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek#define IN_MAX 1 1396800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek#define IN_LOW 2 1406800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marekstatic const u16 W83793_REG_IN[][3] = { 1416800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek /* Current, High, Low */ 1426800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek {0x10, 0x60, 0x61}, /* Vcore A */ 1436800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek {0x11, 0x62, 0x63}, /* Vcore B */ 1446800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek {0x12, 0x64, 0x65}, /* Vtt */ 1456800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek {0x14, 0x6a, 0x6b}, /* VSEN1 */ 1466800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek {0x15, 0x6c, 0x6d}, /* VSEN2 */ 1476800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek {0x16, 0x6e, 0x6f}, /* +3VSEN */ 1486800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek {0x17, 0x70, 0x71}, /* +12VSEN */ 1496800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek {0x18, 0x72, 0x73}, /* 5VDD */ 1506800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek {0x19, 0x74, 0x75}, /* 5VSB */ 1516800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek {0x1a, 0x76, 0x77}, /* VBAT */ 1526800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek}; 1536800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek 1546800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek/* Low Bits of Vcore A/B Vtt Read/High/Low */ 1556800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marekstatic const u16 W83793_REG_IN_LOW_BITS[] = { 0x1b, 0x68, 0x69 }; 1566800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marekstatic u8 scale_in[] = { 2, 2, 2, 16, 16, 16, 8, 24, 24, 16 }; 157ddca933bd554b4f81f27776f3cb9daa67cf241b1Gong Junstatic u8 scale_in_add[] = { 0, 0, 0, 0, 0, 0, 0, 150, 150, 0 }; 1586800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek 1596800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek#define W83793_REG_FAN(index) (0x23 + 2 * (index)) /* High byte */ 1606800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek#define W83793_REG_FAN_MIN(index) (0x90 + 2 * (index)) /* High byte */ 1616800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek 1626800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek#define W83793_REG_PWM_DEFAULT 0xb2 1636800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek#define W83793_REG_PWM_ENABLE 0x207 1646800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek#define W83793_REG_PWM_UPTIME 0xc3 /* Unit in 0.1 second */ 1656800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek#define W83793_REG_PWM_DOWNTIME 0xc4 /* Unit in 0.1 second */ 1666800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek#define W83793_REG_TEMP_CRITICAL 0xc5 1676800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek 1686800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek#define PWM_DUTY 0 1696800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek#define PWM_START 1 1706800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek#define PWM_NONSTOP 2 1715aebefb08682ebd67ea0b902950d00169e1451cbNicolas Kaiser#define PWM_STOP_TIME 3 1726800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek#define W83793_REG_PWM(index, nr) (((nr) == 0 ? 0xb3 : \ 1736800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek (nr) == 1 ? 0x220 : 0x218) + (index)) 1746800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek 1756800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek/* bit field, fan1 is bit0, fan2 is bit1 ... */ 1766800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek#define W83793_REG_TEMP_FAN_MAP(index) (0x201 + (index)) 1776800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek#define W83793_REG_TEMP_TOL(index) (0x208 + (index)) 1786800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek#define W83793_REG_TEMP_CRUISE(index) (0x210 + (index)) 1796800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek#define W83793_REG_PWM_STOP_TIME(index) (0x228 + (index)) 1806800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek#define W83793_REG_SF2_TEMP(index, nr) (0x230 + ((index) << 4) + (nr)) 1816800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek#define W83793_REG_SF2_PWM(index, nr) (0x238 + ((index) << 4) + (nr)) 1826800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek 1836800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marekstatic inline unsigned long FAN_FROM_REG(u16 val) 1846800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek{ 1856800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek if ((val >= 0xfff) || (val == 0)) 1866800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek return 0; 1877fe83ad877321f44c8141b8334bd2f6614deb739Frans Meulenbroeks return 1350000UL / val; 1886800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek} 1896800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek 1906800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marekstatic inline u16 FAN_TO_REG(long rpm) 1916800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek{ 1926800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek if (rpm <= 0) 1936800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek return 0x0fff; 1942a844c148e1f714ebf42cb96e1b172ce394c36c9Guenter Roeck return clamp_val((1350000 + (rpm >> 1)) / rpm, 1, 0xffe); 1956800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek} 1966800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek 1976800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marekstatic inline unsigned long TIME_FROM_REG(u8 reg) 1986800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek{ 1997fe83ad877321f44c8141b8334bd2f6614deb739Frans Meulenbroeks return reg * 100; 2006800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek} 2016800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek 2026800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marekstatic inline u8 TIME_TO_REG(unsigned long val) 2036800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek{ 2042a844c148e1f714ebf42cb96e1b172ce394c36c9Guenter Roeck return clamp_val((val + 50) / 100, 0, 0xff); 2056800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek} 2066800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek 2076800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marekstatic inline long TEMP_FROM_REG(s8 reg) 2086800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek{ 2097fe83ad877321f44c8141b8334bd2f6614deb739Frans Meulenbroeks return reg * 1000; 2106800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek} 2116800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek 2126800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marekstatic inline s8 TEMP_TO_REG(long val, s8 min, s8 max) 2136800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek{ 2142a844c148e1f714ebf42cb96e1b172ce394c36c9Guenter Roeck return clamp_val((val + (val < 0 ? -500 : 500)) / 1000, min, max); 2156800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek} 2166800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek 2176800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marekstruct w83793_data { 2186800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek struct i2c_client *lm75[2]; 2191beeffe43311f64df8dd0ab08ff6b1858c58363fTony Jones struct device *hwmon_dev; 2206800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek struct mutex update_lock; 2216800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek char valid; /* !=0 if following fields are valid */ 2226800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek unsigned long last_updated; /* In jiffies */ 2236800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek unsigned long last_nonvolatile; /* In jiffies, last time we update the 22447efe8772f241c4be540355d90e38b79cc1092a4Guenter Roeck * nonvolatile registers 22547efe8772f241c4be540355d90e38b79cc1092a4Guenter Roeck */ 2266800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek 2276800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek u8 bank; 2286800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek u8 vrm; 2296800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek u8 vid[2]; 2306800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek u8 in[10][3]; /* Register value, read/high/low */ 2316800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek u8 in_low_bits[3]; /* Additional resolution for VCore A/B Vtt */ 2326800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek 2336800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek u16 has_fan; /* Only fan1- fan5 has own pins */ 2346800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek u16 fan[12]; /* Register value combine */ 2356800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek u16 fan_min[12]; /* Register value combine */ 2366800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek 2376800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek s8 temp[6][5]; /* current, crit, crit_hyst,warn, warn_hyst */ 2386800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek u8 temp_low_bits; /* Additional resolution TD1-TD4 */ 2396800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek u8 temp_mode[2]; /* byte 0: Temp D1-D4 mode each has 2 bits 24047efe8772f241c4be540355d90e38b79cc1092a4Guenter Roeck * byte 1: Temp R1,R2 mode, each has 1 bit 24147efe8772f241c4be540355d90e38b79cc1092a4Guenter Roeck */ 2426800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek u8 temp_critical; /* If reached all fan will be at full speed */ 2436800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek u8 temp_fan_map[6]; /* Temp controls which pwm fan, bit field */ 2446800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek 2456800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek u8 has_pwm; 24646bed4dfe5f95f1fc8f68ead592a7e295bbbe01eGong Jun u8 has_temp; 247c70a8c345fd770ecb2ff334bdf88b63edaffb77dGong Jun u8 has_vid; 2486800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek u8 pwm_enable; /* Register value, each Temp has 1 bit */ 2496800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek u8 pwm_uptime; /* Register value */ 2506800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek u8 pwm_downtime; /* Register value */ 2516800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek u8 pwm_default; /* All fan default pwm, next poweron valid */ 2526800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek u8 pwm[8][3]; /* Register value */ 2536800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek u8 pwm_stop_time[8]; 2546800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek u8 temp_cruise[6]; 2556800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek 2566800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek u8 alarms[5]; /* realtime status registers */ 2576800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek u8 beeps[5]; 2586800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek u8 beep_enable; 2596800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek u8 tolerance[3]; /* Temp tolerance(Smart Fan I/II) */ 2606800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek u8 sf2_pwm[6][7]; /* Smart FanII: Fan duty cycle */ 2616800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek u8 sf2_temp[6][7]; /* Smart FanII: Temp level point */ 2625852f9609d21794c45964129b03365883150a6d0Sven Anders 2635852f9609d21794c45964129b03365883150a6d0Sven Anders /* watchdog */ 2645852f9609d21794c45964129b03365883150a6d0Sven Anders struct i2c_client *client; 2655852f9609d21794c45964129b03365883150a6d0Sven Anders struct mutex watchdog_lock; 2665852f9609d21794c45964129b03365883150a6d0Sven Anders struct list_head list; /* member of the watchdog_data_list */ 2675852f9609d21794c45964129b03365883150a6d0Sven Anders struct kref kref; 2685852f9609d21794c45964129b03365883150a6d0Sven Anders struct miscdevice watchdog_miscdev; 2695852f9609d21794c45964129b03365883150a6d0Sven Anders unsigned long watchdog_is_open; 2705852f9609d21794c45964129b03365883150a6d0Sven Anders char watchdog_expect_close; 2715852f9609d21794c45964129b03365883150a6d0Sven Anders char watchdog_name[10]; /* must be unique to avoid sysfs conflict */ 2725852f9609d21794c45964129b03365883150a6d0Sven Anders unsigned int watchdog_caused_reboot; 2735852f9609d21794c45964129b03365883150a6d0Sven Anders int watchdog_timeout; /* watchdog timeout in minutes */ 2746800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek}; 2756800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek 27647efe8772f241c4be540355d90e38b79cc1092a4Guenter Roeck/* 27747efe8772f241c4be540355d90e38b79cc1092a4Guenter Roeck * Somewhat ugly :( global data pointer list with all devices, so that 27847efe8772f241c4be540355d90e38b79cc1092a4Guenter Roeck * we can find our device data as when using misc_register. There is no 27947efe8772f241c4be540355d90e38b79cc1092a4Guenter Roeck * other method to get to one's device data from the open file-op and 28047efe8772f241c4be540355d90e38b79cc1092a4Guenter Roeck * for usage in the reboot notifier callback. 28147efe8772f241c4be540355d90e38b79cc1092a4Guenter Roeck */ 2825852f9609d21794c45964129b03365883150a6d0Sven Andersstatic LIST_HEAD(watchdog_data_list); 2835852f9609d21794c45964129b03365883150a6d0Sven Anders 2845852f9609d21794c45964129b03365883150a6d0Sven Anders/* Note this lock not only protect list access, but also data.kref access */ 2855852f9609d21794c45964129b03365883150a6d0Sven Andersstatic DEFINE_MUTEX(watchdog_data_mutex); 2865852f9609d21794c45964129b03365883150a6d0Sven Anders 28747efe8772f241c4be540355d90e38b79cc1092a4Guenter Roeck/* 28847efe8772f241c4be540355d90e38b79cc1092a4Guenter Roeck * Release our data struct when we're detached from the i2c client *and* all 28947efe8772f241c4be540355d90e38b79cc1092a4Guenter Roeck * references to our watchdog device are released 29047efe8772f241c4be540355d90e38b79cc1092a4Guenter Roeck */ 2915852f9609d21794c45964129b03365883150a6d0Sven Andersstatic void w83793_release_resources(struct kref *ref) 2925852f9609d21794c45964129b03365883150a6d0Sven Anders{ 2935852f9609d21794c45964129b03365883150a6d0Sven Anders struct w83793_data *data = container_of(ref, struct w83793_data, kref); 2945852f9609d21794c45964129b03365883150a6d0Sven Anders kfree(data); 2955852f9609d21794c45964129b03365883150a6d0Sven Anders} 2965852f9609d21794c45964129b03365883150a6d0Sven Anders 2976800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marekstatic u8 w83793_read_value(struct i2c_client *client, u16 reg); 2986800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marekstatic int w83793_write_value(struct i2c_client *client, u16 reg, u8 value); 299a7f13a6ec40379fe2116c647ac8e569227ba8d4fJean Delvarestatic int w83793_probe(struct i2c_client *client, 300a7f13a6ec40379fe2116c647ac8e569227ba8d4fJean Delvare const struct i2c_device_id *id); 301310ec79210d754afe51e2e4a983e846b60179abdJean Delvarestatic int w83793_detect(struct i2c_client *client, 302a7f13a6ec40379fe2116c647ac8e569227ba8d4fJean Delvare struct i2c_board_info *info); 303a7f13a6ec40379fe2116c647ac8e569227ba8d4fJean Delvarestatic int w83793_remove(struct i2c_client *client); 3046800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marekstatic void w83793_init_client(struct i2c_client *client); 3056800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marekstatic void w83793_update_nonvolatile(struct device *dev); 3066800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marekstatic struct w83793_data *w83793_update_device(struct device *dev); 3076800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek 308a7f13a6ec40379fe2116c647ac8e569227ba8d4fJean Delvarestatic const struct i2c_device_id w83793_id[] = { 3091f86df49ddfd0067cce941187d57b2fd2f749a9eJean Delvare { "w83793", 0 }, 310a7f13a6ec40379fe2116c647ac8e569227ba8d4fJean Delvare { } 311a7f13a6ec40379fe2116c647ac8e569227ba8d4fJean Delvare}; 312a7f13a6ec40379fe2116c647ac8e569227ba8d4fJean DelvareMODULE_DEVICE_TABLE(i2c, w83793_id); 313a7f13a6ec40379fe2116c647ac8e569227ba8d4fJean Delvare 3146800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marekstatic struct i2c_driver w83793_driver = { 315a7f13a6ec40379fe2116c647ac8e569227ba8d4fJean Delvare .class = I2C_CLASS_HWMON, 3166800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek .driver = { 3176800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek .name = "w83793", 3186800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek }, 319a7f13a6ec40379fe2116c647ac8e569227ba8d4fJean Delvare .probe = w83793_probe, 320a7f13a6ec40379fe2116c647ac8e569227ba8d4fJean Delvare .remove = w83793_remove, 321a7f13a6ec40379fe2116c647ac8e569227ba8d4fJean Delvare .id_table = w83793_id, 322a7f13a6ec40379fe2116c647ac8e569227ba8d4fJean Delvare .detect = w83793_detect, 323c3813d6af177fab19e322f3114b1f64fbcf08d71Jean Delvare .address_list = normal_i2c, 3246800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek}; 3256800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek 3266800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marekstatic ssize_t 3276800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marekshow_vrm(struct device *dev, struct device_attribute *attr, char *buf) 3286800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek{ 3298f74efe81d122c071410fd74f42879ef81439fa4Jean Delvare struct w83793_data *data = dev_get_drvdata(dev); 3306800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek return sprintf(buf, "%d\n", data->vrm); 3316800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek} 3326800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek 3336800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marekstatic ssize_t 3346800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marekshow_vid(struct device *dev, struct device_attribute *attr, char *buf) 3356800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek{ 3366800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek struct w83793_data *data = w83793_update_device(dev); 3376800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek struct sensor_device_attribute_2 *sensor_attr = 3386800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek to_sensor_dev_attr_2(attr); 3396800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek int index = sensor_attr->index; 3406800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek 3416800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek return sprintf(buf, "%d\n", vid_from_reg(data->vid[index], data->vrm)); 3426800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek} 3436800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek 3446800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marekstatic ssize_t 3456800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marekstore_vrm(struct device *dev, struct device_attribute *attr, 3466800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek const char *buf, size_t count) 3476800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek{ 3488f74efe81d122c071410fd74f42879ef81439fa4Jean Delvare struct w83793_data *data = dev_get_drvdata(dev); 34947efe8772f241c4be540355d90e38b79cc1092a4Guenter Roeck unsigned long val; 35047efe8772f241c4be540355d90e38b79cc1092a4Guenter Roeck int err; 35147efe8772f241c4be540355d90e38b79cc1092a4Guenter Roeck 35247efe8772f241c4be540355d90e38b79cc1092a4Guenter Roeck err = kstrtoul(buf, 10, &val); 35347efe8772f241c4be540355d90e38b79cc1092a4Guenter Roeck if (err) 35447efe8772f241c4be540355d90e38b79cc1092a4Guenter Roeck return err; 35547efe8772f241c4be540355d90e38b79cc1092a4Guenter Roeck 3562aeee04df8e0ea4d5b91da630687af1a1d93c941Axel Lin if (val > 255) 3572aeee04df8e0ea4d5b91da630687af1a1d93c941Axel Lin return -EINVAL; 3582aeee04df8e0ea4d5b91da630687af1a1d93c941Axel Lin 35947efe8772f241c4be540355d90e38b79cc1092a4Guenter Roeck data->vrm = val; 3606800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek return count; 3616800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek} 3626800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek 3636800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek#define ALARM_STATUS 0 3646800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek#define BEEP_ENABLE 1 3656800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marekstatic ssize_t 3666800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marekshow_alarm_beep(struct device *dev, struct device_attribute *attr, char *buf) 3676800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek{ 3686800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek struct w83793_data *data = w83793_update_device(dev); 3696800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek struct sensor_device_attribute_2 *sensor_attr = 3706800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek to_sensor_dev_attr_2(attr); 3716800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek int nr = sensor_attr->nr; 3726800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek int index = sensor_attr->index >> 3; 3736800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek int bit = sensor_attr->index & 0x07; 3746800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek u8 val; 3756800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek 37647efe8772f241c4be540355d90e38b79cc1092a4Guenter Roeck if (nr == ALARM_STATUS) { 3776800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek val = (data->alarms[index] >> (bit)) & 1; 3786800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek } else { /* BEEP_ENABLE */ 3796800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek val = (data->beeps[index] >> (bit)) & 1; 3806800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek } 3816800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek 3826800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek return sprintf(buf, "%u\n", val); 3836800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek} 3846800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek 3856800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marekstatic ssize_t 3866800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marekstore_beep(struct device *dev, struct device_attribute *attr, 3876800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek const char *buf, size_t count) 3886800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek{ 3896800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek struct i2c_client *client = to_i2c_client(dev); 3906800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek struct w83793_data *data = i2c_get_clientdata(client); 3916800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek struct sensor_device_attribute_2 *sensor_attr = 3926800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek to_sensor_dev_attr_2(attr); 3936800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek int index = sensor_attr->index >> 3; 3946800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek int shift = sensor_attr->index & 0x07; 3956800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek u8 beep_bit = 1 << shift; 39647efe8772f241c4be540355d90e38b79cc1092a4Guenter Roeck unsigned long val; 39747efe8772f241c4be540355d90e38b79cc1092a4Guenter Roeck int err; 3986800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek 39947efe8772f241c4be540355d90e38b79cc1092a4Guenter Roeck err = kstrtoul(buf, 10, &val); 40047efe8772f241c4be540355d90e38b79cc1092a4Guenter Roeck if (err) 40147efe8772f241c4be540355d90e38b79cc1092a4Guenter Roeck return err; 40247efe8772f241c4be540355d90e38b79cc1092a4Guenter Roeck 40347efe8772f241c4be540355d90e38b79cc1092a4Guenter Roeck if (val > 1) 4046800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek return -EINVAL; 4056800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek 4066800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek mutex_lock(&data->update_lock); 4076800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek data->beeps[index] = w83793_read_value(client, W83793_REG_BEEP(index)); 4086800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek data->beeps[index] &= ~beep_bit; 4096800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek data->beeps[index] |= val << shift; 4106800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek w83793_write_value(client, W83793_REG_BEEP(index), data->beeps[index]); 4116800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek mutex_unlock(&data->update_lock); 4126800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek 4136800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek return count; 4146800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek} 4156800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek 4166800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marekstatic ssize_t 4176800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marekshow_beep_enable(struct device *dev, struct device_attribute *attr, char *buf) 4186800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek{ 4196800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek struct w83793_data *data = w83793_update_device(dev); 4206800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek return sprintf(buf, "%u\n", (data->beep_enable >> 1) & 0x01); 4216800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek} 4226800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek 4236800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marekstatic ssize_t 4246800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marekstore_beep_enable(struct device *dev, struct device_attribute *attr, 4256800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek const char *buf, size_t count) 4266800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek{ 4276800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek struct i2c_client *client = to_i2c_client(dev); 4286800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek struct w83793_data *data = i2c_get_clientdata(client); 42947efe8772f241c4be540355d90e38b79cc1092a4Guenter Roeck unsigned long val; 43047efe8772f241c4be540355d90e38b79cc1092a4Guenter Roeck int err; 43147efe8772f241c4be540355d90e38b79cc1092a4Guenter Roeck 43247efe8772f241c4be540355d90e38b79cc1092a4Guenter Roeck err = kstrtoul(buf, 10, &val); 43347efe8772f241c4be540355d90e38b79cc1092a4Guenter Roeck if (err) 43447efe8772f241c4be540355d90e38b79cc1092a4Guenter Roeck return err; 4356800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek 43647efe8772f241c4be540355d90e38b79cc1092a4Guenter Roeck if (val > 1) 4376800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek return -EINVAL; 4386800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek 4396800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek mutex_lock(&data->update_lock); 4406800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek data->beep_enable = w83793_read_value(client, W83793_REG_OVT_BEEP) 4416800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek & 0xfd; 4426800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek data->beep_enable |= val << 1; 4436800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek w83793_write_value(client, W83793_REG_OVT_BEEP, data->beep_enable); 4446800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek mutex_unlock(&data->update_lock); 4456800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek 4466800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek return count; 4476800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek} 4486800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek 449a516dc3e9b19adbcaa9aeda0100ee8ee2938748aJean Delvare/* Write 0 to clear chassis alarm */ 450a516dc3e9b19adbcaa9aeda0100ee8ee2938748aJean Delvarestatic ssize_t 451a516dc3e9b19adbcaa9aeda0100ee8ee2938748aJean Delvarestore_chassis_clear(struct device *dev, 452a516dc3e9b19adbcaa9aeda0100ee8ee2938748aJean Delvare struct device_attribute *attr, const char *buf, 453a516dc3e9b19adbcaa9aeda0100ee8ee2938748aJean Delvare size_t count) 454a516dc3e9b19adbcaa9aeda0100ee8ee2938748aJean Delvare{ 455a516dc3e9b19adbcaa9aeda0100ee8ee2938748aJean Delvare struct i2c_client *client = to_i2c_client(dev); 456a516dc3e9b19adbcaa9aeda0100ee8ee2938748aJean Delvare struct w83793_data *data = i2c_get_clientdata(client); 457a516dc3e9b19adbcaa9aeda0100ee8ee2938748aJean Delvare unsigned long val; 458a516dc3e9b19adbcaa9aeda0100ee8ee2938748aJean Delvare u8 reg; 45947efe8772f241c4be540355d90e38b79cc1092a4Guenter Roeck int err; 460a516dc3e9b19adbcaa9aeda0100ee8ee2938748aJean Delvare 46147efe8772f241c4be540355d90e38b79cc1092a4Guenter Roeck err = kstrtoul(buf, 10, &val); 46247efe8772f241c4be540355d90e38b79cc1092a4Guenter Roeck if (err) 46347efe8772f241c4be540355d90e38b79cc1092a4Guenter Roeck return err; 46447efe8772f241c4be540355d90e38b79cc1092a4Guenter Roeck if (val) 465a516dc3e9b19adbcaa9aeda0100ee8ee2938748aJean Delvare return -EINVAL; 466a516dc3e9b19adbcaa9aeda0100ee8ee2938748aJean Delvare 467a516dc3e9b19adbcaa9aeda0100ee8ee2938748aJean Delvare mutex_lock(&data->update_lock); 468a516dc3e9b19adbcaa9aeda0100ee8ee2938748aJean Delvare reg = w83793_read_value(client, W83793_REG_CLR_CHASSIS); 469a516dc3e9b19adbcaa9aeda0100ee8ee2938748aJean Delvare w83793_write_value(client, W83793_REG_CLR_CHASSIS, reg | 0x80); 470a516dc3e9b19adbcaa9aeda0100ee8ee2938748aJean Delvare data->valid = 0; /* Force cache refresh */ 471a516dc3e9b19adbcaa9aeda0100ee8ee2938748aJean Delvare mutex_unlock(&data->update_lock); 472a516dc3e9b19adbcaa9aeda0100ee8ee2938748aJean Delvare return count; 473a516dc3e9b19adbcaa9aeda0100ee8ee2938748aJean Delvare} 474a516dc3e9b19adbcaa9aeda0100ee8ee2938748aJean Delvare 4756800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek#define FAN_INPUT 0 4766800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek#define FAN_MIN 1 4776800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marekstatic ssize_t 4786800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marekshow_fan(struct device *dev, struct device_attribute *attr, char *buf) 4796800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek{ 4806800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek struct sensor_device_attribute_2 *sensor_attr = 4816800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek to_sensor_dev_attr_2(attr); 4826800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek int nr = sensor_attr->nr; 4836800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek int index = sensor_attr->index; 4846800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek struct w83793_data *data = w83793_update_device(dev); 4856800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek u16 val; 4866800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek 48747efe8772f241c4be540355d90e38b79cc1092a4Guenter Roeck if (nr == FAN_INPUT) 4886800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek val = data->fan[index] & 0x0fff; 48947efe8772f241c4be540355d90e38b79cc1092a4Guenter Roeck else 4906800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek val = data->fan_min[index] & 0x0fff; 4916800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek 4926800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek return sprintf(buf, "%lu\n", FAN_FROM_REG(val)); 4936800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek} 4946800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek 4956800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marekstatic ssize_t 4966800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marekstore_fan_min(struct device *dev, struct device_attribute *attr, 4976800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek const char *buf, size_t count) 4986800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek{ 4996800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek struct sensor_device_attribute_2 *sensor_attr = 5006800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek to_sensor_dev_attr_2(attr); 5016800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek int index = sensor_attr->index; 5026800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek struct i2c_client *client = to_i2c_client(dev); 5036800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek struct w83793_data *data = i2c_get_clientdata(client); 50447efe8772f241c4be540355d90e38b79cc1092a4Guenter Roeck unsigned long val; 50547efe8772f241c4be540355d90e38b79cc1092a4Guenter Roeck int err; 50647efe8772f241c4be540355d90e38b79cc1092a4Guenter Roeck 50747efe8772f241c4be540355d90e38b79cc1092a4Guenter Roeck err = kstrtoul(buf, 10, &val); 50847efe8772f241c4be540355d90e38b79cc1092a4Guenter Roeck if (err) 50947efe8772f241c4be540355d90e38b79cc1092a4Guenter Roeck return err; 51047efe8772f241c4be540355d90e38b79cc1092a4Guenter Roeck val = FAN_TO_REG(val); 5116800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek 5126800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek mutex_lock(&data->update_lock); 5136800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek data->fan_min[index] = val; 5146800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek w83793_write_value(client, W83793_REG_FAN_MIN(index), 5156800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek (val >> 8) & 0xff); 5166800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek w83793_write_value(client, W83793_REG_FAN_MIN(index) + 1, val & 0xff); 5176800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek mutex_unlock(&data->update_lock); 5186800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek 5196800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek return count; 5206800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek} 5216800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek 5226800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marekstatic ssize_t 5236800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marekshow_pwm(struct device *dev, struct device_attribute *attr, char *buf) 5246800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek{ 5256800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek struct sensor_device_attribute_2 *sensor_attr = 5266800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek to_sensor_dev_attr_2(attr); 5276800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek struct w83793_data *data = w83793_update_device(dev); 5286800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek u16 val; 5296800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek int nr = sensor_attr->nr; 5306800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek int index = sensor_attr->index; 5316800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek 53247efe8772f241c4be540355d90e38b79cc1092a4Guenter Roeck if (nr == PWM_STOP_TIME) 5336800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek val = TIME_FROM_REG(data->pwm_stop_time[index]); 5346800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek else 5356800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek val = (data->pwm[index][nr] & 0x3f) << 2; 5366800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek 5376800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek return sprintf(buf, "%d\n", val); 5386800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek} 5396800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek 5406800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marekstatic ssize_t 5416800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marekstore_pwm(struct device *dev, struct device_attribute *attr, 5426800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek const char *buf, size_t count) 5436800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek{ 5446800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek struct i2c_client *client = to_i2c_client(dev); 5456800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek struct w83793_data *data = i2c_get_clientdata(client); 5466800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek struct sensor_device_attribute_2 *sensor_attr = 5476800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek to_sensor_dev_attr_2(attr); 5486800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek int nr = sensor_attr->nr; 5496800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek int index = sensor_attr->index; 55047efe8772f241c4be540355d90e38b79cc1092a4Guenter Roeck unsigned long val; 55147efe8772f241c4be540355d90e38b79cc1092a4Guenter Roeck int err; 55247efe8772f241c4be540355d90e38b79cc1092a4Guenter Roeck 55347efe8772f241c4be540355d90e38b79cc1092a4Guenter Roeck err = kstrtoul(buf, 10, &val); 55447efe8772f241c4be540355d90e38b79cc1092a4Guenter Roeck if (err) 55547efe8772f241c4be540355d90e38b79cc1092a4Guenter Roeck return err; 5566800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek 5576800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek mutex_lock(&data->update_lock); 55847efe8772f241c4be540355d90e38b79cc1092a4Guenter Roeck if (nr == PWM_STOP_TIME) { 55947efe8772f241c4be540355d90e38b79cc1092a4Guenter Roeck val = TIME_TO_REG(val); 5606800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek data->pwm_stop_time[index] = val; 5616800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek w83793_write_value(client, W83793_REG_PWM_STOP_TIME(index), 5626800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek val); 5636800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek } else { 5642a844c148e1f714ebf42cb96e1b172ce394c36c9Guenter Roeck val = clamp_val(val, 0, 0xff) >> 2; 5656800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek data->pwm[index][nr] = 5666800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek w83793_read_value(client, W83793_REG_PWM(index, nr)) & 0xc0; 5676800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek data->pwm[index][nr] |= val; 5686800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek w83793_write_value(client, W83793_REG_PWM(index, nr), 5696800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek data->pwm[index][nr]); 5706800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek } 5716800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek 5726800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek mutex_unlock(&data->update_lock); 5736800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek return count; 5746800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek} 5756800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek 5766800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marekstatic ssize_t 5776800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marekshow_temp(struct device *dev, struct device_attribute *attr, char *buf) 5786800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek{ 5796800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek struct sensor_device_attribute_2 *sensor_attr = 5806800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek to_sensor_dev_attr_2(attr); 5816800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek int nr = sensor_attr->nr; 5826800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek int index = sensor_attr->index; 5836800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek struct w83793_data *data = w83793_update_device(dev); 5846800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek long temp = TEMP_FROM_REG(data->temp[index][nr]); 5856800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek 58647efe8772f241c4be540355d90e38b79cc1092a4Guenter Roeck if (nr == TEMP_READ && index < 4) { /* Only TD1-TD4 have low bits */ 5876800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek int low = ((data->temp_low_bits >> (index * 2)) & 0x03) * 250; 5886800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek temp += temp > 0 ? low : -low; 5896800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek } 5906800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek return sprintf(buf, "%ld\n", temp); 5916800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek} 5926800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek 5936800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marekstatic ssize_t 5946800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marekstore_temp(struct device *dev, struct device_attribute *attr, 5956800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek const char *buf, size_t count) 5966800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek{ 5976800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek struct sensor_device_attribute_2 *sensor_attr = 5986800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek to_sensor_dev_attr_2(attr); 5996800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek int nr = sensor_attr->nr; 6006800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek int index = sensor_attr->index; 6016800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek struct i2c_client *client = to_i2c_client(dev); 6026800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek struct w83793_data *data = i2c_get_clientdata(client); 60347efe8772f241c4be540355d90e38b79cc1092a4Guenter Roeck long tmp; 60447efe8772f241c4be540355d90e38b79cc1092a4Guenter Roeck int err; 60547efe8772f241c4be540355d90e38b79cc1092a4Guenter Roeck 60647efe8772f241c4be540355d90e38b79cc1092a4Guenter Roeck err = kstrtol(buf, 10, &tmp); 60747efe8772f241c4be540355d90e38b79cc1092a4Guenter Roeck if (err) 60847efe8772f241c4be540355d90e38b79cc1092a4Guenter Roeck return err; 6096800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek 6106800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek mutex_lock(&data->update_lock); 6116800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek data->temp[index][nr] = TEMP_TO_REG(tmp, -128, 127); 6126800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek w83793_write_value(client, W83793_REG_TEMP[index][nr], 6136800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek data->temp[index][nr]); 6146800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek mutex_unlock(&data->update_lock); 6156800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek return count; 6166800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek} 6176800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek 6186800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek/* 61947efe8772f241c4be540355d90e38b79cc1092a4Guenter Roeck * TD1-TD4 62047efe8772f241c4be540355d90e38b79cc1092a4Guenter Roeck * each has 4 mode:(2 bits) 62147efe8772f241c4be540355d90e38b79cc1092a4Guenter Roeck * 0: Stop monitor 62247efe8772f241c4be540355d90e38b79cc1092a4Guenter Roeck * 1: Use internal temp sensor(default) 62347efe8772f241c4be540355d90e38b79cc1092a4Guenter Roeck * 2: Reserved 62447efe8772f241c4be540355d90e38b79cc1092a4Guenter Roeck * 3: Use sensor in Intel CPU and get result by PECI 62547efe8772f241c4be540355d90e38b79cc1092a4Guenter Roeck * 62647efe8772f241c4be540355d90e38b79cc1092a4Guenter Roeck * TR1-TR2 62747efe8772f241c4be540355d90e38b79cc1092a4Guenter Roeck * each has 2 mode:(1 bit) 62847efe8772f241c4be540355d90e38b79cc1092a4Guenter Roeck * 0: Disable temp sensor monitor 62947efe8772f241c4be540355d90e38b79cc1092a4Guenter Roeck * 1: To enable temp sensors monitor 63047efe8772f241c4be540355d90e38b79cc1092a4Guenter Roeck */ 6316800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek 632ddca933bd554b4f81f27776f3cb9daa67cf241b1Gong Jun/* 0 disable, 6 PECI */ 633ddca933bd554b4f81f27776f3cb9daa67cf241b1Gong Junstatic u8 TO_TEMP_MODE[] = { 0, 0, 0, 6 }; 6346800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek 6356800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marekstatic ssize_t 6366800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marekshow_temp_mode(struct device *dev, struct device_attribute *attr, char *buf) 6376800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek{ 6386800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek struct w83793_data *data = w83793_update_device(dev); 6396800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek struct sensor_device_attribute_2 *sensor_attr = 6406800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek to_sensor_dev_attr_2(attr); 6416800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek int index = sensor_attr->index; 6426800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek u8 mask = (index < 4) ? 0x03 : 0x01; 6436800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek u8 shift = (index < 4) ? (2 * index) : (index - 4); 6446800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek u8 tmp; 6456800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek index = (index < 4) ? 0 : 1; 6466800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek 6476800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek tmp = (data->temp_mode[index] >> shift) & mask; 6486800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek 6496800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek /* for the internal sensor, found out if diode or thermistor */ 65047efe8772f241c4be540355d90e38b79cc1092a4Guenter Roeck if (tmp == 1) 6516800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek tmp = index == 0 ? 3 : 4; 65247efe8772f241c4be540355d90e38b79cc1092a4Guenter Roeck else 6536800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek tmp = TO_TEMP_MODE[tmp]; 6546800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek 6556800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek return sprintf(buf, "%d\n", tmp); 6566800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek} 6576800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek 6586800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marekstatic ssize_t 6596800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marekstore_temp_mode(struct device *dev, struct device_attribute *attr, 6606800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek const char *buf, size_t count) 6616800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek{ 6626800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek struct i2c_client *client = to_i2c_client(dev); 6636800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek struct w83793_data *data = i2c_get_clientdata(client); 6646800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek struct sensor_device_attribute_2 *sensor_attr = 6656800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek to_sensor_dev_attr_2(attr); 6666800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek int index = sensor_attr->index; 6676800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek u8 mask = (index < 4) ? 0x03 : 0x01; 6686800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek u8 shift = (index < 4) ? (2 * index) : (index - 4); 66947efe8772f241c4be540355d90e38b79cc1092a4Guenter Roeck unsigned long val; 67047efe8772f241c4be540355d90e38b79cc1092a4Guenter Roeck int err; 67147efe8772f241c4be540355d90e38b79cc1092a4Guenter Roeck 67247efe8772f241c4be540355d90e38b79cc1092a4Guenter Roeck err = kstrtoul(buf, 10, &val); 67347efe8772f241c4be540355d90e38b79cc1092a4Guenter Roeck if (err) 67447efe8772f241c4be540355d90e38b79cc1092a4Guenter Roeck return err; 6756800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek 6766800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek /* transform the sysfs interface values into table above */ 677ddca933bd554b4f81f27776f3cb9daa67cf241b1Gong Jun if ((val == 6) && (index < 4)) { 6786800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek val -= 3; 6796800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek } else if ((val == 3 && index < 4) 68046bed4dfe5f95f1fc8f68ead592a7e295bbbe01eGong Jun || (val == 4 && index >= 4)) { 6816800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek /* transform diode or thermistor into internal enable */ 6826800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek val = !!val; 6836800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek } else { 6846800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek return -EINVAL; 6856800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek } 6866800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek 6876800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek index = (index < 4) ? 0 : 1; 6886800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek mutex_lock(&data->update_lock); 6896800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek data->temp_mode[index] = 6906800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek w83793_read_value(client, W83793_REG_TEMP_MODE[index]); 6916800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek data->temp_mode[index] &= ~(mask << shift); 6926800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek data->temp_mode[index] |= val << shift; 6936800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek w83793_write_value(client, W83793_REG_TEMP_MODE[index], 6946800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek data->temp_mode[index]); 6956800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek mutex_unlock(&data->update_lock); 6966800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek 6976800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek return count; 6986800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek} 6996800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek 7006800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek#define SETUP_PWM_DEFAULT 0 7016800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek#define SETUP_PWM_UPTIME 1 /* Unit in 0.1s */ 7026800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek#define SETUP_PWM_DOWNTIME 2 /* Unit in 0.1s */ 7036800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek#define SETUP_TEMP_CRITICAL 3 7046800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marekstatic ssize_t 7056800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marekshow_sf_setup(struct device *dev, struct device_attribute *attr, char *buf) 7066800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek{ 7076800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek struct sensor_device_attribute_2 *sensor_attr = 7086800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek to_sensor_dev_attr_2(attr); 7096800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek int nr = sensor_attr->nr; 7106800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek struct w83793_data *data = w83793_update_device(dev); 7116800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek u32 val = 0; 7126800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek 71347efe8772f241c4be540355d90e38b79cc1092a4Guenter Roeck if (nr == SETUP_PWM_DEFAULT) 7146800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek val = (data->pwm_default & 0x3f) << 2; 71547efe8772f241c4be540355d90e38b79cc1092a4Guenter Roeck else if (nr == SETUP_PWM_UPTIME) 7166800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek val = TIME_FROM_REG(data->pwm_uptime); 71747efe8772f241c4be540355d90e38b79cc1092a4Guenter Roeck else if (nr == SETUP_PWM_DOWNTIME) 7186800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek val = TIME_FROM_REG(data->pwm_downtime); 71947efe8772f241c4be540355d90e38b79cc1092a4Guenter Roeck else if (nr == SETUP_TEMP_CRITICAL) 7206800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek val = TEMP_FROM_REG(data->temp_critical & 0x7f); 7216800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek 7226800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek return sprintf(buf, "%d\n", val); 7236800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek} 7246800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek 7256800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marekstatic ssize_t 7266800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marekstore_sf_setup(struct device *dev, struct device_attribute *attr, 7276800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek const char *buf, size_t count) 7286800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek{ 7296800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek struct sensor_device_attribute_2 *sensor_attr = 7306800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek to_sensor_dev_attr_2(attr); 7316800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek int nr = sensor_attr->nr; 7326800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek struct i2c_client *client = to_i2c_client(dev); 7336800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek struct w83793_data *data = i2c_get_clientdata(client); 73447efe8772f241c4be540355d90e38b79cc1092a4Guenter Roeck long val; 73547efe8772f241c4be540355d90e38b79cc1092a4Guenter Roeck int err; 73647efe8772f241c4be540355d90e38b79cc1092a4Guenter Roeck 73747efe8772f241c4be540355d90e38b79cc1092a4Guenter Roeck err = kstrtol(buf, 10, &val); 73847efe8772f241c4be540355d90e38b79cc1092a4Guenter Roeck if (err) 73947efe8772f241c4be540355d90e38b79cc1092a4Guenter Roeck return err; 7406800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek 7416800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek mutex_lock(&data->update_lock); 74247efe8772f241c4be540355d90e38b79cc1092a4Guenter Roeck if (nr == SETUP_PWM_DEFAULT) { 7436800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek data->pwm_default = 7446800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek w83793_read_value(client, W83793_REG_PWM_DEFAULT) & 0xc0; 7452a844c148e1f714ebf42cb96e1b172ce394c36c9Guenter Roeck data->pwm_default |= clamp_val(val, 0, 0xff) >> 2; 7466800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek w83793_write_value(client, W83793_REG_PWM_DEFAULT, 7476800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek data->pwm_default); 74847efe8772f241c4be540355d90e38b79cc1092a4Guenter Roeck } else if (nr == SETUP_PWM_UPTIME) { 74947efe8772f241c4be540355d90e38b79cc1092a4Guenter Roeck data->pwm_uptime = TIME_TO_REG(val); 7506800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek data->pwm_uptime += data->pwm_uptime == 0 ? 1 : 0; 7516800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek w83793_write_value(client, W83793_REG_PWM_UPTIME, 7526800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek data->pwm_uptime); 75347efe8772f241c4be540355d90e38b79cc1092a4Guenter Roeck } else if (nr == SETUP_PWM_DOWNTIME) { 75447efe8772f241c4be540355d90e38b79cc1092a4Guenter Roeck data->pwm_downtime = TIME_TO_REG(val); 7556800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek data->pwm_downtime += data->pwm_downtime == 0 ? 1 : 0; 7566800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek w83793_write_value(client, W83793_REG_PWM_DOWNTIME, 7576800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek data->pwm_downtime); 7586800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek } else { /* SETUP_TEMP_CRITICAL */ 7596800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek data->temp_critical = 7606800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek w83793_read_value(client, W83793_REG_TEMP_CRITICAL) & 0x80; 76147efe8772f241c4be540355d90e38b79cc1092a4Guenter Roeck data->temp_critical |= TEMP_TO_REG(val, 0, 0x7f); 7626800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek w83793_write_value(client, W83793_REG_TEMP_CRITICAL, 7636800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek data->temp_critical); 7646800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek } 7656800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek 7666800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek mutex_unlock(&data->update_lock); 7676800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek return count; 7686800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek} 7696800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek 7706800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek/* 77147efe8772f241c4be540355d90e38b79cc1092a4Guenter Roeck * Temp SmartFan control 77247efe8772f241c4be540355d90e38b79cc1092a4Guenter Roeck * TEMP_FAN_MAP 77347efe8772f241c4be540355d90e38b79cc1092a4Guenter Roeck * Temp channel control which pwm fan, bitfield, bit 0 indicate pwm1... 77447efe8772f241c4be540355d90e38b79cc1092a4Guenter Roeck * It's possible two or more temp channels control the same fan, w83793 77547efe8772f241c4be540355d90e38b79cc1092a4Guenter Roeck * always prefers to pick the most critical request and applies it to 77647efe8772f241c4be540355d90e38b79cc1092a4Guenter Roeck * the related Fan. 77747efe8772f241c4be540355d90e38b79cc1092a4Guenter Roeck * It's possible one fan is not in any mapping of 6 temp channels, this 77847efe8772f241c4be540355d90e38b79cc1092a4Guenter Roeck * means the fan is manual mode 77947efe8772f241c4be540355d90e38b79cc1092a4Guenter Roeck * 78047efe8772f241c4be540355d90e38b79cc1092a4Guenter Roeck * TEMP_PWM_ENABLE 78147efe8772f241c4be540355d90e38b79cc1092a4Guenter Roeck * Each temp channel has its own SmartFan mode, and temp channel 78247efe8772f241c4be540355d90e38b79cc1092a4Guenter Roeck * control fans that are set by TEMP_FAN_MAP 78347efe8772f241c4be540355d90e38b79cc1092a4Guenter Roeck * 0: SmartFanII mode 78447efe8772f241c4be540355d90e38b79cc1092a4Guenter Roeck * 1: Thermal Cruise Mode 78547efe8772f241c4be540355d90e38b79cc1092a4Guenter Roeck * 78647efe8772f241c4be540355d90e38b79cc1092a4Guenter Roeck * TEMP_CRUISE 78747efe8772f241c4be540355d90e38b79cc1092a4Guenter Roeck * Target temperature in thermal cruise mode, w83793 will try to turn 78847efe8772f241c4be540355d90e38b79cc1092a4Guenter Roeck * fan speed to keep the temperature of target device around this 78947efe8772f241c4be540355d90e38b79cc1092a4Guenter Roeck * temperature. 79047efe8772f241c4be540355d90e38b79cc1092a4Guenter Roeck * 79147efe8772f241c4be540355d90e38b79cc1092a4Guenter Roeck * TEMP_TOLERANCE 79247efe8772f241c4be540355d90e38b79cc1092a4Guenter Roeck * If Temp higher or lower than target with this tolerance, w83793 79347efe8772f241c4be540355d90e38b79cc1092a4Guenter Roeck * will take actions to speed up or slow down the fan to keep the 79447efe8772f241c4be540355d90e38b79cc1092a4Guenter Roeck * temperature within the tolerance range. 79547efe8772f241c4be540355d90e38b79cc1092a4Guenter Roeck */ 7966800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek 7976800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek#define TEMP_FAN_MAP 0 7986800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek#define TEMP_PWM_ENABLE 1 7996800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek#define TEMP_CRUISE 2 8006800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek#define TEMP_TOLERANCE 3 8016800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marekstatic ssize_t 8026800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marekshow_sf_ctrl(struct device *dev, struct device_attribute *attr, char *buf) 8036800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek{ 8046800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek struct sensor_device_attribute_2 *sensor_attr = 8056800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek to_sensor_dev_attr_2(attr); 8066800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek int nr = sensor_attr->nr; 8076800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek int index = sensor_attr->index; 8086800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek struct w83793_data *data = w83793_update_device(dev); 8096800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek u32 val; 8106800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek 81147efe8772f241c4be540355d90e38b79cc1092a4Guenter Roeck if (nr == TEMP_FAN_MAP) { 8126800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek val = data->temp_fan_map[index]; 81347efe8772f241c4be540355d90e38b79cc1092a4Guenter Roeck } else if (nr == TEMP_PWM_ENABLE) { 81484fb029faa05e1de229a68829cca5dcf85c79894LABBE Corentin /* +2 to transform into 2 and 3 to conform with sysfs intf */ 8156800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek val = ((data->pwm_enable >> index) & 0x01) + 2; 81647efe8772f241c4be540355d90e38b79cc1092a4Guenter Roeck } else if (nr == TEMP_CRUISE) { 8176800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek val = TEMP_FROM_REG(data->temp_cruise[index] & 0x7f); 8186800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek } else { /* TEMP_TOLERANCE */ 8196800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek val = data->tolerance[index >> 1] >> ((index & 0x01) ? 4 : 0); 8206800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek val = TEMP_FROM_REG(val & 0x0f); 8216800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek } 8226800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek return sprintf(buf, "%d\n", val); 8236800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek} 8246800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek 8256800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marekstatic ssize_t 8266800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marekstore_sf_ctrl(struct device *dev, struct device_attribute *attr, 8276800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek const char *buf, size_t count) 8286800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek{ 8296800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek struct sensor_device_attribute_2 *sensor_attr = 8306800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek to_sensor_dev_attr_2(attr); 8316800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek int nr = sensor_attr->nr; 8326800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek int index = sensor_attr->index; 8336800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek struct i2c_client *client = to_i2c_client(dev); 8346800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek struct w83793_data *data = i2c_get_clientdata(client); 83547efe8772f241c4be540355d90e38b79cc1092a4Guenter Roeck long val; 83647efe8772f241c4be540355d90e38b79cc1092a4Guenter Roeck int err; 83747efe8772f241c4be540355d90e38b79cc1092a4Guenter Roeck 83847efe8772f241c4be540355d90e38b79cc1092a4Guenter Roeck err = kstrtol(buf, 10, &val); 83947efe8772f241c4be540355d90e38b79cc1092a4Guenter Roeck if (err) 84047efe8772f241c4be540355d90e38b79cc1092a4Guenter Roeck return err; 8416800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek 8426800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek mutex_lock(&data->update_lock); 84347efe8772f241c4be540355d90e38b79cc1092a4Guenter Roeck if (nr == TEMP_FAN_MAP) { 8442a844c148e1f714ebf42cb96e1b172ce394c36c9Guenter Roeck val = clamp_val(val, 0, 255); 8456800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek w83793_write_value(client, W83793_REG_TEMP_FAN_MAP(index), val); 8466800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek data->temp_fan_map[index] = val; 84747efe8772f241c4be540355d90e38b79cc1092a4Guenter Roeck } else if (nr == TEMP_PWM_ENABLE) { 84847efe8772f241c4be540355d90e38b79cc1092a4Guenter Roeck if (val == 2 || val == 3) { 8496800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek data->pwm_enable = 8506800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek w83793_read_value(client, W83793_REG_PWM_ENABLE); 8516800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek if (val - 2) 8526800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek data->pwm_enable |= 1 << index; 8536800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek else 8546800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek data->pwm_enable &= ~(1 << index); 8556800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek w83793_write_value(client, W83793_REG_PWM_ENABLE, 8566800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek data->pwm_enable); 8576800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek } else { 8586800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek mutex_unlock(&data->update_lock); 8596800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek return -EINVAL; 8606800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek } 86147efe8772f241c4be540355d90e38b79cc1092a4Guenter Roeck } else if (nr == TEMP_CRUISE) { 8626800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek data->temp_cruise[index] = 8636800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek w83793_read_value(client, W83793_REG_TEMP_CRUISE(index)); 8646800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek data->temp_cruise[index] &= 0x80; 86547efe8772f241c4be540355d90e38b79cc1092a4Guenter Roeck data->temp_cruise[index] |= TEMP_TO_REG(val, 0, 0x7f); 8666800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek 8676800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek w83793_write_value(client, W83793_REG_TEMP_CRUISE(index), 8686800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek data->temp_cruise[index]); 8696800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek } else { /* TEMP_TOLERANCE */ 8706800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek int i = index >> 1; 8716800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek u8 shift = (index & 0x01) ? 4 : 0; 8726800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek data->tolerance[i] = 8736800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek w83793_read_value(client, W83793_REG_TEMP_TOL(i)); 8746800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek 8756800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek data->tolerance[i] &= ~(0x0f << shift); 87647efe8772f241c4be540355d90e38b79cc1092a4Guenter Roeck data->tolerance[i] |= TEMP_TO_REG(val, 0, 0x0f) << shift; 8776800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek w83793_write_value(client, W83793_REG_TEMP_TOL(i), 8786800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek data->tolerance[i]); 8796800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek } 8806800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek 8816800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek mutex_unlock(&data->update_lock); 8826800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek return count; 8836800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek} 8846800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek 8856800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marekstatic ssize_t 8866800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marekshow_sf2_pwm(struct device *dev, struct device_attribute *attr, char *buf) 8876800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek{ 8886800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek struct sensor_device_attribute_2 *sensor_attr = 8896800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek to_sensor_dev_attr_2(attr); 8906800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek int nr = sensor_attr->nr; 8916800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek int index = sensor_attr->index; 8926800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek struct w83793_data *data = w83793_update_device(dev); 8936800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek 8946800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek return sprintf(buf, "%d\n", (data->sf2_pwm[index][nr] & 0x3f) << 2); 8956800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek} 8966800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek 8976800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marekstatic ssize_t 8986800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marekstore_sf2_pwm(struct device *dev, struct device_attribute *attr, 8996800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek const char *buf, size_t count) 9006800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek{ 9016800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek struct i2c_client *client = to_i2c_client(dev); 9026800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek struct w83793_data *data = i2c_get_clientdata(client); 9036800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek struct sensor_device_attribute_2 *sensor_attr = 9046800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek to_sensor_dev_attr_2(attr); 9056800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek int nr = sensor_attr->nr; 9066800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek int index = sensor_attr->index; 90747efe8772f241c4be540355d90e38b79cc1092a4Guenter Roeck unsigned long val; 90847efe8772f241c4be540355d90e38b79cc1092a4Guenter Roeck int err; 90947efe8772f241c4be540355d90e38b79cc1092a4Guenter Roeck 91047efe8772f241c4be540355d90e38b79cc1092a4Guenter Roeck err = kstrtoul(buf, 10, &val); 91147efe8772f241c4be540355d90e38b79cc1092a4Guenter Roeck if (err) 91247efe8772f241c4be540355d90e38b79cc1092a4Guenter Roeck return err; 9132a844c148e1f714ebf42cb96e1b172ce394c36c9Guenter Roeck val = clamp_val(val, 0, 0xff) >> 2; 9146800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek 9156800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek mutex_lock(&data->update_lock); 9166800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek data->sf2_pwm[index][nr] = 9176800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek w83793_read_value(client, W83793_REG_SF2_PWM(index, nr)) & 0xc0; 9186800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek data->sf2_pwm[index][nr] |= val; 9196800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek w83793_write_value(client, W83793_REG_SF2_PWM(index, nr), 9206800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek data->sf2_pwm[index][nr]); 9216800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek mutex_unlock(&data->update_lock); 9226800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek return count; 9236800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek} 9246800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek 9256800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marekstatic ssize_t 9266800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marekshow_sf2_temp(struct device *dev, struct device_attribute *attr, char *buf) 9276800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek{ 9286800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek struct sensor_device_attribute_2 *sensor_attr = 9296800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek to_sensor_dev_attr_2(attr); 9306800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek int nr = sensor_attr->nr; 9316800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek int index = sensor_attr->index; 9326800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek struct w83793_data *data = w83793_update_device(dev); 9336800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek 9346800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek return sprintf(buf, "%ld\n", 9356800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek TEMP_FROM_REG(data->sf2_temp[index][nr] & 0x7f)); 9366800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek} 9376800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek 9386800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marekstatic ssize_t 9396800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marekstore_sf2_temp(struct device *dev, struct device_attribute *attr, 9406800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek const char *buf, size_t count) 9416800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek{ 9426800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek struct i2c_client *client = to_i2c_client(dev); 9436800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek struct w83793_data *data = i2c_get_clientdata(client); 9446800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek struct sensor_device_attribute_2 *sensor_attr = 9456800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek to_sensor_dev_attr_2(attr); 9466800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek int nr = sensor_attr->nr; 9476800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek int index = sensor_attr->index; 94847efe8772f241c4be540355d90e38b79cc1092a4Guenter Roeck long val; 94947efe8772f241c4be540355d90e38b79cc1092a4Guenter Roeck int err; 95047efe8772f241c4be540355d90e38b79cc1092a4Guenter Roeck 95147efe8772f241c4be540355d90e38b79cc1092a4Guenter Roeck err = kstrtol(buf, 10, &val); 95247efe8772f241c4be540355d90e38b79cc1092a4Guenter Roeck if (err) 95347efe8772f241c4be540355d90e38b79cc1092a4Guenter Roeck return err; 95447efe8772f241c4be540355d90e38b79cc1092a4Guenter Roeck val = TEMP_TO_REG(val, 0, 0x7f); 9556800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek 9566800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek mutex_lock(&data->update_lock); 9576800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek data->sf2_temp[index][nr] = 9586800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek w83793_read_value(client, W83793_REG_SF2_TEMP(index, nr)) & 0x80; 9596800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek data->sf2_temp[index][nr] |= val; 9606800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek w83793_write_value(client, W83793_REG_SF2_TEMP(index, nr), 9616800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek data->sf2_temp[index][nr]); 9626800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek mutex_unlock(&data->update_lock); 9636800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek return count; 9646800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek} 9656800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek 9666800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek/* only Vcore A/B and Vtt have additional 2 bits precision */ 9676800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marekstatic ssize_t 9686800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marekshow_in(struct device *dev, struct device_attribute *attr, char *buf) 9696800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek{ 9706800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek struct sensor_device_attribute_2 *sensor_attr = 9716800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek to_sensor_dev_attr_2(attr); 9726800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek int nr = sensor_attr->nr; 9736800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek int index = sensor_attr->index; 9746800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek struct w83793_data *data = w83793_update_device(dev); 9756800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek u16 val = data->in[index][nr]; 9766800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek 9776800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek if (index < 3) { 9786800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek val <<= 2; 9796800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek val += (data->in_low_bits[nr] >> (index * 2)) & 0x3; 9806800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek } 981ddca933bd554b4f81f27776f3cb9daa67cf241b1Gong Jun /* voltage inputs 5VDD and 5VSB needs 150mV offset */ 982ddca933bd554b4f81f27776f3cb9daa67cf241b1Gong Jun val = val * scale_in[index] + scale_in_add[index]; 983ddca933bd554b4f81f27776f3cb9daa67cf241b1Gong Jun return sprintf(buf, "%d\n", val); 9846800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek} 9856800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek 9866800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marekstatic ssize_t 9876800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marekstore_in(struct device *dev, struct device_attribute *attr, 9886800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek const char *buf, size_t count) 9896800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek{ 9906800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek struct sensor_device_attribute_2 *sensor_attr = 9916800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek to_sensor_dev_attr_2(attr); 9926800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek int nr = sensor_attr->nr; 9936800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek int index = sensor_attr->index; 9946800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek struct i2c_client *client = to_i2c_client(dev); 9956800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek struct w83793_data *data = i2c_get_clientdata(client); 99647efe8772f241c4be540355d90e38b79cc1092a4Guenter Roeck unsigned long val; 99747efe8772f241c4be540355d90e38b79cc1092a4Guenter Roeck int err; 99847efe8772f241c4be540355d90e38b79cc1092a4Guenter Roeck 99947efe8772f241c4be540355d90e38b79cc1092a4Guenter Roeck err = kstrtoul(buf, 10, &val); 100047efe8772f241c4be540355d90e38b79cc1092a4Guenter Roeck if (err) 100147efe8772f241c4be540355d90e38b79cc1092a4Guenter Roeck return err; 100247efe8772f241c4be540355d90e38b79cc1092a4Guenter Roeck val = (val + scale_in[index] / 2) / scale_in[index]; 10036800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek 10046800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek mutex_lock(&data->update_lock); 10056800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek if (index > 2) { 1006ddca933bd554b4f81f27776f3cb9daa67cf241b1Gong Jun /* fix the limit values of 5VDD and 5VSB to ALARM mechanism */ 100747efe8772f241c4be540355d90e38b79cc1092a4Guenter Roeck if (nr == 1 || nr == 2) 1008ddca933bd554b4f81f27776f3cb9daa67cf241b1Gong Jun val -= scale_in_add[index] / scale_in[index]; 10092a844c148e1f714ebf42cb96e1b172ce394c36c9Guenter Roeck val = clamp_val(val, 0, 255); 10106800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek } else { 10112a844c148e1f714ebf42cb96e1b172ce394c36c9Guenter Roeck val = clamp_val(val, 0, 0x3FF); 10126800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek data->in_low_bits[nr] = 10136800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek w83793_read_value(client, W83793_REG_IN_LOW_BITS[nr]); 10146800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek data->in_low_bits[nr] &= ~(0x03 << (2 * index)); 10156800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek data->in_low_bits[nr] |= (val & 0x03) << (2 * index); 10166800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek w83793_write_value(client, W83793_REG_IN_LOW_BITS[nr], 10176800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek data->in_low_bits[nr]); 10186800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek val >>= 2; 10196800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek } 10206800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek data->in[index][nr] = val; 10216800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek w83793_write_value(client, W83793_REG_IN[index][nr], 10226800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek data->in[index][nr]); 10236800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek mutex_unlock(&data->update_lock); 10246800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek return count; 10256800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek} 10266800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek 10276800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek#define NOT_USED -1 10286800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek 10296800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek#define SENSOR_ATTR_IN(index) \ 10306800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek SENSOR_ATTR_2(in##index##_input, S_IRUGO, show_in, NULL, \ 10316800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek IN_READ, index), \ 10326800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek SENSOR_ATTR_2(in##index##_max, S_IRUGO | S_IWUSR, show_in, \ 10336800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek store_in, IN_MAX, index), \ 10346800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek SENSOR_ATTR_2(in##index##_min, S_IRUGO | S_IWUSR, show_in, \ 10356800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek store_in, IN_LOW, index), \ 10366800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek SENSOR_ATTR_2(in##index##_alarm, S_IRUGO, show_alarm_beep, \ 10376800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek NULL, ALARM_STATUS, index + ((index > 2) ? 1 : 0)), \ 10386800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek SENSOR_ATTR_2(in##index##_beep, S_IWUSR | S_IRUGO, \ 10396800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek show_alarm_beep, store_beep, BEEP_ENABLE, \ 10406800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek index + ((index > 2) ? 1 : 0)) 10416800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek 10426800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek#define SENSOR_ATTR_FAN(index) \ 10436800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek SENSOR_ATTR_2(fan##index##_alarm, S_IRUGO, show_alarm_beep, \ 10446800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek NULL, ALARM_STATUS, index + 17), \ 10456800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek SENSOR_ATTR_2(fan##index##_beep, S_IWUSR | S_IRUGO, \ 10466800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek show_alarm_beep, store_beep, BEEP_ENABLE, index + 17), \ 10476800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek SENSOR_ATTR_2(fan##index##_input, S_IRUGO, show_fan, \ 10486800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek NULL, FAN_INPUT, index - 1), \ 10496800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek SENSOR_ATTR_2(fan##index##_min, S_IWUSR | S_IRUGO, \ 10506800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek show_fan, store_fan_min, FAN_MIN, index - 1) 10516800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek 10526800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek#define SENSOR_ATTR_PWM(index) \ 10536800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek SENSOR_ATTR_2(pwm##index, S_IWUSR | S_IRUGO, show_pwm, \ 10546800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek store_pwm, PWM_DUTY, index - 1), \ 10556800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek SENSOR_ATTR_2(pwm##index##_nonstop, S_IWUSR | S_IRUGO, \ 10566800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek show_pwm, store_pwm, PWM_NONSTOP, index - 1), \ 10576800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek SENSOR_ATTR_2(pwm##index##_start, S_IWUSR | S_IRUGO, \ 10586800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek show_pwm, store_pwm, PWM_START, index - 1), \ 10596800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek SENSOR_ATTR_2(pwm##index##_stop_time, S_IWUSR | S_IRUGO, \ 10606800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek show_pwm, store_pwm, PWM_STOP_TIME, index - 1) 10616800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek 10626800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek#define SENSOR_ATTR_TEMP(index) \ 10636800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek SENSOR_ATTR_2(temp##index##_type, S_IRUGO | S_IWUSR, \ 10646800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek show_temp_mode, store_temp_mode, NOT_USED, index - 1), \ 10656800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek SENSOR_ATTR_2(temp##index##_input, S_IRUGO, show_temp, \ 10666800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek NULL, TEMP_READ, index - 1), \ 10676800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek SENSOR_ATTR_2(temp##index##_max, S_IRUGO | S_IWUSR, show_temp, \ 10686800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek store_temp, TEMP_CRIT, index - 1), \ 10696800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek SENSOR_ATTR_2(temp##index##_max_hyst, S_IRUGO | S_IWUSR, \ 10706800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek show_temp, store_temp, TEMP_CRIT_HYST, index - 1), \ 10716800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek SENSOR_ATTR_2(temp##index##_warn, S_IRUGO | S_IWUSR, show_temp, \ 10726800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek store_temp, TEMP_WARN, index - 1), \ 10736800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek SENSOR_ATTR_2(temp##index##_warn_hyst, S_IRUGO | S_IWUSR, \ 10746800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek show_temp, store_temp, TEMP_WARN_HYST, index - 1), \ 10756800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek SENSOR_ATTR_2(temp##index##_alarm, S_IRUGO, \ 10766800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek show_alarm_beep, NULL, ALARM_STATUS, index + 11), \ 10776800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek SENSOR_ATTR_2(temp##index##_beep, S_IWUSR | S_IRUGO, \ 10786800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek show_alarm_beep, store_beep, BEEP_ENABLE, index + 11), \ 10796800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek SENSOR_ATTR_2(temp##index##_auto_channels_pwm, \ 10806800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek S_IRUGO | S_IWUSR, show_sf_ctrl, store_sf_ctrl, \ 10816800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek TEMP_FAN_MAP, index - 1), \ 10826800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek SENSOR_ATTR_2(temp##index##_pwm_enable, S_IWUSR | S_IRUGO, \ 10836800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek show_sf_ctrl, store_sf_ctrl, TEMP_PWM_ENABLE, \ 10846800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek index - 1), \ 10856800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek SENSOR_ATTR_2(thermal_cruise##index, S_IRUGO | S_IWUSR, \ 10866800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek show_sf_ctrl, store_sf_ctrl, TEMP_CRUISE, index - 1), \ 10876800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek SENSOR_ATTR_2(tolerance##index, S_IRUGO | S_IWUSR, show_sf_ctrl,\ 10886800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek store_sf_ctrl, TEMP_TOLERANCE, index - 1), \ 10896800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek SENSOR_ATTR_2(temp##index##_auto_point1_pwm, S_IRUGO | S_IWUSR, \ 10906800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek show_sf2_pwm, store_sf2_pwm, 0, index - 1), \ 10916800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek SENSOR_ATTR_2(temp##index##_auto_point2_pwm, S_IRUGO | S_IWUSR, \ 10926800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek show_sf2_pwm, store_sf2_pwm, 1, index - 1), \ 10936800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek SENSOR_ATTR_2(temp##index##_auto_point3_pwm, S_IRUGO | S_IWUSR, \ 10946800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek show_sf2_pwm, store_sf2_pwm, 2, index - 1), \ 10956800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek SENSOR_ATTR_2(temp##index##_auto_point4_pwm, S_IRUGO | S_IWUSR, \ 10966800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek show_sf2_pwm, store_sf2_pwm, 3, index - 1), \ 10976800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek SENSOR_ATTR_2(temp##index##_auto_point5_pwm, S_IRUGO | S_IWUSR, \ 10986800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek show_sf2_pwm, store_sf2_pwm, 4, index - 1), \ 10996800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek SENSOR_ATTR_2(temp##index##_auto_point6_pwm, S_IRUGO | S_IWUSR, \ 11006800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek show_sf2_pwm, store_sf2_pwm, 5, index - 1), \ 11016800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek SENSOR_ATTR_2(temp##index##_auto_point7_pwm, S_IRUGO | S_IWUSR, \ 11026800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek show_sf2_pwm, store_sf2_pwm, 6, index - 1), \ 11036800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek SENSOR_ATTR_2(temp##index##_auto_point1_temp, S_IRUGO | S_IWUSR,\ 11046800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek show_sf2_temp, store_sf2_temp, 0, index - 1), \ 11056800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek SENSOR_ATTR_2(temp##index##_auto_point2_temp, S_IRUGO | S_IWUSR,\ 11066800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek show_sf2_temp, store_sf2_temp, 1, index - 1), \ 11076800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek SENSOR_ATTR_2(temp##index##_auto_point3_temp, S_IRUGO | S_IWUSR,\ 11086800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek show_sf2_temp, store_sf2_temp, 2, index - 1), \ 11096800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek SENSOR_ATTR_2(temp##index##_auto_point4_temp, S_IRUGO | S_IWUSR,\ 11106800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek show_sf2_temp, store_sf2_temp, 3, index - 1), \ 11116800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek SENSOR_ATTR_2(temp##index##_auto_point5_temp, S_IRUGO | S_IWUSR,\ 11126800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek show_sf2_temp, store_sf2_temp, 4, index - 1), \ 11136800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek SENSOR_ATTR_2(temp##index##_auto_point6_temp, S_IRUGO | S_IWUSR,\ 11146800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek show_sf2_temp, store_sf2_temp, 5, index - 1), \ 11156800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek SENSOR_ATTR_2(temp##index##_auto_point7_temp, S_IRUGO | S_IWUSR,\ 11166800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek show_sf2_temp, store_sf2_temp, 6, index - 1) 11176800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek 11186800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marekstatic struct sensor_device_attribute_2 w83793_sensor_attr_2[] = { 11196800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek SENSOR_ATTR_IN(0), 11206800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek SENSOR_ATTR_IN(1), 11216800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek SENSOR_ATTR_IN(2), 11226800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek SENSOR_ATTR_IN(3), 11236800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek SENSOR_ATTR_IN(4), 11246800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek SENSOR_ATTR_IN(5), 11256800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek SENSOR_ATTR_IN(6), 11266800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek SENSOR_ATTR_IN(7), 11276800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek SENSOR_ATTR_IN(8), 11286800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek SENSOR_ATTR_IN(9), 11296800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek SENSOR_ATTR_FAN(1), 11306800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek SENSOR_ATTR_FAN(2), 11316800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek SENSOR_ATTR_FAN(3), 11326800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek SENSOR_ATTR_FAN(4), 11336800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek SENSOR_ATTR_FAN(5), 11346800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek SENSOR_ATTR_PWM(1), 11356800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek SENSOR_ATTR_PWM(2), 11366800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek SENSOR_ATTR_PWM(3), 11376800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek}; 11386800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek 113946bed4dfe5f95f1fc8f68ead592a7e295bbbe01eGong Junstatic struct sensor_device_attribute_2 w83793_temp[] = { 114046bed4dfe5f95f1fc8f68ead592a7e295bbbe01eGong Jun SENSOR_ATTR_TEMP(1), 114146bed4dfe5f95f1fc8f68ead592a7e295bbbe01eGong Jun SENSOR_ATTR_TEMP(2), 114246bed4dfe5f95f1fc8f68ead592a7e295bbbe01eGong Jun SENSOR_ATTR_TEMP(3), 114346bed4dfe5f95f1fc8f68ead592a7e295bbbe01eGong Jun SENSOR_ATTR_TEMP(4), 114446bed4dfe5f95f1fc8f68ead592a7e295bbbe01eGong Jun SENSOR_ATTR_TEMP(5), 114546bed4dfe5f95f1fc8f68ead592a7e295bbbe01eGong Jun SENSOR_ATTR_TEMP(6), 114646bed4dfe5f95f1fc8f68ead592a7e295bbbe01eGong Jun}; 114746bed4dfe5f95f1fc8f68ead592a7e295bbbe01eGong Jun 11486800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek/* Fan6-Fan12 */ 11496800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marekstatic struct sensor_device_attribute_2 w83793_left_fan[] = { 11506800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek SENSOR_ATTR_FAN(6), 11516800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek SENSOR_ATTR_FAN(7), 11526800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek SENSOR_ATTR_FAN(8), 11536800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek SENSOR_ATTR_FAN(9), 11546800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek SENSOR_ATTR_FAN(10), 11556800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek SENSOR_ATTR_FAN(11), 11566800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek SENSOR_ATTR_FAN(12), 11576800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek}; 11586800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek 11596800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek/* Pwm4-Pwm8 */ 11606800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marekstatic struct sensor_device_attribute_2 w83793_left_pwm[] = { 11616800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek SENSOR_ATTR_PWM(4), 11626800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek SENSOR_ATTR_PWM(5), 11636800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek SENSOR_ATTR_PWM(6), 11646800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek SENSOR_ATTR_PWM(7), 11656800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek SENSOR_ATTR_PWM(8), 11666800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek}; 11676800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek 1168c70a8c345fd770ecb2ff334bdf88b63edaffb77dGong Junstatic struct sensor_device_attribute_2 w83793_vid[] = { 11696800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek SENSOR_ATTR_2(cpu0_vid, S_IRUGO, show_vid, NULL, NOT_USED, 0), 11706800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek SENSOR_ATTR_2(cpu1_vid, S_IRUGO, show_vid, NULL, NOT_USED, 1), 1171c70a8c345fd770ecb2ff334bdf88b63edaffb77dGong Jun}; 117293c75a4ac2d95834e7202965d853d3cd23aadb40Jean Delvarestatic DEVICE_ATTR(vrm, S_IWUSR | S_IRUGO, show_vrm, store_vrm); 1173c70a8c345fd770ecb2ff334bdf88b63edaffb77dGong Jun 1174c70a8c345fd770ecb2ff334bdf88b63edaffb77dGong Junstatic struct sensor_device_attribute_2 sda_single_files[] = { 1175a516dc3e9b19adbcaa9aeda0100ee8ee2938748aJean Delvare SENSOR_ATTR_2(intrusion0_alarm, S_IWUSR | S_IRUGO, show_alarm_beep, 11766800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek store_chassis_clear, ALARM_STATUS, 30), 11776800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek SENSOR_ATTR_2(beep_enable, S_IWUSR | S_IRUGO, show_beep_enable, 11786800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek store_beep_enable, NOT_USED, NOT_USED), 11796800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek SENSOR_ATTR_2(pwm_default, S_IWUSR | S_IRUGO, show_sf_setup, 11806800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek store_sf_setup, SETUP_PWM_DEFAULT, NOT_USED), 11816800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek SENSOR_ATTR_2(pwm_uptime, S_IWUSR | S_IRUGO, show_sf_setup, 11826800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek store_sf_setup, SETUP_PWM_UPTIME, NOT_USED), 11836800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek SENSOR_ATTR_2(pwm_downtime, S_IWUSR | S_IRUGO, show_sf_setup, 11846800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek store_sf_setup, SETUP_PWM_DOWNTIME, NOT_USED), 11856800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek SENSOR_ATTR_2(temp_critical, S_IWUSR | S_IRUGO, show_sf_setup, 11866800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek store_sf_setup, SETUP_TEMP_CRITICAL, NOT_USED), 11876800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek}; 11886800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek 11896800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marekstatic void w83793_init_client(struct i2c_client *client) 11906800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek{ 119147efe8772f241c4be540355d90e38b79cc1092a4Guenter Roeck if (reset) 11926800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek w83793_write_value(client, W83793_REG_CONFIG, 0x80); 11936800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek 11946800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek /* Start monitoring */ 11956800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek w83793_write_value(client, W83793_REG_CONFIG, 11966800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek w83793_read_value(client, W83793_REG_CONFIG) | 0x01); 11975852f9609d21794c45964129b03365883150a6d0Sven Anders} 11985852f9609d21794c45964129b03365883150a6d0Sven Anders 11995852f9609d21794c45964129b03365883150a6d0Sven Anders/* 12005852f9609d21794c45964129b03365883150a6d0Sven Anders * Watchdog routines 12015852f9609d21794c45964129b03365883150a6d0Sven Anders */ 12025852f9609d21794c45964129b03365883150a6d0Sven Anders 12035852f9609d21794c45964129b03365883150a6d0Sven Andersstatic int watchdog_set_timeout(struct w83793_data *data, int timeout) 12045852f9609d21794c45964129b03365883150a6d0Sven Anders{ 120526336c8a36c0a6a28b9ecf6f1bb8c8f5605d6a21Dan Carpenter unsigned int mtimeout; 120626336c8a36c0a6a28b9ecf6f1bb8c8f5605d6a21Dan Carpenter int ret; 12075852f9609d21794c45964129b03365883150a6d0Sven Anders 12085852f9609d21794c45964129b03365883150a6d0Sven Anders mtimeout = DIV_ROUND_UP(timeout, 60); 12095852f9609d21794c45964129b03365883150a6d0Sven Anders 12105852f9609d21794c45964129b03365883150a6d0Sven Anders if (mtimeout > 255) 12115852f9609d21794c45964129b03365883150a6d0Sven Anders return -EINVAL; 12125852f9609d21794c45964129b03365883150a6d0Sven Anders 12135852f9609d21794c45964129b03365883150a6d0Sven Anders mutex_lock(&data->watchdog_lock); 12145852f9609d21794c45964129b03365883150a6d0Sven Anders if (!data->client) { 12155852f9609d21794c45964129b03365883150a6d0Sven Anders ret = -ENODEV; 12165852f9609d21794c45964129b03365883150a6d0Sven Anders goto leave; 12175852f9609d21794c45964129b03365883150a6d0Sven Anders } 12185852f9609d21794c45964129b03365883150a6d0Sven Anders 12195852f9609d21794c45964129b03365883150a6d0Sven Anders data->watchdog_timeout = mtimeout; 12205852f9609d21794c45964129b03365883150a6d0Sven Anders 12215852f9609d21794c45964129b03365883150a6d0Sven Anders /* Set Timeout value (in Minutes) */ 12225852f9609d21794c45964129b03365883150a6d0Sven Anders w83793_write_value(data->client, W83793_REG_WDT_TIMEOUT, 12235852f9609d21794c45964129b03365883150a6d0Sven Anders data->watchdog_timeout); 12245852f9609d21794c45964129b03365883150a6d0Sven Anders 12255852f9609d21794c45964129b03365883150a6d0Sven Anders ret = mtimeout * 60; 12265852f9609d21794c45964129b03365883150a6d0Sven Anders 12275852f9609d21794c45964129b03365883150a6d0Sven Andersleave: 12285852f9609d21794c45964129b03365883150a6d0Sven Anders mutex_unlock(&data->watchdog_lock); 12295852f9609d21794c45964129b03365883150a6d0Sven Anders return ret; 12305852f9609d21794c45964129b03365883150a6d0Sven Anders} 12315852f9609d21794c45964129b03365883150a6d0Sven Anders 12325852f9609d21794c45964129b03365883150a6d0Sven Andersstatic int watchdog_get_timeout(struct w83793_data *data) 12335852f9609d21794c45964129b03365883150a6d0Sven Anders{ 12345852f9609d21794c45964129b03365883150a6d0Sven Anders int timeout; 12355852f9609d21794c45964129b03365883150a6d0Sven Anders 12365852f9609d21794c45964129b03365883150a6d0Sven Anders mutex_lock(&data->watchdog_lock); 12375852f9609d21794c45964129b03365883150a6d0Sven Anders timeout = data->watchdog_timeout * 60; 12385852f9609d21794c45964129b03365883150a6d0Sven Anders mutex_unlock(&data->watchdog_lock); 12395852f9609d21794c45964129b03365883150a6d0Sven Anders 12405852f9609d21794c45964129b03365883150a6d0Sven Anders return timeout; 12415852f9609d21794c45964129b03365883150a6d0Sven Anders} 12425852f9609d21794c45964129b03365883150a6d0Sven Anders 12435852f9609d21794c45964129b03365883150a6d0Sven Andersstatic int watchdog_trigger(struct w83793_data *data) 12445852f9609d21794c45964129b03365883150a6d0Sven Anders{ 12455852f9609d21794c45964129b03365883150a6d0Sven Anders int ret = 0; 12465852f9609d21794c45964129b03365883150a6d0Sven Anders 12475852f9609d21794c45964129b03365883150a6d0Sven Anders mutex_lock(&data->watchdog_lock); 12485852f9609d21794c45964129b03365883150a6d0Sven Anders if (!data->client) { 12495852f9609d21794c45964129b03365883150a6d0Sven Anders ret = -ENODEV; 12505852f9609d21794c45964129b03365883150a6d0Sven Anders goto leave; 12515852f9609d21794c45964129b03365883150a6d0Sven Anders } 12525852f9609d21794c45964129b03365883150a6d0Sven Anders 12535852f9609d21794c45964129b03365883150a6d0Sven Anders /* Set Timeout value (in Minutes) */ 12545852f9609d21794c45964129b03365883150a6d0Sven Anders w83793_write_value(data->client, W83793_REG_WDT_TIMEOUT, 12555852f9609d21794c45964129b03365883150a6d0Sven Anders data->watchdog_timeout); 12565852f9609d21794c45964129b03365883150a6d0Sven Anders 12575852f9609d21794c45964129b03365883150a6d0Sven Andersleave: 12585852f9609d21794c45964129b03365883150a6d0Sven Anders mutex_unlock(&data->watchdog_lock); 12595852f9609d21794c45964129b03365883150a6d0Sven Anders return ret; 12605852f9609d21794c45964129b03365883150a6d0Sven Anders} 12615852f9609d21794c45964129b03365883150a6d0Sven Anders 12625852f9609d21794c45964129b03365883150a6d0Sven Andersstatic int watchdog_enable(struct w83793_data *data) 12635852f9609d21794c45964129b03365883150a6d0Sven Anders{ 12645852f9609d21794c45964129b03365883150a6d0Sven Anders int ret = 0; 12655852f9609d21794c45964129b03365883150a6d0Sven Anders 12665852f9609d21794c45964129b03365883150a6d0Sven Anders mutex_lock(&data->watchdog_lock); 12675852f9609d21794c45964129b03365883150a6d0Sven Anders if (!data->client) { 12685852f9609d21794c45964129b03365883150a6d0Sven Anders ret = -ENODEV; 12695852f9609d21794c45964129b03365883150a6d0Sven Anders goto leave; 12705852f9609d21794c45964129b03365883150a6d0Sven Anders } 12715852f9609d21794c45964129b03365883150a6d0Sven Anders 12725852f9609d21794c45964129b03365883150a6d0Sven Anders /* Set initial timeout */ 12735852f9609d21794c45964129b03365883150a6d0Sven Anders w83793_write_value(data->client, W83793_REG_WDT_TIMEOUT, 12745852f9609d21794c45964129b03365883150a6d0Sven Anders data->watchdog_timeout); 12755852f9609d21794c45964129b03365883150a6d0Sven Anders 12765852f9609d21794c45964129b03365883150a6d0Sven Anders /* Enable Soft Watchdog */ 12775852f9609d21794c45964129b03365883150a6d0Sven Anders w83793_write_value(data->client, W83793_REG_WDT_LOCK, 0x55); 12785852f9609d21794c45964129b03365883150a6d0Sven Anders 12795852f9609d21794c45964129b03365883150a6d0Sven Andersleave: 12805852f9609d21794c45964129b03365883150a6d0Sven Anders mutex_unlock(&data->watchdog_lock); 12815852f9609d21794c45964129b03365883150a6d0Sven Anders return ret; 12825852f9609d21794c45964129b03365883150a6d0Sven Anders} 12835852f9609d21794c45964129b03365883150a6d0Sven Anders 12845852f9609d21794c45964129b03365883150a6d0Sven Andersstatic int watchdog_disable(struct w83793_data *data) 12855852f9609d21794c45964129b03365883150a6d0Sven Anders{ 12865852f9609d21794c45964129b03365883150a6d0Sven Anders int ret = 0; 12875852f9609d21794c45964129b03365883150a6d0Sven Anders 12885852f9609d21794c45964129b03365883150a6d0Sven Anders mutex_lock(&data->watchdog_lock); 12895852f9609d21794c45964129b03365883150a6d0Sven Anders if (!data->client) { 12905852f9609d21794c45964129b03365883150a6d0Sven Anders ret = -ENODEV; 12915852f9609d21794c45964129b03365883150a6d0Sven Anders goto leave; 12925852f9609d21794c45964129b03365883150a6d0Sven Anders } 12935852f9609d21794c45964129b03365883150a6d0Sven Anders 12945852f9609d21794c45964129b03365883150a6d0Sven Anders /* Disable Soft Watchdog */ 12955852f9609d21794c45964129b03365883150a6d0Sven Anders w83793_write_value(data->client, W83793_REG_WDT_LOCK, 0xAA); 12965852f9609d21794c45964129b03365883150a6d0Sven Anders 12975852f9609d21794c45964129b03365883150a6d0Sven Andersleave: 12985852f9609d21794c45964129b03365883150a6d0Sven Anders mutex_unlock(&data->watchdog_lock); 12995852f9609d21794c45964129b03365883150a6d0Sven Anders return ret; 13005852f9609d21794c45964129b03365883150a6d0Sven Anders} 13015852f9609d21794c45964129b03365883150a6d0Sven Anders 13025852f9609d21794c45964129b03365883150a6d0Sven Andersstatic int watchdog_open(struct inode *inode, struct file *filp) 13035852f9609d21794c45964129b03365883150a6d0Sven Anders{ 13045852f9609d21794c45964129b03365883150a6d0Sven Anders struct w83793_data *pos, *data = NULL; 13055852f9609d21794c45964129b03365883150a6d0Sven Anders int watchdog_is_open; 13065852f9609d21794c45964129b03365883150a6d0Sven Anders 130747efe8772f241c4be540355d90e38b79cc1092a4Guenter Roeck /* 130847efe8772f241c4be540355d90e38b79cc1092a4Guenter Roeck * We get called from drivers/char/misc.c with misc_mtx hold, and we 130947efe8772f241c4be540355d90e38b79cc1092a4Guenter Roeck * call misc_register() from w83793_probe() with watchdog_data_mutex 131047efe8772f241c4be540355d90e38b79cc1092a4Guenter Roeck * hold, as misc_register() takes the misc_mtx lock, this is a possible 131147efe8772f241c4be540355d90e38b79cc1092a4Guenter Roeck * deadlock, so we use mutex_trylock here. 131247efe8772f241c4be540355d90e38b79cc1092a4Guenter Roeck */ 13135852f9609d21794c45964129b03365883150a6d0Sven Anders if (!mutex_trylock(&watchdog_data_mutex)) 13145852f9609d21794c45964129b03365883150a6d0Sven Anders return -ERESTARTSYS; 13155852f9609d21794c45964129b03365883150a6d0Sven Anders list_for_each_entry(pos, &watchdog_data_list, list) { 13165852f9609d21794c45964129b03365883150a6d0Sven Anders if (pos->watchdog_miscdev.minor == iminor(inode)) { 13175852f9609d21794c45964129b03365883150a6d0Sven Anders data = pos; 13185852f9609d21794c45964129b03365883150a6d0Sven Anders break; 13195852f9609d21794c45964129b03365883150a6d0Sven Anders } 13205852f9609d21794c45964129b03365883150a6d0Sven Anders } 13215852f9609d21794c45964129b03365883150a6d0Sven Anders 13225852f9609d21794c45964129b03365883150a6d0Sven Anders /* Check, if device is already open */ 13235852f9609d21794c45964129b03365883150a6d0Sven Anders watchdog_is_open = test_and_set_bit(0, &data->watchdog_is_open); 13245852f9609d21794c45964129b03365883150a6d0Sven Anders 132547efe8772f241c4be540355d90e38b79cc1092a4Guenter Roeck /* 132647efe8772f241c4be540355d90e38b79cc1092a4Guenter Roeck * Increase data reference counter (if not already done). 132747efe8772f241c4be540355d90e38b79cc1092a4Guenter Roeck * Note we can never not have found data, so we don't check for this 132847efe8772f241c4be540355d90e38b79cc1092a4Guenter Roeck */ 13295852f9609d21794c45964129b03365883150a6d0Sven Anders if (!watchdog_is_open) 13305852f9609d21794c45964129b03365883150a6d0Sven Anders kref_get(&data->kref); 13315852f9609d21794c45964129b03365883150a6d0Sven Anders 13325852f9609d21794c45964129b03365883150a6d0Sven Anders mutex_unlock(&watchdog_data_mutex); 13335852f9609d21794c45964129b03365883150a6d0Sven Anders 13345852f9609d21794c45964129b03365883150a6d0Sven Anders /* Check, if device is already open and possibly issue error */ 13355852f9609d21794c45964129b03365883150a6d0Sven Anders if (watchdog_is_open) 13365852f9609d21794c45964129b03365883150a6d0Sven Anders return -EBUSY; 13375852f9609d21794c45964129b03365883150a6d0Sven Anders 13385852f9609d21794c45964129b03365883150a6d0Sven Anders /* Enable Soft Watchdog */ 13395852f9609d21794c45964129b03365883150a6d0Sven Anders watchdog_enable(data); 13405852f9609d21794c45964129b03365883150a6d0Sven Anders 13415852f9609d21794c45964129b03365883150a6d0Sven Anders /* Store pointer to data into filp's private data */ 13425852f9609d21794c45964129b03365883150a6d0Sven Anders filp->private_data = data; 13435852f9609d21794c45964129b03365883150a6d0Sven Anders 13445852f9609d21794c45964129b03365883150a6d0Sven Anders return nonseekable_open(inode, filp); 13455852f9609d21794c45964129b03365883150a6d0Sven Anders} 13465852f9609d21794c45964129b03365883150a6d0Sven Anders 13475852f9609d21794c45964129b03365883150a6d0Sven Andersstatic int watchdog_close(struct inode *inode, struct file *filp) 13485852f9609d21794c45964129b03365883150a6d0Sven Anders{ 13495852f9609d21794c45964129b03365883150a6d0Sven Anders struct w83793_data *data = filp->private_data; 13506800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek 13515852f9609d21794c45964129b03365883150a6d0Sven Anders if (data->watchdog_expect_close) { 13525852f9609d21794c45964129b03365883150a6d0Sven Anders watchdog_disable(data); 13535852f9609d21794c45964129b03365883150a6d0Sven Anders data->watchdog_expect_close = 0; 13545852f9609d21794c45964129b03365883150a6d0Sven Anders } else { 13555852f9609d21794c45964129b03365883150a6d0Sven Anders watchdog_trigger(data); 13565852f9609d21794c45964129b03365883150a6d0Sven Anders dev_crit(&data->client->dev, 13575852f9609d21794c45964129b03365883150a6d0Sven Anders "unexpected close, not stopping watchdog!\n"); 13585852f9609d21794c45964129b03365883150a6d0Sven Anders } 13595852f9609d21794c45964129b03365883150a6d0Sven Anders 13605852f9609d21794c45964129b03365883150a6d0Sven Anders clear_bit(0, &data->watchdog_is_open); 13615852f9609d21794c45964129b03365883150a6d0Sven Anders 13625852f9609d21794c45964129b03365883150a6d0Sven Anders /* Decrease data reference counter */ 13635852f9609d21794c45964129b03365883150a6d0Sven Anders mutex_lock(&watchdog_data_mutex); 13645852f9609d21794c45964129b03365883150a6d0Sven Anders kref_put(&data->kref, w83793_release_resources); 13655852f9609d21794c45964129b03365883150a6d0Sven Anders mutex_unlock(&watchdog_data_mutex); 13665852f9609d21794c45964129b03365883150a6d0Sven Anders 13675852f9609d21794c45964129b03365883150a6d0Sven Anders return 0; 13685852f9609d21794c45964129b03365883150a6d0Sven Anders} 13695852f9609d21794c45964129b03365883150a6d0Sven Anders 13705852f9609d21794c45964129b03365883150a6d0Sven Andersstatic ssize_t watchdog_write(struct file *filp, const char __user *buf, 13715852f9609d21794c45964129b03365883150a6d0Sven Anders size_t count, loff_t *offset) 13725852f9609d21794c45964129b03365883150a6d0Sven Anders{ 13733f7cd7ea9383755eef53f92667c520489165667fDan Carpenter ssize_t ret; 13745852f9609d21794c45964129b03365883150a6d0Sven Anders struct w83793_data *data = filp->private_data; 13755852f9609d21794c45964129b03365883150a6d0Sven Anders 13765852f9609d21794c45964129b03365883150a6d0Sven Anders if (count) { 13775852f9609d21794c45964129b03365883150a6d0Sven Anders if (!nowayout) { 13785852f9609d21794c45964129b03365883150a6d0Sven Anders size_t i; 13795852f9609d21794c45964129b03365883150a6d0Sven Anders 13805852f9609d21794c45964129b03365883150a6d0Sven Anders /* Clear it in case it was set with a previous write */ 13815852f9609d21794c45964129b03365883150a6d0Sven Anders data->watchdog_expect_close = 0; 13825852f9609d21794c45964129b03365883150a6d0Sven Anders 13835852f9609d21794c45964129b03365883150a6d0Sven Anders for (i = 0; i != count; i++) { 13845852f9609d21794c45964129b03365883150a6d0Sven Anders char c; 13855852f9609d21794c45964129b03365883150a6d0Sven Anders if (get_user(c, buf + i)) 13865852f9609d21794c45964129b03365883150a6d0Sven Anders return -EFAULT; 13875852f9609d21794c45964129b03365883150a6d0Sven Anders if (c == 'V') 13885852f9609d21794c45964129b03365883150a6d0Sven Anders data->watchdog_expect_close = 1; 13895852f9609d21794c45964129b03365883150a6d0Sven Anders } 13905852f9609d21794c45964129b03365883150a6d0Sven Anders } 13915852f9609d21794c45964129b03365883150a6d0Sven Anders ret = watchdog_trigger(data); 13925852f9609d21794c45964129b03365883150a6d0Sven Anders if (ret < 0) 13935852f9609d21794c45964129b03365883150a6d0Sven Anders return ret; 13945852f9609d21794c45964129b03365883150a6d0Sven Anders } 13955852f9609d21794c45964129b03365883150a6d0Sven Anders return count; 13965852f9609d21794c45964129b03365883150a6d0Sven Anders} 13975852f9609d21794c45964129b03365883150a6d0Sven Anders 139855929332c92e5d34d65a8f784604c92677ea3e15Arnd Bergmannstatic long watchdog_ioctl(struct file *filp, unsigned int cmd, 139955929332c92e5d34d65a8f784604c92677ea3e15Arnd Bergmann unsigned long arg) 14005852f9609d21794c45964129b03365883150a6d0Sven Anders{ 140136c7fe133e29a0b2558edaef18b2401e99765417Jean Delvare struct watchdog_info ident = { 14025852f9609d21794c45964129b03365883150a6d0Sven Anders .options = WDIOF_KEEPALIVEPING | 14035852f9609d21794c45964129b03365883150a6d0Sven Anders WDIOF_SETTIMEOUT | 14045852f9609d21794c45964129b03365883150a6d0Sven Anders WDIOF_CARDRESET, 14055852f9609d21794c45964129b03365883150a6d0Sven Anders .identity = "w83793 watchdog" 14065852f9609d21794c45964129b03365883150a6d0Sven Anders }; 14075852f9609d21794c45964129b03365883150a6d0Sven Anders 14085852f9609d21794c45964129b03365883150a6d0Sven Anders int val, ret = 0; 14095852f9609d21794c45964129b03365883150a6d0Sven Anders struct w83793_data *data = filp->private_data; 14105852f9609d21794c45964129b03365883150a6d0Sven Anders 14115852f9609d21794c45964129b03365883150a6d0Sven Anders switch (cmd) { 14125852f9609d21794c45964129b03365883150a6d0Sven Anders case WDIOC_GETSUPPORT: 14135852f9609d21794c45964129b03365883150a6d0Sven Anders if (!nowayout) 14145852f9609d21794c45964129b03365883150a6d0Sven Anders ident.options |= WDIOF_MAGICCLOSE; 14155852f9609d21794c45964129b03365883150a6d0Sven Anders if (copy_to_user((void __user *)arg, &ident, sizeof(ident))) 14165852f9609d21794c45964129b03365883150a6d0Sven Anders ret = -EFAULT; 14175852f9609d21794c45964129b03365883150a6d0Sven Anders break; 14185852f9609d21794c45964129b03365883150a6d0Sven Anders 14195852f9609d21794c45964129b03365883150a6d0Sven Anders case WDIOC_GETSTATUS: 14205852f9609d21794c45964129b03365883150a6d0Sven Anders val = data->watchdog_caused_reboot ? WDIOF_CARDRESET : 0; 14215852f9609d21794c45964129b03365883150a6d0Sven Anders ret = put_user(val, (int __user *)arg); 14225852f9609d21794c45964129b03365883150a6d0Sven Anders break; 14235852f9609d21794c45964129b03365883150a6d0Sven Anders 14245852f9609d21794c45964129b03365883150a6d0Sven Anders case WDIOC_GETBOOTSTATUS: 14255852f9609d21794c45964129b03365883150a6d0Sven Anders ret = put_user(0, (int __user *)arg); 14265852f9609d21794c45964129b03365883150a6d0Sven Anders break; 14275852f9609d21794c45964129b03365883150a6d0Sven Anders 14285852f9609d21794c45964129b03365883150a6d0Sven Anders case WDIOC_KEEPALIVE: 14295852f9609d21794c45964129b03365883150a6d0Sven Anders ret = watchdog_trigger(data); 14305852f9609d21794c45964129b03365883150a6d0Sven Anders break; 14315852f9609d21794c45964129b03365883150a6d0Sven Anders 14325852f9609d21794c45964129b03365883150a6d0Sven Anders case WDIOC_GETTIMEOUT: 14335852f9609d21794c45964129b03365883150a6d0Sven Anders val = watchdog_get_timeout(data); 14345852f9609d21794c45964129b03365883150a6d0Sven Anders ret = put_user(val, (int __user *)arg); 14355852f9609d21794c45964129b03365883150a6d0Sven Anders break; 14365852f9609d21794c45964129b03365883150a6d0Sven Anders 14375852f9609d21794c45964129b03365883150a6d0Sven Anders case WDIOC_SETTIMEOUT: 14385852f9609d21794c45964129b03365883150a6d0Sven Anders if (get_user(val, (int __user *)arg)) { 14395852f9609d21794c45964129b03365883150a6d0Sven Anders ret = -EFAULT; 14405852f9609d21794c45964129b03365883150a6d0Sven Anders break; 14415852f9609d21794c45964129b03365883150a6d0Sven Anders } 14425852f9609d21794c45964129b03365883150a6d0Sven Anders ret = watchdog_set_timeout(data, val); 14435852f9609d21794c45964129b03365883150a6d0Sven Anders if (ret > 0) 14445852f9609d21794c45964129b03365883150a6d0Sven Anders ret = put_user(ret, (int __user *)arg); 14455852f9609d21794c45964129b03365883150a6d0Sven Anders break; 14465852f9609d21794c45964129b03365883150a6d0Sven Anders 14475852f9609d21794c45964129b03365883150a6d0Sven Anders case WDIOC_SETOPTIONS: 14485852f9609d21794c45964129b03365883150a6d0Sven Anders if (get_user(val, (int __user *)arg)) { 14495852f9609d21794c45964129b03365883150a6d0Sven Anders ret = -EFAULT; 14505852f9609d21794c45964129b03365883150a6d0Sven Anders break; 14515852f9609d21794c45964129b03365883150a6d0Sven Anders } 14525852f9609d21794c45964129b03365883150a6d0Sven Anders 14535852f9609d21794c45964129b03365883150a6d0Sven Anders if (val & WDIOS_DISABLECARD) 14545852f9609d21794c45964129b03365883150a6d0Sven Anders ret = watchdog_disable(data); 14555852f9609d21794c45964129b03365883150a6d0Sven Anders else if (val & WDIOS_ENABLECARD) 14565852f9609d21794c45964129b03365883150a6d0Sven Anders ret = watchdog_enable(data); 14575852f9609d21794c45964129b03365883150a6d0Sven Anders else 14585852f9609d21794c45964129b03365883150a6d0Sven Anders ret = -EINVAL; 14595852f9609d21794c45964129b03365883150a6d0Sven Anders 14605852f9609d21794c45964129b03365883150a6d0Sven Anders break; 14615852f9609d21794c45964129b03365883150a6d0Sven Anders default: 14625852f9609d21794c45964129b03365883150a6d0Sven Anders ret = -ENOTTY; 14635852f9609d21794c45964129b03365883150a6d0Sven Anders } 14645852f9609d21794c45964129b03365883150a6d0Sven Anders return ret; 14655852f9609d21794c45964129b03365883150a6d0Sven Anders} 14665852f9609d21794c45964129b03365883150a6d0Sven Anders 14675852f9609d21794c45964129b03365883150a6d0Sven Andersstatic const struct file_operations watchdog_fops = { 14685852f9609d21794c45964129b03365883150a6d0Sven Anders .owner = THIS_MODULE, 14695852f9609d21794c45964129b03365883150a6d0Sven Anders .llseek = no_llseek, 14705852f9609d21794c45964129b03365883150a6d0Sven Anders .open = watchdog_open, 14715852f9609d21794c45964129b03365883150a6d0Sven Anders .release = watchdog_close, 14725852f9609d21794c45964129b03365883150a6d0Sven Anders .write = watchdog_write, 147355929332c92e5d34d65a8f784604c92677ea3e15Arnd Bergmann .unlocked_ioctl = watchdog_ioctl, 14745852f9609d21794c45964129b03365883150a6d0Sven Anders}; 14755852f9609d21794c45964129b03365883150a6d0Sven Anders 14765852f9609d21794c45964129b03365883150a6d0Sven Anders/* 14775852f9609d21794c45964129b03365883150a6d0Sven Anders * Notifier for system down 14785852f9609d21794c45964129b03365883150a6d0Sven Anders */ 14795852f9609d21794c45964129b03365883150a6d0Sven Anders 14805852f9609d21794c45964129b03365883150a6d0Sven Andersstatic int watchdog_notify_sys(struct notifier_block *this, unsigned long code, 14815852f9609d21794c45964129b03365883150a6d0Sven Anders void *unused) 14825852f9609d21794c45964129b03365883150a6d0Sven Anders{ 14835852f9609d21794c45964129b03365883150a6d0Sven Anders struct w83793_data *data = NULL; 14845852f9609d21794c45964129b03365883150a6d0Sven Anders 14855852f9609d21794c45964129b03365883150a6d0Sven Anders if (code == SYS_DOWN || code == SYS_HALT) { 14865852f9609d21794c45964129b03365883150a6d0Sven Anders 14875852f9609d21794c45964129b03365883150a6d0Sven Anders /* Disable each registered watchdog */ 14885852f9609d21794c45964129b03365883150a6d0Sven Anders mutex_lock(&watchdog_data_mutex); 14895852f9609d21794c45964129b03365883150a6d0Sven Anders list_for_each_entry(data, &watchdog_data_list, list) { 14905852f9609d21794c45964129b03365883150a6d0Sven Anders if (data->watchdog_miscdev.minor) 14915852f9609d21794c45964129b03365883150a6d0Sven Anders watchdog_disable(data); 14925852f9609d21794c45964129b03365883150a6d0Sven Anders } 14935852f9609d21794c45964129b03365883150a6d0Sven Anders mutex_unlock(&watchdog_data_mutex); 14945852f9609d21794c45964129b03365883150a6d0Sven Anders } 14955852f9609d21794c45964129b03365883150a6d0Sven Anders 14965852f9609d21794c45964129b03365883150a6d0Sven Anders return NOTIFY_DONE; 14976800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek} 14986800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek 14995852f9609d21794c45964129b03365883150a6d0Sven Anders/* 15005852f9609d21794c45964129b03365883150a6d0Sven Anders * The WDT needs to learn about soft shutdowns in order to 15015852f9609d21794c45964129b03365883150a6d0Sven Anders * turn the timebomb registers off. 15025852f9609d21794c45964129b03365883150a6d0Sven Anders */ 15035852f9609d21794c45964129b03365883150a6d0Sven Anders 15045852f9609d21794c45964129b03365883150a6d0Sven Andersstatic struct notifier_block watchdog_notifier = { 15055852f9609d21794c45964129b03365883150a6d0Sven Anders .notifier_call = watchdog_notify_sys, 15065852f9609d21794c45964129b03365883150a6d0Sven Anders}; 15075852f9609d21794c45964129b03365883150a6d0Sven Anders 15085852f9609d21794c45964129b03365883150a6d0Sven Anders/* 15095852f9609d21794c45964129b03365883150a6d0Sven Anders * Init / remove routines 15105852f9609d21794c45964129b03365883150a6d0Sven Anders */ 15115852f9609d21794c45964129b03365883150a6d0Sven Anders 1512a7f13a6ec40379fe2116c647ac8e569227ba8d4fJean Delvarestatic int w83793_remove(struct i2c_client *client) 15136800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek{ 15146800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek struct w83793_data *data = i2c_get_clientdata(client); 15156800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek struct device *dev = &client->dev; 15165852f9609d21794c45964129b03365883150a6d0Sven Anders int i, tmp; 15175852f9609d21794c45964129b03365883150a6d0Sven Anders 15185852f9609d21794c45964129b03365883150a6d0Sven Anders /* Unregister the watchdog (if registered) */ 15195852f9609d21794c45964129b03365883150a6d0Sven Anders if (data->watchdog_miscdev.minor) { 15205852f9609d21794c45964129b03365883150a6d0Sven Anders misc_deregister(&data->watchdog_miscdev); 15215852f9609d21794c45964129b03365883150a6d0Sven Anders 15225852f9609d21794c45964129b03365883150a6d0Sven Anders if (data->watchdog_is_open) { 15235852f9609d21794c45964129b03365883150a6d0Sven Anders dev_warn(&client->dev, 15245852f9609d21794c45964129b03365883150a6d0Sven Anders "i2c client detached with watchdog open! " 15255852f9609d21794c45964129b03365883150a6d0Sven Anders "Stopping watchdog.\n"); 15265852f9609d21794c45964129b03365883150a6d0Sven Anders watchdog_disable(data); 15275852f9609d21794c45964129b03365883150a6d0Sven Anders } 15285852f9609d21794c45964129b03365883150a6d0Sven Anders 15295852f9609d21794c45964129b03365883150a6d0Sven Anders mutex_lock(&watchdog_data_mutex); 15305852f9609d21794c45964129b03365883150a6d0Sven Anders list_del(&data->list); 15315852f9609d21794c45964129b03365883150a6d0Sven Anders mutex_unlock(&watchdog_data_mutex); 15325852f9609d21794c45964129b03365883150a6d0Sven Anders 15335852f9609d21794c45964129b03365883150a6d0Sven Anders /* Tell the watchdog code the client is gone */ 15345852f9609d21794c45964129b03365883150a6d0Sven Anders mutex_lock(&data->watchdog_lock); 15355852f9609d21794c45964129b03365883150a6d0Sven Anders data->client = NULL; 15365852f9609d21794c45964129b03365883150a6d0Sven Anders mutex_unlock(&data->watchdog_lock); 15375852f9609d21794c45964129b03365883150a6d0Sven Anders } 15385852f9609d21794c45964129b03365883150a6d0Sven Anders 15395852f9609d21794c45964129b03365883150a6d0Sven Anders /* Reset Configuration Register to Disable Watch Dog Registers */ 15405852f9609d21794c45964129b03365883150a6d0Sven Anders tmp = w83793_read_value(client, W83793_REG_CONFIG); 15415852f9609d21794c45964129b03365883150a6d0Sven Anders w83793_write_value(client, W83793_REG_CONFIG, tmp & ~0x04); 15425852f9609d21794c45964129b03365883150a6d0Sven Anders 15435852f9609d21794c45964129b03365883150a6d0Sven Anders unregister_reboot_notifier(&watchdog_notifier); 15446800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek 1545a7f13a6ec40379fe2116c647ac8e569227ba8d4fJean Delvare hwmon_device_unregister(data->hwmon_dev); 15466800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek 1547a7f13a6ec40379fe2116c647ac8e569227ba8d4fJean Delvare for (i = 0; i < ARRAY_SIZE(w83793_sensor_attr_2); i++) 1548a7f13a6ec40379fe2116c647ac8e569227ba8d4fJean Delvare device_remove_file(dev, 1549a7f13a6ec40379fe2116c647ac8e569227ba8d4fJean Delvare &w83793_sensor_attr_2[i].dev_attr); 15506800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek 1551a7f13a6ec40379fe2116c647ac8e569227ba8d4fJean Delvare for (i = 0; i < ARRAY_SIZE(sda_single_files); i++) 1552a7f13a6ec40379fe2116c647ac8e569227ba8d4fJean Delvare device_remove_file(dev, &sda_single_files[i].dev_attr); 15536800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek 1554a7f13a6ec40379fe2116c647ac8e569227ba8d4fJean Delvare for (i = 0; i < ARRAY_SIZE(w83793_vid); i++) 1555a7f13a6ec40379fe2116c647ac8e569227ba8d4fJean Delvare device_remove_file(dev, &w83793_vid[i].dev_attr); 1556a7f13a6ec40379fe2116c647ac8e569227ba8d4fJean Delvare device_remove_file(dev, &dev_attr_vrm); 1557c70a8c345fd770ecb2ff334bdf88b63edaffb77dGong Jun 1558a7f13a6ec40379fe2116c647ac8e569227ba8d4fJean Delvare for (i = 0; i < ARRAY_SIZE(w83793_left_fan); i++) 1559a7f13a6ec40379fe2116c647ac8e569227ba8d4fJean Delvare device_remove_file(dev, &w83793_left_fan[i].dev_attr); 15606800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek 1561a7f13a6ec40379fe2116c647ac8e569227ba8d4fJean Delvare for (i = 0; i < ARRAY_SIZE(w83793_left_pwm); i++) 1562a7f13a6ec40379fe2116c647ac8e569227ba8d4fJean Delvare device_remove_file(dev, &w83793_left_pwm[i].dev_attr); 156346bed4dfe5f95f1fc8f68ead592a7e295bbbe01eGong Jun 1564a7f13a6ec40379fe2116c647ac8e569227ba8d4fJean Delvare for (i = 0; i < ARRAY_SIZE(w83793_temp); i++) 1565a7f13a6ec40379fe2116c647ac8e569227ba8d4fJean Delvare device_remove_file(dev, &w83793_temp[i].dev_attr); 15666800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek 1567a7f13a6ec40379fe2116c647ac8e569227ba8d4fJean Delvare if (data->lm75[0] != NULL) 1568a7f13a6ec40379fe2116c647ac8e569227ba8d4fJean Delvare i2c_unregister_device(data->lm75[0]); 1569a7f13a6ec40379fe2116c647ac8e569227ba8d4fJean Delvare if (data->lm75[1] != NULL) 1570a7f13a6ec40379fe2116c647ac8e569227ba8d4fJean Delvare i2c_unregister_device(data->lm75[1]); 15716800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek 15725852f9609d21794c45964129b03365883150a6d0Sven Anders /* Decrease data reference counter */ 15735852f9609d21794c45964129b03365883150a6d0Sven Anders mutex_lock(&watchdog_data_mutex); 15745852f9609d21794c45964129b03365883150a6d0Sven Anders kref_put(&data->kref, w83793_release_resources); 15755852f9609d21794c45964129b03365883150a6d0Sven Anders mutex_unlock(&watchdog_data_mutex); 15766800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek 15776800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek return 0; 15786800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek} 15796800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek 15806800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marekstatic int 1581a7f13a6ec40379fe2116c647ac8e569227ba8d4fJean Delvarew83793_detect_subclients(struct i2c_client *client) 15826800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek{ 15836800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek int i, id, err; 1584a7f13a6ec40379fe2116c647ac8e569227ba8d4fJean Delvare int address = client->addr; 15856800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek u8 tmp; 1586a7f13a6ec40379fe2116c647ac8e569227ba8d4fJean Delvare struct i2c_adapter *adapter = client->adapter; 15876800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek struct w83793_data *data = i2c_get_clientdata(client); 15886800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek 15896800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek id = i2c_adapter_id(adapter); 15906800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek if (force_subclients[0] == id && force_subclients[1] == address) { 15916800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek for (i = 2; i <= 3; i++) { 15926800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek if (force_subclients[i] < 0x48 15936800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek || force_subclients[i] > 0x4f) { 15946800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek dev_err(&client->dev, 15956800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek "invalid subclient " 15966800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek "address %d; must be 0x48-0x4f\n", 15976800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek force_subclients[i]); 15986800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek err = -EINVAL; 15996800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek goto ERROR_SC_0; 16006800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek } 16016800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek } 16026800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek w83793_write_value(client, W83793_REG_I2C_SUBADDR, 16036800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek (force_subclients[2] & 0x07) | 16046800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek ((force_subclients[3] & 0x07) << 4)); 16056800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek } 16066800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek 16076800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek tmp = w83793_read_value(client, W83793_REG_I2C_SUBADDR); 160847efe8772f241c4be540355d90e38b79cc1092a4Guenter Roeck if (!(tmp & 0x08)) 1609a7f13a6ec40379fe2116c647ac8e569227ba8d4fJean Delvare data->lm75[0] = i2c_new_dummy(adapter, 0x48 + (tmp & 0x7)); 16106800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek if (!(tmp & 0x80)) { 16116800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek if ((data->lm75[0] != NULL) 16126800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek && ((tmp & 0x7) == ((tmp >> 4) & 0x7))) { 16136800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek dev_err(&client->dev, 16146800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek "duplicate addresses 0x%x, " 16156800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek "use force_subclients\n", data->lm75[0]->addr); 16166800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek err = -ENODEV; 16176800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek goto ERROR_SC_1; 16186800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek } 1619a7f13a6ec40379fe2116c647ac8e569227ba8d4fJean Delvare data->lm75[1] = i2c_new_dummy(adapter, 1620a7f13a6ec40379fe2116c647ac8e569227ba8d4fJean Delvare 0x48 + ((tmp >> 4) & 0x7)); 16216800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek } 16226800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek 16236800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek return 0; 16246800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek 16256800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek /* Undo inits in case of errors */ 16266800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek 16276800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf MarekERROR_SC_1: 1628a7f13a6ec40379fe2116c647ac8e569227ba8d4fJean Delvare if (data->lm75[0] != NULL) 1629a7f13a6ec40379fe2116c647ac8e569227ba8d4fJean Delvare i2c_unregister_device(data->lm75[0]); 16306800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf MarekERROR_SC_0: 16316800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek return err; 16326800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek} 16336800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek 1634a7f13a6ec40379fe2116c647ac8e569227ba8d4fJean Delvare/* Return 0 if detection is successful, -ENODEV otherwise */ 1635310ec79210d754afe51e2e4a983e846b60179abdJean Delvarestatic int w83793_detect(struct i2c_client *client, 1636a7f13a6ec40379fe2116c647ac8e569227ba8d4fJean Delvare struct i2c_board_info *info) 16376800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek{ 163852df6440a29123eed912183fe785bbe174ef14b9Jean Delvare u8 tmp, bank, chip_id; 1639a7f13a6ec40379fe2116c647ac8e569227ba8d4fJean Delvare struct i2c_adapter *adapter = client->adapter; 1640a7f13a6ec40379fe2116c647ac8e569227ba8d4fJean Delvare unsigned short address = client->addr; 16416800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek 164247efe8772f241c4be540355d90e38b79cc1092a4Guenter Roeck if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) 1643a7f13a6ec40379fe2116c647ac8e569227ba8d4fJean Delvare return -ENODEV; 16446800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek 1645a7f13a6ec40379fe2116c647ac8e569227ba8d4fJean Delvare bank = i2c_smbus_read_byte_data(client, W83793_REG_BANKSEL); 16466800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek 164752df6440a29123eed912183fe785bbe174ef14b9Jean Delvare tmp = bank & 0x80 ? 0x5c : 0xa3; 164852df6440a29123eed912183fe785bbe174ef14b9Jean Delvare /* Check Winbond vendor ID */ 164952df6440a29123eed912183fe785bbe174ef14b9Jean Delvare if (tmp != i2c_smbus_read_byte_data(client, W83793_REG_VENDORID)) { 165052df6440a29123eed912183fe785bbe174ef14b9Jean Delvare pr_debug("w83793: Detection failed at check vendor id\n"); 165152df6440a29123eed912183fe785bbe174ef14b9Jean Delvare return -ENODEV; 16526800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek } 16536800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek 165447efe8772f241c4be540355d90e38b79cc1092a4Guenter Roeck /* 165547efe8772f241c4be540355d90e38b79cc1092a4Guenter Roeck * If Winbond chip, address of chip and W83793_REG_I2C_ADDR 165647efe8772f241c4be540355d90e38b79cc1092a4Guenter Roeck * should match 165747efe8772f241c4be540355d90e38b79cc1092a4Guenter Roeck */ 165852df6440a29123eed912183fe785bbe174ef14b9Jean Delvare if ((bank & 0x07) == 0 165952df6440a29123eed912183fe785bbe174ef14b9Jean Delvare && i2c_smbus_read_byte_data(client, W83793_REG_I2C_ADDR) != 166052df6440a29123eed912183fe785bbe174ef14b9Jean Delvare (address << 1)) { 166152df6440a29123eed912183fe785bbe174ef14b9Jean Delvare pr_debug("w83793: Detection failed at check i2c addr\n"); 166252df6440a29123eed912183fe785bbe174ef14b9Jean Delvare return -ENODEV; 16636800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek } 16646800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek 166552df6440a29123eed912183fe785bbe174ef14b9Jean Delvare /* Determine the chip type now */ 166652df6440a29123eed912183fe785bbe174ef14b9Jean Delvare chip_id = i2c_smbus_read_byte_data(client, W83793_REG_CHIPID); 166752df6440a29123eed912183fe785bbe174ef14b9Jean Delvare if (chip_id != 0x7b) 166852df6440a29123eed912183fe785bbe174ef14b9Jean Delvare return -ENODEV; 166952df6440a29123eed912183fe785bbe174ef14b9Jean Delvare 1670a7f13a6ec40379fe2116c647ac8e569227ba8d4fJean Delvare strlcpy(info->type, "w83793", I2C_NAME_SIZE); 1671a7f13a6ec40379fe2116c647ac8e569227ba8d4fJean Delvare 1672a7f13a6ec40379fe2116c647ac8e569227ba8d4fJean Delvare return 0; 1673a7f13a6ec40379fe2116c647ac8e569227ba8d4fJean Delvare} 16746800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek 1675a7f13a6ec40379fe2116c647ac8e569227ba8d4fJean Delvarestatic int w83793_probe(struct i2c_client *client, 1676a7f13a6ec40379fe2116c647ac8e569227ba8d4fJean Delvare const struct i2c_device_id *id) 1677a7f13a6ec40379fe2116c647ac8e569227ba8d4fJean Delvare{ 1678a7f13a6ec40379fe2116c647ac8e569227ba8d4fJean Delvare struct device *dev = &client->dev; 16795852f9609d21794c45964129b03365883150a6d0Sven Anders const int watchdog_minors[] = { WATCHDOG_MINOR, 212, 213, 214, 215 }; 1680a7f13a6ec40379fe2116c647ac8e569227ba8d4fJean Delvare struct w83793_data *data; 1681a7f13a6ec40379fe2116c647ac8e569227ba8d4fJean Delvare int i, tmp, val, err; 1682a7f13a6ec40379fe2116c647ac8e569227ba8d4fJean Delvare int files_fan = ARRAY_SIZE(w83793_left_fan) / 7; 1683a7f13a6ec40379fe2116c647ac8e569227ba8d4fJean Delvare int files_pwm = ARRAY_SIZE(w83793_left_pwm) / 5; 1684a7f13a6ec40379fe2116c647ac8e569227ba8d4fJean Delvare int files_temp = ARRAY_SIZE(w83793_temp) / 6; 1685a7f13a6ec40379fe2116c647ac8e569227ba8d4fJean Delvare 1686a7f13a6ec40379fe2116c647ac8e569227ba8d4fJean Delvare data = kzalloc(sizeof(struct w83793_data), GFP_KERNEL); 1687a7f13a6ec40379fe2116c647ac8e569227ba8d4fJean Delvare if (!data) { 1688a7f13a6ec40379fe2116c647ac8e569227ba8d4fJean Delvare err = -ENOMEM; 1689a7f13a6ec40379fe2116c647ac8e569227ba8d4fJean Delvare goto exit; 1690a7f13a6ec40379fe2116c647ac8e569227ba8d4fJean Delvare } 1691a7f13a6ec40379fe2116c647ac8e569227ba8d4fJean Delvare 1692a7f13a6ec40379fe2116c647ac8e569227ba8d4fJean Delvare i2c_set_clientdata(client, data); 1693a7f13a6ec40379fe2116c647ac8e569227ba8d4fJean Delvare data->bank = i2c_smbus_read_byte_data(client, W83793_REG_BANKSEL); 16946800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek mutex_init(&data->update_lock); 16955852f9609d21794c45964129b03365883150a6d0Sven Anders mutex_init(&data->watchdog_lock); 16965852f9609d21794c45964129b03365883150a6d0Sven Anders INIT_LIST_HEAD(&data->list); 16975852f9609d21794c45964129b03365883150a6d0Sven Anders kref_init(&data->kref); 16985852f9609d21794c45964129b03365883150a6d0Sven Anders 169947efe8772f241c4be540355d90e38b79cc1092a4Guenter Roeck /* 170047efe8772f241c4be540355d90e38b79cc1092a4Guenter Roeck * Store client pointer in our data struct for watchdog usage 170147efe8772f241c4be540355d90e38b79cc1092a4Guenter Roeck * (where the client is found through a data ptr instead of the 170247efe8772f241c4be540355d90e38b79cc1092a4Guenter Roeck * otherway around) 170347efe8772f241c4be540355d90e38b79cc1092a4Guenter Roeck */ 17045852f9609d21794c45964129b03365883150a6d0Sven Anders data->client = client; 17056800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek 1706a7f13a6ec40379fe2116c647ac8e569227ba8d4fJean Delvare err = w83793_detect_subclients(client); 1707a7f13a6ec40379fe2116c647ac8e569227ba8d4fJean Delvare if (err) 17086800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek goto free_mem; 17096800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek 17106800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek /* Initialize the chip */ 17116800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek w83793_init_client(client); 17126800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek 17136800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek /* 171447efe8772f241c4be540355d90e38b79cc1092a4Guenter Roeck * Only fan 1-5 has their own input pins, 171547efe8772f241c4be540355d90e38b79cc1092a4Guenter Roeck * Pwm 1-3 has their own pins 17166800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek */ 17176800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek data->has_fan = 0x1f; 17186800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek data->has_pwm = 0x07; 17196800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek tmp = w83793_read_value(client, W83793_REG_MFC); 17206800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek val = w83793_read_value(client, W83793_REG_FANIN_CTRL); 17216800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek 17226800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek /* check the function of pins 49-56 */ 172393c75a4ac2d95834e7202965d853d3cd23aadb40Jean Delvare if (tmp & 0x80) { 172493c75a4ac2d95834e7202965d853d3cd23aadb40Jean Delvare data->has_vid |= 0x2; /* has VIDB */ 172593c75a4ac2d95834e7202965d853d3cd23aadb40Jean Delvare } else { 17266800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek data->has_pwm |= 0x18; /* pwm 4,5 */ 17276800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek if (val & 0x01) { /* fan 6 */ 17286800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek data->has_fan |= 0x20; 17296800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek data->has_pwm |= 0x20; 17306800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek } 17316800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek if (val & 0x02) { /* fan 7 */ 17326800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek data->has_fan |= 0x40; 17336800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek data->has_pwm |= 0x40; 17346800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek } 17356800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek if (!(tmp & 0x40) && (val & 0x04)) { /* fan 8 */ 17366800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek data->has_fan |= 0x80; 17376800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek data->has_pwm |= 0x80; 17386800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek } 17396800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek } 17406800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek 174193c75a4ac2d95834e7202965d853d3cd23aadb40Jean Delvare /* check the function of pins 37-40 */ 174293c75a4ac2d95834e7202965d853d3cd23aadb40Jean Delvare if (!(tmp & 0x29)) 174393c75a4ac2d95834e7202965d853d3cd23aadb40Jean Delvare data->has_vid |= 0x1; /* has VIDA */ 17446800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek if (0x08 == (tmp & 0x0c)) { 17456800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek if (val & 0x08) /* fan 9 */ 17466800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek data->has_fan |= 0x100; 17476800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek if (val & 0x10) /* fan 10 */ 17486800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek data->has_fan |= 0x200; 17496800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek } 17506800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek if (0x20 == (tmp & 0x30)) { 17516800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek if (val & 0x20) /* fan 11 */ 17526800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek data->has_fan |= 0x400; 17536800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek if (val & 0x40) /* fan 12 */ 17546800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek data->has_fan |= 0x800; 17556800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek } 17566800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek 17576800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek if ((tmp & 0x01) && (val & 0x04)) { /* fan 8, second location */ 17586800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek data->has_fan |= 0x80; 17596800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek data->has_pwm |= 0x80; 17606800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek } 17616800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek 1762c92943152884e3777439ad40a40126f2e51b8ea8Rudolf Marek tmp = w83793_read_value(client, W83793_REG_FANIN_SEL); 1763c92943152884e3777439ad40a40126f2e51b8ea8Rudolf Marek if ((tmp & 0x01) && (val & 0x08)) { /* fan 9, second location */ 1764c92943152884e3777439ad40a40126f2e51b8ea8Rudolf Marek data->has_fan |= 0x100; 1765c92943152884e3777439ad40a40126f2e51b8ea8Rudolf Marek } 1766c92943152884e3777439ad40a40126f2e51b8ea8Rudolf Marek if ((tmp & 0x02) && (val & 0x10)) { /* fan 10, second location */ 1767c92943152884e3777439ad40a40126f2e51b8ea8Rudolf Marek data->has_fan |= 0x200; 1768c92943152884e3777439ad40a40126f2e51b8ea8Rudolf Marek } 1769c92943152884e3777439ad40a40126f2e51b8ea8Rudolf Marek if ((tmp & 0x04) && (val & 0x20)) { /* fan 11, second location */ 1770c92943152884e3777439ad40a40126f2e51b8ea8Rudolf Marek data->has_fan |= 0x400; 1771c92943152884e3777439ad40a40126f2e51b8ea8Rudolf Marek } 1772c92943152884e3777439ad40a40126f2e51b8ea8Rudolf Marek if ((tmp & 0x08) && (val & 0x40)) { /* fan 12, second location */ 1773c92943152884e3777439ad40a40126f2e51b8ea8Rudolf Marek data->has_fan |= 0x800; 1774c92943152884e3777439ad40a40126f2e51b8ea8Rudolf Marek } 1775c92943152884e3777439ad40a40126f2e51b8ea8Rudolf Marek 177646bed4dfe5f95f1fc8f68ead592a7e295bbbe01eGong Jun /* check the temp1-6 mode, ignore former AMDSI selected inputs */ 177747efe8772f241c4be540355d90e38b79cc1092a4Guenter Roeck tmp = w83793_read_value(client, W83793_REG_TEMP_MODE[0]); 177846bed4dfe5f95f1fc8f68ead592a7e295bbbe01eGong Jun if (tmp & 0x01) 177946bed4dfe5f95f1fc8f68ead592a7e295bbbe01eGong Jun data->has_temp |= 0x01; 178046bed4dfe5f95f1fc8f68ead592a7e295bbbe01eGong Jun if (tmp & 0x04) 178146bed4dfe5f95f1fc8f68ead592a7e295bbbe01eGong Jun data->has_temp |= 0x02; 178246bed4dfe5f95f1fc8f68ead592a7e295bbbe01eGong Jun if (tmp & 0x10) 178346bed4dfe5f95f1fc8f68ead592a7e295bbbe01eGong Jun data->has_temp |= 0x04; 178446bed4dfe5f95f1fc8f68ead592a7e295bbbe01eGong Jun if (tmp & 0x40) 178546bed4dfe5f95f1fc8f68ead592a7e295bbbe01eGong Jun data->has_temp |= 0x08; 178646bed4dfe5f95f1fc8f68ead592a7e295bbbe01eGong Jun 178747efe8772f241c4be540355d90e38b79cc1092a4Guenter Roeck tmp = w83793_read_value(client, W83793_REG_TEMP_MODE[1]); 178846bed4dfe5f95f1fc8f68ead592a7e295bbbe01eGong Jun if (tmp & 0x01) 178946bed4dfe5f95f1fc8f68ead592a7e295bbbe01eGong Jun data->has_temp |= 0x10; 179046bed4dfe5f95f1fc8f68ead592a7e295bbbe01eGong Jun if (tmp & 0x02) 179146bed4dfe5f95f1fc8f68ead592a7e295bbbe01eGong Jun data->has_temp |= 0x20; 179246bed4dfe5f95f1fc8f68ead592a7e295bbbe01eGong Jun 17936800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek /* Register sysfs hooks */ 17946800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek for (i = 0; i < ARRAY_SIZE(w83793_sensor_attr_2); i++) { 17956800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek err = device_create_file(dev, 17966800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek &w83793_sensor_attr_2[i].dev_attr); 17976800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek if (err) 17986800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek goto exit_remove; 17996800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek } 18006800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek 1801c70a8c345fd770ecb2ff334bdf88b63edaffb77dGong Jun for (i = 0; i < ARRAY_SIZE(w83793_vid); i++) { 1802c70a8c345fd770ecb2ff334bdf88b63edaffb77dGong Jun if (!(data->has_vid & (1 << i))) 1803c70a8c345fd770ecb2ff334bdf88b63edaffb77dGong Jun continue; 1804c70a8c345fd770ecb2ff334bdf88b63edaffb77dGong Jun err = device_create_file(dev, &w83793_vid[i].dev_attr); 1805c70a8c345fd770ecb2ff334bdf88b63edaffb77dGong Jun if (err) 1806c70a8c345fd770ecb2ff334bdf88b63edaffb77dGong Jun goto exit_remove; 1807c70a8c345fd770ecb2ff334bdf88b63edaffb77dGong Jun } 180893c75a4ac2d95834e7202965d853d3cd23aadb40Jean Delvare if (data->has_vid) { 180993c75a4ac2d95834e7202965d853d3cd23aadb40Jean Delvare data->vrm = vid_which_vrm(); 181093c75a4ac2d95834e7202965d853d3cd23aadb40Jean Delvare err = device_create_file(dev, &dev_attr_vrm); 181193c75a4ac2d95834e7202965d853d3cd23aadb40Jean Delvare if (err) 181293c75a4ac2d95834e7202965d853d3cd23aadb40Jean Delvare goto exit_remove; 181393c75a4ac2d95834e7202965d853d3cd23aadb40Jean Delvare } 1814c70a8c345fd770ecb2ff334bdf88b63edaffb77dGong Jun 18156800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek for (i = 0; i < ARRAY_SIZE(sda_single_files); i++) { 18166800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek err = device_create_file(dev, &sda_single_files[i].dev_attr); 18176800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek if (err) 18186800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek goto exit_remove; 18196800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek 18206800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek } 18216800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek 182246bed4dfe5f95f1fc8f68ead592a7e295bbbe01eGong Jun for (i = 0; i < 6; i++) { 182346bed4dfe5f95f1fc8f68ead592a7e295bbbe01eGong Jun int j; 182446bed4dfe5f95f1fc8f68ead592a7e295bbbe01eGong Jun if (!(data->has_temp & (1 << i))) 182546bed4dfe5f95f1fc8f68ead592a7e295bbbe01eGong Jun continue; 182646bed4dfe5f95f1fc8f68ead592a7e295bbbe01eGong Jun for (j = 0; j < files_temp; j++) { 182746bed4dfe5f95f1fc8f68ead592a7e295bbbe01eGong Jun err = device_create_file(dev, 182846bed4dfe5f95f1fc8f68ead592a7e295bbbe01eGong Jun &w83793_temp[(i) * files_temp 182946bed4dfe5f95f1fc8f68ead592a7e295bbbe01eGong Jun + j].dev_attr); 183046bed4dfe5f95f1fc8f68ead592a7e295bbbe01eGong Jun if (err) 183146bed4dfe5f95f1fc8f68ead592a7e295bbbe01eGong Jun goto exit_remove; 183246bed4dfe5f95f1fc8f68ead592a7e295bbbe01eGong Jun } 183346bed4dfe5f95f1fc8f68ead592a7e295bbbe01eGong Jun } 183446bed4dfe5f95f1fc8f68ead592a7e295bbbe01eGong Jun 18356800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek for (i = 5; i < 12; i++) { 18366800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek int j; 18376800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek if (!(data->has_fan & (1 << i))) 18386800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek continue; 18396800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek for (j = 0; j < files_fan; j++) { 18406800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek err = device_create_file(dev, 18416800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek &w83793_left_fan[(i - 5) * files_fan 18426800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek + j].dev_attr); 18436800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek if (err) 18446800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek goto exit_remove; 18456800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek } 18466800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek } 18476800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek 18486800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek for (i = 3; i < 8; i++) { 18496800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek int j; 18506800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek if (!(data->has_pwm & (1 << i))) 18516800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek continue; 18526800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek for (j = 0; j < files_pwm; j++) { 18536800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek err = device_create_file(dev, 18546800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek &w83793_left_pwm[(i - 3) * files_pwm 18556800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek + j].dev_attr); 18566800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek if (err) 18576800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek goto exit_remove; 18586800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek } 18596800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek } 18606800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek 18611beeffe43311f64df8dd0ab08ff6b1858c58363fTony Jones data->hwmon_dev = hwmon_device_register(dev); 18621beeffe43311f64df8dd0ab08ff6b1858c58363fTony Jones if (IS_ERR(data->hwmon_dev)) { 18631beeffe43311f64df8dd0ab08ff6b1858c58363fTony Jones err = PTR_ERR(data->hwmon_dev); 18646800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek goto exit_remove; 18656800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek } 18666800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek 18675852f9609d21794c45964129b03365883150a6d0Sven Anders /* Watchdog initialization */ 18685852f9609d21794c45964129b03365883150a6d0Sven Anders 18695852f9609d21794c45964129b03365883150a6d0Sven Anders /* Register boot notifier */ 18705852f9609d21794c45964129b03365883150a6d0Sven Anders err = register_reboot_notifier(&watchdog_notifier); 18715852f9609d21794c45964129b03365883150a6d0Sven Anders if (err != 0) { 18725852f9609d21794c45964129b03365883150a6d0Sven Anders dev_err(&client->dev, 18735852f9609d21794c45964129b03365883150a6d0Sven Anders "cannot register reboot notifier (err=%d)\n", err); 18745852f9609d21794c45964129b03365883150a6d0Sven Anders goto exit_devunreg; 18755852f9609d21794c45964129b03365883150a6d0Sven Anders } 18765852f9609d21794c45964129b03365883150a6d0Sven Anders 187747efe8772f241c4be540355d90e38b79cc1092a4Guenter Roeck /* 187847efe8772f241c4be540355d90e38b79cc1092a4Guenter Roeck * Enable Watchdog registers. 187947efe8772f241c4be540355d90e38b79cc1092a4Guenter Roeck * Set Configuration Register to Enable Watch Dog Registers 188047efe8772f241c4be540355d90e38b79cc1092a4Guenter Roeck * (Bit 2) = XXXX, X1XX. 188147efe8772f241c4be540355d90e38b79cc1092a4Guenter Roeck */ 18825852f9609d21794c45964129b03365883150a6d0Sven Anders tmp = w83793_read_value(client, W83793_REG_CONFIG); 18835852f9609d21794c45964129b03365883150a6d0Sven Anders w83793_write_value(client, W83793_REG_CONFIG, tmp | 0x04); 18845852f9609d21794c45964129b03365883150a6d0Sven Anders 18855852f9609d21794c45964129b03365883150a6d0Sven Anders /* Set the default watchdog timeout */ 18865852f9609d21794c45964129b03365883150a6d0Sven Anders data->watchdog_timeout = timeout; 18875852f9609d21794c45964129b03365883150a6d0Sven Anders 18885852f9609d21794c45964129b03365883150a6d0Sven Anders /* Check, if last reboot was caused by watchdog */ 18895852f9609d21794c45964129b03365883150a6d0Sven Anders data->watchdog_caused_reboot = 18905852f9609d21794c45964129b03365883150a6d0Sven Anders w83793_read_value(data->client, W83793_REG_WDT_STATUS) & 0x01; 18915852f9609d21794c45964129b03365883150a6d0Sven Anders 18925852f9609d21794c45964129b03365883150a6d0Sven Anders /* Disable Soft Watchdog during initialiation */ 18935852f9609d21794c45964129b03365883150a6d0Sven Anders watchdog_disable(data); 18945852f9609d21794c45964129b03365883150a6d0Sven Anders 189547efe8772f241c4be540355d90e38b79cc1092a4Guenter Roeck /* 189647efe8772f241c4be540355d90e38b79cc1092a4Guenter Roeck * We take the data_mutex lock early so that watchdog_open() cannot 189747efe8772f241c4be540355d90e38b79cc1092a4Guenter Roeck * run when misc_register() has completed, but we've not yet added 189847efe8772f241c4be540355d90e38b79cc1092a4Guenter Roeck * our data to the watchdog_data_list (and set the default timeout) 189947efe8772f241c4be540355d90e38b79cc1092a4Guenter Roeck */ 19005852f9609d21794c45964129b03365883150a6d0Sven Anders mutex_lock(&watchdog_data_mutex); 19015852f9609d21794c45964129b03365883150a6d0Sven Anders for (i = 0; i < ARRAY_SIZE(watchdog_minors); i++) { 19025852f9609d21794c45964129b03365883150a6d0Sven Anders /* Register our watchdog part */ 19035852f9609d21794c45964129b03365883150a6d0Sven Anders snprintf(data->watchdog_name, sizeof(data->watchdog_name), 19045852f9609d21794c45964129b03365883150a6d0Sven Anders "watchdog%c", (i == 0) ? '\0' : ('0' + i)); 19055852f9609d21794c45964129b03365883150a6d0Sven Anders data->watchdog_miscdev.name = data->watchdog_name; 19065852f9609d21794c45964129b03365883150a6d0Sven Anders data->watchdog_miscdev.fops = &watchdog_fops; 19075852f9609d21794c45964129b03365883150a6d0Sven Anders data->watchdog_miscdev.minor = watchdog_minors[i]; 19085852f9609d21794c45964129b03365883150a6d0Sven Anders 19095852f9609d21794c45964129b03365883150a6d0Sven Anders err = misc_register(&data->watchdog_miscdev); 19105852f9609d21794c45964129b03365883150a6d0Sven Anders if (err == -EBUSY) 19115852f9609d21794c45964129b03365883150a6d0Sven Anders continue; 19125852f9609d21794c45964129b03365883150a6d0Sven Anders if (err) { 19135852f9609d21794c45964129b03365883150a6d0Sven Anders data->watchdog_miscdev.minor = 0; 19145852f9609d21794c45964129b03365883150a6d0Sven Anders dev_err(&client->dev, 19155852f9609d21794c45964129b03365883150a6d0Sven Anders "Registering watchdog chardev: %d\n", err); 19165852f9609d21794c45964129b03365883150a6d0Sven Anders break; 19175852f9609d21794c45964129b03365883150a6d0Sven Anders } 19185852f9609d21794c45964129b03365883150a6d0Sven Anders 19195852f9609d21794c45964129b03365883150a6d0Sven Anders list_add(&data->list, &watchdog_data_list); 19205852f9609d21794c45964129b03365883150a6d0Sven Anders 19215852f9609d21794c45964129b03365883150a6d0Sven Anders dev_info(&client->dev, 19225852f9609d21794c45964129b03365883150a6d0Sven Anders "Registered watchdog chardev major 10, minor: %d\n", 19235852f9609d21794c45964129b03365883150a6d0Sven Anders watchdog_minors[i]); 19245852f9609d21794c45964129b03365883150a6d0Sven Anders break; 19255852f9609d21794c45964129b03365883150a6d0Sven Anders } 19265852f9609d21794c45964129b03365883150a6d0Sven Anders if (i == ARRAY_SIZE(watchdog_minors)) { 19275852f9609d21794c45964129b03365883150a6d0Sven Anders data->watchdog_miscdev.minor = 0; 1928b55f375725ff85aada394da488802b0a3cc99e88Guenter Roeck dev_warn(&client->dev, 1929b55f375725ff85aada394da488802b0a3cc99e88Guenter Roeck "Couldn't register watchdog chardev (due to no free minor)\n"); 19305852f9609d21794c45964129b03365883150a6d0Sven Anders } 19315852f9609d21794c45964129b03365883150a6d0Sven Anders 19325852f9609d21794c45964129b03365883150a6d0Sven Anders mutex_unlock(&watchdog_data_mutex); 19335852f9609d21794c45964129b03365883150a6d0Sven Anders 19346800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek return 0; 19356800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek 19365852f9609d21794c45964129b03365883150a6d0Sven Anders /* Unregister hwmon device */ 19375852f9609d21794c45964129b03365883150a6d0Sven Anders 19385852f9609d21794c45964129b03365883150a6d0Sven Andersexit_devunreg: 19395852f9609d21794c45964129b03365883150a6d0Sven Anders 19405852f9609d21794c45964129b03365883150a6d0Sven Anders hwmon_device_unregister(data->hwmon_dev); 19415852f9609d21794c45964129b03365883150a6d0Sven Anders 19426800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek /* Unregister sysfs hooks */ 19436800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek 19446800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marekexit_remove: 19456800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek for (i = 0; i < ARRAY_SIZE(w83793_sensor_attr_2); i++) 19466800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek device_remove_file(dev, &w83793_sensor_attr_2[i].dev_attr); 19476800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek 19486800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek for (i = 0; i < ARRAY_SIZE(sda_single_files); i++) 19496800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek device_remove_file(dev, &sda_single_files[i].dev_attr); 19506800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek 1951c70a8c345fd770ecb2ff334bdf88b63edaffb77dGong Jun for (i = 0; i < ARRAY_SIZE(w83793_vid); i++) 1952c70a8c345fd770ecb2ff334bdf88b63edaffb77dGong Jun device_remove_file(dev, &w83793_vid[i].dev_attr); 1953c70a8c345fd770ecb2ff334bdf88b63edaffb77dGong Jun 19546800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek for (i = 0; i < ARRAY_SIZE(w83793_left_fan); i++) 19556800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek device_remove_file(dev, &w83793_left_fan[i].dev_attr); 19566800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek 19576800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek for (i = 0; i < ARRAY_SIZE(w83793_left_pwm); i++) 19586800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek device_remove_file(dev, &w83793_left_pwm[i].dev_attr); 19596800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek 196046bed4dfe5f95f1fc8f68ead592a7e295bbbe01eGong Jun for (i = 0; i < ARRAY_SIZE(w83793_temp); i++) 196146bed4dfe5f95f1fc8f68ead592a7e295bbbe01eGong Jun device_remove_file(dev, &w83793_temp[i].dev_attr); 196246bed4dfe5f95f1fc8f68ead592a7e295bbbe01eGong Jun 1963a7f13a6ec40379fe2116c647ac8e569227ba8d4fJean Delvare if (data->lm75[0] != NULL) 1964a7f13a6ec40379fe2116c647ac8e569227ba8d4fJean Delvare i2c_unregister_device(data->lm75[0]); 1965a7f13a6ec40379fe2116c647ac8e569227ba8d4fJean Delvare if (data->lm75[1] != NULL) 1966a7f13a6ec40379fe2116c647ac8e569227ba8d4fJean Delvare i2c_unregister_device(data->lm75[1]); 19676800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marekfree_mem: 19686800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek kfree(data); 19696800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marekexit: 19706800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek return err; 19716800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek} 19726800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek 19736800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marekstatic void w83793_update_nonvolatile(struct device *dev) 19746800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek{ 19756800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek struct i2c_client *client = to_i2c_client(dev); 19766800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek struct w83793_data *data = i2c_get_clientdata(client); 19776800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek int i, j; 19786800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek /* 197947efe8772f241c4be540355d90e38b79cc1092a4Guenter Roeck * They are somewhat "stable" registers, and to update them every time 198047efe8772f241c4be540355d90e38b79cc1092a4Guenter Roeck * takes so much time, it's just not worthy. Update them in a long 198147efe8772f241c4be540355d90e38b79cc1092a4Guenter Roeck * interval to avoid exception. 19826800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek */ 19836800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek if (!(time_after(jiffies, data->last_nonvolatile + HZ * 300) 19846800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek || !data->valid)) 19856800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek return; 19866800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek /* update voltage limits */ 19876800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek for (i = 1; i < 3; i++) { 19886800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek for (j = 0; j < ARRAY_SIZE(data->in); j++) { 19896800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek data->in[j][i] = 19906800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek w83793_read_value(client, W83793_REG_IN[j][i]); 19916800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek } 19926800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek data->in_low_bits[i] = 19936800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek w83793_read_value(client, W83793_REG_IN_LOW_BITS[i]); 19946800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek } 19956800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek 19966800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek for (i = 0; i < ARRAY_SIZE(data->fan_min); i++) { 19976800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek /* Update the Fan measured value and limits */ 199847efe8772f241c4be540355d90e38b79cc1092a4Guenter Roeck if (!(data->has_fan & (1 << i))) 19996800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek continue; 20006800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek data->fan_min[i] = 20016800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek w83793_read_value(client, W83793_REG_FAN_MIN(i)) << 8; 20026800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek data->fan_min[i] |= 20036800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek w83793_read_value(client, W83793_REG_FAN_MIN(i) + 1); 20046800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek } 20056800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek 20066800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek for (i = 0; i < ARRAY_SIZE(data->temp_fan_map); i++) { 200746bed4dfe5f95f1fc8f68ead592a7e295bbbe01eGong Jun if (!(data->has_temp & (1 << i))) 200846bed4dfe5f95f1fc8f68ead592a7e295bbbe01eGong Jun continue; 20096800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek data->temp_fan_map[i] = 20106800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek w83793_read_value(client, W83793_REG_TEMP_FAN_MAP(i)); 20116800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek for (j = 1; j < 5; j++) { 20126800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek data->temp[i][j] = 20136800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek w83793_read_value(client, W83793_REG_TEMP[i][j]); 20146800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek } 20156800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek data->temp_cruise[i] = 20166800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek w83793_read_value(client, W83793_REG_TEMP_CRUISE(i)); 20176800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek for (j = 0; j < 7; j++) { 20186800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek data->sf2_pwm[i][j] = 20196800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek w83793_read_value(client, W83793_REG_SF2_PWM(i, j)); 20206800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek data->sf2_temp[i][j] = 20216800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek w83793_read_value(client, 20226800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek W83793_REG_SF2_TEMP(i, j)); 20236800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek } 20246800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek } 20256800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek 20266800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek for (i = 0; i < ARRAY_SIZE(data->temp_mode); i++) 20276800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek data->temp_mode[i] = 20286800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek w83793_read_value(client, W83793_REG_TEMP_MODE[i]); 20296800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek 20306800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek for (i = 0; i < ARRAY_SIZE(data->tolerance); i++) { 20316800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek data->tolerance[i] = 20326800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek w83793_read_value(client, W83793_REG_TEMP_TOL(i)); 20336800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek } 20346800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek 20356800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek for (i = 0; i < ARRAY_SIZE(data->pwm); i++) { 20366800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek if (!(data->has_pwm & (1 << i))) 20376800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek continue; 20386800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek data->pwm[i][PWM_NONSTOP] = 20396800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek w83793_read_value(client, W83793_REG_PWM(i, PWM_NONSTOP)); 20406800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek data->pwm[i][PWM_START] = 20416800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek w83793_read_value(client, W83793_REG_PWM(i, PWM_START)); 20426800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek data->pwm_stop_time[i] = 20436800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek w83793_read_value(client, W83793_REG_PWM_STOP_TIME(i)); 20446800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek } 20456800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek 20466800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek data->pwm_default = w83793_read_value(client, W83793_REG_PWM_DEFAULT); 20476800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek data->pwm_enable = w83793_read_value(client, W83793_REG_PWM_ENABLE); 20486800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek data->pwm_uptime = w83793_read_value(client, W83793_REG_PWM_UPTIME); 20496800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek data->pwm_downtime = w83793_read_value(client, W83793_REG_PWM_DOWNTIME); 20506800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek data->temp_critical = 20516800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek w83793_read_value(client, W83793_REG_TEMP_CRITICAL); 20526800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek data->beep_enable = w83793_read_value(client, W83793_REG_OVT_BEEP); 20536800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek 205447efe8772f241c4be540355d90e38b79cc1092a4Guenter Roeck for (i = 0; i < ARRAY_SIZE(data->beeps); i++) 20556800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek data->beeps[i] = w83793_read_value(client, W83793_REG_BEEP(i)); 20566800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek 20576800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek data->last_nonvolatile = jiffies; 20586800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek} 20596800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek 20606800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marekstatic struct w83793_data *w83793_update_device(struct device *dev) 20616800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek{ 20626800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek struct i2c_client *client = to_i2c_client(dev); 20636800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek struct w83793_data *data = i2c_get_clientdata(client); 20646800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek int i; 20656800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek 20666800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek mutex_lock(&data->update_lock); 20676800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek 20686800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek if (!(time_after(jiffies, data->last_updated + HZ * 2) 20696800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek || !data->valid)) 20706800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek goto END; 20716800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek 20726800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek /* Update the voltages measured value and limits */ 20736800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek for (i = 0; i < ARRAY_SIZE(data->in); i++) 20746800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek data->in[i][IN_READ] = 20756800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek w83793_read_value(client, W83793_REG_IN[i][IN_READ]); 20766800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek 20776800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek data->in_low_bits[IN_READ] = 20786800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek w83793_read_value(client, W83793_REG_IN_LOW_BITS[IN_READ]); 20796800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek 20806800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek for (i = 0; i < ARRAY_SIZE(data->fan); i++) { 208147efe8772f241c4be540355d90e38b79cc1092a4Guenter Roeck if (!(data->has_fan & (1 << i))) 20826800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek continue; 20836800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek data->fan[i] = 20846800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek w83793_read_value(client, W83793_REG_FAN(i)) << 8; 20856800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek data->fan[i] |= 20866800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek w83793_read_value(client, W83793_REG_FAN(i) + 1); 20876800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek } 20886800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek 208946bed4dfe5f95f1fc8f68ead592a7e295bbbe01eGong Jun for (i = 0; i < ARRAY_SIZE(data->temp); i++) { 209046bed4dfe5f95f1fc8f68ead592a7e295bbbe01eGong Jun if (!(data->has_temp & (1 << i))) 209146bed4dfe5f95f1fc8f68ead592a7e295bbbe01eGong Jun continue; 20926800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek data->temp[i][TEMP_READ] = 20936800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek w83793_read_value(client, W83793_REG_TEMP[i][TEMP_READ]); 209446bed4dfe5f95f1fc8f68ead592a7e295bbbe01eGong Jun } 20956800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek 20966800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek data->temp_low_bits = 20976800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek w83793_read_value(client, W83793_REG_TEMP_LOW_BITS); 20986800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek 20996800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek for (i = 0; i < ARRAY_SIZE(data->pwm); i++) { 21006800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek if (data->has_pwm & (1 << i)) 21016800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek data->pwm[i][PWM_DUTY] = 21026800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek w83793_read_value(client, 21036800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek W83793_REG_PWM(i, PWM_DUTY)); 21046800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek } 21056800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek 21066800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek for (i = 0; i < ARRAY_SIZE(data->alarms); i++) 21076800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek data->alarms[i] = 21086800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek w83793_read_value(client, W83793_REG_ALARM(i)); 2109c70a8c345fd770ecb2ff334bdf88b63edaffb77dGong Jun if (data->has_vid & 0x01) 2110c70a8c345fd770ecb2ff334bdf88b63edaffb77dGong Jun data->vid[0] = w83793_read_value(client, W83793_REG_VID_INA); 2111c70a8c345fd770ecb2ff334bdf88b63edaffb77dGong Jun if (data->has_vid & 0x02) 2112c70a8c345fd770ecb2ff334bdf88b63edaffb77dGong Jun data->vid[1] = w83793_read_value(client, W83793_REG_VID_INB); 21136800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek w83793_update_nonvolatile(dev); 21146800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek data->last_updated = jiffies; 21156800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek data->valid = 1; 21166800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek 21176800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf MarekEND: 21186800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek mutex_unlock(&data->update_lock); 21196800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek return data; 21206800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek} 21216800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek 212247efe8772f241c4be540355d90e38b79cc1092a4Guenter Roeck/* 212347efe8772f241c4be540355d90e38b79cc1092a4Guenter Roeck * Ignore the possibility that somebody change bank outside the driver 212447efe8772f241c4be540355d90e38b79cc1092a4Guenter Roeck * Must be called with data->update_lock held, except during initialization 212547efe8772f241c4be540355d90e38b79cc1092a4Guenter Roeck */ 21266800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marekstatic u8 w83793_read_value(struct i2c_client *client, u16 reg) 21276800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek{ 21286800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek struct w83793_data *data = i2c_get_clientdata(client); 21296800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek u8 res = 0xff; 21306800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek u8 new_bank = reg >> 8; 21316800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek 21326800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek new_bank |= data->bank & 0xfc; 21336800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek if (data->bank != new_bank) { 21346800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek if (i2c_smbus_write_byte_data 21356800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek (client, W83793_REG_BANKSEL, new_bank) >= 0) 21366800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek data->bank = new_bank; 21376800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek else { 21386800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek dev_err(&client->dev, 21396800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek "set bank to %d failed, fall back " 21406800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek "to bank %d, read reg 0x%x error\n", 21416800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek new_bank, data->bank, reg); 21426800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek res = 0x0; /* read 0x0 from the chip */ 21436800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek goto END; 21446800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek } 21456800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek } 21466800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek res = i2c_smbus_read_byte_data(client, reg & 0xff); 21476800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf MarekEND: 21486800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek return res; 21496800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek} 21506800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek 21516800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek/* Must be called with data->update_lock held, except during initialization */ 21526800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marekstatic int w83793_write_value(struct i2c_client *client, u16 reg, u8 value) 21536800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek{ 21546800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek struct w83793_data *data = i2c_get_clientdata(client); 21556800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek int res; 21566800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek u8 new_bank = reg >> 8; 21576800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek 21586800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek new_bank |= data->bank & 0xfc; 21596800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek if (data->bank != new_bank) { 216047efe8772f241c4be540355d90e38b79cc1092a4Guenter Roeck res = i2c_smbus_write_byte_data(client, W83793_REG_BANKSEL, 216147efe8772f241c4be540355d90e38b79cc1092a4Guenter Roeck new_bank); 216247efe8772f241c4be540355d90e38b79cc1092a4Guenter Roeck if (res < 0) { 21636800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek dev_err(&client->dev, 21646800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek "set bank to %d failed, fall back " 21656800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek "to bank %d, write reg 0x%x error\n", 21666800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek new_bank, data->bank, reg); 21676800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek goto END; 21686800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek } 216947efe8772f241c4be540355d90e38b79cc1092a4Guenter Roeck data->bank = new_bank; 21706800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek } 21716800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek 21726800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek res = i2c_smbus_write_byte_data(client, reg & 0xff, value); 21736800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf MarekEND: 21746800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek return res; 21756800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek} 21766800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek 2177f0967eea80ec2a19a4fe1ad27e3ff1b22c79a3c7Axel Linmodule_i2c_driver(w83793_driver); 21786800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf Marek 21795852f9609d21794c45964129b03365883150a6d0Sven AndersMODULE_AUTHOR("Yuan Mu, Sven Anders"); 21806800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf MarekMODULE_DESCRIPTION("w83793 driver"); 21816800c3d027b4458a6fb5ab78064c2e3b7da2f94fRudolf MarekMODULE_LICENSE("GPL"); 2182