2 * Copyright (C) 2007 Google, Inc.
3 * Copyright (c) 2007-2012, The Linux Foundation. All rights reserved.
5 * This software is licensed under the terms of the GNU General Public
6 * License version 2, as published by the Free Software Foundation, and
7 * may be copied, distributed, and modified under those terms.
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.
16 #include <linux/kernel.h>
17 #include <linux/err.h>
18 #include <linux/platform_device.h>
19 #include <linux/module.h>
20 #include <linux/clk-provider.h>
21 #include <linux/clkdev.h>
25 #include "proc_comm.h"
27 #include "clock-pcom.h"
32 struct msm_clk msm_clk
;
35 static inline struct clk_pcom
*to_clk_pcom(struct clk_hw
*hw
)
37 return container_of(to_msm_clk(hw
), struct clk_pcom
, msm_clk
);
40 static int pc_clk_enable(struct clk_hw
*hw
)
42 unsigned id
= to_clk_pcom(hw
)->id
;
43 int rc
= msm_proc_comm(PCOM_CLKCTL_RPC_ENABLE
, &id
, NULL
);
47 return (int)id
< 0 ? -EINVAL
: 0;
50 static void pc_clk_disable(struct clk_hw
*hw
)
52 unsigned id
= to_clk_pcom(hw
)->id
;
53 msm_proc_comm(PCOM_CLKCTL_RPC_DISABLE
, &id
, NULL
);
56 static int pc_clk_reset(struct clk_hw
*hw
, enum clk_reset_action action
)
59 unsigned id
= to_clk_pcom(hw
)->id
;
61 if (action
== CLK_RESET_ASSERT
)
62 rc
= msm_proc_comm(PCOM_CLKCTL_RPC_RESET_ASSERT
, &id
, NULL
);
64 rc
= msm_proc_comm(PCOM_CLKCTL_RPC_RESET_DEASSERT
, &id
, NULL
);
69 return (int)id
< 0 ? -EINVAL
: 0;
72 static int pc_clk_set_rate(struct clk_hw
*hw
, unsigned long new_rate
,
75 struct clk_pcom
*p
= to_clk_pcom(hw
);
76 unsigned id
= p
->id
, rate
= new_rate
;
80 * The rate _might_ be rounded off to the nearest KHz value by the
81 * remote function. So a return value of 0 doesn't necessarily mean
82 * that the exact rate was set successfully.
84 if (p
->flags
& CLKFLAG_MIN
)
85 rc
= msm_proc_comm(PCOM_CLKCTL_RPC_MIN_RATE
, &id
, &rate
);
87 rc
= msm_proc_comm(PCOM_CLKCTL_RPC_SET_RATE
, &id
, &rate
);
91 return (int)id
< 0 ? -EINVAL
: 0;
94 static unsigned long pc_clk_recalc_rate(struct clk_hw
*hw
, unsigned long p_rate
)
96 unsigned id
= to_clk_pcom(hw
)->id
;
97 if (msm_proc_comm(PCOM_CLKCTL_RPC_RATE
, &id
, NULL
))
103 static int pc_clk_is_enabled(struct clk_hw
*hw
)
105 unsigned id
= to_clk_pcom(hw
)->id
;
106 if (msm_proc_comm(PCOM_CLKCTL_RPC_ENABLED
, &id
, NULL
))
112 static long pc_clk_round_rate(struct clk_hw
*hw
, unsigned long rate
,
113 unsigned long *p_rate
)
115 /* Not really supported; pc_clk_set_rate() does rounding on it's own. */
119 static struct clk_ops clk_ops_pcom
= {
120 .enable
= pc_clk_enable
,
121 .disable
= pc_clk_disable
,
122 .set_rate
= pc_clk_set_rate
,
123 .recalc_rate
= pc_clk_recalc_rate
,
124 .is_enabled
= pc_clk_is_enabled
,
125 .round_rate
= pc_clk_round_rate
,
128 static int msm_clock_pcom_probe(struct platform_device
*pdev
)
130 const struct pcom_clk_pdata
*pdata
= pdev
->dev
.platform_data
;
133 for (i
= 0; i
< pdata
->num_lookups
; i
++) {
134 const struct clk_pcom_desc
*desc
= &pdata
->lookup
[i
];
138 struct clk_init_data init
;
140 p
= devm_kzalloc(&pdev
->dev
, sizeof(*p
), GFP_KERNEL
);
145 p
->flags
= desc
->flags
;
146 p
->msm_clk
.reset
= pc_clk_reset
;
151 init
.name
= desc
->name
;
152 init
.ops
= &clk_ops_pcom
;
153 init
.num_parents
= 0;
154 init
.flags
= CLK_IS_ROOT
;
156 if (!(p
->flags
& CLKFLAG_AUTO_OFF
))
157 init
.flags
|= CLK_IGNORE_UNUSED
;
159 c
= devm_clk_register(&pdev
->dev
, hw
);
160 ret
= clk_register_clkdev(c
, desc
->con
, desc
->dev
);
168 static struct platform_driver msm_clock_pcom_driver
= {
169 .probe
= msm_clock_pcom_probe
,
171 .name
= "msm-clock-pcom",
172 .owner
= THIS_MODULE
,
175 module_platform_driver(msm_clock_pcom_driver
);
177 MODULE_LICENSE("GPL v2");