From: Wenkai <advantech.susiteam@xxxxxxxxx> All eiois200 series driver functionalities are based on PMC (Peripheral Management Controller) communication. This patch enables communication between the driver and the eiois200_core. However, this version does not yet implement the watchdog timer's functionality. Signed-off-by: Wenkai <advantech.susiteam@xxxxxxxxx> --- drivers/watchdog/eiois200_wdt.c | 114 ++++++++++++++++++++++++++++++++ 1 file changed, 114 insertions(+) diff --git a/drivers/watchdog/eiois200_wdt.c b/drivers/watchdog/eiois200_wdt.c index bf132a75a2ec..ce4435ac62f2 100644 --- a/drivers/watchdog/eiois200_wdt.c +++ b/drivers/watchdog/eiois200_wdt.c @@ -16,6 +16,40 @@ #define WATCHDOG_TIMEOUT 60 #define WATCHDOG_PRETIMEOUT 10 +/* Support Flags */ +#define SUPPORT_AVAILABLE BIT(0) +#define SUPPORT_RESET BIT(7) + +/* PMC registers */ +#define REG_STATUS 0x00 +#define REG_CONTROL 0x02 +#define REG_EVENT 0x10 +#define REG_RESET_EVENT_TIME 0x14 +#define REG_IRQ_NUMBER 0x17 + +/* PMC command and control */ +#define CMD_WDT_WRITE 0x2A +#define CMD_WDT_READ 0x2B +#define CTRL_STOP 0x00 +#define CTRL_START 0x01 +#define CTRL_TRIGGER 0x02 + +/* I/O register and its flags */ +#define IOREG_UNLOCK 0x87 +#define IOREG_LOCK 0xAA +#define IOREG_LDN 0x07 +#define IOREG_LDN_PMCIO 0x0F +#define IOREG_IRQ 0x70 +#define IOREG_WDT_STATUS 0x30 + +/* Flags */ +#define FLAG_WDT_ENABLED 0x01 +#define FLAG_TRIGGER_IRQ BIT(4) + +/* PMC read and write a value */ +#define PMC_WRITE(cmd, data) pmc(CMD_WDT_WRITE, cmd, data) +#define PMC_READ(cmd, data) pmc(CMD_WDT_READ, cmd, data) + static struct _wdt { u32 support; long last_time; @@ -47,6 +81,48 @@ static int wdt_set_timeout(struct watchdog_device *dev, return 0; } +static int pmc(u8 cmd, u8 ctrl, void *payload) +{ + struct pmc_op op = { + .cmd = cmd, + .control = ctrl, + .size = ctrl <= REG_EVENT ? 1 : + ctrl >= REG_IRQ_NUMBER ? 1 : 4, + .payload = payload, + }; + + return eiois200_core_pmc_operation(wdt.dev, &op); +} + +static int get_time(u8 ctrl, u32 *val) +{ + int ret; + + ret = PMC_READ(ctrl, val); + + /* ms to sec */ + *val /= 1000; + + return ret; +} + + +static int wdt_get_config(void) +{ + int ret; + u32 reset_time; + + /* Get Reset Time */ + ret = get_time(REG_RESET_EVENT_TIME, &reset_time); + if (ret) + return ret; + + dev_info(wdt.dev, "Timeout H/W default timeout: %d secs\n", reset_time); + wddev.timeout = reset_time; + + return 0; +} + static int wdt_start(struct watchdog_device *dev) { return 0; @@ -67,6 +143,40 @@ static unsigned int wdt_get_timeleft(struct watchdog_device *dev) return 0; } +static int wdt_support(void) +{ + u8 support; + + if (PMC_READ(REG_STATUS, &support)) + return -EIO; + + if ((support & SUPPORT_AVAILABLE) == 0) + return -EIO; + + /* Must support reset */ + if ((support & SUPPORT_RESET) != SUPPORT_RESET) + return -EIO; + + /* Must has support event **/ + wdt.support = support; + + return 0; +} +static int wdt_init(struct device *dev) +{ + int ret = 0; + + ret = wdt_support(); + if (ret) + return ret; + + ret = wdt_get_config(); + if (ret) + return ret; + + return ret; +} + static const struct watchdog_ops wdt_ops = { .owner = THIS_MODULE, .start = wdt_start, @@ -91,6 +201,10 @@ static int wdt_probe(struct platform_device *pdev) wdt.iomap = dev_get_regmap(dev->parent, NULL); if (!wdt.iomap) return dev_err_probe(dev, -ENOMEM, "Query parent regmap fail\n"); + + /* Initialize EC watchdog */ + if (wdt_init(dev)) + return dev_err_probe(dev, -EIO, "wdt_init fail\n"); /* Inform watchdog info */ wddev.ops = &wdt_ops; -- 2.34.1