[PATCH] hwmon: max34409 driver added

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



diff --git a/Documentation/hwmon/max34409.rst b/Documentation/hwmon/max34409.rst
new file mode 100644
index 000000000000..91779c6a9163
--- /dev/null
+++ b/Documentation/hwmon/max34409.rst
@@ -0,0 +1,23 @@
+Kernel driver max34409
+=====================
+
+Supported chips:
+  * Analog Devices MAX34409
+    Prefix: 'max34409'
+    Datasheet: https://www.analog.com/media/en/technical-documentation/data-sheets/MAX34408-MAX34409.pdf
+
+Author: Andrey Kononov <a.kononov@xxxxxxxxxx>
+
+
+Description
+-----------
+
+This driver for SMBus Dual/Quad Current Monitor MaximIntegrated MAX34409
+
+
+Usage Notes
+-----------
+
+This driver does not auto-detect devices. You will have to instantiate the
+devices explicitly. Please see Documentation/i2c/instantiating-devices.rst
+for details.
diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig
index 3176c33af6c6..de412f7dcad8 100644
--- a/drivers/hwmon/Kconfig
+++ b/drivers/hwmon/Kconfig
@@ -1088,6 +1088,13 @@ config SENSORS_MAX31760
 	  This driver can also be built as a module. If so, the module
 	  will be called max31760.
 
+config SENSORS_MAX3440X
+	tristate "Maxim max3440x SMBus Dual/Quad Current Monitor"
+	depends on I2C
+	help
+	  Say yes here to build support for Maxim family of SMBus Dual/Quad Current Monitors.
+	  This driver is mutually exclusive with the HWMON version.
+
 config SENSORS_MAX6620
 	tristate "Maxim MAX6620 fan controller"
 	depends on I2C
diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile
index e2e4e87b282f..a4e24d2b03c1 100644
--- a/drivers/hwmon/Makefile
+++ b/drivers/hwmon/Makefile
@@ -141,6 +141,7 @@ obj-$(CONFIG_SENSORS_MAX197)	+= max197.o
 obj-$(CONFIG_SENSORS_MAX31722)	+= max31722.o
 obj-$(CONFIG_SENSORS_MAX31730)	+= max31730.o
 obj-$(CONFIG_SENSORS_MAX31760)  += max31760.o
+obj-$(CONFIG_SENSORS_MAX3440X)  += max3440x.o
 obj-$(CONFIG_SENSORS_MAX6620)	+= max6620.o
 obj-$(CONFIG_SENSORS_MAX6621)	+= max6621.o
 obj-$(CONFIG_SENSORS_MAX6639)	+= max6639.o
diff --git a/drivers/hwmon/max3440x.c b/drivers/hwmon/max3440x.c
new file mode 100644
index 000000000000..b62c34f9425c
--- /dev/null
+++ b/drivers/hwmon/max3440x.c
@@ -0,0 +1,213 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+*
+*/
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/jiffies.h>
+#include <linux/i2c.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/err.h>
+#include <linux/mutex.h>
+#include <linux/sysfs.h>
+
+/*
+ * Registers description.
+ */
+#define MAX3440X_STATUS             0x00
+#define MAX3440X_CONTROL            0x01
+#define MAX3440X_OCDELAY            0x02
+#define MAX3440X_SDDELAY            0x03
+#define MAX3440X_ADC1               0x04	/* readonly */
+#define MAX3440X_ADC2               0x05	/* readonly */
+#define MAX3440X_ADC3               0x06	/* readonly */
+#define MAX3440X_ADC4               0x07	/* readonly */
+#define MAX3440X_OCT1               0x08
+#define MAX3440X_OCT2               0x09
+#define MAX3440X_OCT3               0x0A
+#define MAX3440X_OCT4               0x0B
+#define MAX3440X_DID                0x0C	/* readonly */
+#define MAX3440X_DCYY               0x0D	/* readonly */
+#define MAX3440X_DCWW               0x0E    /* readonly */
+
+//maximal current in mA throw RSENSE, that can be measured. see datasheet table 18
+static unsigned short imax[4];
+module_param_array(imax, short, NULL, 0);
+MODULE_PARM_DESC(imax,
+		 "maximal current in mA throw RSENSE, that can be measured. see datasheet table 18");
+struct max3440x_data {
+	struct i2c_client *client;
+	struct device *hwmon_dev;
+	const char *name;
+
+   struct mutex update_lock;
+   bool valid;
+
+	u16 adc[4];
+	u8 oct[4];
+};
+
+static const char * const input_names[] = {
+	[MAX3440X_ADC1]	=	"curr1",
+	[MAX3440X_ADC2]	=	"curr2",
+	[MAX3440X_ADC3]	=	"curr3",
+	[MAX3440X_ADC4]	=	"curr4",
+};
+
+static void max3440x_init_client(struct max3440x_data *data,
+				struct i2c_client *client)
+{
+	u8 status;
+   u16 val = 0;
+	/*
+	 * Start the conversions.
+	 */
+	status = i2c_smbus_read_byte_data(client, MAX3440X_STATUS);
+
+val = (u16)i2c_smbus_read_byte_data(client, MAX3440X_ADC1);
+	data->adc[0] = DIV_ROUND_CLOSEST((imax[0] * val), 256);
+	val = i2c_smbus_read_byte_data(client, MAX3440X_ADC2);
+	data->adc[1] = DIV_ROUND_CLOSEST((imax[1] * val), 256);
+	val = i2c_smbus_read_byte_data(client, MAX3440X_ADC3);
+	data->adc[2] = DIV_ROUND_CLOSEST((imax[2] * val), 256);
+	val = i2c_smbus_read_byte_data(client, MAX3440X_ADC4);
+	data->adc[3] = DIV_ROUND_CLOSEST((imax[3] * val), 256);
+}
+
+static struct max3440x_data *max3440x_update_device(struct device *dev)
+{
+	struct max3440x_data *data = dev_get_drvdata(dev);
+	struct i2c_client *client = data->client;
+	u16 val;
+
+	mutex_lock(&data->update_lock);
+
+	dev_dbg(dev, "Updating max3440 data.\n");
+	val = (u16)i2c_smbus_read_byte_data(client,
+				MAX3440X_ADC1);
+	data->adc[0] = DIV_ROUND_CLOSEST((imax[0] * val), 256);
+	val =  (u16)i2c_smbus_read_byte_data(client,
+				MAX3440X_ADC2);
+	data->adc[1] = DIV_ROUND_CLOSEST((imax[1] * val), 256);
+	val = (u16)i2c_smbus_read_byte_data(client,
+				MAX3440X_ADC3);
+	data->adc[2] = DIV_ROUND_CLOSEST((imax[2] * val), 256);
+	val = (u16)i2c_smbus_read_byte_data(client,
+				MAX3440X_ADC4);
+	data->adc[3] = DIV_ROUND_CLOSEST((imax[3] * val), 256);
+
+	data->valid = 1;
+	mutex_unlock(&data->update_lock);
+
+	return data;
+}
+static ssize_t adc1_show(struct device *dev,
+			     struct device_attribute *attr, char *buf)
+{
+	struct sensor_device_attribute *attr2 = to_sensor_dev_attr(attr);
+	struct max3440x_data *data = max3440x_update_device(dev);
+
+	return sprintf(buf, "%d\n", data->adc[0]);
+}
+static ssize_t adc2_show(struct device *dev,
+			     struct device_attribute *attr, char *buf)
+{
+	struct sensor_device_attribute *attr2 = to_sensor_dev_attr(attr);
+	struct max3440x_data *data = max3440x_update_device(dev);
+
+	return sprintf(buf, "%d\n", data->adc[1]);
+}
+static ssize_t adc3_show(struct device *dev,
+			     struct device_attribute *attr, char *buf)
+{
+	struct sensor_device_attribute *attr2 = to_sensor_dev_attr(attr);
+	struct max3440x_data *data = max3440x_update_device(dev);
+
+	return sprintf(buf, "%d\n", data->adc[2]);
+}
+static ssize_t adc4_show(struct device *dev,
+			     struct device_attribute *attr, char *buf)
+{
+	struct sensor_device_attribute *attr2 = to_sensor_dev_attr(attr);
+	struct max3440x_data *data = max3440x_update_device(dev);
+
+	return sprintf(buf, "%d\n", data->adc[3]);
+}
+
+static ssize_t label_show(struct device *dev,
+			  struct device_attribute *devattr, char *buf)
+{
+	return sprintf(buf, "%s\n",
+		       input_names[to_sensor_dev_attr(devattr)->index]);
+}
+
+static SENSOR_DEVICE_ATTR_RO(curr1_input, adc1, 0);
+static SENSOR_DEVICE_ATTR_RO(curr1_label, label, MAX3440X_ADC1);
+static SENSOR_DEVICE_ATTR_RO(curr2_input, adc2, 0);
+static SENSOR_DEVICE_ATTR_RO(curr2_label, label, MAX3440X_ADC2);
+static SENSOR_DEVICE_ATTR_RO(curr3_input, adc3, 0);
+static SENSOR_DEVICE_ATTR_RO(curr3_label, label, MAX3440X_ADC3);
+static SENSOR_DEVICE_ATTR_RO(curr4_input, adc4, 0);
+static SENSOR_DEVICE_ATTR_RO(curr4_label, label, MAX3440X_ADC4);
+
+static struct attribute *max3440x_attrs[] = {
+	&sensor_dev_attr_curr1_input.dev_attr.attr,
+	&sensor_dev_attr_curr1_label.dev_attr.attr,
+	&sensor_dev_attr_curr2_input.dev_attr.attr,
+	&sensor_dev_attr_curr2_label.dev_attr.attr,
+	&sensor_dev_attr_curr3_input.dev_attr.attr,
+	&sensor_dev_attr_curr3_label.dev_attr.attr,
+	&sensor_dev_attr_curr4_input.dev_attr.attr,
+	&sensor_dev_attr_curr4_label.dev_attr.attr,
+	NULL
+};
+
+ATTRIBUTE_GROUPS(max3440x);
+
+static int max3440x_probe(struct i2c_client *client,
+			 const struct i2c_device_id *id)
+{
+	struct device *dev = &client->dev;
+	struct max3440x_data *data;
+	struct device *hwmon_dev;
+
+	data = devm_kzalloc(dev, sizeof(struct max3440x_data), GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+
+	data->client = client;
+	mutex_init(&data->update_lock);
+
+	/* Initialize the MAX3440x chip */
+	max3440x_init_client(data, client);
+
+	hwmon_dev = devm_hwmon_device_register_with_groups(&client->dev,
+							   client->name, data,
+							   max3440x_groups);
+	return PTR_ERR_OR_ZERO(hwmon_dev);
+}
+
+
+static const struct i2c_device_id max3440x_id[] = {
+	{ "max34409", 0 },
+	{ }
+};
+
+MODULE_DEVICE_TABLE(i2c, max3440x_id);
+
+static const struct i2c_driver max3440x_driver = {
+	.class = I2C_CLASS_HWMON,
+	.driver = {
+		.name = "max3440x",
+	},
+	.probe = max3440x_probe,
+	.id_table	= max3440x_id,
+};
+
+module_i2c_driver(max3440x_driver);
+
+MODULE_AUTHOR("Andrey Kononov");
+MODULE_DESCRIPTION("I2C adc driver");
+MODULE_LICENSE("GPL");
-- 
2.34.1



[Index of Archives]     [LM Sensors]     [Linux Sound]     [ALSA Users]     [ALSA Devel]     [Linux Audio Users]     [Linux Media]     [Kernel]     [Gimp]     [Yosemite News]     [Linux Media]

  Powered by Linux