162306a36Sopenharmony_ci/*
262306a36Sopenharmony_ci * Atmel AT91 SAM9 & SAMA5 SoCs reset code
362306a36Sopenharmony_ci *
462306a36Sopenharmony_ci * Copyright (C) 2007 Atmel Corporation.
562306a36Sopenharmony_ci * Copyright (C) BitBox Ltd 2010
662306a36Sopenharmony_ci * Copyright (C) 2011 Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcosoft.com>
762306a36Sopenharmony_ci * Copyright (C) 2014 Free Electrons
862306a36Sopenharmony_ci *
962306a36Sopenharmony_ci * This file is licensed under the terms of the GNU General Public
1062306a36Sopenharmony_ci * License version 2.  This program is licensed "as is" without any
1162306a36Sopenharmony_ci * warranty of any kind, whether express or implied.
1262306a36Sopenharmony_ci */
1362306a36Sopenharmony_ci
1462306a36Sopenharmony_ci#include <linux/clk.h>
1562306a36Sopenharmony_ci#include <linux/io.h>
1662306a36Sopenharmony_ci#include <linux/module.h>
1762306a36Sopenharmony_ci#include <linux/of_address.h>
1862306a36Sopenharmony_ci#include <linux/platform_device.h>
1962306a36Sopenharmony_ci#include <linux/reboot.h>
2062306a36Sopenharmony_ci#include <linux/reset-controller.h>
2162306a36Sopenharmony_ci#include <linux/power/power_on_reason.h>
2262306a36Sopenharmony_ci
2362306a36Sopenharmony_ci#include <soc/at91/at91sam9_ddrsdr.h>
2462306a36Sopenharmony_ci#include <soc/at91/at91sam9_sdramc.h>
2562306a36Sopenharmony_ci
2662306a36Sopenharmony_ci#include <dt-bindings/reset/sama7g5-reset.h>
2762306a36Sopenharmony_ci
2862306a36Sopenharmony_ci#define AT91_RSTC_CR	0x00		/* Reset Controller Control Register */
2962306a36Sopenharmony_ci#define AT91_RSTC_PROCRST	BIT(0)		/* Processor Reset */
3062306a36Sopenharmony_ci#define AT91_RSTC_PERRST	BIT(2)		/* Peripheral Reset */
3162306a36Sopenharmony_ci#define AT91_RSTC_EXTRST	BIT(3)		/* External Reset */
3262306a36Sopenharmony_ci#define AT91_RSTC_KEY		(0xa5 << 24)	/* KEY Password */
3362306a36Sopenharmony_ci
3462306a36Sopenharmony_ci#define AT91_RSTC_SR	0x04		/* Reset Controller Status Register */
3562306a36Sopenharmony_ci#define AT91_RSTC_URSTS		BIT(0)		/* User Reset Status */
3662306a36Sopenharmony_ci#define AT91_RSTC_RSTTYP	GENMASK(10, 8)	/* Reset Type */
3762306a36Sopenharmony_ci#define AT91_RSTC_NRSTL		BIT(16)		/* NRST Pin Level */
3862306a36Sopenharmony_ci#define AT91_RSTC_SRCMP		BIT(17)		/* Software Reset Command in Progress */
3962306a36Sopenharmony_ci
4062306a36Sopenharmony_ci#define AT91_RSTC_MR	0x08		/* Reset Controller Mode Register */
4162306a36Sopenharmony_ci#define AT91_RSTC_URSTEN	BIT(0)		/* User Reset Enable */
4262306a36Sopenharmony_ci#define AT91_RSTC_URSTASYNC	BIT(2)		/* User Reset Asynchronous Control */
4362306a36Sopenharmony_ci#define AT91_RSTC_URSTIEN	BIT(4)		/* User Reset Interrupt Enable */
4462306a36Sopenharmony_ci#define AT91_RSTC_ERSTL		GENMASK(11, 8)	/* External Reset Length */
4562306a36Sopenharmony_ci
4662306a36Sopenharmony_ci/**
4762306a36Sopenharmony_ci * enum reset_type - reset types
4862306a36Sopenharmony_ci * @RESET_TYPE_GENERAL:		first power-up reset
4962306a36Sopenharmony_ci * @RESET_TYPE_WAKEUP:		return from backup mode
5062306a36Sopenharmony_ci * @RESET_TYPE_WATCHDOG:	watchdog fault
5162306a36Sopenharmony_ci * @RESET_TYPE_SOFTWARE:	processor reset required by software
5262306a36Sopenharmony_ci * @RESET_TYPE_USER:		NRST pin detected low
5362306a36Sopenharmony_ci * @RESET_TYPE_CPU_FAIL:	CPU clock failure detection
5462306a36Sopenharmony_ci * @RESET_TYPE_XTAL_FAIL:	32KHz crystal failure dectection fault
5562306a36Sopenharmony_ci * @RESET_TYPE_ULP2:		ULP2 reset
5662306a36Sopenharmony_ci */
5762306a36Sopenharmony_cienum reset_type {
5862306a36Sopenharmony_ci	RESET_TYPE_GENERAL	= 0,
5962306a36Sopenharmony_ci	RESET_TYPE_WAKEUP	= 1,
6062306a36Sopenharmony_ci	RESET_TYPE_WATCHDOG	= 2,
6162306a36Sopenharmony_ci	RESET_TYPE_SOFTWARE	= 3,
6262306a36Sopenharmony_ci	RESET_TYPE_USER		= 4,
6362306a36Sopenharmony_ci	RESET_TYPE_CPU_FAIL	= 6,
6462306a36Sopenharmony_ci	RESET_TYPE_XTAL_FAIL	= 7,
6562306a36Sopenharmony_ci	RESET_TYPE_ULP2		= 8,
6662306a36Sopenharmony_ci};
6762306a36Sopenharmony_ci
6862306a36Sopenharmony_ci/**
6962306a36Sopenharmony_ci * struct at91_reset - AT91 reset specific data structure
7062306a36Sopenharmony_ci * @rstc_base:		base address for system reset
7162306a36Sopenharmony_ci * @ramc_base:		array with base addresses of RAM controllers
7262306a36Sopenharmony_ci * @dev_base:		base address for devices reset
7362306a36Sopenharmony_ci * @sclk:		slow clock
7462306a36Sopenharmony_ci * @data:		platform specific reset data
7562306a36Sopenharmony_ci * @rcdev:		reset controller device
7662306a36Sopenharmony_ci * @lock:		lock for devices reset register access
7762306a36Sopenharmony_ci * @nb:			reset notifier block
7862306a36Sopenharmony_ci * @args:		SoC specific system reset arguments
7962306a36Sopenharmony_ci * @ramc_lpr:		SDRAM Controller Low Power Register
8062306a36Sopenharmony_ci */
8162306a36Sopenharmony_cistruct at91_reset {
8262306a36Sopenharmony_ci	void __iomem *rstc_base;
8362306a36Sopenharmony_ci	void __iomem *ramc_base[2];
8462306a36Sopenharmony_ci	void __iomem *dev_base;
8562306a36Sopenharmony_ci	struct clk *sclk;
8662306a36Sopenharmony_ci	const struct at91_reset_data *data;
8762306a36Sopenharmony_ci	struct reset_controller_dev rcdev;
8862306a36Sopenharmony_ci	spinlock_t lock;
8962306a36Sopenharmony_ci	struct notifier_block nb;
9062306a36Sopenharmony_ci	u32 args;
9162306a36Sopenharmony_ci	u32 ramc_lpr;
9262306a36Sopenharmony_ci};
9362306a36Sopenharmony_ci
9462306a36Sopenharmony_ci#define to_at91_reset(r)	container_of(r, struct at91_reset, rcdev)
9562306a36Sopenharmony_ci
9662306a36Sopenharmony_ci/**
9762306a36Sopenharmony_ci * struct at91_reset_data - AT91 reset data
9862306a36Sopenharmony_ci * @reset_args:			SoC specific system reset arguments
9962306a36Sopenharmony_ci * @n_device_reset:		number of device resets
10062306a36Sopenharmony_ci * @device_reset_min_id:	min id for device reset
10162306a36Sopenharmony_ci * @device_reset_max_id:	max id for device reset
10262306a36Sopenharmony_ci */
10362306a36Sopenharmony_cistruct at91_reset_data {
10462306a36Sopenharmony_ci	u32 reset_args;
10562306a36Sopenharmony_ci	u32 n_device_reset;
10662306a36Sopenharmony_ci	u8 device_reset_min_id;
10762306a36Sopenharmony_ci	u8 device_reset_max_id;
10862306a36Sopenharmony_ci};
10962306a36Sopenharmony_ci
11062306a36Sopenharmony_ci/*
11162306a36Sopenharmony_ci* unless the SDRAM is cleanly shutdown before we hit the
11262306a36Sopenharmony_ci* reset register it can be left driving the data bus and
11362306a36Sopenharmony_ci* killing the chance of a subsequent boot from NAND
11462306a36Sopenharmony_ci*/
11562306a36Sopenharmony_cistatic int at91_reset(struct notifier_block *this, unsigned long mode,
11662306a36Sopenharmony_ci		      void *cmd)
11762306a36Sopenharmony_ci{
11862306a36Sopenharmony_ci	struct at91_reset *reset = container_of(this, struct at91_reset, nb);
11962306a36Sopenharmony_ci
12062306a36Sopenharmony_ci	asm volatile(
12162306a36Sopenharmony_ci		/* Align to cache lines */
12262306a36Sopenharmony_ci		".balign 32\n\t"
12362306a36Sopenharmony_ci
12462306a36Sopenharmony_ci		/* Disable SDRAM0 accesses */
12562306a36Sopenharmony_ci		"	tst	%0, #0\n\t"
12662306a36Sopenharmony_ci		"	beq	1f\n\t"
12762306a36Sopenharmony_ci		"	str	%3, [%0, #" __stringify(AT91_DDRSDRC_RTR) "]\n\t"
12862306a36Sopenharmony_ci		/* Power down SDRAM0 */
12962306a36Sopenharmony_ci		"	str	%4, [%0, %6]\n\t"
13062306a36Sopenharmony_ci		/* Disable SDRAM1 accesses */
13162306a36Sopenharmony_ci		"1:	tst	%1, #0\n\t"
13262306a36Sopenharmony_ci		"	beq	2f\n\t"
13362306a36Sopenharmony_ci		"	strne	%3, [%1, #" __stringify(AT91_DDRSDRC_RTR) "]\n\t"
13462306a36Sopenharmony_ci		/* Power down SDRAM1 */
13562306a36Sopenharmony_ci		"	strne	%4, [%1, %6]\n\t"
13662306a36Sopenharmony_ci		/* Reset CPU */
13762306a36Sopenharmony_ci		"2:	str	%5, [%2, #" __stringify(AT91_RSTC_CR) "]\n\t"
13862306a36Sopenharmony_ci
13962306a36Sopenharmony_ci		"	b	.\n\t"
14062306a36Sopenharmony_ci		:
14162306a36Sopenharmony_ci		: "r" (reset->ramc_base[0]),
14262306a36Sopenharmony_ci		  "r" (reset->ramc_base[1]),
14362306a36Sopenharmony_ci		  "r" (reset->rstc_base),
14462306a36Sopenharmony_ci		  "r" (1),
14562306a36Sopenharmony_ci		  "r" cpu_to_le32(AT91_DDRSDRC_LPCB_POWER_DOWN),
14662306a36Sopenharmony_ci		  "r" (reset->data->reset_args),
14762306a36Sopenharmony_ci		  "r" (reset->ramc_lpr)
14862306a36Sopenharmony_ci		: "r4");
14962306a36Sopenharmony_ci
15062306a36Sopenharmony_ci	return NOTIFY_DONE;
15162306a36Sopenharmony_ci}
15262306a36Sopenharmony_ci
15362306a36Sopenharmony_cistatic const char *at91_reset_reason(struct at91_reset *reset)
15462306a36Sopenharmony_ci{
15562306a36Sopenharmony_ci	u32 reg = readl(reset->rstc_base + AT91_RSTC_SR);
15662306a36Sopenharmony_ci	const char *reason;
15762306a36Sopenharmony_ci
15862306a36Sopenharmony_ci	switch ((reg & AT91_RSTC_RSTTYP) >> 8) {
15962306a36Sopenharmony_ci	case RESET_TYPE_GENERAL:
16062306a36Sopenharmony_ci		reason = POWER_ON_REASON_REGULAR;
16162306a36Sopenharmony_ci		break;
16262306a36Sopenharmony_ci	case RESET_TYPE_WAKEUP:
16362306a36Sopenharmony_ci		reason = POWER_ON_REASON_RTC;
16462306a36Sopenharmony_ci		break;
16562306a36Sopenharmony_ci	case RESET_TYPE_WATCHDOG:
16662306a36Sopenharmony_ci		reason = POWER_ON_REASON_WATCHDOG;
16762306a36Sopenharmony_ci		break;
16862306a36Sopenharmony_ci	case RESET_TYPE_SOFTWARE:
16962306a36Sopenharmony_ci		reason = POWER_ON_REASON_SOFTWARE;
17062306a36Sopenharmony_ci		break;
17162306a36Sopenharmony_ci	case RESET_TYPE_USER:
17262306a36Sopenharmony_ci		reason = POWER_ON_REASON_RST_BTN;
17362306a36Sopenharmony_ci		break;
17462306a36Sopenharmony_ci	case RESET_TYPE_CPU_FAIL:
17562306a36Sopenharmony_ci		reason = POWER_ON_REASON_CPU_CLK_FAIL;
17662306a36Sopenharmony_ci		break;
17762306a36Sopenharmony_ci	case RESET_TYPE_XTAL_FAIL:
17862306a36Sopenharmony_ci		reason = POWER_ON_REASON_XTAL_FAIL;
17962306a36Sopenharmony_ci		break;
18062306a36Sopenharmony_ci	case RESET_TYPE_ULP2:
18162306a36Sopenharmony_ci		reason = POWER_ON_REASON_BROWN_OUT;
18262306a36Sopenharmony_ci		break;
18362306a36Sopenharmony_ci	default:
18462306a36Sopenharmony_ci		reason = POWER_ON_REASON_UNKNOWN;
18562306a36Sopenharmony_ci		break;
18662306a36Sopenharmony_ci	}
18762306a36Sopenharmony_ci
18862306a36Sopenharmony_ci	return reason;
18962306a36Sopenharmony_ci}
19062306a36Sopenharmony_ci
19162306a36Sopenharmony_cistatic ssize_t power_on_reason_show(struct device *dev,
19262306a36Sopenharmony_ci				    struct device_attribute *attr, char *buf)
19362306a36Sopenharmony_ci{
19462306a36Sopenharmony_ci	struct platform_device *pdev = to_platform_device(dev);
19562306a36Sopenharmony_ci	struct at91_reset *reset = platform_get_drvdata(pdev);
19662306a36Sopenharmony_ci
19762306a36Sopenharmony_ci	return sprintf(buf, "%s\n", at91_reset_reason(reset));
19862306a36Sopenharmony_ci}
19962306a36Sopenharmony_cistatic DEVICE_ATTR_RO(power_on_reason);
20062306a36Sopenharmony_ci
20162306a36Sopenharmony_cistatic const struct of_device_id at91_ramc_of_match[] = {
20262306a36Sopenharmony_ci	{
20362306a36Sopenharmony_ci		.compatible = "atmel,at91sam9260-sdramc",
20462306a36Sopenharmony_ci		.data = (void *)AT91_SDRAMC_LPR,
20562306a36Sopenharmony_ci	},
20662306a36Sopenharmony_ci	{
20762306a36Sopenharmony_ci		.compatible = "atmel,at91sam9g45-ddramc",
20862306a36Sopenharmony_ci		.data = (void *)AT91_DDRSDRC_LPR,
20962306a36Sopenharmony_ci	},
21062306a36Sopenharmony_ci	{ /* sentinel */ }
21162306a36Sopenharmony_ci};
21262306a36Sopenharmony_ci
21362306a36Sopenharmony_cistatic const struct at91_reset_data sam9260 = {
21462306a36Sopenharmony_ci	.reset_args = AT91_RSTC_KEY | AT91_RSTC_PERRST | AT91_RSTC_PROCRST,
21562306a36Sopenharmony_ci};
21662306a36Sopenharmony_ci
21762306a36Sopenharmony_cistatic const struct at91_reset_data samx7 = {
21862306a36Sopenharmony_ci	.reset_args = AT91_RSTC_KEY | AT91_RSTC_PROCRST,
21962306a36Sopenharmony_ci};
22062306a36Sopenharmony_ci
22162306a36Sopenharmony_cistatic const struct at91_reset_data sama7g5 = {
22262306a36Sopenharmony_ci	.reset_args = AT91_RSTC_KEY | AT91_RSTC_PROCRST,
22362306a36Sopenharmony_ci	.n_device_reset = 3,
22462306a36Sopenharmony_ci	.device_reset_min_id = SAMA7G5_RESET_USB_PHY1,
22562306a36Sopenharmony_ci	.device_reset_max_id = SAMA7G5_RESET_USB_PHY3,
22662306a36Sopenharmony_ci};
22762306a36Sopenharmony_ci
22862306a36Sopenharmony_cistatic const struct of_device_id at91_reset_of_match[] = {
22962306a36Sopenharmony_ci	{
23062306a36Sopenharmony_ci		.compatible = "atmel,at91sam9260-rstc",
23162306a36Sopenharmony_ci		.data = &sam9260,
23262306a36Sopenharmony_ci	},
23362306a36Sopenharmony_ci	{
23462306a36Sopenharmony_ci		.compatible = "atmel,at91sam9g45-rstc",
23562306a36Sopenharmony_ci		.data = &sam9260,
23662306a36Sopenharmony_ci	},
23762306a36Sopenharmony_ci	{
23862306a36Sopenharmony_ci		.compatible = "atmel,sama5d3-rstc",
23962306a36Sopenharmony_ci		.data = &sam9260,
24062306a36Sopenharmony_ci	},
24162306a36Sopenharmony_ci	{
24262306a36Sopenharmony_ci		.compatible = "atmel,samx7-rstc",
24362306a36Sopenharmony_ci		.data = &samx7,
24462306a36Sopenharmony_ci	},
24562306a36Sopenharmony_ci	{
24662306a36Sopenharmony_ci		.compatible = "microchip,sam9x60-rstc",
24762306a36Sopenharmony_ci		.data = &samx7,
24862306a36Sopenharmony_ci	},
24962306a36Sopenharmony_ci	{
25062306a36Sopenharmony_ci		.compatible = "microchip,sama7g5-rstc",
25162306a36Sopenharmony_ci		.data = &sama7g5,
25262306a36Sopenharmony_ci	},
25362306a36Sopenharmony_ci	{ /* sentinel */ }
25462306a36Sopenharmony_ci};
25562306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, at91_reset_of_match);
25662306a36Sopenharmony_ci
25762306a36Sopenharmony_cistatic int at91_reset_update(struct reset_controller_dev *rcdev,
25862306a36Sopenharmony_ci			     unsigned long id, bool assert)
25962306a36Sopenharmony_ci{
26062306a36Sopenharmony_ci	struct at91_reset *reset = to_at91_reset(rcdev);
26162306a36Sopenharmony_ci	unsigned long flags;
26262306a36Sopenharmony_ci	u32 val;
26362306a36Sopenharmony_ci
26462306a36Sopenharmony_ci	spin_lock_irqsave(&reset->lock, flags);
26562306a36Sopenharmony_ci	val = readl_relaxed(reset->dev_base);
26662306a36Sopenharmony_ci	if (assert)
26762306a36Sopenharmony_ci		val |= BIT(id);
26862306a36Sopenharmony_ci	else
26962306a36Sopenharmony_ci		val &= ~BIT(id);
27062306a36Sopenharmony_ci	writel_relaxed(val, reset->dev_base);
27162306a36Sopenharmony_ci	spin_unlock_irqrestore(&reset->lock, flags);
27262306a36Sopenharmony_ci
27362306a36Sopenharmony_ci	return 0;
27462306a36Sopenharmony_ci}
27562306a36Sopenharmony_ci
27662306a36Sopenharmony_cistatic int at91_reset_assert(struct reset_controller_dev *rcdev,
27762306a36Sopenharmony_ci			     unsigned long id)
27862306a36Sopenharmony_ci{
27962306a36Sopenharmony_ci	return at91_reset_update(rcdev, id, true);
28062306a36Sopenharmony_ci}
28162306a36Sopenharmony_ci
28262306a36Sopenharmony_cistatic int at91_reset_deassert(struct reset_controller_dev *rcdev,
28362306a36Sopenharmony_ci			       unsigned long id)
28462306a36Sopenharmony_ci{
28562306a36Sopenharmony_ci	return at91_reset_update(rcdev, id, false);
28662306a36Sopenharmony_ci}
28762306a36Sopenharmony_ci
28862306a36Sopenharmony_cistatic int at91_reset_dev_status(struct reset_controller_dev *rcdev,
28962306a36Sopenharmony_ci				 unsigned long id)
29062306a36Sopenharmony_ci{
29162306a36Sopenharmony_ci	struct at91_reset *reset = to_at91_reset(rcdev);
29262306a36Sopenharmony_ci	u32 val;
29362306a36Sopenharmony_ci
29462306a36Sopenharmony_ci	val = readl_relaxed(reset->dev_base);
29562306a36Sopenharmony_ci
29662306a36Sopenharmony_ci	return !!(val & BIT(id));
29762306a36Sopenharmony_ci}
29862306a36Sopenharmony_ci
29962306a36Sopenharmony_cistatic const struct reset_control_ops at91_reset_ops = {
30062306a36Sopenharmony_ci	.assert = at91_reset_assert,
30162306a36Sopenharmony_ci	.deassert = at91_reset_deassert,
30262306a36Sopenharmony_ci	.status = at91_reset_dev_status,
30362306a36Sopenharmony_ci};
30462306a36Sopenharmony_ci
30562306a36Sopenharmony_cistatic int at91_reset_of_xlate(struct reset_controller_dev *rcdev,
30662306a36Sopenharmony_ci			       const struct of_phandle_args *reset_spec)
30762306a36Sopenharmony_ci{
30862306a36Sopenharmony_ci	struct at91_reset *reset = to_at91_reset(rcdev);
30962306a36Sopenharmony_ci
31062306a36Sopenharmony_ci	if (!reset->data->n_device_reset ||
31162306a36Sopenharmony_ci	    (reset_spec->args[0] < reset->data->device_reset_min_id ||
31262306a36Sopenharmony_ci	     reset_spec->args[0] > reset->data->device_reset_max_id))
31362306a36Sopenharmony_ci		return -EINVAL;
31462306a36Sopenharmony_ci
31562306a36Sopenharmony_ci	return reset_spec->args[0];
31662306a36Sopenharmony_ci}
31762306a36Sopenharmony_ci
31862306a36Sopenharmony_cistatic int at91_rcdev_init(struct at91_reset *reset,
31962306a36Sopenharmony_ci			   struct platform_device *pdev)
32062306a36Sopenharmony_ci{
32162306a36Sopenharmony_ci	if (!reset->data->n_device_reset)
32262306a36Sopenharmony_ci		return 0;
32362306a36Sopenharmony_ci
32462306a36Sopenharmony_ci	reset->dev_base = devm_of_iomap(&pdev->dev, pdev->dev.of_node, 1,
32562306a36Sopenharmony_ci					NULL);
32662306a36Sopenharmony_ci	if (IS_ERR(reset->dev_base))
32762306a36Sopenharmony_ci		return -ENODEV;
32862306a36Sopenharmony_ci
32962306a36Sopenharmony_ci	spin_lock_init(&reset->lock);
33062306a36Sopenharmony_ci	reset->rcdev.ops = &at91_reset_ops;
33162306a36Sopenharmony_ci	reset->rcdev.owner = THIS_MODULE;
33262306a36Sopenharmony_ci	reset->rcdev.of_node = pdev->dev.of_node;
33362306a36Sopenharmony_ci	reset->rcdev.nr_resets = reset->data->n_device_reset;
33462306a36Sopenharmony_ci	reset->rcdev.of_reset_n_cells = 1;
33562306a36Sopenharmony_ci	reset->rcdev.of_xlate = at91_reset_of_xlate;
33662306a36Sopenharmony_ci
33762306a36Sopenharmony_ci	return devm_reset_controller_register(&pdev->dev, &reset->rcdev);
33862306a36Sopenharmony_ci}
33962306a36Sopenharmony_ci
34062306a36Sopenharmony_cistatic int __init at91_reset_probe(struct platform_device *pdev)
34162306a36Sopenharmony_ci{
34262306a36Sopenharmony_ci	const struct of_device_id *match;
34362306a36Sopenharmony_ci	struct at91_reset *reset;
34462306a36Sopenharmony_ci	struct device_node *np;
34562306a36Sopenharmony_ci	int ret, idx = 0;
34662306a36Sopenharmony_ci
34762306a36Sopenharmony_ci	reset = devm_kzalloc(&pdev->dev, sizeof(*reset), GFP_KERNEL);
34862306a36Sopenharmony_ci	if (!reset)
34962306a36Sopenharmony_ci		return -ENOMEM;
35062306a36Sopenharmony_ci
35162306a36Sopenharmony_ci	reset->rstc_base = devm_of_iomap(&pdev->dev, pdev->dev.of_node, 0, NULL);
35262306a36Sopenharmony_ci	if (IS_ERR(reset->rstc_base)) {
35362306a36Sopenharmony_ci		dev_err(&pdev->dev, "Could not map reset controller address\n");
35462306a36Sopenharmony_ci		return -ENODEV;
35562306a36Sopenharmony_ci	}
35662306a36Sopenharmony_ci
35762306a36Sopenharmony_ci	if (!of_device_is_compatible(pdev->dev.of_node, "atmel,sama5d3-rstc")) {
35862306a36Sopenharmony_ci		/* we need to shutdown the ddr controller, so get ramc base */
35962306a36Sopenharmony_ci		for_each_matching_node_and_match(np, at91_ramc_of_match, &match) {
36062306a36Sopenharmony_ci			reset->ramc_lpr = (u32)match->data;
36162306a36Sopenharmony_ci			reset->ramc_base[idx] = devm_of_iomap(&pdev->dev, np, 0, NULL);
36262306a36Sopenharmony_ci			if (IS_ERR(reset->ramc_base[idx])) {
36362306a36Sopenharmony_ci				dev_err(&pdev->dev, "Could not map ram controller address\n");
36462306a36Sopenharmony_ci				of_node_put(np);
36562306a36Sopenharmony_ci				return -ENODEV;
36662306a36Sopenharmony_ci			}
36762306a36Sopenharmony_ci			idx++;
36862306a36Sopenharmony_ci		}
36962306a36Sopenharmony_ci	}
37062306a36Sopenharmony_ci
37162306a36Sopenharmony_ci	reset->data = device_get_match_data(&pdev->dev);
37262306a36Sopenharmony_ci	if (!reset->data)
37362306a36Sopenharmony_ci		return -ENODEV;
37462306a36Sopenharmony_ci
37562306a36Sopenharmony_ci	reset->nb.notifier_call = at91_reset;
37662306a36Sopenharmony_ci	reset->nb.priority = 192;
37762306a36Sopenharmony_ci
37862306a36Sopenharmony_ci	reset->sclk = devm_clk_get(&pdev->dev, NULL);
37962306a36Sopenharmony_ci	if (IS_ERR(reset->sclk))
38062306a36Sopenharmony_ci		return PTR_ERR(reset->sclk);
38162306a36Sopenharmony_ci
38262306a36Sopenharmony_ci	ret = clk_prepare_enable(reset->sclk);
38362306a36Sopenharmony_ci	if (ret) {
38462306a36Sopenharmony_ci		dev_err(&pdev->dev, "Could not enable slow clock\n");
38562306a36Sopenharmony_ci		return ret;
38662306a36Sopenharmony_ci	}
38762306a36Sopenharmony_ci
38862306a36Sopenharmony_ci	platform_set_drvdata(pdev, reset);
38962306a36Sopenharmony_ci
39062306a36Sopenharmony_ci	ret = at91_rcdev_init(reset, pdev);
39162306a36Sopenharmony_ci	if (ret)
39262306a36Sopenharmony_ci		goto disable_clk;
39362306a36Sopenharmony_ci
39462306a36Sopenharmony_ci	if (of_device_is_compatible(pdev->dev.of_node, "microchip,sam9x60-rstc")) {
39562306a36Sopenharmony_ci		u32 val = readl(reset->rstc_base + AT91_RSTC_MR);
39662306a36Sopenharmony_ci
39762306a36Sopenharmony_ci		writel(AT91_RSTC_KEY | AT91_RSTC_URSTASYNC | val,
39862306a36Sopenharmony_ci		       reset->rstc_base + AT91_RSTC_MR);
39962306a36Sopenharmony_ci	}
40062306a36Sopenharmony_ci
40162306a36Sopenharmony_ci	ret = register_restart_handler(&reset->nb);
40262306a36Sopenharmony_ci	if (ret)
40362306a36Sopenharmony_ci		goto disable_clk;
40462306a36Sopenharmony_ci
40562306a36Sopenharmony_ci	ret = device_create_file(&pdev->dev, &dev_attr_power_on_reason);
40662306a36Sopenharmony_ci	if (ret) {
40762306a36Sopenharmony_ci		dev_err(&pdev->dev, "Could not create sysfs entry\n");
40862306a36Sopenharmony_ci		return ret;
40962306a36Sopenharmony_ci	}
41062306a36Sopenharmony_ci
41162306a36Sopenharmony_ci	dev_info(&pdev->dev, "Starting after %s\n", at91_reset_reason(reset));
41262306a36Sopenharmony_ci
41362306a36Sopenharmony_ci	return 0;
41462306a36Sopenharmony_ci
41562306a36Sopenharmony_cidisable_clk:
41662306a36Sopenharmony_ci	clk_disable_unprepare(reset->sclk);
41762306a36Sopenharmony_ci	return ret;
41862306a36Sopenharmony_ci}
41962306a36Sopenharmony_ci
42062306a36Sopenharmony_cistatic int __exit at91_reset_remove(struct platform_device *pdev)
42162306a36Sopenharmony_ci{
42262306a36Sopenharmony_ci	struct at91_reset *reset = platform_get_drvdata(pdev);
42362306a36Sopenharmony_ci
42462306a36Sopenharmony_ci	unregister_restart_handler(&reset->nb);
42562306a36Sopenharmony_ci	clk_disable_unprepare(reset->sclk);
42662306a36Sopenharmony_ci
42762306a36Sopenharmony_ci	return 0;
42862306a36Sopenharmony_ci}
42962306a36Sopenharmony_ci
43062306a36Sopenharmony_cistatic struct platform_driver at91_reset_driver = {
43162306a36Sopenharmony_ci	.remove = __exit_p(at91_reset_remove),
43262306a36Sopenharmony_ci	.driver = {
43362306a36Sopenharmony_ci		.name = "at91-reset",
43462306a36Sopenharmony_ci		.of_match_table = at91_reset_of_match,
43562306a36Sopenharmony_ci	},
43662306a36Sopenharmony_ci};
43762306a36Sopenharmony_cimodule_platform_driver_probe(at91_reset_driver, at91_reset_probe);
43862306a36Sopenharmony_ci
43962306a36Sopenharmony_ciMODULE_AUTHOR("Atmel Corporation");
44062306a36Sopenharmony_ciMODULE_DESCRIPTION("Reset driver for Atmel SoCs");
44162306a36Sopenharmony_ciMODULE_LICENSE("GPL v2");
442