162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * thmc50.c - Part of lm_sensors, Linux kernel modules for hardware
462306a36Sopenharmony_ci *	      monitoring
562306a36Sopenharmony_ci * Copyright (C) 2007 Krzysztof Helt <krzysztof.h1@wp.pl>
662306a36Sopenharmony_ci * Based on 2.4 driver by Frodo Looijaard <frodol@dds.nl> and
762306a36Sopenharmony_ci * Philip Edelbrock <phil@netroedge.com>
862306a36Sopenharmony_ci */
962306a36Sopenharmony_ci
1062306a36Sopenharmony_ci#include <linux/module.h>
1162306a36Sopenharmony_ci#include <linux/init.h>
1262306a36Sopenharmony_ci#include <linux/slab.h>
1362306a36Sopenharmony_ci#include <linux/i2c.h>
1462306a36Sopenharmony_ci#include <linux/hwmon.h>
1562306a36Sopenharmony_ci#include <linux/hwmon-sysfs.h>
1662306a36Sopenharmony_ci#include <linux/err.h>
1762306a36Sopenharmony_ci#include <linux/mutex.h>
1862306a36Sopenharmony_ci#include <linux/jiffies.h>
1962306a36Sopenharmony_ci
2062306a36Sopenharmony_ciMODULE_LICENSE("GPL");
2162306a36Sopenharmony_ci
2262306a36Sopenharmony_ci/* Addresses to scan */
2362306a36Sopenharmony_cistatic const unsigned short normal_i2c[] = { 0x2c, 0x2d, 0x2e, I2C_CLIENT_END };
2462306a36Sopenharmony_ci
2562306a36Sopenharmony_ci/* Insmod parameters */
2662306a36Sopenharmony_cienum chips { thmc50, adm1022 };
2762306a36Sopenharmony_ci
2862306a36Sopenharmony_cistatic unsigned short adm1022_temp3[16];
2962306a36Sopenharmony_cistatic unsigned int adm1022_temp3_num;
3062306a36Sopenharmony_cimodule_param_array(adm1022_temp3, ushort, &adm1022_temp3_num, 0);
3162306a36Sopenharmony_ciMODULE_PARM_DESC(adm1022_temp3,
3262306a36Sopenharmony_ci		 "List of adapter,address pairs to enable 3rd temperature (ADM1022 only)");
3362306a36Sopenharmony_ci
3462306a36Sopenharmony_ci/* Many THMC50 constants specified below */
3562306a36Sopenharmony_ci
3662306a36Sopenharmony_ci/* The THMC50 registers */
3762306a36Sopenharmony_ci#define THMC50_REG_CONF				0x40
3862306a36Sopenharmony_ci#define THMC50_REG_COMPANY_ID			0x3E
3962306a36Sopenharmony_ci#define THMC50_REG_DIE_CODE			0x3F
4062306a36Sopenharmony_ci#define THMC50_REG_ANALOG_OUT			0x19
4162306a36Sopenharmony_ci/*
4262306a36Sopenharmony_ci * The mirror status register cannot be used as
4362306a36Sopenharmony_ci * reading it does not clear alarms.
4462306a36Sopenharmony_ci */
4562306a36Sopenharmony_ci#define THMC50_REG_INTR				0x41
4662306a36Sopenharmony_ci
4762306a36Sopenharmony_cistatic const u8 THMC50_REG_TEMP[] = { 0x27, 0x26, 0x20 };
4862306a36Sopenharmony_cistatic const u8 THMC50_REG_TEMP_MIN[] = { 0x3A, 0x38, 0x2C };
4962306a36Sopenharmony_cistatic const u8 THMC50_REG_TEMP_MAX[] = { 0x39, 0x37, 0x2B };
5062306a36Sopenharmony_cistatic const u8 THMC50_REG_TEMP_CRITICAL[] = { 0x13, 0x14, 0x14 };
5162306a36Sopenharmony_cistatic const u8 THMC50_REG_TEMP_DEFAULT[] = { 0x17, 0x18, 0x18 };
5262306a36Sopenharmony_ci
5362306a36Sopenharmony_ci#define THMC50_REG_CONF_nFANOFF			0x20
5462306a36Sopenharmony_ci#define THMC50_REG_CONF_PROGRAMMED		0x08
5562306a36Sopenharmony_ci
5662306a36Sopenharmony_ci/* Each client has this additional data */
5762306a36Sopenharmony_cistruct thmc50_data {
5862306a36Sopenharmony_ci	struct i2c_client *client;
5962306a36Sopenharmony_ci	const struct attribute_group *groups[3];
6062306a36Sopenharmony_ci
6162306a36Sopenharmony_ci	struct mutex update_lock;
6262306a36Sopenharmony_ci	enum chips type;
6362306a36Sopenharmony_ci	unsigned long last_updated;	/* In jiffies */
6462306a36Sopenharmony_ci	char has_temp3;		/* !=0 if it is ADM1022 in temp3 mode */
6562306a36Sopenharmony_ci	bool valid;		/* true if following fields are valid */
6662306a36Sopenharmony_ci
6762306a36Sopenharmony_ci	/* Register values */
6862306a36Sopenharmony_ci	s8 temp_input[3];
6962306a36Sopenharmony_ci	s8 temp_max[3];
7062306a36Sopenharmony_ci	s8 temp_min[3];
7162306a36Sopenharmony_ci	s8 temp_critical[3];
7262306a36Sopenharmony_ci	u8 analog_out;
7362306a36Sopenharmony_ci	u8 alarms;
7462306a36Sopenharmony_ci};
7562306a36Sopenharmony_ci
7662306a36Sopenharmony_cistatic struct thmc50_data *thmc50_update_device(struct device *dev)
7762306a36Sopenharmony_ci{
7862306a36Sopenharmony_ci	struct thmc50_data *data = dev_get_drvdata(dev);
7962306a36Sopenharmony_ci	struct i2c_client *client = data->client;
8062306a36Sopenharmony_ci	int timeout = HZ / 5 + (data->type == thmc50 ? HZ : 0);
8162306a36Sopenharmony_ci
8262306a36Sopenharmony_ci	mutex_lock(&data->update_lock);
8362306a36Sopenharmony_ci
8462306a36Sopenharmony_ci	if (time_after(jiffies, data->last_updated + timeout)
8562306a36Sopenharmony_ci	    || !data->valid) {
8662306a36Sopenharmony_ci
8762306a36Sopenharmony_ci		int temps = data->has_temp3 ? 3 : 2;
8862306a36Sopenharmony_ci		int i;
8962306a36Sopenharmony_ci		int prog = i2c_smbus_read_byte_data(client, THMC50_REG_CONF);
9062306a36Sopenharmony_ci
9162306a36Sopenharmony_ci		prog &= THMC50_REG_CONF_PROGRAMMED;
9262306a36Sopenharmony_ci
9362306a36Sopenharmony_ci		for (i = 0; i < temps; i++) {
9462306a36Sopenharmony_ci			data->temp_input[i] = i2c_smbus_read_byte_data(client,
9562306a36Sopenharmony_ci						THMC50_REG_TEMP[i]);
9662306a36Sopenharmony_ci			data->temp_max[i] = i2c_smbus_read_byte_data(client,
9762306a36Sopenharmony_ci						THMC50_REG_TEMP_MAX[i]);
9862306a36Sopenharmony_ci			data->temp_min[i] = i2c_smbus_read_byte_data(client,
9962306a36Sopenharmony_ci						THMC50_REG_TEMP_MIN[i]);
10062306a36Sopenharmony_ci			data->temp_critical[i] =
10162306a36Sopenharmony_ci				i2c_smbus_read_byte_data(client,
10262306a36Sopenharmony_ci					prog ? THMC50_REG_TEMP_CRITICAL[i]
10362306a36Sopenharmony_ci					     : THMC50_REG_TEMP_DEFAULT[i]);
10462306a36Sopenharmony_ci		}
10562306a36Sopenharmony_ci		data->analog_out =
10662306a36Sopenharmony_ci		    i2c_smbus_read_byte_data(client, THMC50_REG_ANALOG_OUT);
10762306a36Sopenharmony_ci		data->alarms =
10862306a36Sopenharmony_ci		    i2c_smbus_read_byte_data(client, THMC50_REG_INTR);
10962306a36Sopenharmony_ci		data->last_updated = jiffies;
11062306a36Sopenharmony_ci		data->valid = true;
11162306a36Sopenharmony_ci	}
11262306a36Sopenharmony_ci
11362306a36Sopenharmony_ci	mutex_unlock(&data->update_lock);
11462306a36Sopenharmony_ci
11562306a36Sopenharmony_ci	return data;
11662306a36Sopenharmony_ci}
11762306a36Sopenharmony_ci
11862306a36Sopenharmony_cistatic ssize_t analog_out_show(struct device *dev,
11962306a36Sopenharmony_ci			       struct device_attribute *attr, char *buf)
12062306a36Sopenharmony_ci{
12162306a36Sopenharmony_ci	struct thmc50_data *data = thmc50_update_device(dev);
12262306a36Sopenharmony_ci	return sprintf(buf, "%d\n", data->analog_out);
12362306a36Sopenharmony_ci}
12462306a36Sopenharmony_ci
12562306a36Sopenharmony_cistatic ssize_t analog_out_store(struct device *dev,
12662306a36Sopenharmony_ci				struct device_attribute *attr,
12762306a36Sopenharmony_ci				const char *buf, size_t count)
12862306a36Sopenharmony_ci{
12962306a36Sopenharmony_ci	struct thmc50_data *data = dev_get_drvdata(dev);
13062306a36Sopenharmony_ci	struct i2c_client *client = data->client;
13162306a36Sopenharmony_ci	int config;
13262306a36Sopenharmony_ci	unsigned long tmp;
13362306a36Sopenharmony_ci	int err;
13462306a36Sopenharmony_ci
13562306a36Sopenharmony_ci	err = kstrtoul(buf, 10, &tmp);
13662306a36Sopenharmony_ci	if (err)
13762306a36Sopenharmony_ci		return err;
13862306a36Sopenharmony_ci
13962306a36Sopenharmony_ci	mutex_lock(&data->update_lock);
14062306a36Sopenharmony_ci	data->analog_out = clamp_val(tmp, 0, 255);
14162306a36Sopenharmony_ci	i2c_smbus_write_byte_data(client, THMC50_REG_ANALOG_OUT,
14262306a36Sopenharmony_ci				  data->analog_out);
14362306a36Sopenharmony_ci
14462306a36Sopenharmony_ci	config = i2c_smbus_read_byte_data(client, THMC50_REG_CONF);
14562306a36Sopenharmony_ci	if (data->analog_out == 0)
14662306a36Sopenharmony_ci		config &= ~THMC50_REG_CONF_nFANOFF;
14762306a36Sopenharmony_ci	else
14862306a36Sopenharmony_ci		config |= THMC50_REG_CONF_nFANOFF;
14962306a36Sopenharmony_ci	i2c_smbus_write_byte_data(client, THMC50_REG_CONF, config);
15062306a36Sopenharmony_ci
15162306a36Sopenharmony_ci	mutex_unlock(&data->update_lock);
15262306a36Sopenharmony_ci	return count;
15362306a36Sopenharmony_ci}
15462306a36Sopenharmony_ci
15562306a36Sopenharmony_ci/* There is only one PWM mode = DC */
15662306a36Sopenharmony_cistatic ssize_t pwm_mode_show(struct device *dev,
15762306a36Sopenharmony_ci			     struct device_attribute *attr, char *buf)
15862306a36Sopenharmony_ci{
15962306a36Sopenharmony_ci	return sprintf(buf, "0\n");
16062306a36Sopenharmony_ci}
16162306a36Sopenharmony_ci
16262306a36Sopenharmony_ci/* Temperatures */
16362306a36Sopenharmony_cistatic ssize_t temp_show(struct device *dev, struct device_attribute *attr,
16462306a36Sopenharmony_ci			 char *buf)
16562306a36Sopenharmony_ci{
16662306a36Sopenharmony_ci	int nr = to_sensor_dev_attr(attr)->index;
16762306a36Sopenharmony_ci	struct thmc50_data *data = thmc50_update_device(dev);
16862306a36Sopenharmony_ci	return sprintf(buf, "%d\n", data->temp_input[nr] * 1000);
16962306a36Sopenharmony_ci}
17062306a36Sopenharmony_ci
17162306a36Sopenharmony_cistatic ssize_t temp_min_show(struct device *dev,
17262306a36Sopenharmony_ci			     struct device_attribute *attr, char *buf)
17362306a36Sopenharmony_ci{
17462306a36Sopenharmony_ci	int nr = to_sensor_dev_attr(attr)->index;
17562306a36Sopenharmony_ci	struct thmc50_data *data = thmc50_update_device(dev);
17662306a36Sopenharmony_ci	return sprintf(buf, "%d\n", data->temp_min[nr] * 1000);
17762306a36Sopenharmony_ci}
17862306a36Sopenharmony_ci
17962306a36Sopenharmony_cistatic ssize_t temp_min_store(struct device *dev,
18062306a36Sopenharmony_ci			      struct device_attribute *attr, const char *buf,
18162306a36Sopenharmony_ci			      size_t count)
18262306a36Sopenharmony_ci{
18362306a36Sopenharmony_ci	int nr = to_sensor_dev_attr(attr)->index;
18462306a36Sopenharmony_ci	struct thmc50_data *data = dev_get_drvdata(dev);
18562306a36Sopenharmony_ci	struct i2c_client *client = data->client;
18662306a36Sopenharmony_ci	long val;
18762306a36Sopenharmony_ci	int err;
18862306a36Sopenharmony_ci
18962306a36Sopenharmony_ci	err = kstrtol(buf, 10, &val);
19062306a36Sopenharmony_ci	if (err)
19162306a36Sopenharmony_ci		return err;
19262306a36Sopenharmony_ci
19362306a36Sopenharmony_ci	mutex_lock(&data->update_lock);
19462306a36Sopenharmony_ci	data->temp_min[nr] = clamp_val(val / 1000, -128, 127);
19562306a36Sopenharmony_ci	i2c_smbus_write_byte_data(client, THMC50_REG_TEMP_MIN[nr],
19662306a36Sopenharmony_ci				  data->temp_min[nr]);
19762306a36Sopenharmony_ci	mutex_unlock(&data->update_lock);
19862306a36Sopenharmony_ci	return count;
19962306a36Sopenharmony_ci}
20062306a36Sopenharmony_ci
20162306a36Sopenharmony_cistatic ssize_t temp_max_show(struct device *dev,
20262306a36Sopenharmony_ci			     struct device_attribute *attr, char *buf)
20362306a36Sopenharmony_ci{
20462306a36Sopenharmony_ci	int nr = to_sensor_dev_attr(attr)->index;
20562306a36Sopenharmony_ci	struct thmc50_data *data = thmc50_update_device(dev);
20662306a36Sopenharmony_ci	return sprintf(buf, "%d\n", data->temp_max[nr] * 1000);
20762306a36Sopenharmony_ci}
20862306a36Sopenharmony_ci
20962306a36Sopenharmony_cistatic ssize_t temp_max_store(struct device *dev,
21062306a36Sopenharmony_ci			      struct device_attribute *attr, const char *buf,
21162306a36Sopenharmony_ci			      size_t count)
21262306a36Sopenharmony_ci{
21362306a36Sopenharmony_ci	int nr = to_sensor_dev_attr(attr)->index;
21462306a36Sopenharmony_ci	struct thmc50_data *data = dev_get_drvdata(dev);
21562306a36Sopenharmony_ci	struct i2c_client *client = data->client;
21662306a36Sopenharmony_ci	long val;
21762306a36Sopenharmony_ci	int err;
21862306a36Sopenharmony_ci
21962306a36Sopenharmony_ci	err = kstrtol(buf, 10, &val);
22062306a36Sopenharmony_ci	if (err)
22162306a36Sopenharmony_ci		return err;
22262306a36Sopenharmony_ci
22362306a36Sopenharmony_ci	mutex_lock(&data->update_lock);
22462306a36Sopenharmony_ci	data->temp_max[nr] = clamp_val(val / 1000, -128, 127);
22562306a36Sopenharmony_ci	i2c_smbus_write_byte_data(client, THMC50_REG_TEMP_MAX[nr],
22662306a36Sopenharmony_ci				  data->temp_max[nr]);
22762306a36Sopenharmony_ci	mutex_unlock(&data->update_lock);
22862306a36Sopenharmony_ci	return count;
22962306a36Sopenharmony_ci}
23062306a36Sopenharmony_ci
23162306a36Sopenharmony_cistatic ssize_t temp_critical_show(struct device *dev,
23262306a36Sopenharmony_ci				  struct device_attribute *attr, char *buf)
23362306a36Sopenharmony_ci{
23462306a36Sopenharmony_ci	int nr = to_sensor_dev_attr(attr)->index;
23562306a36Sopenharmony_ci	struct thmc50_data *data = thmc50_update_device(dev);
23662306a36Sopenharmony_ci	return sprintf(buf, "%d\n", data->temp_critical[nr] * 1000);
23762306a36Sopenharmony_ci}
23862306a36Sopenharmony_ci
23962306a36Sopenharmony_cistatic ssize_t alarm_show(struct device *dev, struct device_attribute *attr,
24062306a36Sopenharmony_ci			  char *buf)
24162306a36Sopenharmony_ci{
24262306a36Sopenharmony_ci	int index = to_sensor_dev_attr(attr)->index;
24362306a36Sopenharmony_ci	struct thmc50_data *data = thmc50_update_device(dev);
24462306a36Sopenharmony_ci
24562306a36Sopenharmony_ci	return sprintf(buf, "%u\n", (data->alarms >> index) & 1);
24662306a36Sopenharmony_ci}
24762306a36Sopenharmony_ci
24862306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RO(temp1_input, temp, 0);
24962306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(temp1_min, temp_min, 0);
25062306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(temp1_max, temp_max, 0);
25162306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RO(temp1_crit, temp_critical, 0);
25262306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RO(temp2_input, temp, 1);
25362306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(temp2_min, temp_min, 1);
25462306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(temp2_max, temp_max, 1);
25562306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RO(temp2_crit, temp_critical, 1);
25662306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RO(temp3_input, temp, 2);
25762306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(temp3_min, temp_min, 2);
25862306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(temp3_max, temp_max, 2);
25962306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RO(temp3_crit, temp_critical, 2);
26062306a36Sopenharmony_ci
26162306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RO(temp1_alarm, alarm, 0);
26262306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RO(temp2_alarm, alarm, 5);
26362306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RO(temp3_alarm, alarm, 1);
26462306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RO(temp2_fault, alarm, 7);
26562306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RO(temp3_fault, alarm, 2);
26662306a36Sopenharmony_ci
26762306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(pwm1, analog_out, 0);
26862306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RO(pwm1_mode, pwm_mode, 0);
26962306a36Sopenharmony_ci
27062306a36Sopenharmony_cistatic struct attribute *thmc50_attributes[] = {
27162306a36Sopenharmony_ci	&sensor_dev_attr_temp1_max.dev_attr.attr,
27262306a36Sopenharmony_ci	&sensor_dev_attr_temp1_min.dev_attr.attr,
27362306a36Sopenharmony_ci	&sensor_dev_attr_temp1_input.dev_attr.attr,
27462306a36Sopenharmony_ci	&sensor_dev_attr_temp1_crit.dev_attr.attr,
27562306a36Sopenharmony_ci	&sensor_dev_attr_temp1_alarm.dev_attr.attr,
27662306a36Sopenharmony_ci	&sensor_dev_attr_temp2_max.dev_attr.attr,
27762306a36Sopenharmony_ci	&sensor_dev_attr_temp2_min.dev_attr.attr,
27862306a36Sopenharmony_ci	&sensor_dev_attr_temp2_input.dev_attr.attr,
27962306a36Sopenharmony_ci	&sensor_dev_attr_temp2_crit.dev_attr.attr,
28062306a36Sopenharmony_ci	&sensor_dev_attr_temp2_alarm.dev_attr.attr,
28162306a36Sopenharmony_ci	&sensor_dev_attr_temp2_fault.dev_attr.attr,
28262306a36Sopenharmony_ci	&sensor_dev_attr_pwm1.dev_attr.attr,
28362306a36Sopenharmony_ci	&sensor_dev_attr_pwm1_mode.dev_attr.attr,
28462306a36Sopenharmony_ci	NULL
28562306a36Sopenharmony_ci};
28662306a36Sopenharmony_ci
28762306a36Sopenharmony_cistatic const struct attribute_group thmc50_group = {
28862306a36Sopenharmony_ci	.attrs = thmc50_attributes,
28962306a36Sopenharmony_ci};
29062306a36Sopenharmony_ci
29162306a36Sopenharmony_ci/* for ADM1022 3rd temperature mode */
29262306a36Sopenharmony_cistatic struct attribute *temp3_attributes[] = {
29362306a36Sopenharmony_ci	&sensor_dev_attr_temp3_max.dev_attr.attr,
29462306a36Sopenharmony_ci	&sensor_dev_attr_temp3_min.dev_attr.attr,
29562306a36Sopenharmony_ci	&sensor_dev_attr_temp3_input.dev_attr.attr,
29662306a36Sopenharmony_ci	&sensor_dev_attr_temp3_crit.dev_attr.attr,
29762306a36Sopenharmony_ci	&sensor_dev_attr_temp3_alarm.dev_attr.attr,
29862306a36Sopenharmony_ci	&sensor_dev_attr_temp3_fault.dev_attr.attr,
29962306a36Sopenharmony_ci	NULL
30062306a36Sopenharmony_ci};
30162306a36Sopenharmony_ci
30262306a36Sopenharmony_cistatic const struct attribute_group temp3_group = {
30362306a36Sopenharmony_ci	.attrs = temp3_attributes,
30462306a36Sopenharmony_ci};
30562306a36Sopenharmony_ci
30662306a36Sopenharmony_ci/* Return 0 if detection is successful, -ENODEV otherwise */
30762306a36Sopenharmony_cistatic int thmc50_detect(struct i2c_client *client,
30862306a36Sopenharmony_ci			 struct i2c_board_info *info)
30962306a36Sopenharmony_ci{
31062306a36Sopenharmony_ci	unsigned company;
31162306a36Sopenharmony_ci	unsigned revision;
31262306a36Sopenharmony_ci	unsigned config;
31362306a36Sopenharmony_ci	struct i2c_adapter *adapter = client->adapter;
31462306a36Sopenharmony_ci	const char *type_name;
31562306a36Sopenharmony_ci
31662306a36Sopenharmony_ci	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) {
31762306a36Sopenharmony_ci		pr_debug("thmc50: detect failed, smbus byte data not supported!\n");
31862306a36Sopenharmony_ci		return -ENODEV;
31962306a36Sopenharmony_ci	}
32062306a36Sopenharmony_ci
32162306a36Sopenharmony_ci	pr_debug("thmc50: Probing for THMC50 at 0x%2X on bus %d\n",
32262306a36Sopenharmony_ci		 client->addr, i2c_adapter_id(client->adapter));
32362306a36Sopenharmony_ci
32462306a36Sopenharmony_ci	company = i2c_smbus_read_byte_data(client, THMC50_REG_COMPANY_ID);
32562306a36Sopenharmony_ci	revision = i2c_smbus_read_byte_data(client, THMC50_REG_DIE_CODE);
32662306a36Sopenharmony_ci	config = i2c_smbus_read_byte_data(client, THMC50_REG_CONF);
32762306a36Sopenharmony_ci	if (revision < 0xc0 || (config & 0x10))
32862306a36Sopenharmony_ci		return -ENODEV;
32962306a36Sopenharmony_ci
33062306a36Sopenharmony_ci	if (company == 0x41) {
33162306a36Sopenharmony_ci		int id = i2c_adapter_id(client->adapter);
33262306a36Sopenharmony_ci		int i;
33362306a36Sopenharmony_ci
33462306a36Sopenharmony_ci		type_name = "adm1022";
33562306a36Sopenharmony_ci		for (i = 0; i + 1 < adm1022_temp3_num; i += 2)
33662306a36Sopenharmony_ci			if (adm1022_temp3[i] == id &&
33762306a36Sopenharmony_ci			    adm1022_temp3[i + 1] == client->addr) {
33862306a36Sopenharmony_ci				/* enable 2nd remote temp */
33962306a36Sopenharmony_ci				config |= (1 << 7);
34062306a36Sopenharmony_ci				i2c_smbus_write_byte_data(client,
34162306a36Sopenharmony_ci							  THMC50_REG_CONF,
34262306a36Sopenharmony_ci							  config);
34362306a36Sopenharmony_ci				break;
34462306a36Sopenharmony_ci			}
34562306a36Sopenharmony_ci	} else if (company == 0x49) {
34662306a36Sopenharmony_ci		type_name = "thmc50";
34762306a36Sopenharmony_ci	} else {
34862306a36Sopenharmony_ci		pr_debug("thmc50: Detection of THMC50/ADM1022 failed\n");
34962306a36Sopenharmony_ci		return -ENODEV;
35062306a36Sopenharmony_ci	}
35162306a36Sopenharmony_ci
35262306a36Sopenharmony_ci	pr_debug("thmc50: Detected %s (version %x, revision %x)\n",
35362306a36Sopenharmony_ci		 type_name, (revision >> 4) - 0xc, revision & 0xf);
35462306a36Sopenharmony_ci
35562306a36Sopenharmony_ci	strscpy(info->type, type_name, I2C_NAME_SIZE);
35662306a36Sopenharmony_ci
35762306a36Sopenharmony_ci	return 0;
35862306a36Sopenharmony_ci}
35962306a36Sopenharmony_ci
36062306a36Sopenharmony_cistatic void thmc50_init_client(struct thmc50_data *data)
36162306a36Sopenharmony_ci{
36262306a36Sopenharmony_ci	struct i2c_client *client = data->client;
36362306a36Sopenharmony_ci	int config;
36462306a36Sopenharmony_ci
36562306a36Sopenharmony_ci	data->analog_out = i2c_smbus_read_byte_data(client,
36662306a36Sopenharmony_ci						    THMC50_REG_ANALOG_OUT);
36762306a36Sopenharmony_ci	/* set up to at least 1 */
36862306a36Sopenharmony_ci	if (data->analog_out == 0) {
36962306a36Sopenharmony_ci		data->analog_out = 1;
37062306a36Sopenharmony_ci		i2c_smbus_write_byte_data(client, THMC50_REG_ANALOG_OUT,
37162306a36Sopenharmony_ci					  data->analog_out);
37262306a36Sopenharmony_ci	}
37362306a36Sopenharmony_ci	config = i2c_smbus_read_byte_data(client, THMC50_REG_CONF);
37462306a36Sopenharmony_ci	config |= 0x1;	/* start the chip if it is in standby mode */
37562306a36Sopenharmony_ci	if (data->type == adm1022 && (config & (1 << 7)))
37662306a36Sopenharmony_ci		data->has_temp3 = 1;
37762306a36Sopenharmony_ci	i2c_smbus_write_byte_data(client, THMC50_REG_CONF, config);
37862306a36Sopenharmony_ci}
37962306a36Sopenharmony_ci
38062306a36Sopenharmony_cistatic const struct i2c_device_id thmc50_id[];
38162306a36Sopenharmony_ci
38262306a36Sopenharmony_cistatic int thmc50_probe(struct i2c_client *client)
38362306a36Sopenharmony_ci{
38462306a36Sopenharmony_ci	struct device *dev = &client->dev;
38562306a36Sopenharmony_ci	struct thmc50_data *data;
38662306a36Sopenharmony_ci	struct device *hwmon_dev;
38762306a36Sopenharmony_ci	int idx = 0;
38862306a36Sopenharmony_ci
38962306a36Sopenharmony_ci	data = devm_kzalloc(dev, sizeof(struct thmc50_data), GFP_KERNEL);
39062306a36Sopenharmony_ci	if (!data)
39162306a36Sopenharmony_ci		return -ENOMEM;
39262306a36Sopenharmony_ci
39362306a36Sopenharmony_ci	data->client = client;
39462306a36Sopenharmony_ci	data->type = i2c_match_id(thmc50_id, client)->driver_data;
39562306a36Sopenharmony_ci	mutex_init(&data->update_lock);
39662306a36Sopenharmony_ci
39762306a36Sopenharmony_ci	thmc50_init_client(data);
39862306a36Sopenharmony_ci
39962306a36Sopenharmony_ci	/* sysfs hooks */
40062306a36Sopenharmony_ci	data->groups[idx++] = &thmc50_group;
40162306a36Sopenharmony_ci
40262306a36Sopenharmony_ci	/* Register additional ADM1022 sysfs hooks */
40362306a36Sopenharmony_ci	if (data->has_temp3)
40462306a36Sopenharmony_ci		data->groups[idx++] = &temp3_group;
40562306a36Sopenharmony_ci
40662306a36Sopenharmony_ci	hwmon_dev = devm_hwmon_device_register_with_groups(dev, client->name,
40762306a36Sopenharmony_ci							   data, data->groups);
40862306a36Sopenharmony_ci	return PTR_ERR_OR_ZERO(hwmon_dev);
40962306a36Sopenharmony_ci}
41062306a36Sopenharmony_ci
41162306a36Sopenharmony_cistatic const struct i2c_device_id thmc50_id[] = {
41262306a36Sopenharmony_ci	{ "adm1022", adm1022 },
41362306a36Sopenharmony_ci	{ "thmc50", thmc50 },
41462306a36Sopenharmony_ci	{ }
41562306a36Sopenharmony_ci};
41662306a36Sopenharmony_ciMODULE_DEVICE_TABLE(i2c, thmc50_id);
41762306a36Sopenharmony_ci
41862306a36Sopenharmony_cistatic struct i2c_driver thmc50_driver = {
41962306a36Sopenharmony_ci	.class = I2C_CLASS_HWMON,
42062306a36Sopenharmony_ci	.driver = {
42162306a36Sopenharmony_ci		.name = "thmc50",
42262306a36Sopenharmony_ci	},
42362306a36Sopenharmony_ci	.probe = thmc50_probe,
42462306a36Sopenharmony_ci	.id_table = thmc50_id,
42562306a36Sopenharmony_ci	.detect = thmc50_detect,
42662306a36Sopenharmony_ci	.address_list = normal_i2c,
42762306a36Sopenharmony_ci};
42862306a36Sopenharmony_ci
42962306a36Sopenharmony_cimodule_i2c_driver(thmc50_driver);
43062306a36Sopenharmony_ci
43162306a36Sopenharmony_ciMODULE_AUTHOR("Krzysztof Helt <krzysztof.h1@wp.pl>");
43262306a36Sopenharmony_ciMODULE_DESCRIPTION("THMC50 driver");
433