Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Merge tag 'clk-imx-6.19' of git://git.kernel.org/pub/scm/linux/kernel/git/abelvesa/linux into clk-imx

Pull i.MX clk driver updates from Abel Vesa:

- Add delay to the PCC enable/disable in i.MX7ULP composite, needed by
some specific peripherals
- Simplify the i.MX8MP auxiomix by using devm_auxiliary_device_create()
- Add the i.MX8ULP SIM LPAV platform specific clock provider

* tag 'clk-imx-6.19' of git://git.kernel.org/pub/scm/linux/kernel/git/abelvesa/linux:
clk: imx: add driver for imx8ulp's sim lpav
dt-bindings: clock: document 8ULP's SIM LPAV
clk: imx: imx8mp-audiomix: use devm_auxiliary_device_create() to simple code
clk: imx: Add some delay before deassert the reset

+268 -35
+72
Documentation/devicetree/bindings/clock/fsl,imx8ulp-sim-lpav.yaml
··· 1 + # SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) 2 + %YAML 1.2 3 + --- 4 + $id: http://devicetree.org/schemas/clock/fsl,imx8ulp-sim-lpav.yaml# 5 + $schema: http://devicetree.org/meta-schemas/core.yaml# 6 + 7 + title: NXP i.MX8ULP LPAV System Integration Module (SIM) 8 + 9 + maintainers: 10 + - Laurentiu Mihalcea <laurentiu.mihalcea@nxp.com> 11 + 12 + description: 13 + The i.MX8ULP LPAV subsystem contains a block control module known as 14 + SIM LPAV, which offers functionalities such as clock gating or reset 15 + line assertion/de-assertion. 16 + 17 + properties: 18 + compatible: 19 + const: fsl,imx8ulp-sim-lpav 20 + 21 + reg: 22 + maxItems: 1 23 + 24 + clocks: 25 + maxItems: 3 26 + 27 + clock-names: 28 + items: 29 + - const: bus 30 + - const: core 31 + - const: plat 32 + 33 + '#clock-cells': 34 + const: 1 35 + 36 + '#reset-cells': 37 + const: 1 38 + 39 + mux-controller: 40 + $ref: /schemas/mux/reg-mux.yaml# 41 + 42 + required: 43 + - compatible 44 + - reg 45 + - clocks 46 + - clock-names 47 + - '#clock-cells' 48 + - '#reset-cells' 49 + - mux-controller 50 + 51 + additionalProperties: false 52 + 53 + examples: 54 + - | 55 + #include <dt-bindings/clock/imx8ulp-clock.h> 56 + 57 + clock-controller@2da50000 { 58 + compatible = "fsl,imx8ulp-sim-lpav"; 59 + reg = <0x2da50000 0x10000>; 60 + clocks = <&cgc2 IMX8ULP_CLK_LPAV_BUS_DIV>, 61 + <&cgc2 IMX8ULP_CLK_HIFI_DIVCORE>, 62 + <&cgc2 IMX8ULP_CLK_HIFI_DIVPLAT>; 63 + clock-names = "bus", "core", "plat"; 64 + #clock-cells = <1>; 65 + #reset-cells = <1>; 66 + 67 + mux-controller { 68 + compatible = "reg-mux"; 69 + #mux-control-cells = <1>; 70 + mux-reg-masks = <0x8 0x00000200>; 71 + }; 72 + };
+1
drivers/clk/imx/Kconfig
··· 105 105 tristate "IMX8ULP CCM Clock Driver" 106 106 depends on ARCH_MXC || COMPILE_TEST 107 107 select MXC_CLK 108 + select AUXILIARY_BUS 108 109 help 109 110 Build the driver for i.MX8ULP CCM Clock Driver 110 111
+1
drivers/clk/imx/Makefile
··· 41 41 clk-imx-acm-$(CONFIG_CLK_IMX8QXP) = clk-imx8-acm.o 42 42 43 43 obj-$(CONFIG_CLK_IMX8ULP) += clk-imx8ulp.o 44 + obj-$(CONFIG_CLK_IMX8ULP) += clk-imx8ulp-sim-lpav.o 44 45 45 46 obj-$(CONFIG_CLK_IMX1) += clk-imx1.o 46 47 obj-$(CONFIG_CLK_IMX25) += clk-imx25.o
+13
drivers/clk/imx/clk-composite-7ulp.c
··· 7 7 8 8 #include <linux/bits.h> 9 9 #include <linux/clk-provider.h> 10 + #include <linux/delay.h> 10 11 #include <linux/err.h> 11 12 #include <linux/io.h> 12 13 #include <linux/slab.h> ··· 37 36 if (ret) 38 37 return ret; 39 38 39 + /* Make sure the IP's clock is ready before release reset */ 40 + udelay(1); 41 + 40 42 spin_lock_irqsave(gate->lock, flags); 41 43 /* 42 44 * release the sw reset for peripherals associated with ··· 50 46 writel(val, gate->reg); 51 47 52 48 spin_unlock_irqrestore(gate->lock, flags); 49 + 50 + /* 51 + * Read back the register to make sure the previous write has been 52 + * done in the target HW register. For IP like GPU, after deassert 53 + * the reset, need to wait for a while to make sure the sync reset 54 + * is done 55 + */ 56 + readl(gate->reg); 57 + udelay(1); 53 58 54 59 return 0; 55 60 }
+4 -35
drivers/clk/imx/clk-imx8mp-audiomix.c
··· 230 230 231 231 #if IS_ENABLED(CONFIG_RESET_CONTROLLER) 232 232 233 - static void clk_imx8mp_audiomix_reset_unregister_adev(void *_adev) 234 - { 235 - struct auxiliary_device *adev = _adev; 236 - 237 - auxiliary_device_delete(adev); 238 - auxiliary_device_uninit(adev); 239 - } 240 - 241 - static void clk_imx8mp_audiomix_reset_adev_release(struct device *dev) 242 - { 243 - struct auxiliary_device *adev = to_auxiliary_dev(dev); 244 - 245 - kfree(adev); 246 - } 247 - 248 233 static int clk_imx8mp_audiomix_reset_controller_register(struct device *dev, 249 234 struct clk_imx8mp_audiomix_priv *priv) 250 235 { 251 - struct auxiliary_device *adev __free(kfree) = NULL; 252 - int ret; 236 + struct auxiliary_device *adev; 253 237 254 238 if (!of_property_present(dev->of_node, "#reset-cells")) 255 239 return 0; 256 240 257 - adev = kzalloc(sizeof(*adev), GFP_KERNEL); 241 + adev = devm_auxiliary_device_create(dev, "reset", NULL); 258 242 if (!adev) 259 - return -ENOMEM; 243 + return -ENODEV; 260 244 261 - adev->name = "reset"; 262 - adev->dev.parent = dev; 263 - adev->dev.release = clk_imx8mp_audiomix_reset_adev_release; 264 - 265 - ret = auxiliary_device_init(adev); 266 - if (ret) 267 - return ret; 268 - 269 - ret = auxiliary_device_add(adev); 270 - if (ret) { 271 - auxiliary_device_uninit(adev); 272 - return ret; 273 - } 274 - 275 - return devm_add_action_or_reset(dev, clk_imx8mp_audiomix_reset_unregister_adev, 276 - no_free_ptr(adev)); 245 + return 0; 277 246 } 278 247 279 248 #else /* !CONFIG_RESET_CONTROLLER */
+156
drivers/clk/imx/clk-imx8ulp-sim-lpav.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* 3 + * Copyright 2025 NXP 4 + */ 5 + 6 + #include <dt-bindings/clock/imx8ulp-clock.h> 7 + 8 + #include <linux/auxiliary_bus.h> 9 + #include <linux/clk-provider.h> 10 + #include <linux/module.h> 11 + #include <linux/of.h> 12 + #include <linux/of_platform.h> 13 + #include <linux/platform_device.h> 14 + #include <linux/regmap.h> 15 + #include <linux/slab.h> 16 + 17 + #define SYSCTRL0 0x8 18 + 19 + #define IMX8ULP_HIFI_CLK_GATE(gname, cname, pname, bidx) \ 20 + { \ 21 + .name = gname "_cg", \ 22 + .id = IMX8ULP_CLK_SIM_LPAV_HIFI_##cname, \ 23 + .parent = { .fw_name = pname }, \ 24 + .bit = bidx, \ 25 + } 26 + 27 + struct clk_imx8ulp_sim_lpav_data { 28 + spinlock_t lock; /* shared by MUX, clock gate and reset */ 29 + unsigned long flags; /* for spinlock usage */ 30 + struct clk_hw_onecell_data clk_data; /* keep last */ 31 + }; 32 + 33 + struct clk_imx8ulp_sim_lpav_gate { 34 + const char *name; 35 + int id; 36 + const struct clk_parent_data parent; 37 + u8 bit; 38 + }; 39 + 40 + static struct clk_imx8ulp_sim_lpav_gate gates[] = { 41 + IMX8ULP_HIFI_CLK_GATE("hifi_core", CORE, "core", 17), 42 + IMX8ULP_HIFI_CLK_GATE("hifi_pbclk", PBCLK, "bus", 18), 43 + IMX8ULP_HIFI_CLK_GATE("hifi_plat", PLAT, "plat", 19) 44 + }; 45 + 46 + static void clk_imx8ulp_sim_lpav_lock(void *arg) __acquires(&data->lock) 47 + { 48 + struct clk_imx8ulp_sim_lpav_data *data = dev_get_drvdata(arg); 49 + 50 + spin_lock_irqsave(&data->lock, data->flags); 51 + } 52 + 53 + static void clk_imx8ulp_sim_lpav_unlock(void *arg) __releases(&data->lock) 54 + { 55 + struct clk_imx8ulp_sim_lpav_data *data = dev_get_drvdata(arg); 56 + 57 + spin_unlock_irqrestore(&data->lock, data->flags); 58 + } 59 + 60 + static int clk_imx8ulp_sim_lpav_probe(struct platform_device *pdev) 61 + { 62 + const struct regmap_config regmap_config = { 63 + .reg_bits = 32, 64 + .val_bits = 32, 65 + .reg_stride = 4, 66 + .lock = clk_imx8ulp_sim_lpav_lock, 67 + .unlock = clk_imx8ulp_sim_lpav_unlock, 68 + .lock_arg = &pdev->dev, 69 + }; 70 + struct clk_imx8ulp_sim_lpav_data *data; 71 + struct auxiliary_device *adev; 72 + struct regmap *regmap; 73 + void __iomem *base; 74 + struct clk_hw *hw; 75 + int i, ret; 76 + 77 + data = devm_kzalloc(&pdev->dev, 78 + struct_size(data, clk_data.hws, ARRAY_SIZE(gates)), 79 + GFP_KERNEL); 80 + if (!data) 81 + return -ENOMEM; 82 + 83 + dev_set_drvdata(&pdev->dev, data); 84 + 85 + /* 86 + * this lock is used directly by the clock gate and indirectly 87 + * by the reset and mux controller via the regmap API 88 + */ 89 + spin_lock_init(&data->lock); 90 + 91 + base = devm_platform_ioremap_resource(pdev, 0); 92 + if (IS_ERR(base)) 93 + return dev_err_probe(&pdev->dev, PTR_ERR(base), 94 + "failed to ioremap base\n"); 95 + /* 96 + * although the clock gate doesn't use the regmap API to modify the 97 + * registers, we still need the regmap because of the reset auxiliary 98 + * driver and the MUX drivers, which use the parent device's regmap 99 + */ 100 + regmap = devm_regmap_init_mmio(&pdev->dev, base, &regmap_config); 101 + if (IS_ERR(regmap)) 102 + return dev_err_probe(&pdev->dev, PTR_ERR(regmap), 103 + "failed to initialize regmap\n"); 104 + 105 + data->clk_data.num = ARRAY_SIZE(gates); 106 + 107 + for (i = 0; i < ARRAY_SIZE(gates); i++) { 108 + hw = devm_clk_hw_register_gate_parent_data(&pdev->dev, 109 + gates[i].name, 110 + &gates[i].parent, 111 + CLK_SET_RATE_PARENT, 112 + base + SYSCTRL0, 113 + gates[i].bit, 114 + 0x0, &data->lock); 115 + if (IS_ERR(hw)) 116 + return dev_err_probe(&pdev->dev, PTR_ERR(hw), 117 + "failed to register %s gate\n", 118 + gates[i].name); 119 + 120 + data->clk_data.hws[i] = hw; 121 + } 122 + 123 + adev = devm_auxiliary_device_create(&pdev->dev, "reset", NULL); 124 + if (!adev) 125 + return dev_err_probe(&pdev->dev, -ENODEV, 126 + "failed to register aux reset\n"); 127 + 128 + ret = devm_of_clk_add_hw_provider(&pdev->dev, 129 + of_clk_hw_onecell_get, 130 + &data->clk_data); 131 + if (ret) 132 + return dev_err_probe(&pdev->dev, ret, 133 + "failed to register clk hw provider\n"); 134 + 135 + /* used to probe MUX child device */ 136 + return devm_of_platform_populate(&pdev->dev); 137 + } 138 + 139 + static const struct of_device_id clk_imx8ulp_sim_lpav_of_match[] = { 140 + { .compatible = "fsl,imx8ulp-sim-lpav" }, 141 + { } 142 + }; 143 + MODULE_DEVICE_TABLE(of, clk_imx8ulp_sim_lpav_of_match); 144 + 145 + static struct platform_driver clk_imx8ulp_sim_lpav_driver = { 146 + .probe = clk_imx8ulp_sim_lpav_probe, 147 + .driver = { 148 + .name = "clk-imx8ulp-sim-lpav", 149 + .of_match_table = clk_imx8ulp_sim_lpav_of_match, 150 + }, 151 + }; 152 + module_platform_driver(clk_imx8ulp_sim_lpav_driver); 153 + 154 + MODULE_LICENSE("GPL"); 155 + MODULE_DESCRIPTION("i.MX8ULP LPAV System Integration Module (SIM) clock driver"); 156 + MODULE_AUTHOR("Laurentiu Mihalcea <laurentiu.mihalcea@nxp.com>");
+5
include/dt-bindings/clock/imx8ulp-clock.h
··· 255 255 256 256 #define IMX8ULP_CLK_PCC5_END 56 257 257 258 + /* LPAV SIM */ 259 + #define IMX8ULP_CLK_SIM_LPAV_HIFI_CORE 0 260 + #define IMX8ULP_CLK_SIM_LPAV_HIFI_PBCLK 1 261 + #define IMX8ULP_CLK_SIM_LPAV_HIFI_PLAT 2 262 + 258 263 #endif
+16
include/dt-bindings/reset/fsl,imx8ulp-sim-lpav.h
··· 1 + /* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */ 2 + /* 3 + * Copyright 2025 NXP 4 + */ 5 + 6 + #ifndef DT_BINDING_RESET_IMX8ULP_SIM_LPAV_H 7 + #define DT_BINDING_RESET_IMX8ULP_SIM_LPAV_H 8 + 9 + #define IMX8ULP_SIM_LPAV_HIFI4_DSP_DBG_RST 0 10 + #define IMX8ULP_SIM_LPAV_HIFI4_DSP_RST 1 11 + #define IMX8ULP_SIM_LPAV_HIFI4_DSP_STALL 2 12 + #define IMX8ULP_SIM_LPAV_DSI_RST_BYTE_N 3 13 + #define IMX8ULP_SIM_LPAV_DSI_RST_ESC_N 4 14 + #define IMX8ULP_SIM_LPAV_DSI_RST_DPI_N 5 15 + 16 + #endif /* DT_BINDING_RESET_IMX8ULP_SIM_LPAV_H */