1f05259a6SMark Brown /* 2f05259a6SMark Brown * WM831x clock control 3f05259a6SMark Brown * 4f05259a6SMark Brown * Copyright 2011-2 Wolfson Microelectronics PLC. 5f05259a6SMark Brown * 6f05259a6SMark Brown * Author: Mark Brown <broonie@opensource.wolfsonmicro.com> 7f05259a6SMark Brown * 8f05259a6SMark Brown * This program is free software; you can redistribute it and/or modify it 9f05259a6SMark Brown * under the terms of the GNU General Public License as published by the 10f05259a6SMark Brown * Free Software Foundation; either version 2 of the License, or (at your 11f05259a6SMark Brown * option) any later version. 12f05259a6SMark Brown * 13f05259a6SMark Brown */ 14f05259a6SMark Brown 15f05259a6SMark Brown #include <linux/clk-provider.h> 16f05259a6SMark Brown #include <linux/delay.h> 17f05259a6SMark Brown #include <linux/module.h> 18f05259a6SMark Brown #include <linux/slab.h> 19f05259a6SMark Brown #include <linux/platform_device.h> 20f05259a6SMark Brown #include <linux/mfd/wm831x/core.h> 21f05259a6SMark Brown 22f05259a6SMark Brown struct wm831x_clk { 23f05259a6SMark Brown struct wm831x *wm831x; 24f05259a6SMark Brown struct clk_hw xtal_hw; 25f05259a6SMark Brown struct clk_hw fll_hw; 26f05259a6SMark Brown struct clk_hw clkout_hw; 27f05259a6SMark Brown bool xtal_ena; 28f05259a6SMark Brown }; 29f05259a6SMark Brown 30a5828a6cSMark Brown static int wm831x_xtal_is_prepared(struct clk_hw *hw) 31f05259a6SMark Brown { 32f05259a6SMark Brown struct wm831x_clk *clkdata = container_of(hw, struct wm831x_clk, 33f05259a6SMark Brown xtal_hw); 34f05259a6SMark Brown 35f05259a6SMark Brown return clkdata->xtal_ena; 36f05259a6SMark Brown } 37f05259a6SMark Brown 38f05259a6SMark Brown static unsigned long wm831x_xtal_recalc_rate(struct clk_hw *hw, 39f05259a6SMark Brown unsigned long parent_rate) 40f05259a6SMark Brown { 41f05259a6SMark Brown struct wm831x_clk *clkdata = container_of(hw, struct wm831x_clk, 42f05259a6SMark Brown xtal_hw); 43f05259a6SMark Brown 44f05259a6SMark Brown if (clkdata->xtal_ena) 45f05259a6SMark Brown return 32768; 46f05259a6SMark Brown else 47f05259a6SMark Brown return 0; 48f05259a6SMark Brown } 49f05259a6SMark Brown 50f05259a6SMark Brown static const struct clk_ops wm831x_xtal_ops = { 51a5828a6cSMark Brown .is_prepared = wm831x_xtal_is_prepared, 52f05259a6SMark Brown .recalc_rate = wm831x_xtal_recalc_rate, 53f05259a6SMark Brown }; 54f05259a6SMark Brown 55f05259a6SMark Brown static struct clk_init_data wm831x_xtal_init = { 56f05259a6SMark Brown .name = "xtal", 57f05259a6SMark Brown .ops = &wm831x_xtal_ops, 58f05259a6SMark Brown }; 59f05259a6SMark Brown 60f05259a6SMark Brown static const unsigned long wm831x_fll_auto_rates[] = { 61f05259a6SMark Brown 2048000, 62f05259a6SMark Brown 11289600, 63f05259a6SMark Brown 12000000, 64f05259a6SMark Brown 12288000, 65f05259a6SMark Brown 19200000, 66f05259a6SMark Brown 22579600, 67f05259a6SMark Brown 24000000, 68f05259a6SMark Brown 24576000, 69f05259a6SMark Brown }; 70f05259a6SMark Brown 71a5828a6cSMark Brown static int wm831x_fll_is_prepared(struct clk_hw *hw) 72f05259a6SMark Brown { 73f05259a6SMark Brown struct wm831x_clk *clkdata = container_of(hw, struct wm831x_clk, 74f05259a6SMark Brown fll_hw); 75f05259a6SMark Brown struct wm831x *wm831x = clkdata->wm831x; 76f05259a6SMark Brown int ret; 77f05259a6SMark Brown 78f05259a6SMark Brown ret = wm831x_reg_read(wm831x, WM831X_FLL_CONTROL_1); 79f05259a6SMark Brown if (ret < 0) { 80f05259a6SMark Brown dev_err(wm831x->dev, "Unable to read FLL_CONTROL_1: %d\n", 81f05259a6SMark Brown ret); 82f05259a6SMark Brown return true; 83f05259a6SMark Brown } 84f05259a6SMark Brown 85f05259a6SMark Brown return (ret & WM831X_FLL_ENA) != 0; 86f05259a6SMark Brown } 87f05259a6SMark Brown 88f05259a6SMark Brown static int wm831x_fll_prepare(struct clk_hw *hw) 89f05259a6SMark Brown { 90f05259a6SMark Brown struct wm831x_clk *clkdata = container_of(hw, struct wm831x_clk, 91f05259a6SMark Brown fll_hw); 92f05259a6SMark Brown struct wm831x *wm831x = clkdata->wm831x; 93f05259a6SMark Brown int ret; 94f05259a6SMark Brown 956f8b3145SAxel Lin ret = wm831x_set_bits(wm831x, WM831X_FLL_CONTROL_1, 96f05259a6SMark Brown WM831X_FLL_ENA, WM831X_FLL_ENA); 97f05259a6SMark Brown if (ret != 0) 98f05259a6SMark Brown dev_crit(wm831x->dev, "Failed to enable FLL: %d\n", ret); 99f05259a6SMark Brown 100*ed784c53SNicholas Mc Guire /* wait 2-3 ms for new frequency taking effect */ 101*ed784c53SNicholas Mc Guire usleep_range(2000, 3000); 102f05259a6SMark Brown 103f05259a6SMark Brown return ret; 104f05259a6SMark Brown } 105f05259a6SMark Brown 106f05259a6SMark Brown static void wm831x_fll_unprepare(struct clk_hw *hw) 107f05259a6SMark Brown { 108f05259a6SMark Brown struct wm831x_clk *clkdata = container_of(hw, struct wm831x_clk, 109f05259a6SMark Brown fll_hw); 110f05259a6SMark Brown struct wm831x *wm831x = clkdata->wm831x; 111f05259a6SMark Brown int ret; 112f05259a6SMark Brown 1136f8b3145SAxel Lin ret = wm831x_set_bits(wm831x, WM831X_FLL_CONTROL_1, WM831X_FLL_ENA, 0); 114f05259a6SMark Brown if (ret != 0) 1156f8b3145SAxel Lin dev_crit(wm831x->dev, "Failed to disable FLL: %d\n", ret); 116f05259a6SMark Brown } 117f05259a6SMark Brown 118f05259a6SMark Brown static unsigned long wm831x_fll_recalc_rate(struct clk_hw *hw, 119f05259a6SMark Brown unsigned long parent_rate) 120f05259a6SMark Brown { 121f05259a6SMark Brown struct wm831x_clk *clkdata = container_of(hw, struct wm831x_clk, 122f05259a6SMark Brown fll_hw); 123f05259a6SMark Brown struct wm831x *wm831x = clkdata->wm831x; 124f05259a6SMark Brown int ret; 125f05259a6SMark Brown 126f05259a6SMark Brown ret = wm831x_reg_read(wm831x, WM831X_CLOCK_CONTROL_2); 127f05259a6SMark Brown if (ret < 0) { 128f05259a6SMark Brown dev_err(wm831x->dev, "Unable to read CLOCK_CONTROL_2: %d\n", 129f05259a6SMark Brown ret); 130f05259a6SMark Brown return 0; 131f05259a6SMark Brown } 132f05259a6SMark Brown 133f05259a6SMark Brown if (ret & WM831X_FLL_AUTO) 134f05259a6SMark Brown return wm831x_fll_auto_rates[ret & WM831X_FLL_AUTO_FREQ_MASK]; 135f05259a6SMark Brown 136f05259a6SMark Brown dev_err(wm831x->dev, "FLL only supported in AUTO mode\n"); 137f05259a6SMark Brown 138f05259a6SMark Brown return 0; 139f05259a6SMark Brown } 140f05259a6SMark Brown 141f05259a6SMark Brown static long wm831x_fll_round_rate(struct clk_hw *hw, unsigned long rate, 142f05259a6SMark Brown unsigned long *unused) 143f05259a6SMark Brown { 144f05259a6SMark Brown int best = 0; 145f05259a6SMark Brown int i; 146f05259a6SMark Brown 147f05259a6SMark Brown for (i = 0; i < ARRAY_SIZE(wm831x_fll_auto_rates); i++) 148f05259a6SMark Brown if (abs(wm831x_fll_auto_rates[i] - rate) < 149f05259a6SMark Brown abs(wm831x_fll_auto_rates[best] - rate)) 150f05259a6SMark Brown best = i; 151f05259a6SMark Brown 152f05259a6SMark Brown return wm831x_fll_auto_rates[best]; 153f05259a6SMark Brown } 154f05259a6SMark Brown 155f05259a6SMark Brown static int wm831x_fll_set_rate(struct clk_hw *hw, unsigned long rate, 156f05259a6SMark Brown unsigned long parent_rate) 157f05259a6SMark Brown { 158f05259a6SMark Brown struct wm831x_clk *clkdata = container_of(hw, struct wm831x_clk, 159f05259a6SMark Brown fll_hw); 160f05259a6SMark Brown struct wm831x *wm831x = clkdata->wm831x; 161f05259a6SMark Brown int i; 162f05259a6SMark Brown 163f05259a6SMark Brown for (i = 0; i < ARRAY_SIZE(wm831x_fll_auto_rates); i++) 164f05259a6SMark Brown if (wm831x_fll_auto_rates[i] == rate) 165f05259a6SMark Brown break; 166f05259a6SMark Brown if (i == ARRAY_SIZE(wm831x_fll_auto_rates)) 167f05259a6SMark Brown return -EINVAL; 168f05259a6SMark Brown 169a5828a6cSMark Brown if (wm831x_fll_is_prepared(hw)) 170f05259a6SMark Brown return -EPERM; 171f05259a6SMark Brown 172f05259a6SMark Brown return wm831x_set_bits(wm831x, WM831X_CLOCK_CONTROL_2, 173f05259a6SMark Brown WM831X_FLL_AUTO_FREQ_MASK, i); 174f05259a6SMark Brown } 175f05259a6SMark Brown 176f05259a6SMark Brown static const char *wm831x_fll_parents[] = { 177f05259a6SMark Brown "xtal", 178f05259a6SMark Brown "clkin", 179f05259a6SMark Brown }; 180f05259a6SMark Brown 181f05259a6SMark Brown static u8 wm831x_fll_get_parent(struct clk_hw *hw) 182f05259a6SMark Brown { 183f05259a6SMark Brown struct wm831x_clk *clkdata = container_of(hw, struct wm831x_clk, 184f05259a6SMark Brown fll_hw); 185f05259a6SMark Brown struct wm831x *wm831x = clkdata->wm831x; 186f05259a6SMark Brown int ret; 187f05259a6SMark Brown 188f05259a6SMark Brown /* AUTO mode is always clocked from the crystal */ 189f05259a6SMark Brown ret = wm831x_reg_read(wm831x, WM831X_CLOCK_CONTROL_2); 190f05259a6SMark Brown if (ret < 0) { 191f05259a6SMark Brown dev_err(wm831x->dev, "Unable to read CLOCK_CONTROL_2: %d\n", 192f05259a6SMark Brown ret); 193f05259a6SMark Brown return 0; 194f05259a6SMark Brown } 195f05259a6SMark Brown 196f05259a6SMark Brown if (ret & WM831X_FLL_AUTO) 197f05259a6SMark Brown return 0; 198f05259a6SMark Brown 199f05259a6SMark Brown ret = wm831x_reg_read(wm831x, WM831X_FLL_CONTROL_5); 200f05259a6SMark Brown if (ret < 0) { 201f05259a6SMark Brown dev_err(wm831x->dev, "Unable to read FLL_CONTROL_5: %d\n", 202f05259a6SMark Brown ret); 203f05259a6SMark Brown return 0; 204f05259a6SMark Brown } 205f05259a6SMark Brown 206f05259a6SMark Brown switch (ret & WM831X_FLL_CLK_SRC_MASK) { 207f05259a6SMark Brown case 0: 208f05259a6SMark Brown return 0; 209f05259a6SMark Brown case 1: 210f05259a6SMark Brown return 1; 211f05259a6SMark Brown default: 212f05259a6SMark Brown dev_err(wm831x->dev, "Unsupported FLL clock source %d\n", 213f05259a6SMark Brown ret & WM831X_FLL_CLK_SRC_MASK); 214f05259a6SMark Brown return 0; 215f05259a6SMark Brown } 216f05259a6SMark Brown } 217f05259a6SMark Brown 218f05259a6SMark Brown static const struct clk_ops wm831x_fll_ops = { 219a5828a6cSMark Brown .is_prepared = wm831x_fll_is_prepared, 220f05259a6SMark Brown .prepare = wm831x_fll_prepare, 221f05259a6SMark Brown .unprepare = wm831x_fll_unprepare, 222f05259a6SMark Brown .round_rate = wm831x_fll_round_rate, 223f05259a6SMark Brown .recalc_rate = wm831x_fll_recalc_rate, 224f05259a6SMark Brown .set_rate = wm831x_fll_set_rate, 225f05259a6SMark Brown .get_parent = wm831x_fll_get_parent, 226f05259a6SMark Brown }; 227f05259a6SMark Brown 228f05259a6SMark Brown static struct clk_init_data wm831x_fll_init = { 229f05259a6SMark Brown .name = "fll", 230f05259a6SMark Brown .ops = &wm831x_fll_ops, 231f05259a6SMark Brown .parent_names = wm831x_fll_parents, 232f05259a6SMark Brown .num_parents = ARRAY_SIZE(wm831x_fll_parents), 233f05259a6SMark Brown .flags = CLK_SET_RATE_GATE, 234f05259a6SMark Brown }; 235f05259a6SMark Brown 236a5828a6cSMark Brown static int wm831x_clkout_is_prepared(struct clk_hw *hw) 237f05259a6SMark Brown { 238f05259a6SMark Brown struct wm831x_clk *clkdata = container_of(hw, struct wm831x_clk, 239f05259a6SMark Brown clkout_hw); 240f05259a6SMark Brown struct wm831x *wm831x = clkdata->wm831x; 241f05259a6SMark Brown int ret; 242f05259a6SMark Brown 243f05259a6SMark Brown ret = wm831x_reg_read(wm831x, WM831X_CLOCK_CONTROL_1); 244f05259a6SMark Brown if (ret < 0) { 245f05259a6SMark Brown dev_err(wm831x->dev, "Unable to read CLOCK_CONTROL_1: %d\n", 246f05259a6SMark Brown ret); 24720979202SPan Bian return false; 248f05259a6SMark Brown } 249f05259a6SMark Brown 250f05259a6SMark Brown return (ret & WM831X_CLKOUT_ENA) != 0; 251f05259a6SMark Brown } 252f05259a6SMark Brown 253f05259a6SMark Brown static int wm831x_clkout_prepare(struct clk_hw *hw) 254f05259a6SMark Brown { 255f05259a6SMark Brown struct wm831x_clk *clkdata = container_of(hw, struct wm831x_clk, 256f05259a6SMark Brown clkout_hw); 257f05259a6SMark Brown struct wm831x *wm831x = clkdata->wm831x; 258f05259a6SMark Brown int ret; 259f05259a6SMark Brown 260f05259a6SMark Brown ret = wm831x_reg_unlock(wm831x); 261f05259a6SMark Brown if (ret != 0) { 262f05259a6SMark Brown dev_crit(wm831x->dev, "Failed to lock registers: %d\n", ret); 263f05259a6SMark Brown return ret; 264f05259a6SMark Brown } 265f05259a6SMark Brown 266f05259a6SMark Brown ret = wm831x_set_bits(wm831x, WM831X_CLOCK_CONTROL_1, 267f05259a6SMark Brown WM831X_CLKOUT_ENA, WM831X_CLKOUT_ENA); 268f05259a6SMark Brown if (ret != 0) 269f05259a6SMark Brown dev_crit(wm831x->dev, "Failed to enable CLKOUT: %d\n", ret); 270f05259a6SMark Brown 271f05259a6SMark Brown wm831x_reg_lock(wm831x); 272f05259a6SMark Brown 273f05259a6SMark Brown return ret; 274f05259a6SMark Brown } 275f05259a6SMark Brown 276f05259a6SMark Brown static void wm831x_clkout_unprepare(struct clk_hw *hw) 277f05259a6SMark Brown { 278f05259a6SMark Brown struct wm831x_clk *clkdata = container_of(hw, struct wm831x_clk, 279f05259a6SMark Brown clkout_hw); 280f05259a6SMark Brown struct wm831x *wm831x = clkdata->wm831x; 281f05259a6SMark Brown int ret; 282f05259a6SMark Brown 283f05259a6SMark Brown ret = wm831x_reg_unlock(wm831x); 284f05259a6SMark Brown if (ret != 0) { 285f05259a6SMark Brown dev_crit(wm831x->dev, "Failed to lock registers: %d\n", ret); 286f05259a6SMark Brown return; 287f05259a6SMark Brown } 288f05259a6SMark Brown 289f05259a6SMark Brown ret = wm831x_set_bits(wm831x, WM831X_CLOCK_CONTROL_1, 290f05259a6SMark Brown WM831X_CLKOUT_ENA, 0); 291f05259a6SMark Brown if (ret != 0) 292f05259a6SMark Brown dev_crit(wm831x->dev, "Failed to disable CLKOUT: %d\n", ret); 293f05259a6SMark Brown 294f05259a6SMark Brown wm831x_reg_lock(wm831x); 295f05259a6SMark Brown } 296f05259a6SMark Brown 297f05259a6SMark Brown static const char *wm831x_clkout_parents[] = { 298f05259a6SMark Brown "fll", 299bcc7fd20SAxel Lin "xtal", 300f05259a6SMark Brown }; 301f05259a6SMark Brown 302f05259a6SMark Brown static u8 wm831x_clkout_get_parent(struct clk_hw *hw) 303f05259a6SMark Brown { 304f05259a6SMark Brown struct wm831x_clk *clkdata = container_of(hw, struct wm831x_clk, 305f05259a6SMark Brown clkout_hw); 306f05259a6SMark Brown struct wm831x *wm831x = clkdata->wm831x; 307f05259a6SMark Brown int ret; 308f05259a6SMark Brown 309f05259a6SMark Brown ret = wm831x_reg_read(wm831x, WM831X_CLOCK_CONTROL_1); 310f05259a6SMark Brown if (ret < 0) { 311f05259a6SMark Brown dev_err(wm831x->dev, "Unable to read CLOCK_CONTROL_1: %d\n", 312f05259a6SMark Brown ret); 313f05259a6SMark Brown return 0; 314f05259a6SMark Brown } 315f05259a6SMark Brown 316f05259a6SMark Brown if (ret & WM831X_CLKOUT_SRC) 317f05259a6SMark Brown return 1; 318bcc7fd20SAxel Lin else 319bcc7fd20SAxel Lin return 0; 320f05259a6SMark Brown } 321f05259a6SMark Brown 322f05259a6SMark Brown static int wm831x_clkout_set_parent(struct clk_hw *hw, u8 parent) 323f05259a6SMark Brown { 324f05259a6SMark Brown struct wm831x_clk *clkdata = container_of(hw, struct wm831x_clk, 325f05259a6SMark Brown clkout_hw); 326f05259a6SMark Brown struct wm831x *wm831x = clkdata->wm831x; 327f05259a6SMark Brown 328f05259a6SMark Brown return wm831x_set_bits(wm831x, WM831X_CLOCK_CONTROL_1, 329f05259a6SMark Brown WM831X_CLKOUT_SRC, 330f05259a6SMark Brown parent << WM831X_CLKOUT_SRC_SHIFT); 331f05259a6SMark Brown } 332f05259a6SMark Brown 333f05259a6SMark Brown static const struct clk_ops wm831x_clkout_ops = { 334a5828a6cSMark Brown .is_prepared = wm831x_clkout_is_prepared, 335f05259a6SMark Brown .prepare = wm831x_clkout_prepare, 336f05259a6SMark Brown .unprepare = wm831x_clkout_unprepare, 337f05259a6SMark Brown .get_parent = wm831x_clkout_get_parent, 338f05259a6SMark Brown .set_parent = wm831x_clkout_set_parent, 339f05259a6SMark Brown }; 340f05259a6SMark Brown 341f05259a6SMark Brown static struct clk_init_data wm831x_clkout_init = { 342f05259a6SMark Brown .name = "clkout", 343f05259a6SMark Brown .ops = &wm831x_clkout_ops, 344f05259a6SMark Brown .parent_names = wm831x_clkout_parents, 345f05259a6SMark Brown .num_parents = ARRAY_SIZE(wm831x_clkout_parents), 346f05259a6SMark Brown .flags = CLK_SET_RATE_PARENT, 347f05259a6SMark Brown }; 348f05259a6SMark Brown 349018ae93fSBill Pemberton static int wm831x_clk_probe(struct platform_device *pdev) 350f05259a6SMark Brown { 351f05259a6SMark Brown struct wm831x *wm831x = dev_get_drvdata(pdev->dev.parent); 352f05259a6SMark Brown struct wm831x_clk *clkdata; 353f05259a6SMark Brown int ret; 354f05259a6SMark Brown 355f05259a6SMark Brown clkdata = devm_kzalloc(&pdev->dev, sizeof(*clkdata), GFP_KERNEL); 356f05259a6SMark Brown if (!clkdata) 357f05259a6SMark Brown return -ENOMEM; 358f05259a6SMark Brown 35908442ce9SMark Brown clkdata->wm831x = wm831x; 36008442ce9SMark Brown 361f05259a6SMark Brown /* XTAL_ENA can only be set via OTP/InstantConfig so just read once */ 362f05259a6SMark Brown ret = wm831x_reg_read(wm831x, WM831X_CLOCK_CONTROL_2); 363f05259a6SMark Brown if (ret < 0) { 364f05259a6SMark Brown dev_err(wm831x->dev, "Unable to read CLOCK_CONTROL_2: %d\n", 365f05259a6SMark Brown ret); 366f05259a6SMark Brown return ret; 367f05259a6SMark Brown } 368f05259a6SMark Brown clkdata->xtal_ena = ret & WM831X_XTAL_ENA; 369f05259a6SMark Brown 370f05259a6SMark Brown clkdata->xtal_hw.init = &wm831x_xtal_init; 371cc671d13SStephen Boyd ret = devm_clk_hw_register(&pdev->dev, &clkdata->xtal_hw); 372cc671d13SStephen Boyd if (ret) 373cc671d13SStephen Boyd return ret; 374f05259a6SMark Brown 375f05259a6SMark Brown clkdata->fll_hw.init = &wm831x_fll_init; 376cc671d13SStephen Boyd ret = devm_clk_hw_register(&pdev->dev, &clkdata->fll_hw); 377cc671d13SStephen Boyd if (ret) 378cc671d13SStephen Boyd return ret; 379f05259a6SMark Brown 380f05259a6SMark Brown clkdata->clkout_hw.init = &wm831x_clkout_init; 381cc671d13SStephen Boyd ret = devm_clk_hw_register(&pdev->dev, &clkdata->clkout_hw); 382cc671d13SStephen Boyd if (ret) 383cc671d13SStephen Boyd return ret; 384f05259a6SMark Brown 385c0431037SJingoo Han platform_set_drvdata(pdev, clkdata); 386f05259a6SMark Brown 387f05259a6SMark Brown return 0; 388f05259a6SMark Brown } 389f05259a6SMark Brown 390f05259a6SMark Brown static struct platform_driver wm831x_clk_driver = { 391f05259a6SMark Brown .probe = wm831x_clk_probe, 392f05259a6SMark Brown .driver = { 393f05259a6SMark Brown .name = "wm831x-clk", 394f05259a6SMark Brown }, 395f05259a6SMark Brown }; 396f05259a6SMark Brown 397f05259a6SMark Brown module_platform_driver(wm831x_clk_driver); 398f05259a6SMark Brown 399f05259a6SMark Brown /* Module information */ 400f05259a6SMark Brown MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>"); 401f05259a6SMark Brown MODULE_DESCRIPTION("WM831x clock driver"); 402f05259a6SMark Brown MODULE_LICENSE("GPL"); 403f05259a6SMark Brown MODULE_ALIAS("platform:wm831x-clk"); 404