File Index
Files and directories
Sign in
FILE

ltc4245.c

File preview with syntax highlighting.

linux-6.19.14/drivers/hwmon/ltc4245.c C
  1// SPDX-License-Identifier: GPL-2.0-only
  2/*
  3 * Driver for Linear Technology LTC4245 I2C Multiple Supply Hot Swap Controller
  4 *
  5 * Copyright (C) 2008 Ira W. Snyder <iws@ovro.caltech.edu>
  6 *
  7 * This driver is based on the ds1621 and ina209 drivers.
  8 *
  9 * Datasheet:
 10 * http://www.linear.com/pc/downloadDocument.do?navId=H0,C1,C1003,C1006,C1140,P19392,D13517
 11 */
 12
 13#include <linux/kernel.h>
 14#include <linux/module.h>
 15#include <linux/init.h>
 16#include <linux/bitops.h>
 17#include <linux/err.h>
 18#include <linux/slab.h>
 19#include <linux/i2c.h>
 20#include <linux/hwmon.h>
 21#include <linux/jiffies.h>
 22#include <linux/platform_data/ltc4245.h>
 23
 24/* Here are names of the chip's registers (a.k.a. commands) */
 25enum ltc4245_cmd {
 26	LTC4245_STATUS			= 0x00, /* readonly */
 27	LTC4245_ALERT			= 0x01,
 28	LTC4245_CONTROL			= 0x02,
 29	LTC4245_ON			= 0x03,
 30	LTC4245_FAULT1			= 0x04,
 31	LTC4245_FAULT2			= 0x05,
 32	LTC4245_GPIO			= 0x06,
 33	LTC4245_ADCADR			= 0x07,
 34
 35	LTC4245_12VIN			= 0x10,
 36	LTC4245_12VSENSE		= 0x11,
 37	LTC4245_12VOUT			= 0x12,
 38	LTC4245_5VIN			= 0x13,
 39	LTC4245_5VSENSE			= 0x14,
 40	LTC4245_5VOUT			= 0x15,
 41	LTC4245_3VIN			= 0x16,
 42	LTC4245_3VSENSE			= 0x17,
 43	LTC4245_3VOUT			= 0x18,
 44	LTC4245_VEEIN			= 0x19,
 45	LTC4245_VEESENSE		= 0x1a,
 46	LTC4245_VEEOUT			= 0x1b,
 47	LTC4245_GPIOADC			= 0x1c,
 48};
 49
 50struct ltc4245_data {
 51	struct i2c_client *client;
 52
 53	bool valid;
 54	unsigned long last_updated; /* in jiffies */
 55
 56	/* Control registers */
 57	u8 cregs[0x08];
 58
 59	/* Voltage registers */
 60	u8 vregs[0x0d];
 61
 62	/* GPIO ADC registers */
 63	bool use_extra_gpios;
 64	int gpios[3];
 65};
 66
 67/*
 68 * Update the readings from the GPIO pins. If the driver has been configured to
 69 * sample all GPIO's as analog voltages, a round-robin sampling method is used.
 70 * Otherwise, only the configured GPIO pin is sampled.
 71 *
 72 * LOCKING: must hold data->update_lock
 73 */
 74static void ltc4245_update_gpios(struct device *dev)
 75{
 76	struct ltc4245_data *data = dev_get_drvdata(dev);
 77	struct i2c_client *client = data->client;
 78	u8 gpio_curr, gpio_next, gpio_reg;
 79	int i;
 80
 81	/* no extra gpio support, we're basically done */
 82	if (!data->use_extra_gpios) {
 83		data->gpios[0] = data->vregs[LTC4245_GPIOADC - 0x10];
 84		return;
 85	}
 86
 87	/*
 88	 * If the last reading was too long ago, then we mark all old GPIO
 89	 * readings as stale by setting them to -EAGAIN
 90	 */
 91	if (time_after(jiffies, data->last_updated + 5 * HZ)) {
 92		for (i = 0; i < ARRAY_SIZE(data->gpios); i++)
 93			data->gpios[i] = -EAGAIN;
 94	}
 95
 96	/*
 97	 * Get the current GPIO pin
 98	 *
 99	 * The datasheet calls these GPIO[1-3], but we'll calculate the zero
100	 * based array index instead, and call them GPIO[0-2]. This is much
101	 * easier to think about.
102	 */
103	gpio_curr = (data->cregs[LTC4245_GPIO] & 0xc0) >> 6;
104	if (gpio_curr > 0)
105		gpio_curr -= 1;
106
107	/* Read the GPIO voltage from the GPIOADC register */
108	data->gpios[gpio_curr] = data->vregs[LTC4245_GPIOADC - 0x10];
109
110	/* Find the next GPIO pin to read */
111	gpio_next = (gpio_curr + 1) % ARRAY_SIZE(data->gpios);
112
113	/*
114	 * Calculate the correct setting for the GPIO register so it will
115	 * sample the next GPIO pin
116	 */
117	gpio_reg = (data->cregs[LTC4245_GPIO] & 0x3f) | ((gpio_next + 1) << 6);
118
119	/* Update the GPIO register */
120	i2c_smbus_write_byte_data(client, LTC4245_GPIO, gpio_reg);
121
122	/* Update saved data */
123	data->cregs[LTC4245_GPIO] = gpio_reg;
124}
125
126static struct ltc4245_data *ltc4245_update_device(struct device *dev)
127{
128	struct ltc4245_data *data = dev_get_drvdata(dev);
129	struct i2c_client *client = data->client;
130	s32 val;
131	int i;
132
133	if (time_after(jiffies, data->last_updated + HZ) || !data->valid) {
134		/* Read control registers -- 0x00 to 0x07 */
135		for (i = 0; i < ARRAY_SIZE(data->cregs); i++) {
136			val = i2c_smbus_read_byte_data(client, i);
137			if (unlikely(val < 0))
138				data->cregs[i] = 0;
139			else
140				data->cregs[i] = val;
141		}
142
143		/* Read voltage registers -- 0x10 to 0x1c */
144		for (i = 0; i < ARRAY_SIZE(data->vregs); i++) {
145			val = i2c_smbus_read_byte_data(client, i+0x10);
146			if (unlikely(val < 0))
147				data->vregs[i] = 0;
148			else
149				data->vregs[i] = val;
150		}
151
152		/* Update GPIO readings */
153		ltc4245_update_gpios(dev);
154
155		data->last_updated = jiffies;
156		data->valid = true;
157	}
158
159	return data;
160}
161
162/* Return the voltage from the given register in millivolts */
163static int ltc4245_get_voltage(struct device *dev, u8 reg)
164{
165	struct ltc4245_data *data = ltc4245_update_device(dev);
166	const u8 regval = data->vregs[reg - 0x10];
167	u32 voltage = 0;
168
169	switch (reg) {
170	case LTC4245_12VIN:
171	case LTC4245_12VOUT:
172		voltage = regval * 55;
173		break;
174	case LTC4245_5VIN:
175	case LTC4245_5VOUT:
176		voltage = regval * 22;
177		break;
178	case LTC4245_3VIN:
179	case LTC4245_3VOUT:
180		voltage = regval * 15;
181		break;
182	case LTC4245_VEEIN:
183	case LTC4245_VEEOUT:
184		voltage = regval * -55;
185		break;
186	case LTC4245_GPIOADC:
187		voltage = regval * 10;
188		break;
189	default:
190		/* If we get here, the developer messed up */
191		WARN_ON_ONCE(1);
192		break;
193	}
194
195	return voltage;
196}
197
198/* Return the current in the given sense register in milliAmperes */
199static unsigned int ltc4245_get_current(struct device *dev, u8 reg)
200{
201	struct ltc4245_data *data = ltc4245_update_device(dev);
202	const u8 regval = data->vregs[reg - 0x10];
203	unsigned int voltage;
204	unsigned int curr;
205
206	/*
207	 * The strange looking conversions that follow are fixed-point
208	 * math, since we cannot do floating point in the kernel.
209	 *
210	 * Step 1: convert sense register to microVolts
211	 * Step 2: convert voltage to milliAmperes
212	 *
213	 * If you play around with the V=IR equation, you come up with
214	 * the following: X uV / Y mOhm == Z mA
215	 *
216	 * With the resistors that are fractions of a milliOhm, we multiply
217	 * the voltage and resistance by 10, to shift the decimal point.
218	 * Now we can use the normal division operator again.
219	 */
220
221	switch (reg) {
222	case LTC4245_12VSENSE:
223		voltage = regval * 250; /* voltage in uV */
224		curr = voltage / 50; /* sense resistor 50 mOhm */
225		break;
226	case LTC4245_5VSENSE:
227		voltage = regval * 125; /* voltage in uV */
228		curr = (voltage * 10) / 35; /* sense resistor 3.5 mOhm */
229		break;
230	case LTC4245_3VSENSE:
231		voltage = regval * 125; /* voltage in uV */
232		curr = (voltage * 10) / 25; /* sense resistor 2.5 mOhm */
233		break;
234	case LTC4245_VEESENSE:
235		voltage = regval * 250; /* voltage in uV */
236		curr = voltage / 100; /* sense resistor 100 mOhm */
237		break;
238	default:
239		/* If we get here, the developer messed up */
240		WARN_ON_ONCE(1);
241		curr = 0;
242		break;
243	}
244
245	return curr;
246}
247
248/* Map from voltage channel index to voltage register */
249
250static const s8 ltc4245_in_regs[] = {
251	LTC4245_12VIN, LTC4245_5VIN, LTC4245_3VIN, LTC4245_VEEIN,
252	LTC4245_12VOUT, LTC4245_5VOUT, LTC4245_3VOUT, LTC4245_VEEOUT,
253};
254
255/* Map from current channel index to current register */
256
257static const s8 ltc4245_curr_regs[] = {
258	LTC4245_12VSENSE, LTC4245_5VSENSE, LTC4245_3VSENSE, LTC4245_VEESENSE,
259};
260
261static int ltc4245_read_curr(struct device *dev, u32 attr, int channel,
262			     long *val)
263{
264	struct ltc4245_data *data = ltc4245_update_device(dev);
265
266	switch (attr) {
267	case hwmon_curr_input:
268		*val = ltc4245_get_current(dev, ltc4245_curr_regs[channel]);
269		return 0;
270	case hwmon_curr_max_alarm:
271		*val = !!(data->cregs[LTC4245_FAULT1] & BIT(channel + 4));
272		return 0;
273	default:
274		return -EOPNOTSUPP;
275	}
276}
277
278static int ltc4245_read_in(struct device *dev, u32 attr, int channel, long *val)
279{
280	struct ltc4245_data *data = ltc4245_update_device(dev);
281
282	switch (attr) {
283	case hwmon_in_input:
284		if (channel < 8) {
285			*val = ltc4245_get_voltage(dev,
286						ltc4245_in_regs[channel]);
287		} else {
288			int regval = data->gpios[channel - 8];
289
290			if (regval < 0)
291				return regval;
292			*val = regval * 10;
293		}
294		return 0;
295	case hwmon_in_min_alarm:
296		if (channel < 4)
297			*val = !!(data->cregs[LTC4245_FAULT1] & BIT(channel));
298		else
299			*val = !!(data->cregs[LTC4245_FAULT2] &
300				  BIT(channel - 4));
301		return 0;
302	default:
303		return -EOPNOTSUPP;
304	}
305}
306
307static int ltc4245_read_power(struct device *dev, u32 attr, int channel,
308			      long *val)
309{
310	unsigned long curr;
311	long voltage;
312
313	switch (attr) {
314	case hwmon_power_input:
315		(void)ltc4245_update_device(dev);
316		curr = ltc4245_get_current(dev, ltc4245_curr_regs[channel]);
317		voltage = ltc4245_get_voltage(dev, ltc4245_in_regs[channel]);
318		*val = abs(curr * voltage);
319		return 0;
320	default:
321		return -EOPNOTSUPP;
322	}
323}
324
325static int ltc4245_read(struct device *dev, enum hwmon_sensor_types type,
326			u32 attr, int channel, long *val)
327{
328
329	switch (type) {
330	case hwmon_curr:
331		return ltc4245_read_curr(dev, attr, channel, val);
332	case hwmon_power:
333		return ltc4245_read_power(dev, attr, channel, val);
334	case hwmon_in:
335		return ltc4245_read_in(dev, attr, channel - 1, val);
336	default:
337		return -EOPNOTSUPP;
338	}
339}
340
341static umode_t ltc4245_is_visible(const void *_data,
342				  enum hwmon_sensor_types type,
343				  u32 attr, int channel)
344{
345	const struct ltc4245_data *data = _data;
346
347	switch (type) {
348	case hwmon_in:
349		if (channel == 0)
350			return 0;
351		switch (attr) {
352		case hwmon_in_input:
353			if (channel > 9 && !data->use_extra_gpios)
354				return 0;
355			return 0444;
356		case hwmon_in_min_alarm:
357			if (channel > 8)
358				return 0;
359			return 0444;
360		default:
361			return 0;
362		}
363	case hwmon_curr:
364		switch (attr) {
365		case hwmon_curr_input:
366		case hwmon_curr_max_alarm:
367			return 0444;
368		default:
369			return 0;
370		}
371	case hwmon_power:
372		switch (attr) {
373		case hwmon_power_input:
374			return 0444;
375		default:
376			return 0;
377		}
378	default:
379		return 0;
380	}
381}
382
383static const struct hwmon_channel_info * const ltc4245_info[] = {
384	HWMON_CHANNEL_INFO(in,
385			   HWMON_I_INPUT,
386			   HWMON_I_INPUT | HWMON_I_MIN_ALARM,
387			   HWMON_I_INPUT | HWMON_I_MIN_ALARM,
388			   HWMON_I_INPUT | HWMON_I_MIN_ALARM,
389			   HWMON_I_INPUT | HWMON_I_MIN_ALARM,
390			   HWMON_I_INPUT | HWMON_I_MIN_ALARM,
391			   HWMON_I_INPUT | HWMON_I_MIN_ALARM,
392			   HWMON_I_INPUT | HWMON_I_MIN_ALARM,
393			   HWMON_I_INPUT | HWMON_I_MIN_ALARM,
394			   HWMON_I_INPUT,
395			   HWMON_I_INPUT,
396			   HWMON_I_INPUT),
397	HWMON_CHANNEL_INFO(curr,
398			   HWMON_C_INPUT | HWMON_C_MAX_ALARM,
399			   HWMON_C_INPUT | HWMON_C_MAX_ALARM,
400			   HWMON_C_INPUT | HWMON_C_MAX_ALARM,
401			   HWMON_C_INPUT | HWMON_C_MAX_ALARM),
402	HWMON_CHANNEL_INFO(power,
403			   HWMON_P_INPUT,
404			   HWMON_P_INPUT,
405			   HWMON_P_INPUT,
406			   HWMON_P_INPUT),
407	NULL
408};
409
410static const struct hwmon_ops ltc4245_hwmon_ops = {
411	.is_visible = ltc4245_is_visible,
412	.read = ltc4245_read,
413};
414
415static const struct hwmon_chip_info ltc4245_chip_info = {
416	.ops = &ltc4245_hwmon_ops,
417	.info = ltc4245_info,
418};
419
420static bool ltc4245_use_extra_gpios(struct i2c_client *client)
421{
422	struct ltc4245_platform_data *pdata = dev_get_platdata(&client->dev);
423	struct device_node *np = client->dev.of_node;
424
425	/* prefer platform data */
426	if (pdata)
427		return pdata->use_extra_gpios;
428
429	/* fallback on OF */
430	if (of_property_read_bool(np, "ltc4245,use-extra-gpios"))
431		return true;
432
433	return false;
434}
435
436static int ltc4245_probe(struct i2c_client *client)
437{
438	struct i2c_adapter *adapter = client->adapter;
439	struct ltc4245_data *data;
440	struct device *hwmon_dev;
441
442	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
443		return -ENODEV;
444
445	data = devm_kzalloc(&client->dev, sizeof(*data), GFP_KERNEL);
446	if (!data)
447		return -ENOMEM;
448
449	data->client = client;
450	data->use_extra_gpios = ltc4245_use_extra_gpios(client);
451
452	/* Initialize the LTC4245 chip */
453	i2c_smbus_write_byte_data(client, LTC4245_FAULT1, 0x00);
454	i2c_smbus_write_byte_data(client, LTC4245_FAULT2, 0x00);
455
456	hwmon_dev = devm_hwmon_device_register_with_info(&client->dev,
457							 client->name, data,
458							 &ltc4245_chip_info,
459							 NULL);
460	return PTR_ERR_OR_ZERO(hwmon_dev);
461}
462
463static const struct i2c_device_id ltc4245_id[] = {
464	{ "ltc4245" },
465	{ }
466};
467MODULE_DEVICE_TABLE(i2c, ltc4245_id);
468
469/* This is the driver that will be inserted */
470static struct i2c_driver ltc4245_driver = {
471	.driver = {
472		.name	= "ltc4245",
473	},
474	.probe		= ltc4245_probe,
475	.id_table	= ltc4245_id,
476};
477
478module_i2c_driver(ltc4245_driver);
479
480MODULE_AUTHOR("Ira W. Snyder <iws@ovro.caltech.edu>");
481MODULE_DESCRIPTION("LTC4245 driver");
482MODULE_LICENSE("GPL");
~/ Read-only file preview.