18ea3238ba16fbf06ff20b2979f894dc88383584aGuenter Roeck/* 28ea3238ba16fbf06ff20b2979f894dc88383584aGuenter Roeck * Hardware monitoring driver for Maxim MAX8688 38ea3238ba16fbf06ff20b2979f894dc88383584aGuenter Roeck * 48ea3238ba16fbf06ff20b2979f894dc88383584aGuenter Roeck * Copyright (c) 2011 Ericsson AB. 58ea3238ba16fbf06ff20b2979f894dc88383584aGuenter Roeck * 68ea3238ba16fbf06ff20b2979f894dc88383584aGuenter Roeck * This program is free software; you can redistribute it and/or modify 78ea3238ba16fbf06ff20b2979f894dc88383584aGuenter Roeck * it under the terms of the GNU General Public License as published by 88ea3238ba16fbf06ff20b2979f894dc88383584aGuenter Roeck * the Free Software Foundation; either version 2 of the License, or 98ea3238ba16fbf06ff20b2979f894dc88383584aGuenter Roeck * (at your option) any later version. 108ea3238ba16fbf06ff20b2979f894dc88383584aGuenter Roeck * 118ea3238ba16fbf06ff20b2979f894dc88383584aGuenter Roeck * This program is distributed in the hope that it will be useful, 128ea3238ba16fbf06ff20b2979f894dc88383584aGuenter Roeck * but WITHOUT ANY WARRANTY; without even the implied warranty of 138ea3238ba16fbf06ff20b2979f894dc88383584aGuenter Roeck * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 148ea3238ba16fbf06ff20b2979f894dc88383584aGuenter Roeck * GNU General Public License for more details. 158ea3238ba16fbf06ff20b2979f894dc88383584aGuenter Roeck * 168ea3238ba16fbf06ff20b2979f894dc88383584aGuenter Roeck * You should have received a copy of the GNU General Public License 178ea3238ba16fbf06ff20b2979f894dc88383584aGuenter Roeck * along with this program; if not, write to the Free Software 188ea3238ba16fbf06ff20b2979f894dc88383584aGuenter Roeck * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 198ea3238ba16fbf06ff20b2979f894dc88383584aGuenter Roeck */ 208ea3238ba16fbf06ff20b2979f894dc88383584aGuenter Roeck 218ea3238ba16fbf06ff20b2979f894dc88383584aGuenter Roeck#include <linux/kernel.h> 228ea3238ba16fbf06ff20b2979f894dc88383584aGuenter Roeck#include <linux/module.h> 238ea3238ba16fbf06ff20b2979f894dc88383584aGuenter Roeck#include <linux/init.h> 248ea3238ba16fbf06ff20b2979f894dc88383584aGuenter Roeck#include <linux/err.h> 258ea3238ba16fbf06ff20b2979f894dc88383584aGuenter Roeck#include <linux/i2c.h> 268ea3238ba16fbf06ff20b2979f894dc88383584aGuenter Roeck#include "pmbus.h" 278ea3238ba16fbf06ff20b2979f894dc88383584aGuenter Roeck 2870e94b276c21638a0a37908f6696a6b122944deaGuenter Roeck#define MAX8688_MFR_VOUT_PEAK 0xd4 2970e94b276c21638a0a37908f6696a6b122944deaGuenter Roeck#define MAX8688_MFR_IOUT_PEAK 0xd5 3070e94b276c21638a0a37908f6696a6b122944deaGuenter Roeck#define MAX8688_MFR_TEMPERATURE_PEAK 0xd6 318ea3238ba16fbf06ff20b2979f894dc88383584aGuenter Roeck#define MAX8688_MFG_STATUS 0xd8 328ea3238ba16fbf06ff20b2979f894dc88383584aGuenter Roeck 338ea3238ba16fbf06ff20b2979f894dc88383584aGuenter Roeck#define MAX8688_STATUS_OC_FAULT (1 << 4) 348ea3238ba16fbf06ff20b2979f894dc88383584aGuenter Roeck#define MAX8688_STATUS_OV_FAULT (1 << 5) 358ea3238ba16fbf06ff20b2979f894dc88383584aGuenter Roeck#define MAX8688_STATUS_OV_WARNING (1 << 8) 368ea3238ba16fbf06ff20b2979f894dc88383584aGuenter Roeck#define MAX8688_STATUS_UV_FAULT (1 << 9) 378ea3238ba16fbf06ff20b2979f894dc88383584aGuenter Roeck#define MAX8688_STATUS_UV_WARNING (1 << 10) 388ea3238ba16fbf06ff20b2979f894dc88383584aGuenter Roeck#define MAX8688_STATUS_UC_FAULT (1 << 11) 398ea3238ba16fbf06ff20b2979f894dc88383584aGuenter Roeck#define MAX8688_STATUS_OC_WARNING (1 << 12) 408ea3238ba16fbf06ff20b2979f894dc88383584aGuenter Roeck#define MAX8688_STATUS_OT_FAULT (1 << 13) 418ea3238ba16fbf06ff20b2979f894dc88383584aGuenter Roeck#define MAX8688_STATUS_OT_WARNING (1 << 14) 428ea3238ba16fbf06ff20b2979f894dc88383584aGuenter Roeck 4370e94b276c21638a0a37908f6696a6b122944deaGuenter Roeckstatic int max8688_read_word_data(struct i2c_client *client, int page, int reg) 4470e94b276c21638a0a37908f6696a6b122944deaGuenter Roeck{ 4570e94b276c21638a0a37908f6696a6b122944deaGuenter Roeck int ret; 4670e94b276c21638a0a37908f6696a6b122944deaGuenter Roeck 4770e94b276c21638a0a37908f6696a6b122944deaGuenter Roeck if (page) 48179144a0d4128e7588b3d613a14807402f5e7c37Guenter Roeck return -ENXIO; 4970e94b276c21638a0a37908f6696a6b122944deaGuenter Roeck 5070e94b276c21638a0a37908f6696a6b122944deaGuenter Roeck switch (reg) { 5170e94b276c21638a0a37908f6696a6b122944deaGuenter Roeck case PMBUS_VIRT_READ_VOUT_MAX: 5270e94b276c21638a0a37908f6696a6b122944deaGuenter Roeck ret = pmbus_read_word_data(client, 0, MAX8688_MFR_VOUT_PEAK); 5370e94b276c21638a0a37908f6696a6b122944deaGuenter Roeck break; 5470e94b276c21638a0a37908f6696a6b122944deaGuenter Roeck case PMBUS_VIRT_READ_IOUT_MAX: 5570e94b276c21638a0a37908f6696a6b122944deaGuenter Roeck ret = pmbus_read_word_data(client, 0, MAX8688_MFR_IOUT_PEAK); 5670e94b276c21638a0a37908f6696a6b122944deaGuenter Roeck break; 5770e94b276c21638a0a37908f6696a6b122944deaGuenter Roeck case PMBUS_VIRT_READ_TEMP_MAX: 5870e94b276c21638a0a37908f6696a6b122944deaGuenter Roeck ret = pmbus_read_word_data(client, 0, 5970e94b276c21638a0a37908f6696a6b122944deaGuenter Roeck MAX8688_MFR_TEMPERATURE_PEAK); 6070e94b276c21638a0a37908f6696a6b122944deaGuenter Roeck break; 6170e94b276c21638a0a37908f6696a6b122944deaGuenter Roeck case PMBUS_VIRT_RESET_VOUT_HISTORY: 6270e94b276c21638a0a37908f6696a6b122944deaGuenter Roeck case PMBUS_VIRT_RESET_IOUT_HISTORY: 6370e94b276c21638a0a37908f6696a6b122944deaGuenter Roeck case PMBUS_VIRT_RESET_TEMP_HISTORY: 6470e94b276c21638a0a37908f6696a6b122944deaGuenter Roeck ret = 0; 6570e94b276c21638a0a37908f6696a6b122944deaGuenter Roeck break; 6670e94b276c21638a0a37908f6696a6b122944deaGuenter Roeck default: 6770e94b276c21638a0a37908f6696a6b122944deaGuenter Roeck ret = -ENODATA; 6870e94b276c21638a0a37908f6696a6b122944deaGuenter Roeck break; 6970e94b276c21638a0a37908f6696a6b122944deaGuenter Roeck } 7070e94b276c21638a0a37908f6696a6b122944deaGuenter Roeck return ret; 7170e94b276c21638a0a37908f6696a6b122944deaGuenter Roeck} 7270e94b276c21638a0a37908f6696a6b122944deaGuenter Roeck 7370e94b276c21638a0a37908f6696a6b122944deaGuenter Roeckstatic int max8688_write_word_data(struct i2c_client *client, int page, int reg, 7470e94b276c21638a0a37908f6696a6b122944deaGuenter Roeck u16 word) 7570e94b276c21638a0a37908f6696a6b122944deaGuenter Roeck{ 7670e94b276c21638a0a37908f6696a6b122944deaGuenter Roeck int ret; 7770e94b276c21638a0a37908f6696a6b122944deaGuenter Roeck 7870e94b276c21638a0a37908f6696a6b122944deaGuenter Roeck switch (reg) { 7970e94b276c21638a0a37908f6696a6b122944deaGuenter Roeck case PMBUS_VIRT_RESET_VOUT_HISTORY: 8070e94b276c21638a0a37908f6696a6b122944deaGuenter Roeck ret = pmbus_write_word_data(client, 0, MAX8688_MFR_VOUT_PEAK, 8170e94b276c21638a0a37908f6696a6b122944deaGuenter Roeck 0); 8270e94b276c21638a0a37908f6696a6b122944deaGuenter Roeck break; 8370e94b276c21638a0a37908f6696a6b122944deaGuenter Roeck case PMBUS_VIRT_RESET_IOUT_HISTORY: 8470e94b276c21638a0a37908f6696a6b122944deaGuenter Roeck ret = pmbus_write_word_data(client, 0, MAX8688_MFR_IOUT_PEAK, 8570e94b276c21638a0a37908f6696a6b122944deaGuenter Roeck 0); 8670e94b276c21638a0a37908f6696a6b122944deaGuenter Roeck break; 8770e94b276c21638a0a37908f6696a6b122944deaGuenter Roeck case PMBUS_VIRT_RESET_TEMP_HISTORY: 8870e94b276c21638a0a37908f6696a6b122944deaGuenter Roeck ret = pmbus_write_word_data(client, 0, 8970e94b276c21638a0a37908f6696a6b122944deaGuenter Roeck MAX8688_MFR_TEMPERATURE_PEAK, 9070e94b276c21638a0a37908f6696a6b122944deaGuenter Roeck 0xffff); 9170e94b276c21638a0a37908f6696a6b122944deaGuenter Roeck break; 9270e94b276c21638a0a37908f6696a6b122944deaGuenter Roeck default: 9370e94b276c21638a0a37908f6696a6b122944deaGuenter Roeck ret = -ENODATA; 9470e94b276c21638a0a37908f6696a6b122944deaGuenter Roeck break; 9570e94b276c21638a0a37908f6696a6b122944deaGuenter Roeck } 9670e94b276c21638a0a37908f6696a6b122944deaGuenter Roeck return ret; 9770e94b276c21638a0a37908f6696a6b122944deaGuenter Roeck} 9870e94b276c21638a0a37908f6696a6b122944deaGuenter Roeck 992cfa6aedb32c9c1226094ed383dc3c9b3e2ecddbGuenter Roeckstatic int max8688_read_byte_data(struct i2c_client *client, int page, int reg) 1008ea3238ba16fbf06ff20b2979f894dc88383584aGuenter Roeck{ 1018ea3238ba16fbf06ff20b2979f894dc88383584aGuenter Roeck int ret = 0; 1028ea3238ba16fbf06ff20b2979f894dc88383584aGuenter Roeck int mfg_status; 1038ea3238ba16fbf06ff20b2979f894dc88383584aGuenter Roeck 104da8e48ab483e1f54c1099bed91bfd2c302bc7ddfGuenter Roeck if (page > 0) 105179144a0d4128e7588b3d613a14807402f5e7c37Guenter Roeck return -ENXIO; 1068ea3238ba16fbf06ff20b2979f894dc88383584aGuenter Roeck 1078ea3238ba16fbf06ff20b2979f894dc88383584aGuenter Roeck switch (reg) { 1088ea3238ba16fbf06ff20b2979f894dc88383584aGuenter Roeck case PMBUS_STATUS_VOUT: 1098ea3238ba16fbf06ff20b2979f894dc88383584aGuenter Roeck mfg_status = pmbus_read_word_data(client, 0, 1108ea3238ba16fbf06ff20b2979f894dc88383584aGuenter Roeck MAX8688_MFG_STATUS); 1118ea3238ba16fbf06ff20b2979f894dc88383584aGuenter Roeck if (mfg_status < 0) 1128ea3238ba16fbf06ff20b2979f894dc88383584aGuenter Roeck return mfg_status; 1138ea3238ba16fbf06ff20b2979f894dc88383584aGuenter Roeck if (mfg_status & MAX8688_STATUS_UV_WARNING) 1148ea3238ba16fbf06ff20b2979f894dc88383584aGuenter Roeck ret |= PB_VOLTAGE_UV_WARNING; 1158ea3238ba16fbf06ff20b2979f894dc88383584aGuenter Roeck if (mfg_status & MAX8688_STATUS_UV_FAULT) 1168ea3238ba16fbf06ff20b2979f894dc88383584aGuenter Roeck ret |= PB_VOLTAGE_UV_FAULT; 1178ea3238ba16fbf06ff20b2979f894dc88383584aGuenter Roeck if (mfg_status & MAX8688_STATUS_OV_WARNING) 1188ea3238ba16fbf06ff20b2979f894dc88383584aGuenter Roeck ret |= PB_VOLTAGE_OV_WARNING; 1198ea3238ba16fbf06ff20b2979f894dc88383584aGuenter Roeck if (mfg_status & MAX8688_STATUS_OV_FAULT) 1208ea3238ba16fbf06ff20b2979f894dc88383584aGuenter Roeck ret |= PB_VOLTAGE_OV_FAULT; 1218ea3238ba16fbf06ff20b2979f894dc88383584aGuenter Roeck break; 1228ea3238ba16fbf06ff20b2979f894dc88383584aGuenter Roeck case PMBUS_STATUS_IOUT: 1238ea3238ba16fbf06ff20b2979f894dc88383584aGuenter Roeck mfg_status = pmbus_read_word_data(client, 0, 1248ea3238ba16fbf06ff20b2979f894dc88383584aGuenter Roeck MAX8688_MFG_STATUS); 1258ea3238ba16fbf06ff20b2979f894dc88383584aGuenter Roeck if (mfg_status < 0) 1268ea3238ba16fbf06ff20b2979f894dc88383584aGuenter Roeck return mfg_status; 1278ea3238ba16fbf06ff20b2979f894dc88383584aGuenter Roeck if (mfg_status & MAX8688_STATUS_UC_FAULT) 1288ea3238ba16fbf06ff20b2979f894dc88383584aGuenter Roeck ret |= PB_IOUT_UC_FAULT; 1298ea3238ba16fbf06ff20b2979f894dc88383584aGuenter Roeck if (mfg_status & MAX8688_STATUS_OC_WARNING) 1308ea3238ba16fbf06ff20b2979f894dc88383584aGuenter Roeck ret |= PB_IOUT_OC_WARNING; 1318ea3238ba16fbf06ff20b2979f894dc88383584aGuenter Roeck if (mfg_status & MAX8688_STATUS_OC_FAULT) 1328ea3238ba16fbf06ff20b2979f894dc88383584aGuenter Roeck ret |= PB_IOUT_OC_FAULT; 1338ea3238ba16fbf06ff20b2979f894dc88383584aGuenter Roeck break; 1348ea3238ba16fbf06ff20b2979f894dc88383584aGuenter Roeck case PMBUS_STATUS_TEMPERATURE: 1358ea3238ba16fbf06ff20b2979f894dc88383584aGuenter Roeck mfg_status = pmbus_read_word_data(client, 0, 1368ea3238ba16fbf06ff20b2979f894dc88383584aGuenter Roeck MAX8688_MFG_STATUS); 1378ea3238ba16fbf06ff20b2979f894dc88383584aGuenter Roeck if (mfg_status < 0) 1388ea3238ba16fbf06ff20b2979f894dc88383584aGuenter Roeck return mfg_status; 1398ea3238ba16fbf06ff20b2979f894dc88383584aGuenter Roeck if (mfg_status & MAX8688_STATUS_OT_WARNING) 1408ea3238ba16fbf06ff20b2979f894dc88383584aGuenter Roeck ret |= PB_TEMP_OT_WARNING; 1418ea3238ba16fbf06ff20b2979f894dc88383584aGuenter Roeck if (mfg_status & MAX8688_STATUS_OT_FAULT) 1428ea3238ba16fbf06ff20b2979f894dc88383584aGuenter Roeck ret |= PB_TEMP_OT_FAULT; 1438ea3238ba16fbf06ff20b2979f894dc88383584aGuenter Roeck break; 1448ea3238ba16fbf06ff20b2979f894dc88383584aGuenter Roeck default: 1458ea3238ba16fbf06ff20b2979f894dc88383584aGuenter Roeck ret = -ENODATA; 1468ea3238ba16fbf06ff20b2979f894dc88383584aGuenter Roeck break; 1478ea3238ba16fbf06ff20b2979f894dc88383584aGuenter Roeck } 1488ea3238ba16fbf06ff20b2979f894dc88383584aGuenter Roeck return ret; 1498ea3238ba16fbf06ff20b2979f894dc88383584aGuenter Roeck} 1508ea3238ba16fbf06ff20b2979f894dc88383584aGuenter Roeck 1518ea3238ba16fbf06ff20b2979f894dc88383584aGuenter Roeckstatic struct pmbus_driver_info max8688_info = { 1528ea3238ba16fbf06ff20b2979f894dc88383584aGuenter Roeck .pages = 1, 1531061d8518f8bde548a03a5ff77dbe9a4202ad826Guenter Roeck .format[PSC_VOLTAGE_IN] = direct, 1541061d8518f8bde548a03a5ff77dbe9a4202ad826Guenter Roeck .format[PSC_VOLTAGE_OUT] = direct, 1551061d8518f8bde548a03a5ff77dbe9a4202ad826Guenter Roeck .format[PSC_TEMPERATURE] = direct, 1561061d8518f8bde548a03a5ff77dbe9a4202ad826Guenter Roeck .format[PSC_CURRENT_OUT] = direct, 1578ea3238ba16fbf06ff20b2979f894dc88383584aGuenter Roeck .m[PSC_VOLTAGE_IN] = 19995, 1588ea3238ba16fbf06ff20b2979f894dc88383584aGuenter Roeck .b[PSC_VOLTAGE_IN] = 0, 1598ea3238ba16fbf06ff20b2979f894dc88383584aGuenter Roeck .R[PSC_VOLTAGE_IN] = -1, 1608ea3238ba16fbf06ff20b2979f894dc88383584aGuenter Roeck .m[PSC_VOLTAGE_OUT] = 19995, 1618ea3238ba16fbf06ff20b2979f894dc88383584aGuenter Roeck .b[PSC_VOLTAGE_OUT] = 0, 1628ea3238ba16fbf06ff20b2979f894dc88383584aGuenter Roeck .R[PSC_VOLTAGE_OUT] = -1, 1638ea3238ba16fbf06ff20b2979f894dc88383584aGuenter Roeck .m[PSC_CURRENT_OUT] = 23109, 1648ea3238ba16fbf06ff20b2979f894dc88383584aGuenter Roeck .b[PSC_CURRENT_OUT] = 0, 1658ea3238ba16fbf06ff20b2979f894dc88383584aGuenter Roeck .R[PSC_CURRENT_OUT] = -2, 1668ea3238ba16fbf06ff20b2979f894dc88383584aGuenter Roeck .m[PSC_TEMPERATURE] = -7612, 1678ea3238ba16fbf06ff20b2979f894dc88383584aGuenter Roeck .b[PSC_TEMPERATURE] = 335, 1688ea3238ba16fbf06ff20b2979f894dc88383584aGuenter Roeck .R[PSC_TEMPERATURE] = -3, 1698ea3238ba16fbf06ff20b2979f894dc88383584aGuenter Roeck .func[0] = PMBUS_HAVE_VOUT | PMBUS_HAVE_IOUT | PMBUS_HAVE_TEMP 1708ea3238ba16fbf06ff20b2979f894dc88383584aGuenter Roeck | PMBUS_HAVE_STATUS_VOUT | PMBUS_HAVE_STATUS_IOUT 1718ea3238ba16fbf06ff20b2979f894dc88383584aGuenter Roeck | PMBUS_HAVE_STATUS_TEMP, 1722cfa6aedb32c9c1226094ed383dc3c9b3e2ecddbGuenter Roeck .read_byte_data = max8688_read_byte_data, 17370e94b276c21638a0a37908f6696a6b122944deaGuenter Roeck .read_word_data = max8688_read_word_data, 17470e94b276c21638a0a37908f6696a6b122944deaGuenter Roeck .write_word_data = max8688_write_word_data, 1758ea3238ba16fbf06ff20b2979f894dc88383584aGuenter Roeck}; 1768ea3238ba16fbf06ff20b2979f894dc88383584aGuenter Roeck 1778ea3238ba16fbf06ff20b2979f894dc88383584aGuenter Roeckstatic int max8688_probe(struct i2c_client *client, 1788ea3238ba16fbf06ff20b2979f894dc88383584aGuenter Roeck const struct i2c_device_id *id) 1798ea3238ba16fbf06ff20b2979f894dc88383584aGuenter Roeck{ 1808ea3238ba16fbf06ff20b2979f894dc88383584aGuenter Roeck return pmbus_do_probe(client, id, &max8688_info); 1818ea3238ba16fbf06ff20b2979f894dc88383584aGuenter Roeck} 1828ea3238ba16fbf06ff20b2979f894dc88383584aGuenter Roeck 1838ea3238ba16fbf06ff20b2979f894dc88383584aGuenter Roeckstatic const struct i2c_device_id max8688_id[] = { 1848ea3238ba16fbf06ff20b2979f894dc88383584aGuenter Roeck {"max8688", 0}, 1858ea3238ba16fbf06ff20b2979f894dc88383584aGuenter Roeck { } 1868ea3238ba16fbf06ff20b2979f894dc88383584aGuenter Roeck}; 1878ea3238ba16fbf06ff20b2979f894dc88383584aGuenter Roeck 1888ea3238ba16fbf06ff20b2979f894dc88383584aGuenter RoeckMODULE_DEVICE_TABLE(i2c, max8688_id); 1898ea3238ba16fbf06ff20b2979f894dc88383584aGuenter Roeck 1908ea3238ba16fbf06ff20b2979f894dc88383584aGuenter Roeck/* This is the driver that will be inserted */ 1918ea3238ba16fbf06ff20b2979f894dc88383584aGuenter Roeckstatic struct i2c_driver max8688_driver = { 1928ea3238ba16fbf06ff20b2979f894dc88383584aGuenter Roeck .driver = { 1938ea3238ba16fbf06ff20b2979f894dc88383584aGuenter Roeck .name = "max8688", 1948ea3238ba16fbf06ff20b2979f894dc88383584aGuenter Roeck }, 1958ea3238ba16fbf06ff20b2979f894dc88383584aGuenter Roeck .probe = max8688_probe, 196dd285ad7373bf5d21cceacb3b7a5eb8b72d37085Guenter Roeck .remove = pmbus_do_remove, 1978ea3238ba16fbf06ff20b2979f894dc88383584aGuenter Roeck .id_table = max8688_id, 1988ea3238ba16fbf06ff20b2979f894dc88383584aGuenter Roeck}; 1998ea3238ba16fbf06ff20b2979f894dc88383584aGuenter Roeck 200f0967eea80ec2a19a4fe1ad27e3ff1b22c79a3c7Axel Linmodule_i2c_driver(max8688_driver); 2018ea3238ba16fbf06ff20b2979f894dc88383584aGuenter Roeck 2028ea3238ba16fbf06ff20b2979f894dc88383584aGuenter RoeckMODULE_AUTHOR("Guenter Roeck"); 2038ea3238ba16fbf06ff20b2979f894dc88383584aGuenter RoeckMODULE_DESCRIPTION("PMBus driver for Maxim MAX8688"); 2048ea3238ba16fbf06ff20b2979f894dc88383584aGuenter RoeckMODULE_LICENSE("GPL"); 205