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

sch5627.c (13700B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/***************************************************************************
      3 *   Copyright (C) 2010-2012 Hans de Goede <hdegoede@redhat.com>           *
      4 *                                                                         *
      5 ***************************************************************************/
      6
      7#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
      8
      9#include <linux/module.h>
     10#include <linux/mod_devicetable.h>
     11#include <linux/init.h>
     12#include <linux/slab.h>
     13#include <linux/jiffies.h>
     14#include <linux/platform_device.h>
     15#include <linux/hwmon.h>
     16#include <linux/err.h>
     17#include <linux/mutex.h>
     18#include "sch56xx-common.h"
     19
     20#define DRVNAME "sch5627"
     21#define DEVNAME DRVNAME /* We only support one model */
     22
     23#define SCH5627_HWMON_ID		0xa5
     24#define SCH5627_COMPANY_ID		0x5c
     25#define SCH5627_PRIMARY_ID		0xa0
     26
     27#define SCH5627_REG_BUILD_CODE		0x39
     28#define SCH5627_REG_BUILD_ID		0x3a
     29#define SCH5627_REG_HWMON_ID		0x3c
     30#define SCH5627_REG_HWMON_REV		0x3d
     31#define SCH5627_REG_COMPANY_ID		0x3e
     32#define SCH5627_REG_PRIMARY_ID		0x3f
     33#define SCH5627_REG_CTRL		0x40
     34
     35#define SCH5627_NO_TEMPS		8
     36#define SCH5627_NO_FANS			4
     37#define SCH5627_NO_IN			5
     38
     39static const u16 SCH5627_REG_TEMP_MSB[SCH5627_NO_TEMPS] = {
     40	0x2B, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x180, 0x181 };
     41static const u16 SCH5627_REG_TEMP_LSN[SCH5627_NO_TEMPS] = {
     42	0xE2, 0xE1, 0xE1, 0xE5, 0xE5, 0xE6, 0x182, 0x182 };
     43static const u16 SCH5627_REG_TEMP_HIGH_NIBBLE[SCH5627_NO_TEMPS] = {
     44	0, 0, 1, 1, 0, 0, 0, 1 };
     45static const u16 SCH5627_REG_TEMP_HIGH[SCH5627_NO_TEMPS] = {
     46	0x61, 0x57, 0x59, 0x5B, 0x5D, 0x5F, 0x184, 0x186 };
     47static const u16 SCH5627_REG_TEMP_ABS[SCH5627_NO_TEMPS] = {
     48	0x9B, 0x96, 0x97, 0x98, 0x99, 0x9A, 0x1A8, 0x1A9 };
     49
     50static const u16 SCH5627_REG_FAN[SCH5627_NO_FANS] = {
     51	0x2C, 0x2E, 0x30, 0x32 };
     52static const u16 SCH5627_REG_FAN_MIN[SCH5627_NO_FANS] = {
     53	0x62, 0x64, 0x66, 0x68 };
     54
     55static const u16 SCH5627_REG_PWM_MAP[SCH5627_NO_FANS] = {
     56	0xA0, 0xA1, 0xA2, 0xA3 };
     57
     58static const u16 SCH5627_REG_IN_MSB[SCH5627_NO_IN] = {
     59	0x22, 0x23, 0x24, 0x25, 0x189 };
     60static const u16 SCH5627_REG_IN_LSN[SCH5627_NO_IN] = {
     61	0xE4, 0xE4, 0xE3, 0xE3, 0x18A };
     62static const u16 SCH5627_REG_IN_HIGH_NIBBLE[SCH5627_NO_IN] = {
     63	1, 0, 1, 0, 1 };
     64static const u16 SCH5627_REG_IN_FACTOR[SCH5627_NO_IN] = {
     65	10745, 3660, 9765, 10745, 3660 };
     66static const char * const SCH5627_IN_LABELS[SCH5627_NO_IN] = {
     67	"VCC", "VTT", "VBAT", "VTR", "V_IN" };
     68
     69struct sch5627_data {
     70	unsigned short addr;
     71	u8 control;
     72	u8 temp_max[SCH5627_NO_TEMPS];
     73	u8 temp_crit[SCH5627_NO_TEMPS];
     74	u16 fan_min[SCH5627_NO_FANS];
     75
     76	struct mutex update_lock;
     77	unsigned long last_battery;	/* In jiffies */
     78	char temp_valid;		/* !=0 if following fields are valid */
     79	char fan_valid;
     80	char in_valid;
     81	unsigned long temp_last_updated;	/* In jiffies */
     82	unsigned long fan_last_updated;
     83	unsigned long in_last_updated;
     84	u16 temp[SCH5627_NO_TEMPS];
     85	u16 fan[SCH5627_NO_FANS];
     86	u16 in[SCH5627_NO_IN];
     87};
     88
     89static int sch5627_update_temp(struct sch5627_data *data)
     90{
     91	int ret = 0;
     92	int i, val;
     93
     94	mutex_lock(&data->update_lock);
     95
     96	/* Cache the values for 1 second */
     97	if (time_after(jiffies, data->temp_last_updated + HZ) || !data->temp_valid) {
     98		for (i = 0; i < SCH5627_NO_TEMPS; i++) {
     99			val = sch56xx_read_virtual_reg12(data->addr, SCH5627_REG_TEMP_MSB[i],
    100							 SCH5627_REG_TEMP_LSN[i],
    101							 SCH5627_REG_TEMP_HIGH_NIBBLE[i]);
    102			if (unlikely(val < 0)) {
    103				ret = val;
    104				goto abort;
    105			}
    106			data->temp[i] = val;
    107		}
    108		data->temp_last_updated = jiffies;
    109		data->temp_valid = 1;
    110	}
    111abort:
    112	mutex_unlock(&data->update_lock);
    113	return ret;
    114}
    115
    116static int sch5627_update_fan(struct sch5627_data *data)
    117{
    118	int ret = 0;
    119	int i, val;
    120
    121	mutex_lock(&data->update_lock);
    122
    123	/* Cache the values for 1 second */
    124	if (time_after(jiffies, data->fan_last_updated + HZ) || !data->fan_valid) {
    125		for (i = 0; i < SCH5627_NO_FANS; i++) {
    126			val = sch56xx_read_virtual_reg16(data->addr, SCH5627_REG_FAN[i]);
    127			if (unlikely(val < 0)) {
    128				ret = val;
    129				goto abort;
    130			}
    131			data->fan[i] = val;
    132		}
    133		data->fan_last_updated = jiffies;
    134		data->fan_valid = 1;
    135	}
    136abort:
    137	mutex_unlock(&data->update_lock);
    138	return ret;
    139}
    140
    141static int sch5627_update_in(struct sch5627_data *data)
    142{
    143	int ret = 0;
    144	int i, val;
    145
    146	mutex_lock(&data->update_lock);
    147
    148	/* Trigger a Vbat voltage measurement every 5 minutes */
    149	if (time_after(jiffies, data->last_battery + 300 * HZ)) {
    150		sch56xx_write_virtual_reg(data->addr, SCH5627_REG_CTRL, data->control | 0x10);
    151		data->last_battery = jiffies;
    152	}
    153
    154	/* Cache the values for 1 second */
    155	if (time_after(jiffies, data->in_last_updated + HZ) || !data->in_valid) {
    156		for (i = 0; i < SCH5627_NO_IN; i++) {
    157			val = sch56xx_read_virtual_reg12(data->addr, SCH5627_REG_IN_MSB[i],
    158							 SCH5627_REG_IN_LSN[i],
    159							 SCH5627_REG_IN_HIGH_NIBBLE[i]);
    160			if (unlikely(val < 0)) {
    161				ret = val;
    162				goto abort;
    163			}
    164			data->in[i] = val;
    165		}
    166		data->in_last_updated = jiffies;
    167		data->in_valid = 1;
    168	}
    169abort:
    170	mutex_unlock(&data->update_lock);
    171	return ret;
    172}
    173
    174static int sch5627_read_limits(struct sch5627_data *data)
    175{
    176	int i, val;
    177
    178	for (i = 0; i < SCH5627_NO_TEMPS; i++) {
    179		/*
    180		 * Note what SMSC calls ABS, is what lm_sensors calls max
    181		 * (aka high), and HIGH is what lm_sensors calls crit.
    182		 */
    183		val = sch56xx_read_virtual_reg(data->addr,
    184					       SCH5627_REG_TEMP_ABS[i]);
    185		if (val < 0)
    186			return val;
    187		data->temp_max[i] = val;
    188
    189		val = sch56xx_read_virtual_reg(data->addr,
    190					       SCH5627_REG_TEMP_HIGH[i]);
    191		if (val < 0)
    192			return val;
    193		data->temp_crit[i] = val;
    194	}
    195	for (i = 0; i < SCH5627_NO_FANS; i++) {
    196		val = sch56xx_read_virtual_reg16(data->addr,
    197						 SCH5627_REG_FAN_MIN[i]);
    198		if (val < 0)
    199			return val;
    200		data->fan_min[i] = val;
    201	}
    202
    203	return 0;
    204}
    205
    206static int reg_to_temp(u16 reg)
    207{
    208	return (reg * 625) / 10 - 64000;
    209}
    210
    211static int reg_to_temp_limit(u8 reg)
    212{
    213	return (reg - 64) * 1000;
    214}
    215
    216static int reg_to_rpm(u16 reg)
    217{
    218	if (reg == 0)
    219		return -EIO;
    220	if (reg == 0xffff)
    221		return 0;
    222
    223	return 5400540 / reg;
    224}
    225
    226static umode_t sch5627_is_visible(const void *drvdata, enum hwmon_sensor_types type, u32 attr,
    227				  int channel)
    228{
    229	if (type == hwmon_pwm && attr == hwmon_pwm_auto_channels_temp)
    230		return 0644;
    231
    232	return 0444;
    233}
    234
    235static int sch5627_read(struct device *dev, enum hwmon_sensor_types type, u32 attr, int channel,
    236			long *val)
    237{
    238	struct sch5627_data *data = dev_get_drvdata(dev);
    239	int ret;
    240
    241	switch (type) {
    242	case hwmon_temp:
    243		ret = sch5627_update_temp(data);
    244		if (ret < 0)
    245			return ret;
    246		switch (attr) {
    247		case hwmon_temp_input:
    248			*val = reg_to_temp(data->temp[channel]);
    249			return 0;
    250		case hwmon_temp_max:
    251			*val = reg_to_temp_limit(data->temp_max[channel]);
    252			return 0;
    253		case hwmon_temp_crit:
    254			*val = reg_to_temp_limit(data->temp_crit[channel]);
    255			return 0;
    256		case hwmon_temp_fault:
    257			*val = (data->temp[channel] == 0);
    258			return 0;
    259		default:
    260			break;
    261		}
    262		break;
    263	case hwmon_fan:
    264		ret = sch5627_update_fan(data);
    265		if (ret < 0)
    266			return ret;
    267		switch (attr) {
    268		case hwmon_fan_input:
    269			ret = reg_to_rpm(data->fan[channel]);
    270			if (ret < 0)
    271				return ret;
    272			*val = ret;
    273			return 0;
    274		case hwmon_fan_min:
    275			ret = reg_to_rpm(data->fan_min[channel]);
    276			if (ret < 0)
    277				return ret;
    278			*val = ret;
    279			return 0;
    280		case hwmon_fan_fault:
    281			*val = (data->fan[channel] == 0xffff);
    282			return 0;
    283		default:
    284			break;
    285		}
    286		break;
    287	case hwmon_pwm:
    288		switch (attr) {
    289		case hwmon_pwm_auto_channels_temp:
    290			mutex_lock(&data->update_lock);
    291			ret = sch56xx_read_virtual_reg(data->addr, SCH5627_REG_PWM_MAP[channel]);
    292			mutex_unlock(&data->update_lock);
    293
    294			if (ret < 0)
    295				return ret;
    296
    297			*val = ret;
    298
    299			return 0;
    300		default:
    301			break;
    302		}
    303		break;
    304	case hwmon_in:
    305		ret = sch5627_update_in(data);
    306		if (ret < 0)
    307			return ret;
    308		switch (attr) {
    309		case hwmon_in_input:
    310			*val = DIV_ROUND_CLOSEST(data->in[channel] * SCH5627_REG_IN_FACTOR[channel],
    311						 10000);
    312			return 0;
    313		default:
    314			break;
    315		}
    316		break;
    317	default:
    318		break;
    319	}
    320
    321	return -EOPNOTSUPP;
    322}
    323
    324static int sch5627_read_string(struct device *dev, enum hwmon_sensor_types type, u32 attr,
    325			       int channel, const char **str)
    326{
    327	switch (type) {
    328	case hwmon_in:
    329		switch (attr) {
    330		case hwmon_in_label:
    331			*str = SCH5627_IN_LABELS[channel];
    332			return 0;
    333		default:
    334			break;
    335		}
    336		break;
    337	default:
    338		break;
    339	}
    340
    341	return -EOPNOTSUPP;
    342}
    343
    344static int sch5627_write(struct device *dev, enum hwmon_sensor_types type, u32 attr, int channel,
    345			 long val)
    346{
    347	struct sch5627_data *data = dev_get_drvdata(dev);
    348	int ret;
    349
    350	switch (type) {
    351	case hwmon_pwm:
    352		switch (attr) {
    353		case hwmon_pwm_auto_channels_temp:
    354			/* registers are 8 bit wide */
    355			if (val > U8_MAX || val < 0)
    356				return -EINVAL;
    357
    358			mutex_lock(&data->update_lock);
    359			ret = sch56xx_write_virtual_reg(data->addr, SCH5627_REG_PWM_MAP[channel],
    360							val);
    361			mutex_unlock(&data->update_lock);
    362
    363			return ret;
    364		default:
    365			break;
    366		}
    367		break;
    368	default:
    369		break;
    370	}
    371
    372	return -EOPNOTSUPP;
    373}
    374
    375static const struct hwmon_ops sch5627_ops = {
    376	.is_visible = sch5627_is_visible,
    377	.read = sch5627_read,
    378	.read_string = sch5627_read_string,
    379	.write = sch5627_write,
    380};
    381
    382static const struct hwmon_channel_info *sch5627_info[] = {
    383	HWMON_CHANNEL_INFO(chip, HWMON_C_REGISTER_TZ),
    384	HWMON_CHANNEL_INFO(temp,
    385			   HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_CRIT | HWMON_T_FAULT,
    386			   HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_CRIT | HWMON_T_FAULT,
    387			   HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_CRIT | HWMON_T_FAULT,
    388			   HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_CRIT | HWMON_T_FAULT,
    389			   HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_CRIT | HWMON_T_FAULT,
    390			   HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_CRIT | HWMON_T_FAULT,
    391			   HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_CRIT | HWMON_T_FAULT,
    392			   HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_CRIT | HWMON_T_FAULT
    393			   ),
    394	HWMON_CHANNEL_INFO(fan,
    395			   HWMON_F_INPUT | HWMON_F_MIN | HWMON_F_FAULT,
    396			   HWMON_F_INPUT | HWMON_F_MIN | HWMON_F_FAULT,
    397			   HWMON_F_INPUT | HWMON_F_MIN | HWMON_F_FAULT,
    398			   HWMON_F_INPUT | HWMON_F_MIN | HWMON_F_FAULT
    399			   ),
    400	HWMON_CHANNEL_INFO(pwm,
    401			   HWMON_PWM_AUTO_CHANNELS_TEMP,
    402			   HWMON_PWM_AUTO_CHANNELS_TEMP,
    403			   HWMON_PWM_AUTO_CHANNELS_TEMP,
    404			   HWMON_PWM_AUTO_CHANNELS_TEMP
    405			   ),
    406	HWMON_CHANNEL_INFO(in,
    407			   HWMON_I_INPUT | HWMON_I_LABEL,
    408			   HWMON_I_INPUT | HWMON_I_LABEL,
    409			   HWMON_I_INPUT | HWMON_I_LABEL,
    410			   HWMON_I_INPUT | HWMON_I_LABEL,
    411			   HWMON_I_INPUT
    412			   ),
    413	NULL
    414};
    415
    416static const struct hwmon_chip_info sch5627_chip_info = {
    417	.ops = &sch5627_ops,
    418	.info = sch5627_info,
    419};
    420
    421static int sch5627_probe(struct platform_device *pdev)
    422{
    423	struct sch5627_data *data;
    424	struct device *hwmon_dev;
    425	int err, build_code, build_id, hwmon_rev, val;
    426
    427	data = devm_kzalloc(&pdev->dev, sizeof(struct sch5627_data),
    428			    GFP_KERNEL);
    429	if (!data)
    430		return -ENOMEM;
    431
    432	data->addr = platform_get_resource(pdev, IORESOURCE_IO, 0)->start;
    433	mutex_init(&data->update_lock);
    434	platform_set_drvdata(pdev, data);
    435
    436	val = sch56xx_read_virtual_reg(data->addr, SCH5627_REG_HWMON_ID);
    437	if (val < 0)
    438		return val;
    439
    440	if (val != SCH5627_HWMON_ID) {
    441		pr_err("invalid %s id: 0x%02X (expected 0x%02X)\n", "hwmon",
    442		       val, SCH5627_HWMON_ID);
    443		return -ENODEV;
    444	}
    445
    446	val = sch56xx_read_virtual_reg(data->addr, SCH5627_REG_COMPANY_ID);
    447	if (val < 0)
    448		return val;
    449
    450	if (val != SCH5627_COMPANY_ID) {
    451		pr_err("invalid %s id: 0x%02X (expected 0x%02X)\n", "company",
    452		       val, SCH5627_COMPANY_ID);
    453		return -ENODEV;
    454	}
    455
    456	val = sch56xx_read_virtual_reg(data->addr, SCH5627_REG_PRIMARY_ID);
    457	if (val < 0)
    458		return val;
    459
    460	if (val != SCH5627_PRIMARY_ID) {
    461		pr_err("invalid %s id: 0x%02X (expected 0x%02X)\n", "primary",
    462		       val, SCH5627_PRIMARY_ID);
    463		return -ENODEV;
    464	}
    465
    466	build_code = sch56xx_read_virtual_reg(data->addr,
    467					      SCH5627_REG_BUILD_CODE);
    468	if (build_code < 0)
    469		return build_code;
    470
    471	build_id = sch56xx_read_virtual_reg16(data->addr,
    472					      SCH5627_REG_BUILD_ID);
    473	if (build_id < 0)
    474		return build_id;
    475
    476	hwmon_rev = sch56xx_read_virtual_reg(data->addr,
    477					     SCH5627_REG_HWMON_REV);
    478	if (hwmon_rev < 0)
    479		return hwmon_rev;
    480
    481	val = sch56xx_read_virtual_reg(data->addr, SCH5627_REG_CTRL);
    482	if (val < 0)
    483		return val;
    484
    485	data->control = val;
    486	if (!(data->control & 0x01)) {
    487		pr_err("hardware monitoring not enabled\n");
    488		return -ENODEV;
    489	}
    490	/* Trigger a Vbat voltage measurement, so that we get a valid reading
    491	   the first time we read Vbat */
    492	sch56xx_write_virtual_reg(data->addr, SCH5627_REG_CTRL,
    493				  data->control | 0x10);
    494	data->last_battery = jiffies;
    495
    496	/*
    497	 * Read limits, we do this only once as reading a register on
    498	 * the sch5627 is quite expensive (and they don't change).
    499	 */
    500	err = sch5627_read_limits(data);
    501	if (err)
    502		return err;
    503
    504	pr_info("found %s chip at %#hx\n", DEVNAME, data->addr);
    505	pr_info("firmware build: code 0x%02X, id 0x%04X, hwmon: rev 0x%02X\n",
    506		build_code, build_id, hwmon_rev);
    507
    508	hwmon_dev = devm_hwmon_device_register_with_info(&pdev->dev, DEVNAME, data,
    509							 &sch5627_chip_info, NULL);
    510	if (IS_ERR(hwmon_dev))
    511		return PTR_ERR(hwmon_dev);
    512
    513	/* Note failing to register the watchdog is not a fatal error */
    514	sch56xx_watchdog_register(&pdev->dev, data->addr,
    515				  (build_code << 24) | (build_id << 8) | hwmon_rev,
    516				  &data->update_lock, 1);
    517
    518	return 0;
    519}
    520
    521static const struct platform_device_id sch5627_device_id[] = {
    522	{
    523		.name = "sch5627",
    524	},
    525	{ }
    526};
    527MODULE_DEVICE_TABLE(platform, sch5627_device_id);
    528
    529static struct platform_driver sch5627_driver = {
    530	.driver = {
    531		.name	= DRVNAME,
    532	},
    533	.probe		= sch5627_probe,
    534	.id_table	= sch5627_device_id,
    535};
    536
    537module_platform_driver(sch5627_driver);
    538
    539MODULE_DESCRIPTION("SMSC SCH5627 Hardware Monitoring Driver");
    540MODULE_AUTHOR("Hans de Goede <hdegoede@redhat.com>");
    541MODULE_LICENSE("GPL");