Blame view

drivers/hwmon/ltc4151.c 4.92 KB
74ba9207e   Thomas Gleixner   treewide: Replace...
1
  // SPDX-License-Identifier: GPL-2.0-or-later
de7790155   per.dalen@appeartv.com   hwmon: Add suppor...
2
3
4
5
6
7
8
9
10
11
12
13
14
  /*
   * Driver for Linear Technology LTC4151 High Voltage I2C Current
   * and Voltage Monitor
   *
   * Copyright (C) 2011 AppearTV AS
   *
   * Derived from:
   *
   *  Driver for Linear Technology LTC4261 I2C Negative Voltage Hot
   *  Swap Controller
   *  Copyright (C) 2010 Ericsson AB.
   *
   * Datasheet: http://www.linear.com/docs/Datasheet/4151fc.pdf
de7790155   per.dalen@appeartv.com   hwmon: Add suppor...
15
16
17
18
   */
  
  #include <linux/kernel.h>
  #include <linux/module.h>
30fe976fe   Daniel Golle   hwmon: (ltc4151) ...
19
  #include <linux/of.h>
de7790155   per.dalen@appeartv.com   hwmon: Add suppor...
20
21
22
23
24
25
  #include <linux/init.h>
  #include <linux/err.h>
  #include <linux/slab.h>
  #include <linux/i2c.h>
  #include <linux/hwmon.h>
  #include <linux/hwmon-sysfs.h>
dcd8f3923   Jean Delvare   hwmon: Add missin...
26
  #include <linux/jiffies.h>
de7790155   per.dalen@appeartv.com   hwmon: Add suppor...
27
28
29
30
31
32
33
34
35
36
  
  /* chip registers */
  #define LTC4151_SENSE_H	0x00
  #define LTC4151_SENSE_L	0x01
  #define LTC4151_VIN_H	0x02
  #define LTC4151_VIN_L	0x03
  #define LTC4151_ADIN_H	0x04
  #define LTC4151_ADIN_L	0x05
  
  struct ltc4151_data {
31e387912   Axel Lin   hwmon: (ltc4151) ...
37
  	struct i2c_client *client;
de7790155   per.dalen@appeartv.com   hwmon: Add suppor...
38
39
40
41
  
  	struct mutex update_lock;
  	bool valid;
  	unsigned long last_updated; /* in jiffies */
30fe976fe   Daniel Golle   hwmon: (ltc4151) ...
42
  	unsigned int shunt; /* in micro ohms */
de7790155   per.dalen@appeartv.com   hwmon: Add suppor...
43
44
45
46
47
48
49
  
  	/* Registers */
  	u8 regs[6];
  };
  
  static struct ltc4151_data *ltc4151_update_device(struct device *dev)
  {
31e387912   Axel Lin   hwmon: (ltc4151) ...
50
51
  	struct ltc4151_data *data = dev_get_drvdata(dev);
  	struct i2c_client *client = data->client;
de7790155   per.dalen@appeartv.com   hwmon: Add suppor...
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
  	struct ltc4151_data *ret = data;
  
  	mutex_lock(&data->update_lock);
  
  	/*
  	 * The chip's A/D updates 6 times per second
  	 * (Conversion Rate 6 - 9 Hz)
  	 */
  	if (time_after(jiffies, data->last_updated + HZ / 6) || !data->valid) {
  		int i;
  
  		dev_dbg(&client->dev, "Starting ltc4151 update
  ");
  
  		/* Read all registers */
  		for (i = 0; i < ARRAY_SIZE(data->regs); i++) {
  			int val;
  
  			val = i2c_smbus_read_byte_data(client, i);
  			if (unlikely(val < 0)) {
  				dev_dbg(dev,
  					"Failed to read ADC value: error %d
  ",
  					val);
  				ret = ERR_PTR(val);
  				goto abort;
  			}
  			data->regs[i] = val;
  		}
  		data->last_updated = jiffies;
  		data->valid = 1;
  	}
  abort:
  	mutex_unlock(&data->update_lock);
  	return ret;
  }
  
  /* Return the voltage from the given register in mV */
  static int ltc4151_get_value(struct ltc4151_data *data, u8 reg)
  {
  	u32 val;
  
  	val = (data->regs[reg] << 4) + (data->regs[reg + 1] >> 4);
  
  	switch (reg) {
  	case LTC4151_ADIN_H:
  		/* 500uV resolution. Convert to mV. */
  		val = val * 500 / 1000;
  		break;
  	case LTC4151_SENSE_H:
  		/*
  		 * 20uV resolution. Convert to current as measured with
30fe976fe   Daniel Golle   hwmon: (ltc4151) ...
104
  		 * a given sense resistor, in mA.
de7790155   per.dalen@appeartv.com   hwmon: Add suppor...
105
  		 */
30fe976fe   Daniel Golle   hwmon: (ltc4151) ...
106
  		val = val * 20 * 1000 / data->shunt;
de7790155   per.dalen@appeartv.com   hwmon: Add suppor...
107
108
109
110
111
112
113
114
115
116
117
118
119
120
  		break;
  	case LTC4151_VIN_H:
  		/* 25 mV per increment */
  		val = val * 25;
  		break;
  	default:
  		/* If we get here, the developer messed up */
  		WARN_ON_ONCE(1);
  		val = 0;
  		break;
  	}
  
  	return val;
  }
409e8bce6   Guenter Roeck   hwmon: (ltc4151) ...
121
  static ssize_t ltc4151_value_show(struct device *dev,
de7790155   per.dalen@appeartv.com   hwmon: Add suppor...
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
  				  struct device_attribute *da, char *buf)
  {
  	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
  	struct ltc4151_data *data = ltc4151_update_device(dev);
  	int value;
  
  	if (IS_ERR(data))
  		return PTR_ERR(data);
  
  	value = ltc4151_get_value(data, attr->index);
  	return snprintf(buf, PAGE_SIZE, "%d
  ", value);
  }
  
  /*
   * Input voltages.
   */
409e8bce6   Guenter Roeck   hwmon: (ltc4151) ...
139
140
  static SENSOR_DEVICE_ATTR_RO(in1_input, ltc4151_value, LTC4151_VIN_H);
  static SENSOR_DEVICE_ATTR_RO(in2_input, ltc4151_value, LTC4151_ADIN_H);
de7790155   per.dalen@appeartv.com   hwmon: Add suppor...
141
142
  
  /* Currents (via sense resistor) */
409e8bce6   Guenter Roeck   hwmon: (ltc4151) ...
143
  static SENSOR_DEVICE_ATTR_RO(curr1_input, ltc4151_value, LTC4151_SENSE_H);
de7790155   per.dalen@appeartv.com   hwmon: Add suppor...
144

1b05d22f2   Guenter Roeck   hwmon: (ltc4151) ...
145
146
  /*
   * Finally, construct an array of pointers to members of the above objects,
de7790155   per.dalen@appeartv.com   hwmon: Add suppor...
147
148
   * as required for sysfs_create_group()
   */
31e387912   Axel Lin   hwmon: (ltc4151) ...
149
  static struct attribute *ltc4151_attrs[] = {
de7790155   per.dalen@appeartv.com   hwmon: Add suppor...
150
151
152
153
154
155
156
  	&sensor_dev_attr_in1_input.dev_attr.attr,
  	&sensor_dev_attr_in2_input.dev_attr.attr,
  
  	&sensor_dev_attr_curr1_input.dev_attr.attr,
  
  	NULL,
  };
31e387912   Axel Lin   hwmon: (ltc4151) ...
157
  ATTRIBUTE_GROUPS(ltc4151);
de7790155   per.dalen@appeartv.com   hwmon: Add suppor...
158

674870385   Stephen Kitt   hwmon: use simple...
159
  static int ltc4151_probe(struct i2c_client *client)
de7790155   per.dalen@appeartv.com   hwmon: Add suppor...
160
161
  {
  	struct i2c_adapter *adapter = client->adapter;
31e387912   Axel Lin   hwmon: (ltc4151) ...
162
  	struct device *dev = &client->dev;
de7790155   per.dalen@appeartv.com   hwmon: Add suppor...
163
  	struct ltc4151_data *data;
31e387912   Axel Lin   hwmon: (ltc4151) ...
164
  	struct device *hwmon_dev;
30fe976fe   Daniel Golle   hwmon: (ltc4151) ...
165
  	u32 shunt;
de7790155   per.dalen@appeartv.com   hwmon: Add suppor...
166
167
168
  
  	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
  		return -ENODEV;
31e387912   Axel Lin   hwmon: (ltc4151) ...
169
  	data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
78968642c   Guenter Roeck   hwmon: (ltc4151) ...
170
171
  	if (!data)
  		return -ENOMEM;
de7790155   per.dalen@appeartv.com   hwmon: Add suppor...
172

30fe976fe   Daniel Golle   hwmon: (ltc4151) ...
173
174
175
176
177
178
179
180
  	if (of_property_read_u32(client->dev.of_node,
  				 "shunt-resistor-micro-ohms", &shunt))
  		shunt = 1000; /* 1 mOhm if not set via DT */
  
  	if (shunt == 0)
  		return -EINVAL;
  
  	data->shunt = shunt;
31e387912   Axel Lin   hwmon: (ltc4151) ...
181
  	data->client = client;
de7790155   per.dalen@appeartv.com   hwmon: Add suppor...
182
  	mutex_init(&data->update_lock);
31e387912   Axel Lin   hwmon: (ltc4151) ...
183
184
185
186
  	hwmon_dev = devm_hwmon_device_register_with_groups(dev, client->name,
  							   data,
  							   ltc4151_groups);
  	return PTR_ERR_OR_ZERO(hwmon_dev);
de7790155   per.dalen@appeartv.com   hwmon: Add suppor...
187
188
189
190
191
192
193
  }
  
  static const struct i2c_device_id ltc4151_id[] = {
  	{ "ltc4151", 0 },
  	{ }
  };
  MODULE_DEVICE_TABLE(i2c, ltc4151_id);
a90cdd134   Guenter Roeck   hwmon: (ltc4151) ...
194
  static const struct of_device_id __maybe_unused ltc4151_match[] = {
30fe976fe   Daniel Golle   hwmon: (ltc4151) ...
195
196
197
  	{ .compatible = "lltc,ltc4151" },
  	{},
  };
bb85ceb1b   Javier Martinez Canillas   hwmon: (ltc4151) ...
198
  MODULE_DEVICE_TABLE(of, ltc4151_match);
30fe976fe   Daniel Golle   hwmon: (ltc4151) ...
199

de7790155   per.dalen@appeartv.com   hwmon: Add suppor...
200
201
202
203
  /* This is the driver that will be inserted */
  static struct i2c_driver ltc4151_driver = {
  	.driver = {
  		.name	= "ltc4151",
30fe976fe   Daniel Golle   hwmon: (ltc4151) ...
204
  		.of_match_table = of_match_ptr(ltc4151_match),
de7790155   per.dalen@appeartv.com   hwmon: Add suppor...
205
  	},
674870385   Stephen Kitt   hwmon: use simple...
206
  	.probe_new	= ltc4151_probe,
de7790155   per.dalen@appeartv.com   hwmon: Add suppor...
207
208
  	.id_table	= ltc4151_id,
  };
f0967eea8   Axel Lin   hwmon: convert dr...
209
  module_i2c_driver(ltc4151_driver);
de7790155   per.dalen@appeartv.com   hwmon: Add suppor...
210
211
212
213
  
  MODULE_AUTHOR("Per Dalen <per.dalen@appeartv.com>");
  MODULE_DESCRIPTION("LTC4151 driver");
  MODULE_LICENSE("GPL");