-
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 clocks can be switched to a mode called fractional that have two fixed output rate you can choose from. Add a small library to deal with those clocks. 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-4-maxime.ripard@free-electrons.com
- Loading branch information
Maxime Ripard
authored and
Michael Turquette
committed
Jul 9, 2016
1 parent
1d80c14
commit 89a3dfb
Showing
4 changed files
with
175 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,12 @@ | ||
config SUNXI_CCU | ||
bool "Clock support for Allwinner SoCs" | ||
default ARCH_SUNXI | ||
|
||
if SUNXI_CCU | ||
|
||
# Base clock types | ||
|
||
config SUNXI_CCU_FRAC | ||
bool | ||
|
||
endif |
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 |
---|---|---|
@@ -1,3 +1,6 @@ | ||
# Common objects | ||
obj-$(CONFIG_SUNXI_CCU) += ccu_common.o | ||
obj-$(CONFIG_SUNXI_CCU) += ccu_reset.o | ||
|
||
# Base clock types | ||
obj-$(CONFIG_SUNXI_CCU_FRAC) += ccu_frac.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,110 @@ | ||
/* | ||
* 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/clk-provider.h> | ||
#include <linux/spinlock.h> | ||
|
||
#include "ccu_frac.h" | ||
|
||
bool ccu_frac_helper_is_enabled(struct ccu_common *common, | ||
struct _ccu_frac *cf) | ||
{ | ||
if (!(common->features & CCU_FEATURE_FRACTIONAL)) | ||
return false; | ||
|
||
return !(readl(common->base + common->reg) & cf->enable); | ||
} | ||
|
||
void ccu_frac_helper_enable(struct ccu_common *common, | ||
struct _ccu_frac *cf) | ||
{ | ||
unsigned long flags; | ||
u32 reg; | ||
|
||
if (!(common->features & CCU_FEATURE_FRACTIONAL)) | ||
return; | ||
|
||
spin_lock_irqsave(common->lock, flags); | ||
reg = readl(common->base + common->reg); | ||
writel(reg & ~cf->enable, common->base + common->reg); | ||
spin_unlock_irqrestore(common->lock, flags); | ||
} | ||
|
||
void ccu_frac_helper_disable(struct ccu_common *common, | ||
struct _ccu_frac *cf) | ||
{ | ||
unsigned long flags; | ||
u32 reg; | ||
|
||
if (!(common->features & CCU_FEATURE_FRACTIONAL)) | ||
return; | ||
|
||
spin_lock_irqsave(common->lock, flags); | ||
reg = readl(common->base + common->reg); | ||
writel(reg | cf->enable, common->base + common->reg); | ||
spin_unlock_irqrestore(common->lock, flags); | ||
} | ||
|
||
bool ccu_frac_helper_has_rate(struct ccu_common *common, | ||
struct _ccu_frac *cf, | ||
unsigned long rate) | ||
{ | ||
if (!(common->features & CCU_FEATURE_FRACTIONAL)) | ||
return false; | ||
|
||
return (cf->rates[0] == rate) || (cf->rates[1] == rate); | ||
} | ||
|
||
unsigned long ccu_frac_helper_read_rate(struct ccu_common *common, | ||
struct _ccu_frac *cf) | ||
{ | ||
u32 reg; | ||
|
||
printk("%s: Read fractional\n", clk_hw_get_name(&common->hw)); | ||
|
||
if (!(common->features & CCU_FEATURE_FRACTIONAL)) | ||
return 0; | ||
|
||
printk("%s: clock is fractional (rates %lu and %lu)\n", | ||
clk_hw_get_name(&common->hw), cf->rates[0], cf->rates[1]); | ||
|
||
reg = readl(common->base + common->reg); | ||
|
||
printk("%s: clock reg is 0x%x (select is 0x%x)\n", | ||
clk_hw_get_name(&common->hw), reg, cf->select); | ||
|
||
return (reg & cf->select) ? cf->rates[1] : cf->rates[0]; | ||
} | ||
|
||
int ccu_frac_helper_set_rate(struct ccu_common *common, | ||
struct _ccu_frac *cf, | ||
unsigned long rate) | ||
{ | ||
unsigned long flags; | ||
u32 reg, sel; | ||
|
||
if (!(common->features & CCU_FEATURE_FRACTIONAL)) | ||
return -EINVAL; | ||
|
||
if (cf->rates[0] == rate) | ||
sel = 0; | ||
else if (cf->rates[1] == rate) | ||
sel = cf->select; | ||
else | ||
return -EINVAL; | ||
|
||
spin_lock_irqsave(common->lock, flags); | ||
reg = readl(common->base + common->reg); | ||
reg &= ~cf->select; | ||
writel(reg | sel, common->base + common->reg); | ||
spin_unlock_irqrestore(common->lock, flags); | ||
|
||
return 0; | ||
} |
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,53 @@ | ||
/* | ||
* 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_FRAC_H_ | ||
#define _CCU_FRAC_H_ | ||
|
||
#include <linux/clk-provider.h> | ||
|
||
#include "ccu_common.h" | ||
|
||
struct _ccu_frac { | ||
u32 enable; | ||
u32 select; | ||
|
||
unsigned long rates[2]; | ||
}; | ||
|
||
#define _SUNXI_CCU_FRAC(_enable, _select, _rate1, _rate2) \ | ||
{ \ | ||
.enable = _enable, \ | ||
.select = _select, \ | ||
.rates = { _rate1, _rate2 }, \ | ||
} | ||
|
||
bool ccu_frac_helper_is_enabled(struct ccu_common *common, | ||
struct _ccu_frac *cf); | ||
void ccu_frac_helper_enable(struct ccu_common *common, | ||
struct _ccu_frac *cf); | ||
void ccu_frac_helper_disable(struct ccu_common *common, | ||
struct _ccu_frac *cf); | ||
|
||
bool ccu_frac_helper_has_rate(struct ccu_common *common, | ||
struct _ccu_frac *cf, | ||
unsigned long rate); | ||
|
||
unsigned long ccu_frac_helper_read_rate(struct ccu_common *common, | ||
struct _ccu_frac *cf); | ||
|
||
int ccu_frac_helper_set_rate(struct ccu_common *common, | ||
struct _ccu_frac *cf, | ||
unsigned long rate); | ||
|
||
#endif /* _CCU_FRAC_H_ */ |