18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * drivers/clk/at91/clk-slow.c
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci *  Copyright (C) 2013 Boris BREZILLON <b.brezillon@overkiz.com>
68c2ecf20Sopenharmony_ci */
78c2ecf20Sopenharmony_ci
88c2ecf20Sopenharmony_ci#include <linux/clk-provider.h>
98c2ecf20Sopenharmony_ci#include <linux/clkdev.h>
108c2ecf20Sopenharmony_ci#include <linux/clk/at91_pmc.h>
118c2ecf20Sopenharmony_ci#include <linux/of.h>
128c2ecf20Sopenharmony_ci#include <linux/mfd/syscon.h>
138c2ecf20Sopenharmony_ci#include <linux/regmap.h>
148c2ecf20Sopenharmony_ci
158c2ecf20Sopenharmony_ci#include "pmc.h"
168c2ecf20Sopenharmony_ci
178c2ecf20Sopenharmony_cistruct clk_sam9260_slow {
188c2ecf20Sopenharmony_ci	struct clk_hw hw;
198c2ecf20Sopenharmony_ci	struct regmap *regmap;
208c2ecf20Sopenharmony_ci};
218c2ecf20Sopenharmony_ci
228c2ecf20Sopenharmony_ci#define to_clk_sam9260_slow(hw) container_of(hw, struct clk_sam9260_slow, hw)
238c2ecf20Sopenharmony_ci
248c2ecf20Sopenharmony_cistatic u8 clk_sam9260_slow_get_parent(struct clk_hw *hw)
258c2ecf20Sopenharmony_ci{
268c2ecf20Sopenharmony_ci	struct clk_sam9260_slow *slowck = to_clk_sam9260_slow(hw);
278c2ecf20Sopenharmony_ci	unsigned int status;
288c2ecf20Sopenharmony_ci
298c2ecf20Sopenharmony_ci	regmap_read(slowck->regmap, AT91_PMC_SR, &status);
308c2ecf20Sopenharmony_ci
318c2ecf20Sopenharmony_ci	return status & AT91_PMC_OSCSEL ? 1 : 0;
328c2ecf20Sopenharmony_ci}
338c2ecf20Sopenharmony_ci
348c2ecf20Sopenharmony_cistatic const struct clk_ops sam9260_slow_ops = {
358c2ecf20Sopenharmony_ci	.get_parent = clk_sam9260_slow_get_parent,
368c2ecf20Sopenharmony_ci};
378c2ecf20Sopenharmony_ci
388c2ecf20Sopenharmony_cistruct clk_hw * __init
398c2ecf20Sopenharmony_ciat91_clk_register_sam9260_slow(struct regmap *regmap,
408c2ecf20Sopenharmony_ci			       const char *name,
418c2ecf20Sopenharmony_ci			       const char **parent_names,
428c2ecf20Sopenharmony_ci			       int num_parents)
438c2ecf20Sopenharmony_ci{
448c2ecf20Sopenharmony_ci	struct clk_sam9260_slow *slowck;
458c2ecf20Sopenharmony_ci	struct clk_hw *hw;
468c2ecf20Sopenharmony_ci	struct clk_init_data init;
478c2ecf20Sopenharmony_ci	int ret;
488c2ecf20Sopenharmony_ci
498c2ecf20Sopenharmony_ci	if (!name)
508c2ecf20Sopenharmony_ci		return ERR_PTR(-EINVAL);
518c2ecf20Sopenharmony_ci
528c2ecf20Sopenharmony_ci	if (!parent_names || !num_parents)
538c2ecf20Sopenharmony_ci		return ERR_PTR(-EINVAL);
548c2ecf20Sopenharmony_ci
558c2ecf20Sopenharmony_ci	slowck = kzalloc(sizeof(*slowck), GFP_KERNEL);
568c2ecf20Sopenharmony_ci	if (!slowck)
578c2ecf20Sopenharmony_ci		return ERR_PTR(-ENOMEM);
588c2ecf20Sopenharmony_ci
598c2ecf20Sopenharmony_ci	init.name = name;
608c2ecf20Sopenharmony_ci	init.ops = &sam9260_slow_ops;
618c2ecf20Sopenharmony_ci	init.parent_names = parent_names;
628c2ecf20Sopenharmony_ci	init.num_parents = num_parents;
638c2ecf20Sopenharmony_ci	init.flags = 0;
648c2ecf20Sopenharmony_ci
658c2ecf20Sopenharmony_ci	slowck->hw.init = &init;
668c2ecf20Sopenharmony_ci	slowck->regmap = regmap;
678c2ecf20Sopenharmony_ci
688c2ecf20Sopenharmony_ci	hw = &slowck->hw;
698c2ecf20Sopenharmony_ci	ret = clk_hw_register(NULL, &slowck->hw);
708c2ecf20Sopenharmony_ci	if (ret) {
718c2ecf20Sopenharmony_ci		kfree(slowck);
728c2ecf20Sopenharmony_ci		hw = ERR_PTR(ret);
738c2ecf20Sopenharmony_ci	}
748c2ecf20Sopenharmony_ci
758c2ecf20Sopenharmony_ci	return hw;
768c2ecf20Sopenharmony_ci}
77