123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771 |
- // SPDX-License-Identifier: GPL-2.0
- /*
- * Driver for Texas Instruments TMP512, TMP513 power monitor chips
- *
- * TMP513:
- * Thermal/Power Management with Triple Remote and
- * Local Temperature Sensor and Current Shunt Monitor
- * Datasheet: https://www.ti.com/lit/gpn/tmp513
- *
- * TMP512:
- * Thermal/Power Management with Dual Remote
- * and Local Temperature Sensor and Current Shunt Monitor
- * Datasheet: https://www.ti.com/lit/gpn/tmp512
- *
- * Copyright (C) 2019 Eric Tremblay <[email protected]>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- */
- #include <linux/err.h>
- #include <linux/hwmon.h>
- #include <linux/i2c.h>
- #include <linux/init.h>
- #include <linux/kernel.h>
- #include <linux/module.h>
- #include <linux/regmap.h>
- #include <linux/slab.h>
- #include <linux/util_macros.h>
- // Common register definition
- #define TMP51X_SHUNT_CONFIG 0x00
- #define TMP51X_TEMP_CONFIG 0x01
- #define TMP51X_STATUS 0x02
- #define TMP51X_SMBUS_ALERT 0x03
- #define TMP51X_SHUNT_CURRENT_RESULT 0x04
- #define TMP51X_BUS_VOLTAGE_RESULT 0x05
- #define TMP51X_POWER_RESULT 0x06
- #define TMP51X_BUS_CURRENT_RESULT 0x07
- #define TMP51X_LOCAL_TEMP_RESULT 0x08
- #define TMP51X_REMOTE_TEMP_RESULT_1 0x09
- #define TMP51X_REMOTE_TEMP_RESULT_2 0x0A
- #define TMP51X_SHUNT_CURRENT_H_LIMIT 0x0C
- #define TMP51X_SHUNT_CURRENT_L_LIMIT 0x0D
- #define TMP51X_BUS_VOLTAGE_H_LIMIT 0x0E
- #define TMP51X_BUS_VOLTAGE_L_LIMIT 0x0F
- #define TMP51X_POWER_LIMIT 0x10
- #define TMP51X_LOCAL_TEMP_LIMIT 0x11
- #define TMP51X_REMOTE_TEMP_LIMIT_1 0x12
- #define TMP51X_REMOTE_TEMP_LIMIT_2 0x13
- #define TMP51X_SHUNT_CALIBRATION 0x15
- #define TMP51X_N_FACTOR_AND_HYST_1 0x16
- #define TMP51X_N_FACTOR_2 0x17
- #define TMP51X_MAN_ID_REG 0xFE
- #define TMP51X_DEVICE_ID_REG 0xFF
- // TMP513 specific register definition
- #define TMP513_REMOTE_TEMP_RESULT_3 0x0B
- #define TMP513_REMOTE_TEMP_LIMIT_3 0x14
- #define TMP513_N_FACTOR_3 0x18
- // Common attrs, and NULL
- #define TMP51X_MANUFACTURER_ID 0x55FF
- #define TMP512_DEVICE_ID 0x22FF
- #define TMP513_DEVICE_ID 0x23FF
- // Default config
- #define TMP51X_SHUNT_CONFIG_DEFAULT 0x399F
- #define TMP51X_SHUNT_VALUE_DEFAULT 1000
- #define TMP51X_VBUS_RANGE_DEFAULT TMP51X_VBUS_RANGE_32V
- #define TMP51X_PGA_DEFAULT 8
- #define TMP51X_MAX_REGISTER_ADDR 0xFF
- #define TMP512_TEMP_CONFIG_DEFAULT 0xBF80
- #define TMP513_TEMP_CONFIG_DEFAULT 0xFF80
- // Mask and shift
- #define CURRENT_SENSE_VOLTAGE_320_MASK 0x1800
- #define CURRENT_SENSE_VOLTAGE_160_MASK 0x1000
- #define CURRENT_SENSE_VOLTAGE_80_MASK 0x0800
- #define CURRENT_SENSE_VOLTAGE_40_MASK 0
- #define TMP51X_BUS_VOLTAGE_MASK 0x2000
- #define TMP51X_NFACTOR_MASK 0xFF00
- #define TMP51X_HYST_MASK 0x00FF
- #define TMP51X_BUS_VOLTAGE_SHIFT 3
- #define TMP51X_TEMP_SHIFT 3
- // Alarms
- #define TMP51X_SHUNT_CURRENT_H_LIMIT_POS 15
- #define TMP51X_SHUNT_CURRENT_L_LIMIT_POS 14
- #define TMP51X_BUS_VOLTAGE_H_LIMIT_POS 13
- #define TMP51X_BUS_VOLTAGE_L_LIMIT_POS 12
- #define TMP51X_POWER_LIMIT_POS 11
- #define TMP51X_LOCAL_TEMP_LIMIT_POS 10
- #define TMP51X_REMOTE_TEMP_LIMIT_1_POS 9
- #define TMP51X_REMOTE_TEMP_LIMIT_2_POS 8
- #define TMP513_REMOTE_TEMP_LIMIT_3_POS 7
- #define TMP51X_VBUS_RANGE_32V 32000000
- #define TMP51X_VBUS_RANGE_16V 16000000
- // Max and Min value
- #define MAX_BUS_VOLTAGE_32_LIMIT 32764
- #define MAX_BUS_VOLTAGE_16_LIMIT 16382
- // Max possible value is -256 to +256 but datasheet indicated -40 to 125.
- #define MAX_TEMP_LIMIT 125000
- #define MIN_TEMP_LIMIT -40000
- #define MAX_TEMP_HYST 127500
- static const u8 TMP51X_TEMP_INPUT[4] = {
- TMP51X_LOCAL_TEMP_RESULT,
- TMP51X_REMOTE_TEMP_RESULT_1,
- TMP51X_REMOTE_TEMP_RESULT_2,
- TMP513_REMOTE_TEMP_RESULT_3
- };
- static const u8 TMP51X_TEMP_CRIT[4] = {
- TMP51X_LOCAL_TEMP_LIMIT,
- TMP51X_REMOTE_TEMP_LIMIT_1,
- TMP51X_REMOTE_TEMP_LIMIT_2,
- TMP513_REMOTE_TEMP_LIMIT_3
- };
- static const u8 TMP51X_TEMP_CRIT_ALARM[4] = {
- TMP51X_LOCAL_TEMP_LIMIT_POS,
- TMP51X_REMOTE_TEMP_LIMIT_1_POS,
- TMP51X_REMOTE_TEMP_LIMIT_2_POS,
- TMP513_REMOTE_TEMP_LIMIT_3_POS
- };
- static const u8 TMP51X_TEMP_CRIT_HYST[4] = {
- TMP51X_N_FACTOR_AND_HYST_1,
- TMP51X_N_FACTOR_AND_HYST_1,
- TMP51X_N_FACTOR_AND_HYST_1,
- TMP51X_N_FACTOR_AND_HYST_1
- };
- static const u8 TMP51X_CURR_INPUT[2] = {
- TMP51X_SHUNT_CURRENT_RESULT,
- TMP51X_BUS_CURRENT_RESULT
- };
- static struct regmap_config tmp51x_regmap_config = {
- .reg_bits = 8,
- .val_bits = 16,
- .max_register = TMP51X_MAX_REGISTER_ADDR,
- };
- enum tmp51x_ids {
- tmp512, tmp513
- };
- struct tmp51x_data {
- u16 shunt_config;
- u16 pga_gain;
- u32 vbus_range_uvolt;
- u16 temp_config;
- u32 nfactor[3];
- u32 shunt_uohms;
- u32 curr_lsb_ua;
- u32 pwr_lsb_uw;
- enum tmp51x_ids id;
- struct regmap *regmap;
- };
- // Set the shift based on the gain 8=4, 4=3, 2=2, 1=1
- static inline u8 tmp51x_get_pga_shift(struct tmp51x_data *data)
- {
- return 5 - ffs(data->pga_gain);
- }
- static int tmp51x_get_value(struct tmp51x_data *data, u8 reg, u8 pos,
- unsigned int regval, long *val)
- {
- switch (reg) {
- case TMP51X_STATUS:
- *val = (regval >> pos) & 1;
- break;
- case TMP51X_SHUNT_CURRENT_RESULT:
- case TMP51X_SHUNT_CURRENT_H_LIMIT:
- case TMP51X_SHUNT_CURRENT_L_LIMIT:
- /*
- * The valus is read in voltage in the chip but reported as
- * current to the user.
- * 2's complement number shifted by one to four depending
- * on the pga gain setting. 1lsb = 10uV
- */
- *val = sign_extend32(regval, 17 - tmp51x_get_pga_shift(data));
- *val = DIV_ROUND_CLOSEST(*val * 10000, data->shunt_uohms);
- break;
- case TMP51X_BUS_VOLTAGE_RESULT:
- case TMP51X_BUS_VOLTAGE_H_LIMIT:
- case TMP51X_BUS_VOLTAGE_L_LIMIT:
- // 1lsb = 4mV
- *val = (regval >> TMP51X_BUS_VOLTAGE_SHIFT) * 4;
- break;
- case TMP51X_POWER_RESULT:
- case TMP51X_POWER_LIMIT:
- // Power = (current * BusVoltage) / 5000
- *val = regval * data->pwr_lsb_uw;
- break;
- case TMP51X_BUS_CURRENT_RESULT:
- // Current = (ShuntVoltage * CalibrationRegister) / 4096
- *val = sign_extend32(regval, 16) * data->curr_lsb_ua;
- *val = DIV_ROUND_CLOSEST(*val, 1000);
- break;
- case TMP51X_LOCAL_TEMP_RESULT:
- case TMP51X_REMOTE_TEMP_RESULT_1:
- case TMP51X_REMOTE_TEMP_RESULT_2:
- case TMP513_REMOTE_TEMP_RESULT_3:
- case TMP51X_LOCAL_TEMP_LIMIT:
- case TMP51X_REMOTE_TEMP_LIMIT_1:
- case TMP51X_REMOTE_TEMP_LIMIT_2:
- case TMP513_REMOTE_TEMP_LIMIT_3:
- // 1lsb = 0.0625 degrees centigrade
- *val = sign_extend32(regval, 16) >> TMP51X_TEMP_SHIFT;
- *val = DIV_ROUND_CLOSEST(*val * 625, 10);
- break;
- case TMP51X_N_FACTOR_AND_HYST_1:
- // 1lsb = 0.5 degrees centigrade
- *val = (regval & TMP51X_HYST_MASK) * 500;
- break;
- default:
- // Programmer goofed
- WARN_ON_ONCE(1);
- *val = 0;
- return -EOPNOTSUPP;
- }
- return 0;
- }
- static int tmp51x_set_value(struct tmp51x_data *data, u8 reg, long val)
- {
- int regval, max_val;
- u32 mask = 0;
- switch (reg) {
- case TMP51X_SHUNT_CURRENT_H_LIMIT:
- case TMP51X_SHUNT_CURRENT_L_LIMIT:
- /*
- * The user enter current value and we convert it to
- * voltage. 1lsb = 10uV
- */
- val = DIV_ROUND_CLOSEST(val * data->shunt_uohms, 10000);
- max_val = U16_MAX >> tmp51x_get_pga_shift(data);
- regval = clamp_val(val, -max_val, max_val);
- break;
- case TMP51X_BUS_VOLTAGE_H_LIMIT:
- case TMP51X_BUS_VOLTAGE_L_LIMIT:
- // 1lsb = 4mV
- max_val = (data->vbus_range_uvolt == TMP51X_VBUS_RANGE_32V) ?
- MAX_BUS_VOLTAGE_32_LIMIT : MAX_BUS_VOLTAGE_16_LIMIT;
- val = clamp_val(DIV_ROUND_CLOSEST(val, 4), 0, max_val);
- regval = val << TMP51X_BUS_VOLTAGE_SHIFT;
- break;
- case TMP51X_POWER_LIMIT:
- regval = clamp_val(DIV_ROUND_CLOSEST(val, data->pwr_lsb_uw), 0,
- U16_MAX);
- break;
- case TMP51X_LOCAL_TEMP_LIMIT:
- case TMP51X_REMOTE_TEMP_LIMIT_1:
- case TMP51X_REMOTE_TEMP_LIMIT_2:
- case TMP513_REMOTE_TEMP_LIMIT_3:
- // 1lsb = 0.0625 degrees centigrade
- val = clamp_val(val, MIN_TEMP_LIMIT, MAX_TEMP_LIMIT);
- regval = DIV_ROUND_CLOSEST(val * 10, 625) << TMP51X_TEMP_SHIFT;
- break;
- case TMP51X_N_FACTOR_AND_HYST_1:
- // 1lsb = 0.5 degrees centigrade
- val = clamp_val(val, 0, MAX_TEMP_HYST);
- regval = DIV_ROUND_CLOSEST(val, 500);
- mask = TMP51X_HYST_MASK;
- break;
- default:
- // Programmer goofed
- WARN_ON_ONCE(1);
- return -EOPNOTSUPP;
- }
- if (mask == 0)
- return regmap_write(data->regmap, reg, regval);
- else
- return regmap_update_bits(data->regmap, reg, mask, regval);
- }
- static u8 tmp51x_get_reg(enum hwmon_sensor_types type, u32 attr, int channel)
- {
- switch (type) {
- case hwmon_temp:
- switch (attr) {
- case hwmon_temp_input:
- return TMP51X_TEMP_INPUT[channel];
- case hwmon_temp_crit_alarm:
- return TMP51X_STATUS;
- case hwmon_temp_crit:
- return TMP51X_TEMP_CRIT[channel];
- case hwmon_temp_crit_hyst:
- return TMP51X_TEMP_CRIT_HYST[channel];
- }
- break;
- case hwmon_in:
- switch (attr) {
- case hwmon_in_input:
- return TMP51X_BUS_VOLTAGE_RESULT;
- case hwmon_in_lcrit_alarm:
- case hwmon_in_crit_alarm:
- return TMP51X_STATUS;
- case hwmon_in_lcrit:
- return TMP51X_BUS_VOLTAGE_L_LIMIT;
- case hwmon_in_crit:
- return TMP51X_BUS_VOLTAGE_H_LIMIT;
- }
- break;
- case hwmon_curr:
- switch (attr) {
- case hwmon_curr_input:
- return TMP51X_CURR_INPUT[channel];
- case hwmon_curr_lcrit_alarm:
- case hwmon_curr_crit_alarm:
- return TMP51X_STATUS;
- case hwmon_curr_lcrit:
- return TMP51X_SHUNT_CURRENT_L_LIMIT;
- case hwmon_curr_crit:
- return TMP51X_SHUNT_CURRENT_H_LIMIT;
- }
- break;
- case hwmon_power:
- switch (attr) {
- case hwmon_power_input:
- return TMP51X_POWER_RESULT;
- case hwmon_power_crit_alarm:
- return TMP51X_STATUS;
- case hwmon_power_crit:
- return TMP51X_POWER_LIMIT;
- }
- break;
- default:
- break;
- }
- return 0;
- }
- static u8 tmp51x_get_status_pos(enum hwmon_sensor_types type, u32 attr,
- int channel)
- {
- switch (type) {
- case hwmon_temp:
- switch (attr) {
- case hwmon_temp_crit_alarm:
- return TMP51X_TEMP_CRIT_ALARM[channel];
- }
- break;
- case hwmon_in:
- switch (attr) {
- case hwmon_in_lcrit_alarm:
- return TMP51X_BUS_VOLTAGE_L_LIMIT_POS;
- case hwmon_in_crit_alarm:
- return TMP51X_BUS_VOLTAGE_H_LIMIT_POS;
- }
- break;
- case hwmon_curr:
- switch (attr) {
- case hwmon_curr_lcrit_alarm:
- return TMP51X_SHUNT_CURRENT_L_LIMIT_POS;
- case hwmon_curr_crit_alarm:
- return TMP51X_SHUNT_CURRENT_H_LIMIT_POS;
- }
- break;
- case hwmon_power:
- switch (attr) {
- case hwmon_power_crit_alarm:
- return TMP51X_POWER_LIMIT_POS;
- }
- break;
- default:
- break;
- }
- return 0;
- }
- static int tmp51x_read(struct device *dev, enum hwmon_sensor_types type,
- u32 attr, int channel, long *val)
- {
- struct tmp51x_data *data = dev_get_drvdata(dev);
- int ret;
- u32 regval;
- u8 pos = 0, reg = 0;
- reg = tmp51x_get_reg(type, attr, channel);
- if (reg == 0)
- return -EOPNOTSUPP;
- if (reg == TMP51X_STATUS)
- pos = tmp51x_get_status_pos(type, attr, channel);
- ret = regmap_read(data->regmap, reg, ®val);
- if (ret < 0)
- return ret;
- return tmp51x_get_value(data, reg, pos, regval, val);
- }
- static int tmp51x_write(struct device *dev, enum hwmon_sensor_types type,
- u32 attr, int channel, long val)
- {
- u8 reg = 0;
- reg = tmp51x_get_reg(type, attr, channel);
- if (reg == 0)
- return -EOPNOTSUPP;
- return tmp51x_set_value(dev_get_drvdata(dev), reg, val);
- }
- static umode_t tmp51x_is_visible(const void *_data,
- enum hwmon_sensor_types type, u32 attr,
- int channel)
- {
- const struct tmp51x_data *data = _data;
- switch (type) {
- case hwmon_temp:
- if (data->id == tmp512 && channel == 3)
- return 0;
- switch (attr) {
- case hwmon_temp_input:
- case hwmon_temp_crit_alarm:
- return 0444;
- case hwmon_temp_crit:
- return 0644;
- case hwmon_temp_crit_hyst:
- if (channel == 0)
- return 0644;
- return 0444;
- }
- break;
- case hwmon_in:
- switch (attr) {
- case hwmon_in_input:
- case hwmon_in_lcrit_alarm:
- case hwmon_in_crit_alarm:
- return 0444;
- case hwmon_in_lcrit:
- case hwmon_in_crit:
- return 0644;
- }
- break;
- case hwmon_curr:
- if (!data->shunt_uohms)
- return 0;
- switch (attr) {
- case hwmon_curr_input:
- case hwmon_curr_lcrit_alarm:
- case hwmon_curr_crit_alarm:
- return 0444;
- case hwmon_curr_lcrit:
- case hwmon_curr_crit:
- return 0644;
- }
- break;
- case hwmon_power:
- if (!data->shunt_uohms)
- return 0;
- switch (attr) {
- case hwmon_power_input:
- case hwmon_power_crit_alarm:
- return 0444;
- case hwmon_power_crit:
- return 0644;
- }
- break;
- default:
- break;
- }
- return 0;
- }
- static const struct hwmon_channel_info *tmp51x_info[] = {
- HWMON_CHANNEL_INFO(temp,
- HWMON_T_INPUT | HWMON_T_CRIT | HWMON_T_CRIT_ALARM |
- HWMON_T_CRIT_HYST,
- HWMON_T_INPUT | HWMON_T_CRIT | HWMON_T_CRIT_ALARM |
- HWMON_T_CRIT_HYST,
- HWMON_T_INPUT | HWMON_T_CRIT | HWMON_T_CRIT_ALARM |
- HWMON_T_CRIT_HYST,
- HWMON_T_INPUT | HWMON_T_CRIT | HWMON_T_CRIT_ALARM |
- HWMON_T_CRIT_HYST),
- HWMON_CHANNEL_INFO(in,
- HWMON_I_INPUT | HWMON_I_LCRIT | HWMON_I_LCRIT_ALARM |
- HWMON_I_CRIT | HWMON_I_CRIT_ALARM),
- HWMON_CHANNEL_INFO(curr,
- HWMON_C_INPUT | HWMON_C_LCRIT | HWMON_C_LCRIT_ALARM |
- HWMON_C_CRIT | HWMON_C_CRIT_ALARM,
- HWMON_C_INPUT),
- HWMON_CHANNEL_INFO(power,
- HWMON_P_INPUT | HWMON_P_CRIT | HWMON_P_CRIT_ALARM),
- NULL
- };
- static const struct hwmon_ops tmp51x_hwmon_ops = {
- .is_visible = tmp51x_is_visible,
- .read = tmp51x_read,
- .write = tmp51x_write,
- };
- static const struct hwmon_chip_info tmp51x_chip_info = {
- .ops = &tmp51x_hwmon_ops,
- .info = tmp51x_info,
- };
- /*
- * Calibrate the tmp51x following the datasheet method
- */
- static int tmp51x_calibrate(struct tmp51x_data *data)
- {
- int vshunt_max = data->pga_gain * 40;
- u64 max_curr_ma;
- u32 div;
- /*
- * If shunt_uohms is equal to 0, the calibration should be set to 0.
- * The consequence will be that the current and power measurement engine
- * of the sensor will not work. Temperature and voltage sensing will
- * continue to work.
- */
- if (data->shunt_uohms == 0)
- return regmap_write(data->regmap, TMP51X_SHUNT_CALIBRATION, 0);
- max_curr_ma = DIV_ROUND_CLOSEST_ULL(vshunt_max * 1000 * 1000,
- data->shunt_uohms);
- /*
- * Calculate the minimal bit resolution for the current and the power.
- * Those values will be used during register interpretation.
- */
- data->curr_lsb_ua = DIV_ROUND_CLOSEST_ULL(max_curr_ma * 1000, 32767);
- data->pwr_lsb_uw = 20 * data->curr_lsb_ua;
- div = DIV_ROUND_CLOSEST_ULL(data->curr_lsb_ua * data->shunt_uohms,
- 1000 * 1000);
- return regmap_write(data->regmap, TMP51X_SHUNT_CALIBRATION,
- DIV_ROUND_CLOSEST(40960, div));
- }
- /*
- * Initialize the configuration and calibration registers.
- */
- static int tmp51x_init(struct tmp51x_data *data)
- {
- unsigned int regval;
- int ret = regmap_write(data->regmap, TMP51X_SHUNT_CONFIG,
- data->shunt_config);
- if (ret < 0)
- return ret;
- ret = regmap_write(data->regmap, TMP51X_TEMP_CONFIG, data->temp_config);
- if (ret < 0)
- return ret;
- // nFactor configuration
- ret = regmap_update_bits(data->regmap, TMP51X_N_FACTOR_AND_HYST_1,
- TMP51X_NFACTOR_MASK, data->nfactor[0] << 8);
- if (ret < 0)
- return ret;
- ret = regmap_write(data->regmap, TMP51X_N_FACTOR_2,
- data->nfactor[1] << 8);
- if (ret < 0)
- return ret;
- if (data->id == tmp513) {
- ret = regmap_write(data->regmap, TMP513_N_FACTOR_3,
- data->nfactor[2] << 8);
- if (ret < 0)
- return ret;
- }
- ret = tmp51x_calibrate(data);
- if (ret < 0)
- return ret;
- // Read the status register before using as the datasheet propose
- return regmap_read(data->regmap, TMP51X_STATUS, ®val);
- }
- static const struct i2c_device_id tmp51x_id[] = {
- { "tmp512", tmp512 },
- { "tmp513", tmp513 },
- { }
- };
- MODULE_DEVICE_TABLE(i2c, tmp51x_id);
- static const struct of_device_id tmp51x_of_match[] = {
- {
- .compatible = "ti,tmp512",
- .data = (void *)tmp512
- },
- {
- .compatible = "ti,tmp513",
- .data = (void *)tmp513
- },
- { },
- };
- MODULE_DEVICE_TABLE(of, tmp51x_of_match);
- static int tmp51x_vbus_range_to_reg(struct device *dev,
- struct tmp51x_data *data)
- {
- if (data->vbus_range_uvolt == TMP51X_VBUS_RANGE_32V) {
- data->shunt_config |= TMP51X_BUS_VOLTAGE_MASK;
- } else if (data->vbus_range_uvolt == TMP51X_VBUS_RANGE_16V) {
- data->shunt_config &= ~TMP51X_BUS_VOLTAGE_MASK;
- } else {
- dev_err(dev, "ti,bus-range-microvolt is invalid: %u\n",
- data->vbus_range_uvolt);
- return -EINVAL;
- }
- return 0;
- }
- static int tmp51x_pga_gain_to_reg(struct device *dev, struct tmp51x_data *data)
- {
- if (data->pga_gain == 8) {
- data->shunt_config |= CURRENT_SENSE_VOLTAGE_320_MASK;
- } else if (data->pga_gain == 4) {
- data->shunt_config |= CURRENT_SENSE_VOLTAGE_160_MASK;
- } else if (data->pga_gain == 2) {
- data->shunt_config |= CURRENT_SENSE_VOLTAGE_80_MASK;
- } else if (data->pga_gain == 1) {
- data->shunt_config |= CURRENT_SENSE_VOLTAGE_40_MASK;
- } else {
- dev_err(dev, "ti,pga-gain is invalid: %u\n", data->pga_gain);
- return -EINVAL;
- }
- return 0;
- }
- static int tmp51x_read_properties(struct device *dev, struct tmp51x_data *data)
- {
- int ret;
- u32 nfactor[3];
- u32 val;
- ret = device_property_read_u32(dev, "shunt-resistor-micro-ohms", &val);
- data->shunt_uohms = (ret >= 0) ? val : TMP51X_SHUNT_VALUE_DEFAULT;
- ret = device_property_read_u32(dev, "ti,bus-range-microvolt", &val);
- data->vbus_range_uvolt = (ret >= 0) ? val : TMP51X_VBUS_RANGE_DEFAULT;
- ret = tmp51x_vbus_range_to_reg(dev, data);
- if (ret < 0)
- return ret;
- ret = device_property_read_u32(dev, "ti,pga-gain", &val);
- data->pga_gain = (ret >= 0) ? val : TMP51X_PGA_DEFAULT;
- ret = tmp51x_pga_gain_to_reg(dev, data);
- if (ret < 0)
- return ret;
- ret = device_property_read_u32_array(dev, "ti,nfactor", nfactor,
- (data->id == tmp513) ? 3 : 2);
- if (ret >= 0)
- memcpy(data->nfactor, nfactor, (data->id == tmp513) ? 3 : 2);
- // Check if shunt value is compatible with pga-gain
- if (data->shunt_uohms > data->pga_gain * 40 * 1000 * 1000) {
- dev_err(dev, "shunt-resistor: %u too big for pga_gain: %u\n",
- data->shunt_uohms, data->pga_gain);
- return -EINVAL;
- }
- return 0;
- }
- static void tmp51x_use_default(struct tmp51x_data *data)
- {
- data->vbus_range_uvolt = TMP51X_VBUS_RANGE_DEFAULT;
- data->pga_gain = TMP51X_PGA_DEFAULT;
- data->shunt_uohms = TMP51X_SHUNT_VALUE_DEFAULT;
- }
- static int tmp51x_configure(struct device *dev, struct tmp51x_data *data)
- {
- data->shunt_config = TMP51X_SHUNT_CONFIG_DEFAULT;
- data->temp_config = (data->id == tmp513) ?
- TMP513_TEMP_CONFIG_DEFAULT : TMP512_TEMP_CONFIG_DEFAULT;
- if (dev->of_node)
- return tmp51x_read_properties(dev, data);
- tmp51x_use_default(data);
- return 0;
- }
- static int tmp51x_probe(struct i2c_client *client)
- {
- struct device *dev = &client->dev;
- struct tmp51x_data *data;
- struct device *hwmon_dev;
- int ret;
- data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
- if (!data)
- return -ENOMEM;
- if (client->dev.of_node)
- data->id = (enum tmp51x_ids)device_get_match_data(&client->dev);
- else
- data->id = i2c_match_id(tmp51x_id, client)->driver_data;
- ret = tmp51x_configure(dev, data);
- if (ret < 0) {
- dev_err(dev, "error configuring the device: %d\n", ret);
- return ret;
- }
- data->regmap = devm_regmap_init_i2c(client, &tmp51x_regmap_config);
- if (IS_ERR(data->regmap)) {
- dev_err(dev, "failed to allocate register map\n");
- return PTR_ERR(data->regmap);
- }
- ret = tmp51x_init(data);
- if (ret < 0) {
- dev_err(dev, "error configuring the device: %d\n", ret);
- return -ENODEV;
- }
- hwmon_dev = devm_hwmon_device_register_with_info(dev, client->name,
- data,
- &tmp51x_chip_info,
- NULL);
- if (IS_ERR(hwmon_dev))
- return PTR_ERR(hwmon_dev);
- dev_dbg(dev, "power monitor %s\n", client->name);
- return 0;
- }
- static struct i2c_driver tmp51x_driver = {
- .driver = {
- .name = "tmp51x",
- .of_match_table = tmp51x_of_match,
- },
- .probe_new = tmp51x_probe,
- .id_table = tmp51x_id,
- };
- module_i2c_driver(tmp51x_driver);
- MODULE_AUTHOR("Eric Tremblay <[email protected]>");
- MODULE_DESCRIPTION("tmp51x driver");
- MODULE_LICENSE("GPL");
|