xref: /linux/drivers/clk/mediatek/clk-apmixed.c (revision 4f2c0a4acffbec01079c28f839422e64ddeff004)
11802d0beSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
2cdb2bab7SJames Liao /*
3cdb2bab7SJames Liao  * Copyright (c) 2015 MediaTek Inc.
4cdb2bab7SJames Liao  * Author: James Liao <jamesjj.liao@mediatek.com>
5cdb2bab7SJames Liao  */
6cdb2bab7SJames Liao 
7cdb2bab7SJames Liao #include <linux/delay.h>
832b028fbSMiles Chen #include <linux/module.h>
9cdb2bab7SJames Liao #include <linux/of_address.h>
10cdb2bab7SJames Liao #include <linux/slab.h>
11cdb2bab7SJames Liao 
12cdb2bab7SJames Liao #include "clk-mtk.h"
13cdb2bab7SJames Liao 
14cdb2bab7SJames Liao #define REF2USB_TX_EN		BIT(0)
15cdb2bab7SJames Liao #define REF2USB_TX_LPF_EN	BIT(1)
16cdb2bab7SJames Liao #define REF2USB_TX_OUT_EN	BIT(2)
17cdb2bab7SJames Liao #define REF2USB_EN_MASK		(REF2USB_TX_EN | REF2USB_TX_LPF_EN | \
18cdb2bab7SJames Liao 				 REF2USB_TX_OUT_EN)
19cdb2bab7SJames Liao 
20cdb2bab7SJames Liao struct mtk_ref2usb_tx {
21cdb2bab7SJames Liao 	struct clk_hw	hw;
22cdb2bab7SJames Liao 	void __iomem	*base_addr;
23cdb2bab7SJames Liao };
24cdb2bab7SJames Liao 
to_mtk_ref2usb_tx(struct clk_hw * hw)25cdb2bab7SJames Liao static inline struct mtk_ref2usb_tx *to_mtk_ref2usb_tx(struct clk_hw *hw)
26cdb2bab7SJames Liao {
27cdb2bab7SJames Liao 	return container_of(hw, struct mtk_ref2usb_tx, hw);
28cdb2bab7SJames Liao }
29cdb2bab7SJames Liao 
mtk_ref2usb_tx_is_prepared(struct clk_hw * hw)30cdb2bab7SJames Liao static int mtk_ref2usb_tx_is_prepared(struct clk_hw *hw)
31cdb2bab7SJames Liao {
32cdb2bab7SJames Liao 	struct mtk_ref2usb_tx *tx = to_mtk_ref2usb_tx(hw);
33cdb2bab7SJames Liao 
34cdb2bab7SJames Liao 	return (readl(tx->base_addr) & REF2USB_EN_MASK) == REF2USB_EN_MASK;
35cdb2bab7SJames Liao }
36cdb2bab7SJames Liao 
mtk_ref2usb_tx_prepare(struct clk_hw * hw)37cdb2bab7SJames Liao static int mtk_ref2usb_tx_prepare(struct clk_hw *hw)
38cdb2bab7SJames Liao {
39cdb2bab7SJames Liao 	struct mtk_ref2usb_tx *tx = to_mtk_ref2usb_tx(hw);
40cdb2bab7SJames Liao 	u32 val;
41cdb2bab7SJames Liao 
42cdb2bab7SJames Liao 	val = readl(tx->base_addr);
43cdb2bab7SJames Liao 
44cdb2bab7SJames Liao 	val |= REF2USB_TX_EN;
45cdb2bab7SJames Liao 	writel(val, tx->base_addr);
46cdb2bab7SJames Liao 	udelay(100);
47cdb2bab7SJames Liao 
48cdb2bab7SJames Liao 	val |= REF2USB_TX_LPF_EN;
49cdb2bab7SJames Liao 	writel(val, tx->base_addr);
50cdb2bab7SJames Liao 
51cdb2bab7SJames Liao 	val |= REF2USB_TX_OUT_EN;
52cdb2bab7SJames Liao 	writel(val, tx->base_addr);
53cdb2bab7SJames Liao 
54cdb2bab7SJames Liao 	return 0;
55cdb2bab7SJames Liao }
56cdb2bab7SJames Liao 
mtk_ref2usb_tx_unprepare(struct clk_hw * hw)57cdb2bab7SJames Liao static void mtk_ref2usb_tx_unprepare(struct clk_hw *hw)
58cdb2bab7SJames Liao {
59cdb2bab7SJames Liao 	struct mtk_ref2usb_tx *tx = to_mtk_ref2usb_tx(hw);
60cdb2bab7SJames Liao 	u32 val;
61cdb2bab7SJames Liao 
62cdb2bab7SJames Liao 	val = readl(tx->base_addr);
63cdb2bab7SJames Liao 	val &= ~REF2USB_EN_MASK;
64cdb2bab7SJames Liao 	writel(val, tx->base_addr);
65cdb2bab7SJames Liao }
66cdb2bab7SJames Liao 
67cdb2bab7SJames Liao static const struct clk_ops mtk_ref2usb_tx_ops = {
68cdb2bab7SJames Liao 	.is_prepared	= mtk_ref2usb_tx_is_prepared,
69cdb2bab7SJames Liao 	.prepare	= mtk_ref2usb_tx_prepare,
70cdb2bab7SJames Liao 	.unprepare	= mtk_ref2usb_tx_unprepare,
71cdb2bab7SJames Liao };
72cdb2bab7SJames Liao 
mtk_clk_register_ref2usb_tx(const char * name,const char * parent_name,void __iomem * reg)7385b2181cSAngeloGioacchino Del Regno struct clk_hw *mtk_clk_register_ref2usb_tx(const char *name,
74cdb2bab7SJames Liao 			const char *parent_name, void __iomem *reg)
75cdb2bab7SJames Liao {
76cdb2bab7SJames Liao 	struct mtk_ref2usb_tx *tx;
77cdb2bab7SJames Liao 	struct clk_init_data init = {};
786f691a58SChen-Yu Tsai 	int ret;
79cdb2bab7SJames Liao 
80cdb2bab7SJames Liao 	tx = kzalloc(sizeof(*tx), GFP_KERNEL);
81cdb2bab7SJames Liao 	if (!tx)
82cdb2bab7SJames Liao 		return ERR_PTR(-ENOMEM);
83cdb2bab7SJames Liao 
84cdb2bab7SJames Liao 	tx->base_addr = reg;
85cdb2bab7SJames Liao 	tx->hw.init = &init;
86cdb2bab7SJames Liao 
87cdb2bab7SJames Liao 	init.name = name;
88cdb2bab7SJames Liao 	init.ops = &mtk_ref2usb_tx_ops;
89cdb2bab7SJames Liao 	init.parent_names = &parent_name;
90cdb2bab7SJames Liao 	init.num_parents = 1;
91cdb2bab7SJames Liao 
926f691a58SChen-Yu Tsai 	ret = clk_hw_register(NULL, &tx->hw);
93cdb2bab7SJames Liao 
946f691a58SChen-Yu Tsai 	if (ret) {
95cdb2bab7SJames Liao 		kfree(tx);
966f691a58SChen-Yu Tsai 		return ERR_PTR(ret);
976f691a58SChen-Yu Tsai 	}
98cdb2bab7SJames Liao 
996f691a58SChen-Yu Tsai 	return &tx->hw;
100cdb2bab7SJames Liao }
1017cbe5cb2SAngeloGioacchino Del Regno EXPORT_SYMBOL_GPL(mtk_clk_register_ref2usb_tx);
10232b028fbSMiles Chen 
mtk_clk_unregister_ref2usb_tx(struct clk_hw * hw)103*b7520e2dSAngeloGioacchino Del Regno void mtk_clk_unregister_ref2usb_tx(struct clk_hw *hw)
104*b7520e2dSAngeloGioacchino Del Regno {
105*b7520e2dSAngeloGioacchino Del Regno 	struct mtk_ref2usb_tx *tx = to_mtk_ref2usb_tx(hw);
106*b7520e2dSAngeloGioacchino Del Regno 
107*b7520e2dSAngeloGioacchino Del Regno 	clk_hw_unregister(hw);
108*b7520e2dSAngeloGioacchino Del Regno 	kfree(tx);
109*b7520e2dSAngeloGioacchino Del Regno }
110*b7520e2dSAngeloGioacchino Del Regno EXPORT_SYMBOL_GPL(mtk_clk_unregister_ref2usb_tx);
111*b7520e2dSAngeloGioacchino Del Regno 
11232b028fbSMiles Chen MODULE_LICENSE("GPL");
113