162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Driver for Texas Instruments / National Semiconductor LM95234
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright (c) 2013, 2014 Guenter Roeck <linux@roeck-us.net>
662306a36Sopenharmony_ci *
762306a36Sopenharmony_ci * Derived from lm95241.c
862306a36Sopenharmony_ci * Copyright (C) 2008, 2010 Davide Rizzo <elpa.rizzo@gmail.com>
962306a36Sopenharmony_ci */
1062306a36Sopenharmony_ci
1162306a36Sopenharmony_ci#include <linux/module.h>
1262306a36Sopenharmony_ci#include <linux/init.h>
1362306a36Sopenharmony_ci#include <linux/slab.h>
1462306a36Sopenharmony_ci#include <linux/jiffies.h>
1562306a36Sopenharmony_ci#include <linux/i2c.h>
1662306a36Sopenharmony_ci#include <linux/hwmon.h>
1762306a36Sopenharmony_ci#include <linux/hwmon-sysfs.h>
1862306a36Sopenharmony_ci#include <linux/err.h>
1962306a36Sopenharmony_ci#include <linux/mutex.h>
2062306a36Sopenharmony_ci#include <linux/sysfs.h>
2162306a36Sopenharmony_ci
2262306a36Sopenharmony_ci#define DRVNAME "lm95234"
2362306a36Sopenharmony_ci
2462306a36Sopenharmony_cienum chips { lm95233, lm95234 };
2562306a36Sopenharmony_ci
2662306a36Sopenharmony_cistatic const unsigned short normal_i2c[] = {
2762306a36Sopenharmony_ci	0x18, 0x2a, 0x2b, 0x4d, 0x4e, I2C_CLIENT_END };
2862306a36Sopenharmony_ci
2962306a36Sopenharmony_ci/* LM95234 registers */
3062306a36Sopenharmony_ci#define LM95234_REG_MAN_ID		0xFE
3162306a36Sopenharmony_ci#define LM95234_REG_CHIP_ID		0xFF
3262306a36Sopenharmony_ci#define LM95234_REG_STATUS		0x02
3362306a36Sopenharmony_ci#define LM95234_REG_CONFIG		0x03
3462306a36Sopenharmony_ci#define LM95234_REG_CONVRATE		0x04
3562306a36Sopenharmony_ci#define LM95234_REG_STS_FAULT		0x07
3662306a36Sopenharmony_ci#define LM95234_REG_STS_TCRIT1		0x08
3762306a36Sopenharmony_ci#define LM95234_REG_STS_TCRIT2		0x09
3862306a36Sopenharmony_ci#define LM95234_REG_TEMPH(x)		((x) + 0x10)
3962306a36Sopenharmony_ci#define LM95234_REG_TEMPL(x)		((x) + 0x20)
4062306a36Sopenharmony_ci#define LM95234_REG_UTEMPH(x)		((x) + 0x19)	/* Remote only */
4162306a36Sopenharmony_ci#define LM95234_REG_UTEMPL(x)		((x) + 0x29)
4262306a36Sopenharmony_ci#define LM95234_REG_REM_MODEL		0x30
4362306a36Sopenharmony_ci#define LM95234_REG_REM_MODEL_STS	0x38
4462306a36Sopenharmony_ci#define LM95234_REG_OFFSET(x)		((x) + 0x31)	/* Remote only */
4562306a36Sopenharmony_ci#define LM95234_REG_TCRIT1(x)		((x) + 0x40)
4662306a36Sopenharmony_ci#define LM95234_REG_TCRIT2(x)		((x) + 0x49)	/* Remote channel 1,2 */
4762306a36Sopenharmony_ci#define LM95234_REG_TCRIT_HYST		0x5a
4862306a36Sopenharmony_ci
4962306a36Sopenharmony_ci#define NATSEMI_MAN_ID			0x01
5062306a36Sopenharmony_ci#define LM95233_CHIP_ID			0x89
5162306a36Sopenharmony_ci#define LM95234_CHIP_ID			0x79
5262306a36Sopenharmony_ci
5362306a36Sopenharmony_ci/* Client data (each client gets its own) */
5462306a36Sopenharmony_cistruct lm95234_data {
5562306a36Sopenharmony_ci	struct i2c_client *client;
5662306a36Sopenharmony_ci	const struct attribute_group *groups[3];
5762306a36Sopenharmony_ci	struct mutex update_lock;
5862306a36Sopenharmony_ci	unsigned long last_updated, interval;	/* in jiffies */
5962306a36Sopenharmony_ci	bool valid;		/* false until following fields are valid */
6062306a36Sopenharmony_ci	/* registers values */
6162306a36Sopenharmony_ci	int temp[5];		/* temperature (signed) */
6262306a36Sopenharmony_ci	u32 status;		/* fault/alarm status */
6362306a36Sopenharmony_ci	u8 tcrit1[5];		/* critical temperature limit */
6462306a36Sopenharmony_ci	u8 tcrit2[2];		/* high temperature limit */
6562306a36Sopenharmony_ci	s8 toffset[4];		/* remote temperature offset */
6662306a36Sopenharmony_ci	u8 thyst;		/* common hysteresis */
6762306a36Sopenharmony_ci
6862306a36Sopenharmony_ci	u8 sensor_type;		/* temperature sensor type */
6962306a36Sopenharmony_ci};
7062306a36Sopenharmony_ci
7162306a36Sopenharmony_cistatic int lm95234_read_temp(struct i2c_client *client, int index, int *t)
7262306a36Sopenharmony_ci{
7362306a36Sopenharmony_ci	int val;
7462306a36Sopenharmony_ci	u16 temp = 0;
7562306a36Sopenharmony_ci
7662306a36Sopenharmony_ci	if (index) {
7762306a36Sopenharmony_ci		val = i2c_smbus_read_byte_data(client,
7862306a36Sopenharmony_ci					       LM95234_REG_UTEMPH(index - 1));
7962306a36Sopenharmony_ci		if (val < 0)
8062306a36Sopenharmony_ci			return val;
8162306a36Sopenharmony_ci		temp = val << 8;
8262306a36Sopenharmony_ci		val = i2c_smbus_read_byte_data(client,
8362306a36Sopenharmony_ci					       LM95234_REG_UTEMPL(index - 1));
8462306a36Sopenharmony_ci		if (val < 0)
8562306a36Sopenharmony_ci			return val;
8662306a36Sopenharmony_ci		temp |= val;
8762306a36Sopenharmony_ci		*t = temp;
8862306a36Sopenharmony_ci	}
8962306a36Sopenharmony_ci	/*
9062306a36Sopenharmony_ci	 * Read signed temperature if unsigned temperature is 0,
9162306a36Sopenharmony_ci	 * or if this is the local sensor.
9262306a36Sopenharmony_ci	 */
9362306a36Sopenharmony_ci	if (!temp) {
9462306a36Sopenharmony_ci		val = i2c_smbus_read_byte_data(client,
9562306a36Sopenharmony_ci					       LM95234_REG_TEMPH(index));
9662306a36Sopenharmony_ci		if (val < 0)
9762306a36Sopenharmony_ci			return val;
9862306a36Sopenharmony_ci		temp = val << 8;
9962306a36Sopenharmony_ci		val = i2c_smbus_read_byte_data(client,
10062306a36Sopenharmony_ci					       LM95234_REG_TEMPL(index));
10162306a36Sopenharmony_ci		if (val < 0)
10262306a36Sopenharmony_ci			return val;
10362306a36Sopenharmony_ci		temp |= val;
10462306a36Sopenharmony_ci		*t = (s16)temp;
10562306a36Sopenharmony_ci	}
10662306a36Sopenharmony_ci	return 0;
10762306a36Sopenharmony_ci}
10862306a36Sopenharmony_ci
10962306a36Sopenharmony_cistatic u16 update_intervals[] = { 143, 364, 1000, 2500 };
11062306a36Sopenharmony_ci
11162306a36Sopenharmony_ci/* Fill value cache. Must be called with update lock held. */
11262306a36Sopenharmony_ci
11362306a36Sopenharmony_cistatic int lm95234_fill_cache(struct lm95234_data *data,
11462306a36Sopenharmony_ci			      struct i2c_client *client)
11562306a36Sopenharmony_ci{
11662306a36Sopenharmony_ci	int i, ret;
11762306a36Sopenharmony_ci
11862306a36Sopenharmony_ci	ret = i2c_smbus_read_byte_data(client, LM95234_REG_CONVRATE);
11962306a36Sopenharmony_ci	if (ret < 0)
12062306a36Sopenharmony_ci		return ret;
12162306a36Sopenharmony_ci
12262306a36Sopenharmony_ci	data->interval = msecs_to_jiffies(update_intervals[ret & 0x03]);
12362306a36Sopenharmony_ci
12462306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(data->tcrit1); i++) {
12562306a36Sopenharmony_ci		ret = i2c_smbus_read_byte_data(client, LM95234_REG_TCRIT1(i));
12662306a36Sopenharmony_ci		if (ret < 0)
12762306a36Sopenharmony_ci			return ret;
12862306a36Sopenharmony_ci		data->tcrit1[i] = ret;
12962306a36Sopenharmony_ci	}
13062306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(data->tcrit2); i++) {
13162306a36Sopenharmony_ci		ret = i2c_smbus_read_byte_data(client, LM95234_REG_TCRIT2(i));
13262306a36Sopenharmony_ci		if (ret < 0)
13362306a36Sopenharmony_ci			return ret;
13462306a36Sopenharmony_ci		data->tcrit2[i] = ret;
13562306a36Sopenharmony_ci	}
13662306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(data->toffset); i++) {
13762306a36Sopenharmony_ci		ret = i2c_smbus_read_byte_data(client, LM95234_REG_OFFSET(i));
13862306a36Sopenharmony_ci		if (ret < 0)
13962306a36Sopenharmony_ci			return ret;
14062306a36Sopenharmony_ci		data->toffset[i] = ret;
14162306a36Sopenharmony_ci	}
14262306a36Sopenharmony_ci
14362306a36Sopenharmony_ci	ret = i2c_smbus_read_byte_data(client, LM95234_REG_TCRIT_HYST);
14462306a36Sopenharmony_ci	if (ret < 0)
14562306a36Sopenharmony_ci		return ret;
14662306a36Sopenharmony_ci	data->thyst = ret;
14762306a36Sopenharmony_ci
14862306a36Sopenharmony_ci	ret = i2c_smbus_read_byte_data(client, LM95234_REG_REM_MODEL);
14962306a36Sopenharmony_ci	if (ret < 0)
15062306a36Sopenharmony_ci		return ret;
15162306a36Sopenharmony_ci	data->sensor_type = ret;
15262306a36Sopenharmony_ci
15362306a36Sopenharmony_ci	return 0;
15462306a36Sopenharmony_ci}
15562306a36Sopenharmony_ci
15662306a36Sopenharmony_cistatic int lm95234_update_device(struct lm95234_data *data)
15762306a36Sopenharmony_ci{
15862306a36Sopenharmony_ci	struct i2c_client *client = data->client;
15962306a36Sopenharmony_ci	int ret;
16062306a36Sopenharmony_ci
16162306a36Sopenharmony_ci	mutex_lock(&data->update_lock);
16262306a36Sopenharmony_ci
16362306a36Sopenharmony_ci	if (time_after(jiffies, data->last_updated + data->interval) ||
16462306a36Sopenharmony_ci	    !data->valid) {
16562306a36Sopenharmony_ci		int i;
16662306a36Sopenharmony_ci
16762306a36Sopenharmony_ci		if (!data->valid) {
16862306a36Sopenharmony_ci			ret = lm95234_fill_cache(data, client);
16962306a36Sopenharmony_ci			if (ret < 0)
17062306a36Sopenharmony_ci				goto abort;
17162306a36Sopenharmony_ci		}
17262306a36Sopenharmony_ci
17362306a36Sopenharmony_ci		data->valid = false;
17462306a36Sopenharmony_ci		for (i = 0; i < ARRAY_SIZE(data->temp); i++) {
17562306a36Sopenharmony_ci			ret = lm95234_read_temp(client, i, &data->temp[i]);
17662306a36Sopenharmony_ci			if (ret < 0)
17762306a36Sopenharmony_ci				goto abort;
17862306a36Sopenharmony_ci		}
17962306a36Sopenharmony_ci
18062306a36Sopenharmony_ci		ret = i2c_smbus_read_byte_data(client, LM95234_REG_STS_FAULT);
18162306a36Sopenharmony_ci		if (ret < 0)
18262306a36Sopenharmony_ci			goto abort;
18362306a36Sopenharmony_ci		data->status = ret;
18462306a36Sopenharmony_ci
18562306a36Sopenharmony_ci		ret = i2c_smbus_read_byte_data(client, LM95234_REG_STS_TCRIT1);
18662306a36Sopenharmony_ci		if (ret < 0)
18762306a36Sopenharmony_ci			goto abort;
18862306a36Sopenharmony_ci		data->status |= ret << 8;
18962306a36Sopenharmony_ci
19062306a36Sopenharmony_ci		ret = i2c_smbus_read_byte_data(client, LM95234_REG_STS_TCRIT2);
19162306a36Sopenharmony_ci		if (ret < 0)
19262306a36Sopenharmony_ci			goto abort;
19362306a36Sopenharmony_ci		data->status |= ret << 16;
19462306a36Sopenharmony_ci
19562306a36Sopenharmony_ci		data->last_updated = jiffies;
19662306a36Sopenharmony_ci		data->valid = true;
19762306a36Sopenharmony_ci	}
19862306a36Sopenharmony_ci	ret = 0;
19962306a36Sopenharmony_ciabort:
20062306a36Sopenharmony_ci	mutex_unlock(&data->update_lock);
20162306a36Sopenharmony_ci
20262306a36Sopenharmony_ci	return ret;
20362306a36Sopenharmony_ci}
20462306a36Sopenharmony_ci
20562306a36Sopenharmony_cistatic ssize_t temp_show(struct device *dev, struct device_attribute *attr,
20662306a36Sopenharmony_ci			 char *buf)
20762306a36Sopenharmony_ci{
20862306a36Sopenharmony_ci	struct lm95234_data *data = dev_get_drvdata(dev);
20962306a36Sopenharmony_ci	int index = to_sensor_dev_attr(attr)->index;
21062306a36Sopenharmony_ci	int ret = lm95234_update_device(data);
21162306a36Sopenharmony_ci
21262306a36Sopenharmony_ci	if (ret)
21362306a36Sopenharmony_ci		return ret;
21462306a36Sopenharmony_ci
21562306a36Sopenharmony_ci	return sprintf(buf, "%d\n",
21662306a36Sopenharmony_ci		       DIV_ROUND_CLOSEST(data->temp[index] * 125, 32));
21762306a36Sopenharmony_ci}
21862306a36Sopenharmony_ci
21962306a36Sopenharmony_cistatic ssize_t alarm_show(struct device *dev, struct device_attribute *attr,
22062306a36Sopenharmony_ci			  char *buf)
22162306a36Sopenharmony_ci{
22262306a36Sopenharmony_ci	struct lm95234_data *data = dev_get_drvdata(dev);
22362306a36Sopenharmony_ci	u32 mask = to_sensor_dev_attr(attr)->index;
22462306a36Sopenharmony_ci	int ret = lm95234_update_device(data);
22562306a36Sopenharmony_ci
22662306a36Sopenharmony_ci	if (ret)
22762306a36Sopenharmony_ci		return ret;
22862306a36Sopenharmony_ci
22962306a36Sopenharmony_ci	return sprintf(buf, "%u", !!(data->status & mask));
23062306a36Sopenharmony_ci}
23162306a36Sopenharmony_ci
23262306a36Sopenharmony_cistatic ssize_t type_show(struct device *dev, struct device_attribute *attr,
23362306a36Sopenharmony_ci			 char *buf)
23462306a36Sopenharmony_ci{
23562306a36Sopenharmony_ci	struct lm95234_data *data = dev_get_drvdata(dev);
23662306a36Sopenharmony_ci	u8 mask = to_sensor_dev_attr(attr)->index;
23762306a36Sopenharmony_ci	int ret = lm95234_update_device(data);
23862306a36Sopenharmony_ci
23962306a36Sopenharmony_ci	if (ret)
24062306a36Sopenharmony_ci		return ret;
24162306a36Sopenharmony_ci
24262306a36Sopenharmony_ci	return sprintf(buf, data->sensor_type & mask ? "1\n" : "2\n");
24362306a36Sopenharmony_ci}
24462306a36Sopenharmony_ci
24562306a36Sopenharmony_cistatic ssize_t type_store(struct device *dev, struct device_attribute *attr,
24662306a36Sopenharmony_ci			  const char *buf, size_t count)
24762306a36Sopenharmony_ci{
24862306a36Sopenharmony_ci	struct lm95234_data *data = dev_get_drvdata(dev);
24962306a36Sopenharmony_ci	unsigned long val;
25062306a36Sopenharmony_ci	u8 mask = to_sensor_dev_attr(attr)->index;
25162306a36Sopenharmony_ci	int ret = lm95234_update_device(data);
25262306a36Sopenharmony_ci
25362306a36Sopenharmony_ci	if (ret)
25462306a36Sopenharmony_ci		return ret;
25562306a36Sopenharmony_ci
25662306a36Sopenharmony_ci	ret = kstrtoul(buf, 10, &val);
25762306a36Sopenharmony_ci	if (ret < 0)
25862306a36Sopenharmony_ci		return ret;
25962306a36Sopenharmony_ci
26062306a36Sopenharmony_ci	if (val != 1 && val != 2)
26162306a36Sopenharmony_ci		return -EINVAL;
26262306a36Sopenharmony_ci
26362306a36Sopenharmony_ci	mutex_lock(&data->update_lock);
26462306a36Sopenharmony_ci	if (val == 1)
26562306a36Sopenharmony_ci		data->sensor_type |= mask;
26662306a36Sopenharmony_ci	else
26762306a36Sopenharmony_ci		data->sensor_type &= ~mask;
26862306a36Sopenharmony_ci	data->valid = false;
26962306a36Sopenharmony_ci	i2c_smbus_write_byte_data(data->client, LM95234_REG_REM_MODEL,
27062306a36Sopenharmony_ci				  data->sensor_type);
27162306a36Sopenharmony_ci	mutex_unlock(&data->update_lock);
27262306a36Sopenharmony_ci
27362306a36Sopenharmony_ci	return count;
27462306a36Sopenharmony_ci}
27562306a36Sopenharmony_ci
27662306a36Sopenharmony_cistatic ssize_t tcrit2_show(struct device *dev, struct device_attribute *attr,
27762306a36Sopenharmony_ci			   char *buf)
27862306a36Sopenharmony_ci{
27962306a36Sopenharmony_ci	struct lm95234_data *data = dev_get_drvdata(dev);
28062306a36Sopenharmony_ci	int index = to_sensor_dev_attr(attr)->index;
28162306a36Sopenharmony_ci	int ret = lm95234_update_device(data);
28262306a36Sopenharmony_ci
28362306a36Sopenharmony_ci	if (ret)
28462306a36Sopenharmony_ci		return ret;
28562306a36Sopenharmony_ci
28662306a36Sopenharmony_ci	return sprintf(buf, "%u", data->tcrit2[index] * 1000);
28762306a36Sopenharmony_ci}
28862306a36Sopenharmony_ci
28962306a36Sopenharmony_cistatic ssize_t tcrit2_store(struct device *dev, struct device_attribute *attr,
29062306a36Sopenharmony_ci			    const char *buf, size_t count)
29162306a36Sopenharmony_ci{
29262306a36Sopenharmony_ci	struct lm95234_data *data = dev_get_drvdata(dev);
29362306a36Sopenharmony_ci	int index = to_sensor_dev_attr(attr)->index;
29462306a36Sopenharmony_ci	long val;
29562306a36Sopenharmony_ci	int ret = lm95234_update_device(data);
29662306a36Sopenharmony_ci
29762306a36Sopenharmony_ci	if (ret)
29862306a36Sopenharmony_ci		return ret;
29962306a36Sopenharmony_ci
30062306a36Sopenharmony_ci	ret = kstrtol(buf, 10, &val);
30162306a36Sopenharmony_ci	if (ret < 0)
30262306a36Sopenharmony_ci		return ret;
30362306a36Sopenharmony_ci
30462306a36Sopenharmony_ci	val = clamp_val(DIV_ROUND_CLOSEST(val, 1000), 0, index ? 255 : 127);
30562306a36Sopenharmony_ci
30662306a36Sopenharmony_ci	mutex_lock(&data->update_lock);
30762306a36Sopenharmony_ci	data->tcrit2[index] = val;
30862306a36Sopenharmony_ci	i2c_smbus_write_byte_data(data->client, LM95234_REG_TCRIT2(index), val);
30962306a36Sopenharmony_ci	mutex_unlock(&data->update_lock);
31062306a36Sopenharmony_ci
31162306a36Sopenharmony_ci	return count;
31262306a36Sopenharmony_ci}
31362306a36Sopenharmony_ci
31462306a36Sopenharmony_cistatic ssize_t tcrit2_hyst_show(struct device *dev,
31562306a36Sopenharmony_ci				struct device_attribute *attr, char *buf)
31662306a36Sopenharmony_ci{
31762306a36Sopenharmony_ci	struct lm95234_data *data = dev_get_drvdata(dev);
31862306a36Sopenharmony_ci	int index = to_sensor_dev_attr(attr)->index;
31962306a36Sopenharmony_ci	int ret = lm95234_update_device(data);
32062306a36Sopenharmony_ci
32162306a36Sopenharmony_ci	if (ret)
32262306a36Sopenharmony_ci		return ret;
32362306a36Sopenharmony_ci
32462306a36Sopenharmony_ci	/* Result can be negative, so be careful with unsigned operands */
32562306a36Sopenharmony_ci	return sprintf(buf, "%d",
32662306a36Sopenharmony_ci		       ((int)data->tcrit2[index] - (int)data->thyst) * 1000);
32762306a36Sopenharmony_ci}
32862306a36Sopenharmony_ci
32962306a36Sopenharmony_cistatic ssize_t tcrit1_show(struct device *dev, struct device_attribute *attr,
33062306a36Sopenharmony_ci			   char *buf)
33162306a36Sopenharmony_ci{
33262306a36Sopenharmony_ci	struct lm95234_data *data = dev_get_drvdata(dev);
33362306a36Sopenharmony_ci	int index = to_sensor_dev_attr(attr)->index;
33462306a36Sopenharmony_ci
33562306a36Sopenharmony_ci	return sprintf(buf, "%u", data->tcrit1[index] * 1000);
33662306a36Sopenharmony_ci}
33762306a36Sopenharmony_ci
33862306a36Sopenharmony_cistatic ssize_t tcrit1_store(struct device *dev, struct device_attribute *attr,
33962306a36Sopenharmony_ci			    const char *buf, size_t count)
34062306a36Sopenharmony_ci{
34162306a36Sopenharmony_ci	struct lm95234_data *data = dev_get_drvdata(dev);
34262306a36Sopenharmony_ci	int index = to_sensor_dev_attr(attr)->index;
34362306a36Sopenharmony_ci	int ret = lm95234_update_device(data);
34462306a36Sopenharmony_ci	long val;
34562306a36Sopenharmony_ci
34662306a36Sopenharmony_ci	if (ret)
34762306a36Sopenharmony_ci		return ret;
34862306a36Sopenharmony_ci
34962306a36Sopenharmony_ci	ret = kstrtol(buf, 10, &val);
35062306a36Sopenharmony_ci	if (ret < 0)
35162306a36Sopenharmony_ci		return ret;
35262306a36Sopenharmony_ci
35362306a36Sopenharmony_ci	val = clamp_val(DIV_ROUND_CLOSEST(val, 1000), 0, 255);
35462306a36Sopenharmony_ci
35562306a36Sopenharmony_ci	mutex_lock(&data->update_lock);
35662306a36Sopenharmony_ci	data->tcrit1[index] = val;
35762306a36Sopenharmony_ci	i2c_smbus_write_byte_data(data->client, LM95234_REG_TCRIT1(index), val);
35862306a36Sopenharmony_ci	mutex_unlock(&data->update_lock);
35962306a36Sopenharmony_ci
36062306a36Sopenharmony_ci	return count;
36162306a36Sopenharmony_ci}
36262306a36Sopenharmony_ci
36362306a36Sopenharmony_cistatic ssize_t tcrit1_hyst_show(struct device *dev,
36462306a36Sopenharmony_ci				struct device_attribute *attr, char *buf)
36562306a36Sopenharmony_ci{
36662306a36Sopenharmony_ci	struct lm95234_data *data = dev_get_drvdata(dev);
36762306a36Sopenharmony_ci	int index = to_sensor_dev_attr(attr)->index;
36862306a36Sopenharmony_ci	int ret = lm95234_update_device(data);
36962306a36Sopenharmony_ci
37062306a36Sopenharmony_ci	if (ret)
37162306a36Sopenharmony_ci		return ret;
37262306a36Sopenharmony_ci
37362306a36Sopenharmony_ci	/* Result can be negative, so be careful with unsigned operands */
37462306a36Sopenharmony_ci	return sprintf(buf, "%d",
37562306a36Sopenharmony_ci		       ((int)data->tcrit1[index] - (int)data->thyst) * 1000);
37662306a36Sopenharmony_ci}
37762306a36Sopenharmony_ci
37862306a36Sopenharmony_cistatic ssize_t tcrit1_hyst_store(struct device *dev,
37962306a36Sopenharmony_ci				 struct device_attribute *attr,
38062306a36Sopenharmony_ci				 const char *buf, size_t count)
38162306a36Sopenharmony_ci{
38262306a36Sopenharmony_ci	struct lm95234_data *data = dev_get_drvdata(dev);
38362306a36Sopenharmony_ci	int index = to_sensor_dev_attr(attr)->index;
38462306a36Sopenharmony_ci	int ret = lm95234_update_device(data);
38562306a36Sopenharmony_ci	long val;
38662306a36Sopenharmony_ci
38762306a36Sopenharmony_ci	if (ret)
38862306a36Sopenharmony_ci		return ret;
38962306a36Sopenharmony_ci
39062306a36Sopenharmony_ci	ret = kstrtol(buf, 10, &val);
39162306a36Sopenharmony_ci	if (ret < 0)
39262306a36Sopenharmony_ci		return ret;
39362306a36Sopenharmony_ci
39462306a36Sopenharmony_ci	val = DIV_ROUND_CLOSEST(val, 1000);
39562306a36Sopenharmony_ci	val = clamp_val((int)data->tcrit1[index] - val, 0, 31);
39662306a36Sopenharmony_ci
39762306a36Sopenharmony_ci	mutex_lock(&data->update_lock);
39862306a36Sopenharmony_ci	data->thyst = val;
39962306a36Sopenharmony_ci	i2c_smbus_write_byte_data(data->client, LM95234_REG_TCRIT_HYST, val);
40062306a36Sopenharmony_ci	mutex_unlock(&data->update_lock);
40162306a36Sopenharmony_ci
40262306a36Sopenharmony_ci	return count;
40362306a36Sopenharmony_ci}
40462306a36Sopenharmony_ci
40562306a36Sopenharmony_cistatic ssize_t offset_show(struct device *dev, struct device_attribute *attr,
40662306a36Sopenharmony_ci			   char *buf)
40762306a36Sopenharmony_ci{
40862306a36Sopenharmony_ci	struct lm95234_data *data = dev_get_drvdata(dev);
40962306a36Sopenharmony_ci	int index = to_sensor_dev_attr(attr)->index;
41062306a36Sopenharmony_ci	int ret = lm95234_update_device(data);
41162306a36Sopenharmony_ci
41262306a36Sopenharmony_ci	if (ret)
41362306a36Sopenharmony_ci		return ret;
41462306a36Sopenharmony_ci
41562306a36Sopenharmony_ci	return sprintf(buf, "%d", data->toffset[index] * 500);
41662306a36Sopenharmony_ci}
41762306a36Sopenharmony_ci
41862306a36Sopenharmony_cistatic ssize_t offset_store(struct device *dev, struct device_attribute *attr,
41962306a36Sopenharmony_ci			    const char *buf, size_t count)
42062306a36Sopenharmony_ci{
42162306a36Sopenharmony_ci	struct lm95234_data *data = dev_get_drvdata(dev);
42262306a36Sopenharmony_ci	int index = to_sensor_dev_attr(attr)->index;
42362306a36Sopenharmony_ci	int ret = lm95234_update_device(data);
42462306a36Sopenharmony_ci	long val;
42562306a36Sopenharmony_ci
42662306a36Sopenharmony_ci	if (ret)
42762306a36Sopenharmony_ci		return ret;
42862306a36Sopenharmony_ci
42962306a36Sopenharmony_ci	ret = kstrtol(buf, 10, &val);
43062306a36Sopenharmony_ci	if (ret < 0)
43162306a36Sopenharmony_ci		return ret;
43262306a36Sopenharmony_ci
43362306a36Sopenharmony_ci	/* Accuracy is 1/2 degrees C */
43462306a36Sopenharmony_ci	val = clamp_val(DIV_ROUND_CLOSEST(val, 500), -128, 127);
43562306a36Sopenharmony_ci
43662306a36Sopenharmony_ci	mutex_lock(&data->update_lock);
43762306a36Sopenharmony_ci	data->toffset[index] = val;
43862306a36Sopenharmony_ci	i2c_smbus_write_byte_data(data->client, LM95234_REG_OFFSET(index), val);
43962306a36Sopenharmony_ci	mutex_unlock(&data->update_lock);
44062306a36Sopenharmony_ci
44162306a36Sopenharmony_ci	return count;
44262306a36Sopenharmony_ci}
44362306a36Sopenharmony_ci
44462306a36Sopenharmony_cistatic ssize_t update_interval_show(struct device *dev,
44562306a36Sopenharmony_ci				    struct device_attribute *attr, char *buf)
44662306a36Sopenharmony_ci{
44762306a36Sopenharmony_ci	struct lm95234_data *data = dev_get_drvdata(dev);
44862306a36Sopenharmony_ci	int ret = lm95234_update_device(data);
44962306a36Sopenharmony_ci
45062306a36Sopenharmony_ci	if (ret)
45162306a36Sopenharmony_ci		return ret;
45262306a36Sopenharmony_ci
45362306a36Sopenharmony_ci	return sprintf(buf, "%lu\n",
45462306a36Sopenharmony_ci		       DIV_ROUND_CLOSEST(data->interval * 1000, HZ));
45562306a36Sopenharmony_ci}
45662306a36Sopenharmony_ci
45762306a36Sopenharmony_cistatic ssize_t update_interval_store(struct device *dev,
45862306a36Sopenharmony_ci				     struct device_attribute *attr,
45962306a36Sopenharmony_ci				     const char *buf, size_t count)
46062306a36Sopenharmony_ci{
46162306a36Sopenharmony_ci	struct lm95234_data *data = dev_get_drvdata(dev);
46262306a36Sopenharmony_ci	int ret = lm95234_update_device(data);
46362306a36Sopenharmony_ci	unsigned long val;
46462306a36Sopenharmony_ci	u8 regval;
46562306a36Sopenharmony_ci
46662306a36Sopenharmony_ci	if (ret)
46762306a36Sopenharmony_ci		return ret;
46862306a36Sopenharmony_ci
46962306a36Sopenharmony_ci	ret = kstrtoul(buf, 10, &val);
47062306a36Sopenharmony_ci	if (ret < 0)
47162306a36Sopenharmony_ci		return ret;
47262306a36Sopenharmony_ci
47362306a36Sopenharmony_ci	for (regval = 0; regval < 3; regval++) {
47462306a36Sopenharmony_ci		if (val <= update_intervals[regval])
47562306a36Sopenharmony_ci			break;
47662306a36Sopenharmony_ci	}
47762306a36Sopenharmony_ci
47862306a36Sopenharmony_ci	mutex_lock(&data->update_lock);
47962306a36Sopenharmony_ci	data->interval = msecs_to_jiffies(update_intervals[regval]);
48062306a36Sopenharmony_ci	i2c_smbus_write_byte_data(data->client, LM95234_REG_CONVRATE, regval);
48162306a36Sopenharmony_ci	mutex_unlock(&data->update_lock);
48262306a36Sopenharmony_ci
48362306a36Sopenharmony_ci	return count;
48462306a36Sopenharmony_ci}
48562306a36Sopenharmony_ci
48662306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RO(temp1_input, temp, 0);
48762306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RO(temp2_input, temp, 1);
48862306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RO(temp3_input, temp, 2);
48962306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RO(temp4_input, temp, 3);
49062306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RO(temp5_input, temp, 4);
49162306a36Sopenharmony_ci
49262306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RO(temp2_fault, alarm, BIT(0) | BIT(1));
49362306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RO(temp3_fault, alarm, BIT(2) | BIT(3));
49462306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RO(temp4_fault, alarm, BIT(4) | BIT(5));
49562306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RO(temp5_fault, alarm, BIT(6) | BIT(7));
49662306a36Sopenharmony_ci
49762306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(temp2_type, type, BIT(1));
49862306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(temp3_type, type, BIT(2));
49962306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(temp4_type, type, BIT(3));
50062306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(temp5_type, type, BIT(4));
50162306a36Sopenharmony_ci
50262306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(temp1_max, tcrit1, 0);
50362306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(temp2_max, tcrit2, 0);
50462306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(temp3_max, tcrit2, 1);
50562306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(temp4_max, tcrit1, 3);
50662306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(temp5_max, tcrit1, 4);
50762306a36Sopenharmony_ci
50862306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(temp1_max_hyst, tcrit1_hyst, 0);
50962306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RO(temp2_max_hyst, tcrit2_hyst, 0);
51062306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RO(temp3_max_hyst, tcrit2_hyst, 1);
51162306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RO(temp4_max_hyst, tcrit1_hyst, 3);
51262306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RO(temp5_max_hyst, tcrit1_hyst, 4);
51362306a36Sopenharmony_ci
51462306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RO(temp1_max_alarm, alarm, BIT(0 + 8));
51562306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RO(temp2_max_alarm, alarm, BIT(1 + 16));
51662306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RO(temp3_max_alarm, alarm, BIT(2 + 16));
51762306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RO(temp4_max_alarm, alarm, BIT(3 + 8));
51862306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RO(temp5_max_alarm, alarm, BIT(4 + 8));
51962306a36Sopenharmony_ci
52062306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(temp2_crit, tcrit1, 1);
52162306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(temp3_crit, tcrit1, 2);
52262306a36Sopenharmony_ci
52362306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RO(temp2_crit_hyst, tcrit1_hyst, 1);
52462306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RO(temp3_crit_hyst, tcrit1_hyst, 2);
52562306a36Sopenharmony_ci
52662306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RO(temp2_crit_alarm, alarm, BIT(1 + 8));
52762306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RO(temp3_crit_alarm, alarm, BIT(2 + 8));
52862306a36Sopenharmony_ci
52962306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(temp2_offset, offset, 0);
53062306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(temp3_offset, offset, 1);
53162306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(temp4_offset, offset, 2);
53262306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(temp5_offset, offset, 3);
53362306a36Sopenharmony_ci
53462306a36Sopenharmony_cistatic DEVICE_ATTR_RW(update_interval);
53562306a36Sopenharmony_ci
53662306a36Sopenharmony_cistatic struct attribute *lm95234_common_attrs[] = {
53762306a36Sopenharmony_ci	&sensor_dev_attr_temp1_input.dev_attr.attr,
53862306a36Sopenharmony_ci	&sensor_dev_attr_temp2_input.dev_attr.attr,
53962306a36Sopenharmony_ci	&sensor_dev_attr_temp3_input.dev_attr.attr,
54062306a36Sopenharmony_ci	&sensor_dev_attr_temp2_fault.dev_attr.attr,
54162306a36Sopenharmony_ci	&sensor_dev_attr_temp3_fault.dev_attr.attr,
54262306a36Sopenharmony_ci	&sensor_dev_attr_temp2_type.dev_attr.attr,
54362306a36Sopenharmony_ci	&sensor_dev_attr_temp3_type.dev_attr.attr,
54462306a36Sopenharmony_ci	&sensor_dev_attr_temp1_max.dev_attr.attr,
54562306a36Sopenharmony_ci	&sensor_dev_attr_temp2_max.dev_attr.attr,
54662306a36Sopenharmony_ci	&sensor_dev_attr_temp3_max.dev_attr.attr,
54762306a36Sopenharmony_ci	&sensor_dev_attr_temp1_max_hyst.dev_attr.attr,
54862306a36Sopenharmony_ci	&sensor_dev_attr_temp2_max_hyst.dev_attr.attr,
54962306a36Sopenharmony_ci	&sensor_dev_attr_temp3_max_hyst.dev_attr.attr,
55062306a36Sopenharmony_ci	&sensor_dev_attr_temp1_max_alarm.dev_attr.attr,
55162306a36Sopenharmony_ci	&sensor_dev_attr_temp2_max_alarm.dev_attr.attr,
55262306a36Sopenharmony_ci	&sensor_dev_attr_temp3_max_alarm.dev_attr.attr,
55362306a36Sopenharmony_ci	&sensor_dev_attr_temp2_crit.dev_attr.attr,
55462306a36Sopenharmony_ci	&sensor_dev_attr_temp3_crit.dev_attr.attr,
55562306a36Sopenharmony_ci	&sensor_dev_attr_temp2_crit_hyst.dev_attr.attr,
55662306a36Sopenharmony_ci	&sensor_dev_attr_temp3_crit_hyst.dev_attr.attr,
55762306a36Sopenharmony_ci	&sensor_dev_attr_temp2_crit_alarm.dev_attr.attr,
55862306a36Sopenharmony_ci	&sensor_dev_attr_temp3_crit_alarm.dev_attr.attr,
55962306a36Sopenharmony_ci	&sensor_dev_attr_temp2_offset.dev_attr.attr,
56062306a36Sopenharmony_ci	&sensor_dev_attr_temp3_offset.dev_attr.attr,
56162306a36Sopenharmony_ci	&dev_attr_update_interval.attr,
56262306a36Sopenharmony_ci	NULL
56362306a36Sopenharmony_ci};
56462306a36Sopenharmony_ci
56562306a36Sopenharmony_cistatic const struct attribute_group lm95234_common_group = {
56662306a36Sopenharmony_ci	.attrs = lm95234_common_attrs,
56762306a36Sopenharmony_ci};
56862306a36Sopenharmony_ci
56962306a36Sopenharmony_cistatic struct attribute *lm95234_attrs[] = {
57062306a36Sopenharmony_ci	&sensor_dev_attr_temp4_input.dev_attr.attr,
57162306a36Sopenharmony_ci	&sensor_dev_attr_temp5_input.dev_attr.attr,
57262306a36Sopenharmony_ci	&sensor_dev_attr_temp4_fault.dev_attr.attr,
57362306a36Sopenharmony_ci	&sensor_dev_attr_temp5_fault.dev_attr.attr,
57462306a36Sopenharmony_ci	&sensor_dev_attr_temp4_type.dev_attr.attr,
57562306a36Sopenharmony_ci	&sensor_dev_attr_temp5_type.dev_attr.attr,
57662306a36Sopenharmony_ci	&sensor_dev_attr_temp4_max.dev_attr.attr,
57762306a36Sopenharmony_ci	&sensor_dev_attr_temp5_max.dev_attr.attr,
57862306a36Sopenharmony_ci	&sensor_dev_attr_temp4_max_hyst.dev_attr.attr,
57962306a36Sopenharmony_ci	&sensor_dev_attr_temp5_max_hyst.dev_attr.attr,
58062306a36Sopenharmony_ci	&sensor_dev_attr_temp4_max_alarm.dev_attr.attr,
58162306a36Sopenharmony_ci	&sensor_dev_attr_temp5_max_alarm.dev_attr.attr,
58262306a36Sopenharmony_ci	&sensor_dev_attr_temp4_offset.dev_attr.attr,
58362306a36Sopenharmony_ci	&sensor_dev_attr_temp5_offset.dev_attr.attr,
58462306a36Sopenharmony_ci	NULL
58562306a36Sopenharmony_ci};
58662306a36Sopenharmony_ci
58762306a36Sopenharmony_cistatic const struct attribute_group lm95234_group = {
58862306a36Sopenharmony_ci	.attrs = lm95234_attrs,
58962306a36Sopenharmony_ci};
59062306a36Sopenharmony_ci
59162306a36Sopenharmony_cistatic int lm95234_detect(struct i2c_client *client,
59262306a36Sopenharmony_ci			  struct i2c_board_info *info)
59362306a36Sopenharmony_ci{
59462306a36Sopenharmony_ci	struct i2c_adapter *adapter = client->adapter;
59562306a36Sopenharmony_ci	int address = client->addr;
59662306a36Sopenharmony_ci	u8 config_mask, model_mask;
59762306a36Sopenharmony_ci	int mfg_id, chip_id, val;
59862306a36Sopenharmony_ci	const char *name;
59962306a36Sopenharmony_ci
60062306a36Sopenharmony_ci	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
60162306a36Sopenharmony_ci		return -ENODEV;
60262306a36Sopenharmony_ci
60362306a36Sopenharmony_ci	mfg_id = i2c_smbus_read_byte_data(client, LM95234_REG_MAN_ID);
60462306a36Sopenharmony_ci	if (mfg_id != NATSEMI_MAN_ID)
60562306a36Sopenharmony_ci		return -ENODEV;
60662306a36Sopenharmony_ci
60762306a36Sopenharmony_ci	chip_id = i2c_smbus_read_byte_data(client, LM95234_REG_CHIP_ID);
60862306a36Sopenharmony_ci	switch (chip_id) {
60962306a36Sopenharmony_ci	case LM95233_CHIP_ID:
61062306a36Sopenharmony_ci		if (address != 0x18 && address != 0x2a && address != 0x2b)
61162306a36Sopenharmony_ci			return -ENODEV;
61262306a36Sopenharmony_ci		config_mask = 0xbf;
61362306a36Sopenharmony_ci		model_mask = 0xf9;
61462306a36Sopenharmony_ci		name = "lm95233";
61562306a36Sopenharmony_ci		break;
61662306a36Sopenharmony_ci	case LM95234_CHIP_ID:
61762306a36Sopenharmony_ci		if (address != 0x18 && address != 0x4d && address != 0x4e)
61862306a36Sopenharmony_ci			return -ENODEV;
61962306a36Sopenharmony_ci		config_mask = 0xbc;
62062306a36Sopenharmony_ci		model_mask = 0xe1;
62162306a36Sopenharmony_ci		name = "lm95234";
62262306a36Sopenharmony_ci		break;
62362306a36Sopenharmony_ci	default:
62462306a36Sopenharmony_ci		return -ENODEV;
62562306a36Sopenharmony_ci	}
62662306a36Sopenharmony_ci
62762306a36Sopenharmony_ci	val = i2c_smbus_read_byte_data(client, LM95234_REG_STATUS);
62862306a36Sopenharmony_ci	if (val & 0x30)
62962306a36Sopenharmony_ci		return -ENODEV;
63062306a36Sopenharmony_ci
63162306a36Sopenharmony_ci	val = i2c_smbus_read_byte_data(client, LM95234_REG_CONFIG);
63262306a36Sopenharmony_ci	if (val & config_mask)
63362306a36Sopenharmony_ci		return -ENODEV;
63462306a36Sopenharmony_ci
63562306a36Sopenharmony_ci	val = i2c_smbus_read_byte_data(client, LM95234_REG_CONVRATE);
63662306a36Sopenharmony_ci	if (val & 0xfc)
63762306a36Sopenharmony_ci		return -ENODEV;
63862306a36Sopenharmony_ci
63962306a36Sopenharmony_ci	val = i2c_smbus_read_byte_data(client, LM95234_REG_REM_MODEL);
64062306a36Sopenharmony_ci	if (val & model_mask)
64162306a36Sopenharmony_ci		return -ENODEV;
64262306a36Sopenharmony_ci
64362306a36Sopenharmony_ci	val = i2c_smbus_read_byte_data(client, LM95234_REG_REM_MODEL_STS);
64462306a36Sopenharmony_ci	if (val & model_mask)
64562306a36Sopenharmony_ci		return -ENODEV;
64662306a36Sopenharmony_ci
64762306a36Sopenharmony_ci	strscpy(info->type, name, I2C_NAME_SIZE);
64862306a36Sopenharmony_ci	return 0;
64962306a36Sopenharmony_ci}
65062306a36Sopenharmony_ci
65162306a36Sopenharmony_cistatic int lm95234_init_client(struct i2c_client *client)
65262306a36Sopenharmony_ci{
65362306a36Sopenharmony_ci	int val, model;
65462306a36Sopenharmony_ci
65562306a36Sopenharmony_ci	/* start conversion if necessary */
65662306a36Sopenharmony_ci	val = i2c_smbus_read_byte_data(client, LM95234_REG_CONFIG);
65762306a36Sopenharmony_ci	if (val < 0)
65862306a36Sopenharmony_ci		return val;
65962306a36Sopenharmony_ci	if (val & 0x40)
66062306a36Sopenharmony_ci		i2c_smbus_write_byte_data(client, LM95234_REG_CONFIG,
66162306a36Sopenharmony_ci					  val & ~0x40);
66262306a36Sopenharmony_ci
66362306a36Sopenharmony_ci	/* If diode type status reports an error, try to fix it */
66462306a36Sopenharmony_ci	val = i2c_smbus_read_byte_data(client, LM95234_REG_REM_MODEL_STS);
66562306a36Sopenharmony_ci	if (val < 0)
66662306a36Sopenharmony_ci		return val;
66762306a36Sopenharmony_ci	model = i2c_smbus_read_byte_data(client, LM95234_REG_REM_MODEL);
66862306a36Sopenharmony_ci	if (model < 0)
66962306a36Sopenharmony_ci		return model;
67062306a36Sopenharmony_ci	if (model & val) {
67162306a36Sopenharmony_ci		dev_notice(&client->dev,
67262306a36Sopenharmony_ci			   "Fixing remote diode type misconfiguration (0x%x)\n",
67362306a36Sopenharmony_ci			   val);
67462306a36Sopenharmony_ci		i2c_smbus_write_byte_data(client, LM95234_REG_REM_MODEL,
67562306a36Sopenharmony_ci					  model & ~val);
67662306a36Sopenharmony_ci	}
67762306a36Sopenharmony_ci	return 0;
67862306a36Sopenharmony_ci}
67962306a36Sopenharmony_ci
68062306a36Sopenharmony_cistatic const struct i2c_device_id lm95234_id[];
68162306a36Sopenharmony_ci
68262306a36Sopenharmony_cistatic int lm95234_probe(struct i2c_client *client)
68362306a36Sopenharmony_ci{
68462306a36Sopenharmony_ci	struct device *dev = &client->dev;
68562306a36Sopenharmony_ci	struct lm95234_data *data;
68662306a36Sopenharmony_ci	struct device *hwmon_dev;
68762306a36Sopenharmony_ci	int err;
68862306a36Sopenharmony_ci
68962306a36Sopenharmony_ci	data = devm_kzalloc(dev, sizeof(struct lm95234_data), GFP_KERNEL);
69062306a36Sopenharmony_ci	if (!data)
69162306a36Sopenharmony_ci		return -ENOMEM;
69262306a36Sopenharmony_ci
69362306a36Sopenharmony_ci	data->client = client;
69462306a36Sopenharmony_ci	mutex_init(&data->update_lock);
69562306a36Sopenharmony_ci
69662306a36Sopenharmony_ci	/* Initialize the LM95234 chip */
69762306a36Sopenharmony_ci	err = lm95234_init_client(client);
69862306a36Sopenharmony_ci	if (err < 0)
69962306a36Sopenharmony_ci		return err;
70062306a36Sopenharmony_ci
70162306a36Sopenharmony_ci	data->groups[0] = &lm95234_common_group;
70262306a36Sopenharmony_ci	if (i2c_match_id(lm95234_id, client)->driver_data == lm95234)
70362306a36Sopenharmony_ci		data->groups[1] = &lm95234_group;
70462306a36Sopenharmony_ci
70562306a36Sopenharmony_ci	hwmon_dev = devm_hwmon_device_register_with_groups(dev, client->name,
70662306a36Sopenharmony_ci							   data, data->groups);
70762306a36Sopenharmony_ci	return PTR_ERR_OR_ZERO(hwmon_dev);
70862306a36Sopenharmony_ci}
70962306a36Sopenharmony_ci
71062306a36Sopenharmony_ci/* Driver data (common to all clients) */
71162306a36Sopenharmony_cistatic const struct i2c_device_id lm95234_id[] = {
71262306a36Sopenharmony_ci	{ "lm95233", lm95233 },
71362306a36Sopenharmony_ci	{ "lm95234", lm95234 },
71462306a36Sopenharmony_ci	{ }
71562306a36Sopenharmony_ci};
71662306a36Sopenharmony_ciMODULE_DEVICE_TABLE(i2c, lm95234_id);
71762306a36Sopenharmony_ci
71862306a36Sopenharmony_cistatic struct i2c_driver lm95234_driver = {
71962306a36Sopenharmony_ci	.class		= I2C_CLASS_HWMON,
72062306a36Sopenharmony_ci	.driver = {
72162306a36Sopenharmony_ci		.name	= DRVNAME,
72262306a36Sopenharmony_ci	},
72362306a36Sopenharmony_ci	.probe		= lm95234_probe,
72462306a36Sopenharmony_ci	.id_table	= lm95234_id,
72562306a36Sopenharmony_ci	.detect		= lm95234_detect,
72662306a36Sopenharmony_ci	.address_list	= normal_i2c,
72762306a36Sopenharmony_ci};
72862306a36Sopenharmony_ci
72962306a36Sopenharmony_cimodule_i2c_driver(lm95234_driver);
73062306a36Sopenharmony_ci
73162306a36Sopenharmony_ciMODULE_AUTHOR("Guenter Roeck <linux@roeck-us.net>");
73262306a36Sopenharmony_ciMODULE_DESCRIPTION("LM95233/LM95234 sensor driver");
73362306a36Sopenharmony_ciMODULE_LICENSE("GPL");
734