linux/drivers/gpu/drm/msm/dsi/pll/dsi_pll.c
<<
>>
Prefs
   1/*
   2 * Copyright (c) 2012-2015, The Linux Foundation. All rights reserved.
   3 *
   4 * This program is free software; you can redistribute it and/or modify
   5 * it under the terms of the GNU General Public License version 2 and
   6 * only version 2 as published by the Free Software Foundation.
   7 *
   8 * This program is distributed in the hope that it will be useful,
   9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  11 * GNU General Public License for more details.
  12 */
  13
  14#include "dsi_pll.h"
  15
  16static int dsi_pll_enable(struct msm_dsi_pll *pll)
  17{
  18        int i, ret = 0;
  19
  20        /*
  21         * Certain PLLs do not allow VCO rate update when it is on.
  22         * Keep track of their status to turn on/off after set rate success.
  23         */
  24        if (unlikely(pll->pll_on))
  25                return 0;
  26
  27        /* Try all enable sequences until one succeeds */
  28        for (i = 0; i < pll->en_seq_cnt; i++) {
  29                ret = pll->enable_seqs[i](pll);
  30                DBG("DSI PLL %s after sequence #%d",
  31                        ret ? "unlocked" : "locked", i + 1);
  32                if (!ret)
  33                        break;
  34        }
  35
  36        if (ret) {
  37                DRM_ERROR("DSI PLL failed to lock\n");
  38                return ret;
  39        }
  40
  41        pll->pll_on = true;
  42
  43        return 0;
  44}
  45
  46static void dsi_pll_disable(struct msm_dsi_pll *pll)
  47{
  48        if (unlikely(!pll->pll_on))
  49                return;
  50
  51        pll->disable_seq(pll);
  52
  53        pll->pll_on = false;
  54}
  55
  56/*
  57 * DSI PLL Helper functions
  58 */
  59long msm_dsi_pll_helper_clk_round_rate(struct clk_hw *hw,
  60                unsigned long rate, unsigned long *parent_rate)
  61{
  62        struct msm_dsi_pll *pll = hw_clk_to_pll(hw);
  63
  64        if      (rate < pll->min_rate)
  65                return  pll->min_rate;
  66        else if (rate > pll->max_rate)
  67                return  pll->max_rate;
  68        else
  69                return rate;
  70}
  71
  72int msm_dsi_pll_helper_clk_prepare(struct clk_hw *hw)
  73{
  74        struct msm_dsi_pll *pll = hw_clk_to_pll(hw);
  75
  76        return dsi_pll_enable(pll);
  77}
  78
  79void msm_dsi_pll_helper_clk_unprepare(struct clk_hw *hw)
  80{
  81        struct msm_dsi_pll *pll = hw_clk_to_pll(hw);
  82
  83        dsi_pll_disable(pll);
  84}
  85
  86void msm_dsi_pll_helper_unregister_clks(struct platform_device *pdev,
  87                                        struct clk **clks, u32 num_clks)
  88{
  89        of_clk_del_provider(pdev->dev.of_node);
  90
  91        if (!num_clks || !clks)
  92                return;
  93
  94        do {
  95                clk_unregister(clks[--num_clks]);
  96                clks[num_clks] = NULL;
  97        } while (num_clks);
  98}
  99
 100/*
 101 * DSI PLL API
 102 */
 103int msm_dsi_pll_get_clk_provider(struct msm_dsi_pll *pll,
 104        struct clk **byte_clk_provider, struct clk **pixel_clk_provider)
 105{
 106        if (pll->get_provider)
 107                return pll->get_provider(pll,
 108                                        byte_clk_provider,
 109                                        pixel_clk_provider);
 110
 111        return -EINVAL;
 112}
 113
 114void msm_dsi_pll_destroy(struct msm_dsi_pll *pll)
 115{
 116        if (pll->destroy)
 117                pll->destroy(pll);
 118}
 119
 120void msm_dsi_pll_save_state(struct msm_dsi_pll *pll)
 121{
 122        if (pll->save_state) {
 123                pll->save_state(pll);
 124                pll->state_saved = true;
 125        }
 126}
 127
 128int msm_dsi_pll_restore_state(struct msm_dsi_pll *pll)
 129{
 130        int ret;
 131
 132        if (pll->restore_state && pll->state_saved) {
 133                ret = pll->restore_state(pll);
 134                if (ret)
 135                        return ret;
 136
 137                pll->state_saved = false;
 138        }
 139
 140        return 0;
 141}
 142
 143int msm_dsi_pll_set_usecase(struct msm_dsi_pll *pll,
 144                            enum msm_dsi_phy_usecase uc)
 145{
 146        if (pll->set_usecase)
 147                return pll->set_usecase(pll, uc);
 148
 149        return 0;
 150}
 151
 152struct msm_dsi_pll *msm_dsi_pll_init(struct platform_device *pdev,
 153                        enum msm_dsi_phy_type type, int id)
 154{
 155        struct device *dev = &pdev->dev;
 156        struct msm_dsi_pll *pll;
 157
 158        switch (type) {
 159        case MSM_DSI_PHY_28NM_HPM:
 160        case MSM_DSI_PHY_28NM_LP:
 161                pll = msm_dsi_pll_28nm_init(pdev, type, id);
 162                break;
 163        case MSM_DSI_PHY_28NM_8960:
 164                pll = msm_dsi_pll_28nm_8960_init(pdev, id);
 165                break;
 166        case MSM_DSI_PHY_14NM:
 167                pll = msm_dsi_pll_14nm_init(pdev, id);
 168                break;
 169        case MSM_DSI_PHY_10NM:
 170                pll = msm_dsi_pll_10nm_init(pdev, id);
 171                break;
 172        default:
 173                pll = ERR_PTR(-ENXIO);
 174                break;
 175        }
 176
 177        if (IS_ERR(pll)) {
 178                dev_err(dev, "%s: failed to init DSI PLL\n", __func__);
 179                return pll;
 180        }
 181
 182        pll->type = type;
 183
 184        DBG("DSI:%d PLL registered", id);
 185
 186        return pll;
 187}
 188
 189