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

lan966x-hwmon.c (10257B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2
      3#include <linux/bitfield.h>
      4#include <linux/clk.h>
      5#include <linux/hwmon.h>
      6#include <linux/kernel.h>
      7#include <linux/module.h>
      8#include <linux/mod_devicetable.h>
      9#include <linux/platform_device.h>
     10#include <linux/polynomial.h>
     11#include <linux/regmap.h>
     12
     13/*
     14 * The original translation formulae of the temperature (in degrees of Celsius)
     15 * are as follows:
     16 *
     17 *   T = -3.4627e-11*(N^4) + 1.1023e-7*(N^3) + -1.9165e-4*(N^2) +
     18 *       3.0604e-1*(N^1) + -5.6197e1
     19 *
     20 * where [-56.197, 136.402]C and N = [0, 1023].
     21 *
     22 * They must be accordingly altered to be suitable for the integer arithmetics.
     23 * The technique is called 'factor redistribution', which just makes sure the
     24 * multiplications and divisions are made so to have a result of the operations
     25 * within the integer numbers limit. In addition we need to translate the
     26 * formulae to accept millidegrees of Celsius. Here what it looks like after
     27 * the alterations:
     28 *
     29 *   T = -34627e-12*(N^4) + 110230e-9*(N^3) + -191650e-6*(N^2) +
     30 *       306040e-3*(N^1) + -56197
     31 *
     32 * where T = [-56197, 136402]mC and N = [0, 1023].
     33 */
     34
     35static const struct polynomial poly_N_to_temp = {
     36	.terms = {
     37		{4,  -34627, 1000, 1},
     38		{3,  110230, 1000, 1},
     39		{2, -191650, 1000, 1},
     40		{1,  306040, 1000, 1},
     41		{0,  -56197,    1, 1}
     42	}
     43};
     44
     45#define PVT_SENSOR_CTRL		0x0 /* unused */
     46#define PVT_SENSOR_CFG		0x4
     47#define   SENSOR_CFG_CLK_CFG		GENMASK(27, 20)
     48#define   SENSOR_CFG_TRIM_VAL		GENMASK(13, 9)
     49#define   SENSOR_CFG_SAMPLE_ENA		BIT(8)
     50#define   SENSOR_CFG_START_CAPTURE	BIT(7)
     51#define   SENSOR_CFG_CONTINIOUS_MODE	BIT(6)
     52#define   SENSOR_CFG_PSAMPLE_ENA	GENMASK(1, 0)
     53#define PVT_SENSOR_STAT		0x8
     54#define   SENSOR_STAT_DATA_VALID	BIT(10)
     55#define   SENSOR_STAT_DATA		GENMASK(9, 0)
     56
     57#define FAN_CFG			0x0
     58#define   FAN_CFG_DUTY_CYCLE		GENMASK(23, 16)
     59#define   INV_POL			BIT(3)
     60#define   GATE_ENA			BIT(2)
     61#define   PWM_OPEN_COL_ENA		BIT(1)
     62#define   FAN_STAT_CFG			BIT(0)
     63#define FAN_PWM_FREQ		0x4
     64#define   FAN_PWM_CYC_10US		GENMASK(25, 15)
     65#define   FAN_PWM_FREQ_FREQ		GENMASK(14, 0)
     66#define FAN_CNT			0xc
     67#define   FAN_CNT_DATA			GENMASK(15, 0)
     68
     69#define LAN966X_PVT_CLK		1200000 /* 1.2 MHz */
     70
     71struct lan966x_hwmon {
     72	struct regmap *regmap_pvt;
     73	struct regmap *regmap_fan;
     74	struct clk *clk;
     75	unsigned long clk_rate;
     76};
     77
     78static int lan966x_hwmon_read_temp(struct device *dev, long *val)
     79{
     80	struct lan966x_hwmon *hwmon = dev_get_drvdata(dev);
     81	unsigned int data;
     82	int ret;
     83
     84	ret = regmap_read(hwmon->regmap_pvt, PVT_SENSOR_STAT, &data);
     85	if (ret < 0)
     86		return ret;
     87
     88	if (!(data & SENSOR_STAT_DATA_VALID))
     89		return -ENODATA;
     90
     91	*val = polynomial_calc(&poly_N_to_temp,
     92			       FIELD_GET(SENSOR_STAT_DATA, data));
     93
     94	return 0;
     95}
     96
     97static int lan966x_hwmon_read_fan(struct device *dev, long *val)
     98{
     99	struct lan966x_hwmon *hwmon = dev_get_drvdata(dev);
    100	unsigned int data;
    101	int ret;
    102
    103	ret = regmap_read(hwmon->regmap_fan, FAN_CNT, &data);
    104	if (ret < 0)
    105		return ret;
    106
    107	/*
    108	 * Data is given in pulses per second. Assume two pulses
    109	 * per revolution.
    110	 */
    111	*val = FIELD_GET(FAN_CNT_DATA, data) * 60 / 2;
    112
    113	return 0;
    114}
    115
    116static int lan966x_hwmon_read_pwm(struct device *dev, long *val)
    117{
    118	struct lan966x_hwmon *hwmon = dev_get_drvdata(dev);
    119	unsigned int data;
    120	int ret;
    121
    122	ret = regmap_read(hwmon->regmap_fan, FAN_CFG, &data);
    123	if (ret < 0)
    124		return ret;
    125
    126	*val = FIELD_GET(FAN_CFG_DUTY_CYCLE, data);
    127
    128	return 0;
    129}
    130
    131static int lan966x_hwmon_read_pwm_freq(struct device *dev, long *val)
    132{
    133	struct lan966x_hwmon *hwmon = dev_get_drvdata(dev);
    134	unsigned long tmp;
    135	unsigned int data;
    136	int ret;
    137
    138	ret = regmap_read(hwmon->regmap_fan, FAN_PWM_FREQ, &data);
    139	if (ret < 0)
    140		return ret;
    141
    142	/*
    143	 * Datasheet says it is sys_clk / 256 / pwm_freq. But in reality
    144	 * it is sys_clk / 256 / (pwm_freq + 1).
    145	 */
    146	data = FIELD_GET(FAN_PWM_FREQ_FREQ, data) + 1;
    147	tmp = DIV_ROUND_CLOSEST(hwmon->clk_rate, 256);
    148	*val = DIV_ROUND_CLOSEST(tmp, data);
    149
    150	return 0;
    151}
    152
    153static int lan966x_hwmon_read(struct device *dev, enum hwmon_sensor_types type,
    154			      u32 attr, int channel, long *val)
    155{
    156	switch (type) {
    157	case hwmon_temp:
    158		return lan966x_hwmon_read_temp(dev, val);
    159	case hwmon_fan:
    160		return lan966x_hwmon_read_fan(dev, val);
    161	case hwmon_pwm:
    162		switch (attr) {
    163		case hwmon_pwm_input:
    164			return lan966x_hwmon_read_pwm(dev, val);
    165		case hwmon_pwm_freq:
    166			return lan966x_hwmon_read_pwm_freq(dev, val);
    167		default:
    168			return -EOPNOTSUPP;
    169		}
    170	default:
    171		return -EOPNOTSUPP;
    172	}
    173}
    174
    175static int lan966x_hwmon_write_pwm(struct device *dev, long val)
    176{
    177	struct lan966x_hwmon *hwmon = dev_get_drvdata(dev);
    178
    179	if (val < 0 || val > 255)
    180		return -EINVAL;
    181
    182	return regmap_update_bits(hwmon->regmap_fan, FAN_CFG,
    183				  FAN_CFG_DUTY_CYCLE,
    184				  FIELD_PREP(FAN_CFG_DUTY_CYCLE, val));
    185}
    186
    187static int lan966x_hwmon_write_pwm_freq(struct device *dev, long val)
    188{
    189	struct lan966x_hwmon *hwmon = dev_get_drvdata(dev);
    190
    191	if (val <= 0)
    192		return -EINVAL;
    193
    194	val = DIV_ROUND_CLOSEST(hwmon->clk_rate, val);
    195	val = DIV_ROUND_CLOSEST(val, 256) - 1;
    196	val = clamp_val(val, 0, FAN_PWM_FREQ_FREQ);
    197
    198	return regmap_update_bits(hwmon->regmap_fan, FAN_PWM_FREQ,
    199				  FAN_PWM_FREQ_FREQ,
    200				  FIELD_PREP(FAN_PWM_FREQ_FREQ, val));
    201}
    202
    203static int lan966x_hwmon_write(struct device *dev, enum hwmon_sensor_types type,
    204			       u32 attr, int channel, long val)
    205{
    206	switch (type) {
    207	case hwmon_pwm:
    208		switch (attr) {
    209		case hwmon_pwm_input:
    210			return lan966x_hwmon_write_pwm(dev, val);
    211		case hwmon_pwm_freq:
    212			return lan966x_hwmon_write_pwm_freq(dev, val);
    213		default:
    214			return -EOPNOTSUPP;
    215		}
    216	default:
    217		return -EOPNOTSUPP;
    218	}
    219}
    220
    221static umode_t lan966x_hwmon_is_visible(const void *data,
    222					enum hwmon_sensor_types type,
    223					u32 attr, int channel)
    224{
    225	umode_t mode = 0;
    226
    227	switch (type) {
    228	case hwmon_temp:
    229		switch (attr) {
    230		case hwmon_temp_input:
    231			mode = 0444;
    232			break;
    233		default:
    234			break;
    235		}
    236		break;
    237	case hwmon_fan:
    238		switch (attr) {
    239		case hwmon_fan_input:
    240			mode = 0444;
    241			break;
    242		default:
    243			break;
    244		}
    245		break;
    246	case hwmon_pwm:
    247		switch (attr) {
    248		case hwmon_pwm_input:
    249		case hwmon_pwm_freq:
    250			mode = 0644;
    251			break;
    252		default:
    253			break;
    254		}
    255		break;
    256	default:
    257		break;
    258	}
    259
    260	return mode;
    261}
    262
    263static const struct hwmon_channel_info *lan966x_hwmon_info[] = {
    264	HWMON_CHANNEL_INFO(chip, HWMON_C_REGISTER_TZ),
    265	HWMON_CHANNEL_INFO(temp, HWMON_T_INPUT),
    266	HWMON_CHANNEL_INFO(fan, HWMON_F_INPUT),
    267	HWMON_CHANNEL_INFO(pwm, HWMON_PWM_INPUT | HWMON_PWM_FREQ),
    268	NULL
    269};
    270
    271static const struct hwmon_ops lan966x_hwmon_ops = {
    272	.is_visible = lan966x_hwmon_is_visible,
    273	.read = lan966x_hwmon_read,
    274	.write = lan966x_hwmon_write,
    275};
    276
    277static const struct hwmon_chip_info lan966x_hwmon_chip_info = {
    278	.ops = &lan966x_hwmon_ops,
    279	.info = lan966x_hwmon_info,
    280};
    281
    282static void lan966x_hwmon_disable(void *data)
    283{
    284	struct lan966x_hwmon *hwmon = data;
    285
    286	regmap_update_bits(hwmon->regmap_pvt, PVT_SENSOR_CFG,
    287			   SENSOR_CFG_SAMPLE_ENA | SENSOR_CFG_CONTINIOUS_MODE,
    288			   0);
    289}
    290
    291static int lan966x_hwmon_enable(struct device *dev,
    292				struct lan966x_hwmon *hwmon)
    293{
    294	unsigned int mask = SENSOR_CFG_CLK_CFG |
    295			    SENSOR_CFG_SAMPLE_ENA |
    296			    SENSOR_CFG_START_CAPTURE |
    297			    SENSOR_CFG_CONTINIOUS_MODE |
    298			    SENSOR_CFG_PSAMPLE_ENA;
    299	unsigned int val;
    300	unsigned int div;
    301	int ret;
    302
    303	/* enable continuous mode */
    304	val = SENSOR_CFG_SAMPLE_ENA | SENSOR_CFG_CONTINIOUS_MODE;
    305
    306	/* set PVT clock to be between 1.15 and 1.25 MHz */
    307	div = DIV_ROUND_CLOSEST(hwmon->clk_rate, LAN966X_PVT_CLK);
    308	val |= FIELD_PREP(SENSOR_CFG_CLK_CFG, div);
    309
    310	ret = regmap_update_bits(hwmon->regmap_pvt, PVT_SENSOR_CFG,
    311				 mask, val);
    312	if (ret)
    313		return ret;
    314
    315	return devm_add_action_or_reset(dev, lan966x_hwmon_disable, hwmon);
    316}
    317
    318static struct regmap *lan966x_init_regmap(struct platform_device *pdev,
    319					  const char *name)
    320{
    321	struct regmap_config regmap_config = {
    322		.reg_bits = 32,
    323		.reg_stride = 4,
    324		.val_bits = 32,
    325	};
    326	void __iomem *base;
    327
    328	base = devm_platform_ioremap_resource_byname(pdev, name);
    329	if (IS_ERR(base))
    330		return ERR_CAST(base);
    331
    332	regmap_config.name = name;
    333
    334	return devm_regmap_init_mmio(&pdev->dev, base, &regmap_config);
    335}
    336
    337static void lan966x_clk_disable(void *data)
    338{
    339	struct lan966x_hwmon *hwmon = data;
    340
    341	clk_disable_unprepare(hwmon->clk);
    342}
    343
    344static int lan966x_clk_enable(struct device *dev, struct lan966x_hwmon *hwmon)
    345{
    346	int ret;
    347
    348	ret = clk_prepare_enable(hwmon->clk);
    349	if (ret)
    350		return ret;
    351
    352	return devm_add_action_or_reset(dev, lan966x_clk_disable, hwmon);
    353}
    354
    355static int lan966x_hwmon_probe(struct platform_device *pdev)
    356{
    357	struct device *dev = &pdev->dev;
    358	struct lan966x_hwmon *hwmon;
    359	struct device *hwmon_dev;
    360	int ret;
    361
    362	hwmon = devm_kzalloc(dev, sizeof(*hwmon), GFP_KERNEL);
    363	if (!hwmon)
    364		return -ENOMEM;
    365
    366	hwmon->clk = devm_clk_get(dev, NULL);
    367	if (IS_ERR(hwmon->clk))
    368		return dev_err_probe(dev, PTR_ERR(hwmon->clk),
    369				     "failed to get clock\n");
    370
    371	ret = lan966x_clk_enable(dev, hwmon);
    372	if (ret)
    373		return dev_err_probe(dev, ret, "failed to enable clock\n");
    374
    375	hwmon->clk_rate = clk_get_rate(hwmon->clk);
    376
    377	hwmon->regmap_pvt = lan966x_init_regmap(pdev, "pvt");
    378	if (IS_ERR(hwmon->regmap_pvt))
    379		return dev_err_probe(dev, PTR_ERR(hwmon->regmap_pvt),
    380				     "failed to get regmap for PVT registers\n");
    381
    382	hwmon->regmap_fan = lan966x_init_regmap(pdev, "fan");
    383	if (IS_ERR(hwmon->regmap_fan))
    384		return dev_err_probe(dev, PTR_ERR(hwmon->regmap_fan),
    385				     "failed to get regmap for fan registers\n");
    386
    387	ret = lan966x_hwmon_enable(dev, hwmon);
    388	if (ret)
    389		return dev_err_probe(dev, ret, "failed to enable sensor\n");
    390
    391	hwmon_dev = devm_hwmon_device_register_with_info(&pdev->dev,
    392				"lan966x_hwmon", hwmon,
    393				&lan966x_hwmon_chip_info, NULL);
    394	if (IS_ERR(hwmon_dev))
    395		return dev_err_probe(dev, PTR_ERR(hwmon_dev),
    396				     "failed to register hwmon device\n");
    397
    398	return 0;
    399}
    400
    401static const struct of_device_id lan966x_hwmon_of_match[] = {
    402	{ .compatible = "microchip,lan9668-hwmon" },
    403	{}
    404};
    405MODULE_DEVICE_TABLE(of, lan966x_hwmon_of_match);
    406
    407static struct platform_driver lan966x_hwmon_driver = {
    408	.probe = lan966x_hwmon_probe,
    409	.driver = {
    410		.name = "lan966x-hwmon",
    411		.of_match_table = lan966x_hwmon_of_match,
    412	},
    413};
    414module_platform_driver(lan966x_hwmon_driver);
    415
    416MODULE_DESCRIPTION("LAN966x Hardware Monitoring Driver");
    417MODULE_AUTHOR("Michael Walle <michael@walle.cc>");
    418MODULE_LICENSE("GPL");