// SPDX-License-Identifier: GPL-2.0-only 
 | 
/* 
 | 
 * Copyright (c) 2016 MediaTek Inc. 
 | 
 * Author: Ming Hsiu Tsai <minghsiu.tsai@mediatek.com> 
 | 
 */ 
 | 
  
 | 
#include <linux/clk.h> 
 | 
#include <linux/device.h> 
 | 
#include <linux/of.h> 
 | 
#include <linux/of_address.h> 
 | 
#include <linux/of_platform.h> 
 | 
#include <soc/mediatek/smi.h> 
 | 
  
 | 
#include "mtk_mdp_comp.h" 
 | 
  
 | 
  
 | 
void mtk_mdp_comp_clock_on(struct device *dev, struct mtk_mdp_comp *comp) 
 | 
{ 
 | 
    int i, err; 
 | 
  
 | 
    if (comp->larb_dev) { 
 | 
        err = mtk_smi_larb_get(comp->larb_dev); 
 | 
        if (err) 
 | 
            dev_err(dev, 
 | 
                "failed to get larb, err %d. type:%d\n", 
 | 
                err, comp->type); 
 | 
    } 
 | 
  
 | 
    for (i = 0; i < ARRAY_SIZE(comp->clk); i++) { 
 | 
        if (IS_ERR(comp->clk[i])) 
 | 
            continue; 
 | 
        err = clk_prepare_enable(comp->clk[i]); 
 | 
        if (err) 
 | 
            dev_err(dev, 
 | 
            "failed to enable clock, err %d. type:%d i:%d\n", 
 | 
                err, comp->type, i); 
 | 
    } 
 | 
} 
 | 
  
 | 
void mtk_mdp_comp_clock_off(struct device *dev, struct mtk_mdp_comp *comp) 
 | 
{ 
 | 
    int i; 
 | 
  
 | 
    for (i = 0; i < ARRAY_SIZE(comp->clk); i++) { 
 | 
        if (IS_ERR(comp->clk[i])) 
 | 
            continue; 
 | 
        clk_disable_unprepare(comp->clk[i]); 
 | 
    } 
 | 
  
 | 
    if (comp->larb_dev) 
 | 
        mtk_smi_larb_put(comp->larb_dev); 
 | 
} 
 | 
  
 | 
int mtk_mdp_comp_init(struct device *dev, struct device_node *node, 
 | 
              struct mtk_mdp_comp *comp, 
 | 
              enum mtk_mdp_comp_type comp_type) 
 | 
{ 
 | 
    struct device_node *larb_node; 
 | 
    struct platform_device *larb_pdev; 
 | 
    int ret; 
 | 
    int i; 
 | 
  
 | 
    comp->dev_node = of_node_get(node); 
 | 
    comp->type = comp_type; 
 | 
  
 | 
    for (i = 0; i < ARRAY_SIZE(comp->clk); i++) { 
 | 
        comp->clk[i] = of_clk_get(node, i); 
 | 
        if (IS_ERR(comp->clk[i])) { 
 | 
            if (PTR_ERR(comp->clk[i]) != -EPROBE_DEFER) 
 | 
                dev_err(dev, "Failed to get clock\n"); 
 | 
            ret = PTR_ERR(comp->clk[i]); 
 | 
            goto put_dev; 
 | 
        } 
 | 
  
 | 
        /* Only RDMA needs two clocks */ 
 | 
        if (comp->type != MTK_MDP_RDMA) 
 | 
            break; 
 | 
    } 
 | 
  
 | 
    /* Only DMA capable components need the LARB property */ 
 | 
    comp->larb_dev = NULL; 
 | 
    if (comp->type != MTK_MDP_RDMA && 
 | 
        comp->type != MTK_MDP_WDMA && 
 | 
        comp->type != MTK_MDP_WROT) 
 | 
        return 0; 
 | 
  
 | 
    larb_node = of_parse_phandle(node, "mediatek,larb", 0); 
 | 
    if (!larb_node) { 
 | 
        dev_err(dev, 
 | 
            "Missing mediadek,larb phandle in %pOF node\n", node); 
 | 
        ret = -EINVAL; 
 | 
        goto put_dev; 
 | 
    } 
 | 
  
 | 
    larb_pdev = of_find_device_by_node(larb_node); 
 | 
    if (!larb_pdev) { 
 | 
        dev_warn(dev, "Waiting for larb device %pOF\n", larb_node); 
 | 
        of_node_put(larb_node); 
 | 
        ret = -EPROBE_DEFER; 
 | 
        goto put_dev; 
 | 
    } 
 | 
    of_node_put(larb_node); 
 | 
  
 | 
    comp->larb_dev = &larb_pdev->dev; 
 | 
  
 | 
    return 0; 
 | 
  
 | 
put_dev: 
 | 
    of_node_put(comp->dev_node); 
 | 
  
 | 
    return ret; 
 | 
} 
 | 
  
 | 
void mtk_mdp_comp_deinit(struct device *dev, struct mtk_mdp_comp *comp) 
 | 
{ 
 | 
    of_node_put(comp->dev_node); 
 | 
} 
 |