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, ®map_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");