Merge branches 'clk-ti', 'clk-analog', 'clk-trace', 'clk-at91' and 'clk-silabs' into clk-next
- Add some trace points for clk_set_rate() "range" functions - DVFS support for AT91 clk driver * clk-ti: clk: ti: omap5: Fix reboot DPLL lock failure when using ABE TIMERs clk: ti: Fix memleak in ti_fapll_synth_setup * clk-analog: clk: axi-clkgen: move the OF table at the bottom of the file clk: axi-clkgen: wrap limits in a struct and keep copy on the state object dt-bindings: clock: adi,axi-clkgen: convert old binding to yaml format * clk-trace: clk: Trace clk_set_rate() "range" functions * clk-at91: clk: at91: sam9x60: remove atmel,osc-bypass support clk: at91: sama7g5: register cpu clock clk: at91: clk-master: re-factor master clock clk: at91: sama7g5: do not allow cpu pll to go higher than 1GHz clk: at91: sama7g5: decrease lower limit for MCK0 rate clk: at91: sama7g5: remove mck0 from parent list of other clocks clk: at91: clk-sam9x60-pll: allow runtime changes for pll clk: at91: sama7g5: add 5th divisor for mck0 layout and characteristics clk: at91: clk-master: add 5th divisor for mck master clk: at91: sama7g5: allow SYS and CPU PLLs to be exported and referenced in DT dt-bindings: clock: at91: add sama7g5 pll defines clk: at91: sama7g5: fix compilation error * clk-silabs: clk: si5351: Wait for bit clear after PLL reset
This commit is contained in:
commit
b53a1603b4
|
@ -0,0 +1,53 @@
|
|||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/clock/adi,axi-clkgen.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Binding for Analog Devices AXI clkgen pcore clock generator
|
||||
|
||||
maintainers:
|
||||
- Lars-Peter Clausen <lars@metafoo.de>
|
||||
- Michael Hennerich <michael.hennerich@analog.com>
|
||||
|
||||
description: |
|
||||
The axi_clkgen IP core is a software programmable clock generator,
|
||||
that can be synthesized on various FPGA platforms.
|
||||
|
||||
Link: https://wiki.analog.com/resources/fpga/docs/axi_clkgen
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- adi,axi-clkgen-2.00.a
|
||||
|
||||
clocks:
|
||||
description:
|
||||
Specifies the reference clock(s) from which the output frequency is
|
||||
derived. This must either reference one clock if only the first clock
|
||||
input is connected or two if both clock inputs are connected.
|
||||
minItems: 1
|
||||
maxItems: 2
|
||||
|
||||
'#clock-cells':
|
||||
const: 0
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- clocks
|
||||
- '#clock-cells'
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
clock-controller@ff000000 {
|
||||
compatible = "adi,axi-clkgen-2.00.a";
|
||||
#clock-cells = <0>;
|
||||
reg = <0xff000000 0x1000>;
|
||||
clocks = <&osc 1>;
|
||||
};
|
|
@ -1,25 +0,0 @@
|
|||
Binding for the axi-clkgen clock generator
|
||||
|
||||
This binding uses the common clock binding[1].
|
||||
|
||||
[1] Documentation/devicetree/bindings/clock/clock-bindings.txt
|
||||
|
||||
Required properties:
|
||||
- compatible : shall be "adi,axi-clkgen-1.00.a" or "adi,axi-clkgen-2.00.a".
|
||||
- #clock-cells : from common clock binding; Should always be set to 0.
|
||||
- reg : Address and length of the axi-clkgen register set.
|
||||
- clocks : Phandle and clock specifier for the parent clock(s). This must
|
||||
either reference one clock if only the first clock input is connected or two
|
||||
if both clock inputs are connected. For the later case the clock connected
|
||||
to the first input must be specified first.
|
||||
|
||||
Optional properties:
|
||||
- clock-output-names : From common clock binding.
|
||||
|
||||
Example:
|
||||
clock@ff000000 {
|
||||
compatible = "adi,axi-clkgen";
|
||||
#clock-cells = <0>;
|
||||
reg = <0xff000000 0x1000>;
|
||||
clocks = <&osc 1>;
|
||||
};
|
|
@ -7,6 +7,8 @@
|
|||
|
||||
#include "pmc.h"
|
||||
|
||||
static DEFINE_SPINLOCK(rm9200_mck_lock);
|
||||
|
||||
struct sck {
|
||||
char *n;
|
||||
char *p;
|
||||
|
@ -137,9 +139,20 @@ static void __init at91rm9200_pmc_setup(struct device_node *np)
|
|||
parent_names[1] = "mainck";
|
||||
parent_names[2] = "pllack";
|
||||
parent_names[3] = "pllbck";
|
||||
hw = at91_clk_register_master(regmap, "masterck", 4, parent_names,
|
||||
&at91rm9200_master_layout,
|
||||
&rm9200_mck_characteristics);
|
||||
hw = at91_clk_register_master_pres(regmap, "masterck_pres", 4,
|
||||
parent_names,
|
||||
&at91rm9200_master_layout,
|
||||
&rm9200_mck_characteristics,
|
||||
&rm9200_mck_lock, CLK_SET_RATE_GATE,
|
||||
INT_MIN);
|
||||
if (IS_ERR(hw))
|
||||
goto err_free;
|
||||
|
||||
hw = at91_clk_register_master_div(regmap, "masterck_div",
|
||||
"masterck_pres",
|
||||
&at91rm9200_master_layout,
|
||||
&rm9200_mck_characteristics,
|
||||
&rm9200_mck_lock, CLK_SET_RATE_GATE);
|
||||
if (IS_ERR(hw))
|
||||
goto err_free;
|
||||
|
||||
|
@ -181,7 +194,7 @@ static void __init at91rm9200_pmc_setup(struct device_node *np)
|
|||
for (i = 0; i < ARRAY_SIZE(at91rm9200_periphck); i++) {
|
||||
hw = at91_clk_register_peripheral(regmap,
|
||||
at91rm9200_periphck[i].n,
|
||||
"masterck",
|
||||
"masterck_div",
|
||||
at91rm9200_periphck[i].id);
|
||||
if (IS_ERR(hw))
|
||||
goto err_free;
|
||||
|
|
|
@ -32,6 +32,8 @@ struct at91sam926x_data {
|
|||
bool has_slck;
|
||||
};
|
||||
|
||||
static DEFINE_SPINLOCK(at91sam9260_mck_lock);
|
||||
|
||||
static const struct clk_master_characteristics sam9260_mck_characteristics = {
|
||||
.output = { .min = 0, .max = 105000000 },
|
||||
.divisors = { 1, 2, 4, 0 },
|
||||
|
@ -218,8 +220,8 @@ static const struct sck at91sam9261_systemck[] = {
|
|||
{ .n = "pck1", .p = "prog1", .id = 9 },
|
||||
{ .n = "pck2", .p = "prog2", .id = 10 },
|
||||
{ .n = "pck3", .p = "prog3", .id = 11 },
|
||||
{ .n = "hclk0", .p = "masterck", .id = 16 },
|
||||
{ .n = "hclk1", .p = "masterck", .id = 17 },
|
||||
{ .n = "hclk0", .p = "masterck_div", .id = 16 },
|
||||
{ .n = "hclk1", .p = "masterck_div", .id = 17 },
|
||||
};
|
||||
|
||||
static const struct pck at91sam9261_periphck[] = {
|
||||
|
@ -413,9 +415,21 @@ static void __init at91sam926x_pmc_setup(struct device_node *np,
|
|||
parent_names[1] = "mainck";
|
||||
parent_names[2] = "pllack";
|
||||
parent_names[3] = "pllbck";
|
||||
hw = at91_clk_register_master(regmap, "masterck", 4, parent_names,
|
||||
&at91rm9200_master_layout,
|
||||
data->mck_characteristics);
|
||||
hw = at91_clk_register_master_pres(regmap, "masterck_pres", 4,
|
||||
parent_names,
|
||||
&at91rm9200_master_layout,
|
||||
data->mck_characteristics,
|
||||
&at91sam9260_mck_lock,
|
||||
CLK_SET_RATE_GATE, INT_MIN);
|
||||
if (IS_ERR(hw))
|
||||
goto err_free;
|
||||
|
||||
hw = at91_clk_register_master_div(regmap, "masterck_div",
|
||||
"masterck_pres",
|
||||
&at91rm9200_master_layout,
|
||||
data->mck_characteristics,
|
||||
&at91sam9260_mck_lock,
|
||||
CLK_SET_RATE_GATE);
|
||||
if (IS_ERR(hw))
|
||||
goto err_free;
|
||||
|
||||
|
@ -457,7 +471,7 @@ static void __init at91sam926x_pmc_setup(struct device_node *np,
|
|||
for (i = 0; i < data->num_pck; i++) {
|
||||
hw = at91_clk_register_peripheral(regmap,
|
||||
data->pck[i].n,
|
||||
"masterck",
|
||||
"masterck_div",
|
||||
data->pck[i].id);
|
||||
if (IS_ERR(hw))
|
||||
goto err_free;
|
||||
|
|
|
@ -7,6 +7,8 @@
|
|||
|
||||
#include "pmc.h"
|
||||
|
||||
static DEFINE_SPINLOCK(at91sam9g45_mck_lock);
|
||||
|
||||
static const struct clk_master_characteristics mck_characteristics = {
|
||||
.output = { .min = 0, .max = 133333333 },
|
||||
.divisors = { 1, 2, 4, 3 },
|
||||
|
@ -40,10 +42,10 @@ static const struct {
|
|||
char *p;
|
||||
u8 id;
|
||||
} at91sam9g45_systemck[] = {
|
||||
{ .n = "ddrck", .p = "masterck", .id = 2 },
|
||||
{ .n = "uhpck", .p = "usbck", .id = 6 },
|
||||
{ .n = "pck0", .p = "prog0", .id = 8 },
|
||||
{ .n = "pck1", .p = "prog1", .id = 9 },
|
||||
{ .n = "ddrck", .p = "masterck_div", .id = 2 },
|
||||
{ .n = "uhpck", .p = "usbck", .id = 6 },
|
||||
{ .n = "pck0", .p = "prog0", .id = 8 },
|
||||
{ .n = "pck1", .p = "prog1", .id = 9 },
|
||||
};
|
||||
|
||||
struct pck {
|
||||
|
@ -148,9 +150,21 @@ static void __init at91sam9g45_pmc_setup(struct device_node *np)
|
|||
parent_names[1] = "mainck";
|
||||
parent_names[2] = "plladivck";
|
||||
parent_names[3] = "utmick";
|
||||
hw = at91_clk_register_master(regmap, "masterck", 4, parent_names,
|
||||
&at91rm9200_master_layout,
|
||||
&mck_characteristics);
|
||||
hw = at91_clk_register_master_pres(regmap, "masterck_pres", 4,
|
||||
parent_names,
|
||||
&at91rm9200_master_layout,
|
||||
&mck_characteristics,
|
||||
&at91sam9g45_mck_lock,
|
||||
CLK_SET_RATE_GATE, INT_MIN);
|
||||
if (IS_ERR(hw))
|
||||
goto err_free;
|
||||
|
||||
hw = at91_clk_register_master_div(regmap, "masterck_div",
|
||||
"masterck_pres",
|
||||
&at91rm9200_master_layout,
|
||||
&mck_characteristics,
|
||||
&at91sam9g45_mck_lock,
|
||||
CLK_SET_RATE_GATE);
|
||||
if (IS_ERR(hw))
|
||||
goto err_free;
|
||||
|
||||
|
@ -166,7 +180,7 @@ static void __init at91sam9g45_pmc_setup(struct device_node *np)
|
|||
parent_names[1] = "mainck";
|
||||
parent_names[2] = "plladivck";
|
||||
parent_names[3] = "utmick";
|
||||
parent_names[4] = "masterck";
|
||||
parent_names[4] = "masterck_div";
|
||||
for (i = 0; i < 2; i++) {
|
||||
char name[6];
|
||||
|
||||
|
@ -195,7 +209,7 @@ static void __init at91sam9g45_pmc_setup(struct device_node *np)
|
|||
for (i = 0; i < ARRAY_SIZE(at91sam9g45_periphck); i++) {
|
||||
hw = at91_clk_register_peripheral(regmap,
|
||||
at91sam9g45_periphck[i].n,
|
||||
"masterck",
|
||||
"masterck_div",
|
||||
at91sam9g45_periphck[i].id);
|
||||
if (IS_ERR(hw))
|
||||
goto err_free;
|
||||
|
|
|
@ -7,6 +7,8 @@
|
|||
|
||||
#include "pmc.h"
|
||||
|
||||
static DEFINE_SPINLOCK(at91sam9n12_mck_lock);
|
||||
|
||||
static const struct clk_master_characteristics mck_characteristics = {
|
||||
.output = { .min = 0, .max = 133333333 },
|
||||
.divisors = { 1, 2, 4, 3 },
|
||||
|
@ -54,12 +56,12 @@ static const struct {
|
|||
char *p;
|
||||
u8 id;
|
||||
} at91sam9n12_systemck[] = {
|
||||
{ .n = "ddrck", .p = "masterck", .id = 2 },
|
||||
{ .n = "lcdck", .p = "masterck", .id = 3 },
|
||||
{ .n = "uhpck", .p = "usbck", .id = 6 },
|
||||
{ .n = "udpck", .p = "usbck", .id = 7 },
|
||||
{ .n = "pck0", .p = "prog0", .id = 8 },
|
||||
{ .n = "pck1", .p = "prog1", .id = 9 },
|
||||
{ .n = "ddrck", .p = "masterck_div", .id = 2 },
|
||||
{ .n = "lcdck", .p = "masterck_div", .id = 3 },
|
||||
{ .n = "uhpck", .p = "usbck", .id = 6 },
|
||||
{ .n = "udpck", .p = "usbck", .id = 7 },
|
||||
{ .n = "pck0", .p = "prog0", .id = 8 },
|
||||
{ .n = "pck1", .p = "prog1", .id = 9 },
|
||||
};
|
||||
|
||||
static const struct clk_pcr_layout at91sam9n12_pcr_layout = {
|
||||
|
@ -175,9 +177,21 @@ static void __init at91sam9n12_pmc_setup(struct device_node *np)
|
|||
parent_names[1] = "mainck";
|
||||
parent_names[2] = "plladivck";
|
||||
parent_names[3] = "pllbck";
|
||||
hw = at91_clk_register_master(regmap, "masterck", 4, parent_names,
|
||||
&at91sam9x5_master_layout,
|
||||
&mck_characteristics);
|
||||
hw = at91_clk_register_master_pres(regmap, "masterck_pres", 4,
|
||||
parent_names,
|
||||
&at91sam9x5_master_layout,
|
||||
&mck_characteristics,
|
||||
&at91sam9n12_mck_lock,
|
||||
CLK_SET_RATE_GATE, INT_MIN);
|
||||
if (IS_ERR(hw))
|
||||
goto err_free;
|
||||
|
||||
hw = at91_clk_register_master_div(regmap, "masterck_div",
|
||||
"masterck_pres",
|
||||
&at91sam9x5_master_layout,
|
||||
&mck_characteristics,
|
||||
&at91sam9n12_mck_lock,
|
||||
CLK_SET_RATE_GATE);
|
||||
if (IS_ERR(hw))
|
||||
goto err_free;
|
||||
|
||||
|
@ -191,7 +205,7 @@ static void __init at91sam9n12_pmc_setup(struct device_node *np)
|
|||
parent_names[1] = "mainck";
|
||||
parent_names[2] = "plladivck";
|
||||
parent_names[3] = "pllbck";
|
||||
parent_names[4] = "masterck";
|
||||
parent_names[4] = "masterck_div";
|
||||
for (i = 0; i < 2; i++) {
|
||||
char name[6];
|
||||
|
||||
|
@ -221,7 +235,7 @@ static void __init at91sam9n12_pmc_setup(struct device_node *np)
|
|||
hw = at91_clk_register_sam9x5_peripheral(regmap, &pmc_pcr_lock,
|
||||
&at91sam9n12_pcr_layout,
|
||||
at91sam9n12_periphck[i].n,
|
||||
"masterck",
|
||||
"masterck_div",
|
||||
at91sam9n12_periphck[i].id,
|
||||
&range, INT_MIN);
|
||||
if (IS_ERR(hw))
|
||||
|
|
|
@ -7,6 +7,8 @@
|
|||
|
||||
#include "pmc.h"
|
||||
|
||||
static DEFINE_SPINLOCK(sam9rl_mck_lock);
|
||||
|
||||
static const struct clk_master_characteristics sam9rl_mck_characteristics = {
|
||||
.output = { .min = 0, .max = 94000000 },
|
||||
.divisors = { 1, 2, 4, 0 },
|
||||
|
@ -117,9 +119,20 @@ static void __init at91sam9rl_pmc_setup(struct device_node *np)
|
|||
parent_names[1] = "mainck";
|
||||
parent_names[2] = "pllack";
|
||||
parent_names[3] = "utmick";
|
||||
hw = at91_clk_register_master(regmap, "masterck", 4, parent_names,
|
||||
&at91rm9200_master_layout,
|
||||
&sam9rl_mck_characteristics);
|
||||
hw = at91_clk_register_master_pres(regmap, "masterck_pres", 4,
|
||||
parent_names,
|
||||
&at91rm9200_master_layout,
|
||||
&sam9rl_mck_characteristics,
|
||||
&sam9rl_mck_lock, CLK_SET_RATE_GATE,
|
||||
INT_MIN);
|
||||
if (IS_ERR(hw))
|
||||
goto err_free;
|
||||
|
||||
hw = at91_clk_register_master_div(regmap, "masterck_div",
|
||||
"masterck_pres",
|
||||
&at91rm9200_master_layout,
|
||||
&sam9rl_mck_characteristics,
|
||||
&sam9rl_mck_lock, CLK_SET_RATE_GATE);
|
||||
if (IS_ERR(hw))
|
||||
goto err_free;
|
||||
|
||||
|
@ -129,7 +142,7 @@ static void __init at91sam9rl_pmc_setup(struct device_node *np)
|
|||
parent_names[1] = "mainck";
|
||||
parent_names[2] = "pllack";
|
||||
parent_names[3] = "utmick";
|
||||
parent_names[4] = "masterck";
|
||||
parent_names[4] = "masterck_div";
|
||||
for (i = 0; i < 2; i++) {
|
||||
char name[6];
|
||||
|
||||
|
@ -158,7 +171,7 @@ static void __init at91sam9rl_pmc_setup(struct device_node *np)
|
|||
for (i = 0; i < ARRAY_SIZE(at91sam9rl_periphck); i++) {
|
||||
hw = at91_clk_register_peripheral(regmap,
|
||||
at91sam9rl_periphck[i].n,
|
||||
"masterck",
|
||||
"masterck_div",
|
||||
at91sam9rl_periphck[i].id);
|
||||
if (IS_ERR(hw))
|
||||
goto err_free;
|
||||
|
|
|
@ -7,6 +7,8 @@
|
|||
|
||||
#include "pmc.h"
|
||||
|
||||
static DEFINE_SPINLOCK(mck_lock);
|
||||
|
||||
static const struct clk_master_characteristics mck_characteristics = {
|
||||
.output = { .min = 0, .max = 133333333 },
|
||||
.divisors = { 1, 2, 4, 3 },
|
||||
|
@ -41,7 +43,7 @@ static const struct {
|
|||
char *p;
|
||||
u8 id;
|
||||
} at91sam9x5_systemck[] = {
|
||||
{ .n = "ddrck", .p = "masterck", .id = 2 },
|
||||
{ .n = "ddrck", .p = "masterck_div", .id = 2 },
|
||||
{ .n = "smdck", .p = "smdclk", .id = 4 },
|
||||
{ .n = "uhpck", .p = "usbck", .id = 6 },
|
||||
{ .n = "udpck", .p = "usbck", .id = 7 },
|
||||
|
@ -196,9 +198,19 @@ static void __init at91sam9x5_pmc_setup(struct device_node *np,
|
|||
parent_names[1] = "mainck";
|
||||
parent_names[2] = "plladivck";
|
||||
parent_names[3] = "utmick";
|
||||
hw = at91_clk_register_master(regmap, "masterck", 4, parent_names,
|
||||
&at91sam9x5_master_layout,
|
||||
&mck_characteristics);
|
||||
hw = at91_clk_register_master_pres(regmap, "masterck_pres", 4,
|
||||
parent_names,
|
||||
&at91sam9x5_master_layout,
|
||||
&mck_characteristics, &mck_lock,
|
||||
CLK_SET_RATE_GATE, INT_MIN);
|
||||
if (IS_ERR(hw))
|
||||
goto err_free;
|
||||
|
||||
hw = at91_clk_register_master_div(regmap, "masterck_div",
|
||||
"masterck_pres",
|
||||
&at91sam9x5_master_layout,
|
||||
&mck_characteristics, &mck_lock,
|
||||
CLK_SET_RATE_GATE);
|
||||
if (IS_ERR(hw))
|
||||
goto err_free;
|
||||
|
||||
|
@ -218,7 +230,7 @@ static void __init at91sam9x5_pmc_setup(struct device_node *np,
|
|||
parent_names[1] = "mainck";
|
||||
parent_names[2] = "plladivck";
|
||||
parent_names[3] = "utmick";
|
||||
parent_names[4] = "masterck";
|
||||
parent_names[4] = "masterck_div";
|
||||
for (i = 0; i < 2; i++) {
|
||||
char name[6];
|
||||
|
||||
|
@ -245,7 +257,7 @@ static void __init at91sam9x5_pmc_setup(struct device_node *np,
|
|||
}
|
||||
|
||||
if (has_lcdck) {
|
||||
hw = at91_clk_register_system(regmap, "lcdck", "masterck", 3);
|
||||
hw = at91_clk_register_system(regmap, "lcdck", "masterck_div", 3);
|
||||
if (IS_ERR(hw))
|
||||
goto err_free;
|
||||
|
||||
|
@ -256,7 +268,7 @@ static void __init at91sam9x5_pmc_setup(struct device_node *np,
|
|||
hw = at91_clk_register_sam9x5_peripheral(regmap, &pmc_pcr_lock,
|
||||
&at91sam9x5_pcr_layout,
|
||||
at91sam9x5_periphck[i].n,
|
||||
"masterck",
|
||||
"masterck_div",
|
||||
at91sam9x5_periphck[i].id,
|
||||
&range, INT_MIN);
|
||||
if (IS_ERR(hw))
|
||||
|
@ -269,7 +281,7 @@ static void __init at91sam9x5_pmc_setup(struct device_node *np,
|
|||
hw = at91_clk_register_sam9x5_peripheral(regmap, &pmc_pcr_lock,
|
||||
&at91sam9x5_pcr_layout,
|
||||
extra_pcks[i].n,
|
||||
"masterck",
|
||||
"masterck_div",
|
||||
extra_pcks[i].id,
|
||||
&range, INT_MIN);
|
||||
if (IS_ERR(hw))
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
#define MASTER_PRES_MASK 0x7
|
||||
#define MASTER_PRES_MAX MASTER_PRES_MASK
|
||||
#define MASTER_DIV_SHIFT 8
|
||||
#define MASTER_DIV_MASK 0x3
|
||||
#define MASTER_DIV_MASK 0x7
|
||||
|
||||
#define PMC_MCR 0x30
|
||||
#define PMC_MCR_ID_MSK GENMASK(3, 0)
|
||||
|
@ -58,119 +58,153 @@ static inline bool clk_master_ready(struct clk_master *master)
|
|||
static int clk_master_prepare(struct clk_hw *hw)
|
||||
{
|
||||
struct clk_master *master = to_clk_master(hw);
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(master->lock, flags);
|
||||
|
||||
while (!clk_master_ready(master))
|
||||
cpu_relax();
|
||||
|
||||
spin_unlock_irqrestore(master->lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int clk_master_is_prepared(struct clk_hw *hw)
|
||||
{
|
||||
struct clk_master *master = to_clk_master(hw);
|
||||
unsigned long flags;
|
||||
bool status;
|
||||
|
||||
return clk_master_ready(master);
|
||||
spin_lock_irqsave(master->lock, flags);
|
||||
status = clk_master_ready(master);
|
||||
spin_unlock_irqrestore(master->lock, flags);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static unsigned long clk_master_recalc_rate(struct clk_hw *hw,
|
||||
unsigned long parent_rate)
|
||||
static unsigned long clk_master_div_recalc_rate(struct clk_hw *hw,
|
||||
unsigned long parent_rate)
|
||||
{
|
||||
u8 pres;
|
||||
u8 div;
|
||||
unsigned long rate = parent_rate;
|
||||
unsigned long flags, rate = parent_rate;
|
||||
struct clk_master *master = to_clk_master(hw);
|
||||
const struct clk_master_layout *layout = master->layout;
|
||||
const struct clk_master_characteristics *characteristics =
|
||||
master->characteristics;
|
||||
unsigned int mckr;
|
||||
|
||||
spin_lock_irqsave(master->lock, flags);
|
||||
regmap_read(master->regmap, master->layout->offset, &mckr);
|
||||
spin_unlock_irqrestore(master->lock, flags);
|
||||
|
||||
mckr &= layout->mask;
|
||||
|
||||
pres = (mckr >> layout->pres_shift) & MASTER_PRES_MASK;
|
||||
div = (mckr >> MASTER_DIV_SHIFT) & MASTER_DIV_MASK;
|
||||
|
||||
if (characteristics->have_div3_pres && pres == MASTER_PRES_MAX)
|
||||
rate /= 3;
|
||||
else
|
||||
rate >>= pres;
|
||||
|
||||
rate /= characteristics->divisors[div];
|
||||
|
||||
if (rate < characteristics->output.min)
|
||||
pr_warn("master clk is underclocked");
|
||||
pr_warn("master clk div is underclocked");
|
||||
else if (rate > characteristics->output.max)
|
||||
pr_warn("master clk is overclocked");
|
||||
pr_warn("master clk div is overclocked");
|
||||
|
||||
return rate;
|
||||
}
|
||||
|
||||
static u8 clk_master_get_parent(struct clk_hw *hw)
|
||||
{
|
||||
struct clk_master *master = to_clk_master(hw);
|
||||
unsigned int mckr;
|
||||
|
||||
regmap_read(master->regmap, master->layout->offset, &mckr);
|
||||
|
||||
return mckr & AT91_PMC_CSS;
|
||||
}
|
||||
|
||||
static const struct clk_ops master_ops = {
|
||||
static const struct clk_ops master_div_ops = {
|
||||
.prepare = clk_master_prepare,
|
||||
.is_prepared = clk_master_is_prepared,
|
||||
.recalc_rate = clk_master_recalc_rate,
|
||||
.get_parent = clk_master_get_parent,
|
||||
.recalc_rate = clk_master_div_recalc_rate,
|
||||
};
|
||||
|
||||
struct clk_hw * __init
|
||||
at91_clk_register_master(struct regmap *regmap,
|
||||
const char *name, int num_parents,
|
||||
const char **parent_names,
|
||||
const struct clk_master_layout *layout,
|
||||
const struct clk_master_characteristics *characteristics)
|
||||
{
|
||||
struct clk_master *master;
|
||||
struct clk_init_data init;
|
||||
struct clk_hw *hw;
|
||||
int ret;
|
||||
|
||||
if (!name || !num_parents || !parent_names)
|
||||
return ERR_PTR(-EINVAL);
|
||||
|
||||
master = kzalloc(sizeof(*master), GFP_KERNEL);
|
||||
if (!master)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
init.name = name;
|
||||
init.ops = &master_ops;
|
||||
init.parent_names = parent_names;
|
||||
init.num_parents = num_parents;
|
||||
init.flags = 0;
|
||||
|
||||
master->hw.init = &init;
|
||||
master->layout = layout;
|
||||
master->characteristics = characteristics;
|
||||
master->regmap = regmap;
|
||||
|
||||
hw = &master->hw;
|
||||
ret = clk_hw_register(NULL, &master->hw);
|
||||
if (ret) {
|
||||
kfree(master);
|
||||
hw = ERR_PTR(ret);
|
||||
}
|
||||
|
||||
return hw;
|
||||
}
|
||||
|
||||
static unsigned long
|
||||
clk_sama7g5_master_recalc_rate(struct clk_hw *hw,
|
||||
unsigned long parent_rate)
|
||||
static int clk_master_div_set_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long parent_rate)
|
||||
{
|
||||
struct clk_master *master = to_clk_master(hw);
|
||||
const struct clk_master_characteristics *characteristics =
|
||||
master->characteristics;
|
||||
unsigned long flags;
|
||||
int div, i;
|
||||
|
||||
return DIV_ROUND_CLOSEST_ULL(parent_rate, (1 << master->div));
|
||||
div = DIV_ROUND_CLOSEST(parent_rate, rate);
|
||||
if (div > ARRAY_SIZE(characteristics->divisors))
|
||||
return -EINVAL;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(characteristics->divisors); i++) {
|
||||
if (!characteristics->divisors[i])
|
||||
break;
|
||||
|
||||
if (div == characteristics->divisors[i]) {
|
||||
div = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (i == ARRAY_SIZE(characteristics->divisors))
|
||||
return -EINVAL;
|
||||
|
||||
spin_lock_irqsave(master->lock, flags);
|
||||
regmap_update_bits(master->regmap, master->layout->offset,
|
||||
(MASTER_DIV_MASK << MASTER_DIV_SHIFT),
|
||||
(div << MASTER_DIV_SHIFT));
|
||||
while (!clk_master_ready(master))
|
||||
cpu_relax();
|
||||
spin_unlock_irqrestore(master->lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int clk_master_div_determine_rate(struct clk_hw *hw,
|
||||
struct clk_rate_request *req)
|
||||
{
|
||||
struct clk_master *master = to_clk_master(hw);
|
||||
const struct clk_master_characteristics *characteristics =
|
||||
master->characteristics;
|
||||
struct clk_hw *parent;
|
||||
unsigned long parent_rate, tmp_rate, best_rate = 0;
|
||||
int i, best_diff = INT_MIN, tmp_diff;
|
||||
|
||||
parent = clk_hw_get_parent(hw);
|
||||
if (!parent)
|
||||
return -EINVAL;
|
||||
|
||||
parent_rate = clk_hw_get_rate(parent);
|
||||
if (!parent_rate)
|
||||
return -EINVAL;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(characteristics->divisors); i++) {
|
||||
if (!characteristics->divisors[i])
|
||||
break;
|
||||
|
||||
tmp_rate = DIV_ROUND_CLOSEST_ULL(parent_rate,
|
||||
characteristics->divisors[i]);
|
||||
tmp_diff = abs(tmp_rate - req->rate);
|
||||
|
||||
if (!best_rate || best_diff > tmp_diff) {
|
||||
best_diff = tmp_diff;
|
||||
best_rate = tmp_rate;
|
||||
}
|
||||
|
||||
if (!best_diff)
|
||||
break;
|
||||
}
|
||||
|
||||
req->best_parent_rate = best_rate;
|
||||
req->best_parent_hw = parent;
|
||||
req->rate = best_rate;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct clk_ops master_div_ops_chg = {
|
||||
.prepare = clk_master_prepare,
|
||||
.is_prepared = clk_master_is_prepared,
|
||||
.recalc_rate = clk_master_div_recalc_rate,
|
||||
.determine_rate = clk_master_div_determine_rate,
|
||||
.set_rate = clk_master_div_set_rate,
|
||||
};
|
||||
|
||||
static void clk_sama7g5_master_best_diff(struct clk_rate_request *req,
|
||||
struct clk_hw *parent,
|
||||
unsigned long parent_rate,
|
||||
|
@ -195,6 +229,217 @@ static void clk_sama7g5_master_best_diff(struct clk_rate_request *req,
|
|||
}
|
||||
}
|
||||
|
||||
static int clk_master_pres_determine_rate(struct clk_hw *hw,
|
||||
struct clk_rate_request *req)
|
||||
{
|
||||
struct clk_master *master = to_clk_master(hw);
|
||||
struct clk_rate_request req_parent = *req;
|
||||
const struct clk_master_characteristics *characteristics =
|
||||
master->characteristics;
|
||||
struct clk_hw *parent;
|
||||
long best_rate = LONG_MIN, best_diff = LONG_MIN;
|
||||
u32 pres;
|
||||
int i;
|
||||
|
||||
if (master->chg_pid < 0)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
parent = clk_hw_get_parent_by_index(hw, master->chg_pid);
|
||||
if (!parent)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
for (i = 0; i <= MASTER_PRES_MAX; i++) {
|
||||
if (characteristics->have_div3_pres && i == MASTER_PRES_MAX)
|
||||
pres = 3;
|
||||
else
|
||||
pres = 1 << i;
|
||||
|
||||
req_parent.rate = req->rate * pres;
|
||||
if (__clk_determine_rate(parent, &req_parent))
|
||||
continue;
|
||||
|
||||
clk_sama7g5_master_best_diff(req, parent, req_parent.rate,
|
||||
&best_diff, &best_rate, pres);
|
||||
if (!best_diff)
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int clk_master_pres_set_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long parent_rate)
|
||||
{
|
||||
struct clk_master *master = to_clk_master(hw);
|
||||
unsigned long flags;
|
||||
unsigned int pres;
|
||||
|
||||
pres = DIV_ROUND_CLOSEST(parent_rate, rate);
|
||||
if (pres > MASTER_PRES_MAX)
|
||||
return -EINVAL;
|
||||
|
||||
else if (pres == 3)
|
||||
pres = MASTER_PRES_MAX;
|
||||
else
|
||||
pres = ffs(pres) - 1;
|
||||
|
||||
spin_lock_irqsave(master->lock, flags);
|
||||
regmap_update_bits(master->regmap, master->layout->offset,
|
||||
(MASTER_PRES_MASK << master->layout->pres_shift),
|
||||
(pres << master->layout->pres_shift));
|
||||
|
||||
while (!clk_master_ready(master))
|
||||
cpu_relax();
|
||||
spin_unlock_irqrestore(master->lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static unsigned long clk_master_pres_recalc_rate(struct clk_hw *hw,
|
||||
unsigned long parent_rate)
|
||||
{
|
||||
struct clk_master *master = to_clk_master(hw);
|
||||
const struct clk_master_characteristics *characteristics =
|
||||
master->characteristics;
|
||||
unsigned long flags;
|
||||
unsigned int val, pres;
|
||||
|
||||
spin_lock_irqsave(master->lock, flags);
|
||||
regmap_read(master->regmap, master->layout->offset, &val);
|
||||
spin_unlock_irqrestore(master->lock, flags);
|
||||
|
||||
pres = (val >> master->layout->pres_shift) & MASTER_PRES_MASK;
|
||||
if (pres == 3 && characteristics->have_div3_pres)
|
||||
pres = 3;
|
||||
else
|
||||
pres = (1 << pres);
|
||||
|
||||
return DIV_ROUND_CLOSEST_ULL(parent_rate, pres);
|
||||
}
|
||||
|
||||
static u8 clk_master_pres_get_parent(struct clk_hw *hw)
|
||||
{
|
||||
struct clk_master *master = to_clk_master(hw);
|
||||
unsigned long flags;
|
||||
unsigned int mckr;
|
||||
|
||||
spin_lock_irqsave(master->lock, flags);
|
||||
regmap_read(master->regmap, master->layout->offset, &mckr);
|
||||
spin_unlock_irqrestore(master->lock, flags);
|
||||
|
||||
return mckr & AT91_PMC_CSS;
|
||||
}
|
||||
|
||||
static const struct clk_ops master_pres_ops = {
|
||||
.prepare = clk_master_prepare,
|
||||
.is_prepared = clk_master_is_prepared,
|
||||
.recalc_rate = clk_master_pres_recalc_rate,
|
||||
.get_parent = clk_master_pres_get_parent,
|
||||
};
|
||||
|
||||
static const struct clk_ops master_pres_ops_chg = {
|
||||
.prepare = clk_master_prepare,
|
||||
.is_prepared = clk_master_is_prepared,
|
||||
.determine_rate = clk_master_pres_determine_rate,
|
||||
.recalc_rate = clk_master_pres_recalc_rate,
|
||||
.get_parent = clk_master_pres_get_parent,
|
||||
.set_rate = clk_master_pres_set_rate,
|
||||
};
|
||||
|
||||
static struct clk_hw * __init
|
||||
at91_clk_register_master_internal(struct regmap *regmap,
|
||||
const char *name, int num_parents,
|
||||
const char **parent_names,
|
||||
const struct clk_master_layout *layout,
|
||||
const struct clk_master_characteristics *characteristics,
|
||||
const struct clk_ops *ops, spinlock_t *lock, u32 flags,
|
||||
int chg_pid)
|
||||
{
|
||||
struct clk_master *master;
|
||||
struct clk_init_data init;
|
||||
struct clk_hw *hw;
|
||||
int ret;
|
||||
|
||||
if (!name || !num_parents || !parent_names || !lock)
|
||||
return ERR_PTR(-EINVAL);
|
||||
|
||||
master = kzalloc(sizeof(*master), GFP_KERNEL);
|
||||
if (!master)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
init.name = name;
|
||||
init.ops = ops;
|
||||
init.parent_names = parent_names;
|
||||
init.num_parents = num_parents;
|
||||
init.flags = flags;
|
||||
|
||||
master->hw.init = &init;
|
||||
master->layout = layout;
|
||||
master->characteristics = characteristics;
|
||||
master->regmap = regmap;
|
||||
master->chg_pid = chg_pid;
|
||||
master->lock = lock;
|
||||
|
||||
hw = &master->hw;
|
||||
ret = clk_hw_register(NULL, &master->hw);
|
||||
if (ret) {
|
||||
kfree(master);
|
||||
hw = ERR_PTR(ret);
|
||||
}
|
||||
|
||||
return hw;
|
||||
}
|
||||
|
||||
struct clk_hw * __init
|
||||
at91_clk_register_master_pres(struct regmap *regmap,
|
||||
const char *name, int num_parents,
|
||||
const char **parent_names,
|
||||
const struct clk_master_layout *layout,
|
||||
const struct clk_master_characteristics *characteristics,
|
||||
spinlock_t *lock, u32 flags, int chg_pid)
|
||||
{
|
||||
const struct clk_ops *ops;
|
||||
|
||||
if (flags & CLK_SET_RATE_GATE)
|
||||
ops = &master_pres_ops;
|
||||
else
|
||||
ops = &master_pres_ops_chg;
|
||||
|
||||
return at91_clk_register_master_internal(regmap, name, num_parents,
|
||||
parent_names, layout,
|
||||
characteristics, ops,
|
||||
lock, flags, chg_pid);
|
||||
}
|
||||
|
||||
struct clk_hw * __init
|
||||
at91_clk_register_master_div(struct regmap *regmap,
|
||||
const char *name, const char *parent_name,
|
||||
const struct clk_master_layout *layout,
|
||||
const struct clk_master_characteristics *characteristics,
|
||||
spinlock_t *lock, u32 flags)
|
||||
{
|
||||
const struct clk_ops *ops;
|
||||
|
||||
if (flags & CLK_SET_RATE_GATE)
|
||||
ops = &master_div_ops;
|
||||
else
|
||||
ops = &master_div_ops_chg;
|
||||
|
||||
return at91_clk_register_master_internal(regmap, name, 1,
|
||||
&parent_name, layout,
|
||||
characteristics, ops,
|
||||
lock, flags, -EINVAL);
|
||||
}
|
||||
|
||||
static unsigned long
|
||||
clk_sama7g5_master_recalc_rate(struct clk_hw *hw,
|
||||
unsigned long parent_rate)
|
||||
{
|
||||
struct clk_master *master = to_clk_master(hw);
|
||||
|
||||
return DIV_ROUND_CLOSEST_ULL(parent_rate, (1 << master->div));
|
||||
}
|
||||
|
||||
static int clk_sama7g5_master_determine_rate(struct clk_hw *hw,
|
||||
struct clk_rate_request *req)
|
||||
{
|
||||
|
|
|
@ -229,6 +229,57 @@ static int sam9x60_frac_pll_set_rate(struct clk_hw *hw, unsigned long rate,
|
|||
return sam9x60_frac_pll_compute_mul_frac(core, rate, parent_rate, true);
|
||||
}
|
||||
|
||||
static int sam9x60_frac_pll_set_rate_chg(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long parent_rate)
|
||||
{
|
||||
struct sam9x60_pll_core *core = to_sam9x60_pll_core(hw);
|
||||
struct sam9x60_frac *frac = to_sam9x60_frac(core);
|
||||
struct regmap *regmap = core->regmap;
|
||||
unsigned long irqflags;
|
||||
unsigned int val, cfrac, cmul;
|
||||
long ret;
|
||||
|
||||
ret = sam9x60_frac_pll_compute_mul_frac(core, rate, parent_rate, true);
|
||||
if (ret <= 0)
|
||||
return ret;
|
||||
|
||||
spin_lock_irqsave(core->lock, irqflags);
|
||||
|
||||
regmap_update_bits(regmap, AT91_PMC_PLL_UPDT, AT91_PMC_PLL_UPDT_ID_MSK,
|
||||
core->id);
|
||||
regmap_read(regmap, AT91_PMC_PLL_CTRL1, &val);
|
||||
cmul = (val & core->layout->mul_mask) >> core->layout->mul_shift;
|
||||
cfrac = (val & core->layout->frac_mask) >> core->layout->frac_shift;
|
||||
|
||||
if (cmul == frac->mul && cfrac == frac->frac)
|
||||
goto unlock;
|
||||
|
||||
regmap_write(regmap, AT91_PMC_PLL_CTRL1,
|
||||
(frac->mul << core->layout->mul_shift) |
|
||||
(frac->frac << core->layout->frac_shift));
|
||||
|
||||
regmap_update_bits(regmap, AT91_PMC_PLL_UPDT,
|
||||
AT91_PMC_PLL_UPDT_UPDATE | AT91_PMC_PLL_UPDT_ID_MSK,
|
||||
AT91_PMC_PLL_UPDT_UPDATE | core->id);
|
||||
|
||||
regmap_update_bits(regmap, AT91_PMC_PLL_CTRL0,
|
||||
AT91_PMC_PLL_CTRL0_ENLOCK | AT91_PMC_PLL_CTRL0_ENPLL,
|
||||
AT91_PMC_PLL_CTRL0_ENLOCK |
|
||||
AT91_PMC_PLL_CTRL0_ENPLL);
|
||||
|
||||
regmap_update_bits(regmap, AT91_PMC_PLL_UPDT,
|
||||
AT91_PMC_PLL_UPDT_UPDATE | AT91_PMC_PLL_UPDT_ID_MSK,
|
||||
AT91_PMC_PLL_UPDT_UPDATE | core->id);
|
||||
|
||||
while (!sam9x60_pll_ready(regmap, core->id))
|
||||
cpu_relax();
|
||||
|
||||
unlock:
|
||||
spin_unlock_irqrestore(core->lock, irqflags);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct clk_ops sam9x60_frac_pll_ops = {
|
||||
.prepare = sam9x60_frac_pll_prepare,
|
||||
.unprepare = sam9x60_frac_pll_unprepare,
|
||||
|
@ -238,6 +289,15 @@ static const struct clk_ops sam9x60_frac_pll_ops = {
|
|||
.set_rate = sam9x60_frac_pll_set_rate,
|
||||
};
|
||||
|
||||
static const struct clk_ops sam9x60_frac_pll_ops_chg = {
|
||||
.prepare = sam9x60_frac_pll_prepare,
|
||||
.unprepare = sam9x60_frac_pll_unprepare,
|
||||
.is_prepared = sam9x60_frac_pll_is_prepared,
|
||||
.recalc_rate = sam9x60_frac_pll_recalc_rate,
|
||||
.round_rate = sam9x60_frac_pll_round_rate,
|
||||
.set_rate = sam9x60_frac_pll_set_rate_chg,
|
||||
};
|
||||
|
||||
static int sam9x60_div_pll_prepare(struct clk_hw *hw)
|
||||
{
|
||||
struct sam9x60_pll_core *core = to_sam9x60_pll_core(hw);
|
||||
|
@ -384,6 +444,44 @@ static int sam9x60_div_pll_set_rate(struct clk_hw *hw, unsigned long rate,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int sam9x60_div_pll_set_rate_chg(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long parent_rate)
|
||||
{
|
||||
struct sam9x60_pll_core *core = to_sam9x60_pll_core(hw);
|
||||
struct sam9x60_div *div = to_sam9x60_div(core);
|
||||
struct regmap *regmap = core->regmap;
|
||||
unsigned long irqflags;
|
||||
unsigned int val, cdiv;
|
||||
|
||||
div->div = DIV_ROUND_CLOSEST(parent_rate, rate) - 1;
|
||||
|
||||
spin_lock_irqsave(core->lock, irqflags);
|
||||
regmap_update_bits(regmap, AT91_PMC_PLL_UPDT, AT91_PMC_PLL_UPDT_ID_MSK,
|
||||
core->id);
|
||||
regmap_read(regmap, AT91_PMC_PLL_CTRL0, &val);
|
||||
cdiv = (val & core->layout->div_mask) >> core->layout->div_shift;
|
||||
|
||||
/* Stop if nothing changed. */
|
||||
if (cdiv == div->div)
|
||||
goto unlock;
|
||||
|
||||
regmap_update_bits(regmap, AT91_PMC_PLL_CTRL0,
|
||||
core->layout->div_mask,
|
||||
(div->div << core->layout->div_shift));
|
||||
|
||||
regmap_update_bits(regmap, AT91_PMC_PLL_UPDT,
|
||||
AT91_PMC_PLL_UPDT_UPDATE | AT91_PMC_PLL_UPDT_ID_MSK,
|
||||
AT91_PMC_PLL_UPDT_UPDATE | core->id);
|
||||
|
||||
while (!sam9x60_pll_ready(regmap, core->id))
|
||||
cpu_relax();
|
||||
|
||||
unlock:
|
||||
spin_unlock_irqrestore(core->lock, irqflags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct clk_ops sam9x60_div_pll_ops = {
|
||||
.prepare = sam9x60_div_pll_prepare,
|
||||
.unprepare = sam9x60_div_pll_unprepare,
|
||||
|
@ -393,17 +491,26 @@ static const struct clk_ops sam9x60_div_pll_ops = {
|
|||
.set_rate = sam9x60_div_pll_set_rate,
|
||||
};
|
||||
|
||||
static const struct clk_ops sam9x60_div_pll_ops_chg = {
|
||||
.prepare = sam9x60_div_pll_prepare,
|
||||
.unprepare = sam9x60_div_pll_unprepare,
|
||||
.is_prepared = sam9x60_div_pll_is_prepared,
|
||||
.recalc_rate = sam9x60_div_pll_recalc_rate,
|
||||
.round_rate = sam9x60_div_pll_round_rate,
|
||||
.set_rate = sam9x60_div_pll_set_rate_chg,
|
||||
};
|
||||
|
||||
struct clk_hw * __init
|
||||
sam9x60_clk_register_frac_pll(struct regmap *regmap, spinlock_t *lock,
|
||||
const char *name, const char *parent_name,
|
||||
struct clk_hw *parent_hw, u8 id,
|
||||
const struct clk_pll_characteristics *characteristics,
|
||||
const struct clk_pll_layout *layout, bool critical)
|
||||
const struct clk_pll_layout *layout, u32 flags)
|
||||
{
|
||||
struct sam9x60_frac *frac;
|
||||
struct clk_hw *hw;
|
||||
struct clk_init_data init;
|
||||
unsigned long parent_rate, flags;
|
||||
unsigned long parent_rate, irqflags;
|
||||
unsigned int val;
|
||||
int ret;
|
||||
|
||||
|
@ -417,10 +524,12 @@ sam9x60_clk_register_frac_pll(struct regmap *regmap, spinlock_t *lock,
|
|||
init.name = name;
|
||||
init.parent_names = &parent_name;
|
||||
init.num_parents = 1;
|
||||
init.ops = &sam9x60_frac_pll_ops;
|
||||
init.flags = CLK_SET_RATE_GATE;
|
||||
if (critical)
|
||||
init.flags |= CLK_IS_CRITICAL;
|
||||
if (flags & CLK_SET_RATE_GATE)
|
||||
init.ops = &sam9x60_frac_pll_ops;
|
||||
else
|
||||
init.ops = &sam9x60_frac_pll_ops_chg;
|
||||
|
||||
init.flags = flags;
|
||||
|
||||
frac->core.id = id;
|
||||
frac->core.hw.init = &init;
|
||||
|
@ -429,7 +538,7 @@ sam9x60_clk_register_frac_pll(struct regmap *regmap, spinlock_t *lock,
|
|||
frac->core.regmap = regmap;
|
||||
frac->core.lock = lock;
|
||||
|
||||
spin_lock_irqsave(frac->core.lock, flags);
|
||||
spin_lock_irqsave(frac->core.lock, irqflags);
|
||||
if (sam9x60_pll_ready(regmap, id)) {
|
||||
regmap_update_bits(regmap, AT91_PMC_PLL_UPDT,
|
||||
AT91_PMC_PLL_UPDT_ID_MSK, id);
|
||||
|
@ -457,7 +566,7 @@ sam9x60_clk_register_frac_pll(struct regmap *regmap, spinlock_t *lock,
|
|||
goto free;
|
||||
}
|
||||
}
|
||||
spin_unlock_irqrestore(frac->core.lock, flags);
|
||||
spin_unlock_irqrestore(frac->core.lock, irqflags);
|
||||
|
||||
hw = &frac->core.hw;
|
||||
ret = clk_hw_register(NULL, hw);
|
||||
|
@ -469,7 +578,7 @@ sam9x60_clk_register_frac_pll(struct regmap *regmap, spinlock_t *lock,
|
|||
return hw;
|
||||
|
||||
free:
|
||||
spin_unlock_irqrestore(frac->core.lock, flags);
|
||||
spin_unlock_irqrestore(frac->core.lock, irqflags);
|
||||
kfree(frac);
|
||||
return hw;
|
||||
}
|
||||
|
@ -478,12 +587,12 @@ struct clk_hw * __init
|
|||
sam9x60_clk_register_div_pll(struct regmap *regmap, spinlock_t *lock,
|
||||
const char *name, const char *parent_name, u8 id,
|
||||
const struct clk_pll_characteristics *characteristics,
|
||||
const struct clk_pll_layout *layout, bool critical)
|
||||
const struct clk_pll_layout *layout, u32 flags)
|
||||
{
|
||||
struct sam9x60_div *div;
|
||||
struct clk_hw *hw;
|
||||
struct clk_init_data init;
|
||||
unsigned long flags;
|
||||
unsigned long irqflags;
|
||||
unsigned int val;
|
||||
int ret;
|
||||
|
||||
|
@ -497,11 +606,11 @@ sam9x60_clk_register_div_pll(struct regmap *regmap, spinlock_t *lock,
|
|||
init.name = name;
|
||||
init.parent_names = &parent_name;
|
||||
init.num_parents = 1;
|
||||
init.ops = &sam9x60_div_pll_ops;
|
||||
init.flags = CLK_SET_RATE_GATE | CLK_SET_PARENT_GATE |
|
||||
CLK_SET_RATE_PARENT;
|
||||
if (critical)
|
||||
init.flags |= CLK_IS_CRITICAL;
|
||||
if (flags & CLK_SET_RATE_GATE)
|
||||
init.ops = &sam9x60_div_pll_ops;
|
||||
else
|
||||
init.ops = &sam9x60_div_pll_ops_chg;
|
||||
init.flags = flags;
|
||||
|
||||
div->core.id = id;
|
||||
div->core.hw.init = &init;
|
||||
|
@ -510,14 +619,14 @@ sam9x60_clk_register_div_pll(struct regmap *regmap, spinlock_t *lock,
|
|||
div->core.regmap = regmap;
|
||||
div->core.lock = lock;
|
||||
|
||||
spin_lock_irqsave(div->core.lock, flags);
|
||||
spin_lock_irqsave(div->core.lock, irqflags);
|
||||
|
||||
regmap_update_bits(regmap, AT91_PMC_PLL_UPDT,
|
||||
AT91_PMC_PLL_UPDT_ID_MSK, id);
|
||||
regmap_read(regmap, AT91_PMC_PLL_CTRL0, &val);
|
||||
div->div = FIELD_GET(PMC_PLL_CTRL0_DIV_MSK, val);
|
||||
|
||||
spin_unlock_irqrestore(div->core.lock, flags);
|
||||
spin_unlock_irqrestore(div->core.lock, irqflags);
|
||||
|
||||
hw = &div->core.hw;
|
||||
ret = clk_hw_register(NULL, hw);
|
||||
|
|
|
@ -24,6 +24,8 @@
|
|||
|
||||
#define GCK_INDEX_DT_AUDIO_PLL 5
|
||||
|
||||
static DEFINE_SPINLOCK(mck_lock);
|
||||
|
||||
#ifdef CONFIG_HAVE_AT91_AUDIO_PLL
|
||||
static void __init of_sama5d2_clk_audio_pll_frac_setup(struct device_node *np)
|
||||
{
|
||||
|
@ -388,9 +390,16 @@ of_at91_clk_master_setup(struct device_node *np,
|
|||
if (IS_ERR(regmap))
|
||||
return;
|
||||
|
||||
hw = at91_clk_register_master(regmap, name, num_parents,
|
||||
parent_names, layout,
|
||||
characteristics);
|
||||
hw = at91_clk_register_master_pres(regmap, "masterck_pres", num_parents,
|
||||
parent_names, layout,
|
||||
characteristics, &mck_lock,
|
||||
CLK_SET_RATE_GATE, INT_MIN);
|
||||
if (IS_ERR(hw))
|
||||
goto out_free_characteristics;
|
||||
|
||||
hw = at91_clk_register_master_div(regmap, name, "masterck_pres",
|
||||
layout, characteristics,
|
||||
&mck_lock, CLK_SET_RATE_GATE);
|
||||
if (IS_ERR(hw))
|
||||
goto out_free_characteristics;
|
||||
|
||||
|
|
|
@ -48,7 +48,7 @@ extern const struct clk_master_layout at91sam9x5_master_layout;
|
|||
|
||||
struct clk_master_characteristics {
|
||||
struct clk_range output;
|
||||
u32 divisors[4];
|
||||
u32 divisors[5];
|
||||
u8 have_div3_pres;
|
||||
};
|
||||
|
||||
|
@ -155,10 +155,18 @@ at91_clk_register_sam9x5_main(struct regmap *regmap, const char *name,
|
|||
const char **parent_names, int num_parents);
|
||||
|
||||
struct clk_hw * __init
|
||||
at91_clk_register_master(struct regmap *regmap, const char *name,
|
||||
int num_parents, const char **parent_names,
|
||||
const struct clk_master_layout *layout,
|
||||
const struct clk_master_characteristics *characteristics);
|
||||
at91_clk_register_master_pres(struct regmap *regmap, const char *name,
|
||||
int num_parents, const char **parent_names,
|
||||
const struct clk_master_layout *layout,
|
||||
const struct clk_master_characteristics *characteristics,
|
||||
spinlock_t *lock, u32 flags, int chg_pid);
|
||||
|
||||
struct clk_hw * __init
|
||||
at91_clk_register_master_div(struct regmap *regmap, const char *name,
|
||||
const char *parent_names,
|
||||
const struct clk_master_layout *layout,
|
||||
const struct clk_master_characteristics *characteristics,
|
||||
spinlock_t *lock, u32 flags);
|
||||
|
||||
struct clk_hw * __init
|
||||
at91_clk_sama7g5_register_master(struct regmap *regmap,
|
||||
|
@ -190,14 +198,14 @@ struct clk_hw * __init
|
|||
sam9x60_clk_register_div_pll(struct regmap *regmap, spinlock_t *lock,
|
||||
const char *name, const char *parent_name, u8 id,
|
||||
const struct clk_pll_characteristics *characteristics,
|
||||
const struct clk_pll_layout *layout, bool critical);
|
||||
const struct clk_pll_layout *layout, u32 flags);
|
||||
|
||||
struct clk_hw * __init
|
||||
sam9x60_clk_register_frac_pll(struct regmap *regmap, spinlock_t *lock,
|
||||
const char *name, const char *parent_name,
|
||||
struct clk_hw *parent_hw, u8 id,
|
||||
const struct clk_pll_characteristics *characteristics,
|
||||
const struct clk_pll_layout *layout, bool critical);
|
||||
const struct clk_pll_layout *layout, u32 flags);
|
||||
|
||||
struct clk_hw * __init
|
||||
at91_clk_register_programmable(struct regmap *regmap, const char *name,
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
#include "pmc.h"
|
||||
|
||||
static DEFINE_SPINLOCK(pmc_pll_lock);
|
||||
static DEFINE_SPINLOCK(mck_lock);
|
||||
|
||||
static const struct clk_master_characteristics mck_characteristics = {
|
||||
.output = { .min = 140000000, .max = 200000000 },
|
||||
|
@ -76,11 +77,11 @@ static const struct {
|
|||
char *p;
|
||||
u8 id;
|
||||
} sam9x60_systemck[] = {
|
||||
{ .n = "ddrck", .p = "masterck", .id = 2 },
|
||||
{ .n = "ddrck", .p = "masterck_div", .id = 2 },
|
||||
{ .n = "uhpck", .p = "usbck", .id = 6 },
|
||||
{ .n = "pck0", .p = "prog0", .id = 8 },
|
||||
{ .n = "pck1", .p = "prog1", .id = 9 },
|
||||
{ .n = "qspick", .p = "masterck", .id = 19 },
|
||||
{ .n = "qspick", .p = "masterck_div", .id = 19 },
|
||||
};
|
||||
|
||||
static const struct {
|
||||
|
@ -174,7 +175,6 @@ static void __init sam9x60_pmc_setup(struct device_node *np)
|
|||
struct regmap *regmap;
|
||||
struct clk_hw *hw;
|
||||
int i;
|
||||
bool bypass;
|
||||
|
||||
i = of_property_match_string(np, "clock-names", "td_slck");
|
||||
if (i < 0)
|
||||
|
@ -209,10 +209,7 @@ static void __init sam9x60_pmc_setup(struct device_node *np)
|
|||
if (IS_ERR(hw))
|
||||
goto err_free;
|
||||
|
||||
bypass = of_property_read_bool(np, "atmel,osc-bypass");
|
||||
|
||||
hw = at91_clk_register_main_osc(regmap, "main_osc", mainxtal_name,
|
||||
bypass);
|
||||
hw = at91_clk_register_main_osc(regmap, "main_osc", mainxtal_name, 0);
|
||||
if (IS_ERR(hw))
|
||||
goto err_free;
|
||||
main_osc_hw = hw;
|
||||
|
@ -228,13 +225,24 @@ static void __init sam9x60_pmc_setup(struct device_node *np)
|
|||
hw = sam9x60_clk_register_frac_pll(regmap, &pmc_pll_lock, "pllack_fracck",
|
||||
"mainck", sam9x60_pmc->chws[PMC_MAIN],
|
||||
0, &plla_characteristics,
|
||||
&pll_frac_layout, true);
|
||||
&pll_frac_layout,
|
||||
/*
|
||||
* This feeds pllack_divck which
|
||||
* feeds CPU. It should not be
|
||||
* disabled.
|
||||
*/
|
||||
CLK_IS_CRITICAL | CLK_SET_RATE_GATE);
|
||||
if (IS_ERR(hw))
|
||||
goto err_free;
|
||||
|
||||
hw = sam9x60_clk_register_div_pll(regmap, &pmc_pll_lock, "pllack_divck",
|
||||
"pllack_fracck", 0, &plla_characteristics,
|
||||
&pll_div_layout, true);
|
||||
&pll_div_layout,
|
||||
/*
|
||||
* This feeds CPU. It should not
|
||||
* be disabled.
|
||||
*/
|
||||
CLK_IS_CRITICAL | CLK_SET_RATE_GATE);
|
||||
if (IS_ERR(hw))
|
||||
goto err_free;
|
||||
|
||||
|
@ -243,13 +251,16 @@ static void __init sam9x60_pmc_setup(struct device_node *np)
|
|||
hw = sam9x60_clk_register_frac_pll(regmap, &pmc_pll_lock, "upllck_fracck",
|
||||
"main_osc", main_osc_hw, 1,
|
||||
&upll_characteristics,
|
||||
&pll_frac_layout, false);
|
||||
&pll_frac_layout, CLK_SET_RATE_GATE);
|
||||
if (IS_ERR(hw))
|
||||
goto err_free;
|
||||
|
||||
hw = sam9x60_clk_register_div_pll(regmap, &pmc_pll_lock, "upllck_divck",
|
||||
"upllck_fracck", 1, &upll_characteristics,
|
||||
&pll_div_layout, false);
|
||||
&pll_div_layout,
|
||||
CLK_SET_RATE_GATE |
|
||||
CLK_SET_PARENT_GATE |
|
||||
CLK_SET_RATE_PARENT);
|
||||
if (IS_ERR(hw))
|
||||
goto err_free;
|
||||
|
||||
|
@ -258,9 +269,17 @@ static void __init sam9x60_pmc_setup(struct device_node *np)
|
|||
parent_names[0] = md_slck_name;
|
||||
parent_names[1] = "mainck";
|
||||
parent_names[2] = "pllack_divck";
|
||||
hw = at91_clk_register_master(regmap, "masterck", 3, parent_names,
|
||||
&sam9x60_master_layout,
|
||||
&mck_characteristics);
|
||||
hw = at91_clk_register_master_pres(regmap, "masterck_pres", 3,
|
||||
parent_names, &sam9x60_master_layout,
|
||||
&mck_characteristics, &mck_lock,
|
||||
CLK_SET_RATE_GATE, INT_MIN);
|
||||
if (IS_ERR(hw))
|
||||
goto err_free;
|
||||
|
||||
hw = at91_clk_register_master_div(regmap, "masterck_div",
|
||||
"masterck_pres", &sam9x60_master_layout,
|
||||
&mck_characteristics, &mck_lock,
|
||||
CLK_SET_RATE_GATE);
|
||||
if (IS_ERR(hw))
|
||||
goto err_free;
|
||||
|
||||
|
@ -276,7 +295,7 @@ static void __init sam9x60_pmc_setup(struct device_node *np)
|
|||
parent_names[0] = md_slck_name;
|
||||
parent_names[1] = td_slck_name;
|
||||
parent_names[2] = "mainck";
|
||||
parent_names[3] = "masterck";
|
||||
parent_names[3] = "masterck_div";
|
||||
parent_names[4] = "pllack_divck";
|
||||
parent_names[5] = "upllck_divck";
|
||||
for (i = 0; i < 2; i++) {
|
||||
|
@ -308,7 +327,7 @@ static void __init sam9x60_pmc_setup(struct device_node *np)
|
|||
hw = at91_clk_register_sam9x5_peripheral(regmap, &pmc_pcr_lock,
|
||||
&sam9x60_pcr_layout,
|
||||
sam9x60_periphck[i].n,
|
||||
"masterck",
|
||||
"masterck_div",
|
||||
sam9x60_periphck[i].id,
|
||||
&range, INT_MIN);
|
||||
if (IS_ERR(hw))
|
||||
|
|
|
@ -7,6 +7,8 @@
|
|||
|
||||
#include "pmc.h"
|
||||
|
||||
static DEFINE_SPINLOCK(mck_lock);
|
||||
|
||||
static const struct clk_master_characteristics mck_characteristics = {
|
||||
.output = { .min = 124000000, .max = 166000000 },
|
||||
.divisors = { 1, 2, 4, 3 },
|
||||
|
@ -40,14 +42,14 @@ static const struct {
|
|||
char *p;
|
||||
u8 id;
|
||||
} sama5d2_systemck[] = {
|
||||
{ .n = "ddrck", .p = "masterck", .id = 2 },
|
||||
{ .n = "lcdck", .p = "masterck", .id = 3 },
|
||||
{ .n = "uhpck", .p = "usbck", .id = 6 },
|
||||
{ .n = "udpck", .p = "usbck", .id = 7 },
|
||||
{ .n = "pck0", .p = "prog0", .id = 8 },
|
||||
{ .n = "pck1", .p = "prog1", .id = 9 },
|
||||
{ .n = "pck2", .p = "prog2", .id = 10 },
|
||||
{ .n = "iscck", .p = "masterck", .id = 18 },
|
||||
{ .n = "ddrck", .p = "masterck_div", .id = 2 },
|
||||
{ .n = "lcdck", .p = "masterck_div", .id = 3 },
|
||||
{ .n = "uhpck", .p = "usbck", .id = 6 },
|
||||
{ .n = "udpck", .p = "usbck", .id = 7 },
|
||||
{ .n = "pck0", .p = "prog0", .id = 8 },
|
||||
{ .n = "pck1", .p = "prog1", .id = 9 },
|
||||
{ .n = "pck2", .p = "prog2", .id = 10 },
|
||||
{ .n = "iscck", .p = "masterck_div", .id = 18 },
|
||||
};
|
||||
|
||||
static const struct {
|
||||
|
@ -235,15 +237,25 @@ static void __init sama5d2_pmc_setup(struct device_node *np)
|
|||
parent_names[1] = "mainck";
|
||||
parent_names[2] = "plladivck";
|
||||
parent_names[3] = "utmick";
|
||||
hw = at91_clk_register_master(regmap, "masterck", 4, parent_names,
|
||||
&at91sam9x5_master_layout,
|
||||
&mck_characteristics);
|
||||
hw = at91_clk_register_master_pres(regmap, "masterck_pres", 4,
|
||||
parent_names,
|
||||
&at91sam9x5_master_layout,
|
||||
&mck_characteristics, &mck_lock,
|
||||
CLK_SET_RATE_GATE, INT_MIN);
|
||||
if (IS_ERR(hw))
|
||||
goto err_free;
|
||||
|
||||
hw = at91_clk_register_master_div(regmap, "masterck_div",
|
||||
"masterck_pres",
|
||||
&at91sam9x5_master_layout,
|
||||
&mck_characteristics, &mck_lock,
|
||||
CLK_SET_RATE_GATE);
|
||||
if (IS_ERR(hw))
|
||||
goto err_free;
|
||||
|
||||
sama5d2_pmc->chws[PMC_MCK] = hw;
|
||||
|
||||
hw = at91_clk_register_h32mx(regmap, "h32mxck", "masterck");
|
||||
hw = at91_clk_register_h32mx(regmap, "h32mxck", "masterck_div");
|
||||
if (IS_ERR(hw))
|
||||
goto err_free;
|
||||
|
||||
|
@ -259,7 +271,7 @@ static void __init sama5d2_pmc_setup(struct device_node *np)
|
|||
parent_names[1] = "mainck";
|
||||
parent_names[2] = "plladivck";
|
||||
parent_names[3] = "utmick";
|
||||
parent_names[4] = "masterck";
|
||||
parent_names[4] = "masterck_div";
|
||||
parent_names[5] = "audiopll_pmcck";
|
||||
for (i = 0; i < 3; i++) {
|
||||
char name[6];
|
||||
|
@ -290,7 +302,7 @@ static void __init sama5d2_pmc_setup(struct device_node *np)
|
|||
hw = at91_clk_register_sam9x5_peripheral(regmap, &pmc_pcr_lock,
|
||||
&sama5d2_pcr_layout,
|
||||
sama5d2_periphck[i].n,
|
||||
"masterck",
|
||||
"masterck_div",
|
||||
sama5d2_periphck[i].id,
|
||||
&range, INT_MIN);
|
||||
if (IS_ERR(hw))
|
||||
|
@ -317,7 +329,7 @@ static void __init sama5d2_pmc_setup(struct device_node *np)
|
|||
parent_names[1] = "mainck";
|
||||
parent_names[2] = "plladivck";
|
||||
parent_names[3] = "utmick";
|
||||
parent_names[4] = "masterck";
|
||||
parent_names[4] = "masterck_div";
|
||||
parent_names[5] = "audiopll_pmcck";
|
||||
for (i = 0; i < ARRAY_SIZE(sama5d2_gck); i++) {
|
||||
hw = at91_clk_register_generated(regmap, &pmc_pcr_lock,
|
||||
|
|
|
@ -7,6 +7,8 @@
|
|||
|
||||
#include "pmc.h"
|
||||
|
||||
static DEFINE_SPINLOCK(mck_lock);
|
||||
|
||||
static const struct clk_master_characteristics mck_characteristics = {
|
||||
.output = { .min = 0, .max = 166000000 },
|
||||
.divisors = { 1, 2, 4, 3 },
|
||||
|
@ -40,14 +42,14 @@ static const struct {
|
|||
char *p;
|
||||
u8 id;
|
||||
} sama5d3_systemck[] = {
|
||||
{ .n = "ddrck", .p = "masterck", .id = 2 },
|
||||
{ .n = "lcdck", .p = "masterck", .id = 3 },
|
||||
{ .n = "smdck", .p = "smdclk", .id = 4 },
|
||||
{ .n = "uhpck", .p = "usbck", .id = 6 },
|
||||
{ .n = "udpck", .p = "usbck", .id = 7 },
|
||||
{ .n = "pck0", .p = "prog0", .id = 8 },
|
||||
{ .n = "pck1", .p = "prog1", .id = 9 },
|
||||
{ .n = "pck2", .p = "prog2", .id = 10 },
|
||||
{ .n = "ddrck", .p = "masterck_div", .id = 2 },
|
||||
{ .n = "lcdck", .p = "masterck_div", .id = 3 },
|
||||
{ .n = "smdck", .p = "smdclk", .id = 4 },
|
||||
{ .n = "uhpck", .p = "usbck", .id = 6 },
|
||||
{ .n = "udpck", .p = "usbck", .id = 7 },
|
||||
{ .n = "pck0", .p = "prog0", .id = 8 },
|
||||
{ .n = "pck1", .p = "prog1", .id = 9 },
|
||||
{ .n = "pck2", .p = "prog2", .id = 10 },
|
||||
};
|
||||
|
||||
static const struct {
|
||||
|
@ -170,9 +172,19 @@ static void __init sama5d3_pmc_setup(struct device_node *np)
|
|||
parent_names[1] = "mainck";
|
||||
parent_names[2] = "plladivck";
|
||||
parent_names[3] = "utmick";
|
||||
hw = at91_clk_register_master(regmap, "masterck", 4, parent_names,
|
||||
&at91sam9x5_master_layout,
|
||||
&mck_characteristics);
|
||||
hw = at91_clk_register_master_pres(regmap, "masterck_pres", 4,
|
||||
parent_names,
|
||||
&at91sam9x5_master_layout,
|
||||
&mck_characteristics, &mck_lock,
|
||||
CLK_SET_RATE_GATE, INT_MIN);
|
||||
if (IS_ERR(hw))
|
||||
goto err_free;
|
||||
|
||||
hw = at91_clk_register_master_div(regmap, "masterck_div",
|
||||
"masterck_pres",
|
||||
&at91sam9x5_master_layout,
|
||||
&mck_characteristics, &mck_lock,
|
||||
CLK_SET_RATE_GATE);
|
||||
if (IS_ERR(hw))
|
||||
goto err_free;
|
||||
|
||||
|
@ -192,7 +204,7 @@ static void __init sama5d3_pmc_setup(struct device_node *np)
|
|||
parent_names[1] = "mainck";
|
||||
parent_names[2] = "plladivck";
|
||||
parent_names[3] = "utmick";
|
||||
parent_names[4] = "masterck";
|
||||
parent_names[4] = "masterck_div";
|
||||
for (i = 0; i < 3; i++) {
|
||||
char name[6];
|
||||
|
||||
|
@ -222,7 +234,7 @@ static void __init sama5d3_pmc_setup(struct device_node *np)
|
|||
hw = at91_clk_register_sam9x5_peripheral(regmap, &pmc_pcr_lock,
|
||||
&sama5d3_pcr_layout,
|
||||
sama5d3_periphck[i].n,
|
||||
"masterck",
|
||||
"masterck_div",
|
||||
sama5d3_periphck[i].id,
|
||||
&sama5d3_periphck[i].r,
|
||||
INT_MIN);
|
||||
|
|
|
@ -7,6 +7,8 @@
|
|||
|
||||
#include "pmc.h"
|
||||
|
||||
static DEFINE_SPINLOCK(mck_lock);
|
||||
|
||||
static const struct clk_master_characteristics mck_characteristics = {
|
||||
.output = { .min = 125000000, .max = 200000000 },
|
||||
.divisors = { 1, 2, 4, 3 },
|
||||
|
@ -39,14 +41,14 @@ static const struct {
|
|||
char *p;
|
||||
u8 id;
|
||||
} sama5d4_systemck[] = {
|
||||
{ .n = "ddrck", .p = "masterck", .id = 2 },
|
||||
{ .n = "lcdck", .p = "masterck", .id = 3 },
|
||||
{ .n = "smdck", .p = "smdclk", .id = 4 },
|
||||
{ .n = "uhpck", .p = "usbck", .id = 6 },
|
||||
{ .n = "udpck", .p = "usbck", .id = 7 },
|
||||
{ .n = "pck0", .p = "prog0", .id = 8 },
|
||||
{ .n = "pck1", .p = "prog1", .id = 9 },
|
||||
{ .n = "pck2", .p = "prog2", .id = 10 },
|
||||
{ .n = "ddrck", .p = "masterck_div", .id = 2 },
|
||||
{ .n = "lcdck", .p = "masterck_div", .id = 3 },
|
||||
{ .n = "smdck", .p = "smdclk", .id = 4 },
|
||||
{ .n = "uhpck", .p = "usbck", .id = 6 },
|
||||
{ .n = "udpck", .p = "usbck", .id = 7 },
|
||||
{ .n = "pck0", .p = "prog0", .id = 8 },
|
||||
{ .n = "pck1", .p = "prog1", .id = 9 },
|
||||
{ .n = "pck2", .p = "prog2", .id = 10 },
|
||||
};
|
||||
|
||||
static const struct {
|
||||
|
@ -185,15 +187,25 @@ static void __init sama5d4_pmc_setup(struct device_node *np)
|
|||
parent_names[1] = "mainck";
|
||||
parent_names[2] = "plladivck";
|
||||
parent_names[3] = "utmick";
|
||||
hw = at91_clk_register_master(regmap, "masterck", 4, parent_names,
|
||||
&at91sam9x5_master_layout,
|
||||
&mck_characteristics);
|
||||
hw = at91_clk_register_master_pres(regmap, "masterck_pres", 4,
|
||||
parent_names,
|
||||
&at91sam9x5_master_layout,
|
||||
&mck_characteristics, &mck_lock,
|
||||
CLK_SET_RATE_GATE, INT_MIN);
|
||||
if (IS_ERR(hw))
|
||||
goto err_free;
|
||||
|
||||
hw = at91_clk_register_master_div(regmap, "masterck_div",
|
||||
"masterck_pres",
|
||||
&at91sam9x5_master_layout,
|
||||
&mck_characteristics, &mck_lock,
|
||||
CLK_SET_RATE_GATE);
|
||||
if (IS_ERR(hw))
|
||||
goto err_free;
|
||||
|
||||
sama5d4_pmc->chws[PMC_MCK] = hw;
|
||||
|
||||
hw = at91_clk_register_h32mx(regmap, "h32mxck", "masterck");
|
||||
hw = at91_clk_register_h32mx(regmap, "h32mxck", "masterck_div");
|
||||
if (IS_ERR(hw))
|
||||
goto err_free;
|
||||
|
||||
|
@ -215,7 +227,7 @@ static void __init sama5d4_pmc_setup(struct device_node *np)
|
|||
parent_names[1] = "mainck";
|
||||
parent_names[2] = "plladivck";
|
||||
parent_names[3] = "utmick";
|
||||
parent_names[4] = "masterck";
|
||||
parent_names[4] = "masterck_div";
|
||||
for (i = 0; i < 3; i++) {
|
||||
char name[6];
|
||||
|
||||
|
@ -245,7 +257,7 @@ static void __init sama5d4_pmc_setup(struct device_node *np)
|
|||
hw = at91_clk_register_sam9x5_peripheral(regmap, &pmc_pcr_lock,
|
||||
&sama5d4_pcr_layout,
|
||||
sama5d4_periphck[i].n,
|
||||
"masterck",
|
||||
"masterck_div",
|
||||
sama5d4_periphck[i].id,
|
||||
&range, INT_MIN);
|
||||
if (IS_ERR(hw))
|
||||
|
|
|
@ -32,6 +32,7 @@
|
|||
} while (0)
|
||||
|
||||
static DEFINE_SPINLOCK(pmc_pll_lock);
|
||||
static DEFINE_SPINLOCK(pmc_mck0_lock);
|
||||
static DEFINE_SPINLOCK(pmc_mckX_lock);
|
||||
|
||||
/**
|
||||
|
@ -89,118 +90,198 @@ static const struct clk_pll_layout pll_layout_divio = {
|
|||
.endiv_shift = 30,
|
||||
};
|
||||
|
||||
/*
|
||||
* CPU PLL output range.
|
||||
* Notice: The upper limit has been setup to 1000000002 due to hardware
|
||||
* block which cannot output exactly 1GHz.
|
||||
*/
|
||||
static const struct clk_range cpu_pll_outputs[] = {
|
||||
{ .min = 2343750, .max = 1000000002 },
|
||||
};
|
||||
|
||||
/* PLL output range. */
|
||||
static const struct clk_range pll_outputs[] = {
|
||||
{ .min = 2343750, .max = 1200000000 },
|
||||
};
|
||||
|
||||
/* CPU PLL characteristics. */
|
||||
static const struct clk_pll_characteristics cpu_pll_characteristics = {
|
||||
.input = { .min = 12000000, .max = 50000000 },
|
||||
.num_output = ARRAY_SIZE(cpu_pll_outputs),
|
||||
.output = cpu_pll_outputs,
|
||||
};
|
||||
|
||||
/* PLL characteristics. */
|
||||
static const struct clk_pll_characteristics pll_characteristics = {
|
||||
.input = { .min = 12000000, .max = 50000000 },
|
||||
.num_output = ARRAY_SIZE(pll_outputs),
|
||||
.output = pll_outputs,
|
||||
};
|
||||
|
||||
/**
|
||||
* PLL clocks description
|
||||
* @n: clock name
|
||||
* @p: clock parent
|
||||
* @l: clock layout
|
||||
* @c: clock characteristics
|
||||
* @t: clock type
|
||||
* @f: true if clock is critical and cannot be disabled
|
||||
* @f: clock flags
|
||||
* @eid: export index in sama7g5->chws[] array
|
||||
*/
|
||||
static const struct {
|
||||
const char *n;
|
||||
const char *p;
|
||||
const struct clk_pll_layout *l;
|
||||
const struct clk_pll_characteristics *c;
|
||||
unsigned long f;
|
||||
u8 t;
|
||||
u8 c;
|
||||
u8 eid;
|
||||
} sama7g5_plls[][PLL_ID_MAX] = {
|
||||
[PLL_ID_CPU] = {
|
||||
{ .n = "cpupll_fracck",
|
||||
.p = "mainck",
|
||||
.l = &pll_layout_frac,
|
||||
.c = &cpu_pll_characteristics,
|
||||
.t = PLL_TYPE_FRAC,
|
||||
.c = 1, },
|
||||
/*
|
||||
* This feeds cpupll_divpmcck which feeds CPU. It should
|
||||
* not be disabled.
|
||||
*/
|
||||
.f = CLK_IS_CRITICAL, },
|
||||
|
||||
{ .n = "cpupll_divpmcck",
|
||||
.p = "cpupll_fracck",
|
||||
.l = &pll_layout_divpmc,
|
||||
.c = &cpu_pll_characteristics,
|
||||
.t = PLL_TYPE_DIV,
|
||||
.c = 1, },
|
||||
/* This feeds CPU. It should not be disabled. */
|
||||
.f = CLK_IS_CRITICAL | CLK_SET_RATE_PARENT,
|
||||
.eid = PMC_CPUPLL, },
|
||||
},
|
||||
|
||||
[PLL_ID_SYS] = {
|
||||
{ .n = "syspll_fracck",
|
||||
.p = "mainck",
|
||||
.l = &pll_layout_frac,
|
||||
.c = &pll_characteristics,
|
||||
.t = PLL_TYPE_FRAC,
|
||||
.c = 1, },
|
||||
/*
|
||||
* This feeds syspll_divpmcck which may feed critial parts
|
||||
* of the systems like timers. Therefore it should not be
|
||||
* disabled.
|
||||
*/
|
||||
.f = CLK_IS_CRITICAL | CLK_SET_RATE_GATE, },
|
||||
|
||||
{ .n = "syspll_divpmcck",
|
||||
.p = "syspll_fracck",
|
||||
.l = &pll_layout_divpmc,
|
||||
.c = &pll_characteristics,
|
||||
.t = PLL_TYPE_DIV,
|
||||
.c = 1, },
|
||||
/*
|
||||
* This may feed critial parts of the systems like timers.
|
||||
* Therefore it should not be disabled.
|
||||
*/
|
||||
.f = CLK_IS_CRITICAL | CLK_SET_RATE_GATE,
|
||||
.eid = PMC_SYSPLL, },
|
||||
},
|
||||
|
||||
[PLL_ID_DDR] = {
|
||||
{ .n = "ddrpll_fracck",
|
||||
.p = "mainck",
|
||||
.l = &pll_layout_frac,
|
||||
.c = &pll_characteristics,
|
||||
.t = PLL_TYPE_FRAC,
|
||||
.c = 1, },
|
||||
/*
|
||||
* This feeds ddrpll_divpmcck which feeds DDR. It should not
|
||||
* be disabled.
|
||||
*/
|
||||
.f = CLK_IS_CRITICAL | CLK_SET_RATE_GATE, },
|
||||
|
||||
{ .n = "ddrpll_divpmcck",
|
||||
.p = "ddrpll_fracck",
|
||||
.l = &pll_layout_divpmc,
|
||||
.c = &pll_characteristics,
|
||||
.t = PLL_TYPE_DIV,
|
||||
.c = 1, },
|
||||
/* This feeds DDR. It should not be disabled. */
|
||||
.f = CLK_IS_CRITICAL | CLK_SET_RATE_GATE, },
|
||||
},
|
||||
|
||||
[PLL_ID_IMG] = {
|
||||
{ .n = "imgpll_fracck",
|
||||
.p = "mainck",
|
||||
.l = &pll_layout_frac,
|
||||
.t = PLL_TYPE_FRAC, },
|
||||
.c = &pll_characteristics,
|
||||
.t = PLL_TYPE_FRAC,
|
||||
.f = CLK_SET_RATE_GATE, },
|
||||
|
||||
{ .n = "imgpll_divpmcck",
|
||||
.p = "imgpll_fracck",
|
||||
.l = &pll_layout_divpmc,
|
||||
.t = PLL_TYPE_DIV, },
|
||||
.c = &pll_characteristics,
|
||||
.t = PLL_TYPE_DIV,
|
||||
.f = CLK_SET_RATE_GATE | CLK_SET_PARENT_GATE |
|
||||
CLK_SET_RATE_PARENT, },
|
||||
},
|
||||
|
||||
[PLL_ID_BAUD] = {
|
||||
{ .n = "baudpll_fracck",
|
||||
.p = "mainck",
|
||||
.l = &pll_layout_frac,
|
||||
.t = PLL_TYPE_FRAC, },
|
||||
.c = &pll_characteristics,
|
||||
.t = PLL_TYPE_FRAC,
|
||||
.f = CLK_SET_RATE_GATE, },
|
||||
|
||||
{ .n = "baudpll_divpmcck",
|
||||
.p = "baudpll_fracck",
|
||||
.l = &pll_layout_divpmc,
|
||||
.t = PLL_TYPE_DIV, },
|
||||
.c = &pll_characteristics,
|
||||
.t = PLL_TYPE_DIV,
|
||||
.f = CLK_SET_RATE_GATE | CLK_SET_PARENT_GATE |
|
||||
CLK_SET_RATE_PARENT, },
|
||||
},
|
||||
|
||||
[PLL_ID_AUDIO] = {
|
||||
{ .n = "audiopll_fracck",
|
||||
.p = "main_xtal",
|
||||
.l = &pll_layout_frac,
|
||||
.t = PLL_TYPE_FRAC, },
|
||||
.c = &pll_characteristics,
|
||||
.t = PLL_TYPE_FRAC,
|
||||
.f = CLK_SET_RATE_GATE, },
|
||||
|
||||
{ .n = "audiopll_divpmcck",
|
||||
.p = "audiopll_fracck",
|
||||
.l = &pll_layout_divpmc,
|
||||
.c = &pll_characteristics,
|
||||
.t = PLL_TYPE_DIV,
|
||||
.eid = PMC_I2S0_MUX, },
|
||||
.f = CLK_SET_RATE_GATE | CLK_SET_PARENT_GATE |
|
||||
CLK_SET_RATE_PARENT,
|
||||
.eid = PMC_AUDIOPMCPLL, },
|
||||
|
||||
{ .n = "audiopll_diviock",
|
||||
.p = "audiopll_fracck",
|
||||
.l = &pll_layout_divio,
|
||||
.c = &pll_characteristics,
|
||||
.t = PLL_TYPE_DIV,
|
||||
.eid = PMC_I2S1_MUX, },
|
||||
.f = CLK_SET_RATE_GATE | CLK_SET_PARENT_GATE |
|
||||
CLK_SET_RATE_PARENT,
|
||||
.eid = PMC_AUDIOIOPLL, },
|
||||
},
|
||||
|
||||
[PLL_ID_ETH] = {
|
||||
{ .n = "ethpll_fracck",
|
||||
.p = "main_xtal",
|
||||
.l = &pll_layout_frac,
|
||||
.t = PLL_TYPE_FRAC, },
|
||||
.c = &pll_characteristics,
|
||||
.t = PLL_TYPE_FRAC,
|
||||
.f = CLK_SET_RATE_GATE, },
|
||||
|
||||
{ .n = "ethpll_divpmcck",
|
||||
.p = "ethpll_fracck",
|
||||
.l = &pll_layout_divpmc,
|
||||
.t = PLL_TYPE_DIV, },
|
||||
.c = &pll_characteristics,
|
||||
.t = PLL_TYPE_DIV,
|
||||
.f = CLK_SET_RATE_GATE | CLK_SET_PARENT_GATE |
|
||||
CLK_SET_RATE_PARENT, },
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -245,7 +326,7 @@ static const struct {
|
|||
.ep = { "syspll_divpmcck", "ddrpll_divpmcck", "imgpll_divpmcck", },
|
||||
.ep_mux_table = { 5, 6, 7, },
|
||||
.ep_count = 3,
|
||||
.ep_chg_id = 6, },
|
||||
.ep_chg_id = 5, },
|
||||
|
||||
{ .n = "mck4",
|
||||
.id = 4,
|
||||
|
@ -278,7 +359,7 @@ static const struct {
|
|||
};
|
||||
|
||||
/* Mux table for programmable clocks. */
|
||||
static u32 sama7g5_prog_mux_table[] = { 0, 1, 2, 3, 5, 6, 7, 8, 9, 10, };
|
||||
static u32 sama7g5_prog_mux_table[] = { 0, 1, 2, 5, 6, 7, 8, 9, 10, };
|
||||
|
||||
/**
|
||||
* Peripheral clock description
|
||||
|
@ -401,7 +482,7 @@ static const struct {
|
|||
.pp = { "audiopll_divpmcck", },
|
||||
.pp_mux_table = { 9, },
|
||||
.pp_count = 1,
|
||||
.pp_chg_id = 4, },
|
||||
.pp_chg_id = 3, },
|
||||
|
||||
{ .n = "csi_gclk",
|
||||
.id = 33,
|
||||
|
@ -513,7 +594,7 @@ static const struct {
|
|||
.pp = { "ethpll_divpmcck", },
|
||||
.pp_mux_table = { 10, },
|
||||
.pp_count = 1,
|
||||
.pp_chg_id = 4, },
|
||||
.pp_chg_id = 3, },
|
||||
|
||||
{ .n = "gmac1_gclk",
|
||||
.id = 52,
|
||||
|
@ -545,7 +626,7 @@ static const struct {
|
|||
.pp = { "syspll_divpmcck", "audiopll_divpmcck", },
|
||||
.pp_mux_table = { 5, 9, },
|
||||
.pp_count = 2,
|
||||
.pp_chg_id = 5, },
|
||||
.pp_chg_id = 4, },
|
||||
|
||||
{ .n = "i2smcc1_gclk",
|
||||
.id = 58,
|
||||
|
@ -553,7 +634,7 @@ static const struct {
|
|||
.pp = { "syspll_divpmcck", "audiopll_divpmcck", },
|
||||
.pp_mux_table = { 5, 9, },
|
||||
.pp_count = 2,
|
||||
.pp_chg_id = 5, },
|
||||
.pp_chg_id = 4, },
|
||||
|
||||
{ .n = "mcan0_gclk",
|
||||
.id = 61,
|
||||
|
@ -695,7 +776,7 @@ static const struct {
|
|||
.pp = { "syspll_divpmcck", "baudpll_divpmcck", },
|
||||
.pp_mux_table = { 5, 8, },
|
||||
.pp_count = 2,
|
||||
.pp_chg_id = 5, },
|
||||
.pp_chg_id = 4, },
|
||||
|
||||
{ .n = "sdmmc1_gclk",
|
||||
.id = 81,
|
||||
|
@ -703,7 +784,7 @@ static const struct {
|
|||
.pp = { "syspll_divpmcck", "baudpll_divpmcck", },
|
||||
.pp_mux_table = { 5, 8, },
|
||||
.pp_count = 2,
|
||||
.pp_chg_id = 5, },
|
||||
.pp_chg_id = 4, },
|
||||
|
||||
{ .n = "sdmmc2_gclk",
|
||||
.id = 82,
|
||||
|
@ -711,7 +792,7 @@ static const struct {
|
|||
.pp = { "syspll_divpmcck", "baudpll_divpmcck", },
|
||||
.pp_mux_table = { 5, 8, },
|
||||
.pp_count = 2,
|
||||
.pp_chg_id = 5, },
|
||||
.pp_chg_id = 4, },
|
||||
|
||||
{ .n = "spdifrx_gclk",
|
||||
.id = 84,
|
||||
|
@ -719,7 +800,7 @@ static const struct {
|
|||
.pp = { "syspll_divpmcck", "audiopll_divpmcck", },
|
||||
.pp_mux_table = { 5, 9, },
|
||||
.pp_count = 2,
|
||||
.pp_chg_id = 5, },
|
||||
.pp_chg_id = 4, },
|
||||
|
||||
{ .n = "spdiftx_gclk",
|
||||
.id = 85,
|
||||
|
@ -727,7 +808,7 @@ static const struct {
|
|||
.pp = { "syspll_divpmcck", "audiopll_divpmcck", },
|
||||
.pp_mux_table = { 5, 9, },
|
||||
.pp_count = 2,
|
||||
.pp_chg_id = 5, },
|
||||
.pp_chg_id = 4, },
|
||||
|
||||
{ .n = "tcb0_ch0_gclk",
|
||||
.id = 88,
|
||||
|
@ -758,28 +839,16 @@ static const struct {
|
|||
.pp_chg_id = INT_MIN, },
|
||||
};
|
||||
|
||||
/* PLL output range. */
|
||||
static const struct clk_range pll_outputs[] = {
|
||||
{ .min = 2343750, .max = 1200000000 },
|
||||
};
|
||||
|
||||
/* PLL characteristics. */
|
||||
static const struct clk_pll_characteristics pll_characteristics = {
|
||||
.input = { .min = 12000000, .max = 50000000 },
|
||||
.num_output = ARRAY_SIZE(pll_outputs),
|
||||
.output = pll_outputs,
|
||||
};
|
||||
|
||||
/* MCK0 characteristics. */
|
||||
static const struct clk_master_characteristics mck0_characteristics = {
|
||||
.output = { .min = 140000000, .max = 200000000 },
|
||||
.divisors = { 1, 2, 4, 3 },
|
||||
.output = { .min = 50000000, .max = 200000000 },
|
||||
.divisors = { 1, 2, 4, 3, 5 },
|
||||
.have_div3_pres = 1,
|
||||
};
|
||||
|
||||
/* MCK0 layout. */
|
||||
static const struct clk_master_layout mck0_layout = {
|
||||
.mask = 0x373,
|
||||
.mask = 0x773,
|
||||
.pres_shift = 4,
|
||||
.offset = 0x28,
|
||||
};
|
||||
|
@ -835,10 +904,10 @@ static void __init sama7g5_pmc_setup(struct device_node *np)
|
|||
if (IS_ERR(regmap))
|
||||
return;
|
||||
|
||||
sama7g5_pmc = pmc_data_allocate(PMC_I2S1_MUX + 1,
|
||||
sama7g5_pmc = pmc_data_allocate(PMC_CPU + 1,
|
||||
nck(sama7g5_systemck),
|
||||
nck(sama7g5_periphck),
|
||||
nck(sama7g5_gck));
|
||||
nck(sama7g5_gck), 8);
|
||||
if (!sama7g5_pmc)
|
||||
return;
|
||||
|
||||
|
@ -886,18 +955,18 @@ static void __init sama7g5_pmc_setup(struct device_node *np)
|
|||
hw = sam9x60_clk_register_frac_pll(regmap,
|
||||
&pmc_pll_lock, sama7g5_plls[i][j].n,
|
||||
sama7g5_plls[i][j].p, parent_hw, i,
|
||||
&pll_characteristics,
|
||||
sama7g5_plls[i][j].c,
|
||||
sama7g5_plls[i][j].l,
|
||||
sama7g5_plls[i][j].c);
|
||||
sama7g5_plls[i][j].f);
|
||||
break;
|
||||
|
||||
case PLL_TYPE_DIV:
|
||||
hw = sam9x60_clk_register_div_pll(regmap,
|
||||
&pmc_pll_lock, sama7g5_plls[i][j].n,
|
||||
sama7g5_plls[i][j].p, i,
|
||||
&pll_characteristics,
|
||||
sama7g5_plls[i][j].c,
|
||||
sama7g5_plls[i][j].l,
|
||||
sama7g5_plls[i][j].c);
|
||||
sama7g5_plls[i][j].f);
|
||||
break;
|
||||
|
||||
default:
|
||||
|
@ -912,12 +981,19 @@ static void __init sama7g5_pmc_setup(struct device_node *np)
|
|||
}
|
||||
}
|
||||
|
||||
parent_names[0] = md_slck_name;
|
||||
parent_names[1] = "mainck";
|
||||
parent_names[2] = "cpupll_divpmcck";
|
||||
parent_names[3] = "syspll_divpmcck";
|
||||
hw = at91_clk_register_master(regmap, "mck0", 4, parent_names,
|
||||
&mck0_layout, &mck0_characteristics);
|
||||
parent_names[0] = "cpupll_divpmcck";
|
||||
hw = at91_clk_register_master_pres(regmap, "cpuck", 1, parent_names,
|
||||
&mck0_layout, &mck0_characteristics,
|
||||
&pmc_mck0_lock,
|
||||
CLK_SET_RATE_PARENT, 0);
|
||||
if (IS_ERR(hw))
|
||||
goto err_free;
|
||||
|
||||
sama7g5_pmc->chws[PMC_CPU] = hw;
|
||||
|
||||
hw = at91_clk_register_master_div(regmap, "mck0", "cpuck",
|
||||
&mck0_layout, &mck0_characteristics,
|
||||
&pmc_mck0_lock, 0);
|
||||
if (IS_ERR(hw))
|
||||
goto err_free;
|
||||
|
||||
|
@ -926,9 +1002,8 @@ static void __init sama7g5_pmc_setup(struct device_node *np)
|
|||
parent_names[0] = md_slck_name;
|
||||
parent_names[1] = td_slck_name;
|
||||
parent_names[2] = "mainck";
|
||||
parent_names[3] = "mck0";
|
||||
for (i = 0; i < ARRAY_SIZE(sama7g5_mckx); i++) {
|
||||
u8 num_parents = 4 + sama7g5_mckx[i].ep_count;
|
||||
u8 num_parents = 3 + sama7g5_mckx[i].ep_count;
|
||||
u32 *mux_table;
|
||||
|
||||
mux_table = kmalloc_array(num_parents, sizeof(*mux_table),
|
||||
|
@ -936,10 +1011,10 @@ static void __init sama7g5_pmc_setup(struct device_node *np)
|
|||
if (!mux_table)
|
||||
goto err_free;
|
||||
|
||||
SAMA7G5_INIT_TABLE(mux_table, 4);
|
||||
SAMA7G5_FILL_TABLE(&mux_table[4], sama7g5_mckx[i].ep_mux_table,
|
||||
SAMA7G5_INIT_TABLE(mux_table, 3);
|
||||
SAMA7G5_FILL_TABLE(&mux_table[3], sama7g5_mckx[i].ep_mux_table,
|
||||
sama7g5_mckx[i].ep_count);
|
||||
SAMA7G5_FILL_TABLE(&parent_names[4], sama7g5_mckx[i].ep,
|
||||
SAMA7G5_FILL_TABLE(&parent_names[3], sama7g5_mckx[i].ep,
|
||||
sama7g5_mckx[i].ep_count);
|
||||
|
||||
hw = at91_clk_sama7g5_register_master(regmap, sama7g5_mckx[i].n,
|
||||
|
@ -962,24 +1037,25 @@ static void __init sama7g5_pmc_setup(struct device_node *np)
|
|||
parent_names[0] = md_slck_name;
|
||||
parent_names[1] = td_slck_name;
|
||||
parent_names[2] = "mainck";
|
||||
parent_names[3] = "mck0";
|
||||
parent_names[4] = "syspll_divpmcck";
|
||||
parent_names[5] = "ddrpll_divpmcck";
|
||||
parent_names[6] = "imgpll_divpmcck";
|
||||
parent_names[7] = "baudpll_divpmcck";
|
||||
parent_names[8] = "audiopll_divpmcck";
|
||||
parent_names[9] = "ethpll_divpmcck";
|
||||
parent_names[3] = "syspll_divpmcck";
|
||||
parent_names[4] = "ddrpll_divpmcck";
|
||||
parent_names[5] = "imgpll_divpmcck";
|
||||
parent_names[6] = "baudpll_divpmcck";
|
||||
parent_names[7] = "audiopll_divpmcck";
|
||||
parent_names[8] = "ethpll_divpmcck";
|
||||
for (i = 0; i < 8; i++) {
|
||||
char name[6];
|
||||
|
||||
snprintf(name, sizeof(name), "prog%d", i);
|
||||
|
||||
hw = at91_clk_register_programmable(regmap, name, parent_names,
|
||||
10, i,
|
||||
9, i,
|
||||
&programmable_layout,
|
||||
sama7g5_prog_mux_table);
|
||||
if (IS_ERR(hw))
|
||||
goto err_free;
|
||||
|
||||
sama7g5_pmc->pchws[i] = hw;
|
||||
}
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(sama7g5_systemck); i++) {
|
||||
|
@ -1010,9 +1086,8 @@ static void __init sama7g5_pmc_setup(struct device_node *np)
|
|||
parent_names[0] = md_slck_name;
|
||||
parent_names[1] = td_slck_name;
|
||||
parent_names[2] = "mainck";
|
||||
parent_names[3] = "mck0";
|
||||
for (i = 0; i < ARRAY_SIZE(sama7g5_gck); i++) {
|
||||
u8 num_parents = 4 + sama7g5_gck[i].pp_count;
|
||||
u8 num_parents = 3 + sama7g5_gck[i].pp_count;
|
||||
u32 *mux_table;
|
||||
|
||||
mux_table = kmalloc_array(num_parents, sizeof(*mux_table),
|
||||
|
@ -1020,10 +1095,10 @@ static void __init sama7g5_pmc_setup(struct device_node *np)
|
|||
if (!mux_table)
|
||||
goto err_free;
|
||||
|
||||
SAMA7G5_INIT_TABLE(mux_table, 4);
|
||||
SAMA7G5_FILL_TABLE(&mux_table[4], sama7g5_gck[i].pp_mux_table,
|
||||
SAMA7G5_INIT_TABLE(mux_table, 3);
|
||||
SAMA7G5_FILL_TABLE(&mux_table[3], sama7g5_gck[i].pp_mux_table,
|
||||
sama7g5_gck[i].pp_count);
|
||||
SAMA7G5_FILL_TABLE(&parent_names[4], sama7g5_gck[i].pp,
|
||||
SAMA7G5_FILL_TABLE(&parent_names[3], sama7g5_gck[i].pp,
|
||||
sama7g5_gck[i].pp_count);
|
||||
|
||||
hw = at91_clk_register_generated(regmap, &pmc_pcr_lock,
|
||||
|
@ -1052,7 +1127,7 @@ err_free:
|
|||
kfree(alloc_mem);
|
||||
}
|
||||
|
||||
pmc_data_free(sama7g5_pmc);
|
||||
kfree(sama7g5_pmc);
|
||||
}
|
||||
|
||||
/* Some clks are used for a clocksource */
|
||||
|
|
|
@ -46,9 +46,17 @@
|
|||
#define MMCM_CLK_DIV_DIVIDE BIT(11)
|
||||
#define MMCM_CLK_DIV_NOCOUNT BIT(12)
|
||||
|
||||
struct axi_clkgen_limits {
|
||||
unsigned int fpfd_min;
|
||||
unsigned int fpfd_max;
|
||||
unsigned int fvco_min;
|
||||
unsigned int fvco_max;
|
||||
};
|
||||
|
||||
struct axi_clkgen {
|
||||
void __iomem *base;
|
||||
struct clk_hw clk_hw;
|
||||
struct axi_clkgen_limits limits;
|
||||
};
|
||||
|
||||
static uint32_t axi_clkgen_lookup_filter(unsigned int m)
|
||||
|
@ -100,12 +108,15 @@ static uint32_t axi_clkgen_lookup_lock(unsigned int m)
|
|||
return 0x1f1f00fa;
|
||||
}
|
||||
|
||||
static const unsigned int fpfd_min = 10000;
|
||||
static const unsigned int fpfd_max = 300000;
|
||||
static const unsigned int fvco_min = 600000;
|
||||
static const unsigned int fvco_max = 1200000;
|
||||
static const struct axi_clkgen_limits axi_clkgen_zynq_default_limits = {
|
||||
.fpfd_min = 10000,
|
||||
.fpfd_max = 300000,
|
||||
.fvco_min = 600000,
|
||||
.fvco_max = 1200000,
|
||||
};
|
||||
|
||||
static void axi_clkgen_calc_params(unsigned long fin, unsigned long fout,
|
||||
static void axi_clkgen_calc_params(const struct axi_clkgen_limits *limits,
|
||||
unsigned long fin, unsigned long fout,
|
||||
unsigned int *best_d, unsigned int *best_m, unsigned int *best_dout)
|
||||
{
|
||||
unsigned long d, d_min, d_max, _d_min, _d_max;
|
||||
|
@ -122,12 +133,12 @@ static void axi_clkgen_calc_params(unsigned long fin, unsigned long fout,
|
|||
*best_m = 0;
|
||||
*best_dout = 0;
|
||||
|
||||
d_min = max_t(unsigned long, DIV_ROUND_UP(fin, fpfd_max), 1);
|
||||
d_max = min_t(unsigned long, fin / fpfd_min, 80);
|
||||
d_min = max_t(unsigned long, DIV_ROUND_UP(fin, limits->fpfd_max), 1);
|
||||
d_max = min_t(unsigned long, fin / limits->fpfd_min, 80);
|
||||
|
||||
again:
|
||||
fvco_min_fract = fvco_min << fract_shift;
|
||||
fvco_max_fract = fvco_max << fract_shift;
|
||||
fvco_min_fract = limits->fvco_min << fract_shift;
|
||||
fvco_max_fract = limits->fvco_max << fract_shift;
|
||||
|
||||
m_min = max_t(unsigned long, DIV_ROUND_UP(fvco_min_fract, fin) * d_min, 1);
|
||||
m_max = min_t(unsigned long, fvco_max_fract * d_max / fin, 64 << fract_shift);
|
||||
|
@ -319,6 +330,7 @@ static int axi_clkgen_set_rate(struct clk_hw *clk_hw,
|
|||
unsigned long rate, unsigned long parent_rate)
|
||||
{
|
||||
struct axi_clkgen *axi_clkgen = clk_hw_to_axi_clkgen(clk_hw);
|
||||
const struct axi_clkgen_limits *limits = &axi_clkgen->limits;
|
||||
unsigned int d, m, dout;
|
||||
struct axi_clkgen_div_params params;
|
||||
uint32_t power = 0;
|
||||
|
@ -328,7 +340,7 @@ static int axi_clkgen_set_rate(struct clk_hw *clk_hw,
|
|||
if (parent_rate == 0 || rate == 0)
|
||||
return -EINVAL;
|
||||
|
||||
axi_clkgen_calc_params(parent_rate, rate, &d, &m, &dout);
|
||||
axi_clkgen_calc_params(limits, parent_rate, rate, &d, &m, &dout);
|
||||
|
||||
if (d == 0 || dout == 0 || m == 0)
|
||||
return -EINVAL;
|
||||
|
@ -368,10 +380,12 @@ static int axi_clkgen_set_rate(struct clk_hw *clk_hw,
|
|||
static long axi_clkgen_round_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long *parent_rate)
|
||||
{
|
||||
struct axi_clkgen *axi_clkgen = clk_hw_to_axi_clkgen(hw);
|
||||
const struct axi_clkgen_limits *limits = &axi_clkgen->limits;
|
||||
unsigned int d, m, dout;
|
||||
unsigned long long tmp;
|
||||
|
||||
axi_clkgen_calc_params(*parent_rate, rate, &d, &m, &dout);
|
||||
axi_clkgen_calc_params(limits, *parent_rate, rate, &d, &m, &dout);
|
||||
|
||||
if (d == 0 || dout == 0 || m == 0)
|
||||
return -EINVAL;
|
||||
|
@ -482,17 +496,9 @@ static const struct clk_ops axi_clkgen_ops = {
|
|||
.get_parent = axi_clkgen_get_parent,
|
||||
};
|
||||
|
||||
static const struct of_device_id axi_clkgen_ids[] = {
|
||||
{
|
||||
.compatible = "adi,axi-clkgen-2.00.a",
|
||||
},
|
||||
{ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, axi_clkgen_ids);
|
||||
|
||||
static int axi_clkgen_probe(struct platform_device *pdev)
|
||||
{
|
||||
const struct of_device_id *id;
|
||||
const struct axi_clkgen_limits *dflt_limits;
|
||||
struct axi_clkgen *axi_clkgen;
|
||||
struct clk_init_data init;
|
||||
const char *parent_names[2];
|
||||
|
@ -501,11 +507,8 @@ static int axi_clkgen_probe(struct platform_device *pdev)
|
|||
unsigned int i;
|
||||
int ret;
|
||||
|
||||
if (!pdev->dev.of_node)
|
||||
return -ENODEV;
|
||||
|
||||
id = of_match_node(axi_clkgen_ids, pdev->dev.of_node);
|
||||
if (!id)
|
||||
dflt_limits = device_get_match_data(&pdev->dev);
|
||||
if (!dflt_limits)
|
||||
return -ENODEV;
|
||||
|
||||
axi_clkgen = devm_kzalloc(&pdev->dev, sizeof(*axi_clkgen), GFP_KERNEL);
|
||||
|
@ -527,6 +530,8 @@ static int axi_clkgen_probe(struct platform_device *pdev)
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
memcpy(&axi_clkgen->limits, dflt_limits, sizeof(axi_clkgen->limits));
|
||||
|
||||
clk_name = pdev->dev.of_node->name;
|
||||
of_property_read_string(pdev->dev.of_node, "clock-output-names",
|
||||
&clk_name);
|
||||
|
@ -554,6 +559,15 @@ static int axi_clkgen_remove(struct platform_device *pdev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id axi_clkgen_ids[] = {
|
||||
{
|
||||
.compatible = "adi,axi-clkgen-2.00.a",
|
||||
.data = &axi_clkgen_zynq_default_limits,
|
||||
},
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, axi_clkgen_ids);
|
||||
|
||||
static struct platform_driver axi_clkgen_driver = {
|
||||
.driver = {
|
||||
.name = "adi-axi-clkgen",
|
||||
|
|
|
@ -902,6 +902,10 @@ static int _si5351_clkout_set_disable_state(
|
|||
static void _si5351_clkout_reset_pll(struct si5351_driver_data *drvdata, int num)
|
||||
{
|
||||
u8 val = si5351_reg_read(drvdata, SI5351_CLK0_CTRL + num);
|
||||
u8 mask = val & SI5351_CLK_PLL_SELECT ? SI5351_PLL_RESET_B :
|
||||
SI5351_PLL_RESET_A;
|
||||
unsigned int v;
|
||||
int err;
|
||||
|
||||
switch (val & SI5351_CLK_INPUT_MASK) {
|
||||
case SI5351_CLK_INPUT_XTAL:
|
||||
|
@ -909,9 +913,12 @@ static void _si5351_clkout_reset_pll(struct si5351_driver_data *drvdata, int num
|
|||
return; /* pll not used, no need to reset */
|
||||
}
|
||||
|
||||
si5351_reg_write(drvdata, SI5351_PLL_RESET,
|
||||
val & SI5351_CLK_PLL_SELECT ? SI5351_PLL_RESET_B :
|
||||
SI5351_PLL_RESET_A);
|
||||
si5351_reg_write(drvdata, SI5351_PLL_RESET, mask);
|
||||
|
||||
err = regmap_read_poll_timeout(drvdata->regmap, SI5351_PLL_RESET, v,
|
||||
!(v & mask), 0, 20000);
|
||||
if (err < 0)
|
||||
dev_err(&drvdata->client->dev, "Reset bit didn't clear\n");
|
||||
|
||||
dev_dbg(&drvdata->client->dev, "%s - %s: pll = %d\n",
|
||||
__func__, clk_hw_get_name(&drvdata->clkout[num].hw),
|
||||
|
|
|
@ -2314,6 +2314,8 @@ int clk_set_rate_range(struct clk *clk, unsigned long min, unsigned long max)
|
|||
if (!clk)
|
||||
return 0;
|
||||
|
||||
trace_clk_set_rate_range(clk->core, min, max);
|
||||
|
||||
if (min > max) {
|
||||
pr_err("%s: clk %s dev %s con %s: invalid range [%lu, %lu]\n",
|
||||
__func__, clk->core->name, clk->dev_id, clk->con_id,
|
||||
|
@ -2381,6 +2383,8 @@ int clk_set_min_rate(struct clk *clk, unsigned long rate)
|
|||
if (!clk)
|
||||
return 0;
|
||||
|
||||
trace_clk_set_min_rate(clk->core, rate);
|
||||
|
||||
return clk_set_rate_range(clk, rate, clk->max_rate);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(clk_set_min_rate);
|
||||
|
@ -2397,6 +2401,8 @@ int clk_set_max_rate(struct clk *clk, unsigned long rate)
|
|||
if (!clk)
|
||||
return 0;
|
||||
|
||||
trace_clk_set_max_rate(clk->core, rate);
|
||||
|
||||
return clk_set_rate_range(clk, clk->min_rate, rate);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(clk_set_max_rate);
|
||||
|
|
|
@ -605,7 +605,7 @@ static struct ti_dt_clk omap54xx_clks[] = {
|
|||
int __init omap5xxx_dt_clk_init(void)
|
||||
{
|
||||
int rc;
|
||||
struct clk *abe_dpll_ref, *abe_dpll, *sys_32k_ck, *usb_dpll;
|
||||
struct clk *abe_dpll_ref, *abe_dpll, *abe_dpll_byp, *sys_32k_ck, *usb_dpll;
|
||||
|
||||
ti_dt_clocks_register(omap54xx_clks);
|
||||
|
||||
|
@ -616,6 +616,16 @@ int __init omap5xxx_dt_clk_init(void)
|
|||
abe_dpll_ref = clk_get_sys(NULL, "abe_dpll_clk_mux");
|
||||
sys_32k_ck = clk_get_sys(NULL, "sys_32k_ck");
|
||||
rc = clk_set_parent(abe_dpll_ref, sys_32k_ck);
|
||||
|
||||
/*
|
||||
* This must also be set to sys_32k_ck to match or
|
||||
* the ABE DPLL will not lock on a warm reboot when
|
||||
* ABE timers are used.
|
||||
*/
|
||||
abe_dpll_byp = clk_get_sys(NULL, "abe_dpll_bypass_clk_mux");
|
||||
if (!rc)
|
||||
rc = clk_set_parent(abe_dpll_byp, sys_32k_ck);
|
||||
|
||||
abe_dpll = clk_get_sys(NULL, "dpll_abe_ck");
|
||||
if (!rc)
|
||||
rc = clk_set_rate(abe_dpll, OMAP5_DPLL_ABE_DEFFREQ);
|
||||
|
|
|
@ -498,6 +498,7 @@ static struct clk * __init ti_fapll_synth_setup(struct fapll_data *fd,
|
|||
{
|
||||
struct clk_init_data *init;
|
||||
struct fapll_synth *synth;
|
||||
struct clk *clk = ERR_PTR(-ENOMEM);
|
||||
|
||||
init = kzalloc(sizeof(*init), GFP_KERNEL);
|
||||
if (!init)
|
||||
|
@ -520,13 +521,19 @@ static struct clk * __init ti_fapll_synth_setup(struct fapll_data *fd,
|
|||
synth->hw.init = init;
|
||||
synth->clk_pll = pll_clk;
|
||||
|
||||
return clk_register(NULL, &synth->hw);
|
||||
clk = clk_register(NULL, &synth->hw);
|
||||
if (IS_ERR(clk)) {
|
||||
pr_err("failed to register clock\n");
|
||||
goto free;
|
||||
}
|
||||
|
||||
return clk;
|
||||
|
||||
free:
|
||||
kfree(synth);
|
||||
kfree(init);
|
||||
|
||||
return ERR_PTR(-ENOMEM);
|
||||
return clk;
|
||||
}
|
||||
|
||||
static void __init ti_fapll_setup(struct device_node *node)
|
||||
|
|
|
@ -25,6 +25,17 @@
|
|||
#define PMC_PLLBCK 8
|
||||
#define PMC_AUDIOPLLCK 9
|
||||
|
||||
/* SAMA7G5 */
|
||||
#define PMC_CPUPLL (PMC_MAIN + 1)
|
||||
#define PMC_SYSPLL (PMC_MAIN + 2)
|
||||
#define PMC_DDRPLL (PMC_MAIN + 3)
|
||||
#define PMC_IMGPLL (PMC_MAIN + 4)
|
||||
#define PMC_BAUDPLL (PMC_MAIN + 5)
|
||||
#define PMC_AUDIOPMCPLL (PMC_MAIN + 6)
|
||||
#define PMC_AUDIOIOPLL (PMC_MAIN + 7)
|
||||
#define PMC_ETHPLL (PMC_MAIN + 8)
|
||||
#define PMC_CPU (PMC_MAIN + 9)
|
||||
|
||||
#ifndef AT91_PMC_MOSCS
|
||||
#define AT91_PMC_MOSCS 0 /* MOSCS Flag */
|
||||
#define AT91_PMC_LOCKA 1 /* PLLA Lock */
|
||||
|
|
|
@ -118,6 +118,50 @@ DEFINE_EVENT(clk_rate, clk_set_rate_complete,
|
|||
TP_ARGS(core, rate)
|
||||
);
|
||||
|
||||
DEFINE_EVENT(clk_rate, clk_set_min_rate,
|
||||
|
||||
TP_PROTO(struct clk_core *core, unsigned long rate),
|
||||
|
||||
TP_ARGS(core, rate)
|
||||
);
|
||||
|
||||
DEFINE_EVENT(clk_rate, clk_set_max_rate,
|
||||
|
||||
TP_PROTO(struct clk_core *core, unsigned long rate),
|
||||
|
||||
TP_ARGS(core, rate)
|
||||
);
|
||||
|
||||
DECLARE_EVENT_CLASS(clk_rate_range,
|
||||
|
||||
TP_PROTO(struct clk_core *core, unsigned long min, unsigned long max),
|
||||
|
||||
TP_ARGS(core, min, max),
|
||||
|
||||
TP_STRUCT__entry(
|
||||
__string( name, core->name )
|
||||
__field(unsigned long, min )
|
||||
__field(unsigned long, max )
|
||||
),
|
||||
|
||||
TP_fast_assign(
|
||||
__assign_str(name, core->name);
|
||||
__entry->min = min;
|
||||
__entry->max = max;
|
||||
),
|
||||
|
||||
TP_printk("%s min %lu max %lu", __get_str(name),
|
||||
(unsigned long)__entry->min,
|
||||
(unsigned long)__entry->max)
|
||||
);
|
||||
|
||||
DEFINE_EVENT(clk_rate_range, clk_set_rate_range,
|
||||
|
||||
TP_PROTO(struct clk_core *core, unsigned long min, unsigned long max),
|
||||
|
||||
TP_ARGS(core, min, max)
|
||||
);
|
||||
|
||||
DECLARE_EVENT_CLASS(clk_parent,
|
||||
|
||||
TP_PROTO(struct clk_core *core, struct clk_core *parent),
|
||||
|
|
Loading…
Reference in New Issue