diff options
Diffstat (limited to 'kernel/drivers/reset')
-rw-r--r-- | kernel/drivers/reset/Makefile | 3 | ||||
-rw-r--r-- | kernel/drivers/reset/reset-ath79.c | 129 | ||||
-rw-r--r-- | kernel/drivers/reset/reset-berlin.c | 74 | ||||
-rw-r--r-- | kernel/drivers/reset/reset-lpc18xx.c | 258 | ||||
-rw-r--r-- | kernel/drivers/reset/reset-socfpga.c | 19 | ||||
-rw-r--r-- | kernel/drivers/reset/reset-zynq.c | 155 | ||||
-rw-r--r-- | kernel/drivers/reset/sti/reset-stih407.c | 4 | ||||
-rw-r--r-- | kernel/drivers/reset/sti/reset-stih415.c | 4 | ||||
-rw-r--r-- | kernel/drivers/reset/sti/reset-stih416.c | 4 |
9 files changed, 592 insertions, 58 deletions
diff --git a/kernel/drivers/reset/Makefile b/kernel/drivers/reset/Makefile index 157d421f7..85d5904e5 100644 --- a/kernel/drivers/reset/Makefile +++ b/kernel/drivers/reset/Makefile @@ -1,5 +1,8 @@ obj-$(CONFIG_RESET_CONTROLLER) += core.o +obj-$(CONFIG_ARCH_LPC18XX) += reset-lpc18xx.o obj-$(CONFIG_ARCH_SOCFPGA) += reset-socfpga.o obj-$(CONFIG_ARCH_BERLIN) += reset-berlin.o obj-$(CONFIG_ARCH_SUNXI) += reset-sunxi.o obj-$(CONFIG_ARCH_STI) += sti/ +obj-$(CONFIG_ARCH_ZYNQ) += reset-zynq.o +obj-$(CONFIG_ATH79) += reset-ath79.o diff --git a/kernel/drivers/reset/reset-ath79.c b/kernel/drivers/reset/reset-ath79.c new file mode 100644 index 000000000..9aaf646ec --- /dev/null +++ b/kernel/drivers/reset/reset-ath79.c @@ -0,0 +1,129 @@ +/* + * Copyright (C) 2015 Alban Bedel <albeu@free.fr> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/reset-controller.h> + +struct ath79_reset { + struct reset_controller_dev rcdev; + void __iomem *base; + spinlock_t lock; +}; + +static int ath79_reset_update(struct reset_controller_dev *rcdev, + unsigned long id, bool assert) +{ + struct ath79_reset *ath79_reset = + container_of(rcdev, struct ath79_reset, rcdev); + unsigned long flags; + u32 val; + + spin_lock_irqsave(&ath79_reset->lock, flags); + val = readl(ath79_reset->base); + if (assert) + val |= BIT(id); + else + val &= ~BIT(id); + writel(val, ath79_reset->base); + spin_unlock_irqrestore(&ath79_reset->lock, flags); + + return 0; +} + +static int ath79_reset_assert(struct reset_controller_dev *rcdev, + unsigned long id) +{ + return ath79_reset_update(rcdev, id, true); +} + +static int ath79_reset_deassert(struct reset_controller_dev *rcdev, + unsigned long id) +{ + return ath79_reset_update(rcdev, id, false); +} + +static int ath79_reset_status(struct reset_controller_dev *rcdev, + unsigned long id) +{ + struct ath79_reset *ath79_reset = + container_of(rcdev, struct ath79_reset, rcdev); + u32 val; + + val = readl(ath79_reset->base); + + return !!(val & BIT(id)); +} + +static struct reset_control_ops ath79_reset_ops = { + .assert = ath79_reset_assert, + .deassert = ath79_reset_deassert, + .status = ath79_reset_status, +}; + +static int ath79_reset_probe(struct platform_device *pdev) +{ + struct ath79_reset *ath79_reset; + struct resource *res; + + ath79_reset = devm_kzalloc(&pdev->dev, + sizeof(*ath79_reset), GFP_KERNEL); + if (!ath79_reset) + return -ENOMEM; + + platform_set_drvdata(pdev, ath79_reset); + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + ath79_reset->base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(ath79_reset->base)) + return PTR_ERR(ath79_reset->base); + + spin_lock_init(&ath79_reset->lock); + ath79_reset->rcdev.ops = &ath79_reset_ops; + ath79_reset->rcdev.owner = THIS_MODULE; + ath79_reset->rcdev.of_node = pdev->dev.of_node; + ath79_reset->rcdev.of_reset_n_cells = 1; + ath79_reset->rcdev.nr_resets = 32; + + return reset_controller_register(&ath79_reset->rcdev); +} + +static int ath79_reset_remove(struct platform_device *pdev) +{ + struct ath79_reset *ath79_reset = platform_get_drvdata(pdev); + + reset_controller_unregister(&ath79_reset->rcdev); + + return 0; +} + +static const struct of_device_id ath79_reset_dt_ids[] = { + { .compatible = "qca,ar7100-reset", }, + { }, +}; +MODULE_DEVICE_TABLE(of, ath79_reset_dt_ids); + +static struct platform_driver ath79_reset_driver = { + .probe = ath79_reset_probe, + .remove = ath79_reset_remove, + .driver = { + .name = "ath79-reset", + .of_match_table = ath79_reset_dt_ids, + }, +}; +module_platform_driver(ath79_reset_driver); + +MODULE_AUTHOR("Alban Bedel <albeu@free.fr>"); +MODULE_DESCRIPTION("AR71xx Reset Controller Driver"); +MODULE_LICENSE("GPL"); diff --git a/kernel/drivers/reset/reset-berlin.c b/kernel/drivers/reset/reset-berlin.c index f8b48a13c..3c922d372 100644 --- a/kernel/drivers/reset/reset-berlin.c +++ b/kernel/drivers/reset/reset-berlin.c @@ -11,10 +11,12 @@ #include <linux/delay.h> #include <linux/io.h> +#include <linux/mfd/syscon.h> #include <linux/module.h> #include <linux/of.h> #include <linux/of_address.h> #include <linux/platform_device.h> +#include <linux/regmap.h> #include <linux/reset-controller.h> #include <linux/slab.h> #include <linux/types.h> @@ -25,8 +27,7 @@ container_of((p), struct berlin_reset_priv, rcdev) struct berlin_reset_priv { - void __iomem *base; - unsigned int size; + struct regmap *regmap; struct reset_controller_dev rcdev; }; @@ -37,7 +38,7 @@ static int berlin_reset_reset(struct reset_controller_dev *rcdev, int offset = id >> 8; int mask = BIT(id & 0x1f); - writel(mask, priv->base + offset); + regmap_write(priv->regmap, offset, mask); /* let the reset be effective */ udelay(10); @@ -52,7 +53,6 @@ static struct reset_control_ops berlin_reset_ops = { static int berlin_reset_xlate(struct reset_controller_dev *rcdev, const struct of_phandle_args *reset_spec) { - struct berlin_reset_priv *priv = to_berlin_reset_priv(rcdev); unsigned offset, bit; if (WARN_ON(reset_spec->args_count != rcdev->of_reset_n_cells)) @@ -61,71 +61,53 @@ static int berlin_reset_xlate(struct reset_controller_dev *rcdev, offset = reset_spec->args[0]; bit = reset_spec->args[1]; - if (offset >= priv->size) - return -EINVAL; - if (bit >= BERLIN_MAX_RESETS) return -EINVAL; return (offset << 8) | bit; } -static int __berlin_reset_init(struct device_node *np) +static int berlin2_reset_probe(struct platform_device *pdev) { + struct device_node *parent_np = of_get_parent(pdev->dev.of_node); struct berlin_reset_priv *priv; - struct resource res; - resource_size_t size; - int ret; - priv = kzalloc(sizeof(*priv), GFP_KERNEL); + priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); if (!priv) return -ENOMEM; - ret = of_address_to_resource(np, 0, &res); - if (ret) - goto err; - - size = resource_size(&res); - priv->base = ioremap(res.start, size); - if (!priv->base) { - ret = -ENOMEM; - goto err; - } - priv->size = size; + priv->regmap = syscon_node_to_regmap(parent_np); + of_node_put(parent_np); + if (IS_ERR(priv->regmap)) + return PTR_ERR(priv->regmap); priv->rcdev.owner = THIS_MODULE; priv->rcdev.ops = &berlin_reset_ops; - priv->rcdev.of_node = np; + priv->rcdev.of_node = pdev->dev.of_node; priv->rcdev.of_reset_n_cells = 2; priv->rcdev.of_xlate = berlin_reset_xlate; reset_controller_register(&priv->rcdev); return 0; - -err: - kfree(priv); - return ret; } -static const struct of_device_id berlin_reset_of_match[] __initconst = { - { .compatible = "marvell,berlin2-chip-ctrl" }, - { .compatible = "marvell,berlin2cd-chip-ctrl" }, - { .compatible = "marvell,berlin2q-chip-ctrl" }, +static const struct of_device_id berlin_reset_dt_match[] = { + { .compatible = "marvell,berlin2-reset" }, { }, }; +MODULE_DEVICE_TABLE(of, berlin_reset_dt_match); + +static struct platform_driver berlin_reset_driver = { + .probe = berlin2_reset_probe, + .driver = { + .name = "berlin2-reset", + .of_match_table = berlin_reset_dt_match, + }, +}; +module_platform_driver(berlin_reset_driver); -static int __init berlin_reset_init(void) -{ - struct device_node *np; - int ret; - - for_each_matching_node(np, berlin_reset_of_match) { - ret = __berlin_reset_init(np); - if (ret) - return ret; - } - - return 0; -} -arch_initcall(berlin_reset_init); +MODULE_AUTHOR("Antoine Tenart <antoine.tenart@free-electrons.com>"); +MODULE_AUTHOR("Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>"); +MODULE_DESCRIPTION("Marvell Berlin reset driver"); +MODULE_LICENSE("GPL"); diff --git a/kernel/drivers/reset/reset-lpc18xx.c b/kernel/drivers/reset/reset-lpc18xx.c new file mode 100644 index 000000000..70922e9ac --- /dev/null +++ b/kernel/drivers/reset/reset-lpc18xx.c @@ -0,0 +1,258 @@ +/* + * Reset driver for NXP LPC18xx/43xx Reset Generation Unit (RGU). + * + * Copyright (C) 2015 Joachim Eastwood <manabian@gmail.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/clk.h> +#include <linux/delay.h> +#include <linux/err.h> +#include <linux/io.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/platform_device.h> +#include <linux/reboot.h> +#include <linux/reset-controller.h> +#include <linux/spinlock.h> + +/* LPC18xx RGU registers */ +#define LPC18XX_RGU_CTRL0 0x100 +#define LPC18XX_RGU_CTRL1 0x104 +#define LPC18XX_RGU_ACTIVE_STATUS0 0x150 +#define LPC18XX_RGU_ACTIVE_STATUS1 0x154 + +#define LPC18XX_RGU_RESETS_PER_REG 32 + +/* Internal reset outputs */ +#define LPC18XX_RGU_CORE_RST 0 +#define LPC43XX_RGU_M0SUB_RST 12 +#define LPC43XX_RGU_M0APP_RST 56 + +struct lpc18xx_rgu_data { + struct reset_controller_dev rcdev; + struct clk *clk_delay; + struct clk *clk_reg; + void __iomem *base; + spinlock_t lock; + u32 delay_us; +}; + +#define to_rgu_data(p) container_of(p, struct lpc18xx_rgu_data, rcdev) + +static void __iomem *rgu_base; + +static int lpc18xx_rgu_restart(struct notifier_block *this, unsigned long mode, + void *cmd) +{ + writel(BIT(LPC18XX_RGU_CORE_RST), rgu_base + LPC18XX_RGU_CTRL0); + mdelay(2000); + + pr_emerg("%s: unable to restart system\n", __func__); + + return NOTIFY_DONE; +} + +static struct notifier_block lpc18xx_rgu_restart_nb = { + .notifier_call = lpc18xx_rgu_restart, + .priority = 192, +}; + +/* + * The LPC18xx RGU has mostly self-deasserting resets except for the + * two reset lines going to the internal Cortex-M0 cores. + * + * To prevent the M0 core resets from accidentally getting deasserted + * status register must be check and bits in control register set to + * preserve the state. + */ +static int lpc18xx_rgu_setclear_reset(struct reset_controller_dev *rcdev, + unsigned long id, bool set) +{ + struct lpc18xx_rgu_data *rc = to_rgu_data(rcdev); + u32 stat_offset = LPC18XX_RGU_ACTIVE_STATUS0; + u32 ctrl_offset = LPC18XX_RGU_CTRL0; + unsigned long flags; + u32 stat, rst_bit; + + stat_offset += (id / LPC18XX_RGU_RESETS_PER_REG) * sizeof(u32); + ctrl_offset += (id / LPC18XX_RGU_RESETS_PER_REG) * sizeof(u32); + rst_bit = 1 << (id % LPC18XX_RGU_RESETS_PER_REG); + + spin_lock_irqsave(&rc->lock, flags); + stat = ~readl(rc->base + stat_offset); + if (set) + writel(stat | rst_bit, rc->base + ctrl_offset); + else + writel(stat & ~rst_bit, rc->base + ctrl_offset); + spin_unlock_irqrestore(&rc->lock, flags); + + return 0; +} + +static int lpc18xx_rgu_assert(struct reset_controller_dev *rcdev, + unsigned long id) +{ + return lpc18xx_rgu_setclear_reset(rcdev, id, true); +} + +static int lpc18xx_rgu_deassert(struct reset_controller_dev *rcdev, + unsigned long id) +{ + return lpc18xx_rgu_setclear_reset(rcdev, id, false); +} + +/* Only M0 cores require explicit reset deassert */ +static int lpc18xx_rgu_reset(struct reset_controller_dev *rcdev, + unsigned long id) +{ + struct lpc18xx_rgu_data *rc = to_rgu_data(rcdev); + + lpc18xx_rgu_assert(rcdev, id); + udelay(rc->delay_us); + + switch (id) { + case LPC43XX_RGU_M0SUB_RST: + case LPC43XX_RGU_M0APP_RST: + lpc18xx_rgu_setclear_reset(rcdev, id, false); + } + + return 0; +} + +static int lpc18xx_rgu_status(struct reset_controller_dev *rcdev, + unsigned long id) +{ + struct lpc18xx_rgu_data *rc = to_rgu_data(rcdev); + u32 bit, offset = LPC18XX_RGU_ACTIVE_STATUS0; + + offset += (id / LPC18XX_RGU_RESETS_PER_REG) * sizeof(u32); + bit = 1 << (id % LPC18XX_RGU_RESETS_PER_REG); + + return !(readl(rc->base + offset) & bit); +} + +static struct reset_control_ops lpc18xx_rgu_ops = { + .reset = lpc18xx_rgu_reset, + .assert = lpc18xx_rgu_assert, + .deassert = lpc18xx_rgu_deassert, + .status = lpc18xx_rgu_status, +}; + +static int lpc18xx_rgu_probe(struct platform_device *pdev) +{ + struct lpc18xx_rgu_data *rc; + struct resource *res; + u32 fcclk, firc; + int ret; + + rc = devm_kzalloc(&pdev->dev, sizeof(*rc), GFP_KERNEL); + if (!rc) + return -ENOMEM; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + rc->base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(rc->base)) + return PTR_ERR(rc->base); + + rc->clk_reg = devm_clk_get(&pdev->dev, "reg"); + if (IS_ERR(rc->clk_reg)) { + dev_err(&pdev->dev, "reg clock not found\n"); + return PTR_ERR(rc->clk_reg); + } + + rc->clk_delay = devm_clk_get(&pdev->dev, "delay"); + if (IS_ERR(rc->clk_delay)) { + dev_err(&pdev->dev, "delay clock not found\n"); + return PTR_ERR(rc->clk_delay); + } + + ret = clk_prepare_enable(rc->clk_reg); + if (ret) { + dev_err(&pdev->dev, "unable to enable reg clock\n"); + return ret; + } + + ret = clk_prepare_enable(rc->clk_delay); + if (ret) { + dev_err(&pdev->dev, "unable to enable delay clock\n"); + goto dis_clk_reg; + } + + fcclk = clk_get_rate(rc->clk_reg) / USEC_PER_SEC; + firc = clk_get_rate(rc->clk_delay) / USEC_PER_SEC; + if (fcclk == 0 || firc == 0) + rc->delay_us = 2; + else + rc->delay_us = DIV_ROUND_UP(fcclk, firc * firc); + + spin_lock_init(&rc->lock); + + rc->rcdev.owner = THIS_MODULE; + rc->rcdev.nr_resets = 64; + rc->rcdev.ops = &lpc18xx_rgu_ops; + rc->rcdev.of_node = pdev->dev.of_node; + + platform_set_drvdata(pdev, rc); + + ret = reset_controller_register(&rc->rcdev); + if (ret) { + dev_err(&pdev->dev, "unable to register device\n"); + goto dis_clks; + } + + rgu_base = rc->base; + ret = register_restart_handler(&lpc18xx_rgu_restart_nb); + if (ret) + dev_warn(&pdev->dev, "failed to register restart handler\n"); + + return 0; + +dis_clks: + clk_disable_unprepare(rc->clk_delay); +dis_clk_reg: + clk_disable_unprepare(rc->clk_reg); + + return ret; +} + +static int lpc18xx_rgu_remove(struct platform_device *pdev) +{ + struct lpc18xx_rgu_data *rc = platform_get_drvdata(pdev); + int ret; + + ret = unregister_restart_handler(&lpc18xx_rgu_restart_nb); + if (ret) + dev_warn(&pdev->dev, "failed to unregister restart handler\n"); + + reset_controller_unregister(&rc->rcdev); + + clk_disable_unprepare(rc->clk_delay); + clk_disable_unprepare(rc->clk_reg); + + return 0; +} + +static const struct of_device_id lpc18xx_rgu_match[] = { + { .compatible = "nxp,lpc1850-rgu" }, + { } +}; +MODULE_DEVICE_TABLE(of, lpc18xx_rgu_match); + +static struct platform_driver lpc18xx_rgu_driver = { + .probe = lpc18xx_rgu_probe, + .remove = lpc18xx_rgu_remove, + .driver = { + .name = "lpc18xx-reset", + .of_match_table = lpc18xx_rgu_match, + }, +}; +module_platform_driver(lpc18xx_rgu_driver); + +MODULE_AUTHOR("Joachim Eastwood <manabian@gmail.com>"); +MODULE_DESCRIPTION("Reset driver for LPC18xx/43xx RGU"); +MODULE_LICENSE("GPL v2"); diff --git a/kernel/drivers/reset/reset-socfpga.c b/kernel/drivers/reset/reset-socfpga.c index 0a8def35e..1a6c5d66c 100644 --- a/kernel/drivers/reset/reset-socfpga.c +++ b/kernel/drivers/reset/reset-socfpga.c @@ -24,11 +24,11 @@ #include <linux/types.h> #define NR_BANKS 4 -#define OFFSET_MODRST 0x10 struct socfpga_reset_data { spinlock_t lock; void __iomem *membase; + u32 modrst_offset; struct reset_controller_dev rcdev; }; @@ -45,8 +45,8 @@ static int socfpga_reset_assert(struct reset_controller_dev *rcdev, spin_lock_irqsave(&data->lock, flags); - reg = readl(data->membase + OFFSET_MODRST + (bank * NR_BANKS)); - writel(reg | BIT(offset), data->membase + OFFSET_MODRST + + reg = readl(data->membase + data->modrst_offset + (bank * NR_BANKS)); + writel(reg | BIT(offset), data->membase + data->modrst_offset + (bank * NR_BANKS)); spin_unlock_irqrestore(&data->lock, flags); @@ -67,8 +67,8 @@ static int socfpga_reset_deassert(struct reset_controller_dev *rcdev, spin_lock_irqsave(&data->lock, flags); - reg = readl(data->membase + OFFSET_MODRST + (bank * NR_BANKS)); - writel(reg & ~BIT(offset), data->membase + OFFSET_MODRST + + reg = readl(data->membase + data->modrst_offset + (bank * NR_BANKS)); + writel(reg & ~BIT(offset), data->membase + data->modrst_offset + (bank * NR_BANKS)); spin_unlock_irqrestore(&data->lock, flags); @@ -85,7 +85,7 @@ static int socfpga_reset_status(struct reset_controller_dev *rcdev, int offset = id % BITS_PER_LONG; u32 reg; - reg = readl(data->membase + OFFSET_MODRST + (bank * NR_BANKS)); + reg = readl(data->membase + data->modrst_offset + (bank * NR_BANKS)); return !(reg & BIT(offset)); } @@ -100,6 +100,8 @@ static int socfpga_reset_probe(struct platform_device *pdev) { struct socfpga_reset_data *data; struct resource *res; + struct device *dev = &pdev->dev; + struct device_node *np = dev->of_node; /* * The binding was mainlined without the required property. @@ -120,6 +122,11 @@ static int socfpga_reset_probe(struct platform_device *pdev) if (IS_ERR(data->membase)) return PTR_ERR(data->membase); + if (of_property_read_u32(np, "altr,modrst-offset", &data->modrst_offset)) { + dev_warn(dev, "missing altr,modrst-offset property, assuming 0x10!\n"); + data->modrst_offset = 0x10; + } + spin_lock_init(&data->lock); data->rcdev.owner = THIS_MODULE; diff --git a/kernel/drivers/reset/reset-zynq.c b/kernel/drivers/reset/reset-zynq.c new file mode 100644 index 000000000..89318a5d5 --- /dev/null +++ b/kernel/drivers/reset/reset-zynq.c @@ -0,0 +1,155 @@ +/* + * Copyright (c) 2015, National Instruments Corp. + * + * Xilinx Zynq Reset controller driver + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <linux/err.h> +#include <linux/io.h> +#include <linux/module.h> +#include <linux/mfd/syscon.h> +#include <linux/of.h> +#include <linux/platform_device.h> +#include <linux/reset-controller.h> +#include <linux/regmap.h> +#include <linux/types.h> + +struct zynq_reset_data { + struct regmap *slcr; + struct reset_controller_dev rcdev; + u32 offset; +}; + +#define to_zynq_reset_data(p) \ + container_of((p), struct zynq_reset_data, rcdev) + +static int zynq_reset_assert(struct reset_controller_dev *rcdev, + unsigned long id) +{ + struct zynq_reset_data *priv = to_zynq_reset_data(rcdev); + + int bank = id / BITS_PER_LONG; + int offset = id % BITS_PER_LONG; + + pr_debug("%s: %s reset bank %u offset %u\n", KBUILD_MODNAME, __func__, + bank, offset); + + return regmap_update_bits(priv->slcr, + priv->offset + (bank * 4), + BIT(offset), + BIT(offset)); +} + +static int zynq_reset_deassert(struct reset_controller_dev *rcdev, + unsigned long id) +{ + struct zynq_reset_data *priv = to_zynq_reset_data(rcdev); + + int bank = id / BITS_PER_LONG; + int offset = id % BITS_PER_LONG; + + pr_debug("%s: %s reset bank %u offset %u\n", KBUILD_MODNAME, __func__, + bank, offset); + + return regmap_update_bits(priv->slcr, + priv->offset + (bank * 4), + BIT(offset), + ~BIT(offset)); +} + +static int zynq_reset_status(struct reset_controller_dev *rcdev, + unsigned long id) +{ + struct zynq_reset_data *priv = to_zynq_reset_data(rcdev); + + int bank = id / BITS_PER_LONG; + int offset = id % BITS_PER_LONG; + int ret; + u32 reg; + + pr_debug("%s: %s reset bank %u offset %u\n", KBUILD_MODNAME, __func__, + bank, offset); + + ret = regmap_read(priv->slcr, priv->offset + (bank * 4), ®); + if (ret) + return ret; + + return !!(reg & BIT(offset)); +} + +static struct reset_control_ops zynq_reset_ops = { + .assert = zynq_reset_assert, + .deassert = zynq_reset_deassert, + .status = zynq_reset_status, +}; + +static int zynq_reset_probe(struct platform_device *pdev) +{ + struct resource *res; + struct zynq_reset_data *priv; + + priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + platform_set_drvdata(pdev, priv); + + priv->slcr = syscon_regmap_lookup_by_phandle(pdev->dev.of_node, + "syscon"); + if (IS_ERR(priv->slcr)) { + dev_err(&pdev->dev, "unable to get zynq-slcr regmap"); + return PTR_ERR(priv->slcr); + } + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + dev_err(&pdev->dev, "missing IO resource\n"); + return -ENODEV; + } + + priv->offset = res->start; + + priv->rcdev.owner = THIS_MODULE; + priv->rcdev.nr_resets = resource_size(res) / 4 * BITS_PER_LONG; + priv->rcdev.ops = &zynq_reset_ops; + priv->rcdev.of_node = pdev->dev.of_node; + reset_controller_register(&priv->rcdev); + + return 0; +} + +static int zynq_reset_remove(struct platform_device *pdev) +{ + struct zynq_reset_data *priv = platform_get_drvdata(pdev); + + reset_controller_unregister(&priv->rcdev); + + return 0; +} + +static const struct of_device_id zynq_reset_dt_ids[] = { + { .compatible = "xlnx,zynq-reset", }, + { /* sentinel */ }, +}; + +static struct platform_driver zynq_reset_driver = { + .probe = zynq_reset_probe, + .remove = zynq_reset_remove, + .driver = { + .name = KBUILD_MODNAME, + .of_match_table = zynq_reset_dt_ids, + }, +}; +module_platform_driver(zynq_reset_driver); + +MODULE_LICENSE("GPL v2"); +MODULE_AUTHOR("Moritz Fischer <moritz.fischer@ettus.com>"); +MODULE_DESCRIPTION("Zynq Reset Controller Driver"); diff --git a/kernel/drivers/reset/sti/reset-stih407.c b/kernel/drivers/reset/sti/reset-stih407.c index d83db5d72..827eb3dae 100644 --- a/kernel/drivers/reset/sti/reset-stih407.c +++ b/kernel/drivers/reset/sti/reset-stih407.c @@ -11,7 +11,7 @@ #include <linux/of.h> #include <linux/of_platform.h> #include <linux/platform_device.h> -#include <dt-bindings/reset-controller/stih407-resets.h> +#include <dt-bindings/reset/stih407-resets.h> #include "reset-syscfg.h" /* STiH407 Peripheral powerdown definitions. */ @@ -126,7 +126,7 @@ static const struct syscfg_reset_controller_data stih407_picophyreset_controller .channels = stih407_picophyresets, }; -static struct of_device_id stih407_reset_match[] = { +static const struct of_device_id stih407_reset_match[] = { { .compatible = "st,stih407-powerdown", .data = &stih407_powerdown_controller, diff --git a/kernel/drivers/reset/sti/reset-stih415.c b/kernel/drivers/reset/sti/reset-stih415.c index 8dad603d8..6f220cdbe 100644 --- a/kernel/drivers/reset/sti/reset-stih415.c +++ b/kernel/drivers/reset/sti/reset-stih415.c @@ -13,7 +13,7 @@ #include <linux/of_platform.h> #include <linux/platform_device.h> -#include <dt-bindings/reset-controller/stih415-resets.h> +#include <dt-bindings/reset/stih415-resets.h> #include "reset-syscfg.h" @@ -89,7 +89,7 @@ static struct syscfg_reset_controller_data stih415_softreset_controller = { .channels = stih415_softresets, }; -static struct of_device_id stih415_reset_match[] = { +static const struct of_device_id stih415_reset_match[] = { { .compatible = "st,stih415-powerdown", .data = &stih415_powerdown_controller, }, { .compatible = "st,stih415-softreset", diff --git a/kernel/drivers/reset/sti/reset-stih416.c b/kernel/drivers/reset/sti/reset-stih416.c index 79aed70a2..c581d606e 100644 --- a/kernel/drivers/reset/sti/reset-stih416.c +++ b/kernel/drivers/reset/sti/reset-stih416.c @@ -13,7 +13,7 @@ #include <linux/of_platform.h> #include <linux/platform_device.h> -#include <dt-bindings/reset-controller/stih416-resets.h> +#include <dt-bindings/reset/stih416-resets.h> #include "reset-syscfg.h" @@ -120,7 +120,7 @@ static struct syscfg_reset_controller_data stih416_softreset_controller = { .channels = stih416_softresets, }; -static struct of_device_id stih416_reset_match[] = { +static const struct of_device_id stih416_reset_match[] = { { .compatible = "st,stih416-powerdown", .data = &stih416_powerdown_controller, }, { .compatible = "st,stih416-softreset", |