asb100.c revision 310ec79210d754afe51e2e4a983e846b60179abd
11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    asb100.c - Part of lm_sensors, Linux kernel modules for hardware
31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	        monitoring
41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    Copyright (C) 2004 Mark M. Hoffman <mhoffman@lightlink.com>
61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	(derived from w83781d.c)
81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    Copyright (C) 1998 - 2003  Frodo Looijaard <frodol@dds.nl>,
101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    Philip Edelbrock <phil@netroedge.com>, and
111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    Mark Studebaker <mdsxyz123@yahoo.com>
121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    This program is free software; you can redistribute it and/or modify
141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    it under the terms of the GNU General Public License as published by
151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    the Free Software Foundation; either version 2 of the License, or
161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    (at your option) any later version.
171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    This program is distributed in the hope that it will be useful,
191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    but WITHOUT ANY WARRANTY; without even the implied warranty of
201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    GNU General Public License for more details.
221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    You should have received a copy of the GNU General Public License
241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    along with this program; if not, write to the Free Software
251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds*/
271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    This driver supports the hardware sensor chips: Asus ASB100 and
301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    ASB100-A "BACH".
311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    ASB100-A supports pwm1, while plain ASB100 does not.  There is no known
331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    way for the driver to tell which one is there.
341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    Chip	#vin	#fanin	#pwm	#temp	wchipid	vendid	i2c	ISA
361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    asb100	7	3	1	4	0x31	0x0694	yes	no
371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds*/
381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/module.h>
401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/slab.h>
411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/i2c.h>
42943b0830cebe4711354945ed3cb44e84152aaca0Mark M. Hoffman#include <linux/hwmon.h>
43fad33c5fdae73a75af2f8ecf69147011bd57e28cJean Delvare#include <linux/hwmon-sysfs.h>
44303760b44a7a142cb9f4c9df4609fb63bbda98dbJean Delvare#include <linux/hwmon-vid.h>
45943b0830cebe4711354945ed3cb44e84152aaca0Mark M. Hoffman#include <linux/err.h>
461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/init.h>
47ff3240946d6a3d9f2ecf273f7330e09eec5484ebDominik Hackl#include <linux/jiffies.h>
489a61bf6300533d3b64d7ff29adfec00e596de67dIngo Molnar#include <linux/mutex.h>
491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "lm75.h"
501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* I2C addresses to scan */
5225e9c86d5a6d82ea45eb680fc66bf73ac5e50dffMark M. Hoffmanstatic const unsigned short normal_i2c[] = { 0x2d, I2C_CLIENT_END };
531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Insmod parameters */
55f4b50261207c987913f076d867c2e154d71fd012Jean DelvareI2C_CLIENT_INSMOD_1(asb100);
563aed198c35567e5a721f52c0bde23167867e6af6Jean Delvare
573aed198c35567e5a721f52c0bde23167867e6af6Jean Delvarestatic unsigned short force_subclients[4];
583aed198c35567e5a721f52c0bde23167867e6af6Jean Delvaremodule_param_array(force_subclients, short, NULL, 0);
593aed198c35567e5a721f52c0bde23167867e6af6Jean DelvareMODULE_PARM_DESC(force_subclients, "List of subclient addresses: "
601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	"{bus, clientaddr, subclientaddr1, subclientaddr2}");
611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Voltage IN registers 0-6 */
631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define ASB100_REG_IN(nr)	(0x20 + (nr))
641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define ASB100_REG_IN_MAX(nr)	(0x2b + (nr * 2))
651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define ASB100_REG_IN_MIN(nr)	(0x2c + (nr * 2))
661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* FAN IN registers 1-3 */
681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define ASB100_REG_FAN(nr)	(0x28 + (nr))
691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define ASB100_REG_FAN_MIN(nr)	(0x3b + (nr))
701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* TEMPERATURE registers 1-4 */
721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic const u16 asb100_reg_temp[]	= {0, 0x27, 0x150, 0x250, 0x17};
731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic const u16 asb100_reg_temp_max[]	= {0, 0x39, 0x155, 0x255, 0x18};
741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic const u16 asb100_reg_temp_hyst[]	= {0, 0x3a, 0x153, 0x253, 0x19};
751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define ASB100_REG_TEMP(nr) (asb100_reg_temp[nr])
771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define ASB100_REG_TEMP_MAX(nr) (asb100_reg_temp_max[nr])
781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define ASB100_REG_TEMP_HYST(nr) (asb100_reg_temp_hyst[nr])
791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define ASB100_REG_TEMP2_CONFIG	0x0152
811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define ASB100_REG_TEMP3_CONFIG	0x0252
821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define ASB100_REG_CONFIG	0x40
851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define ASB100_REG_ALARM1	0x41
861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define ASB100_REG_ALARM2	0x42
871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define ASB100_REG_SMIM1	0x43
881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define ASB100_REG_SMIM2	0x44
891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define ASB100_REG_VID_FANDIV	0x47
901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define ASB100_REG_I2C_ADDR	0x48
911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define ASB100_REG_CHIPID	0x49
921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define ASB100_REG_I2C_SUBADDR	0x4a
931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define ASB100_REG_PIN		0x4b
941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define ASB100_REG_IRQ		0x4c
951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define ASB100_REG_BANK		0x4e
961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define ASB100_REG_CHIPMAN	0x4f
971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define ASB100_REG_WCHIPID	0x58
991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* bit 7 -> enable, bits 0-3 -> duty cycle */
1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define ASB100_REG_PWM1		0x59
1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* CONVERSIONS
1041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   Rounding and limit checking is only done on the TO_REG variants. */
1051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* These constants are a guess, consistent w/ w83781d */
1071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define ASB100_IN_MIN (   0)
1081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define ASB100_IN_MAX (4080)
1091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* IN: 1/1000 V (0V to 4.08V)
1111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   REG: 16mV/bit */
1121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic u8 IN_TO_REG(unsigned val)
1131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned nval = SENSORS_LIMIT(val, ASB100_IN_MIN, ASB100_IN_MAX);
1151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return (nval + 8) / 16;
1161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic unsigned IN_FROM_REG(u8 reg)
1191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return reg * 16;
1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic u8 FAN_TO_REG(long rpm, int div)
1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (rpm == -1)
1261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return 0;
1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (rpm == 0)
1281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return 255;
1291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	rpm = SENSORS_LIMIT(rpm, 1, 1000000);
1301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return SENSORS_LIMIT((1350000 + rpm * div / 2) / (rpm * div), 1, 254);
1311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int FAN_FROM_REG(u8 val, int div)
1341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return val==0 ? -1 : val==255 ? 0 : 1350000/(val*div);
1361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* These constants are a guess, consistent w/ w83781d */
1391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define ASB100_TEMP_MIN (-128000)
1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define ASB100_TEMP_MAX ( 127000)
1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* TEMP: 0.001C/bit (-128C to +127C)
1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   REG: 1C/bit, two's complement */
1445bfedac045082a97e20d47d876071279ef984d28Christian Hohnstaedtstatic u8 TEMP_TO_REG(long temp)
1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int ntemp = SENSORS_LIMIT(temp, ASB100_TEMP_MIN, ASB100_TEMP_MAX);
1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ntemp += (ntemp<0 ? -500 : 500);
1481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return (u8)(ntemp / 1000);
1491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int TEMP_FROM_REG(u8 reg)
1521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return (s8)reg * 1000;
1541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* PWM: 0 - 255 per sensors documentation
1571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   REG: (6.25% duty cycle per bit) */
1581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic u8 ASB100_PWM_TO_REG(int pwm)
1591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	pwm = SENSORS_LIMIT(pwm, 0, 255);
1611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return (u8)(pwm / 16);
1621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int ASB100_PWM_FROM_REG(u8 reg)
1651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return reg * 16;
1671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DIV_FROM_REG(val) (1 << (val))
1701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* FAN DIV: 1, 2, 4, or 8 (defaults to 2)
1721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   REG: 0, 1, 2, or 3 (respectively) (defaults to 1) */
1731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic u8 DIV_TO_REG(long val)
1741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return val==8 ? 3 : val==4 ? 2 : val==1 ? 0 : 1;
1761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* For each registered client, we need to keep some data in memory. That
1791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   data is pointed to by client->data. The structure itself is
1801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   dynamically allocated, at the same time the client itself is allocated. */
1811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct asb100_data {
1821beeffe43311f64df8dd0ab08ff6b1858c58363fTony Jones	struct device *hwmon_dev;
1839a61bf6300533d3b64d7ff29adfec00e596de67dIngo Molnar	struct mutex lock;
1841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1859a61bf6300533d3b64d7ff29adfec00e596de67dIngo Molnar	struct mutex update_lock;
1861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long last_updated;	/* In jiffies */
1871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* array of 2 pointers to subclients */
1891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct i2c_client *lm75[2];
1901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	char valid;		/* !=0 if following fields are valid */
1921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 in[7];		/* Register value */
1931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 in_max[7];		/* Register value */
1941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 in_min[7];		/* Register value */
1951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 fan[3];		/* Register value */
1961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 fan_min[3];		/* Register value */
1971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u16 temp[4];		/* Register value (0 and 3 are u8 only) */
1981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u16 temp_max[4];	/* Register value (0 and 3 are u8 only) */
1991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u16 temp_hyst[4];	/* Register value (0 and 3 are u8 only) */
2001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 fan_div[3];		/* Register encoding, right justified */
2011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 pwm;			/* Register encoding */
2021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 vid;			/* Register encoding, combined */
2031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 alarms;		/* Register encoding, combined */
2041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 vrm;
2051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
2061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int asb100_read_value(struct i2c_client *client, u16 reg);
2081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void asb100_write_value(struct i2c_client *client, u16 reg, u16 val);
2091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
210063675b15608dfbb8404b3a19546d579bd039d02Jean Delvarestatic int asb100_probe(struct i2c_client *client,
211063675b15608dfbb8404b3a19546d579bd039d02Jean Delvare			const struct i2c_device_id *id);
212310ec79210d754afe51e2e4a983e846b60179abdJean Delvarestatic int asb100_detect(struct i2c_client *client,
213063675b15608dfbb8404b3a19546d579bd039d02Jean Delvare			 struct i2c_board_info *info);
214063675b15608dfbb8404b3a19546d579bd039d02Jean Delvarestatic int asb100_remove(struct i2c_client *client);
2151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct asb100_data *asb100_update_device(struct device *dev);
2161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void asb100_init_client(struct i2c_client *client);
2171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
218063675b15608dfbb8404b3a19546d579bd039d02Jean Delvarestatic const struct i2c_device_id asb100_id[] = {
219063675b15608dfbb8404b3a19546d579bd039d02Jean Delvare	{ "asb100", asb100 },
220063675b15608dfbb8404b3a19546d579bd039d02Jean Delvare	{ }
221063675b15608dfbb8404b3a19546d579bd039d02Jean Delvare};
222063675b15608dfbb8404b3a19546d579bd039d02Jean DelvareMODULE_DEVICE_TABLE(i2c, asb100_id);
223063675b15608dfbb8404b3a19546d579bd039d02Jean Delvare
2241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct i2c_driver asb100_driver = {
225063675b15608dfbb8404b3a19546d579bd039d02Jean Delvare	.class		= I2C_CLASS_HWMON,
226cdaf79349c7d24e1d33acb6497849c9e956a33eaLaurent Riffard	.driver = {
227cdaf79349c7d24e1d33acb6497849c9e956a33eaLaurent Riffard		.name	= "asb100",
228cdaf79349c7d24e1d33acb6497849c9e956a33eaLaurent Riffard	},
229063675b15608dfbb8404b3a19546d579bd039d02Jean Delvare	.probe		= asb100_probe,
230063675b15608dfbb8404b3a19546d579bd039d02Jean Delvare	.remove		= asb100_remove,
231063675b15608dfbb8404b3a19546d579bd039d02Jean Delvare	.id_table	= asb100_id,
232063675b15608dfbb8404b3a19546d579bd039d02Jean Delvare	.detect		= asb100_detect,
233063675b15608dfbb8404b3a19546d579bd039d02Jean Delvare	.address_data	= &addr_data,
2341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
2351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 7 Voltages */
2371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define show_in_reg(reg) \
238fad33c5fdae73a75af2f8ecf69147011bd57e28cJean Delvarestatic ssize_t show_##reg(struct device *dev, struct device_attribute *attr, \
239fad33c5fdae73a75af2f8ecf69147011bd57e28cJean Delvare		char *buf) \
2401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ \
241fad33c5fdae73a75af2f8ecf69147011bd57e28cJean Delvare	int nr = to_sensor_dev_attr(attr)->index; \
2421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct asb100_data *data = asb100_update_device(dev); \
2431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return sprintf(buf, "%d\n", IN_FROM_REG(data->reg[nr])); \
2441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsshow_in_reg(in)
2471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsshow_in_reg(in_min)
2481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsshow_in_reg(in_max)
2491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define set_in_reg(REG, reg) \
251fad33c5fdae73a75af2f8ecf69147011bd57e28cJean Delvarestatic ssize_t set_in_##reg(struct device *dev, struct device_attribute *attr, \
252fad33c5fdae73a75af2f8ecf69147011bd57e28cJean Delvare		const char *buf, size_t count) \
2531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ \
254fad33c5fdae73a75af2f8ecf69147011bd57e28cJean Delvare	int nr = to_sensor_dev_attr(attr)->index; \
2551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct i2c_client *client = to_i2c_client(dev); \
2561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct asb100_data *data = i2c_get_clientdata(client); \
2571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long val = simple_strtoul(buf, NULL, 10); \
2581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds \
2599a61bf6300533d3b64d7ff29adfec00e596de67dIngo Molnar	mutex_lock(&data->update_lock); \
2601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	data->in_##reg[nr] = IN_TO_REG(val); \
2611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	asb100_write_value(client, ASB100_REG_IN_##REG(nr), \
2621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		data->in_##reg[nr]); \
2639a61bf6300533d3b64d7ff29adfec00e596de67dIngo Molnar	mutex_unlock(&data->update_lock); \
2641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return count; \
2651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsset_in_reg(MIN, min)
2681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsset_in_reg(MAX, max)
2691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define sysfs_in(offset) \
271fad33c5fdae73a75af2f8ecf69147011bd57e28cJean Delvarestatic SENSOR_DEVICE_ATTR(in##offset##_input, S_IRUGO, \
272fad33c5fdae73a75af2f8ecf69147011bd57e28cJean Delvare		show_in, NULL, offset); \
273fad33c5fdae73a75af2f8ecf69147011bd57e28cJean Delvarestatic SENSOR_DEVICE_ATTR(in##offset##_min, S_IRUGO | S_IWUSR, \
274fad33c5fdae73a75af2f8ecf69147011bd57e28cJean Delvare		show_in_min, set_in_min, offset); \
275fad33c5fdae73a75af2f8ecf69147011bd57e28cJean Delvarestatic SENSOR_DEVICE_ATTR(in##offset##_max, S_IRUGO | S_IWUSR, \
276fad33c5fdae73a75af2f8ecf69147011bd57e28cJean Delvare		show_in_max, set_in_max, offset)
2771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssysfs_in(0);
2791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssysfs_in(1);
2801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssysfs_in(2);
2811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssysfs_in(3);
2821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssysfs_in(4);
2831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssysfs_in(5);
2841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssysfs_in(6);
2851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 3 Fans */
287fad33c5fdae73a75af2f8ecf69147011bd57e28cJean Delvarestatic ssize_t show_fan(struct device *dev, struct device_attribute *attr,
288fad33c5fdae73a75af2f8ecf69147011bd57e28cJean Delvare		char *buf)
2891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
290fad33c5fdae73a75af2f8ecf69147011bd57e28cJean Delvare	int nr = to_sensor_dev_attr(attr)->index;
2911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct asb100_data *data = asb100_update_device(dev);
2921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return sprintf(buf, "%d\n", FAN_FROM_REG(data->fan[nr],
2931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		DIV_FROM_REG(data->fan_div[nr])));
2941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
296fad33c5fdae73a75af2f8ecf69147011bd57e28cJean Delvarestatic ssize_t show_fan_min(struct device *dev, struct device_attribute *attr,
297fad33c5fdae73a75af2f8ecf69147011bd57e28cJean Delvare		char *buf)
2981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
299fad33c5fdae73a75af2f8ecf69147011bd57e28cJean Delvare	int nr = to_sensor_dev_attr(attr)->index;
3001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct asb100_data *data = asb100_update_device(dev);
3011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return sprintf(buf, "%d\n", FAN_FROM_REG(data->fan_min[nr],
3021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		DIV_FROM_REG(data->fan_div[nr])));
3031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
3041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
305fad33c5fdae73a75af2f8ecf69147011bd57e28cJean Delvarestatic ssize_t show_fan_div(struct device *dev, struct device_attribute *attr,
306fad33c5fdae73a75af2f8ecf69147011bd57e28cJean Delvare		char *buf)
3071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
308fad33c5fdae73a75af2f8ecf69147011bd57e28cJean Delvare	int nr = to_sensor_dev_attr(attr)->index;
3091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct asb100_data *data = asb100_update_device(dev);
3101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return sprintf(buf, "%d\n", DIV_FROM_REG(data->fan_div[nr]));
3111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
3121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
313fad33c5fdae73a75af2f8ecf69147011bd57e28cJean Delvarestatic ssize_t set_fan_min(struct device *dev, struct device_attribute *attr,
314fad33c5fdae73a75af2f8ecf69147011bd57e28cJean Delvare		const char *buf, size_t count)
3151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
316fad33c5fdae73a75af2f8ecf69147011bd57e28cJean Delvare	int nr = to_sensor_dev_attr(attr)->index;
3171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct i2c_client *client = to_i2c_client(dev);
3181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct asb100_data *data = i2c_get_clientdata(client);
3191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 val = simple_strtoul(buf, NULL, 10);
3201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3219a61bf6300533d3b64d7ff29adfec00e596de67dIngo Molnar	mutex_lock(&data->update_lock);
3221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	data->fan_min[nr] = FAN_TO_REG(val, DIV_FROM_REG(data->fan_div[nr]));
3231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	asb100_write_value(client, ASB100_REG_FAN_MIN(nr), data->fan_min[nr]);
3249a61bf6300533d3b64d7ff29adfec00e596de67dIngo Molnar	mutex_unlock(&data->update_lock);
3251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return count;
3261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
3271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Note: we save and restore the fan minimum here, because its value is
3291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   determined in part by the fan divisor.  This follows the principle of
330d6e05edc59ecd79e8badf440c0d295a979bdfa3eAndreas Mohr   least surprise; the user doesn't expect the fan minimum to change just
3311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   because the divisor changed. */
332fad33c5fdae73a75af2f8ecf69147011bd57e28cJean Delvarestatic ssize_t set_fan_div(struct device *dev, struct device_attribute *attr,
333fad33c5fdae73a75af2f8ecf69147011bd57e28cJean Delvare		const char *buf, size_t count)
3341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
335fad33c5fdae73a75af2f8ecf69147011bd57e28cJean Delvare	int nr = to_sensor_dev_attr(attr)->index;
3361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct i2c_client *client = to_i2c_client(dev);
3371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct asb100_data *data = i2c_get_clientdata(client);
3381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long min;
3391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long val = simple_strtoul(buf, NULL, 10);
3401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int reg;
341af221931519571028c98cf7c7030dd973a524011Jean Delvare
3429a61bf6300533d3b64d7ff29adfec00e596de67dIngo Molnar	mutex_lock(&data->update_lock);
3431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	min = FAN_FROM_REG(data->fan_min[nr],
3451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			DIV_FROM_REG(data->fan_div[nr]));
3461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	data->fan_div[nr] = DIV_TO_REG(val);
3471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
348af221931519571028c98cf7c7030dd973a524011Jean Delvare	switch (nr) {
3491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case 0:	/* fan 1 */
3501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		reg = asb100_read_value(client, ASB100_REG_VID_FANDIV);
3511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		reg = (reg & 0xcf) | (data->fan_div[0] << 4);
3521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		asb100_write_value(client, ASB100_REG_VID_FANDIV, reg);
3531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
3541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case 1:	/* fan 2 */
3561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		reg = asb100_read_value(client, ASB100_REG_VID_FANDIV);
3571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		reg = (reg & 0x3f) | (data->fan_div[1] << 6);
3581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		asb100_write_value(client, ASB100_REG_VID_FANDIV, reg);
3591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
3601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case 2:	/* fan 3 */
3621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		reg = asb100_read_value(client, ASB100_REG_PIN);
3631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		reg = (reg & 0x3f) | (data->fan_div[2] << 6);
3641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		asb100_write_value(client, ASB100_REG_PIN, reg);
3651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
3661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	data->fan_min[nr] =
3691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		FAN_TO_REG(min, DIV_FROM_REG(data->fan_div[nr]));
3701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	asb100_write_value(client, ASB100_REG_FAN_MIN(nr), data->fan_min[nr]);
3711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3729a61bf6300533d3b64d7ff29adfec00e596de67dIngo Molnar	mutex_unlock(&data->update_lock);
3731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return count;
3751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
3761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define sysfs_fan(offset) \
378fad33c5fdae73a75af2f8ecf69147011bd57e28cJean Delvarestatic SENSOR_DEVICE_ATTR(fan##offset##_input, S_IRUGO, \
379fad33c5fdae73a75af2f8ecf69147011bd57e28cJean Delvare		show_fan, NULL, offset - 1); \
380fad33c5fdae73a75af2f8ecf69147011bd57e28cJean Delvarestatic SENSOR_DEVICE_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR, \
381fad33c5fdae73a75af2f8ecf69147011bd57e28cJean Delvare		show_fan_min, set_fan_min, offset - 1); \
382fad33c5fdae73a75af2f8ecf69147011bd57e28cJean Delvarestatic SENSOR_DEVICE_ATTR(fan##offset##_div, S_IRUGO | S_IWUSR, \
383fad33c5fdae73a75af2f8ecf69147011bd57e28cJean Delvare		show_fan_div, set_fan_div, offset - 1)
3841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssysfs_fan(1);
3861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssysfs_fan(2);
3871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssysfs_fan(3);
3881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 4 Temp. Sensors */
3901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int sprintf_temp_from_reg(u16 reg, char *buf, int nr)
3911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
3921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int ret = 0;
3931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (nr) {
3951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case 1: case 2:
3961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ret = sprintf(buf, "%d\n", LM75_TEMP_FROM_REG(reg));
3971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
3981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case 0: case 3: default:
3991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ret = sprintf(buf, "%d\n", TEMP_FROM_REG(reg));
4001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
4011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
4021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return ret;
4031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
404af221931519571028c98cf7c7030dd973a524011Jean Delvare
4051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define show_temp_reg(reg) \
406fad33c5fdae73a75af2f8ecf69147011bd57e28cJean Delvarestatic ssize_t show_##reg(struct device *dev, struct device_attribute *attr, \
407fad33c5fdae73a75af2f8ecf69147011bd57e28cJean Delvare		char *buf) \
4081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ \
409fad33c5fdae73a75af2f8ecf69147011bd57e28cJean Delvare	int nr = to_sensor_dev_attr(attr)->index; \
4101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct asb100_data *data = asb100_update_device(dev); \
4111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return sprintf_temp_from_reg(data->reg[nr], buf, nr); \
4121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsshow_temp_reg(temp);
4151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsshow_temp_reg(temp_max);
4161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsshow_temp_reg(temp_hyst);
4171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define set_temp_reg(REG, reg) \
419fad33c5fdae73a75af2f8ecf69147011bd57e28cJean Delvarestatic ssize_t set_##reg(struct device *dev, struct device_attribute *attr, \
420fad33c5fdae73a75af2f8ecf69147011bd57e28cJean Delvare		const char *buf, size_t count) \
4211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ \
422fad33c5fdae73a75af2f8ecf69147011bd57e28cJean Delvare	int nr = to_sensor_dev_attr(attr)->index; \
4231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct i2c_client *client = to_i2c_client(dev); \
4241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct asb100_data *data = i2c_get_clientdata(client); \
4255bfedac045082a97e20d47d876071279ef984d28Christian Hohnstaedt	long val = simple_strtol(buf, NULL, 10); \
4261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds \
4279a61bf6300533d3b64d7ff29adfec00e596de67dIngo Molnar	mutex_lock(&data->update_lock); \
4281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (nr) { \
4291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case 1: case 2: \
4301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		data->reg[nr] = LM75_TEMP_TO_REG(val); \
4311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break; \
4321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case 0: case 3: default: \
4331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		data->reg[nr] = TEMP_TO_REG(val); \
4341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break; \
4351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} \
4361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	asb100_write_value(client, ASB100_REG_TEMP_##REG(nr+1), \
4371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			data->reg[nr]); \
4389a61bf6300533d3b64d7ff29adfec00e596de67dIngo Molnar	mutex_unlock(&data->update_lock); \
4391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return count; \
4401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsset_temp_reg(MAX, temp_max);
4431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsset_temp_reg(HYST, temp_hyst);
4441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define sysfs_temp(num) \
446fad33c5fdae73a75af2f8ecf69147011bd57e28cJean Delvarestatic SENSOR_DEVICE_ATTR(temp##num##_input, S_IRUGO, \
447fad33c5fdae73a75af2f8ecf69147011bd57e28cJean Delvare		show_temp, NULL, num - 1); \
448fad33c5fdae73a75af2f8ecf69147011bd57e28cJean Delvarestatic SENSOR_DEVICE_ATTR(temp##num##_max, S_IRUGO | S_IWUSR, \
449fad33c5fdae73a75af2f8ecf69147011bd57e28cJean Delvare		show_temp_max, set_temp_max, num - 1); \
450fad33c5fdae73a75af2f8ecf69147011bd57e28cJean Delvarestatic SENSOR_DEVICE_ATTR(temp##num##_max_hyst, S_IRUGO | S_IWUSR, \
451fad33c5fdae73a75af2f8ecf69147011bd57e28cJean Delvare		show_temp_hyst, set_temp_hyst, num - 1)
4521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssysfs_temp(1);
4541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssysfs_temp(2);
4551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssysfs_temp(3);
4561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssysfs_temp(4);
4571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* VID */
459af221931519571028c98cf7c7030dd973a524011Jean Delvarestatic ssize_t show_vid(struct device *dev, struct device_attribute *attr,
460af221931519571028c98cf7c7030dd973a524011Jean Delvare		char *buf)
4611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
4621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct asb100_data *data = asb100_update_device(dev);
4631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return sprintf(buf, "%d\n", vid_from_reg(data->vid, data->vrm));
4641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid, NULL);
4671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* VRM */
469af221931519571028c98cf7c7030dd973a524011Jean Delvarestatic ssize_t show_vrm(struct device *dev, struct device_attribute *attr,
470af221931519571028c98cf7c7030dd973a524011Jean Delvare		char *buf)
4711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
47290d6619a916062cb75a176aacb318d108758b4a5Jean Delvare	struct asb100_data *data = dev_get_drvdata(dev);
4731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return sprintf(buf, "%d\n", data->vrm);
4741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
476af221931519571028c98cf7c7030dd973a524011Jean Delvarestatic ssize_t set_vrm(struct device *dev, struct device_attribute *attr,
477af221931519571028c98cf7c7030dd973a524011Jean Delvare		const char *buf, size_t count)
4781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
4798f74efe81d122c071410fd74f42879ef81439fa4Jean Delvare	struct asb100_data *data = dev_get_drvdata(dev);
4808f74efe81d122c071410fd74f42879ef81439fa4Jean Delvare	data->vrm = simple_strtoul(buf, NULL, 10);
4811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return count;
4821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Alarms */
4851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic DEVICE_ATTR(vrm, S_IRUGO | S_IWUSR, show_vrm, set_vrm);
4861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
487af221931519571028c98cf7c7030dd973a524011Jean Delvarestatic ssize_t show_alarms(struct device *dev, struct device_attribute *attr,
488af221931519571028c98cf7c7030dd973a524011Jean Delvare		char *buf)
4891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
4901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct asb100_data *data = asb100_update_device(dev);
49168188ba7de2db9999ff08a4544a78b2f10eb08bdJean Delvare	return sprintf(buf, "%u\n", data->alarms);
4921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL);
4951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
496636866b9f0a72583d2361a897668eb19ff37ded6Jean Delvarestatic ssize_t show_alarm(struct device *dev, struct device_attribute *attr,
497636866b9f0a72583d2361a897668eb19ff37ded6Jean Delvare		char *buf)
498636866b9f0a72583d2361a897668eb19ff37ded6Jean Delvare{
499636866b9f0a72583d2361a897668eb19ff37ded6Jean Delvare	int bitnr = to_sensor_dev_attr(attr)->index;
500636866b9f0a72583d2361a897668eb19ff37ded6Jean Delvare	struct asb100_data *data = asb100_update_device(dev);
501636866b9f0a72583d2361a897668eb19ff37ded6Jean Delvare	return sprintf(buf, "%u\n", (data->alarms >> bitnr) & 1);
502636866b9f0a72583d2361a897668eb19ff37ded6Jean Delvare}
503636866b9f0a72583d2361a897668eb19ff37ded6Jean Delvarestatic SENSOR_DEVICE_ATTR(in0_alarm, S_IRUGO, show_alarm, NULL, 0);
504636866b9f0a72583d2361a897668eb19ff37ded6Jean Delvarestatic SENSOR_DEVICE_ATTR(in1_alarm, S_IRUGO, show_alarm, NULL, 1);
505636866b9f0a72583d2361a897668eb19ff37ded6Jean Delvarestatic SENSOR_DEVICE_ATTR(in2_alarm, S_IRUGO, show_alarm, NULL, 2);
506636866b9f0a72583d2361a897668eb19ff37ded6Jean Delvarestatic SENSOR_DEVICE_ATTR(in3_alarm, S_IRUGO, show_alarm, NULL, 3);
507636866b9f0a72583d2361a897668eb19ff37ded6Jean Delvarestatic SENSOR_DEVICE_ATTR(in4_alarm, S_IRUGO, show_alarm, NULL, 8);
508636866b9f0a72583d2361a897668eb19ff37ded6Jean Delvarestatic SENSOR_DEVICE_ATTR(fan1_alarm, S_IRUGO, show_alarm, NULL, 6);
509636866b9f0a72583d2361a897668eb19ff37ded6Jean Delvarestatic SENSOR_DEVICE_ATTR(fan2_alarm, S_IRUGO, show_alarm, NULL, 7);
510636866b9f0a72583d2361a897668eb19ff37ded6Jean Delvarestatic SENSOR_DEVICE_ATTR(fan3_alarm, S_IRUGO, show_alarm, NULL, 11);
511636866b9f0a72583d2361a897668eb19ff37ded6Jean Delvarestatic SENSOR_DEVICE_ATTR(temp1_alarm, S_IRUGO, show_alarm, NULL, 4);
512636866b9f0a72583d2361a897668eb19ff37ded6Jean Delvarestatic SENSOR_DEVICE_ATTR(temp2_alarm, S_IRUGO, show_alarm, NULL, 5);
513636866b9f0a72583d2361a897668eb19ff37ded6Jean Delvarestatic SENSOR_DEVICE_ATTR(temp3_alarm, S_IRUGO, show_alarm, NULL, 13);
514636866b9f0a72583d2361a897668eb19ff37ded6Jean Delvare
5151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 1 PWM */
516af221931519571028c98cf7c7030dd973a524011Jean Delvarestatic ssize_t show_pwm1(struct device *dev, struct device_attribute *attr,
517af221931519571028c98cf7c7030dd973a524011Jean Delvare		char *buf)
5181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
5191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct asb100_data *data = asb100_update_device(dev);
5201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return sprintf(buf, "%d\n", ASB100_PWM_FROM_REG(data->pwm & 0x0f));
5211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
5221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
523af221931519571028c98cf7c7030dd973a524011Jean Delvarestatic ssize_t set_pwm1(struct device *dev, struct device_attribute *attr,
524af221931519571028c98cf7c7030dd973a524011Jean Delvare		const char *buf, size_t count)
5251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
5261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct i2c_client *client = to_i2c_client(dev);
5271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct asb100_data *data = i2c_get_clientdata(client);
5281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long val = simple_strtoul(buf, NULL, 10);
5291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5309a61bf6300533d3b64d7ff29adfec00e596de67dIngo Molnar	mutex_lock(&data->update_lock);
5311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	data->pwm &= 0x80; /* keep the enable bit */
5321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	data->pwm |= (0x0f & ASB100_PWM_TO_REG(val));
5331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	asb100_write_value(client, ASB100_REG_PWM1, data->pwm);
5349a61bf6300533d3b64d7ff29adfec00e596de67dIngo Molnar	mutex_unlock(&data->update_lock);
5351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return count;
5361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
5371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
538af221931519571028c98cf7c7030dd973a524011Jean Delvarestatic ssize_t show_pwm_enable1(struct device *dev,
539af221931519571028c98cf7c7030dd973a524011Jean Delvare		struct device_attribute *attr, char *buf)
5401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
5411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct asb100_data *data = asb100_update_device(dev);
5421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return sprintf(buf, "%d\n", (data->pwm & 0x80) ? 1 : 0);
5431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
5441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
545af221931519571028c98cf7c7030dd973a524011Jean Delvarestatic ssize_t set_pwm_enable1(struct device *dev,
546af221931519571028c98cf7c7030dd973a524011Jean Delvare		struct device_attribute *attr, const char *buf, size_t count)
5471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
5481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct i2c_client *client = to_i2c_client(dev);
5491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct asb100_data *data = i2c_get_clientdata(client);
5501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long val = simple_strtoul(buf, NULL, 10);
5511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5529a61bf6300533d3b64d7ff29adfec00e596de67dIngo Molnar	mutex_lock(&data->update_lock);
5531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	data->pwm &= 0x0f; /* keep the duty cycle bits */
5541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	data->pwm |= (val ? 0x80 : 0x00);
5551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	asb100_write_value(client, ASB100_REG_PWM1, data->pwm);
5569a61bf6300533d3b64d7ff29adfec00e596de67dIngo Molnar	mutex_unlock(&data->update_lock);
5571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return count;
5581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
5591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic DEVICE_ATTR(pwm1, S_IRUGO | S_IWUSR, show_pwm1, set_pwm1);
5611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic DEVICE_ATTR(pwm1_enable, S_IRUGO | S_IWUSR,
5621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		show_pwm_enable1, set_pwm_enable1);
563c1685f61b0a3110b701d09b84a9f9a3d4e9ef2e2Mark M. Hoffman
564c1685f61b0a3110b701d09b84a9f9a3d4e9ef2e2Mark M. Hoffmanstatic struct attribute *asb100_attributes[] = {
565fad33c5fdae73a75af2f8ecf69147011bd57e28cJean Delvare	&sensor_dev_attr_in0_input.dev_attr.attr,
566fad33c5fdae73a75af2f8ecf69147011bd57e28cJean Delvare	&sensor_dev_attr_in0_min.dev_attr.attr,
567fad33c5fdae73a75af2f8ecf69147011bd57e28cJean Delvare	&sensor_dev_attr_in0_max.dev_attr.attr,
568fad33c5fdae73a75af2f8ecf69147011bd57e28cJean Delvare	&sensor_dev_attr_in1_input.dev_attr.attr,
569fad33c5fdae73a75af2f8ecf69147011bd57e28cJean Delvare	&sensor_dev_attr_in1_min.dev_attr.attr,
570fad33c5fdae73a75af2f8ecf69147011bd57e28cJean Delvare	&sensor_dev_attr_in1_max.dev_attr.attr,
571fad33c5fdae73a75af2f8ecf69147011bd57e28cJean Delvare	&sensor_dev_attr_in2_input.dev_attr.attr,
572fad33c5fdae73a75af2f8ecf69147011bd57e28cJean Delvare	&sensor_dev_attr_in2_min.dev_attr.attr,
573fad33c5fdae73a75af2f8ecf69147011bd57e28cJean Delvare	&sensor_dev_attr_in2_max.dev_attr.attr,
574fad33c5fdae73a75af2f8ecf69147011bd57e28cJean Delvare	&sensor_dev_attr_in3_input.dev_attr.attr,
575fad33c5fdae73a75af2f8ecf69147011bd57e28cJean Delvare	&sensor_dev_attr_in3_min.dev_attr.attr,
576fad33c5fdae73a75af2f8ecf69147011bd57e28cJean Delvare	&sensor_dev_attr_in3_max.dev_attr.attr,
577fad33c5fdae73a75af2f8ecf69147011bd57e28cJean Delvare	&sensor_dev_attr_in4_input.dev_attr.attr,
578fad33c5fdae73a75af2f8ecf69147011bd57e28cJean Delvare	&sensor_dev_attr_in4_min.dev_attr.attr,
579fad33c5fdae73a75af2f8ecf69147011bd57e28cJean Delvare	&sensor_dev_attr_in4_max.dev_attr.attr,
580fad33c5fdae73a75af2f8ecf69147011bd57e28cJean Delvare	&sensor_dev_attr_in5_input.dev_attr.attr,
581fad33c5fdae73a75af2f8ecf69147011bd57e28cJean Delvare	&sensor_dev_attr_in5_min.dev_attr.attr,
582fad33c5fdae73a75af2f8ecf69147011bd57e28cJean Delvare	&sensor_dev_attr_in5_max.dev_attr.attr,
583fad33c5fdae73a75af2f8ecf69147011bd57e28cJean Delvare	&sensor_dev_attr_in6_input.dev_attr.attr,
584fad33c5fdae73a75af2f8ecf69147011bd57e28cJean Delvare	&sensor_dev_attr_in6_min.dev_attr.attr,
585fad33c5fdae73a75af2f8ecf69147011bd57e28cJean Delvare	&sensor_dev_attr_in6_max.dev_attr.attr,
586fad33c5fdae73a75af2f8ecf69147011bd57e28cJean Delvare
587fad33c5fdae73a75af2f8ecf69147011bd57e28cJean Delvare	&sensor_dev_attr_fan1_input.dev_attr.attr,
588fad33c5fdae73a75af2f8ecf69147011bd57e28cJean Delvare	&sensor_dev_attr_fan1_min.dev_attr.attr,
589fad33c5fdae73a75af2f8ecf69147011bd57e28cJean Delvare	&sensor_dev_attr_fan1_div.dev_attr.attr,
590fad33c5fdae73a75af2f8ecf69147011bd57e28cJean Delvare	&sensor_dev_attr_fan2_input.dev_attr.attr,
591fad33c5fdae73a75af2f8ecf69147011bd57e28cJean Delvare	&sensor_dev_attr_fan2_min.dev_attr.attr,
592fad33c5fdae73a75af2f8ecf69147011bd57e28cJean Delvare	&sensor_dev_attr_fan2_div.dev_attr.attr,
593fad33c5fdae73a75af2f8ecf69147011bd57e28cJean Delvare	&sensor_dev_attr_fan3_input.dev_attr.attr,
594fad33c5fdae73a75af2f8ecf69147011bd57e28cJean Delvare	&sensor_dev_attr_fan3_min.dev_attr.attr,
595fad33c5fdae73a75af2f8ecf69147011bd57e28cJean Delvare	&sensor_dev_attr_fan3_div.dev_attr.attr,
596fad33c5fdae73a75af2f8ecf69147011bd57e28cJean Delvare
597fad33c5fdae73a75af2f8ecf69147011bd57e28cJean Delvare	&sensor_dev_attr_temp1_input.dev_attr.attr,
598fad33c5fdae73a75af2f8ecf69147011bd57e28cJean Delvare	&sensor_dev_attr_temp1_max.dev_attr.attr,
599fad33c5fdae73a75af2f8ecf69147011bd57e28cJean Delvare	&sensor_dev_attr_temp1_max_hyst.dev_attr.attr,
600fad33c5fdae73a75af2f8ecf69147011bd57e28cJean Delvare	&sensor_dev_attr_temp2_input.dev_attr.attr,
601fad33c5fdae73a75af2f8ecf69147011bd57e28cJean Delvare	&sensor_dev_attr_temp2_max.dev_attr.attr,
602fad33c5fdae73a75af2f8ecf69147011bd57e28cJean Delvare	&sensor_dev_attr_temp2_max_hyst.dev_attr.attr,
603fad33c5fdae73a75af2f8ecf69147011bd57e28cJean Delvare	&sensor_dev_attr_temp3_input.dev_attr.attr,
604fad33c5fdae73a75af2f8ecf69147011bd57e28cJean Delvare	&sensor_dev_attr_temp3_max.dev_attr.attr,
605fad33c5fdae73a75af2f8ecf69147011bd57e28cJean Delvare	&sensor_dev_attr_temp3_max_hyst.dev_attr.attr,
606fad33c5fdae73a75af2f8ecf69147011bd57e28cJean Delvare	&sensor_dev_attr_temp4_input.dev_attr.attr,
607fad33c5fdae73a75af2f8ecf69147011bd57e28cJean Delvare	&sensor_dev_attr_temp4_max.dev_attr.attr,
608fad33c5fdae73a75af2f8ecf69147011bd57e28cJean Delvare	&sensor_dev_attr_temp4_max_hyst.dev_attr.attr,
609c1685f61b0a3110b701d09b84a9f9a3d4e9ef2e2Mark M. Hoffman
610636866b9f0a72583d2361a897668eb19ff37ded6Jean Delvare	&sensor_dev_attr_in0_alarm.dev_attr.attr,
611636866b9f0a72583d2361a897668eb19ff37ded6Jean Delvare	&sensor_dev_attr_in1_alarm.dev_attr.attr,
612636866b9f0a72583d2361a897668eb19ff37ded6Jean Delvare	&sensor_dev_attr_in2_alarm.dev_attr.attr,
613636866b9f0a72583d2361a897668eb19ff37ded6Jean Delvare	&sensor_dev_attr_in3_alarm.dev_attr.attr,
614636866b9f0a72583d2361a897668eb19ff37ded6Jean Delvare	&sensor_dev_attr_in4_alarm.dev_attr.attr,
615636866b9f0a72583d2361a897668eb19ff37ded6Jean Delvare	&sensor_dev_attr_fan1_alarm.dev_attr.attr,
616636866b9f0a72583d2361a897668eb19ff37ded6Jean Delvare	&sensor_dev_attr_fan2_alarm.dev_attr.attr,
617636866b9f0a72583d2361a897668eb19ff37ded6Jean Delvare	&sensor_dev_attr_fan3_alarm.dev_attr.attr,
618636866b9f0a72583d2361a897668eb19ff37ded6Jean Delvare	&sensor_dev_attr_temp1_alarm.dev_attr.attr,
619636866b9f0a72583d2361a897668eb19ff37ded6Jean Delvare	&sensor_dev_attr_temp2_alarm.dev_attr.attr,
620636866b9f0a72583d2361a897668eb19ff37ded6Jean Delvare	&sensor_dev_attr_temp3_alarm.dev_attr.attr,
621636866b9f0a72583d2361a897668eb19ff37ded6Jean Delvare
622c1685f61b0a3110b701d09b84a9f9a3d4e9ef2e2Mark M. Hoffman	&dev_attr_cpu0_vid.attr,
623c1685f61b0a3110b701d09b84a9f9a3d4e9ef2e2Mark M. Hoffman	&dev_attr_vrm.attr,
624c1685f61b0a3110b701d09b84a9f9a3d4e9ef2e2Mark M. Hoffman	&dev_attr_alarms.attr,
625c1685f61b0a3110b701d09b84a9f9a3d4e9ef2e2Mark M. Hoffman	&dev_attr_pwm1.attr,
626c1685f61b0a3110b701d09b84a9f9a3d4e9ef2e2Mark M. Hoffman	&dev_attr_pwm1_enable.attr,
627c1685f61b0a3110b701d09b84a9f9a3d4e9ef2e2Mark M. Hoffman
628c1685f61b0a3110b701d09b84a9f9a3d4e9ef2e2Mark M. Hoffman	NULL
629c1685f61b0a3110b701d09b84a9f9a3d4e9ef2e2Mark M. Hoffman};
630c1685f61b0a3110b701d09b84a9f9a3d4e9ef2e2Mark M. Hoffman
631c1685f61b0a3110b701d09b84a9f9a3d4e9ef2e2Mark M. Hoffmanstatic const struct attribute_group asb100_group = {
632c1685f61b0a3110b701d09b84a9f9a3d4e9ef2e2Mark M. Hoffman	.attrs = asb100_attributes,
633c1685f61b0a3110b701d09b84a9f9a3d4e9ef2e2Mark M. Hoffman};
6341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
635063675b15608dfbb8404b3a19546d579bd039d02Jean Delvarestatic int asb100_detect_subclients(struct i2c_client *client)
6361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
6371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int i, id, err;
638063675b15608dfbb8404b3a19546d579bd039d02Jean Delvare	int address = client->addr;
639063675b15608dfbb8404b3a19546d579bd039d02Jean Delvare	unsigned short sc_addr[2];
640af221931519571028c98cf7c7030dd973a524011Jean Delvare	struct asb100_data *data = i2c_get_clientdata(client);
641063675b15608dfbb8404b3a19546d579bd039d02Jean Delvare	struct i2c_adapter *adapter = client->adapter;
6421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	id = i2c_adapter_id(adapter);
6441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (force_subclients[0] == id && force_subclients[1] == address) {
6461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		for (i = 2; i <= 3; i++) {
6471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (force_subclients[i] < 0x48 ||
6481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			    force_subclients[i] > 0x4f) {
649af221931519571028c98cf7c7030dd973a524011Jean Delvare				dev_err(&client->dev, "invalid subclient "
6501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					"address %d; must be 0x48-0x4f\n",
6511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					force_subclients[i]);
6521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				err = -ENODEV;
6531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				goto ERROR_SC_2;
6541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
6551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
656af221931519571028c98cf7c7030dd973a524011Jean Delvare		asb100_write_value(client, ASB100_REG_I2C_SUBADDR,
6571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					(force_subclients[2] & 0x07) |
658af221931519571028c98cf7c7030dd973a524011Jean Delvare					((force_subclients[3] & 0x07) << 4));
659063675b15608dfbb8404b3a19546d579bd039d02Jean Delvare		sc_addr[0] = force_subclients[2];
660063675b15608dfbb8404b3a19546d579bd039d02Jean Delvare		sc_addr[1] = force_subclients[3];
6611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
662af221931519571028c98cf7c7030dd973a524011Jean Delvare		int val = asb100_read_value(client, ASB100_REG_I2C_SUBADDR);
663063675b15608dfbb8404b3a19546d579bd039d02Jean Delvare		sc_addr[0] = 0x48 + (val & 0x07);
664063675b15608dfbb8404b3a19546d579bd039d02Jean Delvare		sc_addr[1] = 0x48 + ((val >> 4) & 0x07);
6651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
6661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
667063675b15608dfbb8404b3a19546d579bd039d02Jean Delvare	if (sc_addr[0] == sc_addr[1]) {
668af221931519571028c98cf7c7030dd973a524011Jean Delvare		dev_err(&client->dev, "duplicate addresses 0x%x "
669063675b15608dfbb8404b3a19546d579bd039d02Jean Delvare				"for subclients\n", sc_addr[0]);
6701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		err = -ENODEV;
6711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto ERROR_SC_2;
6721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
6731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
674063675b15608dfbb8404b3a19546d579bd039d02Jean Delvare	data->lm75[0] = i2c_new_dummy(adapter, sc_addr[0]);
675063675b15608dfbb8404b3a19546d579bd039d02Jean Delvare	if (!data->lm75[0]) {
676af221931519571028c98cf7c7030dd973a524011Jean Delvare		dev_err(&client->dev, "subclient %d registration "
677063675b15608dfbb8404b3a19546d579bd039d02Jean Delvare			"at address 0x%x failed.\n", 1, sc_addr[0]);
678063675b15608dfbb8404b3a19546d579bd039d02Jean Delvare		err = -ENOMEM;
6791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto ERROR_SC_2;
6801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
6811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
682063675b15608dfbb8404b3a19546d579bd039d02Jean Delvare	data->lm75[1] = i2c_new_dummy(adapter, sc_addr[1]);
683063675b15608dfbb8404b3a19546d579bd039d02Jean Delvare	if (!data->lm75[1]) {
684af221931519571028c98cf7c7030dd973a524011Jean Delvare		dev_err(&client->dev, "subclient %d registration "
685063675b15608dfbb8404b3a19546d579bd039d02Jean Delvare			"at address 0x%x failed.\n", 2, sc_addr[1]);
686063675b15608dfbb8404b3a19546d579bd039d02Jean Delvare		err = -ENOMEM;
6871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto ERROR_SC_3;
6881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
6891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
6911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Undo inits in case of errors */
6931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsERROR_SC_3:
694063675b15608dfbb8404b3a19546d579bd039d02Jean Delvare	i2c_unregister_device(data->lm75[0]);
6951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsERROR_SC_2:
6961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return err;
6971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
6981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
699063675b15608dfbb8404b3a19546d579bd039d02Jean Delvare/* Return 0 if detection is successful, -ENODEV otherwise */
700310ec79210d754afe51e2e4a983e846b60179abdJean Delvarestatic int asb100_detect(struct i2c_client *client,
701063675b15608dfbb8404b3a19546d579bd039d02Jean Delvare			 struct i2c_board_info *info)
7021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
703063675b15608dfbb8404b3a19546d579bd039d02Jean Delvare	struct i2c_adapter *adapter = client->adapter;
70452df6440a29123eed912183fe785bbe174ef14b9Jean Delvare	int val1, val2;
7051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) {
7071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		pr_debug("asb100.o: detect failed, "
7081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				"smbus byte data not supported!\n");
709063675b15608dfbb8404b3a19546d579bd039d02Jean Delvare		return -ENODEV;
7101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
7111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
71252df6440a29123eed912183fe785bbe174ef14b9Jean Delvare	val1 = i2c_smbus_read_byte_data(client, ASB100_REG_BANK);
71352df6440a29123eed912183fe785bbe174ef14b9Jean Delvare	val2 = i2c_smbus_read_byte_data(client, ASB100_REG_CHIPMAN);
7141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
71552df6440a29123eed912183fe785bbe174ef14b9Jean Delvare	/* If we're in bank 0 */
71652df6440a29123eed912183fe785bbe174ef14b9Jean Delvare	if ((!(val1 & 0x07)) &&
71752df6440a29123eed912183fe785bbe174ef14b9Jean Delvare			/* Check for ASB100 ID (low byte) */
71852df6440a29123eed912183fe785bbe174ef14b9Jean Delvare			(((!(val1 & 0x80)) && (val2 != 0x94)) ||
71952df6440a29123eed912183fe785bbe174ef14b9Jean Delvare			/* Check for ASB100 ID (high byte ) */
72052df6440a29123eed912183fe785bbe174ef14b9Jean Delvare			((val1 & 0x80) && (val2 != 0x06)))) {
72152df6440a29123eed912183fe785bbe174ef14b9Jean Delvare		pr_debug("asb100: detect failed, bad chip id 0x%02x!\n", val2);
72252df6440a29123eed912183fe785bbe174ef14b9Jean Delvare		return -ENODEV;
72352df6440a29123eed912183fe785bbe174ef14b9Jean Delvare	}
7241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
72552df6440a29123eed912183fe785bbe174ef14b9Jean Delvare	/* Put it now into bank 0 and Vendor ID High Byte */
726063675b15608dfbb8404b3a19546d579bd039d02Jean Delvare	i2c_smbus_write_byte_data(client, ASB100_REG_BANK,
727063675b15608dfbb8404b3a19546d579bd039d02Jean Delvare		(i2c_smbus_read_byte_data(client, ASB100_REG_BANK) & 0x78)
728063675b15608dfbb8404b3a19546d579bd039d02Jean Delvare		| 0x80);
7291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Determine the chip type. */
73152df6440a29123eed912183fe785bbe174ef14b9Jean Delvare	val1 = i2c_smbus_read_byte_data(client, ASB100_REG_WCHIPID);
73252df6440a29123eed912183fe785bbe174ef14b9Jean Delvare	val2 = i2c_smbus_read_byte_data(client, ASB100_REG_CHIPMAN);
73352df6440a29123eed912183fe785bbe174ef14b9Jean Delvare
73452df6440a29123eed912183fe785bbe174ef14b9Jean Delvare	if (val1 != 0x31 || val2 != 0x06)
73552df6440a29123eed912183fe785bbe174ef14b9Jean Delvare		return -ENODEV;
7361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
737063675b15608dfbb8404b3a19546d579bd039d02Jean Delvare	strlcpy(info->type, "asb100", I2C_NAME_SIZE);
7381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
739063675b15608dfbb8404b3a19546d579bd039d02Jean Delvare	return 0;
740063675b15608dfbb8404b3a19546d579bd039d02Jean Delvare}
741063675b15608dfbb8404b3a19546d579bd039d02Jean Delvare
742063675b15608dfbb8404b3a19546d579bd039d02Jean Delvarestatic int asb100_probe(struct i2c_client *client,
743063675b15608dfbb8404b3a19546d579bd039d02Jean Delvare			const struct i2c_device_id *id)
744063675b15608dfbb8404b3a19546d579bd039d02Jean Delvare{
745063675b15608dfbb8404b3a19546d579bd039d02Jean Delvare	int err;
746063675b15608dfbb8404b3a19546d579bd039d02Jean Delvare	struct asb100_data *data;
747063675b15608dfbb8404b3a19546d579bd039d02Jean Delvare
748063675b15608dfbb8404b3a19546d579bd039d02Jean Delvare	data = kzalloc(sizeof(struct asb100_data), GFP_KERNEL);
749063675b15608dfbb8404b3a19546d579bd039d02Jean Delvare	if (!data) {
750063675b15608dfbb8404b3a19546d579bd039d02Jean Delvare		pr_debug("asb100.o: probe failed, kzalloc failed!\n");
751063675b15608dfbb8404b3a19546d579bd039d02Jean Delvare		err = -ENOMEM;
752063675b15608dfbb8404b3a19546d579bd039d02Jean Delvare		goto ERROR0;
753063675b15608dfbb8404b3a19546d579bd039d02Jean Delvare	}
754063675b15608dfbb8404b3a19546d579bd039d02Jean Delvare
755063675b15608dfbb8404b3a19546d579bd039d02Jean Delvare	i2c_set_clientdata(client, data);
756063675b15608dfbb8404b3a19546d579bd039d02Jean Delvare	mutex_init(&data->lock);
757063675b15608dfbb8404b3a19546d579bd039d02Jean Delvare	mutex_init(&data->update_lock);
7581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Attach secondary lm75 clients */
760063675b15608dfbb8404b3a19546d579bd039d02Jean Delvare	err = asb100_detect_subclients(client);
761063675b15608dfbb8404b3a19546d579bd039d02Jean Delvare	if (err)
762063675b15608dfbb8404b3a19546d579bd039d02Jean Delvare		goto ERROR1;
7631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Initialize the chip */
765af221931519571028c98cf7c7030dd973a524011Jean Delvare	asb100_init_client(client);
7661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* A few vars need to be filled upon startup */
768af221931519571028c98cf7c7030dd973a524011Jean Delvare	data->fan_min[0] = asb100_read_value(client, ASB100_REG_FAN_MIN(0));
769af221931519571028c98cf7c7030dd973a524011Jean Delvare	data->fan_min[1] = asb100_read_value(client, ASB100_REG_FAN_MIN(1));
770af221931519571028c98cf7c7030dd973a524011Jean Delvare	data->fan_min[2] = asb100_read_value(client, ASB100_REG_FAN_MIN(2));
7711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Register sysfs hooks */
773af221931519571028c98cf7c7030dd973a524011Jean Delvare	if ((err = sysfs_create_group(&client->dev.kobj, &asb100_group)))
774c1685f61b0a3110b701d09b84a9f9a3d4e9ef2e2Mark M. Hoffman		goto ERROR3;
775c1685f61b0a3110b701d09b84a9f9a3d4e9ef2e2Mark M. Hoffman
776af221931519571028c98cf7c7030dd973a524011Jean Delvare	data->hwmon_dev = hwmon_device_register(&client->dev);
7771beeffe43311f64df8dd0ab08ff6b1858c58363fTony Jones	if (IS_ERR(data->hwmon_dev)) {
7781beeffe43311f64df8dd0ab08ff6b1858c58363fTony Jones		err = PTR_ERR(data->hwmon_dev);
779c1685f61b0a3110b701d09b84a9f9a3d4e9ef2e2Mark M. Hoffman		goto ERROR4;
780943b0830cebe4711354945ed3cb44e84152aaca0Mark M. Hoffman	}
781943b0830cebe4711354945ed3cb44e84152aaca0Mark M. Hoffman
7821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
7831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
784c1685f61b0a3110b701d09b84a9f9a3d4e9ef2e2Mark M. HoffmanERROR4:
785af221931519571028c98cf7c7030dd973a524011Jean Delvare	sysfs_remove_group(&client->dev.kobj, &asb100_group);
786943b0830cebe4711354945ed3cb44e84152aaca0Mark M. HoffmanERROR3:
787063675b15608dfbb8404b3a19546d579bd039d02Jean Delvare	i2c_unregister_device(data->lm75[1]);
788063675b15608dfbb8404b3a19546d579bd039d02Jean Delvare	i2c_unregister_device(data->lm75[0]);
7891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsERROR1:
7901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	kfree(data);
7911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsERROR0:
7921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return err;
7931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
7941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
795063675b15608dfbb8404b3a19546d579bd039d02Jean Delvarestatic int asb100_remove(struct i2c_client *client)
7961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
797943b0830cebe4711354945ed3cb44e84152aaca0Mark M. Hoffman	struct asb100_data *data = i2c_get_clientdata(client);
798943b0830cebe4711354945ed3cb44e84152aaca0Mark M. Hoffman
799063675b15608dfbb8404b3a19546d579bd039d02Jean Delvare	hwmon_device_unregister(data->hwmon_dev);
800063675b15608dfbb8404b3a19546d579bd039d02Jean Delvare	sysfs_remove_group(&client->dev.kobj, &asb100_group);
8011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
802063675b15608dfbb8404b3a19546d579bd039d02Jean Delvare	i2c_unregister_device(data->lm75[1]);
803063675b15608dfbb8404b3a19546d579bd039d02Jean Delvare	i2c_unregister_device(data->lm75[0]);
804943b0830cebe4711354945ed3cb44e84152aaca0Mark M. Hoffman
805063675b15608dfbb8404b3a19546d579bd039d02Jean Delvare	kfree(data);
8061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
8081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
8091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* The SMBus locks itself, usually, but nothing may access the chip between
8111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   bank switches. */
8121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int asb100_read_value(struct i2c_client *client, u16 reg)
8131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
8141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct asb100_data *data = i2c_get_clientdata(client);
8151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct i2c_client *cl;
8161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int res, bank;
8171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8189a61bf6300533d3b64d7ff29adfec00e596de67dIngo Molnar	mutex_lock(&data->lock);
8191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	bank = (reg >> 8) & 0x0f;
8211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (bank > 2)
8221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* switch banks */
8231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		i2c_smbus_write_byte_data(client, ASB100_REG_BANK, bank);
8241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (bank == 0 || bank > 2) {
8261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		res = i2c_smbus_read_byte_data(client, reg & 0xff);
8271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
8281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* switch to subclient */
8291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		cl = data->lm75[bank - 1];
8301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* convert from ISA to LM75 I2C addresses */
8321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		switch (reg & 0xff) {
8331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case 0x50: /* TEMP */
834af221931519571028c98cf7c7030dd973a524011Jean Delvare			res = swab16(i2c_smbus_read_word_data(cl, 0));
8351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
8361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case 0x52: /* CONFIG */
8371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			res = i2c_smbus_read_byte_data(cl, 1);
8381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
8391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case 0x53: /* HYST */
840af221931519571028c98cf7c7030dd973a524011Jean Delvare			res = swab16(i2c_smbus_read_word_data(cl, 2));
8411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
8421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case 0x55: /* MAX */
8431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		default:
844af221931519571028c98cf7c7030dd973a524011Jean Delvare			res = swab16(i2c_smbus_read_word_data(cl, 3));
8451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
8461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
8471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
8481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (bank > 2)
8501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		i2c_smbus_write_byte_data(client, ASB100_REG_BANK, 0);
8511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8529a61bf6300533d3b64d7ff29adfec00e596de67dIngo Molnar	mutex_unlock(&data->lock);
8531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return res;
8551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
8561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void asb100_write_value(struct i2c_client *client, u16 reg, u16 value)
8581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
8591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct asb100_data *data = i2c_get_clientdata(client);
8601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct i2c_client *cl;
8611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int bank;
8621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8639a61bf6300533d3b64d7ff29adfec00e596de67dIngo Molnar	mutex_lock(&data->lock);
8641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	bank = (reg >> 8) & 0x0f;
8661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (bank > 2)
8671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* switch banks */
8681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		i2c_smbus_write_byte_data(client, ASB100_REG_BANK, bank);
8691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (bank == 0 || bank > 2) {
8711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		i2c_smbus_write_byte_data(client, reg & 0xff, value & 0xff);
8721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
8731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* switch to subclient */
8741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		cl = data->lm75[bank - 1];
8751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* convert from ISA to LM75 I2C addresses */
8771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		switch (reg & 0xff) {
8781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case 0x52: /* CONFIG */
8791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			i2c_smbus_write_byte_data(cl, 1, value & 0xff);
8801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
8811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case 0x53: /* HYST */
8821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			i2c_smbus_write_word_data(cl, 2, swab16(value));
8831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
8841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case 0x55: /* MAX */
8851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			i2c_smbus_write_word_data(cl, 3, swab16(value));
8861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
8871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
8881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
8891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (bank > 2)
8911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		i2c_smbus_write_byte_data(client, ASB100_REG_BANK, 0);
8921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8939a61bf6300533d3b64d7ff29adfec00e596de67dIngo Molnar	mutex_unlock(&data->lock);
8941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
8951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void asb100_init_client(struct i2c_client *client)
8971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
8981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct asb100_data *data = i2c_get_clientdata(client);
8991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
900303760b44a7a142cb9f4c9df4609fb63bbda98dbJean Delvare	data->vrm = vid_which_vrm();
9011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Start monitoring */
903af221931519571028c98cf7c7030dd973a524011Jean Delvare	asb100_write_value(client, ASB100_REG_CONFIG,
9041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		(asb100_read_value(client, ASB100_REG_CONFIG) & 0xf7) | 0x01);
9051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
9061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct asb100_data *asb100_update_device(struct device *dev)
9081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
9091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct i2c_client *client = to_i2c_client(dev);
9101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct asb100_data *data = i2c_get_clientdata(client);
9111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int i;
9121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9139a61bf6300533d3b64d7ff29adfec00e596de67dIngo Molnar	mutex_lock(&data->update_lock);
9141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (time_after(jiffies, data->last_updated + HZ + HZ / 2)
9161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		|| !data->valid) {
9171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dev_dbg(&client->dev, "starting device update...\n");
9191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* 7 voltage inputs */
9211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		for (i = 0; i < 7; i++) {
9221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			data->in[i] = asb100_read_value(client,
9231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				ASB100_REG_IN(i));
9241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			data->in_min[i] = asb100_read_value(client,
9251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				ASB100_REG_IN_MIN(i));
9261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			data->in_max[i] = asb100_read_value(client,
9271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				ASB100_REG_IN_MAX(i));
9281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
9291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* 3 fan inputs */
9311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		for (i = 0; i < 3; i++) {
9321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			data->fan[i] = asb100_read_value(client,
9331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					ASB100_REG_FAN(i));
9341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			data->fan_min[i] = asb100_read_value(client,
9351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					ASB100_REG_FAN_MIN(i));
9361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
9371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* 4 temperature inputs */
9391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		for (i = 1; i <= 4; i++) {
9401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			data->temp[i-1] = asb100_read_value(client,
9411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					ASB100_REG_TEMP(i));
9421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			data->temp_max[i-1] = asb100_read_value(client,
9431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					ASB100_REG_TEMP_MAX(i));
9441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			data->temp_hyst[i-1] = asb100_read_value(client,
9451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					ASB100_REG_TEMP_HYST(i));
9461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
9471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* VID and fan divisors */
9491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		i = asb100_read_value(client, ASB100_REG_VID_FANDIV);
9501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		data->vid = i & 0x0f;
9511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		data->vid |= (asb100_read_value(client,
9521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				ASB100_REG_CHIPID) & 0x01) << 4;
9531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		data->fan_div[0] = (i >> 4) & 0x03;
9541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		data->fan_div[1] = (i >> 6) & 0x03;
9551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		data->fan_div[2] = (asb100_read_value(client,
9561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				ASB100_REG_PIN) >> 6) & 0x03;
9571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* PWM */
9591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		data->pwm = asb100_read_value(client, ASB100_REG_PWM1);
9601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* alarms */
9621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		data->alarms = asb100_read_value(client, ASB100_REG_ALARM1) +
9631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			(asb100_read_value(client, ASB100_REG_ALARM2) << 8);
9641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		data->last_updated = jiffies;
9661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		data->valid = 1;
9671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dev_dbg(&client->dev, "... device update complete\n");
9691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
9701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9719a61bf6300533d3b64d7ff29adfec00e596de67dIngo Molnar	mutex_unlock(&data->update_lock);
9721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return data;
9741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
9751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int __init asb100_init(void)
9771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
9781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return i2c_add_driver(&asb100_driver);
9791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
9801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void __exit asb100_exit(void)
9821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
9831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	i2c_del_driver(&asb100_driver);
9841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
9851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_AUTHOR("Mark M. Hoffman <mhoffman@lightlink.com>");
9871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_DESCRIPTION("ASB100 Bach driver");
9881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_LICENSE("GPL");
9891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_init(asb100_init);
9911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_exit(asb100_exit);
992