diff options
Diffstat (limited to 'drivers/clk/baikal-t1/ccu-div.h')
-rw-r--r-- | drivers/clk/baikal-t1/ccu-div.h | 121 |
1 files changed, 121 insertions, 0 deletions
diff --git a/drivers/clk/baikal-t1/ccu-div.h b/drivers/clk/baikal-t1/ccu-div.h new file mode 100644 index 0000000000..76d8ee44d4 --- /dev/null +++ b/drivers/clk/baikal-t1/ccu-div.h @@ -0,0 +1,121 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (C) 2020 BAIKAL ELECTRONICS, JSC + * + * Baikal-T1 CCU Dividers interface driver + */ +#ifndef __CLK_BT1_CCU_DIV_H__ +#define __CLK_BT1_CCU_DIV_H__ + +#include <linux/clk-provider.h> +#include <linux/spinlock.h> +#include <linux/regmap.h> +#include <linux/bits.h> +#include <linux/of.h> + +/* + * CCU Divider private clock IDs + * @CCU_SYS_SATA_CLK: CCU SATA internal clock + * @CCU_SYS_XGMAC_CLK: CCU XGMAC internal clock + */ +#define CCU_SYS_SATA_CLK -1 +#define CCU_SYS_XGMAC_CLK -2 + +/* + * CCU Divider private flags + * @CCU_DIV_BASIC: Basic divider clock required by the kernel as early as + * possible. + * @CCU_DIV_SKIP_ONE: Due to some reason divider can't be set to 1. + * It can be 0 though, which is functionally the same. + * @CCU_DIV_SKIP_ONE_TO_THREE: For some reason divider can't be within [1,3]. + * It can be either 0 or greater than 3. + * @CCU_DIV_LOCK_SHIFTED: Find lock-bit at non-standard position. + * @CCU_DIV_RESET_DOMAIN: There is a clock domain reset handle. + */ +#define CCU_DIV_BASIC BIT(0) +#define CCU_DIV_SKIP_ONE BIT(1) +#define CCU_DIV_SKIP_ONE_TO_THREE BIT(2) +#define CCU_DIV_LOCK_SHIFTED BIT(3) +#define CCU_DIV_RESET_DOMAIN BIT(4) + +/* + * enum ccu_div_type - CCU Divider types + * @CCU_DIV_VAR: Clocks gate with variable divider. + * @CCU_DIV_GATE: Clocks gate with fixed divider. + * @CCU_DIV_BUF: Clock gate with no divider. + * @CCU_DIV_FIXED: Ungateable clock with fixed divider. + */ +enum ccu_div_type { + CCU_DIV_VAR, + CCU_DIV_GATE, + CCU_DIV_BUF, + CCU_DIV_FIXED +}; + +/* + * struct ccu_div_init_data - CCU Divider initialization data + * @id: Clocks private identifier. + * @name: Clocks name. + * @parent_name: Parent clocks name in a fw node. + * @base: Divider register base address with respect to the sys_regs base. + * @sys_regs: Baikal-T1 System Controller registers map. + * @np: Pointer to the node describing the CCU Dividers. + * @type: CCU divider type (variable, fixed with and without gate). + * @width: Divider width if it's variable. + * @divider: Divider fixed value. + * @flags: CCU Divider clock flags. + * @features: CCU Divider private features. + */ +struct ccu_div_init_data { + unsigned int id; + const char *name; + const char *parent_name; + unsigned int base; + struct regmap *sys_regs; + struct device_node *np; + enum ccu_div_type type; + union { + unsigned int width; + unsigned int divider; + }; + unsigned long flags; + unsigned long features; +}; + +/* + * struct ccu_div - CCU Divider descriptor + * @hw: clk_hw of the divider. + * @id: Clock private identifier. + * @reg_ctl: Divider control register base address. + * @sys_regs: Baikal-T1 System Controller registers map. + * @lock: Divider state change spin-lock. + * @mask: Divider field mask. + * @divider: Divider fixed value. + * @flags: Divider clock flags. + * @features: CCU Divider private features. + */ +struct ccu_div { + struct clk_hw hw; + unsigned int id; + unsigned int reg_ctl; + struct regmap *sys_regs; + spinlock_t lock; + union { + u32 mask; + unsigned int divider; + }; + unsigned long flags; + unsigned long features; +}; +#define to_ccu_div(_hw) container_of(_hw, struct ccu_div, hw) + +static inline struct clk_hw *ccu_div_get_clk_hw(struct ccu_div *div) +{ + return div ? &div->hw : NULL; +} + +struct ccu_div *ccu_div_hw_register(const struct ccu_div_init_data *init); + +void ccu_div_hw_unregister(struct ccu_div *div); + +#endif /* __CLK_BT1_CCU_DIV_H__ */ |