162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
262306a36Sopenharmony_ci/* tmp421.c
362306a36Sopenharmony_ci *
462306a36Sopenharmony_ci * Copyright (C) 2009 Andre Prendel <andre.prendel@gmx.de>
562306a36Sopenharmony_ci * Preliminary support by:
662306a36Sopenharmony_ci * Melvin Rook, Raymond Ng
762306a36Sopenharmony_ci */
862306a36Sopenharmony_ci
962306a36Sopenharmony_ci/*
1062306a36Sopenharmony_ci * Driver for the Texas Instruments TMP421 SMBus temperature sensor IC.
1162306a36Sopenharmony_ci * Supported models: TMP421, TMP422, TMP423, TMP441, TMP442
1262306a36Sopenharmony_ci */
1362306a36Sopenharmony_ci
1462306a36Sopenharmony_ci#include <linux/module.h>
1562306a36Sopenharmony_ci#include <linux/init.h>
1662306a36Sopenharmony_ci#include <linux/slab.h>
1762306a36Sopenharmony_ci#include <linux/jiffies.h>
1862306a36Sopenharmony_ci#include <linux/i2c.h>
1962306a36Sopenharmony_ci#include <linux/hwmon.h>
2062306a36Sopenharmony_ci#include <linux/hwmon-sysfs.h>
2162306a36Sopenharmony_ci#include <linux/err.h>
2262306a36Sopenharmony_ci#include <linux/mutex.h>
2362306a36Sopenharmony_ci#include <linux/of.h>
2462306a36Sopenharmony_ci#include <linux/sysfs.h>
2562306a36Sopenharmony_ci
2662306a36Sopenharmony_ci/* Addresses to scan */
2762306a36Sopenharmony_cistatic const unsigned short normal_i2c[] = { 0x2a, 0x4c, 0x4d, 0x4e, 0x4f,
2862306a36Sopenharmony_ci					     I2C_CLIENT_END };
2962306a36Sopenharmony_ci
3062306a36Sopenharmony_cienum chips { tmp421, tmp422, tmp423, tmp441, tmp442 };
3162306a36Sopenharmony_ci
3262306a36Sopenharmony_ci#define MAX_CHANNELS				4
3362306a36Sopenharmony_ci/* The TMP421 registers */
3462306a36Sopenharmony_ci#define TMP421_STATUS_REG			0x08
3562306a36Sopenharmony_ci#define TMP421_CONFIG_REG_1			0x09
3662306a36Sopenharmony_ci#define TMP421_CONFIG_REG_2			0x0A
3762306a36Sopenharmony_ci#define TMP421_CONFIG_REG_REN(x)		(BIT(3 + (x)))
3862306a36Sopenharmony_ci#define TMP421_CONFIG_REG_REN_MASK		GENMASK(6, 3)
3962306a36Sopenharmony_ci#define TMP421_CONVERSION_RATE_REG		0x0B
4062306a36Sopenharmony_ci#define TMP421_N_FACTOR_REG_1			0x21
4162306a36Sopenharmony_ci#define TMP421_MANUFACTURER_ID_REG		0xFE
4262306a36Sopenharmony_ci#define TMP421_DEVICE_ID_REG			0xFF
4362306a36Sopenharmony_ci
4462306a36Sopenharmony_cistatic const u8 TMP421_TEMP_MSB[MAX_CHANNELS]	= { 0x00, 0x01, 0x02, 0x03 };
4562306a36Sopenharmony_cistatic const u8 TMP421_TEMP_LSB[MAX_CHANNELS]	= { 0x10, 0x11, 0x12, 0x13 };
4662306a36Sopenharmony_ci
4762306a36Sopenharmony_ci/* Flags */
4862306a36Sopenharmony_ci#define TMP421_CONFIG_SHUTDOWN			0x40
4962306a36Sopenharmony_ci#define TMP421_CONFIG_RANGE			0x04
5062306a36Sopenharmony_ci
5162306a36Sopenharmony_ci/* Manufacturer / Device ID's */
5262306a36Sopenharmony_ci#define TMP421_MANUFACTURER_ID			0x55
5362306a36Sopenharmony_ci#define TMP421_DEVICE_ID			0x21
5462306a36Sopenharmony_ci#define TMP422_DEVICE_ID			0x22
5562306a36Sopenharmony_ci#define TMP423_DEVICE_ID			0x23
5662306a36Sopenharmony_ci#define TMP441_DEVICE_ID			0x41
5762306a36Sopenharmony_ci#define TMP442_DEVICE_ID			0x42
5862306a36Sopenharmony_ci
5962306a36Sopenharmony_cistatic const struct i2c_device_id tmp421_id[] = {
6062306a36Sopenharmony_ci	{ "tmp421", 2 },
6162306a36Sopenharmony_ci	{ "tmp422", 3 },
6262306a36Sopenharmony_ci	{ "tmp423", 4 },
6362306a36Sopenharmony_ci	{ "tmp441", 2 },
6462306a36Sopenharmony_ci	{ "tmp442", 3 },
6562306a36Sopenharmony_ci	{ }
6662306a36Sopenharmony_ci};
6762306a36Sopenharmony_ciMODULE_DEVICE_TABLE(i2c, tmp421_id);
6862306a36Sopenharmony_ci
6962306a36Sopenharmony_cistatic const struct of_device_id __maybe_unused tmp421_of_match[] = {
7062306a36Sopenharmony_ci	{
7162306a36Sopenharmony_ci		.compatible = "ti,tmp421",
7262306a36Sopenharmony_ci		.data = (void *)2
7362306a36Sopenharmony_ci	},
7462306a36Sopenharmony_ci	{
7562306a36Sopenharmony_ci		.compatible = "ti,tmp422",
7662306a36Sopenharmony_ci		.data = (void *)3
7762306a36Sopenharmony_ci	},
7862306a36Sopenharmony_ci	{
7962306a36Sopenharmony_ci		.compatible = "ti,tmp423",
8062306a36Sopenharmony_ci		.data = (void *)4
8162306a36Sopenharmony_ci	},
8262306a36Sopenharmony_ci	{
8362306a36Sopenharmony_ci		.compatible = "ti,tmp441",
8462306a36Sopenharmony_ci		.data = (void *)2
8562306a36Sopenharmony_ci	},
8662306a36Sopenharmony_ci	{
8762306a36Sopenharmony_ci		.compatible = "ti,tmp442",
8862306a36Sopenharmony_ci		.data = (void *)3
8962306a36Sopenharmony_ci	},
9062306a36Sopenharmony_ci	{ },
9162306a36Sopenharmony_ci};
9262306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, tmp421_of_match);
9362306a36Sopenharmony_ci
9462306a36Sopenharmony_cistruct tmp421_channel {
9562306a36Sopenharmony_ci	const char *label;
9662306a36Sopenharmony_ci	bool enabled;
9762306a36Sopenharmony_ci	s16 temp;
9862306a36Sopenharmony_ci};
9962306a36Sopenharmony_ci
10062306a36Sopenharmony_cistruct tmp421_data {
10162306a36Sopenharmony_ci	struct i2c_client *client;
10262306a36Sopenharmony_ci	struct mutex update_lock;
10362306a36Sopenharmony_ci	u32 temp_config[MAX_CHANNELS + 1];
10462306a36Sopenharmony_ci	struct hwmon_channel_info temp_info;
10562306a36Sopenharmony_ci	const struct hwmon_channel_info *info[2];
10662306a36Sopenharmony_ci	struct hwmon_chip_info chip;
10762306a36Sopenharmony_ci	bool valid;
10862306a36Sopenharmony_ci	unsigned long last_updated;
10962306a36Sopenharmony_ci	unsigned long channels;
11062306a36Sopenharmony_ci	u8 config;
11162306a36Sopenharmony_ci	struct tmp421_channel channel[MAX_CHANNELS];
11262306a36Sopenharmony_ci};
11362306a36Sopenharmony_ci
11462306a36Sopenharmony_cistatic int temp_from_raw(u16 reg, bool extended)
11562306a36Sopenharmony_ci{
11662306a36Sopenharmony_ci	/* Mask out status bits */
11762306a36Sopenharmony_ci	int temp = reg & ~0xf;
11862306a36Sopenharmony_ci
11962306a36Sopenharmony_ci	if (extended)
12062306a36Sopenharmony_ci		temp = temp - 64 * 256;
12162306a36Sopenharmony_ci	else
12262306a36Sopenharmony_ci		temp = (s16)temp;
12362306a36Sopenharmony_ci
12462306a36Sopenharmony_ci	return DIV_ROUND_CLOSEST(temp * 1000, 256);
12562306a36Sopenharmony_ci}
12662306a36Sopenharmony_ci
12762306a36Sopenharmony_cistatic int tmp421_update_device(struct tmp421_data *data)
12862306a36Sopenharmony_ci{
12962306a36Sopenharmony_ci	struct i2c_client *client = data->client;
13062306a36Sopenharmony_ci	int ret = 0;
13162306a36Sopenharmony_ci	int i;
13262306a36Sopenharmony_ci
13362306a36Sopenharmony_ci	mutex_lock(&data->update_lock);
13462306a36Sopenharmony_ci
13562306a36Sopenharmony_ci	if (time_after(jiffies, data->last_updated + (HZ / 2)) ||
13662306a36Sopenharmony_ci	    !data->valid) {
13762306a36Sopenharmony_ci		ret = i2c_smbus_read_byte_data(client, TMP421_CONFIG_REG_1);
13862306a36Sopenharmony_ci		if (ret < 0)
13962306a36Sopenharmony_ci			goto exit;
14062306a36Sopenharmony_ci		data->config = ret;
14162306a36Sopenharmony_ci
14262306a36Sopenharmony_ci		for (i = 0; i < data->channels; i++) {
14362306a36Sopenharmony_ci			ret = i2c_smbus_read_byte_data(client, TMP421_TEMP_MSB[i]);
14462306a36Sopenharmony_ci			if (ret < 0)
14562306a36Sopenharmony_ci				goto exit;
14662306a36Sopenharmony_ci			data->channel[i].temp = ret << 8;
14762306a36Sopenharmony_ci
14862306a36Sopenharmony_ci			ret = i2c_smbus_read_byte_data(client, TMP421_TEMP_LSB[i]);
14962306a36Sopenharmony_ci			if (ret < 0)
15062306a36Sopenharmony_ci				goto exit;
15162306a36Sopenharmony_ci			data->channel[i].temp |= ret;
15262306a36Sopenharmony_ci		}
15362306a36Sopenharmony_ci		data->last_updated = jiffies;
15462306a36Sopenharmony_ci		data->valid = true;
15562306a36Sopenharmony_ci	}
15662306a36Sopenharmony_ci
15762306a36Sopenharmony_ciexit:
15862306a36Sopenharmony_ci	mutex_unlock(&data->update_lock);
15962306a36Sopenharmony_ci
16062306a36Sopenharmony_ci	if (ret < 0) {
16162306a36Sopenharmony_ci		data->valid = false;
16262306a36Sopenharmony_ci		return ret;
16362306a36Sopenharmony_ci	}
16462306a36Sopenharmony_ci
16562306a36Sopenharmony_ci	return 0;
16662306a36Sopenharmony_ci}
16762306a36Sopenharmony_ci
16862306a36Sopenharmony_cistatic int tmp421_enable_channels(struct tmp421_data *data)
16962306a36Sopenharmony_ci{
17062306a36Sopenharmony_ci	int err;
17162306a36Sopenharmony_ci	struct i2c_client *client = data->client;
17262306a36Sopenharmony_ci	struct device *dev = &client->dev;
17362306a36Sopenharmony_ci	int old = i2c_smbus_read_byte_data(client, TMP421_CONFIG_REG_2);
17462306a36Sopenharmony_ci	int new, i;
17562306a36Sopenharmony_ci
17662306a36Sopenharmony_ci	if (old < 0) {
17762306a36Sopenharmony_ci		dev_err(dev, "error reading register, can't disable channels\n");
17862306a36Sopenharmony_ci		return old;
17962306a36Sopenharmony_ci	}
18062306a36Sopenharmony_ci
18162306a36Sopenharmony_ci	new = old & ~TMP421_CONFIG_REG_REN_MASK;
18262306a36Sopenharmony_ci	for (i = 0; i < data->channels; i++)
18362306a36Sopenharmony_ci		if (data->channel[i].enabled)
18462306a36Sopenharmony_ci			new |= TMP421_CONFIG_REG_REN(i);
18562306a36Sopenharmony_ci
18662306a36Sopenharmony_ci	if (new == old)
18762306a36Sopenharmony_ci		return 0;
18862306a36Sopenharmony_ci
18962306a36Sopenharmony_ci	err = i2c_smbus_write_byte_data(client, TMP421_CONFIG_REG_2, new);
19062306a36Sopenharmony_ci	if (err < 0)
19162306a36Sopenharmony_ci		dev_err(dev, "error writing register, can't disable channels\n");
19262306a36Sopenharmony_ci
19362306a36Sopenharmony_ci	return err;
19462306a36Sopenharmony_ci}
19562306a36Sopenharmony_ci
19662306a36Sopenharmony_cistatic int tmp421_read(struct device *dev, enum hwmon_sensor_types type,
19762306a36Sopenharmony_ci		       u32 attr, int channel, long *val)
19862306a36Sopenharmony_ci{
19962306a36Sopenharmony_ci	struct tmp421_data *tmp421 = dev_get_drvdata(dev);
20062306a36Sopenharmony_ci	int ret = 0;
20162306a36Sopenharmony_ci
20262306a36Sopenharmony_ci	ret = tmp421_update_device(tmp421);
20362306a36Sopenharmony_ci	if (ret)
20462306a36Sopenharmony_ci		return ret;
20562306a36Sopenharmony_ci
20662306a36Sopenharmony_ci	switch (attr) {
20762306a36Sopenharmony_ci	case hwmon_temp_input:
20862306a36Sopenharmony_ci		if (!tmp421->channel[channel].enabled)
20962306a36Sopenharmony_ci			return -ENODATA;
21062306a36Sopenharmony_ci		*val = temp_from_raw(tmp421->channel[channel].temp,
21162306a36Sopenharmony_ci				     tmp421->config & TMP421_CONFIG_RANGE);
21262306a36Sopenharmony_ci		return 0;
21362306a36Sopenharmony_ci	case hwmon_temp_fault:
21462306a36Sopenharmony_ci		if (!tmp421->channel[channel].enabled)
21562306a36Sopenharmony_ci			return -ENODATA;
21662306a36Sopenharmony_ci		/*
21762306a36Sopenharmony_ci		 * Any of OPEN or /PVLD bits indicate a hardware mulfunction
21862306a36Sopenharmony_ci		 * and the conversion result may be incorrect
21962306a36Sopenharmony_ci		 */
22062306a36Sopenharmony_ci		*val = !!(tmp421->channel[channel].temp & 0x03);
22162306a36Sopenharmony_ci		return 0;
22262306a36Sopenharmony_ci	case hwmon_temp_enable:
22362306a36Sopenharmony_ci		*val = tmp421->channel[channel].enabled;
22462306a36Sopenharmony_ci		return 0;
22562306a36Sopenharmony_ci	default:
22662306a36Sopenharmony_ci		return -EOPNOTSUPP;
22762306a36Sopenharmony_ci	}
22862306a36Sopenharmony_ci
22962306a36Sopenharmony_ci}
23062306a36Sopenharmony_ci
23162306a36Sopenharmony_cistatic int tmp421_read_string(struct device *dev, enum hwmon_sensor_types type,
23262306a36Sopenharmony_ci			     u32 attr, int channel, const char **str)
23362306a36Sopenharmony_ci{
23462306a36Sopenharmony_ci	struct tmp421_data *data = dev_get_drvdata(dev);
23562306a36Sopenharmony_ci
23662306a36Sopenharmony_ci	*str = data->channel[channel].label;
23762306a36Sopenharmony_ci
23862306a36Sopenharmony_ci	return 0;
23962306a36Sopenharmony_ci}
24062306a36Sopenharmony_ci
24162306a36Sopenharmony_cistatic int tmp421_write(struct device *dev, enum hwmon_sensor_types type,
24262306a36Sopenharmony_ci			u32 attr, int channel, long val)
24362306a36Sopenharmony_ci{
24462306a36Sopenharmony_ci	struct tmp421_data *data = dev_get_drvdata(dev);
24562306a36Sopenharmony_ci	int ret;
24662306a36Sopenharmony_ci
24762306a36Sopenharmony_ci	switch (attr) {
24862306a36Sopenharmony_ci	case hwmon_temp_enable:
24962306a36Sopenharmony_ci		data->channel[channel].enabled = val;
25062306a36Sopenharmony_ci		ret = tmp421_enable_channels(data);
25162306a36Sopenharmony_ci		break;
25262306a36Sopenharmony_ci	default:
25362306a36Sopenharmony_ci	    ret = -EOPNOTSUPP;
25462306a36Sopenharmony_ci	}
25562306a36Sopenharmony_ci
25662306a36Sopenharmony_ci	return ret;
25762306a36Sopenharmony_ci}
25862306a36Sopenharmony_ci
25962306a36Sopenharmony_cistatic umode_t tmp421_is_visible(const void *data, enum hwmon_sensor_types type,
26062306a36Sopenharmony_ci				 u32 attr, int channel)
26162306a36Sopenharmony_ci{
26262306a36Sopenharmony_ci	switch (attr) {
26362306a36Sopenharmony_ci	case hwmon_temp_fault:
26462306a36Sopenharmony_ci	case hwmon_temp_input:
26562306a36Sopenharmony_ci		return 0444;
26662306a36Sopenharmony_ci	case hwmon_temp_label:
26762306a36Sopenharmony_ci		return 0444;
26862306a36Sopenharmony_ci	case hwmon_temp_enable:
26962306a36Sopenharmony_ci		return 0644;
27062306a36Sopenharmony_ci	default:
27162306a36Sopenharmony_ci		return 0;
27262306a36Sopenharmony_ci	}
27362306a36Sopenharmony_ci}
27462306a36Sopenharmony_ci
27562306a36Sopenharmony_cistatic int tmp421_init_client(struct tmp421_data *data)
27662306a36Sopenharmony_ci{
27762306a36Sopenharmony_ci	int config, config_orig;
27862306a36Sopenharmony_ci	struct i2c_client *client = data->client;
27962306a36Sopenharmony_ci
28062306a36Sopenharmony_ci	/* Set the conversion rate to 2 Hz */
28162306a36Sopenharmony_ci	i2c_smbus_write_byte_data(client, TMP421_CONVERSION_RATE_REG, 0x05);
28262306a36Sopenharmony_ci
28362306a36Sopenharmony_ci	/* Start conversions (disable shutdown if necessary) */
28462306a36Sopenharmony_ci	config = i2c_smbus_read_byte_data(client, TMP421_CONFIG_REG_1);
28562306a36Sopenharmony_ci	if (config < 0) {
28662306a36Sopenharmony_ci		dev_err(&client->dev,
28762306a36Sopenharmony_ci			"Could not read configuration register (%d)\n", config);
28862306a36Sopenharmony_ci		return config;
28962306a36Sopenharmony_ci	}
29062306a36Sopenharmony_ci
29162306a36Sopenharmony_ci	config_orig = config;
29262306a36Sopenharmony_ci	config &= ~TMP421_CONFIG_SHUTDOWN;
29362306a36Sopenharmony_ci
29462306a36Sopenharmony_ci	if (config != config_orig) {
29562306a36Sopenharmony_ci		dev_info(&client->dev, "Enable monitoring chip\n");
29662306a36Sopenharmony_ci		i2c_smbus_write_byte_data(client, TMP421_CONFIG_REG_1, config);
29762306a36Sopenharmony_ci	}
29862306a36Sopenharmony_ci
29962306a36Sopenharmony_ci	return tmp421_enable_channels(data);
30062306a36Sopenharmony_ci}
30162306a36Sopenharmony_ci
30262306a36Sopenharmony_cistatic int tmp421_detect(struct i2c_client *client,
30362306a36Sopenharmony_ci			 struct i2c_board_info *info)
30462306a36Sopenharmony_ci{
30562306a36Sopenharmony_ci	enum chips kind;
30662306a36Sopenharmony_ci	struct i2c_adapter *adapter = client->adapter;
30762306a36Sopenharmony_ci	static const char * const names[] = {
30862306a36Sopenharmony_ci		"TMP421", "TMP422", "TMP423",
30962306a36Sopenharmony_ci		"TMP441", "TMP442"
31062306a36Sopenharmony_ci	};
31162306a36Sopenharmony_ci	int addr = client->addr;
31262306a36Sopenharmony_ci	u8 reg;
31362306a36Sopenharmony_ci
31462306a36Sopenharmony_ci	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
31562306a36Sopenharmony_ci		return -ENODEV;
31662306a36Sopenharmony_ci
31762306a36Sopenharmony_ci	reg = i2c_smbus_read_byte_data(client, TMP421_MANUFACTURER_ID_REG);
31862306a36Sopenharmony_ci	if (reg != TMP421_MANUFACTURER_ID)
31962306a36Sopenharmony_ci		return -ENODEV;
32062306a36Sopenharmony_ci
32162306a36Sopenharmony_ci	reg = i2c_smbus_read_byte_data(client, TMP421_CONVERSION_RATE_REG);
32262306a36Sopenharmony_ci	if (reg & 0xf8)
32362306a36Sopenharmony_ci		return -ENODEV;
32462306a36Sopenharmony_ci
32562306a36Sopenharmony_ci	reg = i2c_smbus_read_byte_data(client, TMP421_STATUS_REG);
32662306a36Sopenharmony_ci	if (reg & 0x7f)
32762306a36Sopenharmony_ci		return -ENODEV;
32862306a36Sopenharmony_ci
32962306a36Sopenharmony_ci	reg = i2c_smbus_read_byte_data(client, TMP421_DEVICE_ID_REG);
33062306a36Sopenharmony_ci	switch (reg) {
33162306a36Sopenharmony_ci	case TMP421_DEVICE_ID:
33262306a36Sopenharmony_ci		kind = tmp421;
33362306a36Sopenharmony_ci		break;
33462306a36Sopenharmony_ci	case TMP422_DEVICE_ID:
33562306a36Sopenharmony_ci		if (addr == 0x2a)
33662306a36Sopenharmony_ci			return -ENODEV;
33762306a36Sopenharmony_ci		kind = tmp422;
33862306a36Sopenharmony_ci		break;
33962306a36Sopenharmony_ci	case TMP423_DEVICE_ID:
34062306a36Sopenharmony_ci		if (addr != 0x4c && addr != 0x4d)
34162306a36Sopenharmony_ci			return -ENODEV;
34262306a36Sopenharmony_ci		kind = tmp423;
34362306a36Sopenharmony_ci		break;
34462306a36Sopenharmony_ci	case TMP441_DEVICE_ID:
34562306a36Sopenharmony_ci		kind = tmp441;
34662306a36Sopenharmony_ci		break;
34762306a36Sopenharmony_ci	case TMP442_DEVICE_ID:
34862306a36Sopenharmony_ci		if (addr != 0x4c && addr != 0x4d)
34962306a36Sopenharmony_ci			return -ENODEV;
35062306a36Sopenharmony_ci		kind = tmp442;
35162306a36Sopenharmony_ci		break;
35262306a36Sopenharmony_ci	default:
35362306a36Sopenharmony_ci		return -ENODEV;
35462306a36Sopenharmony_ci	}
35562306a36Sopenharmony_ci
35662306a36Sopenharmony_ci	strscpy(info->type, tmp421_id[kind].name, I2C_NAME_SIZE);
35762306a36Sopenharmony_ci	dev_info(&adapter->dev, "Detected TI %s chip at 0x%02x\n",
35862306a36Sopenharmony_ci		 names[kind], client->addr);
35962306a36Sopenharmony_ci
36062306a36Sopenharmony_ci	return 0;
36162306a36Sopenharmony_ci}
36262306a36Sopenharmony_ci
36362306a36Sopenharmony_cistatic int tmp421_probe_child_from_dt(struct i2c_client *client,
36462306a36Sopenharmony_ci				      struct device_node *child,
36562306a36Sopenharmony_ci				      struct tmp421_data *data)
36662306a36Sopenharmony_ci
36762306a36Sopenharmony_ci{
36862306a36Sopenharmony_ci	struct device *dev = &client->dev;
36962306a36Sopenharmony_ci	u32 i;
37062306a36Sopenharmony_ci	s32 val;
37162306a36Sopenharmony_ci	int err;
37262306a36Sopenharmony_ci
37362306a36Sopenharmony_ci	err = of_property_read_u32(child, "reg", &i);
37462306a36Sopenharmony_ci	if (err) {
37562306a36Sopenharmony_ci		dev_err(dev, "missing reg property of %pOFn\n", child);
37662306a36Sopenharmony_ci		return err;
37762306a36Sopenharmony_ci	}
37862306a36Sopenharmony_ci
37962306a36Sopenharmony_ci	if (i >= data->channels) {
38062306a36Sopenharmony_ci		dev_err(dev, "invalid reg %d of %pOFn\n", i, child);
38162306a36Sopenharmony_ci		return -EINVAL;
38262306a36Sopenharmony_ci	}
38362306a36Sopenharmony_ci
38462306a36Sopenharmony_ci	of_property_read_string(child, "label", &data->channel[i].label);
38562306a36Sopenharmony_ci	if (data->channel[i].label)
38662306a36Sopenharmony_ci		data->temp_config[i] |= HWMON_T_LABEL;
38762306a36Sopenharmony_ci
38862306a36Sopenharmony_ci	data->channel[i].enabled = of_device_is_available(child);
38962306a36Sopenharmony_ci
39062306a36Sopenharmony_ci	err = of_property_read_s32(child, "ti,n-factor", &val);
39162306a36Sopenharmony_ci	if (!err) {
39262306a36Sopenharmony_ci		if (i == 0) {
39362306a36Sopenharmony_ci			dev_err(dev, "n-factor can't be set for internal channel\n");
39462306a36Sopenharmony_ci			return -EINVAL;
39562306a36Sopenharmony_ci		}
39662306a36Sopenharmony_ci
39762306a36Sopenharmony_ci		if (val > 127 || val < -128) {
39862306a36Sopenharmony_ci			dev_err(dev, "n-factor for channel %d invalid (%d)\n",
39962306a36Sopenharmony_ci				i, val);
40062306a36Sopenharmony_ci			return -EINVAL;
40162306a36Sopenharmony_ci		}
40262306a36Sopenharmony_ci		i2c_smbus_write_byte_data(client, TMP421_N_FACTOR_REG_1 + i - 1,
40362306a36Sopenharmony_ci					  val);
40462306a36Sopenharmony_ci	}
40562306a36Sopenharmony_ci
40662306a36Sopenharmony_ci	return 0;
40762306a36Sopenharmony_ci}
40862306a36Sopenharmony_ci
40962306a36Sopenharmony_cistatic int tmp421_probe_from_dt(struct i2c_client *client, struct tmp421_data *data)
41062306a36Sopenharmony_ci{
41162306a36Sopenharmony_ci	struct device *dev = &client->dev;
41262306a36Sopenharmony_ci	const struct device_node *np = dev->of_node;
41362306a36Sopenharmony_ci	struct device_node *child;
41462306a36Sopenharmony_ci	int err;
41562306a36Sopenharmony_ci
41662306a36Sopenharmony_ci	for_each_child_of_node(np, child) {
41762306a36Sopenharmony_ci		if (strcmp(child->name, "channel"))
41862306a36Sopenharmony_ci			continue;
41962306a36Sopenharmony_ci
42062306a36Sopenharmony_ci		err = tmp421_probe_child_from_dt(client, child, data);
42162306a36Sopenharmony_ci		if (err) {
42262306a36Sopenharmony_ci			of_node_put(child);
42362306a36Sopenharmony_ci			return err;
42462306a36Sopenharmony_ci		}
42562306a36Sopenharmony_ci	}
42662306a36Sopenharmony_ci
42762306a36Sopenharmony_ci	return 0;
42862306a36Sopenharmony_ci}
42962306a36Sopenharmony_ci
43062306a36Sopenharmony_cistatic const struct hwmon_ops tmp421_ops = {
43162306a36Sopenharmony_ci	.is_visible = tmp421_is_visible,
43262306a36Sopenharmony_ci	.read = tmp421_read,
43362306a36Sopenharmony_ci	.read_string = tmp421_read_string,
43462306a36Sopenharmony_ci	.write = tmp421_write,
43562306a36Sopenharmony_ci};
43662306a36Sopenharmony_ci
43762306a36Sopenharmony_cistatic int tmp421_probe(struct i2c_client *client)
43862306a36Sopenharmony_ci{
43962306a36Sopenharmony_ci	struct device *dev = &client->dev;
44062306a36Sopenharmony_ci	struct device *hwmon_dev;
44162306a36Sopenharmony_ci	struct tmp421_data *data;
44262306a36Sopenharmony_ci	int i, err;
44362306a36Sopenharmony_ci
44462306a36Sopenharmony_ci	data = devm_kzalloc(dev, sizeof(struct tmp421_data), GFP_KERNEL);
44562306a36Sopenharmony_ci	if (!data)
44662306a36Sopenharmony_ci		return -ENOMEM;
44762306a36Sopenharmony_ci
44862306a36Sopenharmony_ci	mutex_init(&data->update_lock);
44962306a36Sopenharmony_ci	if (client->dev.of_node)
45062306a36Sopenharmony_ci		data->channels = (unsigned long)
45162306a36Sopenharmony_ci			of_device_get_match_data(&client->dev);
45262306a36Sopenharmony_ci	else
45362306a36Sopenharmony_ci		data->channels = i2c_match_id(tmp421_id, client)->driver_data;
45462306a36Sopenharmony_ci	data->client = client;
45562306a36Sopenharmony_ci
45662306a36Sopenharmony_ci	for (i = 0; i < data->channels; i++) {
45762306a36Sopenharmony_ci		data->temp_config[i] = HWMON_T_INPUT | HWMON_T_FAULT | HWMON_T_ENABLE;
45862306a36Sopenharmony_ci		data->channel[i].enabled = true;
45962306a36Sopenharmony_ci	}
46062306a36Sopenharmony_ci
46162306a36Sopenharmony_ci	err = tmp421_probe_from_dt(client, data);
46262306a36Sopenharmony_ci	if (err)
46362306a36Sopenharmony_ci		return err;
46462306a36Sopenharmony_ci
46562306a36Sopenharmony_ci	err = tmp421_init_client(data);
46662306a36Sopenharmony_ci	if (err)
46762306a36Sopenharmony_ci		return err;
46862306a36Sopenharmony_ci
46962306a36Sopenharmony_ci	data->chip.ops = &tmp421_ops;
47062306a36Sopenharmony_ci	data->chip.info = data->info;
47162306a36Sopenharmony_ci
47262306a36Sopenharmony_ci	data->info[0] = &data->temp_info;
47362306a36Sopenharmony_ci
47462306a36Sopenharmony_ci	data->temp_info.type = hwmon_temp;
47562306a36Sopenharmony_ci	data->temp_info.config = data->temp_config;
47662306a36Sopenharmony_ci
47762306a36Sopenharmony_ci	hwmon_dev = devm_hwmon_device_register_with_info(dev, client->name,
47862306a36Sopenharmony_ci							 data,
47962306a36Sopenharmony_ci							 &data->chip,
48062306a36Sopenharmony_ci							 NULL);
48162306a36Sopenharmony_ci	return PTR_ERR_OR_ZERO(hwmon_dev);
48262306a36Sopenharmony_ci}
48362306a36Sopenharmony_ci
48462306a36Sopenharmony_cistatic struct i2c_driver tmp421_driver = {
48562306a36Sopenharmony_ci	.class = I2C_CLASS_HWMON,
48662306a36Sopenharmony_ci	.driver = {
48762306a36Sopenharmony_ci		.name	= "tmp421",
48862306a36Sopenharmony_ci		.of_match_table = of_match_ptr(tmp421_of_match),
48962306a36Sopenharmony_ci	},
49062306a36Sopenharmony_ci	.probe = tmp421_probe,
49162306a36Sopenharmony_ci	.id_table = tmp421_id,
49262306a36Sopenharmony_ci	.detect = tmp421_detect,
49362306a36Sopenharmony_ci	.address_list = normal_i2c,
49462306a36Sopenharmony_ci};
49562306a36Sopenharmony_ci
49662306a36Sopenharmony_cimodule_i2c_driver(tmp421_driver);
49762306a36Sopenharmony_ci
49862306a36Sopenharmony_ciMODULE_AUTHOR("Andre Prendel <andre.prendel@gmx.de>");
49962306a36Sopenharmony_ciMODULE_DESCRIPTION("Texas Instruments TMP421/422/423/441/442 temperature sensor driver");
50062306a36Sopenharmony_ciMODULE_LICENSE("GPL");
501