Message ID | 20230815115515.286142-1-dober6023@gmail.com (mailing list archive) |
---|---|
State | Changes Requested |
Headers | show |
Series | hwmon: add in watchdog for nct6686 | expand |
On Tue, Aug 15, 2023 at 07:55:15AM -0400, David Ober wrote: > This change adds in the watchdog timer support for the nct6686 > chip so that it can be used on the Lenovo m90n IOT device > > Signed-off-by: David Ober <dober6023@gmail.com> > --- > Documentation/hwmon/nct6683.rst | 5 +- > drivers/hwmon/nct6683.c | 247 ++++++++++++++++++++++++++++++-- This should be a separate driver in drivers/watchdog/, and sneaking in support for a new vendor with the above description is inappropriate anyway. Besides, why would the watchdog only work for Lenovo ? Guenter > 2 files changed, 242 insertions(+), 10 deletions(-) > > diff --git a/Documentation/hwmon/nct6683.rst b/Documentation/hwmon/nct6683.rst > index 2e1408d174bd..7421bc444365 100644 > --- a/Documentation/hwmon/nct6683.rst > +++ b/Documentation/hwmon/nct6683.rst > @@ -3,7 +3,7 @@ Kernel driver nct6683 > > Supported chips: > > - * Nuvoton NCT6683D/NCT6687D > + * Nuvoton NCT6683D/NCT6686D/NCT6687D > > Prefix: 'nct6683' > > @@ -49,6 +49,8 @@ The driver has only been tested with the Intel firmware, and by default > only instantiates on Intel boards. To enable it on non-Intel boards, > set the 'force' module parameter to 1. > > +Implement the watchdog functionality of the NCT6686D eSIO chip > + > Tested Boards and Firmware Versions > ----------------------------------- > > @@ -63,4 +65,5 @@ Intel DH87MC NCT6683D EC firmware version 1.0 build 04/03/13 > Intel DB85FL NCT6683D EC firmware version 1.0 build 04/03/13 > ASRock X570 NCT6683D EC firmware version 1.0 build 06/28/19 > MSI B550 NCT6687D EC firmware version 1.0 build 05/07/20 > +LENOVO M90n-1 NCT6686D EC firmware version 9.0 build 04/21/21 > =============== =============================================== > diff --git a/drivers/hwmon/nct6683.c b/drivers/hwmon/nct6683.c > index f673f7d07941..eb95b91c4d39 100644 > --- a/drivers/hwmon/nct6683.c > +++ b/drivers/hwmon/nct6683.c > @@ -24,15 +24,16 @@ > #include <linux/acpi.h> > #include <linux/delay.h> > #include <linux/err.h> > +#include <linux/hwmon.h> > +#include <linux/hwmon-sysfs.h> > #include <linux/init.h> > #include <linux/io.h> > #include <linux/jiffies.h> > -#include <linux/hwmon.h> > -#include <linux/hwmon-sysfs.h> > #include <linux/module.h> > #include <linux/mutex.h> > #include <linux/platform_device.h> > #include <linux/slab.h> > +#include <linux/watchdog.h> > > enum kinds { nct6683, nct6686, nct6687 }; > > @@ -73,6 +74,34 @@ static const char * const nct6683_chip_names[] = { > #define SIO_NCT6687_ID 0xd590 > #define SIO_ID_MASK 0xFFF0 > > +#define WDT_CFG 0x828 /* W/O Lock Watchdog Register */ > +#define WDT_CNT 0x829 /* R/W Watchdog Timer Register */ > +#define WDT_STS 0x82A /* R/O Watchdog Status Register */ > +#define WDT_STS_EVT_POS (0) > +#define WDT_STS_EVT_MSK (0x3 << WDT_STS_EVT_POS) > +#define WDT_SOFT_EN 0x87 /* Enable soft watchdog timer */ > +#define WDT_SOFT_DIS 0xAA /* Disable soft watchdog timer */ > + > +#define WATCHDOG_TIMEOUT 60 /* 1 minute default timeout */ > + > +/* The timeout range is 1-255 seconds */ > +#define MIN_TIMEOUT 1 > +#define MAX_TIMEOUT 255 > + > +static int timeout; > +module_param(timeout, int, 0); > +MODULE_PARM_DESC(timeout, "Watchdog timeout in seconds. 1 <= timeout <= 255, default=" > + __MODULE_STRING(WATCHDOG_TIMEOUT) "."); > + > +static bool nowayout = WATCHDOG_NOWAYOUT; > +module_param(nowayout, bool, 0); > +MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" > + __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); > + > +static int early_disable; > +module_param(early_disable, int, 0); > +MODULE_PARM_DESC(early_disable, "Disable watchdog at boot time (default=0)"); > + > static inline void > superio_outb(int ioreg, int reg, int val) > { > @@ -171,10 +200,10 @@ superio_exit(int ioreg) > > #define NCT6683_REG_CUSTOMER_ID 0x602 > #define NCT6683_CUSTOMER_ID_INTEL 0x805 > +#define NCT6683_CUSTOMER_ID_LENOVO 0x1101 > #define NCT6683_CUSTOMER_ID_MITAC 0xa0e > #define NCT6683_CUSTOMER_ID_MSI 0x201 > -#define NCT6683_CUSTOMER_ID_MSI2 0x200 > -#define NCT6683_CUSTOMER_ID_ASROCK 0xe2c > +#define NCT6683_CUSTOMER_ID_ASROCK 0xe2c > #define NCT6683_CUSTOMER_ID_ASROCK2 0xe1b > > #define NCT6683_REG_BUILD_YEAR 0x604 > @@ -183,6 +212,9 @@ superio_exit(int ioreg) > #define NCT6683_REG_SERIAL 0x607 > #define NCT6683_REG_VERSION_HI 0x608 > #define NCT6683_REG_VERSION_LO 0x609 > +#define NCT6686_PAGE_REG_OFFSET 0 > +#define NCT6686_ADDR_REG_OFFSET 1 > +#define NCT6686_DATA_REG_OFFSET 2 > > #define NCT6683_REG_CR_CASEOPEN 0xe8 > #define NCT6683_CR_CASEOPEN_MASK (1 << 7) > @@ -304,6 +336,7 @@ struct nct6683_data { > > struct device *hwmon_dev; > const struct attribute_group *groups[6]; > + struct watchdog_device wdt; > > int temp_num; /* number of temperature attributes */ > u8 temp_index[NCT6683_NUM_REG_MON]; > @@ -518,6 +551,39 @@ static void nct6683_write(struct nct6683_data *data, u16 reg, u16 value) > outb_p(value & 0xff, data->addr + EC_DATA_REG); > } > > +static inline void nct6686_wdt_set_bank(int base_addr, u16 reg) > +{ > + outb_p(0xFF, base_addr + NCT6686_PAGE_REG_OFFSET); > + outb_p(reg >> 8, base_addr + NCT6686_PAGE_REG_OFFSET); > +} > + > +/* Not strictly necessary, but play it safe for now */ > +static inline void nct6686_wdt_reset_bank(int base_addr, u16 reg) > +{ > + if (reg & 0xff00) > + outb_p(0xFF, base_addr + NCT6686_PAGE_REG_OFFSET); > +} > + > +static u8 nct6686_read(struct nct6683_data *data, u16 reg) > +{ > + u8 res; > + > + nct6686_wdt_set_bank(data->addr, reg); > + outb_p(reg & 0xff, data->addr + NCT6686_ADDR_REG_OFFSET); > + res = inb_p(data->addr + NCT6686_DATA_REG_OFFSET); > + > + nct6686_wdt_reset_bank(data->addr, reg); > + return res; > +} > + > +static void nct6686_write(struct nct6683_data *data, u16 reg, u8 value) > +{ > + nct6686_wdt_set_bank(data->addr, reg); > + outb_p(reg & 0xff, data->addr + NCT6686_ADDR_REG_OFFSET); > + outb_p(value & 0xff, data->addr + NCT6686_DATA_REG_OFFSET); > + nct6686_wdt_reset_bank(data->addr, reg); > +} > + > static int get_in_reg(struct nct6683_data *data, int nr, int index) > { > int ch = data->in_index[index]; > @@ -680,11 +746,12 @@ static umode_t nct6683_in_is_visible(struct kobject *kobj, > int nr = index % 4; /* attribute */ > > /* > - * Voltage limits exist for Intel boards, > + * Voltage limits exist for Intel and Lenovo boards, > * but register location and encoding is unknown > */ > if ((nr == 2 || nr == 3) && > - data->customer_id == NCT6683_CUSTOMER_ID_INTEL) > + (data->customer_id == NCT6683_CUSTOMER_ID_INTEL || > + data->customer_id == NCT6683_CUSTOMER_ID_LENOVO)) > return 0; > > return attr->mode; > @@ -1186,6 +1253,139 @@ static void nct6683_setup_sensors(struct nct6683_data *data) > } > } > > +/* > + * Watchdog Functions > + */ > +static int nct6686_wdt_enable(struct watchdog_device *wdog, bool enable) > +{ > + struct nct6683_data *data = watchdog_get_drvdata(wdog); > + > + u_char reg; > + > + mutex_lock(&data->update_lock); > + reg = nct6686_read(data, WDT_CFG); > + > + if (enable) { > + nct6686_write(data, WDT_CFG, reg | 0x3); > + mutex_unlock(&data->update_lock); > + return 0; > + } > + > + nct6686_write(data, WDT_CFG, reg & ~BIT(0)); > + mutex_unlock(&data->update_lock); > + > + return 0; > +} > + > +static int nct6686_wdt_set_time(struct watchdog_device *wdog) > +{ > + struct nct6683_data *data = watchdog_get_drvdata(wdog); > + > + mutex_lock(&data->update_lock); > + nct6686_write(data, WDT_CNT, wdog->timeout); > + mutex_unlock(&data->update_lock); > + > + if (wdog->timeout) { > + nct6686_wdt_enable(wdog, true); > + return 0; > + } > + > + nct6686_wdt_enable(wdog, false); > + return 0; > +} > + > +static int nct6686_wdt_start(struct watchdog_device *wdt) > +{ > + struct nct6683_data *data = watchdog_get_drvdata(wdt); > + u_char reg; > + > + nct6686_wdt_set_time(wdt); > + > + /* Enable soft watchdog timer */ > + mutex_lock(&data->update_lock); > + /* reset trigger status */ > + reg = nct6686_read(data, WDT_STS); > + nct6686_write(data, WDT_STS, reg & ~WDT_STS_EVT_MSK); > + mutex_unlock(&data->update_lock); > + return 0; > +} > + > +static int nct6686_wdt_stop(struct watchdog_device *wdt) > +{ > + struct nct6683_data *data = watchdog_get_drvdata(wdt); > + > + mutex_lock(&data->update_lock); > + nct6686_write(data, WDT_CFG, WDT_SOFT_DIS); > + mutex_unlock(&data->update_lock); > + return 0; > +} > + > +static int nct6686_wdt_set_timeout(struct watchdog_device *wdt, > + unsigned int timeout) > +{ > + struct nct6683_data *data = watchdog_get_drvdata(wdt); > + > + wdt->timeout = timeout; > + mutex_lock(&data->update_lock); > + nct6686_write(data, WDT_CNT, timeout); > + mutex_unlock(&data->update_lock); > + return 0; > +} > + > +static int nct6686_wdt_ping(struct watchdog_device *wdt) > +{ > + struct nct6683_data *data = watchdog_get_drvdata(wdt); > + int timeout; > + > + /* > + * Note: > + * NCT6686 does not support refreshing WDT_TIMER_REG register when > + * the watchdog is active. Please disable watchdog before feeding > + * the watchdog and enable it again. > + */ > + /* Disable soft watchdog timer */ > + nct6686_wdt_enable(wdt, false); > + > + /* feed watchdog */ > + timeout = wdt->timeout; > + mutex_lock(&data->update_lock); > + nct6686_write(data, WDT_CNT, timeout); > + mutex_unlock(&data->update_lock); > + > + /* Enable soft watchdog timer */ > + nct6686_wdt_enable(wdt, true); > + return 0; > +} > + > +static unsigned int nct6686_wdt_get_timeleft(struct watchdog_device *wdt) > +{ > + struct nct6683_data *data = watchdog_get_drvdata(wdt); > + int ret; > + > + mutex_lock(&data->update_lock); > + ret = nct6686_read(data, WDT_CNT); > + mutex_unlock(&data->update_lock); > + if (ret < 0) > + return 0; > + > + return ret; > +} > + > +static const struct watchdog_info nct6686_wdt_info = { > + .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | > + WDIOF_MAGICCLOSE, > + .identity = "nct6686 watchdog", > +}; > + > +static const struct watchdog_ops nct6686_wdt_ops = { > + .owner = THIS_MODULE, > + .start = nct6686_wdt_start, > + .stop = nct6686_wdt_stop, > + .ping = nct6686_wdt_ping, > + .set_timeout = nct6686_wdt_set_timeout, > + .get_timeleft = nct6686_wdt_get_timeleft, > +}; > + > static int nct6683_probe(struct platform_device *pdev) > { > struct device *dev = &pdev->dev; > @@ -1195,7 +1395,9 @@ static int nct6683_probe(struct platform_device *pdev) > struct device *hwmon_dev; > struct resource *res; > int groups = 0; > + int ret; > char build[16]; > + u_char reg; > > res = platform_get_resource(pdev, IORESOURCE_IO, 0); > if (!devm_request_region(dev, res->start, IOREGION_LENGTH, DRVNAME)) > @@ -1215,14 +1417,14 @@ static int nct6683_probe(struct platform_device *pdev) > > /* By default only instantiate driver if the customer ID is known */ > switch (data->customer_id) { > + case NCT6683_CUSTOMER_ID_LENOVO: > + break; > case NCT6683_CUSTOMER_ID_INTEL: > break; > case NCT6683_CUSTOMER_ID_MITAC: > break; > case NCT6683_CUSTOMER_ID_MSI: > break; > - case NCT6683_CUSTOMER_ID_MSI2: > - break; > case NCT6683_CUSTOMER_ID_ASROCK: > break; > case NCT6683_CUSTOMER_ID_ASROCK2: > @@ -1294,7 +1496,34 @@ static int nct6683_probe(struct platform_device *pdev) > > hwmon_dev = devm_hwmon_device_register_with_groups(dev, > nct6683_device_names[data->kind], data, data->groups); > - return PTR_ERR_OR_ZERO(hwmon_dev); > + > + ret = PTR_ERR_OR_ZERO(hwmon_dev); > + if (ret) > + return ret; > + > + if (data->kind == nct6686 && data->customer_id == NCT6683_CUSTOMER_ID_LENOVO) { > + /* Watchdog initialization */ > + data->wdt.ops = &nct6686_wdt_ops; > + data->wdt.info = &nct6686_wdt_info; > + > + data->wdt.timeout = WATCHDOG_TIMEOUT; /* Set default timeout */ > + data->wdt.min_timeout = MIN_TIMEOUT; > + data->wdt.max_timeout = MAX_TIMEOUT; > + data->wdt.parent = &pdev->dev; > + > + watchdog_init_timeout(&data->wdt, timeout, &pdev->dev); > + watchdog_set_nowayout(&data->wdt, nowayout); > + watchdog_set_drvdata(&data->wdt, data); > + > + /* reset trigger status */ > + reg = nct6686_read(data, WDT_STS); > + nct6686_write(data, WDT_STS, reg & ~WDT_STS_EVT_MSK); > + > + watchdog_stop_on_unregister(&data->wdt); > + > + return devm_watchdog_register_device(dev, &data->wdt); > + } > + return ret; > } > > #ifdef CONFIG_PM > -- > 2.34.1 >
Hi David, kernel test robot noticed the following build errors: [auto build test ERROR on groeck-staging/hwmon-next] [also build test ERROR on linus/master v6.5-rc6 next-20230815] [If your patch is applied to the wrong git tree, kindly drop us a note. And when submitting patch, we suggest to use '--base' as documented in https://git-scm.com/docs/git-format-patch#_base_tree_information] url: https://github.com/intel-lab-lkp/linux/commits/David-Ober/hwmon-add-in-watchdog-for-nct6686/20230815-195946 base: https://git.kernel.org/pub/scm/linux/kernel/git/groeck/linux-staging.git hwmon-next patch link: https://lore.kernel.org/r/20230815115515.286142-1-dober6023%40gmail.com patch subject: [PATCH] hwmon: add in watchdog for nct6686 config: x86_64-randconfig-r006-20230815 (https://download.01.org/0day-ci/archive/20230815/202308152354.OmOTyX2r-lkp@intel.com/config) compiler: clang version 16.0.4 (https://github.com/llvm/llvm-project.git ae42196bc493ffe877a7e3dff8be32035dea4d07) reproduce: (https://download.01.org/0day-ci/archive/20230815/202308152354.OmOTyX2r-lkp@intel.com/reproduce) If you fix the issue in a separate patch/commit (i.e. not just a new version of the same patch/commit), kindly add following tags | Reported-by: kernel test robot <lkp@intel.com> | Closes: https://lore.kernel.org/oe-kbuild-all/202308152354.OmOTyX2r-lkp@intel.com/ All errors (new ones prefixed by >>): >> ld.lld: error: undefined symbol: watchdog_init_timeout >>> referenced by nct6683.c:1514 (drivers/hwmon/nct6683.c:1514) >>> drivers/hwmon/nct6683.o:(nct6683_probe) in archive vmlinux.a -- >> ld.lld: error: undefined symbol: devm_watchdog_register_device >>> referenced by nct6683.c:1524 (drivers/hwmon/nct6683.c:1524) >>> drivers/hwmon/nct6683.o:(nct6683_probe) in archive vmlinux.a
Hi David, kernel test robot noticed the following build errors: [auto build test ERROR on groeck-staging/hwmon-next] [also build test ERROR on linus/master v6.5-rc6 next-20230815] [If your patch is applied to the wrong git tree, kindly drop us a note. And when submitting patch, we suggest to use '--base' as documented in https://git-scm.com/docs/git-format-patch#_base_tree_information] url: https://github.com/intel-lab-lkp/linux/commits/David-Ober/hwmon-add-in-watchdog-for-nct6686/20230815-195946 base: https://git.kernel.org/pub/scm/linux/kernel/git/groeck/linux-staging.git hwmon-next patch link: https://lore.kernel.org/r/20230815115515.286142-1-dober6023%40gmail.com patch subject: [PATCH] hwmon: add in watchdog for nct6686 config: i386-randconfig-i015-20230815 (https://download.01.org/0day-ci/archive/20230815/202308152310.lu9rTudo-lkp@intel.com/config) compiler: gcc-12 (Debian 12.2.0-14) 12.2.0 reproduce: (https://download.01.org/0day-ci/archive/20230815/202308152310.lu9rTudo-lkp@intel.com/reproduce) If you fix the issue in a separate patch/commit (i.e. not just a new version of the same patch/commit), kindly add following tags | Reported-by: kernel test robot <lkp@intel.com> | Closes: https://lore.kernel.org/oe-kbuild-all/202308152310.lu9rTudo-lkp@intel.com/ All errors (new ones prefixed by >>): ld: drivers/hwmon/nct6683.o: in function `nct6683_probe': >> drivers/hwmon/nct6683.c:1514: undefined reference to `watchdog_init_timeout' >> ld: drivers/hwmon/nct6683.c:1524: undefined reference to `devm_watchdog_register_device' vim +1514 drivers/hwmon/nct6683.c 1388 1389 static int nct6683_probe(struct platform_device *pdev) 1390 { 1391 struct device *dev = &pdev->dev; 1392 struct nct6683_sio_data *sio_data = dev->platform_data; 1393 struct attribute_group *group; 1394 struct nct6683_data *data; 1395 struct device *hwmon_dev; 1396 struct resource *res; 1397 int groups = 0; 1398 int ret; 1399 char build[16]; 1400 u_char reg; 1401 1402 res = platform_get_resource(pdev, IORESOURCE_IO, 0); 1403 if (!devm_request_region(dev, res->start, IOREGION_LENGTH, DRVNAME)) 1404 return -EBUSY; 1405 1406 data = devm_kzalloc(dev, sizeof(struct nct6683_data), GFP_KERNEL); 1407 if (!data) 1408 return -ENOMEM; 1409 1410 data->kind = sio_data->kind; 1411 data->sioreg = sio_data->sioreg; 1412 data->addr = res->start; 1413 mutex_init(&data->update_lock); 1414 platform_set_drvdata(pdev, data); 1415 1416 data->customer_id = nct6683_read16(data, NCT6683_REG_CUSTOMER_ID); 1417 1418 /* By default only instantiate driver if the customer ID is known */ 1419 switch (data->customer_id) { 1420 case NCT6683_CUSTOMER_ID_LENOVO: 1421 break; 1422 case NCT6683_CUSTOMER_ID_INTEL: 1423 break; 1424 case NCT6683_CUSTOMER_ID_MITAC: 1425 break; 1426 case NCT6683_CUSTOMER_ID_MSI: 1427 break; 1428 case NCT6683_CUSTOMER_ID_ASROCK: 1429 break; 1430 case NCT6683_CUSTOMER_ID_ASROCK2: 1431 break; 1432 default: 1433 if (!force) 1434 return -ENODEV; 1435 } 1436 1437 nct6683_init_device(data); 1438 nct6683_setup_fans(data); 1439 nct6683_setup_sensors(data); 1440 1441 /* Register sysfs hooks */ 1442 1443 if (data->have_pwm) { 1444 group = nct6683_create_attr_group(dev, 1445 &nct6683_pwm_template_group, 1446 fls(data->have_pwm)); 1447 if (IS_ERR(group)) 1448 return PTR_ERR(group); 1449 data->groups[groups++] = group; 1450 } 1451 1452 if (data->in_num) { 1453 group = nct6683_create_attr_group(dev, 1454 &nct6683_in_template_group, 1455 data->in_num); 1456 if (IS_ERR(group)) 1457 return PTR_ERR(group); 1458 data->groups[groups++] = group; 1459 } 1460 1461 if (data->have_fan) { 1462 group = nct6683_create_attr_group(dev, 1463 &nct6683_fan_template_group, 1464 fls(data->have_fan)); 1465 if (IS_ERR(group)) 1466 return PTR_ERR(group); 1467 data->groups[groups++] = group; 1468 } 1469 1470 if (data->temp_num) { 1471 group = nct6683_create_attr_group(dev, 1472 &nct6683_temp_template_group, 1473 data->temp_num); 1474 if (IS_ERR(group)) 1475 return PTR_ERR(group); 1476 data->groups[groups++] = group; 1477 } 1478 data->groups[groups++] = &nct6683_group_other; 1479 1480 if (data->customer_id == NCT6683_CUSTOMER_ID_INTEL) 1481 scnprintf(build, sizeof(build), "%02x/%02x/%02x", 1482 nct6683_read(data, NCT6683_REG_BUILD_MONTH), 1483 nct6683_read(data, NCT6683_REG_BUILD_DAY), 1484 nct6683_read(data, NCT6683_REG_BUILD_YEAR)); 1485 else 1486 scnprintf(build, sizeof(build), "%02d/%02d/%02d", 1487 nct6683_read(data, NCT6683_REG_BUILD_MONTH), 1488 nct6683_read(data, NCT6683_REG_BUILD_DAY), 1489 nct6683_read(data, NCT6683_REG_BUILD_YEAR)); 1490 1491 dev_info(dev, "%s EC firmware version %d.%d build %s\n", 1492 nct6683_chip_names[data->kind], 1493 nct6683_read(data, NCT6683_REG_VERSION_HI), 1494 nct6683_read(data, NCT6683_REG_VERSION_LO), 1495 build); 1496 1497 hwmon_dev = devm_hwmon_device_register_with_groups(dev, 1498 nct6683_device_names[data->kind], data, data->groups); 1499 1500 ret = PTR_ERR_OR_ZERO(hwmon_dev); 1501 if (ret) 1502 return ret; 1503 1504 if (data->kind == nct6686 && data->customer_id == NCT6683_CUSTOMER_ID_LENOVO) { 1505 /* Watchdog initialization */ 1506 data->wdt.ops = &nct6686_wdt_ops; 1507 data->wdt.info = &nct6686_wdt_info; 1508 1509 data->wdt.timeout = WATCHDOG_TIMEOUT; /* Set default timeout */ 1510 data->wdt.min_timeout = MIN_TIMEOUT; 1511 data->wdt.max_timeout = MAX_TIMEOUT; 1512 data->wdt.parent = &pdev->dev; 1513 > 1514 watchdog_init_timeout(&data->wdt, timeout, &pdev->dev); 1515 watchdog_set_nowayout(&data->wdt, nowayout); 1516 watchdog_set_drvdata(&data->wdt, data); 1517 1518 /* reset trigger status */ 1519 reg = nct6686_read(data, WDT_STS); 1520 nct6686_write(data, WDT_STS, reg & ~WDT_STS_EVT_MSK); 1521 1522 watchdog_stop_on_unregister(&data->wdt); 1523 > 1524 return devm_watchdog_register_device(dev, &data->wdt); 1525 } 1526 return ret; 1527 } 1528
Hi David, kernel test robot noticed the following build errors: [auto build test ERROR on groeck-staging/hwmon-next] [also build test ERROR on linus/master v6.5-rc6 next-20230815] [If your patch is applied to the wrong git tree, kindly drop us a note. And when submitting patch, we suggest to use '--base' as documented in https://git-scm.com/docs/git-format-patch#_base_tree_information] url: https://github.com/intel-lab-lkp/linux/commits/David-Ober/hwmon-add-in-watchdog-for-nct6686/20230815-195946 base: https://git.kernel.org/pub/scm/linux/kernel/git/groeck/linux-staging.git hwmon-next patch link: https://lore.kernel.org/r/20230815115515.286142-1-dober6023%40gmail.com patch subject: [PATCH] hwmon: add in watchdog for nct6686 config: i386-randconfig-i013-20230815 (https://download.01.org/0day-ci/archive/20230816/202308160001.hx3WQNSU-lkp@intel.com/config) compiler: gcc-12 (Debian 12.2.0-14) 12.2.0 reproduce: (https://download.01.org/0day-ci/archive/20230816/202308160001.hx3WQNSU-lkp@intel.com/reproduce) If you fix the issue in a separate patch/commit (i.e. not just a new version of the same patch/commit), kindly add following tags | Reported-by: kernel test robot <lkp@intel.com> | Closes: https://lore.kernel.org/oe-kbuild-all/202308160001.hx3WQNSU-lkp@intel.com/ All errors (new ones prefixed by >>, old ones prefixed by <<): WARNING: modpost: missing MODULE_DESCRIPTION() in vmlinux.o WARNING: modpost: missing MODULE_DESCRIPTION() in kernel/locking/locktorture.o WARNING: modpost: missing MODULE_DESCRIPTION() in kernel/rcu/rcutorture.o WARNING: modpost: missing MODULE_DESCRIPTION() in kernel/rcu/rcuscale.o WARNING: modpost: missing MODULE_DESCRIPTION() in kernel/rcu/refscale.o WARNING: modpost: missing MODULE_DESCRIPTION() in kernel/torture.o WARNING: modpost: missing MODULE_DESCRIPTION() in fs/nfs/nfsv4.o WARNING: modpost: missing MODULE_DESCRIPTION() in fs/nls/nls_cp437.o WARNING: modpost: missing MODULE_DESCRIPTION() in fs/nls/nls_cp852.o WARNING: modpost: missing MODULE_DESCRIPTION() in fs/nls/nls_cp863.o WARNING: modpost: missing MODULE_DESCRIPTION() in fs/nls/nls_cp866.o WARNING: modpost: missing MODULE_DESCRIPTION() in fs/nls/nls_cp869.o WARNING: modpost: missing MODULE_DESCRIPTION() in fs/nls/nls_cp932.o WARNING: modpost: missing MODULE_DESCRIPTION() in fs/nls/nls_euc-jp.o WARNING: modpost: missing MODULE_DESCRIPTION() in fs/nls/nls_cp936.o WARNING: modpost: missing MODULE_DESCRIPTION() in fs/nls/nls_cp949.o WARNING: modpost: missing MODULE_DESCRIPTION() in fs/nls/nls_iso8859-6.o WARNING: modpost: missing MODULE_DESCRIPTION() in fs/nls/nls_iso8859-7.o WARNING: modpost: missing MODULE_DESCRIPTION() in fs/nls/nls_iso8859-9.o WARNING: modpost: missing MODULE_DESCRIPTION() in fs/nls/nls_iso8859-14.o WARNING: modpost: missing MODULE_DESCRIPTION() in fs/nls/nls_utf8.o WARNING: modpost: missing MODULE_DESCRIPTION() in fs/nls/mac-greek.o WARNING: modpost: missing MODULE_DESCRIPTION() in fs/nls/mac-iceland.o WARNING: modpost: missing MODULE_DESCRIPTION() in fs/nls/mac-romanian.o WARNING: modpost: missing MODULE_DESCRIPTION() in fs/smb/common/cifs_arc4.o WARNING: modpost: missing MODULE_DESCRIPTION() in fs/smb/common/cifs_md4.o WARNING: modpost: missing MODULE_DESCRIPTION() in security/keys/trusted-keys/trusted.o WARNING: modpost: missing MODULE_DESCRIPTION() in crypto/ecc.o WARNING: modpost: missing MODULE_DESCRIPTION() in crypto/curve25519-generic.o WARNING: modpost: missing MODULE_DESCRIPTION() in block/t10-pi.o WARNING: modpost: missing MODULE_DESCRIPTION() in lib/crypto/libdes.o WARNING: modpost: missing MODULE_DESCRIPTION() in lib/asn1_decoder.o WARNING: modpost: missing MODULE_DESCRIPTION() in lib/asn1_encoder.o WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/video/backlight/rt4831-backlight.o WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/virtio/virtio_dma_buf.o WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/regulator/rt4831-regulator.o WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/tty/serial/8250/serial_cs.o WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/tty/synclink_gt.o WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/char/agp/intel-gtt.o WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/gpu/drm/tiny/cirrus.o WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/gpu/drm/drm_panel_orientation_quirks.o WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/base/regmap/regmap-i2c.o WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/base/regmap/regmap-slimbus.o WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/block/loop.o WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/mfd/arizona.o WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/mfd/timberdale.o WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/mfd/rt4831.o WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/cxl/cxl_mem.o WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/cxl/cxl_pmem.o WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/scsi/scsi_common.o WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/scsi/aha1542.o WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/scsi/aha1740.o WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/scsi/isci/isci.o WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/scsi/g_NCR5380.o WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/scsi/atp870u.o WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/nvme/target/nvmet.o WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/cdrom/cdrom.o WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/input/touchscreen/cyttsp_i2c_common.o WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/i2c/busses/i2c-ccgx-ucsi.o WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/hid/hid-apple.o WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/hid/hid-dr.o WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/hid/hid-emsff.o WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/hid/hid-maltron.o WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/hid/hid-pl.o WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/hid/hid-petalynx.o WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/hid/hid-semitek.o WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/hid/hid-speedlink.o WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/hid/hid-sunplus.o WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/hid/hid-tivo.o WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/hid/hid-twinhan.o WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/hid/hid-xinmo.o WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/hid/hid-zydacron.o WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/hid/hid-viewsonic.o WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/hid/hid-waltop.o WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/devfreq/governor_simpleondemand.o WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/devfreq/governor_performance.o WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/parport/parport.o WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/nvdimm/libnvdimm.o WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/nvdimm/nd_pmem.o WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/nvdimm/nd_e820.o WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/mtd/chips/cfi_util.o WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/mtd/chips/cfi_cmdset_0020.o WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/mtd/maps/map_funcs.o WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/uio/uio.o WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/uio/uio_cif.o WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/uio/uio_aec.o WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/uio/uio_netx.o WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/hwmon/corsair-cpro.o WARNING: modpost: missing MODULE_DESCRIPTION() in samples/vfio-mdev/mtty.o WARNING: modpost: missing MODULE_DESCRIPTION() in samples/vfio-mdev/mdpy.o WARNING: modpost: missing MODULE_DESCRIPTION() in samples/vfio-mdev/mbochs.o WARNING: modpost: missing MODULE_DESCRIPTION() in samples/kfifo/bytestream-example.o WARNING: modpost: missing MODULE_DESCRIPTION() in samples/kfifo/dma-example.o WARNING: modpost: missing MODULE_DESCRIPTION() in samples/kfifo/inttype-example.o WARNING: modpost: missing MODULE_DESCRIPTION() in samples/kfifo/record-example.o >> ERROR: modpost: "watchdog_init_timeout" [drivers/hwmon/nct6683.ko] undefined! >> ERROR: modpost: "devm_watchdog_register_device" [drivers/hwmon/nct6683.ko] undefined!
Hi David, kernel test robot noticed the following build errors: [auto build test ERROR on groeck-staging/hwmon-next] [also build test ERROR on linus/master v6.6-rc2 next-20230921] [If your patch is applied to the wrong git tree, kindly drop us a note. And when submitting patch, we suggest to use '--base' as documented in https://git-scm.com/docs/git-format-patch#_base_tree_information] url: https://github.com/intel-lab-lkp/linux/commits/David-Ober/hwmon-add-in-watchdog-for-nct6686/20230815-195946 base: https://git.kernel.org/pub/scm/linux/kernel/git/groeck/linux-staging.git hwmon-next patch link: https://lore.kernel.org/r/20230815115515.286142-1-dober6023%40gmail.com patch subject: [PATCH] hwmon: add in watchdog for nct6686 config: csky-randconfig-r026-20230816 (https://download.01.org/0day-ci/archive/20230923/202309230032.aGiDd9Or-lkp@intel.com/config) compiler: csky-linux-gcc (GCC) 12.3.0 reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20230923/202309230032.aGiDd9Or-lkp@intel.com/reproduce) If you fix the issue in a separate patch/commit (i.e. not just a new version of the same patch/commit), kindly add following tags | Reported-by: kernel test robot <lkp@intel.com> | Closes: https://lore.kernel.org/oe-kbuild-all/202309230032.aGiDd9Or-lkp@intel.com/ All errors (new ones prefixed by >>): csky-linux-ld: drivers/hwmon/nct6683.o: in function `nct6683_probe': >> nct6683.c:(.text+0x1594): undefined reference to `watchdog_init_timeout' >> csky-linux-ld: nct6683.c:(.text+0x15fc): undefined reference to `watchdog_init_timeout' >> csky-linux-ld: nct6683.c:(.text+0x1684): undefined reference to `devm_watchdog_register_device' csky-linux-ld: nct6683.c:(.text+0x16a4): undefined reference to `devm_watchdog_register_device'
diff --git a/Documentation/hwmon/nct6683.rst b/Documentation/hwmon/nct6683.rst index 2e1408d174bd..7421bc444365 100644 --- a/Documentation/hwmon/nct6683.rst +++ b/Documentation/hwmon/nct6683.rst @@ -3,7 +3,7 @@ Kernel driver nct6683 Supported chips: - * Nuvoton NCT6683D/NCT6687D + * Nuvoton NCT6683D/NCT6686D/NCT6687D Prefix: 'nct6683' @@ -49,6 +49,8 @@ The driver has only been tested with the Intel firmware, and by default only instantiates on Intel boards. To enable it on non-Intel boards, set the 'force' module parameter to 1. +Implement the watchdog functionality of the NCT6686D eSIO chip + Tested Boards and Firmware Versions ----------------------------------- @@ -63,4 +65,5 @@ Intel DH87MC NCT6683D EC firmware version 1.0 build 04/03/13 Intel DB85FL NCT6683D EC firmware version 1.0 build 04/03/13 ASRock X570 NCT6683D EC firmware version 1.0 build 06/28/19 MSI B550 NCT6687D EC firmware version 1.0 build 05/07/20 +LENOVO M90n-1 NCT6686D EC firmware version 9.0 build 04/21/21 =============== =============================================== diff --git a/drivers/hwmon/nct6683.c b/drivers/hwmon/nct6683.c index f673f7d07941..eb95b91c4d39 100644 --- a/drivers/hwmon/nct6683.c +++ b/drivers/hwmon/nct6683.c @@ -24,15 +24,16 @@ #include <linux/acpi.h> #include <linux/delay.h> #include <linux/err.h> +#include <linux/hwmon.h> +#include <linux/hwmon-sysfs.h> #include <linux/init.h> #include <linux/io.h> #include <linux/jiffies.h> -#include <linux/hwmon.h> -#include <linux/hwmon-sysfs.h> #include <linux/module.h> #include <linux/mutex.h> #include <linux/platform_device.h> #include <linux/slab.h> +#include <linux/watchdog.h> enum kinds { nct6683, nct6686, nct6687 }; @@ -73,6 +74,34 @@ static const char * const nct6683_chip_names[] = { #define SIO_NCT6687_ID 0xd590 #define SIO_ID_MASK 0xFFF0 +#define WDT_CFG 0x828 /* W/O Lock Watchdog Register */ +#define WDT_CNT 0x829 /* R/W Watchdog Timer Register */ +#define WDT_STS 0x82A /* R/O Watchdog Status Register */ +#define WDT_STS_EVT_POS (0) +#define WDT_STS_EVT_MSK (0x3 << WDT_STS_EVT_POS) +#define WDT_SOFT_EN 0x87 /* Enable soft watchdog timer */ +#define WDT_SOFT_DIS 0xAA /* Disable soft watchdog timer */ + +#define WATCHDOG_TIMEOUT 60 /* 1 minute default timeout */ + +/* The timeout range is 1-255 seconds */ +#define MIN_TIMEOUT 1 +#define MAX_TIMEOUT 255 + +static int timeout; +module_param(timeout, int, 0); +MODULE_PARM_DESC(timeout, "Watchdog timeout in seconds. 1 <= timeout <= 255, default=" + __MODULE_STRING(WATCHDOG_TIMEOUT) "."); + +static bool nowayout = WATCHDOG_NOWAYOUT; +module_param(nowayout, bool, 0); +MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" + __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); + +static int early_disable; +module_param(early_disable, int, 0); +MODULE_PARM_DESC(early_disable, "Disable watchdog at boot time (default=0)"); + static inline void superio_outb(int ioreg, int reg, int val) { @@ -171,10 +200,10 @@ superio_exit(int ioreg) #define NCT6683_REG_CUSTOMER_ID 0x602 #define NCT6683_CUSTOMER_ID_INTEL 0x805 +#define NCT6683_CUSTOMER_ID_LENOVO 0x1101 #define NCT6683_CUSTOMER_ID_MITAC 0xa0e #define NCT6683_CUSTOMER_ID_MSI 0x201 -#define NCT6683_CUSTOMER_ID_MSI2 0x200 -#define NCT6683_CUSTOMER_ID_ASROCK 0xe2c +#define NCT6683_CUSTOMER_ID_ASROCK 0xe2c #define NCT6683_CUSTOMER_ID_ASROCK2 0xe1b #define NCT6683_REG_BUILD_YEAR 0x604 @@ -183,6 +212,9 @@ superio_exit(int ioreg) #define NCT6683_REG_SERIAL 0x607 #define NCT6683_REG_VERSION_HI 0x608 #define NCT6683_REG_VERSION_LO 0x609 +#define NCT6686_PAGE_REG_OFFSET 0 +#define NCT6686_ADDR_REG_OFFSET 1 +#define NCT6686_DATA_REG_OFFSET 2 #define NCT6683_REG_CR_CASEOPEN 0xe8 #define NCT6683_CR_CASEOPEN_MASK (1 << 7) @@ -304,6 +336,7 @@ struct nct6683_data { struct device *hwmon_dev; const struct attribute_group *groups[6]; + struct watchdog_device wdt; int temp_num; /* number of temperature attributes */ u8 temp_index[NCT6683_NUM_REG_MON]; @@ -518,6 +551,39 @@ static void nct6683_write(struct nct6683_data *data, u16 reg, u16 value) outb_p(value & 0xff, data->addr + EC_DATA_REG); } +static inline void nct6686_wdt_set_bank(int base_addr, u16 reg) +{ + outb_p(0xFF, base_addr + NCT6686_PAGE_REG_OFFSET); + outb_p(reg >> 8, base_addr + NCT6686_PAGE_REG_OFFSET); +} + +/* Not strictly necessary, but play it safe for now */ +static inline void nct6686_wdt_reset_bank(int base_addr, u16 reg) +{ + if (reg & 0xff00) + outb_p(0xFF, base_addr + NCT6686_PAGE_REG_OFFSET); +} + +static u8 nct6686_read(struct nct6683_data *data, u16 reg) +{ + u8 res; + + nct6686_wdt_set_bank(data->addr, reg); + outb_p(reg & 0xff, data->addr + NCT6686_ADDR_REG_OFFSET); + res = inb_p(data->addr + NCT6686_DATA_REG_OFFSET); + + nct6686_wdt_reset_bank(data->addr, reg); + return res; +} + +static void nct6686_write(struct nct6683_data *data, u16 reg, u8 value) +{ + nct6686_wdt_set_bank(data->addr, reg); + outb_p(reg & 0xff, data->addr + NCT6686_ADDR_REG_OFFSET); + outb_p(value & 0xff, data->addr + NCT6686_DATA_REG_OFFSET); + nct6686_wdt_reset_bank(data->addr, reg); +} + static int get_in_reg(struct nct6683_data *data, int nr, int index) { int ch = data->in_index[index]; @@ -680,11 +746,12 @@ static umode_t nct6683_in_is_visible(struct kobject *kobj, int nr = index % 4; /* attribute */ /* - * Voltage limits exist for Intel boards, + * Voltage limits exist for Intel and Lenovo boards, * but register location and encoding is unknown */ if ((nr == 2 || nr == 3) && - data->customer_id == NCT6683_CUSTOMER_ID_INTEL) + (data->customer_id == NCT6683_CUSTOMER_ID_INTEL || + data->customer_id == NCT6683_CUSTOMER_ID_LENOVO)) return 0; return attr->mode; @@ -1186,6 +1253,139 @@ static void nct6683_setup_sensors(struct nct6683_data *data) } } +/* + * Watchdog Functions + */ +static int nct6686_wdt_enable(struct watchdog_device *wdog, bool enable) +{ + struct nct6683_data *data = watchdog_get_drvdata(wdog); + + u_char reg; + + mutex_lock(&data->update_lock); + reg = nct6686_read(data, WDT_CFG); + + if (enable) { + nct6686_write(data, WDT_CFG, reg | 0x3); + mutex_unlock(&data->update_lock); + return 0; + } + + nct6686_write(data, WDT_CFG, reg & ~BIT(0)); + mutex_unlock(&data->update_lock); + + return 0; +} + +static int nct6686_wdt_set_time(struct watchdog_device *wdog) +{ + struct nct6683_data *data = watchdog_get_drvdata(wdog); + + mutex_lock(&data->update_lock); + nct6686_write(data, WDT_CNT, wdog->timeout); + mutex_unlock(&data->update_lock); + + if (wdog->timeout) { + nct6686_wdt_enable(wdog, true); + return 0; + } + + nct6686_wdt_enable(wdog, false); + return 0; +} + +static int nct6686_wdt_start(struct watchdog_device *wdt) +{ + struct nct6683_data *data = watchdog_get_drvdata(wdt); + u_char reg; + + nct6686_wdt_set_time(wdt); + + /* Enable soft watchdog timer */ + mutex_lock(&data->update_lock); + /* reset trigger status */ + reg = nct6686_read(data, WDT_STS); + nct6686_write(data, WDT_STS, reg & ~WDT_STS_EVT_MSK); + mutex_unlock(&data->update_lock); + return 0; +} + +static int nct6686_wdt_stop(struct watchdog_device *wdt) +{ + struct nct6683_data *data = watchdog_get_drvdata(wdt); + + mutex_lock(&data->update_lock); + nct6686_write(data, WDT_CFG, WDT_SOFT_DIS); + mutex_unlock(&data->update_lock); + return 0; +} + +static int nct6686_wdt_set_timeout(struct watchdog_device *wdt, + unsigned int timeout) +{ + struct nct6683_data *data = watchdog_get_drvdata(wdt); + + wdt->timeout = timeout; + mutex_lock(&data->update_lock); + nct6686_write(data, WDT_CNT, timeout); + mutex_unlock(&data->update_lock); + return 0; +} + +static int nct6686_wdt_ping(struct watchdog_device *wdt) +{ + struct nct6683_data *data = watchdog_get_drvdata(wdt); + int timeout; + + /* + * Note: + * NCT6686 does not support refreshing WDT_TIMER_REG register when + * the watchdog is active. Please disable watchdog before feeding + * the watchdog and enable it again. + */ + /* Disable soft watchdog timer */ + nct6686_wdt_enable(wdt, false); + + /* feed watchdog */ + timeout = wdt->timeout; + mutex_lock(&data->update_lock); + nct6686_write(data, WDT_CNT, timeout); + mutex_unlock(&data->update_lock); + + /* Enable soft watchdog timer */ + nct6686_wdt_enable(wdt, true); + return 0; +} + +static unsigned int nct6686_wdt_get_timeleft(struct watchdog_device *wdt) +{ + struct nct6683_data *data = watchdog_get_drvdata(wdt); + int ret; + + mutex_lock(&data->update_lock); + ret = nct6686_read(data, WDT_CNT); + mutex_unlock(&data->update_lock); + if (ret < 0) + return 0; + + return ret; +} + +static const struct watchdog_info nct6686_wdt_info = { + .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | + WDIOF_MAGICCLOSE, + .identity = "nct6686 watchdog", +}; + +static const struct watchdog_ops nct6686_wdt_ops = { + .owner = THIS_MODULE, + .start = nct6686_wdt_start, + .stop = nct6686_wdt_stop, + .ping = nct6686_wdt_ping, + .set_timeout = nct6686_wdt_set_timeout, + .get_timeleft = nct6686_wdt_get_timeleft, +}; + static int nct6683_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; @@ -1195,7 +1395,9 @@ static int nct6683_probe(struct platform_device *pdev) struct device *hwmon_dev; struct resource *res; int groups = 0; + int ret; char build[16]; + u_char reg; res = platform_get_resource(pdev, IORESOURCE_IO, 0); if (!devm_request_region(dev, res->start, IOREGION_LENGTH, DRVNAME)) @@ -1215,14 +1417,14 @@ static int nct6683_probe(struct platform_device *pdev) /* By default only instantiate driver if the customer ID is known */ switch (data->customer_id) { + case NCT6683_CUSTOMER_ID_LENOVO: + break; case NCT6683_CUSTOMER_ID_INTEL: break; case NCT6683_CUSTOMER_ID_MITAC: break; case NCT6683_CUSTOMER_ID_MSI: break; - case NCT6683_CUSTOMER_ID_MSI2: - break; case NCT6683_CUSTOMER_ID_ASROCK: break; case NCT6683_CUSTOMER_ID_ASROCK2: @@ -1294,7 +1496,34 @@ static int nct6683_probe(struct platform_device *pdev) hwmon_dev = devm_hwmon_device_register_with_groups(dev, nct6683_device_names[data->kind], data, data->groups); - return PTR_ERR_OR_ZERO(hwmon_dev); + + ret = PTR_ERR_OR_ZERO(hwmon_dev); + if (ret) + return ret; + + if (data->kind == nct6686 && data->customer_id == NCT6683_CUSTOMER_ID_LENOVO) { + /* Watchdog initialization */ + data->wdt.ops = &nct6686_wdt_ops; + data->wdt.info = &nct6686_wdt_info; + + data->wdt.timeout = WATCHDOG_TIMEOUT; /* Set default timeout */ + data->wdt.min_timeout = MIN_TIMEOUT; + data->wdt.max_timeout = MAX_TIMEOUT; + data->wdt.parent = &pdev->dev; + + watchdog_init_timeout(&data->wdt, timeout, &pdev->dev); + watchdog_set_nowayout(&data->wdt, nowayout); + watchdog_set_drvdata(&data->wdt, data); + + /* reset trigger status */ + reg = nct6686_read(data, WDT_STS); + nct6686_write(data, WDT_STS, reg & ~WDT_STS_EVT_MSK); + + watchdog_stop_on_unregister(&data->wdt); + + return devm_watchdog_register_device(dev, &data->wdt); + } + return ret; } #ifdef CONFIG_PM
This change adds in the watchdog timer support for the nct6686 chip so that it can be used on the Lenovo m90n IOT device Signed-off-by: David Ober <dober6023@gmail.com> --- Documentation/hwmon/nct6683.rst | 5 +- drivers/hwmon/nct6683.c | 247 ++++++++++++++++++++++++++++++-- 2 files changed, 242 insertions(+), 10 deletions(-)