11802d0beSThomas Gleixner /* SPDX-License-Identifier: GPL-2.0-only */ 29741b1a6SJames Liao /* 39741b1a6SJames Liao * Copyright (c) 2014 MediaTek Inc. 49741b1a6SJames Liao * Author: James Liao <jamesjj.liao@mediatek.com> 59741b1a6SJames Liao */ 69741b1a6SJames Liao 79741b1a6SJames Liao #ifndef __DRV_CLK_MTK_H 89741b1a6SJames Liao #define __DRV_CLK_MTK_H 99741b1a6SJames Liao 109741b1a6SJames Liao #include <linux/clk-provider.h> 11c42a2888SChen-Yu Tsai #include <linux/io.h> 12c42a2888SChen-Yu Tsai #include <linux/kernel.h> 13c42a2888SChen-Yu Tsai #include <linux/spinlock.h> 14c42a2888SChen-Yu Tsai #include <linux/types.h> 15c726639bSStephen Boyd 16b348c26cSRex-BC Chen #include "reset.h" 17b348c26cSRex-BC Chen 189741b1a6SJames Liao #define MAX_MUX_GATE_BIT 31 199741b1a6SJames Liao #define INVALID_MUX_GATE_BIT (MAX_MUX_GATE_BIT + 1) 209741b1a6SJames Liao 219741b1a6SJames Liao #define MHZ (1000 * 1000) 229741b1a6SJames Liao 23c42a2888SChen-Yu Tsai struct platform_device; 24c42a2888SChen-Yu Tsai 25b8eb1081SAngeloGioacchino Del Regno /* 26b8eb1081SAngeloGioacchino Del Regno * We need the clock IDs to start from zero but to maintain devicetree 27b8eb1081SAngeloGioacchino Del Regno * backwards compatibility we can't change bindings to start from zero. 28b8eb1081SAngeloGioacchino Del Regno * Only a few platforms are affected, so we solve issues given by the 29b8eb1081SAngeloGioacchino Del Regno * commonized MTK clocks probe function(s) by adding a dummy clock at 30b8eb1081SAngeloGioacchino Del Regno * the beginning where needed. 31b8eb1081SAngeloGioacchino Del Regno */ 32b8eb1081SAngeloGioacchino Del Regno #define CLK_DUMMY 0 33b8eb1081SAngeloGioacchino Del Regno 34b8eb1081SAngeloGioacchino Del Regno extern const struct clk_ops mtk_clk_dummy_ops; 35b8eb1081SAngeloGioacchino Del Regno extern const struct mtk_gate_regs cg_regs_dummy; 36b8eb1081SAngeloGioacchino Del Regno 37b8eb1081SAngeloGioacchino Del Regno #define GATE_DUMMY(_id, _name) { \ 38b8eb1081SAngeloGioacchino Del Regno .id = _id, \ 39b8eb1081SAngeloGioacchino Del Regno .name = _name, \ 40b8eb1081SAngeloGioacchino Del Regno .regs = &cg_regs_dummy, \ 41b8eb1081SAngeloGioacchino Del Regno .ops = &mtk_clk_dummy_ops, \ 42b8eb1081SAngeloGioacchino Del Regno } 43b8eb1081SAngeloGioacchino Del Regno 444fa04380SJames Liao struct mtk_fixed_clk { 454fa04380SJames Liao int id; 464fa04380SJames Liao const char *name; 474fa04380SJames Liao const char *parent; 484fa04380SJames Liao unsigned long rate; 494fa04380SJames Liao }; 504fa04380SJames Liao 514fa04380SJames Liao #define FIXED_CLK(_id, _name, _parent, _rate) { \ 524fa04380SJames Liao .id = _id, \ 534fa04380SJames Liao .name = _name, \ 544fa04380SJames Liao .parent = _parent, \ 554fa04380SJames Liao .rate = _rate, \ 564fa04380SJames Liao } 574fa04380SJames Liao 583c3ba2abSChen-Yu Tsai int mtk_clk_register_fixed_clks(const struct mtk_fixed_clk *clks, int num, 59609cc5e1SChen-Yu Tsai struct clk_hw_onecell_data *clk_data); 6034c9d454SChen-Yu Tsai void mtk_clk_unregister_fixed_clks(const struct mtk_fixed_clk *clks, int num, 61609cc5e1SChen-Yu Tsai struct clk_hw_onecell_data *clk_data); 624fa04380SJames Liao 639741b1a6SJames Liao struct mtk_fixed_factor { 649741b1a6SJames Liao int id; 659741b1a6SJames Liao const char *name; 669741b1a6SJames Liao const char *parent_name; 679741b1a6SJames Liao int mult; 689741b1a6SJames Liao int div; 69672c779eSAngeloGioacchino Del Regno unsigned long flags; 709741b1a6SJames Liao }; 719741b1a6SJames Liao 72672c779eSAngeloGioacchino Del Regno #define FACTOR_FLAGS(_id, _name, _parent, _mult, _div, _fl) { \ 739741b1a6SJames Liao .id = _id, \ 749741b1a6SJames Liao .name = _name, \ 759741b1a6SJames Liao .parent_name = _parent, \ 769741b1a6SJames Liao .mult = _mult, \ 779741b1a6SJames Liao .div = _div, \ 78672c779eSAngeloGioacchino Del Regno .flags = _fl, \ 799741b1a6SJames Liao } 809741b1a6SJames Liao 81672c779eSAngeloGioacchino Del Regno #define FACTOR(_id, _name, _parent, _mult, _div) \ 82672c779eSAngeloGioacchino Del Regno FACTOR_FLAGS(_id, _name, _parent, _mult, _div, CLK_SET_RATE_PARENT) 83672c779eSAngeloGioacchino Del Regno 843c3ba2abSChen-Yu Tsai int mtk_clk_register_factors(const struct mtk_fixed_factor *clks, int num, 85609cc5e1SChen-Yu Tsai struct clk_hw_onecell_data *clk_data); 861c6d6b69SChen-Yu Tsai void mtk_clk_unregister_factors(const struct mtk_fixed_factor *clks, int num, 87609cc5e1SChen-Yu Tsai struct clk_hw_onecell_data *clk_data); 889741b1a6SJames Liao 899741b1a6SJames Liao struct mtk_composite { 909741b1a6SJames Liao int id; 919741b1a6SJames Liao const char *name; 929741b1a6SJames Liao const char * const *parent_names; 939741b1a6SJames Liao const char *parent; 949741b1a6SJames Liao unsigned flags; 959741b1a6SJames Liao 969741b1a6SJames Liao uint32_t mux_reg; 979741b1a6SJames Liao uint32_t divider_reg; 989741b1a6SJames Liao uint32_t gate_reg; 999741b1a6SJames Liao 1009741b1a6SJames Liao signed char mux_shift; 1019741b1a6SJames Liao signed char mux_width; 1029741b1a6SJames Liao signed char gate_shift; 1039741b1a6SJames Liao 1049741b1a6SJames Liao signed char divider_shift; 1059741b1a6SJames Liao signed char divider_width; 1069741b1a6SJames Liao 107b026a7ecSchunhui dai u8 mux_flags; 108b026a7ecSchunhui dai 1099741b1a6SJames Liao signed char num_parents; 1109741b1a6SJames Liao }; 1119741b1a6SJames Liao 112b026a7ecSchunhui dai #define MUX_GATE_FLAGS_2(_id, _name, _parents, _reg, _shift, \ 113b026a7ecSchunhui dai _width, _gate, _flags, _muxflags) { \ 1149741b1a6SJames Liao .id = _id, \ 1159741b1a6SJames Liao .name = _name, \ 1169741b1a6SJames Liao .mux_reg = _reg, \ 1179741b1a6SJames Liao .mux_shift = _shift, \ 1189741b1a6SJames Liao .mux_width = _width, \ 1199741b1a6SJames Liao .gate_reg = _reg, \ 1209741b1a6SJames Liao .gate_shift = _gate, \ 1219741b1a6SJames Liao .divider_shift = -1, \ 1229741b1a6SJames Liao .parent_names = _parents, \ 1239741b1a6SJames Liao .num_parents = ARRAY_SIZE(_parents), \ 12406445994SPhilipp Zabel .flags = _flags, \ 125b026a7ecSchunhui dai .mux_flags = _muxflags, \ 1269741b1a6SJames Liao } 1279741b1a6SJames Liao 12806445994SPhilipp Zabel /* 129b026a7ecSchunhui dai * In case the rate change propagation to parent clocks is undesirable, 130b026a7ecSchunhui dai * this macro allows to specify the clock flags manually. 131b026a7ecSchunhui dai */ 132b026a7ecSchunhui dai #define MUX_GATE_FLAGS(_id, _name, _parents, _reg, _shift, _width, \ 133b026a7ecSchunhui dai _gate, _flags) \ 134b026a7ecSchunhui dai MUX_GATE_FLAGS_2(_id, _name, _parents, _reg, \ 135b026a7ecSchunhui dai _shift, _width, _gate, _flags, 0) 136b026a7ecSchunhui dai 137b026a7ecSchunhui dai /* 13806445994SPhilipp Zabel * Unless necessary, all MUX_GATE clocks propagate rate changes to their 13906445994SPhilipp Zabel * parent clock by default. 14006445994SPhilipp Zabel */ 14106445994SPhilipp Zabel #define MUX_GATE(_id, _name, _parents, _reg, _shift, _width, _gate) \ 142e9862118SShunli Wang MUX_GATE_FLAGS(_id, _name, _parents, _reg, _shift, _width, \ 143e9862118SShunli Wang _gate, CLK_SET_RATE_PARENT) 14406445994SPhilipp Zabel 14503c4fda6SJasper Mattsson #define MUX(_id, _name, _parents, _reg, _shift, _width) \ 14603c4fda6SJasper Mattsson MUX_FLAGS(_id, _name, _parents, _reg, \ 14703c4fda6SJasper Mattsson _shift, _width, CLK_SET_RATE_PARENT) 14803c4fda6SJasper Mattsson 14903c4fda6SJasper Mattsson #define MUX_FLAGS(_id, _name, _parents, _reg, _shift, _width, _flags) { \ 1509741b1a6SJames Liao .id = _id, \ 1519741b1a6SJames Liao .name = _name, \ 1529741b1a6SJames Liao .mux_reg = _reg, \ 1539741b1a6SJames Liao .mux_shift = _shift, \ 1549741b1a6SJames Liao .mux_width = _width, \ 1559741b1a6SJames Liao .gate_shift = -1, \ 1569741b1a6SJames Liao .divider_shift = -1, \ 1579741b1a6SJames Liao .parent_names = _parents, \ 1589741b1a6SJames Liao .num_parents = ARRAY_SIZE(_parents), \ 15903c4fda6SJasper Mattsson .flags = _flags, \ 1609741b1a6SJames Liao } 1619741b1a6SJames Liao 162e9862118SShunli Wang #define DIV_GATE(_id, _name, _parent, _gate_reg, _gate_shift, _div_reg, \ 163e9862118SShunli Wang _div_width, _div_shift) { \ 1649741b1a6SJames Liao .id = _id, \ 1659741b1a6SJames Liao .parent = _parent, \ 1669741b1a6SJames Liao .name = _name, \ 1679741b1a6SJames Liao .divider_reg = _div_reg, \ 1689741b1a6SJames Liao .divider_shift = _div_shift, \ 1699741b1a6SJames Liao .divider_width = _div_width, \ 1709741b1a6SJames Liao .gate_reg = _gate_reg, \ 1719741b1a6SJames Liao .gate_shift = _gate_shift, \ 1729741b1a6SJames Liao .mux_shift = -1, \ 1739741b1a6SJames Liao .flags = 0, \ 1749741b1a6SJames Liao } 1759741b1a6SJames Liao 17601a6c1abSAngeloGioacchino Del Regno int mtk_clk_register_composites(struct device *dev, 17701a6c1abSAngeloGioacchino Del Regno const struct mtk_composite *mcs, int num, 1783c3ba2abSChen-Yu Tsai void __iomem *base, spinlock_t *lock, 179609cc5e1SChen-Yu Tsai struct clk_hw_onecell_data *clk_data); 180cb50864fSChen-Yu Tsai void mtk_clk_unregister_composites(const struct mtk_composite *mcs, int num, 181609cc5e1SChen-Yu Tsai struct clk_hw_onecell_data *clk_data); 1829741b1a6SJames Liao 183e9862118SShunli Wang struct mtk_clk_divider { 184e9862118SShunli Wang int id; 185e9862118SShunli Wang const char *name; 186e9862118SShunli Wang const char *parent_name; 187e9862118SShunli Wang unsigned long flags; 188e9862118SShunli Wang 189e9862118SShunli Wang u32 div_reg; 190e9862118SShunli Wang unsigned char div_shift; 191e9862118SShunli Wang unsigned char div_width; 192e9862118SShunli Wang unsigned char clk_divider_flags; 193e9862118SShunli Wang const struct clk_div_table *clk_div_table; 194e9862118SShunli Wang }; 195e9862118SShunli Wang 196e9862118SShunli Wang #define DIV_ADJ(_id, _name, _parent, _reg, _shift, _width) { \ 197e9862118SShunli Wang .id = _id, \ 198e9862118SShunli Wang .name = _name, \ 199e9862118SShunli Wang .parent_name = _parent, \ 200e9862118SShunli Wang .div_reg = _reg, \ 201e9862118SShunli Wang .div_shift = _shift, \ 202e9862118SShunli Wang .div_width = _width, \ 203e9862118SShunli Wang } 204e9862118SShunli Wang 2056b7daeaaSAngeloGioacchino Del Regno int mtk_clk_register_dividers(struct device *dev, 2066b7daeaaSAngeloGioacchino Del Regno const struct mtk_clk_divider *mcds, int num, 207b87385ebSChen-Yu Tsai void __iomem *base, spinlock_t *lock, 208609cc5e1SChen-Yu Tsai struct clk_hw_onecell_data *clk_data); 209b87385ebSChen-Yu Tsai void mtk_clk_unregister_dividers(const struct mtk_clk_divider *mcds, int num, 210609cc5e1SChen-Yu Tsai struct clk_hw_onecell_data *clk_data); 2119741b1a6SJames Liao 212609cc5e1SChen-Yu Tsai struct clk_hw_onecell_data *mtk_alloc_clk_data(unsigned int clk_num); 21350e68b99SMarkus Schneider-Pargmann struct clk_hw_onecell_data *mtk_devm_alloc_clk_data(struct device *dev, 21450e68b99SMarkus Schneider-Pargmann unsigned int clk_num); 215609cc5e1SChen-Yu Tsai void mtk_free_clk_data(struct clk_hw_onecell_data *clk_data); 2169741b1a6SJames Liao 2176f691a58SChen-Yu Tsai struct clk_hw *mtk_clk_register_ref2usb_tx(const char *name, 218cdb2bab7SJames Liao const char *parent_name, void __iomem *reg); 219b7520e2dSAngeloGioacchino Del Regno void mtk_clk_unregister_ref2usb_tx(struct clk_hw *hw); 220cdb2bab7SJames Liao 221c58cd0e4SChun-Jie Chen struct mtk_clk_desc { 222c58cd0e4SChun-Jie Chen const struct mtk_gate *clks; 223c58cd0e4SChun-Jie Chen size_t num_clks; 2247b618310SAngeloGioacchino Del Regno const struct mtk_composite *composite_clks; 2257b618310SAngeloGioacchino Del Regno size_t num_composite_clks; 2261fe074b1SAngeloGioacchino Del Regno const struct mtk_clk_divider *divider_clks; 2271fe074b1SAngeloGioacchino Del Regno size_t num_divider_clks; 2287b618310SAngeloGioacchino Del Regno const struct mtk_fixed_clk *fixed_clks; 2297b618310SAngeloGioacchino Del Regno size_t num_fixed_clks; 2307b618310SAngeloGioacchino Del Regno const struct mtk_fixed_factor *factor_clks; 2317b618310SAngeloGioacchino Del Regno size_t num_factor_clks; 2327b618310SAngeloGioacchino Del Regno const struct mtk_mux *mux_clks; 2337b618310SAngeloGioacchino Del Regno size_t num_mux_clks; 234b27a604aSRex-BC Chen const struct mtk_clk_rst_desc *rst_desc; 2357b618310SAngeloGioacchino Del Regno spinlock_t *clk_lock; 2367b618310SAngeloGioacchino Del Regno bool shared_io; 237fd9fe654SAngeloGioacchino Del Regno 238fd9fe654SAngeloGioacchino Del Regno int (*clk_notifier_func)(struct device *dev, struct clk *clk); 239fd9fe654SAngeloGioacchino Del Regno unsigned int mfg_clk_idx; 240*878e845dSPin-yen Lin 241*878e845dSPin-yen Lin bool need_runtime_pm; 242c58cd0e4SChun-Jie Chen }; 243c58cd0e4SChun-Jie Chen 24425209124SAngeloGioacchino Del Regno int mtk_clk_pdev_probe(struct platform_device *pdev); 245b3bc7275SUwe Kleine-König void mtk_clk_pdev_remove(struct platform_device *pdev); 246c58cd0e4SChun-Jie Chen int mtk_clk_simple_probe(struct platform_device *pdev); 24761ca6ee7SUwe Kleine-König void mtk_clk_simple_remove(struct platform_device *pdev); 248c58cd0e4SChun-Jie Chen 2499741b1a6SJames Liao #endif /* __DRV_CLK_MTK_H */ 250