162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Driver for Texas Instruments TMP512, TMP513 power monitor chips
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * TMP513:
662306a36Sopenharmony_ci * Thermal/Power Management with Triple Remote and
762306a36Sopenharmony_ci * Local Temperature Sensor and Current Shunt Monitor
862306a36Sopenharmony_ci * Datasheet: https://www.ti.com/lit/gpn/tmp513
962306a36Sopenharmony_ci *
1062306a36Sopenharmony_ci * TMP512:
1162306a36Sopenharmony_ci * Thermal/Power Management with Dual Remote
1262306a36Sopenharmony_ci *	and Local Temperature Sensor and Current Shunt Monitor
1362306a36Sopenharmony_ci * Datasheet: https://www.ti.com/lit/gpn/tmp512
1462306a36Sopenharmony_ci *
1562306a36Sopenharmony_ci * Copyright (C) 2019 Eric Tremblay <etremblay@distech-controls.com>
1662306a36Sopenharmony_ci *
1762306a36Sopenharmony_ci * This program is free software; you can redistribute it and/or modify
1862306a36Sopenharmony_ci * it under the terms of the GNU General Public License as published by
1962306a36Sopenharmony_ci * the Free Software Foundation; version 2 of the License.
2062306a36Sopenharmony_ci */
2162306a36Sopenharmony_ci
2262306a36Sopenharmony_ci#include <linux/err.h>
2362306a36Sopenharmony_ci#include <linux/hwmon.h>
2462306a36Sopenharmony_ci#include <linux/i2c.h>
2562306a36Sopenharmony_ci#include <linux/init.h>
2662306a36Sopenharmony_ci#include <linux/kernel.h>
2762306a36Sopenharmony_ci#include <linux/module.h>
2862306a36Sopenharmony_ci#include <linux/regmap.h>
2962306a36Sopenharmony_ci#include <linux/slab.h>
3062306a36Sopenharmony_ci#include <linux/util_macros.h>
3162306a36Sopenharmony_ci
3262306a36Sopenharmony_ci// Common register definition
3362306a36Sopenharmony_ci#define TMP51X_SHUNT_CONFIG		0x00
3462306a36Sopenharmony_ci#define TMP51X_TEMP_CONFIG		0x01
3562306a36Sopenharmony_ci#define TMP51X_STATUS			0x02
3662306a36Sopenharmony_ci#define TMP51X_SMBUS_ALERT		0x03
3762306a36Sopenharmony_ci#define TMP51X_SHUNT_CURRENT_RESULT	0x04
3862306a36Sopenharmony_ci#define TMP51X_BUS_VOLTAGE_RESULT	0x05
3962306a36Sopenharmony_ci#define TMP51X_POWER_RESULT		0x06
4062306a36Sopenharmony_ci#define TMP51X_BUS_CURRENT_RESULT	0x07
4162306a36Sopenharmony_ci#define TMP51X_LOCAL_TEMP_RESULT	0x08
4262306a36Sopenharmony_ci#define TMP51X_REMOTE_TEMP_RESULT_1	0x09
4362306a36Sopenharmony_ci#define TMP51X_REMOTE_TEMP_RESULT_2	0x0A
4462306a36Sopenharmony_ci#define TMP51X_SHUNT_CURRENT_H_LIMIT	0x0C
4562306a36Sopenharmony_ci#define TMP51X_SHUNT_CURRENT_L_LIMIT	0x0D
4662306a36Sopenharmony_ci#define TMP51X_BUS_VOLTAGE_H_LIMIT	0x0E
4762306a36Sopenharmony_ci#define TMP51X_BUS_VOLTAGE_L_LIMIT	0x0F
4862306a36Sopenharmony_ci#define TMP51X_POWER_LIMIT		0x10
4962306a36Sopenharmony_ci#define TMP51X_LOCAL_TEMP_LIMIT	0x11
5062306a36Sopenharmony_ci#define TMP51X_REMOTE_TEMP_LIMIT_1	0x12
5162306a36Sopenharmony_ci#define TMP51X_REMOTE_TEMP_LIMIT_2	0x13
5262306a36Sopenharmony_ci#define TMP51X_SHUNT_CALIBRATION	0x15
5362306a36Sopenharmony_ci#define TMP51X_N_FACTOR_AND_HYST_1	0x16
5462306a36Sopenharmony_ci#define TMP51X_N_FACTOR_2		0x17
5562306a36Sopenharmony_ci#define TMP51X_MAN_ID_REG		0xFE
5662306a36Sopenharmony_ci#define TMP51X_DEVICE_ID_REG		0xFF
5762306a36Sopenharmony_ci
5862306a36Sopenharmony_ci// TMP513 specific register definition
5962306a36Sopenharmony_ci#define TMP513_REMOTE_TEMP_RESULT_3	0x0B
6062306a36Sopenharmony_ci#define TMP513_REMOTE_TEMP_LIMIT_3	0x14
6162306a36Sopenharmony_ci#define TMP513_N_FACTOR_3		0x18
6262306a36Sopenharmony_ci
6362306a36Sopenharmony_ci// Common attrs, and NULL
6462306a36Sopenharmony_ci#define TMP51X_MANUFACTURER_ID		0x55FF
6562306a36Sopenharmony_ci
6662306a36Sopenharmony_ci#define TMP512_DEVICE_ID		0x22FF
6762306a36Sopenharmony_ci#define TMP513_DEVICE_ID		0x23FF
6862306a36Sopenharmony_ci
6962306a36Sopenharmony_ci// Default config
7062306a36Sopenharmony_ci#define TMP51X_SHUNT_CONFIG_DEFAULT	0x399F
7162306a36Sopenharmony_ci#define TMP51X_SHUNT_VALUE_DEFAULT	1000
7262306a36Sopenharmony_ci#define TMP51X_VBUS_RANGE_DEFAULT	TMP51X_VBUS_RANGE_32V
7362306a36Sopenharmony_ci#define TMP51X_PGA_DEFAULT		8
7462306a36Sopenharmony_ci#define TMP51X_MAX_REGISTER_ADDR	0xFF
7562306a36Sopenharmony_ci
7662306a36Sopenharmony_ci#define TMP512_TEMP_CONFIG_DEFAULT	0xBF80
7762306a36Sopenharmony_ci#define TMP513_TEMP_CONFIG_DEFAULT	0xFF80
7862306a36Sopenharmony_ci
7962306a36Sopenharmony_ci// Mask and shift
8062306a36Sopenharmony_ci#define CURRENT_SENSE_VOLTAGE_320_MASK	0x1800
8162306a36Sopenharmony_ci#define CURRENT_SENSE_VOLTAGE_160_MASK	0x1000
8262306a36Sopenharmony_ci#define CURRENT_SENSE_VOLTAGE_80_MASK	0x0800
8362306a36Sopenharmony_ci#define CURRENT_SENSE_VOLTAGE_40_MASK	0
8462306a36Sopenharmony_ci
8562306a36Sopenharmony_ci#define TMP51X_BUS_VOLTAGE_MASK		0x2000
8662306a36Sopenharmony_ci#define TMP51X_NFACTOR_MASK		0xFF00
8762306a36Sopenharmony_ci#define TMP51X_HYST_MASK		0x00FF
8862306a36Sopenharmony_ci
8962306a36Sopenharmony_ci#define TMP51X_BUS_VOLTAGE_SHIFT	3
9062306a36Sopenharmony_ci#define TMP51X_TEMP_SHIFT		3
9162306a36Sopenharmony_ci
9262306a36Sopenharmony_ci// Alarms
9362306a36Sopenharmony_ci#define TMP51X_SHUNT_CURRENT_H_LIMIT_POS	15
9462306a36Sopenharmony_ci#define TMP51X_SHUNT_CURRENT_L_LIMIT_POS	14
9562306a36Sopenharmony_ci#define TMP51X_BUS_VOLTAGE_H_LIMIT_POS		13
9662306a36Sopenharmony_ci#define TMP51X_BUS_VOLTAGE_L_LIMIT_POS		12
9762306a36Sopenharmony_ci#define TMP51X_POWER_LIMIT_POS			11
9862306a36Sopenharmony_ci#define TMP51X_LOCAL_TEMP_LIMIT_POS		10
9962306a36Sopenharmony_ci#define TMP51X_REMOTE_TEMP_LIMIT_1_POS		9
10062306a36Sopenharmony_ci#define TMP51X_REMOTE_TEMP_LIMIT_2_POS		8
10162306a36Sopenharmony_ci#define TMP513_REMOTE_TEMP_LIMIT_3_POS		7
10262306a36Sopenharmony_ci
10362306a36Sopenharmony_ci#define TMP51X_VBUS_RANGE_32V		32000000
10462306a36Sopenharmony_ci#define TMP51X_VBUS_RANGE_16V		16000000
10562306a36Sopenharmony_ci
10662306a36Sopenharmony_ci// Max and Min value
10762306a36Sopenharmony_ci#define MAX_BUS_VOLTAGE_32_LIMIT	32764
10862306a36Sopenharmony_ci#define MAX_BUS_VOLTAGE_16_LIMIT	16382
10962306a36Sopenharmony_ci
11062306a36Sopenharmony_ci// Max possible value is -256 to +256 but datasheet indicated -40 to 125.
11162306a36Sopenharmony_ci#define MAX_TEMP_LIMIT			125000
11262306a36Sopenharmony_ci#define MIN_TEMP_LIMIT			-40000
11362306a36Sopenharmony_ci
11462306a36Sopenharmony_ci#define MAX_TEMP_HYST			127500
11562306a36Sopenharmony_ci
11662306a36Sopenharmony_cistatic const u8 TMP51X_TEMP_INPUT[4] = {
11762306a36Sopenharmony_ci	TMP51X_LOCAL_TEMP_RESULT,
11862306a36Sopenharmony_ci	TMP51X_REMOTE_TEMP_RESULT_1,
11962306a36Sopenharmony_ci	TMP51X_REMOTE_TEMP_RESULT_2,
12062306a36Sopenharmony_ci	TMP513_REMOTE_TEMP_RESULT_3
12162306a36Sopenharmony_ci};
12262306a36Sopenharmony_ci
12362306a36Sopenharmony_cistatic const u8 TMP51X_TEMP_CRIT[4] = {
12462306a36Sopenharmony_ci	TMP51X_LOCAL_TEMP_LIMIT,
12562306a36Sopenharmony_ci	TMP51X_REMOTE_TEMP_LIMIT_1,
12662306a36Sopenharmony_ci	TMP51X_REMOTE_TEMP_LIMIT_2,
12762306a36Sopenharmony_ci	TMP513_REMOTE_TEMP_LIMIT_3
12862306a36Sopenharmony_ci};
12962306a36Sopenharmony_ci
13062306a36Sopenharmony_cistatic const u8 TMP51X_TEMP_CRIT_ALARM[4] = {
13162306a36Sopenharmony_ci	TMP51X_LOCAL_TEMP_LIMIT_POS,
13262306a36Sopenharmony_ci	TMP51X_REMOTE_TEMP_LIMIT_1_POS,
13362306a36Sopenharmony_ci	TMP51X_REMOTE_TEMP_LIMIT_2_POS,
13462306a36Sopenharmony_ci	TMP513_REMOTE_TEMP_LIMIT_3_POS
13562306a36Sopenharmony_ci};
13662306a36Sopenharmony_ci
13762306a36Sopenharmony_cistatic const u8 TMP51X_TEMP_CRIT_HYST[4] = {
13862306a36Sopenharmony_ci	TMP51X_N_FACTOR_AND_HYST_1,
13962306a36Sopenharmony_ci	TMP51X_N_FACTOR_AND_HYST_1,
14062306a36Sopenharmony_ci	TMP51X_N_FACTOR_AND_HYST_1,
14162306a36Sopenharmony_ci	TMP51X_N_FACTOR_AND_HYST_1
14262306a36Sopenharmony_ci};
14362306a36Sopenharmony_ci
14462306a36Sopenharmony_cistatic const u8 TMP51X_CURR_INPUT[2] = {
14562306a36Sopenharmony_ci	TMP51X_SHUNT_CURRENT_RESULT,
14662306a36Sopenharmony_ci	TMP51X_BUS_CURRENT_RESULT
14762306a36Sopenharmony_ci};
14862306a36Sopenharmony_ci
14962306a36Sopenharmony_cistatic struct regmap_config tmp51x_regmap_config = {
15062306a36Sopenharmony_ci	.reg_bits = 8,
15162306a36Sopenharmony_ci	.val_bits = 16,
15262306a36Sopenharmony_ci	.max_register = TMP51X_MAX_REGISTER_ADDR,
15362306a36Sopenharmony_ci};
15462306a36Sopenharmony_ci
15562306a36Sopenharmony_cienum tmp51x_ids {
15662306a36Sopenharmony_ci	tmp512, tmp513
15762306a36Sopenharmony_ci};
15862306a36Sopenharmony_ci
15962306a36Sopenharmony_cistruct tmp51x_data {
16062306a36Sopenharmony_ci	u16 shunt_config;
16162306a36Sopenharmony_ci	u16 pga_gain;
16262306a36Sopenharmony_ci	u32 vbus_range_uvolt;
16362306a36Sopenharmony_ci
16462306a36Sopenharmony_ci	u16 temp_config;
16562306a36Sopenharmony_ci	u32 nfactor[3];
16662306a36Sopenharmony_ci
16762306a36Sopenharmony_ci	u32 shunt_uohms;
16862306a36Sopenharmony_ci
16962306a36Sopenharmony_ci	u32 curr_lsb_ua;
17062306a36Sopenharmony_ci	u32 pwr_lsb_uw;
17162306a36Sopenharmony_ci
17262306a36Sopenharmony_ci	enum tmp51x_ids id;
17362306a36Sopenharmony_ci	struct regmap *regmap;
17462306a36Sopenharmony_ci};
17562306a36Sopenharmony_ci
17662306a36Sopenharmony_ci// Set the shift based on the gain 8=4, 4=3, 2=2, 1=1
17762306a36Sopenharmony_cistatic inline u8 tmp51x_get_pga_shift(struct tmp51x_data *data)
17862306a36Sopenharmony_ci{
17962306a36Sopenharmony_ci	return 5 - ffs(data->pga_gain);
18062306a36Sopenharmony_ci}
18162306a36Sopenharmony_ci
18262306a36Sopenharmony_cistatic int tmp51x_get_value(struct tmp51x_data *data, u8 reg, u8 pos,
18362306a36Sopenharmony_ci			    unsigned int regval, long *val)
18462306a36Sopenharmony_ci{
18562306a36Sopenharmony_ci	switch (reg) {
18662306a36Sopenharmony_ci	case TMP51X_STATUS:
18762306a36Sopenharmony_ci		*val = (regval >> pos) & 1;
18862306a36Sopenharmony_ci		break;
18962306a36Sopenharmony_ci	case TMP51X_SHUNT_CURRENT_RESULT:
19062306a36Sopenharmony_ci	case TMP51X_SHUNT_CURRENT_H_LIMIT:
19162306a36Sopenharmony_ci	case TMP51X_SHUNT_CURRENT_L_LIMIT:
19262306a36Sopenharmony_ci		/*
19362306a36Sopenharmony_ci		 * The valus is read in voltage in the chip but reported as
19462306a36Sopenharmony_ci		 * current to the user.
19562306a36Sopenharmony_ci		 * 2's complement number shifted by one to four depending
19662306a36Sopenharmony_ci		 * on the pga gain setting. 1lsb = 10uV
19762306a36Sopenharmony_ci		 */
19862306a36Sopenharmony_ci		*val = sign_extend32(regval, 17 - tmp51x_get_pga_shift(data));
19962306a36Sopenharmony_ci		*val = DIV_ROUND_CLOSEST(*val * 10000, data->shunt_uohms);
20062306a36Sopenharmony_ci		break;
20162306a36Sopenharmony_ci	case TMP51X_BUS_VOLTAGE_RESULT:
20262306a36Sopenharmony_ci	case TMP51X_BUS_VOLTAGE_H_LIMIT:
20362306a36Sopenharmony_ci	case TMP51X_BUS_VOLTAGE_L_LIMIT:
20462306a36Sopenharmony_ci		// 1lsb = 4mV
20562306a36Sopenharmony_ci		*val = (regval >> TMP51X_BUS_VOLTAGE_SHIFT) * 4;
20662306a36Sopenharmony_ci		break;
20762306a36Sopenharmony_ci	case TMP51X_POWER_RESULT:
20862306a36Sopenharmony_ci	case TMP51X_POWER_LIMIT:
20962306a36Sopenharmony_ci		// Power = (current * BusVoltage) / 5000
21062306a36Sopenharmony_ci		*val = regval * data->pwr_lsb_uw;
21162306a36Sopenharmony_ci		break;
21262306a36Sopenharmony_ci	case TMP51X_BUS_CURRENT_RESULT:
21362306a36Sopenharmony_ci		// Current = (ShuntVoltage * CalibrationRegister) / 4096
21462306a36Sopenharmony_ci		*val = sign_extend32(regval, 16) * data->curr_lsb_ua;
21562306a36Sopenharmony_ci		*val = DIV_ROUND_CLOSEST(*val, 1000);
21662306a36Sopenharmony_ci		break;
21762306a36Sopenharmony_ci	case TMP51X_LOCAL_TEMP_RESULT:
21862306a36Sopenharmony_ci	case TMP51X_REMOTE_TEMP_RESULT_1:
21962306a36Sopenharmony_ci	case TMP51X_REMOTE_TEMP_RESULT_2:
22062306a36Sopenharmony_ci	case TMP513_REMOTE_TEMP_RESULT_3:
22162306a36Sopenharmony_ci	case TMP51X_LOCAL_TEMP_LIMIT:
22262306a36Sopenharmony_ci	case TMP51X_REMOTE_TEMP_LIMIT_1:
22362306a36Sopenharmony_ci	case TMP51X_REMOTE_TEMP_LIMIT_2:
22462306a36Sopenharmony_ci	case TMP513_REMOTE_TEMP_LIMIT_3:
22562306a36Sopenharmony_ci		// 1lsb = 0.0625 degrees centigrade
22662306a36Sopenharmony_ci		*val = sign_extend32(regval, 16) >> TMP51X_TEMP_SHIFT;
22762306a36Sopenharmony_ci		*val = DIV_ROUND_CLOSEST(*val * 625, 10);
22862306a36Sopenharmony_ci		break;
22962306a36Sopenharmony_ci	case TMP51X_N_FACTOR_AND_HYST_1:
23062306a36Sopenharmony_ci		// 1lsb = 0.5 degrees centigrade
23162306a36Sopenharmony_ci		*val = (regval & TMP51X_HYST_MASK) * 500;
23262306a36Sopenharmony_ci		break;
23362306a36Sopenharmony_ci	default:
23462306a36Sopenharmony_ci		// Programmer goofed
23562306a36Sopenharmony_ci		WARN_ON_ONCE(1);
23662306a36Sopenharmony_ci		*val = 0;
23762306a36Sopenharmony_ci		return -EOPNOTSUPP;
23862306a36Sopenharmony_ci	}
23962306a36Sopenharmony_ci
24062306a36Sopenharmony_ci	return 0;
24162306a36Sopenharmony_ci}
24262306a36Sopenharmony_ci
24362306a36Sopenharmony_cistatic int tmp51x_set_value(struct tmp51x_data *data, u8 reg, long val)
24462306a36Sopenharmony_ci{
24562306a36Sopenharmony_ci	int regval, max_val;
24662306a36Sopenharmony_ci	u32 mask = 0;
24762306a36Sopenharmony_ci
24862306a36Sopenharmony_ci	switch (reg) {
24962306a36Sopenharmony_ci	case TMP51X_SHUNT_CURRENT_H_LIMIT:
25062306a36Sopenharmony_ci	case TMP51X_SHUNT_CURRENT_L_LIMIT:
25162306a36Sopenharmony_ci		/*
25262306a36Sopenharmony_ci		 * The user enter current value and we convert it to
25362306a36Sopenharmony_ci		 * voltage. 1lsb = 10uV
25462306a36Sopenharmony_ci		 */
25562306a36Sopenharmony_ci		val = DIV_ROUND_CLOSEST(val * data->shunt_uohms, 10000);
25662306a36Sopenharmony_ci		max_val = U16_MAX >> tmp51x_get_pga_shift(data);
25762306a36Sopenharmony_ci		regval = clamp_val(val, -max_val, max_val);
25862306a36Sopenharmony_ci		break;
25962306a36Sopenharmony_ci	case TMP51X_BUS_VOLTAGE_H_LIMIT:
26062306a36Sopenharmony_ci	case TMP51X_BUS_VOLTAGE_L_LIMIT:
26162306a36Sopenharmony_ci		// 1lsb = 4mV
26262306a36Sopenharmony_ci		max_val = (data->vbus_range_uvolt == TMP51X_VBUS_RANGE_32V) ?
26362306a36Sopenharmony_ci			MAX_BUS_VOLTAGE_32_LIMIT : MAX_BUS_VOLTAGE_16_LIMIT;
26462306a36Sopenharmony_ci
26562306a36Sopenharmony_ci		val = clamp_val(DIV_ROUND_CLOSEST(val, 4), 0, max_val);
26662306a36Sopenharmony_ci		regval = val << TMP51X_BUS_VOLTAGE_SHIFT;
26762306a36Sopenharmony_ci		break;
26862306a36Sopenharmony_ci	case TMP51X_POWER_LIMIT:
26962306a36Sopenharmony_ci		regval = clamp_val(DIV_ROUND_CLOSEST(val, data->pwr_lsb_uw), 0,
27062306a36Sopenharmony_ci				   U16_MAX);
27162306a36Sopenharmony_ci		break;
27262306a36Sopenharmony_ci	case TMP51X_LOCAL_TEMP_LIMIT:
27362306a36Sopenharmony_ci	case TMP51X_REMOTE_TEMP_LIMIT_1:
27462306a36Sopenharmony_ci	case TMP51X_REMOTE_TEMP_LIMIT_2:
27562306a36Sopenharmony_ci	case TMP513_REMOTE_TEMP_LIMIT_3:
27662306a36Sopenharmony_ci		// 1lsb = 0.0625 degrees centigrade
27762306a36Sopenharmony_ci		val = clamp_val(val, MIN_TEMP_LIMIT, MAX_TEMP_LIMIT);
27862306a36Sopenharmony_ci		regval = DIV_ROUND_CLOSEST(val * 10, 625) << TMP51X_TEMP_SHIFT;
27962306a36Sopenharmony_ci		break;
28062306a36Sopenharmony_ci	case TMP51X_N_FACTOR_AND_HYST_1:
28162306a36Sopenharmony_ci		// 1lsb = 0.5 degrees centigrade
28262306a36Sopenharmony_ci		val = clamp_val(val, 0, MAX_TEMP_HYST);
28362306a36Sopenharmony_ci		regval = DIV_ROUND_CLOSEST(val, 500);
28462306a36Sopenharmony_ci		mask = TMP51X_HYST_MASK;
28562306a36Sopenharmony_ci		break;
28662306a36Sopenharmony_ci	default:
28762306a36Sopenharmony_ci		// Programmer goofed
28862306a36Sopenharmony_ci		WARN_ON_ONCE(1);
28962306a36Sopenharmony_ci		return -EOPNOTSUPP;
29062306a36Sopenharmony_ci	}
29162306a36Sopenharmony_ci
29262306a36Sopenharmony_ci	if (mask == 0)
29362306a36Sopenharmony_ci		return regmap_write(data->regmap, reg, regval);
29462306a36Sopenharmony_ci	else
29562306a36Sopenharmony_ci		return regmap_update_bits(data->regmap, reg, mask, regval);
29662306a36Sopenharmony_ci}
29762306a36Sopenharmony_ci
29862306a36Sopenharmony_cistatic u8 tmp51x_get_reg(enum hwmon_sensor_types type, u32 attr, int channel)
29962306a36Sopenharmony_ci{
30062306a36Sopenharmony_ci	switch (type) {
30162306a36Sopenharmony_ci	case hwmon_temp:
30262306a36Sopenharmony_ci		switch (attr) {
30362306a36Sopenharmony_ci		case hwmon_temp_input:
30462306a36Sopenharmony_ci			return TMP51X_TEMP_INPUT[channel];
30562306a36Sopenharmony_ci		case hwmon_temp_crit_alarm:
30662306a36Sopenharmony_ci			return TMP51X_STATUS;
30762306a36Sopenharmony_ci		case hwmon_temp_crit:
30862306a36Sopenharmony_ci			return TMP51X_TEMP_CRIT[channel];
30962306a36Sopenharmony_ci		case hwmon_temp_crit_hyst:
31062306a36Sopenharmony_ci			return TMP51X_TEMP_CRIT_HYST[channel];
31162306a36Sopenharmony_ci		}
31262306a36Sopenharmony_ci		break;
31362306a36Sopenharmony_ci	case hwmon_in:
31462306a36Sopenharmony_ci		switch (attr) {
31562306a36Sopenharmony_ci		case hwmon_in_input:
31662306a36Sopenharmony_ci			return TMP51X_BUS_VOLTAGE_RESULT;
31762306a36Sopenharmony_ci		case hwmon_in_lcrit_alarm:
31862306a36Sopenharmony_ci		case hwmon_in_crit_alarm:
31962306a36Sopenharmony_ci			return TMP51X_STATUS;
32062306a36Sopenharmony_ci		case hwmon_in_lcrit:
32162306a36Sopenharmony_ci			return TMP51X_BUS_VOLTAGE_L_LIMIT;
32262306a36Sopenharmony_ci		case hwmon_in_crit:
32362306a36Sopenharmony_ci			return TMP51X_BUS_VOLTAGE_H_LIMIT;
32462306a36Sopenharmony_ci		}
32562306a36Sopenharmony_ci		break;
32662306a36Sopenharmony_ci	case hwmon_curr:
32762306a36Sopenharmony_ci		switch (attr) {
32862306a36Sopenharmony_ci		case hwmon_curr_input:
32962306a36Sopenharmony_ci			return TMP51X_CURR_INPUT[channel];
33062306a36Sopenharmony_ci		case hwmon_curr_lcrit_alarm:
33162306a36Sopenharmony_ci		case hwmon_curr_crit_alarm:
33262306a36Sopenharmony_ci			return TMP51X_STATUS;
33362306a36Sopenharmony_ci		case hwmon_curr_lcrit:
33462306a36Sopenharmony_ci			return TMP51X_SHUNT_CURRENT_L_LIMIT;
33562306a36Sopenharmony_ci		case hwmon_curr_crit:
33662306a36Sopenharmony_ci			return TMP51X_SHUNT_CURRENT_H_LIMIT;
33762306a36Sopenharmony_ci		}
33862306a36Sopenharmony_ci		break;
33962306a36Sopenharmony_ci	case hwmon_power:
34062306a36Sopenharmony_ci		switch (attr) {
34162306a36Sopenharmony_ci		case hwmon_power_input:
34262306a36Sopenharmony_ci			return TMP51X_POWER_RESULT;
34362306a36Sopenharmony_ci		case hwmon_power_crit_alarm:
34462306a36Sopenharmony_ci			return TMP51X_STATUS;
34562306a36Sopenharmony_ci		case hwmon_power_crit:
34662306a36Sopenharmony_ci			return TMP51X_POWER_LIMIT;
34762306a36Sopenharmony_ci		}
34862306a36Sopenharmony_ci		break;
34962306a36Sopenharmony_ci	default:
35062306a36Sopenharmony_ci		break;
35162306a36Sopenharmony_ci	}
35262306a36Sopenharmony_ci
35362306a36Sopenharmony_ci	return 0;
35462306a36Sopenharmony_ci}
35562306a36Sopenharmony_ci
35662306a36Sopenharmony_cistatic u8 tmp51x_get_status_pos(enum hwmon_sensor_types type, u32 attr,
35762306a36Sopenharmony_ci				int channel)
35862306a36Sopenharmony_ci{
35962306a36Sopenharmony_ci	switch (type) {
36062306a36Sopenharmony_ci	case hwmon_temp:
36162306a36Sopenharmony_ci		switch (attr) {
36262306a36Sopenharmony_ci		case hwmon_temp_crit_alarm:
36362306a36Sopenharmony_ci			return TMP51X_TEMP_CRIT_ALARM[channel];
36462306a36Sopenharmony_ci		}
36562306a36Sopenharmony_ci		break;
36662306a36Sopenharmony_ci	case hwmon_in:
36762306a36Sopenharmony_ci		switch (attr) {
36862306a36Sopenharmony_ci		case hwmon_in_lcrit_alarm:
36962306a36Sopenharmony_ci			return TMP51X_BUS_VOLTAGE_L_LIMIT_POS;
37062306a36Sopenharmony_ci		case hwmon_in_crit_alarm:
37162306a36Sopenharmony_ci			return TMP51X_BUS_VOLTAGE_H_LIMIT_POS;
37262306a36Sopenharmony_ci		}
37362306a36Sopenharmony_ci		break;
37462306a36Sopenharmony_ci	case hwmon_curr:
37562306a36Sopenharmony_ci		switch (attr) {
37662306a36Sopenharmony_ci		case hwmon_curr_lcrit_alarm:
37762306a36Sopenharmony_ci			return TMP51X_SHUNT_CURRENT_L_LIMIT_POS;
37862306a36Sopenharmony_ci		case hwmon_curr_crit_alarm:
37962306a36Sopenharmony_ci			return TMP51X_SHUNT_CURRENT_H_LIMIT_POS;
38062306a36Sopenharmony_ci		}
38162306a36Sopenharmony_ci		break;
38262306a36Sopenharmony_ci	case hwmon_power:
38362306a36Sopenharmony_ci		switch (attr) {
38462306a36Sopenharmony_ci		case hwmon_power_crit_alarm:
38562306a36Sopenharmony_ci			return TMP51X_POWER_LIMIT_POS;
38662306a36Sopenharmony_ci		}
38762306a36Sopenharmony_ci		break;
38862306a36Sopenharmony_ci	default:
38962306a36Sopenharmony_ci		break;
39062306a36Sopenharmony_ci	}
39162306a36Sopenharmony_ci
39262306a36Sopenharmony_ci	return 0;
39362306a36Sopenharmony_ci}
39462306a36Sopenharmony_ci
39562306a36Sopenharmony_cistatic int tmp51x_read(struct device *dev, enum hwmon_sensor_types type,
39662306a36Sopenharmony_ci		       u32 attr, int channel, long *val)
39762306a36Sopenharmony_ci{
39862306a36Sopenharmony_ci	struct tmp51x_data *data = dev_get_drvdata(dev);
39962306a36Sopenharmony_ci	int ret;
40062306a36Sopenharmony_ci	u32 regval;
40162306a36Sopenharmony_ci	u8 pos = 0, reg = 0;
40262306a36Sopenharmony_ci
40362306a36Sopenharmony_ci	reg = tmp51x_get_reg(type, attr, channel);
40462306a36Sopenharmony_ci	if (reg == 0)
40562306a36Sopenharmony_ci		return -EOPNOTSUPP;
40662306a36Sopenharmony_ci
40762306a36Sopenharmony_ci	if (reg == TMP51X_STATUS)
40862306a36Sopenharmony_ci		pos = tmp51x_get_status_pos(type, attr, channel);
40962306a36Sopenharmony_ci
41062306a36Sopenharmony_ci	ret = regmap_read(data->regmap, reg, &regval);
41162306a36Sopenharmony_ci	if (ret < 0)
41262306a36Sopenharmony_ci		return ret;
41362306a36Sopenharmony_ci
41462306a36Sopenharmony_ci	return tmp51x_get_value(data, reg, pos, regval, val);
41562306a36Sopenharmony_ci}
41662306a36Sopenharmony_ci
41762306a36Sopenharmony_cistatic int tmp51x_write(struct device *dev, enum hwmon_sensor_types type,
41862306a36Sopenharmony_ci			u32 attr, int channel, long val)
41962306a36Sopenharmony_ci{
42062306a36Sopenharmony_ci	u8 reg = 0;
42162306a36Sopenharmony_ci
42262306a36Sopenharmony_ci	reg = tmp51x_get_reg(type, attr, channel);
42362306a36Sopenharmony_ci	if (reg == 0)
42462306a36Sopenharmony_ci		return -EOPNOTSUPP;
42562306a36Sopenharmony_ci
42662306a36Sopenharmony_ci	return tmp51x_set_value(dev_get_drvdata(dev), reg, val);
42762306a36Sopenharmony_ci}
42862306a36Sopenharmony_ci
42962306a36Sopenharmony_cistatic umode_t tmp51x_is_visible(const void *_data,
43062306a36Sopenharmony_ci				 enum hwmon_sensor_types type, u32 attr,
43162306a36Sopenharmony_ci				 int channel)
43262306a36Sopenharmony_ci{
43362306a36Sopenharmony_ci	const struct tmp51x_data *data = _data;
43462306a36Sopenharmony_ci
43562306a36Sopenharmony_ci	switch (type) {
43662306a36Sopenharmony_ci	case hwmon_temp:
43762306a36Sopenharmony_ci		if (data->id == tmp512 && channel == 3)
43862306a36Sopenharmony_ci			return 0;
43962306a36Sopenharmony_ci		switch (attr) {
44062306a36Sopenharmony_ci		case hwmon_temp_input:
44162306a36Sopenharmony_ci		case hwmon_temp_crit_alarm:
44262306a36Sopenharmony_ci			return 0444;
44362306a36Sopenharmony_ci		case hwmon_temp_crit:
44462306a36Sopenharmony_ci			return 0644;
44562306a36Sopenharmony_ci		case hwmon_temp_crit_hyst:
44662306a36Sopenharmony_ci			if (channel == 0)
44762306a36Sopenharmony_ci				return 0644;
44862306a36Sopenharmony_ci			return 0444;
44962306a36Sopenharmony_ci		}
45062306a36Sopenharmony_ci		break;
45162306a36Sopenharmony_ci	case hwmon_in:
45262306a36Sopenharmony_ci		switch (attr) {
45362306a36Sopenharmony_ci		case hwmon_in_input:
45462306a36Sopenharmony_ci		case hwmon_in_lcrit_alarm:
45562306a36Sopenharmony_ci		case hwmon_in_crit_alarm:
45662306a36Sopenharmony_ci			return 0444;
45762306a36Sopenharmony_ci		case hwmon_in_lcrit:
45862306a36Sopenharmony_ci		case hwmon_in_crit:
45962306a36Sopenharmony_ci			return 0644;
46062306a36Sopenharmony_ci		}
46162306a36Sopenharmony_ci		break;
46262306a36Sopenharmony_ci	case hwmon_curr:
46362306a36Sopenharmony_ci		if (!data->shunt_uohms)
46462306a36Sopenharmony_ci			return 0;
46562306a36Sopenharmony_ci
46662306a36Sopenharmony_ci		switch (attr) {
46762306a36Sopenharmony_ci		case hwmon_curr_input:
46862306a36Sopenharmony_ci		case hwmon_curr_lcrit_alarm:
46962306a36Sopenharmony_ci		case hwmon_curr_crit_alarm:
47062306a36Sopenharmony_ci			return 0444;
47162306a36Sopenharmony_ci		case hwmon_curr_lcrit:
47262306a36Sopenharmony_ci		case hwmon_curr_crit:
47362306a36Sopenharmony_ci			return 0644;
47462306a36Sopenharmony_ci		}
47562306a36Sopenharmony_ci		break;
47662306a36Sopenharmony_ci	case hwmon_power:
47762306a36Sopenharmony_ci		if (!data->shunt_uohms)
47862306a36Sopenharmony_ci			return 0;
47962306a36Sopenharmony_ci
48062306a36Sopenharmony_ci		switch (attr) {
48162306a36Sopenharmony_ci		case hwmon_power_input:
48262306a36Sopenharmony_ci		case hwmon_power_crit_alarm:
48362306a36Sopenharmony_ci			return 0444;
48462306a36Sopenharmony_ci		case hwmon_power_crit:
48562306a36Sopenharmony_ci			return 0644;
48662306a36Sopenharmony_ci		}
48762306a36Sopenharmony_ci		break;
48862306a36Sopenharmony_ci	default:
48962306a36Sopenharmony_ci		break;
49062306a36Sopenharmony_ci	}
49162306a36Sopenharmony_ci	return 0;
49262306a36Sopenharmony_ci}
49362306a36Sopenharmony_ci
49462306a36Sopenharmony_cistatic const struct hwmon_channel_info * const tmp51x_info[] = {
49562306a36Sopenharmony_ci	HWMON_CHANNEL_INFO(temp,
49662306a36Sopenharmony_ci			   HWMON_T_INPUT | HWMON_T_CRIT | HWMON_T_CRIT_ALARM |
49762306a36Sopenharmony_ci			   HWMON_T_CRIT_HYST,
49862306a36Sopenharmony_ci			   HWMON_T_INPUT | HWMON_T_CRIT | HWMON_T_CRIT_ALARM |
49962306a36Sopenharmony_ci			   HWMON_T_CRIT_HYST,
50062306a36Sopenharmony_ci			   HWMON_T_INPUT | HWMON_T_CRIT | HWMON_T_CRIT_ALARM |
50162306a36Sopenharmony_ci			   HWMON_T_CRIT_HYST,
50262306a36Sopenharmony_ci			   HWMON_T_INPUT | HWMON_T_CRIT | HWMON_T_CRIT_ALARM |
50362306a36Sopenharmony_ci			   HWMON_T_CRIT_HYST),
50462306a36Sopenharmony_ci	HWMON_CHANNEL_INFO(in,
50562306a36Sopenharmony_ci			   HWMON_I_INPUT | HWMON_I_LCRIT | HWMON_I_LCRIT_ALARM |
50662306a36Sopenharmony_ci			   HWMON_I_CRIT | HWMON_I_CRIT_ALARM),
50762306a36Sopenharmony_ci	HWMON_CHANNEL_INFO(curr,
50862306a36Sopenharmony_ci			   HWMON_C_INPUT | HWMON_C_LCRIT | HWMON_C_LCRIT_ALARM |
50962306a36Sopenharmony_ci			   HWMON_C_CRIT | HWMON_C_CRIT_ALARM,
51062306a36Sopenharmony_ci			   HWMON_C_INPUT),
51162306a36Sopenharmony_ci	HWMON_CHANNEL_INFO(power,
51262306a36Sopenharmony_ci			   HWMON_P_INPUT | HWMON_P_CRIT | HWMON_P_CRIT_ALARM),
51362306a36Sopenharmony_ci	NULL
51462306a36Sopenharmony_ci};
51562306a36Sopenharmony_ci
51662306a36Sopenharmony_cistatic const struct hwmon_ops tmp51x_hwmon_ops = {
51762306a36Sopenharmony_ci	.is_visible = tmp51x_is_visible,
51862306a36Sopenharmony_ci	.read = tmp51x_read,
51962306a36Sopenharmony_ci	.write = tmp51x_write,
52062306a36Sopenharmony_ci};
52162306a36Sopenharmony_ci
52262306a36Sopenharmony_cistatic const struct hwmon_chip_info tmp51x_chip_info = {
52362306a36Sopenharmony_ci	.ops = &tmp51x_hwmon_ops,
52462306a36Sopenharmony_ci	.info = tmp51x_info,
52562306a36Sopenharmony_ci};
52662306a36Sopenharmony_ci
52762306a36Sopenharmony_ci/*
52862306a36Sopenharmony_ci * Calibrate the tmp51x following the datasheet method
52962306a36Sopenharmony_ci */
53062306a36Sopenharmony_cistatic int tmp51x_calibrate(struct tmp51x_data *data)
53162306a36Sopenharmony_ci{
53262306a36Sopenharmony_ci	int vshunt_max = data->pga_gain * 40;
53362306a36Sopenharmony_ci	u64 max_curr_ma;
53462306a36Sopenharmony_ci	u32 div;
53562306a36Sopenharmony_ci
53662306a36Sopenharmony_ci	/*
53762306a36Sopenharmony_ci	 * If shunt_uohms is equal to 0, the calibration should be set to 0.
53862306a36Sopenharmony_ci	 * The consequence will be that the current and power measurement engine
53962306a36Sopenharmony_ci	 * of the sensor will not work. Temperature and voltage sensing will
54062306a36Sopenharmony_ci	 * continue to work.
54162306a36Sopenharmony_ci	 */
54262306a36Sopenharmony_ci	if (data->shunt_uohms == 0)
54362306a36Sopenharmony_ci		return regmap_write(data->regmap, TMP51X_SHUNT_CALIBRATION, 0);
54462306a36Sopenharmony_ci
54562306a36Sopenharmony_ci	max_curr_ma = DIV_ROUND_CLOSEST_ULL(vshunt_max * 1000 * 1000,
54662306a36Sopenharmony_ci					    data->shunt_uohms);
54762306a36Sopenharmony_ci
54862306a36Sopenharmony_ci	/*
54962306a36Sopenharmony_ci	 * Calculate the minimal bit resolution for the current and the power.
55062306a36Sopenharmony_ci	 * Those values will be used during register interpretation.
55162306a36Sopenharmony_ci	 */
55262306a36Sopenharmony_ci	data->curr_lsb_ua = DIV_ROUND_CLOSEST_ULL(max_curr_ma * 1000, 32767);
55362306a36Sopenharmony_ci	data->pwr_lsb_uw = 20 * data->curr_lsb_ua;
55462306a36Sopenharmony_ci
55562306a36Sopenharmony_ci	div = DIV_ROUND_CLOSEST_ULL(data->curr_lsb_ua * data->shunt_uohms,
55662306a36Sopenharmony_ci				    1000 * 1000);
55762306a36Sopenharmony_ci
55862306a36Sopenharmony_ci	return regmap_write(data->regmap, TMP51X_SHUNT_CALIBRATION,
55962306a36Sopenharmony_ci			    DIV_ROUND_CLOSEST(40960, div));
56062306a36Sopenharmony_ci}
56162306a36Sopenharmony_ci
56262306a36Sopenharmony_ci/*
56362306a36Sopenharmony_ci * Initialize the configuration and calibration registers.
56462306a36Sopenharmony_ci */
56562306a36Sopenharmony_cistatic int tmp51x_init(struct tmp51x_data *data)
56662306a36Sopenharmony_ci{
56762306a36Sopenharmony_ci	unsigned int regval;
56862306a36Sopenharmony_ci	int ret = regmap_write(data->regmap, TMP51X_SHUNT_CONFIG,
56962306a36Sopenharmony_ci			       data->shunt_config);
57062306a36Sopenharmony_ci	if (ret < 0)
57162306a36Sopenharmony_ci		return ret;
57262306a36Sopenharmony_ci
57362306a36Sopenharmony_ci	ret = regmap_write(data->regmap, TMP51X_TEMP_CONFIG, data->temp_config);
57462306a36Sopenharmony_ci	if (ret < 0)
57562306a36Sopenharmony_ci		return ret;
57662306a36Sopenharmony_ci
57762306a36Sopenharmony_ci	// nFactor configuration
57862306a36Sopenharmony_ci	ret = regmap_update_bits(data->regmap, TMP51X_N_FACTOR_AND_HYST_1,
57962306a36Sopenharmony_ci				 TMP51X_NFACTOR_MASK, data->nfactor[0] << 8);
58062306a36Sopenharmony_ci	if (ret < 0)
58162306a36Sopenharmony_ci		return ret;
58262306a36Sopenharmony_ci
58362306a36Sopenharmony_ci	ret = regmap_write(data->regmap, TMP51X_N_FACTOR_2,
58462306a36Sopenharmony_ci			   data->nfactor[1] << 8);
58562306a36Sopenharmony_ci	if (ret < 0)
58662306a36Sopenharmony_ci		return ret;
58762306a36Sopenharmony_ci
58862306a36Sopenharmony_ci	if (data->id == tmp513) {
58962306a36Sopenharmony_ci		ret = regmap_write(data->regmap, TMP513_N_FACTOR_3,
59062306a36Sopenharmony_ci				   data->nfactor[2] << 8);
59162306a36Sopenharmony_ci		if (ret < 0)
59262306a36Sopenharmony_ci			return ret;
59362306a36Sopenharmony_ci	}
59462306a36Sopenharmony_ci
59562306a36Sopenharmony_ci	ret = tmp51x_calibrate(data);
59662306a36Sopenharmony_ci	if (ret < 0)
59762306a36Sopenharmony_ci		return ret;
59862306a36Sopenharmony_ci
59962306a36Sopenharmony_ci	// Read the status register before using as the datasheet propose
60062306a36Sopenharmony_ci	return regmap_read(data->regmap, TMP51X_STATUS, &regval);
60162306a36Sopenharmony_ci}
60262306a36Sopenharmony_ci
60362306a36Sopenharmony_cistatic const struct i2c_device_id tmp51x_id[] = {
60462306a36Sopenharmony_ci	{ "tmp512", tmp512 },
60562306a36Sopenharmony_ci	{ "tmp513", tmp513 },
60662306a36Sopenharmony_ci	{ }
60762306a36Sopenharmony_ci};
60862306a36Sopenharmony_ciMODULE_DEVICE_TABLE(i2c, tmp51x_id);
60962306a36Sopenharmony_ci
61062306a36Sopenharmony_cistatic const struct of_device_id tmp51x_of_match[] = {
61162306a36Sopenharmony_ci	{
61262306a36Sopenharmony_ci		.compatible = "ti,tmp512",
61362306a36Sopenharmony_ci		.data = (void *)tmp512
61462306a36Sopenharmony_ci	},
61562306a36Sopenharmony_ci	{
61662306a36Sopenharmony_ci		.compatible = "ti,tmp513",
61762306a36Sopenharmony_ci		.data = (void *)tmp513
61862306a36Sopenharmony_ci	},
61962306a36Sopenharmony_ci	{ },
62062306a36Sopenharmony_ci};
62162306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, tmp51x_of_match);
62262306a36Sopenharmony_ci
62362306a36Sopenharmony_cistatic int tmp51x_vbus_range_to_reg(struct device *dev,
62462306a36Sopenharmony_ci				    struct tmp51x_data *data)
62562306a36Sopenharmony_ci{
62662306a36Sopenharmony_ci	if (data->vbus_range_uvolt == TMP51X_VBUS_RANGE_32V) {
62762306a36Sopenharmony_ci		data->shunt_config |= TMP51X_BUS_VOLTAGE_MASK;
62862306a36Sopenharmony_ci	} else if (data->vbus_range_uvolt == TMP51X_VBUS_RANGE_16V) {
62962306a36Sopenharmony_ci		data->shunt_config &= ~TMP51X_BUS_VOLTAGE_MASK;
63062306a36Sopenharmony_ci	} else {
63162306a36Sopenharmony_ci		dev_err(dev, "ti,bus-range-microvolt is invalid: %u\n",
63262306a36Sopenharmony_ci			data->vbus_range_uvolt);
63362306a36Sopenharmony_ci		return -EINVAL;
63462306a36Sopenharmony_ci	}
63562306a36Sopenharmony_ci	return 0;
63662306a36Sopenharmony_ci}
63762306a36Sopenharmony_ci
63862306a36Sopenharmony_cistatic int tmp51x_pga_gain_to_reg(struct device *dev, struct tmp51x_data *data)
63962306a36Sopenharmony_ci{
64062306a36Sopenharmony_ci	if (data->pga_gain == 8) {
64162306a36Sopenharmony_ci		data->shunt_config |= CURRENT_SENSE_VOLTAGE_320_MASK;
64262306a36Sopenharmony_ci	} else if (data->pga_gain == 4) {
64362306a36Sopenharmony_ci		data->shunt_config |= CURRENT_SENSE_VOLTAGE_160_MASK;
64462306a36Sopenharmony_ci	} else if (data->pga_gain == 2) {
64562306a36Sopenharmony_ci		data->shunt_config |= CURRENT_SENSE_VOLTAGE_80_MASK;
64662306a36Sopenharmony_ci	} else if (data->pga_gain == 1) {
64762306a36Sopenharmony_ci		data->shunt_config |= CURRENT_SENSE_VOLTAGE_40_MASK;
64862306a36Sopenharmony_ci	} else {
64962306a36Sopenharmony_ci		dev_err(dev, "ti,pga-gain is invalid: %u\n", data->pga_gain);
65062306a36Sopenharmony_ci		return -EINVAL;
65162306a36Sopenharmony_ci	}
65262306a36Sopenharmony_ci	return 0;
65362306a36Sopenharmony_ci}
65462306a36Sopenharmony_ci
65562306a36Sopenharmony_cistatic int tmp51x_read_properties(struct device *dev, struct tmp51x_data *data)
65662306a36Sopenharmony_ci{
65762306a36Sopenharmony_ci	int ret;
65862306a36Sopenharmony_ci	u32 nfactor[3];
65962306a36Sopenharmony_ci	u32 val;
66062306a36Sopenharmony_ci
66162306a36Sopenharmony_ci	ret = device_property_read_u32(dev, "shunt-resistor-micro-ohms", &val);
66262306a36Sopenharmony_ci	data->shunt_uohms = (ret >= 0) ? val : TMP51X_SHUNT_VALUE_DEFAULT;
66362306a36Sopenharmony_ci
66462306a36Sopenharmony_ci	ret = device_property_read_u32(dev, "ti,bus-range-microvolt", &val);
66562306a36Sopenharmony_ci	data->vbus_range_uvolt = (ret >= 0) ? val : TMP51X_VBUS_RANGE_DEFAULT;
66662306a36Sopenharmony_ci	ret = tmp51x_vbus_range_to_reg(dev, data);
66762306a36Sopenharmony_ci	if (ret < 0)
66862306a36Sopenharmony_ci		return ret;
66962306a36Sopenharmony_ci
67062306a36Sopenharmony_ci	ret = device_property_read_u32(dev, "ti,pga-gain", &val);
67162306a36Sopenharmony_ci	data->pga_gain = (ret >= 0) ? val : TMP51X_PGA_DEFAULT;
67262306a36Sopenharmony_ci	ret = tmp51x_pga_gain_to_reg(dev, data);
67362306a36Sopenharmony_ci	if (ret < 0)
67462306a36Sopenharmony_ci		return ret;
67562306a36Sopenharmony_ci
67662306a36Sopenharmony_ci	ret = device_property_read_u32_array(dev, "ti,nfactor", nfactor,
67762306a36Sopenharmony_ci					    (data->id == tmp513) ? 3 : 2);
67862306a36Sopenharmony_ci	if (ret >= 0)
67962306a36Sopenharmony_ci		memcpy(data->nfactor, nfactor, (data->id == tmp513) ? 3 : 2);
68062306a36Sopenharmony_ci
68162306a36Sopenharmony_ci	// Check if shunt value is compatible with pga-gain
68262306a36Sopenharmony_ci	if (data->shunt_uohms > data->pga_gain * 40 * 1000 * 1000) {
68362306a36Sopenharmony_ci		dev_err(dev, "shunt-resistor: %u too big for pga_gain: %u\n",
68462306a36Sopenharmony_ci			data->shunt_uohms, data->pga_gain);
68562306a36Sopenharmony_ci		return -EINVAL;
68662306a36Sopenharmony_ci	}
68762306a36Sopenharmony_ci
68862306a36Sopenharmony_ci	return 0;
68962306a36Sopenharmony_ci}
69062306a36Sopenharmony_ci
69162306a36Sopenharmony_cistatic void tmp51x_use_default(struct tmp51x_data *data)
69262306a36Sopenharmony_ci{
69362306a36Sopenharmony_ci	data->vbus_range_uvolt = TMP51X_VBUS_RANGE_DEFAULT;
69462306a36Sopenharmony_ci	data->pga_gain = TMP51X_PGA_DEFAULT;
69562306a36Sopenharmony_ci	data->shunt_uohms = TMP51X_SHUNT_VALUE_DEFAULT;
69662306a36Sopenharmony_ci}
69762306a36Sopenharmony_ci
69862306a36Sopenharmony_cistatic int tmp51x_configure(struct device *dev, struct tmp51x_data *data)
69962306a36Sopenharmony_ci{
70062306a36Sopenharmony_ci	data->shunt_config = TMP51X_SHUNT_CONFIG_DEFAULT;
70162306a36Sopenharmony_ci	data->temp_config = (data->id == tmp513) ?
70262306a36Sopenharmony_ci			TMP513_TEMP_CONFIG_DEFAULT : TMP512_TEMP_CONFIG_DEFAULT;
70362306a36Sopenharmony_ci
70462306a36Sopenharmony_ci	if (dev->of_node)
70562306a36Sopenharmony_ci		return tmp51x_read_properties(dev, data);
70662306a36Sopenharmony_ci
70762306a36Sopenharmony_ci	tmp51x_use_default(data);
70862306a36Sopenharmony_ci
70962306a36Sopenharmony_ci	return 0;
71062306a36Sopenharmony_ci}
71162306a36Sopenharmony_ci
71262306a36Sopenharmony_cistatic int tmp51x_probe(struct i2c_client *client)
71362306a36Sopenharmony_ci{
71462306a36Sopenharmony_ci	struct device *dev = &client->dev;
71562306a36Sopenharmony_ci	struct tmp51x_data *data;
71662306a36Sopenharmony_ci	struct device *hwmon_dev;
71762306a36Sopenharmony_ci	int ret;
71862306a36Sopenharmony_ci
71962306a36Sopenharmony_ci	data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
72062306a36Sopenharmony_ci	if (!data)
72162306a36Sopenharmony_ci		return -ENOMEM;
72262306a36Sopenharmony_ci
72362306a36Sopenharmony_ci	data->id = (uintptr_t)i2c_get_match_data(client);
72462306a36Sopenharmony_ci
72562306a36Sopenharmony_ci	ret = tmp51x_configure(dev, data);
72662306a36Sopenharmony_ci	if (ret < 0) {
72762306a36Sopenharmony_ci		dev_err(dev, "error configuring the device: %d\n", ret);
72862306a36Sopenharmony_ci		return ret;
72962306a36Sopenharmony_ci	}
73062306a36Sopenharmony_ci
73162306a36Sopenharmony_ci	data->regmap = devm_regmap_init_i2c(client, &tmp51x_regmap_config);
73262306a36Sopenharmony_ci	if (IS_ERR(data->regmap)) {
73362306a36Sopenharmony_ci		dev_err(dev, "failed to allocate register map\n");
73462306a36Sopenharmony_ci		return PTR_ERR(data->regmap);
73562306a36Sopenharmony_ci	}
73662306a36Sopenharmony_ci
73762306a36Sopenharmony_ci	ret = tmp51x_init(data);
73862306a36Sopenharmony_ci	if (ret < 0) {
73962306a36Sopenharmony_ci		dev_err(dev, "error configuring the device: %d\n", ret);
74062306a36Sopenharmony_ci		return -ENODEV;
74162306a36Sopenharmony_ci	}
74262306a36Sopenharmony_ci
74362306a36Sopenharmony_ci	hwmon_dev = devm_hwmon_device_register_with_info(dev, client->name,
74462306a36Sopenharmony_ci							 data,
74562306a36Sopenharmony_ci							 &tmp51x_chip_info,
74662306a36Sopenharmony_ci							 NULL);
74762306a36Sopenharmony_ci	if (IS_ERR(hwmon_dev))
74862306a36Sopenharmony_ci		return PTR_ERR(hwmon_dev);
74962306a36Sopenharmony_ci
75062306a36Sopenharmony_ci	dev_dbg(dev, "power monitor %s\n", client->name);
75162306a36Sopenharmony_ci
75262306a36Sopenharmony_ci	return 0;
75362306a36Sopenharmony_ci}
75462306a36Sopenharmony_ci
75562306a36Sopenharmony_cistatic struct i2c_driver tmp51x_driver = {
75662306a36Sopenharmony_ci	.driver = {
75762306a36Sopenharmony_ci		.name	= "tmp51x",
75862306a36Sopenharmony_ci		.of_match_table = tmp51x_of_match,
75962306a36Sopenharmony_ci	},
76062306a36Sopenharmony_ci	.probe		= tmp51x_probe,
76162306a36Sopenharmony_ci	.id_table	= tmp51x_id,
76262306a36Sopenharmony_ci};
76362306a36Sopenharmony_ci
76462306a36Sopenharmony_cimodule_i2c_driver(tmp51x_driver);
76562306a36Sopenharmony_ci
76662306a36Sopenharmony_ciMODULE_AUTHOR("Eric Tremblay <etremblay@distechcontrols.com>");
76762306a36Sopenharmony_ciMODULE_DESCRIPTION("tmp51x driver");
76862306a36Sopenharmony_ciMODULE_LICENSE("GPL");
769