linux/drivers/power/reset/keystone-reset.c
<<
>>
Prefs
   1/*
   2 * TI keystone reboot driver
   3 *
   4 * Copyright (C) 2014 Texas Instruments Incorporated. http://www.ti.com/
   5 *
   6 * Author: Ivan Khoronzhuk <ivan.khoronzhuk@ti.com>
   7 *
   8 * This program is free software; you can redistribute it and/or modify
   9 * it under the terms of the GNU General Public License version 2 as
  10 * published by the Free Software Foundation.
  11 */
  12
  13#include <linux/io.h>
  14#include <linux/module.h>
  15#include <linux/notifier.h>
  16#include <linux/reboot.h>
  17#include <linux/regmap.h>
  18#include <linux/mfd/syscon.h>
  19#include <linux/of_platform.h>
  20
  21#define RSTYPE_RG                       0x0
  22#define RSCTRL_RG                       0x4
  23#define RSCFG_RG                        0x8
  24#define RSISO_RG                        0xc
  25
  26#define RSCTRL_KEY_MASK                 0x0000ffff
  27#define RSCTRL_RESET_MASK               BIT(16)
  28#define RSCTRL_KEY                      0x5a69
  29
  30#define RSMUX_OMODE_MASK                0xe
  31#define RSMUX_OMODE_RESET_ON            0xa
  32#define RSMUX_OMODE_RESET_OFF           0x0
  33#define RSMUX_LOCK_MASK                 0x1
  34#define RSMUX_LOCK_SET                  0x1
  35
  36#define RSCFG_RSTYPE_SOFT               0x300f
  37#define RSCFG_RSTYPE_HARD               0x0
  38
  39#define WDT_MUX_NUMBER                  0x4
  40
  41static int rspll_offset;
  42static struct regmap *pllctrl_regs;
  43
  44/**
  45 * rsctrl_enable_rspll_write - enable access to RSCTRL, RSCFG
  46 * To be able to access to RSCTRL, RSCFG registers
  47 * we have to write a key before
  48 */
  49static inline int rsctrl_enable_rspll_write(void)
  50{
  51        return regmap_update_bits(pllctrl_regs, rspll_offset + RSCTRL_RG,
  52                                  RSCTRL_KEY_MASK, RSCTRL_KEY);
  53}
  54
  55static int rsctrl_restart_handler(struct notifier_block *this,
  56                                  unsigned long mode, void *cmd)
  57{
  58        /* enable write access to RSTCTRL */
  59        rsctrl_enable_rspll_write();
  60
  61        /* reset the SOC */
  62        regmap_update_bits(pllctrl_regs, rspll_offset + RSCTRL_RG,
  63                           RSCTRL_RESET_MASK, 0);
  64
  65        return NOTIFY_DONE;
  66}
  67
  68static struct notifier_block rsctrl_restart_nb = {
  69        .notifier_call = rsctrl_restart_handler,
  70        .priority = 128,
  71};
  72
  73static const struct of_device_id rsctrl_of_match[] = {
  74        {.compatible = "ti,keystone-reset", },
  75        {},
  76};
  77
  78static int rsctrl_probe(struct platform_device *pdev)
  79{
  80        int i;
  81        int ret;
  82        u32 val;
  83        unsigned int rg;
  84        u32 rsmux_offset;
  85        struct regmap *devctrl_regs;
  86        struct device *dev = &pdev->dev;
  87        struct device_node *np = dev->of_node;
  88
  89        if (!np)
  90                return -ENODEV;
  91
  92        /* get regmaps */
  93        pllctrl_regs = syscon_regmap_lookup_by_phandle(np, "ti,syscon-pll");
  94        if (IS_ERR(pllctrl_regs))
  95                return PTR_ERR(pllctrl_regs);
  96
  97        devctrl_regs = syscon_regmap_lookup_by_phandle(np, "ti,syscon-dev");
  98        if (IS_ERR(devctrl_regs))
  99                return PTR_ERR(devctrl_regs);
 100
 101        ret = of_property_read_u32_index(np, "ti,syscon-pll", 1, &rspll_offset);
 102        if (ret) {
 103                dev_err(dev, "couldn't read the reset pll offset!\n");
 104                return -EINVAL;
 105        }
 106
 107        ret = of_property_read_u32_index(np, "ti,syscon-dev", 1, &rsmux_offset);
 108        if (ret) {
 109                dev_err(dev, "couldn't read the rsmux offset!\n");
 110                return -EINVAL;
 111        }
 112
 113        /* set soft/hard reset */
 114        val = of_property_read_bool(np, "ti,soft-reset");
 115        val = val ? RSCFG_RSTYPE_SOFT : RSCFG_RSTYPE_HARD;
 116
 117        ret = rsctrl_enable_rspll_write();
 118        if (ret)
 119                return ret;
 120
 121        ret = regmap_write(pllctrl_regs, rspll_offset + RSCFG_RG, val);
 122        if (ret)
 123                return ret;
 124
 125        /* disable a reset isolation for all module clocks */
 126        ret = regmap_write(pllctrl_regs, rspll_offset + RSISO_RG, 0);
 127        if (ret)
 128                return ret;
 129
 130        /* enable a reset for watchdogs from wdt-list */
 131        for (i = 0; i < WDT_MUX_NUMBER; i++) {
 132                ret = of_property_read_u32_index(np, "ti,wdt-list", i, &val);
 133                if (ret == -EOVERFLOW && !i) {
 134                        dev_err(dev, "ti,wdt-list property has to contain at"
 135                                "least one entry\n");
 136                        return -EINVAL;
 137                } else if (ret) {
 138                        break;
 139                }
 140
 141                if (val >= WDT_MUX_NUMBER) {
 142                        dev_err(dev, "ti,wdt-list property can contain"
 143                                "only numbers < 4\n");
 144                        return -EINVAL;
 145                }
 146
 147                rg = rsmux_offset + val * 4;
 148
 149                ret = regmap_update_bits(devctrl_regs, rg, RSMUX_OMODE_MASK,
 150                                         RSMUX_OMODE_RESET_ON |
 151                                         RSMUX_LOCK_SET);
 152                if (ret)
 153                        return ret;
 154        }
 155
 156        ret = register_restart_handler(&rsctrl_restart_nb);
 157        if (ret)
 158                dev_err(dev, "cannot register restart handler (err=%d)\n", ret);
 159
 160        return ret;
 161}
 162
 163static struct platform_driver rsctrl_driver = {
 164        .probe = rsctrl_probe,
 165        .driver = {
 166                .name = KBUILD_MODNAME,
 167                .of_match_table = rsctrl_of_match,
 168        },
 169};
 170module_platform_driver(rsctrl_driver);
 171
 172MODULE_AUTHOR("Ivan Khoronzhuk <ivan.khoronzhuk@ti.com>");
 173MODULE_DESCRIPTION("Texas Instruments keystone reset driver");
 174MODULE_LICENSE("GPL v2");
 175MODULE_ALIAS("platform:" KBUILD_MODNAME);
 176