1d20620deSHans-Juergen Koch /* 2d20620deSHans-Juergen Koch * max6650.c - Part of lm_sensors, Linux kernel modules for hardware 3d20620deSHans-Juergen Koch * monitoring. 4d20620deSHans-Juergen Koch * 52aa25c22SHans J. Koch * (C) 2007 by Hans J. Koch <hjk@hansjkoch.de> 6d20620deSHans-Juergen Koch * 7d20620deSHans-Juergen Koch * based on code written by John Morris <john.morris@spirentcom.com> 8d20620deSHans-Juergen Koch * Copyright (c) 2003 Spirent Communications 9d20620deSHans-Juergen Koch * and Claus Gindhart <claus.gindhart@kontron.com> 10d20620deSHans-Juergen Koch * 11d20620deSHans-Juergen Koch * This module has only been tested with the MAX6650 chip. It should 12d20620deSHans-Juergen Koch * also work with the MAX6651. It does not distinguish max6650 and max6651 13d20620deSHans-Juergen Koch * chips. 14d20620deSHans-Juergen Koch * 1552b5226fSChristian Engelmayer * The datasheet was last seen at: 16d20620deSHans-Juergen Koch * 17d20620deSHans-Juergen Koch * http://pdfserv.maxim-ic.com/en/ds/MAX6650-MAX6651.pdf 18d20620deSHans-Juergen Koch * 19d20620deSHans-Juergen Koch * This program is free software; you can redistribute it and/or modify 20d20620deSHans-Juergen Koch * it under the terms of the GNU General Public License as published by 21d20620deSHans-Juergen Koch * the Free Software Foundation; either version 2 of the License, or 22d20620deSHans-Juergen Koch * (at your option) any later version. 23d20620deSHans-Juergen Koch * 24d20620deSHans-Juergen Koch * This program is distributed in the hope that it will be useful, 25d20620deSHans-Juergen Koch * but WITHOUT ANY WARRANTY; without even the implied warranty of 26d20620deSHans-Juergen Koch * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 27d20620deSHans-Juergen Koch * GNU General Public License for more details. 28d20620deSHans-Juergen Koch * 29d20620deSHans-Juergen Koch * You should have received a copy of the GNU General Public License 30d20620deSHans-Juergen Koch * along with this program; if not, write to the Free Software 31d20620deSHans-Juergen Koch * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 32d20620deSHans-Juergen Koch */ 33d20620deSHans-Juergen Koch 34d20620deSHans-Juergen Koch #include <linux/module.h> 35d20620deSHans-Juergen Koch #include <linux/init.h> 36d20620deSHans-Juergen Koch #include <linux/slab.h> 37d20620deSHans-Juergen Koch #include <linux/jiffies.h> 38d20620deSHans-Juergen Koch #include <linux/i2c.h> 39d20620deSHans-Juergen Koch #include <linux/hwmon.h> 40d20620deSHans-Juergen Koch #include <linux/hwmon-sysfs.h> 41d20620deSHans-Juergen Koch #include <linux/err.h> 42a6cdeefeSMike Looijmans #include <linux/of_device.h> 434f8d374bSJean-Francois Dagenais #include <linux/thermal.h> 44d20620deSHans-Juergen Koch 45d20620deSHans-Juergen Koch /* 46d20620deSHans-Juergen Koch * Insmod parameters 47d20620deSHans-Juergen Koch */ 48d20620deSHans-Juergen Koch 49d20620deSHans-Juergen Koch /* fan_voltage: 5=5V fan, 12=12V fan, 0=don't change */ 50d20620deSHans-Juergen Koch static int fan_voltage; 51d20620deSHans-Juergen Koch /* prescaler: Possible values are 1, 2, 4, 8, 16 or 0 for don't change */ 52d20620deSHans-Juergen Koch static int prescaler; 53a6cdeefeSMike Looijmans /* clock: The clock frequency of the chip (max6651 can be clocked externally) */ 54d20620deSHans-Juergen Koch static int clock = 254000; 55d20620deSHans-Juergen Koch 560f50b2e8SGuenter Roeck module_param(fan_voltage, int, 0444); 570f50b2e8SGuenter Roeck module_param(prescaler, int, 0444); 580f50b2e8SGuenter Roeck module_param(clock, int, 0444); 59d20620deSHans-Juergen Koch 60d20620deSHans-Juergen Koch /* 61d20620deSHans-Juergen Koch * MAX 6650/6651 registers 62d20620deSHans-Juergen Koch */ 63d20620deSHans-Juergen Koch 64d20620deSHans-Juergen Koch #define MAX6650_REG_SPEED 0x00 65d20620deSHans-Juergen Koch #define MAX6650_REG_CONFIG 0x02 66d20620deSHans-Juergen Koch #define MAX6650_REG_GPIO_DEF 0x04 67d20620deSHans-Juergen Koch #define MAX6650_REG_DAC 0x06 68d20620deSHans-Juergen Koch #define MAX6650_REG_ALARM_EN 0x08 69d20620deSHans-Juergen Koch #define MAX6650_REG_ALARM 0x0A 70d20620deSHans-Juergen Koch #define MAX6650_REG_TACH0 0x0C 71d20620deSHans-Juergen Koch #define MAX6650_REG_TACH1 0x0E 72d20620deSHans-Juergen Koch #define MAX6650_REG_TACH2 0x10 73d20620deSHans-Juergen Koch #define MAX6650_REG_TACH3 0x12 74d20620deSHans-Juergen Koch #define MAX6650_REG_GPIO_STAT 0x14 75d20620deSHans-Juergen Koch #define MAX6650_REG_COUNT 0x16 76d20620deSHans-Juergen Koch 77d20620deSHans-Juergen Koch /* 78d20620deSHans-Juergen Koch * Config register bits 79d20620deSHans-Juergen Koch */ 80d20620deSHans-Juergen Koch 81d20620deSHans-Juergen Koch #define MAX6650_CFG_V12 0x08 82d20620deSHans-Juergen Koch #define MAX6650_CFG_PRESCALER_MASK 0x07 83d20620deSHans-Juergen Koch #define MAX6650_CFG_PRESCALER_2 0x01 84d20620deSHans-Juergen Koch #define MAX6650_CFG_PRESCALER_4 0x02 85d20620deSHans-Juergen Koch #define MAX6650_CFG_PRESCALER_8 0x03 86d20620deSHans-Juergen Koch #define MAX6650_CFG_PRESCALER_16 0x04 87d20620deSHans-Juergen Koch #define MAX6650_CFG_MODE_MASK 0x30 88d20620deSHans-Juergen Koch #define MAX6650_CFG_MODE_ON 0x00 89d20620deSHans-Juergen Koch #define MAX6650_CFG_MODE_OFF 0x10 90d20620deSHans-Juergen Koch #define MAX6650_CFG_MODE_CLOSED_LOOP 0x20 91d20620deSHans-Juergen Koch #define MAX6650_CFG_MODE_OPEN_LOOP 0x30 92d20620deSHans-Juergen Koch #define MAX6650_COUNT_MASK 0x03 93d20620deSHans-Juergen Koch 9452b5226fSChristian Engelmayer /* 9552b5226fSChristian Engelmayer * Alarm status register bits 9652b5226fSChristian Engelmayer */ 9752b5226fSChristian Engelmayer 9852b5226fSChristian Engelmayer #define MAX6650_ALRM_MAX 0x01 9952b5226fSChristian Engelmayer #define MAX6650_ALRM_MIN 0x02 10052b5226fSChristian Engelmayer #define MAX6650_ALRM_TACH 0x04 10152b5226fSChristian Engelmayer #define MAX6650_ALRM_GPIO1 0x08 10252b5226fSChristian Engelmayer #define MAX6650_ALRM_GPIO2 0x10 10352b5226fSChristian Engelmayer 104d20620deSHans-Juergen Koch /* Minimum and maximum values of the FAN-RPM */ 105d20620deSHans-Juergen Koch #define FAN_RPM_MIN 240 106d20620deSHans-Juergen Koch #define FAN_RPM_MAX 30000 107d20620deSHans-Juergen Koch 108d20620deSHans-Juergen Koch #define DIV_FROM_REG(reg) (1 << (reg & 7)) 109d20620deSHans-Juergen Koch 110d20620deSHans-Juergen Koch /* 111d20620deSHans-Juergen Koch * Client data (each client gets its own) 112d20620deSHans-Juergen Koch */ 113d20620deSHans-Juergen Koch 114bafda5d0SGuenter Roeck struct max6650_data { 11517eaa25cSGuenter Roeck struct i2c_client *client; 11617eaa25cSGuenter Roeck const struct attribute_group *groups[3]; 1174f8d374bSJean-Francois Dagenais struct thermal_cooling_device *cooling_dev; 118d20620deSHans-Juergen Koch struct mutex update_lock; 1199c084daeSJean Delvare int nr_fans; 120d20620deSHans-Juergen Koch char valid; /* zero until following fields are valid */ 121d20620deSHans-Juergen Koch unsigned long last_updated; /* in jiffies */ 122d20620deSHans-Juergen Koch 123d20620deSHans-Juergen Koch /* register values */ 124d20620deSHans-Juergen Koch u8 speed; 125d20620deSHans-Juergen Koch u8 config; 126d20620deSHans-Juergen Koch u8 tach[4]; 127d20620deSHans-Juergen Koch u8 count; 128d20620deSHans-Juergen Koch u8 dac; 12952b5226fSChristian Engelmayer u8 alarm; 1304f8d374bSJean-Francois Dagenais unsigned long cooling_dev_state; 131d20620deSHans-Juergen Koch }; 132d20620deSHans-Juergen Koch 1331577f94bSGuenter Roeck static const u8 tach_reg[] = { 1341577f94bSGuenter Roeck MAX6650_REG_TACH0, 1351577f94bSGuenter Roeck MAX6650_REG_TACH1, 1361577f94bSGuenter Roeck MAX6650_REG_TACH2, 1371577f94bSGuenter Roeck MAX6650_REG_TACH3, 1381577f94bSGuenter Roeck }; 1391577f94bSGuenter Roeck 1402720ce7eSGuenter Roeck static const struct of_device_id __maybe_unused max6650_dt_match[] = { 141a6cdeefeSMike Looijmans { 142a6cdeefeSMike Looijmans .compatible = "maxim,max6650", 143a6cdeefeSMike Looijmans .data = (void *)1 144a6cdeefeSMike Looijmans }, 145a6cdeefeSMike Looijmans { 146a6cdeefeSMike Looijmans .compatible = "maxim,max6651", 147a6cdeefeSMike Looijmans .data = (void *)4 148a6cdeefeSMike Looijmans }, 149a6cdeefeSMike Looijmans { }, 150a6cdeefeSMike Looijmans }; 151a6cdeefeSMike Looijmans MODULE_DEVICE_TABLE(of, max6650_dt_match); 152a6cdeefeSMike Looijmans 1531577f94bSGuenter Roeck static struct max6650_data *max6650_update_device(struct device *dev) 1541577f94bSGuenter Roeck { 15517eaa25cSGuenter Roeck struct max6650_data *data = dev_get_drvdata(dev); 15617eaa25cSGuenter Roeck struct i2c_client *client = data->client; 1571577f94bSGuenter Roeck int i; 1581577f94bSGuenter Roeck 1591577f94bSGuenter Roeck mutex_lock(&data->update_lock); 1601577f94bSGuenter Roeck 1611577f94bSGuenter Roeck if (time_after(jiffies, data->last_updated + HZ) || !data->valid) { 1621577f94bSGuenter Roeck data->speed = i2c_smbus_read_byte_data(client, 1631577f94bSGuenter Roeck MAX6650_REG_SPEED); 1641577f94bSGuenter Roeck data->config = i2c_smbus_read_byte_data(client, 1651577f94bSGuenter Roeck MAX6650_REG_CONFIG); 1661577f94bSGuenter Roeck for (i = 0; i < data->nr_fans; i++) { 1671577f94bSGuenter Roeck data->tach[i] = i2c_smbus_read_byte_data(client, 1681577f94bSGuenter Roeck tach_reg[i]); 1691577f94bSGuenter Roeck } 1701577f94bSGuenter Roeck data->count = i2c_smbus_read_byte_data(client, 1711577f94bSGuenter Roeck MAX6650_REG_COUNT); 1721577f94bSGuenter Roeck data->dac = i2c_smbus_read_byte_data(client, MAX6650_REG_DAC); 1731577f94bSGuenter Roeck 1741577f94bSGuenter Roeck /* 1751577f94bSGuenter Roeck * Alarms are cleared on read in case the condition that 1761577f94bSGuenter Roeck * caused the alarm is removed. Keep the value latched here 1771577f94bSGuenter Roeck * for providing the register through different alarm files. 1781577f94bSGuenter Roeck */ 1791577f94bSGuenter Roeck data->alarm |= i2c_smbus_read_byte_data(client, 1801577f94bSGuenter Roeck MAX6650_REG_ALARM); 1811577f94bSGuenter Roeck 1821577f94bSGuenter Roeck data->last_updated = jiffies; 1831577f94bSGuenter Roeck data->valid = 1; 1841577f94bSGuenter Roeck } 1851577f94bSGuenter Roeck 1861577f94bSGuenter Roeck mutex_unlock(&data->update_lock); 1871577f94bSGuenter Roeck 1881577f94bSGuenter Roeck return data; 1891577f94bSGuenter Roeck } 1901577f94bSGuenter Roeck 19120005cc5SMike Looijmans /* 19220005cc5SMike Looijmans * Change the operating mode of the chip (if needed). 19320005cc5SMike Looijmans * mode is one of the MAX6650_CFG_MODE_* values. 19420005cc5SMike Looijmans */ 19520005cc5SMike Looijmans static int max6650_set_operating_mode(struct max6650_data *data, u8 mode) 19620005cc5SMike Looijmans { 19720005cc5SMike Looijmans int result; 19820005cc5SMike Looijmans u8 config = data->config; 19920005cc5SMike Looijmans 20020005cc5SMike Looijmans if (mode == (config & MAX6650_CFG_MODE_MASK)) 20120005cc5SMike Looijmans return 0; 20220005cc5SMike Looijmans 20320005cc5SMike Looijmans config = (config & ~MAX6650_CFG_MODE_MASK) | mode; 20420005cc5SMike Looijmans 20520005cc5SMike Looijmans result = i2c_smbus_write_byte_data(data->client, MAX6650_REG_CONFIG, 20620005cc5SMike Looijmans config); 20720005cc5SMike Looijmans if (result < 0) 20820005cc5SMike Looijmans return result; 20920005cc5SMike Looijmans 21020005cc5SMike Looijmans data->config = config; 21120005cc5SMike Looijmans 21220005cc5SMike Looijmans return 0; 21320005cc5SMike Looijmans } 21420005cc5SMike Looijmans 21544007117SGuenter Roeck static ssize_t fan_show(struct device *dev, struct device_attribute *devattr, 216d20620deSHans-Juergen Koch char *buf) 217d20620deSHans-Juergen Koch { 218d20620deSHans-Juergen Koch struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); 219d20620deSHans-Juergen Koch struct max6650_data *data = max6650_update_device(dev); 220d20620deSHans-Juergen Koch int rpm; 221d20620deSHans-Juergen Koch 222d20620deSHans-Juergen Koch /* 223d20620deSHans-Juergen Koch * Calculation details: 224d20620deSHans-Juergen Koch * 225d20620deSHans-Juergen Koch * Each tachometer counts over an interval given by the "count" 226d20620deSHans-Juergen Koch * register (0.25, 0.5, 1 or 2 seconds). This module assumes 227d20620deSHans-Juergen Koch * that the fans produce two pulses per revolution (this seems 228d20620deSHans-Juergen Koch * to be the most common). 229d20620deSHans-Juergen Koch */ 230d20620deSHans-Juergen Koch 231d20620deSHans-Juergen Koch rpm = ((data->tach[attr->index] * 120) / DIV_FROM_REG(data->count)); 232d20620deSHans-Juergen Koch return sprintf(buf, "%d\n", rpm); 233d20620deSHans-Juergen Koch } 234d20620deSHans-Juergen Koch 235d20620deSHans-Juergen Koch /* 236d20620deSHans-Juergen Koch * Set the fan speed to the specified RPM (or read back the RPM setting). 237d20620deSHans-Juergen Koch * This works in closed loop mode only. Use pwm1 for open loop speed setting. 238d20620deSHans-Juergen Koch * 239d20620deSHans-Juergen Koch * The MAX6650/1 will automatically control fan speed when in closed loop 240d20620deSHans-Juergen Koch * mode. 241d20620deSHans-Juergen Koch * 242d20620deSHans-Juergen Koch * Assumptions: 243d20620deSHans-Juergen Koch * 244d20620deSHans-Juergen Koch * 1) The MAX6650/1 internal 254kHz clock frequency is set correctly. Use 245d20620deSHans-Juergen Koch * the clock module parameter if you need to fine tune this. 246d20620deSHans-Juergen Koch * 247d20620deSHans-Juergen Koch * 2) The prescaler (low three bits of the config register) has already 248d20620deSHans-Juergen Koch * been set to an appropriate value. Use the prescaler module parameter 249d20620deSHans-Juergen Koch * if your BIOS doesn't initialize the chip properly. 250d20620deSHans-Juergen Koch * 251d20620deSHans-Juergen Koch * The relevant equations are given on pages 21 and 22 of the datasheet. 252d20620deSHans-Juergen Koch * 253d20620deSHans-Juergen Koch * From the datasheet, the relevant equation when in regulation is: 254d20620deSHans-Juergen Koch * 255d20620deSHans-Juergen Koch * [fCLK / (128 x (KTACH + 1))] = 2 x FanSpeed / KSCALE 256d20620deSHans-Juergen Koch * 257d20620deSHans-Juergen Koch * where: 258d20620deSHans-Juergen Koch * 259d20620deSHans-Juergen Koch * fCLK is the oscillator frequency (either the 254kHz internal 260d20620deSHans-Juergen Koch * oscillator or the externally applied clock) 261d20620deSHans-Juergen Koch * 262d20620deSHans-Juergen Koch * KTACH is the value in the speed register 263d20620deSHans-Juergen Koch * 264d20620deSHans-Juergen Koch * FanSpeed is the speed of the fan in rps 265d20620deSHans-Juergen Koch * 266d20620deSHans-Juergen Koch * KSCALE is the prescaler value (1, 2, 4, 8, or 16) 267d20620deSHans-Juergen Koch * 268d20620deSHans-Juergen Koch * When reading, we need to solve for FanSpeed. When writing, we need to 269d20620deSHans-Juergen Koch * solve for KTACH. 270d20620deSHans-Juergen Koch * 271d20620deSHans-Juergen Koch * Note: this tachometer is completely separate from the tachometers 272d20620deSHans-Juergen Koch * used to measure the fan speeds. Only one fan's speed (fan1) is 273d20620deSHans-Juergen Koch * controlled. 274d20620deSHans-Juergen Koch */ 275d20620deSHans-Juergen Koch 2761fc67376SJulia Lawall static ssize_t fan1_target_show(struct device *dev, 2771fc67376SJulia Lawall struct device_attribute *devattr, char *buf) 278d20620deSHans-Juergen Koch { 279d20620deSHans-Juergen Koch struct max6650_data *data = max6650_update_device(dev); 280d20620deSHans-Juergen Koch int kscale, ktach, rpm; 281d20620deSHans-Juergen Koch 282d20620deSHans-Juergen Koch /* 283d20620deSHans-Juergen Koch * Use the datasheet equation: 284d20620deSHans-Juergen Koch * 285d20620deSHans-Juergen Koch * FanSpeed = KSCALE x fCLK / [256 x (KTACH + 1)] 286d20620deSHans-Juergen Koch * 287d20620deSHans-Juergen Koch * then multiply by 60 to give rpm. 288d20620deSHans-Juergen Koch */ 289d20620deSHans-Juergen Koch 290d20620deSHans-Juergen Koch kscale = DIV_FROM_REG(data->config); 291d20620deSHans-Juergen Koch ktach = data->speed; 292d20620deSHans-Juergen Koch rpm = 60 * kscale * clock / (256 * (ktach + 1)); 293d20620deSHans-Juergen Koch return sprintf(buf, "%d\n", rpm); 294d20620deSHans-Juergen Koch } 295d20620deSHans-Juergen Koch 29620005cc5SMike Looijmans static int max6650_set_target(struct max6650_data *data, unsigned long rpm) 297d20620deSHans-Juergen Koch { 298d20620deSHans-Juergen Koch int kscale, ktach; 299bafda5d0SGuenter Roeck 30020005cc5SMike Looijmans if (rpm == 0) 30120005cc5SMike Looijmans return max6650_set_operating_mode(data, MAX6650_CFG_MODE_OFF); 302d20620deSHans-Juergen Koch 3032a844c14SGuenter Roeck rpm = clamp_val(rpm, FAN_RPM_MIN, FAN_RPM_MAX); 304d20620deSHans-Juergen Koch 305d20620deSHans-Juergen Koch /* 306d20620deSHans-Juergen Koch * Divide the required speed by 60 to get from rpm to rps, then 307d20620deSHans-Juergen Koch * use the datasheet equation: 308d20620deSHans-Juergen Koch * 309d20620deSHans-Juergen Koch * KTACH = [(fCLK x KSCALE) / (256 x FanSpeed)] - 1 310d20620deSHans-Juergen Koch */ 311d20620deSHans-Juergen Koch 312d20620deSHans-Juergen Koch kscale = DIV_FROM_REG(data->config); 313d20620deSHans-Juergen Koch ktach = ((clock * kscale) / (256 * rpm / 60)) - 1; 314d20620deSHans-Juergen Koch if (ktach < 0) 315d20620deSHans-Juergen Koch ktach = 0; 316d20620deSHans-Juergen Koch if (ktach > 255) 317d20620deSHans-Juergen Koch ktach = 255; 318d20620deSHans-Juergen Koch data->speed = ktach; 319d20620deSHans-Juergen Koch 32020005cc5SMike Looijmans return i2c_smbus_write_byte_data(data->client, MAX6650_REG_SPEED, 32120005cc5SMike Looijmans data->speed); 32220005cc5SMike Looijmans } 32320005cc5SMike Looijmans 3241fc67376SJulia Lawall static ssize_t fan1_target_store(struct device *dev, 3251fc67376SJulia Lawall struct device_attribute *devattr, 32620005cc5SMike Looijmans const char *buf, size_t count) 32720005cc5SMike Looijmans { 32820005cc5SMike Looijmans struct max6650_data *data = dev_get_drvdata(dev); 32920005cc5SMike Looijmans unsigned long rpm; 33020005cc5SMike Looijmans int err; 33120005cc5SMike Looijmans 33220005cc5SMike Looijmans err = kstrtoul(buf, 10, &rpm); 33320005cc5SMike Looijmans if (err) 33420005cc5SMike Looijmans return err; 33520005cc5SMike Looijmans 33620005cc5SMike Looijmans mutex_lock(&data->update_lock); 33720005cc5SMike Looijmans 33820005cc5SMike Looijmans err = max6650_set_target(data, rpm); 339d20620deSHans-Juergen Koch 340d20620deSHans-Juergen Koch mutex_unlock(&data->update_lock); 341d20620deSHans-Juergen Koch 34220005cc5SMike Looijmans if (err < 0) 34320005cc5SMike Looijmans return err; 34420005cc5SMike Looijmans 345d20620deSHans-Juergen Koch return count; 346d20620deSHans-Juergen Koch } 347d20620deSHans-Juergen Koch 348d20620deSHans-Juergen Koch /* 349d20620deSHans-Juergen Koch * Get/set the fan speed in open loop mode using pwm1 sysfs file. 350d20620deSHans-Juergen Koch * Speed is given as a relative value from 0 to 255, where 255 is maximum 351d20620deSHans-Juergen Koch * speed. Note that this is done by writing directly to the chip's DAC, 352d20620deSHans-Juergen Koch * it won't change the closed loop speed set by fan1_target. 353d20620deSHans-Juergen Koch * Also note that due to rounding errors it is possible that you don't read 354d20620deSHans-Juergen Koch * back exactly the value you have set. 355d20620deSHans-Juergen Koch */ 356d20620deSHans-Juergen Koch 3571fc67376SJulia Lawall static ssize_t pwm1_show(struct device *dev, struct device_attribute *devattr, 358d20620deSHans-Juergen Koch char *buf) 359d20620deSHans-Juergen Koch { 360d20620deSHans-Juergen Koch int pwm; 361d20620deSHans-Juergen Koch struct max6650_data *data = max6650_update_device(dev); 362d20620deSHans-Juergen Koch 363703af960SGuenter Roeck /* 364703af960SGuenter Roeck * Useful range for dac is 0-180 for 12V fans and 0-76 for 5V fans. 365703af960SGuenter Roeck * Lower DAC values mean higher speeds. 366703af960SGuenter Roeck */ 367d20620deSHans-Juergen Koch if (data->config & MAX6650_CFG_V12) 368d20620deSHans-Juergen Koch pwm = 255 - (255 * (int)data->dac)/180; 369d20620deSHans-Juergen Koch else 370d20620deSHans-Juergen Koch pwm = 255 - (255 * (int)data->dac)/76; 371d20620deSHans-Juergen Koch 372d20620deSHans-Juergen Koch if (pwm < 0) 373d20620deSHans-Juergen Koch pwm = 0; 374d20620deSHans-Juergen Koch 375d20620deSHans-Juergen Koch return sprintf(buf, "%d\n", pwm); 376d20620deSHans-Juergen Koch } 377d20620deSHans-Juergen Koch 3781fc67376SJulia Lawall static ssize_t pwm1_store(struct device *dev, 3791fc67376SJulia Lawall struct device_attribute *devattr, const char *buf, 3801fc67376SJulia Lawall size_t count) 381d20620deSHans-Juergen Koch { 38217eaa25cSGuenter Roeck struct max6650_data *data = dev_get_drvdata(dev); 38317eaa25cSGuenter Roeck struct i2c_client *client = data->client; 384bafda5d0SGuenter Roeck unsigned long pwm; 385bafda5d0SGuenter Roeck int err; 386bafda5d0SGuenter Roeck 387bafda5d0SGuenter Roeck err = kstrtoul(buf, 10, &pwm); 388bafda5d0SGuenter Roeck if (err) 389bafda5d0SGuenter Roeck return err; 390d20620deSHans-Juergen Koch 3912a844c14SGuenter Roeck pwm = clamp_val(pwm, 0, 255); 392d20620deSHans-Juergen Koch 393d20620deSHans-Juergen Koch mutex_lock(&data->update_lock); 394d20620deSHans-Juergen Koch 395d20620deSHans-Juergen Koch if (data->config & MAX6650_CFG_V12) 396d20620deSHans-Juergen Koch data->dac = 180 - (180 * pwm)/255; 397d20620deSHans-Juergen Koch else 398d20620deSHans-Juergen Koch data->dac = 76 - (76 * pwm)/255; 39920005cc5SMike Looijmans err = i2c_smbus_write_byte_data(client, MAX6650_REG_DAC, data->dac); 400d20620deSHans-Juergen Koch 401d20620deSHans-Juergen Koch mutex_unlock(&data->update_lock); 402d20620deSHans-Juergen Koch 40320005cc5SMike Looijmans return err < 0 ? err : count; 404d20620deSHans-Juergen Koch } 405d20620deSHans-Juergen Koch 406d20620deSHans-Juergen Koch /* 407d20620deSHans-Juergen Koch * Get/Set controller mode: 408d20620deSHans-Juergen Koch * Possible values: 409d20620deSHans-Juergen Koch * 0 = Fan always on 410d20620deSHans-Juergen Koch * 1 = Open loop, Voltage is set according to speed, not regulated. 411d20620deSHans-Juergen Koch * 2 = Closed loop, RPM for all fans regulated by fan1 tachometer 41220005cc5SMike Looijmans * 3 = Fan off 413d20620deSHans-Juergen Koch */ 4141fc67376SJulia Lawall static ssize_t pwm1_enable_show(struct device *dev, 4151fc67376SJulia Lawall struct device_attribute *devattr, char *buf) 416d20620deSHans-Juergen Koch { 417d20620deSHans-Juergen Koch struct max6650_data *data = max6650_update_device(dev); 418d20620deSHans-Juergen Koch int mode = (data->config & MAX6650_CFG_MODE_MASK) >> 4; 41920005cc5SMike Looijmans int sysfs_modes[4] = {0, 3, 2, 1}; 420d20620deSHans-Juergen Koch 421d20620deSHans-Juergen Koch return sprintf(buf, "%d\n", sysfs_modes[mode]); 422d20620deSHans-Juergen Koch } 423d20620deSHans-Juergen Koch 4241fc67376SJulia Lawall static ssize_t pwm1_enable_store(struct device *dev, 4251fc67376SJulia Lawall struct device_attribute *devattr, 426d20620deSHans-Juergen Koch const char *buf, size_t count) 427d20620deSHans-Juergen Koch { 42817eaa25cSGuenter Roeck struct max6650_data *data = dev_get_drvdata(dev); 429bafda5d0SGuenter Roeck unsigned long mode; 430bafda5d0SGuenter Roeck int err; 43120005cc5SMike Looijmans const u8 max6650_modes[] = { 43220005cc5SMike Looijmans MAX6650_CFG_MODE_ON, 43320005cc5SMike Looijmans MAX6650_CFG_MODE_OPEN_LOOP, 43420005cc5SMike Looijmans MAX6650_CFG_MODE_CLOSED_LOOP, 43520005cc5SMike Looijmans MAX6650_CFG_MODE_OFF, 43620005cc5SMike Looijmans }; 437d20620deSHans-Juergen Koch 438bafda5d0SGuenter Roeck err = kstrtoul(buf, 10, &mode); 439bafda5d0SGuenter Roeck if (err) 440bafda5d0SGuenter Roeck return err; 441bafda5d0SGuenter Roeck 44220005cc5SMike Looijmans if (mode >= ARRAY_SIZE(max6650_modes)) 443d20620deSHans-Juergen Koch return -EINVAL; 444d20620deSHans-Juergen Koch 445d20620deSHans-Juergen Koch mutex_lock(&data->update_lock); 446d20620deSHans-Juergen Koch 44720005cc5SMike Looijmans max6650_set_operating_mode(data, max6650_modes[mode]); 448d20620deSHans-Juergen Koch 449d20620deSHans-Juergen Koch mutex_unlock(&data->update_lock); 450d20620deSHans-Juergen Koch 451d20620deSHans-Juergen Koch return count; 452d20620deSHans-Juergen Koch } 453d20620deSHans-Juergen Koch 454d20620deSHans-Juergen Koch /* 455d20620deSHans-Juergen Koch * Read/write functions for fan1_div sysfs file. The MAX6650 has no such 456d20620deSHans-Juergen Koch * divider. We handle this by converting between divider and counttime: 457d20620deSHans-Juergen Koch * 458d20620deSHans-Juergen Koch * (counttime == k) <==> (divider == 2^k), k = 0, 1, 2, or 3 459d20620deSHans-Juergen Koch * 460d20620deSHans-Juergen Koch * Lower values of k allow to connect a faster fan without the risk of 461d20620deSHans-Juergen Koch * counter overflow. The price is lower resolution. You can also set counttime 462d20620deSHans-Juergen Koch * using the module parameter. Note that the module parameter "prescaler" also 463d20620deSHans-Juergen Koch * influences the behaviour. Unfortunately, there's no sysfs attribute 464d20620deSHans-Juergen Koch * defined for that. See the data sheet for details. 465d20620deSHans-Juergen Koch */ 466d20620deSHans-Juergen Koch 4671fc67376SJulia Lawall static ssize_t fan1_div_show(struct device *dev, 4681fc67376SJulia Lawall struct device_attribute *devattr, char *buf) 469d20620deSHans-Juergen Koch { 470d20620deSHans-Juergen Koch struct max6650_data *data = max6650_update_device(dev); 471d20620deSHans-Juergen Koch 472d20620deSHans-Juergen Koch return sprintf(buf, "%d\n", DIV_FROM_REG(data->count)); 473d20620deSHans-Juergen Koch } 474d20620deSHans-Juergen Koch 4751fc67376SJulia Lawall static ssize_t fan1_div_store(struct device *dev, 4761fc67376SJulia Lawall struct device_attribute *devattr, 477d20620deSHans-Juergen Koch const char *buf, size_t count) 478d20620deSHans-Juergen Koch { 47917eaa25cSGuenter Roeck struct max6650_data *data = dev_get_drvdata(dev); 48017eaa25cSGuenter Roeck struct i2c_client *client = data->client; 481bafda5d0SGuenter Roeck unsigned long div; 482bafda5d0SGuenter Roeck int err; 483bafda5d0SGuenter Roeck 484bafda5d0SGuenter Roeck err = kstrtoul(buf, 10, &div); 485bafda5d0SGuenter Roeck if (err) 486bafda5d0SGuenter Roeck return err; 487d20620deSHans-Juergen Koch 488d20620deSHans-Juergen Koch mutex_lock(&data->update_lock); 489d20620deSHans-Juergen Koch switch (div) { 490d20620deSHans-Juergen Koch case 1: 491d20620deSHans-Juergen Koch data->count = 0; 492d20620deSHans-Juergen Koch break; 493d20620deSHans-Juergen Koch case 2: 494d20620deSHans-Juergen Koch data->count = 1; 495d20620deSHans-Juergen Koch break; 496d20620deSHans-Juergen Koch case 4: 497d20620deSHans-Juergen Koch data->count = 2; 498d20620deSHans-Juergen Koch break; 499d20620deSHans-Juergen Koch case 8: 500d20620deSHans-Juergen Koch data->count = 3; 501d20620deSHans-Juergen Koch break; 502d20620deSHans-Juergen Koch default: 503025dc740SJiri Slaby mutex_unlock(&data->update_lock); 504d20620deSHans-Juergen Koch return -EINVAL; 505d20620deSHans-Juergen Koch } 506d20620deSHans-Juergen Koch 507d20620deSHans-Juergen Koch i2c_smbus_write_byte_data(client, MAX6650_REG_COUNT, data->count); 508d20620deSHans-Juergen Koch mutex_unlock(&data->update_lock); 509d20620deSHans-Juergen Koch 510d20620deSHans-Juergen Koch return count; 511d20620deSHans-Juergen Koch } 512d20620deSHans-Juergen Koch 51352b5226fSChristian Engelmayer /* 51452b5226fSChristian Engelmayer * Get alarm stati: 51552b5226fSChristian Engelmayer * Possible values: 51652b5226fSChristian Engelmayer * 0 = no alarm 51752b5226fSChristian Engelmayer * 1 = alarm 51852b5226fSChristian Engelmayer */ 51952b5226fSChristian Engelmayer 52044007117SGuenter Roeck static ssize_t alarm_show(struct device *dev, 52144007117SGuenter Roeck struct device_attribute *devattr, char *buf) 52252b5226fSChristian Engelmayer { 52352b5226fSChristian Engelmayer struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); 52452b5226fSChristian Engelmayer struct max6650_data *data = max6650_update_device(dev); 52517eaa25cSGuenter Roeck struct i2c_client *client = data->client; 52652b5226fSChristian Engelmayer int alarm = 0; 52752b5226fSChristian Engelmayer 52852b5226fSChristian Engelmayer if (data->alarm & attr->index) { 52952b5226fSChristian Engelmayer mutex_lock(&data->update_lock); 53052b5226fSChristian Engelmayer alarm = 1; 53152b5226fSChristian Engelmayer data->alarm &= ~attr->index; 53252b5226fSChristian Engelmayer data->alarm |= i2c_smbus_read_byte_data(client, 53352b5226fSChristian Engelmayer MAX6650_REG_ALARM); 53452b5226fSChristian Engelmayer mutex_unlock(&data->update_lock); 53552b5226fSChristian Engelmayer } 53652b5226fSChristian Engelmayer 53752b5226fSChristian Engelmayer return sprintf(buf, "%d\n", alarm); 53852b5226fSChristian Engelmayer } 53952b5226fSChristian Engelmayer 54044007117SGuenter Roeck static SENSOR_DEVICE_ATTR_RO(fan1_input, fan, 0); 54144007117SGuenter Roeck static SENSOR_DEVICE_ATTR_RO(fan2_input, fan, 1); 54244007117SGuenter Roeck static SENSOR_DEVICE_ATTR_RO(fan3_input, fan, 2); 54344007117SGuenter Roeck static SENSOR_DEVICE_ATTR_RO(fan4_input, fan, 3); 5441fc67376SJulia Lawall static DEVICE_ATTR_RW(fan1_target); 5451fc67376SJulia Lawall static DEVICE_ATTR_RW(fan1_div); 5461fc67376SJulia Lawall static DEVICE_ATTR_RW(pwm1_enable); 5471fc67376SJulia Lawall static DEVICE_ATTR_RW(pwm1); 54844007117SGuenter Roeck static SENSOR_DEVICE_ATTR_RO(fan1_max_alarm, alarm, MAX6650_ALRM_MAX); 54944007117SGuenter Roeck static SENSOR_DEVICE_ATTR_RO(fan1_min_alarm, alarm, MAX6650_ALRM_MIN); 55044007117SGuenter Roeck static SENSOR_DEVICE_ATTR_RO(fan1_fault, alarm, MAX6650_ALRM_TACH); 55144007117SGuenter Roeck static SENSOR_DEVICE_ATTR_RO(gpio1_alarm, alarm, MAX6650_ALRM_GPIO1); 55244007117SGuenter Roeck static SENSOR_DEVICE_ATTR_RO(gpio2_alarm, alarm, MAX6650_ALRM_GPIO2); 553d20620deSHans-Juergen Koch 554587a1f16SAl Viro static umode_t max6650_attrs_visible(struct kobject *kobj, struct attribute *a, 55552b5226fSChristian Engelmayer int n) 55652b5226fSChristian Engelmayer { 55752b5226fSChristian Engelmayer struct device *dev = container_of(kobj, struct device, kobj); 55817eaa25cSGuenter Roeck struct max6650_data *data = dev_get_drvdata(dev); 55917eaa25cSGuenter Roeck struct i2c_client *client = data->client; 56052b5226fSChristian Engelmayer u8 alarm_en = i2c_smbus_read_byte_data(client, MAX6650_REG_ALARM_EN); 56152b5226fSChristian Engelmayer struct device_attribute *devattr; 56252b5226fSChristian Engelmayer 56352b5226fSChristian Engelmayer /* 56452b5226fSChristian Engelmayer * Hide the alarms that have not been enabled by the firmware 56552b5226fSChristian Engelmayer */ 56652b5226fSChristian Engelmayer 56752b5226fSChristian Engelmayer devattr = container_of(a, struct device_attribute, attr); 56852b5226fSChristian Engelmayer if (devattr == &sensor_dev_attr_fan1_max_alarm.dev_attr 56952b5226fSChristian Engelmayer || devattr == &sensor_dev_attr_fan1_min_alarm.dev_attr 57052b5226fSChristian Engelmayer || devattr == &sensor_dev_attr_fan1_fault.dev_attr 57152b5226fSChristian Engelmayer || devattr == &sensor_dev_attr_gpio1_alarm.dev_attr 57252b5226fSChristian Engelmayer || devattr == &sensor_dev_attr_gpio2_alarm.dev_attr) { 57352b5226fSChristian Engelmayer if (!(alarm_en & to_sensor_dev_attr(devattr)->index)) 57452b5226fSChristian Engelmayer return 0; 57552b5226fSChristian Engelmayer } 57652b5226fSChristian Engelmayer 57752b5226fSChristian Engelmayer return a->mode; 57852b5226fSChristian Engelmayer } 579d20620deSHans-Juergen Koch 580d20620deSHans-Juergen Koch static struct attribute *max6650_attrs[] = { 581d20620deSHans-Juergen Koch &sensor_dev_attr_fan1_input.dev_attr.attr, 582d20620deSHans-Juergen Koch &dev_attr_fan1_target.attr, 583d20620deSHans-Juergen Koch &dev_attr_fan1_div.attr, 584d20620deSHans-Juergen Koch &dev_attr_pwm1_enable.attr, 585d20620deSHans-Juergen Koch &dev_attr_pwm1.attr, 58652b5226fSChristian Engelmayer &sensor_dev_attr_fan1_max_alarm.dev_attr.attr, 58752b5226fSChristian Engelmayer &sensor_dev_attr_fan1_min_alarm.dev_attr.attr, 58852b5226fSChristian Engelmayer &sensor_dev_attr_fan1_fault.dev_attr.attr, 58952b5226fSChristian Engelmayer &sensor_dev_attr_gpio1_alarm.dev_attr.attr, 59052b5226fSChristian Engelmayer &sensor_dev_attr_gpio2_alarm.dev_attr.attr, 591d20620deSHans-Juergen Koch NULL 592d20620deSHans-Juergen Koch }; 593d20620deSHans-Juergen Koch 59417eaa25cSGuenter Roeck static const struct attribute_group max6650_group = { 595d20620deSHans-Juergen Koch .attrs = max6650_attrs, 59652b5226fSChristian Engelmayer .is_visible = max6650_attrs_visible, 597d20620deSHans-Juergen Koch }; 598d20620deSHans-Juergen Koch 5999c084daeSJean Delvare static struct attribute *max6651_attrs[] = { 6009c084daeSJean Delvare &sensor_dev_attr_fan2_input.dev_attr.attr, 6019c084daeSJean Delvare &sensor_dev_attr_fan3_input.dev_attr.attr, 6029c084daeSJean Delvare &sensor_dev_attr_fan4_input.dev_attr.attr, 6039c084daeSJean Delvare NULL 6049c084daeSJean Delvare }; 6059c084daeSJean Delvare 60617eaa25cSGuenter Roeck static const struct attribute_group max6651_group = { 6079c084daeSJean Delvare .attrs = max6651_attrs, 6089c084daeSJean Delvare }; 6099c084daeSJean Delvare 610d20620deSHans-Juergen Koch /* 611d20620deSHans-Juergen Koch * Real code 612d20620deSHans-Juergen Koch */ 613d20620deSHans-Juergen Koch 61417eaa25cSGuenter Roeck static int max6650_init_client(struct max6650_data *data, 61517eaa25cSGuenter Roeck struct i2c_client *client) 616d20620deSHans-Juergen Koch { 61771ba0f31SGuenter Roeck struct device *dev = &client->dev; 618d20620deSHans-Juergen Koch int config; 619d20620deSHans-Juergen Koch int err = -EIO; 620a6cdeefeSMike Looijmans u32 voltage; 621a6cdeefeSMike Looijmans u32 prescale; 62220005cc5SMike Looijmans u32 target_rpm; 623a6cdeefeSMike Looijmans 624a6cdeefeSMike Looijmans if (of_property_read_u32(dev->of_node, "maxim,fan-microvolt", 625a6cdeefeSMike Looijmans &voltage)) 626a6cdeefeSMike Looijmans voltage = fan_voltage; 627a6cdeefeSMike Looijmans else 628a6cdeefeSMike Looijmans voltage /= 1000000; /* Microvolts to volts */ 629a6cdeefeSMike Looijmans if (of_property_read_u32(dev->of_node, "maxim,fan-prescale", 630a6cdeefeSMike Looijmans &prescale)) 631a6cdeefeSMike Looijmans prescale = prescaler; 632d20620deSHans-Juergen Koch 633d20620deSHans-Juergen Koch config = i2c_smbus_read_byte_data(client, MAX6650_REG_CONFIG); 634d20620deSHans-Juergen Koch 635d20620deSHans-Juergen Koch if (config < 0) { 63671ba0f31SGuenter Roeck dev_err(dev, "Error reading config, aborting.\n"); 637d20620deSHans-Juergen Koch return err; 638d20620deSHans-Juergen Koch } 639d20620deSHans-Juergen Koch 640a6cdeefeSMike Looijmans switch (voltage) { 641d20620deSHans-Juergen Koch case 0: 642d20620deSHans-Juergen Koch break; 643d20620deSHans-Juergen Koch case 5: 644d20620deSHans-Juergen Koch config &= ~MAX6650_CFG_V12; 645d20620deSHans-Juergen Koch break; 646d20620deSHans-Juergen Koch case 12: 647d20620deSHans-Juergen Koch config |= MAX6650_CFG_V12; 648d20620deSHans-Juergen Koch break; 649d20620deSHans-Juergen Koch default: 650a6cdeefeSMike Looijmans dev_err(dev, "illegal value for fan_voltage (%d)\n", voltage); 651d20620deSHans-Juergen Koch } 652d20620deSHans-Juergen Koch 653a6cdeefeSMike Looijmans switch (prescale) { 654d20620deSHans-Juergen Koch case 0: 655d20620deSHans-Juergen Koch break; 656d20620deSHans-Juergen Koch case 1: 657d20620deSHans-Juergen Koch config &= ~MAX6650_CFG_PRESCALER_MASK; 658d20620deSHans-Juergen Koch break; 659d20620deSHans-Juergen Koch case 2: 660d20620deSHans-Juergen Koch config = (config & ~MAX6650_CFG_PRESCALER_MASK) 661d20620deSHans-Juergen Koch | MAX6650_CFG_PRESCALER_2; 662d20620deSHans-Juergen Koch break; 663d20620deSHans-Juergen Koch case 4: 664d20620deSHans-Juergen Koch config = (config & ~MAX6650_CFG_PRESCALER_MASK) 665d20620deSHans-Juergen Koch | MAX6650_CFG_PRESCALER_4; 666d20620deSHans-Juergen Koch break; 667d20620deSHans-Juergen Koch case 8: 668d20620deSHans-Juergen Koch config = (config & ~MAX6650_CFG_PRESCALER_MASK) 669d20620deSHans-Juergen Koch | MAX6650_CFG_PRESCALER_8; 670d20620deSHans-Juergen Koch break; 671d20620deSHans-Juergen Koch case 16: 672d20620deSHans-Juergen Koch config = (config & ~MAX6650_CFG_PRESCALER_MASK) 673d20620deSHans-Juergen Koch | MAX6650_CFG_PRESCALER_16; 674d20620deSHans-Juergen Koch break; 675d20620deSHans-Juergen Koch default: 676a6cdeefeSMike Looijmans dev_err(dev, "illegal value for prescaler (%d)\n", prescale); 677d20620deSHans-Juergen Koch } 678d20620deSHans-Juergen Koch 679a6cdeefeSMike Looijmans dev_info(dev, "Fan voltage: %dV, prescaler: %d.\n", 680a6cdeefeSMike Looijmans (config & MAX6650_CFG_V12) ? 12 : 5, 681d20620deSHans-Juergen Koch 1 << (config & MAX6650_CFG_PRESCALER_MASK)); 682d20620deSHans-Juergen Koch 683d20620deSHans-Juergen Koch if (i2c_smbus_write_byte_data(client, MAX6650_REG_CONFIG, config)) { 68471ba0f31SGuenter Roeck dev_err(dev, "Config write error, aborting.\n"); 685d20620deSHans-Juergen Koch return err; 686d20620deSHans-Juergen Koch } 687d20620deSHans-Juergen Koch 688d20620deSHans-Juergen Koch data->config = config; 689d20620deSHans-Juergen Koch data->count = i2c_smbus_read_byte_data(client, MAX6650_REG_COUNT); 690d20620deSHans-Juergen Koch 69120005cc5SMike Looijmans if (!of_property_read_u32(client->dev.of_node, "maxim,fan-target-rpm", 69220005cc5SMike Looijmans &target_rpm)) { 69320005cc5SMike Looijmans max6650_set_target(data, target_rpm); 69420005cc5SMike Looijmans max6650_set_operating_mode(data, MAX6650_CFG_MODE_CLOSED_LOOP); 69520005cc5SMike Looijmans } 69620005cc5SMike Looijmans 697d20620deSHans-Juergen Koch return 0; 698d20620deSHans-Juergen Koch } 699d20620deSHans-Juergen Koch 7004f8d374bSJean-Francois Dagenais #if IS_ENABLED(CONFIG_THERMAL) 7014f8d374bSJean-Francois Dagenais 7024f8d374bSJean-Francois Dagenais static int max6650_get_max_state(struct thermal_cooling_device *cdev, 7034f8d374bSJean-Francois Dagenais unsigned long *state) 7044f8d374bSJean-Francois Dagenais { 7054f8d374bSJean-Francois Dagenais *state = 255; 7064f8d374bSJean-Francois Dagenais 7074f8d374bSJean-Francois Dagenais return 0; 7084f8d374bSJean-Francois Dagenais } 7094f8d374bSJean-Francois Dagenais 7104f8d374bSJean-Francois Dagenais static int max6650_get_cur_state(struct thermal_cooling_device *cdev, 7114f8d374bSJean-Francois Dagenais unsigned long *state) 7124f8d374bSJean-Francois Dagenais { 7134f8d374bSJean-Francois Dagenais struct max6650_data *data = cdev->devdata; 7144f8d374bSJean-Francois Dagenais 7154f8d374bSJean-Francois Dagenais *state = data->cooling_dev_state; 7164f8d374bSJean-Francois Dagenais 7174f8d374bSJean-Francois Dagenais return 0; 7184f8d374bSJean-Francois Dagenais } 7194f8d374bSJean-Francois Dagenais 7204f8d374bSJean-Francois Dagenais static int max6650_set_cur_state(struct thermal_cooling_device *cdev, 7214f8d374bSJean-Francois Dagenais unsigned long state) 7224f8d374bSJean-Francois Dagenais { 7234f8d374bSJean-Francois Dagenais struct max6650_data *data = cdev->devdata; 7244f8d374bSJean-Francois Dagenais struct i2c_client *client = data->client; 7254f8d374bSJean-Francois Dagenais int err; 7264f8d374bSJean-Francois Dagenais 7274f8d374bSJean-Francois Dagenais state = clamp_val(state, 0, 255); 7284f8d374bSJean-Francois Dagenais 7294f8d374bSJean-Francois Dagenais mutex_lock(&data->update_lock); 7304f8d374bSJean-Francois Dagenais 7314f8d374bSJean-Francois Dagenais if (data->config & MAX6650_CFG_V12) 7324f8d374bSJean-Francois Dagenais data->dac = 180 - (180 * state)/255; 7334f8d374bSJean-Francois Dagenais else 7344f8d374bSJean-Francois Dagenais data->dac = 76 - (76 * state)/255; 7354f8d374bSJean-Francois Dagenais 7364f8d374bSJean-Francois Dagenais err = i2c_smbus_write_byte_data(client, MAX6650_REG_DAC, data->dac); 7374f8d374bSJean-Francois Dagenais 7384f8d374bSJean-Francois Dagenais if (!err) { 7394f8d374bSJean-Francois Dagenais max6650_set_operating_mode(data, state ? 7404f8d374bSJean-Francois Dagenais MAX6650_CFG_MODE_OPEN_LOOP : 7414f8d374bSJean-Francois Dagenais MAX6650_CFG_MODE_OFF); 7424f8d374bSJean-Francois Dagenais data->cooling_dev_state = state; 7434f8d374bSJean-Francois Dagenais } 7444f8d374bSJean-Francois Dagenais 7454f8d374bSJean-Francois Dagenais mutex_unlock(&data->update_lock); 7464f8d374bSJean-Francois Dagenais 7474f8d374bSJean-Francois Dagenais return err < 0 ? err : 0; 7484f8d374bSJean-Francois Dagenais } 7494f8d374bSJean-Francois Dagenais 7504f8d374bSJean-Francois Dagenais static const struct thermal_cooling_device_ops max6650_cooling_ops = { 7514f8d374bSJean-Francois Dagenais .get_max_state = max6650_get_max_state, 7524f8d374bSJean-Francois Dagenais .get_cur_state = max6650_get_cur_state, 7534f8d374bSJean-Francois Dagenais .set_cur_state = max6650_set_cur_state, 7544f8d374bSJean-Francois Dagenais }; 7554f8d374bSJean-Francois Dagenais #endif 7564f8d374bSJean-Francois Dagenais 7571577f94bSGuenter Roeck static int max6650_probe(struct i2c_client *client, 7581577f94bSGuenter Roeck const struct i2c_device_id *id) 759d20620deSHans-Juergen Koch { 76071ba0f31SGuenter Roeck struct device *dev = &client->dev; 761a6cdeefeSMike Looijmans const struct of_device_id *of_id = 762a6cdeefeSMike Looijmans of_match_device(of_match_ptr(max6650_dt_match), dev); 7631577f94bSGuenter Roeck struct max6650_data *data; 76417eaa25cSGuenter Roeck struct device *hwmon_dev; 7651577f94bSGuenter Roeck int err; 766d20620deSHans-Juergen Koch 76771ba0f31SGuenter Roeck data = devm_kzalloc(dev, sizeof(struct max6650_data), GFP_KERNEL); 7680b5e33b6SGuenter Roeck if (!data) 7691577f94bSGuenter Roeck return -ENOMEM; 7701577f94bSGuenter Roeck 77117eaa25cSGuenter Roeck data->client = client; 7724f8d374bSJean-Francois Dagenais i2c_set_clientdata(client, data); 7731577f94bSGuenter Roeck mutex_init(&data->update_lock); 774a6cdeefeSMike Looijmans data->nr_fans = of_id ? (int)(uintptr_t)of_id->data : id->driver_data; 775d20620deSHans-Juergen Koch 776703af960SGuenter Roeck /* 7771577f94bSGuenter Roeck * Initialize the max6650 chip 778703af960SGuenter Roeck */ 77917eaa25cSGuenter Roeck err = max6650_init_client(data, client); 7801577f94bSGuenter Roeck if (err) 7811577f94bSGuenter Roeck return err; 78252b5226fSChristian Engelmayer 78317eaa25cSGuenter Roeck data->groups[0] = &max6650_group; 7841577f94bSGuenter Roeck /* 3 additional fan inputs for the MAX6651 */ 7851577f94bSGuenter Roeck if (data->nr_fans == 4) 78617eaa25cSGuenter Roeck data->groups[1] = &max6651_group; 787d20620deSHans-Juergen Koch 78871ba0f31SGuenter Roeck hwmon_dev = devm_hwmon_device_register_with_groups(dev, 78917eaa25cSGuenter Roeck client->name, data, 79017eaa25cSGuenter Roeck data->groups); 7914f8d374bSJean-Francois Dagenais err = PTR_ERR_OR_ZERO(hwmon_dev); 7924f8d374bSJean-Francois Dagenais if (err) 7934f8d374bSJean-Francois Dagenais return err; 7944f8d374bSJean-Francois Dagenais 7954f8d374bSJean-Francois Dagenais #if IS_ENABLED(CONFIG_THERMAL) 7964f8d374bSJean-Francois Dagenais data->cooling_dev = 7974f8d374bSJean-Francois Dagenais thermal_of_cooling_device_register(client->dev.of_node, 7984f8d374bSJean-Francois Dagenais client->name, data, 7994f8d374bSJean-Francois Dagenais &max6650_cooling_ops); 8004f8d374bSJean-Francois Dagenais if (IS_ERR(data->cooling_dev)) 8014f8d374bSJean-Francois Dagenais dev_warn(&client->dev, 8024f8d374bSJean-Francois Dagenais "thermal cooling device register failed: %ld\n", 8034f8d374bSJean-Francois Dagenais PTR_ERR(data->cooling_dev)); 8044f8d374bSJean-Francois Dagenais else 8054f8d374bSJean-Francois Dagenais thermal_cdev_update(data->cooling_dev); 8064f8d374bSJean-Francois Dagenais #endif 8074f8d374bSJean-Francois Dagenais return 0; 8084f8d374bSJean-Francois Dagenais } 8094f8d374bSJean-Francois Dagenais 8104f8d374bSJean-Francois Dagenais static int max6650_remove(struct i2c_client *client) 8114f8d374bSJean-Francois Dagenais { 8124f8d374bSJean-Francois Dagenais struct max6650_data *data = i2c_get_clientdata(client); 8134f8d374bSJean-Francois Dagenais 8144f8d374bSJean-Francois Dagenais if (!IS_ERR(data->cooling_dev)) 8154f8d374bSJean-Francois Dagenais thermal_cooling_device_unregister(data->cooling_dev); 8164f8d374bSJean-Francois Dagenais 8174f8d374bSJean-Francois Dagenais return 0; 8181577f94bSGuenter Roeck } 8191577f94bSGuenter Roeck 8201577f94bSGuenter Roeck static const struct i2c_device_id max6650_id[] = { 8211577f94bSGuenter Roeck { "max6650", 1 }, 8221577f94bSGuenter Roeck { "max6651", 4 }, 8231577f94bSGuenter Roeck { } 8241577f94bSGuenter Roeck }; 8251577f94bSGuenter Roeck MODULE_DEVICE_TABLE(i2c, max6650_id); 8261577f94bSGuenter Roeck 8271577f94bSGuenter Roeck static struct i2c_driver max6650_driver = { 8281577f94bSGuenter Roeck .driver = { 8291577f94bSGuenter Roeck .name = "max6650", 830a6cdeefeSMike Looijmans .of_match_table = of_match_ptr(max6650_dt_match), 8311577f94bSGuenter Roeck }, 8321577f94bSGuenter Roeck .probe = max6650_probe, 8334f8d374bSJean-Francois Dagenais .remove = max6650_remove, 8341577f94bSGuenter Roeck .id_table = max6650_id, 8351577f94bSGuenter Roeck }; 8361577f94bSGuenter Roeck 837f0967eeaSAxel Lin module_i2c_driver(max6650_driver); 838d20620deSHans-Juergen Koch 839d20620deSHans-Juergen Koch MODULE_AUTHOR("Hans J. Koch"); 840d20620deSHans-Juergen Koch MODULE_DESCRIPTION("MAX6650 sensor driver"); 841d20620deSHans-Juergen Koch MODULE_LICENSE("GPL"); 842