-
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.
clk: sunxi-ng: Add common infrastructure
Start our new clock infrastructure by adding the registration code, common structure and common code. Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com> Signed-off-by: Michael Turquette <mturquette@baylibre.com> Link: lkml.kernel.org/r/20160629190535.11855-3-maxime.ripard@free-electrons.com
- Loading branch information
Maxime Ripard
authored and
Michael Turquette
committed
Jul 9, 2016
1 parent
c0692d6
commit 1d80c14
Showing
9 changed files
with
293 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
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,3 @@ | ||
config SUNXI_CCU | ||
bool "Clock support for Allwinner SoCs" | ||
default ARCH_SUNXI |
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,3 @@ | ||
# Common objects | ||
obj-$(CONFIG_SUNXI_CCU) += ccu_common.o | ||
obj-$(CONFIG_SUNXI_CCU) += ccu_reset.o |
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,90 @@ | ||
/* | ||
* Copyright 2016 Maxime Ripard | ||
* | ||
* Maxime Ripard <maxime.ripard@free-electrons.com> | ||
* | ||
* This program is free software; you can redistribute it and/or modify | ||
* it under the terms of the GNU General Public License as published by | ||
* the Free Software Foundation; either version 2 of the License, or | ||
* (at your option) any later version. | ||
* | ||
* This program is distributed in the hope that it will be useful, | ||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
* GNU General Public License for more details. | ||
*/ | ||
|
||
#include <linux/clk-provider.h> | ||
#include <linux/iopoll.h> | ||
#include <linux/slab.h> | ||
|
||
#include "ccu_common.h" | ||
#include "ccu_reset.h" | ||
|
||
static DEFINE_SPINLOCK(ccu_lock); | ||
|
||
void ccu_helper_wait_for_lock(struct ccu_common *common, u32 lock) | ||
{ | ||
u32 reg; | ||
|
||
if (!lock) | ||
return; | ||
|
||
WARN_ON(readl_relaxed_poll_timeout(common->base + common->reg, reg, | ||
!(reg & lock), 100, 70000)); | ||
} | ||
|
||
int sunxi_ccu_probe(struct device_node *node, void __iomem *reg, | ||
const struct sunxi_ccu_desc *desc) | ||
{ | ||
struct ccu_reset *reset; | ||
int i, ret; | ||
|
||
for (i = 0; i < desc->num_ccu_clks; i++) { | ||
struct ccu_common *cclk = desc->ccu_clks[i]; | ||
|
||
if (!cclk) | ||
continue; | ||
|
||
cclk->base = reg; | ||
cclk->lock = &ccu_lock; | ||
} | ||
|
||
for (i = 0; i < desc->hw_clks->num ; i++) { | ||
struct clk_hw *hw = desc->hw_clks->hws[i]; | ||
|
||
if (!hw) | ||
continue; | ||
|
||
ret = clk_hw_register(NULL, hw); | ||
if (ret) { | ||
pr_err("Couldn't register clock %s\n", | ||
clk_hw_get_name(hw)); | ||
goto err_clk_unreg; | ||
} | ||
} | ||
|
||
ret = of_clk_add_hw_provider(node, of_clk_hw_onecell_get, | ||
desc->hw_clks); | ||
if (ret) | ||
goto err_clk_unreg; | ||
|
||
reset = kzalloc(sizeof(*reset), GFP_KERNEL); | ||
reset->rcdev.of_node = node; | ||
reset->rcdev.ops = &ccu_reset_ops; | ||
reset->rcdev.owner = THIS_MODULE; | ||
reset->rcdev.nr_resets = desc->num_resets; | ||
reset->base = reg; | ||
reset->lock = &ccu_lock; | ||
reset->reset_map = desc->resets; | ||
|
||
ret = reset_controller_register(&reset->rcdev); | ||
if (ret) | ||
goto err_of_clk_unreg; | ||
|
||
return 0; | ||
|
||
err_of_clk_unreg: | ||
err_clk_unreg: | ||
return ret; | ||
} |
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,85 @@ | ||
/* | ||
* Copyright (c) 2016 Maxime Ripard. All rights reserved. | ||
* | ||
* This software is licensed under the terms of the GNU General Public | ||
* License version 2, as published by the Free Software Foundation, and | ||
* may be copied, distributed, and modified under those terms. | ||
* | ||
* This program is distributed in the hope that it will be useful, | ||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
* GNU General Public License for more details. | ||
*/ | ||
|
||
#ifndef _COMMON_H_ | ||
#define _COMMON_H_ | ||
|
||
#include <linux/compiler.h> | ||
#include <linux/clk-provider.h> | ||
|
||
#define CCU_FEATURE_FRACTIONAL BIT(0) | ||
#define CCU_FEATURE_VARIABLE_PREDIV BIT(1) | ||
#define CCU_FEATURE_FIXED_PREDIV BIT(2) | ||
#define CCU_FEATURE_FIXED_POSTDIV BIT(3) | ||
|
||
struct device_node; | ||
|
||
#define CLK_HW_INIT(_name, _parent, _ops, _flags) \ | ||
&(struct clk_init_data) { \ | ||
.flags = _flags, \ | ||
.name = _name, \ | ||
.parent_names = (const char *[]) { _parent }, \ | ||
.num_parents = 1, \ | ||
.ops = _ops, \ | ||
} | ||
|
||
#define CLK_HW_INIT_PARENTS(_name, _parents, _ops, _flags) \ | ||
&(struct clk_init_data) { \ | ||
.flags = _flags, \ | ||
.name = _name, \ | ||
.parent_names = _parents, \ | ||
.num_parents = ARRAY_SIZE(_parents), \ | ||
.ops = _ops, \ | ||
} | ||
|
||
#define CLK_FIXED_FACTOR(_struct, _name, _parent, \ | ||
_div, _mult, _flags) \ | ||
struct clk_fixed_factor _struct = { \ | ||
.div = _div, \ | ||
.mult = _mult, \ | ||
.hw.init = CLK_HW_INIT(_name, \ | ||
_parent, \ | ||
&clk_fixed_factor_ops, \ | ||
_flags), \ | ||
} | ||
|
||
struct ccu_common { | ||
void __iomem *base; | ||
u16 reg; | ||
|
||
unsigned long features; | ||
spinlock_t *lock; | ||
struct clk_hw hw; | ||
}; | ||
|
||
static inline struct ccu_common *hw_to_ccu_common(struct clk_hw *hw) | ||
{ | ||
return container_of(hw, struct ccu_common, hw); | ||
} | ||
|
||
struct sunxi_ccu_desc { | ||
struct ccu_common **ccu_clks; | ||
unsigned long num_ccu_clks; | ||
|
||
struct clk_hw_onecell_data *hw_clks; | ||
|
||
struct ccu_reset_map *resets; | ||
unsigned long num_resets; | ||
}; | ||
|
||
void ccu_helper_wait_for_lock(struct ccu_common *common, u32 lock); | ||
|
||
int sunxi_ccu_probe(struct device_node *node, void __iomem *reg, | ||
const struct sunxi_ccu_desc *desc); | ||
|
||
#endif /* _COMMON_H_ */ |
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,15 @@ | ||
#ifndef _CCU_MULT_H_ | ||
#define _CCU_MULT_H_ | ||
|
||
struct _ccu_mult { | ||
u8 shift; | ||
u8 width; | ||
}; | ||
|
||
#define _SUNXI_CCU_MULT(_shift, _width) \ | ||
{ \ | ||
.shift = _shift, \ | ||
.width = _width, \ | ||
} | ||
|
||
#endif /* _CCU_MULT_H_ */ |
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,55 @@ | ||
/* | ||
* Copyright (C) 2016 Maxime Ripard | ||
* Maxime Ripard <maxime.ripard@free-electrons.com> | ||
* | ||
* This program is free software; you can redistribute it and/or | ||
* modify it under the terms of the GNU General Public License as | ||
* published by the Free Software Foundation; either version 2 of | ||
* the License, or (at your option) any later version. | ||
*/ | ||
|
||
#include <linux/io.h> | ||
#include <linux/reset-controller.h> | ||
|
||
#include "ccu_reset.h" | ||
|
||
static int ccu_reset_assert(struct reset_controller_dev *rcdev, | ||
unsigned long id) | ||
{ | ||
struct ccu_reset *ccu = rcdev_to_ccu_reset(rcdev); | ||
const struct ccu_reset_map *map = &ccu->reset_map[id]; | ||
unsigned long flags; | ||
u32 reg; | ||
|
||
spin_lock_irqsave(ccu->lock, flags); | ||
|
||
reg = readl(ccu->base + map->reg); | ||
writel(reg & ~map->bit, ccu->base + map->reg); | ||
|
||
spin_unlock_irqrestore(ccu->lock, flags); | ||
|
||
return 0; | ||
} | ||
|
||
static int ccu_reset_deassert(struct reset_controller_dev *rcdev, | ||
unsigned long id) | ||
{ | ||
struct ccu_reset *ccu = rcdev_to_ccu_reset(rcdev); | ||
const struct ccu_reset_map *map = &ccu->reset_map[id]; | ||
unsigned long flags; | ||
u32 reg; | ||
|
||
spin_lock_irqsave(ccu->lock, flags); | ||
|
||
reg = readl(ccu->base + map->reg); | ||
writel(reg | map->bit, ccu->base + map->reg); | ||
|
||
spin_unlock_irqrestore(ccu->lock, flags); | ||
|
||
return 0; | ||
} | ||
|
||
const struct reset_control_ops ccu_reset_ops = { | ||
.assert = ccu_reset_assert, | ||
.deassert = ccu_reset_deassert, | ||
}; |
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,40 @@ | ||
/* | ||
* Copyright (c) 2016 Maxime Ripard. All rights reserved. | ||
* | ||
* This software is licensed under the terms of the GNU General Public | ||
* License version 2, as published by the Free Software Foundation, and | ||
* may be copied, distributed, and modified under those terms. | ||
* | ||
* This program is distributed in the hope that it will be useful, | ||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
* GNU General Public License for more details. | ||
*/ | ||
|
||
#ifndef _CCU_RESET_H_ | ||
#define _CCU_RESET_H_ | ||
|
||
#include <linux/reset-controller.h> | ||
|
||
struct ccu_reset_map { | ||
u16 reg; | ||
u32 bit; | ||
}; | ||
|
||
|
||
struct ccu_reset { | ||
void __iomem *base; | ||
struct ccu_reset_map *reset_map; | ||
spinlock_t *lock; | ||
|
||
struct reset_controller_dev rcdev; | ||
}; | ||
|
||
static inline struct ccu_reset *rcdev_to_ccu_reset(struct reset_controller_dev *rcdev) | ||
{ | ||
return container_of(rcdev, struct ccu_reset, rcdev); | ||
} | ||
|
||
extern const struct reset_control_ops ccu_reset_ops; | ||
|
||
#endif /* _CCU_RESET_H_ */ |