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> 24*0f33272bSNaresh 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 59*0f33272bSNaresh 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 66*0f33272bSNaresh Solanki /* Supported PWM frequency */ 67*0f33272bSNaresh Solanki static const unsigned int freq_table[] = { 20, 33, 50, 100, 5000, 8333, 12500, 68*0f33272bSNaresh Solanki 25000 }; 69*0f33272bSNaresh 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; 79a5b79d62Sstigge@antcom.de 80a5b79d62Sstigge@antcom.de /* Register values initialized only once */ 81*0f33272bSNaresh Solanki u8 ppr[MAX6639_NUM_CHANNELS]; /* Pulses per rotation 0..3 for 1..4 ppr */ 82*0f33272bSNaresh Solanki u8 rpm_range[MAX6639_NUM_CHANNELS]; /* Index in above rpm_ranges table */ 834e2271eaSMarcello Sylvester Bauer 844e2271eaSMarcello Sylvester Bauer /* Optional regulator for FAN supply */ 854e2271eaSMarcello Sylvester Bauer struct regulator *reg; 86a5b79d62Sstigge@antcom.de }; 87a5b79d62Sstigge@antcom.de 88*0f33272bSNaresh Solanki static int max6639_temp_read_input(struct device *dev, int channel, long *temp) 89a5b79d62Sstigge@antcom.de { 9045bf8305SNaresh Solanki struct max6639_data *data = dev_get_drvdata(dev); 9145bf8305SNaresh Solanki unsigned int val; 9245bf8305SNaresh Solanki int res; 93a5b79d62Sstigge@antcom.de 9445bf8305SNaresh Solanki /* 9545bf8305SNaresh Solanki * Lock isn't needed as MAX6639_REG_TEMP wpnt change for at least 250ms after reading 9645bf8305SNaresh Solanki * MAX6639_REG_TEMP_EXT 9745bf8305SNaresh Solanki */ 98*0f33272bSNaresh Solanki res = regmap_read(data->regmap, MAX6639_REG_TEMP_EXT(channel), &val); 9945bf8305SNaresh Solanki if (res < 0) 10045bf8305SNaresh Solanki return res; 101a5b79d62Sstigge@antcom.de 102*0f33272bSNaresh Solanki *temp = val >> 5; 103*0f33272bSNaresh Solanki res = regmap_read(data->regmap, MAX6639_REG_TEMP(channel), &val); 10445bf8305SNaresh Solanki if (res < 0) 10545bf8305SNaresh Solanki return res; 10645bf8305SNaresh Solanki 107*0f33272bSNaresh Solanki *temp |= val << 3; 108*0f33272bSNaresh Solanki *temp *= 125; 10945bf8305SNaresh Solanki 110*0f33272bSNaresh Solanki return 0; 111a5b79d62Sstigge@antcom.de } 112a5b79d62Sstigge@antcom.de 113*0f33272bSNaresh Solanki static int max6639_temp_read_fault(struct device *dev, int channel, long *fault) 114a5b79d62Sstigge@antcom.de { 11545bf8305SNaresh Solanki struct max6639_data *data = dev_get_drvdata(dev); 11645bf8305SNaresh Solanki unsigned int val; 11745bf8305SNaresh Solanki int res; 118a5b79d62Sstigge@antcom.de 119*0f33272bSNaresh Solanki res = regmap_read(data->regmap, MAX6639_REG_TEMP_EXT(channel), &val); 12045bf8305SNaresh Solanki if (res < 0) 12145bf8305SNaresh Solanki return res; 12245bf8305SNaresh Solanki 123*0f33272bSNaresh Solanki *fault = val & 1; 124*0f33272bSNaresh Solanki 125*0f33272bSNaresh Solanki return 0; 126a5b79d62Sstigge@antcom.de } 127a5b79d62Sstigge@antcom.de 128*0f33272bSNaresh Solanki static int max6639_temp_read_max(struct device *dev, int channel, long *max) 129a5b79d62Sstigge@antcom.de { 1307981c584SGuenter Roeck struct max6639_data *data = dev_get_drvdata(dev); 13145bf8305SNaresh Solanki unsigned int val; 13245bf8305SNaresh Solanki int res; 133a5b79d62Sstigge@antcom.de 134*0f33272bSNaresh Solanki res = regmap_read(data->regmap, MAX6639_REG_THERM_LIMIT(channel), &val); 13545bf8305SNaresh Solanki if (res < 0) 13645bf8305SNaresh Solanki return res; 13745bf8305SNaresh Solanki 138*0f33272bSNaresh Solanki *max = (long)val * 1000; 139*0f33272bSNaresh Solanki 140*0f33272bSNaresh Solanki return 0; 141a5b79d62Sstigge@antcom.de } 142a5b79d62Sstigge@antcom.de 143*0f33272bSNaresh Solanki static int max6639_temp_read_crit(struct device *dev, int channel, long *crit) 144a5b79d62Sstigge@antcom.de { 1457981c584SGuenter Roeck struct max6639_data *data = dev_get_drvdata(dev); 14645bf8305SNaresh Solanki unsigned int val; 14745bf8305SNaresh Solanki int res; 148a5b79d62Sstigge@antcom.de 149*0f33272bSNaresh Solanki res = regmap_read(data->regmap, MAX6639_REG_ALERT_LIMIT(channel), &val); 15045bf8305SNaresh Solanki if (res < 0) 15145bf8305SNaresh Solanki return res; 15245bf8305SNaresh Solanki 153*0f33272bSNaresh Solanki *crit = (long)val * 1000; 154*0f33272bSNaresh Solanki 155*0f33272bSNaresh Solanki return 0; 156a5b79d62Sstigge@antcom.de } 157a5b79d62Sstigge@antcom.de 158*0f33272bSNaresh Solanki static int max6639_temp_read_emergency(struct device *dev, int channel, long *emerg) 159a5b79d62Sstigge@antcom.de { 1607981c584SGuenter Roeck struct max6639_data *data = dev_get_drvdata(dev); 16145bf8305SNaresh Solanki unsigned int val; 16245bf8305SNaresh Solanki int res; 163a5b79d62Sstigge@antcom.de 164*0f33272bSNaresh Solanki res = regmap_read(data->regmap, MAX6639_REG_OT_LIMIT(channel), &val); 16545bf8305SNaresh Solanki if (res < 0) 16645bf8305SNaresh Solanki return res; 16745bf8305SNaresh Solanki 168*0f33272bSNaresh Solanki *emerg = (long)val * 1000; 169*0f33272bSNaresh Solanki 170*0f33272bSNaresh Solanki return 0; 171a5b79d62Sstigge@antcom.de } 172a5b79d62Sstigge@antcom.de 173*0f33272bSNaresh Solanki static int max6639_get_status(struct device *dev, unsigned int *status) 174a5b79d62Sstigge@antcom.de { 17545bf8305SNaresh Solanki struct max6639_data *data = dev_get_drvdata(dev); 17645bf8305SNaresh Solanki unsigned int val; 17745bf8305SNaresh Solanki int res; 178a5b79d62Sstigge@antcom.de 17945bf8305SNaresh Solanki res = regmap_read(data->regmap, MAX6639_REG_STATUS, &val); 18045bf8305SNaresh Solanki if (res < 0) 18145bf8305SNaresh Solanki return res; 182a5b79d62Sstigge@antcom.de 183*0f33272bSNaresh Solanki *status = val; 184*0f33272bSNaresh Solanki 185*0f33272bSNaresh Solanki return 0; 186a5b79d62Sstigge@antcom.de } 187a5b79d62Sstigge@antcom.de 188*0f33272bSNaresh Solanki static int max6639_temp_set_max(struct max6639_data *data, int channel, long val) 189*0f33272bSNaresh Solanki { 190*0f33272bSNaresh Solanki int res; 191a5b79d62Sstigge@antcom.de 192*0f33272bSNaresh Solanki res = regmap_write(data->regmap, MAX6639_REG_THERM_LIMIT(channel), 193*0f33272bSNaresh Solanki TEMP_LIMIT_TO_REG(val)); 194*0f33272bSNaresh Solanki return res; 195*0f33272bSNaresh Solanki } 196a5b79d62Sstigge@antcom.de 197*0f33272bSNaresh Solanki static int max6639_temp_set_crit(struct max6639_data *data, int channel, long val) 198*0f33272bSNaresh Solanki { 199*0f33272bSNaresh Solanki int res; 200*0f33272bSNaresh Solanki 201*0f33272bSNaresh Solanki res = regmap_write(data->regmap, MAX6639_REG_ALERT_LIMIT(channel), TEMP_LIMIT_TO_REG(val)); 202*0f33272bSNaresh Solanki 203*0f33272bSNaresh Solanki return res; 204*0f33272bSNaresh Solanki } 205*0f33272bSNaresh Solanki 206*0f33272bSNaresh Solanki static int max6639_temp_set_emergency(struct max6639_data *data, int channel, long val) 207*0f33272bSNaresh Solanki { 208*0f33272bSNaresh Solanki int res; 209*0f33272bSNaresh Solanki 210*0f33272bSNaresh Solanki res = regmap_write(data->regmap, MAX6639_REG_OT_LIMIT(channel), TEMP_LIMIT_TO_REG(val)); 211*0f33272bSNaresh Solanki 212*0f33272bSNaresh Solanki return res; 213*0f33272bSNaresh Solanki } 214*0f33272bSNaresh Solanki 215*0f33272bSNaresh Solanki static int max6639_read_fan(struct device *dev, u32 attr, int channel, 216*0f33272bSNaresh Solanki long *fan_val) 217*0f33272bSNaresh Solanki { 218*0f33272bSNaresh Solanki struct max6639_data *data = dev_get_drvdata(dev); 219*0f33272bSNaresh Solanki unsigned int val; 220*0f33272bSNaresh Solanki int res; 221*0f33272bSNaresh Solanki 222*0f33272bSNaresh Solanki switch (attr) { 223*0f33272bSNaresh Solanki case hwmon_fan_input: 224*0f33272bSNaresh Solanki res = regmap_read(data->regmap, MAX6639_REG_FAN_CNT(channel), &val); 225*0f33272bSNaresh Solanki if (res < 0) 226*0f33272bSNaresh Solanki return res; 227*0f33272bSNaresh Solanki *fan_val = FAN_FROM_REG(val, data->rpm_range[channel]); 228*0f33272bSNaresh Solanki return 0; 229*0f33272bSNaresh Solanki case hwmon_fan_fault: 230*0f33272bSNaresh Solanki res = max6639_get_status(dev, &val); 231*0f33272bSNaresh Solanki if (res < 0) 232*0f33272bSNaresh Solanki return res; 233*0f33272bSNaresh Solanki *fan_val = !!(val & BIT(1 - channel)); 234*0f33272bSNaresh Solanki return 0; 235*0f33272bSNaresh Solanki default: 236*0f33272bSNaresh Solanki return -EOPNOTSUPP; 237*0f33272bSNaresh Solanki } 238*0f33272bSNaresh Solanki } 239*0f33272bSNaresh Solanki 240*0f33272bSNaresh Solanki static int max6639_set_ppr(struct max6639_data *data, int channel, u8 ppr) 241*0f33272bSNaresh Solanki { 242*0f33272bSNaresh Solanki /* Decrement the PPR value and shift left by 6 to match the register format */ 243*0f33272bSNaresh Solanki return regmap_write(data->regmap, MAX6639_REG_FAN_PPR(channel), ppr-- << 6); 244*0f33272bSNaresh Solanki } 245*0f33272bSNaresh Solanki 246*0f33272bSNaresh Solanki static umode_t max6639_fan_is_visible(const void *_data, u32 attr, int channel) 247*0f33272bSNaresh Solanki { 248*0f33272bSNaresh Solanki switch (attr) { 249*0f33272bSNaresh Solanki case hwmon_fan_input: 250*0f33272bSNaresh Solanki case hwmon_fan_fault: 251*0f33272bSNaresh Solanki return 0444; 252*0f33272bSNaresh Solanki case hwmon_fan_pulses: 253*0f33272bSNaresh Solanki return 0644; 254*0f33272bSNaresh Solanki default: 255*0f33272bSNaresh Solanki return 0; 256*0f33272bSNaresh Solanki } 257*0f33272bSNaresh Solanki } 258*0f33272bSNaresh Solanki 259*0f33272bSNaresh Solanki static int max6639_read_pwm(struct device *dev, u32 attr, int channel, 260*0f33272bSNaresh Solanki long *pwm_val) 261*0f33272bSNaresh Solanki { 262*0f33272bSNaresh Solanki struct max6639_data *data = dev_get_drvdata(dev); 263*0f33272bSNaresh Solanki unsigned int val; 264*0f33272bSNaresh Solanki int res; 265*0f33272bSNaresh Solanki 266*0f33272bSNaresh Solanki switch (attr) { 267*0f33272bSNaresh Solanki case hwmon_pwm_input: 268*0f33272bSNaresh Solanki res = regmap_read(data->regmap, MAX6639_REG_TARGTDUTY(channel), &val); 269*0f33272bSNaresh Solanki if (res < 0) 270*0f33272bSNaresh Solanki return res; 271*0f33272bSNaresh Solanki *pwm_val = val * 255 / 120; 272*0f33272bSNaresh Solanki return 0; 273*0f33272bSNaresh Solanki default: 274*0f33272bSNaresh Solanki return -EOPNOTSUPP; 275*0f33272bSNaresh Solanki } 276*0f33272bSNaresh Solanki } 277*0f33272bSNaresh Solanki 278*0f33272bSNaresh Solanki static int max6639_write_pwm(struct device *dev, u32 attr, int channel, 279*0f33272bSNaresh Solanki long val) 280*0f33272bSNaresh Solanki { 281*0f33272bSNaresh Solanki struct max6639_data *data = dev_get_drvdata(dev); 282*0f33272bSNaresh Solanki int err; 283*0f33272bSNaresh Solanki 284*0f33272bSNaresh Solanki switch (attr) { 285*0f33272bSNaresh Solanki case hwmon_pwm_input: 286*0f33272bSNaresh Solanki if (val < 0 || val > 255) 287*0f33272bSNaresh Solanki return -EINVAL; 288*0f33272bSNaresh Solanki err = regmap_write(data->regmap, MAX6639_REG_TARGTDUTY(channel), 289*0f33272bSNaresh Solanki val * 120 / 255); 290*0f33272bSNaresh Solanki return err; 291*0f33272bSNaresh Solanki default: 292*0f33272bSNaresh Solanki return -EOPNOTSUPP; 293*0f33272bSNaresh Solanki } 294*0f33272bSNaresh Solanki } 295*0f33272bSNaresh Solanki 296*0f33272bSNaresh Solanki static umode_t max6639_pwm_is_visible(const void *_data, u32 attr, int channel) 297*0f33272bSNaresh Solanki { 298*0f33272bSNaresh Solanki switch (attr) { 299*0f33272bSNaresh Solanki case hwmon_pwm_input: 300*0f33272bSNaresh Solanki return 0644; 301*0f33272bSNaresh Solanki default: 302*0f33272bSNaresh Solanki return 0; 303*0f33272bSNaresh Solanki } 304*0f33272bSNaresh Solanki } 305*0f33272bSNaresh Solanki 306*0f33272bSNaresh Solanki static int max6639_read_temp(struct device *dev, u32 attr, int channel, 307*0f33272bSNaresh Solanki long *val) 308*0f33272bSNaresh Solanki { 309*0f33272bSNaresh Solanki unsigned int status; 310*0f33272bSNaresh Solanki int res; 311*0f33272bSNaresh Solanki 312*0f33272bSNaresh Solanki switch (attr) { 313*0f33272bSNaresh Solanki case hwmon_temp_input: 314*0f33272bSNaresh Solanki res = max6639_temp_read_input(dev, channel, val); 315*0f33272bSNaresh Solanki return res; 316*0f33272bSNaresh Solanki case hwmon_temp_fault: 317*0f33272bSNaresh Solanki res = max6639_temp_read_fault(dev, channel, val); 318*0f33272bSNaresh Solanki return res; 319*0f33272bSNaresh Solanki case hwmon_temp_max: 320*0f33272bSNaresh Solanki res = max6639_temp_read_max(dev, channel, val); 321*0f33272bSNaresh Solanki return res; 322*0f33272bSNaresh Solanki case hwmon_temp_crit: 323*0f33272bSNaresh Solanki res = max6639_temp_read_crit(dev, channel, val); 324*0f33272bSNaresh Solanki return res; 325*0f33272bSNaresh Solanki case hwmon_temp_emergency: 326*0f33272bSNaresh Solanki res = max6639_temp_read_emergency(dev, channel, val); 327*0f33272bSNaresh Solanki return res; 328*0f33272bSNaresh Solanki case hwmon_temp_max_alarm: 329*0f33272bSNaresh Solanki res = max6639_get_status(dev, &status); 330*0f33272bSNaresh Solanki if (res < 0) 331*0f33272bSNaresh Solanki return res; 332*0f33272bSNaresh Solanki *val = !!(status & BIT(3 - channel)); 333*0f33272bSNaresh Solanki return 0; 334*0f33272bSNaresh Solanki case hwmon_temp_crit_alarm: 335*0f33272bSNaresh Solanki res = max6639_get_status(dev, &status); 336*0f33272bSNaresh Solanki if (res < 0) 337*0f33272bSNaresh Solanki return res; 338*0f33272bSNaresh Solanki *val = !!(status & BIT(7 - channel)); 339*0f33272bSNaresh Solanki return 0; 340*0f33272bSNaresh Solanki case hwmon_temp_emergency_alarm: 341*0f33272bSNaresh Solanki res = max6639_get_status(dev, &status); 342*0f33272bSNaresh Solanki if (res < 0) 343*0f33272bSNaresh Solanki return res; 344*0f33272bSNaresh Solanki *val = !!(status & BIT(5 - channel)); 345*0f33272bSNaresh Solanki return 0; 346*0f33272bSNaresh Solanki default: 347*0f33272bSNaresh Solanki return -EOPNOTSUPP; 348*0f33272bSNaresh Solanki } 349*0f33272bSNaresh Solanki } 350*0f33272bSNaresh Solanki 351*0f33272bSNaresh Solanki static int max6639_write_temp(struct device *dev, u32 attr, int channel, 352*0f33272bSNaresh Solanki long val) 353*0f33272bSNaresh Solanki { 354*0f33272bSNaresh Solanki struct max6639_data *data = dev_get_drvdata(dev); 355*0f33272bSNaresh Solanki 356*0f33272bSNaresh Solanki switch (attr) { 357*0f33272bSNaresh Solanki case hwmon_temp_max: 358*0f33272bSNaresh Solanki return max6639_temp_set_max(data, channel, val); 359*0f33272bSNaresh Solanki case hwmon_temp_crit: 360*0f33272bSNaresh Solanki return max6639_temp_set_crit(data, channel, val); 361*0f33272bSNaresh Solanki case hwmon_temp_emergency: 362*0f33272bSNaresh Solanki return max6639_temp_set_emergency(data, channel, val); 363*0f33272bSNaresh Solanki default: 364*0f33272bSNaresh Solanki return -EOPNOTSUPP; 365*0f33272bSNaresh Solanki } 366*0f33272bSNaresh Solanki } 367*0f33272bSNaresh Solanki 368*0f33272bSNaresh Solanki static umode_t max6639_temp_is_visible(const void *_data, u32 attr, int channel) 369*0f33272bSNaresh Solanki { 370*0f33272bSNaresh Solanki switch (attr) { 371*0f33272bSNaresh Solanki case hwmon_temp_input: 372*0f33272bSNaresh Solanki case hwmon_temp_fault: 373*0f33272bSNaresh Solanki case hwmon_temp_max_alarm: 374*0f33272bSNaresh Solanki case hwmon_temp_crit_alarm: 375*0f33272bSNaresh Solanki case hwmon_temp_emergency_alarm: 376*0f33272bSNaresh Solanki return 0444; 377*0f33272bSNaresh Solanki case hwmon_temp_max: 378*0f33272bSNaresh Solanki case hwmon_temp_crit: 379*0f33272bSNaresh Solanki case hwmon_temp_emergency: 380*0f33272bSNaresh Solanki return 0644; 381*0f33272bSNaresh Solanki default: 382*0f33272bSNaresh Solanki return 0; 383*0f33272bSNaresh Solanki } 384*0f33272bSNaresh Solanki } 385*0f33272bSNaresh Solanki 386*0f33272bSNaresh Solanki static int max6639_read(struct device *dev, enum hwmon_sensor_types type, 387*0f33272bSNaresh Solanki u32 attr, int channel, long *val) 388*0f33272bSNaresh Solanki { 389*0f33272bSNaresh Solanki switch (type) { 390*0f33272bSNaresh Solanki case hwmon_fan: 391*0f33272bSNaresh Solanki return max6639_read_fan(dev, attr, channel, val); 392*0f33272bSNaresh Solanki case hwmon_pwm: 393*0f33272bSNaresh Solanki return max6639_read_pwm(dev, attr, channel, val); 394*0f33272bSNaresh Solanki case hwmon_temp: 395*0f33272bSNaresh Solanki return max6639_read_temp(dev, attr, channel, val); 396*0f33272bSNaresh Solanki default: 397*0f33272bSNaresh Solanki return -EOPNOTSUPP; 398*0f33272bSNaresh Solanki } 399*0f33272bSNaresh Solanki } 400*0f33272bSNaresh Solanki 401*0f33272bSNaresh Solanki static int max6639_write(struct device *dev, enum hwmon_sensor_types type, 402*0f33272bSNaresh Solanki u32 attr, int channel, long val) 403*0f33272bSNaresh Solanki { 404*0f33272bSNaresh Solanki switch (type) { 405*0f33272bSNaresh Solanki case hwmon_pwm: 406*0f33272bSNaresh Solanki return max6639_write_pwm(dev, attr, channel, val); 407*0f33272bSNaresh Solanki case hwmon_temp: 408*0f33272bSNaresh Solanki return max6639_write_temp(dev, attr, channel, val); 409*0f33272bSNaresh Solanki default: 410*0f33272bSNaresh Solanki return -EOPNOTSUPP; 411*0f33272bSNaresh Solanki } 412*0f33272bSNaresh Solanki } 413*0f33272bSNaresh Solanki 414*0f33272bSNaresh Solanki static umode_t max6639_is_visible(const void *data, 415*0f33272bSNaresh Solanki enum hwmon_sensor_types type, 416*0f33272bSNaresh Solanki u32 attr, int channel) 417*0f33272bSNaresh Solanki { 418*0f33272bSNaresh Solanki switch (type) { 419*0f33272bSNaresh Solanki case hwmon_fan: 420*0f33272bSNaresh Solanki return max6639_fan_is_visible(data, attr, channel); 421*0f33272bSNaresh Solanki case hwmon_pwm: 422*0f33272bSNaresh Solanki return max6639_pwm_is_visible(data, attr, channel); 423*0f33272bSNaresh Solanki case hwmon_temp: 424*0f33272bSNaresh Solanki return max6639_temp_is_visible(data, attr, channel); 425*0f33272bSNaresh Solanki default: 426*0f33272bSNaresh Solanki return 0; 427*0f33272bSNaresh Solanki } 428*0f33272bSNaresh Solanki } 429*0f33272bSNaresh Solanki 430*0f33272bSNaresh Solanki static const struct hwmon_channel_info * const max6639_info[] = { 431*0f33272bSNaresh Solanki HWMON_CHANNEL_INFO(fan, 432*0f33272bSNaresh Solanki HWMON_F_INPUT | HWMON_F_FAULT, 433*0f33272bSNaresh Solanki HWMON_F_INPUT | HWMON_F_FAULT), 434*0f33272bSNaresh Solanki HWMON_CHANNEL_INFO(pwm, 435*0f33272bSNaresh Solanki HWMON_PWM_INPUT, 436*0f33272bSNaresh Solanki HWMON_PWM_INPUT), 437*0f33272bSNaresh Solanki HWMON_CHANNEL_INFO(temp, 438*0f33272bSNaresh Solanki HWMON_T_INPUT | HWMON_T_FAULT | HWMON_T_MAX | HWMON_T_MAX_ALARM | 439*0f33272bSNaresh Solanki HWMON_T_CRIT | HWMON_T_CRIT_ALARM | HWMON_T_EMERGENCY | 440*0f33272bSNaresh Solanki HWMON_T_EMERGENCY_ALARM, 441*0f33272bSNaresh Solanki HWMON_T_INPUT | HWMON_T_FAULT | HWMON_T_MAX | HWMON_T_MAX_ALARM | 442*0f33272bSNaresh Solanki HWMON_T_CRIT | HWMON_T_CRIT_ALARM | HWMON_T_EMERGENCY | 443*0f33272bSNaresh Solanki HWMON_T_EMERGENCY_ALARM), 444a5b79d62Sstigge@antcom.de NULL 445a5b79d62Sstigge@antcom.de }; 446*0f33272bSNaresh Solanki 447*0f33272bSNaresh Solanki static const struct hwmon_ops max6639_hwmon_ops = { 448*0f33272bSNaresh Solanki .is_visible = max6639_is_visible, 449*0f33272bSNaresh Solanki .read = max6639_read, 450*0f33272bSNaresh Solanki .write = max6639_write, 451*0f33272bSNaresh Solanki }; 452*0f33272bSNaresh Solanki 453*0f33272bSNaresh Solanki static const struct hwmon_chip_info max6639_chip_info = { 454*0f33272bSNaresh Solanki .ops = &max6639_hwmon_ops, 455*0f33272bSNaresh Solanki .info = max6639_info, 456*0f33272bSNaresh Solanki }; 457a5b79d62Sstigge@antcom.de 458a5b79d62Sstigge@antcom.de /* 459a5b79d62Sstigge@antcom.de * returns respective index in rpm_ranges table 460a5b79d62Sstigge@antcom.de * 1 by default on invalid range 461a5b79d62Sstigge@antcom.de */ 462a5b79d62Sstigge@antcom.de static int rpm_range_to_reg(int range) 463a5b79d62Sstigge@antcom.de { 464a5b79d62Sstigge@antcom.de int i; 465a5b79d62Sstigge@antcom.de 466a5b79d62Sstigge@antcom.de for (i = 0; i < ARRAY_SIZE(rpm_ranges); i++) { 467a5b79d62Sstigge@antcom.de if (rpm_ranges[i] == range) 468a5b79d62Sstigge@antcom.de return i; 469a5b79d62Sstigge@antcom.de } 470a5b79d62Sstigge@antcom.de 471a5b79d62Sstigge@antcom.de return 1; /* default: 4000 RPM */ 472a5b79d62Sstigge@antcom.de } 473a5b79d62Sstigge@antcom.de 4747981c584SGuenter Roeck static int max6639_init_client(struct i2c_client *client, 4757981c584SGuenter Roeck struct max6639_data *data) 476a5b79d62Sstigge@antcom.de { 477a5b79d62Sstigge@antcom.de struct max6639_platform_data *max6639_info = 478a8b3a3a5SJingoo Han dev_get_platdata(&client->dev); 4792f2da1acSChris D Schimp int i; 480a5b79d62Sstigge@antcom.de int rpm_range = 1; /* default: 4000 RPM */ 48145bf8305SNaresh Solanki int err, ppr; 482a5b79d62Sstigge@antcom.de 483177f3b92Sstigge@antcom.de /* Reset chip to default values, see below for GCONFIG setup */ 48445bf8305SNaresh Solanki err = regmap_write(data->regmap, MAX6639_REG_GCONFIG, MAX6639_GCONFIG_POR); 485a5b79d62Sstigge@antcom.de if (err) 48645bf8305SNaresh Solanki return err; 487a5b79d62Sstigge@antcom.de 488a5b79d62Sstigge@antcom.de /* Fans pulse per revolution is 2 by default */ 489a5b79d62Sstigge@antcom.de if (max6639_info && max6639_info->ppr > 0 && 490a5b79d62Sstigge@antcom.de max6639_info->ppr < 5) 49145bf8305SNaresh Solanki ppr = max6639_info->ppr; 492a5b79d62Sstigge@antcom.de else 49345bf8305SNaresh Solanki ppr = 2; 494*0f33272bSNaresh Solanki 495*0f33272bSNaresh Solanki data->ppr[0] = ppr; 496*0f33272bSNaresh Solanki data->ppr[1] = ppr; 497a5b79d62Sstigge@antcom.de 498a5b79d62Sstigge@antcom.de if (max6639_info) 499a5b79d62Sstigge@antcom.de rpm_range = rpm_range_to_reg(max6639_info->rpm_range); 500*0f33272bSNaresh Solanki data->rpm_range[0] = rpm_range; 501*0f33272bSNaresh Solanki data->rpm_range[1] = rpm_range; 502a5b79d62Sstigge@antcom.de 50345bf8305SNaresh Solanki for (i = 0; i < MAX6639_NUM_CHANNELS; i++) { 5042f2da1acSChris D Schimp /* Set Fan pulse per revolution */ 505*0f33272bSNaresh Solanki err = max6639_set_ppr(data, i, data->ppr[i]); 5062f2da1acSChris D Schimp if (err) 50745bf8305SNaresh Solanki return err; 5082f2da1acSChris D Schimp 509a5b79d62Sstigge@antcom.de /* Fans config PWM, RPM */ 51045bf8305SNaresh Solanki err = regmap_write(data->regmap, MAX6639_REG_FAN_CONFIG1(i), 511*0f33272bSNaresh Solanki MAX6639_FAN_CONFIG1_PWM | data->rpm_range[i]); 512a5b79d62Sstigge@antcom.de if (err) 51345bf8305SNaresh Solanki return err; 514a5b79d62Sstigge@antcom.de 515a5b79d62Sstigge@antcom.de /* Fans PWM polarity high by default */ 516*0f33272bSNaresh Solanki if (max6639_info) { 517*0f33272bSNaresh Solanki if (max6639_info->pwm_polarity == 0) 51845bf8305SNaresh Solanki err = regmap_write(data->regmap, MAX6639_REG_FAN_CONFIG2a(i), 0x00); 519a5b79d62Sstigge@antcom.de else 52045bf8305SNaresh Solanki err = regmap_write(data->regmap, MAX6639_REG_FAN_CONFIG2a(i), 0x02); 521*0f33272bSNaresh Solanki } 522a5b79d62Sstigge@antcom.de if (err) 52345bf8305SNaresh Solanki return err; 524a5b79d62Sstigge@antcom.de 525177f3b92Sstigge@antcom.de /* 526177f3b92Sstigge@antcom.de * /THERM full speed enable, 527177f3b92Sstigge@antcom.de * PWM frequency 25kHz, see also GCONFIG below 528177f3b92Sstigge@antcom.de */ 52945bf8305SNaresh Solanki err = regmap_write(data->regmap, MAX6639_REG_FAN_CONFIG3(i), 530177f3b92Sstigge@antcom.de MAX6639_FAN_CONFIG3_THERM_FULL_SPEED | 0x03); 531177f3b92Sstigge@antcom.de if (err) 53245bf8305SNaresh Solanki return err; 533177f3b92Sstigge@antcom.de 534a5b79d62Sstigge@antcom.de /* Max. temp. 80C/90C/100C */ 53545bf8305SNaresh Solanki err = regmap_write(data->regmap, MAX6639_REG_THERM_LIMIT(i), 80); 536a5b79d62Sstigge@antcom.de if (err) 53745bf8305SNaresh Solanki return err; 53845bf8305SNaresh Solanki err = regmap_write(data->regmap, MAX6639_REG_ALERT_LIMIT(i), 90); 539a5b79d62Sstigge@antcom.de if (err) 54045bf8305SNaresh Solanki return err; 54145bf8305SNaresh Solanki err = regmap_write(data->regmap, MAX6639_REG_OT_LIMIT(i), 100); 542a5b79d62Sstigge@antcom.de if (err) 54345bf8305SNaresh Solanki return err; 544a5b79d62Sstigge@antcom.de 545a5b79d62Sstigge@antcom.de /* PWM 120/120 (i.e. 100%) */ 54645bf8305SNaresh Solanki err = regmap_write(data->regmap, MAX6639_REG_TARGTDUTY(i), 120); 547a5b79d62Sstigge@antcom.de if (err) 54845bf8305SNaresh Solanki return err; 549a5b79d62Sstigge@antcom.de } 550a5b79d62Sstigge@antcom.de /* Start monitoring */ 55145bf8305SNaresh Solanki return regmap_write(data->regmap, MAX6639_REG_GCONFIG, 552177f3b92Sstigge@antcom.de MAX6639_GCONFIG_DISABLE_TIMEOUT | MAX6639_GCONFIG_CH2_LOCAL | 553177f3b92Sstigge@antcom.de MAX6639_GCONFIG_PWM_FREQ_HI); 55445bf8305SNaresh Solanki 555a5b79d62Sstigge@antcom.de } 556a5b79d62Sstigge@antcom.de 557a5b79d62Sstigge@antcom.de /* Return 0 if detection is successful, -ENODEV otherwise */ 558a5b79d62Sstigge@antcom.de static int max6639_detect(struct i2c_client *client, 559a5b79d62Sstigge@antcom.de struct i2c_board_info *info) 560a5b79d62Sstigge@antcom.de { 561a5b79d62Sstigge@antcom.de struct i2c_adapter *adapter = client->adapter; 562a5b79d62Sstigge@antcom.de int dev_id, manu_id; 563a5b79d62Sstigge@antcom.de 564a5b79d62Sstigge@antcom.de if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) 565a5b79d62Sstigge@antcom.de return -ENODEV; 566a5b79d62Sstigge@antcom.de 567a5b79d62Sstigge@antcom.de /* Actual detection via device and manufacturer ID */ 568a5b79d62Sstigge@antcom.de dev_id = i2c_smbus_read_byte_data(client, MAX6639_REG_DEVID); 569a5b79d62Sstigge@antcom.de manu_id = i2c_smbus_read_byte_data(client, MAX6639_REG_MANUID); 570a5b79d62Sstigge@antcom.de if (dev_id != 0x58 || manu_id != 0x4D) 571a5b79d62Sstigge@antcom.de return -ENODEV; 572a5b79d62Sstigge@antcom.de 573f2f394dbSWolfram Sang strscpy(info->type, "max6639", I2C_NAME_SIZE); 574a5b79d62Sstigge@antcom.de 575a5b79d62Sstigge@antcom.de return 0; 576a5b79d62Sstigge@antcom.de } 577a5b79d62Sstigge@antcom.de 5784e2271eaSMarcello Sylvester Bauer static void max6639_regulator_disable(void *data) 5794e2271eaSMarcello Sylvester Bauer { 5804e2271eaSMarcello Sylvester Bauer regulator_disable(data); 5814e2271eaSMarcello Sylvester Bauer } 5824e2271eaSMarcello Sylvester Bauer 58345bf8305SNaresh Solanki static bool max6639_regmap_is_volatile(struct device *dev, unsigned int reg) 58445bf8305SNaresh Solanki { 58545bf8305SNaresh Solanki switch (reg) { 58645bf8305SNaresh Solanki case MAX6639_REG_TEMP(0): 58745bf8305SNaresh Solanki case MAX6639_REG_TEMP_EXT(0): 58845bf8305SNaresh Solanki case MAX6639_REG_TEMP(1): 58945bf8305SNaresh Solanki case MAX6639_REG_TEMP_EXT(1): 59045bf8305SNaresh Solanki case MAX6639_REG_STATUS: 59145bf8305SNaresh Solanki case MAX6639_REG_FAN_CNT(0): 59245bf8305SNaresh Solanki case MAX6639_REG_FAN_CNT(1): 59345bf8305SNaresh Solanki case MAX6639_REG_TARGTDUTY(0): 59445bf8305SNaresh Solanki case MAX6639_REG_TARGTDUTY(1): 59545bf8305SNaresh Solanki return true; 59645bf8305SNaresh Solanki default: 59745bf8305SNaresh Solanki return false; 59845bf8305SNaresh Solanki } 59945bf8305SNaresh Solanki } 60045bf8305SNaresh Solanki 60145bf8305SNaresh Solanki static const struct regmap_config max6639_regmap_config = { 60245bf8305SNaresh Solanki .reg_bits = 8, 60345bf8305SNaresh Solanki .val_bits = 8, 60445bf8305SNaresh Solanki .max_register = MAX6639_REG_DEVREV, 60545bf8305SNaresh Solanki .cache_type = REGCACHE_MAPLE, 60645bf8305SNaresh Solanki .volatile_reg = max6639_regmap_is_volatile, 60745bf8305SNaresh Solanki }; 60845bf8305SNaresh Solanki 60967487038SStephen Kitt static int max6639_probe(struct i2c_client *client) 610a5b79d62Sstigge@antcom.de { 611c1ea0a04SGuenter Roeck struct device *dev = &client->dev; 612a5b79d62Sstigge@antcom.de struct max6639_data *data; 6137981c584SGuenter Roeck struct device *hwmon_dev; 614a5b79d62Sstigge@antcom.de int err; 615a5b79d62Sstigge@antcom.de 616c1ea0a04SGuenter Roeck data = devm_kzalloc(dev, sizeof(struct max6639_data), GFP_KERNEL); 617b07405fbSGuenter Roeck if (!data) 618b07405fbSGuenter Roeck return -ENOMEM; 619a5b79d62Sstigge@antcom.de 62045bf8305SNaresh Solanki data->regmap = devm_regmap_init_i2c(client, &max6639_regmap_config); 62145bf8305SNaresh Solanki if (IS_ERR(data->regmap)) 62245bf8305SNaresh Solanki return dev_err_probe(dev, 62345bf8305SNaresh Solanki PTR_ERR(data->regmap), 62445bf8305SNaresh Solanki "regmap initialization failed\n"); 6254e2271eaSMarcello Sylvester Bauer 6264e2271eaSMarcello Sylvester Bauer data->reg = devm_regulator_get_optional(dev, "fan"); 6274e2271eaSMarcello Sylvester Bauer if (IS_ERR(data->reg)) { 6284e2271eaSMarcello Sylvester Bauer if (PTR_ERR(data->reg) != -ENODEV) 6294e2271eaSMarcello Sylvester Bauer return PTR_ERR(data->reg); 6304e2271eaSMarcello Sylvester Bauer 6314e2271eaSMarcello Sylvester Bauer data->reg = NULL; 6324e2271eaSMarcello Sylvester Bauer } else { 6334e2271eaSMarcello Sylvester Bauer /* Spin up fans */ 6344e2271eaSMarcello Sylvester Bauer err = regulator_enable(data->reg); 6354e2271eaSMarcello Sylvester Bauer if (err) { 6364e2271eaSMarcello Sylvester Bauer dev_err(dev, "Failed to enable fan supply: %d\n", err); 6374e2271eaSMarcello Sylvester Bauer return err; 6384e2271eaSMarcello Sylvester Bauer } 6394e2271eaSMarcello Sylvester Bauer err = devm_add_action_or_reset(dev, max6639_regulator_disable, 6404e2271eaSMarcello Sylvester Bauer data->reg); 6414e2271eaSMarcello Sylvester Bauer if (err) { 6424e2271eaSMarcello Sylvester Bauer dev_err(dev, "Failed to register action: %d\n", err); 6434e2271eaSMarcello Sylvester Bauer return err; 6444e2271eaSMarcello Sylvester Bauer } 6454e2271eaSMarcello Sylvester Bauer } 6464e2271eaSMarcello Sylvester Bauer 647a5b79d62Sstigge@antcom.de /* Initialize the max6639 chip */ 6487981c584SGuenter Roeck err = max6639_init_client(client, data); 649a5b79d62Sstigge@antcom.de if (err < 0) 650b07405fbSGuenter Roeck return err; 651a5b79d62Sstigge@antcom.de 652*0f33272bSNaresh Solanki hwmon_dev = devm_hwmon_device_register_with_info(dev, client->name, 653*0f33272bSNaresh Solanki data, &max6639_chip_info, 654*0f33272bSNaresh Solanki NULL); 655*0f33272bSNaresh Solanki 6567981c584SGuenter Roeck return PTR_ERR_OR_ZERO(hwmon_dev); 657a5b79d62Sstigge@antcom.de } 658a5b79d62Sstigge@antcom.de 65952f30f77SMark Brown static int max6639_suspend(struct device *dev) 660a5b79d62Sstigge@antcom.de { 6614e2271eaSMarcello Sylvester Bauer struct max6639_data *data = dev_get_drvdata(dev); 6624e2271eaSMarcello Sylvester Bauer 6634e2271eaSMarcello Sylvester Bauer if (data->reg) 6644e2271eaSMarcello Sylvester Bauer regulator_disable(data->reg); 665a5b79d62Sstigge@antcom.de 66645bf8305SNaresh Solanki return regmap_write_bits(data->regmap, MAX6639_REG_GCONFIG, MAX6639_GCONFIG_STANDBY, 66745bf8305SNaresh Solanki MAX6639_GCONFIG_STANDBY); 668a5b79d62Sstigge@antcom.de } 669a5b79d62Sstigge@antcom.de 67052f30f77SMark Brown static int max6639_resume(struct device *dev) 671a5b79d62Sstigge@antcom.de { 6724e2271eaSMarcello Sylvester Bauer struct max6639_data *data = dev_get_drvdata(dev); 6734e2271eaSMarcello Sylvester Bauer int ret; 6744e2271eaSMarcello Sylvester Bauer 6754e2271eaSMarcello Sylvester Bauer if (data->reg) { 6764e2271eaSMarcello Sylvester Bauer ret = regulator_enable(data->reg); 6774e2271eaSMarcello Sylvester Bauer if (ret) { 6784e2271eaSMarcello Sylvester Bauer dev_err(dev, "Failed to enable fan supply: %d\n", ret); 6794e2271eaSMarcello Sylvester Bauer return ret; 6804e2271eaSMarcello Sylvester Bauer } 6814e2271eaSMarcello Sylvester Bauer } 6824e2271eaSMarcello Sylvester Bauer 68345bf8305SNaresh Solanki return regmap_write_bits(data->regmap, MAX6639_REG_GCONFIG, MAX6639_GCONFIG_STANDBY, 68445bf8305SNaresh Solanki ~MAX6639_GCONFIG_STANDBY); 685a5b79d62Sstigge@antcom.de } 686a5b79d62Sstigge@antcom.de 687a5b79d62Sstigge@antcom.de static const struct i2c_device_id max6639_id[] = { 688d8a66f36SUwe Kleine-König {"max6639"}, 689a5b79d62Sstigge@antcom.de { } 690a5b79d62Sstigge@antcom.de }; 691a5b79d62Sstigge@antcom.de 692a5b79d62Sstigge@antcom.de MODULE_DEVICE_TABLE(i2c, max6639_id); 693a5b79d62Sstigge@antcom.de 69477563092SJonathan Cameron static DEFINE_SIMPLE_DEV_PM_OPS(max6639_pm_ops, max6639_suspend, max6639_resume); 69552f30f77SMark Brown 696f11e2738SNaresh Solanki static const struct of_device_id max6639_of_match[] = { 697f11e2738SNaresh Solanki { .compatible = "maxim,max6639", }, 698f11e2738SNaresh Solanki { }, 699f11e2738SNaresh Solanki }; 700f11e2738SNaresh Solanki 701a5b79d62Sstigge@antcom.de static struct i2c_driver max6639_driver = { 702a5b79d62Sstigge@antcom.de .class = I2C_CLASS_HWMON, 703a5b79d62Sstigge@antcom.de .driver = { 704a5b79d62Sstigge@antcom.de .name = "max6639", 70577563092SJonathan Cameron .pm = pm_sleep_ptr(&max6639_pm_ops), 706f11e2738SNaresh Solanki .of_match_table = max6639_of_match, 707a5b79d62Sstigge@antcom.de }, 7081975d167SUwe Kleine-König .probe = max6639_probe, 709a5b79d62Sstigge@antcom.de .id_table = max6639_id, 710a5b79d62Sstigge@antcom.de .detect = max6639_detect, 711a5b79d62Sstigge@antcom.de .address_list = normal_i2c, 712a5b79d62Sstigge@antcom.de }; 713a5b79d62Sstigge@antcom.de 714f0967eeaSAxel Lin module_i2c_driver(max6639_driver); 715a5b79d62Sstigge@antcom.de 716a5b79d62Sstigge@antcom.de MODULE_AUTHOR("Roland Stigge <stigge@antcom.de>"); 717a5b79d62Sstigge@antcom.de MODULE_DESCRIPTION("max6639 driver"); 718a5b79d62Sstigge@antcom.de MODULE_LICENSE("GPL"); 719