18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * A driver for the Integrated Circuits ICS932S401
48c2ecf20Sopenharmony_ci * Copyright (C) 2008 IBM
58c2ecf20Sopenharmony_ci *
68c2ecf20Sopenharmony_ci * Author: Darrick J. Wong <darrick.wong@oracle.com>
78c2ecf20Sopenharmony_ci */
88c2ecf20Sopenharmony_ci
98c2ecf20Sopenharmony_ci#include <linux/module.h>
108c2ecf20Sopenharmony_ci#include <linux/jiffies.h>
118c2ecf20Sopenharmony_ci#include <linux/i2c.h>
128c2ecf20Sopenharmony_ci#include <linux/err.h>
138c2ecf20Sopenharmony_ci#include <linux/mutex.h>
148c2ecf20Sopenharmony_ci#include <linux/delay.h>
158c2ecf20Sopenharmony_ci#include <linux/log2.h>
168c2ecf20Sopenharmony_ci#include <linux/slab.h>
178c2ecf20Sopenharmony_ci
188c2ecf20Sopenharmony_ci/* Addresses to scan */
198c2ecf20Sopenharmony_cistatic const unsigned short normal_i2c[] = { 0x69, I2C_CLIENT_END };
208c2ecf20Sopenharmony_ci
218c2ecf20Sopenharmony_ci/* ICS932S401 registers */
228c2ecf20Sopenharmony_ci#define ICS932S401_REG_CFG2			0x01
238c2ecf20Sopenharmony_ci#define		ICS932S401_CFG1_SPREAD		0x01
248c2ecf20Sopenharmony_ci#define ICS932S401_REG_CFG7			0x06
258c2ecf20Sopenharmony_ci#define		ICS932S401_FS_MASK		0x07
268c2ecf20Sopenharmony_ci#define	ICS932S401_REG_VENDOR_REV		0x07
278c2ecf20Sopenharmony_ci#define		ICS932S401_VENDOR		1
288c2ecf20Sopenharmony_ci#define		ICS932S401_VENDOR_MASK		0x0F
298c2ecf20Sopenharmony_ci#define		ICS932S401_REV			4
308c2ecf20Sopenharmony_ci#define		ICS932S401_REV_SHIFT		4
318c2ecf20Sopenharmony_ci#define ICS932S401_REG_DEVICE			0x09
328c2ecf20Sopenharmony_ci#define		ICS932S401_DEVICE		11
338c2ecf20Sopenharmony_ci#define	ICS932S401_REG_CTRL			0x0A
348c2ecf20Sopenharmony_ci#define		ICS932S401_MN_ENABLED		0x80
358c2ecf20Sopenharmony_ci#define		ICS932S401_CPU_ALT		0x04
368c2ecf20Sopenharmony_ci#define		ICS932S401_SRC_ALT		0x08
378c2ecf20Sopenharmony_ci#define ICS932S401_REG_CPU_M_CTRL		0x0B
388c2ecf20Sopenharmony_ci#define		ICS932S401_M_MASK		0x3F
398c2ecf20Sopenharmony_ci#define	ICS932S401_REG_CPU_N_CTRL		0x0C
408c2ecf20Sopenharmony_ci#define	ICS932S401_REG_CPU_SPREAD1		0x0D
418c2ecf20Sopenharmony_ci#define ICS932S401_REG_CPU_SPREAD2		0x0E
428c2ecf20Sopenharmony_ci#define		ICS932S401_SPREAD_MASK		0x7FFF
438c2ecf20Sopenharmony_ci#define ICS932S401_REG_SRC_M_CTRL		0x0F
448c2ecf20Sopenharmony_ci#define ICS932S401_REG_SRC_N_CTRL		0x10
458c2ecf20Sopenharmony_ci#define	ICS932S401_REG_SRC_SPREAD1		0x11
468c2ecf20Sopenharmony_ci#define ICS932S401_REG_SRC_SPREAD2		0x12
478c2ecf20Sopenharmony_ci#define ICS932S401_REG_CPU_DIVISOR		0x13
488c2ecf20Sopenharmony_ci#define		ICS932S401_CPU_DIVISOR_SHIFT	4
498c2ecf20Sopenharmony_ci#define ICS932S401_REG_PCISRC_DIVISOR		0x14
508c2ecf20Sopenharmony_ci#define		ICS932S401_SRC_DIVISOR_MASK	0x0F
518c2ecf20Sopenharmony_ci#define		ICS932S401_PCI_DIVISOR_SHIFT	4
528c2ecf20Sopenharmony_ci
538c2ecf20Sopenharmony_ci/* Base clock is 14.318MHz */
548c2ecf20Sopenharmony_ci#define BASE_CLOCK				14318
558c2ecf20Sopenharmony_ci
568c2ecf20Sopenharmony_ci#define NUM_REGS				21
578c2ecf20Sopenharmony_ci#define NUM_MIRRORED_REGS			15
588c2ecf20Sopenharmony_ci
598c2ecf20Sopenharmony_cistatic int regs_to_copy[NUM_MIRRORED_REGS] = {
608c2ecf20Sopenharmony_ci	ICS932S401_REG_CFG2,
618c2ecf20Sopenharmony_ci	ICS932S401_REG_CFG7,
628c2ecf20Sopenharmony_ci	ICS932S401_REG_VENDOR_REV,
638c2ecf20Sopenharmony_ci	ICS932S401_REG_DEVICE,
648c2ecf20Sopenharmony_ci	ICS932S401_REG_CTRL,
658c2ecf20Sopenharmony_ci	ICS932S401_REG_CPU_M_CTRL,
668c2ecf20Sopenharmony_ci	ICS932S401_REG_CPU_N_CTRL,
678c2ecf20Sopenharmony_ci	ICS932S401_REG_CPU_SPREAD1,
688c2ecf20Sopenharmony_ci	ICS932S401_REG_CPU_SPREAD2,
698c2ecf20Sopenharmony_ci	ICS932S401_REG_SRC_M_CTRL,
708c2ecf20Sopenharmony_ci	ICS932S401_REG_SRC_N_CTRL,
718c2ecf20Sopenharmony_ci	ICS932S401_REG_SRC_SPREAD1,
728c2ecf20Sopenharmony_ci	ICS932S401_REG_SRC_SPREAD2,
738c2ecf20Sopenharmony_ci	ICS932S401_REG_CPU_DIVISOR,
748c2ecf20Sopenharmony_ci	ICS932S401_REG_PCISRC_DIVISOR,
758c2ecf20Sopenharmony_ci};
768c2ecf20Sopenharmony_ci
778c2ecf20Sopenharmony_ci/* How often do we reread sensors values? (In jiffies) */
788c2ecf20Sopenharmony_ci#define SENSOR_REFRESH_INTERVAL	(2 * HZ)
798c2ecf20Sopenharmony_ci
808c2ecf20Sopenharmony_ci/* How often do we reread sensor limit values? (In jiffies) */
818c2ecf20Sopenharmony_ci#define LIMIT_REFRESH_INTERVAL	(60 * HZ)
828c2ecf20Sopenharmony_ci
838c2ecf20Sopenharmony_cistruct ics932s401_data {
848c2ecf20Sopenharmony_ci	struct attribute_group	attrs;
858c2ecf20Sopenharmony_ci	struct mutex		lock;
868c2ecf20Sopenharmony_ci	char			sensors_valid;
878c2ecf20Sopenharmony_ci	unsigned long		sensors_last_updated;	/* In jiffies */
888c2ecf20Sopenharmony_ci
898c2ecf20Sopenharmony_ci	u8			regs[NUM_REGS];
908c2ecf20Sopenharmony_ci};
918c2ecf20Sopenharmony_ci
928c2ecf20Sopenharmony_cistatic int ics932s401_probe(struct i2c_client *client,
938c2ecf20Sopenharmony_ci			 const struct i2c_device_id *id);
948c2ecf20Sopenharmony_cistatic int ics932s401_detect(struct i2c_client *client,
958c2ecf20Sopenharmony_ci			  struct i2c_board_info *info);
968c2ecf20Sopenharmony_cistatic int ics932s401_remove(struct i2c_client *client);
978c2ecf20Sopenharmony_ci
988c2ecf20Sopenharmony_cistatic const struct i2c_device_id ics932s401_id[] = {
998c2ecf20Sopenharmony_ci	{ "ics932s401", 0 },
1008c2ecf20Sopenharmony_ci	{ }
1018c2ecf20Sopenharmony_ci};
1028c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(i2c, ics932s401_id);
1038c2ecf20Sopenharmony_ci
1048c2ecf20Sopenharmony_cistatic struct i2c_driver ics932s401_driver = {
1058c2ecf20Sopenharmony_ci	.class		= I2C_CLASS_HWMON,
1068c2ecf20Sopenharmony_ci	.driver = {
1078c2ecf20Sopenharmony_ci		.name	= "ics932s401",
1088c2ecf20Sopenharmony_ci	},
1098c2ecf20Sopenharmony_ci	.probe		= ics932s401_probe,
1108c2ecf20Sopenharmony_ci	.remove		= ics932s401_remove,
1118c2ecf20Sopenharmony_ci	.id_table	= ics932s401_id,
1128c2ecf20Sopenharmony_ci	.detect		= ics932s401_detect,
1138c2ecf20Sopenharmony_ci	.address_list	= normal_i2c,
1148c2ecf20Sopenharmony_ci};
1158c2ecf20Sopenharmony_ci
1168c2ecf20Sopenharmony_cistatic struct ics932s401_data *ics932s401_update_device(struct device *dev)
1178c2ecf20Sopenharmony_ci{
1188c2ecf20Sopenharmony_ci	struct i2c_client *client = to_i2c_client(dev);
1198c2ecf20Sopenharmony_ci	struct ics932s401_data *data = i2c_get_clientdata(client);
1208c2ecf20Sopenharmony_ci	unsigned long local_jiffies = jiffies;
1218c2ecf20Sopenharmony_ci	int i, temp;
1228c2ecf20Sopenharmony_ci
1238c2ecf20Sopenharmony_ci	mutex_lock(&data->lock);
1248c2ecf20Sopenharmony_ci	if (time_before(local_jiffies, data->sensors_last_updated +
1258c2ecf20Sopenharmony_ci		SENSOR_REFRESH_INTERVAL)
1268c2ecf20Sopenharmony_ci		&& data->sensors_valid)
1278c2ecf20Sopenharmony_ci		goto out;
1288c2ecf20Sopenharmony_ci
1298c2ecf20Sopenharmony_ci	/*
1308c2ecf20Sopenharmony_ci	 * Each register must be read as a word and then right shifted 8 bits.
1318c2ecf20Sopenharmony_ci	 * Not really sure why this is; setting the "byte count programming"
1328c2ecf20Sopenharmony_ci	 * register to 1 does not fix this problem.
1338c2ecf20Sopenharmony_ci	 */
1348c2ecf20Sopenharmony_ci	for (i = 0; i < NUM_MIRRORED_REGS; i++) {
1358c2ecf20Sopenharmony_ci		temp = i2c_smbus_read_word_data(client, regs_to_copy[i]);
1368c2ecf20Sopenharmony_ci		if (temp < 0)
1378c2ecf20Sopenharmony_ci			temp = 0;
1388c2ecf20Sopenharmony_ci		data->regs[regs_to_copy[i]] = temp >> 8;
1398c2ecf20Sopenharmony_ci	}
1408c2ecf20Sopenharmony_ci
1418c2ecf20Sopenharmony_ci	data->sensors_last_updated = local_jiffies;
1428c2ecf20Sopenharmony_ci	data->sensors_valid = 1;
1438c2ecf20Sopenharmony_ci
1448c2ecf20Sopenharmony_ciout:
1458c2ecf20Sopenharmony_ci	mutex_unlock(&data->lock);
1468c2ecf20Sopenharmony_ci	return data;
1478c2ecf20Sopenharmony_ci}
1488c2ecf20Sopenharmony_ci
1498c2ecf20Sopenharmony_cistatic ssize_t show_spread_enabled(struct device *dev,
1508c2ecf20Sopenharmony_ci				   struct device_attribute *devattr,
1518c2ecf20Sopenharmony_ci				   char *buf)
1528c2ecf20Sopenharmony_ci{
1538c2ecf20Sopenharmony_ci	struct ics932s401_data *data = ics932s401_update_device(dev);
1548c2ecf20Sopenharmony_ci
1558c2ecf20Sopenharmony_ci	if (data->regs[ICS932S401_REG_CFG2] & ICS932S401_CFG1_SPREAD)
1568c2ecf20Sopenharmony_ci		return sprintf(buf, "1\n");
1578c2ecf20Sopenharmony_ci
1588c2ecf20Sopenharmony_ci	return sprintf(buf, "0\n");
1598c2ecf20Sopenharmony_ci}
1608c2ecf20Sopenharmony_ci
1618c2ecf20Sopenharmony_ci/* bit to cpu khz map */
1628c2ecf20Sopenharmony_cistatic const int fs_speeds[] = {
1638c2ecf20Sopenharmony_ci	266666,
1648c2ecf20Sopenharmony_ci	133333,
1658c2ecf20Sopenharmony_ci	200000,
1668c2ecf20Sopenharmony_ci	166666,
1678c2ecf20Sopenharmony_ci	333333,
1688c2ecf20Sopenharmony_ci	100000,
1698c2ecf20Sopenharmony_ci	400000,
1708c2ecf20Sopenharmony_ci	0,
1718c2ecf20Sopenharmony_ci};
1728c2ecf20Sopenharmony_ci
1738c2ecf20Sopenharmony_ci/* clock divisor map */
1748c2ecf20Sopenharmony_cistatic const int divisors[] = {2, 3, 5, 15, 4, 6, 10, 30, 8, 12, 20, 60, 16,
1758c2ecf20Sopenharmony_ci			       24, 40, 120};
1768c2ecf20Sopenharmony_ci
1778c2ecf20Sopenharmony_ci/* Calculate CPU frequency from the M/N registers. */
1788c2ecf20Sopenharmony_cistatic int calculate_cpu_freq(struct ics932s401_data *data)
1798c2ecf20Sopenharmony_ci{
1808c2ecf20Sopenharmony_ci	int m, n, freq;
1818c2ecf20Sopenharmony_ci
1828c2ecf20Sopenharmony_ci	m = data->regs[ICS932S401_REG_CPU_M_CTRL] & ICS932S401_M_MASK;
1838c2ecf20Sopenharmony_ci	n = data->regs[ICS932S401_REG_CPU_N_CTRL];
1848c2ecf20Sopenharmony_ci
1858c2ecf20Sopenharmony_ci	/* Pull in bits 8 & 9 from the M register */
1868c2ecf20Sopenharmony_ci	n |= ((int)data->regs[ICS932S401_REG_CPU_M_CTRL] & 0x80) << 1;
1878c2ecf20Sopenharmony_ci	n |= ((int)data->regs[ICS932S401_REG_CPU_M_CTRL] & 0x40) << 3;
1888c2ecf20Sopenharmony_ci
1898c2ecf20Sopenharmony_ci	freq = BASE_CLOCK * (n + 8) / (m + 2);
1908c2ecf20Sopenharmony_ci	freq /= divisors[data->regs[ICS932S401_REG_CPU_DIVISOR] >>
1918c2ecf20Sopenharmony_ci			 ICS932S401_CPU_DIVISOR_SHIFT];
1928c2ecf20Sopenharmony_ci
1938c2ecf20Sopenharmony_ci	return freq;
1948c2ecf20Sopenharmony_ci}
1958c2ecf20Sopenharmony_ci
1968c2ecf20Sopenharmony_cistatic ssize_t show_cpu_clock(struct device *dev,
1978c2ecf20Sopenharmony_ci			      struct device_attribute *devattr,
1988c2ecf20Sopenharmony_ci			      char *buf)
1998c2ecf20Sopenharmony_ci{
2008c2ecf20Sopenharmony_ci	struct ics932s401_data *data = ics932s401_update_device(dev);
2018c2ecf20Sopenharmony_ci
2028c2ecf20Sopenharmony_ci	return sprintf(buf, "%d\n", calculate_cpu_freq(data));
2038c2ecf20Sopenharmony_ci}
2048c2ecf20Sopenharmony_ci
2058c2ecf20Sopenharmony_cistatic ssize_t show_cpu_clock_sel(struct device *dev,
2068c2ecf20Sopenharmony_ci				  struct device_attribute *devattr,
2078c2ecf20Sopenharmony_ci				  char *buf)
2088c2ecf20Sopenharmony_ci{
2098c2ecf20Sopenharmony_ci	struct ics932s401_data *data = ics932s401_update_device(dev);
2108c2ecf20Sopenharmony_ci	int freq;
2118c2ecf20Sopenharmony_ci
2128c2ecf20Sopenharmony_ci	if (data->regs[ICS932S401_REG_CTRL] & ICS932S401_MN_ENABLED)
2138c2ecf20Sopenharmony_ci		freq = calculate_cpu_freq(data);
2148c2ecf20Sopenharmony_ci	else {
2158c2ecf20Sopenharmony_ci		/* Freq is neatly wrapped up for us */
2168c2ecf20Sopenharmony_ci		int fid = data->regs[ICS932S401_REG_CFG7] & ICS932S401_FS_MASK;
2178c2ecf20Sopenharmony_ci
2188c2ecf20Sopenharmony_ci		freq = fs_speeds[fid];
2198c2ecf20Sopenharmony_ci		if (data->regs[ICS932S401_REG_CTRL] & ICS932S401_CPU_ALT) {
2208c2ecf20Sopenharmony_ci			switch (freq) {
2218c2ecf20Sopenharmony_ci			case 166666:
2228c2ecf20Sopenharmony_ci				freq = 160000;
2238c2ecf20Sopenharmony_ci				break;
2248c2ecf20Sopenharmony_ci			case 333333:
2258c2ecf20Sopenharmony_ci				freq = 320000;
2268c2ecf20Sopenharmony_ci				break;
2278c2ecf20Sopenharmony_ci			}
2288c2ecf20Sopenharmony_ci		}
2298c2ecf20Sopenharmony_ci	}
2308c2ecf20Sopenharmony_ci
2318c2ecf20Sopenharmony_ci	return sprintf(buf, "%d\n", freq);
2328c2ecf20Sopenharmony_ci}
2338c2ecf20Sopenharmony_ci
2348c2ecf20Sopenharmony_ci/* Calculate SRC frequency from the M/N registers. */
2358c2ecf20Sopenharmony_cistatic int calculate_src_freq(struct ics932s401_data *data)
2368c2ecf20Sopenharmony_ci{
2378c2ecf20Sopenharmony_ci	int m, n, freq;
2388c2ecf20Sopenharmony_ci
2398c2ecf20Sopenharmony_ci	m = data->regs[ICS932S401_REG_SRC_M_CTRL] & ICS932S401_M_MASK;
2408c2ecf20Sopenharmony_ci	n = data->regs[ICS932S401_REG_SRC_N_CTRL];
2418c2ecf20Sopenharmony_ci
2428c2ecf20Sopenharmony_ci	/* Pull in bits 8 & 9 from the M register */
2438c2ecf20Sopenharmony_ci	n |= ((int)data->regs[ICS932S401_REG_SRC_M_CTRL] & 0x80) << 1;
2448c2ecf20Sopenharmony_ci	n |= ((int)data->regs[ICS932S401_REG_SRC_M_CTRL] & 0x40) << 3;
2458c2ecf20Sopenharmony_ci
2468c2ecf20Sopenharmony_ci	freq = BASE_CLOCK * (n + 8) / (m + 2);
2478c2ecf20Sopenharmony_ci	freq /= divisors[data->regs[ICS932S401_REG_PCISRC_DIVISOR] &
2488c2ecf20Sopenharmony_ci			 ICS932S401_SRC_DIVISOR_MASK];
2498c2ecf20Sopenharmony_ci
2508c2ecf20Sopenharmony_ci	return freq;
2518c2ecf20Sopenharmony_ci}
2528c2ecf20Sopenharmony_ci
2538c2ecf20Sopenharmony_cistatic ssize_t show_src_clock(struct device *dev,
2548c2ecf20Sopenharmony_ci			      struct device_attribute *devattr,
2558c2ecf20Sopenharmony_ci			      char *buf)
2568c2ecf20Sopenharmony_ci{
2578c2ecf20Sopenharmony_ci	struct ics932s401_data *data = ics932s401_update_device(dev);
2588c2ecf20Sopenharmony_ci
2598c2ecf20Sopenharmony_ci	return sprintf(buf, "%d\n", calculate_src_freq(data));
2608c2ecf20Sopenharmony_ci}
2618c2ecf20Sopenharmony_ci
2628c2ecf20Sopenharmony_cistatic ssize_t show_src_clock_sel(struct device *dev,
2638c2ecf20Sopenharmony_ci				  struct device_attribute *devattr,
2648c2ecf20Sopenharmony_ci				  char *buf)
2658c2ecf20Sopenharmony_ci{
2668c2ecf20Sopenharmony_ci	struct ics932s401_data *data = ics932s401_update_device(dev);
2678c2ecf20Sopenharmony_ci	int freq;
2688c2ecf20Sopenharmony_ci
2698c2ecf20Sopenharmony_ci	if (data->regs[ICS932S401_REG_CTRL] & ICS932S401_MN_ENABLED)
2708c2ecf20Sopenharmony_ci		freq = calculate_src_freq(data);
2718c2ecf20Sopenharmony_ci	else
2728c2ecf20Sopenharmony_ci		/* Freq is neatly wrapped up for us */
2738c2ecf20Sopenharmony_ci		if (data->regs[ICS932S401_REG_CTRL] & ICS932S401_CPU_ALT &&
2748c2ecf20Sopenharmony_ci		    data->regs[ICS932S401_REG_CTRL] & ICS932S401_SRC_ALT)
2758c2ecf20Sopenharmony_ci			freq = 96000;
2768c2ecf20Sopenharmony_ci		else
2778c2ecf20Sopenharmony_ci			freq = 100000;
2788c2ecf20Sopenharmony_ci
2798c2ecf20Sopenharmony_ci	return sprintf(buf, "%d\n", freq);
2808c2ecf20Sopenharmony_ci}
2818c2ecf20Sopenharmony_ci
2828c2ecf20Sopenharmony_ci/* Calculate PCI frequency from the SRC M/N registers. */
2838c2ecf20Sopenharmony_cistatic int calculate_pci_freq(struct ics932s401_data *data)
2848c2ecf20Sopenharmony_ci{
2858c2ecf20Sopenharmony_ci	int m, n, freq;
2868c2ecf20Sopenharmony_ci
2878c2ecf20Sopenharmony_ci	m = data->regs[ICS932S401_REG_SRC_M_CTRL] & ICS932S401_M_MASK;
2888c2ecf20Sopenharmony_ci	n = data->regs[ICS932S401_REG_SRC_N_CTRL];
2898c2ecf20Sopenharmony_ci
2908c2ecf20Sopenharmony_ci	/* Pull in bits 8 & 9 from the M register */
2918c2ecf20Sopenharmony_ci	n |= ((int)data->regs[ICS932S401_REG_SRC_M_CTRL] & 0x80) << 1;
2928c2ecf20Sopenharmony_ci	n |= ((int)data->regs[ICS932S401_REG_SRC_M_CTRL] & 0x40) << 3;
2938c2ecf20Sopenharmony_ci
2948c2ecf20Sopenharmony_ci	freq = BASE_CLOCK * (n + 8) / (m + 2);
2958c2ecf20Sopenharmony_ci	freq /= divisors[data->regs[ICS932S401_REG_PCISRC_DIVISOR] >>
2968c2ecf20Sopenharmony_ci			 ICS932S401_PCI_DIVISOR_SHIFT];
2978c2ecf20Sopenharmony_ci
2988c2ecf20Sopenharmony_ci	return freq;
2998c2ecf20Sopenharmony_ci}
3008c2ecf20Sopenharmony_ci
3018c2ecf20Sopenharmony_cistatic ssize_t show_pci_clock(struct device *dev,
3028c2ecf20Sopenharmony_ci			      struct device_attribute *devattr,
3038c2ecf20Sopenharmony_ci			      char *buf)
3048c2ecf20Sopenharmony_ci{
3058c2ecf20Sopenharmony_ci	struct ics932s401_data *data = ics932s401_update_device(dev);
3068c2ecf20Sopenharmony_ci
3078c2ecf20Sopenharmony_ci	return sprintf(buf, "%d\n", calculate_pci_freq(data));
3088c2ecf20Sopenharmony_ci}
3098c2ecf20Sopenharmony_ci
3108c2ecf20Sopenharmony_cistatic ssize_t show_pci_clock_sel(struct device *dev,
3118c2ecf20Sopenharmony_ci				  struct device_attribute *devattr,
3128c2ecf20Sopenharmony_ci				  char *buf)
3138c2ecf20Sopenharmony_ci{
3148c2ecf20Sopenharmony_ci	struct ics932s401_data *data = ics932s401_update_device(dev);
3158c2ecf20Sopenharmony_ci	int freq;
3168c2ecf20Sopenharmony_ci
3178c2ecf20Sopenharmony_ci	if (data->regs[ICS932S401_REG_CTRL] & ICS932S401_MN_ENABLED)
3188c2ecf20Sopenharmony_ci		freq = calculate_pci_freq(data);
3198c2ecf20Sopenharmony_ci	else
3208c2ecf20Sopenharmony_ci		freq = 33333;
3218c2ecf20Sopenharmony_ci
3228c2ecf20Sopenharmony_ci	return sprintf(buf, "%d\n", freq);
3238c2ecf20Sopenharmony_ci}
3248c2ecf20Sopenharmony_ci
3258c2ecf20Sopenharmony_cistatic ssize_t show_value(struct device *dev,
3268c2ecf20Sopenharmony_ci			  struct device_attribute *devattr,
3278c2ecf20Sopenharmony_ci			  char *buf);
3288c2ecf20Sopenharmony_ci
3298c2ecf20Sopenharmony_cistatic ssize_t show_spread(struct device *dev,
3308c2ecf20Sopenharmony_ci			   struct device_attribute *devattr,
3318c2ecf20Sopenharmony_ci			   char *buf);
3328c2ecf20Sopenharmony_ci
3338c2ecf20Sopenharmony_cistatic DEVICE_ATTR(spread_enabled, S_IRUGO, show_spread_enabled, NULL);
3348c2ecf20Sopenharmony_cistatic DEVICE_ATTR(cpu_clock_selection, S_IRUGO, show_cpu_clock_sel, NULL);
3358c2ecf20Sopenharmony_cistatic DEVICE_ATTR(cpu_clock, S_IRUGO, show_cpu_clock, NULL);
3368c2ecf20Sopenharmony_cistatic DEVICE_ATTR(src_clock_selection, S_IRUGO, show_src_clock_sel, NULL);
3378c2ecf20Sopenharmony_cistatic DEVICE_ATTR(src_clock, S_IRUGO, show_src_clock, NULL);
3388c2ecf20Sopenharmony_cistatic DEVICE_ATTR(pci_clock_selection, S_IRUGO, show_pci_clock_sel, NULL);
3398c2ecf20Sopenharmony_cistatic DEVICE_ATTR(pci_clock, S_IRUGO, show_pci_clock, NULL);
3408c2ecf20Sopenharmony_cistatic DEVICE_ATTR(usb_clock, S_IRUGO, show_value, NULL);
3418c2ecf20Sopenharmony_cistatic DEVICE_ATTR(ref_clock, S_IRUGO, show_value, NULL);
3428c2ecf20Sopenharmony_cistatic DEVICE_ATTR(cpu_spread, S_IRUGO, show_spread, NULL);
3438c2ecf20Sopenharmony_cistatic DEVICE_ATTR(src_spread, S_IRUGO, show_spread, NULL);
3448c2ecf20Sopenharmony_ci
3458c2ecf20Sopenharmony_cistatic struct attribute *ics932s401_attr[] = {
3468c2ecf20Sopenharmony_ci	&dev_attr_spread_enabled.attr,
3478c2ecf20Sopenharmony_ci	&dev_attr_cpu_clock_selection.attr,
3488c2ecf20Sopenharmony_ci	&dev_attr_cpu_clock.attr,
3498c2ecf20Sopenharmony_ci	&dev_attr_src_clock_selection.attr,
3508c2ecf20Sopenharmony_ci	&dev_attr_src_clock.attr,
3518c2ecf20Sopenharmony_ci	&dev_attr_pci_clock_selection.attr,
3528c2ecf20Sopenharmony_ci	&dev_attr_pci_clock.attr,
3538c2ecf20Sopenharmony_ci	&dev_attr_usb_clock.attr,
3548c2ecf20Sopenharmony_ci	&dev_attr_ref_clock.attr,
3558c2ecf20Sopenharmony_ci	&dev_attr_cpu_spread.attr,
3568c2ecf20Sopenharmony_ci	&dev_attr_src_spread.attr,
3578c2ecf20Sopenharmony_ci	NULL
3588c2ecf20Sopenharmony_ci};
3598c2ecf20Sopenharmony_ci
3608c2ecf20Sopenharmony_cistatic ssize_t show_value(struct device *dev,
3618c2ecf20Sopenharmony_ci			  struct device_attribute *devattr,
3628c2ecf20Sopenharmony_ci			  char *buf)
3638c2ecf20Sopenharmony_ci{
3648c2ecf20Sopenharmony_ci	int x;
3658c2ecf20Sopenharmony_ci
3668c2ecf20Sopenharmony_ci	if (devattr == &dev_attr_usb_clock)
3678c2ecf20Sopenharmony_ci		x = 48000;
3688c2ecf20Sopenharmony_ci	else if (devattr == &dev_attr_ref_clock)
3698c2ecf20Sopenharmony_ci		x = BASE_CLOCK;
3708c2ecf20Sopenharmony_ci	else
3718c2ecf20Sopenharmony_ci		BUG();
3728c2ecf20Sopenharmony_ci
3738c2ecf20Sopenharmony_ci	return sprintf(buf, "%d\n", x);
3748c2ecf20Sopenharmony_ci}
3758c2ecf20Sopenharmony_ci
3768c2ecf20Sopenharmony_cistatic ssize_t show_spread(struct device *dev,
3778c2ecf20Sopenharmony_ci			   struct device_attribute *devattr,
3788c2ecf20Sopenharmony_ci			   char *buf)
3798c2ecf20Sopenharmony_ci{
3808c2ecf20Sopenharmony_ci	struct ics932s401_data *data = ics932s401_update_device(dev);
3818c2ecf20Sopenharmony_ci	int reg;
3828c2ecf20Sopenharmony_ci	unsigned long val;
3838c2ecf20Sopenharmony_ci
3848c2ecf20Sopenharmony_ci	if (!(data->regs[ICS932S401_REG_CFG2] & ICS932S401_CFG1_SPREAD))
3858c2ecf20Sopenharmony_ci		return sprintf(buf, "0%%\n");
3868c2ecf20Sopenharmony_ci
3878c2ecf20Sopenharmony_ci	if (devattr == &dev_attr_src_spread)
3888c2ecf20Sopenharmony_ci		reg = ICS932S401_REG_SRC_SPREAD1;
3898c2ecf20Sopenharmony_ci	else if (devattr == &dev_attr_cpu_spread)
3908c2ecf20Sopenharmony_ci		reg = ICS932S401_REG_CPU_SPREAD1;
3918c2ecf20Sopenharmony_ci	else
3928c2ecf20Sopenharmony_ci		BUG();
3938c2ecf20Sopenharmony_ci
3948c2ecf20Sopenharmony_ci	val = data->regs[reg] | (data->regs[reg + 1] << 8);
3958c2ecf20Sopenharmony_ci	val &= ICS932S401_SPREAD_MASK;
3968c2ecf20Sopenharmony_ci
3978c2ecf20Sopenharmony_ci	/* Scale 0..2^14 to -0.5. */
3988c2ecf20Sopenharmony_ci	val = 500000 * val / 16384;
3998c2ecf20Sopenharmony_ci	return sprintf(buf, "-0.%lu%%\n", val);
4008c2ecf20Sopenharmony_ci}
4018c2ecf20Sopenharmony_ci
4028c2ecf20Sopenharmony_ci/* Return 0 if detection is successful, -ENODEV otherwise */
4038c2ecf20Sopenharmony_cistatic int ics932s401_detect(struct i2c_client *client,
4048c2ecf20Sopenharmony_ci			  struct i2c_board_info *info)
4058c2ecf20Sopenharmony_ci{
4068c2ecf20Sopenharmony_ci	struct i2c_adapter *adapter = client->adapter;
4078c2ecf20Sopenharmony_ci	int vendor, device, revision;
4088c2ecf20Sopenharmony_ci
4098c2ecf20Sopenharmony_ci	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
4108c2ecf20Sopenharmony_ci		return -ENODEV;
4118c2ecf20Sopenharmony_ci
4128c2ecf20Sopenharmony_ci	vendor = i2c_smbus_read_word_data(client, ICS932S401_REG_VENDOR_REV);
4138c2ecf20Sopenharmony_ci	vendor >>= 8;
4148c2ecf20Sopenharmony_ci	revision = vendor >> ICS932S401_REV_SHIFT;
4158c2ecf20Sopenharmony_ci	vendor &= ICS932S401_VENDOR_MASK;
4168c2ecf20Sopenharmony_ci	if (vendor != ICS932S401_VENDOR)
4178c2ecf20Sopenharmony_ci		return -ENODEV;
4188c2ecf20Sopenharmony_ci
4198c2ecf20Sopenharmony_ci	device = i2c_smbus_read_word_data(client, ICS932S401_REG_DEVICE);
4208c2ecf20Sopenharmony_ci	device >>= 8;
4218c2ecf20Sopenharmony_ci	if (device != ICS932S401_DEVICE)
4228c2ecf20Sopenharmony_ci		return -ENODEV;
4238c2ecf20Sopenharmony_ci
4248c2ecf20Sopenharmony_ci	if (revision != ICS932S401_REV)
4258c2ecf20Sopenharmony_ci		dev_info(&adapter->dev, "Unknown revision %d\n", revision);
4268c2ecf20Sopenharmony_ci
4278c2ecf20Sopenharmony_ci	strlcpy(info->type, "ics932s401", I2C_NAME_SIZE);
4288c2ecf20Sopenharmony_ci
4298c2ecf20Sopenharmony_ci	return 0;
4308c2ecf20Sopenharmony_ci}
4318c2ecf20Sopenharmony_ci
4328c2ecf20Sopenharmony_cistatic int ics932s401_probe(struct i2c_client *client,
4338c2ecf20Sopenharmony_ci			 const struct i2c_device_id *id)
4348c2ecf20Sopenharmony_ci{
4358c2ecf20Sopenharmony_ci	struct ics932s401_data *data;
4368c2ecf20Sopenharmony_ci	int err;
4378c2ecf20Sopenharmony_ci
4388c2ecf20Sopenharmony_ci	data = kzalloc(sizeof(struct ics932s401_data), GFP_KERNEL);
4398c2ecf20Sopenharmony_ci	if (!data) {
4408c2ecf20Sopenharmony_ci		err = -ENOMEM;
4418c2ecf20Sopenharmony_ci		goto exit;
4428c2ecf20Sopenharmony_ci	}
4438c2ecf20Sopenharmony_ci
4448c2ecf20Sopenharmony_ci	i2c_set_clientdata(client, data);
4458c2ecf20Sopenharmony_ci	mutex_init(&data->lock);
4468c2ecf20Sopenharmony_ci
4478c2ecf20Sopenharmony_ci	dev_info(&client->dev, "%s chip found\n", client->name);
4488c2ecf20Sopenharmony_ci
4498c2ecf20Sopenharmony_ci	/* Register sysfs hooks */
4508c2ecf20Sopenharmony_ci	data->attrs.attrs = ics932s401_attr;
4518c2ecf20Sopenharmony_ci	err = sysfs_create_group(&client->dev.kobj, &data->attrs);
4528c2ecf20Sopenharmony_ci	if (err)
4538c2ecf20Sopenharmony_ci		goto exit_free;
4548c2ecf20Sopenharmony_ci
4558c2ecf20Sopenharmony_ci	return 0;
4568c2ecf20Sopenharmony_ci
4578c2ecf20Sopenharmony_ciexit_free:
4588c2ecf20Sopenharmony_ci	kfree(data);
4598c2ecf20Sopenharmony_ciexit:
4608c2ecf20Sopenharmony_ci	return err;
4618c2ecf20Sopenharmony_ci}
4628c2ecf20Sopenharmony_ci
4638c2ecf20Sopenharmony_cistatic int ics932s401_remove(struct i2c_client *client)
4648c2ecf20Sopenharmony_ci{
4658c2ecf20Sopenharmony_ci	struct ics932s401_data *data = i2c_get_clientdata(client);
4668c2ecf20Sopenharmony_ci
4678c2ecf20Sopenharmony_ci	sysfs_remove_group(&client->dev.kobj, &data->attrs);
4688c2ecf20Sopenharmony_ci	kfree(data);
4698c2ecf20Sopenharmony_ci	return 0;
4708c2ecf20Sopenharmony_ci}
4718c2ecf20Sopenharmony_ci
4728c2ecf20Sopenharmony_cimodule_i2c_driver(ics932s401_driver);
4738c2ecf20Sopenharmony_ci
4748c2ecf20Sopenharmony_ciMODULE_AUTHOR("Darrick J. Wong <darrick.wong@oracle.com>");
4758c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("ICS932S401 driver");
4768c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL");
4778c2ecf20Sopenharmony_ci
4788c2ecf20Sopenharmony_ci/* IBM IntelliStation Z30 */
4798c2ecf20Sopenharmony_ciMODULE_ALIAS("dmi:bvnIBM:*:rn9228:*");
4808c2ecf20Sopenharmony_ciMODULE_ALIAS("dmi:bvnIBM:*:rn9232:*");
4818c2ecf20Sopenharmony_ci
4828c2ecf20Sopenharmony_ci/* IBM x3650/x3550 */
4838c2ecf20Sopenharmony_ciMODULE_ALIAS("dmi:bvnIBM:*:pnIBMSystemx3650*");
4848c2ecf20Sopenharmony_ciMODULE_ALIAS("dmi:bvnIBM:*:pnIBMSystemx3550*");
485