| 1 | |
| 2 | |
| 3 | * emc1403.c - SMSC Thermal Driver
|
| 4 | *
|
| 5 | * Copyright (C) 2008 Intel Corp
|
| 6 | *
|
| 7 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
| 8 | *
|
| 9 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
| 10 |
|
| 11 |
|
| 12 | #include <linux/module.h>
|
| 13 | #include <linux/init.h>
|
| 14 | #include <linux/slab.h>
|
| 15 | #include <linux/i2c.h>
|
| 16 | #include <linux/hwmon.h>
|
| 17 | #include <linux/hwmon-sysfs.h>
|
| 18 | #include <linux/err.h>
|
| 19 | #include <linux/sysfs.h>
|
| 20 | #include <linux/regmap.h>
|
| 21 | #include <linux/regulator/consumer.h>
|
| 22 | #include <linux/util_macros.h>
|
| 23 |
|
| 24 | #define THERMAL_PID_REG 0xfd
|
| 25 | #define THERMAL_SMSC_ID_REG 0xfe
|
| 26 | #define THERMAL_REVISION_REG 0xff
|
| 27 |
|
| 28 | enum emc1403_chip { emc1402, emc1403, emc1404, emc1428 };
|
| 29 |
|
| 30 | struct thermal_data {
|
| 31 | enum emc1403_chip chip;
|
| 32 | struct regmap *regmap;
|
| 33 | };
|
| 34 |
|
| 35 | static ssize_t power_state_show(struct device *dev, struct device_attribute *attr, char *buf)
|
| 36 | {
|
| 37 | struct thermal_data *data = dev_get_drvdata(dev);
|
| 38 | unsigned int val;
|
| 39 | int retval;
|
| 40 |
|
| 41 | retval = regmap_read(data->regmap, 0x03, &val);
|
| 42 | if (retval < 0)
|
| 43 | return retval;
|
| 44 | return sysfs_emit(buf, "%d\n", !!(val & BIT(6)));
|
| 45 | }
|
| 46 |
|
| 47 | static ssize_t power_state_store(struct device *dev, struct device_attribute *attr,
|
| 48 | const char *buf, size_t count)
|
| 49 | {
|
| 50 | struct thermal_data *data = dev_get_drvdata(dev);
|
| 51 | unsigned long val;
|
| 52 | int retval;
|
| 53 |
|
| 54 | if (kstrtoul(buf, 10, &val))
|
| 55 | return -EINVAL;
|
| 56 |
|
| 57 | retval = regmap_update_bits(data->regmap, 0x03, BIT(6),
|
| 58 | val ? BIT(6) : 0);
|
| 59 | if (retval < 0)
|
| 60 | return retval;
|
| 61 | return count;
|
| 62 | }
|
| 63 |
|
| 64 | static DEVICE_ATTR_RW(power_state);
|
| 65 |
|
| 66 | static struct attribute *emc1403_attrs[] = {
|
| 67 | &dev_attr_power_state.attr,
|
| 68 | NULL
|
| 69 | };
|
| 70 | ATTRIBUTE_GROUPS(emc1403);
|
| 71 |
|
| 72 | static int emc1403_detect(struct i2c_client *client,
|
| 73 | struct i2c_board_info *info)
|
| 74 | {
|
| 75 | int id;
|
| 76 |
|
| 77 |
|
| 78 | id = i2c_smbus_read_byte_data(client, THERMAL_SMSC_ID_REG);
|
| 79 | if (id != 0x5d)
|
| 80 | return -ENODEV;
|
| 81 |
|
| 82 | id = i2c_smbus_read_byte_data(client, THERMAL_PID_REG);
|
| 83 | switch (id) {
|
| 84 | case 0x20:
|
| 85 | strscpy(info->type, "emc1402", I2C_NAME_SIZE);
|
| 86 | break;
|
| 87 | case 0x21:
|
| 88 | strscpy(info->type, "emc1403", I2C_NAME_SIZE);
|
| 89 | break;
|
| 90 | case 0x22:
|
| 91 | strscpy(info->type, "emc1422", I2C_NAME_SIZE);
|
| 92 | break;
|
| 93 | case 0x23:
|
| 94 | strscpy(info->type, "emc1423", I2C_NAME_SIZE);
|
| 95 | break;
|
| 96 | case 0x25:
|
| 97 | strscpy(info->type, "emc1404", I2C_NAME_SIZE);
|
| 98 | break;
|
| 99 | case 0x27:
|
| 100 | strscpy(info->type, "emc1424", I2C_NAME_SIZE);
|
| 101 | break;
|
| 102 | case 0x29:
|
| 103 | strscpy(info->type, "emc1428", I2C_NAME_SIZE);
|
| 104 | break;
|
| 105 | case 0x59:
|
| 106 | strscpy(info->type, "emc1438", I2C_NAME_SIZE);
|
| 107 | break;
|
| 108 | case 0x60:
|
| 109 | strscpy(info->type, "emc1442", I2C_NAME_SIZE);
|
| 110 | break;
|
| 111 | default:
|
| 112 | return -ENODEV;
|
| 113 | }
|
| 114 |
|
| 115 | id = i2c_smbus_read_byte_data(client, THERMAL_REVISION_REG);
|
| 116 | if (id < 0x01 || id > 0x04)
|
| 117 | return -ENODEV;
|
| 118 |
|
| 119 | return 0;
|
| 120 | }
|
| 121 |
|
| 122 | static bool emc1403_regmap_is_volatile(struct device *dev, unsigned int reg)
|
| 123 | {
|
| 124 | switch (reg) {
|
| 125 | case 0x00:
|
| 126 | case 0x01:
|
| 127 | case 0x02:
|
| 128 | case 0x10:
|
| 129 | case 0x1b:
|
| 130 | case 0x23:
|
| 131 | case 0x24:
|
| 132 | case 0x29:
|
| 133 | case 0x2a:
|
| 134 | case 0x2b:
|
| 135 | case 0x35:
|
| 136 | case 0x36:
|
| 137 | case 0x37:
|
| 138 | case 0x41:
|
| 139 | case 0x42:
|
| 140 | case 0x43:
|
| 141 | case 0x44:
|
| 142 | case 0x45:
|
| 143 | case 0x46:
|
| 144 | case 0x47:
|
| 145 | case 0x48:
|
| 146 | return true;
|
| 147 | default:
|
| 148 | return false;
|
| 149 | }
|
| 150 | }
|
| 151 |
|
| 152 | static const struct regmap_config emc1403_regmap_config = {
|
| 153 | .reg_bits = 8,
|
| 154 | .val_bits = 8,
|
| 155 | .cache_type = REGCACHE_MAPLE,
|
| 156 | .volatile_reg = emc1403_regmap_is_volatile,
|
| 157 | };
|
| 158 |
|
| 159 | enum emc1403_reg_map {temp_min, temp_max, temp_crit, temp_input};
|
| 160 |
|
| 161 | static u8 ema1403_temp_map[] = {
|
| 162 | [hwmon_temp_min] = temp_min,
|
| 163 | [hwmon_temp_max] = temp_max,
|
| 164 | [hwmon_temp_crit] = temp_crit,
|
| 165 | [hwmon_temp_input] = temp_input,
|
| 166 | };
|
| 167 |
|
| 168 | static u8 emc1403_temp_regs[][4] = {
|
| 169 | [0] = {
|
| 170 | [temp_min] = 0x06,
|
| 171 | [temp_max] = 0x05,
|
| 172 | [temp_crit] = 0x20,
|
| 173 | [temp_input] = 0x00,
|
| 174 | },
|
| 175 | [1] = {
|
| 176 | [temp_min] = 0x08,
|
| 177 | [temp_max] = 0x07,
|
| 178 | [temp_crit] = 0x19,
|
| 179 | [temp_input] = 0x01,
|
| 180 | },
|
| 181 | [2] = {
|
| 182 | [temp_min] = 0x16,
|
| 183 | [temp_max] = 0x15,
|
| 184 | [temp_crit] = 0x1a,
|
| 185 | [temp_input] = 0x23,
|
| 186 | },
|
| 187 | [3] = {
|
| 188 | [temp_min] = 0x2d,
|
| 189 | [temp_max] = 0x2c,
|
| 190 | [temp_crit] = 0x30,
|
| 191 | [temp_input] = 0x2a,
|
| 192 | },
|
| 193 | [4] = {
|
| 194 | [temp_min] = 0x51,
|
| 195 | [temp_max] = 0x50,
|
| 196 | [temp_crit] = 0x64,
|
| 197 | [temp_input] = 0x41,
|
| 198 | },
|
| 199 | [5] = {
|
| 200 | [temp_min] = 0x55,
|
| 201 | [temp_max] = 0x54,
|
| 202 | [temp_crit] = 0x65,
|
| 203 | [temp_input] = 0x43
|
| 204 | },
|
| 205 | [6] = {
|
| 206 | [temp_min] = 0x59,
|
| 207 | [temp_max] = 0x58,
|
| 208 | [temp_crit] = 0x66,
|
| 209 | [temp_input] = 0x45,
|
| 210 | },
|
| 211 | [7] = {
|
| 212 | [temp_min] = 0x5d,
|
| 213 | [temp_max] = 0x5c,
|
| 214 | [temp_crit] = 0x67,
|
| 215 | [temp_input] = 0x47,
|
| 216 | },
|
| 217 | };
|
| 218 |
|
| 219 | static s8 emc1403_temp_regs_low[][4] = {
|
| 220 | [0] = {
|
| 221 | [temp_min] = -1,
|
| 222 | [temp_max] = -1,
|
| 223 | [temp_crit] = -1,
|
| 224 | [temp_input] = 0x29,
|
| 225 | },
|
| 226 | [1] = {
|
| 227 | [temp_min] = 0x14,
|
| 228 | [temp_max] = 0x13,
|
| 229 | [temp_crit] = -1,
|
| 230 | [temp_input] = 0x10,
|
| 231 | },
|
| 232 | [2] = {
|
| 233 | [temp_min] = 0x18,
|
| 234 | [temp_max] = 0x17,
|
| 235 | [temp_crit] = -1,
|
| 236 | [temp_input] = 0x24,
|
| 237 | },
|
| 238 | [3] = {
|
| 239 | [temp_min] = 0x2f,
|
| 240 | [temp_max] = 0x2e,
|
| 241 | [temp_crit] = -1,
|
| 242 | [temp_input] = 0x2b,
|
| 243 | },
|
| 244 | [4] = {
|
| 245 | [temp_min] = 0x53,
|
| 246 | [temp_max] = 0x52,
|
| 247 | [temp_crit] = -1,
|
| 248 | [temp_input] = 0x42,
|
| 249 | },
|
| 250 | [5] = {
|
| 251 | [temp_min] = 0x57,
|
| 252 | [temp_max] = 0x56,
|
| 253 | [temp_crit] = -1,
|
| 254 | [temp_input] = 0x44,
|
| 255 | },
|
| 256 | [6] = {
|
| 257 | [temp_min] = 0x5b,
|
| 258 | [temp_max] = 0x5a,
|
| 259 | [temp_crit] = -1,
|
| 260 | [temp_input] = 0x46,
|
| 261 | },
|
| 262 | [7] = {
|
| 263 | [temp_min] = 0x5f,
|
| 264 | [temp_max] = 0x5e,
|
| 265 | [temp_crit] = -1,
|
| 266 | [temp_input] = 0x48,
|
| 267 | },
|
| 268 | };
|
| 269 |
|
| 270 | static int emc1403_get_temp(struct thermal_data *data, int channel,
|
| 271 | enum emc1403_reg_map map, long *val)
|
| 272 | {
|
| 273 | unsigned int regvalh;
|
| 274 | unsigned int regvall = 0;
|
| 275 | int ret;
|
| 276 | s8 reg;
|
| 277 |
|
| 278 | ret = regmap_read(data->regmap, emc1403_temp_regs[channel][map], ®valh);
|
| 279 | if (ret < 0)
|
| 280 | return ret;
|
| 281 |
|
| 282 | reg = emc1403_temp_regs_low[channel][map];
|
| 283 | if (reg >= 0) {
|
| 284 | ret = regmap_read(data->regmap, reg, ®vall);
|
| 285 | if (ret < 0)
|
| 286 | return ret;
|
| 287 | }
|
| 288 |
|
| 289 | if (data->chip == emc1428)
|
| 290 | *val = sign_extend32((regvalh << 3) | (regvall >> 5), 10) * 125;
|
| 291 | else
|
| 292 | *val = ((regvalh << 3) | (regvall >> 5)) * 125;
|
| 293 |
|
| 294 | return 0;
|
| 295 | }
|
| 296 |
|
| 297 | static int emc1403_get_hyst(struct thermal_data *data, int channel,
|
| 298 | enum emc1403_reg_map map, long *val)
|
| 299 | {
|
| 300 | int hyst, ret;
|
| 301 | long limit;
|
| 302 |
|
| 303 | ret = emc1403_get_temp(data, channel, map, &limit);
|
| 304 | if (ret < 0)
|
| 305 | return ret;
|
| 306 | ret = regmap_read(data->regmap, 0x21, &hyst);
|
| 307 | if (ret < 0)
|
| 308 | return ret;
|
| 309 |
|
| 310 | *val = limit - hyst * 1000;
|
| 311 |
|
| 312 | return 0;
|
| 313 | }
|
| 314 |
|
| 315 | static int emc1403_temp_read(struct thermal_data *data, u32 attr, int channel, long *val)
|
| 316 | {
|
| 317 | unsigned int regval;
|
| 318 | int ret;
|
| 319 |
|
| 320 | switch (attr) {
|
| 321 | case hwmon_temp_min:
|
| 322 | case hwmon_temp_max:
|
| 323 | case hwmon_temp_crit:
|
| 324 | case hwmon_temp_input:
|
| 325 | ret = emc1403_get_temp(data, channel, ema1403_temp_map[attr], val);
|
| 326 | break;
|
| 327 | case hwmon_temp_max_hyst:
|
| 328 | ret = emc1403_get_hyst(data, channel, temp_max, val);
|
| 329 | break;
|
| 330 | case hwmon_temp_crit_hyst:
|
| 331 | ret = emc1403_get_hyst(data, channel, temp_crit, val);
|
| 332 | break;
|
| 333 | case hwmon_temp_min_alarm:
|
| 334 | if (data->chip == emc1402) {
|
| 335 | ret = regmap_read(data->regmap, 0x02, ®val);
|
| 336 | if (ret < 0)
|
| 337 | break;
|
| 338 | *val = !!(regval & BIT(5 - 2 * channel));
|
| 339 | } else {
|
| 340 | ret = regmap_read(data->regmap, 0x36, ®val);
|
| 341 | if (ret < 0)
|
| 342 | break;
|
| 343 | *val = !!(regval & BIT(channel));
|
| 344 | }
|
| 345 | break;
|
| 346 | case hwmon_temp_max_alarm:
|
| 347 | if (data->chip == emc1402) {
|
| 348 | ret = regmap_read(data->regmap, 0x02, ®val);
|
| 349 | if (ret < 0)
|
| 350 | break;
|
| 351 | *val = !!(regval & BIT(6 - 2 * channel));
|
| 352 | } else {
|
| 353 | ret = regmap_read(data->regmap, 0x35, ®val);
|
| 354 | if (ret < 0)
|
| 355 | break;
|
| 356 | *val = !!(regval & BIT(channel));
|
| 357 | }
|
| 358 | break;
|
| 359 | case hwmon_temp_crit_alarm:
|
| 360 | if (data->chip == emc1402) {
|
| 361 | ret = regmap_read(data->regmap, 0x02, ®val);
|
| 362 | if (ret < 0)
|
| 363 | break;
|
| 364 | *val = !!(regval & BIT(channel));
|
| 365 | } else {
|
| 366 | ret = regmap_read(data->regmap, 0x37, ®val);
|
| 367 | if (ret < 0)
|
| 368 | break;
|
| 369 | *val = !!(regval & BIT(channel));
|
| 370 | }
|
| 371 | break;
|
| 372 | case hwmon_temp_fault:
|
| 373 | ret = regmap_read(data->regmap, 0x1b, ®val);
|
| 374 | if (ret < 0)
|
| 375 | break;
|
| 376 | *val = !!(regval & BIT(channel));
|
| 377 | break;
|
| 378 | default:
|
| 379 | return -EOPNOTSUPP;
|
| 380 | }
|
| 381 | return ret;
|
| 382 | }
|
| 383 |
|
| 384 | static int emc1403_get_convrate(struct thermal_data *data, long *val)
|
| 385 | {
|
| 386 | unsigned int convrate;
|
| 387 | int ret;
|
| 388 |
|
| 389 | ret = regmap_read(data->regmap, 0x04, &convrate);
|
| 390 | if (ret < 0)
|
| 391 | return ret;
|
| 392 | if (convrate > 10)
|
| 393 | convrate = 4;
|
| 394 |
|
| 395 | *val = 16000 >> convrate;
|
| 396 | return 0;
|
| 397 | }
|
| 398 |
|
| 399 | static int emc1403_chip_read(struct thermal_data *data, u32 attr, long *val)
|
| 400 | {
|
| 401 | switch (attr) {
|
| 402 | case hwmon_chip_update_interval:
|
| 403 | return emc1403_get_convrate(data, val);
|
| 404 | default:
|
| 405 | return -EOPNOTSUPP;
|
| 406 | }
|
| 407 | }
|
| 408 |
|
| 409 | static int emc1403_read(struct device *dev, enum hwmon_sensor_types type,
|
| 410 | u32 attr, int channel, long *val)
|
| 411 | {
|
| 412 | struct thermal_data *data = dev_get_drvdata(dev);
|
| 413 |
|
| 414 | switch (type) {
|
| 415 | case hwmon_temp:
|
| 416 | return emc1403_temp_read(data, attr, channel, val);
|
| 417 | case hwmon_chip:
|
| 418 | return emc1403_chip_read(data, attr, val);
|
| 419 | default:
|
| 420 | return -EOPNOTSUPP;
|
| 421 | }
|
| 422 | }
|
| 423 |
|
| 424 | static int emc1403_set_hyst(struct thermal_data *data, long val)
|
| 425 | {
|
| 426 | int hyst, ret;
|
| 427 | long limit;
|
| 428 |
|
| 429 | if (data->chip == emc1428)
|
| 430 | val = clamp_val(val, -128000, 127000);
|
| 431 | else
|
| 432 | val = clamp_val(val, 0, 255000);
|
| 433 |
|
| 434 | ret = emc1403_get_temp(data, 0, temp_crit, &limit);
|
| 435 | if (ret < 0)
|
| 436 | return ret;
|
| 437 |
|
| 438 | hyst = limit - val;
|
| 439 | if (data->chip == emc1428)
|
| 440 | hyst = clamp_val(DIV_ROUND_CLOSEST(hyst, 1000), 0, 127);
|
| 441 | else
|
| 442 | hyst = clamp_val(DIV_ROUND_CLOSEST(hyst, 1000), 0, 255);
|
| 443 | return regmap_write(data->regmap, 0x21, hyst);
|
| 444 | }
|
| 445 |
|
| 446 | static int emc1403_set_temp(struct thermal_data *data, int channel,
|
| 447 | enum emc1403_reg_map map, long val)
|
| 448 | {
|
| 449 | unsigned int regval;
|
| 450 | int ret;
|
| 451 | u8 regh;
|
| 452 | s8 regl;
|
| 453 |
|
| 454 | regh = emc1403_temp_regs[channel][map];
|
| 455 | regl = emc1403_temp_regs_low[channel][map];
|
| 456 |
|
| 457 | if (regl >= 0) {
|
| 458 | if (data->chip == emc1428)
|
| 459 | val = clamp_val(val, -128000, 127875);
|
| 460 | else
|
| 461 | val = clamp_val(val, 0, 255875);
|
| 462 | regval = DIV_ROUND_CLOSEST(val, 125);
|
| 463 | ret = regmap_write(data->regmap, regh, (regval >> 3) & 0xff);
|
| 464 | if (ret < 0)
|
| 465 | return ret;
|
| 466 | ret = regmap_write(data->regmap, regl, (regval & 0x07) << 5);
|
| 467 | } else {
|
| 468 | if (data->chip == emc1428)
|
| 469 | val = clamp_val(val, -128000, 127000);
|
| 470 | else
|
| 471 | val = clamp_val(val, 0, 255000);
|
| 472 | regval = DIV_ROUND_CLOSEST(val, 1000);
|
| 473 | ret = regmap_write(data->regmap, regh, regval);
|
| 474 | }
|
| 475 | return ret;
|
| 476 | }
|
| 477 |
|
| 478 | static int emc1403_temp_write(struct thermal_data *data, u32 attr, int channel, long val)
|
| 479 | {
|
| 480 | switch (attr) {
|
| 481 | case hwmon_temp_min:
|
| 482 | case hwmon_temp_max:
|
| 483 | case hwmon_temp_crit:
|
| 484 | return emc1403_set_temp(data, channel, ema1403_temp_map[attr], val);
|
| 485 | case hwmon_temp_crit_hyst:
|
| 486 | return emc1403_set_hyst(data, val);
|
| 487 | default:
|
| 488 | return -EOPNOTSUPP;
|
| 489 | }
|
| 490 | }
|
| 491 |
|
| 492 |
|
| 493 | static const u16 ina3221_conv_time[] = {
|
| 494 | 16000, 8000, 4000, 2000, 1000, 500, 250, 125, 62, 31, 16
|
| 495 | };
|
| 496 |
|
| 497 | static int emc1403_set_convrate(struct thermal_data *data, unsigned int interval)
|
| 498 | {
|
| 499 | int convrate;
|
| 500 |
|
| 501 | convrate = find_closest_descending(interval, ina3221_conv_time,
|
| 502 | ARRAY_SIZE(ina3221_conv_time));
|
| 503 | return regmap_write(data->regmap, 0x04, convrate);
|
| 504 | }
|
| 505 |
|
| 506 | static int emc1403_chip_write(struct thermal_data *data, u32 attr, long val)
|
| 507 | {
|
| 508 | switch (attr) {
|
| 509 | case hwmon_chip_update_interval:
|
| 510 | return emc1403_set_convrate(data, clamp_val(val, 0, 100000));
|
| 511 | default:
|
| 512 | return -EOPNOTSUPP;
|
| 513 | }
|
| 514 | }
|
| 515 |
|
| 516 | static int emc1403_write(struct device *dev, enum hwmon_sensor_types type,
|
| 517 | u32 attr, int channel, long val)
|
| 518 | {
|
| 519 | struct thermal_data *data = dev_get_drvdata(dev);
|
| 520 |
|
| 521 | switch (type) {
|
| 522 | case hwmon_temp:
|
| 523 | return emc1403_temp_write(data, attr, channel, val);
|
| 524 | case hwmon_chip:
|
| 525 | return emc1403_chip_write(data, attr, val);
|
| 526 | default:
|
| 527 | return -EOPNOTSUPP;
|
| 528 | }
|
| 529 | }
|
| 530 |
|
| 531 | static umode_t emc1403_temp_is_visible(const void *_data, u32 attr, int channel)
|
| 532 | {
|
| 533 | const struct thermal_data *data = _data;
|
| 534 |
|
| 535 | if (data->chip == emc1402 && channel > 1)
|
| 536 | return 0;
|
| 537 | if (data->chip == emc1403 && channel > 2)
|
| 538 | return 0;
|
| 539 | if (data->chip != emc1428 && channel > 3)
|
| 540 | return 0;
|
| 541 |
|
| 542 | switch (attr) {
|
| 543 | case hwmon_temp_input:
|
| 544 | case hwmon_temp_min_alarm:
|
| 545 | case hwmon_temp_max_alarm:
|
| 546 | case hwmon_temp_crit_alarm:
|
| 547 | case hwmon_temp_fault:
|
| 548 | case hwmon_temp_max_hyst:
|
| 549 | return 0444;
|
| 550 | case hwmon_temp_min:
|
| 551 | case hwmon_temp_max:
|
| 552 | case hwmon_temp_crit:
|
| 553 | return 0644;
|
| 554 | case hwmon_temp_crit_hyst:
|
| 555 | if (channel == 0)
|
| 556 | return 0644;
|
| 557 | return 0444;
|
| 558 | default:
|
| 559 | return 0;
|
| 560 | }
|
| 561 | }
|
| 562 |
|
| 563 | static umode_t emc1403_chip_is_visible(const void *_data, u32 attr)
|
| 564 | {
|
| 565 | switch (attr) {
|
| 566 | case hwmon_chip_update_interval:
|
| 567 | return 0644;
|
| 568 | default:
|
| 569 | return 0;
|
| 570 | }
|
| 571 | }
|
| 572 |
|
| 573 | static umode_t emc1403_is_visible(const void *data, enum hwmon_sensor_types type,
|
| 574 | u32 attr, int channel)
|
| 575 | {
|
| 576 | switch (type) {
|
| 577 | case hwmon_temp:
|
| 578 | return emc1403_temp_is_visible(data, attr, channel);
|
| 579 | case hwmon_chip:
|
| 580 | return emc1403_chip_is_visible(data, attr);
|
| 581 | default:
|
| 582 | return 0;
|
| 583 | }
|
| 584 | }
|
| 585 |
|
| 586 | static const struct hwmon_channel_info * const emc1403_info[] = {
|
| 587 | HWMON_CHANNEL_INFO(chip, HWMON_C_UPDATE_INTERVAL),
|
| 588 | HWMON_CHANNEL_INFO(temp,
|
| 589 | HWMON_T_INPUT | HWMON_T_MIN | HWMON_T_MAX |
|
| 590 | HWMON_T_CRIT | HWMON_T_MAX_HYST |
|
| 591 | HWMON_T_CRIT_HYST | HWMON_T_MIN_ALARM |
|
| 592 | HWMON_T_MAX_ALARM | HWMON_T_CRIT_ALARM,
|
| 593 | HWMON_T_INPUT | HWMON_T_MIN | HWMON_T_MAX |
|
| 594 | HWMON_T_CRIT | HWMON_T_MAX_HYST |
|
| 595 | HWMON_T_CRIT_HYST | HWMON_T_MIN_ALARM |
|
| 596 | HWMON_T_MAX_ALARM | HWMON_T_CRIT_ALARM | HWMON_T_FAULT,
|
| 597 | HWMON_T_INPUT | HWMON_T_MIN | HWMON_T_MAX |
|
| 598 | HWMON_T_CRIT | HWMON_T_MAX_HYST |
|
| 599 | HWMON_T_CRIT_HYST | HWMON_T_MIN_ALARM |
|
| 600 | HWMON_T_MAX_ALARM | HWMON_T_CRIT_ALARM | HWMON_T_FAULT,
|
| 601 | HWMON_T_INPUT | HWMON_T_MIN | HWMON_T_MAX |
|
| 602 | HWMON_T_CRIT | HWMON_T_MAX_HYST |
|
| 603 | HWMON_T_CRIT_HYST | HWMON_T_MIN_ALARM |
|
| 604 | HWMON_T_MAX_ALARM | HWMON_T_CRIT_ALARM | HWMON_T_FAULT,
|
| 605 | HWMON_T_INPUT | HWMON_T_MIN | HWMON_T_MAX |
|
| 606 | HWMON_T_CRIT | HWMON_T_MAX_HYST |
|
| 607 | HWMON_T_CRIT_HYST | HWMON_T_MIN_ALARM |
|
| 608 | HWMON_T_MAX_ALARM | HWMON_T_CRIT_ALARM | HWMON_T_FAULT,
|
| 609 | HWMON_T_INPUT | HWMON_T_MIN | HWMON_T_MAX |
|
| 610 | HWMON_T_CRIT | HWMON_T_MAX_HYST |
|
| 611 | HWMON_T_CRIT_HYST | HWMON_T_MIN_ALARM |
|
| 612 | HWMON_T_MAX_ALARM | HWMON_T_CRIT_ALARM | HWMON_T_FAULT,
|
| 613 | HWMON_T_INPUT | HWMON_T_MIN | HWMON_T_MAX |
|
| 614 | HWMON_T_CRIT | HWMON_T_MAX_HYST |
|
| 615 | HWMON_T_CRIT_HYST | HWMON_T_MIN_ALARM |
|
| 616 | HWMON_T_MAX_ALARM | HWMON_T_CRIT_ALARM | HWMON_T_FAULT,
|
| 617 | HWMON_T_INPUT | HWMON_T_MIN | HWMON_T_MAX |
|
| 618 | HWMON_T_CRIT | HWMON_T_MAX_HYST |
|
| 619 | HWMON_T_CRIT_HYST | HWMON_T_MIN_ALARM |
|
| 620 | HWMON_T_MAX_ALARM | HWMON_T_CRIT_ALARM | HWMON_T_FAULT
|
| 621 | ),
|
| 622 | NULL
|
| 623 | };
|
| 624 |
|
| 625 | static const struct hwmon_ops emc1403_hwmon_ops = {
|
| 626 | .is_visible = emc1403_is_visible,
|
| 627 | .read = emc1403_read,
|
| 628 | .write = emc1403_write,
|
| 629 | };
|
| 630 |
|
| 631 | static const struct hwmon_chip_info emc1403_chip_info = {
|
| 632 | .ops = &emc1403_hwmon_ops,
|
| 633 | .info = emc1403_info,
|
| 634 | };
|
| 635 |
|
| 636 |
|
| 637 | static const struct i2c_device_id emc1403_idtable[] = {
|
| 638 | { .name = "emc1402", .driver_data = emc1402 },
|
| 639 | { .name = "emc1403", .driver_data = emc1403 },
|
| 640 | { .name = "emc1404", .driver_data = emc1404 },
|
| 641 | { .name = "emc1412", .driver_data = emc1402 },
|
| 642 | { .name = "emc1413", .driver_data = emc1403 },
|
| 643 | { .name = "emc1414", .driver_data = emc1404 },
|
| 644 | { .name = "emc1422", .driver_data = emc1402 },
|
| 645 | { .name = "emc1423", .driver_data = emc1403 },
|
| 646 | { .name = "emc1424", .driver_data = emc1404 },
|
| 647 | { .name = "emc1428", .driver_data = emc1428 },
|
| 648 | { .name = "emc1438", .driver_data = emc1428 },
|
| 649 | { .name = "emc1442", .driver_data = emc1402 },
|
| 650 | { }
|
| 651 | };
|
| 652 | MODULE_DEVICE_TABLE(i2c, emc1403_idtable);
|
| 653 |
|
| 654 | static int emc1403_probe(struct i2c_client *client)
|
| 655 | {
|
| 656 | struct thermal_data *data;
|
| 657 | struct device *hwmon_dev;
|
| 658 | int ret;
|
| 659 |
|
| 660 | ret = devm_regulator_get_enable(&client->dev, "vdd");
|
| 661 | if (ret)
|
| 662 | return dev_err_probe(&client->dev, ret,
|
| 663 | "Failed to enable regulator\n");
|
| 664 |
|
| 665 | data = devm_kzalloc(&client->dev, sizeof(struct thermal_data),
|
| 666 | GFP_KERNEL);
|
| 667 | if (!data)
|
| 668 | return -ENOMEM;
|
| 669 |
|
| 670 | data->chip = (uintptr_t)i2c_get_match_data(client);
|
| 671 |
|
| 672 | data->regmap = devm_regmap_init_i2c(client, &emc1403_regmap_config);
|
| 673 | if (IS_ERR(data->regmap))
|
| 674 | return PTR_ERR(data->regmap);
|
| 675 |
|
| 676 | hwmon_dev = devm_hwmon_device_register_with_info(&client->dev,
|
| 677 | client->name, data,
|
| 678 | &emc1403_chip_info,
|
| 679 | emc1403_groups);
|
| 680 | return PTR_ERR_OR_ZERO(hwmon_dev);
|
| 681 | }
|
| 682 |
|
| 683 | static const unsigned short emc1403_address_list[] = {
|
| 684 | 0x18, 0x1c, 0x29, 0x3c, 0x4c, 0x4d, 0x5c, I2C_CLIENT_END
|
| 685 | };
|
| 686 |
|
| 687 | static const struct of_device_id emc1403_of_match[] = {
|
| 688 | { .compatible = "smsc,emc1402", .data = (void *)emc1402 },
|
| 689 | { .compatible = "smsc,emc1403", .data = (void *)emc1403 },
|
| 690 | { .compatible = "smsc,emc1404", .data = (void *)emc1404 },
|
| 691 | { .compatible = "smsc,emc1428", .data = (void *)emc1428 },
|
| 692 | { }
|
| 693 | };
|
| 694 | MODULE_DEVICE_TABLE(of, emc1403_of_match);
|
| 695 |
|
| 696 | static struct i2c_driver sensor_emc1403 = {
|
| 697 | .class = I2C_CLASS_HWMON,
|
| 698 | .driver = {
|
| 699 | .name = "emc1403",
|
| 700 | .of_match_table = emc1403_of_match,
|
| 701 | },
|
| 702 | .detect = emc1403_detect,
|
| 703 | .probe = emc1403_probe,
|
| 704 | .id_table = emc1403_idtable,
|
| 705 | .address_list = emc1403_address_list,
|
| 706 | };
|
| 707 |
|
| 708 | module_i2c_driver(sensor_emc1403);
|
| 709 |
|
| 710 | MODULE_AUTHOR("Kalhan Trisal <[email protected]");
|
| 711 | MODULE_DESCRIPTION("emc1403 Thermal Driver");
|
| 712 | MODULE_LICENSE("GPL v2");
|