Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  * Driver for Linear Technology LTC4260 I2C Positive Voltage Hot Swap Controller
0004  *
0005  * Copyright (c) 2014 Guenter Roeck
0006  */
0007 
0008 #include <linux/kernel.h>
0009 #include <linux/module.h>
0010 #include <linux/err.h>
0011 #include <linux/slab.h>
0012 #include <linux/i2c.h>
0013 #include <linux/hwmon.h>
0014 #include <linux/hwmon-sysfs.h>
0015 #include <linux/jiffies.h>
0016 #include <linux/regmap.h>
0017 
0018 /* chip registers */
0019 #define LTC4260_CONTROL 0x00
0020 #define LTC4260_ALERT   0x01
0021 #define LTC4260_STATUS  0x02
0022 #define LTC4260_FAULT   0x03
0023 #define LTC4260_SENSE   0x04
0024 #define LTC4260_SOURCE  0x05
0025 #define LTC4260_ADIN    0x06
0026 
0027 /*
0028  * Fault register bits
0029  */
0030 #define FAULT_OV    (1 << 0)
0031 #define FAULT_UV    (1 << 1)
0032 #define FAULT_OC    (1 << 2)
0033 #define FAULT_POWER_BAD (1 << 3)
0034 #define FAULT_FET_SHORT (1 << 5)
0035 
0036 /* Return the voltage from the given register in mV or mA */
0037 static int ltc4260_get_value(struct device *dev, u8 reg)
0038 {
0039     struct regmap *regmap = dev_get_drvdata(dev);
0040     unsigned int val;
0041     int ret;
0042 
0043     ret = regmap_read(regmap, reg, &val);
0044     if (ret < 0)
0045         return ret;
0046 
0047     switch (reg) {
0048     case LTC4260_ADIN:
0049         /* 10 mV resolution. Convert to mV. */
0050         val = val * 10;
0051         break;
0052     case LTC4260_SOURCE:
0053         /* 400 mV resolution. Convert to mV. */
0054         val = val * 400;
0055         break;
0056     case LTC4260_SENSE:
0057         /*
0058          * 300 uV resolution. Convert to current as measured with
0059          * an 1 mOhm sense resistor, in mA. If a different sense
0060          * resistor is installed, calculate the actual current by
0061          * dividing the reported current by the sense resistor value
0062          * in mOhm.
0063          */
0064         val = val * 300;
0065         break;
0066     default:
0067         return -EINVAL;
0068     }
0069 
0070     return val;
0071 }
0072 
0073 static ssize_t ltc4260_value_show(struct device *dev,
0074                   struct device_attribute *da, char *buf)
0075 {
0076     struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
0077     int value;
0078 
0079     value = ltc4260_get_value(dev, attr->index);
0080     if (value < 0)
0081         return value;
0082     return sysfs_emit(buf, "%d\n", value);
0083 }
0084 
0085 static ssize_t ltc4260_bool_show(struct device *dev,
0086                  struct device_attribute *da, char *buf)
0087 {
0088     struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
0089     struct regmap *regmap = dev_get_drvdata(dev);
0090     unsigned int fault;
0091     int ret;
0092 
0093     ret = regmap_read(regmap, LTC4260_FAULT, &fault);
0094     if (ret < 0)
0095         return ret;
0096 
0097     fault &= attr->index;
0098     if (fault)      /* Clear reported faults in chip register */
0099         regmap_update_bits(regmap, LTC4260_FAULT, attr->index, 0);
0100 
0101     return sysfs_emit(buf, "%d\n", !!fault);
0102 }
0103 
0104 /* Voltages */
0105 static SENSOR_DEVICE_ATTR_RO(in1_input, ltc4260_value, LTC4260_SOURCE);
0106 static SENSOR_DEVICE_ATTR_RO(in2_input, ltc4260_value, LTC4260_ADIN);
0107 
0108 /*
0109  * Voltage alarms
0110  * UV/OV faults are associated with the input voltage, and the POWER BAD and
0111  * FET SHORT faults are associated with the output voltage.
0112  */
0113 static SENSOR_DEVICE_ATTR_RO(in1_min_alarm, ltc4260_bool, FAULT_UV);
0114 static SENSOR_DEVICE_ATTR_RO(in1_max_alarm, ltc4260_bool, FAULT_OV);
0115 static SENSOR_DEVICE_ATTR_RO(in2_alarm, ltc4260_bool,
0116                  FAULT_POWER_BAD | FAULT_FET_SHORT);
0117 
0118 /* Current (via sense resistor) */
0119 static SENSOR_DEVICE_ATTR_RO(curr1_input, ltc4260_value, LTC4260_SENSE);
0120 
0121 /* Overcurrent alarm */
0122 static SENSOR_DEVICE_ATTR_RO(curr1_max_alarm, ltc4260_bool, FAULT_OC);
0123 
0124 static struct attribute *ltc4260_attrs[] = {
0125     &sensor_dev_attr_in1_input.dev_attr.attr,
0126     &sensor_dev_attr_in1_min_alarm.dev_attr.attr,
0127     &sensor_dev_attr_in1_max_alarm.dev_attr.attr,
0128     &sensor_dev_attr_in2_input.dev_attr.attr,
0129     &sensor_dev_attr_in2_alarm.dev_attr.attr,
0130 
0131     &sensor_dev_attr_curr1_input.dev_attr.attr,
0132     &sensor_dev_attr_curr1_max_alarm.dev_attr.attr,
0133 
0134     NULL,
0135 };
0136 ATTRIBUTE_GROUPS(ltc4260);
0137 
0138 static const struct regmap_config ltc4260_regmap_config = {
0139     .reg_bits = 8,
0140     .val_bits = 8,
0141     .max_register = LTC4260_ADIN,
0142 };
0143 
0144 static int ltc4260_probe(struct i2c_client *client)
0145 {
0146     struct device *dev = &client->dev;
0147     struct device *hwmon_dev;
0148     struct regmap *regmap;
0149 
0150     regmap = devm_regmap_init_i2c(client, &ltc4260_regmap_config);
0151     if (IS_ERR(regmap)) {
0152         dev_err(dev, "failed to allocate register map\n");
0153         return PTR_ERR(regmap);
0154     }
0155 
0156     /* Clear faults */
0157     regmap_write(regmap, LTC4260_FAULT, 0x00);
0158 
0159     hwmon_dev = devm_hwmon_device_register_with_groups(dev, client->name,
0160                                regmap,
0161                                ltc4260_groups);
0162     return PTR_ERR_OR_ZERO(hwmon_dev);
0163 }
0164 
0165 static const struct i2c_device_id ltc4260_id[] = {
0166     {"ltc4260", 0},
0167     { }
0168 };
0169 
0170 MODULE_DEVICE_TABLE(i2c, ltc4260_id);
0171 
0172 static struct i2c_driver ltc4260_driver = {
0173     .driver = {
0174            .name = "ltc4260",
0175            },
0176     .probe_new = ltc4260_probe,
0177     .id_table = ltc4260_id,
0178 };
0179 
0180 module_i2c_driver(ltc4260_driver);
0181 
0182 MODULE_AUTHOR("Guenter Roeck <linux@roeck-us.net>");
0183 MODULE_DESCRIPTION("LTC4260 driver");
0184 MODULE_LICENSE("GPL");