19d2ecfb7SGuenter Roeck /* 29d2ecfb7SGuenter Roeck * Hardware monitoring driver for Maxim MAX34440/MAX34441 39d2ecfb7SGuenter Roeck * 49d2ecfb7SGuenter Roeck * Copyright (c) 2011 Ericsson AB. 59d2ecfb7SGuenter Roeck * 69d2ecfb7SGuenter Roeck * This program is free software; you can redistribute it and/or modify 79d2ecfb7SGuenter Roeck * it under the terms of the GNU General Public License as published by 89d2ecfb7SGuenter Roeck * the Free Software Foundation; either version 2 of the License, or 99d2ecfb7SGuenter Roeck * (at your option) any later version. 109d2ecfb7SGuenter Roeck * 119d2ecfb7SGuenter Roeck * This program is distributed in the hope that it will be useful, 129d2ecfb7SGuenter Roeck * but WITHOUT ANY WARRANTY; without even the implied warranty of 139d2ecfb7SGuenter Roeck * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 149d2ecfb7SGuenter Roeck * GNU General Public License for more details. 159d2ecfb7SGuenter Roeck * 169d2ecfb7SGuenter Roeck * You should have received a copy of the GNU General Public License 179d2ecfb7SGuenter Roeck * along with this program; if not, write to the Free Software 189d2ecfb7SGuenter Roeck * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 199d2ecfb7SGuenter Roeck */ 209d2ecfb7SGuenter Roeck 219d2ecfb7SGuenter Roeck #include <linux/kernel.h> 229d2ecfb7SGuenter Roeck #include <linux/module.h> 239d2ecfb7SGuenter Roeck #include <linux/init.h> 249d2ecfb7SGuenter Roeck #include <linux/err.h> 259d2ecfb7SGuenter Roeck #include <linux/i2c.h> 269d2ecfb7SGuenter Roeck #include "pmbus.h" 279d2ecfb7SGuenter Roeck 289d2ecfb7SGuenter Roeck enum chips { max34440, max34441 }; 299d2ecfb7SGuenter Roeck 30*98591dbeSGuenter Roeck #define MAX34440_MFR_VOUT_PEAK 0xd4 31*98591dbeSGuenter Roeck #define MAX34440_MFR_IOUT_PEAK 0xd5 32*98591dbeSGuenter Roeck #define MAX34440_MFR_TEMPERATURE_PEAK 0xd6 33*98591dbeSGuenter Roeck 349d2ecfb7SGuenter Roeck #define MAX34440_STATUS_OC_WARN (1 << 0) 359d2ecfb7SGuenter Roeck #define MAX34440_STATUS_OC_FAULT (1 << 1) 369d2ecfb7SGuenter Roeck #define MAX34440_STATUS_OT_FAULT (1 << 5) 379d2ecfb7SGuenter Roeck #define MAX34440_STATUS_OT_WARN (1 << 6) 389d2ecfb7SGuenter Roeck 39*98591dbeSGuenter Roeck static int max34440_read_word_data(struct i2c_client *client, int page, int reg) 40*98591dbeSGuenter Roeck { 41*98591dbeSGuenter Roeck int ret; 42*98591dbeSGuenter Roeck 43*98591dbeSGuenter Roeck switch (reg) { 44*98591dbeSGuenter Roeck case PMBUS_VIRT_READ_VOUT_MAX: 45*98591dbeSGuenter Roeck ret = pmbus_read_word_data(client, page, 46*98591dbeSGuenter Roeck MAX34440_MFR_VOUT_PEAK); 47*98591dbeSGuenter Roeck break; 48*98591dbeSGuenter Roeck case PMBUS_VIRT_READ_IOUT_MAX: 49*98591dbeSGuenter Roeck ret = pmbus_read_word_data(client, page, 50*98591dbeSGuenter Roeck MAX34440_MFR_IOUT_PEAK); 51*98591dbeSGuenter Roeck break; 52*98591dbeSGuenter Roeck case PMBUS_VIRT_READ_TEMP_MAX: 53*98591dbeSGuenter Roeck ret = pmbus_read_word_data(client, page, 54*98591dbeSGuenter Roeck MAX34440_MFR_TEMPERATURE_PEAK); 55*98591dbeSGuenter Roeck break; 56*98591dbeSGuenter Roeck case PMBUS_VIRT_RESET_VOUT_HISTORY: 57*98591dbeSGuenter Roeck case PMBUS_VIRT_RESET_IOUT_HISTORY: 58*98591dbeSGuenter Roeck case PMBUS_VIRT_RESET_TEMP_HISTORY: 59*98591dbeSGuenter Roeck ret = 0; 60*98591dbeSGuenter Roeck break; 61*98591dbeSGuenter Roeck default: 62*98591dbeSGuenter Roeck ret = -ENODATA; 63*98591dbeSGuenter Roeck break; 64*98591dbeSGuenter Roeck } 65*98591dbeSGuenter Roeck return ret; 66*98591dbeSGuenter Roeck } 67*98591dbeSGuenter Roeck 68*98591dbeSGuenter Roeck static int max34440_write_word_data(struct i2c_client *client, int page, 69*98591dbeSGuenter Roeck int reg, u16 word) 70*98591dbeSGuenter Roeck { 71*98591dbeSGuenter Roeck int ret; 72*98591dbeSGuenter Roeck 73*98591dbeSGuenter Roeck switch (reg) { 74*98591dbeSGuenter Roeck case PMBUS_VIRT_RESET_VOUT_HISTORY: 75*98591dbeSGuenter Roeck ret = pmbus_write_word_data(client, page, 76*98591dbeSGuenter Roeck MAX34440_MFR_VOUT_PEAK, 0); 77*98591dbeSGuenter Roeck break; 78*98591dbeSGuenter Roeck case PMBUS_VIRT_RESET_IOUT_HISTORY: 79*98591dbeSGuenter Roeck ret = pmbus_write_word_data(client, page, 80*98591dbeSGuenter Roeck MAX34440_MFR_IOUT_PEAK, 0); 81*98591dbeSGuenter Roeck break; 82*98591dbeSGuenter Roeck case PMBUS_VIRT_RESET_TEMP_HISTORY: 83*98591dbeSGuenter Roeck ret = pmbus_write_word_data(client, page, 84*98591dbeSGuenter Roeck MAX34440_MFR_TEMPERATURE_PEAK, 85*98591dbeSGuenter Roeck 0xffff); 86*98591dbeSGuenter Roeck break; 87*98591dbeSGuenter Roeck default: 88*98591dbeSGuenter Roeck ret = -ENODATA; 89*98591dbeSGuenter Roeck break; 90*98591dbeSGuenter Roeck } 91*98591dbeSGuenter Roeck return ret; 92*98591dbeSGuenter Roeck } 93*98591dbeSGuenter Roeck 949d2ecfb7SGuenter Roeck static int max34440_read_byte_data(struct i2c_client *client, int page, int reg) 959d2ecfb7SGuenter Roeck { 969d2ecfb7SGuenter Roeck int ret; 979d2ecfb7SGuenter Roeck int mfg_status; 989d2ecfb7SGuenter Roeck 999d2ecfb7SGuenter Roeck ret = pmbus_set_page(client, page); 1009d2ecfb7SGuenter Roeck if (ret < 0) 1019d2ecfb7SGuenter Roeck return ret; 1029d2ecfb7SGuenter Roeck 1039d2ecfb7SGuenter Roeck switch (reg) { 1049d2ecfb7SGuenter Roeck case PMBUS_STATUS_IOUT: 1059d2ecfb7SGuenter Roeck mfg_status = pmbus_read_word_data(client, 0, 1069d2ecfb7SGuenter Roeck PMBUS_STATUS_MFR_SPECIFIC); 1079d2ecfb7SGuenter Roeck if (mfg_status < 0) 1089d2ecfb7SGuenter Roeck return mfg_status; 1099d2ecfb7SGuenter Roeck if (mfg_status & MAX34440_STATUS_OC_WARN) 1109d2ecfb7SGuenter Roeck ret |= PB_IOUT_OC_WARNING; 1119d2ecfb7SGuenter Roeck if (mfg_status & MAX34440_STATUS_OC_FAULT) 1129d2ecfb7SGuenter Roeck ret |= PB_IOUT_OC_FAULT; 1139d2ecfb7SGuenter Roeck break; 1149d2ecfb7SGuenter Roeck case PMBUS_STATUS_TEMPERATURE: 1159d2ecfb7SGuenter Roeck mfg_status = pmbus_read_word_data(client, 0, 1169d2ecfb7SGuenter Roeck PMBUS_STATUS_MFR_SPECIFIC); 1179d2ecfb7SGuenter Roeck if (mfg_status < 0) 1189d2ecfb7SGuenter Roeck return mfg_status; 1199d2ecfb7SGuenter Roeck if (mfg_status & MAX34440_STATUS_OT_WARN) 1209d2ecfb7SGuenter Roeck ret |= PB_TEMP_OT_WARNING; 1219d2ecfb7SGuenter Roeck if (mfg_status & MAX34440_STATUS_OT_FAULT) 1229d2ecfb7SGuenter Roeck ret |= PB_TEMP_OT_FAULT; 1239d2ecfb7SGuenter Roeck break; 1249d2ecfb7SGuenter Roeck default: 1259d2ecfb7SGuenter Roeck ret = -ENODATA; 1269d2ecfb7SGuenter Roeck break; 1279d2ecfb7SGuenter Roeck } 1289d2ecfb7SGuenter Roeck return ret; 1299d2ecfb7SGuenter Roeck } 1309d2ecfb7SGuenter Roeck 1319d2ecfb7SGuenter Roeck static struct pmbus_driver_info max34440_info[] = { 1329d2ecfb7SGuenter Roeck [max34440] = { 1339d2ecfb7SGuenter Roeck .pages = 14, 1341061d851SGuenter Roeck .format[PSC_VOLTAGE_IN] = direct, 1351061d851SGuenter Roeck .format[PSC_VOLTAGE_OUT] = direct, 1361061d851SGuenter Roeck .format[PSC_TEMPERATURE] = direct, 1371061d851SGuenter Roeck .format[PSC_CURRENT_OUT] = direct, 1389d2ecfb7SGuenter Roeck .m[PSC_VOLTAGE_IN] = 1, 1399d2ecfb7SGuenter Roeck .b[PSC_VOLTAGE_IN] = 0, 1409d2ecfb7SGuenter Roeck .R[PSC_VOLTAGE_IN] = 3, /* R = 0 in datasheet reflects mV */ 1419d2ecfb7SGuenter Roeck .m[PSC_VOLTAGE_OUT] = 1, 1429d2ecfb7SGuenter Roeck .b[PSC_VOLTAGE_OUT] = 0, 1439d2ecfb7SGuenter Roeck .R[PSC_VOLTAGE_OUT] = 3, /* R = 0 in datasheet reflects mV */ 1449d2ecfb7SGuenter Roeck .m[PSC_CURRENT_OUT] = 1, 1459d2ecfb7SGuenter Roeck .b[PSC_CURRENT_OUT] = 0, 1469d2ecfb7SGuenter Roeck .R[PSC_CURRENT_OUT] = 3, /* R = 0 in datasheet reflects mA */ 1479d2ecfb7SGuenter Roeck .m[PSC_TEMPERATURE] = 1, 1489d2ecfb7SGuenter Roeck .b[PSC_TEMPERATURE] = 0, 1499d2ecfb7SGuenter Roeck .R[PSC_TEMPERATURE] = 2, 1509d2ecfb7SGuenter Roeck .func[0] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT 1519d2ecfb7SGuenter Roeck | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT, 1529d2ecfb7SGuenter Roeck .func[1] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT 1539d2ecfb7SGuenter Roeck | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT, 1549d2ecfb7SGuenter Roeck .func[2] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT 1559d2ecfb7SGuenter Roeck | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT, 1569d2ecfb7SGuenter Roeck .func[3] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT 1579d2ecfb7SGuenter Roeck | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT, 1589d2ecfb7SGuenter Roeck .func[4] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT 1599d2ecfb7SGuenter Roeck | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT, 1609d2ecfb7SGuenter Roeck .func[5] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT 1619d2ecfb7SGuenter Roeck | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT, 1629d2ecfb7SGuenter Roeck .func[6] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP, 1639d2ecfb7SGuenter Roeck .func[7] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP, 1649d2ecfb7SGuenter Roeck .func[8] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP, 1659d2ecfb7SGuenter Roeck .func[9] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP, 1669d2ecfb7SGuenter Roeck .func[10] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP, 1679d2ecfb7SGuenter Roeck .func[11] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP, 1689d2ecfb7SGuenter Roeck .func[12] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP, 1699d2ecfb7SGuenter Roeck .func[13] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP, 1709d2ecfb7SGuenter Roeck .read_byte_data = max34440_read_byte_data, 171*98591dbeSGuenter Roeck .read_word_data = max34440_read_word_data, 172*98591dbeSGuenter Roeck .write_word_data = max34440_write_word_data, 1739d2ecfb7SGuenter Roeck }, 1749d2ecfb7SGuenter Roeck [max34441] = { 1759d2ecfb7SGuenter Roeck .pages = 12, 1761061d851SGuenter Roeck .format[PSC_VOLTAGE_IN] = direct, 1771061d851SGuenter Roeck .format[PSC_VOLTAGE_OUT] = direct, 1781061d851SGuenter Roeck .format[PSC_TEMPERATURE] = direct, 1791061d851SGuenter Roeck .format[PSC_CURRENT_OUT] = direct, 1801061d851SGuenter Roeck .format[PSC_FAN] = direct, 1819d2ecfb7SGuenter Roeck .m[PSC_VOLTAGE_IN] = 1, 1829d2ecfb7SGuenter Roeck .b[PSC_VOLTAGE_IN] = 0, 1839d2ecfb7SGuenter Roeck .R[PSC_VOLTAGE_IN] = 3, 1849d2ecfb7SGuenter Roeck .m[PSC_VOLTAGE_OUT] = 1, 1859d2ecfb7SGuenter Roeck .b[PSC_VOLTAGE_OUT] = 0, 1869d2ecfb7SGuenter Roeck .R[PSC_VOLTAGE_OUT] = 3, 1879d2ecfb7SGuenter Roeck .m[PSC_CURRENT_OUT] = 1, 1889d2ecfb7SGuenter Roeck .b[PSC_CURRENT_OUT] = 0, 1899d2ecfb7SGuenter Roeck .R[PSC_CURRENT_OUT] = 3, 1909d2ecfb7SGuenter Roeck .m[PSC_TEMPERATURE] = 1, 1919d2ecfb7SGuenter Roeck .b[PSC_TEMPERATURE] = 0, 1929d2ecfb7SGuenter Roeck .R[PSC_TEMPERATURE] = 2, 1939d2ecfb7SGuenter Roeck .m[PSC_FAN] = 1, 1949d2ecfb7SGuenter Roeck .b[PSC_FAN] = 0, 1959d2ecfb7SGuenter Roeck .R[PSC_FAN] = 0, 1969d2ecfb7SGuenter Roeck .func[0] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT 1979d2ecfb7SGuenter Roeck | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT, 1989d2ecfb7SGuenter Roeck .func[1] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT 1999d2ecfb7SGuenter Roeck | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT, 2009d2ecfb7SGuenter Roeck .func[2] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT 2019d2ecfb7SGuenter Roeck | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT, 2029d2ecfb7SGuenter Roeck .func[3] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT 2039d2ecfb7SGuenter Roeck | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT, 2049d2ecfb7SGuenter Roeck .func[4] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT 2059d2ecfb7SGuenter Roeck | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT, 2069d2ecfb7SGuenter Roeck .func[5] = PMBUS_HAVE_FAN12 | PMBUS_HAVE_STATUS_FAN12, 2079d2ecfb7SGuenter Roeck .func[6] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP, 2089d2ecfb7SGuenter Roeck .func[7] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP, 2099d2ecfb7SGuenter Roeck .func[8] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP, 2109d2ecfb7SGuenter Roeck .func[9] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP, 2119d2ecfb7SGuenter Roeck .func[10] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP, 2129d2ecfb7SGuenter Roeck .func[11] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP, 2139d2ecfb7SGuenter Roeck .read_byte_data = max34440_read_byte_data, 214*98591dbeSGuenter Roeck .read_word_data = max34440_read_word_data, 215*98591dbeSGuenter Roeck .write_word_data = max34440_write_word_data, 2169d2ecfb7SGuenter Roeck }, 2179d2ecfb7SGuenter Roeck }; 2189d2ecfb7SGuenter Roeck 2199d2ecfb7SGuenter Roeck static int max34440_probe(struct i2c_client *client, 2209d2ecfb7SGuenter Roeck const struct i2c_device_id *id) 2219d2ecfb7SGuenter Roeck { 2229d2ecfb7SGuenter Roeck return pmbus_do_probe(client, id, &max34440_info[id->driver_data]); 2239d2ecfb7SGuenter Roeck } 2249d2ecfb7SGuenter Roeck 2259d2ecfb7SGuenter Roeck static int max34440_remove(struct i2c_client *client) 2269d2ecfb7SGuenter Roeck { 2279d2ecfb7SGuenter Roeck return pmbus_do_remove(client); 2289d2ecfb7SGuenter Roeck } 2299d2ecfb7SGuenter Roeck 2309d2ecfb7SGuenter Roeck static const struct i2c_device_id max34440_id[] = { 2319d2ecfb7SGuenter Roeck {"max34440", max34440}, 2329d2ecfb7SGuenter Roeck {"max34441", max34441}, 2339d2ecfb7SGuenter Roeck {} 2349d2ecfb7SGuenter Roeck }; 2359d2ecfb7SGuenter Roeck 2369d2ecfb7SGuenter Roeck MODULE_DEVICE_TABLE(i2c, max34440_id); 2379d2ecfb7SGuenter Roeck 2389d2ecfb7SGuenter Roeck /* This is the driver that will be inserted */ 2399d2ecfb7SGuenter Roeck static struct i2c_driver max34440_driver = { 2409d2ecfb7SGuenter Roeck .driver = { 2419d2ecfb7SGuenter Roeck .name = "max34440", 2429d2ecfb7SGuenter Roeck }, 2439d2ecfb7SGuenter Roeck .probe = max34440_probe, 2449d2ecfb7SGuenter Roeck .remove = max34440_remove, 2459d2ecfb7SGuenter Roeck .id_table = max34440_id, 2469d2ecfb7SGuenter Roeck }; 2479d2ecfb7SGuenter Roeck 2489d2ecfb7SGuenter Roeck static int __init max34440_init(void) 2499d2ecfb7SGuenter Roeck { 2509d2ecfb7SGuenter Roeck return i2c_add_driver(&max34440_driver); 2519d2ecfb7SGuenter Roeck } 2529d2ecfb7SGuenter Roeck 2539d2ecfb7SGuenter Roeck static void __exit max34440_exit(void) 2549d2ecfb7SGuenter Roeck { 2559d2ecfb7SGuenter Roeck i2c_del_driver(&max34440_driver); 2569d2ecfb7SGuenter Roeck } 2579d2ecfb7SGuenter Roeck 2589d2ecfb7SGuenter Roeck MODULE_AUTHOR("Guenter Roeck"); 2599d2ecfb7SGuenter Roeck MODULE_DESCRIPTION("PMBus driver for Maxim MAX34440/MAX34441"); 2609d2ecfb7SGuenter Roeck MODULE_LICENSE("GPL"); 2619d2ecfb7SGuenter Roeck module_init(max34440_init); 2629d2ecfb7SGuenter Roeck module_exit(max34440_exit); 263