Linux Audio

Check our new training course

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