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 3098591dbeSGuenter Roeck #define MAX34440_MFR_VOUT_PEAK 0xd4 3198591dbeSGuenter Roeck #define MAX34440_MFR_IOUT_PEAK 0xd5 3298591dbeSGuenter Roeck #define MAX34440_MFR_TEMPERATURE_PEAK 0xd6 3398591dbeSGuenter 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 3998591dbeSGuenter Roeck static int max34440_read_word_data(struct i2c_client *client, int page, int reg) 4098591dbeSGuenter Roeck { 4198591dbeSGuenter Roeck int ret; 4298591dbeSGuenter Roeck 4398591dbeSGuenter Roeck switch (reg) { 4498591dbeSGuenter Roeck case PMBUS_VIRT_READ_VOUT_MAX: 4598591dbeSGuenter Roeck ret = pmbus_read_word_data(client, page, 4698591dbeSGuenter Roeck MAX34440_MFR_VOUT_PEAK); 4798591dbeSGuenter Roeck break; 4898591dbeSGuenter Roeck case PMBUS_VIRT_READ_IOUT_MAX: 4998591dbeSGuenter Roeck ret = pmbus_read_word_data(client, page, 5098591dbeSGuenter Roeck MAX34440_MFR_IOUT_PEAK); 5198591dbeSGuenter Roeck break; 5298591dbeSGuenter Roeck case PMBUS_VIRT_READ_TEMP_MAX: 5398591dbeSGuenter Roeck ret = pmbus_read_word_data(client, page, 5498591dbeSGuenter Roeck MAX34440_MFR_TEMPERATURE_PEAK); 5598591dbeSGuenter Roeck break; 5698591dbeSGuenter Roeck case PMBUS_VIRT_RESET_VOUT_HISTORY: 5798591dbeSGuenter Roeck case PMBUS_VIRT_RESET_IOUT_HISTORY: 5898591dbeSGuenter Roeck case PMBUS_VIRT_RESET_TEMP_HISTORY: 5998591dbeSGuenter Roeck ret = 0; 6098591dbeSGuenter Roeck break; 6198591dbeSGuenter Roeck default: 6298591dbeSGuenter Roeck ret = -ENODATA; 6398591dbeSGuenter Roeck break; 6498591dbeSGuenter Roeck } 6598591dbeSGuenter Roeck return ret; 6698591dbeSGuenter Roeck } 6798591dbeSGuenter Roeck 6898591dbeSGuenter Roeck static int max34440_write_word_data(struct i2c_client *client, int page, 6998591dbeSGuenter Roeck int reg, u16 word) 7098591dbeSGuenter Roeck { 7198591dbeSGuenter Roeck int ret; 7298591dbeSGuenter Roeck 7398591dbeSGuenter Roeck switch (reg) { 7498591dbeSGuenter Roeck case PMBUS_VIRT_RESET_VOUT_HISTORY: 7598591dbeSGuenter Roeck ret = pmbus_write_word_data(client, page, 7698591dbeSGuenter Roeck MAX34440_MFR_VOUT_PEAK, 0); 7798591dbeSGuenter Roeck break; 7898591dbeSGuenter Roeck case PMBUS_VIRT_RESET_IOUT_HISTORY: 7998591dbeSGuenter Roeck ret = pmbus_write_word_data(client, page, 8098591dbeSGuenter Roeck MAX34440_MFR_IOUT_PEAK, 0); 8198591dbeSGuenter Roeck break; 8298591dbeSGuenter Roeck case PMBUS_VIRT_RESET_TEMP_HISTORY: 8398591dbeSGuenter Roeck ret = pmbus_write_word_data(client, page, 8498591dbeSGuenter Roeck MAX34440_MFR_TEMPERATURE_PEAK, 8598591dbeSGuenter Roeck 0xffff); 8698591dbeSGuenter Roeck break; 8798591dbeSGuenter Roeck default: 8898591dbeSGuenter Roeck ret = -ENODATA; 8998591dbeSGuenter Roeck break; 9098591dbeSGuenter Roeck } 9198591dbeSGuenter Roeck return ret; 9298591dbeSGuenter Roeck } 9398591dbeSGuenter Roeck 949d2ecfb7SGuenter Roeck static int max34440_read_byte_data(struct i2c_client *client, int page, int reg) 959d2ecfb7SGuenter Roeck { 96*da8e48abSGuenter Roeck int ret = 0; 979d2ecfb7SGuenter Roeck int mfg_status; 989d2ecfb7SGuenter Roeck 99*da8e48abSGuenter Roeck if (page >= 0) { 1009d2ecfb7SGuenter Roeck ret = pmbus_set_page(client, page); 1019d2ecfb7SGuenter Roeck if (ret < 0) 1029d2ecfb7SGuenter Roeck return ret; 103*da8e48abSGuenter Roeck } 1049d2ecfb7SGuenter Roeck 1059d2ecfb7SGuenter Roeck switch (reg) { 1069d2ecfb7SGuenter Roeck case PMBUS_STATUS_IOUT: 1079d2ecfb7SGuenter Roeck mfg_status = pmbus_read_word_data(client, 0, 1089d2ecfb7SGuenter Roeck PMBUS_STATUS_MFR_SPECIFIC); 1099d2ecfb7SGuenter Roeck if (mfg_status < 0) 1109d2ecfb7SGuenter Roeck return mfg_status; 1119d2ecfb7SGuenter Roeck if (mfg_status & MAX34440_STATUS_OC_WARN) 1129d2ecfb7SGuenter Roeck ret |= PB_IOUT_OC_WARNING; 1139d2ecfb7SGuenter Roeck if (mfg_status & MAX34440_STATUS_OC_FAULT) 1149d2ecfb7SGuenter Roeck ret |= PB_IOUT_OC_FAULT; 1159d2ecfb7SGuenter Roeck break; 1169d2ecfb7SGuenter Roeck case PMBUS_STATUS_TEMPERATURE: 1179d2ecfb7SGuenter Roeck mfg_status = pmbus_read_word_data(client, 0, 1189d2ecfb7SGuenter Roeck PMBUS_STATUS_MFR_SPECIFIC); 1199d2ecfb7SGuenter Roeck if (mfg_status < 0) 1209d2ecfb7SGuenter Roeck return mfg_status; 1219d2ecfb7SGuenter Roeck if (mfg_status & MAX34440_STATUS_OT_WARN) 1229d2ecfb7SGuenter Roeck ret |= PB_TEMP_OT_WARNING; 1239d2ecfb7SGuenter Roeck if (mfg_status & MAX34440_STATUS_OT_FAULT) 1249d2ecfb7SGuenter Roeck ret |= PB_TEMP_OT_FAULT; 1259d2ecfb7SGuenter Roeck break; 1269d2ecfb7SGuenter Roeck default: 1279d2ecfb7SGuenter Roeck ret = -ENODATA; 1289d2ecfb7SGuenter Roeck break; 1299d2ecfb7SGuenter Roeck } 1309d2ecfb7SGuenter Roeck return ret; 1319d2ecfb7SGuenter Roeck } 1329d2ecfb7SGuenter Roeck 1339d2ecfb7SGuenter Roeck static struct pmbus_driver_info max34440_info[] = { 1349d2ecfb7SGuenter Roeck [max34440] = { 1359d2ecfb7SGuenter Roeck .pages = 14, 1361061d851SGuenter Roeck .format[PSC_VOLTAGE_IN] = direct, 1371061d851SGuenter Roeck .format[PSC_VOLTAGE_OUT] = direct, 1381061d851SGuenter Roeck .format[PSC_TEMPERATURE] = direct, 1391061d851SGuenter Roeck .format[PSC_CURRENT_OUT] = direct, 1409d2ecfb7SGuenter Roeck .m[PSC_VOLTAGE_IN] = 1, 1419d2ecfb7SGuenter Roeck .b[PSC_VOLTAGE_IN] = 0, 1429d2ecfb7SGuenter Roeck .R[PSC_VOLTAGE_IN] = 3, /* R = 0 in datasheet reflects mV */ 1439d2ecfb7SGuenter Roeck .m[PSC_VOLTAGE_OUT] = 1, 1449d2ecfb7SGuenter Roeck .b[PSC_VOLTAGE_OUT] = 0, 1459d2ecfb7SGuenter Roeck .R[PSC_VOLTAGE_OUT] = 3, /* R = 0 in datasheet reflects mV */ 1469d2ecfb7SGuenter Roeck .m[PSC_CURRENT_OUT] = 1, 1479d2ecfb7SGuenter Roeck .b[PSC_CURRENT_OUT] = 0, 1489d2ecfb7SGuenter Roeck .R[PSC_CURRENT_OUT] = 3, /* R = 0 in datasheet reflects mA */ 1499d2ecfb7SGuenter Roeck .m[PSC_TEMPERATURE] = 1, 1509d2ecfb7SGuenter Roeck .b[PSC_TEMPERATURE] = 0, 1519d2ecfb7SGuenter Roeck .R[PSC_TEMPERATURE] = 2, 1529d2ecfb7SGuenter Roeck .func[0] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT 1539d2ecfb7SGuenter Roeck | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT, 1549d2ecfb7SGuenter Roeck .func[1] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT 1559d2ecfb7SGuenter Roeck | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT, 1569d2ecfb7SGuenter Roeck .func[2] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT 1579d2ecfb7SGuenter Roeck | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT, 1589d2ecfb7SGuenter Roeck .func[3] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT 1599d2ecfb7SGuenter Roeck | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT, 1609d2ecfb7SGuenter Roeck .func[4] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT 1619d2ecfb7SGuenter Roeck | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT, 1629d2ecfb7SGuenter Roeck .func[5] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT 1639d2ecfb7SGuenter Roeck | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT, 1649d2ecfb7SGuenter Roeck .func[6] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP, 1659d2ecfb7SGuenter Roeck .func[7] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP, 1669d2ecfb7SGuenter Roeck .func[8] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP, 1679d2ecfb7SGuenter Roeck .func[9] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP, 1689d2ecfb7SGuenter Roeck .func[10] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP, 1699d2ecfb7SGuenter Roeck .func[11] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP, 1709d2ecfb7SGuenter Roeck .func[12] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP, 1719d2ecfb7SGuenter Roeck .func[13] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP, 1729d2ecfb7SGuenter Roeck .read_byte_data = max34440_read_byte_data, 17398591dbeSGuenter Roeck .read_word_data = max34440_read_word_data, 17498591dbeSGuenter Roeck .write_word_data = max34440_write_word_data, 1759d2ecfb7SGuenter Roeck }, 1769d2ecfb7SGuenter Roeck [max34441] = { 1779d2ecfb7SGuenter Roeck .pages = 12, 1781061d851SGuenter Roeck .format[PSC_VOLTAGE_IN] = direct, 1791061d851SGuenter Roeck .format[PSC_VOLTAGE_OUT] = direct, 1801061d851SGuenter Roeck .format[PSC_TEMPERATURE] = direct, 1811061d851SGuenter Roeck .format[PSC_CURRENT_OUT] = direct, 1821061d851SGuenter Roeck .format[PSC_FAN] = direct, 1839d2ecfb7SGuenter Roeck .m[PSC_VOLTAGE_IN] = 1, 1849d2ecfb7SGuenter Roeck .b[PSC_VOLTAGE_IN] = 0, 1859d2ecfb7SGuenter Roeck .R[PSC_VOLTAGE_IN] = 3, 1869d2ecfb7SGuenter Roeck .m[PSC_VOLTAGE_OUT] = 1, 1879d2ecfb7SGuenter Roeck .b[PSC_VOLTAGE_OUT] = 0, 1889d2ecfb7SGuenter Roeck .R[PSC_VOLTAGE_OUT] = 3, 1899d2ecfb7SGuenter Roeck .m[PSC_CURRENT_OUT] = 1, 1909d2ecfb7SGuenter Roeck .b[PSC_CURRENT_OUT] = 0, 1919d2ecfb7SGuenter Roeck .R[PSC_CURRENT_OUT] = 3, 1929d2ecfb7SGuenter Roeck .m[PSC_TEMPERATURE] = 1, 1939d2ecfb7SGuenter Roeck .b[PSC_TEMPERATURE] = 0, 1949d2ecfb7SGuenter Roeck .R[PSC_TEMPERATURE] = 2, 1959d2ecfb7SGuenter Roeck .m[PSC_FAN] = 1, 1969d2ecfb7SGuenter Roeck .b[PSC_FAN] = 0, 1979d2ecfb7SGuenter Roeck .R[PSC_FAN] = 0, 1989d2ecfb7SGuenter Roeck .func[0] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT 1999d2ecfb7SGuenter Roeck | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT, 2009d2ecfb7SGuenter Roeck .func[1] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT 2019d2ecfb7SGuenter Roeck | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT, 2029d2ecfb7SGuenter Roeck .func[2] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT 2039d2ecfb7SGuenter Roeck | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT, 2049d2ecfb7SGuenter Roeck .func[3] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT 2059d2ecfb7SGuenter Roeck | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT, 2069d2ecfb7SGuenter Roeck .func[4] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT 2079d2ecfb7SGuenter Roeck | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT, 2089d2ecfb7SGuenter Roeck .func[5] = PMBUS_HAVE_FAN12 | PMBUS_HAVE_STATUS_FAN12, 2099d2ecfb7SGuenter Roeck .func[6] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP, 2109d2ecfb7SGuenter Roeck .func[7] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP, 2119d2ecfb7SGuenter Roeck .func[8] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP, 2129d2ecfb7SGuenter Roeck .func[9] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP, 2139d2ecfb7SGuenter Roeck .func[10] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP, 2149d2ecfb7SGuenter Roeck .func[11] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP, 2159d2ecfb7SGuenter Roeck .read_byte_data = max34440_read_byte_data, 21698591dbeSGuenter Roeck .read_word_data = max34440_read_word_data, 21798591dbeSGuenter Roeck .write_word_data = max34440_write_word_data, 2189d2ecfb7SGuenter Roeck }, 2199d2ecfb7SGuenter Roeck }; 2209d2ecfb7SGuenter Roeck 2219d2ecfb7SGuenter Roeck static int max34440_probe(struct i2c_client *client, 2229d2ecfb7SGuenter Roeck const struct i2c_device_id *id) 2239d2ecfb7SGuenter Roeck { 2249d2ecfb7SGuenter Roeck return pmbus_do_probe(client, id, &max34440_info[id->driver_data]); 2259d2ecfb7SGuenter Roeck } 2269d2ecfb7SGuenter Roeck 2279d2ecfb7SGuenter Roeck static int max34440_remove(struct i2c_client *client) 2289d2ecfb7SGuenter Roeck { 229866cf12aSGuenter Roeck pmbus_do_remove(client); 230866cf12aSGuenter Roeck return 0; 2319d2ecfb7SGuenter Roeck } 2329d2ecfb7SGuenter Roeck 2339d2ecfb7SGuenter Roeck static const struct i2c_device_id max34440_id[] = { 2349d2ecfb7SGuenter Roeck {"max34440", max34440}, 2359d2ecfb7SGuenter Roeck {"max34441", max34441}, 2369d2ecfb7SGuenter Roeck {} 2379d2ecfb7SGuenter Roeck }; 2389d2ecfb7SGuenter Roeck 2399d2ecfb7SGuenter Roeck MODULE_DEVICE_TABLE(i2c, max34440_id); 2409d2ecfb7SGuenter Roeck 2419d2ecfb7SGuenter Roeck /* This is the driver that will be inserted */ 2429d2ecfb7SGuenter Roeck static struct i2c_driver max34440_driver = { 2439d2ecfb7SGuenter Roeck .driver = { 2449d2ecfb7SGuenter Roeck .name = "max34440", 2459d2ecfb7SGuenter Roeck }, 2469d2ecfb7SGuenter Roeck .probe = max34440_probe, 2479d2ecfb7SGuenter Roeck .remove = max34440_remove, 2489d2ecfb7SGuenter Roeck .id_table = max34440_id, 2499d2ecfb7SGuenter Roeck }; 2509d2ecfb7SGuenter Roeck 2519d2ecfb7SGuenter Roeck static int __init max34440_init(void) 2529d2ecfb7SGuenter Roeck { 2539d2ecfb7SGuenter Roeck return i2c_add_driver(&max34440_driver); 2549d2ecfb7SGuenter Roeck } 2559d2ecfb7SGuenter Roeck 2569d2ecfb7SGuenter Roeck static void __exit max34440_exit(void) 2579d2ecfb7SGuenter Roeck { 2589d2ecfb7SGuenter Roeck i2c_del_driver(&max34440_driver); 2599d2ecfb7SGuenter Roeck } 2609d2ecfb7SGuenter Roeck 2619d2ecfb7SGuenter Roeck MODULE_AUTHOR("Guenter Roeck"); 2629d2ecfb7SGuenter Roeck MODULE_DESCRIPTION("PMBus driver for Maxim MAX34440/MAX34441"); 2639d2ecfb7SGuenter Roeck MODULE_LICENSE("GPL"); 2649d2ecfb7SGuenter Roeck module_init(max34440_init); 2659d2ecfb7SGuenter Roeck module_exit(max34440_exit); 266