1 // SPDX-License-Identifier: GPL-2.0-or-later
6 #include <linux/auxiliary_bus.h>
7 #include <linux/device.h>
9 #include <linux/module.h>
11 #include <linux/of_address.h>
12 #include <linux/reset-controller.h>
15 #define EARC_RESET_MASK 0x3
17 struct imx8mp_audiomix_reset
{
18 struct reset_controller_dev rcdev
;
19 spinlock_t lock
; /* protect register read-modify-write cycle */
23 static struct imx8mp_audiomix_reset
*to_imx8mp_audiomix_reset(struct reset_controller_dev
*rcdev
)
25 return container_of(rcdev
, struct imx8mp_audiomix_reset
, rcdev
);
28 static int imx8mp_audiomix_reset_assert(struct reset_controller_dev
*rcdev
,
31 struct imx8mp_audiomix_reset
*priv
= to_imx8mp_audiomix_reset(rcdev
);
32 void __iomem
*reg_addr
= priv
->base
;
33 unsigned int mask
, reg
;
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
);
45 static int imx8mp_audiomix_reset_deassert(struct reset_controller_dev
*rcdev
,
48 struct imx8mp_audiomix_reset
*priv
= to_imx8mp_audiomix_reset(rcdev
);
49 void __iomem
*reg_addr
= priv
->base
;
50 unsigned int mask
, reg
;
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
);
62 static const struct reset_control_ops imx8mp_audiomix_reset_ops
= {
63 .assert = imx8mp_audiomix_reset_assert
,
64 .deassert
= imx8mp_audiomix_reset_deassert
,
67 static int imx8mp_audiomix_reset_probe(struct auxiliary_device
*adev
,
68 const struct auxiliary_device_id
*id
)
70 struct imx8mp_audiomix_reset
*priv
;
71 struct device
*dev
= &adev
->dev
;
74 priv
= devm_kzalloc(dev
, sizeof(*priv
), GFP_KERNEL
);
78 spin_lock_init(&priv
->lock
);
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);
90 dev_set_drvdata(dev
, priv
);
92 ret
= devm_reset_controller_register(dev
, &priv
->rcdev
);
103 static void imx8mp_audiomix_reset_remove(struct auxiliary_device
*adev
)
105 struct imx8mp_audiomix_reset
*priv
= dev_get_drvdata(&adev
->dev
);
110 static const struct auxiliary_device_id imx8mp_audiomix_reset_ids
[] = {
112 .name
= "clk_imx8mp_audiomix.reset",
116 MODULE_DEVICE_TABLE(auxiliary
, imx8mp_audiomix_reset_ids
);
118 static 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
,
124 module_auxiliary_driver(imx8mp_audiomix_reset_driver
);
126 MODULE_AUTHOR("Shengjiu Wang <shengjiu.wang@nxp.com>");
127 MODULE_DESCRIPTION("Freescale i.MX8MP Audio Block Controller reset driver");
128 MODULE_LICENSE("GPL");