-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[ARM] msm: clock: provide clk_*() api support for
Makes use of the proc_comm interface to provide clock control on MSM7X01A family SoCs. Signed-off-by: Brian Swetland <swetland@google.com>
- Loading branch information
Brian Swetland
committed
Oct 22, 2008
1 parent
bcc0f6a
commit 600f7cf
Showing
6 changed files
with
395 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,7 @@ | ||
obj-y += io.o idle.o irq.o timer.o dma.o | ||
obj-y += devices.o | ||
obj-y += proc_comm.o | ||
obj-y += clock.o clock-7x01a.o | ||
|
||
obj-$(CONFIG_MACH_HALIBUT) += board-halibut.o | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,126 @@ | ||
/* arch/arm/mach-msm/clock-7x01a.c | ||
* | ||
* Clock tables for MSM7X01A | ||
* | ||
* Copyright (C) 2007 Google, Inc. | ||
* Copyright (c) 2007 QUALCOMM Incorporated | ||
* | ||
* This software is licensed under the terms of the GNU General Public | ||
* License version 2, as published by the Free Software Foundation, and | ||
* may be copied, distributed, and modified under those terms. | ||
* | ||
* This program is distributed in the hope that it will be useful, | ||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
* GNU General Public License for more details. | ||
* | ||
*/ | ||
|
||
#include <linux/kernel.h> | ||
#include <linux/platform_device.h> | ||
|
||
#include "clock.h" | ||
#include "devices.h" | ||
|
||
/* clock IDs used by the modem processor */ | ||
|
||
#define ACPU_CLK 0 /* Applications processor clock */ | ||
#define ADM_CLK 1 /* Applications data mover clock */ | ||
#define ADSP_CLK 2 /* ADSP clock */ | ||
#define EBI1_CLK 3 /* External bus interface 1 clock */ | ||
#define EBI2_CLK 4 /* External bus interface 2 clock */ | ||
#define ECODEC_CLK 5 /* External CODEC clock */ | ||
#define EMDH_CLK 6 /* External MDDI host clock */ | ||
#define GP_CLK 7 /* General purpose clock */ | ||
#define GRP_CLK 8 /* Graphics clock */ | ||
#define I2C_CLK 9 /* I2C clock */ | ||
#define ICODEC_RX_CLK 10 /* Internal CODEX RX clock */ | ||
#define ICODEC_TX_CLK 11 /* Internal CODEX TX clock */ | ||
#define IMEM_CLK 12 /* Internal graphics memory clock */ | ||
#define MDC_CLK 13 /* MDDI client clock */ | ||
#define MDP_CLK 14 /* Mobile display processor clock */ | ||
#define PBUS_CLK 15 /* Peripheral bus clock */ | ||
#define PCM_CLK 16 /* PCM clock */ | ||
#define PMDH_CLK 17 /* Primary MDDI host clock */ | ||
#define SDAC_CLK 18 /* Stereo DAC clock */ | ||
#define SDC1_CLK 19 /* Secure Digital Card clocks */ | ||
#define SDC1_PCLK 20 | ||
#define SDC2_CLK 21 | ||
#define SDC2_PCLK 22 | ||
#define SDC3_CLK 23 | ||
#define SDC3_PCLK 24 | ||
#define SDC4_CLK 25 | ||
#define SDC4_PCLK 26 | ||
#define TSIF_CLK 27 /* Transport Stream Interface clocks */ | ||
#define TSIF_REF_CLK 28 | ||
#define TV_DAC_CLK 29 /* TV clocks */ | ||
#define TV_ENC_CLK 30 | ||
#define UART1_CLK 31 /* UART clocks */ | ||
#define UART2_CLK 32 | ||
#define UART3_CLK 33 | ||
#define UART1DM_CLK 34 | ||
#define UART2DM_CLK 35 | ||
#define USB_HS_CLK 36 /* High speed USB core clock */ | ||
#define USB_HS_PCLK 37 /* High speed USB pbus clock */ | ||
#define USB_OTG_CLK 38 /* Full speed USB clock */ | ||
#define VDC_CLK 39 /* Video controller clock */ | ||
#define VFE_CLK 40 /* Camera / Video Front End clock */ | ||
#define VFE_MDC_CLK 41 /* VFE MDDI client clock */ | ||
|
||
#define NR_CLKS 42 | ||
|
||
#define CLOCK(clk_name, clk_id, clk_dev, clk_flags) { \ | ||
.name = clk_name, \ | ||
.id = clk_id, \ | ||
.flags = clk_flags, \ | ||
.dev = clk_dev, \ | ||
} | ||
|
||
#define OFF CLKFLAG_AUTO_OFF | ||
#define MINMAX CLKFLAG_USE_MIN_MAX_TO_SET | ||
|
||
struct clk msm_clocks[] = { | ||
CLOCK("adm_clk", ADM_CLK, NULL, 0), | ||
CLOCK("adsp_clk", ADSP_CLK, NULL, 0), | ||
CLOCK("ebi1_clk", EBI1_CLK, NULL, 0), | ||
CLOCK("ebi2_clk", EBI2_CLK, NULL, 0), | ||
CLOCK("ecodec_clk", ECODEC_CLK, NULL, 0), | ||
CLOCK("emdh_clk", EMDH_CLK, NULL, OFF), | ||
CLOCK("gp_clk", GP_CLK, NULL, 0), | ||
CLOCK("grp_clk", GRP_CLK, NULL, OFF), | ||
CLOCK("i2c_clk", I2C_CLK, &msm_device_i2c.dev, 0), | ||
CLOCK("icodec_rx_clk", ICODEC_RX_CLK, NULL, 0), | ||
CLOCK("icodec_tx_clk", ICODEC_TX_CLK, NULL, 0), | ||
CLOCK("imem_clk", IMEM_CLK, NULL, OFF), | ||
CLOCK("mdc_clk", MDC_CLK, NULL, 0), | ||
CLOCK("mdp_clk", MDP_CLK, NULL, OFF), | ||
CLOCK("pbus_clk", PBUS_CLK, NULL, 0), | ||
CLOCK("pcm_clk", PCM_CLK, NULL, 0), | ||
CLOCK("pmdh_clk", PMDH_CLK, NULL, OFF | MINMAX), | ||
CLOCK("sdac_clk", SDAC_CLK, NULL, OFF), | ||
CLOCK("sdc_clk", SDC1_CLK, &msm_device_sdc1.dev, OFF), | ||
CLOCK("sdc_pclk", SDC1_PCLK, &msm_device_sdc1.dev, OFF), | ||
CLOCK("sdc_clk", SDC2_CLK, &msm_device_sdc2.dev, OFF), | ||
CLOCK("sdc_pclk", SDC2_PCLK, &msm_device_sdc2.dev, OFF), | ||
CLOCK("sdc_clk", SDC3_CLK, &msm_device_sdc3.dev, OFF), | ||
CLOCK("sdc_pclk", SDC3_PCLK, &msm_device_sdc3.dev, OFF), | ||
CLOCK("sdc_clk", SDC4_CLK, &msm_device_sdc4.dev, OFF), | ||
CLOCK("sdc_pclk", SDC4_PCLK, &msm_device_sdc4.dev, OFF), | ||
CLOCK("tsif_clk", TSIF_CLK, NULL, 0), | ||
CLOCK("tsif_ref_clk", TSIF_REF_CLK, NULL, 0), | ||
CLOCK("tv_dac_clk", TV_DAC_CLK, NULL, 0), | ||
CLOCK("tv_enc_clk", TV_ENC_CLK, NULL, 0), | ||
CLOCK("uart_clk", UART1_CLK, &msm_device_uart1.dev, OFF), | ||
CLOCK("uart_clk", UART2_CLK, &msm_device_uart2.dev, 0), | ||
CLOCK("uart_clk", UART3_CLK, &msm_device_uart3.dev, OFF), | ||
CLOCK("uart1dm_clk", UART1DM_CLK, NULL, OFF), | ||
CLOCK("uart2dm_clk", UART2DM_CLK, NULL, 0), | ||
CLOCK("usb_hs_clk", USB_HS_CLK, &msm_device_hsusb.dev, OFF), | ||
CLOCK("usb_hs_pclk", USB_HS_PCLK, &msm_device_hsusb.dev, OFF), | ||
CLOCK("usb_otg_clk", USB_OTG_CLK, NULL, 0), | ||
CLOCK("vdc_clk", VDC_CLK, NULL, OFF | MINMAX), | ||
CLOCK("vfe_clk", VFE_CLK, NULL, OFF), | ||
CLOCK("vfe_mdc_clk", VFE_MDC_CLK, NULL, OFF), | ||
}; | ||
|
||
unsigned msm_num_clocks = ARRAY_SIZE(msm_clocks); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,218 @@ | ||
/* arch/arm/mach-msm/clock.c | ||
* | ||
* Copyright (C) 2007 Google, Inc. | ||
* Copyright (c) 2007 QUALCOMM Incorporated | ||
* | ||
* This software is licensed under the terms of the GNU General Public | ||
* License version 2, as published by the Free Software Foundation, and | ||
* may be copied, distributed, and modified under those terms. | ||
* | ||
* This program is distributed in the hope that it will be useful, | ||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
* GNU General Public License for more details. | ||
* | ||
*/ | ||
|
||
#include <linux/version.h> | ||
#include <linux/kernel.h> | ||
#include <linux/init.h> | ||
#include <linux/module.h> | ||
#include <linux/list.h> | ||
#include <linux/err.h> | ||
#include <linux/clk.h> | ||
#include <linux/spinlock.h> | ||
|
||
#include "clock.h" | ||
#include "proc_comm.h" | ||
|
||
static DEFINE_MUTEX(clocks_mutex); | ||
static DEFINE_SPINLOCK(clocks_lock); | ||
static LIST_HEAD(clocks); | ||
|
||
/* | ||
* glue for the proc_comm interface | ||
*/ | ||
static inline int pc_clk_enable(unsigned id) | ||
{ | ||
return msm_proc_comm(PCOM_CLKCTL_RPC_ENABLE, &id, NULL); | ||
} | ||
|
||
static inline void pc_clk_disable(unsigned id) | ||
{ | ||
msm_proc_comm(PCOM_CLKCTL_RPC_DISABLE, &id, NULL); | ||
} | ||
|
||
static inline int pc_clk_set_rate(unsigned id, unsigned rate) | ||
{ | ||
return msm_proc_comm(PCOM_CLKCTL_RPC_SET_RATE, &id, &rate); | ||
} | ||
|
||
static inline int pc_clk_set_min_rate(unsigned id, unsigned rate) | ||
{ | ||
return msm_proc_comm(PCOM_CLKCTL_RPC_MIN_RATE, &id, &rate); | ||
} | ||
|
||
static inline int pc_clk_set_max_rate(unsigned id, unsigned rate) | ||
{ | ||
return msm_proc_comm(PCOM_CLKCTL_RPC_MAX_RATE, &id, &rate); | ||
} | ||
|
||
static inline int pc_clk_set_flags(unsigned id, unsigned flags) | ||
{ | ||
return msm_proc_comm(PCOM_CLKCTL_RPC_SET_FLAGS, &id, &flags); | ||
} | ||
|
||
static inline unsigned pc_clk_get_rate(unsigned id) | ||
{ | ||
if (msm_proc_comm(PCOM_CLKCTL_RPC_RATE, &id, NULL)) | ||
return 0; | ||
else | ||
return id; | ||
} | ||
|
||
static inline unsigned pc_clk_is_enabled(unsigned id) | ||
{ | ||
if (msm_proc_comm(PCOM_CLKCTL_RPC_ENABLED, &id, NULL)) | ||
return 0; | ||
else | ||
return id; | ||
} | ||
|
||
static inline int pc_pll_request(unsigned id, unsigned on) | ||
{ | ||
on = !!on; | ||
return msm_proc_comm(PCOM_CLKCTL_RPC_PLL_REQUEST, &id, &on); | ||
} | ||
|
||
/* | ||
* Standard clock functions defined in include/linux/clk.h | ||
*/ | ||
struct clk *clk_get(struct device *dev, const char *id) | ||
{ | ||
struct clk *clk; | ||
|
||
mutex_lock(&clocks_mutex); | ||
|
||
list_for_each_entry(clk, &clocks, list) | ||
if (!strcmp(id, clk->name) && clk->dev == dev) | ||
goto found_it; | ||
|
||
list_for_each_entry(clk, &clocks, list) | ||
if (!strcmp(id, clk->name) && clk->dev == NULL) | ||
goto found_it; | ||
|
||
clk = ERR_PTR(-ENOENT); | ||
found_it: | ||
mutex_unlock(&clocks_mutex); | ||
return clk; | ||
} | ||
EXPORT_SYMBOL(clk_get); | ||
|
||
void clk_put(struct clk *clk) | ||
{ | ||
} | ||
EXPORT_SYMBOL(clk_put); | ||
|
||
int clk_enable(struct clk *clk) | ||
{ | ||
unsigned long flags; | ||
spin_lock_irqsave(&clocks_lock, flags); | ||
clk->count++; | ||
if (clk->count == 1) | ||
pc_clk_enable(clk->id); | ||
spin_unlock_irqrestore(&clocks_lock, flags); | ||
return 0; | ||
} | ||
EXPORT_SYMBOL(clk_enable); | ||
|
||
void clk_disable(struct clk *clk) | ||
{ | ||
unsigned long flags; | ||
spin_lock_irqsave(&clocks_lock, flags); | ||
BUG_ON(clk->count == 0); | ||
clk->count--; | ||
if (clk->count == 0) | ||
pc_clk_disable(clk->id); | ||
spin_unlock_irqrestore(&clocks_lock, flags); | ||
} | ||
EXPORT_SYMBOL(clk_disable); | ||
|
||
unsigned long clk_get_rate(struct clk *clk) | ||
{ | ||
return pc_clk_get_rate(clk->id); | ||
} | ||
EXPORT_SYMBOL(clk_get_rate); | ||
|
||
int clk_set_rate(struct clk *clk, unsigned long rate) | ||
{ | ||
int ret; | ||
if (clk->flags & CLKFLAG_USE_MIN_MAX_TO_SET) { | ||
ret = pc_clk_set_max_rate(clk->id, rate); | ||
if (ret) | ||
return ret; | ||
return pc_clk_set_min_rate(clk->id, rate); | ||
} | ||
return pc_clk_set_rate(clk->id, rate); | ||
} | ||
EXPORT_SYMBOL(clk_set_rate); | ||
|
||
int clk_set_parent(struct clk *clk, struct clk *parent) | ||
{ | ||
return -ENOSYS; | ||
} | ||
EXPORT_SYMBOL(clk_set_parent); | ||
|
||
struct clk *clk_get_parent(struct clk *clk) | ||
{ | ||
return ERR_PTR(-ENOSYS); | ||
} | ||
EXPORT_SYMBOL(clk_get_parent); | ||
|
||
int clk_set_flags(struct clk *clk, unsigned long flags) | ||
{ | ||
if (clk == NULL || IS_ERR(clk)) | ||
return -EINVAL; | ||
return pc_clk_set_flags(clk->id, flags); | ||
} | ||
EXPORT_SYMBOL(clk_set_flags); | ||
|
||
|
||
void __init msm_clock_init(void) | ||
{ | ||
unsigned n; | ||
|
||
spin_lock_init(&clocks_lock); | ||
mutex_lock(&clocks_mutex); | ||
for (n = 0; n < msm_num_clocks; n++) | ||
list_add_tail(&msm_clocks[n].list, &clocks); | ||
mutex_unlock(&clocks_mutex); | ||
} | ||
|
||
/* The bootloader and/or AMSS may have left various clocks enabled. | ||
* Disable any clocks that belong to us (CLKFLAG_AUTO_OFF) but have | ||
* not been explicitly enabled by a clk_enable() call. | ||
*/ | ||
static int __init clock_late_init(void) | ||
{ | ||
unsigned long flags; | ||
struct clk *clk; | ||
unsigned count = 0; | ||
|
||
mutex_lock(&clocks_mutex); | ||
list_for_each_entry(clk, &clocks, list) { | ||
if (clk->flags & CLKFLAG_AUTO_OFF) { | ||
spin_lock_irqsave(&clocks_lock, flags); | ||
if (!clk->count) { | ||
count++; | ||
pc_clk_disable(clk->id); | ||
} | ||
spin_unlock_irqrestore(&clocks_lock, flags); | ||
} | ||
} | ||
mutex_unlock(&clocks_mutex); | ||
pr_info("clock_late_init() disabled %d unused clocks\n", count); | ||
return 0; | ||
} | ||
|
||
late_initcall(clock_late_init); |
Oops, something went wrong.