Thomas Gleixner | 9c92ab6 | 2019-05-29 07:17:56 -0700 | [diff] [blame] | 1 | // SPDX-License-Identifier: GPL-2.0-only |
Chen-Yu Tsai | 783ab76 | 2017-01-28 20:22:36 +0800 | [diff] [blame] | 2 | /* |
| 3 | * Copyright (c) 2016 Chen-Yu Tsai. All rights reserved. |
Chen-Yu Tsai | 783ab76 | 2017-01-28 20:22:36 +0800 | [diff] [blame] | 4 | */ |
| 5 | |
| 6 | #include <linux/clk.h> |
| 7 | #include <linux/clk-provider.h> |
| 8 | #include <linux/of_address.h> |
| 9 | #include <linux/platform_device.h> |
| 10 | #include <linux/reset.h> |
| 11 | |
| 12 | #include "ccu_common.h" |
| 13 | #include "ccu_div.h" |
| 14 | #include "ccu_gate.h" |
| 15 | #include "ccu_reset.h" |
| 16 | |
| 17 | #include "ccu-sun9i-a80-de.h" |
| 18 | |
| 19 | static SUNXI_CCU_GATE(fe0_clk, "fe0", "fe0-div", |
| 20 | 0x00, BIT(0), 0); |
| 21 | static SUNXI_CCU_GATE(fe1_clk, "fe1", "fe1-div", |
| 22 | 0x00, BIT(1), 0); |
| 23 | static SUNXI_CCU_GATE(fe2_clk, "fe2", "fe2-div", |
| 24 | 0x00, BIT(2), 0); |
| 25 | static SUNXI_CCU_GATE(iep_deu0_clk, "iep-deu0", "de", |
| 26 | 0x00, BIT(4), 0); |
| 27 | static SUNXI_CCU_GATE(iep_deu1_clk, "iep-deu1", "de", |
| 28 | 0x00, BIT(5), 0); |
| 29 | static SUNXI_CCU_GATE(be0_clk, "be0", "be0-div", |
| 30 | 0x00, BIT(8), 0); |
| 31 | static SUNXI_CCU_GATE(be1_clk, "be1", "be1-div", |
| 32 | 0x00, BIT(9), 0); |
| 33 | static SUNXI_CCU_GATE(be2_clk, "be2", "be2-div", |
| 34 | 0x00, BIT(10), 0); |
| 35 | static SUNXI_CCU_GATE(iep_drc0_clk, "iep-drc0", "de", |
| 36 | 0x00, BIT(12), 0); |
| 37 | static SUNXI_CCU_GATE(iep_drc1_clk, "iep-drc1", "de", |
| 38 | 0x00, BIT(13), 0); |
| 39 | static SUNXI_CCU_GATE(merge_clk, "merge", "de", |
| 40 | 0x00, BIT(20), 0); |
| 41 | |
| 42 | static SUNXI_CCU_GATE(dram_fe0_clk, "dram-fe0", "sdram", |
| 43 | 0x04, BIT(0), 0); |
| 44 | static SUNXI_CCU_GATE(dram_fe1_clk, "dram-fe1", "sdram", |
| 45 | 0x04, BIT(1), 0); |
| 46 | static SUNXI_CCU_GATE(dram_fe2_clk, "dram-fe2", "sdram", |
| 47 | 0x04, BIT(2), 0); |
| 48 | static SUNXI_CCU_GATE(dram_deu0_clk, "dram-deu0", "sdram", |
| 49 | 0x04, BIT(4), 0); |
| 50 | static SUNXI_CCU_GATE(dram_deu1_clk, "dram-deu1", "sdram", |
| 51 | 0x04, BIT(5), 0); |
| 52 | static SUNXI_CCU_GATE(dram_be0_clk, "dram-be0", "sdram", |
| 53 | 0x04, BIT(8), 0); |
| 54 | static SUNXI_CCU_GATE(dram_be1_clk, "dram-be1", "sdram", |
| 55 | 0x04, BIT(9), 0); |
| 56 | static SUNXI_CCU_GATE(dram_be2_clk, "dram-be2", "sdram", |
| 57 | 0x04, BIT(10), 0); |
| 58 | static SUNXI_CCU_GATE(dram_drc0_clk, "dram-drc0", "sdram", |
| 59 | 0x04, BIT(12), 0); |
| 60 | static SUNXI_CCU_GATE(dram_drc1_clk, "dram-drc1", "sdram", |
| 61 | 0x04, BIT(13), 0); |
| 62 | |
| 63 | static SUNXI_CCU_GATE(bus_fe0_clk, "bus-fe0", "bus-de", |
| 64 | 0x08, BIT(0), 0); |
| 65 | static SUNXI_CCU_GATE(bus_fe1_clk, "bus-fe1", "bus-de", |
| 66 | 0x08, BIT(1), 0); |
| 67 | static SUNXI_CCU_GATE(bus_fe2_clk, "bus-fe2", "bus-de", |
| 68 | 0x08, BIT(2), 0); |
| 69 | static SUNXI_CCU_GATE(bus_deu0_clk, "bus-deu0", "bus-de", |
| 70 | 0x08, BIT(4), 0); |
| 71 | static SUNXI_CCU_GATE(bus_deu1_clk, "bus-deu1", "bus-de", |
| 72 | 0x08, BIT(5), 0); |
| 73 | static SUNXI_CCU_GATE(bus_be0_clk, "bus-be0", "bus-de", |
| 74 | 0x08, BIT(8), 0); |
| 75 | static SUNXI_CCU_GATE(bus_be1_clk, "bus-be1", "bus-de", |
| 76 | 0x08, BIT(9), 0); |
| 77 | static SUNXI_CCU_GATE(bus_be2_clk, "bus-be2", "bus-de", |
| 78 | 0x08, BIT(10), 0); |
| 79 | static SUNXI_CCU_GATE(bus_drc0_clk, "bus-drc0", "bus-de", |
| 80 | 0x08, BIT(12), 0); |
| 81 | static SUNXI_CCU_GATE(bus_drc1_clk, "bus-drc1", "bus-de", |
| 82 | 0x08, BIT(13), 0); |
| 83 | |
| 84 | static SUNXI_CCU_M(fe0_div_clk, "fe0-div", "de", 0x20, 0, 4, 0); |
| 85 | static SUNXI_CCU_M(fe1_div_clk, "fe1-div", "de", 0x20, 4, 4, 0); |
| 86 | static SUNXI_CCU_M(fe2_div_clk, "fe2-div", "de", 0x20, 8, 4, 0); |
| 87 | static SUNXI_CCU_M(be0_div_clk, "be0-div", "de", 0x20, 16, 4, 0); |
| 88 | static SUNXI_CCU_M(be1_div_clk, "be1-div", "de", 0x20, 20, 4, 0); |
| 89 | static SUNXI_CCU_M(be2_div_clk, "be2-div", "de", 0x20, 24, 4, 0); |
| 90 | |
| 91 | static struct ccu_common *sun9i_a80_de_clks[] = { |
| 92 | &fe0_clk.common, |
| 93 | &fe1_clk.common, |
| 94 | &fe2_clk.common, |
| 95 | &iep_deu0_clk.common, |
| 96 | &iep_deu1_clk.common, |
| 97 | &be0_clk.common, |
| 98 | &be1_clk.common, |
| 99 | &be2_clk.common, |
| 100 | &iep_drc0_clk.common, |
| 101 | &iep_drc1_clk.common, |
| 102 | &merge_clk.common, |
| 103 | |
| 104 | &dram_fe0_clk.common, |
| 105 | &dram_fe1_clk.common, |
| 106 | &dram_fe2_clk.common, |
| 107 | &dram_deu0_clk.common, |
| 108 | &dram_deu1_clk.common, |
| 109 | &dram_be0_clk.common, |
| 110 | &dram_be1_clk.common, |
| 111 | &dram_be2_clk.common, |
| 112 | &dram_drc0_clk.common, |
| 113 | &dram_drc1_clk.common, |
| 114 | |
| 115 | &bus_fe0_clk.common, |
| 116 | &bus_fe1_clk.common, |
| 117 | &bus_fe2_clk.common, |
| 118 | &bus_deu0_clk.common, |
| 119 | &bus_deu1_clk.common, |
| 120 | &bus_be0_clk.common, |
| 121 | &bus_be1_clk.common, |
| 122 | &bus_be2_clk.common, |
| 123 | &bus_drc0_clk.common, |
| 124 | &bus_drc1_clk.common, |
| 125 | |
| 126 | &fe0_div_clk.common, |
| 127 | &fe1_div_clk.common, |
| 128 | &fe2_div_clk.common, |
| 129 | &be0_div_clk.common, |
| 130 | &be1_div_clk.common, |
| 131 | &be2_div_clk.common, |
| 132 | }; |
| 133 | |
| 134 | static struct clk_hw_onecell_data sun9i_a80_de_hw_clks = { |
| 135 | .hws = { |
| 136 | [CLK_FE0] = &fe0_clk.common.hw, |
| 137 | [CLK_FE1] = &fe1_clk.common.hw, |
| 138 | [CLK_FE2] = &fe2_clk.common.hw, |
| 139 | [CLK_IEP_DEU0] = &iep_deu0_clk.common.hw, |
| 140 | [CLK_IEP_DEU1] = &iep_deu1_clk.common.hw, |
| 141 | [CLK_BE0] = &be0_clk.common.hw, |
| 142 | [CLK_BE1] = &be1_clk.common.hw, |
| 143 | [CLK_BE2] = &be2_clk.common.hw, |
| 144 | [CLK_IEP_DRC0] = &iep_drc0_clk.common.hw, |
| 145 | [CLK_IEP_DRC1] = &iep_drc1_clk.common.hw, |
| 146 | [CLK_MERGE] = &merge_clk.common.hw, |
| 147 | |
| 148 | [CLK_DRAM_FE0] = &dram_fe0_clk.common.hw, |
| 149 | [CLK_DRAM_FE1] = &dram_fe1_clk.common.hw, |
| 150 | [CLK_DRAM_FE2] = &dram_fe2_clk.common.hw, |
| 151 | [CLK_DRAM_DEU0] = &dram_deu0_clk.common.hw, |
| 152 | [CLK_DRAM_DEU1] = &dram_deu1_clk.common.hw, |
| 153 | [CLK_DRAM_BE0] = &dram_be0_clk.common.hw, |
| 154 | [CLK_DRAM_BE1] = &dram_be1_clk.common.hw, |
| 155 | [CLK_DRAM_BE2] = &dram_be2_clk.common.hw, |
| 156 | [CLK_DRAM_DRC0] = &dram_drc0_clk.common.hw, |
| 157 | [CLK_DRAM_DRC1] = &dram_drc1_clk.common.hw, |
| 158 | |
| 159 | [CLK_BUS_FE0] = &bus_fe0_clk.common.hw, |
| 160 | [CLK_BUS_FE1] = &bus_fe1_clk.common.hw, |
| 161 | [CLK_BUS_FE2] = &bus_fe2_clk.common.hw, |
| 162 | [CLK_BUS_DEU0] = &bus_deu0_clk.common.hw, |
| 163 | [CLK_BUS_DEU1] = &bus_deu1_clk.common.hw, |
| 164 | [CLK_BUS_BE0] = &bus_be0_clk.common.hw, |
| 165 | [CLK_BUS_BE1] = &bus_be1_clk.common.hw, |
| 166 | [CLK_BUS_BE2] = &bus_be2_clk.common.hw, |
| 167 | [CLK_BUS_DRC0] = &bus_drc0_clk.common.hw, |
| 168 | [CLK_BUS_DRC1] = &bus_drc1_clk.common.hw, |
| 169 | |
| 170 | [CLK_FE0_DIV] = &fe0_div_clk.common.hw, |
| 171 | [CLK_FE1_DIV] = &fe1_div_clk.common.hw, |
| 172 | [CLK_FE2_DIV] = &fe2_div_clk.common.hw, |
| 173 | [CLK_BE0_DIV] = &be0_div_clk.common.hw, |
| 174 | [CLK_BE1_DIV] = &be1_div_clk.common.hw, |
| 175 | [CLK_BE2_DIV] = &be2_div_clk.common.hw, |
| 176 | }, |
| 177 | .num = CLK_NUMBER, |
| 178 | }; |
| 179 | |
| 180 | static struct ccu_reset_map sun9i_a80_de_resets[] = { |
| 181 | [RST_FE0] = { 0x0c, BIT(0) }, |
| 182 | [RST_FE1] = { 0x0c, BIT(1) }, |
| 183 | [RST_FE2] = { 0x0c, BIT(2) }, |
| 184 | [RST_DEU0] = { 0x0c, BIT(4) }, |
| 185 | [RST_DEU1] = { 0x0c, BIT(5) }, |
| 186 | [RST_BE0] = { 0x0c, BIT(8) }, |
| 187 | [RST_BE1] = { 0x0c, BIT(9) }, |
| 188 | [RST_BE2] = { 0x0c, BIT(10) }, |
| 189 | [RST_DRC0] = { 0x0c, BIT(12) }, |
| 190 | [RST_DRC1] = { 0x0c, BIT(13) }, |
| 191 | [RST_MERGE] = { 0x0c, BIT(20) }, |
| 192 | }; |
| 193 | |
| 194 | static const struct sunxi_ccu_desc sun9i_a80_de_clk_desc = { |
| 195 | .ccu_clks = sun9i_a80_de_clks, |
| 196 | .num_ccu_clks = ARRAY_SIZE(sun9i_a80_de_clks), |
| 197 | |
| 198 | .hw_clks = &sun9i_a80_de_hw_clks, |
| 199 | |
| 200 | .resets = sun9i_a80_de_resets, |
| 201 | .num_resets = ARRAY_SIZE(sun9i_a80_de_resets), |
| 202 | }; |
| 203 | |
| 204 | static int sun9i_a80_de_clk_probe(struct platform_device *pdev) |
| 205 | { |
| 206 | struct resource *res; |
| 207 | struct clk *bus_clk; |
| 208 | struct reset_control *rstc; |
| 209 | void __iomem *reg; |
| 210 | int ret; |
| 211 | |
| 212 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
| 213 | reg = devm_ioremap_resource(&pdev->dev, res); |
| 214 | if (IS_ERR(reg)) |
| 215 | return PTR_ERR(reg); |
| 216 | |
| 217 | bus_clk = devm_clk_get(&pdev->dev, "bus"); |
| 218 | if (IS_ERR(bus_clk)) { |
| 219 | ret = PTR_ERR(bus_clk); |
| 220 | if (ret != -EPROBE_DEFER) |
| 221 | dev_err(&pdev->dev, "Couldn't get bus clk: %d\n", ret); |
| 222 | return ret; |
| 223 | } |
| 224 | |
| 225 | rstc = devm_reset_control_get_exclusive(&pdev->dev, NULL); |
| 226 | if (IS_ERR(rstc)) { |
Wei Yongjun | 09bdcd6 | 2017-02-06 16:09:26 +0000 | [diff] [blame] | 227 | ret = PTR_ERR(rstc); |
Chen-Yu Tsai | 783ab76 | 2017-01-28 20:22:36 +0800 | [diff] [blame] | 228 | if (ret != -EPROBE_DEFER) |
| 229 | dev_err(&pdev->dev, |
| 230 | "Couldn't get reset control: %d\n", ret); |
| 231 | return ret; |
| 232 | } |
| 233 | |
| 234 | /* The bus clock needs to be enabled for us to access the registers */ |
| 235 | ret = clk_prepare_enable(bus_clk); |
| 236 | if (ret) { |
| 237 | dev_err(&pdev->dev, "Couldn't enable bus clk: %d\n", ret); |
| 238 | return ret; |
| 239 | } |
| 240 | |
| 241 | /* The reset control needs to be asserted for the controls to work */ |
| 242 | ret = reset_control_deassert(rstc); |
| 243 | if (ret) { |
| 244 | dev_err(&pdev->dev, |
| 245 | "Couldn't deassert reset control: %d\n", ret); |
| 246 | goto err_disable_clk; |
| 247 | } |
| 248 | |
| 249 | ret = sunxi_ccu_probe(pdev->dev.of_node, reg, |
| 250 | &sun9i_a80_de_clk_desc); |
| 251 | if (ret) |
| 252 | goto err_assert_reset; |
| 253 | |
| 254 | return 0; |
| 255 | |
| 256 | err_assert_reset: |
| 257 | reset_control_assert(rstc); |
| 258 | err_disable_clk: |
| 259 | clk_disable_unprepare(bus_clk); |
| 260 | return ret; |
| 261 | } |
| 262 | |
| 263 | static const struct of_device_id sun9i_a80_de_clk_ids[] = { |
| 264 | { .compatible = "allwinner,sun9i-a80-de-clks" }, |
| 265 | { } |
| 266 | }; |
| 267 | |
| 268 | static struct platform_driver sun9i_a80_de_clk_driver = { |
| 269 | .probe = sun9i_a80_de_clk_probe, |
| 270 | .driver = { |
| 271 | .name = "sun9i-a80-de-clks", |
| 272 | .of_match_table = sun9i_a80_de_clk_ids, |
| 273 | }, |
| 274 | }; |
| 275 | builtin_platform_driver(sun9i_a80_de_clk_driver); |