/*
* OMAP powerdomain control
*
* Copyright (C) 2007-2008 Texas Instruments, Inc.
* Copyright (C) 2007-2008 Nokia Corporation
*
* Written by Paul Walmsley
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#ifdef CONFIG_OMAP_DEBUG_POWERDOMAIN
# define DEBUG
#endif
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/types.h>
#include <linux/delay.h>
#include <linux/spinlock.h>
#include <linux/list.h>
#include <linux/errno.h>
#include <linux/err.h>
#include <linux/io.h>
#include <asm/atomic.h>
#include "cm.h"
#include "cm-regbits-34xx.h"
#include "prm.h"
#include "prm-regbits-34xx.h"
#include <mach/cpu.h>
#include <mach/powerdomain.h>
#include <mach/clockdomain.h>
#include "pm.h"
enum {
PWRDM_STATE_NOW = 0,
PWRDM_STATE_PREV,
};
/* pwrdm_list contains all registered struct powerdomains */
static LIST_HEAD(pwrdm_list);
/*
* pwrdm_rwlock protects pwrdm_list add and del ops - also reused to
* protect pwrdm_clkdms[] during clkdm add/del ops
*/
static DEFINE_RWLOCK(pwrdm_rwlock);
/* Private functions */
static u32 prm_read_mod_bits_shift(s16 domain, s16 idx, u32 mask)
{
u32 v;
v = prm_read_mod_reg(domain, idx);
v &= mask;
v >>= __ffs(mask);
return v;
}
static struct powerdomain *_pwrdm_lookup(const char *name)
{
struct powerdomain *pwrdm, *temp_pwrdm;
pwrdm = NULL;
list_for_each_entry(temp_pwrdm, &pwrdm_list, node) {
if (!strcmp(name, temp_pwrdm->name)) {
pwrdm = temp_pwrdm;
break;
}
}
return pwrdm;
}
/* _pwrdm_deps_lookup - look up the specified powerdomain in a pwrdm list */
static struct powerdomain *_pwrdm_deps_lookup(struct powerdomain *pwrdm,
struct pwrdm_dep *deps)
{
struct pwrdm_dep *pd;
if (!pwrdm || !deps || !omap_chip_is(pwrdm->omap_chip))
return ERR_PTR(-EINVAL);
for (pd = deps; pd->pwrdm_name; pd++) {
if (!omap_chip_is(pd->omap_chip))
continue;
if (!pd->pwrdm && pd->pwrdm_name)
pd->pwrdm = pwrdm_lookup(pd->pwrdm_name);
if (pd->pwrdm == pwrdm)
break;
}
if (!pd->pwrdm_name)
return ERR_PTR(-ENOENT);
return pd->pwrdm;
}
static int _pwrdm_state_switch(struct powerdomain *pwrdm, int flag)
{
int prev;
int state;
if (pwrdm == NULL)
return -EINVAL;
state = pwrdm_read_pwrst(pwrdm);
switch (flag) {
case PWRDM_STATE_NOW:
prev = pwrdm->state;
break;
case PWRDM_STATE_PREV:
prev = pwrdm_read_prev_pwrst(pwrdm);
if (pwrdm->state != prev)
pwrdm->state_counter[prev]++;
break