Commit 16fb2173 authored by Stephen Boyd's avatar Stephen Boyd

Merge tag 'clk-imx-6.10' of...

Merge tag 'clk-imx-6.10' 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 PM runtime support to i.MX8MP Audiomix
 - Add i.MX95 BLK CTL clock driver
 - Add DT schema for i.MX95 Display Master Block Control
 - Convert to platform remove callback returning void for i.MX8MP
   Audiomix

* tag 'clk-imx-6.10' of git://git.kernel.org/pub/scm/linux/kernel/git/abelvesa/linux:
  clk: imx: imx8mp: Convert to platform remove callback returning void
  clk: imx: imx8mp: Switch to RUNTIME_PM_OPS()
  clk: imx: add i.MX95 BLK CTL clk driver
  dt-bindings: clock: support i.MX95 Display Master CSR module
  dt-bindings: clock: support i.MX95 BLK CTL module
  dt-bindings: clock: add i.MX95 clock header
  clk: imx: imx8mp: Add pm_runtime support for power saving
parents 4cece764 f5072cff
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/clock/nxp,imx95-blk-ctl.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: NXP i.MX95 Block Control
maintainers:
- Peng Fan <peng.fan@nxp.com>
properties:
compatible:
items:
- enum:
- nxp,imx95-lvds-csr
- nxp,imx95-display-csr
- nxp,imx95-camera-csr
- nxp,imx95-vpu-csr
- const: syscon
reg:
maxItems: 1
power-domains:
maxItems: 1
clocks:
maxItems: 1
'#clock-cells':
const: 1
description:
The clock consumer should specify the desired clock by having the clock
ID in its "clocks" phandle cell. See
include/dt-bindings/clock/nxp,imx95-clock.h
required:
- compatible
- reg
- '#clock-cells'
- power-domains
- clocks
additionalProperties: false
examples:
- |
syscon@4c410000 {
compatible = "nxp,imx95-vpu-csr", "syscon";
reg = <0x4c410000 0x10000>;
#clock-cells = <1>;
clocks = <&scmi_clk 114>;
power-domains = <&scmi_devpd 21>;
};
...
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/clock/nxp,imx95-display-master-csr.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: NXP i.MX95 Display Master Block Control
maintainers:
- Peng Fan <peng.fan@nxp.com>
properties:
compatible:
items:
- const: nxp,imx95-display-master-csr
- const: syscon
reg:
maxItems: 1
power-domains:
maxItems: 1
clocks:
maxItems: 1
'#clock-cells':
const: 1
description:
The clock consumer should specify the desired clock by having the clock
ID in its "clocks" phandle cell. See
include/dt-bindings/clock/nxp,imx95-clock.h
mux-controller:
type: object
$ref: /schemas/mux/reg-mux.yaml
required:
- compatible
- reg
- '#clock-cells'
- mux-controller
- power-domains
- clocks
additionalProperties: false
examples:
- |
syscon@4c410000 {
compatible = "nxp,imx95-display-master-csr", "syscon";
reg = <0x4c410000 0x10000>;
#clock-cells = <1>;
clocks = <&scmi_clk 62>;
power-domains = <&scmi_devpd 3>;
mux: mux-controller {
compatible = "mmio-mux";
#mux-control-cells = <1>;
mux-reg-masks = <0x4 0x00000001>; /* Pixel_link_sel */
idle-states = <0>;
};
};
...
......@@ -114,6 +114,13 @@ config CLK_IMX93
help
Build the driver for i.MX93 CCM Clock Driver
config CLK_IMX95_BLK_CTL
tristate "IMX95 Clock Driver for BLK CTL"
depends on ARCH_MXC || COMPILE_TEST
select MXC_CLK
help
Build the clock driver for i.MX95 BLK CTL
config CLK_IMXRT1050
tristate "IMXRT1050 CCM Clock Driver"
depends on SOC_IMXRT || COMPILE_TEST
......
......@@ -31,6 +31,7 @@ obj-$(CONFIG_CLK_IMX8MP) += clk-imx8mp.o clk-imx8mp-audiomix.o
obj-$(CONFIG_CLK_IMX8MQ) += clk-imx8mq.o
obj-$(CONFIG_CLK_IMX93) += clk-imx93.o
obj-$(CONFIG_CLK_IMX95_BLK_CTL) += clk-imx95-blk-ctl.o
obj-$(CONFIG_MXC_CLK_SCU) += clk-imx-scu.o clk-imx-lpcg-scu.o clk-imx-acm.o
clk-imx-scu-$(CONFIG_CLK_IMX8QXP) += clk-scu.o clk-imx8qxp.o \
......
......@@ -7,10 +7,12 @@
#include <linux/clk-provider.h>
#include <linux/device.h>
#include <linux/io.h>
#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <dt-bindings/clock/imx8mp-clock.h>
......@@ -18,6 +20,7 @@
#define CLKEN0 0x000
#define CLKEN1 0x004
#define EARC 0x200
#define SAI1_MCLK_SEL 0x300
#define SAI2_MCLK_SEL 0x304
#define SAI3_MCLK_SEL 0x308
......@@ -26,6 +29,11 @@
#define SAI7_MCLK_SEL 0x314
#define PDM_SEL 0x318
#define SAI_PLL_GNRL_CTL 0x400
#define SAI_PLL_FDIVL_CTL0 0x404
#define SAI_PLL_FDIVL_CTL1 0x408
#define SAI_PLL_SSCG_CTL 0x40C
#define SAI_PLL_MNIT_CTL 0x410
#define IPG_LP_CTRL 0x504
#define SAIn_MCLK1_PARENT(n) \
static const struct clk_parent_data \
......@@ -182,26 +190,82 @@ static struct clk_imx8mp_audiomix_sel sels[] = {
CLK_SAIn(7)
};
static const u16 audiomix_regs[] = {
CLKEN0,
CLKEN1,
EARC,
SAI1_MCLK_SEL,
SAI2_MCLK_SEL,
SAI3_MCLK_SEL,
SAI5_MCLK_SEL,
SAI6_MCLK_SEL,
SAI7_MCLK_SEL,
PDM_SEL,
SAI_PLL_GNRL_CTL,
SAI_PLL_FDIVL_CTL0,
SAI_PLL_FDIVL_CTL1,
SAI_PLL_SSCG_CTL,
SAI_PLL_MNIT_CTL,
IPG_LP_CTRL,
};
struct clk_imx8mp_audiomix_priv {
void __iomem *base;
u32 regs_save[ARRAY_SIZE(audiomix_regs)];
/* Must be last */
struct clk_hw_onecell_data clk_data;
};
static void clk_imx8mp_audiomix_save_restore(struct device *dev, bool save)
{
struct clk_imx8mp_audiomix_priv *priv = dev_get_drvdata(dev);
void __iomem *base = priv->base;
int i;
if (save) {
for (i = 0; i < ARRAY_SIZE(audiomix_regs); i++)
priv->regs_save[i] = readl(base + audiomix_regs[i]);
} else {
for (i = 0; i < ARRAY_SIZE(audiomix_regs); i++)
writel(priv->regs_save[i], base + audiomix_regs[i]);
}
}
static int clk_imx8mp_audiomix_probe(struct platform_device *pdev)
{
struct clk_hw_onecell_data *priv;
struct clk_imx8mp_audiomix_priv *priv;
struct clk_hw_onecell_data *clk_hw_data;
struct device *dev = &pdev->dev;
void __iomem *base;
struct clk_hw *hw;
int i;
int i, ret;
priv = devm_kzalloc(dev,
struct_size(priv, hws, IMX8MP_CLK_AUDIOMIX_END),
struct_size(priv, clk_data.hws, IMX8MP_CLK_AUDIOMIX_END),
GFP_KERNEL);
if (!priv)
return -ENOMEM;
priv->num = IMX8MP_CLK_AUDIOMIX_END;
clk_hw_data = &priv->clk_data;
clk_hw_data->num = IMX8MP_CLK_AUDIOMIX_END;
base = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(base))
return PTR_ERR(base);
priv->base = base;
dev_set_drvdata(dev, priv);
/*
* pm_runtime_enable needs to be called before clk register.
* That is to make core->rpm_enabled to be true for clock
* usage.
*/
pm_runtime_get_noresume(dev);
pm_runtime_set_active(dev);
pm_runtime_enable(dev);
for (i = 0; i < ARRAY_SIZE(sels); i++) {
if (sels[i].num_parents == 1) {
hw = devm_clk_hw_register_gate_parent_data(dev,
......@@ -216,10 +280,12 @@ static int clk_imx8mp_audiomix_probe(struct platform_device *pdev)
0, NULL, NULL);
}
if (IS_ERR(hw))
return PTR_ERR(hw);
if (IS_ERR(hw)) {
ret = PTR_ERR(hw);
goto err_clk_register;
}
priv->hws[sels[i].clkid] = hw;
clk_hw_data->hws[sels[i].clkid] = hw;
}
/* SAI PLL */
......@@ -228,39 +294,84 @@ static int clk_imx8mp_audiomix_probe(struct platform_device *pdev)
ARRAY_SIZE(clk_imx8mp_audiomix_pll_parents),
CLK_SET_RATE_NO_REPARENT, base + SAI_PLL_GNRL_CTL,
0, 2, 0, NULL, NULL);
priv->hws[IMX8MP_CLK_AUDIOMIX_SAI_PLL_REF_SEL] = hw;
clk_hw_data->hws[IMX8MP_CLK_AUDIOMIX_SAI_PLL_REF_SEL] = hw;
hw = imx_dev_clk_hw_pll14xx(dev, "sai_pll", "sai_pll_ref_sel",
base + 0x400, &imx_1443x_pll);
if (IS_ERR(hw))
return PTR_ERR(hw);
priv->hws[IMX8MP_CLK_AUDIOMIX_SAI_PLL] = hw;
if (IS_ERR(hw)) {
ret = PTR_ERR(hw);
goto err_clk_register;
}
clk_hw_data->hws[IMX8MP_CLK_AUDIOMIX_SAI_PLL] = hw;
hw = devm_clk_hw_register_mux_parent_data_table(dev,
"sai_pll_bypass", clk_imx8mp_audiomix_pll_bypass_sels,
ARRAY_SIZE(clk_imx8mp_audiomix_pll_bypass_sels),
CLK_SET_RATE_NO_REPARENT | CLK_SET_RATE_PARENT,
base + SAI_PLL_GNRL_CTL, 16, 1, 0, NULL, NULL);
if (IS_ERR(hw))
return PTR_ERR(hw);
priv->hws[IMX8MP_CLK_AUDIOMIX_SAI_PLL_BYPASS] = hw;
if (IS_ERR(hw)) {
ret = PTR_ERR(hw);
goto err_clk_register;
}
clk_hw_data->hws[IMX8MP_CLK_AUDIOMIX_SAI_PLL_BYPASS] = hw;
hw = devm_clk_hw_register_gate(dev, "sai_pll_out", "sai_pll_bypass",
0, base + SAI_PLL_GNRL_CTL, 13,
0, NULL);
if (IS_ERR(hw))
return PTR_ERR(hw);
priv->hws[IMX8MP_CLK_AUDIOMIX_SAI_PLL_OUT] = hw;
if (IS_ERR(hw)) {
ret = PTR_ERR(hw);
goto err_clk_register;
}
clk_hw_data->hws[IMX8MP_CLK_AUDIOMIX_SAI_PLL_OUT] = hw;
hw = devm_clk_hw_register_fixed_factor(dev, "sai_pll_out_div2",
"sai_pll_out", 0, 1, 2);
if (IS_ERR(hw))
return PTR_ERR(hw);
if (IS_ERR(hw)) {
ret = PTR_ERR(hw);
goto err_clk_register;
}
ret = devm_of_clk_add_hw_provider(&pdev->dev, of_clk_hw_onecell_get,
clk_hw_data);
if (ret)
goto err_clk_register;
pm_runtime_put_sync(dev);
return 0;
err_clk_register:
pm_runtime_put_sync(dev);
pm_runtime_disable(dev);
return ret;
}
static void clk_imx8mp_audiomix_remove(struct platform_device *pdev)
{
pm_runtime_disable(&pdev->dev);
}
static int clk_imx8mp_audiomix_runtime_suspend(struct device *dev)
{
clk_imx8mp_audiomix_save_restore(dev, true);
return devm_of_clk_add_hw_provider(&pdev->dev, of_clk_hw_onecell_get,
priv);
return 0;
}
static int clk_imx8mp_audiomix_runtime_resume(struct device *dev)
{
clk_imx8mp_audiomix_save_restore(dev, false);
return 0;
}
static const struct dev_pm_ops clk_imx8mp_audiomix_pm_ops = {
RUNTIME_PM_OPS(clk_imx8mp_audiomix_runtime_suspend,
clk_imx8mp_audiomix_runtime_resume, NULL)
SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
pm_runtime_force_resume)
};
static const struct of_device_id clk_imx8mp_audiomix_of_match[] = {
{ .compatible = "fsl,imx8mp-audio-blk-ctrl" },
{ /* sentinel */ }
......@@ -269,9 +380,11 @@ MODULE_DEVICE_TABLE(of, clk_imx8mp_audiomix_of_match);
static struct platform_driver clk_imx8mp_audiomix_driver = {
.probe = clk_imx8mp_audiomix_probe,
.remove_new = clk_imx8mp_audiomix_remove,
.driver = {
.name = "imx8mp-audio-blk-ctrl",
.of_match_table = clk_imx8mp_audiomix_of_match,
.pm = pm_ptr(&clk_imx8mp_audiomix_pm_ops),
},
};
......
This diff is collapsed.
/* SPDX-License-Identifier: GPL-2.0-only OR MIT */
/*
* Copyright 2024 NXP
*/
#ifndef __DT_BINDINGS_CLOCK_IMX95_H
#define __DT_BINDINGS_CLOCK_IMX95_H
#define IMX95_CLK_VPUBLK_WAVE 0
#define IMX95_CLK_VPUBLK_JPEG_ENC 1
#define IMX95_CLK_VPUBLK_JPEG_DEC 2
#define IMX95_CLK_CAMBLK_CSI2_FOR0 0
#define IMX95_CLK_CAMBLK_CSI2_FOR1 1
#define IMX95_CLK_CAMBLK_ISP_AXI 2
#define IMX95_CLK_CAMBLK_ISP_PIXEL 3
#define IMX95_CLK_CAMBLK_ISP 4
#define IMX95_CLK_DISPMIX_LVDS_PHY_DIV 0
#define IMX95_CLK_DISPMIX_LVDS_CH0_GATE 1
#define IMX95_CLK_DISPMIX_LVDS_CH1_GATE 2
#define IMX95_CLK_DISPMIX_PIX_DI0_GATE 3
#define IMX95_CLK_DISPMIX_PIX_DI1_GATE 4
#define IMX95_CLK_DISPMIX_ENG0_SEL 0
#define IMX95_CLK_DISPMIX_ENG1_SEL 1
#endif /* __DT_BINDINGS_CLOCK_IMX95_H */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment