Linux Audio

Check our new training course

Loading...
Note: File does not exist in v3.5.6.
  1// SPDX-License-Identifier: GPL-2.0-only
  2/*
  3 * Toshiba Visconti ARM SoC reset controller
  4 *
  5 * Copyright (c) 2021 TOSHIBA CORPORATION
  6 * Copyright (c) 2021 Toshiba Electronic Devices & Storage Corporation
  7 *
  8 * Nobuhiro Iwamatsu <nobuhiro1.iwamatsu@toshiba.co.jp>
  9 */
 10#include <linux/delay.h>
 11#include <linux/device.h>
 12#include <linux/mfd/syscon.h>
 13#include <linux/regmap.h>
 14#include <linux/slab.h>
 15
 16#include "reset.h"
 17
 18static inline struct visconti_reset *to_visconti_reset(struct reset_controller_dev *rcdev)
 19{
 20	return container_of(rcdev, struct visconti_reset, rcdev);
 21}
 22
 23static int visconti_reset_assert(struct reset_controller_dev *rcdev, unsigned long id)
 24{
 25	struct visconti_reset *reset = to_visconti_reset(rcdev);
 26	const struct visconti_reset_data *data = &reset->resets[id];
 27	u32 rst = BIT(data->rs_idx);
 28	unsigned long flags;
 29	int ret;
 30
 31	spin_lock_irqsave(reset->lock, flags);
 32	ret = regmap_update_bits(reset->regmap, data->rson_offset, rst, rst);
 33	spin_unlock_irqrestore(reset->lock, flags);
 34
 35	return ret;
 36}
 37
 38static int visconti_reset_deassert(struct reset_controller_dev *rcdev, unsigned long id)
 39{
 40	struct visconti_reset *reset = to_visconti_reset(rcdev);
 41	const struct visconti_reset_data *data = &reset->resets[id];
 42	u32 rst = BIT(data->rs_idx);
 43	unsigned long flags;
 44	int ret;
 45
 46	spin_lock_irqsave(reset->lock, flags);
 47	ret = regmap_update_bits(reset->regmap, data->rsoff_offset, rst, rst);
 48	spin_unlock_irqrestore(reset->lock, flags);
 49
 50	return ret;
 51}
 52
 53static int visconti_reset_reset(struct reset_controller_dev *rcdev, unsigned long id)
 54{
 55	visconti_reset_assert(rcdev, id);
 56	udelay(1);
 57	visconti_reset_deassert(rcdev, id);
 58
 59	return 0;
 60}
 61
 62static int visconti_reset_status(struct reset_controller_dev *rcdev, unsigned long id)
 63{
 64	struct visconti_reset *reset = to_visconti_reset(rcdev);
 65	const struct visconti_reset_data *data = &reset->resets[id];
 66	unsigned long flags;
 67	u32 reg;
 68	int ret;
 69
 70	spin_lock_irqsave(reset->lock, flags);
 71	ret = regmap_read(reset->regmap, data->rson_offset, &reg);
 72	spin_unlock_irqrestore(reset->lock, flags);
 73	if (ret)
 74		return ret;
 75
 76	return !(reg & data->rs_idx);
 77}
 78
 79const struct reset_control_ops visconti_reset_ops = {
 80	.assert		= visconti_reset_assert,
 81	.deassert	= visconti_reset_deassert,
 82	.reset		= visconti_reset_reset,
 83	.status		= visconti_reset_status,
 84};
 85
 86int visconti_register_reset_controller(struct device *dev,
 87				       struct regmap *regmap,
 88				       const struct visconti_reset_data *resets,
 89				       unsigned int num_resets,
 90				       const struct reset_control_ops *reset_ops,
 91				       spinlock_t *lock)
 92{
 93	struct visconti_reset *reset;
 94
 95	reset = devm_kzalloc(dev, sizeof(*reset), GFP_KERNEL);
 96	if (!reset)
 97		return -ENOMEM;
 98
 99	reset->regmap = regmap;
100	reset->resets = resets;
101	reset->rcdev.ops = reset_ops;
102	reset->rcdev.nr_resets = num_resets;
103	reset->rcdev.of_node = dev->of_node;
104	reset->lock = lock;
105
106	return devm_reset_controller_register(dev, &reset->rcdev);
107}