xref: /openbmc/linux/drivers/hwmon/asc7621.c (revision 1975d167)
174ba9207SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
2d58de038SGeorge Joseph /*
3d58de038SGeorge Joseph  * asc7621.c - Part of lm_sensors, Linux kernel modules for hardware monitoring
4d58de038SGeorge Joseph  * Copyright (c) 2007, 2010 George Joseph  <george.joseph@fairview5.com>
5d58de038SGeorge Joseph  */
6d58de038SGeorge Joseph 
7d58de038SGeorge Joseph #include <linux/module.h>
8d58de038SGeorge Joseph #include <linux/init.h>
9d58de038SGeorge Joseph #include <linux/slab.h>
10d58de038SGeorge Joseph #include <linux/jiffies.h>
11d58de038SGeorge Joseph #include <linux/i2c.h>
12d58de038SGeorge Joseph #include <linux/hwmon.h>
13d58de038SGeorge Joseph #include <linux/hwmon-sysfs.h>
14d58de038SGeorge Joseph #include <linux/err.h>
15d58de038SGeorge Joseph #include <linux/mutex.h>
16d58de038SGeorge Joseph 
17d58de038SGeorge Joseph /* Addresses to scan */
18918ee91cSJean Delvare static const unsigned short normal_i2c[] = {
19d58de038SGeorge Joseph 	0x2c, 0x2d, 0x2e, I2C_CLIENT_END
20d58de038SGeorge Joseph };
21d58de038SGeorge Joseph 
22d58de038SGeorge Joseph enum asc7621_type {
23d58de038SGeorge Joseph 	asc7621,
24d58de038SGeorge Joseph 	asc7621a
25d58de038SGeorge Joseph };
26d58de038SGeorge Joseph 
27d58de038SGeorge Joseph #define INTERVAL_HIGH   (HZ + HZ / 2)
28d58de038SGeorge Joseph #define INTERVAL_LOW    (1 * 60 * HZ)
29d58de038SGeorge Joseph #define PRI_NONE        0
30d58de038SGeorge Joseph #define PRI_LOW         1
31d58de038SGeorge Joseph #define PRI_HIGH        2
32d58de038SGeorge Joseph #define FIRST_CHIP      asc7621
33d58de038SGeorge Joseph #define LAST_CHIP       asc7621a
34d58de038SGeorge Joseph 
35d58de038SGeorge Joseph struct asc7621_chip {
36d58de038SGeorge Joseph 	char *name;
37d58de038SGeorge Joseph 	enum asc7621_type chip_type;
38d58de038SGeorge Joseph 	u8 company_reg;
39d58de038SGeorge Joseph 	u8 company_id;
40d58de038SGeorge Joseph 	u8 verstep_reg;
41d58de038SGeorge Joseph 	u8 verstep_id;
42918ee91cSJean Delvare 	const unsigned short *addresses;
43d58de038SGeorge Joseph };
44d58de038SGeorge Joseph 
45d58de038SGeorge Joseph static struct asc7621_chip asc7621_chips[] = {
46d58de038SGeorge Joseph 	{
47d58de038SGeorge Joseph 		.name = "asc7621",
48d58de038SGeorge Joseph 		.chip_type = asc7621,
49d58de038SGeorge Joseph 		.company_reg = 0x3e,
50d58de038SGeorge Joseph 		.company_id = 0x61,
51d58de038SGeorge Joseph 		.verstep_reg = 0x3f,
52d58de038SGeorge Joseph 		.verstep_id = 0x6c,
53d58de038SGeorge Joseph 		.addresses = normal_i2c,
54d58de038SGeorge Joseph 	 },
55d58de038SGeorge Joseph 	{
56d58de038SGeorge Joseph 		.name = "asc7621a",
57d58de038SGeorge Joseph 		.chip_type = asc7621a,
58d58de038SGeorge Joseph 		.company_reg = 0x3e,
59d58de038SGeorge Joseph 		.company_id = 0x61,
60d58de038SGeorge Joseph 		.verstep_reg = 0x3f,
61d58de038SGeorge Joseph 		.verstep_id = 0x6d,
62d58de038SGeorge Joseph 		.addresses = normal_i2c,
63d58de038SGeorge Joseph 	 },
64d58de038SGeorge Joseph };
65d58de038SGeorge Joseph 
66d58de038SGeorge Joseph /*
67d58de038SGeorge Joseph  * Defines the highest register to be used, not the count.
68d58de038SGeorge Joseph  * The actual count will probably be smaller because of gaps
69d58de038SGeorge Joseph  * in the implementation (unused register locations).
70d58de038SGeorge Joseph  * This define will safely set the array size of both the parameter
71d58de038SGeorge Joseph  * and data arrays.
72d58de038SGeorge Joseph  * This comes from the data sheet register description table.
73d58de038SGeorge Joseph  */
74d58de038SGeorge Joseph #define LAST_REGISTER 0xff
75d58de038SGeorge Joseph 
76d58de038SGeorge Joseph struct asc7621_data {
77d58de038SGeorge Joseph 	struct i2c_client client;
78d58de038SGeorge Joseph 	struct device *class_dev;
79d58de038SGeorge Joseph 	struct mutex update_lock;
80952a11caSPaul Fertser 	bool valid;		/* true if following fields are valid */
81d58de038SGeorge Joseph 	unsigned long last_high_reading;	/* In jiffies */
82d58de038SGeorge Joseph 	unsigned long last_low_reading;		/* In jiffies */
83d58de038SGeorge Joseph 	/*
84d58de038SGeorge Joseph 	 * Registers we care about occupy the corresponding index
85d58de038SGeorge Joseph 	 * in the array.  Registers we don't care about are left
86d58de038SGeorge Joseph 	 * at 0.
87d58de038SGeorge Joseph 	 */
88d58de038SGeorge Joseph 	u8 reg[LAST_REGISTER + 1];
89d58de038SGeorge Joseph };
90d58de038SGeorge Joseph 
91d58de038SGeorge Joseph /*
92d58de038SGeorge Joseph  * Macro to get the parent asc7621_param structure
93d58de038SGeorge Joseph  * from a sensor_device_attribute passed into the
94d58de038SGeorge Joseph  * show/store functions.
95d58de038SGeorge Joseph  */
96d58de038SGeorge Joseph #define to_asc7621_param(_sda) \
97d58de038SGeorge Joseph 	container_of(_sda, struct asc7621_param, sda)
98d58de038SGeorge Joseph 
99d58de038SGeorge Joseph /*
100d58de038SGeorge Joseph  * Each parameter to be retrieved needs an asc7621_param structure
101d58de038SGeorge Joseph  * allocated.  It contains the sensor_device_attribute structure
102d58de038SGeorge Joseph  * and the control info needed to retrieve the value from the register map.
103d58de038SGeorge Joseph  */
104d58de038SGeorge Joseph struct asc7621_param {
105d58de038SGeorge Joseph 	struct sensor_device_attribute sda;
106d58de038SGeorge Joseph 	u8 priority;
107d58de038SGeorge Joseph 	u8 msb[3];
108d58de038SGeorge Joseph 	u8 lsb[3];
109d58de038SGeorge Joseph 	u8 mask[3];
110d58de038SGeorge Joseph 	u8 shift[3];
111d58de038SGeorge Joseph };
112d58de038SGeorge Joseph 
113d58de038SGeorge Joseph /*
114d58de038SGeorge Joseph  * This is the map that ultimately indicates whether we'll be
115d58de038SGeorge Joseph  * retrieving a register value or not, and at what frequency.
116d58de038SGeorge Joseph  */
117d58de038SGeorge Joseph static u8 asc7621_register_priorities[255];
118d58de038SGeorge Joseph 
119d58de038SGeorge Joseph static struct asc7621_data *asc7621_update_device(struct device *dev);
120d58de038SGeorge Joseph 
read_byte(struct i2c_client * client,u8 reg)121d58de038SGeorge Joseph static inline u8 read_byte(struct i2c_client *client, u8 reg)
122d58de038SGeorge Joseph {
123d58de038SGeorge Joseph 	int res = i2c_smbus_read_byte_data(client, reg);
124d58de038SGeorge Joseph 	if (res < 0) {
125d58de038SGeorge Joseph 		dev_err(&client->dev,
126d58de038SGeorge Joseph 			"Unable to read from register 0x%02x.\n", reg);
127d58de038SGeorge Joseph 		return 0;
128a0393713SGuenter Roeck 	}
129d58de038SGeorge Joseph 	return res & 0xff;
130d58de038SGeorge Joseph }
131d58de038SGeorge Joseph 
write_byte(struct i2c_client * client,u8 reg,u8 data)132d58de038SGeorge Joseph static inline int write_byte(struct i2c_client *client, u8 reg, u8 data)
133d58de038SGeorge Joseph {
134d58de038SGeorge Joseph 	int res = i2c_smbus_write_byte_data(client, reg, data);
135d58de038SGeorge Joseph 	if (res < 0) {
136d58de038SGeorge Joseph 		dev_err(&client->dev,
137d58de038SGeorge Joseph 			"Unable to write value 0x%02x to register 0x%02x.\n",
138d58de038SGeorge Joseph 			data, reg);
139a0393713SGuenter Roeck 	}
140d58de038SGeorge Joseph 	return res;
141d58de038SGeorge Joseph }
142d58de038SGeorge Joseph 
143d58de038SGeorge Joseph /*
144d58de038SGeorge Joseph  * Data Handlers
145d58de038SGeorge Joseph  * Each function handles the formatting, storage
146d58de038SGeorge Joseph  * and retrieval of like parameters.
147d58de038SGeorge Joseph  */
148d58de038SGeorge Joseph 
149088ce2acSGuenter Roeck #define SETUP_SHOW_DATA_PARAM(d, a) \
150d58de038SGeorge Joseph 	struct sensor_device_attribute *sda = to_sensor_dev_attr(a); \
151d58de038SGeorge Joseph 	struct asc7621_data *data = asc7621_update_device(d); \
152d58de038SGeorge Joseph 	struct asc7621_param *param = to_asc7621_param(sda)
153d58de038SGeorge Joseph 
154088ce2acSGuenter Roeck #define SETUP_STORE_DATA_PARAM(d, a) \
155d58de038SGeorge Joseph 	struct sensor_device_attribute *sda = to_sensor_dev_attr(a); \
156d58de038SGeorge Joseph 	struct i2c_client *client = to_i2c_client(d); \
157d58de038SGeorge Joseph 	struct asc7621_data *data = i2c_get_clientdata(client); \
158d58de038SGeorge Joseph 	struct asc7621_param *param = to_asc7621_param(sda)
159d58de038SGeorge Joseph 
160d58de038SGeorge Joseph /*
161d58de038SGeorge Joseph  * u8 is just what it sounds like...an unsigned byte with no
162d58de038SGeorge Joseph  * special formatting.
163d58de038SGeorge Joseph  */
show_u8(struct device * dev,struct device_attribute * attr,char * buf)164d58de038SGeorge Joseph static ssize_t show_u8(struct device *dev, struct device_attribute *attr,
165d58de038SGeorge Joseph 		       char *buf)
166d58de038SGeorge Joseph {
167088ce2acSGuenter Roeck 	SETUP_SHOW_DATA_PARAM(dev, attr);
168d58de038SGeorge Joseph 
169d58de038SGeorge Joseph 	return sprintf(buf, "%u\n", data->reg[param->msb[0]]);
170d58de038SGeorge Joseph }
171d58de038SGeorge Joseph 
store_u8(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)172d58de038SGeorge Joseph static ssize_t store_u8(struct device *dev, struct device_attribute *attr,
173d58de038SGeorge Joseph 			const char *buf, size_t count)
174d58de038SGeorge Joseph {
175088ce2acSGuenter Roeck 	SETUP_STORE_DATA_PARAM(dev, attr);
176d58de038SGeorge Joseph 	long reqval;
177d58de038SGeorge Joseph 
178179c4fdbSFrans Meulenbroeks 	if (kstrtol(buf, 10, &reqval))
179d58de038SGeorge Joseph 		return -EINVAL;
180d58de038SGeorge Joseph 
1812a844c14SGuenter Roeck 	reqval = clamp_val(reqval, 0, 255);
182d58de038SGeorge Joseph 
183d58de038SGeorge Joseph 	mutex_lock(&data->update_lock);
184d58de038SGeorge Joseph 	data->reg[param->msb[0]] = reqval;
185d58de038SGeorge Joseph 	write_byte(client, param->msb[0], reqval);
186d58de038SGeorge Joseph 	mutex_unlock(&data->update_lock);
187d58de038SGeorge Joseph 	return count;
188d58de038SGeorge Joseph }
189d58de038SGeorge Joseph 
190d58de038SGeorge Joseph /*
191d58de038SGeorge Joseph  * Many of the config values occupy only a few bits of a register.
192d58de038SGeorge Joseph  */
show_bitmask(struct device * dev,struct device_attribute * attr,char * buf)193d58de038SGeorge Joseph static ssize_t show_bitmask(struct device *dev,
194d58de038SGeorge Joseph 			    struct device_attribute *attr, char *buf)
195d58de038SGeorge Joseph {
196088ce2acSGuenter Roeck 	SETUP_SHOW_DATA_PARAM(dev, attr);
197d58de038SGeorge Joseph 
198d58de038SGeorge Joseph 	return sprintf(buf, "%u\n",
199d58de038SGeorge Joseph 		       (data->reg[param->msb[0]] >> param->
200d58de038SGeorge Joseph 			shift[0]) & param->mask[0]);
201d58de038SGeorge Joseph }
202d58de038SGeorge Joseph 
store_bitmask(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)203d58de038SGeorge Joseph static ssize_t store_bitmask(struct device *dev,
204d58de038SGeorge Joseph 			     struct device_attribute *attr,
205d58de038SGeorge Joseph 			     const char *buf, size_t count)
206d58de038SGeorge Joseph {
207088ce2acSGuenter Roeck 	SETUP_STORE_DATA_PARAM(dev, attr);
208d58de038SGeorge Joseph 	long reqval;
209d58de038SGeorge Joseph 	u8 currval;
210d58de038SGeorge Joseph 
211179c4fdbSFrans Meulenbroeks 	if (kstrtol(buf, 10, &reqval))
212d58de038SGeorge Joseph 		return -EINVAL;
213d58de038SGeorge Joseph 
2142a844c14SGuenter Roeck 	reqval = clamp_val(reqval, 0, param->mask[0]);
215d58de038SGeorge Joseph 
216d58de038SGeorge Joseph 	reqval = (reqval & param->mask[0]) << param->shift[0];
217d58de038SGeorge Joseph 
218d58de038SGeorge Joseph 	mutex_lock(&data->update_lock);
219d58de038SGeorge Joseph 	currval = read_byte(client, param->msb[0]);
220d58de038SGeorge Joseph 	reqval |= (currval & ~(param->mask[0] << param->shift[0]));
221d58de038SGeorge Joseph 	data->reg[param->msb[0]] = reqval;
222d58de038SGeorge Joseph 	write_byte(client, param->msb[0], reqval);
223d58de038SGeorge Joseph 	mutex_unlock(&data->update_lock);
224d58de038SGeorge Joseph 	return count;
225d58de038SGeorge Joseph }
226d58de038SGeorge Joseph 
227d58de038SGeorge Joseph /*
228d58de038SGeorge Joseph  * 16 bit fan rpm values
229d58de038SGeorge Joseph  * reported by the device as the number of 11.111us periods (90khz)
230d58de038SGeorge Joseph  * between full fan rotations.  Therefore...
231d58de038SGeorge Joseph  * RPM = (90000 * 60) / register value
232d58de038SGeorge Joseph  */
show_fan16(struct device * dev,struct device_attribute * attr,char * buf)233d58de038SGeorge Joseph static ssize_t show_fan16(struct device *dev,
234d58de038SGeorge Joseph 			  struct device_attribute *attr, char *buf)
235d58de038SGeorge Joseph {
236088ce2acSGuenter Roeck 	SETUP_SHOW_DATA_PARAM(dev, attr);
237d58de038SGeorge Joseph 	u16 regval;
238d58de038SGeorge Joseph 
239d58de038SGeorge Joseph 	mutex_lock(&data->update_lock);
240d58de038SGeorge Joseph 	regval = (data->reg[param->msb[0]] << 8) | data->reg[param->lsb[0]];
241d58de038SGeorge Joseph 	mutex_unlock(&data->update_lock);
242d58de038SGeorge Joseph 
243d58de038SGeorge Joseph 	return sprintf(buf, "%u\n",
244d58de038SGeorge Joseph 		       (regval == 0 ? -1 : (regval) ==
245d58de038SGeorge Joseph 			0xffff ? 0 : 5400000 / regval));
246d58de038SGeorge Joseph }
247d58de038SGeorge Joseph 
store_fan16(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)248d58de038SGeorge Joseph static ssize_t store_fan16(struct device *dev,
249d58de038SGeorge Joseph 			   struct device_attribute *attr, const char *buf,
250d58de038SGeorge Joseph 			   size_t count)
251d58de038SGeorge Joseph {
252088ce2acSGuenter Roeck 	SETUP_STORE_DATA_PARAM(dev, attr);
253d58de038SGeorge Joseph 	long reqval;
254d58de038SGeorge Joseph 
255179c4fdbSFrans Meulenbroeks 	if (kstrtol(buf, 10, &reqval))
256d58de038SGeorge Joseph 		return -EINVAL;
257d58de038SGeorge Joseph 
2583c56b066SGuenter Roeck 	/*
2593c56b066SGuenter Roeck 	 * If a minimum RPM of zero is requested, then we set the register to
2603c56b066SGuenter Roeck 	 * 0xffff. This value allows the fan to be stopped completely without
2613c56b066SGuenter Roeck 	 * generating an alarm.
2623c56b066SGuenter Roeck 	 */
263d58de038SGeorge Joseph 	reqval =
2642a844c14SGuenter Roeck 	    (reqval <= 0 ? 0xffff : clamp_val(5400000 / reqval, 0, 0xfffe));
265d58de038SGeorge Joseph 
266d58de038SGeorge Joseph 	mutex_lock(&data->update_lock);
267d58de038SGeorge Joseph 	data->reg[param->msb[0]] = (reqval >> 8) & 0xff;
268d58de038SGeorge Joseph 	data->reg[param->lsb[0]] = reqval & 0xff;
269d58de038SGeorge Joseph 	write_byte(client, param->msb[0], data->reg[param->msb[0]]);
270d58de038SGeorge Joseph 	write_byte(client, param->lsb[0], data->reg[param->lsb[0]]);
271d58de038SGeorge Joseph 	mutex_unlock(&data->update_lock);
272d58de038SGeorge Joseph 
273d58de038SGeorge Joseph 	return count;
274d58de038SGeorge Joseph }
275d58de038SGeorge Joseph 
276d58de038SGeorge Joseph /*
277d58de038SGeorge Joseph  * Voltages are scaled in the device so that the nominal voltage
278d58de038SGeorge Joseph  * is 3/4ths of the 0-255 range (i.e. 192).
279d58de038SGeorge Joseph  * If all voltages are 'normal' then all voltage registers will
280d1bf8cf6SKen Milmore  * read 0xC0.
281d1bf8cf6SKen Milmore  *
282d1bf8cf6SKen Milmore  * The data sheet provides us with the 3/4 scale value for each voltage
283d58de038SGeorge Joseph  * which is stored in in_scaling.  The sda->index parameter value provides
284d58de038SGeorge Joseph  * the index into in_scaling.
285d58de038SGeorge Joseph  *
286d58de038SGeorge Joseph  * NOTE: The chip expects the first 2 inputs be 2.5 and 2.25 volts
287d58de038SGeorge Joseph  * respectively. That doesn't mean that's what the motherboard provides. :)
288d58de038SGeorge Joseph  */
289d58de038SGeorge Joseph 
2907a7176aaSAxel Lin static const int asc7621_in_scaling[] = {
291d1bf8cf6SKen Milmore 	2500, 2250, 3300, 5000, 12000
292d58de038SGeorge Joseph };
293d58de038SGeorge Joseph 
show_in10(struct device * dev,struct device_attribute * attr,char * buf)294d58de038SGeorge Joseph static ssize_t show_in10(struct device *dev, struct device_attribute *attr,
295d58de038SGeorge Joseph 			 char *buf)
296d58de038SGeorge Joseph {
297088ce2acSGuenter Roeck 	SETUP_SHOW_DATA_PARAM(dev, attr);
298d58de038SGeorge Joseph 	u16 regval;
299d58de038SGeorge Joseph 	u8 nr = sda->index;
300d58de038SGeorge Joseph 
301d58de038SGeorge Joseph 	mutex_lock(&data->update_lock);
302d1bf8cf6SKen Milmore 	regval = (data->reg[param->msb[0]] << 8) | (data->reg[param->lsb[0]]);
303d58de038SGeorge Joseph 	mutex_unlock(&data->update_lock);
304d58de038SGeorge Joseph 
305d1bf8cf6SKen Milmore 	/* The LSB value is a 2-bit scaling of the MSB's LSbit value. */
306d1bf8cf6SKen Milmore 	regval = (regval >> 6) * asc7621_in_scaling[nr] / (0xc0 << 2);
307d1bf8cf6SKen Milmore 
308d58de038SGeorge Joseph 	return sprintf(buf, "%u\n", regval);
309d58de038SGeorge Joseph }
310d58de038SGeorge Joseph 
311d58de038SGeorge Joseph /* 8 bit voltage values (the mins and maxs) */
show_in8(struct device * dev,struct device_attribute * attr,char * buf)312d58de038SGeorge Joseph static ssize_t show_in8(struct device *dev, struct device_attribute *attr,
313d58de038SGeorge Joseph 			char *buf)
314d58de038SGeorge Joseph {
315088ce2acSGuenter Roeck 	SETUP_SHOW_DATA_PARAM(dev, attr);
316d58de038SGeorge Joseph 	u8 nr = sda->index;
317d58de038SGeorge Joseph 
318d58de038SGeorge Joseph 	return sprintf(buf, "%u\n",
319d58de038SGeorge Joseph 		       ((data->reg[param->msb[0]] *
320d1bf8cf6SKen Milmore 			 asc7621_in_scaling[nr]) / 0xc0));
321d58de038SGeorge Joseph }
322d58de038SGeorge Joseph 
store_in8(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)323d58de038SGeorge Joseph static ssize_t store_in8(struct device *dev, struct device_attribute *attr,
324d58de038SGeorge Joseph 			 const char *buf, size_t count)
325d58de038SGeorge Joseph {
326088ce2acSGuenter Roeck 	SETUP_STORE_DATA_PARAM(dev, attr);
327d58de038SGeorge Joseph 	long reqval;
328d58de038SGeorge Joseph 	u8 nr = sda->index;
329d58de038SGeorge Joseph 
330179c4fdbSFrans Meulenbroeks 	if (kstrtol(buf, 10, &reqval))
331d58de038SGeorge Joseph 		return -EINVAL;
332d58de038SGeorge Joseph 
3332a844c14SGuenter Roeck 	reqval = clamp_val(reqval, 0, 0xffff);
334d58de038SGeorge Joseph 
335d1bf8cf6SKen Milmore 	reqval = reqval * 0xc0 / asc7621_in_scaling[nr];
336d1bf8cf6SKen Milmore 
3372a844c14SGuenter Roeck 	reqval = clamp_val(reqval, 0, 0xff);
338d58de038SGeorge Joseph 
339d58de038SGeorge Joseph 	mutex_lock(&data->update_lock);
340d58de038SGeorge Joseph 	data->reg[param->msb[0]] = reqval;
341d58de038SGeorge Joseph 	write_byte(client, param->msb[0], reqval);
342d58de038SGeorge Joseph 	mutex_unlock(&data->update_lock);
343d58de038SGeorge Joseph 
344d58de038SGeorge Joseph 	return count;
345d58de038SGeorge Joseph }
346d58de038SGeorge Joseph 
show_temp8(struct device * dev,struct device_attribute * attr,char * buf)347d58de038SGeorge Joseph static ssize_t show_temp8(struct device *dev,
348d58de038SGeorge Joseph 			  struct device_attribute *attr, char *buf)
349d58de038SGeorge Joseph {
350088ce2acSGuenter Roeck 	SETUP_SHOW_DATA_PARAM(dev, attr);
351d58de038SGeorge Joseph 
352d58de038SGeorge Joseph 	return sprintf(buf, "%d\n", ((s8) data->reg[param->msb[0]]) * 1000);
353d58de038SGeorge Joseph }
354d58de038SGeorge Joseph 
store_temp8(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)355d58de038SGeorge Joseph static ssize_t store_temp8(struct device *dev,
356d58de038SGeorge Joseph 			   struct device_attribute *attr, const char *buf,
357d58de038SGeorge Joseph 			   size_t count)
358d58de038SGeorge Joseph {
359088ce2acSGuenter Roeck 	SETUP_STORE_DATA_PARAM(dev, attr);
360d58de038SGeorge Joseph 	long reqval;
361d58de038SGeorge Joseph 	s8 temp;
362d58de038SGeorge Joseph 
363179c4fdbSFrans Meulenbroeks 	if (kstrtol(buf, 10, &reqval))
364d58de038SGeorge Joseph 		return -EINVAL;
365d58de038SGeorge Joseph 
3662a844c14SGuenter Roeck 	reqval = clamp_val(reqval, -127000, 127000);
367d58de038SGeorge Joseph 
368d58de038SGeorge Joseph 	temp = reqval / 1000;
369d58de038SGeorge Joseph 
370d58de038SGeorge Joseph 	mutex_lock(&data->update_lock);
371d58de038SGeorge Joseph 	data->reg[param->msb[0]] = temp;
372d58de038SGeorge Joseph 	write_byte(client, param->msb[0], temp);
373d58de038SGeorge Joseph 	mutex_unlock(&data->update_lock);
374d58de038SGeorge Joseph 	return count;
375d58de038SGeorge Joseph }
376d58de038SGeorge Joseph 
377d58de038SGeorge Joseph /*
378d58de038SGeorge Joseph  * Temperatures that occupy 2 bytes always have the whole
379d58de038SGeorge Joseph  * number of degrees in the MSB with some part of the LSB
380d58de038SGeorge Joseph  * indicating fractional degrees.
381d58de038SGeorge Joseph  */
382d58de038SGeorge Joseph 
383d58de038SGeorge Joseph /*   mmmmmmmm.llxxxxxx */
show_temp10(struct device * dev,struct device_attribute * attr,char * buf)384d58de038SGeorge Joseph static ssize_t show_temp10(struct device *dev,
385d58de038SGeorge Joseph 			   struct device_attribute *attr, char *buf)
386d58de038SGeorge Joseph {
387088ce2acSGuenter Roeck 	SETUP_SHOW_DATA_PARAM(dev, attr);
388d58de038SGeorge Joseph 	u8 msb, lsb;
389d58de038SGeorge Joseph 	int temp;
390d58de038SGeorge Joseph 
391d58de038SGeorge Joseph 	mutex_lock(&data->update_lock);
392d58de038SGeorge Joseph 	msb = data->reg[param->msb[0]];
393d58de038SGeorge Joseph 	lsb = (data->reg[param->lsb[0]] >> 6) & 0x03;
394d58de038SGeorge Joseph 	temp = (((s8) msb) * 1000) + (lsb * 250);
395d58de038SGeorge Joseph 	mutex_unlock(&data->update_lock);
396d58de038SGeorge Joseph 
397d58de038SGeorge Joseph 	return sprintf(buf, "%d\n", temp);
398d58de038SGeorge Joseph }
399d58de038SGeorge Joseph 
400d58de038SGeorge Joseph /*   mmmmmm.ll */
show_temp62(struct device * dev,struct device_attribute * attr,char * buf)401d58de038SGeorge Joseph static ssize_t show_temp62(struct device *dev,
402d58de038SGeorge Joseph 			   struct device_attribute *attr, char *buf)
403d58de038SGeorge Joseph {
404088ce2acSGuenter Roeck 	SETUP_SHOW_DATA_PARAM(dev, attr);
405d58de038SGeorge Joseph 	u8 regval = data->reg[param->msb[0]];
406d58de038SGeorge Joseph 	int temp = ((s8) (regval & 0xfc) * 1000) + ((regval & 0x03) * 250);
407d58de038SGeorge Joseph 
408d58de038SGeorge Joseph 	return sprintf(buf, "%d\n", temp);
409d58de038SGeorge Joseph }
410d58de038SGeorge Joseph 
store_temp62(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)411d58de038SGeorge Joseph static ssize_t store_temp62(struct device *dev,
412d58de038SGeorge Joseph 			    struct device_attribute *attr, const char *buf,
413d58de038SGeorge Joseph 			    size_t count)
414d58de038SGeorge Joseph {
415088ce2acSGuenter Roeck 	SETUP_STORE_DATA_PARAM(dev, attr);
416d58de038SGeorge Joseph 	long reqval, i, f;
417d58de038SGeorge Joseph 	s8 temp;
418d58de038SGeorge Joseph 
419179c4fdbSFrans Meulenbroeks 	if (kstrtol(buf, 10, &reqval))
420d58de038SGeorge Joseph 		return -EINVAL;
421d58de038SGeorge Joseph 
4222a844c14SGuenter Roeck 	reqval = clamp_val(reqval, -32000, 31750);
423d58de038SGeorge Joseph 	i = reqval / 1000;
424d58de038SGeorge Joseph 	f = reqval - (i * 1000);
425d58de038SGeorge Joseph 	temp = i << 2;
426d58de038SGeorge Joseph 	temp |= f / 250;
427d58de038SGeorge Joseph 
428d58de038SGeorge Joseph 	mutex_lock(&data->update_lock);
429d58de038SGeorge Joseph 	data->reg[param->msb[0]] = temp;
430d58de038SGeorge Joseph 	write_byte(client, param->msb[0], temp);
431d58de038SGeorge Joseph 	mutex_unlock(&data->update_lock);
432d58de038SGeorge Joseph 	return count;
433d58de038SGeorge Joseph }
434d58de038SGeorge Joseph 
435d58de038SGeorge Joseph /*
436d58de038SGeorge Joseph  * The aSC7621 doesn't provide an "auto_point2".  Instead, you
437d58de038SGeorge Joseph  * specify the auto_point1 and a range.  To keep with the sysfs
438d58de038SGeorge Joseph  * hwmon specs, we synthesize the auto_point_2 from them.
439d58de038SGeorge Joseph  */
440d58de038SGeorge Joseph 
4417a7176aaSAxel Lin static const u32 asc7621_range_map[] = {
442d58de038SGeorge Joseph 	2000, 2500, 3330, 4000, 5000, 6670, 8000, 10000,
443d58de038SGeorge Joseph 	13330, 16000, 20000, 26670, 32000, 40000, 53330, 80000,
444d58de038SGeorge Joseph };
445d58de038SGeorge Joseph 
show_ap2_temp(struct device * dev,struct device_attribute * attr,char * buf)446d58de038SGeorge Joseph static ssize_t show_ap2_temp(struct device *dev,
447d58de038SGeorge Joseph 			     struct device_attribute *attr, char *buf)
448d58de038SGeorge Joseph {
449088ce2acSGuenter Roeck 	SETUP_SHOW_DATA_PARAM(dev, attr);
450d58de038SGeorge Joseph 	long auto_point1;
451d58de038SGeorge Joseph 	u8 regval;
452d58de038SGeorge Joseph 	int temp;
453d58de038SGeorge Joseph 
454d58de038SGeorge Joseph 	mutex_lock(&data->update_lock);
455d58de038SGeorge Joseph 	auto_point1 = ((s8) data->reg[param->msb[1]]) * 1000;
456d58de038SGeorge Joseph 	regval =
457d58de038SGeorge Joseph 	    ((data->reg[param->msb[0]] >> param->shift[0]) & param->mask[0]);
4582a844c14SGuenter Roeck 	temp = auto_point1 + asc7621_range_map[clamp_val(regval, 0, 15)];
459d58de038SGeorge Joseph 	mutex_unlock(&data->update_lock);
460d58de038SGeorge Joseph 
461d58de038SGeorge Joseph 	return sprintf(buf, "%d\n", temp);
462d58de038SGeorge Joseph 
463d58de038SGeorge Joseph }
464d58de038SGeorge Joseph 
store_ap2_temp(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)465d58de038SGeorge Joseph static ssize_t store_ap2_temp(struct device *dev,
466d58de038SGeorge Joseph 			      struct device_attribute *attr,
467d58de038SGeorge Joseph 			      const char *buf, size_t count)
468d58de038SGeorge Joseph {
469088ce2acSGuenter Roeck 	SETUP_STORE_DATA_PARAM(dev, attr);
470d58de038SGeorge Joseph 	long reqval, auto_point1;
471d58de038SGeorge Joseph 	int i;
472d58de038SGeorge Joseph 	u8 currval, newval = 0;
473d58de038SGeorge Joseph 
474179c4fdbSFrans Meulenbroeks 	if (kstrtol(buf, 10, &reqval))
475d58de038SGeorge Joseph 		return -EINVAL;
476d58de038SGeorge Joseph 
477d58de038SGeorge Joseph 	mutex_lock(&data->update_lock);
478d58de038SGeorge Joseph 	auto_point1 = data->reg[param->msb[1]] * 1000;
4792a844c14SGuenter Roeck 	reqval = clamp_val(reqval, auto_point1 + 2000, auto_point1 + 80000);
480d58de038SGeorge Joseph 
481d58de038SGeorge Joseph 	for (i = ARRAY_SIZE(asc7621_range_map) - 1; i >= 0; i--) {
482d58de038SGeorge Joseph 		if (reqval >= auto_point1 + asc7621_range_map[i]) {
483d58de038SGeorge Joseph 			newval = i;
484d58de038SGeorge Joseph 			break;
485d58de038SGeorge Joseph 		}
486d58de038SGeorge Joseph 	}
487d58de038SGeorge Joseph 
488d58de038SGeorge Joseph 	newval = (newval & param->mask[0]) << param->shift[0];
489d58de038SGeorge Joseph 	currval = read_byte(client, param->msb[0]);
490d58de038SGeorge Joseph 	newval |= (currval & ~(param->mask[0] << param->shift[0]));
491d58de038SGeorge Joseph 	data->reg[param->msb[0]] = newval;
492d58de038SGeorge Joseph 	write_byte(client, param->msb[0], newval);
493d58de038SGeorge Joseph 	mutex_unlock(&data->update_lock);
494d58de038SGeorge Joseph 	return count;
495d58de038SGeorge Joseph }
496d58de038SGeorge Joseph 
show_pwm_ac(struct device * dev,struct device_attribute * attr,char * buf)497d58de038SGeorge Joseph static ssize_t show_pwm_ac(struct device *dev,
498d58de038SGeorge Joseph 			   struct device_attribute *attr, char *buf)
499d58de038SGeorge Joseph {
500088ce2acSGuenter Roeck 	SETUP_SHOW_DATA_PARAM(dev, attr);
501d58de038SGeorge Joseph 	u8 config, altbit, regval;
50269301258SColin Ian King 	static const u8 map[] = {
503d58de038SGeorge Joseph 		0x01, 0x02, 0x04, 0x1f, 0x00, 0x06, 0x07, 0x10,
504d58de038SGeorge Joseph 		0x08, 0x0f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f
505d58de038SGeorge Joseph 	};
506d58de038SGeorge Joseph 
507d58de038SGeorge Joseph 	mutex_lock(&data->update_lock);
508d58de038SGeorge Joseph 	config = (data->reg[param->msb[0]] >> param->shift[0]) & param->mask[0];
509d58de038SGeorge Joseph 	altbit = (data->reg[param->msb[1]] >> param->shift[1]) & param->mask[1];
510d58de038SGeorge Joseph 	regval = config | (altbit << 3);
511d58de038SGeorge Joseph 	mutex_unlock(&data->update_lock);
512d58de038SGeorge Joseph 
5132a844c14SGuenter Roeck 	return sprintf(buf, "%u\n", map[clamp_val(regval, 0, 15)]);
514d58de038SGeorge Joseph }
515d58de038SGeorge Joseph 
store_pwm_ac(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)516d58de038SGeorge Joseph static ssize_t store_pwm_ac(struct device *dev,
517d58de038SGeorge Joseph 			    struct device_attribute *attr,
518d58de038SGeorge Joseph 			    const char *buf, size_t count)
519d58de038SGeorge Joseph {
520088ce2acSGuenter Roeck 	SETUP_STORE_DATA_PARAM(dev, attr);
521d58de038SGeorge Joseph 	unsigned long reqval;
522d58de038SGeorge Joseph 	u8 currval, config, altbit, newval;
52369301258SColin Ian King 	static const u16 map[] = {
524d58de038SGeorge Joseph 		0x04, 0x00, 0x01, 0xff, 0x02, 0xff, 0x05, 0x06,
525d58de038SGeorge Joseph 		0x08, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0f,
526d58de038SGeorge Joseph 		0x07, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
527d58de038SGeorge Joseph 		0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x03,
528d58de038SGeorge Joseph 	};
529d58de038SGeorge Joseph 
530179c4fdbSFrans Meulenbroeks 	if (kstrtoul(buf, 10, &reqval))
531d58de038SGeorge Joseph 		return -EINVAL;
532d58de038SGeorge Joseph 
533d58de038SGeorge Joseph 	if (reqval > 31)
534d58de038SGeorge Joseph 		return -EINVAL;
535d58de038SGeorge Joseph 
536d58de038SGeorge Joseph 	reqval = map[reqval];
537d58de038SGeorge Joseph 	if (reqval == 0xff)
538d58de038SGeorge Joseph 		return -EINVAL;
539d58de038SGeorge Joseph 
540d58de038SGeorge Joseph 	config = reqval & 0x07;
541d58de038SGeorge Joseph 	altbit = (reqval >> 3) & 0x01;
542d58de038SGeorge Joseph 
543d58de038SGeorge Joseph 	config = (config & param->mask[0]) << param->shift[0];
544d58de038SGeorge Joseph 	altbit = (altbit & param->mask[1]) << param->shift[1];
545d58de038SGeorge Joseph 
546d58de038SGeorge Joseph 	mutex_lock(&data->update_lock);
547d58de038SGeorge Joseph 	currval = read_byte(client, param->msb[0]);
548d58de038SGeorge Joseph 	newval = config | (currval & ~(param->mask[0] << param->shift[0]));
549d58de038SGeorge Joseph 	newval = altbit | (newval & ~(param->mask[1] << param->shift[1]));
550d58de038SGeorge Joseph 	data->reg[param->msb[0]] = newval;
551d58de038SGeorge Joseph 	write_byte(client, param->msb[0], newval);
552d58de038SGeorge Joseph 	mutex_unlock(&data->update_lock);
553d58de038SGeorge Joseph 	return count;
554d58de038SGeorge Joseph }
555d58de038SGeorge Joseph 
show_pwm_enable(struct device * dev,struct device_attribute * attr,char * buf)556d58de038SGeorge Joseph static ssize_t show_pwm_enable(struct device *dev,
557d58de038SGeorge Joseph 			       struct device_attribute *attr, char *buf)
558d58de038SGeorge Joseph {
559088ce2acSGuenter Roeck 	SETUP_SHOW_DATA_PARAM(dev, attr);
560d58de038SGeorge Joseph 	u8 config, altbit, minoff, val, newval;
561d58de038SGeorge Joseph 
562d58de038SGeorge Joseph 	mutex_lock(&data->update_lock);
563d58de038SGeorge Joseph 	config = (data->reg[param->msb[0]] >> param->shift[0]) & param->mask[0];
564d58de038SGeorge Joseph 	altbit = (data->reg[param->msb[1]] >> param->shift[1]) & param->mask[1];
565d58de038SGeorge Joseph 	minoff = (data->reg[param->msb[2]] >> param->shift[2]) & param->mask[2];
566d58de038SGeorge Joseph 	mutex_unlock(&data->update_lock);
567d58de038SGeorge Joseph 
568d58de038SGeorge Joseph 	val = config | (altbit << 3);
569d58de038SGeorge Joseph 
570d58de038SGeorge Joseph 	if (val == 3 || val >= 10)
571d58de038SGeorge Joseph 		newval = 255;
572d58de038SGeorge Joseph 	else if (val == 4)
573d58de038SGeorge Joseph 		newval = 0;
574d58de038SGeorge Joseph 	else if (val == 7)
575d58de038SGeorge Joseph 		newval = 1;
576d58de038SGeorge Joseph 	else if (minoff == 1)
577d58de038SGeorge Joseph 		newval = 2;
578d58de038SGeorge Joseph 	else
579d58de038SGeorge Joseph 		newval = 3;
580d58de038SGeorge Joseph 
581d58de038SGeorge Joseph 	return sprintf(buf, "%u\n", newval);
582d58de038SGeorge Joseph }
583d58de038SGeorge Joseph 
store_pwm_enable(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)584d58de038SGeorge Joseph static ssize_t store_pwm_enable(struct device *dev,
585d58de038SGeorge Joseph 				struct device_attribute *attr,
586d58de038SGeorge Joseph 				const char *buf, size_t count)
587d58de038SGeorge Joseph {
588088ce2acSGuenter Roeck 	SETUP_STORE_DATA_PARAM(dev, attr);
589d58de038SGeorge Joseph 	long reqval;
590d58de038SGeorge Joseph 	u8 currval, config, altbit, newval, minoff = 255;
591d58de038SGeorge Joseph 
592179c4fdbSFrans Meulenbroeks 	if (kstrtol(buf, 10, &reqval))
593d58de038SGeorge Joseph 		return -EINVAL;
594d58de038SGeorge Joseph 
595d58de038SGeorge Joseph 	switch (reqval) {
596d58de038SGeorge Joseph 	case 0:
597d58de038SGeorge Joseph 		newval = 0x04;
598d58de038SGeorge Joseph 		break;
599d58de038SGeorge Joseph 	case 1:
600d58de038SGeorge Joseph 		newval = 0x07;
601d58de038SGeorge Joseph 		break;
602d58de038SGeorge Joseph 	case 2:
603d58de038SGeorge Joseph 		newval = 0x00;
604d58de038SGeorge Joseph 		minoff = 1;
605d58de038SGeorge Joseph 		break;
606d58de038SGeorge Joseph 	case 3:
607d58de038SGeorge Joseph 		newval = 0x00;
608d58de038SGeorge Joseph 		minoff = 0;
609d58de038SGeorge Joseph 		break;
610d58de038SGeorge Joseph 	case 255:
611d58de038SGeorge Joseph 		newval = 0x03;
612d58de038SGeorge Joseph 		break;
613d58de038SGeorge Joseph 	default:
614d58de038SGeorge Joseph 		return -EINVAL;
615d58de038SGeorge Joseph 	}
616d58de038SGeorge Joseph 
617d58de038SGeorge Joseph 	config = newval & 0x07;
618d58de038SGeorge Joseph 	altbit = (newval >> 3) & 0x01;
619d58de038SGeorge Joseph 
620d58de038SGeorge Joseph 	mutex_lock(&data->update_lock);
621d58de038SGeorge Joseph 	config = (config & param->mask[0]) << param->shift[0];
622d58de038SGeorge Joseph 	altbit = (altbit & param->mask[1]) << param->shift[1];
623d58de038SGeorge Joseph 	currval = read_byte(client, param->msb[0]);
624d58de038SGeorge Joseph 	newval = config | (currval & ~(param->mask[0] << param->shift[0]));
625d58de038SGeorge Joseph 	newval = altbit | (newval & ~(param->mask[1] << param->shift[1]));
626d58de038SGeorge Joseph 	data->reg[param->msb[0]] = newval;
627d58de038SGeorge Joseph 	write_byte(client, param->msb[0], newval);
628d58de038SGeorge Joseph 	if (minoff < 255) {
629d58de038SGeorge Joseph 		minoff = (minoff & param->mask[2]) << param->shift[2];
630d58de038SGeorge Joseph 		currval = read_byte(client, param->msb[2]);
631d58de038SGeorge Joseph 		newval =
632d58de038SGeorge Joseph 		    minoff | (currval & ~(param->mask[2] << param->shift[2]));
633d58de038SGeorge Joseph 		data->reg[param->msb[2]] = newval;
634d58de038SGeorge Joseph 		write_byte(client, param->msb[2], newval);
635d58de038SGeorge Joseph 	}
636d58de038SGeorge Joseph 	mutex_unlock(&data->update_lock);
637d58de038SGeorge Joseph 	return count;
638d58de038SGeorge Joseph }
639d58de038SGeorge Joseph 
6407a7176aaSAxel Lin static const u32 asc7621_pwm_freq_map[] = {
641d58de038SGeorge Joseph 	10, 15, 23, 30, 38, 47, 62, 94,
642d58de038SGeorge Joseph 	23000, 24000, 25000, 26000, 27000, 28000, 29000, 30000
643d58de038SGeorge Joseph };
644d58de038SGeorge Joseph 
show_pwm_freq(struct device * dev,struct device_attribute * attr,char * buf)645d58de038SGeorge Joseph static ssize_t show_pwm_freq(struct device *dev,
646d58de038SGeorge Joseph 			     struct device_attribute *attr, char *buf)
647d58de038SGeorge Joseph {
648088ce2acSGuenter Roeck 	SETUP_SHOW_DATA_PARAM(dev, attr);
649d58de038SGeorge Joseph 	u8 regval =
650d58de038SGeorge Joseph 	    (data->reg[param->msb[0]] >> param->shift[0]) & param->mask[0];
651d58de038SGeorge Joseph 
6522a844c14SGuenter Roeck 	regval = clamp_val(regval, 0, 15);
653d58de038SGeorge Joseph 
654d58de038SGeorge Joseph 	return sprintf(buf, "%u\n", asc7621_pwm_freq_map[regval]);
655d58de038SGeorge Joseph }
656d58de038SGeorge Joseph 
store_pwm_freq(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)657d58de038SGeorge Joseph static ssize_t store_pwm_freq(struct device *dev,
658d58de038SGeorge Joseph 			      struct device_attribute *attr,
659d58de038SGeorge Joseph 			      const char *buf, size_t count)
660d58de038SGeorge Joseph {
661088ce2acSGuenter Roeck 	SETUP_STORE_DATA_PARAM(dev, attr);
662d58de038SGeorge Joseph 	unsigned long reqval;
663d58de038SGeorge Joseph 	u8 currval, newval = 255;
664d58de038SGeorge Joseph 	int i;
665d58de038SGeorge Joseph 
666179c4fdbSFrans Meulenbroeks 	if (kstrtoul(buf, 10, &reqval))
667d58de038SGeorge Joseph 		return -EINVAL;
668d58de038SGeorge Joseph 
669d58de038SGeorge Joseph 	for (i = 0; i < ARRAY_SIZE(asc7621_pwm_freq_map); i++) {
670d58de038SGeorge Joseph 		if (reqval == asc7621_pwm_freq_map[i]) {
671d58de038SGeorge Joseph 			newval = i;
672d58de038SGeorge Joseph 			break;
673d58de038SGeorge Joseph 		}
674d58de038SGeorge Joseph 	}
675d58de038SGeorge Joseph 	if (newval == 255)
676d58de038SGeorge Joseph 		return -EINVAL;
677d58de038SGeorge Joseph 
678d58de038SGeorge Joseph 	newval = (newval & param->mask[0]) << param->shift[0];
679d58de038SGeorge Joseph 
680d58de038SGeorge Joseph 	mutex_lock(&data->update_lock);
681d58de038SGeorge Joseph 	currval = read_byte(client, param->msb[0]);
682d58de038SGeorge Joseph 	newval |= (currval & ~(param->mask[0] << param->shift[0]));
683d58de038SGeorge Joseph 	data->reg[param->msb[0]] = newval;
684d58de038SGeorge Joseph 	write_byte(client, param->msb[0], newval);
685d58de038SGeorge Joseph 	mutex_unlock(&data->update_lock);
686d58de038SGeorge Joseph 	return count;
687d58de038SGeorge Joseph }
688d58de038SGeorge Joseph 
6897a7176aaSAxel Lin static const u32 asc7621_pwm_auto_spinup_map[] =  {
690d58de038SGeorge Joseph 	0, 100, 250, 400, 700, 1000, 2000, 4000
691d58de038SGeorge Joseph };
692d58de038SGeorge Joseph 
show_pwm_ast(struct device * dev,struct device_attribute * attr,char * buf)693d58de038SGeorge Joseph static ssize_t show_pwm_ast(struct device *dev,
694d58de038SGeorge Joseph 			    struct device_attribute *attr, char *buf)
695d58de038SGeorge Joseph {
696088ce2acSGuenter Roeck 	SETUP_SHOW_DATA_PARAM(dev, attr);
697d58de038SGeorge Joseph 	u8 regval =
698d58de038SGeorge Joseph 	    (data->reg[param->msb[0]] >> param->shift[0]) & param->mask[0];
699d58de038SGeorge Joseph 
7002a844c14SGuenter Roeck 	regval = clamp_val(regval, 0, 7);
701d58de038SGeorge Joseph 
702d58de038SGeorge Joseph 	return sprintf(buf, "%u\n", asc7621_pwm_auto_spinup_map[regval]);
703d58de038SGeorge Joseph 
704d58de038SGeorge Joseph }
705d58de038SGeorge Joseph 
store_pwm_ast(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)706d58de038SGeorge Joseph static ssize_t store_pwm_ast(struct device *dev,
707d58de038SGeorge Joseph 			     struct device_attribute *attr,
708d58de038SGeorge Joseph 			     const char *buf, size_t count)
709d58de038SGeorge Joseph {
710088ce2acSGuenter Roeck 	SETUP_STORE_DATA_PARAM(dev, attr);
711d58de038SGeorge Joseph 	long reqval;
712d58de038SGeorge Joseph 	u8 currval, newval = 255;
713d58de038SGeorge Joseph 	u32 i;
714d58de038SGeorge Joseph 
715179c4fdbSFrans Meulenbroeks 	if (kstrtol(buf, 10, &reqval))
716d58de038SGeorge Joseph 		return -EINVAL;
717d58de038SGeorge Joseph 
718d58de038SGeorge Joseph 	for (i = 0; i < ARRAY_SIZE(asc7621_pwm_auto_spinup_map); i++) {
719d58de038SGeorge Joseph 		if (reqval == asc7621_pwm_auto_spinup_map[i]) {
720d58de038SGeorge Joseph 			newval = i;
721d58de038SGeorge Joseph 			break;
722d58de038SGeorge Joseph 		}
723d58de038SGeorge Joseph 	}
724d58de038SGeorge Joseph 	if (newval == 255)
725d58de038SGeorge Joseph 		return -EINVAL;
726d58de038SGeorge Joseph 
727d58de038SGeorge Joseph 	newval = (newval & param->mask[0]) << param->shift[0];
728d58de038SGeorge Joseph 
729d58de038SGeorge Joseph 	mutex_lock(&data->update_lock);
730d58de038SGeorge Joseph 	currval = read_byte(client, param->msb[0]);
731d58de038SGeorge Joseph 	newval |= (currval & ~(param->mask[0] << param->shift[0]));
732d58de038SGeorge Joseph 	data->reg[param->msb[0]] = newval;
733d58de038SGeorge Joseph 	write_byte(client, param->msb[0], newval);
734d58de038SGeorge Joseph 	mutex_unlock(&data->update_lock);
735d58de038SGeorge Joseph 	return count;
736d58de038SGeorge Joseph }
737d58de038SGeorge Joseph 
7387a7176aaSAxel Lin static const u32 asc7621_temp_smoothing_time_map[] = {
739d58de038SGeorge Joseph 	35000, 17600, 11800, 7000, 4400, 3000, 1600, 800
740d58de038SGeorge Joseph };
741d58de038SGeorge Joseph 
show_temp_st(struct device * dev,struct device_attribute * attr,char * buf)742d58de038SGeorge Joseph static ssize_t show_temp_st(struct device *dev,
743d58de038SGeorge Joseph 			    struct device_attribute *attr, char *buf)
744d58de038SGeorge Joseph {
745088ce2acSGuenter Roeck 	SETUP_SHOW_DATA_PARAM(dev, attr);
746d58de038SGeorge Joseph 	u8 regval =
747d58de038SGeorge Joseph 	    (data->reg[param->msb[0]] >> param->shift[0]) & param->mask[0];
7482a844c14SGuenter Roeck 	regval = clamp_val(regval, 0, 7);
749d58de038SGeorge Joseph 
750d58de038SGeorge Joseph 	return sprintf(buf, "%u\n", asc7621_temp_smoothing_time_map[regval]);
751d58de038SGeorge Joseph }
752d58de038SGeorge Joseph 
store_temp_st(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)753d58de038SGeorge Joseph static ssize_t store_temp_st(struct device *dev,
754d58de038SGeorge Joseph 			     struct device_attribute *attr,
755d58de038SGeorge Joseph 			     const char *buf, size_t count)
756d58de038SGeorge Joseph {
757088ce2acSGuenter Roeck 	SETUP_STORE_DATA_PARAM(dev, attr);
758d58de038SGeorge Joseph 	long reqval;
759d58de038SGeorge Joseph 	u8 currval, newval = 255;
760d58de038SGeorge Joseph 	u32 i;
761d58de038SGeorge Joseph 
762179c4fdbSFrans Meulenbroeks 	if (kstrtol(buf, 10, &reqval))
763d58de038SGeorge Joseph 		return -EINVAL;
764d58de038SGeorge Joseph 
765d58de038SGeorge Joseph 	for (i = 0; i < ARRAY_SIZE(asc7621_temp_smoothing_time_map); i++) {
766d58de038SGeorge Joseph 		if (reqval == asc7621_temp_smoothing_time_map[i]) {
767d58de038SGeorge Joseph 			newval = i;
768d58de038SGeorge Joseph 			break;
769d58de038SGeorge Joseph 		}
770d58de038SGeorge Joseph 	}
771d58de038SGeorge Joseph 
772d58de038SGeorge Joseph 	if (newval == 255)
773d58de038SGeorge Joseph 		return -EINVAL;
774d58de038SGeorge Joseph 
775d58de038SGeorge Joseph 	newval = (newval & param->mask[0]) << param->shift[0];
776d58de038SGeorge Joseph 
777d58de038SGeorge Joseph 	mutex_lock(&data->update_lock);
778d58de038SGeorge Joseph 	currval = read_byte(client, param->msb[0]);
779d58de038SGeorge Joseph 	newval |= (currval & ~(param->mask[0] << param->shift[0]));
780d58de038SGeorge Joseph 	data->reg[param->msb[0]] = newval;
781d58de038SGeorge Joseph 	write_byte(client, param->msb[0], newval);
782d58de038SGeorge Joseph 	mutex_unlock(&data->update_lock);
783d58de038SGeorge Joseph 	return count;
784d58de038SGeorge Joseph }
785d58de038SGeorge Joseph 
786d58de038SGeorge Joseph /*
787d58de038SGeorge Joseph  * End of data handlers
788d58de038SGeorge Joseph  *
789d58de038SGeorge Joseph  * These defines do nothing more than make the table easier
790d58de038SGeorge Joseph  * to read when wrapped at column 80.
791d58de038SGeorge Joseph  */
792d58de038SGeorge Joseph 
793d58de038SGeorge Joseph /*
794d58de038SGeorge Joseph  * Creates a variable length array inititalizer.
795d58de038SGeorge Joseph  * VAA(1,3,5,7) would produce {1,3,5,7}
796d58de038SGeorge Joseph  */
797d58de038SGeorge Joseph #define VAA(args...) {args}
798d58de038SGeorge Joseph 
799d58de038SGeorge Joseph #define PREAD(name, n, pri, rm, rl, m, s, r) \
800d58de038SGeorge Joseph 	{.sda = SENSOR_ATTR(name, S_IRUGO, show_##r, NULL, n), \
801d58de038SGeorge Joseph 	  .priority = pri, .msb[0] = rm, .lsb[0] = rl, .mask[0] = m, \
802d58de038SGeorge Joseph 	  .shift[0] = s,}
803d58de038SGeorge Joseph 
804d58de038SGeorge Joseph #define PWRITE(name, n, pri, rm, rl, m, s, r) \
805d58de038SGeorge Joseph 	{.sda = SENSOR_ATTR(name, S_IRUGO | S_IWUSR, show_##r, store_##r, n), \
806d58de038SGeorge Joseph 	  .priority = pri, .msb[0] = rm, .lsb[0] = rl, .mask[0] = m, \
807d58de038SGeorge Joseph 	  .shift[0] = s,}
808d58de038SGeorge Joseph 
809d58de038SGeorge Joseph /*
810d58de038SGeorge Joseph  * PWRITEM assumes that the initializers for the .msb, .lsb, .mask and .shift
811d58de038SGeorge Joseph  * were created using the VAA macro.
812d58de038SGeorge Joseph  */
813d58de038SGeorge Joseph #define PWRITEM(name, n, pri, rm, rl, m, s, r) \
814d58de038SGeorge Joseph 	{.sda = SENSOR_ATTR(name, S_IRUGO | S_IWUSR, show_##r, store_##r, n), \
815d58de038SGeorge Joseph 	  .priority = pri, .msb = rm, .lsb = rl, .mask = m, .shift = s,}
816d58de038SGeorge Joseph 
817d58de038SGeorge Joseph static struct asc7621_param asc7621_params[] = {
818d58de038SGeorge Joseph 	PREAD(in0_input, 0, PRI_HIGH, 0x20, 0x13, 0, 0, in10),
819d58de038SGeorge Joseph 	PREAD(in1_input, 1, PRI_HIGH, 0x21, 0x18, 0, 0, in10),
820d58de038SGeorge Joseph 	PREAD(in2_input, 2, PRI_HIGH, 0x22, 0x11, 0, 0, in10),
821d58de038SGeorge Joseph 	PREAD(in3_input, 3, PRI_HIGH, 0x23, 0x12, 0, 0, in10),
822d58de038SGeorge Joseph 	PREAD(in4_input, 4, PRI_HIGH, 0x24, 0x14, 0, 0, in10),
823d58de038SGeorge Joseph 
824d58de038SGeorge Joseph 	PWRITE(in0_min, 0, PRI_LOW, 0x44, 0, 0, 0, in8),
825d58de038SGeorge Joseph 	PWRITE(in1_min, 1, PRI_LOW, 0x46, 0, 0, 0, in8),
826d58de038SGeorge Joseph 	PWRITE(in2_min, 2, PRI_LOW, 0x48, 0, 0, 0, in8),
827d58de038SGeorge Joseph 	PWRITE(in3_min, 3, PRI_LOW, 0x4a, 0, 0, 0, in8),
828d58de038SGeorge Joseph 	PWRITE(in4_min, 4, PRI_LOW, 0x4c, 0, 0, 0, in8),
829d58de038SGeorge Joseph 
830d58de038SGeorge Joseph 	PWRITE(in0_max, 0, PRI_LOW, 0x45, 0, 0, 0, in8),
831d58de038SGeorge Joseph 	PWRITE(in1_max, 1, PRI_LOW, 0x47, 0, 0, 0, in8),
832d58de038SGeorge Joseph 	PWRITE(in2_max, 2, PRI_LOW, 0x49, 0, 0, 0, in8),
833d58de038SGeorge Joseph 	PWRITE(in3_max, 3, PRI_LOW, 0x4b, 0, 0, 0, in8),
834d58de038SGeorge Joseph 	PWRITE(in4_max, 4, PRI_LOW, 0x4d, 0, 0, 0, in8),
835d58de038SGeorge Joseph 
836d1bf8cf6SKen Milmore 	PREAD(in0_alarm, 0, PRI_HIGH, 0x41, 0, 0x01, 0, bitmask),
837d1bf8cf6SKen Milmore 	PREAD(in1_alarm, 1, PRI_HIGH, 0x41, 0, 0x01, 1, bitmask),
838d1bf8cf6SKen Milmore 	PREAD(in2_alarm, 2, PRI_HIGH, 0x41, 0, 0x01, 2, bitmask),
839d1bf8cf6SKen Milmore 	PREAD(in3_alarm, 3, PRI_HIGH, 0x41, 0, 0x01, 3, bitmask),
840d1bf8cf6SKen Milmore 	PREAD(in4_alarm, 4, PRI_HIGH, 0x42, 0, 0x01, 0, bitmask),
841d58de038SGeorge Joseph 
842d58de038SGeorge Joseph 	PREAD(fan1_input, 0, PRI_HIGH, 0x29, 0x28, 0, 0, fan16),
843d58de038SGeorge Joseph 	PREAD(fan2_input, 1, PRI_HIGH, 0x2b, 0x2a, 0, 0, fan16),
844d58de038SGeorge Joseph 	PREAD(fan3_input, 2, PRI_HIGH, 0x2d, 0x2c, 0, 0, fan16),
845d58de038SGeorge Joseph 	PREAD(fan4_input, 3, PRI_HIGH, 0x2f, 0x2e, 0, 0, fan16),
846d58de038SGeorge Joseph 
847d58de038SGeorge Joseph 	PWRITE(fan1_min, 0, PRI_LOW, 0x55, 0x54, 0, 0, fan16),
848d58de038SGeorge Joseph 	PWRITE(fan2_min, 1, PRI_LOW, 0x57, 0x56, 0, 0, fan16),
849d58de038SGeorge Joseph 	PWRITE(fan3_min, 2, PRI_LOW, 0x59, 0x58, 0, 0, fan16),
850d58de038SGeorge Joseph 	PWRITE(fan4_min, 3, PRI_LOW, 0x5b, 0x5a, 0, 0, fan16),
851d58de038SGeorge Joseph 
852d1bf8cf6SKen Milmore 	PREAD(fan1_alarm, 0, PRI_HIGH, 0x42, 0, 0x01, 2, bitmask),
853d1bf8cf6SKen Milmore 	PREAD(fan2_alarm, 1, PRI_HIGH, 0x42, 0, 0x01, 3, bitmask),
854d1bf8cf6SKen Milmore 	PREAD(fan3_alarm, 2, PRI_HIGH, 0x42, 0, 0x01, 4, bitmask),
855d1bf8cf6SKen Milmore 	PREAD(fan4_alarm, 3, PRI_HIGH, 0x42, 0, 0x01, 5, bitmask),
856d58de038SGeorge Joseph 
857d58de038SGeorge Joseph 	PREAD(temp1_input, 0, PRI_HIGH, 0x25, 0x10, 0, 0, temp10),
858d58de038SGeorge Joseph 	PREAD(temp2_input, 1, PRI_HIGH, 0x26, 0x15, 0, 0, temp10),
859d58de038SGeorge Joseph 	PREAD(temp3_input, 2, PRI_HIGH, 0x27, 0x16, 0, 0, temp10),
860d58de038SGeorge Joseph 	PREAD(temp4_input, 3, PRI_HIGH, 0x33, 0x17, 0, 0, temp10),
861d58de038SGeorge Joseph 	PREAD(temp5_input, 4, PRI_HIGH, 0xf7, 0xf6, 0, 0, temp10),
862d58de038SGeorge Joseph 	PREAD(temp6_input, 5, PRI_HIGH, 0xf9, 0xf8, 0, 0, temp10),
863d58de038SGeorge Joseph 	PREAD(temp7_input, 6, PRI_HIGH, 0xfb, 0xfa, 0, 0, temp10),
864d58de038SGeorge Joseph 	PREAD(temp8_input, 7, PRI_HIGH, 0xfd, 0xfc, 0, 0, temp10),
865d58de038SGeorge Joseph 
866d58de038SGeorge Joseph 	PWRITE(temp1_min, 0, PRI_LOW, 0x4e, 0, 0, 0, temp8),
867d58de038SGeorge Joseph 	PWRITE(temp2_min, 1, PRI_LOW, 0x50, 0, 0, 0, temp8),
868d58de038SGeorge Joseph 	PWRITE(temp3_min, 2, PRI_LOW, 0x52, 0, 0, 0, temp8),
869d58de038SGeorge Joseph 	PWRITE(temp4_min, 3, PRI_LOW, 0x34, 0, 0, 0, temp8),
870d58de038SGeorge Joseph 
871d58de038SGeorge Joseph 	PWRITE(temp1_max, 0, PRI_LOW, 0x4f, 0, 0, 0, temp8),
872d58de038SGeorge Joseph 	PWRITE(temp2_max, 1, PRI_LOW, 0x51, 0, 0, 0, temp8),
873d58de038SGeorge Joseph 	PWRITE(temp3_max, 2, PRI_LOW, 0x53, 0, 0, 0, temp8),
874d58de038SGeorge Joseph 	PWRITE(temp4_max, 3, PRI_LOW, 0x35, 0, 0, 0, temp8),
875d58de038SGeorge Joseph 
876d1bf8cf6SKen Milmore 	PREAD(temp1_alarm, 0, PRI_HIGH, 0x41, 0, 0x01, 4, bitmask),
877d1bf8cf6SKen Milmore 	PREAD(temp2_alarm, 1, PRI_HIGH, 0x41, 0, 0x01, 5, bitmask),
878d1bf8cf6SKen Milmore 	PREAD(temp3_alarm, 2, PRI_HIGH, 0x41, 0, 0x01, 6, bitmask),
879d1bf8cf6SKen Milmore 	PREAD(temp4_alarm, 3, PRI_HIGH, 0x43, 0, 0x01, 0, bitmask),
880d58de038SGeorge Joseph 
881d58de038SGeorge Joseph 	PWRITE(temp1_source, 0, PRI_LOW, 0x02, 0, 0x07, 4, bitmask),
882d58de038SGeorge Joseph 	PWRITE(temp2_source, 1, PRI_LOW, 0x02, 0, 0x07, 0, bitmask),
883d58de038SGeorge Joseph 	PWRITE(temp3_source, 2, PRI_LOW, 0x03, 0, 0x07, 4, bitmask),
884d58de038SGeorge Joseph 	PWRITE(temp4_source, 3, PRI_LOW, 0x03, 0, 0x07, 0, bitmask),
885d58de038SGeorge Joseph 
886d58de038SGeorge Joseph 	PWRITE(temp1_smoothing_enable, 0, PRI_LOW, 0x62, 0, 0x01, 3, bitmask),
887d58de038SGeorge Joseph 	PWRITE(temp2_smoothing_enable, 1, PRI_LOW, 0x63, 0, 0x01, 7, bitmask),
888d1bf8cf6SKen Milmore 	PWRITE(temp3_smoothing_enable, 2, PRI_LOW, 0x63, 0, 0x01, 3, bitmask),
889d58de038SGeorge Joseph 	PWRITE(temp4_smoothing_enable, 3, PRI_LOW, 0x3c, 0, 0x01, 3, bitmask),
890d58de038SGeorge Joseph 
891d58de038SGeorge Joseph 	PWRITE(temp1_smoothing_time, 0, PRI_LOW, 0x62, 0, 0x07, 0, temp_st),
892d58de038SGeorge Joseph 	PWRITE(temp2_smoothing_time, 1, PRI_LOW, 0x63, 0, 0x07, 4, temp_st),
893d58de038SGeorge Joseph 	PWRITE(temp3_smoothing_time, 2, PRI_LOW, 0x63, 0, 0x07, 0, temp_st),
894d58de038SGeorge Joseph 	PWRITE(temp4_smoothing_time, 3, PRI_LOW, 0x3c, 0, 0x07, 0, temp_st),
895d58de038SGeorge Joseph 
896d58de038SGeorge Joseph 	PWRITE(temp1_auto_point1_temp_hyst, 0, PRI_LOW, 0x6d, 0, 0x0f, 4,
897d58de038SGeorge Joseph 	       bitmask),
898d58de038SGeorge Joseph 	PWRITE(temp2_auto_point1_temp_hyst, 1, PRI_LOW, 0x6d, 0, 0x0f, 0,
899d58de038SGeorge Joseph 	       bitmask),
900d58de038SGeorge Joseph 	PWRITE(temp3_auto_point1_temp_hyst, 2, PRI_LOW, 0x6e, 0, 0x0f, 4,
901d58de038SGeorge Joseph 	       bitmask),
902d58de038SGeorge Joseph 	PWRITE(temp4_auto_point1_temp_hyst, 3, PRI_LOW, 0x6e, 0, 0x0f, 0,
903d58de038SGeorge Joseph 	       bitmask),
904d58de038SGeorge Joseph 
905d58de038SGeorge Joseph 	PREAD(temp1_auto_point2_temp_hyst, 0, PRI_LOW, 0x6d, 0, 0x0f, 4,
906d58de038SGeorge Joseph 	      bitmask),
907d58de038SGeorge Joseph 	PREAD(temp2_auto_point2_temp_hyst, 1, PRI_LOW, 0x6d, 0, 0x0f, 0,
908d58de038SGeorge Joseph 	      bitmask),
909d58de038SGeorge Joseph 	PREAD(temp3_auto_point2_temp_hyst, 2, PRI_LOW, 0x6e, 0, 0x0f, 4,
910d58de038SGeorge Joseph 	      bitmask),
911d58de038SGeorge Joseph 	PREAD(temp4_auto_point2_temp_hyst, 3, PRI_LOW, 0x6e, 0, 0x0f, 0,
912d58de038SGeorge Joseph 	      bitmask),
913d58de038SGeorge Joseph 
914d58de038SGeorge Joseph 	PWRITE(temp1_auto_point1_temp, 0, PRI_LOW, 0x67, 0, 0, 0, temp8),
915d58de038SGeorge Joseph 	PWRITE(temp2_auto_point1_temp, 1, PRI_LOW, 0x68, 0, 0, 0, temp8),
916d58de038SGeorge Joseph 	PWRITE(temp3_auto_point1_temp, 2, PRI_LOW, 0x69, 0, 0, 0, temp8),
917d58de038SGeorge Joseph 	PWRITE(temp4_auto_point1_temp, 3, PRI_LOW, 0x3b, 0, 0, 0, temp8),
918d58de038SGeorge Joseph 
919d58de038SGeorge Joseph 	PWRITEM(temp1_auto_point2_temp, 0, PRI_LOW, VAA(0x5f, 0x67), VAA(0),
920d58de038SGeorge Joseph 		VAA(0x0f), VAA(4), ap2_temp),
921d58de038SGeorge Joseph 	PWRITEM(temp2_auto_point2_temp, 1, PRI_LOW, VAA(0x60, 0x68), VAA(0),
922d58de038SGeorge Joseph 		VAA(0x0f), VAA(4), ap2_temp),
923d58de038SGeorge Joseph 	PWRITEM(temp3_auto_point2_temp, 2, PRI_LOW, VAA(0x61, 0x69), VAA(0),
924d58de038SGeorge Joseph 		VAA(0x0f), VAA(4), ap2_temp),
925d58de038SGeorge Joseph 	PWRITEM(temp4_auto_point2_temp, 3, PRI_LOW, VAA(0x3c, 0x3b), VAA(0),
926d58de038SGeorge Joseph 		VAA(0x0f), VAA(4), ap2_temp),
927d58de038SGeorge Joseph 
928d58de038SGeorge Joseph 	PWRITE(temp1_crit, 0, PRI_LOW, 0x6a, 0, 0, 0, temp8),
929d58de038SGeorge Joseph 	PWRITE(temp2_crit, 1, PRI_LOW, 0x6b, 0, 0, 0, temp8),
930d58de038SGeorge Joseph 	PWRITE(temp3_crit, 2, PRI_LOW, 0x6c, 0, 0, 0, temp8),
931d58de038SGeorge Joseph 	PWRITE(temp4_crit, 3, PRI_LOW, 0x3d, 0, 0, 0, temp8),
932d58de038SGeorge Joseph 
933d58de038SGeorge Joseph 	PWRITE(temp5_enable, 4, PRI_LOW, 0x0e, 0, 0x01, 0, bitmask),
934d58de038SGeorge Joseph 	PWRITE(temp6_enable, 5, PRI_LOW, 0x0e, 0, 0x01, 1, bitmask),
935d58de038SGeorge Joseph 	PWRITE(temp7_enable, 6, PRI_LOW, 0x0e, 0, 0x01, 2, bitmask),
936d58de038SGeorge Joseph 	PWRITE(temp8_enable, 7, PRI_LOW, 0x0e, 0, 0x01, 3, bitmask),
937d58de038SGeorge Joseph 
938d58de038SGeorge Joseph 	PWRITE(remote1_offset, 0, PRI_LOW, 0x1c, 0, 0, 0, temp62),
939d58de038SGeorge Joseph 	PWRITE(remote2_offset, 1, PRI_LOW, 0x1d, 0, 0, 0, temp62),
940d58de038SGeorge Joseph 
941d58de038SGeorge Joseph 	PWRITE(pwm1, 0, PRI_HIGH, 0x30, 0, 0, 0, u8),
942d58de038SGeorge Joseph 	PWRITE(pwm2, 1, PRI_HIGH, 0x31, 0, 0, 0, u8),
943d58de038SGeorge Joseph 	PWRITE(pwm3, 2, PRI_HIGH, 0x32, 0, 0, 0, u8),
944d58de038SGeorge Joseph 
945d58de038SGeorge Joseph 	PWRITE(pwm1_invert, 0, PRI_LOW, 0x5c, 0, 0x01, 4, bitmask),
946d58de038SGeorge Joseph 	PWRITE(pwm2_invert, 1, PRI_LOW, 0x5d, 0, 0x01, 4, bitmask),
947d58de038SGeorge Joseph 	PWRITE(pwm3_invert, 2, PRI_LOW, 0x5e, 0, 0x01, 4, bitmask),
948d58de038SGeorge Joseph 
949d58de038SGeorge Joseph 	PWRITEM(pwm1_enable, 0, PRI_LOW, VAA(0x5c, 0x5c, 0x62), VAA(0, 0, 0),
950d58de038SGeorge Joseph 		VAA(0x07, 0x01, 0x01), VAA(5, 3, 5), pwm_enable),
951d58de038SGeorge Joseph 	PWRITEM(pwm2_enable, 1, PRI_LOW, VAA(0x5d, 0x5d, 0x62), VAA(0, 0, 0),
952d58de038SGeorge Joseph 		VAA(0x07, 0x01, 0x01), VAA(5, 3, 6), pwm_enable),
953d58de038SGeorge Joseph 	PWRITEM(pwm3_enable, 2, PRI_LOW, VAA(0x5e, 0x5e, 0x62), VAA(0, 0, 0),
954d58de038SGeorge Joseph 		VAA(0x07, 0x01, 0x01), VAA(5, 3, 7), pwm_enable),
955d58de038SGeorge Joseph 
956d58de038SGeorge Joseph 	PWRITEM(pwm1_auto_channels, 0, PRI_LOW, VAA(0x5c, 0x5c), VAA(0, 0),
957d58de038SGeorge Joseph 		VAA(0x07, 0x01), VAA(5, 3), pwm_ac),
958d58de038SGeorge Joseph 	PWRITEM(pwm2_auto_channels, 1, PRI_LOW, VAA(0x5d, 0x5d), VAA(0, 0),
959d58de038SGeorge Joseph 		VAA(0x07, 0x01), VAA(5, 3), pwm_ac),
960d58de038SGeorge Joseph 	PWRITEM(pwm3_auto_channels, 2, PRI_LOW, VAA(0x5e, 0x5e), VAA(0, 0),
961d58de038SGeorge Joseph 		VAA(0x07, 0x01), VAA(5, 3), pwm_ac),
962d58de038SGeorge Joseph 
963d58de038SGeorge Joseph 	PWRITE(pwm1_auto_point1_pwm, 0, PRI_LOW, 0x64, 0, 0, 0, u8),
964d58de038SGeorge Joseph 	PWRITE(pwm2_auto_point1_pwm, 1, PRI_LOW, 0x65, 0, 0, 0, u8),
965d58de038SGeorge Joseph 	PWRITE(pwm3_auto_point1_pwm, 2, PRI_LOW, 0x66, 0, 0, 0, u8),
966d58de038SGeorge Joseph 
967d58de038SGeorge Joseph 	PWRITE(pwm1_auto_point2_pwm, 0, PRI_LOW, 0x38, 0, 0, 0, u8),
968d58de038SGeorge Joseph 	PWRITE(pwm2_auto_point2_pwm, 1, PRI_LOW, 0x39, 0, 0, 0, u8),
969d58de038SGeorge Joseph 	PWRITE(pwm3_auto_point2_pwm, 2, PRI_LOW, 0x3a, 0, 0, 0, u8),
970d58de038SGeorge Joseph 
971d58de038SGeorge Joseph 	PWRITE(pwm1_freq, 0, PRI_LOW, 0x5f, 0, 0x0f, 0, pwm_freq),
972d58de038SGeorge Joseph 	PWRITE(pwm2_freq, 1, PRI_LOW, 0x60, 0, 0x0f, 0, pwm_freq),
973d58de038SGeorge Joseph 	PWRITE(pwm3_freq, 2, PRI_LOW, 0x61, 0, 0x0f, 0, pwm_freq),
974d58de038SGeorge Joseph 
975d58de038SGeorge Joseph 	PREAD(pwm1_auto_zone_assigned, 0, PRI_LOW, 0, 0, 0x03, 2, bitmask),
976d58de038SGeorge Joseph 	PREAD(pwm2_auto_zone_assigned, 1, PRI_LOW, 0, 0, 0x03, 4, bitmask),
977d58de038SGeorge Joseph 	PREAD(pwm3_auto_zone_assigned, 2, PRI_LOW, 0, 0, 0x03, 6, bitmask),
978d58de038SGeorge Joseph 
979d58de038SGeorge Joseph 	PWRITE(pwm1_auto_spinup_time, 0, PRI_LOW, 0x5c, 0, 0x07, 0, pwm_ast),
980d58de038SGeorge Joseph 	PWRITE(pwm2_auto_spinup_time, 1, PRI_LOW, 0x5d, 0, 0x07, 0, pwm_ast),
981d58de038SGeorge Joseph 	PWRITE(pwm3_auto_spinup_time, 2, PRI_LOW, 0x5e, 0, 0x07, 0, pwm_ast),
982d58de038SGeorge Joseph 
983d58de038SGeorge Joseph 	PWRITE(peci_enable, 0, PRI_LOW, 0x40, 0, 0x01, 4, bitmask),
984d58de038SGeorge Joseph 	PWRITE(peci_avg, 0, PRI_LOW, 0x36, 0, 0x07, 0, bitmask),
985d58de038SGeorge Joseph 	PWRITE(peci_domain, 0, PRI_LOW, 0x36, 0, 0x01, 3, bitmask),
986d58de038SGeorge Joseph 	PWRITE(peci_legacy, 0, PRI_LOW, 0x36, 0, 0x01, 4, bitmask),
987d58de038SGeorge Joseph 	PWRITE(peci_diode, 0, PRI_LOW, 0x0e, 0, 0x07, 4, bitmask),
988d58de038SGeorge Joseph 	PWRITE(peci_4domain, 0, PRI_LOW, 0x0e, 0, 0x01, 4, bitmask),
989d58de038SGeorge Joseph 
990d58de038SGeorge Joseph };
991d58de038SGeorge Joseph 
asc7621_update_device(struct device * dev)992d58de038SGeorge Joseph static struct asc7621_data *asc7621_update_device(struct device *dev)
993d58de038SGeorge Joseph {
994d58de038SGeorge Joseph 	struct i2c_client *client = to_i2c_client(dev);
995d58de038SGeorge Joseph 	struct asc7621_data *data = i2c_get_clientdata(client);
996d58de038SGeorge Joseph 	int i;
997d58de038SGeorge Joseph 
998d58de038SGeorge Joseph /*
999d58de038SGeorge Joseph  * The asc7621 chips guarantee consistent reads of multi-byte values
1000d58de038SGeorge Joseph  * regardless of the order of the reads.  No special logic is needed
1001d58de038SGeorge Joseph  * so we can just read the registers in whatever  order they appear
1002d58de038SGeorge Joseph  * in the asc7621_params array.
1003d58de038SGeorge Joseph  */
1004d58de038SGeorge Joseph 
1005d58de038SGeorge Joseph 	mutex_lock(&data->update_lock);
1006d58de038SGeorge Joseph 
1007d58de038SGeorge Joseph 	/* Read all the high priority registers */
1008d58de038SGeorge Joseph 
1009d58de038SGeorge Joseph 	if (!data->valid ||
1010d58de038SGeorge Joseph 	    time_after(jiffies, data->last_high_reading + INTERVAL_HIGH)) {
1011d58de038SGeorge Joseph 
1012d58de038SGeorge Joseph 		for (i = 0; i < ARRAY_SIZE(asc7621_register_priorities); i++) {
1013d58de038SGeorge Joseph 			if (asc7621_register_priorities[i] == PRI_HIGH) {
1014d58de038SGeorge Joseph 				data->reg[i] =
1015d58de038SGeorge Joseph 				    i2c_smbus_read_byte_data(client, i) & 0xff;
1016d58de038SGeorge Joseph 			}
1017d58de038SGeorge Joseph 		}
1018d58de038SGeorge Joseph 		data->last_high_reading = jiffies;
1019a0393713SGuenter Roeck 	}			/* last_reading */
1020d58de038SGeorge Joseph 
1021d58de038SGeorge Joseph 	/* Read all the low priority registers. */
1022d58de038SGeorge Joseph 
1023d58de038SGeorge Joseph 	if (!data->valid ||
1024d58de038SGeorge Joseph 	    time_after(jiffies, data->last_low_reading + INTERVAL_LOW)) {
1025d58de038SGeorge Joseph 
1026d58de038SGeorge Joseph 		for (i = 0; i < ARRAY_SIZE(asc7621_params); i++) {
1027d58de038SGeorge Joseph 			if (asc7621_register_priorities[i] == PRI_LOW) {
1028d58de038SGeorge Joseph 				data->reg[i] =
1029d58de038SGeorge Joseph 				    i2c_smbus_read_byte_data(client, i) & 0xff;
1030d58de038SGeorge Joseph 			}
1031d58de038SGeorge Joseph 		}
1032d58de038SGeorge Joseph 		data->last_low_reading = jiffies;
1033a0393713SGuenter Roeck 	}			/* last_reading */
1034d58de038SGeorge Joseph 
1035952a11caSPaul Fertser 	data->valid = true;
1036d58de038SGeorge Joseph 
1037d58de038SGeorge Joseph 	mutex_unlock(&data->update_lock);
1038d58de038SGeorge Joseph 
1039d58de038SGeorge Joseph 	return data;
1040d58de038SGeorge Joseph }
1041d58de038SGeorge Joseph 
1042d58de038SGeorge Joseph /*
1043d58de038SGeorge Joseph  * Standard detection and initialization below
1044d58de038SGeorge Joseph  *
1045d58de038SGeorge Joseph  * Helper function that checks if an address is valid
1046d58de038SGeorge Joseph  * for a particular chip.
1047d58de038SGeorge Joseph  */
1048d58de038SGeorge Joseph 
valid_address_for_chip(int chip_type,int address)1049d58de038SGeorge Joseph static inline int valid_address_for_chip(int chip_type, int address)
1050d58de038SGeorge Joseph {
1051d58de038SGeorge Joseph 	int i;
1052d58de038SGeorge Joseph 
1053d58de038SGeorge Joseph 	for (i = 0; asc7621_chips[chip_type].addresses[i] != I2C_CLIENT_END;
1054d58de038SGeorge Joseph 	     i++) {
1055d58de038SGeorge Joseph 		if (asc7621_chips[chip_type].addresses[i] == address)
1056d58de038SGeorge Joseph 			return 1;
1057d58de038SGeorge Joseph 	}
1058d58de038SGeorge Joseph 	return 0;
1059d58de038SGeorge Joseph }
1060d58de038SGeorge Joseph 
asc7621_init_client(struct i2c_client * client)1061d58de038SGeorge Joseph static void asc7621_init_client(struct i2c_client *client)
1062d58de038SGeorge Joseph {
1063d58de038SGeorge Joseph 	int value;
1064d58de038SGeorge Joseph 
1065d58de038SGeorge Joseph 	/* Warn if part was not "READY" */
1066d58de038SGeorge Joseph 
1067d58de038SGeorge Joseph 	value = read_byte(client, 0x40);
1068d58de038SGeorge Joseph 
1069d58de038SGeorge Joseph 	if (value & 0x02) {
1070d58de038SGeorge Joseph 		dev_err(&client->dev,
1071d58de038SGeorge Joseph 			"Client (%d,0x%02x) config is locked.\n",
1072d58de038SGeorge Joseph 			i2c_adapter_id(client->adapter), client->addr);
1073a0393713SGuenter Roeck 	}
1074d58de038SGeorge Joseph 	if (!(value & 0x04)) {
1075d58de038SGeorge Joseph 		dev_err(&client->dev, "Client (%d,0x%02x) is not ready.\n",
1076d58de038SGeorge Joseph 			i2c_adapter_id(client->adapter), client->addr);
1077a0393713SGuenter Roeck 	}
1078d58de038SGeorge Joseph 
1079d58de038SGeorge Joseph /*
1080d58de038SGeorge Joseph  * Start monitoring
1081d58de038SGeorge Joseph  *
1082d58de038SGeorge Joseph  * Try to clear LOCK, Set START, save everything else
1083d58de038SGeorge Joseph  */
1084d58de038SGeorge Joseph 	value = (value & ~0x02) | 0x01;
1085d58de038SGeorge Joseph 	write_byte(client, 0x40, value & 0xff);
1086d58de038SGeorge Joseph 
1087d58de038SGeorge Joseph }
1088d58de038SGeorge Joseph 
1089d58de038SGeorge Joseph static int
asc7621_probe(struct i2c_client * client)10907dedb79dSStephen Kitt asc7621_probe(struct i2c_client *client)
1091d58de038SGeorge Joseph {
1092d58de038SGeorge Joseph 	struct asc7621_data *data;
1093d58de038SGeorge Joseph 	int i, err;
1094d58de038SGeorge Joseph 
1095d58de038SGeorge Joseph 	if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
1096d58de038SGeorge Joseph 		return -EIO;
1097d58de038SGeorge Joseph 
109835bb95a1SGuenter Roeck 	data = devm_kzalloc(&client->dev, sizeof(struct asc7621_data),
109935bb95a1SGuenter Roeck 			    GFP_KERNEL);
1100d58de038SGeorge Joseph 	if (data == NULL)
1101d58de038SGeorge Joseph 		return -ENOMEM;
1102d58de038SGeorge Joseph 
1103d58de038SGeorge Joseph 	i2c_set_clientdata(client, data);
1104d58de038SGeorge Joseph 	mutex_init(&data->update_lock);
1105d58de038SGeorge Joseph 
1106d58de038SGeorge Joseph 	/* Initialize the asc7621 chip */
1107d58de038SGeorge Joseph 	asc7621_init_client(client);
1108d58de038SGeorge Joseph 
1109d58de038SGeorge Joseph 	/* Create the sysfs entries */
1110d58de038SGeorge Joseph 	for (i = 0; i < ARRAY_SIZE(asc7621_params); i++) {
1111d58de038SGeorge Joseph 		err =
1112d58de038SGeorge Joseph 		    device_create_file(&client->dev,
1113d58de038SGeorge Joseph 				       &(asc7621_params[i].sda.dev_attr));
1114d58de038SGeorge Joseph 		if (err)
1115d58de038SGeorge Joseph 			goto exit_remove;
1116d58de038SGeorge Joseph 	}
1117d58de038SGeorge Joseph 
1118d58de038SGeorge Joseph 	data->class_dev = hwmon_device_register(&client->dev);
1119d58de038SGeorge Joseph 	if (IS_ERR(data->class_dev)) {
1120d58de038SGeorge Joseph 		err = PTR_ERR(data->class_dev);
1121d58de038SGeorge Joseph 		goto exit_remove;
1122d58de038SGeorge Joseph 	}
1123d58de038SGeorge Joseph 
1124d58de038SGeorge Joseph 	return 0;
1125d58de038SGeorge Joseph 
1126d58de038SGeorge Joseph exit_remove:
1127d58de038SGeorge Joseph 	for (i = 0; i < ARRAY_SIZE(asc7621_params); i++) {
1128d58de038SGeorge Joseph 		device_remove_file(&client->dev,
1129d58de038SGeorge Joseph 				   &(asc7621_params[i].sda.dev_attr));
1130d58de038SGeorge Joseph 	}
1131d58de038SGeorge Joseph 
1132d58de038SGeorge Joseph 	return err;
1133d58de038SGeorge Joseph }
1134d58de038SGeorge Joseph 
asc7621_detect(struct i2c_client * client,struct i2c_board_info * info)1135d58de038SGeorge Joseph static int asc7621_detect(struct i2c_client *client,
1136d58de038SGeorge Joseph 			  struct i2c_board_info *info)
1137d58de038SGeorge Joseph {
1138d58de038SGeorge Joseph 	struct i2c_adapter *adapter = client->adapter;
1139d58de038SGeorge Joseph 	int company, verstep, chip_index;
1140d58de038SGeorge Joseph 
1141d58de038SGeorge Joseph 	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
1142d58de038SGeorge Joseph 		return -ENODEV;
1143d58de038SGeorge Joseph 
1144d58de038SGeorge Joseph 	for (chip_index = FIRST_CHIP; chip_index <= LAST_CHIP; chip_index++) {
1145d58de038SGeorge Joseph 
1146d58de038SGeorge Joseph 		if (!valid_address_for_chip(chip_index, client->addr))
1147d58de038SGeorge Joseph 			continue;
1148d58de038SGeorge Joseph 
1149d58de038SGeorge Joseph 		company = read_byte(client,
1150d58de038SGeorge Joseph 			asc7621_chips[chip_index].company_reg);
1151d58de038SGeorge Joseph 		verstep = read_byte(client,
1152d58de038SGeorge Joseph 			asc7621_chips[chip_index].verstep_reg);
1153d58de038SGeorge Joseph 
1154d58de038SGeorge Joseph 		if (company == asc7621_chips[chip_index].company_id &&
1155d58de038SGeorge Joseph 		    verstep == asc7621_chips[chip_index].verstep_id) {
1156f2f394dbSWolfram Sang 			strscpy(info->type, asc7621_chips[chip_index].name,
1157d58de038SGeorge Joseph 				I2C_NAME_SIZE);
1158d58de038SGeorge Joseph 
115928cbd461SJean Delvare 			dev_info(&adapter->dev, "Matched %s at 0x%02x\n",
116028cbd461SJean Delvare 				 asc7621_chips[chip_index].name, client->addr);
1161d58de038SGeorge Joseph 			return 0;
1162d58de038SGeorge Joseph 		}
1163d58de038SGeorge Joseph 	}
1164d58de038SGeorge Joseph 
1165d58de038SGeorge Joseph 	return -ENODEV;
1166d58de038SGeorge Joseph }
1167d58de038SGeorge Joseph 
asc7621_remove(struct i2c_client * client)1168ed5c2f5fSUwe Kleine-König static void asc7621_remove(struct i2c_client *client)
1169d58de038SGeorge Joseph {
1170d58de038SGeorge Joseph 	struct asc7621_data *data = i2c_get_clientdata(client);
1171d58de038SGeorge Joseph 	int i;
1172d58de038SGeorge Joseph 
1173d58de038SGeorge Joseph 	hwmon_device_unregister(data->class_dev);
1174d58de038SGeorge Joseph 
1175d58de038SGeorge Joseph 	for (i = 0; i < ARRAY_SIZE(asc7621_params); i++) {
1176d58de038SGeorge Joseph 		device_remove_file(&client->dev,
1177d58de038SGeorge Joseph 				   &(asc7621_params[i].sda.dev_attr));
1178d58de038SGeorge Joseph 	}
1179d58de038SGeorge Joseph }
1180d58de038SGeorge Joseph 
1181d58de038SGeorge Joseph static const struct i2c_device_id asc7621_id[] = {
1182d58de038SGeorge Joseph 	{"asc7621", asc7621},
1183d58de038SGeorge Joseph 	{"asc7621a", asc7621a},
1184d58de038SGeorge Joseph 	{},
1185d58de038SGeorge Joseph };
1186d58de038SGeorge Joseph 
1187d58de038SGeorge Joseph MODULE_DEVICE_TABLE(i2c, asc7621_id);
1188d58de038SGeorge Joseph 
1189d58de038SGeorge Joseph static struct i2c_driver asc7621_driver = {
1190d58de038SGeorge Joseph 	.class = I2C_CLASS_HWMON,
1191d58de038SGeorge Joseph 	.driver = {
1192d58de038SGeorge Joseph 		.name = "asc7621",
1193d58de038SGeorge Joseph 	},
1194*1975d167SUwe Kleine-König 	.probe = asc7621_probe,
1195d58de038SGeorge Joseph 	.remove = asc7621_remove,
1196d58de038SGeorge Joseph 	.id_table = asc7621_id,
1197d58de038SGeorge Joseph 	.detect = asc7621_detect,
1198d58de038SGeorge Joseph 	.address_list = normal_i2c,
1199d58de038SGeorge Joseph };
1200d58de038SGeorge Joseph 
sm_asc7621_init(void)1201d58de038SGeorge Joseph static int __init sm_asc7621_init(void)
1202d58de038SGeorge Joseph {
1203d58de038SGeorge Joseph 	int i, j;
1204d58de038SGeorge Joseph /*
1205d58de038SGeorge Joseph  * Collect all the registers needed into a single array.
1206d58de038SGeorge Joseph  * This way, if a register isn't actually used for anything,
1207d58de038SGeorge Joseph  * we don't retrieve it.
1208d58de038SGeorge Joseph  */
1209d58de038SGeorge Joseph 
1210d58de038SGeorge Joseph 	for (i = 0; i < ARRAY_SIZE(asc7621_params); i++) {
1211d58de038SGeorge Joseph 		for (j = 0; j < ARRAY_SIZE(asc7621_params[i].msb); j++)
1212d58de038SGeorge Joseph 			asc7621_register_priorities[asc7621_params[i].msb[j]] =
1213d58de038SGeorge Joseph 			    asc7621_params[i].priority;
1214d58de038SGeorge Joseph 		for (j = 0; j < ARRAY_SIZE(asc7621_params[i].lsb); j++)
1215d58de038SGeorge Joseph 			asc7621_register_priorities[asc7621_params[i].lsb[j]] =
1216d58de038SGeorge Joseph 			    asc7621_params[i].priority;
1217d58de038SGeorge Joseph 	}
1218d58de038SGeorge Joseph 	return i2c_add_driver(&asc7621_driver);
1219d58de038SGeorge Joseph }
1220d58de038SGeorge Joseph 
sm_asc7621_exit(void)1221d58de038SGeorge Joseph static void __exit sm_asc7621_exit(void)
1222d58de038SGeorge Joseph {
1223d58de038SGeorge Joseph 	i2c_del_driver(&asc7621_driver);
1224d58de038SGeorge Joseph }
1225d58de038SGeorge Joseph 
1226d58de038SGeorge Joseph MODULE_LICENSE("GPL");
1227d58de038SGeorge Joseph MODULE_AUTHOR("George Joseph");
1228d58de038SGeorge Joseph MODULE_DESCRIPTION("Andigilog aSC7621 and aSC7621a driver");
1229d58de038SGeorge Joseph 
1230d58de038SGeorge Joseph module_init(sm_asc7621_init);
1231d58de038SGeorge Joseph module_exit(sm_asc7621_exit);
1232