xref: /linux/drivers/hwmon/max77705-hwmon.c (revision ab93e0dd72c37d378dd936f031ffb83ff2bd87ce)
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 
16 struct 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 
24 static 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 
38 static 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 
max77705_read_and_convert(struct regmap * regmap,u8 reg,u32 res,bool is_signed,long * val)51 static 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 
max77705_is_visible(const void * data,enum hwmon_sensor_types type,u32 attr,int channel)69 static 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 
max77705_read_string(struct device * dev,enum hwmon_sensor_types type,u32 attr,int channel,const char ** buf)102 static 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 
max77705_read(struct device * dev,enum hwmon_sensor_types type,u32 attr,int channel,long * val)128 static 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 
169 static 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 
175 static 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 
187 static const struct hwmon_chip_info max77705_chip_info = {
188 	.ops = &max77705_hwmon_ops,
189 	.info = max77705_info,
190 };
191 
max77705_hwmon_probe(struct platform_device * pdev)192 static 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 
210 static struct platform_driver max77705_hwmon_driver = {
211 	.driver = {
212 		.name = "max77705-hwmon",
213 	},
214 	.probe = max77705_hwmon_probe,
215 };
216 
217 module_platform_driver(max77705_hwmon_driver);
218 
219 MODULE_AUTHOR("Dzmitry Sankouski <dsankouski@gmail.com>");
220 MODULE_DESCRIPTION("MAX77705 monitor driver");
221 MODULE_LICENSE("GPL");
222