Skip to content

Commit 761c177

Browse files
maciejsszmigierogroeck
authored andcommitted
hwmon: add driver for Microchip TC74
Add hwmon driver for the Microchip TC74. The TC74 is a single-input 8-bit I2C temperature sensor, with +-2 degrees centigrade accuracy. Signed-off-by: Maciej Szmigiero <[email protected]> Signed-off-by: Guenter Roeck <[email protected]>
1 parent f6725ae commit 761c177

File tree

4 files changed

+208
-0
lines changed

4 files changed

+208
-0
lines changed

Documentation/hwmon/tc74

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
Kernel driver tc74
2+
====================
3+
4+
Supported chips:
5+
* Microchip TC74
6+
Prefix: 'tc74'
7+
Datasheet: Publicly available at Microchip website.
8+
9+
Description
10+
-----------
11+
12+
Driver supports the above part.
13+
14+
The tc74 has an 8-bit sensor, with 1 degree centigrade resolution
15+
and +- 2 degrees centigrade accuracy.
16+
17+
Notes
18+
-----
19+
20+
Currently entering low power standby mode is not supported.

drivers/hwmon/Kconfig

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1452,6 +1452,16 @@ config SENSORS_INA2XX
14521452
This driver can also be built as a module. If so, the module
14531453
will be called ina2xx.
14541454

1455+
config SENSORS_TC74
1456+
tristate "Microchip TC74"
1457+
depends on I2C
1458+
help
1459+
If you say yes here you get support for Microchip TC74 single
1460+
input temperature sensor chips.
1461+
1462+
This driver can also be built as a module. If so, the module
1463+
will be called tc74.
1464+
14551465
config SENSORS_THMC50
14561466
tristate "Texas Instruments THMC50 / Analog Devices ADM1022"
14571467
depends on I2C

drivers/hwmon/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,7 @@ obj-$(CONFIG_SENSORS_SMSC47B397)+= smsc47b397.o
140140
obj-$(CONFIG_SENSORS_SMSC47M1) += smsc47m1.o
141141
obj-$(CONFIG_SENSORS_SMSC47M192)+= smsc47m192.o
142142
obj-$(CONFIG_SENSORS_AMC6821) += amc6821.o
143+
obj-$(CONFIG_SENSORS_TC74) += tc74.o
143144
obj-$(CONFIG_SENSORS_THMC50) += thmc50.o
144145
obj-$(CONFIG_SENSORS_TMP102) += tmp102.o
145146
obj-$(CONFIG_SENSORS_TMP103) += tmp103.o

drivers/hwmon/tc74.c

Lines changed: 177 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,177 @@
1+
/*
2+
* An hwmon driver for the Microchip TC74
3+
*
4+
* Copyright 2015 Maciej Szmigiero <[email protected]>
5+
*
6+
* Based on ad7414.c:
7+
* Copyright 2006 Stefan Roese, DENX Software Engineering
8+
* Copyright 2008 Sean MacLennan, PIKA Technologies
9+
* Copyright 2008 Frank Edelhaeuser, Spansion Inc.
10+
*
11+
* This program is free software; you can redistribute it and/or modify
12+
* it under the terms of the GNU General Public License as published by
13+
* the Free Software Foundation; either version 2 of the License, or
14+
* (at your option) any later version.
15+
*/
16+
17+
#include <linux/bitops.h>
18+
#include <linux/err.h>
19+
#include <linux/hwmon.h>
20+
#include <linux/hwmon-sysfs.h>
21+
#include <linux/i2c.h>
22+
#include <linux/jiffies.h>
23+
#include <linux/module.h>
24+
#include <linux/mutex.h>
25+
#include <linux/slab.h>
26+
#include <linux/sysfs.h>
27+
28+
/* TC74 registers */
29+
#define TC74_REG_TEMP 0x00
30+
#define TC74_REG_CONFIG 0x01
31+
32+
struct tc74_data {
33+
struct i2c_client *client;
34+
struct mutex lock; /* atomic read data updates */
35+
bool valid; /* validity of fields below */
36+
unsigned long next_update; /* In jiffies */
37+
s8 temp_input; /* Temp value in dC */
38+
};
39+
40+
static int tc74_update_device(struct device *dev)
41+
{
42+
struct tc74_data *data = dev_get_drvdata(dev);
43+
struct i2c_client *client = data->client;
44+
int ret;
45+
46+
ret = mutex_lock_interruptible(&data->lock);
47+
if (ret)
48+
return ret;
49+
50+
if (time_after(jiffies, data->next_update) || !data->valid) {
51+
s32 value;
52+
53+
value = i2c_smbus_read_byte_data(client, TC74_REG_CONFIG);
54+
if (value < 0) {
55+
dev_dbg(&client->dev, "TC74_REG_CONFIG read err %d\n",
56+
(int)value);
57+
58+
ret = value;
59+
goto ret_unlock;
60+
}
61+
62+
if (!(value & BIT(6))) {
63+
/* not ready yet */
64+
65+
ret = -EAGAIN;
66+
goto ret_unlock;
67+
}
68+
69+
value = i2c_smbus_read_byte_data(client, TC74_REG_TEMP);
70+
if (value < 0) {
71+
dev_dbg(&client->dev, "TC74_REG_TEMP read err %d\n",
72+
(int)value);
73+
74+
ret = value;
75+
goto ret_unlock;
76+
}
77+
78+
data->temp_input = value;
79+
data->next_update = jiffies + HZ / 4;
80+
data->valid = true;
81+
}
82+
83+
ret_unlock:
84+
mutex_unlock(&data->lock);
85+
86+
return ret;
87+
}
88+
89+
static ssize_t show_temp_input(struct device *dev,
90+
struct device_attribute *attr, char *buf)
91+
{
92+
struct tc74_data *data = dev_get_drvdata(dev);
93+
int ret;
94+
95+
ret = tc74_update_device(dev);
96+
if (ret)
97+
return ret;
98+
99+
return sprintf(buf, "%d\n", data->temp_input * 1000);
100+
}
101+
static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_temp_input, NULL, 0);
102+
103+
static struct attribute *tc74_attrs[] = {
104+
&sensor_dev_attr_temp1_input.dev_attr.attr,
105+
NULL
106+
};
107+
108+
ATTRIBUTE_GROUPS(tc74);
109+
110+
static int tc74_probe(struct i2c_client *client,
111+
const struct i2c_device_id *dev_id)
112+
{
113+
struct device *dev = &client->dev;
114+
struct tc74_data *data;
115+
struct device *hwmon_dev;
116+
s32 conf;
117+
118+
if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
119+
return -EOPNOTSUPP;
120+
121+
data = devm_kzalloc(dev, sizeof(struct tc74_data), GFP_KERNEL);
122+
if (!data)
123+
return -ENOMEM;
124+
125+
data->client = client;
126+
mutex_init(&data->lock);
127+
128+
/* Make sure the chip is powered up. */
129+
conf = i2c_smbus_read_byte_data(client, TC74_REG_CONFIG);
130+
if (conf < 0) {
131+
dev_err(dev, "unable to read config register\n");
132+
133+
return conf;
134+
}
135+
136+
if (conf & 0x3f) {
137+
dev_err(dev, "invalid config register value\n");
138+
139+
return -ENODEV;
140+
}
141+
142+
if (conf & BIT(7)) {
143+
s32 ret;
144+
145+
conf &= ~BIT(7);
146+
147+
ret = i2c_smbus_write_byte_data(client, TC74_REG_CONFIG, conf);
148+
if (ret)
149+
dev_warn(dev, "unable to disable STANDBY\n");
150+
}
151+
152+
hwmon_dev = devm_hwmon_device_register_with_groups(dev,
153+
client->name,
154+
data, tc74_groups);
155+
return PTR_ERR_OR_ZERO(hwmon_dev);
156+
}
157+
158+
static const struct i2c_device_id tc74_id[] = {
159+
{ "tc74", 0 },
160+
{}
161+
};
162+
MODULE_DEVICE_TABLE(i2c, tc74_id);
163+
164+
static struct i2c_driver tc74_driver = {
165+
.driver = {
166+
.name = "tc74",
167+
},
168+
.probe = tc74_probe,
169+
.id_table = tc74_id,
170+
};
171+
172+
module_i2c_driver(tc74_driver);
173+
174+
MODULE_AUTHOR("Maciej Szmigiero <[email protected]>");
175+
176+
MODULE_DESCRIPTION("TC74 driver");
177+
MODULE_LICENSE("GPL");

0 commit comments

Comments
 (0)