162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0-only */ 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright (c) 2014 MediaTek Inc. 462306a36Sopenharmony_ci * Author: James Liao <jamesjj.liao@mediatek.com> 562306a36Sopenharmony_ci */ 662306a36Sopenharmony_ci 762306a36Sopenharmony_ci#ifndef __DRV_CLK_MTK_H 862306a36Sopenharmony_ci#define __DRV_CLK_MTK_H 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ci#include <linux/clk-provider.h> 1162306a36Sopenharmony_ci#include <linux/io.h> 1262306a36Sopenharmony_ci#include <linux/kernel.h> 1362306a36Sopenharmony_ci#include <linux/spinlock.h> 1462306a36Sopenharmony_ci#include <linux/types.h> 1562306a36Sopenharmony_ci 1662306a36Sopenharmony_ci#include "reset.h" 1762306a36Sopenharmony_ci 1862306a36Sopenharmony_ci#define MAX_MUX_GATE_BIT 31 1962306a36Sopenharmony_ci#define INVALID_MUX_GATE_BIT (MAX_MUX_GATE_BIT + 1) 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_ci#define MHZ (1000 * 1000) 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_cistruct platform_device; 2462306a36Sopenharmony_ci 2562306a36Sopenharmony_ci/* 2662306a36Sopenharmony_ci * We need the clock IDs to start from zero but to maintain devicetree 2762306a36Sopenharmony_ci * backwards compatibility we can't change bindings to start from zero. 2862306a36Sopenharmony_ci * Only a few platforms are affected, so we solve issues given by the 2962306a36Sopenharmony_ci * commonized MTK clocks probe function(s) by adding a dummy clock at 3062306a36Sopenharmony_ci * the beginning where needed. 3162306a36Sopenharmony_ci */ 3262306a36Sopenharmony_ci#define CLK_DUMMY 0 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_ciextern const struct clk_ops mtk_clk_dummy_ops; 3562306a36Sopenharmony_ciextern const struct mtk_gate_regs cg_regs_dummy; 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_ci#define GATE_DUMMY(_id, _name) { \ 3862306a36Sopenharmony_ci .id = _id, \ 3962306a36Sopenharmony_ci .name = _name, \ 4062306a36Sopenharmony_ci .regs = &cg_regs_dummy, \ 4162306a36Sopenharmony_ci .ops = &mtk_clk_dummy_ops, \ 4262306a36Sopenharmony_ci } 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_cistruct mtk_fixed_clk { 4562306a36Sopenharmony_ci int id; 4662306a36Sopenharmony_ci const char *name; 4762306a36Sopenharmony_ci const char *parent; 4862306a36Sopenharmony_ci unsigned long rate; 4962306a36Sopenharmony_ci}; 5062306a36Sopenharmony_ci 5162306a36Sopenharmony_ci#define FIXED_CLK(_id, _name, _parent, _rate) { \ 5262306a36Sopenharmony_ci .id = _id, \ 5362306a36Sopenharmony_ci .name = _name, \ 5462306a36Sopenharmony_ci .parent = _parent, \ 5562306a36Sopenharmony_ci .rate = _rate, \ 5662306a36Sopenharmony_ci } 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_ciint mtk_clk_register_fixed_clks(const struct mtk_fixed_clk *clks, int num, 5962306a36Sopenharmony_ci struct clk_hw_onecell_data *clk_data); 6062306a36Sopenharmony_civoid mtk_clk_unregister_fixed_clks(const struct mtk_fixed_clk *clks, int num, 6162306a36Sopenharmony_ci struct clk_hw_onecell_data *clk_data); 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_cistruct mtk_fixed_factor { 6462306a36Sopenharmony_ci int id; 6562306a36Sopenharmony_ci const char *name; 6662306a36Sopenharmony_ci const char *parent_name; 6762306a36Sopenharmony_ci int mult; 6862306a36Sopenharmony_ci int div; 6962306a36Sopenharmony_ci unsigned long flags; 7062306a36Sopenharmony_ci}; 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_ci#define FACTOR_FLAGS(_id, _name, _parent, _mult, _div, _fl) { \ 7362306a36Sopenharmony_ci .id = _id, \ 7462306a36Sopenharmony_ci .name = _name, \ 7562306a36Sopenharmony_ci .parent_name = _parent, \ 7662306a36Sopenharmony_ci .mult = _mult, \ 7762306a36Sopenharmony_ci .div = _div, \ 7862306a36Sopenharmony_ci .flags = _fl, \ 7962306a36Sopenharmony_ci } 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_ci#define FACTOR(_id, _name, _parent, _mult, _div) \ 8262306a36Sopenharmony_ci FACTOR_FLAGS(_id, _name, _parent, _mult, _div, CLK_SET_RATE_PARENT) 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_ciint mtk_clk_register_factors(const struct mtk_fixed_factor *clks, int num, 8562306a36Sopenharmony_ci struct clk_hw_onecell_data *clk_data); 8662306a36Sopenharmony_civoid mtk_clk_unregister_factors(const struct mtk_fixed_factor *clks, int num, 8762306a36Sopenharmony_ci struct clk_hw_onecell_data *clk_data); 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_cistruct mtk_composite { 9062306a36Sopenharmony_ci int id; 9162306a36Sopenharmony_ci const char *name; 9262306a36Sopenharmony_ci const char * const *parent_names; 9362306a36Sopenharmony_ci const char *parent; 9462306a36Sopenharmony_ci unsigned flags; 9562306a36Sopenharmony_ci 9662306a36Sopenharmony_ci uint32_t mux_reg; 9762306a36Sopenharmony_ci uint32_t divider_reg; 9862306a36Sopenharmony_ci uint32_t gate_reg; 9962306a36Sopenharmony_ci 10062306a36Sopenharmony_ci signed char mux_shift; 10162306a36Sopenharmony_ci signed char mux_width; 10262306a36Sopenharmony_ci signed char gate_shift; 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_ci signed char divider_shift; 10562306a36Sopenharmony_ci signed char divider_width; 10662306a36Sopenharmony_ci 10762306a36Sopenharmony_ci u8 mux_flags; 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_ci signed char num_parents; 11062306a36Sopenharmony_ci}; 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_ci#define MUX_GATE_FLAGS_2(_id, _name, _parents, _reg, _shift, \ 11362306a36Sopenharmony_ci _width, _gate, _flags, _muxflags) { \ 11462306a36Sopenharmony_ci .id = _id, \ 11562306a36Sopenharmony_ci .name = _name, \ 11662306a36Sopenharmony_ci .mux_reg = _reg, \ 11762306a36Sopenharmony_ci .mux_shift = _shift, \ 11862306a36Sopenharmony_ci .mux_width = _width, \ 11962306a36Sopenharmony_ci .gate_reg = _reg, \ 12062306a36Sopenharmony_ci .gate_shift = _gate, \ 12162306a36Sopenharmony_ci .divider_shift = -1, \ 12262306a36Sopenharmony_ci .parent_names = _parents, \ 12362306a36Sopenharmony_ci .num_parents = ARRAY_SIZE(_parents), \ 12462306a36Sopenharmony_ci .flags = _flags, \ 12562306a36Sopenharmony_ci .mux_flags = _muxflags, \ 12662306a36Sopenharmony_ci } 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_ci/* 12962306a36Sopenharmony_ci * In case the rate change propagation to parent clocks is undesirable, 13062306a36Sopenharmony_ci * this macro allows to specify the clock flags manually. 13162306a36Sopenharmony_ci */ 13262306a36Sopenharmony_ci#define MUX_GATE_FLAGS(_id, _name, _parents, _reg, _shift, _width, \ 13362306a36Sopenharmony_ci _gate, _flags) \ 13462306a36Sopenharmony_ci MUX_GATE_FLAGS_2(_id, _name, _parents, _reg, \ 13562306a36Sopenharmony_ci _shift, _width, _gate, _flags, 0) 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_ci/* 13862306a36Sopenharmony_ci * Unless necessary, all MUX_GATE clocks propagate rate changes to their 13962306a36Sopenharmony_ci * parent clock by default. 14062306a36Sopenharmony_ci */ 14162306a36Sopenharmony_ci#define MUX_GATE(_id, _name, _parents, _reg, _shift, _width, _gate) \ 14262306a36Sopenharmony_ci MUX_GATE_FLAGS(_id, _name, _parents, _reg, _shift, _width, \ 14362306a36Sopenharmony_ci _gate, CLK_SET_RATE_PARENT) 14462306a36Sopenharmony_ci 14562306a36Sopenharmony_ci#define MUX(_id, _name, _parents, _reg, _shift, _width) \ 14662306a36Sopenharmony_ci MUX_FLAGS(_id, _name, _parents, _reg, \ 14762306a36Sopenharmony_ci _shift, _width, CLK_SET_RATE_PARENT) 14862306a36Sopenharmony_ci 14962306a36Sopenharmony_ci#define MUX_FLAGS(_id, _name, _parents, _reg, _shift, _width, _flags) { \ 15062306a36Sopenharmony_ci .id = _id, \ 15162306a36Sopenharmony_ci .name = _name, \ 15262306a36Sopenharmony_ci .mux_reg = _reg, \ 15362306a36Sopenharmony_ci .mux_shift = _shift, \ 15462306a36Sopenharmony_ci .mux_width = _width, \ 15562306a36Sopenharmony_ci .gate_shift = -1, \ 15662306a36Sopenharmony_ci .divider_shift = -1, \ 15762306a36Sopenharmony_ci .parent_names = _parents, \ 15862306a36Sopenharmony_ci .num_parents = ARRAY_SIZE(_parents), \ 15962306a36Sopenharmony_ci .flags = _flags, \ 16062306a36Sopenharmony_ci } 16162306a36Sopenharmony_ci 16262306a36Sopenharmony_ci#define DIV_GATE(_id, _name, _parent, _gate_reg, _gate_shift, _div_reg, \ 16362306a36Sopenharmony_ci _div_width, _div_shift) { \ 16462306a36Sopenharmony_ci .id = _id, \ 16562306a36Sopenharmony_ci .parent = _parent, \ 16662306a36Sopenharmony_ci .name = _name, \ 16762306a36Sopenharmony_ci .divider_reg = _div_reg, \ 16862306a36Sopenharmony_ci .divider_shift = _div_shift, \ 16962306a36Sopenharmony_ci .divider_width = _div_width, \ 17062306a36Sopenharmony_ci .gate_reg = _gate_reg, \ 17162306a36Sopenharmony_ci .gate_shift = _gate_shift, \ 17262306a36Sopenharmony_ci .mux_shift = -1, \ 17362306a36Sopenharmony_ci .flags = 0, \ 17462306a36Sopenharmony_ci } 17562306a36Sopenharmony_ci 17662306a36Sopenharmony_ciint mtk_clk_register_composites(struct device *dev, 17762306a36Sopenharmony_ci const struct mtk_composite *mcs, int num, 17862306a36Sopenharmony_ci void __iomem *base, spinlock_t *lock, 17962306a36Sopenharmony_ci struct clk_hw_onecell_data *clk_data); 18062306a36Sopenharmony_civoid mtk_clk_unregister_composites(const struct mtk_composite *mcs, int num, 18162306a36Sopenharmony_ci struct clk_hw_onecell_data *clk_data); 18262306a36Sopenharmony_ci 18362306a36Sopenharmony_cistruct mtk_clk_divider { 18462306a36Sopenharmony_ci int id; 18562306a36Sopenharmony_ci const char *name; 18662306a36Sopenharmony_ci const char *parent_name; 18762306a36Sopenharmony_ci unsigned long flags; 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_ci u32 div_reg; 19062306a36Sopenharmony_ci unsigned char div_shift; 19162306a36Sopenharmony_ci unsigned char div_width; 19262306a36Sopenharmony_ci unsigned char clk_divider_flags; 19362306a36Sopenharmony_ci const struct clk_div_table *clk_div_table; 19462306a36Sopenharmony_ci}; 19562306a36Sopenharmony_ci 19662306a36Sopenharmony_ci#define DIV_ADJ(_id, _name, _parent, _reg, _shift, _width) { \ 19762306a36Sopenharmony_ci .id = _id, \ 19862306a36Sopenharmony_ci .name = _name, \ 19962306a36Sopenharmony_ci .parent_name = _parent, \ 20062306a36Sopenharmony_ci .div_reg = _reg, \ 20162306a36Sopenharmony_ci .div_shift = _shift, \ 20262306a36Sopenharmony_ci .div_width = _width, \ 20362306a36Sopenharmony_ci} 20462306a36Sopenharmony_ci 20562306a36Sopenharmony_ciint mtk_clk_register_dividers(struct device *dev, 20662306a36Sopenharmony_ci const struct mtk_clk_divider *mcds, int num, 20762306a36Sopenharmony_ci void __iomem *base, spinlock_t *lock, 20862306a36Sopenharmony_ci struct clk_hw_onecell_data *clk_data); 20962306a36Sopenharmony_civoid mtk_clk_unregister_dividers(const struct mtk_clk_divider *mcds, int num, 21062306a36Sopenharmony_ci struct clk_hw_onecell_data *clk_data); 21162306a36Sopenharmony_ci 21262306a36Sopenharmony_cistruct clk_hw_onecell_data *mtk_alloc_clk_data(unsigned int clk_num); 21362306a36Sopenharmony_cistruct clk_hw_onecell_data *mtk_devm_alloc_clk_data(struct device *dev, 21462306a36Sopenharmony_ci unsigned int clk_num); 21562306a36Sopenharmony_civoid mtk_free_clk_data(struct clk_hw_onecell_data *clk_data); 21662306a36Sopenharmony_ci 21762306a36Sopenharmony_cistruct clk_hw *mtk_clk_register_ref2usb_tx(const char *name, 21862306a36Sopenharmony_ci const char *parent_name, void __iomem *reg); 21962306a36Sopenharmony_civoid mtk_clk_unregister_ref2usb_tx(struct clk_hw *hw); 22062306a36Sopenharmony_ci 22162306a36Sopenharmony_cistruct mtk_clk_desc { 22262306a36Sopenharmony_ci const struct mtk_gate *clks; 22362306a36Sopenharmony_ci size_t num_clks; 22462306a36Sopenharmony_ci const struct mtk_composite *composite_clks; 22562306a36Sopenharmony_ci size_t num_composite_clks; 22662306a36Sopenharmony_ci const struct mtk_clk_divider *divider_clks; 22762306a36Sopenharmony_ci size_t num_divider_clks; 22862306a36Sopenharmony_ci const struct mtk_fixed_clk *fixed_clks; 22962306a36Sopenharmony_ci size_t num_fixed_clks; 23062306a36Sopenharmony_ci const struct mtk_fixed_factor *factor_clks; 23162306a36Sopenharmony_ci size_t num_factor_clks; 23262306a36Sopenharmony_ci const struct mtk_mux *mux_clks; 23362306a36Sopenharmony_ci size_t num_mux_clks; 23462306a36Sopenharmony_ci const struct mtk_clk_rst_desc *rst_desc; 23562306a36Sopenharmony_ci spinlock_t *clk_lock; 23662306a36Sopenharmony_ci bool shared_io; 23762306a36Sopenharmony_ci 23862306a36Sopenharmony_ci int (*clk_notifier_func)(struct device *dev, struct clk *clk); 23962306a36Sopenharmony_ci unsigned int mfg_clk_idx; 24062306a36Sopenharmony_ci}; 24162306a36Sopenharmony_ci 24262306a36Sopenharmony_ciint mtk_clk_pdev_probe(struct platform_device *pdev); 24362306a36Sopenharmony_civoid mtk_clk_pdev_remove(struct platform_device *pdev); 24462306a36Sopenharmony_ciint mtk_clk_simple_probe(struct platform_device *pdev); 24562306a36Sopenharmony_civoid mtk_clk_simple_remove(struct platform_device *pdev); 24662306a36Sopenharmony_ci 24762306a36Sopenharmony_ci#endif /* __DRV_CLK_MTK_H */ 248