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