brintos

brintos / linux-shallow public Read only

0
0
Text · 7.1 KiB · 5f9ca65 Raw
338 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3 * powr1220.c - Driver for the Lattice POWR1220 programmable power supply4 * and monitor. Users can read all ADC inputs along with their labels5 * using the sysfs nodes.6 *7 * Copyright (c) 2014 Echo360 https://www.echo360.com8 * 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			223#define ADC_MAX_LOW_MEASUREMENT_MV	200024 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_REGS56};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_VALUES74};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 for120		 * high inputs or inputs that we don't yet have a measurement121		 * for. We dynamically set the attenuator depending on the122		 * 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 the136		 * conversion to complete137		 */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_t174powr1220_is_visible(const void *data, enum hwmon_sensor_types type, u32175		    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 int201powr1220_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 int222powr1220_read(struct device *dev, enum hwmon_sensor_types type, u32223	      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	NULL269};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 int powr1220_probe(struct i2c_client *client)283{284	struct powr1220_data *data;285	struct device *hwmon_dev;286	enum powr1xxx_chips chip;287 288	if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))289		return -ENODEV;290 291	data = devm_kzalloc(&client->dev, sizeof(*data), GFP_KERNEL);292	if (!data)293		return -ENOMEM;294 295	chip = (uintptr_t)i2c_get_match_data(client);296	switch (chip) {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	.driver = {327		.name	= "powr1220",328	},329	.probe		= powr1220_probe,330	.id_table	= powr1220_ids,331};332 333module_i2c_driver(powr1220_driver);334 335MODULE_AUTHOR("Scott Kanowitz");336MODULE_DESCRIPTION("POWR1220 driver");337MODULE_LICENSE("GPL");338