Linux Audio

Check our new training course

Loading...
Note: File does not exist in v5.4.
  1/*
  2 * OMAP2 and OMAP3 clockdomain control
  3 *
  4 * Copyright (C) 2008-2010 Texas Instruments, Inc.
  5 * Copyright (C) 2008-2010 Nokia Corporation
  6 *
  7 * Derived from mach-omap2/clockdomain.c written by Paul Walmsley
  8 * Rajendra Nayak <rnayak@ti.com>
  9 *
 10 * This program is free software; you can redistribute it and/or modify
 11 * it under the terms of the GNU General Public License version 2 as
 12 * published by the Free Software Foundation.
 13 */
 14
 15#include <linux/types.h>
 16#include <plat/prcm.h>
 17#include "prm.h"
 18#include "prm2xxx_3xxx.h"
 19#include "cm.h"
 20#include "cm2xxx_3xxx.h"
 21#include "cm-regbits-24xx.h"
 22#include "cm-regbits-34xx.h"
 23#include "prm-regbits-24xx.h"
 24#include "clockdomain.h"
 25
 26static int omap2_clkdm_add_wkdep(struct clockdomain *clkdm1,
 27						struct clockdomain *clkdm2)
 28{
 29	omap2_prm_set_mod_reg_bits((1 << clkdm2->dep_bit),
 30				clkdm1->pwrdm.ptr->prcm_offs, PM_WKDEP);
 31	return 0;
 32}
 33
 34static int omap2_clkdm_del_wkdep(struct clockdomain *clkdm1,
 35						 struct clockdomain *clkdm2)
 36{
 37	omap2_prm_clear_mod_reg_bits((1 << clkdm2->dep_bit),
 38				clkdm1->pwrdm.ptr->prcm_offs, PM_WKDEP);
 39	return 0;
 40}
 41
 42static int omap2_clkdm_read_wkdep(struct clockdomain *clkdm1,
 43						 struct clockdomain *clkdm2)
 44{
 45	return omap2_prm_read_mod_bits_shift(clkdm1->pwrdm.ptr->prcm_offs,
 46				PM_WKDEP, (1 << clkdm2->dep_bit));
 47}
 48
 49static int omap2_clkdm_clear_all_wkdeps(struct clockdomain *clkdm)
 50{
 51	struct clkdm_dep *cd;
 52	u32 mask = 0;
 53
 54	for (cd = clkdm->wkdep_srcs; cd && cd->clkdm_name; cd++) {
 55		if (!cd->clkdm)
 56			continue; /* only happens if data is erroneous */
 57
 58		/* PRM accesses are slow, so minimize them */
 59		mask |= 1 << cd->clkdm->dep_bit;
 60		atomic_set(&cd->wkdep_usecount, 0);
 61	}
 62
 63	omap2_prm_clear_mod_reg_bits(mask, clkdm->pwrdm.ptr->prcm_offs,
 64				 PM_WKDEP);
 65	return 0;
 66}
 67
 68static int omap3_clkdm_add_sleepdep(struct clockdomain *clkdm1,
 69						 struct clockdomain *clkdm2)
 70{
 71	omap2_cm_set_mod_reg_bits((1 << clkdm2->dep_bit),
 72				clkdm1->pwrdm.ptr->prcm_offs,
 73				OMAP3430_CM_SLEEPDEP);
 74	return 0;
 75}
 76
 77static int omap3_clkdm_del_sleepdep(struct clockdomain *clkdm1,
 78						 struct clockdomain *clkdm2)
 79{
 80	omap2_cm_clear_mod_reg_bits((1 << clkdm2->dep_bit),
 81				clkdm1->pwrdm.ptr->prcm_offs,
 82				OMAP3430_CM_SLEEPDEP);
 83	return 0;
 84}
 85
 86static int omap3_clkdm_read_sleepdep(struct clockdomain *clkdm1,
 87						 struct clockdomain *clkdm2)
 88{
 89	return omap2_prm_read_mod_bits_shift(clkdm1->pwrdm.ptr->prcm_offs,
 90				OMAP3430_CM_SLEEPDEP, (1 << clkdm2->dep_bit));
 91}
 92
 93static int omap3_clkdm_clear_all_sleepdeps(struct clockdomain *clkdm)
 94{
 95	struct clkdm_dep *cd;
 96	u32 mask = 0;
 97
 98	for (cd = clkdm->sleepdep_srcs; cd && cd->clkdm_name; cd++) {
 99		if (!cd->clkdm)
100			continue; /* only happens if data is erroneous */
101
102		/* PRM accesses are slow, so minimize them */
103		mask |= 1 << cd->clkdm->dep_bit;
104		atomic_set(&cd->sleepdep_usecount, 0);
105	}
106	omap2_prm_clear_mod_reg_bits(mask, clkdm->pwrdm.ptr->prcm_offs,
107				OMAP3430_CM_SLEEPDEP);
108	return 0;
109}
110
111static int omap2_clkdm_sleep(struct clockdomain *clkdm)
112{
113	omap2_cm_set_mod_reg_bits(OMAP24XX_FORCESTATE_MASK,
114				clkdm->pwrdm.ptr->prcm_offs,
115				OMAP2_PM_PWSTCTRL);
116	return 0;
117}
118
119static int omap2_clkdm_wakeup(struct clockdomain *clkdm)
120{
121	omap2_cm_clear_mod_reg_bits(OMAP24XX_FORCESTATE_MASK,
122				clkdm->pwrdm.ptr->prcm_offs,
123				OMAP2_PM_PWSTCTRL);
124	return 0;
125}
126
127static void omap2_clkdm_allow_idle(struct clockdomain *clkdm)
128{
129	if (atomic_read(&clkdm->usecount) > 0)
130		_clkdm_add_autodeps(clkdm);
131
132	omap2xxx_cm_clkdm_enable_hwsup(clkdm->pwrdm.ptr->prcm_offs,
133				clkdm->clktrctrl_mask);
134}
135
136static void omap2_clkdm_deny_idle(struct clockdomain *clkdm)
137{
138	omap2xxx_cm_clkdm_disable_hwsup(clkdm->pwrdm.ptr->prcm_offs,
139				clkdm->clktrctrl_mask);
140
141	if (atomic_read(&clkdm->usecount) > 0)
142		_clkdm_del_autodeps(clkdm);
143}
144
145static void _enable_hwsup(struct clockdomain *clkdm)
146{
147	if (cpu_is_omap24xx())
148		omap2xxx_cm_clkdm_enable_hwsup(clkdm->pwrdm.ptr->prcm_offs,
149					       clkdm->clktrctrl_mask);
150	else if (cpu_is_omap34xx())
151		omap3xxx_cm_clkdm_enable_hwsup(clkdm->pwrdm.ptr->prcm_offs,
152					       clkdm->clktrctrl_mask);
153}
154
155static void _disable_hwsup(struct clockdomain *clkdm)
156{
157	if (cpu_is_omap24xx())
158		omap2xxx_cm_clkdm_disable_hwsup(clkdm->pwrdm.ptr->prcm_offs,
159						clkdm->clktrctrl_mask);
160	else if (cpu_is_omap34xx())
161		omap3xxx_cm_clkdm_disable_hwsup(clkdm->pwrdm.ptr->prcm_offs,
162						clkdm->clktrctrl_mask);
163}
164
165
166static int omap2_clkdm_clk_enable(struct clockdomain *clkdm)
167{
168	bool hwsup = false;
169
170	if (!clkdm->clktrctrl_mask)
171		return 0;
172
173	hwsup = omap2_cm_is_clkdm_in_hwsup(clkdm->pwrdm.ptr->prcm_offs,
174				clkdm->clktrctrl_mask);
175
176	if (hwsup) {
177		/* Disable HW transitions when we are changing deps */
178		_disable_hwsup(clkdm);
179		_clkdm_add_autodeps(clkdm);
180		_enable_hwsup(clkdm);
181	} else {
182		if (clkdm->flags & CLKDM_CAN_FORCE_WAKEUP)
183			omap2_clkdm_wakeup(clkdm);
184	}
185
186	return 0;
187}
188
189static int omap2_clkdm_clk_disable(struct clockdomain *clkdm)
190{
191	bool hwsup = false;
192
193	if (!clkdm->clktrctrl_mask)
194		return 0;
195
196	hwsup = omap2_cm_is_clkdm_in_hwsup(clkdm->pwrdm.ptr->prcm_offs,
197				clkdm->clktrctrl_mask);
198
199	if (hwsup) {
200		/* Disable HW transitions when we are changing deps */
201		_disable_hwsup(clkdm);
202		_clkdm_del_autodeps(clkdm);
203		_enable_hwsup(clkdm);
204	} else {
205		if (clkdm->flags & CLKDM_CAN_FORCE_SLEEP)
206			omap2_clkdm_sleep(clkdm);
207	}
208
209	return 0;
210}
211
212static int omap3_clkdm_sleep(struct clockdomain *clkdm)
213{
214	omap3xxx_cm_clkdm_force_sleep(clkdm->pwrdm.ptr->prcm_offs,
215				clkdm->clktrctrl_mask);
216	return 0;
217}
218
219static int omap3_clkdm_wakeup(struct clockdomain *clkdm)
220{
221	omap3xxx_cm_clkdm_force_wakeup(clkdm->pwrdm.ptr->prcm_offs,
222				clkdm->clktrctrl_mask);
223	return 0;
224}
225
226static void omap3_clkdm_allow_idle(struct clockdomain *clkdm)
227{
228	if (atomic_read(&clkdm->usecount) > 0)
229		_clkdm_add_autodeps(clkdm);
230
231	omap3xxx_cm_clkdm_enable_hwsup(clkdm->pwrdm.ptr->prcm_offs,
232				clkdm->clktrctrl_mask);
233}
234
235static void omap3_clkdm_deny_idle(struct clockdomain *clkdm)
236{
237	omap3xxx_cm_clkdm_disable_hwsup(clkdm->pwrdm.ptr->prcm_offs,
238				clkdm->clktrctrl_mask);
239
240	if (atomic_read(&clkdm->usecount) > 0)
241		_clkdm_del_autodeps(clkdm);
242}
243
244struct clkdm_ops omap2_clkdm_operations = {
245	.clkdm_add_wkdep	= omap2_clkdm_add_wkdep,
246	.clkdm_del_wkdep	= omap2_clkdm_del_wkdep,
247	.clkdm_read_wkdep	= omap2_clkdm_read_wkdep,
248	.clkdm_clear_all_wkdeps	= omap2_clkdm_clear_all_wkdeps,
249	.clkdm_sleep		= omap2_clkdm_sleep,
250	.clkdm_wakeup		= omap2_clkdm_wakeup,
251	.clkdm_allow_idle	= omap2_clkdm_allow_idle,
252	.clkdm_deny_idle	= omap2_clkdm_deny_idle,
253	.clkdm_clk_enable	= omap2_clkdm_clk_enable,
254	.clkdm_clk_disable	= omap2_clkdm_clk_disable,
255};
256
257struct clkdm_ops omap3_clkdm_operations = {
258	.clkdm_add_wkdep	= omap2_clkdm_add_wkdep,
259	.clkdm_del_wkdep	= omap2_clkdm_del_wkdep,
260	.clkdm_read_wkdep	= omap2_clkdm_read_wkdep,
261	.clkdm_clear_all_wkdeps	= omap2_clkdm_clear_all_wkdeps,
262	.clkdm_add_sleepdep	= omap3_clkdm_add_sleepdep,
263	.clkdm_del_sleepdep	= omap3_clkdm_del_sleepdep,
264	.clkdm_read_sleepdep	= omap3_clkdm_read_sleepdep,
265	.clkdm_clear_all_sleepdeps	= omap3_clkdm_clear_all_sleepdeps,
266	.clkdm_sleep		= omap3_clkdm_sleep,
267	.clkdm_wakeup		= omap3_clkdm_wakeup,
268	.clkdm_allow_idle	= omap3_clkdm_allow_idle,
269	.clkdm_deny_idle	= omap3_clkdm_deny_idle,
270	.clkdm_clk_enable	= omap2_clkdm_clk_enable,
271	.clkdm_clk_disable	= omap2_clkdm_clk_disable,
272};