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