Blame view
drivers/power/reset/keystone-reset.c
4.25 KB
a3e01e802 power: reset: key... |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
/* * 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> |
f59a42d4e power/reset: keys... |
15 |
#include <linux/notifier.h> |
a3e01e802 power: reset: key... |
16 17 |
#include <linux/reboot.h> #include <linux/regmap.h> |
a3e01e802 power: reset: key... |
18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 |
#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); } |
f59a42d4e power/reset: keys... |
54 55 |
static int rsctrl_restart_handler(struct notifier_block *this, unsigned long mode, void *cmd) |
a3e01e802 power: reset: key... |
56 57 58 59 60 61 62 |
{ /* 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); |
f59a42d4e power/reset: keys... |
63 64 |
return NOTIFY_DONE; |
a3e01e802 power: reset: key... |
65 |
} |
f59a42d4e power/reset: keys... |
66 67 68 69 |
static struct notifier_block rsctrl_restart_nb = { .notifier_call = rsctrl_restart_handler, .priority = 128, }; |
8fb088550 power: constify o... |
70 |
static const struct of_device_id rsctrl_of_match[] = { |
a3e01e802 power: reset: key... |
71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 |
{.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! "); 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! "); 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; |
a3e01e802 power: reset: key... |
123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 |
/* 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 "); return -EINVAL; } else if (ret) { break; } if (val >= WDT_MUX_NUMBER) { |
1dff6ce02 power: reset: add... |
141 |
dev_err(dev, "ti,wdt-list property can contain " |
a3e01e802 power: reset: key... |
142 143 144 145 146 147 148 149 150 151 152 153 154 |
"only numbers < 4 "); 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; } |
f59a42d4e power/reset: keys... |
155 156 157 158 159 160 |
ret = register_restart_handler(&rsctrl_restart_nb); if (ret) dev_err(dev, "cannot register restart handler (err=%d) ", ret); return ret; |
a3e01e802 power: reset: key... |
161 162 163 164 165 |
} static struct platform_driver rsctrl_driver = { .probe = rsctrl_probe, .driver = { |
a3e01e802 power: reset: key... |
166 167 168 169 170 171 172 173 174 175 |
.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); |