Merge branch 'clk-next-mmp' into clk-next
This commit is contained in:
commit
280da70580
21
Documentation/devicetree/bindings/clock/marvell,mmp2.txt
Normal file
21
Documentation/devicetree/bindings/clock/marvell,mmp2.txt
Normal file
@ -0,0 +1,21 @@
|
||||
* Marvell MMP2 Clock Controller
|
||||
|
||||
The MMP2 clock subsystem generates and supplies clock to various
|
||||
controllers within the MMP2 SoC.
|
||||
|
||||
Required Properties:
|
||||
|
||||
- compatible: should be one of the following.
|
||||
- "marvell,mmp2-clock" - controller compatible with MMP2 SoC.
|
||||
|
||||
- reg: physical base address of the clock subsystem and length of memory mapped
|
||||
region. There are 3 places in SOC has clock control logic:
|
||||
"mpmu", "apmu", "apbc". So three reg spaces need to be defined.
|
||||
|
||||
- #clock-cells: should be 1.
|
||||
- #reset-cells: should be 1.
|
||||
|
||||
Each clock is assigned an identifier and client nodes use this identifier
|
||||
to specify the clock which they consume.
|
||||
|
||||
All these identifier could be found in <dt-bindings/clock/marvell-mmp2.h>.
|
21
Documentation/devicetree/bindings/clock/marvell,pxa168.txt
Normal file
21
Documentation/devicetree/bindings/clock/marvell,pxa168.txt
Normal file
@ -0,0 +1,21 @@
|
||||
* Marvell PXA168 Clock Controller
|
||||
|
||||
The PXA168 clock subsystem generates and supplies clock to various
|
||||
controllers within the PXA168 SoC.
|
||||
|
||||
Required Properties:
|
||||
|
||||
- compatible: should be one of the following.
|
||||
- "marvell,pxa168-clock" - controller compatible with PXA168 SoC.
|
||||
|
||||
- reg: physical base address of the clock subsystem and length of memory mapped
|
||||
region. There are 3 places in SOC has clock control logic:
|
||||
"mpmu", "apmu", "apbc". So three reg spaces need to be defined.
|
||||
|
||||
- #clock-cells: should be 1.
|
||||
- #reset-cells: should be 1.
|
||||
|
||||
Each clock is assigned an identifier and client nodes use this identifier
|
||||
to specify the clock which they consume.
|
||||
|
||||
All these identifier could be found in <dt-bindings/clock/marvell,pxa168.h>.
|
21
Documentation/devicetree/bindings/clock/marvell,pxa910.txt
Normal file
21
Documentation/devicetree/bindings/clock/marvell,pxa910.txt
Normal file
@ -0,0 +1,21 @@
|
||||
* Marvell PXA910 Clock Controller
|
||||
|
||||
The PXA910 clock subsystem generates and supplies clock to various
|
||||
controllers within the PXA910 SoC.
|
||||
|
||||
Required Properties:
|
||||
|
||||
- compatible: should be one of the following.
|
||||
- "marvell,pxa910-clock" - controller compatible with PXA910 SoC.
|
||||
|
||||
- reg: physical base address of the clock subsystem and length of memory mapped
|
||||
region. There are 4 places in SOC has clock control logic:
|
||||
"mpmu", "apmu", "apbc", "apbcp". So four reg spaces need to be defined.
|
||||
|
||||
- #clock-cells: should be 1.
|
||||
- #reset-cells: should be 1.
|
||||
|
||||
Each clock is assigned an identifier and client nodes use this identifier
|
||||
to specify the clock which they consume.
|
||||
|
||||
All these identifier could be found in <dt-bindings/clock/marvell-pxa910.h>.
|
@ -164,6 +164,9 @@ dtb-$(CONFIG_MACH_KIRKWOOD) += kirkwood-b3.dtb \
|
||||
dtb-$(CONFIG_ARCH_LPC32XX) += ea3250.dtb phy3250.dtb
|
||||
dtb-$(CONFIG_ARCH_MARCO) += marco-evb.dtb
|
||||
dtb-$(CONFIG_MACH_MESON6) += meson6-atv1200.dtb
|
||||
dtb-$(CONFIG_ARCH_MMP) += pxa168-aspenite.dtb \
|
||||
pxa910-dkb.dtb \
|
||||
mmp2-brownstone.dtb
|
||||
dtb-$(CONFIG_ARCH_MOXART) += moxart-uc7112lx.dtb
|
||||
dtb-$(CONFIG_ARCH_MXC) += \
|
||||
imx1-ads.dtb \
|
||||
|
@ -8,7 +8,7 @@
|
||||
*/
|
||||
|
||||
/dts-v1/;
|
||||
/include/ "mmp2.dtsi"
|
||||
#include "mmp2.dtsi"
|
||||
|
||||
/ {
|
||||
model = "Marvell MMP2 Brownstone Development Board";
|
||||
|
@ -7,7 +7,8 @@
|
||||
* publishhed by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
/include/ "skeleton.dtsi"
|
||||
#include "skeleton.dtsi"
|
||||
#include <dt-bindings/clock/marvell,mmp2.h>
|
||||
|
||||
/ {
|
||||
aliases {
|
||||
@ -135,6 +136,8 @@
|
||||
compatible = "mrvl,mmp-uart";
|
||||
reg = <0xd4030000 0x1000>;
|
||||
interrupts = <27>;
|
||||
clocks = <&soc_clocks MMP2_CLK_UART0>;
|
||||
resets = <&soc_clocks MMP2_CLK_UART0>;
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
@ -142,6 +145,8 @@
|
||||
compatible = "mrvl,mmp-uart";
|
||||
reg = <0xd4017000 0x1000>;
|
||||
interrupts = <28>;
|
||||
clocks = <&soc_clocks MMP2_CLK_UART1>;
|
||||
resets = <&soc_clocks MMP2_CLK_UART1>;
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
@ -149,6 +154,8 @@
|
||||
compatible = "mrvl,mmp-uart";
|
||||
reg = <0xd4018000 0x1000>;
|
||||
interrupts = <24>;
|
||||
clocks = <&soc_clocks MMP2_CLK_UART2>;
|
||||
resets = <&soc_clocks MMP2_CLK_UART2>;
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
@ -156,6 +163,8 @@
|
||||
compatible = "mrvl,mmp-uart";
|
||||
reg = <0xd4016000 0x1000>;
|
||||
interrupts = <46>;
|
||||
clocks = <&soc_clocks MMP2_CLK_UART3>;
|
||||
resets = <&soc_clocks MMP2_CLK_UART3>;
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
@ -168,6 +177,8 @@
|
||||
#gpio-cells = <2>;
|
||||
interrupts = <49>;
|
||||
interrupt-names = "gpio_mux";
|
||||
clocks = <&soc_clocks MMP2_CLK_GPIO>;
|
||||
resets = <&soc_clocks MMP2_CLK_GPIO>;
|
||||
interrupt-controller;
|
||||
#interrupt-cells = <1>;
|
||||
ranges;
|
||||
@ -201,6 +212,8 @@
|
||||
compatible = "mrvl,mmp-twsi";
|
||||
reg = <0xd4011000 0x1000>;
|
||||
interrupts = <7>;
|
||||
clocks = <&soc_clocks MMP2_CLK_TWSI0>;
|
||||
resets = <&soc_clocks MMP2_CLK_TWSI0>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
mrvl,i2c-fast-mode;
|
||||
@ -211,6 +224,8 @@
|
||||
compatible = "mrvl,mmp-twsi";
|
||||
reg = <0xd4025000 0x1000>;
|
||||
interrupts = <58>;
|
||||
clocks = <&soc_clocks MMP2_CLK_TWSI1>;
|
||||
resets = <&soc_clocks MMP2_CLK_TWSI1>;
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
@ -220,8 +235,20 @@
|
||||
interrupts = <1 0>;
|
||||
interrupt-names = "rtc 1Hz", "rtc alarm";
|
||||
interrupt-parent = <&intcmux5>;
|
||||
clocks = <&soc_clocks MMP2_CLK_RTC>;
|
||||
resets = <&soc_clocks MMP2_CLK_RTC>;
|
||||
status = "disabled";
|
||||
};
|
||||
};
|
||||
|
||||
soc_clocks: clocks{
|
||||
compatible = "marvell,mmp2-clock";
|
||||
reg = <0xd4050000 0x1000>,
|
||||
<0xd4282800 0x400>,
|
||||
<0xd4015000 0x1000>;
|
||||
reg-names = "mpmu", "apmu", "apbc";
|
||||
#clock-cells = <1>;
|
||||
#reset-cells = <1>;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
@ -8,7 +8,7 @@
|
||||
*/
|
||||
|
||||
/dts-v1/;
|
||||
/include/ "pxa168.dtsi"
|
||||
#include "pxa168.dtsi"
|
||||
|
||||
/ {
|
||||
model = "Marvell PXA168 Aspenite Development Board";
|
||||
|
@ -7,7 +7,8 @@
|
||||
* publishhed by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
/include/ "skeleton.dtsi"
|
||||
#include "skeleton.dtsi"
|
||||
#include <dt-bindings/clock/marvell,pxa168.h>
|
||||
|
||||
/ {
|
||||
aliases {
|
||||
@ -59,6 +60,8 @@
|
||||
compatible = "mrvl,mmp-uart";
|
||||
reg = <0xd4017000 0x1000>;
|
||||
interrupts = <27>;
|
||||
clocks = <&soc_clocks PXA168_CLK_UART0>;
|
||||
resets = <&soc_clocks PXA168_CLK_UART0>;
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
@ -66,6 +69,8 @@
|
||||
compatible = "mrvl,mmp-uart";
|
||||
reg = <0xd4018000 0x1000>;
|
||||
interrupts = <28>;
|
||||
clocks = <&soc_clocks PXA168_CLK_UART1>;
|
||||
resets = <&soc_clocks PXA168_CLK_UART1>;
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
@ -73,6 +78,8 @@
|
||||
compatible = "mrvl,mmp-uart";
|
||||
reg = <0xd4026000 0x1000>;
|
||||
interrupts = <29>;
|
||||
clocks = <&soc_clocks PXA168_CLK_UART2>;
|
||||
resets = <&soc_clocks PXA168_CLK_UART2>;
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
@ -84,6 +91,8 @@
|
||||
gpio-controller;
|
||||
#gpio-cells = <2>;
|
||||
interrupts = <49>;
|
||||
clocks = <&soc_clocks PXA168_CLK_GPIO>;
|
||||
resets = <&soc_clocks PXA168_CLK_GPIO>;
|
||||
interrupt-names = "gpio_mux";
|
||||
interrupt-controller;
|
||||
#interrupt-cells = <1>;
|
||||
@ -110,6 +119,8 @@
|
||||
compatible = "mrvl,mmp-twsi";
|
||||
reg = <0xd4011000 0x1000>;
|
||||
interrupts = <7>;
|
||||
clocks = <&soc_clocks PXA168_CLK_TWSI0>;
|
||||
resets = <&soc_clocks PXA168_CLK_TWSI0>;
|
||||
mrvl,i2c-fast-mode;
|
||||
status = "disabled";
|
||||
};
|
||||
@ -118,6 +129,8 @@
|
||||
compatible = "mrvl,mmp-twsi";
|
||||
reg = <0xd4025000 0x1000>;
|
||||
interrupts = <58>;
|
||||
clocks = <&soc_clocks PXA168_CLK_TWSI1>;
|
||||
resets = <&soc_clocks PXA168_CLK_TWSI1>;
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
@ -126,8 +139,20 @@
|
||||
reg = <0xd4010000 0x1000>;
|
||||
interrupts = <5 6>;
|
||||
interrupt-names = "rtc 1Hz", "rtc alarm";
|
||||
clocks = <&soc_clocks PXA168_CLK_RTC>;
|
||||
resets = <&soc_clocks PXA168_CLK_RTC>;
|
||||
status = "disabled";
|
||||
};
|
||||
};
|
||||
|
||||
soc_clocks: clocks{
|
||||
compatible = "marvell,pxa168-clock";
|
||||
reg = <0xd4050000 0x1000>,
|
||||
<0xd4282800 0x400>,
|
||||
<0xd4015000 0x1000>;
|
||||
reg-names = "mpmu", "apmu", "apbc";
|
||||
#clock-cells = <1>;
|
||||
#reset-cells = <1>;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
@ -8,7 +8,7 @@
|
||||
*/
|
||||
|
||||
/dts-v1/;
|
||||
/include/ "pxa910.dtsi"
|
||||
#include "pxa910.dtsi"
|
||||
|
||||
/ {
|
||||
model = "Marvell PXA910 DKB Development Board";
|
||||
|
@ -7,7 +7,8 @@
|
||||
* publishhed by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
/include/ "skeleton.dtsi"
|
||||
#include "skeleton.dtsi"
|
||||
#include <dt-bindings/clock/marvell,pxa910.h>
|
||||
|
||||
/ {
|
||||
aliases {
|
||||
@ -71,6 +72,8 @@
|
||||
compatible = "mrvl,mmp-uart";
|
||||
reg = <0xd4017000 0x1000>;
|
||||
interrupts = <27>;
|
||||
clocks = <&soc_clocks PXA910_CLK_UART0>;
|
||||
resets = <&soc_clocks PXA910_CLK_UART0>;
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
@ -78,6 +81,8 @@
|
||||
compatible = "mrvl,mmp-uart";
|
||||
reg = <0xd4018000 0x1000>;
|
||||
interrupts = <28>;
|
||||
clocks = <&soc_clocks PXA910_CLK_UART1>;
|
||||
resets = <&soc_clocks PXA910_CLK_UART1>;
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
@ -85,6 +90,8 @@
|
||||
compatible = "mrvl,mmp-uart";
|
||||
reg = <0xd4036000 0x1000>;
|
||||
interrupts = <59>;
|
||||
clocks = <&soc_clocks PXA910_CLK_UART2>;
|
||||
resets = <&soc_clocks PXA910_CLK_UART2>;
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
@ -97,6 +104,8 @@
|
||||
#gpio-cells = <2>;
|
||||
interrupts = <49>;
|
||||
interrupt-names = "gpio_mux";
|
||||
clocks = <&soc_clocks PXA910_CLK_GPIO>;
|
||||
resets = <&soc_clocks PXA910_CLK_GPIO>;
|
||||
interrupt-controller;
|
||||
#interrupt-cells = <1>;
|
||||
ranges;
|
||||
@ -124,6 +133,8 @@
|
||||
#size-cells = <0>;
|
||||
reg = <0xd4011000 0x1000>;
|
||||
interrupts = <7>;
|
||||
clocks = <&soc_clocks PXA910_CLK_TWSI0>;
|
||||
resets = <&soc_clocks PXA910_CLK_TWSI0>;
|
||||
mrvl,i2c-fast-mode;
|
||||
status = "disabled";
|
||||
};
|
||||
@ -134,6 +145,8 @@
|
||||
#size-cells = <0>;
|
||||
reg = <0xd4037000 0x1000>;
|
||||
interrupts = <54>;
|
||||
clocks = <&soc_clocks PXA910_CLK_TWSI1>;
|
||||
resets = <&soc_clocks PXA910_CLK_TWSI1>;
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
@ -142,8 +155,21 @@
|
||||
reg = <0xd4010000 0x1000>;
|
||||
interrupts = <5 6>;
|
||||
interrupt-names = "rtc 1Hz", "rtc alarm";
|
||||
clocks = <&soc_clocks PXA910_CLK_RTC>;
|
||||
resets = <&soc_clocks PXA910_CLK_RTC>;
|
||||
status = "disabled";
|
||||
};
|
||||
};
|
||||
|
||||
soc_clocks: clocks{
|
||||
compatible = "marvell,pxa910-clock";
|
||||
reg = <0xd4050000 0x1000>,
|
||||
<0xd4282800 0x400>,
|
||||
<0xd4015000 0x1000>,
|
||||
<0xd403b000 0x1000>;
|
||||
reg-names = "mpmu", "apmu", "apbc", "apbcp";
|
||||
#clock-cells = <1>;
|
||||
#reset-cells = <1>;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
@ -86,11 +86,12 @@ config MACH_GPLUGD
|
||||
|
||||
config MACH_MMP_DT
|
||||
bool "Support MMP (ARMv5) platforms from device tree"
|
||||
select CPU_PXA168
|
||||
select CPU_PXA910
|
||||
select USE_OF
|
||||
select PINCTRL
|
||||
select PINCTRL_SINGLE
|
||||
select COMMON_CLK
|
||||
select ARCH_HAS_RESET_CONTROLLER
|
||||
select CPU_MOHAWK
|
||||
help
|
||||
Include support for Marvell MMP2 based platforms using
|
||||
the device tree. Needn't select any other machine while
|
||||
@ -99,10 +100,12 @@ config MACH_MMP_DT
|
||||
config MACH_MMP2_DT
|
||||
bool "Support MMP2 (ARMv7) platforms from device tree"
|
||||
depends on !CPU_MOHAWK
|
||||
select CPU_MMP2
|
||||
select USE_OF
|
||||
select PINCTRL
|
||||
select PINCTRL_SINGLE
|
||||
select COMMON_CLK
|
||||
select ARCH_HAS_RESET_CONTROLLER
|
||||
select CPU_PJ4
|
||||
help
|
||||
Include support for Marvell MMP2 based platforms using
|
||||
the device tree.
|
||||
@ -111,21 +114,18 @@ endmenu
|
||||
|
||||
config CPU_PXA168
|
||||
bool
|
||||
select COMMON_CLK
|
||||
select CPU_MOHAWK
|
||||
help
|
||||
Select code specific to PXA168
|
||||
|
||||
config CPU_PXA910
|
||||
bool
|
||||
select COMMON_CLK
|
||||
select CPU_MOHAWK
|
||||
help
|
||||
Select code specific to PXA910
|
||||
|
||||
config CPU_MMP2
|
||||
bool
|
||||
select COMMON_CLK
|
||||
select CPU_PJ4
|
||||
help
|
||||
Select code specific to MMP2. MMP2 is ARMv7 compatible.
|
||||
|
@ -11,63 +11,42 @@
|
||||
|
||||
#include <linux/irqchip.h>
|
||||
#include <linux/of_platform.h>
|
||||
#include <linux/clk-provider.h>
|
||||
#include <asm/mach/arch.h>
|
||||
#include <asm/mach/time.h>
|
||||
#include <asm/hardware/cache-tauros2.h>
|
||||
|
||||
#include "common.h"
|
||||
|
||||
extern void __init mmp_dt_init_timer(void);
|
||||
|
||||
static const struct of_dev_auxdata pxa168_auxdata_lookup[] __initconst = {
|
||||
OF_DEV_AUXDATA("mrvl,mmp-uart", 0xd4017000, "pxa2xx-uart.0", NULL),
|
||||
OF_DEV_AUXDATA("mrvl,mmp-uart", 0xd4018000, "pxa2xx-uart.1", NULL),
|
||||
OF_DEV_AUXDATA("mrvl,mmp-uart", 0xd4026000, "pxa2xx-uart.2", NULL),
|
||||
OF_DEV_AUXDATA("mrvl,mmp-twsi", 0xd4011000, "pxa2xx-i2c.0", NULL),
|
||||
OF_DEV_AUXDATA("mrvl,mmp-twsi", 0xd4025000, "pxa2xx-i2c.1", NULL),
|
||||
OF_DEV_AUXDATA("marvell,mmp-gpio", 0xd4019000, "mmp-gpio", NULL),
|
||||
OF_DEV_AUXDATA("mrvl,mmp-rtc", 0xd4010000, "sa1100-rtc", NULL),
|
||||
{}
|
||||
};
|
||||
|
||||
static const struct of_dev_auxdata pxa910_auxdata_lookup[] __initconst = {
|
||||
OF_DEV_AUXDATA("mrvl,mmp-uart", 0xd4017000, "pxa2xx-uart.0", NULL),
|
||||
OF_DEV_AUXDATA("mrvl,mmp-uart", 0xd4018000, "pxa2xx-uart.1", NULL),
|
||||
OF_DEV_AUXDATA("mrvl,mmp-uart", 0xd4036000, "pxa2xx-uart.2", NULL),
|
||||
OF_DEV_AUXDATA("mrvl,mmp-twsi", 0xd4011000, "pxa2xx-i2c.0", NULL),
|
||||
OF_DEV_AUXDATA("mrvl,mmp-twsi", 0xd4037000, "pxa2xx-i2c.1", NULL),
|
||||
OF_DEV_AUXDATA("marvell,mmp-gpio", 0xd4019000, "mmp-gpio", NULL),
|
||||
OF_DEV_AUXDATA("mrvl,mmp-rtc", 0xd4010000, "sa1100-rtc", NULL),
|
||||
{}
|
||||
};
|
||||
|
||||
static void __init pxa168_dt_init(void)
|
||||
{
|
||||
of_platform_populate(NULL, of_default_bus_match_table,
|
||||
pxa168_auxdata_lookup, NULL);
|
||||
}
|
||||
|
||||
static void __init pxa910_dt_init(void)
|
||||
{
|
||||
of_platform_populate(NULL, of_default_bus_match_table,
|
||||
pxa910_auxdata_lookup, NULL);
|
||||
}
|
||||
|
||||
static const char *mmp_dt_board_compat[] __initdata = {
|
||||
static const char *pxa168_dt_board_compat[] __initdata = {
|
||||
"mrvl,pxa168-aspenite",
|
||||
NULL,
|
||||
};
|
||||
|
||||
static const char *pxa910_dt_board_compat[] __initdata = {
|
||||
"mrvl,pxa910-dkb",
|
||||
NULL,
|
||||
};
|
||||
|
||||
static void __init mmp_init_time(void)
|
||||
{
|
||||
#ifdef CONFIG_CACHE_TAUROS2
|
||||
tauros2_init(0);
|
||||
#endif
|
||||
mmp_dt_init_timer();
|
||||
of_clk_init(NULL);
|
||||
}
|
||||
|
||||
DT_MACHINE_START(PXA168_DT, "Marvell PXA168 (Device Tree Support)")
|
||||
.map_io = mmp_map_io,
|
||||
.init_time = mmp_dt_init_timer,
|
||||
.init_machine = pxa168_dt_init,
|
||||
.dt_compat = mmp_dt_board_compat,
|
||||
.init_time = mmp_init_time,
|
||||
.dt_compat = pxa168_dt_board_compat,
|
||||
MACHINE_END
|
||||
|
||||
DT_MACHINE_START(PXA910_DT, "Marvell PXA910 (Device Tree Support)")
|
||||
.map_io = mmp_map_io,
|
||||
.init_time = mmp_dt_init_timer,
|
||||
.init_machine = pxa910_dt_init,
|
||||
.dt_compat = mmp_dt_board_compat,
|
||||
.init_time = mmp_init_time,
|
||||
.dt_compat = pxa910_dt_board_compat,
|
||||
MACHINE_END
|
||||
|
@ -12,29 +12,22 @@
|
||||
#include <linux/io.h>
|
||||
#include <linux/irqchip.h>
|
||||
#include <linux/of_platform.h>
|
||||
#include <linux/clk-provider.h>
|
||||
#include <asm/mach/arch.h>
|
||||
#include <asm/mach/time.h>
|
||||
#include <asm/hardware/cache-tauros2.h>
|
||||
|
||||
#include "common.h"
|
||||
|
||||
extern void __init mmp_dt_init_timer(void);
|
||||
|
||||
static const struct of_dev_auxdata mmp2_auxdata_lookup[] __initconst = {
|
||||
OF_DEV_AUXDATA("mrvl,mmp-uart", 0xd4030000, "pxa2xx-uart.0", NULL),
|
||||
OF_DEV_AUXDATA("mrvl,mmp-uart", 0xd4017000, "pxa2xx-uart.1", NULL),
|
||||
OF_DEV_AUXDATA("mrvl,mmp-uart", 0xd4018000, "pxa2xx-uart.2", NULL),
|
||||
OF_DEV_AUXDATA("mrvl,mmp-uart", 0xd4016000, "pxa2xx-uart.3", NULL),
|
||||
OF_DEV_AUXDATA("mrvl,mmp-twsi", 0xd4011000, "pxa2xx-i2c.0", NULL),
|
||||
OF_DEV_AUXDATA("mrvl,mmp-twsi", 0xd4025000, "pxa2xx-i2c.1", NULL),
|
||||
OF_DEV_AUXDATA("marvell,mmp-gpio", 0xd4019000, "mmp2-gpio", NULL),
|
||||
OF_DEV_AUXDATA("mrvl,mmp-rtc", 0xd4010000, "sa1100-rtc", NULL),
|
||||
{}
|
||||
};
|
||||
|
||||
static void __init mmp2_dt_init(void)
|
||||
static void __init mmp_init_time(void)
|
||||
{
|
||||
of_platform_populate(NULL, of_default_bus_match_table,
|
||||
mmp2_auxdata_lookup, NULL);
|
||||
#ifdef CONFIG_CACHE_TAUROS2
|
||||
tauros2_init(0);
|
||||
#endif
|
||||
mmp_dt_init_timer();
|
||||
of_clk_init(NULL);
|
||||
}
|
||||
|
||||
static const char *mmp2_dt_board_compat[] __initdata = {
|
||||
@ -44,7 +37,6 @@ static const char *mmp2_dt_board_compat[] __initdata = {
|
||||
|
||||
DT_MACHINE_START(MMP2_DT, "Marvell MMP2 (Device Tree Support)")
|
||||
.map_io = mmp_map_io,
|
||||
.init_time = mmp_dt_init_timer,
|
||||
.init_machine = mmp2_dt_init,
|
||||
.init_time = mmp_init_time,
|
||||
.dt_compat = mmp2_dt_board_compat,
|
||||
MACHINE_END
|
||||
|
@ -2,7 +2,12 @@
|
||||
# Makefile for mmp specific clk
|
||||
#
|
||||
|
||||
obj-y += clk-apbc.o clk-apmu.o clk-frac.o
|
||||
obj-y += clk-apbc.o clk-apmu.o clk-frac.o clk-mix.o clk-gate.o clk.o
|
||||
|
||||
obj-$(CONFIG_RESET_CONTROLLER) += reset.o
|
||||
|
||||
obj-$(CONFIG_MACH_MMP_DT) += clk-of-pxa168.o clk-of-pxa910.o
|
||||
obj-$(CONFIG_MACH_MMP2_DT) += clk-of-mmp2.o
|
||||
|
||||
obj-$(CONFIG_CPU_PXA168) += clk-pxa168.o
|
||||
obj-$(CONFIG_CPU_PXA910) += clk-pxa910.o
|
||||
|
@ -22,19 +22,12 @@
|
||||
* numerator/denominator = Fin / (Fout * factor)
|
||||
*/
|
||||
|
||||
#define to_clk_factor(hw) container_of(hw, struct clk_factor, hw)
|
||||
struct clk_factor {
|
||||
struct clk_hw hw;
|
||||
void __iomem *base;
|
||||
struct clk_factor_masks *masks;
|
||||
struct clk_factor_tbl *ftbl;
|
||||
unsigned int ftbl_cnt;
|
||||
};
|
||||
#define to_clk_factor(hw) container_of(hw, struct mmp_clk_factor, hw)
|
||||
|
||||
static long clk_factor_round_rate(struct clk_hw *hw, unsigned long drate,
|
||||
unsigned long *prate)
|
||||
{
|
||||
struct clk_factor *factor = to_clk_factor(hw);
|
||||
struct mmp_clk_factor *factor = to_clk_factor(hw);
|
||||
unsigned long rate = 0, prev_rate;
|
||||
int i;
|
||||
|
||||
@ -58,8 +51,8 @@ static long clk_factor_round_rate(struct clk_hw *hw, unsigned long drate,
|
||||
static unsigned long clk_factor_recalc_rate(struct clk_hw *hw,
|
||||
unsigned long parent_rate)
|
||||
{
|
||||
struct clk_factor *factor = to_clk_factor(hw);
|
||||
struct clk_factor_masks *masks = factor->masks;
|
||||
struct mmp_clk_factor *factor = to_clk_factor(hw);
|
||||
struct mmp_clk_factor_masks *masks = factor->masks;
|
||||
unsigned int val, num, den;
|
||||
|
||||
val = readl_relaxed(factor->base);
|
||||
@ -81,11 +74,12 @@ static unsigned long clk_factor_recalc_rate(struct clk_hw *hw,
|
||||
static int clk_factor_set_rate(struct clk_hw *hw, unsigned long drate,
|
||||
unsigned long prate)
|
||||
{
|
||||
struct clk_factor *factor = to_clk_factor(hw);
|
||||
struct clk_factor_masks *masks = factor->masks;
|
||||
struct mmp_clk_factor *factor = to_clk_factor(hw);
|
||||
struct mmp_clk_factor_masks *masks = factor->masks;
|
||||
int i;
|
||||
unsigned long val;
|
||||
unsigned long prev_rate, rate = 0;
|
||||
unsigned long flags = 0;
|
||||
|
||||
for (i = 0; i < factor->ftbl_cnt; i++) {
|
||||
prev_rate = rate;
|
||||
@ -97,6 +91,9 @@ static int clk_factor_set_rate(struct clk_hw *hw, unsigned long drate,
|
||||
if (i > 0)
|
||||
i--;
|
||||
|
||||
if (factor->lock)
|
||||
spin_lock_irqsave(factor->lock, flags);
|
||||
|
||||
val = readl_relaxed(factor->base);
|
||||
|
||||
val &= ~(masks->num_mask << masks->num_shift);
|
||||
@ -107,21 +104,65 @@ static int clk_factor_set_rate(struct clk_hw *hw, unsigned long drate,
|
||||
|
||||
writel_relaxed(val, factor->base);
|
||||
|
||||
if (factor->lock)
|
||||
spin_unlock_irqrestore(factor->lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void clk_factor_init(struct clk_hw *hw)
|
||||
{
|
||||
struct mmp_clk_factor *factor = to_clk_factor(hw);
|
||||
struct mmp_clk_factor_masks *masks = factor->masks;
|
||||
u32 val, num, den;
|
||||
int i;
|
||||
unsigned long flags = 0;
|
||||
|
||||
if (factor->lock)
|
||||
spin_lock_irqsave(factor->lock, flags);
|
||||
|
||||
val = readl(factor->base);
|
||||
|
||||
/* calculate numerator */
|
||||
num = (val >> masks->num_shift) & masks->num_mask;
|
||||
|
||||
/* calculate denominator */
|
||||
den = (val >> masks->den_shift) & masks->den_mask;
|
||||
|
||||
for (i = 0; i < factor->ftbl_cnt; i++)
|
||||
if (den == factor->ftbl[i].den && num == factor->ftbl[i].num)
|
||||
break;
|
||||
|
||||
if (i >= factor->ftbl_cnt) {
|
||||
val &= ~(masks->num_mask << masks->num_shift);
|
||||
val |= (factor->ftbl[0].num & masks->num_mask) <<
|
||||
masks->num_shift;
|
||||
|
||||
val &= ~(masks->den_mask << masks->den_shift);
|
||||
val |= (factor->ftbl[0].den & masks->den_mask) <<
|
||||
masks->den_shift;
|
||||
|
||||
writel(val, factor->base);
|
||||
}
|
||||
|
||||
if (factor->lock)
|
||||
spin_unlock_irqrestore(factor->lock, flags);
|
||||
}
|
||||
|
||||
static struct clk_ops clk_factor_ops = {
|
||||
.recalc_rate = clk_factor_recalc_rate,
|
||||
.round_rate = clk_factor_round_rate,
|
||||
.set_rate = clk_factor_set_rate,
|
||||
.init = clk_factor_init,
|
||||
};
|
||||
|
||||
struct clk *mmp_clk_register_factor(const char *name, const char *parent_name,
|
||||
unsigned long flags, void __iomem *base,
|
||||
struct clk_factor_masks *masks, struct clk_factor_tbl *ftbl,
|
||||
unsigned int ftbl_cnt)
|
||||
struct mmp_clk_factor_masks *masks,
|
||||
struct mmp_clk_factor_tbl *ftbl,
|
||||
unsigned int ftbl_cnt, spinlock_t *lock)
|
||||
{
|
||||
struct clk_factor *factor;
|
||||
struct mmp_clk_factor *factor;
|
||||
struct clk_init_data init;
|
||||
struct clk *clk;
|
||||
|
||||
@ -142,6 +183,7 @@ struct clk *mmp_clk_register_factor(const char *name, const char *parent_name,
|
||||
factor->ftbl = ftbl;
|
||||
factor->ftbl_cnt = ftbl_cnt;
|
||||
factor->hw.init = &init;
|
||||
factor->lock = lock;
|
||||
|
||||
init.name = name;
|
||||
init.ops = &clk_factor_ops;
|
||||
|
133
drivers/clk/mmp/clk-gate.c
Normal file
133
drivers/clk/mmp/clk-gate.c
Normal file
@ -0,0 +1,133 @@
|
||||
/*
|
||||
* mmp gate clock operation source file
|
||||
*
|
||||
* Copyright (C) 2014 Marvell
|
||||
* Chao Xie <chao.xie@marvell.com>
|
||||
*
|
||||
* This file is licensed under the terms of the GNU General Public
|
||||
* License version 2. This program is licensed "as is" without any
|
||||
* warranty of any kind, whether express or implied.
|
||||
*/
|
||||
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/delay.h>
|
||||
|
||||
#include "clk.h"
|
||||
|
||||
/*
|
||||
* Some clocks will have mutiple bits to enable the clocks, and
|
||||
* the bits to disable the clock is not same as enabling bits.
|
||||
*/
|
||||
|
||||
#define to_clk_mmp_gate(hw) container_of(hw, struct mmp_clk_gate, hw)
|
||||
|
||||
static int mmp_clk_gate_enable(struct clk_hw *hw)
|
||||
{
|
||||
struct mmp_clk_gate *gate = to_clk_mmp_gate(hw);
|
||||
struct clk *clk = hw->clk;
|
||||
unsigned long flags = 0;
|
||||
unsigned long rate;
|
||||
u32 tmp;
|
||||
|
||||
if (gate->lock)
|
||||
spin_lock_irqsave(gate->lock, flags);
|
||||
|
||||
tmp = readl(gate->reg);
|
||||
tmp &= ~gate->mask;
|
||||
tmp |= gate->val_enable;
|
||||
writel(tmp, gate->reg);
|
||||
|
||||
if (gate->lock)
|
||||
spin_unlock_irqrestore(gate->lock, flags);
|
||||
|
||||
if (gate->flags & MMP_CLK_GATE_NEED_DELAY) {
|
||||
rate = __clk_get_rate(clk);
|
||||
/* Need delay 2 cycles. */
|
||||
udelay(2000000/rate);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void mmp_clk_gate_disable(struct clk_hw *hw)
|
||||
{
|
||||
struct mmp_clk_gate *gate = to_clk_mmp_gate(hw);
|
||||
unsigned long flags = 0;
|
||||
u32 tmp;
|
||||
|
||||
if (gate->lock)
|
||||
spin_lock_irqsave(gate->lock, flags);
|
||||
|
||||
tmp = readl(gate->reg);
|
||||
tmp &= ~gate->mask;
|
||||
tmp |= gate->val_disable;
|
||||
writel(tmp, gate->reg);
|
||||
|
||||
if (gate->lock)
|
||||
spin_unlock_irqrestore(gate->lock, flags);
|
||||
}
|
||||
|
||||
static int mmp_clk_gate_is_enabled(struct clk_hw *hw)
|
||||
{
|
||||
struct mmp_clk_gate *gate = to_clk_mmp_gate(hw);
|
||||
unsigned long flags = 0;
|
||||
u32 tmp;
|
||||
|
||||
if (gate->lock)
|
||||
spin_lock_irqsave(gate->lock, flags);
|
||||
|
||||
tmp = readl(gate->reg);
|
||||
|
||||
if (gate->lock)
|
||||
spin_unlock_irqrestore(gate->lock, flags);
|
||||
|
||||
return (tmp & gate->mask) == gate->val_enable;
|
||||
}
|
||||
|
||||
const struct clk_ops mmp_clk_gate_ops = {
|
||||
.enable = mmp_clk_gate_enable,
|
||||
.disable = mmp_clk_gate_disable,
|
||||
.is_enabled = mmp_clk_gate_is_enabled,
|
||||
};
|
||||
|
||||
struct clk *mmp_clk_register_gate(struct device *dev, const char *name,
|
||||
const char *parent_name, unsigned long flags,
|
||||
void __iomem *reg, u32 mask, u32 val_enable, u32 val_disable,
|
||||
unsigned int gate_flags, spinlock_t *lock)
|
||||
{
|
||||
struct mmp_clk_gate *gate;
|
||||
struct clk *clk;
|
||||
struct clk_init_data init;
|
||||
|
||||
/* allocate the gate */
|
||||
gate = kzalloc(sizeof(*gate), GFP_KERNEL);
|
||||
if (!gate) {
|
||||
pr_err("%s:%s could not allocate gate clk\n", __func__, name);
|
||||
return ERR_PTR(-ENOMEM);
|
||||
}
|
||||
|
||||
init.name = name;
|
||||
init.ops = &mmp_clk_gate_ops;
|
||||
init.flags = flags | CLK_IS_BASIC;
|
||||
init.parent_names = (parent_name ? &parent_name : NULL);
|
||||
init.num_parents = (parent_name ? 1 : 0);
|
||||
|
||||
/* struct clk_gate assignments */
|
||||
gate->reg = reg;
|
||||
gate->mask = mask;
|
||||
gate->val_enable = val_enable;
|
||||
gate->val_disable = val_disable;
|
||||
gate->flags = gate_flags;
|
||||
gate->lock = lock;
|
||||
gate->hw.init = &init;
|
||||
|
||||
clk = clk_register(dev, &gate->hw);
|
||||
|
||||
if (IS_ERR(clk))
|
||||
kfree(gate);
|
||||
|
||||
return clk;
|
||||
}
|
513
drivers/clk/mmp/clk-mix.c
Normal file
513
drivers/clk/mmp/clk-mix.c
Normal file
@ -0,0 +1,513 @@
|
||||
/*
|
||||
* mmp mix(div and mux) clock operation source file
|
||||
*
|
||||
* Copyright (C) 2014 Marvell
|
||||
* Chao Xie <chao.xie@marvell.com>
|
||||
*
|
||||
* This file is licensed under the terms of the GNU General Public
|
||||
* License version 2. This program is licensed "as is" without any
|
||||
* warranty of any kind, whether express or implied.
|
||||
*/
|
||||
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/err.h>
|
||||
|
||||
#include "clk.h"
|
||||
|
||||
/*
|
||||
* The mix clock is a clock combined mux and div type clock.
|
||||
* Because the div field and mux field need to be set at same
|
||||
* time, we can not divide it into 2 types of clock
|
||||
*/
|
||||
|
||||
#define to_clk_mix(hw) container_of(hw, struct mmp_clk_mix, hw)
|
||||
|
||||
static unsigned int _get_maxdiv(struct mmp_clk_mix *mix)
|
||||
{
|
||||
unsigned int div_mask = (1 << mix->reg_info.width_div) - 1;
|
||||
unsigned int maxdiv = 0;
|
||||
struct clk_div_table *clkt;
|
||||
|
||||
if (mix->div_flags & CLK_DIVIDER_ONE_BASED)
|
||||
return div_mask;
|
||||
if (mix->div_flags & CLK_DIVIDER_POWER_OF_TWO)
|
||||
return 1 << div_mask;
|
||||
if (mix->div_table) {
|
||||
for (clkt = mix->div_table; clkt->div; clkt++)
|
||||
if (clkt->div > maxdiv)
|
||||
maxdiv = clkt->div;
|
||||
return maxdiv;
|
||||
}
|
||||
return div_mask + 1;
|
||||
}
|
||||
|
||||
static unsigned int _get_div(struct mmp_clk_mix *mix, unsigned int val)
|
||||
{
|
||||
struct clk_div_table *clkt;
|
||||
|
||||
if (mix->div_flags & CLK_DIVIDER_ONE_BASED)
|
||||
return val;
|
||||
if (mix->div_flags & CLK_DIVIDER_POWER_OF_TWO)
|
||||
return 1 << val;
|
||||
if (mix->div_table) {
|
||||
for (clkt = mix->div_table; clkt->div; clkt++)
|
||||
if (clkt->val == val)
|
||||
return clkt->div;
|
||||
if (clkt->div == 0)
|
||||
return 0;
|
||||
}
|
||||
return val + 1;
|
||||
}
|
||||
|
||||
static unsigned int _get_mux(struct mmp_clk_mix *mix, unsigned int val)
|
||||
{
|
||||
int num_parents = __clk_get_num_parents(mix->hw.clk);
|
||||
int i;
|
||||
|
||||
if (mix->mux_flags & CLK_MUX_INDEX_BIT)
|
||||
return ffs(val) - 1;
|
||||
if (mix->mux_flags & CLK_MUX_INDEX_ONE)
|
||||
return val - 1;
|
||||
if (mix->mux_table) {
|
||||
for (i = 0; i < num_parents; i++)
|
||||
if (mix->mux_table[i] == val)
|
||||
return i;
|
||||
if (i == num_parents)
|
||||
return 0;
|
||||
}
|
||||
|
||||
return val;
|
||||
}
|
||||
static unsigned int _get_div_val(struct mmp_clk_mix *mix, unsigned int div)
|
||||
{
|
||||
struct clk_div_table *clkt;
|
||||
|
||||
if (mix->div_flags & CLK_DIVIDER_ONE_BASED)
|
||||
return div;
|
||||
if (mix->div_flags & CLK_DIVIDER_POWER_OF_TWO)
|
||||
return __ffs(div);
|
||||
if (mix->div_table) {
|
||||
for (clkt = mix->div_table; clkt->div; clkt++)
|
||||
if (clkt->div == div)
|
||||
return clkt->val;
|
||||
if (clkt->div == 0)
|
||||
return 0;
|
||||
}
|
||||
|
||||
return div - 1;
|
||||
}
|
||||
|
||||
static unsigned int _get_mux_val(struct mmp_clk_mix *mix, unsigned int mux)
|
||||
{
|
||||
if (mix->mux_table)
|
||||
return mix->mux_table[mux];
|
||||
|
||||
return mux;
|
||||
}
|
||||
|
||||
static void _filter_clk_table(struct mmp_clk_mix *mix,
|
||||
struct mmp_clk_mix_clk_table *table,
|
||||
unsigned int table_size)
|
||||
{
|
||||
int i;
|
||||
struct mmp_clk_mix_clk_table *item;
|
||||
struct clk *parent, *clk;
|
||||
unsigned long parent_rate;
|
||||
|
||||
clk = mix->hw.clk;
|
||||
|
||||
for (i = 0; i < table_size; i++) {
|
||||
item = &table[i];
|
||||
parent = clk_get_parent_by_index(clk, item->parent_index);
|
||||
parent_rate = __clk_get_rate(parent);
|
||||
if (parent_rate % item->rate) {
|
||||
item->valid = 0;
|
||||
} else {
|
||||
item->divisor = parent_rate / item->rate;
|
||||
item->valid = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int _set_rate(struct mmp_clk_mix *mix, u32 mux_val, u32 div_val,
|
||||
unsigned int change_mux, unsigned int change_div)
|
||||
{
|
||||
struct mmp_clk_mix_reg_info *ri = &mix->reg_info;
|
||||
u8 width, shift;
|
||||
u32 mux_div, fc_req;
|
||||
int ret, timeout = 50;
|
||||
unsigned long flags = 0;
|
||||
|
||||
if (!change_mux && !change_div)
|
||||
return -EINVAL;
|
||||
|
||||
if (mix->lock)
|
||||
spin_lock_irqsave(mix->lock, flags);
|
||||
|
||||
if (mix->type == MMP_CLK_MIX_TYPE_V1
|
||||
|| mix->type == MMP_CLK_MIX_TYPE_V2)
|
||||
mux_div = readl(ri->reg_clk_ctrl);
|
||||
else
|
||||
mux_div = readl(ri->reg_clk_sel);
|
||||
|
||||
if (change_div) {
|
||||
width = ri->width_div;
|
||||
shift = ri->shift_div;
|
||||
mux_div &= ~MMP_CLK_BITS_MASK(width, shift);
|
||||
mux_div |= MMP_CLK_BITS_SET_VAL(div_val, width, shift);
|
||||
}
|
||||
|
||||
if (change_mux) {
|
||||
width = ri->width_mux;
|
||||
shift = ri->shift_mux;
|
||||
mux_div &= ~MMP_CLK_BITS_MASK(width, shift);
|
||||
mux_div |= MMP_CLK_BITS_SET_VAL(mux_val, width, shift);
|
||||
}
|
||||
|
||||
if (mix->type == MMP_CLK_MIX_TYPE_V1) {
|
||||
writel(mux_div, ri->reg_clk_ctrl);
|
||||
} else if (mix->type == MMP_CLK_MIX_TYPE_V2) {
|
||||
mux_div |= (1 << ri->bit_fc);
|
||||
writel(mux_div, ri->reg_clk_ctrl);
|
||||
|
||||
do {
|
||||
fc_req = readl(ri->reg_clk_ctrl);
|
||||
timeout--;
|
||||
if (!(fc_req & (1 << ri->bit_fc)))
|
||||
break;
|
||||
} while (timeout);
|
||||
|
||||
if (timeout == 0) {
|
||||
pr_err("%s:%s cannot do frequency change\n",
|
||||
__func__, __clk_get_name(mix->hw.clk));
|
||||
ret = -EBUSY;
|
||||
goto error;
|
||||
}
|
||||
} else {
|
||||
fc_req = readl(ri->reg_clk_ctrl);
|
||||
fc_req |= 1 << ri->bit_fc;
|
||||
writel(fc_req, ri->reg_clk_ctrl);
|
||||
writel(mux_div, ri->reg_clk_sel);
|
||||
fc_req &= ~(1 << ri->bit_fc);
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
error:
|
||||
if (mix->lock)
|
||||
spin_unlock_irqrestore(mix->lock, flags);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static long mmp_clk_mix_determine_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long *best_parent_rate,
|
||||
struct clk **best_parent_clk)
|
||||
{
|
||||
struct mmp_clk_mix *mix = to_clk_mix(hw);
|
||||
struct mmp_clk_mix_clk_table *item;
|
||||
struct clk *parent, *parent_best, *mix_clk;
|
||||
unsigned long parent_rate, mix_rate, mix_rate_best, parent_rate_best;
|
||||
unsigned long gap, gap_best;
|
||||
u32 div_val_max;
|
||||
unsigned int div;
|
||||
int i, j;
|
||||
|
||||
mix_clk = hw->clk;
|
||||
|
||||
parent = NULL;
|
||||
mix_rate_best = 0;
|
||||
parent_rate_best = 0;
|
||||
gap_best = rate;
|
||||
parent_best = NULL;
|
||||
|
||||
if (mix->table) {
|
||||
for (i = 0; i < mix->table_size; i++) {
|
||||
item = &mix->table[i];
|
||||
if (item->valid == 0)
|
||||
continue;
|
||||
parent = clk_get_parent_by_index(mix_clk,
|
||||
item->parent_index);
|
||||
parent_rate = __clk_get_rate(parent);
|
||||
mix_rate = parent_rate / item->divisor;
|
||||
gap = abs(mix_rate - rate);
|
||||
if (parent_best == NULL || gap < gap_best) {
|
||||
parent_best = parent;
|
||||
parent_rate_best = parent_rate;
|
||||
mix_rate_best = mix_rate;
|
||||
gap_best = gap;
|
||||
if (gap_best == 0)
|
||||
goto found;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (i = 0; i < __clk_get_num_parents(mix_clk); i++) {
|
||||
parent = clk_get_parent_by_index(mix_clk, i);
|
||||
parent_rate = __clk_get_rate(parent);
|
||||
div_val_max = _get_maxdiv(mix);
|
||||
for (j = 0; j < div_val_max; j++) {
|
||||
div = _get_div(mix, j);
|
||||
mix_rate = parent_rate / div;
|
||||
gap = abs(mix_rate - rate);
|
||||
if (parent_best == NULL || gap < gap_best) {
|
||||
parent_best = parent;
|
||||
parent_rate_best = parent_rate;
|
||||
mix_rate_best = mix_rate;
|
||||
gap_best = gap;
|
||||
if (gap_best == 0)
|
||||
goto found;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
found:
|
||||
*best_parent_rate = parent_rate_best;
|
||||
*best_parent_clk = parent_best;
|
||||
|
||||
return mix_rate_best;
|
||||
}
|
||||
|
||||
static int mmp_clk_mix_set_rate_and_parent(struct clk_hw *hw,
|
||||
unsigned long rate,
|
||||
unsigned long parent_rate,
|
||||
u8 index)
|
||||
{
|
||||
struct mmp_clk_mix *mix = to_clk_mix(hw);
|
||||
unsigned int div;
|
||||
u32 div_val, mux_val;
|
||||
|
||||
div = parent_rate / rate;
|
||||
div_val = _get_div_val(mix, div);
|
||||
mux_val = _get_mux_val(mix, index);
|
||||
|
||||
return _set_rate(mix, mux_val, div_val, 1, 1);
|
||||
}
|
||||
|
||||
static u8 mmp_clk_mix_get_parent(struct clk_hw *hw)
|
||||
{
|
||||
struct mmp_clk_mix *mix = to_clk_mix(hw);
|
||||
struct mmp_clk_mix_reg_info *ri = &mix->reg_info;
|
||||
unsigned long flags = 0;
|
||||
u32 mux_div = 0;
|
||||
u8 width, shift;
|
||||
u32 mux_val;
|
||||
|
||||
if (mix->lock)
|
||||
spin_lock_irqsave(mix->lock, flags);
|
||||
|
||||
if (mix->type == MMP_CLK_MIX_TYPE_V1
|
||||
|| mix->type == MMP_CLK_MIX_TYPE_V2)
|
||||
mux_div = readl(ri->reg_clk_ctrl);
|
||||
else
|
||||
mux_div = readl(ri->reg_clk_sel);
|
||||
|
||||
if (mix->lock)
|
||||
spin_unlock_irqrestore(mix->lock, flags);
|
||||
|
||||
width = mix->reg_info.width_mux;
|
||||
shift = mix->reg_info.shift_mux;
|
||||
|
||||
mux_val = MMP_CLK_BITS_GET_VAL(mux_div, width, shift);
|
||||
|
||||
return _get_mux(mix, mux_val);
|
||||
}
|
||||
|
||||
static unsigned long mmp_clk_mix_recalc_rate(struct clk_hw *hw,
|
||||
unsigned long parent_rate)
|
||||
{
|
||||
struct mmp_clk_mix *mix = to_clk_mix(hw);
|
||||
struct mmp_clk_mix_reg_info *ri = &mix->reg_info;
|
||||
unsigned long flags = 0;
|
||||
u32 mux_div = 0;
|
||||
u8 width, shift;
|
||||
unsigned int div;
|
||||
|
||||
if (mix->lock)
|
||||
spin_lock_irqsave(mix->lock, flags);
|
||||
|
||||
if (mix->type == MMP_CLK_MIX_TYPE_V1
|
||||
|| mix->type == MMP_CLK_MIX_TYPE_V2)
|
||||
mux_div = readl(ri->reg_clk_ctrl);
|
||||
else
|
||||
mux_div = readl(ri->reg_clk_sel);
|
||||
|
||||
if (mix->lock)
|
||||
spin_unlock_irqrestore(mix->lock, flags);
|
||||
|
||||
width = mix->reg_info.width_div;
|
||||
shift = mix->reg_info.shift_div;
|
||||
|
||||
div = _get_div(mix, MMP_CLK_BITS_GET_VAL(mux_div, width, shift));
|
||||
|
||||
return parent_rate / div;
|
||||
}
|
||||
|
||||
static int mmp_clk_set_parent(struct clk_hw *hw, u8 index)
|
||||
{
|
||||
struct mmp_clk_mix *mix = to_clk_mix(hw);
|
||||
struct mmp_clk_mix_clk_table *item;
|
||||
int i;
|
||||
u32 div_val, mux_val;
|
||||
|
||||
if (mix->table) {
|
||||
for (i = 0; i < mix->table_size; i++) {
|
||||
item = &mix->table[i];
|
||||
if (item->valid == 0)
|
||||
continue;
|
||||
if (item->parent_index == index)
|
||||
break;
|
||||
}
|
||||
if (i < mix->table_size) {
|
||||
div_val = _get_div_val(mix, item->divisor);
|
||||
mux_val = _get_mux_val(mix, item->parent_index);
|
||||
} else
|
||||
return -EINVAL;
|
||||
} else {
|
||||
mux_val = _get_mux_val(mix, index);
|
||||
div_val = 0;
|
||||
}
|
||||
|
||||
return _set_rate(mix, mux_val, div_val, 1, div_val ? 1 : 0);
|
||||
}
|
||||
|
||||
static int mmp_clk_set_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long best_parent_rate)
|
||||
{
|
||||
struct mmp_clk_mix *mix = to_clk_mix(hw);
|
||||
struct mmp_clk_mix_clk_table *item;
|
||||
unsigned long parent_rate;
|
||||
unsigned int best_divisor;
|
||||
struct clk *mix_clk, *parent;
|
||||
int i;
|
||||
|
||||
best_divisor = best_parent_rate / rate;
|
||||
|
||||
mix_clk = hw->clk;
|
||||
if (mix->table) {
|
||||
for (i = 0; i < mix->table_size; i++) {
|
||||
item = &mix->table[i];
|
||||
if (item->valid == 0)
|
||||
continue;
|
||||
parent = clk_get_parent_by_index(mix_clk,
|
||||
item->parent_index);
|
||||
parent_rate = __clk_get_rate(parent);
|
||||
if (parent_rate == best_parent_rate
|
||||
&& item->divisor == best_divisor)
|
||||
break;
|
||||
}
|
||||
if (i < mix->table_size)
|
||||
return _set_rate(mix,
|
||||
_get_mux_val(mix, item->parent_index),
|
||||
_get_div_val(mix, item->divisor),
|
||||
1, 1);
|
||||
else
|
||||
return -EINVAL;
|
||||
} else {
|
||||
for (i = 0; i < __clk_get_num_parents(mix_clk); i++) {
|
||||
parent = clk_get_parent_by_index(mix_clk, i);
|
||||
parent_rate = __clk_get_rate(parent);
|
||||
if (parent_rate == best_parent_rate)
|
||||
break;
|
||||
}
|
||||
if (i < __clk_get_num_parents(mix_clk))
|
||||
return _set_rate(mix, _get_mux_val(mix, i),
|
||||
_get_div_val(mix, best_divisor), 1, 1);
|
||||
else
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
static void mmp_clk_mix_init(struct clk_hw *hw)
|
||||
{
|
||||
struct mmp_clk_mix *mix = to_clk_mix(hw);
|
||||
|
||||
if (mix->table)
|
||||
_filter_clk_table(mix, mix->table, mix->table_size);
|
||||
}
|
||||
|
||||
const struct clk_ops mmp_clk_mix_ops = {
|
||||
.determine_rate = mmp_clk_mix_determine_rate,
|
||||
.set_rate_and_parent = mmp_clk_mix_set_rate_and_parent,
|
||||
.set_rate = mmp_clk_set_rate,
|
||||
.set_parent = mmp_clk_set_parent,
|
||||
.get_parent = mmp_clk_mix_get_parent,
|
||||
.recalc_rate = mmp_clk_mix_recalc_rate,
|
||||
.init = mmp_clk_mix_init,
|
||||
};
|
||||
|
||||
struct clk *mmp_clk_register_mix(struct device *dev,
|
||||
const char *name,
|
||||
const char **parent_names,
|
||||
u8 num_parents,
|
||||
unsigned long flags,
|
||||
struct mmp_clk_mix_config *config,
|
||||
spinlock_t *lock)
|
||||
{
|
||||
struct mmp_clk_mix *mix;
|
||||
struct clk *clk;
|
||||
struct clk_init_data init;
|
||||
size_t table_bytes;
|
||||
|
||||
mix = kzalloc(sizeof(*mix), GFP_KERNEL);
|
||||
if (!mix) {
|
||||
pr_err("%s:%s: could not allocate mmp mix clk\n",
|
||||
__func__, name);
|
||||
return ERR_PTR(-ENOMEM);
|
||||
}
|
||||
|
||||
init.name = name;
|
||||
init.flags = flags | CLK_GET_RATE_NOCACHE;
|
||||
init.parent_names = parent_names;
|
||||
init.num_parents = num_parents;
|
||||
init.ops = &mmp_clk_mix_ops;
|
||||
|
||||
memcpy(&mix->reg_info, &config->reg_info, sizeof(config->reg_info));
|
||||
if (config->table) {
|
||||
table_bytes = sizeof(*config->table) * config->table_size;
|
||||
mix->table = kzalloc(table_bytes, GFP_KERNEL);
|
||||
if (!mix->table) {
|
||||
pr_err("%s:%s: could not allocate mmp mix table\n",
|
||||
__func__, name);
|
||||
kfree(mix);
|
||||
return ERR_PTR(-ENOMEM);
|
||||
}
|
||||
memcpy(mix->table, config->table, table_bytes);
|
||||
mix->table_size = config->table_size;
|
||||
}
|
||||
|
||||
if (config->mux_table) {
|
||||
table_bytes = sizeof(u32) * num_parents;
|
||||
mix->mux_table = kzalloc(table_bytes, GFP_KERNEL);
|
||||
if (!mix->mux_table) {
|
||||
pr_err("%s:%s: could not allocate mmp mix mux-table\n",
|
||||
__func__, name);
|
||||
kfree(mix->table);
|
||||
kfree(mix);
|
||||
return ERR_PTR(-ENOMEM);
|
||||
}
|
||||
memcpy(mix->mux_table, config->mux_table, table_bytes);
|
||||
}
|
||||
|
||||
mix->div_flags = config->div_flags;
|
||||
mix->mux_flags = config->mux_flags;
|
||||
mix->lock = lock;
|
||||
mix->hw.init = &init;
|
||||
|
||||
if (config->reg_info.bit_fc >= 32)
|
||||
mix->type = MMP_CLK_MIX_TYPE_V1;
|
||||
else if (config->reg_info.reg_clk_sel)
|
||||
mix->type = MMP_CLK_MIX_TYPE_V3;
|
||||
else
|
||||
mix->type = MMP_CLK_MIX_TYPE_V2;
|
||||
clk = clk_register(dev, &mix->hw);
|
||||
|
||||
if (IS_ERR(clk)) {
|
||||
kfree(mix->mux_table);
|
||||
kfree(mix->table);
|
||||
kfree(mix);
|
||||
}
|
||||
|
||||
return clk;
|
||||
}
|
@ -54,7 +54,7 @@
|
||||
|
||||
static DEFINE_SPINLOCK(clk_lock);
|
||||
|
||||
static struct clk_factor_masks uart_factor_masks = {
|
||||
static struct mmp_clk_factor_masks uart_factor_masks = {
|
||||
.factor = 2,
|
||||
.num_mask = 0x1fff,
|
||||
.den_mask = 0x1fff,
|
||||
@ -62,7 +62,7 @@ static struct clk_factor_masks uart_factor_masks = {
|
||||
.den_shift = 0,
|
||||
};
|
||||
|
||||
static struct clk_factor_tbl uart_factor_tbl[] = {
|
||||
static struct mmp_clk_factor_tbl uart_factor_tbl[] = {
|
||||
{.num = 14634, .den = 2165}, /*14.745MHZ */
|
||||
{.num = 3521, .den = 689}, /*19.23MHZ */
|
||||
{.num = 9679, .den = 5728}, /*58.9824MHZ */
|
||||
@ -191,7 +191,7 @@ void __init mmp2_clk_init(void)
|
||||
clk = mmp_clk_register_factor("uart_pll", "pll1_4", 0,
|
||||
mpmu_base + MPMU_UART_PLL,
|
||||
&uart_factor_masks, uart_factor_tbl,
|
||||
ARRAY_SIZE(uart_factor_tbl));
|
||||
ARRAY_SIZE(uart_factor_tbl), &clk_lock);
|
||||
clk_set_rate(clk, 14745600);
|
||||
clk_register_clkdev(clk, "uart_pll", NULL);
|
||||
|
||||
|
334
drivers/clk/mmp/clk-of-mmp2.c
Normal file
334
drivers/clk/mmp/clk-of-mmp2.c
Normal file
@ -0,0 +1,334 @@
|
||||
/*
|
||||
* mmp2 clock framework source file
|
||||
*
|
||||
* Copyright (C) 2012 Marvell
|
||||
* Chao Xie <xiechao.mail@gmail.com>
|
||||
*
|
||||
* This file is licensed under the terms of the GNU General Public
|
||||
* License version 2. This program is licensed "as is" without any
|
||||
* warranty of any kind, whether express or implied.
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/of_address.h>
|
||||
|
||||
#include <dt-bindings/clock/marvell,mmp2.h>
|
||||
|
||||
#include "clk.h"
|
||||
#include "reset.h"
|
||||
|
||||
#define APBC_RTC 0x0
|
||||
#define APBC_TWSI0 0x4
|
||||
#define APBC_TWSI1 0x8
|
||||
#define APBC_TWSI2 0xc
|
||||
#define APBC_TWSI3 0x10
|
||||
#define APBC_TWSI4 0x7c
|
||||
#define APBC_TWSI5 0x80
|
||||
#define APBC_KPC 0x18
|
||||
#define APBC_UART0 0x2c
|
||||
#define APBC_UART1 0x30
|
||||
#define APBC_UART2 0x34
|
||||
#define APBC_UART3 0x88
|
||||
#define APBC_GPIO 0x38
|
||||
#define APBC_PWM0 0x3c
|
||||
#define APBC_PWM1 0x40
|
||||
#define APBC_PWM2 0x44
|
||||
#define APBC_PWM3 0x48
|
||||
#define APBC_SSP0 0x50
|
||||
#define APBC_SSP1 0x54
|
||||
#define APBC_SSP2 0x58
|
||||
#define APBC_SSP3 0x5c
|
||||
#define APMU_SDH0 0x54
|
||||
#define APMU_SDH1 0x58
|
||||
#define APMU_SDH2 0xe8
|
||||
#define APMU_SDH3 0xec
|
||||
#define APMU_USB 0x5c
|
||||
#define APMU_DISP0 0x4c
|
||||
#define APMU_DISP1 0x110
|
||||
#define APMU_CCIC0 0x50
|
||||
#define APMU_CCIC1 0xf4
|
||||
#define MPMU_UART_PLL 0x14
|
||||
|
||||
struct mmp2_clk_unit {
|
||||
struct mmp_clk_unit unit;
|
||||
void __iomem *mpmu_base;
|
||||
void __iomem *apmu_base;
|
||||
void __iomem *apbc_base;
|
||||
};
|
||||
|
||||
static struct mmp_param_fixed_rate_clk fixed_rate_clks[] = {
|
||||
{MMP2_CLK_CLK32, "clk32", NULL, CLK_IS_ROOT, 32768},
|
||||
{MMP2_CLK_VCTCXO, "vctcxo", NULL, CLK_IS_ROOT, 26000000},
|
||||
{MMP2_CLK_PLL1, "pll1", NULL, CLK_IS_ROOT, 800000000},
|
||||
{MMP2_CLK_PLL2, "pll2", NULL, CLK_IS_ROOT, 960000000},
|
||||
{MMP2_CLK_USB_PLL, "usb_pll", NULL, CLK_IS_ROOT, 480000000},
|
||||
};
|
||||
|
||||
static struct mmp_param_fixed_factor_clk fixed_factor_clks[] = {
|
||||
{MMP2_CLK_PLL1_2, "pll1_2", "pll1", 1, 2, 0},
|
||||
{MMP2_CLK_PLL1_4, "pll1_4", "pll1_2", 1, 2, 0},
|
||||
{MMP2_CLK_PLL1_8, "pll1_8", "pll1_4", 1, 2, 0},
|
||||
{MMP2_CLK_PLL1_16, "pll1_16", "pll1_8", 1, 2, 0},
|
||||
{MMP2_CLK_PLL1_20, "pll1_20", "pll1_4", 1, 5, 0},
|
||||
{MMP2_CLK_PLL1_3, "pll1_3", "pll1", 1, 3, 0},
|
||||
{MMP2_CLK_PLL1_6, "pll1_6", "pll1_3", 1, 2, 0},
|
||||
{MMP2_CLK_PLL1_12, "pll1_12", "pll1_6", 1, 2, 0},
|
||||
{MMP2_CLK_PLL2_2, "pll2_2", "pll2", 1, 2, 0},
|
||||
{MMP2_CLK_PLL2_4, "pll2_4", "pll2_2", 1, 2, 0},
|
||||
{MMP2_CLK_PLL2_8, "pll2_8", "pll2_4", 1, 2, 0},
|
||||
{MMP2_CLK_PLL2_16, "pll2_16", "pll2_8", 1, 2, 0},
|
||||
{MMP2_CLK_PLL2_3, "pll2_3", "pll2", 1, 3, 0},
|
||||
{MMP2_CLK_PLL2_6, "pll2_6", "pll2_3", 1, 2, 0},
|
||||
{MMP2_CLK_PLL2_12, "pll2_12", "pll2_6", 1, 2, 0},
|
||||
{MMP2_CLK_VCTCXO_2, "vctcxo_2", "vctcxo", 1, 2, 0},
|
||||
{MMP2_CLK_VCTCXO_4, "vctcxo_4", "vctcxo_2", 1, 2, 0},
|
||||
};
|
||||
|
||||
static struct mmp_clk_factor_masks uart_factor_masks = {
|
||||
.factor = 2,
|
||||
.num_mask = 0x1fff,
|
||||
.den_mask = 0x1fff,
|
||||
.num_shift = 16,
|
||||
.den_shift = 0,
|
||||
};
|
||||
|
||||
static struct mmp_clk_factor_tbl uart_factor_tbl[] = {
|
||||
{.num = 14634, .den = 2165}, /*14.745MHZ */
|
||||
{.num = 3521, .den = 689}, /*19.23MHZ */
|
||||
{.num = 9679, .den = 5728}, /*58.9824MHZ */
|
||||
{.num = 15850, .den = 9451}, /*59.429MHZ */
|
||||
};
|
||||
|
||||
static void mmp2_pll_init(struct mmp2_clk_unit *pxa_unit)
|
||||
{
|
||||
struct clk *clk;
|
||||
struct mmp_clk_unit *unit = &pxa_unit->unit;
|
||||
|
||||
mmp_register_fixed_rate_clks(unit, fixed_rate_clks,
|
||||
ARRAY_SIZE(fixed_rate_clks));
|
||||
|
||||
mmp_register_fixed_factor_clks(unit, fixed_factor_clks,
|
||||
ARRAY_SIZE(fixed_factor_clks));
|
||||
|
||||
clk = mmp_clk_register_factor("uart_pll", "pll1_4",
|
||||
CLK_SET_RATE_PARENT,
|
||||
pxa_unit->mpmu_base + MPMU_UART_PLL,
|
||||
&uart_factor_masks, uart_factor_tbl,
|
||||
ARRAY_SIZE(uart_factor_tbl), NULL);
|
||||
mmp_clk_add(unit, MMP2_CLK_UART_PLL, clk);
|
||||
}
|
||||
|
||||
static DEFINE_SPINLOCK(uart0_lock);
|
||||
static DEFINE_SPINLOCK(uart1_lock);
|
||||
static DEFINE_SPINLOCK(uart2_lock);
|
||||
static const char *uart_parent_names[] = {"uart_pll", "vctcxo"};
|
||||
|
||||
static DEFINE_SPINLOCK(ssp0_lock);
|
||||
static DEFINE_SPINLOCK(ssp1_lock);
|
||||
static DEFINE_SPINLOCK(ssp2_lock);
|
||||
static DEFINE_SPINLOCK(ssp3_lock);
|
||||
static const char *ssp_parent_names[] = {"vctcxo_4", "vctcxo_2", "vctcxo", "pll1_16"};
|
||||
|
||||
static DEFINE_SPINLOCK(reset_lock);
|
||||
|
||||
static struct mmp_param_mux_clk apbc_mux_clks[] = {
|
||||
{0, "uart0_mux", uart_parent_names, ARRAY_SIZE(uart_parent_names), CLK_SET_RATE_PARENT, APBC_UART0, 4, 3, 0, &uart0_lock},
|
||||
{0, "uart1_mux", uart_parent_names, ARRAY_SIZE(uart_parent_names), CLK_SET_RATE_PARENT, APBC_UART1, 4, 3, 0, &uart1_lock},
|
||||
{0, "uart2_mux", uart_parent_names, ARRAY_SIZE(uart_parent_names), CLK_SET_RATE_PARENT, APBC_UART2, 4, 3, 0, &uart2_lock},
|
||||
{0, "uart3_mux", uart_parent_names, ARRAY_SIZE(uart_parent_names), CLK_SET_RATE_PARENT, APBC_UART3, 4, 3, 0, &uart2_lock},
|
||||
{0, "ssp0_mux", ssp_parent_names, ARRAY_SIZE(ssp_parent_names), CLK_SET_RATE_PARENT, APBC_SSP0, 4, 3, 0, &ssp0_lock},
|
||||
{0, "ssp1_mux", ssp_parent_names, ARRAY_SIZE(ssp_parent_names), CLK_SET_RATE_PARENT, APBC_SSP1, 4, 3, 0, &ssp1_lock},
|
||||
{0, "ssp2_mux", ssp_parent_names, ARRAY_SIZE(ssp_parent_names), CLK_SET_RATE_PARENT, APBC_SSP2, 4, 3, 0, &ssp2_lock},
|
||||
{0, "ssp3_mux", ssp_parent_names, ARRAY_SIZE(ssp_parent_names), CLK_SET_RATE_PARENT, APBC_SSP3, 4, 3, 0, &ssp3_lock},
|
||||
};
|
||||
|
||||
static struct mmp_param_gate_clk apbc_gate_clks[] = {
|
||||
{MMP2_CLK_TWSI0, "twsi0_clk", "vctcxo", CLK_SET_RATE_PARENT, APBC_TWSI0, 0x7, 0x3, 0x0, 0, &reset_lock},
|
||||
{MMP2_CLK_TWSI1, "twsi1_clk", "vctcxo", CLK_SET_RATE_PARENT, APBC_TWSI1, 0x7, 0x3, 0x0, 0, &reset_lock},
|
||||
{MMP2_CLK_TWSI2, "twsi2_clk", "vctcxo", CLK_SET_RATE_PARENT, APBC_TWSI2, 0x7, 0x3, 0x0, 0, &reset_lock},
|
||||
{MMP2_CLK_TWSI3, "twsi3_clk", "vctcxo", CLK_SET_RATE_PARENT, APBC_TWSI3, 0x7, 0x3, 0x0, 0, &reset_lock},
|
||||
{MMP2_CLK_TWSI4, "twsi4_clk", "vctcxo", CLK_SET_RATE_PARENT, APBC_TWSI4, 0x7, 0x3, 0x0, 0, &reset_lock},
|
||||
{MMP2_CLK_TWSI5, "twsi5_clk", "vctcxo", CLK_SET_RATE_PARENT, APBC_TWSI5, 0x7, 0x3, 0x0, 0, &reset_lock},
|
||||
{MMP2_CLK_GPIO, "gpio_clk", "vctcxo", CLK_SET_RATE_PARENT, APBC_GPIO, 0x7, 0x3, 0x0, 0, &reset_lock},
|
||||
{MMP2_CLK_KPC, "kpc_clk", "clk32", CLK_SET_RATE_PARENT, APBC_KPC, 0x7, 0x3, 0x0, MMP_CLK_GATE_NEED_DELAY, &reset_lock},
|
||||
{MMP2_CLK_RTC, "rtc_clk", "clk32", CLK_SET_RATE_PARENT, APBC_RTC, 0x87, 0x83, 0x0, MMP_CLK_GATE_NEED_DELAY, &reset_lock},
|
||||
{MMP2_CLK_PWM0, "pwm0_clk", "pll1_48", CLK_SET_RATE_PARENT, APBC_PWM0, 0x7, 0x3, 0x0, 0, &reset_lock},
|
||||
{MMP2_CLK_PWM1, "pwm1_clk", "pll1_48", CLK_SET_RATE_PARENT, APBC_PWM1, 0x7, 0x3, 0x0, 0, &reset_lock},
|
||||
{MMP2_CLK_PWM2, "pwm2_clk", "pll1_48", CLK_SET_RATE_PARENT, APBC_PWM2, 0x7, 0x3, 0x0, 0, &reset_lock},
|
||||
{MMP2_CLK_PWM3, "pwm3_clk", "pll1_48", CLK_SET_RATE_PARENT, APBC_PWM3, 0x7, 0x3, 0x0, 0, &reset_lock},
|
||||
/* The gate clocks has mux parent. */
|
||||
{MMP2_CLK_UART0, "uart0_clk", "uart0_mux", CLK_SET_RATE_PARENT, APBC_UART0, 0x7, 0x3, 0x0, 0, &uart0_lock},
|
||||
{MMP2_CLK_UART1, "uart1_clk", "uart1_mux", CLK_SET_RATE_PARENT, APBC_UART1, 0x7, 0x3, 0x0, 0, &uart1_lock},
|
||||
{MMP2_CLK_UART2, "uart2_clk", "uart2_mux", CLK_SET_RATE_PARENT, APBC_UART2, 0x7, 0x3, 0x0, 0, &uart2_lock},
|
||||
{MMP2_CLK_UART3, "uart3_clk", "uart3_mux", CLK_SET_RATE_PARENT, APBC_UART3, 0x7, 0x3, 0x0, 0, &uart2_lock},
|
||||
{MMP2_CLK_SSP0, "ssp0_clk", "ssp0_mux", CLK_SET_RATE_PARENT, APBC_SSP0, 0x7, 0x3, 0x0, 0, &ssp0_lock},
|
||||
{MMP2_CLK_SSP1, "ssp1_clk", "ssp1_mux", CLK_SET_RATE_PARENT, APBC_SSP1, 0x7, 0x3, 0x0, 0, &ssp1_lock},
|
||||
{MMP2_CLK_SSP2, "ssp2_clk", "ssp2_mux", CLK_SET_RATE_PARENT, APBC_SSP2, 0x7, 0x3, 0x0, 0, &ssp2_lock},
|
||||
{MMP2_CLK_SSP3, "ssp3_clk", "ssp3_mux", CLK_SET_RATE_PARENT, APBC_SSP3, 0x7, 0x3, 0x0, 0, &ssp3_lock},
|
||||
};
|
||||
|
||||
static void mmp2_apb_periph_clk_init(struct mmp2_clk_unit *pxa_unit)
|
||||
{
|
||||
struct mmp_clk_unit *unit = &pxa_unit->unit;
|
||||
|
||||
mmp_register_mux_clks(unit, apbc_mux_clks, pxa_unit->apbc_base,
|
||||
ARRAY_SIZE(apbc_mux_clks));
|
||||
|
||||
mmp_register_gate_clks(unit, apbc_gate_clks, pxa_unit->apbc_base,
|
||||
ARRAY_SIZE(apbc_gate_clks));
|
||||
}
|
||||
|
||||
static DEFINE_SPINLOCK(sdh_lock);
|
||||
static const char *sdh_parent_names[] = {"pll1_4", "pll2", "usb_pll", "pll1"};
|
||||
static struct mmp_clk_mix_config sdh_mix_config = {
|
||||
.reg_info = DEFINE_MIX_REG_INFO(4, 10, 2, 8, 32),
|
||||
};
|
||||
|
||||
static DEFINE_SPINLOCK(usb_lock);
|
||||
|
||||
static DEFINE_SPINLOCK(disp0_lock);
|
||||
static DEFINE_SPINLOCK(disp1_lock);
|
||||
static const char *disp_parent_names[] = {"pll1", "pll1_16", "pll2", "vctcxo"};
|
||||
|
||||
static DEFINE_SPINLOCK(ccic0_lock);
|
||||
static DEFINE_SPINLOCK(ccic1_lock);
|
||||
static const char *ccic_parent_names[] = {"pll1_2", "pll1_16", "vctcxo"};
|
||||
static struct mmp_clk_mix_config ccic0_mix_config = {
|
||||
.reg_info = DEFINE_MIX_REG_INFO(4, 17, 2, 6, 32),
|
||||
};
|
||||
static struct mmp_clk_mix_config ccic1_mix_config = {
|
||||
.reg_info = DEFINE_MIX_REG_INFO(4, 16, 2, 6, 32),
|
||||
};
|
||||
|
||||
static struct mmp_param_mux_clk apmu_mux_clks[] = {
|
||||
{MMP2_CLK_DISP0_MUX, "disp0_mux", disp_parent_names, ARRAY_SIZE(disp_parent_names), CLK_SET_RATE_PARENT, APMU_DISP0, 6, 2, 0, &disp0_lock},
|
||||
{MMP2_CLK_DISP1_MUX, "disp1_mux", disp_parent_names, ARRAY_SIZE(disp_parent_names), CLK_SET_RATE_PARENT, APMU_DISP1, 6, 2, 0, &disp1_lock},
|
||||
};
|
||||
|
||||
static struct mmp_param_div_clk apmu_div_clks[] = {
|
||||
{0, "disp0_div", "disp0_mux", CLK_SET_RATE_PARENT, APMU_DISP0, 8, 4, 0, &disp0_lock},
|
||||
{0, "disp0_sphy_div", "disp0_mux", CLK_SET_RATE_PARENT, APMU_DISP0, 15, 5, 0, &disp0_lock},
|
||||
{0, "disp1_div", "disp1_mux", CLK_SET_RATE_PARENT, APMU_DISP1, 8, 4, 0, &disp1_lock},
|
||||
{0, "ccic0_sphy_div", "ccic0_mix_clk", CLK_SET_RATE_PARENT, APMU_CCIC0, 10, 5, 0, &ccic0_lock},
|
||||
{0, "ccic1_sphy_div", "ccic1_mix_clk", CLK_SET_RATE_PARENT, APMU_CCIC1, 10, 5, 0, &ccic1_lock},
|
||||
};
|
||||
|
||||
static struct mmp_param_gate_clk apmu_gate_clks[] = {
|
||||
{MMP2_CLK_USB, "usb_clk", "usb_pll", 0, APMU_USB, 0x9, 0x9, 0x0, 0, &usb_lock},
|
||||
/* The gate clocks has mux parent. */
|
||||
{MMP2_CLK_SDH0, "sdh0_clk", "sdh_mix_clk", CLK_SET_RATE_PARENT, APMU_SDH0, 0x1b, 0x1b, 0x0, 0, &sdh_lock},
|
||||
{MMP2_CLK_SDH1, "sdh1_clk", "sdh_mix_clk", CLK_SET_RATE_PARENT, APMU_SDH1, 0x1b, 0x1b, 0x0, 0, &sdh_lock},
|
||||
{MMP2_CLK_SDH1, "sdh2_clk", "sdh_mix_clk", CLK_SET_RATE_PARENT, APMU_SDH2, 0x1b, 0x1b, 0x0, 0, &sdh_lock},
|
||||
{MMP2_CLK_SDH1, "sdh3_clk", "sdh_mix_clk", CLK_SET_RATE_PARENT, APMU_SDH3, 0x1b, 0x1b, 0x0, 0, &sdh_lock},
|
||||
{MMP2_CLK_DISP0, "disp0_clk", "disp0_div", CLK_SET_RATE_PARENT, APMU_DISP0, 0x1b, 0x1b, 0x0, 0, &disp0_lock},
|
||||
{MMP2_CLK_DISP0_SPHY, "disp0_sphy_clk", "disp0_sphy_div", CLK_SET_RATE_PARENT, APMU_DISP0, 0x1024, 0x1024, 0x0, 0, &disp0_lock},
|
||||
{MMP2_CLK_DISP1, "disp1_clk", "disp1_div", CLK_SET_RATE_PARENT, APMU_DISP1, 0x1b, 0x1b, 0x0, 0, &disp1_lock},
|
||||
{MMP2_CLK_CCIC_ARBITER, "ccic_arbiter", "vctcxo", CLK_SET_RATE_PARENT, APMU_CCIC0, 0x1800, 0x1800, 0x0, 0, &ccic0_lock},
|
||||
{MMP2_CLK_CCIC0, "ccic0_clk", "ccic0_mix_clk", CLK_SET_RATE_PARENT, APMU_CCIC0, 0x1b, 0x1b, 0x0, 0, &ccic0_lock},
|
||||
{MMP2_CLK_CCIC0_PHY, "ccic0_phy_clk", "ccic0_mix_clk", CLK_SET_RATE_PARENT, APMU_CCIC0, 0x24, 0x24, 0x0, 0, &ccic0_lock},
|
||||
{MMP2_CLK_CCIC0_SPHY, "ccic0_sphy_clk", "ccic0_sphy_div", CLK_SET_RATE_PARENT, APMU_CCIC0, 0x300, 0x300, 0x0, 0, &ccic0_lock},
|
||||
{MMP2_CLK_CCIC1, "ccic1_clk", "ccic1_mix_clk", CLK_SET_RATE_PARENT, APMU_CCIC1, 0x1b, 0x1b, 0x0, 0, &ccic1_lock},
|
||||
{MMP2_CLK_CCIC1_PHY, "ccic1_phy_clk", "ccic1_mix_clk", CLK_SET_RATE_PARENT, APMU_CCIC1, 0x24, 0x24, 0x0, 0, &ccic1_lock},
|
||||
{MMP2_CLK_CCIC1_SPHY, "ccic1_sphy_clk", "ccic1_sphy_div", CLK_SET_RATE_PARENT, APMU_CCIC1, 0x300, 0x300, 0x0, 0, &ccic1_lock},
|
||||
};
|
||||
|
||||
static void mmp2_axi_periph_clk_init(struct mmp2_clk_unit *pxa_unit)
|
||||
{
|
||||
struct clk *clk;
|
||||
struct mmp_clk_unit *unit = &pxa_unit->unit;
|
||||
|
||||
sdh_mix_config.reg_info.reg_clk_ctrl = pxa_unit->apmu_base + APMU_SDH0;
|
||||
clk = mmp_clk_register_mix(NULL, "sdh_mix_clk", sdh_parent_names,
|
||||
ARRAY_SIZE(sdh_parent_names),
|
||||
CLK_SET_RATE_PARENT,
|
||||
&sdh_mix_config, &sdh_lock);
|
||||
|
||||
ccic0_mix_config.reg_info.reg_clk_ctrl = pxa_unit->apmu_base + APMU_CCIC0;
|
||||
clk = mmp_clk_register_mix(NULL, "ccic0_mix_clk", ccic_parent_names,
|
||||
ARRAY_SIZE(ccic_parent_names),
|
||||
CLK_SET_RATE_PARENT,
|
||||
&ccic0_mix_config, &ccic0_lock);
|
||||
mmp_clk_add(unit, MMP2_CLK_CCIC0_MIX, clk);
|
||||
|
||||
ccic1_mix_config.reg_info.reg_clk_ctrl = pxa_unit->apmu_base + APMU_CCIC1;
|
||||
clk = mmp_clk_register_mix(NULL, "ccic1_mix_clk", ccic_parent_names,
|
||||
ARRAY_SIZE(ccic_parent_names),
|
||||
CLK_SET_RATE_PARENT,
|
||||
&ccic1_mix_config, &ccic1_lock);
|
||||
mmp_clk_add(unit, MMP2_CLK_CCIC1_MIX, clk);
|
||||
|
||||
mmp_register_mux_clks(unit, apmu_mux_clks, pxa_unit->apmu_base,
|
||||
ARRAY_SIZE(apmu_mux_clks));
|
||||
|
||||
mmp_register_div_clks(unit, apmu_div_clks, pxa_unit->apmu_base,
|
||||
ARRAY_SIZE(apmu_div_clks));
|
||||
|
||||
mmp_register_gate_clks(unit, apmu_gate_clks, pxa_unit->apmu_base,
|
||||
ARRAY_SIZE(apmu_gate_clks));
|
||||
}
|
||||
|
||||
static void mmp2_clk_reset_init(struct device_node *np,
|
||||
struct mmp2_clk_unit *pxa_unit)
|
||||
{
|
||||
struct mmp_clk_reset_cell *cells;
|
||||
int i, nr_resets;
|
||||
|
||||
nr_resets = ARRAY_SIZE(apbc_gate_clks);
|
||||
cells = kcalloc(nr_resets, sizeof(*cells), GFP_KERNEL);
|
||||
if (!cells)
|
||||
return;
|
||||
|
||||
for (i = 0; i < nr_resets; i++) {
|
||||
cells[i].clk_id = apbc_gate_clks[i].id;
|
||||
cells[i].reg = pxa_unit->apbc_base + apbc_gate_clks[i].offset;
|
||||
cells[i].flags = 0;
|
||||
cells[i].lock = apbc_gate_clks[i].lock;
|
||||
cells[i].bits = 0x4;
|
||||
}
|
||||
|
||||
mmp_clk_reset_register(np, cells, nr_resets);
|
||||
}
|
||||
|
||||
static void __init mmp2_clk_init(struct device_node *np)
|
||||
{
|
||||
struct mmp2_clk_unit *pxa_unit;
|
||||
|
||||
pxa_unit = kzalloc(sizeof(*pxa_unit), GFP_KERNEL);
|
||||
if (!pxa_unit)
|
||||
return;
|
||||
|
||||
pxa_unit->mpmu_base = of_iomap(np, 0);
|
||||
if (!pxa_unit->mpmu_base) {
|
||||
pr_err("failed to map mpmu registers\n");
|
||||
return;
|
||||
}
|
||||
|
||||
pxa_unit->apmu_base = of_iomap(np, 1);
|
||||
if (!pxa_unit->mpmu_base) {
|
||||
pr_err("failed to map apmu registers\n");
|
||||
return;
|
||||
}
|
||||
|
||||
pxa_unit->apbc_base = of_iomap(np, 2);
|
||||
if (!pxa_unit->apbc_base) {
|
||||
pr_err("failed to map apbc registers\n");
|
||||
return;
|
||||
}
|
||||
|
||||
mmp_clk_init(np, &pxa_unit->unit, MMP2_NR_CLKS);
|
||||
|
||||
mmp2_pll_init(pxa_unit);
|
||||
|
||||
mmp2_apb_periph_clk_init(pxa_unit);
|
||||
|
||||
mmp2_axi_periph_clk_init(pxa_unit);
|
||||
|
||||
mmp2_clk_reset_init(np, pxa_unit);
|
||||
}
|
||||
|
||||
CLK_OF_DECLARE(mmp2_clk, "marvell,mmp2-clock", mmp2_clk_init);
|
279
drivers/clk/mmp/clk-of-pxa168.c
Normal file
279
drivers/clk/mmp/clk-of-pxa168.c
Normal file
@ -0,0 +1,279 @@
|
||||
/*
|
||||
* pxa168 clock framework source file
|
||||
*
|
||||
* Copyright (C) 2012 Marvell
|
||||
* Chao Xie <xiechao.mail@gmail.com>
|
||||
*
|
||||
* This file is licensed under the terms of the GNU General Public
|
||||
* License version 2. This program is licensed "as is" without any
|
||||
* warranty of any kind, whether express or implied.
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/of_address.h>
|
||||
|
||||
#include <dt-bindings/clock/marvell,pxa168.h>
|
||||
|
||||
#include "clk.h"
|
||||
#include "reset.h"
|
||||
|
||||
#define APBC_RTC 0x28
|
||||
#define APBC_TWSI0 0x2c
|
||||
#define APBC_KPC 0x30
|
||||
#define APBC_UART0 0x0
|
||||
#define APBC_UART1 0x4
|
||||
#define APBC_GPIO 0x8
|
||||
#define APBC_PWM0 0xc
|
||||
#define APBC_PWM1 0x10
|
||||
#define APBC_PWM2 0x14
|
||||
#define APBC_PWM3 0x18
|
||||
#define APBC_SSP0 0x81c
|
||||
#define APBC_SSP1 0x820
|
||||
#define APBC_SSP2 0x84c
|
||||
#define APBC_SSP3 0x858
|
||||
#define APBC_SSP4 0x85c
|
||||
#define APBC_TWSI1 0x6c
|
||||
#define APBC_UART2 0x70
|
||||
#define APMU_SDH0 0x54
|
||||
#define APMU_SDH1 0x58
|
||||
#define APMU_USB 0x5c
|
||||
#define APMU_DISP0 0x4c
|
||||
#define APMU_CCIC0 0x50
|
||||
#define APMU_DFC 0x60
|
||||
#define MPMU_UART_PLL 0x14
|
||||
|
||||
struct pxa168_clk_unit {
|
||||
struct mmp_clk_unit unit;
|
||||
void __iomem *mpmu_base;
|
||||
void __iomem *apmu_base;
|
||||
void __iomem *apbc_base;
|
||||
};
|
||||
|
||||
static struct mmp_param_fixed_rate_clk fixed_rate_clks[] = {
|
||||
{PXA168_CLK_CLK32, "clk32", NULL, CLK_IS_ROOT, 32768},
|
||||
{PXA168_CLK_VCTCXO, "vctcxo", NULL, CLK_IS_ROOT, 26000000},
|
||||
{PXA168_CLK_PLL1, "pll1", NULL, CLK_IS_ROOT, 624000000},
|
||||
};
|
||||
|
||||
static struct mmp_param_fixed_factor_clk fixed_factor_clks[] = {
|
||||
{PXA168_CLK_PLL1_2, "pll1_2", "pll1", 1, 2, 0},
|
||||
{PXA168_CLK_PLL1_4, "pll1_4", "pll1_2", 1, 2, 0},
|
||||
{PXA168_CLK_PLL1_8, "pll1_8", "pll1_4", 1, 2, 0},
|
||||
{PXA168_CLK_PLL1_16, "pll1_16", "pll1_8", 1, 2, 0},
|
||||
{PXA168_CLK_PLL1_6, "pll1_6", "pll1_2", 1, 3, 0},
|
||||
{PXA168_CLK_PLL1_12, "pll1_12", "pll1_6", 1, 2, 0},
|
||||
{PXA168_CLK_PLL1_24, "pll1_24", "pll1_12", 1, 2, 0},
|
||||
{PXA168_CLK_PLL1_48, "pll1_48", "pll1_24", 1, 2, 0},
|
||||
{PXA168_CLK_PLL1_96, "pll1_96", "pll1_48", 1, 2, 0},
|
||||
{PXA168_CLK_PLL1_13, "pll1_13", "pll1", 1, 13, 0},
|
||||
{PXA168_CLK_PLL1_13_1_5, "pll1_13_1_5", "pll1_13", 2, 3, 0},
|
||||
{PXA168_CLK_PLL1_2_1_5, "pll1_2_1_5", "pll1_2", 2, 3, 0},
|
||||
{PXA168_CLK_PLL1_3_16, "pll1_3_16", "pll1", 3, 16, 0},
|
||||
};
|
||||
|
||||
static struct mmp_clk_factor_masks uart_factor_masks = {
|
||||
.factor = 2,
|
||||
.num_mask = 0x1fff,
|
||||
.den_mask = 0x1fff,
|
||||
.num_shift = 16,
|
||||
.den_shift = 0,
|
||||
};
|
||||
|
||||
static struct mmp_clk_factor_tbl uart_factor_tbl[] = {
|
||||
{.num = 8125, .den = 1536}, /*14.745MHZ */
|
||||
};
|
||||
|
||||
static void pxa168_pll_init(struct pxa168_clk_unit *pxa_unit)
|
||||
{
|
||||
struct clk *clk;
|
||||
struct mmp_clk_unit *unit = &pxa_unit->unit;
|
||||
|
||||
mmp_register_fixed_rate_clks(unit, fixed_rate_clks,
|
||||
ARRAY_SIZE(fixed_rate_clks));
|
||||
|
||||
mmp_register_fixed_factor_clks(unit, fixed_factor_clks,
|
||||
ARRAY_SIZE(fixed_factor_clks));
|
||||
|
||||
clk = mmp_clk_register_factor("uart_pll", "pll1_4",
|
||||
CLK_SET_RATE_PARENT,
|
||||
pxa_unit->mpmu_base + MPMU_UART_PLL,
|
||||
&uart_factor_masks, uart_factor_tbl,
|
||||
ARRAY_SIZE(uart_factor_tbl), NULL);
|
||||
mmp_clk_add(unit, PXA168_CLK_UART_PLL, clk);
|
||||
}
|
||||
|
||||
static DEFINE_SPINLOCK(uart0_lock);
|
||||
static DEFINE_SPINLOCK(uart1_lock);
|
||||
static DEFINE_SPINLOCK(uart2_lock);
|
||||
static const char *uart_parent_names[] = {"pll1_3_16", "uart_pll"};
|
||||
|
||||
static DEFINE_SPINLOCK(ssp0_lock);
|
||||
static DEFINE_SPINLOCK(ssp1_lock);
|
||||
static DEFINE_SPINLOCK(ssp2_lock);
|
||||
static DEFINE_SPINLOCK(ssp3_lock);
|
||||
static DEFINE_SPINLOCK(ssp4_lock);
|
||||
static const char *ssp_parent_names[] = {"pll1_96", "pll1_48", "pll1_24", "pll1_12"};
|
||||
|
||||
static DEFINE_SPINLOCK(reset_lock);
|
||||
|
||||
static struct mmp_param_mux_clk apbc_mux_clks[] = {
|
||||
{0, "uart0_mux", uart_parent_names, ARRAY_SIZE(uart_parent_names), CLK_SET_RATE_PARENT, APBC_UART0, 4, 3, 0, &uart0_lock},
|
||||
{0, "uart1_mux", uart_parent_names, ARRAY_SIZE(uart_parent_names), CLK_SET_RATE_PARENT, APBC_UART1, 4, 3, 0, &uart1_lock},
|
||||
{0, "uart2_mux", uart_parent_names, ARRAY_SIZE(uart_parent_names), CLK_SET_RATE_PARENT, APBC_UART2, 4, 3, 0, &uart2_lock},
|
||||
{0, "ssp0_mux", ssp_parent_names, ARRAY_SIZE(ssp_parent_names), CLK_SET_RATE_PARENT, APBC_SSP0, 4, 3, 0, &ssp0_lock},
|
||||
{0, "ssp1_mux", ssp_parent_names, ARRAY_SIZE(ssp_parent_names), CLK_SET_RATE_PARENT, APBC_SSP1, 4, 3, 0, &ssp1_lock},
|
||||
{0, "ssp2_mux", ssp_parent_names, ARRAY_SIZE(ssp_parent_names), CLK_SET_RATE_PARENT, APBC_SSP2, 4, 3, 0, &ssp2_lock},
|
||||
{0, "ssp3_mux", ssp_parent_names, ARRAY_SIZE(ssp_parent_names), CLK_SET_RATE_PARENT, APBC_SSP3, 4, 3, 0, &ssp3_lock},
|
||||
{0, "ssp4_mux", ssp_parent_names, ARRAY_SIZE(ssp_parent_names), CLK_SET_RATE_PARENT, APBC_SSP4, 4, 3, 0, &ssp4_lock},
|
||||
};
|
||||
|
||||
static struct mmp_param_gate_clk apbc_gate_clks[] = {
|
||||
{PXA168_CLK_TWSI0, "twsi0_clk", "pll1_13_1_5", CLK_SET_RATE_PARENT, APBC_TWSI0, 0x3, 0x3, 0x0, 0, &reset_lock},
|
||||
{PXA168_CLK_TWSI1, "twsi1_clk", "pll1_13_1_5", CLK_SET_RATE_PARENT, APBC_TWSI1, 0x3, 0x3, 0x0, 0, &reset_lock},
|
||||
{PXA168_CLK_GPIO, "gpio_clk", "vctcxo", CLK_SET_RATE_PARENT, APBC_GPIO, 0x3, 0x3, 0x0, 0, &reset_lock},
|
||||
{PXA168_CLK_KPC, "kpc_clk", "clk32", CLK_SET_RATE_PARENT, APBC_KPC, 0x3, 0x3, 0x0, MMP_CLK_GATE_NEED_DELAY, NULL},
|
||||
{PXA168_CLK_RTC, "rtc_clk", "clk32", CLK_SET_RATE_PARENT, APBC_RTC, 0x83, 0x83, 0x0, MMP_CLK_GATE_NEED_DELAY, NULL},
|
||||
{PXA168_CLK_PWM0, "pwm0_clk", "pll1_48", CLK_SET_RATE_PARENT, APBC_PWM0, 0x3, 0x3, 0x0, 0, &reset_lock},
|
||||
{PXA168_CLK_PWM1, "pwm1_clk", "pll1_48", CLK_SET_RATE_PARENT, APBC_PWM1, 0x3, 0x3, 0x0, 0, &reset_lock},
|
||||
{PXA168_CLK_PWM2, "pwm2_clk", "pll1_48", CLK_SET_RATE_PARENT, APBC_PWM2, 0x3, 0x3, 0x0, 0, &reset_lock},
|
||||
{PXA168_CLK_PWM3, "pwm3_clk", "pll1_48", CLK_SET_RATE_PARENT, APBC_PWM3, 0x3, 0x3, 0x0, 0, &reset_lock},
|
||||
/* The gate clocks has mux parent. */
|
||||
{PXA168_CLK_UART0, "uart0_clk", "uart0_mux", CLK_SET_RATE_PARENT, APBC_UART0, 0x3, 0x3, 0x0, 0, &uart0_lock},
|
||||
{PXA168_CLK_UART1, "uart1_clk", "uart1_mux", CLK_SET_RATE_PARENT, APBC_UART1, 0x3, 0x3, 0x0, 0, &uart1_lock},
|
||||
{PXA168_CLK_UART2, "uart2_clk", "uart2_mux", CLK_SET_RATE_PARENT, APBC_UART2, 0x3, 0x3, 0x0, 0, &uart2_lock},
|
||||
{PXA168_CLK_SSP0, "ssp0_clk", "ssp0_mux", CLK_SET_RATE_PARENT, APBC_SSP0, 0x3, 0x3, 0x0, 0, &ssp0_lock},
|
||||
{PXA168_CLK_SSP1, "ssp1_clk", "ssp1_mux", CLK_SET_RATE_PARENT, APBC_SSP1, 0x3, 0x3, 0x0, 0, &ssp1_lock},
|
||||
{PXA168_CLK_SSP2, "ssp2_clk", "ssp2_mux", CLK_SET_RATE_PARENT, APBC_SSP2, 0x3, 0x3, 0x0, 0, &ssp2_lock},
|
||||
{PXA168_CLK_SSP3, "ssp3_clk", "ssp3_mux", CLK_SET_RATE_PARENT, APBC_SSP3, 0x3, 0x3, 0x0, 0, &ssp3_lock},
|
||||
{PXA168_CLK_SSP4, "ssp4_clk", "ssp4_mux", CLK_SET_RATE_PARENT, APBC_SSP4, 0x3, 0x3, 0x0, 0, &ssp4_lock},
|
||||
};
|
||||
|
||||
static void pxa168_apb_periph_clk_init(struct pxa168_clk_unit *pxa_unit)
|
||||
{
|
||||
struct mmp_clk_unit *unit = &pxa_unit->unit;
|
||||
|
||||
mmp_register_mux_clks(unit, apbc_mux_clks, pxa_unit->apbc_base,
|
||||
ARRAY_SIZE(apbc_mux_clks));
|
||||
|
||||
mmp_register_gate_clks(unit, apbc_gate_clks, pxa_unit->apbc_base,
|
||||
ARRAY_SIZE(apbc_gate_clks));
|
||||
|
||||
}
|
||||
|
||||
static DEFINE_SPINLOCK(sdh0_lock);
|
||||
static DEFINE_SPINLOCK(sdh1_lock);
|
||||
static const char *sdh_parent_names[] = {"pll1_12", "pll1_13"};
|
||||
|
||||
static DEFINE_SPINLOCK(usb_lock);
|
||||
|
||||
static DEFINE_SPINLOCK(disp0_lock);
|
||||
static const char *disp_parent_names[] = {"pll1_2", "pll1_12"};
|
||||
|
||||
static DEFINE_SPINLOCK(ccic0_lock);
|
||||
static const char *ccic_parent_names[] = {"pll1_2", "pll1_12"};
|
||||
static const char *ccic_phy_parent_names[] = {"pll1_6", "pll1_12"};
|
||||
|
||||
static struct mmp_param_mux_clk apmu_mux_clks[] = {
|
||||
{0, "sdh0_mux", sdh_parent_names, ARRAY_SIZE(sdh_parent_names), CLK_SET_RATE_PARENT, APMU_SDH0, 6, 1, 0, &sdh0_lock},
|
||||
{0, "sdh1_mux", sdh_parent_names, ARRAY_SIZE(sdh_parent_names), CLK_SET_RATE_PARENT, APMU_SDH1, 6, 1, 0, &sdh1_lock},
|
||||
{0, "disp0_mux", disp_parent_names, ARRAY_SIZE(disp_parent_names), CLK_SET_RATE_PARENT, APMU_DISP0, 6, 1, 0, &disp0_lock},
|
||||
{0, "ccic0_mux", ccic_parent_names, ARRAY_SIZE(ccic_parent_names), CLK_SET_RATE_PARENT, APMU_CCIC0, 6, 1, 0, &ccic0_lock},
|
||||
{0, "ccic0_phy_mux", ccic_phy_parent_names, ARRAY_SIZE(ccic_phy_parent_names), CLK_SET_RATE_PARENT, APMU_CCIC0, 7, 1, 0, &ccic0_lock},
|
||||
};
|
||||
|
||||
static struct mmp_param_div_clk apmu_div_clks[] = {
|
||||
{0, "ccic0_sphy_div", "ccic0_mux", CLK_SET_RATE_PARENT, APMU_CCIC0, 10, 5, 0, &ccic0_lock},
|
||||
};
|
||||
|
||||
static struct mmp_param_gate_clk apmu_gate_clks[] = {
|
||||
{PXA168_CLK_DFC, "dfc_clk", "pll1_4", CLK_SET_RATE_PARENT, APMU_DFC, 0x19b, 0x19b, 0x0, 0, NULL},
|
||||
{PXA168_CLK_USB, "usb_clk", "usb_pll", 0, APMU_USB, 0x9, 0x9, 0x0, 0, &usb_lock},
|
||||
{PXA168_CLK_SPH, "sph_clk", "usb_pll", 0, APMU_USB, 0x12, 0x12, 0x0, 0, &usb_lock},
|
||||
/* The gate clocks has mux parent. */
|
||||
{PXA168_CLK_SDH0, "sdh0_clk", "sdh0_mux", CLK_SET_RATE_PARENT, APMU_SDH0, 0x1b, 0x1b, 0x0, 0, &sdh0_lock},
|
||||
{PXA168_CLK_SDH1, "sdh1_clk", "sdh1_mux", CLK_SET_RATE_PARENT, APMU_SDH1, 0x1b, 0x1b, 0x0, 0, &sdh1_lock},
|
||||
{PXA168_CLK_DISP0, "disp0_clk", "disp0_mux", CLK_SET_RATE_PARENT, APMU_DISP0, 0x1b, 0x1b, 0x0, 0, &disp0_lock},
|
||||
{PXA168_CLK_CCIC0, "ccic0_clk", "ccic0_mux", CLK_SET_RATE_PARENT, APMU_CCIC0, 0x1b, 0x1b, 0x0, 0, &ccic0_lock},
|
||||
{PXA168_CLK_CCIC0_PHY, "ccic0_phy_clk", "ccic0_phy_mux", CLK_SET_RATE_PARENT, APMU_CCIC0, 0x24, 0x24, 0x0, 0, &ccic0_lock},
|
||||
{PXA168_CLK_CCIC0_SPHY, "ccic0_sphy_clk", "ccic0_sphy_div", CLK_SET_RATE_PARENT, APMU_CCIC0, 0x300, 0x300, 0x0, 0, &ccic0_lock},
|
||||
};
|
||||
|
||||
static void pxa168_axi_periph_clk_init(struct pxa168_clk_unit *pxa_unit)
|
||||
{
|
||||
struct mmp_clk_unit *unit = &pxa_unit->unit;
|
||||
|
||||
mmp_register_mux_clks(unit, apmu_mux_clks, pxa_unit->apmu_base,
|
||||
ARRAY_SIZE(apmu_mux_clks));
|
||||
|
||||
mmp_register_div_clks(unit, apmu_div_clks, pxa_unit->apmu_base,
|
||||
ARRAY_SIZE(apmu_div_clks));
|
||||
|
||||
mmp_register_gate_clks(unit, apmu_gate_clks, pxa_unit->apmu_base,
|
||||
ARRAY_SIZE(apmu_gate_clks));
|
||||
}
|
||||
|
||||
static void pxa168_clk_reset_init(struct device_node *np,
|
||||
struct pxa168_clk_unit *pxa_unit)
|
||||
{
|
||||
struct mmp_clk_reset_cell *cells;
|
||||
int i, nr_resets;
|
||||
|
||||
nr_resets = ARRAY_SIZE(apbc_gate_clks);
|
||||
cells = kcalloc(nr_resets, sizeof(*cells), GFP_KERNEL);
|
||||
if (!cells)
|
||||
return;
|
||||
|
||||
for (i = 0; i < nr_resets; i++) {
|
||||
cells[i].clk_id = apbc_gate_clks[i].id;
|
||||
cells[i].reg = pxa_unit->apbc_base + apbc_gate_clks[i].offset;
|
||||
cells[i].flags = 0;
|
||||
cells[i].lock = apbc_gate_clks[i].lock;
|
||||
cells[i].bits = 0x4;
|
||||
}
|
||||
|
||||
mmp_clk_reset_register(np, cells, nr_resets);
|
||||
}
|
||||
|
||||
static void __init pxa168_clk_init(struct device_node *np)
|
||||
{
|
||||
struct pxa168_clk_unit *pxa_unit;
|
||||
|
||||
pxa_unit = kzalloc(sizeof(*pxa_unit), GFP_KERNEL);
|
||||
if (!pxa_unit)
|
||||
return;
|
||||
|
||||
pxa_unit->mpmu_base = of_iomap(np, 0);
|
||||
if (!pxa_unit->mpmu_base) {
|
||||
pr_err("failed to map mpmu registers\n");
|
||||
return;
|
||||
}
|
||||
|
||||
pxa_unit->apmu_base = of_iomap(np, 1);
|
||||
if (!pxa_unit->mpmu_base) {
|
||||
pr_err("failed to map apmu registers\n");
|
||||
return;
|
||||
}
|
||||
|
||||
pxa_unit->apbc_base = of_iomap(np, 2);
|
||||
if (!pxa_unit->apbc_base) {
|
||||
pr_err("failed to map apbc registers\n");
|
||||
return;
|
||||
}
|
||||
|
||||
mmp_clk_init(np, &pxa_unit->unit, PXA168_NR_CLKS);
|
||||
|
||||
pxa168_pll_init(pxa_unit);
|
||||
|
||||
pxa168_apb_periph_clk_init(pxa_unit);
|
||||
|
||||
pxa168_axi_periph_clk_init(pxa_unit);
|
||||
|
||||
pxa168_clk_reset_init(np, pxa_unit);
|
||||
}
|
||||
|
||||
CLK_OF_DECLARE(pxa168_clk, "marvell,pxa168-clock", pxa168_clk_init);
|
301
drivers/clk/mmp/clk-of-pxa910.c
Normal file
301
drivers/clk/mmp/clk-of-pxa910.c
Normal file
@ -0,0 +1,301 @@
|
||||
/*
|
||||
* pxa910 clock framework source file
|
||||
*
|
||||
* Copyright (C) 2012 Marvell
|
||||
* Chao Xie <xiechao.mail@gmail.com>
|
||||
*
|
||||
* This file is licensed under the terms of the GNU General Public
|
||||
* License version 2. This program is licensed "as is" without any
|
||||
* warranty of any kind, whether express or implied.
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/of_address.h>
|
||||
|
||||
#include <dt-bindings/clock/marvell,pxa910.h>
|
||||
|
||||
#include "clk.h"
|
||||
#include "reset.h"
|
||||
|
||||
#define APBC_RTC 0x28
|
||||
#define APBC_TWSI0 0x2c
|
||||
#define APBC_KPC 0x18
|
||||
#define APBC_UART0 0x0
|
||||
#define APBC_UART1 0x4
|
||||
#define APBC_GPIO 0x8
|
||||
#define APBC_PWM0 0xc
|
||||
#define APBC_PWM1 0x10
|
||||
#define APBC_PWM2 0x14
|
||||
#define APBC_PWM3 0x18
|
||||
#define APBC_SSP0 0x1c
|
||||
#define APBC_SSP1 0x20
|
||||
#define APBC_SSP2 0x4c
|
||||
#define APBCP_TWSI1 0x28
|
||||
#define APBCP_UART2 0x1c
|
||||
#define APMU_SDH0 0x54
|
||||
#define APMU_SDH1 0x58
|
||||
#define APMU_USB 0x5c
|
||||
#define APMU_DISP0 0x4c
|
||||
#define APMU_CCIC0 0x50
|
||||
#define APMU_DFC 0x60
|
||||
#define MPMU_UART_PLL 0x14
|
||||
|
||||
struct pxa910_clk_unit {
|
||||
struct mmp_clk_unit unit;
|
||||
void __iomem *mpmu_base;
|
||||
void __iomem *apmu_base;
|
||||
void __iomem *apbc_base;
|
||||
void __iomem *apbcp_base;
|
||||
};
|
||||
|
||||
static struct mmp_param_fixed_rate_clk fixed_rate_clks[] = {
|
||||
{PXA910_CLK_CLK32, "clk32", NULL, CLK_IS_ROOT, 32768},
|
||||
{PXA910_CLK_VCTCXO, "vctcxo", NULL, CLK_IS_ROOT, 26000000},
|
||||
{PXA910_CLK_PLL1, "pll1", NULL, CLK_IS_ROOT, 624000000},
|
||||
};
|
||||
|
||||
static struct mmp_param_fixed_factor_clk fixed_factor_clks[] = {
|
||||
{PXA910_CLK_PLL1_2, "pll1_2", "pll1", 1, 2, 0},
|
||||
{PXA910_CLK_PLL1_4, "pll1_4", "pll1_2", 1, 2, 0},
|
||||
{PXA910_CLK_PLL1_8, "pll1_8", "pll1_4", 1, 2, 0},
|
||||
{PXA910_CLK_PLL1_16, "pll1_16", "pll1_8", 1, 2, 0},
|
||||
{PXA910_CLK_PLL1_6, "pll1_6", "pll1_2", 1, 3, 0},
|
||||
{PXA910_CLK_PLL1_12, "pll1_12", "pll1_6", 1, 2, 0},
|
||||
{PXA910_CLK_PLL1_24, "pll1_24", "pll1_12", 1, 2, 0},
|
||||
{PXA910_CLK_PLL1_48, "pll1_48", "pll1_24", 1, 2, 0},
|
||||
{PXA910_CLK_PLL1_96, "pll1_96", "pll1_48", 1, 2, 0},
|
||||
{PXA910_CLK_PLL1_13, "pll1_13", "pll1", 1, 13, 0},
|
||||
{PXA910_CLK_PLL1_13_1_5, "pll1_13_1_5", "pll1_13", 2, 3, 0},
|
||||
{PXA910_CLK_PLL1_2_1_5, "pll1_2_1_5", "pll1_2", 2, 3, 0},
|
||||
{PXA910_CLK_PLL1_3_16, "pll1_3_16", "pll1", 3, 16, 0},
|
||||
};
|
||||
|
||||
static struct mmp_clk_factor_masks uart_factor_masks = {
|
||||
.factor = 2,
|
||||
.num_mask = 0x1fff,
|
||||
.den_mask = 0x1fff,
|
||||
.num_shift = 16,
|
||||
.den_shift = 0,
|
||||
};
|
||||
|
||||
static struct mmp_clk_factor_tbl uart_factor_tbl[] = {
|
||||
{.num = 8125, .den = 1536}, /*14.745MHZ */
|
||||
};
|
||||
|
||||
static void pxa910_pll_init(struct pxa910_clk_unit *pxa_unit)
|
||||
{
|
||||
struct clk *clk;
|
||||
struct mmp_clk_unit *unit = &pxa_unit->unit;
|
||||
|
||||
mmp_register_fixed_rate_clks(unit, fixed_rate_clks,
|
||||
ARRAY_SIZE(fixed_rate_clks));
|
||||
|
||||
mmp_register_fixed_factor_clks(unit, fixed_factor_clks,
|
||||
ARRAY_SIZE(fixed_factor_clks));
|
||||
|
||||
clk = mmp_clk_register_factor("uart_pll", "pll1_4",
|
||||
CLK_SET_RATE_PARENT,
|
||||
pxa_unit->mpmu_base + MPMU_UART_PLL,
|
||||
&uart_factor_masks, uart_factor_tbl,
|
||||
ARRAY_SIZE(uart_factor_tbl), NULL);
|
||||
mmp_clk_add(unit, PXA910_CLK_UART_PLL, clk);
|
||||
}
|
||||
|
||||
static DEFINE_SPINLOCK(uart0_lock);
|
||||
static DEFINE_SPINLOCK(uart1_lock);
|
||||
static DEFINE_SPINLOCK(uart2_lock);
|
||||
static const char *uart_parent_names[] = {"pll1_3_16", "uart_pll"};
|
||||
|
||||
static DEFINE_SPINLOCK(ssp0_lock);
|
||||
static DEFINE_SPINLOCK(ssp1_lock);
|
||||
static const char *ssp_parent_names[] = {"pll1_96", "pll1_48", "pll1_24", "pll1_12"};
|
||||
|
||||
static DEFINE_SPINLOCK(reset_lock);
|
||||
|
||||
static struct mmp_param_mux_clk apbc_mux_clks[] = {
|
||||
{0, "uart0_mux", uart_parent_names, ARRAY_SIZE(uart_parent_names), CLK_SET_RATE_PARENT, APBC_UART0, 4, 3, 0, &uart0_lock},
|
||||
{0, "uart1_mux", uart_parent_names, ARRAY_SIZE(uart_parent_names), CLK_SET_RATE_PARENT, APBC_UART1, 4, 3, 0, &uart1_lock},
|
||||
{0, "ssp0_mux", ssp_parent_names, ARRAY_SIZE(ssp_parent_names), CLK_SET_RATE_PARENT, APBC_SSP0, 4, 3, 0, &ssp0_lock},
|
||||
{0, "ssp1_mux", ssp_parent_names, ARRAY_SIZE(ssp_parent_names), CLK_SET_RATE_PARENT, APBC_SSP1, 4, 3, 0, &ssp1_lock},
|
||||
};
|
||||
|
||||
static struct mmp_param_mux_clk apbcp_mux_clks[] = {
|
||||
{0, "uart2_mux", uart_parent_names, ARRAY_SIZE(uart_parent_names), CLK_SET_RATE_PARENT, APBCP_UART2, 4, 3, 0, &uart2_lock},
|
||||
};
|
||||
|
||||
static struct mmp_param_gate_clk apbc_gate_clks[] = {
|
||||
{PXA910_CLK_TWSI0, "twsi0_clk", "pll1_13_1_5", CLK_SET_RATE_PARENT, APBC_TWSI0, 0x3, 0x3, 0x0, 0, &reset_lock},
|
||||
{PXA910_CLK_GPIO, "gpio_clk", "vctcxo", CLK_SET_RATE_PARENT, APBC_GPIO, 0x3, 0x3, 0x0, 0, &reset_lock},
|
||||
{PXA910_CLK_KPC, "kpc_clk", "clk32", CLK_SET_RATE_PARENT, APBC_KPC, 0x3, 0x3, 0x0, MMP_CLK_GATE_NEED_DELAY, NULL},
|
||||
{PXA910_CLK_RTC, "rtc_clk", "clk32", CLK_SET_RATE_PARENT, APBC_RTC, 0x83, 0x83, 0x0, MMP_CLK_GATE_NEED_DELAY, NULL},
|
||||
{PXA910_CLK_PWM0, "pwm0_clk", "pll1_48", CLK_SET_RATE_PARENT, APBC_PWM0, 0x3, 0x3, 0x0, 0, &reset_lock},
|
||||
{PXA910_CLK_PWM1, "pwm1_clk", "pll1_48", CLK_SET_RATE_PARENT, APBC_PWM1, 0x3, 0x3, 0x0, 0, &reset_lock},
|
||||
{PXA910_CLK_PWM2, "pwm2_clk", "pll1_48", CLK_SET_RATE_PARENT, APBC_PWM2, 0x3, 0x3, 0x0, 0, &reset_lock},
|
||||
{PXA910_CLK_PWM3, "pwm3_clk", "pll1_48", CLK_SET_RATE_PARENT, APBC_PWM3, 0x3, 0x3, 0x0, 0, &reset_lock},
|
||||
/* The gate clocks has mux parent. */
|
||||
{PXA910_CLK_UART0, "uart0_clk", "uart0_mux", CLK_SET_RATE_PARENT, APBC_UART0, 0x3, 0x3, 0x0, 0, &uart0_lock},
|
||||
{PXA910_CLK_UART1, "uart1_clk", "uart1_mux", CLK_SET_RATE_PARENT, APBC_UART1, 0x3, 0x3, 0x0, 0, &uart1_lock},
|
||||
{PXA910_CLK_SSP0, "ssp0_clk", "ssp0_mux", CLK_SET_RATE_PARENT, APBC_SSP0, 0x3, 0x3, 0x0, 0, &ssp0_lock},
|
||||
{PXA910_CLK_SSP1, "ssp1_clk", "ssp1_mux", CLK_SET_RATE_PARENT, APBC_SSP1, 0x3, 0x3, 0x0, 0, &ssp1_lock},
|
||||
};
|
||||
|
||||
static struct mmp_param_gate_clk apbcp_gate_clks[] = {
|
||||
{PXA910_CLK_TWSI1, "twsi1_clk", "pll1_13_1_5", CLK_SET_RATE_PARENT, APBCP_TWSI1, 0x3, 0x3, 0x0, 0, &reset_lock},
|
||||
/* The gate clocks has mux parent. */
|
||||
{PXA910_CLK_UART2, "uart2_clk", "uart2_mux", CLK_SET_RATE_PARENT, APBCP_UART2, 0x3, 0x3, 0x0, 0, &uart2_lock},
|
||||
};
|
||||
|
||||
static void pxa910_apb_periph_clk_init(struct pxa910_clk_unit *pxa_unit)
|
||||
{
|
||||
struct mmp_clk_unit *unit = &pxa_unit->unit;
|
||||
|
||||
mmp_register_mux_clks(unit, apbc_mux_clks, pxa_unit->apbc_base,
|
||||
ARRAY_SIZE(apbc_mux_clks));
|
||||
|
||||
mmp_register_mux_clks(unit, apbcp_mux_clks, pxa_unit->apbcp_base,
|
||||
ARRAY_SIZE(apbcp_mux_clks));
|
||||
|
||||
mmp_register_gate_clks(unit, apbc_gate_clks, pxa_unit->apbc_base,
|
||||
ARRAY_SIZE(apbc_gate_clks));
|
||||
|
||||
mmp_register_gate_clks(unit, apbcp_gate_clks, pxa_unit->apbcp_base,
|
||||
ARRAY_SIZE(apbcp_gate_clks));
|
||||
}
|
||||
|
||||
static DEFINE_SPINLOCK(sdh0_lock);
|
||||
static DEFINE_SPINLOCK(sdh1_lock);
|
||||
static const char *sdh_parent_names[] = {"pll1_12", "pll1_13"};
|
||||
|
||||
static DEFINE_SPINLOCK(usb_lock);
|
||||
|
||||
static DEFINE_SPINLOCK(disp0_lock);
|
||||
static const char *disp_parent_names[] = {"pll1_2", "pll1_12"};
|
||||
|
||||
static DEFINE_SPINLOCK(ccic0_lock);
|
||||
static const char *ccic_parent_names[] = {"pll1_2", "pll1_12"};
|
||||
static const char *ccic_phy_parent_names[] = {"pll1_6", "pll1_12"};
|
||||
|
||||
static struct mmp_param_mux_clk apmu_mux_clks[] = {
|
||||
{0, "sdh0_mux", sdh_parent_names, ARRAY_SIZE(sdh_parent_names), CLK_SET_RATE_PARENT, APMU_SDH0, 6, 1, 0, &sdh0_lock},
|
||||
{0, "sdh1_mux", sdh_parent_names, ARRAY_SIZE(sdh_parent_names), CLK_SET_RATE_PARENT, APMU_SDH1, 6, 1, 0, &sdh1_lock},
|
||||
{0, "disp0_mux", disp_parent_names, ARRAY_SIZE(disp_parent_names), CLK_SET_RATE_PARENT, APMU_DISP0, 6, 1, 0, &disp0_lock},
|
||||
{0, "ccic0_mux", ccic_parent_names, ARRAY_SIZE(ccic_parent_names), CLK_SET_RATE_PARENT, APMU_CCIC0, 6, 1, 0, &ccic0_lock},
|
||||
{0, "ccic0_phy_mux", ccic_phy_parent_names, ARRAY_SIZE(ccic_phy_parent_names), CLK_SET_RATE_PARENT, APMU_CCIC0, 7, 1, 0, &ccic0_lock},
|
||||
};
|
||||
|
||||
static struct mmp_param_div_clk apmu_div_clks[] = {
|
||||
{0, "ccic0_sphy_div", "ccic0_mux", CLK_SET_RATE_PARENT, APMU_CCIC0, 10, 5, 0, &ccic0_lock},
|
||||
};
|
||||
|
||||
static struct mmp_param_gate_clk apmu_gate_clks[] = {
|
||||
{PXA910_CLK_DFC, "dfc_clk", "pll1_4", CLK_SET_RATE_PARENT, APMU_DFC, 0x19b, 0x19b, 0x0, 0, NULL},
|
||||
{PXA910_CLK_USB, "usb_clk", "usb_pll", 0, APMU_USB, 0x9, 0x9, 0x0, 0, &usb_lock},
|
||||
{PXA910_CLK_SPH, "sph_clk", "usb_pll", 0, APMU_USB, 0x12, 0x12, 0x0, 0, &usb_lock},
|
||||
/* The gate clocks has mux parent. */
|
||||
{PXA910_CLK_SDH0, "sdh0_clk", "sdh0_mux", CLK_SET_RATE_PARENT, APMU_SDH0, 0x1b, 0x1b, 0x0, 0, &sdh0_lock},
|
||||
{PXA910_CLK_SDH1, "sdh1_clk", "sdh1_mux", CLK_SET_RATE_PARENT, APMU_SDH1, 0x1b, 0x1b, 0x0, 0, &sdh1_lock},
|
||||
{PXA910_CLK_DISP0, "disp0_clk", "disp0_mux", CLK_SET_RATE_PARENT, APMU_DISP0, 0x1b, 0x1b, 0x0, 0, &disp0_lock},
|
||||
{PXA910_CLK_CCIC0, "ccic0_clk", "ccic0_mux", CLK_SET_RATE_PARENT, APMU_CCIC0, 0x1b, 0x1b, 0x0, 0, &ccic0_lock},
|
||||
{PXA910_CLK_CCIC0_PHY, "ccic0_phy_clk", "ccic0_phy_mux", CLK_SET_RATE_PARENT, APMU_CCIC0, 0x24, 0x24, 0x0, 0, &ccic0_lock},
|
||||
{PXA910_CLK_CCIC0_SPHY, "ccic0_sphy_clk", "ccic0_sphy_div", CLK_SET_RATE_PARENT, APMU_CCIC0, 0x300, 0x300, 0x0, 0, &ccic0_lock},
|
||||
};
|
||||
|
||||
static void pxa910_axi_periph_clk_init(struct pxa910_clk_unit *pxa_unit)
|
||||
{
|
||||
struct mmp_clk_unit *unit = &pxa_unit->unit;
|
||||
|
||||
mmp_register_mux_clks(unit, apmu_mux_clks, pxa_unit->apmu_base,
|
||||
ARRAY_SIZE(apmu_mux_clks));
|
||||
|
||||
mmp_register_div_clks(unit, apmu_div_clks, pxa_unit->apmu_base,
|
||||
ARRAY_SIZE(apmu_div_clks));
|
||||
|
||||
mmp_register_gate_clks(unit, apmu_gate_clks, pxa_unit->apmu_base,
|
||||
ARRAY_SIZE(apmu_gate_clks));
|
||||
}
|
||||
|
||||
static void pxa910_clk_reset_init(struct device_node *np,
|
||||
struct pxa910_clk_unit *pxa_unit)
|
||||
{
|
||||
struct mmp_clk_reset_cell *cells;
|
||||
int i, base, nr_resets_apbc, nr_resets_apbcp, nr_resets;
|
||||
|
||||
nr_resets_apbc = ARRAY_SIZE(apbc_gate_clks);
|
||||
nr_resets_apbcp = ARRAY_SIZE(apbcp_gate_clks);
|
||||
nr_resets = nr_resets_apbc + nr_resets_apbcp;
|
||||
cells = kcalloc(nr_resets, sizeof(*cells), GFP_KERNEL);
|
||||
if (!cells)
|
||||
return;
|
||||
|
||||
base = 0;
|
||||
for (i = 0; i < nr_resets_apbc; i++) {
|
||||
cells[base + i].clk_id = apbc_gate_clks[i].id;
|
||||
cells[base + i].reg =
|
||||
pxa_unit->apbc_base + apbc_gate_clks[i].offset;
|
||||
cells[base + i].flags = 0;
|
||||
cells[base + i].lock = apbc_gate_clks[i].lock;
|
||||
cells[base + i].bits = 0x4;
|
||||
}
|
||||
|
||||
base = nr_resets_apbc;
|
||||
for (i = 0; i < nr_resets_apbcp; i++) {
|
||||
cells[base + i].clk_id = apbcp_gate_clks[i].id;
|
||||
cells[base + i].reg =
|
||||
pxa_unit->apbc_base + apbc_gate_clks[i].offset;
|
||||
cells[base + i].flags = 0;
|
||||
cells[base + i].lock = apbc_gate_clks[i].lock;
|
||||
cells[base + i].bits = 0x4;
|
||||
}
|
||||
|
||||
mmp_clk_reset_register(np, cells, nr_resets);
|
||||
}
|
||||
|
||||
static void __init pxa910_clk_init(struct device_node *np)
|
||||
{
|
||||
struct pxa910_clk_unit *pxa_unit;
|
||||
|
||||
pxa_unit = kzalloc(sizeof(*pxa_unit), GFP_KERNEL);
|
||||
if (!pxa_unit)
|
||||
return;
|
||||
|
||||
pxa_unit->mpmu_base = of_iomap(np, 0);
|
||||
if (!pxa_unit->mpmu_base) {
|
||||
pr_err("failed to map mpmu registers\n");
|
||||
return;
|
||||
}
|
||||
|
||||
pxa_unit->apmu_base = of_iomap(np, 1);
|
||||
if (!pxa_unit->mpmu_base) {
|
||||
pr_err("failed to map apmu registers\n");
|
||||
return;
|
||||
}
|
||||
|
||||
pxa_unit->apbc_base = of_iomap(np, 2);
|
||||
if (!pxa_unit->apbc_base) {
|
||||
pr_err("failed to map apbc registers\n");
|
||||
return;
|
||||
}
|
||||
|
||||
pxa_unit->apbcp_base = of_iomap(np, 3);
|
||||
if (!pxa_unit->mpmu_base) {
|
||||
pr_err("failed to map apbcp registers\n");
|
||||
return;
|
||||
}
|
||||
|
||||
mmp_clk_init(np, &pxa_unit->unit, PXA910_NR_CLKS);
|
||||
|
||||
pxa910_pll_init(pxa_unit);
|
||||
|
||||
pxa910_apb_periph_clk_init(pxa_unit);
|
||||
|
||||
pxa910_axi_periph_clk_init(pxa_unit);
|
||||
|
||||
pxa910_clk_reset_init(np, pxa_unit);
|
||||
}
|
||||
|
||||
CLK_OF_DECLARE(pxa910_clk, "marvell,pxa910-clock", pxa910_clk_init);
|
@ -47,7 +47,7 @@
|
||||
|
||||
static DEFINE_SPINLOCK(clk_lock);
|
||||
|
||||
static struct clk_factor_masks uart_factor_masks = {
|
||||
static struct mmp_clk_factor_masks uart_factor_masks = {
|
||||
.factor = 2,
|
||||
.num_mask = 0x1fff,
|
||||
.den_mask = 0x1fff,
|
||||
@ -55,7 +55,7 @@ static struct clk_factor_masks uart_factor_masks = {
|
||||
.den_shift = 0,
|
||||
};
|
||||
|
||||
static struct clk_factor_tbl uart_factor_tbl[] = {
|
||||
static struct mmp_clk_factor_tbl uart_factor_tbl[] = {
|
||||
{.num = 8125, .den = 1536}, /*14.745MHZ */
|
||||
};
|
||||
|
||||
@ -158,7 +158,7 @@ void __init pxa168_clk_init(void)
|
||||
uart_pll = mmp_clk_register_factor("uart_pll", "pll1_4", 0,
|
||||
mpmu_base + MPMU_UART_PLL,
|
||||
&uart_factor_masks, uart_factor_tbl,
|
||||
ARRAY_SIZE(uart_factor_tbl));
|
||||
ARRAY_SIZE(uart_factor_tbl), &clk_lock);
|
||||
clk_set_rate(uart_pll, 14745600);
|
||||
clk_register_clkdev(uart_pll, "uart_pll", NULL);
|
||||
|
||||
|
@ -45,7 +45,7 @@
|
||||
|
||||
static DEFINE_SPINLOCK(clk_lock);
|
||||
|
||||
static struct clk_factor_masks uart_factor_masks = {
|
||||
static struct mmp_clk_factor_masks uart_factor_masks = {
|
||||
.factor = 2,
|
||||
.num_mask = 0x1fff,
|
||||
.den_mask = 0x1fff,
|
||||
@ -53,7 +53,7 @@ static struct clk_factor_masks uart_factor_masks = {
|
||||
.den_shift = 0,
|
||||
};
|
||||
|
||||
static struct clk_factor_tbl uart_factor_tbl[] = {
|
||||
static struct mmp_clk_factor_tbl uart_factor_tbl[] = {
|
||||
{.num = 8125, .den = 1536}, /*14.745MHZ */
|
||||
};
|
||||
|
||||
@ -163,7 +163,7 @@ void __init pxa910_clk_init(void)
|
||||
uart_pll = mmp_clk_register_factor("uart_pll", "pll1_4", 0,
|
||||
mpmu_base + MPMU_UART_PLL,
|
||||
&uart_factor_masks, uart_factor_tbl,
|
||||
ARRAY_SIZE(uart_factor_tbl));
|
||||
ARRAY_SIZE(uart_factor_tbl), &clk_lock);
|
||||
clk_set_rate(uart_pll, 14745600);
|
||||
clk_register_clkdev(uart_pll, "uart_pll", NULL);
|
||||
|
||||
|
192
drivers/clk/mmp/clk.c
Normal file
192
drivers/clk/mmp/clk.c
Normal file
@ -0,0 +1,192 @@
|
||||
#include <linux/io.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/clkdev.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_address.h>
|
||||
|
||||
#include "clk.h"
|
||||
|
||||
void mmp_clk_init(struct device_node *np, struct mmp_clk_unit *unit,
|
||||
int nr_clks)
|
||||
{
|
||||
static struct clk **clk_table;
|
||||
|
||||
clk_table = kcalloc(nr_clks, sizeof(struct clk *), GFP_KERNEL);
|
||||
if (!clk_table)
|
||||
return;
|
||||
|
||||
unit->clk_table = clk_table;
|
||||
unit->nr_clks = nr_clks;
|
||||
unit->clk_data.clks = clk_table;
|
||||
unit->clk_data.clk_num = nr_clks;
|
||||
of_clk_add_provider(np, of_clk_src_onecell_get, &unit->clk_data);
|
||||
}
|
||||
|
||||
void mmp_register_fixed_rate_clks(struct mmp_clk_unit *unit,
|
||||
struct mmp_param_fixed_rate_clk *clks,
|
||||
int size)
|
||||
{
|
||||
int i;
|
||||
struct clk *clk;
|
||||
|
||||
for (i = 0; i < size; i++) {
|
||||
clk = clk_register_fixed_rate(NULL, clks[i].name,
|
||||
clks[i].parent_name,
|
||||
clks[i].flags,
|
||||
clks[i].fixed_rate);
|
||||
if (IS_ERR(clk)) {
|
||||
pr_err("%s: failed to register clock %s\n",
|
||||
__func__, clks[i].name);
|
||||
continue;
|
||||
}
|
||||
if (clks[i].id)
|
||||
unit->clk_table[clks[i].id] = clk;
|
||||
}
|
||||
}
|
||||
|
||||
void mmp_register_fixed_factor_clks(struct mmp_clk_unit *unit,
|
||||
struct mmp_param_fixed_factor_clk *clks,
|
||||
int size)
|
||||
{
|
||||
struct clk *clk;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < size; i++) {
|
||||
clk = clk_register_fixed_factor(NULL, clks[i].name,
|
||||
clks[i].parent_name,
|
||||
clks[i].flags, clks[i].mult,
|
||||
clks[i].div);
|
||||
if (IS_ERR(clk)) {
|
||||
pr_err("%s: failed to register clock %s\n",
|
||||
__func__, clks[i].name);
|
||||
continue;
|
||||
}
|
||||
if (clks[i].id)
|
||||
unit->clk_table[clks[i].id] = clk;
|
||||
}
|
||||
}
|
||||
|
||||
void mmp_register_general_gate_clks(struct mmp_clk_unit *unit,
|
||||
struct mmp_param_general_gate_clk *clks,
|
||||
void __iomem *base, int size)
|
||||
{
|
||||
struct clk *clk;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < size; i++) {
|
||||
clk = clk_register_gate(NULL, clks[i].name,
|
||||
clks[i].parent_name,
|
||||
clks[i].flags,
|
||||
base + clks[i].offset,
|
||||
clks[i].bit_idx,
|
||||
clks[i].gate_flags,
|
||||
clks[i].lock);
|
||||
|
||||
if (IS_ERR(clk)) {
|
||||
pr_err("%s: failed to register clock %s\n",
|
||||
__func__, clks[i].name);
|
||||
continue;
|
||||
}
|
||||
if (clks[i].id)
|
||||
unit->clk_table[clks[i].id] = clk;
|
||||
}
|
||||
}
|
||||
|
||||
void mmp_register_gate_clks(struct mmp_clk_unit *unit,
|
||||
struct mmp_param_gate_clk *clks,
|
||||
void __iomem *base, int size)
|
||||
{
|
||||
struct clk *clk;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < size; i++) {
|
||||
clk = mmp_clk_register_gate(NULL, clks[i].name,
|
||||
clks[i].parent_name,
|
||||
clks[i].flags,
|
||||
base + clks[i].offset,
|
||||
clks[i].mask,
|
||||
clks[i].val_enable,
|
||||
clks[i].val_disable,
|
||||
clks[i].gate_flags,
|
||||
clks[i].lock);
|
||||
|
||||
if (IS_ERR(clk)) {
|
||||
pr_err("%s: failed to register clock %s\n",
|
||||
__func__, clks[i].name);
|
||||
continue;
|
||||
}
|
||||
if (clks[i].id)
|
||||
unit->clk_table[clks[i].id] = clk;
|
||||
}
|
||||
}
|
||||
|
||||
void mmp_register_mux_clks(struct mmp_clk_unit *unit,
|
||||
struct mmp_param_mux_clk *clks,
|
||||
void __iomem *base, int size)
|
||||
{
|
||||
struct clk *clk;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < size; i++) {
|
||||
clk = clk_register_mux(NULL, clks[i].name,
|
||||
clks[i].parent_name,
|
||||
clks[i].num_parents,
|
||||
clks[i].flags,
|
||||
base + clks[i].offset,
|
||||
clks[i].shift,
|
||||
clks[i].width,
|
||||
clks[i].mux_flags,
|
||||
clks[i].lock);
|
||||
|
||||
if (IS_ERR(clk)) {
|
||||
pr_err("%s: failed to register clock %s\n",
|
||||
__func__, clks[i].name);
|
||||
continue;
|
||||
}
|
||||
if (clks[i].id)
|
||||
unit->clk_table[clks[i].id] = clk;
|
||||
}
|
||||
}
|
||||
|
||||
void mmp_register_div_clks(struct mmp_clk_unit *unit,
|
||||
struct mmp_param_div_clk *clks,
|
||||
void __iomem *base, int size)
|
||||
{
|
||||
struct clk *clk;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < size; i++) {
|
||||
clk = clk_register_divider(NULL, clks[i].name,
|
||||
clks[i].parent_name,
|
||||
clks[i].flags,
|
||||
base + clks[i].offset,
|
||||
clks[i].shift,
|
||||
clks[i].width,
|
||||
clks[i].div_flags,
|
||||
clks[i].lock);
|
||||
|
||||
if (IS_ERR(clk)) {
|
||||
pr_err("%s: failed to register clock %s\n",
|
||||
__func__, clks[i].name);
|
||||
continue;
|
||||
}
|
||||
if (clks[i].id)
|
||||
unit->clk_table[clks[i].id] = clk;
|
||||
}
|
||||
}
|
||||
|
||||
void mmp_clk_add(struct mmp_clk_unit *unit, unsigned int id,
|
||||
struct clk *clk)
|
||||
{
|
||||
if (IS_ERR_OR_NULL(clk)) {
|
||||
pr_err("CLK %d has invalid pointer %p\n", id, clk);
|
||||
return;
|
||||
}
|
||||
if (id > unit->nr_clks) {
|
||||
pr_err("CLK %d is invalid\n", id);
|
||||
return;
|
||||
}
|
||||
|
||||
unit->clk_table[id] = clk;
|
||||
}
|
@ -7,19 +7,123 @@
|
||||
#define APBC_NO_BUS_CTRL BIT(0)
|
||||
#define APBC_POWER_CTRL BIT(1)
|
||||
|
||||
struct clk_factor_masks {
|
||||
unsigned int factor;
|
||||
unsigned int num_mask;
|
||||
unsigned int den_mask;
|
||||
unsigned int num_shift;
|
||||
unsigned int den_shift;
|
||||
|
||||
/* Clock type "factor" */
|
||||
struct mmp_clk_factor_masks {
|
||||
unsigned int factor;
|
||||
unsigned int num_mask;
|
||||
unsigned int den_mask;
|
||||
unsigned int num_shift;
|
||||
unsigned int den_shift;
|
||||
};
|
||||
|
||||
struct clk_factor_tbl {
|
||||
struct mmp_clk_factor_tbl {
|
||||
unsigned int num;
|
||||
unsigned int den;
|
||||
};
|
||||
|
||||
struct mmp_clk_factor {
|
||||
struct clk_hw hw;
|
||||
void __iomem *base;
|
||||
struct mmp_clk_factor_masks *masks;
|
||||
struct mmp_clk_factor_tbl *ftbl;
|
||||
unsigned int ftbl_cnt;
|
||||
spinlock_t *lock;
|
||||
};
|
||||
|
||||
extern struct clk *mmp_clk_register_factor(const char *name,
|
||||
const char *parent_name, unsigned long flags,
|
||||
void __iomem *base, struct mmp_clk_factor_masks *masks,
|
||||
struct mmp_clk_factor_tbl *ftbl, unsigned int ftbl_cnt,
|
||||
spinlock_t *lock);
|
||||
|
||||
/* Clock type "mix" */
|
||||
#define MMP_CLK_BITS_MASK(width, shift) \
|
||||
(((1 << (width)) - 1) << (shift))
|
||||
#define MMP_CLK_BITS_GET_VAL(data, width, shift) \
|
||||
((data & MMP_CLK_BITS_MASK(width, shift)) >> (shift))
|
||||
#define MMP_CLK_BITS_SET_VAL(val, width, shift) \
|
||||
(((val) << (shift)) & MMP_CLK_BITS_MASK(width, shift))
|
||||
|
||||
enum {
|
||||
MMP_CLK_MIX_TYPE_V1,
|
||||
MMP_CLK_MIX_TYPE_V2,
|
||||
MMP_CLK_MIX_TYPE_V3,
|
||||
};
|
||||
|
||||
/* The register layout */
|
||||
struct mmp_clk_mix_reg_info {
|
||||
void __iomem *reg_clk_ctrl;
|
||||
void __iomem *reg_clk_sel;
|
||||
u8 width_div;
|
||||
u8 shift_div;
|
||||
u8 width_mux;
|
||||
u8 shift_mux;
|
||||
u8 bit_fc;
|
||||
};
|
||||
|
||||
/* The suggested clock table from user. */
|
||||
struct mmp_clk_mix_clk_table {
|
||||
unsigned long rate;
|
||||
u8 parent_index;
|
||||
unsigned int divisor;
|
||||
unsigned int valid;
|
||||
};
|
||||
|
||||
struct mmp_clk_mix_config {
|
||||
struct mmp_clk_mix_reg_info reg_info;
|
||||
struct mmp_clk_mix_clk_table *table;
|
||||
unsigned int table_size;
|
||||
u32 *mux_table;
|
||||
struct clk_div_table *div_table;
|
||||
u8 div_flags;
|
||||
u8 mux_flags;
|
||||
};
|
||||
|
||||
struct mmp_clk_mix {
|
||||
struct clk_hw hw;
|
||||
struct mmp_clk_mix_reg_info reg_info;
|
||||
struct mmp_clk_mix_clk_table *table;
|
||||
u32 *mux_table;
|
||||
struct clk_div_table *div_table;
|
||||
unsigned int table_size;
|
||||
u8 div_flags;
|
||||
u8 mux_flags;
|
||||
unsigned int type;
|
||||
spinlock_t *lock;
|
||||
};
|
||||
|
||||
extern const struct clk_ops mmp_clk_mix_ops;
|
||||
extern struct clk *mmp_clk_register_mix(struct device *dev,
|
||||
const char *name,
|
||||
const char **parent_names,
|
||||
u8 num_parents,
|
||||
unsigned long flags,
|
||||
struct mmp_clk_mix_config *config,
|
||||
spinlock_t *lock);
|
||||
|
||||
|
||||
/* Clock type "gate". MMP private gate */
|
||||
#define MMP_CLK_GATE_NEED_DELAY BIT(0)
|
||||
|
||||
struct mmp_clk_gate {
|
||||
struct clk_hw hw;
|
||||
void __iomem *reg;
|
||||
u32 mask;
|
||||
u32 val_enable;
|
||||
u32 val_disable;
|
||||
unsigned int flags;
|
||||
spinlock_t *lock;
|
||||
};
|
||||
|
||||
extern const struct clk_ops mmp_clk_gate_ops;
|
||||
extern struct clk *mmp_clk_register_gate(struct device *dev, const char *name,
|
||||
const char *parent_name, unsigned long flags,
|
||||
void __iomem *reg, u32 mask, u32 val_enable,
|
||||
u32 val_disable, unsigned int gate_flags,
|
||||
spinlock_t *lock);
|
||||
|
||||
|
||||
extern struct clk *mmp_clk_register_pll2(const char *name,
|
||||
const char *parent_name, unsigned long flags);
|
||||
extern struct clk *mmp_clk_register_apbc(const char *name,
|
||||
@ -28,8 +132,108 @@ extern struct clk *mmp_clk_register_apbc(const char *name,
|
||||
extern struct clk *mmp_clk_register_apmu(const char *name,
|
||||
const char *parent_name, void __iomem *base, u32 enable_mask,
|
||||
spinlock_t *lock);
|
||||
extern struct clk *mmp_clk_register_factor(const char *name,
|
||||
const char *parent_name, unsigned long flags,
|
||||
void __iomem *base, struct clk_factor_masks *masks,
|
||||
struct clk_factor_tbl *ftbl, unsigned int ftbl_cnt);
|
||||
|
||||
struct mmp_clk_unit {
|
||||
unsigned int nr_clks;
|
||||
struct clk **clk_table;
|
||||
struct clk_onecell_data clk_data;
|
||||
};
|
||||
|
||||
struct mmp_param_fixed_rate_clk {
|
||||
unsigned int id;
|
||||
char *name;
|
||||
const char *parent_name;
|
||||
unsigned long flags;
|
||||
unsigned long fixed_rate;
|
||||
};
|
||||
void mmp_register_fixed_rate_clks(struct mmp_clk_unit *unit,
|
||||
struct mmp_param_fixed_rate_clk *clks,
|
||||
int size);
|
||||
|
||||
struct mmp_param_fixed_factor_clk {
|
||||
unsigned int id;
|
||||
char *name;
|
||||
const char *parent_name;
|
||||
unsigned long mult;
|
||||
unsigned long div;
|
||||
unsigned long flags;
|
||||
};
|
||||
void mmp_register_fixed_factor_clks(struct mmp_clk_unit *unit,
|
||||
struct mmp_param_fixed_factor_clk *clks,
|
||||
int size);
|
||||
|
||||
struct mmp_param_general_gate_clk {
|
||||
unsigned int id;
|
||||
const char *name;
|
||||
const char *parent_name;
|
||||
unsigned long flags;
|
||||
unsigned long offset;
|
||||
u8 bit_idx;
|
||||
u8 gate_flags;
|
||||
spinlock_t *lock;
|
||||
};
|
||||
void mmp_register_general_gate_clks(struct mmp_clk_unit *unit,
|
||||
struct mmp_param_general_gate_clk *clks,
|
||||
void __iomem *base, int size);
|
||||
|
||||
struct mmp_param_gate_clk {
|
||||
unsigned int id;
|
||||
char *name;
|
||||
const char *parent_name;
|
||||
unsigned long flags;
|
||||
unsigned long offset;
|
||||
u32 mask;
|
||||
u32 val_enable;
|
||||
u32 val_disable;
|
||||
unsigned int gate_flags;
|
||||
spinlock_t *lock;
|
||||
};
|
||||
void mmp_register_gate_clks(struct mmp_clk_unit *unit,
|
||||
struct mmp_param_gate_clk *clks,
|
||||
void __iomem *base, int size);
|
||||
|
||||
struct mmp_param_mux_clk {
|
||||
unsigned int id;
|
||||
char *name;
|
||||
const char **parent_name;
|
||||
u8 num_parents;
|
||||
unsigned long flags;
|
||||
unsigned long offset;
|
||||
u8 shift;
|
||||
u8 width;
|
||||
u8 mux_flags;
|
||||
spinlock_t *lock;
|
||||
};
|
||||
void mmp_register_mux_clks(struct mmp_clk_unit *unit,
|
||||
struct mmp_param_mux_clk *clks,
|
||||
void __iomem *base, int size);
|
||||
|
||||
struct mmp_param_div_clk {
|
||||
unsigned int id;
|
||||
char *name;
|
||||
const char *parent_name;
|
||||
unsigned long flags;
|
||||
unsigned long offset;
|
||||
u8 shift;
|
||||
u8 width;
|
||||
u8 div_flags;
|
||||
spinlock_t *lock;
|
||||
};
|
||||
void mmp_register_div_clks(struct mmp_clk_unit *unit,
|
||||
struct mmp_param_div_clk *clks,
|
||||
void __iomem *base, int size);
|
||||
|
||||
#define DEFINE_MIX_REG_INFO(w_d, s_d, w_m, s_m, fc) \
|
||||
{ \
|
||||
.width_div = (w_d), \
|
||||
.shift_div = (s_d), \
|
||||
.width_mux = (w_m), \
|
||||
.shift_mux = (s_m), \
|
||||
.bit_fc = (fc), \
|
||||
}
|
||||
|
||||
void mmp_clk_init(struct device_node *np, struct mmp_clk_unit *unit,
|
||||
int nr_clks);
|
||||
void mmp_clk_add(struct mmp_clk_unit *unit, unsigned int id,
|
||||
struct clk *clk);
|
||||
#endif
|
||||
|
99
drivers/clk/mmp/reset.c
Normal file
99
drivers/clk/mmp/reset.c
Normal file
@ -0,0 +1,99 @@
|
||||
#include <linux/slab.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/reset-controller.h>
|
||||
|
||||
#include "reset.h"
|
||||
|
||||
#define rcdev_to_unit(rcdev) container_of(rcdev, struct mmp_clk_reset_unit, rcdev)
|
||||
|
||||
static int mmp_of_reset_xlate(struct reset_controller_dev *rcdev,
|
||||
const struct of_phandle_args *reset_spec)
|
||||
{
|
||||
struct mmp_clk_reset_unit *unit = rcdev_to_unit(rcdev);
|
||||
struct mmp_clk_reset_cell *cell;
|
||||
int i;
|
||||
|
||||
if (WARN_ON(reset_spec->args_count != rcdev->of_reset_n_cells))
|
||||
return -EINVAL;
|
||||
|
||||
for (i = 0; i < rcdev->nr_resets; i++) {
|
||||
cell = &unit->cells[i];
|
||||
if (cell->clk_id == reset_spec->args[0])
|
||||
break;
|
||||
}
|
||||
|
||||
if (i == rcdev->nr_resets)
|
||||
return -EINVAL;
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
static int mmp_clk_reset_assert(struct reset_controller_dev *rcdev,
|
||||
unsigned long id)
|
||||
{
|
||||
struct mmp_clk_reset_unit *unit = rcdev_to_unit(rcdev);
|
||||
struct mmp_clk_reset_cell *cell;
|
||||
unsigned long flags = 0;
|
||||
u32 val;
|
||||
|
||||
cell = &unit->cells[id];
|
||||
if (cell->lock)
|
||||
spin_lock_irqsave(cell->lock, flags);
|
||||
|
||||
val = readl(cell->reg);
|
||||
val |= cell->bits;
|
||||
writel(val, cell->reg);
|
||||
|
||||
if (cell->lock)
|
||||
spin_unlock_irqrestore(cell->lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mmp_clk_reset_deassert(struct reset_controller_dev *rcdev,
|
||||
unsigned long id)
|
||||
{
|
||||
struct mmp_clk_reset_unit *unit = rcdev_to_unit(rcdev);
|
||||
struct mmp_clk_reset_cell *cell;
|
||||
unsigned long flags = 0;
|
||||
u32 val;
|
||||
|
||||
cell = &unit->cells[id];
|
||||
if (cell->lock)
|
||||
spin_lock_irqsave(cell->lock, flags);
|
||||
|
||||
val = readl(cell->reg);
|
||||
val &= ~cell->bits;
|
||||
writel(val, cell->reg);
|
||||
|
||||
if (cell->lock)
|
||||
spin_unlock_irqrestore(cell->lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct reset_control_ops mmp_clk_reset_ops = {
|
||||
.assert = mmp_clk_reset_assert,
|
||||
.deassert = mmp_clk_reset_deassert,
|
||||
};
|
||||
|
||||
void mmp_clk_reset_register(struct device_node *np,
|
||||
struct mmp_clk_reset_cell *cells, int nr_resets)
|
||||
{
|
||||
struct mmp_clk_reset_unit *unit;
|
||||
|
||||
unit = kzalloc(sizeof(*unit), GFP_KERNEL);
|
||||
if (!unit)
|
||||
return;
|
||||
|
||||
unit->cells = cells;
|
||||
unit->rcdev.of_reset_n_cells = 1;
|
||||
unit->rcdev.nr_resets = nr_resets;
|
||||
unit->rcdev.ops = &mmp_clk_reset_ops;
|
||||
unit->rcdev.of_node = np;
|
||||
unit->rcdev.of_xlate = mmp_of_reset_xlate;
|
||||
|
||||
reset_controller_register(&unit->rcdev);
|
||||
}
|
31
drivers/clk/mmp/reset.h
Normal file
31
drivers/clk/mmp/reset.h
Normal file
@ -0,0 +1,31 @@
|
||||
#ifndef __MACH_MMP_CLK_RESET_H
|
||||
#define __MACH_MMP_CLK_RESET_H
|
||||
|
||||
#include <linux/reset-controller.h>
|
||||
|
||||
#define MMP_RESET_INVERT 1
|
||||
|
||||
struct mmp_clk_reset_cell {
|
||||
unsigned int clk_id;
|
||||
void __iomem *reg;
|
||||
u32 bits;
|
||||
unsigned int flags;
|
||||
spinlock_t *lock;
|
||||
};
|
||||
|
||||
struct mmp_clk_reset_unit {
|
||||
struct reset_controller_dev rcdev;
|
||||
struct mmp_clk_reset_cell *cells;
|
||||
};
|
||||
|
||||
#ifdef CONFIG_RESET_CONTROLLER
|
||||
void mmp_clk_reset_register(struct device_node *np,
|
||||
struct mmp_clk_reset_cell *cells, int nr_resets);
|
||||
#else
|
||||
static inline void mmp_clk_reset_register(struct device_node *np,
|
||||
struct mmp_clk_reset_cell *cells, int nr_resets)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
74
include/dt-bindings/clock/marvell,mmp2.h
Normal file
74
include/dt-bindings/clock/marvell,mmp2.h
Normal file
@ -0,0 +1,74 @@
|
||||
#ifndef __DTS_MARVELL_MMP2_CLOCK_H
|
||||
#define __DTS_MARVELL_MMP2_CLOCK_H
|
||||
|
||||
/* fixed clocks and plls */
|
||||
#define MMP2_CLK_CLK32 1
|
||||
#define MMP2_CLK_VCTCXO 2
|
||||
#define MMP2_CLK_PLL1 3
|
||||
#define MMP2_CLK_PLL1_2 8
|
||||
#define MMP2_CLK_PLL1_4 9
|
||||
#define MMP2_CLK_PLL1_8 10
|
||||
#define MMP2_CLK_PLL1_16 11
|
||||
#define MMP2_CLK_PLL1_3 12
|
||||
#define MMP2_CLK_PLL1_6 13
|
||||
#define MMP2_CLK_PLL1_12 14
|
||||
#define MMP2_CLK_PLL1_20 15
|
||||
#define MMP2_CLK_PLL2 16
|
||||
#define MMP2_CLK_PLL2_2 17
|
||||
#define MMP2_CLK_PLL2_4 18
|
||||
#define MMP2_CLK_PLL2_8 19
|
||||
#define MMP2_CLK_PLL2_16 20
|
||||
#define MMP2_CLK_PLL2_3 21
|
||||
#define MMP2_CLK_PLL2_6 22
|
||||
#define MMP2_CLK_PLL2_12 23
|
||||
#define MMP2_CLK_VCTCXO_2 24
|
||||
#define MMP2_CLK_VCTCXO_4 25
|
||||
#define MMP2_CLK_UART_PLL 26
|
||||
#define MMP2_CLK_USB_PLL 27
|
||||
|
||||
/* apb periphrals */
|
||||
#define MMP2_CLK_TWSI0 60
|
||||
#define MMP2_CLK_TWSI1 61
|
||||
#define MMP2_CLK_TWSI2 62
|
||||
#define MMP2_CLK_TWSI3 63
|
||||
#define MMP2_CLK_TWSI4 64
|
||||
#define MMP2_CLK_TWSI5 65
|
||||
#define MMP2_CLK_GPIO 66
|
||||
#define MMP2_CLK_KPC 67
|
||||
#define MMP2_CLK_RTC 68
|
||||
#define MMP2_CLK_PWM0 69
|
||||
#define MMP2_CLK_PWM1 70
|
||||
#define MMP2_CLK_PWM2 71
|
||||
#define MMP2_CLK_PWM3 72
|
||||
#define MMP2_CLK_UART0 73
|
||||
#define MMP2_CLK_UART1 74
|
||||
#define MMP2_CLK_UART2 75
|
||||
#define MMP2_CLK_UART3 76
|
||||
#define MMP2_CLK_SSP0 77
|
||||
#define MMP2_CLK_SSP1 78
|
||||
#define MMP2_CLK_SSP2 79
|
||||
#define MMP2_CLK_SSP3 80
|
||||
|
||||
/* axi periphrals */
|
||||
#define MMP2_CLK_SDH0 101
|
||||
#define MMP2_CLK_SDH1 102
|
||||
#define MMP2_CLK_SDH2 103
|
||||
#define MMP2_CLK_SDH3 104
|
||||
#define MMP2_CLK_USB 105
|
||||
#define MMP2_CLK_DISP0 106
|
||||
#define MMP2_CLK_DISP0_MUX 107
|
||||
#define MMP2_CLK_DISP0_SPHY 108
|
||||
#define MMP2_CLK_DISP1 109
|
||||
#define MMP2_CLK_DISP1_MUX 110
|
||||
#define MMP2_CLK_CCIC_ARBITER 111
|
||||
#define MMP2_CLK_CCIC0 112
|
||||
#define MMP2_CLK_CCIC0_MIX 113
|
||||
#define MMP2_CLK_CCIC0_PHY 114
|
||||
#define MMP2_CLK_CCIC0_SPHY 115
|
||||
#define MMP2_CLK_CCIC1 116
|
||||
#define MMP2_CLK_CCIC1_MIX 117
|
||||
#define MMP2_CLK_CCIC1_PHY 118
|
||||
#define MMP2_CLK_CCIC1_SPHY 119
|
||||
|
||||
#define MMP2_NR_CLKS 200
|
||||
#endif
|
57
include/dt-bindings/clock/marvell,pxa168.h
Normal file
57
include/dt-bindings/clock/marvell,pxa168.h
Normal file
@ -0,0 +1,57 @@
|
||||
#ifndef __DTS_MARVELL_PXA168_CLOCK_H
|
||||
#define __DTS_MARVELL_PXA168_CLOCK_H
|
||||
|
||||
/* fixed clocks and plls */
|
||||
#define PXA168_CLK_CLK32 1
|
||||
#define PXA168_CLK_VCTCXO 2
|
||||
#define PXA168_CLK_PLL1 3
|
||||
#define PXA168_CLK_PLL1_2 8
|
||||
#define PXA168_CLK_PLL1_4 9
|
||||
#define PXA168_CLK_PLL1_8 10
|
||||
#define PXA168_CLK_PLL1_16 11
|
||||
#define PXA168_CLK_PLL1_6 12
|
||||
#define PXA168_CLK_PLL1_12 13
|
||||
#define PXA168_CLK_PLL1_24 14
|
||||
#define PXA168_CLK_PLL1_48 15
|
||||
#define PXA168_CLK_PLL1_96 16
|
||||
#define PXA168_CLK_PLL1_13 17
|
||||
#define PXA168_CLK_PLL1_13_1_5 18
|
||||
#define PXA168_CLK_PLL1_2_1_5 19
|
||||
#define PXA168_CLK_PLL1_3_16 20
|
||||
#define PXA168_CLK_UART_PLL 27
|
||||
|
||||
/* apb periphrals */
|
||||
#define PXA168_CLK_TWSI0 60
|
||||
#define PXA168_CLK_TWSI1 61
|
||||
#define PXA168_CLK_TWSI2 62
|
||||
#define PXA168_CLK_TWSI3 63
|
||||
#define PXA168_CLK_GPIO 64
|
||||
#define PXA168_CLK_KPC 65
|
||||
#define PXA168_CLK_RTC 66
|
||||
#define PXA168_CLK_PWM0 67
|
||||
#define PXA168_CLK_PWM1 68
|
||||
#define PXA168_CLK_PWM2 69
|
||||
#define PXA168_CLK_PWM3 70
|
||||
#define PXA168_CLK_UART0 71
|
||||
#define PXA168_CLK_UART1 72
|
||||
#define PXA168_CLK_UART2 73
|
||||
#define PXA168_CLK_SSP0 74
|
||||
#define PXA168_CLK_SSP1 75
|
||||
#define PXA168_CLK_SSP2 76
|
||||
#define PXA168_CLK_SSP3 77
|
||||
#define PXA168_CLK_SSP4 78
|
||||
|
||||
/* axi periphrals */
|
||||
#define PXA168_CLK_DFC 100
|
||||
#define PXA168_CLK_SDH0 101
|
||||
#define PXA168_CLK_SDH1 102
|
||||
#define PXA168_CLK_SDH2 103
|
||||
#define PXA168_CLK_USB 104
|
||||
#define PXA168_CLK_SPH 105
|
||||
#define PXA168_CLK_DISP0 106
|
||||
#define PXA168_CLK_CCIC0 107
|
||||
#define PXA168_CLK_CCIC0_PHY 108
|
||||
#define PXA168_CLK_CCIC0_SPHY 109
|
||||
|
||||
#define PXA168_NR_CLKS 200
|
||||
#endif
|
54
include/dt-bindings/clock/marvell,pxa910.h
Normal file
54
include/dt-bindings/clock/marvell,pxa910.h
Normal file
@ -0,0 +1,54 @@
|
||||
#ifndef __DTS_MARVELL_PXA910_CLOCK_H
|
||||
#define __DTS_MARVELL_PXA910_CLOCK_H
|
||||
|
||||
/* fixed clocks and plls */
|
||||
#define PXA910_CLK_CLK32 1
|
||||
#define PXA910_CLK_VCTCXO 2
|
||||
#define PXA910_CLK_PLL1 3
|
||||
#define PXA910_CLK_PLL1_2 8
|
||||
#define PXA910_CLK_PLL1_4 9
|
||||
#define PXA910_CLK_PLL1_8 10
|
||||
#define PXA910_CLK_PLL1_16 11
|
||||
#define PXA910_CLK_PLL1_6 12
|
||||
#define PXA910_CLK_PLL1_12 13
|
||||
#define PXA910_CLK_PLL1_24 14
|
||||
#define PXA910_CLK_PLL1_48 15
|
||||
#define PXA910_CLK_PLL1_96 16
|
||||
#define PXA910_CLK_PLL1_13 17
|
||||
#define PXA910_CLK_PLL1_13_1_5 18
|
||||
#define PXA910_CLK_PLL1_2_1_5 19
|
||||
#define PXA910_CLK_PLL1_3_16 20
|
||||
#define PXA910_CLK_UART_PLL 27
|
||||
|
||||
/* apb periphrals */
|
||||
#define PXA910_CLK_TWSI0 60
|
||||
#define PXA910_CLK_TWSI1 61
|
||||
#define PXA910_CLK_TWSI2 62
|
||||
#define PXA910_CLK_TWSI3 63
|
||||
#define PXA910_CLK_GPIO 64
|
||||
#define PXA910_CLK_KPC 65
|
||||
#define PXA910_CLK_RTC 66
|
||||
#define PXA910_CLK_PWM0 67
|
||||
#define PXA910_CLK_PWM1 68
|
||||
#define PXA910_CLK_PWM2 69
|
||||
#define PXA910_CLK_PWM3 70
|
||||
#define PXA910_CLK_UART0 71
|
||||
#define PXA910_CLK_UART1 72
|
||||
#define PXA910_CLK_UART2 73
|
||||
#define PXA910_CLK_SSP0 74
|
||||
#define PXA910_CLK_SSP1 75
|
||||
|
||||
/* axi periphrals */
|
||||
#define PXA910_CLK_DFC 100
|
||||
#define PXA910_CLK_SDH0 101
|
||||
#define PXA910_CLK_SDH1 102
|
||||
#define PXA910_CLK_SDH2 103
|
||||
#define PXA910_CLK_USB 104
|
||||
#define PXA910_CLK_SPH 105
|
||||
#define PXA910_CLK_DISP0 106
|
||||
#define PXA910_CLK_CCIC0 107
|
||||
#define PXA910_CLK_CCIC0_PHY 108
|
||||
#define PXA910_CLK_CCIC0_SPHY 109
|
||||
|
||||
#define PXA910_NR_CLKS 200
|
||||
#endif
|
Loading…
Reference in New Issue
Block a user