217 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3 * Driver for Linear Technology LTC4151 High Voltage I2C Current4 * and Voltage Monitor5 *6 * Copyright (C) 2011 AppearTV AS7 *8 * Derived from:9 *10 * Driver for Linear Technology LTC4261 I2C Negative Voltage Hot11 * Swap Controller12 * Copyright (C) 2010 Ericsson AB.13 *14 * Datasheet: http://www.linear.com/docs/Datasheet/4151fc.pdf15 */16 17#include <linux/kernel.h>18#include <linux/module.h>19#include <linux/of.h>20#include <linux/init.h>21#include <linux/err.h>22#include <linux/slab.h>23#include <linux/i2c.h>24#include <linux/hwmon.h>25#include <linux/hwmon-sysfs.h>26#include <linux/jiffies.h>27 28/* chip registers */29#define LTC4151_SENSE_H 0x0030#define LTC4151_SENSE_L 0x0131#define LTC4151_VIN_H 0x0232#define LTC4151_VIN_L 0x0333#define LTC4151_ADIN_H 0x0434#define LTC4151_ADIN_L 0x0535 36struct ltc4151_data {37 struct i2c_client *client;38 39 struct mutex update_lock;40 bool valid;41 unsigned long last_updated; /* in jiffies */42 unsigned int shunt; /* in micro ohms */43 44 /* Registers */45 u8 regs[6];46};47 48static struct ltc4151_data *ltc4151_update_device(struct device *dev)49{50 struct ltc4151_data *data = dev_get_drvdata(dev);51 struct i2c_client *client = data->client;52 struct ltc4151_data *ret = data;53 54 mutex_lock(&data->update_lock);55 56 /*57 * The chip's A/D updates 6 times per second58 * (Conversion Rate 6 - 9 Hz)59 */60 if (time_after(jiffies, data->last_updated + HZ / 6) || !data->valid) {61 int i;62 63 dev_dbg(&client->dev, "Starting ltc4151 update\n");64 65 /* Read all registers */66 for (i = 0; i < ARRAY_SIZE(data->regs); i++) {67 int val;68 69 val = i2c_smbus_read_byte_data(client, i);70 if (unlikely(val < 0)) {71 dev_dbg(dev,72 "Failed to read ADC value: error %d\n",73 val);74 ret = ERR_PTR(val);75 goto abort;76 }77 data->regs[i] = val;78 }79 data->last_updated = jiffies;80 data->valid = true;81 }82abort:83 mutex_unlock(&data->update_lock);84 return ret;85}86 87/* Return the voltage from the given register in mV */88static int ltc4151_get_value(struct ltc4151_data *data, u8 reg)89{90 u32 val;91 92 val = (data->regs[reg] << 4) + (data->regs[reg + 1] >> 4);93 94 switch (reg) {95 case LTC4151_ADIN_H:96 /* 500uV resolution. Convert to mV. */97 val = val * 500 / 1000;98 break;99 case LTC4151_SENSE_H:100 /*101 * 20uV resolution. Convert to current as measured with102 * a given sense resistor, in mA.103 */104 val = val * 20 * 1000 / data->shunt;105 break;106 case LTC4151_VIN_H:107 /* 25 mV per increment */108 val = val * 25;109 break;110 default:111 /* If we get here, the developer messed up */112 WARN_ON_ONCE(1);113 val = 0;114 break;115 }116 117 return val;118}119 120static ssize_t ltc4151_value_show(struct device *dev,121 struct device_attribute *da, char *buf)122{123 struct sensor_device_attribute *attr = to_sensor_dev_attr(da);124 struct ltc4151_data *data = ltc4151_update_device(dev);125 int value;126 127 if (IS_ERR(data))128 return PTR_ERR(data);129 130 value = ltc4151_get_value(data, attr->index);131 return sysfs_emit(buf, "%d\n", value);132}133 134/*135 * Input voltages.136 */137static SENSOR_DEVICE_ATTR_RO(in1_input, ltc4151_value, LTC4151_VIN_H);138static SENSOR_DEVICE_ATTR_RO(in2_input, ltc4151_value, LTC4151_ADIN_H);139 140/* Currents (via sense resistor) */141static SENSOR_DEVICE_ATTR_RO(curr1_input, ltc4151_value, LTC4151_SENSE_H);142 143/*144 * Finally, construct an array of pointers to members of the above objects,145 * as required for sysfs_create_group()146 */147static struct attribute *ltc4151_attrs[] = {148 &sensor_dev_attr_in1_input.dev_attr.attr,149 &sensor_dev_attr_in2_input.dev_attr.attr,150 151 &sensor_dev_attr_curr1_input.dev_attr.attr,152 153 NULL,154};155ATTRIBUTE_GROUPS(ltc4151);156 157static int ltc4151_probe(struct i2c_client *client)158{159 struct i2c_adapter *adapter = client->adapter;160 struct device *dev = &client->dev;161 struct ltc4151_data *data;162 struct device *hwmon_dev;163 u32 shunt;164 165 if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))166 return -ENODEV;167 168 data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);169 if (!data)170 return -ENOMEM;171 172 if (of_property_read_u32(client->dev.of_node,173 "shunt-resistor-micro-ohms", &shunt))174 shunt = 1000; /* 1 mOhm if not set via DT */175 176 if (shunt == 0)177 return -EINVAL;178 179 data->shunt = shunt;180 181 data->client = client;182 mutex_init(&data->update_lock);183 184 hwmon_dev = devm_hwmon_device_register_with_groups(dev, client->name,185 data,186 ltc4151_groups);187 return PTR_ERR_OR_ZERO(hwmon_dev);188}189 190static const struct i2c_device_id ltc4151_id[] = {191 { "ltc4151" },192 { }193};194MODULE_DEVICE_TABLE(i2c, ltc4151_id);195 196static const struct of_device_id __maybe_unused ltc4151_match[] = {197 { .compatible = "lltc,ltc4151" },198 {},199};200MODULE_DEVICE_TABLE(of, ltc4151_match);201 202/* This is the driver that will be inserted */203static struct i2c_driver ltc4151_driver = {204 .driver = {205 .name = "ltc4151",206 .of_match_table = of_match_ptr(ltc4151_match),207 },208 .probe = ltc4151_probe,209 .id_table = ltc4151_id,210};211 212module_i2c_driver(ltc4151_driver);213 214MODULE_AUTHOR("Per Dalen <per.dalen@appeartv.com>");215MODULE_DESCRIPTION("LTC4151 driver");216MODULE_LICENSE("GPL");217