linux/drivers/clk/rockchip/softrst.c
<<
>>
Prefs
   1/*
   2 * Copyright (c) 2014 MundoReader S.L.
   3 * Author: Heiko Stuebner <heiko@sntech.de>
   4 *
   5 * This program is free software; you can redistribute it and/or modify
   6 * it under the terms of the GNU General Public License as published by
   7 * the Free Software Foundation; either version 2 of the License, or
   8 * (at your option) any later version.
   9 *
  10 * This program is distributed in the hope that it will be useful,
  11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13 * GNU General Public License for more details.
  14 */
  15
  16#include <linux/slab.h>
  17#include <linux/io.h>
  18#include <linux/reset-controller.h>
  19#include <linux/spinlock.h>
  20#include "clk.h"
  21
  22struct rockchip_softrst {
  23        struct reset_controller_dev     rcdev;
  24        void __iomem                    *reg_base;
  25        int                             num_regs;
  26        int                             num_per_reg;
  27        u8                              flags;
  28        spinlock_t                      lock;
  29};
  30
  31static int rockchip_softrst_assert(struct reset_controller_dev *rcdev,
  32                              unsigned long id)
  33{
  34        struct rockchip_softrst *softrst = container_of(rcdev,
  35                                                     struct rockchip_softrst,
  36                                                     rcdev);
  37        int bank = id / softrst->num_per_reg;
  38        int offset = id % softrst->num_per_reg;
  39
  40        if (softrst->flags & ROCKCHIP_SOFTRST_HIWORD_MASK) {
  41                writel(BIT(offset) | (BIT(offset) << 16),
  42                       softrst->reg_base + (bank * 4));
  43        } else {
  44                unsigned long flags;
  45                u32 reg;
  46
  47                spin_lock_irqsave(&softrst->lock, flags);
  48
  49                reg = readl(softrst->reg_base + (bank * 4));
  50                writel(reg | BIT(offset), softrst->reg_base + (bank * 4));
  51
  52                spin_unlock_irqrestore(&softrst->lock, flags);
  53        }
  54
  55        return 0;
  56}
  57
  58static int rockchip_softrst_deassert(struct reset_controller_dev *rcdev,
  59                                unsigned long id)
  60{
  61        struct rockchip_softrst *softrst = container_of(rcdev,
  62                                                     struct rockchip_softrst,
  63                                                     rcdev);
  64        int bank = id / softrst->num_per_reg;
  65        int offset = id % softrst->num_per_reg;
  66
  67        if (softrst->flags & ROCKCHIP_SOFTRST_HIWORD_MASK) {
  68                writel((BIT(offset) << 16), softrst->reg_base + (bank * 4));
  69        } else {
  70                unsigned long flags;
  71                u32 reg;
  72
  73                spin_lock_irqsave(&softrst->lock, flags);
  74
  75                reg = readl(softrst->reg_base + (bank * 4));
  76                writel(reg & ~BIT(offset), softrst->reg_base + (bank * 4));
  77
  78                spin_unlock_irqrestore(&softrst->lock, flags);
  79        }
  80
  81        return 0;
  82}
  83
  84static const struct reset_control_ops rockchip_softrst_ops = {
  85        .assert         = rockchip_softrst_assert,
  86        .deassert       = rockchip_softrst_deassert,
  87};
  88
  89void __init rockchip_register_softrst(struct device_node *np,
  90                                      unsigned int num_regs,
  91                                      void __iomem *base, u8 flags)
  92{
  93        struct rockchip_softrst *softrst;
  94        int ret;
  95
  96        softrst = kzalloc(sizeof(*softrst), GFP_KERNEL);
  97        if (!softrst)
  98                return;
  99
 100        spin_lock_init(&softrst->lock);
 101
 102        softrst->reg_base = base;
 103        softrst->flags = flags;
 104        softrst->num_regs = num_regs;
 105        softrst->num_per_reg = (flags & ROCKCHIP_SOFTRST_HIWORD_MASK) ? 16
 106                                                                      : 32;
 107
 108        softrst->rcdev.owner = THIS_MODULE;
 109        softrst->rcdev.nr_resets =  num_regs * softrst->num_per_reg;
 110        softrst->rcdev.ops = &rockchip_softrst_ops;
 111        softrst->rcdev.of_node = np;
 112        ret = reset_controller_register(&softrst->rcdev);
 113        if (ret) {
 114                pr_err("%s: could not register reset controller, %d\n",
 115                       __func__, ret);
 116                kfree(softrst);
 117        }
 118};
 119