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