1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * Synopsys AXS10X SDP I2S PLL clock driver 4 * 5 * Copyright (C) 2016 Synopsys 6 */ 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 0x0 20 #define PLL_FBDIV_REG 0x4 21 #define PLL_ODIV0_REG 0x8 22 #define PLL_ODIV1_REG 0xC 23 24 struct 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 32 static 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 45 static 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 58 struct i2s_pll_clk { 59 void __iomem *base; 60 struct clk_hw hw; 61 struct device *dev; 62 }; 63 64 static 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 70 static 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 76 static 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 81 static inline unsigned int i2s_pll_get_value(unsigned int val) 82 { 83 return (val & 0x3F) + ((val >> 6) & 0x3F); 84 } 85 86 static 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 98 static 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 111 static 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 130 static 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 157 static 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 163 static 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 201 static int i2s_pll_clk_remove(struct platform_device *pdev) 202 { 203 of_clk_del_provider(pdev->dev.of_node); 204 return 0; 205 } 206 207 static const struct of_device_id i2s_pll_clk_id[] = { 208 { .compatible = "snps,axs10x-i2s-pll-clock", }, 209 { }, 210 }; 211 MODULE_DEVICE_TABLE(of, i2s_pll_clk_id); 212 213 static struct platform_driver i2s_pll_clk_driver = { 214 .driver = { 215 .name = "axs10x-i2s-pll-clock", 216 .of_match_table = i2s_pll_clk_id, 217 }, 218 .probe = i2s_pll_clk_probe, 219 .remove = i2s_pll_clk_remove, 220 }; 221 module_platform_driver(i2s_pll_clk_driver); 222 223 MODULE_AUTHOR("Jose Abreu <joabreu@synopsys.com>"); 224 MODULE_DESCRIPTION("Synopsys AXS10X SDP I2S PLL Clock Driver"); 225 MODULE_LICENSE("GPL v2"); 226