1 // SPDX-License-Identifier: GPL-2.0-or-later 2 /* 3 * Copyright 2024 NXP 4 */ 5 6 #include <dt-bindings/reset/fsl,imx8ulp-sim-lpav.h> 7 #include <dt-bindings/reset/imx8mp-reset-audiomix.h> 8 9 #include <linux/auxiliary_bus.h> 10 #include <linux/bits.h> 11 #include <linux/device.h> 12 #include <linux/io.h> 13 #include <linux/module.h> 14 #include <linux/of.h> 15 #include <linux/of_address.h> 16 #include <linux/regmap.h> 17 #include <linux/reset-controller.h> 18 19 #define IMX8MP_AUDIOMIX_EARC_RESET_OFFSET 0x200 20 #define IMX8MP_AUDIOMIX_DSP_RUNSTALL_OFFSET 0x108 21 22 #define IMX8ULP_SIM_LPAV_SYSCTRL0_OFFSET 0x8 23 24 struct imx8mp_reset_map { 25 unsigned int offset; 26 unsigned int mask; 27 bool active_low; 28 }; 29 30 struct imx8mp_reset_info { 31 const struct imx8mp_reset_map *map; 32 int num_lines; 33 }; 34 35 static const struct imx8mp_reset_map imx8mp_reset_map[] = { 36 [IMX8MP_AUDIOMIX_EARC_RESET] = { 37 .offset = IMX8MP_AUDIOMIX_EARC_RESET_OFFSET, 38 .mask = BIT(0), 39 .active_low = true, 40 }, 41 [IMX8MP_AUDIOMIX_EARC_PHY_RESET] = { 42 .offset = IMX8MP_AUDIOMIX_EARC_RESET_OFFSET, 43 .mask = BIT(1), 44 .active_low = true, 45 }, 46 [IMX8MP_AUDIOMIX_DSP_RUNSTALL] = { 47 .offset = IMX8MP_AUDIOMIX_DSP_RUNSTALL_OFFSET, 48 .mask = BIT(5), 49 .active_low = false, 50 }, 51 }; 52 53 static const struct imx8mp_reset_info imx8mp_reset_info = { 54 .map = imx8mp_reset_map, 55 .num_lines = ARRAY_SIZE(imx8mp_reset_map), 56 }; 57 58 static const struct imx8mp_reset_map imx8ulp_reset_map[] = { 59 [IMX8ULP_SIM_LPAV_HIFI4_DSP_DBG_RST] = { 60 .offset = IMX8ULP_SIM_LPAV_SYSCTRL0_OFFSET, 61 .mask = BIT(25), 62 .active_low = false, 63 }, 64 [IMX8ULP_SIM_LPAV_HIFI4_DSP_RST] = { 65 .offset = IMX8ULP_SIM_LPAV_SYSCTRL0_OFFSET, 66 .mask = BIT(16), 67 .active_low = false, 68 }, 69 [IMX8ULP_SIM_LPAV_HIFI4_DSP_STALL] = { 70 .offset = IMX8ULP_SIM_LPAV_SYSCTRL0_OFFSET, 71 .mask = BIT(13), 72 .active_low = false, 73 }, 74 [IMX8ULP_SIM_LPAV_DSI_RST_BYTE_N] = { 75 .offset = IMX8ULP_SIM_LPAV_SYSCTRL0_OFFSET, 76 .mask = BIT(5), 77 .active_low = true, 78 }, 79 [IMX8ULP_SIM_LPAV_DSI_RST_ESC_N] = { 80 .offset = IMX8ULP_SIM_LPAV_SYSCTRL0_OFFSET, 81 .mask = BIT(4), 82 .active_low = true, 83 }, 84 [IMX8ULP_SIM_LPAV_DSI_RST_DPI_N] = { 85 .offset = IMX8ULP_SIM_LPAV_SYSCTRL0_OFFSET, 86 .mask = BIT(3), 87 .active_low = true, 88 }, 89 }; 90 91 static const struct imx8mp_reset_info imx8ulp_reset_info = { 92 .map = imx8ulp_reset_map, 93 .num_lines = ARRAY_SIZE(imx8ulp_reset_map), 94 }; 95 96 struct imx8mp_audiomix_reset { 97 struct reset_controller_dev rcdev; 98 struct regmap *regmap; 99 const struct imx8mp_reset_map *map; 100 }; 101 102 static struct imx8mp_audiomix_reset *to_imx8mp_audiomix_reset(struct reset_controller_dev *rcdev) 103 { 104 return container_of(rcdev, struct imx8mp_audiomix_reset, rcdev); 105 } 106 107 static int imx8mp_audiomix_update(struct reset_controller_dev *rcdev, 108 unsigned long id, bool assert) 109 { 110 struct imx8mp_audiomix_reset *priv = to_imx8mp_audiomix_reset(rcdev); 111 const struct imx8mp_reset_map *reset_map = priv->map; 112 unsigned int mask, offset, active_low, val; 113 114 mask = reset_map[id].mask; 115 offset = reset_map[id].offset; 116 active_low = reset_map[id].active_low; 117 val = (active_low ^ assert) ? mask : ~mask; 118 119 return regmap_update_bits(priv->regmap, offset, mask, val); 120 } 121 122 static int imx8mp_audiomix_reset_assert(struct reset_controller_dev *rcdev, 123 unsigned long id) 124 { 125 return imx8mp_audiomix_update(rcdev, id, true); 126 } 127 128 static int imx8mp_audiomix_reset_deassert(struct reset_controller_dev *rcdev, 129 unsigned long id) 130 { 131 return imx8mp_audiomix_update(rcdev, id, false); 132 } 133 134 static const struct reset_control_ops imx8mp_audiomix_reset_ops = { 135 .assert = imx8mp_audiomix_reset_assert, 136 .deassert = imx8mp_audiomix_reset_deassert, 137 }; 138 139 static const struct regmap_config regmap_config = { 140 .reg_bits = 32, 141 .val_bits = 32, 142 .reg_stride = 4, 143 }; 144 145 /* assumption: registered only if not using parent regmap */ 146 static void imx8mp_audiomix_reset_iounmap(void *data) 147 { 148 void __iomem *base = (void __iomem *)data; 149 150 iounmap(base); 151 } 152 153 static int imx8mp_audiomix_reset_get_regmap(struct imx8mp_audiomix_reset *priv) 154 { 155 void __iomem *base; 156 struct device *dev; 157 int ret; 158 159 dev = priv->rcdev.dev; 160 161 /* try to use the parent's regmap */ 162 priv->regmap = dev_get_regmap(dev->parent, NULL); 163 if (priv->regmap) 164 return 0; 165 166 /* ... if that's not possible then initialize the regmap right now */ 167 base = of_iomap(dev->parent->of_node, 0); 168 if (!base) 169 return dev_err_probe(dev, -ENOMEM, "failed to iomap address space\n"); 170 171 ret = devm_add_action_or_reset(dev, 172 imx8mp_audiomix_reset_iounmap, 173 (void __force *)base); 174 if (ret) 175 return dev_err_probe(dev, ret, "failed to register action\n"); 176 177 priv->regmap = devm_regmap_init_mmio(dev, base, ®map_config); 178 if (IS_ERR(priv->regmap)) 179 return dev_err_probe(dev, PTR_ERR(priv->regmap), 180 "failed to initialize regmap\n"); 181 182 return 0; 183 } 184 185 static int imx8mp_audiomix_reset_probe(struct auxiliary_device *adev, 186 const struct auxiliary_device_id *id) 187 { 188 const struct imx8mp_reset_info *rinfo; 189 struct imx8mp_audiomix_reset *priv; 190 struct device *dev = &adev->dev; 191 int ret; 192 193 rinfo = (void *)id->driver_data; 194 195 priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); 196 if (!priv) 197 return -ENOMEM; 198 199 priv->rcdev.owner = THIS_MODULE; 200 priv->map = rinfo->map; 201 priv->rcdev.nr_resets = rinfo->num_lines; 202 priv->rcdev.ops = &imx8mp_audiomix_reset_ops; 203 priv->rcdev.of_node = dev->parent->of_node; 204 priv->rcdev.dev = dev; 205 priv->rcdev.of_reset_n_cells = 1; 206 207 dev_set_drvdata(dev, priv); 208 209 ret = imx8mp_audiomix_reset_get_regmap(priv); 210 if (ret) 211 return dev_err_probe(dev, ret, "failed to get regmap\n"); 212 213 ret = devm_reset_controller_register(dev, &priv->rcdev); 214 if (ret) 215 return dev_err_probe(dev, ret, 216 "failed to register reset controller\n"); 217 218 return 0; 219 } 220 221 static const struct auxiliary_device_id imx8mp_audiomix_reset_ids[] = { 222 { 223 .name = "clk_imx8mp_audiomix.reset", 224 .driver_data = (kernel_ulong_t)&imx8mp_reset_info, 225 }, 226 { 227 .name = "clk_imx8ulp_sim_lpav.reset", 228 .driver_data = (kernel_ulong_t)&imx8ulp_reset_info, 229 }, 230 { } 231 }; 232 MODULE_DEVICE_TABLE(auxiliary, imx8mp_audiomix_reset_ids); 233 234 static struct auxiliary_driver imx8mp_audiomix_reset_driver = { 235 .probe = imx8mp_audiomix_reset_probe, 236 .id_table = imx8mp_audiomix_reset_ids, 237 }; 238 239 module_auxiliary_driver(imx8mp_audiomix_reset_driver); 240 241 MODULE_AUTHOR("Shengjiu Wang <shengjiu.wang@nxp.com>"); 242 MODULE_DESCRIPTION("Freescale i.MX8MP Audio Block Controller reset driver"); 243 MODULE_LICENSE("GPL"); 244