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