Linux Audio

Check our new training course

Loading...
Note: File does not exist in v3.1.
  1/*
  2 * AR71xx Reset Controller Driver
  3 * Author: Alban Bedel
  4 *
  5 * Copyright (C) 2015 Alban Bedel <albeu@free.fr>
  6 *
  7 * This program is free software; you can redistribute it and/or modify
  8 * it under the terms of the GNU General Public License as published by
  9 * the Free Software Foundation; either version 2 of the License, or
 10 * (at your option) any later version.
 11 *
 12 * This program is distributed in the hope that it will be useful,
 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 15 * GNU General Public License for more details.
 16 */
 17
 18#include <linux/io.h>
 19#include <linux/init.h>
 20#include <linux/platform_device.h>
 21#include <linux/reset-controller.h>
 22#include <linux/reboot.h>
 23
 24struct ath79_reset {
 25	struct reset_controller_dev rcdev;
 26	struct notifier_block restart_nb;
 27	void __iomem *base;
 28	spinlock_t lock;
 29};
 30
 31#define FULL_CHIP_RESET 24
 32
 33static int ath79_reset_update(struct reset_controller_dev *rcdev,
 34			unsigned long id, bool assert)
 35{
 36	struct ath79_reset *ath79_reset =
 37		container_of(rcdev, struct ath79_reset, rcdev);
 38	unsigned long flags;
 39	u32 val;
 40
 41	spin_lock_irqsave(&ath79_reset->lock, flags);
 42	val = readl(ath79_reset->base);
 43	if (assert)
 44		val |= BIT(id);
 45	else
 46		val &= ~BIT(id);
 47	writel(val, ath79_reset->base);
 48	spin_unlock_irqrestore(&ath79_reset->lock, flags);
 49
 50	return 0;
 51}
 52
 53static int ath79_reset_assert(struct reset_controller_dev *rcdev,
 54			unsigned long id)
 55{
 56	return ath79_reset_update(rcdev, id, true);
 57}
 58
 59static int ath79_reset_deassert(struct reset_controller_dev *rcdev,
 60				unsigned long id)
 61{
 62	return ath79_reset_update(rcdev, id, false);
 63}
 64
 65static int ath79_reset_status(struct reset_controller_dev *rcdev,
 66			unsigned long id)
 67{
 68	struct ath79_reset *ath79_reset =
 69		container_of(rcdev, struct ath79_reset, rcdev);
 70	u32 val;
 71
 72	val = readl(ath79_reset->base);
 73
 74	return !!(val & BIT(id));
 75}
 76
 77static const struct reset_control_ops ath79_reset_ops = {
 78	.assert = ath79_reset_assert,
 79	.deassert = ath79_reset_deassert,
 80	.status = ath79_reset_status,
 81};
 82
 83static int ath79_reset_restart_handler(struct notifier_block *nb,
 84				unsigned long action, void *data)
 85{
 86	struct ath79_reset *ath79_reset =
 87		container_of(nb, struct ath79_reset, restart_nb);
 88
 89	ath79_reset_assert(&ath79_reset->rcdev, FULL_CHIP_RESET);
 90
 91	return NOTIFY_DONE;
 92}
 93
 94static int ath79_reset_probe(struct platform_device *pdev)
 95{
 96	struct ath79_reset *ath79_reset;
 97	struct resource *res;
 98	int err;
 99
100	ath79_reset = devm_kzalloc(&pdev->dev,
101				sizeof(*ath79_reset), GFP_KERNEL);
102	if (!ath79_reset)
103		return -ENOMEM;
104
105	platform_set_drvdata(pdev, ath79_reset);
106
107	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
108	ath79_reset->base = devm_ioremap_resource(&pdev->dev, res);
109	if (IS_ERR(ath79_reset->base))
110		return PTR_ERR(ath79_reset->base);
111
112	spin_lock_init(&ath79_reset->lock);
113	ath79_reset->rcdev.ops = &ath79_reset_ops;
114	ath79_reset->rcdev.owner = THIS_MODULE;
115	ath79_reset->rcdev.of_node = pdev->dev.of_node;
116	ath79_reset->rcdev.of_reset_n_cells = 1;
117	ath79_reset->rcdev.nr_resets = 32;
118
119	err = devm_reset_controller_register(&pdev->dev, &ath79_reset->rcdev);
120	if (err)
121		return err;
122
123	ath79_reset->restart_nb.notifier_call = ath79_reset_restart_handler;
124	ath79_reset->restart_nb.priority = 128;
125
126	err = register_restart_handler(&ath79_reset->restart_nb);
127	if (err)
128		dev_warn(&pdev->dev, "Failed to register restart handler\n");
129
130	return 0;
131}
132
133static const struct of_device_id ath79_reset_dt_ids[] = {
134	{ .compatible = "qca,ar7100-reset", },
135	{ },
136};
137
138static struct platform_driver ath79_reset_driver = {
139	.probe	= ath79_reset_probe,
140	.driver = {
141		.name			= "ath79-reset",
142		.of_match_table		= ath79_reset_dt_ids,
143		.suppress_bind_attrs	= true,
144	},
145};
146builtin_platform_driver(ath79_reset_driver);