Add the rt linux 4.1.3-rt3 as base
[kvmfornfv.git] / kernel / drivers / power / reset / keystone-reset.c
diff --git a/kernel/drivers/power/reset/keystone-reset.c b/kernel/drivers/power/reset/keystone-reset.c
new file mode 100644 (file)
index 0000000..c70f1bf
--- /dev/null
@@ -0,0 +1,175 @@
+/*
+ * TI keystone reboot driver
+ *
+ * Copyright (C) 2014 Texas Instruments Incorporated. http://www.ti.com/
+ *
+ * Author: Ivan Khoronzhuk <ivan.khoronzhuk@ti.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/notifier.h>
+#include <linux/reboot.h>
+#include <linux/regmap.h>
+#include <linux/mfd/syscon.h>
+#include <linux/of_platform.h>
+
+#define RSTYPE_RG                      0x0
+#define RSCTRL_RG                      0x4
+#define RSCFG_RG                       0x8
+#define RSISO_RG                       0xc
+
+#define RSCTRL_KEY_MASK                        0x0000ffff
+#define RSCTRL_RESET_MASK              BIT(16)
+#define RSCTRL_KEY                     0x5a69
+
+#define RSMUX_OMODE_MASK               0xe
+#define RSMUX_OMODE_RESET_ON           0xa
+#define RSMUX_OMODE_RESET_OFF          0x0
+#define RSMUX_LOCK_MASK                        0x1
+#define RSMUX_LOCK_SET                 0x1
+
+#define RSCFG_RSTYPE_SOFT              0x300f
+#define RSCFG_RSTYPE_HARD              0x0
+
+#define WDT_MUX_NUMBER                 0x4
+
+static int rspll_offset;
+static struct regmap *pllctrl_regs;
+
+/**
+ * rsctrl_enable_rspll_write - enable access to RSCTRL, RSCFG
+ * To be able to access to RSCTRL, RSCFG registers
+ * we have to write a key before
+ */
+static inline int rsctrl_enable_rspll_write(void)
+{
+       return regmap_update_bits(pllctrl_regs, rspll_offset + RSCTRL_RG,
+                                 RSCTRL_KEY_MASK, RSCTRL_KEY);
+}
+
+static int rsctrl_restart_handler(struct notifier_block *this,
+                                 unsigned long mode, void *cmd)
+{
+       /* enable write access to RSTCTRL */
+       rsctrl_enable_rspll_write();
+
+       /* reset the SOC */
+       regmap_update_bits(pllctrl_regs, rspll_offset + RSCTRL_RG,
+                          RSCTRL_RESET_MASK, 0);
+
+       return NOTIFY_DONE;
+}
+
+static struct notifier_block rsctrl_restart_nb = {
+       .notifier_call = rsctrl_restart_handler,
+       .priority = 128,
+};
+
+static const struct of_device_id rsctrl_of_match[] = {
+       {.compatible = "ti,keystone-reset", },
+       {},
+};
+
+static int rsctrl_probe(struct platform_device *pdev)
+{
+       int i;
+       int ret;
+       u32 val;
+       unsigned int rg;
+       u32 rsmux_offset;
+       struct regmap *devctrl_regs;
+       struct device *dev = &pdev->dev;
+       struct device_node *np = dev->of_node;
+
+       if (!np)
+               return -ENODEV;
+
+       /* get regmaps */
+       pllctrl_regs = syscon_regmap_lookup_by_phandle(np, "ti,syscon-pll");
+       if (IS_ERR(pllctrl_regs))
+               return PTR_ERR(pllctrl_regs);
+
+       devctrl_regs = syscon_regmap_lookup_by_phandle(np, "ti,syscon-dev");
+       if (IS_ERR(devctrl_regs))
+               return PTR_ERR(devctrl_regs);
+
+       ret = of_property_read_u32_index(np, "ti,syscon-pll", 1, &rspll_offset);
+       if (ret) {
+               dev_err(dev, "couldn't read the reset pll offset!\n");
+               return -EINVAL;
+       }
+
+       ret = of_property_read_u32_index(np, "ti,syscon-dev", 1, &rsmux_offset);
+       if (ret) {
+               dev_err(dev, "couldn't read the rsmux offset!\n");
+               return -EINVAL;
+       }
+
+       /* set soft/hard reset */
+       val = of_property_read_bool(np, "ti,soft-reset");
+       val = val ? RSCFG_RSTYPE_SOFT : RSCFG_RSTYPE_HARD;
+
+       ret = rsctrl_enable_rspll_write();
+       if (ret)
+               return ret;
+
+       ret = regmap_write(pllctrl_regs, rspll_offset + RSCFG_RG, val);
+       if (ret)
+               return ret;
+
+       /* disable a reset isolation for all module clocks */
+       ret = regmap_write(pllctrl_regs, rspll_offset + RSISO_RG, 0);
+       if (ret)
+               return ret;
+
+       /* enable a reset for watchdogs from wdt-list */
+       for (i = 0; i < WDT_MUX_NUMBER; i++) {
+               ret = of_property_read_u32_index(np, "ti,wdt-list", i, &val);
+               if (ret == -EOVERFLOW && !i) {
+                       dev_err(dev, "ti,wdt-list property has to contain at"
+                               "least one entry\n");
+                       return -EINVAL;
+               } else if (ret) {
+                       break;
+               }
+
+               if (val >= WDT_MUX_NUMBER) {
+                       dev_err(dev, "ti,wdt-list property can contain"
+                               "only numbers < 4\n");
+                       return -EINVAL;
+               }
+
+               rg = rsmux_offset + val * 4;
+
+               ret = regmap_update_bits(devctrl_regs, rg, RSMUX_OMODE_MASK,
+                                        RSMUX_OMODE_RESET_ON |
+                                        RSMUX_LOCK_SET);
+               if (ret)
+                       return ret;
+       }
+
+       ret = register_restart_handler(&rsctrl_restart_nb);
+       if (ret)
+               dev_err(dev, "cannot register restart handler (err=%d)\n", ret);
+
+       return ret;
+}
+
+static struct platform_driver rsctrl_driver = {
+       .probe = rsctrl_probe,
+       .driver = {
+               .name = KBUILD_MODNAME,
+               .of_match_table = rsctrl_of_match,
+       },
+};
+module_platform_driver(rsctrl_driver);
+
+MODULE_AUTHOR("Ivan Khoronzhuk <ivan.khoronzhuk@ti.com>");
+MODULE_DESCRIPTION("Texas Instruments keystone reset driver");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:" KBUILD_MODNAME);