brintos

brintos / linux-shallow public Read only

0
0
Text · 10.7 KiB · 2f4b419 Raw
440 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3 * Driver for MAX31730 3-Channel Remote Temperature Sensor4 *5 * Copyright (c) 2019 Guenter Roeck <linux@roeck-us.net>6 */7 8#include <linux/bits.h>9#include <linux/err.h>10#include <linux/i2c.h>11#include <linux/init.h>12#include <linux/hwmon.h>13#include <linux/module.h>14#include <linux/of.h>15#include <linux/slab.h>16 17/* Addresses scanned */18static const unsigned short normal_i2c[] = { 0x1c, 0x1d, 0x1e, 0x1f, 0x4c,19					     0x4d, 0x4e, 0x4f, I2C_CLIENT_END };20 21/* The MAX31730 registers */22#define MAX31730_REG_TEMP		0x0023#define MAX31730_REG_CONF		0x1324#define  MAX31730_STOP			BIT(7)25#define  MAX31730_EXTRANGE		BIT(1)26#define MAX31730_REG_TEMP_OFFSET	0x1627#define  MAX31730_TEMP_OFFSET_BASELINE	0x7728#define MAX31730_REG_OFFSET_ENABLE	0x1729#define MAX31730_REG_TEMP_MAX		0x2030#define MAX31730_REG_TEMP_MIN		0x3031#define MAX31730_REG_STATUS_HIGH	0x3232#define MAX31730_REG_STATUS_LOW		0x3333#define MAX31730_REG_CHANNEL_ENABLE	0x3534#define MAX31730_REG_TEMP_FAULT		0x3635 36#define MAX31730_REG_MFG_ID		0x5037#define  MAX31730_MFG_ID		0x4d38#define MAX31730_REG_MFG_REV		0x5139#define  MAX31730_MFG_REV		0x0140 41#define MAX31730_TEMP_MIN		(-128000)42#define MAX31730_TEMP_MAX		12793743 44/* Each client has this additional data */45struct max31730_data {46	struct i2c_client	*client;47	u8			orig_conf;48	u8			current_conf;49	u8			offset_enable;50	u8			channel_enable;51};52 53/*-----------------------------------------------------------------------*/54 55static inline long max31730_reg_to_mc(s16 temp)56{57	return DIV_ROUND_CLOSEST((temp >> 4) * 1000, 16);58}59 60static int max31730_write_config(struct max31730_data *data, u8 set_mask,61				 u8 clr_mask)62{63	u8 value;64 65	clr_mask |= MAX31730_EXTRANGE;66	value = data->current_conf & ~clr_mask;67	value |= set_mask;68 69	if (data->current_conf != value) {70		s32 err;71 72		err = i2c_smbus_write_byte_data(data->client, MAX31730_REG_CONF,73						value);74		if (err)75			return err;76		data->current_conf = value;77	}78	return 0;79}80 81static int max31730_set_enable(struct i2c_client *client, int reg,82			       u8 *confdata, int channel, bool enable)83{84	u8 regval = *confdata;85	int err;86 87	if (enable)88		regval |= BIT(channel);89	else90		regval &= ~BIT(channel);91 92	if (regval != *confdata) {93		err = i2c_smbus_write_byte_data(client, reg, regval);94		if (err)95			return err;96		*confdata = regval;97	}98	return 0;99}100 101static int max31730_set_offset_enable(struct max31730_data *data, int channel,102				      bool enable)103{104	return max31730_set_enable(data->client, MAX31730_REG_OFFSET_ENABLE,105				   &data->offset_enable, channel, enable);106}107 108static int max31730_set_channel_enable(struct max31730_data *data, int channel,109				       bool enable)110{111	return max31730_set_enable(data->client, MAX31730_REG_CHANNEL_ENABLE,112				   &data->channel_enable, channel, enable);113}114 115static int max31730_read(struct device *dev, enum hwmon_sensor_types type,116			 u32 attr, int channel, long *val)117{118	struct max31730_data *data = dev_get_drvdata(dev);119	int regval, reg, offset;120 121	if (type != hwmon_temp)122		return -EINVAL;123 124	switch (attr) {125	case hwmon_temp_input:126		if (!(data->channel_enable & BIT(channel)))127			return -ENODATA;128		reg = MAX31730_REG_TEMP + (channel * 2);129		break;130	case hwmon_temp_max:131		reg = MAX31730_REG_TEMP_MAX + (channel * 2);132		break;133	case hwmon_temp_min:134		reg = MAX31730_REG_TEMP_MIN;135		break;136	case hwmon_temp_enable:137		*val = !!(data->channel_enable & BIT(channel));138		return 0;139	case hwmon_temp_offset:140		if (!channel)141			return -EINVAL;142		if (!(data->offset_enable & BIT(channel))) {143			*val = 0;144			return 0;145		}146		offset = i2c_smbus_read_byte_data(data->client,147						  MAX31730_REG_TEMP_OFFSET);148		if (offset < 0)149			return offset;150		*val = (offset - MAX31730_TEMP_OFFSET_BASELINE) * 125;151		return 0;152	case hwmon_temp_fault:153		regval = i2c_smbus_read_byte_data(data->client,154						  MAX31730_REG_TEMP_FAULT);155		if (regval < 0)156			return regval;157		*val = !!(regval & BIT(channel));158		return 0;159	case hwmon_temp_min_alarm:160		regval = i2c_smbus_read_byte_data(data->client,161						  MAX31730_REG_STATUS_LOW);162		if (regval < 0)163			return regval;164		*val = !!(regval & BIT(channel));165		return 0;166	case hwmon_temp_max_alarm:167		regval = i2c_smbus_read_byte_data(data->client,168						  MAX31730_REG_STATUS_HIGH);169		if (regval < 0)170			return regval;171		*val = !!(regval & BIT(channel));172		return 0;173	default:174		return -EINVAL;175	}176	regval = i2c_smbus_read_word_swapped(data->client, reg);177	if (regval < 0)178		return regval;179 180	*val = max31730_reg_to_mc(regval);181 182	return 0;183}184 185static int max31730_write(struct device *dev, enum hwmon_sensor_types type,186			  u32 attr, int channel, long val)187{188	struct max31730_data *data = dev_get_drvdata(dev);189	int reg, err;190 191	if (type != hwmon_temp)192		return -EINVAL;193 194	switch (attr) {195	case hwmon_temp_max:196		reg = MAX31730_REG_TEMP_MAX + channel * 2;197		break;198	case hwmon_temp_min:199		reg = MAX31730_REG_TEMP_MIN;200		break;201	case hwmon_temp_enable:202		if (val != 0 && val != 1)203			return -EINVAL;204		return max31730_set_channel_enable(data, channel, val);205	case hwmon_temp_offset:206		val = clamp_val(val, -14875, 17000) + 14875;207		val = DIV_ROUND_CLOSEST(val, 125);208		err = max31730_set_offset_enable(data, channel,209					val != MAX31730_TEMP_OFFSET_BASELINE);210		if (err)211			return err;212		return i2c_smbus_write_byte_data(data->client,213						 MAX31730_REG_TEMP_OFFSET, val);214	default:215		return -EINVAL;216	}217 218	val = clamp_val(val, MAX31730_TEMP_MIN, MAX31730_TEMP_MAX);219	val = DIV_ROUND_CLOSEST(val << 4, 1000) << 4;220 221	return i2c_smbus_write_word_swapped(data->client, reg, (u16)val);222}223 224static umode_t max31730_is_visible(const void *data,225				   enum hwmon_sensor_types type,226				   u32 attr, int channel)227{228	switch (type) {229	case hwmon_temp:230		switch (attr) {231		case hwmon_temp_input:232		case hwmon_temp_min_alarm:233		case hwmon_temp_max_alarm:234		case hwmon_temp_fault:235			return 0444;236		case hwmon_temp_min:237			return channel ? 0444 : 0644;238		case hwmon_temp_offset:239		case hwmon_temp_enable:240		case hwmon_temp_max:241			return 0644;242		}243		break;244	default:245		break;246	}247	return 0;248}249 250static const struct hwmon_channel_info * const max31730_info[] = {251	HWMON_CHANNEL_INFO(chip,252			   HWMON_C_REGISTER_TZ),253	HWMON_CHANNEL_INFO(temp,254			   HWMON_T_INPUT | HWMON_T_MIN | HWMON_T_MAX |255			   HWMON_T_ENABLE |256			   HWMON_T_MIN_ALARM | HWMON_T_MAX_ALARM,257			   HWMON_T_INPUT | HWMON_T_MIN | HWMON_T_MAX |258			   HWMON_T_OFFSET | HWMON_T_ENABLE |259			   HWMON_T_MIN_ALARM | HWMON_T_MAX_ALARM |260			   HWMON_T_FAULT,261			   HWMON_T_INPUT | HWMON_T_MIN | HWMON_T_MAX |262			   HWMON_T_OFFSET | HWMON_T_ENABLE |263			   HWMON_T_MIN_ALARM | HWMON_T_MAX_ALARM |264			   HWMON_T_FAULT,265			   HWMON_T_INPUT | HWMON_T_MIN | HWMON_T_MAX |266			   HWMON_T_OFFSET | HWMON_T_ENABLE |267			   HWMON_T_MIN_ALARM | HWMON_T_MAX_ALARM |268			   HWMON_T_FAULT269			   ),270	NULL271};272 273static const struct hwmon_ops max31730_hwmon_ops = {274	.is_visible = max31730_is_visible,275	.read = max31730_read,276	.write = max31730_write,277};278 279static const struct hwmon_chip_info max31730_chip_info = {280	.ops = &max31730_hwmon_ops,281	.info = max31730_info,282};283 284static void max31730_remove(void *data)285{286	struct max31730_data *max31730 = data;287	struct i2c_client *client = max31730->client;288 289	i2c_smbus_write_byte_data(client, MAX31730_REG_CONF,290				  max31730->orig_conf);291}292 293static int294max31730_probe(struct i2c_client *client)295{296	struct device *dev = &client->dev;297	struct device *hwmon_dev;298	struct max31730_data *data;299	int status, err;300 301	if (!i2c_check_functionality(client->adapter,302			I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA))303		return -EIO;304 305	data = devm_kzalloc(dev, sizeof(struct max31730_data), GFP_KERNEL);306	if (!data)307		return -ENOMEM;308 309	data->client = client;310 311	/* Cache original configuration and enable status */312	status = i2c_smbus_read_byte_data(client, MAX31730_REG_CHANNEL_ENABLE);313	if (status < 0)314		return status;315	data->channel_enable = status;316 317	status = i2c_smbus_read_byte_data(client, MAX31730_REG_OFFSET_ENABLE);318	if (status < 0)319		return status;320	data->offset_enable = status;321 322	status = i2c_smbus_read_byte_data(client, MAX31730_REG_CONF);323	if (status < 0)324		return status;325	data->orig_conf = status;326	data->current_conf = status;327 328	err = max31730_write_config(data,329				    data->channel_enable ? 0 : MAX31730_STOP,330				    data->channel_enable ? MAX31730_STOP : 0);331	if (err)332		return err;333 334	dev_set_drvdata(dev, data);335 336	err = devm_add_action_or_reset(dev, max31730_remove, data);337	if (err)338		return err;339 340	hwmon_dev = devm_hwmon_device_register_with_info(dev, client->name,341							 data,342							 &max31730_chip_info,343							 NULL);344	return PTR_ERR_OR_ZERO(hwmon_dev);345}346 347static const struct i2c_device_id max31730_ids[] = {348	{ "max31730" },349	{ }350};351MODULE_DEVICE_TABLE(i2c, max31730_ids);352 353static const struct of_device_id __maybe_unused max31730_of_match[] = {354	{355		.compatible = "maxim,max31730",356	},357	{ },358};359MODULE_DEVICE_TABLE(of, max31730_of_match);360 361static bool max31730_check_reg_temp(struct i2c_client *client,362				    int reg)363{364	int regval;365 366	regval = i2c_smbus_read_byte_data(client, reg + 1);367	return regval < 0 || (regval & 0x0f);368}369 370/* Return 0 if detection is successful, -ENODEV otherwise */371static int max31730_detect(struct i2c_client *client,372			   struct i2c_board_info *info)373{374	struct i2c_adapter *adapter = client->adapter;375	int regval;376	int i;377 378	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA |379				     I2C_FUNC_SMBUS_WORD_DATA))380		return -ENODEV;381 382	regval = i2c_smbus_read_byte_data(client, MAX31730_REG_MFG_ID);383	if (regval != MAX31730_MFG_ID)384		return -ENODEV;385	regval = i2c_smbus_read_byte_data(client, MAX31730_REG_MFG_REV);386	if (regval != MAX31730_MFG_REV)387		return -ENODEV;388 389	/* lower 4 bit of temperature and limit registers must be 0 */390	if (max31730_check_reg_temp(client, MAX31730_REG_TEMP_MIN))391		return -ENODEV;392 393	for (i = 0; i < 4; i++) {394		if (max31730_check_reg_temp(client, MAX31730_REG_TEMP + i * 2))395			return -ENODEV;396		if (max31730_check_reg_temp(client,397					    MAX31730_REG_TEMP_MAX + i * 2))398			return -ENODEV;399	}400 401	strscpy(info->type, "max31730", I2C_NAME_SIZE);402 403	return 0;404}405 406static int max31730_suspend(struct device *dev)407{408	struct max31730_data *data = dev_get_drvdata(dev);409 410	return max31730_write_config(data, MAX31730_STOP, 0);411}412 413static int max31730_resume(struct device *dev)414{415	struct max31730_data *data = dev_get_drvdata(dev);416 417	return max31730_write_config(data, 0, MAX31730_STOP);418}419 420static DEFINE_SIMPLE_DEV_PM_OPS(max31730_pm_ops, max31730_suspend, max31730_resume);421 422static struct i2c_driver max31730_driver = {423	.class		= I2C_CLASS_HWMON,424	.driver = {425		.name	= "max31730",426		.of_match_table = of_match_ptr(max31730_of_match),427		.pm	= pm_sleep_ptr(&max31730_pm_ops),428	},429	.probe		= max31730_probe,430	.id_table	= max31730_ids,431	.detect		= max31730_detect,432	.address_list	= normal_i2c,433};434 435module_i2c_driver(max31730_driver);436 437MODULE_AUTHOR("Guenter Roeck <linux@roeck-us.net>");438MODULE_DESCRIPTION("MAX31730 driver");439MODULE_LICENSE("GPL");440