1ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger/*
2ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger * vt1211.c - driver for the VIA VT1211 Super-I/O chip integrated hardware
3ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger *            monitoring features
4ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger * Copyright (C) 2006 Juerg Haefliger <juergh@gmail.com>
5ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger *
6ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger * This driver is based on the driver for kernel 2.4 by Mark D. Studebaker
7ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger * and its port to kernel 2.6 by Lars Ekman.
8ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger *
9ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger * This program is free software; you can redistribute it and/or modify
10ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger * it under the terms of the GNU General Public License as published by
11ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger * the Free Software Foundation; either version 2 of the License, or
12ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger * (at your option) any later version.
13ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger *
14ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger * This program is distributed in the hope that it will be useful,
15ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger * but WITHOUT ANY WARRANTY; without even the implied warranty of
16ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger * GNU General Public License for more details.
18ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger *
19ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger * You should have received a copy of the GNU General Public License
20ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger * along with this program; if not, write to the Free Software
21ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger */
23ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger
245ed9ba6b87545d21b48e50a028bfb79f9812f89fJoe Perches#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
255ed9ba6b87545d21b48e50a028bfb79f9812f89fJoe Perches
26ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger#include <linux/module.h>
27ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger#include <linux/init.h>
28ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger#include <linux/slab.h>
29ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger#include <linux/jiffies.h>
30ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger#include <linux/platform_device.h>
31ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger#include <linux/hwmon.h>
32ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger#include <linux/hwmon-sysfs.h>
33ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger#include <linux/hwmon-vid.h>
34ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger#include <linux/err.h>
35ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger#include <linux/mutex.h>
36ce7ee4e80a72d3b1009ca232be8981de93c015f6Jean Delvare#include <linux/ioport.h>
37b9acb64a385c5b26fc392e0d58ac7b8e0a2cd812Jean Delvare#include <linux/acpi.h>
386055fae8aceee41471edfd1876e5617d16e028feH Hartley Sweeten#include <linux/io.h>
39ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger
40ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefligerstatic int uch_config = -1;
41ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefligermodule_param(uch_config, int, 0);
42ab41319eab3b5e600873dc77dff7756970424ca6Juerg HaefligerMODULE_PARM_DESC(uch_config, "Initialize the universal channel configuration");
43ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger
44ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefligerstatic int int_mode = -1;
45ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefligermodule_param(int_mode, int, 0);
46ab41319eab3b5e600873dc77dff7756970424ca6Juerg HaefligerMODULE_PARM_DESC(int_mode, "Force the temperature interrupt mode");
47ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger
4867b671bceb4a8340a30929e9642620d99ed5ad76Jean Delvarestatic unsigned short force_id;
4967b671bceb4a8340a30929e9642620d99ed5ad76Jean Delvaremodule_param(force_id, ushort, 0);
5067b671bceb4a8340a30929e9642620d99ed5ad76Jean DelvareMODULE_PARM_DESC(force_id, "Override the detected device ID");
5167b671bceb4a8340a30929e9642620d99ed5ad76Jean Delvare
52ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefligerstatic struct platform_device *pdev;
53ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger
54ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger#define DRVNAME "vt1211"
55ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger
56ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger/* ---------------------------------------------------------------------
57ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger * Registers
58ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger *
59ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger * The sensors are defined as follows.
60ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger *
61ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger * Sensor          Voltage Mode   Temp Mode   Notes (from the datasheet)
62ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger * --------        ------------   ---------   --------------------------
63ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger * Reading 1                      temp1       Intel thermal diode
64ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger * Reading 3                      temp2       Internal thermal diode
65ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger * UCH1/Reading2   in0            temp3       NTC type thermistor
66ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger * UCH2            in1            temp4       +2.5V
67ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger * UCH3            in2            temp5       VccP
68ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger * UCH4            in3            temp6       +5V
69ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger * UCH5            in4            temp7       +12V
70ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger * 3.3V            in5                        Internal VDD (+3.3V)
71ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger *
72ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger * --------------------------------------------------------------------- */
73ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger
74ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger/* Voltages (in) numbered 0-5 (ix) */
75ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger#define VT1211_REG_IN(ix)		(0x21 + (ix))
76ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger#define VT1211_REG_IN_MIN(ix)		((ix) == 0 ? 0x3e : 0x2a + 2 * (ix))
77ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger#define VT1211_REG_IN_MAX(ix)		((ix) == 0 ? 0x3d : 0x29 + 2 * (ix))
78ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger
79ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger/* Temperatures (temp) numbered 0-6 (ix) */
80ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefligerstatic u8 regtemp[]	= {0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25};
81ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefligerstatic u8 regtempmax[]	= {0x39, 0x1d, 0x3d, 0x2b, 0x2d, 0x2f, 0x31};
82ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefligerstatic u8 regtemphyst[]	= {0x3a, 0x1e, 0x3e, 0x2c, 0x2e, 0x30, 0x32};
83ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger
84ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger/* Fans numbered 0-1 (ix) */
85ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger#define VT1211_REG_FAN(ix)		(0x29 + (ix))
86ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger#define VT1211_REG_FAN_MIN(ix)		(0x3b + (ix))
87ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger#define VT1211_REG_FAN_DIV		 0x47
88ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger
89ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger/* PWMs numbered 0-1 (ix) */
90ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger/* Auto points numbered 0-3 (ap) */
91ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger#define VT1211_REG_PWM(ix)		(0x60 + (ix))
92ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger#define VT1211_REG_PWM_CLK		 0x50
93ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger#define VT1211_REG_PWM_CTL		 0x51
94ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger#define VT1211_REG_PWM_AUTO_TEMP(ap)	(0x55 - (ap))
95ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger#define VT1211_REG_PWM_AUTO_PWM(ix, ap)	(0x58 + 2 * (ix) - (ap))
96ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger
97ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger/* Miscellaneous registers */
98ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger#define VT1211_REG_CONFIG		0x40
99ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger#define VT1211_REG_ALARM1		0x41
100ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger#define VT1211_REG_ALARM2		0x42
101ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger#define VT1211_REG_VID			0x45
102ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger#define VT1211_REG_UCH_CONFIG		0x4a
103ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger#define VT1211_REG_TEMP1_CONFIG		0x4b
104ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger#define VT1211_REG_TEMP2_CONFIG		0x4c
105ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger
106ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger/* In, temp & fan alarm bits */
107ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefligerstatic const u8 bitalarmin[]	= {11, 0, 1, 3, 8, 2, 9};
108ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefligerstatic const u8 bitalarmtemp[]	= {4, 15, 11, 0, 1, 3, 8};
109ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefligerstatic const u8 bitalarmfan[]	= {6, 7};
110ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger
111ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger/* ---------------------------------------------------------------------
112ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger * Data structures and manipulation thereof
113ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger * --------------------------------------------------------------------- */
114ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger
115ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefligerstruct vt1211_data {
116ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	unsigned short addr;
117ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	const char *name;
1181beeffe43311f64df8dd0ab08ff6b1858c58363fTony Jones	struct device *hwmon_dev;
119ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger
120ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	struct mutex update_lock;
121ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	char valid;			/* !=0 if following fields are valid */
122ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	unsigned long last_updated;	/* In jiffies */
123ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger
124ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	/* Register values */
125ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	u8  in[6];
126ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	u8  in_max[6];
127ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	u8  in_min[6];
128ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	u8  temp[7];
129ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	u8  temp_max[7];
130ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	u8  temp_hyst[7];
131ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	u8  fan[2];
132ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	u8  fan_min[2];
133ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	u8  fan_div[2];
134ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	u8  fan_ctl;
135ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	u8  pwm[2];
136ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	u8  pwm_ctl[2];
137ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	u8  pwm_clk;
138ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	u8  pwm_auto_temp[4];
139ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	u8  pwm_auto_pwm[2][4];
140ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	u8  vid;		/* Read once at init time */
141ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	u8  vrm;
142ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	u8  uch_config;		/* Read once at init time */
143ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	u16 alarms;
144ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger};
145ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger
146ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger/* ix = [0-5] */
147ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger#define ISVOLT(ix, uch_config)	((ix) > 4 ? 1 : \
148ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger				 !(((uch_config) >> ((ix) + 2)) & 1))
149ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger
150ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger/* ix = [0-6] */
151ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger#define ISTEMP(ix, uch_config)	((ix) < 2 ? 1 : \
152ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger				 ((uch_config) >> (ix)) & 1)
153ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger
154b162c033480a7ba0433d329f56c142a0ab59049dGuenter Roeck/*
155b162c033480a7ba0433d329f56c142a0ab59049dGuenter Roeck * in5 (ix = 5) is special. It's the internal 3.3V so it's scaled in the
156b162c033480a7ba0433d329f56c142a0ab59049dGuenter Roeck * driver according to the VT1211 BIOS porting guide
157b162c033480a7ba0433d329f56c142a0ab59049dGuenter Roeck */
158ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger#define IN_FROM_REG(ix, reg)	((reg) < 3 ? 0 : (ix) == 5 ? \
159ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger				 (((reg) - 3) * 15882 + 479) / 958 : \
160ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger				 (((reg) - 3) * 10000 + 479) / 958)
161ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger#define IN_TO_REG(ix, val)	(SENSORS_LIMIT((ix) == 5 ? \
162ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger				 ((val) * 958 + 7941) / 15882 + 3 : \
163ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger				 ((val) * 958 + 5000) / 10000 + 3, 0, 255))
164ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger
165b162c033480a7ba0433d329f56c142a0ab59049dGuenter Roeck/*
166b162c033480a7ba0433d329f56c142a0ab59049dGuenter Roeck * temp1 (ix = 0) is an intel thermal diode which is scaled in user space.
167b162c033480a7ba0433d329f56c142a0ab59049dGuenter Roeck * temp2 (ix = 1) is the internal temp diode so it's scaled in the driver
168b162c033480a7ba0433d329f56c142a0ab59049dGuenter Roeck * according to some measurements that I took on an EPIA M10000.
169b162c033480a7ba0433d329f56c142a0ab59049dGuenter Roeck * temp3-7 are thermistor based so the driver returns the voltage measured at
170b162c033480a7ba0433d329f56c142a0ab59049dGuenter Roeck * the pin (range 0V - 2.2V).
171b162c033480a7ba0433d329f56c142a0ab59049dGuenter Roeck */
172ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger#define TEMP_FROM_REG(ix, reg)	((ix) == 0 ? (reg) * 1000 : \
173ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger				 (ix) == 1 ? (reg) < 51 ? 0 : \
174ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger				 ((reg) - 51) * 1000 : \
175ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger				 ((253 - (reg)) * 2200 + 105) / 210)
176ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger#define TEMP_TO_REG(ix, val)	SENSORS_LIMIT( \
177ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger				 ((ix) == 0 ? ((val) + 500) / 1000 : \
178ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger				  (ix) == 1 ? ((val) + 500) / 1000 + 51 : \
179ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger				  253 - ((val) * 210 + 1100) / 2200), 0, 255)
180ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger
181ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger#define DIV_FROM_REG(reg)	(1 << (reg))
182ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger
183ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger#define RPM_FROM_REG(reg, div)	(((reg) == 0) || ((reg) == 255) ? 0 : \
184ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger				 1310720 / (reg) / DIV_FROM_REG(div))
185ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger#define RPM_TO_REG(val, div)	((val) == 0 ? 255 : \
186ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger				 SENSORS_LIMIT((1310720 / (val) / \
187ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger				 DIV_FROM_REG(div)), 1, 254))
188ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger
189ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger/* ---------------------------------------------------------------------
190ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger * Super-I/O constants and functions
191ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger * --------------------------------------------------------------------- */
192ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger
193b162c033480a7ba0433d329f56c142a0ab59049dGuenter Roeck/*
194b162c033480a7ba0433d329f56c142a0ab59049dGuenter Roeck * Configuration index port registers
195b162c033480a7ba0433d329f56c142a0ab59049dGuenter Roeck * The vt1211 can live at 2 different addresses so we need to probe both
196b162c033480a7ba0433d329f56c142a0ab59049dGuenter Roeck */
1972219cd81a6cd186200606693b360c6429c003bb3Juerg Haefliger#define SIO_REG_CIP1		0x2e
1982219cd81a6cd186200606693b360c6429c003bb3Juerg Haefliger#define SIO_REG_CIP2		0x4e
199ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger
200ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger/* Configuration registers */
201ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger#define SIO_VT1211_LDN		0x07	/* logical device number */
202ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger#define SIO_VT1211_DEVID	0x20	/* device ID */
203ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger#define SIO_VT1211_DEVREV	0x21	/* device revision */
204ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger#define SIO_VT1211_ACTIVE	0x30	/* HW monitor active */
205ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger#define SIO_VT1211_BADDR	0x60	/* base I/O address */
206ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger#define SIO_VT1211_ID		0x3c	/* VT1211 device ID */
207ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger
208ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger/* VT1211 logical device numbers */
209ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger#define SIO_VT1211_LDN_HWMON	0x0b	/* HW monitor */
210ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger
2112219cd81a6cd186200606693b360c6429c003bb3Juerg Haefligerstatic inline void superio_outb(int sio_cip, int reg, int val)
212ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger{
2132219cd81a6cd186200606693b360c6429c003bb3Juerg Haefliger	outb(reg, sio_cip);
2142219cd81a6cd186200606693b360c6429c003bb3Juerg Haefliger	outb(val, sio_cip + 1);
215ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger}
216ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger
2172219cd81a6cd186200606693b360c6429c003bb3Juerg Haefligerstatic inline int superio_inb(int sio_cip, int reg)
218ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger{
2192219cd81a6cd186200606693b360c6429c003bb3Juerg Haefliger	outb(reg, sio_cip);
2202219cd81a6cd186200606693b360c6429c003bb3Juerg Haefliger	return inb(sio_cip + 1);
221ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger}
222ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger
2232219cd81a6cd186200606693b360c6429c003bb3Juerg Haefligerstatic inline void superio_select(int sio_cip, int ldn)
224ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger{
2252219cd81a6cd186200606693b360c6429c003bb3Juerg Haefliger	outb(SIO_VT1211_LDN, sio_cip);
2262219cd81a6cd186200606693b360c6429c003bb3Juerg Haefliger	outb(ldn, sio_cip + 1);
227ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger}
228ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger
2292219cd81a6cd186200606693b360c6429c003bb3Juerg Haefligerstatic inline void superio_enter(int sio_cip)
230ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger{
2312219cd81a6cd186200606693b360c6429c003bb3Juerg Haefliger	outb(0x87, sio_cip);
2322219cd81a6cd186200606693b360c6429c003bb3Juerg Haefliger	outb(0x87, sio_cip);
233ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger}
234ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger
2352219cd81a6cd186200606693b360c6429c003bb3Juerg Haefligerstatic inline void superio_exit(int sio_cip)
236ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger{
2372219cd81a6cd186200606693b360c6429c003bb3Juerg Haefliger	outb(0xaa, sio_cip);
238ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger}
239ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger
240ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger/* ---------------------------------------------------------------------
241ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger * Device I/O access
242ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger * --------------------------------------------------------------------- */
243ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger
244ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefligerstatic inline u8 vt1211_read8(struct vt1211_data *data, u8 reg)
245ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger{
246ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	return inb(data->addr + reg);
247ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger}
248ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger
249ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefligerstatic inline void vt1211_write8(struct vt1211_data *data, u8 reg, u8 val)
250ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger{
251ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	outb(val, data->addr + reg);
252ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger}
253ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger
254ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefligerstatic struct vt1211_data *vt1211_update_device(struct device *dev)
255ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger{
256ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	struct vt1211_data *data = dev_get_drvdata(dev);
257ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	int ix, val;
258ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger
259ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	mutex_lock(&data->update_lock);
260ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger
261ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	/* registers cache is refreshed after 1 second */
262ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	if (time_after(jiffies, data->last_updated + HZ) || !data->valid) {
263ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger		/* read VID */
264ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger		data->vid = vt1211_read8(data, VT1211_REG_VID) & 0x1f;
265ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger
266ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger		/* voltage (in) registers */
267ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger		for (ix = 0; ix < ARRAY_SIZE(data->in); ix++) {
268ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger			if (ISVOLT(ix, data->uch_config)) {
269ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger				data->in[ix] = vt1211_read8(data,
270ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger						VT1211_REG_IN(ix));
271ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger				data->in_min[ix] = vt1211_read8(data,
272ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger						VT1211_REG_IN_MIN(ix));
273ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger				data->in_max[ix] = vt1211_read8(data,
274ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger						VT1211_REG_IN_MAX(ix));
275ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger			}
276ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger		}
277ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger
278ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger		/* temp registers */
279ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger		for (ix = 0; ix < ARRAY_SIZE(data->temp); ix++) {
280ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger			if (ISTEMP(ix, data->uch_config)) {
281ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger				data->temp[ix] = vt1211_read8(data,
282ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger						regtemp[ix]);
283ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger				data->temp_max[ix] = vt1211_read8(data,
284ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger						regtempmax[ix]);
285ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger				data->temp_hyst[ix] = vt1211_read8(data,
286ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger						regtemphyst[ix]);
287ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger			}
288ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger		}
289ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger
290ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger		/* fan & pwm registers */
291ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger		for (ix = 0; ix < ARRAY_SIZE(data->fan); ix++) {
292ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger			data->fan[ix] = vt1211_read8(data,
293ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger						VT1211_REG_FAN(ix));
294ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger			data->fan_min[ix] = vt1211_read8(data,
295ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger						VT1211_REG_FAN_MIN(ix));
296ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger			data->pwm[ix] = vt1211_read8(data,
297ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger						VT1211_REG_PWM(ix));
298ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger		}
299ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger		val = vt1211_read8(data, VT1211_REG_FAN_DIV);
300ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger		data->fan_div[0] = (val >> 4) & 3;
301ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger		data->fan_div[1] = (val >> 6) & 3;
302ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger		data->fan_ctl = val & 0xf;
303ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger
304ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger		val = vt1211_read8(data, VT1211_REG_PWM_CTL);
305ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger		data->pwm_ctl[0] = val & 0xf;
306ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger		data->pwm_ctl[1] = (val >> 4) & 0xf;
307ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger
308ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger		data->pwm_clk = vt1211_read8(data, VT1211_REG_PWM_CLK);
309ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger
310ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger		/* pwm & temp auto point registers */
311ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger		data->pwm_auto_pwm[0][1] = vt1211_read8(data,
312ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger						VT1211_REG_PWM_AUTO_PWM(0, 1));
313ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger		data->pwm_auto_pwm[0][2] = vt1211_read8(data,
314ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger						VT1211_REG_PWM_AUTO_PWM(0, 2));
315ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger		data->pwm_auto_pwm[1][1] = vt1211_read8(data,
316ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger						VT1211_REG_PWM_AUTO_PWM(1, 1));
317ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger		data->pwm_auto_pwm[1][2] = vt1211_read8(data,
318ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger						VT1211_REG_PWM_AUTO_PWM(1, 2));
319ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger		for (ix = 0; ix < ARRAY_SIZE(data->pwm_auto_temp); ix++) {
320ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger			data->pwm_auto_temp[ix] = vt1211_read8(data,
321ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger						VT1211_REG_PWM_AUTO_TEMP(ix));
322ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger		}
323ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger
324ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger		/* alarm registers */
325ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger		data->alarms = (vt1211_read8(data, VT1211_REG_ALARM2) << 8) |
326ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger				vt1211_read8(data, VT1211_REG_ALARM1);
327ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger
328ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger		data->last_updated = jiffies;
329ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger		data->valid = 1;
330ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	}
331ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger
332ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	mutex_unlock(&data->update_lock);
333ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger
334ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	return data;
335ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger}
336ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger
337ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger/* ---------------------------------------------------------------------
338ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger * Voltage sysfs interfaces
339ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger * ix = [0-5]
340ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger * --------------------------------------------------------------------- */
341ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger
342ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger#define SHOW_IN_INPUT	0
343ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger#define SHOW_SET_IN_MIN	1
344ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger#define SHOW_SET_IN_MAX	2
345ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger#define SHOW_IN_ALARM	3
346ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger
347ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefligerstatic ssize_t show_in(struct device *dev, struct device_attribute *attr,
348ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger		       char *buf)
349ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger{
350ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	struct vt1211_data *data = vt1211_update_device(dev);
351ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	struct sensor_device_attribute_2 *sensor_attr_2 =
352ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger						to_sensor_dev_attr_2(attr);
353ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	int ix = sensor_attr_2->index;
354ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	int fn = sensor_attr_2->nr;
355ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	int res;
356ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger
357ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	switch (fn) {
358ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	case SHOW_IN_INPUT:
359ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger		res = IN_FROM_REG(ix, data->in[ix]);
360ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger		break;
361ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	case SHOW_SET_IN_MIN:
362ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger		res = IN_FROM_REG(ix, data->in_min[ix]);
363ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger		break;
364ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	case SHOW_SET_IN_MAX:
365ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger		res = IN_FROM_REG(ix, data->in_max[ix]);
366ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger		break;
367ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	case SHOW_IN_ALARM:
368ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger		res = (data->alarms >> bitalarmin[ix]) & 1;
369ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger		break;
370ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	default:
371ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger		res = 0;
372ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger		dev_dbg(dev, "Unknown attr fetch (%d)\n", fn);
373ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	}
374ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger
375ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	return sprintf(buf, "%d\n", res);
376ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger}
377ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger
378ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefligerstatic ssize_t set_in(struct device *dev, struct device_attribute *attr,
379ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger		      const char *buf, size_t count)
380ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger{
381ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	struct vt1211_data *data = dev_get_drvdata(dev);
382ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	struct sensor_device_attribute_2 *sensor_attr_2 =
383ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger						to_sensor_dev_attr_2(attr);
384ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	int ix = sensor_attr_2->index;
385ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	int fn = sensor_attr_2->nr;
386b162c033480a7ba0433d329f56c142a0ab59049dGuenter Roeck	long val;
387b162c033480a7ba0433d329f56c142a0ab59049dGuenter Roeck	int err;
388b162c033480a7ba0433d329f56c142a0ab59049dGuenter Roeck
389b162c033480a7ba0433d329f56c142a0ab59049dGuenter Roeck	err = kstrtol(buf, 10, &val);
390b162c033480a7ba0433d329f56c142a0ab59049dGuenter Roeck	if (err)
391b162c033480a7ba0433d329f56c142a0ab59049dGuenter Roeck		return err;
392ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger
393ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	mutex_lock(&data->update_lock);
394ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	switch (fn) {
395ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	case SHOW_SET_IN_MIN:
396ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger		data->in_min[ix] = IN_TO_REG(ix, val);
397ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger		vt1211_write8(data, VT1211_REG_IN_MIN(ix), data->in_min[ix]);
398ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger		break;
399ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	case SHOW_SET_IN_MAX:
400ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger		data->in_max[ix] = IN_TO_REG(ix, val);
401ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger		vt1211_write8(data, VT1211_REG_IN_MAX(ix), data->in_max[ix]);
402ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger		break;
403ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	default:
404ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger		dev_dbg(dev, "Unknown attr fetch (%d)\n", fn);
405ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	}
406ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	mutex_unlock(&data->update_lock);
407ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger
408ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	return count;
409ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger}
410ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger
411ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger/* ---------------------------------------------------------------------
412ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger * Temperature sysfs interfaces
413ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger * ix = [0-6]
414ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger * --------------------------------------------------------------------- */
415ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger
416ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger#define SHOW_TEMP_INPUT		0
417ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger#define SHOW_SET_TEMP_MAX	1
418ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger#define SHOW_SET_TEMP_MAX_HYST	2
419ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger#define SHOW_TEMP_ALARM		3
420ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger
421ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefligerstatic ssize_t show_temp(struct device *dev, struct device_attribute *attr,
422ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger			 char *buf)
423ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger{
424ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	struct vt1211_data *data = vt1211_update_device(dev);
425ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	struct sensor_device_attribute_2 *sensor_attr_2 =
426ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger						to_sensor_dev_attr_2(attr);
427ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	int ix = sensor_attr_2->index;
428ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	int fn = sensor_attr_2->nr;
429ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	int res;
430ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger
431ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	switch (fn) {
432ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	case SHOW_TEMP_INPUT:
433ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger		res = TEMP_FROM_REG(ix, data->temp[ix]);
434ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger		break;
435ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	case SHOW_SET_TEMP_MAX:
436ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger		res = TEMP_FROM_REG(ix, data->temp_max[ix]);
437ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger		break;
438ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	case SHOW_SET_TEMP_MAX_HYST:
439ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger		res = TEMP_FROM_REG(ix, data->temp_hyst[ix]);
440ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger		break;
441ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	case SHOW_TEMP_ALARM:
442ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger		res = (data->alarms >> bitalarmtemp[ix]) & 1;
443ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger		break;
444ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	default:
445ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger		res = 0;
446ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger		dev_dbg(dev, "Unknown attr fetch (%d)\n", fn);
447ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	}
448ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger
449ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	return sprintf(buf, "%d\n", res);
450ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger}
451ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger
452ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefligerstatic ssize_t set_temp(struct device *dev, struct device_attribute *attr,
453ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger			const char *buf, size_t count)
454ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger{
455ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	struct vt1211_data *data = dev_get_drvdata(dev);
456ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	struct sensor_device_attribute_2 *sensor_attr_2 =
457ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger						to_sensor_dev_attr_2(attr);
458ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	int ix = sensor_attr_2->index;
459ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	int fn = sensor_attr_2->nr;
460b162c033480a7ba0433d329f56c142a0ab59049dGuenter Roeck	long val;
461b162c033480a7ba0433d329f56c142a0ab59049dGuenter Roeck	int err;
462b162c033480a7ba0433d329f56c142a0ab59049dGuenter Roeck
463b162c033480a7ba0433d329f56c142a0ab59049dGuenter Roeck	err = kstrtol(buf, 10, &val);
464b162c033480a7ba0433d329f56c142a0ab59049dGuenter Roeck	if (err)
465b162c033480a7ba0433d329f56c142a0ab59049dGuenter Roeck		return err;
466ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger
467ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	mutex_lock(&data->update_lock);
468ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	switch (fn) {
469ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	case SHOW_SET_TEMP_MAX:
470ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger		data->temp_max[ix] = TEMP_TO_REG(ix, val);
471ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger		vt1211_write8(data, regtempmax[ix],
472ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger			      data->temp_max[ix]);
473ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger		break;
474ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	case SHOW_SET_TEMP_MAX_HYST:
475ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger		data->temp_hyst[ix] = TEMP_TO_REG(ix, val);
476ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger		vt1211_write8(data, regtemphyst[ix],
477ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger			      data->temp_hyst[ix]);
478ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger		break;
479ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	default:
480ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger		dev_dbg(dev, "Unknown attr fetch (%d)\n", fn);
481ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	}
482ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	mutex_unlock(&data->update_lock);
483ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger
484ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	return count;
485ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger}
486ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger
487ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger/* ---------------------------------------------------------------------
488ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger * Fan sysfs interfaces
489ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger * ix = [0-1]
490ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger * --------------------------------------------------------------------- */
491ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger
492ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger#define SHOW_FAN_INPUT		0
493ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger#define SHOW_SET_FAN_MIN	1
494ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger#define SHOW_SET_FAN_DIV	2
495ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger#define SHOW_FAN_ALARM		3
496ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger
497ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefligerstatic ssize_t show_fan(struct device *dev, struct device_attribute *attr,
498ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger			char *buf)
499ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger{
500ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	struct vt1211_data *data = vt1211_update_device(dev);
501ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	struct sensor_device_attribute_2 *sensor_attr_2 =
502ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger						to_sensor_dev_attr_2(attr);
503ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	int ix = sensor_attr_2->index;
504ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	int fn = sensor_attr_2->nr;
505ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	int res;
506ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger
507ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	switch (fn) {
508ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	case SHOW_FAN_INPUT:
509ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger		res = RPM_FROM_REG(data->fan[ix], data->fan_div[ix]);
510ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger		break;
511ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	case SHOW_SET_FAN_MIN:
512ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger		res = RPM_FROM_REG(data->fan_min[ix], data->fan_div[ix]);
513ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger		break;
514ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	case SHOW_SET_FAN_DIV:
515ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger		res = DIV_FROM_REG(data->fan_div[ix]);
516ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger		break;
517ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	case SHOW_FAN_ALARM:
518ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger		res = (data->alarms >> bitalarmfan[ix]) & 1;
519ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger		break;
520ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	default:
521ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger		res = 0;
522ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger		dev_dbg(dev, "Unknown attr fetch (%d)\n", fn);
523ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	}
524ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger
525ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	return sprintf(buf, "%d\n", res);
526ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger}
527ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger
528ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefligerstatic ssize_t set_fan(struct device *dev, struct device_attribute *attr,
529ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger		       const char *buf, size_t count)
530ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger{
531ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	struct vt1211_data *data = dev_get_drvdata(dev);
532ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	struct sensor_device_attribute_2 *sensor_attr_2 =
533ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger						to_sensor_dev_attr_2(attr);
534ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	int ix = sensor_attr_2->index;
535ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	int fn = sensor_attr_2->nr;
536ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	int reg;
537b162c033480a7ba0433d329f56c142a0ab59049dGuenter Roeck	unsigned long val;
538b162c033480a7ba0433d329f56c142a0ab59049dGuenter Roeck	int err;
539b162c033480a7ba0433d329f56c142a0ab59049dGuenter Roeck
540b162c033480a7ba0433d329f56c142a0ab59049dGuenter Roeck	err = kstrtoul(buf, 10, &val);
541b162c033480a7ba0433d329f56c142a0ab59049dGuenter Roeck	if (err)
542b162c033480a7ba0433d329f56c142a0ab59049dGuenter Roeck		return err;
543ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger
544ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	mutex_lock(&data->update_lock);
545ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger
546ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	/* sync the data cache */
547ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	reg = vt1211_read8(data, VT1211_REG_FAN_DIV);
548ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	data->fan_div[0] = (reg >> 4) & 3;
549ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	data->fan_div[1] = (reg >> 6) & 3;
550ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	data->fan_ctl = reg & 0xf;
551ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger
552ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	switch (fn) {
553ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	case SHOW_SET_FAN_MIN:
554ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger		data->fan_min[ix] = RPM_TO_REG(val, data->fan_div[ix]);
555ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger		vt1211_write8(data, VT1211_REG_FAN_MIN(ix),
556ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger			      data->fan_min[ix]);
557ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger		break;
558ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	case SHOW_SET_FAN_DIV:
559ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger		switch (val) {
560b162c033480a7ba0433d329f56c142a0ab59049dGuenter Roeck		case 1:
561b162c033480a7ba0433d329f56c142a0ab59049dGuenter Roeck			data->fan_div[ix] = 0;
562b162c033480a7ba0433d329f56c142a0ab59049dGuenter Roeck			break;
563b162c033480a7ba0433d329f56c142a0ab59049dGuenter Roeck		case 2:
564b162c033480a7ba0433d329f56c142a0ab59049dGuenter Roeck			data->fan_div[ix] = 1;
565b162c033480a7ba0433d329f56c142a0ab59049dGuenter Roeck			break;
566b162c033480a7ba0433d329f56c142a0ab59049dGuenter Roeck		case 4:
567b162c033480a7ba0433d329f56c142a0ab59049dGuenter Roeck			data->fan_div[ix] = 2;
568b162c033480a7ba0433d329f56c142a0ab59049dGuenter Roeck			break;
569b162c033480a7ba0433d329f56c142a0ab59049dGuenter Roeck		case 8:
570b162c033480a7ba0433d329f56c142a0ab59049dGuenter Roeck			data->fan_div[ix] = 3;
571b162c033480a7ba0433d329f56c142a0ab59049dGuenter Roeck			break;
572b162c033480a7ba0433d329f56c142a0ab59049dGuenter Roeck		default:
573b162c033480a7ba0433d329f56c142a0ab59049dGuenter Roeck			count = -EINVAL;
574b162c033480a7ba0433d329f56c142a0ab59049dGuenter Roeck			dev_warn(dev, "fan div value %ld not supported. "
575b162c033480a7ba0433d329f56c142a0ab59049dGuenter Roeck				 "Choose one of 1, 2, 4, or 8.\n", val);
576b162c033480a7ba0433d329f56c142a0ab59049dGuenter Roeck			goto EXIT;
577ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger		}
578ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger		vt1211_write8(data, VT1211_REG_FAN_DIV,
579ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger			      ((data->fan_div[1] << 6) |
580ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger			       (data->fan_div[0] << 4) |
581ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger				data->fan_ctl));
582ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger		break;
583ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	default:
584ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger		dev_dbg(dev, "Unknown attr fetch (%d)\n", fn);
585ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	}
586ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger
587ab41319eab3b5e600873dc77dff7756970424ca6Juerg HaefligerEXIT:
588ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	mutex_unlock(&data->update_lock);
589ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	return count;
590ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger}
591ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger
592ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger/* ---------------------------------------------------------------------
593ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger * PWM sysfs interfaces
594ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger * ix = [0-1]
595ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger * --------------------------------------------------------------------- */
596ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger
597ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger#define SHOW_PWM			0
598ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger#define SHOW_SET_PWM_ENABLE		1
599ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger#define SHOW_SET_PWM_FREQ		2
600ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger#define SHOW_SET_PWM_AUTO_CHANNELS_TEMP	3
601ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger
602ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefligerstatic ssize_t show_pwm(struct device *dev, struct device_attribute *attr,
603ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger			char *buf)
604ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger{
605ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	struct vt1211_data *data = vt1211_update_device(dev);
606ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	struct sensor_device_attribute_2 *sensor_attr_2 =
607ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger						to_sensor_dev_attr_2(attr);
608ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	int ix = sensor_attr_2->index;
609ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	int fn = sensor_attr_2->nr;
610ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	int res;
611ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger
612ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	switch (fn) {
613ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	case SHOW_PWM:
614ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger		res = data->pwm[ix];
615ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger		break;
616ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	case SHOW_SET_PWM_ENABLE:
617ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger		res = ((data->pwm_ctl[ix] >> 3) & 1) ? 2 : 0;
618ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger		break;
619ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	case SHOW_SET_PWM_FREQ:
620ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger		res = 90000 >> (data->pwm_clk & 7);
621ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger		break;
622ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	case SHOW_SET_PWM_AUTO_CHANNELS_TEMP:
623ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger		res = (data->pwm_ctl[ix] & 7) + 1;
624ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger		break;
625ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	default:
626ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger		res = 0;
627ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger		dev_dbg(dev, "Unknown attr fetch (%d)\n", fn);
628ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	}
629ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger
630ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	return sprintf(buf, "%d\n", res);
631ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger}
632ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger
633ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefligerstatic ssize_t set_pwm(struct device *dev, struct device_attribute *attr,
634ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger		       const char *buf, size_t count)
635ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger{
636ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	struct vt1211_data *data = dev_get_drvdata(dev);
637ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	struct sensor_device_attribute_2 *sensor_attr_2 =
638ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger						to_sensor_dev_attr_2(attr);
639ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	int ix = sensor_attr_2->index;
640ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	int fn = sensor_attr_2->nr;
641ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	int tmp, reg;
642b162c033480a7ba0433d329f56c142a0ab59049dGuenter Roeck	unsigned long val;
643b162c033480a7ba0433d329f56c142a0ab59049dGuenter Roeck	int err;
644b162c033480a7ba0433d329f56c142a0ab59049dGuenter Roeck
645b162c033480a7ba0433d329f56c142a0ab59049dGuenter Roeck	err = kstrtoul(buf, 10, &val);
646b162c033480a7ba0433d329f56c142a0ab59049dGuenter Roeck	if (err)
647b162c033480a7ba0433d329f56c142a0ab59049dGuenter Roeck		return err;
648ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger
649ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	mutex_lock(&data->update_lock);
650ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger
651ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	switch (fn) {
652ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	case SHOW_SET_PWM_ENABLE:
653ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger		/* sync the data cache */
654ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger		reg = vt1211_read8(data, VT1211_REG_FAN_DIV);
655ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger		data->fan_div[0] = (reg >> 4) & 3;
656ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger		data->fan_div[1] = (reg >> 6) & 3;
657ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger		data->fan_ctl = reg & 0xf;
658ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger		reg = vt1211_read8(data, VT1211_REG_PWM_CTL);
659ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger		data->pwm_ctl[0] = reg & 0xf;
660ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger		data->pwm_ctl[1] = (reg >> 4) & 0xf;
661ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger		switch (val) {
662ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger		case 0:
663ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger			data->pwm_ctl[ix] &= 7;
664b162c033480a7ba0433d329f56c142a0ab59049dGuenter Roeck			/*
665b162c033480a7ba0433d329f56c142a0ab59049dGuenter Roeck			 * disable SmartGuardian if both PWM outputs are
666b162c033480a7ba0433d329f56c142a0ab59049dGuenter Roeck			 * disabled
667b162c033480a7ba0433d329f56c142a0ab59049dGuenter Roeck			 */
668b162c033480a7ba0433d329f56c142a0ab59049dGuenter Roeck			if ((data->pwm_ctl[ix ^ 1] & 1) == 0)
669ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger				data->fan_ctl &= 0xe;
670ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger			break;
671ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger		case 2:
672ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger			data->pwm_ctl[ix] |= 8;
673ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger			data->fan_ctl |= 1;
674ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger			break;
675ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger		default:
676ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger			count = -EINVAL;
677ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger			dev_warn(dev, "pwm mode %ld not supported. "
678ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger				 "Choose one of 0 or 2.\n", val);
679ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger			goto EXIT;
680ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger		}
681ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger		vt1211_write8(data, VT1211_REG_PWM_CTL,
682ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger			      ((data->pwm_ctl[1] << 4) |
683ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger				data->pwm_ctl[0]));
684ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger		vt1211_write8(data, VT1211_REG_FAN_DIV,
685ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger			      ((data->fan_div[1] << 6) |
686ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger			       (data->fan_div[0] << 4) |
687ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger				data->fan_ctl));
688ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger		break;
689ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	case SHOW_SET_PWM_FREQ:
690ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger		val = 135000 / SENSORS_LIMIT(val, 135000 >> 7, 135000);
691ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger		/* calculate tmp = log2(val) */
692ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger		tmp = 0;
693b162c033480a7ba0433d329f56c142a0ab59049dGuenter Roeck		for (val >>= 1; val > 0; val >>= 1)
694ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger			tmp++;
695ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger		/* sync the data cache */
696ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger		reg = vt1211_read8(data, VT1211_REG_PWM_CLK);
697ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger		data->pwm_clk = (reg & 0xf8) | tmp;
698ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger		vt1211_write8(data, VT1211_REG_PWM_CLK, data->pwm_clk);
699ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger		break;
700ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	case SHOW_SET_PWM_AUTO_CHANNELS_TEMP:
701b162c033480a7ba0433d329f56c142a0ab59049dGuenter Roeck		if (val < 1 || val > 7) {
702ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger			count = -EINVAL;
703ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger			dev_warn(dev, "temp channel %ld not supported. "
704ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger				 "Choose a value between 1 and 7.\n", val);
705ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger			goto EXIT;
706ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger		}
707ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger		if (!ISTEMP(val - 1, data->uch_config)) {
708ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger			count = -EINVAL;
709ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger			dev_warn(dev, "temp channel %ld is not available.\n",
710ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger				 val);
711ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger			goto EXIT;
712ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger		}
713ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger		/* sync the data cache */
714ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger		reg = vt1211_read8(data, VT1211_REG_PWM_CTL);
715ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger		data->pwm_ctl[0] = reg & 0xf;
716ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger		data->pwm_ctl[1] = (reg >> 4) & 0xf;
717ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger		data->pwm_ctl[ix] = (data->pwm_ctl[ix] & 8) | (val - 1);
718ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger		vt1211_write8(data, VT1211_REG_PWM_CTL,
719ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger			      ((data->pwm_ctl[1] << 4) | data->pwm_ctl[0]));
720ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger		break;
721ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	default:
722ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger		dev_dbg(dev, "Unknown attr fetch (%d)\n", fn);
723ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	}
724ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger
725ab41319eab3b5e600873dc77dff7756970424ca6Juerg HaefligerEXIT:
726ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	mutex_unlock(&data->update_lock);
727ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	return count;
728ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger}
729ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger
730ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger/* ---------------------------------------------------------------------
731ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger * PWM auto point definitions
732ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger * ix = [0-1]
733ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger * ap = [0-3]
734ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger * --------------------------------------------------------------------- */
735ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger
736ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger/*
737ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger * pwm[ix+1]_auto_point[ap+1]_temp mapping table:
738ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger * Note that there is only a single set of temp auto points that controls both
739ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger * PWM controllers. We still create 2 sets of sysfs files to make it look
740ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger * more consistent even though they map to the same registers.
741ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger *
742ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger * ix ap : description
743ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger * -------------------
744ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger * 0  0  : pwm1/2 off temperature        (pwm_auto_temp[0])
745ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger * 0  1  : pwm1/2 low speed temperature  (pwm_auto_temp[1])
746ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger * 0  2  : pwm1/2 high speed temperature (pwm_auto_temp[2])
747ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger * 0  3  : pwm1/2 full speed temperature (pwm_auto_temp[3])
748ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger * 1  0  : pwm1/2 off temperature        (pwm_auto_temp[0])
749ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger * 1  1  : pwm1/2 low speed temperature  (pwm_auto_temp[1])
750ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger * 1  2  : pwm1/2 high speed temperature (pwm_auto_temp[2])
751ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger * 1  3  : pwm1/2 full speed temperature (pwm_auto_temp[3])
752ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger */
753ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger
754ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefligerstatic ssize_t show_pwm_auto_point_temp(struct device *dev,
755ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger					struct device_attribute *attr,
756ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger					char *buf)
757ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger{
758ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	struct vt1211_data *data = vt1211_update_device(dev);
759ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	struct sensor_device_attribute_2 *sensor_attr_2 =
760ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger						to_sensor_dev_attr_2(attr);
761ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	int ix = sensor_attr_2->index;
762ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	int ap = sensor_attr_2->nr;
763ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger
764ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	return sprintf(buf, "%d\n", TEMP_FROM_REG(data->pwm_ctl[ix] & 7,
765ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger		       data->pwm_auto_temp[ap]));
766ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger}
767ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger
768ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefligerstatic ssize_t set_pwm_auto_point_temp(struct device *dev,
769ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger				       struct device_attribute *attr,
770ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger				       const char *buf, size_t count)
771ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger{
772ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	struct vt1211_data *data = dev_get_drvdata(dev);
773ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	struct sensor_device_attribute_2 *sensor_attr_2 =
774ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger						to_sensor_dev_attr_2(attr);
775ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	int ix = sensor_attr_2->index;
776ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	int ap = sensor_attr_2->nr;
777ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	int reg;
778b162c033480a7ba0433d329f56c142a0ab59049dGuenter Roeck	long val;
779b162c033480a7ba0433d329f56c142a0ab59049dGuenter Roeck	int err;
780b162c033480a7ba0433d329f56c142a0ab59049dGuenter Roeck
781b162c033480a7ba0433d329f56c142a0ab59049dGuenter Roeck	err = kstrtol(buf, 10, &val);
782b162c033480a7ba0433d329f56c142a0ab59049dGuenter Roeck	if (err)
783b162c033480a7ba0433d329f56c142a0ab59049dGuenter Roeck		return err;
784b162c033480a7ba0433d329f56c142a0ab59049dGuenter Roeck
785ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger
786ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	mutex_lock(&data->update_lock);
787ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger
788ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	/* sync the data cache */
789ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	reg = vt1211_read8(data, VT1211_REG_PWM_CTL);
790ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	data->pwm_ctl[0] = reg & 0xf;
791ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	data->pwm_ctl[1] = (reg >> 4) & 0xf;
792ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger
793ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	data->pwm_auto_temp[ap] = TEMP_TO_REG(data->pwm_ctl[ix] & 7, val);
794ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	vt1211_write8(data, VT1211_REG_PWM_AUTO_TEMP(ap),
795ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger		      data->pwm_auto_temp[ap]);
796ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	mutex_unlock(&data->update_lock);
797ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger
798ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	return count;
799ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger}
800ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger
801ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger/*
802ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger * pwm[ix+1]_auto_point[ap+1]_pwm mapping table:
803ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger * Note that the PWM auto points 0 & 3 are hard-wired in the VT1211 and can't
804ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger * be changed.
805ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger *
806ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger * ix ap : description
807ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger * -------------------
808ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger * 0  0  : pwm1 off                   (pwm_auto_pwm[0][0], hard-wired to 0)
809ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger * 0  1  : pwm1 low speed duty cycle  (pwm_auto_pwm[0][1])
810ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger * 0  2  : pwm1 high speed duty cycle (pwm_auto_pwm[0][2])
811ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger * 0  3  : pwm1 full speed            (pwm_auto_pwm[0][3], hard-wired to 255)
812ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger * 1  0  : pwm2 off                   (pwm_auto_pwm[1][0], hard-wired to 0)
813ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger * 1  1  : pwm2 low speed duty cycle  (pwm_auto_pwm[1][1])
814ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger * 1  2  : pwm2 high speed duty cycle (pwm_auto_pwm[1][2])
815ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger * 1  3  : pwm2 full speed            (pwm_auto_pwm[1][3], hard-wired to 255)
816b162c033480a7ba0433d329f56c142a0ab59049dGuenter Roeck */
817ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger
818ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefligerstatic ssize_t show_pwm_auto_point_pwm(struct device *dev,
819ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger				       struct device_attribute *attr,
820ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger				       char *buf)
821ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger{
822ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	struct vt1211_data *data = vt1211_update_device(dev);
823ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	struct sensor_device_attribute_2 *sensor_attr_2 =
824ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger						to_sensor_dev_attr_2(attr);
825ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	int ix = sensor_attr_2->index;
826ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	int ap = sensor_attr_2->nr;
827ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger
828ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	return sprintf(buf, "%d\n", data->pwm_auto_pwm[ix][ap]);
829ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger}
830ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger
831ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefligerstatic ssize_t set_pwm_auto_point_pwm(struct device *dev,
832ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger				      struct device_attribute *attr,
833ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger				      const char *buf, size_t count)
834ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger{
835ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	struct vt1211_data *data = dev_get_drvdata(dev);
836ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	struct sensor_device_attribute_2 *sensor_attr_2 =
837ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger						to_sensor_dev_attr_2(attr);
838ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	int ix = sensor_attr_2->index;
839ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	int ap = sensor_attr_2->nr;
840b162c033480a7ba0433d329f56c142a0ab59049dGuenter Roeck	unsigned long val;
841b162c033480a7ba0433d329f56c142a0ab59049dGuenter Roeck	int err;
842ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger
843b162c033480a7ba0433d329f56c142a0ab59049dGuenter Roeck	err = kstrtoul(buf, 10, &val);
844b162c033480a7ba0433d329f56c142a0ab59049dGuenter Roeck	if (err)
845b162c033480a7ba0433d329f56c142a0ab59049dGuenter Roeck		return err;
846ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger
847ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	mutex_lock(&data->update_lock);
848b162c033480a7ba0433d329f56c142a0ab59049dGuenter Roeck	data->pwm_auto_pwm[ix][ap] = SENSORS_LIMIT(val, 0, 255);
849ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	vt1211_write8(data, VT1211_REG_PWM_AUTO_PWM(ix, ap),
850ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger		      data->pwm_auto_pwm[ix][ap]);
851ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	mutex_unlock(&data->update_lock);
852ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger
853ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	return count;
854ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger}
855ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger
856ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger/* ---------------------------------------------------------------------
857ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger * Miscellaneous sysfs interfaces (VRM, VID, name, and (legacy) alarms)
858ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger * --------------------------------------------------------------------- */
859ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger
860ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefligerstatic ssize_t show_vrm(struct device *dev, struct device_attribute *attr,
861ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger			char *buf)
862ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger{
863ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	struct vt1211_data *data = dev_get_drvdata(dev);
864ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger
865ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	return sprintf(buf, "%d\n", data->vrm);
866ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger}
867ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger
868ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefligerstatic ssize_t set_vrm(struct device *dev, struct device_attribute *attr,
869ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger		       const char *buf, size_t count)
870ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger{
871ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	struct vt1211_data *data = dev_get_drvdata(dev);
872b162c033480a7ba0433d329f56c142a0ab59049dGuenter Roeck	unsigned long val;
873b162c033480a7ba0433d329f56c142a0ab59049dGuenter Roeck	int err;
874b162c033480a7ba0433d329f56c142a0ab59049dGuenter Roeck
875b162c033480a7ba0433d329f56c142a0ab59049dGuenter Roeck	err = kstrtoul(buf, 10, &val);
876b162c033480a7ba0433d329f56c142a0ab59049dGuenter Roeck	if (err)
877b162c033480a7ba0433d329f56c142a0ab59049dGuenter Roeck		return err;
878ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger
879ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	data->vrm = val;
880ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger
881ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	return count;
882ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger}
883ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger
884ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefligerstatic ssize_t show_vid(struct device *dev, struct device_attribute *attr,
885ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger			char *buf)
886ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger{
887ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	struct vt1211_data *data = dev_get_drvdata(dev);
888ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger
889ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	return sprintf(buf, "%d\n", vid_from_reg(data->vid, data->vrm));
890ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger}
891ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger
892ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefligerstatic ssize_t show_name(struct device *dev,
893ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger			 struct device_attribute *attr, char *buf)
894ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger{
895ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	struct vt1211_data *data = dev_get_drvdata(dev);
896ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger
897ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	return sprintf(buf, "%s\n", data->name);
898ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger}
899ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger
900ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefligerstatic ssize_t show_alarms(struct device *dev,
901ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger			   struct device_attribute *attr, char *buf)
902ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger{
903ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	struct vt1211_data *data = vt1211_update_device(dev);
904ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger
905ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	return sprintf(buf, "%d\n", data->alarms);
906ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger}
907ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger
908ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger/* ---------------------------------------------------------------------
909ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger * Device attribute structs
910ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger * --------------------------------------------------------------------- */
911ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger
9122185696d7d8a852146f6a901b35e9b94be43329aGuenter Roeck#define SENSOR_ATTR_IN(ix) \
9132185696d7d8a852146f6a901b35e9b94be43329aGuenter Roeck{	SENSOR_ATTR_2(in##ix##_input, S_IRUGO, \
9142185696d7d8a852146f6a901b35e9b94be43329aGuenter Roeck		show_in, NULL, SHOW_IN_INPUT, ix), \
915ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	SENSOR_ATTR_2(in##ix##_min, S_IRUGO | S_IWUSR, \
9162185696d7d8a852146f6a901b35e9b94be43329aGuenter Roeck		show_in, set_in, SHOW_SET_IN_MIN, ix), \
917ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	SENSOR_ATTR_2(in##ix##_max, S_IRUGO | S_IWUSR, \
9182185696d7d8a852146f6a901b35e9b94be43329aGuenter Roeck		show_in, set_in, SHOW_SET_IN_MAX, ix), \
9192185696d7d8a852146f6a901b35e9b94be43329aGuenter Roeck	SENSOR_ATTR_2(in##ix##_alarm, S_IRUGO, \
9202185696d7d8a852146f6a901b35e9b94be43329aGuenter Roeck		show_in, NULL, SHOW_IN_ALARM, ix) \
9212185696d7d8a852146f6a901b35e9b94be43329aGuenter Roeck}
9222185696d7d8a852146f6a901b35e9b94be43329aGuenter Roeck
9232185696d7d8a852146f6a901b35e9b94be43329aGuenter Roeckstatic struct sensor_device_attribute_2 vt1211_sysfs_in[][4] = {
9242185696d7d8a852146f6a901b35e9b94be43329aGuenter Roeck	SENSOR_ATTR_IN(0),
9252185696d7d8a852146f6a901b35e9b94be43329aGuenter Roeck	SENSOR_ATTR_IN(1),
9262185696d7d8a852146f6a901b35e9b94be43329aGuenter Roeck	SENSOR_ATTR_IN(2),
9272185696d7d8a852146f6a901b35e9b94be43329aGuenter Roeck	SENSOR_ATTR_IN(3),
9282185696d7d8a852146f6a901b35e9b94be43329aGuenter Roeck	SENSOR_ATTR_IN(4),
9292185696d7d8a852146f6a901b35e9b94be43329aGuenter Roeck	SENSOR_ATTR_IN(5)
930ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger};
931ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger
9322185696d7d8a852146f6a901b35e9b94be43329aGuenter Roeck#define IN_UNIT_ATTRS(X)			\
9332185696d7d8a852146f6a901b35e9b94be43329aGuenter Roeck{	&vt1211_sysfs_in[X][0].dev_attr.attr,	\
9342185696d7d8a852146f6a901b35e9b94be43329aGuenter Roeck	&vt1211_sysfs_in[X][1].dev_attr.attr,	\
9352185696d7d8a852146f6a901b35e9b94be43329aGuenter Roeck	&vt1211_sysfs_in[X][2].dev_attr.attr,	\
9362185696d7d8a852146f6a901b35e9b94be43329aGuenter Roeck	&vt1211_sysfs_in[X][3].dev_attr.attr,	\
9372185696d7d8a852146f6a901b35e9b94be43329aGuenter Roeck	NULL					\
9382185696d7d8a852146f6a901b35e9b94be43329aGuenter Roeck}
9392185696d7d8a852146f6a901b35e9b94be43329aGuenter Roeck
9402185696d7d8a852146f6a901b35e9b94be43329aGuenter Roeckstatic struct attribute *vt1211_in_attr[][5] = {
9412185696d7d8a852146f6a901b35e9b94be43329aGuenter Roeck	IN_UNIT_ATTRS(0),
9422185696d7d8a852146f6a901b35e9b94be43329aGuenter Roeck	IN_UNIT_ATTRS(1),
9432185696d7d8a852146f6a901b35e9b94be43329aGuenter Roeck	IN_UNIT_ATTRS(2),
9442185696d7d8a852146f6a901b35e9b94be43329aGuenter Roeck	IN_UNIT_ATTRS(3),
9452185696d7d8a852146f6a901b35e9b94be43329aGuenter Roeck	IN_UNIT_ATTRS(4),
9462185696d7d8a852146f6a901b35e9b94be43329aGuenter Roeck	IN_UNIT_ATTRS(5)
947ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger};
948ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger
9492185696d7d8a852146f6a901b35e9b94be43329aGuenter Roeckstatic const struct attribute_group vt1211_in_attr_group[] = {
9502185696d7d8a852146f6a901b35e9b94be43329aGuenter Roeck	{ .attrs = vt1211_in_attr[0] },
9512185696d7d8a852146f6a901b35e9b94be43329aGuenter Roeck	{ .attrs = vt1211_in_attr[1] },
9522185696d7d8a852146f6a901b35e9b94be43329aGuenter Roeck	{ .attrs = vt1211_in_attr[2] },
9532185696d7d8a852146f6a901b35e9b94be43329aGuenter Roeck	{ .attrs = vt1211_in_attr[3] },
9542185696d7d8a852146f6a901b35e9b94be43329aGuenter Roeck	{ .attrs = vt1211_in_attr[4] },
9552185696d7d8a852146f6a901b35e9b94be43329aGuenter Roeck	{ .attrs = vt1211_in_attr[5] }
956ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger};
957ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger
9582185696d7d8a852146f6a901b35e9b94be43329aGuenter Roeck#define SENSOR_ATTR_TEMP(ix) \
9592185696d7d8a852146f6a901b35e9b94be43329aGuenter Roeck{	SENSOR_ATTR_2(temp##ix##_input, S_IRUGO, \
9602185696d7d8a852146f6a901b35e9b94be43329aGuenter Roeck		show_temp, NULL, SHOW_TEMP_INPUT, ix-1), \
961ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	SENSOR_ATTR_2(temp##ix##_max, S_IRUGO | S_IWUSR, \
9622185696d7d8a852146f6a901b35e9b94be43329aGuenter Roeck		show_temp, set_temp, SHOW_SET_TEMP_MAX, ix-1), \
9632185696d7d8a852146f6a901b35e9b94be43329aGuenter Roeck	SENSOR_ATTR_2(temp##ix##_max_hyst, S_IRUGO | S_IWUSR, \
9642185696d7d8a852146f6a901b35e9b94be43329aGuenter Roeck		show_temp, set_temp, SHOW_SET_TEMP_MAX_HYST, ix-1), \
9652185696d7d8a852146f6a901b35e9b94be43329aGuenter Roeck	SENSOR_ATTR_2(temp##ix##_alarm, S_IRUGO, \
9662185696d7d8a852146f6a901b35e9b94be43329aGuenter Roeck		show_temp, NULL, SHOW_TEMP_ALARM, ix-1) \
9672185696d7d8a852146f6a901b35e9b94be43329aGuenter Roeck}
9682185696d7d8a852146f6a901b35e9b94be43329aGuenter Roeck
9692185696d7d8a852146f6a901b35e9b94be43329aGuenter Roeckstatic struct sensor_device_attribute_2 vt1211_sysfs_temp[][4] = {
9702185696d7d8a852146f6a901b35e9b94be43329aGuenter Roeck	SENSOR_ATTR_TEMP(1),
9712185696d7d8a852146f6a901b35e9b94be43329aGuenter Roeck	SENSOR_ATTR_TEMP(2),
9722185696d7d8a852146f6a901b35e9b94be43329aGuenter Roeck	SENSOR_ATTR_TEMP(3),
9732185696d7d8a852146f6a901b35e9b94be43329aGuenter Roeck	SENSOR_ATTR_TEMP(4),
9742185696d7d8a852146f6a901b35e9b94be43329aGuenter Roeck	SENSOR_ATTR_TEMP(5),
9752185696d7d8a852146f6a901b35e9b94be43329aGuenter Roeck	SENSOR_ATTR_TEMP(6),
9762185696d7d8a852146f6a901b35e9b94be43329aGuenter Roeck	SENSOR_ATTR_TEMP(7),
977ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger};
978ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger
9792185696d7d8a852146f6a901b35e9b94be43329aGuenter Roeck#define TEMP_UNIT_ATTRS(X)			\
9802185696d7d8a852146f6a901b35e9b94be43329aGuenter Roeck{	&vt1211_sysfs_temp[X][0].dev_attr.attr,	\
9812185696d7d8a852146f6a901b35e9b94be43329aGuenter Roeck	&vt1211_sysfs_temp[X][1].dev_attr.attr,	\
9822185696d7d8a852146f6a901b35e9b94be43329aGuenter Roeck	&vt1211_sysfs_temp[X][2].dev_attr.attr,	\
9832185696d7d8a852146f6a901b35e9b94be43329aGuenter Roeck	&vt1211_sysfs_temp[X][3].dev_attr.attr,	\
9842185696d7d8a852146f6a901b35e9b94be43329aGuenter Roeck	NULL					\
9852185696d7d8a852146f6a901b35e9b94be43329aGuenter Roeck}
9862185696d7d8a852146f6a901b35e9b94be43329aGuenter Roeck
9872185696d7d8a852146f6a901b35e9b94be43329aGuenter Roeckstatic struct attribute *vt1211_temp_attr[][5] = {
9882185696d7d8a852146f6a901b35e9b94be43329aGuenter Roeck	TEMP_UNIT_ATTRS(0),
9892185696d7d8a852146f6a901b35e9b94be43329aGuenter Roeck	TEMP_UNIT_ATTRS(1),
9902185696d7d8a852146f6a901b35e9b94be43329aGuenter Roeck	TEMP_UNIT_ATTRS(2),
9912185696d7d8a852146f6a901b35e9b94be43329aGuenter Roeck	TEMP_UNIT_ATTRS(3),
9922185696d7d8a852146f6a901b35e9b94be43329aGuenter Roeck	TEMP_UNIT_ATTRS(4),
9932185696d7d8a852146f6a901b35e9b94be43329aGuenter Roeck	TEMP_UNIT_ATTRS(5),
9942185696d7d8a852146f6a901b35e9b94be43329aGuenter Roeck	TEMP_UNIT_ATTRS(6)
995ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger};
996ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger
9972185696d7d8a852146f6a901b35e9b94be43329aGuenter Roeckstatic const struct attribute_group vt1211_temp_attr_group[] = {
9982185696d7d8a852146f6a901b35e9b94be43329aGuenter Roeck	{ .attrs = vt1211_temp_attr[0] },
9992185696d7d8a852146f6a901b35e9b94be43329aGuenter Roeck	{ .attrs = vt1211_temp_attr[1] },
10002185696d7d8a852146f6a901b35e9b94be43329aGuenter Roeck	{ .attrs = vt1211_temp_attr[2] },
10012185696d7d8a852146f6a901b35e9b94be43329aGuenter Roeck	{ .attrs = vt1211_temp_attr[3] },
10022185696d7d8a852146f6a901b35e9b94be43329aGuenter Roeck	{ .attrs = vt1211_temp_attr[4] },
10032185696d7d8a852146f6a901b35e9b94be43329aGuenter Roeck	{ .attrs = vt1211_temp_attr[5] },
10042185696d7d8a852146f6a901b35e9b94be43329aGuenter Roeck	{ .attrs = vt1211_temp_attr[6] }
1005ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger};
1006ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger
1007ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger#define SENSOR_ATTR_FAN(ix) \
1008ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	SENSOR_ATTR_2(fan##ix##_input, S_IRUGO, \
1009ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger		show_fan, NULL, SHOW_FAN_INPUT, ix-1), \
1010ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	SENSOR_ATTR_2(fan##ix##_min, S_IRUGO | S_IWUSR, \
1011ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger		show_fan, set_fan, SHOW_SET_FAN_MIN, ix-1), \
1012ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	SENSOR_ATTR_2(fan##ix##_div, S_IRUGO | S_IWUSR, \
1013ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger		show_fan, set_fan, SHOW_SET_FAN_DIV, ix-1), \
1014ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	SENSOR_ATTR_2(fan##ix##_alarm, S_IRUGO, \
1015ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger		show_fan, NULL, SHOW_FAN_ALARM, ix-1)
1016ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger
1017ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger#define SENSOR_ATTR_PWM(ix) \
1018ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	SENSOR_ATTR_2(pwm##ix, S_IRUGO, \
1019ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger		show_pwm, NULL, SHOW_PWM, ix-1), \
1020ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	SENSOR_ATTR_2(pwm##ix##_enable, S_IRUGO | S_IWUSR, \
1021ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger		show_pwm, set_pwm, SHOW_SET_PWM_ENABLE, ix-1), \
1022ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	SENSOR_ATTR_2(pwm##ix##_auto_channels_temp, S_IRUGO | S_IWUSR, \
1023ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger		show_pwm, set_pwm, SHOW_SET_PWM_AUTO_CHANNELS_TEMP, ix-1)
1024ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger
1025ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger#define SENSOR_ATTR_PWM_FREQ(ix) \
1026ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	SENSOR_ATTR_2(pwm##ix##_freq, S_IRUGO | S_IWUSR, \
1027ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger		show_pwm, set_pwm, SHOW_SET_PWM_FREQ, ix-1)
1028ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger
1029ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger#define SENSOR_ATTR_PWM_FREQ_RO(ix) \
1030ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	SENSOR_ATTR_2(pwm##ix##_freq, S_IRUGO, \
1031ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger		show_pwm, NULL, SHOW_SET_PWM_FREQ, ix-1)
1032ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger
1033ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger#define SENSOR_ATTR_PWM_AUTO_POINT_TEMP(ix, ap) \
1034ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	SENSOR_ATTR_2(pwm##ix##_auto_point##ap##_temp, S_IRUGO | S_IWUSR, \
1035ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger		show_pwm_auto_point_temp, set_pwm_auto_point_temp, \
1036ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger		ap-1, ix-1)
1037ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger
1038ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger#define SENSOR_ATTR_PWM_AUTO_POINT_TEMP_RO(ix, ap) \
1039ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	SENSOR_ATTR_2(pwm##ix##_auto_point##ap##_temp, S_IRUGO, \
1040ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger		show_pwm_auto_point_temp, NULL, \
1041ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger		ap-1, ix-1)
1042ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger
1043ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger#define SENSOR_ATTR_PWM_AUTO_POINT_PWM(ix, ap) \
1044ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	SENSOR_ATTR_2(pwm##ix##_auto_point##ap##_pwm, S_IRUGO | S_IWUSR, \
1045ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger		show_pwm_auto_point_pwm, set_pwm_auto_point_pwm, \
1046ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger		ap-1, ix-1)
1047ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger
1048ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger#define SENSOR_ATTR_PWM_AUTO_POINT_PWM_RO(ix, ap) \
1049ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	SENSOR_ATTR_2(pwm##ix##_auto_point##ap##_pwm, S_IRUGO, \
1050ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger		show_pwm_auto_point_pwm, NULL, \
1051ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger		ap-1, ix-1)
1052ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger
1053ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefligerstatic struct sensor_device_attribute_2 vt1211_sysfs_fan_pwm[] = {
1054ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	SENSOR_ATTR_FAN(1),
1055ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	SENSOR_ATTR_FAN(2),
1056ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	SENSOR_ATTR_PWM(1),
1057ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	SENSOR_ATTR_PWM(2),
1058ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	SENSOR_ATTR_PWM_FREQ(1),
1059ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	SENSOR_ATTR_PWM_FREQ_RO(2),
1060ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	SENSOR_ATTR_PWM_AUTO_POINT_TEMP(1, 1),
1061ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	SENSOR_ATTR_PWM_AUTO_POINT_TEMP(1, 2),
1062ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	SENSOR_ATTR_PWM_AUTO_POINT_TEMP(1, 3),
1063ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	SENSOR_ATTR_PWM_AUTO_POINT_TEMP(1, 4),
1064ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	SENSOR_ATTR_PWM_AUTO_POINT_TEMP_RO(2, 1),
1065ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	SENSOR_ATTR_PWM_AUTO_POINT_TEMP_RO(2, 2),
1066ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	SENSOR_ATTR_PWM_AUTO_POINT_TEMP_RO(2, 3),
1067ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	SENSOR_ATTR_PWM_AUTO_POINT_TEMP_RO(2, 4),
1068ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	SENSOR_ATTR_PWM_AUTO_POINT_PWM_RO(1, 1),
1069ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	SENSOR_ATTR_PWM_AUTO_POINT_PWM(1, 2),
1070ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	SENSOR_ATTR_PWM_AUTO_POINT_PWM(1, 3),
1071ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	SENSOR_ATTR_PWM_AUTO_POINT_PWM_RO(1, 4),
1072ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	SENSOR_ATTR_PWM_AUTO_POINT_PWM_RO(2, 1),
1073ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	SENSOR_ATTR_PWM_AUTO_POINT_PWM(2, 2),
1074ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	SENSOR_ATTR_PWM_AUTO_POINT_PWM(2, 3),
1075ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	SENSOR_ATTR_PWM_AUTO_POINT_PWM_RO(2, 4),
1076ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger};
1077ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger
1078ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefligerstatic struct device_attribute vt1211_sysfs_misc[] = {
1079ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	__ATTR(vrm, S_IRUGO | S_IWUSR, show_vrm, set_vrm),
1080ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	__ATTR(cpu0_vid, S_IRUGO, show_vid, NULL),
1081ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	__ATTR(name, S_IRUGO, show_name, NULL),
1082ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	__ATTR(alarms, S_IRUGO, show_alarms, NULL),
1083ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger};
1084ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger
1085ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger/* ---------------------------------------------------------------------
1086ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger * Device registration and initialization
1087ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger * --------------------------------------------------------------------- */
1088ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger
1089ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefligerstatic void __devinit vt1211_init_device(struct vt1211_data *data)
1090ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger{
1091ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	/* set VRM */
1092ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	data->vrm = vid_which_vrm();
1093ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger
1094ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	/* Read (and initialize) UCH config */
1095ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	data->uch_config = vt1211_read8(data, VT1211_REG_UCH_CONFIG);
1096ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	if (uch_config > -1) {
1097ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger		data->uch_config = (data->uch_config & 0x83) |
1098ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger				   (uch_config << 2);
1099ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger		vt1211_write8(data, VT1211_REG_UCH_CONFIG, data->uch_config);
1100ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	}
1101ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger
1102b162c033480a7ba0433d329f56c142a0ab59049dGuenter Roeck	/*
1103b162c033480a7ba0433d329f56c142a0ab59049dGuenter Roeck	 * Initialize the interrupt mode (if request at module load time).
1104ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	 * The VT1211 implements 3 different modes for clearing interrupts:
1105ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	 * 0: Clear INT when status register is read. Regenerate INT as long
1106ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	 *    as temp stays above hysteresis limit.
1107ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	 * 1: Clear INT when status register is read. DON'T regenerate INT
1108ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	 *    until temp falls below hysteresis limit and exceeds hot limit
1109ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	 *    again.
1110ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	 * 2: Clear INT when temp falls below max limit.
1111ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	 *
1112ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	 * The driver only allows to force mode 0 since that's the only one
1113b162c033480a7ba0433d329f56c142a0ab59049dGuenter Roeck	 * that makes sense for 'sensors'
1114b162c033480a7ba0433d329f56c142a0ab59049dGuenter Roeck	 */
1115ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	if (int_mode == 0) {
1116ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger		vt1211_write8(data, VT1211_REG_TEMP1_CONFIG, 0);
1117ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger		vt1211_write8(data, VT1211_REG_TEMP2_CONFIG, 0);
1118ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	}
1119ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger
1120ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	/* Fill in some hard wired values into our data struct */
1121ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	data->pwm_auto_pwm[0][3] = 255;
1122ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	data->pwm_auto_pwm[1][3] = 255;
1123ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger}
1124ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger
1125ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefligerstatic void vt1211_remove_sysfs(struct platform_device *pdev)
1126ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger{
1127ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	struct device *dev = &pdev->dev;
1128ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	int i;
1129ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger
11302185696d7d8a852146f6a901b35e9b94be43329aGuenter Roeck	for (i = 0; i < ARRAY_SIZE(vt1211_in_attr_group); i++)
11312185696d7d8a852146f6a901b35e9b94be43329aGuenter Roeck		sysfs_remove_group(&dev->kobj, &vt1211_in_attr_group[i]);
11322185696d7d8a852146f6a901b35e9b94be43329aGuenter Roeck
11332185696d7d8a852146f6a901b35e9b94be43329aGuenter Roeck	for (i = 0; i < ARRAY_SIZE(vt1211_temp_attr_group); i++)
11342185696d7d8a852146f6a901b35e9b94be43329aGuenter Roeck		sysfs_remove_group(&dev->kobj, &vt1211_temp_attr_group[i]);
11352185696d7d8a852146f6a901b35e9b94be43329aGuenter Roeck
1136ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	for (i = 0; i < ARRAY_SIZE(vt1211_sysfs_fan_pwm); i++) {
1137ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger		device_remove_file(dev,
1138ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger			&vt1211_sysfs_fan_pwm[i].dev_attr);
1139ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	}
1140b162c033480a7ba0433d329f56c142a0ab59049dGuenter Roeck	for (i = 0; i < ARRAY_SIZE(vt1211_sysfs_misc); i++)
1141ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger		device_remove_file(dev, &vt1211_sysfs_misc[i]);
1142ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger}
1143ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger
1144ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefligerstatic int __devinit vt1211_probe(struct platform_device *pdev)
1145ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger{
1146ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	struct device *dev = &pdev->dev;
1147ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	struct vt1211_data *data;
1148ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	struct resource *res;
1149ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	int i, err;
1150ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger
1151b162c033480a7ba0433d329f56c142a0ab59049dGuenter Roeck	data = kzalloc(sizeof(struct vt1211_data), GFP_KERNEL);
1152b162c033480a7ba0433d329f56c142a0ab59049dGuenter Roeck	if (!data) {
1153ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger		err = -ENOMEM;
1154ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger		dev_err(dev, "Out of memory\n");
1155ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger		goto EXIT;
1156ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	}
1157ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger
1158ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	res = platform_get_resource(pdev, IORESOURCE_IO, 0);
115986855b0c1fd75338c67cabbf85d64d033612c47bJulia Lawall	if (!request_region(res->start, resource_size(res), DRVNAME)) {
1160ce7ee4e80a72d3b1009ca232be8981de93c015f6Jean Delvare		err = -EBUSY;
1161ce7ee4e80a72d3b1009ca232be8981de93c015f6Jean Delvare		dev_err(dev, "Failed to request region 0x%lx-0x%lx\n",
1162ce7ee4e80a72d3b1009ca232be8981de93c015f6Jean Delvare			(unsigned long)res->start, (unsigned long)res->end);
1163ce7ee4e80a72d3b1009ca232be8981de93c015f6Jean Delvare		goto EXIT_KFREE;
1164ce7ee4e80a72d3b1009ca232be8981de93c015f6Jean Delvare	}
1165ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	data->addr = res->start;
1166ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	data->name = DRVNAME;
1167ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	mutex_init(&data->update_lock);
1168ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger
1169ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	platform_set_drvdata(pdev, data);
1170ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger
1171ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	/* Initialize the VT1211 chip */
1172ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	vt1211_init_device(data);
1173ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger
1174ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	/* Create sysfs interface files */
11752185696d7d8a852146f6a901b35e9b94be43329aGuenter Roeck	for (i = 0; i < ARRAY_SIZE(vt1211_in_attr_group); i++) {
1176ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger		if (ISVOLT(i, data->uch_config)) {
11772185696d7d8a852146f6a901b35e9b94be43329aGuenter Roeck			err = sysfs_create_group(&dev->kobj,
11782185696d7d8a852146f6a901b35e9b94be43329aGuenter Roeck						 &vt1211_in_attr_group[i]);
11792185696d7d8a852146f6a901b35e9b94be43329aGuenter Roeck			if (err)
1180ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger				goto EXIT_DEV_REMOVE;
1181ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger		}
1182ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	}
11832185696d7d8a852146f6a901b35e9b94be43329aGuenter Roeck	for (i = 0; i < ARRAY_SIZE(vt1211_temp_attr_group); i++) {
1184ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger		if (ISTEMP(i, data->uch_config)) {
11852185696d7d8a852146f6a901b35e9b94be43329aGuenter Roeck			err = sysfs_create_group(&dev->kobj,
11862185696d7d8a852146f6a901b35e9b94be43329aGuenter Roeck						 &vt1211_temp_attr_group[i]);
11872185696d7d8a852146f6a901b35e9b94be43329aGuenter Roeck			if (err)
1188ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger				goto EXIT_DEV_REMOVE;
1189ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger		}
1190ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	}
1191ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	for (i = 0; i < ARRAY_SIZE(vt1211_sysfs_fan_pwm); i++) {
1192ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger		err = device_create_file(dev,
1193ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger			&vt1211_sysfs_fan_pwm[i].dev_attr);
1194b162c033480a7ba0433d329f56c142a0ab59049dGuenter Roeck		if (err)
1195ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger			goto EXIT_DEV_REMOVE;
1196ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	}
1197ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	for (i = 0; i < ARRAY_SIZE(vt1211_sysfs_misc); i++) {
1198ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger		err = device_create_file(dev,
1199ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger		       &vt1211_sysfs_misc[i]);
1200b162c033480a7ba0433d329f56c142a0ab59049dGuenter Roeck		if (err)
1201ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger			goto EXIT_DEV_REMOVE;
1202ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	}
1203ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger
1204ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	/* Register device */
12051beeffe43311f64df8dd0ab08ff6b1858c58363fTony Jones	data->hwmon_dev = hwmon_device_register(dev);
12061beeffe43311f64df8dd0ab08ff6b1858c58363fTony Jones	if (IS_ERR(data->hwmon_dev)) {
12071beeffe43311f64df8dd0ab08ff6b1858c58363fTony Jones		err = PTR_ERR(data->hwmon_dev);
1208ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger		dev_err(dev, "Class registration failed (%d)\n", err);
1209ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger		goto EXIT_DEV_REMOVE_SILENT;
1210ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	}
1211ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger
1212ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	return 0;
1213ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger
1214ab41319eab3b5e600873dc77dff7756970424ca6Juerg HaefligerEXIT_DEV_REMOVE:
1215ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	dev_err(dev, "Sysfs interface creation failed (%d)\n", err);
1216ab41319eab3b5e600873dc77dff7756970424ca6Juerg HaefligerEXIT_DEV_REMOVE_SILENT:
1217ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	vt1211_remove_sysfs(pdev);
121886855b0c1fd75338c67cabbf85d64d033612c47bJulia Lawall	release_region(res->start, resource_size(res));
1219ce7ee4e80a72d3b1009ca232be8981de93c015f6Jean DelvareEXIT_KFREE:
1220ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	platform_set_drvdata(pdev, NULL);
1221ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	kfree(data);
1222ab41319eab3b5e600873dc77dff7756970424ca6Juerg HaefligerEXIT:
1223ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	return err;
1224ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger}
1225ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger
1226ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefligerstatic int __devexit vt1211_remove(struct platform_device *pdev)
1227ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger{
1228ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	struct vt1211_data *data = platform_get_drvdata(pdev);
1229ce7ee4e80a72d3b1009ca232be8981de93c015f6Jean Delvare	struct resource *res;
1230ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger
12311beeffe43311f64df8dd0ab08ff6b1858c58363fTony Jones	hwmon_device_unregister(data->hwmon_dev);
1232ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	vt1211_remove_sysfs(pdev);
1233ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	platform_set_drvdata(pdev, NULL);
1234ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	kfree(data);
1235ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger
1236ce7ee4e80a72d3b1009ca232be8981de93c015f6Jean Delvare	res = platform_get_resource(pdev, IORESOURCE_IO, 0);
123786855b0c1fd75338c67cabbf85d64d033612c47bJulia Lawall	release_region(res->start, resource_size(res));
1238ce7ee4e80a72d3b1009ca232be8981de93c015f6Jean Delvare
1239ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	return 0;
1240ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger}
1241ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger
1242ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefligerstatic struct platform_driver vt1211_driver = {
1243ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	.driver = {
1244ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger		.owner = THIS_MODULE,
1245ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger		.name  = DRVNAME,
1246ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	},
1247ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	.probe  = vt1211_probe,
1248ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	.remove = __devexit_p(vt1211_remove),
1249ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger};
1250ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger
1251ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefligerstatic int __init vt1211_device_add(unsigned short address)
1252ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger{
1253ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	struct resource res = {
1254ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger		.start	= address,
1255ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger		.end	= address + 0x7f,
1256ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger		.flags	= IORESOURCE_IO,
1257ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	};
1258ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	int err;
1259ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger
1260ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	pdev = platform_device_alloc(DRVNAME, address);
1261ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	if (!pdev) {
1262ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger		err = -ENOMEM;
12635ed9ba6b87545d21b48e50a028bfb79f9812f89fJoe Perches		pr_err("Device allocation failed (%d)\n", err);
1264ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger		goto EXIT;
1265ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	}
1266ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger
1267ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	res.name = pdev->name;
1268b9acb64a385c5b26fc392e0d58ac7b8e0a2cd812Jean Delvare	err = acpi_check_resource_conflict(&res);
1269b9acb64a385c5b26fc392e0d58ac7b8e0a2cd812Jean Delvare	if (err)
127018632f84fac770125c0982dfadec6b551e82144eHans de Goede		goto EXIT_DEV_PUT;
1271b9acb64a385c5b26fc392e0d58ac7b8e0a2cd812Jean Delvare
1272ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	err = platform_device_add_resources(pdev, &res, 1);
1273ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	if (err) {
12745ed9ba6b87545d21b48e50a028bfb79f9812f89fJoe Perches		pr_err("Device resource addition failed (%d)\n", err);
1275ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger		goto EXIT_DEV_PUT;
1276ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	}
1277ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger
1278ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	err = platform_device_add(pdev);
1279ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	if (err) {
12805ed9ba6b87545d21b48e50a028bfb79f9812f89fJoe Perches		pr_err("Device addition failed (%d)\n", err);
1281ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger		goto EXIT_DEV_PUT;
1282ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	}
1283ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger
1284ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	return 0;
1285ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger
1286ab41319eab3b5e600873dc77dff7756970424ca6Juerg HaefligerEXIT_DEV_PUT:
1287ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	platform_device_put(pdev);
1288ab41319eab3b5e600873dc77dff7756970424ca6Juerg HaefligerEXIT:
1289ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	return err;
1290ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger}
1291ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger
12922219cd81a6cd186200606693b360c6429c003bb3Juerg Haefligerstatic int __init vt1211_find(int sio_cip, unsigned short *address)
1293ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger{
1294ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	int err = -ENODEV;
129567b671bceb4a8340a30929e9642620d99ed5ad76Jean Delvare	int devid;
1296ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger
12972219cd81a6cd186200606693b360c6429c003bb3Juerg Haefliger	superio_enter(sio_cip);
1298ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger
129967b671bceb4a8340a30929e9642620d99ed5ad76Jean Delvare	devid = force_id ? force_id : superio_inb(sio_cip, SIO_VT1211_DEVID);
1300b162c033480a7ba0433d329f56c142a0ab59049dGuenter Roeck	if (devid != SIO_VT1211_ID)
1301ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger		goto EXIT;
1302ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger
13032219cd81a6cd186200606693b360c6429c003bb3Juerg Haefliger	superio_select(sio_cip, SIO_VT1211_LDN_HWMON);
1304ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger
13052219cd81a6cd186200606693b360c6429c003bb3Juerg Haefliger	if ((superio_inb(sio_cip, SIO_VT1211_ACTIVE) & 1) == 0) {
13065ed9ba6b87545d21b48e50a028bfb79f9812f89fJoe Perches		pr_warn("HW monitor is disabled, skipping\n");
1307ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger		goto EXIT;
1308ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	}
1309ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger
13102219cd81a6cd186200606693b360c6429c003bb3Juerg Haefliger	*address = ((superio_inb(sio_cip, SIO_VT1211_BADDR) << 8) |
13112219cd81a6cd186200606693b360c6429c003bb3Juerg Haefliger		    (superio_inb(sio_cip, SIO_VT1211_BADDR + 1))) & 0xff00;
1312ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	if (*address == 0) {
13135ed9ba6b87545d21b48e50a028bfb79f9812f89fJoe Perches		pr_warn("Base address is not set, skipping\n");
1314ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger		goto EXIT;
1315ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	}
1316ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger
1317ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	err = 0;
13185ed9ba6b87545d21b48e50a028bfb79f9812f89fJoe Perches	pr_info("Found VT1211 chip at 0x%04x, revision %u\n",
13195ed9ba6b87545d21b48e50a028bfb79f9812f89fJoe Perches		*address, superio_inb(sio_cip, SIO_VT1211_DEVREV));
1320ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger
1321ab41319eab3b5e600873dc77dff7756970424ca6Juerg HaefligerEXIT:
13222219cd81a6cd186200606693b360c6429c003bb3Juerg Haefliger	superio_exit(sio_cip);
1323ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	return err;
1324ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger}
1325ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger
1326ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefligerstatic int __init vt1211_init(void)
1327ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger{
1328ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	int err;
1329ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	unsigned short address = 0;
1330ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger
1331b162c033480a7ba0433d329f56c142a0ab59049dGuenter Roeck	err = vt1211_find(SIO_REG_CIP1, &address);
1332b162c033480a7ba0433d329f56c142a0ab59049dGuenter Roeck	if (err) {
1333b162c033480a7ba0433d329f56c142a0ab59049dGuenter Roeck		err = vt1211_find(SIO_REG_CIP2, &address);
1334b162c033480a7ba0433d329f56c142a0ab59049dGuenter Roeck		if (err)
1335b162c033480a7ba0433d329f56c142a0ab59049dGuenter Roeck			goto EXIT;
1336ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	}
1337ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger
1338ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	if ((uch_config < -1) || (uch_config > 31)) {
1339ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger		err = -EINVAL;
13405ed9ba6b87545d21b48e50a028bfb79f9812f89fJoe Perches		pr_warn("Invalid UCH configuration %d. "
13415ed9ba6b87545d21b48e50a028bfb79f9812f89fJoe Perches			"Choose a value between 0 and 31.\n", uch_config);
1342b162c033480a7ba0433d329f56c142a0ab59049dGuenter Roeck		goto EXIT;
1343ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	}
1344ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger
1345ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	if ((int_mode < -1) || (int_mode > 0)) {
1346ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger		err = -EINVAL;
13475ed9ba6b87545d21b48e50a028bfb79f9812f89fJoe Perches		pr_warn("Invalid interrupt mode %d. "
13485ed9ba6b87545d21b48e50a028bfb79f9812f89fJoe Perches			"Only mode 0 is supported.\n", int_mode);
1349b162c033480a7ba0433d329f56c142a0ab59049dGuenter Roeck		goto EXIT;
1350ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	}
1351ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger
1352ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	err = platform_driver_register(&vt1211_driver);
1353b162c033480a7ba0433d329f56c142a0ab59049dGuenter Roeck	if (err)
1354ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger		goto EXIT;
1355ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger
1356ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	/* Sets global pdev as a side effect */
1357ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	err = vt1211_device_add(address);
1358b162c033480a7ba0433d329f56c142a0ab59049dGuenter Roeck	if (err)
1359ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger		goto EXIT_DRV_UNREGISTER;
1360ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger
1361ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	return 0;
1362ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger
1363ab41319eab3b5e600873dc77dff7756970424ca6Juerg HaefligerEXIT_DRV_UNREGISTER:
1364ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	platform_driver_unregister(&vt1211_driver);
1365ab41319eab3b5e600873dc77dff7756970424ca6Juerg HaefligerEXIT:
1366ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	return err;
1367ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger}
1368ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger
1369ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefligerstatic void __exit vt1211_exit(void)
1370ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger{
1371ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	platform_device_unregister(pdev);
1372ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger	platform_driver_unregister(&vt1211_driver);
1373ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger}
1374ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger
1375ab41319eab3b5e600873dc77dff7756970424ca6Juerg HaefligerMODULE_AUTHOR("Juerg Haefliger <juergh@gmail.com>");
1376ab41319eab3b5e600873dc77dff7756970424ca6Juerg HaefligerMODULE_DESCRIPTION("VT1211 sensors");
1377ab41319eab3b5e600873dc77dff7756970424ca6Juerg HaefligerMODULE_LICENSE("GPL");
1378ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefliger
1379ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefligermodule_init(vt1211_init);
1380ab41319eab3b5e600873dc77dff7756970424ca6Juerg Haefligermodule_exit(vt1211_exit);
1381