Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

hwmon: Driver for Linear Technologies LTC4260

LTC4260 is a Positive Voltage Hot Swap Controller.
The driver currently only supports voltage monitoring, not voltage control.

Signed-off-by: Guenter Roeck <linux@roeck-us.net>

+269
+56
Documentation/hwmon/ltc4260
··· 1 + Kernel driver ltc4260 2 + ===================== 3 + 4 + Supported chips: 5 + * Linear Technology LTC4260 6 + Prefix: 'ltc4260' 7 + Addresses scanned: - 8 + Datasheet: 9 + http://cds.linear.com/docs/en/datasheet/4260fc.pdf 10 + 11 + Author: Guenter Roeck <linux@roeck-us.net> 12 + 13 + 14 + Description 15 + ----------- 16 + 17 + The LTC4260 Hot Swap controller allows a board to be safely inserted 18 + and removed from a live backplane. 19 + 20 + 21 + Usage Notes 22 + ----------- 23 + 24 + This driver does not probe for LTC4260 devices, since there is no register 25 + which can be safely used to identify the chip. You will have to instantiate 26 + the devices explicitly. 27 + 28 + Example: the following will load the driver for an LTC4260 at address 0x10 29 + on I2C bus #1: 30 + $ modprobe ltc4260 31 + $ echo ltc4260 0x10 > /sys/bus/i2c/devices/i2c-1/new_device 32 + 33 + 34 + Sysfs entries 35 + ------------- 36 + 37 + Voltage readings provided by this driver are reported as obtained from the ADC 38 + registers. If a set of voltage divider resistors is installed, calculate the 39 + real voltage by multiplying the reported value with (R1+R2)/R2, where R1 is the 40 + value of the divider resistor against the measured voltage and R2 is the value 41 + of the divider resistor against Ground. 42 + 43 + Current reading provided by this driver is reported as obtained from the ADC 44 + Current Sense register. The reported value assumes that a 1 mOhm sense resistor 45 + is installed. If a different sense resistor is installed, calculate the real 46 + current by dividing the reported value by the sense resistor value in mOhm. 47 + 48 + in1_input SOURCE voltage (mV) 49 + in1_min_alarm Undervoltage alarm 50 + in1_max_alarm Overvoltage alarm 51 + 52 + in2_input ADIN voltage (mV) 53 + in2_alarm Power bad alarm 54 + 55 + curr1_input SENSE current (mA) 56 + curr1_alarm SENSE overcurrent alarm
+12
drivers/hwmon/Kconfig
··· 821 821 This driver can also be built as a module. If so, the module will 822 822 be called ltc4245. 823 823 824 + config SENSORS_LTC4260 825 + tristate "Linear Technology LTC4260" 826 + depends on I2C 827 + select REGMAP_I2C 828 + default n 829 + help 830 + If you say yes here you get support for Linear Technology LTC4261 831 + Positive Voltage Hot Swap Controller I2C interface. 832 + 833 + This driver can also be built as a module. If so, the module will 834 + be called ltc4260. 835 + 824 836 config SENSORS_LTC4261 825 837 tristate "Linear Technology LTC4261" 826 838 depends on I2C
+1
drivers/hwmon/Makefile
··· 99 99 obj-$(CONFIG_SENSORS_LTC4215) += ltc4215.o 100 100 obj-$(CONFIG_SENSORS_LTC4222) += ltc4222.o 101 101 obj-$(CONFIG_SENSORS_LTC4245) += ltc4245.o 102 + obj-$(CONFIG_SENSORS_LTC4260) += ltc4260.o 102 103 obj-$(CONFIG_SENSORS_LTC4261) += ltc4261.o 103 104 obj-$(CONFIG_SENSORS_MAX1111) += max1111.o 104 105 obj-$(CONFIG_SENSORS_MAX16065) += max16065.o
+200
drivers/hwmon/ltc4260.c
··· 1 + /* 2 + * Driver for Linear Technology LTC4260 I2C Positive Voltage Hot Swap Controller 3 + * 4 + * Copyright (c) 2014 Guenter Roeck 5 + * 6 + * This program is free software; you can redistribute it and/or modify 7 + * it under the terms of the GNU General Public License as published by 8 + * the Free Software Foundation; either version 2 of the License, or 9 + * (at your option) any later version. 10 + * 11 + * This program is distributed in the hope that it will be useful, 12 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 + * GNU General Public License for more details. 15 + */ 16 + 17 + #include <linux/kernel.h> 18 + #include <linux/module.h> 19 + #include <linux/err.h> 20 + #include <linux/slab.h> 21 + #include <linux/i2c.h> 22 + #include <linux/hwmon.h> 23 + #include <linux/hwmon-sysfs.h> 24 + #include <linux/jiffies.h> 25 + #include <linux/regmap.h> 26 + 27 + /* chip registers */ 28 + #define LTC4260_CONTROL 0x00 29 + #define LTC4260_ALERT 0x01 30 + #define LTC4260_STATUS 0x02 31 + #define LTC4260_FAULT 0x03 32 + #define LTC4260_SENSE 0x04 33 + #define LTC4260_SOURCE 0x05 34 + #define LTC4260_ADIN 0x06 35 + 36 + /* 37 + * Fault register bits 38 + */ 39 + #define FAULT_OV (1 << 0) 40 + #define FAULT_UV (1 << 1) 41 + #define FAULT_OC (1 << 2) 42 + #define FAULT_POWER_BAD (1 << 3) 43 + #define FAULT_FET_SHORT (1 << 5) 44 + 45 + /* Return the voltage from the given register in mV or mA */ 46 + static int ltc4260_get_value(struct device *dev, u8 reg) 47 + { 48 + struct regmap *regmap = dev_get_drvdata(dev); 49 + unsigned int val; 50 + int ret; 51 + 52 + ret = regmap_read(regmap, reg, &val); 53 + if (ret < 0) 54 + return ret; 55 + 56 + switch (reg) { 57 + case LTC4260_ADIN: 58 + /* 10 mV resolution. Convert to mV. */ 59 + val = val * 10; 60 + break; 61 + case LTC4260_SOURCE: 62 + /* 400 mV resolution. Convert to mV. */ 63 + val = val * 400; 64 + break; 65 + case LTC4260_SENSE: 66 + /* 67 + * 300 uV resolution. Convert to current as measured with 68 + * an 1 mOhm sense resistor, in mA. If a different sense 69 + * resistor is installed, calculate the actual current by 70 + * dividing the reported current by the sense resistor value 71 + * in mOhm. 72 + */ 73 + val = val * 300; 74 + break; 75 + default: 76 + return -EINVAL; 77 + } 78 + 79 + return val; 80 + } 81 + 82 + static ssize_t ltc4260_show_value(struct device *dev, 83 + struct device_attribute *da, char *buf) 84 + { 85 + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); 86 + int value; 87 + 88 + value = ltc4260_get_value(dev, attr->index); 89 + if (value < 0) 90 + return value; 91 + return snprintf(buf, PAGE_SIZE, "%d\n", value); 92 + } 93 + 94 + static ssize_t ltc4260_show_bool(struct device *dev, 95 + struct device_attribute *da, char *buf) 96 + { 97 + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); 98 + struct regmap *regmap = dev_get_drvdata(dev); 99 + unsigned int fault; 100 + int ret; 101 + 102 + ret = regmap_read(regmap, LTC4260_FAULT, &fault); 103 + if (ret < 0) 104 + return ret; 105 + 106 + fault &= attr->index; 107 + if (fault) /* Clear reported faults in chip register */ 108 + regmap_update_bits(regmap, LTC4260_FAULT, attr->index, 0); 109 + 110 + return snprintf(buf, PAGE_SIZE, "%d\n", !!fault); 111 + } 112 + 113 + /* Voltages */ 114 + static SENSOR_DEVICE_ATTR(in1_input, S_IRUGO, ltc4260_show_value, NULL, 115 + LTC4260_SOURCE); 116 + static SENSOR_DEVICE_ATTR(in2_input, S_IRUGO, ltc4260_show_value, NULL, 117 + LTC4260_ADIN); 118 + 119 + /* 120 + * Voltage alarms 121 + * UV/OV faults are associated with the input voltage, and the POWER BAD and 122 + * FET SHORT faults are associated with the output voltage. 123 + */ 124 + static SENSOR_DEVICE_ATTR(in1_min_alarm, S_IRUGO, ltc4260_show_bool, NULL, 125 + FAULT_UV); 126 + static SENSOR_DEVICE_ATTR(in1_max_alarm, S_IRUGO, ltc4260_show_bool, NULL, 127 + FAULT_OV); 128 + static SENSOR_DEVICE_ATTR(in2_alarm, S_IRUGO, ltc4260_show_bool, NULL, 129 + FAULT_POWER_BAD | FAULT_FET_SHORT); 130 + 131 + /* Current (via sense resistor) */ 132 + static SENSOR_DEVICE_ATTR(curr1_input, S_IRUGO, ltc4260_show_value, NULL, 133 + LTC4260_SENSE); 134 + 135 + /* Overcurrent alarm */ 136 + static SENSOR_DEVICE_ATTR(curr1_max_alarm, S_IRUGO, ltc4260_show_bool, NULL, 137 + FAULT_OC); 138 + 139 + static struct attribute *ltc4260_attrs[] = { 140 + &sensor_dev_attr_in1_input.dev_attr.attr, 141 + &sensor_dev_attr_in1_min_alarm.dev_attr.attr, 142 + &sensor_dev_attr_in1_max_alarm.dev_attr.attr, 143 + &sensor_dev_attr_in2_input.dev_attr.attr, 144 + &sensor_dev_attr_in2_alarm.dev_attr.attr, 145 + 146 + &sensor_dev_attr_curr1_input.dev_attr.attr, 147 + &sensor_dev_attr_curr1_max_alarm.dev_attr.attr, 148 + 149 + NULL, 150 + }; 151 + ATTRIBUTE_GROUPS(ltc4260); 152 + 153 + static struct regmap_config ltc4260_regmap_config = { 154 + .reg_bits = 8, 155 + .val_bits = 8, 156 + .max_register = LTC4260_ADIN, 157 + }; 158 + 159 + static int ltc4260_probe(struct i2c_client *client, 160 + const struct i2c_device_id *id) 161 + { 162 + struct device *dev = &client->dev; 163 + struct device *hwmon_dev; 164 + struct regmap *regmap; 165 + 166 + regmap = devm_regmap_init_i2c(client, &ltc4260_regmap_config); 167 + if (IS_ERR(regmap)) { 168 + dev_err(dev, "failed to allocate register map\n"); 169 + return PTR_ERR(regmap); 170 + } 171 + 172 + /* Clear faults */ 173 + regmap_write(regmap, LTC4260_FAULT, 0x00); 174 + 175 + hwmon_dev = devm_hwmon_device_register_with_groups(dev, client->name, 176 + regmap, 177 + ltc4260_groups); 178 + return PTR_ERR_OR_ZERO(hwmon_dev); 179 + } 180 + 181 + static const struct i2c_device_id ltc4260_id[] = { 182 + {"ltc4260", 0}, 183 + { } 184 + }; 185 + 186 + MODULE_DEVICE_TABLE(i2c, ltc4260_id); 187 + 188 + static struct i2c_driver ltc4260_driver = { 189 + .driver = { 190 + .name = "ltc4260", 191 + }, 192 + .probe = ltc4260_probe, 193 + .id_table = ltc4260_id, 194 + }; 195 + 196 + module_i2c_driver(ltc4260_driver); 197 + 198 + MODULE_AUTHOR("Guenter Roeck <linux@roeck-us.net>"); 199 + MODULE_DESCRIPTION("LTC4260 driver"); 200 + MODULE_LICENSE("GPL");