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