xref: /openbmc/linux/drivers/misc/ics932s401.c (revision 2612e3bbc0386368a850140a6c9b990cd496a5ec)
11a59d1b8SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
2a412ae3fSDarrick J. Wong /*
3a412ae3fSDarrick J. Wong  * A driver for the Integrated Circuits ICS932S401
4a412ae3fSDarrick J. Wong  * Copyright (C) 2008 IBM
5a412ae3fSDarrick J. Wong  *
65407e051SDarrick J. Wong  * Author: Darrick J. Wong <darrick.wong@oracle.com>
7a412ae3fSDarrick J. Wong  */
8a412ae3fSDarrick J. Wong 
9a412ae3fSDarrick J. Wong #include <linux/module.h>
10a412ae3fSDarrick J. Wong #include <linux/jiffies.h>
11a412ae3fSDarrick J. Wong #include <linux/i2c.h>
12a412ae3fSDarrick J. Wong #include <linux/err.h>
13a412ae3fSDarrick J. Wong #include <linux/mutex.h>
14a412ae3fSDarrick J. Wong #include <linux/delay.h>
15a412ae3fSDarrick J. Wong #include <linux/log2.h>
165a0e3ad6STejun Heo #include <linux/slab.h>
17a412ae3fSDarrick J. Wong 
18a412ae3fSDarrick J. Wong /* Addresses to scan */
19a412ae3fSDarrick J. Wong static const unsigned short normal_i2c[] = { 0x69, I2C_CLIENT_END };
20a412ae3fSDarrick J. Wong 
21a412ae3fSDarrick J. Wong /* ICS932S401 registers */
22a412ae3fSDarrick J. Wong #define ICS932S401_REG_CFG2			0x01
23a412ae3fSDarrick J. Wong #define		ICS932S401_CFG1_SPREAD		0x01
24a412ae3fSDarrick J. Wong #define ICS932S401_REG_CFG7			0x06
25a412ae3fSDarrick J. Wong #define		ICS932S401_FS_MASK		0x07
26a412ae3fSDarrick J. Wong #define	ICS932S401_REG_VENDOR_REV		0x07
27a412ae3fSDarrick J. Wong #define		ICS932S401_VENDOR		1
28a412ae3fSDarrick J. Wong #define		ICS932S401_VENDOR_MASK		0x0F
29a412ae3fSDarrick J. Wong #define		ICS932S401_REV			4
30a412ae3fSDarrick J. Wong #define		ICS932S401_REV_SHIFT		4
31a412ae3fSDarrick J. Wong #define ICS932S401_REG_DEVICE			0x09
32a412ae3fSDarrick J. Wong #define		ICS932S401_DEVICE		11
33a412ae3fSDarrick J. Wong #define	ICS932S401_REG_CTRL			0x0A
34a412ae3fSDarrick J. Wong #define		ICS932S401_MN_ENABLED		0x80
35a412ae3fSDarrick J. Wong #define		ICS932S401_CPU_ALT		0x04
36a412ae3fSDarrick J. Wong #define		ICS932S401_SRC_ALT		0x08
37a412ae3fSDarrick J. Wong #define ICS932S401_REG_CPU_M_CTRL		0x0B
38a412ae3fSDarrick J. Wong #define		ICS932S401_M_MASK		0x3F
39a412ae3fSDarrick J. Wong #define	ICS932S401_REG_CPU_N_CTRL		0x0C
40a412ae3fSDarrick J. Wong #define	ICS932S401_REG_CPU_SPREAD1		0x0D
41a412ae3fSDarrick J. Wong #define ICS932S401_REG_CPU_SPREAD2		0x0E
42a412ae3fSDarrick J. Wong #define		ICS932S401_SPREAD_MASK		0x7FFF
43a412ae3fSDarrick J. Wong #define ICS932S401_REG_SRC_M_CTRL		0x0F
44a412ae3fSDarrick J. Wong #define ICS932S401_REG_SRC_N_CTRL		0x10
45a412ae3fSDarrick J. Wong #define	ICS932S401_REG_SRC_SPREAD1		0x11
46a412ae3fSDarrick J. Wong #define ICS932S401_REG_SRC_SPREAD2		0x12
47a412ae3fSDarrick J. Wong #define ICS932S401_REG_CPU_DIVISOR		0x13
48a412ae3fSDarrick J. Wong #define		ICS932S401_CPU_DIVISOR_SHIFT	4
49a412ae3fSDarrick J. Wong #define ICS932S401_REG_PCISRC_DIVISOR		0x14
50a412ae3fSDarrick J. Wong #define		ICS932S401_SRC_DIVISOR_MASK	0x0F
51a412ae3fSDarrick J. Wong #define		ICS932S401_PCI_DIVISOR_SHIFT	4
52a412ae3fSDarrick J. Wong 
53a412ae3fSDarrick J. Wong /* Base clock is 14.318MHz */
54a412ae3fSDarrick J. Wong #define BASE_CLOCK				14318
55a412ae3fSDarrick J. Wong 
56a412ae3fSDarrick J. Wong #define NUM_REGS				21
57a412ae3fSDarrick J. Wong #define NUM_MIRRORED_REGS			15
58a412ae3fSDarrick J. Wong 
59a412ae3fSDarrick J. Wong static int regs_to_copy[NUM_MIRRORED_REGS] = {
60a412ae3fSDarrick J. Wong 	ICS932S401_REG_CFG2,
61a412ae3fSDarrick J. Wong 	ICS932S401_REG_CFG7,
62a412ae3fSDarrick J. Wong 	ICS932S401_REG_VENDOR_REV,
63a412ae3fSDarrick J. Wong 	ICS932S401_REG_DEVICE,
64a412ae3fSDarrick J. Wong 	ICS932S401_REG_CTRL,
65a412ae3fSDarrick J. Wong 	ICS932S401_REG_CPU_M_CTRL,
66a412ae3fSDarrick J. Wong 	ICS932S401_REG_CPU_N_CTRL,
67a412ae3fSDarrick J. Wong 	ICS932S401_REG_CPU_SPREAD1,
68a412ae3fSDarrick J. Wong 	ICS932S401_REG_CPU_SPREAD2,
69a412ae3fSDarrick J. Wong 	ICS932S401_REG_SRC_M_CTRL,
70a412ae3fSDarrick J. Wong 	ICS932S401_REG_SRC_N_CTRL,
71a412ae3fSDarrick J. Wong 	ICS932S401_REG_SRC_SPREAD1,
72a412ae3fSDarrick J. Wong 	ICS932S401_REG_SRC_SPREAD2,
73a412ae3fSDarrick J. Wong 	ICS932S401_REG_CPU_DIVISOR,
74a412ae3fSDarrick J. Wong 	ICS932S401_REG_PCISRC_DIVISOR,
75a412ae3fSDarrick J. Wong };
76a412ae3fSDarrick J. Wong 
77a412ae3fSDarrick J. Wong /* How often do we reread sensors values? (In jiffies) */
78a412ae3fSDarrick J. Wong #define SENSOR_REFRESH_INTERVAL	(2 * HZ)
79a412ae3fSDarrick J. Wong 
80a412ae3fSDarrick J. Wong /* How often do we reread sensor limit values? (In jiffies) */
81a412ae3fSDarrick J. Wong #define LIMIT_REFRESH_INTERVAL	(60 * HZ)
82a412ae3fSDarrick J. Wong 
83a412ae3fSDarrick J. Wong struct ics932s401_data {
84a412ae3fSDarrick J. Wong 	struct attribute_group	attrs;
85a412ae3fSDarrick J. Wong 	struct mutex		lock;
86a412ae3fSDarrick J. Wong 	char			sensors_valid;
87a412ae3fSDarrick J. Wong 	unsigned long		sensors_last_updated;	/* In jiffies */
88a412ae3fSDarrick J. Wong 
89a412ae3fSDarrick J. Wong 	u8			regs[NUM_REGS];
90a412ae3fSDarrick J. Wong };
91a412ae3fSDarrick J. Wong 
929c18dad4SUwe Kleine-König static int ics932s401_probe(struct i2c_client *client);
93310ec792SJean Delvare static int ics932s401_detect(struct i2c_client *client,
94a412ae3fSDarrick J. Wong 			  struct i2c_board_info *info);
95ed5c2f5fSUwe Kleine-König static void ics932s401_remove(struct i2c_client *client);
96a412ae3fSDarrick J. Wong 
97a412ae3fSDarrick J. Wong static const struct i2c_device_id ics932s401_id[] = {
981f86df49SJean Delvare 	{ "ics932s401", 0 },
99a412ae3fSDarrick J. Wong 	{ }
100a412ae3fSDarrick J. Wong };
101a412ae3fSDarrick J. Wong MODULE_DEVICE_TABLE(i2c, ics932s401_id);
102a412ae3fSDarrick J. Wong 
103a412ae3fSDarrick J. Wong static struct i2c_driver ics932s401_driver = {
104a412ae3fSDarrick J. Wong 	.class		= I2C_CLASS_HWMON,
105a412ae3fSDarrick J. Wong 	.driver = {
106a412ae3fSDarrick J. Wong 		.name	= "ics932s401",
107a412ae3fSDarrick J. Wong 	},
108*f050bb8fSUwe Kleine-König 	.probe		= ics932s401_probe,
109a412ae3fSDarrick J. Wong 	.remove		= ics932s401_remove,
110a412ae3fSDarrick J. Wong 	.id_table	= ics932s401_id,
111a412ae3fSDarrick J. Wong 	.detect		= ics932s401_detect,
112c3813d6aSJean Delvare 	.address_list	= normal_i2c,
113a412ae3fSDarrick J. Wong };
114a412ae3fSDarrick J. Wong 
ics932s401_update_device(struct device * dev)115a412ae3fSDarrick J. Wong static struct ics932s401_data *ics932s401_update_device(struct device *dev)
116a412ae3fSDarrick J. Wong {
117a412ae3fSDarrick J. Wong 	struct i2c_client *client = to_i2c_client(dev);
118a412ae3fSDarrick J. Wong 	struct ics932s401_data *data = i2c_get_clientdata(client);
119a412ae3fSDarrick J. Wong 	unsigned long local_jiffies = jiffies;
120a412ae3fSDarrick J. Wong 	int i, temp;
121a412ae3fSDarrick J. Wong 
122a412ae3fSDarrick J. Wong 	mutex_lock(&data->lock);
123a412ae3fSDarrick J. Wong 	if (time_before(local_jiffies, data->sensors_last_updated +
124a412ae3fSDarrick J. Wong 		SENSOR_REFRESH_INTERVAL)
125a412ae3fSDarrick J. Wong 		&& data->sensors_valid)
126a412ae3fSDarrick J. Wong 		goto out;
127a412ae3fSDarrick J. Wong 
128a412ae3fSDarrick J. Wong 	/*
129a412ae3fSDarrick J. Wong 	 * Each register must be read as a word and then right shifted 8 bits.
130a412ae3fSDarrick J. Wong 	 * Not really sure why this is; setting the "byte count programming"
131a412ae3fSDarrick J. Wong 	 * register to 1 does not fix this problem.
132a412ae3fSDarrick J. Wong 	 */
133a412ae3fSDarrick J. Wong 	for (i = 0; i < NUM_MIRRORED_REGS; i++) {
134a412ae3fSDarrick J. Wong 		temp = i2c_smbus_read_word_data(client, regs_to_copy[i]);
135b05ae01fSAditya Pakki 		if (temp < 0)
136a73b6a3bSDarrick J. Wong 			temp = 0;
137a412ae3fSDarrick J. Wong 		data->regs[regs_to_copy[i]] = temp >> 8;
138a412ae3fSDarrick J. Wong 	}
139a412ae3fSDarrick J. Wong 
140a412ae3fSDarrick J. Wong 	data->sensors_last_updated = local_jiffies;
141a412ae3fSDarrick J. Wong 	data->sensors_valid = 1;
142a412ae3fSDarrick J. Wong 
143a412ae3fSDarrick J. Wong out:
144a412ae3fSDarrick J. Wong 	mutex_unlock(&data->lock);
145a412ae3fSDarrick J. Wong 	return data;
146a412ae3fSDarrick J. Wong }
147a412ae3fSDarrick J. Wong 
show_spread_enabled(struct device * dev,struct device_attribute * devattr,char * buf)148a412ae3fSDarrick J. Wong static ssize_t show_spread_enabled(struct device *dev,
149a412ae3fSDarrick J. Wong 				   struct device_attribute *devattr,
150a412ae3fSDarrick J. Wong 				   char *buf)
151a412ae3fSDarrick J. Wong {
152a412ae3fSDarrick J. Wong 	struct ics932s401_data *data = ics932s401_update_device(dev);
153a412ae3fSDarrick J. Wong 
154a412ae3fSDarrick J. Wong 	if (data->regs[ICS932S401_REG_CFG2] & ICS932S401_CFG1_SPREAD)
155a412ae3fSDarrick J. Wong 		return sprintf(buf, "1\n");
156a412ae3fSDarrick J. Wong 
157a412ae3fSDarrick J. Wong 	return sprintf(buf, "0\n");
158a412ae3fSDarrick J. Wong }
159a412ae3fSDarrick J. Wong 
160a412ae3fSDarrick J. Wong /* bit to cpu khz map */
161a412ae3fSDarrick J. Wong static const int fs_speeds[] = {
162a412ae3fSDarrick J. Wong 	266666,
163a412ae3fSDarrick J. Wong 	133333,
164a412ae3fSDarrick J. Wong 	200000,
165a412ae3fSDarrick J. Wong 	166666,
166a412ae3fSDarrick J. Wong 	333333,
167a412ae3fSDarrick J. Wong 	100000,
168a412ae3fSDarrick J. Wong 	400000,
169a412ae3fSDarrick J. Wong 	0,
170a412ae3fSDarrick J. Wong };
171a412ae3fSDarrick J. Wong 
172a412ae3fSDarrick J. Wong /* clock divisor map */
173a412ae3fSDarrick J. Wong static const int divisors[] = {2, 3, 5, 15, 4, 6, 10, 30, 8, 12, 20, 60, 16,
174a412ae3fSDarrick J. Wong 			       24, 40, 120};
175a412ae3fSDarrick J. Wong 
176a412ae3fSDarrick J. Wong /* Calculate CPU frequency from the M/N registers. */
calculate_cpu_freq(struct ics932s401_data * data)177a412ae3fSDarrick J. Wong static int calculate_cpu_freq(struct ics932s401_data *data)
178a412ae3fSDarrick J. Wong {
179a412ae3fSDarrick J. Wong 	int m, n, freq;
180a412ae3fSDarrick J. Wong 
181a412ae3fSDarrick J. Wong 	m = data->regs[ICS932S401_REG_CPU_M_CTRL] & ICS932S401_M_MASK;
182a412ae3fSDarrick J. Wong 	n = data->regs[ICS932S401_REG_CPU_N_CTRL];
183a412ae3fSDarrick J. Wong 
184a412ae3fSDarrick J. Wong 	/* Pull in bits 8 & 9 from the M register */
185a412ae3fSDarrick J. Wong 	n |= ((int)data->regs[ICS932S401_REG_CPU_M_CTRL] & 0x80) << 1;
186a412ae3fSDarrick J. Wong 	n |= ((int)data->regs[ICS932S401_REG_CPU_M_CTRL] & 0x40) << 3;
187a412ae3fSDarrick J. Wong 
188a412ae3fSDarrick J. Wong 	freq = BASE_CLOCK * (n + 8) / (m + 2);
189a412ae3fSDarrick J. Wong 	freq /= divisors[data->regs[ICS932S401_REG_CPU_DIVISOR] >>
190a412ae3fSDarrick J. Wong 			 ICS932S401_CPU_DIVISOR_SHIFT];
191a412ae3fSDarrick J. Wong 
192a412ae3fSDarrick J. Wong 	return freq;
193a412ae3fSDarrick J. Wong }
194a412ae3fSDarrick J. Wong 
show_cpu_clock(struct device * dev,struct device_attribute * devattr,char * buf)195a412ae3fSDarrick J. Wong static ssize_t show_cpu_clock(struct device *dev,
196a412ae3fSDarrick J. Wong 			      struct device_attribute *devattr,
197a412ae3fSDarrick J. Wong 			      char *buf)
198a412ae3fSDarrick J. Wong {
199a412ae3fSDarrick J. Wong 	struct ics932s401_data *data = ics932s401_update_device(dev);
200a412ae3fSDarrick J. Wong 
201a412ae3fSDarrick J. Wong 	return sprintf(buf, "%d\n", calculate_cpu_freq(data));
202a412ae3fSDarrick J. Wong }
203a412ae3fSDarrick J. Wong 
show_cpu_clock_sel(struct device * dev,struct device_attribute * devattr,char * buf)204a412ae3fSDarrick J. Wong static ssize_t show_cpu_clock_sel(struct device *dev,
205a412ae3fSDarrick J. Wong 				  struct device_attribute *devattr,
206a412ae3fSDarrick J. Wong 				  char *buf)
207a412ae3fSDarrick J. Wong {
208a412ae3fSDarrick J. Wong 	struct ics932s401_data *data = ics932s401_update_device(dev);
209a412ae3fSDarrick J. Wong 	int freq;
210a412ae3fSDarrick J. Wong 
211a412ae3fSDarrick J. Wong 	if (data->regs[ICS932S401_REG_CTRL] & ICS932S401_MN_ENABLED)
212a412ae3fSDarrick J. Wong 		freq = calculate_cpu_freq(data);
213a412ae3fSDarrick J. Wong 	else {
214a412ae3fSDarrick J. Wong 		/* Freq is neatly wrapped up for us */
215a412ae3fSDarrick J. Wong 		int fid = data->regs[ICS932S401_REG_CFG7] & ICS932S401_FS_MASK;
21667d0833fSDhaval Shah 
217a412ae3fSDarrick J. Wong 		freq = fs_speeds[fid];
218a412ae3fSDarrick J. Wong 		if (data->regs[ICS932S401_REG_CTRL] & ICS932S401_CPU_ALT) {
219a412ae3fSDarrick J. Wong 			switch (freq) {
220a412ae3fSDarrick J. Wong 			case 166666:
221a412ae3fSDarrick J. Wong 				freq = 160000;
222a412ae3fSDarrick J. Wong 				break;
223a412ae3fSDarrick J. Wong 			case 333333:
224a412ae3fSDarrick J. Wong 				freq = 320000;
225a412ae3fSDarrick J. Wong 				break;
226a412ae3fSDarrick J. Wong 			}
227a412ae3fSDarrick J. Wong 		}
228a412ae3fSDarrick J. Wong 	}
229a412ae3fSDarrick J. Wong 
230a412ae3fSDarrick J. Wong 	return sprintf(buf, "%d\n", freq);
231a412ae3fSDarrick J. Wong }
232a412ae3fSDarrick J. Wong 
233a412ae3fSDarrick J. Wong /* Calculate SRC frequency from the M/N registers. */
calculate_src_freq(struct ics932s401_data * data)234a412ae3fSDarrick J. Wong static int calculate_src_freq(struct ics932s401_data *data)
235a412ae3fSDarrick J. Wong {
236a412ae3fSDarrick J. Wong 	int m, n, freq;
237a412ae3fSDarrick J. Wong 
238a412ae3fSDarrick J. Wong 	m = data->regs[ICS932S401_REG_SRC_M_CTRL] & ICS932S401_M_MASK;
239a412ae3fSDarrick J. Wong 	n = data->regs[ICS932S401_REG_SRC_N_CTRL];
240a412ae3fSDarrick J. Wong 
241a412ae3fSDarrick J. Wong 	/* Pull in bits 8 & 9 from the M register */
242a412ae3fSDarrick J. Wong 	n |= ((int)data->regs[ICS932S401_REG_SRC_M_CTRL] & 0x80) << 1;
243a412ae3fSDarrick J. Wong 	n |= ((int)data->regs[ICS932S401_REG_SRC_M_CTRL] & 0x40) << 3;
244a412ae3fSDarrick J. Wong 
245a412ae3fSDarrick J. Wong 	freq = BASE_CLOCK * (n + 8) / (m + 2);
246a412ae3fSDarrick J. Wong 	freq /= divisors[data->regs[ICS932S401_REG_PCISRC_DIVISOR] &
247a412ae3fSDarrick J. Wong 			 ICS932S401_SRC_DIVISOR_MASK];
248a412ae3fSDarrick J. Wong 
249a412ae3fSDarrick J. Wong 	return freq;
250a412ae3fSDarrick J. Wong }
251a412ae3fSDarrick J. Wong 
show_src_clock(struct device * dev,struct device_attribute * devattr,char * buf)252a412ae3fSDarrick J. Wong static ssize_t show_src_clock(struct device *dev,
253a412ae3fSDarrick J. Wong 			      struct device_attribute *devattr,
254a412ae3fSDarrick J. Wong 			      char *buf)
255a412ae3fSDarrick J. Wong {
256a412ae3fSDarrick J. Wong 	struct ics932s401_data *data = ics932s401_update_device(dev);
257a412ae3fSDarrick J. Wong 
258a412ae3fSDarrick J. Wong 	return sprintf(buf, "%d\n", calculate_src_freq(data));
259a412ae3fSDarrick J. Wong }
260a412ae3fSDarrick J. Wong 
show_src_clock_sel(struct device * dev,struct device_attribute * devattr,char * buf)261a412ae3fSDarrick J. Wong static ssize_t show_src_clock_sel(struct device *dev,
262a412ae3fSDarrick J. Wong 				  struct device_attribute *devattr,
263a412ae3fSDarrick J. Wong 				  char *buf)
264a412ae3fSDarrick J. Wong {
265a412ae3fSDarrick J. Wong 	struct ics932s401_data *data = ics932s401_update_device(dev);
266a412ae3fSDarrick J. Wong 	int freq;
267a412ae3fSDarrick J. Wong 
268a412ae3fSDarrick J. Wong 	if (data->regs[ICS932S401_REG_CTRL] & ICS932S401_MN_ENABLED)
269a412ae3fSDarrick J. Wong 		freq = calculate_src_freq(data);
270a412ae3fSDarrick J. Wong 	else
271a412ae3fSDarrick J. Wong 		/* Freq is neatly wrapped up for us */
272a412ae3fSDarrick J. Wong 		if (data->regs[ICS932S401_REG_CTRL] & ICS932S401_CPU_ALT &&
273a412ae3fSDarrick J. Wong 		    data->regs[ICS932S401_REG_CTRL] & ICS932S401_SRC_ALT)
274a412ae3fSDarrick J. Wong 			freq = 96000;
275a412ae3fSDarrick J. Wong 		else
276a412ae3fSDarrick J. Wong 			freq = 100000;
277a412ae3fSDarrick J. Wong 
278a412ae3fSDarrick J. Wong 	return sprintf(buf, "%d\n", freq);
279a412ae3fSDarrick J. Wong }
280a412ae3fSDarrick J. Wong 
281a412ae3fSDarrick J. Wong /* Calculate PCI frequency from the SRC M/N registers. */
calculate_pci_freq(struct ics932s401_data * data)282a412ae3fSDarrick J. Wong static int calculate_pci_freq(struct ics932s401_data *data)
283a412ae3fSDarrick J. Wong {
284a412ae3fSDarrick J. Wong 	int m, n, freq;
285a412ae3fSDarrick J. Wong 
286a412ae3fSDarrick J. Wong 	m = data->regs[ICS932S401_REG_SRC_M_CTRL] & ICS932S401_M_MASK;
287a412ae3fSDarrick J. Wong 	n = data->regs[ICS932S401_REG_SRC_N_CTRL];
288a412ae3fSDarrick J. Wong 
289a412ae3fSDarrick J. Wong 	/* Pull in bits 8 & 9 from the M register */
290a412ae3fSDarrick J. Wong 	n |= ((int)data->regs[ICS932S401_REG_SRC_M_CTRL] & 0x80) << 1;
291a412ae3fSDarrick J. Wong 	n |= ((int)data->regs[ICS932S401_REG_SRC_M_CTRL] & 0x40) << 3;
292a412ae3fSDarrick J. Wong 
293a412ae3fSDarrick J. Wong 	freq = BASE_CLOCK * (n + 8) / (m + 2);
294a412ae3fSDarrick J. Wong 	freq /= divisors[data->regs[ICS932S401_REG_PCISRC_DIVISOR] >>
295a412ae3fSDarrick J. Wong 			 ICS932S401_PCI_DIVISOR_SHIFT];
296a412ae3fSDarrick J. Wong 
297a412ae3fSDarrick J. Wong 	return freq;
298a412ae3fSDarrick J. Wong }
299a412ae3fSDarrick J. Wong 
show_pci_clock(struct device * dev,struct device_attribute * devattr,char * buf)300a412ae3fSDarrick J. Wong static ssize_t show_pci_clock(struct device *dev,
301a412ae3fSDarrick J. Wong 			      struct device_attribute *devattr,
302a412ae3fSDarrick J. Wong 			      char *buf)
303a412ae3fSDarrick J. Wong {
304a412ae3fSDarrick J. Wong 	struct ics932s401_data *data = ics932s401_update_device(dev);
305a412ae3fSDarrick J. Wong 
306a412ae3fSDarrick J. Wong 	return sprintf(buf, "%d\n", calculate_pci_freq(data));
307a412ae3fSDarrick J. Wong }
308a412ae3fSDarrick J. Wong 
show_pci_clock_sel(struct device * dev,struct device_attribute * devattr,char * buf)309a412ae3fSDarrick J. Wong static ssize_t show_pci_clock_sel(struct device *dev,
310a412ae3fSDarrick J. Wong 				  struct device_attribute *devattr,
311a412ae3fSDarrick J. Wong 				  char *buf)
312a412ae3fSDarrick J. Wong {
313a412ae3fSDarrick J. Wong 	struct ics932s401_data *data = ics932s401_update_device(dev);
314a412ae3fSDarrick J. Wong 	int freq;
315a412ae3fSDarrick J. Wong 
316a412ae3fSDarrick J. Wong 	if (data->regs[ICS932S401_REG_CTRL] & ICS932S401_MN_ENABLED)
317a412ae3fSDarrick J. Wong 		freq = calculate_pci_freq(data);
318a412ae3fSDarrick J. Wong 	else
319a412ae3fSDarrick J. Wong 		freq = 33333;
320a412ae3fSDarrick J. Wong 
321a412ae3fSDarrick J. Wong 	return sprintf(buf, "%d\n", freq);
322a412ae3fSDarrick J. Wong }
323a412ae3fSDarrick J. Wong 
324a412ae3fSDarrick J. Wong static ssize_t show_value(struct device *dev,
325a412ae3fSDarrick J. Wong 			  struct device_attribute *devattr,
326a412ae3fSDarrick J. Wong 			  char *buf);
327a412ae3fSDarrick J. Wong 
328a412ae3fSDarrick J. Wong static ssize_t show_spread(struct device *dev,
329a412ae3fSDarrick J. Wong 			   struct device_attribute *devattr,
330a412ae3fSDarrick J. Wong 			   char *buf);
331a412ae3fSDarrick J. Wong 
332a412ae3fSDarrick J. Wong static DEVICE_ATTR(spread_enabled, S_IRUGO, show_spread_enabled, NULL);
333a412ae3fSDarrick J. Wong static DEVICE_ATTR(cpu_clock_selection, S_IRUGO, show_cpu_clock_sel, NULL);
334a412ae3fSDarrick J. Wong static DEVICE_ATTR(cpu_clock, S_IRUGO, show_cpu_clock, NULL);
335a412ae3fSDarrick J. Wong static DEVICE_ATTR(src_clock_selection, S_IRUGO, show_src_clock_sel, NULL);
336a412ae3fSDarrick J. Wong static DEVICE_ATTR(src_clock, S_IRUGO, show_src_clock, NULL);
337a412ae3fSDarrick J. Wong static DEVICE_ATTR(pci_clock_selection, S_IRUGO, show_pci_clock_sel, NULL);
338a412ae3fSDarrick J. Wong static DEVICE_ATTR(pci_clock, S_IRUGO, show_pci_clock, NULL);
339a412ae3fSDarrick J. Wong static DEVICE_ATTR(usb_clock, S_IRUGO, show_value, NULL);
340a412ae3fSDarrick J. Wong static DEVICE_ATTR(ref_clock, S_IRUGO, show_value, NULL);
341a412ae3fSDarrick J. Wong static DEVICE_ATTR(cpu_spread, S_IRUGO, show_spread, NULL);
342a412ae3fSDarrick J. Wong static DEVICE_ATTR(src_spread, S_IRUGO, show_spread, NULL);
343a412ae3fSDarrick J. Wong 
3443288de12SDhaval Shah static struct attribute *ics932s401_attr[] = {
345a412ae3fSDarrick J. Wong 	&dev_attr_spread_enabled.attr,
346a412ae3fSDarrick J. Wong 	&dev_attr_cpu_clock_selection.attr,
347a412ae3fSDarrick J. Wong 	&dev_attr_cpu_clock.attr,
348a412ae3fSDarrick J. Wong 	&dev_attr_src_clock_selection.attr,
349a412ae3fSDarrick J. Wong 	&dev_attr_src_clock.attr,
350a412ae3fSDarrick J. Wong 	&dev_attr_pci_clock_selection.attr,
351a412ae3fSDarrick J. Wong 	&dev_attr_pci_clock.attr,
352a412ae3fSDarrick J. Wong 	&dev_attr_usb_clock.attr,
353a412ae3fSDarrick J. Wong 	&dev_attr_ref_clock.attr,
354a412ae3fSDarrick J. Wong 	&dev_attr_cpu_spread.attr,
355a412ae3fSDarrick J. Wong 	&dev_attr_src_spread.attr,
356a412ae3fSDarrick J. Wong 	NULL
357a412ae3fSDarrick J. Wong };
358a412ae3fSDarrick J. Wong 
show_value(struct device * dev,struct device_attribute * devattr,char * buf)359a412ae3fSDarrick J. Wong static ssize_t show_value(struct device *dev,
360a412ae3fSDarrick J. Wong 			  struct device_attribute *devattr,
361a412ae3fSDarrick J. Wong 			  char *buf)
362a412ae3fSDarrick J. Wong {
363a412ae3fSDarrick J. Wong 	int x;
364a412ae3fSDarrick J. Wong 
365a412ae3fSDarrick J. Wong 	if (devattr == &dev_attr_usb_clock)
366a412ae3fSDarrick J. Wong 		x = 48000;
367a412ae3fSDarrick J. Wong 	else if (devattr == &dev_attr_ref_clock)
368a412ae3fSDarrick J. Wong 		x = BASE_CLOCK;
369a412ae3fSDarrick J. Wong 	else
370a412ae3fSDarrick J. Wong 		BUG();
371a412ae3fSDarrick J. Wong 
372a412ae3fSDarrick J. Wong 	return sprintf(buf, "%d\n", x);
373a412ae3fSDarrick J. Wong }
374a412ae3fSDarrick J. Wong 
show_spread(struct device * dev,struct device_attribute * devattr,char * buf)375a412ae3fSDarrick J. Wong static ssize_t show_spread(struct device *dev,
376a412ae3fSDarrick J. Wong 			   struct device_attribute *devattr,
377a412ae3fSDarrick J. Wong 			   char *buf)
378a412ae3fSDarrick J. Wong {
379a412ae3fSDarrick J. Wong 	struct ics932s401_data *data = ics932s401_update_device(dev);
380a412ae3fSDarrick J. Wong 	int reg;
381a412ae3fSDarrick J. Wong 	unsigned long val;
382a412ae3fSDarrick J. Wong 
383a412ae3fSDarrick J. Wong 	if (!(data->regs[ICS932S401_REG_CFG2] & ICS932S401_CFG1_SPREAD))
384a412ae3fSDarrick J. Wong 		return sprintf(buf, "0%%\n");
385a412ae3fSDarrick J. Wong 
386a412ae3fSDarrick J. Wong 	if (devattr == &dev_attr_src_spread)
387a412ae3fSDarrick J. Wong 		reg = ICS932S401_REG_SRC_SPREAD1;
388a412ae3fSDarrick J. Wong 	else if (devattr == &dev_attr_cpu_spread)
389a412ae3fSDarrick J. Wong 		reg = ICS932S401_REG_CPU_SPREAD1;
390a412ae3fSDarrick J. Wong 	else
391a412ae3fSDarrick J. Wong 		BUG();
392a412ae3fSDarrick J. Wong 
393a412ae3fSDarrick J. Wong 	val = data->regs[reg] | (data->regs[reg + 1] << 8);
394a412ae3fSDarrick J. Wong 	val &= ICS932S401_SPREAD_MASK;
395a412ae3fSDarrick J. Wong 
396a412ae3fSDarrick J. Wong 	/* Scale 0..2^14 to -0.5. */
397a412ae3fSDarrick J. Wong 	val = 500000 * val / 16384;
398a412ae3fSDarrick J. Wong 	return sprintf(buf, "-0.%lu%%\n", val);
399a412ae3fSDarrick J. Wong }
400a412ae3fSDarrick J. Wong 
401a412ae3fSDarrick J. Wong /* Return 0 if detection is successful, -ENODEV otherwise */
ics932s401_detect(struct i2c_client * client,struct i2c_board_info * info)402310ec792SJean Delvare static int ics932s401_detect(struct i2c_client *client,
403a412ae3fSDarrick J. Wong 			  struct i2c_board_info *info)
404a412ae3fSDarrick J. Wong {
405a412ae3fSDarrick J. Wong 	struct i2c_adapter *adapter = client->adapter;
406c2e90e9bSJean Delvare 	int vendor, device, revision;
407a412ae3fSDarrick J. Wong 
408a412ae3fSDarrick J. Wong 	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
409a412ae3fSDarrick J. Wong 		return -ENODEV;
410a412ae3fSDarrick J. Wong 
411c2e90e9bSJean Delvare 	vendor = i2c_smbus_read_word_data(client, ICS932S401_REG_VENDOR_REV);
412a412ae3fSDarrick J. Wong 	vendor >>= 8;
413a412ae3fSDarrick J. Wong 	revision = vendor >> ICS932S401_REV_SHIFT;
414a412ae3fSDarrick J. Wong 	vendor &= ICS932S401_VENDOR_MASK;
415a412ae3fSDarrick J. Wong 	if (vendor != ICS932S401_VENDOR)
416a412ae3fSDarrick J. Wong 		return -ENODEV;
417a412ae3fSDarrick J. Wong 
418c2e90e9bSJean Delvare 	device = i2c_smbus_read_word_data(client, ICS932S401_REG_DEVICE);
419a412ae3fSDarrick J. Wong 	device >>= 8;
420a412ae3fSDarrick J. Wong 	if (device != ICS932S401_DEVICE)
421a412ae3fSDarrick J. Wong 		return -ENODEV;
422a412ae3fSDarrick J. Wong 
423a412ae3fSDarrick J. Wong 	if (revision != ICS932S401_REV)
424c2e90e9bSJean Delvare 		dev_info(&adapter->dev, "Unknown revision %d\n", revision);
425a412ae3fSDarrick J. Wong 
4265192e395SWolfram Sang 	strscpy(info->type, "ics932s401", I2C_NAME_SIZE);
427a412ae3fSDarrick J. Wong 
428a412ae3fSDarrick J. Wong 	return 0;
429a412ae3fSDarrick J. Wong }
430a412ae3fSDarrick J. Wong 
ics932s401_probe(struct i2c_client * client)4319c18dad4SUwe Kleine-König static int ics932s401_probe(struct i2c_client *client)
432a412ae3fSDarrick J. Wong {
433a412ae3fSDarrick J. Wong 	struct ics932s401_data *data;
434a412ae3fSDarrick J. Wong 	int err;
435a412ae3fSDarrick J. Wong 
436a412ae3fSDarrick J. Wong 	data = kzalloc(sizeof(struct ics932s401_data), GFP_KERNEL);
437a412ae3fSDarrick J. Wong 	if (!data) {
438a412ae3fSDarrick J. Wong 		err = -ENOMEM;
439a412ae3fSDarrick J. Wong 		goto exit;
440a412ae3fSDarrick J. Wong 	}
441a412ae3fSDarrick J. Wong 
442a412ae3fSDarrick J. Wong 	i2c_set_clientdata(client, data);
443a412ae3fSDarrick J. Wong 	mutex_init(&data->lock);
444a412ae3fSDarrick J. Wong 
445a412ae3fSDarrick J. Wong 	dev_info(&client->dev, "%s chip found\n", client->name);
446a412ae3fSDarrick J. Wong 
447a412ae3fSDarrick J. Wong 	/* Register sysfs hooks */
448a412ae3fSDarrick J. Wong 	data->attrs.attrs = ics932s401_attr;
449a412ae3fSDarrick J. Wong 	err = sysfs_create_group(&client->dev.kobj, &data->attrs);
450a412ae3fSDarrick J. Wong 	if (err)
451a412ae3fSDarrick J. Wong 		goto exit_free;
452a412ae3fSDarrick J. Wong 
453a412ae3fSDarrick J. Wong 	return 0;
454a412ae3fSDarrick J. Wong 
455a412ae3fSDarrick J. Wong exit_free:
456a412ae3fSDarrick J. Wong 	kfree(data);
457a412ae3fSDarrick J. Wong exit:
458a412ae3fSDarrick J. Wong 	return err;
459a412ae3fSDarrick J. Wong }
460a412ae3fSDarrick J. Wong 
ics932s401_remove(struct i2c_client * client)461ed5c2f5fSUwe Kleine-König static void ics932s401_remove(struct i2c_client *client)
462a412ae3fSDarrick J. Wong {
463a412ae3fSDarrick J. Wong 	struct ics932s401_data *data = i2c_get_clientdata(client);
464a412ae3fSDarrick J. Wong 
465a412ae3fSDarrick J. Wong 	sysfs_remove_group(&client->dev.kobj, &data->attrs);
466a412ae3fSDarrick J. Wong 	kfree(data);
467a412ae3fSDarrick J. Wong }
468a412ae3fSDarrick J. Wong 
469a64fe2edSAxel Lin module_i2c_driver(ics932s401_driver);
470a412ae3fSDarrick J. Wong 
4715407e051SDarrick J. Wong MODULE_AUTHOR("Darrick J. Wong <darrick.wong@oracle.com>");
472a412ae3fSDarrick J. Wong MODULE_DESCRIPTION("ICS932S401 driver");
473a412ae3fSDarrick J. Wong MODULE_LICENSE("GPL");
474a412ae3fSDarrick J. Wong 
475a412ae3fSDarrick J. Wong /* IBM IntelliStation Z30 */
476a412ae3fSDarrick J. Wong MODULE_ALIAS("dmi:bvnIBM:*:rn9228:*");
477a412ae3fSDarrick J. Wong MODULE_ALIAS("dmi:bvnIBM:*:rn9232:*");
478a412ae3fSDarrick J. Wong 
479a412ae3fSDarrick J. Wong /* IBM x3650/x3550 */
480a412ae3fSDarrick J. Wong MODULE_ALIAS("dmi:bvnIBM:*:pnIBMSystemx3650*");
481a412ae3fSDarrick J. Wong MODULE_ALIAS("dmi:bvnIBM:*:pnIBMSystemx3550*");
482