| // SPDX-License-Identifier: GPL-2.0-or-later | 
 | /* | 
 |  * powr1220.c - Driver for the Lattice POWR1220 programmable power supply | 
 |  * and monitor. Users can read all ADC inputs along with their labels | 
 |  * using the sysfs nodes. | 
 |  * | 
 |  * Copyright (c) 2014 Echo360 https://www.echo360.com | 
 |  * Scott Kanowitz <skanowitz@echo360.com> <scott.kanowitz@gmail.com> | 
 |  */ | 
 |  | 
 | #include <linux/module.h> | 
 | #include <linux/init.h> | 
 | #include <linux/slab.h> | 
 | #include <linux/jiffies.h> | 
 | #include <linux/i2c.h> | 
 | #include <linux/hwmon.h> | 
 | #include <linux/hwmon-sysfs.h> | 
 | #include <linux/err.h> | 
 | #include <linux/mutex.h> | 
 | #include <linux/delay.h> | 
 |  | 
 | #define ADC_STEP_MV			2 | 
 | #define ADC_MAX_LOW_MEASUREMENT_MV	2000 | 
 |  | 
 | enum powr1xxx_chips { powr1014, powr1220 }; | 
 |  | 
 | enum powr1220_regs { | 
 | 	VMON_STATUS0, | 
 | 	VMON_STATUS1, | 
 | 	VMON_STATUS2, | 
 | 	OUTPUT_STATUS0, | 
 | 	OUTPUT_STATUS1, | 
 | 	OUTPUT_STATUS2, | 
 | 	INPUT_STATUS, | 
 | 	ADC_VALUE_LOW, | 
 | 	ADC_VALUE_HIGH, | 
 | 	ADC_MUX, | 
 | 	UES_BYTE0, | 
 | 	UES_BYTE1, | 
 | 	UES_BYTE2, | 
 | 	UES_BYTE3, | 
 | 	GP_OUTPUT1, | 
 | 	GP_OUTPUT2, | 
 | 	GP_OUTPUT3, | 
 | 	INPUT_VALUE, | 
 | 	RESET, | 
 | 	TRIM1_TRIM, | 
 | 	TRIM2_TRIM, | 
 | 	TRIM3_TRIM, | 
 | 	TRIM4_TRIM, | 
 | 	TRIM5_TRIM, | 
 | 	TRIM6_TRIM, | 
 | 	TRIM7_TRIM, | 
 | 	TRIM8_TRIM, | 
 | 	MAX_POWR1220_REGS | 
 | }; | 
 |  | 
 | enum powr1220_adc_values { | 
 | 	VMON1, | 
 | 	VMON2, | 
 | 	VMON3, | 
 | 	VMON4, | 
 | 	VMON5, | 
 | 	VMON6, | 
 | 	VMON7, | 
 | 	VMON8, | 
 | 	VMON9, | 
 | 	VMON10, | 
 | 	VMON11, | 
 | 	VMON12, | 
 | 	VCCA, | 
 | 	VCCINP, | 
 | 	MAX_POWR1220_ADC_VALUES | 
 | }; | 
 |  | 
 | struct powr1220_data { | 
 | 	struct i2c_client *client; | 
 | 	struct mutex update_lock; | 
 | 	u8 max_channels; | 
 | 	bool adc_valid[MAX_POWR1220_ADC_VALUES]; | 
 | 	 /* the next value is in jiffies */ | 
 | 	unsigned long adc_last_updated[MAX_POWR1220_ADC_VALUES]; | 
 |  | 
 | 	/* values */ | 
 | 	int adc_maxes[MAX_POWR1220_ADC_VALUES]; | 
 | 	int adc_values[MAX_POWR1220_ADC_VALUES]; | 
 | }; | 
 |  | 
 | static const char * const input_names[] = { | 
 | 	[VMON1]    = "vmon1", | 
 | 	[VMON2]    = "vmon2", | 
 | 	[VMON3]    = "vmon3", | 
 | 	[VMON4]    = "vmon4", | 
 | 	[VMON5]    = "vmon5", | 
 | 	[VMON6]    = "vmon6", | 
 | 	[VMON7]    = "vmon7", | 
 | 	[VMON8]    = "vmon8", | 
 | 	[VMON9]    = "vmon9", | 
 | 	[VMON10]   = "vmon10", | 
 | 	[VMON11]   = "vmon11", | 
 | 	[VMON12]   = "vmon12", | 
 | 	[VCCA]     = "vcca", | 
 | 	[VCCINP]   = "vccinp", | 
 | }; | 
 |  | 
 | /* Reads the specified ADC channel */ | 
 | static int powr1220_read_adc(struct device *dev, int ch_num) | 
 | { | 
 | 	struct powr1220_data *data = dev_get_drvdata(dev); | 
 | 	int reading; | 
 | 	int result; | 
 | 	int adc_range = 0; | 
 |  | 
 | 	mutex_lock(&data->update_lock); | 
 |  | 
 | 	if (time_after(jiffies, data->adc_last_updated[ch_num] + HZ) || | 
 | 	    !data->adc_valid[ch_num]) { | 
 | 		/* | 
 | 		 * figure out if we need to use the attenuator for | 
 | 		 * high inputs or inputs that we don't yet have a measurement | 
 | 		 * for. We dynamically set the attenuator depending on the | 
 | 		 * max reading. | 
 | 		 */ | 
 | 		if (data->adc_maxes[ch_num] > ADC_MAX_LOW_MEASUREMENT_MV || | 
 | 		    data->adc_maxes[ch_num] == 0) | 
 | 			adc_range = 1 << 4; | 
 |  | 
 | 		/* set the attenuator and mux */ | 
 | 		result = i2c_smbus_write_byte_data(data->client, ADC_MUX, | 
 | 						   adc_range | ch_num); | 
 | 		if (result) | 
 | 			goto exit; | 
 |  | 
 | 		/* | 
 | 		 * wait at least Tconvert time (200 us) for the | 
 | 		 * conversion to complete | 
 | 		 */ | 
 | 		udelay(200); | 
 |  | 
 | 		/* get the ADC reading */ | 
 | 		result = i2c_smbus_read_byte_data(data->client, ADC_VALUE_LOW); | 
 | 		if (result < 0) | 
 | 			goto exit; | 
 |  | 
 | 		reading = result >> 4; | 
 |  | 
 | 		/* get the upper half of the reading */ | 
 | 		result = i2c_smbus_read_byte_data(data->client, ADC_VALUE_HIGH); | 
 | 		if (result < 0) | 
 | 			goto exit; | 
 |  | 
 | 		reading |= result << 4; | 
 |  | 
 | 		/* now convert the reading to a voltage */ | 
 | 		reading *= ADC_STEP_MV; | 
 | 		data->adc_values[ch_num] = reading; | 
 | 		data->adc_valid[ch_num] = true; | 
 | 		data->adc_last_updated[ch_num] = jiffies; | 
 | 		result = reading; | 
 |  | 
 | 		if (reading > data->adc_maxes[ch_num]) | 
 | 			data->adc_maxes[ch_num] = reading; | 
 | 	} else { | 
 | 		result = data->adc_values[ch_num]; | 
 | 	} | 
 |  | 
 | exit: | 
 | 	mutex_unlock(&data->update_lock); | 
 |  | 
 | 	return result; | 
 | } | 
 |  | 
 | static umode_t | 
 | powr1220_is_visible(const void *data, enum hwmon_sensor_types type, u32 | 
 | 		    attr, int channel) | 
 | { | 
 | 	struct powr1220_data *chip_data = (struct powr1220_data *)data; | 
 |  | 
 | 	if (channel >= chip_data->max_channels) | 
 | 		return 0; | 
 |  | 
 | 	switch (type) { | 
 | 	case hwmon_in: | 
 | 		switch (attr) { | 
 | 		case hwmon_in_input: | 
 | 		case hwmon_in_highest: | 
 | 		case hwmon_in_label: | 
 | 			return 0444; | 
 | 		default: | 
 | 			break; | 
 | 		} | 
 | 		break; | 
 | 	default: | 
 | 		break; | 
 | 	} | 
 |  | 
 | 	return 0; | 
 | } | 
 |  | 
 | static int | 
 | powr1220_read_string(struct device *dev, enum hwmon_sensor_types type, u32 attr, | 
 | 		     int channel, const char **str) | 
 | { | 
 | 	switch (type) { | 
 | 	case hwmon_in: | 
 | 		switch (attr) { | 
 | 		case hwmon_in_label: | 
 | 			*str = input_names[channel]; | 
 | 			return 0; | 
 | 		default: | 
 | 			return -EOPNOTSUPP; | 
 | 		} | 
 | 		break; | 
 | 	default: | 
 | 		return -EOPNOTSUPP; | 
 | 	} | 
 |  | 
 | 	return -EOPNOTSUPP; | 
 | } | 
 |  | 
 | static int | 
 | powr1220_read(struct device *dev, enum hwmon_sensor_types type, u32 | 
 | 	      attr, int channel, long *val) | 
 | { | 
 | 	struct powr1220_data *data = dev_get_drvdata(dev); | 
 | 	int ret; | 
 |  | 
 | 	switch (type) { | 
 | 	case hwmon_in: | 
 | 		switch (attr) { | 
 | 		case hwmon_in_input: | 
 | 			ret = powr1220_read_adc(dev, channel); | 
 | 			if (ret < 0) | 
 | 				return ret; | 
 | 			*val = ret; | 
 | 			break; | 
 | 		case hwmon_in_highest: | 
 | 			*val = data->adc_maxes[channel]; | 
 | 			break; | 
 | 		default: | 
 | 			return -EOPNOTSUPP; | 
 | 		} | 
 | 		break; | 
 | 	default: | 
 | 		return -EOPNOTSUPP; | 
 | } | 
 |  | 
 | 	return 0; | 
 | } | 
 |  | 
 | static const struct hwmon_channel_info *powr1220_info[] = { | 
 | 	HWMON_CHANNEL_INFO(in, | 
 | 			   HWMON_I_INPUT | HWMON_I_HIGHEST | HWMON_I_LABEL, | 
 | 			   HWMON_I_INPUT | HWMON_I_HIGHEST | HWMON_I_LABEL, | 
 | 			   HWMON_I_INPUT | HWMON_I_HIGHEST | HWMON_I_LABEL, | 
 | 			   HWMON_I_INPUT | HWMON_I_HIGHEST | HWMON_I_LABEL, | 
 | 			   HWMON_I_INPUT | HWMON_I_HIGHEST | HWMON_I_LABEL, | 
 | 			   HWMON_I_INPUT | HWMON_I_HIGHEST | HWMON_I_LABEL, | 
 | 			   HWMON_I_INPUT | HWMON_I_HIGHEST | HWMON_I_LABEL, | 
 | 			   HWMON_I_INPUT | HWMON_I_HIGHEST | HWMON_I_LABEL, | 
 | 			   HWMON_I_INPUT | HWMON_I_HIGHEST | HWMON_I_LABEL, | 
 | 			   HWMON_I_INPUT | HWMON_I_HIGHEST | HWMON_I_LABEL, | 
 | 			   HWMON_I_INPUT | HWMON_I_HIGHEST | HWMON_I_LABEL, | 
 | 			   HWMON_I_INPUT | HWMON_I_HIGHEST | HWMON_I_LABEL, | 
 | 			   HWMON_I_INPUT | HWMON_I_HIGHEST | HWMON_I_LABEL, | 
 | 			   HWMON_I_INPUT | HWMON_I_HIGHEST | HWMON_I_LABEL), | 
 |  | 
 | 	NULL | 
 | }; | 
 |  | 
 | static const struct hwmon_ops powr1220_hwmon_ops = { | 
 | 	.read = powr1220_read, | 
 | 	.read_string = powr1220_read_string, | 
 | 	.is_visible = powr1220_is_visible, | 
 | }; | 
 |  | 
 | static const struct hwmon_chip_info powr1220_chip_info = { | 
 | 	.ops = &powr1220_hwmon_ops, | 
 | 	.info = powr1220_info, | 
 | }; | 
 |  | 
 | static const struct i2c_device_id powr1220_ids[]; | 
 |  | 
 | static int powr1220_probe(struct i2c_client *client) | 
 | { | 
 | 	struct powr1220_data *data; | 
 | 	struct device *hwmon_dev; | 
 |  | 
 | 	if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) | 
 | 		return -ENODEV; | 
 |  | 
 | 	data = devm_kzalloc(&client->dev, sizeof(*data), GFP_KERNEL); | 
 | 	if (!data) | 
 | 		return -ENOMEM; | 
 |  | 
 | 	switch (i2c_match_id(powr1220_ids, client)->driver_data) { | 
 | 	case powr1014: | 
 | 		data->max_channels = 10; | 
 | 		break; | 
 | 	default: | 
 | 		data->max_channels = 12; | 
 | 		break; | 
 | 	} | 
 |  | 
 | 	mutex_init(&data->update_lock); | 
 | 	data->client = client; | 
 |  | 
 | 	hwmon_dev = devm_hwmon_device_register_with_info(&client->dev, | 
 | 							 client->name, | 
 | 							 data, | 
 | 							 &powr1220_chip_info, | 
 | 							 NULL); | 
 |  | 
 | 	return PTR_ERR_OR_ZERO(hwmon_dev); | 
 | } | 
 |  | 
 | static const struct i2c_device_id powr1220_ids[] = { | 
 | 	{ "powr1014", powr1014, }, | 
 | 	{ "powr1220", powr1220, }, | 
 | 	{ } | 
 | }; | 
 |  | 
 | MODULE_DEVICE_TABLE(i2c, powr1220_ids); | 
 |  | 
 | static struct i2c_driver powr1220_driver = { | 
 | 	.class		= I2C_CLASS_HWMON, | 
 | 	.driver = { | 
 | 		.name	= "powr1220", | 
 | 	}, | 
 | 	.probe_new	= powr1220_probe, | 
 | 	.id_table	= powr1220_ids, | 
 | }; | 
 |  | 
 | module_i2c_driver(powr1220_driver); | 
 |  | 
 | MODULE_AUTHOR("Scott Kanowitz"); | 
 | MODULE_DESCRIPTION("POWR1220 driver"); | 
 | MODULE_LICENSE("GPL"); |