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