cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

ltc4151.c (5032B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/*
      3 * Driver for Linear Technology LTC4151 High Voltage I2C Current
      4 * and Voltage Monitor
      5 *
      6 * Copyright (C) 2011 AppearTV AS
      7 *
      8 * Derived from:
      9 *
     10 *  Driver for Linear Technology LTC4261 I2C Negative Voltage Hot
     11 *  Swap Controller
     12 *  Copyright (C) 2010 Ericsson AB.
     13 *
     14 * Datasheet: http://www.linear.com/docs/Datasheet/4151fc.pdf
     15 */
     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	0x00
     30#define LTC4151_SENSE_L	0x01
     31#define LTC4151_VIN_H	0x02
     32#define LTC4151_VIN_L	0x03
     33#define LTC4151_ADIN_H	0x04
     34#define LTC4151_ADIN_L	0x05
     35
     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 second
     58	 * (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 with
    102		 * 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", 0 },
    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_new	= 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");