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