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> 35*f07f9d24SAndy Shevchenko #include <linux/units.h> 3659dfa75eSEric Tremblay 3759dfa75eSEric Tremblay // Common register definition 3859dfa75eSEric Tremblay #define TMP51X_SHUNT_CONFIG 0x00 3959dfa75eSEric Tremblay #define TMP51X_TEMP_CONFIG 0x01 4059dfa75eSEric Tremblay #define TMP51X_STATUS 0x02 4159dfa75eSEric Tremblay #define TMP51X_SMBUS_ALERT 0x03 4259dfa75eSEric Tremblay #define TMP51X_SHUNT_CURRENT_RESULT 0x04 4359dfa75eSEric Tremblay #define TMP51X_BUS_VOLTAGE_RESULT 0x05 4459dfa75eSEric Tremblay #define TMP51X_POWER_RESULT 0x06 4559dfa75eSEric Tremblay #define TMP51X_BUS_CURRENT_RESULT 0x07 4659dfa75eSEric Tremblay #define TMP51X_LOCAL_TEMP_RESULT 0x08 4759dfa75eSEric Tremblay #define TMP51X_REMOTE_TEMP_RESULT_1 0x09 4859dfa75eSEric Tremblay #define TMP51X_REMOTE_TEMP_RESULT_2 0x0A 4959dfa75eSEric Tremblay #define TMP51X_SHUNT_CURRENT_H_LIMIT 0x0C 5059dfa75eSEric Tremblay #define TMP51X_SHUNT_CURRENT_L_LIMIT 0x0D 5159dfa75eSEric Tremblay #define TMP51X_BUS_VOLTAGE_H_LIMIT 0x0E 5259dfa75eSEric Tremblay #define TMP51X_BUS_VOLTAGE_L_LIMIT 0x0F 5359dfa75eSEric Tremblay #define TMP51X_POWER_LIMIT 0x10 5459dfa75eSEric Tremblay #define TMP51X_LOCAL_TEMP_LIMIT 0x11 5559dfa75eSEric Tremblay #define TMP51X_REMOTE_TEMP_LIMIT_1 0x12 5659dfa75eSEric Tremblay #define TMP51X_REMOTE_TEMP_LIMIT_2 0x13 5759dfa75eSEric Tremblay #define TMP51X_SHUNT_CALIBRATION 0x15 5859dfa75eSEric Tremblay #define TMP51X_N_FACTOR_AND_HYST_1 0x16 5959dfa75eSEric Tremblay #define TMP51X_N_FACTOR_2 0x17 6059dfa75eSEric Tremblay #define TMP51X_MAN_ID_REG 0xFE 6159dfa75eSEric Tremblay #define TMP51X_DEVICE_ID_REG 0xFF 6259dfa75eSEric Tremblay 6359dfa75eSEric Tremblay // TMP513 specific register definition 6459dfa75eSEric Tremblay #define TMP513_REMOTE_TEMP_RESULT_3 0x0B 6559dfa75eSEric Tremblay #define TMP513_REMOTE_TEMP_LIMIT_3 0x14 6659dfa75eSEric Tremblay #define TMP513_N_FACTOR_3 0x18 6759dfa75eSEric Tremblay 6859dfa75eSEric Tremblay // Common attrs, and NULL 6959dfa75eSEric Tremblay #define TMP51X_MANUFACTURER_ID 0x55FF 7059dfa75eSEric Tremblay 7159dfa75eSEric Tremblay #define TMP512_DEVICE_ID 0x22FF 7259dfa75eSEric Tremblay #define TMP513_DEVICE_ID 0x23FF 7359dfa75eSEric Tremblay 7459dfa75eSEric Tremblay // Default config 7559dfa75eSEric Tremblay #define TMP51X_SHUNT_CONFIG_DEFAULT 0x399F 7659dfa75eSEric Tremblay #define TMP51X_SHUNT_VALUE_DEFAULT 1000 7759dfa75eSEric Tremblay #define TMP51X_VBUS_RANGE_DEFAULT TMP51X_VBUS_RANGE_32V 7859dfa75eSEric Tremblay #define TMP51X_PGA_DEFAULT 8 7959dfa75eSEric Tremblay #define TMP51X_MAX_REGISTER_ADDR 0xFF 8059dfa75eSEric Tremblay 8159dfa75eSEric Tremblay // Mask and shift 8259dfa75eSEric Tremblay #define CURRENT_SENSE_VOLTAGE_320_MASK 0x1800 8359dfa75eSEric Tremblay #define CURRENT_SENSE_VOLTAGE_160_MASK 0x1000 8459dfa75eSEric Tremblay #define CURRENT_SENSE_VOLTAGE_80_MASK 0x0800 8559dfa75eSEric Tremblay #define CURRENT_SENSE_VOLTAGE_40_MASK 0 8659dfa75eSEric Tremblay 8759dfa75eSEric Tremblay #define TMP51X_BUS_VOLTAGE_MASK 0x2000 8859dfa75eSEric Tremblay #define TMP51X_NFACTOR_MASK 0xFF00 8959dfa75eSEric Tremblay #define TMP51X_HYST_MASK 0x00FF 9059dfa75eSEric Tremblay 9159dfa75eSEric Tremblay #define TMP51X_BUS_VOLTAGE_SHIFT 3 9259dfa75eSEric Tremblay #define TMP51X_TEMP_SHIFT 3 9359dfa75eSEric Tremblay 9459dfa75eSEric Tremblay // Alarms 9559dfa75eSEric Tremblay #define TMP51X_SHUNT_CURRENT_H_LIMIT_POS 15 9659dfa75eSEric Tremblay #define TMP51X_SHUNT_CURRENT_L_LIMIT_POS 14 9759dfa75eSEric Tremblay #define TMP51X_BUS_VOLTAGE_H_LIMIT_POS 13 9859dfa75eSEric Tremblay #define TMP51X_BUS_VOLTAGE_L_LIMIT_POS 12 9959dfa75eSEric Tremblay #define TMP51X_POWER_LIMIT_POS 11 10059dfa75eSEric Tremblay #define TMP51X_LOCAL_TEMP_LIMIT_POS 10 10159dfa75eSEric Tremblay #define TMP51X_REMOTE_TEMP_LIMIT_1_POS 9 10259dfa75eSEric Tremblay #define TMP51X_REMOTE_TEMP_LIMIT_2_POS 8 10359dfa75eSEric Tremblay #define TMP513_REMOTE_TEMP_LIMIT_3_POS 7 10459dfa75eSEric Tremblay 105*f07f9d24SAndy Shevchenko #define TMP51X_VBUS_RANGE_32V (32 * MICRO) 106*f07f9d24SAndy Shevchenko #define TMP51X_VBUS_RANGE_16V (16 * MICRO) 10759dfa75eSEric Tremblay 10859dfa75eSEric Tremblay // Max and Min value 10959dfa75eSEric Tremblay #define MAX_BUS_VOLTAGE_32_LIMIT 32764 11059dfa75eSEric Tremblay #define MAX_BUS_VOLTAGE_16_LIMIT 16382 11159dfa75eSEric Tremblay 11259dfa75eSEric Tremblay // Max possible value is -256 to +256 but datasheet indicated -40 to 125. 11359dfa75eSEric Tremblay #define MAX_TEMP_LIMIT 125000 11459dfa75eSEric Tremblay #define MIN_TEMP_LIMIT -40000 11559dfa75eSEric Tremblay 11659dfa75eSEric Tremblay #define MAX_TEMP_HYST 127500 11759dfa75eSEric Tremblay 118fb99e07aSBiju Das #define TMP512_MAX_CHANNELS 3 119fb99e07aSBiju Das #define TMP513_MAX_CHANNELS 4 120fb99e07aSBiju Das 121fb99e07aSBiju Das #define TMP51X_TEMP_CONFIG_CONV_RATE GENMASK(9, 7) 122fb99e07aSBiju Das #define TMP51X_TEMP_CONFIG_RC BIT(10) 123fb99e07aSBiju Das #define TMP51X_TEMP_CHANNEL_MASK(n) (GENMASK((n) - 1, 0) << 11) 124fb99e07aSBiju Das #define TMP51X_TEMP_CONFIG_CONT BIT(15) 125fb99e07aSBiju Das #define TMP51X_TEMP_CONFIG_DEFAULT(n) \ 126fb99e07aSBiju Das (TMP51X_TEMP_CHANNEL_MASK(n) | TMP51X_TEMP_CONFIG_CONT | \ 127fb99e07aSBiju Das TMP51X_TEMP_CONFIG_CONV_RATE | TMP51X_TEMP_CONFIG_RC) 128fb99e07aSBiju Das 12959dfa75eSEric Tremblay static const u8 TMP51X_TEMP_INPUT[4] = { 13059dfa75eSEric Tremblay TMP51X_LOCAL_TEMP_RESULT, 13159dfa75eSEric Tremblay TMP51X_REMOTE_TEMP_RESULT_1, 13259dfa75eSEric Tremblay TMP51X_REMOTE_TEMP_RESULT_2, 13359dfa75eSEric Tremblay TMP513_REMOTE_TEMP_RESULT_3 13459dfa75eSEric Tremblay }; 13559dfa75eSEric Tremblay 13659dfa75eSEric Tremblay static const u8 TMP51X_TEMP_CRIT[4] = { 13759dfa75eSEric Tremblay TMP51X_LOCAL_TEMP_LIMIT, 13859dfa75eSEric Tremblay TMP51X_REMOTE_TEMP_LIMIT_1, 13959dfa75eSEric Tremblay TMP51X_REMOTE_TEMP_LIMIT_2, 14059dfa75eSEric Tremblay TMP513_REMOTE_TEMP_LIMIT_3 14159dfa75eSEric Tremblay }; 14259dfa75eSEric Tremblay 14359dfa75eSEric Tremblay static const u8 TMP51X_TEMP_CRIT_ALARM[4] = { 14459dfa75eSEric Tremblay TMP51X_LOCAL_TEMP_LIMIT_POS, 14559dfa75eSEric Tremblay TMP51X_REMOTE_TEMP_LIMIT_1_POS, 14659dfa75eSEric Tremblay TMP51X_REMOTE_TEMP_LIMIT_2_POS, 14759dfa75eSEric Tremblay TMP513_REMOTE_TEMP_LIMIT_3_POS 14859dfa75eSEric Tremblay }; 14959dfa75eSEric Tremblay 15059dfa75eSEric Tremblay static const u8 TMP51X_TEMP_CRIT_HYST[4] = { 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 TMP51X_N_FACTOR_AND_HYST_1 15559dfa75eSEric Tremblay }; 15659dfa75eSEric Tremblay 15759dfa75eSEric Tremblay static const u8 TMP51X_CURR_INPUT[2] = { 15859dfa75eSEric Tremblay TMP51X_SHUNT_CURRENT_RESULT, 15959dfa75eSEric Tremblay TMP51X_BUS_CURRENT_RESULT 16059dfa75eSEric Tremblay }; 16159dfa75eSEric Tremblay 16259dfa75eSEric Tremblay static struct regmap_config tmp51x_regmap_config = { 16359dfa75eSEric Tremblay .reg_bits = 8, 16459dfa75eSEric Tremblay .val_bits = 16, 16559dfa75eSEric Tremblay .max_register = TMP51X_MAX_REGISTER_ADDR, 16659dfa75eSEric Tremblay }; 16759dfa75eSEric Tremblay 16859dfa75eSEric Tremblay struct tmp51x_data { 16959dfa75eSEric Tremblay u16 shunt_config; 17059dfa75eSEric Tremblay u16 pga_gain; 17159dfa75eSEric Tremblay u32 vbus_range_uvolt; 17259dfa75eSEric Tremblay 17359dfa75eSEric Tremblay u16 temp_config; 17459dfa75eSEric Tremblay u32 nfactor[3]; 17559dfa75eSEric Tremblay 17659dfa75eSEric Tremblay u32 shunt_uohms; 17759dfa75eSEric Tremblay 17859dfa75eSEric Tremblay u32 curr_lsb_ua; 17959dfa75eSEric Tremblay u32 pwr_lsb_uw; 18059dfa75eSEric Tremblay 181fb99e07aSBiju Das u8 max_channels; 18259dfa75eSEric Tremblay struct regmap *regmap; 18359dfa75eSEric Tremblay }; 18459dfa75eSEric Tremblay 18559dfa75eSEric Tremblay // Set the shift based on the gain 8=4, 4=3, 2=2, 1=1 18659dfa75eSEric Tremblay static inline u8 tmp51x_get_pga_shift(struct tmp51x_data *data) 18759dfa75eSEric Tremblay { 18859dfa75eSEric Tremblay return 5 - ffs(data->pga_gain); 18959dfa75eSEric Tremblay } 19059dfa75eSEric Tremblay 19159dfa75eSEric Tremblay static int tmp51x_get_value(struct tmp51x_data *data, u8 reg, u8 pos, 19259dfa75eSEric Tremblay unsigned int regval, long *val) 19359dfa75eSEric Tremblay { 19459dfa75eSEric Tremblay switch (reg) { 19559dfa75eSEric Tremblay case TMP51X_STATUS: 19659dfa75eSEric Tremblay *val = (regval >> pos) & 1; 19759dfa75eSEric Tremblay break; 19859dfa75eSEric Tremblay case TMP51X_SHUNT_CURRENT_RESULT: 19959dfa75eSEric Tremblay case TMP51X_SHUNT_CURRENT_H_LIMIT: 20059dfa75eSEric Tremblay case TMP51X_SHUNT_CURRENT_L_LIMIT: 20159dfa75eSEric Tremblay /* 20259dfa75eSEric Tremblay * The valus is read in voltage in the chip but reported as 20359dfa75eSEric Tremblay * current to the user. 204c073292bSWang Qing * 2's complement number shifted by one to four depending 20559dfa75eSEric Tremblay * on the pga gain setting. 1lsb = 10uV 20659dfa75eSEric Tremblay */ 20759dfa75eSEric Tremblay *val = sign_extend32(regval, 17 - tmp51x_get_pga_shift(data)); 208*f07f9d24SAndy Shevchenko *val = DIV_ROUND_CLOSEST(*val * 10 * MILLI, data->shunt_uohms); 20959dfa75eSEric Tremblay break; 21059dfa75eSEric Tremblay case TMP51X_BUS_VOLTAGE_RESULT: 21159dfa75eSEric Tremblay case TMP51X_BUS_VOLTAGE_H_LIMIT: 21259dfa75eSEric Tremblay case TMP51X_BUS_VOLTAGE_L_LIMIT: 21359dfa75eSEric Tremblay // 1lsb = 4mV 21459dfa75eSEric Tremblay *val = (regval >> TMP51X_BUS_VOLTAGE_SHIFT) * 4; 21559dfa75eSEric Tremblay break; 21659dfa75eSEric Tremblay case TMP51X_POWER_RESULT: 21759dfa75eSEric Tremblay case TMP51X_POWER_LIMIT: 21859dfa75eSEric Tremblay // Power = (current * BusVoltage) / 5000 21959dfa75eSEric Tremblay *val = regval * data->pwr_lsb_uw; 22059dfa75eSEric Tremblay break; 22159dfa75eSEric Tremblay case TMP51X_BUS_CURRENT_RESULT: 22259dfa75eSEric Tremblay // Current = (ShuntVoltage * CalibrationRegister) / 4096 22359dfa75eSEric Tremblay *val = sign_extend32(regval, 16) * data->curr_lsb_ua; 224*f07f9d24SAndy Shevchenko *val = DIV_ROUND_CLOSEST(*val, MILLI); 22559dfa75eSEric Tremblay break; 22659dfa75eSEric Tremblay case TMP51X_LOCAL_TEMP_RESULT: 22759dfa75eSEric Tremblay case TMP51X_REMOTE_TEMP_RESULT_1: 22859dfa75eSEric Tremblay case TMP51X_REMOTE_TEMP_RESULT_2: 22959dfa75eSEric Tremblay case TMP513_REMOTE_TEMP_RESULT_3: 23059dfa75eSEric Tremblay case TMP51X_LOCAL_TEMP_LIMIT: 23159dfa75eSEric Tremblay case TMP51X_REMOTE_TEMP_LIMIT_1: 23259dfa75eSEric Tremblay case TMP51X_REMOTE_TEMP_LIMIT_2: 23359dfa75eSEric Tremblay case TMP513_REMOTE_TEMP_LIMIT_3: 23459dfa75eSEric Tremblay // 1lsb = 0.0625 degrees centigrade 23559dfa75eSEric Tremblay *val = sign_extend32(regval, 16) >> TMP51X_TEMP_SHIFT; 23659dfa75eSEric Tremblay *val = DIV_ROUND_CLOSEST(*val * 625, 10); 23759dfa75eSEric Tremblay break; 23859dfa75eSEric Tremblay case TMP51X_N_FACTOR_AND_HYST_1: 23959dfa75eSEric Tremblay // 1lsb = 0.5 degrees centigrade 24059dfa75eSEric Tremblay *val = (regval & TMP51X_HYST_MASK) * 500; 24159dfa75eSEric Tremblay break; 24259dfa75eSEric Tremblay default: 24359dfa75eSEric Tremblay // Programmer goofed 24459dfa75eSEric Tremblay WARN_ON_ONCE(1); 24559dfa75eSEric Tremblay *val = 0; 24659dfa75eSEric Tremblay return -EOPNOTSUPP; 24759dfa75eSEric Tremblay } 24859dfa75eSEric Tremblay 24959dfa75eSEric Tremblay return 0; 25059dfa75eSEric Tremblay } 25159dfa75eSEric Tremblay 25259dfa75eSEric Tremblay static int tmp51x_set_value(struct tmp51x_data *data, u8 reg, long val) 25359dfa75eSEric Tremblay { 25459dfa75eSEric Tremblay int regval, max_val; 25559dfa75eSEric Tremblay u32 mask = 0; 25659dfa75eSEric Tremblay 25759dfa75eSEric Tremblay switch (reg) { 25859dfa75eSEric Tremblay case TMP51X_SHUNT_CURRENT_H_LIMIT: 25959dfa75eSEric Tremblay case TMP51X_SHUNT_CURRENT_L_LIMIT: 26059dfa75eSEric Tremblay /* 26159dfa75eSEric Tremblay * The user enter current value and we convert it to 26259dfa75eSEric Tremblay * voltage. 1lsb = 10uV 26359dfa75eSEric Tremblay */ 264*f07f9d24SAndy Shevchenko val = DIV_ROUND_CLOSEST(val * data->shunt_uohms, 10 * MILLI); 26559dfa75eSEric Tremblay max_val = U16_MAX >> tmp51x_get_pga_shift(data); 26659dfa75eSEric Tremblay regval = clamp_val(val, -max_val, max_val); 26759dfa75eSEric Tremblay break; 26859dfa75eSEric Tremblay case TMP51X_BUS_VOLTAGE_H_LIMIT: 26959dfa75eSEric Tremblay case TMP51X_BUS_VOLTAGE_L_LIMIT: 27059dfa75eSEric Tremblay // 1lsb = 4mV 27159dfa75eSEric Tremblay max_val = (data->vbus_range_uvolt == TMP51X_VBUS_RANGE_32V) ? 27259dfa75eSEric Tremblay MAX_BUS_VOLTAGE_32_LIMIT : MAX_BUS_VOLTAGE_16_LIMIT; 27359dfa75eSEric Tremblay 27459dfa75eSEric Tremblay val = clamp_val(DIV_ROUND_CLOSEST(val, 4), 0, max_val); 27559dfa75eSEric Tremblay regval = val << TMP51X_BUS_VOLTAGE_SHIFT; 27659dfa75eSEric Tremblay break; 27759dfa75eSEric Tremblay case TMP51X_POWER_LIMIT: 27859dfa75eSEric Tremblay regval = clamp_val(DIV_ROUND_CLOSEST(val, data->pwr_lsb_uw), 0, 27959dfa75eSEric Tremblay U16_MAX); 28059dfa75eSEric Tremblay break; 28159dfa75eSEric Tremblay case TMP51X_LOCAL_TEMP_LIMIT: 28259dfa75eSEric Tremblay case TMP51X_REMOTE_TEMP_LIMIT_1: 28359dfa75eSEric Tremblay case TMP51X_REMOTE_TEMP_LIMIT_2: 28459dfa75eSEric Tremblay case TMP513_REMOTE_TEMP_LIMIT_3: 28559dfa75eSEric Tremblay // 1lsb = 0.0625 degrees centigrade 28659dfa75eSEric Tremblay val = clamp_val(val, MIN_TEMP_LIMIT, MAX_TEMP_LIMIT); 28759dfa75eSEric Tremblay regval = DIV_ROUND_CLOSEST(val * 10, 625) << TMP51X_TEMP_SHIFT; 28859dfa75eSEric Tremblay break; 28959dfa75eSEric Tremblay case TMP51X_N_FACTOR_AND_HYST_1: 29059dfa75eSEric Tremblay // 1lsb = 0.5 degrees centigrade 29159dfa75eSEric Tremblay val = clamp_val(val, 0, MAX_TEMP_HYST); 29259dfa75eSEric Tremblay regval = DIV_ROUND_CLOSEST(val, 500); 29359dfa75eSEric Tremblay mask = TMP51X_HYST_MASK; 29459dfa75eSEric Tremblay break; 29559dfa75eSEric Tremblay default: 29659dfa75eSEric Tremblay // Programmer goofed 29759dfa75eSEric Tremblay WARN_ON_ONCE(1); 29859dfa75eSEric Tremblay return -EOPNOTSUPP; 29959dfa75eSEric Tremblay } 30059dfa75eSEric Tremblay 30159dfa75eSEric Tremblay if (mask == 0) 30259dfa75eSEric Tremblay return regmap_write(data->regmap, reg, regval); 30359dfa75eSEric Tremblay else 30459dfa75eSEric Tremblay return regmap_update_bits(data->regmap, reg, mask, regval); 30559dfa75eSEric Tremblay } 30659dfa75eSEric Tremblay 30759dfa75eSEric Tremblay static u8 tmp51x_get_reg(enum hwmon_sensor_types type, u32 attr, int channel) 30859dfa75eSEric Tremblay { 30959dfa75eSEric Tremblay switch (type) { 31059dfa75eSEric Tremblay case hwmon_temp: 31159dfa75eSEric Tremblay switch (attr) { 31259dfa75eSEric Tremblay case hwmon_temp_input: 31359dfa75eSEric Tremblay return TMP51X_TEMP_INPUT[channel]; 31459dfa75eSEric Tremblay case hwmon_temp_crit_alarm: 31559dfa75eSEric Tremblay return TMP51X_STATUS; 31659dfa75eSEric Tremblay case hwmon_temp_crit: 31759dfa75eSEric Tremblay return TMP51X_TEMP_CRIT[channel]; 31859dfa75eSEric Tremblay case hwmon_temp_crit_hyst: 31959dfa75eSEric Tremblay return TMP51X_TEMP_CRIT_HYST[channel]; 32059dfa75eSEric Tremblay } 32159dfa75eSEric Tremblay break; 32259dfa75eSEric Tremblay case hwmon_in: 32359dfa75eSEric Tremblay switch (attr) { 32459dfa75eSEric Tremblay case hwmon_in_input: 32559dfa75eSEric Tremblay return TMP51X_BUS_VOLTAGE_RESULT; 32659dfa75eSEric Tremblay case hwmon_in_lcrit_alarm: 32759dfa75eSEric Tremblay case hwmon_in_crit_alarm: 32859dfa75eSEric Tremblay return TMP51X_STATUS; 32959dfa75eSEric Tremblay case hwmon_in_lcrit: 33059dfa75eSEric Tremblay return TMP51X_BUS_VOLTAGE_L_LIMIT; 33159dfa75eSEric Tremblay case hwmon_in_crit: 33259dfa75eSEric Tremblay return TMP51X_BUS_VOLTAGE_H_LIMIT; 33359dfa75eSEric Tremblay } 33459dfa75eSEric Tremblay break; 33559dfa75eSEric Tremblay case hwmon_curr: 33659dfa75eSEric Tremblay switch (attr) { 33759dfa75eSEric Tremblay case hwmon_curr_input: 33859dfa75eSEric Tremblay return TMP51X_CURR_INPUT[channel]; 33959dfa75eSEric Tremblay case hwmon_curr_lcrit_alarm: 34059dfa75eSEric Tremblay case hwmon_curr_crit_alarm: 34159dfa75eSEric Tremblay return TMP51X_STATUS; 34259dfa75eSEric Tremblay case hwmon_curr_lcrit: 34359dfa75eSEric Tremblay return TMP51X_SHUNT_CURRENT_L_LIMIT; 34459dfa75eSEric Tremblay case hwmon_curr_crit: 34559dfa75eSEric Tremblay return TMP51X_SHUNT_CURRENT_H_LIMIT; 34659dfa75eSEric Tremblay } 34759dfa75eSEric Tremblay break; 34859dfa75eSEric Tremblay case hwmon_power: 34959dfa75eSEric Tremblay switch (attr) { 35059dfa75eSEric Tremblay case hwmon_power_input: 35159dfa75eSEric Tremblay return TMP51X_POWER_RESULT; 35259dfa75eSEric Tremblay case hwmon_power_crit_alarm: 35359dfa75eSEric Tremblay return TMP51X_STATUS; 35459dfa75eSEric Tremblay case hwmon_power_crit: 35559dfa75eSEric Tremblay return TMP51X_POWER_LIMIT; 35659dfa75eSEric Tremblay } 35759dfa75eSEric Tremblay break; 35859dfa75eSEric Tremblay default: 35959dfa75eSEric Tremblay break; 36059dfa75eSEric Tremblay } 36159dfa75eSEric Tremblay 36259dfa75eSEric Tremblay return 0; 36359dfa75eSEric Tremblay } 36459dfa75eSEric Tremblay 36559dfa75eSEric Tremblay static u8 tmp51x_get_status_pos(enum hwmon_sensor_types type, u32 attr, 36659dfa75eSEric Tremblay int channel) 36759dfa75eSEric Tremblay { 36859dfa75eSEric Tremblay switch (type) { 36959dfa75eSEric Tremblay case hwmon_temp: 37059dfa75eSEric Tremblay switch (attr) { 37159dfa75eSEric Tremblay case hwmon_temp_crit_alarm: 37259dfa75eSEric Tremblay return TMP51X_TEMP_CRIT_ALARM[channel]; 37359dfa75eSEric Tremblay } 37459dfa75eSEric Tremblay break; 37559dfa75eSEric Tremblay case hwmon_in: 37659dfa75eSEric Tremblay switch (attr) { 37759dfa75eSEric Tremblay case hwmon_in_lcrit_alarm: 37859dfa75eSEric Tremblay return TMP51X_BUS_VOLTAGE_L_LIMIT_POS; 37959dfa75eSEric Tremblay case hwmon_in_crit_alarm: 38059dfa75eSEric Tremblay return TMP51X_BUS_VOLTAGE_H_LIMIT_POS; 38159dfa75eSEric Tremblay } 38259dfa75eSEric Tremblay break; 38359dfa75eSEric Tremblay case hwmon_curr: 38459dfa75eSEric Tremblay switch (attr) { 38559dfa75eSEric Tremblay case hwmon_curr_lcrit_alarm: 38659dfa75eSEric Tremblay return TMP51X_SHUNT_CURRENT_L_LIMIT_POS; 38759dfa75eSEric Tremblay case hwmon_curr_crit_alarm: 38859dfa75eSEric Tremblay return TMP51X_SHUNT_CURRENT_H_LIMIT_POS; 38959dfa75eSEric Tremblay } 39059dfa75eSEric Tremblay break; 39159dfa75eSEric Tremblay case hwmon_power: 39259dfa75eSEric Tremblay switch (attr) { 39359dfa75eSEric Tremblay case hwmon_power_crit_alarm: 39459dfa75eSEric Tremblay return TMP51X_POWER_LIMIT_POS; 39559dfa75eSEric Tremblay } 39659dfa75eSEric Tremblay break; 39759dfa75eSEric Tremblay default: 39859dfa75eSEric Tremblay break; 39959dfa75eSEric Tremblay } 40059dfa75eSEric Tremblay 40159dfa75eSEric Tremblay return 0; 40259dfa75eSEric Tremblay } 40359dfa75eSEric Tremblay 40459dfa75eSEric Tremblay static int tmp51x_read(struct device *dev, enum hwmon_sensor_types type, 40559dfa75eSEric Tremblay u32 attr, int channel, long *val) 40659dfa75eSEric Tremblay { 40759dfa75eSEric Tremblay struct tmp51x_data *data = dev_get_drvdata(dev); 40859dfa75eSEric Tremblay int ret; 40959dfa75eSEric Tremblay u32 regval; 41059dfa75eSEric Tremblay u8 pos = 0, reg = 0; 41159dfa75eSEric Tremblay 41259dfa75eSEric Tremblay reg = tmp51x_get_reg(type, attr, channel); 41359dfa75eSEric Tremblay if (reg == 0) 41459dfa75eSEric Tremblay return -EOPNOTSUPP; 41559dfa75eSEric Tremblay 41659dfa75eSEric Tremblay if (reg == TMP51X_STATUS) 41759dfa75eSEric Tremblay pos = tmp51x_get_status_pos(type, attr, channel); 41859dfa75eSEric Tremblay 41959dfa75eSEric Tremblay ret = regmap_read(data->regmap, reg, ®val); 42059dfa75eSEric Tremblay if (ret < 0) 42159dfa75eSEric Tremblay return ret; 42259dfa75eSEric Tremblay 42359dfa75eSEric Tremblay return tmp51x_get_value(data, reg, pos, regval, val); 42459dfa75eSEric Tremblay } 42559dfa75eSEric Tremblay 42659dfa75eSEric Tremblay static int tmp51x_write(struct device *dev, enum hwmon_sensor_types type, 42759dfa75eSEric Tremblay u32 attr, int channel, long val) 42859dfa75eSEric Tremblay { 42959dfa75eSEric Tremblay u8 reg = 0; 43059dfa75eSEric Tremblay 43159dfa75eSEric Tremblay reg = tmp51x_get_reg(type, attr, channel); 43259dfa75eSEric Tremblay if (reg == 0) 43359dfa75eSEric Tremblay return -EOPNOTSUPP; 43459dfa75eSEric Tremblay 43559dfa75eSEric Tremblay return tmp51x_set_value(dev_get_drvdata(dev), reg, val); 43659dfa75eSEric Tremblay } 43759dfa75eSEric Tremblay 43859dfa75eSEric Tremblay static umode_t tmp51x_is_visible(const void *_data, 43959dfa75eSEric Tremblay enum hwmon_sensor_types type, u32 attr, 44059dfa75eSEric Tremblay int channel) 44159dfa75eSEric Tremblay { 44259dfa75eSEric Tremblay const struct tmp51x_data *data = _data; 44359dfa75eSEric Tremblay 44459dfa75eSEric Tremblay switch (type) { 44559dfa75eSEric Tremblay case hwmon_temp: 446fb99e07aSBiju Das if (channel >= data->max_channels) 44759dfa75eSEric Tremblay return 0; 44859dfa75eSEric Tremblay switch (attr) { 44959dfa75eSEric Tremblay case hwmon_temp_input: 45059dfa75eSEric Tremblay case hwmon_temp_crit_alarm: 45159dfa75eSEric Tremblay return 0444; 45259dfa75eSEric Tremblay case hwmon_temp_crit: 45359dfa75eSEric Tremblay return 0644; 45459dfa75eSEric Tremblay case hwmon_temp_crit_hyst: 45559dfa75eSEric Tremblay if (channel == 0) 45659dfa75eSEric Tremblay return 0644; 45759dfa75eSEric Tremblay return 0444; 45859dfa75eSEric Tremblay } 45959dfa75eSEric Tremblay break; 46059dfa75eSEric Tremblay case hwmon_in: 46159dfa75eSEric Tremblay switch (attr) { 46259dfa75eSEric Tremblay case hwmon_in_input: 46359dfa75eSEric Tremblay case hwmon_in_lcrit_alarm: 46459dfa75eSEric Tremblay case hwmon_in_crit_alarm: 46559dfa75eSEric Tremblay return 0444; 46659dfa75eSEric Tremblay case hwmon_in_lcrit: 46759dfa75eSEric Tremblay case hwmon_in_crit: 46859dfa75eSEric Tremblay return 0644; 46959dfa75eSEric Tremblay } 47059dfa75eSEric Tremblay break; 47159dfa75eSEric Tremblay case hwmon_curr: 47259dfa75eSEric Tremblay if (!data->shunt_uohms) 47359dfa75eSEric Tremblay return 0; 47459dfa75eSEric Tremblay 47559dfa75eSEric Tremblay switch (attr) { 47659dfa75eSEric Tremblay case hwmon_curr_input: 47759dfa75eSEric Tremblay case hwmon_curr_lcrit_alarm: 47859dfa75eSEric Tremblay case hwmon_curr_crit_alarm: 47959dfa75eSEric Tremblay return 0444; 48059dfa75eSEric Tremblay case hwmon_curr_lcrit: 48159dfa75eSEric Tremblay case hwmon_curr_crit: 48259dfa75eSEric Tremblay return 0644; 48359dfa75eSEric Tremblay } 48459dfa75eSEric Tremblay break; 48559dfa75eSEric Tremblay case hwmon_power: 48659dfa75eSEric Tremblay if (!data->shunt_uohms) 48759dfa75eSEric Tremblay return 0; 48859dfa75eSEric Tremblay 48959dfa75eSEric Tremblay switch (attr) { 49059dfa75eSEric Tremblay case hwmon_power_input: 49159dfa75eSEric Tremblay case hwmon_power_crit_alarm: 49259dfa75eSEric Tremblay return 0444; 49359dfa75eSEric Tremblay case hwmon_power_crit: 49459dfa75eSEric Tremblay return 0644; 49559dfa75eSEric Tremblay } 49659dfa75eSEric Tremblay break; 49759dfa75eSEric Tremblay default: 49859dfa75eSEric Tremblay break; 49959dfa75eSEric Tremblay } 50059dfa75eSEric Tremblay return 0; 50159dfa75eSEric Tremblay } 50259dfa75eSEric Tremblay 503b39c94a1SKrzysztof Kozlowski static const struct hwmon_channel_info * const tmp51x_info[] = { 50459dfa75eSEric Tremblay HWMON_CHANNEL_INFO(temp, 50559dfa75eSEric Tremblay HWMON_T_INPUT | HWMON_T_CRIT | HWMON_T_CRIT_ALARM | 50659dfa75eSEric Tremblay HWMON_T_CRIT_HYST, 50759dfa75eSEric Tremblay HWMON_T_INPUT | HWMON_T_CRIT | HWMON_T_CRIT_ALARM | 50859dfa75eSEric Tremblay HWMON_T_CRIT_HYST, 50959dfa75eSEric Tremblay HWMON_T_INPUT | HWMON_T_CRIT | HWMON_T_CRIT_ALARM | 51059dfa75eSEric Tremblay HWMON_T_CRIT_HYST, 51159dfa75eSEric Tremblay HWMON_T_INPUT | HWMON_T_CRIT | HWMON_T_CRIT_ALARM | 51259dfa75eSEric Tremblay HWMON_T_CRIT_HYST), 51359dfa75eSEric Tremblay HWMON_CHANNEL_INFO(in, 51459dfa75eSEric Tremblay HWMON_I_INPUT | HWMON_I_LCRIT | HWMON_I_LCRIT_ALARM | 51559dfa75eSEric Tremblay HWMON_I_CRIT | HWMON_I_CRIT_ALARM), 51659dfa75eSEric Tremblay HWMON_CHANNEL_INFO(curr, 51759dfa75eSEric Tremblay HWMON_C_INPUT | HWMON_C_LCRIT | HWMON_C_LCRIT_ALARM | 51859dfa75eSEric Tremblay HWMON_C_CRIT | HWMON_C_CRIT_ALARM, 51959dfa75eSEric Tremblay HWMON_C_INPUT), 52059dfa75eSEric Tremblay HWMON_CHANNEL_INFO(power, 52159dfa75eSEric Tremblay HWMON_P_INPUT | HWMON_P_CRIT | HWMON_P_CRIT_ALARM), 52259dfa75eSEric Tremblay NULL 52359dfa75eSEric Tremblay }; 52459dfa75eSEric Tremblay 52559dfa75eSEric Tremblay static const struct hwmon_ops tmp51x_hwmon_ops = { 52659dfa75eSEric Tremblay .is_visible = tmp51x_is_visible, 52759dfa75eSEric Tremblay .read = tmp51x_read, 52859dfa75eSEric Tremblay .write = tmp51x_write, 52959dfa75eSEric Tremblay }; 53059dfa75eSEric Tremblay 53159dfa75eSEric Tremblay static const struct hwmon_chip_info tmp51x_chip_info = { 53259dfa75eSEric Tremblay .ops = &tmp51x_hwmon_ops, 53359dfa75eSEric Tremblay .info = tmp51x_info, 53459dfa75eSEric Tremblay }; 53559dfa75eSEric Tremblay 53659dfa75eSEric Tremblay /* 53759dfa75eSEric Tremblay * Calibrate the tmp51x following the datasheet method 53859dfa75eSEric Tremblay */ 53959dfa75eSEric Tremblay static int tmp51x_calibrate(struct tmp51x_data *data) 54059dfa75eSEric Tremblay { 54159dfa75eSEric Tremblay int vshunt_max = data->pga_gain * 40; 54259dfa75eSEric Tremblay u64 max_curr_ma; 54359dfa75eSEric Tremblay u32 div; 54459dfa75eSEric Tremblay 54559dfa75eSEric Tremblay /* 54659dfa75eSEric Tremblay * If shunt_uohms is equal to 0, the calibration should be set to 0. 54759dfa75eSEric Tremblay * The consequence will be that the current and power measurement engine 54859dfa75eSEric Tremblay * of the sensor will not work. Temperature and voltage sensing will 54959dfa75eSEric Tremblay * continue to work. 55059dfa75eSEric Tremblay */ 55159dfa75eSEric Tremblay if (data->shunt_uohms == 0) 55259dfa75eSEric Tremblay return regmap_write(data->regmap, TMP51X_SHUNT_CALIBRATION, 0); 55359dfa75eSEric Tremblay 554*f07f9d24SAndy Shevchenko max_curr_ma = DIV_ROUND_CLOSEST_ULL(vshunt_max * MICRO, 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 */ 560*f07f9d24SAndy Shevchenko data->curr_lsb_ua = DIV_ROUND_CLOSEST_ULL(max_curr_ma * MILLI, 32767); 56159dfa75eSEric Tremblay data->pwr_lsb_uw = 20 * data->curr_lsb_ua; 56259dfa75eSEric Tremblay 563*f07f9d24SAndy Shevchenko div = DIV_ROUND_CLOSEST_ULL(data->curr_lsb_ua * data->shunt_uohms, MICRO); 56459dfa75eSEric Tremblay 56559dfa75eSEric Tremblay return regmap_write(data->regmap, TMP51X_SHUNT_CALIBRATION, 56659dfa75eSEric Tremblay DIV_ROUND_CLOSEST(40960, div)); 56759dfa75eSEric Tremblay } 56859dfa75eSEric Tremblay 56959dfa75eSEric Tremblay /* 57059dfa75eSEric Tremblay * Initialize the configuration and calibration registers. 57159dfa75eSEric Tremblay */ 57259dfa75eSEric Tremblay static int tmp51x_init(struct tmp51x_data *data) 57359dfa75eSEric Tremblay { 57459dfa75eSEric Tremblay unsigned int regval; 57559dfa75eSEric Tremblay int ret = regmap_write(data->regmap, TMP51X_SHUNT_CONFIG, 57659dfa75eSEric Tremblay data->shunt_config); 57759dfa75eSEric Tremblay if (ret < 0) 57859dfa75eSEric Tremblay return ret; 57959dfa75eSEric Tremblay 58059dfa75eSEric Tremblay ret = regmap_write(data->regmap, TMP51X_TEMP_CONFIG, data->temp_config); 58159dfa75eSEric Tremblay if (ret < 0) 58259dfa75eSEric Tremblay return ret; 58359dfa75eSEric Tremblay 58459dfa75eSEric Tremblay // nFactor configuration 58559dfa75eSEric Tremblay ret = regmap_update_bits(data->regmap, TMP51X_N_FACTOR_AND_HYST_1, 58659dfa75eSEric Tremblay TMP51X_NFACTOR_MASK, data->nfactor[0] << 8); 58759dfa75eSEric Tremblay if (ret < 0) 58859dfa75eSEric Tremblay return ret; 58959dfa75eSEric Tremblay 59059dfa75eSEric Tremblay ret = regmap_write(data->regmap, TMP51X_N_FACTOR_2, 59159dfa75eSEric Tremblay data->nfactor[1] << 8); 59259dfa75eSEric Tremblay if (ret < 0) 59359dfa75eSEric Tremblay return ret; 59459dfa75eSEric Tremblay 595fb99e07aSBiju Das if (data->max_channels == TMP513_MAX_CHANNELS) { 59659dfa75eSEric Tremblay ret = regmap_write(data->regmap, TMP513_N_FACTOR_3, 59759dfa75eSEric Tremblay data->nfactor[2] << 8); 59859dfa75eSEric Tremblay if (ret < 0) 59959dfa75eSEric Tremblay return ret; 60059dfa75eSEric Tremblay } 60159dfa75eSEric Tremblay 60259dfa75eSEric Tremblay ret = tmp51x_calibrate(data); 60359dfa75eSEric Tremblay if (ret < 0) 60459dfa75eSEric Tremblay return ret; 60559dfa75eSEric Tremblay 60659dfa75eSEric Tremblay // Read the status register before using as the datasheet propose 60759dfa75eSEric Tremblay return regmap_read(data->regmap, TMP51X_STATUS, ®val); 60859dfa75eSEric Tremblay } 60959dfa75eSEric Tremblay 61059dfa75eSEric Tremblay static const struct i2c_device_id tmp51x_id[] = { 611fb99e07aSBiju Das { "tmp512", TMP512_MAX_CHANNELS }, 612fb99e07aSBiju Das { "tmp513", TMP513_MAX_CHANNELS }, 61359dfa75eSEric Tremblay { } 61459dfa75eSEric Tremblay }; 61559dfa75eSEric Tremblay MODULE_DEVICE_TABLE(i2c, tmp51x_id); 61659dfa75eSEric Tremblay 61759dfa75eSEric Tremblay static const struct of_device_id tmp51x_of_match[] = { 618fb99e07aSBiju Das { .compatible = "ti,tmp512", .data = (void *)TMP512_MAX_CHANNELS }, 619fb99e07aSBiju Das { .compatible = "ti,tmp513", .data = (void *)TMP513_MAX_CHANNELS }, 620fb99e07aSBiju Das { } 62159dfa75eSEric Tremblay }; 62259dfa75eSEric Tremblay MODULE_DEVICE_TABLE(of, tmp51x_of_match); 62359dfa75eSEric Tremblay 62459dfa75eSEric Tremblay static int tmp51x_vbus_range_to_reg(struct device *dev, 62559dfa75eSEric Tremblay struct tmp51x_data *data) 62659dfa75eSEric Tremblay { 62759dfa75eSEric Tremblay if (data->vbus_range_uvolt == TMP51X_VBUS_RANGE_32V) { 62859dfa75eSEric Tremblay data->shunt_config |= TMP51X_BUS_VOLTAGE_MASK; 62959dfa75eSEric Tremblay } else if (data->vbus_range_uvolt == TMP51X_VBUS_RANGE_16V) { 63059dfa75eSEric Tremblay data->shunt_config &= ~TMP51X_BUS_VOLTAGE_MASK; 63159dfa75eSEric Tremblay } else { 632df989762SAndy Shevchenko return dev_err_probe(dev, -EINVAL, 633df989762SAndy Shevchenko "ti,bus-range-microvolt is invalid: %u\n", 63459dfa75eSEric Tremblay data->vbus_range_uvolt); 63559dfa75eSEric Tremblay } 63659dfa75eSEric Tremblay return 0; 63759dfa75eSEric Tremblay } 63859dfa75eSEric Tremblay 63959dfa75eSEric Tremblay static int tmp51x_pga_gain_to_reg(struct device *dev, struct tmp51x_data *data) 64059dfa75eSEric Tremblay { 64159dfa75eSEric Tremblay if (data->pga_gain == 8) { 64259dfa75eSEric Tremblay data->shunt_config |= CURRENT_SENSE_VOLTAGE_320_MASK; 64359dfa75eSEric Tremblay } else if (data->pga_gain == 4) { 64459dfa75eSEric Tremblay data->shunt_config |= CURRENT_SENSE_VOLTAGE_160_MASK; 64559dfa75eSEric Tremblay } else if (data->pga_gain == 2) { 64659dfa75eSEric Tremblay data->shunt_config |= CURRENT_SENSE_VOLTAGE_80_MASK; 64759dfa75eSEric Tremblay } else if (data->pga_gain == 1) { 64859dfa75eSEric Tremblay data->shunt_config |= CURRENT_SENSE_VOLTAGE_40_MASK; 64959dfa75eSEric Tremblay } else { 650df989762SAndy Shevchenko return dev_err_probe(dev, -EINVAL, 651df989762SAndy Shevchenko "ti,pga-gain is invalid: %u\n", data->pga_gain); 65259dfa75eSEric Tremblay } 65359dfa75eSEric Tremblay return 0; 65459dfa75eSEric Tremblay } 65559dfa75eSEric Tremblay 65659dfa75eSEric Tremblay static int tmp51x_read_properties(struct device *dev, struct tmp51x_data *data) 65759dfa75eSEric Tremblay { 65859dfa75eSEric Tremblay int ret; 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 67627887b06SBiju Das device_property_read_u32_array(dev, "ti,nfactor", data->nfactor, 677fb99e07aSBiju Das data->max_channels - 1); 67859dfa75eSEric Tremblay 67959dfa75eSEric Tremblay // Check if shunt value is compatible with pga-gain 680*f07f9d24SAndy Shevchenko if (data->shunt_uohms > data->pga_gain * 40 * MICRO) { 681df989762SAndy Shevchenko return dev_err_probe(dev, -EINVAL, 682df989762SAndy Shevchenko "shunt-resistor: %u too big for pga_gain: %u\n", 68359dfa75eSEric Tremblay data->shunt_uohms, data->pga_gain); 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; 699fb99e07aSBiju 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 720fb99e07aSBiju Das data->max_channels = (uintptr_t)i2c_get_match_data(client); 72159dfa75eSEric Tremblay 72259dfa75eSEric Tremblay ret = tmp51x_configure(dev, data); 723df989762SAndy Shevchenko if (ret < 0) 724df989762SAndy Shevchenko return dev_err_probe(dev, ret, "error configuring the device\n"); 72559dfa75eSEric Tremblay 72659dfa75eSEric Tremblay data->regmap = devm_regmap_init_i2c(client, &tmp51x_regmap_config); 727df989762SAndy Shevchenko if (IS_ERR(data->regmap)) 728df989762SAndy Shevchenko return dev_err_probe(dev, PTR_ERR(data->regmap), 729df989762SAndy Shevchenko "failed to allocate register map\n"); 73059dfa75eSEric Tremblay 73159dfa75eSEric Tremblay ret = tmp51x_init(data); 732df989762SAndy Shevchenko if (ret < 0) 733df989762SAndy Shevchenko return dev_err_probe(dev, ret, "error configuring the device\n"); 73459dfa75eSEric Tremblay 73559dfa75eSEric Tremblay hwmon_dev = devm_hwmon_device_register_with_info(dev, client->name, 73659dfa75eSEric Tremblay data, 73759dfa75eSEric Tremblay &tmp51x_chip_info, 73859dfa75eSEric Tremblay NULL); 73959dfa75eSEric Tremblay if (IS_ERR(hwmon_dev)) 74059dfa75eSEric Tremblay return PTR_ERR(hwmon_dev); 74159dfa75eSEric Tremblay 742e3b9f691SStephen Kitt dev_dbg(dev, "power monitor %s\n", client->name); 74359dfa75eSEric Tremblay 74459dfa75eSEric Tremblay return 0; 74559dfa75eSEric Tremblay } 74659dfa75eSEric Tremblay 74759dfa75eSEric Tremblay static struct i2c_driver tmp51x_driver = { 74859dfa75eSEric Tremblay .driver = { 74959dfa75eSEric Tremblay .name = "tmp51x", 75000d85e81SKrzysztof Kozlowski .of_match_table = tmp51x_of_match, 75159dfa75eSEric Tremblay }, 7521975d167SUwe Kleine-König .probe = tmp51x_probe, 75359dfa75eSEric Tremblay .id_table = tmp51x_id, 75459dfa75eSEric Tremblay }; 75559dfa75eSEric Tremblay 75659dfa75eSEric Tremblay module_i2c_driver(tmp51x_driver); 75759dfa75eSEric Tremblay 75859dfa75eSEric Tremblay MODULE_AUTHOR("Eric Tremblay <etremblay@distechcontrols.com>"); 75959dfa75eSEric Tremblay MODULE_DESCRIPTION("tmp51x driver"); 76059dfa75eSEric Tremblay MODULE_LICENSE("GPL"); 761