]> git.karo-electronics.de Git - linux-beck.git/commitdiff
hwmon: (pmbus) Add client driver for LTC3815
authorGuenter Roeck <linux@roeck-us.net>
Sat, 22 Aug 2015 07:49:37 +0000 (00:49 -0700)
committerGuenter Roeck <linux@roeck-us.net>
Fri, 18 Dec 2015 16:20:59 +0000 (08:20 -0800)
LTC3815 is a Monolithic Synchronous DC/DC Step-Down Converter.

Cc: Michael Jones <mike@proclivis.com>
Signed-off-by: Guenter Roeck <linux@roeck-us.net>
Documentation/hwmon/ltc3815 [new file with mode: 0644]
drivers/hwmon/pmbus/Kconfig
drivers/hwmon/pmbus/Makefile
drivers/hwmon/pmbus/ltc3815.c [new file with mode: 0644]

diff --git a/Documentation/hwmon/ltc3815 b/Documentation/hwmon/ltc3815
new file mode 100644 (file)
index 0000000..eb7db2d
--- /dev/null
@@ -0,0 +1,61 @@
+Kernel driver ltc3815
+=====================
+
+Supported chips:
+  * Linear Technology LTC3815
+    Prefix: 'ltc3815'
+    Addresses scanned: -
+    Datasheet: http://www.linear.com/product/ltc3815
+
+Author: Guenter Roeck <linux@roeck-us.net>
+
+
+Description
+-----------
+
+LTC3815 is a Monolithic Synchronous DC/DC Step-Down Converter.
+
+
+Usage Notes
+-----------
+
+This driver does not probe for PMBus devices. You will have to instantiate
+devices explicitly.
+
+Example: the following commands will load the driver for an LTC3815
+at address 0x20 on I2C bus #1:
+
+# modprobe ltc3815
+# echo ltc3815 0x20 > /sys/bus/i2c/devices/i2c-1/new_device
+
+
+Sysfs attributes
+----------------
+
+in1_label              "vin"
+in1_input              Measured input voltage.
+in1_alarm              Input voltage alarm.
+in1_highest            Highest input voltage.
+in1_reset_history      Reset input voltage history.
+
+in2_label              "vout1".
+in2_input              Measured output voltage.
+in2_alarm              Output voltage alarm.
+in2_highest            Highest output voltage.
+in2_reset_history      Reset output voltage history.
+
+temp1_input            Measured chip temperature.
+temp1_alarm            Temperature alarm.
+temp1_highest          Highest measured temperature.
+temp1_reset_history    Reset temperature history.
+
+curr1_label            "iin".
+curr1_input            Measured input current.
+curr1_highest          Highest input current.
+curr1_reset_history    Reset input current history.
+
+curr2_label            "iout1".
+curr2_input            Measured output current.
+curr2_alarm            Output current alarm.
+curr2_highest          Highest output current.
+curr2_reset_history    Reset output current history.
index df6ebb2b8f0f94e3eb82ccdb6b380674f50d3b20..7e5cc3d025efece94357d369837d4806551e3d83 100644 (file)
@@ -65,6 +65,16 @@ config SENSORS_LTC2978_REGULATOR
          If you say yes here you get regulator support for Linear
          Technology LTC2974, LTC2977, LTC2978, LTC3880, LTC3883, and LTM4676.
 
+config SENSORS_LTC3815
+       tristate "Linear Technologies LTC3815"
+       default n
+       help
+         If you say yes here you get hardware monitoring support for Linear
+         Technology LTC3815.
+
+         This driver can also be built as a module. If so, the module will
+         be called ltc3815.
+
 config SENSORS_MAX16064
        tristate "Maxim MAX16064"
        default n
index bce046d37f0264eff48a44010ceb1cd8994f65d1..562132054aafe9e7d5154ab582ec6080f84a19a2 100644 (file)
@@ -7,6 +7,7 @@ obj-$(CONFIG_SENSORS_PMBUS)     += pmbus.o
 obj-$(CONFIG_SENSORS_ADM1275)  += adm1275.o
 obj-$(CONFIG_SENSORS_LM25066)  += lm25066.o
 obj-$(CONFIG_SENSORS_LTC2978)  += ltc2978.o
+obj-$(CONFIG_SENSORS_LTC3815)  += ltc3815.o
 obj-$(CONFIG_SENSORS_MAX16064) += max16064.o
 obj-$(CONFIG_SENSORS_MAX20751) += max20751.o
 obj-$(CONFIG_SENSORS_MAX34440) += max34440.o
diff --git a/drivers/hwmon/pmbus/ltc3815.c b/drivers/hwmon/pmbus/ltc3815.c
new file mode 100644 (file)
index 0000000..bb32e62
--- /dev/null
@@ -0,0 +1,215 @@
+/*
+ * Hardware monitoring driver for LTC3815
+ *
+ * Copyright (c) 2015 Linear Technology
+ * Copyright (c) 2015 Guenter Roeck
+ *
+ * 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; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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.
+ */
+
+#include <linux/err.h>
+#include <linux/i2c.h>
+#include <linux/init.h>
+#include <linux/jiffies.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include "pmbus.h"
+
+#define LTC3815_MFR_IOUT_PEAK  0xd7
+#define LTC3815_MFR_VOUT_PEAK  0xdd
+#define LTC3815_MFR_VIN_PEAK   0xde
+#define LTC3815_MFR_TEMP_PEAK  0xdf
+#define LTC3815_MFR_IIN_PEAK   0xe1
+#define LTC3815_MFR_SPECIAL_ID 0xe7
+
+#define LTC3815_ID             0x8000
+#define LTC3815_ID_MASK                0xff00
+
+static int ltc3815_read_byte_data(struct i2c_client *client, int page, int reg)
+{
+       int ret;
+
+       switch (reg) {
+       case PMBUS_VOUT_MODE:
+               /*
+                * The chip returns 0x3e, suggesting VID mode with manufacturer
+                * specific VID codes. Since the output voltage is reported
+                * with a LSB of 0.5mV, override and report direct mode with
+                * appropriate coefficients.
+                */
+               ret = 0x40;
+               break;
+       default:
+               ret = -ENODATA;
+               break;
+       }
+       return ret;
+}
+
+static int ltc3815_write_byte(struct i2c_client *client, int page, u8 reg)
+{
+       int ret;
+
+       switch (reg) {
+       case PMBUS_CLEAR_FAULTS:
+               /*
+                * LTC3815 does not support the CLEAR_FAULTS command.
+                * Emulate it by clearing the status register.
+                */
+               ret = pmbus_read_word_data(client, 0, PMBUS_STATUS_WORD);
+               if (ret > 0) {
+                       pmbus_write_word_data(client, 0, PMBUS_STATUS_WORD,
+                                             ret);
+                       ret = 0;
+               }
+               break;
+       default:
+               ret = -ENODATA;
+               break;
+       }
+       return ret;
+}
+
+static int ltc3815_read_word_data(struct i2c_client *client, int page, int reg)
+{
+       int ret;
+
+       switch (reg) {
+       case PMBUS_VIRT_READ_VIN_MAX:
+               ret = pmbus_read_word_data(client, page, LTC3815_MFR_VIN_PEAK);
+               break;
+       case PMBUS_VIRT_READ_VOUT_MAX:
+               ret = pmbus_read_word_data(client, page, LTC3815_MFR_VOUT_PEAK);
+               break;
+       case PMBUS_VIRT_READ_TEMP_MAX:
+               ret = pmbus_read_word_data(client, page, LTC3815_MFR_TEMP_PEAK);
+               break;
+       case PMBUS_VIRT_READ_IOUT_MAX:
+               ret = pmbus_read_word_data(client, page, LTC3815_MFR_IOUT_PEAK);
+               break;
+       case PMBUS_VIRT_READ_IIN_MAX:
+               ret = pmbus_read_word_data(client, page, LTC3815_MFR_IIN_PEAK);
+               break;
+       case PMBUS_VIRT_RESET_VOUT_HISTORY:
+       case PMBUS_VIRT_RESET_VIN_HISTORY:
+       case PMBUS_VIRT_RESET_TEMP_HISTORY:
+       case PMBUS_VIRT_RESET_IOUT_HISTORY:
+       case PMBUS_VIRT_RESET_IIN_HISTORY:
+               ret = 0;
+               break;
+       default:
+               ret = -ENODATA;
+               break;
+       }
+       return ret;
+}
+
+static int ltc3815_write_word_data(struct i2c_client *client, int page,
+                                  int reg, u16 word)
+{
+       int ret;
+
+       switch (reg) {
+       case PMBUS_VIRT_RESET_IIN_HISTORY:
+               ret = pmbus_write_word_data(client, page,
+                                           LTC3815_MFR_IIN_PEAK, 0);
+               break;
+       case PMBUS_VIRT_RESET_IOUT_HISTORY:
+               ret = pmbus_write_word_data(client, page,
+                                           LTC3815_MFR_IOUT_PEAK, 0);
+               break;
+       case PMBUS_VIRT_RESET_VOUT_HISTORY:
+               ret = pmbus_write_word_data(client, page,
+                                           LTC3815_MFR_VOUT_PEAK, 0);
+               break;
+       case PMBUS_VIRT_RESET_VIN_HISTORY:
+               ret = pmbus_write_word_data(client, page,
+                                           LTC3815_MFR_VIN_PEAK, 0);
+               break;
+       case PMBUS_VIRT_RESET_TEMP_HISTORY:
+               ret = pmbus_write_word_data(client, page,
+                                           LTC3815_MFR_TEMP_PEAK, 0);
+               break;
+       default:
+               ret = -ENODATA;
+               break;
+       }
+       return ret;
+}
+
+static const struct i2c_device_id ltc3815_id[] = {
+       {"ltc3815", 0},
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, ltc3815_id);
+
+static struct pmbus_driver_info ltc3815_info = {
+       .pages = 1,
+       .format[PSC_VOLTAGE_IN] = direct,
+       .format[PSC_VOLTAGE_OUT] = direct,
+       .format[PSC_CURRENT_IN] = direct,
+       .format[PSC_CURRENT_OUT] = direct,
+       .format[PSC_TEMPERATURE] = direct,
+       .m[PSC_VOLTAGE_IN] = 250,
+       .b[PSC_VOLTAGE_IN] = 0,
+       .R[PSC_VOLTAGE_IN] = 0,
+       .m[PSC_VOLTAGE_OUT] = 2,
+       .b[PSC_VOLTAGE_OUT] = 0,
+       .R[PSC_VOLTAGE_OUT] = 3,
+       .m[PSC_CURRENT_IN] = 1,
+       .b[PSC_CURRENT_IN] = 0,
+       .R[PSC_CURRENT_IN] = 2,
+       .m[PSC_CURRENT_OUT] = 1,
+       .b[PSC_CURRENT_OUT] = 0,
+       .R[PSC_CURRENT_OUT] = 2,
+       .m[PSC_TEMPERATURE] = 1,
+       .b[PSC_TEMPERATURE] = 0,
+       .R[PSC_TEMPERATURE] = 0,
+       .func[0] = PMBUS_HAVE_VIN | PMBUS_HAVE_IIN | PMBUS_HAVE_VOUT |
+               PMBUS_HAVE_IOUT | PMBUS_HAVE_TEMP,
+       .read_byte_data = ltc3815_read_byte_data,
+       .read_word_data = ltc3815_read_word_data,
+       .write_byte = ltc3815_write_byte,
+       .write_word_data = ltc3815_write_word_data,
+};
+
+static int ltc3815_probe(struct i2c_client *client,
+                        const struct i2c_device_id *id)
+{
+       int chip_id;
+
+       if (!i2c_check_functionality(client->adapter,
+                                    I2C_FUNC_SMBUS_READ_WORD_DATA))
+               return -ENODEV;
+
+       chip_id = i2c_smbus_read_word_data(client, LTC3815_MFR_SPECIAL_ID);
+       if (chip_id < 0)
+               return chip_id;
+       if ((chip_id & LTC3815_ID_MASK) != LTC3815_ID)
+               return -ENODEV;
+
+       return pmbus_do_probe(client, id, &ltc3815_info);
+}
+
+static struct i2c_driver ltc3815_driver = {
+       .driver = {
+                  .name = "ltc3815",
+                  },
+       .probe = ltc3815_probe,
+       .remove = pmbus_do_remove,
+       .id_table = ltc3815_id,
+};
+
+module_i2c_driver(ltc3815_driver);
+
+MODULE_AUTHOR("Guenter Roeck");
+MODULE_DESCRIPTION("PMBus driver for LTC3815");
+MODULE_LICENSE("GPL");