Commit 94c5216e authored by Olof Johansson's avatar Olof Johansson

Merge tag 'at91-cleanup' of git://github.com/at91linux/linux-at91 into next/cleanup

From Nicolas Ferre:
AT91: Move to Common Clock Framework and sama5d3 implementation
This is the first step to move AT91 to the CCF.
- core CCF and drivers for most of the clocks
- use of CCF for sama5d3 (100% DT-based)

* tag 'at91-cleanup' of git://github.com/at91linux/linux-at91: (22 commits)
  ARM: at91/dt: remove old clk material
  ARM: at91: move sama5d3 SoC to common clk
  ARM: at91/dt: define sama5d3xek's main clk frequency
  ARM: at91/dt: define sama5d3 clocks
  ARM: at91: prepare common clk transition for sama5d3 SoC
  ARM: at91: prepare sama5 dt boards transition to common clk
  ARM: at91: add new compatible strings for pmc driver
  ARM: at91: move pit timer to common clk framework
  dt: binding: add at91 clks dt bindings documentation
  clk: at91: add PMC smd clock
  clk: at91: add PMC usb clock
  clk: at91: add PMC utmi clock
  clk: at91: add PMC programmable clocks
  clk: at91: add PMC peripheral clocks
  clk: at91: add PMC system clocks
  clk: at91: add PMC master clock
  clk: at91: add PMC pll clocks
  clk: at91: add PMC main clock
  clk: at91: add PMC macro file for dt definitions
  clk: at91: add PMC base support
  ...
Signed-off-by: default avatarOlof Johansson <olof@lixom.net>
parents 330641ce b46e837d
This diff is collapsed.
This diff is collapsed.
...@@ -32,12 +32,30 @@ pinctrl_can1_rx_tx: can1_rx_tx { ...@@ -32,12 +32,30 @@ pinctrl_can1_rx_tx: can1_rx_tx {
}; };
pmc: pmc@fffffc00 {
periphck {
can0_clk: can0_clk {
#clock-cells = <0>;
reg = <40>;
atmel,clk-output-range = <0 66000000>;
};
can1_clk: can0_clk {
#clock-cells = <0>;
reg = <41>;
atmel,clk-output-range = <0 66000000>;
};
};
};
can0: can@f000c000 { can0: can@f000c000 {
compatible = "atmel,at91sam9x5-can"; compatible = "atmel,at91sam9x5-can";
reg = <0xf000c000 0x300>; reg = <0xf000c000 0x300>;
interrupts = <40 IRQ_TYPE_LEVEL_HIGH 3>; interrupts = <40 IRQ_TYPE_LEVEL_HIGH 3>;
pinctrl-names = "default"; pinctrl-names = "default";
pinctrl-0 = <&pinctrl_can0_rx_tx>; pinctrl-0 = <&pinctrl_can0_rx_tx>;
clocks = <&can0_clk>;
clock-names = "can_clk";
status = "disabled"; status = "disabled";
}; };
...@@ -47,6 +65,8 @@ can1: can@f8010000 { ...@@ -47,6 +65,8 @@ can1: can@f8010000 {
interrupts = <41 IRQ_TYPE_LEVEL_HIGH 3>; interrupts = <41 IRQ_TYPE_LEVEL_HIGH 3>;
pinctrl-names = "default"; pinctrl-names = "default";
pinctrl-0 = <&pinctrl_can1_rx_tx>; pinctrl-0 = <&pinctrl_can1_rx_tx>;
clocks = <&can1_clk>;
clock-names = "can_clk";
status = "disabled"; status = "disabled";
}; };
}; };
......
...@@ -31,12 +31,23 @@ AT91_PIOC 8 AT91_PERIPH_A AT91_PINCTRL_NONE /* PC8 periph A EMDC, conflicts with ...@@ -31,12 +31,23 @@ AT91_PIOC 8 AT91_PERIPH_A AT91_PINCTRL_NONE /* PC8 periph A EMDC, conflicts with
}; };
}; };
pmc: pmc@fffffc00 {
periphck {
macb1_clk: macb1_clk {
#clock-cells = <0>;
reg = <35>;
};
};
};
macb1: ethernet@f802c000 { macb1: ethernet@f802c000 {
compatible = "cdns,at32ap7000-macb", "cdns,macb"; compatible = "cdns,at32ap7000-macb", "cdns,macb";
reg = <0xf802c000 0x100>; reg = <0xf802c000 0x100>;
interrupts = <35 IRQ_TYPE_LEVEL_HIGH 3>; interrupts = <35 IRQ_TYPE_LEVEL_HIGH 3>;
pinctrl-names = "default"; pinctrl-names = "default";
pinctrl-0 = <&pinctrl_macb1_rmii>; pinctrl-0 = <&pinctrl_macb1_rmii>;
clocks = <&macb1_clk>, <&macb1_clk>;
clock-names = "hclk", "pclk";
status = "disabled"; status = "disabled";
}; };
}; };
......
...@@ -64,12 +64,23 @@ AT91_PIOB 17 AT91_PERIPH_A AT91_PINCTRL_NONE /* PB17 periph A GMDIO */ ...@@ -64,12 +64,23 @@ AT91_PIOB 17 AT91_PERIPH_A AT91_PINCTRL_NONE /* PB17 periph A GMDIO */
}; };
}; };
pmc: pmc@fffffc00 {
periphck {
macb0_clk: macb0_clk {
#clock-cells = <0>;
reg = <34>;
};
};
};
macb0: ethernet@f0028000 { macb0: ethernet@f0028000 {
compatible = "cdns,pc302-gem", "cdns,gem"; compatible = "cdns,pc302-gem", "cdns,gem";
reg = <0xf0028000 0x100>; reg = <0xf0028000 0x100>;
interrupts = <34 IRQ_TYPE_LEVEL_HIGH 3>; interrupts = <34 IRQ_TYPE_LEVEL_HIGH 3>;
pinctrl-names = "default"; pinctrl-names = "default";
pinctrl-0 = <&pinctrl_macb0_data_rgmii &pinctrl_macb0_signal_rgmii>; pinctrl-0 = <&pinctrl_macb0_data_rgmii &pinctrl_macb0_signal_rgmii>;
clocks = <&macb0_clk>, <&macb0_clk>;
clock-names = "hclk", "pclk";
status = "disabled"; status = "disabled";
}; };
}; };
......
...@@ -50,6 +50,23 @@ AT91_PIOE 27 AT91_PERIPH_C AT91_PINCTRL_NONE /* PE27 periph C LCDD22 pin */ ...@@ -50,6 +50,23 @@ AT91_PIOE 27 AT91_PERIPH_C AT91_PINCTRL_NONE /* PE27 periph C LCDD22 pin */
}; };
}; };
}; };
pmc: pmc@fffffc00 {
periphck {
lcdc_clk: lcdc_clk {
#clock-cells = <0>;
reg = <36>;
};
};
systemck {
lcdck: lcdck {
#clock-cells = <0>;
reg = <3>;
clocks = <&mck>;
};
};
};
}; };
}; };
}; };
...@@ -9,6 +9,7 @@ ...@@ -9,6 +9,7 @@
#include <dt-bindings/pinctrl/at91.h> #include <dt-bindings/pinctrl/at91.h>
#include <dt-bindings/interrupt-controller/irq.h> #include <dt-bindings/interrupt-controller/irq.h>
#include <dt-bindings/clk/at91.h>
/ { / {
ahb { ahb {
...@@ -30,6 +31,15 @@ AT91_PIOC 13 AT91_PERIPH_A AT91_PINCTRL_NONE /* PC13 periph A MCI2_DA2 with pull ...@@ -30,6 +31,15 @@ AT91_PIOC 13 AT91_PERIPH_A AT91_PINCTRL_NONE /* PC13 periph A MCI2_DA2 with pull
}; };
}; };
pmc: pmc@fffffc00 {
periphck {
mci2_clk: mci2_clk {
#clock-cells = <0>;
reg = <23>;
};
};
};
mmc2: mmc@f8004000 { mmc2: mmc@f8004000 {
compatible = "atmel,hsmci"; compatible = "atmel,hsmci";
reg = <0xf8004000 0x600>; reg = <0xf8004000 0x600>;
...@@ -38,6 +48,8 @@ mmc2: mmc@f8004000 { ...@@ -38,6 +48,8 @@ mmc2: mmc@f8004000 {
dma-names = "rxtx"; dma-names = "rxtx";
pinctrl-names = "default"; pinctrl-names = "default";
pinctrl-0 = <&pinctrl_mmc2_clk_cmd_dat0 &pinctrl_mmc2_dat1_3>; pinctrl-0 = <&pinctrl_mmc2_clk_cmd_dat0 &pinctrl_mmc2_dat1_3>;
clocks = <&mci2_clk>;
clock-names = "mci_clk";
status = "disabled"; status = "disabled";
#address-cells = <1>; #address-cells = <1>;
#size-cells = <0>; #size-cells = <0>;
......
...@@ -9,6 +9,7 @@ ...@@ -9,6 +9,7 @@
#include <dt-bindings/pinctrl/at91.h> #include <dt-bindings/pinctrl/at91.h>
#include <dt-bindings/interrupt-controller/irq.h> #include <dt-bindings/interrupt-controller/irq.h>
#include <dt-bindings/clk/at91.h>
/ { / {
aliases { aliases {
...@@ -17,10 +18,21 @@ aliases { ...@@ -17,10 +18,21 @@ aliases {
ahb { ahb {
apb { apb {
pmc: pmc@fffffc00 {
periphck {
tcb1_clk: tcb1_clk {
#clock-cells = <0>;
reg = <27>;
};
};
};
tcb1: timer@f8014000 { tcb1: timer@f8014000 {
compatible = "atmel,at91sam9x5-tcb"; compatible = "atmel,at91sam9x5-tcb";
reg = <0xf8014000 0x100>; reg = <0xf8014000 0x100>;
interrupts = <27 IRQ_TYPE_LEVEL_HIGH 0>; interrupts = <27 IRQ_TYPE_LEVEL_HIGH 0>;
clocks = <&tcb1_clk>;
clock-names = "t0_clk";
}; };
}; };
}; };
......
...@@ -9,6 +9,7 @@ ...@@ -9,6 +9,7 @@
#include <dt-bindings/pinctrl/at91.h> #include <dt-bindings/pinctrl/at91.h>
#include <dt-bindings/interrupt-controller/irq.h> #include <dt-bindings/interrupt-controller/irq.h>
#include <dt-bindings/clk/at91.h>
/ { / {
ahb { ahb {
...@@ -31,12 +32,30 @@ pinctrl_uart1: uart1-0 { ...@@ -31,12 +32,30 @@ pinctrl_uart1: uart1-0 {
}; };
}; };
pmc: pmc@fffffc00 {
periphck {
uart0_clk: uart0_clk {
#clock-cells = <0>;
reg = <16>;
atmel,clk-output-range = <0 66000000>;
};
uart1_clk: uart1_clk {
#clock-cells = <0>;
reg = <17>;
atmel,clk-output-range = <0 66000000>;
};
};
};
uart0: serial@f0024000 { uart0: serial@f0024000 {
compatible = "atmel,at91sam9260-usart"; compatible = "atmel,at91sam9260-usart";
reg = <0xf0024000 0x200>; reg = <0xf0024000 0x200>;
interrupts = <16 IRQ_TYPE_LEVEL_HIGH 5>; interrupts = <16 IRQ_TYPE_LEVEL_HIGH 5>;
pinctrl-names = "default"; pinctrl-names = "default";
pinctrl-0 = <&pinctrl_uart0>; pinctrl-0 = <&pinctrl_uart0>;
clocks = <&uart0_clk>;
clock-names = "usart";
status = "disabled"; status = "disabled";
}; };
...@@ -46,6 +65,8 @@ uart1: serial@f8028000 { ...@@ -46,6 +65,8 @@ uart1: serial@f8028000 {
interrupts = <17 IRQ_TYPE_LEVEL_HIGH 5>; interrupts = <17 IRQ_TYPE_LEVEL_HIGH 5>;
pinctrl-names = "default"; pinctrl-names = "default";
pinctrl-0 = <&pinctrl_uart1>; pinctrl-0 = <&pinctrl_uart1>;
clocks = <&uart1_clk>;
clock-names = "usart";
status = "disabled"; status = "disabled";
}; };
}; };
......
...@@ -18,17 +18,6 @@ memory { ...@@ -18,17 +18,6 @@ memory {
reg = <0x20000000 0x20000000>; reg = <0x20000000 0x20000000>;
}; };
clocks {
#address-cells = <1>;
#size-cells = <1>;
ranges;
main_clock: clock@0 {
compatible = "atmel,osc", "fixed-clock";
clock-frequency = <12000000>;
};
};
ahb { ahb {
apb { apb {
spi0: spi@f0004000 { spi0: spi@f0004000 {
...@@ -38,6 +27,12 @@ spi0: spi@f0004000 { ...@@ -38,6 +27,12 @@ spi0: spi@f0004000 {
macb0: ethernet@f0028000 { macb0: ethernet@f0028000 {
phy-mode = "rgmii"; phy-mode = "rgmii";
}; };
pmc: pmc@fffffc00 {
main: mainck {
clock-frequency = <12000000>;
};
};
}; };
nand0: nand@60000000 { nand0: nand@60000000 {
......
if ARCH_AT91 if ARCH_AT91
config HAVE_AT91_UTMI
bool
config HAVE_AT91_USB_CLK
bool
config HAVE_AT91_DBGU0 config HAVE_AT91_DBGU0
bool bool
config HAVE_AT91_DBGU1 config HAVE_AT91_DBGU1
bool bool
config AT91_USE_OLD_CLK
bool
config AT91_PMC_UNIT config AT91_PMC_UNIT
bool bool
default !ARCH_AT91X40 default !ARCH_AT91X40
config COMMON_CLK_AT91
bool
default AT91_PMC_UNIT && USE_OF && !AT91_USE_OLD_CLK
select COMMON_CLK
config OLD_CLK_AT91
bool
default AT91_PMC_UNIT && AT91_USE_OLD_CLK
config AT91_SAM9_ALT_RESET config AT91_SAM9_ALT_RESET
bool bool
default !ARCH_AT91X40 default !ARCH_AT91X40
...@@ -21,6 +39,9 @@ config AT91_SAM9G45_RESET ...@@ -21,6 +39,9 @@ config AT91_SAM9G45_RESET
config AT91_SAM9_TIME config AT91_SAM9_TIME
bool bool
config HAVE_AT91_SMD
bool
config SOC_AT91SAM9 config SOC_AT91SAM9
bool bool
select AT91_SAM9_TIME select AT91_SAM9_TIME
...@@ -65,6 +86,9 @@ config SOC_SAMA5D3 ...@@ -65,6 +86,9 @@ config SOC_SAMA5D3
select SOC_SAMA5 select SOC_SAMA5
select HAVE_FB_ATMEL select HAVE_FB_ATMEL
select HAVE_AT91_DBGU1 select HAVE_AT91_DBGU1
select HAVE_AT91_UTMI
select HAVE_AT91_SMD
select HAVE_AT91_USB_CLK
help help
Select this if you are using one of Atmel's SAMA5D3 family SoC. Select this if you are using one of Atmel's SAMA5D3 family SoC.
This support covers SAMA5D31, SAMA5D33, SAMA5D34, SAMA5D35. This support covers SAMA5D31, SAMA5D33, SAMA5D34, SAMA5D35.
...@@ -78,11 +102,15 @@ config SOC_AT91RM9200 ...@@ -78,11 +102,15 @@ config SOC_AT91RM9200
select HAVE_AT91_DBGU0 select HAVE_AT91_DBGU0
select MULTI_IRQ_HANDLER select MULTI_IRQ_HANDLER
select SPARSE_IRQ select SPARSE_IRQ
select AT91_USE_OLD_CLK
select HAVE_AT91_USB_CLK
config SOC_AT91SAM9260 config SOC_AT91SAM9260
bool "AT91SAM9260, AT91SAM9XE or AT91SAM9G20" bool "AT91SAM9260, AT91SAM9XE or AT91SAM9G20"
select HAVE_AT91_DBGU0 select HAVE_AT91_DBGU0
select SOC_AT91SAM9 select SOC_AT91SAM9
select AT91_USE_OLD_CLK
select HAVE_AT91_USB_CLK
help help
Select this if you are using one of Atmel's AT91SAM9260, AT91SAM9XE Select this if you are using one of Atmel's AT91SAM9260, AT91SAM9XE
or AT91SAM9G20 SoC. or AT91SAM9G20 SoC.
...@@ -92,6 +120,8 @@ config SOC_AT91SAM9261 ...@@ -92,6 +120,8 @@ config SOC_AT91SAM9261
select HAVE_AT91_DBGU0 select HAVE_AT91_DBGU0
select HAVE_FB_ATMEL select HAVE_FB_ATMEL
select SOC_AT91SAM9 select SOC_AT91SAM9
select AT91_USE_OLD_CLK
select HAVE_AT91_USB_CLK
help help
Select this if you are using one of Atmel's AT91SAM9261 or AT91SAM9G10 SoC. Select this if you are using one of Atmel's AT91SAM9261 or AT91SAM9G10 SoC.
...@@ -100,18 +130,25 @@ config SOC_AT91SAM9263 ...@@ -100,18 +130,25 @@ config SOC_AT91SAM9263
select HAVE_AT91_DBGU1 select HAVE_AT91_DBGU1
select HAVE_FB_ATMEL select HAVE_FB_ATMEL
select SOC_AT91SAM9 select SOC_AT91SAM9
select AT91_USE_OLD_CLK
select HAVE_AT91_USB_CLK
config SOC_AT91SAM9RL config SOC_AT91SAM9RL
bool "AT91SAM9RL" bool "AT91SAM9RL"
select HAVE_AT91_DBGU0 select HAVE_AT91_DBGU0
select HAVE_FB_ATMEL select HAVE_FB_ATMEL
select SOC_AT91SAM9 select SOC_AT91SAM9
select AT91_USE_OLD_CLK
select HAVE_AT91_UTMI
config SOC_AT91SAM9G45 config SOC_AT91SAM9G45
bool "AT91SAM9G45 or AT91SAM9M10 families" bool "AT91SAM9G45 or AT91SAM9M10 families"
select HAVE_AT91_DBGU1 select HAVE_AT91_DBGU1
select HAVE_FB_ATMEL select HAVE_FB_ATMEL
select SOC_AT91SAM9 select SOC_AT91SAM9
select AT91_USE_OLD_CLK
select HAVE_AT91_UTMI
select HAVE_AT91_USB_CLK
help help
Select this if you are using one of Atmel's AT91SAM9G45 family SoC. Select this if you are using one of Atmel's AT91SAM9G45 family SoC.
This support covers AT91SAM9G45, AT91SAM9G46, AT91SAM9M10 and AT91SAM9M11. This support covers AT91SAM9G45, AT91SAM9G46, AT91SAM9M10 and AT91SAM9M11.
...@@ -121,6 +158,10 @@ config SOC_AT91SAM9X5 ...@@ -121,6 +158,10 @@ config SOC_AT91SAM9X5
select HAVE_AT91_DBGU0 select HAVE_AT91_DBGU0
select HAVE_FB_ATMEL select HAVE_FB_ATMEL
select SOC_AT91SAM9 select SOC_AT91SAM9
select AT91_USE_OLD_CLK
select HAVE_AT91_UTMI
select HAVE_AT91_SMD
select HAVE_AT91_USB_CLK
help help
Select this if you are using one of Atmel's AT91SAM9x5 family SoC. Select this if you are using one of Atmel's AT91SAM9x5 family SoC.
This means that your SAM9 name finishes with a '5' (except if it is This means that your SAM9 name finishes with a '5' (except if it is
...@@ -133,6 +174,8 @@ config SOC_AT91SAM9N12 ...@@ -133,6 +174,8 @@ config SOC_AT91SAM9N12
select HAVE_AT91_DBGU0 select HAVE_AT91_DBGU0
select HAVE_FB_ATMEL select HAVE_FB_ATMEL
select SOC_AT91SAM9 select SOC_AT91SAM9
select AT91_USE_OLD_CLK
select HAVE_AT91_USB_CLK
help help
Select this if you are using Atmel's AT91SAM9N12 SoC. Select this if you are using Atmel's AT91SAM9N12 SoC.
......
...@@ -12,26 +12,32 @@ config ARCH_AT91_NONE ...@@ -12,26 +12,32 @@ config ARCH_AT91_NONE
config ARCH_AT91RM9200 config ARCH_AT91RM9200
bool "AT91RM9200" bool "AT91RM9200"
select SOC_AT91RM9200 select SOC_AT91RM9200
select AT91_USE_OLD_CLK
config ARCH_AT91SAM9260 config ARCH_AT91SAM9260
bool "AT91SAM9260 or AT91SAM9XE or AT91SAM9G20" bool "AT91SAM9260 or AT91SAM9XE or AT91SAM9G20"
select SOC_AT91SAM9260 select SOC_AT91SAM9260
select AT91_USE_OLD_CLK
config ARCH_AT91SAM9261 config ARCH_AT91SAM9261
bool "AT91SAM9261 or AT91SAM9G10" bool "AT91SAM9261 or AT91SAM9G10"
select SOC_AT91SAM9261 select SOC_AT91SAM9261
select AT91_USE_OLD_CLK
config ARCH_AT91SAM9263 config ARCH_AT91SAM9263
bool "AT91SAM9263" bool "AT91SAM9263"
select SOC_AT91SAM9263 select SOC_AT91SAM9263
select AT91_USE_OLD_CLK
config ARCH_AT91SAM9RL config ARCH_AT91SAM9RL
bool "AT91SAM9RL" bool "AT91SAM9RL"
select SOC_AT91SAM9RL select SOC_AT91SAM9RL
select AT91_USE_OLD_CLK
config ARCH_AT91SAM9G45 config ARCH_AT91SAM9G45
bool "AT91SAM9G45" bool "AT91SAM9G45"
select SOC_AT91SAM9G45 select SOC_AT91SAM9G45
select AT91_USE_OLD_CLK
config ARCH_AT91X40 config ARCH_AT91X40
bool "AT91x40" bool "AT91x40"
......
...@@ -7,7 +7,7 @@ obj-m := ...@@ -7,7 +7,7 @@ obj-m :=
obj-n := obj-n :=
obj- := obj- :=
obj-$(CONFIG_AT91_PMC_UNIT) += clock.o obj-$(CONFIG_OLD_CLK_AT91) += clock.o
obj-$(CONFIG_AT91_SAM9_ALT_RESET) += at91sam9_alt_reset.o obj-$(CONFIG_AT91_SAM9_ALT_RESET) += at91sam9_alt_reset.o
obj-$(CONFIG_AT91_SAM9G45_RESET) += at91sam9g45_reset.o obj-$(CONFIG_AT91_SAM9G45_RESET) += at91sam9g45_reset.o
obj-$(CONFIG_AT91_SAM9_TIME) += at91sam926x_time.o obj-$(CONFIG_AT91_SAM9_TIME) += at91sam926x_time.o
......
...@@ -12,13 +12,13 @@ ...@@ -12,13 +12,13 @@
#include <linux/module.h> #include <linux/module.h>
#include <linux/reboot.h> #include <linux/reboot.h>
#include <linux/clk/at91_pmc.h>
#include <asm/irq.h> #include <asm/irq.h>
#include <asm/mach/arch.h> #include <asm/mach/arch.h>
#include <asm/mach/map.h> #include <asm/mach/map.h>
#include <asm/system_misc.h> #include <asm/system_misc.h>
#include <mach/at91rm9200.h> #include <mach/at91rm9200.h>
#include <mach/at91_pmc.h>
#include <mach/at91_st.h> #include <mach/at91_st.h>
#include <mach/cpu.h> #include <mach/cpu.h>
......
...@@ -11,6 +11,7 @@ ...@@ -11,6 +11,7 @@
*/ */
#include <linux/module.h> #include <linux/module.h>
#include <linux/clk/at91_pmc.h>
#include <asm/proc-fns.h> #include <asm/proc-fns.h>
#include <asm/irq.h> #include <asm/irq.h>
...@@ -20,7 +21,6 @@ ...@@ -20,7 +21,6 @@
#include <mach/cpu.h> #include <mach/cpu.h>
#include <mach/at91_dbgu.h> #include <mach/at91_dbgu.h>
#include <mach/at91sam9260.h> #include <mach/at91sam9260.h>
#include <mach/at91_pmc.h>
#include "at91_aic.h" #include "at91_aic.h"
#include "at91_rstc.h" #include "at91_rstc.h"
......
...@@ -11,6 +11,7 @@ ...@@ -11,6 +11,7 @@
*/ */
#include <linux/module.h> #include <linux/module.h>
#include <linux/clk/at91_pmc.h>
#include <asm/proc-fns.h> #include <asm/proc-fns.h>
#include <asm/irq.h> #include <asm/irq.h>
...@@ -19,7 +20,6 @@ ...@@ -19,7 +20,6 @@
#include <asm/system_misc.h> #include <asm/system_misc.h>
#include <mach/cpu.h> #include <mach/cpu.h>
#include <mach/at91sam9261.h> #include <mach/at91sam9261.h>
#include <mach/at91_pmc.h>
#include "at91_aic.h" #include "at91_aic.h"
#include "at91_rstc.h" #include "at91_rstc.h"
......
...@@ -11,6 +11,7 @@ ...@@ -11,6 +11,7 @@
*/ */
#include <linux/module.h> #include <linux/module.h>
#include <linux/clk/at91_pmc.h>
#include <asm/proc-fns.h> #include <asm/proc-fns.h>
#include <asm/irq.h> #include <asm/irq.h>
...@@ -18,7 +19,6 @@ ...@@ -18,7 +19,6 @@
#include <asm/mach/map.h> #include <asm/mach/map.h>
#include <asm/system_misc.h> #include <asm/system_misc.h>
#include <mach/at91sam9263.h> #include <mach/at91sam9263.h>
#include <mach/at91_pmc.h>
#include "at91_aic.h" #include "at91_aic.h"
#include "at91_rstc.h" #include "at91_rstc.h"
......
...@@ -39,6 +39,7 @@ ...@@ -39,6 +39,7 @@
static u32 pit_cycle; /* write-once */ static u32 pit_cycle; /* write-once */
static u32 pit_cnt; /* access only w/system irq blocked */ static u32 pit_cnt; /* access only w/system irq blocked */
static void __iomem *pit_base_addr __read_mostly; static void __iomem *pit_base_addr __read_mostly;
static struct clk *mck;
static inline unsigned int pit_read(unsigned int reg_offset) static inline unsigned int pit_read(unsigned int reg_offset)
{ {
...@@ -195,10 +196,14 @@ static int __init of_at91sam926x_pit_init(void) ...@@ -195,10 +196,14 @@ static int __init of_at91sam926x_pit_init(void)
if (!pit_base_addr) if (!pit_base_addr)
goto node_err; goto node_err;
mck = of_clk_get(np, 0);
/* Get the interrupts property */ /* Get the interrupts property */
ret = irq_of_parse_and_map(np, 0); ret = irq_of_parse_and_map(np, 0);
if (!ret) { if (!ret) {
pr_crit("AT91: PIT: Unable to get IRQ from DT\n"); pr_crit("AT91: PIT: Unable to get IRQ from DT\n");
if (!IS_ERR(mck))
clk_put(mck);
goto ioremap_err; goto ioremap_err;
} }
at91sam926x_pit_irq.irq = ret; at91sam926x_pit_irq.irq = ret;
...@@ -230,6 +235,8 @@ void __init at91sam926x_pit_init(void) ...@@ -230,6 +235,8 @@ void __init at91sam926x_pit_init(void)
unsigned bits; unsigned bits;
int ret; int ret;
mck = ERR_PTR(-ENOENT);
/* For device tree enabled device: initialize here */ /* For device tree enabled device: initialize here */
of_at91sam926x_pit_init(); of_at91sam926x_pit_init();
...@@ -237,7 +244,12 @@ void __init at91sam926x_pit_init(void) ...@@ -237,7 +244,12 @@ void __init at91sam926x_pit_init(void)
* Use our actual MCK to figure out how many MCK/16 ticks per * Use our actual MCK to figure out how many MCK/16 ticks per
* 1/HZ period (instead of a compile-time constant LATCH). * 1/HZ period (instead of a compile-time constant LATCH).
*/ */
pit_rate = clk_get_rate(clk_get(NULL, "mck")) / 16; if (IS_ERR(mck))
mck = clk_get(NULL, "mck");
if (IS_ERR(mck))
panic("AT91: PIT: Unable to get mck clk\n");
pit_rate = clk_get_rate(mck) / 16;
pit_cycle = (pit_rate + HZ/2) / HZ; pit_cycle = (pit_rate + HZ/2) / HZ;
WARN_ON(((pit_cycle - 1) & ~AT91_PIT_PIV) != 0); WARN_ON(((pit_cycle - 1) & ~AT91_PIT_PIV) != 0);
......
...@@ -12,13 +12,13 @@ ...@@ -12,13 +12,13 @@
#include <linux/module.h> #include <linux/module.h>
#include <linux/dma-mapping.h> #include <linux/dma-mapping.h>
#include <linux/clk/at91_pmc.h>
#include <asm/irq.h> #include <asm/irq.h>
#include <asm/mach/arch.h> #include <asm/mach/arch.h>
#include <asm/mach/map.h> #include <asm/mach/map.h>
#include <asm/system_misc.h> #include <asm/system_misc.h>
#include <mach/at91sam9g45.h> #include <mach/at91sam9g45.h>
#include <mach/at91_pmc.h>
#include <mach/cpu.h> #include <mach/cpu.h>
#include "at91_aic.h" #include "at91_aic.h"
......
...@@ -8,12 +8,12 @@ ...@@ -8,12 +8,12 @@
#include <linux/module.h> #include <linux/module.h>
#include <linux/dma-mapping.h> #include <linux/dma-mapping.h>
#include <linux/clk/at91_pmc.h>
#include <asm/irq.h> #include <asm/irq.h>
#include <asm/mach/arch.h> #include <asm/mach/arch.h>
#include <asm/mach/map.h> #include <asm/mach/map.h>
#include <mach/at91sam9n12.h> #include <mach/at91sam9n12.h>
#include <mach/at91_pmc.h>
#include <mach/cpu.h> #include <mach/cpu.h>
#include "board.h" #include "board.h"
......
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
*/ */
#include <linux/module.h> #include <linux/module.h>
#include <linux/clk/at91_pmc.h>
#include <asm/proc-fns.h> #include <asm/proc-fns.h>
#include <asm/irq.h> #include <asm/irq.h>
...@@ -19,7 +20,6 @@ ...@@ -19,7 +20,6 @@
#include <mach/cpu.h> #include <mach/cpu.h>
#include <mach/at91_dbgu.h> #include <mach/at91_dbgu.h>
#include <mach/at91sam9rl.h> #include <mach/at91sam9rl.h>
#include <mach/at91_pmc.h>
#include "at91_aic.h" #include "at91_aic.h"
#include "at91_rstc.h" #include "at91_rstc.h"
......
...@@ -8,12 +8,12 @@ ...@@ -8,12 +8,12 @@
#include <linux/module.h> #include <linux/module.h>
#include <linux/dma-mapping.h> #include <linux/dma-mapping.h>
#include <linux/clk/at91_pmc.h>
#include <asm/irq.h> #include <asm/irq.h>
#include <asm/mach/arch.h> #include <asm/mach/arch.h>
#include <asm/mach/map.h> #include <asm/mach/map.h>
#include <mach/at91sam9x5.h> #include <mach/at91sam9x5.h>
#include <mach/at91_pmc.h>
#include <mach/cpu.h> #include <mach/cpu.h>
#include "board.h" #include "board.h"
......
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
#include <linux/of_irq.h> #include <linux/of_irq.h>
#include <linux/of_platform.h> #include <linux/of_platform.h>
#include <linux/phy.h> #include <linux/phy.h>
#include <linux/clk-provider.h>
#include <asm/setup.h> #include <asm/setup.h>
#include <asm/irq.h> #include <asm/irq.h>
...@@ -26,6 +27,13 @@ ...@@ -26,6 +27,13 @@
#include "at91_aic.h" #include "at91_aic.h"
#include "generic.h" #include "generic.h"
static void __init sama5_dt_timer_init(void)
{
#if defined(CONFIG_COMMON_CLK)
of_clk_init(NULL);
#endif
at91sam926x_pit_init();
}
static const struct of_device_id irq_of_match[] __initconst = { static const struct of_device_id irq_of_match[] __initconst = {
...@@ -72,7 +80,7 @@ static const char *sama5_dt_board_compat[] __initdata = { ...@@ -72,7 +80,7 @@ static const char *sama5_dt_board_compat[] __initdata = {
DT_MACHINE_START(sama5_dt, "Atmel SAMA5 (Device Tree)") DT_MACHINE_START(sama5_dt, "Atmel SAMA5 (Device Tree)")
/* Maintainer: Atmel */ /* Maintainer: Atmel */
.init_time = at91sam926x_pit_init, .init_time = sama5_dt_timer_init,
.map_io = at91_map_io, .map_io = at91_map_io,
.handle_irq = at91_aic5_handle_irq, .handle_irq = at91_aic5_handle_irq,
.init_early = at91_dt_initialize, .init_early = at91_dt_initialize,
......
...@@ -24,9 +24,9 @@ ...@@ -24,9 +24,9 @@
#include <linux/clk.h> #include <linux/clk.h>
#include <linux/io.h> #include <linux/io.h>
#include <linux/of_address.h> #include <linux/of_address.h>
#include <linux/clk/at91_pmc.h>
#include <mach/hardware.h> #include <mach/hardware.h>
#include <mach/at91_pmc.h>
#include <mach/cpu.h> #include <mach/cpu.h>
#include <asm/proc-fns.h> #include <asm/proc-fns.h>
...@@ -884,6 +884,11 @@ static int __init at91_pmc_init(unsigned long main_clock) ...@@ -884,6 +884,11 @@ static int __init at91_pmc_init(unsigned long main_clock)
#if defined(CONFIG_OF) #if defined(CONFIG_OF)
static struct of_device_id pmc_ids[] = { static struct of_device_id pmc_ids[] = {
{ .compatible = "atmel,at91rm9200-pmc" }, { .compatible = "atmel,at91rm9200-pmc" },
{ .compatible = "atmel,at91sam9260-pmc" },
{ .compatible = "atmel,at91sam9g45-pmc" },
{ .compatible = "atmel,at91sam9n12-pmc" },
{ .compatible = "atmel,at91sam9x5-pmc" },
{ .compatible = "atmel,sama5d3-pmc" },
{ /*sentinel*/ } { /*sentinel*/ }
}; };
......
...@@ -46,11 +46,12 @@ extern void at91sam926x_pit_init(void); ...@@ -46,11 +46,12 @@ extern void at91sam926x_pit_init(void);
extern void at91x40_timer_init(void); extern void at91x40_timer_init(void);
/* Clocks */ /* Clocks */
#ifdef CONFIG_AT91_PMC_UNIT #ifdef CONFIG_OLD_CLK_AT91
extern int __init at91_clock_init(unsigned long main_clock); extern int __init at91_clock_init(unsigned long main_clock);
extern int __init at91_dt_clock_init(void); extern int __init at91_dt_clock_init(void);
#else #else
static int inline at91_clock_init(unsigned long main_clock) { return 0; } static int inline at91_clock_init(unsigned long main_clock) { return 0; }
static int inline at91_dt_clock_init(void) { return 0; }
#endif #endif
struct device; struct device;
......
...@@ -19,13 +19,13 @@ ...@@ -19,13 +19,13 @@
#include <linux/module.h> #include <linux/module.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/io.h> #include <linux/io.h>
#include <linux/clk/at91_pmc.h>
#include <asm/irq.h> #include <asm/irq.h>
#include <linux/atomic.h> #include <linux/atomic.h>
#include <asm/mach/time.h> #include <asm/mach/time.h>
#include <asm/mach/irq.h> #include <asm/mach/irq.h>
#include <mach/at91_pmc.h>
#include <mach/cpu.h> #include <mach/cpu.h>
#include "at91_aic.h" #include "at91_aic.h"
......
...@@ -13,8 +13,8 @@ ...@@ -13,8 +13,8 @@
*/ */
#include <linux/linkage.h> #include <linux/linkage.h>
#include <linux/clk/at91_pmc.h>
#include <mach/hardware.h> #include <mach/hardware.h>
#include <mach/at91_pmc.h>
#include <mach/at91_ramc.h> #include <mach/at91_ramc.h>
......
...@@ -9,359 +9,18 @@ ...@@ -9,359 +9,18 @@
#include <linux/module.h> #include <linux/module.h>
#include <linux/dma-mapping.h> #include <linux/dma-mapping.h>
#include <linux/clk/at91_pmc.h>
#include <asm/irq.h> #include <asm/irq.h>
#include <asm/mach/arch.h> #include <asm/mach/arch.h>
#include <asm/mach/map.h> #include <asm/mach/map.h>
#include <mach/sama5d3.h> #include <mach/sama5d3.h>
#include <mach/at91_pmc.h>
#include <mach/cpu.h> #include <mach/cpu.h>
#include "soc.h" #include "soc.h"
#include "generic.h" #include "generic.h"
#include "clock.h"
#include "sam9_smc.h" #include "sam9_smc.h"
/* --------------------------------------------------------------------
* Clocks
* -------------------------------------------------------------------- */
/*
* The peripheral clocks.
*/
static struct clk pioA_clk = {
.name = "pioA_clk",
.pid = SAMA5D3_ID_PIOA,
.type = CLK_TYPE_PERIPHERAL,
};
static struct clk pioB_clk = {
.name = "pioB_clk",
.pid = SAMA5D3_ID_PIOB,
.type = CLK_TYPE_PERIPHERAL,
};
static struct clk pioC_clk = {
.name = "pioC_clk",
.pid = SAMA5D3_ID_PIOC,
.type = CLK_TYPE_PERIPHERAL,
};
static struct clk pioD_clk = {
.name = "pioD_clk",
.pid = SAMA5D3_ID_PIOD,
.type = CLK_TYPE_PERIPHERAL,
};
static struct clk pioE_clk = {
.name = "pioE_clk",
.pid = SAMA5D3_ID_PIOE,
.type = CLK_TYPE_PERIPHERAL,
};
static struct clk usart0_clk = {
.name = "usart0_clk",
.pid = SAMA5D3_ID_USART0,
.type = CLK_TYPE_PERIPHERAL,
.div = AT91_PMC_PCR_DIV2,
};
static struct clk usart1_clk = {
.name = "usart1_clk",
.pid = SAMA5D3_ID_USART1,
.type = CLK_TYPE_PERIPHERAL,
.div = AT91_PMC_PCR_DIV2,
};
static struct clk usart2_clk = {
.name = "usart2_clk",
.pid = SAMA5D3_ID_USART2,
.type = CLK_TYPE_PERIPHERAL,
.div = AT91_PMC_PCR_DIV2,
};
static struct clk usart3_clk = {
.name = "usart3_clk",
.pid = SAMA5D3_ID_USART3,
.type = CLK_TYPE_PERIPHERAL,
.div = AT91_PMC_PCR_DIV2,
};
static struct clk uart0_clk = {
.name = "uart0_clk",
.pid = SAMA5D3_ID_UART0,
.type = CLK_TYPE_PERIPHERAL,
.div = AT91_PMC_PCR_DIV2,
};
static struct clk uart1_clk = {
.name = "uart1_clk",
.pid = SAMA5D3_ID_UART1,
.type = CLK_TYPE_PERIPHERAL,
.div = AT91_PMC_PCR_DIV2,
};
static struct clk twi0_clk = {
.name = "twi0_clk",
.pid = SAMA5D3_ID_TWI0,
.type = CLK_TYPE_PERIPHERAL,
.div = AT91_PMC_PCR_DIV8,
};
static struct clk twi1_clk = {
.name = "twi1_clk",
.pid = SAMA5D3_ID_TWI1,
.type = CLK_TYPE_PERIPHERAL,
.div = AT91_PMC_PCR_DIV8,
};
static struct clk twi2_clk = {
.name = "twi2_clk",
.pid = SAMA5D3_ID_TWI2,
.type = CLK_TYPE_PERIPHERAL,
.div = AT91_PMC_PCR_DIV8,
};
static struct clk mmc0_clk = {
.name = "mci0_clk",
.pid = SAMA5D3_ID_HSMCI0,
.type = CLK_TYPE_PERIPHERAL,
};
static struct clk mmc1_clk = {
.name = "mci1_clk",
.pid = SAMA5D3_ID_HSMCI1,
.type = CLK_TYPE_PERIPHERAL,
};
static struct clk mmc2_clk = {
.name = "mci2_clk",
.pid = SAMA5D3_ID_HSMCI2,
.type = CLK_TYPE_PERIPHERAL,
};
static struct clk spi0_clk = {
.name = "spi0_clk",
.pid = SAMA5D3_ID_SPI0,
.type = CLK_TYPE_PERIPHERAL,
};
static struct clk spi1_clk = {
.name = "spi1_clk",
.pid = SAMA5D3_ID_SPI1,
.type = CLK_TYPE_PERIPHERAL,
};
static struct clk tcb0_clk = {
.name = "tcb0_clk",
.pid = SAMA5D3_ID_TC0,
.type = CLK_TYPE_PERIPHERAL,
.div = AT91_PMC_PCR_DIV2,
};
static struct clk tcb1_clk = {
.name = "tcb1_clk",
.pid = SAMA5D3_ID_TC1,
.type = CLK_TYPE_PERIPHERAL,
.div = AT91_PMC_PCR_DIV2,
};
static struct clk adc_clk = {
.name = "adc_clk",
.pid = SAMA5D3_ID_ADC,
.type = CLK_TYPE_PERIPHERAL,
.div = AT91_PMC_PCR_DIV2,
};
static struct clk adc_op_clk = {
.name = "adc_op_clk",
.type = CLK_TYPE_PERIPHERAL,
.rate_hz = 5000000,
};
static struct clk dma0_clk = {
.name = "dma0_clk",
.pid = SAMA5D3_ID_DMA0,
.type = CLK_TYPE_PERIPHERAL,
};
static struct clk dma1_clk = {
.name = "dma1_clk",
.pid = SAMA5D3_ID_DMA1,
.type = CLK_TYPE_PERIPHERAL,
};
static struct clk uhphs_clk = {
.name = "uhphs",
.pid = SAMA5D3_ID_UHPHS,
.type = CLK_TYPE_PERIPHERAL,
};
static struct clk udphs_clk = {
.name = "udphs_clk",
.pid = SAMA5D3_ID_UDPHS,
.type = CLK_TYPE_PERIPHERAL,
};
/* gmac only for sama5d33, sama5d34, sama5d35 */
static struct clk macb0_clk = {
.name = "macb0_clk",
.pid = SAMA5D3_ID_GMAC,
.type = CLK_TYPE_PERIPHERAL,
};
/* emac only for sama5d31, sama5d35 */
static struct clk macb1_clk = {
.name = "macb1_clk",
.pid = SAMA5D3_ID_EMAC,
.type = CLK_TYPE_PERIPHERAL,
};
/* lcd only for sama5d31, sama5d33, sama5d34 */
static struct clk lcdc_clk = {
.name = "lcdc_clk",
.pid = SAMA5D3_ID_LCDC,
.type = CLK_TYPE_PERIPHERAL,
};
/* isi only for sama5d33, sama5d35 */
static struct clk isi_clk = {
.name = "isi_clk",
.pid = SAMA5D3_ID_ISI,
.type = CLK_TYPE_PERIPHERAL,
};
static struct clk can0_clk = {
.name = "can0_clk",
.pid = SAMA5D3_ID_CAN0,
.type = CLK_TYPE_PERIPHERAL,
.div = AT91_PMC_PCR_DIV2,
};
static struct clk can1_clk = {
.name = "can1_clk",
.pid = SAMA5D3_ID_CAN1,
.type = CLK_TYPE_PERIPHERAL,
.div = AT91_PMC_PCR_DIV2,
};
static struct clk ssc0_clk = {
.name = "ssc0_clk",
.pid = SAMA5D3_ID_SSC0,
.type = CLK_TYPE_PERIPHERAL,
.div = AT91_PMC_PCR_DIV2,
};
static struct clk ssc1_clk = {
.name = "ssc1_clk",
.pid = SAMA5D3_ID_SSC1,
.type = CLK_TYPE_PERIPHERAL,
.div = AT91_PMC_PCR_DIV2,
};
static struct clk sha_clk = {
.name = "sha_clk",
.pid = SAMA5D3_ID_SHA,
.type = CLK_TYPE_PERIPHERAL,
.div = AT91_PMC_PCR_DIV8,
};
static struct clk aes_clk = {
.name = "aes_clk",
.pid = SAMA5D3_ID_AES,
.type = CLK_TYPE_PERIPHERAL,
};
static struct clk tdes_clk = {
.name = "tdes_clk",
.pid = SAMA5D3_ID_TDES,
.type = CLK_TYPE_PERIPHERAL,
};
static struct clk *periph_clocks[] __initdata = {
&pioA_clk,
&pioB_clk,
&pioC_clk,
&pioD_clk,
&pioE_clk,
&usart0_clk,
&usart1_clk,
&usart2_clk,
&usart3_clk,
&uart0_clk,
&uart1_clk,
&twi0_clk,
&twi1_clk,
&twi2_clk,
&mmc0_clk,
&mmc1_clk,
&mmc2_clk,
&spi0_clk,
&spi1_clk,
&tcb0_clk,
&tcb1_clk,
&adc_clk,
&adc_op_clk,
&dma0_clk,
&dma1_clk,
&uhphs_clk,
&udphs_clk,
&macb0_clk,
&macb1_clk,
&lcdc_clk,
&isi_clk,
&can0_clk,
&can1_clk,
&ssc0_clk,
&ssc1_clk,
&sha_clk,
&aes_clk,
&tdes_clk,
};
static struct clk pck0 = {
.name = "pck0",
.pmc_mask = AT91_PMC_PCK0,
.type = CLK_TYPE_PROGRAMMABLE,
.id = 0,
};
static struct clk pck1 = {
.name = "pck1",
.pmc_mask = AT91_PMC_PCK1,
.type = CLK_TYPE_PROGRAMMABLE,
.id = 1,
};
static struct clk pck2 = {
.name = "pck2",
.pmc_mask = AT91_PMC_PCK2,
.type = CLK_TYPE_PROGRAMMABLE,
.id = 2,
};
static struct clk_lookup periph_clocks_lookups[] = {
/* lookup table for DT entries */
CLKDEV_CON_DEV_ID("usart", "ffffee00.serial", &mck),
CLKDEV_CON_DEV_ID(NULL, "fffff200.gpio", &pioA_clk),
CLKDEV_CON_DEV_ID(NULL, "fffff400.gpio", &pioB_clk),
CLKDEV_CON_DEV_ID(NULL, "fffff600.gpio", &pioC_clk),
CLKDEV_CON_DEV_ID(NULL, "fffff800.gpio", &pioD_clk),
CLKDEV_CON_DEV_ID(NULL, "fffffa00.gpio", &pioE_clk),
CLKDEV_CON_DEV_ID("usart", "f001c000.serial", &usart0_clk),
CLKDEV_CON_DEV_ID("usart", "f0020000.serial", &usart1_clk),
CLKDEV_CON_DEV_ID("usart", "f8020000.serial", &usart2_clk),
CLKDEV_CON_DEV_ID("usart", "f8024000.serial", &usart3_clk),
CLKDEV_CON_DEV_ID(NULL, "f0014000.i2c", &twi0_clk),
CLKDEV_CON_DEV_ID(NULL, "f0018000.i2c", &twi1_clk),
CLKDEV_CON_DEV_ID(NULL, "f801c000.i2c", &twi2_clk),
CLKDEV_CON_DEV_ID("mci_clk", "f0000000.mmc", &mmc0_clk),
CLKDEV_CON_DEV_ID("mci_clk", "f8000000.mmc", &mmc1_clk),
CLKDEV_CON_DEV_ID("mci_clk", "f8004000.mmc", &mmc2_clk),
CLKDEV_CON_DEV_ID("spi_clk", "f0004000.spi", &spi0_clk),
CLKDEV_CON_DEV_ID("spi_clk", "f8008000.spi", &spi1_clk),
CLKDEV_CON_DEV_ID("t0_clk", "f0010000.timer", &tcb0_clk),
CLKDEV_CON_DEV_ID("t0_clk", "f8014000.timer", &tcb1_clk),
CLKDEV_CON_DEV_ID("tsc_clk", "f8018000.tsadcc", &adc_clk),
CLKDEV_CON_DEV_ID("dma_clk", "ffffe600.dma-controller", &dma0_clk),
CLKDEV_CON_DEV_ID("dma_clk", "ffffe800.dma-controller", &dma1_clk),
CLKDEV_CON_DEV_ID("hclk", "600000.ohci", &uhphs_clk),
CLKDEV_CON_DEV_ID("ohci_clk", "600000.ohci", &uhphs_clk),
CLKDEV_CON_DEV_ID("ehci_clk", "700000.ehci", &uhphs_clk),
CLKDEV_CON_DEV_ID("pclk", "500000.gadget", &udphs_clk),
CLKDEV_CON_DEV_ID("hclk", "500000.gadget", &utmi_clk),
CLKDEV_CON_DEV_ID("hclk", "f0028000.ethernet", &macb0_clk),
CLKDEV_CON_DEV_ID("pclk", "f0028000.ethernet", &macb0_clk),
CLKDEV_CON_DEV_ID("hclk", "f802c000.ethernet", &macb1_clk),
CLKDEV_CON_DEV_ID("pclk", "f802c000.ethernet", &macb1_clk),
CLKDEV_CON_DEV_ID("pclk", "f0008000.ssc", &ssc0_clk),
CLKDEV_CON_DEV_ID("pclk", "f000c000.ssc", &ssc1_clk),
CLKDEV_CON_DEV_ID("can_clk", "f000c000.can", &can0_clk),
CLKDEV_CON_DEV_ID("can_clk", "f8010000.can", &can1_clk),
CLKDEV_CON_DEV_ID("sha_clk", "f8034000.sha", &sha_clk),
CLKDEV_CON_DEV_ID("aes_clk", "f8038000.aes", &aes_clk),
CLKDEV_CON_DEV_ID("tdes_clk", "f803c000.tdes", &tdes_clk),
};
static void __init sama5d3_register_clocks(void)
{
int i;
for (i = 0; i < ARRAY_SIZE(periph_clocks); i++)
clk_register(periph_clocks[i]);
clkdev_add_table(periph_clocks_lookups,
ARRAY_SIZE(periph_clocks_lookups));
clk_register(&pck0);
clk_register(&pck1);
clk_register(&pck2);
}
/* -------------------------------------------------------------------- /* --------------------------------------------------------------------
* AT91SAM9x5 processor initialization * AT91SAM9x5 processor initialization
* -------------------------------------------------------------------- */ * -------------------------------------------------------------------- */
...@@ -378,6 +37,5 @@ static void __init sama5d3_initialize(void) ...@@ -378,6 +37,5 @@ static void __init sama5d3_initialize(void)
AT91_SOC_START(sama5d3) AT91_SOC_START(sama5d3)
.map_io = sama5d3_map_io, .map_io = sama5d3_map_io,
.register_clocks = sama5d3_register_clocks,
.init = sama5d3_initialize, .init = sama5d3_initialize,
AT91_SOC_END AT91_SOC_END
...@@ -11,6 +11,7 @@ ...@@ -11,6 +11,7 @@
#include <linux/pm.h> #include <linux/pm.h>
#include <linux/of_address.h> #include <linux/of_address.h>
#include <linux/pinctrl/machine.h> #include <linux/pinctrl/machine.h>
#include <linux/clk/at91_pmc.h>
#include <asm/system_misc.h> #include <asm/system_misc.h>
#include <asm/mach/map.h> #include <asm/mach/map.h>
...@@ -18,7 +19,6 @@ ...@@ -18,7 +19,6 @@
#include <mach/hardware.h> #include <mach/hardware.h>
#include <mach/cpu.h> #include <mach/cpu.h>
#include <mach/at91_dbgu.h> #include <mach/at91_dbgu.h>
#include <mach/at91_pmc.h>
#include "at91_shdwc.h" #include "at91_shdwc.h"
#include "soc.h" #include "soc.h"
...@@ -491,7 +491,8 @@ void __init at91rm9200_dt_initialize(void) ...@@ -491,7 +491,8 @@ void __init at91rm9200_dt_initialize(void)
at91_dt_clock_init(); at91_dt_clock_init();
/* Register the processor-specific clocks */ /* Register the processor-specific clocks */
at91_boot_soc.register_clocks(); if (at91_boot_soc.register_clocks)
at91_boot_soc.register_clocks();
at91_boot_soc.init(); at91_boot_soc.init();
} }
...@@ -506,7 +507,8 @@ void __init at91_dt_initialize(void) ...@@ -506,7 +507,8 @@ void __init at91_dt_initialize(void)
at91_dt_clock_init(); at91_dt_clock_init();
/* Register the processor-specific clocks */ /* Register the processor-specific clocks */
at91_boot_soc.register_clocks(); if (at91_boot_soc.register_clocks)
at91_boot_soc.register_clocks();
if (at91_boot_soc.init) if (at91_boot_soc.init)
at91_boot_soc.init(); at91_boot_soc.init();
......
...@@ -35,6 +35,7 @@ obj-$(CONFIG_ARCH_TEGRA) += tegra/ ...@@ -35,6 +35,7 @@ obj-$(CONFIG_ARCH_TEGRA) += tegra/
obj-$(CONFIG_PLAT_SAMSUNG) += samsung/ obj-$(CONFIG_PLAT_SAMSUNG) += samsung/
obj-$(CONFIG_COMMON_CLK_XGENE) += clk-xgene.o obj-$(CONFIG_COMMON_CLK_XGENE) += clk-xgene.o
obj-$(CONFIG_COMMON_CLK_KEYSTONE) += keystone/ obj-$(CONFIG_COMMON_CLK_KEYSTONE) += keystone/
obj-$(CONFIG_COMMON_CLK_AT91) += at91/
obj-$(CONFIG_X86) += x86/ obj-$(CONFIG_X86) += x86/
......
#
# Makefile for at91 specific clk
#
obj-y += pmc.o
obj-y += clk-main.o clk-pll.o clk-plldiv.o clk-master.o
obj-y += clk-system.o clk-peripheral.o
obj-$(CONFIG_AT91_PROGRAMMABLE_CLOCKS) += clk-programmable.o
obj-$(CONFIG_HAVE_AT91_UTMI) += clk-utmi.o
obj-$(CONFIG_HAVE_AT91_USB_CLK) += clk-usb.o
obj-$(CONFIG_HAVE_AT91_SMD) += clk-smd.o
/*
* Copyright (C) 2013 Boris BREZILLON <b.brezillon@overkiz.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
*/
#include <linux/clk-provider.h>
#include <linux/clkdev.h>
#include <linux/clk/at91_pmc.h>
#include <linux/delay.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_irq.h>
#include <linux/io.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/sched.h>
#include <linux/wait.h>
#include "pmc.h"
#define SLOW_CLOCK_FREQ 32768
#define MAINF_DIV 16
#define MAINFRDY_TIMEOUT (((MAINF_DIV + 1) * USEC_PER_SEC) / \
SLOW_CLOCK_FREQ)
#define MAINF_LOOP_MIN_WAIT (USEC_PER_SEC / SLOW_CLOCK_FREQ)
#define MAINF_LOOP_MAX_WAIT MAINFRDY_TIMEOUT
struct clk_main {
struct clk_hw hw;
struct at91_pmc *pmc;
unsigned long rate;
unsigned int irq;
wait_queue_head_t wait;
};
#define to_clk_main(hw) container_of(hw, struct clk_main, hw)
static irqreturn_t clk_main_irq_handler(int irq, void *dev_id)
{
struct clk_main *clkmain = (struct clk_main *)dev_id;
wake_up(&clkmain->wait);
disable_irq_nosync(clkmain->irq);
return IRQ_HANDLED;
}
static int clk_main_prepare(struct clk_hw *hw)
{
struct clk_main *clkmain = to_clk_main(hw);
struct at91_pmc *pmc = clkmain->pmc;
unsigned long halt_time, timeout;
u32 tmp;
while (!(pmc_read(pmc, AT91_PMC_SR) & AT91_PMC_MOSCS)) {
enable_irq(clkmain->irq);
wait_event(clkmain->wait,
pmc_read(pmc, AT91_PMC_SR) & AT91_PMC_MOSCS);
}
if (clkmain->rate)
return 0;
timeout = jiffies + usecs_to_jiffies(MAINFRDY_TIMEOUT);
do {
halt_time = jiffies;
tmp = pmc_read(pmc, AT91_CKGR_MCFR);
if (tmp & AT91_PMC_MAINRDY)
return 0;
usleep_range(MAINF_LOOP_MIN_WAIT, MAINF_LOOP_MAX_WAIT);
} while (time_before(halt_time, timeout));
return 0;
}
static int clk_main_is_prepared(struct clk_hw *hw)
{
struct clk_main *clkmain = to_clk_main(hw);
return !!(pmc_read(clkmain->pmc, AT91_PMC_SR) & AT91_PMC_MOSCS);
}
static unsigned long clk_main_recalc_rate(struct clk_hw *hw,
unsigned long parent_rate)
{
u32 tmp;
struct clk_main *clkmain = to_clk_main(hw);
struct at91_pmc *pmc = clkmain->pmc;
if (clkmain->rate)
return clkmain->rate;
tmp = pmc_read(pmc, AT91_CKGR_MCFR) & AT91_PMC_MAINF;
clkmain->rate = (tmp * parent_rate) / MAINF_DIV;
return clkmain->rate;
}
static const struct clk_ops main_ops = {
.prepare = clk_main_prepare,
.is_prepared = clk_main_is_prepared,
.recalc_rate = clk_main_recalc_rate,
};
static struct clk * __init
at91_clk_register_main(struct at91_pmc *pmc,
unsigned int irq,
const char *name,
const char *parent_name,
unsigned long rate)
{
int ret;
struct clk_main *clkmain;
struct clk *clk = NULL;
struct clk_init_data init;
if (!pmc || !irq || !name)
return ERR_PTR(-EINVAL);
if (!rate && !parent_name)
return ERR_PTR(-EINVAL);
clkmain = kzalloc(sizeof(*clkmain), GFP_KERNEL);
if (!clkmain)
return ERR_PTR(-ENOMEM);
init.name = name;
init.ops = &main_ops;
init.parent_names = parent_name ? &parent_name : NULL;
init.num_parents = parent_name ? 1 : 0;
init.flags = parent_name ? 0 : CLK_IS_ROOT;
clkmain->hw.init = &init;
clkmain->rate = rate;
clkmain->pmc = pmc;
clkmain->irq = irq;
init_waitqueue_head(&clkmain->wait);
irq_set_status_flags(clkmain->irq, IRQ_NOAUTOEN);
ret = request_irq(clkmain->irq, clk_main_irq_handler,
IRQF_TRIGGER_HIGH, "clk-main", clkmain);
if (ret)
return ERR_PTR(ret);
clk = clk_register(NULL, &clkmain->hw);
if (IS_ERR(clk)) {
free_irq(clkmain->irq, clkmain);
kfree(clkmain);
}
return clk;
}
static void __init
of_at91_clk_main_setup(struct device_node *np, struct at91_pmc *pmc)
{
struct clk *clk;
unsigned int irq;
const char *parent_name;
const char *name = np->name;
u32 rate = 0;
parent_name = of_clk_get_parent_name(np, 0);
of_property_read_string(np, "clock-output-names", &name);
of_property_read_u32(np, "clock-frequency", &rate);
irq = irq_of_parse_and_map(np, 0);
if (!irq)
return;
clk = at91_clk_register_main(pmc, irq, name, parent_name, rate);
if (IS_ERR(clk))
return;
of_clk_add_provider(np, of_clk_src_simple_get, clk);
}
void __init of_at91rm9200_clk_main_setup(struct device_node *np,
struct at91_pmc *pmc)
{
of_at91_clk_main_setup(np, pmc);
}
/*
* Copyright (C) 2013 Boris BREZILLON <b.brezillon@overkiz.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
*/
#include <linux/clk-provider.h>
#include <linux/clkdev.h>
#include <linux/clk/at91_pmc.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_irq.h>
#include <linux/io.h>
#include <linux/wait.h>
#include <linux/sched.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include "pmc.h"
#define MASTER_SOURCE_MAX 4
#define MASTER_PRES_MASK 0x7
#define MASTER_PRES_MAX MASTER_PRES_MASK
#define MASTER_DIV_SHIFT 8
#define MASTER_DIV_MASK 0x3
struct clk_master_characteristics {
struct clk_range output;
u32 divisors[4];
u8 have_div3_pres;
};
struct clk_master_layout {
u32 mask;
u8 pres_shift;
};
#define to_clk_master(hw) container_of(hw, struct clk_master, hw)
struct clk_master {
struct clk_hw hw;
struct at91_pmc *pmc;
unsigned int irq;
wait_queue_head_t wait;
const struct clk_master_layout *layout;
const struct clk_master_characteristics *characteristics;
};
static irqreturn_t clk_master_irq_handler(int irq, void *dev_id)
{
struct clk_master *master = (struct clk_master *)dev_id;
wake_up(&master->wait);
disable_irq_nosync(master->irq);
return IRQ_HANDLED;
}
static int clk_master_prepare(struct clk_hw *hw)
{
struct clk_master *master = to_clk_master(hw);
struct at91_pmc *pmc = master->pmc;
while (!(pmc_read(pmc, AT91_PMC_SR) & AT91_PMC_MCKRDY)) {
enable_irq(master->irq);
wait_event(master->wait,
pmc_read(pmc, AT91_PMC_SR) & AT91_PMC_MCKRDY);
}
return 0;
}
static int clk_master_is_prepared(struct clk_hw *hw)
{
struct clk_master *master = to_clk_master(hw);
return !!(pmc_read(master->pmc, AT91_PMC_SR) & AT91_PMC_MCKRDY);
}
static unsigned long clk_master_recalc_rate(struct clk_hw *hw,
unsigned long parent_rate)
{
u8 pres;
u8 div;
unsigned long rate = parent_rate;
struct clk_master *master = to_clk_master(hw);
struct at91_pmc *pmc = master->pmc;
const struct clk_master_layout *layout = master->layout;
const struct clk_master_characteristics *characteristics =
master->characteristics;
u32 tmp;
pmc_lock(pmc);
tmp = pmc_read(pmc, AT91_PMC_MCKR) & layout->mask;
pmc_unlock(pmc);
pres = (tmp >> layout->pres_shift) & MASTER_PRES_MASK;
div = (tmp >> 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");
else if (rate > characteristics->output.max)
pr_warn("master clk is overclocked");
return rate;
}
static u8 clk_master_get_parent(struct clk_hw *hw)
{
struct clk_master *master = to_clk_master(hw);
struct at91_pmc *pmc = master->pmc;
return pmc_read(pmc, AT91_PMC_MCKR) & AT91_PMC_CSS;
}
static const struct clk_ops master_ops = {
.prepare = clk_master_prepare,
.is_prepared = clk_master_is_prepared,
.recalc_rate = clk_master_recalc_rate,
.get_parent = clk_master_get_parent,
};
static struct clk * __init
at91_clk_register_master(struct at91_pmc *pmc, unsigned int irq,
const char *name, int num_parents,
const char **parent_names,
const struct clk_master_layout *layout,
const struct clk_master_characteristics *characteristics)
{
int ret;
struct clk_master *master;
struct clk *clk = NULL;
struct clk_init_data init;
if (!pmc || !irq || !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->pmc = pmc;
master->irq = irq;
init_waitqueue_head(&master->wait);
irq_set_status_flags(master->irq, IRQ_NOAUTOEN);
ret = request_irq(master->irq, clk_master_irq_handler,
IRQF_TRIGGER_HIGH, "clk-master", master);
if (ret)
return ERR_PTR(ret);
clk = clk_register(NULL, &master->hw);
if (IS_ERR(clk))
kfree(master);
return clk;
}
static const struct clk_master_layout at91rm9200_master_layout = {
.mask = 0x31F,
.pres_shift = 2,
};
static const struct clk_master_layout at91sam9x5_master_layout = {
.mask = 0x373,
.pres_shift = 4,
};
static struct clk_master_characteristics * __init
of_at91_clk_master_get_characteristics(struct device_node *np)
{
struct clk_master_characteristics *characteristics;
characteristics = kzalloc(sizeof(*characteristics), GFP_KERNEL);
if (!characteristics)
return NULL;
if (of_at91_get_clk_range(np, "atmel,clk-output-range", &characteristics->output))
goto out_free_characteristics;
of_property_read_u32_array(np, "atmel,clk-divisors",
characteristics->divisors, 4);
characteristics->have_div3_pres =
of_property_read_bool(np, "atmel,master-clk-have-div3-pres");
return characteristics;
out_free_characteristics:
kfree(characteristics);
return NULL;
}
static void __init
of_at91_clk_master_setup(struct device_node *np, struct at91_pmc *pmc,
const struct clk_master_layout *layout)
{
struct clk *clk;
int num_parents;
int i;
unsigned int irq;
const char *parent_names[MASTER_SOURCE_MAX];
const char *name = np->name;
struct clk_master_characteristics *characteristics;
num_parents = of_count_phandle_with_args(np, "clocks", "#clock-cells");
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_property_read_string(np, "clock-output-names", &name);
characteristics = of_at91_clk_master_get_characteristics(np);
if (!characteristics)
return;
irq = irq_of_parse_and_map(np, 0);
if (!irq)
return;
clk = at91_clk_register_master(pmc, irq, name, num_parents,
parent_names, layout,
characteristics);
if (IS_ERR(clk))
goto out_free_characteristics;
of_clk_add_provider(np, of_clk_src_simple_get, clk);
return;
out_free_characteristics:
kfree(characteristics);
}
void __init of_at91rm9200_clk_master_setup(struct device_node *np,
struct at91_pmc *pmc)
{
of_at91_clk_master_setup(np, pmc, &at91rm9200_master_layout);
}
void __init of_at91sam9x5_clk_master_setup(struct device_node *np,
struct at91_pmc *pmc)
{
of_at91_clk_master_setup(np, pmc, &at91sam9x5_master_layout);
}
/*
* Copyright (C) 2013 Boris BREZILLON <b.brezillon@overkiz.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
*/
#include <linux/clk-provider.h>
#include <linux/clkdev.h>
#include <linux/clk/at91_pmc.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/io.h>
#include "pmc.h"
#define PERIPHERAL_MAX 64
#define PERIPHERAL_AT91RM9200 0
#define PERIPHERAL_AT91SAM9X5 1
#define PERIPHERAL_ID_MIN 2
#define PERIPHERAL_ID_MAX 31
#define PERIPHERAL_MASK(id) (1 << ((id) & PERIPHERAL_ID_MAX))
#define PERIPHERAL_RSHIFT_MASK 0x3
#define PERIPHERAL_RSHIFT(val) (((val) >> 16) & PERIPHERAL_RSHIFT_MASK)
#define PERIPHERAL_MAX_SHIFT 4
struct clk_peripheral {
struct clk_hw hw;
struct at91_pmc *pmc;
u32 id;
};
#define to_clk_peripheral(hw) container_of(hw, struct clk_peripheral, hw)
struct clk_sam9x5_peripheral {
struct clk_hw hw;
struct at91_pmc *pmc;
struct clk_range range;
u32 id;
u32 div;
bool auto_div;
};
#define to_clk_sam9x5_peripheral(hw) \
container_of(hw, struct clk_sam9x5_peripheral, hw)
static int clk_peripheral_enable(struct clk_hw *hw)
{
struct clk_peripheral *periph = to_clk_peripheral(hw);
struct at91_pmc *pmc = periph->pmc;
int offset = AT91_PMC_PCER;
u32 id = periph->id;
if (id < PERIPHERAL_ID_MIN)
return 0;
if (id > PERIPHERAL_ID_MAX)
offset = AT91_PMC_PCER1;
pmc_write(pmc, offset, PERIPHERAL_MASK(id));
return 0;
}
static void clk_peripheral_disable(struct clk_hw *hw)
{
struct clk_peripheral *periph = to_clk_peripheral(hw);
struct at91_pmc *pmc = periph->pmc;
int offset = AT91_PMC_PCDR;
u32 id = periph->id;
if (id < PERIPHERAL_ID_MIN)
return;
if (id > PERIPHERAL_ID_MAX)
offset = AT91_PMC_PCDR1;
pmc_write(pmc, offset, PERIPHERAL_MASK(id));
}
static int clk_peripheral_is_enabled(struct clk_hw *hw)
{
struct clk_peripheral *periph = to_clk_peripheral(hw);
struct at91_pmc *pmc = periph->pmc;
int offset = AT91_PMC_PCSR;
u32 id = periph->id;
if (id < PERIPHERAL_ID_MIN)
return 1;
if (id > PERIPHERAL_ID_MAX)
offset = AT91_PMC_PCSR1;
return !!(pmc_read(pmc, offset) & PERIPHERAL_MASK(id));
}
static const struct clk_ops peripheral_ops = {
.enable = clk_peripheral_enable,
.disable = clk_peripheral_disable,
.is_enabled = clk_peripheral_is_enabled,
};
static struct clk * __init
at91_clk_register_peripheral(struct at91_pmc *pmc, const char *name,
const char *parent_name, u32 id)
{
struct clk_peripheral *periph;
struct clk *clk = NULL;
struct clk_init_data init;
if (!pmc || !name || !parent_name || id > PERIPHERAL_ID_MAX)
return ERR_PTR(-EINVAL);
periph = kzalloc(sizeof(*periph), GFP_KERNEL);
if (!periph)
return ERR_PTR(-ENOMEM);
init.name = name;
init.ops = &peripheral_ops;
init.parent_names = (parent_name ? &parent_name : NULL);
init.num_parents = (parent_name ? 1 : 0);
init.flags = 0;
periph->id = id;
periph->hw.init = &init;
periph->pmc = pmc;
clk = clk_register(NULL, &periph->hw);
if (IS_ERR(clk))
kfree(periph);
return clk;
}
static void clk_sam9x5_peripheral_autodiv(struct clk_sam9x5_peripheral *periph)
{
struct clk *parent;
unsigned long parent_rate;
int shift = 0;
if (!periph->auto_div)
return;
if (periph->range.max) {
parent = clk_get_parent_by_index(periph->hw.clk, 0);
parent_rate = __clk_get_rate(parent);
if (!parent_rate)
return;
for (; shift < PERIPHERAL_MAX_SHIFT; shift++) {
if (parent_rate >> shift <= periph->range.max)
break;
}
}
periph->auto_div = false;
periph->div = shift;
}
static int clk_sam9x5_peripheral_enable(struct clk_hw *hw)
{
struct clk_sam9x5_peripheral *periph = to_clk_sam9x5_peripheral(hw);
struct at91_pmc *pmc = periph->pmc;
if (periph->id < PERIPHERAL_ID_MIN)
return 0;
pmc_write(pmc, AT91_PMC_PCR, (periph->id & AT91_PMC_PCR_PID) |
AT91_PMC_PCR_CMD |
AT91_PMC_PCR_DIV(periph->div) |
AT91_PMC_PCR_EN);
return 0;
}
static void clk_sam9x5_peripheral_disable(struct clk_hw *hw)
{
struct clk_sam9x5_peripheral *periph = to_clk_sam9x5_peripheral(hw);
struct at91_pmc *pmc = periph->pmc;
if (periph->id < PERIPHERAL_ID_MIN)
return;
pmc_write(pmc, AT91_PMC_PCR, (periph->id & AT91_PMC_PCR_PID) |
AT91_PMC_PCR_CMD);
}
static int clk_sam9x5_peripheral_is_enabled(struct clk_hw *hw)
{
struct clk_sam9x5_peripheral *periph = to_clk_sam9x5_peripheral(hw);
struct at91_pmc *pmc = periph->pmc;
int ret;
if (periph->id < PERIPHERAL_ID_MIN)
return 1;
pmc_lock(pmc);
pmc_write(pmc, AT91_PMC_PCR, (periph->id & AT91_PMC_PCR_PID));
ret = !!(pmc_read(pmc, AT91_PMC_PCR) & AT91_PMC_PCR_EN);
pmc_unlock(pmc);
return ret;
}
static unsigned long
clk_sam9x5_peripheral_recalc_rate(struct clk_hw *hw,
unsigned long parent_rate)
{
struct clk_sam9x5_peripheral *periph = to_clk_sam9x5_peripheral(hw);
struct at91_pmc *pmc = periph->pmc;
u32 tmp;
if (periph->id < PERIPHERAL_ID_MIN)
return parent_rate;
pmc_lock(pmc);
pmc_write(pmc, AT91_PMC_PCR, (periph->id & AT91_PMC_PCR_PID));
tmp = pmc_read(pmc, AT91_PMC_PCR);
pmc_unlock(pmc);
if (tmp & AT91_PMC_PCR_EN) {
periph->div = PERIPHERAL_RSHIFT(tmp);
periph->auto_div = false;
} else {
clk_sam9x5_peripheral_autodiv(periph);
}
return parent_rate >> periph->div;
}
static long clk_sam9x5_peripheral_round_rate(struct clk_hw *hw,
unsigned long rate,
unsigned long *parent_rate)
{
int shift = 0;
unsigned long best_rate;
unsigned long best_diff;
unsigned long cur_rate = *parent_rate;
unsigned long cur_diff;
struct clk_sam9x5_peripheral *periph = to_clk_sam9x5_peripheral(hw);
if (periph->id < PERIPHERAL_ID_MIN || !periph->range.max)
return *parent_rate;
if (periph->range.max) {
for (; shift < PERIPHERAL_MAX_SHIFT; shift++) {
cur_rate = *parent_rate >> shift;
if (cur_rate <= periph->range.max)
break;
}
}
if (rate >= cur_rate)
return cur_rate;
best_diff = cur_rate - rate;
best_rate = cur_rate;
for (; shift < PERIPHERAL_MAX_SHIFT; shift++) {
cur_rate = *parent_rate >> shift;
if (cur_rate < rate)
cur_diff = rate - cur_rate;
else
cur_diff = cur_rate - rate;
if (cur_diff < best_diff) {
best_diff = cur_diff;
best_rate = cur_rate;
}
if (!best_diff || cur_rate < rate)
break;
}
return best_rate;
}
static int clk_sam9x5_peripheral_set_rate(struct clk_hw *hw,
unsigned long rate,
unsigned long parent_rate)
{
int shift;
struct clk_sam9x5_peripheral *periph = to_clk_sam9x5_peripheral(hw);
if (periph->id < PERIPHERAL_ID_MIN || !periph->range.max) {
if (parent_rate == rate)
return 0;
else
return -EINVAL;
}
if (periph->range.max && rate > periph->range.max)
return -EINVAL;
for (shift = 0; shift < PERIPHERAL_MAX_SHIFT; shift++) {
if (parent_rate >> shift == rate) {
periph->auto_div = false;
periph->div = shift;
return 0;
}
}
return -EINVAL;
}
static const struct clk_ops sam9x5_peripheral_ops = {
.enable = clk_sam9x5_peripheral_enable,
.disable = clk_sam9x5_peripheral_disable,
.is_enabled = clk_sam9x5_peripheral_is_enabled,
.recalc_rate = clk_sam9x5_peripheral_recalc_rate,
.round_rate = clk_sam9x5_peripheral_round_rate,
.set_rate = clk_sam9x5_peripheral_set_rate,
};
static struct clk * __init
at91_clk_register_sam9x5_peripheral(struct at91_pmc *pmc, const char *name,
const char *parent_name, u32 id,
const struct clk_range *range)
{
struct clk_sam9x5_peripheral *periph;
struct clk *clk = NULL;
struct clk_init_data init;
if (!pmc || !name || !parent_name)
return ERR_PTR(-EINVAL);
periph = kzalloc(sizeof(*periph), GFP_KERNEL);
if (!periph)
return ERR_PTR(-ENOMEM);
init.name = name;
init.ops = &sam9x5_peripheral_ops;
init.parent_names = (parent_name ? &parent_name : NULL);
init.num_parents = (parent_name ? 1 : 0);
init.flags = 0;
periph->id = id;
periph->hw.init = &init;
periph->div = 0;
periph->pmc = pmc;
periph->auto_div = true;
periph->range = *range;
clk = clk_register(NULL, &periph->hw);
if (IS_ERR(clk))
kfree(periph);
else
clk_sam9x5_peripheral_autodiv(periph);
return clk;
}
static void __init
of_at91_clk_periph_setup(struct device_node *np, struct at91_pmc *pmc, u8 type)
{
int num;
u32 id;
struct clk *clk;
const char *parent_name;
const char *name;
struct device_node *periphclknp;
parent_name = of_clk_get_parent_name(np, 0);
if (!parent_name)
return;
num = of_get_child_count(np);
if (!num || num > PERIPHERAL_MAX)
return;
for_each_child_of_node(np, periphclknp) {
if (of_property_read_u32(periphclknp, "reg", &id))
continue;
if (id >= PERIPHERAL_MAX)
continue;
if (of_property_read_string(np, "clock-output-names", &name))
name = periphclknp->name;
if (type == PERIPHERAL_AT91RM9200) {
clk = at91_clk_register_peripheral(pmc, name,
parent_name, id);
} else {
struct clk_range range = CLK_RANGE(0, 0);
of_at91_get_clk_range(periphclknp,
"atmel,clk-output-range",
&range);
clk = at91_clk_register_sam9x5_peripheral(pmc, name,
parent_name,
id, &range);
}
if (IS_ERR(clk))
continue;
of_clk_add_provider(periphclknp, of_clk_src_simple_get, clk);
}
}
void __init of_at91rm9200_clk_periph_setup(struct device_node *np,
struct at91_pmc *pmc)
{
of_at91_clk_periph_setup(np, pmc, PERIPHERAL_AT91RM9200);
}
void __init of_at91sam9x5_clk_periph_setup(struct device_node *np,
struct at91_pmc *pmc)
{
of_at91_clk_periph_setup(np, pmc, PERIPHERAL_AT91SAM9X5);
}
This diff is collapsed.
/*
* Copyright (C) 2013 Boris BREZILLON <b.brezillon@overkiz.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
*/
#include <linux/clk-provider.h>
#include <linux/clkdev.h>
#include <linux/clk/at91_pmc.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/io.h>
#include "pmc.h"
#define to_clk_plldiv(hw) container_of(hw, struct clk_plldiv, hw)
struct clk_plldiv {
struct clk_hw hw;
struct at91_pmc *pmc;
};
static unsigned long clk_plldiv_recalc_rate(struct clk_hw *hw,
unsigned long parent_rate)
{
struct clk_plldiv *plldiv = to_clk_plldiv(hw);
struct at91_pmc *pmc = plldiv->pmc;
if (pmc_read(pmc, AT91_PMC_MCKR) & AT91_PMC_PLLADIV2)
return parent_rate / 2;
return parent_rate;
}
static long clk_plldiv_round_rate(struct clk_hw *hw, unsigned long rate,
unsigned long *parent_rate)
{
unsigned long div;
if (rate > *parent_rate)
return *parent_rate;
div = *parent_rate / 2;
if (rate < div)
return div;
if (rate - div < *parent_rate - rate)
return div;
return *parent_rate;
}
static int clk_plldiv_set_rate(struct clk_hw *hw, unsigned long rate,
unsigned long parent_rate)
{
struct clk_plldiv *plldiv = to_clk_plldiv(hw);
struct at91_pmc *pmc = plldiv->pmc;
u32 tmp;
if (parent_rate != rate && (parent_rate / 2) != rate)
return -EINVAL;
pmc_lock(pmc);
tmp = pmc_read(pmc, AT91_PMC_MCKR) & ~AT91_PMC_PLLADIV2;
if ((parent_rate / 2) == rate)
tmp |= AT91_PMC_PLLADIV2;
pmc_write(pmc, AT91_PMC_MCKR, tmp);
pmc_unlock(pmc);
return 0;
}
static const struct clk_ops plldiv_ops = {
.recalc_rate = clk_plldiv_recalc_rate,
.round_rate = clk_plldiv_round_rate,
.set_rate = clk_plldiv_set_rate,
};
static struct clk * __init
at91_clk_register_plldiv(struct at91_pmc *pmc, const char *name,
const char *parent_name)
{
struct clk_plldiv *plldiv;
struct clk *clk = NULL;
struct clk_init_data init;
plldiv = kzalloc(sizeof(*plldiv), GFP_KERNEL);
if (!plldiv)
return ERR_PTR(-ENOMEM);
init.name = name;
init.ops = &plldiv_ops;
init.parent_names = parent_name ? &parent_name : NULL;
init.num_parents = parent_name ? 1 : 0;
init.flags = CLK_SET_RATE_GATE;
plldiv->hw.init = &init;
plldiv->pmc = pmc;
clk = clk_register(NULL, &plldiv->hw);
if (IS_ERR(clk))
kfree(plldiv);
return clk;
}
static void __init
of_at91_clk_plldiv_setup(struct device_node *np, struct at91_pmc *pmc)
{
struct clk *clk;
const char *parent_name;
const char *name = np->name;
parent_name = of_clk_get_parent_name(np, 0);
of_property_read_string(np, "clock-output-names", &name);
clk = at91_clk_register_plldiv(pmc, name, parent_name);
if (IS_ERR(clk))
return;
of_clk_add_provider(np, of_clk_src_simple_get, clk);
return;
}
void __init of_at91sam9x5_clk_plldiv_setup(struct device_node *np,
struct at91_pmc *pmc)
{
of_at91_clk_plldiv_setup(np, pmc);
}
/*
* Copyright (C) 2013 Boris BREZILLON <b.brezillon@overkiz.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
*/
#include <linux/clk-provider.h>
#include <linux/clkdev.h>
#include <linux/clk/at91_pmc.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_irq.h>
#include <linux/io.h>
#include <linux/wait.h>
#include <linux/sched.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include "pmc.h"
#define PROG_SOURCE_MAX 5
#define PROG_ID_MAX 7
#define PROG_STATUS_MASK(id) (1 << ((id) + 8))
#define PROG_PRES_MASK 0x7
#define PROG_MAX_RM9200_CSS 3
struct clk_programmable_layout {
u8 pres_shift;
u8 css_mask;
u8 have_slck_mck;
};
struct clk_programmable {
struct clk_hw hw;
struct at91_pmc *pmc;
unsigned int irq;
wait_queue_head_t wait;
u8 id;
u8 css;
u8 pres;
u8 slckmck;
const struct clk_programmable_layout *layout;
};
#define to_clk_programmable(hw) container_of(hw, struct clk_programmable, hw)
static irqreturn_t clk_programmable_irq_handler(int irq, void *dev_id)
{
struct clk_programmable *prog = (struct clk_programmable *)dev_id;
wake_up(&prog->wait);
return IRQ_HANDLED;
}
static int clk_programmable_prepare(struct clk_hw *hw)
{
u32 tmp;
struct clk_programmable *prog = to_clk_programmable(hw);
struct at91_pmc *pmc = prog->pmc;
const struct clk_programmable_layout *layout = prog->layout;
u8 id = prog->id;
u32 mask = PROG_STATUS_MASK(id);
tmp = prog->css | (prog->pres << layout->pres_shift);
if (layout->have_slck_mck && prog->slckmck)
tmp |= AT91_PMC_CSSMCK_MCK;
pmc_write(pmc, AT91_PMC_PCKR(id), tmp);
while (!(pmc_read(pmc, AT91_PMC_SR) & mask))
wait_event(prog->wait, pmc_read(pmc, AT91_PMC_SR) & mask);
return 0;
}
static int clk_programmable_is_ready(struct clk_hw *hw)
{
struct clk_programmable *prog = to_clk_programmable(hw);
struct at91_pmc *pmc = prog->pmc;
return !!(pmc_read(pmc, AT91_PMC_SR) & AT91_PMC_PCKR(prog->id));
}
static unsigned long clk_programmable_recalc_rate(struct clk_hw *hw,
unsigned long parent_rate)
{
u32 tmp;
struct clk_programmable *prog = to_clk_programmable(hw);
struct at91_pmc *pmc = prog->pmc;
const struct clk_programmable_layout *layout = prog->layout;
tmp = pmc_read(pmc, AT91_PMC_PCKR(prog->id));
prog->pres = (tmp >> layout->pres_shift) & PROG_PRES_MASK;
return parent_rate >> prog->pres;
}
static long clk_programmable_round_rate(struct clk_hw *hw, unsigned long rate,
unsigned long *parent_rate)
{
unsigned long best_rate = *parent_rate;
unsigned long best_diff;
unsigned long new_diff;
unsigned long cur_rate;
int shift = shift;
if (rate > *parent_rate)
return *parent_rate;
else
best_diff = *parent_rate - rate;
if (!best_diff)
return best_rate;
for (shift = 1; shift < PROG_PRES_MASK; shift++) {
cur_rate = *parent_rate >> shift;
if (cur_rate > rate)
new_diff = cur_rate - rate;
else
new_diff = rate - cur_rate;
if (!new_diff)
return cur_rate;
if (new_diff < best_diff) {
best_diff = new_diff;
best_rate = cur_rate;
}
if (rate > cur_rate)
break;
}
return best_rate;
}
static int clk_programmable_set_parent(struct clk_hw *hw, u8 index)
{
struct clk_programmable *prog = to_clk_programmable(hw);
const struct clk_programmable_layout *layout = prog->layout;
if (index > layout->css_mask) {
if (index > PROG_MAX_RM9200_CSS && layout->have_slck_mck) {
prog->css = 0;
prog->slckmck = 1;
return 0;
} else {
return -EINVAL;
}
}
prog->css = index;
return 0;
}
static u8 clk_programmable_get_parent(struct clk_hw *hw)
{
u32 tmp;
u8 ret;
struct clk_programmable *prog = to_clk_programmable(hw);
struct at91_pmc *pmc = prog->pmc;
const struct clk_programmable_layout *layout = prog->layout;
tmp = pmc_read(pmc, AT91_PMC_PCKR(prog->id));
prog->css = tmp & layout->css_mask;
ret = prog->css;
if (layout->have_slck_mck) {
prog->slckmck = !!(tmp & AT91_PMC_CSSMCK_MCK);
if (prog->slckmck && !ret)
ret = PROG_MAX_RM9200_CSS + 1;
}
return ret;
}
static int clk_programmable_set_rate(struct clk_hw *hw, unsigned long rate,
unsigned long parent_rate)
{
struct clk_programmable *prog = to_clk_programmable(hw);
unsigned long best_rate = parent_rate;
unsigned long best_diff;
unsigned long new_diff;
unsigned long cur_rate;
int shift = 0;
if (rate > parent_rate)
return parent_rate;
else
best_diff = parent_rate - rate;
if (!best_diff) {
prog->pres = shift;
return 0;
}
for (shift = 1; shift < PROG_PRES_MASK; shift++) {
cur_rate = parent_rate >> shift;
if (cur_rate > rate)
new_diff = cur_rate - rate;
else
new_diff = rate - cur_rate;
if (!new_diff)
break;
if (new_diff < best_diff) {
best_diff = new_diff;
best_rate = cur_rate;
}
if (rate > cur_rate)
break;
}
prog->pres = shift;
return 0;
}
static const struct clk_ops programmable_ops = {
.prepare = clk_programmable_prepare,
.is_prepared = clk_programmable_is_ready,
.recalc_rate = clk_programmable_recalc_rate,
.round_rate = clk_programmable_round_rate,
.get_parent = clk_programmable_get_parent,
.set_parent = clk_programmable_set_parent,
.set_rate = clk_programmable_set_rate,
};
static struct clk * __init
at91_clk_register_programmable(struct at91_pmc *pmc, unsigned int irq,
const char *name, const char **parent_names,
u8 num_parents, u8 id,
const struct clk_programmable_layout *layout)
{
int ret;
struct clk_programmable *prog;
struct clk *clk = NULL;
struct clk_init_data init;
char irq_name[11];
if (id > PROG_ID_MAX)
return ERR_PTR(-EINVAL);
prog = kzalloc(sizeof(*prog), GFP_KERNEL);
if (!prog)
return ERR_PTR(-ENOMEM);
init.name = name;
init.ops = &programmable_ops;
init.parent_names = parent_names;
init.num_parents = num_parents;
init.flags = CLK_SET_RATE_GATE | CLK_SET_PARENT_GATE;
prog->id = id;
prog->layout = layout;
prog->hw.init = &init;
prog->pmc = pmc;
prog->irq = irq;
init_waitqueue_head(&prog->wait);
irq_set_status_flags(prog->irq, IRQ_NOAUTOEN);
snprintf(irq_name, sizeof(irq_name), "clk-prog%d", id);
ret = request_irq(prog->irq, clk_programmable_irq_handler,
IRQF_TRIGGER_HIGH, irq_name, prog);
if (ret)
return ERR_PTR(ret);
clk = clk_register(NULL, &prog->hw);
if (IS_ERR(clk))
kfree(prog);
return clk;
}
static const struct clk_programmable_layout at91rm9200_programmable_layout = {
.pres_shift = 2,
.css_mask = 0x3,
.have_slck_mck = 0,
};
static const struct clk_programmable_layout at91sam9g45_programmable_layout = {
.pres_shift = 2,
.css_mask = 0x3,
.have_slck_mck = 1,
};
static const struct clk_programmable_layout at91sam9x5_programmable_layout = {
.pres_shift = 4,
.css_mask = 0x7,
.have_slck_mck = 0,
};
static void __init
of_at91_clk_prog_setup(struct device_node *np, struct at91_pmc *pmc,
const struct clk_programmable_layout *layout)
{
int num;
u32 id;
int i;
unsigned int irq;
struct clk *clk;
int num_parents;
const char *parent_names[PROG_SOURCE_MAX];
const char *name;
struct device_node *progclknp;
num_parents = of_count_phandle_with_args(np, "clocks", "#clock-cells");
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;
}
num = of_get_child_count(np);
if (!num || num > (PROG_ID_MAX + 1))
return;
for_each_child_of_node(np, progclknp) {
if (of_property_read_u32(progclknp, "reg", &id))
continue;
if (of_property_read_string(np, "clock-output-names", &name))
name = progclknp->name;
irq = irq_of_parse_and_map(progclknp, 0);
if (!irq)
continue;
clk = at91_clk_register_programmable(pmc, irq, name,
parent_names, num_parents,
id, layout);
if (IS_ERR(clk))
continue;
of_clk_add_provider(progclknp, of_clk_src_simple_get, clk);
}
}
void __init of_at91rm9200_clk_prog_setup(struct device_node *np,
struct at91_pmc *pmc)
{
of_at91_clk_prog_setup(np, pmc, &at91rm9200_programmable_layout);
}
void __init of_at91sam9g45_clk_prog_setup(struct device_node *np,
struct at91_pmc *pmc)
{
of_at91_clk_prog_setup(np, pmc, &at91sam9g45_programmable_layout);
}
void __init of_at91sam9x5_clk_prog_setup(struct device_node *np,
struct at91_pmc *pmc)
{
of_at91_clk_prog_setup(np, pmc, &at91sam9x5_programmable_layout);
}
/*
* Copyright (C) 2013 Boris BREZILLON <b.brezillon@overkiz.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
*/
#include <linux/clk-provider.h>
#include <linux/clkdev.h>
#include <linux/clk/at91_pmc.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/io.h>
#include "pmc.h"
#define SMD_SOURCE_MAX 2
#define SMD_DIV_SHIFT 8
#define SMD_MAX_DIV 0xf
struct at91sam9x5_clk_smd {
struct clk_hw hw;
struct at91_pmc *pmc;
};
#define to_at91sam9x5_clk_smd(hw) \
container_of(hw, struct at91sam9x5_clk_smd, hw)
static unsigned long at91sam9x5_clk_smd_recalc_rate(struct clk_hw *hw,
unsigned long parent_rate)
{
u32 tmp;
u8 smddiv;
struct at91sam9x5_clk_smd *smd = to_at91sam9x5_clk_smd(hw);
struct at91_pmc *pmc = smd->pmc;
tmp = pmc_read(pmc, AT91_PMC_SMD);
smddiv = (tmp & AT91_PMC_SMD_DIV) >> SMD_DIV_SHIFT;
return parent_rate / (smddiv + 1);
}
static long at91sam9x5_clk_smd_round_rate(struct clk_hw *hw, unsigned long rate,
unsigned long *parent_rate)
{
unsigned long div;
unsigned long bestrate;
unsigned long tmp;
if (rate >= *parent_rate)
return *parent_rate;
div = *parent_rate / rate;
if (div > SMD_MAX_DIV)
return *parent_rate / (SMD_MAX_DIV + 1);
bestrate = *parent_rate / div;
tmp = *parent_rate / (div + 1);
if (bestrate - rate > rate - tmp)
bestrate = tmp;
return bestrate;
}
static int at91sam9x5_clk_smd_set_parent(struct clk_hw *hw, u8 index)
{
u32 tmp;
struct at91sam9x5_clk_smd *smd = to_at91sam9x5_clk_smd(hw);
struct at91_pmc *pmc = smd->pmc;
if (index > 1)
return -EINVAL;
tmp = pmc_read(pmc, AT91_PMC_SMD) & ~AT91_PMC_SMDS;
if (index)
tmp |= AT91_PMC_SMDS;
pmc_write(pmc, AT91_PMC_SMD, tmp);
return 0;
}
static u8 at91sam9x5_clk_smd_get_parent(struct clk_hw *hw)
{
struct at91sam9x5_clk_smd *smd = to_at91sam9x5_clk_smd(hw);
struct at91_pmc *pmc = smd->pmc;
return pmc_read(pmc, AT91_PMC_SMD) & AT91_PMC_SMDS;
}
static int at91sam9x5_clk_smd_set_rate(struct clk_hw *hw, unsigned long rate,
unsigned long parent_rate)
{
u32 tmp;
struct at91sam9x5_clk_smd *smd = to_at91sam9x5_clk_smd(hw);
struct at91_pmc *pmc = smd->pmc;
unsigned long div = parent_rate / rate;
if (parent_rate % rate || div < 1 || div > (SMD_MAX_DIV + 1))
return -EINVAL;
tmp = pmc_read(pmc, AT91_PMC_SMD) & ~AT91_PMC_SMD_DIV;
tmp |= (div - 1) << SMD_DIV_SHIFT;
pmc_write(pmc, AT91_PMC_SMD, tmp);
return 0;
}
static const struct clk_ops at91sam9x5_smd_ops = {
.recalc_rate = at91sam9x5_clk_smd_recalc_rate,
.round_rate = at91sam9x5_clk_smd_round_rate,
.get_parent = at91sam9x5_clk_smd_get_parent,
.set_parent = at91sam9x5_clk_smd_set_parent,
.set_rate = at91sam9x5_clk_smd_set_rate,
};
static struct clk * __init
at91sam9x5_clk_register_smd(struct at91_pmc *pmc, const char *name,
const char **parent_names, u8 num_parents)
{
struct at91sam9x5_clk_smd *smd;
struct clk *clk = NULL;
struct clk_init_data init;
smd = kzalloc(sizeof(*smd), GFP_KERNEL);
if (!smd)
return ERR_PTR(-ENOMEM);
init.name = name;
init.ops = &at91sam9x5_smd_ops;
init.parent_names = parent_names;
init.num_parents = num_parents;
init.flags = CLK_SET_RATE_GATE | CLK_SET_PARENT_GATE;
smd->hw.init = &init;
smd->pmc = pmc;
clk = clk_register(NULL, &smd->hw);
if (IS_ERR(clk))
kfree(smd);
return clk;
}
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;
num_parents = of_count_phandle_with_args(np, "clocks", "#clock-cells");
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_property_read_string(np, "clock-output-names", &name);
clk = at91sam9x5_clk_register_smd(pmc, name, parent_names,
num_parents);
if (IS_ERR(clk))
return;
of_clk_add_provider(np, of_clk_src_simple_get, clk);
}
/*
* Copyright (C) 2013 Boris BREZILLON <b.brezillon@overkiz.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
*/
#include <linux/clk-provider.h>
#include <linux/clkdev.h>
#include <linux/clk/at91_pmc.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/io.h>
#include "pmc.h"
#define SYSTEM_MAX_ID 31
#define SYSTEM_MAX_NAME_SZ 32
#define to_clk_system(hw) container_of(hw, struct clk_system, hw)
struct clk_system {
struct clk_hw hw;
struct at91_pmc *pmc;
u8 id;
};
static int clk_system_enable(struct clk_hw *hw)
{
struct clk_system *sys = to_clk_system(hw);
struct at91_pmc *pmc = sys->pmc;
pmc_write(pmc, AT91_PMC_SCER, 1 << sys->id);
return 0;
}
static void clk_system_disable(struct clk_hw *hw)
{
struct clk_system *sys = to_clk_system(hw);
struct at91_pmc *pmc = sys->pmc;
pmc_write(pmc, AT91_PMC_SCDR, 1 << sys->id);
}
static int clk_system_is_enabled(struct clk_hw *hw)
{
struct clk_system *sys = to_clk_system(hw);
struct at91_pmc *pmc = sys->pmc;
return !!(pmc_read(pmc, AT91_PMC_SCSR) & (1 << sys->id));
}
static const struct clk_ops system_ops = {
.enable = clk_system_enable,
.disable = clk_system_disable,
.is_enabled = clk_system_is_enabled,
};
static struct clk * __init
at91_clk_register_system(struct at91_pmc *pmc, const char *name,
const char *parent_name, u8 id)
{
struct clk_system *sys;
struct clk *clk = NULL;
struct clk_init_data init;
if (!parent_name || id > SYSTEM_MAX_ID)
return ERR_PTR(-EINVAL);
sys = kzalloc(sizeof(*sys), GFP_KERNEL);
if (!sys)
return ERR_PTR(-ENOMEM);
init.name = name;
init.ops = &system_ops;
init.parent_names = &parent_name;
init.num_parents = 1;
/*
* CLK_IGNORE_UNUSED is used to avoid ddrck switch off.
* TODO : we should implement a driver supporting at91 ddr controller
* (see drivers/memory) which would request and enable the ddrck clock.
* When this is done we will be able to remove CLK_IGNORE_UNUSED flag.
*/
init.flags = CLK_IGNORE_UNUSED;
sys->id = id;
sys->hw.init = &init;
sys->pmc = pmc;
clk = clk_register(NULL, &sys->hw);
if (IS_ERR(clk))
kfree(sys);
return clk;
}
static void __init
of_at91_clk_sys_setup(struct device_node *np, struct at91_pmc *pmc)
{
int num;
u32 id;
struct clk *clk;
const char *name;
struct device_node *sysclknp;
const char *parent_name;
num = of_get_child_count(np);
if (num > (SYSTEM_MAX_ID + 1))
return;
for_each_child_of_node(np, sysclknp) {
if (of_property_read_u32(sysclknp, "reg", &id))
continue;
if (of_property_read_string(np, "clock-output-names", &name))
name = sysclknp->name;
parent_name = of_clk_get_parent_name(sysclknp, 0);
clk = at91_clk_register_system(pmc, name, parent_name, id);
if (IS_ERR(clk))
continue;
of_clk_add_provider(sysclknp, of_clk_src_simple_get, clk);
}
}
void __init of_at91rm9200_clk_sys_setup(struct device_node *np,
struct at91_pmc *pmc)
{
of_at91_clk_sys_setup(np, pmc);
}
/*
* Copyright (C) 2013 Boris BREZILLON <b.brezillon@overkiz.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
*/
#include <linux/clk-provider.h>
#include <linux/clkdev.h>
#include <linux/clk/at91_pmc.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/io.h>
#include "pmc.h"
#define USB_SOURCE_MAX 2
#define SAM9X5_USB_DIV_SHIFT 8
#define SAM9X5_USB_MAX_DIV 0xf
#define RM9200_USB_DIV_SHIFT 28
#define RM9200_USB_DIV_TAB_SIZE 4
struct at91sam9x5_clk_usb {
struct clk_hw hw;
struct at91_pmc *pmc;
};
#define to_at91sam9x5_clk_usb(hw) \
container_of(hw, struct at91sam9x5_clk_usb, hw)
struct at91rm9200_clk_usb {
struct clk_hw hw;
struct at91_pmc *pmc;
u32 divisors[4];
};
#define to_at91rm9200_clk_usb(hw) \
container_of(hw, struct at91rm9200_clk_usb, hw)
static unsigned long at91sam9x5_clk_usb_recalc_rate(struct clk_hw *hw,
unsigned long parent_rate)
{
u32 tmp;
u8 usbdiv;
struct at91sam9x5_clk_usb *usb = to_at91sam9x5_clk_usb(hw);
struct at91_pmc *pmc = usb->pmc;
tmp = pmc_read(pmc, AT91_PMC_USB);
usbdiv = (tmp & AT91_PMC_OHCIUSBDIV) >> SAM9X5_USB_DIV_SHIFT;
return parent_rate / (usbdiv + 1);
}
static long at91sam9x5_clk_usb_round_rate(struct clk_hw *hw, unsigned long rate,
unsigned long *parent_rate)
{
unsigned long div;
unsigned long bestrate;
unsigned long tmp;
if (rate >= *parent_rate)
return *parent_rate;
div = *parent_rate / rate;
if (div >= SAM9X5_USB_MAX_DIV)
return *parent_rate / (SAM9X5_USB_MAX_DIV + 1);
bestrate = *parent_rate / div;
tmp = *parent_rate / (div + 1);
if (bestrate - rate > rate - tmp)
bestrate = tmp;
return bestrate;
}
static int at91sam9x5_clk_usb_set_parent(struct clk_hw *hw, u8 index)
{
u32 tmp;
struct at91sam9x5_clk_usb *usb = to_at91sam9x5_clk_usb(hw);
struct at91_pmc *pmc = usb->pmc;
if (index > 1)
return -EINVAL;
tmp = pmc_read(pmc, AT91_PMC_USB) & ~AT91_PMC_USBS;
if (index)
tmp |= AT91_PMC_USBS;
pmc_write(pmc, AT91_PMC_USB, tmp);
return 0;
}
static u8 at91sam9x5_clk_usb_get_parent(struct clk_hw *hw)
{
struct at91sam9x5_clk_usb *usb = to_at91sam9x5_clk_usb(hw);
struct at91_pmc *pmc = usb->pmc;
return pmc_read(pmc, AT91_PMC_USB) & AT91_PMC_USBS;
}
static int at91sam9x5_clk_usb_set_rate(struct clk_hw *hw, unsigned long rate,
unsigned long parent_rate)
{
u32 tmp;
struct at91sam9x5_clk_usb *usb = to_at91sam9x5_clk_usb(hw);
struct at91_pmc *pmc = usb->pmc;
unsigned long div = parent_rate / rate;
if (parent_rate % rate || div < 1 || div >= SAM9X5_USB_MAX_DIV)
return -EINVAL;
tmp = pmc_read(pmc, AT91_PMC_USB) & ~AT91_PMC_OHCIUSBDIV;
tmp |= (div - 1) << SAM9X5_USB_DIV_SHIFT;
pmc_write(pmc, AT91_PMC_USB, tmp);
return 0;
}
static const struct clk_ops at91sam9x5_usb_ops = {
.recalc_rate = at91sam9x5_clk_usb_recalc_rate,
.round_rate = at91sam9x5_clk_usb_round_rate,
.get_parent = at91sam9x5_clk_usb_get_parent,
.set_parent = at91sam9x5_clk_usb_set_parent,
.set_rate = at91sam9x5_clk_usb_set_rate,
};
static int at91sam9n12_clk_usb_enable(struct clk_hw *hw)
{
struct at91sam9x5_clk_usb *usb = to_at91sam9x5_clk_usb(hw);
struct at91_pmc *pmc = usb->pmc;
pmc_write(pmc, AT91_PMC_USB,
pmc_read(pmc, AT91_PMC_USB) | AT91_PMC_USBS);
return 0;
}
static void at91sam9n12_clk_usb_disable(struct clk_hw *hw)
{
struct at91sam9x5_clk_usb *usb = to_at91sam9x5_clk_usb(hw);
struct at91_pmc *pmc = usb->pmc;
pmc_write(pmc, AT91_PMC_USB,
pmc_read(pmc, AT91_PMC_USB) & ~AT91_PMC_USBS);
}
static int at91sam9n12_clk_usb_is_enabled(struct clk_hw *hw)
{
struct at91sam9x5_clk_usb *usb = to_at91sam9x5_clk_usb(hw);
struct at91_pmc *pmc = usb->pmc;
return !!(pmc_read(pmc, AT91_PMC_USB) & AT91_PMC_USBS);
}
static const struct clk_ops at91sam9n12_usb_ops = {
.enable = at91sam9n12_clk_usb_enable,
.disable = at91sam9n12_clk_usb_disable,
.is_enabled = at91sam9n12_clk_usb_is_enabled,
.recalc_rate = at91sam9x5_clk_usb_recalc_rate,
.round_rate = at91sam9x5_clk_usb_round_rate,
.set_rate = at91sam9x5_clk_usb_set_rate,
};
static struct clk * __init
at91sam9x5_clk_register_usb(struct at91_pmc *pmc, const char *name,
const char **parent_names, u8 num_parents)
{
struct at91sam9x5_clk_usb *usb;
struct clk *clk = NULL;
struct clk_init_data init;
usb = kzalloc(sizeof(*usb), GFP_KERNEL);
if (!usb)
return ERR_PTR(-ENOMEM);
init.name = name;
init.ops = &at91sam9x5_usb_ops;
init.parent_names = parent_names;
init.num_parents = num_parents;
init.flags = CLK_SET_RATE_GATE | CLK_SET_PARENT_GATE;
usb->hw.init = &init;
usb->pmc = pmc;
clk = clk_register(NULL, &usb->hw);
if (IS_ERR(clk))
kfree(usb);
return clk;
}
static struct clk * __init
at91sam9n12_clk_register_usb(struct at91_pmc *pmc, const char *name,
const char *parent_name)
{
struct at91sam9x5_clk_usb *usb;
struct clk *clk = NULL;
struct clk_init_data init;
usb = kzalloc(sizeof(*usb), GFP_KERNEL);
if (!usb)
return ERR_PTR(-ENOMEM);
init.name = name;
init.ops = &at91sam9n12_usb_ops;
init.parent_names = &parent_name;
init.num_parents = 1;
init.flags = CLK_SET_RATE_GATE;
usb->hw.init = &init;
usb->pmc = pmc;
clk = clk_register(NULL, &usb->hw);
if (IS_ERR(clk))
kfree(usb);
return clk;
}
static unsigned long at91rm9200_clk_usb_recalc_rate(struct clk_hw *hw,
unsigned long parent_rate)
{
struct at91rm9200_clk_usb *usb = to_at91rm9200_clk_usb(hw);
struct at91_pmc *pmc = usb->pmc;
u32 tmp;
u8 usbdiv;
tmp = pmc_read(pmc, AT91_CKGR_PLLBR);
usbdiv = (tmp & AT91_PMC_USBDIV) >> RM9200_USB_DIV_SHIFT;
if (usb->divisors[usbdiv])
return parent_rate / usb->divisors[usbdiv];
return 0;
}
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);
unsigned long bestrate = 0;
int bestdiff = -1;
unsigned long tmprate;
int tmpdiff;
int i = 0;
for (i = 0; i < 4; i++) {
if (!usb->divisors[i])
continue;
tmprate = *parent_rate / usb->divisors[i];
if (tmprate < rate)
tmpdiff = rate - tmprate;
else
tmpdiff = tmprate - rate;
if (bestdiff < 0 || bestdiff > tmpdiff) {
bestrate = tmprate;
bestdiff = tmpdiff;
}
if (!bestdiff)
break;
}
return bestrate;
}
static int at91rm9200_clk_usb_set_rate(struct clk_hw *hw, unsigned long rate,
unsigned long parent_rate)
{
u32 tmp;
int i;
struct at91rm9200_clk_usb *usb = to_at91rm9200_clk_usb(hw);
struct at91_pmc *pmc = usb->pmc;
unsigned long div = parent_rate / rate;
if (parent_rate % rate)
return -EINVAL;
for (i = 0; i < RM9200_USB_DIV_TAB_SIZE; i++) {
if (usb->divisors[i] == div) {
tmp = pmc_read(pmc, AT91_CKGR_PLLBR) &
~AT91_PMC_USBDIV;
tmp |= i << RM9200_USB_DIV_SHIFT;
pmc_write(pmc, AT91_CKGR_PLLBR, tmp);
return 0;
}
}
return -EINVAL;
}
static const struct clk_ops at91rm9200_usb_ops = {
.recalc_rate = at91rm9200_clk_usb_recalc_rate,
.round_rate = at91rm9200_clk_usb_round_rate,
.set_rate = at91rm9200_clk_usb_set_rate,
};
static struct clk * __init
at91rm9200_clk_register_usb(struct at91_pmc *pmc, const char *name,
const char *parent_name, const u32 *divisors)
{
struct at91rm9200_clk_usb *usb;
struct clk *clk = NULL;
struct clk_init_data init;
usb = kzalloc(sizeof(*usb), GFP_KERNEL);
if (!usb)
return ERR_PTR(-ENOMEM);
init.name = name;
init.ops = &at91rm9200_usb_ops;
init.parent_names = &parent_name;
init.num_parents = 1;
init.flags = 0;
usb->hw.init = &init;
usb->pmc = pmc;
memcpy(usb->divisors, divisors, sizeof(usb->divisors));
clk = clk_register(NULL, &usb->hw);
if (IS_ERR(clk))
kfree(usb);
return clk;
}
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;
num_parents = of_count_phandle_with_args(np, "clocks", "#clock-cells");
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_property_read_string(np, "clock-output-names", &name);
clk = at91sam9x5_clk_register_usb(pmc, name, parent_names, num_parents);
if (IS_ERR(clk))
return;
of_clk_add_provider(np, of_clk_src_simple_get, clk);
}
void __init of_at91sam9n12_clk_usb_setup(struct device_node *np,
struct at91_pmc *pmc)
{
struct clk *clk;
const char *parent_name;
const char *name = np->name;
parent_name = of_clk_get_parent_name(np, 0);
if (!parent_name)
return;
of_property_read_string(np, "clock-output-names", &name);
clk = at91sam9n12_clk_register_usb(pmc, name, parent_name);
if (IS_ERR(clk))
return;
of_clk_add_provider(np, of_clk_src_simple_get, clk);
}
void __init of_at91rm9200_clk_usb_setup(struct device_node *np,
struct at91_pmc *pmc)
{
struct clk *clk;
const char *parent_name;
const char *name = np->name;
u32 divisors[4] = {0, 0, 0, 0};
parent_name = of_clk_get_parent_name(np, 0);
if (!parent_name)
return;
of_property_read_u32_array(np, "atmel,clk-divisors", divisors, 4);
if (!divisors[0])
return;
of_property_read_string(np, "clock-output-names", &name);
clk = at91rm9200_clk_register_usb(pmc, name, parent_name, divisors);
if (IS_ERR(clk))
return;
of_clk_add_provider(np, of_clk_src_simple_get, clk);
}
/*
* Copyright (C) 2013 Boris BREZILLON <b.brezillon@overkiz.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
*/
#include <linux/clk-provider.h>
#include <linux/clkdev.h>
#include <linux/clk/at91_pmc.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_irq.h>
#include <linux/io.h>
#include <linux/sched.h>
#include <linux/wait.h>
#include "pmc.h"
#define UTMI_FIXED_MUL 40
struct clk_utmi {
struct clk_hw hw;
struct at91_pmc *pmc;
unsigned int irq;
wait_queue_head_t wait;
};
#define to_clk_utmi(hw) container_of(hw, struct clk_utmi, hw)
static irqreturn_t clk_utmi_irq_handler(int irq, void *dev_id)
{
struct clk_utmi *utmi = (struct clk_utmi *)dev_id;
wake_up(&utmi->wait);
disable_irq_nosync(utmi->irq);
return IRQ_HANDLED;
}
static int clk_utmi_prepare(struct clk_hw *hw)
{
struct clk_utmi *utmi = to_clk_utmi(hw);
struct at91_pmc *pmc = utmi->pmc;
u32 tmp = at91_pmc_read(AT91_CKGR_UCKR) | AT91_PMC_UPLLEN |
AT91_PMC_UPLLCOUNT | AT91_PMC_BIASEN;
pmc_write(pmc, AT91_CKGR_UCKR, tmp);
while (!(pmc_read(pmc, AT91_PMC_SR) & AT91_PMC_LOCKU)) {
enable_irq(utmi->irq);
wait_event(utmi->wait,
pmc_read(pmc, AT91_PMC_SR) & AT91_PMC_LOCKU);
}
return 0;
}
static int clk_utmi_is_prepared(struct clk_hw *hw)
{
struct clk_utmi *utmi = to_clk_utmi(hw);
struct at91_pmc *pmc = utmi->pmc;
return !!(pmc_read(pmc, AT91_PMC_SR) & AT91_PMC_LOCKU);
}
static void clk_utmi_unprepare(struct clk_hw *hw)
{
struct clk_utmi *utmi = to_clk_utmi(hw);
struct at91_pmc *pmc = utmi->pmc;
u32 tmp = at91_pmc_read(AT91_CKGR_UCKR) & ~AT91_PMC_UPLLEN;
pmc_write(pmc, AT91_CKGR_UCKR, tmp);
}
static unsigned long clk_utmi_recalc_rate(struct clk_hw *hw,
unsigned long parent_rate)
{
/* UTMI clk is a fixed clk multiplier */
return parent_rate * UTMI_FIXED_MUL;
}
static const struct clk_ops utmi_ops = {
.prepare = clk_utmi_prepare,
.unprepare = clk_utmi_unprepare,
.is_prepared = clk_utmi_is_prepared,
.recalc_rate = clk_utmi_recalc_rate,
};
static struct clk * __init
at91_clk_register_utmi(struct at91_pmc *pmc, unsigned int irq,
const char *name, const char *parent_name)
{
int ret;
struct clk_utmi *utmi;
struct clk *clk = NULL;
struct clk_init_data init;
utmi = kzalloc(sizeof(*utmi), GFP_KERNEL);
if (!utmi)
return ERR_PTR(-ENOMEM);
init.name = name;
init.ops = &utmi_ops;
init.parent_names = parent_name ? &parent_name : NULL;
init.num_parents = parent_name ? 1 : 0;
init.flags = CLK_SET_RATE_GATE;
utmi->hw.init = &init;
utmi->pmc = pmc;
utmi->irq = irq;
init_waitqueue_head(&utmi->wait);
irq_set_status_flags(utmi->irq, IRQ_NOAUTOEN);
ret = request_irq(utmi->irq, clk_utmi_irq_handler,
IRQF_TRIGGER_HIGH, "clk-utmi", utmi);
if (ret)
return ERR_PTR(ret);
clk = clk_register(NULL, &utmi->hw);
if (IS_ERR(clk))
kfree(utmi);
return clk;
}
static void __init
of_at91_clk_utmi_setup(struct device_node *np, struct at91_pmc *pmc)
{
unsigned int irq;
struct clk *clk;
const char *parent_name;
const char *name = np->name;
parent_name = of_clk_get_parent_name(np, 0);
of_property_read_string(np, "clock-output-names", &name);
irq = irq_of_parse_and_map(np, 0);
if (!irq)
return;
clk = at91_clk_register_utmi(pmc, irq, name, parent_name);
if (IS_ERR(clk))
return;
of_clk_add_provider(np, of_clk_src_simple_get, clk);
return;
}
void __init of_at91sam9x5_clk_utmi_setup(struct device_node *np,
struct at91_pmc *pmc)
{
of_at91_clk_utmi_setup(np, pmc);
}
This diff is collapsed.
/*
* drivers/clk/at91/pmc.h
*
* Copyright (C) 2013 Boris BREZILLON <b.brezillon@overkiz.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*/
#ifndef __PMC_H_
#define __PMC_H_
#include <linux/io.h>
#include <linux/irqdomain.h>
#include <linux/spinlock.h>
struct clk_range {
unsigned long min;
unsigned long max;
};
#define CLK_RANGE(MIN, MAX) {.min = MIN, .max = MAX,}
struct at91_pmc_caps {
u32 available_irqs;
};
struct at91_pmc {
void __iomem *regbase;
int virq;
spinlock_t lock;
const struct at91_pmc_caps *caps;
struct irq_domain *irqdomain;
};
static inline void pmc_lock(struct at91_pmc *pmc)
{
spin_lock(&pmc->lock);
}
static inline void pmc_unlock(struct at91_pmc *pmc)
{
spin_unlock(&pmc->lock);
}
static inline u32 pmc_read(struct at91_pmc *pmc, int offset)
{
return readl(pmc->regbase + offset);
}
static inline void pmc_write(struct at91_pmc *pmc, int offset, u32 value)
{
writel(value, pmc->regbase + offset);
}
int of_at91_get_clk_range(struct device_node *np, const char *propname,
struct clk_range *range);
extern void __init of_at91rm9200_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);
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);
extern void __init 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);
#if defined(CONFIG_AT91_PROGRAMMABLE_CLOCKS)
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);
#endif
#if defined(CONFIG_HAVE_AT91_UTMI)
extern void __init of_at91sam9x5_clk_utmi_setup(struct device_node *np,
struct at91_pmc *pmc);
#endif
#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
#if defined(CONFIG_HAVE_AT91_SMD)
extern void __init of_at91sam9x5_clk_smd_setup(struct device_node *np,
struct at91_pmc *pmc);
#endif
#endif /* __PMC_H_ */
...@@ -326,7 +326,7 @@ static int vbus_is_present(struct usba_udc *udc) ...@@ -326,7 +326,7 @@ static int vbus_is_present(struct usba_udc *udc)
#if defined(CONFIG_ARCH_AT91SAM9RL) #if defined(CONFIG_ARCH_AT91SAM9RL)
#include <mach/at91_pmc.h> #include <linux/clk/at91_pmc.h>
static void toggle_bias(int is_on) static void toggle_bias(int is_on)
{ {
......
/*
* This header provides constants for AT91 pmc status.
*
* The constants defined in this header are being used in dts.
*
* Licensed under GPLv2 or later.
*/
#ifndef _DT_BINDINGS_CLK_AT91_H
#define _DT_BINDINGS_CLK_AT91_H
#define AT91_PMC_MOSCS 0 /* MOSCS Flag */
#define AT91_PMC_LOCKA 1 /* PLLA Lock */
#define AT91_PMC_LOCKB 2 /* PLLB Lock */
#define AT91_PMC_MCKRDY 3 /* Master Clock */
#define AT91_PMC_LOCKU 6 /* UPLL Lock */
#define AT91_PMC_PCKRDY(id) (8 + (id)) /* Programmable Clock */
#define AT91_PMC_MOSCSELS 16 /* Main Oscillator Selection */
#define AT91_PMC_MOSCRCS 17 /* Main On-Chip RC */
#define AT91_PMC_CFDEV 18 /* Clock Failure Detector Event */
#endif
/* /*
* arch/arm/mach-at91/include/mach/at91_pmc.h * include/linux/clk/at91_pmc.h
* *
* Copyright (C) 2005 Ivan Kokshaysky * Copyright (C) 2005 Ivan Kokshaysky
* Copyright (C) SAN People * Copyright (C) SAN People
...@@ -164,6 +164,8 @@ extern void __iomem *at91_pmc_base; ...@@ -164,6 +164,8 @@ extern void __iomem *at91_pmc_base;
#define AT91_PMC_CFDEV (1 << 18) /* Clock Failure Detector Event [some SAM9] */ #define AT91_PMC_CFDEV (1 << 18) /* Clock Failure Detector Event [some SAM9] */
#define AT91_PMC_IMR 0x6c /* Interrupt Mask Register */ #define AT91_PMC_IMR 0x6c /* Interrupt Mask Register */
#define AT91_PMC_PLLICPR 0x80 /* PLL Charge Pump Current Register */
#define AT91_PMC_PROT 0xe4 /* Write Protect Mode Register [some SAM9] */ #define AT91_PMC_PROT 0xe4 /* Write Protect Mode Register [some SAM9] */
#define AT91_PMC_WPEN (0x1 << 0) /* Write Protect Enable */ #define AT91_PMC_WPEN (0x1 << 0) /* Write Protect Enable */
#define AT91_PMC_WPKEY (0xffffff << 8) /* Write Protect Key */ #define AT91_PMC_WPKEY (0xffffff << 8) /* Write Protect Key */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment