Linux Audio

Check our new training course

Loading...
Note: File does not exist in v3.1.
  1// SPDX-License-Identifier: GPL-2.0-or-later
  2/*
  3 * powr1220.c - Driver for the Lattice POWR1220 programmable power supply
  4 * and monitor. Users can read all ADC inputs along with their labels
  5 * using the sysfs nodes.
  6 *
  7 * Copyright (c) 2014 Echo360 https://www.echo360.com
  8 * Scott Kanowitz <skanowitz@echo360.com> <scott.kanowitz@gmail.com>
  9 */
 10
 11#include <linux/module.h>
 12#include <linux/init.h>
 13#include <linux/slab.h>
 14#include <linux/jiffies.h>
 15#include <linux/i2c.h>
 16#include <linux/hwmon.h>
 17#include <linux/hwmon-sysfs.h>
 18#include <linux/err.h>
 19#include <linux/mutex.h>
 20#include <linux/delay.h>
 21
 22#define ADC_STEP_MV			2
 23#define ADC_MAX_LOW_MEASUREMENT_MV	2000
 24
 25enum powr1xxx_chips { powr1014, powr1220 };
 26
 27enum powr1220_regs {
 28	VMON_STATUS0,
 29	VMON_STATUS1,
 30	VMON_STATUS2,
 31	OUTPUT_STATUS0,
 32	OUTPUT_STATUS1,
 33	OUTPUT_STATUS2,
 34	INPUT_STATUS,
 35	ADC_VALUE_LOW,
 36	ADC_VALUE_HIGH,
 37	ADC_MUX,
 38	UES_BYTE0,
 39	UES_BYTE1,
 40	UES_BYTE2,
 41	UES_BYTE3,
 42	GP_OUTPUT1,
 43	GP_OUTPUT2,
 44	GP_OUTPUT3,
 45	INPUT_VALUE,
 46	RESET,
 47	TRIM1_TRIM,
 48	TRIM2_TRIM,
 49	TRIM3_TRIM,
 50	TRIM4_TRIM,
 51	TRIM5_TRIM,
 52	TRIM6_TRIM,
 53	TRIM7_TRIM,
 54	TRIM8_TRIM,
 55	MAX_POWR1220_REGS
 56};
 57
 58enum powr1220_adc_values {
 59	VMON1,
 60	VMON2,
 61	VMON3,
 62	VMON4,
 63	VMON5,
 64	VMON6,
 65	VMON7,
 66	VMON8,
 67	VMON9,
 68	VMON10,
 69	VMON11,
 70	VMON12,
 71	VCCA,
 72	VCCINP,
 73	MAX_POWR1220_ADC_VALUES
 74};
 75
 76struct powr1220_data {
 77	struct i2c_client *client;
 78	struct mutex update_lock;
 79	u8 max_channels;
 80	bool adc_valid[MAX_POWR1220_ADC_VALUES];
 81	 /* the next value is in jiffies */
 82	unsigned long adc_last_updated[MAX_POWR1220_ADC_VALUES];
 83
 84	/* values */
 85	int adc_maxes[MAX_POWR1220_ADC_VALUES];
 86	int adc_values[MAX_POWR1220_ADC_VALUES];
 87};
 88
 89static const char * const input_names[] = {
 90	[VMON1]    = "vmon1",
 91	[VMON2]    = "vmon2",
 92	[VMON3]    = "vmon3",
 93	[VMON4]    = "vmon4",
 94	[VMON5]    = "vmon5",
 95	[VMON6]    = "vmon6",
 96	[VMON7]    = "vmon7",
 97	[VMON8]    = "vmon8",
 98	[VMON9]    = "vmon9",
 99	[VMON10]   = "vmon10",
100	[VMON11]   = "vmon11",
101	[VMON12]   = "vmon12",
102	[VCCA]     = "vcca",
103	[VCCINP]   = "vccinp",
104};
105
106/* Reads the specified ADC channel */
107static int powr1220_read_adc(struct device *dev, int ch_num)
108{
109	struct powr1220_data *data = dev_get_drvdata(dev);
110	int reading;
111	int result;
112	int adc_range = 0;
113
114	mutex_lock(&data->update_lock);
115
116	if (time_after(jiffies, data->adc_last_updated[ch_num] + HZ) ||
117	    !data->adc_valid[ch_num]) {
118		/*
119		 * figure out if we need to use the attenuator for
120		 * high inputs or inputs that we don't yet have a measurement
121		 * for. We dynamically set the attenuator depending on the
122		 * max reading.
123		 */
124		if (data->adc_maxes[ch_num] > ADC_MAX_LOW_MEASUREMENT_MV ||
125		    data->adc_maxes[ch_num] == 0)
126			adc_range = 1 << 4;
127
128		/* set the attenuator and mux */
129		result = i2c_smbus_write_byte_data(data->client, ADC_MUX,
130						   adc_range | ch_num);
131		if (result)
132			goto exit;
133
134		/*
135		 * wait at least Tconvert time (200 us) for the
136		 * conversion to complete
137		 */
138		udelay(200);
139
140		/* get the ADC reading */
141		result = i2c_smbus_read_byte_data(data->client, ADC_VALUE_LOW);
142		if (result < 0)
143			goto exit;
144
145		reading = result >> 4;
146
147		/* get the upper half of the reading */
148		result = i2c_smbus_read_byte_data(data->client, ADC_VALUE_HIGH);
149		if (result < 0)
150			goto exit;
151
152		reading |= result << 4;
153
154		/* now convert the reading to a voltage */
155		reading *= ADC_STEP_MV;
156		data->adc_values[ch_num] = reading;
157		data->adc_valid[ch_num] = true;
158		data->adc_last_updated[ch_num] = jiffies;
159		result = reading;
160
161		if (reading > data->adc_maxes[ch_num])
162			data->adc_maxes[ch_num] = reading;
163	} else {
164		result = data->adc_values[ch_num];
165	}
166
167exit:
168	mutex_unlock(&data->update_lock);
169
170	return result;
171}
172
173static umode_t
174powr1220_is_visible(const void *data, enum hwmon_sensor_types type, u32
175		    attr, int channel)
176{
177	struct powr1220_data *chip_data = (struct powr1220_data *)data;
178
179	if (channel >= chip_data->max_channels)
180		return 0;
181
182	switch (type) {
183	case hwmon_in:
184		switch (attr) {
185		case hwmon_in_input:
186		case hwmon_in_highest:
187		case hwmon_in_label:
188			return 0444;
189		default:
190			break;
191		}
192		break;
193	default:
194		break;
195	}
196
197	return 0;
198}
199
200static int
201powr1220_read_string(struct device *dev, enum hwmon_sensor_types type, u32 attr,
202		     int channel, const char **str)
203{
204	switch (type) {
205	case hwmon_in:
206		switch (attr) {
207		case hwmon_in_label:
208			*str = input_names[channel];
209			return 0;
210		default:
211			return -EOPNOTSUPP;
212		}
213		break;
214	default:
215		return -EOPNOTSUPP;
216	}
217
218	return -EOPNOTSUPP;
219}
220
221static int
222powr1220_read(struct device *dev, enum hwmon_sensor_types type, u32
223	      attr, int channel, long *val)
224{
225	struct powr1220_data *data = dev_get_drvdata(dev);
226	int ret;
227
228	switch (type) {
229	case hwmon_in:
230		switch (attr) {
231		case hwmon_in_input:
232			ret = powr1220_read_adc(dev, channel);
233			if (ret < 0)
234				return ret;
235			*val = ret;
236			break;
237		case hwmon_in_highest:
238			*val = data->adc_maxes[channel];
239			break;
240		default:
241			return -EOPNOTSUPP;
242		}
243		break;
244	default:
245		return -EOPNOTSUPP;
246}
247
248	return 0;
249}
250
251static const struct hwmon_channel_info * const powr1220_info[] = {
252	HWMON_CHANNEL_INFO(in,
253			   HWMON_I_INPUT | HWMON_I_HIGHEST | HWMON_I_LABEL,
254			   HWMON_I_INPUT | HWMON_I_HIGHEST | HWMON_I_LABEL,
255			   HWMON_I_INPUT | HWMON_I_HIGHEST | HWMON_I_LABEL,
256			   HWMON_I_INPUT | HWMON_I_HIGHEST | HWMON_I_LABEL,
257			   HWMON_I_INPUT | HWMON_I_HIGHEST | HWMON_I_LABEL,
258			   HWMON_I_INPUT | HWMON_I_HIGHEST | HWMON_I_LABEL,
259			   HWMON_I_INPUT | HWMON_I_HIGHEST | HWMON_I_LABEL,
260			   HWMON_I_INPUT | HWMON_I_HIGHEST | HWMON_I_LABEL,
261			   HWMON_I_INPUT | HWMON_I_HIGHEST | HWMON_I_LABEL,
262			   HWMON_I_INPUT | HWMON_I_HIGHEST | HWMON_I_LABEL,
263			   HWMON_I_INPUT | HWMON_I_HIGHEST | HWMON_I_LABEL,
264			   HWMON_I_INPUT | HWMON_I_HIGHEST | HWMON_I_LABEL,
265			   HWMON_I_INPUT | HWMON_I_HIGHEST | HWMON_I_LABEL,
266			   HWMON_I_INPUT | HWMON_I_HIGHEST | HWMON_I_LABEL),
267
268	NULL
269};
270
271static const struct hwmon_ops powr1220_hwmon_ops = {
272	.read = powr1220_read,
273	.read_string = powr1220_read_string,
274	.is_visible = powr1220_is_visible,
275};
276
277static const struct hwmon_chip_info powr1220_chip_info = {
278	.ops = &powr1220_hwmon_ops,
279	.info = powr1220_info,
280};
281
282static const struct i2c_device_id powr1220_ids[];
283
284static int powr1220_probe(struct i2c_client *client)
285{
286	struct powr1220_data *data;
287	struct device *hwmon_dev;
288
289	if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
290		return -ENODEV;
291
292	data = devm_kzalloc(&client->dev, sizeof(*data), GFP_KERNEL);
293	if (!data)
294		return -ENOMEM;
295
296	switch (i2c_match_id(powr1220_ids, client)->driver_data) {
297	case powr1014:
298		data->max_channels = 10;
299		break;
300	default:
301		data->max_channels = 12;
302		break;
303	}
304
305	mutex_init(&data->update_lock);
306	data->client = client;
307
308	hwmon_dev = devm_hwmon_device_register_with_info(&client->dev,
309							 client->name,
310							 data,
311							 &powr1220_chip_info,
312							 NULL);
313
314	return PTR_ERR_OR_ZERO(hwmon_dev);
315}
316
317static const struct i2c_device_id powr1220_ids[] = {
318	{ "powr1014", powr1014, },
319	{ "powr1220", powr1220, },
320	{ }
321};
322
323MODULE_DEVICE_TABLE(i2c, powr1220_ids);
324
325static struct i2c_driver powr1220_driver = {
326	.class		= I2C_CLASS_HWMON,
327	.driver = {
328		.name	= "powr1220",
329	},
330	.probe		= powr1220_probe,
331	.id_table	= powr1220_ids,
332};
333
334module_i2c_driver(powr1220_driver);
335
336MODULE_AUTHOR("Scott Kanowitz");
337MODULE_DESCRIPTION("POWR1220 driver");
338MODULE_LICENSE("GPL");