linux/drivers/clk/sunxi-ng/ccu-sun9i-a80-de.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * Copyright (c) 2016 Chen-Yu Tsai. All rights reserved.
   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
  19static SUNXI_CCU_GATE(fe0_clk,          "fe0",          "fe0-div",
  20                      0x00, BIT(0), 0);
  21static SUNXI_CCU_GATE(fe1_clk,          "fe1",          "fe1-div",
  22                      0x00, BIT(1), 0);
  23static SUNXI_CCU_GATE(fe2_clk,          "fe2",          "fe2-div",
  24                      0x00, BIT(2), 0);
  25static SUNXI_CCU_GATE(iep_deu0_clk,     "iep-deu0",     "de",
  26                      0x00, BIT(4), 0);
  27static SUNXI_CCU_GATE(iep_deu1_clk,     "iep-deu1",     "de",
  28                      0x00, BIT(5), 0);
  29static SUNXI_CCU_GATE(be0_clk,          "be0",          "be0-div",
  30                      0x00, BIT(8), 0);
  31static SUNXI_CCU_GATE(be1_clk,          "be1",          "be1-div",
  32                      0x00, BIT(9), 0);
  33static SUNXI_CCU_GATE(be2_clk,          "be2",          "be2-div",
  34                      0x00, BIT(10), 0);
  35static SUNXI_CCU_GATE(iep_drc0_clk,     "iep-drc0",     "de",
  36                      0x00, BIT(12), 0);
  37static SUNXI_CCU_GATE(iep_drc1_clk,     "iep-drc1",     "de",
  38                      0x00, BIT(13), 0);
  39static SUNXI_CCU_GATE(merge_clk,        "merge",        "de",
  40                      0x00, BIT(20), 0);
  41
  42static SUNXI_CCU_GATE(dram_fe0_clk,     "dram-fe0",     "sdram",
  43                      0x04, BIT(0), 0);
  44static SUNXI_CCU_GATE(dram_fe1_clk,     "dram-fe1",     "sdram",
  45                      0x04, BIT(1), 0);
  46static SUNXI_CCU_GATE(dram_fe2_clk,     "dram-fe2",     "sdram",
  47                      0x04, BIT(2), 0);
  48static SUNXI_CCU_GATE(dram_deu0_clk,    "dram-deu0",    "sdram",
  49                      0x04, BIT(4), 0);
  50static SUNXI_CCU_GATE(dram_deu1_clk,    "dram-deu1",    "sdram",
  51                      0x04, BIT(5), 0);
  52static SUNXI_CCU_GATE(dram_be0_clk,     "dram-be0",     "sdram",
  53                      0x04, BIT(8), 0);
  54static SUNXI_CCU_GATE(dram_be1_clk,     "dram-be1",     "sdram",
  55                      0x04, BIT(9), 0);
  56static SUNXI_CCU_GATE(dram_be2_clk,     "dram-be2",     "sdram",
  57                      0x04, BIT(10), 0);
  58static SUNXI_CCU_GATE(dram_drc0_clk,    "dram-drc0",    "sdram",
  59                      0x04, BIT(12), 0);
  60static SUNXI_CCU_GATE(dram_drc1_clk,    "dram-drc1",    "sdram",
  61                      0x04, BIT(13), 0);
  62
  63static SUNXI_CCU_GATE(bus_fe0_clk,      "bus-fe0",      "bus-de",
  64                      0x08, BIT(0), 0);
  65static SUNXI_CCU_GATE(bus_fe1_clk,      "bus-fe1",      "bus-de",
  66                      0x08, BIT(1), 0);
  67static SUNXI_CCU_GATE(bus_fe2_clk,      "bus-fe2",      "bus-de",
  68                      0x08, BIT(2), 0);
  69static SUNXI_CCU_GATE(bus_deu0_clk,     "bus-deu0",     "bus-de",
  70                      0x08, BIT(4), 0);
  71static SUNXI_CCU_GATE(bus_deu1_clk,     "bus-deu1",     "bus-de",
  72                      0x08, BIT(5), 0);
  73static SUNXI_CCU_GATE(bus_be0_clk,      "bus-be0",      "bus-de",
  74                      0x08, BIT(8), 0);
  75static SUNXI_CCU_GATE(bus_be1_clk,      "bus-be1",      "bus-de",
  76                      0x08, BIT(9), 0);
  77static SUNXI_CCU_GATE(bus_be2_clk,      "bus-be2",      "bus-de",
  78                      0x08, BIT(10), 0);
  79static SUNXI_CCU_GATE(bus_drc0_clk,     "bus-drc0",     "bus-de",
  80                      0x08, BIT(12), 0);
  81static SUNXI_CCU_GATE(bus_drc1_clk,     "bus-drc1",     "bus-de",
  82                      0x08, BIT(13), 0);
  83
  84static SUNXI_CCU_M(fe0_div_clk, "fe0-div", "de", 0x20, 0, 4, 0);
  85static SUNXI_CCU_M(fe1_div_clk, "fe1-div", "de", 0x20, 4, 4, 0);
  86static SUNXI_CCU_M(fe2_div_clk, "fe2-div", "de", 0x20, 8, 4, 0);
  87static SUNXI_CCU_M(be0_div_clk, "be0-div", "de", 0x20, 16, 4, 0);
  88static SUNXI_CCU_M(be1_div_clk, "be1-div", "de", 0x20, 20, 4, 0);
  89static SUNXI_CCU_M(be2_div_clk, "be2-div", "de", 0x20, 24, 4, 0);
  90
  91static 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
 134static 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
 180static 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
 194static 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
 204static 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)) {
 227                ret = PTR_ERR(rstc);
 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
 256err_assert_reset:
 257        reset_control_assert(rstc);
 258err_disable_clk:
 259        clk_disable_unprepare(bus_clk);
 260        return ret;
 261}
 262
 263static const struct of_device_id sun9i_a80_de_clk_ids[] = {
 264        { .compatible = "allwinner,sun9i-a80-de-clks" },
 265        { }
 266};
 267
 268static 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};
 275builtin_platform_driver(sun9i_a80_de_clk_driver);
 276