1/* SPDX-License-Identifier: GPL-2.0-only */
2/*
3 * Copyright (C) 2020 BAIKAL ELECTRONICS, JSC
4 *
5 * Baikal-T1 CCU Dividers interface driver
6 */
7#ifndef __CLK_BT1_CCU_DIV_H__
8#define __CLK_BT1_CCU_DIV_H__
9
10#include <linux/clk-provider.h>
11#include <linux/spinlock.h>
12#include <linux/regmap.h>
13#include <linux/bits.h>
14#include <linux/of.h>
15
16/*
17 * CCU Divider private clock IDs
18 * @CCU_SYS_SATA_CLK: CCU SATA internal clock
19 * @CCU_SYS_XGMAC_CLK: CCU XGMAC internal clock
20 */
21#define CCU_SYS_SATA_CLK		-1
22#define CCU_SYS_XGMAC_CLK		-2
23
24/*
25 * CCU Divider private flags
26 * @CCU_DIV_SKIP_ONE: Due to some reason divider can't be set to 1.
27 *		      It can be 0 though, which is functionally the same.
28 * @CCU_DIV_SKIP_ONE_TO_THREE: For some reason divider can't be within [1,3].
29 *			       It can be either 0 or greater than 3.
30 * @CCU_DIV_LOCK_SHIFTED: Find lock-bit at non-standard position.
31 * @CCU_DIV_RESET_DOMAIN: Provide reset clock domain method.
32 */
33#define CCU_DIV_SKIP_ONE		BIT(1)
34#define CCU_DIV_SKIP_ONE_TO_THREE	BIT(2)
35#define CCU_DIV_LOCK_SHIFTED		BIT(3)
36#define CCU_DIV_RESET_DOMAIN		BIT(4)
37
38/*
39 * enum ccu_div_type - CCU Divider types
40 * @CCU_DIV_VAR: Clocks gate with variable divider.
41 * @CCU_DIV_GATE: Clocks gate with fixed divider.
42 * @CCU_DIV_BUF: Clock gate with no divider.
43 * @CCU_DIV_FIXED: Ungateable clock with fixed divider.
44 */
45enum ccu_div_type {
46	CCU_DIV_VAR,
47	CCU_DIV_GATE,
48	CCU_DIV_BUF,
49	CCU_DIV_FIXED
50};
51
52/*
53 * struct ccu_div_init_data - CCU Divider initialization data
54 * @id: Clocks private identifier.
55 * @name: Clocks name.
56 * @parent_name: Parent clocks name in a fw node.
57 * @base: Divider register base address with respect to the sys_regs base.
58 * @sys_regs: Baikal-T1 System Controller registers map.
59 * @np: Pointer to the node describing the CCU Dividers.
60 * @type: CCU divider type (variable, fixed with and without gate).
61 * @width: Divider width if it's variable.
62 * @divider: Divider fixed value.
63 * @flags: CCU Divider clock flags.
64 * @features: CCU Divider private features.
65 */
66struct ccu_div_init_data {
67	unsigned int id;
68	const char *name;
69	const char *parent_name;
70	unsigned int base;
71	struct regmap *sys_regs;
72	struct device_node *np;
73	enum ccu_div_type type;
74	union {
75		unsigned int width;
76		unsigned int divider;
77	};
78	unsigned long flags;
79	unsigned long features;
80};
81
82/*
83 * struct ccu_div - CCU Divider descriptor
84 * @hw: clk_hw of the divider.
85 * @id: Clock private identifier.
86 * @reg_ctl: Divider control register base address.
87 * @sys_regs: Baikal-T1 System Controller registers map.
88 * @lock: Divider state change spin-lock.
89 * @mask: Divider field mask.
90 * @divider: Divider fixed value.
91 * @flags: Divider clock flags.
92 * @features: CCU Divider private features.
93 */
94struct ccu_div {
95	struct clk_hw hw;
96	unsigned int id;
97	unsigned int reg_ctl;
98	struct regmap *sys_regs;
99	spinlock_t lock;
100	union {
101		u32 mask;
102		unsigned int divider;
103	};
104	unsigned long flags;
105	unsigned long features;
106};
107#define to_ccu_div(_hw) container_of(_hw, struct ccu_div, hw)
108
109static inline struct clk_hw *ccu_div_get_clk_hw(struct ccu_div *div)
110{
111	return div ? &div->hw : NULL;
112}
113
114struct ccu_div *ccu_div_hw_register(const struct ccu_div_init_data *init);
115
116void ccu_div_hw_unregister(struct ccu_div *div);
117
118int ccu_div_reset_domain(struct ccu_div *div);
119
120#endif /* __CLK_BT1_CCU_DIV_H__ */
121