xref: /kernel/linux/linux-5.10/drivers/hwmon/tmp513.c (revision 8c2ecf20)
18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Driver for Texas Instruments TMP512, TMP513 power monitor chips
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * TMP513:
68c2ecf20Sopenharmony_ci * Thermal/Power Management with Triple Remote and
78c2ecf20Sopenharmony_ci * Local Temperature Sensor and Current Shunt Monitor
88c2ecf20Sopenharmony_ci * Datasheet: https://www.ti.com/lit/gpn/tmp513
98c2ecf20Sopenharmony_ci *
108c2ecf20Sopenharmony_ci * TMP512:
118c2ecf20Sopenharmony_ci * Thermal/Power Management with Dual Remote
128c2ecf20Sopenharmony_ci *	and Local Temperature Sensor and Current Shunt Monitor
138c2ecf20Sopenharmony_ci * Datasheet: https://www.ti.com/lit/gpn/tmp512
148c2ecf20Sopenharmony_ci *
158c2ecf20Sopenharmony_ci * Copyright (C) 2019 Eric Tremblay <etremblay@distech-controls.com>
168c2ecf20Sopenharmony_ci *
178c2ecf20Sopenharmony_ci * This program is free software; you can redistribute it and/or modify
188c2ecf20Sopenharmony_ci * it under the terms of the GNU General Public License as published by
198c2ecf20Sopenharmony_ci * the Free Software Foundation; version 2 of the License.
208c2ecf20Sopenharmony_ci */
218c2ecf20Sopenharmony_ci
228c2ecf20Sopenharmony_ci#include <linux/err.h>
238c2ecf20Sopenharmony_ci#include <linux/hwmon.h>
248c2ecf20Sopenharmony_ci#include <linux/i2c.h>
258c2ecf20Sopenharmony_ci#include <linux/init.h>
268c2ecf20Sopenharmony_ci#include <linux/kernel.h>
278c2ecf20Sopenharmony_ci#include <linux/module.h>
288c2ecf20Sopenharmony_ci#include <linux/regmap.h>
298c2ecf20Sopenharmony_ci#include <linux/slab.h>
308c2ecf20Sopenharmony_ci#include <linux/util_macros.h>
318c2ecf20Sopenharmony_ci
328c2ecf20Sopenharmony_ci// Common register definition
338c2ecf20Sopenharmony_ci#define TMP51X_SHUNT_CONFIG		0x00
348c2ecf20Sopenharmony_ci#define TMP51X_TEMP_CONFIG		0x01
358c2ecf20Sopenharmony_ci#define TMP51X_STATUS			0x02
368c2ecf20Sopenharmony_ci#define TMP51X_SMBUS_ALERT		0x03
378c2ecf20Sopenharmony_ci#define TMP51X_SHUNT_CURRENT_RESULT	0x04
388c2ecf20Sopenharmony_ci#define TMP51X_BUS_VOLTAGE_RESULT	0x05
398c2ecf20Sopenharmony_ci#define TMP51X_POWER_RESULT		0x06
408c2ecf20Sopenharmony_ci#define TMP51X_BUS_CURRENT_RESULT	0x07
418c2ecf20Sopenharmony_ci#define TMP51X_LOCAL_TEMP_RESULT	0x08
428c2ecf20Sopenharmony_ci#define TMP51X_REMOTE_TEMP_RESULT_1	0x09
438c2ecf20Sopenharmony_ci#define TMP51X_REMOTE_TEMP_RESULT_2	0x0A
448c2ecf20Sopenharmony_ci#define TMP51X_SHUNT_CURRENT_H_LIMIT	0x0C
458c2ecf20Sopenharmony_ci#define TMP51X_SHUNT_CURRENT_L_LIMIT	0x0D
468c2ecf20Sopenharmony_ci#define TMP51X_BUS_VOLTAGE_H_LIMIT	0x0E
478c2ecf20Sopenharmony_ci#define TMP51X_BUS_VOLTAGE_L_LIMIT	0x0F
488c2ecf20Sopenharmony_ci#define TMP51X_POWER_LIMIT		0x10
498c2ecf20Sopenharmony_ci#define TMP51X_LOCAL_TEMP_LIMIT	0x11
508c2ecf20Sopenharmony_ci#define TMP51X_REMOTE_TEMP_LIMIT_1	0x12
518c2ecf20Sopenharmony_ci#define TMP51X_REMOTE_TEMP_LIMIT_2	0x13
528c2ecf20Sopenharmony_ci#define TMP51X_SHUNT_CALIBRATION	0x15
538c2ecf20Sopenharmony_ci#define TMP51X_N_FACTOR_AND_HYST_1	0x16
548c2ecf20Sopenharmony_ci#define TMP51X_N_FACTOR_2		0x17
558c2ecf20Sopenharmony_ci#define TMP51X_MAN_ID_REG		0xFE
568c2ecf20Sopenharmony_ci#define TMP51X_DEVICE_ID_REG		0xFF
578c2ecf20Sopenharmony_ci
588c2ecf20Sopenharmony_ci// TMP513 specific register definition
598c2ecf20Sopenharmony_ci#define TMP513_REMOTE_TEMP_RESULT_3	0x0B
608c2ecf20Sopenharmony_ci#define TMP513_REMOTE_TEMP_LIMIT_3	0x14
618c2ecf20Sopenharmony_ci#define TMP513_N_FACTOR_3		0x18
628c2ecf20Sopenharmony_ci
638c2ecf20Sopenharmony_ci// Common attrs, and NULL
648c2ecf20Sopenharmony_ci#define TMP51X_MANUFACTURER_ID		0x55FF
658c2ecf20Sopenharmony_ci
668c2ecf20Sopenharmony_ci#define TMP512_DEVICE_ID		0x22FF
678c2ecf20Sopenharmony_ci#define TMP513_DEVICE_ID		0x23FF
688c2ecf20Sopenharmony_ci
698c2ecf20Sopenharmony_ci// Default config
708c2ecf20Sopenharmony_ci#define TMP51X_SHUNT_CONFIG_DEFAULT	0x399F
718c2ecf20Sopenharmony_ci#define TMP51X_SHUNT_VALUE_DEFAULT	1000
728c2ecf20Sopenharmony_ci#define TMP51X_VBUS_RANGE_DEFAULT	TMP51X_VBUS_RANGE_32V
738c2ecf20Sopenharmony_ci#define TMP51X_PGA_DEFAULT		8
748c2ecf20Sopenharmony_ci#define TMP51X_MAX_REGISTER_ADDR	0xFF
758c2ecf20Sopenharmony_ci
768c2ecf20Sopenharmony_ci#define TMP512_TEMP_CONFIG_DEFAULT	0xBF80
778c2ecf20Sopenharmony_ci#define TMP513_TEMP_CONFIG_DEFAULT	0xFF80
788c2ecf20Sopenharmony_ci
798c2ecf20Sopenharmony_ci// Mask and shift
808c2ecf20Sopenharmony_ci#define CURRENT_SENSE_VOLTAGE_320_MASK	0x1800
818c2ecf20Sopenharmony_ci#define CURRENT_SENSE_VOLTAGE_160_MASK	0x1000
828c2ecf20Sopenharmony_ci#define CURRENT_SENSE_VOLTAGE_80_MASK	0x0800
838c2ecf20Sopenharmony_ci#define CURRENT_SENSE_VOLTAGE_40_MASK	0
848c2ecf20Sopenharmony_ci
858c2ecf20Sopenharmony_ci#define TMP51X_BUS_VOLTAGE_MASK		0x2000
868c2ecf20Sopenharmony_ci#define TMP51X_NFACTOR_MASK		0xFF00
878c2ecf20Sopenharmony_ci#define TMP51X_HYST_MASK		0x00FF
888c2ecf20Sopenharmony_ci
898c2ecf20Sopenharmony_ci#define TMP51X_BUS_VOLTAGE_SHIFT	3
908c2ecf20Sopenharmony_ci#define TMP51X_TEMP_SHIFT		3
918c2ecf20Sopenharmony_ci
928c2ecf20Sopenharmony_ci// Alarms
938c2ecf20Sopenharmony_ci#define TMP51X_SHUNT_CURRENT_H_LIMIT_POS	15
948c2ecf20Sopenharmony_ci#define TMP51X_SHUNT_CURRENT_L_LIMIT_POS	14
958c2ecf20Sopenharmony_ci#define TMP51X_BUS_VOLTAGE_H_LIMIT_POS		13
968c2ecf20Sopenharmony_ci#define TMP51X_BUS_VOLTAGE_L_LIMIT_POS		12
978c2ecf20Sopenharmony_ci#define TMP51X_POWER_LIMIT_POS			11
988c2ecf20Sopenharmony_ci#define TMP51X_LOCAL_TEMP_LIMIT_POS		10
998c2ecf20Sopenharmony_ci#define TMP51X_REMOTE_TEMP_LIMIT_1_POS		9
1008c2ecf20Sopenharmony_ci#define TMP51X_REMOTE_TEMP_LIMIT_2_POS		8
1018c2ecf20Sopenharmony_ci#define TMP513_REMOTE_TEMP_LIMIT_3_POS		7
1028c2ecf20Sopenharmony_ci
1038c2ecf20Sopenharmony_ci#define TMP51X_VBUS_RANGE_32V		32000000
1048c2ecf20Sopenharmony_ci#define TMP51X_VBUS_RANGE_16V		16000000
1058c2ecf20Sopenharmony_ci
1068c2ecf20Sopenharmony_ci// Max and Min value
1078c2ecf20Sopenharmony_ci#define MAX_BUS_VOLTAGE_32_LIMIT	32764
1088c2ecf20Sopenharmony_ci#define MAX_BUS_VOLTAGE_16_LIMIT	16382
1098c2ecf20Sopenharmony_ci
1108c2ecf20Sopenharmony_ci// Max possible value is -256 to +256 but datasheet indicated -40 to 125.
1118c2ecf20Sopenharmony_ci#define MAX_TEMP_LIMIT			125000
1128c2ecf20Sopenharmony_ci#define MIN_TEMP_LIMIT			-40000
1138c2ecf20Sopenharmony_ci
1148c2ecf20Sopenharmony_ci#define MAX_TEMP_HYST			127500
1158c2ecf20Sopenharmony_ci
1168c2ecf20Sopenharmony_cistatic const u8 TMP51X_TEMP_INPUT[4] = {
1178c2ecf20Sopenharmony_ci	TMP51X_LOCAL_TEMP_RESULT,
1188c2ecf20Sopenharmony_ci	TMP51X_REMOTE_TEMP_RESULT_1,
1198c2ecf20Sopenharmony_ci	TMP51X_REMOTE_TEMP_RESULT_2,
1208c2ecf20Sopenharmony_ci	TMP513_REMOTE_TEMP_RESULT_3
1218c2ecf20Sopenharmony_ci};
1228c2ecf20Sopenharmony_ci
1238c2ecf20Sopenharmony_cistatic const u8 TMP51X_TEMP_CRIT[4] = {
1248c2ecf20Sopenharmony_ci	TMP51X_LOCAL_TEMP_LIMIT,
1258c2ecf20Sopenharmony_ci	TMP51X_REMOTE_TEMP_LIMIT_1,
1268c2ecf20Sopenharmony_ci	TMP51X_REMOTE_TEMP_LIMIT_2,
1278c2ecf20Sopenharmony_ci	TMP513_REMOTE_TEMP_LIMIT_3
1288c2ecf20Sopenharmony_ci};
1298c2ecf20Sopenharmony_ci
1308c2ecf20Sopenharmony_cistatic const u8 TMP51X_TEMP_CRIT_ALARM[4] = {
1318c2ecf20Sopenharmony_ci	TMP51X_LOCAL_TEMP_LIMIT_POS,
1328c2ecf20Sopenharmony_ci	TMP51X_REMOTE_TEMP_LIMIT_1_POS,
1338c2ecf20Sopenharmony_ci	TMP51X_REMOTE_TEMP_LIMIT_2_POS,
1348c2ecf20Sopenharmony_ci	TMP513_REMOTE_TEMP_LIMIT_3_POS
1358c2ecf20Sopenharmony_ci};
1368c2ecf20Sopenharmony_ci
1378c2ecf20Sopenharmony_cistatic const u8 TMP51X_TEMP_CRIT_HYST[4] = {
1388c2ecf20Sopenharmony_ci	TMP51X_N_FACTOR_AND_HYST_1,
1398c2ecf20Sopenharmony_ci	TMP51X_N_FACTOR_AND_HYST_1,
1408c2ecf20Sopenharmony_ci	TMP51X_N_FACTOR_AND_HYST_1,
1418c2ecf20Sopenharmony_ci	TMP51X_N_FACTOR_AND_HYST_1
1428c2ecf20Sopenharmony_ci};
1438c2ecf20Sopenharmony_ci
1448c2ecf20Sopenharmony_cistatic const u8 TMP51X_CURR_INPUT[2] = {
1458c2ecf20Sopenharmony_ci	TMP51X_SHUNT_CURRENT_RESULT,
1468c2ecf20Sopenharmony_ci	TMP51X_BUS_CURRENT_RESULT
1478c2ecf20Sopenharmony_ci};
1488c2ecf20Sopenharmony_ci
1498c2ecf20Sopenharmony_cistatic struct regmap_config tmp51x_regmap_config = {
1508c2ecf20Sopenharmony_ci	.reg_bits = 8,
1518c2ecf20Sopenharmony_ci	.val_bits = 16,
1528c2ecf20Sopenharmony_ci	.max_register = TMP51X_MAX_REGISTER_ADDR,
1538c2ecf20Sopenharmony_ci};
1548c2ecf20Sopenharmony_ci
1558c2ecf20Sopenharmony_cienum tmp51x_ids {
1568c2ecf20Sopenharmony_ci	tmp512, tmp513
1578c2ecf20Sopenharmony_ci};
1588c2ecf20Sopenharmony_ci
1598c2ecf20Sopenharmony_cistruct tmp51x_data {
1608c2ecf20Sopenharmony_ci	u16 shunt_config;
1618c2ecf20Sopenharmony_ci	u16 pga_gain;
1628c2ecf20Sopenharmony_ci	u32 vbus_range_uvolt;
1638c2ecf20Sopenharmony_ci
1648c2ecf20Sopenharmony_ci	u16 temp_config;
1658c2ecf20Sopenharmony_ci	u32 nfactor[3];
1668c2ecf20Sopenharmony_ci
1678c2ecf20Sopenharmony_ci	u32 shunt_uohms;
1688c2ecf20Sopenharmony_ci
1698c2ecf20Sopenharmony_ci	u32 curr_lsb_ua;
1708c2ecf20Sopenharmony_ci	u32 pwr_lsb_uw;
1718c2ecf20Sopenharmony_ci
1728c2ecf20Sopenharmony_ci	enum tmp51x_ids id;
1738c2ecf20Sopenharmony_ci	struct regmap *regmap;
1748c2ecf20Sopenharmony_ci};
1758c2ecf20Sopenharmony_ci
1768c2ecf20Sopenharmony_ci// Set the shift based on the gain 8=4, 4=3, 2=2, 1=1
1778c2ecf20Sopenharmony_cistatic inline u8 tmp51x_get_pga_shift(struct tmp51x_data *data)
1788c2ecf20Sopenharmony_ci{
1798c2ecf20Sopenharmony_ci	return 5 - ffs(data->pga_gain);
1808c2ecf20Sopenharmony_ci}
1818c2ecf20Sopenharmony_ci
1828c2ecf20Sopenharmony_cistatic int tmp51x_get_value(struct tmp51x_data *data, u8 reg, u8 pos,
1838c2ecf20Sopenharmony_ci			    unsigned int regval, long *val)
1848c2ecf20Sopenharmony_ci{
1858c2ecf20Sopenharmony_ci	switch (reg) {
1868c2ecf20Sopenharmony_ci	case TMP51X_STATUS:
1878c2ecf20Sopenharmony_ci		*val = (regval >> pos) & 1;
1888c2ecf20Sopenharmony_ci		break;
1898c2ecf20Sopenharmony_ci	case TMP51X_SHUNT_CURRENT_RESULT:
1908c2ecf20Sopenharmony_ci	case TMP51X_SHUNT_CURRENT_H_LIMIT:
1918c2ecf20Sopenharmony_ci	case TMP51X_SHUNT_CURRENT_L_LIMIT:
1928c2ecf20Sopenharmony_ci		/*
1938c2ecf20Sopenharmony_ci		 * The valus is read in voltage in the chip but reported as
1948c2ecf20Sopenharmony_ci		 * current to the user.
1958c2ecf20Sopenharmony_ci		 * 2's complement number shifted by one to four depending
1968c2ecf20Sopenharmony_ci		 * on the pga gain setting. 1lsb = 10uV
1978c2ecf20Sopenharmony_ci		 */
1988c2ecf20Sopenharmony_ci		*val = sign_extend32(regval, 17 - tmp51x_get_pga_shift(data));
1998c2ecf20Sopenharmony_ci		*val = DIV_ROUND_CLOSEST(*val * 10000, data->shunt_uohms);
2008c2ecf20Sopenharmony_ci		break;
2018c2ecf20Sopenharmony_ci	case TMP51X_BUS_VOLTAGE_RESULT:
2028c2ecf20Sopenharmony_ci	case TMP51X_BUS_VOLTAGE_H_LIMIT:
2038c2ecf20Sopenharmony_ci	case TMP51X_BUS_VOLTAGE_L_LIMIT:
2048c2ecf20Sopenharmony_ci		// 1lsb = 4mV
2058c2ecf20Sopenharmony_ci		*val = (regval >> TMP51X_BUS_VOLTAGE_SHIFT) * 4;
2068c2ecf20Sopenharmony_ci		break;
2078c2ecf20Sopenharmony_ci	case TMP51X_POWER_RESULT:
2088c2ecf20Sopenharmony_ci	case TMP51X_POWER_LIMIT:
2098c2ecf20Sopenharmony_ci		// Power = (current * BusVoltage) / 5000
2108c2ecf20Sopenharmony_ci		*val = regval * data->pwr_lsb_uw;
2118c2ecf20Sopenharmony_ci		break;
2128c2ecf20Sopenharmony_ci	case TMP51X_BUS_CURRENT_RESULT:
2138c2ecf20Sopenharmony_ci		// Current = (ShuntVoltage * CalibrationRegister) / 4096
2148c2ecf20Sopenharmony_ci		*val = sign_extend32(regval, 16) * data->curr_lsb_ua;
2158c2ecf20Sopenharmony_ci		*val = DIV_ROUND_CLOSEST(*val, 1000);
2168c2ecf20Sopenharmony_ci		break;
2178c2ecf20Sopenharmony_ci	case TMP51X_LOCAL_TEMP_RESULT:
2188c2ecf20Sopenharmony_ci	case TMP51X_REMOTE_TEMP_RESULT_1:
2198c2ecf20Sopenharmony_ci	case TMP51X_REMOTE_TEMP_RESULT_2:
2208c2ecf20Sopenharmony_ci	case TMP513_REMOTE_TEMP_RESULT_3:
2218c2ecf20Sopenharmony_ci	case TMP51X_LOCAL_TEMP_LIMIT:
2228c2ecf20Sopenharmony_ci	case TMP51X_REMOTE_TEMP_LIMIT_1:
2238c2ecf20Sopenharmony_ci	case TMP51X_REMOTE_TEMP_LIMIT_2:
2248c2ecf20Sopenharmony_ci	case TMP513_REMOTE_TEMP_LIMIT_3:
2258c2ecf20Sopenharmony_ci		// 1lsb = 0.0625 degrees centigrade
2268c2ecf20Sopenharmony_ci		*val = sign_extend32(regval, 16) >> TMP51X_TEMP_SHIFT;
2278c2ecf20Sopenharmony_ci		*val = DIV_ROUND_CLOSEST(*val * 625, 10);
2288c2ecf20Sopenharmony_ci		break;
2298c2ecf20Sopenharmony_ci	case TMP51X_N_FACTOR_AND_HYST_1:
2308c2ecf20Sopenharmony_ci		// 1lsb = 0.5 degrees centigrade
2318c2ecf20Sopenharmony_ci		*val = (regval & TMP51X_HYST_MASK) * 500;
2328c2ecf20Sopenharmony_ci		break;
2338c2ecf20Sopenharmony_ci	default:
2348c2ecf20Sopenharmony_ci		// Programmer goofed
2358c2ecf20Sopenharmony_ci		WARN_ON_ONCE(1);
2368c2ecf20Sopenharmony_ci		*val = 0;
2378c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
2388c2ecf20Sopenharmony_ci	}
2398c2ecf20Sopenharmony_ci
2408c2ecf20Sopenharmony_ci	return 0;
2418c2ecf20Sopenharmony_ci}
2428c2ecf20Sopenharmony_ci
2438c2ecf20Sopenharmony_cistatic int tmp51x_set_value(struct tmp51x_data *data, u8 reg, long val)
2448c2ecf20Sopenharmony_ci{
2458c2ecf20Sopenharmony_ci	int regval, max_val;
2468c2ecf20Sopenharmony_ci	u32 mask = 0;
2478c2ecf20Sopenharmony_ci
2488c2ecf20Sopenharmony_ci	switch (reg) {
2498c2ecf20Sopenharmony_ci	case TMP51X_SHUNT_CURRENT_H_LIMIT:
2508c2ecf20Sopenharmony_ci	case TMP51X_SHUNT_CURRENT_L_LIMIT:
2518c2ecf20Sopenharmony_ci		/*
2528c2ecf20Sopenharmony_ci		 * The user enter current value and we convert it to
2538c2ecf20Sopenharmony_ci		 * voltage. 1lsb = 10uV
2548c2ecf20Sopenharmony_ci		 */
2558c2ecf20Sopenharmony_ci		val = DIV_ROUND_CLOSEST(val * data->shunt_uohms, 10000);
2568c2ecf20Sopenharmony_ci		max_val = U16_MAX >> tmp51x_get_pga_shift(data);
2578c2ecf20Sopenharmony_ci		regval = clamp_val(val, -max_val, max_val);
2588c2ecf20Sopenharmony_ci		break;
2598c2ecf20Sopenharmony_ci	case TMP51X_BUS_VOLTAGE_H_LIMIT:
2608c2ecf20Sopenharmony_ci	case TMP51X_BUS_VOLTAGE_L_LIMIT:
2618c2ecf20Sopenharmony_ci		// 1lsb = 4mV
2628c2ecf20Sopenharmony_ci		max_val = (data->vbus_range_uvolt == TMP51X_VBUS_RANGE_32V) ?
2638c2ecf20Sopenharmony_ci			MAX_BUS_VOLTAGE_32_LIMIT : MAX_BUS_VOLTAGE_16_LIMIT;
2648c2ecf20Sopenharmony_ci
2658c2ecf20Sopenharmony_ci		val = clamp_val(DIV_ROUND_CLOSEST(val, 4), 0, max_val);
2668c2ecf20Sopenharmony_ci		regval = val << TMP51X_BUS_VOLTAGE_SHIFT;
2678c2ecf20Sopenharmony_ci		break;
2688c2ecf20Sopenharmony_ci	case TMP51X_POWER_LIMIT:
2698c2ecf20Sopenharmony_ci		regval = clamp_val(DIV_ROUND_CLOSEST(val, data->pwr_lsb_uw), 0,
2708c2ecf20Sopenharmony_ci				   U16_MAX);
2718c2ecf20Sopenharmony_ci		break;
2728c2ecf20Sopenharmony_ci	case TMP51X_LOCAL_TEMP_LIMIT:
2738c2ecf20Sopenharmony_ci	case TMP51X_REMOTE_TEMP_LIMIT_1:
2748c2ecf20Sopenharmony_ci	case TMP51X_REMOTE_TEMP_LIMIT_2:
2758c2ecf20Sopenharmony_ci	case TMP513_REMOTE_TEMP_LIMIT_3:
2768c2ecf20Sopenharmony_ci		// 1lsb = 0.0625 degrees centigrade
2778c2ecf20Sopenharmony_ci		val = clamp_val(val, MIN_TEMP_LIMIT, MAX_TEMP_LIMIT);
2788c2ecf20Sopenharmony_ci		regval = DIV_ROUND_CLOSEST(val * 10, 625) << TMP51X_TEMP_SHIFT;
2798c2ecf20Sopenharmony_ci		break;
2808c2ecf20Sopenharmony_ci	case TMP51X_N_FACTOR_AND_HYST_1:
2818c2ecf20Sopenharmony_ci		// 1lsb = 0.5 degrees centigrade
2828c2ecf20Sopenharmony_ci		val = clamp_val(val, 0, MAX_TEMP_HYST);
2838c2ecf20Sopenharmony_ci		regval = DIV_ROUND_CLOSEST(val, 500);
2848c2ecf20Sopenharmony_ci		mask = TMP51X_HYST_MASK;
2858c2ecf20Sopenharmony_ci		break;
2868c2ecf20Sopenharmony_ci	default:
2878c2ecf20Sopenharmony_ci		// Programmer goofed
2888c2ecf20Sopenharmony_ci		WARN_ON_ONCE(1);
2898c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
2908c2ecf20Sopenharmony_ci	}
2918c2ecf20Sopenharmony_ci
2928c2ecf20Sopenharmony_ci	if (mask == 0)
2938c2ecf20Sopenharmony_ci		return regmap_write(data->regmap, reg, regval);
2948c2ecf20Sopenharmony_ci	else
2958c2ecf20Sopenharmony_ci		return regmap_update_bits(data->regmap, reg, mask, regval);
2968c2ecf20Sopenharmony_ci}
2978c2ecf20Sopenharmony_ci
2988c2ecf20Sopenharmony_cistatic u8 tmp51x_get_reg(enum hwmon_sensor_types type, u32 attr, int channel)
2998c2ecf20Sopenharmony_ci{
3008c2ecf20Sopenharmony_ci	switch (type) {
3018c2ecf20Sopenharmony_ci	case hwmon_temp:
3028c2ecf20Sopenharmony_ci		switch (attr) {
3038c2ecf20Sopenharmony_ci		case hwmon_temp_input:
3048c2ecf20Sopenharmony_ci			return TMP51X_TEMP_INPUT[channel];
3058c2ecf20Sopenharmony_ci		case hwmon_temp_crit_alarm:
3068c2ecf20Sopenharmony_ci			return TMP51X_STATUS;
3078c2ecf20Sopenharmony_ci		case hwmon_temp_crit:
3088c2ecf20Sopenharmony_ci			return TMP51X_TEMP_CRIT[channel];
3098c2ecf20Sopenharmony_ci		case hwmon_temp_crit_hyst:
3108c2ecf20Sopenharmony_ci			return TMP51X_TEMP_CRIT_HYST[channel];
3118c2ecf20Sopenharmony_ci		}
3128c2ecf20Sopenharmony_ci		break;
3138c2ecf20Sopenharmony_ci	case hwmon_in:
3148c2ecf20Sopenharmony_ci		switch (attr) {
3158c2ecf20Sopenharmony_ci		case hwmon_in_input:
3168c2ecf20Sopenharmony_ci			return TMP51X_BUS_VOLTAGE_RESULT;
3178c2ecf20Sopenharmony_ci		case hwmon_in_lcrit_alarm:
3188c2ecf20Sopenharmony_ci		case hwmon_in_crit_alarm:
3198c2ecf20Sopenharmony_ci			return TMP51X_STATUS;
3208c2ecf20Sopenharmony_ci		case hwmon_in_lcrit:
3218c2ecf20Sopenharmony_ci			return TMP51X_BUS_VOLTAGE_L_LIMIT;
3228c2ecf20Sopenharmony_ci		case hwmon_in_crit:
3238c2ecf20Sopenharmony_ci			return TMP51X_BUS_VOLTAGE_H_LIMIT;
3248c2ecf20Sopenharmony_ci		}
3258c2ecf20Sopenharmony_ci		break;
3268c2ecf20Sopenharmony_ci	case hwmon_curr:
3278c2ecf20Sopenharmony_ci		switch (attr) {
3288c2ecf20Sopenharmony_ci		case hwmon_curr_input:
3298c2ecf20Sopenharmony_ci			return TMP51X_CURR_INPUT[channel];
3308c2ecf20Sopenharmony_ci		case hwmon_curr_lcrit_alarm:
3318c2ecf20Sopenharmony_ci		case hwmon_curr_crit_alarm:
3328c2ecf20Sopenharmony_ci			return TMP51X_STATUS;
3338c2ecf20Sopenharmony_ci		case hwmon_curr_lcrit:
3348c2ecf20Sopenharmony_ci			return TMP51X_SHUNT_CURRENT_L_LIMIT;
3358c2ecf20Sopenharmony_ci		case hwmon_curr_crit:
3368c2ecf20Sopenharmony_ci			return TMP51X_SHUNT_CURRENT_H_LIMIT;
3378c2ecf20Sopenharmony_ci		}
3388c2ecf20Sopenharmony_ci		break;
3398c2ecf20Sopenharmony_ci	case hwmon_power:
3408c2ecf20Sopenharmony_ci		switch (attr) {
3418c2ecf20Sopenharmony_ci		case hwmon_power_input:
3428c2ecf20Sopenharmony_ci			return TMP51X_POWER_RESULT;
3438c2ecf20Sopenharmony_ci		case hwmon_power_crit_alarm:
3448c2ecf20Sopenharmony_ci			return TMP51X_STATUS;
3458c2ecf20Sopenharmony_ci		case hwmon_power_crit:
3468c2ecf20Sopenharmony_ci			return TMP51X_POWER_LIMIT;
3478c2ecf20Sopenharmony_ci		}
3488c2ecf20Sopenharmony_ci		break;
3498c2ecf20Sopenharmony_ci	default:
3508c2ecf20Sopenharmony_ci		break;
3518c2ecf20Sopenharmony_ci	}
3528c2ecf20Sopenharmony_ci
3538c2ecf20Sopenharmony_ci	return 0;
3548c2ecf20Sopenharmony_ci}
3558c2ecf20Sopenharmony_ci
3568c2ecf20Sopenharmony_cistatic u8 tmp51x_get_status_pos(enum hwmon_sensor_types type, u32 attr,
3578c2ecf20Sopenharmony_ci				int channel)
3588c2ecf20Sopenharmony_ci{
3598c2ecf20Sopenharmony_ci	switch (type) {
3608c2ecf20Sopenharmony_ci	case hwmon_temp:
3618c2ecf20Sopenharmony_ci		switch (attr) {
3628c2ecf20Sopenharmony_ci		case hwmon_temp_crit_alarm:
3638c2ecf20Sopenharmony_ci			return TMP51X_TEMP_CRIT_ALARM[channel];
3648c2ecf20Sopenharmony_ci		}
3658c2ecf20Sopenharmony_ci		break;
3668c2ecf20Sopenharmony_ci	case hwmon_in:
3678c2ecf20Sopenharmony_ci		switch (attr) {
3688c2ecf20Sopenharmony_ci		case hwmon_in_lcrit_alarm:
3698c2ecf20Sopenharmony_ci			return TMP51X_BUS_VOLTAGE_L_LIMIT_POS;
3708c2ecf20Sopenharmony_ci		case hwmon_in_crit_alarm:
3718c2ecf20Sopenharmony_ci			return TMP51X_BUS_VOLTAGE_H_LIMIT_POS;
3728c2ecf20Sopenharmony_ci		}
3738c2ecf20Sopenharmony_ci		break;
3748c2ecf20Sopenharmony_ci	case hwmon_curr:
3758c2ecf20Sopenharmony_ci		switch (attr) {
3768c2ecf20Sopenharmony_ci		case hwmon_curr_lcrit_alarm:
3778c2ecf20Sopenharmony_ci			return TMP51X_SHUNT_CURRENT_L_LIMIT_POS;
3788c2ecf20Sopenharmony_ci		case hwmon_curr_crit_alarm:
3798c2ecf20Sopenharmony_ci			return TMP51X_SHUNT_CURRENT_H_LIMIT_POS;
3808c2ecf20Sopenharmony_ci		}
3818c2ecf20Sopenharmony_ci		break;
3828c2ecf20Sopenharmony_ci	case hwmon_power:
3838c2ecf20Sopenharmony_ci		switch (attr) {
3848c2ecf20Sopenharmony_ci		case hwmon_power_crit_alarm:
3858c2ecf20Sopenharmony_ci			return TMP51X_POWER_LIMIT_POS;
3868c2ecf20Sopenharmony_ci		}
3878c2ecf20Sopenharmony_ci		break;
3888c2ecf20Sopenharmony_ci	default:
3898c2ecf20Sopenharmony_ci		break;
3908c2ecf20Sopenharmony_ci	}
3918c2ecf20Sopenharmony_ci
3928c2ecf20Sopenharmony_ci	return 0;
3938c2ecf20Sopenharmony_ci}
3948c2ecf20Sopenharmony_ci
3958c2ecf20Sopenharmony_cistatic int tmp51x_read(struct device *dev, enum hwmon_sensor_types type,
3968c2ecf20Sopenharmony_ci		       u32 attr, int channel, long *val)
3978c2ecf20Sopenharmony_ci{
3988c2ecf20Sopenharmony_ci	struct tmp51x_data *data = dev_get_drvdata(dev);
3998c2ecf20Sopenharmony_ci	int ret;
4008c2ecf20Sopenharmony_ci	u32 regval;
4018c2ecf20Sopenharmony_ci	u8 pos = 0, reg = 0;
4028c2ecf20Sopenharmony_ci
4038c2ecf20Sopenharmony_ci	reg = tmp51x_get_reg(type, attr, channel);
4048c2ecf20Sopenharmony_ci	if (reg == 0)
4058c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
4068c2ecf20Sopenharmony_ci
4078c2ecf20Sopenharmony_ci	if (reg == TMP51X_STATUS)
4088c2ecf20Sopenharmony_ci		pos = tmp51x_get_status_pos(type, attr, channel);
4098c2ecf20Sopenharmony_ci
4108c2ecf20Sopenharmony_ci	ret = regmap_read(data->regmap, reg, &regval);
4118c2ecf20Sopenharmony_ci	if (ret < 0)
4128c2ecf20Sopenharmony_ci		return ret;
4138c2ecf20Sopenharmony_ci
4148c2ecf20Sopenharmony_ci	return tmp51x_get_value(data, reg, pos, regval, val);
4158c2ecf20Sopenharmony_ci}
4168c2ecf20Sopenharmony_ci
4178c2ecf20Sopenharmony_cistatic int tmp51x_write(struct device *dev, enum hwmon_sensor_types type,
4188c2ecf20Sopenharmony_ci			u32 attr, int channel, long val)
4198c2ecf20Sopenharmony_ci{
4208c2ecf20Sopenharmony_ci	u8 reg = 0;
4218c2ecf20Sopenharmony_ci
4228c2ecf20Sopenharmony_ci	reg = tmp51x_get_reg(type, attr, channel);
4238c2ecf20Sopenharmony_ci	if (reg == 0)
4248c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
4258c2ecf20Sopenharmony_ci
4268c2ecf20Sopenharmony_ci	return tmp51x_set_value(dev_get_drvdata(dev), reg, val);
4278c2ecf20Sopenharmony_ci}
4288c2ecf20Sopenharmony_ci
4298c2ecf20Sopenharmony_cistatic umode_t tmp51x_is_visible(const void *_data,
4308c2ecf20Sopenharmony_ci				 enum hwmon_sensor_types type, u32 attr,
4318c2ecf20Sopenharmony_ci				 int channel)
4328c2ecf20Sopenharmony_ci{
4338c2ecf20Sopenharmony_ci	const struct tmp51x_data *data = _data;
4348c2ecf20Sopenharmony_ci
4358c2ecf20Sopenharmony_ci	switch (type) {
4368c2ecf20Sopenharmony_ci	case hwmon_temp:
4378c2ecf20Sopenharmony_ci		if (data->id == tmp512 && channel == 3)
4388c2ecf20Sopenharmony_ci			return 0;
4398c2ecf20Sopenharmony_ci		switch (attr) {
4408c2ecf20Sopenharmony_ci		case hwmon_temp_input:
4418c2ecf20Sopenharmony_ci		case hwmon_temp_crit_alarm:
4428c2ecf20Sopenharmony_ci			return 0444;
4438c2ecf20Sopenharmony_ci		case hwmon_temp_crit:
4448c2ecf20Sopenharmony_ci			return 0644;
4458c2ecf20Sopenharmony_ci		case hwmon_temp_crit_hyst:
4468c2ecf20Sopenharmony_ci			if (channel == 0)
4478c2ecf20Sopenharmony_ci				return 0644;
4488c2ecf20Sopenharmony_ci			return 0444;
4498c2ecf20Sopenharmony_ci		}
4508c2ecf20Sopenharmony_ci		break;
4518c2ecf20Sopenharmony_ci	case hwmon_in:
4528c2ecf20Sopenharmony_ci		switch (attr) {
4538c2ecf20Sopenharmony_ci		case hwmon_in_input:
4548c2ecf20Sopenharmony_ci		case hwmon_in_lcrit_alarm:
4558c2ecf20Sopenharmony_ci		case hwmon_in_crit_alarm:
4568c2ecf20Sopenharmony_ci			return 0444;
4578c2ecf20Sopenharmony_ci		case hwmon_in_lcrit:
4588c2ecf20Sopenharmony_ci		case hwmon_in_crit:
4598c2ecf20Sopenharmony_ci			return 0644;
4608c2ecf20Sopenharmony_ci		}
4618c2ecf20Sopenharmony_ci		break;
4628c2ecf20Sopenharmony_ci	case hwmon_curr:
4638c2ecf20Sopenharmony_ci		if (!data->shunt_uohms)
4648c2ecf20Sopenharmony_ci			return 0;
4658c2ecf20Sopenharmony_ci
4668c2ecf20Sopenharmony_ci		switch (attr) {
4678c2ecf20Sopenharmony_ci		case hwmon_curr_input:
4688c2ecf20Sopenharmony_ci		case hwmon_curr_lcrit_alarm:
4698c2ecf20Sopenharmony_ci		case hwmon_curr_crit_alarm:
4708c2ecf20Sopenharmony_ci			return 0444;
4718c2ecf20Sopenharmony_ci		case hwmon_curr_lcrit:
4728c2ecf20Sopenharmony_ci		case hwmon_curr_crit:
4738c2ecf20Sopenharmony_ci			return 0644;
4748c2ecf20Sopenharmony_ci		}
4758c2ecf20Sopenharmony_ci		break;
4768c2ecf20Sopenharmony_ci	case hwmon_power:
4778c2ecf20Sopenharmony_ci		if (!data->shunt_uohms)
4788c2ecf20Sopenharmony_ci			return 0;
4798c2ecf20Sopenharmony_ci
4808c2ecf20Sopenharmony_ci		switch (attr) {
4818c2ecf20Sopenharmony_ci		case hwmon_power_input:
4828c2ecf20Sopenharmony_ci		case hwmon_power_crit_alarm:
4838c2ecf20Sopenharmony_ci			return 0444;
4848c2ecf20Sopenharmony_ci		case hwmon_power_crit:
4858c2ecf20Sopenharmony_ci			return 0644;
4868c2ecf20Sopenharmony_ci		}
4878c2ecf20Sopenharmony_ci		break;
4888c2ecf20Sopenharmony_ci	default:
4898c2ecf20Sopenharmony_ci		break;
4908c2ecf20Sopenharmony_ci	}
4918c2ecf20Sopenharmony_ci	return 0;
4928c2ecf20Sopenharmony_ci}
4938c2ecf20Sopenharmony_ci
4948c2ecf20Sopenharmony_cistatic const struct hwmon_channel_info *tmp51x_info[] = {
4958c2ecf20Sopenharmony_ci	HWMON_CHANNEL_INFO(temp,
4968c2ecf20Sopenharmony_ci			   HWMON_T_INPUT | HWMON_T_CRIT | HWMON_T_CRIT_ALARM |
4978c2ecf20Sopenharmony_ci			   HWMON_T_CRIT_HYST,
4988c2ecf20Sopenharmony_ci			   HWMON_T_INPUT | HWMON_T_CRIT | HWMON_T_CRIT_ALARM |
4998c2ecf20Sopenharmony_ci			   HWMON_T_CRIT_HYST,
5008c2ecf20Sopenharmony_ci			   HWMON_T_INPUT | HWMON_T_CRIT | HWMON_T_CRIT_ALARM |
5018c2ecf20Sopenharmony_ci			   HWMON_T_CRIT_HYST,
5028c2ecf20Sopenharmony_ci			   HWMON_T_INPUT | HWMON_T_CRIT | HWMON_T_CRIT_ALARM |
5038c2ecf20Sopenharmony_ci			   HWMON_T_CRIT_HYST),
5048c2ecf20Sopenharmony_ci	HWMON_CHANNEL_INFO(in,
5058c2ecf20Sopenharmony_ci			   HWMON_I_INPUT | HWMON_I_LCRIT | HWMON_I_LCRIT_ALARM |
5068c2ecf20Sopenharmony_ci			   HWMON_I_CRIT | HWMON_I_CRIT_ALARM),
5078c2ecf20Sopenharmony_ci	HWMON_CHANNEL_INFO(curr,
5088c2ecf20Sopenharmony_ci			   HWMON_C_INPUT | HWMON_C_LCRIT | HWMON_C_LCRIT_ALARM |
5098c2ecf20Sopenharmony_ci			   HWMON_C_CRIT | HWMON_C_CRIT_ALARM,
5108c2ecf20Sopenharmony_ci			   HWMON_C_INPUT),
5118c2ecf20Sopenharmony_ci	HWMON_CHANNEL_INFO(power,
5128c2ecf20Sopenharmony_ci			   HWMON_P_INPUT | HWMON_P_CRIT | HWMON_P_CRIT_ALARM),
5138c2ecf20Sopenharmony_ci	NULL
5148c2ecf20Sopenharmony_ci};
5158c2ecf20Sopenharmony_ci
5168c2ecf20Sopenharmony_cistatic const struct hwmon_ops tmp51x_hwmon_ops = {
5178c2ecf20Sopenharmony_ci	.is_visible = tmp51x_is_visible,
5188c2ecf20Sopenharmony_ci	.read = tmp51x_read,
5198c2ecf20Sopenharmony_ci	.write = tmp51x_write,
5208c2ecf20Sopenharmony_ci};
5218c2ecf20Sopenharmony_ci
5228c2ecf20Sopenharmony_cistatic const struct hwmon_chip_info tmp51x_chip_info = {
5238c2ecf20Sopenharmony_ci	.ops = &tmp51x_hwmon_ops,
5248c2ecf20Sopenharmony_ci	.info = tmp51x_info,
5258c2ecf20Sopenharmony_ci};
5268c2ecf20Sopenharmony_ci
5278c2ecf20Sopenharmony_ci/*
5288c2ecf20Sopenharmony_ci * Calibrate the tmp51x following the datasheet method
5298c2ecf20Sopenharmony_ci */
5308c2ecf20Sopenharmony_cistatic int tmp51x_calibrate(struct tmp51x_data *data)
5318c2ecf20Sopenharmony_ci{
5328c2ecf20Sopenharmony_ci	int vshunt_max = data->pga_gain * 40;
5338c2ecf20Sopenharmony_ci	u64 max_curr_ma;
5348c2ecf20Sopenharmony_ci	u32 div;
5358c2ecf20Sopenharmony_ci
5368c2ecf20Sopenharmony_ci	/*
5378c2ecf20Sopenharmony_ci	 * If shunt_uohms is equal to 0, the calibration should be set to 0.
5388c2ecf20Sopenharmony_ci	 * The consequence will be that the current and power measurement engine
5398c2ecf20Sopenharmony_ci	 * of the sensor will not work. Temperature and voltage sensing will
5408c2ecf20Sopenharmony_ci	 * continue to work.
5418c2ecf20Sopenharmony_ci	 */
5428c2ecf20Sopenharmony_ci	if (data->shunt_uohms == 0)
5438c2ecf20Sopenharmony_ci		return regmap_write(data->regmap, TMP51X_SHUNT_CALIBRATION, 0);
5448c2ecf20Sopenharmony_ci
5458c2ecf20Sopenharmony_ci	max_curr_ma = DIV_ROUND_CLOSEST_ULL(vshunt_max * 1000 * 1000,
5468c2ecf20Sopenharmony_ci					    data->shunt_uohms);
5478c2ecf20Sopenharmony_ci
5488c2ecf20Sopenharmony_ci	/*
5498c2ecf20Sopenharmony_ci	 * Calculate the minimal bit resolution for the current and the power.
5508c2ecf20Sopenharmony_ci	 * Those values will be used during register interpretation.
5518c2ecf20Sopenharmony_ci	 */
5528c2ecf20Sopenharmony_ci	data->curr_lsb_ua = DIV_ROUND_CLOSEST_ULL(max_curr_ma * 1000, 32767);
5538c2ecf20Sopenharmony_ci	data->pwr_lsb_uw = 20 * data->curr_lsb_ua;
5548c2ecf20Sopenharmony_ci
5558c2ecf20Sopenharmony_ci	div = DIV_ROUND_CLOSEST_ULL(data->curr_lsb_ua * data->shunt_uohms,
5568c2ecf20Sopenharmony_ci				    1000 * 1000);
5578c2ecf20Sopenharmony_ci
5588c2ecf20Sopenharmony_ci	return regmap_write(data->regmap, TMP51X_SHUNT_CALIBRATION,
5598c2ecf20Sopenharmony_ci			    DIV_ROUND_CLOSEST(40960, div));
5608c2ecf20Sopenharmony_ci}
5618c2ecf20Sopenharmony_ci
5628c2ecf20Sopenharmony_ci/*
5638c2ecf20Sopenharmony_ci * Initialize the configuration and calibration registers.
5648c2ecf20Sopenharmony_ci */
5658c2ecf20Sopenharmony_cistatic int tmp51x_init(struct tmp51x_data *data)
5668c2ecf20Sopenharmony_ci{
5678c2ecf20Sopenharmony_ci	unsigned int regval;
5688c2ecf20Sopenharmony_ci	int ret = regmap_write(data->regmap, TMP51X_SHUNT_CONFIG,
5698c2ecf20Sopenharmony_ci			       data->shunt_config);
5708c2ecf20Sopenharmony_ci	if (ret < 0)
5718c2ecf20Sopenharmony_ci		return ret;
5728c2ecf20Sopenharmony_ci
5738c2ecf20Sopenharmony_ci	ret = regmap_write(data->regmap, TMP51X_TEMP_CONFIG, data->temp_config);
5748c2ecf20Sopenharmony_ci	if (ret < 0)
5758c2ecf20Sopenharmony_ci		return ret;
5768c2ecf20Sopenharmony_ci
5778c2ecf20Sopenharmony_ci	// nFactor configuration
5788c2ecf20Sopenharmony_ci	ret = regmap_update_bits(data->regmap, TMP51X_N_FACTOR_AND_HYST_1,
5798c2ecf20Sopenharmony_ci				 TMP51X_NFACTOR_MASK, data->nfactor[0] << 8);
5808c2ecf20Sopenharmony_ci	if (ret < 0)
5818c2ecf20Sopenharmony_ci		return ret;
5828c2ecf20Sopenharmony_ci
5838c2ecf20Sopenharmony_ci	ret = regmap_write(data->regmap, TMP51X_N_FACTOR_2,
5848c2ecf20Sopenharmony_ci			   data->nfactor[1] << 8);
5858c2ecf20Sopenharmony_ci	if (ret < 0)
5868c2ecf20Sopenharmony_ci		return ret;
5878c2ecf20Sopenharmony_ci
5888c2ecf20Sopenharmony_ci	if (data->id == tmp513) {
5898c2ecf20Sopenharmony_ci		ret = regmap_write(data->regmap, TMP513_N_FACTOR_3,
5908c2ecf20Sopenharmony_ci				   data->nfactor[2] << 8);
5918c2ecf20Sopenharmony_ci		if (ret < 0)
5928c2ecf20Sopenharmony_ci			return ret;
5938c2ecf20Sopenharmony_ci	}
5948c2ecf20Sopenharmony_ci
5958c2ecf20Sopenharmony_ci	ret = tmp51x_calibrate(data);
5968c2ecf20Sopenharmony_ci	if (ret < 0)
5978c2ecf20Sopenharmony_ci		return ret;
5988c2ecf20Sopenharmony_ci
5998c2ecf20Sopenharmony_ci	// Read the status register before using as the datasheet propose
6008c2ecf20Sopenharmony_ci	return regmap_read(data->regmap, TMP51X_STATUS, &regval);
6018c2ecf20Sopenharmony_ci}
6028c2ecf20Sopenharmony_ci
6038c2ecf20Sopenharmony_cistatic const struct i2c_device_id tmp51x_id[] = {
6048c2ecf20Sopenharmony_ci	{ "tmp512", tmp512 },
6058c2ecf20Sopenharmony_ci	{ "tmp513", tmp513 },
6068c2ecf20Sopenharmony_ci	{ }
6078c2ecf20Sopenharmony_ci};
6088c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(i2c, tmp51x_id);
6098c2ecf20Sopenharmony_ci
6108c2ecf20Sopenharmony_cistatic const struct of_device_id tmp51x_of_match[] = {
6118c2ecf20Sopenharmony_ci	{
6128c2ecf20Sopenharmony_ci		.compatible = "ti,tmp512",
6138c2ecf20Sopenharmony_ci		.data = (void *)tmp512
6148c2ecf20Sopenharmony_ci	},
6158c2ecf20Sopenharmony_ci	{
6168c2ecf20Sopenharmony_ci		.compatible = "ti,tmp513",
6178c2ecf20Sopenharmony_ci		.data = (void *)tmp513
6188c2ecf20Sopenharmony_ci	},
6198c2ecf20Sopenharmony_ci	{ },
6208c2ecf20Sopenharmony_ci};
6218c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, tmp51x_of_match);
6228c2ecf20Sopenharmony_ci
6238c2ecf20Sopenharmony_cistatic int tmp51x_vbus_range_to_reg(struct device *dev,
6248c2ecf20Sopenharmony_ci				    struct tmp51x_data *data)
6258c2ecf20Sopenharmony_ci{
6268c2ecf20Sopenharmony_ci	if (data->vbus_range_uvolt == TMP51X_VBUS_RANGE_32V) {
6278c2ecf20Sopenharmony_ci		data->shunt_config |= TMP51X_BUS_VOLTAGE_MASK;
6288c2ecf20Sopenharmony_ci	} else if (data->vbus_range_uvolt == TMP51X_VBUS_RANGE_16V) {
6298c2ecf20Sopenharmony_ci		data->shunt_config &= ~TMP51X_BUS_VOLTAGE_MASK;
6308c2ecf20Sopenharmony_ci	} else {
6318c2ecf20Sopenharmony_ci		dev_err(dev, "ti,bus-range-microvolt is invalid: %u\n",
6328c2ecf20Sopenharmony_ci			data->vbus_range_uvolt);
6338c2ecf20Sopenharmony_ci		return -EINVAL;
6348c2ecf20Sopenharmony_ci	}
6358c2ecf20Sopenharmony_ci	return 0;
6368c2ecf20Sopenharmony_ci}
6378c2ecf20Sopenharmony_ci
6388c2ecf20Sopenharmony_cistatic int tmp51x_pga_gain_to_reg(struct device *dev, struct tmp51x_data *data)
6398c2ecf20Sopenharmony_ci{
6408c2ecf20Sopenharmony_ci	if (data->pga_gain == 8) {
6418c2ecf20Sopenharmony_ci		data->shunt_config |= CURRENT_SENSE_VOLTAGE_320_MASK;
6428c2ecf20Sopenharmony_ci	} else if (data->pga_gain == 4) {
6438c2ecf20Sopenharmony_ci		data->shunt_config |= CURRENT_SENSE_VOLTAGE_160_MASK;
6448c2ecf20Sopenharmony_ci	} else if (data->pga_gain == 2) {
6458c2ecf20Sopenharmony_ci		data->shunt_config |= CURRENT_SENSE_VOLTAGE_80_MASK;
6468c2ecf20Sopenharmony_ci	} else if (data->pga_gain == 1) {
6478c2ecf20Sopenharmony_ci		data->shunt_config |= CURRENT_SENSE_VOLTAGE_40_MASK;
6488c2ecf20Sopenharmony_ci	} else {
6498c2ecf20Sopenharmony_ci		dev_err(dev, "ti,pga-gain is invalid: %u\n", data->pga_gain);
6508c2ecf20Sopenharmony_ci		return -EINVAL;
6518c2ecf20Sopenharmony_ci	}
6528c2ecf20Sopenharmony_ci	return 0;
6538c2ecf20Sopenharmony_ci}
6548c2ecf20Sopenharmony_ci
6558c2ecf20Sopenharmony_cistatic int tmp51x_read_properties(struct device *dev, struct tmp51x_data *data)
6568c2ecf20Sopenharmony_ci{
6578c2ecf20Sopenharmony_ci	int ret;
6588c2ecf20Sopenharmony_ci	u32 nfactor[3];
6598c2ecf20Sopenharmony_ci	u32 val;
6608c2ecf20Sopenharmony_ci
6618c2ecf20Sopenharmony_ci	ret = device_property_read_u32(dev, "shunt-resistor-micro-ohms", &val);
6628c2ecf20Sopenharmony_ci	data->shunt_uohms = (ret >= 0) ? val : TMP51X_SHUNT_VALUE_DEFAULT;
6638c2ecf20Sopenharmony_ci
6648c2ecf20Sopenharmony_ci	ret = device_property_read_u32(dev, "ti,bus-range-microvolt", &val);
6658c2ecf20Sopenharmony_ci	data->vbus_range_uvolt = (ret >= 0) ? val : TMP51X_VBUS_RANGE_DEFAULT;
6668c2ecf20Sopenharmony_ci	ret = tmp51x_vbus_range_to_reg(dev, data);
6678c2ecf20Sopenharmony_ci	if (ret < 0)
6688c2ecf20Sopenharmony_ci		return ret;
6698c2ecf20Sopenharmony_ci
6708c2ecf20Sopenharmony_ci	ret = device_property_read_u32(dev, "ti,pga-gain", &val);
6718c2ecf20Sopenharmony_ci	data->pga_gain = (ret >= 0) ? val : TMP51X_PGA_DEFAULT;
6728c2ecf20Sopenharmony_ci	ret = tmp51x_pga_gain_to_reg(dev, data);
6738c2ecf20Sopenharmony_ci	if (ret < 0)
6748c2ecf20Sopenharmony_ci		return ret;
6758c2ecf20Sopenharmony_ci
6768c2ecf20Sopenharmony_ci	ret = device_property_read_u32_array(dev, "ti,nfactor", nfactor,
6778c2ecf20Sopenharmony_ci					    (data->id == tmp513) ? 3 : 2);
6788c2ecf20Sopenharmony_ci	if (ret >= 0)
6798c2ecf20Sopenharmony_ci		memcpy(data->nfactor, nfactor, (data->id == tmp513) ? 3 : 2);
6808c2ecf20Sopenharmony_ci
6818c2ecf20Sopenharmony_ci	// Check if shunt value is compatible with pga-gain
6828c2ecf20Sopenharmony_ci	if (data->shunt_uohms > data->pga_gain * 40 * 1000 * 1000) {
6838c2ecf20Sopenharmony_ci		dev_err(dev, "shunt-resistor: %u too big for pga_gain: %u\n",
6848c2ecf20Sopenharmony_ci			data->shunt_uohms, data->pga_gain);
6858c2ecf20Sopenharmony_ci		return -EINVAL;
6868c2ecf20Sopenharmony_ci	}
6878c2ecf20Sopenharmony_ci
6888c2ecf20Sopenharmony_ci	return 0;
6898c2ecf20Sopenharmony_ci}
6908c2ecf20Sopenharmony_ci
6918c2ecf20Sopenharmony_cistatic void tmp51x_use_default(struct tmp51x_data *data)
6928c2ecf20Sopenharmony_ci{
6938c2ecf20Sopenharmony_ci	data->vbus_range_uvolt = TMP51X_VBUS_RANGE_DEFAULT;
6948c2ecf20Sopenharmony_ci	data->pga_gain = TMP51X_PGA_DEFAULT;
6958c2ecf20Sopenharmony_ci	data->shunt_uohms = TMP51X_SHUNT_VALUE_DEFAULT;
6968c2ecf20Sopenharmony_ci}
6978c2ecf20Sopenharmony_ci
6988c2ecf20Sopenharmony_cistatic int tmp51x_configure(struct device *dev, struct tmp51x_data *data)
6998c2ecf20Sopenharmony_ci{
7008c2ecf20Sopenharmony_ci	data->shunt_config = TMP51X_SHUNT_CONFIG_DEFAULT;
7018c2ecf20Sopenharmony_ci	data->temp_config = (data->id == tmp513) ?
7028c2ecf20Sopenharmony_ci			TMP513_TEMP_CONFIG_DEFAULT : TMP512_TEMP_CONFIG_DEFAULT;
7038c2ecf20Sopenharmony_ci
7048c2ecf20Sopenharmony_ci	if (dev->of_node)
7058c2ecf20Sopenharmony_ci		return tmp51x_read_properties(dev, data);
7068c2ecf20Sopenharmony_ci
7078c2ecf20Sopenharmony_ci	tmp51x_use_default(data);
7088c2ecf20Sopenharmony_ci
7098c2ecf20Sopenharmony_ci	return 0;
7108c2ecf20Sopenharmony_ci}
7118c2ecf20Sopenharmony_ci
7128c2ecf20Sopenharmony_cistatic int tmp51x_probe(struct i2c_client *client)
7138c2ecf20Sopenharmony_ci{
7148c2ecf20Sopenharmony_ci	struct device *dev = &client->dev;
7158c2ecf20Sopenharmony_ci	struct tmp51x_data *data;
7168c2ecf20Sopenharmony_ci	struct device *hwmon_dev;
7178c2ecf20Sopenharmony_ci	int ret;
7188c2ecf20Sopenharmony_ci
7198c2ecf20Sopenharmony_ci	data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
7208c2ecf20Sopenharmony_ci	if (!data)
7218c2ecf20Sopenharmony_ci		return -ENOMEM;
7228c2ecf20Sopenharmony_ci
7238c2ecf20Sopenharmony_ci	if (client->dev.of_node)
7248c2ecf20Sopenharmony_ci		data->id = (enum tmp51x_ids)device_get_match_data(&client->dev);
7258c2ecf20Sopenharmony_ci	else
7268c2ecf20Sopenharmony_ci		data->id = i2c_match_id(tmp51x_id, client)->driver_data;
7278c2ecf20Sopenharmony_ci
7288c2ecf20Sopenharmony_ci	ret = tmp51x_configure(dev, data);
7298c2ecf20Sopenharmony_ci	if (ret < 0) {
7308c2ecf20Sopenharmony_ci		dev_err(dev, "error configuring the device: %d\n", ret);
7318c2ecf20Sopenharmony_ci		return ret;
7328c2ecf20Sopenharmony_ci	}
7338c2ecf20Sopenharmony_ci
7348c2ecf20Sopenharmony_ci	data->regmap = devm_regmap_init_i2c(client, &tmp51x_regmap_config);
7358c2ecf20Sopenharmony_ci	if (IS_ERR(data->regmap)) {
7368c2ecf20Sopenharmony_ci		dev_err(dev, "failed to allocate register map\n");
7378c2ecf20Sopenharmony_ci		return PTR_ERR(data->regmap);
7388c2ecf20Sopenharmony_ci	}
7398c2ecf20Sopenharmony_ci
7408c2ecf20Sopenharmony_ci	ret = tmp51x_init(data);
7418c2ecf20Sopenharmony_ci	if (ret < 0) {
7428c2ecf20Sopenharmony_ci		dev_err(dev, "error configuring the device: %d\n", ret);
7438c2ecf20Sopenharmony_ci		return -ENODEV;
7448c2ecf20Sopenharmony_ci	}
7458c2ecf20Sopenharmony_ci
7468c2ecf20Sopenharmony_ci	hwmon_dev = devm_hwmon_device_register_with_info(dev, client->name,
7478c2ecf20Sopenharmony_ci							 data,
7488c2ecf20Sopenharmony_ci							 &tmp51x_chip_info,
7498c2ecf20Sopenharmony_ci							 NULL);
7508c2ecf20Sopenharmony_ci	if (IS_ERR(hwmon_dev))
7518c2ecf20Sopenharmony_ci		return PTR_ERR(hwmon_dev);
7528c2ecf20Sopenharmony_ci
7538c2ecf20Sopenharmony_ci	dev_dbg(dev, "power monitor %s\n", client->name);
7548c2ecf20Sopenharmony_ci
7558c2ecf20Sopenharmony_ci	return 0;
7568c2ecf20Sopenharmony_ci}
7578c2ecf20Sopenharmony_ci
7588c2ecf20Sopenharmony_cistatic struct i2c_driver tmp51x_driver = {
7598c2ecf20Sopenharmony_ci	.driver = {
7608c2ecf20Sopenharmony_ci		.name	= "tmp51x",
7618c2ecf20Sopenharmony_ci		.of_match_table = tmp51x_of_match,
7628c2ecf20Sopenharmony_ci	},
7638c2ecf20Sopenharmony_ci	.probe_new	= tmp51x_probe,
7648c2ecf20Sopenharmony_ci	.id_table	= tmp51x_id,
7658c2ecf20Sopenharmony_ci};
7668c2ecf20Sopenharmony_ci
7678c2ecf20Sopenharmony_cimodule_i2c_driver(tmp51x_driver);
7688c2ecf20Sopenharmony_ci
7698c2ecf20Sopenharmony_ciMODULE_AUTHOR("Eric Tremblay <etremblay@distechcontrols.com>");
7708c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("tmp51x driver");
7718c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL");
772