return IRQ_HANDLED;
}
-static void disp_mix_sft_rstn(struct regmap *gpr, bool enable)
+static int disp_mix_sft_rstn(struct reset_control *reset, bool enable)
{
- if (!gpr)
- return;
+ int ret;
- if (!enable)
- /* release isi soft reset */
- regmap_update_bits(gpr,
- DISP_MIX_SFT_RSTN_CSR,
- EN_ISI_APB_CLK_RSTN | EN_ISI_PROC_CLK_RSTN,
- EN_ISI_APB_CLK_RSTN | EN_ISI_PROC_CLK_RSTN);
- else
- regmap_update_bits(gpr,
- DISP_MIX_SFT_RSTN_CSR,
- EN_ISI_APB_CLK_RSTN | EN_ISI_APB_CLK_RSTN,
- 0x0);
+ if (!reset)
+ return 0;
+ ret = enable ? reset_control_assert(reset) :
+ reset_control_deassert(reset);
+ return ret;
}
-static void disp_mix_clks_enable(struct regmap *gpr, bool enable)
+static int disp_mix_clks_enable(struct reset_control *reset, bool enable)
{
- if (!gpr)
- return;
+ int ret;
- if (enable)
- /* enable isi clks */
- regmap_update_bits(gpr,
- DISP_MIX_CLK_EN_CSR,
- EN_ISI_APB_CLK | EN_ISI_PROC_CLK,
- EN_ISI_APB_CLK | EN_ISI_PROC_CLK);
- else
- /* disable isi clks */
- regmap_update_bits(gpr,
- DISP_MIX_CLK_EN_CSR,
- EN_ISI_APB_CLK | EN_ISI_PROC_CLK,
- 0x0);
+ if (!reset)
+ return 0;
+
+ ret = enable ? reset_control_assert(reset) :
+ reset_control_deassert(reset);
+ return ret;
}
/**
ops->clk_disable(mxc_isi);
}
+static int mxc_isi_of_parse_resets(struct mxc_isi_dev *mxc_isi)
+{
+ int ret;
+ struct device *dev = &mxc_isi->pdev->dev;
+ struct device_node *np = dev->of_node;
+ struct device_node *parent, *child;
+ struct of_phandle_args args;
+ struct reset_control *rstc;
+ const char *compat;
+ uint32_t len, rstc_num = 0;
+
+ ret = of_parse_phandle_with_args(np, "resets", "#reset-cells",
+ 0, &args);
+ if (ret)
+ return ret;
+
+ parent = args.np;
+ for_each_child_of_node(parent, child) {
+ compat = of_get_property(child, "compatible", NULL);
+ if (!compat)
+ continue;
+
+ rstc = of_reset_control_array_get(child, false, false);
+ if (IS_ERR(rstc))
+ continue;
+
+ len = strlen(compat);
+ if (!of_compat_cmp("isi,soft-resetn", compat, len)) {
+ mxc_isi->soft_resetn = rstc;
+ rstc_num++;
+ } else if (!of_compat_cmp("isi,clk-enable", compat, len)) {
+ mxc_isi->clk_enable = rstc;
+ rstc_num++;
+ } else {
+ dev_warn(dev, "invalid isi reset node: %s\n", compat);
+ }
+ }
+
+ if (!rstc_num) {
+ dev_err(dev, "no invalid reset control exists\n");
+ return -EINVAL;
+ }
+
+ of_node_put(parent);
+ return 0;
+}
+
static int mxc_isi_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
mutex_init(&mxc_isi->m2m_lock);
atomic_set(&mxc_isi->open_count, 0);
- mxc_isi->gpr = syscon_regmap_lookup_by_phandle(dev->of_node, "isi-gpr");
- if (IS_ERR(mxc_isi->gpr)) {
- mxc_isi->gpr = NULL;
- dev_warn(dev, "can't find isi-gpr property\n");
+ if (of_device_is_compatible(dev->of_node, "fsl,imx8mn-isi")) {
+ ret = mxc_isi_of_parse_resets(mxc_isi);
+ if (ret) {
+ dev_warn(dev, "Can not parse reset control\n");
+ return ret;
+ }
}
ret = mxc_isi_clk_get(mxc_isi);
dev_err(dev, "ISI_%d enable clocks fail\n", mxc_isi->id);
return ret;
}
- disp_mix_sft_rstn(mxc_isi->gpr, false);
- disp_mix_clks_enable(mxc_isi->gpr, true);
+ disp_mix_sft_rstn(mxc_isi->soft_resetn, false);
+ disp_mix_clks_enable(mxc_isi->clk_enable, true);
mxc_isi_clean_registers(mxc_isi);
{
struct mxc_isi_dev *mxc_isi = dev_get_drvdata(dev);
- disp_mix_clks_enable(mxc_isi->gpr, false);
+ disp_mix_clks_enable(mxc_isi->clk_enable, false);
mxc_isi_clk_disable(mxc_isi);
return 0;
dev_err(dev, "%s clk enable fail\n", __func__);
return ret;
}
- disp_mix_sft_rstn(mxc_isi->gpr, false);
- disp_mix_clks_enable(mxc_isi->gpr, true);
+ disp_mix_sft_rstn(mxc_isi->soft_resetn, false);
+ disp_mix_clks_enable(mxc_isi->clk_enable, true);
return 0;
}
#include <media/v4l2-ctrls.h>
#include <media/videobuf2-core.h>
#include <media/videobuf2-dma-contig.h>
+#include <linux/reset.h>
#define MXC_ISI_DRIVER_NAME "mxc-isi"
#define MXC_ISI_MAX_DEVS 8
#define ISI_OF_NODE_NAME "isi"
-/* display_mix_sft_rstn_csr */
-#define EN_BUS_BLK_CLK_RSTN BIT(8)
-#define EN_ISI_APB_CLK_RSTN BIT(7)
-#define EN_ISI_PROC_CLK_RSTN BIT(6)
-
-/* display_mix_clk_en_csr */
-#define EN_BUS_BLK_CLK BIT(8)
-#define EN_ISI_APB_CLK BIT(7)
-#define EN_ISI_PROC_CLK BIT(6)
-
#define MXC_ISI_SD_PAD_SINK_MIPI0_VC0 0
#define MXC_ISI_SD_PAD_SINK_MIPI0_VC1 1
#define MXC_ISI_SD_PAD_SINK_MIPI0_VC2 2
struct clk *clk_root_disp_axi;
struct clk *clk_root_disp_apb;
- struct regmap *gpr;
const struct mxc_isi_dev_ops *ops;
+ struct reset_control *soft_resetn;
+ struct reset_control *clk_enable;
+
u32 interface[MAX_PORTS];
u32 flags;
u32 skip_m2m;
#include <linux/videodev2.h>
#include <media/v4l2-subdev.h>
#include <media/v4l2-device.h>
+#include <linux/reset.h>
#include "mxc-mipi-csi2-sam.h"
static void mipi_csis_phy_reset_mx8mn(struct csi_state *state)
{
- struct regmap *gpr = state->gpr;
+ struct reset_control *reset = state->mipi_reset;
- regmap_update_bits(gpr, GPR_MIPI_RESET, GPR_MIPI_S_RESETN, 0x0);
+ reset_control_assert(reset);
usleep_range(10, 20);
- regmap_update_bits(gpr, GPR_MIPI_RESET, GPR_MIPI_S_RESETN,
- GPR_MIPI_S_RESETN);
+ reset_control_deassert(reset);
usleep_range(10, 20);
}
return 0;
}
-static void disp_mix_sft_rstn(struct regmap *gpr, bool enable)
+static int disp_mix_sft_rstn(struct reset_control *reset, bool enable)
{
- if (!enable)
- /* release isi soft reset */
- regmap_update_bits(gpr,
- DISP_MIX_SFT_RSTN_CSR,
- EN_CSI_ACLK_RSTN | EN_CSI_PCLK_RSTN,
- EN_CSI_ACLK_RSTN | EN_CSI_PCLK_RSTN);
- else
- regmap_update_bits(gpr,
- DISP_MIX_SFT_RSTN_CSR,
- EN_CSI_ACLK_RSTN | EN_CSI_PCLK_RSTN,
- 0x0);
- usleep_range(20, 30);
+ int ret;
+
+ ret = enable ? reset_control_assert(reset) :
+ reset_control_deassert(reset);
+ return ret;
}
-static void disp_mix_clks_enable(struct regmap *gpr, bool enable)
+static int disp_mix_clks_enable(struct reset_control *reset, bool enable)
{
- if (enable)
- regmap_update_bits(gpr,
- DISP_MIX_CLK_EN_CSR,
- EN_CSI_ACLK | EN_CSI_PCLK,
- EN_CSI_ACLK | EN_CSI_PCLK);
- else
- regmap_update_bits(gpr,
- DISP_MIX_CLK_EN_CSR,
- EN_CSI_ACLK | EN_CSI_PCLK,
- 0x0);
- usleep_range(20, 30);
+ int ret;
+
+ ret = enable ? reset_control_assert(reset) :
+ reset_control_deassert(reset);
+ return ret;
}
static void disp_mix_gasket_config(struct csi_state *state)
return ret;
}
+static int mipi_csis_of_parse_resets(struct csi_state *state)
+{
+ int ret;
+ struct device *dev = state->dev;
+ struct device_node *np = dev->of_node;
+ struct device_node *parent, *child;
+ struct of_phandle_args args;
+ struct reset_control *rstc;
+ const char *compat;
+ uint32_t len, rstc_num = 0;
+
+ ret = of_parse_phandle_with_args(np, "resets", "#reset-cells",
+ 0, &args);
+ if (ret)
+ return ret;
+
+ parent = args.np;
+ for_each_child_of_node(parent, child) {
+ compat = of_get_property(child, "compatible", NULL);
+ if (!compat)
+ continue;
+
+ rstc = of_reset_control_array_get(child, false, false);
+ if (IS_ERR(rstc))
+ continue;
+
+ len = strlen(compat);
+ if (!of_compat_cmp("csi,soft-resetn", compat, len)) {
+ state->soft_resetn = rstc;
+ rstc_num++;
+ } else if (!of_compat_cmp("csi,clk-enable", compat, len)) {
+ state->clk_enable = rstc;
+ rstc_num++;
+ } else if (!of_compat_cmp("csi,mipi-reset", compat, len)) {
+ state->mipi_reset = rstc;
+ rstc_num++;
+ } else {
+ dev_warn(dev, "invalid csis reset node: %s\n", compat);
+ }
+ }
+
+ if (!rstc_num) {
+ dev_err(dev, "no invalid reset control exists\n");
+ return -EINVAL;
+ }
+ of_node_put(parent);
+
+ return 0;
+}
+
static int mipi_csis_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
return PTR_ERR(state->gpr);
}
+ ret = mipi_csis_of_parse_resets(state);
+ if (ret < 0) {
+ dev_err(dev, "Can not parse reset control\n");
+ return ret;
+ }
+
mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
state->regs = devm_ioremap_resource(dev, mem_res);
if (IS_ERR(state->regs))
if (ret < 0)
return ret;
- disp_mix_clks_enable(state->gpr, true);
- disp_mix_sft_rstn(state->gpr, false);
+ disp_mix_clks_enable(state->clk_enable, true);
+ disp_mix_sft_rstn(state->soft_resetn, false);
phy_reset_fn(state);
mipi_csis_clk_disable(state);
if (ret < 0)
return ret;
- disp_mix_clks_enable(state->gpr, false);
+ disp_mix_clks_enable(state->clk_enable, false);
mipi_csis_clk_disable(state);
return 0;
}
if (ret < 0)
return ret;
- disp_mix_clks_enable(state->gpr, true);
- disp_mix_sft_rstn(state->gpr, false);
+ disp_mix_clks_enable(state->clk_enable, true);
+ disp_mix_sft_rstn(state->soft_resetn, false);
return 0;
}
#define MIPI_CSIS_PKTDATA_EVEN 0x3000
#define MIPI_CSIS_PKTDATA_SIZE SZ_4K
-#define GPR_MIPI_RESET 0x08
-#define GPR_MIPI_S_RESETN BIT(16)
-
#define DEFAULT_SCLK_CSIS_FREQ 166000000UL
-/* display_mix_sft_rstn_csr */
-#define DISP_MIX_SFT_RSTN_CSR 0x00
-#define EN_CSI_ACLK_RSTN BIT(3)
-#define EN_CSI_PCLK_RSTN BIT(2)
-
-/* display_mix_clk_en_csr */
-#define DISP_MIX_CLK_EN_CSR 0x04
-#define EN_CSI_ACLK BIT(3)
-#define EN_CSI_PCLK BIT(2)
-
/* display_mix_clk_en_csr */
#define DISP_MIX_GASKET_0_CTRL 0x60
#define GASKET_0_CTRL_DATA_TYPE(x) (((x) & (0x3F)) << 8)
struct regulator *mipi_phy_regulator;
struct regmap *gpr;
+ struct reset_control *soft_resetn;
+ struct reset_control *clk_enable;
+ struct reset_control *mipi_reset;
};
/**