1c942fddfSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later 2aaf6fabfSChris Packham /* 3aaf6fabfSChris Packham * tc654.c - Linux kernel modules for fan speed controller 4aaf6fabfSChris Packham * 5aaf6fabfSChris Packham * Copyright (C) 2016 Allied Telesis Labs NZ 6aaf6fabfSChris Packham */ 7aaf6fabfSChris Packham 8aaf6fabfSChris Packham #include <linux/bitops.h> 9aaf6fabfSChris Packham #include <linux/err.h> 10aaf6fabfSChris Packham #include <linux/hwmon.h> 11aaf6fabfSChris Packham #include <linux/hwmon-sysfs.h> 12aaf6fabfSChris Packham #include <linux/i2c.h> 13aaf6fabfSChris Packham #include <linux/init.h> 14aaf6fabfSChris Packham #include <linux/jiffies.h> 15aaf6fabfSChris Packham #include <linux/module.h> 16aaf6fabfSChris Packham #include <linux/mutex.h> 17aaf6fabfSChris Packham #include <linux/slab.h> 1899cb5e9fSChristian Lamparter #include <linux/thermal.h> 19aaf6fabfSChris Packham #include <linux/util_macros.h> 20aaf6fabfSChris Packham 21aaf6fabfSChris Packham enum tc654_regs { 22aaf6fabfSChris Packham TC654_REG_RPM1 = 0x00, /* RPM Output 1 */ 23aaf6fabfSChris Packham TC654_REG_RPM2 = 0x01, /* RPM Output 2 */ 24aaf6fabfSChris Packham TC654_REG_FAN_FAULT1 = 0x02, /* Fan Fault 1 Threshold */ 25aaf6fabfSChris Packham TC654_REG_FAN_FAULT2 = 0x03, /* Fan Fault 2 Threshold */ 26aaf6fabfSChris Packham TC654_REG_CONFIG = 0x04, /* Configuration */ 27aaf6fabfSChris Packham TC654_REG_STATUS = 0x05, /* Status */ 28aaf6fabfSChris Packham TC654_REG_DUTY_CYCLE = 0x06, /* Fan Speed Duty Cycle */ 29aaf6fabfSChris Packham TC654_REG_MFR_ID = 0x07, /* Manufacturer Identification */ 30aaf6fabfSChris Packham TC654_REG_VER_ID = 0x08, /* Version Identification */ 31aaf6fabfSChris Packham }; 32aaf6fabfSChris Packham 33aaf6fabfSChris Packham /* Macros to easily index the registers */ 34aaf6fabfSChris Packham #define TC654_REG_RPM(idx) (TC654_REG_RPM1 + (idx)) 35aaf6fabfSChris Packham #define TC654_REG_FAN_FAULT(idx) (TC654_REG_FAN_FAULT1 + (idx)) 36aaf6fabfSChris Packham 37aaf6fabfSChris Packham /* Config register bits */ 38aaf6fabfSChris Packham #define TC654_REG_CONFIG_RES BIT(6) /* Resolution Selection */ 39aaf6fabfSChris Packham #define TC654_REG_CONFIG_DUTYC BIT(5) /* Duty Cycle Control */ 40aaf6fabfSChris Packham #define TC654_REG_CONFIG_SDM BIT(0) /* Shutdown Mode */ 41aaf6fabfSChris Packham 42aaf6fabfSChris Packham /* Status register bits */ 43aaf6fabfSChris Packham #define TC654_REG_STATUS_F2F BIT(1) /* Fan 2 Fault */ 44aaf6fabfSChris Packham #define TC654_REG_STATUS_F1F BIT(0) /* Fan 1 Fault */ 45aaf6fabfSChris Packham 46aaf6fabfSChris Packham /* RPM resolution for RPM Output registers */ 47aaf6fabfSChris Packham #define TC654_HIGH_RPM_RESOLUTION 25 /* 25 RPM resolution */ 48aaf6fabfSChris Packham #define TC654_LOW_RPM_RESOLUTION 50 /* 50 RPM resolution */ 49aaf6fabfSChris Packham 50aaf6fabfSChris Packham /* Convert to the fan fault RPM threshold from register value */ 51aaf6fabfSChris Packham #define TC654_FAN_FAULT_FROM_REG(val) ((val) * 50) /* 50 RPM resolution */ 52aaf6fabfSChris Packham 53aaf6fabfSChris Packham /* Convert to register value from the fan fault RPM threshold */ 54aaf6fabfSChris Packham #define TC654_FAN_FAULT_TO_REG(val) (((val) / 50) & 0xff) 55aaf6fabfSChris Packham 56aaf6fabfSChris Packham /* Register data is read (and cached) at most once per second. */ 57aaf6fabfSChris Packham #define TC654_UPDATE_INTERVAL HZ 58aaf6fabfSChris Packham 59aaf6fabfSChris Packham struct tc654_data { 60aaf6fabfSChris Packham struct i2c_client *client; 61aaf6fabfSChris Packham 62aaf6fabfSChris Packham /* update mutex */ 63aaf6fabfSChris Packham struct mutex update_lock; 64aaf6fabfSChris Packham 65aaf6fabfSChris Packham /* tc654 register cache */ 66aaf6fabfSChris Packham bool valid; 67aaf6fabfSChris Packham unsigned long last_updated; /* in jiffies */ 68aaf6fabfSChris Packham 69aaf6fabfSChris Packham u8 rpm_output[2]; /* The fan RPM data for fans 1 and 2 is then 70aaf6fabfSChris Packham * written to registers RPM1 and RPM2 71aaf6fabfSChris Packham */ 72aaf6fabfSChris Packham u8 fan_fault[2]; /* The Fan Fault Threshold Registers are used to 73aaf6fabfSChris Packham * set the fan fault threshold levels for fan 1 74aaf6fabfSChris Packham * and fan 2 75aaf6fabfSChris Packham */ 76aaf6fabfSChris Packham u8 config; /* The Configuration Register is an 8-bit read/ 77aaf6fabfSChris Packham * writable multi-function control register 78aaf6fabfSChris Packham * 7: Fan Fault Clear 79aaf6fabfSChris Packham * 1 = Clear Fan Fault 80aaf6fabfSChris Packham * 0 = Normal Operation (default) 81aaf6fabfSChris Packham * 6: Resolution Selection for RPM Output Registers 82aaf6fabfSChris Packham * RPM Output Registers (RPM1 and RPM2) will be 83aaf6fabfSChris Packham * set for 84aaf6fabfSChris Packham * 1 = 25 RPM (9-bit) resolution 85aaf6fabfSChris Packham * 0 = 50 RPM (8-bit) resolution (default) 86aaf6fabfSChris Packham * 5: Duty Cycle Control Method 87aaf6fabfSChris Packham * The V OUT duty cycle will be controlled via 88aaf6fabfSChris Packham * 1 = the SMBus interface. 89aaf6fabfSChris Packham * 0 = via the V IN analog input pin. (default) 90aaf6fabfSChris Packham * 4,3: Fan 2 Pulses Per Rotation 91aaf6fabfSChris Packham * 00 = 1 92aaf6fabfSChris Packham * 01 = 2 (default) 93aaf6fabfSChris Packham * 10 = 4 94aaf6fabfSChris Packham * 11 = 8 95aaf6fabfSChris Packham * 2,1: Fan 1 Pulses Per Rotation 96aaf6fabfSChris Packham * 00 = 1 97aaf6fabfSChris Packham * 01 = 2 (default) 98aaf6fabfSChris Packham * 10 = 4 99aaf6fabfSChris Packham * 11 = 8 100aaf6fabfSChris Packham * 0: Shutdown Mode 101aaf6fabfSChris Packham * 1 = Shutdown mode. 102aaf6fabfSChris Packham * 0 = Normal operation. (default) 103aaf6fabfSChris Packham */ 104aaf6fabfSChris Packham u8 status; /* The Status register provides all the information 105aaf6fabfSChris Packham * about what is going on within the TC654/TC655 106aaf6fabfSChris Packham * devices. 107aaf6fabfSChris Packham * 7,6: Unimplemented, Read as '0' 108aaf6fabfSChris Packham * 5: Over-Temperature Fault Condition 109aaf6fabfSChris Packham * 1 = Over-Temperature condition has occurred 110aaf6fabfSChris Packham * 0 = Normal operation. V IN is less than 2.6V 111aaf6fabfSChris Packham * 4: RPM2 Counter Overflow 112aaf6fabfSChris Packham * 1 = Fault condition 113aaf6fabfSChris Packham * 0 = Normal operation 114aaf6fabfSChris Packham * 3: RPM1 Counter Overflow 115aaf6fabfSChris Packham * 1 = Fault condition 116aaf6fabfSChris Packham * 0 = Normal operation 117aaf6fabfSChris Packham * 2: V IN Input Status 118aaf6fabfSChris Packham * 1 = V IN is open 119aaf6fabfSChris Packham * 0 = Normal operation. voltage present at V IN 120aaf6fabfSChris Packham * 1: Fan 2 Fault 121aaf6fabfSChris Packham * 1 = Fault condition 122aaf6fabfSChris Packham * 0 = Normal operation 123aaf6fabfSChris Packham * 0: Fan 1 Fault 124aaf6fabfSChris Packham * 1 = Fault condition 125aaf6fabfSChris Packham * 0 = Normal operation 126aaf6fabfSChris Packham */ 127aaf6fabfSChris Packham u8 duty_cycle; /* The DUTY_CYCLE register is a 4-bit read/ 128aaf6fabfSChris Packham * writable register used to control the duty 129aaf6fabfSChris Packham * cycle of the V OUT output. 130aaf6fabfSChris Packham */ 131aaf6fabfSChris Packham }; 132aaf6fabfSChris Packham 133aaf6fabfSChris Packham /* helper to grab and cache data, at most one time per second */ 134aaf6fabfSChris Packham static struct tc654_data *tc654_update_client(struct device *dev) 135aaf6fabfSChris Packham { 136aaf6fabfSChris Packham struct tc654_data *data = dev_get_drvdata(dev); 137aaf6fabfSChris Packham struct i2c_client *client = data->client; 138aaf6fabfSChris Packham int ret = 0; 139aaf6fabfSChris Packham 140aaf6fabfSChris Packham mutex_lock(&data->update_lock); 141aaf6fabfSChris Packham if (time_before(jiffies, data->last_updated + TC654_UPDATE_INTERVAL) && 142aaf6fabfSChris Packham likely(data->valid)) 143aaf6fabfSChris Packham goto out; 144aaf6fabfSChris Packham 145aaf6fabfSChris Packham ret = i2c_smbus_read_byte_data(client, TC654_REG_RPM(0)); 146aaf6fabfSChris Packham if (ret < 0) 147aaf6fabfSChris Packham goto out; 148aaf6fabfSChris Packham data->rpm_output[0] = ret; 149aaf6fabfSChris Packham 150aaf6fabfSChris Packham ret = i2c_smbus_read_byte_data(client, TC654_REG_RPM(1)); 151aaf6fabfSChris Packham if (ret < 0) 152aaf6fabfSChris Packham goto out; 153aaf6fabfSChris Packham data->rpm_output[1] = ret; 154aaf6fabfSChris Packham 155aaf6fabfSChris Packham ret = i2c_smbus_read_byte_data(client, TC654_REG_FAN_FAULT(0)); 156aaf6fabfSChris Packham if (ret < 0) 157aaf6fabfSChris Packham goto out; 158aaf6fabfSChris Packham data->fan_fault[0] = ret; 159aaf6fabfSChris Packham 160aaf6fabfSChris Packham ret = i2c_smbus_read_byte_data(client, TC654_REG_FAN_FAULT(1)); 161aaf6fabfSChris Packham if (ret < 0) 162aaf6fabfSChris Packham goto out; 163aaf6fabfSChris Packham data->fan_fault[1] = ret; 164aaf6fabfSChris Packham 165aaf6fabfSChris Packham ret = i2c_smbus_read_byte_data(client, TC654_REG_CONFIG); 166aaf6fabfSChris Packham if (ret < 0) 167aaf6fabfSChris Packham goto out; 168aaf6fabfSChris Packham data->config = ret; 169aaf6fabfSChris Packham 170aaf6fabfSChris Packham ret = i2c_smbus_read_byte_data(client, TC654_REG_STATUS); 171aaf6fabfSChris Packham if (ret < 0) 172aaf6fabfSChris Packham goto out; 173aaf6fabfSChris Packham data->status = ret; 174aaf6fabfSChris Packham 175aaf6fabfSChris Packham ret = i2c_smbus_read_byte_data(client, TC654_REG_DUTY_CYCLE); 176aaf6fabfSChris Packham if (ret < 0) 177aaf6fabfSChris Packham goto out; 178aaf6fabfSChris Packham data->duty_cycle = ret & 0x0f; 179aaf6fabfSChris Packham 180aaf6fabfSChris Packham data->last_updated = jiffies; 181aaf6fabfSChris Packham data->valid = true; 182aaf6fabfSChris Packham out: 183aaf6fabfSChris Packham mutex_unlock(&data->update_lock); 184aaf6fabfSChris Packham 185aaf6fabfSChris Packham if (ret < 0) /* upon error, encode it in return value */ 186aaf6fabfSChris Packham data = ERR_PTR(ret); 187aaf6fabfSChris Packham 188aaf6fabfSChris Packham return data; 189aaf6fabfSChris Packham } 190aaf6fabfSChris Packham 191aaf6fabfSChris Packham /* 192aaf6fabfSChris Packham * sysfs attributes 193aaf6fabfSChris Packham */ 194aaf6fabfSChris Packham 1951acd2e29SGuenter Roeck static ssize_t fan_show(struct device *dev, struct device_attribute *da, 196aaf6fabfSChris Packham char *buf) 197aaf6fabfSChris Packham { 198aaf6fabfSChris Packham int nr = to_sensor_dev_attr(da)->index; 199aaf6fabfSChris Packham struct tc654_data *data = tc654_update_client(dev); 200aaf6fabfSChris Packham int val; 201aaf6fabfSChris Packham 202aaf6fabfSChris Packham if (IS_ERR(data)) 203aaf6fabfSChris Packham return PTR_ERR(data); 204aaf6fabfSChris Packham 205aaf6fabfSChris Packham if (data->config & TC654_REG_CONFIG_RES) 206aaf6fabfSChris Packham val = data->rpm_output[nr] * TC654_HIGH_RPM_RESOLUTION; 207aaf6fabfSChris Packham else 208aaf6fabfSChris Packham val = data->rpm_output[nr] * TC654_LOW_RPM_RESOLUTION; 209aaf6fabfSChris Packham 210aaf6fabfSChris Packham return sprintf(buf, "%d\n", val); 211aaf6fabfSChris Packham } 212aaf6fabfSChris Packham 2131acd2e29SGuenter Roeck static ssize_t fan_min_show(struct device *dev, struct device_attribute *da, 214aaf6fabfSChris Packham char *buf) 215aaf6fabfSChris Packham { 216aaf6fabfSChris Packham int nr = to_sensor_dev_attr(da)->index; 217aaf6fabfSChris Packham struct tc654_data *data = tc654_update_client(dev); 218aaf6fabfSChris Packham 219aaf6fabfSChris Packham if (IS_ERR(data)) 220aaf6fabfSChris Packham return PTR_ERR(data); 221aaf6fabfSChris Packham 222aaf6fabfSChris Packham return sprintf(buf, "%d\n", 223aaf6fabfSChris Packham TC654_FAN_FAULT_FROM_REG(data->fan_fault[nr])); 224aaf6fabfSChris Packham } 225aaf6fabfSChris Packham 2261acd2e29SGuenter Roeck static ssize_t fan_min_store(struct device *dev, struct device_attribute *da, 227aaf6fabfSChris Packham const char *buf, size_t count) 228aaf6fabfSChris Packham { 229aaf6fabfSChris Packham int nr = to_sensor_dev_attr(da)->index; 230aaf6fabfSChris Packham struct tc654_data *data = dev_get_drvdata(dev); 231aaf6fabfSChris Packham struct i2c_client *client = data->client; 232aaf6fabfSChris Packham unsigned long val; 233aaf6fabfSChris Packham int ret; 234aaf6fabfSChris Packham 235aaf6fabfSChris Packham if (kstrtoul(buf, 10, &val)) 236aaf6fabfSChris Packham return -EINVAL; 237aaf6fabfSChris Packham 238aaf6fabfSChris Packham val = clamp_val(val, 0, 12750); 239aaf6fabfSChris Packham 240aaf6fabfSChris Packham mutex_lock(&data->update_lock); 241aaf6fabfSChris Packham 242aaf6fabfSChris Packham data->fan_fault[nr] = TC654_FAN_FAULT_TO_REG(val); 243aaf6fabfSChris Packham ret = i2c_smbus_write_byte_data(client, TC654_REG_FAN_FAULT(nr), 244aaf6fabfSChris Packham data->fan_fault[nr]); 245aaf6fabfSChris Packham 246aaf6fabfSChris Packham mutex_unlock(&data->update_lock); 247aaf6fabfSChris Packham return ret < 0 ? ret : count; 248aaf6fabfSChris Packham } 249aaf6fabfSChris Packham 2501acd2e29SGuenter Roeck static ssize_t fan_alarm_show(struct device *dev, struct device_attribute *da, 251aaf6fabfSChris Packham char *buf) 252aaf6fabfSChris Packham { 253aaf6fabfSChris Packham int nr = to_sensor_dev_attr(da)->index; 254aaf6fabfSChris Packham struct tc654_data *data = tc654_update_client(dev); 255aaf6fabfSChris Packham int val; 256aaf6fabfSChris Packham 257aaf6fabfSChris Packham if (IS_ERR(data)) 258aaf6fabfSChris Packham return PTR_ERR(data); 259aaf6fabfSChris Packham 260aaf6fabfSChris Packham if (nr == 0) 261aaf6fabfSChris Packham val = !!(data->status & TC654_REG_STATUS_F1F); 262aaf6fabfSChris Packham else 263aaf6fabfSChris Packham val = !!(data->status & TC654_REG_STATUS_F2F); 264aaf6fabfSChris Packham 265aaf6fabfSChris Packham return sprintf(buf, "%d\n", val); 266aaf6fabfSChris Packham } 267aaf6fabfSChris Packham 268aaf6fabfSChris Packham static const u8 TC654_FAN_PULSE_SHIFT[] = { 1, 3 }; 269aaf6fabfSChris Packham 2701acd2e29SGuenter Roeck static ssize_t fan_pulses_show(struct device *dev, 2711acd2e29SGuenter Roeck struct device_attribute *da, char *buf) 272aaf6fabfSChris Packham { 273aaf6fabfSChris Packham int nr = to_sensor_dev_attr(da)->index; 274aaf6fabfSChris Packham struct tc654_data *data = tc654_update_client(dev); 275aaf6fabfSChris Packham u8 val; 276aaf6fabfSChris Packham 277aaf6fabfSChris Packham if (IS_ERR(data)) 278aaf6fabfSChris Packham return PTR_ERR(data); 279aaf6fabfSChris Packham 280aaf6fabfSChris Packham val = BIT((data->config >> TC654_FAN_PULSE_SHIFT[nr]) & 0x03); 281aaf6fabfSChris Packham return sprintf(buf, "%d\n", val); 282aaf6fabfSChris Packham } 283aaf6fabfSChris Packham 2841acd2e29SGuenter Roeck static ssize_t fan_pulses_store(struct device *dev, 2851acd2e29SGuenter Roeck struct device_attribute *da, const char *buf, 2861acd2e29SGuenter Roeck size_t count) 287aaf6fabfSChris Packham { 288aaf6fabfSChris Packham int nr = to_sensor_dev_attr(da)->index; 289aaf6fabfSChris Packham struct tc654_data *data = dev_get_drvdata(dev); 290aaf6fabfSChris Packham struct i2c_client *client = data->client; 291aaf6fabfSChris Packham u8 config; 292aaf6fabfSChris Packham unsigned long val; 293aaf6fabfSChris Packham int ret; 294aaf6fabfSChris Packham 295aaf6fabfSChris Packham if (kstrtoul(buf, 10, &val)) 296aaf6fabfSChris Packham return -EINVAL; 297aaf6fabfSChris Packham 298aaf6fabfSChris Packham switch (val) { 299aaf6fabfSChris Packham case 1: 300aaf6fabfSChris Packham config = 0; 301aaf6fabfSChris Packham break; 302aaf6fabfSChris Packham case 2: 303aaf6fabfSChris Packham config = 1; 304aaf6fabfSChris Packham break; 305aaf6fabfSChris Packham case 4: 306aaf6fabfSChris Packham config = 2; 307aaf6fabfSChris Packham break; 308aaf6fabfSChris Packham case 8: 309aaf6fabfSChris Packham config = 3; 310aaf6fabfSChris Packham break; 311aaf6fabfSChris Packham default: 312aaf6fabfSChris Packham return -EINVAL; 313aaf6fabfSChris Packham } 314aaf6fabfSChris Packham 315aaf6fabfSChris Packham mutex_lock(&data->update_lock); 316aaf6fabfSChris Packham 317aaf6fabfSChris Packham data->config &= ~(0x03 << TC654_FAN_PULSE_SHIFT[nr]); 318aaf6fabfSChris Packham data->config |= (config << TC654_FAN_PULSE_SHIFT[nr]); 319aaf6fabfSChris Packham ret = i2c_smbus_write_byte_data(client, TC654_REG_CONFIG, data->config); 320aaf6fabfSChris Packham 321aaf6fabfSChris Packham mutex_unlock(&data->update_lock); 322aaf6fabfSChris Packham return ret < 0 ? ret : count; 323aaf6fabfSChris Packham } 324aaf6fabfSChris Packham 3251acd2e29SGuenter Roeck static ssize_t pwm_mode_show(struct device *dev, struct device_attribute *da, 3261acd2e29SGuenter Roeck char *buf) 327aaf6fabfSChris Packham { 328aaf6fabfSChris Packham struct tc654_data *data = tc654_update_client(dev); 329aaf6fabfSChris Packham 330aaf6fabfSChris Packham if (IS_ERR(data)) 331aaf6fabfSChris Packham return PTR_ERR(data); 332aaf6fabfSChris Packham 333aaf6fabfSChris Packham return sprintf(buf, "%d\n", !!(data->config & TC654_REG_CONFIG_DUTYC)); 334aaf6fabfSChris Packham } 335aaf6fabfSChris Packham 3361acd2e29SGuenter Roeck static ssize_t pwm_mode_store(struct device *dev, struct device_attribute *da, 337aaf6fabfSChris Packham const char *buf, size_t count) 338aaf6fabfSChris Packham { 339aaf6fabfSChris Packham struct tc654_data *data = dev_get_drvdata(dev); 340aaf6fabfSChris Packham struct i2c_client *client = data->client; 341aaf6fabfSChris Packham unsigned long val; 342aaf6fabfSChris Packham int ret; 343aaf6fabfSChris Packham 344aaf6fabfSChris Packham if (kstrtoul(buf, 10, &val)) 345aaf6fabfSChris Packham return -EINVAL; 346aaf6fabfSChris Packham 347aaf6fabfSChris Packham if (val != 0 && val != 1) 348aaf6fabfSChris Packham return -EINVAL; 349aaf6fabfSChris Packham 350aaf6fabfSChris Packham mutex_lock(&data->update_lock); 351aaf6fabfSChris Packham 352aaf6fabfSChris Packham if (val) 353aaf6fabfSChris Packham data->config |= TC654_REG_CONFIG_DUTYC; 354aaf6fabfSChris Packham else 355aaf6fabfSChris Packham data->config &= ~TC654_REG_CONFIG_DUTYC; 356aaf6fabfSChris Packham 357aaf6fabfSChris Packham ret = i2c_smbus_write_byte_data(client, TC654_REG_CONFIG, data->config); 358aaf6fabfSChris Packham 359aaf6fabfSChris Packham mutex_unlock(&data->update_lock); 360aaf6fabfSChris Packham return ret < 0 ? ret : count; 361aaf6fabfSChris Packham } 362aaf6fabfSChris Packham 363aaf6fabfSChris Packham static const int tc654_pwm_map[16] = { 77, 88, 102, 112, 124, 136, 148, 160, 364aaf6fabfSChris Packham 172, 184, 196, 207, 219, 231, 243, 255}; 365aaf6fabfSChris Packham 3661acd2e29SGuenter Roeck static ssize_t pwm_show(struct device *dev, struct device_attribute *da, 367aaf6fabfSChris Packham char *buf) 368aaf6fabfSChris Packham { 369aaf6fabfSChris Packham struct tc654_data *data = tc654_update_client(dev); 370aaf6fabfSChris Packham int pwm; 371aaf6fabfSChris Packham 372aaf6fabfSChris Packham if (IS_ERR(data)) 373aaf6fabfSChris Packham return PTR_ERR(data); 374aaf6fabfSChris Packham 375aaf6fabfSChris Packham if (data->config & TC654_REG_CONFIG_SDM) 376aaf6fabfSChris Packham pwm = 0; 377aaf6fabfSChris Packham else 378aaf6fabfSChris Packham pwm = tc654_pwm_map[data->duty_cycle]; 379aaf6fabfSChris Packham 380aaf6fabfSChris Packham return sprintf(buf, "%d\n", pwm); 381aaf6fabfSChris Packham } 382aaf6fabfSChris Packham 38399cb5e9fSChristian Lamparter static int _set_pwm(struct tc654_data *data, unsigned long val) 384aaf6fabfSChris Packham { 385aaf6fabfSChris Packham struct i2c_client *client = data->client; 386aaf6fabfSChris Packham int ret; 387aaf6fabfSChris Packham 388aaf6fabfSChris Packham mutex_lock(&data->update_lock); 389aaf6fabfSChris Packham 39099cb5e9fSChristian Lamparter if (val == 0) { 391aaf6fabfSChris Packham data->config |= TC654_REG_CONFIG_SDM; 39299cb5e9fSChristian Lamparter data->duty_cycle = 0; 39399cb5e9fSChristian Lamparter } else { 394aaf6fabfSChris Packham data->config &= ~TC654_REG_CONFIG_SDM; 39599cb5e9fSChristian Lamparter data->duty_cycle = val - 1; 39699cb5e9fSChristian Lamparter } 397aaf6fabfSChris Packham 398aaf6fabfSChris Packham ret = i2c_smbus_write_byte_data(client, TC654_REG_CONFIG, data->config); 399aaf6fabfSChris Packham if (ret < 0) 400aaf6fabfSChris Packham goto out; 401aaf6fabfSChris Packham 402aaf6fabfSChris Packham ret = i2c_smbus_write_byte_data(client, TC654_REG_DUTY_CYCLE, 403aaf6fabfSChris Packham data->duty_cycle); 404aaf6fabfSChris Packham 405aaf6fabfSChris Packham out: 406aaf6fabfSChris Packham mutex_unlock(&data->update_lock); 40799cb5e9fSChristian Lamparter return ret; 40899cb5e9fSChristian Lamparter } 40999cb5e9fSChristian Lamparter 41099cb5e9fSChristian Lamparter static ssize_t pwm_store(struct device *dev, struct device_attribute *da, 41199cb5e9fSChristian Lamparter const char *buf, size_t count) 41299cb5e9fSChristian Lamparter { 41399cb5e9fSChristian Lamparter struct tc654_data *data = dev_get_drvdata(dev); 41499cb5e9fSChristian Lamparter unsigned long val; 41599cb5e9fSChristian Lamparter int ret; 41699cb5e9fSChristian Lamparter 41799cb5e9fSChristian Lamparter if (kstrtoul(buf, 10, &val)) 41899cb5e9fSChristian Lamparter return -EINVAL; 41999cb5e9fSChristian Lamparter if (val > 255) 42099cb5e9fSChristian Lamparter return -EINVAL; 42199cb5e9fSChristian Lamparter if (val > 0) 42299cb5e9fSChristian Lamparter val = find_closest(val, tc654_pwm_map, ARRAY_SIZE(tc654_pwm_map)) + 1; 42399cb5e9fSChristian Lamparter 42499cb5e9fSChristian Lamparter ret = _set_pwm(data, val); 425aaf6fabfSChris Packham return ret < 0 ? ret : count; 426aaf6fabfSChris Packham } 427aaf6fabfSChris Packham 4281acd2e29SGuenter Roeck static SENSOR_DEVICE_ATTR_RO(fan1_input, fan, 0); 4291acd2e29SGuenter Roeck static SENSOR_DEVICE_ATTR_RO(fan2_input, fan, 1); 4301acd2e29SGuenter Roeck static SENSOR_DEVICE_ATTR_RW(fan1_min, fan_min, 0); 4311acd2e29SGuenter Roeck static SENSOR_DEVICE_ATTR_RW(fan2_min, fan_min, 1); 4321acd2e29SGuenter Roeck static SENSOR_DEVICE_ATTR_RO(fan1_alarm, fan_alarm, 0); 4331acd2e29SGuenter Roeck static SENSOR_DEVICE_ATTR_RO(fan2_alarm, fan_alarm, 1); 4341acd2e29SGuenter Roeck static SENSOR_DEVICE_ATTR_RW(fan1_pulses, fan_pulses, 0); 4351acd2e29SGuenter Roeck static SENSOR_DEVICE_ATTR_RW(fan2_pulses, fan_pulses, 1); 4361acd2e29SGuenter Roeck static SENSOR_DEVICE_ATTR_RW(pwm1_mode, pwm_mode, 0); 4371acd2e29SGuenter Roeck static SENSOR_DEVICE_ATTR_RW(pwm1, pwm, 0); 438aaf6fabfSChris Packham 439aaf6fabfSChris Packham /* Driver data */ 440aaf6fabfSChris Packham static struct attribute *tc654_attrs[] = { 441aaf6fabfSChris Packham &sensor_dev_attr_fan1_input.dev_attr.attr, 442aaf6fabfSChris Packham &sensor_dev_attr_fan2_input.dev_attr.attr, 443aaf6fabfSChris Packham &sensor_dev_attr_fan1_min.dev_attr.attr, 444aaf6fabfSChris Packham &sensor_dev_attr_fan2_min.dev_attr.attr, 445aaf6fabfSChris Packham &sensor_dev_attr_fan1_alarm.dev_attr.attr, 446aaf6fabfSChris Packham &sensor_dev_attr_fan2_alarm.dev_attr.attr, 447aaf6fabfSChris Packham &sensor_dev_attr_fan1_pulses.dev_attr.attr, 448aaf6fabfSChris Packham &sensor_dev_attr_fan2_pulses.dev_attr.attr, 449aaf6fabfSChris Packham &sensor_dev_attr_pwm1_mode.dev_attr.attr, 450aaf6fabfSChris Packham &sensor_dev_attr_pwm1.dev_attr.attr, 451aaf6fabfSChris Packham NULL 452aaf6fabfSChris Packham }; 453aaf6fabfSChris Packham 454aaf6fabfSChris Packham ATTRIBUTE_GROUPS(tc654); 455aaf6fabfSChris Packham 456aaf6fabfSChris Packham /* 45799cb5e9fSChristian Lamparter * thermal cooling device functions 45899cb5e9fSChristian Lamparter * 45999cb5e9fSChristian Lamparter * Account for the "ShutDown Mode (SDM)" state by offsetting 46099cb5e9fSChristian Lamparter * the 16 PWM duty cycle states by 1. 46199cb5e9fSChristian Lamparter * 46299cb5e9fSChristian Lamparter * State 0 = 0% PWM | Shutdown - Fan(s) are off 46399cb5e9fSChristian Lamparter * State 1 = 30% PWM | duty_cycle = 0 46499cb5e9fSChristian Lamparter * State 2 = ~35% PWM | duty_cycle = 1 46599cb5e9fSChristian Lamparter * [...] 46699cb5e9fSChristian Lamparter * State 15 = ~95% PWM | duty_cycle = 14 46799cb5e9fSChristian Lamparter * State 16 = 100% PWM | duty_cycle = 15 46899cb5e9fSChristian Lamparter */ 46999cb5e9fSChristian Lamparter #define TC654_MAX_COOLING_STATE 16 47099cb5e9fSChristian Lamparter 47199cb5e9fSChristian Lamparter static int tc654_get_max_state(struct thermal_cooling_device *cdev, unsigned long *state) 47299cb5e9fSChristian Lamparter { 47399cb5e9fSChristian Lamparter *state = TC654_MAX_COOLING_STATE; 47499cb5e9fSChristian Lamparter return 0; 47599cb5e9fSChristian Lamparter } 47699cb5e9fSChristian Lamparter 47799cb5e9fSChristian Lamparter static int tc654_get_cur_state(struct thermal_cooling_device *cdev, unsigned long *state) 47899cb5e9fSChristian Lamparter { 47999cb5e9fSChristian Lamparter struct tc654_data *data = tc654_update_client(cdev->devdata); 48099cb5e9fSChristian Lamparter 48199cb5e9fSChristian Lamparter if (IS_ERR(data)) 48299cb5e9fSChristian Lamparter return PTR_ERR(data); 48399cb5e9fSChristian Lamparter 48499cb5e9fSChristian Lamparter if (data->config & TC654_REG_CONFIG_SDM) 48599cb5e9fSChristian Lamparter *state = 0; /* FAN is off */ 48699cb5e9fSChristian Lamparter else 48799cb5e9fSChristian Lamparter *state = data->duty_cycle + 1; /* offset PWM States by 1 */ 48899cb5e9fSChristian Lamparter 48999cb5e9fSChristian Lamparter return 0; 49099cb5e9fSChristian Lamparter } 49199cb5e9fSChristian Lamparter 49299cb5e9fSChristian Lamparter static int tc654_set_cur_state(struct thermal_cooling_device *cdev, unsigned long state) 49399cb5e9fSChristian Lamparter { 49499cb5e9fSChristian Lamparter struct tc654_data *data = tc654_update_client(cdev->devdata); 49599cb5e9fSChristian Lamparter 49699cb5e9fSChristian Lamparter if (IS_ERR(data)) 49799cb5e9fSChristian Lamparter return PTR_ERR(data); 49899cb5e9fSChristian Lamparter 49999cb5e9fSChristian Lamparter return _set_pwm(data, clamp_val(state, 0, TC654_MAX_COOLING_STATE)); 50099cb5e9fSChristian Lamparter } 50199cb5e9fSChristian Lamparter 50299cb5e9fSChristian Lamparter static const struct thermal_cooling_device_ops tc654_fan_cool_ops = { 50399cb5e9fSChristian Lamparter .get_max_state = tc654_get_max_state, 50499cb5e9fSChristian Lamparter .get_cur_state = tc654_get_cur_state, 50599cb5e9fSChristian Lamparter .set_cur_state = tc654_set_cur_state, 50699cb5e9fSChristian Lamparter }; 50799cb5e9fSChristian Lamparter 50899cb5e9fSChristian Lamparter /* 509aaf6fabfSChris Packham * device probe and removal 510aaf6fabfSChris Packham */ 511aaf6fabfSChris Packham 51267487038SStephen Kitt static int tc654_probe(struct i2c_client *client) 513aaf6fabfSChris Packham { 514aaf6fabfSChris Packham struct device *dev = &client->dev; 515aaf6fabfSChris Packham struct tc654_data *data; 516aaf6fabfSChris Packham struct device *hwmon_dev; 517aaf6fabfSChris Packham int ret; 518aaf6fabfSChris Packham 519aaf6fabfSChris Packham if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) 520aaf6fabfSChris Packham return -ENODEV; 521aaf6fabfSChris Packham 522aaf6fabfSChris Packham data = devm_kzalloc(dev, sizeof(struct tc654_data), GFP_KERNEL); 523aaf6fabfSChris Packham if (!data) 524aaf6fabfSChris Packham return -ENOMEM; 525aaf6fabfSChris Packham 526aaf6fabfSChris Packham data->client = client; 527aaf6fabfSChris Packham mutex_init(&data->update_lock); 528aaf6fabfSChris Packham 529aaf6fabfSChris Packham ret = i2c_smbus_read_byte_data(client, TC654_REG_CONFIG); 530aaf6fabfSChris Packham if (ret < 0) 531aaf6fabfSChris Packham return ret; 532aaf6fabfSChris Packham 533aaf6fabfSChris Packham data->config = ret; 534aaf6fabfSChris Packham 535aaf6fabfSChris Packham hwmon_dev = 536aaf6fabfSChris Packham devm_hwmon_device_register_with_groups(dev, client->name, data, 537aaf6fabfSChris Packham tc654_groups); 53899cb5e9fSChristian Lamparter if (IS_ERR(hwmon_dev)) 53999cb5e9fSChristian Lamparter return PTR_ERR(hwmon_dev); 54099cb5e9fSChristian Lamparter 54199cb5e9fSChristian Lamparter if (IS_ENABLED(CONFIG_THERMAL)) { 54299cb5e9fSChristian Lamparter struct thermal_cooling_device *cdev; 54399cb5e9fSChristian Lamparter 54499cb5e9fSChristian Lamparter cdev = devm_thermal_of_cooling_device_register(dev, dev->of_node, client->name, 54599cb5e9fSChristian Lamparter hwmon_dev, &tc654_fan_cool_ops); 54699cb5e9fSChristian Lamparter return PTR_ERR_OR_ZERO(cdev); 54799cb5e9fSChristian Lamparter } 54899cb5e9fSChristian Lamparter 54999cb5e9fSChristian Lamparter return 0; 550aaf6fabfSChris Packham } 551aaf6fabfSChris Packham 552aaf6fabfSChris Packham static const struct i2c_device_id tc654_id[] = { 553aaf6fabfSChris Packham {"tc654", 0}, 554aaf6fabfSChris Packham {"tc655", 0}, 555aaf6fabfSChris Packham {} 556aaf6fabfSChris Packham }; 557aaf6fabfSChris Packham 558aaf6fabfSChris Packham MODULE_DEVICE_TABLE(i2c, tc654_id); 559aaf6fabfSChris Packham 560aaf6fabfSChris Packham static struct i2c_driver tc654_driver = { 561aaf6fabfSChris Packham .driver = { 562aaf6fabfSChris Packham .name = "tc654", 563aaf6fabfSChris Packham }, 564*1975d167SUwe Kleine-König .probe = tc654_probe, 565aaf6fabfSChris Packham .id_table = tc654_id, 566aaf6fabfSChris Packham }; 567aaf6fabfSChris Packham 568aaf6fabfSChris Packham module_i2c_driver(tc654_driver); 569aaf6fabfSChris Packham 570aaf6fabfSChris Packham MODULE_AUTHOR("Allied Telesis Labs"); 571aaf6fabfSChris Packham MODULE_DESCRIPTION("Microchip TC654/TC655 driver"); 572aaf6fabfSChris Packham MODULE_LICENSE("GPL"); 573