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