Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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 <mail@maciej.szmigiero.name>
Signed-off-by: Guenter Roeck <linux@roeck-us.net>

authored by

Maciej S. Szmigiero and committed by
Guenter Roeck
761c1770 f6725ae2

+208
+20
Documentation/hwmon/tc74
··· 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.
+10
drivers/hwmon/Kconfig
··· 1452 1452 This driver can also be built as a module. If so, the module 1453 1453 will be called ina2xx. 1454 1454 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 + 1455 1465 config SENSORS_THMC50 1456 1466 tristate "Texas Instruments THMC50 / Analog Devices ADM1022" 1457 1467 depends on I2C
+1
drivers/hwmon/Makefile
··· 140 140 obj-$(CONFIG_SENSORS_SMSC47M1) += smsc47m1.o 141 141 obj-$(CONFIG_SENSORS_SMSC47M192)+= smsc47m192.o 142 142 obj-$(CONFIG_SENSORS_AMC6821) += amc6821.o 143 + obj-$(CONFIG_SENSORS_TC74) += tc74.o 143 144 obj-$(CONFIG_SENSORS_THMC50) += thmc50.o 144 145 obj-$(CONFIG_SENSORS_TMP102) += tmp102.o 145 146 obj-$(CONFIG_SENSORS_TMP103) += tmp103.o
+177
drivers/hwmon/tc74.c
··· 1 + /* 2 + * An hwmon driver for the Microchip TC74 3 + * 4 + * Copyright 2015 Maciej Szmigiero <mail@maciej.szmigiero.name> 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 <mail@maciej.szmigiero.name>"); 175 + 176 + MODULE_DESCRIPTION("TC74 driver"); 177 + MODULE_LICENSE("GPL");