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