File Index
Files and directories
Sign in
FILE

max77705-hwmon.c

File preview with syntax highlighting.

linux-6.19.14/drivers/hwmon/max77705-hwmon.c C
  1// SPDX-License-Identifier: GPL-2.0
  2/*
  3 *  MAX77705 voltage and current hwmon driver.
  4 *
  5 *  Copyright (C) 2025 Dzmitry Sankouski <dsankouski@gmail.com>
  6 */
  7
  8#include <linux/err.h>
  9#include <linux/hwmon-sysfs.h>
 10#include <linux/hwmon.h>
 11#include <linux/kernel.h>
 12#include <linux/mfd/max77705-private.h>
 13#include <linux/platform_device.h>
 14#include <linux/regmap.h>
 15
 16struct channel_desc {
 17	u8 reg;
 18	u8 avg_reg;
 19	const char *const label;
 20	// register resolution. nano Volts for voltage, nano Amperes for current
 21	u32 resolution;
 22};
 23
 24static const struct channel_desc current_channel_desc[] = {
 25	{
 26		.reg = IIN_REG,
 27		.label = "IIN_REG",
 28		.resolution = 125000
 29	},
 30	{
 31		.reg = ISYS_REG,
 32		.avg_reg = AVGISYS_REG,
 33		.label = "ISYS_REG",
 34		.resolution = 312500
 35	}
 36};
 37
 38static const struct channel_desc voltage_channel_desc[] = {
 39	{
 40		.reg = VBYP_REG,
 41		.label = "VBYP_REG",
 42		.resolution = 427246
 43	},
 44	{
 45		.reg = VSYS_REG,
 46		.label = "VSYS_REG",
 47		.resolution = 156250
 48	}
 49};
 50
 51static int max77705_read_and_convert(struct regmap *regmap, u8 reg, u32 res,
 52				     bool is_signed, long *val)
 53{
 54	int ret;
 55	u32 regval;
 56
 57	ret = regmap_read(regmap, reg, &regval);
 58	if (ret < 0)
 59		return ret;
 60
 61	if (is_signed)
 62		*val = mult_frac((long)sign_extend32(regval, 15), res, 1000000);
 63	else
 64		*val = mult_frac((long)regval, res, 1000000);
 65
 66	return 0;
 67}
 68
 69static umode_t max77705_is_visible(const void *data,
 70				   enum hwmon_sensor_types type,
 71				   u32 attr, int channel)
 72{
 73	switch (type) {
 74	case hwmon_in:
 75		switch (attr) {
 76		case hwmon_in_input:
 77		case hwmon_in_label:
 78			return 0444;
 79		default:
 80			break;
 81		}
 82		break;
 83	case hwmon_curr:
 84		switch (attr) {
 85		case hwmon_curr_input:
 86		case hwmon_in_label:
 87			return 0444;
 88		case hwmon_curr_average:
 89			if (current_channel_desc[channel].avg_reg)
 90				return 0444;
 91			break;
 92		default:
 93			break;
 94		}
 95		break;
 96	default:
 97		break;
 98	}
 99	return 0;
100}
101
102static int max77705_read_string(struct device *dev, enum hwmon_sensor_types type, u32 attr,
103				int channel, const char **buf)
104{
105	switch (type) {
106	case hwmon_curr:
107		switch (attr) {
108		case hwmon_in_label:
109			*buf = current_channel_desc[channel].label;
110			return 0;
111		default:
112			return -EOPNOTSUPP;
113		}
114
115	case hwmon_in:
116		switch (attr) {
117		case hwmon_in_label:
118			*buf = voltage_channel_desc[channel].label;
119			return 0;
120		default:
121			return -EOPNOTSUPP;
122		}
123	default:
124		return -EOPNOTSUPP;
125	}
126}
127
128static int max77705_read(struct device *dev, enum hwmon_sensor_types type,
129			 u32 attr, int channel, long *val)
130{
131	struct regmap *regmap = dev_get_drvdata(dev);
132	u8 reg;
133	u32 res;
134
135	switch (type) {
136	case hwmon_curr:
137		switch (attr) {
138		case hwmon_curr_input:
139			reg = current_channel_desc[channel].reg;
140			res = current_channel_desc[channel].resolution;
141
142			return max77705_read_and_convert(regmap, reg, res, true, val);
143		case hwmon_curr_average:
144			reg = current_channel_desc[channel].avg_reg;
145			res = current_channel_desc[channel].resolution;
146
147			return max77705_read_and_convert(regmap, reg, res, true, val);
148		default:
149			return -EOPNOTSUPP;
150		}
151
152	case hwmon_in:
153		switch (attr) {
154		case hwmon_in_input:
155			reg = voltage_channel_desc[channel].reg;
156			res = voltage_channel_desc[channel].resolution;
157
158			return max77705_read_and_convert(regmap, reg, res, false, val);
159		default:
160			return -EOPNOTSUPP;
161		}
162	default:
163		return -EOPNOTSUPP;
164	}
165
166	return 0;
167}
168
169static const struct hwmon_ops max77705_hwmon_ops = {
170	.is_visible = max77705_is_visible,
171	.read = max77705_read,
172	.read_string = max77705_read_string,
173};
174
175static const struct hwmon_channel_info *max77705_info[] = {
176	HWMON_CHANNEL_INFO(in,
177			   HWMON_I_INPUT | HWMON_I_LABEL,
178			   HWMON_I_INPUT | HWMON_I_LABEL
179			),
180	HWMON_CHANNEL_INFO(curr,
181			   HWMON_C_INPUT | HWMON_C_LABEL,
182			   HWMON_C_INPUT | HWMON_C_AVERAGE | HWMON_C_LABEL
183			),
184	NULL
185};
186
187static const struct hwmon_chip_info max77705_chip_info = {
188	.ops = &max77705_hwmon_ops,
189	.info = max77705_info,
190};
191
192static int max77705_hwmon_probe(struct platform_device *pdev)
193{
194	struct device *hwmon_dev;
195	struct regmap *regmap;
196
197	regmap = dev_get_regmap(pdev->dev.parent, NULL);
198	if (!regmap)
199		return -ENODEV;
200
201	hwmon_dev = devm_hwmon_device_register_with_info(&pdev->dev, "max77705", regmap,
202							 &max77705_chip_info, NULL);
203	if (IS_ERR(hwmon_dev))
204		return dev_err_probe(&pdev->dev, PTR_ERR(hwmon_dev),
205				"Unable to register hwmon device\n");
206
207	return 0;
208};
209
210static struct platform_driver max77705_hwmon_driver = {
211	.driver = {
212		.name = "max77705-hwmon",
213	},
214	.probe = max77705_hwmon_probe,
215};
216
217module_platform_driver(max77705_hwmon_driver);
218
219MODULE_AUTHOR("Dzmitry Sankouski <dsankouski@gmail.com>");
220MODULE_DESCRIPTION("MAX77705 monitor driver");
221MODULE_LICENSE("GPL");
~/ Read-only file preview.