brintos

brintos / linux-shallow public Read only

0
0
Text · 3.2 KiB · 6e3f306 Raw
129 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3 * Copyright 2024 NXP4 */5 6#include <linux/auxiliary_bus.h>7#include <linux/device.h>8#include <linux/io.h>9#include <linux/module.h>10#include <linux/of.h>11#include <linux/of_address.h>12#include <linux/reset-controller.h>13 14#define EARC			0x20015#define EARC_RESET_MASK		0x316 17struct imx8mp_audiomix_reset {18	struct reset_controller_dev rcdev;19	spinlock_t lock; /* protect register read-modify-write cycle */20	void __iomem *base;21};22 23static struct imx8mp_audiomix_reset *to_imx8mp_audiomix_reset(struct reset_controller_dev *rcdev)24{25	return container_of(rcdev, struct imx8mp_audiomix_reset, rcdev);26}27 28static int imx8mp_audiomix_reset_assert(struct reset_controller_dev *rcdev,29					unsigned long id)30{31	struct imx8mp_audiomix_reset *priv = to_imx8mp_audiomix_reset(rcdev);32	void __iomem *reg_addr = priv->base;33	unsigned int mask, reg;34	unsigned long flags;35 36	mask = BIT(id);37	spin_lock_irqsave(&priv->lock, flags);38	reg = readl(reg_addr + EARC);39	writel(reg & ~mask, reg_addr + EARC);40	spin_unlock_irqrestore(&priv->lock, flags);41 42	return 0;43}44 45static int imx8mp_audiomix_reset_deassert(struct reset_controller_dev *rcdev,46					  unsigned long id)47{48	struct imx8mp_audiomix_reset *priv = to_imx8mp_audiomix_reset(rcdev);49	void __iomem *reg_addr = priv->base;50	unsigned int mask, reg;51	unsigned long flags;52 53	mask = BIT(id);54	spin_lock_irqsave(&priv->lock, flags);55	reg = readl(reg_addr + EARC);56	writel(reg | mask, reg_addr + EARC);57	spin_unlock_irqrestore(&priv->lock, flags);58 59	return 0;60}61 62static const struct reset_control_ops imx8mp_audiomix_reset_ops = {63	.assert   = imx8mp_audiomix_reset_assert,64	.deassert = imx8mp_audiomix_reset_deassert,65};66 67static int imx8mp_audiomix_reset_probe(struct auxiliary_device *adev,68				       const struct auxiliary_device_id *id)69{70	struct imx8mp_audiomix_reset *priv;71	struct device *dev = &adev->dev;72	int ret;73 74	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);75	if (!priv)76		return -ENOMEM;77 78	spin_lock_init(&priv->lock);79 80	priv->rcdev.owner     = THIS_MODULE;81	priv->rcdev.nr_resets = fls(EARC_RESET_MASK);82	priv->rcdev.ops       = &imx8mp_audiomix_reset_ops;83	priv->rcdev.of_node   = dev->parent->of_node;84	priv->rcdev.dev	      = dev;85	priv->rcdev.of_reset_n_cells = 1;86	priv->base            = of_iomap(dev->parent->of_node, 0);87	if (!priv->base)88		return -ENOMEM;89 90	dev_set_drvdata(dev, priv);91 92	ret = devm_reset_controller_register(dev, &priv->rcdev);93	if (ret)94		goto out_unmap;95 96	return 0;97 98out_unmap:99	iounmap(priv->base);100	return ret;101}102 103static void imx8mp_audiomix_reset_remove(struct auxiliary_device *adev)104{105	struct imx8mp_audiomix_reset *priv = dev_get_drvdata(&adev->dev);106 107	iounmap(priv->base);108}109 110static const struct auxiliary_device_id imx8mp_audiomix_reset_ids[] = {111	{112		.name = "clk_imx8mp_audiomix.reset",113	},114	{ }115};116MODULE_DEVICE_TABLE(auxiliary, imx8mp_audiomix_reset_ids);117 118static struct auxiliary_driver imx8mp_audiomix_reset_driver = {119	.probe		= imx8mp_audiomix_reset_probe,120	.remove		= imx8mp_audiomix_reset_remove,121	.id_table	= imx8mp_audiomix_reset_ids,122};123 124module_auxiliary_driver(imx8mp_audiomix_reset_driver);125 126MODULE_AUTHOR("Shengjiu Wang <shengjiu.wang@nxp.com>");127MODULE_DESCRIPTION("Freescale i.MX8MP Audio Block Controller reset driver");128MODULE_LICENSE("GPL");129