Linux Audio

Check our new training course

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