18c2ecf20Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0-or-later */
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Ingenic SoC CGU driver
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Copyright (c) 2013-2015 Imagination Technologies
68c2ecf20Sopenharmony_ci * Author: Paul Burton <paul.burton@mips.com>
78c2ecf20Sopenharmony_ci */
88c2ecf20Sopenharmony_ci
98c2ecf20Sopenharmony_ci#ifndef __DRIVERS_CLK_INGENIC_CGU_H__
108c2ecf20Sopenharmony_ci#define __DRIVERS_CLK_INGENIC_CGU_H__
118c2ecf20Sopenharmony_ci
128c2ecf20Sopenharmony_ci#include <linux/bitops.h>
138c2ecf20Sopenharmony_ci#include <linux/clk-provider.h>
148c2ecf20Sopenharmony_ci#include <linux/of.h>
158c2ecf20Sopenharmony_ci#include <linux/spinlock.h>
168c2ecf20Sopenharmony_ci
178c2ecf20Sopenharmony_ci/**
188c2ecf20Sopenharmony_ci * struct ingenic_cgu_pll_info - information about a PLL
198c2ecf20Sopenharmony_ci * @reg: the offset of the PLL's control register within the CGU
208c2ecf20Sopenharmony_ci * @rate_multiplier: the multiplier needed by pll rate calculation
218c2ecf20Sopenharmony_ci * @m_shift: the number of bits to shift the multiplier value by (ie. the
228c2ecf20Sopenharmony_ci *           index of the lowest bit of the multiplier value in the PLL's
238c2ecf20Sopenharmony_ci *           control register)
248c2ecf20Sopenharmony_ci * @m_bits: the size of the multiplier field in bits
258c2ecf20Sopenharmony_ci * @m_offset: the multiplier value which encodes to 0 in the PLL's control
268c2ecf20Sopenharmony_ci *            register
278c2ecf20Sopenharmony_ci * @n_shift: the number of bits to shift the divider value by (ie. the
288c2ecf20Sopenharmony_ci *           index of the lowest bit of the divider value in the PLL's
298c2ecf20Sopenharmony_ci *           control register)
308c2ecf20Sopenharmony_ci * @n_bits: the size of the divider field in bits
318c2ecf20Sopenharmony_ci * @n_offset: the divider value which encodes to 0 in the PLL's control
328c2ecf20Sopenharmony_ci *            register
338c2ecf20Sopenharmony_ci * @od_shift: the number of bits to shift the post-VCO divider value by (ie.
348c2ecf20Sopenharmony_ci *            the index of the lowest bit of the post-VCO divider value in
358c2ecf20Sopenharmony_ci *            the PLL's control register)
368c2ecf20Sopenharmony_ci * @od_bits: the size of the post-VCO divider field in bits
378c2ecf20Sopenharmony_ci * @od_max: the maximum post-VCO divider value
388c2ecf20Sopenharmony_ci * @od_encoding: a pointer to an array mapping post-VCO divider values to
398c2ecf20Sopenharmony_ci *               their encoded values in the PLL control register, or -1 for
408c2ecf20Sopenharmony_ci *               unsupported values
418c2ecf20Sopenharmony_ci * @bypass_reg: the offset of the bypass control register within the CGU
428c2ecf20Sopenharmony_ci * @bypass_bit: the index of the bypass bit in the PLL control register
438c2ecf20Sopenharmony_ci * @enable_bit: the index of the enable bit in the PLL control register
448c2ecf20Sopenharmony_ci * @stable_bit: the index of the stable bit in the PLL control register
458c2ecf20Sopenharmony_ci * @no_bypass_bit: if set, the PLL has no bypass functionality
468c2ecf20Sopenharmony_ci */
478c2ecf20Sopenharmony_cistruct ingenic_cgu_pll_info {
488c2ecf20Sopenharmony_ci	unsigned reg;
498c2ecf20Sopenharmony_ci	unsigned rate_multiplier;
508c2ecf20Sopenharmony_ci	const s8 *od_encoding;
518c2ecf20Sopenharmony_ci	u8 m_shift, m_bits, m_offset;
528c2ecf20Sopenharmony_ci	u8 n_shift, n_bits, n_offset;
538c2ecf20Sopenharmony_ci	u8 od_shift, od_bits, od_max;
548c2ecf20Sopenharmony_ci	unsigned bypass_reg;
558c2ecf20Sopenharmony_ci	u8 bypass_bit;
568c2ecf20Sopenharmony_ci	u8 enable_bit;
578c2ecf20Sopenharmony_ci	u8 stable_bit;
588c2ecf20Sopenharmony_ci	bool no_bypass_bit;
598c2ecf20Sopenharmony_ci};
608c2ecf20Sopenharmony_ci
618c2ecf20Sopenharmony_ci/**
628c2ecf20Sopenharmony_ci * struct ingenic_cgu_mux_info - information about a clock mux
638c2ecf20Sopenharmony_ci * @reg: offset of the mux control register within the CGU
648c2ecf20Sopenharmony_ci * @shift: number of bits to shift the mux value by (ie. the index of
658c2ecf20Sopenharmony_ci *         the lowest bit of the mux value within its control register)
668c2ecf20Sopenharmony_ci * @bits: the size of the mux value in bits
678c2ecf20Sopenharmony_ci */
688c2ecf20Sopenharmony_cistruct ingenic_cgu_mux_info {
698c2ecf20Sopenharmony_ci	unsigned reg;
708c2ecf20Sopenharmony_ci	u8 shift;
718c2ecf20Sopenharmony_ci	u8 bits;
728c2ecf20Sopenharmony_ci};
738c2ecf20Sopenharmony_ci
748c2ecf20Sopenharmony_ci/**
758c2ecf20Sopenharmony_ci * struct ingenic_cgu_div_info - information about a divider
768c2ecf20Sopenharmony_ci * @reg: offset of the divider control register within the CGU
778c2ecf20Sopenharmony_ci * @shift: number of bits to left shift the divide value by (ie. the index of
788c2ecf20Sopenharmony_ci *         the lowest bit of the divide value within its control register)
798c2ecf20Sopenharmony_ci * @div: number to divide the divider value by (i.e. if the
808c2ecf20Sopenharmony_ci *	 effective divider value is the value written to the register
818c2ecf20Sopenharmony_ci *	 multiplied by some constant)
828c2ecf20Sopenharmony_ci * @bits: the size of the divide value in bits
838c2ecf20Sopenharmony_ci * @ce_bit: the index of the change enable bit within reg, or -1 if there
848c2ecf20Sopenharmony_ci *          isn't one
858c2ecf20Sopenharmony_ci * @busy_bit: the index of the busy bit within reg, or -1 if there isn't one
868c2ecf20Sopenharmony_ci * @stop_bit: the index of the stop bit within reg, or -1 if there isn't one
878c2ecf20Sopenharmony_ci * @div_table: optional table to map the value read from the register to the
888c2ecf20Sopenharmony_ci *             actual divider value
898c2ecf20Sopenharmony_ci */
908c2ecf20Sopenharmony_cistruct ingenic_cgu_div_info {
918c2ecf20Sopenharmony_ci	unsigned reg;
928c2ecf20Sopenharmony_ci	u8 shift;
938c2ecf20Sopenharmony_ci	u8 div;
948c2ecf20Sopenharmony_ci	u8 bits;
958c2ecf20Sopenharmony_ci	s8 ce_bit;
968c2ecf20Sopenharmony_ci	s8 busy_bit;
978c2ecf20Sopenharmony_ci	s8 stop_bit;
988c2ecf20Sopenharmony_ci	const u8 *div_table;
998c2ecf20Sopenharmony_ci};
1008c2ecf20Sopenharmony_ci
1018c2ecf20Sopenharmony_ci/**
1028c2ecf20Sopenharmony_ci * struct ingenic_cgu_fixdiv_info - information about a fixed divider
1038c2ecf20Sopenharmony_ci * @div: the divider applied to the parent clock
1048c2ecf20Sopenharmony_ci */
1058c2ecf20Sopenharmony_cistruct ingenic_cgu_fixdiv_info {
1068c2ecf20Sopenharmony_ci	unsigned div;
1078c2ecf20Sopenharmony_ci};
1088c2ecf20Sopenharmony_ci
1098c2ecf20Sopenharmony_ci/**
1108c2ecf20Sopenharmony_ci * struct ingenic_cgu_gate_info - information about a clock gate
1118c2ecf20Sopenharmony_ci * @reg: offset of the gate control register within the CGU
1128c2ecf20Sopenharmony_ci * @bit: offset of the bit in the register that controls the gate
1138c2ecf20Sopenharmony_ci * @clear_to_gate: if set, the clock is gated when the bit is cleared
1148c2ecf20Sopenharmony_ci * @delay_us: delay in microseconds after which the clock is considered stable
1158c2ecf20Sopenharmony_ci */
1168c2ecf20Sopenharmony_cistruct ingenic_cgu_gate_info {
1178c2ecf20Sopenharmony_ci	unsigned reg;
1188c2ecf20Sopenharmony_ci	u8 bit;
1198c2ecf20Sopenharmony_ci	bool clear_to_gate;
1208c2ecf20Sopenharmony_ci	u16 delay_us;
1218c2ecf20Sopenharmony_ci};
1228c2ecf20Sopenharmony_ci
1238c2ecf20Sopenharmony_ci/**
1248c2ecf20Sopenharmony_ci * struct ingenic_cgu_custom_info - information about a custom (SoC) clock
1258c2ecf20Sopenharmony_ci * @clk_ops: custom clock operation callbacks
1268c2ecf20Sopenharmony_ci */
1278c2ecf20Sopenharmony_cistruct ingenic_cgu_custom_info {
1288c2ecf20Sopenharmony_ci	const struct clk_ops *clk_ops;
1298c2ecf20Sopenharmony_ci};
1308c2ecf20Sopenharmony_ci
1318c2ecf20Sopenharmony_ci/**
1328c2ecf20Sopenharmony_ci * struct ingenic_cgu_clk_info - information about a clock
1338c2ecf20Sopenharmony_ci * @name: name of the clock
1348c2ecf20Sopenharmony_ci * @type: a bitmask formed from CGU_CLK_* values
1358c2ecf20Sopenharmony_ci * @parents: an array of the indices of potential parents of this clock
1368c2ecf20Sopenharmony_ci *           within the clock_info array of the CGU, or -1 in entries
1378c2ecf20Sopenharmony_ci *           which correspond to no valid parent
1388c2ecf20Sopenharmony_ci * @pll: information valid if type includes CGU_CLK_PLL
1398c2ecf20Sopenharmony_ci * @gate: information valid if type includes CGU_CLK_GATE
1408c2ecf20Sopenharmony_ci * @mux: information valid if type includes CGU_CLK_MUX
1418c2ecf20Sopenharmony_ci * @div: information valid if type includes CGU_CLK_DIV
1428c2ecf20Sopenharmony_ci * @fixdiv: information valid if type includes CGU_CLK_FIXDIV
1438c2ecf20Sopenharmony_ci * @custom: information valid if type includes CGU_CLK_CUSTOM
1448c2ecf20Sopenharmony_ci */
1458c2ecf20Sopenharmony_cistruct ingenic_cgu_clk_info {
1468c2ecf20Sopenharmony_ci	const char *name;
1478c2ecf20Sopenharmony_ci
1488c2ecf20Sopenharmony_ci	enum {
1498c2ecf20Sopenharmony_ci		CGU_CLK_NONE		= 0,
1508c2ecf20Sopenharmony_ci		CGU_CLK_EXT		= BIT(0),
1518c2ecf20Sopenharmony_ci		CGU_CLK_PLL		= BIT(1),
1528c2ecf20Sopenharmony_ci		CGU_CLK_GATE		= BIT(2),
1538c2ecf20Sopenharmony_ci		CGU_CLK_MUX		= BIT(3),
1548c2ecf20Sopenharmony_ci		CGU_CLK_MUX_GLITCHFREE	= BIT(4),
1558c2ecf20Sopenharmony_ci		CGU_CLK_DIV		= BIT(5),
1568c2ecf20Sopenharmony_ci		CGU_CLK_FIXDIV		= BIT(6),
1578c2ecf20Sopenharmony_ci		CGU_CLK_CUSTOM		= BIT(7),
1588c2ecf20Sopenharmony_ci	} type;
1598c2ecf20Sopenharmony_ci
1608c2ecf20Sopenharmony_ci	int parents[4];
1618c2ecf20Sopenharmony_ci
1628c2ecf20Sopenharmony_ci	union {
1638c2ecf20Sopenharmony_ci		struct ingenic_cgu_pll_info pll;
1648c2ecf20Sopenharmony_ci
1658c2ecf20Sopenharmony_ci		struct {
1668c2ecf20Sopenharmony_ci			struct ingenic_cgu_gate_info gate;
1678c2ecf20Sopenharmony_ci			struct ingenic_cgu_mux_info mux;
1688c2ecf20Sopenharmony_ci			struct ingenic_cgu_div_info div;
1698c2ecf20Sopenharmony_ci			struct ingenic_cgu_fixdiv_info fixdiv;
1708c2ecf20Sopenharmony_ci		};
1718c2ecf20Sopenharmony_ci
1728c2ecf20Sopenharmony_ci		struct ingenic_cgu_custom_info custom;
1738c2ecf20Sopenharmony_ci	};
1748c2ecf20Sopenharmony_ci};
1758c2ecf20Sopenharmony_ci
1768c2ecf20Sopenharmony_ci/**
1778c2ecf20Sopenharmony_ci * struct ingenic_cgu - data about the CGU
1788c2ecf20Sopenharmony_ci * @np: the device tree node that caused the CGU to be probed
1798c2ecf20Sopenharmony_ci * @base: the ioremap'ed base address of the CGU registers
1808c2ecf20Sopenharmony_ci * @clock_info: an array containing information about implemented clocks
1818c2ecf20Sopenharmony_ci * @clocks: used to provide clocks to DT, allows lookup of struct clk*
1828c2ecf20Sopenharmony_ci * @lock: lock to be held whilst manipulating CGU registers
1838c2ecf20Sopenharmony_ci */
1848c2ecf20Sopenharmony_cistruct ingenic_cgu {
1858c2ecf20Sopenharmony_ci	struct device_node *np;
1868c2ecf20Sopenharmony_ci	void __iomem *base;
1878c2ecf20Sopenharmony_ci
1888c2ecf20Sopenharmony_ci	const struct ingenic_cgu_clk_info *clock_info;
1898c2ecf20Sopenharmony_ci	struct clk_onecell_data clocks;
1908c2ecf20Sopenharmony_ci
1918c2ecf20Sopenharmony_ci	spinlock_t lock;
1928c2ecf20Sopenharmony_ci};
1938c2ecf20Sopenharmony_ci
1948c2ecf20Sopenharmony_ci/**
1958c2ecf20Sopenharmony_ci * struct ingenic_clk - private data for a clock
1968c2ecf20Sopenharmony_ci * @hw: see Documentation/driver-api/clk.rst
1978c2ecf20Sopenharmony_ci * @cgu: a pointer to the CGU data
1988c2ecf20Sopenharmony_ci * @idx: the index of this clock in cgu->clock_info
1998c2ecf20Sopenharmony_ci */
2008c2ecf20Sopenharmony_cistruct ingenic_clk {
2018c2ecf20Sopenharmony_ci	struct clk_hw hw;
2028c2ecf20Sopenharmony_ci	struct ingenic_cgu *cgu;
2038c2ecf20Sopenharmony_ci	unsigned idx;
2048c2ecf20Sopenharmony_ci};
2058c2ecf20Sopenharmony_ci
2068c2ecf20Sopenharmony_ci#define to_ingenic_clk(_hw) container_of(_hw, struct ingenic_clk, hw)
2078c2ecf20Sopenharmony_ci
2088c2ecf20Sopenharmony_ci/**
2098c2ecf20Sopenharmony_ci * ingenic_cgu_new() - create a new CGU instance
2108c2ecf20Sopenharmony_ci * @clock_info: an array of clock information structures describing the clocks
2118c2ecf20Sopenharmony_ci *              which are implemented by the CGU
2128c2ecf20Sopenharmony_ci * @num_clocks: the number of entries in clock_info
2138c2ecf20Sopenharmony_ci * @np: the device tree node which causes this CGU to be probed
2148c2ecf20Sopenharmony_ci *
2158c2ecf20Sopenharmony_ci * Return: a pointer to the CGU instance if initialisation is successful,
2168c2ecf20Sopenharmony_ci *         otherwise NULL.
2178c2ecf20Sopenharmony_ci */
2188c2ecf20Sopenharmony_cistruct ingenic_cgu *
2198c2ecf20Sopenharmony_ciingenic_cgu_new(const struct ingenic_cgu_clk_info *clock_info,
2208c2ecf20Sopenharmony_ci		unsigned num_clocks, struct device_node *np);
2218c2ecf20Sopenharmony_ci
2228c2ecf20Sopenharmony_ci/**
2238c2ecf20Sopenharmony_ci * ingenic_cgu_register_clocks() - Registers the clocks
2248c2ecf20Sopenharmony_ci * @cgu: pointer to cgu data
2258c2ecf20Sopenharmony_ci *
2268c2ecf20Sopenharmony_ci * Register the clocks described by the CGU with the common clock framework.
2278c2ecf20Sopenharmony_ci *
2288c2ecf20Sopenharmony_ci * Return: 0 on success or -errno if unsuccesful.
2298c2ecf20Sopenharmony_ci */
2308c2ecf20Sopenharmony_ciint ingenic_cgu_register_clocks(struct ingenic_cgu *cgu);
2318c2ecf20Sopenharmony_ci
2328c2ecf20Sopenharmony_ci#endif /* __DRIVERS_CLK_INGENIC_CGU_H__ */
233