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/reboot.h>
  16#include <linux/regmap.h>
  17#include <asm/system_misc.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 void rsctrl_restart(enum reboot_mode mode, const char *cmd)
  56{
  57        /* enable write access to RSTCTRL */
  58        rsctrl_enable_rspll_write();
  59
  60        /* reset the SOC */
  61        regmap_update_bits(pllctrl_regs, rspll_offset + RSCTRL_RG,
  62                           RSCTRL_RESET_MASK, 0);
  63}
  64
  65static struct of_device_id rsctrl_of_match[] = {
  66        {.compatible = "ti,keystone-reset", },
  67        {},
  68};
  69
  70static int rsctrl_probe(struct platform_device *pdev)
  71{
  72        int i;
  73        int ret;
  74        u32 val;
  75        unsigned int rg;
  76        u32 rsmux_offset;
  77        struct regmap *devctrl_regs;
  78        struct device *dev = &pdev->dev;
  79        struct device_node *np = dev->of_node;
  80
  81        if (!np)
  82                return -ENODEV;
  83
  84        /* get regmaps */
  85        pllctrl_regs = syscon_regmap_lookup_by_phandle(np, "ti,syscon-pll");
  86        if (IS_ERR(pllctrl_regs))
  87                return PTR_ERR(pllctrl_regs);
  88
  89        devctrl_regs = syscon_regmap_lookup_by_phandle(np, "ti,syscon-dev");
  90        if (IS_ERR(devctrl_regs))
  91                return PTR_ERR(devctrl_regs);
  92
  93        ret = of_property_read_u32_index(np, "ti,syscon-pll", 1, &rspll_offset);
  94        if (ret) {
  95                dev_err(dev, "couldn't read the reset pll offset!\n");
  96                return -EINVAL;
  97        }
  98
  99        ret = of_property_read_u32_index(np, "ti,syscon-dev", 1, &rsmux_offset);
 100        if (ret) {
 101                dev_err(dev, "couldn't read the rsmux offset!\n");
 102                return -EINVAL;
 103        }
 104
 105        /* set soft/hard reset */
 106        val = of_property_read_bool(np, "ti,soft-reset");
 107        val = val ? RSCFG_RSTYPE_SOFT : RSCFG_RSTYPE_HARD;
 108
 109        ret = rsctrl_enable_rspll_write();
 110        if (ret)
 111                return ret;
 112
 113        ret = regmap_write(pllctrl_regs, rspll_offset + RSCFG_RG, val);
 114        if (ret)
 115                return ret;
 116
 117        arm_pm_restart = rsctrl_restart;
 118
 119        /* disable a reset isolation for all module clocks */
 120        ret = regmap_write(pllctrl_regs, rspll_offset + RSISO_RG, 0);
 121        if (ret)
 122                return ret;
 123
 124        /* enable a reset for watchdogs from wdt-list */
 125        for (i = 0; i < WDT_MUX_NUMBER; i++) {
 126                ret = of_property_read_u32_index(np, "ti,wdt-list", i, &val);
 127                if (ret == -EOVERFLOW && !i) {
 128                        dev_err(dev, "ti,wdt-list property has to contain at"
 129                                "least one entry\n");
 130                        return -EINVAL;
 131                } else if (ret) {
 132                        break;
 133                }
 134
 135                if (val >= WDT_MUX_NUMBER) {
 136                        dev_err(dev, "ti,wdt-list property can contain"
 137                                "only numbers < 4\n");
 138                        return -EINVAL;
 139                }
 140
 141                rg = rsmux_offset + val * 4;
 142
 143                ret = regmap_update_bits(devctrl_regs, rg, RSMUX_OMODE_MASK,
 144                                         RSMUX_OMODE_RESET_ON |
 145                                         RSMUX_LOCK_SET);
 146                if (ret)
 147                        return ret;
 148        }
 149
 150        return 0;
 151}
 152
 153static struct platform_driver rsctrl_driver = {
 154        .probe = rsctrl_probe,
 155        .driver = {
 156                .owner = THIS_MODULE,
 157                .name = KBUILD_MODNAME,
 158                .of_match_table = rsctrl_of_match,
 159        },
 160};
 161module_platform_driver(rsctrl_driver);
 162
 163MODULE_AUTHOR("Ivan Khoronzhuk <ivan.khoronzhuk@ti.com>");
 164MODULE_DESCRIPTION("Texas Instruments keystone reset driver");
 165MODULE_LICENSE("GPL v2");
 166MODULE_ALIAS("platform:" KBUILD_MODNAME);
 167
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.