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