221 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3 * Copyright (C) 2016 Socionext Inc.4 * Author: Masahiro Yamada <yamada.masahiro@socionext.com>5 */6 7#include <linux/clk-provider.h>8#include <linux/init.h>9#include <linux/mfd/syscon.h>10#include <linux/of.h>11#include <linux/platform_device.h>12 13#include "clk-uniphier.h"14 15static struct clk_hw *uniphier_clk_register(struct device *dev,16 struct regmap *regmap,17 const struct uniphier_clk_data *data)18{19 switch (data->type) {20 case UNIPHIER_CLK_TYPE_CPUGEAR:21 return uniphier_clk_register_cpugear(dev, regmap, data->name,22 &data->data.cpugear);23 case UNIPHIER_CLK_TYPE_FIXED_FACTOR:24 return uniphier_clk_register_fixed_factor(dev, data->name,25 &data->data.factor);26 case UNIPHIER_CLK_TYPE_FIXED_RATE:27 return uniphier_clk_register_fixed_rate(dev, data->name,28 &data->data.rate);29 case UNIPHIER_CLK_TYPE_GATE:30 return uniphier_clk_register_gate(dev, regmap, data->name,31 &data->data.gate);32 case UNIPHIER_CLK_TYPE_MUX:33 return uniphier_clk_register_mux(dev, regmap, data->name,34 &data->data.mux);35 default:36 dev_err(dev, "unsupported clock type\n");37 return ERR_PTR(-EINVAL);38 }39}40 41static int uniphier_clk_probe(struct platform_device *pdev)42{43 struct device *dev = &pdev->dev;44 struct clk_hw_onecell_data *hw_data;45 const struct uniphier_clk_data *p, *data;46 struct regmap *regmap;47 struct device_node *parent;48 int clk_num = 0;49 50 data = of_device_get_match_data(dev);51 if (WARN_ON(!data))52 return -EINVAL;53 54 parent = of_get_parent(dev->of_node); /* parent should be syscon node */55 regmap = syscon_node_to_regmap(parent);56 of_node_put(parent);57 if (IS_ERR(regmap)) {58 dev_err(dev, "failed to get regmap (error %ld)\n",59 PTR_ERR(regmap));60 return PTR_ERR(regmap);61 }62 63 for (p = data; p->name; p++)64 clk_num = max(clk_num, p->idx + 1);65 66 hw_data = devm_kzalloc(dev, struct_size(hw_data, hws, clk_num),67 GFP_KERNEL);68 if (!hw_data)69 return -ENOMEM;70 71 hw_data->num = clk_num;72 73 /* avoid returning NULL for unused idx */74 while (--clk_num >= 0)75 hw_data->hws[clk_num] = ERR_PTR(-EINVAL);76 77 for (p = data; p->name; p++) {78 struct clk_hw *hw;79 80 dev_dbg(dev, "register %s (index=%d)\n", p->name, p->idx);81 hw = uniphier_clk_register(dev, regmap, p);82 if (WARN(IS_ERR(hw), "failed to register %s", p->name))83 continue;84 85 if (p->idx >= 0)86 hw_data->hws[p->idx] = hw;87 }88 89 return devm_of_clk_add_hw_provider(dev, of_clk_hw_onecell_get,90 hw_data);91}92 93static const struct of_device_id uniphier_clk_match[] = {94 /* System clock */95 {96 .compatible = "socionext,uniphier-ld4-clock",97 .data = uniphier_ld4_sys_clk_data,98 },99 {100 .compatible = "socionext,uniphier-pro4-clock",101 .data = uniphier_pro4_sys_clk_data,102 },103 {104 .compatible = "socionext,uniphier-sld8-clock",105 .data = uniphier_sld8_sys_clk_data,106 },107 {108 .compatible = "socionext,uniphier-pro5-clock",109 .data = uniphier_pro5_sys_clk_data,110 },111 {112 .compatible = "socionext,uniphier-pxs2-clock",113 .data = uniphier_pxs2_sys_clk_data,114 },115 {116 .compatible = "socionext,uniphier-ld11-clock",117 .data = uniphier_ld11_sys_clk_data,118 },119 {120 .compatible = "socionext,uniphier-ld20-clock",121 .data = uniphier_ld20_sys_clk_data,122 },123 {124 .compatible = "socionext,uniphier-pxs3-clock",125 .data = uniphier_pxs3_sys_clk_data,126 },127 {128 .compatible = "socionext,uniphier-nx1-clock",129 .data = uniphier_nx1_sys_clk_data,130 },131 /* Media I/O clock, SD clock */132 {133 .compatible = "socionext,uniphier-ld4-mio-clock",134 .data = uniphier_ld4_mio_clk_data,135 },136 {137 .compatible = "socionext,uniphier-pro4-mio-clock",138 .data = uniphier_ld4_mio_clk_data,139 },140 {141 .compatible = "socionext,uniphier-sld8-mio-clock",142 .data = uniphier_ld4_mio_clk_data,143 },144 {145 .compatible = "socionext,uniphier-pro5-sd-clock",146 .data = uniphier_pro5_sd_clk_data,147 },148 {149 .compatible = "socionext,uniphier-pxs2-sd-clock",150 .data = uniphier_pro5_sd_clk_data,151 },152 {153 .compatible = "socionext,uniphier-ld11-mio-clock",154 .data = uniphier_ld4_mio_clk_data,155 },156 {157 .compatible = "socionext,uniphier-ld20-sd-clock",158 .data = uniphier_pro5_sd_clk_data,159 },160 {161 .compatible = "socionext,uniphier-pxs3-sd-clock",162 .data = uniphier_pro5_sd_clk_data,163 },164 {165 .compatible = "socionext,uniphier-nx1-sd-clock",166 .data = uniphier_pro5_sd_clk_data,167 },168 /* Peripheral clock */169 {170 .compatible = "socionext,uniphier-ld4-peri-clock",171 .data = uniphier_ld4_peri_clk_data,172 },173 {174 .compatible = "socionext,uniphier-pro4-peri-clock",175 .data = uniphier_pro4_peri_clk_data,176 },177 {178 .compatible = "socionext,uniphier-sld8-peri-clock",179 .data = uniphier_ld4_peri_clk_data,180 },181 {182 .compatible = "socionext,uniphier-pro5-peri-clock",183 .data = uniphier_pro4_peri_clk_data,184 },185 {186 .compatible = "socionext,uniphier-pxs2-peri-clock",187 .data = uniphier_pro4_peri_clk_data,188 },189 {190 .compatible = "socionext,uniphier-ld11-peri-clock",191 .data = uniphier_pro4_peri_clk_data,192 },193 {194 .compatible = "socionext,uniphier-ld20-peri-clock",195 .data = uniphier_pro4_peri_clk_data,196 },197 {198 .compatible = "socionext,uniphier-pxs3-peri-clock",199 .data = uniphier_pro4_peri_clk_data,200 },201 {202 .compatible = "socionext,uniphier-nx1-peri-clock",203 .data = uniphier_pro4_peri_clk_data,204 },205 /* SoC-glue clock */206 {207 .compatible = "socionext,uniphier-pro4-sg-clock",208 .data = uniphier_pro4_sg_clk_data,209 },210 { /* sentinel */ }211};212 213static struct platform_driver uniphier_clk_driver = {214 .probe = uniphier_clk_probe,215 .driver = {216 .name = "uniphier-clk",217 .of_match_table = uniphier_clk_match,218 },219};220builtin_platform_driver(uniphier_clk_driver);221