// SPDX-License-Identifier: GPL-2.0
/*
* Analog Devices LTC2947 high precision power and energy monitor
*
* Copyright 2019 Analog Devices Inc.
*/
#include <linux/bitfield.h>
#include <linux/bits.h>
#include <linux/clk.h>
#include <linux/device.h>
#include <linux/hwmon.h>
#include <linux/hwmon-sysfs.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/regmap.h>
#include "ltc2947.h"
/* register's */
#define LTC2947_REG_PAGE_CTRL 0xFF
#define LTC2947_REG_CTRL 0xF0
#define LTC2947_REG_TBCTL 0xE9
#define LTC2947_CONT_MODE_MASK BIT(3)
#define LTC2947_CONT_MODE(x) FIELD_PREP(LTC2947_CONT_MODE_MASK, x)
#define LTC2947_PRE_MASK GENMASK(2, 0)
#define LTC2947_PRE(x) FIELD_PREP(LTC2947_PRE_MASK, x)
#define LTC2947_DIV_MASK GENMASK(7, 3)
#define LTC2947_DIV(x) FIELD_PREP(LTC2947_DIV_MASK, x)
#define LTC2947_SHUTDOWN_MASK BIT(0)
#define LTC2947_REG_ACCUM_POL 0xE1
#define LTC2947_ACCUM_POL_1_MASK GENMASK(1, 0)
#define LTC2947_ACCUM_POL_1(x) FIELD_PREP(LTC2947_ACCUM_POL_1_MASK, x)
#define LTC2947_ACCUM_POL_2_MASK GENMASK(3, 2)
#define LTC2947_ACCUM_POL_2(x) FIELD_PREP(LTC2947_ACCUM_POL_2_MASK, x)
#define LTC2947_REG_ACCUM_DEADBAND 0xE4
#define LTC2947_REG_GPIOSTATCTL 0x67
#define LTC2947_GPIO_EN_MASK BIT(0)
#define LTC2947_GPIO_EN(x) FIELD_PREP(LTC2947_GPIO_EN_MASK, x)
#define LTC2947_GPIO_FAN_EN_MASK BIT(6)
#define LTC2947_GPIO_FAN_EN(x) FIELD_PREP(LTC2947_GPIO_FAN_EN_MASK, x)
#define LTC2947_GPIO_FAN_POL_MASK BIT(7)
#define LTC2947_GPIO_FAN_POL(x) FIELD_PREP(LTC2947_GPIO_FAN_POL_MASK, x)
#define LTC2947_REG_GPIO_ACCUM 0xE3
/* 200Khz */
#define LTC2947_CLK_MIN 200000
/* 25Mhz */
#define LTC2947_CLK_MAX 25000000
#define LTC2947_PAGE0 0
#define LTC2947_PAGE1 1
/* Voltage registers */
#define LTC2947_REG_VOLTAGE 0xA0
#define LTC2947_REG_VOLTAGE_MAX 0x50
#define LTC2947_REG_VOLTAGE_MIN 0x52
#define LTC2947_REG_VOLTAGE_THRE_H 0x90
#define LTC2947_REG_VOLTAGE_THRE_L 0x92
#define LTC2947_REG_DVCC 0xA4
#define LTC2947_REG_DVCC_MAX 0x58
#define LTC2947_REG_DVCC_MIN 0x5A
#define LTC2947_REG_DVCC_THRE_H 0x98
#define LTC2947_REG_DVCC_THRE_L 0x9A
#define LTC2947_VOLTAGE_GEN_CHAN 0
#define LTC2947_VOLTAGE_DVCC_CHAN 1
/* in mV */
#define VOLTAGE_MAX 15500
#define VOLTAGE_MIN -300
#define VDVCC_MAX 15000
#define VDVCC_MIN 4750
/* Current registers */
#define LTC2947_REG_CURRENT 0x90
#define LTC2947_REG_CURRENT_MAX 0x40
#define LTC2947_REG_CURRENT_MIN 0x42
#define LTC2947_REG_CURRENT_THRE_H 0x80
#define LTC2947_REG_CURRENT_THRE_L 0x82
/* in mA */
#define CURRENT_MAX 30000
#define CURRENT_MIN -30000
/* Power registers */
#define LTC2947_REG_POWER 0x93
#define LTC2947_REG_POWER_MAX 0x44
#define LTC2947_REG_POWER_MIN 0x46
#define LTC2947_REG_POWER_THRE_H 0x84
#define LTC2947_REG_POWER_THRE_L 0x86
/* in uW */
#define POWER_MAX 450000000
#define POWER_MIN -450000000
/* Temperature registers */
#define LTC2947_REG_TEMP 0xA2
#define LTC2947_REG_TEMP_MAX 0x54
#define LTC2947_REG_TEMP_MIN 0x56
#define LTC2947_REG_TEMP_THRE_H 0x94
#define LTC2947_REG_TEMP_THRE_L 0x96
#define LTC2947_REG_TEMP_FAN_THRE_H 0x9C
#define LTC2947_REG_TEMP_FAN_THRE_L 0x9E
#define LTC2947_TEMP_FAN_CHAN 1
/* in millidegress Celsius */
#define TEMP_MAX 85000
#define TEMP_MIN -40000
/* Energy registers */
#define LTC2947_REG_ENERGY1 0x06
#define LTC2947_REG_ENERGY2 0x16
/* Status/Alarm/Overflow registers */
#define LTC2947_REG_STATUS 0x80
#define LTC2947_REG_STATVT 0x81
#define LTC2947_REG_STATIP 0x82
#define LTC2947_REG_STATVDVCC 0x87
#define LTC2947_ALERTS_SIZE (LTC2947_REG_STATVDVCC - LTC2947_REG_STATUS)
#define LTC2947_MAX_VOLTAGE_MASK BIT(0)
#define LTC2947_MIN_VOLTAGE_MASK BIT(1)
#define LTC2947_MAX_CURRENT_MASK BIT(0)
#define LTC2947_MIN_CURRENT_MASK BIT(1)
#define LTC2947_MAX_POWER_MASK BIT(2)
#define LTC2947_MIN_POWER_MASK BIT(3)
#define LTC2947_MAX_TEMP_MASK BIT(2)
#define LTC2947_MIN_TEMP_MASK BIT(3)
#define LTC2947_MAX_TEMP_FAN_MASK BIT(4)
#define LTC2947_MIN_TEMP_FAN_MASK BIT(5)
struct ltc2947_data {
struct regmap *map;
struct device *dev;
/*
* The mutex is needed because the device has 2 memory pages. When
* reading/writing the correct page needs to be set so that, the
* complete sequence select_page->read/write needs to be protected.
*/
struct mutex lock;
u32 lsb_energy;
bool gpio_out;
};
static int __ltc2947_val_read16(const struct ltc2947_data *st, const u8 reg,
u64 *val)
{
__be16 __val = 0;
int ret;
ret = regmap_bulk_read(st->map, reg, &__val, 2);
if (ret)
return ret;
*val = be16_to_cpu(__val);
return 0;
}
static int __ltc2947_val_read24(const struct ltc2947_data *st, const u8 reg,
u64 *val)
{
__be32 __val = 0;
int ret;
ret = regmap_bulk_read(st->map, reg, &__val, 3);
if (ret)
return ret;
*val = be32_to_cpu(__val) >> 8;
return 0;
}
static int __ltc2947_val_read64(const struct ltc2947_data *st, const u8 reg,
u64 *val)
{
__be64 __val = 0;
int ret;
ret = regmap_bulk_read(st->map, reg, &__val, 6);
if (ret)
return ret;
*val = be64_to_cpu(__val) >> 16;
return 0;
}
static int ltc2947_val_read(struct ltc2947_data *st, const u8 reg,
const u8 page, const size_t size, s64 *val)
{
int ret;
u64 __val = 0;
mutex_lock(&st->lock);
ret = regmap_write(st->map, LTC2947_REG_PAGE_CTRL, page);
if (ret) {
mutex_unlock(&st->lock);
return ret;
}
dev_dbg(st->dev, "Read val, reg:%02X, p:%d sz:%zu\n", reg, page,
size);
switch (size) {
case 2:
ret = __ltc2947_val_read16(st, reg, &__val);
break