1 // SPDX-License-Identifier: GPL-2.0-or-later 2 /* 3 * Hardware monitoring driver for Maxim MAX8688 4 * 5 * Copyright (c) 2011 Ericsson AB. 6 */ 7 8 #include <linux/bitops.h> 9 #include <linux/kernel.h> 10 #include <linux/module.h> 11 #include <linux/init.h> 12 #include <linux/err.h> 13 #include <linux/i2c.h> 14 #include "pmbus.h" 15 16 #define MAX8688_MFR_VOUT_PEAK 0xd4 17 #define MAX8688_MFR_IOUT_PEAK 0xd5 18 #define MAX8688_MFR_TEMPERATURE_PEAK 0xd6 19 #define MAX8688_MFG_STATUS 0xd8 20 21 #define MAX8688_STATUS_OC_FAULT BIT(4) 22 #define MAX8688_STATUS_OV_FAULT BIT(5) 23 #define MAX8688_STATUS_OV_WARNING BIT(8) 24 #define MAX8688_STATUS_UV_FAULT BIT(9) 25 #define MAX8688_STATUS_UV_WARNING BIT(10) 26 #define MAX8688_STATUS_UC_FAULT BIT(11) 27 #define MAX8688_STATUS_OC_WARNING BIT(12) 28 #define MAX8688_STATUS_OT_FAULT BIT(13) 29 #define MAX8688_STATUS_OT_WARNING BIT(14) 30 31 static int max8688_read_word_data(struct i2c_client *client, int page, 32 int phase, int reg) 33 { 34 int ret; 35 36 if (page > 0) 37 return -ENXIO; 38 39 switch (reg) { 40 case PMBUS_VIRT_READ_VOUT_MAX: 41 ret = pmbus_read_word_data(client, 0, 0xff, 42 MAX8688_MFR_VOUT_PEAK); 43 break; 44 case PMBUS_VIRT_READ_IOUT_MAX: 45 ret = pmbus_read_word_data(client, 0, 0xff, 46 MAX8688_MFR_IOUT_PEAK); 47 break; 48 case PMBUS_VIRT_READ_TEMP_MAX: 49 ret = pmbus_read_word_data(client, 0, 0xff, 50 MAX8688_MFR_TEMPERATURE_PEAK); 51 break; 52 case PMBUS_VIRT_RESET_VOUT_HISTORY: 53 case PMBUS_VIRT_RESET_IOUT_HISTORY: 54 case PMBUS_VIRT_RESET_TEMP_HISTORY: 55 ret = 0; 56 break; 57 default: 58 ret = -ENODATA; 59 break; 60 } 61 return ret; 62 } 63 64 static int max8688_write_word_data(struct i2c_client *client, int page, int reg, 65 u16 word) 66 { 67 int ret; 68 69 switch (reg) { 70 case PMBUS_VIRT_RESET_VOUT_HISTORY: 71 ret = pmbus_write_word_data(client, 0, MAX8688_MFR_VOUT_PEAK, 72 0); 73 break; 74 case PMBUS_VIRT_RESET_IOUT_HISTORY: 75 ret = pmbus_write_word_data(client, 0, MAX8688_MFR_IOUT_PEAK, 76 0); 77 break; 78 case PMBUS_VIRT_RESET_TEMP_HISTORY: 79 ret = pmbus_write_word_data(client, 0, 80 MAX8688_MFR_TEMPERATURE_PEAK, 81 0xffff); 82 break; 83 default: 84 ret = -ENODATA; 85 break; 86 } 87 return ret; 88 } 89 90 static int max8688_read_byte_data(struct i2c_client *client, int page, int reg) 91 { 92 int ret = 0; 93 int mfg_status; 94 95 if (page > 0) 96 return -ENXIO; 97 98 switch (reg) { 99 case PMBUS_STATUS_VOUT: 100 mfg_status = pmbus_read_word_data(client, 0, 0xff, 101 MAX8688_MFG_STATUS); 102 if (mfg_status < 0) 103 return mfg_status; 104 if (mfg_status & MAX8688_STATUS_UV_WARNING) 105 ret |= PB_VOLTAGE_UV_WARNING; 106 if (mfg_status & MAX8688_STATUS_UV_FAULT) 107 ret |= PB_VOLTAGE_UV_FAULT; 108 if (mfg_status & MAX8688_STATUS_OV_WARNING) 109 ret |= PB_VOLTAGE_OV_WARNING; 110 if (mfg_status & MAX8688_STATUS_OV_FAULT) 111 ret |= PB_VOLTAGE_OV_FAULT; 112 break; 113 case PMBUS_STATUS_IOUT: 114 mfg_status = pmbus_read_word_data(client, 0, 0xff, 115 MAX8688_MFG_STATUS); 116 if (mfg_status < 0) 117 return mfg_status; 118 if (mfg_status & MAX8688_STATUS_UC_FAULT) 119 ret |= PB_IOUT_UC_FAULT; 120 if (mfg_status & MAX8688_STATUS_OC_WARNING) 121 ret |= PB_IOUT_OC_WARNING; 122 if (mfg_status & MAX8688_STATUS_OC_FAULT) 123 ret |= PB_IOUT_OC_FAULT; 124 break; 125 case PMBUS_STATUS_TEMPERATURE: 126 mfg_status = pmbus_read_word_data(client, 0, 0xff, 127 MAX8688_MFG_STATUS); 128 if (mfg_status < 0) 129 return mfg_status; 130 if (mfg_status & MAX8688_STATUS_OT_WARNING) 131 ret |= PB_TEMP_OT_WARNING; 132 if (mfg_status & MAX8688_STATUS_OT_FAULT) 133 ret |= PB_TEMP_OT_FAULT; 134 break; 135 default: 136 ret = -ENODATA; 137 break; 138 } 139 return ret; 140 } 141 142 static struct pmbus_driver_info max8688_info = { 143 .pages = 1, 144 .format[PSC_VOLTAGE_IN] = direct, 145 .format[PSC_VOLTAGE_OUT] = direct, 146 .format[PSC_TEMPERATURE] = direct, 147 .format[PSC_CURRENT_OUT] = direct, 148 .m[PSC_VOLTAGE_IN] = 19995, 149 .b[PSC_VOLTAGE_IN] = 0, 150 .R[PSC_VOLTAGE_IN] = -1, 151 .m[PSC_VOLTAGE_OUT] = 19995, 152 .b[PSC_VOLTAGE_OUT] = 0, 153 .R[PSC_VOLTAGE_OUT] = -1, 154 .m[PSC_CURRENT_OUT] = 23109, 155 .b[PSC_CURRENT_OUT] = 0, 156 .R[PSC_CURRENT_OUT] = -2, 157 .m[PSC_TEMPERATURE] = -7612, 158 .b[PSC_TEMPERATURE] = 335, 159 .R[PSC_TEMPERATURE] = -3, 160 .func[0] = PMBUS_HAVE_VOUT | PMBUS_HAVE_IOUT | PMBUS_HAVE_TEMP 161 | PMBUS_HAVE_STATUS_VOUT | PMBUS_HAVE_STATUS_IOUT 162 | PMBUS_HAVE_STATUS_TEMP, 163 .read_byte_data = max8688_read_byte_data, 164 .read_word_data = max8688_read_word_data, 165 .write_word_data = max8688_write_word_data, 166 }; 167 168 static int max8688_probe(struct i2c_client *client, 169 const struct i2c_device_id *id) 170 { 171 return pmbus_do_probe(client, id, &max8688_info); 172 } 173 174 static const struct i2c_device_id max8688_id[] = { 175 {"max8688", 0}, 176 { } 177 }; 178 179 MODULE_DEVICE_TABLE(i2c, max8688_id); 180 181 /* This is the driver that will be inserted */ 182 static struct i2c_driver max8688_driver = { 183 .driver = { 184 .name = "max8688", 185 }, 186 .probe = max8688_probe, 187 .remove = pmbus_do_remove, 188 .id_table = max8688_id, 189 }; 190 191 module_i2c_driver(max8688_driver); 192 193 MODULE_AUTHOR("Guenter Roeck"); 194 MODULE_DESCRIPTION("PMBus driver for Maxim MAX8688"); 195 MODULE_LICENSE("GPL"); 196