amc6821.c revision b5430a04e995081a308b4419bd0940f2badc6e6b
1b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj/*
2b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	amc6821.c - Part of lm_sensors, Linux kernel modules for hardware
3b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	monitoring
4b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	Copyright (C) 2009 T. Mertelj <tomaz.mertelj@guest.arnes.si>
5b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj
6b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	Based on max6650.c:
7b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	Copyright (C) 2007 Hans J. Koch <hjk@linutronix.de>
8b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj
9b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	This program is free software; you can redistribute it and/or modify
10b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	it under the terms of the GNU General Public License as published by
11b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	the Free Software Foundation; either version 2 of the License, or
12b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	(at your option) any later version.
13b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj
14b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	This program is distributed in the hope that it will be useful,
15b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	but WITHOUT ANY WARRANTY; without even the implied warranty of
16b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	GNU General Public License for more details.
18b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj
19b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	You should have received a copy of the GNU General Public License
20b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	along with this program; if not, write to the Free Software
21b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj*/
23b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj
24b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj
25b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj#include <linux/kernel.h>	/* Needed for KERN_INFO */
26b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj#include <linux/module.h>
27b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj#include <linux/init.h>
28b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj#include <linux/slab.h>
29b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj#include <linux/jiffies.h>
30b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj#include <linux/i2c.h>
31b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj#include <linux/hwmon.h>
32b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj#include <linux/hwmon-sysfs.h>
33b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj#include <linux/err.h>
34b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj#include <linux/mutex.h>
35b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj
36b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj
37b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj/*
38b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj * Addresses to scan.
39b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj */
40b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj
41b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Merteljstatic const unsigned short normal_i2c[] = {0x18, 0x19, 0x1a, 0x2c, 0x2d, 0x2e,
42b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	0x4c, 0x4d, 0x4e, I2C_CLIENT_END};
43b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj
44b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj
45b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj
46b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj/*
47b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj * Insmod parameters
48b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj */
49b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj
50b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Merteljstatic int pwminv = 0;	/*Inverted PWM output. */
51b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Merteljmodule_param(pwminv, int, S_IRUGO);
52b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj
53b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Merteljstatic int init = 1; /*Power-on initialization.*/
54b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Merteljmodule_param(init, int, S_IRUGO);
55b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj
56b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj
57b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Merteljenum chips { amc6821 };
58b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj
59b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj#define AMC6821_REG_DEV_ID 0x3D
60b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj#define AMC6821_REG_COMP_ID 0x3E
61b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj#define AMC6821_REG_CONF1 0x00
62b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj#define AMC6821_REG_CONF2 0x01
63b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj#define AMC6821_REG_CONF3 0x3F
64b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj#define AMC6821_REG_CONF4 0x04
65b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj#define AMC6821_REG_STAT1 0x02
66b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj#define AMC6821_REG_STAT2 0x03
67b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj#define AMC6821_REG_TDATA_LOW 0x08
68b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj#define AMC6821_REG_TDATA_HI 0x09
69b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj#define AMC6821_REG_LTEMP_HI 0x0A
70b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj#define AMC6821_REG_RTEMP_HI 0x0B
71b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj#define AMC6821_REG_LTEMP_LIMIT_MIN 0x15
72b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj#define AMC6821_REG_LTEMP_LIMIT_MAX 0x14
73b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj#define AMC6821_REG_RTEMP_LIMIT_MIN 0x19
74b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj#define AMC6821_REG_RTEMP_LIMIT_MAX 0x18
75b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj#define AMC6821_REG_LTEMP_CRIT 0x1B
76b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj#define AMC6821_REG_RTEMP_CRIT 0x1D
77b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj#define AMC6821_REG_PSV_TEMP 0x1C
78b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj#define AMC6821_REG_DCY 0x22
79b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj#define AMC6821_REG_LTEMP_FAN_CTRL 0x24
80b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj#define AMC6821_REG_RTEMP_FAN_CTRL 0x25
81b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj#define AMC6821_REG_DCY_LOW_TEMP 0x21
82b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj
83b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj#define AMC6821_REG_TACH_LLIMITL 0x10
84b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj#define AMC6821_REG_TACH_LLIMITH 0x11
85b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj#define AMC6821_REG_TACH_HLIMITL 0x12
86b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj#define AMC6821_REG_TACH_HLIMITH 0x13
87b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj
88b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj#define AMC6821_CONF1_START 0x01
89b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj#define AMC6821_CONF1_FAN_INT_EN 0x02
90b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj#define AMC6821_CONF1_FANIE 0x04
91b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj#define AMC6821_CONF1_PWMINV 0x08
92b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj#define AMC6821_CONF1_FAN_FAULT_EN 0x10
93b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj#define AMC6821_CONF1_FDRC0 0x20
94b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj#define AMC6821_CONF1_FDRC1 0x40
95b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj#define AMC6821_CONF1_THERMOVIE 0x80
96b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj
97b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj#define AMC6821_CONF2_PWM_EN 0x01
98b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj#define AMC6821_CONF2_TACH_MODE 0x02
99b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj#define AMC6821_CONF2_TACH_EN 0x04
100b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj#define AMC6821_CONF2_RTFIE 0x08
101b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj#define AMC6821_CONF2_LTOIE 0x10
102b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj#define AMC6821_CONF2_RTOIE 0x20
103b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj#define AMC6821_CONF2_PSVIE 0x40
104b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj#define AMC6821_CONF2_RST 0x80
105b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj
106b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj#define AMC6821_CONF3_THERM_FAN_EN 0x80
107b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj#define AMC6821_CONF3_REV_MASK 0x0F
108b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj
109b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj#define AMC6821_CONF4_OVREN 0x10
110b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj#define AMC6821_CONF4_TACH_FAST 0x20
111b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj#define AMC6821_CONF4_PSPR 0x40
112b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj#define AMC6821_CONF4_MODE 0x80
113b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj
114b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj#define AMC6821_STAT1_RPM_ALARM 0x01
115b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj#define AMC6821_STAT1_FANS 0x02
116b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj#define AMC6821_STAT1_RTH 0x04
117b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj#define AMC6821_STAT1_RTL 0x08
118b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj#define AMC6821_STAT1_R_THERM 0x10
119b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj#define AMC6821_STAT1_RTF 0x20
120b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj#define AMC6821_STAT1_LTH 0x40
121b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj#define AMC6821_STAT1_LTL 0x80
122b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj
123b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj#define AMC6821_STAT2_RTC 0x08
124b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj#define AMC6821_STAT2_LTC 0x10
125b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj#define AMC6821_STAT2_LPSV 0x20
126b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj#define AMC6821_STAT2_L_THERM 0x40
127b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj#define AMC6821_STAT2_THERM_IN 0x80
128b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj
129b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Merteljenum {IDX_TEMP1_INPUT = 0, IDX_TEMP1_MIN, IDX_TEMP1_MAX,
130b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	IDX_TEMP1_CRIT, IDX_TEMP2_INPUT, IDX_TEMP2_MIN,
131b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	IDX_TEMP2_MAX, IDX_TEMP2_CRIT,
132b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	TEMP_IDX_LEN, };
133b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj
134b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Merteljstatic const u8 temp_reg[] = {AMC6821_REG_LTEMP_HI,
135b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj			AMC6821_REG_LTEMP_LIMIT_MIN,
136b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj			AMC6821_REG_LTEMP_LIMIT_MAX,
137b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj			AMC6821_REG_LTEMP_CRIT,
138b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj			AMC6821_REG_RTEMP_HI,
139b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj			AMC6821_REG_RTEMP_LIMIT_MIN,
140b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj			AMC6821_REG_RTEMP_LIMIT_MAX,
141b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj			AMC6821_REG_RTEMP_CRIT, };
142b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj
143b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Merteljenum {IDX_FAN1_INPUT = 0, IDX_FAN1_MIN, IDX_FAN1_MAX,
144b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	FAN1_IDX_LEN, };
145b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj
146b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Merteljstatic const u8 fan_reg_low[] = {AMC6821_REG_TDATA_LOW,
147b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj			AMC6821_REG_TACH_LLIMITL,
148b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj			AMC6821_REG_TACH_HLIMITL, };
149b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj
150b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj
151b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Merteljstatic const u8 fan_reg_hi[] = {AMC6821_REG_TDATA_HI,
152b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj			AMC6821_REG_TACH_LLIMITH,
153b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj			AMC6821_REG_TACH_HLIMITH, };
154b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj
155b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Merteljstatic int amc6821_probe(
156b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj		struct i2c_client *client,
157b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj		const struct i2c_device_id *id);
158b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Merteljstatic int amc6821_detect(
159b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj		struct i2c_client *client,
160b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj		struct i2c_board_info *info);
161b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Merteljstatic int amc6821_init_client(struct i2c_client *client);
162b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Merteljstatic int amc6821_remove(struct i2c_client *client);
163b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Merteljstatic struct amc6821_data *amc6821_update_device(struct device *dev);
164b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj
165b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj/*
166b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj * Driver data (common to all clients)
167b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj */
168b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj
169b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Merteljstatic const struct i2c_device_id amc6821_id[] = {
170b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	{ "amc6821", amc6821 },
171b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	{ }
172b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj};
173b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj
174b5430a04e995081a308b4419bd0940f2badc6e6bTomaz MerteljMODULE_DEVICE_TABLE(i2c, amc6821_id);
175b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj
176b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Merteljstatic struct i2c_driver amc6821_driver = {
177b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	.class = I2C_CLASS_HWMON,
178b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	.driver = {
179b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj		.name	= "amc6821",
180b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	},
181b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	.probe = amc6821_probe,
182b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	.remove = amc6821_remove,
183b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	.id_table = amc6821_id,
184b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	.detect = amc6821_detect,
185b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	.address_list = normal_i2c,
186b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj};
187b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj
188b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj
189b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj/*
190b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj * Client data (each client gets its own)
191b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj  */
192b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj
193b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Merteljstruct amc6821_data {
194b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	struct device *hwmon_dev;
195b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	struct mutex update_lock;
196b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	char valid; /* zero until following fields are valid */
197b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	unsigned long last_updated; /* in jiffies */
198b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj
199b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	/* register values */
200b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	int temp[TEMP_IDX_LEN];
201b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj
202b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	u16 fan[FAN1_IDX_LEN];
203b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	u8 fan1_div;
204b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj
205b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	u8 pwm1;
206b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	u8 temp1_auto_point_temp[3];
207b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	u8 temp2_auto_point_temp[3];
208b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	u8 pwm1_auto_point_pwm[3];
209b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	u8 pwm1_enable;
210b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	u8 pwm1_auto_channels_temp;
211b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj
212b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	u8 stat1;
213b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	u8 stat2;
214b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj};
215b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj
216b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj
217b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Merteljstatic ssize_t get_temp(
218b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj		struct device *dev,
219b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj		struct device_attribute *devattr,
220b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj		char *buf)
221b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj{
222b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	struct amc6821_data *data = amc6821_update_device(dev);
223b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	int ix = to_sensor_dev_attr(devattr)->index;
224b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj
225b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	return sprintf(buf, "%d\n", data->temp[ix] * 1000);
226b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj}
227b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj
228b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj
229b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj
230b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Merteljstatic ssize_t set_temp(
231b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj		struct device *dev,
232b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj		struct device_attribute *attr,
233b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj		const char *buf,
234b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj		size_t count)
235b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj{
236b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	struct i2c_client *client = to_i2c_client(dev);
237b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	struct amc6821_data *data = i2c_get_clientdata(client);
238b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	int ix = to_sensor_dev_attr(attr)->index;
239b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	long val;
240b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj
241b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	int ret = strict_strtol(buf, 10, &val);
242b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	if (ret)
243b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj		return ret;
244b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	val = SENSORS_LIMIT(val / 1000, -128, 127);
245b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj
246b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	mutex_lock(&data->update_lock);
247b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	data->temp[ix] = val;
248b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	if (i2c_smbus_write_byte_data(client, temp_reg[ix], data->temp[ix])) {
249b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj		dev_err(&client->dev, "Register write error, aborting.\n");
250b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj		count = -EIO;
251b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	}
252b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	mutex_unlock(&data->update_lock);
253b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	return count;
254b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj}
255b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj
256b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj
257b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj
258b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj
259b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Merteljstatic ssize_t get_temp_alarm(
260b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	struct device *dev,
261b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	struct device_attribute *devattr,
262b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	char *buf)
263b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj{
264b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	struct amc6821_data *data = amc6821_update_device(dev);
265b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	int ix = to_sensor_dev_attr(devattr)->index;
266b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	u8 flag;
267b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj
268b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	switch (ix) {
269b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	case IDX_TEMP1_MIN:
270b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj		flag = data->stat1 & AMC6821_STAT1_LTL;
271b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj		break;
272b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	case IDX_TEMP1_MAX:
273b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj		flag = data->stat1 & AMC6821_STAT1_LTH;
274b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj		break;
275b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	case IDX_TEMP1_CRIT:
276b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj		flag = data->stat2 & AMC6821_STAT2_LTC;
277b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj		break;
278b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	case IDX_TEMP2_MIN:
279b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj		flag = data->stat1 & AMC6821_STAT1_RTL;
280b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj		break;
281b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	case IDX_TEMP2_MAX:
282b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj		flag = data->stat1 & AMC6821_STAT1_RTH;
283b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj		break;
284b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	case IDX_TEMP2_CRIT:
285b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj		flag = data->stat2 & AMC6821_STAT2_RTC;
286b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj		break;
287b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	default:
288b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj		dev_dbg(dev, "Unknown attr->index (%d).\n", ix);
289b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj		return -EINVAL;
290b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	}
291b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	if (flag)
292b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj		return sprintf(buf, "1");
293b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	else
294b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj		return sprintf(buf, "0");
295b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj}
296b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj
297b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj
298b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj
299b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj
300b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Merteljstatic ssize_t get_temp2_fault(
301b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj		struct device *dev,
302b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj		struct device_attribute *devattr,
303b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj		char *buf)
304b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj{
305b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	struct amc6821_data *data = amc6821_update_device(dev);
306b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	if (data->stat1 & AMC6821_STAT1_RTF)
307b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj		return sprintf(buf, "1");
308b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	else
309b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj		return sprintf(buf, "0");
310b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj}
311b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj
312b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Merteljstatic ssize_t get_pwm1(
313b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj		struct device *dev,
314b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj		struct device_attribute *devattr,
315b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj		char *buf)
316b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj{
317b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	struct amc6821_data *data = amc6821_update_device(dev);
318b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	return sprintf(buf, "%d\n", data->pwm1);
319b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj}
320b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj
321b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Merteljstatic ssize_t set_pwm1(
322b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj		struct device *dev,
323b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj		struct device_attribute *devattr,
324b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj		const char *buf,
325b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj		size_t count)
326b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj{
327b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	struct i2c_client *client = to_i2c_client(dev);
328b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	struct amc6821_data *data = i2c_get_clientdata(client);
329b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	long val;
330b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	int ret = strict_strtol(buf, 10, &val);
331b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	if (ret)
332b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj		return ret;
333b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj
334b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	mutex_lock(&data->update_lock);
335b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	data->pwm1 = SENSORS_LIMIT(val , 0, 255);
336b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	i2c_smbus_write_byte_data(client, AMC6821_REG_DCY, data->pwm1);
337b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	mutex_unlock(&data->update_lock);
338b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	return count;
339b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj}
340b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj
341b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Merteljstatic ssize_t get_pwm1_enable(
342b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj		struct device *dev,
343b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj		struct device_attribute *devattr,
344b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj		char *buf)
345b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj{
346b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	struct amc6821_data *data = amc6821_update_device(dev);
347b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	return sprintf(buf, "%d\n", data->pwm1_enable);
348b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj}
349b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj
350b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Merteljstatic ssize_t set_pwm1_enable(
351b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj		struct device *dev,
352b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj		struct device_attribute *attr,
353b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj		const char *buf,
354b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj		size_t count)
355b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj{
356b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	struct i2c_client *client = to_i2c_client(dev);
357b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	struct amc6821_data *data = i2c_get_clientdata(client);
358b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	long val;
359b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	int config = strict_strtol(buf, 10, &val);
360b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	if (config)
361b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj		return config;
362b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj
363b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	config = i2c_smbus_read_byte_data(client, AMC6821_REG_CONF1);
364b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	if (config < 0) {
365b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj			dev_err(&client->dev,
366b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj			"Error reading configuration register, aborting.\n");
367b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj			return -EIO;
368b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	}
369b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj
370b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	switch (val) {
371b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	case 1:
372b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj		config &= ~AMC6821_CONF1_FDRC0;
373b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj		config &= ~AMC6821_CONF1_FDRC1;
374b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj		break;
375b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	case 2:
376b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj		config &= ~AMC6821_CONF1_FDRC0;
377b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj		config |= AMC6821_CONF1_FDRC1;
378b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj		break;
379b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	case 3:
380b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj		config |= AMC6821_CONF1_FDRC0;
381b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj		config |= AMC6821_CONF1_FDRC1;
382b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj		break;
383b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	default:
384b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj		return -EINVAL;
385b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	}
386b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	mutex_lock(&data->update_lock);
387b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	if (i2c_smbus_write_byte_data(client, AMC6821_REG_CONF1, config)) {
388b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj			dev_err(&client->dev,
389b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj			"Configuration register write error, aborting.\n");
390b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj			count = -EIO;
391b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	}
392b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	mutex_unlock(&data->update_lock);
393b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	return count;
394b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj}
395b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj
396b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj
397b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Merteljstatic ssize_t get_pwm1_auto_channels_temp(
398b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj		struct device *dev,
399b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj		struct device_attribute *devattr,
400b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj		char *buf)
401b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj{
402b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	struct amc6821_data *data = amc6821_update_device(dev);
403b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	return sprintf(buf, "%d\n", data->pwm1_auto_channels_temp);
404b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj}
405b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj
406b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj
407b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Merteljstatic ssize_t get_temp_auto_point_temp(
408b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj		struct device *dev,
409b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj		struct device_attribute *devattr,
410b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj		char *buf)
411b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj{
412b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	int ix = to_sensor_dev_attr_2(devattr)->index;
413b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	int nr = to_sensor_dev_attr_2(devattr)->nr;
414b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	struct amc6821_data *data = amc6821_update_device(dev);
415b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	switch (nr) {
416b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	case 1:
417b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj		return sprintf(buf, "%d\n",
418b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj			data->temp1_auto_point_temp[ix] * 1000);
419b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj		break;
420b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	case 2:
421b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj		return sprintf(buf, "%d\n",
422b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj			data->temp2_auto_point_temp[ix] * 1000);
423b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj		break;
424b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	default:
425b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj		dev_dbg(dev, "Unknown attr->nr (%d).\n", nr);
426b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj		return -EINVAL;
427b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	}
428b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj}
429b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj
430b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj
431b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Merteljstatic ssize_t get_pwm1_auto_point_pwm(
432b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj		struct device *dev,
433b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj		struct device_attribute *devattr,
434b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj		char *buf)
435b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj{
436b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	int ix = to_sensor_dev_attr(devattr)->index;
437b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	struct amc6821_data *data = amc6821_update_device(dev);
438b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	return sprintf(buf, "%d\n", data->pwm1_auto_point_pwm[ix]);
439b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj}
440b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj
441b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj
442b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Merteljstatic inline ssize_t set_slope_register(struct i2c_client *client,
443b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj		u8 reg,
444b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj		u8 dpwm,
445b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj		u8 *ptemp)
446b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj{
447b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	int dt;
448b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	u8 tmp;
449b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj
450b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	dt = ptemp[2]-ptemp[1];
451b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	for (tmp = 4; tmp > 0; tmp--) {
452b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj		if (dt * (0x20 >> tmp) >= dpwm)
453b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj			break;
454b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	}
455b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	tmp |= (ptemp[1] & 0x7C) << 1;
456b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	if (i2c_smbus_write_byte_data(client,
457b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj			reg, tmp)) {
458b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj		dev_err(&client->dev, "Register write error, aborting.\n");
459b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj		return -EIO;
460b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	}
461b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	return 0;
462b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj}
463b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj
464b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj
465b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj
466b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Merteljstatic ssize_t set_temp_auto_point_temp(
467b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj		struct device *dev,
468b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj		struct device_attribute *attr,
469b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj		const char *buf,
470b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj		size_t count)
471b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj{
472b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	struct i2c_client *client = to_i2c_client(dev);
473b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	struct amc6821_data *data = amc6821_update_device(dev);
474b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	int ix = to_sensor_dev_attr_2(attr)->index;
475b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	int nr = to_sensor_dev_attr_2(attr)->nr;
476b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	u8 *ptemp;
477b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	u8 reg;
478b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	int dpwm;
479b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	long val;
480b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	int ret = strict_strtol(buf, 10, &val);
481b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	if (ret)
482b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj		return ret;
483b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj
484b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	switch (nr) {
485b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	case 1:
486b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj		ptemp = data->temp1_auto_point_temp;
487b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj		reg = AMC6821_REG_LTEMP_FAN_CTRL;
488b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj		break;
489b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	case 2:
490b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj		ptemp = data->temp2_auto_point_temp;
491b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj		reg = AMC6821_REG_RTEMP_FAN_CTRL;
492b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj		break;
493b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	default:
494b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj		dev_dbg(dev, "Unknown attr->nr (%d).\n", nr);
495b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj		return -EINVAL;
496b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	}
497b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj
498b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	data->valid = 0;
499b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	mutex_lock(&data->update_lock);
500b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	switch (ix) {
501b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	case 0:
502b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj		ptemp[0] = SENSORS_LIMIT(val / 1000, 0,
503b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj				data->temp1_auto_point_temp[1]);
504b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj		ptemp[0] = SENSORS_LIMIT(ptemp[0], 0,
505b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj				data->temp2_auto_point_temp[1]);
506b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj		ptemp[0] = SENSORS_LIMIT(ptemp[0], 0, 63);
507b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj		if (i2c_smbus_write_byte_data(
508b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj					client,
509b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj					AMC6821_REG_PSV_TEMP,
510b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj					ptemp[0])) {
511b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj				dev_err(&client->dev,
512b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj					"Register write error, aborting.\n");
513b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj				count = -EIO;
514b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj		}
515b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj		goto EXIT;
516b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj		break;
517b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	case 1:
518b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj		ptemp[1] = SENSORS_LIMIT(
519b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj					val / 1000,
520b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj					(ptemp[0] & 0x7C) + 4,
521b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj					124);
522b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj		ptemp[1] &= 0x7C;
523b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj		ptemp[2] = SENSORS_LIMIT(
524b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj					ptemp[2], ptemp[1] + 1,
525b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj					255);
526b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj		break;
527b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	case 2:
528b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj		ptemp[2] = SENSORS_LIMIT(
529b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj					val / 1000,
530b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj					ptemp[1]+1,
531b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj					255);
532b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj		break;
533b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	default:
534b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj		dev_dbg(dev, "Unknown attr->index (%d).\n", ix);
535b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj		count = -EINVAL;
536b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj		goto EXIT;
537b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	}
538b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	dpwm = data->pwm1_auto_point_pwm[2] - data->pwm1_auto_point_pwm[1];
539b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	if (set_slope_register(client, reg, dpwm, ptemp))
540b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj		count = -EIO;
541b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj
542b5430a04e995081a308b4419bd0940f2badc6e6bTomaz MerteljEXIT:
543b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	mutex_unlock(&data->update_lock);
544b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	return count;
545b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj}
546b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj
547b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj
548b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj
549b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Merteljstatic ssize_t set_pwm1_auto_point_pwm(
550b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj		struct device *dev,
551b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj		struct device_attribute *attr,
552b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj		const char *buf,
553b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj		size_t count)
554b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj{
555b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	struct i2c_client *client = to_i2c_client(dev);
556b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	struct amc6821_data *data = i2c_get_clientdata(client);
557b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	int dpwm;
558b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	long val;
559b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	int ret = strict_strtol(buf, 10, &val);
560b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	if (ret)
561b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj		return ret;
562b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj
563b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	mutex_lock(&data->update_lock);
564b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	data->pwm1_auto_point_pwm[1] = SENSORS_LIMIT(val, 0, 254);
565b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	if (i2c_smbus_write_byte_data(client, AMC6821_REG_DCY_LOW_TEMP,
566b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj			data->pwm1_auto_point_pwm[1])) {
567b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj		dev_err(&client->dev, "Register write error, aborting.\n");
568b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj		count = -EIO;
569b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj		goto EXIT;
570b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	}
571b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	dpwm = data->pwm1_auto_point_pwm[2] - data->pwm1_auto_point_pwm[1];
572b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	if (set_slope_register(client, AMC6821_REG_LTEMP_FAN_CTRL, dpwm,
573b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj			data->temp1_auto_point_temp)) {
574b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj		count = -EIO;
575b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj		goto EXIT;
576b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	}
577b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	if (set_slope_register(client, AMC6821_REG_RTEMP_FAN_CTRL, dpwm,
578b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj			data->temp2_auto_point_temp)) {
579b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj		count = -EIO;
580b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj		goto EXIT;
581b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	}
582b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj
583b5430a04e995081a308b4419bd0940f2badc6e6bTomaz MerteljEXIT:
584b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	data->valid = 0;
585b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	mutex_unlock(&data->update_lock);
586b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	return count;
587b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj}
588b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj
589b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Merteljstatic ssize_t get_fan(
590b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj		struct device *dev,
591b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj		struct device_attribute *devattr,
592b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj		char *buf)
593b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj{
594b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	struct amc6821_data *data = amc6821_update_device(dev);
595b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	int ix = to_sensor_dev_attr(devattr)->index;
596b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	if (0 == data->fan[ix])
597b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj		return sprintf(buf, "0");
598b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	return sprintf(buf, "%d\n", (int)(6000000 / data->fan[ix]));
599b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj}
600b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj
601b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj
602b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj
603b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Merteljstatic ssize_t get_fan1_fault(
604b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj		struct device *dev,
605b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj		struct device_attribute *devattr,
606b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj		char *buf)
607b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj{
608b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	struct amc6821_data *data = amc6821_update_device(dev);
609b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	if (data->stat1 & AMC6821_STAT1_FANS)
610b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj		return sprintf(buf, "1");
611b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	else
612b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj		return sprintf(buf, "0");
613b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj}
614b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj
615b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj
616b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj
617b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Merteljstatic ssize_t set_fan(
618b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj		struct device *dev,
619b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj		struct device_attribute *attr,
620b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj		const char *buf, size_t count)
621b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj{
622b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	struct i2c_client *client = to_i2c_client(dev);
623b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	struct amc6821_data *data = i2c_get_clientdata(client);
624b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	long val;
625b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	int ix = to_sensor_dev_attr(attr)->index;
626b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	int ret = strict_strtol(buf, 10, &val);
627b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	if (ret)
628b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj		return ret;
629b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	val = 1 > val ? 0xFFFF : 6000000/val;
630b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj
631b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	mutex_lock(&data->update_lock);
632b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	data->fan[ix] = (u16) SENSORS_LIMIT(val, 1, 0xFFFF);
633b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	if (i2c_smbus_write_byte_data(client, fan_reg_low[ix],
634b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj			data->fan[ix] & 0xFF)) {
635b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj		dev_err(&client->dev, "Register write error, aborting.\n");
636b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj		count = -EIO;
637b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj		goto EXIT;
638b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	}
639b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	if (i2c_smbus_write_byte_data(client,
640b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj			fan_reg_hi[ix], data->fan[ix] >> 8)) {
641b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj		dev_err(&client->dev, "Register write error, aborting.\n");
642b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj		count = -EIO;
643b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	}
644b5430a04e995081a308b4419bd0940f2badc6e6bTomaz MerteljEXIT:
645b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	mutex_unlock(&data->update_lock);
646b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	return count;
647b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj}
648b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj
649b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj
650b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj
651b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Merteljstatic ssize_t get_fan1_div(
652b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj		struct device *dev,
653b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj		struct device_attribute *devattr,
654b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj		char *buf)
655b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj{
656b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	struct amc6821_data *data = amc6821_update_device(dev);
657b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	return sprintf(buf, "%d\n", data->fan1_div);
658b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj}
659b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj
660b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Merteljstatic ssize_t set_fan1_div(
661b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj		struct device *dev,
662b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj		struct device_attribute *attr,
663b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj		const char *buf, size_t count)
664b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj{
665b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	struct i2c_client *client = to_i2c_client(dev);
666b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	struct amc6821_data *data = i2c_get_clientdata(client);
667b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	long val;
668b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	int config = strict_strtol(buf, 10, &val);
669b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	if (config)
670b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj		return config;
671b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj
672b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	config = i2c_smbus_read_byte_data(client, AMC6821_REG_CONF4);
673b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	if (config < 0) {
674b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj		dev_err(&client->dev,
675b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj			"Error reading configuration register, aborting.\n");
676b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj		return -EIO;
677b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	}
678b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	mutex_lock(&data->update_lock);
679b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	switch (val) {
680b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	case 2:
681b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj		config &= ~AMC6821_CONF4_PSPR;
682b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj		data->fan1_div = 2;
683b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj		break;
684b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	case 4:
685b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj		config |= AMC6821_CONF4_PSPR;
686b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj		data->fan1_div = 4;
687b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj		break;
688b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	default:
689b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj		mutex_unlock(&data->update_lock);
690b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj		count = -EINVAL;
691b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj		goto EXIT;
692b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	}
693b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	if (i2c_smbus_write_byte_data(client, AMC6821_REG_CONF4, config)) {
694b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj		dev_err(&client->dev,
695b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj			"Configuration register write error, aborting.\n");
696b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj		count = -EIO;
697b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	}
698b5430a04e995081a308b4419bd0940f2badc6e6bTomaz MerteljEXIT:
699b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	mutex_unlock(&data->update_lock);
700b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	return count;
701b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj}
702b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj
703b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj
704b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj
705b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Merteljstatic SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO,
706b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	get_temp, NULL, IDX_TEMP1_INPUT);
707b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Merteljstatic SENSOR_DEVICE_ATTR(temp1_min, S_IRUGO | S_IWUSR, get_temp,
708b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	set_temp, IDX_TEMP1_MIN);
709b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Merteljstatic SENSOR_DEVICE_ATTR(temp1_max, S_IRUGO | S_IWUSR, get_temp,
710b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	set_temp, IDX_TEMP1_MAX);
711b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Merteljstatic SENSOR_DEVICE_ATTR(temp1_crit, S_IRUGO | S_IWUSR, get_temp,
712b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	set_temp, IDX_TEMP1_CRIT);
713b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Merteljstatic SENSOR_DEVICE_ATTR(temp1_min_alarm, S_IRUGO,
714b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	get_temp_alarm, NULL, IDX_TEMP1_MIN);
715b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Merteljstatic SENSOR_DEVICE_ATTR(temp1_max_alarm, S_IRUGO,
716b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	get_temp_alarm, NULL, IDX_TEMP1_MAX);
717b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Merteljstatic SENSOR_DEVICE_ATTR(temp1_crit_alarm, S_IRUGO,
718b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	get_temp_alarm, NULL, IDX_TEMP1_CRIT);
719b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Merteljstatic SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO | S_IWUSR,
720b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	get_temp, NULL, IDX_TEMP2_INPUT);
721b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Merteljstatic SENSOR_DEVICE_ATTR(temp2_min, S_IRUGO | S_IWUSR, get_temp,
722b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	set_temp, IDX_TEMP2_MIN);
723b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Merteljstatic SENSOR_DEVICE_ATTR(temp2_max, S_IRUGO | S_IWUSR, get_temp,
724b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	set_temp, IDX_TEMP2_MAX);
725b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Merteljstatic SENSOR_DEVICE_ATTR(temp2_crit, S_IRUGO | S_IWUSR, get_temp,
726b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	set_temp, IDX_TEMP2_CRIT);
727b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Merteljstatic SENSOR_DEVICE_ATTR(temp2_fault, S_IRUGO,
728b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	get_temp2_fault, NULL, 0);
729b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Merteljstatic SENSOR_DEVICE_ATTR(temp2_min_alarm, S_IRUGO,
730b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	get_temp_alarm, NULL, IDX_TEMP2_MIN);
731b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Merteljstatic SENSOR_DEVICE_ATTR(temp2_max_alarm, S_IRUGO,
732b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	get_temp_alarm, NULL, IDX_TEMP2_MAX);
733b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Merteljstatic SENSOR_DEVICE_ATTR(temp2_crit_alarm, S_IRUGO,
734b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	get_temp_alarm, NULL, IDX_TEMP2_CRIT);
735b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Merteljstatic SENSOR_DEVICE_ATTR(fan1_input, S_IRUGO, get_fan, NULL, IDX_FAN1_INPUT);
736b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Merteljstatic SENSOR_DEVICE_ATTR(fan1_min, S_IRUGO | S_IWUSR,
737b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	get_fan, set_fan, IDX_FAN1_MIN);
738b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Merteljstatic SENSOR_DEVICE_ATTR(fan1_max, S_IRUGO | S_IWUSR,
739b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	get_fan, set_fan, IDX_FAN1_MAX);
740b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Merteljstatic SENSOR_DEVICE_ATTR(fan1_fault, S_IRUGO, get_fan1_fault, NULL, 0);
741b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Merteljstatic SENSOR_DEVICE_ATTR(fan1_div, S_IRUGO | S_IWUSR,
742b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	get_fan1_div, set_fan1_div, 0);
743b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj
744b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Merteljstatic SENSOR_DEVICE_ATTR(pwm1, S_IWUSR | S_IRUGO, get_pwm1, set_pwm1, 0);
745b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Merteljstatic SENSOR_DEVICE_ATTR(pwm1_enable, S_IWUSR | S_IRUGO,
746b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	get_pwm1_enable, set_pwm1_enable, 0);
747b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Merteljstatic SENSOR_DEVICE_ATTR(pwm1_auto_point1_pwm, S_IRUGO,
748b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	get_pwm1_auto_point_pwm, NULL, 0);
749b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Merteljstatic SENSOR_DEVICE_ATTR(pwm1_auto_point2_pwm, S_IWUSR | S_IRUGO,
750b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	get_pwm1_auto_point_pwm, set_pwm1_auto_point_pwm, 1);
751b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Merteljstatic SENSOR_DEVICE_ATTR(pwm1_auto_point3_pwm, S_IRUGO,
752b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	get_pwm1_auto_point_pwm, NULL, 2);
753b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Merteljstatic SENSOR_DEVICE_ATTR(pwm1_auto_channels_temp, S_IRUGO,
754b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	get_pwm1_auto_channels_temp, NULL, 0);
755b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Merteljstatic SENSOR_DEVICE_ATTR_2(temp1_auto_point1_temp, S_IRUGO,
756b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	get_temp_auto_point_temp, NULL, 1, 0);
757b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Merteljstatic SENSOR_DEVICE_ATTR_2(temp1_auto_point2_temp, S_IWUSR | S_IRUGO,
758b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	get_temp_auto_point_temp, set_temp_auto_point_temp, 1, 1);
759b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Merteljstatic SENSOR_DEVICE_ATTR_2(temp1_auto_point3_temp, S_IWUSR | S_IRUGO,
760b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	get_temp_auto_point_temp, set_temp_auto_point_temp, 1, 2);
761b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj
762b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Merteljstatic SENSOR_DEVICE_ATTR_2(temp2_auto_point1_temp, S_IWUSR | S_IRUGO,
763b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	get_temp_auto_point_temp, set_temp_auto_point_temp, 2, 0);
764b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Merteljstatic SENSOR_DEVICE_ATTR_2(temp2_auto_point2_temp, S_IWUSR | S_IRUGO,
765b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	get_temp_auto_point_temp, set_temp_auto_point_temp, 2, 1);
766b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Merteljstatic SENSOR_DEVICE_ATTR_2(temp2_auto_point3_temp, S_IWUSR | S_IRUGO,
767b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	get_temp_auto_point_temp, set_temp_auto_point_temp, 2, 2);
768b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj
769b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj
770b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj
771b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Merteljstatic struct attribute *amc6821_attrs[] = {
772b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	&sensor_dev_attr_temp1_input.dev_attr.attr,
773b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	&sensor_dev_attr_temp1_min.dev_attr.attr,
774b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	&sensor_dev_attr_temp1_max.dev_attr.attr,
775b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	&sensor_dev_attr_temp1_crit.dev_attr.attr,
776b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	&sensor_dev_attr_temp1_min_alarm.dev_attr.attr,
777b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	&sensor_dev_attr_temp1_max_alarm.dev_attr.attr,
778b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	&sensor_dev_attr_temp1_crit_alarm.dev_attr.attr,
779b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	&sensor_dev_attr_temp2_input.dev_attr.attr,
780b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	&sensor_dev_attr_temp2_min.dev_attr.attr,
781b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	&sensor_dev_attr_temp2_max.dev_attr.attr,
782b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	&sensor_dev_attr_temp2_crit.dev_attr.attr,
783b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	&sensor_dev_attr_temp2_min_alarm.dev_attr.attr,
784b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	&sensor_dev_attr_temp2_max_alarm.dev_attr.attr,
785b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	&sensor_dev_attr_temp2_crit_alarm.dev_attr.attr,
786b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	&sensor_dev_attr_temp2_fault.dev_attr.attr,
787b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	&sensor_dev_attr_fan1_input.dev_attr.attr,
788b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	&sensor_dev_attr_fan1_min.dev_attr.attr,
789b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	&sensor_dev_attr_fan1_max.dev_attr.attr,
790b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	&sensor_dev_attr_fan1_fault.dev_attr.attr,
791b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	&sensor_dev_attr_fan1_div.dev_attr.attr,
792b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	&sensor_dev_attr_pwm1.dev_attr.attr,
793b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	&sensor_dev_attr_pwm1_enable.dev_attr.attr,
794b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	&sensor_dev_attr_pwm1_auto_channels_temp.dev_attr.attr,
795b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	&sensor_dev_attr_pwm1_auto_point1_pwm.dev_attr.attr,
796b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	&sensor_dev_attr_pwm1_auto_point2_pwm.dev_attr.attr,
797b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	&sensor_dev_attr_pwm1_auto_point3_pwm.dev_attr.attr,
798b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	&sensor_dev_attr_temp1_auto_point1_temp.dev_attr.attr,
799b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	&sensor_dev_attr_temp1_auto_point2_temp.dev_attr.attr,
800b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	&sensor_dev_attr_temp1_auto_point3_temp.dev_attr.attr,
801b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	&sensor_dev_attr_temp2_auto_point1_temp.dev_attr.attr,
802b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	&sensor_dev_attr_temp2_auto_point2_temp.dev_attr.attr,
803b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	&sensor_dev_attr_temp2_auto_point3_temp.dev_attr.attr,
804b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	NULL
805b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj};
806b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj
807b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Merteljstatic struct attribute_group amc6821_attr_grp = {
808b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	.attrs = amc6821_attrs,
809b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj};
810b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj
811b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj
812b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj
813b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj/* Return 0 if detection is successful, -ENODEV otherwise */
814b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Merteljstatic int amc6821_detect(
815b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj		struct i2c_client *client,
816b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj		struct i2c_board_info *info)
817b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj{
818b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	struct i2c_adapter *adapter = client->adapter;
819b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	int address = client->addr;
820b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	int dev_id, comp_id;
821b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj
822b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	dev_dbg(&adapter->dev, "amc6821_detect called.\n");
823b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj
824b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) {
825b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj		dev_dbg(&adapter->dev,
826b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj			"amc6821: I2C bus doesn't support byte mode, "
827b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj			"skipping.\n");
828b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj		return -ENODEV;
829b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	}
830b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj
831b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	dev_id = i2c_smbus_read_byte_data(client, AMC6821_REG_DEV_ID);
832b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	comp_id = i2c_smbus_read_byte_data(client, AMC6821_REG_COMP_ID);
833b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	if (dev_id != 0x21 || comp_id != 0x49) {
834b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj		dev_dbg(&adapter->dev,
835b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj			"amc6821: detection failed at 0x%02x.\n",
836b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj			address);
837b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj		return -ENODEV;
838b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	}
839b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj
840b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	/* Bit 7 of the address register is ignored, so we can check the
841b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	   ID registers again */
842b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	dev_id = i2c_smbus_read_byte_data(client, 0x80 | AMC6821_REG_DEV_ID);
843b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	comp_id = i2c_smbus_read_byte_data(client, 0x80 | AMC6821_REG_COMP_ID);
844b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	if (dev_id != 0x21 || comp_id != 0x49) {
845b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj		dev_dbg(&adapter->dev,
846b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj			"amc6821: detection failed at 0x%02x.\n",
847b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj			address);
848b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj		return -ENODEV;
849b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	}
850b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj
851b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	dev_info(&adapter->dev, "amc6821: chip found at 0x%02x.\n", address);
852b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	strlcpy(info->type, "amc6821", I2C_NAME_SIZE);
853b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj
854b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	return 0;
855b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj}
856b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj
857b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Merteljstatic int amc6821_probe(
858b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	struct i2c_client *client,
859b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	const struct i2c_device_id *id)
860b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj{
861b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	struct amc6821_data *data;
862b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	int err;
863b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj
864b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	data = kzalloc(sizeof(struct amc6821_data), GFP_KERNEL);
865b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	if (!data) {
866b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj		dev_err(&client->dev, "out of memory.\n");
867b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj		return -ENOMEM;
868b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	}
869b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj
870b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj
871b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	i2c_set_clientdata(client, data);
872b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	mutex_init(&data->update_lock);
873b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj
874b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	/*
875b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	 * Initialize the amc6821 chip
876b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	 */
877b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	err = amc6821_init_client(client);
878b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	if (err)
879b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj		goto err_free;
880b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj
881b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	err = sysfs_create_group(&client->dev.kobj, &amc6821_attr_grp);
882b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	if (err)
883b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj		goto err_free;
884b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj
885b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	data->hwmon_dev = hwmon_device_register(&client->dev);
886b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	if (!IS_ERR(data->hwmon_dev))
887b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj		return 0;
888b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj
889b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	err = PTR_ERR(data->hwmon_dev);
890b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	dev_err(&client->dev, "error registering hwmon device.\n");
891b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	sysfs_remove_group(&client->dev.kobj, &amc6821_attr_grp);
892b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Merteljerr_free:
893b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	kfree(data);
894b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	return err;
895b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj}
896b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj
897b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Merteljstatic int amc6821_remove(struct i2c_client *client)
898b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj{
899b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	struct amc6821_data *data = i2c_get_clientdata(client);
900b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj
901b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	hwmon_device_unregister(data->hwmon_dev);
902b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	sysfs_remove_group(&client->dev.kobj, &amc6821_attr_grp);
903b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj
904b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	kfree(data);
905b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj
906b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	return 0;
907b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj}
908b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj
909b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj
910b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Merteljstatic int amc6821_init_client(struct i2c_client *client)
911b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj{
912b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	int config;
913b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	int err = -EIO;
914b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj
915b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	if (init) {
916b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj		config = i2c_smbus_read_byte_data(client, AMC6821_REG_CONF4);
917b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj
918b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj		if (config < 0) {
919b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj				dev_err(&client->dev,
920b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj			"Error reading configuration register, aborting.\n");
921b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj				return err;
922b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj		}
923b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj
924b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj		config |= AMC6821_CONF4_MODE;
925b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj
926b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj		if (i2c_smbus_write_byte_data(client, AMC6821_REG_CONF4,
927b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj				config)) {
928b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj			dev_err(&client->dev,
929b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj			"Configuration register write error, aborting.\n");
930b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj			return err;
931b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj		}
932b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj
933b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj		config = i2c_smbus_read_byte_data(client, AMC6821_REG_CONF3);
934b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj
935b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj		if (config < 0) {
936b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj			dev_err(&client->dev,
937b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj			"Error reading configuration register, aborting.\n");
938b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj			return err;
939b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj		}
940b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj
941b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj		dev_info(&client->dev, "Revision %d\n", config & 0x0f);
942b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj
943b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj		config &= ~AMC6821_CONF3_THERM_FAN_EN;
944b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj
945b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj		if (i2c_smbus_write_byte_data(client, AMC6821_REG_CONF3,
946b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj				config)) {
947b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj			dev_err(&client->dev,
948b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj			"Configuration register write error, aborting.\n");
949b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj			return err;
950b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj		}
951b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj
952b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj		config = i2c_smbus_read_byte_data(client, AMC6821_REG_CONF2);
953b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj
954b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj		if (config < 0) {
955b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj			dev_err(&client->dev,
956b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj			"Error reading configuration register, aborting.\n");
957b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj			return err;
958b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj		}
959b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj
960b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj		config &= ~AMC6821_CONF2_RTFIE;
961b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj		config &= ~AMC6821_CONF2_LTOIE;
962b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj		config &= ~AMC6821_CONF2_RTOIE;
963b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj		if (i2c_smbus_write_byte_data(client,
964b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj				AMC6821_REG_CONF2, config)) {
965b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj			dev_err(&client->dev,
966b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj			"Configuration register write error, aborting.\n");
967b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj			return err;
968b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj		}
969b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj
970b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj		config = i2c_smbus_read_byte_data(client, AMC6821_REG_CONF1);
971b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj
972b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj		if (config < 0) {
973b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj			dev_err(&client->dev,
974b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj			"Error reading configuration register, aborting.\n");
975b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj			return err;
976b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj		}
977b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj
978b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj		config &= ~AMC6821_CONF1_THERMOVIE;
979b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj		config &= ~AMC6821_CONF1_FANIE;
980b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj		config |= AMC6821_CONF1_START;
981b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj		if (pwminv)
982b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj			config |= AMC6821_CONF1_PWMINV;
983b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj		else
984b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj			config &= ~AMC6821_CONF1_PWMINV;
985b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj
986b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj		if (i2c_smbus_write_byte_data(
987b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj				client, AMC6821_REG_CONF1, config)) {
988b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj			dev_err(&client->dev,
989b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj			"Configuration register write error, aborting.\n");
990b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj			return err;
991b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj		}
992b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	}
993b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	return 0;
994b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj}
995b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj
996b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj
997b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Merteljstatic struct amc6821_data *amc6821_update_device(struct device *dev)
998b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj{
999b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	struct i2c_client *client = to_i2c_client(dev);
1000b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	struct amc6821_data *data = i2c_get_clientdata(client);
1001b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	int timeout = HZ;
1002b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	u8 reg;
1003b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	int i;
1004b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj
1005b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	mutex_lock(&data->update_lock);
1006b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj
1007b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	if (time_after(jiffies, data->last_updated + timeout) ||
1008b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj			!data->valid) {
1009b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj
1010b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj		for (i = 0; i < TEMP_IDX_LEN; i++)
1011b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj			data->temp[i] = i2c_smbus_read_byte_data(client,
1012b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj				temp_reg[i]);
1013b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj
1014b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj		data->stat1 = i2c_smbus_read_byte_data(client,
1015b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj			AMC6821_REG_STAT1);
1016b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj		data->stat2 = i2c_smbus_read_byte_data(client,
1017b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj			AMC6821_REG_STAT2);
1018b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj
1019b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj		data->pwm1 = i2c_smbus_read_byte_data(client,
1020b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj			AMC6821_REG_DCY);
1021b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj		for (i = 0; i < FAN1_IDX_LEN; i++) {
1022b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj			data->fan[i] = i2c_smbus_read_byte_data(
1023b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj					client,
1024b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj					fan_reg_low[i]);
1025b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj			data->fan[i] += i2c_smbus_read_byte_data(
1026b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj					client,
1027b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj					fan_reg_hi[i]) << 8;
1028b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj		}
1029b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj		data->fan1_div = i2c_smbus_read_byte_data(client,
1030b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj			AMC6821_REG_CONF4);
1031b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj		data->fan1_div = data->fan1_div & AMC6821_CONF4_PSPR ? 4 : 2;
1032b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj
1033b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj		data->pwm1_auto_point_pwm[0] = 0;
1034b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj		data->pwm1_auto_point_pwm[2] = 255;
1035b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj		data->pwm1_auto_point_pwm[1] = i2c_smbus_read_byte_data(client,
1036b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj			AMC6821_REG_DCY_LOW_TEMP);
1037b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj
1038b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj		data->temp1_auto_point_temp[0] =
1039b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj			i2c_smbus_read_byte_data(client,
1040b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj					AMC6821_REG_PSV_TEMP);
1041b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj		data->temp2_auto_point_temp[0] =
1042b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj				data->temp1_auto_point_temp[0];
1043b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj		reg = i2c_smbus_read_byte_data(client,
1044b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj			AMC6821_REG_LTEMP_FAN_CTRL);
1045b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj		data->temp1_auto_point_temp[1] = (reg & 0xF8) >> 1;
1046b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj		reg &= 0x07;
1047b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj		reg = 0x20 >> reg;
1048b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj		if (reg > 0)
1049b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj			data->temp1_auto_point_temp[2] =
1050b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj				data->temp1_auto_point_temp[1] +
1051b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj				(data->pwm1_auto_point_pwm[2] -
1052b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj				data->pwm1_auto_point_pwm[1]) / reg;
1053b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj		else
1054b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj			data->temp1_auto_point_temp[2] = 255;
1055b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj
1056b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj		reg = i2c_smbus_read_byte_data(client,
1057b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj			AMC6821_REG_RTEMP_FAN_CTRL);
1058b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj		data->temp2_auto_point_temp[1] = (reg & 0xF8) >> 1;
1059b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj		reg &= 0x07;
1060b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj		reg = 0x20 >> reg;
1061b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj		if (reg > 0)
1062b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj			data->temp2_auto_point_temp[2] =
1063b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj				data->temp2_auto_point_temp[1] +
1064b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj				(data->pwm1_auto_point_pwm[2] -
1065b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj				data->pwm1_auto_point_pwm[1]) / reg;
1066b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj		else
1067b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj			data->temp2_auto_point_temp[2] = 255;
1068b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj
1069b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj		reg = i2c_smbus_read_byte_data(client, AMC6821_REG_CONF1);
1070b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj		reg = (reg >> 5) & 0x3;
1071b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj		switch (reg) {
1072b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj		case 0: /*open loop: software sets pwm1*/
1073b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj			data->pwm1_auto_channels_temp = 0;
1074b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj			data->pwm1_enable = 1;
1075b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj			break;
1076b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj		case 2: /*closed loop: remote T (temp2)*/
1077b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj			data->pwm1_auto_channels_temp = 2;
1078b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj			data->pwm1_enable = 2;
1079b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj			break;
1080b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj		case 3: /*closed loop: local and remote T (temp2)*/
1081b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj			data->pwm1_auto_channels_temp = 3;
1082b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj			data->pwm1_enable = 3;
1083b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj			break;
1084b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj		case 1: /*semi-open loop: software sets rpm, chip controls pwm1,
1085b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj			  *currently not implemented
1086b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj			  */
1087b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj			data->pwm1_auto_channels_temp = 0;
1088b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj			data->pwm1_enable = 0;
1089b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj			break;
1090b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj		}
1091b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj
1092b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj		data->last_updated = jiffies;
1093b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj		data->valid = 1;
1094b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	}
1095b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	mutex_unlock(&data->update_lock);
1096b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	return data;
1097b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj}
1098b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj
1099b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj
1100b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Merteljstatic int __init amc6821_init(void)
1101b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj{
1102b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	return i2c_add_driver(&amc6821_driver);
1103b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj}
1104b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj
1105b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Merteljstatic void __exit amc6821_exit(void)
1106b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj{
1107b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj	i2c_del_driver(&amc6821_driver);
1108b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj}
1109b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj
1110b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Merteljmodule_init(amc6821_init);
1111b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Merteljmodule_exit(amc6821_exit);
1112b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj
1113b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj
1114b5430a04e995081a308b4419bd0940f2badc6e6bTomaz MerteljMODULE_LICENSE("GPL");
1115b5430a04e995081a308b4419bd0940f2badc6e6bTomaz MerteljMODULE_AUTHOR("T. Mertelj <tomaz.mertelj@guest.arnes.si>");
1116b5430a04e995081a308b4419bd0940f2badc6e6bTomaz MerteljMODULE_DESCRIPTION("Texas Instruments amc6821 hwmon driver");
1117