| xj | b04a402 | 2021-11-25 15:01:52 +0800 | [diff] [blame] | 1 | /* | 
 | 2 |  * Copyright (C) 2016 Socionext Inc. | 
 | 3 |  *   Author: Masahiro Yamada <yamada.masahiro@socionext.com> | 
 | 4 |  * | 
 | 5 |  * This program is free software; you can redistribute it and/or modify | 
 | 6 |  * it under the terms of the GNU General Public License as published by | 
 | 7 |  * the Free Software Foundation; either version 2 of the License, or | 
 | 8 |  * (at your option) any later version. | 
 | 9 |  * | 
 | 10 |  * This program is distributed in the hope that it will be useful, | 
 | 11 |  * but WITHOUT ANY WARRANTY; without even the implied warranty of | 
 | 12 |  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | 
 | 13 |  * GNU General Public License for more details. | 
 | 14 |  */ | 
 | 15 |  | 
 | 16 | #include <linux/clk-provider.h> | 
 | 17 | #include <linux/device.h> | 
 | 18 | #include <linux/regmap.h> | 
 | 19 |  | 
 | 20 | #include "clk-uniphier.h" | 
 | 21 |  | 
 | 22 | struct uniphier_clk_mux { | 
 | 23 | 	struct clk_hw hw; | 
 | 24 | 	struct regmap *regmap; | 
 | 25 | 	unsigned int reg; | 
 | 26 | 	const unsigned int *masks; | 
 | 27 | 	const unsigned int *vals; | 
 | 28 | }; | 
 | 29 |  | 
 | 30 | #define to_uniphier_clk_mux(_hw) container_of(_hw, struct uniphier_clk_mux, hw) | 
 | 31 |  | 
 | 32 | static int uniphier_clk_mux_set_parent(struct clk_hw *hw, u8 index) | 
 | 33 | { | 
 | 34 | 	struct uniphier_clk_mux *mux = to_uniphier_clk_mux(hw); | 
 | 35 |  | 
 | 36 | 	return regmap_write_bits(mux->regmap, mux->reg, mux->masks[index], | 
 | 37 | 				 mux->vals[index]); | 
 | 38 | } | 
 | 39 |  | 
 | 40 | static u8 uniphier_clk_mux_get_parent(struct clk_hw *hw) | 
 | 41 | { | 
 | 42 | 	struct uniphier_clk_mux *mux = to_uniphier_clk_mux(hw); | 
 | 43 | 	int num_parents = clk_hw_get_num_parents(hw); | 
 | 44 | 	int ret; | 
 | 45 | 	unsigned int val; | 
 | 46 | 	u8 i; | 
 | 47 |  | 
 | 48 | 	ret = regmap_read(mux->regmap, mux->reg, &val); | 
 | 49 | 	if (ret) | 
 | 50 | 		return ret; | 
 | 51 |  | 
 | 52 | 	for (i = 0; i < num_parents; i++) | 
 | 53 | 		if ((mux->masks[i] & val) == mux->vals[i]) | 
 | 54 | 			return i; | 
 | 55 |  | 
 | 56 | 	return -EINVAL; | 
 | 57 | } | 
 | 58 |  | 
 | 59 | static const struct clk_ops uniphier_clk_mux_ops = { | 
 | 60 | 	.determine_rate = __clk_mux_determine_rate, | 
 | 61 | 	.set_parent = uniphier_clk_mux_set_parent, | 
 | 62 | 	.get_parent = uniphier_clk_mux_get_parent, | 
 | 63 | }; | 
 | 64 |  | 
 | 65 | struct clk_hw *uniphier_clk_register_mux(struct device *dev, | 
 | 66 | 					 struct regmap *regmap, | 
 | 67 | 					 const char *name, | 
 | 68 | 				const struct uniphier_clk_mux_data *data) | 
 | 69 | { | 
 | 70 | 	struct uniphier_clk_mux *mux; | 
 | 71 | 	struct clk_init_data init; | 
 | 72 | 	int ret; | 
 | 73 |  | 
 | 74 | 	mux = devm_kzalloc(dev, sizeof(*mux), GFP_KERNEL); | 
 | 75 | 	if (!mux) | 
 | 76 | 		return ERR_PTR(-ENOMEM); | 
 | 77 |  | 
 | 78 | 	init.name = name; | 
 | 79 | 	init.ops = &uniphier_clk_mux_ops; | 
 | 80 | 	init.flags = CLK_SET_RATE_PARENT; | 
 | 81 | 	init.parent_names = data->parent_names; | 
 | 82 | 	init.num_parents = data->num_parents, | 
 | 83 |  | 
 | 84 | 	mux->regmap = regmap; | 
 | 85 | 	mux->reg = data->reg; | 
 | 86 | 	mux->masks = data->masks; | 
 | 87 | 	mux->vals = data->vals; | 
 | 88 | 	mux->hw.init = &init; | 
 | 89 |  | 
 | 90 | 	ret = devm_clk_hw_register(dev, &mux->hw); | 
 | 91 | 	if (ret) | 
 | 92 | 		return ERR_PTR(ret); | 
 | 93 |  | 
 | 94 | 	return &mux->hw; | 
 | 95 | } |