11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  pc87360.c - Part of lm_sensors, Linux kernel modules
31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *              for hardware monitoring
4f641b588fdfd25e73c73f6e4977cd2daf8a5e363Jean Delvare *  Copyright (C) 2004, 2007 Jean Delvare <khali@linux-fr.org>
51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  Copied from smsc47m1.c:
71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  Copyright (C) 2002 Mark D. Studebaker <mdsxyz123@yahoo.com>
81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  This program is free software; you can redistribute it and/or modify
101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  it under the terms of the GNU General Public License as published by
111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  the Free Software Foundation; either version 2 of the License, or
121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  (at your option) any later version.
131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  This program is distributed in the hope that it will be useful,
151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  but WITHOUT ANY WARRANTY; without even the implied warranty of
161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  GNU General Public License for more details.
181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  You should have received a copy of the GNU General Public License
201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  along with this program; if not, write to the Free Software
211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  Supports the following chips:
241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  Chip        #vin    #fan    #pwm    #temp   devid
261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  PC87360     -       2       2       -       0xE1
271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  PC87363     -       2       2       -       0xE8
281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  PC87364     -       3       3       -       0xE4
291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  PC87365     11      3       3       2       0xE5
301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  PC87366     11      3       3       3-4     0xE9
311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  This driver assumes that no more than one chip is present, and one of
331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  the standard Super-I/O addresses is used (0x2E/0x2F or 0x4E/0x4F).
341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
369e991c6fad4618a9158437f1f650225f9ec485c3Joe Perches#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
379e991c6fad4618a9158437f1f650225f9ec485c3Joe Perches
381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/module.h>
391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/init.h>
401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/slab.h>
411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/jiffies.h>
42f641b588fdfd25e73c73f6e4977cd2daf8a5e363Jean Delvare#include <linux/platform_device.h>
43943b0830cebe4711354945ed3cb44e84152aaca0Mark M. Hoffman#include <linux/hwmon.h>
44f0986bd8f390392948db85dac526fb238752372bJim Cromie#include <linux/hwmon-sysfs.h>
45303760b44a7a142cb9f4c9df4609fb63bbda98dbJean Delvare#include <linux/hwmon-vid.h>
46943b0830cebe4711354945ed3cb44e84152aaca0Mark M. Hoffman#include <linux/err.h>
479a61bf6300533d3b64d7ff29adfec00e596de67dIngo Molnar#include <linux/mutex.h>
48b9acb64a385c5b26fc392e0d58ac7b8e0a2cd812Jean Delvare#include <linux/acpi.h>
496055fae8aceee41471edfd1876e5617d16e028feH Hartley Sweeten#include <linux/io.h>
501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic u8 devid;
52f641b588fdfd25e73c73f6e4977cd2daf8a5e363Jean Delvarestatic struct platform_device *pdev;
532d8672c5a6ba0d3f1d8d3ad61ef67868941364f0Jean Delvarestatic unsigned short extra_isa[3];
541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic u8 confreg[4];
551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int init = 1;
571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_param(init, int, 0);
581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_PARM_DESC(init,
59449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck"Chip initialization level:\n"
60449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck" 0: None\n"
61449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck"*1: Forcibly enable internal voltage and temperature channels, except in9\n"
62449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck" 2: Forcibly enable all voltage and temperature channels, except in9\n"
63449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck" 3: Forcibly enable all voltage and temperature channels, including in9");
641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6567b671bceb4a8340a30929e9642620d99ed5ad76Jean Delvarestatic unsigned short force_id;
6667b671bceb4a8340a30929e9642620d99ed5ad76Jean Delvaremodule_param(force_id, ushort, 0);
6767b671bceb4a8340a30929e9642620d99ed5ad76Jean DelvareMODULE_PARM_DESC(force_id, "Override the detected device ID");
6867b671bceb4a8340a30929e9642620d99ed5ad76Jean Delvare
691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Super-I/O registers and operations
711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DEV	0x07	/* Register: Logical device select */
741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DEVID	0x20	/* Register: Device ID */
751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define ACT	0x30	/* Register: Device activation */
761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define BASE	0x60	/* Register: Base address */
771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define FSCM	0x09	/* Logical device: fans */
791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define VLM	0x0d	/* Logical device: voltages */
801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TMS	0x0e	/* Logical device: temperatures */
812a32ec2500514109754e07721d9d5d431a706a31Jim Cromie#define LDNI_MAX 3
822a32ec2500514109754e07721d9d5d431a706a31Jim Cromiestatic const u8 logdev[LDNI_MAX] = { FSCM, VLM, TMS };
831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define LD_FAN		0
851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define LD_IN		1
861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define LD_TEMP		2
871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline void superio_outb(int sioaddr, int reg, int val)
891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	outb(reg, sioaddr);
91449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck	outb(val, sioaddr + 1);
921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline int superio_inb(int sioaddr, int reg)
951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	outb(reg, sioaddr);
97449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck	return inb(sioaddr + 1);
981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline void superio_exit(int sioaddr)
1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	outb(0x02, sioaddr);
103449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck	outb(0x02, sioaddr + 1);
1041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
1071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Logical devices
1081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
1091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define PC87360_EXTENT		0x10
1111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define PC87365_REG_BANK	0x09
1121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define NO_BANK			0xff
1131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
1151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Fan registers and conversions
1161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
1171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* nr has to be 0 or 1 (PC87360/87363) or 2 (PC87364/87365/87366) */
1191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define PC87360_REG_PRESCALE(nr)	(0x00 + 2 * (nr))
1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define PC87360_REG_PWM(nr)		(0x01 + 2 * (nr))
1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define PC87360_REG_FAN_MIN(nr)		(0x06 + 3 * (nr))
1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define PC87360_REG_FAN(nr)		(0x07 + 3 * (nr))
1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define PC87360_REG_FAN_STATUS(nr)	(0x08 + 3 * (nr))
1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
125449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck#define FAN_FROM_REG(val, div)		((val) == 0 ? 0 : \
126449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck					 480000 / ((val) * (div)))
127449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck#define FAN_TO_REG(val, div)		((val) <= 100 ? 0 : \
128449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck					 480000 / ((val) * (div)))
129449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck#define FAN_DIV_FROM_REG(val)		(1 << (((val) >> 5) & 0x03))
1301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define FAN_STATUS_FROM_REG(val)	((val) & 0x07)
1311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
132449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck#define FAN_CONFIG_MONITOR(val, nr)	(((val) >> (2 + (nr) * 3)) & 1)
133449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck#define FAN_CONFIG_CONTROL(val, nr)	(((val) >> (3 + (nr) * 3)) & 1)
134449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck#define FAN_CONFIG_INVERT(val, nr)	(((val) >> (4 + (nr) * 3)) & 1)
1351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
136449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck#define PWM_FROM_REG(val, inv)		((inv) ? 255 - (val) : (val))
1371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline u8 PWM_TO_REG(int val, int inv)
1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (inv)
1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		val = 255 - val;
1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (val < 0)
1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return 0;
1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (val > 255)
1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return 255;
1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return val;
1461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
1491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Voltage registers and conversions
1501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
1511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define PC87365_REG_IN_CONVRATE		0x07
1531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define PC87365_REG_IN_CONFIG		0x08
1541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define PC87365_REG_IN			0x0B
1551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define PC87365_REG_IN_MIN		0x0D
1561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define PC87365_REG_IN_MAX		0x0C
1571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define PC87365_REG_IN_STATUS		0x0A
1581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define PC87365_REG_IN_ALARMS1		0x00
1591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define PC87365_REG_IN_ALARMS2		0x01
1601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define PC87365_REG_VID			0x06
1611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
162449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck#define IN_FROM_REG(val, ref)		(((val) * (ref) + 128) / 256)
163449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck#define IN_TO_REG(val, ref)		((val) < 0 ? 0 : \
164449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck					 (val) * 256 >= (ref) * 255 ? 255 : \
165449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck					 ((val) * 256 + (ref) / 2) / (ref))
1661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
1681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Temperature registers and conversions
1691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
1701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define PC87365_REG_TEMP_CONFIG		0x08
1721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define PC87365_REG_TEMP		0x0B
1731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define PC87365_REG_TEMP_MIN		0x0D
1741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define PC87365_REG_TEMP_MAX		0x0C
1751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define PC87365_REG_TEMP_CRIT		0x0E
1761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define PC87365_REG_TEMP_STATUS		0x0A
1771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define PC87365_REG_TEMP_ALARMS		0x00
1781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TEMP_FROM_REG(val)		((val) * 1000)
1801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TEMP_TO_REG(val)		((val) < -55000 ? -55 : \
1811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					 (val) > 127000 ? 127 : \
1821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					 (val) < 0 ? ((val) - 500) / 1000 : \
1831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					 ((val) + 500) / 1000)
1841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
186f641b588fdfd25e73c73f6e4977cd2daf8a5e363Jean Delvare * Device data
1871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
1881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct pc87360_data {
190f641b588fdfd25e73c73f6e4977cd2daf8a5e363Jean Delvare	const char *name;
1911beeffe43311f64df8dd0ab08ff6b1858c58363fTony Jones	struct device *hwmon_dev;
1929a61bf6300533d3b64d7ff29adfec00e596de67dIngo Molnar	struct mutex lock;
1939a61bf6300533d3b64d7ff29adfec00e596de67dIngo Molnar	struct mutex update_lock;
1941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	char valid;		/* !=0 if following fields are valid */
1951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long last_updated;	/* In jiffies */
1961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int address[3];
1981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 fannr, innr, tempnr;
2001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 fan[3];		/* Register value */
2021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 fan_min[3];		/* Register value */
2031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 fan_status[3];	/* Register value */
2041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 pwm[3];		/* Register value */
2051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u16 fan_conf;		/* Configuration register values, combined */
2061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u16 in_vref;		/* 1 mV/bit */
2081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 in[14];		/* Register value */
2091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 in_min[14];		/* Register value */
2101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 in_max[14];		/* Register value */
2111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 in_crit[3];		/* Register value */
2121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 in_status[14];	/* Register value */
2131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u16 in_alarms;		/* Register values, combined, masked */
2141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 vid_conf;		/* Configuration register value */
2151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 vrm;
2161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 vid;			/* Register value */
2171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	s8 temp[3];		/* Register value */
2191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	s8 temp_min[3];		/* Register value */
2201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	s8 temp_max[3];		/* Register value */
2211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	s8 temp_crit[3];	/* Register value */
2221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 temp_status[3];	/* Register value */
2231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 temp_alarms;		/* Register value, masked */
2241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
2251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
2271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Functions declaration
2281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
2291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
230f641b588fdfd25e73c73f6e4977cd2daf8a5e363Jean Delvarestatic int pc87360_probe(struct platform_device *pdev);
231d0546128980c18748010c758903b02909e634830Jean Delvarestatic int __devexit pc87360_remove(struct platform_device *pdev);
2321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int pc87360_read_value(struct pc87360_data *data, u8 ldi, u8 bank,
2341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      u8 reg);
2351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void pc87360_write_value(struct pc87360_data *data, u8 ldi, u8 bank,
2361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				u8 reg, u8 value);
237f641b588fdfd25e73c73f6e4977cd2daf8a5e363Jean Delvarestatic void pc87360_init_device(struct platform_device *pdev,
238f641b588fdfd25e73c73f6e4977cd2daf8a5e363Jean Delvare				int use_thermistors);
2391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct pc87360_data *pc87360_update_device(struct device *dev);
2401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
242f641b588fdfd25e73c73f6e4977cd2daf8a5e363Jean Delvare * Driver data
2431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
2441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
245f641b588fdfd25e73c73f6e4977cd2daf8a5e363Jean Delvarestatic struct platform_driver pc87360_driver = {
246cdaf79349c7d24e1d33acb6497849c9e956a33eaLaurent Riffard	.driver = {
247872188420997f7f7c1b968fd9bce6578e4c3d45fJean Delvare		.owner	= THIS_MODULE,
248cdaf79349c7d24e1d33acb6497849c9e956a33eaLaurent Riffard		.name	= "pc87360",
249cdaf79349c7d24e1d33acb6497849c9e956a33eaLaurent Riffard	},
250f641b588fdfd25e73c73f6e4977cd2daf8a5e363Jean Delvare	.probe		= pc87360_probe,
251f641b588fdfd25e73c73f6e4977cd2daf8a5e363Jean Delvare	.remove		= __devexit_p(pc87360_remove),
2521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
2531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
2551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Sysfs stuff
2561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
2571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
258449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeckstatic ssize_t show_fan_input(struct device *dev,
259449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck			      struct device_attribute *devattr, char *buf)
260f0986bd8f390392948db85dac526fb238752372bJim Cromie{
261f0986bd8f390392948db85dac526fb238752372bJim Cromie	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
262f0986bd8f390392948db85dac526fb238752372bJim Cromie	struct pc87360_data *data = pc87360_update_device(dev);
263694fa056a60828ef54a5db958468cc600c3b3622Jim Cromie	return sprintf(buf, "%u\n", FAN_FROM_REG(data->fan[attr->index],
264694fa056a60828ef54a5db958468cc600c3b3622Jim Cromie		       FAN_DIV_FROM_REG(data->fan_status[attr->index])));
265f0986bd8f390392948db85dac526fb238752372bJim Cromie}
266449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeckstatic ssize_t show_fan_min(struct device *dev,
267449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck			    struct device_attribute *devattr, char *buf)
268f0986bd8f390392948db85dac526fb238752372bJim Cromie{
269f0986bd8f390392948db85dac526fb238752372bJim Cromie	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
270f0986bd8f390392948db85dac526fb238752372bJim Cromie	struct pc87360_data *data = pc87360_update_device(dev);
271694fa056a60828ef54a5db958468cc600c3b3622Jim Cromie	return sprintf(buf, "%u\n", FAN_FROM_REG(data->fan_min[attr->index],
272694fa056a60828ef54a5db958468cc600c3b3622Jim Cromie		       FAN_DIV_FROM_REG(data->fan_status[attr->index])));
273f0986bd8f390392948db85dac526fb238752372bJim Cromie}
274449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeckstatic ssize_t show_fan_div(struct device *dev,
275449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck			    struct device_attribute *devattr, char *buf)
276f0986bd8f390392948db85dac526fb238752372bJim Cromie{
277f0986bd8f390392948db85dac526fb238752372bJim Cromie	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
278f0986bd8f390392948db85dac526fb238752372bJim Cromie	struct pc87360_data *data = pc87360_update_device(dev);
279f0986bd8f390392948db85dac526fb238752372bJim Cromie	return sprintf(buf, "%u\n",
280694fa056a60828ef54a5db958468cc600c3b3622Jim Cromie		       FAN_DIV_FROM_REG(data->fan_status[attr->index]));
281f0986bd8f390392948db85dac526fb238752372bJim Cromie}
282449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeckstatic ssize_t show_fan_status(struct device *dev,
283449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck			       struct device_attribute *devattr, char *buf)
284f0986bd8f390392948db85dac526fb238752372bJim Cromie{
285f0986bd8f390392948db85dac526fb238752372bJim Cromie	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
286f0986bd8f390392948db85dac526fb238752372bJim Cromie	struct pc87360_data *data = pc87360_update_device(dev);
287f0986bd8f390392948db85dac526fb238752372bJim Cromie	return sprintf(buf, "%u\n",
288694fa056a60828ef54a5db958468cc600c3b3622Jim Cromie		       FAN_STATUS_FROM_REG(data->fan_status[attr->index]));
289f0986bd8f390392948db85dac526fb238752372bJim Cromie}
290449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeckstatic ssize_t set_fan_min(struct device *dev,
291449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck			   struct device_attribute *devattr, const char *buf,
292f0986bd8f390392948db85dac526fb238752372bJim Cromie	size_t count)
293f0986bd8f390392948db85dac526fb238752372bJim Cromie{
294f0986bd8f390392948db85dac526fb238752372bJim Cromie	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
295f641b588fdfd25e73c73f6e4977cd2daf8a5e363Jean Delvare	struct pc87360_data *data = dev_get_drvdata(dev);
296449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck	long fan_min;
297449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck	int err;
298449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck
299449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck	err = kstrtol(buf, 10, &fan_min);
300449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck	if (err)
301449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck		return err;
30211be27ea9bfd0ea7bca797ba6937285d18d426c2Jim Cromie
3039a61bf6300533d3b64d7ff29adfec00e596de67dIngo Molnar	mutex_lock(&data->update_lock);
304449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck	fan_min = FAN_TO_REG(fan_min,
305449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck			     FAN_DIV_FROM_REG(data->fan_status[attr->index]));
30611be27ea9bfd0ea7bca797ba6937285d18d426c2Jim Cromie
30711be27ea9bfd0ea7bca797ba6937285d18d426c2Jim Cromie	/* If it wouldn't fit, change clock divisor */
30811be27ea9bfd0ea7bca797ba6937285d18d426c2Jim Cromie	while (fan_min > 255
30911be27ea9bfd0ea7bca797ba6937285d18d426c2Jim Cromie	    && (data->fan_status[attr->index] & 0x60) != 0x60) {
31011be27ea9bfd0ea7bca797ba6937285d18d426c2Jim Cromie		fan_min >>= 1;
31111be27ea9bfd0ea7bca797ba6937285d18d426c2Jim Cromie		data->fan[attr->index] >>= 1;
31211be27ea9bfd0ea7bca797ba6937285d18d426c2Jim Cromie		data->fan_status[attr->index] += 0x20;
31311be27ea9bfd0ea7bca797ba6937285d18d426c2Jim Cromie	}
31411be27ea9bfd0ea7bca797ba6937285d18d426c2Jim Cromie	data->fan_min[attr->index] = fan_min > 255 ? 255 : fan_min;
315449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck	pc87360_write_value(data, LD_FAN, NO_BANK,
316449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck			    PC87360_REG_FAN_MIN(attr->index),
31711be27ea9bfd0ea7bca797ba6937285d18d426c2Jim Cromie			    data->fan_min[attr->index]);
31811be27ea9bfd0ea7bca797ba6937285d18d426c2Jim Cromie
31911be27ea9bfd0ea7bca797ba6937285d18d426c2Jim Cromie	/* Write new divider, preserve alarm bits */
320449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck	pc87360_write_value(data, LD_FAN, NO_BANK,
321449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck			    PC87360_REG_FAN_STATUS(attr->index),
32211be27ea9bfd0ea7bca797ba6937285d18d426c2Jim Cromie			    data->fan_status[attr->index] & 0xF9);
3239a61bf6300533d3b64d7ff29adfec00e596de67dIngo Molnar	mutex_unlock(&data->update_lock);
32411be27ea9bfd0ea7bca797ba6937285d18d426c2Jim Cromie
32511be27ea9bfd0ea7bca797ba6937285d18d426c2Jim Cromie	return count;
326f0986bd8f390392948db85dac526fb238752372bJim Cromie}
327f0986bd8f390392948db85dac526fb238752372bJim Cromie
328dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromiestatic struct sensor_device_attribute fan_input[] = {
329dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromie	SENSOR_ATTR(fan1_input, S_IRUGO, show_fan_input, NULL, 0),
330dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromie	SENSOR_ATTR(fan2_input, S_IRUGO, show_fan_input, NULL, 1),
331dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromie	SENSOR_ATTR(fan3_input, S_IRUGO, show_fan_input, NULL, 2),
332dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromie};
333dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromiestatic struct sensor_device_attribute fan_status[] = {
334dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromie	SENSOR_ATTR(fan1_status, S_IRUGO, show_fan_status, NULL, 0),
335dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromie	SENSOR_ATTR(fan2_status, S_IRUGO, show_fan_status, NULL, 1),
336dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromie	SENSOR_ATTR(fan3_status, S_IRUGO, show_fan_status, NULL, 2),
337dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromie};
338dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromiestatic struct sensor_device_attribute fan_div[] = {
339dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromie	SENSOR_ATTR(fan1_div, S_IRUGO, show_fan_div, NULL, 0),
340dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromie	SENSOR_ATTR(fan2_div, S_IRUGO, show_fan_div, NULL, 1),
341dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromie	SENSOR_ATTR(fan3_div, S_IRUGO, show_fan_div, NULL, 2),
342dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromie};
343dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromiestatic struct sensor_device_attribute fan_min[] = {
344dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromie	SENSOR_ATTR(fan1_min, S_IWUSR | S_IRUGO, show_fan_min, set_fan_min, 0),
345dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromie	SENSOR_ATTR(fan2_min, S_IWUSR | S_IRUGO, show_fan_min, set_fan_min, 1),
346dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromie	SENSOR_ATTR(fan3_min, S_IWUSR | S_IRUGO, show_fan_min, set_fan_min, 2),
347dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromie};
3481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
349bce2778df9ea32146d59344c027001e270911f4bGuenter Roeck#define FAN_UNIT_ATTRS(X)		\
350bce2778df9ea32146d59344c027001e270911f4bGuenter Roeck{	&fan_input[X].dev_attr.attr,	\
351941c5c05cf38da5e12d70edc5d0fec5c24bce8b6Jim Cromie	&fan_status[X].dev_attr.attr,	\
352941c5c05cf38da5e12d70edc5d0fec5c24bce8b6Jim Cromie	&fan_div[X].dev_attr.attr,	\
353bce2778df9ea32146d59344c027001e270911f4bGuenter Roeck	&fan_min[X].dev_attr.attr,	\
354bce2778df9ea32146d59344c027001e270911f4bGuenter Roeck	NULL				\
355bce2778df9ea32146d59344c027001e270911f4bGuenter Roeck}
356941c5c05cf38da5e12d70edc5d0fec5c24bce8b6Jim Cromie
357449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeckstatic ssize_t show_pwm(struct device *dev, struct device_attribute *devattr,
358449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck			char *buf)
359f0986bd8f390392948db85dac526fb238752372bJim Cromie{
360f0986bd8f390392948db85dac526fb238752372bJim Cromie	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
361f0986bd8f390392948db85dac526fb238752372bJim Cromie	struct pc87360_data *data = pc87360_update_device(dev);
362f0986bd8f390392948db85dac526fb238752372bJim Cromie	return sprintf(buf, "%u\n",
363694fa056a60828ef54a5db958468cc600c3b3622Jim Cromie		       PWM_FROM_REG(data->pwm[attr->index],
364f0986bd8f390392948db85dac526fb238752372bJim Cromie				    FAN_CONFIG_INVERT(data->fan_conf,
365694fa056a60828ef54a5db958468cc600c3b3622Jim Cromie						      attr->index)));
366f0986bd8f390392948db85dac526fb238752372bJim Cromie}
367449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeckstatic ssize_t set_pwm(struct device *dev, struct device_attribute *devattr,
368449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck		       const char *buf, size_t count)
369f0986bd8f390392948db85dac526fb238752372bJim Cromie{
370f0986bd8f390392948db85dac526fb238752372bJim Cromie	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
371f641b588fdfd25e73c73f6e4977cd2daf8a5e363Jean Delvare	struct pc87360_data *data = dev_get_drvdata(dev);
372449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck	long val;
373449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck	int err;
374449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck
375449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck	err = kstrtol(buf, 10, &val);
376449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck	if (err)
377449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck		return err;
378f0986bd8f390392948db85dac526fb238752372bJim Cromie
3799a61bf6300533d3b64d7ff29adfec00e596de67dIngo Molnar	mutex_lock(&data->update_lock);
380694fa056a60828ef54a5db958468cc600c3b3622Jim Cromie	data->pwm[attr->index] = PWM_TO_REG(val,
381694fa056a60828ef54a5db958468cc600c3b3622Jim Cromie			      FAN_CONFIG_INVERT(data->fan_conf, attr->index));
382694fa056a60828ef54a5db958468cc600c3b3622Jim Cromie	pc87360_write_value(data, LD_FAN, NO_BANK, PC87360_REG_PWM(attr->index),
383694fa056a60828ef54a5db958468cc600c3b3622Jim Cromie			    data->pwm[attr->index]);
3849a61bf6300533d3b64d7ff29adfec00e596de67dIngo Molnar	mutex_unlock(&data->update_lock);
385f0986bd8f390392948db85dac526fb238752372bJim Cromie	return count;
386f0986bd8f390392948db85dac526fb238752372bJim Cromie}
387f0986bd8f390392948db85dac526fb238752372bJim Cromie
388dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromiestatic struct sensor_device_attribute pwm[] = {
389dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromie	SENSOR_ATTR(pwm1, S_IWUSR | S_IRUGO, show_pwm, set_pwm, 0),
390dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromie	SENSOR_ATTR(pwm2, S_IWUSR | S_IRUGO, show_pwm, set_pwm, 1),
391dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromie	SENSOR_ATTR(pwm3, S_IWUSR | S_IRUGO, show_pwm, set_pwm, 2),
392dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromie};
3931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
394bce2778df9ea32146d59344c027001e270911f4bGuenter Roeckstatic struct attribute *pc8736x_fan_attr[][5] = {
395941c5c05cf38da5e12d70edc5d0fec5c24bce8b6Jim Cromie	FAN_UNIT_ATTRS(0),
396941c5c05cf38da5e12d70edc5d0fec5c24bce8b6Jim Cromie	FAN_UNIT_ATTRS(1),
397bce2778df9ea32146d59344c027001e270911f4bGuenter Roeck	FAN_UNIT_ATTRS(2)
398941c5c05cf38da5e12d70edc5d0fec5c24bce8b6Jim Cromie};
399bce2778df9ea32146d59344c027001e270911f4bGuenter Roeck
400bce2778df9ea32146d59344c027001e270911f4bGuenter Roeckstatic const struct attribute_group pc8736x_fan_attr_group[] = {
401bce2778df9ea32146d59344c027001e270911f4bGuenter Roeck	{ .attrs = pc8736x_fan_attr[0], },
402bce2778df9ea32146d59344c027001e270911f4bGuenter Roeck	{ .attrs = pc8736x_fan_attr[1], },
403bce2778df9ea32146d59344c027001e270911f4bGuenter Roeck	{ .attrs = pc8736x_fan_attr[2], },
404941c5c05cf38da5e12d70edc5d0fec5c24bce8b6Jim Cromie};
405941c5c05cf38da5e12d70edc5d0fec5c24bce8b6Jim Cromie
406449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeckstatic ssize_t show_in_input(struct device *dev,
407449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck			     struct device_attribute *devattr, char *buf)
408f0986bd8f390392948db85dac526fb238752372bJim Cromie{
409f0986bd8f390392948db85dac526fb238752372bJim Cromie	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
410f0986bd8f390392948db85dac526fb238752372bJim Cromie	struct pc87360_data *data = pc87360_update_device(dev);
411f0986bd8f390392948db85dac526fb238752372bJim Cromie	return sprintf(buf, "%u\n", IN_FROM_REG(data->in[attr->index],
412f0986bd8f390392948db85dac526fb238752372bJim Cromie		       data->in_vref));
413f0986bd8f390392948db85dac526fb238752372bJim Cromie}
414449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeckstatic ssize_t show_in_min(struct device *dev,
415449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck			   struct device_attribute *devattr, char *buf)
416f0986bd8f390392948db85dac526fb238752372bJim Cromie{
417f0986bd8f390392948db85dac526fb238752372bJim Cromie	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
418f0986bd8f390392948db85dac526fb238752372bJim Cromie	struct pc87360_data *data = pc87360_update_device(dev);
419f0986bd8f390392948db85dac526fb238752372bJim Cromie	return sprintf(buf, "%u\n", IN_FROM_REG(data->in_min[attr->index],
420f0986bd8f390392948db85dac526fb238752372bJim Cromie		       data->in_vref));
421f0986bd8f390392948db85dac526fb238752372bJim Cromie}
422449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeckstatic ssize_t show_in_max(struct device *dev,
423449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck			   struct device_attribute *devattr, char *buf)
424f0986bd8f390392948db85dac526fb238752372bJim Cromie{
425f0986bd8f390392948db85dac526fb238752372bJim Cromie	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
426f0986bd8f390392948db85dac526fb238752372bJim Cromie	struct pc87360_data *data = pc87360_update_device(dev);
427f0986bd8f390392948db85dac526fb238752372bJim Cromie	return sprintf(buf, "%u\n", IN_FROM_REG(data->in_max[attr->index],
428f0986bd8f390392948db85dac526fb238752372bJim Cromie		       data->in_vref));
429f0986bd8f390392948db85dac526fb238752372bJim Cromie}
430449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeckstatic ssize_t show_in_status(struct device *dev,
431449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck			      struct device_attribute *devattr, char *buf)
432f0986bd8f390392948db85dac526fb238752372bJim Cromie{
433f0986bd8f390392948db85dac526fb238752372bJim Cromie	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
434f0986bd8f390392948db85dac526fb238752372bJim Cromie	struct pc87360_data *data = pc87360_update_device(dev);
435f0986bd8f390392948db85dac526fb238752372bJim Cromie	return sprintf(buf, "%u\n", data->in_status[attr->index]);
436f0986bd8f390392948db85dac526fb238752372bJim Cromie}
437449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeckstatic ssize_t set_in_min(struct device *dev, struct device_attribute *devattr,
438449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck			  const char *buf, size_t count)
439f0986bd8f390392948db85dac526fb238752372bJim Cromie{
440f0986bd8f390392948db85dac526fb238752372bJim Cromie	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
441f641b588fdfd25e73c73f6e4977cd2daf8a5e363Jean Delvare	struct pc87360_data *data = dev_get_drvdata(dev);
442449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck	long val;
443449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck	int err;
444449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck
445449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck	err = kstrtol(buf, 10, &val);
446449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck	if (err)
447449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck		return err;
448f0986bd8f390392948db85dac526fb238752372bJim Cromie
4499a61bf6300533d3b64d7ff29adfec00e596de67dIngo Molnar	mutex_lock(&data->update_lock);
450f0986bd8f390392948db85dac526fb238752372bJim Cromie	data->in_min[attr->index] = IN_TO_REG(val, data->in_vref);
451f0986bd8f390392948db85dac526fb238752372bJim Cromie	pc87360_write_value(data, LD_IN, attr->index, PC87365_REG_IN_MIN,
452f0986bd8f390392948db85dac526fb238752372bJim Cromie			    data->in_min[attr->index]);
4539a61bf6300533d3b64d7ff29adfec00e596de67dIngo Molnar	mutex_unlock(&data->update_lock);
454f0986bd8f390392948db85dac526fb238752372bJim Cromie	return count;
455f0986bd8f390392948db85dac526fb238752372bJim Cromie}
456449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeckstatic ssize_t set_in_max(struct device *dev, struct device_attribute *devattr,
457449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck			  const char *buf, size_t count)
458f0986bd8f390392948db85dac526fb238752372bJim Cromie{
459f0986bd8f390392948db85dac526fb238752372bJim Cromie	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
460f641b588fdfd25e73c73f6e4977cd2daf8a5e363Jean Delvare	struct pc87360_data *data = dev_get_drvdata(dev);
461449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck	long val;
462449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck	int err;
463449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck
464449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck	err = kstrtol(buf, 10, &val);
465449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck	if (err)
466449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck		return err;
467f0986bd8f390392948db85dac526fb238752372bJim Cromie
4689a61bf6300533d3b64d7ff29adfec00e596de67dIngo Molnar	mutex_lock(&data->update_lock);
469f0986bd8f390392948db85dac526fb238752372bJim Cromie	data->in_max[attr->index] = IN_TO_REG(val,
470f0986bd8f390392948db85dac526fb238752372bJim Cromie			       data->in_vref);
471f0986bd8f390392948db85dac526fb238752372bJim Cromie	pc87360_write_value(data, LD_IN, attr->index, PC87365_REG_IN_MAX,
472f0986bd8f390392948db85dac526fb238752372bJim Cromie			    data->in_max[attr->index]);
4739a61bf6300533d3b64d7ff29adfec00e596de67dIngo Molnar	mutex_unlock(&data->update_lock);
474f0986bd8f390392948db85dac526fb238752372bJim Cromie	return count;
475f0986bd8f390392948db85dac526fb238752372bJim Cromie}
476f0986bd8f390392948db85dac526fb238752372bJim Cromie
477dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromiestatic struct sensor_device_attribute in_input[] = {
478dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromie	SENSOR_ATTR(in0_input, S_IRUGO, show_in_input, NULL, 0),
479dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromie	SENSOR_ATTR(in1_input, S_IRUGO, show_in_input, NULL, 1),
480dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromie	SENSOR_ATTR(in2_input, S_IRUGO, show_in_input, NULL, 2),
481dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromie	SENSOR_ATTR(in3_input, S_IRUGO, show_in_input, NULL, 3),
482dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromie	SENSOR_ATTR(in4_input, S_IRUGO, show_in_input, NULL, 4),
483dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromie	SENSOR_ATTR(in5_input, S_IRUGO, show_in_input, NULL, 5),
484dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromie	SENSOR_ATTR(in6_input, S_IRUGO, show_in_input, NULL, 6),
485dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromie	SENSOR_ATTR(in7_input, S_IRUGO, show_in_input, NULL, 7),
486dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromie	SENSOR_ATTR(in8_input, S_IRUGO, show_in_input, NULL, 8),
487dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromie	SENSOR_ATTR(in9_input, S_IRUGO, show_in_input, NULL, 9),
488dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromie	SENSOR_ATTR(in10_input, S_IRUGO, show_in_input, NULL, 10),
489dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromie};
490dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromiestatic struct sensor_device_attribute in_status[] = {
491dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromie	SENSOR_ATTR(in0_status, S_IRUGO, show_in_status, NULL, 0),
492dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromie	SENSOR_ATTR(in1_status, S_IRUGO, show_in_status, NULL, 1),
493dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromie	SENSOR_ATTR(in2_status, S_IRUGO, show_in_status, NULL, 2),
494dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromie	SENSOR_ATTR(in3_status, S_IRUGO, show_in_status, NULL, 3),
495dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromie	SENSOR_ATTR(in4_status, S_IRUGO, show_in_status, NULL, 4),
496dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromie	SENSOR_ATTR(in5_status, S_IRUGO, show_in_status, NULL, 5),
497dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromie	SENSOR_ATTR(in6_status, S_IRUGO, show_in_status, NULL, 6),
498dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromie	SENSOR_ATTR(in7_status, S_IRUGO, show_in_status, NULL, 7),
499dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromie	SENSOR_ATTR(in8_status, S_IRUGO, show_in_status, NULL, 8),
500dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromie	SENSOR_ATTR(in9_status, S_IRUGO, show_in_status, NULL, 9),
501dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromie	SENSOR_ATTR(in10_status, S_IRUGO, show_in_status, NULL, 10),
502dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromie};
503dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromiestatic struct sensor_device_attribute in_min[] = {
504dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromie	SENSOR_ATTR(in0_min, S_IWUSR | S_IRUGO, show_in_min, set_in_min, 0),
505dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromie	SENSOR_ATTR(in1_min, S_IWUSR | S_IRUGO, show_in_min, set_in_min, 1),
506dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromie	SENSOR_ATTR(in2_min, S_IWUSR | S_IRUGO, show_in_min, set_in_min, 2),
507dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromie	SENSOR_ATTR(in3_min, S_IWUSR | S_IRUGO, show_in_min, set_in_min, 3),
508dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromie	SENSOR_ATTR(in4_min, S_IWUSR | S_IRUGO, show_in_min, set_in_min, 4),
509dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromie	SENSOR_ATTR(in5_min, S_IWUSR | S_IRUGO, show_in_min, set_in_min, 5),
510dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromie	SENSOR_ATTR(in6_min, S_IWUSR | S_IRUGO, show_in_min, set_in_min, 6),
511dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromie	SENSOR_ATTR(in7_min, S_IWUSR | S_IRUGO, show_in_min, set_in_min, 7),
512dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromie	SENSOR_ATTR(in8_min, S_IWUSR | S_IRUGO, show_in_min, set_in_min, 8),
513dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromie	SENSOR_ATTR(in9_min, S_IWUSR | S_IRUGO, show_in_min, set_in_min, 9),
514dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromie	SENSOR_ATTR(in10_min, S_IWUSR | S_IRUGO, show_in_min, set_in_min, 10),
515dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromie};
516dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromiestatic struct sensor_device_attribute in_max[] = {
517dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromie	SENSOR_ATTR(in0_max, S_IWUSR | S_IRUGO, show_in_max, set_in_max, 0),
518dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromie	SENSOR_ATTR(in1_max, S_IWUSR | S_IRUGO, show_in_max, set_in_max, 1),
519dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromie	SENSOR_ATTR(in2_max, S_IWUSR | S_IRUGO, show_in_max, set_in_max, 2),
520dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromie	SENSOR_ATTR(in3_max, S_IWUSR | S_IRUGO, show_in_max, set_in_max, 3),
521dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromie	SENSOR_ATTR(in4_max, S_IWUSR | S_IRUGO, show_in_max, set_in_max, 4),
522dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromie	SENSOR_ATTR(in5_max, S_IWUSR | S_IRUGO, show_in_max, set_in_max, 5),
523dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromie	SENSOR_ATTR(in6_max, S_IWUSR | S_IRUGO, show_in_max, set_in_max, 6),
524dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromie	SENSOR_ATTR(in7_max, S_IWUSR | S_IRUGO, show_in_max, set_in_max, 7),
525dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromie	SENSOR_ATTR(in8_max, S_IWUSR | S_IRUGO, show_in_max, set_in_max, 8),
526dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromie	SENSOR_ATTR(in9_max, S_IWUSR | S_IRUGO, show_in_max, set_in_max, 9),
527dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromie	SENSOR_ATTR(in10_max, S_IWUSR | S_IRUGO, show_in_max, set_in_max, 10),
528dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromie};
5291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
53028f74e71775b1ae0ebf7fe87f7a7f39ecb77a2b8Jim Cromie/* (temp & vin) channel status register alarm bits (pdf sec.11.5.12) */
53128f74e71775b1ae0ebf7fe87f7a7f39ecb77a2b8Jim Cromie#define CHAN_ALM_MIN	0x02	/* min limit crossed */
53228f74e71775b1ae0ebf7fe87f7a7f39ecb77a2b8Jim Cromie#define CHAN_ALM_MAX	0x04	/* max limit exceeded */
53328f74e71775b1ae0ebf7fe87f7a7f39ecb77a2b8Jim Cromie#define TEMP_ALM_CRIT	0x08	/* temp crit exceeded (temp only) */
53428f74e71775b1ae0ebf7fe87f7a7f39ecb77a2b8Jim Cromie
5353af2861e8b80676d32c5498f9ac1b2de70d3e19bGuenter Roeck/*
5363af2861e8b80676d32c5498f9ac1b2de70d3e19bGuenter Roeck * show_in_min/max_alarm() reads data from the per-channel status
5373af2861e8b80676d32c5498f9ac1b2de70d3e19bGuenter Roeck * register (sec 11.5.12), not the vin event status registers (sec
5383af2861e8b80676d32c5498f9ac1b2de70d3e19bGuenter Roeck * 11.5.2) that (legacy) show_in_alarm() resds (via data->in_alarms)
5393af2861e8b80676d32c5498f9ac1b2de70d3e19bGuenter Roeck */
540492e9657d1a790f44ab9b0e03fc72c1d8145f590Jim Cromie
541492e9657d1a790f44ab9b0e03fc72c1d8145f590Jim Cromiestatic ssize_t show_in_min_alarm(struct device *dev,
542492e9657d1a790f44ab9b0e03fc72c1d8145f590Jim Cromie			struct device_attribute *devattr, char *buf)
543492e9657d1a790f44ab9b0e03fc72c1d8145f590Jim Cromie{
544492e9657d1a790f44ab9b0e03fc72c1d8145f590Jim Cromie	struct pc87360_data *data = pc87360_update_device(dev);
545492e9657d1a790f44ab9b0e03fc72c1d8145f590Jim Cromie	unsigned nr = to_sensor_dev_attr(devattr)->index;
546492e9657d1a790f44ab9b0e03fc72c1d8145f590Jim Cromie
547492e9657d1a790f44ab9b0e03fc72c1d8145f590Jim Cromie	return sprintf(buf, "%u\n", !!(data->in_status[nr] & CHAN_ALM_MIN));
548492e9657d1a790f44ab9b0e03fc72c1d8145f590Jim Cromie}
549492e9657d1a790f44ab9b0e03fc72c1d8145f590Jim Cromiestatic ssize_t show_in_max_alarm(struct device *dev,
550492e9657d1a790f44ab9b0e03fc72c1d8145f590Jim Cromie			struct device_attribute *devattr, char *buf)
551492e9657d1a790f44ab9b0e03fc72c1d8145f590Jim Cromie{
552492e9657d1a790f44ab9b0e03fc72c1d8145f590Jim Cromie	struct pc87360_data *data = pc87360_update_device(dev);
553492e9657d1a790f44ab9b0e03fc72c1d8145f590Jim Cromie	unsigned nr = to_sensor_dev_attr(devattr)->index;
554492e9657d1a790f44ab9b0e03fc72c1d8145f590Jim Cromie
555492e9657d1a790f44ab9b0e03fc72c1d8145f590Jim Cromie	return sprintf(buf, "%u\n", !!(data->in_status[nr] & CHAN_ALM_MAX));
556492e9657d1a790f44ab9b0e03fc72c1d8145f590Jim Cromie}
557492e9657d1a790f44ab9b0e03fc72c1d8145f590Jim Cromie
558492e9657d1a790f44ab9b0e03fc72c1d8145f590Jim Cromiestatic struct sensor_device_attribute in_min_alarm[] = {
559492e9657d1a790f44ab9b0e03fc72c1d8145f590Jim Cromie	SENSOR_ATTR(in0_min_alarm, S_IRUGO, show_in_min_alarm, NULL, 0),
560492e9657d1a790f44ab9b0e03fc72c1d8145f590Jim Cromie	SENSOR_ATTR(in1_min_alarm, S_IRUGO, show_in_min_alarm, NULL, 1),
561492e9657d1a790f44ab9b0e03fc72c1d8145f590Jim Cromie	SENSOR_ATTR(in2_min_alarm, S_IRUGO, show_in_min_alarm, NULL, 2),
562492e9657d1a790f44ab9b0e03fc72c1d8145f590Jim Cromie	SENSOR_ATTR(in3_min_alarm, S_IRUGO, show_in_min_alarm, NULL, 3),
563492e9657d1a790f44ab9b0e03fc72c1d8145f590Jim Cromie	SENSOR_ATTR(in4_min_alarm, S_IRUGO, show_in_min_alarm, NULL, 4),
564492e9657d1a790f44ab9b0e03fc72c1d8145f590Jim Cromie	SENSOR_ATTR(in5_min_alarm, S_IRUGO, show_in_min_alarm, NULL, 5),
565492e9657d1a790f44ab9b0e03fc72c1d8145f590Jim Cromie	SENSOR_ATTR(in6_min_alarm, S_IRUGO, show_in_min_alarm, NULL, 6),
566492e9657d1a790f44ab9b0e03fc72c1d8145f590Jim Cromie	SENSOR_ATTR(in7_min_alarm, S_IRUGO, show_in_min_alarm, NULL, 7),
567492e9657d1a790f44ab9b0e03fc72c1d8145f590Jim Cromie	SENSOR_ATTR(in8_min_alarm, S_IRUGO, show_in_min_alarm, NULL, 8),
568492e9657d1a790f44ab9b0e03fc72c1d8145f590Jim Cromie	SENSOR_ATTR(in9_min_alarm, S_IRUGO, show_in_min_alarm, NULL, 9),
569492e9657d1a790f44ab9b0e03fc72c1d8145f590Jim Cromie	SENSOR_ATTR(in10_min_alarm, S_IRUGO, show_in_min_alarm, NULL, 10),
570492e9657d1a790f44ab9b0e03fc72c1d8145f590Jim Cromie};
571492e9657d1a790f44ab9b0e03fc72c1d8145f590Jim Cromiestatic struct sensor_device_attribute in_max_alarm[] = {
572492e9657d1a790f44ab9b0e03fc72c1d8145f590Jim Cromie	SENSOR_ATTR(in0_max_alarm, S_IRUGO, show_in_max_alarm, NULL, 0),
573492e9657d1a790f44ab9b0e03fc72c1d8145f590Jim Cromie	SENSOR_ATTR(in1_max_alarm, S_IRUGO, show_in_max_alarm, NULL, 1),
574492e9657d1a790f44ab9b0e03fc72c1d8145f590Jim Cromie	SENSOR_ATTR(in2_max_alarm, S_IRUGO, show_in_max_alarm, NULL, 2),
575492e9657d1a790f44ab9b0e03fc72c1d8145f590Jim Cromie	SENSOR_ATTR(in3_max_alarm, S_IRUGO, show_in_max_alarm, NULL, 3),
576492e9657d1a790f44ab9b0e03fc72c1d8145f590Jim Cromie	SENSOR_ATTR(in4_max_alarm, S_IRUGO, show_in_max_alarm, NULL, 4),
577492e9657d1a790f44ab9b0e03fc72c1d8145f590Jim Cromie	SENSOR_ATTR(in5_max_alarm, S_IRUGO, show_in_max_alarm, NULL, 5),
578492e9657d1a790f44ab9b0e03fc72c1d8145f590Jim Cromie	SENSOR_ATTR(in6_max_alarm, S_IRUGO, show_in_max_alarm, NULL, 6),
579492e9657d1a790f44ab9b0e03fc72c1d8145f590Jim Cromie	SENSOR_ATTR(in7_max_alarm, S_IRUGO, show_in_max_alarm, NULL, 7),
580492e9657d1a790f44ab9b0e03fc72c1d8145f590Jim Cromie	SENSOR_ATTR(in8_max_alarm, S_IRUGO, show_in_max_alarm, NULL, 8),
581492e9657d1a790f44ab9b0e03fc72c1d8145f590Jim Cromie	SENSOR_ATTR(in9_max_alarm, S_IRUGO, show_in_max_alarm, NULL, 9),
582492e9657d1a790f44ab9b0e03fc72c1d8145f590Jim Cromie	SENSOR_ATTR(in10_max_alarm, S_IRUGO, show_in_max_alarm, NULL, 10),
583492e9657d1a790f44ab9b0e03fc72c1d8145f590Jim Cromie};
584492e9657d1a790f44ab9b0e03fc72c1d8145f590Jim Cromie
585941c5c05cf38da5e12d70edc5d0fec5c24bce8b6Jim Cromie#define VIN_UNIT_ATTRS(X) \
586941c5c05cf38da5e12d70edc5d0fec5c24bce8b6Jim Cromie	&in_input[X].dev_attr.attr,	\
587941c5c05cf38da5e12d70edc5d0fec5c24bce8b6Jim Cromie	&in_status[X].dev_attr.attr,	\
588941c5c05cf38da5e12d70edc5d0fec5c24bce8b6Jim Cromie	&in_min[X].dev_attr.attr,	\
589492e9657d1a790f44ab9b0e03fc72c1d8145f590Jim Cromie	&in_max[X].dev_attr.attr,	\
590492e9657d1a790f44ab9b0e03fc72c1d8145f590Jim Cromie	&in_min_alarm[X].dev_attr.attr,	\
591492e9657d1a790f44ab9b0e03fc72c1d8145f590Jim Cromie	&in_max_alarm[X].dev_attr.attr
592941c5c05cf38da5e12d70edc5d0fec5c24bce8b6Jim Cromie
593449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeckstatic ssize_t show_vid(struct device *dev, struct device_attribute *attr,
594449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck			char *buf)
59544646c19b41e40d81f5e4863466914e8ce060cc0Jim Cromie{
59644646c19b41e40d81f5e4863466914e8ce060cc0Jim Cromie	struct pc87360_data *data = pc87360_update_device(dev);
59744646c19b41e40d81f5e4863466914e8ce060cc0Jim Cromie	return sprintf(buf, "%u\n", vid_from_reg(data->vid, data->vrm));
59844646c19b41e40d81f5e4863466914e8ce060cc0Jim Cromie}
59944646c19b41e40d81f5e4863466914e8ce060cc0Jim Cromiestatic DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid, NULL);
60044646c19b41e40d81f5e4863466914e8ce060cc0Jim Cromie
601449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeckstatic ssize_t show_vrm(struct device *dev, struct device_attribute *attr,
602449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck			char *buf)
60344646c19b41e40d81f5e4863466914e8ce060cc0Jim Cromie{
60490d6619a916062cb75a176aacb318d108758b4a5Jean Delvare	struct pc87360_data *data = dev_get_drvdata(dev);
60544646c19b41e40d81f5e4863466914e8ce060cc0Jim Cromie	return sprintf(buf, "%u\n", data->vrm);
60644646c19b41e40d81f5e4863466914e8ce060cc0Jim Cromie}
607449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeckstatic ssize_t set_vrm(struct device *dev, struct device_attribute *attr,
608449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck		       const char *buf, size_t count)
60944646c19b41e40d81f5e4863466914e8ce060cc0Jim Cromie{
610f641b588fdfd25e73c73f6e4977cd2daf8a5e363Jean Delvare	struct pc87360_data *data = dev_get_drvdata(dev);
611449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck	unsigned long val;
612449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck	int err;
613449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck
614449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck	err = kstrtoul(buf, 10, &val);
615449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck	if (err)
616449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck		return err;
617449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck
618449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck	data->vrm = val;
61944646c19b41e40d81f5e4863466914e8ce060cc0Jim Cromie	return count;
62044646c19b41e40d81f5e4863466914e8ce060cc0Jim Cromie}
62144646c19b41e40d81f5e4863466914e8ce060cc0Jim Cromiestatic DEVICE_ATTR(vrm, S_IRUGO | S_IWUSR, show_vrm, set_vrm);
62244646c19b41e40d81f5e4863466914e8ce060cc0Jim Cromie
623449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeckstatic ssize_t show_in_alarms(struct device *dev,
624449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck			      struct device_attribute *attr, char *buf)
62544646c19b41e40d81f5e4863466914e8ce060cc0Jim Cromie{
62644646c19b41e40d81f5e4863466914e8ce060cc0Jim Cromie	struct pc87360_data *data = pc87360_update_device(dev);
62744646c19b41e40d81f5e4863466914e8ce060cc0Jim Cromie	return sprintf(buf, "%u\n", data->in_alarms);
62844646c19b41e40d81f5e4863466914e8ce060cc0Jim Cromie}
62944646c19b41e40d81f5e4863466914e8ce060cc0Jim Cromiestatic DEVICE_ATTR(alarms_in, S_IRUGO, show_in_alarms, NULL);
63044646c19b41e40d81f5e4863466914e8ce060cc0Jim Cromie
631941c5c05cf38da5e12d70edc5d0fec5c24bce8b6Jim Cromiestatic struct attribute *pc8736x_vin_attr_array[] = {
632941c5c05cf38da5e12d70edc5d0fec5c24bce8b6Jim Cromie	VIN_UNIT_ATTRS(0),
633941c5c05cf38da5e12d70edc5d0fec5c24bce8b6Jim Cromie	VIN_UNIT_ATTRS(1),
634941c5c05cf38da5e12d70edc5d0fec5c24bce8b6Jim Cromie	VIN_UNIT_ATTRS(2),
635941c5c05cf38da5e12d70edc5d0fec5c24bce8b6Jim Cromie	VIN_UNIT_ATTRS(3),
636941c5c05cf38da5e12d70edc5d0fec5c24bce8b6Jim Cromie	VIN_UNIT_ATTRS(4),
637941c5c05cf38da5e12d70edc5d0fec5c24bce8b6Jim Cromie	VIN_UNIT_ATTRS(5),
638941c5c05cf38da5e12d70edc5d0fec5c24bce8b6Jim Cromie	VIN_UNIT_ATTRS(6),
639941c5c05cf38da5e12d70edc5d0fec5c24bce8b6Jim Cromie	VIN_UNIT_ATTRS(7),
640941c5c05cf38da5e12d70edc5d0fec5c24bce8b6Jim Cromie	VIN_UNIT_ATTRS(8),
641941c5c05cf38da5e12d70edc5d0fec5c24bce8b6Jim Cromie	VIN_UNIT_ATTRS(9),
642941c5c05cf38da5e12d70edc5d0fec5c24bce8b6Jim Cromie	VIN_UNIT_ATTRS(10),
643941c5c05cf38da5e12d70edc5d0fec5c24bce8b6Jim Cromie	&dev_attr_cpu0_vid.attr,
644941c5c05cf38da5e12d70edc5d0fec5c24bce8b6Jim Cromie	&dev_attr_vrm.attr,
645941c5c05cf38da5e12d70edc5d0fec5c24bce8b6Jim Cromie	&dev_attr_alarms_in.attr,
646941c5c05cf38da5e12d70edc5d0fec5c24bce8b6Jim Cromie	NULL
647941c5c05cf38da5e12d70edc5d0fec5c24bce8b6Jim Cromie};
648941c5c05cf38da5e12d70edc5d0fec5c24bce8b6Jim Cromiestatic const struct attribute_group pc8736x_vin_group = {
649941c5c05cf38da5e12d70edc5d0fec5c24bce8b6Jim Cromie	.attrs = pc8736x_vin_attr_array,
650941c5c05cf38da5e12d70edc5d0fec5c24bce8b6Jim Cromie};
651941c5c05cf38da5e12d70edc5d0fec5c24bce8b6Jim Cromie
652449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeckstatic ssize_t show_therm_input(struct device *dev,
653449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck				struct device_attribute *devattr, char *buf)
654f0986bd8f390392948db85dac526fb238752372bJim Cromie{
655f0986bd8f390392948db85dac526fb238752372bJim Cromie	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
656f0986bd8f390392948db85dac526fb238752372bJim Cromie	struct pc87360_data *data = pc87360_update_device(dev);
657694fa056a60828ef54a5db958468cc600c3b3622Jim Cromie	return sprintf(buf, "%u\n", IN_FROM_REG(data->in[attr->index],
658f0986bd8f390392948db85dac526fb238752372bJim Cromie		       data->in_vref));
659f0986bd8f390392948db85dac526fb238752372bJim Cromie}
660449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeckstatic ssize_t show_therm_min(struct device *dev,
661449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck			      struct device_attribute *devattr, char *buf)
662f0986bd8f390392948db85dac526fb238752372bJim Cromie{
663f0986bd8f390392948db85dac526fb238752372bJim Cromie	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
664f0986bd8f390392948db85dac526fb238752372bJim Cromie	struct pc87360_data *data = pc87360_update_device(dev);
665694fa056a60828ef54a5db958468cc600c3b3622Jim Cromie	return sprintf(buf, "%u\n", IN_FROM_REG(data->in_min[attr->index],
666f0986bd8f390392948db85dac526fb238752372bJim Cromie		       data->in_vref));
667f0986bd8f390392948db85dac526fb238752372bJim Cromie}
668449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeckstatic ssize_t show_therm_max(struct device *dev,
669449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck			      struct device_attribute *devattr, char *buf)
670f0986bd8f390392948db85dac526fb238752372bJim Cromie{
671f0986bd8f390392948db85dac526fb238752372bJim Cromie	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
672f0986bd8f390392948db85dac526fb238752372bJim Cromie	struct pc87360_data *data = pc87360_update_device(dev);
673694fa056a60828ef54a5db958468cc600c3b3622Jim Cromie	return sprintf(buf, "%u\n", IN_FROM_REG(data->in_max[attr->index],
674f0986bd8f390392948db85dac526fb238752372bJim Cromie		       data->in_vref));
675f0986bd8f390392948db85dac526fb238752372bJim Cromie}
676449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeckstatic ssize_t show_therm_crit(struct device *dev,
677449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck			       struct device_attribute *devattr, char *buf)
678f0986bd8f390392948db85dac526fb238752372bJim Cromie{
679f0986bd8f390392948db85dac526fb238752372bJim Cromie	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
680f0986bd8f390392948db85dac526fb238752372bJim Cromie	struct pc87360_data *data = pc87360_update_device(dev);
681694fa056a60828ef54a5db958468cc600c3b3622Jim Cromie	return sprintf(buf, "%u\n", IN_FROM_REG(data->in_crit[attr->index-11],
682f0986bd8f390392948db85dac526fb238752372bJim Cromie		       data->in_vref));
683f0986bd8f390392948db85dac526fb238752372bJim Cromie}
684449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeckstatic ssize_t show_therm_status(struct device *dev,
685449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck				 struct device_attribute *devattr, char *buf)
686f0986bd8f390392948db85dac526fb238752372bJim Cromie{
687f0986bd8f390392948db85dac526fb238752372bJim Cromie	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
688f0986bd8f390392948db85dac526fb238752372bJim Cromie	struct pc87360_data *data = pc87360_update_device(dev);
689694fa056a60828ef54a5db958468cc600c3b3622Jim Cromie	return sprintf(buf, "%u\n", data->in_status[attr->index]);
690f0986bd8f390392948db85dac526fb238752372bJim Cromie}
691449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck
692449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeckstatic ssize_t set_therm_min(struct device *dev,
693449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck			     struct device_attribute *devattr,
694449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck			     const char *buf, size_t count)
695f0986bd8f390392948db85dac526fb238752372bJim Cromie{
696f0986bd8f390392948db85dac526fb238752372bJim Cromie	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
697f641b588fdfd25e73c73f6e4977cd2daf8a5e363Jean Delvare	struct pc87360_data *data = dev_get_drvdata(dev);
698449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck	long val;
699449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck	int err;
700449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck
701449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck	err = kstrtol(buf, 10, &val);
702449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck	if (err)
703449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck		return err;
704f0986bd8f390392948db85dac526fb238752372bJim Cromie
7059a61bf6300533d3b64d7ff29adfec00e596de67dIngo Molnar	mutex_lock(&data->update_lock);
706694fa056a60828ef54a5db958468cc600c3b3622Jim Cromie	data->in_min[attr->index] = IN_TO_REG(val, data->in_vref);
707694fa056a60828ef54a5db958468cc600c3b3622Jim Cromie	pc87360_write_value(data, LD_IN, attr->index, PC87365_REG_TEMP_MIN,
708694fa056a60828ef54a5db958468cc600c3b3622Jim Cromie			    data->in_min[attr->index]);
7099a61bf6300533d3b64d7ff29adfec00e596de67dIngo Molnar	mutex_unlock(&data->update_lock);
710f0986bd8f390392948db85dac526fb238752372bJim Cromie	return count;
711f0986bd8f390392948db85dac526fb238752372bJim Cromie}
712449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck
713449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeckstatic ssize_t set_therm_max(struct device *dev,
714449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck			     struct device_attribute *devattr,
715449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck			     const char *buf, size_t count)
716f0986bd8f390392948db85dac526fb238752372bJim Cromie{
717f0986bd8f390392948db85dac526fb238752372bJim Cromie	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
718f641b588fdfd25e73c73f6e4977cd2daf8a5e363Jean Delvare	struct pc87360_data *data = dev_get_drvdata(dev);
719449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck	long val;
720449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck	int err;
721449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck
722449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck	err = kstrtol(buf, 10, &val);
723449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck	if (err)
724449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck		return err;
725f0986bd8f390392948db85dac526fb238752372bJim Cromie
7269a61bf6300533d3b64d7ff29adfec00e596de67dIngo Molnar	mutex_lock(&data->update_lock);
727694fa056a60828ef54a5db958468cc600c3b3622Jim Cromie	data->in_max[attr->index] = IN_TO_REG(val, data->in_vref);
728694fa056a60828ef54a5db958468cc600c3b3622Jim Cromie	pc87360_write_value(data, LD_IN, attr->index, PC87365_REG_TEMP_MAX,
729694fa056a60828ef54a5db958468cc600c3b3622Jim Cromie			    data->in_max[attr->index]);
7309a61bf6300533d3b64d7ff29adfec00e596de67dIngo Molnar	mutex_unlock(&data->update_lock);
731f0986bd8f390392948db85dac526fb238752372bJim Cromie	return count;
732f0986bd8f390392948db85dac526fb238752372bJim Cromie}
733449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeckstatic ssize_t set_therm_crit(struct device *dev,
734449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck			      struct device_attribute *devattr,
735449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck			      const char *buf, size_t count)
736f0986bd8f390392948db85dac526fb238752372bJim Cromie{
737f0986bd8f390392948db85dac526fb238752372bJim Cromie	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
738f641b588fdfd25e73c73f6e4977cd2daf8a5e363Jean Delvare	struct pc87360_data *data = dev_get_drvdata(dev);
739449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck	long val;
740449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck	int err;
741449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck
742449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck	err = kstrtol(buf, 10, &val);
743449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck	if (err)
744449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck		return err;
745f0986bd8f390392948db85dac526fb238752372bJim Cromie
7469a61bf6300533d3b64d7ff29adfec00e596de67dIngo Molnar	mutex_lock(&data->update_lock);
747694fa056a60828ef54a5db958468cc600c3b3622Jim Cromie	data->in_crit[attr->index-11] = IN_TO_REG(val, data->in_vref);
748694fa056a60828ef54a5db958468cc600c3b3622Jim Cromie	pc87360_write_value(data, LD_IN, attr->index, PC87365_REG_TEMP_CRIT,
749694fa056a60828ef54a5db958468cc600c3b3622Jim Cromie			    data->in_crit[attr->index-11]);
7509a61bf6300533d3b64d7ff29adfec00e596de67dIngo Molnar	mutex_unlock(&data->update_lock);
751f0986bd8f390392948db85dac526fb238752372bJim Cromie	return count;
752f0986bd8f390392948db85dac526fb238752372bJim Cromie}
753f0986bd8f390392948db85dac526fb238752372bJim Cromie
7543af2861e8b80676d32c5498f9ac1b2de70d3e19bGuenter Roeck/*
7553af2861e8b80676d32c5498f9ac1b2de70d3e19bGuenter Roeck * the +11 term below reflects the fact that VLM units 11,12,13 are
7563af2861e8b80676d32c5498f9ac1b2de70d3e19bGuenter Roeck * used in the chip to measure voltage across the thermistors
7573af2861e8b80676d32c5498f9ac1b2de70d3e19bGuenter Roeck */
758dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromiestatic struct sensor_device_attribute therm_input[] = {
759449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck	SENSOR_ATTR(temp4_input, S_IRUGO, show_therm_input, NULL, 0 + 11),
760449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck	SENSOR_ATTR(temp5_input, S_IRUGO, show_therm_input, NULL, 1 + 11),
761449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck	SENSOR_ATTR(temp6_input, S_IRUGO, show_therm_input, NULL, 2 + 11),
762dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromie};
763dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromiestatic struct sensor_device_attribute therm_status[] = {
764449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck	SENSOR_ATTR(temp4_status, S_IRUGO, show_therm_status, NULL, 0 + 11),
765449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck	SENSOR_ATTR(temp5_status, S_IRUGO, show_therm_status, NULL, 1 + 11),
766449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck	SENSOR_ATTR(temp6_status, S_IRUGO, show_therm_status, NULL, 2 + 11),
767dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromie};
768dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromiestatic struct sensor_device_attribute therm_min[] = {
769dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromie	SENSOR_ATTR(temp4_min, S_IRUGO | S_IWUSR,
770449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck		    show_therm_min, set_therm_min, 0 + 11),
771dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromie	SENSOR_ATTR(temp5_min, S_IRUGO | S_IWUSR,
772449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck		    show_therm_min, set_therm_min, 1 + 11),
773dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromie	SENSOR_ATTR(temp6_min, S_IRUGO | S_IWUSR,
774449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck		    show_therm_min, set_therm_min, 2 + 11),
775dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromie};
776dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromiestatic struct sensor_device_attribute therm_max[] = {
777dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromie	SENSOR_ATTR(temp4_max, S_IRUGO | S_IWUSR,
778449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck		    show_therm_max, set_therm_max, 0 + 11),
779dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromie	SENSOR_ATTR(temp5_max, S_IRUGO | S_IWUSR,
780449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck		    show_therm_max, set_therm_max, 1 + 11),
781dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromie	SENSOR_ATTR(temp6_max, S_IRUGO | S_IWUSR,
782449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck		    show_therm_max, set_therm_max, 2 + 11),
783dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromie};
784dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromiestatic struct sensor_device_attribute therm_crit[] = {
785dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromie	SENSOR_ATTR(temp4_crit, S_IRUGO | S_IWUSR,
786449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck		    show_therm_crit, set_therm_crit, 0 + 11),
787dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromie	SENSOR_ATTR(temp5_crit, S_IRUGO | S_IWUSR,
788449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck		    show_therm_crit, set_therm_crit, 1 + 11),
789dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromie	SENSOR_ATTR(temp6_crit, S_IRUGO | S_IWUSR,
790449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck		    show_therm_crit, set_therm_crit, 2 + 11),
791dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromie};
7921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7933af2861e8b80676d32c5498f9ac1b2de70d3e19bGuenter Roeck/*
7943af2861e8b80676d32c5498f9ac1b2de70d3e19bGuenter Roeck * show_therm_min/max_alarm() reads data from the per-channel voltage
7953af2861e8b80676d32c5498f9ac1b2de70d3e19bGuenter Roeck * status register (sec 11.5.12)
7963af2861e8b80676d32c5498f9ac1b2de70d3e19bGuenter Roeck */
797865c295360f61c2f3634fb1387b4468fdc8287daJim Cromie
798865c295360f61c2f3634fb1387b4468fdc8287daJim Cromiestatic ssize_t show_therm_min_alarm(struct device *dev,
799865c295360f61c2f3634fb1387b4468fdc8287daJim Cromie				struct device_attribute *devattr, char *buf)
800865c295360f61c2f3634fb1387b4468fdc8287daJim Cromie{
801865c295360f61c2f3634fb1387b4468fdc8287daJim Cromie	struct pc87360_data *data = pc87360_update_device(dev);
802865c295360f61c2f3634fb1387b4468fdc8287daJim Cromie	unsigned nr = to_sensor_dev_attr(devattr)->index;
803865c295360f61c2f3634fb1387b4468fdc8287daJim Cromie
804865c295360f61c2f3634fb1387b4468fdc8287daJim Cromie	return sprintf(buf, "%u\n", !!(data->in_status[nr] & CHAN_ALM_MIN));
805865c295360f61c2f3634fb1387b4468fdc8287daJim Cromie}
806865c295360f61c2f3634fb1387b4468fdc8287daJim Cromiestatic ssize_t show_therm_max_alarm(struct device *dev,
807865c295360f61c2f3634fb1387b4468fdc8287daJim Cromie				struct device_attribute *devattr, char *buf)
808865c295360f61c2f3634fb1387b4468fdc8287daJim Cromie{
809865c295360f61c2f3634fb1387b4468fdc8287daJim Cromie	struct pc87360_data *data = pc87360_update_device(dev);
810865c295360f61c2f3634fb1387b4468fdc8287daJim Cromie	unsigned nr = to_sensor_dev_attr(devattr)->index;
811865c295360f61c2f3634fb1387b4468fdc8287daJim Cromie
812865c295360f61c2f3634fb1387b4468fdc8287daJim Cromie	return sprintf(buf, "%u\n", !!(data->in_status[nr] & CHAN_ALM_MAX));
813865c295360f61c2f3634fb1387b4468fdc8287daJim Cromie}
814865c295360f61c2f3634fb1387b4468fdc8287daJim Cromiestatic ssize_t show_therm_crit_alarm(struct device *dev,
815865c295360f61c2f3634fb1387b4468fdc8287daJim Cromie				struct device_attribute *devattr, char *buf)
816865c295360f61c2f3634fb1387b4468fdc8287daJim Cromie{
817865c295360f61c2f3634fb1387b4468fdc8287daJim Cromie	struct pc87360_data *data = pc87360_update_device(dev);
818865c295360f61c2f3634fb1387b4468fdc8287daJim Cromie	unsigned nr = to_sensor_dev_attr(devattr)->index;
819865c295360f61c2f3634fb1387b4468fdc8287daJim Cromie
820865c295360f61c2f3634fb1387b4468fdc8287daJim Cromie	return sprintf(buf, "%u\n", !!(data->in_status[nr] & TEMP_ALM_CRIT));
821865c295360f61c2f3634fb1387b4468fdc8287daJim Cromie}
822865c295360f61c2f3634fb1387b4468fdc8287daJim Cromie
823865c295360f61c2f3634fb1387b4468fdc8287daJim Cromiestatic struct sensor_device_attribute therm_min_alarm[] = {
824865c295360f61c2f3634fb1387b4468fdc8287daJim Cromie	SENSOR_ATTR(temp4_min_alarm, S_IRUGO,
825449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck		    show_therm_min_alarm, NULL, 0 + 11),
826865c295360f61c2f3634fb1387b4468fdc8287daJim Cromie	SENSOR_ATTR(temp5_min_alarm, S_IRUGO,
827449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck		    show_therm_min_alarm, NULL, 1 + 11),
828865c295360f61c2f3634fb1387b4468fdc8287daJim Cromie	SENSOR_ATTR(temp6_min_alarm, S_IRUGO,
829449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck		    show_therm_min_alarm, NULL, 2 + 11),
830865c295360f61c2f3634fb1387b4468fdc8287daJim Cromie};
831865c295360f61c2f3634fb1387b4468fdc8287daJim Cromiestatic struct sensor_device_attribute therm_max_alarm[] = {
832865c295360f61c2f3634fb1387b4468fdc8287daJim Cromie	SENSOR_ATTR(temp4_max_alarm, S_IRUGO,
833449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck		    show_therm_max_alarm, NULL, 0 + 11),
834865c295360f61c2f3634fb1387b4468fdc8287daJim Cromie	SENSOR_ATTR(temp5_max_alarm, S_IRUGO,
835449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck		    show_therm_max_alarm, NULL, 1 + 11),
836865c295360f61c2f3634fb1387b4468fdc8287daJim Cromie	SENSOR_ATTR(temp6_max_alarm, S_IRUGO,
837449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck		    show_therm_max_alarm, NULL, 2 + 11),
838865c295360f61c2f3634fb1387b4468fdc8287daJim Cromie};
839865c295360f61c2f3634fb1387b4468fdc8287daJim Cromiestatic struct sensor_device_attribute therm_crit_alarm[] = {
840865c295360f61c2f3634fb1387b4468fdc8287daJim Cromie	SENSOR_ATTR(temp4_crit_alarm, S_IRUGO,
841449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck		    show_therm_crit_alarm, NULL, 0 + 11),
842865c295360f61c2f3634fb1387b4468fdc8287daJim Cromie	SENSOR_ATTR(temp5_crit_alarm, S_IRUGO,
843449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck		    show_therm_crit_alarm, NULL, 1 + 11),
844865c295360f61c2f3634fb1387b4468fdc8287daJim Cromie	SENSOR_ATTR(temp6_crit_alarm, S_IRUGO,
845449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck		    show_therm_crit_alarm, NULL, 2 + 11),
846865c295360f61c2f3634fb1387b4468fdc8287daJim Cromie};
847865c295360f61c2f3634fb1387b4468fdc8287daJim Cromie
848941c5c05cf38da5e12d70edc5d0fec5c24bce8b6Jim Cromie#define THERM_UNIT_ATTRS(X) \
849941c5c05cf38da5e12d70edc5d0fec5c24bce8b6Jim Cromie	&therm_input[X].dev_attr.attr,	\
850941c5c05cf38da5e12d70edc5d0fec5c24bce8b6Jim Cromie	&therm_status[X].dev_attr.attr,	\
851941c5c05cf38da5e12d70edc5d0fec5c24bce8b6Jim Cromie	&therm_min[X].dev_attr.attr,	\
852941c5c05cf38da5e12d70edc5d0fec5c24bce8b6Jim Cromie	&therm_max[X].dev_attr.attr,	\
853865c295360f61c2f3634fb1387b4468fdc8287daJim Cromie	&therm_crit[X].dev_attr.attr,	\
854865c295360f61c2f3634fb1387b4468fdc8287daJim Cromie	&therm_min_alarm[X].dev_attr.attr, \
855865c295360f61c2f3634fb1387b4468fdc8287daJim Cromie	&therm_max_alarm[X].dev_attr.attr, \
856865c295360f61c2f3634fb1387b4468fdc8287daJim Cromie	&therm_crit_alarm[X].dev_attr.attr
857941c5c05cf38da5e12d70edc5d0fec5c24bce8b6Jim Cromie
858449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeckstatic struct attribute *pc8736x_therm_attr_array[] = {
859941c5c05cf38da5e12d70edc5d0fec5c24bce8b6Jim Cromie	THERM_UNIT_ATTRS(0),
860941c5c05cf38da5e12d70edc5d0fec5c24bce8b6Jim Cromie	THERM_UNIT_ATTRS(1),
861941c5c05cf38da5e12d70edc5d0fec5c24bce8b6Jim Cromie	THERM_UNIT_ATTRS(2),
862941c5c05cf38da5e12d70edc5d0fec5c24bce8b6Jim Cromie	NULL
863941c5c05cf38da5e12d70edc5d0fec5c24bce8b6Jim Cromie};
864941c5c05cf38da5e12d70edc5d0fec5c24bce8b6Jim Cromiestatic const struct attribute_group pc8736x_therm_group = {
865941c5c05cf38da5e12d70edc5d0fec5c24bce8b6Jim Cromie	.attrs = pc8736x_therm_attr_array,
866941c5c05cf38da5e12d70edc5d0fec5c24bce8b6Jim Cromie};
867941c5c05cf38da5e12d70edc5d0fec5c24bce8b6Jim Cromie
868449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeckstatic ssize_t show_temp_input(struct device *dev,
869449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck			       struct device_attribute *devattr, char *buf)
870f0986bd8f390392948db85dac526fb238752372bJim Cromie{
871f0986bd8f390392948db85dac526fb238752372bJim Cromie	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
872f0986bd8f390392948db85dac526fb238752372bJim Cromie	struct pc87360_data *data = pc87360_update_device(dev);
873694fa056a60828ef54a5db958468cc600c3b3622Jim Cromie	return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp[attr->index]));
874f0986bd8f390392948db85dac526fb238752372bJim Cromie}
875449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck
876449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeckstatic ssize_t show_temp_min(struct device *dev,
877449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck			     struct device_attribute *devattr, char *buf)
878f0986bd8f390392948db85dac526fb238752372bJim Cromie{
879f0986bd8f390392948db85dac526fb238752372bJim Cromie	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
880f0986bd8f390392948db85dac526fb238752372bJim Cromie	struct pc87360_data *data = pc87360_update_device(dev);
881694fa056a60828ef54a5db958468cc600c3b3622Jim Cromie	return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_min[attr->index]));
882f0986bd8f390392948db85dac526fb238752372bJim Cromie}
883449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck
884449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeckstatic ssize_t show_temp_max(struct device *dev,
885449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck			     struct device_attribute *devattr, char *buf)
886f0986bd8f390392948db85dac526fb238752372bJim Cromie{
887f0986bd8f390392948db85dac526fb238752372bJim Cromie	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
888f0986bd8f390392948db85dac526fb238752372bJim Cromie	struct pc87360_data *data = pc87360_update_device(dev);
889694fa056a60828ef54a5db958468cc600c3b3622Jim Cromie	return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_max[attr->index]));
890f0986bd8f390392948db85dac526fb238752372bJim Cromie}
891449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck
892449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeckstatic ssize_t show_temp_crit(struct device *dev,
893449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck			      struct device_attribute *devattr, char *buf)
894f0986bd8f390392948db85dac526fb238752372bJim Cromie{
895f0986bd8f390392948db85dac526fb238752372bJim Cromie	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
896f0986bd8f390392948db85dac526fb238752372bJim Cromie	struct pc87360_data *data = pc87360_update_device(dev);
897449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck	return sprintf(buf, "%d\n",
898449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck		       TEMP_FROM_REG(data->temp_crit[attr->index]));
899f0986bd8f390392948db85dac526fb238752372bJim Cromie}
900449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck
901449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeckstatic ssize_t show_temp_status(struct device *dev,
902449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck				struct device_attribute *devattr, char *buf)
903f0986bd8f390392948db85dac526fb238752372bJim Cromie{
904f0986bd8f390392948db85dac526fb238752372bJim Cromie	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
905f0986bd8f390392948db85dac526fb238752372bJim Cromie	struct pc87360_data *data = pc87360_update_device(dev);
906694fa056a60828ef54a5db958468cc600c3b3622Jim Cromie	return sprintf(buf, "%d\n", data->temp_status[attr->index]);
907f0986bd8f390392948db85dac526fb238752372bJim Cromie}
908449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck
909449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeckstatic ssize_t set_temp_min(struct device *dev,
910449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck			    struct device_attribute *devattr,
911449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck			    const char *buf, size_t count)
912f0986bd8f390392948db85dac526fb238752372bJim Cromie{
913f0986bd8f390392948db85dac526fb238752372bJim Cromie	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
914f641b588fdfd25e73c73f6e4977cd2daf8a5e363Jean Delvare	struct pc87360_data *data = dev_get_drvdata(dev);
915449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck	long val;
916449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck	int err;
917449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck
918449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck	err = kstrtol(buf, 10, &val);
919449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck	if (err)
920449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck		return err;
921f0986bd8f390392948db85dac526fb238752372bJim Cromie
9229a61bf6300533d3b64d7ff29adfec00e596de67dIngo Molnar	mutex_lock(&data->update_lock);
923694fa056a60828ef54a5db958468cc600c3b3622Jim Cromie	data->temp_min[attr->index] = TEMP_TO_REG(val);
924694fa056a60828ef54a5db958468cc600c3b3622Jim Cromie	pc87360_write_value(data, LD_TEMP, attr->index, PC87365_REG_TEMP_MIN,
925694fa056a60828ef54a5db958468cc600c3b3622Jim Cromie			    data->temp_min[attr->index]);
9269a61bf6300533d3b64d7ff29adfec00e596de67dIngo Molnar	mutex_unlock(&data->update_lock);
927f0986bd8f390392948db85dac526fb238752372bJim Cromie	return count;
928f0986bd8f390392948db85dac526fb238752372bJim Cromie}
929449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck
930449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeckstatic ssize_t set_temp_max(struct device *dev,
931449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck			    struct device_attribute *devattr,
932449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck			    const char *buf, size_t count)
933f0986bd8f390392948db85dac526fb238752372bJim Cromie{
934f0986bd8f390392948db85dac526fb238752372bJim Cromie	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
935f641b588fdfd25e73c73f6e4977cd2daf8a5e363Jean Delvare	struct pc87360_data *data = dev_get_drvdata(dev);
936449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck	long val;
937449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck	int err;
938449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck
939449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck	err = kstrtol(buf, 10, &val);
940449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck	if (err)
941449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck		return err;
942f0986bd8f390392948db85dac526fb238752372bJim Cromie
9439a61bf6300533d3b64d7ff29adfec00e596de67dIngo Molnar	mutex_lock(&data->update_lock);
944694fa056a60828ef54a5db958468cc600c3b3622Jim Cromie	data->temp_max[attr->index] = TEMP_TO_REG(val);
945694fa056a60828ef54a5db958468cc600c3b3622Jim Cromie	pc87360_write_value(data, LD_TEMP, attr->index, PC87365_REG_TEMP_MAX,
946694fa056a60828ef54a5db958468cc600c3b3622Jim Cromie			    data->temp_max[attr->index]);
9479a61bf6300533d3b64d7ff29adfec00e596de67dIngo Molnar	mutex_unlock(&data->update_lock);
948f0986bd8f390392948db85dac526fb238752372bJim Cromie	return count;
949f0986bd8f390392948db85dac526fb238752372bJim Cromie}
950449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck
951449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeckstatic ssize_t set_temp_crit(struct device *dev,
952449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck			     struct device_attribute *devattr, const char *buf,
953449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck			     size_t count)
954f0986bd8f390392948db85dac526fb238752372bJim Cromie{
955f0986bd8f390392948db85dac526fb238752372bJim Cromie	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
956f641b588fdfd25e73c73f6e4977cd2daf8a5e363Jean Delvare	struct pc87360_data *data = dev_get_drvdata(dev);
957449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck	long val;
958449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck	int err;
959449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck
960449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck	err = kstrtol(buf, 10, &val);
961449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck	if (err)
962449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck		return err;
963f0986bd8f390392948db85dac526fb238752372bJim Cromie
9649a61bf6300533d3b64d7ff29adfec00e596de67dIngo Molnar	mutex_lock(&data->update_lock);
965694fa056a60828ef54a5db958468cc600c3b3622Jim Cromie	data->temp_crit[attr->index] = TEMP_TO_REG(val);
966694fa056a60828ef54a5db958468cc600c3b3622Jim Cromie	pc87360_write_value(data, LD_TEMP, attr->index, PC87365_REG_TEMP_CRIT,
967694fa056a60828ef54a5db958468cc600c3b3622Jim Cromie			    data->temp_crit[attr->index]);
9689a61bf6300533d3b64d7ff29adfec00e596de67dIngo Molnar	mutex_unlock(&data->update_lock);
969f0986bd8f390392948db85dac526fb238752372bJim Cromie	return count;
970f0986bd8f390392948db85dac526fb238752372bJim Cromie}
971f0986bd8f390392948db85dac526fb238752372bJim Cromie
972dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromiestatic struct sensor_device_attribute temp_input[] = {
973dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromie	SENSOR_ATTR(temp1_input, S_IRUGO, show_temp_input, NULL, 0),
974dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromie	SENSOR_ATTR(temp2_input, S_IRUGO, show_temp_input, NULL, 1),
975dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromie	SENSOR_ATTR(temp3_input, S_IRUGO, show_temp_input, NULL, 2),
976dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromie};
977dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromiestatic struct sensor_device_attribute temp_status[] = {
978dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromie	SENSOR_ATTR(temp1_status, S_IRUGO, show_temp_status, NULL, 0),
979dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromie	SENSOR_ATTR(temp2_status, S_IRUGO, show_temp_status, NULL, 1),
980dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromie	SENSOR_ATTR(temp3_status, S_IRUGO, show_temp_status, NULL, 2),
981dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromie};
982dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromiestatic struct sensor_device_attribute temp_min[] = {
983dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromie	SENSOR_ATTR(temp1_min, S_IRUGO | S_IWUSR,
984dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromie		    show_temp_min, set_temp_min, 0),
985dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromie	SENSOR_ATTR(temp2_min, S_IRUGO | S_IWUSR,
986dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromie		    show_temp_min, set_temp_min, 1),
987dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromie	SENSOR_ATTR(temp3_min, S_IRUGO | S_IWUSR,
988dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromie		    show_temp_min, set_temp_min, 2),
989dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromie};
990dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromiestatic struct sensor_device_attribute temp_max[] = {
991dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromie	SENSOR_ATTR(temp1_max, S_IRUGO | S_IWUSR,
992dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromie		    show_temp_max, set_temp_max, 0),
993dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromie	SENSOR_ATTR(temp2_max, S_IRUGO | S_IWUSR,
994dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromie		    show_temp_max, set_temp_max, 1),
995dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromie	SENSOR_ATTR(temp3_max, S_IRUGO | S_IWUSR,
996dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromie		    show_temp_max, set_temp_max, 2),
997dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromie};
998dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromiestatic struct sensor_device_attribute temp_crit[] = {
999dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromie	SENSOR_ATTR(temp1_crit, S_IRUGO | S_IWUSR,
1000dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromie		    show_temp_crit, set_temp_crit, 0),
1001dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromie	SENSOR_ATTR(temp2_crit, S_IRUGO | S_IWUSR,
1002dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromie		    show_temp_crit, set_temp_crit, 1),
1003dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromie	SENSOR_ATTR(temp3_crit, S_IRUGO | S_IWUSR,
1004dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromie		    show_temp_crit, set_temp_crit, 2),
1005dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromie};
10061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1007449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeckstatic ssize_t show_temp_alarms(struct device *dev,
1008449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck				struct device_attribute *attr, char *buf)
10091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
10101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct pc87360_data *data = pc87360_update_device(dev);
10111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return sprintf(buf, "%u\n", data->temp_alarms);
10121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1013449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck
10141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic DEVICE_ATTR(alarms_temp, S_IRUGO, show_temp_alarms, NULL);
10151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10163af2861e8b80676d32c5498f9ac1b2de70d3e19bGuenter Roeck/*
10173af2861e8b80676d32c5498f9ac1b2de70d3e19bGuenter Roeck * show_temp_min/max_alarm() reads data from the per-channel status
10183af2861e8b80676d32c5498f9ac1b2de70d3e19bGuenter Roeck * register (sec 12.3.7), not the temp event status registers (sec
10193af2861e8b80676d32c5498f9ac1b2de70d3e19bGuenter Roeck * 12.3.2) that show_temp_alarm() reads (via data->temp_alarms)
10203af2861e8b80676d32c5498f9ac1b2de70d3e19bGuenter Roeck */
1021b267e8cdc638dfa53360d532aa56afa0ec12e6a5Jim Cromie
1022b267e8cdc638dfa53360d532aa56afa0ec12e6a5Jim Cromiestatic ssize_t show_temp_min_alarm(struct device *dev,
1023b267e8cdc638dfa53360d532aa56afa0ec12e6a5Jim Cromie			struct device_attribute *devattr, char *buf)
1024b267e8cdc638dfa53360d532aa56afa0ec12e6a5Jim Cromie{
1025b267e8cdc638dfa53360d532aa56afa0ec12e6a5Jim Cromie	struct pc87360_data *data = pc87360_update_device(dev);
1026b267e8cdc638dfa53360d532aa56afa0ec12e6a5Jim Cromie	unsigned nr = to_sensor_dev_attr(devattr)->index;
1027b267e8cdc638dfa53360d532aa56afa0ec12e6a5Jim Cromie
1028b267e8cdc638dfa53360d532aa56afa0ec12e6a5Jim Cromie	return sprintf(buf, "%u\n", !!(data->temp_status[nr] & CHAN_ALM_MIN));
1029b267e8cdc638dfa53360d532aa56afa0ec12e6a5Jim Cromie}
1030449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck
1031b267e8cdc638dfa53360d532aa56afa0ec12e6a5Jim Cromiestatic ssize_t show_temp_max_alarm(struct device *dev,
1032b267e8cdc638dfa53360d532aa56afa0ec12e6a5Jim Cromie			struct device_attribute *devattr, char *buf)
1033b267e8cdc638dfa53360d532aa56afa0ec12e6a5Jim Cromie{
1034b267e8cdc638dfa53360d532aa56afa0ec12e6a5Jim Cromie	struct pc87360_data *data = pc87360_update_device(dev);
1035b267e8cdc638dfa53360d532aa56afa0ec12e6a5Jim Cromie	unsigned nr = to_sensor_dev_attr(devattr)->index;
1036b267e8cdc638dfa53360d532aa56afa0ec12e6a5Jim Cromie
1037b267e8cdc638dfa53360d532aa56afa0ec12e6a5Jim Cromie	return sprintf(buf, "%u\n", !!(data->temp_status[nr] & CHAN_ALM_MAX));
1038b267e8cdc638dfa53360d532aa56afa0ec12e6a5Jim Cromie}
1039449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck
1040b267e8cdc638dfa53360d532aa56afa0ec12e6a5Jim Cromiestatic ssize_t show_temp_crit_alarm(struct device *dev,
1041b267e8cdc638dfa53360d532aa56afa0ec12e6a5Jim Cromie			struct device_attribute *devattr, char *buf)
1042b267e8cdc638dfa53360d532aa56afa0ec12e6a5Jim Cromie{
1043b267e8cdc638dfa53360d532aa56afa0ec12e6a5Jim Cromie	struct pc87360_data *data = pc87360_update_device(dev);
1044b267e8cdc638dfa53360d532aa56afa0ec12e6a5Jim Cromie	unsigned nr = to_sensor_dev_attr(devattr)->index;
1045b267e8cdc638dfa53360d532aa56afa0ec12e6a5Jim Cromie
1046b267e8cdc638dfa53360d532aa56afa0ec12e6a5Jim Cromie	return sprintf(buf, "%u\n", !!(data->temp_status[nr] & TEMP_ALM_CRIT));
1047b267e8cdc638dfa53360d532aa56afa0ec12e6a5Jim Cromie}
1048b267e8cdc638dfa53360d532aa56afa0ec12e6a5Jim Cromie
1049b267e8cdc638dfa53360d532aa56afa0ec12e6a5Jim Cromiestatic struct sensor_device_attribute temp_min_alarm[] = {
1050b267e8cdc638dfa53360d532aa56afa0ec12e6a5Jim Cromie	SENSOR_ATTR(temp1_min_alarm, S_IRUGO, show_temp_min_alarm, NULL, 0),
1051b267e8cdc638dfa53360d532aa56afa0ec12e6a5Jim Cromie	SENSOR_ATTR(temp2_min_alarm, S_IRUGO, show_temp_min_alarm, NULL, 1),
1052b267e8cdc638dfa53360d532aa56afa0ec12e6a5Jim Cromie	SENSOR_ATTR(temp3_min_alarm, S_IRUGO, show_temp_min_alarm, NULL, 2),
1053b267e8cdc638dfa53360d532aa56afa0ec12e6a5Jim Cromie};
1054449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck
1055b267e8cdc638dfa53360d532aa56afa0ec12e6a5Jim Cromiestatic struct sensor_device_attribute temp_max_alarm[] = {
1056b267e8cdc638dfa53360d532aa56afa0ec12e6a5Jim Cromie	SENSOR_ATTR(temp1_max_alarm, S_IRUGO, show_temp_max_alarm, NULL, 0),
1057b267e8cdc638dfa53360d532aa56afa0ec12e6a5Jim Cromie	SENSOR_ATTR(temp2_max_alarm, S_IRUGO, show_temp_max_alarm, NULL, 1),
1058b267e8cdc638dfa53360d532aa56afa0ec12e6a5Jim Cromie	SENSOR_ATTR(temp3_max_alarm, S_IRUGO, show_temp_max_alarm, NULL, 2),
1059b267e8cdc638dfa53360d532aa56afa0ec12e6a5Jim Cromie};
1060449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck
1061b267e8cdc638dfa53360d532aa56afa0ec12e6a5Jim Cromiestatic struct sensor_device_attribute temp_crit_alarm[] = {
1062b267e8cdc638dfa53360d532aa56afa0ec12e6a5Jim Cromie	SENSOR_ATTR(temp1_crit_alarm, S_IRUGO, show_temp_crit_alarm, NULL, 0),
1063b267e8cdc638dfa53360d532aa56afa0ec12e6a5Jim Cromie	SENSOR_ATTR(temp2_crit_alarm, S_IRUGO, show_temp_crit_alarm, NULL, 1),
1064b267e8cdc638dfa53360d532aa56afa0ec12e6a5Jim Cromie	SENSOR_ATTR(temp3_crit_alarm, S_IRUGO, show_temp_crit_alarm, NULL, 2),
1065b267e8cdc638dfa53360d532aa56afa0ec12e6a5Jim Cromie};
1066b267e8cdc638dfa53360d532aa56afa0ec12e6a5Jim Cromie
1067b267e8cdc638dfa53360d532aa56afa0ec12e6a5Jim Cromie#define TEMP_FAULT	0x40	/* open diode */
1068b267e8cdc638dfa53360d532aa56afa0ec12e6a5Jim Cromiestatic ssize_t show_temp_fault(struct device *dev,
1069b267e8cdc638dfa53360d532aa56afa0ec12e6a5Jim Cromie			struct device_attribute *devattr, char *buf)
1070b267e8cdc638dfa53360d532aa56afa0ec12e6a5Jim Cromie{
1071b267e8cdc638dfa53360d532aa56afa0ec12e6a5Jim Cromie	struct pc87360_data *data = pc87360_update_device(dev);
1072b267e8cdc638dfa53360d532aa56afa0ec12e6a5Jim Cromie	unsigned nr = to_sensor_dev_attr(devattr)->index;
1073b267e8cdc638dfa53360d532aa56afa0ec12e6a5Jim Cromie
1074b267e8cdc638dfa53360d532aa56afa0ec12e6a5Jim Cromie	return sprintf(buf, "%u\n", !!(data->temp_status[nr] & TEMP_FAULT));
1075b267e8cdc638dfa53360d532aa56afa0ec12e6a5Jim Cromie}
1076b267e8cdc638dfa53360d532aa56afa0ec12e6a5Jim Cromiestatic struct sensor_device_attribute temp_fault[] = {
1077b267e8cdc638dfa53360d532aa56afa0ec12e6a5Jim Cromie	SENSOR_ATTR(temp1_fault, S_IRUGO, show_temp_fault, NULL, 0),
1078b267e8cdc638dfa53360d532aa56afa0ec12e6a5Jim Cromie	SENSOR_ATTR(temp2_fault, S_IRUGO, show_temp_fault, NULL, 1),
1079b267e8cdc638dfa53360d532aa56afa0ec12e6a5Jim Cromie	SENSOR_ATTR(temp3_fault, S_IRUGO, show_temp_fault, NULL, 2),
1080b267e8cdc638dfa53360d532aa56afa0ec12e6a5Jim Cromie};
1081b267e8cdc638dfa53360d532aa56afa0ec12e6a5Jim Cromie
1082bce2778df9ea32146d59344c027001e270911f4bGuenter Roeck#define TEMP_UNIT_ATTRS(X)			\
1083bce2778df9ea32146d59344c027001e270911f4bGuenter Roeck{	&temp_input[X].dev_attr.attr,		\
1084bce2778df9ea32146d59344c027001e270911f4bGuenter Roeck	&temp_status[X].dev_attr.attr,		\
1085bce2778df9ea32146d59344c027001e270911f4bGuenter Roeck	&temp_min[X].dev_attr.attr,		\
1086bce2778df9ea32146d59344c027001e270911f4bGuenter Roeck	&temp_max[X].dev_attr.attr,		\
1087bce2778df9ea32146d59344c027001e270911f4bGuenter Roeck	&temp_crit[X].dev_attr.attr,		\
1088bce2778df9ea32146d59344c027001e270911f4bGuenter Roeck	&temp_min_alarm[X].dev_attr.attr,	\
1089bce2778df9ea32146d59344c027001e270911f4bGuenter Roeck	&temp_max_alarm[X].dev_attr.attr,	\
1090bce2778df9ea32146d59344c027001e270911f4bGuenter Roeck	&temp_crit_alarm[X].dev_attr.attr,	\
1091bce2778df9ea32146d59344c027001e270911f4bGuenter Roeck	&temp_fault[X].dev_attr.attr,		\
1092bce2778df9ea32146d59344c027001e270911f4bGuenter Roeck	NULL					\
1093bce2778df9ea32146d59344c027001e270911f4bGuenter Roeck}
1094bce2778df9ea32146d59344c027001e270911f4bGuenter Roeck
1095bce2778df9ea32146d59344c027001e270911f4bGuenter Roeckstatic struct attribute *pc8736x_temp_attr[][10] = {
1096941c5c05cf38da5e12d70edc5d0fec5c24bce8b6Jim Cromie	TEMP_UNIT_ATTRS(0),
1097941c5c05cf38da5e12d70edc5d0fec5c24bce8b6Jim Cromie	TEMP_UNIT_ATTRS(1),
1098bce2778df9ea32146d59344c027001e270911f4bGuenter Roeck	TEMP_UNIT_ATTRS(2)
1099941c5c05cf38da5e12d70edc5d0fec5c24bce8b6Jim Cromie};
1100449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck
1101bce2778df9ea32146d59344c027001e270911f4bGuenter Roeckstatic const struct attribute_group pc8736x_temp_attr_group[] = {
1102bce2778df9ea32146d59344c027001e270911f4bGuenter Roeck	{ .attrs = pc8736x_temp_attr[0] },
1103bce2778df9ea32146d59344c027001e270911f4bGuenter Roeck	{ .attrs = pc8736x_temp_attr[1] },
1104bce2778df9ea32146d59344c027001e270911f4bGuenter Roeck	{ .attrs = pc8736x_temp_attr[2] }
1105941c5c05cf38da5e12d70edc5d0fec5c24bce8b6Jim Cromie};
1106941c5c05cf38da5e12d70edc5d0fec5c24bce8b6Jim Cromie
1107b267e8cdc638dfa53360d532aa56afa0ec12e6a5Jim Cromiestatic ssize_t show_name(struct device *dev,
1108b267e8cdc638dfa53360d532aa56afa0ec12e6a5Jim Cromie			struct device_attribute *devattr, char *buf)
1109f641b588fdfd25e73c73f6e4977cd2daf8a5e363Jean Delvare{
1110f641b588fdfd25e73c73f6e4977cd2daf8a5e363Jean Delvare	struct pc87360_data *data = dev_get_drvdata(dev);
1111f641b588fdfd25e73c73f6e4977cd2daf8a5e363Jean Delvare	return sprintf(buf, "%s\n", data->name);
1112f641b588fdfd25e73c73f6e4977cd2daf8a5e363Jean Delvare}
1113449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck
1114f641b588fdfd25e73c73f6e4977cd2daf8a5e363Jean Delvarestatic DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
1115f641b588fdfd25e73c73f6e4977cd2daf8a5e363Jean Delvare
11161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
11171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Device detection, registration and update
11181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
11191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1120449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeckstatic int __init pc87360_find(int sioaddr, u8 *devid,
1121449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck			       unsigned short *addresses)
11221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
11231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u16 val;
11241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int i;
11251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int nrdev; /* logical device count */
11261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* No superio_enter */
11281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Identify device */
113067b671bceb4a8340a30929e9642620d99ed5ad76Jean Delvare	val = force_id ? force_id : superio_inb(sioaddr, DEVID);
11311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (val) {
11321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case 0xE1: /* PC87360 */
11331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case 0xE8: /* PC87363 */
11341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case 0xE4: /* PC87364 */
11351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		nrdev = 1;
11361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
11371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case 0xE5: /* PC87365 */
11381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case 0xE9: /* PC87366 */
11391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		nrdev = 3;
11401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
11411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	default:
11421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		superio_exit(sioaddr);
11431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ENODEV;
11441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
11451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Remember the device id */
11461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	*devid = val;
11471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (i = 0; i < nrdev; i++) {
11491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* select logical device */
11501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		superio_outb(sioaddr, DEV, logdev[i]);
11511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		val = superio_inb(sioaddr, ACT);
11531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!(val & 0x01)) {
11549e991c6fad4618a9158437f1f650225f9ec485c3Joe Perches			pr_info("Device 0x%02x not activated\n", logdev[i]);
11551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			continue;
11561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
11571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		val = (superio_inb(sioaddr, BASE) << 8)
11591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		    | superio_inb(sioaddr, BASE + 1);
11601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!val) {
11619e991c6fad4618a9158437f1f650225f9ec485c3Joe Perches			pr_info("Base address not set for device 0x%02x\n",
11629e991c6fad4618a9158437f1f650225f9ec485c3Joe Perches				logdev[i]);
11631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			continue;
11641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
11651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11662d8672c5a6ba0d3f1d8d3ad61ef67868941364f0Jean Delvare		addresses[i] = val;
11671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1168449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck		if (i == 0) { /* Fans */
11691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			confreg[0] = superio_inb(sioaddr, 0xF0);
11701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			confreg[1] = superio_inb(sioaddr, 0xF1);
11711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11729e991c6fad4618a9158437f1f650225f9ec485c3Joe Perches			pr_debug("Fan %d: mon=%d ctrl=%d inv=%d\n", 1,
11739e991c6fad4618a9158437f1f650225f9ec485c3Joe Perches				 (confreg[0] >> 2) & 1, (confreg[0] >> 3) & 1,
11749e991c6fad4618a9158437f1f650225f9ec485c3Joe Perches				 (confreg[0] >> 4) & 1);
11759e991c6fad4618a9158437f1f650225f9ec485c3Joe Perches			pr_debug("Fan %d: mon=%d ctrl=%d inv=%d\n", 2,
11769e991c6fad4618a9158437f1f650225f9ec485c3Joe Perches				 (confreg[0] >> 5) & 1, (confreg[0] >> 6) & 1,
11779e991c6fad4618a9158437f1f650225f9ec485c3Joe Perches				 (confreg[0] >> 7) & 1);
11789e991c6fad4618a9158437f1f650225f9ec485c3Joe Perches			pr_debug("Fan %d: mon=%d ctrl=%d inv=%d\n", 3,
11799e991c6fad4618a9158437f1f650225f9ec485c3Joe Perches				 confreg[1] & 1, (confreg[1] >> 1) & 1,
11809e991c6fad4618a9158437f1f650225f9ec485c3Joe Perches				 (confreg[1] >> 2) & 1);
1181449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck		} else if (i == 1) { /* Voltages */
11821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* Are we using thermistors? */
11831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (*devid == 0xE9) { /* PC87366 */
11843af2861e8b80676d32c5498f9ac1b2de70d3e19bGuenter Roeck				/*
11853af2861e8b80676d32c5498f9ac1b2de70d3e19bGuenter Roeck				 * These registers are not logical-device
11863af2861e8b80676d32c5498f9ac1b2de70d3e19bGuenter Roeck				 * specific, just that we won't need them if
11873af2861e8b80676d32c5498f9ac1b2de70d3e19bGuenter Roeck				 * we don't use the VLM device
11883af2861e8b80676d32c5498f9ac1b2de70d3e19bGuenter Roeck				 */
11891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				confreg[2] = superio_inb(sioaddr, 0x2B);
11901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				confreg[3] = superio_inb(sioaddr, 0x25);
11911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (confreg[2] & 0x40) {
11939e991c6fad4618a9158437f1f650225f9ec485c3Joe Perches					pr_info("Using thermistors for "
11949e991c6fad4618a9158437f1f650225f9ec485c3Joe Perches						"temperature monitoring\n");
11951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				}
11961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (confreg[3] & 0xE0) {
11979e991c6fad4618a9158437f1f650225f9ec485c3Joe Perches					pr_info("VID inputs routed (mode %u)\n",
11989e991c6fad4618a9158437f1f650225f9ec485c3Joe Perches						confreg[3] >> 5);
11991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				}
12001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
12011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
12021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
12031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	superio_exit(sioaddr);
12051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
12061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
12071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1208bce2778df9ea32146d59344c027001e270911f4bGuenter Roeckstatic void pc87360_remove_files(struct device *dev)
1209bce2778df9ea32146d59344c027001e270911f4bGuenter Roeck{
1210bce2778df9ea32146d59344c027001e270911f4bGuenter Roeck	int i;
1211bce2778df9ea32146d59344c027001e270911f4bGuenter Roeck
1212bce2778df9ea32146d59344c027001e270911f4bGuenter Roeck	device_remove_file(dev, &dev_attr_name);
1213bce2778df9ea32146d59344c027001e270911f4bGuenter Roeck	device_remove_file(dev, &dev_attr_alarms_temp);
1214bce2778df9ea32146d59344c027001e270911f4bGuenter Roeck	for (i = 0; i < ARRAY_SIZE(pc8736x_temp_attr_group); i++)
1215bce2778df9ea32146d59344c027001e270911f4bGuenter Roeck		sysfs_remove_group(&dev->kobj, &pc8736x_temp_attr_group[i]);
1216bce2778df9ea32146d59344c027001e270911f4bGuenter Roeck	for (i = 0; i < ARRAY_SIZE(pc8736x_fan_attr_group); i++) {
1217bce2778df9ea32146d59344c027001e270911f4bGuenter Roeck		sysfs_remove_group(&pdev->dev.kobj, &pc8736x_fan_attr_group[i]);
1218bce2778df9ea32146d59344c027001e270911f4bGuenter Roeck		device_remove_file(dev, &pwm[i].dev_attr);
1219bce2778df9ea32146d59344c027001e270911f4bGuenter Roeck	}
1220bce2778df9ea32146d59344c027001e270911f4bGuenter Roeck	sysfs_remove_group(&dev->kobj, &pc8736x_therm_group);
1221bce2778df9ea32146d59344c027001e270911f4bGuenter Roeck	sysfs_remove_group(&dev->kobj, &pc8736x_vin_group);
1222bce2778df9ea32146d59344c027001e270911f4bGuenter Roeck}
1223bce2778df9ea32146d59344c027001e270911f4bGuenter Roeck
1224f641b588fdfd25e73c73f6e4977cd2daf8a5e363Jean Delvarestatic int __devinit pc87360_probe(struct platform_device *pdev)
12251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
12261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int i;
12271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct pc87360_data *data;
12281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int err = 0;
12291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	const char *name = "pc87360";
12301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int use_thermistors = 0;
1231f641b588fdfd25e73c73f6e4977cd2daf8a5e363Jean Delvare	struct device *dev = &pdev->dev;
12321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1233449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck	data = kzalloc(sizeof(struct pc87360_data), GFP_KERNEL);
1234449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck	if (!data)
12351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ENOMEM;
12361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	data->fannr = 2;
12381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	data->innr = 0;
12391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	data->tempnr = 0;
12401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (devid) {
12421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case 0xe8:
12431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		name = "pc87363";
12441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
12451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case 0xe4:
12461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		name = "pc87364";
12471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		data->fannr = 3;
12481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
12491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case 0xe5:
12501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		name = "pc87365";
12511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		data->fannr = extra_isa[0] ? 3 : 0;
12521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		data->innr = extra_isa[1] ? 11 : 0;
12531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		data->tempnr = extra_isa[2] ? 2 : 0;
12541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
12551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case 0xe9:
12561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		name = "pc87366";
12571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		data->fannr = extra_isa[0] ? 3 : 0;
12581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		data->innr = extra_isa[1] ? 14 : 0;
12591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		data->tempnr = extra_isa[2] ? 3 : 0;
12601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
12611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
12621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1263f641b588fdfd25e73c73f6e4977cd2daf8a5e363Jean Delvare	data->name = name;
12641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	data->valid = 0;
1265f641b588fdfd25e73c73f6e4977cd2daf8a5e363Jean Delvare	mutex_init(&data->lock);
12669a61bf6300533d3b64d7ff29adfec00e596de67dIngo Molnar	mutex_init(&data->update_lock);
1267f641b588fdfd25e73c73f6e4977cd2daf8a5e363Jean Delvare	platform_set_drvdata(pdev, data);
12681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12692a32ec2500514109754e07721d9d5d431a706a31Jim Cromie	for (i = 0; i < LDNI_MAX; i++) {
1270449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck		data->address[i] = extra_isa[i];
1271449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck		if (data->address[i]
12721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 && !request_region(extra_isa[i], PC87360_EXTENT,
1273449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck				    pc87360_driver.driver.name)) {
1274f641b588fdfd25e73c73f6e4977cd2daf8a5e363Jean Delvare			dev_err(dev, "Region 0x%x-0x%x already "
12751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				"in use!\n", extra_isa[i],
12761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				extra_isa[i]+PC87360_EXTENT-1);
12771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			for (i--; i >= 0; i--)
12781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				release_region(extra_isa[i], PC87360_EXTENT);
12791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			err = -EBUSY;
12801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto ERROR1;
12811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
12821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
12831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Retrieve the fans configuration from Super-I/O space */
12851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (data->fannr)
12861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		data->fan_conf = confreg[0] | (confreg[1] << 8);
12871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12883af2861e8b80676d32c5498f9ac1b2de70d3e19bGuenter Roeck	/*
12893af2861e8b80676d32c5498f9ac1b2de70d3e19bGuenter Roeck	 * Use the correct reference voltage
12903af2861e8b80676d32c5498f9ac1b2de70d3e19bGuenter Roeck	 * Unless both the VLM and the TMS logical devices agree to
12913af2861e8b80676d32c5498f9ac1b2de70d3e19bGuenter Roeck	 * use an external Vref, the internal one is used.
12923af2861e8b80676d32c5498f9ac1b2de70d3e19bGuenter Roeck	 */
12931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (data->innr) {
12941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		i = pc87360_read_value(data, LD_IN, NO_BANK,
12951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				       PC87365_REG_IN_CONFIG);
12961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (data->tempnr) {
12971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			i &= pc87360_read_value(data, LD_TEMP, NO_BANK,
12981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						PC87365_REG_TEMP_CONFIG);
12991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
13001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		data->in_vref = (i&0x02) ? 3025 : 2966;
1301f641b588fdfd25e73c73f6e4977cd2daf8a5e363Jean Delvare		dev_dbg(dev, "Using %s reference voltage\n",
13021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			(i&0x02) ? "external" : "internal");
13031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		data->vid_conf = confreg[3];
13053d7f9a8697ffe76e9edaf6b1751f2a2db660e4d5Jim Cromie		data->vrm = vid_which_vrm();
13061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
13071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Fan clock dividers may be needed before any data is read */
13091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (i = 0; i < data->fannr; i++) {
13101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (FAN_CONFIG_MONITOR(data->fan_conf, i))
13111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			data->fan_status[i] = pc87360_read_value(data,
13121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					      LD_FAN, NO_BANK,
13131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					      PC87360_REG_FAN_STATUS(i));
13141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
13151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (init > 0) {
13171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (devid == 0xe9 && data->address[1]) /* PC87366 */
13181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			use_thermistors = confreg[2] & 0x40;
13191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1320f641b588fdfd25e73c73f6e4977cd2daf8a5e363Jean Delvare		pc87360_init_device(pdev, use_thermistors);
13211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
13221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1323f3722d5b6a474e31237d23980e9bd38facfda6f4Jim Cromie	/* Register all-or-nothing sysfs groups */
1324f3722d5b6a474e31237d23980e9bd38facfda6f4Jim Cromie
1325449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck	if (data->innr) {
1326449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck		err = sysfs_create_group(&dev->kobj, &pc8736x_vin_group);
1327449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck		if (err)
1328449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck			goto ERROR3;
1329449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck	}
1330943b0830cebe4711354945ed3cb44e84152aaca0Mark M. Hoffman
1331449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck	if (data->innr == 14) {
1332449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck		err = sysfs_create_group(&dev->kobj, &pc8736x_therm_group);
1333449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck		if (err)
1334449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck			goto ERROR3;
1335449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck	}
1336f3722d5b6a474e31237d23980e9bd38facfda6f4Jim Cromie
1337f3722d5b6a474e31237d23980e9bd38facfda6f4Jim Cromie	/* create device attr-files for varying sysfs groups */
13381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (data->tempnr) {
1340dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromie		for (i = 0; i < data->tempnr; i++) {
1341bce2778df9ea32146d59344c027001e270911f4bGuenter Roeck			err = sysfs_create_group(&dev->kobj,
1342bce2778df9ea32146d59344c027001e270911f4bGuenter Roeck						 &pc8736x_temp_attr_group[i]);
1343bce2778df9ea32146d59344c027001e270911f4bGuenter Roeck			if (err)
1344f3722d5b6a474e31237d23980e9bd38facfda6f4Jim Cromie				goto ERROR3;
13451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
1346449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck		err = device_create_file(dev, &dev_attr_alarms_temp);
1347449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck		if (err)
1348f3722d5b6a474e31237d23980e9bd38facfda6f4Jim Cromie			goto ERROR3;
13491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
13501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1351dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromie	for (i = 0; i < data->fannr; i++) {
1352bce2778df9ea32146d59344c027001e270911f4bGuenter Roeck		if (FAN_CONFIG_MONITOR(data->fan_conf, i)) {
1353bce2778df9ea32146d59344c027001e270911f4bGuenter Roeck			err = sysfs_create_group(&dev->kobj,
1354bce2778df9ea32146d59344c027001e270911f4bGuenter Roeck						 &pc8736x_fan_attr_group[i]);
1355bce2778df9ea32146d59344c027001e270911f4bGuenter Roeck			if (err)
1356bce2778df9ea32146d59344c027001e270911f4bGuenter Roeck				goto ERROR3;
1357bce2778df9ea32146d59344c027001e270911f4bGuenter Roeck		}
1358449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck		if (FAN_CONFIG_CONTROL(data->fan_conf, i)) {
1359449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck			err = device_create_file(dev, &pwm[i].dev_attr);
1360449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck			if (err)
1361449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck				goto ERROR3;
1362449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck		}
13631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
13641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1365449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck	err = device_create_file(dev, &dev_attr_name);
1366449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck	if (err)
1367f641b588fdfd25e73c73f6e4977cd2daf8a5e363Jean Delvare		goto ERROR3;
1368f641b588fdfd25e73c73f6e4977cd2daf8a5e363Jean Delvare
13691beeffe43311f64df8dd0ab08ff6b1858c58363fTony Jones	data->hwmon_dev = hwmon_device_register(dev);
13701beeffe43311f64df8dd0ab08ff6b1858c58363fTony Jones	if (IS_ERR(data->hwmon_dev)) {
13711beeffe43311f64df8dd0ab08ff6b1858c58363fTony Jones		err = PTR_ERR(data->hwmon_dev);
1372f3722d5b6a474e31237d23980e9bd38facfda6f4Jim Cromie		goto ERROR3;
1373f3722d5b6a474e31237d23980e9bd38facfda6f4Jim Cromie	}
13741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
13751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1376943b0830cebe4711354945ed3cb44e84152aaca0Mark M. HoffmanERROR3:
1377bce2778df9ea32146d59344c027001e270911f4bGuenter Roeck	pc87360_remove_files(dev);
13781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (i = 0; i < 3; i++) {
1379449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck		if (data->address[i])
13801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			release_region(data->address[i], PC87360_EXTENT);
13811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
13821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsERROR1:
13831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	kfree(data);
13841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return err;
13851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
13861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1387f641b588fdfd25e73c73f6e4977cd2daf8a5e363Jean Delvarestatic int __devexit pc87360_remove(struct platform_device *pdev)
13881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1389f641b588fdfd25e73c73f6e4977cd2daf8a5e363Jean Delvare	struct pc87360_data *data = platform_get_drvdata(pdev);
13901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int i;
13911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13921beeffe43311f64df8dd0ab08ff6b1858c58363fTony Jones	hwmon_device_unregister(data->hwmon_dev);
1393bce2778df9ea32146d59344c027001e270911f4bGuenter Roeck	pc87360_remove_files(&pdev->dev);
13941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (i = 0; i < 3; i++) {
1395449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck		if (data->address[i])
13961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			release_region(data->address[i], PC87360_EXTENT);
13971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
13981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	kfree(data);
13991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
14011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
14021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14033af2861e8b80676d32c5498f9ac1b2de70d3e19bGuenter Roeck/*
14043af2861e8b80676d32c5498f9ac1b2de70d3e19bGuenter Roeck * ldi is the logical device index
14053af2861e8b80676d32c5498f9ac1b2de70d3e19bGuenter Roeck * bank is for voltages and temperatures only
14063af2861e8b80676d32c5498f9ac1b2de70d3e19bGuenter Roeck */
14071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int pc87360_read_value(struct pc87360_data *data, u8 ldi, u8 bank,
14081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      u8 reg)
14091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
14101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int res;
14111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14129a61bf6300533d3b64d7ff29adfec00e596de67dIngo Molnar	mutex_lock(&(data->lock));
14131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (bank != NO_BANK)
14141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		outb_p(bank, data->address[ldi] + PC87365_REG_BANK);
14151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	res = inb_p(data->address[ldi] + reg);
14169a61bf6300533d3b64d7ff29adfec00e596de67dIngo Molnar	mutex_unlock(&(data->lock));
14171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return res;
14191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
14201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void pc87360_write_value(struct pc87360_data *data, u8 ldi, u8 bank,
14221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				u8 reg, u8 value)
14231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
14249a61bf6300533d3b64d7ff29adfec00e596de67dIngo Molnar	mutex_lock(&(data->lock));
14251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (bank != NO_BANK)
14261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		outb_p(bank, data->address[ldi] + PC87365_REG_BANK);
14271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	outb_p(value, data->address[ldi] + reg);
14289a61bf6300533d3b64d7ff29adfec00e596de67dIngo Molnar	mutex_unlock(&(data->lock));
14291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
14301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
143128f74e71775b1ae0ebf7fe87f7a7f39ecb77a2b8Jim Cromie/* (temp & vin) channel conversion status register flags (pdf sec.11.5.12) */
143228f74e71775b1ae0ebf7fe87f7a7f39ecb77a2b8Jim Cromie#define CHAN_CNVRTD	0x80	/* new data ready */
143328f74e71775b1ae0ebf7fe87f7a7f39ecb77a2b8Jim Cromie#define CHAN_ENA	0x01	/* enabled channel (temp or vin) */
143428f74e71775b1ae0ebf7fe87f7a7f39ecb77a2b8Jim Cromie#define CHAN_ALM_ENA	0x10	/* propagate to alarms-reg ?? (chk val!) */
143528f74e71775b1ae0ebf7fe87f7a7f39ecb77a2b8Jim Cromie#define CHAN_READY	(CHAN_ENA|CHAN_CNVRTD) /* sample ready mask */
143628f74e71775b1ae0ebf7fe87f7a7f39ecb77a2b8Jim Cromie
1437b267e8cdc638dfa53360d532aa56afa0ec12e6a5Jim Cromie#define TEMP_OTS_OE	0x20	/* OTS Output Enable */
1438b267e8cdc638dfa53360d532aa56afa0ec12e6a5Jim Cromie#define VIN_RW1C_MASK	(CHAN_READY|CHAN_ALM_MAX|CHAN_ALM_MIN)   /* 0x87 */
1439b267e8cdc638dfa53360d532aa56afa0ec12e6a5Jim Cromie#define TEMP_RW1C_MASK	(VIN_RW1C_MASK|TEMP_ALM_CRIT|TEMP_FAULT) /* 0xCF */
1440b267e8cdc638dfa53360d532aa56afa0ec12e6a5Jim Cromie
1441f641b588fdfd25e73c73f6e4977cd2daf8a5e363Jean Delvarestatic void pc87360_init_device(struct platform_device *pdev,
1442f641b588fdfd25e73c73f6e4977cd2daf8a5e363Jean Delvare				int use_thermistors)
14431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1444f641b588fdfd25e73c73f6e4977cd2daf8a5e363Jean Delvare	struct pc87360_data *data = platform_get_drvdata(pdev);
14451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int i, nr;
14461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	const u8 init_in[14] = { 2, 2, 2, 2, 2, 2, 2, 1, 1, 3, 1, 2, 2, 2 };
14471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	const u8 init_temp[3] = { 2, 2, 1 };
14481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 reg;
14491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (init >= 2 && data->innr) {
14511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		reg = pc87360_read_value(data, LD_IN, NO_BANK,
14521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					 PC87365_REG_IN_CONVRATE);
1453f641b588fdfd25e73c73f6e4977cd2daf8a5e363Jean Delvare		dev_info(&pdev->dev, "VLM conversion set to "
14541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 "1s period, 160us delay\n");
14551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		pc87360_write_value(data, LD_IN, NO_BANK,
14561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				    PC87365_REG_IN_CONVRATE,
14571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				    (reg & 0xC0) | 0x11);
14581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
14591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	nr = data->innr < 11 ? data->innr : 11;
1461dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromie	for (i = 0; i < nr; i++) {
14628ca136741e15e8546e787ae92a7f4aeca84be494Jim Cromie		reg = pc87360_read_value(data, LD_IN, i,
14638ca136741e15e8546e787ae92a7f4aeca84be494Jim Cromie					 PC87365_REG_IN_STATUS);
14648ca136741e15e8546e787ae92a7f4aeca84be494Jim Cromie		dev_dbg(&pdev->dev, "bios in%d status:0x%02x\n", i, reg);
14651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (init >= init_in[i]) {
14661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* Forcibly enable voltage channel */
146728f74e71775b1ae0ebf7fe87f7a7f39ecb77a2b8Jim Cromie			if (!(reg & CHAN_ENA)) {
1468f641b588fdfd25e73c73f6e4977cd2daf8a5e363Jean Delvare				dev_dbg(&pdev->dev, "Forcibly "
14691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					"enabling in%d\n", i);
14701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				pc87360_write_value(data, LD_IN, i,
14711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						    PC87365_REG_IN_STATUS,
14721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						    (reg & 0x68) | 0x87);
14731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
14741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
14751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
14761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14773af2861e8b80676d32c5498f9ac1b2de70d3e19bGuenter Roeck	/*
14783af2861e8b80676d32c5498f9ac1b2de70d3e19bGuenter Roeck	 * We can't blindly trust the Super-I/O space configuration bit,
14793af2861e8b80676d32c5498f9ac1b2de70d3e19bGuenter Roeck	 * most BIOS won't set it properly
14803af2861e8b80676d32c5498f9ac1b2de70d3e19bGuenter Roeck	 */
14818ca136741e15e8546e787ae92a7f4aeca84be494Jim Cromie	dev_dbg(&pdev->dev, "bios thermistors:%d\n", use_thermistors);
1482dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromie	for (i = 11; i < data->innr; i++) {
14831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		reg = pc87360_read_value(data, LD_IN, i,
14841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					 PC87365_REG_TEMP_STATUS);
148528f74e71775b1ae0ebf7fe87f7a7f39ecb77a2b8Jim Cromie		use_thermistors = use_thermistors || (reg & CHAN_ENA);
14868ca136741e15e8546e787ae92a7f4aeca84be494Jim Cromie		/* thermistors are temp[4-6], measured on vin[11-14] */
14878ca136741e15e8546e787ae92a7f4aeca84be494Jim Cromie		dev_dbg(&pdev->dev, "bios temp%d_status:0x%02x\n", i-7, reg);
14881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
14898ca136741e15e8546e787ae92a7f4aeca84be494Jim Cromie	dev_dbg(&pdev->dev, "using thermistors:%d\n", use_thermistors);
14901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	i = use_thermistors ? 2 : 0;
1492dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromie	for (; i < data->tempnr; i++) {
14938ca136741e15e8546e787ae92a7f4aeca84be494Jim Cromie		reg = pc87360_read_value(data, LD_TEMP, i,
14948ca136741e15e8546e787ae92a7f4aeca84be494Jim Cromie					 PC87365_REG_TEMP_STATUS);
1495449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck		dev_dbg(&pdev->dev, "bios temp%d_status:0x%02x\n", i + 1, reg);
14961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (init >= init_temp[i]) {
14971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* Forcibly enable temperature channel */
149828f74e71775b1ae0ebf7fe87f7a7f39ecb77a2b8Jim Cromie			if (!(reg & CHAN_ENA)) {
1499449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck				dev_dbg(&pdev->dev,
1500449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck					"Forcibly enabling temp%d\n", i + 1);
15011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				pc87360_write_value(data, LD_TEMP, i,
15021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						    PC87365_REG_TEMP_STATUS,
15031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						    0xCF);
15041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
15051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
15061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
15071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (use_thermistors) {
1509dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromie		for (i = 11; i < data->innr; i++) {
15101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (init >= init_in[i]) {
15113af2861e8b80676d32c5498f9ac1b2de70d3e19bGuenter Roeck				/*
15123af2861e8b80676d32c5498f9ac1b2de70d3e19bGuenter Roeck				 * The pin may already be used by thermal
15133af2861e8b80676d32c5498f9ac1b2de70d3e19bGuenter Roeck				 * diodes
15143af2861e8b80676d32c5498f9ac1b2de70d3e19bGuenter Roeck				 */
15151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				reg = pc87360_read_value(data, LD_TEMP,
1516449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck				      (i - 11) / 2, PC87365_REG_TEMP_STATUS);
151728f74e71775b1ae0ebf7fe87f7a7f39ecb77a2b8Jim Cromie				if (reg & CHAN_ENA) {
1518449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck					dev_dbg(&pdev->dev,
1519449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck			"Skipping temp%d, pin already in use by temp%d\n",
1520449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck						i - 7, (i - 11) / 2);
15211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					continue;
15221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				}
15231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				/* Forcibly enable thermistor channel */
15251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				reg = pc87360_read_value(data, LD_IN, i,
15261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds							 PC87365_REG_IN_STATUS);
152728f74e71775b1ae0ebf7fe87f7a7f39ecb77a2b8Jim Cromie				if (!(reg & CHAN_ENA)) {
1528449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck					dev_dbg(&pdev->dev,
1529449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck						"Forcibly enabling temp%d\n",
1530449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck						i - 7);
15311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					pc87360_write_value(data, LD_IN, i,
15321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						PC87365_REG_TEMP_STATUS,
15331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						(reg & 0x60) | 0x8F);
15341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				}
15351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
15361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
15371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
15381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (data->innr) {
15401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		reg = pc87360_read_value(data, LD_IN, NO_BANK,
15411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					 PC87365_REG_IN_CONFIG);
15428ca136741e15e8546e787ae92a7f4aeca84be494Jim Cromie		dev_dbg(&pdev->dev, "bios vin-cfg:0x%02x\n", reg);
154328f74e71775b1ae0ebf7fe87f7a7f39ecb77a2b8Jim Cromie		if (reg & CHAN_ENA) {
1544449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck			dev_dbg(&pdev->dev,
1545449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck				"Forcibly enabling monitoring (VLM)\n");
15461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			pc87360_write_value(data, LD_IN, NO_BANK,
15471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					    PC87365_REG_IN_CONFIG,
15481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					    reg & 0xFE);
15491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
15501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
15511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (data->tempnr) {
15531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		reg = pc87360_read_value(data, LD_TEMP, NO_BANK,
15541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					 PC87365_REG_TEMP_CONFIG);
15558ca136741e15e8546e787ae92a7f4aeca84be494Jim Cromie		dev_dbg(&pdev->dev, "bios temp-cfg:0x%02x\n", reg);
155628f74e71775b1ae0ebf7fe87f7a7f39ecb77a2b8Jim Cromie		if (reg & CHAN_ENA) {
1557449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck			dev_dbg(&pdev->dev,
1558449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck				"Forcibly enabling monitoring (TMS)\n");
15591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			pc87360_write_value(data, LD_TEMP, NO_BANK,
15601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					    PC87365_REG_TEMP_CONFIG,
15611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					    reg & 0xFE);
15621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
15631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (init >= 2) {
15651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* Chip config as documented by National Semi. */
15661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			pc87360_write_value(data, LD_TEMP, 0xF, 0xA, 0x08);
15673af2861e8b80676d32c5498f9ac1b2de70d3e19bGuenter Roeck			/*
15683af2861e8b80676d32c5498f9ac1b2de70d3e19bGuenter Roeck			 * We voluntarily omit the bank here, in case the
15693af2861e8b80676d32c5498f9ac1b2de70d3e19bGuenter Roeck			 * sequence itself matters. It shouldn't be a problem,
15703af2861e8b80676d32c5498f9ac1b2de70d3e19bGuenter Roeck			 * since nobody else is supposed to access the
15713af2861e8b80676d32c5498f9ac1b2de70d3e19bGuenter Roeck			 * device at that point.
15723af2861e8b80676d32c5498f9ac1b2de70d3e19bGuenter Roeck			 */
15731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			pc87360_write_value(data, LD_TEMP, NO_BANK, 0xB, 0x04);
15741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			pc87360_write_value(data, LD_TEMP, NO_BANK, 0xC, 0x35);
15751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			pc87360_write_value(data, LD_TEMP, NO_BANK, 0xD, 0x05);
15761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			pc87360_write_value(data, LD_TEMP, NO_BANK, 0xE, 0x05);
15771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
15781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
15791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
15801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1581f641b588fdfd25e73c73f6e4977cd2daf8a5e363Jean Delvarestatic void pc87360_autodiv(struct device *dev, int nr)
15821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1583f641b588fdfd25e73c73f6e4977cd2daf8a5e363Jean Delvare	struct pc87360_data *data = dev_get_drvdata(dev);
15841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 old_min = data->fan_min[nr];
15851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Increase clock divider if needed and possible */
15871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if ((data->fan_status[nr] & 0x04) /* overflow flag */
15881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 || (data->fan[nr] >= 224)) { /* next to overflow */
15891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if ((data->fan_status[nr] & 0x60) != 0x60) {
15901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			data->fan_status[nr] += 0x20;
15911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			data->fan_min[nr] >>= 1;
15921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			data->fan[nr] >>= 1;
1593f641b588fdfd25e73c73f6e4977cd2daf8a5e363Jean Delvare			dev_dbg(dev, "Increasing "
15941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				"clock divider to %d for fan %d\n",
1595449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck				FAN_DIV_FROM_REG(data->fan_status[nr]), nr + 1);
15961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
15971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
15981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* Decrease clock divider if possible */
15991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		while (!(data->fan_min[nr] & 0x80) /* min "nails" divider */
16001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 && data->fan[nr] < 85 /* bad accuracy */
16011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 && (data->fan_status[nr] & 0x60) != 0x00) {
16021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			data->fan_status[nr] -= 0x20;
16031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			data->fan_min[nr] <<= 1;
16041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			data->fan[nr] <<= 1;
1605f641b588fdfd25e73c73f6e4977cd2daf8a5e363Jean Delvare			dev_dbg(dev, "Decreasing "
16061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				"clock divider to %d for fan %d\n",
16071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				FAN_DIV_FROM_REG(data->fan_status[nr]),
1608449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck				nr + 1);
16091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
16101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
16111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Write new fan min if it changed */
16131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (old_min != data->fan_min[nr]) {
16141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		pc87360_write_value(data, LD_FAN, NO_BANK,
16151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				    PC87360_REG_FAN_MIN(nr),
16161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				    data->fan_min[nr]);
16171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
16181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
16191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct pc87360_data *pc87360_update_device(struct device *dev)
16211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1622f641b588fdfd25e73c73f6e4977cd2daf8a5e363Jean Delvare	struct pc87360_data *data = dev_get_drvdata(dev);
16231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 i;
16241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16259a61bf6300533d3b64d7ff29adfec00e596de67dIngo Molnar	mutex_lock(&data->update_lock);
16261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (time_after(jiffies, data->last_updated + HZ * 2) || !data->valid) {
1628f641b588fdfd25e73c73f6e4977cd2daf8a5e363Jean Delvare		dev_dbg(dev, "Data update\n");
16291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* Fans */
16311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		for (i = 0; i < data->fannr; i++) {
16321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (FAN_CONFIG_MONITOR(data->fan_conf, i)) {
16331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				data->fan_status[i] =
16341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					pc87360_read_value(data, LD_FAN,
16351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					NO_BANK, PC87360_REG_FAN_STATUS(i));
16361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				data->fan[i] = pc87360_read_value(data, LD_FAN,
16371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					       NO_BANK, PC87360_REG_FAN(i));
16381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				data->fan_min[i] = pc87360_read_value(data,
16391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						   LD_FAN, NO_BANK,
16401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						   PC87360_REG_FAN_MIN(i));
16411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				/* Change clock divider if needed */
1642f641b588fdfd25e73c73f6e4977cd2daf8a5e363Jean Delvare				pc87360_autodiv(dev, i);
16431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				/* Clear bits and write new divider */
16441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				pc87360_write_value(data, LD_FAN, NO_BANK,
16451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						    PC87360_REG_FAN_STATUS(i),
16461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						    data->fan_status[i]);
16471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
16481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (FAN_CONFIG_CONTROL(data->fan_conf, i))
16491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				data->pwm[i] = pc87360_read_value(data, LD_FAN,
16501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					       NO_BANK, PC87360_REG_PWM(i));
16511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
16521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* Voltages */
16541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		for (i = 0; i < data->innr; i++) {
16551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			data->in_status[i] = pc87360_read_value(data, LD_IN, i,
16561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					     PC87365_REG_IN_STATUS);
16571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* Clear bits */
16581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			pc87360_write_value(data, LD_IN, i,
16591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					    PC87365_REG_IN_STATUS,
16601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					    data->in_status[i]);
166128f74e71775b1ae0ebf7fe87f7a7f39ecb77a2b8Jim Cromie			if ((data->in_status[i] & CHAN_READY) == CHAN_READY) {
16621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				data->in[i] = pc87360_read_value(data, LD_IN,
16631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					      i, PC87365_REG_IN);
16641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
166528f74e71775b1ae0ebf7fe87f7a7f39ecb77a2b8Jim Cromie			if (data->in_status[i] & CHAN_ENA) {
16661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				data->in_min[i] = pc87360_read_value(data,
16671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						  LD_IN, i,
16681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						  PC87365_REG_IN_MIN);
16691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				data->in_max[i] = pc87360_read_value(data,
16701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						  LD_IN, i,
16711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						  PC87365_REG_IN_MAX);
16721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (i >= 11)
16731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					data->in_crit[i-11] =
16741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						pc87360_read_value(data, LD_IN,
16751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						i, PC87365_REG_TEMP_CRIT);
16761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
16771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
16781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (data->innr) {
16791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			data->in_alarms = pc87360_read_value(data, LD_IN,
16801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					  NO_BANK, PC87365_REG_IN_ALARMS1)
16811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					| ((pc87360_read_value(data, LD_IN,
16821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					    NO_BANK, PC87365_REG_IN_ALARMS2)
16831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					    & 0x07) << 8);
16841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			data->vid = (data->vid_conf & 0xE0) ?
16851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				    pc87360_read_value(data, LD_IN,
16861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				    NO_BANK, PC87365_REG_VID) : 0x1F;
16871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
16881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* Temperatures */
16901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		for (i = 0; i < data->tempnr; i++) {
16911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			data->temp_status[i] = pc87360_read_value(data,
16921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					       LD_TEMP, i,
16931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					       PC87365_REG_TEMP_STATUS);
16941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* Clear bits */
16951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			pc87360_write_value(data, LD_TEMP, i,
16961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					    PC87365_REG_TEMP_STATUS,
16971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					    data->temp_status[i]);
169828f74e71775b1ae0ebf7fe87f7a7f39ecb77a2b8Jim Cromie			if ((data->temp_status[i] & CHAN_READY) == CHAN_READY) {
16991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				data->temp[i] = pc87360_read_value(data,
17001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						LD_TEMP, i,
17011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						PC87365_REG_TEMP);
17021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
170328f74e71775b1ae0ebf7fe87f7a7f39ecb77a2b8Jim Cromie			if (data->temp_status[i] & CHAN_ENA) {
17041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				data->temp_min[i] = pc87360_read_value(data,
17051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						    LD_TEMP, i,
17061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						    PC87365_REG_TEMP_MIN);
17071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				data->temp_max[i] = pc87360_read_value(data,
17081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						    LD_TEMP, i,
17091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						    PC87365_REG_TEMP_MAX);
17101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				data->temp_crit[i] = pc87360_read_value(data,
17111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						     LD_TEMP, i,
17121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						     PC87365_REG_TEMP_CRIT);
17131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
17141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
17151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (data->tempnr) {
17161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			data->temp_alarms = pc87360_read_value(data, LD_TEMP,
17171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					    NO_BANK, PC87365_REG_TEMP_ALARMS)
17181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					    & 0x3F;
17191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
17201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
17211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		data->last_updated = jiffies;
17221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		data->valid = 1;
17231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
17241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
17259a61bf6300533d3b64d7ff29adfec00e596de67dIngo Molnar	mutex_unlock(&data->update_lock);
17261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
17271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return data;
17281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
17291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1730f641b588fdfd25e73c73f6e4977cd2daf8a5e363Jean Delvarestatic int __init pc87360_device_add(unsigned short address)
1731f641b588fdfd25e73c73f6e4977cd2daf8a5e363Jean Delvare{
1732b9783dcebe952bf73449fe70a19ee4814adc81a0Jean Delvare	struct resource res[3];
1733b9783dcebe952bf73449fe70a19ee4814adc81a0Jean Delvare	int err, i, res_count;
1734f641b588fdfd25e73c73f6e4977cd2daf8a5e363Jean Delvare
1735f641b588fdfd25e73c73f6e4977cd2daf8a5e363Jean Delvare	pdev = platform_device_alloc("pc87360", address);
1736f641b588fdfd25e73c73f6e4977cd2daf8a5e363Jean Delvare	if (!pdev) {
1737f641b588fdfd25e73c73f6e4977cd2daf8a5e363Jean Delvare		err = -ENOMEM;
17389e991c6fad4618a9158437f1f650225f9ec485c3Joe Perches		pr_err("Device allocation failed\n");
1739f641b588fdfd25e73c73f6e4977cd2daf8a5e363Jean Delvare		goto exit;
1740f641b588fdfd25e73c73f6e4977cd2daf8a5e363Jean Delvare	}
1741f641b588fdfd25e73c73f6e4977cd2daf8a5e363Jean Delvare
1742b9783dcebe952bf73449fe70a19ee4814adc81a0Jean Delvare	memset(res, 0, 3 * sizeof(struct resource));
1743b9783dcebe952bf73449fe70a19ee4814adc81a0Jean Delvare	res_count = 0;
1744f641b588fdfd25e73c73f6e4977cd2daf8a5e363Jean Delvare	for (i = 0; i < 3; i++) {
1745f641b588fdfd25e73c73f6e4977cd2daf8a5e363Jean Delvare		if (!extra_isa[i])
1746f641b588fdfd25e73c73f6e4977cd2daf8a5e363Jean Delvare			continue;
1747b9783dcebe952bf73449fe70a19ee4814adc81a0Jean Delvare		res[res_count].start = extra_isa[i];
1748b9783dcebe952bf73449fe70a19ee4814adc81a0Jean Delvare		res[res_count].end = extra_isa[i] + PC87360_EXTENT - 1;
1749b9783dcebe952bf73449fe70a19ee4814adc81a0Jean Delvare		res[res_count].name = "pc87360",
1750b9783dcebe952bf73449fe70a19ee4814adc81a0Jean Delvare		res[res_count].flags = IORESOURCE_IO,
1751b9acb64a385c5b26fc392e0d58ac7b8e0a2cd812Jean Delvare
1752b9783dcebe952bf73449fe70a19ee4814adc81a0Jean Delvare		err = acpi_check_resource_conflict(&res[res_count]);
1753b9acb64a385c5b26fc392e0d58ac7b8e0a2cd812Jean Delvare		if (err)
1754b9acb64a385c5b26fc392e0d58ac7b8e0a2cd812Jean Delvare			goto exit_device_put;
1755b9acb64a385c5b26fc392e0d58ac7b8e0a2cd812Jean Delvare
1756b9783dcebe952bf73449fe70a19ee4814adc81a0Jean Delvare		res_count++;
1757b9783dcebe952bf73449fe70a19ee4814adc81a0Jean Delvare	}
1758b9783dcebe952bf73449fe70a19ee4814adc81a0Jean Delvare
1759b9783dcebe952bf73449fe70a19ee4814adc81a0Jean Delvare	err = platform_device_add_resources(pdev, res, res_count);
1760b9783dcebe952bf73449fe70a19ee4814adc81a0Jean Delvare	if (err) {
17619e991c6fad4618a9158437f1f650225f9ec485c3Joe Perches		pr_err("Device resources addition failed (%d)\n", err);
1762b9783dcebe952bf73449fe70a19ee4814adc81a0Jean Delvare		goto exit_device_put;
1763f641b588fdfd25e73c73f6e4977cd2daf8a5e363Jean Delvare	}
1764f641b588fdfd25e73c73f6e4977cd2daf8a5e363Jean Delvare
1765f641b588fdfd25e73c73f6e4977cd2daf8a5e363Jean Delvare	err = platform_device_add(pdev);
1766f641b588fdfd25e73c73f6e4977cd2daf8a5e363Jean Delvare	if (err) {
17679e991c6fad4618a9158437f1f650225f9ec485c3Joe Perches		pr_err("Device addition failed (%d)\n", err);
1768f641b588fdfd25e73c73f6e4977cd2daf8a5e363Jean Delvare		goto exit_device_put;
1769f641b588fdfd25e73c73f6e4977cd2daf8a5e363Jean Delvare	}
1770f641b588fdfd25e73c73f6e4977cd2daf8a5e363Jean Delvare
1771f641b588fdfd25e73c73f6e4977cd2daf8a5e363Jean Delvare	return 0;
1772f641b588fdfd25e73c73f6e4977cd2daf8a5e363Jean Delvare
1773f641b588fdfd25e73c73f6e4977cd2daf8a5e363Jean Delvareexit_device_put:
1774f641b588fdfd25e73c73f6e4977cd2daf8a5e363Jean Delvare	platform_device_put(pdev);
1775f641b588fdfd25e73c73f6e4977cd2daf8a5e363Jean Delvareexit:
1776f641b588fdfd25e73c73f6e4977cd2daf8a5e363Jean Delvare	return err;
1777f641b588fdfd25e73c73f6e4977cd2daf8a5e363Jean Delvare}
1778f641b588fdfd25e73c73f6e4977cd2daf8a5e363Jean Delvare
17791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int __init pc87360_init(void)
17801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1781f641b588fdfd25e73c73f6e4977cd2daf8a5e363Jean Delvare	int err, i;
1782f641b588fdfd25e73c73f6e4977cd2daf8a5e363Jean Delvare	unsigned short address = 0;
17831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
17841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (pc87360_find(0x2e, &devid, extra_isa)
17851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 && pc87360_find(0x4e, &devid, extra_isa)) {
17869e991c6fad4618a9158437f1f650225f9ec485c3Joe Perches		pr_warn("PC8736x not detected, module not inserted\n");
17871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ENODEV;
17881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
17891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
17901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Arbitrarily pick one of the addresses */
17911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (i = 0; i < 3; i++) {
17921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (extra_isa[i] != 0x0000) {
17932d8672c5a6ba0d3f1d8d3ad61ef67868941364f0Jean Delvare			address = extra_isa[i];
17941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
17951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
17961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
17971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
17982d8672c5a6ba0d3f1d8d3ad61ef67868941364f0Jean Delvare	if (address == 0x0000) {
17999e991c6fad4618a9158437f1f650225f9ec485c3Joe Perches		pr_warn("No active logical device, module not inserted\n");
18001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ENODEV;
18011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
18021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1803f641b588fdfd25e73c73f6e4977cd2daf8a5e363Jean Delvare	err = platform_driver_register(&pc87360_driver);
1804f641b588fdfd25e73c73f6e4977cd2daf8a5e363Jean Delvare	if (err)
1805f641b588fdfd25e73c73f6e4977cd2daf8a5e363Jean Delvare		goto exit;
1806f641b588fdfd25e73c73f6e4977cd2daf8a5e363Jean Delvare
1807f641b588fdfd25e73c73f6e4977cd2daf8a5e363Jean Delvare	/* Sets global pdev as a side effect */
1808f641b588fdfd25e73c73f6e4977cd2daf8a5e363Jean Delvare	err = pc87360_device_add(address);
1809f641b588fdfd25e73c73f6e4977cd2daf8a5e363Jean Delvare	if (err)
1810f641b588fdfd25e73c73f6e4977cd2daf8a5e363Jean Delvare		goto exit_driver;
1811f641b588fdfd25e73c73f6e4977cd2daf8a5e363Jean Delvare
1812f641b588fdfd25e73c73f6e4977cd2daf8a5e363Jean Delvare	return 0;
1813f641b588fdfd25e73c73f6e4977cd2daf8a5e363Jean Delvare
1814f641b588fdfd25e73c73f6e4977cd2daf8a5e363Jean Delvare exit_driver:
1815f641b588fdfd25e73c73f6e4977cd2daf8a5e363Jean Delvare	platform_driver_unregister(&pc87360_driver);
1816f641b588fdfd25e73c73f6e4977cd2daf8a5e363Jean Delvare exit:
1817f641b588fdfd25e73c73f6e4977cd2daf8a5e363Jean Delvare	return err;
18181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
18191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
18201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void __exit pc87360_exit(void)
18211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1822f641b588fdfd25e73c73f6e4977cd2daf8a5e363Jean Delvare	platform_device_unregister(pdev);
1823f641b588fdfd25e73c73f6e4977cd2daf8a5e363Jean Delvare	platform_driver_unregister(&pc87360_driver);
18241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
18251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
18261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
18271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_AUTHOR("Jean Delvare <khali@linux-fr.org>");
18281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_DESCRIPTION("PC8736x hardware monitor");
18291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_LICENSE("GPL");
18301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
18311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_init(pc87360_init);
18321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_exit(pc87360_exit);
1833