123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160 |
- #include <linux/clk.h>
- #include <linux/compiler.h>
- #include <linux/io.h>
- #include <linux/spinlock.h>
- #include <asm/suspend.h>
- #include <asm/hwblk.h>
- #include <asm/clock.h>
- static DEFINE_SPINLOCK(hwblk_lock);
- static void hwblk_area_mod_cnt(struct hwblk_info *info,
- int area, int counter, int value, int goal)
- {
- struct hwblk_area *hap = info->areas + area;
- hap->cnt[counter] += value;
- if (hap->cnt[counter] != goal)
- return;
- if (hap->flags & HWBLK_AREA_FLAG_PARENT)
- hwblk_area_mod_cnt(info, hap->parent, counter, value, goal);
- }
- static int __hwblk_mod_cnt(struct hwblk_info *info, int hwblk,
- int counter, int value, int goal)
- {
- struct hwblk *hp = info->hwblks + hwblk;
- hp->cnt[counter] += value;
- if (hp->cnt[counter] == goal)
- hwblk_area_mod_cnt(info, hp->area, counter, value, goal);
- return hp->cnt[counter];
- }
- static void hwblk_mod_cnt(struct hwblk_info *info, int hwblk,
- int counter, int value, int goal)
- {
- unsigned long flags;
- spin_lock_irqsave(&hwblk_lock, flags);
- __hwblk_mod_cnt(info, hwblk, counter, value, goal);
- spin_unlock_irqrestore(&hwblk_lock, flags);
- }
- void hwblk_cnt_inc(struct hwblk_info *info, int hwblk, int counter)
- {
- hwblk_mod_cnt(info, hwblk, counter, 1, 1);
- }
- void hwblk_cnt_dec(struct hwblk_info *info, int hwblk, int counter)
- {
- hwblk_mod_cnt(info, hwblk, counter, -1, 0);
- }
- void hwblk_enable(struct hwblk_info *info, int hwblk)
- {
- struct hwblk *hp = info->hwblks + hwblk;
- unsigned long tmp;
- unsigned long flags;
- int ret;
- spin_lock_irqsave(&hwblk_lock, flags);
- ret = __hwblk_mod_cnt(info, hwblk, HWBLK_CNT_USAGE, 1, 1);
- if (ret == 1) {
- tmp = __raw_readl(hp->mstp);
- tmp &= ~(1 << hp->bit);
- __raw_writel(tmp, hp->mstp);
- }
- spin_unlock_irqrestore(&hwblk_lock, flags);
- }
- void hwblk_disable(struct hwblk_info *info, int hwblk)
- {
- struct hwblk *hp = info->hwblks + hwblk;
- unsigned long tmp;
- unsigned long flags;
- int ret;
- spin_lock_irqsave(&hwblk_lock, flags);
- ret = __hwblk_mod_cnt(info, hwblk, HWBLK_CNT_USAGE, -1, 0);
- if (ret == 0) {
- tmp = __raw_readl(hp->mstp);
- tmp |= 1 << hp->bit;
- __raw_writel(tmp, hp->mstp);
- }
- spin_unlock_irqrestore(&hwblk_lock, flags);
- }
- struct hwblk_info *hwblk_info;
- int __init hwblk_register(struct hwblk_info *info)
- {
- hwblk_info = info;
- return 0;
- }
- int __init __weak arch_hwblk_init(void)
- {
- return 0;
- }
- int __weak arch_hwblk_sleep_mode(void)
- {
- return SUSP_SH_SLEEP;
- }
- int __init hwblk_init(void)
- {
- return arch_hwblk_init();
- }
- /* allow clocks to enable and disable hardware blocks */
- static int sh_hwblk_clk_enable(struct clk *clk)
- {
- if (!hwblk_info)
- return -ENOENT;
- hwblk_enable(hwblk_info, clk->arch_flags);
- return 0;
- }
- static void sh_hwblk_clk_disable(struct clk *clk)
- {
- if (hwblk_info)
- hwblk_disable(hwblk_info, clk->arch_flags);
- }
- static struct clk_ops sh_hwblk_clk_ops = {
- .enable = sh_hwblk_clk_enable,
- .disable = sh_hwblk_clk_disable,
- .recalc = followparent_recalc,
- };
- int __init sh_hwblk_clk_register(struct clk *clks, int nr)
- {
- struct clk *clkp;
- int ret = 0;
- int k;
- for (k = 0; !ret && (k < nr); k++) {
- clkp = clks + k;
- /* skip over clocks using hwblk 0 (HWBLK_UNKNOWN) */
- if (!clkp->arch_flags)
- continue;
- clkp->ops = &sh_hwblk_clk_ops;
- ret |= clk_register(clkp);
- }
- return ret;
- }
|