diff options
author | Olof Johansson <olof@lixom.net> | 2013-06-27 17:04:27 -0700 |
---|---|---|
committer | Olof Johansson <olof@lixom.net> | 2013-06-27 17:04:27 -0700 |
commit | 8c3d913888cfb0066d62831969c3a992f7e4aba5 (patch) | |
tree | 0b52b0b71cb6b7c141ffa050b36245a13cff4f54 | |
parent | fbd1a04b210d56ef84200df56fc0291746d4d4dc (diff) | |
parent | 8cc7f5338e729b79194e6c22e3c794faaef974b8 (diff) |
Merge tag 'msm-clock-for-3.11b' of git://git.kernel.org/pub/scm/linux/kernel/git/davidb/linux-msm into next/late
From David Brown:
MSM clock updates for 3.11.
Per Stephen Boyd's coverletter:
Resending to collect higher level maintainer acks per Olof's request.
The plan is to push this patchset through MSM to the arm-soc tree.
This patchset moves the existing MSM clock code and affected drivers
to the common clock framework. A prerequisite of moving to the common
clock framework is to use clk_prepare() and clk_enable() so the first
few patches migrate drivers to that call (clk_prepare() is a no-op on
MSM right now). It also removes some custom clock APIs that MSM
provides and finally moves the proc_comm clock code to the common
struct clk.
This patch series will be used as the foundation of the MSM 8660/8960
clock code that I plan to send out after this series.
* tag 'msm-clock-for-3.11b' of git://git.kernel.org/pub/scm/linux/kernel/git/davidb/linux-msm:
ARM: msm: Migrate to common clock framework
ARM: msm: Make proc_comm clock control into a platform driver
ARM: msm: Prepare clk_get() users in mach-msm for clock-pcom driver
ARM: msm: Remove clock-7x30.h include file
ARM: msm: Remove custom clk_set_{max,min}_rate() API
ARM: msm: Remove custom clk_set_flags() API
msm: iommu: Use clk_set_rate() instead of clk_set_min_rate()
msm: iommu: Convert to clk_prepare/unprepare
msm_sdcc: Convert to clk_prepare/unprepare
usb: otg: msm: Convert to clk_prepare/unprepare
msm_serial: Use devm_clk_get() and properly return errors
msm_serial: Convert to clk_prepare/unprepare
Acked-by: Chris Ball <cjb@laptop.org> # for msm_sdcc.c
Signed-off-by: Olof Johansson <olof@lixom.net>
24 files changed, 243 insertions, 659 deletions
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 9fbdc10fe835..45230dec9ebf 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -623,8 +623,8 @@ config ARCH_MSM bool "Qualcomm MSM" select ARCH_REQUIRE_GPIOLIB select CLKDEV_LOOKUP + select COMMON_CLK select GENERIC_CLOCKEVENTS - select HAVE_CLK help Support for Qualcomm MSM/QSD based systems. This runs on the apps processor of the MSM/QSD and depends on a shared memory diff --git a/arch/arm/mach-msm/Makefile b/arch/arm/mach-msm/Makefile index 17519faf082f..700d77b7eb1a 100644 --- a/arch/arm/mach-msm/Makefile +++ b/arch/arm/mach-msm/Makefile @@ -1,16 +1,18 @@ obj-y += io.o timer.o obj-y += clock.o -obj-$(CONFIG_DEBUG_FS) += clock-debug.o obj-$(CONFIG_MSM_VIC) += irq-vic.o obj-$(CONFIG_MSM_IOMMU) += devices-iommu.o -obj-$(CONFIG_ARCH_MSM7X00A) += dma.o irq.o -obj-$(CONFIG_ARCH_MSM7X30) += dma.o -obj-$(CONFIG_ARCH_QSD8X50) += dma.o sirc.o +obj-$(CONFIG_ARCH_MSM7X00A) += irq.o +obj-$(CONFIG_ARCH_QSD8X50) += sirc.o obj-$(CONFIG_MSM_PROC_COMM) += proc_comm.o clock-pcom.o vreg.o +obj-$(CONFIG_ARCH_MSM7X00A) += dma.o +obj-$(CONFIG_ARCH_MSM7X30) += dma.o +obj-$(CONFIG_ARCH_QSD8X50) += dma.o + obj-$(CONFIG_MSM_SMD) += smd.o smd_debug.o obj-$(CONFIG_MSM_SMD) += last_radio_log.o obj-$(CONFIG_MSM_SCM) += scm.o scm-boot.o diff --git a/arch/arm/mach-msm/board-halibut.c b/arch/arm/mach-msm/board-halibut.c index 82eaf88d2026..803651ad4f62 100644 --- a/arch/arm/mach-msm/board-halibut.c +++ b/arch/arm/mach-msm/board-halibut.c @@ -59,6 +59,7 @@ static struct platform_device smc91x_device = { }; static struct platform_device *devices[] __initdata = { + &msm_clock_7x01a, &msm_device_gpio_7201, &msm_device_uart3, &msm_device_smd, @@ -91,7 +92,6 @@ static void __init halibut_fixup(struct tag *tags, char **cmdline, static void __init halibut_map_io(void) { msm_map_common_io(); - msm_clock_init(msm_clocks_7x01a, msm_num_clocks_7x01a); } static void __init halibut_init_late(void) diff --git a/arch/arm/mach-msm/board-msm7x30.c b/arch/arm/mach-msm/board-msm7x30.c index 520c141acd03..db3d8c0bc8a4 100644 --- a/arch/arm/mach-msm/board-msm7x30.c +++ b/arch/arm/mach-msm/board-msm7x30.c @@ -89,6 +89,7 @@ struct msm_gpiomux_config msm_gpiomux_configs[GPIOMUX_NGPIOS] = { }; static struct platform_device *devices[] __initdata = { + &msm_clock_7x30, &msm_device_gpio_7x30, #if defined(CONFIG_SERIAL_MSM) || defined(CONFIG_MSM_SERIAL_DEBUGGER) &msm_device_uart2, @@ -116,7 +117,6 @@ static void __init msm7x30_init(void) static void __init msm7x30_map_io(void) { msm_map_msm7x30_io(); - msm_clock_init(msm_clocks_7x30, msm_num_clocks_7x30); } static void __init msm7x30_init_late(void) diff --git a/arch/arm/mach-msm/board-qsd8x50.c b/arch/arm/mach-msm/board-qsd8x50.c index 38a532d6937c..f14a73d86bc0 100644 --- a/arch/arm/mach-msm/board-qsd8x50.c +++ b/arch/arm/mach-msm/board-qsd8x50.c @@ -89,6 +89,7 @@ static struct msm_otg_platform_data msm_otg_pdata = { }; static struct platform_device *devices[] __initdata = { + &msm_clock_8x50, &msm_device_gpio_8x50, &msm_device_uart3, &msm_device_smd, @@ -172,7 +173,6 @@ static void __init qsd8x50_init_mmc(void) static void __init qsd8x50_map_io(void) { msm_map_qsd8x50_io(); - msm_clock_init(msm_clocks_8x50, msm_num_clocks_8x50); } static void __init qsd8x50_init_irq(void) diff --git a/arch/arm/mach-msm/board-trout-panel.c b/arch/arm/mach-msm/board-trout-panel.c index f9a5db6d2ced..77b0a26f897f 100644 --- a/arch/arm/mach-msm/board-trout-panel.c +++ b/arch/arm/mach-msm/board-trout-panel.c @@ -7,7 +7,6 @@ #include <linux/platform_device.h> #include <linux/delay.h> #include <linux/leds.h> -#include <linux/clk.h> #include <linux/err.h> #include <asm/io.h> @@ -19,6 +18,7 @@ #include "board-trout.h" #include "proc_comm.h" +#include "clock-pcom.h" #include "devices.h" #define TROUT_DEFAULT_BACKLIGHT_BRIGHTNESS 255 @@ -170,7 +170,6 @@ static struct mddi_table mddi_toshiba_init_table[] = { #define INTMASK_VWAKEOUT (1U << 0) -static struct clk *gp_clk; static int trout_new_backlight = 1; static struct vreg *vreg_mddi_1v5; static struct vreg *vreg_lcm_2v85; @@ -273,18 +272,14 @@ int __init trout_init_panel(void) } else { uint32_t config = PCOM_GPIO_CFG(27, 1, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_8MA); + uint32_t id = P_GP_CLK; + uint32_t rate = 19200000; + msm_proc_comm(PCOM_RPC_GPIO_TLMM_CONFIG_EX, &config, 0); - gp_clk = clk_get(NULL, "gp_clk"); - if (IS_ERR(gp_clk)) { - printk(KERN_ERR "trout_init_panel: could not get gp" - "clock\n"); - gp_clk = NULL; - } - rc = clk_set_rate(gp_clk, 19200000); - if (rc) - printk(KERN_ERR "trout_init_panel: set clock rate " - "failed\n"); + msm_proc_comm(PCOM_CLKCTL_RPC_SET_RATE, &id, &rate); + if (id < 0) + pr_err("trout_init_panel: set clock rate failed\n"); } rc = platform_device_register(&msm_device_mdp); diff --git a/arch/arm/mach-msm/board-trout.c b/arch/arm/mach-msm/board-trout.c index 80fe1c5ff5c1..64a46eb4fc49 100644 --- a/arch/arm/mach-msm/board-trout.c +++ b/arch/arm/mach-msm/board-trout.c @@ -36,6 +36,7 @@ extern int trout_init_mmc(unsigned int); static struct platform_device *devices[] __initdata = { + &msm_clock_7x01a, &msm_device_gpio_7201, &msm_device_uart3, &msm_device_smd, @@ -94,8 +95,6 @@ static void __init trout_map_io(void) /* route UART3 to the "H2W" extended usb connector */ writeb(0x80, TROUT_CPLD_BASE + 0x00); #endif - - msm_clock_init(msm_clocks_7x01a, msm_num_clocks_7x01a); } static void __init trout_init_late(void) diff --git a/arch/arm/mach-msm/clock-7x30.h b/arch/arm/mach-msm/clock-7x30.h deleted file mode 100644 index 14104453688b..000000000000 --- a/arch/arm/mach-msm/clock-7x30.h +++ /dev/null @@ -1,155 +0,0 @@ -/* Copyright (c) 2009, Code Aurora Forum. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 and - * only version 2 as published by the Free Software Foundation. - * - * 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_7X30_H -#define __ARCH_ARM_MACH_MSM_CLOCK_7X30_H - -enum { - L_7X30_NONE_CLK = -1, - L_7X30_ADM_CLK, - L_7X30_I2C_CLK, - L_7X30_I2C_2_CLK, - L_7X30_QUP_I2C_CLK, - L_7X30_UART1DM_CLK, - L_7X30_UART1DM_P_CLK, - L_7X30_UART2DM_CLK, - L_7X30_UART2DM_P_CLK, - L_7X30_EMDH_CLK, - L_7X30_EMDH_P_CLK, - L_7X30_PMDH_CLK, - L_7X30_PMDH_P_CLK, - L_7X30_GRP_2D_CLK, - L_7X30_GRP_2D_P_CLK, - L_7X30_GRP_3D_SRC_CLK, - L_7X30_GRP_3D_CLK, - L_7X30_GRP_3D_P_CLK, - L_7X30_IMEM_CLK, - L_7X30_SDC1_CLK, - L_7X30_SDC1_P_CLK, - L_7X30_SDC2_CLK, - L_7X30_SDC2_P_CLK, - L_7X30_SDC3_CLK, - L_7X30_SDC3_P_CLK, - L_7X30_SDC4_CLK, - L_7X30_SDC4_P_CLK, - L_7X30_MDP_CLK, - L_7X30_MDP_P_CLK, - L_7X30_MDP_LCDC_PCLK_CLK, - L_7X30_MDP_LCDC_PAD_PCLK_CLK, - L_7X30_MDP_VSYNC_CLK, - L_7X30_MI2S_CODEC_RX_M_CLK, - L_7X30_MI2S_CODEC_RX_S_CLK, - L_7X30_MI2S_CODEC_TX_M_CLK, - L_7X30_MI2S_CODEC_TX_S_CLK, - L_7X30_MI2S_M_CLK, - L_7X30_MI2S_S_CLK, - L_7X30_LPA_CODEC_CLK, - L_7X30_LPA_CORE_CLK, - L_7X30_LPA_P_CLK, - L_7X30_MIDI_CLK, - L_7X30_MDC_CLK, - L_7X30_ROTATOR_IMEM_CLK, - L_7X30_ROTATOR_P_CLK, - L_7X30_SDAC_M_CLK, - L_7X30_SDAC_CLK, - L_7X30_UART1_CLK, - L_7X30_UART2_CLK, - L_7X30_UART3_CLK, - L_7X30_TV_CLK, - L_7X30_TV_DAC_CLK, - L_7X30_TV_ENC_CLK, - L_7X30_HDMI_CLK, - L_7X30_TSIF_REF_CLK, - L_7X30_TSIF_P_CLK, - L_7X30_USB_HS_SRC_CLK, - L_7X30_USB_HS_CLK, - L_7X30_USB_HS_CORE_CLK, - L_7X30_USB_HS_P_CLK, - L_7X30_USB_HS2_CLK, - L_7X30_USB_HS2_CORE_CLK, - L_7X30_USB_HS2_P_CLK, - L_7X30_USB_HS3_CLK, - L_7X30_USB_HS3_CORE_CLK, - L_7X30_USB_HS3_P_CLK, - L_7X30_VFE_CLK, - L_7X30_VFE_P_CLK, - L_7X30_VFE_MDC_CLK, - L_7X30_VFE_CAMIF_CLK, - L_7X30_CAMIF_PAD_P_CLK, - L_7X30_CAM_M_CLK, - L_7X30_JPEG_CLK, - L_7X30_JPEG_P_CLK, - L_7X30_VPE_CLK, - L_7X30_MFC_CLK, - L_7X30_MFC_DIV2_CLK, - L_7X30_MFC_P_CLK, - L_7X30_SPI_CLK, - L_7X30_SPI_P_CLK, - L_7X30_CSI0_CLK, - L_7X30_CSI0_VFE_CLK, - L_7X30_CSI0_P_CLK, - L_7X30_CSI1_CLK, - L_7X30_CSI1_VFE_CLK, - L_7X30_CSI1_P_CLK, - L_7X30_GLBL_ROOT_CLK, - - L_7X30_AXI_LI_VG_CLK, - L_7X30_AXI_LI_GRP_CLK, - L_7X30_AXI_LI_JPEG_CLK, - L_7X30_AXI_GRP_2D_CLK, - L_7X30_AXI_MFC_CLK, - L_7X30_AXI_VPE_CLK, - L_7X30_AXI_LI_VFE_CLK, - L_7X30_AXI_LI_APPS_CLK, - L_7X30_AXI_MDP_CLK, - L_7X30_AXI_IMEM_CLK, - L_7X30_AXI_LI_ADSP_A_CLK, - L_7X30_AXI_ROTATOR_CLK, - - L_7X30_NR_CLKS -}; - -struct clk_ops; -extern struct clk_ops clk_ops_7x30; - -struct clk_ops *clk_7x30_is_local(uint32_t id); -int clk_7x30_init(void); - -void pll_enable(uint32_t pll); -void pll_disable(uint32_t pll); - -extern int internal_pwr_rail_ctl_auto(unsigned rail_id, bool enable); - -#define CLK_7X30(clk_name, clk_id, clk_dev, clk_flags) { \ - .con_id = clk_name, \ - .dev_id = clk_dev, \ - .clk = &(struct clk){ \ - .id = L_7X30_##clk_id, \ - .remote_id = P_##clk_id, \ - .flags = clk_flags, \ - .dbg_name = #clk_id, \ - }, \ - } - -#define CLK_7X30S(clk_name, l_id, r_id, clk_dev, clk_flags) { \ - .con_id = clk_name, \ - .dev_id = clk_dev, \ - .clk = &(struct clk){ \ - .id = L_7X30_##l_id, \ - .remote_id = P_##r_id, \ - .flags = clk_flags, \ - .dbg_name = #l_id, \ - .ops = &clk_ops_pcom, \ - }, \ - } - -#endif diff --git a/arch/arm/mach-msm/clock-debug.c b/arch/arm/mach-msm/clock-debug.c deleted file mode 100644 index b0fbdf1cbdd1..000000000000 --- a/arch/arm/mach-msm/clock-debug.c +++ /dev/null @@ -1,130 +0,0 @@ -/* - * Copyright (C) 2007 Google, Inc. - * Copyright (c) 2007-2010, Code Aurora Forum. All rights reserved. - * - * 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/module.h> -#include <linux/ctype.h> -#include <linux/debugfs.h> -#include <linux/clk.h> -#include "clock.h" - -static int clock_debug_rate_set(void *data, u64 val) -{ - struct clk *clock = data; - int ret; - - /* Only increases to max rate will succeed, but that's actually good - * for debugging purposes so we don't check for error. */ - if (clock->flags & CLK_MAX) - clk_set_max_rate(clock, val); - if (clock->flags & CLK_MIN) - ret = clk_set_min_rate(clock, val); - else - ret = clk_set_rate(clock, val); - if (ret != 0) - printk(KERN_ERR "clk_set%s_rate failed (%d)\n", - (clock->flags & CLK_MIN) ? "_min" : "", ret); - return ret; -} - -static int clock_debug_rate_get(void *data, u64 *val) -{ - struct clk *clock = data; - *val = clk_get_rate(clock); - return 0; -} - -DEFINE_SIMPLE_ATTRIBUTE(clock_rate_fops, clock_debug_rate_get, - clock_debug_rate_set, "%llu\n"); - -static int clock_debug_enable_set(void *data, u64 val) -{ - struct clk *clock = data; - int rc = 0; - - if (val) - rc = clock->ops->enable(clock->id); - else - clock->ops->disable(clock->id); - - return rc; -} - -static int clock_debug_enable_get(void *data, u64 *val) -{ - struct clk *clock = data; - - *val = clock->ops->is_enabled(clock->id); - - return 0; -} - -DEFINE_SIMPLE_ATTRIBUTE(clock_enable_fops, clock_debug_enable_get, - clock_debug_enable_set, "%llu\n"); - -static int clock_debug_local_get(void *data, u64 *val) -{ - struct clk *clock = data; - - *val = clock->ops->is_local(clock->id); - - return 0; -} - -DEFINE_SIMPLE_ATTRIBUTE(clock_local_fops, clock_debug_local_get, - NULL, "%llu\n"); - -static struct dentry *debugfs_base; - -int __init clock_debug_init(void) -{ - debugfs_base = debugfs_create_dir("clk", NULL); - if (!debugfs_base) - return -ENOMEM; - return 0; -} - -int __init clock_debug_add(struct clk *clock) -{ - char temp[50], *ptr; - struct dentry *clk_dir; - - if (!debugfs_base) - return -ENOMEM; - - strlcpy(temp, clock->dbg_name, ARRAY_SIZE(temp)); - for (ptr = temp; *ptr; ptr++) - *ptr = tolower(*ptr); - - clk_dir = debugfs_create_dir(temp, debugfs_base); - if (!clk_dir) - return -ENOMEM; - - if (!debugfs_create_file("rate", S_IRUGO | S_IWUSR, clk_dir, - clock, &clock_rate_fops)) - goto error; - - if (!debugfs_create_file("enable", S_IRUGO | S_IWUSR, clk_dir, - clock, &clock_enable_fops)) - goto error; - - if (!debugfs_create_file("is_local", S_IRUGO, clk_dir, clock, - &clock_local_fops)) - goto error; - return 0; -error: - debugfs_remove_recursive(clk_dir); - return -ENOMEM; -} diff --git a/arch/arm/mach-msm/clock-pcom.c b/arch/arm/mach-msm/clock-pcom.c index a52c970df157..9a80449518e6 100644 --- a/arch/arm/mach-msm/clock-pcom.c +++ b/arch/arm/mach-msm/clock-pcom.c @@ -1,6 +1,6 @@ /* * Copyright (C) 2007 Google, Inc. - * Copyright (c) 2007-2010, Code Aurora Forum. All rights reserved. + * Copyright (c) 2007-2012, The Linux Foundation. All rights reserved. * * This software is licensed under the terms of the GNU General Public * License version 2, as published by the Free Software Foundation, and @@ -13,20 +13,33 @@ * */ +#include <linux/kernel.h> #include <linux/err.h> -#include <linux/ctype.h> -#include <linux/stddef.h> +#include <linux/platform_device.h> +#include <linux/module.h> +#include <linux/clk-provider.h> +#include <linux/clkdev.h> + #include <mach/clk.h> #include "proc_comm.h" #include "clock.h" #include "clock-pcom.h" -/* - * glue for the proc_comm interface - */ -static int pc_clk_enable(unsigned id) +struct clk_pcom { + unsigned id; + unsigned long flags; + struct msm_clk msm_clk; +}; + +static inline struct clk_pcom *to_clk_pcom(struct clk_hw *hw) { + return container_of(to_msm_clk(hw), struct clk_pcom, msm_clk); +} + +static int pc_clk_enable(struct clk_hw *hw) +{ + unsigned id = to_clk_pcom(hw)->id; int rc = msm_proc_comm(PCOM_CLKCTL_RPC_ENABLE, &id, NULL); if (rc < 0) return rc; @@ -34,14 +47,16 @@ static int pc_clk_enable(unsigned id) return (int)id < 0 ? -EINVAL : 0; } -static void pc_clk_disable(unsigned id) +static void pc_clk_disable(struct clk_hw *hw) { + unsigned id = to_clk_pcom(hw)->id; msm_proc_comm(PCOM_CLKCTL_RPC_DISABLE, &id, NULL); } -int pc_clk_reset(unsigned id, enum clk_reset_action action) +static int pc_clk_reset(struct clk_hw *hw, enum clk_reset_action action) { int rc; + unsigned id = to_clk_pcom(hw)->id; if (action == CLK_RESET_ASSERT) rc = msm_proc_comm(PCOM_CLKCTL_RPC_RESET_ASSERT, &id, NULL); @@ -54,85 +69,109 @@ int pc_clk_reset(unsigned id, enum clk_reset_action action) return (int)id < 0 ? -EINVAL : 0; } -static int pc_clk_set_rate(unsigned id, unsigned rate) +static int pc_clk_set_rate(struct clk_hw *hw, unsigned long new_rate, + unsigned long p_rate) { - /* The rate _might_ be rounded off to the nearest KHz value by the + struct clk_pcom *p = to_clk_pcom(hw); + unsigned id = p->id, rate = new_rate; + int rc; + + /* + * The rate _might_ be rounded off to the nearest KHz value by the * remote function. So a return value of 0 doesn't necessarily mean * that the exact rate was set successfully. */ - int rc = msm_proc_comm(PCOM_CLKCTL_RPC_SET_RATE, &id, &rate); - if (rc < 0) - return rc; - else - return (int)id < 0 ? -EINVAL : 0; -} - -static int pc_clk_set_min_rate(unsigned id, unsigned rate) -{ - int rc = msm_proc_comm(PCOM_CLKCTL_RPC_MIN_RATE, &id, &rate); - if (rc < 0) - return rc; - else - return (int)id < 0 ? -EINVAL : 0; -} - -static int pc_clk_set_max_rate(unsigned id, unsigned rate) -{ - int rc = msm_proc_comm(PCOM_CLKCTL_RPC_MAX_RATE, &id, &rate); - if (rc < 0) - return rc; + if (p->flags & CLKFLAG_MIN) + rc = msm_proc_comm(PCOM_CLKCTL_RPC_MIN_RATE, &id, &rate); else - return (int)id < 0 ? -EINVAL : 0; -} - -static int pc_clk_set_flags(unsigned id, unsigned flags) -{ - int rc = msm_proc_comm(PCOM_CLKCTL_RPC_SET_FLAGS, &id, &flags); + rc = msm_proc_comm(PCOM_CLKCTL_RPC_SET_RATE, &id, &rate); if (rc < 0) return rc; else return (int)id < 0 ? -EINVAL : 0; } -static unsigned pc_clk_get_rate(unsigned id) +static unsigned long pc_clk_recalc_rate(struct clk_hw *hw, unsigned long p_rate) { + unsigned id = to_clk_pcom(hw)->id; if (msm_proc_comm(PCOM_CLKCTL_RPC_RATE, &id, NULL)) return 0; else return id; } -static unsigned pc_clk_is_enabled(unsigned id) +static int pc_clk_is_enabled(struct clk_hw *hw) { + unsigned id = to_clk_pcom(hw)->id; if (msm_proc_comm(PCOM_CLKCTL_RPC_ENABLED, &id, NULL)) return 0; else return id; } -static long pc_clk_round_rate(unsigned id, unsigned rate) +static long pc_clk_round_rate(struct clk_hw *hw, unsigned long rate, + unsigned long *p_rate) { - /* Not really supported; pc_clk_set_rate() does rounding on it's own. */ return rate; } -static bool pc_clk_is_local(unsigned id) -{ - return false; -} - -struct clk_ops clk_ops_pcom = { +static struct clk_ops clk_ops_pcom = { .enable = pc_clk_enable, .disable = pc_clk_disable, - .auto_off = pc_clk_disable, - .reset = pc_clk_reset, .set_rate = pc_clk_set_rate, - .set_min_rate = pc_clk_set_min_rate, - .set_max_rate = pc_clk_set_max_rate, - .set_flags = pc_clk_set_flags, - .get_rate = pc_clk_get_rate, + .recalc_rate = pc_clk_recalc_rate, .is_enabled = pc_clk_is_enabled, .round_rate = pc_clk_round_rate, - .is_local = pc_clk_is_local, }; + +static int msm_clock_pcom_probe(struct platform_device *pdev) +{ + const struct pcom_clk_pdata *pdata = pdev->dev.platform_data; + int i, ret; + + for (i = 0; i < pdata->num_lookups; i++) { + const struct clk_pcom_desc *desc = &pdata->lookup[i]; + struct clk *c; + struct clk_pcom *p; + struct clk_hw *hw; + struct clk_init_data init; + + p = devm_kzalloc(&pdev->dev, sizeof(*p), GFP_KERNEL); + if (!p) + return -ENOMEM; + + p->id = desc->id; + p->flags = desc->flags; + p->msm_clk.reset = pc_clk_reset; + + hw = &p->msm_clk.hw; + hw->init = &init; + + init.name = desc->name; + init.ops = &clk_ops_pcom; + init.num_parents = 0; + init.flags = CLK_IS_ROOT; + + if (!(p->flags & CLKFLAG_AUTO_OFF)) + init.flags |= CLK_IGNORE_UNUSED; + + c = devm_clk_register(&pdev->dev, hw); + ret = clk_register_clkdev(c, desc->con, desc->dev); + if (ret) + return ret; + } + + return 0; +} + +static struct platform_driver msm_clock_pcom_driver = { + .probe = msm_clock_pcom_probe, + .driver = { + .name = "msm-clock-pcom", + .owner = THIS_MODULE, + }, +}; +module_platform_driver(msm_clock_pcom_driver); + +MODULE_LICENSE("GPL v2"); diff --git a/arch/arm/mach-msm/clock-pcom.h b/arch/arm/mach-msm/clock-pcom.h index 974d0032f3a3..5bb164fd46a8 100644 --- a/arch/arm/mach-msm/clock-pcom.h +++ b/arch/arm/mach-msm/clock-pcom.h @@ -1,4 +1,5 @@ -/* Copyright (c) 2009, Code Aurora Forum. All rights reserved. +/* + * Copyright (c) 2009-2012, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -120,21 +121,25 @@ #define P_NR_CLKS 102 -struct clk_ops; -extern struct clk_ops clk_ops_pcom; +struct clk_pcom_desc { + unsigned id; + const char *name; + const char *con; + const char *dev; + unsigned long flags; +}; -int pc_clk_reset(unsigned id, enum clk_reset_action action); +struct pcom_clk_pdata { + struct clk_pcom_desc *lookup; + u32 num_lookups; +}; #define CLK_PCOM(clk_name, clk_id, clk_dev, clk_flags) { \ - .con_id = clk_name, \ - .dev_id = clk_dev, \ - .clk = &(struct clk){ \ - .id = P_##clk_id, \ - .remote_id = P_##clk_id, \ - .ops = &clk_ops_pcom, \ - .flags = clk_flags, \ - .dbg_name = #clk_id, \ - }, \ + .id = P_##clk_id, \ + .name = #clk_id, \ + .con = clk_name, \ + .dev = clk_dev, \ + .flags = clk_flags, \ } #endif diff --git a/arch/arm/mach-msm/clock.c b/arch/arm/mach-msm/clock.c index d9145dfc2a3b..35ea02b52483 100644 --- a/arch/arm/mach-msm/clock.c +++ b/arch/arm/mach-msm/clock.c @@ -1,7 +1,7 @@ /* arch/arm/mach-msm/clock.c * * Copyright (C) 2007 Google, Inc. - * Copyright (c) 2007-2010, Code Aurora Forum. All rights reserved. + * Copyright (c) 2007-2012, The Linux Foundation. All rights reserved. * * This software is licensed under the terms of the GNU General Public * License version 2, as published by the Free Software Foundation, and @@ -14,171 +14,15 @@ * */ -#include <linux/kernel.h> -#include <linux/list.h> -#include <linux/err.h> -#include <linux/spinlock.h> -#include <linux/pm_qos.h> -#include <linux/mutex.h> -#include <linux/clk.h> -#include <linux/string.h> +#include <linux/clk-provider.h> #include <linux/module.h> -#include <linux/clkdev.h> #include "clock.h" -static DEFINE_MUTEX(clocks_mutex); -static DEFINE_SPINLOCK(clocks_lock); -static LIST_HEAD(clocks); - -/* - * Standard clock functions defined in include/linux/clk.h - */ -int clk_enable(struct clk *clk) -{ - unsigned long flags; - spin_lock_irqsave(&clocks_lock, flags); - clk->count++; - if (clk->count == 1) - clk->ops->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) - clk->ops->disable(clk->id); - spin_unlock_irqrestore(&clocks_lock, flags); -} -EXPORT_SYMBOL(clk_disable); - int clk_reset(struct clk *clk, enum clk_reset_action action) { - return clk->ops->reset(clk->remote_id, action); + struct clk_hw *hw = __clk_get_hw(clk); + struct msm_clk *m = to_msm_clk(hw); + return m->reset(hw, action); } EXPORT_SYMBOL(clk_reset); - -unsigned long clk_get_rate(struct clk *clk) -{ - return clk->ops->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_MAX) { - ret = clk->ops->set_max_rate(clk->id, rate); - if (ret) - return ret; - } - if (clk->flags & CLKFLAG_MIN) { - ret = clk->ops->set_min_rate(clk->id, rate); - if (ret) - return ret; - } - - if (clk->flags & CLKFLAG_MAX || clk->flags & CLKFLAG_MIN) - return ret; - - return clk->ops->set_rate(clk->id, rate); -} -EXPORT_SYMBOL(clk_set_rate); - -long clk_round_rate(struct clk *clk, unsigned long rate) -{ - return clk->ops->round_rate(clk->id, rate); -} -EXPORT_SYMBOL(clk_round_rate); - -int clk_set_min_rate(struct clk *clk, unsigned long rate) -{ - return clk->ops->set_min_rate(clk->id, rate); -} -EXPORT_SYMBOL(clk_set_min_rate); - -int clk_set_max_rate(struct clk *clk, unsigned long rate) -{ - return clk->ops->set_max_rate(clk->id, rate); -} -EXPORT_SYMBOL(clk_set_max_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 clk->ops->set_flags(clk->id, flags); -} -EXPORT_SYMBOL(clk_set_flags); - -/* EBI1 is the only shared clock that several clients want to vote on as of - * this commit. If this changes in the future, then it might be better to - * make clk_min_rate handle the voting or make ebi1_clk_set_min_rate more - * generic to support different clocks. - */ -static struct clk *ebi1_clk; - -void __init msm_clock_init(struct clk_lookup *clock_tbl, unsigned num_clocks) -{ - unsigned n; - - mutex_lock(&clocks_mutex); - for (n = 0; n < num_clocks; n++) { - clkdev_add(&clock_tbl[n]); - list_add_tail(&clock_tbl[n].clk->list, &clocks); - } - mutex_unlock(&clocks_mutex); - - ebi1_clk = clk_get(NULL, "ebi1_clk"); - BUG_ON(ebi1_clk == NULL); - -} - -/* 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; - - clock_debug_init(); - mutex_lock(&clocks_mutex); - list_for_each_entry(clk, &clocks, list) { - clock_debug_add(clk); - if (clk->flags & CLKFLAG_AUTO_OFF) { - spin_lock_irqsave(&clocks_lock, flags); - if (!clk->count) { - count++; - clk->ops->auto_off(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); - diff --git a/arch/arm/mach-msm/clock.h b/arch/arm/mach-msm/clock.h index 2c007f606d29..42d29dd7aafc 100644 --- a/arch/arm/mach-msm/clock.h +++ b/ |