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