1*cdb2bab7SJames Liao /* 2*cdb2bab7SJames Liao * Copyright (c) 2015 MediaTek Inc. 3*cdb2bab7SJames Liao * Author: James Liao <jamesjj.liao@mediatek.com> 4*cdb2bab7SJames Liao * 5*cdb2bab7SJames Liao * This program is free software; you can redistribute it and/or modify 6*cdb2bab7SJames Liao * it under the terms of the GNU General Public License version 2 as 7*cdb2bab7SJames Liao * published by the Free Software Foundation. 8*cdb2bab7SJames Liao * 9*cdb2bab7SJames Liao * This program is distributed in the hope that it will be useful, 10*cdb2bab7SJames Liao * but WITHOUT ANY WARRANTY; without even the implied warranty of 11*cdb2bab7SJames Liao * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12*cdb2bab7SJames Liao * GNU General Public License for more details. 13*cdb2bab7SJames Liao */ 14*cdb2bab7SJames Liao 15*cdb2bab7SJames Liao #include <linux/delay.h> 16*cdb2bab7SJames Liao #include <linux/of_address.h> 17*cdb2bab7SJames Liao #include <linux/slab.h> 18*cdb2bab7SJames Liao 19*cdb2bab7SJames Liao #include "clk-mtk.h" 20*cdb2bab7SJames Liao 21*cdb2bab7SJames Liao #define REF2USB_TX_EN BIT(0) 22*cdb2bab7SJames Liao #define REF2USB_TX_LPF_EN BIT(1) 23*cdb2bab7SJames Liao #define REF2USB_TX_OUT_EN BIT(2) 24*cdb2bab7SJames Liao #define REF2USB_EN_MASK (REF2USB_TX_EN | REF2USB_TX_LPF_EN | \ 25*cdb2bab7SJames Liao REF2USB_TX_OUT_EN) 26*cdb2bab7SJames Liao 27*cdb2bab7SJames Liao struct mtk_ref2usb_tx { 28*cdb2bab7SJames Liao struct clk_hw hw; 29*cdb2bab7SJames Liao void __iomem *base_addr; 30*cdb2bab7SJames Liao }; 31*cdb2bab7SJames Liao 32*cdb2bab7SJames Liao static inline struct mtk_ref2usb_tx *to_mtk_ref2usb_tx(struct clk_hw *hw) 33*cdb2bab7SJames Liao { 34*cdb2bab7SJames Liao return container_of(hw, struct mtk_ref2usb_tx, hw); 35*cdb2bab7SJames Liao } 36*cdb2bab7SJames Liao 37*cdb2bab7SJames Liao static int mtk_ref2usb_tx_is_prepared(struct clk_hw *hw) 38*cdb2bab7SJames Liao { 39*cdb2bab7SJames Liao struct mtk_ref2usb_tx *tx = to_mtk_ref2usb_tx(hw); 40*cdb2bab7SJames Liao 41*cdb2bab7SJames Liao return (readl(tx->base_addr) & REF2USB_EN_MASK) == REF2USB_EN_MASK; 42*cdb2bab7SJames Liao } 43*cdb2bab7SJames Liao 44*cdb2bab7SJames Liao static int mtk_ref2usb_tx_prepare(struct clk_hw *hw) 45*cdb2bab7SJames Liao { 46*cdb2bab7SJames Liao struct mtk_ref2usb_tx *tx = to_mtk_ref2usb_tx(hw); 47*cdb2bab7SJames Liao u32 val; 48*cdb2bab7SJames Liao 49*cdb2bab7SJames Liao val = readl(tx->base_addr); 50*cdb2bab7SJames Liao 51*cdb2bab7SJames Liao val |= REF2USB_TX_EN; 52*cdb2bab7SJames Liao writel(val, tx->base_addr); 53*cdb2bab7SJames Liao udelay(100); 54*cdb2bab7SJames Liao 55*cdb2bab7SJames Liao val |= REF2USB_TX_LPF_EN; 56*cdb2bab7SJames Liao writel(val, tx->base_addr); 57*cdb2bab7SJames Liao 58*cdb2bab7SJames Liao val |= REF2USB_TX_OUT_EN; 59*cdb2bab7SJames Liao writel(val, tx->base_addr); 60*cdb2bab7SJames Liao 61*cdb2bab7SJames Liao return 0; 62*cdb2bab7SJames Liao } 63*cdb2bab7SJames Liao 64*cdb2bab7SJames Liao static void mtk_ref2usb_tx_unprepare(struct clk_hw *hw) 65*cdb2bab7SJames Liao { 66*cdb2bab7SJames Liao struct mtk_ref2usb_tx *tx = to_mtk_ref2usb_tx(hw); 67*cdb2bab7SJames Liao u32 val; 68*cdb2bab7SJames Liao 69*cdb2bab7SJames Liao val = readl(tx->base_addr); 70*cdb2bab7SJames Liao val &= ~REF2USB_EN_MASK; 71*cdb2bab7SJames Liao writel(val, tx->base_addr); 72*cdb2bab7SJames Liao } 73*cdb2bab7SJames Liao 74*cdb2bab7SJames Liao static const struct clk_ops mtk_ref2usb_tx_ops = { 75*cdb2bab7SJames Liao .is_prepared = mtk_ref2usb_tx_is_prepared, 76*cdb2bab7SJames Liao .prepare = mtk_ref2usb_tx_prepare, 77*cdb2bab7SJames Liao .unprepare = mtk_ref2usb_tx_unprepare, 78*cdb2bab7SJames Liao }; 79*cdb2bab7SJames Liao 80*cdb2bab7SJames Liao struct clk * __init mtk_clk_register_ref2usb_tx(const char *name, 81*cdb2bab7SJames Liao const char *parent_name, void __iomem *reg) 82*cdb2bab7SJames Liao { 83*cdb2bab7SJames Liao struct mtk_ref2usb_tx *tx; 84*cdb2bab7SJames Liao struct clk_init_data init = {}; 85*cdb2bab7SJames Liao struct clk *clk; 86*cdb2bab7SJames Liao 87*cdb2bab7SJames Liao tx = kzalloc(sizeof(*tx), GFP_KERNEL); 88*cdb2bab7SJames Liao if (!tx) 89*cdb2bab7SJames Liao return ERR_PTR(-ENOMEM); 90*cdb2bab7SJames Liao 91*cdb2bab7SJames Liao tx->base_addr = reg; 92*cdb2bab7SJames Liao tx->hw.init = &init; 93*cdb2bab7SJames Liao 94*cdb2bab7SJames Liao init.name = name; 95*cdb2bab7SJames Liao init.ops = &mtk_ref2usb_tx_ops; 96*cdb2bab7SJames Liao init.parent_names = &parent_name; 97*cdb2bab7SJames Liao init.num_parents = 1; 98*cdb2bab7SJames Liao 99*cdb2bab7SJames Liao clk = clk_register(NULL, &tx->hw); 100*cdb2bab7SJames Liao 101*cdb2bab7SJames Liao if (IS_ERR(clk)) { 102*cdb2bab7SJames Liao pr_err("Failed to register clk %s: %ld\n", name, PTR_ERR(clk)); 103*cdb2bab7SJames Liao kfree(tx); 104*cdb2bab7SJames Liao } 105*cdb2bab7SJames Liao 106*cdb2bab7SJames Liao return clk; 107*cdb2bab7SJames Liao } 108