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