mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-08-27 11:19:37 +00:00
[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>
This commit is contained in:
parent
bcc0f6af07
commit
600f7cfebe
6 changed files with 395 additions and 0 deletions
|
@ -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
|
||||
|
||||
|
|
|
@ -79,6 +79,7 @@ static void __init halibut_init(void)
|
|||
static void __init halibut_map_io(void)
|
||||
{
|
||||
msm_map_common_io();
|
||||
msm_clock_init();
|
||||
}
|
||||
|
||||
MACHINE_START(HALIBUT, "Halibut Board (QCT SURF7200A)")
|
||||
|
|
126
arch/arm/mach-msm/clock-7x01a.c
Normal file
126
arch/arm/mach-msm/clock-7x01a.c
Normal file
|
@ -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);
|
218
arch/arm/mach-msm/clock.c
Normal file
218
arch/arm/mach-msm/clock.c
Normal file
|
@ -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);
|
48
arch/arm/mach-msm/clock.h
Normal file
48
arch/arm/mach-msm/clock.h
Normal file
|
@ -0,0 +1,48 @@
|
|||
/* arch/arm/mach-msm/clock.h
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __ARCH_ARM_MACH_MSM_CLOCK_H
|
||||
#define __ARCH_ARM_MACH_MSM_CLOCK_H
|
||||
|
||||
#include <linux/list.h>
|
||||
|
||||
#define CLKFLAG_INVERT 0x00000001
|
||||
#define CLKFLAG_NOINVERT 0x00000002
|
||||
#define CLKFLAG_NONEST 0x00000004
|
||||
#define CLKFLAG_NORESET 0x00000008
|
||||
|
||||
#define CLK_FIRST_AVAILABLE_FLAG 0x00000100
|
||||
#define CLKFLAG_USE_MIN_MAX_TO_SET 0x00000200
|
||||
#define CLKFLAG_AUTO_OFF 0x00000400
|
||||
|
||||
struct clk {
|
||||
uint32_t id;
|
||||
uint32_t count;
|
||||
uint32_t flags;
|
||||
const char *name;
|
||||
struct list_head list;
|
||||
struct device *dev;
|
||||
};
|
||||
|
||||
#define A11S_CLK_CNTL_ADDR (MSM_CSR_BASE + 0x100)
|
||||
#define A11S_CLK_SEL_ADDR (MSM_CSR_BASE + 0x104)
|
||||
#define A11S_VDD_SVS_PLEVEL_ADDR (MSM_CSR_BASE + 0x124)
|
||||
|
||||
extern struct clk msm_clocks[];
|
||||
extern unsigned msm_num_clocks;
|
||||
|
||||
#endif
|
||||
|
|
@ -33,5 +33,6 @@ void __init msm_add_devices(void);
|
|||
void __init msm_map_common_io(void);
|
||||
void __init msm_init_irq(void);
|
||||
void __init msm_init_gpio(void);
|
||||
void __init msm_clock_init(void);
|
||||
|
||||
#endif
|
||||
|
|
Loading…
Reference in a new issue