14d420a6aSAndrew Jeffery /* 24d420a6aSAndrew Jeffery * Copyright (C) 2017 IBM Corp. 34d420a6aSAndrew Jeffery * 44d420a6aSAndrew Jeffery * This program is free software; you can redistribute it and/or modify 54d420a6aSAndrew Jeffery * it under the terms of the GNU General Public License as published by 64d420a6aSAndrew Jeffery * the Free Software Foundation; either version 2 of the License, or 74d420a6aSAndrew Jeffery * (at your option) any later version. 84d420a6aSAndrew Jeffery */ 94d420a6aSAndrew Jeffery 104d420a6aSAndrew Jeffery #include <linux/kernel.h> 114d420a6aSAndrew Jeffery #include <linux/module.h> 124d420a6aSAndrew Jeffery #include <linux/init.h> 134d420a6aSAndrew Jeffery #include <linux/err.h> 144d420a6aSAndrew Jeffery #include <linux/i2c.h> 154d420a6aSAndrew Jeffery #include "pmbus.h" 164d420a6aSAndrew Jeffery 174d420a6aSAndrew Jeffery enum max31785_regs { 184d420a6aSAndrew Jeffery MFR_REVISION = 0x9b, 19*cf583b42SAndrew Jeffery MFR_FAN_CONFIG = 0xf1, 204d420a6aSAndrew Jeffery }; 214d420a6aSAndrew Jeffery 22*cf583b42SAndrew Jeffery #define MAX31785 0x3030 23*cf583b42SAndrew Jeffery #define MAX31785A 0x3040 24*cf583b42SAndrew Jeffery 25*cf583b42SAndrew Jeffery #define MFR_FAN_CONFIG_DUAL_TACH BIT(12) 26*cf583b42SAndrew Jeffery 274d420a6aSAndrew Jeffery #define MAX31785_NR_PAGES 23 28*cf583b42SAndrew Jeffery #define MAX31785_NR_FAN_PAGES 6 29*cf583b42SAndrew Jeffery 30*cf583b42SAndrew Jeffery static int max31785_read_byte_data(struct i2c_client *client, int page, 31*cf583b42SAndrew Jeffery int reg) 32*cf583b42SAndrew Jeffery { 33*cf583b42SAndrew Jeffery if (page < MAX31785_NR_PAGES) 34*cf583b42SAndrew Jeffery return -ENODATA; 35*cf583b42SAndrew Jeffery 36*cf583b42SAndrew Jeffery switch (reg) { 37*cf583b42SAndrew Jeffery case PMBUS_VOUT_MODE: 38*cf583b42SAndrew Jeffery return -ENOTSUPP; 39*cf583b42SAndrew Jeffery case PMBUS_FAN_CONFIG_12: 40*cf583b42SAndrew Jeffery return pmbus_read_byte_data(client, page - MAX31785_NR_PAGES, 41*cf583b42SAndrew Jeffery reg); 42*cf583b42SAndrew Jeffery } 43*cf583b42SAndrew Jeffery 44*cf583b42SAndrew Jeffery return -ENODATA; 45*cf583b42SAndrew Jeffery } 46*cf583b42SAndrew Jeffery 47*cf583b42SAndrew Jeffery static int max31785_write_byte(struct i2c_client *client, int page, u8 value) 48*cf583b42SAndrew Jeffery { 49*cf583b42SAndrew Jeffery if (page < MAX31785_NR_PAGES) 50*cf583b42SAndrew Jeffery return -ENODATA; 51*cf583b42SAndrew Jeffery 52*cf583b42SAndrew Jeffery return -ENOTSUPP; 53*cf583b42SAndrew Jeffery } 54*cf583b42SAndrew Jeffery 55*cf583b42SAndrew Jeffery static int max31785_read_long_data(struct i2c_client *client, int page, 56*cf583b42SAndrew Jeffery int reg, u32 *data) 57*cf583b42SAndrew Jeffery { 58*cf583b42SAndrew Jeffery unsigned char cmdbuf[1]; 59*cf583b42SAndrew Jeffery unsigned char rspbuf[4]; 60*cf583b42SAndrew Jeffery int rc; 61*cf583b42SAndrew Jeffery 62*cf583b42SAndrew Jeffery struct i2c_msg msg[2] = { 63*cf583b42SAndrew Jeffery { 64*cf583b42SAndrew Jeffery .addr = client->addr, 65*cf583b42SAndrew Jeffery .flags = 0, 66*cf583b42SAndrew Jeffery .len = sizeof(cmdbuf), 67*cf583b42SAndrew Jeffery .buf = cmdbuf, 68*cf583b42SAndrew Jeffery }, 69*cf583b42SAndrew Jeffery { 70*cf583b42SAndrew Jeffery .addr = client->addr, 71*cf583b42SAndrew Jeffery .flags = I2C_M_RD, 72*cf583b42SAndrew Jeffery .len = sizeof(rspbuf), 73*cf583b42SAndrew Jeffery .buf = rspbuf, 74*cf583b42SAndrew Jeffery }, 75*cf583b42SAndrew Jeffery }; 76*cf583b42SAndrew Jeffery 77*cf583b42SAndrew Jeffery cmdbuf[0] = reg; 78*cf583b42SAndrew Jeffery 79*cf583b42SAndrew Jeffery rc = pmbus_set_page(client, page); 80*cf583b42SAndrew Jeffery if (rc < 0) 81*cf583b42SAndrew Jeffery return rc; 82*cf583b42SAndrew Jeffery 83*cf583b42SAndrew Jeffery rc = i2c_transfer(client->adapter, msg, ARRAY_SIZE(msg)); 84*cf583b42SAndrew Jeffery if (rc < 0) 85*cf583b42SAndrew Jeffery return rc; 86*cf583b42SAndrew Jeffery 87*cf583b42SAndrew Jeffery *data = (rspbuf[0] << (0 * 8)) | (rspbuf[1] << (1 * 8)) | 88*cf583b42SAndrew Jeffery (rspbuf[2] << (2 * 8)) | (rspbuf[3] << (3 * 8)); 89*cf583b42SAndrew Jeffery 90*cf583b42SAndrew Jeffery return rc; 91*cf583b42SAndrew Jeffery } 924d420a6aSAndrew Jeffery 9356ad86b4SAndrew Jeffery static int max31785_get_pwm(struct i2c_client *client, int page) 9456ad86b4SAndrew Jeffery { 9556ad86b4SAndrew Jeffery int rv; 9656ad86b4SAndrew Jeffery 9756ad86b4SAndrew Jeffery rv = pmbus_get_fan_rate_device(client, page, 0, percent); 9856ad86b4SAndrew Jeffery if (rv < 0) 9956ad86b4SAndrew Jeffery return rv; 10056ad86b4SAndrew Jeffery else if (rv >= 0x8000) 10156ad86b4SAndrew Jeffery return 0; 10256ad86b4SAndrew Jeffery else if (rv >= 0x2711) 10356ad86b4SAndrew Jeffery return 0x2710; 10456ad86b4SAndrew Jeffery 10556ad86b4SAndrew Jeffery return rv; 10656ad86b4SAndrew Jeffery } 10756ad86b4SAndrew Jeffery 10856ad86b4SAndrew Jeffery static int max31785_get_pwm_mode(struct i2c_client *client, int page) 10956ad86b4SAndrew Jeffery { 11056ad86b4SAndrew Jeffery int config; 11156ad86b4SAndrew Jeffery int command; 11256ad86b4SAndrew Jeffery 11356ad86b4SAndrew Jeffery config = pmbus_read_byte_data(client, page, PMBUS_FAN_CONFIG_12); 11456ad86b4SAndrew Jeffery if (config < 0) 11556ad86b4SAndrew Jeffery return config; 11656ad86b4SAndrew Jeffery 11756ad86b4SAndrew Jeffery command = pmbus_read_word_data(client, page, PMBUS_FAN_COMMAND_1); 11856ad86b4SAndrew Jeffery if (command < 0) 11956ad86b4SAndrew Jeffery return command; 12056ad86b4SAndrew Jeffery 12156ad86b4SAndrew Jeffery if (config & PB_FAN_1_RPM) 12256ad86b4SAndrew Jeffery return (command >= 0x8000) ? 3 : 2; 12356ad86b4SAndrew Jeffery 12456ad86b4SAndrew Jeffery if (command >= 0x8000) 12556ad86b4SAndrew Jeffery return 3; 12656ad86b4SAndrew Jeffery else if (command >= 0x2711) 12756ad86b4SAndrew Jeffery return 0; 12856ad86b4SAndrew Jeffery 12956ad86b4SAndrew Jeffery return 1; 13056ad86b4SAndrew Jeffery } 13156ad86b4SAndrew Jeffery 13256ad86b4SAndrew Jeffery static int max31785_read_word_data(struct i2c_client *client, int page, 13356ad86b4SAndrew Jeffery int reg) 13456ad86b4SAndrew Jeffery { 135*cf583b42SAndrew Jeffery u32 val; 13656ad86b4SAndrew Jeffery int rv; 13756ad86b4SAndrew Jeffery 13856ad86b4SAndrew Jeffery switch (reg) { 139*cf583b42SAndrew Jeffery case PMBUS_READ_FAN_SPEED_1: 140*cf583b42SAndrew Jeffery if (page < MAX31785_NR_PAGES) 141*cf583b42SAndrew Jeffery return -ENODATA; 142*cf583b42SAndrew Jeffery 143*cf583b42SAndrew Jeffery rv = max31785_read_long_data(client, page - MAX31785_NR_PAGES, 144*cf583b42SAndrew Jeffery reg, &val); 145*cf583b42SAndrew Jeffery if (rv < 0) 146*cf583b42SAndrew Jeffery return rv; 147*cf583b42SAndrew Jeffery 148*cf583b42SAndrew Jeffery rv = (val >> 16) & 0xffff; 149*cf583b42SAndrew Jeffery break; 150*cf583b42SAndrew Jeffery case PMBUS_FAN_COMMAND_1: 151*cf583b42SAndrew Jeffery /* 152*cf583b42SAndrew Jeffery * PMBUS_FAN_COMMAND_x is probed to judge whether or not to 153*cf583b42SAndrew Jeffery * expose fan control registers. 154*cf583b42SAndrew Jeffery * 155*cf583b42SAndrew Jeffery * Don't expose fan_target attribute for virtual pages. 156*cf583b42SAndrew Jeffery */ 157*cf583b42SAndrew Jeffery rv = (page >= MAX31785_NR_PAGES) ? -ENOTSUPP : -ENODATA; 158*cf583b42SAndrew Jeffery break; 15956ad86b4SAndrew Jeffery case PMBUS_VIRT_PWM_1: 16056ad86b4SAndrew Jeffery rv = max31785_get_pwm(client, page); 16156ad86b4SAndrew Jeffery break; 16256ad86b4SAndrew Jeffery case PMBUS_VIRT_PWM_ENABLE_1: 16356ad86b4SAndrew Jeffery rv = max31785_get_pwm_mode(client, page); 16456ad86b4SAndrew Jeffery break; 16556ad86b4SAndrew Jeffery default: 16656ad86b4SAndrew Jeffery rv = -ENODATA; 16756ad86b4SAndrew Jeffery break; 16856ad86b4SAndrew Jeffery } 16956ad86b4SAndrew Jeffery 17056ad86b4SAndrew Jeffery return rv; 17156ad86b4SAndrew Jeffery } 17256ad86b4SAndrew Jeffery 17356ad86b4SAndrew Jeffery static inline u32 max31785_scale_pwm(u32 sensor_val) 17456ad86b4SAndrew Jeffery { 17556ad86b4SAndrew Jeffery /* 17656ad86b4SAndrew Jeffery * The datasheet describes the accepted value range for manual PWM as 17756ad86b4SAndrew Jeffery * [0, 0x2710], while the hwmon pwmX sysfs interface accepts values in 17856ad86b4SAndrew Jeffery * [0, 255]. The MAX31785 uses DIRECT mode to scale the FAN_COMMAND 17956ad86b4SAndrew Jeffery * registers and in PWM mode the coefficients are m=1, b=0, R=2. The 18056ad86b4SAndrew Jeffery * important observation here is that 0x2710 == 10000 == 100 * 100. 18156ad86b4SAndrew Jeffery * 18256ad86b4SAndrew Jeffery * R=2 (== 10^2 == 100) accounts for scaling the value provided at the 18356ad86b4SAndrew Jeffery * sysfs interface into the required hardware resolution, but it does 18456ad86b4SAndrew Jeffery * not yet yield a value that we can write to the device (this initial 18556ad86b4SAndrew Jeffery * scaling is handled by pmbus_data2reg()). Multiplying by 100 below 18656ad86b4SAndrew Jeffery * translates the parameter value into the percentage units required by 18756ad86b4SAndrew Jeffery * PMBus, and then we scale back by 255 as required by the hwmon pwmX 18856ad86b4SAndrew Jeffery * interface to yield the percentage value at the appropriate 18956ad86b4SAndrew Jeffery * resolution for hardware. 19056ad86b4SAndrew Jeffery */ 19156ad86b4SAndrew Jeffery return (sensor_val * 100) / 255; 19256ad86b4SAndrew Jeffery } 19356ad86b4SAndrew Jeffery 19456ad86b4SAndrew Jeffery static int max31785_pwm_enable(struct i2c_client *client, int page, 19556ad86b4SAndrew Jeffery u16 word) 19656ad86b4SAndrew Jeffery { 19756ad86b4SAndrew Jeffery int config = 0; 19856ad86b4SAndrew Jeffery int rate; 19956ad86b4SAndrew Jeffery 20056ad86b4SAndrew Jeffery switch (word) { 20156ad86b4SAndrew Jeffery case 0: 20256ad86b4SAndrew Jeffery rate = 0x7fff; 20356ad86b4SAndrew Jeffery break; 20456ad86b4SAndrew Jeffery case 1: 20556ad86b4SAndrew Jeffery rate = pmbus_get_fan_rate_cached(client, page, 0, percent); 20656ad86b4SAndrew Jeffery if (rate < 0) 20756ad86b4SAndrew Jeffery return rate; 20856ad86b4SAndrew Jeffery rate = max31785_scale_pwm(rate); 20956ad86b4SAndrew Jeffery break; 21056ad86b4SAndrew Jeffery case 2: 21156ad86b4SAndrew Jeffery config = PB_FAN_1_RPM; 21256ad86b4SAndrew Jeffery rate = pmbus_get_fan_rate_cached(client, page, 0, rpm); 21356ad86b4SAndrew Jeffery if (rate < 0) 21456ad86b4SAndrew Jeffery return rate; 21556ad86b4SAndrew Jeffery break; 21656ad86b4SAndrew Jeffery case 3: 21756ad86b4SAndrew Jeffery rate = 0xffff; 21856ad86b4SAndrew Jeffery break; 21956ad86b4SAndrew Jeffery default: 22056ad86b4SAndrew Jeffery return -EINVAL; 22156ad86b4SAndrew Jeffery } 22256ad86b4SAndrew Jeffery 22356ad86b4SAndrew Jeffery return pmbus_update_fan(client, page, 0, config, PB_FAN_1_RPM, rate); 22456ad86b4SAndrew Jeffery } 22556ad86b4SAndrew Jeffery 22656ad86b4SAndrew Jeffery static int max31785_write_word_data(struct i2c_client *client, int page, 22756ad86b4SAndrew Jeffery int reg, u16 word) 22856ad86b4SAndrew Jeffery { 22956ad86b4SAndrew Jeffery switch (reg) { 23056ad86b4SAndrew Jeffery case PMBUS_VIRT_PWM_1: 23156ad86b4SAndrew Jeffery return pmbus_update_fan(client, page, 0, 0, PB_FAN_1_RPM, 23256ad86b4SAndrew Jeffery max31785_scale_pwm(word)); 23356ad86b4SAndrew Jeffery case PMBUS_VIRT_PWM_ENABLE_1: 23456ad86b4SAndrew Jeffery return max31785_pwm_enable(client, page, word); 23556ad86b4SAndrew Jeffery default: 23656ad86b4SAndrew Jeffery break; 23756ad86b4SAndrew Jeffery } 23856ad86b4SAndrew Jeffery 23956ad86b4SAndrew Jeffery return -ENODATA; 24056ad86b4SAndrew Jeffery } 24156ad86b4SAndrew Jeffery 2424d420a6aSAndrew Jeffery #define MAX31785_FAN_FUNCS \ 24356ad86b4SAndrew Jeffery (PMBUS_HAVE_FAN12 | PMBUS_HAVE_STATUS_FAN12 | PMBUS_HAVE_PWM12) 2444d420a6aSAndrew Jeffery 2454d420a6aSAndrew Jeffery #define MAX31785_TEMP_FUNCS \ 2464d420a6aSAndrew Jeffery (PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP) 2474d420a6aSAndrew Jeffery 2484d420a6aSAndrew Jeffery #define MAX31785_VOUT_FUNCS \ 2494d420a6aSAndrew Jeffery (PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT) 2504d420a6aSAndrew Jeffery 251*cf583b42SAndrew Jeffery #define MAX37185_NUM_FAN_PAGES 6 252*cf583b42SAndrew Jeffery 2534d420a6aSAndrew Jeffery static const struct pmbus_driver_info max31785_info = { 2544d420a6aSAndrew Jeffery .pages = MAX31785_NR_PAGES, 2554d420a6aSAndrew Jeffery 25656ad86b4SAndrew Jeffery .write_word_data = max31785_write_word_data, 257*cf583b42SAndrew Jeffery .read_byte_data = max31785_read_byte_data, 25856ad86b4SAndrew Jeffery .read_word_data = max31785_read_word_data, 259*cf583b42SAndrew Jeffery .write_byte = max31785_write_byte, 26056ad86b4SAndrew Jeffery 2614d420a6aSAndrew Jeffery /* RPM */ 2624d420a6aSAndrew Jeffery .format[PSC_FAN] = direct, 2634d420a6aSAndrew Jeffery .m[PSC_FAN] = 1, 2644d420a6aSAndrew Jeffery .b[PSC_FAN] = 0, 2654d420a6aSAndrew Jeffery .R[PSC_FAN] = 0, 26656ad86b4SAndrew Jeffery /* PWM */ 26756ad86b4SAndrew Jeffery .format[PSC_PWM] = direct, 26856ad86b4SAndrew Jeffery .m[PSC_PWM] = 1, 26956ad86b4SAndrew Jeffery .b[PSC_PWM] = 0, 27056ad86b4SAndrew Jeffery .R[PSC_PWM] = 2, 2714d420a6aSAndrew Jeffery .func[0] = MAX31785_FAN_FUNCS, 2724d420a6aSAndrew Jeffery .func[1] = MAX31785_FAN_FUNCS, 2734d420a6aSAndrew Jeffery .func[2] = MAX31785_FAN_FUNCS, 2744d420a6aSAndrew Jeffery .func[3] = MAX31785_FAN_FUNCS, 2754d420a6aSAndrew Jeffery .func[4] = MAX31785_FAN_FUNCS, 2764d420a6aSAndrew Jeffery .func[5] = MAX31785_FAN_FUNCS, 2774d420a6aSAndrew Jeffery 2784d420a6aSAndrew Jeffery .format[PSC_TEMPERATURE] = direct, 2794d420a6aSAndrew Jeffery .m[PSC_TEMPERATURE] = 1, 2804d420a6aSAndrew Jeffery .b[PSC_TEMPERATURE] = 0, 2814d420a6aSAndrew Jeffery .R[PSC_TEMPERATURE] = 2, 2824d420a6aSAndrew Jeffery .func[6] = MAX31785_TEMP_FUNCS, 2834d420a6aSAndrew Jeffery .func[7] = MAX31785_TEMP_FUNCS, 2844d420a6aSAndrew Jeffery .func[8] = MAX31785_TEMP_FUNCS, 2854d420a6aSAndrew Jeffery .func[9] = MAX31785_TEMP_FUNCS, 2864d420a6aSAndrew Jeffery .func[10] = MAX31785_TEMP_FUNCS, 2874d420a6aSAndrew Jeffery .func[11] = MAX31785_TEMP_FUNCS, 2884d420a6aSAndrew Jeffery .func[12] = MAX31785_TEMP_FUNCS, 2894d420a6aSAndrew Jeffery .func[13] = MAX31785_TEMP_FUNCS, 2904d420a6aSAndrew Jeffery .func[14] = MAX31785_TEMP_FUNCS, 2914d420a6aSAndrew Jeffery .func[15] = MAX31785_TEMP_FUNCS, 2924d420a6aSAndrew Jeffery .func[16] = MAX31785_TEMP_FUNCS, 2934d420a6aSAndrew Jeffery 2944d420a6aSAndrew Jeffery .format[PSC_VOLTAGE_OUT] = direct, 2954d420a6aSAndrew Jeffery .m[PSC_VOLTAGE_OUT] = 1, 2964d420a6aSAndrew Jeffery .b[PSC_VOLTAGE_OUT] = 0, 2974d420a6aSAndrew Jeffery .R[PSC_VOLTAGE_OUT] = 0, 2984d420a6aSAndrew Jeffery .func[17] = MAX31785_VOUT_FUNCS, 2994d420a6aSAndrew Jeffery .func[18] = MAX31785_VOUT_FUNCS, 3004d420a6aSAndrew Jeffery .func[19] = MAX31785_VOUT_FUNCS, 3014d420a6aSAndrew Jeffery .func[20] = MAX31785_VOUT_FUNCS, 3024d420a6aSAndrew Jeffery .func[21] = MAX31785_VOUT_FUNCS, 3034d420a6aSAndrew Jeffery .func[22] = MAX31785_VOUT_FUNCS, 3044d420a6aSAndrew Jeffery }; 3054d420a6aSAndrew Jeffery 306*cf583b42SAndrew Jeffery static int max31785_configure_dual_tach(struct i2c_client *client, 307*cf583b42SAndrew Jeffery struct pmbus_driver_info *info) 308*cf583b42SAndrew Jeffery { 309*cf583b42SAndrew Jeffery int ret; 310*cf583b42SAndrew Jeffery int i; 311*cf583b42SAndrew Jeffery 312*cf583b42SAndrew Jeffery for (i = 0; i < MAX31785_NR_FAN_PAGES; i++) { 313*cf583b42SAndrew Jeffery ret = i2c_smbus_write_byte_data(client, PMBUS_PAGE, i); 314*cf583b42SAndrew Jeffery if (ret < 0) 315*cf583b42SAndrew Jeffery return ret; 316*cf583b42SAndrew Jeffery 317*cf583b42SAndrew Jeffery ret = i2c_smbus_read_word_data(client, MFR_FAN_CONFIG); 318*cf583b42SAndrew Jeffery if (ret < 0) 319*cf583b42SAndrew Jeffery return ret; 320*cf583b42SAndrew Jeffery 321*cf583b42SAndrew Jeffery if (ret & MFR_FAN_CONFIG_DUAL_TACH) { 322*cf583b42SAndrew Jeffery int virtual = MAX31785_NR_PAGES + i; 323*cf583b42SAndrew Jeffery 324*cf583b42SAndrew Jeffery info->pages = virtual + 1; 325*cf583b42SAndrew Jeffery info->func[virtual] |= PMBUS_HAVE_FAN12; 326*cf583b42SAndrew Jeffery info->func[virtual] |= PMBUS_PAGE_VIRTUAL; 327*cf583b42SAndrew Jeffery } 328*cf583b42SAndrew Jeffery } 329*cf583b42SAndrew Jeffery 330*cf583b42SAndrew Jeffery return 0; 331*cf583b42SAndrew Jeffery } 332*cf583b42SAndrew Jeffery 3334d420a6aSAndrew Jeffery static int max31785_probe(struct i2c_client *client, 3344d420a6aSAndrew Jeffery const struct i2c_device_id *id) 3354d420a6aSAndrew Jeffery { 3364d420a6aSAndrew Jeffery struct device *dev = &client->dev; 3374d420a6aSAndrew Jeffery struct pmbus_driver_info *info; 338*cf583b42SAndrew Jeffery bool dual_tach = false; 3394d420a6aSAndrew Jeffery s64 ret; 3404d420a6aSAndrew Jeffery 341*cf583b42SAndrew Jeffery if (!i2c_check_functionality(client->adapter, 342*cf583b42SAndrew Jeffery I2C_FUNC_SMBUS_BYTE_DATA | 343*cf583b42SAndrew Jeffery I2C_FUNC_SMBUS_WORD_DATA)) 344*cf583b42SAndrew Jeffery return -ENODEV; 345*cf583b42SAndrew Jeffery 3464d420a6aSAndrew Jeffery info = devm_kzalloc(dev, sizeof(struct pmbus_driver_info), GFP_KERNEL); 3474d420a6aSAndrew Jeffery if (!info) 3484d420a6aSAndrew Jeffery return -ENOMEM; 3494d420a6aSAndrew Jeffery 3504d420a6aSAndrew Jeffery *info = max31785_info; 3514d420a6aSAndrew Jeffery 3524d420a6aSAndrew Jeffery ret = i2c_smbus_write_byte_data(client, PMBUS_PAGE, 255); 3534d420a6aSAndrew Jeffery if (ret < 0) 3544d420a6aSAndrew Jeffery return ret; 3554d420a6aSAndrew Jeffery 356*cf583b42SAndrew Jeffery ret = i2c_smbus_read_word_data(client, MFR_REVISION); 357*cf583b42SAndrew Jeffery if (ret < 0) 358*cf583b42SAndrew Jeffery return ret; 359*cf583b42SAndrew Jeffery 360*cf583b42SAndrew Jeffery if (ret == MAX31785A) { 361*cf583b42SAndrew Jeffery dual_tach = true; 362*cf583b42SAndrew Jeffery } else if (ret == MAX31785) { 363*cf583b42SAndrew Jeffery if (!strcmp("max31785a", id->name)) 364*cf583b42SAndrew Jeffery dev_warn(dev, "Expected max3175a, found max31785: cannot provide secondary tachometer readings\n"); 365*cf583b42SAndrew Jeffery } else { 366*cf583b42SAndrew Jeffery return -ENODEV; 367*cf583b42SAndrew Jeffery } 368*cf583b42SAndrew Jeffery 369*cf583b42SAndrew Jeffery if (dual_tach) { 370*cf583b42SAndrew Jeffery ret = max31785_configure_dual_tach(client, info); 371*cf583b42SAndrew Jeffery if (ret < 0) 372*cf583b42SAndrew Jeffery return ret; 373*cf583b42SAndrew Jeffery } 374*cf583b42SAndrew Jeffery 3754d420a6aSAndrew Jeffery return pmbus_do_probe(client, id, info); 3764d420a6aSAndrew Jeffery } 3774d420a6aSAndrew Jeffery 3784d420a6aSAndrew Jeffery static const struct i2c_device_id max31785_id[] = { 3794d420a6aSAndrew Jeffery { "max31785", 0 }, 3804d420a6aSAndrew Jeffery { "max31785a", 0 }, 3814d420a6aSAndrew Jeffery { }, 3824d420a6aSAndrew Jeffery }; 3834d420a6aSAndrew Jeffery 3844d420a6aSAndrew Jeffery MODULE_DEVICE_TABLE(i2c, max31785_id); 3854d420a6aSAndrew Jeffery 3864d420a6aSAndrew Jeffery static struct i2c_driver max31785_driver = { 3874d420a6aSAndrew Jeffery .driver = { 3884d420a6aSAndrew Jeffery .name = "max31785", 3894d420a6aSAndrew Jeffery }, 3904d420a6aSAndrew Jeffery .probe = max31785_probe, 3914d420a6aSAndrew Jeffery .remove = pmbus_do_remove, 3924d420a6aSAndrew Jeffery .id_table = max31785_id, 3934d420a6aSAndrew Jeffery }; 3944d420a6aSAndrew Jeffery 3954d420a6aSAndrew Jeffery module_i2c_driver(max31785_driver); 3964d420a6aSAndrew Jeffery 3974d420a6aSAndrew Jeffery MODULE_AUTHOR("Andrew Jeffery <andrew@aj.id.au>"); 3984d420a6aSAndrew Jeffery MODULE_DESCRIPTION("PMBus driver for the Maxim MAX31785"); 3994d420a6aSAndrew Jeffery MODULE_LICENSE("GPL"); 400