hwmon: Add support for ltc2947

The ltc2947 is a high precision power and energy monitor with an
internal sense resistor supporting up to +/- 30A. Three internal no
Latency ADCs ensure accurate measurement of voltage and current, while
high-bandwidth analog multiplication of voltage and current provides
accurate power measurement in a wide range of applications. Internal or
external clocking options enable precise charge and energy measurements.

Signed-off-by: Nuno Sá <nuno.sa@analog.com>
Link: https://lore.kernel.org/r/20191021154115.319073-1-nuno.sa@analog.com
[groeck: Removed unnecessary checks when reading temperature and energy;
	 PAGE{0,1} -> LTC2947_PAGE_{0,1}]
Signed-off-by: Guenter Roeck <linux@roeck-us.net>
This commit is contained in:
Nuno Sá 2019-10-21 17:41:14 +02:00 committed by Guenter Roeck
parent 2057bdfb71
commit 9f90fd652b
9 changed files with 1435 additions and 0 deletions

View File

@ -90,6 +90,7 @@ Hardware Monitoring Kernel Drivers
lm95245
lochnagar
ltc2945
ltc2947
ltc2978
ltc2990
ltc3815

View File

@ -0,0 +1,100 @@
Kernel drivers ltc2947-i2c and ltc2947-spi
==========================================
Supported chips:
* Analog Devices LTC2947
Prefix: 'ltc2947'
Addresses scanned: -
Datasheet:
https://www.analog.com/media/en/technical-documentation/data-sheets/LTC2947.pdf
Author: Nuno Sá <nuno.sa@analog.com>
Description
___________
The LTC2947 is a high precision power and energy monitor that measures current,
voltage, power, temperature, charge and energy. The device supports both SPI
and I2C depending on the chip configuration.
The device also measures accumulated quantities as energy. It has two banks of
register's to read/set energy related values. These banks can be configured
independently to have setups like: energy1 accumulates always and enrgy2 only
accumulates if current is positive (to check battery charging efficiency for
example). The device also supports a GPIO pin that can be configured as output
to control a fan as a function of measured temperature. Then, the GPIO becomes
active as soon as a temperature reading is higher than a defined threshold. The
temp2 channel is used to control this thresholds and to read the respective
alarms.
Sysfs entries
_____________
The following attributes are supported. Limits are read-write, reset_history
is write-only and all the other attributes are read-only.
======================= ==========================================
in0_input VP-VM voltage (mV).
in0_min Undervoltage threshold
in0_max Overvoltage threshold
in0_lowest Lowest measured voltage
in0_highest Highest measured voltage
in0_reset_history Write 1 to reset in1 history
in0_min_alarm Undervoltage alarm
in0_max_alarm Overvoltage alarm
in0_label Channel label (VP-VM)
in1_input DVCC voltage (mV)
in1_min Undervoltage threshold
in1_max Overvoltage threshold
in1_lowest Lowest measured voltage
in1_highest Highest measured voltage
in1_reset_history Write 1 to reset in2 history
in1_min_alarm Undervoltage alarm
in1_max_alarm Overvoltage alarm
in1_label Channel label (DVCC)
curr1_input IP-IM Sense current (mA)
curr1_min Undercurrent threshold
curr1_max Overcurrent threshold
curr1_lowest Lowest measured current
curr1_highest Highest measured current
curr1_reset_history Write 1 to reset curr1 history
curr1_min_alarm Undercurrent alarm
curr1_max_alarm Overcurrent alarm
curr1_label Channel label (IP-IM)
power1_input Power (in uW)
power1_min Low power threshold
power1_max High power threshold
power1_input_lowest Historical minimum power use
power1_input_highest Historical maximum power use
power1_reset_history Write 1 to reset power1 history
power1_min_alarm Low power alarm
power1_max_alarm High power alarm
power1_label Channel label (Power)
temp1_input Chip Temperature (in milliC)
temp1_min Low temperature threshold
temp1_max High temperature threshold
temp1_input_lowest Historical minimum temperature use
temp1_input_highest Historical maximum temperature use
temp1_reset_history Write 1 to reset temp1 history
temp1_min_alarm Low temperature alarm
temp1_max_alarm High temperature alarm
temp1_label Channel label (Ambient)
temp2_min Low temperature threshold for fan control
temp2_max High temperature threshold for fan control
temp2_min_alarm Low temperature fan control alarm
temp2_max_alarm High temperature fan control alarm
temp2_label Channel label (TEMPFAN)
energy1_input Measured energy over time (in microJoule)
energy2_input Measured energy over time (in microJoule)
======================= ==========================================

View File

@ -9630,6 +9630,16 @@ S: Maintained
F: Documentation/hwmon/ltc4261.rst
F: drivers/hwmon/ltc4261.c
LTC2947 HARDWARE MONITOR DRIVER
M: Nuno Sá <nuno.sa@analog.com>
W: http://ez.analog.com/community/linux-device-drivers
L: linux-hwmon@vger.kernel.org
S: Supported
F: drivers/hwmon/ltc2947-core.c
F: drivers/hwmon/ltc2947-spi.c
F: drivers/hwmon/ltc2947-i2c.c
F: drivers/hwmon/ltc2947.h
LTC4306 I2C MULTIPLEXER DRIVER
M: Michael Hennerich <michael.hennerich@analog.com>
W: http://ez.analog.com/community/linux-device-drivers

View File

@ -726,6 +726,33 @@ config SENSORS_LTC2945
This driver can also be built as a module. If so, the module will
be called ltc2945.
config SENSORS_LTC2947
tristate
config SENSORS_LTC2947_I2C
tristate "Analog Devices LTC2947 High Precision Power and Energy Monitor over I2C"
depends on I2C
select REGMAP_I2C
select SENSORS_LTC2947
help
If you say yes here you get support for Linear Technology LTC2947
I2C High Precision Power and Energy Monitor
This driver can also be built as a module. If so, the module will
be called ltc2947-i2c.
config SENSORS_LTC2947_SPI
tristate "Analog Devices LTC2947 High Precision Power and Energy Monitor over SPI"
depends on SPI_MASTER
select REGMAP_SPI
select SENSORS_LTC2947
help
If you say yes here you get support for Linear Technology LTC2947
SPI High Precision Power and Energy Monitor
This driver can also be built as a module. If so, the module will
be called ltc2947-spi.
config SENSORS_LTC2990
tristate "Linear Technology LTC2990"
depends on I2C

View File

@ -106,6 +106,9 @@ obj-$(CONFIG_SENSORS_LM95234) += lm95234.o
obj-$(CONFIG_SENSORS_LM95241) += lm95241.o
obj-$(CONFIG_SENSORS_LM95245) += lm95245.o
obj-$(CONFIG_SENSORS_LTC2945) += ltc2945.o
obj-$(CONFIG_SENSORS_LTC2947) += ltc2947-core.o
obj-$(CONFIG_SENSORS_LTC2947_I2C) += ltc2947-i2c.o
obj-$(CONFIG_SENSORS_LTC2947_SPI) += ltc2947-spi.o
obj-$(CONFIG_SENSORS_LTC2990) += ltc2990.o
obj-$(CONFIG_SENSORS_LTC4151) += ltc4151.o
obj-$(CONFIG_SENSORS_LTC4215) += ltc4215.o

1183
drivers/hwmon/ltc2947-core.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,49 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Analog Devices LTC2947 high precision power and energy monitor over I2C
*
* Copyright 2019 Analog Devices Inc.
*/
#include <linux/i2c.h>
#include <linux/module.h>
#include <linux/regmap.h>
#include "ltc2947.h"
static const struct regmap_config ltc2947_regmap_config = {
.reg_bits = 8,
.val_bits = 8,
};
static int ltc2947_probe(struct i2c_client *i2c,
const struct i2c_device_id *id)
{
struct regmap *map;
map = devm_regmap_init_i2c(i2c, &ltc2947_regmap_config);
if (IS_ERR(map))
return PTR_ERR(map);
return ltc2947_core_probe(map, i2c->name);
}
static const struct i2c_device_id ltc2947_id[] = {
{"ltc2947", 0},
{}
};
MODULE_DEVICE_TABLE(i2c, ltc2947_id);
static struct i2c_driver ltc2947_driver = {
.driver = {
.name = "ltc2947",
.of_match_table = ltc2947_of_match,
.pm = &ltc2947_pm_ops,
},
.probe = ltc2947_probe,
.id_table = ltc2947_id,
};
module_i2c_driver(ltc2947_driver);
MODULE_AUTHOR("Nuno Sa <nuno.sa@analog.com>");
MODULE_DESCRIPTION("LTC2947 I2C power and energy monitor driver");
MODULE_LICENSE("GPL");

View File

@ -0,0 +1,50 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Analog Devices LTC2947 high precision power and energy monitor over SPI
*
* Copyright 2019 Analog Devices Inc.
*/
#include <linux/module.h>
#include <linux/of.h>
#include <linux/regmap.h>
#include <linux/spi/spi.h>
#include "ltc2947.h"
static const struct regmap_config ltc2947_regmap_config = {
.reg_bits = 16,
.val_bits = 8,
.read_flag_mask = BIT(0),
};
static int ltc2947_probe(struct spi_device *spi)
{
struct regmap *map;
map = devm_regmap_init_spi(spi, &ltc2947_regmap_config);
if (IS_ERR(map))
return PTR_ERR(map);
return ltc2947_core_probe(map, spi_get_device_id(spi)->name);
}
static const struct spi_device_id ltc2947_id[] = {
{"ltc2947", 0},
{}
};
MODULE_DEVICE_TABLE(spi, ltc2947_id);
static struct spi_driver ltc2947_driver = {
.driver = {
.name = "ltc2947",
.of_match_table = ltc2947_of_match,
.pm = &ltc2947_pm_ops,
},
.probe = ltc2947_probe,
.id_table = ltc2947_id,
};
module_spi_driver(ltc2947_driver);
MODULE_AUTHOR("Nuno Sa <nuno.sa@analog.com>");
MODULE_DESCRIPTION("LTC2947 SPI power and energy monitor driver");
MODULE_LICENSE("GPL");

12
drivers/hwmon/ltc2947.h Normal file
View File

@ -0,0 +1,12 @@
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef _LINUX_LTC2947_H
#define _LINUX_LTC2947_H
struct regmap;
extern const struct of_device_id ltc2947_of_match[];
extern const struct dev_pm_ops ltc2947_pm_ops;
int ltc2947_core_probe(struct regmap *map, const char *name);
#endif