18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Copyright (C) 2008, 2010 Davide Rizzo <elpa.rizzo@gmail.com>
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * The LM95241 is a sensor chip made by National Semiconductors.
68c2ecf20Sopenharmony_ci * It reports up to three temperatures (its own plus up to two external ones).
78c2ecf20Sopenharmony_ci * Complete datasheet can be obtained from National's website at:
88c2ecf20Sopenharmony_ci *   http://www.national.com/ds.cgi/LM/LM95241.pdf
98c2ecf20Sopenharmony_ci */
108c2ecf20Sopenharmony_ci
118c2ecf20Sopenharmony_ci#include <linux/bitops.h>
128c2ecf20Sopenharmony_ci#include <linux/err.h>
138c2ecf20Sopenharmony_ci#include <linux/i2c.h>
148c2ecf20Sopenharmony_ci#include <linux/init.h>
158c2ecf20Sopenharmony_ci#include <linux/jiffies.h>
168c2ecf20Sopenharmony_ci#include <linux/hwmon.h>
178c2ecf20Sopenharmony_ci#include <linux/module.h>
188c2ecf20Sopenharmony_ci#include <linux/mutex.h>
198c2ecf20Sopenharmony_ci#include <linux/slab.h>
208c2ecf20Sopenharmony_ci
218c2ecf20Sopenharmony_ci#define DEVNAME "lm95241"
228c2ecf20Sopenharmony_ci
238c2ecf20Sopenharmony_cistatic const unsigned short normal_i2c[] = {
248c2ecf20Sopenharmony_ci	0x19, 0x2a, 0x2b, I2C_CLIENT_END };
258c2ecf20Sopenharmony_ci
268c2ecf20Sopenharmony_ci/* LM95241 registers */
278c2ecf20Sopenharmony_ci#define LM95241_REG_R_MAN_ID		0xFE
288c2ecf20Sopenharmony_ci#define LM95241_REG_R_CHIP_ID		0xFF
298c2ecf20Sopenharmony_ci#define LM95241_REG_R_STATUS		0x02
308c2ecf20Sopenharmony_ci#define LM95241_REG_RW_CONFIG		0x03
318c2ecf20Sopenharmony_ci#define LM95241_REG_RW_REM_FILTER	0x06
328c2ecf20Sopenharmony_ci#define LM95241_REG_RW_TRUTHERM		0x07
338c2ecf20Sopenharmony_ci#define LM95241_REG_W_ONE_SHOT		0x0F
348c2ecf20Sopenharmony_ci#define LM95241_REG_R_LOCAL_TEMPH	0x10
358c2ecf20Sopenharmony_ci#define LM95241_REG_R_REMOTE1_TEMPH	0x11
368c2ecf20Sopenharmony_ci#define LM95241_REG_R_REMOTE2_TEMPH	0x12
378c2ecf20Sopenharmony_ci#define LM95241_REG_R_LOCAL_TEMPL	0x20
388c2ecf20Sopenharmony_ci#define LM95241_REG_R_REMOTE1_TEMPL	0x21
398c2ecf20Sopenharmony_ci#define LM95241_REG_R_REMOTE2_TEMPL	0x22
408c2ecf20Sopenharmony_ci#define LM95241_REG_RW_REMOTE_MODEL	0x30
418c2ecf20Sopenharmony_ci
428c2ecf20Sopenharmony_ci/* LM95241 specific bitfields */
438c2ecf20Sopenharmony_ci#define CFG_STOP	BIT(6)
448c2ecf20Sopenharmony_ci#define CFG_CR0076	0x00
458c2ecf20Sopenharmony_ci#define CFG_CR0182	BIT(4)
468c2ecf20Sopenharmony_ci#define CFG_CR1000	BIT(5)
478c2ecf20Sopenharmony_ci#define CFG_CR2700	(BIT(4) | BIT(5))
488c2ecf20Sopenharmony_ci#define CFG_CRMASK	(BIT(4) | BIT(5))
498c2ecf20Sopenharmony_ci#define R1MS_MASK	BIT(0)
508c2ecf20Sopenharmony_ci#define R2MS_MASK	BIT(2)
518c2ecf20Sopenharmony_ci#define R1DF_MASK	BIT(1)
528c2ecf20Sopenharmony_ci#define R2DF_MASK	BIT(2)
538c2ecf20Sopenharmony_ci#define R1FE_MASK	BIT(0)
548c2ecf20Sopenharmony_ci#define R2FE_MASK	BIT(2)
558c2ecf20Sopenharmony_ci#define R1DM		BIT(0)
568c2ecf20Sopenharmony_ci#define R2DM		BIT(1)
578c2ecf20Sopenharmony_ci#define TT1_SHIFT	0
588c2ecf20Sopenharmony_ci#define TT2_SHIFT	4
598c2ecf20Sopenharmony_ci#define TT_OFF		0
608c2ecf20Sopenharmony_ci#define TT_ON		1
618c2ecf20Sopenharmony_ci#define TT_MASK		7
628c2ecf20Sopenharmony_ci#define NATSEMI_MAN_ID	0x01
638c2ecf20Sopenharmony_ci#define LM95231_CHIP_ID	0xA1
648c2ecf20Sopenharmony_ci#define LM95241_CHIP_ID	0xA4
658c2ecf20Sopenharmony_ci
668c2ecf20Sopenharmony_cistatic const u8 lm95241_reg_address[] = {
678c2ecf20Sopenharmony_ci	LM95241_REG_R_LOCAL_TEMPH,
688c2ecf20Sopenharmony_ci	LM95241_REG_R_LOCAL_TEMPL,
698c2ecf20Sopenharmony_ci	LM95241_REG_R_REMOTE1_TEMPH,
708c2ecf20Sopenharmony_ci	LM95241_REG_R_REMOTE1_TEMPL,
718c2ecf20Sopenharmony_ci	LM95241_REG_R_REMOTE2_TEMPH,
728c2ecf20Sopenharmony_ci	LM95241_REG_R_REMOTE2_TEMPL
738c2ecf20Sopenharmony_ci};
748c2ecf20Sopenharmony_ci
758c2ecf20Sopenharmony_ci/* Client data (each client gets its own) */
768c2ecf20Sopenharmony_cistruct lm95241_data {
778c2ecf20Sopenharmony_ci	struct i2c_client *client;
788c2ecf20Sopenharmony_ci	struct mutex update_lock;
798c2ecf20Sopenharmony_ci	unsigned long last_updated;	/* in jiffies */
808c2ecf20Sopenharmony_ci	unsigned long interval;		/* in milli-seconds */
818c2ecf20Sopenharmony_ci	char valid;		/* zero until following fields are valid */
828c2ecf20Sopenharmony_ci	/* registers values */
838c2ecf20Sopenharmony_ci	u8 temp[ARRAY_SIZE(lm95241_reg_address)];
848c2ecf20Sopenharmony_ci	u8 status, config, model, trutherm;
858c2ecf20Sopenharmony_ci};
868c2ecf20Sopenharmony_ci
878c2ecf20Sopenharmony_ci/* Conversions */
888c2ecf20Sopenharmony_cistatic int temp_from_reg_signed(u8 val_h, u8 val_l)
898c2ecf20Sopenharmony_ci{
908c2ecf20Sopenharmony_ci	s16 val_hl = (val_h << 8) | val_l;
918c2ecf20Sopenharmony_ci	return val_hl * 1000 / 256;
928c2ecf20Sopenharmony_ci}
938c2ecf20Sopenharmony_ci
948c2ecf20Sopenharmony_cistatic int temp_from_reg_unsigned(u8 val_h, u8 val_l)
958c2ecf20Sopenharmony_ci{
968c2ecf20Sopenharmony_ci	u16 val_hl = (val_h << 8) | val_l;
978c2ecf20Sopenharmony_ci	return val_hl * 1000 / 256;
988c2ecf20Sopenharmony_ci}
998c2ecf20Sopenharmony_ci
1008c2ecf20Sopenharmony_cistatic struct lm95241_data *lm95241_update_device(struct device *dev)
1018c2ecf20Sopenharmony_ci{
1028c2ecf20Sopenharmony_ci	struct lm95241_data *data = dev_get_drvdata(dev);
1038c2ecf20Sopenharmony_ci	struct i2c_client *client = data->client;
1048c2ecf20Sopenharmony_ci
1058c2ecf20Sopenharmony_ci	mutex_lock(&data->update_lock);
1068c2ecf20Sopenharmony_ci
1078c2ecf20Sopenharmony_ci	if (time_after(jiffies, data->last_updated
1088c2ecf20Sopenharmony_ci		       + msecs_to_jiffies(data->interval)) ||
1098c2ecf20Sopenharmony_ci	    !data->valid) {
1108c2ecf20Sopenharmony_ci		int i;
1118c2ecf20Sopenharmony_ci
1128c2ecf20Sopenharmony_ci		dev_dbg(dev, "Updating lm95241 data.\n");
1138c2ecf20Sopenharmony_ci		for (i = 0; i < ARRAY_SIZE(lm95241_reg_address); i++)
1148c2ecf20Sopenharmony_ci			data->temp[i]
1158c2ecf20Sopenharmony_ci			  = i2c_smbus_read_byte_data(client,
1168c2ecf20Sopenharmony_ci						     lm95241_reg_address[i]);
1178c2ecf20Sopenharmony_ci
1188c2ecf20Sopenharmony_ci		data->status = i2c_smbus_read_byte_data(client,
1198c2ecf20Sopenharmony_ci							LM95241_REG_R_STATUS);
1208c2ecf20Sopenharmony_ci		data->last_updated = jiffies;
1218c2ecf20Sopenharmony_ci		data->valid = 1;
1228c2ecf20Sopenharmony_ci	}
1238c2ecf20Sopenharmony_ci
1248c2ecf20Sopenharmony_ci	mutex_unlock(&data->update_lock);
1258c2ecf20Sopenharmony_ci
1268c2ecf20Sopenharmony_ci	return data;
1278c2ecf20Sopenharmony_ci}
1288c2ecf20Sopenharmony_ci
1298c2ecf20Sopenharmony_cistatic int lm95241_read_chip(struct device *dev, u32 attr, int channel,
1308c2ecf20Sopenharmony_ci			     long *val)
1318c2ecf20Sopenharmony_ci{
1328c2ecf20Sopenharmony_ci	struct lm95241_data *data = dev_get_drvdata(dev);
1338c2ecf20Sopenharmony_ci
1348c2ecf20Sopenharmony_ci	switch (attr) {
1358c2ecf20Sopenharmony_ci	case hwmon_chip_update_interval:
1368c2ecf20Sopenharmony_ci		*val = data->interval;
1378c2ecf20Sopenharmony_ci		return 0;
1388c2ecf20Sopenharmony_ci	default:
1398c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
1408c2ecf20Sopenharmony_ci	}
1418c2ecf20Sopenharmony_ci}
1428c2ecf20Sopenharmony_ci
1438c2ecf20Sopenharmony_cistatic int lm95241_read_temp(struct device *dev, u32 attr, int channel,
1448c2ecf20Sopenharmony_ci			     long *val)
1458c2ecf20Sopenharmony_ci{
1468c2ecf20Sopenharmony_ci	struct lm95241_data *data = lm95241_update_device(dev);
1478c2ecf20Sopenharmony_ci
1488c2ecf20Sopenharmony_ci	switch (attr) {
1498c2ecf20Sopenharmony_ci	case hwmon_temp_input:
1508c2ecf20Sopenharmony_ci		if (!channel || (data->config & BIT(channel - 1)))
1518c2ecf20Sopenharmony_ci			*val = temp_from_reg_signed(data->temp[channel * 2],
1528c2ecf20Sopenharmony_ci						data->temp[channel * 2 + 1]);
1538c2ecf20Sopenharmony_ci		else
1548c2ecf20Sopenharmony_ci			*val = temp_from_reg_unsigned(data->temp[channel * 2],
1558c2ecf20Sopenharmony_ci						data->temp[channel * 2 + 1]);
1568c2ecf20Sopenharmony_ci		return 0;
1578c2ecf20Sopenharmony_ci	case hwmon_temp_min:
1588c2ecf20Sopenharmony_ci		if (channel == 1)
1598c2ecf20Sopenharmony_ci			*val = (data->config & R1DF_MASK) ? -128000 : 0;
1608c2ecf20Sopenharmony_ci		else
1618c2ecf20Sopenharmony_ci			*val = (data->config & R2DF_MASK) ? -128000 : 0;
1628c2ecf20Sopenharmony_ci		return 0;
1638c2ecf20Sopenharmony_ci	case hwmon_temp_max:
1648c2ecf20Sopenharmony_ci		if (channel == 1)
1658c2ecf20Sopenharmony_ci			*val = (data->config & R1DF_MASK) ? 127875 : 255875;
1668c2ecf20Sopenharmony_ci		else
1678c2ecf20Sopenharmony_ci			*val = (data->config & R2DF_MASK) ? 127875 : 255875;
1688c2ecf20Sopenharmony_ci		return 0;
1698c2ecf20Sopenharmony_ci	case hwmon_temp_type:
1708c2ecf20Sopenharmony_ci		if (channel == 1)
1718c2ecf20Sopenharmony_ci			*val = (data->model & R1MS_MASK) ? 1 : 2;
1728c2ecf20Sopenharmony_ci		else
1738c2ecf20Sopenharmony_ci			*val = (data->model & R2MS_MASK) ? 1 : 2;
1748c2ecf20Sopenharmony_ci		return 0;
1758c2ecf20Sopenharmony_ci	case hwmon_temp_fault:
1768c2ecf20Sopenharmony_ci		if (channel == 1)
1778c2ecf20Sopenharmony_ci			*val = !!(data->status & R1DM);
1788c2ecf20Sopenharmony_ci		else
1798c2ecf20Sopenharmony_ci			*val = !!(data->status & R2DM);
1808c2ecf20Sopenharmony_ci		return 0;
1818c2ecf20Sopenharmony_ci	default:
1828c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
1838c2ecf20Sopenharmony_ci	}
1848c2ecf20Sopenharmony_ci}
1858c2ecf20Sopenharmony_ci
1868c2ecf20Sopenharmony_cistatic int lm95241_read(struct device *dev, enum hwmon_sensor_types type,
1878c2ecf20Sopenharmony_ci			u32 attr, int channel, long *val)
1888c2ecf20Sopenharmony_ci{
1898c2ecf20Sopenharmony_ci	switch (type) {
1908c2ecf20Sopenharmony_ci	case hwmon_chip:
1918c2ecf20Sopenharmony_ci		return lm95241_read_chip(dev, attr, channel, val);
1928c2ecf20Sopenharmony_ci	case hwmon_temp:
1938c2ecf20Sopenharmony_ci		return lm95241_read_temp(dev, attr, channel, val);
1948c2ecf20Sopenharmony_ci	default:
1958c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
1968c2ecf20Sopenharmony_ci	}
1978c2ecf20Sopenharmony_ci}
1988c2ecf20Sopenharmony_ci
1998c2ecf20Sopenharmony_cistatic int lm95241_write_chip(struct device *dev, u32 attr, int channel,
2008c2ecf20Sopenharmony_ci			      long val)
2018c2ecf20Sopenharmony_ci{
2028c2ecf20Sopenharmony_ci	struct lm95241_data *data = dev_get_drvdata(dev);
2038c2ecf20Sopenharmony_ci	int convrate;
2048c2ecf20Sopenharmony_ci	u8 config;
2058c2ecf20Sopenharmony_ci	int ret;
2068c2ecf20Sopenharmony_ci
2078c2ecf20Sopenharmony_ci	mutex_lock(&data->update_lock);
2088c2ecf20Sopenharmony_ci
2098c2ecf20Sopenharmony_ci	switch (attr) {
2108c2ecf20Sopenharmony_ci	case hwmon_chip_update_interval:
2118c2ecf20Sopenharmony_ci		config = data->config & ~CFG_CRMASK;
2128c2ecf20Sopenharmony_ci		if (val < 130) {
2138c2ecf20Sopenharmony_ci			convrate = 76;
2148c2ecf20Sopenharmony_ci			config |= CFG_CR0076;
2158c2ecf20Sopenharmony_ci		} else if (val < 590) {
2168c2ecf20Sopenharmony_ci			convrate = 182;
2178c2ecf20Sopenharmony_ci			config |= CFG_CR0182;
2188c2ecf20Sopenharmony_ci		} else if (val < 1850) {
2198c2ecf20Sopenharmony_ci			convrate = 1000;
2208c2ecf20Sopenharmony_ci			config |= CFG_CR1000;
2218c2ecf20Sopenharmony_ci		} else {
2228c2ecf20Sopenharmony_ci			convrate = 2700;
2238c2ecf20Sopenharmony_ci			config |= CFG_CR2700;
2248c2ecf20Sopenharmony_ci		}
2258c2ecf20Sopenharmony_ci		data->interval = convrate;
2268c2ecf20Sopenharmony_ci		data->config = config;
2278c2ecf20Sopenharmony_ci		ret = i2c_smbus_write_byte_data(data->client,
2288c2ecf20Sopenharmony_ci						LM95241_REG_RW_CONFIG, config);
2298c2ecf20Sopenharmony_ci		break;
2308c2ecf20Sopenharmony_ci	default:
2318c2ecf20Sopenharmony_ci		ret = -EOPNOTSUPP;
2328c2ecf20Sopenharmony_ci		break;
2338c2ecf20Sopenharmony_ci	}
2348c2ecf20Sopenharmony_ci	mutex_unlock(&data->update_lock);
2358c2ecf20Sopenharmony_ci	return ret;
2368c2ecf20Sopenharmony_ci}
2378c2ecf20Sopenharmony_ci
2388c2ecf20Sopenharmony_cistatic int lm95241_write_temp(struct device *dev, u32 attr, int channel,
2398c2ecf20Sopenharmony_ci			      long val)
2408c2ecf20Sopenharmony_ci{
2418c2ecf20Sopenharmony_ci	struct lm95241_data *data = dev_get_drvdata(dev);
2428c2ecf20Sopenharmony_ci	struct i2c_client *client = data->client;
2438c2ecf20Sopenharmony_ci	int ret;
2448c2ecf20Sopenharmony_ci
2458c2ecf20Sopenharmony_ci	mutex_lock(&data->update_lock);
2468c2ecf20Sopenharmony_ci
2478c2ecf20Sopenharmony_ci	switch (attr) {
2488c2ecf20Sopenharmony_ci	case hwmon_temp_min:
2498c2ecf20Sopenharmony_ci		if (channel == 1) {
2508c2ecf20Sopenharmony_ci			if (val < 0)
2518c2ecf20Sopenharmony_ci				data->config |= R1DF_MASK;
2528c2ecf20Sopenharmony_ci			else
2538c2ecf20Sopenharmony_ci				data->config &= ~R1DF_MASK;
2548c2ecf20Sopenharmony_ci		} else {
2558c2ecf20Sopenharmony_ci			if (val < 0)
2568c2ecf20Sopenharmony_ci				data->config |= R2DF_MASK;
2578c2ecf20Sopenharmony_ci			else
2588c2ecf20Sopenharmony_ci				data->config &= ~R2DF_MASK;
2598c2ecf20Sopenharmony_ci		}
2608c2ecf20Sopenharmony_ci		data->valid = 0;
2618c2ecf20Sopenharmony_ci		ret = i2c_smbus_write_byte_data(client, LM95241_REG_RW_CONFIG,
2628c2ecf20Sopenharmony_ci						data->config);
2638c2ecf20Sopenharmony_ci		break;
2648c2ecf20Sopenharmony_ci	case hwmon_temp_max:
2658c2ecf20Sopenharmony_ci		if (channel == 1) {
2668c2ecf20Sopenharmony_ci			if (val <= 127875)
2678c2ecf20Sopenharmony_ci				data->config |= R1DF_MASK;
2688c2ecf20Sopenharmony_ci			else
2698c2ecf20Sopenharmony_ci				data->config &= ~R1DF_MASK;
2708c2ecf20Sopenharmony_ci		} else {
2718c2ecf20Sopenharmony_ci			if (val <= 127875)
2728c2ecf20Sopenharmony_ci				data->config |= R2DF_MASK;
2738c2ecf20Sopenharmony_ci			else
2748c2ecf20Sopenharmony_ci				data->config &= ~R2DF_MASK;
2758c2ecf20Sopenharmony_ci		}
2768c2ecf20Sopenharmony_ci		data->valid = 0;
2778c2ecf20Sopenharmony_ci		ret = i2c_smbus_write_byte_data(client, LM95241_REG_RW_CONFIG,
2788c2ecf20Sopenharmony_ci						data->config);
2798c2ecf20Sopenharmony_ci		break;
2808c2ecf20Sopenharmony_ci	case hwmon_temp_type:
2818c2ecf20Sopenharmony_ci		if (val != 1 && val != 2) {
2828c2ecf20Sopenharmony_ci			ret = -EINVAL;
2838c2ecf20Sopenharmony_ci			break;
2848c2ecf20Sopenharmony_ci		}
2858c2ecf20Sopenharmony_ci		if (channel == 1) {
2868c2ecf20Sopenharmony_ci			data->trutherm &= ~(TT_MASK << TT1_SHIFT);
2878c2ecf20Sopenharmony_ci			if (val == 1) {
2888c2ecf20Sopenharmony_ci				data->model |= R1MS_MASK;
2898c2ecf20Sopenharmony_ci				data->trutherm |= (TT_ON << TT1_SHIFT);
2908c2ecf20Sopenharmony_ci			} else {
2918c2ecf20Sopenharmony_ci				data->model &= ~R1MS_MASK;
2928c2ecf20Sopenharmony_ci				data->trutherm |= (TT_OFF << TT1_SHIFT);
2938c2ecf20Sopenharmony_ci			}
2948c2ecf20Sopenharmony_ci		} else {
2958c2ecf20Sopenharmony_ci			data->trutherm &= ~(TT_MASK << TT2_SHIFT);
2968c2ecf20Sopenharmony_ci			if (val == 1) {
2978c2ecf20Sopenharmony_ci				data->model |= R2MS_MASK;
2988c2ecf20Sopenharmony_ci				data->trutherm |= (TT_ON << TT2_SHIFT);
2998c2ecf20Sopenharmony_ci			} else {
3008c2ecf20Sopenharmony_ci				data->model &= ~R2MS_MASK;
3018c2ecf20Sopenharmony_ci				data->trutherm |= (TT_OFF << TT2_SHIFT);
3028c2ecf20Sopenharmony_ci			}
3038c2ecf20Sopenharmony_ci		}
3048c2ecf20Sopenharmony_ci		ret = i2c_smbus_write_byte_data(client,
3058c2ecf20Sopenharmony_ci						LM95241_REG_RW_REMOTE_MODEL,
3068c2ecf20Sopenharmony_ci						data->model);
3078c2ecf20Sopenharmony_ci		if (ret < 0)
3088c2ecf20Sopenharmony_ci			break;
3098c2ecf20Sopenharmony_ci		ret = i2c_smbus_write_byte_data(client, LM95241_REG_RW_TRUTHERM,
3108c2ecf20Sopenharmony_ci						data->trutherm);
3118c2ecf20Sopenharmony_ci		break;
3128c2ecf20Sopenharmony_ci	default:
3138c2ecf20Sopenharmony_ci		ret = -EOPNOTSUPP;
3148c2ecf20Sopenharmony_ci		break;
3158c2ecf20Sopenharmony_ci	}
3168c2ecf20Sopenharmony_ci
3178c2ecf20Sopenharmony_ci	mutex_unlock(&data->update_lock);
3188c2ecf20Sopenharmony_ci
3198c2ecf20Sopenharmony_ci	return ret;
3208c2ecf20Sopenharmony_ci}
3218c2ecf20Sopenharmony_ci
3228c2ecf20Sopenharmony_cistatic int lm95241_write(struct device *dev, enum hwmon_sensor_types type,
3238c2ecf20Sopenharmony_ci			 u32 attr, int channel, long val)
3248c2ecf20Sopenharmony_ci{
3258c2ecf20Sopenharmony_ci	switch (type) {
3268c2ecf20Sopenharmony_ci	case hwmon_chip:
3278c2ecf20Sopenharmony_ci		return lm95241_write_chip(dev, attr, channel, val);
3288c2ecf20Sopenharmony_ci	case hwmon_temp:
3298c2ecf20Sopenharmony_ci		return lm95241_write_temp(dev, attr, channel, val);
3308c2ecf20Sopenharmony_ci	default:
3318c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
3328c2ecf20Sopenharmony_ci	}
3338c2ecf20Sopenharmony_ci}
3348c2ecf20Sopenharmony_ci
3358c2ecf20Sopenharmony_cistatic umode_t lm95241_is_visible(const void *data,
3368c2ecf20Sopenharmony_ci				  enum hwmon_sensor_types type,
3378c2ecf20Sopenharmony_ci				  u32 attr, int channel)
3388c2ecf20Sopenharmony_ci{
3398c2ecf20Sopenharmony_ci	switch (type) {
3408c2ecf20Sopenharmony_ci	case hwmon_chip:
3418c2ecf20Sopenharmony_ci		switch (attr) {
3428c2ecf20Sopenharmony_ci		case hwmon_chip_update_interval:
3438c2ecf20Sopenharmony_ci			return 0644;
3448c2ecf20Sopenharmony_ci		}
3458c2ecf20Sopenharmony_ci		break;
3468c2ecf20Sopenharmony_ci	case hwmon_temp:
3478c2ecf20Sopenharmony_ci		switch (attr) {
3488c2ecf20Sopenharmony_ci		case hwmon_temp_input:
3498c2ecf20Sopenharmony_ci			return 0444;
3508c2ecf20Sopenharmony_ci		case hwmon_temp_fault:
3518c2ecf20Sopenharmony_ci			return 0444;
3528c2ecf20Sopenharmony_ci		case hwmon_temp_min:
3538c2ecf20Sopenharmony_ci		case hwmon_temp_max:
3548c2ecf20Sopenharmony_ci		case hwmon_temp_type:
3558c2ecf20Sopenharmony_ci			return 0644;
3568c2ecf20Sopenharmony_ci		}
3578c2ecf20Sopenharmony_ci		break;
3588c2ecf20Sopenharmony_ci	default:
3598c2ecf20Sopenharmony_ci		break;
3608c2ecf20Sopenharmony_ci	}
3618c2ecf20Sopenharmony_ci	return 0;
3628c2ecf20Sopenharmony_ci}
3638c2ecf20Sopenharmony_ci
3648c2ecf20Sopenharmony_ci/* Return 0 if detection is successful, -ENODEV otherwise */
3658c2ecf20Sopenharmony_cistatic int lm95241_detect(struct i2c_client *new_client,
3668c2ecf20Sopenharmony_ci			  struct i2c_board_info *info)
3678c2ecf20Sopenharmony_ci{
3688c2ecf20Sopenharmony_ci	struct i2c_adapter *adapter = new_client->adapter;
3698c2ecf20Sopenharmony_ci	const char *name;
3708c2ecf20Sopenharmony_ci	int mfg_id, chip_id;
3718c2ecf20Sopenharmony_ci
3728c2ecf20Sopenharmony_ci	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
3738c2ecf20Sopenharmony_ci		return -ENODEV;
3748c2ecf20Sopenharmony_ci
3758c2ecf20Sopenharmony_ci	mfg_id = i2c_smbus_read_byte_data(new_client, LM95241_REG_R_MAN_ID);
3768c2ecf20Sopenharmony_ci	if (mfg_id != NATSEMI_MAN_ID)
3778c2ecf20Sopenharmony_ci		return -ENODEV;
3788c2ecf20Sopenharmony_ci
3798c2ecf20Sopenharmony_ci	chip_id = i2c_smbus_read_byte_data(new_client, LM95241_REG_R_CHIP_ID);
3808c2ecf20Sopenharmony_ci	switch (chip_id) {
3818c2ecf20Sopenharmony_ci	case LM95231_CHIP_ID:
3828c2ecf20Sopenharmony_ci		name = "lm95231";
3838c2ecf20Sopenharmony_ci		break;
3848c2ecf20Sopenharmony_ci	case LM95241_CHIP_ID:
3858c2ecf20Sopenharmony_ci		name = "lm95241";
3868c2ecf20Sopenharmony_ci		break;
3878c2ecf20Sopenharmony_ci	default:
3888c2ecf20Sopenharmony_ci		return -ENODEV;
3898c2ecf20Sopenharmony_ci	}
3908c2ecf20Sopenharmony_ci
3918c2ecf20Sopenharmony_ci	/* Fill the i2c board info */
3928c2ecf20Sopenharmony_ci	strlcpy(info->type, name, I2C_NAME_SIZE);
3938c2ecf20Sopenharmony_ci	return 0;
3948c2ecf20Sopenharmony_ci}
3958c2ecf20Sopenharmony_ci
3968c2ecf20Sopenharmony_cistatic void lm95241_init_client(struct i2c_client *client,
3978c2ecf20Sopenharmony_ci				struct lm95241_data *data)
3988c2ecf20Sopenharmony_ci{
3998c2ecf20Sopenharmony_ci	data->interval = 1000;
4008c2ecf20Sopenharmony_ci	data->config = CFG_CR1000;
4018c2ecf20Sopenharmony_ci	data->trutherm = (TT_OFF << TT1_SHIFT) | (TT_OFF << TT2_SHIFT);
4028c2ecf20Sopenharmony_ci
4038c2ecf20Sopenharmony_ci	i2c_smbus_write_byte_data(client, LM95241_REG_RW_CONFIG, data->config);
4048c2ecf20Sopenharmony_ci	i2c_smbus_write_byte_data(client, LM95241_REG_RW_REM_FILTER,
4058c2ecf20Sopenharmony_ci				  R1FE_MASK | R2FE_MASK);
4068c2ecf20Sopenharmony_ci	i2c_smbus_write_byte_data(client, LM95241_REG_RW_TRUTHERM,
4078c2ecf20Sopenharmony_ci				  data->trutherm);
4088c2ecf20Sopenharmony_ci	i2c_smbus_write_byte_data(client, LM95241_REG_RW_REMOTE_MODEL,
4098c2ecf20Sopenharmony_ci				  data->model);
4108c2ecf20Sopenharmony_ci}
4118c2ecf20Sopenharmony_ci
4128c2ecf20Sopenharmony_cistatic const struct hwmon_channel_info *lm95241_info[] = {
4138c2ecf20Sopenharmony_ci	HWMON_CHANNEL_INFO(chip,
4148c2ecf20Sopenharmony_ci			   HWMON_C_UPDATE_INTERVAL),
4158c2ecf20Sopenharmony_ci	HWMON_CHANNEL_INFO(temp,
4168c2ecf20Sopenharmony_ci			   HWMON_T_INPUT,
4178c2ecf20Sopenharmony_ci			   HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_MIN |
4188c2ecf20Sopenharmony_ci			   HWMON_T_TYPE | HWMON_T_FAULT,
4198c2ecf20Sopenharmony_ci			   HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_MIN |
4208c2ecf20Sopenharmony_ci			   HWMON_T_TYPE | HWMON_T_FAULT),
4218c2ecf20Sopenharmony_ci	NULL
4228c2ecf20Sopenharmony_ci};
4238c2ecf20Sopenharmony_ci
4248c2ecf20Sopenharmony_cistatic const struct hwmon_ops lm95241_hwmon_ops = {
4258c2ecf20Sopenharmony_ci	.is_visible = lm95241_is_visible,
4268c2ecf20Sopenharmony_ci	.read = lm95241_read,
4278c2ecf20Sopenharmony_ci	.write = lm95241_write,
4288c2ecf20Sopenharmony_ci};
4298c2ecf20Sopenharmony_ci
4308c2ecf20Sopenharmony_cistatic const struct hwmon_chip_info lm95241_chip_info = {
4318c2ecf20Sopenharmony_ci	.ops = &lm95241_hwmon_ops,
4328c2ecf20Sopenharmony_ci	.info = lm95241_info,
4338c2ecf20Sopenharmony_ci};
4348c2ecf20Sopenharmony_ci
4358c2ecf20Sopenharmony_cistatic int lm95241_probe(struct i2c_client *client)
4368c2ecf20Sopenharmony_ci{
4378c2ecf20Sopenharmony_ci	struct device *dev = &client->dev;
4388c2ecf20Sopenharmony_ci	struct lm95241_data *data;
4398c2ecf20Sopenharmony_ci	struct device *hwmon_dev;
4408c2ecf20Sopenharmony_ci
4418c2ecf20Sopenharmony_ci	data = devm_kzalloc(dev, sizeof(struct lm95241_data), GFP_KERNEL);
4428c2ecf20Sopenharmony_ci	if (!data)
4438c2ecf20Sopenharmony_ci		return -ENOMEM;
4448c2ecf20Sopenharmony_ci
4458c2ecf20Sopenharmony_ci	data->client = client;
4468c2ecf20Sopenharmony_ci	mutex_init(&data->update_lock);
4478c2ecf20Sopenharmony_ci
4488c2ecf20Sopenharmony_ci	/* Initialize the LM95241 chip */
4498c2ecf20Sopenharmony_ci	lm95241_init_client(client, data);
4508c2ecf20Sopenharmony_ci
4518c2ecf20Sopenharmony_ci	hwmon_dev = devm_hwmon_device_register_with_info(dev, client->name,
4528c2ecf20Sopenharmony_ci							   data,
4538c2ecf20Sopenharmony_ci							   &lm95241_chip_info,
4548c2ecf20Sopenharmony_ci							   NULL);
4558c2ecf20Sopenharmony_ci	return PTR_ERR_OR_ZERO(hwmon_dev);
4568c2ecf20Sopenharmony_ci}
4578c2ecf20Sopenharmony_ci
4588c2ecf20Sopenharmony_ci/* Driver data (common to all clients) */
4598c2ecf20Sopenharmony_cistatic const struct i2c_device_id lm95241_id[] = {
4608c2ecf20Sopenharmony_ci	{ "lm95231", 0 },
4618c2ecf20Sopenharmony_ci	{ "lm95241", 0 },
4628c2ecf20Sopenharmony_ci	{ }
4638c2ecf20Sopenharmony_ci};
4648c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(i2c, lm95241_id);
4658c2ecf20Sopenharmony_ci
4668c2ecf20Sopenharmony_cistatic struct i2c_driver lm95241_driver = {
4678c2ecf20Sopenharmony_ci	.class		= I2C_CLASS_HWMON,
4688c2ecf20Sopenharmony_ci	.driver = {
4698c2ecf20Sopenharmony_ci		.name	= DEVNAME,
4708c2ecf20Sopenharmony_ci	},
4718c2ecf20Sopenharmony_ci	.probe_new	= lm95241_probe,
4728c2ecf20Sopenharmony_ci	.id_table	= lm95241_id,
4738c2ecf20Sopenharmony_ci	.detect		= lm95241_detect,
4748c2ecf20Sopenharmony_ci	.address_list	= normal_i2c,
4758c2ecf20Sopenharmony_ci};
4768c2ecf20Sopenharmony_ci
4778c2ecf20Sopenharmony_cimodule_i2c_driver(lm95241_driver);
4788c2ecf20Sopenharmony_ci
4798c2ecf20Sopenharmony_ciMODULE_AUTHOR("Davide Rizzo <elpa.rizzo@gmail.com>");
4808c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("LM95231/LM95241 sensor driver");
4818c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL");
482