225 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * Synopsys AXS10X SDP I2S PLL clock driver4 *5 * Copyright (C) 2016 Synopsys6 */7 8#include <linux/platform_device.h>9#include <linux/module.h>10#include <linux/clk-provider.h>11#include <linux/err.h>12#include <linux/device.h>13#include <linux/io.h>14#include <linux/of_address.h>15#include <linux/slab.h>16#include <linux/of.h>17 18/* PLL registers addresses */19#define PLL_IDIV_REG 0x020#define PLL_FBDIV_REG 0x421#define PLL_ODIV0_REG 0x822#define PLL_ODIV1_REG 0xC23 24struct i2s_pll_cfg {25 unsigned int rate;26 unsigned int idiv;27 unsigned int fbdiv;28 unsigned int odiv0;29 unsigned int odiv1;30};31 32static const struct i2s_pll_cfg i2s_pll_cfg_27m[] = {33 /* 27 Mhz */34 { 1024000, 0x104, 0x451, 0x10E38, 0x2000 },35 { 1411200, 0x104, 0x596, 0x10D35, 0x2000 },36 { 1536000, 0x208, 0xA28, 0x10B2C, 0x2000 },37 { 2048000, 0x82, 0x451, 0x10E38, 0x2000 },38 { 2822400, 0x82, 0x596, 0x10D35, 0x2000 },39 { 3072000, 0x104, 0xA28, 0x10B2C, 0x2000 },40 { 2116800, 0x82, 0x3CF, 0x10C30, 0x2000 },41 { 2304000, 0x104, 0x79E, 0x10B2C, 0x2000 },42 { 0, 0, 0, 0, 0 },43};44 45static const struct i2s_pll_cfg i2s_pll_cfg_28m[] = {46 /* 28.224 Mhz */47 { 1024000, 0x82, 0x105, 0x107DF, 0x2000 },48 { 1411200, 0x28A, 0x1, 0x10001, 0x2000 },49 { 1536000, 0xA28, 0x187, 0x10042, 0x2000 },50 { 2048000, 0x41, 0x105, 0x107DF, 0x2000 },51 { 2822400, 0x145, 0x1, 0x10001, 0x2000 },52 { 3072000, 0x514, 0x187, 0x10042, 0x2000 },53 { 2116800, 0x514, 0x42, 0x10001, 0x2000 },54 { 2304000, 0x619, 0x82, 0x10001, 0x2000 },55 { 0, 0, 0, 0, 0 },56};57 58struct i2s_pll_clk {59 void __iomem *base;60 struct clk_hw hw;61 struct device *dev;62};63 64static inline void i2s_pll_write(struct i2s_pll_clk *clk, unsigned int reg,65 unsigned int val)66{67 writel_relaxed(val, clk->base + reg);68}69 70static inline unsigned int i2s_pll_read(struct i2s_pll_clk *clk,71 unsigned int reg)72{73 return readl_relaxed(clk->base + reg);74}75 76static inline struct i2s_pll_clk *to_i2s_pll_clk(struct clk_hw *hw)77{78 return container_of(hw, struct i2s_pll_clk, hw);79}80 81static inline unsigned int i2s_pll_get_value(unsigned int val)82{83 return (val & 0x3F) + ((val >> 6) & 0x3F);84}85 86static const struct i2s_pll_cfg *i2s_pll_get_cfg(unsigned long prate)87{88 switch (prate) {89 case 27000000:90 return i2s_pll_cfg_27m;91 case 28224000:92 return i2s_pll_cfg_28m;93 default:94 return NULL;95 }96}97 98static unsigned long i2s_pll_recalc_rate(struct clk_hw *hw,99 unsigned long parent_rate)100{101 struct i2s_pll_clk *clk = to_i2s_pll_clk(hw);102 unsigned int idiv, fbdiv, odiv;103 104 idiv = i2s_pll_get_value(i2s_pll_read(clk, PLL_IDIV_REG));105 fbdiv = i2s_pll_get_value(i2s_pll_read(clk, PLL_FBDIV_REG));106 odiv = i2s_pll_get_value(i2s_pll_read(clk, PLL_ODIV0_REG));107 108 return ((parent_rate / idiv) * fbdiv) / odiv;109}110 111static long i2s_pll_round_rate(struct clk_hw *hw, unsigned long rate,112 unsigned long *prate)113{114 struct i2s_pll_clk *clk = to_i2s_pll_clk(hw);115 const struct i2s_pll_cfg *pll_cfg = i2s_pll_get_cfg(*prate);116 int i;117 118 if (!pll_cfg) {119 dev_err(clk->dev, "invalid parent rate=%ld\n", *prate);120 return -EINVAL;121 }122 123 for (i = 0; pll_cfg[i].rate != 0; i++)124 if (pll_cfg[i].rate == rate)125 return rate;126 127 return -EINVAL;128}129 130static int i2s_pll_set_rate(struct clk_hw *hw, unsigned long rate,131 unsigned long parent_rate)132{133 struct i2s_pll_clk *clk = to_i2s_pll_clk(hw);134 const struct i2s_pll_cfg *pll_cfg = i2s_pll_get_cfg(parent_rate);135 int i;136 137 if (!pll_cfg) {138 dev_err(clk->dev, "invalid parent rate=%ld\n", parent_rate);139 return -EINVAL;140 }141 142 for (i = 0; pll_cfg[i].rate != 0; i++) {143 if (pll_cfg[i].rate == rate) {144 i2s_pll_write(clk, PLL_IDIV_REG, pll_cfg[i].idiv);145 i2s_pll_write(clk, PLL_FBDIV_REG, pll_cfg[i].fbdiv);146 i2s_pll_write(clk, PLL_ODIV0_REG, pll_cfg[i].odiv0);147 i2s_pll_write(clk, PLL_ODIV1_REG, pll_cfg[i].odiv1);148 return 0;149 }150 }151 152 dev_err(clk->dev, "invalid rate=%ld, parent_rate=%ld\n", rate,153 parent_rate);154 return -EINVAL;155}156 157static const struct clk_ops i2s_pll_ops = {158 .recalc_rate = i2s_pll_recalc_rate,159 .round_rate = i2s_pll_round_rate,160 .set_rate = i2s_pll_set_rate,161};162 163static int i2s_pll_clk_probe(struct platform_device *pdev)164{165 struct device *dev = &pdev->dev;166 struct device_node *node = dev->of_node;167 const char *clk_name;168 const char *parent_name;169 struct clk *clk;170 struct i2s_pll_clk *pll_clk;171 struct clk_init_data init;172 173 pll_clk = devm_kzalloc(dev, sizeof(*pll_clk), GFP_KERNEL);174 if (!pll_clk)175 return -ENOMEM;176 177 pll_clk->base = devm_platform_ioremap_resource(pdev, 0);178 if (IS_ERR(pll_clk->base))179 return PTR_ERR(pll_clk->base);180 181 memset(&init, 0, sizeof(init));182 clk_name = node->name;183 init.name = clk_name;184 init.ops = &i2s_pll_ops;185 parent_name = of_clk_get_parent_name(node, 0);186 init.parent_names = &parent_name;187 init.num_parents = 1;188 pll_clk->hw.init = &init;189 pll_clk->dev = dev;190 191 clk = devm_clk_register(dev, &pll_clk->hw);192 if (IS_ERR(clk)) {193 dev_err(dev, "failed to register %s clock (%ld)\n",194 clk_name, PTR_ERR(clk));195 return PTR_ERR(clk);196 }197 198 return of_clk_add_provider(node, of_clk_src_simple_get, clk);199}200 201static void i2s_pll_clk_remove(struct platform_device *pdev)202{203 of_clk_del_provider(pdev->dev.of_node);204}205 206static const struct of_device_id i2s_pll_clk_id[] = {207 { .compatible = "snps,axs10x-i2s-pll-clock", },208 { },209};210MODULE_DEVICE_TABLE(of, i2s_pll_clk_id);211 212static struct platform_driver i2s_pll_clk_driver = {213 .driver = {214 .name = "axs10x-i2s-pll-clock",215 .of_match_table = i2s_pll_clk_id,216 },217 .probe = i2s_pll_clk_probe,218 .remove = i2s_pll_clk_remove,219};220module_platform_driver(i2s_pll_clk_driver);221 222MODULE_AUTHOR("Jose Abreu <joabreu@synopsys.com>");223MODULE_DESCRIPTION("Synopsys AXS10X SDP I2S PLL Clock Driver");224MODULE_LICENSE("GPL v2");225