^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0-or-later
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * nct6683 - Driver for the hardware monitoring functionality of
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) * Nuvoton NCT6683D eSIO
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) * Copyright (C) 2013 Guenter Roeck <linux@roeck-us.net>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) * Derived from nct6775 driver
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) * Copyright (C) 2012, 2013 Guenter Roeck <linux@roeck-us.net>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) * Supports the following chips:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) * Chip #vin #fan #pwm #temp chip ID
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) * nct6683d 21(1) 16 8 32(1) 0xc730
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) * Notes:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) * (1) Total number of vin and temp inputs is 32.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) #include <linux/acpi.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) #include <linux/delay.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) #include <linux/err.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) #include <linux/init.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) #include <linux/io.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) #include <linux/jiffies.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) #include <linux/hwmon.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) #include <linux/hwmon-sysfs.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) #include <linux/mutex.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) #include <linux/platform_device.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) #include <linux/slab.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) enum kinds { nct6683 };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) static bool force;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) module_param(force, bool, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) MODULE_PARM_DESC(force, "Set to one to enable support for unknown vendors");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) static const char * const nct6683_device_names[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) "nct6683",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) static const char * const nct6683_chip_names[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) "NCT6683D",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) #define DRVNAME "nct6683"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) * Super-I/O constants and functions
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) #define NCT6683_LD_ACPI 0x0a
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) #define NCT6683_LD_HWM 0x0b
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) #define NCT6683_LD_VID 0x0d
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) #define SIO_REG_LDSEL 0x07 /* Logical device select */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) #define SIO_REG_DEVID 0x20 /* Device ID (2 bytes) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) #define SIO_REG_ENABLE 0x30 /* Logical device enable */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) #define SIO_REG_ADDR 0x60 /* Logical device address (2 bytes) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) #define SIO_NCT6681_ID 0xb270 /* for later */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) #define SIO_NCT6683_ID 0xc730
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) #define SIO_ID_MASK 0xFFF0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) static inline void
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) superio_outb(int ioreg, int reg, int val)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) outb(reg, ioreg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) outb(val, ioreg + 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) static inline int
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) superio_inb(int ioreg, int reg)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) outb(reg, ioreg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) return inb(ioreg + 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) static inline void
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) superio_select(int ioreg, int ld)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) outb(SIO_REG_LDSEL, ioreg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) outb(ld, ioreg + 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) static inline int
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) superio_enter(int ioreg)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) * Try to reserve <ioreg> and <ioreg + 1> for exclusive access.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) if (!request_muxed_region(ioreg, 2, DRVNAME))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) return -EBUSY;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) outb(0x87, ioreg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) outb(0x87, ioreg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) static inline void
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) superio_exit(int ioreg)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) outb(0xaa, ioreg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) outb(0x02, ioreg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) outb(0x02, ioreg + 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) release_region(ioreg, 2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) * ISA constants
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) #define IOREGION_ALIGNMENT (~7)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) #define IOREGION_OFFSET 4 /* Use EC port 1 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) #define IOREGION_LENGTH 4
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) #define EC_PAGE_REG 0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) #define EC_INDEX_REG 1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) #define EC_DATA_REG 2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) #define EC_EVENT_REG 3
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) /* Common and NCT6683 specific data */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) #define NCT6683_NUM_REG_MON 32
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) #define NCT6683_NUM_REG_FAN 16
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) #define NCT6683_NUM_REG_PWM 8
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) #define NCT6683_REG_MON(x) (0x100 + (x) * 2)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) #define NCT6683_REG_FAN_RPM(x) (0x140 + (x) * 2)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) #define NCT6683_REG_PWM(x) (0x160 + (x))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) #define NCT6683_REG_PWM_WRITE(x) (0xa28 + (x))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) #define NCT6683_REG_MON_STS(x) (0x174 + (x))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) #define NCT6683_REG_IDLE(x) (0x178 + (x))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) #define NCT6683_REG_FAN_STS(x) (0x17c + (x))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) #define NCT6683_REG_FAN_ERRSTS 0x17e
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) #define NCT6683_REG_FAN_INITSTS 0x17f
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) #define NCT6683_HWM_CFG 0x180
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) #define NCT6683_REG_MON_CFG(x) (0x1a0 + (x))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) #define NCT6683_REG_FANIN_CFG(x) (0x1c0 + (x))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) #define NCT6683_REG_FANOUT_CFG(x) (0x1d0 + (x))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) #define NCT6683_REG_INTEL_TEMP_MAX(x) (0x901 + (x) * 16)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) #define NCT6683_REG_INTEL_TEMP_CRIT(x) (0x90d + (x) * 16)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) #define NCT6683_REG_TEMP_HYST(x) (0x330 + (x)) /* 8 bit */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) #define NCT6683_REG_TEMP_MAX(x) (0x350 + (x)) /* 8 bit */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) #define NCT6683_REG_MON_HIGH(x) (0x370 + (x) * 2) /* 8 bit */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) #define NCT6683_REG_MON_LOW(x) (0x371 + (x) * 2) /* 8 bit */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) #define NCT6683_REG_FAN_MIN(x) (0x3b8 + (x) * 2) /* 16 bit */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) #define NCT6683_REG_FAN_CFG_CTRL 0xa01
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) #define NCT6683_FAN_CFG_REQ 0x80
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) #define NCT6683_FAN_CFG_DONE 0x40
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) #define NCT6683_REG_CUSTOMER_ID 0x602
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) #define NCT6683_CUSTOMER_ID_INTEL 0x805
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) #define NCT6683_CUSTOMER_ID_MITAC 0xa0e
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) #define NCT6683_REG_BUILD_YEAR 0x604
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) #define NCT6683_REG_BUILD_MONTH 0x605
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) #define NCT6683_REG_BUILD_DAY 0x606
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) #define NCT6683_REG_SERIAL 0x607
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) #define NCT6683_REG_VERSION_HI 0x608
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) #define NCT6683_REG_VERSION_LO 0x609
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) #define NCT6683_REG_CR_CASEOPEN 0xe8
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) #define NCT6683_CR_CASEOPEN_MASK (1 << 7)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) #define NCT6683_REG_CR_BEEP 0xe0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) #define NCT6683_CR_BEEP_MASK (1 << 6)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) static const char *const nct6683_mon_label[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) NULL, /* disabled */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) "Local",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) "Diode 0 (curr)",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) "Diode 1 (curr)",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) "Diode 2 (curr)",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) "Diode 0 (volt)",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) "Diode 1 (volt)",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) "Diode 2 (volt)",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) "Thermistor 14",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) "Thermistor 15",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) "Thermistor 16",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) "Thermistor 0",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) "Thermistor 1",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) "Thermistor 2",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) "Thermistor 3",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) "Thermistor 4",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) "Thermistor 5", /* 0x10 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) "Thermistor 6",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) "Thermistor 7",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) "Thermistor 8",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) "Thermistor 9",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) "Thermistor 10",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) "Thermistor 11",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) "Thermistor 12",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) "Thermistor 13",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) NULL, NULL, NULL, NULL, NULL, NULL, NULL,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) "PECI 0.0", /* 0x20 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) "PECI 1.0",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) "PECI 2.0",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) "PECI 3.0",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) "PECI 0.1",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) "PECI 1.1",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) "PECI 2.1",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) "PECI 3.1",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) "PECI DIMM 0",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) "PECI DIMM 1",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) "PECI DIMM 2",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) "PECI DIMM 3",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) NULL, NULL, NULL, NULL,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) "PCH CPU", /* 0x30 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) "PCH CHIP",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) "PCH CHIP CPU MAX",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) "PCH MCH",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) "PCH DIMM 0",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) "PCH DIMM 1",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) "PCH DIMM 2",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) "PCH DIMM 3",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) "SMBus 0",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) "SMBus 1",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) "SMBus 2",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) "SMBus 3",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) "SMBus 4",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) "SMBus 5",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) "DIMM 0",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) "DIMM 1",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237) "DIMM 2", /* 0x40 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) "DIMM 3",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) "AMD TSI Addr 90h",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) "AMD TSI Addr 92h",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) "AMD TSI Addr 94h",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) "AMD TSI Addr 96h",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) "AMD TSI Addr 98h",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) "AMD TSI Addr 9ah",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) "AMD TSI Addr 9ch",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246) "AMD TSI Addr 9dh",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) NULL, NULL, NULL, NULL, NULL, NULL,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) "Virtual 0", /* 0x50 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249) "Virtual 1",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) "Virtual 2",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) "Virtual 3",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) "Virtual 4",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253) "Virtual 5",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) "Virtual 6",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) "Virtual 7",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257) "VCC", /* 0x60 voltage sensors */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) "VSB",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259) "AVSB",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260) "VTT",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) "VBAT",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262) "VREF",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) "VIN0",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264) "VIN1",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) "VIN2",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266) "VIN3",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267) "VIN4",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268) "VIN5",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269) "VIN6",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270) "VIN7",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) "VIN8",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272) "VIN9",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273) "VIN10",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274) "VIN11",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275) "VIN12",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276) "VIN13",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277) "VIN14",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278) "VIN15",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279) "VIN16",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282) #define NUM_MON_LABELS ARRAY_SIZE(nct6683_mon_label)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283) #define MON_VOLTAGE_START 0x60
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285) /* ------------------------------------------------------- */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287) struct nct6683_data {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288) int addr; /* IO base of EC space */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289) int sioreg; /* SIO register */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290) enum kinds kind;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291) u16 customer_id;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293) struct device *hwmon_dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294) const struct attribute_group *groups[6];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296) int temp_num; /* number of temperature attributes */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297) u8 temp_index[NCT6683_NUM_REG_MON];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298) u8 temp_src[NCT6683_NUM_REG_MON];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300) u8 in_num; /* number of voltage attributes */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301) u8 in_index[NCT6683_NUM_REG_MON];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302) u8 in_src[NCT6683_NUM_REG_MON];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304) struct mutex update_lock; /* used to protect sensor updates */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305) bool valid; /* true if following fields are valid */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306) unsigned long last_updated; /* In jiffies */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308) /* Voltage attribute values */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309) u8 in[3][NCT6683_NUM_REG_MON]; /* [0]=in, [1]=in_max, [2]=in_min */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311) /* Temperature attribute values */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312) s16 temp_in[NCT6683_NUM_REG_MON];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313) s8 temp[4][NCT6683_NUM_REG_MON];/* [0]=min, [1]=max, [2]=hyst,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314) * [3]=crit
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317) /* Fan attribute values */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318) unsigned int rpm[NCT6683_NUM_REG_FAN];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319) u16 fan_min[NCT6683_NUM_REG_FAN];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320) u8 fanin_cfg[NCT6683_NUM_REG_FAN];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321) u8 fanout_cfg[NCT6683_NUM_REG_FAN];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322) u16 have_fan; /* some fan inputs can be disabled */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324) u8 have_pwm;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325) u8 pwm[NCT6683_NUM_REG_PWM];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 327) #ifdef CONFIG_PM
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 328) /* Remember extra register values over suspend/resume */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 329) u8 hwm_cfg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 330) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 331) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 332)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 333) struct nct6683_sio_data {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 334) int sioreg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 335) enum kinds kind;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 336) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 337)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 338) struct sensor_device_template {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 339) struct device_attribute dev_attr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 340) union {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 341) struct {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 342) u8 nr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 343) u8 index;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 344) } s;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 345) int index;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 346) } u;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 347) bool s2; /* true if both index and nr are used */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 348) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 349)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 350) struct sensor_device_attr_u {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 351) union {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 352) struct sensor_device_attribute a1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 353) struct sensor_device_attribute_2 a2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 354) } u;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 355) char name[32];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 356) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 357)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 358) #define __TEMPLATE_ATTR(_template, _mode, _show, _store) { \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 359) .attr = {.name = _template, .mode = _mode }, \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 360) .show = _show, \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 361) .store = _store, \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 362) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 363)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 364) #define SENSOR_DEVICE_TEMPLATE(_template, _mode, _show, _store, _index) \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 365) { .dev_attr = __TEMPLATE_ATTR(_template, _mode, _show, _store), \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 366) .u.index = _index, \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 367) .s2 = false }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 368)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 369) #define SENSOR_DEVICE_TEMPLATE_2(_template, _mode, _show, _store, \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 370) _nr, _index) \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 371) { .dev_attr = __TEMPLATE_ATTR(_template, _mode, _show, _store), \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 372) .u.s.index = _index, \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 373) .u.s.nr = _nr, \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 374) .s2 = true }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 375)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 376) #define SENSOR_TEMPLATE(_name, _template, _mode, _show, _store, _index) \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 377) static struct sensor_device_template sensor_dev_template_##_name \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 378) = SENSOR_DEVICE_TEMPLATE(_template, _mode, _show, _store, \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 379) _index)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 380)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 381) #define SENSOR_TEMPLATE_2(_name, _template, _mode, _show, _store, \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 382) _nr, _index) \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 383) static struct sensor_device_template sensor_dev_template_##_name \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 384) = SENSOR_DEVICE_TEMPLATE_2(_template, _mode, _show, _store, \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 385) _nr, _index)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 386)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 387) struct sensor_template_group {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 388) struct sensor_device_template **templates;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 389) umode_t (*is_visible)(struct kobject *, struct attribute *, int);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 390) int base;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 391) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 392)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 393) static struct attribute_group *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 394) nct6683_create_attr_group(struct device *dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 395) const struct sensor_template_group *tg,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 396) int repeat)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 397) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 398) struct sensor_device_attribute_2 *a2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 399) struct sensor_device_attribute *a;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 400) struct sensor_device_template **t;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 401) struct sensor_device_attr_u *su;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 402) struct attribute_group *group;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 403) struct attribute **attrs;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 404) int i, j, count;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 405)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 406) if (repeat <= 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 407) return ERR_PTR(-EINVAL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 408)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 409) t = tg->templates;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 410) for (count = 0; *t; t++, count++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 411) ;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 412)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 413) if (count == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 414) return ERR_PTR(-EINVAL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 415)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 416) group = devm_kzalloc(dev, sizeof(*group), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 417) if (group == NULL)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 418) return ERR_PTR(-ENOMEM);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 419)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 420) attrs = devm_kcalloc(dev, repeat * count + 1, sizeof(*attrs),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 421) GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 422) if (attrs == NULL)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 423) return ERR_PTR(-ENOMEM);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 424)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 425) su = devm_kzalloc(dev, array3_size(repeat, count, sizeof(*su)),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 426) GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 427) if (su == NULL)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 428) return ERR_PTR(-ENOMEM);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 429)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 430) group->attrs = attrs;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 431) group->is_visible = tg->is_visible;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 432)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 433) for (i = 0; i < repeat; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 434) t = tg->templates;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 435) for (j = 0; *t != NULL; j++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 436) snprintf(su->name, sizeof(su->name),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 437) (*t)->dev_attr.attr.name, tg->base + i);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 438) if ((*t)->s2) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 439) a2 = &su->u.a2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 440) sysfs_attr_init(&a2->dev_attr.attr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 441) a2->dev_attr.attr.name = su->name;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 442) a2->nr = (*t)->u.s.nr + i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 443) a2->index = (*t)->u.s.index;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 444) a2->dev_attr.attr.mode =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 445) (*t)->dev_attr.attr.mode;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 446) a2->dev_attr.show = (*t)->dev_attr.show;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 447) a2->dev_attr.store = (*t)->dev_attr.store;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 448) *attrs = &a2->dev_attr.attr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 449) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 450) a = &su->u.a1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 451) sysfs_attr_init(&a->dev_attr.attr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 452) a->dev_attr.attr.name = su->name;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 453) a->index = (*t)->u.index + i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 454) a->dev_attr.attr.mode =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 455) (*t)->dev_attr.attr.mode;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 456) a->dev_attr.show = (*t)->dev_attr.show;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 457) a->dev_attr.store = (*t)->dev_attr.store;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 458) *attrs = &a->dev_attr.attr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 459) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 460) attrs++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 461) su++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 462) t++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 463) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 464) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 465)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 466) return group;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 467) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 468)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 469) /* LSB is 16 mV, except for the following sources, where it is 32 mV */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 470) #define MON_SRC_VCC 0x60
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 471) #define MON_SRC_VSB 0x61
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 472) #define MON_SRC_AVSB 0x62
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 473) #define MON_SRC_VBAT 0x64
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 474)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 475) static inline long in_from_reg(u16 reg, u8 src)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 476) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 477) int scale = 16;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 478)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 479) if (src == MON_SRC_VCC || src == MON_SRC_VSB || src == MON_SRC_AVSB ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 480) src == MON_SRC_VBAT)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 481) scale <<= 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 482) return reg * scale;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 483) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 484)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 485) static inline u16 in_to_reg(u32 val, u8 src)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 486) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 487) int scale = 16;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 488)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 489) if (src == MON_SRC_VCC || src == MON_SRC_VSB || src == MON_SRC_AVSB ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 490) src == MON_SRC_VBAT)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 491) scale <<= 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 492)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 493) return clamp_val(DIV_ROUND_CLOSEST(val, scale), 0, 127);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 494) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 495)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 496) static u16 nct6683_read(struct nct6683_data *data, u16 reg)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 497) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 498) int res;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 499)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 500) outb_p(0xff, data->addr + EC_PAGE_REG); /* unlock */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 501) outb_p(reg >> 8, data->addr + EC_PAGE_REG);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 502) outb_p(reg & 0xff, data->addr + EC_INDEX_REG);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 503) res = inb_p(data->addr + EC_DATA_REG);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 504) return res;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 505) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 506)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 507) static u16 nct6683_read16(struct nct6683_data *data, u16 reg)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 508) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 509) return (nct6683_read(data, reg) << 8) | nct6683_read(data, reg + 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 510) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 511)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 512) static void nct6683_write(struct nct6683_data *data, u16 reg, u16 value)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 513) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 514) outb_p(0xff, data->addr + EC_PAGE_REG); /* unlock */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 515) outb_p(reg >> 8, data->addr + EC_PAGE_REG);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 516) outb_p(reg & 0xff, data->addr + EC_INDEX_REG);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 517) outb_p(value & 0xff, data->addr + EC_DATA_REG);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 518) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 519)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 520) static int get_in_reg(struct nct6683_data *data, int nr, int index)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 521) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 522) int ch = data->in_index[index];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 523) int reg = -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 524)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 525) switch (nr) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 526) case 0:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 527) reg = NCT6683_REG_MON(ch);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 528) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 529) case 1:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 530) if (data->customer_id != NCT6683_CUSTOMER_ID_INTEL)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 531) reg = NCT6683_REG_MON_LOW(ch);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 532) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 533) case 2:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 534) if (data->customer_id != NCT6683_CUSTOMER_ID_INTEL)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 535) reg = NCT6683_REG_MON_HIGH(ch);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 536) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 537) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 538) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 539) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 540) return reg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 541) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 542)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 543) static int get_temp_reg(struct nct6683_data *data, int nr, int index)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 544) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 545) int ch = data->temp_index[index];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 546) int reg = -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 547)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 548) switch (data->customer_id) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 549) case NCT6683_CUSTOMER_ID_INTEL:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 550) switch (nr) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 551) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 552) case 1: /* max */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 553) reg = NCT6683_REG_INTEL_TEMP_MAX(ch);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 554) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 555) case 3: /* crit */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 556) reg = NCT6683_REG_INTEL_TEMP_CRIT(ch);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 557) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 558) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 559) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 560) case NCT6683_CUSTOMER_ID_MITAC:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 561) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 562) switch (nr) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 563) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 564) case 0: /* min */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 565) reg = NCT6683_REG_MON_LOW(ch);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 566) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 567) case 1: /* max */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 568) reg = NCT6683_REG_TEMP_MAX(ch);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 569) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 570) case 2: /* hyst */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 571) reg = NCT6683_REG_TEMP_HYST(ch);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 572) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 573) case 3: /* crit */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 574) reg = NCT6683_REG_MON_HIGH(ch);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 575) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 576) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 577) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 578) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 579) return reg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 580) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 581)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 582) static void nct6683_update_pwm(struct device *dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 583) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 584) struct nct6683_data *data = dev_get_drvdata(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 585) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 586)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 587) for (i = 0; i < NCT6683_NUM_REG_PWM; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 588) if (!(data->have_pwm & (1 << i)))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 589) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 590) data->pwm[i] = nct6683_read(data, NCT6683_REG_PWM(i));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 591) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 592) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 593)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 594) static struct nct6683_data *nct6683_update_device(struct device *dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 595) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 596) struct nct6683_data *data = dev_get_drvdata(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 597) int i, j;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 598)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 599) mutex_lock(&data->update_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 600)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 601) if (time_after(jiffies, data->last_updated + HZ) || !data->valid) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 602) /* Measured voltages and limits */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 603) for (i = 0; i < data->in_num; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 604) for (j = 0; j < 3; j++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 605) int reg = get_in_reg(data, j, i);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 606)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 607) if (reg >= 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 608) data->in[j][i] =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 609) nct6683_read(data, reg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 610) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 611) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 612)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 613) /* Measured temperatures and limits */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 614) for (i = 0; i < data->temp_num; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 615) u8 ch = data->temp_index[i];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 616)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 617) data->temp_in[i] = nct6683_read16(data,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 618) NCT6683_REG_MON(ch));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 619) for (j = 0; j < 4; j++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 620) int reg = get_temp_reg(data, j, i);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 621)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 622) if (reg >= 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 623) data->temp[j][i] =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 624) nct6683_read(data, reg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 625) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 626) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 627)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 628) /* Measured fan speeds and limits */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 629) for (i = 0; i < ARRAY_SIZE(data->rpm); i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 630) if (!(data->have_fan & (1 << i)))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 631) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 632)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 633) data->rpm[i] = nct6683_read16(data,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 634) NCT6683_REG_FAN_RPM(i));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 635) data->fan_min[i] = nct6683_read16(data,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 636) NCT6683_REG_FAN_MIN(i));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 637) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 638)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 639) nct6683_update_pwm(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 640)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 641) data->last_updated = jiffies;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 642) data->valid = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 643) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 644)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 645) mutex_unlock(&data->update_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 646) return data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 647) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 648)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 649) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 650) * Sysfs callback functions
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 651) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 652) static ssize_t
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 653) show_in_label(struct device *dev, struct device_attribute *attr, char *buf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 654) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 655) struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 656) struct nct6683_data *data = nct6683_update_device(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 657) int nr = sattr->index;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 658)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 659) return sprintf(buf, "%s\n", nct6683_mon_label[data->in_src[nr]]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 660) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 661)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 662) static ssize_t
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 663) show_in_reg(struct device *dev, struct device_attribute *attr, char *buf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 664) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 665) struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 666) struct nct6683_data *data = nct6683_update_device(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 667) int index = sattr->index;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 668) int nr = sattr->nr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 669)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 670) return sprintf(buf, "%ld\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 671) in_from_reg(data->in[index][nr], data->in_index[index]));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 672) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 673)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 674) static umode_t nct6683_in_is_visible(struct kobject *kobj,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 675) struct attribute *attr, int index)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 676) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 677) struct device *dev = kobj_to_dev(kobj);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 678) struct nct6683_data *data = dev_get_drvdata(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 679) int nr = index % 4; /* attribute */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 680)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 681) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 682) * Voltage limits exist for Intel boards,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 683) * but register location and encoding is unknown
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 684) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 685) if ((nr == 2 || nr == 3) &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 686) data->customer_id == NCT6683_CUSTOMER_ID_INTEL)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 687) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 688)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 689) return attr->mode;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 690) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 691)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 692) SENSOR_TEMPLATE(in_label, "in%d_label", S_IRUGO, show_in_label, NULL, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 693) SENSOR_TEMPLATE_2(in_input, "in%d_input", S_IRUGO, show_in_reg, NULL, 0, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 694) SENSOR_TEMPLATE_2(in_min, "in%d_min", S_IRUGO, show_in_reg, NULL, 0, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 695) SENSOR_TEMPLATE_2(in_max, "in%d_max", S_IRUGO, show_in_reg, NULL, 0, 2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 696)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 697) static struct sensor_device_template *nct6683_attributes_in_template[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 698) &sensor_dev_template_in_label,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 699) &sensor_dev_template_in_input,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 700) &sensor_dev_template_in_min,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 701) &sensor_dev_template_in_max,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 702) NULL
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 703) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 704)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 705) static const struct sensor_template_group nct6683_in_template_group = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 706) .templates = nct6683_attributes_in_template,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 707) .is_visible = nct6683_in_is_visible,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 708) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 709)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 710) static ssize_t
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 711) show_fan(struct device *dev, struct device_attribute *attr, char *buf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 712) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 713) struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 714) struct nct6683_data *data = nct6683_update_device(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 715)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 716) return sprintf(buf, "%d\n", data->rpm[sattr->index]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 717) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 718)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 719) static ssize_t
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 720) show_fan_min(struct device *dev, struct device_attribute *attr, char *buf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 721) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 722) struct nct6683_data *data = nct6683_update_device(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 723) struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 724) int nr = sattr->index;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 725)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 726) return sprintf(buf, "%d\n", data->fan_min[nr]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 727) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 728)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 729) static ssize_t
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 730) show_fan_pulses(struct device *dev, struct device_attribute *attr, char *buf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 731) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 732) struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 733) struct nct6683_data *data = nct6683_update_device(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 734)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 735) return sprintf(buf, "%d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 736) ((data->fanin_cfg[sattr->index] >> 5) & 0x03) + 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 737) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 738)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 739) static umode_t nct6683_fan_is_visible(struct kobject *kobj,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 740) struct attribute *attr, int index)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 741) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 742) struct device *dev = kobj_to_dev(kobj);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 743) struct nct6683_data *data = dev_get_drvdata(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 744) int fan = index / 3; /* fan index */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 745) int nr = index % 3; /* attribute index */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 746)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 747) if (!(data->have_fan & (1 << fan)))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 748) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 749)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 750) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 751) * Intel may have minimum fan speed limits,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 752) * but register location and encoding are unknown.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 753) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 754) if (nr == 2 && data->customer_id == NCT6683_CUSTOMER_ID_INTEL)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 755) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 756)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 757) return attr->mode;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 758) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 759)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 760) SENSOR_TEMPLATE(fan_input, "fan%d_input", S_IRUGO, show_fan, NULL, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 761) SENSOR_TEMPLATE(fan_pulses, "fan%d_pulses", S_IRUGO, show_fan_pulses, NULL, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 762) SENSOR_TEMPLATE(fan_min, "fan%d_min", S_IRUGO, show_fan_min, NULL, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 763)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 764) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 765) * nct6683_fan_is_visible uses the index into the following array
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 766) * to determine if attributes should be created or not.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 767) * Any change in order or content must be matched.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 768) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 769) static struct sensor_device_template *nct6683_attributes_fan_template[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 770) &sensor_dev_template_fan_input,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 771) &sensor_dev_template_fan_pulses,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 772) &sensor_dev_template_fan_min,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 773) NULL
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 774) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 775)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 776) static const struct sensor_template_group nct6683_fan_template_group = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 777) .templates = nct6683_attributes_fan_template,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 778) .is_visible = nct6683_fan_is_visible,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 779) .base = 1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 780) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 781)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 782) static ssize_t
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 783) show_temp_label(struct device *dev, struct device_attribute *attr, char *buf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 784) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 785) struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 786) struct nct6683_data *data = nct6683_update_device(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 787) int nr = sattr->index;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 788)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 789) return sprintf(buf, "%s\n", nct6683_mon_label[data->temp_src[nr]]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 790) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 791)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 792) static ssize_t
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 793) show_temp8(struct device *dev, struct device_attribute *attr, char *buf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 794) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 795) struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 796) struct nct6683_data *data = nct6683_update_device(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 797) int index = sattr->index;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 798) int nr = sattr->nr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 799)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 800) return sprintf(buf, "%d\n", data->temp[index][nr] * 1000);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 801) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 802)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 803) static ssize_t
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 804) show_temp_hyst(struct device *dev, struct device_attribute *attr, char *buf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 805) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 806) struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 807) struct nct6683_data *data = nct6683_update_device(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 808) int nr = sattr->index;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 809) int temp = data->temp[1][nr] - data->temp[2][nr];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 810)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 811) return sprintf(buf, "%d\n", temp * 1000);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 812) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 813)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 814) static ssize_t
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 815) show_temp16(struct device *dev, struct device_attribute *attr, char *buf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 816) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 817) struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 818) struct nct6683_data *data = nct6683_update_device(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 819) int index = sattr->index;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 820)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 821) return sprintf(buf, "%d\n", (data->temp_in[index] / 128) * 500);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 822) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 823)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 824) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 825) * Temperature sensor type is determined by temperature source
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 826) * and can not be modified.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 827) * 0x02..0x07: Thermal diode
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 828) * 0x08..0x18: Thermistor
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 829) * 0x20..0x2b: Intel PECI
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 830) * 0x42..0x49: AMD TSI
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 831) * Others are unspecified (not visible)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 832) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 833)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 834) static int get_temp_type(u8 src)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 835) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 836) if (src >= 0x02 && src <= 0x07)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 837) return 3; /* thermal diode */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 838) else if (src >= 0x08 && src <= 0x18)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 839) return 4; /* thermistor */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 840) else if (src >= 0x20 && src <= 0x2b)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 841) return 6; /* PECI */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 842) else if (src >= 0x42 && src <= 0x49)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 843) return 5;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 844)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 845) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 846) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 847)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 848) static ssize_t
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 849) show_temp_type(struct device *dev, struct device_attribute *attr, char *buf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 850) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 851) struct nct6683_data *data = nct6683_update_device(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 852) struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 853) int nr = sattr->index;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 854) return sprintf(buf, "%d\n", get_temp_type(data->temp_src[nr]));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 855) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 856)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 857) static umode_t nct6683_temp_is_visible(struct kobject *kobj,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 858) struct attribute *attr, int index)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 859) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 860) struct device *dev = kobj_to_dev(kobj);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 861) struct nct6683_data *data = dev_get_drvdata(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 862) int temp = index / 7; /* temp index */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 863) int nr = index % 7; /* attribute index */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 864)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 865) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 866) * Intel does not have low temperature limits or temperature hysteresis
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 867) * registers, or at least register location and encoding is unknown.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 868) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 869) if ((nr == 2 || nr == 4) &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 870) data->customer_id == NCT6683_CUSTOMER_ID_INTEL)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 871) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 872)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 873) if (nr == 6 && get_temp_type(data->temp_src[temp]) == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 874) return 0; /* type */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 875)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 876) return attr->mode;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 877) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 878)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 879) SENSOR_TEMPLATE(temp_input, "temp%d_input", S_IRUGO, show_temp16, NULL, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 880) SENSOR_TEMPLATE(temp_label, "temp%d_label", S_IRUGO, show_temp_label, NULL, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 881) SENSOR_TEMPLATE_2(temp_min, "temp%d_min", S_IRUGO, show_temp8, NULL, 0, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 882) SENSOR_TEMPLATE_2(temp_max, "temp%d_max", S_IRUGO, show_temp8, NULL, 0, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 883) SENSOR_TEMPLATE(temp_max_hyst, "temp%d_max_hyst", S_IRUGO, show_temp_hyst, NULL,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 884) 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 885) SENSOR_TEMPLATE_2(temp_crit, "temp%d_crit", S_IRUGO, show_temp8, NULL, 0, 3);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 886) SENSOR_TEMPLATE(temp_type, "temp%d_type", S_IRUGO, show_temp_type, NULL, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 887)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 888) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 889) * nct6683_temp_is_visible uses the index into the following array
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 890) * to determine if attributes should be created or not.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 891) * Any change in order or content must be matched.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 892) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 893) static struct sensor_device_template *nct6683_attributes_temp_template[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 894) &sensor_dev_template_temp_input,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 895) &sensor_dev_template_temp_label,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 896) &sensor_dev_template_temp_min, /* 2 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 897) &sensor_dev_template_temp_max, /* 3 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 898) &sensor_dev_template_temp_max_hyst, /* 4 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 899) &sensor_dev_template_temp_crit, /* 5 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 900) &sensor_dev_template_temp_type, /* 6 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 901) NULL
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 902) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 903)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 904) static const struct sensor_template_group nct6683_temp_template_group = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 905) .templates = nct6683_attributes_temp_template,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 906) .is_visible = nct6683_temp_is_visible,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 907) .base = 1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 908) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 909)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 910) static ssize_t
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 911) show_pwm(struct device *dev, struct device_attribute *attr, char *buf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 912) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 913) struct nct6683_data *data = nct6683_update_device(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 914) struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 915) int index = sattr->index;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 916)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 917) return sprintf(buf, "%d\n", data->pwm[index]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 918) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 919)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 920) static ssize_t
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 921) store_pwm(struct device *dev, struct device_attribute *attr, const char *buf,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 922) size_t count)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 923) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 924) struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 925) struct nct6683_data *data = dev_get_drvdata(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 926) int index = sattr->index;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 927) unsigned long val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 928)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 929) if (kstrtoul(buf, 10, &val) || val > 255)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 930) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 931)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 932) mutex_lock(&data->update_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 933) nct6683_write(data, NCT6683_REG_FAN_CFG_CTRL, NCT6683_FAN_CFG_REQ);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 934) usleep_range(1000, 2000);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 935) nct6683_write(data, NCT6683_REG_PWM_WRITE(index), val);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 936) nct6683_write(data, NCT6683_REG_FAN_CFG_CTRL, NCT6683_FAN_CFG_DONE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 937) mutex_unlock(&data->update_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 938)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 939) return count;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 940) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 941)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 942) SENSOR_TEMPLATE(pwm, "pwm%d", S_IRUGO, show_pwm, store_pwm, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 943)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 944) static umode_t nct6683_pwm_is_visible(struct kobject *kobj,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 945) struct attribute *attr, int index)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 946) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 947) struct device *dev = kobj_to_dev(kobj);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 948) struct nct6683_data *data = dev_get_drvdata(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 949) int pwm = index; /* pwm index */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 950)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 951) if (!(data->have_pwm & (1 << pwm)))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 952) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 953)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 954) /* Only update pwm values for Mitac boards */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 955) if (data->customer_id == NCT6683_CUSTOMER_ID_MITAC)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 956) return attr->mode | S_IWUSR;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 957)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 958) return attr->mode;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 959) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 960)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 961) static struct sensor_device_template *nct6683_attributes_pwm_template[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 962) &sensor_dev_template_pwm,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 963) NULL
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 964) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 965)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 966) static const struct sensor_template_group nct6683_pwm_template_group = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 967) .templates = nct6683_attributes_pwm_template,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 968) .is_visible = nct6683_pwm_is_visible,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 969) .base = 1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 970) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 971)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 972) static ssize_t
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 973) beep_enable_show(struct device *dev, struct device_attribute *attr, char *buf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 974) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 975) struct nct6683_data *data = dev_get_drvdata(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 976) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 977) u8 reg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 978)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 979) mutex_lock(&data->update_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 980)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 981) ret = superio_enter(data->sioreg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 982) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 983) goto error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 984) superio_select(data->sioreg, NCT6683_LD_HWM);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 985) reg = superio_inb(data->sioreg, NCT6683_REG_CR_BEEP);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 986) superio_exit(data->sioreg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 987)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 988) mutex_unlock(&data->update_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 989)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 990) return sprintf(buf, "%u\n", !!(reg & NCT6683_CR_BEEP_MASK));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 991)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 992) error:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 993) mutex_unlock(&data->update_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 994) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 995) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 996)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 997) static ssize_t
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 998) beep_enable_store(struct device *dev, struct device_attribute *attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 999) const char *buf, size_t count)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1000) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1001) struct nct6683_data *data = dev_get_drvdata(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1002) unsigned long val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1003) u8 reg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1004) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1005)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1006) if (kstrtoul(buf, 10, &val) || (val != 0 && val != 1))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1007) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1008)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1009) mutex_lock(&data->update_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1010)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1011) ret = superio_enter(data->sioreg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1012) if (ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1013) count = ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1014) goto error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1015) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1016)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1017) superio_select(data->sioreg, NCT6683_LD_HWM);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1018) reg = superio_inb(data->sioreg, NCT6683_REG_CR_BEEP);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1019) if (val)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1020) reg |= NCT6683_CR_BEEP_MASK;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1021) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1022) reg &= ~NCT6683_CR_BEEP_MASK;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1023) superio_outb(data->sioreg, NCT6683_REG_CR_BEEP, reg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1024) superio_exit(data->sioreg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1025) error:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1026) mutex_unlock(&data->update_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1027) return count;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1028) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1029)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1030) /* Case open detection */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1031)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1032) static ssize_t
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1033) intrusion0_alarm_show(struct device *dev, struct device_attribute *attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1034) char *buf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1035) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1036) struct nct6683_data *data = dev_get_drvdata(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1037) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1038) u8 reg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1039)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1040) mutex_lock(&data->update_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1041)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1042) ret = superio_enter(data->sioreg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1043) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1044) goto error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1045) superio_select(data->sioreg, NCT6683_LD_ACPI);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1046) reg = superio_inb(data->sioreg, NCT6683_REG_CR_CASEOPEN);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1047) superio_exit(data->sioreg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1048)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1049) mutex_unlock(&data->update_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1050)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1051) return sprintf(buf, "%u\n", !(reg & NCT6683_CR_CASEOPEN_MASK));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1052)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1053) error:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1054) mutex_unlock(&data->update_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1055) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1056) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1057)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1058) static ssize_t
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1059) intrusion0_alarm_store(struct device *dev, struct device_attribute *attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1060) const char *buf, size_t count)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1061) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1062) struct nct6683_data *data = dev_get_drvdata(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1063) unsigned long val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1064) u8 reg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1065) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1066)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1067) if (kstrtoul(buf, 10, &val) || val != 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1068) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1069)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1070) mutex_lock(&data->update_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1071)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1072) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1073) * Use CR registers to clear caseopen status.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1074) * Caseopen is activ low, clear by writing 1 into the register.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1075) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1076)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1077) ret = superio_enter(data->sioreg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1078) if (ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1079) count = ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1080) goto error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1081) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1082)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1083) superio_select(data->sioreg, NCT6683_LD_ACPI);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1084) reg = superio_inb(data->sioreg, NCT6683_REG_CR_CASEOPEN);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1085) reg |= NCT6683_CR_CASEOPEN_MASK;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1086) superio_outb(data->sioreg, NCT6683_REG_CR_CASEOPEN, reg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1087) reg &= ~NCT6683_CR_CASEOPEN_MASK;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1088) superio_outb(data->sioreg, NCT6683_REG_CR_CASEOPEN, reg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1089) superio_exit(data->sioreg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1090)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1091) data->valid = false; /* Force cache refresh */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1092) error:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1093) mutex_unlock(&data->update_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1094) return count;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1095) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1096)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1097) static DEVICE_ATTR_RW(intrusion0_alarm);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1098) static DEVICE_ATTR_RW(beep_enable);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1099)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1100) static struct attribute *nct6683_attributes_other[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1101) &dev_attr_intrusion0_alarm.attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1102) &dev_attr_beep_enable.attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1103) NULL
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1104) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1105)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1106) static const struct attribute_group nct6683_group_other = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1107) .attrs = nct6683_attributes_other,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1108) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1109)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1110) /* Get the monitoring functions started */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1111) static inline void nct6683_init_device(struct nct6683_data *data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1112) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1113) u8 tmp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1114)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1115) /* Start hardware monitoring if needed */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1116) tmp = nct6683_read(data, NCT6683_HWM_CFG);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1117) if (!(tmp & 0x80))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1118) nct6683_write(data, NCT6683_HWM_CFG, tmp | 0x80);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1119) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1120)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1121) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1122) * There are a total of 24 fan inputs. Each can be configured as input
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1123) * or as output. A maximum of 16 inputs and 8 outputs is configurable.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1124) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1125) static void
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1126) nct6683_setup_fans(struct nct6683_data *data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1127) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1128) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1129) u8 reg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1130)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1131) for (i = 0; i < NCT6683_NUM_REG_FAN; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1132) reg = nct6683_read(data, NCT6683_REG_FANIN_CFG(i));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1133) if (reg & 0x80)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1134) data->have_fan |= 1 << i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1135) data->fanin_cfg[i] = reg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1136) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1137) for (i = 0; i < NCT6683_NUM_REG_PWM; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1138) reg = nct6683_read(data, NCT6683_REG_FANOUT_CFG(i));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1139) if (reg & 0x80)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1140) data->have_pwm |= 1 << i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1141) data->fanout_cfg[i] = reg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1142) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1143) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1144)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1145) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1146) * Translation from monitoring register to temperature and voltage attributes
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1147) * ==========================================================================
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1148) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1149) * There are a total of 32 monitoring registers. Each can be assigned to either
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1150) * a temperature or voltage monitoring source.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1151) * NCT6683_REG_MON_CFG(x) defines assignment for each monitoring source.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1152) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1153) * Temperature and voltage attribute mapping is determined by walking through
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1154) * the NCT6683_REG_MON_CFG registers. If the assigned source is
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1155) * a temperature, temp_index[n] is set to the monitor register index, and
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1156) * temp_src[n] is set to the temperature source. If the assigned source is
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1157) * a voltage, the respective values are stored in in_index[] and in_src[],
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1158) * respectively.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1159) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1160)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1161) static void nct6683_setup_sensors(struct nct6683_data *data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1162) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1163) u8 reg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1164) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1165)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1166) data->temp_num = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1167) data->in_num = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1168) for (i = 0; i < NCT6683_NUM_REG_MON; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1169) reg = nct6683_read(data, NCT6683_REG_MON_CFG(i)) & 0x7f;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1170) /* Ignore invalid assignments */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1171) if (reg >= NUM_MON_LABELS)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1172) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1173) /* Skip if disabled or reserved */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1174) if (nct6683_mon_label[reg] == NULL)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1175) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1176) if (reg < MON_VOLTAGE_START) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1177) data->temp_index[data->temp_num] = i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1178) data->temp_src[data->temp_num] = reg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1179) data->temp_num++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1180) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1181) data->in_index[data->in_num] = i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1182) data->in_src[data->in_num] = reg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1183) data->in_num++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1184) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1185) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1186) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1187)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1188) static int nct6683_probe(struct platform_device *pdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1189) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1190) struct device *dev = &pdev->dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1191) struct nct6683_sio_data *sio_data = dev->platform_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1192) struct attribute_group *group;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1193) struct nct6683_data *data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1194) struct device *hwmon_dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1195) struct resource *res;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1196) int groups = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1197) char build[16];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1198)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1199) res = platform_get_resource(pdev, IORESOURCE_IO, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1200) if (!devm_request_region(dev, res->start, IOREGION_LENGTH, DRVNAME))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1201) return -EBUSY;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1202)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1203) data = devm_kzalloc(dev, sizeof(struct nct6683_data), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1204) if (!data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1205) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1206)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1207) data->kind = sio_data->kind;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1208) data->sioreg = sio_data->sioreg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1209) data->addr = res->start;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1210) mutex_init(&data->update_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1211) platform_set_drvdata(pdev, data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1212)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1213) data->customer_id = nct6683_read16(data, NCT6683_REG_CUSTOMER_ID);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1214)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1215) /* By default only instantiate driver if the customer ID is known */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1216) switch (data->customer_id) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1217) case NCT6683_CUSTOMER_ID_INTEL:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1218) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1219) case NCT6683_CUSTOMER_ID_MITAC:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1220) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1221) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1222) if (!force)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1223) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1224) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1225)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1226) nct6683_init_device(data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1227) nct6683_setup_fans(data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1228) nct6683_setup_sensors(data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1229)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1230) /* Register sysfs hooks */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1231)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1232) if (data->have_pwm) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1233) group = nct6683_create_attr_group(dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1234) &nct6683_pwm_template_group,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1235) fls(data->have_pwm));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1236) if (IS_ERR(group))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1237) return PTR_ERR(group);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1238) data->groups[groups++] = group;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1239) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1240)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1241) if (data->in_num) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1242) group = nct6683_create_attr_group(dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1243) &nct6683_in_template_group,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1244) data->in_num);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1245) if (IS_ERR(group))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1246) return PTR_ERR(group);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1247) data->groups[groups++] = group;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1248) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1249)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1250) if (data->have_fan) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1251) group = nct6683_create_attr_group(dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1252) &nct6683_fan_template_group,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1253) fls(data->have_fan));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1254) if (IS_ERR(group))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1255) return PTR_ERR(group);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1256) data->groups[groups++] = group;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1257) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1258)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1259) if (data->temp_num) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1260) group = nct6683_create_attr_group(dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1261) &nct6683_temp_template_group,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1262) data->temp_num);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1263) if (IS_ERR(group))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1264) return PTR_ERR(group);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1265) data->groups[groups++] = group;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1266) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1267) data->groups[groups++] = &nct6683_group_other;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1268)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1269) if (data->customer_id == NCT6683_CUSTOMER_ID_INTEL)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1270) scnprintf(build, sizeof(build), "%02x/%02x/%02x",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1271) nct6683_read(data, NCT6683_REG_BUILD_MONTH),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1272) nct6683_read(data, NCT6683_REG_BUILD_DAY),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1273) nct6683_read(data, NCT6683_REG_BUILD_YEAR));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1274) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1275) scnprintf(build, sizeof(build), "%02d/%02d/%02d",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1276) nct6683_read(data, NCT6683_REG_BUILD_MONTH),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1277) nct6683_read(data, NCT6683_REG_BUILD_DAY),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1278) nct6683_read(data, NCT6683_REG_BUILD_YEAR));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1279)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1280) dev_info(dev, "%s EC firmware version %d.%d build %s\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1281) nct6683_chip_names[data->kind],
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1282) nct6683_read(data, NCT6683_REG_VERSION_HI),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1283) nct6683_read(data, NCT6683_REG_VERSION_LO),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1284) build);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1285)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1286) hwmon_dev = devm_hwmon_device_register_with_groups(dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1287) nct6683_device_names[data->kind], data, data->groups);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1288) return PTR_ERR_OR_ZERO(hwmon_dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1289) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1290)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1291) #ifdef CONFIG_PM
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1292) static int nct6683_suspend(struct device *dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1293) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1294) struct nct6683_data *data = nct6683_update_device(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1295)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1296) mutex_lock(&data->update_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1297) data->hwm_cfg = nct6683_read(data, NCT6683_HWM_CFG);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1298) mutex_unlock(&data->update_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1299)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1300) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1301) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1302)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1303) static int nct6683_resume(struct device *dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1304) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1305) struct nct6683_data *data = dev_get_drvdata(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1306)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1307) mutex_lock(&data->update_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1308)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1309) nct6683_write(data, NCT6683_HWM_CFG, data->hwm_cfg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1310)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1311) /* Force re-reading all values */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1312) data->valid = false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1313) mutex_unlock(&data->update_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1314)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1315) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1316) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1317)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1318) static const struct dev_pm_ops nct6683_dev_pm_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1319) .suspend = nct6683_suspend,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1320) .resume = nct6683_resume,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1321) .freeze = nct6683_suspend,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1322) .restore = nct6683_resume,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1323) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1324)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1325) #define NCT6683_DEV_PM_OPS (&nct6683_dev_pm_ops)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1326) #else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1327) #define NCT6683_DEV_PM_OPS NULL
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1328) #endif /* CONFIG_PM */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1329)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1330) static struct platform_driver nct6683_driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1331) .driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1332) .name = DRVNAME,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1333) .pm = NCT6683_DEV_PM_OPS,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1334) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1335) .probe = nct6683_probe,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1336) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1337)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1338) static int __init nct6683_find(int sioaddr, struct nct6683_sio_data *sio_data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1339) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1340) int addr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1341) u16 val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1342) int err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1343)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1344) err = superio_enter(sioaddr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1345) if (err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1346) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1347)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1348) val = (superio_inb(sioaddr, SIO_REG_DEVID) << 8)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1349) | superio_inb(sioaddr, SIO_REG_DEVID + 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1350)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1351) switch (val & SIO_ID_MASK) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1352) case SIO_NCT6683_ID:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1353) sio_data->kind = nct6683;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1354) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1355) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1356) if (val != 0xffff)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1357) pr_debug("unsupported chip ID: 0x%04x\n", val);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1358) goto fail;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1359) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1360)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1361) /* We have a known chip, find the HWM I/O address */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1362) superio_select(sioaddr, NCT6683_LD_HWM);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1363) val = (superio_inb(sioaddr, SIO_REG_ADDR) << 8)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1364) | superio_inb(sioaddr, SIO_REG_ADDR + 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1365) addr = val & IOREGION_ALIGNMENT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1366) if (addr == 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1367) pr_err("EC base I/O port unconfigured\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1368) goto fail;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1369) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1370)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1371) /* Activate logical device if needed */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1372) val = superio_inb(sioaddr, SIO_REG_ENABLE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1373) if (!(val & 0x01)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1374) pr_warn("Forcibly enabling EC access. Data may be unusable.\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1375) superio_outb(sioaddr, SIO_REG_ENABLE, val | 0x01);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1376) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1377)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1378) superio_exit(sioaddr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1379) pr_info("Found %s or compatible chip at %#x:%#x\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1380) nct6683_chip_names[sio_data->kind], sioaddr, addr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1381) sio_data->sioreg = sioaddr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1382)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1383) return addr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1384)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1385) fail:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1386) superio_exit(sioaddr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1387) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1388) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1389)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1390) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1391) * when Super-I/O functions move to a separate file, the Super-I/O
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1392) * bus will manage the lifetime of the device and this module will only keep
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1393) * track of the nct6683 driver. But since we use platform_device_alloc(), we
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1394) * must keep track of the device
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1395) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1396) static struct platform_device *pdev[2];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1397)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1398) static int __init sensors_nct6683_init(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1399) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1400) struct nct6683_sio_data sio_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1401) int sioaddr[2] = { 0x2e, 0x4e };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1402) struct resource res;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1403) bool found = false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1404) int address;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1405) int i, err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1406)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1407) err = platform_driver_register(&nct6683_driver);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1408) if (err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1409) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1410)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1411) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1412) * initialize sio_data->kind and sio_data->sioreg.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1413) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1414) * when Super-I/O functions move to a separate file, the Super-I/O
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1415) * driver will probe 0x2e and 0x4e and auto-detect the presence of a
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1416) * nct6683 hardware monitor, and call probe()
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1417) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1418) for (i = 0; i < ARRAY_SIZE(pdev); i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1419) address = nct6683_find(sioaddr[i], &sio_data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1420) if (address <= 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1421) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1422)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1423) found = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1424)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1425) pdev[i] = platform_device_alloc(DRVNAME, address);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1426) if (!pdev[i]) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1427) err = -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1428) goto exit_device_unregister;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1429) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1430)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1431) err = platform_device_add_data(pdev[i], &sio_data,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1432) sizeof(struct nct6683_sio_data));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1433) if (err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1434) goto exit_device_put;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1435)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1436) memset(&res, 0, sizeof(res));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1437) res.name = DRVNAME;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1438) res.start = address + IOREGION_OFFSET;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1439) res.end = address + IOREGION_OFFSET + IOREGION_LENGTH - 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1440) res.flags = IORESOURCE_IO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1441)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1442) err = acpi_check_resource_conflict(&res);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1443) if (err) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1444) platform_device_put(pdev[i]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1445) pdev[i] = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1446) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1447) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1448)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1449) err = platform_device_add_resources(pdev[i], &res, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1450) if (err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1451) goto exit_device_put;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1452)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1453) /* platform_device_add calls probe() */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1454) err = platform_device_add(pdev[i]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1455) if (err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1456) goto exit_device_put;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1457) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1458) if (!found) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1459) err = -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1460) goto exit_unregister;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1461) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1462)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1463) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1464)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1465) exit_device_put:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1466) platform_device_put(pdev[i]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1467) exit_device_unregister:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1468) while (--i >= 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1469) if (pdev[i])
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1470) platform_device_unregister(pdev[i]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1471) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1472) exit_unregister:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1473) platform_driver_unregister(&nct6683_driver);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1474) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1475) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1476)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1477) static void __exit sensors_nct6683_exit(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1478) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1479) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1480)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1481) for (i = 0; i < ARRAY_SIZE(pdev); i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1482) if (pdev[i])
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1483) platform_device_unregister(pdev[i]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1484) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1485) platform_driver_unregister(&nct6683_driver);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1486) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1487)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1488) MODULE_AUTHOR("Guenter Roeck <linux@roeck-us.net>");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1489) MODULE_DESCRIPTION("NCT6683D driver");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1490) MODULE_LICENSE("GPL");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1491)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1492) module_init(sensors_nct6683_init);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1493) module_exit(sensors_nct6683_exit);