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; 79842b4d98SNaresh 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 { 91*21a93a9eSGuenter Roeck u32 regs[2] = { MAX6639_REG_TEMP_EXT(channel), MAX6639_REG_TEMP(channel) }; 9245bf8305SNaresh Solanki struct max6639_data *data = dev_get_drvdata(dev); 93*21a93a9eSGuenter Roeck u8 regvals[2]; 9445bf8305SNaresh Solanki int res; 95a5b79d62Sstigge@antcom.de 96*21a93a9eSGuenter Roeck res = regmap_multi_reg_read(data->regmap, regs, regvals, 2); 9745bf8305SNaresh Solanki if (res < 0) 9845bf8305SNaresh Solanki return res; 99a5b79d62Sstigge@antcom.de 100*21a93a9eSGuenter Roeck *temp = ((regvals[0] >> 5) | (regvals[1] << 3)) * 125; 10145bf8305SNaresh Solanki 1020f33272bSNaresh Solanki return 0; 103a5b79d62Sstigge@antcom.de } 104a5b79d62Sstigge@antcom.de 1050f33272bSNaresh Solanki static int max6639_temp_read_fault(struct device *dev, int channel, long *fault) 106a5b79d62Sstigge@antcom.de { 10745bf8305SNaresh Solanki struct max6639_data *data = dev_get_drvdata(dev); 10845bf8305SNaresh Solanki unsigned int val; 10945bf8305SNaresh Solanki int res; 110a5b79d62Sstigge@antcom.de 1110f33272bSNaresh Solanki res = regmap_read(data->regmap, MAX6639_REG_TEMP_EXT(channel), &val); 11245bf8305SNaresh Solanki if (res < 0) 11345bf8305SNaresh Solanki return res; 11445bf8305SNaresh Solanki 1150f33272bSNaresh Solanki *fault = val & 1; 1160f33272bSNaresh Solanki 1170f33272bSNaresh Solanki return 0; 118a5b79d62Sstigge@antcom.de } 119a5b79d62Sstigge@antcom.de 1200f33272bSNaresh Solanki static int max6639_temp_read_max(struct device *dev, int channel, long *max) 121a5b79d62Sstigge@antcom.de { 1227981c584SGuenter Roeck struct max6639_data *data = dev_get_drvdata(dev); 12345bf8305SNaresh Solanki unsigned int val; 12445bf8305SNaresh Solanki int res; 125a5b79d62Sstigge@antcom.de 1260f33272bSNaresh Solanki res = regmap_read(data->regmap, MAX6639_REG_THERM_LIMIT(channel), &val); 12745bf8305SNaresh Solanki if (res < 0) 12845bf8305SNaresh Solanki return res; 12945bf8305SNaresh Solanki 1300f33272bSNaresh Solanki *max = (long)val * 1000; 1310f33272bSNaresh Solanki 1320f33272bSNaresh Solanki return 0; 133a5b79d62Sstigge@antcom.de } 134a5b79d62Sstigge@antcom.de 1350f33272bSNaresh Solanki static int max6639_temp_read_crit(struct device *dev, int channel, long *crit) 136a5b79d62Sstigge@antcom.de { 1377981c584SGuenter Roeck struct max6639_data *data = dev_get_drvdata(dev); 13845bf8305SNaresh Solanki unsigned int val; 13945bf8305SNaresh Solanki int res; 140a5b79d62Sstigge@antcom.de 1410f33272bSNaresh Solanki res = regmap_read(data->regmap, MAX6639_REG_ALERT_LIMIT(channel), &val); 14245bf8305SNaresh Solanki if (res < 0) 14345bf8305SNaresh Solanki return res; 14445bf8305SNaresh Solanki 1450f33272bSNaresh Solanki *crit = (long)val * 1000; 1460f33272bSNaresh Solanki 1470f33272bSNaresh Solanki return 0; 148a5b79d62Sstigge@antcom.de } 149a5b79d62Sstigge@antcom.de 1500f33272bSNaresh Solanki static int max6639_temp_read_emergency(struct device *dev, int channel, long *emerg) 151a5b79d62Sstigge@antcom.de { 1527981c584SGuenter Roeck struct max6639_data *data = dev_get_drvdata(dev); 15345bf8305SNaresh Solanki unsigned int val; 15445bf8305SNaresh Solanki int res; 155a5b79d62Sstigge@antcom.de 1560f33272bSNaresh Solanki res = regmap_read(data->regmap, MAX6639_REG_OT_LIMIT(channel), &val); 15745bf8305SNaresh Solanki if (res < 0) 15845bf8305SNaresh Solanki return res; 15945bf8305SNaresh Solanki 1600f33272bSNaresh Solanki *emerg = (long)val * 1000; 1610f33272bSNaresh Solanki 1620f33272bSNaresh Solanki return 0; 163a5b79d62Sstigge@antcom.de } 164a5b79d62Sstigge@antcom.de 1650f33272bSNaresh Solanki static int max6639_get_status(struct device *dev, unsigned int *status) 166a5b79d62Sstigge@antcom.de { 16745bf8305SNaresh Solanki struct max6639_data *data = dev_get_drvdata(dev); 16845bf8305SNaresh Solanki unsigned int val; 16945bf8305SNaresh Solanki int res; 170a5b79d62Sstigge@antcom.de 17145bf8305SNaresh Solanki res = regmap_read(data->regmap, MAX6639_REG_STATUS, &val); 17245bf8305SNaresh Solanki if (res < 0) 17345bf8305SNaresh Solanki return res; 174a5b79d62Sstigge@antcom.de 1750f33272bSNaresh Solanki *status = val; 1760f33272bSNaresh Solanki 1770f33272bSNaresh Solanki return 0; 178a5b79d62Sstigge@antcom.de } 179a5b79d62Sstigge@antcom.de 1800f33272bSNaresh Solanki static int max6639_temp_set_max(struct max6639_data *data, int channel, long val) 1810f33272bSNaresh Solanki { 1820f33272bSNaresh Solanki int res; 183a5b79d62Sstigge@antcom.de 1840f33272bSNaresh Solanki res = regmap_write(data->regmap, MAX6639_REG_THERM_LIMIT(channel), 1850f33272bSNaresh Solanki TEMP_LIMIT_TO_REG(val)); 1860f33272bSNaresh Solanki return res; 1870f33272bSNaresh Solanki } 188a5b79d62Sstigge@antcom.de 1890f33272bSNaresh Solanki static int max6639_temp_set_crit(struct max6639_data *data, int channel, long val) 1900f33272bSNaresh Solanki { 1910f33272bSNaresh Solanki int res; 1920f33272bSNaresh Solanki 1930f33272bSNaresh Solanki res = regmap_write(data->regmap, MAX6639_REG_ALERT_LIMIT(channel), TEMP_LIMIT_TO_REG(val)); 1940f33272bSNaresh Solanki 1950f33272bSNaresh Solanki return res; 1960f33272bSNaresh Solanki } 1970f33272bSNaresh Solanki 1980f33272bSNaresh Solanki static int max6639_temp_set_emergency(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_OT_LIMIT(channel), TEMP_LIMIT_TO_REG(val)); 2030f33272bSNaresh Solanki 2040f33272bSNaresh Solanki return res; 2050f33272bSNaresh Solanki } 2060f33272bSNaresh Solanki 2070f33272bSNaresh Solanki static int max6639_read_fan(struct device *dev, u32 attr, int channel, 2080f33272bSNaresh Solanki long *fan_val) 2090f33272bSNaresh Solanki { 2100f33272bSNaresh Solanki struct max6639_data *data = dev_get_drvdata(dev); 2110f33272bSNaresh Solanki unsigned int val; 2120f33272bSNaresh Solanki int res; 2130f33272bSNaresh Solanki 2140f33272bSNaresh Solanki switch (attr) { 2150f33272bSNaresh Solanki case hwmon_fan_input: 2160f33272bSNaresh Solanki res = regmap_read(data->regmap, MAX6639_REG_FAN_CNT(channel), &val); 2170f33272bSNaresh Solanki if (res < 0) 2180f33272bSNaresh Solanki return res; 2190f33272bSNaresh Solanki *fan_val = FAN_FROM_REG(val, data->rpm_range[channel]); 2200f33272bSNaresh Solanki return 0; 2210f33272bSNaresh Solanki case hwmon_fan_fault: 2220f33272bSNaresh Solanki res = max6639_get_status(dev, &val); 2230f33272bSNaresh Solanki if (res < 0) 2240f33272bSNaresh Solanki return res; 2250f33272bSNaresh Solanki *fan_val = !!(val & BIT(1 - channel)); 2260f33272bSNaresh Solanki return 0; 227842b4d98SNaresh Solanki case hwmon_fan_pulses: 228842b4d98SNaresh Solanki *fan_val = data->ppr[channel]; 229842b4d98SNaresh Solanki return 0; 2300f33272bSNaresh Solanki default: 2310f33272bSNaresh Solanki return -EOPNOTSUPP; 2320f33272bSNaresh Solanki } 2330f33272bSNaresh Solanki } 2340f33272bSNaresh Solanki 2350f33272bSNaresh Solanki static int max6639_set_ppr(struct max6639_data *data, int channel, u8 ppr) 2360f33272bSNaresh Solanki { 2370f33272bSNaresh Solanki /* Decrement the PPR value and shift left by 6 to match the register format */ 2380f33272bSNaresh Solanki return regmap_write(data->regmap, MAX6639_REG_FAN_PPR(channel), ppr-- << 6); 2390f33272bSNaresh Solanki } 2400f33272bSNaresh Solanki 241842b4d98SNaresh Solanki static int max6639_write_fan(struct device *dev, u32 attr, int channel, 242842b4d98SNaresh Solanki long val) 243842b4d98SNaresh Solanki { 244842b4d98SNaresh Solanki struct max6639_data *data = dev_get_drvdata(dev); 245842b4d98SNaresh Solanki int err; 246842b4d98SNaresh Solanki 247842b4d98SNaresh Solanki switch (attr) { 248842b4d98SNaresh Solanki case hwmon_fan_pulses: 249842b4d98SNaresh Solanki if (val <= 0 || val > 4) 250842b4d98SNaresh Solanki return -EINVAL; 251842b4d98SNaresh Solanki 252842b4d98SNaresh Solanki mutex_lock(&data->update_lock); 253842b4d98SNaresh Solanki /* Set Fan pulse per revolution */ 254842b4d98SNaresh Solanki err = max6639_set_ppr(data, channel, val); 255842b4d98SNaresh Solanki if (err < 0) { 256842b4d98SNaresh Solanki mutex_unlock(&data->update_lock); 257842b4d98SNaresh Solanki return err; 258842b4d98SNaresh Solanki } 259842b4d98SNaresh Solanki data->ppr[channel] = val; 260842b4d98SNaresh Solanki 261842b4d98SNaresh Solanki mutex_unlock(&data->update_lock); 262842b4d98SNaresh Solanki return 0; 263842b4d98SNaresh Solanki default: 264842b4d98SNaresh Solanki return -EOPNOTSUPP; 265842b4d98SNaresh Solanki } 266842b4d98SNaresh Solanki } 267842b4d98SNaresh Solanki 2680f33272bSNaresh Solanki static umode_t max6639_fan_is_visible(const void *_data, u32 attr, int channel) 2690f33272bSNaresh Solanki { 2700f33272bSNaresh Solanki switch (attr) { 2710f33272bSNaresh Solanki case hwmon_fan_input: 2720f33272bSNaresh Solanki case hwmon_fan_fault: 2730f33272bSNaresh Solanki return 0444; 2740f33272bSNaresh Solanki case hwmon_fan_pulses: 2750f33272bSNaresh Solanki return 0644; 2760f33272bSNaresh Solanki default: 2770f33272bSNaresh Solanki return 0; 2780f33272bSNaresh Solanki } 2790f33272bSNaresh Solanki } 2800f33272bSNaresh Solanki 2810f33272bSNaresh Solanki static int max6639_read_pwm(struct device *dev, u32 attr, int channel, 2820f33272bSNaresh Solanki long *pwm_val) 2830f33272bSNaresh Solanki { 284*21a93a9eSGuenter Roeck u32 regs[2] = { MAX6639_REG_FAN_CONFIG3(channel), MAX6639_REG_GCONFIG }; 2850f33272bSNaresh Solanki struct max6639_data *data = dev_get_drvdata(dev); 2860f33272bSNaresh Solanki unsigned int val; 287*21a93a9eSGuenter Roeck u8 regvals[2]; 2880f33272bSNaresh Solanki int res; 289842b4d98SNaresh Solanki u8 i; 2900f33272bSNaresh Solanki 2910f33272bSNaresh Solanki switch (attr) { 2920f33272bSNaresh Solanki case hwmon_pwm_input: 2930f33272bSNaresh Solanki res = regmap_read(data->regmap, MAX6639_REG_TARGTDUTY(channel), &val); 2940f33272bSNaresh Solanki if (res < 0) 2950f33272bSNaresh Solanki return res; 2960f33272bSNaresh Solanki *pwm_val = val * 255 / 120; 2970f33272bSNaresh Solanki return 0; 298842b4d98SNaresh Solanki case hwmon_pwm_freq: 299*21a93a9eSGuenter Roeck res = regmap_multi_reg_read(data->regmap, regs, regvals, 2); 300*21a93a9eSGuenter Roeck if (res < 0) 301842b4d98SNaresh Solanki return res; 302*21a93a9eSGuenter Roeck i = regvals[0] & MAX6639_FAN_CONFIG3_FREQ_MASK; 303*21a93a9eSGuenter Roeck if (regvals[1] & MAX6639_GCONFIG_PWM_FREQ_HI) 304842b4d98SNaresh Solanki i |= 0x4; 305842b4d98SNaresh Solanki *pwm_val = freq_table[i]; 306842b4d98SNaresh Solanki return 0; 3070f33272bSNaresh Solanki default: 3080f33272bSNaresh Solanki return -EOPNOTSUPP; 3090f33272bSNaresh Solanki } 3100f33272bSNaresh Solanki } 3110f33272bSNaresh Solanki 3120f33272bSNaresh Solanki static int max6639_write_pwm(struct device *dev, u32 attr, int channel, 3130f33272bSNaresh Solanki long val) 3140f33272bSNaresh Solanki { 3150f33272bSNaresh Solanki struct max6639_data *data = dev_get_drvdata(dev); 3160f33272bSNaresh Solanki int err; 317842b4d98SNaresh Solanki u8 i; 3180f33272bSNaresh Solanki 3190f33272bSNaresh Solanki switch (attr) { 3200f33272bSNaresh Solanki case hwmon_pwm_input: 3210f33272bSNaresh Solanki if (val < 0 || val > 255) 3220f33272bSNaresh Solanki return -EINVAL; 3230f33272bSNaresh Solanki err = regmap_write(data->regmap, MAX6639_REG_TARGTDUTY(channel), 3240f33272bSNaresh Solanki val * 120 / 255); 3250f33272bSNaresh Solanki return err; 326842b4d98SNaresh Solanki case hwmon_pwm_freq: 327842b4d98SNaresh Solanki val = clamp_val(val, 0, 25000); 328842b4d98SNaresh Solanki 329842b4d98SNaresh Solanki i = find_closest(val, freq_table, ARRAY_SIZE(freq_table)); 330842b4d98SNaresh Solanki 331842b4d98SNaresh Solanki mutex_lock(&data->update_lock); 332842b4d98SNaresh Solanki err = regmap_update_bits(data->regmap, MAX6639_REG_FAN_CONFIG3(channel), 333842b4d98SNaresh Solanki MAX6639_FAN_CONFIG3_FREQ_MASK, i); 334842b4d98SNaresh Solanki if (err < 0) { 335842b4d98SNaresh Solanki mutex_unlock(&data->update_lock); 336842b4d98SNaresh Solanki return err; 337842b4d98SNaresh Solanki } 338842b4d98SNaresh Solanki 339842b4d98SNaresh Solanki if (i >> 2) 340842b4d98SNaresh Solanki err = regmap_set_bits(data->regmap, MAX6639_REG_GCONFIG, 341842b4d98SNaresh Solanki MAX6639_GCONFIG_PWM_FREQ_HI); 342842b4d98SNaresh Solanki else 343842b4d98SNaresh Solanki err = regmap_clear_bits(data->regmap, MAX6639_REG_GCONFIG, 344842b4d98SNaresh Solanki MAX6639_GCONFIG_PWM_FREQ_HI); 345842b4d98SNaresh Solanki 346842b4d98SNaresh Solanki mutex_unlock(&data->update_lock); 347842b4d98SNaresh Solanki return err; 3480f33272bSNaresh Solanki default: 3490f33272bSNaresh Solanki return -EOPNOTSUPP; 3500f33272bSNaresh Solanki } 3510f33272bSNaresh Solanki } 3520f33272bSNaresh Solanki 3530f33272bSNaresh Solanki static umode_t max6639_pwm_is_visible(const void *_data, u32 attr, int channel) 3540f33272bSNaresh Solanki { 3550f33272bSNaresh Solanki switch (attr) { 3560f33272bSNaresh Solanki case hwmon_pwm_input: 357842b4d98SNaresh Solanki case hwmon_pwm_freq: 3580f33272bSNaresh Solanki return 0644; 3590f33272bSNaresh Solanki default: 3600f33272bSNaresh Solanki return 0; 3610f33272bSNaresh Solanki } 3620f33272bSNaresh Solanki } 3630f33272bSNaresh Solanki 3640f33272bSNaresh Solanki static int max6639_read_temp(struct device *dev, u32 attr, int channel, 3650f33272bSNaresh Solanki long *val) 3660f33272bSNaresh Solanki { 3670f33272bSNaresh Solanki unsigned int status; 3680f33272bSNaresh Solanki int res; 3690f33272bSNaresh Solanki 3700f33272bSNaresh Solanki switch (attr) { 3710f33272bSNaresh Solanki case hwmon_temp_input: 3720f33272bSNaresh Solanki res = max6639_temp_read_input(dev, channel, val); 3730f33272bSNaresh Solanki return res; 3740f33272bSNaresh Solanki case hwmon_temp_fault: 3750f33272bSNaresh Solanki res = max6639_temp_read_fault(dev, channel, val); 3760f33272bSNaresh Solanki return res; 3770f33272bSNaresh Solanki case hwmon_temp_max: 3780f33272bSNaresh Solanki res = max6639_temp_read_max(dev, channel, val); 3790f33272bSNaresh Solanki return res; 3800f33272bSNaresh Solanki case hwmon_temp_crit: 3810f33272bSNaresh Solanki res = max6639_temp_read_crit(dev, channel, val); 3820f33272bSNaresh Solanki return res; 3830f33272bSNaresh Solanki case hwmon_temp_emergency: 3840f33272bSNaresh Solanki res = max6639_temp_read_emergency(dev, channel, val); 3850f33272bSNaresh Solanki return res; 3860f33272bSNaresh Solanki case hwmon_temp_max_alarm: 3870f33272bSNaresh Solanki res = max6639_get_status(dev, &status); 3880f33272bSNaresh Solanki if (res < 0) 3890f33272bSNaresh Solanki return res; 3900f33272bSNaresh Solanki *val = !!(status & BIT(3 - channel)); 3910f33272bSNaresh Solanki return 0; 3920f33272bSNaresh Solanki case hwmon_temp_crit_alarm: 3930f33272bSNaresh Solanki res = max6639_get_status(dev, &status); 3940f33272bSNaresh Solanki if (res < 0) 3950f33272bSNaresh Solanki return res; 3960f33272bSNaresh Solanki *val = !!(status & BIT(7 - channel)); 3970f33272bSNaresh Solanki return 0; 3980f33272bSNaresh Solanki case hwmon_temp_emergency_alarm: 3990f33272bSNaresh Solanki res = max6639_get_status(dev, &status); 4000f33272bSNaresh Solanki if (res < 0) 4010f33272bSNaresh Solanki return res; 4020f33272bSNaresh Solanki *val = !!(status & BIT(5 - channel)); 4030f33272bSNaresh Solanki return 0; 4040f33272bSNaresh Solanki default: 4050f33272bSNaresh Solanki return -EOPNOTSUPP; 4060f33272bSNaresh Solanki } 4070f33272bSNaresh Solanki } 4080f33272bSNaresh Solanki 4090f33272bSNaresh Solanki static int max6639_write_temp(struct device *dev, u32 attr, int channel, 4100f33272bSNaresh Solanki long val) 4110f33272bSNaresh Solanki { 4120f33272bSNaresh Solanki struct max6639_data *data = dev_get_drvdata(dev); 4130f33272bSNaresh Solanki 4140f33272bSNaresh Solanki switch (attr) { 4150f33272bSNaresh Solanki case hwmon_temp_max: 4160f33272bSNaresh Solanki return max6639_temp_set_max(data, channel, val); 4170f33272bSNaresh Solanki case hwmon_temp_crit: 4180f33272bSNaresh Solanki return max6639_temp_set_crit(data, channel, val); 4190f33272bSNaresh Solanki case hwmon_temp_emergency: 4200f33272bSNaresh Solanki return max6639_temp_set_emergency(data, channel, val); 4210f33272bSNaresh Solanki default: 4220f33272bSNaresh Solanki return -EOPNOTSUPP; 4230f33272bSNaresh Solanki } 4240f33272bSNaresh Solanki } 4250f33272bSNaresh Solanki 4260f33272bSNaresh Solanki static umode_t max6639_temp_is_visible(const void *_data, u32 attr, int channel) 4270f33272bSNaresh Solanki { 4280f33272bSNaresh Solanki switch (attr) { 4290f33272bSNaresh Solanki case hwmon_temp_input: 4300f33272bSNaresh Solanki case hwmon_temp_fault: 4310f33272bSNaresh Solanki case hwmon_temp_max_alarm: 4320f33272bSNaresh Solanki case hwmon_temp_crit_alarm: 4330f33272bSNaresh Solanki case hwmon_temp_emergency_alarm: 4340f33272bSNaresh Solanki return 0444; 4350f33272bSNaresh Solanki case hwmon_temp_max: 4360f33272bSNaresh Solanki case hwmon_temp_crit: 4370f33272bSNaresh Solanki case hwmon_temp_emergency: 4380f33272bSNaresh Solanki return 0644; 4390f33272bSNaresh Solanki default: 4400f33272bSNaresh Solanki return 0; 4410f33272bSNaresh Solanki } 4420f33272bSNaresh Solanki } 4430f33272bSNaresh Solanki 4440f33272bSNaresh Solanki static int max6639_read(struct device *dev, enum hwmon_sensor_types type, 4450f33272bSNaresh Solanki u32 attr, int channel, long *val) 4460f33272bSNaresh Solanki { 4470f33272bSNaresh Solanki switch (type) { 4480f33272bSNaresh Solanki case hwmon_fan: 4490f33272bSNaresh Solanki return max6639_read_fan(dev, attr, channel, val); 4500f33272bSNaresh Solanki case hwmon_pwm: 4510f33272bSNaresh Solanki return max6639_read_pwm(dev, attr, channel, val); 4520f33272bSNaresh Solanki case hwmon_temp: 4530f33272bSNaresh Solanki return max6639_read_temp(dev, attr, channel, val); 4540f33272bSNaresh Solanki default: 4550f33272bSNaresh Solanki return -EOPNOTSUPP; 4560f33272bSNaresh Solanki } 4570f33272bSNaresh Solanki } 4580f33272bSNaresh Solanki 4590f33272bSNaresh Solanki static int max6639_write(struct device *dev, enum hwmon_sensor_types type, 4600f33272bSNaresh Solanki u32 attr, int channel, long val) 4610f33272bSNaresh Solanki { 4620f33272bSNaresh Solanki switch (type) { 463842b4d98SNaresh Solanki case hwmon_fan: 464842b4d98SNaresh Solanki return max6639_write_fan(dev, attr, channel, val); 4650f33272bSNaresh Solanki case hwmon_pwm: 4660f33272bSNaresh Solanki return max6639_write_pwm(dev, attr, channel, val); 4670f33272bSNaresh Solanki case hwmon_temp: 4680f33272bSNaresh Solanki return max6639_write_temp(dev, attr, channel, val); 4690f33272bSNaresh Solanki default: 4700f33272bSNaresh Solanki return -EOPNOTSUPP; 4710f33272bSNaresh Solanki } 4720f33272bSNaresh Solanki } 4730f33272bSNaresh Solanki 4740f33272bSNaresh Solanki static umode_t max6639_is_visible(const void *data, 4750f33272bSNaresh Solanki enum hwmon_sensor_types type, 4760f33272bSNaresh Solanki u32 attr, int channel) 4770f33272bSNaresh Solanki { 4780f33272bSNaresh Solanki switch (type) { 4790f33272bSNaresh Solanki case hwmon_fan: 4800f33272bSNaresh Solanki return max6639_fan_is_visible(data, attr, channel); 4810f33272bSNaresh Solanki case hwmon_pwm: 4820f33272bSNaresh Solanki return max6639_pwm_is_visible(data, attr, channel); 4830f33272bSNaresh Solanki case hwmon_temp: 4840f33272bSNaresh Solanki return max6639_temp_is_visible(data, attr, channel); 4850f33272bSNaresh Solanki default: 4860f33272bSNaresh Solanki return 0; 4870f33272bSNaresh Solanki } 4880f33272bSNaresh Solanki } 4890f33272bSNaresh Solanki 4900f33272bSNaresh Solanki static const struct hwmon_channel_info * const max6639_info[] = { 4910f33272bSNaresh Solanki HWMON_CHANNEL_INFO(fan, 492842b4d98SNaresh Solanki HWMON_F_INPUT | HWMON_F_FAULT | HWMON_F_PULSES, 493842b4d98SNaresh Solanki HWMON_F_INPUT | HWMON_F_FAULT | HWMON_F_PULSES), 4940f33272bSNaresh Solanki HWMON_CHANNEL_INFO(pwm, 495842b4d98SNaresh Solanki HWMON_PWM_INPUT | HWMON_PWM_FREQ, 496842b4d98SNaresh Solanki HWMON_PWM_INPUT | HWMON_PWM_FREQ), 4970f33272bSNaresh Solanki HWMON_CHANNEL_INFO(temp, 4980f33272bSNaresh Solanki HWMON_T_INPUT | HWMON_T_FAULT | HWMON_T_MAX | HWMON_T_MAX_ALARM | 4990f33272bSNaresh Solanki HWMON_T_CRIT | HWMON_T_CRIT_ALARM | HWMON_T_EMERGENCY | 5000f33272bSNaresh Solanki HWMON_T_EMERGENCY_ALARM, 5010f33272bSNaresh Solanki HWMON_T_INPUT | HWMON_T_FAULT | HWMON_T_MAX | HWMON_T_MAX_ALARM | 5020f33272bSNaresh Solanki HWMON_T_CRIT | HWMON_T_CRIT_ALARM | HWMON_T_EMERGENCY | 5030f33272bSNaresh Solanki HWMON_T_EMERGENCY_ALARM), 504a5b79d62Sstigge@antcom.de NULL 505a5b79d62Sstigge@antcom.de }; 5060f33272bSNaresh Solanki 5070f33272bSNaresh Solanki static const struct hwmon_ops max6639_hwmon_ops = { 5080f33272bSNaresh Solanki .is_visible = max6639_is_visible, 5090f33272bSNaresh Solanki .read = max6639_read, 5100f33272bSNaresh Solanki .write = max6639_write, 5110f33272bSNaresh Solanki }; 5120f33272bSNaresh Solanki 5130f33272bSNaresh Solanki static const struct hwmon_chip_info max6639_chip_info = { 5140f33272bSNaresh Solanki .ops = &max6639_hwmon_ops, 5150f33272bSNaresh Solanki .info = max6639_info, 5160f33272bSNaresh Solanki }; 517a5b79d62Sstigge@antcom.de 518a5b79d62Sstigge@antcom.de /* 519a5b79d62Sstigge@antcom.de * returns respective index in rpm_ranges table 520a5b79d62Sstigge@antcom.de * 1 by default on invalid range 521a5b79d62Sstigge@antcom.de */ 522a5b79d62Sstigge@antcom.de static int rpm_range_to_reg(int range) 523a5b79d62Sstigge@antcom.de { 524a5b79d62Sstigge@antcom.de int i; 525a5b79d62Sstigge@antcom.de 526a5b79d62Sstigge@antcom.de for (i = 0; i < ARRAY_SIZE(rpm_ranges); i++) { 527a5b79d62Sstigge@antcom.de if (rpm_ranges[i] == range) 528a5b79d62Sstigge@antcom.de return i; 529a5b79d62Sstigge@antcom.de } 530a5b79d62Sstigge@antcom.de 531a5b79d62Sstigge@antcom.de return 1; /* default: 4000 RPM */ 532a5b79d62Sstigge@antcom.de } 533a5b79d62Sstigge@antcom.de 5347981c584SGuenter Roeck static int max6639_init_client(struct i2c_client *client, 5357981c584SGuenter Roeck struct max6639_data *data) 536a5b79d62Sstigge@antcom.de { 537a5b79d62Sstigge@antcom.de struct max6639_platform_data *max6639_info = 538a8b3a3a5SJingoo Han dev_get_platdata(&client->dev); 5392f2da1acSChris D Schimp int i; 540a5b79d62Sstigge@antcom.de int rpm_range = 1; /* default: 4000 RPM */ 54145bf8305SNaresh Solanki int err, ppr; 542a5b79d62Sstigge@antcom.de 543177f3b92Sstigge@antcom.de /* Reset chip to default values, see below for GCONFIG setup */ 54445bf8305SNaresh Solanki err = regmap_write(data->regmap, MAX6639_REG_GCONFIG, MAX6639_GCONFIG_POR); 545a5b79d62Sstigge@antcom.de if (err) 54645bf8305SNaresh Solanki return err; 547a5b79d62Sstigge@antcom.de 548a5b79d62Sstigge@antcom.de /* Fans pulse per revolution is 2 by default */ 549a5b79d62Sstigge@antcom.de if (max6639_info && max6639_info->ppr > 0 && 550a5b79d62Sstigge@antcom.de max6639_info->ppr < 5) 55145bf8305SNaresh Solanki ppr = max6639_info->ppr; 552a5b79d62Sstigge@antcom.de else 55345bf8305SNaresh Solanki ppr = 2; 5540f33272bSNaresh Solanki 5550f33272bSNaresh Solanki data->ppr[0] = ppr; 5560f33272bSNaresh Solanki data->ppr[1] = ppr; 557a5b79d62Sstigge@antcom.de 558a5b79d62Sstigge@antcom.de if (max6639_info) 559a5b79d62Sstigge@antcom.de rpm_range = rpm_range_to_reg(max6639_info->rpm_range); 5600f33272bSNaresh Solanki data->rpm_range[0] = rpm_range; 5610f33272bSNaresh Solanki data->rpm_range[1] = rpm_range; 562a5b79d62Sstigge@antcom.de 56345bf8305SNaresh Solanki for (i = 0; i < MAX6639_NUM_CHANNELS; i++) { 5642f2da1acSChris D Schimp /* Set Fan pulse per revolution */ 5650f33272bSNaresh Solanki err = max6639_set_ppr(data, i, data->ppr[i]); 5662f2da1acSChris D Schimp if (err) 56745bf8305SNaresh Solanki return err; 5682f2da1acSChris D Schimp 569a5b79d62Sstigge@antcom.de /* Fans config PWM, RPM */ 57045bf8305SNaresh Solanki err = regmap_write(data->regmap, MAX6639_REG_FAN_CONFIG1(i), 5710f33272bSNaresh Solanki MAX6639_FAN_CONFIG1_PWM | data->rpm_range[i]); 572a5b79d62Sstigge@antcom.de if (err) 57345bf8305SNaresh Solanki return err; 574a5b79d62Sstigge@antcom.de 575a5b79d62Sstigge@antcom.de /* Fans PWM polarity high by default */ 5760f33272bSNaresh Solanki if (max6639_info) { 5770f33272bSNaresh Solanki if (max6639_info->pwm_polarity == 0) 57845bf8305SNaresh Solanki err = regmap_write(data->regmap, MAX6639_REG_FAN_CONFIG2a(i), 0x00); 579a5b79d62Sstigge@antcom.de else 58045bf8305SNaresh Solanki err = regmap_write(data->regmap, MAX6639_REG_FAN_CONFIG2a(i), 0x02); 5810f33272bSNaresh Solanki } 582a5b79d62Sstigge@antcom.de if (err) 58345bf8305SNaresh Solanki return err; 584a5b79d62Sstigge@antcom.de 585177f3b92Sstigge@antcom.de /* 586177f3b92Sstigge@antcom.de * /THERM full speed enable, 587177f3b92Sstigge@antcom.de * PWM frequency 25kHz, see also GCONFIG below 588177f3b92Sstigge@antcom.de */ 58945bf8305SNaresh Solanki err = regmap_write(data->regmap, MAX6639_REG_FAN_CONFIG3(i), 590177f3b92Sstigge@antcom.de MAX6639_FAN_CONFIG3_THERM_FULL_SPEED | 0x03); 591177f3b92Sstigge@antcom.de if (err) 59245bf8305SNaresh Solanki return err; 593177f3b92Sstigge@antcom.de 594a5b79d62Sstigge@antcom.de /* Max. temp. 80C/90C/100C */ 59545bf8305SNaresh Solanki err = regmap_write(data->regmap, MAX6639_REG_THERM_LIMIT(i), 80); 596a5b79d62Sstigge@antcom.de if (err) 59745bf8305SNaresh Solanki return err; 59845bf8305SNaresh Solanki err = regmap_write(data->regmap, MAX6639_REG_ALERT_LIMIT(i), 90); 599a5b79d62Sstigge@antcom.de if (err) 60045bf8305SNaresh Solanki return err; 60145bf8305SNaresh Solanki err = regmap_write(data->regmap, MAX6639_REG_OT_LIMIT(i), 100); 602a5b79d62Sstigge@antcom.de if (err) 60345bf8305SNaresh Solanki return err; 604a5b79d62Sstigge@antcom.de 605a5b79d62Sstigge@antcom.de /* PWM 120/120 (i.e. 100%) */ 60645bf8305SNaresh Solanki err = regmap_write(data->regmap, MAX6639_REG_TARGTDUTY(i), 120); 607a5b79d62Sstigge@antcom.de if (err) 60845bf8305SNaresh Solanki return err; 609a5b79d62Sstigge@antcom.de } 610a5b79d62Sstigge@antcom.de /* Start monitoring */ 61145bf8305SNaresh Solanki return regmap_write(data->regmap, MAX6639_REG_GCONFIG, 612177f3b92Sstigge@antcom.de MAX6639_GCONFIG_DISABLE_TIMEOUT | MAX6639_GCONFIG_CH2_LOCAL | 613177f3b92Sstigge@antcom.de MAX6639_GCONFIG_PWM_FREQ_HI); 61445bf8305SNaresh Solanki 615a5b79d62Sstigge@antcom.de } 616a5b79d62Sstigge@antcom.de 617a5b79d62Sstigge@antcom.de /* Return 0 if detection is successful, -ENODEV otherwise */ 618a5b79d62Sstigge@antcom.de static int max6639_detect(struct i2c_client *client, 619a5b79d62Sstigge@antcom.de struct i2c_board_info *info) 620a5b79d62Sstigge@antcom.de { 621a5b79d62Sstigge@antcom.de struct i2c_adapter *adapter = client->adapter; 622a5b79d62Sstigge@antcom.de int dev_id, manu_id; 623a5b79d62Sstigge@antcom.de 624a5b79d62Sstigge@antcom.de if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) 625a5b79d62Sstigge@antcom.de return -ENODEV; 626a5b79d62Sstigge@antcom.de 627a5b79d62Sstigge@antcom.de /* Actual detection via device and manufacturer ID */ 628a5b79d62Sstigge@antcom.de dev_id = i2c_smbus_read_byte_data(client, MAX6639_REG_DEVID); 629a5b79d62Sstigge@antcom.de manu_id = i2c_smbus_read_byte_data(client, MAX6639_REG_MANUID); 630a5b79d62Sstigge@antcom.de if (dev_id != 0x58 || manu_id != 0x4D) 631a5b79d62Sstigge@antcom.de return -ENODEV; 632a5b79d62Sstigge@antcom.de 633f2f394dbSWolfram Sang strscpy(info->type, "max6639", I2C_NAME_SIZE); 634a5b79d62Sstigge@antcom.de 635a5b79d62Sstigge@antcom.de return 0; 636a5b79d62Sstigge@antcom.de } 637a5b79d62Sstigge@antcom.de 6384e2271eaSMarcello Sylvester Bauer static void max6639_regulator_disable(void *data) 6394e2271eaSMarcello Sylvester Bauer { 6404e2271eaSMarcello Sylvester Bauer regulator_disable(data); 6414e2271eaSMarcello Sylvester Bauer } 6424e2271eaSMarcello Sylvester Bauer 64345bf8305SNaresh Solanki static bool max6639_regmap_is_volatile(struct device *dev, unsigned int reg) 64445bf8305SNaresh Solanki { 64545bf8305SNaresh Solanki switch (reg) { 64645bf8305SNaresh Solanki case MAX6639_REG_TEMP(0): 64745bf8305SNaresh Solanki case MAX6639_REG_TEMP_EXT(0): 64845bf8305SNaresh Solanki case MAX6639_REG_TEMP(1): 64945bf8305SNaresh Solanki case MAX6639_REG_TEMP_EXT(1): 65045bf8305SNaresh Solanki case MAX6639_REG_STATUS: 65145bf8305SNaresh Solanki case MAX6639_REG_FAN_CNT(0): 65245bf8305SNaresh Solanki case MAX6639_REG_FAN_CNT(1): 65345bf8305SNaresh Solanki case MAX6639_REG_TARGTDUTY(0): 65445bf8305SNaresh Solanki case MAX6639_REG_TARGTDUTY(1): 65545bf8305SNaresh Solanki return true; 65645bf8305SNaresh Solanki default: 65745bf8305SNaresh Solanki return false; 65845bf8305SNaresh Solanki } 65945bf8305SNaresh Solanki } 66045bf8305SNaresh Solanki 66145bf8305SNaresh Solanki static const struct regmap_config max6639_regmap_config = { 66245bf8305SNaresh Solanki .reg_bits = 8, 66345bf8305SNaresh Solanki .val_bits = 8, 66445bf8305SNaresh Solanki .max_register = MAX6639_REG_DEVREV, 66545bf8305SNaresh Solanki .cache_type = REGCACHE_MAPLE, 66645bf8305SNaresh Solanki .volatile_reg = max6639_regmap_is_volatile, 66745bf8305SNaresh Solanki }; 66845bf8305SNaresh Solanki 66967487038SStephen Kitt static int max6639_probe(struct i2c_client *client) 670a5b79d62Sstigge@antcom.de { 671c1ea0a04SGuenter Roeck struct device *dev = &client->dev; 672a5b79d62Sstigge@antcom.de struct max6639_data *data; 6737981c584SGuenter Roeck struct device *hwmon_dev; 674a5b79d62Sstigge@antcom.de int err; 675a5b79d62Sstigge@antcom.de 676c1ea0a04SGuenter Roeck data = devm_kzalloc(dev, sizeof(struct max6639_data), GFP_KERNEL); 677b07405fbSGuenter Roeck if (!data) 678b07405fbSGuenter Roeck return -ENOMEM; 679a5b79d62Sstigge@antcom.de 68045bf8305SNaresh Solanki data->regmap = devm_regmap_init_i2c(client, &max6639_regmap_config); 68145bf8305SNaresh Solanki if (IS_ERR(data->regmap)) 68245bf8305SNaresh Solanki return dev_err_probe(dev, 68345bf8305SNaresh Solanki PTR_ERR(data->regmap), 68445bf8305SNaresh Solanki "regmap initialization failed\n"); 6854e2271eaSMarcello Sylvester Bauer 6864e2271eaSMarcello Sylvester Bauer data->reg = devm_regulator_get_optional(dev, "fan"); 6874e2271eaSMarcello Sylvester Bauer if (IS_ERR(data->reg)) { 6884e2271eaSMarcello Sylvester Bauer if (PTR_ERR(data->reg) != -ENODEV) 6894e2271eaSMarcello Sylvester Bauer return PTR_ERR(data->reg); 6904e2271eaSMarcello Sylvester Bauer 6914e2271eaSMarcello Sylvester Bauer data->reg = NULL; 6924e2271eaSMarcello Sylvester Bauer } else { 6934e2271eaSMarcello Sylvester Bauer /* Spin up fans */ 6944e2271eaSMarcello Sylvester Bauer err = regulator_enable(data->reg); 6954e2271eaSMarcello Sylvester Bauer if (err) { 6964e2271eaSMarcello Sylvester Bauer dev_err(dev, "Failed to enable fan supply: %d\n", err); 6974e2271eaSMarcello Sylvester Bauer return err; 6984e2271eaSMarcello Sylvester Bauer } 6994e2271eaSMarcello Sylvester Bauer err = devm_add_action_or_reset(dev, max6639_regulator_disable, 7004e2271eaSMarcello Sylvester Bauer data->reg); 7014e2271eaSMarcello Sylvester Bauer if (err) { 7024e2271eaSMarcello Sylvester Bauer dev_err(dev, "Failed to register action: %d\n", err); 7034e2271eaSMarcello Sylvester Bauer return err; 7044e2271eaSMarcello Sylvester Bauer } 7054e2271eaSMarcello Sylvester Bauer } 7064e2271eaSMarcello Sylvester Bauer 707842b4d98SNaresh Solanki mutex_init(&data->update_lock); 708842b4d98SNaresh Solanki 709a5b79d62Sstigge@antcom.de /* Initialize the max6639 chip */ 7107981c584SGuenter Roeck err = max6639_init_client(client, data); 711a5b79d62Sstigge@antcom.de if (err < 0) 712b07405fbSGuenter Roeck return err; 713a5b79d62Sstigge@antcom.de 7140f33272bSNaresh Solanki hwmon_dev = devm_hwmon_device_register_with_info(dev, client->name, 7150f33272bSNaresh Solanki data, &max6639_chip_info, 7160f33272bSNaresh Solanki NULL); 7170f33272bSNaresh Solanki 7187981c584SGuenter Roeck return PTR_ERR_OR_ZERO(hwmon_dev); 719a5b79d62Sstigge@antcom.de } 720a5b79d62Sstigge@antcom.de 72152f30f77SMark Brown static int max6639_suspend(struct device *dev) 722a5b79d62Sstigge@antcom.de { 7234e2271eaSMarcello Sylvester Bauer struct max6639_data *data = dev_get_drvdata(dev); 7244e2271eaSMarcello Sylvester Bauer 7254e2271eaSMarcello Sylvester Bauer if (data->reg) 7264e2271eaSMarcello Sylvester Bauer regulator_disable(data->reg); 727a5b79d62Sstigge@antcom.de 72845bf8305SNaresh Solanki return regmap_write_bits(data->regmap, MAX6639_REG_GCONFIG, MAX6639_GCONFIG_STANDBY, 72945bf8305SNaresh Solanki MAX6639_GCONFIG_STANDBY); 730a5b79d62Sstigge@antcom.de } 731a5b79d62Sstigge@antcom.de 73252f30f77SMark Brown static int max6639_resume(struct device *dev) 733a5b79d62Sstigge@antcom.de { 7344e2271eaSMarcello Sylvester Bauer struct max6639_data *data = dev_get_drvdata(dev); 7354e2271eaSMarcello Sylvester Bauer int ret; 7364e2271eaSMarcello Sylvester Bauer 7374e2271eaSMarcello Sylvester Bauer if (data->reg) { 7384e2271eaSMarcello Sylvester Bauer ret = regulator_enable(data->reg); 7394e2271eaSMarcello Sylvester Bauer if (ret) { 7404e2271eaSMarcello Sylvester Bauer dev_err(dev, "Failed to enable fan supply: %d\n", ret); 7414e2271eaSMarcello Sylvester Bauer return ret; 7424e2271eaSMarcello Sylvester Bauer } 7434e2271eaSMarcello Sylvester Bauer } 7444e2271eaSMarcello Sylvester Bauer 74545bf8305SNaresh Solanki return regmap_write_bits(data->regmap, MAX6639_REG_GCONFIG, MAX6639_GCONFIG_STANDBY, 74645bf8305SNaresh Solanki ~MAX6639_GCONFIG_STANDBY); 747a5b79d62Sstigge@antcom.de } 748a5b79d62Sstigge@antcom.de 749a5b79d62Sstigge@antcom.de static const struct i2c_device_id max6639_id[] = { 750d8a66f36SUwe Kleine-König {"max6639"}, 751a5b79d62Sstigge@antcom.de { } 752a5b79d62Sstigge@antcom.de }; 753a5b79d62Sstigge@antcom.de 754a5b79d62Sstigge@antcom.de MODULE_DEVICE_TABLE(i2c, max6639_id); 755a5b79d62Sstigge@antcom.de 75677563092SJonathan Cameron static DEFINE_SIMPLE_DEV_PM_OPS(max6639_pm_ops, max6639_suspend, max6639_resume); 75752f30f77SMark Brown 758f11e2738SNaresh Solanki static const struct of_device_id max6639_of_match[] = { 759f11e2738SNaresh Solanki { .compatible = "maxim,max6639", }, 760f11e2738SNaresh Solanki { }, 761f11e2738SNaresh Solanki }; 762f11e2738SNaresh Solanki 763a5b79d62Sstigge@antcom.de static struct i2c_driver max6639_driver = { 764a5b79d62Sstigge@antcom.de .class = I2C_CLASS_HWMON, 765a5b79d62Sstigge@antcom.de .driver = { 766a5b79d62Sstigge@antcom.de .name = "max6639", 76777563092SJonathan Cameron .pm = pm_sleep_ptr(&max6639_pm_ops), 768f11e2738SNaresh Solanki .of_match_table = max6639_of_match, 769a5b79d62Sstigge@antcom.de }, 7701975d167SUwe Kleine-König .probe = max6639_probe, 771a5b79d62Sstigge@antcom.de .id_table = max6639_id, 772a5b79d62Sstigge@antcom.de .detect = max6639_detect, 773a5b79d62Sstigge@antcom.de .address_list = normal_i2c, 774a5b79d62Sstigge@antcom.de }; 775a5b79d62Sstigge@antcom.de 776f0967eeaSAxel Lin module_i2c_driver(max6639_driver); 777a5b79d62Sstigge@antcom.de 778a5b79d62Sstigge@antcom.de MODULE_AUTHOR("Roland Stigge <stigge@antcom.de>"); 779a5b79d62Sstigge@antcom.de MODULE_DESCRIPTION("max6639 driver"); 780a5b79d62Sstigge@antcom.de MODULE_LICENSE("GPL"); 781