| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0 |
|---|
| 1 | 2 | /* |
|---|
| 2 | 3 | * Copyright (c) 2013 NVIDIA CORPORATION. All rights reserved. |
|---|
| 3 | | - * |
|---|
| 4 | | - * This program is free software; you can redistribute it and/or modify it |
|---|
| 5 | | - * under the terms and conditions of the GNU General Public License, |
|---|
| 6 | | - * version 2, as published by the Free Software Foundation. |
|---|
| 7 | | - * |
|---|
| 8 | | - * This program is distributed in the hope it will be useful, but WITHOUT |
|---|
| 9 | | - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
|---|
| 10 | | - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for |
|---|
| 11 | | - * more details. |
|---|
| 12 | | - * |
|---|
| 13 | | - * You should have received a copy of the GNU General Public License |
|---|
| 14 | | - * along with this program. If not, see <http://www.gnu.org/licenses/>. |
|---|
| 15 | 4 | */ |
|---|
| 16 | 5 | |
|---|
| 17 | | -#include <linux/clk.h> |
|---|
| 18 | 6 | #include <linux/clk-provider.h> |
|---|
| 19 | 7 | #include <linux/err.h> |
|---|
| 20 | 8 | #include <linux/slab.h> |
|---|
| .. | .. |
|---|
| 161 | 149 | const struct clk_ops *mux_ops = composite->mux_ops; |
|---|
| 162 | 150 | struct clk_hw *rate_hw = composite->rate_hw; |
|---|
| 163 | 151 | struct clk_hw *mux_hw = composite->mux_hw; |
|---|
| 164 | | - struct clk_hw *brother_hw = composite->brother_hw; |
|---|
| 165 | 152 | unsigned long temp_rate; |
|---|
| 166 | | - |
|---|
| 167 | | - if (brother_hw) { |
|---|
| 168 | | - struct clk_composite *bcomposite = to_clk_composite(brother_hw); |
|---|
| 169 | | - const struct clk_ops *brate_ops = bcomposite->rate_ops; |
|---|
| 170 | | - struct clk_hw *brate_hw = bcomposite->rate_hw; |
|---|
| 171 | | - struct clk_hw *parent_hw = clk_hw_get_parent(brother_hw); |
|---|
| 172 | | - struct clk_hw *new_parent_hw = clk_hw_get_parent(hw); |
|---|
| 173 | | - |
|---|
| 174 | | - __clk_hw_set_clk(brate_hw, brother_hw); |
|---|
| 175 | | - |
|---|
| 176 | | - temp_rate = brate_ops->recalc_rate(brate_hw, parent_rate); |
|---|
| 177 | | - if (temp_rate > rate) |
|---|
| 178 | | - brate_ops->set_rate(brate_hw, rate, parent_rate); |
|---|
| 179 | | - if (clk_hw_is_prepared(brother_hw)) { |
|---|
| 180 | | - clk_prepare_enable(new_parent_hw->clk); |
|---|
| 181 | | - clk_enable(brother_hw->clk); |
|---|
| 182 | | - } |
|---|
| 183 | | - clk_hw_reparent(brother_hw, new_parent_hw); |
|---|
| 184 | | - if (clk_hw_is_prepared(brother_hw)) { |
|---|
| 185 | | - clk_disable(brother_hw->clk); |
|---|
| 186 | | - clk_disable_unprepare(parent_hw->clk); |
|---|
| 187 | | - } |
|---|
| 188 | | - } |
|---|
| 189 | 153 | |
|---|
| 190 | 154 | __clk_hw_set_clk(rate_hw, hw); |
|---|
| 191 | 155 | __clk_hw_set_clk(mux_hw, hw); |
|---|
| .. | .. |
|---|
| 235 | 199 | gate_ops->disable(gate_hw); |
|---|
| 236 | 200 | } |
|---|
| 237 | 201 | |
|---|
| 238 | | -struct clk_hw *clk_hw_register_composite(struct device *dev, const char *name, |
|---|
| 239 | | - const char * const *parent_names, int num_parents, |
|---|
| 202 | +static struct clk_hw *__clk_hw_register_composite(struct device *dev, |
|---|
| 203 | + const char *name, const char * const *parent_names, |
|---|
| 204 | + const struct clk_parent_data *pdata, int num_parents, |
|---|
| 240 | 205 | struct clk_hw *mux_hw, const struct clk_ops *mux_ops, |
|---|
| 241 | 206 | struct clk_hw *rate_hw, const struct clk_ops *rate_ops, |
|---|
| 242 | 207 | struct clk_hw *gate_hw, const struct clk_ops *gate_ops, |
|---|
| .. | .. |
|---|
| 253 | 218 | return ERR_PTR(-ENOMEM); |
|---|
| 254 | 219 | |
|---|
| 255 | 220 | init.name = name; |
|---|
| 256 | | - init.flags = flags | CLK_IS_BASIC; |
|---|
| 257 | | - init.parent_names = parent_names; |
|---|
| 221 | + init.flags = flags; |
|---|
| 222 | + if (parent_names) |
|---|
| 223 | + init.parent_names = parent_names; |
|---|
| 224 | + else |
|---|
| 225 | + init.parent_data = pdata; |
|---|
| 258 | 226 | init.num_parents = num_parents; |
|---|
| 259 | 227 | hw = &composite->hw; |
|---|
| 260 | 228 | |
|---|
| .. | .. |
|---|
| 348 | 316 | return hw; |
|---|
| 349 | 317 | } |
|---|
| 350 | 318 | |
|---|
| 319 | +struct clk_hw *clk_hw_register_composite(struct device *dev, const char *name, |
|---|
| 320 | + const char * const *parent_names, int num_parents, |
|---|
| 321 | + struct clk_hw *mux_hw, const struct clk_ops *mux_ops, |
|---|
| 322 | + struct clk_hw *rate_hw, const struct clk_ops *rate_ops, |
|---|
| 323 | + struct clk_hw *gate_hw, const struct clk_ops *gate_ops, |
|---|
| 324 | + unsigned long flags) |
|---|
| 325 | +{ |
|---|
| 326 | + return __clk_hw_register_composite(dev, name, parent_names, NULL, |
|---|
| 327 | + num_parents, mux_hw, mux_ops, |
|---|
| 328 | + rate_hw, rate_ops, gate_hw, |
|---|
| 329 | + gate_ops, flags); |
|---|
| 330 | +} |
|---|
| 331 | +EXPORT_SYMBOL_GPL(clk_hw_register_composite); |
|---|
| 332 | + |
|---|
| 333 | +struct clk_hw *clk_hw_register_composite_pdata(struct device *dev, |
|---|
| 334 | + const char *name, |
|---|
| 335 | + const struct clk_parent_data *parent_data, |
|---|
| 336 | + int num_parents, |
|---|
| 337 | + struct clk_hw *mux_hw, const struct clk_ops *mux_ops, |
|---|
| 338 | + struct clk_hw *rate_hw, const struct clk_ops *rate_ops, |
|---|
| 339 | + struct clk_hw *gate_hw, const struct clk_ops *gate_ops, |
|---|
| 340 | + unsigned long flags) |
|---|
| 341 | +{ |
|---|
| 342 | + return __clk_hw_register_composite(dev, name, NULL, parent_data, |
|---|
| 343 | + num_parents, mux_hw, mux_ops, |
|---|
| 344 | + rate_hw, rate_ops, gate_hw, |
|---|
| 345 | + gate_ops, flags); |
|---|
| 346 | +} |
|---|
| 347 | + |
|---|
| 351 | 348 | struct clk *clk_register_composite(struct device *dev, const char *name, |
|---|
| 352 | 349 | const char * const *parent_names, int num_parents, |
|---|
| 353 | 350 | struct clk_hw *mux_hw, const struct clk_ops *mux_ops, |
|---|
| .. | .. |
|---|
| 360 | 357 | hw = clk_hw_register_composite(dev, name, parent_names, num_parents, |
|---|
| 361 | 358 | mux_hw, mux_ops, rate_hw, rate_ops, gate_hw, gate_ops, |
|---|
| 362 | 359 | flags); |
|---|
| 360 | + if (IS_ERR(hw)) |
|---|
| 361 | + return ERR_CAST(hw); |
|---|
| 362 | + return hw->clk; |
|---|
| 363 | +} |
|---|
| 364 | +EXPORT_SYMBOL_GPL(clk_register_composite); |
|---|
| 365 | + |
|---|
| 366 | +struct clk *clk_register_composite_pdata(struct device *dev, const char *name, |
|---|
| 367 | + const struct clk_parent_data *parent_data, |
|---|
| 368 | + int num_parents, |
|---|
| 369 | + struct clk_hw *mux_hw, const struct clk_ops *mux_ops, |
|---|
| 370 | + struct clk_hw *rate_hw, const struct clk_ops *rate_ops, |
|---|
| 371 | + struct clk_hw *gate_hw, const struct clk_ops *gate_ops, |
|---|
| 372 | + unsigned long flags) |
|---|
| 373 | +{ |
|---|
| 374 | + struct clk_hw *hw; |
|---|
| 375 | + |
|---|
| 376 | + hw = clk_hw_register_composite_pdata(dev, name, parent_data, |
|---|
| 377 | + num_parents, mux_hw, mux_ops, rate_hw, rate_ops, |
|---|
| 378 | + gate_hw, gate_ops, flags); |
|---|
| 363 | 379 | if (IS_ERR(hw)) |
|---|
| 364 | 380 | return ERR_CAST(hw); |
|---|
| 365 | 381 | return hw->clk; |
|---|
| .. | .. |
|---|
| 379 | 395 | clk_unregister(clk); |
|---|
| 380 | 396 | kfree(composite); |
|---|
| 381 | 397 | } |
|---|
| 398 | + |
|---|
| 399 | +void clk_hw_unregister_composite(struct clk_hw *hw) |
|---|
| 400 | +{ |
|---|
| 401 | + struct clk_composite *composite; |
|---|
| 402 | + |
|---|
| 403 | + composite = to_clk_composite(hw); |
|---|
| 404 | + |
|---|
| 405 | + clk_hw_unregister(hw); |
|---|
| 406 | + kfree(composite); |
|---|
| 407 | +} |
|---|
| 408 | +EXPORT_SYMBOL_GPL(clk_hw_unregister_composite); |
|---|