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

lm77.c (10180B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/*
      3 * lm77.c - Part of lm_sensors, Linux kernel modules for hardware
      4 *	    monitoring
      5 *
      6 * Copyright (c) 2004  Andras BALI <drewie@freemail.hu>
      7 *
      8 * Heavily based on lm75.c by Frodo Looijaard <frodol@dds.nl>.  The LM77
      9 * is a temperature sensor and thermal window comparator with 0.5 deg
     10 * resolution made by National Semiconductor.  Complete datasheet can be
     11 * obtained at their site:
     12 *	http://www.national.com/pf/LM/LM77.html
     13 */
     14
     15#include <linux/module.h>
     16#include <linux/init.h>
     17#include <linux/slab.h>
     18#include <linux/jiffies.h>
     19#include <linux/i2c.h>
     20#include <linux/hwmon.h>
     21#include <linux/hwmon-sysfs.h>
     22#include <linux/err.h>
     23#include <linux/mutex.h>
     24
     25/* Addresses to scan */
     26static const unsigned short normal_i2c[] = { 0x48, 0x49, 0x4a, 0x4b,
     27						I2C_CLIENT_END };
     28
     29/* The LM77 registers */
     30#define LM77_REG_TEMP		0x00
     31#define LM77_REG_CONF		0x01
     32#define LM77_REG_TEMP_HYST	0x02
     33#define LM77_REG_TEMP_CRIT	0x03
     34#define LM77_REG_TEMP_MIN	0x04
     35#define LM77_REG_TEMP_MAX	0x05
     36
     37enum temp_index {
     38	t_input = 0,
     39	t_crit,
     40	t_min,
     41	t_max,
     42	t_hyst,
     43	t_num_temp
     44};
     45
     46static const u8 temp_regs[t_num_temp] = {
     47	[t_input] = LM77_REG_TEMP,
     48	[t_min] = LM77_REG_TEMP_MIN,
     49	[t_max] = LM77_REG_TEMP_MAX,
     50	[t_crit] = LM77_REG_TEMP_CRIT,
     51	[t_hyst] = LM77_REG_TEMP_HYST,
     52};
     53
     54/* Each client has this additional data */
     55struct lm77_data {
     56	struct i2c_client	*client;
     57	struct mutex		update_lock;
     58	bool			valid;
     59	unsigned long		last_updated;	/* In jiffies */
     60	int			temp[t_num_temp]; /* index using temp_index */
     61	u8			alarms;
     62};
     63
     64/* straight from the datasheet */
     65#define LM77_TEMP_MIN (-55000)
     66#define LM77_TEMP_MAX 125000
     67
     68/*
     69 * In the temperature registers, the low 3 bits are not part of the
     70 * temperature values; they are the status bits.
     71 */
     72static inline s16 LM77_TEMP_TO_REG(int temp)
     73{
     74	return (temp / 500) * 8;
     75}
     76
     77static inline int LM77_TEMP_FROM_REG(s16 reg)
     78{
     79	return (reg / 8) * 500;
     80}
     81
     82/*
     83 * All registers are word-sized, except for the configuration register.
     84 * The LM77 uses the high-byte first convention.
     85 */
     86static u16 lm77_read_value(struct i2c_client *client, u8 reg)
     87{
     88	if (reg == LM77_REG_CONF)
     89		return i2c_smbus_read_byte_data(client, reg);
     90	else
     91		return i2c_smbus_read_word_swapped(client, reg);
     92}
     93
     94static int lm77_write_value(struct i2c_client *client, u8 reg, u16 value)
     95{
     96	if (reg == LM77_REG_CONF)
     97		return i2c_smbus_write_byte_data(client, reg, value);
     98	else
     99		return i2c_smbus_write_word_swapped(client, reg, value);
    100}
    101
    102static struct lm77_data *lm77_update_device(struct device *dev)
    103{
    104	struct lm77_data *data = dev_get_drvdata(dev);
    105	struct i2c_client *client = data->client;
    106	int i;
    107
    108	mutex_lock(&data->update_lock);
    109
    110	if (time_after(jiffies, data->last_updated + HZ + HZ / 2)
    111	    || !data->valid) {
    112		dev_dbg(&client->dev, "Starting lm77 update\n");
    113		for (i = 0; i < t_num_temp; i++) {
    114			data->temp[i] =
    115			  LM77_TEMP_FROM_REG(lm77_read_value(client,
    116							     temp_regs[i]));
    117		}
    118		data->alarms =
    119			lm77_read_value(client, LM77_REG_TEMP) & 0x0007;
    120		data->last_updated = jiffies;
    121		data->valid = true;
    122	}
    123
    124	mutex_unlock(&data->update_lock);
    125
    126	return data;
    127}
    128
    129/* sysfs stuff */
    130
    131static ssize_t temp_show(struct device *dev, struct device_attribute *devattr,
    132			 char *buf)
    133{
    134	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
    135	struct lm77_data *data = lm77_update_device(dev);
    136
    137	return sprintf(buf, "%d\n", data->temp[attr->index]);
    138}
    139
    140static ssize_t temp_hyst_show(struct device *dev,
    141			      struct device_attribute *devattr, char *buf)
    142{
    143	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
    144	struct lm77_data *data = lm77_update_device(dev);
    145	int nr = attr->index;
    146	int temp;
    147
    148	temp = nr == t_min ? data->temp[nr] + data->temp[t_hyst] :
    149			     data->temp[nr] - data->temp[t_hyst];
    150
    151	return sprintf(buf, "%d\n", temp);
    152}
    153
    154static ssize_t temp_store(struct device *dev,
    155			  struct device_attribute *devattr, const char *buf,
    156			  size_t count)
    157{
    158	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
    159	struct lm77_data *data = dev_get_drvdata(dev);
    160	struct i2c_client *client = data->client;
    161	int nr = attr->index;
    162	long val;
    163	int err;
    164
    165	err = kstrtol(buf, 10, &val);
    166	if (err)
    167		return err;
    168
    169	val = clamp_val(val, LM77_TEMP_MIN, LM77_TEMP_MAX);
    170	mutex_lock(&data->update_lock);
    171	data->temp[nr] = val;
    172	lm77_write_value(client, temp_regs[nr], LM77_TEMP_TO_REG(val));
    173	mutex_unlock(&data->update_lock);
    174	return count;
    175}
    176
    177/*
    178 * hysteresis is stored as a relative value on the chip, so it has to be
    179 * converted first.
    180 */
    181static ssize_t temp_hyst_store(struct device *dev,
    182			       struct device_attribute *devattr,
    183			       const char *buf, size_t count)
    184{
    185	struct lm77_data *data = dev_get_drvdata(dev);
    186	struct i2c_client *client = data->client;
    187	long val;
    188	int err;
    189
    190	err = kstrtol(buf, 10, &val);
    191	if (err)
    192		return err;
    193
    194	mutex_lock(&data->update_lock);
    195	val = clamp_val(data->temp[t_crit] - val, LM77_TEMP_MIN, LM77_TEMP_MAX);
    196	data->temp[t_hyst] = val;
    197	lm77_write_value(client, LM77_REG_TEMP_HYST,
    198			 LM77_TEMP_TO_REG(data->temp[t_hyst]));
    199	mutex_unlock(&data->update_lock);
    200	return count;
    201}
    202
    203static ssize_t alarm_show(struct device *dev, struct device_attribute *attr,
    204			  char *buf)
    205{
    206	int bitnr = to_sensor_dev_attr(attr)->index;
    207	struct lm77_data *data = lm77_update_device(dev);
    208	return sprintf(buf, "%u\n", (data->alarms >> bitnr) & 1);
    209}
    210
    211static SENSOR_DEVICE_ATTR_RO(temp1_input, temp, t_input);
    212static SENSOR_DEVICE_ATTR_RW(temp1_crit, temp, t_crit);
    213static SENSOR_DEVICE_ATTR_RW(temp1_min, temp, t_min);
    214static SENSOR_DEVICE_ATTR_RW(temp1_max, temp, t_max);
    215
    216static SENSOR_DEVICE_ATTR_RW(temp1_crit_hyst, temp_hyst, t_crit);
    217static SENSOR_DEVICE_ATTR_RO(temp1_min_hyst, temp_hyst, t_min);
    218static SENSOR_DEVICE_ATTR_RO(temp1_max_hyst, temp_hyst, t_max);
    219
    220static SENSOR_DEVICE_ATTR_RO(temp1_crit_alarm, alarm, 2);
    221static SENSOR_DEVICE_ATTR_RO(temp1_min_alarm, alarm, 0);
    222static SENSOR_DEVICE_ATTR_RO(temp1_max_alarm, alarm, 1);
    223
    224static struct attribute *lm77_attrs[] = {
    225	&sensor_dev_attr_temp1_input.dev_attr.attr,
    226	&sensor_dev_attr_temp1_crit.dev_attr.attr,
    227	&sensor_dev_attr_temp1_min.dev_attr.attr,
    228	&sensor_dev_attr_temp1_max.dev_attr.attr,
    229	&sensor_dev_attr_temp1_crit_hyst.dev_attr.attr,
    230	&sensor_dev_attr_temp1_min_hyst.dev_attr.attr,
    231	&sensor_dev_attr_temp1_max_hyst.dev_attr.attr,
    232	&sensor_dev_attr_temp1_crit_alarm.dev_attr.attr,
    233	&sensor_dev_attr_temp1_min_alarm.dev_attr.attr,
    234	&sensor_dev_attr_temp1_max_alarm.dev_attr.attr,
    235	NULL
    236};
    237ATTRIBUTE_GROUPS(lm77);
    238
    239/* Return 0 if detection is successful, -ENODEV otherwise */
    240static int lm77_detect(struct i2c_client *client, struct i2c_board_info *info)
    241{
    242	struct i2c_adapter *adapter = client->adapter;
    243	int i, cur, conf, hyst, crit, min, max;
    244
    245	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA |
    246				     I2C_FUNC_SMBUS_WORD_DATA))
    247		return -ENODEV;
    248
    249	/*
    250	 * Here comes the remaining detection.  Since the LM77 has no
    251	 * register dedicated to identification, we have to rely on the
    252	 * following tricks:
    253	 *
    254	 * 1. the high 4 bits represent the sign and thus they should
    255	 *    always be the same
    256	 * 2. the high 3 bits are unused in the configuration register
    257	 * 3. addresses 0x06 and 0x07 return the last read value
    258	 * 4. registers cycling over 8-address boundaries
    259	 *
    260	 * Word-sized registers are high-byte first.
    261	 */
    262
    263	/* addresses cycling */
    264	cur = i2c_smbus_read_word_data(client, 0);
    265	conf = i2c_smbus_read_byte_data(client, 1);
    266	hyst = i2c_smbus_read_word_data(client, 2);
    267	crit = i2c_smbus_read_word_data(client, 3);
    268	min = i2c_smbus_read_word_data(client, 4);
    269	max = i2c_smbus_read_word_data(client, 5);
    270	for (i = 8; i <= 0xff; i += 8) {
    271		if (i2c_smbus_read_byte_data(client, i + 1) != conf
    272		 || i2c_smbus_read_word_data(client, i + 2) != hyst
    273		 || i2c_smbus_read_word_data(client, i + 3) != crit
    274		 || i2c_smbus_read_word_data(client, i + 4) != min
    275		 || i2c_smbus_read_word_data(client, i + 5) != max)
    276			return -ENODEV;
    277	}
    278
    279	/* sign bits */
    280	if (((cur & 0x00f0) != 0xf0 && (cur & 0x00f0) != 0x0)
    281	 || ((hyst & 0x00f0) != 0xf0 && (hyst & 0x00f0) != 0x0)
    282	 || ((crit & 0x00f0) != 0xf0 && (crit & 0x00f0) != 0x0)
    283	 || ((min & 0x00f0) != 0xf0 && (min & 0x00f0) != 0x0)
    284	 || ((max & 0x00f0) != 0xf0 && (max & 0x00f0) != 0x0))
    285		return -ENODEV;
    286
    287	/* unused bits */
    288	if (conf & 0xe0)
    289		return -ENODEV;
    290
    291	/* 0x06 and 0x07 return the last read value */
    292	cur = i2c_smbus_read_word_data(client, 0);
    293	if (i2c_smbus_read_word_data(client, 6) != cur
    294	 || i2c_smbus_read_word_data(client, 7) != cur)
    295		return -ENODEV;
    296	hyst = i2c_smbus_read_word_data(client, 2);
    297	if (i2c_smbus_read_word_data(client, 6) != hyst
    298	 || i2c_smbus_read_word_data(client, 7) != hyst)
    299		return -ENODEV;
    300	min = i2c_smbus_read_word_data(client, 4);
    301	if (i2c_smbus_read_word_data(client, 6) != min
    302	 || i2c_smbus_read_word_data(client, 7) != min)
    303		return -ENODEV;
    304
    305	strlcpy(info->type, "lm77", I2C_NAME_SIZE);
    306
    307	return 0;
    308}
    309
    310static void lm77_init_client(struct i2c_client *client)
    311{
    312	/* Initialize the LM77 chip - turn off shutdown mode */
    313	int conf = lm77_read_value(client, LM77_REG_CONF);
    314	if (conf & 1)
    315		lm77_write_value(client, LM77_REG_CONF, conf & 0xfe);
    316}
    317
    318static int lm77_probe(struct i2c_client *client)
    319{
    320	struct device *dev = &client->dev;
    321	struct device *hwmon_dev;
    322	struct lm77_data *data;
    323
    324	data = devm_kzalloc(dev, sizeof(struct lm77_data), GFP_KERNEL);
    325	if (!data)
    326		return -ENOMEM;
    327
    328	data->client = client;
    329	mutex_init(&data->update_lock);
    330
    331	/* Initialize the LM77 chip */
    332	lm77_init_client(client);
    333
    334	hwmon_dev = devm_hwmon_device_register_with_groups(dev, client->name,
    335							   data, lm77_groups);
    336	return PTR_ERR_OR_ZERO(hwmon_dev);
    337}
    338
    339static const struct i2c_device_id lm77_id[] = {
    340	{ "lm77", 0 },
    341	{ }
    342};
    343MODULE_DEVICE_TABLE(i2c, lm77_id);
    344
    345/* This is the driver that will be inserted */
    346static struct i2c_driver lm77_driver = {
    347	.class		= I2C_CLASS_HWMON,
    348	.driver = {
    349		.name	= "lm77",
    350	},
    351	.probe_new	= lm77_probe,
    352	.id_table	= lm77_id,
    353	.detect		= lm77_detect,
    354	.address_list	= normal_i2c,
    355};
    356
    357module_i2c_driver(lm77_driver);
    358
    359MODULE_AUTHOR("Andras BALI <drewie@freemail.hu>");
    360MODULE_DESCRIPTION("LM77 driver");
    361MODULE_LICENSE("GPL");