174ba9207SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later 2a5b79d62Sstigge@antcom.de /* 3a5b79d62Sstigge@antcom.de * max6639.c - Support for Maxim MAX6639 4a5b79d62Sstigge@antcom.de * 5a5b79d62Sstigge@antcom.de * 2-Channel Temperature Monitor with Dual PWM Fan-Speed Controller 6a5b79d62Sstigge@antcom.de * 7a5b79d62Sstigge@antcom.de * Copyright (C) 2010, 2011 Roland Stigge <stigge@antcom.de> 8a5b79d62Sstigge@antcom.de * 9a5b79d62Sstigge@antcom.de * based on the initial MAX6639 support from semptian.net 10a5b79d62Sstigge@antcom.de * by He Changqing <hechangqing@semptian.com> 11a5b79d62Sstigge@antcom.de */ 12a5b79d62Sstigge@antcom.de 13a5b79d62Sstigge@antcom.de #include <linux/module.h> 14a5b79d62Sstigge@antcom.de #include <linux/init.h> 15a5b79d62Sstigge@antcom.de #include <linux/slab.h> 16a5b79d62Sstigge@antcom.de #include <linux/jiffies.h> 17a5b79d62Sstigge@antcom.de #include <linux/i2c.h> 18a5b79d62Sstigge@antcom.de #include <linux/hwmon.h> 19a5b79d62Sstigge@antcom.de #include <linux/hwmon-sysfs.h> 20a5b79d62Sstigge@antcom.de #include <linux/err.h> 21a5b79d62Sstigge@antcom.de #include <linux/mutex.h> 220c9fe161SWolfram Sang #include <linux/platform_data/max6639.h> 2345bf8305SNaresh Solanki #include <linux/regmap.h> 240f33272bSNaresh Solanki #include <linux/util_macros.h> 25a5b79d62Sstigge@antcom.de 26a5b79d62Sstigge@antcom.de /* Addresses to scan */ 277edc8cc1SAxel Lin static const unsigned short normal_i2c[] = { 0x2c, 0x2e, 0x2f, I2C_CLIENT_END }; 28a5b79d62Sstigge@antcom.de 29a5b79d62Sstigge@antcom.de /* The MAX6639 registers, valid channel numbers: 0, 1 */ 30a5b79d62Sstigge@antcom.de #define MAX6639_REG_TEMP(ch) (0x00 + (ch)) 31a5b79d62Sstigge@antcom.de #define MAX6639_REG_STATUS 0x02 32a5b79d62Sstigge@antcom.de #define MAX6639_REG_OUTPUT_MASK 0x03 33a5b79d62Sstigge@antcom.de #define MAX6639_REG_GCONFIG 0x04 34a5b79d62Sstigge@antcom.de #define MAX6639_REG_TEMP_EXT(ch) (0x05 + (ch)) 35a5b79d62Sstigge@antcom.de #define MAX6639_REG_ALERT_LIMIT(ch) (0x08 + (ch)) 36a5b79d62Sstigge@antcom.de #define MAX6639_REG_OT_LIMIT(ch) (0x0A + (ch)) 37a5b79d62Sstigge@antcom.de #define MAX6639_REG_THERM_LIMIT(ch) (0x0C + (ch)) 38a5b79d62Sstigge@antcom.de #define MAX6639_REG_FAN_CONFIG1(ch) (0x10 + (ch) * 4) 39a5b79d62Sstigge@antcom.de #define MAX6639_REG_FAN_CONFIG2a(ch) (0x11 + (ch) * 4) 40a5b79d62Sstigge@antcom.de #define MAX6639_REG_FAN_CONFIG2b(ch) (0x12 + (ch) * 4) 41a5b79d62Sstigge@antcom.de #define MAX6639_REG_FAN_CONFIG3(ch) (0x13 + (ch) * 4) 42a5b79d62Sstigge@antcom.de #define MAX6639_REG_FAN_CNT(ch) (0x20 + (ch)) 43a5b79d62Sstigge@antcom.de #define MAX6639_REG_TARGET_CNT(ch) (0x22 + (ch)) 44a5b79d62Sstigge@antcom.de #define MAX6639_REG_FAN_PPR(ch) (0x24 + (ch)) 45a5b79d62Sstigge@antcom.de #define MAX6639_REG_TARGTDUTY(ch) (0x26 + (ch)) 46a5b79d62Sstigge@antcom.de #define MAX6639_REG_FAN_START_TEMP(ch) (0x28 + (ch)) 47a5b79d62Sstigge@antcom.de #define MAX6639_REG_DEVID 0x3D 48a5b79d62Sstigge@antcom.de #define MAX6639_REG_MANUID 0x3E 49a5b79d62Sstigge@antcom.de #define MAX6639_REG_DEVREV 0x3F 50a5b79d62Sstigge@antcom.de 51a5b79d62Sstigge@antcom.de /* Register bits */ 52a5b79d62Sstigge@antcom.de #define MAX6639_GCONFIG_STANDBY 0x80 53a5b79d62Sstigge@antcom.de #define MAX6639_GCONFIG_POR 0x40 54a5b79d62Sstigge@antcom.de #define MAX6639_GCONFIG_DISABLE_TIMEOUT 0x20 55a5b79d62Sstigge@antcom.de #define MAX6639_GCONFIG_CH2_LOCAL 0x10 56177f3b92Sstigge@antcom.de #define MAX6639_GCONFIG_PWM_FREQ_HI 0x08 57a5b79d62Sstigge@antcom.de 58a5b79d62Sstigge@antcom.de #define MAX6639_FAN_CONFIG1_PWM 0x80 590f33272bSNaresh Solanki #define MAX6639_FAN_CONFIG3_FREQ_MASK 0x03 60177f3b92Sstigge@antcom.de #define MAX6639_FAN_CONFIG3_THERM_FULL_SPEED 0x40 61177f3b92Sstigge@antcom.de 6245bf8305SNaresh Solanki #define MAX6639_NUM_CHANNELS 2 6345bf8305SNaresh Solanki 64a5b79d62Sstigge@antcom.de static const int rpm_ranges[] = { 2000, 4000, 8000, 16000 }; 65a5b79d62Sstigge@antcom.de 660f33272bSNaresh Solanki /* Supported PWM frequency */ 670f33272bSNaresh Solanki static const unsigned int freq_table[] = { 20, 33, 50, 100, 5000, 8333, 12500, 680f33272bSNaresh Solanki 25000 }; 690f33272bSNaresh Solanki 70b63d97a3SChris D Schimp #define FAN_FROM_REG(val, rpm_range) ((val) == 0 || (val) == 255 ? \ 71b63d97a3SChris D Schimp 0 : (rpm_ranges[rpm_range] * 30) / (val)) 722a844c14SGuenter Roeck #define TEMP_LIMIT_TO_REG(val) clamp_val((val) / 1000, 0, 255) 73a5b79d62Sstigge@antcom.de 74a5b79d62Sstigge@antcom.de /* 75a5b79d62Sstigge@antcom.de * Client data (each client gets its own) 76a5b79d62Sstigge@antcom.de */ 77a5b79d62Sstigge@antcom.de struct max6639_data { 7845bf8305SNaresh Solanki struct regmap *regmap; 79*842b4d98SNaresh Solanki struct mutex update_lock; 80a5b79d62Sstigge@antcom.de 81a5b79d62Sstigge@antcom.de /* Register values initialized only once */ 820f33272bSNaresh Solanki u8 ppr[MAX6639_NUM_CHANNELS]; /* Pulses per rotation 0..3 for 1..4 ppr */ 830f33272bSNaresh Solanki u8 rpm_range[MAX6639_NUM_CHANNELS]; /* Index in above rpm_ranges table */ 844e2271eaSMarcello Sylvester Bauer 854e2271eaSMarcello Sylvester Bauer /* Optional regulator for FAN supply */ 864e2271eaSMarcello Sylvester Bauer struct regulator *reg; 87a5b79d62Sstigge@antcom.de }; 88a5b79d62Sstigge@antcom.de 890f33272bSNaresh Solanki static int max6639_temp_read_input(struct device *dev, int channel, long *temp) 90a5b79d62Sstigge@antcom.de { 9145bf8305SNaresh Solanki struct max6639_data *data = dev_get_drvdata(dev); 9245bf8305SNaresh Solanki unsigned int val; 9345bf8305SNaresh Solanki int res; 94a5b79d62Sstigge@antcom.de 9545bf8305SNaresh Solanki /* 9645bf8305SNaresh Solanki * Lock isn't needed as MAX6639_REG_TEMP wpnt change for at least 250ms after reading 9745bf8305SNaresh Solanki * MAX6639_REG_TEMP_EXT 9845bf8305SNaresh Solanki */ 990f33272bSNaresh Solanki res = regmap_read(data->regmap, MAX6639_REG_TEMP_EXT(channel), &val); 10045bf8305SNaresh Solanki if (res < 0) 10145bf8305SNaresh Solanki return res; 102a5b79d62Sstigge@antcom.de 1030f33272bSNaresh Solanki *temp = val >> 5; 1040f33272bSNaresh Solanki res = regmap_read(data->regmap, MAX6639_REG_TEMP(channel), &val); 10545bf8305SNaresh Solanki if (res < 0) 10645bf8305SNaresh Solanki return res; 10745bf8305SNaresh Solanki 1080f33272bSNaresh Solanki *temp |= val << 3; 1090f33272bSNaresh Solanki *temp *= 125; 11045bf8305SNaresh Solanki 1110f33272bSNaresh Solanki return 0; 112a5b79d62Sstigge@antcom.de } 113a5b79d62Sstigge@antcom.de 1140f33272bSNaresh Solanki static int max6639_temp_read_fault(struct device *dev, int channel, long *fault) 115a5b79d62Sstigge@antcom.de { 11645bf8305SNaresh Solanki struct max6639_data *data = dev_get_drvdata(dev); 11745bf8305SNaresh Solanki unsigned int val; 11845bf8305SNaresh Solanki int res; 119a5b79d62Sstigge@antcom.de 1200f33272bSNaresh Solanki res = regmap_read(data->regmap, MAX6639_REG_TEMP_EXT(channel), &val); 12145bf8305SNaresh Solanki if (res < 0) 12245bf8305SNaresh Solanki return res; 12345bf8305SNaresh Solanki 1240f33272bSNaresh Solanki *fault = val & 1; 1250f33272bSNaresh Solanki 1260f33272bSNaresh Solanki return 0; 127a5b79d62Sstigge@antcom.de } 128a5b79d62Sstigge@antcom.de 1290f33272bSNaresh Solanki static int max6639_temp_read_max(struct device *dev, int channel, long *max) 130a5b79d62Sstigge@antcom.de { 1317981c584SGuenter Roeck struct max6639_data *data = dev_get_drvdata(dev); 13245bf8305SNaresh Solanki unsigned int val; 13345bf8305SNaresh Solanki int res; 134a5b79d62Sstigge@antcom.de 1350f33272bSNaresh Solanki res = regmap_read(data->regmap, MAX6639_REG_THERM_LIMIT(channel), &val); 13645bf8305SNaresh Solanki if (res < 0) 13745bf8305SNaresh Solanki return res; 13845bf8305SNaresh Solanki 1390f33272bSNaresh Solanki *max = (long)val * 1000; 1400f33272bSNaresh Solanki 1410f33272bSNaresh Solanki return 0; 142a5b79d62Sstigge@antcom.de } 143a5b79d62Sstigge@antcom.de 1440f33272bSNaresh Solanki static int max6639_temp_read_crit(struct device *dev, int channel, long *crit) 145a5b79d62Sstigge@antcom.de { 1467981c584SGuenter Roeck struct max6639_data *data = dev_get_drvdata(dev); 14745bf8305SNaresh Solanki unsigned int val; 14845bf8305SNaresh Solanki int res; 149a5b79d62Sstigge@antcom.de 1500f33272bSNaresh Solanki res = regmap_read(data->regmap, MAX6639_REG_ALERT_LIMIT(channel), &val); 15145bf8305SNaresh Solanki if (res < 0) 15245bf8305SNaresh Solanki return res; 15345bf8305SNaresh Solanki 1540f33272bSNaresh Solanki *crit = (long)val * 1000; 1550f33272bSNaresh Solanki 1560f33272bSNaresh Solanki return 0; 157a5b79d62Sstigge@antcom.de } 158a5b79d62Sstigge@antcom.de 1590f33272bSNaresh Solanki static int max6639_temp_read_emergency(struct device *dev, int channel, long *emerg) 160a5b79d62Sstigge@antcom.de { 1617981c584SGuenter Roeck struct max6639_data *data = dev_get_drvdata(dev); 16245bf8305SNaresh Solanki unsigned int val; 16345bf8305SNaresh Solanki int res; 164a5b79d62Sstigge@antcom.de 1650f33272bSNaresh Solanki res = regmap_read(data->regmap, MAX6639_REG_OT_LIMIT(channel), &val); 16645bf8305SNaresh Solanki if (res < 0) 16745bf8305SNaresh Solanki return res; 16845bf8305SNaresh Solanki 1690f33272bSNaresh Solanki *emerg = (long)val * 1000; 1700f33272bSNaresh Solanki 1710f33272bSNaresh Solanki return 0; 172a5b79d62Sstigge@antcom.de } 173a5b79d62Sstigge@antcom.de 1740f33272bSNaresh Solanki static int max6639_get_status(struct device *dev, unsigned int *status) 175a5b79d62Sstigge@antcom.de { 17645bf8305SNaresh Solanki struct max6639_data *data = dev_get_drvdata(dev); 17745bf8305SNaresh Solanki unsigned int val; 17845bf8305SNaresh Solanki int res; 179a5b79d62Sstigge@antcom.de 18045bf8305SNaresh Solanki res = regmap_read(data->regmap, MAX6639_REG_STATUS, &val); 18145bf8305SNaresh Solanki if (res < 0) 18245bf8305SNaresh Solanki return res; 183a5b79d62Sstigge@antcom.de 1840f33272bSNaresh Solanki *status = val; 1850f33272bSNaresh Solanki 1860f33272bSNaresh Solanki return 0; 187a5b79d62Sstigge@antcom.de } 188a5b79d62Sstigge@antcom.de 1890f33272bSNaresh Solanki static int max6639_temp_set_max(struct max6639_data *data, int channel, long val) 1900f33272bSNaresh Solanki { 1910f33272bSNaresh Solanki int res; 192a5b79d62Sstigge@antcom.de 1930f33272bSNaresh Solanki res = regmap_write(data->regmap, MAX6639_REG_THERM_LIMIT(channel), 1940f33272bSNaresh Solanki TEMP_LIMIT_TO_REG(val)); 1950f33272bSNaresh Solanki return res; 1960f33272bSNaresh Solanki } 197a5b79d62Sstigge@antcom.de 1980f33272bSNaresh Solanki static int max6639_temp_set_crit(struct max6639_data *data, int channel, long val) 1990f33272bSNaresh Solanki { 2000f33272bSNaresh Solanki int res; 2010f33272bSNaresh Solanki 2020f33272bSNaresh Solanki res = regmap_write(data->regmap, MAX6639_REG_ALERT_LIMIT(channel), TEMP_LIMIT_TO_REG(val)); 2030f33272bSNaresh Solanki 2040f33272bSNaresh Solanki return res; 2050f33272bSNaresh Solanki } 2060f33272bSNaresh Solanki 2070f33272bSNaresh Solanki static int max6639_temp_set_emergency(struct max6639_data *data, int channel, long val) 2080f33272bSNaresh Solanki { 2090f33272bSNaresh Solanki int res; 2100f33272bSNaresh Solanki 2110f33272bSNaresh Solanki res = regmap_write(data->regmap, MAX6639_REG_OT_LIMIT(channel), TEMP_LIMIT_TO_REG(val)); 2120f33272bSNaresh Solanki 2130f33272bSNaresh Solanki return res; 2140f33272bSNaresh Solanki } 2150f33272bSNaresh Solanki 2160f33272bSNaresh Solanki static int max6639_read_fan(struct device *dev, u32 attr, int channel, 2170f33272bSNaresh Solanki long *fan_val) 2180f33272bSNaresh Solanki { 2190f33272bSNaresh Solanki struct max6639_data *data = dev_get_drvdata(dev); 2200f33272bSNaresh Solanki unsigned int val; 2210f33272bSNaresh Solanki int res; 2220f33272bSNaresh Solanki 2230f33272bSNaresh Solanki switch (attr) { 2240f33272bSNaresh Solanki case hwmon_fan_input: 2250f33272bSNaresh Solanki res = regmap_read(data->regmap, MAX6639_REG_FAN_CNT(channel), &val); 2260f33272bSNaresh Solanki if (res < 0) 2270f33272bSNaresh Solanki return res; 2280f33272bSNaresh Solanki *fan_val = FAN_FROM_REG(val, data->rpm_range[channel]); 2290f33272bSNaresh Solanki return 0; 2300f33272bSNaresh Solanki case hwmon_fan_fault: 2310f33272bSNaresh Solanki res = max6639_get_status(dev, &val); 2320f33272bSNaresh Solanki if (res < 0) 2330f33272bSNaresh Solanki return res; 2340f33272bSNaresh Solanki *fan_val = !!(val & BIT(1 - channel)); 2350f33272bSNaresh Solanki return 0; 236*842b4d98SNaresh Solanki case hwmon_fan_pulses: 237*842b4d98SNaresh Solanki *fan_val = data->ppr[channel]; 238*842b4d98SNaresh Solanki return 0; 2390f33272bSNaresh Solanki default: 2400f33272bSNaresh Solanki return -EOPNOTSUPP; 2410f33272bSNaresh Solanki } 2420f33272bSNaresh Solanki } 2430f33272bSNaresh Solanki 2440f33272bSNaresh Solanki static int max6639_set_ppr(struct max6639_data *data, int channel, u8 ppr) 2450f33272bSNaresh Solanki { 2460f33272bSNaresh Solanki /* Decrement the PPR value and shift left by 6 to match the register format */ 2470f33272bSNaresh Solanki return regmap_write(data->regmap, MAX6639_REG_FAN_PPR(channel), ppr-- << 6); 2480f33272bSNaresh Solanki } 2490f33272bSNaresh Solanki 250*842b4d98SNaresh Solanki static int max6639_write_fan(struct device *dev, u32 attr, int channel, 251*842b4d98SNaresh Solanki long val) 252*842b4d98SNaresh Solanki { 253*842b4d98SNaresh Solanki struct max6639_data *data = dev_get_drvdata(dev); 254*842b4d98SNaresh Solanki int err; 255*842b4d98SNaresh Solanki 256*842b4d98SNaresh Solanki switch (attr) { 257*842b4d98SNaresh Solanki case hwmon_fan_pulses: 258*842b4d98SNaresh Solanki if (val <= 0 || val > 4) 259*842b4d98SNaresh Solanki return -EINVAL; 260*842b4d98SNaresh Solanki 261*842b4d98SNaresh Solanki mutex_lock(&data->update_lock); 262*842b4d98SNaresh Solanki /* Set Fan pulse per revolution */ 263*842b4d98SNaresh Solanki err = max6639_set_ppr(data, channel, val); 264*842b4d98SNaresh Solanki if (err < 0) { 265*842b4d98SNaresh Solanki mutex_unlock(&data->update_lock); 266*842b4d98SNaresh Solanki return err; 267*842b4d98SNaresh Solanki } 268*842b4d98SNaresh Solanki data->ppr[channel] = val; 269*842b4d98SNaresh Solanki 270*842b4d98SNaresh Solanki mutex_unlock(&data->update_lock); 271*842b4d98SNaresh Solanki return 0; 272*842b4d98SNaresh Solanki default: 273*842b4d98SNaresh Solanki return -EOPNOTSUPP; 274*842b4d98SNaresh Solanki } 275*842b4d98SNaresh Solanki } 276*842b4d98SNaresh Solanki 2770f33272bSNaresh Solanki static umode_t max6639_fan_is_visible(const void *_data, u32 attr, int channel) 2780f33272bSNaresh Solanki { 2790f33272bSNaresh Solanki switch (attr) { 2800f33272bSNaresh Solanki case hwmon_fan_input: 2810f33272bSNaresh Solanki case hwmon_fan_fault: 2820f33272bSNaresh Solanki return 0444; 2830f33272bSNaresh Solanki case hwmon_fan_pulses: 2840f33272bSNaresh Solanki return 0644; 2850f33272bSNaresh Solanki default: 2860f33272bSNaresh Solanki return 0; 2870f33272bSNaresh Solanki } 2880f33272bSNaresh Solanki } 2890f33272bSNaresh Solanki 2900f33272bSNaresh Solanki static int max6639_read_pwm(struct device *dev, u32 attr, int channel, 2910f33272bSNaresh Solanki long *pwm_val) 2920f33272bSNaresh Solanki { 2930f33272bSNaresh Solanki struct max6639_data *data = dev_get_drvdata(dev); 2940f33272bSNaresh Solanki unsigned int val; 2950f33272bSNaresh Solanki int res; 296*842b4d98SNaresh Solanki u8 i; 2970f33272bSNaresh Solanki 2980f33272bSNaresh Solanki switch (attr) { 2990f33272bSNaresh Solanki case hwmon_pwm_input: 3000f33272bSNaresh Solanki res = regmap_read(data->regmap, MAX6639_REG_TARGTDUTY(channel), &val); 3010f33272bSNaresh Solanki if (res < 0) 3020f33272bSNaresh Solanki return res; 3030f33272bSNaresh Solanki *pwm_val = val * 255 / 120; 3040f33272bSNaresh Solanki return 0; 305*842b4d98SNaresh Solanki case hwmon_pwm_freq: 306*842b4d98SNaresh Solanki mutex_lock(&data->update_lock); 307*842b4d98SNaresh Solanki res = regmap_read(data->regmap, MAX6639_REG_FAN_CONFIG3(channel), &val); 308*842b4d98SNaresh Solanki if (res < 0) { 309*842b4d98SNaresh Solanki mutex_unlock(&data->update_lock); 310*842b4d98SNaresh Solanki return res; 311*842b4d98SNaresh Solanki } 312*842b4d98SNaresh Solanki i = val & MAX6639_FAN_CONFIG3_FREQ_MASK; 313*842b4d98SNaresh Solanki 314*842b4d98SNaresh Solanki res = regmap_read(data->regmap, MAX6639_REG_GCONFIG, &val); 315*842b4d98SNaresh Solanki if (res < 0) { 316*842b4d98SNaresh Solanki mutex_unlock(&data->update_lock); 317*842b4d98SNaresh Solanki return res; 318*842b4d98SNaresh Solanki } 319*842b4d98SNaresh Solanki 320*842b4d98SNaresh Solanki if (val & MAX6639_GCONFIG_PWM_FREQ_HI) 321*842b4d98SNaresh Solanki i |= 0x4; 322*842b4d98SNaresh Solanki i &= 0x7; 323*842b4d98SNaresh Solanki *pwm_val = freq_table[i]; 324*842b4d98SNaresh Solanki 325*842b4d98SNaresh Solanki mutex_unlock(&data->update_lock); 326*842b4d98SNaresh Solanki return 0; 3270f33272bSNaresh Solanki default: 3280f33272bSNaresh Solanki return -EOPNOTSUPP; 3290f33272bSNaresh Solanki } 3300f33272bSNaresh Solanki } 3310f33272bSNaresh Solanki 3320f33272bSNaresh Solanki static int max6639_write_pwm(struct device *dev, u32 attr, int channel, 3330f33272bSNaresh Solanki long val) 3340f33272bSNaresh Solanki { 3350f33272bSNaresh Solanki struct max6639_data *data = dev_get_drvdata(dev); 3360f33272bSNaresh Solanki int err; 337*842b4d98SNaresh Solanki u8 i; 3380f33272bSNaresh Solanki 3390f33272bSNaresh Solanki switch (attr) { 3400f33272bSNaresh Solanki case hwmon_pwm_input: 3410f33272bSNaresh Solanki if (val < 0 || val > 255) 3420f33272bSNaresh Solanki return -EINVAL; 3430f33272bSNaresh Solanki err = regmap_write(data->regmap, MAX6639_REG_TARGTDUTY(channel), 3440f33272bSNaresh Solanki val * 120 / 255); 3450f33272bSNaresh Solanki return err; 346*842b4d98SNaresh Solanki case hwmon_pwm_freq: 347*842b4d98SNaresh Solanki val = clamp_val(val, 0, 25000); 348*842b4d98SNaresh Solanki 349*842b4d98SNaresh Solanki i = find_closest(val, freq_table, ARRAY_SIZE(freq_table)); 350*842b4d98SNaresh Solanki 351*842b4d98SNaresh Solanki mutex_lock(&data->update_lock); 352*842b4d98SNaresh Solanki err = regmap_update_bits(data->regmap, MAX6639_REG_FAN_CONFIG3(channel), 353*842b4d98SNaresh Solanki MAX6639_FAN_CONFIG3_FREQ_MASK, i); 354*842b4d98SNaresh Solanki if (err < 0) { 355*842b4d98SNaresh Solanki mutex_unlock(&data->update_lock); 356*842b4d98SNaresh Solanki return err; 357*842b4d98SNaresh Solanki } 358*842b4d98SNaresh Solanki 359*842b4d98SNaresh Solanki if (i >> 2) 360*842b4d98SNaresh Solanki err = regmap_set_bits(data->regmap, MAX6639_REG_GCONFIG, 361*842b4d98SNaresh Solanki MAX6639_GCONFIG_PWM_FREQ_HI); 362*842b4d98SNaresh Solanki else 363*842b4d98SNaresh Solanki err = regmap_clear_bits(data->regmap, MAX6639_REG_GCONFIG, 364*842b4d98SNaresh Solanki MAX6639_GCONFIG_PWM_FREQ_HI); 365*842b4d98SNaresh Solanki 366*842b4d98SNaresh Solanki mutex_unlock(&data->update_lock); 367*842b4d98SNaresh Solanki return err; 3680f33272bSNaresh Solanki default: 3690f33272bSNaresh Solanki return -EOPNOTSUPP; 3700f33272bSNaresh Solanki } 3710f33272bSNaresh Solanki } 3720f33272bSNaresh Solanki 3730f33272bSNaresh Solanki static umode_t max6639_pwm_is_visible(const void *_data, u32 attr, int channel) 3740f33272bSNaresh Solanki { 3750f33272bSNaresh Solanki switch (attr) { 3760f33272bSNaresh Solanki case hwmon_pwm_input: 377*842b4d98SNaresh Solanki case hwmon_pwm_freq: 3780f33272bSNaresh Solanki return 0644; 3790f33272bSNaresh Solanki default: 3800f33272bSNaresh Solanki return 0; 3810f33272bSNaresh Solanki } 3820f33272bSNaresh Solanki } 3830f33272bSNaresh Solanki 3840f33272bSNaresh Solanki static int max6639_read_temp(struct device *dev, u32 attr, int channel, 3850f33272bSNaresh Solanki long *val) 3860f33272bSNaresh Solanki { 3870f33272bSNaresh Solanki unsigned int status; 3880f33272bSNaresh Solanki int res; 3890f33272bSNaresh Solanki 3900f33272bSNaresh Solanki switch (attr) { 3910f33272bSNaresh Solanki case hwmon_temp_input: 3920f33272bSNaresh Solanki res = max6639_temp_read_input(dev, channel, val); 3930f33272bSNaresh Solanki return res; 3940f33272bSNaresh Solanki case hwmon_temp_fault: 3950f33272bSNaresh Solanki res = max6639_temp_read_fault(dev, channel, val); 3960f33272bSNaresh Solanki return res; 3970f33272bSNaresh Solanki case hwmon_temp_max: 3980f33272bSNaresh Solanki res = max6639_temp_read_max(dev, channel, val); 3990f33272bSNaresh Solanki return res; 4000f33272bSNaresh Solanki case hwmon_temp_crit: 4010f33272bSNaresh Solanki res = max6639_temp_read_crit(dev, channel, val); 4020f33272bSNaresh Solanki return res; 4030f33272bSNaresh Solanki case hwmon_temp_emergency: 4040f33272bSNaresh Solanki res = max6639_temp_read_emergency(dev, channel, val); 4050f33272bSNaresh Solanki return res; 4060f33272bSNaresh Solanki case hwmon_temp_max_alarm: 4070f33272bSNaresh Solanki res = max6639_get_status(dev, &status); 4080f33272bSNaresh Solanki if (res < 0) 4090f33272bSNaresh Solanki return res; 4100f33272bSNaresh Solanki *val = !!(status & BIT(3 - channel)); 4110f33272bSNaresh Solanki return 0; 4120f33272bSNaresh Solanki case hwmon_temp_crit_alarm: 4130f33272bSNaresh Solanki res = max6639_get_status(dev, &status); 4140f33272bSNaresh Solanki if (res < 0) 4150f33272bSNaresh Solanki return res; 4160f33272bSNaresh Solanki *val = !!(status & BIT(7 - channel)); 4170f33272bSNaresh Solanki return 0; 4180f33272bSNaresh Solanki case hwmon_temp_emergency_alarm: 4190f33272bSNaresh Solanki res = max6639_get_status(dev, &status); 4200f33272bSNaresh Solanki if (res < 0) 4210f33272bSNaresh Solanki return res; 4220f33272bSNaresh Solanki *val = !!(status & BIT(5 - channel)); 4230f33272bSNaresh Solanki return 0; 4240f33272bSNaresh Solanki default: 4250f33272bSNaresh Solanki return -EOPNOTSUPP; 4260f33272bSNaresh Solanki } 4270f33272bSNaresh Solanki } 4280f33272bSNaresh Solanki 4290f33272bSNaresh Solanki static int max6639_write_temp(struct device *dev, u32 attr, int channel, 4300f33272bSNaresh Solanki long val) 4310f33272bSNaresh Solanki { 4320f33272bSNaresh Solanki struct max6639_data *data = dev_get_drvdata(dev); 4330f33272bSNaresh Solanki 4340f33272bSNaresh Solanki switch (attr) { 4350f33272bSNaresh Solanki case hwmon_temp_max: 4360f33272bSNaresh Solanki return max6639_temp_set_max(data, channel, val); 4370f33272bSNaresh Solanki case hwmon_temp_crit: 4380f33272bSNaresh Solanki return max6639_temp_set_crit(data, channel, val); 4390f33272bSNaresh Solanki case hwmon_temp_emergency: 4400f33272bSNaresh Solanki return max6639_temp_set_emergency(data, channel, val); 4410f33272bSNaresh Solanki default: 4420f33272bSNaresh Solanki return -EOPNOTSUPP; 4430f33272bSNaresh Solanki } 4440f33272bSNaresh Solanki } 4450f33272bSNaresh Solanki 4460f33272bSNaresh Solanki static umode_t max6639_temp_is_visible(const void *_data, u32 attr, int channel) 4470f33272bSNaresh Solanki { 4480f33272bSNaresh Solanki switch (attr) { 4490f33272bSNaresh Solanki case hwmon_temp_input: 4500f33272bSNaresh Solanki case hwmon_temp_fault: 4510f33272bSNaresh Solanki case hwmon_temp_max_alarm: 4520f33272bSNaresh Solanki case hwmon_temp_crit_alarm: 4530f33272bSNaresh Solanki case hwmon_temp_emergency_alarm: 4540f33272bSNaresh Solanki return 0444; 4550f33272bSNaresh Solanki case hwmon_temp_max: 4560f33272bSNaresh Solanki case hwmon_temp_crit: 4570f33272bSNaresh Solanki case hwmon_temp_emergency: 4580f33272bSNaresh Solanki return 0644; 4590f33272bSNaresh Solanki default: 4600f33272bSNaresh Solanki return 0; 4610f33272bSNaresh Solanki } 4620f33272bSNaresh Solanki } 4630f33272bSNaresh Solanki 4640f33272bSNaresh Solanki static int max6639_read(struct device *dev, enum hwmon_sensor_types type, 4650f33272bSNaresh Solanki u32 attr, int channel, long *val) 4660f33272bSNaresh Solanki { 4670f33272bSNaresh Solanki switch (type) { 4680f33272bSNaresh Solanki case hwmon_fan: 4690f33272bSNaresh Solanki return max6639_read_fan(dev, attr, channel, val); 4700f33272bSNaresh Solanki case hwmon_pwm: 4710f33272bSNaresh Solanki return max6639_read_pwm(dev, attr, channel, val); 4720f33272bSNaresh Solanki case hwmon_temp: 4730f33272bSNaresh Solanki return max6639_read_temp(dev, attr, channel, val); 4740f33272bSNaresh Solanki default: 4750f33272bSNaresh Solanki return -EOPNOTSUPP; 4760f33272bSNaresh Solanki } 4770f33272bSNaresh Solanki } 4780f33272bSNaresh Solanki 4790f33272bSNaresh Solanki static int max6639_write(struct device *dev, enum hwmon_sensor_types type, 4800f33272bSNaresh Solanki u32 attr, int channel, long val) 4810f33272bSNaresh Solanki { 4820f33272bSNaresh Solanki switch (type) { 483*842b4d98SNaresh Solanki case hwmon_fan: 484*842b4d98SNaresh Solanki return max6639_write_fan(dev, attr, channel, val); 4850f33272bSNaresh Solanki case hwmon_pwm: 4860f33272bSNaresh Solanki return max6639_write_pwm(dev, attr, channel, val); 4870f33272bSNaresh Solanki case hwmon_temp: 4880f33272bSNaresh Solanki return max6639_write_temp(dev, attr, channel, val); 4890f33272bSNaresh Solanki default: 4900f33272bSNaresh Solanki return -EOPNOTSUPP; 4910f33272bSNaresh Solanki } 4920f33272bSNaresh Solanki } 4930f33272bSNaresh Solanki 4940f33272bSNaresh Solanki static umode_t max6639_is_visible(const void *data, 4950f33272bSNaresh Solanki enum hwmon_sensor_types type, 4960f33272bSNaresh Solanki u32 attr, int channel) 4970f33272bSNaresh Solanki { 4980f33272bSNaresh Solanki switch (type) { 4990f33272bSNaresh Solanki case hwmon_fan: 5000f33272bSNaresh Solanki return max6639_fan_is_visible(data, attr, channel); 5010f33272bSNaresh Solanki case hwmon_pwm: 5020f33272bSNaresh Solanki return max6639_pwm_is_visible(data, attr, channel); 5030f33272bSNaresh Solanki case hwmon_temp: 5040f33272bSNaresh Solanki return max6639_temp_is_visible(data, attr, channel); 5050f33272bSNaresh Solanki default: 5060f33272bSNaresh Solanki return 0; 5070f33272bSNaresh Solanki } 5080f33272bSNaresh Solanki } 5090f33272bSNaresh Solanki 5100f33272bSNaresh Solanki static const struct hwmon_channel_info * const max6639_info[] = { 5110f33272bSNaresh Solanki HWMON_CHANNEL_INFO(fan, 512*842b4d98SNaresh Solanki HWMON_F_INPUT | HWMON_F_FAULT | HWMON_F_PULSES, 513*842b4d98SNaresh Solanki HWMON_F_INPUT | HWMON_F_FAULT | HWMON_F_PULSES), 5140f33272bSNaresh Solanki HWMON_CHANNEL_INFO(pwm, 515*842b4d98SNaresh Solanki HWMON_PWM_INPUT | HWMON_PWM_FREQ, 516*842b4d98SNaresh Solanki HWMON_PWM_INPUT | HWMON_PWM_FREQ), 5170f33272bSNaresh Solanki HWMON_CHANNEL_INFO(temp, 5180f33272bSNaresh Solanki HWMON_T_INPUT | HWMON_T_FAULT | HWMON_T_MAX | HWMON_T_MAX_ALARM | 5190f33272bSNaresh Solanki HWMON_T_CRIT | HWMON_T_CRIT_ALARM | HWMON_T_EMERGENCY | 5200f33272bSNaresh Solanki HWMON_T_EMERGENCY_ALARM, 5210f33272bSNaresh Solanki HWMON_T_INPUT | HWMON_T_FAULT | HWMON_T_MAX | HWMON_T_MAX_ALARM | 5220f33272bSNaresh Solanki HWMON_T_CRIT | HWMON_T_CRIT_ALARM | HWMON_T_EMERGENCY | 5230f33272bSNaresh Solanki HWMON_T_EMERGENCY_ALARM), 524a5b79d62Sstigge@antcom.de NULL 525a5b79d62Sstigge@antcom.de }; 5260f33272bSNaresh Solanki 5270f33272bSNaresh Solanki static const struct hwmon_ops max6639_hwmon_ops = { 5280f33272bSNaresh Solanki .is_visible = max6639_is_visible, 5290f33272bSNaresh Solanki .read = max6639_read, 5300f33272bSNaresh Solanki .write = max6639_write, 5310f33272bSNaresh Solanki }; 5320f33272bSNaresh Solanki 5330f33272bSNaresh Solanki static const struct hwmon_chip_info max6639_chip_info = { 5340f33272bSNaresh Solanki .ops = &max6639_hwmon_ops, 5350f33272bSNaresh Solanki .info = max6639_info, 5360f33272bSNaresh Solanki }; 537a5b79d62Sstigge@antcom.de 538a5b79d62Sstigge@antcom.de /* 539a5b79d62Sstigge@antcom.de * returns respective index in rpm_ranges table 540a5b79d62Sstigge@antcom.de * 1 by default on invalid range 541a5b79d62Sstigge@antcom.de */ 542a5b79d62Sstigge@antcom.de static int rpm_range_to_reg(int range) 543a5b79d62Sstigge@antcom.de { 544a5b79d62Sstigge@antcom.de int i; 545a5b79d62Sstigge@antcom.de 546a5b79d62Sstigge@antcom.de for (i = 0; i < ARRAY_SIZE(rpm_ranges); i++) { 547a5b79d62Sstigge@antcom.de if (rpm_ranges[i] == range) 548a5b79d62Sstigge@antcom.de return i; 549a5b79d62Sstigge@antcom.de } 550a5b79d62Sstigge@antcom.de 551a5b79d62Sstigge@antcom.de return 1; /* default: 4000 RPM */ 552a5b79d62Sstigge@antcom.de } 553a5b79d62Sstigge@antcom.de 5547981c584SGuenter Roeck static int max6639_init_client(struct i2c_client *client, 5557981c584SGuenter Roeck struct max6639_data *data) 556a5b79d62Sstigge@antcom.de { 557a5b79d62Sstigge@antcom.de struct max6639_platform_data *max6639_info = 558a8b3a3a5SJingoo Han dev_get_platdata(&client->dev); 5592f2da1acSChris D Schimp int i; 560a5b79d62Sstigge@antcom.de int rpm_range = 1; /* default: 4000 RPM */ 56145bf8305SNaresh Solanki int err, ppr; 562a5b79d62Sstigge@antcom.de 563177f3b92Sstigge@antcom.de /* Reset chip to default values, see below for GCONFIG setup */ 56445bf8305SNaresh Solanki err = regmap_write(data->regmap, MAX6639_REG_GCONFIG, MAX6639_GCONFIG_POR); 565a5b79d62Sstigge@antcom.de if (err) 56645bf8305SNaresh Solanki return err; 567a5b79d62Sstigge@antcom.de 568a5b79d62Sstigge@antcom.de /* Fans pulse per revolution is 2 by default */ 569a5b79d62Sstigge@antcom.de if (max6639_info && max6639_info->ppr > 0 && 570a5b79d62Sstigge@antcom.de max6639_info->ppr < 5) 57145bf8305SNaresh Solanki ppr = max6639_info->ppr; 572a5b79d62Sstigge@antcom.de else 57345bf8305SNaresh Solanki ppr = 2; 5740f33272bSNaresh Solanki 5750f33272bSNaresh Solanki data->ppr[0] = ppr; 5760f33272bSNaresh Solanki data->ppr[1] = ppr; 577a5b79d62Sstigge@antcom.de 578a5b79d62Sstigge@antcom.de if (max6639_info) 579a5b79d62Sstigge@antcom.de rpm_range = rpm_range_to_reg(max6639_info->rpm_range); 5800f33272bSNaresh Solanki data->rpm_range[0] = rpm_range; 5810f33272bSNaresh Solanki data->rpm_range[1] = rpm_range; 582a5b79d62Sstigge@antcom.de 58345bf8305SNaresh Solanki for (i = 0; i < MAX6639_NUM_CHANNELS; i++) { 5842f2da1acSChris D Schimp /* Set Fan pulse per revolution */ 5850f33272bSNaresh Solanki err = max6639_set_ppr(data, i, data->ppr[i]); 5862f2da1acSChris D Schimp if (err) 58745bf8305SNaresh Solanki return err; 5882f2da1acSChris D Schimp 589a5b79d62Sstigge@antcom.de /* Fans config PWM, RPM */ 59045bf8305SNaresh Solanki err = regmap_write(data->regmap, MAX6639_REG_FAN_CONFIG1(i), 5910f33272bSNaresh Solanki MAX6639_FAN_CONFIG1_PWM | data->rpm_range[i]); 592a5b79d62Sstigge@antcom.de if (err) 59345bf8305SNaresh Solanki return err; 594a5b79d62Sstigge@antcom.de 595a5b79d62Sstigge@antcom.de /* Fans PWM polarity high by default */ 5960f33272bSNaresh Solanki if (max6639_info) { 5970f33272bSNaresh Solanki if (max6639_info->pwm_polarity == 0) 59845bf8305SNaresh Solanki err = regmap_write(data->regmap, MAX6639_REG_FAN_CONFIG2a(i), 0x00); 599a5b79d62Sstigge@antcom.de else 60045bf8305SNaresh Solanki err = regmap_write(data->regmap, MAX6639_REG_FAN_CONFIG2a(i), 0x02); 6010f33272bSNaresh Solanki } 602a5b79d62Sstigge@antcom.de if (err) 60345bf8305SNaresh Solanki return err; 604a5b79d62Sstigge@antcom.de 605177f3b92Sstigge@antcom.de /* 606177f3b92Sstigge@antcom.de * /THERM full speed enable, 607177f3b92Sstigge@antcom.de * PWM frequency 25kHz, see also GCONFIG below 608177f3b92Sstigge@antcom.de */ 60945bf8305SNaresh Solanki err = regmap_write(data->regmap, MAX6639_REG_FAN_CONFIG3(i), 610177f3b92Sstigge@antcom.de MAX6639_FAN_CONFIG3_THERM_FULL_SPEED | 0x03); 611177f3b92Sstigge@antcom.de if (err) 61245bf8305SNaresh Solanki return err; 613177f3b92Sstigge@antcom.de 614a5b79d62Sstigge@antcom.de /* Max. temp. 80C/90C/100C */ 61545bf8305SNaresh Solanki err = regmap_write(data->regmap, MAX6639_REG_THERM_LIMIT(i), 80); 616a5b79d62Sstigge@antcom.de if (err) 61745bf8305SNaresh Solanki return err; 61845bf8305SNaresh Solanki err = regmap_write(data->regmap, MAX6639_REG_ALERT_LIMIT(i), 90); 619a5b79d62Sstigge@antcom.de if (err) 62045bf8305SNaresh Solanki return err; 62145bf8305SNaresh Solanki err = regmap_write(data->regmap, MAX6639_REG_OT_LIMIT(i), 100); 622a5b79d62Sstigge@antcom.de if (err) 62345bf8305SNaresh Solanki return err; 624a5b79d62Sstigge@antcom.de 625a5b79d62Sstigge@antcom.de /* PWM 120/120 (i.e. 100%) */ 62645bf8305SNaresh Solanki err = regmap_write(data->regmap, MAX6639_REG_TARGTDUTY(i), 120); 627a5b79d62Sstigge@antcom.de if (err) 62845bf8305SNaresh Solanki return err; 629a5b79d62Sstigge@antcom.de } 630a5b79d62Sstigge@antcom.de /* Start monitoring */ 63145bf8305SNaresh Solanki return regmap_write(data->regmap, MAX6639_REG_GCONFIG, 632177f3b92Sstigge@antcom.de MAX6639_GCONFIG_DISABLE_TIMEOUT | MAX6639_GCONFIG_CH2_LOCAL | 633177f3b92Sstigge@antcom.de MAX6639_GCONFIG_PWM_FREQ_HI); 63445bf8305SNaresh Solanki 635a5b79d62Sstigge@antcom.de } 636a5b79d62Sstigge@antcom.de 637a5b79d62Sstigge@antcom.de /* Return 0 if detection is successful, -ENODEV otherwise */ 638a5b79d62Sstigge@antcom.de static int max6639_detect(struct i2c_client *client, 639a5b79d62Sstigge@antcom.de struct i2c_board_info *info) 640a5b79d62Sstigge@antcom.de { 641a5b79d62Sstigge@antcom.de struct i2c_adapter *adapter = client->adapter; 642a5b79d62Sstigge@antcom.de int dev_id, manu_id; 643a5b79d62Sstigge@antcom.de 644a5b79d62Sstigge@antcom.de if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) 645a5b79d62Sstigge@antcom.de return -ENODEV; 646a5b79d62Sstigge@antcom.de 647a5b79d62Sstigge@antcom.de /* Actual detection via device and manufacturer ID */ 648a5b79d62Sstigge@antcom.de dev_id = i2c_smbus_read_byte_data(client, MAX6639_REG_DEVID); 649a5b79d62Sstigge@antcom.de manu_id = i2c_smbus_read_byte_data(client, MAX6639_REG_MANUID); 650a5b79d62Sstigge@antcom.de if (dev_id != 0x58 || manu_id != 0x4D) 651a5b79d62Sstigge@antcom.de return -ENODEV; 652a5b79d62Sstigge@antcom.de 653f2f394dbSWolfram Sang strscpy(info->type, "max6639", I2C_NAME_SIZE); 654a5b79d62Sstigge@antcom.de 655a5b79d62Sstigge@antcom.de return 0; 656a5b79d62Sstigge@antcom.de } 657a5b79d62Sstigge@antcom.de 6584e2271eaSMarcello Sylvester Bauer static void max6639_regulator_disable(void *data) 6594e2271eaSMarcello Sylvester Bauer { 6604e2271eaSMarcello Sylvester Bauer regulator_disable(data); 6614e2271eaSMarcello Sylvester Bauer } 6624e2271eaSMarcello Sylvester Bauer 66345bf8305SNaresh Solanki static bool max6639_regmap_is_volatile(struct device *dev, unsigned int reg) 66445bf8305SNaresh Solanki { 66545bf8305SNaresh Solanki switch (reg) { 66645bf8305SNaresh Solanki case MAX6639_REG_TEMP(0): 66745bf8305SNaresh Solanki case MAX6639_REG_TEMP_EXT(0): 66845bf8305SNaresh Solanki case MAX6639_REG_TEMP(1): 66945bf8305SNaresh Solanki case MAX6639_REG_TEMP_EXT(1): 67045bf8305SNaresh Solanki case MAX6639_REG_STATUS: 67145bf8305SNaresh Solanki case MAX6639_REG_FAN_CNT(0): 67245bf8305SNaresh Solanki case MAX6639_REG_FAN_CNT(1): 67345bf8305SNaresh Solanki case MAX6639_REG_TARGTDUTY(0): 67445bf8305SNaresh Solanki case MAX6639_REG_TARGTDUTY(1): 67545bf8305SNaresh Solanki return true; 67645bf8305SNaresh Solanki default: 67745bf8305SNaresh Solanki return false; 67845bf8305SNaresh Solanki } 67945bf8305SNaresh Solanki } 68045bf8305SNaresh Solanki 68145bf8305SNaresh Solanki static const struct regmap_config max6639_regmap_config = { 68245bf8305SNaresh Solanki .reg_bits = 8, 68345bf8305SNaresh Solanki .val_bits = 8, 68445bf8305SNaresh Solanki .max_register = MAX6639_REG_DEVREV, 68545bf8305SNaresh Solanki .cache_type = REGCACHE_MAPLE, 68645bf8305SNaresh Solanki .volatile_reg = max6639_regmap_is_volatile, 68745bf8305SNaresh Solanki }; 68845bf8305SNaresh Solanki 68967487038SStephen Kitt static int max6639_probe(struct i2c_client *client) 690a5b79d62Sstigge@antcom.de { 691c1ea0a04SGuenter Roeck struct device *dev = &client->dev; 692a5b79d62Sstigge@antcom.de struct max6639_data *data; 6937981c584SGuenter Roeck struct device *hwmon_dev; 694a5b79d62Sstigge@antcom.de int err; 695a5b79d62Sstigge@antcom.de 696c1ea0a04SGuenter Roeck data = devm_kzalloc(dev, sizeof(struct max6639_data), GFP_KERNEL); 697b07405fbSGuenter Roeck if (!data) 698b07405fbSGuenter Roeck return -ENOMEM; 699a5b79d62Sstigge@antcom.de 70045bf8305SNaresh Solanki data->regmap = devm_regmap_init_i2c(client, &max6639_regmap_config); 70145bf8305SNaresh Solanki if (IS_ERR(data->regmap)) 70245bf8305SNaresh Solanki return dev_err_probe(dev, 70345bf8305SNaresh Solanki PTR_ERR(data->regmap), 70445bf8305SNaresh Solanki "regmap initialization failed\n"); 7054e2271eaSMarcello Sylvester Bauer 7064e2271eaSMarcello Sylvester Bauer data->reg = devm_regulator_get_optional(dev, "fan"); 7074e2271eaSMarcello Sylvester Bauer if (IS_ERR(data->reg)) { 7084e2271eaSMarcello Sylvester Bauer if (PTR_ERR(data->reg) != -ENODEV) 7094e2271eaSMarcello Sylvester Bauer return PTR_ERR(data->reg); 7104e2271eaSMarcello Sylvester Bauer 7114e2271eaSMarcello Sylvester Bauer data->reg = NULL; 7124e2271eaSMarcello Sylvester Bauer } else { 7134e2271eaSMarcello Sylvester Bauer /* Spin up fans */ 7144e2271eaSMarcello Sylvester Bauer err = regulator_enable(data->reg); 7154e2271eaSMarcello Sylvester Bauer if (err) { 7164e2271eaSMarcello Sylvester Bauer dev_err(dev, "Failed to enable fan supply: %d\n", err); 7174e2271eaSMarcello Sylvester Bauer return err; 7184e2271eaSMarcello Sylvester Bauer } 7194e2271eaSMarcello Sylvester Bauer err = devm_add_action_or_reset(dev, max6639_regulator_disable, 7204e2271eaSMarcello Sylvester Bauer data->reg); 7214e2271eaSMarcello Sylvester Bauer if (err) { 7224e2271eaSMarcello Sylvester Bauer dev_err(dev, "Failed to register action: %d\n", err); 7234e2271eaSMarcello Sylvester Bauer return err; 7244e2271eaSMarcello Sylvester Bauer } 7254e2271eaSMarcello Sylvester Bauer } 7264e2271eaSMarcello Sylvester Bauer 727*842b4d98SNaresh Solanki mutex_init(&data->update_lock); 728*842b4d98SNaresh Solanki 729a5b79d62Sstigge@antcom.de /* Initialize the max6639 chip */ 7307981c584SGuenter Roeck err = max6639_init_client(client, data); 731a5b79d62Sstigge@antcom.de if (err < 0) 732b07405fbSGuenter Roeck return err; 733a5b79d62Sstigge@antcom.de 7340f33272bSNaresh Solanki hwmon_dev = devm_hwmon_device_register_with_info(dev, client->name, 7350f33272bSNaresh Solanki data, &max6639_chip_info, 7360f33272bSNaresh Solanki NULL); 7370f33272bSNaresh Solanki 7387981c584SGuenter Roeck return PTR_ERR_OR_ZERO(hwmon_dev); 739a5b79d62Sstigge@antcom.de } 740a5b79d62Sstigge@antcom.de 74152f30f77SMark Brown static int max6639_suspend(struct device *dev) 742a5b79d62Sstigge@antcom.de { 7434e2271eaSMarcello Sylvester Bauer struct max6639_data *data = dev_get_drvdata(dev); 7444e2271eaSMarcello Sylvester Bauer 7454e2271eaSMarcello Sylvester Bauer if (data->reg) 7464e2271eaSMarcello Sylvester Bauer regulator_disable(data->reg); 747a5b79d62Sstigge@antcom.de 74845bf8305SNaresh Solanki return regmap_write_bits(data->regmap, MAX6639_REG_GCONFIG, MAX6639_GCONFIG_STANDBY, 74945bf8305SNaresh Solanki MAX6639_GCONFIG_STANDBY); 750a5b79d62Sstigge@antcom.de } 751a5b79d62Sstigge@antcom.de 75252f30f77SMark Brown static int max6639_resume(struct device *dev) 753a5b79d62Sstigge@antcom.de { 7544e2271eaSMarcello Sylvester Bauer struct max6639_data *data = dev_get_drvdata(dev); 7554e2271eaSMarcello Sylvester Bauer int ret; 7564e2271eaSMarcello Sylvester Bauer 7574e2271eaSMarcello Sylvester Bauer if (data->reg) { 7584e2271eaSMarcello Sylvester Bauer ret = regulator_enable(data->reg); 7594e2271eaSMarcello Sylvester Bauer if (ret) { 7604e2271eaSMarcello Sylvester Bauer dev_err(dev, "Failed to enable fan supply: %d\n", ret); 7614e2271eaSMarcello Sylvester Bauer return ret; 7624e2271eaSMarcello Sylvester Bauer } 7634e2271eaSMarcello Sylvester Bauer } 7644e2271eaSMarcello Sylvester Bauer 76545bf8305SNaresh Solanki return regmap_write_bits(data->regmap, MAX6639_REG_GCONFIG, MAX6639_GCONFIG_STANDBY, 76645bf8305SNaresh Solanki ~MAX6639_GCONFIG_STANDBY); 767a5b79d62Sstigge@antcom.de } 768a5b79d62Sstigge@antcom.de 769a5b79d62Sstigge@antcom.de static const struct i2c_device_id max6639_id[] = { 770d8a66f36SUwe Kleine-König {"max6639"}, 771a5b79d62Sstigge@antcom.de { } 772a5b79d62Sstigge@antcom.de }; 773a5b79d62Sstigge@antcom.de 774a5b79d62Sstigge@antcom.de MODULE_DEVICE_TABLE(i2c, max6639_id); 775a5b79d62Sstigge@antcom.de 77677563092SJonathan Cameron static DEFINE_SIMPLE_DEV_PM_OPS(max6639_pm_ops, max6639_suspend, max6639_resume); 77752f30f77SMark Brown 778f11e2738SNaresh Solanki static const struct of_device_id max6639_of_match[] = { 779f11e2738SNaresh Solanki { .compatible = "maxim,max6639", }, 780f11e2738SNaresh Solanki { }, 781f11e2738SNaresh Solanki }; 782f11e2738SNaresh Solanki 783a5b79d62Sstigge@antcom.de static struct i2c_driver max6639_driver = { 784a5b79d62Sstigge@antcom.de .class = I2C_CLASS_HWMON, 785a5b79d62Sstigge@antcom.de .driver = { 786a5b79d62Sstigge@antcom.de .name = "max6639", 78777563092SJonathan Cameron .pm = pm_sleep_ptr(&max6639_pm_ops), 788f11e2738SNaresh Solanki .of_match_table = max6639_of_match, 789a5b79d62Sstigge@antcom.de }, 7901975d167SUwe Kleine-König .probe = max6639_probe, 791a5b79d62Sstigge@antcom.de .id_table = max6639_id, 792a5b79d62Sstigge@antcom.de .detect = max6639_detect, 793a5b79d62Sstigge@antcom.de .address_list = normal_i2c, 794a5b79d62Sstigge@antcom.de }; 795a5b79d62Sstigge@antcom.de 796f0967eeaSAxel Lin module_i2c_driver(max6639_driver); 797a5b79d62Sstigge@antcom.de 798a5b79d62Sstigge@antcom.de MODULE_AUTHOR("Roland Stigge <stigge@antcom.de>"); 799a5b79d62Sstigge@antcom.de MODULE_DESCRIPTION("max6639 driver"); 800a5b79d62Sstigge@antcom.de MODULE_LICENSE("GPL"); 801