0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017 #include <linux/clk-provider.h>
0018 #include <linux/clkdev.h>
0019 #include <linux/kernel.h>
0020 #include <linux/mfd/tps68470.h>
0021 #include <linux/module.h>
0022 #include <linux/platform_device.h>
0023 #include <linux/platform_data/tps68470.h>
0024 #include <linux/regmap.h>
0025
0026 #define TPS68470_CLK_NAME "tps68470-clk"
0027
0028 #define to_tps68470_clkdata(clkd) \
0029 container_of(clkd, struct tps68470_clkdata, clkout_hw)
0030
0031 static struct tps68470_clkout_freqs {
0032 unsigned long freq;
0033 unsigned int xtaldiv;
0034 unsigned int plldiv;
0035 unsigned int postdiv;
0036 unsigned int buckdiv;
0037 unsigned int boostdiv;
0038 } clk_freqs[] = {
0039
0040
0041
0042
0043
0044
0045
0046
0047
0048
0049
0050
0051
0052
0053
0054
0055
0056
0057
0058
0059
0060
0061
0062
0063
0064 { 19200000, 170, 32, 1, 2, 3 },
0065 { 20000000, 170, 40, 1, 3, 4 },
0066 { 24000000, 170, 80, 1, 4, 8 },
0067 };
0068
0069 struct tps68470_clkdata {
0070 struct clk_hw clkout_hw;
0071 struct regmap *regmap;
0072 unsigned long rate;
0073 };
0074
0075 static int tps68470_clk_is_prepared(struct clk_hw *hw)
0076 {
0077 struct tps68470_clkdata *clkdata = to_tps68470_clkdata(hw);
0078 int val;
0079
0080 if (regmap_read(clkdata->regmap, TPS68470_REG_PLLCTL, &val))
0081 return 0;
0082
0083 return val & TPS68470_PLL_EN_MASK;
0084 }
0085
0086 static int tps68470_clk_prepare(struct clk_hw *hw)
0087 {
0088 struct tps68470_clkdata *clkdata = to_tps68470_clkdata(hw);
0089
0090 regmap_write(clkdata->regmap, TPS68470_REG_CLKCFG1,
0091 (TPS68470_PLL_OUTPUT_ENABLE << TPS68470_OUTPUT_A_SHIFT) |
0092 (TPS68470_PLL_OUTPUT_ENABLE << TPS68470_OUTPUT_B_SHIFT));
0093
0094 regmap_update_bits(clkdata->regmap, TPS68470_REG_PLLCTL,
0095 TPS68470_PLL_EN_MASK, TPS68470_PLL_EN_MASK);
0096
0097
0098
0099
0100
0101 usleep_range(4000, 5000);
0102
0103 return 0;
0104 }
0105
0106 static void tps68470_clk_unprepare(struct clk_hw *hw)
0107 {
0108 struct tps68470_clkdata *clkdata = to_tps68470_clkdata(hw);
0109
0110
0111 regmap_update_bits(clkdata->regmap, TPS68470_REG_PLLCTL, TPS68470_PLL_EN_MASK, 0);
0112
0113
0114 regmap_write(clkdata->regmap, TPS68470_REG_CLKCFG1, 0);
0115 }
0116
0117 static unsigned long tps68470_clk_recalc_rate(struct clk_hw *hw, unsigned long parent_rate)
0118 {
0119 struct tps68470_clkdata *clkdata = to_tps68470_clkdata(hw);
0120
0121 return clkdata->rate;
0122 }
0123
0124
0125
0126
0127
0128
0129 static unsigned int tps68470_clk_cfg_lookup(unsigned long rate)
0130 {
0131 long diff, best_diff = LONG_MAX;
0132 unsigned int i, best_idx = 0;
0133
0134 for (i = 0; i < ARRAY_SIZE(clk_freqs); i++) {
0135 diff = clk_freqs[i].freq - rate;
0136 if (diff == 0)
0137 return i;
0138
0139 diff = abs(diff);
0140 if (diff < best_diff) {
0141 best_diff = diff;
0142 best_idx = i;
0143 }
0144 }
0145
0146 return best_idx;
0147 }
0148
0149 static long tps68470_clk_round_rate(struct clk_hw *hw, unsigned long rate,
0150 unsigned long *parent_rate)
0151 {
0152 unsigned int idx = tps68470_clk_cfg_lookup(rate);
0153
0154 return clk_freqs[idx].freq;
0155 }
0156
0157 static int tps68470_clk_set_rate(struct clk_hw *hw, unsigned long rate,
0158 unsigned long parent_rate)
0159 {
0160 struct tps68470_clkdata *clkdata = to_tps68470_clkdata(hw);
0161 unsigned int idx = tps68470_clk_cfg_lookup(rate);
0162
0163 if (rate != clk_freqs[idx].freq)
0164 return -EINVAL;
0165
0166 regmap_write(clkdata->regmap, TPS68470_REG_BOOSTDIV, clk_freqs[idx].boostdiv);
0167 regmap_write(clkdata->regmap, TPS68470_REG_BUCKDIV, clk_freqs[idx].buckdiv);
0168 regmap_write(clkdata->regmap, TPS68470_REG_PLLSWR, TPS68470_PLLSWR_DEFAULT);
0169 regmap_write(clkdata->regmap, TPS68470_REG_XTALDIV, clk_freqs[idx].xtaldiv);
0170 regmap_write(clkdata->regmap, TPS68470_REG_PLLDIV, clk_freqs[idx].plldiv);
0171 regmap_write(clkdata->regmap, TPS68470_REG_POSTDIV, clk_freqs[idx].postdiv);
0172 regmap_write(clkdata->regmap, TPS68470_REG_POSTDIV2, clk_freqs[idx].postdiv);
0173 regmap_write(clkdata->regmap, TPS68470_REG_CLKCFG2, TPS68470_CLKCFG2_DRV_STR_2MA);
0174
0175 regmap_write(clkdata->regmap, TPS68470_REG_PLLCTL,
0176 TPS68470_OSC_EXT_CAP_DEFAULT << TPS68470_OSC_EXT_CAP_SHIFT |
0177 TPS68470_CLK_SRC_XTAL << TPS68470_CLK_SRC_SHIFT);
0178
0179 clkdata->rate = rate;
0180
0181 return 0;
0182 }
0183
0184 static const struct clk_ops tps68470_clk_ops = {
0185 .is_prepared = tps68470_clk_is_prepared,
0186 .prepare = tps68470_clk_prepare,
0187 .unprepare = tps68470_clk_unprepare,
0188 .recalc_rate = tps68470_clk_recalc_rate,
0189 .round_rate = tps68470_clk_round_rate,
0190 .set_rate = tps68470_clk_set_rate,
0191 };
0192
0193 static int tps68470_clk_probe(struct platform_device *pdev)
0194 {
0195 struct tps68470_clk_platform_data *pdata = pdev->dev.platform_data;
0196 struct clk_init_data tps68470_clk_initdata = {
0197 .name = TPS68470_CLK_NAME,
0198 .ops = &tps68470_clk_ops,
0199
0200 .flags = CLK_SET_RATE_GATE,
0201 };
0202 struct tps68470_clkdata *tps68470_clkdata;
0203 int ret;
0204
0205 tps68470_clkdata = devm_kzalloc(&pdev->dev, sizeof(*tps68470_clkdata),
0206 GFP_KERNEL);
0207 if (!tps68470_clkdata)
0208 return -ENOMEM;
0209
0210 tps68470_clkdata->regmap = dev_get_drvdata(pdev->dev.parent);
0211 tps68470_clkdata->clkout_hw.init = &tps68470_clk_initdata;
0212
0213
0214 tps68470_clk_set_rate(&tps68470_clkdata->clkout_hw, clk_freqs[0].freq, 0);
0215
0216 ret = devm_clk_hw_register(&pdev->dev, &tps68470_clkdata->clkout_hw);
0217 if (ret)
0218 return ret;
0219
0220 ret = devm_clk_hw_register_clkdev(&pdev->dev, &tps68470_clkdata->clkout_hw,
0221 TPS68470_CLK_NAME, NULL);
0222 if (ret)
0223 return ret;
0224
0225 if (pdata) {
0226 ret = devm_clk_hw_register_clkdev(&pdev->dev,
0227 &tps68470_clkdata->clkout_hw,
0228 pdata->consumer_con_id,
0229 pdata->consumer_dev_name);
0230 }
0231
0232 return ret;
0233 }
0234
0235 static struct platform_driver tps68470_clk_driver = {
0236 .driver = {
0237 .name = TPS68470_CLK_NAME,
0238 },
0239 .probe = tps68470_clk_probe,
0240 };
0241
0242
0243
0244
0245
0246
0247 static int __init tps68470_clk_init(void)
0248 {
0249 return platform_driver_register(&tps68470_clk_driver);
0250 }
0251 subsys_initcall(tps68470_clk_init);
0252
0253 static void __exit tps68470_clk_exit(void)
0254 {
0255 platform_driver_unregister(&tps68470_clk_driver);
0256 }
0257 module_exit(tps68470_clk_exit);
0258
0259 MODULE_ALIAS("platform:tps68470-clk");
0260 MODULE_DESCRIPTION("clock driver for TPS68470 pmic");
0261 MODULE_LICENSE("GPL");