1c942fddfSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later 29d2ecfb7SGuenter Roeck /* 39d2ecfb7SGuenter Roeck * Hardware monitoring driver for Analog Devices ADM1275 Hot-Swap Controller 49d2ecfb7SGuenter Roeck * and Digital Power Monitor 59d2ecfb7SGuenter Roeck * 69d2ecfb7SGuenter Roeck * Copyright (c) 2011 Ericsson AB. 74ff0ce22SGuenter Roeck * Copyright (c) 2018 Guenter Roeck 89d2ecfb7SGuenter Roeck */ 99d2ecfb7SGuenter Roeck 109d2ecfb7SGuenter Roeck #include <linux/kernel.h> 119d2ecfb7SGuenter Roeck #include <linux/module.h> 129d2ecfb7SGuenter Roeck #include <linux/init.h> 139d2ecfb7SGuenter Roeck #include <linux/err.h> 149d2ecfb7SGuenter Roeck #include <linux/slab.h> 159d2ecfb7SGuenter Roeck #include <linux/i2c.h> 1699b41608SGuenter Roeck #include <linux/bitops.h> 17c83529c1SAdamski, Krzysztof (Nokia - PL/Wroclaw) #include <linux/bitfield.h> 18c83529c1SAdamski, Krzysztof (Nokia - PL/Wroclaw) #include <linux/log2.h> 199d2ecfb7SGuenter Roeck #include "pmbus.h" 209d2ecfb7SGuenter Roeck 214ff0ce22SGuenter Roeck enum chips { adm1075, adm1272, adm1275, adm1276, adm1278, adm1293, adm1294 }; 2268a40382SGuenter Roeck 2368a40382SGuenter Roeck #define ADM1275_MFR_STATUS_IOUT_WARN2 BIT(0) 2468a40382SGuenter Roeck #define ADM1293_MFR_STATUS_VAUX_UV_WARN BIT(5) 2568a40382SGuenter Roeck #define ADM1293_MFR_STATUS_VAUX_OV_WARN BIT(6) 265cf231a3SGuenter Roeck 27c576e30cSGuenter Roeck #define ADM1275_PEAK_IOUT 0xd0 28c576e30cSGuenter Roeck #define ADM1275_PEAK_VIN 0xd1 29c576e30cSGuenter Roeck #define ADM1275_PEAK_VOUT 0xd2 309d2ecfb7SGuenter Roeck #define ADM1275_PMON_CONFIG 0xd4 319d2ecfb7SGuenter Roeck 3299b41608SGuenter Roeck #define ADM1275_VIN_VOUT_SELECT BIT(6) 3399b41608SGuenter Roeck #define ADM1275_VRANGE BIT(5) 3499b41608SGuenter Roeck #define ADM1075_IRANGE_50 BIT(4) 3599b41608SGuenter Roeck #define ADM1075_IRANGE_25 BIT(3) 3699b41608SGuenter Roeck #define ADM1075_IRANGE_MASK (BIT(3) | BIT(4)) 379d2ecfb7SGuenter Roeck 384ff0ce22SGuenter Roeck #define ADM1272_IRANGE BIT(0) 394ff0ce22SGuenter Roeck 40709066acSGuenter Roeck #define ADM1278_TEMP1_EN BIT(3) 41709066acSGuenter Roeck #define ADM1278_VIN_EN BIT(2) 42709066acSGuenter Roeck #define ADM1278_VOUT_EN BIT(1) 43709066acSGuenter Roeck 4468a40382SGuenter Roeck #define ADM1293_IRANGE_25 0 4568a40382SGuenter Roeck #define ADM1293_IRANGE_50 BIT(6) 4668a40382SGuenter Roeck #define ADM1293_IRANGE_100 BIT(7) 4768a40382SGuenter Roeck #define ADM1293_IRANGE_200 (BIT(6) | BIT(7)) 4868a40382SGuenter Roeck #define ADM1293_IRANGE_MASK (BIT(6) | BIT(7)) 4968a40382SGuenter Roeck 5068a40382SGuenter Roeck #define ADM1293_VIN_SEL_012 BIT(2) 5168a40382SGuenter Roeck #define ADM1293_VIN_SEL_074 BIT(3) 5268a40382SGuenter Roeck #define ADM1293_VIN_SEL_210 (BIT(2) | BIT(3)) 5368a40382SGuenter Roeck #define ADM1293_VIN_SEL_MASK (BIT(2) | BIT(3)) 5468a40382SGuenter Roeck 5568a40382SGuenter Roeck #define ADM1293_VAUX_EN BIT(1) 5668a40382SGuenter Roeck 57709066acSGuenter Roeck #define ADM1278_PEAK_TEMP 0xd7 58c5e67636SGuenter Roeck #define ADM1275_IOUT_WARN2_LIMIT 0xd7 59c5e67636SGuenter Roeck #define ADM1275_DEVICE_CONFIG 0xd8 60c5e67636SGuenter Roeck 6199b41608SGuenter Roeck #define ADM1275_IOUT_WARN2_SELECT BIT(4) 62c5e67636SGuenter Roeck 635cf231a3SGuenter Roeck #define ADM1276_PEAK_PIN 0xda 6492711269SGuenter Roeck #define ADM1075_READ_VAUX 0xdd 6592711269SGuenter Roeck #define ADM1075_VAUX_OV_WARN_LIMIT 0xde 6692711269SGuenter Roeck #define ADM1075_VAUX_UV_WARN_LIMIT 0xdf 6768a40382SGuenter Roeck #define ADM1293_IOUT_MIN 0xe3 6868a40382SGuenter Roeck #define ADM1293_PIN_MIN 0xe4 6992711269SGuenter Roeck #define ADM1075_VAUX_STATUS 0xf6 7092711269SGuenter Roeck 7199b41608SGuenter Roeck #define ADM1075_VAUX_OV_WARN BIT(7) 7299b41608SGuenter Roeck #define ADM1075_VAUX_UV_WARN BIT(6) 7392711269SGuenter Roeck 747d45deb3SGuenter Roeck #define ADM1275_VI_AVG_SHIFT 0 757d45deb3SGuenter Roeck #define ADM1275_VI_AVG_MASK GENMASK(ADM1275_VI_AVG_SHIFT + 2, \ 767d45deb3SGuenter Roeck ADM1275_VI_AVG_SHIFT) 77c83529c1SAdamski, Krzysztof (Nokia - PL/Wroclaw) #define ADM1275_SAMPLES_AVG_MAX 128 78c83529c1SAdamski, Krzysztof (Nokia - PL/Wroclaw) 797d45deb3SGuenter Roeck #define ADM1278_PWR_AVG_SHIFT 11 807d45deb3SGuenter Roeck #define ADM1278_PWR_AVG_MASK GENMASK(ADM1278_PWR_AVG_SHIFT + 2, \ 817d45deb3SGuenter Roeck ADM1278_PWR_AVG_SHIFT) 827d45deb3SGuenter Roeck #define ADM1278_VI_AVG_SHIFT 8 837d45deb3SGuenter Roeck #define ADM1278_VI_AVG_MASK GENMASK(ADM1278_VI_AVG_SHIFT + 2, \ 847d45deb3SGuenter Roeck ADM1278_VI_AVG_SHIFT) 857d45deb3SGuenter Roeck 86c5e67636SGuenter Roeck struct adm1275_data { 875cf231a3SGuenter Roeck int id; 88c5e67636SGuenter Roeck bool have_oc_fault; 899048539bSGuenter Roeck bool have_uc_fault; 909048539bSGuenter Roeck bool have_vout; 919048539bSGuenter Roeck bool have_vaux_status; 9268a40382SGuenter Roeck bool have_mfr_vaux_status; 9368a40382SGuenter Roeck bool have_iout_min; 9468a40382SGuenter Roeck bool have_pin_min; 959048539bSGuenter Roeck bool have_pin_max; 96709066acSGuenter Roeck bool have_temp_max; 977d45deb3SGuenter Roeck bool have_power_sampling; 98c5e67636SGuenter Roeck struct pmbus_driver_info info; 99c5e67636SGuenter Roeck }; 100c5e67636SGuenter Roeck 101c5e67636SGuenter Roeck #define to_adm1275_data(x) container_of(x, struct adm1275_data, info) 102c5e67636SGuenter Roeck 103904b296fSGuenter Roeck struct coefficients { 104904b296fSGuenter Roeck s16 m; 105904b296fSGuenter Roeck s16 b; 106904b296fSGuenter Roeck s16 R; 107904b296fSGuenter Roeck }; 108904b296fSGuenter Roeck 109904b296fSGuenter Roeck static const struct coefficients adm1075_coefficients[] = { 110904b296fSGuenter Roeck [0] = { 27169, 0, -1 }, /* voltage */ 111904b296fSGuenter Roeck [1] = { 806, 20475, -1 }, /* current, irange25 */ 112904b296fSGuenter Roeck [2] = { 404, 20475, -1 }, /* current, irange50 */ 1136faecba0SShikhar Dogra [3] = { 8549, 0, -1 }, /* power, irange25 */ 1146faecba0SShikhar Dogra [4] = { 4279, 0, -1 }, /* power, irange50 */ 115904b296fSGuenter Roeck }; 116904b296fSGuenter Roeck 1174ff0ce22SGuenter Roeck static const struct coefficients adm1272_coefficients[] = { 1184ff0ce22SGuenter Roeck [0] = { 6770, 0, -2 }, /* voltage, vrange 60V */ 1194ff0ce22SGuenter Roeck [1] = { 4062, 0, -2 }, /* voltage, vrange 100V */ 1204ff0ce22SGuenter Roeck [2] = { 1326, 20480, -1 }, /* current, vsense range 15mV */ 1214ff0ce22SGuenter Roeck [3] = { 663, 20480, -1 }, /* current, vsense range 30mV */ 1224ff0ce22SGuenter Roeck [4] = { 3512, 0, -2 }, /* power, vrange 60V, irange 15mV */ 1234ff0ce22SGuenter Roeck [5] = { 21071, 0, -3 }, /* power, vrange 100V, irange 15mV */ 1244ff0ce22SGuenter Roeck [6] = { 17561, 0, -3 }, /* power, vrange 60V, irange 30mV */ 1254ff0ce22SGuenter Roeck [7] = { 10535, 0, -3 }, /* power, vrange 100V, irange 30mV */ 1264ff0ce22SGuenter Roeck [8] = { 42, 31871, -1 }, /* temperature */ 1274ff0ce22SGuenter Roeck 1284ff0ce22SGuenter Roeck }; 1294ff0ce22SGuenter Roeck 130904b296fSGuenter Roeck static const struct coefficients adm1275_coefficients[] = { 131904b296fSGuenter Roeck [0] = { 19199, 0, -2 }, /* voltage, vrange set */ 132904b296fSGuenter Roeck [1] = { 6720, 0, -1 }, /* voltage, vrange not set */ 133904b296fSGuenter Roeck [2] = { 807, 20475, -1 }, /* current */ 134904b296fSGuenter Roeck }; 135904b296fSGuenter Roeck 136904b296fSGuenter Roeck static const struct coefficients adm1276_coefficients[] = { 137904b296fSGuenter Roeck [0] = { 19199, 0, -2 }, /* voltage, vrange set */ 138904b296fSGuenter Roeck [1] = { 6720, 0, -1 }, /* voltage, vrange not set */ 139904b296fSGuenter Roeck [2] = { 807, 20475, -1 }, /* current */ 140904b296fSGuenter Roeck [3] = { 6043, 0, -2 }, /* power, vrange set */ 141904b296fSGuenter Roeck [4] = { 2115, 0, -1 }, /* power, vrange not set */ 142904b296fSGuenter Roeck }; 143904b296fSGuenter Roeck 144709066acSGuenter Roeck static const struct coefficients adm1278_coefficients[] = { 145709066acSGuenter Roeck [0] = { 19599, 0, -2 }, /* voltage */ 146709066acSGuenter Roeck [1] = { 800, 20475, -1 }, /* current */ 147709066acSGuenter Roeck [2] = { 6123, 0, -2 }, /* power */ 148709066acSGuenter Roeck [3] = { 42, 31880, -1 }, /* temperature */ 149709066acSGuenter Roeck }; 150709066acSGuenter Roeck 15168a40382SGuenter Roeck static const struct coefficients adm1293_coefficients[] = { 15268a40382SGuenter Roeck [0] = { 3333, -1, 0 }, /* voltage, vrange 1.2V */ 15368a40382SGuenter Roeck [1] = { 5552, -5, -1 }, /* voltage, vrange 7.4V */ 15468a40382SGuenter Roeck [2] = { 19604, -50, -2 }, /* voltage, vrange 21V */ 15568a40382SGuenter Roeck [3] = { 8000, -100, -2 }, /* current, irange25 */ 15668a40382SGuenter Roeck [4] = { 4000, -100, -2 }, /* current, irange50 */ 15768a40382SGuenter Roeck [5] = { 20000, -1000, -3 }, /* current, irange100 */ 15868a40382SGuenter Roeck [6] = { 10000, -1000, -3 }, /* current, irange200 */ 15968a40382SGuenter Roeck [7] = { 10417, 0, -1 }, /* power, 1.2V, irange25 */ 16068a40382SGuenter Roeck [8] = { 5208, 0, -1 }, /* power, 1.2V, irange50 */ 16168a40382SGuenter Roeck [9] = { 26042, 0, -2 }, /* power, 1.2V, irange100 */ 16268a40382SGuenter Roeck [10] = { 13021, 0, -2 }, /* power, 1.2V, irange200 */ 16368a40382SGuenter Roeck [11] = { 17351, 0, -2 }, /* power, 7.4V, irange25 */ 16468a40382SGuenter Roeck [12] = { 8676, 0, -2 }, /* power, 7.4V, irange50 */ 16568a40382SGuenter Roeck [13] = { 4338, 0, -2 }, /* power, 7.4V, irange100 */ 16668a40382SGuenter Roeck [14] = { 21689, 0, -3 }, /* power, 7.4V, irange200 */ 16768a40382SGuenter Roeck [15] = { 6126, 0, -2 }, /* power, 21V, irange25 */ 16868a40382SGuenter Roeck [16] = { 30631, 0, -3 }, /* power, 21V, irange50 */ 16968a40382SGuenter Roeck [17] = { 15316, 0, -3 }, /* power, 21V, irange100 */ 17068a40382SGuenter Roeck [18] = { 7658, 0, -3 }, /* power, 21V, irange200 */ 17168a40382SGuenter Roeck }; 17268a40382SGuenter Roeck 1737d45deb3SGuenter Roeck static int adm1275_read_pmon_config(const struct adm1275_data *data, 1747d45deb3SGuenter Roeck struct i2c_client *client, bool is_power) 175c83529c1SAdamski, Krzysztof (Nokia - PL/Wroclaw) { 1767d45deb3SGuenter Roeck int shift, ret; 1777d45deb3SGuenter Roeck u16 mask; 178c83529c1SAdamski, Krzysztof (Nokia - PL/Wroclaw) 1797d45deb3SGuenter Roeck /* 1807d45deb3SGuenter Roeck * The PMON configuration register is a 16-bit register only on chips 1817d45deb3SGuenter Roeck * supporting power average sampling. On other chips it is an 8-bit 1827d45deb3SGuenter Roeck * register. 1837d45deb3SGuenter Roeck */ 1847d45deb3SGuenter Roeck if (data->have_power_sampling) { 185c83529c1SAdamski, Krzysztof (Nokia - PL/Wroclaw) ret = i2c_smbus_read_word_data(client, ADM1275_PMON_CONFIG); 1867d45deb3SGuenter Roeck mask = is_power ? ADM1278_PWR_AVG_MASK : ADM1278_VI_AVG_MASK; 1877d45deb3SGuenter Roeck shift = is_power ? ADM1278_PWR_AVG_SHIFT : ADM1278_VI_AVG_SHIFT; 1887d45deb3SGuenter Roeck } else { 1897d45deb3SGuenter Roeck ret = i2c_smbus_read_byte_data(client, ADM1275_PMON_CONFIG); 1907d45deb3SGuenter Roeck mask = ADM1275_VI_AVG_MASK; 1917d45deb3SGuenter Roeck shift = ADM1275_VI_AVG_SHIFT; 1927d45deb3SGuenter Roeck } 193c83529c1SAdamski, Krzysztof (Nokia - PL/Wroclaw) if (ret < 0) 194c83529c1SAdamski, Krzysztof (Nokia - PL/Wroclaw) return ret; 195c83529c1SAdamski, Krzysztof (Nokia - PL/Wroclaw) 1967d45deb3SGuenter Roeck return (ret & mask) >> shift; 197c83529c1SAdamski, Krzysztof (Nokia - PL/Wroclaw) } 198c83529c1SAdamski, Krzysztof (Nokia - PL/Wroclaw) 1997d45deb3SGuenter Roeck static int adm1275_write_pmon_config(const struct adm1275_data *data, 2007d45deb3SGuenter Roeck struct i2c_client *client, 2017d45deb3SGuenter Roeck bool is_power, u16 word) 202c83529c1SAdamski, Krzysztof (Nokia - PL/Wroclaw) { 2037d45deb3SGuenter Roeck int shift, ret; 2047d45deb3SGuenter Roeck u16 mask; 205c83529c1SAdamski, Krzysztof (Nokia - PL/Wroclaw) 2067d45deb3SGuenter Roeck if (data->have_power_sampling) { 207c83529c1SAdamski, Krzysztof (Nokia - PL/Wroclaw) ret = i2c_smbus_read_word_data(client, ADM1275_PMON_CONFIG); 2087d45deb3SGuenter Roeck mask = is_power ? ADM1278_PWR_AVG_MASK : ADM1278_VI_AVG_MASK; 2097d45deb3SGuenter Roeck shift = is_power ? ADM1278_PWR_AVG_SHIFT : ADM1278_VI_AVG_SHIFT; 2107d45deb3SGuenter Roeck } else { 2117d45deb3SGuenter Roeck ret = i2c_smbus_read_byte_data(client, ADM1275_PMON_CONFIG); 2127d45deb3SGuenter Roeck mask = ADM1275_VI_AVG_MASK; 2137d45deb3SGuenter Roeck shift = ADM1275_VI_AVG_SHIFT; 2147d45deb3SGuenter Roeck } 215c83529c1SAdamski, Krzysztof (Nokia - PL/Wroclaw) if (ret < 0) 216c83529c1SAdamski, Krzysztof (Nokia - PL/Wroclaw) return ret; 217c83529c1SAdamski, Krzysztof (Nokia - PL/Wroclaw) 2187d45deb3SGuenter Roeck word = (ret & ~mask) | ((word << shift) & mask); 2197d45deb3SGuenter Roeck if (data->have_power_sampling) 2207d45deb3SGuenter Roeck ret = i2c_smbus_write_word_data(client, ADM1275_PMON_CONFIG, 2217d45deb3SGuenter Roeck word); 2227d45deb3SGuenter Roeck else 2237d45deb3SGuenter Roeck ret = i2c_smbus_write_byte_data(client, ADM1275_PMON_CONFIG, 2247d45deb3SGuenter Roeck word); 225c83529c1SAdamski, Krzysztof (Nokia - PL/Wroclaw) 226c83529c1SAdamski, Krzysztof (Nokia - PL/Wroclaw) return ret; 227c83529c1SAdamski, Krzysztof (Nokia - PL/Wroclaw) } 228c83529c1SAdamski, Krzysztof (Nokia - PL/Wroclaw) 22943f33b6eSGuenter Roeck static int adm1275_read_word_data(struct i2c_client *client, int page, 23043f33b6eSGuenter Roeck int phase, int reg) 231c576e30cSGuenter Roeck { 232c5e67636SGuenter Roeck const struct pmbus_driver_info *info = pmbus_get_driver_info(client); 233c5e67636SGuenter Roeck const struct adm1275_data *data = to_adm1275_data(info); 2345cf231a3SGuenter Roeck int ret = 0; 235c576e30cSGuenter Roeck 236ecb29abdSGuenter Roeck if (page > 0) 237c5e67636SGuenter Roeck return -ENXIO; 238c576e30cSGuenter Roeck 239c576e30cSGuenter Roeck switch (reg) { 240c5e67636SGuenter Roeck case PMBUS_IOUT_UC_FAULT_LIMIT: 2419048539bSGuenter Roeck if (!data->have_uc_fault) 2429048539bSGuenter Roeck return -ENXIO; 24343f33b6eSGuenter Roeck ret = pmbus_read_word_data(client, 0, 0xff, 24443f33b6eSGuenter Roeck ADM1275_IOUT_WARN2_LIMIT); 245c5e67636SGuenter Roeck break; 246c5e67636SGuenter Roeck case PMBUS_IOUT_OC_FAULT_LIMIT: 2479048539bSGuenter Roeck if (!data->have_oc_fault) 2489048539bSGuenter Roeck return -ENXIO; 24943f33b6eSGuenter Roeck ret = pmbus_read_word_data(client, 0, 0xff, 25043f33b6eSGuenter Roeck ADM1275_IOUT_WARN2_LIMIT); 251c5e67636SGuenter Roeck break; 25292711269SGuenter Roeck case PMBUS_VOUT_OV_WARN_LIMIT: 2539048539bSGuenter Roeck if (data->have_vout) 2549048539bSGuenter Roeck return -ENODATA; 25543f33b6eSGuenter Roeck ret = pmbus_read_word_data(client, 0, 0xff, 25692711269SGuenter Roeck ADM1075_VAUX_OV_WARN_LIMIT); 25792711269SGuenter Roeck break; 25892711269SGuenter Roeck case PMBUS_VOUT_UV_WARN_LIMIT: 2599048539bSGuenter Roeck if (data->have_vout) 2609048539bSGuenter Roeck return -ENODATA; 26143f33b6eSGuenter Roeck ret = pmbus_read_word_data(client, 0, 0xff, 26292711269SGuenter Roeck ADM1075_VAUX_UV_WARN_LIMIT); 26392711269SGuenter Roeck break; 26492711269SGuenter Roeck case PMBUS_READ_VOUT: 2659048539bSGuenter Roeck if (data->have_vout) 2669048539bSGuenter Roeck return -ENODATA; 26743f33b6eSGuenter Roeck ret = pmbus_read_word_data(client, 0, 0xff, 26843f33b6eSGuenter Roeck ADM1075_READ_VAUX); 26992711269SGuenter Roeck break; 27068a40382SGuenter Roeck case PMBUS_VIRT_READ_IOUT_MIN: 27168a40382SGuenter Roeck if (!data->have_iout_min) 27268a40382SGuenter Roeck return -ENXIO; 27343f33b6eSGuenter Roeck ret = pmbus_read_word_data(client, 0, 0xff, 27443f33b6eSGuenter Roeck ADM1293_IOUT_MIN); 27568a40382SGuenter Roeck break; 276c576e30cSGuenter Roeck case PMBUS_VIRT_READ_IOUT_MAX: 27743f33b6eSGuenter Roeck ret = pmbus_read_word_data(client, 0, 0xff, 27843f33b6eSGuenter Roeck ADM1275_PEAK_IOUT); 279c576e30cSGuenter Roeck break; 280c576e30cSGuenter Roeck case PMBUS_VIRT_READ_VOUT_MAX: 28143f33b6eSGuenter Roeck ret = pmbus_read_word_data(client, 0, 0xff, 28243f33b6eSGuenter Roeck ADM1275_PEAK_VOUT); 283c576e30cSGuenter Roeck break; 284c576e30cSGuenter Roeck case PMBUS_VIRT_READ_VIN_MAX: 28543f33b6eSGuenter Roeck ret = pmbus_read_word_data(client, 0, 0xff, 28643f33b6eSGuenter Roeck ADM1275_PEAK_VIN); 287c576e30cSGuenter Roeck break; 28868a40382SGuenter Roeck case PMBUS_VIRT_READ_PIN_MIN: 28968a40382SGuenter Roeck if (!data->have_pin_min) 29068a40382SGuenter Roeck return -ENXIO; 29143f33b6eSGuenter Roeck ret = pmbus_read_word_data(client, 0, 0xff, 29243f33b6eSGuenter Roeck ADM1293_PIN_MIN); 29368a40382SGuenter Roeck break; 2945cf231a3SGuenter Roeck case PMBUS_VIRT_READ_PIN_MAX: 2959048539bSGuenter Roeck if (!data->have_pin_max) 2969048539bSGuenter Roeck return -ENXIO; 29743f33b6eSGuenter Roeck ret = pmbus_read_word_data(client, 0, 0xff, 29843f33b6eSGuenter Roeck ADM1276_PEAK_PIN); 2995cf231a3SGuenter Roeck break; 300709066acSGuenter Roeck case PMBUS_VIRT_READ_TEMP_MAX: 301709066acSGuenter Roeck if (!data->have_temp_max) 302709066acSGuenter Roeck return -ENXIO; 30343f33b6eSGuenter Roeck ret = pmbus_read_word_data(client, 0, 0xff, 30443f33b6eSGuenter Roeck ADM1278_PEAK_TEMP); 305709066acSGuenter Roeck break; 306c576e30cSGuenter Roeck case PMBUS_VIRT_RESET_IOUT_HISTORY: 307c576e30cSGuenter Roeck case PMBUS_VIRT_RESET_VOUT_HISTORY: 308c576e30cSGuenter Roeck case PMBUS_VIRT_RESET_VIN_HISTORY: 3095cf231a3SGuenter Roeck break; 3105cf231a3SGuenter Roeck case PMBUS_VIRT_RESET_PIN_HISTORY: 3119048539bSGuenter Roeck if (!data->have_pin_max) 3129048539bSGuenter Roeck return -ENXIO; 313c576e30cSGuenter Roeck break; 314709066acSGuenter Roeck case PMBUS_VIRT_RESET_TEMP_HISTORY: 315709066acSGuenter Roeck if (!data->have_temp_max) 316709066acSGuenter Roeck return -ENXIO; 317709066acSGuenter Roeck break; 318c83529c1SAdamski, Krzysztof (Nokia - PL/Wroclaw) case PMBUS_VIRT_POWER_SAMPLES: 3197d45deb3SGuenter Roeck if (!data->have_power_sampling) 3207d45deb3SGuenter Roeck return -ENXIO; 3217d45deb3SGuenter Roeck ret = adm1275_read_pmon_config(data, client, true); 322c83529c1SAdamski, Krzysztof (Nokia - PL/Wroclaw) if (ret < 0) 323c83529c1SAdamski, Krzysztof (Nokia - PL/Wroclaw) break; 324c83529c1SAdamski, Krzysztof (Nokia - PL/Wroclaw) ret = BIT(ret); 325c83529c1SAdamski, Krzysztof (Nokia - PL/Wroclaw) break; 326c83529c1SAdamski, Krzysztof (Nokia - PL/Wroclaw) case PMBUS_VIRT_IN_SAMPLES: 327c83529c1SAdamski, Krzysztof (Nokia - PL/Wroclaw) case PMBUS_VIRT_CURR_SAMPLES: 3287d45deb3SGuenter Roeck ret = adm1275_read_pmon_config(data, client, false); 329c83529c1SAdamski, Krzysztof (Nokia - PL/Wroclaw) if (ret < 0) 330c83529c1SAdamski, Krzysztof (Nokia - PL/Wroclaw) break; 331c83529c1SAdamski, Krzysztof (Nokia - PL/Wroclaw) ret = BIT(ret); 332c83529c1SAdamski, Krzysztof (Nokia - PL/Wroclaw) break; 333c576e30cSGuenter Roeck default: 334c576e30cSGuenter Roeck ret = -ENODATA; 335c576e30cSGuenter Roeck break; 336c576e30cSGuenter Roeck } 337c576e30cSGuenter Roeck return ret; 338c576e30cSGuenter Roeck } 339c576e30cSGuenter Roeck 340c576e30cSGuenter Roeck static int adm1275_write_word_data(struct i2c_client *client, int page, int reg, 341c576e30cSGuenter Roeck u16 word) 342c576e30cSGuenter Roeck { 34368a40382SGuenter Roeck const struct pmbus_driver_info *info = pmbus_get_driver_info(client); 34468a40382SGuenter Roeck const struct adm1275_data *data = to_adm1275_data(info); 345c576e30cSGuenter Roeck int ret; 346c576e30cSGuenter Roeck 347ecb29abdSGuenter Roeck if (page > 0) 348c5e67636SGuenter Roeck return -ENXIO; 349c576e30cSGuenter Roeck 350c576e30cSGuenter Roeck switch (reg) { 351c5e67636SGuenter Roeck case PMBUS_IOUT_UC_FAULT_LIMIT: 352c5e67636SGuenter Roeck case PMBUS_IOUT_OC_FAULT_LIMIT: 353c5e67636SGuenter Roeck ret = pmbus_write_word_data(client, 0, ADM1275_IOUT_WARN2_LIMIT, 354c5e67636SGuenter Roeck word); 355c5e67636SGuenter Roeck break; 356c576e30cSGuenter Roeck case PMBUS_VIRT_RESET_IOUT_HISTORY: 357c576e30cSGuenter Roeck ret = pmbus_write_word_data(client, 0, ADM1275_PEAK_IOUT, 0); 35868a40382SGuenter Roeck if (!ret && data->have_iout_min) 35968a40382SGuenter Roeck ret = pmbus_write_word_data(client, 0, 36068a40382SGuenter Roeck ADM1293_IOUT_MIN, 0); 361c576e30cSGuenter Roeck break; 362c576e30cSGuenter Roeck case PMBUS_VIRT_RESET_VOUT_HISTORY: 363c576e30cSGuenter Roeck ret = pmbus_write_word_data(client, 0, ADM1275_PEAK_VOUT, 0); 364c576e30cSGuenter Roeck break; 365c576e30cSGuenter Roeck case PMBUS_VIRT_RESET_VIN_HISTORY: 366c576e30cSGuenter Roeck ret = pmbus_write_word_data(client, 0, ADM1275_PEAK_VIN, 0); 367c576e30cSGuenter Roeck break; 3685cf231a3SGuenter Roeck case PMBUS_VIRT_RESET_PIN_HISTORY: 3695cf231a3SGuenter Roeck ret = pmbus_write_word_data(client, 0, ADM1276_PEAK_PIN, 0); 37068a40382SGuenter Roeck if (!ret && data->have_pin_min) 37168a40382SGuenter Roeck ret = pmbus_write_word_data(client, 0, 37268a40382SGuenter Roeck ADM1293_PIN_MIN, 0); 3735cf231a3SGuenter Roeck break; 374709066acSGuenter Roeck case PMBUS_VIRT_RESET_TEMP_HISTORY: 375709066acSGuenter Roeck ret = pmbus_write_word_data(client, 0, ADM1278_PEAK_TEMP, 0); 376709066acSGuenter Roeck break; 377c83529c1SAdamski, Krzysztof (Nokia - PL/Wroclaw) case PMBUS_VIRT_POWER_SAMPLES: 3787d45deb3SGuenter Roeck if (!data->have_power_sampling) 3797d45deb3SGuenter Roeck return -ENXIO; 380c83529c1SAdamski, Krzysztof (Nokia - PL/Wroclaw) word = clamp_val(word, 1, ADM1275_SAMPLES_AVG_MAX); 3817d45deb3SGuenter Roeck ret = adm1275_write_pmon_config(data, client, true, 382c83529c1SAdamski, Krzysztof (Nokia - PL/Wroclaw) ilog2(word)); 383c83529c1SAdamski, Krzysztof (Nokia - PL/Wroclaw) break; 384c83529c1SAdamski, Krzysztof (Nokia - PL/Wroclaw) case PMBUS_VIRT_IN_SAMPLES: 385c83529c1SAdamski, Krzysztof (Nokia - PL/Wroclaw) case PMBUS_VIRT_CURR_SAMPLES: 386c83529c1SAdamski, Krzysztof (Nokia - PL/Wroclaw) word = clamp_val(word, 1, ADM1275_SAMPLES_AVG_MAX); 3877d45deb3SGuenter Roeck ret = adm1275_write_pmon_config(data, client, false, 388c83529c1SAdamski, Krzysztof (Nokia - PL/Wroclaw) ilog2(word)); 389c83529c1SAdamski, Krzysztof (Nokia - PL/Wroclaw) break; 390c576e30cSGuenter Roeck default: 391c576e30cSGuenter Roeck ret = -ENODATA; 392c576e30cSGuenter Roeck break; 393c576e30cSGuenter Roeck } 394c576e30cSGuenter Roeck return ret; 395c576e30cSGuenter Roeck } 396c576e30cSGuenter Roeck 397c5e67636SGuenter Roeck static int adm1275_read_byte_data(struct i2c_client *client, int page, int reg) 398c5e67636SGuenter Roeck { 399c5e67636SGuenter Roeck const struct pmbus_driver_info *info = pmbus_get_driver_info(client); 400c5e67636SGuenter Roeck const struct adm1275_data *data = to_adm1275_data(info); 401c5e67636SGuenter Roeck int mfr_status, ret; 402c5e67636SGuenter Roeck 403da8e48abSGuenter Roeck if (page > 0) 404c5e67636SGuenter Roeck return -ENXIO; 405c5e67636SGuenter Roeck 406c5e67636SGuenter Roeck switch (reg) { 407c5e67636SGuenter Roeck case PMBUS_STATUS_IOUT: 408c5e67636SGuenter Roeck ret = pmbus_read_byte_data(client, page, PMBUS_STATUS_IOUT); 409c5e67636SGuenter Roeck if (ret < 0) 410c5e67636SGuenter Roeck break; 4119048539bSGuenter Roeck if (!data->have_oc_fault && !data->have_uc_fault) 4129048539bSGuenter Roeck break; 413c5e67636SGuenter Roeck mfr_status = pmbus_read_byte_data(client, page, 414c5e67636SGuenter Roeck PMBUS_STATUS_MFR_SPECIFIC); 4159048539bSGuenter Roeck if (mfr_status < 0) 4169048539bSGuenter Roeck return mfr_status; 417c5e67636SGuenter Roeck if (mfr_status & ADM1275_MFR_STATUS_IOUT_WARN2) { 418c5e67636SGuenter Roeck ret |= data->have_oc_fault ? 419c5e67636SGuenter Roeck PB_IOUT_OC_FAULT : PB_IOUT_UC_FAULT; 420c5e67636SGuenter Roeck } 421c5e67636SGuenter Roeck break; 42292711269SGuenter Roeck case PMBUS_STATUS_VOUT: 4239048539bSGuenter Roeck if (data->have_vout) 4249048539bSGuenter Roeck return -ENODATA; 42592711269SGuenter Roeck ret = 0; 4269048539bSGuenter Roeck if (data->have_vaux_status) { 42792711269SGuenter Roeck mfr_status = pmbus_read_byte_data(client, 0, 42892711269SGuenter Roeck ADM1075_VAUX_STATUS); 4299048539bSGuenter Roeck if (mfr_status < 0) 4309048539bSGuenter Roeck return mfr_status; 43192711269SGuenter Roeck if (mfr_status & ADM1075_VAUX_OV_WARN) 43292711269SGuenter Roeck ret |= PB_VOLTAGE_OV_WARNING; 43392711269SGuenter Roeck if (mfr_status & ADM1075_VAUX_UV_WARN) 43492711269SGuenter Roeck ret |= PB_VOLTAGE_UV_WARNING; 43568a40382SGuenter Roeck } else if (data->have_mfr_vaux_status) { 43668a40382SGuenter Roeck mfr_status = pmbus_read_byte_data(client, page, 43768a40382SGuenter Roeck PMBUS_STATUS_MFR_SPECIFIC); 43868a40382SGuenter Roeck if (mfr_status < 0) 43968a40382SGuenter Roeck return mfr_status; 44068a40382SGuenter Roeck if (mfr_status & ADM1293_MFR_STATUS_VAUX_OV_WARN) 44168a40382SGuenter Roeck ret |= PB_VOLTAGE_OV_WARNING; 44268a40382SGuenter Roeck if (mfr_status & ADM1293_MFR_STATUS_VAUX_UV_WARN) 44368a40382SGuenter Roeck ret |= PB_VOLTAGE_UV_WARNING; 4449048539bSGuenter Roeck } 44592711269SGuenter Roeck break; 446c5e67636SGuenter Roeck default: 447c5e67636SGuenter Roeck ret = -ENODATA; 448c5e67636SGuenter Roeck break; 449c5e67636SGuenter Roeck } 450c5e67636SGuenter Roeck return ret; 451c5e67636SGuenter Roeck } 452c5e67636SGuenter Roeck 45387102808SGuenter Roeck static const struct i2c_device_id adm1275_id[] = { 45492711269SGuenter Roeck { "adm1075", adm1075 }, 4554ff0ce22SGuenter Roeck { "adm1272", adm1272 }, 45687102808SGuenter Roeck { "adm1275", adm1275 }, 45787102808SGuenter Roeck { "adm1276", adm1276 }, 458709066acSGuenter Roeck { "adm1278", adm1278 }, 45968a40382SGuenter Roeck { "adm1293", adm1293 }, 46068a40382SGuenter Roeck { "adm1294", adm1294 }, 46187102808SGuenter Roeck { } 46287102808SGuenter Roeck }; 46387102808SGuenter Roeck MODULE_DEVICE_TABLE(i2c, adm1275_id); 46487102808SGuenter Roeck 465dd431939SStephen Kitt static int adm1275_probe(struct i2c_client *client) 4669d2ecfb7SGuenter Roeck { 4676d1d41c0SChu Lin s32 (*config_read_fn)(const struct i2c_client *client, u8 reg); 46887102808SGuenter Roeck u8 block_buffer[I2C_SMBUS_BLOCK_MAX + 1]; 469c5e67636SGuenter Roeck int config, device_config; 4709d2ecfb7SGuenter Roeck int ret; 4719d2ecfb7SGuenter Roeck struct pmbus_driver_info *info; 472c5e67636SGuenter Roeck struct adm1275_data *data; 47387102808SGuenter Roeck const struct i2c_device_id *mid; 474904b296fSGuenter Roeck const struct coefficients *coefficients; 47568a40382SGuenter Roeck int vindex = -1, voindex = -1, cindex = -1, pindex = -1; 476709066acSGuenter Roeck int tindex = -1; 4776e5c06adSKun Yi u32 shunt; 478*a3cd66d7SPotin Lai u32 avg; 4799d2ecfb7SGuenter Roeck 4809d2ecfb7SGuenter Roeck if (!i2c_check_functionality(client->adapter, 48187102808SGuenter Roeck I2C_FUNC_SMBUS_READ_BYTE_DATA 48287102808SGuenter Roeck | I2C_FUNC_SMBUS_BLOCK_DATA)) 4839d2ecfb7SGuenter Roeck return -ENODEV; 4849d2ecfb7SGuenter Roeck 48587102808SGuenter Roeck ret = i2c_smbus_read_block_data(client, PMBUS_MFR_ID, block_buffer); 48687102808SGuenter Roeck if (ret < 0) { 48787102808SGuenter Roeck dev_err(&client->dev, "Failed to read Manufacturer ID\n"); 48887102808SGuenter Roeck return ret; 48987102808SGuenter Roeck } 49087102808SGuenter Roeck if (ret != 3 || strncmp(block_buffer, "ADI", 3)) { 49187102808SGuenter Roeck dev_err(&client->dev, "Unsupported Manufacturer ID\n"); 49287102808SGuenter Roeck return -ENODEV; 49387102808SGuenter Roeck } 49487102808SGuenter Roeck 49587102808SGuenter Roeck ret = i2c_smbus_read_block_data(client, PMBUS_MFR_MODEL, block_buffer); 49687102808SGuenter Roeck if (ret < 0) { 49787102808SGuenter Roeck dev_err(&client->dev, "Failed to read Manufacturer Model\n"); 49887102808SGuenter Roeck return ret; 49987102808SGuenter Roeck } 50087102808SGuenter Roeck for (mid = adm1275_id; mid->name[0]; mid++) { 50187102808SGuenter Roeck if (!strncasecmp(mid->name, block_buffer, strlen(mid->name))) 50287102808SGuenter Roeck break; 50387102808SGuenter Roeck } 50487102808SGuenter Roeck if (!mid->name[0]) { 50587102808SGuenter Roeck dev_err(&client->dev, "Unsupported device\n"); 50687102808SGuenter Roeck return -ENODEV; 50787102808SGuenter Roeck } 50887102808SGuenter Roeck 509dd431939SStephen Kitt if (strcmp(client->name, mid->name) != 0) 51087102808SGuenter Roeck dev_notice(&client->dev, 51187102808SGuenter Roeck "Device mismatch: Configured %s, detected %s\n", 512dd431939SStephen Kitt client->name, mid->name); 51387102808SGuenter Roeck 5146d1d41c0SChu Lin if (mid->driver_data == adm1272 || mid->driver_data == adm1278 || 5156d1d41c0SChu Lin mid->driver_data == adm1293 || mid->driver_data == adm1294) 5166d1d41c0SChu Lin config_read_fn = i2c_smbus_read_word_data; 5176d1d41c0SChu Lin else 5186d1d41c0SChu Lin config_read_fn = i2c_smbus_read_byte_data; 5196d1d41c0SChu Lin config = config_read_fn(client, ADM1275_PMON_CONFIG); 52087102808SGuenter Roeck if (config < 0) 52187102808SGuenter Roeck return config; 52287102808SGuenter Roeck 5236d1d41c0SChu Lin device_config = config_read_fn(client, ADM1275_DEVICE_CONFIG); 52487102808SGuenter Roeck if (device_config < 0) 52587102808SGuenter Roeck return device_config; 52687102808SGuenter Roeck 5278b313ca7SGuenter Roeck data = devm_kzalloc(&client->dev, sizeof(struct adm1275_data), 5288b313ca7SGuenter Roeck GFP_KERNEL); 529c5e67636SGuenter Roeck if (!data) 5309d2ecfb7SGuenter Roeck return -ENOMEM; 5319d2ecfb7SGuenter Roeck 5326e5c06adSKun Yi if (of_property_read_u32(client->dev.of_node, 5336e5c06adSKun Yi "shunt-resistor-micro-ohms", &shunt)) 5346e5c06adSKun Yi shunt = 1000; /* 1 mOhm if not set via DT */ 5356e5c06adSKun Yi 5366e5c06adSKun Yi if (shunt == 0) 5376e5c06adSKun Yi return -EINVAL; 5386e5c06adSKun Yi 53987102808SGuenter Roeck data->id = mid->driver_data; 5409d2ecfb7SGuenter Roeck 541c5e67636SGuenter Roeck info = &data->info; 542c5e67636SGuenter Roeck 5439d2ecfb7SGuenter Roeck info->pages = 1; 5441061d851SGuenter Roeck info->format[PSC_VOLTAGE_IN] = direct; 5451061d851SGuenter Roeck info->format[PSC_VOLTAGE_OUT] = direct; 5461061d851SGuenter Roeck info->format[PSC_CURRENT_OUT] = direct; 547904b296fSGuenter Roeck info->format[PSC_POWER] = direct; 548709066acSGuenter Roeck info->format[PSC_TEMPERATURE] = direct; 549c83529c1SAdamski, Krzysztof (Nokia - PL/Wroclaw) info->func[0] = PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT | 550c83529c1SAdamski, Krzysztof (Nokia - PL/Wroclaw) PMBUS_HAVE_SAMPLES; 5519d2ecfb7SGuenter Roeck 552c576e30cSGuenter Roeck info->read_word_data = adm1275_read_word_data; 553c5e67636SGuenter Roeck info->read_byte_data = adm1275_read_byte_data; 554c576e30cSGuenter Roeck info->write_word_data = adm1275_write_word_data; 555c576e30cSGuenter Roeck 55687102808SGuenter Roeck switch (data->id) { 55792711269SGuenter Roeck case adm1075: 5589048539bSGuenter Roeck if (device_config & ADM1275_IOUT_WARN2_SELECT) 5599048539bSGuenter Roeck data->have_oc_fault = true; 5609048539bSGuenter Roeck else 5619048539bSGuenter Roeck data->have_uc_fault = true; 5629048539bSGuenter Roeck data->have_pin_max = true; 5639048539bSGuenter Roeck data->have_vaux_status = true; 5649048539bSGuenter Roeck 565904b296fSGuenter Roeck coefficients = adm1075_coefficients; 566904b296fSGuenter Roeck vindex = 0; 56792711269SGuenter Roeck switch (config & ADM1075_IRANGE_MASK) { 56892711269SGuenter Roeck case ADM1075_IRANGE_25: 569904b296fSGuenter Roeck cindex = 1; 570904b296fSGuenter Roeck pindex = 3; 57192711269SGuenter Roeck break; 57292711269SGuenter Roeck case ADM1075_IRANGE_50: 573904b296fSGuenter Roeck cindex = 2; 574904b296fSGuenter Roeck pindex = 4; 57592711269SGuenter Roeck break; 57692711269SGuenter Roeck default: 57792711269SGuenter Roeck dev_err(&client->dev, "Invalid input current range"); 57892711269SGuenter Roeck break; 57992711269SGuenter Roeck } 580904b296fSGuenter Roeck 58192711269SGuenter Roeck info->func[0] |= PMBUS_HAVE_VIN | PMBUS_HAVE_PIN 58292711269SGuenter Roeck | PMBUS_HAVE_STATUS_INPUT; 58392711269SGuenter Roeck if (config & ADM1275_VIN_VOUT_SELECT) 58492711269SGuenter Roeck info->func[0] |= 58592711269SGuenter Roeck PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT; 58692711269SGuenter Roeck break; 5874ff0ce22SGuenter Roeck case adm1272: 5884ff0ce22SGuenter Roeck data->have_vout = true; 5894ff0ce22SGuenter Roeck data->have_pin_max = true; 5904ff0ce22SGuenter Roeck data->have_temp_max = true; 5917d45deb3SGuenter Roeck data->have_power_sampling = true; 5924ff0ce22SGuenter Roeck 5934ff0ce22SGuenter Roeck coefficients = adm1272_coefficients; 5944ff0ce22SGuenter Roeck vindex = (config & ADM1275_VRANGE) ? 1 : 0; 5954ff0ce22SGuenter Roeck cindex = (config & ADM1272_IRANGE) ? 3 : 2; 5964ff0ce22SGuenter Roeck /* pindex depends on the combination of the above */ 5974ff0ce22SGuenter Roeck switch (config & (ADM1275_VRANGE | ADM1272_IRANGE)) { 5984ff0ce22SGuenter Roeck case 0: 5994ff0ce22SGuenter Roeck default: 6004ff0ce22SGuenter Roeck pindex = 4; 6014ff0ce22SGuenter Roeck break; 6024ff0ce22SGuenter Roeck case ADM1275_VRANGE: 6034ff0ce22SGuenter Roeck pindex = 5; 6044ff0ce22SGuenter Roeck break; 6054ff0ce22SGuenter Roeck case ADM1272_IRANGE: 6064ff0ce22SGuenter Roeck pindex = 6; 6074ff0ce22SGuenter Roeck break; 6084ff0ce22SGuenter Roeck case ADM1275_VRANGE | ADM1272_IRANGE: 6094ff0ce22SGuenter Roeck pindex = 7; 6104ff0ce22SGuenter Roeck break; 6114ff0ce22SGuenter Roeck } 6124ff0ce22SGuenter Roeck tindex = 8; 6134ff0ce22SGuenter Roeck 6144ff0ce22SGuenter Roeck info->func[0] |= PMBUS_HAVE_PIN | PMBUS_HAVE_STATUS_INPUT | 6159da9c2dcSChu Lin PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT | 6169da9c2dcSChu Lin PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP; 6174ff0ce22SGuenter Roeck 6189da9c2dcSChu Lin /* Enable VOUT & TEMP1 if not enabled (disabled by default) */ 6199da9c2dcSChu Lin if ((config & (ADM1278_VOUT_EN | ADM1278_TEMP1_EN)) != 6209da9c2dcSChu Lin (ADM1278_VOUT_EN | ADM1278_TEMP1_EN)) { 6219da9c2dcSChu Lin config |= ADM1278_VOUT_EN | ADM1278_TEMP1_EN; 6224ff0ce22SGuenter Roeck ret = i2c_smbus_write_byte_data(client, 6234ff0ce22SGuenter Roeck ADM1275_PMON_CONFIG, 6244ff0ce22SGuenter Roeck config); 6254ff0ce22SGuenter Roeck if (ret < 0) { 6264ff0ce22SGuenter Roeck dev_err(&client->dev, 6274ff0ce22SGuenter Roeck "Failed to enable VOUT monitoring\n"); 6284ff0ce22SGuenter Roeck return -ENODEV; 6294ff0ce22SGuenter Roeck } 6304ff0ce22SGuenter Roeck } 6314ff0ce22SGuenter Roeck if (config & ADM1278_VIN_EN) 6324ff0ce22SGuenter Roeck info->func[0] |= PMBUS_HAVE_VIN; 6334ff0ce22SGuenter Roeck break; 6345cf231a3SGuenter Roeck case adm1275: 6359048539bSGuenter Roeck if (device_config & ADM1275_IOUT_WARN2_SELECT) 6369048539bSGuenter Roeck data->have_oc_fault = true; 6379048539bSGuenter Roeck else 6389048539bSGuenter Roeck data->have_uc_fault = true; 6399048539bSGuenter Roeck data->have_vout = true; 6409048539bSGuenter Roeck 641904b296fSGuenter Roeck coefficients = adm1275_coefficients; 642904b296fSGuenter Roeck vindex = (config & ADM1275_VRANGE) ? 0 : 1; 643904b296fSGuenter Roeck cindex = 2; 644904b296fSGuenter Roeck 6459d2ecfb7SGuenter Roeck if (config & ADM1275_VIN_VOUT_SELECT) 6465cf231a3SGuenter Roeck info->func[0] |= 6475cf231a3SGuenter Roeck PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT; 6489d2ecfb7SGuenter Roeck else 6495cf231a3SGuenter Roeck info->func[0] |= 6505cf231a3SGuenter Roeck PMBUS_HAVE_VIN | PMBUS_HAVE_STATUS_INPUT; 6515cf231a3SGuenter Roeck break; 6525cf231a3SGuenter Roeck case adm1276: 6539048539bSGuenter Roeck if (device_config & ADM1275_IOUT_WARN2_SELECT) 6549048539bSGuenter Roeck data->have_oc_fault = true; 6559048539bSGuenter Roeck else 6569048539bSGuenter Roeck data->have_uc_fault = true; 6579048539bSGuenter Roeck data->have_vout = true; 6589048539bSGuenter Roeck data->have_pin_max = true; 6599048539bSGuenter Roeck 660904b296fSGuenter Roeck coefficients = adm1276_coefficients; 661904b296fSGuenter Roeck vindex = (config & ADM1275_VRANGE) ? 0 : 1; 662904b296fSGuenter Roeck cindex = 2; 663904b296fSGuenter Roeck pindex = (config & ADM1275_VRANGE) ? 3 : 4; 664904b296fSGuenter Roeck 6655cf231a3SGuenter Roeck info->func[0] |= PMBUS_HAVE_VIN | PMBUS_HAVE_PIN 6665cf231a3SGuenter Roeck | PMBUS_HAVE_STATUS_INPUT; 6675cf231a3SGuenter Roeck if (config & ADM1275_VIN_VOUT_SELECT) 6685cf231a3SGuenter Roeck info->func[0] |= 6695cf231a3SGuenter Roeck PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT; 6705cf231a3SGuenter Roeck break; 671709066acSGuenter Roeck case adm1278: 672709066acSGuenter Roeck data->have_vout = true; 673709066acSGuenter Roeck data->have_pin_max = true; 674709066acSGuenter Roeck data->have_temp_max = true; 6757d45deb3SGuenter Roeck data->have_power_sampling = true; 676709066acSGuenter Roeck 677709066acSGuenter Roeck coefficients = adm1278_coefficients; 678709066acSGuenter Roeck vindex = 0; 679709066acSGuenter Roeck cindex = 1; 680709066acSGuenter Roeck pindex = 2; 681709066acSGuenter Roeck tindex = 3; 682709066acSGuenter Roeck 6832b3d0c19SYi Li info->func[0] |= PMBUS_HAVE_PIN | PMBUS_HAVE_STATUS_INPUT | 684a37881deSManikandan Elumalai PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT | 685a37881deSManikandan Elumalai PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP; 6862b3d0c19SYi Li 687a37881deSManikandan Elumalai /* Enable VOUT & TEMP1 if not enabled (disabled by default) */ 688a37881deSManikandan Elumalai if ((config & (ADM1278_VOUT_EN | ADM1278_TEMP1_EN)) != 689a37881deSManikandan Elumalai (ADM1278_VOUT_EN | ADM1278_TEMP1_EN)) { 690a37881deSManikandan Elumalai config |= ADM1278_VOUT_EN | ADM1278_TEMP1_EN; 691*a3cd66d7SPotin Lai ret = i2c_smbus_write_word_data(client, 6922b3d0c19SYi Li ADM1275_PMON_CONFIG, 6932b3d0c19SYi Li config); 6942b3d0c19SYi Li if (ret < 0) { 6952b3d0c19SYi Li dev_err(&client->dev, 6962b3d0c19SYi Li "Failed to enable VOUT monitoring\n"); 6972b3d0c19SYi Li return -ENODEV; 6982b3d0c19SYi Li } 6992b3d0c19SYi Li } 7002b3d0c19SYi Li 701709066acSGuenter Roeck if (config & ADM1278_VIN_EN) 702709066acSGuenter Roeck info->func[0] |= PMBUS_HAVE_VIN; 703709066acSGuenter Roeck break; 70468a40382SGuenter Roeck case adm1293: 70568a40382SGuenter Roeck case adm1294: 70668a40382SGuenter Roeck data->have_iout_min = true; 70768a40382SGuenter Roeck data->have_pin_min = true; 70868a40382SGuenter Roeck data->have_pin_max = true; 70968a40382SGuenter Roeck data->have_mfr_vaux_status = true; 7107d45deb3SGuenter Roeck data->have_power_sampling = true; 71168a40382SGuenter Roeck 71268a40382SGuenter Roeck coefficients = adm1293_coefficients; 71368a40382SGuenter Roeck 71468a40382SGuenter Roeck voindex = 0; 71568a40382SGuenter Roeck switch (config & ADM1293_VIN_SEL_MASK) { 71668a40382SGuenter Roeck case ADM1293_VIN_SEL_012: /* 1.2V */ 71768a40382SGuenter Roeck vindex = 0; 71868a40382SGuenter Roeck break; 71968a40382SGuenter Roeck case ADM1293_VIN_SEL_074: /* 7.4V */ 72068a40382SGuenter Roeck vindex = 1; 72168a40382SGuenter Roeck break; 72268a40382SGuenter Roeck case ADM1293_VIN_SEL_210: /* 21V */ 72368a40382SGuenter Roeck vindex = 2; 72468a40382SGuenter Roeck break; 72568a40382SGuenter Roeck default: /* disabled */ 72668a40382SGuenter Roeck break; 72768a40382SGuenter Roeck } 72868a40382SGuenter Roeck 72968a40382SGuenter Roeck switch (config & ADM1293_IRANGE_MASK) { 73068a40382SGuenter Roeck case ADM1293_IRANGE_25: 73168a40382SGuenter Roeck cindex = 3; 73268a40382SGuenter Roeck break; 73368a40382SGuenter Roeck case ADM1293_IRANGE_50: 73468a40382SGuenter Roeck cindex = 4; 73568a40382SGuenter Roeck break; 73668a40382SGuenter Roeck case ADM1293_IRANGE_100: 73768a40382SGuenter Roeck cindex = 5; 73868a40382SGuenter Roeck break; 73968a40382SGuenter Roeck case ADM1293_IRANGE_200: 74068a40382SGuenter Roeck cindex = 6; 74168a40382SGuenter Roeck break; 74268a40382SGuenter Roeck } 74368a40382SGuenter Roeck 74468a40382SGuenter Roeck if (vindex >= 0) 74568a40382SGuenter Roeck pindex = 7 + vindex * 4 + (cindex - 3); 74668a40382SGuenter Roeck 74768a40382SGuenter Roeck if (config & ADM1293_VAUX_EN) 74868a40382SGuenter Roeck info->func[0] |= 74968a40382SGuenter Roeck PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT; 75068a40382SGuenter Roeck 75168a40382SGuenter Roeck info->func[0] |= PMBUS_HAVE_PIN | 75268a40382SGuenter Roeck PMBUS_HAVE_VIN | PMBUS_HAVE_STATUS_INPUT; 75368a40382SGuenter Roeck 75468a40382SGuenter Roeck break; 755904b296fSGuenter Roeck default: 756904b296fSGuenter Roeck dev_err(&client->dev, "Unsupported device\n"); 757904b296fSGuenter Roeck return -ENODEV; 758904b296fSGuenter Roeck } 75968a40382SGuenter Roeck 760*a3cd66d7SPotin Lai if (data->have_power_sampling && 761*a3cd66d7SPotin Lai of_property_read_u32(client->dev.of_node, 762*a3cd66d7SPotin Lai "adi,power-sample-average", &avg) == 0) { 763*a3cd66d7SPotin Lai if (!avg || avg > ADM1275_SAMPLES_AVG_MAX || 764*a3cd66d7SPotin Lai BIT(__fls(avg)) != avg) { 765*a3cd66d7SPotin Lai dev_err(&client->dev, 766*a3cd66d7SPotin Lai "Invalid number of power samples"); 767*a3cd66d7SPotin Lai return -EINVAL; 768*a3cd66d7SPotin Lai } 769*a3cd66d7SPotin Lai ret = adm1275_write_pmon_config(data, client, true, 770*a3cd66d7SPotin Lai ilog2(avg)); 771*a3cd66d7SPotin Lai if (ret < 0) { 772*a3cd66d7SPotin Lai dev_err(&client->dev, 773*a3cd66d7SPotin Lai "Setting power sample averaging failed with error %d", 774*a3cd66d7SPotin Lai ret); 775*a3cd66d7SPotin Lai return ret; 776*a3cd66d7SPotin Lai } 777*a3cd66d7SPotin Lai } 778*a3cd66d7SPotin Lai 779*a3cd66d7SPotin Lai if (of_property_read_u32(client->dev.of_node, 780*a3cd66d7SPotin Lai "adi,volt-curr-sample-average", &avg) == 0) { 781*a3cd66d7SPotin Lai if (!avg || avg > ADM1275_SAMPLES_AVG_MAX || 782*a3cd66d7SPotin Lai BIT(__fls(avg)) != avg) { 783*a3cd66d7SPotin Lai dev_err(&client->dev, 784*a3cd66d7SPotin Lai "Invalid number of voltage/current samples"); 785*a3cd66d7SPotin Lai return -EINVAL; 786*a3cd66d7SPotin Lai } 787*a3cd66d7SPotin Lai ret = adm1275_write_pmon_config(data, client, false, 788*a3cd66d7SPotin Lai ilog2(avg)); 789*a3cd66d7SPotin Lai if (ret < 0) { 790*a3cd66d7SPotin Lai dev_err(&client->dev, 791*a3cd66d7SPotin Lai "Setting voltage and current sample averaging failed with error %d", 792*a3cd66d7SPotin Lai ret); 793*a3cd66d7SPotin Lai return ret; 794*a3cd66d7SPotin Lai } 795*a3cd66d7SPotin Lai } 796*a3cd66d7SPotin Lai 79768a40382SGuenter Roeck if (voindex < 0) 79868a40382SGuenter Roeck voindex = vindex; 799904b296fSGuenter Roeck if (vindex >= 0) { 800904b296fSGuenter Roeck info->m[PSC_VOLTAGE_IN] = coefficients[vindex].m; 801904b296fSGuenter Roeck info->b[PSC_VOLTAGE_IN] = coefficients[vindex].b; 802904b296fSGuenter Roeck info->R[PSC_VOLTAGE_IN] = coefficients[vindex].R; 80368a40382SGuenter Roeck } 80468a40382SGuenter Roeck if (voindex >= 0) { 80568a40382SGuenter Roeck info->m[PSC_VOLTAGE_OUT] = coefficients[voindex].m; 80668a40382SGuenter Roeck info->b[PSC_VOLTAGE_OUT] = coefficients[voindex].b; 80768a40382SGuenter Roeck info->R[PSC_VOLTAGE_OUT] = coefficients[voindex].R; 808904b296fSGuenter Roeck } 809904b296fSGuenter Roeck if (cindex >= 0) { 8106e5c06adSKun Yi /* Scale current with sense resistor value */ 8116e5c06adSKun Yi info->m[PSC_CURRENT_OUT] = 8126e5c06adSKun Yi coefficients[cindex].m * shunt / 1000; 813904b296fSGuenter Roeck info->b[PSC_CURRENT_OUT] = coefficients[cindex].b; 814904b296fSGuenter Roeck info->R[PSC_CURRENT_OUT] = coefficients[cindex].R; 815904b296fSGuenter Roeck } 816904b296fSGuenter Roeck if (pindex >= 0) { 8176e5c06adSKun Yi info->m[PSC_POWER] = 8186e5c06adSKun Yi coefficients[pindex].m * shunt / 1000; 819904b296fSGuenter Roeck info->b[PSC_POWER] = coefficients[pindex].b; 820904b296fSGuenter Roeck info->R[PSC_POWER] = coefficients[pindex].R; 8215cf231a3SGuenter Roeck } 822709066acSGuenter Roeck if (tindex >= 0) { 823709066acSGuenter Roeck info->m[PSC_TEMPERATURE] = coefficients[tindex].m; 824709066acSGuenter Roeck info->b[PSC_TEMPERATURE] = coefficients[tindex].b; 825709066acSGuenter Roeck info->R[PSC_TEMPERATURE] = coefficients[tindex].R; 826709066acSGuenter Roeck } 8279d2ecfb7SGuenter Roeck 828dd431939SStephen Kitt return pmbus_do_probe(client, info); 8299d2ecfb7SGuenter Roeck } 8309d2ecfb7SGuenter Roeck 8319d2ecfb7SGuenter Roeck static struct i2c_driver adm1275_driver = { 8329d2ecfb7SGuenter Roeck .driver = { 8339d2ecfb7SGuenter Roeck .name = "adm1275", 8349d2ecfb7SGuenter Roeck }, 835dd431939SStephen Kitt .probe_new = adm1275_probe, 8369d2ecfb7SGuenter Roeck .id_table = adm1275_id, 8379d2ecfb7SGuenter Roeck }; 8389d2ecfb7SGuenter Roeck 839f0967eeaSAxel Lin module_i2c_driver(adm1275_driver); 8409d2ecfb7SGuenter Roeck 8419d2ecfb7SGuenter Roeck MODULE_AUTHOR("Guenter Roeck"); 8425cf231a3SGuenter Roeck MODULE_DESCRIPTION("PMBus driver for Analog Devices ADM1275 and compatibles"); 8439d2ecfb7SGuenter Roeck MODULE_LICENSE("GPL"); 844b94ca77eSGuenter Roeck MODULE_IMPORT_NS(PMBUS); 845