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