linux/drivers/mfd/sun6i-prcm.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * Copyright (C) 2014 Free Electrons
   4 *
   5 * Author: Boris BREZILLON <boris.brezillon@free-electrons.com>
   6 *
   7 * Allwinner PRCM (Power/Reset/Clock Management) driver
   8 */
   9
  10#include <linux/mfd/core.h>
  11#include <linux/init.h>
  12#include <linux/of.h>
  13
  14#define SUN8I_CODEC_ANALOG_BASE 0x1c0
  15#define SUN8I_CODEC_ANALOG_SIZE 0x4
  16
  17struct prcm_data {
  18        int nsubdevs;
  19        const struct mfd_cell *subdevs;
  20};
  21
  22static const struct resource sun6i_a31_ar100_clk_res[] = {
  23        {
  24                .start = 0x0,
  25                .end = 0x3,
  26                .flags = IORESOURCE_MEM,
  27        },
  28};
  29
  30static const struct resource sun6i_a31_apb0_clk_res[] = {
  31        {
  32                .start = 0xc,
  33                .end = 0xf,
  34                .flags = IORESOURCE_MEM,
  35        },
  36};
  37
  38static const struct resource sun6i_a31_apb0_gates_clk_res[] = {
  39        {
  40                .start = 0x28,
  41                .end = 0x2b,
  42                .flags = IORESOURCE_MEM,
  43        },
  44};
  45
  46static const struct resource sun6i_a31_ir_clk_res[] = {
  47        {
  48                .start = 0x54,
  49                .end = 0x57,
  50                .flags = IORESOURCE_MEM,
  51        },
  52};
  53
  54static const struct resource sun6i_a31_apb0_rstc_res[] = {
  55        {
  56                .start = 0xb0,
  57                .end = 0xb3,
  58                .flags = IORESOURCE_MEM,
  59        },
  60};
  61
  62static const struct resource sun8i_codec_analog_res[] = {
  63        DEFINE_RES_MEM(SUN8I_CODEC_ANALOG_BASE, SUN8I_CODEC_ANALOG_SIZE),
  64};
  65
  66static const struct mfd_cell sun6i_a31_prcm_subdevs[] = {
  67        {
  68                .name = "sun6i-a31-ar100-clk",
  69                .of_compatible = "allwinner,sun6i-a31-ar100-clk",
  70                .num_resources = ARRAY_SIZE(sun6i_a31_ar100_clk_res),
  71                .resources = sun6i_a31_ar100_clk_res,
  72        },
  73        {
  74                .name = "sun6i-a31-apb0-clk",
  75                .of_compatible = "allwinner,sun6i-a31-apb0-clk",
  76                .num_resources = ARRAY_SIZE(sun6i_a31_apb0_clk_res),
  77                .resources = sun6i_a31_apb0_clk_res,
  78        },
  79        {
  80                .name = "sun6i-a31-apb0-gates-clk",
  81                .of_compatible = "allwinner,sun6i-a31-apb0-gates-clk",
  82                .num_resources = ARRAY_SIZE(sun6i_a31_apb0_gates_clk_res),
  83                .resources = sun6i_a31_apb0_gates_clk_res,
  84        },
  85        {
  86                .name = "sun6i-a31-ir-clk",
  87                .of_compatible = "allwinner,sun4i-a10-mod0-clk",
  88                .num_resources = ARRAY_SIZE(sun6i_a31_ir_clk_res),
  89                .resources = sun6i_a31_ir_clk_res,
  90        },
  91        {
  92                .name = "sun6i-a31-apb0-clock-reset",
  93                .of_compatible = "allwinner,sun6i-a31-clock-reset",
  94                .num_resources = ARRAY_SIZE(sun6i_a31_apb0_rstc_res),
  95                .resources = sun6i_a31_apb0_rstc_res,
  96        },
  97};
  98
  99static const struct mfd_cell sun8i_a23_prcm_subdevs[] = {
 100        {
 101                .name = "sun8i-a23-apb0-clk",
 102                .of_compatible = "allwinner,sun8i-a23-apb0-clk",
 103                .num_resources = ARRAY_SIZE(sun6i_a31_apb0_clk_res),
 104                .resources = sun6i_a31_apb0_clk_res,
 105        },
 106        {
 107                .name = "sun6i-a31-apb0-gates-clk",
 108                .of_compatible = "allwinner,sun8i-a23-apb0-gates-clk",
 109                .num_resources = ARRAY_SIZE(sun6i_a31_apb0_gates_clk_res),
 110                .resources = sun6i_a31_apb0_gates_clk_res,
 111        },
 112        {
 113                .name = "sun6i-a31-apb0-clock-reset",
 114                .of_compatible = "allwinner,sun6i-a31-clock-reset",
 115                .num_resources = ARRAY_SIZE(sun6i_a31_apb0_rstc_res),
 116                .resources = sun6i_a31_apb0_rstc_res,
 117        },
 118        {
 119                .name           = "sun8i-codec-analog",
 120                .of_compatible  = "allwinner,sun8i-a23-codec-analog",
 121                .num_resources  = ARRAY_SIZE(sun8i_codec_analog_res),
 122                .resources      = sun8i_codec_analog_res,
 123        },
 124};
 125
 126static const struct prcm_data sun6i_a31_prcm_data = {
 127        .nsubdevs = ARRAY_SIZE(sun6i_a31_prcm_subdevs),
 128        .subdevs = sun6i_a31_prcm_subdevs,
 129};
 130
 131static const struct prcm_data sun8i_a23_prcm_data = {
 132        .nsubdevs = ARRAY_SIZE(sun8i_a23_prcm_subdevs),
 133        .subdevs = sun8i_a23_prcm_subdevs,
 134};
 135
 136static const struct of_device_id sun6i_prcm_dt_ids[] = {
 137        {
 138                .compatible = "allwinner,sun6i-a31-prcm",
 139                .data = &sun6i_a31_prcm_data,
 140        },
 141        {
 142                .compatible = "allwinner,sun8i-a23-prcm",
 143                .data = &sun8i_a23_prcm_data,
 144        },
 145        { /* sentinel */ },
 146};
 147
 148static int sun6i_prcm_probe(struct platform_device *pdev)
 149{
 150        const struct of_device_id *match;
 151        const struct prcm_data *data;
 152        struct resource *res;
 153        int ret;
 154
 155        match = of_match_node(sun6i_prcm_dt_ids, pdev->dev.of_node);
 156        if (!match)
 157                return -EINVAL;
 158
 159        data = match->data;
 160
 161        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 162        if (!res) {
 163                dev_err(&pdev->dev, "no prcm memory region provided\n");
 164                return -ENOENT;
 165        }
 166
 167        ret = mfd_add_devices(&pdev->dev, 0, data->subdevs, data->nsubdevs,
 168                              res, -1, NULL);
 169        if (ret) {
 170                dev_err(&pdev->dev, "failed to add subdevices\n");
 171                return ret;
 172        }
 173
 174        return 0;
 175}
 176
 177static struct platform_driver sun6i_prcm_driver = {
 178        .driver = {
 179                .name = "sun6i-prcm",
 180                .of_match_table = sun6i_prcm_dt_ids,
 181        },
 182        .probe = sun6i_prcm_probe,
 183};
 184builtin_platform_driver(sun6i_prcm_driver);
 185