-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Some clock control regsiter has bit to reset the cotroller. So before enable the clock, we need deassert the reset pin. Make use of reset controller framework to export reset interface for device drivers, then device driver can control the reset action. Signed-off-by: Chao Xie <chao.xie@marvell.com> Acked-by: Haojian Zhuang <haojian.zhuang@gmail.com> Signed-off-by: Michael Turquette <mturquette@linaro.org>
- Loading branch information
Chao Xie
authored and
Michael Turquette
committed
Nov 13, 2014
1 parent
4661fda
commit ae32a5b
Showing
3 changed files
with
132 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,99 @@ | ||
#include <linux/slab.h> | ||
#include <linux/io.h> | ||
#include <linux/of.h> | ||
#include <linux/of_address.h> | ||
#include <linux/reset-controller.h> | ||
|
||
#include "reset.h" | ||
|
||
#define rcdev_to_unit(rcdev) container_of(rcdev, struct mmp_clk_reset_unit, rcdev) | ||
|
||
static int mmp_of_reset_xlate(struct reset_controller_dev *rcdev, | ||
const struct of_phandle_args *reset_spec) | ||
{ | ||
struct mmp_clk_reset_unit *unit = rcdev_to_unit(rcdev); | ||
struct mmp_clk_reset_cell *cell; | ||
int i; | ||
|
||
if (WARN_ON(reset_spec->args_count != rcdev->of_reset_n_cells)) | ||
return -EINVAL; | ||
|
||
for (i = 0; i < rcdev->nr_resets; i++) { | ||
cell = &unit->cells[i]; | ||
if (cell->clk_id == reset_spec->args[0]) | ||
break; | ||
} | ||
|
||
if (i == rcdev->nr_resets) | ||
return -EINVAL; | ||
|
||
return i; | ||
} | ||
|
||
static int mmp_clk_reset_assert(struct reset_controller_dev *rcdev, | ||
unsigned long id) | ||
{ | ||
struct mmp_clk_reset_unit *unit = rcdev_to_unit(rcdev); | ||
struct mmp_clk_reset_cell *cell; | ||
unsigned long flags = 0; | ||
u32 val; | ||
|
||
cell = &unit->cells[id]; | ||
if (cell->lock) | ||
spin_lock_irqsave(cell->lock, flags); | ||
|
||
val = readl(cell->reg); | ||
val |= cell->bits; | ||
writel(val, cell->reg); | ||
|
||
if (cell->lock) | ||
spin_unlock_irqrestore(cell->lock, flags); | ||
|
||
return 0; | ||
} | ||
|
||
static int mmp_clk_reset_deassert(struct reset_controller_dev *rcdev, | ||
unsigned long id) | ||
{ | ||
struct mmp_clk_reset_unit *unit = rcdev_to_unit(rcdev); | ||
struct mmp_clk_reset_cell *cell; | ||
unsigned long flags = 0; | ||
u32 val; | ||
|
||
cell = &unit->cells[id]; | ||
if (cell->lock) | ||
spin_lock_irqsave(cell->lock, flags); | ||
|
||
val = readl(cell->reg); | ||
val &= ~cell->bits; | ||
writel(val, cell->reg); | ||
|
||
if (cell->lock) | ||
spin_unlock_irqrestore(cell->lock, flags); | ||
|
||
return 0; | ||
} | ||
|
||
static struct reset_control_ops mmp_clk_reset_ops = { | ||
.assert = mmp_clk_reset_assert, | ||
.deassert = mmp_clk_reset_deassert, | ||
}; | ||
|
||
void mmp_clk_reset_register(struct device_node *np, | ||
struct mmp_clk_reset_cell *cells, int nr_resets) | ||
{ | ||
struct mmp_clk_reset_unit *unit; | ||
|
||
unit = kzalloc(sizeof(*unit), GFP_KERNEL); | ||
if (!unit) | ||
return; | ||
|
||
unit->cells = cells; | ||
unit->rcdev.of_reset_n_cells = 1; | ||
unit->rcdev.nr_resets = nr_resets; | ||
unit->rcdev.ops = &mmp_clk_reset_ops; | ||
unit->rcdev.of_node = np; | ||
unit->rcdev.of_xlate = mmp_of_reset_xlate; | ||
|
||
reset_controller_register(&unit->rcdev); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
#ifndef __MACH_MMP_CLK_RESET_H | ||
#define __MACH_MMP_CLK_RESET_H | ||
|
||
#include <linux/reset-controller.h> | ||
|
||
#define MMP_RESET_INVERT 1 | ||
|
||
struct mmp_clk_reset_cell { | ||
unsigned int clk_id; | ||
void __iomem *reg; | ||
u32 bits; | ||
unsigned int flags; | ||
spinlock_t *lock; | ||
}; | ||
|
||
struct mmp_clk_reset_unit { | ||
struct reset_controller_dev rcdev; | ||
struct mmp_clk_reset_cell *cells; | ||
}; | ||
|
||
#ifdef CONFIG_RESET_CONTROLLER | ||
void mmp_clk_reset_register(struct device_node *np, | ||
struct mmp_clk_reset_cell *cells, int nr_resets); | ||
#else | ||
static inline void mmp_clk_reset_register(struct device_node *np, | ||
struct mmp_clk_reset_cell *cells, int nr_resets) | ||
{ | ||
} | ||
#endif | ||
|
||
#endif |