diff options
author | Olof Johansson <olof@lixom.net> | 2012-11-21 04:06:05 -0500 |
---|---|---|
committer | Olof Johansson <olof@lixom.net> | 2012-11-21 05:13:11 -0500 |
commit | 17bffc78438d010c3e57ad5c1956e3ab50be423a (patch) | |
tree | b69583a61ba780be64ce806c208bc170ff44fa4f /drivers/clk | |
parent | f86804af89686562fdeeabbdc0dfc6db9397f202 (diff) | |
parent | bcd6f569e87471d7f104bd9497f0b516a3b12e32 (diff) |
Merge branch 'depends/clk' into next/soc
From Mike Turquette:
* depends/clk:
clk: Common clocks implementation for Versatile Express
clk: Versatile Express clock generators ("osc") driver
CLK: clk-twl6040: Initial clock driver for OMAP4+ McPDM fclk clock
clk: fix return value check in sirfsoc_of_clk_init()
clk: fix return value check in of_fixed_clk_setup()
clk: ux500: Update sdmmc clock to 100MHz for u8500
clk: ux500: Support prcmu ape opp voltage clock
mfd: dbx500: Export prmcu_request_ape_opp_100_voltage
clk: Don't return negative numbers for unsigned values with !clk
clk: Fix documentation typos
clk: Document .is_enabled op
clk: SPEAr: Vco-pll: Fix compilation warning
Diffstat (limited to 'drivers/clk')
-rw-r--r-- | drivers/clk/Kconfig | 16 | ||||
-rw-r--r-- | drivers/clk/Makefile | 1 | ||||
-rw-r--r-- | drivers/clk/clk-fixed-rate.c | 2 | ||||
-rw-r--r-- | drivers/clk/clk-prima2.c | 84 | ||||
-rw-r--r-- | drivers/clk/clk-twl6040.c | 126 | ||||
-rw-r--r-- | drivers/clk/clk.c | 20 | ||||
-rw-r--r-- | drivers/clk/spear/clk-vco-pll.c | 2 | ||||
-rw-r--r-- | drivers/clk/ux500/clk-prcmu.c | 55 | ||||
-rw-r--r-- | drivers/clk/ux500/clk.h | 6 | ||||
-rw-r--r-- | drivers/clk/ux500/u8500_clk.c | 5 | ||||
-rw-r--r-- | drivers/clk/versatile/Makefile | 2 | ||||
-rw-r--r-- | drivers/clk/versatile/clk-vexpress-osc.c | 146 | ||||
-rw-r--r-- | drivers/clk/versatile/clk-vexpress.c | 142 |
13 files changed, 548 insertions, 59 deletions
diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig index bace9e98f75d..823f62d900ba 100644 --- a/drivers/clk/Kconfig +++ b/drivers/clk/Kconfig | |||
@@ -42,10 +42,12 @@ config COMMON_CLK_WM831X | |||
42 | 42 | ||
43 | config COMMON_CLK_VERSATILE | 43 | config COMMON_CLK_VERSATILE |
44 | bool "Clock driver for ARM Reference designs" | 44 | bool "Clock driver for ARM Reference designs" |
45 | depends on ARCH_INTEGRATOR || ARCH_REALVIEW | 45 | depends on ARCH_INTEGRATOR || ARCH_REALVIEW || ARCH_VEXPRESS |
46 | ---help--- | 46 | ---help--- |
47 | Supports clocking on ARM Reference designs Integrator/AP, | 47 | Supports clocking on ARM Reference designs: |
48 | Integrator/CP, RealView PB1176, EB, PB11MP and PBX. | 48 | - Integrator/AP and Integrator/CP |
49 | - RealView PB1176, EB, PB11MP and PBX | ||
50 | - Versatile Express | ||
49 | 51 | ||
50 | config COMMON_CLK_MAX77686 | 52 | config COMMON_CLK_MAX77686 |
51 | tristate "Clock driver for Maxim 77686 MFD" | 53 | tristate "Clock driver for Maxim 77686 MFD" |
@@ -53,4 +55,12 @@ config COMMON_CLK_MAX77686 | |||
53 | ---help--- | 55 | ---help--- |
54 | This driver supports Maxim 77686 crystal oscillator clock. | 56 | This driver supports Maxim 77686 crystal oscillator clock. |
55 | 57 | ||
58 | config CLK_TWL6040 | ||
59 | tristate "External McPDM functional clock from twl6040" | ||
60 | depends on TWL6040_CORE | ||
61 | ---help--- | ||
62 | Enable the external functional clock support on OMAP4+ platforms for | ||
63 | McPDM. McPDM module is using the external bit clock on the McPDM bus | ||
64 | as functional clock. | ||
65 | |||
56 | endmenu | 66 | endmenu |
diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile index 9c300a828ede..a96bda3d3b84 100644 --- a/drivers/clk/Makefile +++ b/drivers/clk/Makefile | |||
@@ -24,3 +24,4 @@ obj-$(CONFIG_ARCH_SUNXI) += clk-sunxi.o | |||
24 | # Chip specific | 24 | # Chip specific |
25 | obj-$(CONFIG_COMMON_CLK_WM831X) += clk-wm831x.o | 25 | obj-$(CONFIG_COMMON_CLK_WM831X) += clk-wm831x.o |
26 | obj-$(CONFIG_COMMON_CLK_MAX77686) += clk-max77686.o | 26 | obj-$(CONFIG_COMMON_CLK_MAX77686) += clk-max77686.o |
27 | obj-$(CONFIG_CLK_TWL6040) += clk-twl6040.o | ||
diff --git a/drivers/clk/clk-fixed-rate.c b/drivers/clk/clk-fixed-rate.c index f5ec0eebd4d7..af78ed6b67ef 100644 --- a/drivers/clk/clk-fixed-rate.c +++ b/drivers/clk/clk-fixed-rate.c | |||
@@ -97,7 +97,7 @@ void __init of_fixed_clk_setup(struct device_node *node) | |||
97 | of_property_read_string(node, "clock-output-names", &clk_name); | 97 | of_property_read_string(node, "clock-output-names", &clk_name); |
98 | 98 | ||
99 | clk = clk_register_fixed_rate(NULL, clk_name, NULL, CLK_IS_ROOT, rate); | 99 | clk = clk_register_fixed_rate(NULL, clk_name, NULL, CLK_IS_ROOT, rate); |
100 | if (clk) | 100 | if (!IS_ERR(clk)) |
101 | of_clk_add_provider(node, of_clk_src_simple_get, clk); | 101 | of_clk_add_provider(node, of_clk_src_simple_get, clk); |
102 | } | 102 | } |
103 | EXPORT_SYMBOL_GPL(of_fixed_clk_setup); | 103 | EXPORT_SYMBOL_GPL(of_fixed_clk_setup); |
diff --git a/drivers/clk/clk-prima2.c b/drivers/clk/clk-prima2.c index 517874fa6858..a203ecccdc4f 100644 --- a/drivers/clk/clk-prima2.c +++ b/drivers/clk/clk-prima2.c | |||
@@ -1054,118 +1054,118 @@ void __init sirfsoc_of_clk_init(void) | |||
1054 | /* These are always available (RTC and 26MHz OSC)*/ | 1054 | /* These are always available (RTC and 26MHz OSC)*/ |
1055 | clk = clk_register_fixed_rate(NULL, "rtc", NULL, | 1055 | clk = clk_register_fixed_rate(NULL, "rtc", NULL, |
1056 | CLK_IS_ROOT, 32768); | 1056 | CLK_IS_ROOT, 32768); |
1057 | BUG_ON(!clk); | 1057 | BUG_ON(IS_ERR(clk)); |
1058 | clk = clk_register_fixed_rate(NULL, "osc", NULL, | 1058 | clk = clk_register_fixed_rate(NULL, "osc", NULL, |
1059 | CLK_IS_ROOT, 26000000); | 1059 | CLK_IS_ROOT, 26000000); |
1060 | BUG_ON(!clk); | 1060 | BUG_ON(IS_ERR(clk)); |
1061 | 1061 | ||
1062 | clk = clk_register(NULL, &clk_pll1.hw); | 1062 | clk = clk_register(NULL, &clk_pll1.hw); |
1063 | BUG_ON(!clk); | 1063 | BUG_ON(IS_ERR(clk)); |
1064 | clk = clk_register(NULL, &clk_pll2.hw); | 1064 | clk = clk_register(NULL, &clk_pll2.hw); |
1065 | BUG_ON(!clk); | 1065 | BUG_ON(IS_ERR(clk)); |
1066 | clk = clk_register(NULL, &clk_pll3.hw); | 1066 | clk = clk_register(NULL, &clk_pll3.hw); |
1067 | BUG_ON(!clk); | 1067 | BUG_ON(IS_ERR(clk)); |
1068 | clk = clk_register(NULL, &clk_mem.hw); | 1068 | clk = clk_register(NULL, &clk_mem.hw); |
1069 | BUG_ON(!clk); | 1069 | BUG_ON(IS_ERR(clk)); |
1070 | clk = clk_register(NULL, &clk_sys.hw); | 1070 | clk = clk_register(NULL, &clk_sys.hw); |
1071 | BUG_ON(!clk); | 1071 | BUG_ON(IS_ERR(clk)); |
1072 | clk = clk_register(NULL, &clk_security.hw); | 1072 | clk = clk_register(NULL, &clk_security.hw); |
1073 | BUG_ON(!clk); | 1073 | BUG_ON(IS_ERR(clk)); |
1074 | clk_register_clkdev(clk, NULL, "b8030000.security"); | 1074 | clk_register_clkdev(clk, NULL, "b8030000.security"); |
1075 | clk = clk_register(NULL, &clk_dsp.hw); | 1075 | clk = clk_register(NULL, &clk_dsp.hw); |
1076 | BUG_ON(!clk); | 1076 | BUG_ON(IS_ERR(clk)); |
1077 | clk = clk_register(NULL, &clk_gps.hw); | 1077 | clk = clk_register(NULL, &clk_gps.hw); |
1078 | BUG_ON(!clk); | 1078 | BUG_ON(IS_ERR(clk)); |
1079 | clk_register_clkdev(clk, NULL, "a8010000.gps"); | 1079 | clk_register_clkdev(clk, NULL, "a8010000.gps"); |
1080 | clk = clk_register(NULL, &clk_mf.hw); | 1080 | clk = clk_register(NULL, &clk_mf.hw); |
1081 | BUG_ON(!clk); | 1081 | BUG_ON(IS_ERR(clk)); |
1082 | clk = clk_register(NULL, &clk_io.hw); | 1082 | clk = clk_register(NULL, &clk_io.hw); |
1083 | BUG_ON(!clk); | 1083 | BUG_ON(IS_ERR(clk)); |
1084 | clk_register_clkdev(clk, NULL, "io"); | 1084 | clk_register_clkdev(clk, NULL, "io"); |
1085 | clk = clk_register(NULL, &clk_cpu.hw); | 1085 | clk = clk_register(NULL, &clk_cpu.hw); |
1086 | BUG_ON(!clk); | 1086 | BUG_ON(IS_ERR(clk)); |
1087 | clk_register_clkdev(clk, NULL, "cpu"); | 1087 | clk_register_clkdev(clk, NULL, "cpu"); |
1088 | clk = clk_register(NULL, &clk_uart0.hw); | 1088 | clk = clk_register(NULL, &clk_uart0.hw); |
1089 | BUG_ON(!clk); | 1089 | BUG_ON(IS_ERR(clk)); |
1090 | clk_register_clkdev(clk, NULL, "b0050000.uart"); | 1090 | clk_register_clkdev(clk, NULL, "b0050000.uart"); |
1091 | clk = clk_register(NULL, &clk_uart1.hw); | 1091 | clk = clk_register(NULL, &clk_uart1.hw); |
1092 | BUG_ON(!clk); | 1092 | BUG_ON(IS_ERR(clk)); |
1093 | clk_register_clkdev(clk, NULL, "b0060000.uart"); | 1093 | clk_register_clkdev(clk, NULL, "b0060000.uart"); |
1094 | clk = clk_register(NULL, &clk_uart2.hw); | 1094 | clk = clk_register(NULL, &clk_uart2.hw); |
1095 | BUG_ON(!clk); | 1095 | BUG_ON(IS_ERR(clk)); |
1096 | clk_register_clkdev(clk, NULL, "b0070000.uart"); | 1096 | clk_register_clkdev(clk, NULL, "b0070000.uart"); |
1097 | clk = clk_register(NULL, &clk_tsc.hw); | 1097 | clk = clk_register(NULL, &clk_tsc.hw); |
1098 | BUG_ON(!clk); | 1098 | BUG_ON(IS_ERR(clk)); |
1099 | clk_register_clkdev(clk, NULL, "b0110000.tsc"); | 1099 | clk_register_clkdev(clk, NULL, "b0110000.tsc"); |
1100 | clk = clk_register(NULL, &clk_i2c0.hw); | 1100 | clk = clk_register(NULL, &clk_i2c0.hw); |
1101 | BUG_ON(!clk); | 1101 | BUG_ON(IS_ERR(clk)); |
1102 | clk_register_clkdev(clk, NULL, "b00e0000.i2c"); | 1102 | clk_register_clkdev(clk, NULL, "b00e0000.i2c"); |
1103 | clk = clk_register(NULL, &clk_i2c1.hw); | 1103 | clk = clk_register(NULL, &clk_i2c1.hw); |
1104 | BUG_ON(!clk); | 1104 | BUG_ON(IS_ERR(clk)); |
1105 | clk_register_clkdev(clk, NULL, "b00f0000.i2c"); | 1105 | clk_register_clkdev(clk, NULL, "b00f0000.i2c"); |
1106 | clk = clk_register(NULL, &clk_spi0.hw); | 1106 | clk = clk_register(NULL, &clk_spi0.hw); |
1107 | BUG_ON(!clk); | 1107 | BUG_ON(IS_ERR(clk)); |
1108 | clk_register_clkdev(clk, NULL, "b00d0000.spi"); | 1108 | clk_register_clkdev(clk, NULL, "b00d0000.spi"); |
1109 | clk = clk_register(NULL, &clk_spi1.hw); | 1109 | clk = clk_register(NULL, &clk_spi1.hw); |
1110 | BUG_ON(!clk); | 1110 | BUG_ON(IS_ERR(clk)); |
1111 | clk_register_clkdev(clk, NULL, "b0170000.spi"); | 1111 | clk_register_clkdev(clk, NULL, "b0170000.spi"); |
1112 | clk = clk_register(NULL, &clk_pwmc.hw); | 1112 | clk = clk_register(NULL, &clk_pwmc.hw); |
1113 | BUG_ON(!clk); | 1113 | BUG_ON(IS_ERR(clk)); |
1114 | clk_register_clkdev(clk, NULL, "b0130000.pwm"); | 1114 | clk_register_clkdev(clk, NULL, "b0130000.pwm"); |
1115 | clk = clk_register(NULL, &clk_efuse.hw); | 1115 | clk = clk_register(NULL, &clk_efuse.hw); |
1116 | BUG_ON(!clk); | 1116 | BUG_ON(IS_ERR(clk)); |
1117 | clk_register_clkdev(clk, NULL, "b0140000.efusesys"); | 1117 | clk_register_clkdev(clk, NULL, "b0140000.efusesys"); |
1118 | clk = clk_register(NULL, &clk_pulse.hw); | 1118 | clk = clk_register(NULL, &clk_pulse.hw); |
1119 | BUG_ON(!clk); | 1119 | BUG_ON(IS_ERR(clk)); |
1120 | clk_register_clkdev(clk, NULL, "b0150000.pulsec"); | 1120 | clk_register_clkdev(clk, NULL, "b0150000.pulsec"); |
1121 | clk = clk_register(NULL, &clk_dmac0.hw); | 1121 | clk = clk_register(NULL, &clk_dmac0.hw); |
1122 | BUG_ON(!clk); | 1122 | BUG_ON(IS_ERR(clk)); |
1123 | clk_register_clkdev(clk, NULL, "b00b0000.dma-controller"); | 1123 | clk_register_clkdev(clk, NULL, "b00b0000.dma-controller"); |
1124 | clk = clk_register(NULL, &clk_dmac1.hw); | 1124 | clk = clk_register(NULL, &clk_dmac1.hw); |
1125 | BUG_ON(!clk); | 1125 | BUG_ON(IS_ERR(clk)); |
1126 | clk_register_clkdev(clk, NULL, "b0160000.dma-controller"); | 1126 | clk_register_clkdev(clk, NULL, "b0160000.dma-controller"); |
1127 | clk = clk_register(NULL, &clk_nand.hw); | 1127 | clk = clk_register(NULL, &clk_nand.hw); |
1128 | BUG_ON(!clk); | 1128 | BUG_ON(IS_ERR(clk)); |
1129 | clk_register_clkdev(clk, NULL, "b0030000.nand"); | 1129 | clk_register_clkdev(clk, NULL, "b0030000.nand"); |
1130 | clk = clk_register(NULL, &clk_audio.hw); | 1130 | clk = clk_register(NULL, &clk_audio.hw); |
1131 | BUG_ON(!clk); | 1131 | BUG_ON(IS_ERR(clk)); |
1132 | clk_register_clkdev(clk, NULL, "b0040000.audio"); | 1132 | clk_register_clkdev(clk, NULL, "b0040000.audio"); |
1133 | clk = clk_register(NULL, &clk_usp0.hw); | 1133 | clk = clk_register(NULL, &clk_usp0.hw); |
1134 | BUG_ON(!clk); | 1134 | BUG_ON(IS_ERR(clk)); |
1135 | clk_register_clkdev(clk, NULL, "b0080000.usp"); | 1135 | clk_register_clkdev(clk, NULL, "b0080000.usp"); |
1136 | clk = clk_register(NULL, &clk_usp1.hw); | 1136 | clk = clk_register(NULL, &clk_usp1.hw); |
1137 | BUG_ON(!clk); | 1137 | BUG_ON(IS_ERR(clk)); |
1138 | clk_register_clkdev(clk, NULL, "b0090000.usp"); | 1138 | clk_register_clkdev(clk, NULL, "b0090000.usp"); |
1139 | clk = clk_register(NULL, &clk_usp2.hw); | 1139 | clk = clk_register(NULL, &clk_usp2.hw); |
1140 | BUG_ON(!clk); | 1140 | BUG_ON(IS_ERR(clk)); |
1141 | clk_register_clkdev(clk, NULL, "b00a0000.usp"); | 1141 | clk_register_clkdev(clk, NULL, "b00a0000.usp"); |
1142 | clk = clk_register(NULL, &clk_vip.hw); | 1142 | clk = clk_register(NULL, &clk_vip.hw); |
1143 | BUG_ON(!clk); | 1143 | BUG_ON(IS_ERR(clk)); |
1144 | clk_register_clkdev(clk, NULL, "b00c0000.vip"); | 1144 | clk_register_clkdev(clk, NULL, "b00c0000.vip"); |
1145 | clk = clk_register(NULL, &clk_gfx.hw); | 1145 | clk = clk_register(NULL, &clk_gfx.hw); |
1146 | BUG_ON(!clk); | 1146 | BUG_ON(IS_ERR(clk)); |
1147 | clk_register_clkdev(clk, NULL, "98000000.graphics"); | 1147 | clk_register_clkdev(clk, NULL, "98000000.graphics"); |
1148 | clk = clk_register(NULL, &clk_mm.hw); | 1148 | clk = clk_register(NULL, &clk_mm.hw); |
1149 | BUG_ON(!clk); | 1149 | BUG_ON(IS_ERR(clk)); |
1150 | clk_register_clkdev(clk, NULL, "a0000000.multimedia"); | 1150 | clk_register_clkdev(clk, NULL, "a0000000.multimedia"); |
1151 | clk = clk_register(NULL, &clk_lcd.hw); | 1151 | clk = clk_register(NULL, &clk_lcd.hw); |
1152 | BUG_ON(!clk); | 1152 | BUG_ON(IS_ERR(clk)); |
1153 | clk_register_clkdev(clk, NULL, "90010000.display"); | 1153 | clk_register_clkdev(clk, NULL, "90010000.display"); |
1154 | clk = clk_register(NULL, &clk_vpp.hw); | 1154 | clk = clk_register(NULL, &clk_vpp.hw); |
1155 | BUG_ON(!clk); | 1155 | BUG_ON(IS_ERR(clk)); |
1156 | clk_register_clkdev(clk, NULL, "90020000.vpp"); | 1156 | clk_register_clkdev(clk, NULL, "90020000.vpp"); |
1157 | clk = clk_register(NULL, &clk_mmc01.hw); | 1157 | clk = clk_register(NULL, &clk_mmc01.hw); |
1158 | BUG_ON(!clk); | 1158 | BUG_ON(IS_ERR(clk)); |
1159 | clk = clk_register(NULL, &clk_mmc23.hw); | 1159 | clk = clk_register(NULL, &clk_mmc23.hw); |
1160 | BUG_ON(!clk); | 1160 | BUG_ON(IS_ERR(clk)); |
1161 | clk = clk_register(NULL, &clk_mmc45.hw); | 1161 | clk = clk_register(NULL, &clk_mmc45.hw); |
1162 | BUG_ON(!clk); | 1162 | BUG_ON(IS_ERR(clk)); |
1163 | clk = clk_register(NULL, &usb_pll_clk_hw); | 1163 | clk = clk_register(NULL, &usb_pll_clk_hw); |
1164 | BUG_ON(!clk); | 1164 | BUG_ON(IS_ERR(clk)); |
1165 | clk = clk_register(NULL, &clk_usb0.hw); | 1165 | clk = clk_register(NULL, &clk_usb0.hw); |
1166 | BUG_ON(!clk); | 1166 | BUG_ON(IS_ERR(clk)); |
1167 | clk_register_clkdev(clk, NULL, "b00e0000.usb"); | 1167 | clk_register_clkdev(clk, NULL, "b00e0000.usb"); |
1168 | clk = clk_register(NULL, &clk_usb1.hw); | 1168 | clk = clk_register(NULL, &clk_usb1.hw); |
1169 | BUG_ON(!clk); | 1169 | BUG_ON(IS_ERR(clk)); |
1170 | clk_register_clkdev(clk, NULL, "b00f0000.usb"); | 1170 | clk_register_clkdev(clk, NULL, "b00f0000.usb"); |
1171 | } | 1171 | } |
diff --git a/drivers/clk/clk-twl6040.c b/drivers/clk/clk-twl6040.c new file mode 100644 index 000000000000..f4a3389c3d09 --- /dev/null +++ b/drivers/clk/clk-twl6040.c | |||
@@ -0,0 +1,126 @@ | |||
1 | /* | ||
2 | * TWL6040 clock module driver for OMAP4 McPDM functional clock | ||
3 | * | ||
4 | * Copyright (C) 2012 Texas Instruments Inc. | ||
5 | * Peter Ujfalusi <peter.ujfalusi@ti.com> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or | ||
8 | * modify it under the terms of the GNU General Public License | ||
9 | * version 2 as published by the Free Software Foundation. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, but | ||
12 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
14 | * General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License | ||
17 | * along with this program; if not, write to the Free Software | ||
18 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA | ||
19 | * 02110-1301 USA | ||
20 | * | ||
21 | */ | ||
22 | |||
23 | #include <linux/clk.h> | ||
24 | #include <linux/module.h> | ||
25 | #include <linux/slab.h> | ||
26 | #include <linux/platform_device.h> | ||
27 | #include <linux/mfd/twl6040.h> | ||
28 | #include <linux/clk-provider.h> | ||
29 | |||
30 | struct twl6040_clk { | ||
31 | struct twl6040 *twl6040; | ||
32 | struct device *dev; | ||
33 | struct clk_hw mcpdm_fclk; | ||
34 | struct clk *clk; | ||
35 | int enabled; | ||
36 | }; | ||
37 | |||
38 | static int twl6040_bitclk_is_enabled(struct clk_hw *hw) | ||
39 | { | ||
40 | struct twl6040_clk *twl6040_clk = container_of(hw, struct twl6040_clk, | ||
41 | mcpdm_fclk); | ||
42 | return twl6040_clk->enabled; | ||
43 | } | ||
44 | |||
45 | static int twl6040_bitclk_prepare(struct clk_hw *hw) | ||
46 | { | ||
47 | struct twl6040_clk *twl6040_clk = container_of(hw, struct twl6040_clk, | ||
48 | mcpdm_fclk); | ||
49 | int ret; | ||
50 | |||
51 | ret = twl6040_power(twl6040_clk->twl6040, 1); | ||
52 | if (!ret) | ||
53 | twl6040_clk->enabled = 1; | ||
54 | |||
55 | return ret; | ||
56 | } | ||
57 | |||
58 | static void twl6040_bitclk_unprepare(struct clk_hw *hw) | ||
59 | { | ||
60 | struct twl6040_clk *twl6040_clk = container_of(hw, struct twl6040_clk, | ||
61 | mcpdm_fclk); | ||
62 | int ret; | ||
63 | |||
64 | ret = twl6040_power(twl6040_clk->twl6040, 0); | ||
65 | if (!ret) | ||
66 | twl6040_clk->enabled = 0; | ||
67 | } | ||
68 | |||
69 | static const struct clk_ops twl6040_mcpdm_ops = { | ||
70 | .is_enabled = twl6040_bitclk_is_enabled, | ||
71 | .prepare = twl6040_bitclk_prepare, | ||
72 | .unprepare = twl6040_bitclk_unprepare, | ||
73 | }; | ||
74 | |||
75 | static struct clk_init_data wm831x_clkout_init = { | ||
76 | .name = "mcpdm_fclk", | ||
77 | .ops = &twl6040_mcpdm_ops, | ||
78 | .flags = CLK_IS_ROOT, | ||
79 | }; | ||
80 | |||
81 | static int __devinit twl6040_clk_probe(struct platform_device *pdev) | ||
82 | { | ||
83 | struct twl6040 *twl6040 = dev_get_drvdata(pdev->dev.parent); | ||
84 | struct twl6040_clk *clkdata; | ||
85 | |||
86 | clkdata = devm_kzalloc(&pdev->dev, sizeof(*clkdata), GFP_KERNEL); | ||
87 | if (!clkdata) | ||
88 | return -ENOMEM; | ||
89 | |||
90 | clkdata->dev = &pdev->dev; | ||
91 | clkdata->twl6040 = twl6040; | ||
92 | |||
93 | clkdata->mcpdm_fclk.init = &wm831x_clkout_init; | ||
94 | clkdata->clk = clk_register(&pdev->dev, &clkdata->mcpdm_fclk); | ||
95 | if (!clkdata->clk) | ||
96 | return -EINVAL; | ||
97 | |||
98 | dev_set_drvdata(&pdev->dev, clkdata); | ||
99 | |||
100 | return 0; | ||
101 | } | ||
102 | |||
103 | static int __devexit twl6040_clk_remove(struct platform_device *pdev) | ||
104 | { | ||
105 | struct twl6040_clk *clkdata = dev_get_drvdata(&pdev->dev); | ||
106 | |||
107 | clk_unregister(clkdata->clk); | ||
108 | |||
109 | return 0; | ||
110 | } | ||
111 | |||
112 | static struct platform_driver twl6040_clk_driver = { | ||
113 | .driver = { | ||
114 | .name = "twl6040-clk", | ||
115 | .owner = THIS_MODULE, | ||
116 | }, | ||
117 | .probe = twl6040_clk_probe, | ||
118 | .remove = __devexit_p(twl6040_clk_remove), | ||
119 | }; | ||
120 | |||
121 | module_platform_driver(twl6040_clk_driver); | ||
122 | |||
123 | MODULE_DESCRIPTION("TWL6040 clock driver for McPDM functional clock"); | ||
124 | MODULE_AUTHOR("Peter Ujfalusi <peter.ujfalusi@ti.com>"); | ||
125 | MODULE_ALIAS("platform:twl6040-clk"); | ||
126 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c index 56e4495ebeb1..bbe52c4ae7ca 100644 --- a/drivers/clk/clk.c +++ b/drivers/clk/clk.c | |||
@@ -261,7 +261,7 @@ inline struct clk_hw *__clk_get_hw(struct clk *clk) | |||
261 | 261 | ||
262 | inline u8 __clk_get_num_parents(struct clk *clk) | 262 | inline u8 __clk_get_num_parents(struct clk *clk) |
263 | { | 263 | { |
264 | return !clk ? -EINVAL : clk->num_parents; | 264 | return !clk ? 0 : clk->num_parents; |
265 | } | 265 | } |
266 | 266 | ||
267 | inline struct clk *__clk_get_parent(struct clk *clk) | 267 | inline struct clk *__clk_get_parent(struct clk *clk) |
@@ -269,14 +269,14 @@ inline struct clk *__clk_get_parent(struct clk *clk) | |||
269 | return !clk ? NULL : clk->parent; | 269 | return !clk ? NULL : clk->parent; |
270 | } | 270 | } |
271 | 271 | ||
272 | inline int __clk_get_enable_count(struct clk *clk) | 272 | inline unsigned int __clk_get_enable_count(struct clk *clk) |
273 | { | 273 | { |
274 | return !clk ? -EINVAL : clk->enable_count; | 274 | return !clk ? 0 : clk->enable_count; |
275 | } | 275 | } |
276 | 276 | ||
277 | inline int __clk_get_prepare_count(struct clk *clk) | 277 | inline unsigned int __clk_get_prepare_count(struct clk *clk) |
278 | { | 278 | { |
279 | return !clk ? -EINVAL : clk->prepare_count; | 279 | return !clk ? 0 : clk->prepare_count; |
280 | } | 280 | } |
281 | 281 | ||
282 | unsigned long __clk_get_rate(struct clk *clk) | 282 | unsigned long __clk_get_rate(struct clk *clk) |
@@ -302,15 +302,15 @@ out: | |||
302 | 302 | ||
303 | inline unsigned long __clk_get_flags(struct clk *clk) | 303 | inline unsigned long __clk_get_flags(struct clk *clk) |
304 | { | 304 | { |
305 | return !clk ? -EINVAL : clk->flags; | 305 | return !clk ? 0 : clk->flags; |
306 | } | 306 | } |
307 | 307 | ||
308 | int __clk_is_enabled(struct clk *clk) | 308 | bool __clk_is_enabled(struct clk *clk) |
309 | { | 309 | { |
310 | int ret; | 310 | int ret; |
311 | 311 | ||
312 | if (!clk) | 312 | if (!clk) |
313 | return -EINVAL; | 313 | return false; |
314 | 314 | ||
315 | /* | 315 | /* |
316 | * .is_enabled is only mandatory for clocks that gate | 316 | * .is_enabled is only mandatory for clocks that gate |
@@ -323,7 +323,7 @@ int __clk_is_enabled(struct clk *clk) | |||
323 | 323 | ||
324 | ret = clk->ops->is_enabled(clk->hw); | 324 | ret = clk->ops->is_enabled(clk->hw); |
325 | out: | 325 | out: |
326 | return ret; | 326 | return !!ret; |
327 | } | 327 | } |
328 | 328 | ||
329 | static struct clk *__clk_lookup_subtree(const char *name, struct clk *clk) | 329 | static struct clk *__clk_lookup_subtree(const char *name, struct clk *clk) |
@@ -568,7 +568,7 @@ unsigned long __clk_round_rate(struct clk *clk, unsigned long rate) | |||
568 | unsigned long parent_rate = 0; | 568 | unsigned long parent_rate = 0; |
569 | 569 | ||
570 | if (!clk) | 570 | if (!clk) |
571 | return -EINVAL; | 571 | return 0; |
572 | 572 | ||
573 | if (!clk->ops->round_rate) { | 573 | if (!clk->ops->round_rate) { |
574 | if (clk->flags & CLK_SET_RATE_PARENT) | 574 | if (clk->flags & CLK_SET_RATE_PARENT) |
diff --git a/drivers/clk/spear/clk-vco-pll.c b/drivers/clk/spear/clk-vco-pll.c index 5f1b6badeb15..1b9b65bca51e 100644 --- a/drivers/clk/spear/clk-vco-pll.c +++ b/drivers/clk/spear/clk-vco-pll.c | |||
@@ -147,7 +147,7 @@ static int clk_pll_set_rate(struct clk_hw *hw, unsigned long drate, | |||
147 | struct clk_pll *pll = to_clk_pll(hw); | 147 | struct clk_pll *pll = to_clk_pll(hw); |
148 | struct pll_rate_tbl *rtbl = pll->vco->rtbl; | 148 | struct pll_rate_tbl *rtbl = pll->vco->rtbl; |
149 | unsigned long flags = 0, val; | 149 | unsigned long flags = 0, val; |
150 | int i; | 150 | int uninitialized_var(i); |
151 | 151 | ||
152 | clk_pll_round_rate_index(hw, drate, NULL, &i); | 152 | clk_pll_round_rate_index(hw, drate, NULL, &i); |
153 | 153 | ||
diff --git a/drivers/clk/ux500/clk-prcmu.c b/drivers/clk/ux500/clk-prcmu.c index 930cdfeb47ab..04577ca6a308 100644 --- a/drivers/clk/ux500/clk-prcmu.c +++ b/drivers/clk/ux500/clk-prcmu.c | |||
@@ -133,6 +133,40 @@ out_error: | |||
133 | hw->init->name); | 133 | hw->init->name); |
134 | } | 134 | } |
135 | 135 | ||
136 | static int clk_prcmu_opp_volt_prepare(struct clk_hw *hw) | ||
137 | { | ||
138 | int err; | ||
139 | struct clk_prcmu *clk = to_clk_prcmu(hw); | ||
140 | |||
141 | err = prcmu_request_ape_opp_100_voltage(true); | ||
142 | if (err) { | ||
143 | pr_err("clk_prcmu: %s failed to request APE OPP VOLT for %s.\n", | ||
144 | __func__, hw->init->name); | ||
145 | return err; | ||
146 | } | ||
147 | |||
148 | err = prcmu_request_clock(clk->cg_sel, true); | ||
149 | if (err) | ||
150 | prcmu_request_ape_opp_100_voltage(false); | ||
151 | |||
152 | return err; | ||
153 | } | ||
154 | |||
155 | static void clk_prcmu_opp_volt_unprepare(struct clk_hw *hw) | ||
156 | { | ||
157 | struct clk_prcmu *clk = to_clk_prcmu(hw); | ||
158 | |||
159 | if (prcmu_request_clock(clk->cg_sel, false)) | ||
160 | goto out_error; | ||
161 | if (prcmu_request_ape_opp_100_voltage(false)) | ||
162 | goto out_error; | ||
163 | return; | ||
164 | |||
165 | out_error: | ||
166 | pr_err("clk_prcmu: %s failed to disable %s.\n", __func__, | ||
167 | hw->init->name); | ||
168 | } | ||
169 | |||
136 | static struct clk_ops clk_prcmu_scalable_ops = { | 170 | static struct clk_ops clk_prcmu_scalable_ops = { |
137 | .prepare = clk_prcmu_prepare, | 171 | .prepare = clk_prcmu_prepare, |
138 | .unprepare = clk_prcmu_unprepare, | 172 | .unprepare = clk_prcmu_unprepare, |
@@ -167,6 +201,17 @@ static struct clk_ops clk_prcmu_opp_gate_ops = { | |||
167 | .recalc_rate = clk_prcmu_recalc_rate, | 201 | .recalc_rate = clk_prcmu_recalc_rate, |
168 | }; | 202 | }; |
169 | 203 | ||
204 | static struct clk_ops clk_prcmu_opp_volt_scalable_ops = { | ||
205 | .prepare = clk_prcmu_opp_volt_prepare, | ||
206 | .unprepare = clk_prcmu_opp_volt_unprepare, | ||
207 | .enable = clk_prcmu_enable, | ||
208 | .disable = clk_prcmu_disable, | ||
209 | .is_enabled = clk_prcmu_is_enabled, | ||
210 | .recalc_rate = clk_prcmu_recalc_rate, | ||
211 | .round_rate = clk_prcmu_round_rate, | ||
212 | .set_rate = clk_prcmu_set_rate, | ||
213 | }; | ||
214 | |||
170 | static struct clk *clk_reg_prcmu(const char *name, | 215 | static struct clk *clk_reg_prcmu(const char *name, |
171 | const char *parent_name, | 216 | const char *parent_name, |
172 | u8 cg_sel, | 217 | u8 cg_sel, |
@@ -250,3 +295,13 @@ struct clk *clk_reg_prcmu_opp_gate(const char *name, | |||
250 | return clk_reg_prcmu(name, parent_name, cg_sel, 0, flags, | 295 | return clk_reg_prcmu(name, parent_name, cg_sel, 0, flags, |
251 | &clk_prcmu_opp_gate_ops); | 296 | &clk_prcmu_opp_gate_ops); |
252 | } | 297 | } |
298 | |||
299 | struct clk *clk_reg_prcmu_opp_volt_scalable(const char *name, | ||
300 | const char *parent_name, | ||
301 | u8 cg_sel, | ||
302 | unsigned long rate, | ||
303 | unsigned long flags) | ||
304 | { | ||
305 | return clk_reg_prcmu(name, parent_name, cg_sel, rate, flags, | ||
306 | &clk_prcmu_opp_volt_scalable_ops); | ||
307 | } | ||
diff --git a/drivers/clk/ux500/clk.h b/drivers/clk/ux500/clk.h index 836d7d16751e..f36eeedca493 100644 --- a/drivers/clk/ux500/clk.h +++ b/drivers/clk/ux500/clk.h | |||
@@ -45,4 +45,10 @@ struct clk *clk_reg_prcmu_opp_gate(const char *name, | |||
45 | u8 cg_sel, | 45 | u8 cg_sel, |
46 | unsigned long flags); | 46 | unsigned long flags); |
47 | 47 | ||
48 | struct clk *clk_reg_prcmu_opp_volt_scalable(const char *name, | ||
49 | const char *parent_name, | ||
50 | u8 cg_sel, | ||
51 | unsigned long rate, | ||
52 | unsigned long flags); | ||
53 | |||
48 | #endif /* __UX500_CLK_H */ | 54 | #endif /* __UX500_CLK_H */ |
diff --git a/drivers/clk/ux500/u8500_clk.c b/drivers/clk/ux500/u8500_clk.c index ca4a25ed844c..7bebf1f62c65 100644 --- a/drivers/clk/ux500/u8500_clk.c +++ b/drivers/clk/ux500/u8500_clk.c | |||
@@ -170,10 +170,11 @@ void u8500_clk_init(void) | |||
170 | clk_register_clkdev(clk, NULL, "mtu0"); | 170 | clk_register_clkdev(clk, NULL, "mtu0"); |
171 | clk_register_clkdev(clk, NULL, "mtu1"); | 171 | clk_register_clkdev(clk, NULL, "mtu1"); |
172 | 172 | ||
173 | clk = clk_reg_prcmu_gate("sdmmcclk", NULL, PRCMU_SDMMCCLK, CLK_IS_ROOT); | 173 | clk = clk_reg_prcmu_opp_volt_scalable("sdmmcclk", NULL, PRCMU_SDMMCCLK, |
174 | 100000000, | ||
175 | CLK_IS_ROOT|CLK_SET_RATE_GATE); | ||
174 | clk_register_clkdev(clk, NULL, "sdmmc"); | 176 | clk_register_clkdev(clk, NULL, "sdmmc"); |
175 | 177 | ||
176 | |||
177 | clk = clk_reg_prcmu_scalable("dsi_pll", "hdmiclk", | 178 | clk = clk_reg_prcmu_scalable("dsi_pll", "hdmiclk", |
178 | PRCMU_PLLDSI, 0, CLK_SET_RATE_GATE); | 179 | PRCMU_PLLDSI, 0, CLK_SET_RATE_GATE); |
179 | clk_register_clkdev(clk, "dsihs2", "mcde"); | 180 | clk_register_clkdev(clk, "dsihs2", "mcde"); |
diff --git a/drivers/clk/versatile/Makefile b/drivers/clk/versatile/Makefile index c0a0f6478798..c776053e5bb4 100644 --- a/drivers/clk/versatile/Makefile +++ b/drivers/clk/versatile/Makefile | |||
@@ -2,3 +2,5 @@ | |||
2 | obj-$(CONFIG_ICST) += clk-icst.o | 2 | obj-$(CONFIG_ICST) += clk-icst.o |
3 | obj-$(CONFIG_ARCH_INTEGRATOR) += clk-integrator.o | 3 | obj-$(CONFIG_ARCH_INTEGRATOR) += clk-integrator.o |
4 | obj-$(CONFIG_ARCH_REALVIEW) += clk-realview.o | 4 | obj-$(CONFIG_ARCH_REALVIEW) += clk-realview.o |
5 | obj-$(CONFIG_ARCH_VEXPRESS) += clk-vexpress.o | ||
6 | obj-$(CONFIG_VEXPRESS_CONFIG) += clk-vexpress-osc.o | ||
diff --git a/drivers/clk/versatile/clk-vexpress-osc.c b/drivers/clk/versatile/clk-vexpress-osc.c new file mode 100644 index 000000000000..dcb6ae0a0425 --- /dev/null +++ b/drivers/clk/versatile/clk-vexpress-osc.c | |||
@@ -0,0 +1,146 @@ | |||
1 | /* | ||
2 | * This program is free software; you can redistribute it and/or modify | ||
3 | * it under the terms of the GNU General Public License version 2 as | ||
4 | * published by the Free Software Foundation. | ||
5 | * | ||
6 | * This program is distributed in the hope that it will be useful, | ||
7 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
8 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
9 | * GNU General Public License for more details. | ||
10 | * | ||
11 | * Copyright (C) 2012 ARM Limited | ||
12 | */ | ||
13 | |||
14 | #define pr_fmt(fmt) "vexpress-osc: " fmt | ||
15 | |||
16 | #include <linux/clkdev.h> | ||
17 | #include <linux/clk-provider.h> | ||
18 | #include <linux/err.h> | ||
19 | #include <linux/of.h> | ||
20 | #include <linux/platform_device.h> | ||
21 | #include <linux/slab.h> | ||
22 | #include <linux/vexpress.h> | ||
23 | |||
24 | struct vexpress_osc { | ||
25 | struct vexpress_config_func *func; | ||
26 | struct clk_hw hw; | ||
27 | unsigned long rate_min; | ||
28 | unsigned long rate_max; | ||
29 | }; | ||
30 | |||
31 | #define to_vexpress_osc(osc) container_of(osc, struct vexpress_osc, hw) | ||
32 | |||
33 | static unsigned long vexpress_osc_recalc_rate(struct clk_hw *hw, | ||
34 | unsigned long parent_rate) | ||
35 | { | ||
36 | struct vexpress_osc *osc = to_vexpress_osc(hw); | ||
37 | u32 rate; | ||
38 | |||
39 | vexpress_config_read(osc->func, 0, &rate); | ||
40 | |||
41 | return rate; | ||
42 | } | ||
43 | |||
44 | static long vexpress_osc_round_rate(struct clk_hw *hw, unsigned long rate, | ||
45 | unsigned long *parent_rate) | ||
46 | { | ||
47 | struct vexpress_osc *osc = to_vexpress_osc(hw); | ||
48 | |||
49 | if (WARN_ON(osc->rate_min && rate < osc->rate_min)) | ||
50 | rate = osc->rate_min; | ||
51 | |||
52 | if (WARN_ON(osc->rate_max && rate > osc->rate_max)) | ||
53 | rate = osc->rate_max; | ||
54 | |||
55 | return rate; | ||
56 | } | ||
57 | |||
58 | static int vexpress_osc_set_rate(struct clk_hw *hw, unsigned long rate, | ||
59 | unsigned long parent_rate) | ||
60 | { | ||
61 | struct vexpress_osc *osc = to_vexpress_osc(hw); | ||
62 | |||
63 | return vexpress_config_write(osc->func, 0, rate); | ||
64 | } | ||
65 | |||
66 | static struct clk_ops vexpress_osc_ops = { | ||
67 | .recalc_rate = vexpress_osc_recalc_rate, | ||
68 | .round_rate = vexpress_osc_round_rate, | ||
69 | .set_rate = vexpress_osc_set_rate, | ||
70 | }; | ||
71 | |||
72 | |||
73 | struct clk * __init vexpress_osc_setup(struct device *dev) | ||
74 | { | ||
75 | struct clk_init_data init; | ||
76 | struct vexpress_osc *osc = kzalloc(sizeof(*osc), GFP_KERNEL); | ||
77 | |||
78 | if (!osc) | ||
79 | return NULL; | ||
80 | |||
81 | osc->func = vexpress_config_func_get_by_dev(dev); | ||
82 | if (!osc->func) { | ||
83 | kfree(osc); | ||
84 | return NULL; | ||
85 | } | ||
86 | |||
87 | init.name = dev_name(dev); | ||
88 | init.ops = &vexpress_osc_ops; | ||
89 | init.flags = CLK_IS_ROOT; | ||
90 | init.num_parents = 0; | ||
91 | osc->hw.init = &init; | ||
92 | |||
93 | return clk_register(NULL, &osc->hw); | ||
94 | } | ||
95 | |||
96 | void __init vexpress_osc_of_setup(struct device_node *node) | ||
97 | { | ||
98 | struct clk_init_data init; | ||
99 | struct vexpress_osc *osc; | ||
100 | struct clk *clk; | ||
101 | u32 range[2]; | ||
102 | |||
103 | osc = kzalloc(sizeof(*osc), GFP_KERNEL); | ||
104 | if (!osc) | ||
105 | goto error; | ||
106 | |||
107 | osc->func = vexpress_config_func_get_by_node(node); | ||
108 | if (!osc->func) { | ||
109 | pr_err("Failed to obtain config func for node '%s'!\n", | ||
110 | node->name); | ||
111 | goto error; | ||
112 | } | ||
113 | |||
114 | if (of_property_read_u32_array(node, "freq-range", range, | ||
115 | ARRAY_SIZE(range)) == 0) { | ||
116 | osc->rate_min = range[0]; | ||
117 | osc->rate_max = range[1]; | ||
118 | } | ||
119 | |||
120 | of_property_read_string(node, "clock-output-names", &init.name); | ||
121 | if (!init.name) | ||
122 | init.name = node->name; | ||
123 | |||
124 | init.ops = &vexpress_osc_ops; | ||
125 | init.flags = CLK_IS_ROOT; | ||
126 | init.num_parents = 0; | ||
127 | |||
128 | osc->hw.init = &init; | ||
129 | |||
130 | clk = clk_register(NULL, &osc->hw); | ||
131 | if (IS_ERR(clk)) { | ||
132 | pr_err("Failed to register clock '%s'!\n", init.name); | ||
133 | goto error; | ||
134 | } | ||
135 | |||
136 | of_clk_add_provider(node, of_clk_src_simple_get, clk); | ||
137 | |||
138 | pr_debug("Registered clock '%s'\n", init.name); | ||
139 | |||
140 | return; | ||
141 | |||
142 | error: | ||
143 | if (osc->func) | ||
144 | vexpress_config_func_put(osc->func); | ||
145 | kfree(osc); | ||
146 | } | ||
diff --git a/drivers/clk/versatile/clk-vexpress.c b/drivers/clk/versatile/clk-vexpress.c new file mode 100644 index 000000000000..c742ac7c60bb --- /dev/null +++ b/drivers/clk/versatile/clk-vexpress.c | |||
@@ -0,0 +1,142 @@ | |||
1 | /* | ||
2 | * This program is free software; you can redistribute it and/or modify | ||
3 | * it under the terms of the GNU General Public License version 2 as | ||
4 | * published by the Free Software Foundation. | ||
5 | * | ||
6 | * This program is distributed in the hope that it will be useful, | ||
7 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
8 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
9 | * GNU General Public License for more details. | ||
10 | * | ||
11 | * Copyright (C) 2012 ARM Limited | ||
12 | */ | ||
13 | |||
14 | #include <linux/clkdev.h> | ||
15 | #include <linux/clk-provider.h> | ||
16 | #include <linux/err.h> | ||
17 | #include <linux/of.h> | ||
18 | #include <linux/of_address.h> | ||
19 | #include <linux/vexpress.h> | ||
20 | |||
21 | #include <asm/hardware/sp810.h> | ||
22 | |||
23 | static struct clk *vexpress_sp810_timerclken[4]; | ||
24 | static DEFINE_SPINLOCK(vexpress_sp810_lock); | ||
25 | |||
26 | static void __init vexpress_sp810_init(void __iomem *base) | ||
27 | { | ||
28 | int i; | ||
29 | |||
30 | if (WARN_ON(!base)) | ||
31 | return; | ||
32 | |||
33 | for (i = 0; i < ARRAY_SIZE(vexpress_sp810_timerclken); i++) { | ||
34 | char name[12]; | ||
35 | const char *parents[] = { | ||
36 | "v2m:refclk32khz", /* REFCLK */ | ||
37 | "v2m:refclk1mhz" /* TIMCLK */ | ||
38 | }; | ||
39 | |||
40 | snprintf(name, ARRAY_SIZE(name), "timerclken%d", i); | ||
41 | |||
42 | vexpress_sp810_timerclken[i] = clk_register_mux(NULL, name, | ||
43 | parents, 2, 0, base + SCCTRL, | ||
44 | SCCTRL_TIMERENnSEL_SHIFT(i), 1, | ||
45 | 0, &vexpress_sp810_lock); | ||
46 | |||
47 | if (WARN_ON(IS_ERR(vexpress_sp810_timerclken[i]))) | ||
48 | break; | ||
49 | } | ||
50 | } | ||
51 | |||
52 | |||
53 | static const char * const vexpress_clk_24mhz_periphs[] __initconst = { | ||
54 | "mb:uart0", "mb:uart1", "mb:uart2", "mb:uart3", | ||
55 | "mb:mmci", "mb:kmi0", "mb:kmi1" | ||
56 | }; | ||
57 | |||
58 | void __init vexpress_clk_init(void __iomem *sp810_base) | ||
59 | { | ||
60 | struct clk *clk; | ||
61 | int i; | ||
62 | |||
63 | clk = clk_register_fixed_rate(NULL, "dummy_apb_pclk", NULL, | ||
64 | CLK_IS_ROOT, 0); | ||
65 | WARN_ON(clk_register_clkdev(clk, "apb_pclk", NULL)); | ||
66 | |||
67 | clk = clk_register_fixed_rate(NULL, "v2m:clk_24mhz", NULL, | ||
68 | CLK_IS_ROOT, 24000000); | ||
69 | for (i = 0; i < ARRAY_SIZE(vexpress_clk_24mhz_periphs); i++) | ||
70 | WARN_ON(clk_register_clkdev(clk, NULL, | ||
71 | vexpress_clk_24mhz_periphs[i])); | ||
72 | |||
73 | clk = clk_register_fixed_rate(NULL, "v2m:refclk32khz", NULL, | ||
74 | CLK_IS_ROOT, 32768); | ||
75 | WARN_ON(clk_register_clkdev(clk, NULL, "v2m:wdt")); | ||
76 | |||
77 | clk = clk_register_fixed_rate(NULL, "v2m:refclk1mhz", NULL, | ||
78 | CLK_IS_ROOT, 1000000); | ||
79 | |||
80 | vexpress_sp810_init(sp810_base); | ||
81 | |||
82 | for (i = 0; i < ARRAY_SIZE(vexpress_sp810_timerclken); i++) | ||
83 | WARN_ON(clk_set_parent(vexpress_sp810_timerclken[i], clk)); | ||
84 | |||
85 | WARN_ON(clk_register_clkdev(vexpress_sp810_timerclken[0], | ||
86 | "v2m-timer0", "sp804")); | ||
87 | WARN_ON(clk_register_clkdev(vexpress_sp810_timerclken[1], | ||
88 | "v2m-timer1", "sp804")); | ||
89 | } | ||
90 | |||
91 | #if defined(CONFIG_OF) | ||
92 | |||
93 | struct clk *vexpress_sp810_of_get(struct of_phandle_args *clkspec, void *data) | ||
94 | { | ||
95 | if (WARN_ON(clkspec->args_count != 1 || clkspec->args[0] > | ||
96 | ARRAY_SIZE(vexpress_sp810_timerclken))) | ||
97 | return NULL; | ||
98 | |||
99 | return vexpress_sp810_timerclken[clkspec->args[0]]; | ||
100 | } | ||
101 | |||
102 | static const __initconst struct of_device_id vexpress_fixed_clk_match[] = { | ||
103 | { .compatible = "fixed-clock", .data = of_fixed_clk_setup, }, | ||
104 | { .compatible = "arm,vexpress-osc", .data = vexpress_osc_of_setup, }, | ||
105 | {} | ||
106 | }; | ||
107 | |||
108 | void __init vexpress_clk_of_init(void) | ||
109 | { | ||
110 | struct device_node *node; | ||
111 | struct clk *clk; | ||
112 | struct clk *refclk, *timclk; | ||
113 | |||
114 | of_clk_init(vexpress_fixed_clk_match); | ||
115 | |||
116 | node = of_find_compatible_node(NULL, NULL, "arm,sp810"); | ||
117 | vexpress_sp810_init(of_iomap(node, 0)); | ||
118 | of_clk_add_provider(node, vexpress_sp810_of_get, NULL); | ||
119 | |||
120 | /* Select "better" (faster) parent for SP804 timers */ | ||
121 | refclk = of_clk_get_by_name(node, "refclk"); | ||
122 | timclk = of_clk_get_by_name(node, "timclk"); | ||
123 | if (!WARN_ON(IS_ERR(refclk) || IS_ERR(timclk))) { | ||
124 | int i = 0; | ||
125 | |||
126 | if (clk_get_rate(refclk) > clk_get_rate(timclk)) | ||
127 | clk = refclk; | ||
128 | else | ||
129 | clk = timclk; | ||
130 | |||
131 | for (i = 0; i < ARRAY_SIZE(vexpress_sp810_timerclken); i++) | ||
132 | WARN_ON(clk_set_parent(vexpress_sp810_timerclken[i], | ||
133 | clk)); | ||
134 | } | ||
135 | |||
136 | WARN_ON(clk_register_clkdev(vexpress_sp810_timerclken[0], | ||
137 | "v2m-timer0", "sp804")); | ||
138 | WARN_ON(clk_register_clkdev(vexpress_sp810_timerclken[1], | ||
139 | "v2m-timer1", "sp804")); | ||
140 | } | ||
141 | |||
142 | #endif | ||