xref: /linux/drivers/clk/mediatek/clk-apmixed.c (revision cdb2bab78aff97101da767b9643fbd692af4623b)
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