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/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 } 100