diff options
Diffstat (limited to 'drivers/reset')
-rw-r--r-- | drivers/reset/Kconfig | 1 | ||||
-rw-r--r-- | drivers/reset/Makefile | 1 | ||||
-rw-r--r-- | drivers/reset/core.c | 9 | ||||
-rw-r--r-- | drivers/reset/hisilicon/Kconfig | 5 | ||||
-rw-r--r-- | drivers/reset/hisilicon/Makefile | 1 | ||||
-rw-r--r-- | drivers/reset/hisilicon/hi6220_reset.c | 108 | ||||
-rw-r--r-- | drivers/reset/reset-ath79.c | 30 |
7 files changed, 146 insertions, 9 deletions
diff --git a/drivers/reset/Kconfig b/drivers/reset/Kconfig index 0615f50a14cd..df37212a5cbd 100644 --- a/drivers/reset/Kconfig +++ b/drivers/reset/Kconfig @@ -13,3 +13,4 @@ menuconfig RESET_CONTROLLER If unsure, say no. source "drivers/reset/sti/Kconfig" +source "drivers/reset/hisilicon/Kconfig" diff --git a/drivers/reset/Makefile b/drivers/reset/Makefile index f191cf33be16..4d7178e46afa 100644 --- a/drivers/reset/Makefile +++ b/drivers/reset/Makefile @@ -4,5 +4,6 @@ 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_HISI) += hisilicon/ obj-$(CONFIG_ARCH_ZYNQ) += reset-zynq.o obj-$(CONFIG_ATH79) += reset-ath79.o diff --git a/drivers/reset/core.c b/drivers/reset/core.c index 9ab929049b9d..87376638948d 100644 --- a/drivers/reset/core.c +++ b/drivers/reset/core.c @@ -30,7 +30,6 @@ static LIST_HEAD(reset_controller_list); */ struct reset_control { struct reset_controller_dev *rcdev; - struct device *dev; unsigned int id; }; @@ -236,16 +235,10 @@ EXPORT_SYMBOL_GPL(of_reset_control_get); */ struct reset_control *reset_control_get(struct device *dev, const char *id) { - struct reset_control *rstc; - if (!dev) return ERR_PTR(-EINVAL); - rstc = of_reset_control_get(dev->of_node, id); - if (!IS_ERR(rstc)) - rstc->dev = dev; - - return rstc; + return of_reset_control_get(dev->of_node, id); } EXPORT_SYMBOL_GPL(reset_control_get); diff --git a/drivers/reset/hisilicon/Kconfig b/drivers/reset/hisilicon/Kconfig new file mode 100644 index 000000000000..26bf95a83a8e --- /dev/null +++ b/drivers/reset/hisilicon/Kconfig @@ -0,0 +1,5 @@ +config COMMON_RESET_HI6220 + tristate "Hi6220 Reset Driver" + depends on (ARCH_HISI && RESET_CONTROLLER) + help + Build the Hisilicon Hi6220 reset driver. diff --git a/drivers/reset/hisilicon/Makefile b/drivers/reset/hisilicon/Makefile new file mode 100644 index 000000000000..c932f86e2f10 --- /dev/null +++ b/drivers/reset/hisilicon/Makefile @@ -0,0 +1 @@ +obj-$(CONFIG_COMMON_RESET_HI6220) += hi6220_reset.o diff --git a/drivers/reset/hisilicon/hi6220_reset.c b/drivers/reset/hisilicon/hi6220_reset.c new file mode 100644 index 000000000000..d17c910e8b63 --- /dev/null +++ b/drivers/reset/hisilicon/hi6220_reset.c @@ -0,0 +1,108 @@ +/* + * Hisilicon Hi6220 reset controller driver + * + * Copyright (c) 2015 Hisilicon Limited. + * + * Author: Feng Chen <puck.chen@hisilicon.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/init.h> +#include <linux/bitops.h> +#include <linux/of.h> +#include <linux/reset-controller.h> +#include <linux/reset.h> +#include <linux/platform_device.h> + +#define ASSERT_OFFSET 0x300 +#define DEASSERT_OFFSET 0x304 +#define MAX_INDEX 0x509 + +#define to_reset_data(x) container_of(x, struct hi6220_reset_data, rc_dev) + +struct hi6220_reset_data { + void __iomem *assert_base; + void __iomem *deassert_base; + struct reset_controller_dev rc_dev; +}; + +static int hi6220_reset_assert(struct reset_controller_dev *rc_dev, + unsigned long idx) +{ + struct hi6220_reset_data *data = to_reset_data(rc_dev); + + int bank = idx >> 8; + int offset = idx & 0xff; + + writel(BIT(offset), data->assert_base + (bank * 0x10)); + + return 0; +} + +static int hi6220_reset_deassert(struct reset_controller_dev *rc_dev, + unsigned long idx) +{ + struct hi6220_reset_data *data = to_reset_data(rc_dev); + + int bank = idx >> 8; + int offset = idx & 0xff; + + writel(BIT(offset), data->deassert_base + (bank * 0x10)); + + return 0; +} + +static struct reset_control_ops hi6220_reset_ops = { + .assert = hi6220_reset_assert, + .deassert = hi6220_reset_deassert, +}; + +static int hi6220_reset_probe(struct platform_device *pdev) +{ + struct hi6220_reset_data *data; + struct resource *res; + void __iomem *src_base; + + data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL); + if (!data) + return -ENOMEM; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + src_base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(src_base)) + return PTR_ERR(src_base); + + data->assert_base = src_base + ASSERT_OFFSET; + data->deassert_base = src_base + DEASSERT_OFFSET; + data->rc_dev.nr_resets = MAX_INDEX; + data->rc_dev.ops = &hi6220_reset_ops; + data->rc_dev.of_node = pdev->dev.of_node; + + reset_controller_register(&data->rc_dev); + + return 0; +} + +static const struct of_device_id hi6220_reset_match[] = { + { .compatible = "hisilicon,hi6220-sysctrl" }, + { }, +}; + +static struct platform_driver hi6220_reset_driver = { + .probe = hi6220_reset_probe, + .driver = { + .name = "reset-hi6220", + .of_match_table = hi6220_reset_match, + }, +}; + +static int __init hi6220_reset_init(void) +{ + return platform_driver_register(&hi6220_reset_driver); +} + +postcore_initcall(hi6220_reset_init); diff --git a/drivers/reset/reset-ath79.c b/drivers/reset/reset-ath79.c index 9aaf646ece55..692fc890e94b 100644 --- a/drivers/reset/reset-ath79.c +++ b/drivers/reset/reset-ath79.c @@ -15,13 +15,17 @@ #include <linux/module.h> #include <linux/platform_device.h> #include <linux/reset-controller.h> +#include <linux/reboot.h> struct ath79_reset { struct reset_controller_dev rcdev; + struct notifier_block restart_nb; void __iomem *base; spinlock_t lock; }; +#define FULL_CHIP_RESET 24 + static int ath79_reset_update(struct reset_controller_dev *rcdev, unsigned long id, bool assert) { @@ -72,10 +76,22 @@ static struct reset_control_ops ath79_reset_ops = { .status = ath79_reset_status, }; +static int ath79_reset_restart_handler(struct notifier_block *nb, + unsigned long action, void *data) +{ + struct ath79_reset *ath79_reset = + container_of(nb, struct ath79_reset, restart_nb); + + ath79_reset_assert(&ath79_reset->rcdev, FULL_CHIP_RESET); + + return NOTIFY_DONE; +} + static int ath79_reset_probe(struct platform_device *pdev) { struct ath79_reset *ath79_reset; struct resource *res; + int err; ath79_reset = devm_kzalloc(&pdev->dev, sizeof(*ath79_reset), GFP_KERNEL); @@ -96,13 +112,25 @@ static int ath79_reset_probe(struct platform_device *pdev) ath79_reset->rcdev.of_reset_n_cells = 1; ath79_reset->rcdev.nr_resets = 32; - return reset_controller_register(&ath79_reset->rcdev); + err = reset_controller_register(&ath79_reset->rcdev); + if (err) + return err; + + ath79_reset->restart_nb.notifier_call = ath79_reset_restart_handler; + ath79_reset->restart_nb.priority = 128; + + err = register_restart_handler(&ath79_reset->restart_nb); + if (err) + dev_warn(&pdev->dev, "Failed to register restart handler\n"); + + return 0; } static int ath79_reset_remove(struct platform_device *pdev) { struct ath79_reset *ath79_reset = platform_get_drvdata(pdev); + unregister_restart_handler(&ath79_reset->restart_nb); reset_controller_unregister(&ath79_reset->rcdev); return 0; |