162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Copyright (C) 2008, 2010 Davide Rizzo <elpa.rizzo@gmail.com>
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * The LM95241 is a sensor chip made by National Semiconductors.
662306a36Sopenharmony_ci * It reports up to three temperatures (its own plus up to two external ones).
762306a36Sopenharmony_ci * Complete datasheet can be obtained from National's website at:
862306a36Sopenharmony_ci *   http://www.national.com/ds.cgi/LM/LM95241.pdf
962306a36Sopenharmony_ci */
1062306a36Sopenharmony_ci
1162306a36Sopenharmony_ci#include <linux/bitops.h>
1262306a36Sopenharmony_ci#include <linux/err.h>
1362306a36Sopenharmony_ci#include <linux/i2c.h>
1462306a36Sopenharmony_ci#include <linux/init.h>
1562306a36Sopenharmony_ci#include <linux/jiffies.h>
1662306a36Sopenharmony_ci#include <linux/hwmon.h>
1762306a36Sopenharmony_ci#include <linux/module.h>
1862306a36Sopenharmony_ci#include <linux/mutex.h>
1962306a36Sopenharmony_ci#include <linux/slab.h>
2062306a36Sopenharmony_ci
2162306a36Sopenharmony_ci#define DEVNAME "lm95241"
2262306a36Sopenharmony_ci
2362306a36Sopenharmony_cistatic const unsigned short normal_i2c[] = {
2462306a36Sopenharmony_ci	0x19, 0x2a, 0x2b, I2C_CLIENT_END };
2562306a36Sopenharmony_ci
2662306a36Sopenharmony_ci/* LM95241 registers */
2762306a36Sopenharmony_ci#define LM95241_REG_R_MAN_ID		0xFE
2862306a36Sopenharmony_ci#define LM95241_REG_R_CHIP_ID		0xFF
2962306a36Sopenharmony_ci#define LM95241_REG_R_STATUS		0x02
3062306a36Sopenharmony_ci#define LM95241_REG_RW_CONFIG		0x03
3162306a36Sopenharmony_ci#define LM95241_REG_RW_REM_FILTER	0x06
3262306a36Sopenharmony_ci#define LM95241_REG_RW_TRUTHERM		0x07
3362306a36Sopenharmony_ci#define LM95241_REG_W_ONE_SHOT		0x0F
3462306a36Sopenharmony_ci#define LM95241_REG_R_LOCAL_TEMPH	0x10
3562306a36Sopenharmony_ci#define LM95241_REG_R_REMOTE1_TEMPH	0x11
3662306a36Sopenharmony_ci#define LM95241_REG_R_REMOTE2_TEMPH	0x12
3762306a36Sopenharmony_ci#define LM95241_REG_R_LOCAL_TEMPL	0x20
3862306a36Sopenharmony_ci#define LM95241_REG_R_REMOTE1_TEMPL	0x21
3962306a36Sopenharmony_ci#define LM95241_REG_R_REMOTE2_TEMPL	0x22
4062306a36Sopenharmony_ci#define LM95241_REG_RW_REMOTE_MODEL	0x30
4162306a36Sopenharmony_ci
4262306a36Sopenharmony_ci/* LM95241 specific bitfields */
4362306a36Sopenharmony_ci#define CFG_STOP	BIT(6)
4462306a36Sopenharmony_ci#define CFG_CR0076	0x00
4562306a36Sopenharmony_ci#define CFG_CR0182	BIT(4)
4662306a36Sopenharmony_ci#define CFG_CR1000	BIT(5)
4762306a36Sopenharmony_ci#define CFG_CR2700	(BIT(4) | BIT(5))
4862306a36Sopenharmony_ci#define CFG_CRMASK	(BIT(4) | BIT(5))
4962306a36Sopenharmony_ci#define R1MS_MASK	BIT(0)
5062306a36Sopenharmony_ci#define R2MS_MASK	BIT(2)
5162306a36Sopenharmony_ci#define R1DF_MASK	BIT(1)
5262306a36Sopenharmony_ci#define R2DF_MASK	BIT(2)
5362306a36Sopenharmony_ci#define R1FE_MASK	BIT(0)
5462306a36Sopenharmony_ci#define R2FE_MASK	BIT(2)
5562306a36Sopenharmony_ci#define R1DM		BIT(0)
5662306a36Sopenharmony_ci#define R2DM		BIT(1)
5762306a36Sopenharmony_ci#define TT1_SHIFT	0
5862306a36Sopenharmony_ci#define TT2_SHIFT	4
5962306a36Sopenharmony_ci#define TT_OFF		0
6062306a36Sopenharmony_ci#define TT_ON		1
6162306a36Sopenharmony_ci#define TT_MASK		7
6262306a36Sopenharmony_ci#define NATSEMI_MAN_ID	0x01
6362306a36Sopenharmony_ci#define LM95231_CHIP_ID	0xA1
6462306a36Sopenharmony_ci#define LM95241_CHIP_ID	0xA4
6562306a36Sopenharmony_ci
6662306a36Sopenharmony_cistatic const u8 lm95241_reg_address[] = {
6762306a36Sopenharmony_ci	LM95241_REG_R_LOCAL_TEMPH,
6862306a36Sopenharmony_ci	LM95241_REG_R_LOCAL_TEMPL,
6962306a36Sopenharmony_ci	LM95241_REG_R_REMOTE1_TEMPH,
7062306a36Sopenharmony_ci	LM95241_REG_R_REMOTE1_TEMPL,
7162306a36Sopenharmony_ci	LM95241_REG_R_REMOTE2_TEMPH,
7262306a36Sopenharmony_ci	LM95241_REG_R_REMOTE2_TEMPL
7362306a36Sopenharmony_ci};
7462306a36Sopenharmony_ci
7562306a36Sopenharmony_ci/* Client data (each client gets its own) */
7662306a36Sopenharmony_cistruct lm95241_data {
7762306a36Sopenharmony_ci	struct i2c_client *client;
7862306a36Sopenharmony_ci	struct mutex update_lock;
7962306a36Sopenharmony_ci	unsigned long last_updated;	/* in jiffies */
8062306a36Sopenharmony_ci	unsigned long interval;		/* in milli-seconds */
8162306a36Sopenharmony_ci	bool valid;		/* false until following fields are valid */
8262306a36Sopenharmony_ci	/* registers values */
8362306a36Sopenharmony_ci	u8 temp[ARRAY_SIZE(lm95241_reg_address)];
8462306a36Sopenharmony_ci	u8 status, config, model, trutherm;
8562306a36Sopenharmony_ci};
8662306a36Sopenharmony_ci
8762306a36Sopenharmony_ci/* Conversions */
8862306a36Sopenharmony_cistatic int temp_from_reg_signed(u8 val_h, u8 val_l)
8962306a36Sopenharmony_ci{
9062306a36Sopenharmony_ci	s16 val_hl = (val_h << 8) | val_l;
9162306a36Sopenharmony_ci	return val_hl * 1000 / 256;
9262306a36Sopenharmony_ci}
9362306a36Sopenharmony_ci
9462306a36Sopenharmony_cistatic int temp_from_reg_unsigned(u8 val_h, u8 val_l)
9562306a36Sopenharmony_ci{
9662306a36Sopenharmony_ci	u16 val_hl = (val_h << 8) | val_l;
9762306a36Sopenharmony_ci	return val_hl * 1000 / 256;
9862306a36Sopenharmony_ci}
9962306a36Sopenharmony_ci
10062306a36Sopenharmony_cistatic struct lm95241_data *lm95241_update_device(struct device *dev)
10162306a36Sopenharmony_ci{
10262306a36Sopenharmony_ci	struct lm95241_data *data = dev_get_drvdata(dev);
10362306a36Sopenharmony_ci	struct i2c_client *client = data->client;
10462306a36Sopenharmony_ci
10562306a36Sopenharmony_ci	mutex_lock(&data->update_lock);
10662306a36Sopenharmony_ci
10762306a36Sopenharmony_ci	if (time_after(jiffies, data->last_updated
10862306a36Sopenharmony_ci		       + msecs_to_jiffies(data->interval)) ||
10962306a36Sopenharmony_ci	    !data->valid) {
11062306a36Sopenharmony_ci		int i;
11162306a36Sopenharmony_ci
11262306a36Sopenharmony_ci		dev_dbg(dev, "Updating lm95241 data.\n");
11362306a36Sopenharmony_ci		for (i = 0; i < ARRAY_SIZE(lm95241_reg_address); i++)
11462306a36Sopenharmony_ci			data->temp[i]
11562306a36Sopenharmony_ci			  = i2c_smbus_read_byte_data(client,
11662306a36Sopenharmony_ci						     lm95241_reg_address[i]);
11762306a36Sopenharmony_ci
11862306a36Sopenharmony_ci		data->status = i2c_smbus_read_byte_data(client,
11962306a36Sopenharmony_ci							LM95241_REG_R_STATUS);
12062306a36Sopenharmony_ci		data->last_updated = jiffies;
12162306a36Sopenharmony_ci		data->valid = true;
12262306a36Sopenharmony_ci	}
12362306a36Sopenharmony_ci
12462306a36Sopenharmony_ci	mutex_unlock(&data->update_lock);
12562306a36Sopenharmony_ci
12662306a36Sopenharmony_ci	return data;
12762306a36Sopenharmony_ci}
12862306a36Sopenharmony_ci
12962306a36Sopenharmony_cistatic int lm95241_read_chip(struct device *dev, u32 attr, int channel,
13062306a36Sopenharmony_ci			     long *val)
13162306a36Sopenharmony_ci{
13262306a36Sopenharmony_ci	struct lm95241_data *data = dev_get_drvdata(dev);
13362306a36Sopenharmony_ci
13462306a36Sopenharmony_ci	switch (attr) {
13562306a36Sopenharmony_ci	case hwmon_chip_update_interval:
13662306a36Sopenharmony_ci		*val = data->interval;
13762306a36Sopenharmony_ci		return 0;
13862306a36Sopenharmony_ci	default:
13962306a36Sopenharmony_ci		return -EOPNOTSUPP;
14062306a36Sopenharmony_ci	}
14162306a36Sopenharmony_ci}
14262306a36Sopenharmony_ci
14362306a36Sopenharmony_cistatic int lm95241_read_temp(struct device *dev, u32 attr, int channel,
14462306a36Sopenharmony_ci			     long *val)
14562306a36Sopenharmony_ci{
14662306a36Sopenharmony_ci	struct lm95241_data *data = lm95241_update_device(dev);
14762306a36Sopenharmony_ci
14862306a36Sopenharmony_ci	switch (attr) {
14962306a36Sopenharmony_ci	case hwmon_temp_input:
15062306a36Sopenharmony_ci		if (!channel || (data->config & BIT(channel - 1)))
15162306a36Sopenharmony_ci			*val = temp_from_reg_signed(data->temp[channel * 2],
15262306a36Sopenharmony_ci						data->temp[channel * 2 + 1]);
15362306a36Sopenharmony_ci		else
15462306a36Sopenharmony_ci			*val = temp_from_reg_unsigned(data->temp[channel * 2],
15562306a36Sopenharmony_ci						data->temp[channel * 2 + 1]);
15662306a36Sopenharmony_ci		return 0;
15762306a36Sopenharmony_ci	case hwmon_temp_min:
15862306a36Sopenharmony_ci		if (channel == 1)
15962306a36Sopenharmony_ci			*val = (data->config & R1DF_MASK) ? -128000 : 0;
16062306a36Sopenharmony_ci		else
16162306a36Sopenharmony_ci			*val = (data->config & R2DF_MASK) ? -128000 : 0;
16262306a36Sopenharmony_ci		return 0;
16362306a36Sopenharmony_ci	case hwmon_temp_max:
16462306a36Sopenharmony_ci		if (channel == 1)
16562306a36Sopenharmony_ci			*val = (data->config & R1DF_MASK) ? 127875 : 255875;
16662306a36Sopenharmony_ci		else
16762306a36Sopenharmony_ci			*val = (data->config & R2DF_MASK) ? 127875 : 255875;
16862306a36Sopenharmony_ci		return 0;
16962306a36Sopenharmony_ci	case hwmon_temp_type:
17062306a36Sopenharmony_ci		if (channel == 1)
17162306a36Sopenharmony_ci			*val = (data->model & R1MS_MASK) ? 1 : 2;
17262306a36Sopenharmony_ci		else
17362306a36Sopenharmony_ci			*val = (data->model & R2MS_MASK) ? 1 : 2;
17462306a36Sopenharmony_ci		return 0;
17562306a36Sopenharmony_ci	case hwmon_temp_fault:
17662306a36Sopenharmony_ci		if (channel == 1)
17762306a36Sopenharmony_ci			*val = !!(data->status & R1DM);
17862306a36Sopenharmony_ci		else
17962306a36Sopenharmony_ci			*val = !!(data->status & R2DM);
18062306a36Sopenharmony_ci		return 0;
18162306a36Sopenharmony_ci	default:
18262306a36Sopenharmony_ci		return -EOPNOTSUPP;
18362306a36Sopenharmony_ci	}
18462306a36Sopenharmony_ci}
18562306a36Sopenharmony_ci
18662306a36Sopenharmony_cistatic int lm95241_read(struct device *dev, enum hwmon_sensor_types type,
18762306a36Sopenharmony_ci			u32 attr, int channel, long *val)
18862306a36Sopenharmony_ci{
18962306a36Sopenharmony_ci	switch (type) {
19062306a36Sopenharmony_ci	case hwmon_chip:
19162306a36Sopenharmony_ci		return lm95241_read_chip(dev, attr, channel, val);
19262306a36Sopenharmony_ci	case hwmon_temp:
19362306a36Sopenharmony_ci		return lm95241_read_temp(dev, attr, channel, val);
19462306a36Sopenharmony_ci	default:
19562306a36Sopenharmony_ci		return -EOPNOTSUPP;
19662306a36Sopenharmony_ci	}
19762306a36Sopenharmony_ci}
19862306a36Sopenharmony_ci
19962306a36Sopenharmony_cistatic int lm95241_write_chip(struct device *dev, u32 attr, int channel,
20062306a36Sopenharmony_ci			      long val)
20162306a36Sopenharmony_ci{
20262306a36Sopenharmony_ci	struct lm95241_data *data = dev_get_drvdata(dev);
20362306a36Sopenharmony_ci	int convrate;
20462306a36Sopenharmony_ci	u8 config;
20562306a36Sopenharmony_ci	int ret;
20662306a36Sopenharmony_ci
20762306a36Sopenharmony_ci	mutex_lock(&data->update_lock);
20862306a36Sopenharmony_ci
20962306a36Sopenharmony_ci	switch (attr) {
21062306a36Sopenharmony_ci	case hwmon_chip_update_interval:
21162306a36Sopenharmony_ci		config = data->config & ~CFG_CRMASK;
21262306a36Sopenharmony_ci		if (val < 130) {
21362306a36Sopenharmony_ci			convrate = 76;
21462306a36Sopenharmony_ci			config |= CFG_CR0076;
21562306a36Sopenharmony_ci		} else if (val < 590) {
21662306a36Sopenharmony_ci			convrate = 182;
21762306a36Sopenharmony_ci			config |= CFG_CR0182;
21862306a36Sopenharmony_ci		} else if (val < 1850) {
21962306a36Sopenharmony_ci			convrate = 1000;
22062306a36Sopenharmony_ci			config |= CFG_CR1000;
22162306a36Sopenharmony_ci		} else {
22262306a36Sopenharmony_ci			convrate = 2700;
22362306a36Sopenharmony_ci			config |= CFG_CR2700;
22462306a36Sopenharmony_ci		}
22562306a36Sopenharmony_ci		data->interval = convrate;
22662306a36Sopenharmony_ci		data->config = config;
22762306a36Sopenharmony_ci		ret = i2c_smbus_write_byte_data(data->client,
22862306a36Sopenharmony_ci						LM95241_REG_RW_CONFIG, config);
22962306a36Sopenharmony_ci		break;
23062306a36Sopenharmony_ci	default:
23162306a36Sopenharmony_ci		ret = -EOPNOTSUPP;
23262306a36Sopenharmony_ci		break;
23362306a36Sopenharmony_ci	}
23462306a36Sopenharmony_ci	mutex_unlock(&data->update_lock);
23562306a36Sopenharmony_ci	return ret;
23662306a36Sopenharmony_ci}
23762306a36Sopenharmony_ci
23862306a36Sopenharmony_cistatic int lm95241_write_temp(struct device *dev, u32 attr, int channel,
23962306a36Sopenharmony_ci			      long val)
24062306a36Sopenharmony_ci{
24162306a36Sopenharmony_ci	struct lm95241_data *data = dev_get_drvdata(dev);
24262306a36Sopenharmony_ci	struct i2c_client *client = data->client;
24362306a36Sopenharmony_ci	int ret;
24462306a36Sopenharmony_ci
24562306a36Sopenharmony_ci	mutex_lock(&data->update_lock);
24662306a36Sopenharmony_ci
24762306a36Sopenharmony_ci	switch (attr) {
24862306a36Sopenharmony_ci	case hwmon_temp_min:
24962306a36Sopenharmony_ci		if (channel == 1) {
25062306a36Sopenharmony_ci			if (val < 0)
25162306a36Sopenharmony_ci				data->config |= R1DF_MASK;
25262306a36Sopenharmony_ci			else
25362306a36Sopenharmony_ci				data->config &= ~R1DF_MASK;
25462306a36Sopenharmony_ci		} else {
25562306a36Sopenharmony_ci			if (val < 0)
25662306a36Sopenharmony_ci				data->config |= R2DF_MASK;
25762306a36Sopenharmony_ci			else
25862306a36Sopenharmony_ci				data->config &= ~R2DF_MASK;
25962306a36Sopenharmony_ci		}
26062306a36Sopenharmony_ci		data->valid = false;
26162306a36Sopenharmony_ci		ret = i2c_smbus_write_byte_data(client, LM95241_REG_RW_CONFIG,
26262306a36Sopenharmony_ci						data->config);
26362306a36Sopenharmony_ci		break;
26462306a36Sopenharmony_ci	case hwmon_temp_max:
26562306a36Sopenharmony_ci		if (channel == 1) {
26662306a36Sopenharmony_ci			if (val <= 127875)
26762306a36Sopenharmony_ci				data->config |= R1DF_MASK;
26862306a36Sopenharmony_ci			else
26962306a36Sopenharmony_ci				data->config &= ~R1DF_MASK;
27062306a36Sopenharmony_ci		} else {
27162306a36Sopenharmony_ci			if (val <= 127875)
27262306a36Sopenharmony_ci				data->config |= R2DF_MASK;
27362306a36Sopenharmony_ci			else
27462306a36Sopenharmony_ci				data->config &= ~R2DF_MASK;
27562306a36Sopenharmony_ci		}
27662306a36Sopenharmony_ci		data->valid = false;
27762306a36Sopenharmony_ci		ret = i2c_smbus_write_byte_data(client, LM95241_REG_RW_CONFIG,
27862306a36Sopenharmony_ci						data->config);
27962306a36Sopenharmony_ci		break;
28062306a36Sopenharmony_ci	case hwmon_temp_type:
28162306a36Sopenharmony_ci		if (val != 1 && val != 2) {
28262306a36Sopenharmony_ci			ret = -EINVAL;
28362306a36Sopenharmony_ci			break;
28462306a36Sopenharmony_ci		}
28562306a36Sopenharmony_ci		if (channel == 1) {
28662306a36Sopenharmony_ci			data->trutherm &= ~(TT_MASK << TT1_SHIFT);
28762306a36Sopenharmony_ci			if (val == 1) {
28862306a36Sopenharmony_ci				data->model |= R1MS_MASK;
28962306a36Sopenharmony_ci				data->trutherm |= (TT_ON << TT1_SHIFT);
29062306a36Sopenharmony_ci			} else {
29162306a36Sopenharmony_ci				data->model &= ~R1MS_MASK;
29262306a36Sopenharmony_ci				data->trutherm |= (TT_OFF << TT1_SHIFT);
29362306a36Sopenharmony_ci			}
29462306a36Sopenharmony_ci		} else {
29562306a36Sopenharmony_ci			data->trutherm &= ~(TT_MASK << TT2_SHIFT);
29662306a36Sopenharmony_ci			if (val == 1) {
29762306a36Sopenharmony_ci				data->model |= R2MS_MASK;
29862306a36Sopenharmony_ci				data->trutherm |= (TT_ON << TT2_SHIFT);
29962306a36Sopenharmony_ci			} else {
30062306a36Sopenharmony_ci				data->model &= ~R2MS_MASK;
30162306a36Sopenharmony_ci				data->trutherm |= (TT_OFF << TT2_SHIFT);
30262306a36Sopenharmony_ci			}
30362306a36Sopenharmony_ci		}
30462306a36Sopenharmony_ci		ret = i2c_smbus_write_byte_data(client,
30562306a36Sopenharmony_ci						LM95241_REG_RW_REMOTE_MODEL,
30662306a36Sopenharmony_ci						data->model);
30762306a36Sopenharmony_ci		if (ret < 0)
30862306a36Sopenharmony_ci			break;
30962306a36Sopenharmony_ci		ret = i2c_smbus_write_byte_data(client, LM95241_REG_RW_TRUTHERM,
31062306a36Sopenharmony_ci						data->trutherm);
31162306a36Sopenharmony_ci		break;
31262306a36Sopenharmony_ci	default:
31362306a36Sopenharmony_ci		ret = -EOPNOTSUPP;
31462306a36Sopenharmony_ci		break;
31562306a36Sopenharmony_ci	}
31662306a36Sopenharmony_ci
31762306a36Sopenharmony_ci	mutex_unlock(&data->update_lock);
31862306a36Sopenharmony_ci
31962306a36Sopenharmony_ci	return ret;
32062306a36Sopenharmony_ci}
32162306a36Sopenharmony_ci
32262306a36Sopenharmony_cistatic int lm95241_write(struct device *dev, enum hwmon_sensor_types type,
32362306a36Sopenharmony_ci			 u32 attr, int channel, long val)
32462306a36Sopenharmony_ci{
32562306a36Sopenharmony_ci	switch (type) {
32662306a36Sopenharmony_ci	case hwmon_chip:
32762306a36Sopenharmony_ci		return lm95241_write_chip(dev, attr, channel, val);
32862306a36Sopenharmony_ci	case hwmon_temp:
32962306a36Sopenharmony_ci		return lm95241_write_temp(dev, attr, channel, val);
33062306a36Sopenharmony_ci	default:
33162306a36Sopenharmony_ci		return -EOPNOTSUPP;
33262306a36Sopenharmony_ci	}
33362306a36Sopenharmony_ci}
33462306a36Sopenharmony_ci
33562306a36Sopenharmony_cistatic umode_t lm95241_is_visible(const void *data,
33662306a36Sopenharmony_ci				  enum hwmon_sensor_types type,
33762306a36Sopenharmony_ci				  u32 attr, int channel)
33862306a36Sopenharmony_ci{
33962306a36Sopenharmony_ci	switch (type) {
34062306a36Sopenharmony_ci	case hwmon_chip:
34162306a36Sopenharmony_ci		switch (attr) {
34262306a36Sopenharmony_ci		case hwmon_chip_update_interval:
34362306a36Sopenharmony_ci			return 0644;
34462306a36Sopenharmony_ci		}
34562306a36Sopenharmony_ci		break;
34662306a36Sopenharmony_ci	case hwmon_temp:
34762306a36Sopenharmony_ci		switch (attr) {
34862306a36Sopenharmony_ci		case hwmon_temp_input:
34962306a36Sopenharmony_ci			return 0444;
35062306a36Sopenharmony_ci		case hwmon_temp_fault:
35162306a36Sopenharmony_ci			return 0444;
35262306a36Sopenharmony_ci		case hwmon_temp_min:
35362306a36Sopenharmony_ci		case hwmon_temp_max:
35462306a36Sopenharmony_ci		case hwmon_temp_type:
35562306a36Sopenharmony_ci			return 0644;
35662306a36Sopenharmony_ci		}
35762306a36Sopenharmony_ci		break;
35862306a36Sopenharmony_ci	default:
35962306a36Sopenharmony_ci		break;
36062306a36Sopenharmony_ci	}
36162306a36Sopenharmony_ci	return 0;
36262306a36Sopenharmony_ci}
36362306a36Sopenharmony_ci
36462306a36Sopenharmony_ci/* Return 0 if detection is successful, -ENODEV otherwise */
36562306a36Sopenharmony_cistatic int lm95241_detect(struct i2c_client *new_client,
36662306a36Sopenharmony_ci			  struct i2c_board_info *info)
36762306a36Sopenharmony_ci{
36862306a36Sopenharmony_ci	struct i2c_adapter *adapter = new_client->adapter;
36962306a36Sopenharmony_ci	const char *name;
37062306a36Sopenharmony_ci	int mfg_id, chip_id;
37162306a36Sopenharmony_ci
37262306a36Sopenharmony_ci	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
37362306a36Sopenharmony_ci		return -ENODEV;
37462306a36Sopenharmony_ci
37562306a36Sopenharmony_ci	mfg_id = i2c_smbus_read_byte_data(new_client, LM95241_REG_R_MAN_ID);
37662306a36Sopenharmony_ci	if (mfg_id != NATSEMI_MAN_ID)
37762306a36Sopenharmony_ci		return -ENODEV;
37862306a36Sopenharmony_ci
37962306a36Sopenharmony_ci	chip_id = i2c_smbus_read_byte_data(new_client, LM95241_REG_R_CHIP_ID);
38062306a36Sopenharmony_ci	switch (chip_id) {
38162306a36Sopenharmony_ci	case LM95231_CHIP_ID:
38262306a36Sopenharmony_ci		name = "lm95231";
38362306a36Sopenharmony_ci		break;
38462306a36Sopenharmony_ci	case LM95241_CHIP_ID:
38562306a36Sopenharmony_ci		name = "lm95241";
38662306a36Sopenharmony_ci		break;
38762306a36Sopenharmony_ci	default:
38862306a36Sopenharmony_ci		return -ENODEV;
38962306a36Sopenharmony_ci	}
39062306a36Sopenharmony_ci
39162306a36Sopenharmony_ci	/* Fill the i2c board info */
39262306a36Sopenharmony_ci	strscpy(info->type, name, I2C_NAME_SIZE);
39362306a36Sopenharmony_ci	return 0;
39462306a36Sopenharmony_ci}
39562306a36Sopenharmony_ci
39662306a36Sopenharmony_cistatic void lm95241_init_client(struct i2c_client *client,
39762306a36Sopenharmony_ci				struct lm95241_data *data)
39862306a36Sopenharmony_ci{
39962306a36Sopenharmony_ci	data->interval = 1000;
40062306a36Sopenharmony_ci	data->config = CFG_CR1000;
40162306a36Sopenharmony_ci	data->trutherm = (TT_OFF << TT1_SHIFT) | (TT_OFF << TT2_SHIFT);
40262306a36Sopenharmony_ci
40362306a36Sopenharmony_ci	i2c_smbus_write_byte_data(client, LM95241_REG_RW_CONFIG, data->config);
40462306a36Sopenharmony_ci	i2c_smbus_write_byte_data(client, LM95241_REG_RW_REM_FILTER,
40562306a36Sopenharmony_ci				  R1FE_MASK | R2FE_MASK);
40662306a36Sopenharmony_ci	i2c_smbus_write_byte_data(client, LM95241_REG_RW_TRUTHERM,
40762306a36Sopenharmony_ci				  data->trutherm);
40862306a36Sopenharmony_ci	i2c_smbus_write_byte_data(client, LM95241_REG_RW_REMOTE_MODEL,
40962306a36Sopenharmony_ci				  data->model);
41062306a36Sopenharmony_ci}
41162306a36Sopenharmony_ci
41262306a36Sopenharmony_cistatic const struct hwmon_channel_info * const lm95241_info[] = {
41362306a36Sopenharmony_ci	HWMON_CHANNEL_INFO(chip,
41462306a36Sopenharmony_ci			   HWMON_C_UPDATE_INTERVAL),
41562306a36Sopenharmony_ci	HWMON_CHANNEL_INFO(temp,
41662306a36Sopenharmony_ci			   HWMON_T_INPUT,
41762306a36Sopenharmony_ci			   HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_MIN |
41862306a36Sopenharmony_ci			   HWMON_T_TYPE | HWMON_T_FAULT,
41962306a36Sopenharmony_ci			   HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_MIN |
42062306a36Sopenharmony_ci			   HWMON_T_TYPE | HWMON_T_FAULT),
42162306a36Sopenharmony_ci	NULL
42262306a36Sopenharmony_ci};
42362306a36Sopenharmony_ci
42462306a36Sopenharmony_cistatic const struct hwmon_ops lm95241_hwmon_ops = {
42562306a36Sopenharmony_ci	.is_visible = lm95241_is_visible,
42662306a36Sopenharmony_ci	.read = lm95241_read,
42762306a36Sopenharmony_ci	.write = lm95241_write,
42862306a36Sopenharmony_ci};
42962306a36Sopenharmony_ci
43062306a36Sopenharmony_cistatic const struct hwmon_chip_info lm95241_chip_info = {
43162306a36Sopenharmony_ci	.ops = &lm95241_hwmon_ops,
43262306a36Sopenharmony_ci	.info = lm95241_info,
43362306a36Sopenharmony_ci};
43462306a36Sopenharmony_ci
43562306a36Sopenharmony_cistatic int lm95241_probe(struct i2c_client *client)
43662306a36Sopenharmony_ci{
43762306a36Sopenharmony_ci	struct device *dev = &client->dev;
43862306a36Sopenharmony_ci	struct lm95241_data *data;
43962306a36Sopenharmony_ci	struct device *hwmon_dev;
44062306a36Sopenharmony_ci
44162306a36Sopenharmony_ci	data = devm_kzalloc(dev, sizeof(struct lm95241_data), GFP_KERNEL);
44262306a36Sopenharmony_ci	if (!data)
44362306a36Sopenharmony_ci		return -ENOMEM;
44462306a36Sopenharmony_ci
44562306a36Sopenharmony_ci	data->client = client;
44662306a36Sopenharmony_ci	mutex_init(&data->update_lock);
44762306a36Sopenharmony_ci
44862306a36Sopenharmony_ci	/* Initialize the LM95241 chip */
44962306a36Sopenharmony_ci	lm95241_init_client(client, data);
45062306a36Sopenharmony_ci
45162306a36Sopenharmony_ci	hwmon_dev = devm_hwmon_device_register_with_info(dev, client->name,
45262306a36Sopenharmony_ci							   data,
45362306a36Sopenharmony_ci							   &lm95241_chip_info,
45462306a36Sopenharmony_ci							   NULL);
45562306a36Sopenharmony_ci	return PTR_ERR_OR_ZERO(hwmon_dev);
45662306a36Sopenharmony_ci}
45762306a36Sopenharmony_ci
45862306a36Sopenharmony_ci/* Driver data (common to all clients) */
45962306a36Sopenharmony_cistatic const struct i2c_device_id lm95241_id[] = {
46062306a36Sopenharmony_ci	{ "lm95231", 0 },
46162306a36Sopenharmony_ci	{ "lm95241", 0 },
46262306a36Sopenharmony_ci	{ }
46362306a36Sopenharmony_ci};
46462306a36Sopenharmony_ciMODULE_DEVICE_TABLE(i2c, lm95241_id);
46562306a36Sopenharmony_ci
46662306a36Sopenharmony_cistatic struct i2c_driver lm95241_driver = {
46762306a36Sopenharmony_ci	.class		= I2C_CLASS_HWMON,
46862306a36Sopenharmony_ci	.driver = {
46962306a36Sopenharmony_ci		.name	= DEVNAME,
47062306a36Sopenharmony_ci	},
47162306a36Sopenharmony_ci	.probe		= lm95241_probe,
47262306a36Sopenharmony_ci	.id_table	= lm95241_id,
47362306a36Sopenharmony_ci	.detect		= lm95241_detect,
47462306a36Sopenharmony_ci	.address_list	= normal_i2c,
47562306a36Sopenharmony_ci};
47662306a36Sopenharmony_ci
47762306a36Sopenharmony_cimodule_i2c_driver(lm95241_driver);
47862306a36Sopenharmony_ci
47962306a36Sopenharmony_ciMODULE_AUTHOR("Davide Rizzo <elpa.rizzo@gmail.com>");
48062306a36Sopenharmony_ciMODULE_DESCRIPTION("LM95231/LM95241 sensor driver");
48162306a36Sopenharmony_ciMODULE_LICENSE("GPL");
482