1117395Skan// SPDX-License-Identifier: GPL-2.0-or-later 2169689Skan/* 3169689Skan * Copyright (C) 2016 Socionext Inc. 490075Sobrien * Author: Masahiro Yamada <yamada.masahiro@socionext.com> 590075Sobrien */ 690075Sobrien 790075Sobrien#include <linux/clk-provider.h> 890075Sobrien#include <linux/device.h> 990075Sobrien#include <linux/regmap.h> 1090075Sobrien 1190075Sobrien#include "clk-uniphier.h" 1290075Sobrien 1390075Sobrienstruct uniphier_clk_mux { 1490075Sobrien struct clk_hw hw; 1590075Sobrien struct regmap *regmap; 1690075Sobrien unsigned int reg; 1790075Sobrien const unsigned int *masks; 1890075Sobrien const unsigned int *vals; 1990075Sobrien}; 20169689Skan 21169689Skan#define to_uniphier_clk_mux(_hw) container_of(_hw, struct uniphier_clk_mux, hw) 2290075Sobrien 2390075Sobrienstatic int uniphier_clk_mux_set_parent(struct clk_hw *hw, u8 index) 2490075Sobrien{ 2590075Sobrien struct uniphier_clk_mux *mux = to_uniphier_clk_mux(hw); 2690075Sobrien 2790075Sobrien return regmap_write_bits(mux->regmap, mux->reg, mux->masks[index], 2890075Sobrien mux->vals[index]); 2990075Sobrien} 3090075Sobrien 31132718Skanstatic u8 uniphier_clk_mux_get_parent(struct clk_hw *hw) 32132718Skan{ 3390075Sobrien struct uniphier_clk_mux *mux = to_uniphier_clk_mux(hw); 34169689Skan unsigned int num_parents = clk_hw_get_num_parents(hw); 3590075Sobrien int ret; 3690075Sobrien unsigned int val; 3790075Sobrien unsigned int i; 3890075Sobrien 3990075Sobrien ret = regmap_read(mux->regmap, mux->reg, &val); 4090075Sobrien if (ret) 41117395Skan return ret; 42117395Skan 43169689Skan for (i = 0; i < num_parents; i++) 4490075Sobrien if ((mux->masks[i] & val) == mux->vals[i]) 4590075Sobrien return i; 4690075Sobrien 47132718Skan return -EINVAL; 4890075Sobrien} 49132718Skan 50132718Skanstatic const struct clk_ops uniphier_clk_mux_ops = { 51132718Skan .determine_rate = __clk_mux_determine_rate, 52132718Skan .set_parent = uniphier_clk_mux_set_parent, 5390075Sobrien .get_parent = uniphier_clk_mux_get_parent, 54132718Skan}; 55132718Skan 56132718Skanstruct clk_hw *uniphier_clk_register_mux(struct device *dev, 57132718Skan struct regmap *regmap, 58132718Skan const char *name, 59132718Skan const struct uniphier_clk_mux_data *data) 6090075Sobrien{ 6190075Sobrien struct uniphier_clk_mux *mux; 6290075Sobrien struct clk_init_data init; 6390075Sobrien int ret; 6490075Sobrien 6590075Sobrien mux = devm_kzalloc(dev, sizeof(*mux), GFP_KERNEL); 66132718Skan if (!mux) 67132718Skan return ERR_PTR(-ENOMEM); 6890075Sobrien 69132718Skan init.name = name; 7090075Sobrien init.ops = &uniphier_clk_mux_ops; 7190075Sobrien init.flags = CLK_SET_RATE_PARENT; 72132718Skan init.parent_names = data->parent_names; 7390075Sobrien init.num_parents = data->num_parents; 74132718Skan 7590075Sobrien mux->regmap = regmap; 76132718Skan mux->reg = data->reg; 7790075Sobrien mux->masks = data->masks; 7890075Sobrien mux->vals = data->vals; 7990075Sobrien mux->hw.init = &init; 8090075Sobrien 81132718Skan ret = devm_clk_hw_register(dev, &mux->hw); 8290075Sobrien if (ret) 83132718Skan return ERR_PTR(ret); 8490075Sobrien 8590075Sobrien return &mux->hw; 8690075Sobrien} 8790075Sobrien