brintos

brintos / linux-shallow public Read only

0
0
Text · 4.9 KiB · fa66eda Raw
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