12c6fcbb2SVadim Pasternak // SPDX-License-Identifier: GPL-2.0-or-later 22c6fcbb2SVadim Pasternak /* 32c6fcbb2SVadim Pasternak * Hardware monitoring driver for MPS Multi-phase Digital VR Controllers 42c6fcbb2SVadim Pasternak * 52c6fcbb2SVadim Pasternak * Copyright (C) 2020 Nvidia Technologies Ltd. 62c6fcbb2SVadim Pasternak */ 72c6fcbb2SVadim Pasternak 82c6fcbb2SVadim Pasternak #include <linux/err.h> 92c6fcbb2SVadim Pasternak #include <linux/i2c.h> 102c6fcbb2SVadim Pasternak #include <linux/init.h> 112c6fcbb2SVadim Pasternak #include <linux/kernel.h> 122c6fcbb2SVadim Pasternak #include <linux/module.h> 131f6f34d0SPatrick Rudolph #include <linux/of_device.h> 142c6fcbb2SVadim Pasternak #include "pmbus.h" 152c6fcbb2SVadim Pasternak 162c6fcbb2SVadim Pasternak /* Vendor specific registers. */ 172c6fcbb2SVadim Pasternak #define MP2975_MFR_APS_HYS_R2 0x0d 182c6fcbb2SVadim Pasternak #define MP2975_MFR_SLOPE_TRIM3 0x1d 192c6fcbb2SVadim Pasternak #define MP2975_MFR_VR_MULTI_CONFIG_R1 0x0d 202c6fcbb2SVadim Pasternak #define MP2975_MFR_VR_MULTI_CONFIG_R2 0x1d 212c6fcbb2SVadim Pasternak #define MP2975_MFR_APS_DECAY_ADV 0x56 222c6fcbb2SVadim Pasternak #define MP2975_MFR_DC_LOOP_CTRL 0x59 232c6fcbb2SVadim Pasternak #define MP2975_MFR_OCP_UCP_PHASE_SET 0x65 242c6fcbb2SVadim Pasternak #define MP2975_MFR_VR_CONFIG1 0x68 252c6fcbb2SVadim Pasternak #define MP2975_MFR_READ_CS1_2 0x82 262c6fcbb2SVadim Pasternak #define MP2975_MFR_READ_CS3_4 0x83 272c6fcbb2SVadim Pasternak #define MP2975_MFR_READ_CS5_6 0x84 282c6fcbb2SVadim Pasternak #define MP2975_MFR_READ_CS7_8 0x85 292c6fcbb2SVadim Pasternak #define MP2975_MFR_READ_CS9_10 0x86 302c6fcbb2SVadim Pasternak #define MP2975_MFR_READ_CS11_12 0x87 312c6fcbb2SVadim Pasternak #define MP2975_MFR_READ_IOUT_PK 0x90 322c6fcbb2SVadim Pasternak #define MP2975_MFR_READ_POUT_PK 0x91 332c6fcbb2SVadim Pasternak #define MP2975_MFR_READ_VREF_R1 0xa1 342c6fcbb2SVadim Pasternak #define MP2975_MFR_READ_VREF_R2 0xa3 352c6fcbb2SVadim Pasternak #define MP2975_MFR_OVP_TH_SET 0xe5 362c6fcbb2SVadim Pasternak #define MP2975_MFR_UVP_SET 0xe6 372c6fcbb2SVadim Pasternak 385239277eSPatrick Rudolph #define MP2973_MFR_RESO_SET 0xc7 395239277eSPatrick Rudolph 402c6fcbb2SVadim Pasternak #define MP2975_VOUT_FORMAT BIT(15) 412c6fcbb2SVadim Pasternak #define MP2975_VID_STEP_SEL_R1 BIT(4) 422c6fcbb2SVadim Pasternak #define MP2975_IMVP9_EN_R1 BIT(13) 432c6fcbb2SVadim Pasternak #define MP2975_VID_STEP_SEL_R2 BIT(3) 442c6fcbb2SVadim Pasternak #define MP2975_IMVP9_EN_R2 BIT(12) 452c6fcbb2SVadim Pasternak #define MP2975_PRT_THRES_DIV_OV_EN BIT(14) 462c6fcbb2SVadim Pasternak #define MP2975_DRMOS_KCS GENMASK(13, 12) 472c6fcbb2SVadim Pasternak #define MP2975_PROT_DEV_OV_OFF 10 482c6fcbb2SVadim Pasternak #define MP2975_PROT_DEV_OV_ON 5 492c6fcbb2SVadim Pasternak #define MP2975_SENSE_AMPL BIT(11) 502c6fcbb2SVadim Pasternak #define MP2975_SENSE_AMPL_UNIT 1 512c6fcbb2SVadim Pasternak #define MP2975_SENSE_AMPL_HALF 2 522c6fcbb2SVadim Pasternak #define MP2975_VIN_UV_LIMIT_UNIT 8 532c6fcbb2SVadim Pasternak 545239277eSPatrick Rudolph #define MP2973_VOUT_FORMAT_R1 GENMASK(7, 6) 555239277eSPatrick Rudolph #define MP2973_VOUT_FORMAT_R2 GENMASK(4, 3) 565239277eSPatrick Rudolph #define MP2973_VOUT_FORMAT_DIRECT_R1 BIT(7) 575239277eSPatrick Rudolph #define MP2973_VOUT_FORMAT_LINEAR_R1 BIT(6) 585239277eSPatrick Rudolph #define MP2973_VOUT_FORMAT_DIRECT_R2 BIT(4) 595239277eSPatrick Rudolph #define MP2973_VOUT_FORMAT_LINEAR_R2 BIT(3) 605239277eSPatrick Rudolph 615239277eSPatrick Rudolph #define MP2973_MFR_VR_MULTI_CONFIG_R1 0x0d 625239277eSPatrick Rudolph #define MP2973_MFR_VR_MULTI_CONFIG_R2 0x1d 635239277eSPatrick Rudolph #define MP2973_VID_STEP_SEL_R1 BIT(4) 645239277eSPatrick Rudolph #define MP2973_IMVP9_EN_R1 BIT(14) 655239277eSPatrick Rudolph #define MP2973_VID_STEP_SEL_R2 BIT(3) 665239277eSPatrick Rudolph #define MP2973_IMVP9_EN_R2 BIT(13) 675239277eSPatrick Rudolph 6845f154dcSPatrick Rudolph #define MP2973_MFR_OCP_TOTAL_SET 0x5f 6945f154dcSPatrick Rudolph #define MP2973_OCP_TOTAL_CUR_MASK GENMASK(6, 0) 7045f154dcSPatrick Rudolph #define MP2973_MFR_OCP_LEVEL_RES BIT(15) 7145f154dcSPatrick Rudolph 725239277eSPatrick Rudolph #define MP2973_MFR_READ_IOUT_PK 0x90 735239277eSPatrick Rudolph #define MP2973_MFR_READ_POUT_PK 0x91 745239277eSPatrick Rudolph 752c6fcbb2SVadim Pasternak #define MP2975_MAX_PHASE_RAIL1 8 762c6fcbb2SVadim Pasternak #define MP2975_MAX_PHASE_RAIL2 4 775239277eSPatrick Rudolph 785239277eSPatrick Rudolph #define MP2973_MAX_PHASE_RAIL1 14 795239277eSPatrick Rudolph #define MP2973_MAX_PHASE_RAIL2 6 805239277eSPatrick Rudolph 815239277eSPatrick Rudolph #define MP2971_MAX_PHASE_RAIL1 8 825239277eSPatrick Rudolph #define MP2971_MAX_PHASE_RAIL2 3 835239277eSPatrick Rudolph 842c6fcbb2SVadim Pasternak #define MP2975_PAGE_NUM 2 852c6fcbb2SVadim Pasternak 862c6fcbb2SVadim Pasternak #define MP2975_RAIL2_FUNC (PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT | \ 872c6fcbb2SVadim Pasternak PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT | \ 882292e2f6SVadim Pasternak PMBUS_HAVE_POUT | PMBUS_PHASE_VIRTUAL) 892c6fcbb2SVadim Pasternak 901f6f34d0SPatrick Rudolph enum chips { 915239277eSPatrick Rudolph mp2971, mp2973, mp2975 921f6f34d0SPatrick Rudolph }; 931f6f34d0SPatrick Rudolph 94e2c90b48SPatrick Rudolph static const int mp2975_max_phases[][MP2975_PAGE_NUM] = { 95e2c90b48SPatrick Rudolph [mp2975] = { MP2975_MAX_PHASE_RAIL1, MP2975_MAX_PHASE_RAIL2 }, 965239277eSPatrick Rudolph [mp2973] = { MP2973_MAX_PHASE_RAIL1, MP2973_MAX_PHASE_RAIL2 }, 975239277eSPatrick Rudolph [mp2971] = { MP2971_MAX_PHASE_RAIL1, MP2971_MAX_PHASE_RAIL2 }, 98e2c90b48SPatrick Rudolph }; 99e2c90b48SPatrick Rudolph 1002c6fcbb2SVadim Pasternak struct mp2975_data { 1012c6fcbb2SVadim Pasternak struct pmbus_driver_info info; 1021f6f34d0SPatrick Rudolph enum chips chip_id; 1032c6fcbb2SVadim Pasternak int vout_scale; 104e2c90b48SPatrick Rudolph int max_phases[MP2975_PAGE_NUM]; 1052c6fcbb2SVadim Pasternak int vid_step[MP2975_PAGE_NUM]; 1062c6fcbb2SVadim Pasternak int vref[MP2975_PAGE_NUM]; 1072c6fcbb2SVadim Pasternak int vref_off[MP2975_PAGE_NUM]; 1082c6fcbb2SVadim Pasternak int vout_max[MP2975_PAGE_NUM]; 1092c6fcbb2SVadim Pasternak int vout_ov_fixed[MP2975_PAGE_NUM]; 1102c6fcbb2SVadim Pasternak int curr_sense_gain[MP2975_PAGE_NUM]; 1112c6fcbb2SVadim Pasternak }; 1122c6fcbb2SVadim Pasternak 1131f6f34d0SPatrick Rudolph static const struct i2c_device_id mp2975_id[] = { 1145239277eSPatrick Rudolph {"mp2971", mp2971}, 1155239277eSPatrick Rudolph {"mp2973", mp2973}, 1161f6f34d0SPatrick Rudolph {"mp2975", mp2975}, 1171f6f34d0SPatrick Rudolph {} 1181f6f34d0SPatrick Rudolph }; 1191f6f34d0SPatrick Rudolph 1201f6f34d0SPatrick Rudolph MODULE_DEVICE_TABLE(i2c, mp2975_id); 1211f6f34d0SPatrick Rudolph 12288fc1efcSPatrick Rudolph static const struct regulator_desc __maybe_unused mp2975_reg_desc[] = { 12388fc1efcSPatrick Rudolph PMBUS_REGULATOR("vout", 0), 12488fc1efcSPatrick Rudolph PMBUS_REGULATOR("vout", 1), 12588fc1efcSPatrick Rudolph }; 12688fc1efcSPatrick Rudolph 1272c6fcbb2SVadim Pasternak #define to_mp2975_data(x) container_of(x, struct mp2975_data, info) 1282c6fcbb2SVadim Pasternak 129c60fe56cSKonstantin Aladyshev static int mp2975_read_byte_data(struct i2c_client *client, int page, int reg) 130c60fe56cSKonstantin Aladyshev { 131c60fe56cSKonstantin Aladyshev switch (reg) { 132c60fe56cSKonstantin Aladyshev case PMBUS_VOUT_MODE: 133c60fe56cSKonstantin Aladyshev /* 13491564418SKonstantin Aladyshev * Report direct format as configured by MFR_DC_LOOP_CTRL. 13591564418SKonstantin Aladyshev * Unlike on MP2971/MP2973 the reported VOUT_MODE isn't automatically 13691564418SKonstantin Aladyshev * internally updated, but always reads as PB_VOUT_MODE_VID. 137c60fe56cSKonstantin Aladyshev */ 138c60fe56cSKonstantin Aladyshev return PB_VOUT_MODE_DIRECT; 139c60fe56cSKonstantin Aladyshev default: 140c60fe56cSKonstantin Aladyshev return -ENODATA; 141c60fe56cSKonstantin Aladyshev } 142c60fe56cSKonstantin Aladyshev } 143c60fe56cSKonstantin Aladyshev 1442c6fcbb2SVadim Pasternak static int 1452c6fcbb2SVadim Pasternak mp2975_read_word_helper(struct i2c_client *client, int page, int phase, u8 reg, 1462c6fcbb2SVadim Pasternak u16 mask) 1472c6fcbb2SVadim Pasternak { 1482c6fcbb2SVadim Pasternak int ret = pmbus_read_word_data(client, page, phase, reg); 1492c6fcbb2SVadim Pasternak 1502c6fcbb2SVadim Pasternak return (ret > 0) ? ret & mask : ret; 1512c6fcbb2SVadim Pasternak } 1522c6fcbb2SVadim Pasternak 1532c6fcbb2SVadim Pasternak static int 1542c6fcbb2SVadim Pasternak mp2975_vid2direct(int vrf, int val) 1552c6fcbb2SVadim Pasternak { 1562c6fcbb2SVadim Pasternak switch (vrf) { 1572c6fcbb2SVadim Pasternak case vr12: 1582c6fcbb2SVadim Pasternak if (val >= 0x01) 1592c6fcbb2SVadim Pasternak return 250 + (val - 1) * 5; 1602c6fcbb2SVadim Pasternak break; 1612c6fcbb2SVadim Pasternak case vr13: 1622c6fcbb2SVadim Pasternak if (val >= 0x01) 1632c6fcbb2SVadim Pasternak return 500 + (val - 1) * 10; 1642c6fcbb2SVadim Pasternak break; 1652c6fcbb2SVadim Pasternak case imvp9: 1662c6fcbb2SVadim Pasternak if (val >= 0x01) 1672c6fcbb2SVadim Pasternak return 200 + (val - 1) * 10; 1682c6fcbb2SVadim Pasternak break; 1692c6fcbb2SVadim Pasternak default: 1702c6fcbb2SVadim Pasternak return -EINVAL; 1712c6fcbb2SVadim Pasternak } 1722c6fcbb2SVadim Pasternak return 0; 1732c6fcbb2SVadim Pasternak } 1742c6fcbb2SVadim Pasternak 17545f154dcSPatrick Rudolph #define MAX_LIN_MANTISSA (1023 * 1000) 17645f154dcSPatrick Rudolph #define MIN_LIN_MANTISSA (511 * 1000) 17745f154dcSPatrick Rudolph 17845f154dcSPatrick Rudolph /* Converts a milli-unit DIRECT value to LINEAR11 format */ 17945f154dcSPatrick Rudolph static u16 mp2975_data2reg_linear11(s64 val) 18045f154dcSPatrick Rudolph { 18145f154dcSPatrick Rudolph s16 exponent = 0, mantissa; 18245f154dcSPatrick Rudolph bool negative = false; 18345f154dcSPatrick Rudolph 18445f154dcSPatrick Rudolph /* simple case */ 18545f154dcSPatrick Rudolph if (val == 0) 18645f154dcSPatrick Rudolph return 0; 18745f154dcSPatrick Rudolph 18845f154dcSPatrick Rudolph /* Reduce large mantissa until it fits into 10 bit */ 18945f154dcSPatrick Rudolph while (val >= MAX_LIN_MANTISSA && exponent < 15) { 19045f154dcSPatrick Rudolph exponent++; 19145f154dcSPatrick Rudolph val >>= 1; 19245f154dcSPatrick Rudolph } 19345f154dcSPatrick Rudolph /* Increase small mantissa to improve precision */ 19445f154dcSPatrick Rudolph while (val < MIN_LIN_MANTISSA && exponent > -15) { 19545f154dcSPatrick Rudolph exponent--; 19645f154dcSPatrick Rudolph val <<= 1; 19745f154dcSPatrick Rudolph } 19845f154dcSPatrick Rudolph 19945f154dcSPatrick Rudolph /* Convert mantissa from milli-units to units */ 20045f154dcSPatrick Rudolph mantissa = clamp_val(DIV_ROUND_CLOSEST_ULL(val, 1000), 0, 0x3ff); 20145f154dcSPatrick Rudolph 20245f154dcSPatrick Rudolph /* restore sign */ 20345f154dcSPatrick Rudolph if (negative) 20445f154dcSPatrick Rudolph mantissa = -mantissa; 20545f154dcSPatrick Rudolph 20645f154dcSPatrick Rudolph /* Convert to 5 bit exponent, 11 bit mantissa */ 20745f154dcSPatrick Rudolph return (mantissa & 0x7ff) | ((exponent << 11) & 0xf800); 20845f154dcSPatrick Rudolph } 20945f154dcSPatrick Rudolph 2102c6fcbb2SVadim Pasternak static int 2112c6fcbb2SVadim Pasternak mp2975_read_phase(struct i2c_client *client, struct mp2975_data *data, 2122c6fcbb2SVadim Pasternak int page, int phase, u8 reg) 2132c6fcbb2SVadim Pasternak { 2142c6fcbb2SVadim Pasternak int ph_curr, ret; 2152c6fcbb2SVadim Pasternak 2162c6fcbb2SVadim Pasternak ret = pmbus_read_word_data(client, page, phase, reg); 2172c6fcbb2SVadim Pasternak if (ret < 0) 2182c6fcbb2SVadim Pasternak return ret; 2192c6fcbb2SVadim Pasternak 2202c6fcbb2SVadim Pasternak if (!((phase + 1) % MP2975_PAGE_NUM)) 2212c6fcbb2SVadim Pasternak ret >>= 8; 2222c6fcbb2SVadim Pasternak ret &= 0xff; 2232c6fcbb2SVadim Pasternak 2242c6fcbb2SVadim Pasternak /* 2252c6fcbb2SVadim Pasternak * Output value is calculated as: (READ_CSx / 80 – 1.23) / (Kcs * Rcs) 2262c6fcbb2SVadim Pasternak * where: 2272c6fcbb2SVadim Pasternak * - Kcs is the DrMOS current sense gain of power stage, which is 2282c6fcbb2SVadim Pasternak * obtained from the register MP2975_MFR_VR_CONFIG1, bits 13-12 with 2292c6fcbb2SVadim Pasternak * the following selection of DrMOS (data->curr_sense_gain[page]): 2302c6fcbb2SVadim Pasternak * 00b - 5µA/A, 01b - 8.5µA/A, 10b - 9.7µA/A, 11b - 10µA/A. 2312c6fcbb2SVadim Pasternak * - Rcs is the internal phase current sense resistor which is constant 2322c6fcbb2SVadim Pasternak * value 1kΩ. 2332c6fcbb2SVadim Pasternak */ 2342c6fcbb2SVadim Pasternak ph_curr = ret * 100 - 9800; 2352c6fcbb2SVadim Pasternak 2362c6fcbb2SVadim Pasternak /* 2372c6fcbb2SVadim Pasternak * Current phase sensing, providing by the device is not accurate 2382c6fcbb2SVadim Pasternak * for the light load. This because sampling of current occurrence of 2392c6fcbb2SVadim Pasternak * bit weight has a big deviation for light load. For handling such 2402c6fcbb2SVadim Pasternak * case phase current is represented as the maximum between the value 2412c6fcbb2SVadim Pasternak * calculated above and total rail current divided by number phases. 2422c6fcbb2SVadim Pasternak */ 2432c6fcbb2SVadim Pasternak ret = pmbus_read_word_data(client, page, phase, PMBUS_READ_IOUT); 2442c6fcbb2SVadim Pasternak if (ret < 0) 2452c6fcbb2SVadim Pasternak return ret; 2462c6fcbb2SVadim Pasternak 2472c6fcbb2SVadim Pasternak return max_t(int, DIV_ROUND_CLOSEST(ret, data->info.phases[page]), 2482c6fcbb2SVadim Pasternak DIV_ROUND_CLOSEST(ph_curr, data->curr_sense_gain[page])); 2492c6fcbb2SVadim Pasternak } 2502c6fcbb2SVadim Pasternak 2512c6fcbb2SVadim Pasternak static int 2522c6fcbb2SVadim Pasternak mp2975_read_phases(struct i2c_client *client, struct mp2975_data *data, 2532c6fcbb2SVadim Pasternak int page, int phase) 2542c6fcbb2SVadim Pasternak { 2552c6fcbb2SVadim Pasternak int ret; 2562c6fcbb2SVadim Pasternak 2572c6fcbb2SVadim Pasternak if (page) { 2582c6fcbb2SVadim Pasternak switch (phase) { 2592c6fcbb2SVadim Pasternak case 0 ... 1: 2602c6fcbb2SVadim Pasternak ret = mp2975_read_phase(client, data, page, phase, 2612c6fcbb2SVadim Pasternak MP2975_MFR_READ_CS7_8); 2622c6fcbb2SVadim Pasternak break; 2632c6fcbb2SVadim Pasternak case 2 ... 3: 2642c6fcbb2SVadim Pasternak ret = mp2975_read_phase(client, data, page, phase, 2652c6fcbb2SVadim Pasternak MP2975_MFR_READ_CS9_10); 2662c6fcbb2SVadim Pasternak break; 2672c6fcbb2SVadim Pasternak case 4 ... 5: 2682c6fcbb2SVadim Pasternak ret = mp2975_read_phase(client, data, page, phase, 2692c6fcbb2SVadim Pasternak MP2975_MFR_READ_CS11_12); 2702c6fcbb2SVadim Pasternak break; 2712c6fcbb2SVadim Pasternak default: 2722c6fcbb2SVadim Pasternak return -ENODATA; 2732c6fcbb2SVadim Pasternak } 2742c6fcbb2SVadim Pasternak } else { 2752c6fcbb2SVadim Pasternak switch (phase) { 2762c6fcbb2SVadim Pasternak case 0 ... 1: 2772c6fcbb2SVadim Pasternak ret = mp2975_read_phase(client, data, page, phase, 2782c6fcbb2SVadim Pasternak MP2975_MFR_READ_CS1_2); 2792c6fcbb2SVadim Pasternak break; 2802c6fcbb2SVadim Pasternak case 2 ... 3: 2812c6fcbb2SVadim Pasternak ret = mp2975_read_phase(client, data, page, phase, 2822c6fcbb2SVadim Pasternak MP2975_MFR_READ_CS3_4); 2832c6fcbb2SVadim Pasternak break; 2842c6fcbb2SVadim Pasternak case 4 ... 5: 2852c6fcbb2SVadim Pasternak ret = mp2975_read_phase(client, data, page, phase, 2862c6fcbb2SVadim Pasternak MP2975_MFR_READ_CS5_6); 2872c6fcbb2SVadim Pasternak break; 2882c6fcbb2SVadim Pasternak case 6 ... 7: 2892c6fcbb2SVadim Pasternak ret = mp2975_read_phase(client, data, page, phase, 2902c6fcbb2SVadim Pasternak MP2975_MFR_READ_CS7_8); 2912c6fcbb2SVadim Pasternak break; 2922c6fcbb2SVadim Pasternak case 8 ... 9: 2932c6fcbb2SVadim Pasternak ret = mp2975_read_phase(client, data, page, phase, 2942c6fcbb2SVadim Pasternak MP2975_MFR_READ_CS9_10); 2952c6fcbb2SVadim Pasternak break; 2962c6fcbb2SVadim Pasternak case 10 ... 11: 2972c6fcbb2SVadim Pasternak ret = mp2975_read_phase(client, data, page, phase, 2982c6fcbb2SVadim Pasternak MP2975_MFR_READ_CS11_12); 2992c6fcbb2SVadim Pasternak break; 3002c6fcbb2SVadim Pasternak default: 3012c6fcbb2SVadim Pasternak return -ENODATA; 3022c6fcbb2SVadim Pasternak } 3032c6fcbb2SVadim Pasternak } 3042c6fcbb2SVadim Pasternak return ret; 3052c6fcbb2SVadim Pasternak } 3062c6fcbb2SVadim Pasternak 3075239277eSPatrick Rudolph static int mp2973_read_word_data(struct i2c_client *client, int page, 3085239277eSPatrick Rudolph int phase, int reg) 3095239277eSPatrick Rudolph { 3105239277eSPatrick Rudolph const struct pmbus_driver_info *info = pmbus_get_driver_info(client); 3115239277eSPatrick Rudolph struct mp2975_data *data = to_mp2975_data(info); 3125239277eSPatrick Rudolph int ret; 3135239277eSPatrick Rudolph 3145239277eSPatrick Rudolph switch (reg) { 3159da2901cSNaresh Solanki case PMBUS_STATUS_WORD: 3169da2901cSNaresh Solanki /* MP2973 & MP2971 return PGOOD instead of PB_STATUS_POWER_GOOD_N. */ 3179da2901cSNaresh Solanki ret = pmbus_read_word_data(client, page, phase, reg); 3189da2901cSNaresh Solanki ret ^= PB_STATUS_POWER_GOOD_N; 3199da2901cSNaresh Solanki break; 3205239277eSPatrick Rudolph case PMBUS_OT_FAULT_LIMIT: 3215239277eSPatrick Rudolph ret = mp2975_read_word_helper(client, page, phase, reg, 3225239277eSPatrick Rudolph GENMASK(7, 0)); 3235239277eSPatrick Rudolph break; 3245239277eSPatrick Rudolph case PMBUS_VIN_OV_FAULT_LIMIT: 3255239277eSPatrick Rudolph ret = mp2975_read_word_helper(client, page, phase, reg, 3265239277eSPatrick Rudolph GENMASK(7, 0)); 3275239277eSPatrick Rudolph if (ret < 0) 3285239277eSPatrick Rudolph return ret; 3295239277eSPatrick Rudolph 3305239277eSPatrick Rudolph ret = DIV_ROUND_CLOSEST(ret, MP2975_VIN_UV_LIMIT_UNIT); 3315239277eSPatrick Rudolph break; 3325239277eSPatrick Rudolph case PMBUS_VOUT_OV_FAULT_LIMIT: 3335239277eSPatrick Rudolph /* 3345239277eSPatrick Rudolph * MP2971 and mp2973 only supports tracking (ovp1) mode. 3355239277eSPatrick Rudolph */ 3365239277eSPatrick Rudolph ret = mp2975_read_word_helper(client, page, phase, 3375239277eSPatrick Rudolph MP2975_MFR_OVP_TH_SET, 3385239277eSPatrick Rudolph GENMASK(2, 0)); 3395239277eSPatrick Rudolph if (ret < 0) 3405239277eSPatrick Rudolph return ret; 3415239277eSPatrick Rudolph 3425239277eSPatrick Rudolph ret = data->vout_max[page] + 50 * (ret + 1); 3435239277eSPatrick Rudolph break; 3445239277eSPatrick Rudolph case PMBUS_VOUT_UV_FAULT_LIMIT: 3455239277eSPatrick Rudolph ret = mp2975_read_word_helper(client, page, phase, reg, 3465239277eSPatrick Rudolph GENMASK(8, 0)); 3475239277eSPatrick Rudolph if (ret < 0) 3485239277eSPatrick Rudolph return ret; 3495239277eSPatrick Rudolph ret = mp2975_vid2direct(info->vrm_version[page], ret); 3505239277eSPatrick Rudolph break; 3515239277eSPatrick Rudolph case PMBUS_VIRT_READ_POUT_MAX: 3525239277eSPatrick Rudolph ret = pmbus_read_word_data(client, page, phase, 3535239277eSPatrick Rudolph MP2973_MFR_READ_POUT_PK); 3545239277eSPatrick Rudolph break; 3555239277eSPatrick Rudolph case PMBUS_VIRT_READ_IOUT_MAX: 3565239277eSPatrick Rudolph ret = pmbus_read_word_data(client, page, phase, 3575239277eSPatrick Rudolph MP2973_MFR_READ_IOUT_PK); 3585239277eSPatrick Rudolph break; 35945f154dcSPatrick Rudolph case PMBUS_IOUT_OC_FAULT_LIMIT: 36045f154dcSPatrick Rudolph ret = mp2975_read_word_helper(client, page, phase, 36145f154dcSPatrick Rudolph MP2973_MFR_OCP_TOTAL_SET, 36245f154dcSPatrick Rudolph GENMASK(15, 0)); 36345f154dcSPatrick Rudolph if (ret < 0) 36445f154dcSPatrick Rudolph return ret; 36545f154dcSPatrick Rudolph 36645f154dcSPatrick Rudolph if (ret & MP2973_MFR_OCP_LEVEL_RES) 36745f154dcSPatrick Rudolph ret = 2 * (ret & MP2973_OCP_TOTAL_CUR_MASK); 36845f154dcSPatrick Rudolph else 36945f154dcSPatrick Rudolph ret = ret & MP2973_OCP_TOTAL_CUR_MASK; 37045f154dcSPatrick Rudolph 37145f154dcSPatrick Rudolph ret = mp2975_data2reg_linear11(ret * info->phases[page] * 1000); 37245f154dcSPatrick Rudolph break; 3735239277eSPatrick Rudolph case PMBUS_UT_WARN_LIMIT: 3745239277eSPatrick Rudolph case PMBUS_UT_FAULT_LIMIT: 3755239277eSPatrick Rudolph case PMBUS_VIN_UV_WARN_LIMIT: 3765239277eSPatrick Rudolph case PMBUS_VIN_UV_FAULT_LIMIT: 3775239277eSPatrick Rudolph case PMBUS_VOUT_UV_WARN_LIMIT: 3785239277eSPatrick Rudolph case PMBUS_VOUT_OV_WARN_LIMIT: 3795239277eSPatrick Rudolph case PMBUS_VIN_OV_WARN_LIMIT: 3805239277eSPatrick Rudolph case PMBUS_IIN_OC_FAULT_LIMIT: 3815239277eSPatrick Rudolph case PMBUS_IOUT_OC_LV_FAULT_LIMIT: 3825239277eSPatrick Rudolph case PMBUS_IOUT_OC_WARN_LIMIT: 3835239277eSPatrick Rudolph case PMBUS_IOUT_UC_FAULT_LIMIT: 3845239277eSPatrick Rudolph case PMBUS_POUT_OP_FAULT_LIMIT: 3855239277eSPatrick Rudolph case PMBUS_POUT_OP_WARN_LIMIT: 3865239277eSPatrick Rudolph case PMBUS_PIN_OP_WARN_LIMIT: 3875239277eSPatrick Rudolph return -ENXIO; 3885239277eSPatrick Rudolph default: 3895239277eSPatrick Rudolph return -ENODATA; 3905239277eSPatrick Rudolph } 3915239277eSPatrick Rudolph 3925239277eSPatrick Rudolph return ret; 3935239277eSPatrick Rudolph } 3945239277eSPatrick Rudolph 395*c7506a2bSPatrick Rudolph static int mp2973_write_word_data(struct i2c_client *client, int page, 396*c7506a2bSPatrick Rudolph int reg, u16 word) 397*c7506a2bSPatrick Rudolph { 398*c7506a2bSPatrick Rudolph u8 target, mask; 399*c7506a2bSPatrick Rudolph int ret; 400*c7506a2bSPatrick Rudolph 401*c7506a2bSPatrick Rudolph if (reg != PMBUS_SMBALERT_MASK) 402*c7506a2bSPatrick Rudolph return -ENODATA; 403*c7506a2bSPatrick Rudolph 404*c7506a2bSPatrick Rudolph /* 405*c7506a2bSPatrick Rudolph * Vendor-specific SMBALERT_MASK register with 16 maskable bits. 406*c7506a2bSPatrick Rudolph */ 407*c7506a2bSPatrick Rudolph ret = pmbus_read_word_data(client, 0, 0, PMBUS_SMBALERT_MASK); 408*c7506a2bSPatrick Rudolph if (ret < 0) 409*c7506a2bSPatrick Rudolph return ret; 410*c7506a2bSPatrick Rudolph 411*c7506a2bSPatrick Rudolph target = word & 0xff; 412*c7506a2bSPatrick Rudolph mask = word >> 8; 413*c7506a2bSPatrick Rudolph 414*c7506a2bSPatrick Rudolph /* 415*c7506a2bSPatrick Rudolph * Set/Clear 'bit' in 'ret' based on condition followed by define for each bit in SMBALERT_MASK. 416*c7506a2bSPatrick Rudolph * Also bit 2 & 15 are reserved. 417*c7506a2bSPatrick Rudolph */ 418*c7506a2bSPatrick Rudolph #define SWAP(val, mask, cond, bit) (((mask) & (cond)) ? ((val) & ~BIT(bit)) : ((val) | BIT(bit))) 419*c7506a2bSPatrick Rudolph 420*c7506a2bSPatrick Rudolph #define MP2973_TEMP_OT 0 421*c7506a2bSPatrick Rudolph #define MP2973_VIN_UVLO 1 422*c7506a2bSPatrick Rudolph #define MP2973_VIN_OVP 3 423*c7506a2bSPatrick Rudolph #define MP2973_MTP_FAULT 4 424*c7506a2bSPatrick Rudolph #define MP2973_OTHER_COMM 5 425*c7506a2bSPatrick Rudolph #define MP2973_MTP_BLK_TRIG 6 426*c7506a2bSPatrick Rudolph #define MP2973_PACKET_ERROR 7 427*c7506a2bSPatrick Rudolph #define MP2973_INVALID_DATA 8 428*c7506a2bSPatrick Rudolph #define MP2973_INVALID_COMMAND 9 429*c7506a2bSPatrick Rudolph #define MP2973_IOUT_OC_LV 10 430*c7506a2bSPatrick Rudolph #define MP2973_IOUT_OC 11 431*c7506a2bSPatrick Rudolph #define MP2973_VOUT_MAX_MIN_WARNING 12 432*c7506a2bSPatrick Rudolph #define MP2973_VOLTAGE_UV 13 433*c7506a2bSPatrick Rudolph #define MP2973_VOLTAGE_OV 14 434*c7506a2bSPatrick Rudolph 435*c7506a2bSPatrick Rudolph switch (target) { 436*c7506a2bSPatrick Rudolph case PMBUS_STATUS_CML: 437*c7506a2bSPatrick Rudolph ret = SWAP(ret, mask, PB_CML_FAULT_INVALID_DATA, MP2973_INVALID_DATA); 438*c7506a2bSPatrick Rudolph ret = SWAP(ret, mask, PB_CML_FAULT_INVALID_COMMAND, MP2973_INVALID_COMMAND); 439*c7506a2bSPatrick Rudolph ret = SWAP(ret, mask, PB_CML_FAULT_OTHER_COMM, MP2973_OTHER_COMM); 440*c7506a2bSPatrick Rudolph ret = SWAP(ret, mask, PB_CML_FAULT_PACKET_ERROR, MP2973_PACKET_ERROR); 441*c7506a2bSPatrick Rudolph break; 442*c7506a2bSPatrick Rudolph case PMBUS_STATUS_VOUT: 443*c7506a2bSPatrick Rudolph ret = SWAP(ret, mask, PB_VOLTAGE_UV_FAULT, MP2973_VOLTAGE_UV); 444*c7506a2bSPatrick Rudolph ret = SWAP(ret, mask, PB_VOLTAGE_OV_FAULT, MP2973_VOLTAGE_OV); 445*c7506a2bSPatrick Rudolph break; 446*c7506a2bSPatrick Rudolph case PMBUS_STATUS_IOUT: 447*c7506a2bSPatrick Rudolph ret = SWAP(ret, mask, PB_IOUT_OC_FAULT, MP2973_IOUT_OC); 448*c7506a2bSPatrick Rudolph ret = SWAP(ret, mask, PB_IOUT_OC_LV_FAULT, MP2973_IOUT_OC_LV); 449*c7506a2bSPatrick Rudolph break; 450*c7506a2bSPatrick Rudolph case PMBUS_STATUS_TEMPERATURE: 451*c7506a2bSPatrick Rudolph ret = SWAP(ret, mask, PB_TEMP_OT_FAULT, MP2973_TEMP_OT); 452*c7506a2bSPatrick Rudolph break; 453*c7506a2bSPatrick Rudolph /* 454*c7506a2bSPatrick Rudolph * Map remaining bits to MFR specific to let the PMBUS core mask 455*c7506a2bSPatrick Rudolph * those bits by default. 456*c7506a2bSPatrick Rudolph */ 457*c7506a2bSPatrick Rudolph case PMBUS_STATUS_MFR_SPECIFIC: 458*c7506a2bSPatrick Rudolph ret = SWAP(ret, mask, BIT(1), MP2973_VIN_UVLO); 459*c7506a2bSPatrick Rudolph ret = SWAP(ret, mask, BIT(3), MP2973_VIN_OVP); 460*c7506a2bSPatrick Rudolph ret = SWAP(ret, mask, BIT(4), MP2973_MTP_FAULT); 461*c7506a2bSPatrick Rudolph ret = SWAP(ret, mask, BIT(6), MP2973_MTP_BLK_TRIG); 462*c7506a2bSPatrick Rudolph break; 463*c7506a2bSPatrick Rudolph default: 464*c7506a2bSPatrick Rudolph return 0; 465*c7506a2bSPatrick Rudolph } 466*c7506a2bSPatrick Rudolph #undef SWAP 467*c7506a2bSPatrick Rudolph 468*c7506a2bSPatrick Rudolph return pmbus_write_word_data(client, 0, PMBUS_SMBALERT_MASK, ret); 469*c7506a2bSPatrick Rudolph } 470*c7506a2bSPatrick Rudolph 4712c6fcbb2SVadim Pasternak static int mp2975_read_word_data(struct i2c_client *client, int page, 4722c6fcbb2SVadim Pasternak int phase, int reg) 4732c6fcbb2SVadim Pasternak { 4742c6fcbb2SVadim Pasternak const struct pmbus_driver_info *info = pmbus_get_driver_info(client); 4752c6fcbb2SVadim Pasternak struct mp2975_data *data = to_mp2975_data(info); 4762c6fcbb2SVadim Pasternak int ret; 4772c6fcbb2SVadim Pasternak 4782c6fcbb2SVadim Pasternak switch (reg) { 4792c6fcbb2SVadim Pasternak case PMBUS_OT_FAULT_LIMIT: 4802c6fcbb2SVadim Pasternak ret = mp2975_read_word_helper(client, page, phase, reg, 4812c6fcbb2SVadim Pasternak GENMASK(7, 0)); 4822c6fcbb2SVadim Pasternak break; 4832c6fcbb2SVadim Pasternak case PMBUS_VIN_OV_FAULT_LIMIT: 4842c6fcbb2SVadim Pasternak ret = mp2975_read_word_helper(client, page, phase, reg, 4852c6fcbb2SVadim Pasternak GENMASK(7, 0)); 4862c6fcbb2SVadim Pasternak if (ret < 0) 4872c6fcbb2SVadim Pasternak return ret; 4882c6fcbb2SVadim Pasternak 4892c6fcbb2SVadim Pasternak ret = DIV_ROUND_CLOSEST(ret, MP2975_VIN_UV_LIMIT_UNIT); 4902c6fcbb2SVadim Pasternak break; 4912c6fcbb2SVadim Pasternak case PMBUS_VOUT_OV_FAULT_LIMIT: 4922c6fcbb2SVadim Pasternak /* 4932c6fcbb2SVadim Pasternak * Register provides two values for over-voltage protection 4942c6fcbb2SVadim Pasternak * threshold for fixed (ovp2) and tracking (ovp1) modes. The 4952c6fcbb2SVadim Pasternak * minimum of these two values is provided as over-voltage 4962c6fcbb2SVadim Pasternak * fault alarm. 4972c6fcbb2SVadim Pasternak */ 4982c6fcbb2SVadim Pasternak ret = mp2975_read_word_helper(client, page, phase, 4992c6fcbb2SVadim Pasternak MP2975_MFR_OVP_TH_SET, 5002c6fcbb2SVadim Pasternak GENMASK(2, 0)); 5012c6fcbb2SVadim Pasternak if (ret < 0) 5022c6fcbb2SVadim Pasternak return ret; 5032c6fcbb2SVadim Pasternak 5042c6fcbb2SVadim Pasternak ret = min_t(int, data->vout_max[page] + 50 * (ret + 1), 5052c6fcbb2SVadim Pasternak data->vout_ov_fixed[page]); 5062c6fcbb2SVadim Pasternak break; 5072c6fcbb2SVadim Pasternak case PMBUS_VOUT_UV_FAULT_LIMIT: 5082c6fcbb2SVadim Pasternak ret = mp2975_read_word_helper(client, page, phase, 5092c6fcbb2SVadim Pasternak MP2975_MFR_UVP_SET, 5102c6fcbb2SVadim Pasternak GENMASK(2, 0)); 5112c6fcbb2SVadim Pasternak if (ret < 0) 5122c6fcbb2SVadim Pasternak return ret; 5132c6fcbb2SVadim Pasternak 5142c6fcbb2SVadim Pasternak ret = DIV_ROUND_CLOSEST(data->vref[page] * 10 - 50 * 5152c6fcbb2SVadim Pasternak (ret + 1) * data->vout_scale, 10); 5162c6fcbb2SVadim Pasternak break; 5172c6fcbb2SVadim Pasternak case PMBUS_VIRT_READ_POUT_MAX: 5182c6fcbb2SVadim Pasternak ret = mp2975_read_word_helper(client, page, phase, 5192c6fcbb2SVadim Pasternak MP2975_MFR_READ_POUT_PK, 5202c6fcbb2SVadim Pasternak GENMASK(12, 0)); 5212c6fcbb2SVadim Pasternak if (ret < 0) 5222c6fcbb2SVadim Pasternak return ret; 5232c6fcbb2SVadim Pasternak 5242c6fcbb2SVadim Pasternak ret = DIV_ROUND_CLOSEST(ret, 4); 5252c6fcbb2SVadim Pasternak break; 5262c6fcbb2SVadim Pasternak case PMBUS_VIRT_READ_IOUT_MAX: 5272c6fcbb2SVadim Pasternak ret = mp2975_read_word_helper(client, page, phase, 5282c6fcbb2SVadim Pasternak MP2975_MFR_READ_IOUT_PK, 5292c6fcbb2SVadim Pasternak GENMASK(12, 0)); 5302c6fcbb2SVadim Pasternak if (ret < 0) 5312c6fcbb2SVadim Pasternak return ret; 5322c6fcbb2SVadim Pasternak 5332c6fcbb2SVadim Pasternak ret = DIV_ROUND_CLOSEST(ret, 4); 5342c6fcbb2SVadim Pasternak break; 5352c6fcbb2SVadim Pasternak case PMBUS_READ_IOUT: 5362c6fcbb2SVadim Pasternak ret = mp2975_read_phases(client, data, page, phase); 5372c6fcbb2SVadim Pasternak if (ret < 0) 5382c6fcbb2SVadim Pasternak return ret; 5392c6fcbb2SVadim Pasternak 5402c6fcbb2SVadim Pasternak break; 5412c6fcbb2SVadim Pasternak case PMBUS_UT_WARN_LIMIT: 5422c6fcbb2SVadim Pasternak case PMBUS_UT_FAULT_LIMIT: 5432c6fcbb2SVadim Pasternak case PMBUS_VIN_UV_WARN_LIMIT: 5442c6fcbb2SVadim Pasternak case PMBUS_VIN_UV_FAULT_LIMIT: 5452c6fcbb2SVadim Pasternak case PMBUS_VOUT_UV_WARN_LIMIT: 5462c6fcbb2SVadim Pasternak case PMBUS_VOUT_OV_WARN_LIMIT: 5472c6fcbb2SVadim Pasternak case PMBUS_VIN_OV_WARN_LIMIT: 5482c6fcbb2SVadim Pasternak case PMBUS_IIN_OC_FAULT_LIMIT: 5492c6fcbb2SVadim Pasternak case PMBUS_IOUT_OC_LV_FAULT_LIMIT: 5502c6fcbb2SVadim Pasternak case PMBUS_IIN_OC_WARN_LIMIT: 5512c6fcbb2SVadim Pasternak case PMBUS_IOUT_OC_WARN_LIMIT: 5522c6fcbb2SVadim Pasternak case PMBUS_IOUT_OC_FAULT_LIMIT: 5532c6fcbb2SVadim Pasternak case PMBUS_IOUT_UC_FAULT_LIMIT: 5542c6fcbb2SVadim Pasternak case PMBUS_POUT_OP_FAULT_LIMIT: 5552c6fcbb2SVadim Pasternak case PMBUS_POUT_OP_WARN_LIMIT: 5562c6fcbb2SVadim Pasternak case PMBUS_PIN_OP_WARN_LIMIT: 5572c6fcbb2SVadim Pasternak return -ENXIO; 5582c6fcbb2SVadim Pasternak default: 5592c6fcbb2SVadim Pasternak return -ENODATA; 5602c6fcbb2SVadim Pasternak } 5612c6fcbb2SVadim Pasternak 5622c6fcbb2SVadim Pasternak return ret; 5632c6fcbb2SVadim Pasternak } 5642c6fcbb2SVadim Pasternak 565e2c90b48SPatrick Rudolph static int mp2975_identify_multiphase_rail2(struct i2c_client *client, 566e2c90b48SPatrick Rudolph struct mp2975_data *data) 5672c6fcbb2SVadim Pasternak { 5682c6fcbb2SVadim Pasternak int ret; 5692c6fcbb2SVadim Pasternak 5702c6fcbb2SVadim Pasternak /* 571e2c90b48SPatrick Rudolph * Identify multiphase for rail 2 - could be from 0 to data->max_phases[1]. 5722c6fcbb2SVadim Pasternak * In case phase number is zero – only page zero is supported 5732c6fcbb2SVadim Pasternak */ 5742c6fcbb2SVadim Pasternak ret = i2c_smbus_write_byte_data(client, PMBUS_PAGE, 2); 5752c6fcbb2SVadim Pasternak if (ret < 0) 5762c6fcbb2SVadim Pasternak return ret; 5772c6fcbb2SVadim Pasternak 5782c6fcbb2SVadim Pasternak ret = i2c_smbus_read_word_data(client, MP2975_MFR_VR_MULTI_CONFIG_R2); 5792c6fcbb2SVadim Pasternak if (ret < 0) 5802c6fcbb2SVadim Pasternak return ret; 5812c6fcbb2SVadim Pasternak 5822c6fcbb2SVadim Pasternak ret &= GENMASK(2, 0); 583e2c90b48SPatrick Rudolph return (ret >= data->max_phases[1]) ? data->max_phases[1] : ret; 5842c6fcbb2SVadim Pasternak } 5852c6fcbb2SVadim Pasternak 5862c6fcbb2SVadim Pasternak static void mp2975_set_phase_rail1(struct pmbus_driver_info *info) 5872c6fcbb2SVadim Pasternak { 5882c6fcbb2SVadim Pasternak int i; 5892c6fcbb2SVadim Pasternak 5902c6fcbb2SVadim Pasternak for (i = 0 ; i < info->phases[0]; i++) 5912c6fcbb2SVadim Pasternak info->pfunc[i] = PMBUS_HAVE_IOUT; 5922c6fcbb2SVadim Pasternak } 5932c6fcbb2SVadim Pasternak 5942c6fcbb2SVadim Pasternak static void 5952c6fcbb2SVadim Pasternak mp2975_set_phase_rail2(struct pmbus_driver_info *info, int num_phases) 5962c6fcbb2SVadim Pasternak { 5972c6fcbb2SVadim Pasternak int i; 5982c6fcbb2SVadim Pasternak 5992c6fcbb2SVadim Pasternak /* Set phases for rail 2 from upper to lower. */ 6002c6fcbb2SVadim Pasternak for (i = 1; i <= num_phases; i++) 6012c6fcbb2SVadim Pasternak info->pfunc[MP2975_MAX_PHASE_RAIL1 - i] = PMBUS_HAVE_IOUT; 6022c6fcbb2SVadim Pasternak } 6032c6fcbb2SVadim Pasternak 6042c6fcbb2SVadim Pasternak static int 6052c6fcbb2SVadim Pasternak mp2975_identify_multiphase(struct i2c_client *client, struct mp2975_data *data, 6062c6fcbb2SVadim Pasternak struct pmbus_driver_info *info) 6072c6fcbb2SVadim Pasternak { 6082c6fcbb2SVadim Pasternak int num_phases2, ret; 6092c6fcbb2SVadim Pasternak 6102c6fcbb2SVadim Pasternak ret = i2c_smbus_write_byte_data(client, PMBUS_PAGE, 2); 6112c6fcbb2SVadim Pasternak if (ret < 0) 6122c6fcbb2SVadim Pasternak return ret; 6132c6fcbb2SVadim Pasternak 614e2c90b48SPatrick Rudolph /* Identify multiphase for rail 1 - could be from 1 to data->max_phases[0]. */ 6152c6fcbb2SVadim Pasternak ret = i2c_smbus_read_word_data(client, MP2975_MFR_VR_MULTI_CONFIG_R1); 6162c6fcbb2SVadim Pasternak if (ret <= 0) 6172c6fcbb2SVadim Pasternak return ret; 6182c6fcbb2SVadim Pasternak 6192c6fcbb2SVadim Pasternak info->phases[0] = ret & GENMASK(3, 0); 6202c6fcbb2SVadim Pasternak 6212c6fcbb2SVadim Pasternak /* 622e2c90b48SPatrick Rudolph * The device provides a total of $n PWM pins, and can be configured 6232c6fcbb2SVadim Pasternak * to different phase count applications for rail 1 and rail 2. 624e2c90b48SPatrick Rudolph * Rail 1 can be set to $n phases, while rail 2 can be set to less than 625e2c90b48SPatrick Rudolph * that. When rail 1’s phase count is configured as 0, rail 6262c6fcbb2SVadim Pasternak * 1 operates with 1-phase DCM. When rail 2 phase count is configured 6272c6fcbb2SVadim Pasternak * as 0, rail 2 is disabled. 6282c6fcbb2SVadim Pasternak */ 629e2c90b48SPatrick Rudolph if (info->phases[0] > data->max_phases[0]) 6302c6fcbb2SVadim Pasternak return -EINVAL; 6312c6fcbb2SVadim Pasternak 63245f154dcSPatrick Rudolph if (data->chip_id == mp2975) { 6332c6fcbb2SVadim Pasternak mp2975_set_phase_rail1(info); 634e2c90b48SPatrick Rudolph num_phases2 = min(data->max_phases[0] - info->phases[0], 635e2c90b48SPatrick Rudolph data->max_phases[1]); 6362c6fcbb2SVadim Pasternak if (info->phases[1] && info->phases[1] <= num_phases2) 6372c6fcbb2SVadim Pasternak mp2975_set_phase_rail2(info, num_phases2); 63845f154dcSPatrick Rudolph } 6392c6fcbb2SVadim Pasternak 6402c6fcbb2SVadim Pasternak return 0; 6412c6fcbb2SVadim Pasternak } 6422c6fcbb2SVadim Pasternak 6432c6fcbb2SVadim Pasternak static int 6442c6fcbb2SVadim Pasternak mp2975_identify_vid(struct i2c_client *client, struct mp2975_data *data, 6452c6fcbb2SVadim Pasternak struct pmbus_driver_info *info, u32 reg, int page, 6462c6fcbb2SVadim Pasternak u32 imvp_bit, u32 vr_bit) 6472c6fcbb2SVadim Pasternak { 6482c6fcbb2SVadim Pasternak int ret; 6492c6fcbb2SVadim Pasternak 6502c6fcbb2SVadim Pasternak /* Identify VID mode and step selection. */ 6512c6fcbb2SVadim Pasternak ret = i2c_smbus_read_word_data(client, reg); 6522c6fcbb2SVadim Pasternak if (ret < 0) 6532c6fcbb2SVadim Pasternak return ret; 6542c6fcbb2SVadim Pasternak 6552c6fcbb2SVadim Pasternak if (ret & imvp_bit) { 6562c6fcbb2SVadim Pasternak info->vrm_version[page] = imvp9; 6572c6fcbb2SVadim Pasternak data->vid_step[page] = MP2975_PROT_DEV_OV_OFF; 6582c6fcbb2SVadim Pasternak } else if (ret & vr_bit) { 6592c6fcbb2SVadim Pasternak info->vrm_version[page] = vr12; 6602c6fcbb2SVadim Pasternak data->vid_step[page] = MP2975_PROT_DEV_OV_ON; 6612c6fcbb2SVadim Pasternak } else { 6622c6fcbb2SVadim Pasternak info->vrm_version[page] = vr13; 6632c6fcbb2SVadim Pasternak data->vid_step[page] = MP2975_PROT_DEV_OV_OFF; 6642c6fcbb2SVadim Pasternak } 6652c6fcbb2SVadim Pasternak 6662c6fcbb2SVadim Pasternak return 0; 6672c6fcbb2SVadim Pasternak } 6682c6fcbb2SVadim Pasternak 6692c6fcbb2SVadim Pasternak static int 6702c6fcbb2SVadim Pasternak mp2975_identify_rails_vid(struct i2c_client *client, struct mp2975_data *data, 6712c6fcbb2SVadim Pasternak struct pmbus_driver_info *info) 6722c6fcbb2SVadim Pasternak { 6732c6fcbb2SVadim Pasternak int ret; 6742c6fcbb2SVadim Pasternak 6752c6fcbb2SVadim Pasternak ret = i2c_smbus_write_byte_data(client, PMBUS_PAGE, 2); 6762c6fcbb2SVadim Pasternak if (ret < 0) 6772c6fcbb2SVadim Pasternak return ret; 6782c6fcbb2SVadim Pasternak 6792c6fcbb2SVadim Pasternak /* Identify VID mode for rail 1. */ 6802c6fcbb2SVadim Pasternak ret = mp2975_identify_vid(client, data, info, 6812c6fcbb2SVadim Pasternak MP2975_MFR_VR_MULTI_CONFIG_R1, 0, 6822c6fcbb2SVadim Pasternak MP2975_IMVP9_EN_R1, MP2975_VID_STEP_SEL_R1); 6832c6fcbb2SVadim Pasternak if (ret < 0) 6842c6fcbb2SVadim Pasternak return ret; 6852c6fcbb2SVadim Pasternak 6862c6fcbb2SVadim Pasternak /* Identify VID mode for rail 2, if connected. */ 6872c6fcbb2SVadim Pasternak if (info->phases[1]) 6882c6fcbb2SVadim Pasternak ret = mp2975_identify_vid(client, data, info, 6892c6fcbb2SVadim Pasternak MP2975_MFR_VR_MULTI_CONFIG_R2, 1, 6902c6fcbb2SVadim Pasternak MP2975_IMVP9_EN_R2, 6912c6fcbb2SVadim Pasternak MP2975_VID_STEP_SEL_R2); 6925239277eSPatrick Rudolph 6935239277eSPatrick Rudolph return ret; 6945239277eSPatrick Rudolph } 6955239277eSPatrick Rudolph 6965239277eSPatrick Rudolph static int 6975239277eSPatrick Rudolph mp2973_identify_rails_vid(struct i2c_client *client, struct mp2975_data *data, 6985239277eSPatrick Rudolph struct pmbus_driver_info *info) 6995239277eSPatrick Rudolph { 7005239277eSPatrick Rudolph int ret; 7015239277eSPatrick Rudolph 7025239277eSPatrick Rudolph ret = i2c_smbus_write_byte_data(client, PMBUS_PAGE, 2); 7035239277eSPatrick Rudolph if (ret < 0) 7045239277eSPatrick Rudolph return ret; 7055239277eSPatrick Rudolph 7065239277eSPatrick Rudolph /* Identify VID mode for rail 1. */ 7075239277eSPatrick Rudolph ret = mp2975_identify_vid(client, data, info, 7085239277eSPatrick Rudolph MP2973_MFR_VR_MULTI_CONFIG_R1, 0, 7095239277eSPatrick Rudolph MP2973_IMVP9_EN_R1, MP2973_VID_STEP_SEL_R1); 7105239277eSPatrick Rudolph 7115239277eSPatrick Rudolph if (ret < 0) 7125239277eSPatrick Rudolph return ret; 7135239277eSPatrick Rudolph 7145239277eSPatrick Rudolph /* Identify VID mode for rail 2, if connected. */ 7155239277eSPatrick Rudolph if (info->phases[1]) 7165239277eSPatrick Rudolph ret = mp2975_identify_vid(client, data, info, 7175239277eSPatrick Rudolph MP2973_MFR_VR_MULTI_CONFIG_R2, 1, 7185239277eSPatrick Rudolph MP2973_IMVP9_EN_R2, 7195239277eSPatrick Rudolph MP2973_VID_STEP_SEL_R2); 7205239277eSPatrick Rudolph 7212c6fcbb2SVadim Pasternak return ret; 7222c6fcbb2SVadim Pasternak } 7232c6fcbb2SVadim Pasternak 7242c6fcbb2SVadim Pasternak static int 7252c6fcbb2SVadim Pasternak mp2975_current_sense_gain_get(struct i2c_client *client, 7262c6fcbb2SVadim Pasternak struct mp2975_data *data) 7272c6fcbb2SVadim Pasternak { 7282c6fcbb2SVadim Pasternak int i, ret; 7292c6fcbb2SVadim Pasternak 7302c6fcbb2SVadim Pasternak /* 7312c6fcbb2SVadim Pasternak * Obtain DrMOS current sense gain of power stage from the register 7322c6fcbb2SVadim Pasternak * MP2975_MFR_VR_CONFIG1, bits 13-12. The value is selected as below: 7332c6fcbb2SVadim Pasternak * 00b - 5µA/A, 01b - 8.5µA/A, 10b - 9.7µA/A, 11b - 10µA/A. Other 7342c6fcbb2SVadim Pasternak * values are invalid. 7352c6fcbb2SVadim Pasternak */ 7362c6fcbb2SVadim Pasternak for (i = 0 ; i < data->info.pages; i++) { 7372c6fcbb2SVadim Pasternak ret = i2c_smbus_write_byte_data(client, PMBUS_PAGE, i); 7382c6fcbb2SVadim Pasternak if (ret < 0) 7392c6fcbb2SVadim Pasternak return ret; 7402c6fcbb2SVadim Pasternak ret = i2c_smbus_read_word_data(client, 7412c6fcbb2SVadim Pasternak MP2975_MFR_VR_CONFIG1); 7422c6fcbb2SVadim Pasternak if (ret < 0) 7432c6fcbb2SVadim Pasternak return ret; 7442c6fcbb2SVadim Pasternak 7452c6fcbb2SVadim Pasternak switch ((ret & MP2975_DRMOS_KCS) >> 12) { 7462c6fcbb2SVadim Pasternak case 0: 7472c6fcbb2SVadim Pasternak data->curr_sense_gain[i] = 50; 7482c6fcbb2SVadim Pasternak break; 7492c6fcbb2SVadim Pasternak case 1: 7502c6fcbb2SVadim Pasternak data->curr_sense_gain[i] = 85; 7512c6fcbb2SVadim Pasternak break; 7522c6fcbb2SVadim Pasternak case 2: 7532c6fcbb2SVadim Pasternak data->curr_sense_gain[i] = 97; 7542c6fcbb2SVadim Pasternak break; 7552c6fcbb2SVadim Pasternak default: 7562c6fcbb2SVadim Pasternak data->curr_sense_gain[i] = 100; 7572c6fcbb2SVadim Pasternak break; 7582c6fcbb2SVadim Pasternak } 7592c6fcbb2SVadim Pasternak } 7602c6fcbb2SVadim Pasternak 7612c6fcbb2SVadim Pasternak return 0; 7622c6fcbb2SVadim Pasternak } 7632c6fcbb2SVadim Pasternak 7642c6fcbb2SVadim Pasternak static int 7652c6fcbb2SVadim Pasternak mp2975_vref_get(struct i2c_client *client, struct mp2975_data *data, 7662c6fcbb2SVadim Pasternak struct pmbus_driver_info *info) 7672c6fcbb2SVadim Pasternak { 7682c6fcbb2SVadim Pasternak int ret; 7692c6fcbb2SVadim Pasternak 7702c6fcbb2SVadim Pasternak ret = i2c_smbus_write_byte_data(client, PMBUS_PAGE, 3); 7712c6fcbb2SVadim Pasternak if (ret < 0) 7722c6fcbb2SVadim Pasternak return ret; 7732c6fcbb2SVadim Pasternak 7742c6fcbb2SVadim Pasternak /* Get voltage reference value for rail 1. */ 7752c6fcbb2SVadim Pasternak ret = i2c_smbus_read_word_data(client, MP2975_MFR_READ_VREF_R1); 7762c6fcbb2SVadim Pasternak if (ret < 0) 7772c6fcbb2SVadim Pasternak return ret; 7782c6fcbb2SVadim Pasternak 7792c6fcbb2SVadim Pasternak data->vref[0] = ret * data->vid_step[0]; 7802c6fcbb2SVadim Pasternak 7812c6fcbb2SVadim Pasternak /* Get voltage reference value for rail 2, if connected. */ 7822c6fcbb2SVadim Pasternak if (data->info.pages == MP2975_PAGE_NUM) { 7832c6fcbb2SVadim Pasternak ret = i2c_smbus_read_word_data(client, MP2975_MFR_READ_VREF_R2); 7842c6fcbb2SVadim Pasternak if (ret < 0) 7852c6fcbb2SVadim Pasternak return ret; 7862c6fcbb2SVadim Pasternak 7872c6fcbb2SVadim Pasternak data->vref[1] = ret * data->vid_step[1]; 7882c6fcbb2SVadim Pasternak } 7892c6fcbb2SVadim Pasternak return 0; 7902c6fcbb2SVadim Pasternak } 7912c6fcbb2SVadim Pasternak 7922c6fcbb2SVadim Pasternak static int 7932c6fcbb2SVadim Pasternak mp2975_vref_offset_get(struct i2c_client *client, struct mp2975_data *data, 7942c6fcbb2SVadim Pasternak int page) 7952c6fcbb2SVadim Pasternak { 7962c6fcbb2SVadim Pasternak int ret; 7972c6fcbb2SVadim Pasternak 7982c6fcbb2SVadim Pasternak ret = i2c_smbus_read_word_data(client, MP2975_MFR_OVP_TH_SET); 7992c6fcbb2SVadim Pasternak if (ret < 0) 8002c6fcbb2SVadim Pasternak return ret; 8012c6fcbb2SVadim Pasternak 8022c6fcbb2SVadim Pasternak switch ((ret & GENMASK(5, 3)) >> 3) { 8032c6fcbb2SVadim Pasternak case 1: 8042c6fcbb2SVadim Pasternak data->vref_off[page] = 140; 8052c6fcbb2SVadim Pasternak break; 8062c6fcbb2SVadim Pasternak case 2: 8072c6fcbb2SVadim Pasternak data->vref_off[page] = 220; 8082c6fcbb2SVadim Pasternak break; 8092c6fcbb2SVadim Pasternak case 4: 8102c6fcbb2SVadim Pasternak data->vref_off[page] = 400; 8112c6fcbb2SVadim Pasternak break; 8122c6fcbb2SVadim Pasternak default: 8132c6fcbb2SVadim Pasternak return -EINVAL; 8142c6fcbb2SVadim Pasternak } 8152c6fcbb2SVadim Pasternak return 0; 8162c6fcbb2SVadim Pasternak } 8172c6fcbb2SVadim Pasternak 8182c6fcbb2SVadim Pasternak static int 8192c6fcbb2SVadim Pasternak mp2975_vout_max_get(struct i2c_client *client, struct mp2975_data *data, 8202c6fcbb2SVadim Pasternak struct pmbus_driver_info *info, int page) 8212c6fcbb2SVadim Pasternak { 8222c6fcbb2SVadim Pasternak int ret; 8232c6fcbb2SVadim Pasternak 8242c6fcbb2SVadim Pasternak /* Get maximum reference voltage of VID-DAC in VID format. */ 8252c6fcbb2SVadim Pasternak ret = i2c_smbus_read_word_data(client, PMBUS_VOUT_MAX); 8262c6fcbb2SVadim Pasternak if (ret < 0) 8272c6fcbb2SVadim Pasternak return ret; 8282c6fcbb2SVadim Pasternak 8292c6fcbb2SVadim Pasternak data->vout_max[page] = mp2975_vid2direct(info->vrm_version[page], ret & 8302c6fcbb2SVadim Pasternak GENMASK(8, 0)); 8312c6fcbb2SVadim Pasternak return 0; 8322c6fcbb2SVadim Pasternak } 8332c6fcbb2SVadim Pasternak 8342c6fcbb2SVadim Pasternak static int 8351feb31e8SPatrick Rudolph mp2975_set_vout_format(struct i2c_client *client, 8362c6fcbb2SVadim Pasternak struct mp2975_data *data, int page) 8372c6fcbb2SVadim Pasternak { 8385239277eSPatrick Rudolph int ret, i; 8392c6fcbb2SVadim Pasternak 8405239277eSPatrick Rudolph /* Enable DIRECT VOUT format 1mV/LSB */ 8415239277eSPatrick Rudolph if (data->chip_id == mp2975) { 8422c6fcbb2SVadim Pasternak ret = i2c_smbus_read_word_data(client, MP2975_MFR_DC_LOOP_CTRL); 8432c6fcbb2SVadim Pasternak if (ret < 0) 8442c6fcbb2SVadim Pasternak return ret; 8451feb31e8SPatrick Rudolph if (ret & MP2975_VOUT_FORMAT) { 8461feb31e8SPatrick Rudolph ret &= ~MP2975_VOUT_FORMAT; 8471feb31e8SPatrick Rudolph ret = i2c_smbus_write_word_data(client, MP2975_MFR_DC_LOOP_CTRL, ret); 8481feb31e8SPatrick Rudolph } 8495239277eSPatrick Rudolph } else { 8505239277eSPatrick Rudolph ret = i2c_smbus_read_word_data(client, MP2973_MFR_RESO_SET); 8515239277eSPatrick Rudolph if (ret < 0) 8525239277eSPatrick Rudolph return ret; 8535239277eSPatrick Rudolph i = ret; 8545239277eSPatrick Rudolph 8555239277eSPatrick Rudolph if (page == 0) { 8565239277eSPatrick Rudolph i &= ~MP2973_VOUT_FORMAT_R1; 8575239277eSPatrick Rudolph i |= MP2973_VOUT_FORMAT_DIRECT_R1; 8585239277eSPatrick Rudolph } else { 8595239277eSPatrick Rudolph i &= ~MP2973_VOUT_FORMAT_R2; 8605239277eSPatrick Rudolph i |= MP2973_VOUT_FORMAT_DIRECT_R2; 8615239277eSPatrick Rudolph } 8625239277eSPatrick Rudolph if (i != ret) 8635239277eSPatrick Rudolph ret = i2c_smbus_write_word_data(client, MP2973_MFR_RESO_SET, i); 8645239277eSPatrick Rudolph } 8651feb31e8SPatrick Rudolph return ret; 8662c6fcbb2SVadim Pasternak } 8672c6fcbb2SVadim Pasternak 8682c6fcbb2SVadim Pasternak static int 8692c6fcbb2SVadim Pasternak mp2975_vout_ov_scale_get(struct i2c_client *client, struct mp2975_data *data, 8702c6fcbb2SVadim Pasternak struct pmbus_driver_info *info) 8712c6fcbb2SVadim Pasternak { 8722c6fcbb2SVadim Pasternak int thres_dev, sense_ampl, ret; 8732c6fcbb2SVadim Pasternak 8742c6fcbb2SVadim Pasternak ret = i2c_smbus_write_byte_data(client, PMBUS_PAGE, 0); 8752c6fcbb2SVadim Pasternak if (ret < 0) 8762c6fcbb2SVadim Pasternak return ret; 8772c6fcbb2SVadim Pasternak 8782c6fcbb2SVadim Pasternak /* 8792c6fcbb2SVadim Pasternak * Get divider for over- and under-voltage protection thresholds 8802c6fcbb2SVadim Pasternak * configuration from the Advanced Options of Auto Phase Shedding and 8812c6fcbb2SVadim Pasternak * decay register. 8822c6fcbb2SVadim Pasternak */ 8832c6fcbb2SVadim Pasternak ret = i2c_smbus_read_word_data(client, MP2975_MFR_APS_DECAY_ADV); 8842c6fcbb2SVadim Pasternak if (ret < 0) 8852c6fcbb2SVadim Pasternak return ret; 8862c6fcbb2SVadim Pasternak thres_dev = ret & MP2975_PRT_THRES_DIV_OV_EN ? MP2975_PROT_DEV_OV_ON : 8872c6fcbb2SVadim Pasternak MP2975_PROT_DEV_OV_OFF; 8882c6fcbb2SVadim Pasternak 8892c6fcbb2SVadim Pasternak /* Select the gain of remote sense amplifier. */ 8902c6fcbb2SVadim Pasternak ret = i2c_smbus_read_word_data(client, PMBUS_VOUT_SCALE_LOOP); 8912c6fcbb2SVadim Pasternak if (ret < 0) 8922c6fcbb2SVadim Pasternak return ret; 8932c6fcbb2SVadim Pasternak sense_ampl = ret & MP2975_SENSE_AMPL ? MP2975_SENSE_AMPL_HALF : 8942c6fcbb2SVadim Pasternak MP2975_SENSE_AMPL_UNIT; 8952c6fcbb2SVadim Pasternak 8962c6fcbb2SVadim Pasternak data->vout_scale = sense_ampl * thres_dev; 8972c6fcbb2SVadim Pasternak 8982c6fcbb2SVadim Pasternak return 0; 8992c6fcbb2SVadim Pasternak } 9002c6fcbb2SVadim Pasternak 9012c6fcbb2SVadim Pasternak static int 9022c6fcbb2SVadim Pasternak mp2975_vout_per_rail_config_get(struct i2c_client *client, 9032c6fcbb2SVadim Pasternak struct mp2975_data *data, 9042c6fcbb2SVadim Pasternak struct pmbus_driver_info *info) 9052c6fcbb2SVadim Pasternak { 9062c6fcbb2SVadim Pasternak int i, ret; 9072c6fcbb2SVadim Pasternak 9082c6fcbb2SVadim Pasternak for (i = 0; i < data->info.pages; i++) { 9092c6fcbb2SVadim Pasternak ret = i2c_smbus_write_byte_data(client, PMBUS_PAGE, i); 9102c6fcbb2SVadim Pasternak if (ret < 0) 9115239277eSPatrick Rudolph continue; 9122c6fcbb2SVadim Pasternak 9135239277eSPatrick Rudolph /* Set VOUT format for READ_VOUT command : direct. */ 9145239277eSPatrick Rudolph ret = mp2975_set_vout_format(client, data, i); 9152c6fcbb2SVadim Pasternak if (ret < 0) 9162c6fcbb2SVadim Pasternak return ret; 9172c6fcbb2SVadim Pasternak 9182c6fcbb2SVadim Pasternak /* Obtain maximum voltage values. */ 9192c6fcbb2SVadim Pasternak ret = mp2975_vout_max_get(client, data, info, i); 9202c6fcbb2SVadim Pasternak if (ret < 0) 9212c6fcbb2SVadim Pasternak return ret; 9222c6fcbb2SVadim Pasternak 9235239277eSPatrick Rudolph /* Skip if reading Vref is unsupported */ 9245239277eSPatrick Rudolph if (data->chip_id != mp2975) 9255239277eSPatrick Rudolph continue; 9265239277eSPatrick Rudolph 9275239277eSPatrick Rudolph /* Obtain voltage reference offsets. */ 9285239277eSPatrick Rudolph ret = mp2975_vref_offset_get(client, data, i); 9292c6fcbb2SVadim Pasternak if (ret < 0) 9302c6fcbb2SVadim Pasternak return ret; 9312c6fcbb2SVadim Pasternak 9322c6fcbb2SVadim Pasternak /* 9332c6fcbb2SVadim Pasternak * Set over-voltage fixed value. Thresholds are provided as 9342c6fcbb2SVadim Pasternak * fixed value, and tracking value. The minimum of them are 9352c6fcbb2SVadim Pasternak * exposed as over-voltage critical threshold. 9362c6fcbb2SVadim Pasternak */ 9372c6fcbb2SVadim Pasternak data->vout_ov_fixed[i] = data->vref[i] + 9382c6fcbb2SVadim Pasternak DIV_ROUND_CLOSEST(data->vref_off[i] * 9392c6fcbb2SVadim Pasternak data->vout_scale, 9402c6fcbb2SVadim Pasternak 10); 9412c6fcbb2SVadim Pasternak } 9422c6fcbb2SVadim Pasternak 9432c6fcbb2SVadim Pasternak return 0; 9442c6fcbb2SVadim Pasternak } 9452c6fcbb2SVadim Pasternak 9462c6fcbb2SVadim Pasternak static struct pmbus_driver_info mp2975_info = { 9472c6fcbb2SVadim Pasternak .pages = 1, 9482c6fcbb2SVadim Pasternak .format[PSC_VOLTAGE_IN] = linear, 9492c6fcbb2SVadim Pasternak .format[PSC_VOLTAGE_OUT] = direct, 9502c6fcbb2SVadim Pasternak .format[PSC_TEMPERATURE] = direct, 9512c6fcbb2SVadim Pasternak .format[PSC_CURRENT_IN] = linear, 9522c6fcbb2SVadim Pasternak .format[PSC_CURRENT_OUT] = direct, 9532c6fcbb2SVadim Pasternak .format[PSC_POWER] = direct, 9542c6fcbb2SVadim Pasternak .m[PSC_TEMPERATURE] = 1, 9552c6fcbb2SVadim Pasternak .m[PSC_VOLTAGE_OUT] = 1, 9562c6fcbb2SVadim Pasternak .R[PSC_VOLTAGE_OUT] = 3, 9572c6fcbb2SVadim Pasternak .m[PSC_CURRENT_OUT] = 1, 9582c6fcbb2SVadim Pasternak .m[PSC_POWER] = 1, 9592c6fcbb2SVadim Pasternak .func[0] = PMBUS_HAVE_VIN | PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT | 9602c6fcbb2SVadim Pasternak PMBUS_HAVE_IIN | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT | 9612c6fcbb2SVadim Pasternak PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP | PMBUS_HAVE_POUT | 9622c6fcbb2SVadim Pasternak PMBUS_HAVE_PIN | PMBUS_HAVE_STATUS_INPUT | PMBUS_PHASE_VIRTUAL, 963c60fe56cSKonstantin Aladyshev .read_byte_data = mp2975_read_byte_data, 9642c6fcbb2SVadim Pasternak .read_word_data = mp2975_read_word_data, 96588fc1efcSPatrick Rudolph #if IS_ENABLED(CONFIG_SENSORS_MP2975_REGULATOR) 96688fc1efcSPatrick Rudolph .num_regulators = 1, 96788fc1efcSPatrick Rudolph .reg_desc = mp2975_reg_desc, 96888fc1efcSPatrick Rudolph #endif 9692c6fcbb2SVadim Pasternak }; 9702c6fcbb2SVadim Pasternak 9715239277eSPatrick Rudolph static struct pmbus_driver_info mp2973_info = { 9725239277eSPatrick Rudolph .pages = 1, 9735239277eSPatrick Rudolph .format[PSC_VOLTAGE_IN] = linear, 9745239277eSPatrick Rudolph .format[PSC_VOLTAGE_OUT] = direct, 9755239277eSPatrick Rudolph .format[PSC_TEMPERATURE] = linear, 9765239277eSPatrick Rudolph .format[PSC_CURRENT_IN] = linear, 9775239277eSPatrick Rudolph .format[PSC_CURRENT_OUT] = linear, 9785239277eSPatrick Rudolph .format[PSC_POWER] = linear, 9795239277eSPatrick Rudolph .m[PSC_VOLTAGE_OUT] = 1, 9805239277eSPatrick Rudolph .R[PSC_VOLTAGE_OUT] = 3, 9815239277eSPatrick Rudolph .func[0] = PMBUS_HAVE_VIN | PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT | 9825239277eSPatrick Rudolph PMBUS_HAVE_IIN | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT | 9835239277eSPatrick Rudolph PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP | PMBUS_HAVE_POUT | 9845239277eSPatrick Rudolph PMBUS_HAVE_PIN | PMBUS_HAVE_STATUS_INPUT, 9855239277eSPatrick Rudolph .read_word_data = mp2973_read_word_data, 986*c7506a2bSPatrick Rudolph .write_word_data = mp2973_write_word_data, 98788fc1efcSPatrick Rudolph #if IS_ENABLED(CONFIG_SENSORS_MP2975_REGULATOR) 98888fc1efcSPatrick Rudolph .num_regulators = 1, 98988fc1efcSPatrick Rudolph .reg_desc = mp2975_reg_desc, 99088fc1efcSPatrick Rudolph #endif 9915239277eSPatrick Rudolph }; 9925239277eSPatrick Rudolph 9932c6fcbb2SVadim Pasternak static int mp2975_probe(struct i2c_client *client) 9942c6fcbb2SVadim Pasternak { 9952c6fcbb2SVadim Pasternak struct pmbus_driver_info *info; 9962c6fcbb2SVadim Pasternak struct mp2975_data *data; 9972c6fcbb2SVadim Pasternak int ret; 9982c6fcbb2SVadim Pasternak 9992c6fcbb2SVadim Pasternak data = devm_kzalloc(&client->dev, sizeof(struct mp2975_data), 10002c6fcbb2SVadim Pasternak GFP_KERNEL); 10012c6fcbb2SVadim Pasternak if (!data) 10022c6fcbb2SVadim Pasternak return -ENOMEM; 10032c6fcbb2SVadim Pasternak 10041f6f34d0SPatrick Rudolph if (client->dev.of_node) 10051f6f34d0SPatrick Rudolph data->chip_id = (enum chips)(unsigned long)of_device_get_match_data(&client->dev); 10061f6f34d0SPatrick Rudolph else 10071f6f34d0SPatrick Rudolph data->chip_id = i2c_match_id(mp2975_id, client)->driver_data; 10081f6f34d0SPatrick Rudolph 1009e2c90b48SPatrick Rudolph memcpy(data->max_phases, mp2975_max_phases[data->chip_id], 1010e2c90b48SPatrick Rudolph sizeof(data->max_phases)); 1011e2c90b48SPatrick Rudolph 10125239277eSPatrick Rudolph if (data->chip_id == mp2975) 10135239277eSPatrick Rudolph memcpy(&data->info, &mp2975_info, sizeof(*info)); 10145239277eSPatrick Rudolph else 10155239277eSPatrick Rudolph memcpy(&data->info, &mp2973_info, sizeof(*info)); 10165239277eSPatrick Rudolph 10172c6fcbb2SVadim Pasternak info = &data->info; 10182c6fcbb2SVadim Pasternak 10192c6fcbb2SVadim Pasternak /* Identify multiphase configuration for rail 2. */ 1020e2c90b48SPatrick Rudolph ret = mp2975_identify_multiphase_rail2(client, data); 10212c6fcbb2SVadim Pasternak if (ret < 0) 10222c6fcbb2SVadim Pasternak return ret; 10232c6fcbb2SVadim Pasternak 10242c6fcbb2SVadim Pasternak if (ret) { 10252c6fcbb2SVadim Pasternak /* Two rails are connected. */ 10262c6fcbb2SVadim Pasternak data->info.pages = MP2975_PAGE_NUM; 10272c6fcbb2SVadim Pasternak data->info.phases[1] = ret; 10282c6fcbb2SVadim Pasternak data->info.func[1] = MP2975_RAIL2_FUNC; 102988fc1efcSPatrick Rudolph if (IS_ENABLED(CONFIG_SENSORS_MP2975_REGULATOR)) 103088fc1efcSPatrick Rudolph data->info.num_regulators = MP2975_PAGE_NUM; 10312c6fcbb2SVadim Pasternak } 10322c6fcbb2SVadim Pasternak 10332c6fcbb2SVadim Pasternak /* Identify multiphase configuration. */ 10342c6fcbb2SVadim Pasternak ret = mp2975_identify_multiphase(client, data, info); 10352c6fcbb2SVadim Pasternak if (ret) 10362c6fcbb2SVadim Pasternak return ret; 10372c6fcbb2SVadim Pasternak 103845f154dcSPatrick Rudolph if (data->chip_id == mp2975) { 10392c6fcbb2SVadim Pasternak /* Identify VID setting per rail. */ 10402c6fcbb2SVadim Pasternak ret = mp2975_identify_rails_vid(client, data, info); 10412c6fcbb2SVadim Pasternak if (ret < 0) 10422c6fcbb2SVadim Pasternak return ret; 10432c6fcbb2SVadim Pasternak 10442c6fcbb2SVadim Pasternak /* Obtain current sense gain of power stage. */ 10452c6fcbb2SVadim Pasternak ret = mp2975_current_sense_gain_get(client, data); 10462c6fcbb2SVadim Pasternak if (ret) 10472c6fcbb2SVadim Pasternak return ret; 10482c6fcbb2SVadim Pasternak 10492c6fcbb2SVadim Pasternak /* Obtain voltage reference values. */ 10502c6fcbb2SVadim Pasternak ret = mp2975_vref_get(client, data, info); 10512c6fcbb2SVadim Pasternak if (ret) 10522c6fcbb2SVadim Pasternak return ret; 10532c6fcbb2SVadim Pasternak 10542c6fcbb2SVadim Pasternak /* Obtain vout over-voltage scales. */ 10552c6fcbb2SVadim Pasternak ret = mp2975_vout_ov_scale_get(client, data, info); 10562c6fcbb2SVadim Pasternak if (ret < 0) 10572c6fcbb2SVadim Pasternak return ret; 10585239277eSPatrick Rudolph } else { 10595239277eSPatrick Rudolph /* Identify VID setting per rail. */ 10605239277eSPatrick Rudolph ret = mp2973_identify_rails_vid(client, data, info); 10615239277eSPatrick Rudolph if (ret < 0) 10625239277eSPatrick Rudolph return ret; 10635239277eSPatrick Rudolph } 10642c6fcbb2SVadim Pasternak 10652c6fcbb2SVadim Pasternak /* Obtain offsets, maximum and format for vout. */ 10662c6fcbb2SVadim Pasternak ret = mp2975_vout_per_rail_config_get(client, data, info); 10672c6fcbb2SVadim Pasternak if (ret) 10682c6fcbb2SVadim Pasternak return ret; 10692c6fcbb2SVadim Pasternak 10702c6fcbb2SVadim Pasternak return pmbus_do_probe(client, info); 10712c6fcbb2SVadim Pasternak } 10722c6fcbb2SVadim Pasternak 10732c6fcbb2SVadim Pasternak static const struct of_device_id __maybe_unused mp2975_of_match[] = { 10745239277eSPatrick Rudolph {.compatible = "mps,mp2971", .data = (void *)mp2971}, 10755239277eSPatrick Rudolph {.compatible = "mps,mp2973", .data = (void *)mp2973}, 10761f6f34d0SPatrick Rudolph {.compatible = "mps,mp2975", .data = (void *)mp2975}, 10772c6fcbb2SVadim Pasternak {} 10782c6fcbb2SVadim Pasternak }; 10792c6fcbb2SVadim Pasternak MODULE_DEVICE_TABLE(of, mp2975_of_match); 10802c6fcbb2SVadim Pasternak 10812c6fcbb2SVadim Pasternak static struct i2c_driver mp2975_driver = { 10822c6fcbb2SVadim Pasternak .driver = { 10832c6fcbb2SVadim Pasternak .name = "mp2975", 10842c6fcbb2SVadim Pasternak .of_match_table = of_match_ptr(mp2975_of_match), 10852c6fcbb2SVadim Pasternak }, 10861975d167SUwe Kleine-König .probe = mp2975_probe, 10872c6fcbb2SVadim Pasternak .id_table = mp2975_id, 10882c6fcbb2SVadim Pasternak }; 10892c6fcbb2SVadim Pasternak 10902c6fcbb2SVadim Pasternak module_i2c_driver(mp2975_driver); 10912c6fcbb2SVadim Pasternak 10922c6fcbb2SVadim Pasternak MODULE_AUTHOR("Vadim Pasternak <vadimp@nvidia.com>"); 10932c6fcbb2SVadim Pasternak MODULE_DESCRIPTION("PMBus driver for MPS MP2975 device"); 10942c6fcbb2SVadim Pasternak MODULE_LICENSE("GPL"); 1095b94ca77eSGuenter Roeck MODULE_IMPORT_NS(PMBUS); 1096