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