xref: /openbmc/linux/drivers/hwmon/powr1220.c (revision 1975d167)
1c942fddfSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
2f4ff4155SScott Kanowitz /*
3f4ff4155SScott Kanowitz  * powr1220.c - Driver for the Lattice POWR1220 programmable power supply
4f4ff4155SScott Kanowitz  * and monitor. Users can read all ADC inputs along with their labels
5f4ff4155SScott Kanowitz  * using the sysfs nodes.
6f4ff4155SScott Kanowitz  *
7ad736c1aSAlexander A. Klimov  * Copyright (c) 2014 Echo360 https://www.echo360.com
8f4ff4155SScott Kanowitz  * Scott Kanowitz <skanowitz@echo360.com> <scott.kanowitz@gmail.com>
9f4ff4155SScott Kanowitz  */
10f4ff4155SScott Kanowitz 
11f4ff4155SScott Kanowitz #include <linux/module.h>
12f4ff4155SScott Kanowitz #include <linux/init.h>
13f4ff4155SScott Kanowitz #include <linux/slab.h>
14f4ff4155SScott Kanowitz #include <linux/jiffies.h>
15f4ff4155SScott Kanowitz #include <linux/i2c.h>
16f4ff4155SScott Kanowitz #include <linux/hwmon.h>
17f4ff4155SScott Kanowitz #include <linux/hwmon-sysfs.h>
18f4ff4155SScott Kanowitz #include <linux/err.h>
19f4ff4155SScott Kanowitz #include <linux/mutex.h>
20f4ff4155SScott Kanowitz #include <linux/delay.h>
21f4ff4155SScott Kanowitz 
22f4ff4155SScott Kanowitz #define ADC_STEP_MV			2
23f4ff4155SScott Kanowitz #define ADC_MAX_LOW_MEASUREMENT_MV	2000
24f4ff4155SScott Kanowitz 
259f93aa10SMichael Shych enum powr1xxx_chips { powr1014, powr1220 };
269f93aa10SMichael Shych 
27f4ff4155SScott Kanowitz enum powr1220_regs {
28f4ff4155SScott Kanowitz 	VMON_STATUS0,
29f4ff4155SScott Kanowitz 	VMON_STATUS1,
30f4ff4155SScott Kanowitz 	VMON_STATUS2,
31f4ff4155SScott Kanowitz 	OUTPUT_STATUS0,
32f4ff4155SScott Kanowitz 	OUTPUT_STATUS1,
33f4ff4155SScott Kanowitz 	OUTPUT_STATUS2,
34f4ff4155SScott Kanowitz 	INPUT_STATUS,
35f4ff4155SScott Kanowitz 	ADC_VALUE_LOW,
36f4ff4155SScott Kanowitz 	ADC_VALUE_HIGH,
37f4ff4155SScott Kanowitz 	ADC_MUX,
38f4ff4155SScott Kanowitz 	UES_BYTE0,
39f4ff4155SScott Kanowitz 	UES_BYTE1,
40f4ff4155SScott Kanowitz 	UES_BYTE2,
41f4ff4155SScott Kanowitz 	UES_BYTE3,
42f4ff4155SScott Kanowitz 	GP_OUTPUT1,
43f4ff4155SScott Kanowitz 	GP_OUTPUT2,
44f4ff4155SScott Kanowitz 	GP_OUTPUT3,
45f4ff4155SScott Kanowitz 	INPUT_VALUE,
46f4ff4155SScott Kanowitz 	RESET,
47f4ff4155SScott Kanowitz 	TRIM1_TRIM,
48f4ff4155SScott Kanowitz 	TRIM2_TRIM,
49f4ff4155SScott Kanowitz 	TRIM3_TRIM,
50f4ff4155SScott Kanowitz 	TRIM4_TRIM,
51f4ff4155SScott Kanowitz 	TRIM5_TRIM,
52f4ff4155SScott Kanowitz 	TRIM6_TRIM,
53f4ff4155SScott Kanowitz 	TRIM7_TRIM,
54f4ff4155SScott Kanowitz 	TRIM8_TRIM,
55f4ff4155SScott Kanowitz 	MAX_POWR1220_REGS
56f4ff4155SScott Kanowitz };
57f4ff4155SScott Kanowitz 
58f4ff4155SScott Kanowitz enum powr1220_adc_values {
59f4ff4155SScott Kanowitz 	VMON1,
60f4ff4155SScott Kanowitz 	VMON2,
61f4ff4155SScott Kanowitz 	VMON3,
62f4ff4155SScott Kanowitz 	VMON4,
63f4ff4155SScott Kanowitz 	VMON5,
64f4ff4155SScott Kanowitz 	VMON6,
65f4ff4155SScott Kanowitz 	VMON7,
66f4ff4155SScott Kanowitz 	VMON8,
67f4ff4155SScott Kanowitz 	VMON9,
68f4ff4155SScott Kanowitz 	VMON10,
69f4ff4155SScott Kanowitz 	VMON11,
70f4ff4155SScott Kanowitz 	VMON12,
71f4ff4155SScott Kanowitz 	VCCA,
72f4ff4155SScott Kanowitz 	VCCINP,
73f4ff4155SScott Kanowitz 	MAX_POWR1220_ADC_VALUES
74f4ff4155SScott Kanowitz };
75f4ff4155SScott Kanowitz 
76f4ff4155SScott Kanowitz struct powr1220_data {
77f4ff4155SScott Kanowitz 	struct i2c_client *client;
78f4ff4155SScott Kanowitz 	struct mutex update_lock;
799f93aa10SMichael Shych 	u8 max_channels;
80f4ff4155SScott Kanowitz 	bool adc_valid[MAX_POWR1220_ADC_VALUES];
81f4ff4155SScott Kanowitz 	 /* the next value is in jiffies */
82f4ff4155SScott Kanowitz 	unsigned long adc_last_updated[MAX_POWR1220_ADC_VALUES];
83f4ff4155SScott Kanowitz 
84f4ff4155SScott Kanowitz 	/* values */
85f4ff4155SScott Kanowitz 	int adc_maxes[MAX_POWR1220_ADC_VALUES];
86f4ff4155SScott Kanowitz 	int adc_values[MAX_POWR1220_ADC_VALUES];
87f4ff4155SScott Kanowitz };
88f4ff4155SScott Kanowitz 
89f4ff4155SScott Kanowitz static const char * const input_names[] = {
90f4ff4155SScott Kanowitz 	[VMON1]    = "vmon1",
91f4ff4155SScott Kanowitz 	[VMON2]    = "vmon2",
92f4ff4155SScott Kanowitz 	[VMON3]    = "vmon3",
93f4ff4155SScott Kanowitz 	[VMON4]    = "vmon4",
94f4ff4155SScott Kanowitz 	[VMON5]    = "vmon5",
95f4ff4155SScott Kanowitz 	[VMON6]    = "vmon6",
96f4ff4155SScott Kanowitz 	[VMON7]    = "vmon7",
97f4ff4155SScott Kanowitz 	[VMON8]    = "vmon8",
98f4ff4155SScott Kanowitz 	[VMON9]    = "vmon9",
99f4ff4155SScott Kanowitz 	[VMON10]   = "vmon10",
100f4ff4155SScott Kanowitz 	[VMON11]   = "vmon11",
101f4ff4155SScott Kanowitz 	[VMON12]   = "vmon12",
102f4ff4155SScott Kanowitz 	[VCCA]     = "vcca",
103f4ff4155SScott Kanowitz 	[VCCINP]   = "vccinp",
104f4ff4155SScott Kanowitz };
105f4ff4155SScott Kanowitz 
106f4ff4155SScott Kanowitz /* Reads the specified ADC channel */
powr1220_read_adc(struct device * dev,int ch_num)107f4ff4155SScott Kanowitz static int powr1220_read_adc(struct device *dev, int ch_num)
108f4ff4155SScott Kanowitz {
109f4ff4155SScott Kanowitz 	struct powr1220_data *data = dev_get_drvdata(dev);
110f4ff4155SScott Kanowitz 	int reading;
111f4ff4155SScott Kanowitz 	int result;
112f4ff4155SScott Kanowitz 	int adc_range = 0;
113f4ff4155SScott Kanowitz 
114f4ff4155SScott Kanowitz 	mutex_lock(&data->update_lock);
115f4ff4155SScott Kanowitz 
116f4ff4155SScott Kanowitz 	if (time_after(jiffies, data->adc_last_updated[ch_num] + HZ) ||
117f4ff4155SScott Kanowitz 	    !data->adc_valid[ch_num]) {
118f4ff4155SScott Kanowitz 		/*
119f4ff4155SScott Kanowitz 		 * figure out if we need to use the attenuator for
120f4ff4155SScott Kanowitz 		 * high inputs or inputs that we don't yet have a measurement
121f4ff4155SScott Kanowitz 		 * for. We dynamically set the attenuator depending on the
122f4ff4155SScott Kanowitz 		 * max reading.
123f4ff4155SScott Kanowitz 		 */
124f4ff4155SScott Kanowitz 		if (data->adc_maxes[ch_num] > ADC_MAX_LOW_MEASUREMENT_MV ||
125f4ff4155SScott Kanowitz 		    data->adc_maxes[ch_num] == 0)
126f4ff4155SScott Kanowitz 			adc_range = 1 << 4;
127f4ff4155SScott Kanowitz 
128f4ff4155SScott Kanowitz 		/* set the attenuator and mux */
129f4ff4155SScott Kanowitz 		result = i2c_smbus_write_byte_data(data->client, ADC_MUX,
130f4ff4155SScott Kanowitz 						   adc_range | ch_num);
131f4ff4155SScott Kanowitz 		if (result)
132f4ff4155SScott Kanowitz 			goto exit;
133f4ff4155SScott Kanowitz 
134f4ff4155SScott Kanowitz 		/*
135f4ff4155SScott Kanowitz 		 * wait at least Tconvert time (200 us) for the
136f4ff4155SScott Kanowitz 		 * conversion to complete
137f4ff4155SScott Kanowitz 		 */
138f4ff4155SScott Kanowitz 		udelay(200);
139f4ff4155SScott Kanowitz 
140f4ff4155SScott Kanowitz 		/* get the ADC reading */
141f4ff4155SScott Kanowitz 		result = i2c_smbus_read_byte_data(data->client, ADC_VALUE_LOW);
142f4ff4155SScott Kanowitz 		if (result < 0)
143f4ff4155SScott Kanowitz 			goto exit;
144f4ff4155SScott Kanowitz 
145f4ff4155SScott Kanowitz 		reading = result >> 4;
146f4ff4155SScott Kanowitz 
147f4ff4155SScott Kanowitz 		/* get the upper half of the reading */
148f4ff4155SScott Kanowitz 		result = i2c_smbus_read_byte_data(data->client, ADC_VALUE_HIGH);
149f4ff4155SScott Kanowitz 		if (result < 0)
150f4ff4155SScott Kanowitz 			goto exit;
151f4ff4155SScott Kanowitz 
152f4ff4155SScott Kanowitz 		reading |= result << 4;
153f4ff4155SScott Kanowitz 
154f4ff4155SScott Kanowitz 		/* now convert the reading to a voltage */
155f4ff4155SScott Kanowitz 		reading *= ADC_STEP_MV;
156f4ff4155SScott Kanowitz 		data->adc_values[ch_num] = reading;
157f4ff4155SScott Kanowitz 		data->adc_valid[ch_num] = true;
158f4ff4155SScott Kanowitz 		data->adc_last_updated[ch_num] = jiffies;
159f4ff4155SScott Kanowitz 		result = reading;
160f4ff4155SScott Kanowitz 
161f4ff4155SScott Kanowitz 		if (reading > data->adc_maxes[ch_num])
162f4ff4155SScott Kanowitz 			data->adc_maxes[ch_num] = reading;
163f4ff4155SScott Kanowitz 	} else {
164f4ff4155SScott Kanowitz 		result = data->adc_values[ch_num];
165f4ff4155SScott Kanowitz 	}
166f4ff4155SScott Kanowitz 
167f4ff4155SScott Kanowitz exit:
168f4ff4155SScott Kanowitz 	mutex_unlock(&data->update_lock);
169f4ff4155SScott Kanowitz 
170f4ff4155SScott Kanowitz 	return result;
171f4ff4155SScott Kanowitz }
172f4ff4155SScott Kanowitz 
173915d4664SMichael Shych static umode_t
powr1220_is_visible(const void * data,enum hwmon_sensor_types type,u32 attr,int channel)174915d4664SMichael Shych powr1220_is_visible(const void *data, enum hwmon_sensor_types type, u32
175915d4664SMichael Shych 		    attr, int channel)
176f4ff4155SScott Kanowitz {
1779f93aa10SMichael Shych 	struct powr1220_data *chip_data = (struct powr1220_data *)data;
1789f93aa10SMichael Shych 
1799f93aa10SMichael Shych 	if (channel >= chip_data->max_channels)
1809f93aa10SMichael Shych 		return 0;
1819f93aa10SMichael Shych 
182915d4664SMichael Shych 	switch (type) {
183915d4664SMichael Shych 	case hwmon_in:
184915d4664SMichael Shych 		switch (attr) {
185915d4664SMichael Shych 		case hwmon_in_input:
186915d4664SMichael Shych 		case hwmon_in_highest:
187915d4664SMichael Shych 		case hwmon_in_label:
188915d4664SMichael Shych 			return 0444;
189915d4664SMichael Shych 		default:
190915d4664SMichael Shych 			break;
191915d4664SMichael Shych 		}
192915d4664SMichael Shych 		break;
193915d4664SMichael Shych 	default:
194915d4664SMichael Shych 		break;
195f4ff4155SScott Kanowitz 	}
196f4ff4155SScott Kanowitz 
197915d4664SMichael Shych 	return 0;
198915d4664SMichael Shych }
199915d4664SMichael Shych 
200915d4664SMichael Shych static int
powr1220_read_string(struct device * dev,enum hwmon_sensor_types type,u32 attr,int channel,const char ** str)201915d4664SMichael Shych powr1220_read_string(struct device *dev, enum hwmon_sensor_types type, u32 attr,
202915d4664SMichael Shych 		     int channel, const char **str)
203f4ff4155SScott Kanowitz {
204915d4664SMichael Shych 	switch (type) {
205915d4664SMichael Shych 	case hwmon_in:
206915d4664SMichael Shych 		switch (attr) {
207915d4664SMichael Shych 		case hwmon_in_label:
208915d4664SMichael Shych 			*str = input_names[channel];
209915d4664SMichael Shych 			return 0;
210915d4664SMichael Shych 		default:
211915d4664SMichael Shych 			return -EOPNOTSUPP;
212915d4664SMichael Shych 		}
213915d4664SMichael Shych 		break;
214915d4664SMichael Shych 	default:
215915d4664SMichael Shych 		return -EOPNOTSUPP;
216915d4664SMichael Shych 	}
217915d4664SMichael Shych 
218915d4664SMichael Shych 	return -EOPNOTSUPP;
219915d4664SMichael Shych }
220915d4664SMichael Shych 
221915d4664SMichael Shych static int
powr1220_read(struct device * dev,enum hwmon_sensor_types type,u32 attr,int channel,long * val)222915d4664SMichael Shych powr1220_read(struct device *dev, enum hwmon_sensor_types type, u32
223915d4664SMichael Shych 	      attr, int channel, long *val)
224915d4664SMichael Shych {
225f4ff4155SScott Kanowitz 	struct powr1220_data *data = dev_get_drvdata(dev);
226915d4664SMichael Shych 	int ret;
227f4ff4155SScott Kanowitz 
228915d4664SMichael Shych 	switch (type) {
229915d4664SMichael Shych 	case hwmon_in:
230915d4664SMichael Shych 		switch (attr) {
231915d4664SMichael Shych 		case hwmon_in_input:
232915d4664SMichael Shych 			ret = powr1220_read_adc(dev, channel);
233915d4664SMichael Shych 			if (ret < 0)
234915d4664SMichael Shych 				return ret;
235915d4664SMichael Shych 			*val = ret;
236915d4664SMichael Shych 			break;
237915d4664SMichael Shych 		case hwmon_in_highest:
238915d4664SMichael Shych 			*val = data->adc_maxes[channel];
239915d4664SMichael Shych 			break;
240915d4664SMichael Shych 		default:
241915d4664SMichael Shych 			return -EOPNOTSUPP;
242915d4664SMichael Shych 		}
243915d4664SMichael Shych 		break;
244915d4664SMichael Shych 	default:
245915d4664SMichael Shych 		return -EOPNOTSUPP;
246f4ff4155SScott Kanowitz }
247f4ff4155SScott Kanowitz 
248915d4664SMichael Shych 	return 0;
249f4ff4155SScott Kanowitz }
250f4ff4155SScott Kanowitz 
25142d273bcSKrzysztof Kozlowski static const struct hwmon_channel_info * const powr1220_info[] = {
252915d4664SMichael Shych 	HWMON_CHANNEL_INFO(in,
253915d4664SMichael Shych 			   HWMON_I_INPUT | HWMON_I_HIGHEST | HWMON_I_LABEL,
254915d4664SMichael Shych 			   HWMON_I_INPUT | HWMON_I_HIGHEST | HWMON_I_LABEL,
255915d4664SMichael Shych 			   HWMON_I_INPUT | HWMON_I_HIGHEST | HWMON_I_LABEL,
256915d4664SMichael Shych 			   HWMON_I_INPUT | HWMON_I_HIGHEST | HWMON_I_LABEL,
257915d4664SMichael Shych 			   HWMON_I_INPUT | HWMON_I_HIGHEST | HWMON_I_LABEL,
258915d4664SMichael Shych 			   HWMON_I_INPUT | HWMON_I_HIGHEST | HWMON_I_LABEL,
259915d4664SMichael Shych 			   HWMON_I_INPUT | HWMON_I_HIGHEST | HWMON_I_LABEL,
260915d4664SMichael Shych 			   HWMON_I_INPUT | HWMON_I_HIGHEST | HWMON_I_LABEL,
261915d4664SMichael Shych 			   HWMON_I_INPUT | HWMON_I_HIGHEST | HWMON_I_LABEL,
262915d4664SMichael Shych 			   HWMON_I_INPUT | HWMON_I_HIGHEST | HWMON_I_LABEL,
263915d4664SMichael Shych 			   HWMON_I_INPUT | HWMON_I_HIGHEST | HWMON_I_LABEL,
264915d4664SMichael Shych 			   HWMON_I_INPUT | HWMON_I_HIGHEST | HWMON_I_LABEL,
265915d4664SMichael Shych 			   HWMON_I_INPUT | HWMON_I_HIGHEST | HWMON_I_LABEL,
266915d4664SMichael Shych 			   HWMON_I_INPUT | HWMON_I_HIGHEST | HWMON_I_LABEL),
267f4ff4155SScott Kanowitz 
268f4ff4155SScott Kanowitz 	NULL
269f4ff4155SScott Kanowitz };
270f4ff4155SScott Kanowitz 
271915d4664SMichael Shych static const struct hwmon_ops powr1220_hwmon_ops = {
272915d4664SMichael Shych 	.read = powr1220_read,
273915d4664SMichael Shych 	.read_string = powr1220_read_string,
274915d4664SMichael Shych 	.is_visible = powr1220_is_visible,
275915d4664SMichael Shych };
276915d4664SMichael Shych 
277915d4664SMichael Shych static const struct hwmon_chip_info powr1220_chip_info = {
278915d4664SMichael Shych 	.ops = &powr1220_hwmon_ops,
279915d4664SMichael Shych 	.info = powr1220_info,
280915d4664SMichael Shych };
281f4ff4155SScott Kanowitz 
2829f93aa10SMichael Shych static const struct i2c_device_id powr1220_ids[];
2839f93aa10SMichael Shych 
powr1220_probe(struct i2c_client * client)28467487038SStephen Kitt static int powr1220_probe(struct i2c_client *client)
285f4ff4155SScott Kanowitz {
286f4ff4155SScott Kanowitz 	struct powr1220_data *data;
287f4ff4155SScott Kanowitz 	struct device *hwmon_dev;
288f4ff4155SScott Kanowitz 
289f4ff4155SScott Kanowitz 	if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
290f4ff4155SScott Kanowitz 		return -ENODEV;
291f4ff4155SScott Kanowitz 
292f4ff4155SScott Kanowitz 	data = devm_kzalloc(&client->dev, sizeof(*data), GFP_KERNEL);
293f4ff4155SScott Kanowitz 	if (!data)
294f4ff4155SScott Kanowitz 		return -ENOMEM;
295f4ff4155SScott Kanowitz 
2969f93aa10SMichael Shych 	switch (i2c_match_id(powr1220_ids, client)->driver_data) {
2979f93aa10SMichael Shych 	case powr1014:
2989f93aa10SMichael Shych 		data->max_channels = 10;
2999f93aa10SMichael Shych 		break;
3009f93aa10SMichael Shych 	default:
3019f93aa10SMichael Shych 		data->max_channels = 12;
3029f93aa10SMichael Shych 		break;
3039f93aa10SMichael Shych 	}
3049f93aa10SMichael Shych 
305f4ff4155SScott Kanowitz 	mutex_init(&data->update_lock);
306f4ff4155SScott Kanowitz 	data->client = client;
307f4ff4155SScott Kanowitz 
308915d4664SMichael Shych 	hwmon_dev = devm_hwmon_device_register_with_info(&client->dev,
309915d4664SMichael Shych 							 client->name,
310915d4664SMichael Shych 							 data,
311915d4664SMichael Shych 							 &powr1220_chip_info,
312915d4664SMichael Shych 							 NULL);
313f4ff4155SScott Kanowitz 
314f4ff4155SScott Kanowitz 	return PTR_ERR_OR_ZERO(hwmon_dev);
315f4ff4155SScott Kanowitz }
316f4ff4155SScott Kanowitz 
317f4ff4155SScott Kanowitz static const struct i2c_device_id powr1220_ids[] = {
3189f93aa10SMichael Shych 	{ "powr1014", powr1014, },
3199f93aa10SMichael Shych 	{ "powr1220", powr1220, },
320f4ff4155SScott Kanowitz 	{ }
321f4ff4155SScott Kanowitz };
322f4ff4155SScott Kanowitz 
323f4ff4155SScott Kanowitz MODULE_DEVICE_TABLE(i2c, powr1220_ids);
324f4ff4155SScott Kanowitz 
325f4ff4155SScott Kanowitz static struct i2c_driver powr1220_driver = {
326f4ff4155SScott Kanowitz 	.class		= I2C_CLASS_HWMON,
327f4ff4155SScott Kanowitz 	.driver = {
328f4ff4155SScott Kanowitz 		.name	= "powr1220",
329f4ff4155SScott Kanowitz 	},
330*1975d167SUwe Kleine-König 	.probe		= powr1220_probe,
331f4ff4155SScott Kanowitz 	.id_table	= powr1220_ids,
332f4ff4155SScott Kanowitz };
333f4ff4155SScott Kanowitz 
334f4ff4155SScott Kanowitz module_i2c_driver(powr1220_driver);
335f4ff4155SScott Kanowitz 
336f4ff4155SScott Kanowitz MODULE_AUTHOR("Scott Kanowitz");
337f4ff4155SScott Kanowitz MODULE_DESCRIPTION("POWR1220 driver");
338f4ff4155SScott Kanowitz MODULE_LICENSE("GPL");
339