File Index
Files and directories
Sign in
FILE

clk-inverter.c

File preview with syntax highlighting.

linux-6.19.14/drivers/clk/rockchip/clk-inverter.c C
  1// SPDX-License-Identifier: GPL-2.0-or-later
  2/*
  3 * Copyright 2015 Heiko Stuebner <heiko@sntech.de>
  4 */
  5
  6#include <linux/slab.h>
  7#include <linux/clk-provider.h>
  8#include <linux/io.h>
  9#include <linux/spinlock.h>
 10#include <linux/kernel.h>
 11#include "clk.h"
 12
 13struct rockchip_inv_clock {
 14	struct clk_hw	hw;
 15	void __iomem	*reg;
 16	int		shift;
 17	int		flags;
 18	spinlock_t	*lock;
 19};
 20
 21#define to_inv_clock(_hw) container_of(_hw, struct rockchip_inv_clock, hw)
 22
 23#define INVERTER_MASK 0x1
 24
 25static int rockchip_inv_get_phase(struct clk_hw *hw)
 26{
 27	struct rockchip_inv_clock *inv_clock = to_inv_clock(hw);
 28	u32 val;
 29
 30	val = readl(inv_clock->reg) >> inv_clock->shift;
 31	val &= INVERTER_MASK;
 32	return val ? 180 : 0;
 33}
 34
 35static int rockchip_inv_set_phase(struct clk_hw *hw, int degrees)
 36{
 37	struct rockchip_inv_clock *inv_clock = to_inv_clock(hw);
 38	u32 val;
 39
 40	if (degrees % 180 == 0) {
 41		val = !!degrees;
 42	} else {
 43		pr_err("%s: unsupported phase %d for %s\n",
 44		       __func__, degrees, clk_hw_get_name(hw));
 45		return -EINVAL;
 46	}
 47
 48	if (inv_clock->flags & ROCKCHIP_INVERTER_HIWORD_MASK) {
 49		writel(HIWORD_UPDATE(val, INVERTER_MASK, inv_clock->shift),
 50		       inv_clock->reg);
 51	} else {
 52		unsigned long flags;
 53		u32 reg;
 54
 55		spin_lock_irqsave(inv_clock->lock, flags);
 56
 57		reg = readl(inv_clock->reg);
 58		reg &= ~BIT(inv_clock->shift);
 59		reg |= val;
 60		writel(reg, inv_clock->reg);
 61
 62		spin_unlock_irqrestore(inv_clock->lock, flags);
 63	}
 64
 65	return 0;
 66}
 67
 68static const struct clk_ops rockchip_inv_clk_ops = {
 69	.get_phase	= rockchip_inv_get_phase,
 70	.set_phase	= rockchip_inv_set_phase,
 71};
 72
 73struct clk *rockchip_clk_register_inverter(const char *name,
 74				const char *const *parent_names, u8 num_parents,
 75				void __iomem *reg, int shift, int flags,
 76				spinlock_t *lock)
 77{
 78	struct clk_init_data init;
 79	struct rockchip_inv_clock *inv_clock;
 80	struct clk *clk;
 81
 82	inv_clock = kmalloc(sizeof(*inv_clock), GFP_KERNEL);
 83	if (!inv_clock)
 84		return ERR_PTR(-ENOMEM);
 85
 86	init.name = name;
 87	init.num_parents = num_parents;
 88	init.flags = CLK_SET_RATE_PARENT;
 89	init.parent_names = parent_names;
 90	init.ops = &rockchip_inv_clk_ops;
 91
 92	inv_clock->hw.init = &init;
 93	inv_clock->reg = reg;
 94	inv_clock->shift = shift;
 95	inv_clock->flags = flags;
 96	inv_clock->lock = lock;
 97
 98	clk = clk_register(NULL, &inv_clock->hw);
 99	if (IS_ERR(clk))
100		kfree(inv_clock);
101
102	return clk;
103}
~/ Read-only file preview.