cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

w83l785ts.c (7420B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/*
      3 * w83l785ts.c - Part of lm_sensors, Linux kernel modules for hardware
      4 *               monitoring
      5 * Copyright (C) 2003-2009  Jean Delvare <jdelvare@suse.de>
      6 *
      7 * Inspired from the lm83 driver. The W83L785TS-S is a sensor chip made
      8 * by Winbond. It reports a single external temperature with a 1 deg
      9 * resolution and a 3 deg accuracy. Datasheet can be obtained from
     10 * Winbond's website at:
     11 *   http://www.winbond-usa.com/products/winbond_products/pdfs/PCIC/W83L785TS-S.pdf
     12 *
     13 * Ported to Linux 2.6 by Wolfgang Ziegler <nuppla@gmx.at> and Jean Delvare
     14 * <jdelvare@suse.de>.
     15 *
     16 * Thanks to James Bolt <james@evilpenguin.com> for benchmarking the read
     17 * error handling mechanism.
     18 */
     19
     20#include <linux/module.h>
     21#include <linux/delay.h>
     22#include <linux/init.h>
     23#include <linux/slab.h>
     24#include <linux/jiffies.h>
     25#include <linux/i2c.h>
     26#include <linux/hwmon.h>
     27#include <linux/hwmon-sysfs.h>
     28#include <linux/err.h>
     29#include <linux/mutex.h>
     30
     31/* How many retries on register read error */
     32#define MAX_RETRIES	5
     33
     34/*
     35 * Address to scan
     36 * Address is fully defined internally and cannot be changed.
     37 */
     38
     39static const unsigned short normal_i2c[] = { 0x2e, I2C_CLIENT_END };
     40
     41/*
     42 * The W83L785TS-S registers
     43 * Manufacturer ID is 0x5CA3 for Winbond.
     44 */
     45
     46#define W83L785TS_REG_MAN_ID1		0x4D
     47#define W83L785TS_REG_MAN_ID2		0x4C
     48#define W83L785TS_REG_CHIP_ID		0x4E
     49#define W83L785TS_REG_CONFIG		0x40
     50#define W83L785TS_REG_TYPE		0x52
     51#define W83L785TS_REG_TEMP		0x27
     52#define W83L785TS_REG_TEMP_OVER		0x53 /* not sure about this one */
     53
     54/*
     55 * Conversions
     56 * The W83L785TS-S uses signed 8-bit values.
     57 */
     58
     59#define TEMP_FROM_REG(val)	((val) * 1000)
     60
     61/*
     62 * Functions declaration
     63 */
     64
     65static int w83l785ts_probe(struct i2c_client *client);
     66static int w83l785ts_detect(struct i2c_client *client,
     67			    struct i2c_board_info *info);
     68static int w83l785ts_remove(struct i2c_client *client);
     69static u8 w83l785ts_read_value(struct i2c_client *client, u8 reg, u8 defval);
     70static struct w83l785ts_data *w83l785ts_update_device(struct device *dev);
     71
     72/*
     73 * Driver data (common to all clients)
     74 */
     75
     76static const struct i2c_device_id w83l785ts_id[] = {
     77	{ "w83l785ts", 0 },
     78	{ }
     79};
     80MODULE_DEVICE_TABLE(i2c, w83l785ts_id);
     81
     82static struct i2c_driver w83l785ts_driver = {
     83	.class		= I2C_CLASS_HWMON,
     84	.driver = {
     85		.name	= "w83l785ts",
     86	},
     87	.probe_new	= w83l785ts_probe,
     88	.remove		= w83l785ts_remove,
     89	.id_table	= w83l785ts_id,
     90	.detect		= w83l785ts_detect,
     91	.address_list	= normal_i2c,
     92};
     93
     94/*
     95 * Client data (each client gets its own)
     96 */
     97
     98struct w83l785ts_data {
     99	struct device *hwmon_dev;
    100	struct mutex update_lock;
    101	bool valid; /* false until following fields are valid */
    102	unsigned long last_updated; /* in jiffies */
    103
    104	/* registers values */
    105	s8 temp[2]; /* 0: input, 1: critical limit */
    106};
    107
    108/*
    109 * Sysfs stuff
    110 */
    111
    112static ssize_t show_temp(struct device *dev, struct device_attribute *devattr,
    113	char *buf)
    114{
    115	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
    116	struct w83l785ts_data *data = w83l785ts_update_device(dev);
    117	return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp[attr->index]));
    118}
    119
    120static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_temp, NULL, 0);
    121static SENSOR_DEVICE_ATTR(temp1_max, S_IRUGO, show_temp, NULL, 1);
    122
    123/*
    124 * Real code
    125 */
    126
    127/* Return 0 if detection is successful, -ENODEV otherwise */
    128static int w83l785ts_detect(struct i2c_client *client,
    129			    struct i2c_board_info *info)
    130{
    131	struct i2c_adapter *adapter = client->adapter;
    132	u16 man_id;
    133	u8 chip_id;
    134
    135	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
    136		return -ENODEV;
    137
    138	/* detection */
    139	if ((w83l785ts_read_value(client, W83L785TS_REG_CONFIG, 0) & 0x80)
    140	 || (w83l785ts_read_value(client, W83L785TS_REG_TYPE, 0) & 0xFC)) {
    141		dev_dbg(&adapter->dev,
    142			"W83L785TS-S detection failed at 0x%02x\n",
    143			client->addr);
    144		return -ENODEV;
    145	}
    146
    147	/* Identification */
    148	man_id = (w83l785ts_read_value(client, W83L785TS_REG_MAN_ID1, 0) << 8)
    149	       + w83l785ts_read_value(client, W83L785TS_REG_MAN_ID2, 0);
    150	chip_id = w83l785ts_read_value(client, W83L785TS_REG_CHIP_ID, 0);
    151
    152	if (man_id != 0x5CA3		/* Winbond */
    153	 || chip_id != 0x70) {		/* W83L785TS-S */
    154		dev_dbg(&adapter->dev,
    155			"Unsupported chip (man_id=0x%04X, chip_id=0x%02X)\n",
    156			man_id, chip_id);
    157		return -ENODEV;
    158	}
    159
    160	strlcpy(info->type, "w83l785ts", I2C_NAME_SIZE);
    161
    162	return 0;
    163}
    164
    165static int w83l785ts_probe(struct i2c_client *client)
    166{
    167	struct w83l785ts_data *data;
    168	struct device *dev = &client->dev;
    169	int err;
    170
    171	data = devm_kzalloc(dev, sizeof(struct w83l785ts_data), GFP_KERNEL);
    172	if (!data)
    173		return -ENOMEM;
    174
    175	i2c_set_clientdata(client, data);
    176	mutex_init(&data->update_lock);
    177
    178	/*
    179	 * Initialize the W83L785TS chip
    180	 * Nothing yet, assume it is already started.
    181	 */
    182
    183	err = device_create_file(dev, &sensor_dev_attr_temp1_input.dev_attr);
    184	if (err)
    185		return err;
    186
    187	err = device_create_file(dev, &sensor_dev_attr_temp1_max.dev_attr);
    188	if (err)
    189		goto exit_remove;
    190
    191	/* Register sysfs hooks */
    192	data->hwmon_dev = hwmon_device_register(dev);
    193	if (IS_ERR(data->hwmon_dev)) {
    194		err = PTR_ERR(data->hwmon_dev);
    195		goto exit_remove;
    196	}
    197
    198	return 0;
    199
    200exit_remove:
    201	device_remove_file(dev, &sensor_dev_attr_temp1_input.dev_attr);
    202	device_remove_file(dev, &sensor_dev_attr_temp1_max.dev_attr);
    203	return err;
    204}
    205
    206static int w83l785ts_remove(struct i2c_client *client)
    207{
    208	struct w83l785ts_data *data = i2c_get_clientdata(client);
    209
    210	hwmon_device_unregister(data->hwmon_dev);
    211	device_remove_file(&client->dev,
    212			   &sensor_dev_attr_temp1_input.dev_attr);
    213	device_remove_file(&client->dev,
    214			   &sensor_dev_attr_temp1_max.dev_attr);
    215
    216	return 0;
    217}
    218
    219static u8 w83l785ts_read_value(struct i2c_client *client, u8 reg, u8 defval)
    220{
    221	int value, i;
    222	struct device *dev;
    223	const char *prefix;
    224
    225	/*
    226	 * We might be called during detection, at which point the client
    227	 * isn't yet fully initialized, so we can't use dev_dbg on it
    228	 */
    229	if (i2c_get_clientdata(client)) {
    230		dev = &client->dev;
    231		prefix = "";
    232	} else {
    233		dev = &client->adapter->dev;
    234		prefix = "w83l785ts: ";
    235	}
    236
    237	/*
    238	 * Frequent read errors have been reported on Asus boards, so we
    239	 * retry on read errors. If it still fails (unlikely), return the
    240	 * default value requested by the caller.
    241	 */
    242	for (i = 1; i <= MAX_RETRIES; i++) {
    243		value = i2c_smbus_read_byte_data(client, reg);
    244		if (value >= 0) {
    245			dev_dbg(dev, "%sRead 0x%02x from register 0x%02x.\n",
    246				prefix, value, reg);
    247			return value;
    248		}
    249		dev_dbg(dev, "%sRead failed, will retry in %d.\n", prefix, i);
    250		msleep(i);
    251	}
    252
    253	dev_err(dev, "%sCouldn't read value from register 0x%02x.\n", prefix,
    254		reg);
    255	return defval;
    256}
    257
    258static struct w83l785ts_data *w83l785ts_update_device(struct device *dev)
    259{
    260	struct i2c_client *client = to_i2c_client(dev);
    261	struct w83l785ts_data *data = i2c_get_clientdata(client);
    262
    263	mutex_lock(&data->update_lock);
    264
    265	if (!data->valid || time_after(jiffies, data->last_updated + HZ * 2)) {
    266		dev_dbg(&client->dev, "Updating w83l785ts data.\n");
    267		data->temp[0] = w83l785ts_read_value(client,
    268				W83L785TS_REG_TEMP, data->temp[0]);
    269		data->temp[1] = w83l785ts_read_value(client,
    270				W83L785TS_REG_TEMP_OVER, data->temp[1]);
    271
    272		data->last_updated = jiffies;
    273		data->valid = true;
    274	}
    275
    276	mutex_unlock(&data->update_lock);
    277
    278	return data;
    279}
    280
    281module_i2c_driver(w83l785ts_driver);
    282
    283MODULE_AUTHOR("Jean Delvare <jdelvare@suse.de>");
    284MODULE_DESCRIPTION("W83L785TS-S driver");
    285MODULE_LICENSE("GPL");