mirror of
https://github.com/BobTheBlinker/android_kernel_motorola_sm6375.git
synced 2026-10-28 02:32:09 -04:00
The clk framework changes for 4.3 are mostly updates to existing drivers
and the addition of new clock drivers. Stephen Boyd has also done a lot of subsystem-wide driver clean-ups (thanks!). There are also fixes to the framework core and changes to better split clock provider drivers from clock consumer drivers. -----BEGIN PGP SIGNATURE----- Version: GnuPG v1 iQIcBAABAgAGBQJV5KelAAoJEKI6nJvDJaTUwaQP/RVb70v6XSgMIePuOq3iaECT bclCAyito3YFwykrPPmQ1DucHvEjlWopeFwKqEE9VjNl07TVIH/OMGeonb9yErIY aN+FMoA9RUGVexMhy004q5sSbOEihAqTgKWaOiYoY8zAfJfeTpYXUoy34FcrW7MB j/cDDJgigtWe9zzcdrW04oT454lXQaSQuGX39tDCR0s0S3soYU2JyjkyBGiO5Yid 1yIMq/nzI8SrCwxwD/nFwQNtg7lqiAN291Nbi4At1vvG5r4RhNveuLGv8uJ50XRB xwy0sdHLIVJrIJ8OUcs1sY8wxu7ghDS8u+vjTNO2RzBf3KZWbuXWX+yVM7JQi4Ty 0iL5hGbvERy5E9QSzzH+Ox2jVt5e/r/dyvRf3oBDPVrFXhKusYhn6JmdUVJkTZ83 GTw2sQdEpcmry4z/50/MaqpZuXVZ09VTOCTqp8ToseJjsz9jXxVhQ4HdAwLc8cmV txWGRXuBxCB+2o8M0oky3IKS69VFFH5u6QQ0KG8+JYOrDDG7GcnJsFeV7mQjlu8g 3evYUILNAUfJGBpkOeLs654KUBHwUyXc87cUIKwjGaPruWb2048+kdCVrL3IFwPb sS/7Qn3DQ90pHFUTssDnWLz3X0IWT3H0iV4zZyAqqdARugEo+mpykmXmMWcWc3VR MrD1l3GVxLegEf242Zpo =QAiQ -----END PGP SIGNATURE----- Merge tag 'clk-for-linus-4.3' of git://git.kernel.org/pub/scm/linux/kernel/git/clk/linux Pull clk updates from Michael Turquette: "The clk framework changes for 4.3 are mostly updates to existing drivers and the addition of new clock drivers. Stephen Boyd has also done a lot of subsystem-wide driver clean-ups (thanks!). There are also fixes to the framework core and changes to better split clock provider drivers from clock consumer drivers" * tag 'clk-for-linus-4.3' of git://git.kernel.org/pub/scm/linux/kernel/git/clk/linux: (227 commits) clk: s5pv210: add missing call to samsung_clk_of_add_provider() clk: pistachio: correct critical clock list clk: pistachio: Fix PLL rate calculation in integer mode clk: pistachio: Fix override of clk-pll settings from boot loader clk: pistachio: Fix 32bit integer overflows clk: tegra: Fix some static checker problems clk: qcom: Fix MSM8916 prng clock enable bit clk: Add missing header for 'bool' definition to clk-conf.h drivers/clk: appropriate __init annotation for const data clk: rockchip: register pll mux before pll itself clk: add bindings for the Ux500 clocks clk/ARM: move Ux500 PRCC bases to the device tree clk: remove duplicated code with __clk_set_parent_after clk: Convert __clk_get_name(hw->clk) to clk_hw_get_name(hw) clk: Constify clk_hw argument to provider APIs clk: Hi6220: add stub clock driver dt-bindings: clk: Hi6220: Document stub clock driver dt-bindings: arm: Hi6220: add doc for SRAM controller clk: atlas7: fix pll missed divide NR in fraction mode clk: atlas7: fix bit field and its root clk for coresight_tpiu ...
This commit is contained in:
commit
f36fc04e4c
320 changed files with 9096 additions and 4940 deletions
|
|
@ -9,7 +9,7 @@ obj-$(CONFIG_COMMON_CLK) += clk-gate.o
|
|||
obj-$(CONFIG_COMMON_CLK) += clk-mux.o
|
||||
obj-$(CONFIG_COMMON_CLK) += clk-composite.o
|
||||
obj-$(CONFIG_COMMON_CLK) += clk-fractional-divider.o
|
||||
obj-$(CONFIG_COMMON_CLK) += clk-gpio-gate.o
|
||||
obj-$(CONFIG_COMMON_CLK) += clk-gpio.o
|
||||
ifeq ($(CONFIG_OF), y)
|
||||
obj-$(CONFIG_COMMON_CLK) += clk-conf.o
|
||||
endif
|
||||
|
|
|
|||
|
|
@ -614,17 +614,12 @@ void __init of_at91sam9x5_clk_main_setup(struct device_node *np,
|
|||
int num_parents;
|
||||
unsigned int irq;
|
||||
const char *name = np->name;
|
||||
int i;
|
||||
|
||||
num_parents = of_clk_get_parent_count(np);
|
||||
if (num_parents <= 0 || num_parents > 2)
|
||||
return;
|
||||
|
||||
for (i = 0; i < num_parents; ++i) {
|
||||
parent_names[i] = of_clk_get_parent_name(np, i);
|
||||
if (!parent_names[i])
|
||||
return;
|
||||
}
|
||||
of_clk_parent_fill(np, parent_names, num_parents);
|
||||
|
||||
of_property_read_string(np, "clock-output-names", &name);
|
||||
|
||||
|
|
|
|||
|
|
@ -222,7 +222,6 @@ of_at91_clk_master_setup(struct device_node *np, struct at91_pmc *pmc,
|
|||
{
|
||||
struct clk *clk;
|
||||
int num_parents;
|
||||
int i;
|
||||
unsigned int irq;
|
||||
const char *parent_names[MASTER_SOURCE_MAX];
|
||||
const char *name = np->name;
|
||||
|
|
@ -232,11 +231,7 @@ of_at91_clk_master_setup(struct device_node *np, struct at91_pmc *pmc,
|
|||
if (num_parents <= 0 || num_parents > MASTER_SOURCE_MAX)
|
||||
return;
|
||||
|
||||
for (i = 0; i < num_parents; ++i) {
|
||||
parent_names[i] = of_clk_get_parent_name(np, i);
|
||||
if (!parent_names[i])
|
||||
return;
|
||||
}
|
||||
of_clk_parent_fill(np, parent_names, num_parents);
|
||||
|
||||
of_property_read_string(np, "clock-output-names", &name);
|
||||
|
||||
|
|
|
|||
|
|
@ -134,7 +134,7 @@ at91_clk_register_peripheral(struct at91_pmc *pmc, const char *name,
|
|||
|
||||
static void clk_sam9x5_peripheral_autodiv(struct clk_sam9x5_peripheral *periph)
|
||||
{
|
||||
struct clk *parent;
|
||||
struct clk_hw *parent;
|
||||
unsigned long parent_rate;
|
||||
int shift = 0;
|
||||
|
||||
|
|
@ -142,8 +142,8 @@ static void clk_sam9x5_peripheral_autodiv(struct clk_sam9x5_peripheral *periph)
|
|||
return;
|
||||
|
||||
if (periph->range.max) {
|
||||
parent = clk_get_parent_by_index(periph->hw.clk, 0);
|
||||
parent_rate = __clk_get_rate(parent);
|
||||
parent = clk_hw_get_parent_by_index(&periph->hw, 0);
|
||||
parent_rate = clk_hw_get_rate(parent);
|
||||
if (!parent_rate)
|
||||
return;
|
||||
|
||||
|
|
|
|||
|
|
@ -54,46 +54,47 @@ static unsigned long clk_programmable_recalc_rate(struct clk_hw *hw,
|
|||
return parent_rate >> pres;
|
||||
}
|
||||
|
||||
static long clk_programmable_determine_rate(struct clk_hw *hw,
|
||||
unsigned long rate,
|
||||
unsigned long min_rate,
|
||||
unsigned long max_rate,
|
||||
unsigned long *best_parent_rate,
|
||||
struct clk_hw **best_parent_hw)
|
||||
static int clk_programmable_determine_rate(struct clk_hw *hw,
|
||||
struct clk_rate_request *req)
|
||||
{
|
||||
struct clk *parent = NULL;
|
||||
struct clk_hw *parent;
|
||||
long best_rate = -EINVAL;
|
||||
unsigned long parent_rate;
|
||||
unsigned long tmp_rate;
|
||||
int shift;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < __clk_get_num_parents(hw->clk); i++) {
|
||||
parent = clk_get_parent_by_index(hw->clk, i);
|
||||
for (i = 0; i < clk_hw_get_num_parents(hw); i++) {
|
||||
parent = clk_hw_get_parent_by_index(hw, i);
|
||||
if (!parent)
|
||||
continue;
|
||||
|
||||
parent_rate = __clk_get_rate(parent);
|
||||
parent_rate = clk_hw_get_rate(parent);
|
||||
for (shift = 0; shift < PROG_PRES_MASK; shift++) {
|
||||
tmp_rate = parent_rate >> shift;
|
||||
if (tmp_rate <= rate)
|
||||
if (tmp_rate <= req->rate)
|
||||
break;
|
||||
}
|
||||
|
||||
if (tmp_rate > rate)
|
||||
if (tmp_rate > req->rate)
|
||||
continue;
|
||||
|
||||
if (best_rate < 0 || (rate - tmp_rate) < (rate - best_rate)) {
|
||||
if (best_rate < 0 ||
|
||||
(req->rate - tmp_rate) < (req->rate - best_rate)) {
|
||||
best_rate = tmp_rate;
|
||||
*best_parent_rate = parent_rate;
|
||||
*best_parent_hw = __clk_get_hw(parent);
|
||||
req->best_parent_rate = parent_rate;
|
||||
req->best_parent_hw = parent;
|
||||
}
|
||||
|
||||
if (!best_rate)
|
||||
break;
|
||||
}
|
||||
|
||||
return best_rate;
|
||||
if (best_rate < 0)
|
||||
return best_rate;
|
||||
|
||||
req->rate = best_rate;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int clk_programmable_set_parent(struct clk_hw *hw, u8 index)
|
||||
|
|
@ -230,7 +231,6 @@ of_at91_clk_prog_setup(struct device_node *np, struct at91_pmc *pmc,
|
|||
{
|
||||
int num;
|
||||
u32 id;
|
||||
int i;
|
||||
struct clk *clk;
|
||||
int num_parents;
|
||||
const char *parent_names[PROG_SOURCE_MAX];
|
||||
|
|
@ -241,11 +241,7 @@ of_at91_clk_prog_setup(struct device_node *np, struct at91_pmc *pmc,
|
|||
if (num_parents <= 0 || num_parents > PROG_SOURCE_MAX)
|
||||
return;
|
||||
|
||||
for (i = 0; i < num_parents; ++i) {
|
||||
parent_names[i] = of_clk_get_parent_name(np, i);
|
||||
if (!parent_names[i])
|
||||
return;
|
||||
}
|
||||
of_clk_parent_fill(np, parent_names, num_parents);
|
||||
|
||||
num = of_get_child_count(np);
|
||||
if (!num || num > (PROG_ID_MAX + 1))
|
||||
|
|
|
|||
|
|
@ -10,8 +10,10 @@
|
|||
*
|
||||
*/
|
||||
|
||||
#include <linux/clk.h>
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/clkdev.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/clk/at91_pmc.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/of.h>
|
||||
|
|
@ -371,17 +373,12 @@ void __init of_at91sam9x5_clk_slow_setup(struct device_node *np,
|
|||
const char *parent_names[2];
|
||||
int num_parents;
|
||||
const char *name = np->name;
|
||||
int i;
|
||||
|
||||
num_parents = of_clk_get_parent_count(np);
|
||||
if (num_parents <= 0 || num_parents > 2)
|
||||
return;
|
||||
|
||||
for (i = 0; i < num_parents; ++i) {
|
||||
parent_names[i] = of_clk_get_parent_name(np, i);
|
||||
if (!parent_names[i])
|
||||
return;
|
||||
}
|
||||
of_clk_parent_fill(np, parent_names, num_parents);
|
||||
|
||||
of_property_read_string(np, "clock-output-names", &name);
|
||||
|
||||
|
|
@ -449,17 +446,12 @@ void __init of_at91sam9260_clk_slow_setup(struct device_node *np,
|
|||
const char *parent_names[2];
|
||||
int num_parents;
|
||||
const char *name = np->name;
|
||||
int i;
|
||||
|
||||
num_parents = of_clk_get_parent_count(np);
|
||||
if (num_parents != 2)
|
||||
return;
|
||||
|
||||
for (i = 0; i < num_parents; ++i) {
|
||||
parent_names[i] = of_clk_get_parent_name(np, i);
|
||||
if (!parent_names[i])
|
||||
return;
|
||||
}
|
||||
of_clk_parent_fill(np, parent_names, num_parents);
|
||||
|
||||
of_property_read_string(np, "clock-output-names", &name);
|
||||
|
||||
|
|
|
|||
|
|
@ -145,7 +145,6 @@ void __init of_at91sam9x5_clk_smd_setup(struct device_node *np,
|
|||
struct at91_pmc *pmc)
|
||||
{
|
||||
struct clk *clk;
|
||||
int i;
|
||||
int num_parents;
|
||||
const char *parent_names[SMD_SOURCE_MAX];
|
||||
const char *name = np->name;
|
||||
|
|
@ -154,11 +153,7 @@ void __init of_at91sam9x5_clk_smd_setup(struct device_node *np,
|
|||
if (num_parents <= 0 || num_parents > SMD_SOURCE_MAX)
|
||||
return;
|
||||
|
||||
for (i = 0; i < num_parents; i++) {
|
||||
parent_names[i] = of_clk_get_parent_name(np, i);
|
||||
if (!parent_names[i])
|
||||
return;
|
||||
}
|
||||
of_clk_parent_fill(np, parent_names, num_parents);
|
||||
|
||||
of_property_read_string(np, "clock-output-names", &name);
|
||||
|
||||
|
|
|
|||
|
|
@ -56,47 +56,43 @@ static unsigned long at91sam9x5_clk_usb_recalc_rate(struct clk_hw *hw,
|
|||
return DIV_ROUND_CLOSEST(parent_rate, (usbdiv + 1));
|
||||
}
|
||||
|
||||
static long at91sam9x5_clk_usb_determine_rate(struct clk_hw *hw,
|
||||
unsigned long rate,
|
||||
unsigned long min_rate,
|
||||
unsigned long max_rate,
|
||||
unsigned long *best_parent_rate,
|
||||
struct clk_hw **best_parent_hw)
|
||||
static int at91sam9x5_clk_usb_determine_rate(struct clk_hw *hw,
|
||||
struct clk_rate_request *req)
|
||||
{
|
||||
struct clk *parent = NULL;
|
||||
struct clk_hw *parent;
|
||||
long best_rate = -EINVAL;
|
||||
unsigned long tmp_rate;
|
||||
int best_diff = -1;
|
||||
int tmp_diff;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < __clk_get_num_parents(hw->clk); i++) {
|
||||
for (i = 0; i < clk_hw_get_num_parents(hw); i++) {
|
||||
int div;
|
||||
|
||||
parent = clk_get_parent_by_index(hw->clk, i);
|
||||
parent = clk_hw_get_parent_by_index(hw, i);
|
||||
if (!parent)
|
||||
continue;
|
||||
|
||||
for (div = 1; div < SAM9X5_USB_MAX_DIV + 2; div++) {
|
||||
unsigned long tmp_parent_rate;
|
||||
|
||||
tmp_parent_rate = rate * div;
|
||||
tmp_parent_rate = __clk_round_rate(parent,
|
||||
tmp_parent_rate = req->rate * div;
|
||||
tmp_parent_rate = clk_hw_round_rate(parent,
|
||||
tmp_parent_rate);
|
||||
tmp_rate = DIV_ROUND_CLOSEST(tmp_parent_rate, div);
|
||||
if (tmp_rate < rate)
|
||||
tmp_diff = rate - tmp_rate;
|
||||
if (tmp_rate < req->rate)
|
||||
tmp_diff = req->rate - tmp_rate;
|
||||
else
|
||||
tmp_diff = tmp_rate - rate;
|
||||
tmp_diff = tmp_rate - req->rate;
|
||||
|
||||
if (best_diff < 0 || best_diff > tmp_diff) {
|
||||
best_rate = tmp_rate;
|
||||
best_diff = tmp_diff;
|
||||
*best_parent_rate = tmp_parent_rate;
|
||||
*best_parent_hw = __clk_get_hw(parent);
|
||||
req->best_parent_rate = tmp_parent_rate;
|
||||
req->best_parent_hw = parent;
|
||||
}
|
||||
|
||||
if (!best_diff || tmp_rate < rate)
|
||||
if (!best_diff || tmp_rate < req->rate)
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
@ -104,7 +100,11 @@ static long at91sam9x5_clk_usb_determine_rate(struct clk_hw *hw,
|
|||
break;
|
||||
}
|
||||
|
||||
return best_rate;
|
||||
if (best_rate < 0)
|
||||
return best_rate;
|
||||
|
||||
req->rate = best_rate;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int at91sam9x5_clk_usb_set_parent(struct clk_hw *hw, u8 index)
|
||||
|
|
@ -273,7 +273,7 @@ static long at91rm9200_clk_usb_round_rate(struct clk_hw *hw, unsigned long rate,
|
|||
unsigned long *parent_rate)
|
||||
{
|
||||
struct at91rm9200_clk_usb *usb = to_at91rm9200_clk_usb(hw);
|
||||
struct clk *parent = __clk_get_parent(hw->clk);
|
||||
struct clk_hw *parent = clk_hw_get_parent(hw);
|
||||
unsigned long bestrate = 0;
|
||||
int bestdiff = -1;
|
||||
unsigned long tmprate;
|
||||
|
|
@ -287,7 +287,7 @@ static long at91rm9200_clk_usb_round_rate(struct clk_hw *hw, unsigned long rate,
|
|||
continue;
|
||||
|
||||
tmp_parent_rate = rate * usb->divisors[i];
|
||||
tmp_parent_rate = __clk_round_rate(parent, tmp_parent_rate);
|
||||
tmp_parent_rate = clk_hw_round_rate(parent, tmp_parent_rate);
|
||||
tmprate = DIV_ROUND_CLOSEST(tmp_parent_rate, usb->divisors[i]);
|
||||
if (tmprate < rate)
|
||||
tmpdiff = rate - tmprate;
|
||||
|
|
@ -373,7 +373,6 @@ void __init of_at91sam9x5_clk_usb_setup(struct device_node *np,
|
|||
struct at91_pmc *pmc)
|
||||
{
|
||||
struct clk *clk;
|
||||
int i;
|
||||
int num_parents;
|
||||
const char *parent_names[USB_SOURCE_MAX];
|
||||
const char *name = np->name;
|
||||
|
|
@ -382,11 +381,7 @@ void __init of_at91sam9x5_clk_usb_setup(struct device_node *np,
|
|||
if (num_parents <= 0 || num_parents > USB_SOURCE_MAX)
|
||||
return;
|
||||
|
||||
for (i = 0; i < num_parents; i++) {
|
||||
parent_names[i] = of_clk_get_parent_name(np, i);
|
||||
if (!parent_names[i])
|
||||
return;
|
||||
}
|
||||
of_clk_parent_fill(np, parent_names, num_parents);
|
||||
|
||||
of_property_read_string(np, "clock-output-names", &name);
|
||||
|
||||
|
|
|
|||
|
|
@ -125,7 +125,6 @@ static int pmc_irq_map(struct irq_domain *h, unsigned int virq,
|
|||
|
||||
irq_set_chip_and_handler(virq, &pmc_irq,
|
||||
handle_level_irq);
|
||||
set_irq_flags(virq, IRQF_VALID);
|
||||
irq_set_chip_data(virq, pmc);
|
||||
|
||||
return 0;
|
||||
|
|
|
|||
|
|
@ -59,71 +59,63 @@ static inline void pmc_write(struct at91_pmc *pmc, int offset, u32 value)
|
|||
int of_at91_get_clk_range(struct device_node *np, const char *propname,
|
||||
struct clk_range *range);
|
||||
|
||||
extern void __init of_at91sam9260_clk_slow_setup(struct device_node *np,
|
||||
struct at91_pmc *pmc);
|
||||
void of_at91sam9260_clk_slow_setup(struct device_node *np,
|
||||
struct at91_pmc *pmc);
|
||||
|
||||
extern void __init of_at91rm9200_clk_main_osc_setup(struct device_node *np,
|
||||
struct at91_pmc *pmc);
|
||||
extern void __init of_at91sam9x5_clk_main_rc_osc_setup(struct device_node *np,
|
||||
struct at91_pmc *pmc);
|
||||
extern void __init of_at91rm9200_clk_main_setup(struct device_node *np,
|
||||
struct at91_pmc *pmc);
|
||||
extern void __init of_at91sam9x5_clk_main_setup(struct device_node *np,
|
||||
struct at91_pmc *pmc);
|
||||
void of_at91rm9200_clk_main_osc_setup(struct device_node *np,
|
||||
struct at91_pmc *pmc);
|
||||
void of_at91sam9x5_clk_main_rc_osc_setup(struct device_node *np,
|
||||
struct at91_pmc *pmc);
|
||||
void of_at91rm9200_clk_main_setup(struct device_node *np,
|
||||
struct at91_pmc *pmc);
|
||||
void of_at91sam9x5_clk_main_setup(struct device_node *np,
|
||||
struct at91_pmc *pmc);
|
||||
|
||||
extern void __init of_at91rm9200_clk_pll_setup(struct device_node *np,
|
||||
struct at91_pmc *pmc);
|
||||
extern void __init of_at91sam9g45_clk_pll_setup(struct device_node *np,
|
||||
struct at91_pmc *pmc);
|
||||
extern void __init of_at91sam9g20_clk_pllb_setup(struct device_node *np,
|
||||
struct at91_pmc *pmc);
|
||||
extern void __init of_sama5d3_clk_pll_setup(struct device_node *np,
|
||||
struct at91_pmc *pmc);
|
||||
extern void __init of_at91sam9x5_clk_plldiv_setup(struct device_node *np,
|
||||
struct at91_pmc *pmc);
|
||||
void of_at91rm9200_clk_pll_setup(struct device_node *np,
|
||||
struct at91_pmc *pmc);
|
||||
void of_at91sam9g45_clk_pll_setup(struct device_node *np,
|
||||
struct at91_pmc *pmc);
|
||||
void of_at91sam9g20_clk_pllb_setup(struct device_node *np,
|
||||
struct at91_pmc *pmc);
|
||||
void of_sama5d3_clk_pll_setup(struct device_node *np,
|
||||
struct at91_pmc *pmc);
|
||||
void of_at91sam9x5_clk_plldiv_setup(struct device_node *np,
|
||||
struct at91_pmc *pmc);
|
||||
|
||||
extern void __init of_at91rm9200_clk_master_setup(struct device_node *np,
|
||||
struct at91_pmc *pmc);
|
||||
extern void __init of_at91sam9x5_clk_master_setup(struct device_node *np,
|
||||
struct at91_pmc *pmc);
|
||||
void of_at91rm9200_clk_master_setup(struct device_node *np,
|
||||
struct at91_pmc *pmc);
|
||||
void of_at91sam9x5_clk_master_setup(struct device_node *np,
|
||||
struct at91_pmc *pmc);
|
||||
|
||||
extern void __init of_at91rm9200_clk_sys_setup(struct device_node *np,
|
||||
struct at91_pmc *pmc);
|
||||
void of_at91rm9200_clk_sys_setup(struct device_node *np,
|
||||
struct at91_pmc *pmc);
|
||||
|
||||
extern void __init of_at91rm9200_clk_periph_setup(struct device_node *np,
|
||||
struct at91_pmc *pmc);
|
||||
extern void __init of_at91sam9x5_clk_periph_setup(struct device_node *np,
|
||||
struct at91_pmc *pmc);
|
||||
void of_at91rm9200_clk_periph_setup(struct device_node *np,
|
||||
struct at91_pmc *pmc);
|
||||
void of_at91sam9x5_clk_periph_setup(struct device_node *np,
|
||||
struct at91_pmc *pmc);
|
||||
|
||||
extern void __init of_at91rm9200_clk_prog_setup(struct device_node *np,
|
||||
struct at91_pmc *pmc);
|
||||
extern void __init of_at91sam9g45_clk_prog_setup(struct device_node *np,
|
||||
struct at91_pmc *pmc);
|
||||
extern void __init of_at91sam9x5_clk_prog_setup(struct device_node *np,
|
||||
struct at91_pmc *pmc);
|
||||
void of_at91rm9200_clk_prog_setup(struct device_node *np,
|
||||
struct at91_pmc *pmc);
|
||||
void of_at91sam9g45_clk_prog_setup(struct device_node *np,
|
||||
struct at91_pmc *pmc);
|
||||
void of_at91sam9x5_clk_prog_setup(struct device_node *np,
|
||||
struct at91_pmc *pmc);
|
||||
|
||||
#if defined(CONFIG_HAVE_AT91_UTMI)
|
||||
extern void __init of_at91sam9x5_clk_utmi_setup(struct device_node *np,
|
||||
struct at91_pmc *pmc);
|
||||
#endif
|
||||
void of_at91sam9x5_clk_utmi_setup(struct device_node *np,
|
||||
struct at91_pmc *pmc);
|
||||
|
||||
#if defined(CONFIG_HAVE_AT91_USB_CLK)
|
||||
extern void __init of_at91rm9200_clk_usb_setup(struct device_node *np,
|
||||
struct at91_pmc *pmc);
|
||||
extern void __init of_at91sam9x5_clk_usb_setup(struct device_node *np,
|
||||
struct at91_pmc *pmc);
|
||||
extern void __init of_at91sam9n12_clk_usb_setup(struct device_node *np,
|
||||
struct at91_pmc *pmc);
|
||||
#endif
|
||||
void of_at91rm9200_clk_usb_setup(struct device_node *np,
|
||||
struct at91_pmc *pmc);
|
||||
void of_at91sam9x5_clk_usb_setup(struct device_node *np,
|
||||
struct at91_pmc *pmc);
|
||||
void of_at91sam9n12_clk_usb_setup(struct device_node *np,
|
||||
struct at91_pmc *pmc);
|
||||
|
||||
#if defined(CONFIG_HAVE_AT91_SMD)
|
||||
extern void __init of_at91sam9x5_clk_smd_setup(struct device_node *np,
|
||||
struct at91_pmc *pmc);
|
||||
#endif
|
||||
void of_at91sam9x5_clk_smd_setup(struct device_node *np,
|
||||
struct at91_pmc *pmc);
|
||||
|
||||
#if defined(CONFIG_HAVE_AT91_H32MX)
|
||||
extern void __init of_sama5d4_clk_h32mx_setup(struct device_node *np,
|
||||
struct at91_pmc *pmc);
|
||||
#endif
|
||||
void of_sama5d4_clk_h32mx_setup(struct device_node *np,
|
||||
struct at91_pmc *pmc);
|
||||
|
||||
#endif /* __PMC_H_ */
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@
|
|||
|
||||
#include <linux/delay.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/clk.h>
|
||||
|
||||
/*
|
||||
* "Policies" affect the frequencies of bus clocks provided by a
|
||||
|
|
@ -1010,25 +1011,23 @@ static long kona_peri_clk_round_rate(struct clk_hw *hw, unsigned long rate,
|
|||
struct bcm_clk_div *div = &bcm_clk->u.peri->div;
|
||||
|
||||
if (!divider_exists(div))
|
||||
return __clk_get_rate(hw->clk);
|
||||
return clk_hw_get_rate(hw);
|
||||
|
||||
/* Quietly avoid a zero rate */
|
||||
return round_rate(bcm_clk->ccu, div, &bcm_clk->u.peri->pre_div,
|
||||
rate ? rate : 1, *parent_rate, NULL);
|
||||
}
|
||||
|
||||
static long kona_peri_clk_determine_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long min_rate,
|
||||
unsigned long max_rate,
|
||||
unsigned long *best_parent_rate, struct clk_hw **best_parent)
|
||||
static int kona_peri_clk_determine_rate(struct clk_hw *hw,
|
||||
struct clk_rate_request *req)
|
||||
{
|
||||
struct kona_clk *bcm_clk = to_kona_clk(hw);
|
||||
struct clk *clk = hw->clk;
|
||||
struct clk *current_parent;
|
||||
struct clk_hw *current_parent;
|
||||
unsigned long parent_rate;
|
||||
unsigned long best_delta;
|
||||
unsigned long best_rate;
|
||||
u32 parent_count;
|
||||
long rate;
|
||||
u32 which;
|
||||
|
||||
/*
|
||||
|
|
@ -1037,18 +1036,25 @@ static long kona_peri_clk_determine_rate(struct clk_hw *hw, unsigned long rate,
|
|||
*/
|
||||
WARN_ON_ONCE(bcm_clk->init_data.flags & CLK_SET_RATE_NO_REPARENT);
|
||||
parent_count = (u32)bcm_clk->init_data.num_parents;
|
||||
if (parent_count < 2)
|
||||
return kona_peri_clk_round_rate(hw, rate, best_parent_rate);
|
||||
if (parent_count < 2) {
|
||||
rate = kona_peri_clk_round_rate(hw, req->rate,
|
||||
&req->best_parent_rate);
|
||||
if (rate < 0)
|
||||
return rate;
|
||||
|
||||
req->rate = rate;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Unless we can do better, stick with current parent */
|
||||
current_parent = clk_get_parent(clk);
|
||||
parent_rate = __clk_get_rate(current_parent);
|
||||
best_rate = kona_peri_clk_round_rate(hw, rate, &parent_rate);
|
||||
best_delta = abs(best_rate - rate);
|
||||
current_parent = clk_hw_get_parent(hw);
|
||||
parent_rate = clk_hw_get_rate(current_parent);
|
||||
best_rate = kona_peri_clk_round_rate(hw, req->rate, &parent_rate);
|
||||
best_delta = abs(best_rate - req->rate);
|
||||
|
||||
/* Check whether any other parent clock can produce a better result */
|
||||
for (which = 0; which < parent_count; which++) {
|
||||
struct clk *parent = clk_get_parent_by_index(clk, which);
|
||||
struct clk_hw *parent = clk_hw_get_parent_by_index(hw, which);
|
||||
unsigned long delta;
|
||||
unsigned long other_rate;
|
||||
|
||||
|
|
@ -1057,18 +1063,20 @@ static long kona_peri_clk_determine_rate(struct clk_hw *hw, unsigned long rate,
|
|||
continue;
|
||||
|
||||
/* We don't support CLK_SET_RATE_PARENT */
|
||||
parent_rate = __clk_get_rate(parent);
|
||||
other_rate = kona_peri_clk_round_rate(hw, rate, &parent_rate);
|
||||
delta = abs(other_rate - rate);
|
||||
parent_rate = clk_hw_get_rate(parent);
|
||||
other_rate = kona_peri_clk_round_rate(hw, req->rate,
|
||||
&parent_rate);
|
||||
delta = abs(other_rate - req->rate);
|
||||
if (delta < best_delta) {
|
||||
best_delta = delta;
|
||||
best_rate = other_rate;
|
||||
*best_parent = __clk_get_hw(parent);
|
||||
*best_parent_rate = parent_rate;
|
||||
req->best_parent_hw = parent;
|
||||
req->best_parent_rate = parent_rate;
|
||||
}
|
||||
}
|
||||
|
||||
return best_rate;
|
||||
req->rate = best_rate;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int kona_peri_clk_set_parent(struct clk_hw *hw, u8 index)
|
||||
|
|
@ -1130,7 +1138,7 @@ static int kona_peri_clk_set_rate(struct clk_hw *hw, unsigned long rate,
|
|||
if (parent_rate > (unsigned long)LONG_MAX)
|
||||
return -EINVAL;
|
||||
|
||||
if (rate == __clk_get_rate(hw->clk))
|
||||
if (rate == clk_hw_get_rate(hw))
|
||||
return 0;
|
||||
|
||||
if (!divider_exists(div))
|
||||
|
|
@ -1249,6 +1257,7 @@ bool __init kona_ccu_init(struct ccu_data *ccu)
|
|||
unsigned long flags;
|
||||
unsigned int which;
|
||||
struct clk **clks = ccu->clk_data.clks;
|
||||
struct kona_clk *kona_clks = ccu->kona_clks;
|
||||
bool success = true;
|
||||
|
||||
flags = ccu_lock(ccu);
|
||||
|
|
@ -1259,7 +1268,7 @@ bool __init kona_ccu_init(struct ccu_data *ccu)
|
|||
|
||||
if (!clks[which])
|
||||
continue;
|
||||
bcm_clk = to_kona_clk(__clk_get_hw(clks[which]));
|
||||
bcm_clk = &kona_clks[which];
|
||||
success &= __kona_clk_init(bcm_clk);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -61,7 +61,7 @@ berlin2_pll_recalc_rate(struct clk_hw *hw, unsigned long parent_rate)
|
|||
fbdiv = (val >> map->fbdiv_shift) & FBDIV_MASK;
|
||||
rfdiv = (val >> map->rfdiv_shift) & RFDIV_MASK;
|
||||
if (rfdiv == 0) {
|
||||
pr_warn("%s has zero rfdiv\n", __clk_get_name(hw->clk));
|
||||
pr_warn("%s has zero rfdiv\n", clk_hw_get_name(hw));
|
||||
rfdiv = 1;
|
||||
}
|
||||
|
||||
|
|
@ -70,7 +70,7 @@ berlin2_pll_recalc_rate(struct clk_hw *hw, unsigned long parent_rate)
|
|||
vcodiv = map->vcodiv[vcodivsel];
|
||||
if (vcodiv == 0) {
|
||||
pr_warn("%s has zero vcodiv (index %d)\n",
|
||||
__clk_get_name(hw->clk), vcodivsel);
|
||||
clk_hw_get_name(hw), vcodivsel);
|
||||
vcodiv = 1;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -10,7 +10,6 @@
|
|||
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/of.h>
|
||||
|
|
|
|||
|
|
@ -32,11 +32,6 @@ void __init bcm2835_init_clocks(void)
|
|||
struct clk *clk;
|
||||
int ret;
|
||||
|
||||
clk = clk_register_fixed_rate(NULL, "sys_pclk", NULL, CLK_IS_ROOT,
|
||||
250000000);
|
||||
if (IS_ERR(clk))
|
||||
pr_err("sys_pclk not registered\n");
|
||||
|
||||
clk = clk_register_fixed_rate(NULL, "apb_pclk", NULL, CLK_IS_ROOT,
|
||||
126000000);
|
||||
if (IS_ERR(clk))
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@
|
|||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#include <linux/clk.h>
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/i2c.h>
|
||||
|
|
@ -309,7 +310,7 @@ static long cdce706_divider_round_rate(struct clk_hw *hw, unsigned long rate,
|
|||
if (!mul)
|
||||
div = CDCE706_DIVIDER_DIVIDER_MAX;
|
||||
|
||||
if (__clk_get_flags(hw->clk) & CLK_SET_RATE_PARENT) {
|
||||
if (clk_hw_get_flags(hw) & CLK_SET_RATE_PARENT) {
|
||||
unsigned long best_diff = rate;
|
||||
unsigned long best_div = 0;
|
||||
struct clk *gp_clk = cdce->clkin_clk[cdce->clkin[0].parent];
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@
|
|||
* Copyright (C) 2014, Topic Embedded Products
|
||||
* Licenced under GPL
|
||||
*/
|
||||
#include <linux/clk.h>
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/module.h>
|
||||
|
|
|
|||
|
|
@ -9,7 +9,6 @@
|
|||
* (at your option) any later version.
|
||||
*/
|
||||
|
||||
#include <linux/clk.h>
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/clkdev.h>
|
||||
#include <linux/io.h>
|
||||
|
|
|
|||
|
|
@ -55,78 +55,77 @@ static unsigned long clk_composite_recalc_rate(struct clk_hw *hw,
|
|||
return rate_ops->recalc_rate(rate_hw, parent_rate);
|
||||
}
|
||||
|
||||
static long clk_composite_determine_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long min_rate,
|
||||
unsigned long max_rate,
|
||||
unsigned long *best_parent_rate,
|
||||
struct clk_hw **best_parent_p)
|
||||
static int clk_composite_determine_rate(struct clk_hw *hw,
|
||||
struct clk_rate_request *req)
|
||||
{
|
||||
struct clk_composite *composite = to_clk_composite(hw);
|
||||
const struct clk_ops *rate_ops = composite->rate_ops;
|
||||
const struct clk_ops *mux_ops = composite->mux_ops;
|
||||
struct clk_hw *rate_hw = composite->rate_hw;
|
||||
struct clk_hw *mux_hw = composite->mux_hw;
|
||||
struct clk *parent;
|
||||
struct clk_hw *parent;
|
||||
unsigned long parent_rate;
|
||||
long tmp_rate, best_rate = 0;
|
||||
unsigned long rate_diff;
|
||||
unsigned long best_rate_diff = ULONG_MAX;
|
||||
long rate;
|
||||
int i;
|
||||
|
||||
if (rate_hw && rate_ops && rate_ops->determine_rate) {
|
||||
__clk_hw_set_clk(rate_hw, hw);
|
||||
return rate_ops->determine_rate(rate_hw, rate, min_rate,
|
||||
max_rate,
|
||||
best_parent_rate,
|
||||
best_parent_p);
|
||||
return rate_ops->determine_rate(rate_hw, req);
|
||||
} else if (rate_hw && rate_ops && rate_ops->round_rate &&
|
||||
mux_hw && mux_ops && mux_ops->set_parent) {
|
||||
*best_parent_p = NULL;
|
||||
req->best_parent_hw = NULL;
|
||||
|
||||
if (__clk_get_flags(hw->clk) & CLK_SET_RATE_NO_REPARENT) {
|
||||
parent = clk_get_parent(mux_hw->clk);
|
||||
*best_parent_p = __clk_get_hw(parent);
|
||||
*best_parent_rate = __clk_get_rate(parent);
|
||||
if (clk_hw_get_flags(hw) & CLK_SET_RATE_NO_REPARENT) {
|
||||
parent = clk_hw_get_parent(mux_hw);
|
||||
req->best_parent_hw = parent;
|
||||
req->best_parent_rate = clk_hw_get_rate(parent);
|
||||
|
||||
return rate_ops->round_rate(rate_hw, rate,
|
||||
best_parent_rate);
|
||||
rate = rate_ops->round_rate(rate_hw, req->rate,
|
||||
&req->best_parent_rate);
|
||||
if (rate < 0)
|
||||
return rate;
|
||||
|
||||
req->rate = rate;
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (i = 0; i < __clk_get_num_parents(mux_hw->clk); i++) {
|
||||
parent = clk_get_parent_by_index(mux_hw->clk, i);
|
||||
for (i = 0; i < clk_hw_get_num_parents(mux_hw); i++) {
|
||||
parent = clk_hw_get_parent_by_index(mux_hw, i);
|
||||
if (!parent)
|
||||
continue;
|
||||
|
||||
parent_rate = __clk_get_rate(parent);
|
||||
parent_rate = clk_hw_get_rate(parent);
|
||||
|
||||
tmp_rate = rate_ops->round_rate(rate_hw, rate,
|
||||
tmp_rate = rate_ops->round_rate(rate_hw, req->rate,
|
||||
&parent_rate);
|
||||
if (tmp_rate < 0)
|
||||
continue;
|
||||
|
||||
rate_diff = abs(rate - tmp_rate);
|
||||
rate_diff = abs(req->rate - tmp_rate);
|
||||
|
||||
if (!rate_diff || !*best_parent_p
|
||||
if (!rate_diff || !req->best_parent_hw
|
||||
|| best_rate_diff > rate_diff) {
|
||||
*best_parent_p = __clk_get_hw(parent);
|
||||
*best_parent_rate = parent_rate;
|
||||
req->best_parent_hw = parent;
|
||||
req->best_parent_rate = parent_rate;
|
||||
best_rate_diff = rate_diff;
|
||||
best_rate = tmp_rate;
|
||||
}
|
||||
|
||||
if (!rate_diff)
|
||||
return rate;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return best_rate;
|
||||
req->rate = best_rate;
|
||||
return 0;
|
||||
} else if (mux_hw && mux_ops && mux_ops->determine_rate) {
|
||||
__clk_hw_set_clk(mux_hw, hw);
|
||||
return mux_ops->determine_rate(mux_hw, rate, min_rate,
|
||||
max_rate, best_parent_rate,
|
||||
best_parent_p);
|
||||
return mux_ops->determine_rate(mux_hw, req);
|
||||
} else {
|
||||
pr_err("clk: clk_composite_determine_rate function called, but no mux or rate callback set!\n");
|
||||
return 0;
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -78,12 +78,14 @@ static unsigned int _get_table_div(const struct clk_div_table *table,
|
|||
}
|
||||
|
||||
static unsigned int _get_div(const struct clk_div_table *table,
|
||||
unsigned int val, unsigned long flags)
|
||||
unsigned int val, unsigned long flags, u8 width)
|
||||
{
|
||||
if (flags & CLK_DIVIDER_ONE_BASED)
|
||||
return val;
|
||||
if (flags & CLK_DIVIDER_POWER_OF_TWO)
|
||||
return 1 << val;
|
||||
if (flags & CLK_DIVIDER_MAX_AT_ZERO)
|
||||
return val ? val : div_mask(width) + 1;
|
||||
if (table)
|
||||
return _get_table_div(table, val);
|
||||
return val + 1;
|
||||
|
|
@ -101,12 +103,14 @@ static unsigned int _get_table_val(const struct clk_div_table *table,
|
|||
}
|
||||
|
||||
static unsigned int _get_val(const struct clk_div_table *table,
|
||||
unsigned int div, unsigned long flags)
|
||||
unsigned int div, unsigned long flags, u8 width)
|
||||
{
|
||||
if (flags & CLK_DIVIDER_ONE_BASED)
|
||||
return div;
|
||||
if (flags & CLK_DIVIDER_POWER_OF_TWO)
|
||||
return __ffs(div);
|
||||
if (flags & CLK_DIVIDER_MAX_AT_ZERO)
|
||||
return (div == div_mask(width) + 1) ? 0 : div;
|
||||
if (table)
|
||||
return _get_table_val(table, div);
|
||||
return div - 1;
|
||||
|
|
@ -117,13 +121,14 @@ unsigned long divider_recalc_rate(struct clk_hw *hw, unsigned long parent_rate,
|
|||
const struct clk_div_table *table,
|
||||
unsigned long flags)
|
||||
{
|
||||
struct clk_divider *divider = to_clk_divider(hw);
|
||||
unsigned int div;
|
||||
|
||||
div = _get_div(table, val, flags);
|
||||
div = _get_div(table, val, flags, divider->width);
|
||||
if (!div) {
|
||||
WARN(!(flags & CLK_DIVIDER_ALLOW_ZERO),
|
||||
"%s: Zero divisor and CLK_DIVIDER_ALLOW_ZERO not set\n",
|
||||
__clk_get_name(hw->clk));
|
||||
clk_hw_get_name(hw));
|
||||
return parent_rate;
|
||||
}
|
||||
|
||||
|
|
@ -285,7 +290,7 @@ static int clk_divider_bestdiv(struct clk_hw *hw, unsigned long rate,
|
|||
|
||||
maxdiv = _get_maxdiv(table, width, flags);
|
||||
|
||||
if (!(__clk_get_flags(hw->clk) & CLK_SET_RATE_PARENT)) {
|
||||
if (!(clk_hw_get_flags(hw) & CLK_SET_RATE_PARENT)) {
|
||||
parent_rate = *best_parent_rate;
|
||||
bestdiv = _div_round(table, parent_rate, rate, flags);
|
||||
bestdiv = bestdiv == 0 ? 1 : bestdiv;
|
||||
|
|
@ -311,7 +316,7 @@ static int clk_divider_bestdiv(struct clk_hw *hw, unsigned long rate,
|
|||
*best_parent_rate = parent_rate_saved;
|
||||
return i;
|
||||
}
|
||||
parent_rate = __clk_round_rate(__clk_get_parent(hw->clk),
|
||||
parent_rate = clk_hw_round_rate(clk_hw_get_parent(hw),
|
||||
rate * i);
|
||||
now = DIV_ROUND_UP(parent_rate, i);
|
||||
if (_is_best_div(rate, now, best, flags)) {
|
||||
|
|
@ -323,7 +328,7 @@ static int clk_divider_bestdiv(struct clk_hw *hw, unsigned long rate,
|
|||
|
||||
if (!bestdiv) {
|
||||
bestdiv = _get_maxdiv(table, width, flags);
|
||||
*best_parent_rate = __clk_round_rate(__clk_get_parent(hw->clk), 1);
|
||||
*best_parent_rate = clk_hw_round_rate(clk_hw_get_parent(hw), 1);
|
||||
}
|
||||
|
||||
return bestdiv;
|
||||
|
|
@ -351,7 +356,8 @@ static long clk_divider_round_rate(struct clk_hw *hw, unsigned long rate,
|
|||
if (divider->flags & CLK_DIVIDER_READ_ONLY) {
|
||||
bestdiv = readl(divider->reg) >> divider->shift;
|
||||
bestdiv &= div_mask(divider->width);
|
||||
bestdiv = _get_div(divider->table, bestdiv, divider->flags);
|
||||
bestdiv = _get_div(divider->table, bestdiv, divider->flags,
|
||||
divider->width);
|
||||
return DIV_ROUND_UP(*prate, bestdiv);
|
||||
}
|
||||
|
||||
|
|
@ -370,7 +376,7 @@ int divider_get_val(unsigned long rate, unsigned long parent_rate,
|
|||
if (!_is_valid_div(table, div, flags))
|
||||
return -EINVAL;
|
||||
|
||||
value = _get_val(table, div, flags);
|
||||
value = _get_val(table, div, flags, width);
|
||||
|
||||
return min_t(unsigned int, value, div_mask(width));
|
||||
}
|
||||
|
|
@ -389,6 +395,8 @@ static int clk_divider_set_rate(struct clk_hw *hw, unsigned long rate,
|
|||
|
||||
if (divider->lock)
|
||||
spin_lock_irqsave(divider->lock, flags);
|
||||
else
|
||||
__acquire(divider->lock);
|
||||
|
||||
if (divider->flags & CLK_DIVIDER_HIWORD_MASK) {
|
||||
val = div_mask(divider->width) << (divider->shift + 16);
|
||||
|
|
@ -401,6 +409,8 @@ static int clk_divider_set_rate(struct clk_hw *hw, unsigned long rate,
|
|||
|
||||
if (divider->lock)
|
||||
spin_unlock_irqrestore(divider->lock, flags);
|
||||
else
|
||||
__release(divider->lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,7 +6,6 @@
|
|||
* the terms of the GNU General Public License version 2 as published by the
|
||||
* Free Software Foundation.
|
||||
*/
|
||||
#include <linux/clk.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/of.h>
|
||||
|
|
|
|||
|
|
@ -41,12 +41,11 @@ static long clk_factor_round_rate(struct clk_hw *hw, unsigned long rate,
|
|||
{
|
||||
struct clk_fixed_factor *fix = to_clk_fixed_factor(hw);
|
||||
|
||||
if (__clk_get_flags(hw->clk) & CLK_SET_RATE_PARENT) {
|
||||
if (clk_hw_get_flags(hw) & CLK_SET_RATE_PARENT) {
|
||||
unsigned long best_parent;
|
||||
|
||||
best_parent = (rate / fix->mult) * fix->div;
|
||||
*prate = __clk_round_rate(__clk_get_parent(hw->clk),
|
||||
best_parent);
|
||||
*prate = clk_hw_round_rate(clk_hw_get_parent(hw), best_parent);
|
||||
}
|
||||
|
||||
return (*prate / fix->div) * fix->mult;
|
||||
|
|
|
|||
|
|
@ -27,11 +27,15 @@ static unsigned long clk_fd_recalc_rate(struct clk_hw *hw,
|
|||
|
||||
if (fd->lock)
|
||||
spin_lock_irqsave(fd->lock, flags);
|
||||
else
|
||||
__acquire(fd->lock);
|
||||
|
||||
val = clk_readl(fd->reg);
|
||||
|
||||
if (fd->lock)
|
||||
spin_unlock_irqrestore(fd->lock, flags);
|
||||
else
|
||||
__release(fd->lock);
|
||||
|
||||
m = (val & fd->mmask) >> fd->mshift;
|
||||
n = (val & fd->nmask) >> fd->nshift;
|
||||
|
|
@ -80,6 +84,8 @@ static int clk_fd_set_rate(struct clk_hw *hw, unsigned long rate,
|
|||
|
||||
if (fd->lock)
|
||||
spin_lock_irqsave(fd->lock, flags);
|
||||
else
|
||||
__acquire(fd->lock);
|
||||
|
||||
val = clk_readl(fd->reg);
|
||||
val &= ~(fd->mmask | fd->nmask);
|
||||
|
|
@ -88,6 +94,8 @@ static int clk_fd_set_rate(struct clk_hw *hw, unsigned long rate,
|
|||
|
||||
if (fd->lock)
|
||||
spin_unlock_irqrestore(fd->lock, flags);
|
||||
else
|
||||
__release(fd->lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -52,6 +52,8 @@ static void clk_gate_endisable(struct clk_hw *hw, int enable)
|
|||
|
||||
if (gate->lock)
|
||||
spin_lock_irqsave(gate->lock, flags);
|
||||
else
|
||||
__acquire(gate->lock);
|
||||
|
||||
if (gate->flags & CLK_GATE_HIWORD_MASK) {
|
||||
reg = BIT(gate->bit_idx + 16);
|
||||
|
|
@ -70,6 +72,8 @@ static void clk_gate_endisable(struct clk_hw *hw, int enable)
|
|||
|
||||
if (gate->lock)
|
||||
spin_unlock_irqrestore(gate->lock, flags);
|
||||
else
|
||||
__release(gate->lock);
|
||||
}
|
||||
|
||||
static int clk_gate_enable(struct clk_hw *hw)
|
||||
|
|
|
|||
|
|
@ -1,207 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2013 - 2014 Texas Instruments Incorporated - http://www.ti.com
|
||||
* Author: Jyri Sarha <jsarha@ti.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* Gpio gated clock implementation
|
||||
*/
|
||||
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/gpio/consumer.h>
|
||||
#include <linux/of_gpio.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/device.h>
|
||||
|
||||
/**
|
||||
* DOC: basic gpio gated clock which can be enabled and disabled
|
||||
* with gpio output
|
||||
* Traits of this clock:
|
||||
* prepare - clk_(un)prepare only ensures parent is (un)prepared
|
||||
* enable - clk_enable and clk_disable are functional & control gpio
|
||||
* rate - inherits rate from parent. No clk_set_rate support
|
||||
* parent - fixed parent. No clk_set_parent support
|
||||
*/
|
||||
|
||||
#define to_clk_gpio(_hw) container_of(_hw, struct clk_gpio, hw)
|
||||
|
||||
static int clk_gpio_gate_enable(struct clk_hw *hw)
|
||||
{
|
||||
struct clk_gpio *clk = to_clk_gpio(hw);
|
||||
|
||||
gpiod_set_value(clk->gpiod, 1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void clk_gpio_gate_disable(struct clk_hw *hw)
|
||||
{
|
||||
struct clk_gpio *clk = to_clk_gpio(hw);
|
||||
|
||||
gpiod_set_value(clk->gpiod, 0);
|
||||
}
|
||||
|
||||
static int clk_gpio_gate_is_enabled(struct clk_hw *hw)
|
||||
{
|
||||
struct clk_gpio *clk = to_clk_gpio(hw);
|
||||
|
||||
return gpiod_get_value(clk->gpiod);
|
||||
}
|
||||
|
||||
const struct clk_ops clk_gpio_gate_ops = {
|
||||
.enable = clk_gpio_gate_enable,
|
||||
.disable = clk_gpio_gate_disable,
|
||||
.is_enabled = clk_gpio_gate_is_enabled,
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(clk_gpio_gate_ops);
|
||||
|
||||
/**
|
||||
* clk_register_gpio - register a gpip clock with the clock framework
|
||||
* @dev: device that is registering this clock
|
||||
* @name: name of this clock
|
||||
* @parent_name: name of this clock's parent
|
||||
* @gpio: gpio number to gate this clock
|
||||
* @active_low: true if gpio should be set to 0 to enable clock
|
||||
* @flags: clock flags
|
||||
*/
|
||||
struct clk *clk_register_gpio_gate(struct device *dev, const char *name,
|
||||
const char *parent_name, unsigned gpio, bool active_low,
|
||||
unsigned long flags)
|
||||
{
|
||||
struct clk_gpio *clk_gpio = NULL;
|
||||
struct clk *clk = ERR_PTR(-EINVAL);
|
||||
struct clk_init_data init = { NULL };
|
||||
unsigned long gpio_flags;
|
||||
int err;
|
||||
|
||||
if (active_low)
|
||||
gpio_flags = GPIOF_ACTIVE_LOW | GPIOF_OUT_INIT_HIGH;
|
||||
else
|
||||
gpio_flags = GPIOF_OUT_INIT_LOW;
|
||||
|
||||
if (dev)
|
||||
err = devm_gpio_request_one(dev, gpio, gpio_flags, name);
|
||||
else
|
||||
err = gpio_request_one(gpio, gpio_flags, name);
|
||||
|
||||
if (err) {
|
||||
pr_err("%s: %s: Error requesting clock control gpio %u\n",
|
||||
__func__, name, gpio);
|
||||
return ERR_PTR(err);
|
||||
}
|
||||
|
||||
if (dev)
|
||||
clk_gpio = devm_kzalloc(dev, sizeof(struct clk_gpio),
|
||||
GFP_KERNEL);
|
||||
else
|
||||
clk_gpio = kzalloc(sizeof(struct clk_gpio), GFP_KERNEL);
|
||||
|
||||
if (!clk_gpio) {
|
||||
clk = ERR_PTR(-ENOMEM);
|
||||
goto clk_register_gpio_gate_err;
|
||||
}
|
||||
|
||||
init.name = name;
|
||||
init.ops = &clk_gpio_gate_ops;
|
||||
init.flags = flags | CLK_IS_BASIC;
|
||||
init.parent_names = (parent_name ? &parent_name : NULL);
|
||||
init.num_parents = (parent_name ? 1 : 0);
|
||||
|
||||
clk_gpio->gpiod = gpio_to_desc(gpio);
|
||||
clk_gpio->hw.init = &init;
|
||||
|
||||
clk = clk_register(dev, &clk_gpio->hw);
|
||||
|
||||
if (!IS_ERR(clk))
|
||||
return clk;
|
||||
|
||||
if (!dev)
|
||||
kfree(clk_gpio);
|
||||
|
||||
clk_register_gpio_gate_err:
|
||||
if (!dev)
|
||||
gpio_free(gpio);
|
||||
|
||||
return clk;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(clk_register_gpio_gate);
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
/**
|
||||
* The clk_register_gpio_gate has to be delayed, because the EPROBE_DEFER
|
||||
* can not be handled properly at of_clk_init() call time.
|
||||
*/
|
||||
|
||||
struct clk_gpio_gate_delayed_register_data {
|
||||
struct device_node *node;
|
||||
struct mutex lock;
|
||||
struct clk *clk;
|
||||
};
|
||||
|
||||
static struct clk *of_clk_gpio_gate_delayed_register_get(
|
||||
struct of_phandle_args *clkspec,
|
||||
void *_data)
|
||||
{
|
||||
struct clk_gpio_gate_delayed_register_data *data = _data;
|
||||
struct clk *clk;
|
||||
const char *clk_name = data->node->name;
|
||||
const char *parent_name;
|
||||
int gpio;
|
||||
enum of_gpio_flags of_flags;
|
||||
|
||||
mutex_lock(&data->lock);
|
||||
|
||||
if (data->clk) {
|
||||
mutex_unlock(&data->lock);
|
||||
return data->clk;
|
||||
}
|
||||
|
||||
gpio = of_get_named_gpio_flags(data->node, "enable-gpios", 0,
|
||||
&of_flags);
|
||||
if (gpio < 0) {
|
||||
mutex_unlock(&data->lock);
|
||||
if (gpio != -EPROBE_DEFER)
|
||||
pr_err("%s: %s: Can't get 'enable-gpios' DT property\n",
|
||||
__func__, clk_name);
|
||||
return ERR_PTR(gpio);
|
||||
}
|
||||
|
||||
parent_name = of_clk_get_parent_name(data->node, 0);
|
||||
|
||||
clk = clk_register_gpio_gate(NULL, clk_name, parent_name, gpio,
|
||||
of_flags & OF_GPIO_ACTIVE_LOW, 0);
|
||||
if (IS_ERR(clk)) {
|
||||
mutex_unlock(&data->lock);
|
||||
return clk;
|
||||
}
|
||||
|
||||
data->clk = clk;
|
||||
mutex_unlock(&data->lock);
|
||||
|
||||
return clk;
|
||||
}
|
||||
|
||||
/**
|
||||
* of_gpio_gate_clk_setup() - Setup function for gpio controlled clock
|
||||
*/
|
||||
static void __init of_gpio_gate_clk_setup(struct device_node *node)
|
||||
{
|
||||
struct clk_gpio_gate_delayed_register_data *data;
|
||||
|
||||
data = kzalloc(sizeof(struct clk_gpio_gate_delayed_register_data),
|
||||
GFP_KERNEL);
|
||||
if (!data)
|
||||
return;
|
||||
|
||||
data->node = node;
|
||||
mutex_init(&data->lock);
|
||||
|
||||
of_clk_add_provider(node, of_clk_gpio_gate_delayed_register_get, data);
|
||||
}
|
||||
CLK_OF_DECLARE(gpio_gate_clk, "gpio-gate-clock", of_gpio_gate_clk_setup);
|
||||
#endif
|
||||
325
drivers/clk/clk-gpio.c
Normal file
325
drivers/clk/clk-gpio.c
Normal file
|
|
@ -0,0 +1,325 @@
|
|||
/*
|
||||
* Copyright (C) 2013 - 2014 Texas Instruments Incorporated - http://www.ti.com
|
||||
*
|
||||
* Authors:
|
||||
* Jyri Sarha <jsarha@ti.com>
|
||||
* Sergej Sawazki <ce3a@gmx.de>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* Gpio controlled clock implementation
|
||||
*/
|
||||
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/export.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/gpio/consumer.h>
|
||||
#include <linux/of_gpio.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/device.h>
|
||||
|
||||
/**
|
||||
* DOC: basic gpio gated clock which can be enabled and disabled
|
||||
* with gpio output
|
||||
* Traits of this clock:
|
||||
* prepare - clk_(un)prepare only ensures parent is (un)prepared
|
||||
* enable - clk_enable and clk_disable are functional & control gpio
|
||||
* rate - inherits rate from parent. No clk_set_rate support
|
||||
* parent - fixed parent. No clk_set_parent support
|
||||
*/
|
||||
|
||||
#define to_clk_gpio(_hw) container_of(_hw, struct clk_gpio, hw)
|
||||
|
||||
static int clk_gpio_gate_enable(struct clk_hw *hw)
|
||||
{
|
||||
struct clk_gpio *clk = to_clk_gpio(hw);
|
||||
|
||||
gpiod_set_value(clk->gpiod, 1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void clk_gpio_gate_disable(struct clk_hw *hw)
|
||||
{
|
||||
struct clk_gpio *clk = to_clk_gpio(hw);
|
||||
|
||||
gpiod_set_value(clk->gpiod, 0);
|
||||
}
|
||||
|
||||
static int clk_gpio_gate_is_enabled(struct clk_hw *hw)
|
||||
{
|
||||
struct clk_gpio *clk = to_clk_gpio(hw);
|
||||
|
||||
return gpiod_get_value(clk->gpiod);
|
||||
}
|
||||
|
||||
const struct clk_ops clk_gpio_gate_ops = {
|
||||
.enable = clk_gpio_gate_enable,
|
||||
.disable = clk_gpio_gate_disable,
|
||||
.is_enabled = clk_gpio_gate_is_enabled,
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(clk_gpio_gate_ops);
|
||||
|
||||
/**
|
||||
* DOC: basic clock multiplexer which can be controlled with a gpio output
|
||||
* Traits of this clock:
|
||||
* prepare - clk_prepare only ensures that parents are prepared
|
||||
* rate - rate is only affected by parent switching. No clk_set_rate support
|
||||
* parent - parent is adjustable through clk_set_parent
|
||||
*/
|
||||
|
||||
static u8 clk_gpio_mux_get_parent(struct clk_hw *hw)
|
||||
{
|
||||
struct clk_gpio *clk = to_clk_gpio(hw);
|
||||
|
||||
return gpiod_get_value(clk->gpiod);
|
||||
}
|
||||
|
||||
static int clk_gpio_mux_set_parent(struct clk_hw *hw, u8 index)
|
||||
{
|
||||
struct clk_gpio *clk = to_clk_gpio(hw);
|
||||
|
||||
gpiod_set_value(clk->gpiod, index);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
const struct clk_ops clk_gpio_mux_ops = {
|
||||
.get_parent = clk_gpio_mux_get_parent,
|
||||
.set_parent = clk_gpio_mux_set_parent,
|
||||
.determine_rate = __clk_mux_determine_rate,
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(clk_gpio_mux_ops);
|
||||
|
||||
static struct clk *clk_register_gpio(struct device *dev, const char *name,
|
||||
const char * const *parent_names, u8 num_parents, unsigned gpio,
|
||||
bool active_low, unsigned long flags,
|
||||
const struct clk_ops *clk_gpio_ops)
|
||||
{
|
||||
struct clk_gpio *clk_gpio;
|
||||
struct clk *clk;
|
||||
struct clk_init_data init = {};
|
||||
unsigned long gpio_flags;
|
||||
int err;
|
||||
|
||||
if (dev)
|
||||
clk_gpio = devm_kzalloc(dev, sizeof(*clk_gpio), GFP_KERNEL);
|
||||
else
|
||||
clk_gpio = kzalloc(sizeof(*clk_gpio), GFP_KERNEL);
|
||||
|
||||
if (!clk_gpio)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
if (active_low)
|
||||
gpio_flags = GPIOF_ACTIVE_LOW | GPIOF_OUT_INIT_HIGH;
|
||||
else
|
||||
gpio_flags = GPIOF_OUT_INIT_LOW;
|
||||
|
||||
if (dev)
|
||||
err = devm_gpio_request_one(dev, gpio, gpio_flags, name);
|
||||
else
|
||||
err = gpio_request_one(gpio, gpio_flags, name);
|
||||
if (err) {
|
||||
if (err != -EPROBE_DEFER)
|
||||
pr_err("%s: %s: Error requesting clock control gpio %u\n",
|
||||
__func__, name, gpio);
|
||||
if (!dev)
|
||||
kfree(clk_gpio);
|
||||
|
||||
return ERR_PTR(err);
|
||||
}
|
||||
|
||||
init.name = name;
|
||||
init.ops = clk_gpio_ops;
|
||||
init.flags = flags | CLK_IS_BASIC;
|
||||
init.parent_names = parent_names;
|
||||
init.num_parents = num_parents;
|
||||
|
||||
clk_gpio->gpiod = gpio_to_desc(gpio);
|
||||
clk_gpio->hw.init = &init;
|
||||
|
||||
if (dev)
|
||||
clk = devm_clk_register(dev, &clk_gpio->hw);
|
||||
else
|
||||
clk = clk_register(NULL, &clk_gpio->hw);
|
||||
|
||||
if (!IS_ERR(clk))
|
||||
return clk;
|
||||
|
||||
if (!dev) {
|
||||
gpiod_put(clk_gpio->gpiod);
|
||||
kfree(clk_gpio);
|
||||
}
|
||||
|
||||
return clk;
|
||||
}
|
||||
|
||||
/**
|
||||
* clk_register_gpio_gate - register a gpio clock gate with the clock framework
|
||||
* @dev: device that is registering this clock
|
||||
* @name: name of this clock
|
||||
* @parent_name: name of this clock's parent
|
||||
* @gpio: gpio number to gate this clock
|
||||
* @active_low: true if gpio should be set to 0 to enable clock
|
||||
* @flags: clock flags
|
||||
*/
|
||||
struct clk *clk_register_gpio_gate(struct device *dev, const char *name,
|
||||
const char *parent_name, unsigned gpio, bool active_low,
|
||||
unsigned long flags)
|
||||
{
|
||||
return clk_register_gpio(dev, name,
|
||||
(parent_name ? &parent_name : NULL),
|
||||
(parent_name ? 1 : 0), gpio, active_low, flags,
|
||||
&clk_gpio_gate_ops);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(clk_register_gpio_gate);
|
||||
|
||||
/**
|
||||
* clk_register_gpio_mux - register a gpio clock mux with the clock framework
|
||||
* @dev: device that is registering this clock
|
||||
* @name: name of this clock
|
||||
* @parent_names: names of this clock's parents
|
||||
* @num_parents: number of parents listed in @parent_names
|
||||
* @gpio: gpio number to gate this clock
|
||||
* @active_low: true if gpio should be set to 0 to enable clock
|
||||
* @flags: clock flags
|
||||
*/
|
||||
struct clk *clk_register_gpio_mux(struct device *dev, const char *name,
|
||||
const char * const *parent_names, u8 num_parents, unsigned gpio,
|
||||
bool active_low, unsigned long flags)
|
||||
{
|
||||
if (num_parents != 2) {
|
||||
pr_err("mux-clock %s must have 2 parents\n", name);
|
||||
return ERR_PTR(-EINVAL);
|
||||
}
|
||||
|
||||
return clk_register_gpio(dev, name, parent_names, num_parents,
|
||||
gpio, active_low, flags, &clk_gpio_mux_ops);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(clk_register_gpio_mux);
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
/**
|
||||
* clk_register_get() has to be delayed, because -EPROBE_DEFER
|
||||
* can not be handled properly at of_clk_init() call time.
|
||||
*/
|
||||
|
||||
struct clk_gpio_delayed_register_data {
|
||||
const char *gpio_name;
|
||||
struct device_node *node;
|
||||
struct mutex lock;
|
||||
struct clk *clk;
|
||||
struct clk *(*clk_register_get)(const char *name,
|
||||
const char * const *parent_names, u8 num_parents,
|
||||
unsigned gpio, bool active_low);
|
||||
};
|
||||
|
||||
static struct clk *of_clk_gpio_delayed_register_get(
|
||||
struct of_phandle_args *clkspec, void *_data)
|
||||
{
|
||||
struct clk_gpio_delayed_register_data *data = _data;
|
||||
struct clk *clk;
|
||||
const char **parent_names;
|
||||
int i, num_parents;
|
||||
int gpio;
|
||||
enum of_gpio_flags of_flags;
|
||||
|
||||
mutex_lock(&data->lock);
|
||||
|
||||
if (data->clk) {
|
||||
mutex_unlock(&data->lock);
|
||||
return data->clk;
|
||||
}
|
||||
|
||||
gpio = of_get_named_gpio_flags(data->node, data->gpio_name, 0,
|
||||
&of_flags);
|
||||
if (gpio < 0) {
|
||||
mutex_unlock(&data->lock);
|
||||
if (gpio == -EPROBE_DEFER)
|
||||
pr_debug("%s: %s: GPIOs not yet available, retry later\n",
|
||||
data->node->name, __func__);
|
||||
else
|
||||
pr_err("%s: %s: Can't get '%s' DT property\n",
|
||||
data->node->name, __func__,
|
||||
data->gpio_name);
|
||||
return ERR_PTR(gpio);
|
||||
}
|
||||
|
||||
num_parents = of_clk_get_parent_count(data->node);
|
||||
|
||||
parent_names = kcalloc(num_parents, sizeof(char *), GFP_KERNEL);
|
||||
if (!parent_names) {
|
||||
clk = ERR_PTR(-ENOMEM);
|
||||
goto out;
|
||||
}
|
||||
|
||||
for (i = 0; i < num_parents; i++)
|
||||
parent_names[i] = of_clk_get_parent_name(data->node, i);
|
||||
|
||||
clk = data->clk_register_get(data->node->name, parent_names,
|
||||
num_parents, gpio, of_flags & OF_GPIO_ACTIVE_LOW);
|
||||
if (IS_ERR(clk))
|
||||
goto out;
|
||||
|
||||
data->clk = clk;
|
||||
out:
|
||||
mutex_unlock(&data->lock);
|
||||
kfree(parent_names);
|
||||
|
||||
return clk;
|
||||
}
|
||||
|
||||
static struct clk *of_clk_gpio_gate_delayed_register_get(const char *name,
|
||||
const char * const *parent_names, u8 num_parents,
|
||||
unsigned gpio, bool active_low)
|
||||
{
|
||||
return clk_register_gpio_gate(NULL, name, parent_names[0],
|
||||
gpio, active_low, 0);
|
||||
}
|
||||
|
||||
static struct clk *of_clk_gpio_mux_delayed_register_get(const char *name,
|
||||
const char * const *parent_names, u8 num_parents, unsigned gpio,
|
||||
bool active_low)
|
||||
{
|
||||
return clk_register_gpio_mux(NULL, name, parent_names, num_parents,
|
||||
gpio, active_low, 0);
|
||||
}
|
||||
|
||||
static void __init of_gpio_clk_setup(struct device_node *node,
|
||||
const char *gpio_name,
|
||||
struct clk *(*clk_register_get)(const char *name,
|
||||
const char * const *parent_names,
|
||||
u8 num_parents,
|
||||
unsigned gpio, bool active_low))
|
||||
{
|
||||
struct clk_gpio_delayed_register_data *data;
|
||||
|
||||
data = kzalloc(sizeof(*data), GFP_KERNEL);
|
||||
if (!data)
|
||||
return;
|
||||
|
||||
data->node = node;
|
||||
data->gpio_name = gpio_name;
|
||||
data->clk_register_get = clk_register_get;
|
||||
mutex_init(&data->lock);
|
||||
|
||||
of_clk_add_provider(node, of_clk_gpio_delayed_register_get, data);
|
||||
}
|
||||
|
||||
static void __init of_gpio_gate_clk_setup(struct device_node *node)
|
||||
{
|
||||
of_gpio_clk_setup(node, "enable-gpios",
|
||||
of_clk_gpio_gate_delayed_register_get);
|
||||
}
|
||||
CLK_OF_DECLARE(gpio_gate_clk, "gpio-gate-clock", of_gpio_gate_clk_setup);
|
||||
|
||||
void __init of_gpio_mux_clk_setup(struct device_node *node)
|
||||
{
|
||||
of_gpio_clk_setup(node, "select-gpios",
|
||||
of_clk_gpio_mux_delayed_register_get);
|
||||
}
|
||||
CLK_OF_DECLARE(gpio_mux_clk, "gpio-mux-clock", of_gpio_mux_clk_setup);
|
||||
#endif
|
||||
|
|
@ -17,6 +17,7 @@
|
|||
#include <linux/kernel.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/of.h>
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@
|
|||
* warranty of any kind, whether express or implied.
|
||||
*/
|
||||
|
||||
#include <linux/clk.h>
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/of_address.h>
|
||||
|
|
|
|||
|
|
@ -10,7 +10,6 @@
|
|||
* Simple multiplexer clock implementation
|
||||
*/
|
||||
|
||||
#include <linux/clk.h>
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/slab.h>
|
||||
|
|
@ -32,7 +31,7 @@
|
|||
static u8 clk_mux_get_parent(struct clk_hw *hw)
|
||||
{
|
||||
struct clk_mux *mux = to_clk_mux(hw);
|
||||
int num_parents = __clk_get_num_parents(hw->clk);
|
||||
int num_parents = clk_hw_get_num_parents(hw);
|
||||
u32 val;
|
||||
|
||||
/*
|
||||
|
|
@ -85,6 +84,8 @@ static int clk_mux_set_parent(struct clk_hw *hw, u8 index)
|
|||
|
||||
if (mux->lock)
|
||||
spin_lock_irqsave(mux->lock, flags);
|
||||
else
|
||||
__acquire(mux->lock);
|
||||
|
||||
if (mux->flags & CLK_MUX_HIWORD_MASK) {
|
||||
val = mux->mask << (mux->shift + 16);
|
||||
|
|
@ -97,6 +98,8 @@ static int clk_mux_set_parent(struct clk_hw *hw, u8 index)
|
|||
|
||||
if (mux->lock)
|
||||
spin_unlock_irqrestore(mux->lock, flags);
|
||||
else
|
||||
__release(mux->lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,8 +8,7 @@
|
|||
#define pr_fmt(fmt) "Nomadik SRC clocks: " fmt
|
||||
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/clkdev.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/clk-provider.h>
|
||||
|
|
|
|||
|
|
@ -18,7 +18,6 @@
|
|||
*/
|
||||
|
||||
#include <linux/clk.h>
|
||||
#include <linux/clkdev.h>
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/mfd/palmas.h>
|
||||
#include <linux/module.h>
|
||||
|
|
|
|||
|
|
@ -15,7 +15,6 @@
|
|||
* more details.
|
||||
*/
|
||||
|
||||
#include <linux/clk.h>
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/slab.h>
|
||||
|
|
|
|||
|
|
@ -58,21 +58,17 @@ static struct s2mps11_clk *to_s2mps11_clk(struct clk_hw *hw)
|
|||
static int s2mps11_clk_prepare(struct clk_hw *hw)
|
||||
{
|
||||
struct s2mps11_clk *s2mps11 = to_s2mps11_clk(hw);
|
||||
int ret;
|
||||
|
||||
ret = regmap_update_bits(s2mps11->iodev->regmap_pmic,
|
||||
return regmap_update_bits(s2mps11->iodev->regmap_pmic,
|
||||
s2mps11->reg,
|
||||
s2mps11->mask, s2mps11->mask);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void s2mps11_clk_unprepare(struct clk_hw *hw)
|
||||
{
|
||||
struct s2mps11_clk *s2mps11 = to_s2mps11_clk(hw);
|
||||
int ret;
|
||||
|
||||
ret = regmap_update_bits(s2mps11->iodev->regmap_pmic, s2mps11->reg,
|
||||
regmap_update_bits(s2mps11->iodev->regmap_pmic, s2mps11->reg,
|
||||
s2mps11->mask, ~s2mps11->mask);
|
||||
}
|
||||
|
||||
|
|
@ -186,15 +182,15 @@ static int s2mps11_clk_probe(struct platform_device *pdev)
|
|||
struct clk_init_data *clks_init;
|
||||
int i, ret = 0;
|
||||
|
||||
s2mps11_clks = devm_kzalloc(&pdev->dev, sizeof(*s2mps11_clk) *
|
||||
S2MPS11_CLKS_NUM, GFP_KERNEL);
|
||||
s2mps11_clks = devm_kcalloc(&pdev->dev, S2MPS11_CLKS_NUM,
|
||||
sizeof(*s2mps11_clk), GFP_KERNEL);
|
||||
if (!s2mps11_clks)
|
||||
return -ENOMEM;
|
||||
|
||||
s2mps11_clk = s2mps11_clks;
|
||||
|
||||
clk_table = devm_kzalloc(&pdev->dev, sizeof(struct clk *) *
|
||||
S2MPS11_CLKS_NUM, GFP_KERNEL);
|
||||
clk_table = devm_kcalloc(&pdev->dev, S2MPS11_CLKS_NUM,
|
||||
sizeof(struct clk *), GFP_KERNEL);
|
||||
if (!clk_table)
|
||||
return -ENOMEM;
|
||||
|
||||
|
|
@ -246,7 +242,7 @@ static int s2mps11_clk_probe(struct platform_device *pdev)
|
|||
s2mps11_name(s2mps11_clk), NULL);
|
||||
if (!s2mps11_clk->lookup) {
|
||||
ret = -ENOMEM;
|
||||
goto err_lup;
|
||||
goto err_reg;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -265,16 +261,10 @@ static int s2mps11_clk_probe(struct platform_device *pdev)
|
|||
platform_set_drvdata(pdev, s2mps11_clks);
|
||||
|
||||
return ret;
|
||||
err_lup:
|
||||
devm_clk_unregister(&pdev->dev, s2mps11_clk->clk);
|
||||
|
||||
err_reg:
|
||||
while (s2mps11_clk > s2mps11_clks) {
|
||||
if (s2mps11_clk->lookup) {
|
||||
clkdev_drop(s2mps11_clk->lookup);
|
||||
devm_clk_unregister(&pdev->dev, s2mps11_clk->clk);
|
||||
}
|
||||
s2mps11_clk--;
|
||||
}
|
||||
while (--i >= 0)
|
||||
clkdev_drop(s2mps11_clks[i].lookup);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
|
@ -322,7 +312,7 @@ static int __init s2mps11_clk_init(void)
|
|||
}
|
||||
subsys_initcall(s2mps11_clk_init);
|
||||
|
||||
static void __init s2mps11_clk_cleanup(void)
|
||||
static void __exit s2mps11_clk_cleanup(void)
|
||||
{
|
||||
platform_driver_unregister(&s2mps11_clk_driver);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@
|
|||
|
||||
#include <linux/module.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/clkdev.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/err.h>
|
||||
|
|
@ -439,7 +439,7 @@ static unsigned long si5351_pll_recalc_rate(struct clk_hw *hw,
|
|||
|
||||
dev_dbg(&hwdata->drvdata->client->dev,
|
||||
"%s - %s: p1 = %lu, p2 = %lu, p3 = %lu, parent_rate = %lu, rate = %lu\n",
|
||||
__func__, __clk_get_name(hwdata->hw.clk),
|
||||
__func__, clk_hw_get_name(hw),
|
||||
hwdata->params.p1, hwdata->params.p2, hwdata->params.p3,
|
||||
parent_rate, (unsigned long)rate);
|
||||
|
||||
|
|
@ -497,7 +497,7 @@ static long si5351_pll_round_rate(struct clk_hw *hw, unsigned long rate,
|
|||
|
||||
dev_dbg(&hwdata->drvdata->client->dev,
|
||||
"%s - %s: a = %lu, b = %lu, c = %lu, parent_rate = %lu, rate = %lu\n",
|
||||
__func__, __clk_get_name(hwdata->hw.clk), a, b, c,
|
||||
__func__, clk_hw_get_name(hw), a, b, c,
|
||||
*parent_rate, rate);
|
||||
|
||||
return rate;
|
||||
|
|
@ -521,7 +521,7 @@ static int si5351_pll_set_rate(struct clk_hw *hw, unsigned long rate,
|
|||
|
||||
dev_dbg(&hwdata->drvdata->client->dev,
|
||||
"%s - %s: p1 = %lu, p2 = %lu, p3 = %lu, parent_rate = %lu, rate = %lu\n",
|
||||
__func__, __clk_get_name(hwdata->hw.clk),
|
||||
__func__, clk_hw_get_name(hw),
|
||||
hwdata->params.p1, hwdata->params.p2, hwdata->params.p3,
|
||||
parent_rate, rate);
|
||||
|
||||
|
|
@ -632,7 +632,7 @@ static unsigned long si5351_msynth_recalc_rate(struct clk_hw *hw,
|
|||
|
||||
dev_dbg(&hwdata->drvdata->client->dev,
|
||||
"%s - %s: p1 = %lu, p2 = %lu, p3 = %lu, m = %lu, parent_rate = %lu, rate = %lu\n",
|
||||
__func__, __clk_get_name(hwdata->hw.clk),
|
||||
__func__, clk_hw_get_name(hw),
|
||||
hwdata->params.p1, hwdata->params.p2, hwdata->params.p3,
|
||||
m, parent_rate, (unsigned long)rate);
|
||||
|
||||
|
|
@ -663,7 +663,7 @@ static long si5351_msynth_round_rate(struct clk_hw *hw, unsigned long rate,
|
|||
divby4 = 1;
|
||||
|
||||
/* multisync can set pll */
|
||||
if (__clk_get_flags(hwdata->hw.clk) & CLK_SET_RATE_PARENT) {
|
||||
if (clk_hw_get_flags(hw) & CLK_SET_RATE_PARENT) {
|
||||
/*
|
||||
* find largest integer divider for max
|
||||
* vco frequency and given target rate
|
||||
|
|
@ -745,7 +745,7 @@ static long si5351_msynth_round_rate(struct clk_hw *hw, unsigned long rate,
|
|||
|
||||
dev_dbg(&hwdata->drvdata->client->dev,
|
||||
"%s - %s: a = %lu, b = %lu, c = %lu, divby4 = %d, parent_rate = %lu, rate = %lu\n",
|
||||
__func__, __clk_get_name(hwdata->hw.clk), a, b, c, divby4,
|
||||
__func__, clk_hw_get_name(hw), a, b, c, divby4,
|
||||
*parent_rate, rate);
|
||||
|
||||
return rate;
|
||||
|
|
@ -777,7 +777,7 @@ static int si5351_msynth_set_rate(struct clk_hw *hw, unsigned long rate,
|
|||
|
||||
dev_dbg(&hwdata->drvdata->client->dev,
|
||||
"%s - %s: p1 = %lu, p2 = %lu, p3 = %lu, divby4 = %d, parent_rate = %lu, rate = %lu\n",
|
||||
__func__, __clk_get_name(hwdata->hw.clk),
|
||||
__func__, clk_hw_get_name(hw),
|
||||
hwdata->params.p1, hwdata->params.p2, hwdata->params.p3,
|
||||
divby4, parent_rate, rate);
|
||||
|
||||
|
|
@ -1013,7 +1013,7 @@ static long si5351_clkout_round_rate(struct clk_hw *hw, unsigned long rate,
|
|||
rate = SI5351_CLKOUT_MIN_FREQ;
|
||||
|
||||
/* request frequency if multisync master */
|
||||
if (__clk_get_flags(hwdata->hw.clk) & CLK_SET_RATE_PARENT) {
|
||||
if (clk_hw_get_flags(hw) & CLK_SET_RATE_PARENT) {
|
||||
/* use r divider for frequencies below 1MHz */
|
||||
rdiv = SI5351_OUTPUT_CLK_DIV_1;
|
||||
while (rate < SI5351_MULTISYNTH_MIN_FREQ &&
|
||||
|
|
@ -1042,7 +1042,7 @@ static long si5351_clkout_round_rate(struct clk_hw *hw, unsigned long rate,
|
|||
|
||||
dev_dbg(&hwdata->drvdata->client->dev,
|
||||
"%s - %s: rdiv = %u, parent_rate = %lu, rate = %lu\n",
|
||||
__func__, __clk_get_name(hwdata->hw.clk), (1 << rdiv),
|
||||
__func__, clk_hw_get_name(hw), (1 << rdiv),
|
||||
*parent_rate, rate);
|
||||
|
||||
return rate;
|
||||
|
|
@ -1093,7 +1093,7 @@ static int si5351_clkout_set_rate(struct clk_hw *hw, unsigned long rate,
|
|||
|
||||
dev_dbg(&hwdata->drvdata->client->dev,
|
||||
"%s - %s: rdiv = %u, parent_rate = %lu, rate = %lu\n",
|
||||
__func__, __clk_get_name(hwdata->hw.clk), (1 << rdiv),
|
||||
__func__, clk_hw_get_name(hw), (1 << rdiv),
|
||||
parent_rate, rate);
|
||||
|
||||
return 0;
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@
|
|||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include <linux/clk.h>
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/module.h>
|
||||
|
|
|
|||
|
|
@ -175,11 +175,10 @@ static long clk_apb_mul_round_rate(struct clk_hw *hw, unsigned long rate,
|
|||
if (readl(base + STM32F4_RCC_CFGR) & BIT(am->bit_idx))
|
||||
mult = 2;
|
||||
|
||||
if (__clk_get_flags(hw->clk) & CLK_SET_RATE_PARENT) {
|
||||
if (clk_hw_get_flags(hw) & CLK_SET_RATE_PARENT) {
|
||||
unsigned long best_parent = rate / mult;
|
||||
|
||||
*prate =
|
||||
__clk_round_rate(__clk_get_parent(hw->clk), best_parent);
|
||||
*prate = clk_hw_round_rate(clk_hw_get_parent(hw), best_parent);
|
||||
}
|
||||
|
||||
return *prate * mult;
|
||||
|
|
|
|||
|
|
@ -20,7 +20,6 @@
|
|||
*
|
||||
*/
|
||||
|
||||
#include <linux/clk.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/platform_device.h>
|
||||
|
|
@ -91,7 +90,7 @@ static int twl6040_clk_probe(struct platform_device *pdev)
|
|||
clkdata->twl6040 = twl6040;
|
||||
|
||||
clkdata->mcpdm_fclk.init = &wm831x_clkout_init;
|
||||
clkdata->clk = clk_register(&pdev->dev, &clkdata->mcpdm_fclk);
|
||||
clkdata->clk = devm_clk_register(&pdev->dev, &clkdata->mcpdm_fclk);
|
||||
if (IS_ERR(clkdata->clk))
|
||||
return PTR_ERR(clkdata->clk);
|
||||
|
||||
|
|
@ -100,21 +99,11 @@ static int twl6040_clk_probe(struct platform_device *pdev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int twl6040_clk_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct twl6040_clk *clkdata = platform_get_drvdata(pdev);
|
||||
|
||||
clk_unregister(clkdata->clk);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver twl6040_clk_driver = {
|
||||
.driver = {
|
||||
.name = "twl6040-clk",
|
||||
},
|
||||
.probe = twl6040_clk_probe,
|
||||
.remove = twl6040_clk_remove,
|
||||
};
|
||||
|
||||
module_platform_driver(twl6040_clk_driver);
|
||||
|
|
|
|||
|
|
@ -5,8 +5,8 @@
|
|||
* Author: Linus Walleij <linus.walleij@stericsson.com>
|
||||
* Author: Jonas Aaberg <jonas.aberg@stericsson.com>
|
||||
*/
|
||||
#include <linux/clk.h>
|
||||
#include <linux/clkdev.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/clk-provider.h>
|
||||
|
|
|
|||
|
|
@ -12,7 +12,6 @@
|
|||
*
|
||||
*/
|
||||
|
||||
#include <linux/clk.h>
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/module.h>
|
||||
|
|
|
|||
|
|
@ -60,7 +60,6 @@ enum xgene_pll_type {
|
|||
|
||||
struct xgene_clk_pll {
|
||||
struct clk_hw hw;
|
||||
const char *name;
|
||||
void __iomem *reg;
|
||||
spinlock_t *lock;
|
||||
u32 pll_offset;
|
||||
|
|
@ -75,7 +74,7 @@ static int xgene_clk_pll_is_enabled(struct clk_hw *hw)
|
|||
u32 data;
|
||||
|
||||
data = xgene_clk_read(pllclk->reg + pllclk->pll_offset);
|
||||
pr_debug("%s pll %s\n", pllclk->name,
|
||||
pr_debug("%s pll %s\n", clk_hw_get_name(hw),
|
||||
data & REGSPEC_RESET_F1_MASK ? "disabled" : "enabled");
|
||||
|
||||
return data & REGSPEC_RESET_F1_MASK ? 0 : 1;
|
||||
|
|
@ -113,7 +112,7 @@ static unsigned long xgene_clk_pll_recalc_rate(struct clk_hw *hw,
|
|||
fref = parent_rate / nref;
|
||||
fvco = fref * nfb;
|
||||
}
|
||||
pr_debug("%s pll recalc rate %ld parent %ld\n", pllclk->name,
|
||||
pr_debug("%s pll recalc rate %ld parent %ld\n", clk_hw_get_name(hw),
|
||||
fvco / nout, parent_rate);
|
||||
|
||||
return fvco / nout;
|
||||
|
|
@ -146,7 +145,6 @@ static struct clk *xgene_register_clk_pll(struct device *dev,
|
|||
init.parent_names = parent_name ? &parent_name : NULL;
|
||||
init.num_parents = parent_name ? 1 : 0;
|
||||
|
||||
apmclk->name = name;
|
||||
apmclk->reg = reg;
|
||||
apmclk->lock = lock;
|
||||
apmclk->pll_offset = pll_offset;
|
||||
|
|
@ -210,7 +208,6 @@ struct xgene_dev_parameters {
|
|||
|
||||
struct xgene_clk {
|
||||
struct clk_hw hw;
|
||||
const char *name;
|
||||
spinlock_t *lock;
|
||||
struct xgene_dev_parameters param;
|
||||
};
|
||||
|
|
@ -228,7 +225,7 @@ static int xgene_clk_enable(struct clk_hw *hw)
|
|||
spin_lock_irqsave(pclk->lock, flags);
|
||||
|
||||
if (pclk->param.csr_reg != NULL) {
|
||||
pr_debug("%s clock enabled\n", pclk->name);
|
||||
pr_debug("%s clock enabled\n", clk_hw_get_name(hw));
|
||||
reg = __pa(pclk->param.csr_reg);
|
||||
/* First enable the clock */
|
||||
data = xgene_clk_read(pclk->param.csr_reg +
|
||||
|
|
@ -237,7 +234,7 @@ static int xgene_clk_enable(struct clk_hw *hw)
|
|||
xgene_clk_write(data, pclk->param.csr_reg +
|
||||
pclk->param.reg_clk_offset);
|
||||
pr_debug("%s clock PADDR base %pa clk offset 0x%08X mask 0x%08X value 0x%08X\n",
|
||||
pclk->name, ®,
|
||||
clk_hw_get_name(hw), ®,
|
||||
pclk->param.reg_clk_offset, pclk->param.reg_clk_mask,
|
||||
data);
|
||||
|
||||
|
|
@ -248,7 +245,7 @@ static int xgene_clk_enable(struct clk_hw *hw)
|
|||
xgene_clk_write(data, pclk->param.csr_reg +
|
||||
pclk->param.reg_csr_offset);
|
||||
pr_debug("%s CSR RESET PADDR base %pa csr offset 0x%08X mask 0x%08X value 0x%08X\n",
|
||||
pclk->name, ®,
|
||||
clk_hw_get_name(hw), ®,
|
||||
pclk->param.reg_csr_offset, pclk->param.reg_csr_mask,
|
||||
data);
|
||||
}
|
||||
|
|
@ -269,7 +266,7 @@ static void xgene_clk_disable(struct clk_hw *hw)
|
|||
spin_lock_irqsave(pclk->lock, flags);
|
||||
|
||||
if (pclk->param.csr_reg != NULL) {
|
||||
pr_debug("%s clock disabled\n", pclk->name);
|
||||
pr_debug("%s clock disabled\n", clk_hw_get_name(hw));
|
||||
/* First put the CSR in reset */
|
||||
data = xgene_clk_read(pclk->param.csr_reg +
|
||||
pclk->param.reg_csr_offset);
|
||||
|
|
@ -295,10 +292,10 @@ static int xgene_clk_is_enabled(struct clk_hw *hw)
|
|||
u32 data = 0;
|
||||
|
||||
if (pclk->param.csr_reg != NULL) {
|
||||
pr_debug("%s clock checking\n", pclk->name);
|
||||
pr_debug("%s clock checking\n", clk_hw_get_name(hw));
|
||||
data = xgene_clk_read(pclk->param.csr_reg +
|
||||
pclk->param.reg_clk_offset);
|
||||
pr_debug("%s clock is %s\n", pclk->name,
|
||||
pr_debug("%s clock is %s\n", clk_hw_get_name(hw),
|
||||
data & pclk->param.reg_clk_mask ? "enabled" :
|
||||
"disabled");
|
||||
}
|
||||
|
|
@ -321,11 +318,13 @@ static unsigned long xgene_clk_recalc_rate(struct clk_hw *hw,
|
|||
data &= (1 << pclk->param.reg_divider_width) - 1;
|
||||
|
||||
pr_debug("%s clock recalc rate %ld parent %ld\n",
|
||||
pclk->name, parent_rate / data, parent_rate);
|
||||
clk_hw_get_name(hw),
|
||||
parent_rate / data, parent_rate);
|
||||
|
||||
return parent_rate / data;
|
||||
} else {
|
||||
pr_debug("%s clock recalc rate %ld parent %ld\n",
|
||||
pclk->name, parent_rate, parent_rate);
|
||||
clk_hw_get_name(hw), parent_rate, parent_rate);
|
||||
return parent_rate;
|
||||
}
|
||||
}
|
||||
|
|
@ -357,7 +356,7 @@ static int xgene_clk_set_rate(struct clk_hw *hw, unsigned long rate,
|
|||
data |= divider;
|
||||
xgene_clk_write(data, pclk->param.divider_reg +
|
||||
pclk->param.reg_divider_offset);
|
||||
pr_debug("%s clock set rate %ld\n", pclk->name,
|
||||
pr_debug("%s clock set rate %ld\n", clk_hw_get_name(hw),
|
||||
parent_rate / divider_save);
|
||||
} else {
|
||||
divider_save = 1;
|
||||
|
|
@ -419,7 +418,6 @@ static struct clk *xgene_register_clk(struct device *dev,
|
|||
init.parent_names = parent_name ? &parent_name : NULL;
|
||||
init.num_parents = parent_name ? 1 : 0;
|
||||
|
||||
apmclk->name = name;
|
||||
apmclk->lock = lock;
|
||||
apmclk->hw.init = &init;
|
||||
apmclk->param = *parameters;
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@
|
|||
* Standard functionality for the common clock API. See Documentation/clk.txt
|
||||
*/
|
||||
|
||||
#include <linux/clk.h>
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/clk/clk-conf.h>
|
||||
#include <linux/module.h>
|
||||
|
|
@ -56,8 +57,11 @@ struct clk_core {
|
|||
struct clk_core *new_parent;
|
||||
struct clk_core *new_child;
|
||||
unsigned long flags;
|
||||
bool orphan;
|
||||
unsigned int enable_count;
|
||||
unsigned int prepare_count;
|
||||
unsigned long min_rate;
|
||||
unsigned long max_rate;
|
||||
unsigned long accuracy;
|
||||
int phase;
|
||||
struct hlist_head children;
|
||||
|
|
@ -111,12 +115,14 @@ static void clk_prepare_unlock(void)
|
|||
}
|
||||
|
||||
static unsigned long clk_enable_lock(void)
|
||||
__acquires(enable_lock)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
if (!spin_trylock_irqsave(&enable_lock, flags)) {
|
||||
if (enable_owner == current) {
|
||||
enable_refcnt++;
|
||||
__acquire(enable_lock);
|
||||
return flags;
|
||||
}
|
||||
spin_lock_irqsave(&enable_lock, flags);
|
||||
|
|
@ -129,12 +135,15 @@ static unsigned long clk_enable_lock(void)
|
|||
}
|
||||
|
||||
static void clk_enable_unlock(unsigned long flags)
|
||||
__releases(enable_lock)
|
||||
{
|
||||
WARN_ON_ONCE(enable_owner != current);
|
||||
WARN_ON_ONCE(enable_refcnt == 0);
|
||||
|
||||
if (--enable_refcnt)
|
||||
if (--enable_refcnt) {
|
||||
__release(enable_lock);
|
||||
return;
|
||||
}
|
||||
enable_owner = NULL;
|
||||
spin_unlock_irqrestore(&enable_lock, flags);
|
||||
}
|
||||
|
|
@ -269,27 +278,29 @@ const char *__clk_get_name(struct clk *clk)
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(__clk_get_name);
|
||||
|
||||
const char *clk_hw_get_name(const struct clk_hw *hw)
|
||||
{
|
||||
return hw->core->name;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(clk_hw_get_name);
|
||||
|
||||
struct clk_hw *__clk_get_hw(struct clk *clk)
|
||||
{
|
||||
return !clk ? NULL : clk->core->hw;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(__clk_get_hw);
|
||||
|
||||
u8 __clk_get_num_parents(struct clk *clk)
|
||||
unsigned int clk_hw_get_num_parents(const struct clk_hw *hw)
|
||||
{
|
||||
return !clk ? 0 : clk->core->num_parents;
|
||||
return hw->core->num_parents;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(__clk_get_num_parents);
|
||||
EXPORT_SYMBOL_GPL(clk_hw_get_num_parents);
|
||||
|
||||
struct clk *__clk_get_parent(struct clk *clk)
|
||||
struct clk_hw *clk_hw_get_parent(const struct clk_hw *hw)
|
||||
{
|
||||
if (!clk)
|
||||
return NULL;
|
||||
|
||||
/* TODO: Create a per-user clk and change callers to call clk_put */
|
||||
return !clk->core->parent ? NULL : clk->core->parent->hw->clk;
|
||||
return hw->core->parent ? hw->core->parent->hw : NULL;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(__clk_get_parent);
|
||||
EXPORT_SYMBOL_GPL(clk_hw_get_parent);
|
||||
|
||||
static struct clk_core *__clk_lookup_subtree(const char *name,
|
||||
struct clk_core *core)
|
||||
|
|
@ -348,18 +359,16 @@ static struct clk_core *clk_core_get_parent_by_index(struct clk_core *core,
|
|||
return core->parents[index];
|
||||
}
|
||||
|
||||
struct clk *clk_get_parent_by_index(struct clk *clk, u8 index)
|
||||
struct clk_hw *
|
||||
clk_hw_get_parent_by_index(const struct clk_hw *hw, unsigned int index)
|
||||
{
|
||||
struct clk_core *parent;
|
||||
|
||||
if (!clk)
|
||||
return NULL;
|
||||
parent = clk_core_get_parent_by_index(hw->core, index);
|
||||
|
||||
parent = clk_core_get_parent_by_index(clk->core, index);
|
||||
|
||||
return !parent ? NULL : parent->hw->clk;
|
||||
return !parent ? NULL : parent->hw;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(clk_get_parent_by_index);
|
||||
EXPORT_SYMBOL_GPL(clk_hw_get_parent_by_index);
|
||||
|
||||
unsigned int __clk_get_enable_count(struct clk *clk)
|
||||
{
|
||||
|
|
@ -387,14 +396,11 @@ out:
|
|||
return ret;
|
||||
}
|
||||
|
||||
unsigned long __clk_get_rate(struct clk *clk)
|
||||
unsigned long clk_hw_get_rate(const struct clk_hw *hw)
|
||||
{
|
||||
if (!clk)
|
||||
return 0;
|
||||
|
||||
return clk_core_get_rate_nolock(clk->core);
|
||||
return clk_core_get_rate_nolock(hw->core);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(__clk_get_rate);
|
||||
EXPORT_SYMBOL_GPL(clk_hw_get_rate);
|
||||
|
||||
static unsigned long __clk_get_accuracy(struct clk_core *core)
|
||||
{
|
||||
|
|
@ -410,12 +416,15 @@ unsigned long __clk_get_flags(struct clk *clk)
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(__clk_get_flags);
|
||||
|
||||
bool __clk_is_prepared(struct clk *clk)
|
||||
unsigned long clk_hw_get_flags(const struct clk_hw *hw)
|
||||
{
|
||||
if (!clk)
|
||||
return false;
|
||||
return hw->core->flags;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(clk_hw_get_flags);
|
||||
|
||||
return clk_core_is_prepared(clk->core);
|
||||
bool clk_hw_is_prepared(const struct clk_hw *hw)
|
||||
{
|
||||
return clk_core_is_prepared(hw->core);
|
||||
}
|
||||
|
||||
bool __clk_is_enabled(struct clk *clk)
|
||||
|
|
@ -436,28 +445,31 @@ static bool mux_is_better_rate(unsigned long rate, unsigned long now,
|
|||
return now <= rate && now > best;
|
||||
}
|
||||
|
||||
static long
|
||||
clk_mux_determine_rate_flags(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long min_rate,
|
||||
unsigned long max_rate,
|
||||
unsigned long *best_parent_rate,
|
||||
struct clk_hw **best_parent_p,
|
||||
static int
|
||||
clk_mux_determine_rate_flags(struct clk_hw *hw, struct clk_rate_request *req,
|
||||
unsigned long flags)
|
||||
{
|
||||
struct clk_core *core = hw->core, *parent, *best_parent = NULL;
|
||||
int i, num_parents;
|
||||
unsigned long parent_rate, best = 0;
|
||||
int i, num_parents, ret;
|
||||
unsigned long best = 0;
|
||||
struct clk_rate_request parent_req = *req;
|
||||
|
||||
/* if NO_REPARENT flag set, pass through to current parent */
|
||||
if (core->flags & CLK_SET_RATE_NO_REPARENT) {
|
||||
parent = core->parent;
|
||||
if (core->flags & CLK_SET_RATE_PARENT)
|
||||
best = __clk_determine_rate(parent ? parent->hw : NULL,
|
||||
rate, min_rate, max_rate);
|
||||
else if (parent)
|
||||
if (core->flags & CLK_SET_RATE_PARENT) {
|
||||
ret = __clk_determine_rate(parent ? parent->hw : NULL,
|
||||
&parent_req);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
best = parent_req.rate;
|
||||
} else if (parent) {
|
||||
best = clk_core_get_rate_nolock(parent);
|
||||
else
|
||||
} else {
|
||||
best = clk_core_get_rate_nolock(core);
|
||||
}
|
||||
|
||||
goto out;
|
||||
}
|
||||
|
||||
|
|
@ -467,24 +479,33 @@ clk_mux_determine_rate_flags(struct clk_hw *hw, unsigned long rate,
|
|||
parent = clk_core_get_parent_by_index(core, i);
|
||||
if (!parent)
|
||||
continue;
|
||||
if (core->flags & CLK_SET_RATE_PARENT)
|
||||
parent_rate = __clk_determine_rate(parent->hw, rate,
|
||||
min_rate,
|
||||
max_rate);
|
||||
else
|
||||
parent_rate = clk_core_get_rate_nolock(parent);
|
||||
if (mux_is_better_rate(rate, parent_rate, best, flags)) {
|
||||
|
||||
if (core->flags & CLK_SET_RATE_PARENT) {
|
||||
parent_req = *req;
|
||||
ret = __clk_determine_rate(parent->hw, &parent_req);
|
||||
if (ret)
|
||||
continue;
|
||||
} else {
|
||||
parent_req.rate = clk_core_get_rate_nolock(parent);
|
||||
}
|
||||
|
||||
if (mux_is_better_rate(req->rate, parent_req.rate,
|
||||
best, flags)) {
|
||||
best_parent = parent;
|
||||
best = parent_rate;
|
||||
best = parent_req.rate;
|
||||
}
|
||||
}
|
||||
|
||||
if (!best_parent)
|
||||
return -EINVAL;
|
||||
|
||||
out:
|
||||
if (best_parent)
|
||||
*best_parent_p = best_parent->hw;
|
||||
*best_parent_rate = best;
|
||||
req->best_parent_hw = best_parent->hw;
|
||||
req->best_parent_rate = best;
|
||||
req->rate = best;
|
||||
|
||||
return best;
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct clk *__clk_lookup(const char *name)
|
||||
|
|
@ -500,8 +521,8 @@ static void clk_core_get_boundaries(struct clk_core *core,
|
|||
{
|
||||
struct clk *clk_user;
|
||||
|
||||
*min_rate = 0;
|
||||
*max_rate = ULONG_MAX;
|
||||
*min_rate = core->min_rate;
|
||||
*max_rate = core->max_rate;
|
||||
|
||||
hlist_for_each_entry(clk_user, &core->clks, clks_node)
|
||||
*min_rate = max(*min_rate, clk_user->min_rate);
|
||||
|
|
@ -510,33 +531,30 @@ static void clk_core_get_boundaries(struct clk_core *core,
|
|||
*max_rate = min(*max_rate, clk_user->max_rate);
|
||||
}
|
||||
|
||||
void clk_hw_set_rate_range(struct clk_hw *hw, unsigned long min_rate,
|
||||
unsigned long max_rate)
|
||||
{
|
||||
hw->core->min_rate = min_rate;
|
||||
hw->core->max_rate = max_rate;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(clk_hw_set_rate_range);
|
||||
|
||||
/*
|
||||
* Helper for finding best parent to provide a given frequency. This can be used
|
||||
* directly as a determine_rate callback (e.g. for a mux), or from a more
|
||||
* complex clock that may combine a mux with other operations.
|
||||
*/
|
||||
long __clk_mux_determine_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long min_rate,
|
||||
unsigned long max_rate,
|
||||
unsigned long *best_parent_rate,
|
||||
struct clk_hw **best_parent_p)
|
||||
int __clk_mux_determine_rate(struct clk_hw *hw,
|
||||
struct clk_rate_request *req)
|
||||
{
|
||||
return clk_mux_determine_rate_flags(hw, rate, min_rate, max_rate,
|
||||
best_parent_rate,
|
||||
best_parent_p, 0);
|
||||
return clk_mux_determine_rate_flags(hw, req, 0);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(__clk_mux_determine_rate);
|
||||
|
||||
long __clk_mux_determine_rate_closest(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long min_rate,
|
||||
unsigned long max_rate,
|
||||
unsigned long *best_parent_rate,
|
||||
struct clk_hw **best_parent_p)
|
||||
int __clk_mux_determine_rate_closest(struct clk_hw *hw,
|
||||
struct clk_rate_request *req)
|
||||
{
|
||||
return clk_mux_determine_rate_flags(hw, rate, min_rate, max_rate,
|
||||
best_parent_rate,
|
||||
best_parent_p,
|
||||
CLK_MUX_ROUND_CLOSEST);
|
||||
return clk_mux_determine_rate_flags(hw, req, CLK_MUX_ROUND_CLOSEST);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(__clk_mux_determine_rate_closest);
|
||||
|
||||
|
|
@ -759,14 +777,11 @@ int clk_enable(struct clk *clk)
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(clk_enable);
|
||||
|
||||
static unsigned long clk_core_round_rate_nolock(struct clk_core *core,
|
||||
unsigned long rate,
|
||||
unsigned long min_rate,
|
||||
unsigned long max_rate)
|
||||
static int clk_core_round_rate_nolock(struct clk_core *core,
|
||||
struct clk_rate_request *req)
|
||||
{
|
||||
unsigned long parent_rate = 0;
|
||||
struct clk_core *parent;
|
||||
struct clk_hw *parent_hw;
|
||||
long rate;
|
||||
|
||||
lockdep_assert_held(&prepare_lock);
|
||||
|
||||
|
|
@ -774,21 +789,30 @@ static unsigned long clk_core_round_rate_nolock(struct clk_core *core,
|
|||
return 0;
|
||||
|
||||
parent = core->parent;
|
||||
if (parent)
|
||||
parent_rate = parent->rate;
|
||||
if (parent) {
|
||||
req->best_parent_hw = parent->hw;
|
||||
req->best_parent_rate = parent->rate;
|
||||
} else {
|
||||
req->best_parent_hw = NULL;
|
||||
req->best_parent_rate = 0;
|
||||
}
|
||||
|
||||
if (core->ops->determine_rate) {
|
||||
parent_hw = parent ? parent->hw : NULL;
|
||||
return core->ops->determine_rate(core->hw, rate,
|
||||
min_rate, max_rate,
|
||||
&parent_rate, &parent_hw);
|
||||
} else if (core->ops->round_rate)
|
||||
return core->ops->round_rate(core->hw, rate, &parent_rate);
|
||||
else if (core->flags & CLK_SET_RATE_PARENT)
|
||||
return clk_core_round_rate_nolock(core->parent, rate, min_rate,
|
||||
max_rate);
|
||||
else
|
||||
return core->rate;
|
||||
return core->ops->determine_rate(core->hw, req);
|
||||
} else if (core->ops->round_rate) {
|
||||
rate = core->ops->round_rate(core->hw, req->rate,
|
||||
&req->best_parent_rate);
|
||||
if (rate < 0)
|
||||
return rate;
|
||||
|
||||
req->rate = rate;
|
||||
} else if (core->flags & CLK_SET_RATE_PARENT) {
|
||||
return clk_core_round_rate_nolock(parent, req);
|
||||
} else {
|
||||
req->rate = core->rate;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -800,38 +824,32 @@ static unsigned long clk_core_round_rate_nolock(struct clk_core *core,
|
|||
*
|
||||
* Useful for clk_ops such as .set_rate and .determine_rate.
|
||||
*/
|
||||
unsigned long __clk_determine_rate(struct clk_hw *hw,
|
||||
unsigned long rate,
|
||||
unsigned long min_rate,
|
||||
unsigned long max_rate)
|
||||
int __clk_determine_rate(struct clk_hw *hw, struct clk_rate_request *req)
|
||||
{
|
||||
if (!hw)
|
||||
if (!hw) {
|
||||
req->rate = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return clk_core_round_rate_nolock(hw->core, rate, min_rate, max_rate);
|
||||
return clk_core_round_rate_nolock(hw->core, req);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(__clk_determine_rate);
|
||||
|
||||
/**
|
||||
* __clk_round_rate - round the given rate for a clk
|
||||
* @clk: round the rate of this clock
|
||||
* @rate: the rate which is to be rounded
|
||||
*
|
||||
* Useful for clk_ops such as .set_rate
|
||||
*/
|
||||
unsigned long __clk_round_rate(struct clk *clk, unsigned long rate)
|
||||
unsigned long clk_hw_round_rate(struct clk_hw *hw, unsigned long rate)
|
||||
{
|
||||
unsigned long min_rate;
|
||||
unsigned long max_rate;
|
||||
int ret;
|
||||
struct clk_rate_request req;
|
||||
|
||||
if (!clk)
|
||||
clk_core_get_boundaries(hw->core, &req.min_rate, &req.max_rate);
|
||||
req.rate = rate;
|
||||
|
||||
ret = clk_core_round_rate_nolock(hw->core, &req);
|
||||
if (ret)
|
||||
return 0;
|
||||
|
||||
clk_core_get_boundaries(clk->core, &min_rate, &max_rate);
|
||||
|
||||
return clk_core_round_rate_nolock(clk->core, rate, min_rate, max_rate);
|
||||
return req.rate;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(__clk_round_rate);
|
||||
EXPORT_SYMBOL_GPL(clk_hw_round_rate);
|
||||
|
||||
/**
|
||||
* clk_round_rate - round the given rate for a clk
|
||||
|
|
@ -844,16 +862,24 @@ EXPORT_SYMBOL_GPL(__clk_round_rate);
|
|||
*/
|
||||
long clk_round_rate(struct clk *clk, unsigned long rate)
|
||||
{
|
||||
unsigned long ret;
|
||||
struct clk_rate_request req;
|
||||
int ret;
|
||||
|
||||
if (!clk)
|
||||
return 0;
|
||||
|
||||
clk_prepare_lock();
|
||||
ret = __clk_round_rate(clk, rate);
|
||||
|
||||
clk_core_get_boundaries(clk->core, &req.min_rate, &req.max_rate);
|
||||
req.rate = rate;
|
||||
|
||||
ret = clk_core_round_rate_nolock(clk->core, &req);
|
||||
clk_prepare_unlock();
|
||||
|
||||
return ret;
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return req.rate;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(clk_round_rate);
|
||||
|
||||
|
|
@ -1064,18 +1090,40 @@ static int clk_fetch_parent_index(struct clk_core *core,
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Update the orphan status of @core and all its children.
|
||||
*/
|
||||
static void clk_core_update_orphan_status(struct clk_core *core, bool is_orphan)
|
||||
{
|
||||
struct clk_core *child;
|
||||
|
||||
core->orphan = is_orphan;
|
||||
|
||||
hlist_for_each_entry(child, &core->children, child_node)
|
||||
clk_core_update_orphan_status(child, is_orphan);
|
||||
}
|
||||
|
||||
static void clk_reparent(struct clk_core *core, struct clk_core *new_parent)
|
||||
{
|
||||
bool was_orphan = core->orphan;
|
||||
|
||||
hlist_del(&core->child_node);
|
||||
|
||||
if (new_parent) {
|
||||
bool becomes_orphan = new_parent->orphan;
|
||||
|
||||
/* avoid duplicate POST_RATE_CHANGE notifications */
|
||||
if (new_parent->new_child == core)
|
||||
new_parent->new_child = NULL;
|
||||
|
||||
hlist_add_head(&core->child_node, &new_parent->children);
|
||||
|
||||
if (was_orphan != becomes_orphan)
|
||||
clk_core_update_orphan_status(core, becomes_orphan);
|
||||
} else {
|
||||
hlist_add_head(&core->child_node, &clk_orphan_list);
|
||||
if (!was_orphan)
|
||||
clk_core_update_orphan_status(core, true);
|
||||
}
|
||||
|
||||
core->parent = new_parent;
|
||||
|
|
@ -1160,14 +1208,8 @@ static int __clk_set_parent(struct clk_core *core, struct clk_core *parent,
|
|||
flags = clk_enable_lock();
|
||||
clk_reparent(core, old_parent);
|
||||
clk_enable_unlock(flags);
|
||||
__clk_set_parent_after(core, old_parent, parent);
|
||||
|
||||
if (core->prepare_count) {
|
||||
flags = clk_enable_lock();
|
||||
clk_core_disable(core);
|
||||
clk_core_disable(parent);
|
||||
clk_enable_unlock(flags);
|
||||
clk_core_unprepare(parent);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
@ -1249,7 +1291,6 @@ static struct clk_core *clk_calc_new_rates(struct clk_core *core,
|
|||
{
|
||||
struct clk_core *top = core;
|
||||
struct clk_core *old_parent, *parent;
|
||||
struct clk_hw *parent_hw;
|
||||
unsigned long best_parent_rate = 0;
|
||||
unsigned long new_rate;
|
||||
unsigned long min_rate;
|
||||
|
|
@ -1270,20 +1311,29 @@ static struct clk_core *clk_calc_new_rates(struct clk_core *core,
|
|||
|
||||
/* find the closest rate and parent clk/rate */
|
||||
if (core->ops->determine_rate) {
|
||||
parent_hw = parent ? parent->hw : NULL;
|
||||
ret = core->ops->determine_rate(core->hw, rate,
|
||||
min_rate,
|
||||
max_rate,
|
||||
&best_parent_rate,
|
||||
&parent_hw);
|
||||
struct clk_rate_request req;
|
||||
|
||||
req.rate = rate;
|
||||
req.min_rate = min_rate;
|
||||
req.max_rate = max_rate;
|
||||
if (parent) {
|
||||
req.best_parent_hw = parent->hw;
|
||||
req.best_parent_rate = parent->rate;
|
||||
} else {
|
||||
req.best_parent_hw = NULL;
|
||||
req.best_parent_rate = 0;
|
||||
}
|
||||
|
||||
ret = core->ops->determine_rate(core->hw, &req);
|
||||
if (ret < 0)
|
||||
return NULL;
|
||||
|
||||
new_rate = ret;
|
||||
parent = parent_hw ? parent_hw->core : NULL;
|
||||
best_parent_rate = req.best_parent_rate;
|
||||
new_rate = req.rate;
|
||||
parent = req.best_parent_hw ? req.best_parent_hw->core : NULL;
|
||||
} else if (core->ops->round_rate) {
|
||||
ret = core->ops->round_rate(core->hw, rate,
|
||||
&best_parent_rate);
|
||||
&best_parent_rate);
|
||||
if (ret < 0)
|
||||
return NULL;
|
||||
|
||||
|
|
@ -1592,8 +1642,12 @@ struct clk *clk_get_parent(struct clk *clk)
|
|||
{
|
||||
struct clk *parent;
|
||||
|
||||
if (!clk)
|
||||
return NULL;
|
||||
|
||||
clk_prepare_lock();
|
||||
parent = __clk_get_parent(clk);
|
||||
/* TODO: Create a per-user clk and change callers to call clk_put */
|
||||
parent = !clk->core->parent ? NULL : clk->core->parent->hw->clk;
|
||||
clk_prepare_unlock();
|
||||
|
||||
return parent;
|
||||
|
|
@ -2324,13 +2378,17 @@ static int __clk_init(struct device *dev, struct clk *clk_user)
|
|||
* clocks and re-parent any that are children of the clock currently
|
||||
* being clk_init'd.
|
||||
*/
|
||||
if (core->parent)
|
||||
if (core->parent) {
|
||||
hlist_add_head(&core->child_node,
|
||||
&core->parent->children);
|
||||
else if (core->flags & CLK_IS_ROOT)
|
||||
core->orphan = core->parent->orphan;
|
||||
} else if (core->flags & CLK_IS_ROOT) {
|
||||
hlist_add_head(&core->child_node, &clk_root_list);
|
||||
else
|
||||
core->orphan = false;
|
||||
} else {
|
||||
hlist_add_head(&core->child_node, &clk_orphan_list);
|
||||
core->orphan = true;
|
||||
}
|
||||
|
||||
/*
|
||||
* Set clk's accuracy. The preferred method is to use
|
||||
|
|
@ -2479,6 +2537,8 @@ struct clk *clk_register(struct device *dev, struct clk_hw *hw)
|
|||
core->hw = hw;
|
||||
core->flags = hw->init->flags;
|
||||
core->num_parents = hw->init->num_parents;
|
||||
core->min_rate = 0;
|
||||
core->max_rate = ULONG_MAX;
|
||||
hw->core = core;
|
||||
|
||||
/* allocate local copy in case parent_names is __initdata */
|
||||
|
|
@ -3054,8 +3114,6 @@ struct clock_provider {
|
|||
struct list_head node;
|
||||
};
|
||||
|
||||
static LIST_HEAD(clk_provider_list);
|
||||
|
||||
/*
|
||||
* This function looks for a parent clock. If there is one, then it
|
||||
* checks that the provider for this parent clock was initialized, in
|
||||
|
|
@ -3106,14 +3164,24 @@ void __init of_clk_init(const struct of_device_id *matches)
|
|||
struct clock_provider *clk_provider, *next;
|
||||
bool is_init_done;
|
||||
bool force = false;
|
||||
LIST_HEAD(clk_provider_list);
|
||||
|
||||
if (!matches)
|
||||
matches = &__clk_of_table;
|
||||
|
||||
/* First prepare the list of the clocks providers */
|
||||
for_each_matching_node_and_match(np, matches, &match) {
|
||||
struct clock_provider *parent =
|
||||
kzalloc(sizeof(struct clock_provider), GFP_KERNEL);
|
||||
struct clock_provider *parent;
|
||||
|
||||
parent = kzalloc(sizeof(*parent), GFP_KERNEL);
|
||||
if (!parent) {
|
||||
list_for_each_entry_safe(clk_provider, next,
|
||||
&clk_provider_list, node) {
|
||||
list_del(&clk_provider->node);
|
||||
kfree(clk_provider);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
parent->clk_init_cb = match->data;
|
||||
parent->np = np;
|
||||
|
|
|
|||
|
|
@ -4,8 +4,6 @@
|
|||
* Copyright 2015 Yoshinori Sato <ysato@users.sourceforge.jp>
|
||||
*/
|
||||
|
||||
#include <linux/clk.h>
|
||||
#include <linux/clkdev.h>
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/of.h>
|
||||
|
|
@ -15,7 +13,7 @@ static DEFINE_SPINLOCK(clklock);
|
|||
|
||||
static void __init h8300_div_clk_setup(struct device_node *node)
|
||||
{
|
||||
unsigned int num_parents;
|
||||
int num_parents;
|
||||
struct clk *clk;
|
||||
const char *clk_name = node->name;
|
||||
const char *parent_name;
|
||||
|
|
|
|||
|
|
@ -4,8 +4,6 @@
|
|||
* Copyright 2015 Yoshinori Sato <ysato@users.sourceforge.jp>
|
||||
*/
|
||||
|
||||
#include <linux/clk.h>
|
||||
#include <linux/clkdev.h>
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/device.h>
|
||||
|
|
@ -28,7 +26,7 @@ static unsigned long pll_recalc_rate(struct clk_hw *hw,
|
|||
unsigned long parent_rate)
|
||||
{
|
||||
struct pll_clock *pll_clock = to_pll_clock(hw);
|
||||
int mul = 1 << (ctrl_inb((unsigned long)pll_clock->pllcr) & 3);
|
||||
int mul = 1 << (readb(pll_clock->pllcr) & 3);
|
||||
|
||||
return parent_rate * mul;
|
||||
}
|
||||
|
|
@ -65,13 +63,13 @@ static int pll_set_rate(struct clk_hw *hw, unsigned long rate,
|
|||
|
||||
pll = ((rate / parent_rate) / 2) & 0x03;
|
||||
spin_lock_irqsave(&clklock, flags);
|
||||
val = ctrl_inb((unsigned long)pll_clock->sckcr);
|
||||
val = readb(pll_clock->sckcr);
|
||||
val |= 0x08;
|
||||
ctrl_outb(val, (unsigned long)pll_clock->sckcr);
|
||||
val = ctrl_inb((unsigned long)pll_clock->pllcr);
|
||||
writeb(val, pll_clock->sckcr);
|
||||
val = readb(pll_clock->pllcr);
|
||||
val &= ~0x03;
|
||||
val |= pll;
|
||||
ctrl_outb(val, (unsigned long)pll_clock->pllcr);
|
||||
writeb(val, pll_clock->pllcr);
|
||||
spin_unlock_irqrestore(&clklock, flags);
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -84,7 +82,7 @@ static const struct clk_ops pll_ops = {
|
|||
|
||||
static void __init h8s2678_pll_clk_setup(struct device_node *node)
|
||||
{
|
||||
unsigned int num_parents;
|
||||
int num_parents;
|
||||
struct clk *clk;
|
||||
const char *clk_name = node->name;
|
||||
const char *parent_name;
|
||||
|
|
@ -98,11 +96,9 @@ static void __init h8s2678_pll_clk_setup(struct device_node *node)
|
|||
}
|
||||
|
||||
|
||||
pll_clock = kzalloc(sizeof(struct pll_clock), GFP_KERNEL);
|
||||
if (!pll_clock) {
|
||||
pr_err("%s: failed to alloc memory", clk_name);
|
||||
pll_clock = kzalloc(sizeof(*pll_clock), GFP_KERNEL);
|
||||
if (!pll_clock)
|
||||
return;
|
||||
}
|
||||
|
||||
pll_clock->sckcr = of_iomap(node, 0);
|
||||
if (pll_clock->sckcr == NULL) {
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
config COMMON_CLK_HI6220
|
||||
bool "Hi6220 Clock Driver"
|
||||
depends on ARCH_HISI || COMPILE_TEST
|
||||
depends on (ARCH_HISI || COMPILE_TEST) && MAILBOX
|
||||
default ARCH_HISI
|
||||
help
|
||||
Build the Hisilicon Hi6220 clock driver based on the common clock framework.
|
||||
|
|
|
|||
|
|
@ -7,4 +7,4 @@ obj-y += clk.o clkgate-separated.o clkdivider-hi6220.o
|
|||
obj-$(CONFIG_ARCH_HI3xxx) += clk-hi3620.o
|
||||
obj-$(CONFIG_ARCH_HIP04) += clk-hip04.o
|
||||
obj-$(CONFIG_ARCH_HIX5HD2) += clk-hix5hd2.o
|
||||
obj-$(CONFIG_COMMON_CLK_HI6220) += clk-hi6220.o
|
||||
obj-$(CONFIG_COMMON_CLK_HI6220) += clk-hi6220.o clk-hi6220-stub.o
|
||||
|
|
|
|||
|
|
@ -25,13 +25,11 @@
|
|||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/clkdev.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/clk.h>
|
||||
|
||||
#include <dt-bindings/clock/hi3620-clock.h>
|
||||
|
||||
|
|
@ -294,34 +292,29 @@ static unsigned long mmc_clk_recalc_rate(struct clk_hw *hw,
|
|||
}
|
||||
}
|
||||
|
||||
static long mmc_clk_determine_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long min_rate,
|
||||
unsigned long max_rate,
|
||||
unsigned long *best_parent_rate,
|
||||
struct clk_hw **best_parent_p)
|
||||
static int mmc_clk_determine_rate(struct clk_hw *hw,
|
||||
struct clk_rate_request *req)
|
||||
{
|
||||
struct clk_mmc *mclk = to_mmc(hw);
|
||||
unsigned long best = 0;
|
||||
|
||||
if ((rate <= 13000000) && (mclk->id == HI3620_MMC_CIUCLK1)) {
|
||||
rate = 13000000;
|
||||
best = 26000000;
|
||||
} else if (rate <= 26000000) {
|
||||
rate = 25000000;
|
||||
best = 180000000;
|
||||
} else if (rate <= 52000000) {
|
||||
rate = 50000000;
|
||||
best = 360000000;
|
||||
} else if (rate <= 100000000) {
|
||||
rate = 100000000;
|
||||
best = 720000000;
|
||||
if ((req->rate <= 13000000) && (mclk->id == HI3620_MMC_CIUCLK1)) {
|
||||
req->rate = 13000000;
|
||||
req->best_parent_rate = 26000000;
|
||||
} else if (req->rate <= 26000000) {
|
||||
req->rate = 25000000;
|
||||
req->best_parent_rate = 180000000;
|
||||
} else if (req->rate <= 52000000) {
|
||||
req->rate = 50000000;
|
||||
req->best_parent_rate = 360000000;
|
||||
} else if (req->rate <= 100000000) {
|
||||
req->rate = 100000000;
|
||||
req->best_parent_rate = 720000000;
|
||||
} else {
|
||||
/* max is 180M */
|
||||
rate = 180000000;
|
||||
best = 1440000000;
|
||||
req->rate = 180000000;
|
||||
req->best_parent_rate = 1440000000;
|
||||
}
|
||||
*best_parent_rate = best;
|
||||
return rate;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static u32 mmc_clk_delay(u32 val, u32 para, u32 off, u32 len)
|
||||
|
|
|
|||
276
drivers/clk/hisilicon/clk-hi6220-stub.c
Normal file
276
drivers/clk/hisilicon/clk-hi6220-stub.c
Normal file
|
|
@ -0,0 +1,276 @@
|
|||
/*
|
||||
* Hi6220 stub clock driver
|
||||
*
|
||||
* Copyright (c) 2015 Hisilicon Limited.
|
||||
* Copyright (c) 2015 Linaro Limited.
|
||||
*
|
||||
* Author: Leo Yan <leo.yan@linaro.org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/mfd/syscon.h>
|
||||
#include <linux/mailbox_client.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/regmap.h>
|
||||
|
||||
/* Stub clocks id */
|
||||
#define HI6220_STUB_ACPU0 0
|
||||
#define HI6220_STUB_ACPU1 1
|
||||
#define HI6220_STUB_GPU 2
|
||||
#define HI6220_STUB_DDR 5
|
||||
|
||||
/* Mailbox message */
|
||||
#define HI6220_MBOX_MSG_LEN 8
|
||||
|
||||
#define HI6220_MBOX_FREQ 0xA
|
||||
#define HI6220_MBOX_CMD_SET 0x3
|
||||
#define HI6220_MBOX_OBJ_AP 0x0
|
||||
|
||||
/* CPU dynamic frequency scaling */
|
||||
#define ACPU_DFS_FREQ_MAX 0x1724
|
||||
#define ACPU_DFS_CUR_FREQ 0x17CC
|
||||
#define ACPU_DFS_FLAG 0x1B30
|
||||
#define ACPU_DFS_FREQ_REQ 0x1B34
|
||||
#define ACPU_DFS_FREQ_LMT 0x1B38
|
||||
#define ACPU_DFS_LOCK_FLAG 0xAEAEAEAE
|
||||
|
||||
#define to_stub_clk(hw) container_of(hw, struct hi6220_stub_clk, hw)
|
||||
|
||||
struct hi6220_stub_clk {
|
||||
u32 id;
|
||||
|
||||
struct device *dev;
|
||||
struct clk_hw hw;
|
||||
|
||||
struct regmap *dfs_map;
|
||||
struct mbox_client cl;
|
||||
struct mbox_chan *mbox;
|
||||
};
|
||||
|
||||
struct hi6220_mbox_msg {
|
||||
unsigned char type;
|
||||
unsigned char cmd;
|
||||
unsigned char obj;
|
||||
unsigned char src;
|
||||
unsigned char para[4];
|
||||
};
|
||||
|
||||
union hi6220_mbox_data {
|
||||
unsigned int data[HI6220_MBOX_MSG_LEN];
|
||||
struct hi6220_mbox_msg msg;
|
||||
};
|
||||
|
||||
static unsigned int hi6220_acpu_get_freq(struct hi6220_stub_clk *stub_clk)
|
||||
{
|
||||
unsigned int freq;
|
||||
|
||||
regmap_read(stub_clk->dfs_map, ACPU_DFS_CUR_FREQ, &freq);
|
||||
return freq;
|
||||
}
|
||||
|
||||
static int hi6220_acpu_set_freq(struct hi6220_stub_clk *stub_clk,
|
||||
unsigned int freq)
|
||||
{
|
||||
union hi6220_mbox_data data;
|
||||
|
||||
/* set the frequency in sram */
|
||||
regmap_write(stub_clk->dfs_map, ACPU_DFS_FREQ_REQ, freq);
|
||||
|
||||
/* compound mailbox message */
|
||||
data.msg.type = HI6220_MBOX_FREQ;
|
||||
data.msg.cmd = HI6220_MBOX_CMD_SET;
|
||||
data.msg.obj = HI6220_MBOX_OBJ_AP;
|
||||
data.msg.src = HI6220_MBOX_OBJ_AP;
|
||||
|
||||
mbox_send_message(stub_clk->mbox, &data);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int hi6220_acpu_round_freq(struct hi6220_stub_clk *stub_clk,
|
||||
unsigned int freq)
|
||||
{
|
||||
unsigned int limit_flag, limit_freq = UINT_MAX;
|
||||
unsigned int max_freq;
|
||||
|
||||
/* check the constrained frequency */
|
||||
regmap_read(stub_clk->dfs_map, ACPU_DFS_FLAG, &limit_flag);
|
||||
if (limit_flag == ACPU_DFS_LOCK_FLAG)
|
||||
regmap_read(stub_clk->dfs_map, ACPU_DFS_FREQ_LMT, &limit_freq);
|
||||
|
||||
/* check the supported maximum frequency */
|
||||
regmap_read(stub_clk->dfs_map, ACPU_DFS_FREQ_MAX, &max_freq);
|
||||
|
||||
/* calculate the real maximum frequency */
|
||||
max_freq = min(max_freq, limit_freq);
|
||||
|
||||
if (WARN_ON(freq > max_freq))
|
||||
freq = max_freq;
|
||||
|
||||
return freq;
|
||||
}
|
||||
|
||||
static unsigned long hi6220_stub_clk_recalc_rate(struct clk_hw *hw,
|
||||
unsigned long parent_rate)
|
||||
{
|
||||
u32 rate = 0;
|
||||
struct hi6220_stub_clk *stub_clk = to_stub_clk(hw);
|
||||
|
||||
switch (stub_clk->id) {
|
||||
case HI6220_STUB_ACPU0:
|
||||
rate = hi6220_acpu_get_freq(stub_clk);
|
||||
|
||||
/* convert from kHz to Hz */
|
||||
rate *= 1000;
|
||||
break;
|
||||
|
||||
default:
|
||||
dev_err(stub_clk->dev, "%s: un-supported clock id %d\n",
|
||||
__func__, stub_clk->id);
|
||||
break;
|
||||
}
|
||||
|
||||
return rate;
|
||||
}
|
||||
|
||||
static int hi6220_stub_clk_set_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long parent_rate)
|
||||
{
|
||||
struct hi6220_stub_clk *stub_clk = to_stub_clk(hw);
|
||||
unsigned long new_rate = rate / 1000; /* kHz */
|
||||
int ret = 0;
|
||||
|
||||
switch (stub_clk->id) {
|
||||
case HI6220_STUB_ACPU0:
|
||||
ret = hi6220_acpu_set_freq(stub_clk, new_rate);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
dev_err(stub_clk->dev, "%s: un-supported clock id %d\n",
|
||||
__func__, stub_clk->id);
|
||||
break;
|
||||
}
|
||||
|
||||
pr_debug("%s: set rate=%ldkHz\n", __func__, new_rate);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static long hi6220_stub_clk_round_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long *parent_rate)
|
||||
{
|
||||
struct hi6220_stub_clk *stub_clk = to_stub_clk(hw);
|
||||
unsigned long new_rate = rate / 1000; /* kHz */
|
||||
|
||||
switch (stub_clk->id) {
|
||||
case HI6220_STUB_ACPU0:
|
||||
new_rate = hi6220_acpu_round_freq(stub_clk, new_rate);
|
||||
|
||||
/* convert from kHz to Hz */
|
||||
new_rate *= 1000;
|
||||
break;
|
||||
|
||||
default:
|
||||
dev_err(stub_clk->dev, "%s: un-supported clock id %d\n",
|
||||
__func__, stub_clk->id);
|
||||
break;
|
||||
}
|
||||
|
||||
return new_rate;
|
||||
}
|
||||
|
||||
static const struct clk_ops hi6220_stub_clk_ops = {
|
||||
.recalc_rate = hi6220_stub_clk_recalc_rate,
|
||||
.round_rate = hi6220_stub_clk_round_rate,
|
||||
.set_rate = hi6220_stub_clk_set_rate,
|
||||
};
|
||||
|
||||
static int hi6220_stub_clk_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct clk_init_data init;
|
||||
struct hi6220_stub_clk *stub_clk;
|
||||
struct clk *clk;
|
||||
struct device_node *np = pdev->dev.of_node;
|
||||
int ret;
|
||||
|
||||
stub_clk = devm_kzalloc(dev, sizeof(*stub_clk), GFP_KERNEL);
|
||||
if (!stub_clk)
|
||||
return -ENOMEM;
|
||||
|
||||
stub_clk->dfs_map = syscon_regmap_lookup_by_phandle(np,
|
||||
"hisilicon,hi6220-clk-sram");
|
||||
if (IS_ERR(stub_clk->dfs_map)) {
|
||||
dev_err(dev, "failed to get sram regmap\n");
|
||||
return PTR_ERR(stub_clk->dfs_map);
|
||||
}
|
||||
|
||||
stub_clk->hw.init = &init;
|
||||
stub_clk->dev = dev;
|
||||
stub_clk->id = HI6220_STUB_ACPU0;
|
||||
|
||||
/* Use mailbox client with blocking mode */
|
||||
stub_clk->cl.dev = dev;
|
||||
stub_clk->cl.tx_done = NULL;
|
||||
stub_clk->cl.tx_block = true;
|
||||
stub_clk->cl.tx_tout = 500;
|
||||
stub_clk->cl.knows_txdone = false;
|
||||
|
||||
/* Allocate mailbox channel */
|
||||
stub_clk->mbox = mbox_request_channel(&stub_clk->cl, 0);
|
||||
if (IS_ERR(stub_clk->mbox)) {
|
||||
dev_err(dev, "failed get mailbox channel\n");
|
||||
return PTR_ERR(stub_clk->mbox);
|
||||
};
|
||||
|
||||
init.name = "acpu0";
|
||||
init.ops = &hi6220_stub_clk_ops;
|
||||
init.num_parents = 0;
|
||||
init.flags = CLK_IS_ROOT;
|
||||
|
||||
clk = devm_clk_register(dev, &stub_clk->hw);
|
||||
if (IS_ERR(clk))
|
||||
return PTR_ERR(clk);
|
||||
|
||||
ret = of_clk_add_provider(np, of_clk_src_simple_get, clk);
|
||||
if (ret) {
|
||||
dev_err(dev, "failed to register OF clock provider\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* initialize buffer to zero */
|
||||
regmap_write(stub_clk->dfs_map, ACPU_DFS_FLAG, 0x0);
|
||||
regmap_write(stub_clk->dfs_map, ACPU_DFS_FREQ_REQ, 0x0);
|
||||
regmap_write(stub_clk->dfs_map, ACPU_DFS_FREQ_LMT, 0x0);
|
||||
|
||||
dev_dbg(dev, "Registered clock '%s'\n", init.name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id hi6220_stub_clk_of_match[] = {
|
||||
{ .compatible = "hisilicon,hi6220-stub-clk", },
|
||||
{}
|
||||
};
|
||||
|
||||
static struct platform_driver hi6220_stub_clk_driver = {
|
||||
.driver = {
|
||||
.name = "hi6220-stub-clk",
|
||||
.of_match_table = hi6220_stub_clk_of_match,
|
||||
},
|
||||
.probe = hi6220_stub_clk_probe,
|
||||
};
|
||||
|
||||
static int __init hi6220_stub_clk_init(void)
|
||||
{
|
||||
return platform_driver_register(&hi6220_stub_clk_driver);
|
||||
}
|
||||
subsys_initcall(hi6220_stub_clk_init);
|
||||
|
|
@ -24,13 +24,11 @@
|
|||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/clkdev.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/clk.h>
|
||||
|
||||
#include <dt-bindings/clock/hip04-clock.h>
|
||||
|
||||
|
|
|
|||
|
|
@ -24,15 +24,14 @@
|
|||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/clkdev.h>
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/clk.h>
|
||||
|
||||
#include "clk.h"
|
||||
|
||||
|
|
@ -45,14 +44,9 @@ struct hisi_clock_data __init *hisi_clk_init(struct device_node *np,
|
|||
struct clk **clk_table;
|
||||
void __iomem *base;
|
||||
|
||||
if (np) {
|
||||
base = of_iomap(np, 0);
|
||||
if (!base) {
|
||||
pr_err("failed to map Hisilicon clock registers\n");
|
||||
goto err;
|
||||
}
|
||||
} else {
|
||||
pr_err("failed to find Hisilicon clock node in DTS\n");
|
||||
base = of_iomap(np, 0);
|
||||
if (!base) {
|
||||
pr_err("%s: failed to map clock registers\n", __func__);
|
||||
goto err;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -25,10 +25,8 @@
|
|||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/clkdev.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/clk.h>
|
||||
|
||||
#include "clk.h"
|
||||
|
||||
|
|
|
|||
|
|
@ -22,5 +22,6 @@ obj-$(CONFIG_SOC_IMX5) += clk-imx51-imx53.o
|
|||
obj-$(CONFIG_SOC_IMX6Q) += clk-imx6q.o
|
||||
obj-$(CONFIG_SOC_IMX6SL) += clk-imx6sl.o
|
||||
obj-$(CONFIG_SOC_IMX6SX) += clk-imx6sx.o
|
||||
obj-$(CONFIG_SOC_IMX6UL) += clk-imx6ul.o
|
||||
obj-$(CONFIG_SOC_IMX7D) += clk-imx7d.o
|
||||
obj-$(CONFIG_SOC_VF610) += clk-vf610.o
|
||||
|
|
|
|||
|
|
@ -15,7 +15,6 @@
|
|||
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include <linux/clk.h>
|
||||
#include <linux/clkdev.h>
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/err.h>
|
||||
|
|
|
|||
|
|
@ -9,7 +9,6 @@
|
|||
* of the License, or (at your option) any later version.
|
||||
*/
|
||||
|
||||
#include <linux/clk.h>
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/clkdev.h>
|
||||
#include <linux/of.h>
|
||||
|
|
|
|||
|
|
@ -147,7 +147,8 @@ int __init mx31_clocks_init(unsigned long fref)
|
|||
clk_register_clkdev(clk[cspi3_gate], NULL, "imx31-cspi.2");
|
||||
clk_register_clkdev(clk[pwm_gate], "pwm", NULL);
|
||||
clk_register_clkdev(clk[wdog_gate], NULL, "imx2-wdt.0");
|
||||
clk_register_clkdev(clk[rtc_gate], NULL, "imx21-rtc");
|
||||
clk_register_clkdev(clk[ckil], "ref", "imx21-rtc");
|
||||
clk_register_clkdev(clk[rtc_gate], "ipg", "imx21-rtc");
|
||||
clk_register_clkdev(clk[epit1_gate], "epit", NULL);
|
||||
clk_register_clkdev(clk[epit2_gate], "epit", NULL);
|
||||
clk_register_clkdev(clk[nfc], NULL, "imx27-nand.0");
|
||||
|
|
|
|||
|
|
@ -66,7 +66,7 @@ static const char *std_sel[] = {"ppll", "arm"};
|
|||
static const char *ipg_per_sel[] = {"ahb_per_div", "arm_per_div"};
|
||||
|
||||
enum mx35_clks {
|
||||
ckih, mpll, ppll, mpll_075, arm, hsp, hsp_div, hsp_sel, ahb, ipg,
|
||||
ckih, ckil, mpll, ppll, mpll_075, arm, hsp, hsp_div, hsp_sel, ahb, ipg,
|
||||
arm_per_div, ahb_per_div, ipg_per, uart_sel, uart_div, esdhc_sel,
|
||||
esdhc1_div, esdhc2_div, esdhc3_div, spdif_sel, spdif_div_pre,
|
||||
spdif_div_post, ssi_sel, ssi1_div_pre, ssi1_div_post, ssi2_div_pre,
|
||||
|
|
@ -107,6 +107,7 @@ int __init mx35_clocks_init(void)
|
|||
}
|
||||
|
||||
clk[ckih] = imx_clk_fixed("ckih", 24000000);
|
||||
clk[ckil] = imx_clk_fixed("ckih", 32768);
|
||||
clk[mpll] = imx_clk_pllv1(IMX_PLLV1_IMX35, "mpll", "ckih", base + MX35_CCM_MPCTL);
|
||||
clk[ppll] = imx_clk_pllv1(IMX_PLLV1_IMX35, "ppll", "ckih", base + MX35_CCM_PPCTL);
|
||||
|
||||
|
|
@ -258,6 +259,9 @@ int __init mx35_clocks_init(void)
|
|||
clk_register_clkdev(clk[ipg], "ipg", "imx21-uart.1");
|
||||
clk_register_clkdev(clk[uart3_gate], "per", "imx21-uart.2");
|
||||
clk_register_clkdev(clk[ipg], "ipg", "imx21-uart.2");
|
||||
/* i.mx35 has the i.mx21 type rtc */
|
||||
clk_register_clkdev(clk[ckil], "ref", "imx21-rtc");
|
||||
clk_register_clkdev(clk[rtc_gate], "ipg", "imx21-rtc");
|
||||
clk_register_clkdev(clk[usb_div], "per", "mxc-ehci.0");
|
||||
clk_register_clkdev(clk[ipg], "ipg", "mxc-ehci.0");
|
||||
clk_register_clkdev(clk[usbotg_gate], "ahb", "mxc-ehci.0");
|
||||
|
|
|
|||
|
|
@ -494,6 +494,10 @@ static void __init imx6q_clocks_init(struct device_node *ccm_node)
|
|||
clk_set_parent(clk[IMX6QDL_CLK_LDB_DI1_SEL], clk[IMX6QDL_CLK_PLL5_VIDEO_DIV]);
|
||||
}
|
||||
|
||||
clk_set_rate(clk[IMX6QDL_CLK_PLL3_PFD1_540M], 540000000);
|
||||
if (clk_on_imx6dl())
|
||||
clk_set_parent(clk[IMX6QDL_CLK_IPU1_SEL], clk[IMX6QDL_CLK_PLL3_PFD1_540M]);
|
||||
|
||||
clk_set_parent(clk[IMX6QDL_CLK_IPU1_DI0_PRE_SEL], clk[IMX6QDL_CLK_PLL5_VIDEO_DIV]);
|
||||
clk_set_parent(clk[IMX6QDL_CLK_IPU1_DI1_PRE_SEL], clk[IMX6QDL_CLK_PLL5_VIDEO_DIV]);
|
||||
clk_set_parent(clk[IMX6QDL_CLK_IPU2_DI0_PRE_SEL], clk[IMX6QDL_CLK_PLL5_VIDEO_DIV]);
|
||||
|
|
|
|||
432
drivers/clk/imx/clk-imx6ul.c
Normal file
432
drivers/clk/imx/clk-imx6ul.c
Normal file
|
|
@ -0,0 +1,432 @@
|
|||
/*
|
||||
* Copyright (C) 2015 Freescale Semiconductor, Inc.
|
||||
*
|
||||
* The code contained herein is licensed under the GNU General Public
|
||||
* License. You may obtain a copy of the GNU General Public License
|
||||
* Version 2 or later at the following locations:
|
||||
*
|
||||
* http://www.opensource.org/licenses/gpl-license.html
|
||||
* http://www.gnu.org/copyleft/gpl.html
|
||||
*/
|
||||
|
||||
#include <dt-bindings/clock/imx6ul-clock.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/clkdev.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/of_irq.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
#include "clk.h"
|
||||
|
||||
#define BM_CCM_CCDR_MMDC_CH0_MASK (0x2 << 16)
|
||||
#define CCDR 0x4
|
||||
|
||||
static const char *pll_bypass_src_sels[] = { "osc", "dummy", };
|
||||
static const char *pll1_bypass_sels[] = { "pll1", "pll1_bypass_src", };
|
||||
static const char *pll2_bypass_sels[] = { "pll2", "pll2_bypass_src", };
|
||||
static const char *pll3_bypass_sels[] = { "pll3", "pll3_bypass_src", };
|
||||
static const char *pll4_bypass_sels[] = { "pll4", "pll4_bypass_src", };
|
||||
static const char *pll5_bypass_sels[] = { "pll5", "pll5_bypass_src", };
|
||||
static const char *pll6_bypass_sels[] = { "pll6", "pll6_bypass_src", };
|
||||
static const char *pll7_bypass_sels[] = { "pll7", "pll7_bypass_src", };
|
||||
static const char *ca7_secondary_sels[] = { "pll2_pfd2_396m", "pll2_bus", };
|
||||
static const char *step_sels[] = { "osc", "ca7_secondary_sel", };
|
||||
static const char *pll1_sw_sels[] = { "pll1_sys", "step", };
|
||||
static const char *axi_alt_sels[] = { "pll2_pfd2_396m", "pll3_pfd1_540m", };
|
||||
static const char *axi_sels[] = {"periph", "axi_alt_sel", };
|
||||
static const char *periph_pre_sels[] = { "pll2_bus", "pll2_pfd2_396m", "pll2_pfd0_352m", "pll2_198m", };
|
||||
static const char *periph2_pre_sels[] = { "pll2_bus", "pll2_pfd2_396m", "pll2_pfd0_352m", "pll4_audio_div", };
|
||||
static const char *periph_clk2_sels[] = { "pll3_usb_otg", "osc", "osc", };
|
||||
static const char *periph2_clk2_sels[] = { "pll3_usb_otg", "osc", };
|
||||
static const char *periph_sels[] = { "periph_pre", "periph_clk2", };
|
||||
static const char *periph2_sels[] = { "periph2_pre", "periph2_clk2", };
|
||||
static const char *usdhc_sels[] = { "pll2_pfd2_396m", "pll2_pfd0_352m", };
|
||||
static const char *bch_sels[] = { "pll2_pfd2_396m", "pll2_pfd0_352m", };
|
||||
static const char *gpmi_sels[] = { "pll2_pfd2_396m", "pll2_pfd0_352m", };
|
||||
static const char *eim_slow_sels[] = { "axi", "pll3_usb_otg", "pll2_pfd2_396m", "pll3_pfd0_720m", };
|
||||
static const char *spdif_sels[] = { "pll4_audio_div", "pll3_pfd2_508m", "pll5_video_div", "pll3_usb_otg", };
|
||||
static const char *sai_sels[] = { "pll3_pfd2_508m", "pll5_video_div", "pll4_audio_div", };
|
||||
static const char *lcdif_pre_sels[] = { "pll2_bus", "pll3_pfd3_454m", "pll5_video_div", "pll2_pfd0_352m", "pll2_pfd1_594m", "pll3_pfd1_540m", };
|
||||
static const char *sim_pre_sels[] = { "pll2_bus", "pll3_usb_otg", "pll5_video_div", "pll2_pfd0_352m", "pll2_pfd2_396m", "pll3_pfd2_508m", };
|
||||
static const char *ldb_di0_sels[] = { "pll5_video_div", "pll2_pfd0_352m", "pll2_pfd2_396m", "pll2_pfd3_594m", "pll2_pfd1_594m", "pll3_pfd3_454m", };
|
||||
static const char *ldb_di0_div_sels[] = { "ldb_di0_div_3_5", "ldb_di0_div_7", };
|
||||
static const char *ldb_di1_div_sels[] = { "ldb_di1_div_3_5", "ldb_di1_div_7", };
|
||||
static const char *qspi1_sels[] = { "pll3_usb_otg", "pll2_pfd0_352m", "pll2_pfd2_396m", "pll2_bus", "pll3_pfd3_454m", "pll3_pfd2_508m", };
|
||||
static const char *enfc_sels[] = { "pll2_pfd0_352m", "pll2_bus", "pll3_usb_otg", "pll2_pfd2_396m", "pll3_pfd3_454m", "dummy", "dummy", "dummy", };
|
||||
static const char *can_sels[] = { "pll3_60m", "osc", "pll3_80m", "dummy", };
|
||||
static const char *ecspi_sels[] = { "pll3_60m", "osc", };
|
||||
static const char *uart_sels[] = { "pll3_80m", "osc", };
|
||||
static const char *perclk_sels[] = { "ipg", "osc", };
|
||||
static const char *lcdif_sels[] = { "lcdif_podf", "ipp_di0", "ipp_di1", "ldb_di0", "ldb_di1", };
|
||||
static const char *csi_sels[] = { "osc", "pll2_pfd2_396m", "pll3_120m", "pll3_pfd1_540m", };
|
||||
static const char *sim_sels[] = { "sim_podf", "ipp_di0", "ipp_di1", "ldb_di0", "ldb_di1", };
|
||||
|
||||
static struct clk *clks[IMX6UL_CLK_END];
|
||||
static struct clk_onecell_data clk_data;
|
||||
|
||||
static int const clks_init_on[] __initconst = {
|
||||
IMX6UL_CLK_AIPSTZ1, IMX6UL_CLK_AIPSTZ2, IMX6UL_CLK_AIPSTZ3,
|
||||
IMX6UL_CLK_AXI, IMX6UL_CLK_ARM, IMX6UL_CLK_ROM,
|
||||
IMX6UL_CLK_MMDC_P0_FAST, IMX6UL_CLK_MMDC_P0_IPG,
|
||||
};
|
||||
|
||||
static struct clk_div_table clk_enet_ref_table[] = {
|
||||
{ .val = 0, .div = 20, },
|
||||
{ .val = 1, .div = 10, },
|
||||
{ .val = 2, .div = 5, },
|
||||
{ .val = 3, .div = 4, },
|
||||
{ }
|
||||
};
|
||||
|
||||
static struct clk_div_table post_div_table[] = {
|
||||
{ .val = 2, .div = 1, },
|
||||
{ .val = 1, .div = 2, },
|
||||
{ .val = 0, .div = 4, },
|
||||
{ }
|
||||
};
|
||||
|
||||
static struct clk_div_table video_div_table[] = {
|
||||
{ .val = 0, .div = 1, },
|
||||
{ .val = 1, .div = 2, },
|
||||
{ .val = 2, .div = 1, },
|
||||
{ .val = 3, .div = 4, },
|
||||
{ }
|
||||
};
|
||||
|
||||
static u32 share_count_asrc;
|
||||
static u32 share_count_audio;
|
||||
static u32 share_count_sai1;
|
||||
static u32 share_count_sai2;
|
||||
static u32 share_count_sai3;
|
||||
|
||||
static void __init imx6ul_clocks_init(struct device_node *ccm_node)
|
||||
{
|
||||
struct device_node *np;
|
||||
void __iomem *base;
|
||||
int i;
|
||||
|
||||
clks[IMX6UL_CLK_DUMMY] = imx_clk_fixed("dummy", 0);
|
||||
|
||||
clks[IMX6UL_CLK_CKIL] = of_clk_get_by_name(ccm_node, "ckil");
|
||||
clks[IMX6UL_CLK_OSC] = of_clk_get_by_name(ccm_node, "osc");
|
||||
|
||||
/* ipp_di clock is external input */
|
||||
clks[IMX6UL_CLK_IPP_DI0] = of_clk_get_by_name(ccm_node, "ipp_di0");
|
||||
clks[IMX6UL_CLK_IPP_DI1] = of_clk_get_by_name(ccm_node, "ipp_di1");
|
||||
|
||||
np = of_find_compatible_node(NULL, NULL, "fsl,imx6ul-anatop");
|
||||
base = of_iomap(np, 0);
|
||||
WARN_ON(!base);
|
||||
|
||||
clks[IMX6UL_PLL1_BYPASS_SRC] = imx_clk_mux("pll1_bypass_src", base + 0x00, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
|
||||
clks[IMX6UL_PLL2_BYPASS_SRC] = imx_clk_mux("pll2_bypass_src", base + 0x30, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
|
||||
clks[IMX6UL_PLL3_BYPASS_SRC] = imx_clk_mux("pll3_bypass_src", base + 0x10, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
|
||||
clks[IMX6UL_PLL4_BYPASS_SRC] = imx_clk_mux("pll4_bypass_src", base + 0x70, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
|
||||
clks[IMX6UL_PLL5_BYPASS_SRC] = imx_clk_mux("pll5_bypass_src", base + 0xa0, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
|
||||
clks[IMX6UL_PLL6_BYPASS_SRC] = imx_clk_mux("pll6_bypass_src", base + 0xe0, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
|
||||
clks[IMX6UL_PLL7_BYPASS_SRC] = imx_clk_mux("pll7_bypass_src", base + 0x20, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
|
||||
|
||||
clks[IMX6UL_CLK_PLL1] = imx_clk_pllv3(IMX_PLLV3_SYS, "pll1", "pll1_bypass_src", base + 0x00, 0x7f);
|
||||
clks[IMX6UL_CLK_PLL2] = imx_clk_pllv3(IMX_PLLV3_GENERIC, "pll2", "pll2_bypass_src", base + 0x30, 0x1);
|
||||
clks[IMX6UL_CLK_PLL3] = imx_clk_pllv3(IMX_PLLV3_USB, "pll3", "pll3_bypass_src", base + 0x10, 0x3);
|
||||
clks[IMX6UL_CLK_PLL4] = imx_clk_pllv3(IMX_PLLV3_AV, "pll4", "pll4_bypass_src", base + 0x70, 0x7f);
|
||||
clks[IMX6UL_CLK_PLL5] = imx_clk_pllv3(IMX_PLLV3_AV, "pll5", "pll5_bypass_src", base + 0xa0, 0x7f);
|
||||
clks[IMX6UL_CLK_PLL6] = imx_clk_pllv3(IMX_PLLV3_ENET, "pll6", "pll6_bypass_src", base + 0xe0, 0x3);
|
||||
clks[IMX6UL_CLK_PLL7] = imx_clk_pllv3(IMX_PLLV3_USB, "pll7", "pll7_bypass_src", base + 0x20, 0x3);
|
||||
|
||||
clks[IMX6UL_PLL1_BYPASS] = imx_clk_mux_flags("pll1_bypass", base + 0x00, 16, 1, pll1_bypass_sels, ARRAY_SIZE(pll1_bypass_sels), CLK_SET_RATE_PARENT);
|
||||
clks[IMX6UL_PLL2_BYPASS] = imx_clk_mux_flags("pll2_bypass", base + 0x30, 16, 1, pll2_bypass_sels, ARRAY_SIZE(pll2_bypass_sels), CLK_SET_RATE_PARENT);
|
||||
clks[IMX6UL_PLL3_BYPASS] = imx_clk_mux_flags("pll3_bypass", base + 0x10, 16, 1, pll3_bypass_sels, ARRAY_SIZE(pll3_bypass_sels), CLK_SET_RATE_PARENT);
|
||||
clks[IMX6UL_PLL4_BYPASS] = imx_clk_mux_flags("pll4_bypass", base + 0x70, 16, 1, pll4_bypass_sels, ARRAY_SIZE(pll4_bypass_sels), CLK_SET_RATE_PARENT);
|
||||
clks[IMX6UL_PLL5_BYPASS] = imx_clk_mux_flags("pll5_bypass", base + 0xa0, 16, 1, pll5_bypass_sels, ARRAY_SIZE(pll5_bypass_sels), CLK_SET_RATE_PARENT);
|
||||
clks[IMX6UL_PLL6_BYPASS] = imx_clk_mux_flags("pll6_bypass", base + 0xe0, 16, 1, pll6_bypass_sels, ARRAY_SIZE(pll6_bypass_sels), CLK_SET_RATE_PARENT);
|
||||
clks[IMX6UL_PLL7_BYPASS] = imx_clk_mux_flags("pll7_bypass", base + 0x20, 16, 1, pll7_bypass_sels, ARRAY_SIZE(pll7_bypass_sels), CLK_SET_RATE_PARENT);
|
||||
clks[IMX6UL_CLK_CSI_SEL] = imx_clk_mux_flags("csi_sel", base + 0x3c, 9, 2, csi_sels, ARRAY_SIZE(csi_sels), CLK_SET_RATE_PARENT);
|
||||
|
||||
/* Do not bypass PLLs initially */
|
||||
clk_set_parent(clks[IMX6UL_PLL1_BYPASS], clks[IMX6UL_CLK_PLL1]);
|
||||
clk_set_parent(clks[IMX6UL_PLL2_BYPASS], clks[IMX6UL_CLK_PLL2]);
|
||||
clk_set_parent(clks[IMX6UL_PLL3_BYPASS], clks[IMX6UL_CLK_PLL3]);
|
||||
clk_set_parent(clks[IMX6UL_PLL4_BYPASS], clks[IMX6UL_CLK_PLL4]);
|
||||
clk_set_parent(clks[IMX6UL_PLL5_BYPASS], clks[IMX6UL_CLK_PLL5]);
|
||||
clk_set_parent(clks[IMX6UL_PLL6_BYPASS], clks[IMX6UL_CLK_PLL6]);
|
||||
clk_set_parent(clks[IMX6UL_PLL7_BYPASS], clks[IMX6UL_CLK_PLL7]);
|
||||
|
||||
clks[IMX6UL_CLK_PLL1_SYS] = imx_clk_fixed_factor("pll1_sys", "pll1_bypass", 1, 1);
|
||||
clks[IMX6UL_CLK_PLL2_BUS] = imx_clk_gate("pll2_bus", "pll2_bypass", base + 0x30, 13);
|
||||
clks[IMX6UL_CLK_PLL3_USB_OTG] = imx_clk_gate("pll3_usb_otg", "pll3_bypass", base + 0x10, 13);
|
||||
clks[IMX6UL_CLK_PLL4_AUDIO] = imx_clk_gate("pll4_audio", "pll4_bypass", base + 0x70, 13);
|
||||
clks[IMX6UL_CLK_PLL5_VIDEO] = imx_clk_gate("pll5_video", "pll5_bypass", base + 0xa0, 13);
|
||||
clks[IMX6UL_CLK_PLL6_ENET] = imx_clk_gate("pll6_enet", "pll6_bypass", base + 0xe0, 13);
|
||||
clks[IMX6UL_CLK_PLL7_USB_HOST] = imx_clk_gate("pll7_usb_host", "pll7_bypass", base + 0x20, 13);
|
||||
|
||||
/*
|
||||
* Bit 20 is the reserved and read-only bit, we do this only for:
|
||||
* - Do nothing for usbphy clk_enable/disable
|
||||
* - Keep refcount when do usbphy clk_enable/disable, in that case,
|
||||
* the clk framework many need to enable/disable usbphy's parent
|
||||
*/
|
||||
clks[IMX6UL_CLK_USBPHY1] = imx_clk_gate("usbphy1", "pll3_usb_otg", base + 0x10, 20);
|
||||
clks[IMX6UL_CLK_USBPHY2] = imx_clk_gate("usbphy2", "pll7_usb_host", base + 0x20, 20);
|
||||
|
||||
/*
|
||||
* usbphy*_gate needs to be on after system boots up, and software
|
||||
* never needs to control it anymore.
|
||||
*/
|
||||
clks[IMX6UL_CLK_USBPHY1_GATE] = imx_clk_gate("usbphy1_gate", "dummy", base + 0x10, 6);
|
||||
clks[IMX6UL_CLK_USBPHY2_GATE] = imx_clk_gate("usbphy2_gate", "dummy", base + 0x20, 6);
|
||||
|
||||
/* name parent_name reg idx */
|
||||
clks[IMX6UL_CLK_PLL2_PFD0] = imx_clk_pfd("pll2_pfd0_352m", "pll2_bus", base + 0x100, 0);
|
||||
clks[IMX6UL_CLK_PLL2_PFD1] = imx_clk_pfd("pll2_pfd1_594m", "pll2_bus", base + 0x100, 1);
|
||||
clks[IMX6UL_CLK_PLL2_PFD2] = imx_clk_pfd("pll2_pfd2_396m", "pll2_bus", base + 0x100, 2);
|
||||
clks[IMX6UL_CLK_PLL2_PFD3] = imx_clk_pfd("pll2_pfd3_594m", "pll2_bus", base + 0x100, 3);
|
||||
clks[IMX6UL_CLK_PLL3_PFD0] = imx_clk_pfd("pll3_pfd0_720m", "pll3_usb_otg", base + 0xf0, 0);
|
||||
clks[IMX6UL_CLK_PLL3_PFD1] = imx_clk_pfd("pll3_pfd1_540m", "pll3_usb_otg", base + 0xf0, 1);
|
||||
clks[IMX6UL_CLK_PLL3_PFD2] = imx_clk_pfd("pll3_pfd2_508m", "pll3_usb_otg", base + 0xf0, 2);
|
||||
clks[IMX6UL_CLK_PLL3_PFD3] = imx_clk_pfd("pll3_pfd3_454m", "pll3_usb_otg", base + 0xf0, 3);
|
||||
|
||||
clks[IMX6UL_CLK_ENET_REF] = clk_register_divider_table(NULL, "enet_ref", "pll6_enet", 0,
|
||||
base + 0xe0, 0, 2, 0, clk_enet_ref_table, &imx_ccm_lock);
|
||||
clks[IMX6UL_CLK_ENET2_REF] = clk_register_divider_table(NULL, "enet2_ref", "pll6_enet", 0,
|
||||
base + 0xe0, 2, 2, 0, clk_enet_ref_table, &imx_ccm_lock);
|
||||
|
||||
clks[IMX6UL_CLK_ENET2_REF_125M] = imx_clk_gate("enet_ref_125m", "enet2_ref", base + 0xe0, 20);
|
||||
clks[IMX6UL_CLK_ENET_PTP_REF] = imx_clk_fixed_factor("enet_ptp_ref", "pll6_enet", 1, 20);
|
||||
clks[IMX6UL_CLK_ENET_PTP] = imx_clk_gate("enet_ptp", "enet_ptp_ref", base + 0xe0, 21);
|
||||
|
||||
clks[IMX6UL_CLK_PLL4_POST_DIV] = clk_register_divider_table(NULL, "pll4_post_div", "pll4_audio",
|
||||
CLK_SET_RATE_PARENT | CLK_SET_RATE_GATE, base + 0x70, 19, 2, 0, post_div_table, &imx_ccm_lock);
|
||||
clks[IMX6UL_CLK_PLL4_AUDIO_DIV] = clk_register_divider(NULL, "pll4_audio_div", "pll4_post_div",
|
||||
CLK_SET_RATE_PARENT | CLK_SET_RATE_GATE, base + 0x170, 15, 1, 0, &imx_ccm_lock);
|
||||
clks[IMX6UL_CLK_PLL5_POST_DIV] = clk_register_divider_table(NULL, "pll5_post_div", "pll5_video",
|
||||
CLK_SET_RATE_PARENT | CLK_SET_RATE_GATE, base + 0xa0, 19, 2, 0, post_div_table, &imx_ccm_lock);
|
||||
clks[IMX6UL_CLK_PLL5_VIDEO_DIV] = clk_register_divider_table(NULL, "pll5_video_div", "pll5_post_div",
|
||||
CLK_SET_RATE_PARENT | CLK_SET_RATE_GATE, base + 0x170, 30, 2, 0, video_div_table, &imx_ccm_lock);
|
||||
|
||||
/* name parent_name mult div */
|
||||
clks[IMX6UL_CLK_PLL2_198M] = imx_clk_fixed_factor("pll2_198m", "pll2_pfd2_396m", 1, 2);
|
||||
clks[IMX6UL_CLK_PLL3_80M] = imx_clk_fixed_factor("pll3_80m", "pll3_usb_otg", 1, 6);
|
||||
clks[IMX6UL_CLK_PLL3_60M] = imx_clk_fixed_factor("pll3_60m", "pll3_usb_otg", 1, 8);
|
||||
clks[IMX6UL_CLK_GPT_3M] = imx_clk_fixed_factor("gpt_3m", "osc", 1, 8);
|
||||
|
||||
np = ccm_node;
|
||||
base = of_iomap(np, 0);
|
||||
WARN_ON(!base);
|
||||
|
||||
clks[IMX6UL_CA7_SECONDARY_SEL] = imx_clk_mux("ca7_secondary_sel", base + 0xc, 3, 1, ca7_secondary_sels, ARRAY_SIZE(ca7_secondary_sels));
|
||||
clks[IMX6UL_CLK_STEP] = imx_clk_mux("step", base + 0x0c, 8, 1, step_sels, ARRAY_SIZE(step_sels));
|
||||
clks[IMX6UL_CLK_PLL1_SW] = imx_clk_mux_flags("pll1_sw", base + 0x0c, 2, 1, pll1_sw_sels, ARRAY_SIZE(pll1_sw_sels), 0);
|
||||
clks[IMX6UL_CLK_AXI_ALT_SEL] = imx_clk_mux("axi_alt_sel", base + 0x14, 7, 1, axi_alt_sels, ARRAY_SIZE(axi_alt_sels));
|
||||
clks[IMX6UL_CLK_AXI_SEL] = imx_clk_mux_flags("axi_sel", base + 0x14, 6, 1, axi_sels, ARRAY_SIZE(axi_sels), 0);
|
||||
clks[IMX6UL_CLK_PERIPH_PRE] = imx_clk_mux("periph_pre", base + 0x18, 18, 2, periph_pre_sels, ARRAY_SIZE(periph_pre_sels));
|
||||
clks[IMX6UL_CLK_PERIPH2_PRE] = imx_clk_mux("periph2_pre", base + 0x18, 21, 2, periph2_pre_sels, ARRAY_SIZE(periph2_pre_sels));
|
||||
clks[IMX6UL_CLK_PERIPH_CLK2_SEL] = imx_clk_mux("periph_clk2_sel", base + 0x18, 12, 2, periph_clk2_sels, ARRAY_SIZE(periph_clk2_sels));
|
||||
clks[IMX6UL_CLK_PERIPH2_CLK2_SEL] = imx_clk_mux("periph2_clk2_sel", base + 0x18, 20, 1, periph2_clk2_sels, ARRAY_SIZE(periph2_clk2_sels));
|
||||
clks[IMX6UL_CLK_EIM_SLOW_SEL] = imx_clk_mux("eim_slow_sel", base + 0x1c, 29, 2, eim_slow_sels, ARRAY_SIZE(eim_slow_sels));
|
||||
clks[IMX6UL_CLK_GPMI_SEL] = imx_clk_mux("gpmi_sel", base + 0x1c, 19, 1, gpmi_sels, ARRAY_SIZE(gpmi_sels));
|
||||
clks[IMX6UL_CLK_BCH_SEL] = imx_clk_mux("bch_sel", base + 0x1c, 18, 1, bch_sels, ARRAY_SIZE(bch_sels));
|
||||
clks[IMX6UL_CLK_USDHC2_SEL] = imx_clk_mux("usdhc2_sel", base + 0x1c, 17, 1, usdhc_sels, ARRAY_SIZE(usdhc_sels));
|
||||
clks[IMX6UL_CLK_USDHC1_SEL] = imx_clk_mux("usdhc1_sel", base + 0x1c, 16, 1, usdhc_sels, ARRAY_SIZE(usdhc_sels));
|
||||
clks[IMX6UL_CLK_SAI3_SEL] = imx_clk_mux("sai3_sel", base + 0x1c, 14, 2, sai_sels, ARRAY_SIZE(sai_sels));
|
||||
clks[IMX6UL_CLK_SAI2_SEL] = imx_clk_mux("sai2_sel", base + 0x1c, 12, 2, sai_sels, ARRAY_SIZE(sai_sels));
|
||||
clks[IMX6UL_CLK_SAI1_SEL] = imx_clk_mux("sai1_sel", base + 0x1c, 10, 2, sai_sels, ARRAY_SIZE(sai_sels));
|
||||
clks[IMX6UL_CLK_QSPI1_SEL] = imx_clk_mux("qspi1_sel", base + 0x1c, 7, 3, qspi1_sels, ARRAY_SIZE(qspi1_sels));
|
||||
clks[IMX6UL_CLK_PERCLK_SEL] = imx_clk_mux("perclk_sel", base + 0x1c, 6, 1, perclk_sels, ARRAY_SIZE(perclk_sels));
|
||||
clks[IMX6UL_CLK_CAN_SEL] = imx_clk_mux("can_sel", base + 0x20, 8, 2, can_sels, ARRAY_SIZE(can_sels));
|
||||
clks[IMX6UL_CLK_UART_SEL] = imx_clk_mux("uart_sel", base + 0x24, 6, 1, uart_sels, ARRAY_SIZE(uart_sels));
|
||||
clks[IMX6UL_CLK_ENFC_SEL] = imx_clk_mux("enfc_sel", base + 0x2c, 15, 3, enfc_sels, ARRAY_SIZE(enfc_sels));
|
||||
clks[IMX6UL_CLK_LDB_DI0_SEL] = imx_clk_mux("ldb_di0_sel", base + 0x2c, 9, 3, ldb_di0_sels, ARRAY_SIZE(ldb_di0_sels));
|
||||
clks[IMX6UL_CLK_SPDIF_SEL] = imx_clk_mux("spdif_sel", base + 0x30, 20, 2, spdif_sels, ARRAY_SIZE(spdif_sels));
|
||||
clks[IMX6UL_CLK_SIM_PRE_SEL] = imx_clk_mux("sim_pre_sel", base + 0x34, 15, 3, sim_pre_sels, ARRAY_SIZE(sim_pre_sels));
|
||||
clks[IMX6UL_CLK_SIM_SEL] = imx_clk_mux("sim_sel", base + 0x34, 9, 3, sim_sels, ARRAY_SIZE(sim_sels));
|
||||
clks[IMX6UL_CLK_ECSPI_SEL] = imx_clk_mux("ecspi_sel", base + 0x38, 18, 1, ecspi_sels, ARRAY_SIZE(ecspi_sels));
|
||||
clks[IMX6UL_CLK_LCDIF_PRE_SEL] = imx_clk_mux("lcdif_pre_sel", base + 0x38, 15, 3, lcdif_pre_sels, ARRAY_SIZE(lcdif_pre_sels));
|
||||
clks[IMX6UL_CLK_LCDIF_SEL] = imx_clk_mux("lcdif_sel", base + 0x38, 9, 3, lcdif_sels, ARRAY_SIZE(lcdif_sels));
|
||||
|
||||
clks[IMX6UL_CLK_LDB_DI0_DIV_SEL] = imx_clk_mux("ldb_di0", base + 0x20, 10, 1, ldb_di0_div_sels, ARRAY_SIZE(ldb_di0_div_sels));
|
||||
clks[IMX6UL_CLK_LDB_DI1_DIV_SEL] = imx_clk_mux("ldb_di1", base + 0x20, 11, 1, ldb_di1_div_sels, ARRAY_SIZE(ldb_di1_div_sels));
|
||||
|
||||
clks[IMX6UL_CLK_LDB_DI0_DIV_3_5] = imx_clk_fixed_factor("ldb_di0_div_3_5", "ldb_di0_sel", 2, 7);
|
||||
clks[IMX6UL_CLK_LDB_DI0_DIV_7] = imx_clk_fixed_factor("ldb_di0_div_7", "ldb_di0_sel", 1, 7);
|
||||
clks[IMX6UL_CLK_LDB_DI1_DIV_3_5] = imx_clk_fixed_factor("ldb_di1_div_3_5", "qspi1_sel", 2, 7);
|
||||
clks[IMX6UL_CLK_LDB_DI1_DIV_7] = imx_clk_fixed_factor("ldb_di1_div_7", "qspi1_sel", 1, 7);
|
||||
|
||||
clks[IMX6UL_CLK_PERIPH] = imx_clk_busy_mux("periph", base + 0x14, 25, 1, base + 0x48, 5, periph_sels, ARRAY_SIZE(periph_sels));
|
||||
clks[IMX6UL_CLK_PERIPH2] = imx_clk_busy_mux("periph2", base + 0x14, 26, 1, base + 0x48, 3, periph2_sels, ARRAY_SIZE(periph2_sels));
|
||||
|
||||
clks[IMX6UL_CLK_PERIPH_CLK2] = imx_clk_divider("periph_clk2", "periph_clk2_sel", base + 0x14, 27, 3);
|
||||
clks[IMX6UL_CLK_PERIPH2_CLK2] = imx_clk_divider("periph2_clk2", "periph2_clk2_sel", base + 0x14, 0, 3);
|
||||
clks[IMX6UL_CLK_IPG] = imx_clk_divider("ipg", "ahb", base + 0x14, 8, 2);
|
||||
clks[IMX6UL_CLK_LCDIF_PODF] = imx_clk_divider("lcdif_podf", "lcdif_pred", base + 0x18, 23, 3);
|
||||
clks[IMX6UL_CLK_QSPI1_PDOF] = imx_clk_divider("qspi1_podf", "qspi1_sel", base + 0x1c, 26, 3);
|
||||
clks[IMX6UL_CLK_EIM_SLOW_PODF] = imx_clk_divider("eim_slow_podf", "eim_slow_sel", base + 0x1c, 23, 3);
|
||||
clks[IMX6UL_CLK_PERCLK] = imx_clk_divider("perclk", "perclk_sel", base + 0x1c, 0, 6);
|
||||
clks[IMX6UL_CLK_CAN_PODF] = imx_clk_divider("can_podf", "can_sel", base + 0x20, 2, 6);
|
||||
clks[IMX6UL_CLK_GPMI_PODF] = imx_clk_divider("gpmi_podf", "gpmi_sel", base + 0x24, 22, 3);
|
||||
clks[IMX6UL_CLK_BCH_PODF] = imx_clk_divider("bch_podf", "bch_sel", base + 0x24, 19, 3);
|
||||
clks[IMX6UL_CLK_USDHC2_PODF] = imx_clk_divider("usdhc2_podf", "usdhc2_sel", base + 0x24, 16, 3);
|
||||
clks[IMX6UL_CLK_USDHC1_PODF] = imx_clk_divider("usdhc1_podf", "usdhc1_sel", base + 0x24, 11, 3);
|
||||
clks[IMX6UL_CLK_UART_PODF] = imx_clk_divider("uart_podf", "uart_sel", base + 0x24, 0, 6);
|
||||
clks[IMX6UL_CLK_SAI3_PRED] = imx_clk_divider("sai3_pred", "sai3_sel", base + 0x28, 22, 3);
|
||||
clks[IMX6UL_CLK_SAI3_PODF] = imx_clk_divider("sai3_podf", "sai3_pred", base + 0x28, 16, 6);
|
||||
clks[IMX6UL_CLK_SAI1_PRED] = imx_clk_divider("sai1_pred", "sai1_sel", base + 0x28, 6, 3);
|
||||
clks[IMX6UL_CLK_SAI1_PODF] = imx_clk_divider("sai1_podf", "sai1_pred", base + 0x28, 0, 6);
|
||||
clks[IMX6UL_CLK_ENFC_PRED] = imx_clk_divider("enfc_pred", "enfc_sel", base + 0x2c, 18, 3);
|
||||
clks[IMX6UL_CLK_ENFC_PODF] = imx_clk_divider("enfc_podf", "enfc_pred", base + 0x2c, 21, 6);
|
||||
clks[IMX6UL_CLK_SAI2_PRED] = imx_clk_divider("sai2_pred", "sai2_sel", base + 0x2c, 6, 3);
|
||||
clks[IMX6UL_CLK_SAI2_PODF] = imx_clk_divider("sai2_podf", "sai2_pred", base + 0x2c, 0, 6);
|
||||
clks[IMX6UL_CLK_SPDIF_PRED] = imx_clk_divider("spdif_pred", "spdif_sel", base + 0x30, 25, 3);
|
||||
clks[IMX6UL_CLK_SPDIF_PODF] = imx_clk_divider("spdif_podf", "spdif_pred", base + 0x30, 22, 3);
|
||||
clks[IMX6UL_CLK_SIM_PODF] = imx_clk_divider("sim_podf", "sim_pre_sel", base + 0x34, 12, 3);
|
||||
clks[IMX6UL_CLK_ECSPI_PODF] = imx_clk_divider("ecspi_podf", "ecspi_sel", base + 0x38, 19, 6);
|
||||
clks[IMX6UL_CLK_LCDIF_PRED] = imx_clk_divider("lcdif_pred", "lcdif_pre_sel", base + 0x38, 12, 3);
|
||||
clks[IMX6UL_CLK_CSI_PODF] = imx_clk_divider("csi_podf", "csi_sel", base + 0x3c, 11, 3);
|
||||
|
||||
clks[IMX6UL_CLK_ARM] = imx_clk_busy_divider("arm", "pll1_sw", base + 0x10, 0, 3, base + 0x48, 16);
|
||||
clks[IMX6UL_CLK_MMDC_PODF] = imx_clk_busy_divider("mmdc_podf", "periph2", base + 0x14, 3, 3, base + 0x48, 2);
|
||||
clks[IMX6UL_CLK_AXI_PODF] = imx_clk_busy_divider("axi_podf", "axi_sel", base + 0x14, 16, 3, base + 0x48, 0);
|
||||
clks[IMX6UL_CLK_AHB] = imx_clk_busy_divider("ahb", "periph", base + 0x14, 10, 3, base + 0x48, 1);
|
||||
|
||||
/* CCGR0 */
|
||||
clks[IMX6UL_CLK_AIPSTZ1] = imx_clk_gate2("aips_tz1", "ahb", base + 0x68, 0);
|
||||
clks[IMX6UL_CLK_AIPSTZ2] = imx_clk_gate2("aips_tz2", "ahb", base + 0x68, 2);
|
||||
clks[IMX6UL_CLK_APBHDMA] = imx_clk_gate2("apbh_dma", "bch_podf", base + 0x68, 4);
|
||||
clks[IMX6UL_CLK_ASRC_IPG] = imx_clk_gate2_shared("asrc_ipg", "ahb", base + 0x68, 6, &share_count_asrc);
|
||||
clks[IMX6UL_CLK_ASRC_MEM] = imx_clk_gate2_shared("asrc_mem", "ahb", base + 0x68, 6, &share_count_asrc);
|
||||
clks[IMX6UL_CLK_CAAM_MEM] = imx_clk_gate2("caam_mem", "ahb", base + 0x68, 8);
|
||||
clks[IMX6UL_CLK_CAAM_ACLK] = imx_clk_gate2("caam_aclk", "ahb", base + 0x68, 10);
|
||||
clks[IMX6UL_CLK_CAAM_IPG] = imx_clk_gate2("caam_ipg", "ipg", base + 0x68, 12);
|
||||
clks[IMX6UL_CLK_CAN1_IPG] = imx_clk_gate2("can1_ipg", "ipg", base + 0x68, 14);
|
||||
clks[IMX6UL_CLK_CAN1_SERIAL] = imx_clk_gate2("can1_serial", "can_podf", base + 0x68, 16);
|
||||
clks[IMX6UL_CLK_CAN2_IPG] = imx_clk_gate2("can2_ipg", "ipg", base + 0x68, 18);
|
||||
clks[IMX6UL_CLK_CAN2_SERIAL] = imx_clk_gate2("can2_serial", "can_podf", base + 0x68, 20);
|
||||
clks[IMX6UL_CLK_GPT2_BUS] = imx_clk_gate2("gpt_bus", "perclk", base + 0x68, 24);
|
||||
clks[IMX6UL_CLK_GPT2_SERIAL] = imx_clk_gate2("gpt_serial", "perclk", base + 0x68, 26);
|
||||
clks[IMX6UL_CLK_UART2_IPG] = imx_clk_gate2("uart2_ipg", "ipg", base + 0x68, 28);
|
||||
clks[IMX6UL_CLK_UART2_SERIAL] = imx_clk_gate2("uart2_serial", "uart_podf", base + 0x68, 28);
|
||||
clks[IMX6UL_CLK_AIPSTZ3] = imx_clk_gate2("aips_tz3", "ahb", base + 0x68, 30);
|
||||
|
||||
/* CCGR1 */
|
||||
clks[IMX6UL_CLK_ECSPI1] = imx_clk_gate2("ecspi1", "ecspi_podf", base + 0x6c, 0);
|
||||
clks[IMX6UL_CLK_ECSPI2] = imx_clk_gate2("ecspi2", "ecspi_podf", base + 0x6c, 2);
|
||||
clks[IMX6UL_CLK_ECSPI3] = imx_clk_gate2("ecspi3", "ecspi_podf", base + 0x6c, 4);
|
||||
clks[IMX6UL_CLK_ECSPI4] = imx_clk_gate2("ecspi4", "ecspi_podf", base + 0x6c, 6);
|
||||
clks[IMX6UL_CLK_ADC2] = imx_clk_gate2("adc2", "ipg", base + 0x6c, 8);
|
||||
clks[IMX6UL_CLK_UART3_IPG] = imx_clk_gate2("uart3_ipg", "ipg", base + 0x6c, 10);
|
||||
clks[IMX6UL_CLK_UART3_SERIAL] = imx_clk_gate2("uart3_serial", "uart_podf", base + 0x6c, 10);
|
||||
clks[IMX6UL_CLK_EPIT1] = imx_clk_gate2("epit1", "perclk", base + 0x6c, 12);
|
||||
clks[IMX6UL_CLK_EPIT2] = imx_clk_gate2("epit2", "perclk", base + 0x6c, 14);
|
||||
clks[IMX6UL_CLK_ADC1] = imx_clk_gate2("adc1", "ipg", base + 0x6c, 16);
|
||||
clks[IMX6UL_CLK_GPT1_BUS] = imx_clk_gate2("gpt1_bus", "perclk", base + 0x6c, 20);
|
||||
clks[IMX6UL_CLK_GPT1_SERIAL] = imx_clk_gate2("gpt1_serial", "perclk", base + 0x6c, 22);
|
||||
clks[IMX6UL_CLK_UART4_IPG] = imx_clk_gate2("uart4_ipg", "ipg", base + 0x6c, 24);
|
||||
clks[IMX6UL_CLK_UART4_SERIAL] = imx_clk_gate2("uart4_serail", "uart_podf", base + 0x6c, 24);
|
||||
|
||||
/* CCGR2 */
|
||||
clks[IMX6UL_CLK_CSI] = imx_clk_gate2("csi", "csi_podf", base + 0x70, 2);
|
||||
clks[IMX6UL_CLK_I2C1] = imx_clk_gate2("i2c1", "perclk", base + 0x70, 6);
|
||||
clks[IMX6UL_CLK_I2C2] = imx_clk_gate2("i2c2", "perclk", base + 0x70, 8);
|
||||
clks[IMX6UL_CLK_I2C3] = imx_clk_gate2("i2c3", "perclk", base + 0x70, 10);
|
||||
clks[IMX6UL_CLK_OCOTP] = imx_clk_gate2("ocotp", "ipg", base + 0x70, 12);
|
||||
clks[IMX6UL_CLK_IOMUXC] = imx_clk_gate2("iomuxc", "lcdif_podf", base + 0x70, 14);
|
||||
clks[IMX6UL_CLK_LCDIF_APB] = imx_clk_gate2("lcdif_apb", "axi", base + 0x70, 28);
|
||||
clks[IMX6UL_CLK_PXP] = imx_clk_gate2("pxp", "axi", base + 0x70, 30);
|
||||
|
||||
/* CCGR3 */
|
||||
clks[IMX6UL_CLK_UART5_IPG] = imx_clk_gate2("uart5_ipg", "ipg", base + 0x74, 2);
|
||||
clks[IMX6UL_CLK_UART5_SERIAL] = imx_clk_gate2("uart5_serial", "uart_podf", base + 0x74, 2);
|
||||
clks[IMX6UL_CLK_ENET] = imx_clk_gate2("enet", "ipg", base + 0x74, 4);
|
||||
clks[IMX6UL_CLK_ENET_AHB] = imx_clk_gate2("enet_ahb", "ahb", base + 0x74, 4);
|
||||
clks[IMX6UL_CLK_UART6_IPG] = imx_clk_gate2("uart6_ipg", "ipg", base + 0x74, 6);
|
||||
clks[IMX6UL_CLK_UART6_SERIAL] = imx_clk_gate2("uart6_serial", "uart_podf", base + 0x74, 6);
|
||||
clks[IMX6UL_CLK_LCDIF_PIX] = imx_clk_gate2("lcdif_pix", "lcdif_podf", base + 0x74, 10);
|
||||
clks[IMX6UL_CLK_QSPI] = imx_clk_gate2("qspi1", "qspi1_podf", base + 0x74, 14);
|
||||
clks[IMX6UL_CLK_WDOG1] = imx_clk_gate2("wdog1", "ipg", base + 0x74, 16);
|
||||
clks[IMX6UL_CLK_MMDC_P0_FAST] = imx_clk_gate("mmdc_p0_fast", "mmdc_podf", base + 0x74, 20);
|
||||
clks[IMX6UL_CLK_MMDC_P0_IPG] = imx_clk_gate2("mmdc_p0_ipg", "ipg", base + 0x74, 24);
|
||||
clks[IMX6UL_CLK_AXI] = imx_clk_gate("axi", "axi_podf", base + 0x74, 28);
|
||||
|
||||
/* CCGR4 */
|
||||
clks[IMX6UL_CLK_PER_BCH] = imx_clk_gate2("per_bch", "bch_podf", base + 0x78, 12);
|
||||
clks[IMX6UL_CLK_PWM1] = imx_clk_gate2("pwm1", "perclk", base + 0x78, 16);
|
||||
clks[IMX6UL_CLK_PWM2] = imx_clk_gate2("pwm2", "perclk", base + 0x78, 18);
|
||||
clks[IMX6UL_CLK_PWM3] = imx_clk_gate2("pwm3", "perclk", base + 0x78, 20);
|
||||
clks[IMX6UL_CLK_PWM4] = imx_clk_gate2("pwm4", "perclk", base + 0x78, 22);
|
||||
clks[IMX6UL_CLK_GPMI_BCH_APB] = imx_clk_gate2("gpmi_bch_apb", "bch_podf", base + 0x78, 24);
|
||||
clks[IMX6UL_CLK_GPMI_BCH] = imx_clk_gate2("gpmi_bch", "gpmi_podf", base + 0x78, 26);
|
||||
clks[IMX6UL_CLK_GPMI_IO] = imx_clk_gate2("gpmi_io", "enfc_podf", base + 0x78, 28);
|
||||
clks[IMX6UL_CLK_GPMI_APB] = imx_clk_gate2("gpmi_apb", "bch_podf", base + 0x78, 30);
|
||||
|
||||
/* CCGR5 */
|
||||
clks[IMX6UL_CLK_ROM] = imx_clk_gate2("rom", "ahb", base + 0x7c, 0);
|
||||
clks[IMX6UL_CLK_SDMA] = imx_clk_gate2("sdma", "ahb", base + 0x7c, 6);
|
||||
clks[IMX6UL_CLK_WDOG2] = imx_clk_gate2("wdog2", "ipg", base + 0x7c, 10);
|
||||
clks[IMX6UL_CLK_SPBA] = imx_clk_gate2("spba", "ipg", base + 0x7c, 12);
|
||||
clks[IMX6UL_CLK_SPDIF] = imx_clk_gate2_shared("spdif", "spdif_podf", base + 0x7c, 14, &share_count_audio);
|
||||
clks[IMX6UL_CLK_SPDIF_GCLK] = imx_clk_gate2_shared("spdif_gclk", "ipg", base + 0x7c, 14, &share_count_audio);
|
||||
clks[IMX6UL_CLK_SAI3] = imx_clk_gate2_shared("sai3", "sai3_podf", base + 0x7c, 22, &share_count_sai3);
|
||||
clks[IMX6UL_CLK_SAI3_IPG] = imx_clk_gate2_shared("sai3_ipg", "ipg", base + 0x7c, 22, &share_count_sai3);
|
||||
clks[IMX6UL_CLK_UART1_IPG] = imx_clk_gate2("uart1_ipg", "ipg", base + 0x7c, 24);
|
||||
clks[IMX6UL_CLK_UART1_SERIAL] = imx_clk_gate2("uart1_serial", "uart_podf", base + 0x7c, 24);
|
||||
clks[IMX6UL_CLK_UART7_IPG] = imx_clk_gate2("uart7_ipg", "ipg", base + 0x7c, 26);
|
||||
clks[IMX6UL_CLK_UART7_SERIAL] = imx_clk_gate2("uart7_serial", "uart_podf", base + 0x7c, 26);
|
||||
clks[IMX6UL_CLK_SAI1] = imx_clk_gate2_shared("sai1", "sai1_podf", base + 0x7c, 28, &share_count_sai1);
|
||||
clks[IMX6UL_CLK_SAI1_IPG] = imx_clk_gate2_shared("sai1_ipg", "ipg", base + 0x7c, 28, &share_count_sai1);
|
||||
clks[IMX6UL_CLK_SAI2] = imx_clk_gate2_shared("sai2", "sai2_podf", base + 0x7c, 30, &share_count_sai2);
|
||||
clks[IMX6UL_CLK_SAI2_IPG] = imx_clk_gate2_shared("sai2_ipg", "ipg", base + 0x7c, 30, &share_count_sai2);
|
||||
|
||||
/* CCGR6 */
|
||||
clks[IMX6UL_CLK_USBOH3] = imx_clk_gate2("usboh3", "ipg", base + 0x80, 0);
|
||||
clks[IMX6UL_CLK_USDHC1] = imx_clk_gate2("usdhc1", "usdhc1_podf", base + 0x80, 2);
|
||||
clks[IMX6UL_CLK_USDHC2] = imx_clk_gate2("usdhc2", "usdhc2_podf", base + 0x80, 4);
|
||||
clks[IMX6UL_CLK_SIM1] = imx_clk_gate2("sim1", "sim_sel", base + 0x80, 6);
|
||||
clks[IMX6UL_CLK_SIM2] = imx_clk_gate2("sim2", "sim_sel", base + 0x80, 8);
|
||||
clks[IMX6UL_CLK_EIM] = imx_clk_gate2("eim", "eim_slow_podf", base + 0x80, 10);
|
||||
clks[IMX6UL_CLK_PWM8] = imx_clk_gate2("pwm8", "perclk", base + 0x80, 16);
|
||||
clks[IMX6UL_CLK_UART8_IPG] = imx_clk_gate2("uart8_ipg", "ipg", base + 0x80, 14);
|
||||
clks[IMX6UL_CLK_UART8_SERIAL] = imx_clk_gate2("uart8_serial", "uart_podf", base + 0x80, 14);
|
||||
clks[IMX6UL_CLK_WDOG3] = imx_clk_gate2("wdog3", "ipg", base + 0x80, 20);
|
||||
clks[IMX6UL_CLK_I2C4] = imx_clk_gate2("i2c4", "perclk", base + 0x80, 24);
|
||||
clks[IMX6UL_CLK_PWM5] = imx_clk_gate2("pwm5", "perclk", base + 0x80, 26);
|
||||
clks[IMX6UL_CLK_PWM6] = imx_clk_gate2("pwm6", "perclk", base + 0x80, 28);
|
||||
clks[IMX6UL_CLK_PWM7] = imx_clk_gate2("Pwm7", "perclk", base + 0x80, 30);
|
||||
|
||||
/* mask handshake of mmdc */
|
||||
writel_relaxed(BM_CCM_CCDR_MMDC_CH0_MASK, base + CCDR);
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(clks); i++)
|
||||
if (IS_ERR(clks[i]))
|
||||
pr_err("i.MX6UL clk %d: register failed with %ld\n", i, PTR_ERR(clks[i]));
|
||||
|
||||
clk_data.clks = clks;
|
||||
clk_data.clk_num = ARRAY_SIZE(clks);
|
||||
of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data);
|
||||
|
||||
/* set perclk to from OSC */
|
||||
clk_set_parent(clks[IMX6UL_CLK_PERCLK_SEL], clks[IMX6UL_CLK_OSC]);
|
||||
|
||||
clk_set_rate(clks[IMX6UL_CLK_ENET_REF], 50000000);
|
||||
clk_set_rate(clks[IMX6UL_CLK_ENET2_REF], 50000000);
|
||||
clk_set_rate(clks[IMX6UL_CLK_CSI], 24000000);
|
||||
|
||||
/* keep all the clks on just for bringup */
|
||||
for (i = 0; i < ARRAY_SIZE(clks_init_on); i++)
|
||||
clk_prepare_enable(clks[clks_init_on[i]]);
|
||||
|
||||
if (IS_ENABLED(CONFIG_USB_MXS_PHY)) {
|
||||
clk_prepare_enable(clks[IMX6UL_CLK_USBPHY1_GATE]);
|
||||
clk_prepare_enable(clks[IMX6UL_CLK_USBPHY2_GATE]);
|
||||
}
|
||||
|
||||
clk_set_parent(clks[IMX6UL_CLK_CAN_SEL], clks[IMX6UL_CLK_PLL3_60M]);
|
||||
clk_set_parent(clks[IMX6UL_CLK_SIM_PRE_SEL], clks[IMX6UL_CLK_PLL3_USB_OTG]);
|
||||
|
||||
clk_set_parent(clks[IMX6UL_CLK_ENFC_SEL], clks[IMX6UL_CLK_PLL2_PFD2]);
|
||||
}
|
||||
|
||||
CLK_OF_DECLARE(imx6ul, "fsl,imx6ul-ccm", imx6ul_clocks_init);
|
||||
|
|
@ -10,7 +10,6 @@
|
|||
* http://www.gnu.org/copyleft/gpl.html
|
||||
*/
|
||||
|
||||
#include <linux/clk.h>
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/slab.h>
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
#include <linux/clk.h>
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/slab.h>
|
||||
|
|
|
|||
|
|
@ -10,7 +10,6 @@
|
|||
* http://www.gnu.org/copyleft/gpl.html
|
||||
*/
|
||||
|
||||
#include <linux/clk.h>
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/io.h>
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@
|
|||
*/
|
||||
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/clkdev.h>
|
||||
#include <linux/delay.h>
|
||||
|
|
|
|||
|
|
@ -10,7 +10,6 @@
|
|||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*/
|
||||
#include <linux/clk.h>
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/io.h>
|
||||
|
|
|
|||
|
|
@ -10,7 +10,6 @@
|
|||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*/
|
||||
#include <linux/clk.h>
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/io.h>
|
||||
|
|
@ -309,8 +308,7 @@ static void __init of_pll_mux_clk_init(struct device_node *node)
|
|||
return;
|
||||
}
|
||||
|
||||
parents[0] = of_clk_get_parent_name(node, 0);
|
||||
parents[1] = of_clk_get_parent_name(node, 1);
|
||||
of_clk_parent_fill(node, parents, 2);
|
||||
if (!parents[0] || !parents[1]) {
|
||||
pr_err("%s: missing parent clocks\n", __func__);
|
||||
return;
|
||||
|
|
|
|||
|
|
@ -16,9 +16,10 @@
|
|||
#define __DRV_CLK_GATE_H
|
||||
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/clk-provider.h>
|
||||
|
||||
struct clk;
|
||||
|
||||
struct mtk_clk_gate {
|
||||
struct clk_hw hw;
|
||||
struct regmap *regmap;
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@
|
|||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include <linux/clk.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/slab.h>
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@
|
|||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include <linux/clk.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/slab.h>
|
||||
|
|
@ -795,8 +796,9 @@ CLK_OF_DECLARE(mtk_pericfg, "mediatek,mt8173-pericfg", mtk_pericfg_init);
|
|||
|
||||
#define CON0_MT8173_RST_BAR BIT(24)
|
||||
|
||||
#define PLL(_id, _name, _reg, _pwr_reg, _en_mask, _flags, _pcwbits, _pd_reg, _pd_shift, \
|
||||
_tuner_reg, _pcw_reg, _pcw_shift) { \
|
||||
#define PLL_B(_id, _name, _reg, _pwr_reg, _en_mask, _flags, _pcwbits, \
|
||||
_pd_reg, _pd_shift, _tuner_reg, _pcw_reg, \
|
||||
_pcw_shift, _div_table) { \
|
||||
.id = _id, \
|
||||
.name = _name, \
|
||||
.reg = _reg, \
|
||||
|
|
@ -811,14 +813,31 @@ CLK_OF_DECLARE(mtk_pericfg, "mediatek,mt8173-pericfg", mtk_pericfg_init);
|
|||
.tuner_reg = _tuner_reg, \
|
||||
.pcw_reg = _pcw_reg, \
|
||||
.pcw_shift = _pcw_shift, \
|
||||
.div_table = _div_table, \
|
||||
}
|
||||
|
||||
#define PLL(_id, _name, _reg, _pwr_reg, _en_mask, _flags, _pcwbits, \
|
||||
_pd_reg, _pd_shift, _tuner_reg, _pcw_reg, \
|
||||
_pcw_shift) \
|
||||
PLL_B(_id, _name, _reg, _pwr_reg, _en_mask, _flags, _pcwbits, \
|
||||
_pd_reg, _pd_shift, _tuner_reg, _pcw_reg, _pcw_shift, \
|
||||
NULL)
|
||||
|
||||
static const struct mtk_pll_div_table mmpll_div_table[] = {
|
||||
{ .div = 0, .freq = MT8173_PLL_FMAX },
|
||||
{ .div = 1, .freq = 1000000000 },
|
||||
{ .div = 2, .freq = 702000000 },
|
||||
{ .div = 3, .freq = 253500000 },
|
||||
{ .div = 4, .freq = 126750000 },
|
||||
{ } /* sentinel */
|
||||
};
|
||||
|
||||
static const struct mtk_pll_data plls[] = {
|
||||
PLL(CLK_APMIXED_ARMCA15PLL, "armca15pll", 0x200, 0x20c, 0x00000001, 0, 21, 0x204, 24, 0x0, 0x204, 0),
|
||||
PLL(CLK_APMIXED_ARMCA7PLL, "armca7pll", 0x210, 0x21c, 0x00000001, 0, 21, 0x214, 24, 0x0, 0x214, 0),
|
||||
PLL(CLK_APMIXED_MAINPLL, "mainpll", 0x220, 0x22c, 0xf0000101, HAVE_RST_BAR, 21, 0x220, 4, 0x0, 0x224, 0),
|
||||
PLL(CLK_APMIXED_UNIVPLL, "univpll", 0x230, 0x23c, 0xfe000001, HAVE_RST_BAR, 7, 0x230, 4, 0x0, 0x234, 14),
|
||||
PLL(CLK_APMIXED_MMPLL, "mmpll", 0x240, 0x24c, 0x00000001, 0, 21, 0x244, 24, 0x0, 0x244, 0),
|
||||
PLL_B(CLK_APMIXED_MMPLL, "mmpll", 0x240, 0x24c, 0x00000001, 0, 21, 0x244, 24, 0x0, 0x244, 0, mmpll_div_table),
|
||||
PLL(CLK_APMIXED_MSDCPLL, "msdcpll", 0x250, 0x25c, 0x00000001, 0, 21, 0x250, 4, 0x0, 0x254, 0),
|
||||
PLL(CLK_APMIXED_VENCPLL, "vencpll", 0x260, 0x26c, 0x00000001, 0, 21, 0x260, 4, 0x0, 0x264, 0),
|
||||
PLL(CLK_APMIXED_TVDPLL, "tvdpll", 0x270, 0x27c, 0x00000001, 0, 21, 0x270, 4, 0x0, 0x274, 0),
|
||||
|
|
|
|||
|
|
@ -17,9 +17,10 @@
|
|||
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/clk-provider.h>
|
||||
|
||||
struct clk;
|
||||
|
||||
#define MAX_MUX_GATE_BIT 31
|
||||
#define INVALID_MUX_GATE_BIT (MAX_MUX_GATE_BIT + 1)
|
||||
|
||||
|
|
@ -134,6 +135,11 @@ struct clk_onecell_data *mtk_alloc_clk_data(unsigned int clk_num);
|
|||
|
||||
#define HAVE_RST_BAR BIT(0)
|
||||
|
||||
struct mtk_pll_div_table {
|
||||
u32 div;
|
||||
unsigned long freq;
|
||||
};
|
||||
|
||||
struct mtk_pll_data {
|
||||
int id;
|
||||
const char *name;
|
||||
|
|
@ -150,6 +156,7 @@ struct mtk_pll_data {
|
|||
int pcwbits;
|
||||
uint32_t pcw_reg;
|
||||
int pcw_shift;
|
||||
const struct mtk_pll_div_table *div_table;
|
||||
};
|
||||
|
||||
void __init mtk_clk_register_plls(struct device_node *node,
|
||||
|
|
|
|||
|
|
@ -90,20 +90,23 @@ static unsigned long __mtk_pll_recalc_rate(struct mtk_clk_pll *pll, u32 fin,
|
|||
static void mtk_pll_set_rate_regs(struct mtk_clk_pll *pll, u32 pcw,
|
||||
int postdiv)
|
||||
{
|
||||
u32 con1, pd, val;
|
||||
u32 con1, val;
|
||||
int pll_en;
|
||||
|
||||
/* set postdiv */
|
||||
pd = readl(pll->pd_addr);
|
||||
pd &= ~(POSTDIV_MASK << pll->data->pd_shift);
|
||||
pd |= (ffs(postdiv) - 1) << pll->data->pd_shift;
|
||||
writel(pd, pll->pd_addr);
|
||||
|
||||
pll_en = readl(pll->base_addr + REG_CON0) & CON0_BASE_EN;
|
||||
|
||||
/* set pcw */
|
||||
val = readl(pll->pcw_addr);
|
||||
/* set postdiv */
|
||||
val = readl(pll->pd_addr);
|
||||
val &= ~(POSTDIV_MASK << pll->data->pd_shift);
|
||||
val |= (ffs(postdiv) - 1) << pll->data->pd_shift;
|
||||
|
||||
/* postdiv and pcw need to set at the same time if on same register */
|
||||
if (pll->pd_addr != pll->pcw_addr) {
|
||||
writel(val, pll->pd_addr);
|
||||
val = readl(pll->pcw_addr);
|
||||
}
|
||||
|
||||
/* set pcw */
|
||||
val &= ~GENMASK(pll->data->pcw_shift + pll->data->pcwbits - 1,
|
||||
pll->data->pcw_shift);
|
||||
val |= pcw << pll->data->pcw_shift;
|
||||
|
|
@ -135,16 +138,28 @@ static void mtk_pll_calc_values(struct mtk_clk_pll *pll, u32 *pcw, u32 *postdiv,
|
|||
u32 freq, u32 fin)
|
||||
{
|
||||
unsigned long fmin = 1000 * MHZ;
|
||||
const struct mtk_pll_div_table *div_table = pll->data->div_table;
|
||||
u64 _pcw;
|
||||
u32 val;
|
||||
|
||||
if (freq > pll->data->fmax)
|
||||
freq = pll->data->fmax;
|
||||
|
||||
for (val = 0; val < 4; val++) {
|
||||
if (div_table) {
|
||||
if (freq > div_table[0].freq)
|
||||
freq = div_table[0].freq;
|
||||
|
||||
for (val = 0; div_table[val + 1].freq != 0; val++) {
|
||||
if (freq > div_table[val + 1].freq)
|
||||
break;
|
||||
}
|
||||
*postdiv = 1 << val;
|
||||
if (freq * *postdiv >= fmin)
|
||||
break;
|
||||
} else {
|
||||
for (val = 0; val < 5; val++) {
|
||||
*postdiv = 1 << val;
|
||||
if ((u64)freq * *postdiv >= fmin)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* _pcw = freq * postdiv / fin * 2^pcwfbits */
|
||||
|
|
|
|||
|
|
@ -35,6 +35,7 @@
|
|||
#include <linux/module.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/clk-provider.h>
|
||||
|
||||
#define MESON_CPU_CLK_CNTL1 0x00
|
||||
|
|
|
|||
|
|
@ -15,7 +15,6 @@
|
|||
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <linux/clk.h>
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/mfd/syscon.h>
|
||||
#include <linux/slab.h>
|
||||
|
|
|
|||
|
|
@ -10,7 +10,6 @@
|
|||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/delay.h>
|
||||
|
|
|
|||
|
|
@ -10,7 +10,6 @@
|
|||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/delay.h>
|
||||
|
|
|
|||
|
|
@ -27,7 +27,6 @@
|
|||
static int mmp_clk_gate_enable(struct clk_hw *hw)
|
||||
{
|
||||
struct mmp_clk_gate *gate = to_clk_mmp_gate(hw);
|
||||
struct clk *clk = hw->clk;
|
||||
unsigned long flags = 0;
|
||||
unsigned long rate;
|
||||
u32 tmp;
|
||||
|
|
@ -44,7 +43,7 @@ static int mmp_clk_gate_enable(struct clk_hw *hw)
|
|||
spin_unlock_irqrestore(gate->lock, flags);
|
||||
|
||||
if (gate->flags & MMP_CLK_GATE_NEED_DELAY) {
|
||||
rate = __clk_get_rate(clk);
|
||||
rate = clk_hw_get_rate(hw);
|
||||
/* Need delay 2 cycles. */
|
||||
udelay(2000000/rate);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -63,7 +63,7 @@ static unsigned int _get_div(struct mmp_clk_mix *mix, unsigned int val)
|
|||
|
||||
static unsigned int _get_mux(struct mmp_clk_mix *mix, unsigned int val)
|
||||
{
|
||||
int num_parents = __clk_get_num_parents(mix->hw.clk);
|
||||
int num_parents = clk_hw_get_num_parents(&mix->hw);
|
||||
int i;
|
||||
|
||||
if (mix->mux_flags & CLK_MUX_INDEX_BIT)
|
||||
|
|
@ -113,15 +113,15 @@ static void _filter_clk_table(struct mmp_clk_mix *mix,
|
|||
{
|
||||
int i;
|
||||
struct mmp_clk_mix_clk_table *item;
|
||||
struct clk *parent, *clk;
|
||||
struct clk_hw *parent, *hw;
|
||||
unsigned long parent_rate;
|
||||
|
||||
clk = mix->hw.clk;
|
||||
hw = &mix->hw;
|
||||
|
||||
for (i = 0; i < table_size; i++) {
|
||||
item = &table[i];
|
||||
parent = clk_get_parent_by_index(clk, item->parent_index);
|
||||
parent_rate = __clk_get_rate(parent);
|
||||
parent = clk_hw_get_parent_by_index(hw, item->parent_index);
|
||||
parent_rate = clk_hw_get_rate(parent);
|
||||
if (parent_rate % item->rate) {
|
||||
item->valid = 0;
|
||||
} else {
|
||||
|
|
@ -181,7 +181,7 @@ static int _set_rate(struct mmp_clk_mix *mix, u32 mux_val, u32 div_val,
|
|||
|
||||
if (timeout == 0) {
|
||||
pr_err("%s:%s cannot do frequency change\n",
|
||||
__func__, __clk_get_name(mix->hw.clk));
|
||||
__func__, clk_hw_get_name(&mix->hw));
|
||||
ret = -EBUSY;
|
||||
goto error;
|
||||
}
|
||||
|
|
@ -201,27 +201,22 @@ error:
|
|||
return ret;
|
||||
}
|
||||
|
||||
static long mmp_clk_mix_determine_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long min_rate,
|
||||
unsigned long max_rate,
|
||||
unsigned long *best_parent_rate,
|
||||
struct clk_hw **best_parent_clk)
|
||||
static int mmp_clk_mix_determine_rate(struct clk_hw *hw,
|
||||
struct clk_rate_request *req)
|
||||
{
|
||||
struct mmp_clk_mix *mix = to_clk_mix(hw);
|
||||
struct mmp_clk_mix_clk_table *item;
|
||||
struct clk *parent, *parent_best, *mix_clk;
|
||||
struct clk_hw *parent, *parent_best;
|
||||
unsigned long parent_rate, mix_rate, mix_rate_best, parent_rate_best;
|
||||
unsigned long gap, gap_best;
|
||||
u32 div_val_max;
|
||||
unsigned int div;
|
||||
int i, j;
|
||||
|
||||
mix_clk = hw->clk;
|
||||
|
||||
parent = NULL;
|
||||
mix_rate_best = 0;
|
||||
parent_rate_best = 0;
|
||||
gap_best = rate;
|
||||
gap_best = ULONG_MAX;
|
||||
parent_best = NULL;
|
||||
|
||||
if (mix->table) {
|
||||
|
|
@ -229,11 +224,11 @@ static long mmp_clk_mix_determine_rate(struct clk_hw *hw, unsigned long rate,
|
|||
item = &mix->table[i];
|
||||
if (item->valid == 0)
|
||||
continue;
|
||||
parent = clk_get_parent_by_index(mix_clk,
|
||||
parent = clk_hw_get_parent_by_index(hw,
|
||||
item->parent_index);
|
||||
parent_rate = __clk_get_rate(parent);
|
||||
parent_rate = clk_hw_get_rate(parent);
|
||||
mix_rate = parent_rate / item->divisor;
|
||||
gap = abs(mix_rate - rate);
|
||||
gap = abs(mix_rate - req->rate);
|
||||
if (parent_best == NULL || gap < gap_best) {
|
||||
parent_best = parent;
|
||||
parent_rate_best = parent_rate;
|
||||
|
|
@ -244,14 +239,14 @@ static long mmp_clk_mix_determine_rate(struct clk_hw *hw, unsigned long rate,
|
|||
}
|
||||
}
|
||||
} else {
|
||||
for (i = 0; i < __clk_get_num_parents(mix_clk); i++) {
|
||||
parent = clk_get_parent_by_index(mix_clk, i);
|
||||
parent_rate = __clk_get_rate(parent);
|
||||
for (i = 0; i < clk_hw_get_num_parents(hw); i++) {
|
||||
parent = clk_hw_get_parent_by_index(hw, i);
|
||||
parent_rate = clk_hw_get_rate(parent);
|
||||
div_val_max = _get_maxdiv(mix);
|
||||
for (j = 0; j < div_val_max; j++) {
|
||||
div = _get_div(mix, j);
|
||||
mix_rate = parent_rate / div;
|
||||
gap = abs(mix_rate - rate);
|
||||
gap = abs(mix_rate - req->rate);
|
||||
if (parent_best == NULL || gap < gap_best) {
|
||||
parent_best = parent;
|
||||
parent_rate_best = parent_rate;
|
||||
|
|
@ -265,10 +260,14 @@ static long mmp_clk_mix_determine_rate(struct clk_hw *hw, unsigned long rate,
|
|||
}
|
||||
|
||||
found:
|
||||
*best_parent_rate = parent_rate_best;
|
||||
*best_parent_clk = __clk_get_hw(parent_best);
|
||||
if (!parent_best)
|
||||
return -EINVAL;
|
||||
|
||||
return mix_rate_best;
|
||||
req->best_parent_rate = parent_rate_best;
|
||||
req->best_parent_hw = parent_best;
|
||||
req->rate = mix_rate_best;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mmp_clk_mix_set_rate_and_parent(struct clk_hw *hw,
|
||||
|
|
@ -381,20 +380,19 @@ static int mmp_clk_set_rate(struct clk_hw *hw, unsigned long rate,
|
|||
struct mmp_clk_mix_clk_table *item;
|
||||
unsigned long parent_rate;
|
||||
unsigned int best_divisor;
|
||||
struct clk *mix_clk, *parent;
|
||||
struct clk_hw *parent;
|
||||
int i;
|
||||
|
||||
best_divisor = best_parent_rate / rate;
|
||||
|
||||
mix_clk = hw->clk;
|
||||
if (mix->table) {
|
||||
for (i = 0; i < mix->table_size; i++) {
|
||||
item = &mix->table[i];
|
||||
if (item->valid == 0)
|
||||
continue;
|
||||
parent = clk_get_parent_by_index(mix_clk,
|
||||
parent = clk_hw_get_parent_by_index(hw,
|
||||
item->parent_index);
|
||||
parent_rate = __clk_get_rate(parent);
|
||||
parent_rate = clk_hw_get_rate(parent);
|
||||
if (parent_rate == best_parent_rate
|
||||
&& item->divisor == best_divisor)
|
||||
break;
|
||||
|
|
@ -407,13 +405,13 @@ static int mmp_clk_set_rate(struct clk_hw *hw, unsigned long rate,
|
|||
else
|
||||
return -EINVAL;
|
||||
} else {
|
||||
for (i = 0; i < __clk_get_num_parents(mix_clk); i++) {
|
||||
parent = clk_get_parent_by_index(mix_clk, i);
|
||||
parent_rate = __clk_get_rate(parent);
|
||||
for (i = 0; i < clk_hw_get_num_parents(hw); i++) {
|
||||
parent = clk_hw_get_parent_by_index(hw, i);
|
||||
parent_rate = clk_hw_get_rate(parent);
|
||||
if (parent_rate == best_parent_rate)
|
||||
break;
|
||||
}
|
||||
if (i < __clk_get_num_parents(mix_clk))
|
||||
if (i < clk_hw_get_num_parents(hw))
|
||||
return _set_rate(mix, _get_mux_val(mix, i),
|
||||
_get_div_val(mix, best_divisor), 1, 1);
|
||||
else
|
||||
|
|
@ -468,20 +466,20 @@ struct clk *mmp_clk_register_mix(struct device *dev,
|
|||
memcpy(&mix->reg_info, &config->reg_info, sizeof(config->reg_info));
|
||||
if (config->table) {
|
||||
table_bytes = sizeof(*config->table) * config->table_size;
|
||||
mix->table = kzalloc(table_bytes, GFP_KERNEL);
|
||||
mix->table = kmemdup(config->table, table_bytes, GFP_KERNEL);
|
||||
if (!mix->table) {
|
||||
pr_err("%s:%s: could not allocate mmp mix table\n",
|
||||
__func__, name);
|
||||
kfree(mix);
|
||||
return ERR_PTR(-ENOMEM);
|
||||
}
|
||||
memcpy(mix->table, config->table, table_bytes);
|
||||
mix->table_size = config->table_size;
|
||||
}
|
||||
|
||||
if (config->mux_table) {
|
||||
table_bytes = sizeof(u32) * num_parents;
|
||||
mix->mux_table = kzalloc(table_bytes, GFP_KERNEL);
|
||||
mix->mux_table = kmemdup(config->mux_table, table_bytes,
|
||||
GFP_KERNEL);
|
||||
if (!mix->mux_table) {
|
||||
pr_err("%s:%s: could not allocate mmp mix mux-table\n",
|
||||
__func__, name);
|
||||
|
|
@ -489,7 +487,6 @@ struct clk *mmp_clk_register_mix(struct device *dev,
|
|||
kfree(mix);
|
||||
return ERR_PTR(-ENOMEM);
|
||||
}
|
||||
memcpy(mix->mux_table, config->mux_table, table_bytes);
|
||||
}
|
||||
|
||||
mix->div_flags = config->div_flags;
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
#include <linux/io.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/clkdev.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_address.h>
|
||||
|
||||
|
|
|
|||
|
|
@ -10,7 +10,8 @@
|
|||
* warranty of any kind, whether express or implied.
|
||||
*/
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/clkdev.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/io.h>
|
||||
|
|
@ -120,7 +121,7 @@ static int clk_cpu_on_set_rate(struct clk_hw *hwclk, unsigned long rate,
|
|||
if (!cpuclk->pmu_dfs)
|
||||
return -ENODEV;
|
||||
|
||||
cur_rate = __clk_get_rate(hwclk->clk);
|
||||
cur_rate = clk_hw_get_rate(hwclk);
|
||||
|
||||
reg = readl(cpuclk->reg_base + SYS_CTRL_CLK_DIVIDER_CTRL2_OFFSET);
|
||||
fabric_div = (reg >> SYS_CTRL_CLK_DIVIDER_CTRL2_NBCLK_RATIO_SHIFT) &
|
||||
|
|
@ -196,7 +197,6 @@ static void __init of_cpu_clk_setup(struct device_node *node)
|
|||
for_each_node_by_type(dn, "cpu") {
|
||||
struct clk_init_data init;
|
||||
struct clk *clk;
|
||||
struct clk *parent_clk;
|
||||
char *clk_name = kzalloc(5, GFP_KERNEL);
|
||||
int cpu, err;
|
||||
|
||||
|
|
@ -208,9 +208,8 @@ static void __init of_cpu_clk_setup(struct device_node *node)
|
|||
goto bail_out;
|
||||
|
||||
sprintf(clk_name, "cpu%d", cpu);
|
||||
parent_clk = of_clk_get(node, 0);
|
||||
|
||||
cpuclk[cpu].parent_name = __clk_get_name(parent_clk);
|
||||
cpuclk[cpu].parent_name = of_clk_get_parent_name(node, 0);
|
||||
cpuclk[cpu].clk_name = clk_name;
|
||||
cpuclk[cpu].cpu = cpu;
|
||||
cpuclk[cpu].reg_base = clock_complex_base;
|
||||
|
|
|
|||
|
|
@ -13,8 +13,8 @@
|
|||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/clkdev.h>
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/of.h>
|
||||
|
|
|
|||
|
|
@ -9,7 +9,6 @@
|
|||
* http://www.gnu.org/copyleft/gpl.html
|
||||
*/
|
||||
|
||||
#include <linux/clk.h>
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/slab.h>
|
||||
|
|
|
|||
|
|
@ -9,7 +9,6 @@
|
|||
* http://www.gnu.org/copyleft/gpl.html
|
||||
*/
|
||||
|
||||
#include <linux/clk.h>
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/io.h>
|
||||
|
|
|
|||
|
|
@ -9,9 +9,8 @@
|
|||
* http://www.gnu.org/copyleft/gpl.html
|
||||
*/
|
||||
|
||||
#include <linux/clk.h>
|
||||
#include <linux/clk/mxs.h>
|
||||
#include <linux/clkdev.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/init.h>
|
||||
|
|
|
|||
|
|
@ -9,9 +9,9 @@
|
|||
* http://www.gnu.org/copyleft/gpl.html
|
||||
*/
|
||||
|
||||
#include <linux/clk.h>
|
||||
#include <linux/clk/mxs.h>
|
||||
#include <linux/clkdev.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/init.h>
|
||||
|
|
|
|||
|
|
@ -9,7 +9,6 @@
|
|||
* http://www.gnu.org/copyleft/gpl.html
|
||||
*/
|
||||
|
||||
#include <linux/clk.h>
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/err.h>
|
||||
|
|
|
|||
|
|
@ -9,7 +9,6 @@
|
|||
* http://www.gnu.org/copyleft/gpl.html
|
||||
*/
|
||||
|
||||
#include <linux/clk.h>
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/io.h>
|
||||
|
|
|
|||
|
|
@ -12,7 +12,8 @@
|
|||
#ifndef __MXS_CLK_H
|
||||
#define __MXS_CLK_H
|
||||
|
||||
#include <linux/clk.h>
|
||||
struct clk;
|
||||
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/spinlock.h>
|
||||
|
||||
|
|
|
|||
|
|
@ -8,7 +8,6 @@
|
|||
* warranty of any kind, whether express or implied.
|
||||
*/
|
||||
|
||||
#include <linux/clk.h>
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/kernel.h>
|
||||
|
|
|
|||
|
|
@ -159,9 +159,15 @@ PNAME(mux_debug) = { "mips_pll_mux", "rpu_v_pll_mux",
|
|||
"wifi_pll_mux", "bt_pll_mux" };
|
||||
static u32 mux_debug_idx[] = { 0x0, 0x1, 0x2, 0x4, 0x8, 0x10 };
|
||||
|
||||
static unsigned int pistachio_critical_clks[] __initdata = {
|
||||
CLK_MIPS,
|
||||
CLK_PERIPH_SYS,
|
||||
static unsigned int pistachio_critical_clks_core[] __initdata = {
|
||||
CLK_MIPS
|
||||
};
|
||||
|
||||
static unsigned int pistachio_critical_clks_sys[] __initdata = {
|
||||
PERIPH_CLK_SYS,
|
||||
PERIPH_CLK_SYS_BUS,
|
||||
PERIPH_CLK_DDR,
|
||||
PERIPH_CLK_ROM,
|
||||
};
|
||||
|
||||
static void __init pistachio_clk_init(struct device_node *np)
|
||||
|
|
@ -193,8 +199,8 @@ static void __init pistachio_clk_init(struct device_node *np)
|
|||
|
||||
pistachio_clk_register_provider(p);
|
||||
|
||||
pistachio_clk_force_enable(p, pistachio_critical_clks,
|
||||
ARRAY_SIZE(pistachio_critical_clks));
|
||||
pistachio_clk_force_enable(p, pistachio_critical_clks_core,
|
||||
ARRAY_SIZE(pistachio_critical_clks_core));
|
||||
}
|
||||
CLK_OF_DECLARE(pistachio_clk, "img,pistachio-clk", pistachio_clk_init);
|
||||
|
||||
|
|
@ -261,6 +267,9 @@ static void __init pistachio_clk_periph_init(struct device_node *np)
|
|||
ARRAY_SIZE(pistachio_periph_gates));
|
||||
|
||||
pistachio_clk_register_provider(p);
|
||||
|
||||
pistachio_clk_force_enable(p, pistachio_critical_clks_sys,
|
||||
ARRAY_SIZE(pistachio_critical_clks_sys));
|
||||
}
|
||||
CLK_OF_DECLARE(pistachio_clk_periph, "img,pistachio-clk-periph",
|
||||
pistachio_clk_periph_init);
|
||||
|
|
|
|||
|
|
@ -65,6 +65,12 @@
|
|||
#define MIN_OUTPUT_FRAC 12000000UL
|
||||
#define MAX_OUTPUT_FRAC 1600000000UL
|
||||
|
||||
/* Fractional PLL operating modes */
|
||||
enum pll_mode {
|
||||
PLL_MODE_FRAC,
|
||||
PLL_MODE_INT,
|
||||
};
|
||||
|
||||
struct pistachio_clk_pll {
|
||||
struct clk_hw hw;
|
||||
void __iomem *base;
|
||||
|
|
@ -88,12 +94,10 @@ static inline void pll_lock(struct pistachio_clk_pll *pll)
|
|||
cpu_relax();
|
||||
}
|
||||
|
||||
static inline u32 do_div_round_closest(u64 dividend, u32 divisor)
|
||||
static inline u64 do_div_round_closest(u64 dividend, u64 divisor)
|
||||
{
|
||||
dividend += divisor / 2;
|
||||
do_div(dividend, divisor);
|
||||
|
||||
return dividend;
|
||||
return div64_u64(dividend, divisor);
|
||||
}
|
||||
|
||||
static inline struct pistachio_clk_pll *to_pistachio_pll(struct clk_hw *hw)
|
||||
|
|
@ -101,6 +105,29 @@ static inline struct pistachio_clk_pll *to_pistachio_pll(struct clk_hw *hw)
|
|||
return container_of(hw, struct pistachio_clk_pll, hw);
|
||||
}
|
||||
|
||||
static inline enum pll_mode pll_frac_get_mode(struct clk_hw *hw)
|
||||
{
|
||||
struct pistachio_clk_pll *pll = to_pistachio_pll(hw);
|
||||
u32 val;
|
||||
|
||||
val = pll_readl(pll, PLL_CTRL3) & PLL_FRAC_CTRL3_DSMPD;
|
||||
return val ? PLL_MODE_INT : PLL_MODE_FRAC;
|
||||
}
|
||||
|
||||
static inline void pll_frac_set_mode(struct clk_hw *hw, enum pll_mode mode)
|
||||
{
|
||||
struct pistachio_clk_pll *pll = to_pistachio_pll(hw);
|
||||
u32 val;
|
||||
|
||||
val = pll_readl(pll, PLL_CTRL3);
|
||||
if (mode == PLL_MODE_INT)
|
||||
val |= PLL_FRAC_CTRL3_DSMPD | PLL_FRAC_CTRL3_DACPD;
|
||||
else
|
||||
val &= ~(PLL_FRAC_CTRL3_DSMPD | PLL_FRAC_CTRL3_DACPD);
|
||||
|
||||
pll_writel(pll, val, PLL_CTRL3);
|
||||
}
|
||||
|
||||
static struct pistachio_pll_rate_table *
|
||||
pll_get_params(struct pistachio_clk_pll *pll, unsigned long fref,
|
||||
unsigned long fout)
|
||||
|
|
@ -136,8 +163,7 @@ static int pll_gf40lp_frac_enable(struct clk_hw *hw)
|
|||
u32 val;
|
||||
|
||||
val = pll_readl(pll, PLL_CTRL3);
|
||||
val &= ~(PLL_FRAC_CTRL3_PD | PLL_FRAC_CTRL3_DACPD |
|
||||
PLL_FRAC_CTRL3_DSMPD | PLL_FRAC_CTRL3_FOUTPOSTDIVPD |
|
||||
val &= ~(PLL_FRAC_CTRL3_PD | PLL_FRAC_CTRL3_FOUTPOSTDIVPD |
|
||||
PLL_FRAC_CTRL3_FOUT4PHASEPD | PLL_FRAC_CTRL3_FOUTVCOPD);
|
||||
pll_writel(pll, val, PLL_CTRL3);
|
||||
|
||||
|
|
@ -173,8 +199,8 @@ static int pll_gf40lp_frac_set_rate(struct clk_hw *hw, unsigned long rate,
|
|||
struct pistachio_clk_pll *pll = to_pistachio_pll(hw);
|
||||
struct pistachio_pll_rate_table *params;
|
||||
int enabled = pll_gf40lp_frac_is_enabled(hw);
|
||||
u32 val, vco, old_postdiv1, old_postdiv2;
|
||||
const char *name = __clk_get_name(hw->clk);
|
||||
u64 val, vco, old_postdiv1, old_postdiv2;
|
||||
const char *name = clk_hw_get_name(hw);
|
||||
|
||||
if (rate < MIN_OUTPUT_FRAC || rate > MAX_OUTPUT_FRAC)
|
||||
return -EINVAL;
|
||||
|
|
@ -183,17 +209,21 @@ static int pll_gf40lp_frac_set_rate(struct clk_hw *hw, unsigned long rate,
|
|||
if (!params || !params->refdiv)
|
||||
return -EINVAL;
|
||||
|
||||
vco = params->fref * params->fbdiv / params->refdiv;
|
||||
/* calculate vco */
|
||||
vco = params->fref;
|
||||
vco *= (params->fbdiv << 24) + params->frac;
|
||||
vco = div64_u64(vco, params->refdiv << 24);
|
||||
|
||||
if (vco < MIN_VCO_FRAC_FRAC || vco > MAX_VCO_FRAC_FRAC)
|
||||
pr_warn("%s: VCO %u is out of range %lu..%lu\n", name, vco,
|
||||
pr_warn("%s: VCO %llu is out of range %lu..%lu\n", name, vco,
|
||||
MIN_VCO_FRAC_FRAC, MAX_VCO_FRAC_FRAC);
|
||||
|
||||
val = params->fref / params->refdiv;
|
||||
val = div64_u64(params->fref, params->refdiv);
|
||||
if (val < MIN_PFD)
|
||||
pr_warn("%s: PFD %u is too low (min %lu)\n",
|
||||
pr_warn("%s: PFD %llu is too low (min %lu)\n",
|
||||
name, val, MIN_PFD);
|
||||
if (val > vco / 16)
|
||||
pr_warn("%s: PFD %u is too high (max %u)\n",
|
||||
pr_warn("%s: PFD %llu is too high (max %llu)\n",
|
||||
name, val, vco / 16);
|
||||
|
||||
val = pll_readl(pll, PLL_CTRL1);
|
||||
|
|
@ -227,6 +257,12 @@ static int pll_gf40lp_frac_set_rate(struct clk_hw *hw, unsigned long rate,
|
|||
(params->postdiv2 << PLL_FRAC_CTRL2_POSTDIV2_SHIFT);
|
||||
pll_writel(pll, val, PLL_CTRL2);
|
||||
|
||||
/* set operating mode */
|
||||
if (params->frac)
|
||||
pll_frac_set_mode(hw, PLL_MODE_FRAC);
|
||||
else
|
||||
pll_frac_set_mode(hw, PLL_MODE_INT);
|
||||
|
||||
if (enabled)
|
||||
pll_lock(pll);
|
||||
|
||||
|
|
@ -237,8 +273,7 @@ static unsigned long pll_gf40lp_frac_recalc_rate(struct clk_hw *hw,
|
|||
unsigned long parent_rate)
|
||||
{
|
||||
struct pistachio_clk_pll *pll = to_pistachio_pll(hw);
|
||||
u32 val, prediv, fbdiv, frac, postdiv1, postdiv2;
|
||||
u64 rate = parent_rate;
|
||||
u64 val, prediv, fbdiv, frac, postdiv1, postdiv2, rate;
|
||||
|
||||
val = pll_readl(pll, PLL_CTRL1);
|
||||
prediv = (val >> PLL_CTRL1_REFDIV_SHIFT) & PLL_CTRL1_REFDIV_MASK;
|
||||
|
|
@ -251,7 +286,13 @@ static unsigned long pll_gf40lp_frac_recalc_rate(struct clk_hw *hw,
|
|||
PLL_FRAC_CTRL2_POSTDIV2_MASK;
|
||||
frac = (val >> PLL_FRAC_CTRL2_FRAC_SHIFT) & PLL_FRAC_CTRL2_FRAC_MASK;
|
||||
|
||||
rate *= (fbdiv << 24) + frac;
|
||||
/* get operating mode (int/frac) and calculate rate accordingly */
|
||||
rate = parent_rate;
|
||||
if (pll_frac_get_mode(hw) == PLL_MODE_FRAC)
|
||||
rate *= (fbdiv << 24) + frac;
|
||||
else
|
||||
rate *= (fbdiv << 24);
|
||||
|
||||
rate = do_div_round_closest(rate, (prediv * postdiv1 * postdiv2) << 24);
|
||||
|
||||
return rate;
|
||||
|
|
@ -279,7 +320,7 @@ static int pll_gf40lp_laint_enable(struct clk_hw *hw)
|
|||
u32 val;
|
||||
|
||||
val = pll_readl(pll, PLL_CTRL1);
|
||||
val &= ~(PLL_INT_CTRL1_PD | PLL_INT_CTRL1_DSMPD |
|
||||
val &= ~(PLL_INT_CTRL1_PD |
|
||||
PLL_INT_CTRL1_FOUTPOSTDIVPD | PLL_INT_CTRL1_FOUTVCOPD);
|
||||
pll_writel(pll, val, PLL_CTRL1);
|
||||
|
||||
|
|
@ -316,7 +357,7 @@ static int pll_gf40lp_laint_set_rate(struct clk_hw *hw, unsigned long rate,
|
|||
struct pistachio_pll_rate_table *params;
|
||||
int enabled = pll_gf40lp_laint_is_enabled(hw);
|
||||
u32 val, vco, old_postdiv1, old_postdiv2;
|
||||
const char *name = __clk_get_name(hw->clk);
|
||||
const char *name = clk_hw_get_name(hw);
|
||||
|
||||
if (rate < MIN_OUTPUT_LA || rate > MAX_OUTPUT_LA)
|
||||
return -EINVAL;
|
||||
|
|
@ -325,12 +366,12 @@ static int pll_gf40lp_laint_set_rate(struct clk_hw *hw, unsigned long rate,
|
|||
if (!params || !params->refdiv)
|
||||
return -EINVAL;
|
||||
|
||||
vco = params->fref * params->fbdiv / params->refdiv;
|
||||
vco = div_u64(params->fref * params->fbdiv, params->refdiv);
|
||||
if (vco < MIN_VCO_LA || vco > MAX_VCO_LA)
|
||||
pr_warn("%s: VCO %u is out of range %lu..%lu\n", name, vco,
|
||||
MIN_VCO_LA, MAX_VCO_LA);
|
||||
|
||||
val = params->fref / params->refdiv;
|
||||
val = div_u64(params->fref, params->refdiv);
|
||||
if (val < MIN_PFD)
|
||||
pr_warn("%s: PFD %u is too low (min %lu)\n",
|
||||
name, val, MIN_PFD);
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@
|
|||
* version 2, as published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#include <linux/clk.h>
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/of.h>
|
||||
|
|
|
|||
|
|
@ -95,13 +95,13 @@ struct pistachio_fixed_factor {
|
|||
}
|
||||
|
||||
struct pistachio_pll_rate_table {
|
||||
unsigned long fref;
|
||||
unsigned long fout;
|
||||
unsigned int refdiv;
|
||||
unsigned int fbdiv;
|
||||
unsigned int postdiv1;
|
||||
unsigned int postdiv2;
|
||||
unsigned int frac;
|
||||
unsigned long long fref;
|
||||
unsigned long long fout;
|
||||
unsigned long long refdiv;
|
||||
unsigned long long fbdiv;
|
||||
unsigned long long postdiv1;
|
||||
unsigned long long postdiv2;
|
||||
unsigned long long frac;
|
||||
};
|
||||
|
||||
enum pistachio_pll_type {
|
||||
|
|
|
|||
|
|
@ -79,7 +79,7 @@ unsigned int pxa25x_get_clk_frequency_khz(int info)
|
|||
clks[3] / 1000000, (clks[3] % 1000000) / 10000);
|
||||
}
|
||||
|
||||
return (unsigned int)clks[0];
|
||||
return (unsigned int)clks[0] / KHz;
|
||||
}
|
||||
|
||||
static unsigned long clk_pxa25x_memory_get_rate(struct clk_hw *hw,
|
||||
|
|
|
|||
|
|
@ -80,7 +80,7 @@ unsigned int pxa27x_get_clk_frequency_khz(int info)
|
|||
pr_info("System bus clock: %ld.%02ldMHz\n",
|
||||
clks[4] / 1000000, (clks[4] % 1000000) / 10000);
|
||||
}
|
||||
return (unsigned int)clks[0];
|
||||
return (unsigned int)clks[0] / KHz;
|
||||
}
|
||||
|
||||
bool pxa27x_is_ppll_disabled(void)
|
||||
|
|
|
|||
|
|
@ -78,7 +78,7 @@ unsigned int pxa3xx_get_clk_frequency_khz(int info)
|
|||
pr_info("System bus clock: %ld.%02ldMHz\n",
|
||||
clks[4] / 1000000, (clks[4] % 1000000) / 10000);
|
||||
}
|
||||
return (unsigned int)clks[0];
|
||||
return (unsigned int)clks[0] / KHz;
|
||||
}
|
||||
|
||||
static unsigned long clk_pxa3xx_ac97_get_rate(struct clk_hw *hw,
|
||||
|
|
|
|||
|
|
@ -75,7 +75,7 @@ static int clk_branch_wait(const struct clk_branch *br, bool enabling,
|
|||
bool (check_halt)(const struct clk_branch *, bool))
|
||||
{
|
||||
bool voted = br->halt_check & BRANCH_VOTED;
|
||||
const char *name = __clk_get_name(br->clkr.hw.clk);
|
||||
const char *name = clk_hw_get_name(&br->clkr.hw);
|
||||
|
||||
/* Skip checking halt bit if the clock is in hardware gated mode */
|
||||
if (clk_branch_in_hwcg_mode(br))
|
||||
|
|
|
|||
|
|
@ -135,19 +135,19 @@ struct pll_freq_tbl *find_freq(const struct pll_freq_tbl *f, unsigned long rate)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
static long
|
||||
clk_pll_determine_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long min_rate, unsigned long max_rate,
|
||||
unsigned long *p_rate, struct clk_hw **p)
|
||||
static int
|
||||
clk_pll_determine_rate(struct clk_hw *hw, struct clk_rate_request *req)
|
||||
{
|
||||
struct clk_pll *pll = to_clk_pll(hw);
|
||||
const struct pll_freq_tbl *f;
|
||||
|
||||
f = find_freq(pll->freq_tbl, rate);
|
||||
f = find_freq(pll->freq_tbl, req->rate);
|
||||
if (!f)
|
||||
return clk_pll_recalc_rate(hw, *p_rate);
|
||||
req->rate = clk_pll_recalc_rate(hw, req->best_parent_rate);
|
||||
else
|
||||
req->rate = f->freq;
|
||||
|
||||
return f->freq;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
|
|
@ -194,7 +194,7 @@ static int wait_for_pll(struct clk_pll *pll)
|
|||
u32 val;
|
||||
int count;
|
||||
int ret;
|
||||
const char *name = __clk_get_name(pll->clkr.hw.clk);
|
||||
const char *name = clk_hw_get_name(&pll->clkr.hw);
|
||||
|
||||
/* Wait for pll to enable. */
|
||||
for (count = 200; count > 0; count--) {
|
||||
|
|
@ -213,7 +213,7 @@ static int wait_for_pll(struct clk_pll *pll)
|
|||
static int clk_pll_vote_enable(struct clk_hw *hw)
|
||||
{
|
||||
int ret;
|
||||
struct clk_pll *p = to_clk_pll(__clk_get_hw(__clk_get_parent(hw->clk)));
|
||||
struct clk_pll *p = to_clk_pll(clk_hw_get_parent(hw));
|
||||
|
||||
ret = clk_enable_regmap(hw);
|
||||
if (ret)
|
||||
|
|
@ -292,3 +292,78 @@ void clk_pll_configure_sr_hpm_lp(struct clk_pll *pll, struct regmap *regmap,
|
|||
clk_pll_set_fsm_mode(pll, regmap, 0);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(clk_pll_configure_sr_hpm_lp);
|
||||
|
||||
static int clk_pll_sr2_enable(struct clk_hw *hw)
|
||||
{
|
||||
struct clk_pll *pll = to_clk_pll(hw);
|
||||
int ret;
|
||||
u32 mode;
|
||||
|
||||
ret = regmap_read(pll->clkr.regmap, pll->mode_reg, &mode);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* Disable PLL bypass mode. */
|
||||
ret = regmap_update_bits(pll->clkr.regmap, pll->mode_reg, PLL_BYPASSNL,
|
||||
PLL_BYPASSNL);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/*
|
||||
* H/W requires a 5us delay between disabling the bypass and
|
||||
* de-asserting the reset. Delay 10us just to be safe.
|
||||
*/
|
||||
udelay(10);
|
||||
|
||||
/* De-assert active-low PLL reset. */
|
||||
ret = regmap_update_bits(pll->clkr.regmap, pll->mode_reg, PLL_RESET_N,
|
||||
PLL_RESET_N);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = wait_for_pll(pll);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* Enable PLL output. */
|
||||
return regmap_update_bits(pll->clkr.regmap, pll->mode_reg, PLL_OUTCTRL,
|
||||
PLL_OUTCTRL);
|
||||
}
|
||||
|
||||
static int
|
||||
clk_pll_sr2_set_rate(struct clk_hw *hw, unsigned long rate, unsigned long prate)
|
||||
{
|
||||
struct clk_pll *pll = to_clk_pll(hw);
|
||||
const struct pll_freq_tbl *f;
|
||||
bool enabled;
|
||||
u32 mode;
|
||||
u32 enable_mask = PLL_OUTCTRL | PLL_BYPASSNL | PLL_RESET_N;
|
||||
|
||||
f = find_freq(pll->freq_tbl, rate);
|
||||
if (!f)
|
||||
return -EINVAL;
|
||||
|
||||
regmap_read(pll->clkr.regmap, pll->mode_reg, &mode);
|
||||
enabled = (mode & enable_mask) == enable_mask;
|
||||
|
||||
if (enabled)
|
||||
clk_pll_disable(hw);
|
||||
|
||||
regmap_update_bits(pll->clkr.regmap, pll->l_reg, 0x3ff, f->l);
|
||||
regmap_update_bits(pll->clkr.regmap, pll->m_reg, 0x7ffff, f->m);
|
||||
regmap_update_bits(pll->clkr.regmap, pll->n_reg, 0x7ffff, f->n);
|
||||
|
||||
if (enabled)
|
||||
clk_pll_sr2_enable(hw);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
const struct clk_ops clk_pll_sr2_ops = {
|
||||
.enable = clk_pll_sr2_enable,
|
||||
.disable = clk_pll_disable,
|
||||
.set_rate = clk_pll_sr2_set_rate,
|
||||
.recalc_rate = clk_pll_recalc_rate,
|
||||
.determine_rate = clk_pll_determine_rate,
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(clk_pll_sr2_ops);
|
||||
|
|
|
|||
|
|
@ -62,6 +62,7 @@ struct clk_pll {
|
|||
|
||||
extern const struct clk_ops clk_pll_ops;
|
||||
extern const struct clk_ops clk_pll_vote_ops;
|
||||
extern const struct clk_ops clk_pll_sr2_ops;
|
||||
|
||||
#define to_clk_pll(_hw) container_of(to_clk_regmap(_hw), struct clk_pll, clkr)
|
||||
|
||||
|
|
|
|||
|
|
@ -45,7 +45,7 @@ static u32 src_to_ns(struct src_sel *s, u8 src, u32 ns)
|
|||
static u8 clk_rcg_get_parent(struct clk_hw *hw)
|
||||
{
|
||||
struct clk_rcg *rcg = to_clk_rcg(hw);
|
||||
int num_parents = __clk_get_num_parents(hw->clk);
|
||||
int num_parents = clk_hw_get_num_parents(hw);
|
||||
u32 ns;
|
||||
int i, ret;
|
||||
|
||||
|
|
@ -59,7 +59,7 @@ static u8 clk_rcg_get_parent(struct clk_hw *hw)
|
|||
|
||||
err:
|
||||
pr_debug("%s: Clock %s has invalid parent, using default.\n",
|
||||
__func__, __clk_get_name(hw->clk));
|
||||
__func__, clk_hw_get_name(hw));
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -72,7 +72,7 @@ static int reg_to_bank(struct clk_dyn_rcg *rcg, u32 bank)
|
|||
static u8 clk_dyn_rcg_get_parent(struct clk_hw *hw)
|
||||
{
|
||||
struct clk_dyn_rcg *rcg = to_clk_dyn_rcg(hw);
|
||||
int num_parents = __clk_get_num_parents(hw->clk);
|
||||
int num_parents = clk_hw_get_num_parents(hw);
|
||||
u32 ns, reg;
|
||||
int bank;
|
||||
int i, ret;
|
||||
|
|
@ -95,7 +95,7 @@ static u8 clk_dyn_rcg_get_parent(struct clk_hw *hw)
|
|||
|
||||
err:
|
||||
pr_debug("%s: Clock %s has invalid parent, using default.\n",
|
||||
__func__, __clk_get_name(hw->clk));
|
||||
__func__, clk_hw_get_name(hw));
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -404,14 +404,12 @@ clk_dyn_rcg_recalc_rate(struct clk_hw *hw, unsigned long parent_rate)
|
|||
return calc_rate(parent_rate, m, n, mode, pre_div);
|
||||
}
|
||||
|
||||
static long _freq_tbl_determine_rate(struct clk_hw *hw,
|
||||
const struct freq_tbl *f, unsigned long rate,
|
||||
unsigned long min_rate, unsigned long max_rate,
|
||||
unsigned long *p_rate, struct clk_hw **p_hw,
|
||||
static int _freq_tbl_determine_rate(struct clk_hw *hw, const struct freq_tbl *f,
|
||||
struct clk_rate_request *req,
|
||||
const struct parent_map *parent_map)
|
||||
{
|
||||
unsigned long clk_flags;
|
||||
struct clk *p;
|
||||
unsigned long clk_flags, rate = req->rate;
|
||||
struct clk_hw *p;
|
||||
int index;
|
||||
|
||||
f = qcom_find_freq(f, rate);
|
||||
|
|
@ -422,8 +420,8 @@ static long _freq_tbl_determine_rate(struct clk_hw *hw,
|
|||
if (index < 0)
|
||||
return index;
|
||||
|
||||
clk_flags = __clk_get_flags(hw->clk);
|
||||
p = clk_get_parent_by_index(hw->clk, index);
|
||||
clk_flags = clk_hw_get_flags(hw);
|
||||
p = clk_hw_get_parent_by_index(hw, index);
|
||||
if (clk_flags & CLK_SET_RATE_PARENT) {
|
||||
rate = rate * f->pre_div;
|
||||
if (f->n) {
|
||||
|
|
@ -433,27 +431,26 @@ static long _freq_tbl_determine_rate(struct clk_hw *hw,
|
|||
rate = tmp;
|
||||
}
|
||||
} else {
|
||||
rate = __clk_get_rate(p);
|
||||
rate = clk_hw_get_rate(p);
|
||||
}
|
||||
*p_hw = __clk_get_hw(p);
|
||||
*p_rate = rate;
|
||||
req->best_parent_hw = p;
|
||||
req->best_parent_rate = rate;
|
||||
req->rate = f->freq;
|
||||
|
||||
return f->freq;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static long clk_rcg_determine_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long min_rate, unsigned long max_rate,
|
||||
unsigned long *p_rate, struct clk_hw **p)
|
||||
static int clk_rcg_determine_rate(struct clk_hw *hw,
|
||||
struct clk_rate_request *req)
|
||||
{
|
||||
struct clk_rcg *rcg = to_clk_rcg(hw);
|
||||
|
||||
return _freq_tbl_determine_rate(hw, rcg->freq_tbl, rate, min_rate,
|
||||
max_rate, p_rate, p, rcg->s.parent_map);
|
||||
return _freq_tbl_determine_rate(hw, rcg->freq_tbl, req,
|
||||
rcg->s.parent_map);
|
||||
}
|
||||
|
||||
static long clk_dyn_rcg_determine_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long min_rate, unsigned long max_rate,
|
||||
unsigned long *p_rate, struct clk_hw **p)
|
||||
static int clk_dyn_rcg_determine_rate(struct clk_hw *hw,
|
||||
struct clk_rate_request *req)
|
||||
{
|
||||
struct clk_dyn_rcg *rcg = to_clk_dyn_rcg(hw);
|
||||
u32 reg;
|
||||
|
|
@ -464,24 +461,22 @@ static long clk_dyn_rcg_determine_rate(struct clk_hw *hw, unsigned long rate,
|
|||
bank = reg_to_bank(rcg, reg);
|
||||
s = &rcg->s[bank];
|
||||
|
||||
return _freq_tbl_determine_rate(hw, rcg->freq_tbl, rate, min_rate,
|
||||
max_rate, p_rate, p, s->parent_map);
|
||||
return _freq_tbl_determine_rate(hw, rcg->freq_tbl, req, s->parent_map);
|
||||
}
|
||||
|
||||
static long clk_rcg_bypass_determine_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long min_rate, unsigned long max_rate,
|
||||
unsigned long *p_rate, struct clk_hw **p_hw)
|
||||
static int clk_rcg_bypass_determine_rate(struct clk_hw *hw,
|
||||
struct clk_rate_request *req)
|
||||
{
|
||||
struct clk_rcg *rcg = to_clk_rcg(hw);
|
||||
const struct freq_tbl *f = rcg->freq_tbl;
|
||||
struct clk *p;
|
||||
struct clk_hw *p;
|
||||
int index = qcom_find_src_index(hw, rcg->s.parent_map, f->src);
|
||||
|
||||
p = clk_get_parent_by_index(hw->clk, index);
|
||||
*p_hw = __clk_get_hw(p);
|
||||
*p_rate = __clk_round_rate(p, rate);
|
||||
req->best_parent_hw = p = clk_hw_get_parent_by_index(hw, index);
|
||||
req->best_parent_rate = clk_hw_round_rate(p, req->rate);
|
||||
req->rate = req->best_parent_rate;
|
||||
|
||||
return *p_rate;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __clk_rcg_set_rate(struct clk_rcg *rcg, const struct freq_tbl *f)
|
||||
|
|
|
|||
|
|
@ -63,7 +63,7 @@ static int clk_rcg2_is_enabled(struct clk_hw *hw)
|
|||
static u8 clk_rcg2_get_parent(struct clk_hw *hw)
|
||||
{
|
||||
struct clk_rcg2 *rcg = to_clk_rcg2(hw);
|
||||
int num_parents = __clk_get_num_parents(hw->clk);
|
||||
int num_parents = clk_hw_get_num_parents(hw);
|
||||
u32 cfg;
|
||||
int i, ret;
|
||||
|
||||
|
|
@ -80,7 +80,7 @@ static u8 clk_rcg2_get_parent(struct clk_hw *hw)
|
|||
|
||||
err:
|
||||
pr_debug("%s: Clock %s has invalid parent, using default.\n",
|
||||
__func__, __clk_get_name(hw->clk));
|
||||
__func__, clk_hw_get_name(hw));
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -89,7 +89,7 @@ static int update_config(struct clk_rcg2 *rcg)
|
|||
int count, ret;
|
||||
u32 cmd;
|
||||
struct clk_hw *hw = &rcg->clkr.hw;
|
||||
const char *name = __clk_get_name(hw->clk);
|
||||
const char *name = clk_hw_get_name(hw);
|
||||
|
||||
ret = regmap_update_bits(rcg->clkr.regmap, rcg->cmd_rcgr + CMD_REG,
|
||||
CMD_UPDATE, CMD_UPDATE);
|
||||
|
|
@ -176,12 +176,11 @@ clk_rcg2_recalc_rate(struct clk_hw *hw, unsigned long parent_rate)
|
|||
return calc_rate(parent_rate, m, n, mode, hid_div);
|
||||
}
|
||||
|
||||
static long _freq_tbl_determine_rate(struct clk_hw *hw,
|
||||
const struct freq_tbl *f, unsigned long rate,
|
||||
unsigned long *p_rate, struct clk_hw **p_hw)
|
||||
static int _freq_tbl_determine_rate(struct clk_hw *hw,
|
||||
const struct freq_tbl *f, struct clk_rate_request *req)
|
||||
{
|
||||
unsigned long clk_flags;
|
||||
struct clk *p;
|
||||
unsigned long clk_flags, rate = req->rate;
|
||||
struct clk_hw *p;
|
||||
struct clk_rcg2 *rcg = to_clk_rcg2(hw);
|
||||
int index;
|
||||
|
||||
|
|
@ -193,8 +192,8 @@ static long _freq_tbl_determine_rate(struct clk_hw *hw,
|
|||
if (index < 0)
|
||||
return index;
|
||||
|
||||
clk_flags = __clk_get_flags(hw->clk);
|
||||
p = clk_get_parent_by_index(hw->clk, index);
|
||||
clk_flags = clk_hw_get_flags(hw);
|
||||
p = clk_hw_get_parent_by_index(hw, index);
|
||||
if (clk_flags & CLK_SET_RATE_PARENT) {
|
||||
if (f->pre_div) {
|
||||
rate /= 2;
|
||||
|
|
@ -208,21 +207,21 @@ static long _freq_tbl_determine_rate(struct clk_hw *hw,
|
|||
rate = tmp;
|
||||
}
|
||||
} else {
|
||||
rate = __clk_get_rate(p);
|
||||
rate = clk_hw_get_rate(p);
|
||||
}
|
||||
*p_hw = __clk_get_hw(p);
|
||||
*p_rate = rate;
|
||||
req->best_parent_hw = p;
|
||||
req->best_parent_rate = rate;
|
||||
req->rate = f->freq;
|
||||
|
||||
return f->freq;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static long clk_rcg2_determine_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long min_rate, unsigned long max_rate,
|
||||
unsigned long *p_rate, struct clk_hw **p)
|
||||
static int clk_rcg2_determine_rate(struct clk_hw *hw,
|
||||
struct clk_rate_request *req)
|
||||
{
|
||||
struct clk_rcg2 *rcg = to_clk_rcg2(hw);
|
||||
|
||||
return _freq_tbl_determine_rate(hw, rcg->freq_tbl, rate, p_rate, p);
|
||||
return _freq_tbl_determine_rate(hw, rcg->freq_tbl, req);
|
||||
}
|
||||
|
||||
static int clk_rcg2_configure(struct clk_rcg2 *rcg, const struct freq_tbl *f)
|
||||
|
|
@ -374,35 +373,33 @@ static int clk_edp_pixel_set_rate_and_parent(struct clk_hw *hw,
|
|||
return clk_edp_pixel_set_rate(hw, rate, parent_rate);
|
||||
}
|
||||
|
||||
static long clk_edp_pixel_determine_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long min_rate,
|
||||
unsigned long max_rate,
|
||||
unsigned long *p_rate, struct clk_hw **p)
|
||||
static int clk_edp_pixel_determine_rate(struct clk_hw *hw,
|
||||
struct clk_rate_request *req)
|
||||
{
|
||||
struct clk_rcg2 *rcg = to_clk_rcg2(hw);
|
||||
const struct freq_tbl *f = rcg->freq_tbl;
|
||||
const struct frac_entry *frac;
|
||||
int delta = 100000;
|
||||
s64 src_rate = *p_rate;
|
||||
s64 request;
|
||||
u32 mask = BIT(rcg->hid_width) - 1;
|
||||
u32 hid_div;
|
||||
int index = qcom_find_src_index(hw, rcg->parent_map, f->src);
|
||||
|
||||
/* Force the correct parent */
|
||||
*p = __clk_get_hw(clk_get_parent_by_index(hw->clk, index));
|
||||
req->best_parent_hw = clk_hw_get_parent_by_index(hw, index);
|
||||
req->best_parent_rate = clk_hw_get_rate(req->best_parent_hw);
|
||||
|
||||
if (src_rate == 810000000)
|
||||
if (req->best_parent_rate == 810000000)
|
||||
frac = frac_table_810m;
|
||||
else
|
||||
frac = frac_table_675m;
|
||||
|
||||
for (; frac->num; frac++) {
|
||||
request = rate;
|
||||
request = req->rate;
|
||||
request *= frac->den;
|
||||
request = div_s64(request, frac->num);
|
||||
if ((src_rate < (request - delta)) ||
|
||||
(src_rate > (request + delta)))
|
||||
if ((req->best_parent_rate < (request - delta)) ||
|
||||
(req->best_parent_rate > (request + delta)))
|
||||
continue;
|
||||
|
||||
regmap_read(rcg->clkr.regmap, rcg->cmd_rcgr + CFG_REG,
|
||||
|
|
@ -410,8 +407,10 @@ static long clk_edp_pixel_determine_rate(struct clk_hw *hw, unsigned long rate,
|
|||
hid_div >>= CFG_SRC_DIV_SHIFT;
|
||||
hid_div &= mask;
|
||||
|
||||
return calc_rate(src_rate, frac->num, frac->den, !!frac->den,
|
||||
hid_div);
|
||||
req->rate = calc_rate(req->best_parent_rate,
|
||||
frac->num, frac->den,
|
||||
!!frac->den, hid_div);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -EINVAL;
|
||||
|
|
@ -428,28 +427,28 @@ const struct clk_ops clk_edp_pixel_ops = {
|
|||
};
|
||||
EXPORT_SYMBOL_GPL(clk_edp_pixel_ops);
|
||||
|
||||
static long clk_byte_determine_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long min_rate, unsigned long max_rate,
|
||||
unsigned long *p_rate, struct clk_hw **p_hw)
|
||||
static int clk_byte_determine_rate(struct clk_hw *hw,
|
||||
struct clk_rate_request *req)
|
||||
{
|
||||
struct clk_rcg2 *rcg = to_clk_rcg2(hw);
|
||||
const struct freq_tbl *f = rcg->freq_tbl;
|
||||
int index = qcom_find_src_index(hw, rcg->parent_map, f->src);
|
||||
unsigned long parent_rate, div;
|
||||
u32 mask = BIT(rcg->hid_width) - 1;
|
||||
struct clk *p;
|
||||
struct clk_hw *p;
|
||||
|
||||
if (rate == 0)
|
||||
if (req->rate == 0)
|
||||
return -EINVAL;
|
||||
|
||||
p = clk_get_parent_by_index(hw->clk, index);
|
||||
*p_hw = __clk_get_hw(p);
|
||||
*p_rate = parent_rate = __clk_round_rate(p, rate);
|
||||
req->best_parent_hw = p = clk_hw_get_parent_by_index(hw, index);
|
||||
req->best_parent_rate = parent_rate = clk_hw_round_rate(p, req->rate);
|
||||
|
||||
div = DIV_ROUND_UP((2 * parent_rate), rate) - 1;
|
||||
div = DIV_ROUND_UP((2 * parent_rate), req->rate) - 1;
|
||||
div = min_t(u32, div, mask);
|
||||
|
||||
return calc_rate(parent_rate, 0, 0, 0, div);
|
||||
req->rate = calc_rate(parent_rate, 0, 0, 0, div);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int clk_byte_set_rate(struct clk_hw *hw, unsigned long rate,
|
||||
|
|
@ -494,10 +493,8 @@ static const struct frac_entry frac_table_pixel[] = {
|
|||
{ }
|
||||
};
|
||||
|
||||
static long clk_pixel_determine_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long min_rate,
|
||||
unsigned long max_rate,
|
||||
unsigned long *p_rate, struct clk_hw **p)
|
||||
static int clk_pixel_determine_rate(struct clk_hw *hw,
|
||||
struct clk_rate_request *req)
|
||||
{
|
||||
struct clk_rcg2 *rcg = to_clk_rcg2(hw);
|
||||
unsigned long request, src_rate;
|
||||
|
|
@ -505,20 +502,20 @@ static long clk_pixel_determine_rate(struct clk_hw *hw, unsigned long rate,
|
|||
const struct freq_tbl *f = rcg->freq_tbl;
|
||||
const struct frac_entry *frac = frac_table_pixel;
|
||||
int index = qcom_find_src_index(hw, rcg->parent_map, f->src);
|
||||
struct clk *parent = clk_get_parent_by_index(hw->clk, index);
|
||||
|
||||
*p = __clk_get_hw(parent);
|
||||
req->best_parent_hw = clk_hw_get_parent_by_index(hw, index);
|
||||
|
||||
for (; frac->num; frac++) {
|
||||
request = (rate * frac->den) / frac->num;
|
||||
request = (req->rate * frac->den) / frac->num;
|
||||
|
||||
src_rate = __clk_round_rate(parent, request);
|
||||
src_rate = clk_hw_round_rate(req->best_parent_hw, request);
|
||||
if ((src_rate < (request - delta)) ||
|
||||
(src_rate > (request + delta)))
|
||||
continue;
|
||||
|
||||
*p_rate = src_rate;
|
||||
return (src_rate * frac->num) / frac->den;
|
||||
req->best_parent_rate = src_rate;
|
||||
req->rate = (src_rate * frac->num) / frac->den;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -EINVAL;
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@
|
|||
*/
|
||||
|
||||
#include <linux/export.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/clk-provider.h>
|
||||
|
|
@ -45,7 +46,7 @@ EXPORT_SYMBOL_GPL(qcom_find_freq);
|
|||
|
||||
int qcom_find_src_index(struct clk_hw *hw, const struct parent_map *map, u8 src)
|
||||
{
|
||||
int i, num_parents = __clk_get_num_parents(hw->clk);
|
||||
int i, num_parents = clk_hw_get_num_parents(hw);
|
||||
|
||||
for (i = 0; i < num_parents; i++)
|
||||
if (src == map[i].src)
|
||||
|
|
@ -144,3 +145,5 @@ void qcom_cc_remove(struct platform_device *pdev)
|
|||
reset_controller_unregister(platform_get_drvdata(pdev));
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(qcom_cc_remove);
|
||||
|
||||
MODULE_LICENSE("GPL v2");
|
||||
|
|
|
|||
|
|
@ -48,7 +48,7 @@ static const struct parent_map gcc_xo_gpll0_map[] = {
|
|||
{ P_GPLL0, 1 }
|
||||
};
|
||||
|
||||
static const char *gcc_xo_gpll0[] = {
|
||||
static const char * const gcc_xo_gpll0[] = {
|
||||
"xo",
|
||||
"gpll0_vote",
|
||||
};
|
||||
|
|
@ -59,7 +59,7 @@ static const struct parent_map gcc_xo_gpll0_gpll4_map[] = {
|
|||
{ P_GPLL4, 5 }
|
||||
};
|
||||
|
||||
static const char *gcc_xo_gpll0_gpll4[] = {
|
||||
static const char * const gcc_xo_gpll0_gpll4[] = {
|
||||
"xo",
|
||||
"gpll0_vote",
|
||||
"gpll4_vote",
|
||||
|
|
@ -70,7 +70,7 @@ static const struct parent_map gcc_xo_sata_asic0_map[] = {
|
|||
{ P_SATA_ASIC0_CLK, 2 }
|
||||
};
|
||||
|
||||
static const char *gcc_xo_sata_asic0[] = {
|
||||
static const char * const gcc_xo_sata_asic0[] = {
|
||||
"xo",
|
||||
"sata_asic0_clk",
|
||||
};
|
||||
|
|
@ -80,7 +80,7 @@ static const struct parent_map gcc_xo_sata_rx_map[] = {
|
|||
{ P_SATA_RX_CLK, 2}
|
||||
};
|
||||
|
||||
static const char *gcc_xo_sata_rx[] = {
|
||||
static const char * const gcc_xo_sata_rx[] = {
|
||||
"xo",
|
||||
"sata_rx_clk",
|
||||
};
|
||||
|
|
@ -90,7 +90,7 @@ static const struct parent_map gcc_xo_pcie_map[] = {
|
|||
{ P_PCIE_0_1_PIPE_CLK, 2 }
|
||||
};
|
||||
|
||||
static const char *gcc_xo_pcie[] = {
|
||||
static const char * const gcc_xo_pcie[] = {
|
||||
"xo",
|
||||
"pcie_pipe",
|
||||
};
|
||||
|
|
@ -100,7 +100,7 @@ static const struct parent_map gcc_xo_pcie_sleep_map[] = {
|
|||
{ P_SLEEP_CLK, 6 }
|
||||
};
|
||||
|
||||
static const char *gcc_xo_pcie_sleep[] = {
|
||||
static const char * const gcc_xo_pcie_sleep[] = {
|
||||
"xo",
|
||||
"sleep_clk_src",
|
||||
};
|
||||
|
|
@ -2105,6 +2105,7 @@ static struct clk_branch gcc_ce1_clk = {
|
|||
"ce1_clk_src",
|
||||
},
|
||||
.num_parents = 1,
|
||||
.flags = CLK_SET_RATE_PARENT,
|
||||
.ops = &clk_branch2_ops,
|
||||
},
|
||||
},
|
||||
|
|
|
|||
|
|
@ -188,7 +188,7 @@ static const struct parent_map gcc_pxo_pll8_map[] = {
|
|||
{ P_PLL8, 3 }
|
||||
};
|
||||
|
||||
static const char *gcc_pxo_pll8[] = {
|
||||
static const char * const gcc_pxo_pll8[] = {
|
||||
"pxo",
|
||||
"pll8_vote",
|
||||
};
|
||||
|
|
@ -199,7 +199,7 @@ static const struct parent_map gcc_pxo_pll8_cxo_map[] = {
|
|||
{ P_CXO, 5 }
|
||||
};
|
||||
|
||||
static const char *gcc_pxo_pll8_cxo[] = {
|
||||
static const char * const gcc_pxo_pll8_cxo[] = {
|
||||
"pxo",
|
||||
"pll8_vote",
|
||||
"cxo",
|
||||
|
|
@ -215,7 +215,7 @@ static const struct parent_map gcc_pxo_pll3_sata_map[] = {
|
|||
{ P_PLL3, 6 }
|
||||
};
|
||||
|
||||
static const char *gcc_pxo_pll3[] = {
|
||||
static const char * const gcc_pxo_pll3[] = {
|
||||
"pxo",
|
||||
"pll3",
|
||||
};
|
||||
|
|
@ -226,7 +226,7 @@ static const struct parent_map gcc_pxo_pll8_pll0[] = {
|
|||
{ P_PLL0, 2 }
|
||||
};
|
||||
|
||||
static const char *gcc_pxo_pll8_pll0_map[] = {
|
||||
static const char * const gcc_pxo_pll8_pll0_map[] = {
|
||||
"pxo",
|
||||
"pll8_vote",
|
||||
"pll0_vote",
|
||||
|
|
@ -240,7 +240,7 @@ static const struct parent_map gcc_pxo_pll8_pll14_pll18_pll0_map[] = {
|
|||
{ P_PLL18, 1 }
|
||||
};
|
||||
|
||||
static const char *gcc_pxo_pll8_pll14_pll18_pll0[] = {
|
||||
static const char * const gcc_pxo_pll8_pll14_pll18_pll0[] = {
|
||||
"pxo",
|
||||
"pll8_vote",
|
||||
"pll0_vote",
|
||||
|
|
|
|||
|
|
@ -70,7 +70,7 @@ static const struct parent_map gcc_pxo_pll8_map[] = {
|
|||
{ P_PLL8, 3 }
|
||||
};
|
||||
|
||||
static const char *gcc_pxo_pll8[] = {
|
||||
static const char * const gcc_pxo_pll8[] = {
|
||||
"pxo",
|
||||
"pll8_vote",
|
||||
};
|
||||
|
|
@ -81,7 +81,7 @@ static const struct parent_map gcc_pxo_pll8_cxo_map[] = {
|
|||
{ P_CXO, 5 }
|
||||
};
|
||||
|
||||
static const char *gcc_pxo_pll8_cxo[] = {
|
||||
static const char * const gcc_pxo_pll8_cxo[] = {
|
||||
"pxo",
|
||||
"pll8_vote",
|
||||
"cxo",
|
||||
|
|
@ -1917,7 +1917,7 @@ static struct clk_rcg usb_fs1_xcvr_fs_src = {
|
|||
}
|
||||
};
|
||||
|
||||
static const char *usb_fs1_xcvr_fs_src_p[] = { "usb_fs1_xcvr_fs_src" };
|
||||
static const char * const usb_fs1_xcvr_fs_src_p[] = { "usb_fs1_xcvr_fs_src" };
|
||||
|
||||
static struct clk_branch usb_fs1_xcvr_fs_clk = {
|
||||
.halt_reg = 0x2fcc,
|
||||
|
|
@ -1984,7 +1984,7 @@ static struct clk_rcg usb_fs2_xcvr_fs_src = {
|
|||
}
|
||||
};
|
||||
|
||||
static const char *usb_fs2_xcvr_fs_src_p[] = { "usb_fs2_xcvr_fs_src" };
|
||||
static const char * const usb_fs2_xcvr_fs_src_p[] = { "usb_fs2_xcvr_fs_src" };
|
||||
|
||||
static struct clk_branch usb_fs2_xcvr_fs_clk = {
|
||||
.halt_reg = 0x2fcc,
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue