162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * drivers/clk/at91/clk-slow.c
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci *  Copyright (C) 2013 Boris BREZILLON <b.brezillon@overkiz.com>
662306a36Sopenharmony_ci */
762306a36Sopenharmony_ci
862306a36Sopenharmony_ci#include <linux/clk-provider.h>
962306a36Sopenharmony_ci#include <linux/clkdev.h>
1062306a36Sopenharmony_ci#include <linux/clk/at91_pmc.h>
1162306a36Sopenharmony_ci#include <linux/of.h>
1262306a36Sopenharmony_ci#include <linux/mfd/syscon.h>
1362306a36Sopenharmony_ci#include <linux/regmap.h>
1462306a36Sopenharmony_ci
1562306a36Sopenharmony_ci#include "pmc.h"
1662306a36Sopenharmony_ci
1762306a36Sopenharmony_cistruct clk_sam9260_slow {
1862306a36Sopenharmony_ci	struct clk_hw hw;
1962306a36Sopenharmony_ci	struct regmap *regmap;
2062306a36Sopenharmony_ci};
2162306a36Sopenharmony_ci
2262306a36Sopenharmony_ci#define to_clk_sam9260_slow(hw) container_of(hw, struct clk_sam9260_slow, hw)
2362306a36Sopenharmony_ci
2462306a36Sopenharmony_cistatic u8 clk_sam9260_slow_get_parent(struct clk_hw *hw)
2562306a36Sopenharmony_ci{
2662306a36Sopenharmony_ci	struct clk_sam9260_slow *slowck = to_clk_sam9260_slow(hw);
2762306a36Sopenharmony_ci	unsigned int status;
2862306a36Sopenharmony_ci
2962306a36Sopenharmony_ci	regmap_read(slowck->regmap, AT91_PMC_SR, &status);
3062306a36Sopenharmony_ci
3162306a36Sopenharmony_ci	return status & AT91_PMC_OSCSEL ? 1 : 0;
3262306a36Sopenharmony_ci}
3362306a36Sopenharmony_ci
3462306a36Sopenharmony_cistatic const struct clk_ops sam9260_slow_ops = {
3562306a36Sopenharmony_ci	.get_parent = clk_sam9260_slow_get_parent,
3662306a36Sopenharmony_ci};
3762306a36Sopenharmony_ci
3862306a36Sopenharmony_cistruct clk_hw * __init
3962306a36Sopenharmony_ciat91_clk_register_sam9260_slow(struct regmap *regmap,
4062306a36Sopenharmony_ci			       const char *name,
4162306a36Sopenharmony_ci			       const char **parent_names,
4262306a36Sopenharmony_ci			       int num_parents)
4362306a36Sopenharmony_ci{
4462306a36Sopenharmony_ci	struct clk_sam9260_slow *slowck;
4562306a36Sopenharmony_ci	struct clk_hw *hw;
4662306a36Sopenharmony_ci	struct clk_init_data init;
4762306a36Sopenharmony_ci	int ret;
4862306a36Sopenharmony_ci
4962306a36Sopenharmony_ci	if (!name)
5062306a36Sopenharmony_ci		return ERR_PTR(-EINVAL);
5162306a36Sopenharmony_ci
5262306a36Sopenharmony_ci	if (!parent_names || !num_parents)
5362306a36Sopenharmony_ci		return ERR_PTR(-EINVAL);
5462306a36Sopenharmony_ci
5562306a36Sopenharmony_ci	slowck = kzalloc(sizeof(*slowck), GFP_KERNEL);
5662306a36Sopenharmony_ci	if (!slowck)
5762306a36Sopenharmony_ci		return ERR_PTR(-ENOMEM);
5862306a36Sopenharmony_ci
5962306a36Sopenharmony_ci	init.name = name;
6062306a36Sopenharmony_ci	init.ops = &sam9260_slow_ops;
6162306a36Sopenharmony_ci	init.parent_names = parent_names;
6262306a36Sopenharmony_ci	init.num_parents = num_parents;
6362306a36Sopenharmony_ci	init.flags = 0;
6462306a36Sopenharmony_ci
6562306a36Sopenharmony_ci	slowck->hw.init = &init;
6662306a36Sopenharmony_ci	slowck->regmap = regmap;
6762306a36Sopenharmony_ci
6862306a36Sopenharmony_ci	hw = &slowck->hw;
6962306a36Sopenharmony_ci	ret = clk_hw_register(NULL, &slowck->hw);
7062306a36Sopenharmony_ci	if (ret) {
7162306a36Sopenharmony_ci		kfree(slowck);
7262306a36Sopenharmony_ci		hw = ERR_PTR(ret);
7362306a36Sopenharmony_ci	}
7462306a36Sopenharmony_ci
7562306a36Sopenharmony_ci	return hw;
7662306a36Sopenharmony_ci}
77