159dfa75eSEric Tremblay // SPDX-License-Identifier: GPL-2.0 259dfa75eSEric Tremblay /* 359dfa75eSEric Tremblay * Driver for Texas Instruments TMP512, TMP513 power monitor chips 459dfa75eSEric Tremblay * 559dfa75eSEric Tremblay * TMP513: 659dfa75eSEric Tremblay * Thermal/Power Management with Triple Remote and 759dfa75eSEric Tremblay * Local Temperature Sensor and Current Shunt Monitor 8e263f2d3SAlexander A. Klimov * Datasheet: https://www.ti.com/lit/gpn/tmp513 959dfa75eSEric Tremblay * 1059dfa75eSEric Tremblay * TMP512: 1159dfa75eSEric Tremblay * Thermal/Power Management with Dual Remote 1259dfa75eSEric Tremblay * and Local Temperature Sensor and Current Shunt Monitor 13e263f2d3SAlexander A. Klimov * Datasheet: https://www.ti.com/lit/gpn/tmp512 1459dfa75eSEric Tremblay * 1559dfa75eSEric Tremblay * Copyright (C) 2019 Eric Tremblay <etremblay@distech-controls.com> 1659dfa75eSEric Tremblay * 1759dfa75eSEric Tremblay * This program is free software; you can redistribute it and/or modify 1859dfa75eSEric Tremblay * it under the terms of the GNU General Public License as published by 1959dfa75eSEric Tremblay * the Free Software Foundation; version 2 of the License. 2059dfa75eSEric Tremblay */ 2159dfa75eSEric Tremblay 225d9ad4e0SAndy Shevchenko #include <linux/bitops.h> 235d9ad4e0SAndy Shevchenko #include <linux/bug.h> 245d9ad4e0SAndy Shevchenko #include <linux/device.h> 2559dfa75eSEric Tremblay #include <linux/err.h> 2659dfa75eSEric Tremblay #include <linux/hwmon.h> 2759dfa75eSEric Tremblay #include <linux/i2c.h> 2859dfa75eSEric Tremblay #include <linux/init.h> 295d9ad4e0SAndy Shevchenko #include <linux/math.h> 3059dfa75eSEric Tremblay #include <linux/module.h> 315d9ad4e0SAndy Shevchenko #include <linux/property.h> 3259dfa75eSEric Tremblay #include <linux/regmap.h> 3359dfa75eSEric Tremblay #include <linux/slab.h> 345d9ad4e0SAndy Shevchenko #include <linux/types.h> 3559dfa75eSEric Tremblay 3659dfa75eSEric Tremblay // Common register definition 3759dfa75eSEric Tremblay #define TMP51X_SHUNT_CONFIG 0x00 3859dfa75eSEric Tremblay #define TMP51X_TEMP_CONFIG 0x01 3959dfa75eSEric Tremblay #define TMP51X_STATUS 0x02 4059dfa75eSEric Tremblay #define TMP51X_SMBUS_ALERT 0x03 4159dfa75eSEric Tremblay #define TMP51X_SHUNT_CURRENT_RESULT 0x04 4259dfa75eSEric Tremblay #define TMP51X_BUS_VOLTAGE_RESULT 0x05 4359dfa75eSEric Tremblay #define TMP51X_POWER_RESULT 0x06 4459dfa75eSEric Tremblay #define TMP51X_BUS_CURRENT_RESULT 0x07 4559dfa75eSEric Tremblay #define TMP51X_LOCAL_TEMP_RESULT 0x08 4659dfa75eSEric Tremblay #define TMP51X_REMOTE_TEMP_RESULT_1 0x09 4759dfa75eSEric Tremblay #define TMP51X_REMOTE_TEMP_RESULT_2 0x0A 4859dfa75eSEric Tremblay #define TMP51X_SHUNT_CURRENT_H_LIMIT 0x0C 4959dfa75eSEric Tremblay #define TMP51X_SHUNT_CURRENT_L_LIMIT 0x0D 5059dfa75eSEric Tremblay #define TMP51X_BUS_VOLTAGE_H_LIMIT 0x0E 5159dfa75eSEric Tremblay #define TMP51X_BUS_VOLTAGE_L_LIMIT 0x0F 5259dfa75eSEric Tremblay #define TMP51X_POWER_LIMIT 0x10 5359dfa75eSEric Tremblay #define TMP51X_LOCAL_TEMP_LIMIT 0x11 5459dfa75eSEric Tremblay #define TMP51X_REMOTE_TEMP_LIMIT_1 0x12 5559dfa75eSEric Tremblay #define TMP51X_REMOTE_TEMP_LIMIT_2 0x13 5659dfa75eSEric Tremblay #define TMP51X_SHUNT_CALIBRATION 0x15 5759dfa75eSEric Tremblay #define TMP51X_N_FACTOR_AND_HYST_1 0x16 5859dfa75eSEric Tremblay #define TMP51X_N_FACTOR_2 0x17 5959dfa75eSEric Tremblay #define TMP51X_MAN_ID_REG 0xFE 6059dfa75eSEric Tremblay #define TMP51X_DEVICE_ID_REG 0xFF 6159dfa75eSEric Tremblay 6259dfa75eSEric Tremblay // TMP513 specific register definition 6359dfa75eSEric Tremblay #define TMP513_REMOTE_TEMP_RESULT_3 0x0B 6459dfa75eSEric Tremblay #define TMP513_REMOTE_TEMP_LIMIT_3 0x14 6559dfa75eSEric Tremblay #define TMP513_N_FACTOR_3 0x18 6659dfa75eSEric Tremblay 6759dfa75eSEric Tremblay // Common attrs, and NULL 6859dfa75eSEric Tremblay #define TMP51X_MANUFACTURER_ID 0x55FF 6959dfa75eSEric Tremblay 7059dfa75eSEric Tremblay #define TMP512_DEVICE_ID 0x22FF 7159dfa75eSEric Tremblay #define TMP513_DEVICE_ID 0x23FF 7259dfa75eSEric Tremblay 7359dfa75eSEric Tremblay // Default config 7459dfa75eSEric Tremblay #define TMP51X_SHUNT_CONFIG_DEFAULT 0x399F 7559dfa75eSEric Tremblay #define TMP51X_SHUNT_VALUE_DEFAULT 1000 7659dfa75eSEric Tremblay #define TMP51X_VBUS_RANGE_DEFAULT TMP51X_VBUS_RANGE_32V 7759dfa75eSEric Tremblay #define TMP51X_PGA_DEFAULT 8 7859dfa75eSEric Tremblay #define TMP51X_MAX_REGISTER_ADDR 0xFF 7959dfa75eSEric Tremblay 8059dfa75eSEric Tremblay // Mask and shift 8159dfa75eSEric Tremblay #define CURRENT_SENSE_VOLTAGE_320_MASK 0x1800 8259dfa75eSEric Tremblay #define CURRENT_SENSE_VOLTAGE_160_MASK 0x1000 8359dfa75eSEric Tremblay #define CURRENT_SENSE_VOLTAGE_80_MASK 0x0800 8459dfa75eSEric Tremblay #define CURRENT_SENSE_VOLTAGE_40_MASK 0 8559dfa75eSEric Tremblay 8659dfa75eSEric Tremblay #define TMP51X_BUS_VOLTAGE_MASK 0x2000 8759dfa75eSEric Tremblay #define TMP51X_NFACTOR_MASK 0xFF00 8859dfa75eSEric Tremblay #define TMP51X_HYST_MASK 0x00FF 8959dfa75eSEric Tremblay 9059dfa75eSEric Tremblay #define TMP51X_BUS_VOLTAGE_SHIFT 3 9159dfa75eSEric Tremblay #define TMP51X_TEMP_SHIFT 3 9259dfa75eSEric Tremblay 9359dfa75eSEric Tremblay // Alarms 9459dfa75eSEric Tremblay #define TMP51X_SHUNT_CURRENT_H_LIMIT_POS 15 9559dfa75eSEric Tremblay #define TMP51X_SHUNT_CURRENT_L_LIMIT_POS 14 9659dfa75eSEric Tremblay #define TMP51X_BUS_VOLTAGE_H_LIMIT_POS 13 9759dfa75eSEric Tremblay #define TMP51X_BUS_VOLTAGE_L_LIMIT_POS 12 9859dfa75eSEric Tremblay #define TMP51X_POWER_LIMIT_POS 11 9959dfa75eSEric Tremblay #define TMP51X_LOCAL_TEMP_LIMIT_POS 10 10059dfa75eSEric Tremblay #define TMP51X_REMOTE_TEMP_LIMIT_1_POS 9 10159dfa75eSEric Tremblay #define TMP51X_REMOTE_TEMP_LIMIT_2_POS 8 10259dfa75eSEric Tremblay #define TMP513_REMOTE_TEMP_LIMIT_3_POS 7 10359dfa75eSEric Tremblay 10459dfa75eSEric Tremblay #define TMP51X_VBUS_RANGE_32V 32000000 10559dfa75eSEric Tremblay #define TMP51X_VBUS_RANGE_16V 16000000 10659dfa75eSEric Tremblay 10759dfa75eSEric Tremblay // Max and Min value 10859dfa75eSEric Tremblay #define MAX_BUS_VOLTAGE_32_LIMIT 32764 10959dfa75eSEric Tremblay #define MAX_BUS_VOLTAGE_16_LIMIT 16382 11059dfa75eSEric Tremblay 11159dfa75eSEric Tremblay // Max possible value is -256 to +256 but datasheet indicated -40 to 125. 11259dfa75eSEric Tremblay #define MAX_TEMP_LIMIT 125000 11359dfa75eSEric Tremblay #define MIN_TEMP_LIMIT -40000 11459dfa75eSEric Tremblay 11559dfa75eSEric Tremblay #define MAX_TEMP_HYST 127500 11659dfa75eSEric Tremblay 117fb99e07aSBiju Das #define TMP512_MAX_CHANNELS 3 118fb99e07aSBiju Das #define TMP513_MAX_CHANNELS 4 119fb99e07aSBiju Das 120fb99e07aSBiju Das #define TMP51X_TEMP_CONFIG_CONV_RATE GENMASK(9, 7) 121fb99e07aSBiju Das #define TMP51X_TEMP_CONFIG_RC BIT(10) 122fb99e07aSBiju Das #define TMP51X_TEMP_CHANNEL_MASK(n) (GENMASK((n) - 1, 0) << 11) 123fb99e07aSBiju Das #define TMP51X_TEMP_CONFIG_CONT BIT(15) 124fb99e07aSBiju Das #define TMP51X_TEMP_CONFIG_DEFAULT(n) \ 125fb99e07aSBiju Das (TMP51X_TEMP_CHANNEL_MASK(n) | TMP51X_TEMP_CONFIG_CONT | \ 126fb99e07aSBiju Das TMP51X_TEMP_CONFIG_CONV_RATE | TMP51X_TEMP_CONFIG_RC) 127fb99e07aSBiju Das 12859dfa75eSEric Tremblay static const u8 TMP51X_TEMP_INPUT[4] = { 12959dfa75eSEric Tremblay TMP51X_LOCAL_TEMP_RESULT, 13059dfa75eSEric Tremblay TMP51X_REMOTE_TEMP_RESULT_1, 13159dfa75eSEric Tremblay TMP51X_REMOTE_TEMP_RESULT_2, 13259dfa75eSEric Tremblay TMP513_REMOTE_TEMP_RESULT_3 13359dfa75eSEric Tremblay }; 13459dfa75eSEric Tremblay 13559dfa75eSEric Tremblay static const u8 TMP51X_TEMP_CRIT[4] = { 13659dfa75eSEric Tremblay TMP51X_LOCAL_TEMP_LIMIT, 13759dfa75eSEric Tremblay TMP51X_REMOTE_TEMP_LIMIT_1, 13859dfa75eSEric Tremblay TMP51X_REMOTE_TEMP_LIMIT_2, 13959dfa75eSEric Tremblay TMP513_REMOTE_TEMP_LIMIT_3 14059dfa75eSEric Tremblay }; 14159dfa75eSEric Tremblay 14259dfa75eSEric Tremblay static const u8 TMP51X_TEMP_CRIT_ALARM[4] = { 14359dfa75eSEric Tremblay TMP51X_LOCAL_TEMP_LIMIT_POS, 14459dfa75eSEric Tremblay TMP51X_REMOTE_TEMP_LIMIT_1_POS, 14559dfa75eSEric Tremblay TMP51X_REMOTE_TEMP_LIMIT_2_POS, 14659dfa75eSEric Tremblay TMP513_REMOTE_TEMP_LIMIT_3_POS 14759dfa75eSEric Tremblay }; 14859dfa75eSEric Tremblay 14959dfa75eSEric Tremblay static const u8 TMP51X_TEMP_CRIT_HYST[4] = { 15059dfa75eSEric Tremblay TMP51X_N_FACTOR_AND_HYST_1, 15159dfa75eSEric Tremblay TMP51X_N_FACTOR_AND_HYST_1, 15259dfa75eSEric Tremblay TMP51X_N_FACTOR_AND_HYST_1, 15359dfa75eSEric Tremblay TMP51X_N_FACTOR_AND_HYST_1 15459dfa75eSEric Tremblay }; 15559dfa75eSEric Tremblay 15659dfa75eSEric Tremblay static const u8 TMP51X_CURR_INPUT[2] = { 15759dfa75eSEric Tremblay TMP51X_SHUNT_CURRENT_RESULT, 15859dfa75eSEric Tremblay TMP51X_BUS_CURRENT_RESULT 15959dfa75eSEric Tremblay }; 16059dfa75eSEric Tremblay 16159dfa75eSEric Tremblay static struct regmap_config tmp51x_regmap_config = { 16259dfa75eSEric Tremblay .reg_bits = 8, 16359dfa75eSEric Tremblay .val_bits = 16, 16459dfa75eSEric Tremblay .max_register = TMP51X_MAX_REGISTER_ADDR, 16559dfa75eSEric Tremblay }; 16659dfa75eSEric Tremblay 16759dfa75eSEric Tremblay struct tmp51x_data { 16859dfa75eSEric Tremblay u16 shunt_config; 16959dfa75eSEric Tremblay u16 pga_gain; 17059dfa75eSEric Tremblay u32 vbus_range_uvolt; 17159dfa75eSEric Tremblay 17259dfa75eSEric Tremblay u16 temp_config; 17359dfa75eSEric Tremblay u32 nfactor[3]; 17459dfa75eSEric Tremblay 17559dfa75eSEric Tremblay u32 shunt_uohms; 17659dfa75eSEric Tremblay 17759dfa75eSEric Tremblay u32 curr_lsb_ua; 17859dfa75eSEric Tremblay u32 pwr_lsb_uw; 17959dfa75eSEric Tremblay 180fb99e07aSBiju Das u8 max_channels; 18159dfa75eSEric Tremblay struct regmap *regmap; 18259dfa75eSEric Tremblay }; 18359dfa75eSEric Tremblay 18459dfa75eSEric Tremblay // Set the shift based on the gain 8=4, 4=3, 2=2, 1=1 18559dfa75eSEric Tremblay static inline u8 tmp51x_get_pga_shift(struct tmp51x_data *data) 18659dfa75eSEric Tremblay { 18759dfa75eSEric Tremblay return 5 - ffs(data->pga_gain); 18859dfa75eSEric Tremblay } 18959dfa75eSEric Tremblay 19059dfa75eSEric Tremblay static int tmp51x_get_value(struct tmp51x_data *data, u8 reg, u8 pos, 19159dfa75eSEric Tremblay unsigned int regval, long *val) 19259dfa75eSEric Tremblay { 19359dfa75eSEric Tremblay switch (reg) { 19459dfa75eSEric Tremblay case TMP51X_STATUS: 19559dfa75eSEric Tremblay *val = (regval >> pos) & 1; 19659dfa75eSEric Tremblay break; 19759dfa75eSEric Tremblay case TMP51X_SHUNT_CURRENT_RESULT: 19859dfa75eSEric Tremblay case TMP51X_SHUNT_CURRENT_H_LIMIT: 19959dfa75eSEric Tremblay case TMP51X_SHUNT_CURRENT_L_LIMIT: 20059dfa75eSEric Tremblay /* 20159dfa75eSEric Tremblay * The valus is read in voltage in the chip but reported as 20259dfa75eSEric Tremblay * current to the user. 203c073292bSWang Qing * 2's complement number shifted by one to four depending 20459dfa75eSEric Tremblay * on the pga gain setting. 1lsb = 10uV 20559dfa75eSEric Tremblay */ 20659dfa75eSEric Tremblay *val = sign_extend32(regval, 17 - tmp51x_get_pga_shift(data)); 20759dfa75eSEric Tremblay *val = DIV_ROUND_CLOSEST(*val * 10000, data->shunt_uohms); 20859dfa75eSEric Tremblay break; 20959dfa75eSEric Tremblay case TMP51X_BUS_VOLTAGE_RESULT: 21059dfa75eSEric Tremblay case TMP51X_BUS_VOLTAGE_H_LIMIT: 21159dfa75eSEric Tremblay case TMP51X_BUS_VOLTAGE_L_LIMIT: 21259dfa75eSEric Tremblay // 1lsb = 4mV 21359dfa75eSEric Tremblay *val = (regval >> TMP51X_BUS_VOLTAGE_SHIFT) * 4; 21459dfa75eSEric Tremblay break; 21559dfa75eSEric Tremblay case TMP51X_POWER_RESULT: 21659dfa75eSEric Tremblay case TMP51X_POWER_LIMIT: 21759dfa75eSEric Tremblay // Power = (current * BusVoltage) / 5000 21859dfa75eSEric Tremblay *val = regval * data->pwr_lsb_uw; 21959dfa75eSEric Tremblay break; 22059dfa75eSEric Tremblay case TMP51X_BUS_CURRENT_RESULT: 22159dfa75eSEric Tremblay // Current = (ShuntVoltage * CalibrationRegister) / 4096 22259dfa75eSEric Tremblay *val = sign_extend32(regval, 16) * data->curr_lsb_ua; 22359dfa75eSEric Tremblay *val = DIV_ROUND_CLOSEST(*val, 1000); 22459dfa75eSEric Tremblay break; 22559dfa75eSEric Tremblay case TMP51X_LOCAL_TEMP_RESULT: 22659dfa75eSEric Tremblay case TMP51X_REMOTE_TEMP_RESULT_1: 22759dfa75eSEric Tremblay case TMP51X_REMOTE_TEMP_RESULT_2: 22859dfa75eSEric Tremblay case TMP513_REMOTE_TEMP_RESULT_3: 22959dfa75eSEric Tremblay case TMP51X_LOCAL_TEMP_LIMIT: 23059dfa75eSEric Tremblay case TMP51X_REMOTE_TEMP_LIMIT_1: 23159dfa75eSEric Tremblay case TMP51X_REMOTE_TEMP_LIMIT_2: 23259dfa75eSEric Tremblay case TMP513_REMOTE_TEMP_LIMIT_3: 23359dfa75eSEric Tremblay // 1lsb = 0.0625 degrees centigrade 23459dfa75eSEric Tremblay *val = sign_extend32(regval, 16) >> TMP51X_TEMP_SHIFT; 23559dfa75eSEric Tremblay *val = DIV_ROUND_CLOSEST(*val * 625, 10); 23659dfa75eSEric Tremblay break; 23759dfa75eSEric Tremblay case TMP51X_N_FACTOR_AND_HYST_1: 23859dfa75eSEric Tremblay // 1lsb = 0.5 degrees centigrade 23959dfa75eSEric Tremblay *val = (regval & TMP51X_HYST_MASK) * 500; 24059dfa75eSEric Tremblay break; 24159dfa75eSEric Tremblay default: 24259dfa75eSEric Tremblay // Programmer goofed 24359dfa75eSEric Tremblay WARN_ON_ONCE(1); 24459dfa75eSEric Tremblay *val = 0; 24559dfa75eSEric Tremblay return -EOPNOTSUPP; 24659dfa75eSEric Tremblay } 24759dfa75eSEric Tremblay 24859dfa75eSEric Tremblay return 0; 24959dfa75eSEric Tremblay } 25059dfa75eSEric Tremblay 25159dfa75eSEric Tremblay static int tmp51x_set_value(struct tmp51x_data *data, u8 reg, long val) 25259dfa75eSEric Tremblay { 25359dfa75eSEric Tremblay int regval, max_val; 25459dfa75eSEric Tremblay u32 mask = 0; 25559dfa75eSEric Tremblay 25659dfa75eSEric Tremblay switch (reg) { 25759dfa75eSEric Tremblay case TMP51X_SHUNT_CURRENT_H_LIMIT: 25859dfa75eSEric Tremblay case TMP51X_SHUNT_CURRENT_L_LIMIT: 25959dfa75eSEric Tremblay /* 26059dfa75eSEric Tremblay * The user enter current value and we convert it to 26159dfa75eSEric Tremblay * voltage. 1lsb = 10uV 26259dfa75eSEric Tremblay */ 26359dfa75eSEric Tremblay val = DIV_ROUND_CLOSEST(val * data->shunt_uohms, 10000); 26459dfa75eSEric Tremblay max_val = U16_MAX >> tmp51x_get_pga_shift(data); 26559dfa75eSEric Tremblay regval = clamp_val(val, -max_val, max_val); 26659dfa75eSEric Tremblay break; 26759dfa75eSEric Tremblay case TMP51X_BUS_VOLTAGE_H_LIMIT: 26859dfa75eSEric Tremblay case TMP51X_BUS_VOLTAGE_L_LIMIT: 26959dfa75eSEric Tremblay // 1lsb = 4mV 27059dfa75eSEric Tremblay max_val = (data->vbus_range_uvolt == TMP51X_VBUS_RANGE_32V) ? 27159dfa75eSEric Tremblay MAX_BUS_VOLTAGE_32_LIMIT : MAX_BUS_VOLTAGE_16_LIMIT; 27259dfa75eSEric Tremblay 27359dfa75eSEric Tremblay val = clamp_val(DIV_ROUND_CLOSEST(val, 4), 0, max_val); 27459dfa75eSEric Tremblay regval = val << TMP51X_BUS_VOLTAGE_SHIFT; 27559dfa75eSEric Tremblay break; 27659dfa75eSEric Tremblay case TMP51X_POWER_LIMIT: 27759dfa75eSEric Tremblay regval = clamp_val(DIV_ROUND_CLOSEST(val, data->pwr_lsb_uw), 0, 27859dfa75eSEric Tremblay U16_MAX); 27959dfa75eSEric Tremblay break; 28059dfa75eSEric Tremblay case TMP51X_LOCAL_TEMP_LIMIT: 28159dfa75eSEric Tremblay case TMP51X_REMOTE_TEMP_LIMIT_1: 28259dfa75eSEric Tremblay case TMP51X_REMOTE_TEMP_LIMIT_2: 28359dfa75eSEric Tremblay case TMP513_REMOTE_TEMP_LIMIT_3: 28459dfa75eSEric Tremblay // 1lsb = 0.0625 degrees centigrade 28559dfa75eSEric Tremblay val = clamp_val(val, MIN_TEMP_LIMIT, MAX_TEMP_LIMIT); 28659dfa75eSEric Tremblay regval = DIV_ROUND_CLOSEST(val * 10, 625) << TMP51X_TEMP_SHIFT; 28759dfa75eSEric Tremblay break; 28859dfa75eSEric Tremblay case TMP51X_N_FACTOR_AND_HYST_1: 28959dfa75eSEric Tremblay // 1lsb = 0.5 degrees centigrade 29059dfa75eSEric Tremblay val = clamp_val(val, 0, MAX_TEMP_HYST); 29159dfa75eSEric Tremblay regval = DIV_ROUND_CLOSEST(val, 500); 29259dfa75eSEric Tremblay mask = TMP51X_HYST_MASK; 29359dfa75eSEric Tremblay break; 29459dfa75eSEric Tremblay default: 29559dfa75eSEric Tremblay // Programmer goofed 29659dfa75eSEric Tremblay WARN_ON_ONCE(1); 29759dfa75eSEric Tremblay return -EOPNOTSUPP; 29859dfa75eSEric Tremblay } 29959dfa75eSEric Tremblay 30059dfa75eSEric Tremblay if (mask == 0) 30159dfa75eSEric Tremblay return regmap_write(data->regmap, reg, regval); 30259dfa75eSEric Tremblay else 30359dfa75eSEric Tremblay return regmap_update_bits(data->regmap, reg, mask, regval); 30459dfa75eSEric Tremblay } 30559dfa75eSEric Tremblay 30659dfa75eSEric Tremblay static u8 tmp51x_get_reg(enum hwmon_sensor_types type, u32 attr, int channel) 30759dfa75eSEric Tremblay { 30859dfa75eSEric Tremblay switch (type) { 30959dfa75eSEric Tremblay case hwmon_temp: 31059dfa75eSEric Tremblay switch (attr) { 31159dfa75eSEric Tremblay case hwmon_temp_input: 31259dfa75eSEric Tremblay return TMP51X_TEMP_INPUT[channel]; 31359dfa75eSEric Tremblay case hwmon_temp_crit_alarm: 31459dfa75eSEric Tremblay return TMP51X_STATUS; 31559dfa75eSEric Tremblay case hwmon_temp_crit: 31659dfa75eSEric Tremblay return TMP51X_TEMP_CRIT[channel]; 31759dfa75eSEric Tremblay case hwmon_temp_crit_hyst: 31859dfa75eSEric Tremblay return TMP51X_TEMP_CRIT_HYST[channel]; 31959dfa75eSEric Tremblay } 32059dfa75eSEric Tremblay break; 32159dfa75eSEric Tremblay case hwmon_in: 32259dfa75eSEric Tremblay switch (attr) { 32359dfa75eSEric Tremblay case hwmon_in_input: 32459dfa75eSEric Tremblay return TMP51X_BUS_VOLTAGE_RESULT; 32559dfa75eSEric Tremblay case hwmon_in_lcrit_alarm: 32659dfa75eSEric Tremblay case hwmon_in_crit_alarm: 32759dfa75eSEric Tremblay return TMP51X_STATUS; 32859dfa75eSEric Tremblay case hwmon_in_lcrit: 32959dfa75eSEric Tremblay return TMP51X_BUS_VOLTAGE_L_LIMIT; 33059dfa75eSEric Tremblay case hwmon_in_crit: 33159dfa75eSEric Tremblay return TMP51X_BUS_VOLTAGE_H_LIMIT; 33259dfa75eSEric Tremblay } 33359dfa75eSEric Tremblay break; 33459dfa75eSEric Tremblay case hwmon_curr: 33559dfa75eSEric Tremblay switch (attr) { 33659dfa75eSEric Tremblay case hwmon_curr_input: 33759dfa75eSEric Tremblay return TMP51X_CURR_INPUT[channel]; 33859dfa75eSEric Tremblay case hwmon_curr_lcrit_alarm: 33959dfa75eSEric Tremblay case hwmon_curr_crit_alarm: 34059dfa75eSEric Tremblay return TMP51X_STATUS; 34159dfa75eSEric Tremblay case hwmon_curr_lcrit: 34259dfa75eSEric Tremblay return TMP51X_SHUNT_CURRENT_L_LIMIT; 34359dfa75eSEric Tremblay case hwmon_curr_crit: 34459dfa75eSEric Tremblay return TMP51X_SHUNT_CURRENT_H_LIMIT; 34559dfa75eSEric Tremblay } 34659dfa75eSEric Tremblay break; 34759dfa75eSEric Tremblay case hwmon_power: 34859dfa75eSEric Tremblay switch (attr) { 34959dfa75eSEric Tremblay case hwmon_power_input: 35059dfa75eSEric Tremblay return TMP51X_POWER_RESULT; 35159dfa75eSEric Tremblay case hwmon_power_crit_alarm: 35259dfa75eSEric Tremblay return TMP51X_STATUS; 35359dfa75eSEric Tremblay case hwmon_power_crit: 35459dfa75eSEric Tremblay return TMP51X_POWER_LIMIT; 35559dfa75eSEric Tremblay } 35659dfa75eSEric Tremblay break; 35759dfa75eSEric Tremblay default: 35859dfa75eSEric Tremblay break; 35959dfa75eSEric Tremblay } 36059dfa75eSEric Tremblay 36159dfa75eSEric Tremblay return 0; 36259dfa75eSEric Tremblay } 36359dfa75eSEric Tremblay 36459dfa75eSEric Tremblay static u8 tmp51x_get_status_pos(enum hwmon_sensor_types type, u32 attr, 36559dfa75eSEric Tremblay int channel) 36659dfa75eSEric Tremblay { 36759dfa75eSEric Tremblay switch (type) { 36859dfa75eSEric Tremblay case hwmon_temp: 36959dfa75eSEric Tremblay switch (attr) { 37059dfa75eSEric Tremblay case hwmon_temp_crit_alarm: 37159dfa75eSEric Tremblay return TMP51X_TEMP_CRIT_ALARM[channel]; 37259dfa75eSEric Tremblay } 37359dfa75eSEric Tremblay break; 37459dfa75eSEric Tremblay case hwmon_in: 37559dfa75eSEric Tremblay switch (attr) { 37659dfa75eSEric Tremblay case hwmon_in_lcrit_alarm: 37759dfa75eSEric Tremblay return TMP51X_BUS_VOLTAGE_L_LIMIT_POS; 37859dfa75eSEric Tremblay case hwmon_in_crit_alarm: 37959dfa75eSEric Tremblay return TMP51X_BUS_VOLTAGE_H_LIMIT_POS; 38059dfa75eSEric Tremblay } 38159dfa75eSEric Tremblay break; 38259dfa75eSEric Tremblay case hwmon_curr: 38359dfa75eSEric Tremblay switch (attr) { 38459dfa75eSEric Tremblay case hwmon_curr_lcrit_alarm: 38559dfa75eSEric Tremblay return TMP51X_SHUNT_CURRENT_L_LIMIT_POS; 38659dfa75eSEric Tremblay case hwmon_curr_crit_alarm: 38759dfa75eSEric Tremblay return TMP51X_SHUNT_CURRENT_H_LIMIT_POS; 38859dfa75eSEric Tremblay } 38959dfa75eSEric Tremblay break; 39059dfa75eSEric Tremblay case hwmon_power: 39159dfa75eSEric Tremblay switch (attr) { 39259dfa75eSEric Tremblay case hwmon_power_crit_alarm: 39359dfa75eSEric Tremblay return TMP51X_POWER_LIMIT_POS; 39459dfa75eSEric Tremblay } 39559dfa75eSEric Tremblay break; 39659dfa75eSEric Tremblay default: 39759dfa75eSEric Tremblay break; 39859dfa75eSEric Tremblay } 39959dfa75eSEric Tremblay 40059dfa75eSEric Tremblay return 0; 40159dfa75eSEric Tremblay } 40259dfa75eSEric Tremblay 40359dfa75eSEric Tremblay static int tmp51x_read(struct device *dev, enum hwmon_sensor_types type, 40459dfa75eSEric Tremblay u32 attr, int channel, long *val) 40559dfa75eSEric Tremblay { 40659dfa75eSEric Tremblay struct tmp51x_data *data = dev_get_drvdata(dev); 40759dfa75eSEric Tremblay int ret; 40859dfa75eSEric Tremblay u32 regval; 40959dfa75eSEric Tremblay u8 pos = 0, reg = 0; 41059dfa75eSEric Tremblay 41159dfa75eSEric Tremblay reg = tmp51x_get_reg(type, attr, channel); 41259dfa75eSEric Tremblay if (reg == 0) 41359dfa75eSEric Tremblay return -EOPNOTSUPP; 41459dfa75eSEric Tremblay 41559dfa75eSEric Tremblay if (reg == TMP51X_STATUS) 41659dfa75eSEric Tremblay pos = tmp51x_get_status_pos(type, attr, channel); 41759dfa75eSEric Tremblay 41859dfa75eSEric Tremblay ret = regmap_read(data->regmap, reg, ®val); 41959dfa75eSEric Tremblay if (ret < 0) 42059dfa75eSEric Tremblay return ret; 42159dfa75eSEric Tremblay 42259dfa75eSEric Tremblay return tmp51x_get_value(data, reg, pos, regval, val); 42359dfa75eSEric Tremblay } 42459dfa75eSEric Tremblay 42559dfa75eSEric Tremblay static int tmp51x_write(struct device *dev, enum hwmon_sensor_types type, 42659dfa75eSEric Tremblay u32 attr, int channel, long val) 42759dfa75eSEric Tremblay { 42859dfa75eSEric Tremblay u8 reg = 0; 42959dfa75eSEric Tremblay 43059dfa75eSEric Tremblay reg = tmp51x_get_reg(type, attr, channel); 43159dfa75eSEric Tremblay if (reg == 0) 43259dfa75eSEric Tremblay return -EOPNOTSUPP; 43359dfa75eSEric Tremblay 43459dfa75eSEric Tremblay return tmp51x_set_value(dev_get_drvdata(dev), reg, val); 43559dfa75eSEric Tremblay } 43659dfa75eSEric Tremblay 43759dfa75eSEric Tremblay static umode_t tmp51x_is_visible(const void *_data, 43859dfa75eSEric Tremblay enum hwmon_sensor_types type, u32 attr, 43959dfa75eSEric Tremblay int channel) 44059dfa75eSEric Tremblay { 44159dfa75eSEric Tremblay const struct tmp51x_data *data = _data; 44259dfa75eSEric Tremblay 44359dfa75eSEric Tremblay switch (type) { 44459dfa75eSEric Tremblay case hwmon_temp: 445fb99e07aSBiju Das if (channel >= data->max_channels) 44659dfa75eSEric Tremblay return 0; 44759dfa75eSEric Tremblay switch (attr) { 44859dfa75eSEric Tremblay case hwmon_temp_input: 44959dfa75eSEric Tremblay case hwmon_temp_crit_alarm: 45059dfa75eSEric Tremblay return 0444; 45159dfa75eSEric Tremblay case hwmon_temp_crit: 45259dfa75eSEric Tremblay return 0644; 45359dfa75eSEric Tremblay case hwmon_temp_crit_hyst: 45459dfa75eSEric Tremblay if (channel == 0) 45559dfa75eSEric Tremblay return 0644; 45659dfa75eSEric Tremblay return 0444; 45759dfa75eSEric Tremblay } 45859dfa75eSEric Tremblay break; 45959dfa75eSEric Tremblay case hwmon_in: 46059dfa75eSEric Tremblay switch (attr) { 46159dfa75eSEric Tremblay case hwmon_in_input: 46259dfa75eSEric Tremblay case hwmon_in_lcrit_alarm: 46359dfa75eSEric Tremblay case hwmon_in_crit_alarm: 46459dfa75eSEric Tremblay return 0444; 46559dfa75eSEric Tremblay case hwmon_in_lcrit: 46659dfa75eSEric Tremblay case hwmon_in_crit: 46759dfa75eSEric Tremblay return 0644; 46859dfa75eSEric Tremblay } 46959dfa75eSEric Tremblay break; 47059dfa75eSEric Tremblay case hwmon_curr: 47159dfa75eSEric Tremblay if (!data->shunt_uohms) 47259dfa75eSEric Tremblay return 0; 47359dfa75eSEric Tremblay 47459dfa75eSEric Tremblay switch (attr) { 47559dfa75eSEric Tremblay case hwmon_curr_input: 47659dfa75eSEric Tremblay case hwmon_curr_lcrit_alarm: 47759dfa75eSEric Tremblay case hwmon_curr_crit_alarm: 47859dfa75eSEric Tremblay return 0444; 47959dfa75eSEric Tremblay case hwmon_curr_lcrit: 48059dfa75eSEric Tremblay case hwmon_curr_crit: 48159dfa75eSEric Tremblay return 0644; 48259dfa75eSEric Tremblay } 48359dfa75eSEric Tremblay break; 48459dfa75eSEric Tremblay case hwmon_power: 48559dfa75eSEric Tremblay if (!data->shunt_uohms) 48659dfa75eSEric Tremblay return 0; 48759dfa75eSEric Tremblay 48859dfa75eSEric Tremblay switch (attr) { 48959dfa75eSEric Tremblay case hwmon_power_input: 49059dfa75eSEric Tremblay case hwmon_power_crit_alarm: 49159dfa75eSEric Tremblay return 0444; 49259dfa75eSEric Tremblay case hwmon_power_crit: 49359dfa75eSEric Tremblay return 0644; 49459dfa75eSEric Tremblay } 49559dfa75eSEric Tremblay break; 49659dfa75eSEric Tremblay default: 49759dfa75eSEric Tremblay break; 49859dfa75eSEric Tremblay } 49959dfa75eSEric Tremblay return 0; 50059dfa75eSEric Tremblay } 50159dfa75eSEric Tremblay 502b39c94a1SKrzysztof Kozlowski static const struct hwmon_channel_info * const tmp51x_info[] = { 50359dfa75eSEric Tremblay HWMON_CHANNEL_INFO(temp, 50459dfa75eSEric Tremblay HWMON_T_INPUT | HWMON_T_CRIT | HWMON_T_CRIT_ALARM | 50559dfa75eSEric Tremblay HWMON_T_CRIT_HYST, 50659dfa75eSEric Tremblay HWMON_T_INPUT | HWMON_T_CRIT | HWMON_T_CRIT_ALARM | 50759dfa75eSEric Tremblay HWMON_T_CRIT_HYST, 50859dfa75eSEric Tremblay HWMON_T_INPUT | HWMON_T_CRIT | HWMON_T_CRIT_ALARM | 50959dfa75eSEric Tremblay HWMON_T_CRIT_HYST, 51059dfa75eSEric Tremblay HWMON_T_INPUT | HWMON_T_CRIT | HWMON_T_CRIT_ALARM | 51159dfa75eSEric Tremblay HWMON_T_CRIT_HYST), 51259dfa75eSEric Tremblay HWMON_CHANNEL_INFO(in, 51359dfa75eSEric Tremblay HWMON_I_INPUT | HWMON_I_LCRIT | HWMON_I_LCRIT_ALARM | 51459dfa75eSEric Tremblay HWMON_I_CRIT | HWMON_I_CRIT_ALARM), 51559dfa75eSEric Tremblay HWMON_CHANNEL_INFO(curr, 51659dfa75eSEric Tremblay HWMON_C_INPUT | HWMON_C_LCRIT | HWMON_C_LCRIT_ALARM | 51759dfa75eSEric Tremblay HWMON_C_CRIT | HWMON_C_CRIT_ALARM, 51859dfa75eSEric Tremblay HWMON_C_INPUT), 51959dfa75eSEric Tremblay HWMON_CHANNEL_INFO(power, 52059dfa75eSEric Tremblay HWMON_P_INPUT | HWMON_P_CRIT | HWMON_P_CRIT_ALARM), 52159dfa75eSEric Tremblay NULL 52259dfa75eSEric Tremblay }; 52359dfa75eSEric Tremblay 52459dfa75eSEric Tremblay static const struct hwmon_ops tmp51x_hwmon_ops = { 52559dfa75eSEric Tremblay .is_visible = tmp51x_is_visible, 52659dfa75eSEric Tremblay .read = tmp51x_read, 52759dfa75eSEric Tremblay .write = tmp51x_write, 52859dfa75eSEric Tremblay }; 52959dfa75eSEric Tremblay 53059dfa75eSEric Tremblay static const struct hwmon_chip_info tmp51x_chip_info = { 53159dfa75eSEric Tremblay .ops = &tmp51x_hwmon_ops, 53259dfa75eSEric Tremblay .info = tmp51x_info, 53359dfa75eSEric Tremblay }; 53459dfa75eSEric Tremblay 53559dfa75eSEric Tremblay /* 53659dfa75eSEric Tremblay * Calibrate the tmp51x following the datasheet method 53759dfa75eSEric Tremblay */ 53859dfa75eSEric Tremblay static int tmp51x_calibrate(struct tmp51x_data *data) 53959dfa75eSEric Tremblay { 54059dfa75eSEric Tremblay int vshunt_max = data->pga_gain * 40; 54159dfa75eSEric Tremblay u64 max_curr_ma; 54259dfa75eSEric Tremblay u32 div; 54359dfa75eSEric Tremblay 54459dfa75eSEric Tremblay /* 54559dfa75eSEric Tremblay * If shunt_uohms is equal to 0, the calibration should be set to 0. 54659dfa75eSEric Tremblay * The consequence will be that the current and power measurement engine 54759dfa75eSEric Tremblay * of the sensor will not work. Temperature and voltage sensing will 54859dfa75eSEric Tremblay * continue to work. 54959dfa75eSEric Tremblay */ 55059dfa75eSEric Tremblay if (data->shunt_uohms == 0) 55159dfa75eSEric Tremblay return regmap_write(data->regmap, TMP51X_SHUNT_CALIBRATION, 0); 55259dfa75eSEric Tremblay 55359dfa75eSEric Tremblay max_curr_ma = DIV_ROUND_CLOSEST_ULL(vshunt_max * 1000 * 1000, 55459dfa75eSEric Tremblay data->shunt_uohms); 55559dfa75eSEric Tremblay 55659dfa75eSEric Tremblay /* 55759dfa75eSEric Tremblay * Calculate the minimal bit resolution for the current and the power. 55859dfa75eSEric Tremblay * Those values will be used during register interpretation. 55959dfa75eSEric Tremblay */ 56059dfa75eSEric Tremblay data->curr_lsb_ua = DIV_ROUND_CLOSEST_ULL(max_curr_ma * 1000, 32767); 56159dfa75eSEric Tremblay data->pwr_lsb_uw = 20 * data->curr_lsb_ua; 56259dfa75eSEric Tremblay 56359dfa75eSEric Tremblay div = DIV_ROUND_CLOSEST_ULL(data->curr_lsb_ua * data->shunt_uohms, 56459dfa75eSEric Tremblay 1000 * 1000); 56559dfa75eSEric Tremblay 56659dfa75eSEric Tremblay return regmap_write(data->regmap, TMP51X_SHUNT_CALIBRATION, 56759dfa75eSEric Tremblay DIV_ROUND_CLOSEST(40960, div)); 56859dfa75eSEric Tremblay } 56959dfa75eSEric Tremblay 57059dfa75eSEric Tremblay /* 57159dfa75eSEric Tremblay * Initialize the configuration and calibration registers. 57259dfa75eSEric Tremblay */ 57359dfa75eSEric Tremblay static int tmp51x_init(struct tmp51x_data *data) 57459dfa75eSEric Tremblay { 57559dfa75eSEric Tremblay unsigned int regval; 57659dfa75eSEric Tremblay int ret = regmap_write(data->regmap, TMP51X_SHUNT_CONFIG, 57759dfa75eSEric Tremblay data->shunt_config); 57859dfa75eSEric Tremblay if (ret < 0) 57959dfa75eSEric Tremblay return ret; 58059dfa75eSEric Tremblay 58159dfa75eSEric Tremblay ret = regmap_write(data->regmap, TMP51X_TEMP_CONFIG, data->temp_config); 58259dfa75eSEric Tremblay if (ret < 0) 58359dfa75eSEric Tremblay return ret; 58459dfa75eSEric Tremblay 58559dfa75eSEric Tremblay // nFactor configuration 58659dfa75eSEric Tremblay ret = regmap_update_bits(data->regmap, TMP51X_N_FACTOR_AND_HYST_1, 58759dfa75eSEric Tremblay TMP51X_NFACTOR_MASK, data->nfactor[0] << 8); 58859dfa75eSEric Tremblay if (ret < 0) 58959dfa75eSEric Tremblay return ret; 59059dfa75eSEric Tremblay 59159dfa75eSEric Tremblay ret = regmap_write(data->regmap, TMP51X_N_FACTOR_2, 59259dfa75eSEric Tremblay data->nfactor[1] << 8); 59359dfa75eSEric Tremblay if (ret < 0) 59459dfa75eSEric Tremblay return ret; 59559dfa75eSEric Tremblay 596fb99e07aSBiju Das if (data->max_channels == TMP513_MAX_CHANNELS) { 59759dfa75eSEric Tremblay ret = regmap_write(data->regmap, TMP513_N_FACTOR_3, 59859dfa75eSEric Tremblay data->nfactor[2] << 8); 59959dfa75eSEric Tremblay if (ret < 0) 60059dfa75eSEric Tremblay return ret; 60159dfa75eSEric Tremblay } 60259dfa75eSEric Tremblay 60359dfa75eSEric Tremblay ret = tmp51x_calibrate(data); 60459dfa75eSEric Tremblay if (ret < 0) 60559dfa75eSEric Tremblay return ret; 60659dfa75eSEric Tremblay 60759dfa75eSEric Tremblay // Read the status register before using as the datasheet propose 60859dfa75eSEric Tremblay return regmap_read(data->regmap, TMP51X_STATUS, ®val); 60959dfa75eSEric Tremblay } 61059dfa75eSEric Tremblay 61159dfa75eSEric Tremblay static const struct i2c_device_id tmp51x_id[] = { 612fb99e07aSBiju Das { "tmp512", TMP512_MAX_CHANNELS }, 613fb99e07aSBiju Das { "tmp513", TMP513_MAX_CHANNELS }, 61459dfa75eSEric Tremblay { } 61559dfa75eSEric Tremblay }; 61659dfa75eSEric Tremblay MODULE_DEVICE_TABLE(i2c, tmp51x_id); 61759dfa75eSEric Tremblay 61859dfa75eSEric Tremblay static const struct of_device_id tmp51x_of_match[] = { 619fb99e07aSBiju Das { .compatible = "ti,tmp512", .data = (void *)TMP512_MAX_CHANNELS }, 620fb99e07aSBiju Das { .compatible = "ti,tmp513", .data = (void *)TMP513_MAX_CHANNELS }, 621fb99e07aSBiju Das { } 62259dfa75eSEric Tremblay }; 62359dfa75eSEric Tremblay MODULE_DEVICE_TABLE(of, tmp51x_of_match); 62459dfa75eSEric Tremblay 62559dfa75eSEric Tremblay static int tmp51x_vbus_range_to_reg(struct device *dev, 62659dfa75eSEric Tremblay struct tmp51x_data *data) 62759dfa75eSEric Tremblay { 62859dfa75eSEric Tremblay if (data->vbus_range_uvolt == TMP51X_VBUS_RANGE_32V) { 62959dfa75eSEric Tremblay data->shunt_config |= TMP51X_BUS_VOLTAGE_MASK; 63059dfa75eSEric Tremblay } else if (data->vbus_range_uvolt == TMP51X_VBUS_RANGE_16V) { 63159dfa75eSEric Tremblay data->shunt_config &= ~TMP51X_BUS_VOLTAGE_MASK; 63259dfa75eSEric Tremblay } else { 633*df989762SAndy Shevchenko return dev_err_probe(dev, -EINVAL, 634*df989762SAndy Shevchenko "ti,bus-range-microvolt is invalid: %u\n", 63559dfa75eSEric Tremblay data->vbus_range_uvolt); 63659dfa75eSEric Tremblay } 63759dfa75eSEric Tremblay return 0; 63859dfa75eSEric Tremblay } 63959dfa75eSEric Tremblay 64059dfa75eSEric Tremblay static int tmp51x_pga_gain_to_reg(struct device *dev, struct tmp51x_data *data) 64159dfa75eSEric Tremblay { 64259dfa75eSEric Tremblay if (data->pga_gain == 8) { 64359dfa75eSEric Tremblay data->shunt_config |= CURRENT_SENSE_VOLTAGE_320_MASK; 64459dfa75eSEric Tremblay } else if (data->pga_gain == 4) { 64559dfa75eSEric Tremblay data->shunt_config |= CURRENT_SENSE_VOLTAGE_160_MASK; 64659dfa75eSEric Tremblay } else if (data->pga_gain == 2) { 64759dfa75eSEric Tremblay data->shunt_config |= CURRENT_SENSE_VOLTAGE_80_MASK; 64859dfa75eSEric Tremblay } else if (data->pga_gain == 1) { 64959dfa75eSEric Tremblay data->shunt_config |= CURRENT_SENSE_VOLTAGE_40_MASK; 65059dfa75eSEric Tremblay } else { 651*df989762SAndy Shevchenko return dev_err_probe(dev, -EINVAL, 652*df989762SAndy Shevchenko "ti,pga-gain is invalid: %u\n", data->pga_gain); 65359dfa75eSEric Tremblay } 65459dfa75eSEric Tremblay return 0; 65559dfa75eSEric Tremblay } 65659dfa75eSEric Tremblay 65759dfa75eSEric Tremblay static int tmp51x_read_properties(struct device *dev, struct tmp51x_data *data) 65859dfa75eSEric Tremblay { 65959dfa75eSEric Tremblay int ret; 66059dfa75eSEric Tremblay u32 val; 66159dfa75eSEric Tremblay 66259dfa75eSEric Tremblay ret = device_property_read_u32(dev, "shunt-resistor-micro-ohms", &val); 66359dfa75eSEric Tremblay data->shunt_uohms = (ret >= 0) ? val : TMP51X_SHUNT_VALUE_DEFAULT; 66459dfa75eSEric Tremblay 66559dfa75eSEric Tremblay ret = device_property_read_u32(dev, "ti,bus-range-microvolt", &val); 66659dfa75eSEric Tremblay data->vbus_range_uvolt = (ret >= 0) ? val : TMP51X_VBUS_RANGE_DEFAULT; 66759dfa75eSEric Tremblay ret = tmp51x_vbus_range_to_reg(dev, data); 66859dfa75eSEric Tremblay if (ret < 0) 66959dfa75eSEric Tremblay return ret; 67059dfa75eSEric Tremblay 67159dfa75eSEric Tremblay ret = device_property_read_u32(dev, "ti,pga-gain", &val); 67259dfa75eSEric Tremblay data->pga_gain = (ret >= 0) ? val : TMP51X_PGA_DEFAULT; 67359dfa75eSEric Tremblay ret = tmp51x_pga_gain_to_reg(dev, data); 67459dfa75eSEric Tremblay if (ret < 0) 67559dfa75eSEric Tremblay return ret; 67659dfa75eSEric Tremblay 67727887b06SBiju Das device_property_read_u32_array(dev, "ti,nfactor", data->nfactor, 678fb99e07aSBiju Das data->max_channels - 1); 67959dfa75eSEric Tremblay 68059dfa75eSEric Tremblay // Check if shunt value is compatible with pga-gain 68159dfa75eSEric Tremblay if (data->shunt_uohms > data->pga_gain * 40 * 1000 * 1000) { 682*df989762SAndy Shevchenko return dev_err_probe(dev, -EINVAL, 683*df989762SAndy Shevchenko "shunt-resistor: %u too big for pga_gain: %u\n", 68459dfa75eSEric Tremblay data->shunt_uohms, data->pga_gain); 68559dfa75eSEric Tremblay } 68659dfa75eSEric Tremblay 68759dfa75eSEric Tremblay return 0; 68859dfa75eSEric Tremblay } 68959dfa75eSEric Tremblay 69059dfa75eSEric Tremblay static void tmp51x_use_default(struct tmp51x_data *data) 69159dfa75eSEric Tremblay { 69259dfa75eSEric Tremblay data->vbus_range_uvolt = TMP51X_VBUS_RANGE_DEFAULT; 69359dfa75eSEric Tremblay data->pga_gain = TMP51X_PGA_DEFAULT; 69459dfa75eSEric Tremblay data->shunt_uohms = TMP51X_SHUNT_VALUE_DEFAULT; 69559dfa75eSEric Tremblay } 69659dfa75eSEric Tremblay 69759dfa75eSEric Tremblay static int tmp51x_configure(struct device *dev, struct tmp51x_data *data) 69859dfa75eSEric Tremblay { 69959dfa75eSEric Tremblay data->shunt_config = TMP51X_SHUNT_CONFIG_DEFAULT; 700fb99e07aSBiju Das data->temp_config = TMP51X_TEMP_CONFIG_DEFAULT(data->max_channels); 70159dfa75eSEric Tremblay 70259dfa75eSEric Tremblay if (dev->of_node) 70359dfa75eSEric Tremblay return tmp51x_read_properties(dev, data); 70459dfa75eSEric Tremblay 70559dfa75eSEric Tremblay tmp51x_use_default(data); 70659dfa75eSEric Tremblay 70759dfa75eSEric Tremblay return 0; 70859dfa75eSEric Tremblay } 70959dfa75eSEric Tremblay 710e3b9f691SStephen Kitt static int tmp51x_probe(struct i2c_client *client) 71159dfa75eSEric Tremblay { 71259dfa75eSEric Tremblay struct device *dev = &client->dev; 71359dfa75eSEric Tremblay struct tmp51x_data *data; 71459dfa75eSEric Tremblay struct device *hwmon_dev; 71559dfa75eSEric Tremblay int ret; 71659dfa75eSEric Tremblay 71759dfa75eSEric Tremblay data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); 71859dfa75eSEric Tremblay if (!data) 71959dfa75eSEric Tremblay return -ENOMEM; 72059dfa75eSEric Tremblay 721fb99e07aSBiju Das data->max_channels = (uintptr_t)i2c_get_match_data(client); 72259dfa75eSEric Tremblay 72359dfa75eSEric Tremblay ret = tmp51x_configure(dev, data); 724*df989762SAndy Shevchenko if (ret < 0) 725*df989762SAndy Shevchenko return dev_err_probe(dev, ret, "error configuring the device\n"); 72659dfa75eSEric Tremblay 72759dfa75eSEric Tremblay data->regmap = devm_regmap_init_i2c(client, &tmp51x_regmap_config); 728*df989762SAndy Shevchenko if (IS_ERR(data->regmap)) 729*df989762SAndy Shevchenko return dev_err_probe(dev, PTR_ERR(data->regmap), 730*df989762SAndy Shevchenko "failed to allocate register map\n"); 73159dfa75eSEric Tremblay 73259dfa75eSEric Tremblay ret = tmp51x_init(data); 733*df989762SAndy Shevchenko if (ret < 0) 734*df989762SAndy Shevchenko return dev_err_probe(dev, ret, "error configuring the device\n"); 73559dfa75eSEric Tremblay 73659dfa75eSEric Tremblay hwmon_dev = devm_hwmon_device_register_with_info(dev, client->name, 73759dfa75eSEric Tremblay data, 73859dfa75eSEric Tremblay &tmp51x_chip_info, 73959dfa75eSEric Tremblay NULL); 74059dfa75eSEric Tremblay if (IS_ERR(hwmon_dev)) 74159dfa75eSEric Tremblay return PTR_ERR(hwmon_dev); 74259dfa75eSEric Tremblay 743e3b9f691SStephen Kitt dev_dbg(dev, "power monitor %s\n", client->name); 74459dfa75eSEric Tremblay 74559dfa75eSEric Tremblay return 0; 74659dfa75eSEric Tremblay } 74759dfa75eSEric Tremblay 74859dfa75eSEric Tremblay static struct i2c_driver tmp51x_driver = { 74959dfa75eSEric Tremblay .driver = { 75059dfa75eSEric Tremblay .name = "tmp51x", 75100d85e81SKrzysztof Kozlowski .of_match_table = tmp51x_of_match, 75259dfa75eSEric Tremblay }, 7531975d167SUwe Kleine-König .probe = tmp51x_probe, 75459dfa75eSEric Tremblay .id_table = tmp51x_id, 75559dfa75eSEric Tremblay }; 75659dfa75eSEric Tremblay 75759dfa75eSEric Tremblay module_i2c_driver(tmp51x_driver); 75859dfa75eSEric Tremblay 75959dfa75eSEric Tremblay MODULE_AUTHOR("Eric Tremblay <etremblay@distechcontrols.com>"); 76059dfa75eSEric Tremblay MODULE_DESCRIPTION("tmp51x driver"); 76159dfa75eSEric Tremblay MODULE_LICENSE("GPL"); 762