1026 lines
30 KiB
Diff
1026 lines
30 KiB
Diff
From 9f438ebf01d70477fdddc545af0f01690177d683 Mon Sep 17 00:00:00 2001
|
|
From: yangwei1 <yangwei1@eswincomputing.com>
|
|
Date: Thu, 23 May 2024 16:16:05 +0800
|
|
Subject: [PATCH 025/219] feat:add support pac1934 to get som voltage info
|
|
|
|
Changelogs:
|
|
---
|
|
.../boot/dts/eswin/hifive-premier-550.dts | 5 +-
|
|
arch/riscv/configs/win2030_defconfig | 1 +
|
|
drivers/hwmon/Kconfig | 6 +
|
|
drivers/hwmon/Makefile | 1 +
|
|
drivers/hwmon/pac193x.c | 938 ++++++++++++++++++
|
|
5 files changed, 949 insertions(+), 2 deletions(-)
|
|
create mode 100644 drivers/hwmon/pac193x.c
|
|
|
|
diff --git a/arch/riscv/boot/dts/eswin/hifive-premier-550.dts b/arch/riscv/boot/dts/eswin/hifive-premier-550.dts
|
|
index 550a8cc2fbaf..f0883f403393 100644
|
|
--- a/arch/riscv/boot/dts/eswin/hifive-premier-550.dts
|
|
+++ b/arch/riscv/boot/dts/eswin/hifive-premier-550.dts
|
|
@@ -663,13 +663,14 @@ &d0_aon_i2c1 {
|
|
status = "okay";
|
|
eswin,syscfg = <&d0_sys_con 0x3C0 15>;
|
|
iic_hold_time = <0x40>;
|
|
- sic451@10 {
|
|
+ pac1934@10 {
|
|
compatible = "microchip,pac1934";
|
|
/*update all register data*/
|
|
update_time_ms = <1000>;
|
|
+ eswin,chan_label = "som vdd", "soc vdd", "cpu vdd", "ddr lpvdd";
|
|
/*The update number of times the energy accumulates*/
|
|
energy_acc_count = <0>;
|
|
- sense_resistances=<4 4 4 4>;
|
|
+ shunt_resistors=<4 4 4 4>;
|
|
reg = <0x10>;
|
|
};
|
|
sic451@11 {
|
|
diff --git a/arch/riscv/configs/win2030_defconfig b/arch/riscv/configs/win2030_defconfig
|
|
index f57a7581943b..82c00984fe52 100644
|
|
--- a/arch/riscv/configs/win2030_defconfig
|
|
+++ b/arch/riscv/configs/win2030_defconfig
|
|
@@ -149,6 +149,7 @@ CONFIG_GPIOLIB=y
|
|
CONFIG_GPIO_SYSFS=y
|
|
CONFIG_GPIO_DWAPB=y
|
|
CONFIG_SENSORS_INA2XX=y
|
|
+CONFIG_SENSORS_PAC1934=y
|
|
CONFIG_WATCHDOG=y
|
|
CONFIG_DW_WATCHDOG=y
|
|
CONFIG_REGULATOR=y
|
|
diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig
|
|
index a4c361b6619c..14e8320b5c07 100644
|
|
--- a/drivers/hwmon/Kconfig
|
|
+++ b/drivers/hwmon/Kconfig
|
|
@@ -2371,6 +2371,12 @@ config SENSORS_INTEL_M10_BMC_HWMON
|
|
sensors monitor various telemetry data of different components on the
|
|
card, e.g. board temperature, FPGA core temperature/voltage/current.
|
|
|
|
+config SENSORS_PAC1934
|
|
+ tristate "microchip PAC193X Hardware Monitoring"
|
|
+ depends on I2C
|
|
+ help
|
|
+ If you say yes here you get support for microchip PAC193X
|
|
+ Single/Multi-Channel DC Power/Energy Monitor with Accumulator.
|
|
if ACPI
|
|
|
|
comment "ACPI drivers"
|
|
diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile
|
|
index 4ac9452b5430..6b5643ef316a 100644
|
|
--- a/drivers/hwmon/Makefile
|
|
+++ b/drivers/hwmon/Makefile
|
|
@@ -220,6 +220,7 @@ obj-$(CONFIG_SENSORS_W83L786NG) += w83l786ng.o
|
|
obj-$(CONFIG_SENSORS_WM831X) += wm831x-hwmon.o
|
|
obj-$(CONFIG_SENSORS_WM8350) += wm8350-hwmon.o
|
|
obj-$(CONFIG_SENSORS_XGENE) += xgene-hwmon.o
|
|
+obj-$(CONFIG_SENSORS_PAC1934) += pac193x.o
|
|
|
|
obj-$(CONFIG_SENSORS_OCC) += occ/
|
|
obj-$(CONFIG_SENSORS_PECI) += peci/
|
|
diff --git a/drivers/hwmon/pac193x.c b/drivers/hwmon/pac193x.c
|
|
new file mode 100644
|
|
index 000000000000..ebad3bde611e
|
|
--- /dev/null
|
|
+++ b/drivers/hwmon/pac193x.c
|
|
@@ -0,0 +1,938 @@
|
|
+// SPDX-License-Identifier: GPL-2.0
|
|
+/*
|
|
+ * Driver for microchip pac1931,pac1932,pac1933,pac1934 power monitor chips
|
|
+ *
|
|
+ * Copyright 2024, Beijing ESWIN Computing Technology Co., Ltd.. All rights reserved.
|
|
+ * SPDX-License-Identifier: GPL-2.0
|
|
+ *
|
|
+ * 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.
|
|
+ *
|
|
+ * This program is distributed in the hope that it will be useful,
|
|
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
+ * GNU General Public License for more details.
|
|
+ *
|
|
+ * You should have received a copy of the GNU General Public License
|
|
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
+ *
|
|
+ * Authors: Yang Wei <yangwei1@eswincomputing.com>
|
|
+ */
|
|
+
|
|
+#include <linux/kernel.h>
|
|
+#include <linux/module.h>
|
|
+#include <linux/init.h>
|
|
+#include <linux/err.h>
|
|
+#include <linux/slab.h>
|
|
+#include <linux/i2c.h>
|
|
+#include <linux/hwmon.h>
|
|
+#include <linux/hwmon-sysfs.h>
|
|
+#include <linux/jiffies.h>
|
|
+#include <linux/of_device.h>
|
|
+#include <linux/of.h>
|
|
+#include <linux/delay.h>
|
|
+#include <linux/util_macros.h>
|
|
+
|
|
+#define PAC193X_MAX_CHAN_CNT 4
|
|
+
|
|
+#define PAC193X_REGISTERS 0x27
|
|
+#define PAC193X_VPOWERN_ACC_LEN 6
|
|
+#define PAC193X_VOLT_VALUE_LEN 2
|
|
+#define PAC193X_VPOWERN_VALUE_LEN 4
|
|
+#define PAC193X_ACC_COUNT_LEN 3
|
|
+
|
|
+#define PAC193X_CMD_REFRESH 0x0
|
|
+#define PAC193X_CMD_CTRL 0x1
|
|
+#define PAC193X_CMD_ACC_COUNT 0x2
|
|
+#define PAC193X_CMD_VPOWER1_ACC 0x3
|
|
+#define PAC193X_CMD_VPOWER2_ACC 0x4
|
|
+#define PAC193X_CMD_VPOWER3_ACC 0x5
|
|
+#define PAC193X_CMD_VPOWER4_ACC 0x6
|
|
+#define PAC193X_CMD_VBUS1 0x7
|
|
+#define PAC193X_CMD_VBUS2 0x8
|
|
+#define PAC193X_CMD_VBUS3 0x9
|
|
+#define PAC193X_CMD_VBUS4 0xa
|
|
+#define PAC193X_CMD_VSENSE1 0xb
|
|
+#define PAC193X_CMD_VSENSE2 0xc
|
|
+#define PAC193X_CMD_VSENSE3 0xd
|
|
+#define PAC193X_CMD_VSENSE4 0xe
|
|
+#define PAC193X_CMD_VBUS1_AVG 0xf
|
|
+#define PAC193X_CMD_VBUS2_AVG 0x10
|
|
+#define PAC193X_CMD_VBUS3_AVG 0x11
|
|
+#define PAC193X_CMD_VBUS4_AVG 0x12
|
|
+#define PAC193X_CMD_VSENSE1_AVG 0x13
|
|
+#define PAC193X_CMD_VSENSE2_AVG 0x14
|
|
+#define PAC193X_CMD_VSENSE3_AVG 0x15
|
|
+#define PAC193X_CMD_VSENSE4_AVG 0x16
|
|
+#define PAC193X_CMD_VPOWER1 0x17
|
|
+#define PAC193X_CMD_VPOWER2 0x18
|
|
+#define PAC193X_CMD_VPOWER3 0x19
|
|
+#define PAC193X_CMD_VPOWER4 0x1a
|
|
+#define PAC193X_CMD_CHANNEL_SMBUS 0x1c
|
|
+#define PAC193X_CMD_NEG_PWR 0x1D
|
|
+#define PAC193X_CMD_REFRESH_G 0x1E
|
|
+#define PAC193X_CMD_REFRESH_V 0x1F
|
|
+#define PAC193X_CMD_SLOW 0x1F
|
|
+#define PAC193X_CMD_CTRL_ACT 0x21
|
|
+#define PAC193X_CMD_DIS_ACT 0x22
|
|
+#define PAC193X_CMD_NEG_PWR_ACT 0x23
|
|
+#define PAC193X_CMD_CTRL_LAT 0x24
|
|
+#define PAC193X_CMD_DIS_LAT 0x25
|
|
+#define PAC193X_CMD_NEG_PWR_LAT 0x26
|
|
+#define PAC193X_CMD_PID 0xFD
|
|
+#define PAC193X_CMD_MID 0xFE
|
|
+#define PAC193X_CMD_REVERSION_ID 0xFF
|
|
+
|
|
+#define PAC193X_COSTANT_PWR_M 3200000000ull /* 3.2V^2*1000mO*/
|
|
+#define PAC193X_COSTANT_CURRENT_M 100000 /* 100mv*1000mO*/
|
|
+
|
|
+struct pac193x_data
|
|
+{
|
|
+ struct mutex config_lock;
|
|
+ struct i2c_client *client;
|
|
+ u32 update_time_ms;
|
|
+ u32 energy_acc_count;
|
|
+ struct workqueue_struct *update_workqueue;
|
|
+ struct delayed_work update_work;
|
|
+ u32 vbus_denominator[PAC193X_MAX_CHAN_CNT];
|
|
+ u32 vsense_denominator[PAC193X_MAX_CHAN_CNT];
|
|
+ u32 vpower_denominator[PAC193X_MAX_CHAN_CNT];
|
|
+ u32 shunt_resistors[PAC193X_MAX_CHAN_CNT];
|
|
+ char pac193x_label[PAC193X_MAX_CHAN_CNT][16];
|
|
+ u32 sample_rate;
|
|
+};
|
|
+
|
|
+enum PAC193X_CHAN_INDEX
|
|
+{
|
|
+ pac1931_index = 0,
|
|
+ pac1932_index,
|
|
+ pac1933_index,
|
|
+ pac1934_index
|
|
+};
|
|
+
|
|
+static int pac193x_get_energy(struct device *dev, u8 commmd, u8 chan, long *val)
|
|
+{
|
|
+ struct pac193x_data *data = dev_get_drvdata(dev);
|
|
+ int ret;
|
|
+ u64 cache = 0;
|
|
+ u8 *pcache = (u8 *)&cache;
|
|
+ u64 energy_value = 0;
|
|
+
|
|
+ commmd = commmd + chan;
|
|
+ dev_dbg(dev, "%s.%d,chan:%d,commad:%d,LEN:%ld\n", __FUNCTION__,
|
|
+ __LINE__, chan, commmd, sizeof(cache));
|
|
+ mutex_lock(&data->config_lock);
|
|
+ ret = i2c_smbus_read_i2c_block_data(data->client, commmd,
|
|
+ PAC193X_VPOWERN_ACC_LEN, pcache);
|
|
+ mutex_unlock(&data->config_lock);
|
|
+
|
|
+ energy_value = ((cache & 0xff) << 40) | (((cache >> 8) & 0xff) << 32) |
|
|
+ (((cache >> 16) & 0xff) << 24) |
|
|
+ (((cache >> 24) & 0xff) << 16) |
|
|
+ (((cache >> 32) & 0xff) << 8) | (((cache >> 40) & 0xff));
|
|
+ energy_value = energy_value & 0xffffffffffffULL;
|
|
+ dev_dbg(dev,
|
|
+ "%s.%d,commd:0x%x,value:%lld,ret:%d,resistances:%u,denominator:%u,sample_rate:%u\n",
|
|
+ __FUNCTION__, __LINE__, commmd, energy_value, ret,
|
|
+ data->shunt_resistors[chan], data->vpower_denominator[chan],
|
|
+ data->sample_rate);
|
|
+
|
|
+ /* energy=3200000*Vpower/(Rsense*denominator*sample_rate) */
|
|
+ energy_value = ((energy_value / (u64)data->vpower_denominator[chan]) *
|
|
+ (PAC193X_COSTANT_PWR_M /
|
|
+ (data->shunt_resistors[chan] * data->sample_rate)));
|
|
+
|
|
+ *val = energy_value;
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static u16 pac193x_get_word(struct pac193x_data *data, u8 commmd)
|
|
+{
|
|
+ int ret;
|
|
+ u16 cache = 0;
|
|
+
|
|
+ mutex_lock(&data->config_lock);
|
|
+ ret = i2c_smbus_read_word_data(data->client, commmd);
|
|
+ mutex_unlock(&data->config_lock);
|
|
+ cache = ((ret & 0xff) << 8) | ((ret >> 8) & 0xff);
|
|
+ dev_dbg(&data->client->dev, "%s.%d,commd:0x%x,value:0x%x,ret:0x%x\n",
|
|
+ __FUNCTION__, __LINE__, commmd, cache, ret);
|
|
+
|
|
+ return cache;
|
|
+}
|
|
+
|
|
+static int pac193x_get_volt(struct device *dev, u8 commmd, u8 chan, long *val)
|
|
+{
|
|
+ struct pac193x_data *data = dev_get_drvdata(dev);
|
|
+ u32 cache = 0;
|
|
+
|
|
+ commmd = commmd + chan;
|
|
+ dev_dbg(dev, "%s.%d,commd:0x%x,chan:%d,vbus_denominator:%d\n",
|
|
+ __FUNCTION__, __LINE__, commmd, chan,
|
|
+ data->vbus_denominator[chan]);
|
|
+ cache = pac193x_get_word(data, commmd);
|
|
+ /*to mV*/
|
|
+ cache = cache * 1000 / data->vbus_denominator[chan];
|
|
+ *val = cache;
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int pac193x_get_current(struct device *dev, u8 commmd, u8 chan,
|
|
+ long *val)
|
|
+{
|
|
+ struct pac193x_data *data = dev_get_drvdata(dev);
|
|
+ u32 cache = 0;
|
|
+
|
|
+ commmd = commmd + chan;
|
|
+ dev_dbg(dev,
|
|
+ "%s.%d,commd:0x%x,chan:%d,vbus_denominator:%d,resistances:%d\n",
|
|
+ __FUNCTION__, __LINE__, commmd, chan,
|
|
+ data->vsense_denominator[chan], data->shunt_resistors[chan]);
|
|
+ cache = pac193x_get_word(data, commmd);
|
|
+ /* I=Vsense*100/(Rsense*denominator) */
|
|
+ cache = cache * PAC193X_COSTANT_CURRENT_M /
|
|
+ (data->vsense_denominator[chan] *
|
|
+ data->shunt_resistors[chan]);
|
|
+ *val = cache;
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int pac193x_get_power(struct device *dev, u8 commmd, u8 chan, long *val)
|
|
+{
|
|
+ struct pac193x_data *data = dev_get_drvdata(dev);
|
|
+ int ret;
|
|
+ u32 cache = 0;
|
|
+ u8 *pcache = (u8 *)&cache;
|
|
+ u64 pwr_value = 0;
|
|
+
|
|
+ commmd = commmd + chan;
|
|
+ mutex_lock(&data->config_lock);
|
|
+ ret = i2c_smbus_read_i2c_block_data(data->client, commmd,
|
|
+ PAC193X_VPOWERN_VALUE_LEN, pcache);
|
|
+ mutex_unlock(&data->config_lock);
|
|
+ pwr_value = ((cache & 0xff) << 24) | (((cache >> 8) & 0xff) << 16) |
|
|
+ (((cache >> 16) & 0xff) << 8) | ((cache >> 24) & 0xff);
|
|
+ pwr_value = pwr_value >> 4;
|
|
+ dev_dbg(dev,
|
|
+ "%s.%d,commd:0x%x,chan:%d,value:0x%x,pwr_value:0x%llx,%llu,ret:%d,resistances:%u,denominator:%u\n",
|
|
+ __FUNCTION__, __LINE__, commmd, chan, cache, pwr_value,
|
|
+ pwr_value, ret, data->shunt_resistors[chan],
|
|
+ data->vpower_denominator[chan]);
|
|
+ /* pwr=3200000*Vpower/Rsense*denominator */
|
|
+ pwr_value = pwr_value * PAC193X_COSTANT_PWR_M /
|
|
+ ((u64)data->shunt_resistors[chan] *
|
|
+ (u64)data->vpower_denominator[chan]);
|
|
+ *val = pwr_value;
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int pac193x_send_refresh_cmd(struct pac193x_data *data, u8 command)
|
|
+{
|
|
+ int ret = 0;
|
|
+
|
|
+ mutex_lock(&data->config_lock);
|
|
+ ret = i2c_smbus_write_byte(data->client, command);
|
|
+ mutex_unlock(&data->config_lock);
|
|
+ dev_dbg(&data->client->dev, "%s.%d,commd:0x%x,ret:%d\n", __FUNCTION__,
|
|
+ __LINE__, command, ret);
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+static ssize_t pac193x_refresh_store(struct device *dev,
|
|
+ struct device_attribute *da,
|
|
+ const char *buf, size_t count)
|
|
+{
|
|
+ struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(da);
|
|
+ struct pac193x_data *data = dev_get_drvdata(dev);
|
|
+
|
|
+ pac193x_send_refresh_cmd(data, (u8)sensor_attr->index);
|
|
+ return count;
|
|
+}
|
|
+
|
|
+static struct sensor_device_attribute pac1934_refreshs[] = {
|
|
+ SENSOR_ATTR_WO(refresh_clear_acc, pac193x_refresh, PAC193X_CMD_REFRESH),
|
|
+ SENSOR_ATTR_WO(refresh_all_193x, pac193x_refresh,
|
|
+ PAC193X_CMD_REFRESH_G),
|
|
+ SENSOR_ATTR_WO(refresh_updata_value, pac193x_refresh,
|
|
+ PAC193X_CMD_REFRESH_V),
|
|
+};
|
|
+
|
|
+static u8 pac193x_read_byte_data(struct pac193x_data *data, u8 command)
|
|
+{
|
|
+ int cache = 0;
|
|
+ int cnt = 0;
|
|
+ while (1)
|
|
+ {
|
|
+ mutex_lock(&data->config_lock);
|
|
+ cache = i2c_smbus_read_byte_data(data->client, command);
|
|
+ mutex_unlock(&data->config_lock);
|
|
+ if (0xff != cache)
|
|
+ {
|
|
+ break;
|
|
+ }
|
|
+ cnt++;
|
|
+ if (cnt > 100)
|
|
+ {
|
|
+ dev_err(&data->client->dev,
|
|
+ "get command:%d value error\n", command);
|
|
+ return 0xff;
|
|
+ }
|
|
+ }
|
|
+ return (u8)cache;
|
|
+}
|
|
+
|
|
+static ssize_t pac193x_ctrl_show(struct device *dev,
|
|
+ struct device_attribute *attr, char *buf)
|
|
+{
|
|
+ struct pac193x_data *data = dev_get_drvdata(dev);
|
|
+ u8 set_val = 0, act_val = 0, lat_val = 0;
|
|
+
|
|
+ set_val = pac193x_read_byte_data(data, PAC193X_CMD_CTRL);
|
|
+ act_val = pac193x_read_byte_data(data, PAC193X_CMD_CTRL_ACT);
|
|
+ lat_val = pac193x_read_byte_data(data, PAC193X_CMD_CTRL_LAT);
|
|
+
|
|
+ return sprintf(buf,
|
|
+ "%16s:%6s,%6s,%6s\n"
|
|
+ "%16s:%6d,%6d,%6d\n"
|
|
+ "%16s:%6d,%6d,%6d\n"
|
|
+ "%16s:%6d,%6d,%6d\n"
|
|
+ "%16s:%6d,%6d,%6d\n"
|
|
+ "%16s:%6d,%6d,%6d\n"
|
|
+ "%16s:%6d,%6d,%6d\n"
|
|
+ "%16s:%6d,%6d,%6d\n",
|
|
+ "", "set", "act", "latch",
|
|
+ "sample_rate", (set_val >> 6) & 0x3, (act_val >> 6) & 0x3, (lat_val >> 6) & 0x3,
|
|
+ "SLEEP", (set_val >> 5) & 0x1, (act_val >> 5) & 0x1, (lat_val >> 5) & 0x1,
|
|
+ "SING", (set_val >> 4) & 0x1, (act_val >> 4) & 0x1, (lat_val >> 4) & 0x1,
|
|
+ "ALERT_PIN", (set_val >> 3) & 0x1, (act_val >> 3) & 0x1, (lat_val >> 3) & 0x1,
|
|
+ "ALERT_CC", (set_val >> 2) & 0x1, (act_val >> 2) & 0x1, (lat_val >> 2) & 0x1,
|
|
+ "OVF ALERT", (set_val >> 1) & 0x1, (act_val >> 1) & 0x1, (lat_val >> 1) & 0x1,
|
|
+ "OVF", (set_val >> 0) & 0x1, (act_val >> 0) & 0x1, (lat_val >> 0) & 0x1);
|
|
+}
|
|
+
|
|
+int pac193x_common_reg_set(struct device *dev, const char *buf, u8 commad)
|
|
+{
|
|
+ struct pac193x_data *data = dev_get_drvdata(dev);
|
|
+ unsigned long val;
|
|
+ int status;
|
|
+ int ret = 0;
|
|
+
|
|
+ status = kstrtoul(buf, 10, &val);
|
|
+ if (status < 0)
|
|
+ return status;
|
|
+ mutex_lock(&data->config_lock);
|
|
+ ret = i2c_smbus_write_byte_data(data->client, commad, (u8)val);
|
|
+ mutex_unlock(&data->config_lock);
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+static ssize_t pac193x_ctrl_store(struct device *dev,
|
|
+ struct device_attribute *attr,
|
|
+ const char *buf, size_t count)
|
|
+{
|
|
+ return pac193x_common_reg_set(dev, buf, PAC193X_CMD_CTRL);
|
|
+}
|
|
+
|
|
+DEVICE_ATTR(control, S_IWUSR | S_IRUGO, pac193x_ctrl_show, pac193x_ctrl_store);
|
|
+
|
|
+static ssize_t pac193x_acc_count_show(struct device *dev,
|
|
+ struct device_attribute *attr, char *buf)
|
|
+{
|
|
+ struct pac193x_data *data = dev_get_drvdata(dev);
|
|
+ int ret;
|
|
+ u32 cache = 0;
|
|
+ u8 *pcache = (u8 *)&cache;
|
|
+ u32 acc_cnt = 0;
|
|
+ mutex_lock(&data->config_lock);
|
|
+ ret = i2c_smbus_read_i2c_block_data(data->client, PAC193X_CMD_ACC_COUNT,
|
|
+ PAC193X_ACC_COUNT_LEN, pcache);
|
|
+ mutex_unlock(&data->config_lock);
|
|
+
|
|
+ acc_cnt = ((cache & 0xff) << 16) | (((cache >> 8) & 0xff) << 8) |
|
|
+ ((cache >> 16) & 0xff);
|
|
+ acc_cnt = acc_cnt & 0xffffff;
|
|
+
|
|
+ ret = sysfs_emit(buf, "%u\n", acc_cnt);
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+DEVICE_ATTR(acc_count, 0400, pac193x_acc_count_show, NULL);
|
|
+
|
|
+static ssize_t pac193x_dis_show(struct device *dev,
|
|
+ struct device_attribute *attr, char *buf)
|
|
+{
|
|
+ struct pac193x_data *data = dev_get_drvdata(dev);
|
|
+ u8 set_val = 0, act_val = 0, lat_val = 0;
|
|
+
|
|
+ set_val = pac193x_read_byte_data(data, PAC193X_CMD_CHANNEL_SMBUS);
|
|
+ act_val = pac193x_read_byte_data(data, PAC193X_CMD_DIS_ACT);
|
|
+ lat_val = pac193x_read_byte_data(data, PAC193X_CMD_DIS_LAT);
|
|
+
|
|
+ return sprintf(buf,
|
|
+ "%16s:%6s,%6s,%6s\n"
|
|
+ "%16s:%6d,%6d,%6d\n"
|
|
+ "%16s:%6d,%6d,%6d\n"
|
|
+ "%16s:%6d,%6d,%6d\n"
|
|
+ "%16s:%6d,%6d,%6d\n"
|
|
+ "%16s:%6d,%6d,%6d\n"
|
|
+ "%16s:%6d,%6d,%6d\n"
|
|
+ "%16s:%6d,%6d,%6d\n",
|
|
+ "", "set", "act", "latch",
|
|
+ "CH1_OFF", (set_val >> 7) & 0x1, (act_val >> 7) & 0x1, (lat_val >> 7) & 0x1,
|
|
+ "CH2_OFF", (set_val >> 6) & 0x1, (act_val >> 6) & 0x1, (lat_val >> 6) & 0x1,
|
|
+ "CH3_OFF", (set_val >> 5) & 0x1, (act_val >> 5) & 0x1, (lat_val >> 5) & 0x1,
|
|
+ "CH4_OFF", (set_val >> 4) & 0x1, (act_val >> 4) & 0x1, (lat_val >> 4) & 0x1,
|
|
+ "TIMEOUT", (set_val >> 3) & 0x1, (act_val >> 3) & 0x1, (lat_val >> 3) & 0x1,
|
|
+ "BYTE COUNT", (set_val >> 2) & 0x1, (act_val >> 2) & 0x1, (lat_val >> 2) & 0x1,
|
|
+ "NO SKIP", (set_val >> 1) & 0x1, (act_val >> 1) & 0x1, (lat_val >> 1) & 0x1);
|
|
+}
|
|
+
|
|
+static ssize_t pac193x_dis_store(struct device *dev,
|
|
+ struct device_attribute *attr, const char *buf,
|
|
+ size_t count)
|
|
+{
|
|
+ return pac193x_common_reg_set(dev, buf, PAC193X_CMD_CHANNEL_SMBUS);
|
|
+}
|
|
+
|
|
+DEVICE_ATTR(disable_chan_pmbus, S_IWUSR | S_IRUGO, pac193x_dis_show,
|
|
+ pac193x_dis_store);
|
|
+
|
|
+static ssize_t pac193x_neg_pwr_show(struct device *dev,
|
|
+ struct device_attribute *attr, char *buf)
|
|
+{
|
|
+ struct pac193x_data *data = dev_get_drvdata(dev);
|
|
+ u8 set_val = 0, act_val = 0, lat_val = 0;
|
|
+
|
|
+ set_val = pac193x_read_byte_data(data, PAC193X_CMD_NEG_PWR);
|
|
+ act_val = pac193x_read_byte_data(data, PAC193X_CMD_NEG_PWR_ACT);
|
|
+ lat_val = pac193x_read_byte_data(data, PAC193X_CMD_NEG_PWR_LAT);
|
|
+
|
|
+ return sprintf(buf,
|
|
+ "%16s:%6s,%6s,%6s\n"
|
|
+ "%16s:%6d,%6d,%6d\n"
|
|
+ "%16s:%6d,%6d,%6d\n"
|
|
+ "%16s:%6d,%6d,%6d\n"
|
|
+ "%16s:%6d,%6d,%6d\n"
|
|
+ "%16s:%6d,%6d,%6d\n"
|
|
+ "%16s:%6d,%6d,%6d\n"
|
|
+ "%16s:%6d,%6d,%6d\n"
|
|
+ "%16s:%6d,%6d,%6d\n",
|
|
+ "", "set", "act", "latch",
|
|
+ "CH1_BIDI", (set_val >> 7) & 0x1, (act_val >> 7) & 0x1, (lat_val >> 7) & 0x1,
|
|
+ "CH2_BIDI", (set_val >> 6) & 0x1, (act_val >> 6) & 0x1, (lat_val >> 6) & 0x1,
|
|
+ "CH3_BIDI", (set_val >> 5) & 0x1, (act_val >> 5) & 0x1, (lat_val >> 5) & 0x1,
|
|
+ "CH4_BIDI", (set_val >> 4) & 0x1, (act_val >> 4) & 0x1, (lat_val >> 5) & 0x1,
|
|
+ "CH1_BIDV", (set_val >> 3) & 0x1, (act_val >> 3) & 0x1, (lat_val >> 3) & 0x1,
|
|
+ "CH2_BIDV", (set_val >> 2) & 0x1, (act_val >> 2) & 0x1, (lat_val >> 2) & 0x1,
|
|
+ "CH3_BIDV", (set_val >> 1) & 0x1, (act_val >> 1) & 0x1, (lat_val >> 1) & 0x1,
|
|
+ "CH4_BIDV", (set_val >> 0) & 0x1, (act_val >> 0) & 0x1, (lat_val >> 0) & 0x1);
|
|
+}
|
|
+
|
|
+static ssize_t pac193x_neg_pwr_store(struct device *dev,
|
|
+ struct device_attribute *attr,
|
|
+ const char *buf, size_t count)
|
|
+{
|
|
+ return pac193x_common_reg_set(dev, buf, PAC193X_CMD_NEG_PWR);
|
|
+}
|
|
+
|
|
+DEVICE_ATTR(neg_pwr, S_IWUSR | S_IRUGO, pac193x_neg_pwr_show,
|
|
+ pac193x_neg_pwr_store);
|
|
+
|
|
+static ssize_t pac193x_slow_show(struct device *dev,
|
|
+ struct device_attribute *attr, char *buf)
|
|
+{
|
|
+ struct pac193x_data *data = dev_get_drvdata(dev);
|
|
+ u8 set_val = 0;
|
|
+
|
|
+ set_val = pac193x_read_byte_data(data, PAC193X_CMD_SLOW);
|
|
+
|
|
+ return sprintf(buf,
|
|
+ "SLOW:%d,SLOW-LH:%d,SLOW-HL:%d, R_RISE:%d,"
|
|
+ "R_V_RISE:%d,R_FALL:%d,R_V_FALL:%d,POR:%d\n",
|
|
+ (set_val >> 7) & 0x1, (set_val >> 6) & 0x1,
|
|
+ (set_val >> 5) & 0x1, (set_val >> 4) & 0x1,
|
|
+ (set_val >> 3) & 0x1, (set_val >> 2) & 0x1,
|
|
+ (set_val >> 1) & 0x1, (set_val >> 0) & 0x1);
|
|
+}
|
|
+
|
|
+static ssize_t pac193x_slow_store(struct device *dev,
|
|
+ struct device_attribute *attr,
|
|
+ const char *buf, size_t count)
|
|
+{
|
|
+ return pac193x_common_reg_set(dev, buf, PAC193X_CMD_SLOW);
|
|
+}
|
|
+
|
|
+DEVICE_ATTR(slow_ctrl, S_IWUSR | S_IRUGO, pac193x_slow_show,
|
|
+ pac193x_slow_store);
|
|
+
|
|
+static ssize_t pac193x_version_show(struct device *dev,
|
|
+ struct device_attribute *attr, char *buf)
|
|
+{
|
|
+ struct pac193x_data *data = dev_get_drvdata(dev);
|
|
+ int ret;
|
|
+ u8 pid = 0, mid = 0, rid = 0;
|
|
+
|
|
+ pid = pac193x_read_byte_data(data, PAC193X_CMD_PID);
|
|
+ mid = pac193x_read_byte_data(data, PAC193X_CMD_MID);
|
|
+ rid = pac193x_read_byte_data(data, PAC193X_CMD_REVERSION_ID);
|
|
+
|
|
+ ret = sysfs_emit(buf, "PID:0x%x,MID:0x%x,RID:0x%x\n", pid, mid, rid);
|
|
+ return ret;
|
|
+}
|
|
+DEVICE_ATTR(pac193x_version, 0400, pac193x_version_show, NULL);
|
|
+
|
|
+static struct attribute *pac193x_attrs[] = {
|
|
+ &dev_attr_control.attr,
|
|
+ &dev_attr_acc_count.attr,
|
|
+ &dev_attr_neg_pwr.attr,
|
|
+ &dev_attr_disable_chan_pmbus.attr,
|
|
+ &dev_attr_slow_ctrl.attr,
|
|
+ &dev_attr_pac193x_version.attr,
|
|
+ &pac1934_refreshs[0].dev_attr.attr,
|
|
+ &pac1934_refreshs[1].dev_attr.attr,
|
|
+ &pac1934_refreshs[2].dev_attr.attr,
|
|
+ NULL,
|
|
+};
|
|
+
|
|
+ATTRIBUTE_GROUPS(pac193x);
|
|
+
|
|
+static const struct hwmon_channel_info *pac1931_info[] = {
|
|
+ HWMON_CHANNEL_INFO(in, HWMON_I_INPUT | HWMON_I_AVERAGE,
|
|
+ HWMON_I_INPUT | HWMON_I_AVERAGE),
|
|
+ HWMON_CHANNEL_INFO(curr, HWMON_C_INPUT | HWMON_C_AVERAGE),
|
|
+ HWMON_CHANNEL_INFO(power, HWMON_P_INPUT),
|
|
+ HWMON_CHANNEL_INFO(energy, HWMON_E_INPUT),
|
|
+ NULL};
|
|
+static const struct hwmon_channel_info *pac1932_info[] = {
|
|
+ HWMON_CHANNEL_INFO(in, HWMON_I_INPUT | HWMON_I_AVERAGE,
|
|
+ HWMON_I_INPUT | HWMON_I_AVERAGE,
|
|
+ HWMON_I_INPUT | HWMON_I_AVERAGE),
|
|
+ HWMON_CHANNEL_INFO(curr, HWMON_C_INPUT | HWMON_C_AVERAGE,
|
|
+ HWMON_C_INPUT | HWMON_C_AVERAGE),
|
|
+ HWMON_CHANNEL_INFO(power, HWMON_P_INPUT, HWMON_P_INPUT),
|
|
+ HWMON_CHANNEL_INFO(energy, HWMON_E_INPUT, HWMON_E_INPUT),
|
|
+ NULL};
|
|
+static const struct hwmon_channel_info *pac1933_info[] = {
|
|
+ HWMON_CHANNEL_INFO(in, HWMON_I_INPUT | HWMON_I_AVERAGE,
|
|
+ HWMON_I_INPUT | HWMON_I_AVERAGE,
|
|
+ HWMON_I_INPUT | HWMON_I_AVERAGE,
|
|
+ HWMON_I_INPUT | HWMON_I_AVERAGE),
|
|
+ HWMON_CHANNEL_INFO(curr, HWMON_C_INPUT | HWMON_C_AVERAGE,
|
|
+ HWMON_C_INPUT | HWMON_C_AVERAGE,
|
|
+ HWMON_C_INPUT | HWMON_C_AVERAGE),
|
|
+ HWMON_CHANNEL_INFO(power, HWMON_P_INPUT, HWMON_P_INPUT, HWMON_P_INPUT),
|
|
+ HWMON_CHANNEL_INFO(energy, HWMON_E_INPUT, HWMON_E_INPUT, HWMON_E_INPUT),
|
|
+ NULL};
|
|
+static const struct hwmon_channel_info *pac1934_info[] = {
|
|
+ HWMON_CHANNEL_INFO(in,
|
|
+ HWMON_I_INPUT | HWMON_I_AVERAGE,
|
|
+ HWMON_I_INPUT | HWMON_I_AVERAGE | HWMON_I_LABEL,
|
|
+ HWMON_I_INPUT | HWMON_I_AVERAGE | HWMON_I_LABEL,
|
|
+ HWMON_I_INPUT | HWMON_I_AVERAGE | HWMON_I_LABEL,
|
|
+ HWMON_I_INPUT | HWMON_I_AVERAGE | HWMON_I_LABEL),
|
|
+ HWMON_CHANNEL_INFO(curr,
|
|
+ HWMON_C_INPUT | HWMON_C_AVERAGE | HWMON_C_LABEL,
|
|
+ HWMON_C_INPUT | HWMON_C_AVERAGE | HWMON_C_LABEL,
|
|
+ HWMON_C_INPUT | HWMON_C_AVERAGE | HWMON_C_LABEL,
|
|
+ HWMON_C_INPUT | HWMON_C_AVERAGE | HWMON_C_LABEL),
|
|
+ HWMON_CHANNEL_INFO(power, HWMON_P_INPUT | HWMON_P_LABEL,
|
|
+ HWMON_P_INPUT | HWMON_P_LABEL,
|
|
+ HWMON_P_INPUT | HWMON_P_LABEL,
|
|
+ HWMON_P_INPUT | HWMON_P_LABEL),
|
|
+ HWMON_CHANNEL_INFO(energy, HWMON_E_INPUT | HWMON_E_LABEL,
|
|
+ HWMON_E_INPUT | HWMON_E_LABEL,
|
|
+ HWMON_E_INPUT | HWMON_E_LABEL,
|
|
+ HWMON_E_INPUT | HWMON_E_LABEL),
|
|
+ NULL};
|
|
+
|
|
+static umode_t pac1934x_is_visible(const void *_data,
|
|
+ enum hwmon_sensor_types type, u32 attr,
|
|
+ int channel)
|
|
+{
|
|
+ switch (type)
|
|
+ {
|
|
+ case hwmon_in:
|
|
+ switch (attr)
|
|
+ {
|
|
+ case hwmon_in_label:
|
|
+ if (channel == 0)
|
|
+ {
|
|
+ return 0;
|
|
+ }
|
|
+ else
|
|
+ {
|
|
+ return 0444;
|
|
+ }
|
|
+ case hwmon_in_input:
|
|
+ case hwmon_in_average:
|
|
+ if (channel == 0)
|
|
+ {
|
|
+ return 0;
|
|
+ }
|
|
+ else
|
|
+ {
|
|
+ return S_IRUGO;
|
|
+ }
|
|
+ }
|
|
+ break;
|
|
+ case hwmon_curr:
|
|
+ switch (attr)
|
|
+ {
|
|
+ case hwmon_curr_label:
|
|
+ return 0444;
|
|
+ case hwmon_curr_input:
|
|
+ case hwmon_curr_average:
|
|
+ return S_IRUGO;
|
|
+ }
|
|
+ break;
|
|
+ case hwmon_power:
|
|
+ switch (attr)
|
|
+ {
|
|
+ case hwmon_power_label:
|
|
+ return 0444;
|
|
+ case hwmon_power_input:
|
|
+ return S_IRUGO;
|
|
+ }
|
|
+ break;
|
|
+ case hwmon_energy:
|
|
+ switch (attr)
|
|
+ {
|
|
+ case hwmon_energy_label:
|
|
+ return 0444;
|
|
+ case hwmon_energy_input:
|
|
+ return S_IRUGO;
|
|
+ }
|
|
+ break;
|
|
+ default:
|
|
+ break;
|
|
+ }
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int pac1934x_read_string(struct device *dev,
|
|
+ enum hwmon_sensor_types type,
|
|
+ u32 attr, int channel, const char **str)
|
|
+{
|
|
+ struct pac193x_data *data = dev_get_drvdata(dev);
|
|
+ switch (type)
|
|
+ {
|
|
+ case hwmon_in:
|
|
+ switch (attr)
|
|
+ {
|
|
+ case hwmon_in_label:
|
|
+ if (channel != 0)
|
|
+ {
|
|
+ *str = data->pac193x_label[channel - 1];
|
|
+ }
|
|
+ break;
|
|
+ }
|
|
+ break;
|
|
+ case hwmon_curr:
|
|
+ switch (attr)
|
|
+ {
|
|
+ case hwmon_curr_label:
|
|
+ *str = data->pac193x_label[channel];
|
|
+ break;
|
|
+ }
|
|
+ break;
|
|
+ case hwmon_power:
|
|
+ switch (attr)
|
|
+ {
|
|
+ case hwmon_power_label:
|
|
+ *str = data->pac193x_label[channel];
|
|
+ break;
|
|
+ }
|
|
+ break;
|
|
+ case hwmon_energy:
|
|
+ switch (attr)
|
|
+ {
|
|
+ case hwmon_energy_label:
|
|
+ *str = data->pac193x_label[channel];
|
|
+ break;
|
|
+ }
|
|
+ break;
|
|
+ default:
|
|
+ break;
|
|
+ }
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int pac193x_read(struct device *dev, enum hwmon_sensor_types type,
|
|
+ u32 attr, int channel, long *val)
|
|
+{
|
|
+ switch (type)
|
|
+ {
|
|
+ case hwmon_in:
|
|
+ switch (attr)
|
|
+ {
|
|
+ case hwmon_in_input:
|
|
+ return pac193x_get_volt(dev, PAC193X_CMD_VBUS1, channel - 1,
|
|
+ val);
|
|
+ case hwmon_in_average:
|
|
+ return pac193x_get_volt(dev, PAC193X_CMD_VBUS1_AVG,
|
|
+ channel - 1, val);
|
|
+ }
|
|
+ break;
|
|
+ case hwmon_curr:
|
|
+ switch (attr)
|
|
+ {
|
|
+ case hwmon_curr_input:
|
|
+ return pac193x_get_current(dev, PAC193X_CMD_VSENSE1,
|
|
+ channel, val);
|
|
+ case hwmon_curr_average:
|
|
+ return pac193x_get_current(dev, PAC193X_CMD_VSENSE1_AVG,
|
|
+ channel, val);
|
|
+ }
|
|
+ break;
|
|
+ case hwmon_power:
|
|
+ switch (attr)
|
|
+ {
|
|
+ case hwmon_power_input:
|
|
+ return pac193x_get_power(dev, PAC193X_CMD_VPOWER1,
|
|
+ channel, val);
|
|
+ }
|
|
+ break;
|
|
+ case hwmon_energy:
|
|
+ switch (attr)
|
|
+ {
|
|
+ case hwmon_energy_input:
|
|
+ return pac193x_get_energy(dev, PAC193X_CMD_VPOWER1_ACC,
|
|
+ channel, val);
|
|
+ }
|
|
+ break;
|
|
+ default:
|
|
+ break;
|
|
+ }
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static const struct hwmon_ops pac193x_hwmon_ops = {
|
|
+ .is_visible = pac1934x_is_visible,
|
|
+ .read = pac193x_read,
|
|
+ .read_string = pac1934x_read_string,
|
|
+};
|
|
+
|
|
+static struct hwmon_chip_info pac193x_chip_info = {
|
|
+ .ops = &pac193x_hwmon_ops,
|
|
+ .info = NULL,
|
|
+};
|
|
+
|
|
+static void update_reg_data(struct work_struct *work)
|
|
+{
|
|
+ static u32 updata_cnt = 0;
|
|
+ struct pac193x_data *data;
|
|
+ int act_val = 0, ctrl_val = 0, slow_val = 0;
|
|
+ int num = 0;
|
|
+ bool is_neg = false;
|
|
+
|
|
+ data = container_of(work, struct pac193x_data, update_work.work);
|
|
+ if ((data->energy_acc_count == 0) || (updata_cnt < data->energy_acc_count))
|
|
+ {
|
|
+ pac193x_send_refresh_cmd(data, PAC193X_CMD_REFRESH_V);
|
|
+ updata_cnt++;
|
|
+ }
|
|
+ else
|
|
+ {
|
|
+ pac193x_send_refresh_cmd(data, PAC193X_CMD_REFRESH);
|
|
+ updata_cnt = 0;
|
|
+ }
|
|
+
|
|
+ act_val = pac193x_read_byte_data(data, PAC193X_CMD_NEG_PWR_ACT);
|
|
+
|
|
+ for (num = 0; num < PAC193X_MAX_CHAN_CNT; num++)
|
|
+ {
|
|
+ is_neg = false;
|
|
+ if (0x1 == ((act_val >> num) & 0x1))
|
|
+ {
|
|
+ /* Vsource=32*Vbus/2^15 = Vbus/2^10=Vbus/1024 */
|
|
+ data->vbus_denominator[3 - num] = 1024;
|
|
+ is_neg = true;
|
|
+ }
|
|
+ else
|
|
+ {
|
|
+ /* Vsource=32*Vbus/2^16 = Vbus/2^10=Vbus/1024 */
|
|
+ data->vbus_denominator[3 - num] = 2048;
|
|
+ }
|
|
+
|
|
+ if (0x1 == ((act_val >> (num + 4)) & 0x1))
|
|
+ {
|
|
+ /* 2^15 */
|
|
+ data->vsense_denominator[3 - num] = 32768;
|
|
+ is_neg = true;
|
|
+ }
|
|
+ else
|
|
+ {
|
|
+ /*2^16 */
|
|
+ data->vsense_denominator[3 - num] = 65536;
|
|
+ }
|
|
+ if (true == is_neg)
|
|
+ {
|
|
+ /* 2^28 */
|
|
+ data->vpower_denominator[3 - num] = 134217728;
|
|
+ }
|
|
+ else
|
|
+ {
|
|
+ /* 2^29 */
|
|
+ data->vpower_denominator[3 - num] = 268435456;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ slow_val = pac193x_read_byte_data(data, PAC193X_CMD_SLOW);
|
|
+ ctrl_val = pac193x_read_byte_data(data, PAC193X_CMD_CTRL_ACT);
|
|
+ if ((0x1 == ((slow_val >> 7) & 0x1)) &&
|
|
+ (0x0 == ((ctrl_val >> 3) & 0x1)))
|
|
+ {
|
|
+ data->sample_rate = 8;
|
|
+ }
|
|
+ else
|
|
+ {
|
|
+ switch ((ctrl_val >> 6) & 0x3)
|
|
+ {
|
|
+ case 0:
|
|
+ data->sample_rate = 1024;
|
|
+ break;
|
|
+ case 1:
|
|
+ data->sample_rate = 256;
|
|
+ break;
|
|
+ case 2:
|
|
+ data->sample_rate = 64;
|
|
+ break;
|
|
+ case 3:
|
|
+ data->sample_rate = 8;
|
|
+ break;
|
|
+ default:
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+ queue_delayed_work(data->update_workqueue, &data->update_work,
|
|
+ msecs_to_jiffies(data->update_time_ms));
|
|
+}
|
|
+
|
|
+static int pac193x_probe(struct i2c_client *client)
|
|
+{
|
|
+ struct device *dev = &client->dev;
|
|
+ struct pac193x_data *data;
|
|
+ struct device *hwmon_dev;
|
|
+ int ret = 0;
|
|
+ int num = 0;
|
|
+ const char *output_names[4];
|
|
+ struct device_node *np;
|
|
+ enum PAC193X_CHAN_INDEX chan_index =
|
|
+ (enum PAC193X_CHAN_INDEX)of_device_get_match_data(&client->dev);
|
|
+
|
|
+ switch (chan_index)
|
|
+ {
|
|
+ case pac1931_index:
|
|
+ pac193x_chip_info.info = pac1931_info;
|
|
+ break;
|
|
+ case pac1932_index:
|
|
+ pac193x_chip_info.info = pac1932_info;
|
|
+ break;
|
|
+ case pac1933_index:
|
|
+ pac193x_chip_info.info = pac1933_info;
|
|
+ break;
|
|
+ case pac1934_index:
|
|
+ pac193x_chip_info.info = pac1934_info;
|
|
+ break;
|
|
+ default:
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
|
|
+ if (!data)
|
|
+ return -ENOMEM;
|
|
+
|
|
+ for (num = 0; num < PAC193X_MAX_CHAN_CNT; num++)
|
|
+ {
|
|
+ data->vbus_denominator[num] = 1;
|
|
+ data->vsense_denominator[num] = 1;
|
|
+ data->shunt_resistors[num] = 1;
|
|
+ }
|
|
+
|
|
+ np = of_node_get(dev->of_node);
|
|
+ if (!np)
|
|
+ return -EINVAL;
|
|
+ ret = of_property_read_u32(np, "update_time_ms",
|
|
+ &data->update_time_ms);
|
|
+ if (0 != ret)
|
|
+ {
|
|
+ dev_err(dev, "can not get update_time_ms:%d\n", ret);
|
|
+ data->update_time_ms = 100;
|
|
+ }
|
|
+
|
|
+ ret = of_property_read_u32(np, "energy_acc_count",
|
|
+ &data->energy_acc_count);
|
|
+ if (0 != ret)
|
|
+ {
|
|
+ dev_err(dev, "can not get energy_acc_count:%d\n", ret);
|
|
+ data->energy_acc_count = 0;
|
|
+ }
|
|
+ ret = of_property_read_u32_array(np, "shunt_resistors",
|
|
+ data->shunt_resistors,
|
|
+ PAC193X_MAX_CHAN_CNT);
|
|
+ if (0 != ret)
|
|
+ {
|
|
+ dev_err(dev, "can not get shunt_resistors:%d\n", ret);
|
|
+ }
|
|
+
|
|
+ dev_info(dev,
|
|
+ "update_time:%d,energy_acc_count:%d,resistances:%d,%d,%d,%dmOhm\n",
|
|
+ data->update_time_ms, data->energy_acc_count,
|
|
+ data->shunt_resistors[0], data->shunt_resistors[1],
|
|
+ data->shunt_resistors[2], data->shunt_resistors[3]);
|
|
+
|
|
+ np = of_node_get(np);
|
|
+ if (!np)
|
|
+ return -EINVAL;
|
|
+ of_property_read_string_array(np, "eswin,chan_label", output_names, 4);
|
|
+
|
|
+ strcpy(data->pac193x_label[0], output_names[0]);
|
|
+ strcpy(data->pac193x_label[1], output_names[1]);
|
|
+ strcpy(data->pac193x_label[2], output_names[2]);
|
|
+ strcpy(data->pac193x_label[3], output_names[3]);
|
|
+
|
|
+ mutex_init(&data->config_lock);
|
|
+ data->client = client;
|
|
+ mutex_lock(&data->config_lock);
|
|
+ i2c_smbus_write_byte_data(data->client, PAC193X_CMD_CTRL, 0x8);
|
|
+ mutex_unlock(&data->config_lock);
|
|
+ pac193x_send_refresh_cmd(data, PAC193X_CMD_REFRESH);
|
|
+
|
|
+ hwmon_dev = devm_hwmon_device_register_with_info(
|
|
+ dev, client->name, data, &pac193x_chip_info, pac193x_groups);
|
|
+ if (IS_ERR(hwmon_dev))
|
|
+ return PTR_ERR(hwmon_dev);
|
|
+
|
|
+ data->update_workqueue = create_workqueue("update_workqueue");
|
|
+
|
|
+ INIT_DELAYED_WORK(&data->update_work, update_reg_data);
|
|
+ queue_delayed_work(data->update_workqueue, &data->update_work,
|
|
+ msecs_to_jiffies(0));
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static const struct of_device_id __maybe_unused pac193x_of_match[] = {
|
|
+ {.compatible = "microchip,pac1931", .data = (void *)pac1931_index},
|
|
+ {.compatible = "microchip,pac1932", .data = (void *)pac1932_index},
|
|
+ {.compatible = "microchip,pac1933", .data = (void *)pac1933_index},
|
|
+ {.compatible = "microchip,pac1934", .data = (void *)pac1934_index},
|
|
+ {},
|
|
+};
|
|
+MODULE_DEVICE_TABLE(of, pac193x_of_match);
|
|
+
|
|
+static struct i2c_driver pac193x_driver = {
|
|
+ .driver = {
|
|
+ .name = "pac193x",
|
|
+ .of_match_table = of_match_ptr(pac193x_of_match),
|
|
+ },
|
|
+ .probe = pac193x_probe,
|
|
+};
|
|
+
|
|
+module_i2c_driver(pac193x_driver);
|
|
+
|
|
+MODULE_AUTHOR("Yang Wei <yangwei1@eswincomputing.com");
|
|
+MODULE_DESCRIPTION("pac193x driver");
|
|
+MODULE_LICENSE("GPL");
|
|
\ No newline at end of file
|
|
--
|
|
2.47.0
|
|
|