diff --git a/arch/arm/mach-msm/Makefile b/arch/arm/mach-msm/Makefile index 34e9442d..56d54188 100644 --- a/arch/arm/mach-msm/Makefile +++ b/arch/arm/mach-msm/Makefile @@ -15,7 +15,6 @@ obj-$(CONFIG_ARCH_MSM7X30) += clock-7x30.o arch-init-7x30.o socinfo.o obj-$(CONFIG_ARCH_MSM7X30) += rpc_pmapp.o smd_rpcrouter_clients.o spm.o obj-$(CONFIG_ARCH_MSM7X30) += rpc_hsusb.o obj-$(CONFIG_ARCH_MSM_SCORPION) += idle-v7.o -obj-y += clock.o obj-y += gpio.o generic_gpio.o obj-y += nand_partitions.o obj-y += drv_callback.o @@ -59,17 +58,17 @@ obj-$(CONFIG_MSM7KV2_AUDIO) += htc_acoustic_7x30.o obj-$(CONFIG_SENSORS_AKM8976) += htc_akm_cal.o obj-$(CONFIG_MACH_HALIBUT) += board-halibut.o board-halibut-panel.o -obj-$(CONFIG_MACH_HALIBUT) += board-halibut-keypad.o fish_battery.o -obj-$(CONFIG_MACH_SWORDFISH) += board-swordfish.o +obj-$(CONFIG_MACH_HALIBUT) += board-halibut-keypad.o fish_battery.o clock.o +obj-$(CONFIG_MACH_SWORDFISH) += board-swordfish.o clock.o obj-$(CONFIG_MACH_SWORDFISH) += board-swordfish-keypad.o fish_battery.o obj-$(CONFIG_MACH_SWORDFISH) += board-swordfish-panel.o obj-$(CONFIG_MACH_SWORDFISH) += board-swordfish-mmc.o -obj-$(CONFIG_MACH_TROUT) += board-trout.o board-trout-gpio.o +obj-$(CONFIG_MACH_TROUT) += board-trout.o board-trout-gpio.o clock.o obj-$(CONFIG_MACH_TROUT) += board-trout-keypad.o board-trout-panel.o obj-$(CONFIG_MACH_TROUT) += htc_akm_cal.o htc_wifi_nvs.o htc_acoustic.o obj-$(CONFIG_MACH_TROUT) += board-trout-mmc.o board-trout-wifi.o obj-$(CONFIG_MACH_TROUT) += devices_htc.o -obj-$(CONFIG_MACH_MAHIMAHI) += board-mahimahi.o board-mahimahi-panel.o +obj-$(CONFIG_MACH_MAHIMAHI) += board-mahimahi.o board-mahimahi-panel.o clock.o obj-$(CONFIG_MACH_MAHIMAHI) += board-mahimahi-keypad.o board-mahimahi-mmc.o obj-$(CONFIG_MACH_MAHIMAHI) += board-mahimahi-rfkill.o htc_wifi_nvs.o obj-$(CONFIG_MACH_MAHIMAHI) += board-mahimahi-wifi.o board-mahimahi-audio.o @@ -81,26 +80,26 @@ obj-$(CONFIG_MACH_MAHIMAHI) += board-mahimahi-flashlight.o obj-$(CONFIG_MACH_INCREDIBLEC) += board-incrediblec.o panel-samsungwvga-tl2796a.o board-incrediblec-tv.o obj-$(CONFIG_MACH_INCREDIBLEC) += board-incrediblec-keypad.o board-incrediblec-mmc.o obj-$(CONFIG_MACH_INCREDIBLEC) += board-incrediblec-rfkill.o board-incrediblec-audio.o -obj-$(CONFIG_MACH_INCREDIBLEC) += board-incrediblec-wifi.o htc_awb_cal.o +obj-$(CONFIG_MACH_INCREDIBLEC) += board-incrediblec-wifi.o htc_awb_cal.o clock.o obj-$(CONFIG_MACH_INCREDIBLEC) += board-incrediblec-microp.o obj-$(CONFIG_MACH_INCREDIBLEC) += proc_engineerid.o obj-$(CONFIG_MACH_SUPERSONIC) += board-supersonic.o board-supersonic-panel.o obj-$(CONFIG_MACH_SUPERSONIC) += board-supersonic-keypad.o board-supersonic-mmc.o obj-$(CONFIG_MACH_SUPERSONIC) += board-supersonic-rfkill.o board-supersonic-audio.o obj-$(CONFIG_MACH_SUPERSONIC) += board-supersonic-wifi.o htc_awb_cal.o -obj-$(CONFIG_MACH_SUPERSONIC) += board-supersonic-microp.o +obj-$(CONFIG_MACH_SUPERSONIC) += board-supersonic-microp.o clock.o obj-$(CONFIG_MACH_BRAVO) += board-bravo.o panel-samsungwvga-tl2796a.o panel-sonywvga-s6d16a0x21.o obj-$(CONFIG_MACH_BRAVO) += board-bravo-keypad.o board-bravo-mmc.o obj-$(CONFIG_MACH_BRAVO) += board-bravo-rfkill.o obj-$(CONFIG_MACH_BRAVO) += board-bravo-audio.o board-bravo-wifi.o htc_awb_cal.o -obj-$(CONFIG_MACH_BRAVO) += board-bravo-microp.o +obj-$(CONFIG_MACH_BRAVO) += board-bravo-microp.o clock.o obj-$(CONFIG_MACH_BRAVOC) += board-bravoc.o panel-samsungwvga-tl2796a.o panel-sonywvga-s6d16a0x21.o obj-$(CONFIG_MACH_BRAVOC) += board-bravoc-keypad.o board-bravoc-mmc.o obj-$(CONFIG_MACH_BRAVOC) += board-bravoc-rfkill.o board-bravoc-audio.o obj-$(CONFIG_MACH_BRAVOC) += board-bravoc-wifi.o htc_awb_cal.o -obj-$(CONFIG_MACH_BRAVOC) += board-bravoc-microp.o +obj-$(CONFIG_MACH_BRAVOC) += board-bravoc-microp.o clock.o -obj-$(CONFIG_MACH_HTCLEO) += board-htcleo.o board-htcleo-spi.o board-htcleo-panel.o +obj-$(CONFIG_MACH_HTCLEO) += board-htcleo.o board-htcleo-spi.o board-htcleo-panel.o clock-wince.o # MSM7x30 boards obj-$(CONFIG_ARCH_MSM7X30) += panel-samsungwvga-tl2796a.o panel-samsungwvga-s6e63m0.o panel-sonywvga-s6d16a0x21-7x30.o @@ -110,7 +109,7 @@ obj-$(CONFIG_MACH_VISION)+= board-vision-keypad.o obj-$(CONFIG_MACH_VISION)+= board-vision-microp.o obj-$(CONFIG_MACH_VISION)+= board-vision-audio.o obj-$(CONFIG_MACH_VISION)+= board-vision-mmc.o board-vision-wifi.o -obj-$(CONFIG_MACH_VISION)+= board-vision-rfkill.o htc_bluetooth.o +obj-$(CONFIG_MACH_VISION)+= board-vision-rfkill.o htc_bluetooth.o clock.o obj-$(CONFIG_MACH_LEXIKON)+= board-lexikon.o obj-$(CONFIG_MACH_LEXIKON)+= board-lexikon-keypad.o @@ -118,7 +117,7 @@ obj-$(CONFIG_MACH_LEXIKON)+= board-lexikon-microp.o obj-$(CONFIG_MACH_LEXIKON)+= board-lexikon-audio.o obj-$(CONFIG_MACH_LEXIKON)+= board-lexikon-mmc.o board-lexikon-wifi.o obj-$(CONFIG_MACH_LEXIKON)+= board-lexikon-rfkill.o -obj-$(CONFIG_MACH_LEXIKON)+= board-lexikon-panel.o htc_bluetooth.o +obj-$(CONFIG_MACH_LEXIKON)+= board-lexikon-panel.o htc_bluetooth.o clock.o obj-$(CONFIG_MACH_SPEEDY)+= board-speedy.o obj-$(CONFIG_MACH_SPEEDY)+= board-speedy-keypad.o @@ -126,7 +125,7 @@ obj-$(CONFIG_MACH_SPEEDY)+= board-speedy-microp.o obj-$(CONFIG_MACH_SPEEDY)+= board-speedy-audio.o obj-$(CONFIG_MACH_SPEEDY)+= board-speedy-mmc.o board-speedy-wifi.o obj-$(CONFIG_MACH_SPEEDY)+= board-speedy-rfkill.o -obj-$(CONFIG_MACH_SPEEDY)+= board-speedy-panel.o htc_bluetooth.o +obj-$(CONFIG_MACH_SPEEDY)+= board-speedy-panel.o htc_bluetooth.o clock.o obj-$(CONFIG_MACH_BLITZC)+= board-blitzc.o obj-$(CONFIG_MACH_BLITZC)+= board-blitzc-keypad.o @@ -134,7 +133,7 @@ obj-$(CONFIG_MACH_BLITZC)+= board-blitzc-microp.o obj-$(CONFIG_MACH_BLITZC)+= board-blitzc-audio.o obj-$(CONFIG_MACH_BLITZC)+= board-blitzc-mmc.o obj-$(CONFIG_MACH_BLITZC)+= board-blitzc-rfkill.o -obj-$(CONFIG_MACH_BLITZC)+= board-blitzc-panel.o +obj-$(CONFIG_MACH_BLITZC)+= board-blitzc-panel.o clock.o obj-$(CONFIG_MACH_MECHA)+= board-mecha.o obj-$(CONFIG_MACH_MECHA)+= board-mecha-keypad.o @@ -142,7 +141,7 @@ obj-$(CONFIG_MACH_MECHA)+= board-mecha-microp.o obj-$(CONFIG_MACH_MECHA)+= board-mecha-audio.o obj-$(CONFIG_MACH_MECHA)+= board-mecha-mmc.o board-mecha-wifi.o obj-$(CONFIG_MACH_MECHA)+= board-mecha-rfkill.o -obj-$(CONFIG_MACH_MECHA)+= board-mecha-panel.o htc_bluetooth.o +obj-$(CONFIG_MACH_MECHA)+= board-mecha-panel.o htc_bluetooth.o clock.o obj-$(CONFIG_MACH_GLACIER)+= board-glacier.o obj-$(CONFIG_MACH_GLACIER)+= board-glacier-keypad.o @@ -151,36 +150,36 @@ obj-$(CONFIG_MACH_GLACIER)+= board-glacier-audio.o obj-$(CONFIG_MACH_GLACIER)+= board-glacier-mmc.o board-glacier-wifi.o obj-$(CONFIG_MACH_GLACIER)+= board-glacier-rfkill.o obj-$(CONFIG_MACH_GLACIER)+= htc_fmtx_rfkill.o -obj-$(CONFIG_MACH_GLACIER)+= board-glacier-panel.o htc_bluetooth.o +obj-$(CONFIG_MACH_GLACIER)+= board-glacier-panel.o htc_bluetooth.o clock.o obj-$(CONFIG_MACH_SPADE)+= board-spade.o obj-$(CONFIG_MACH_SPADE)+= board-spade-keypad.o obj-$(CONFIG_MACH_SPADE)+= board-spade-microp.o obj-$(CONFIG_MACH_SPADE)+= board-spade-audio.o obj-$(CONFIG_MACH_SPADE)+= board-spade-mmc.o board-spade-wifi.o htc_awb_cal.o -obj-$(CONFIG_MACH_SPADE)+= board-spade-rfkill.o htc_bluetooth.o board-spade-panel.o +obj-$(CONFIG_MACH_SPADE)+= board-spade-rfkill.o htc_bluetooth.o board-spade-panel.o clock.o # MSM7200A boards obj-$(CONFIG_MACH_HERO) += board-hero.o board-hero-panel.o board-hero-keypad.o -obj-$(CONFIG_MACH_HERO) += board-hero-rfkill.o +obj-$(CONFIG_MACH_HERO) += board-hero-rfkill.o clock.o obj-$(CONFIG_MACH_HERO) += board-hero-mmc.o board-hero-wifi.o htc_wifi_nvs.o htc_awb_cal.o # MSM7225 boards obj-$(CONFIG_MACH_BUZZ) += board-buzz.o board-buzz-panel.o board-buzz-keypad.o board-buzz-microp.o -obj-$(CONFIG_MACH_BUZZ) += board-buzz-rfkill.o board-buzz-mmc.o board-buzz-wifi.o +obj-$(CONFIG_MACH_BUZZ) += board-buzz-rfkill.o board-buzz-mmc.o board-buzz-wifi.o clock.o obj-$(CONFIG_MACH_BEE) += board-bee.o board-bee-panel.o board-bee-keypad.o board-bee-microp.o -obj-$(CONFIG_MACH_BEE) += board-bee-rfkill.o board-bee-mmc.o board-bee-wifi.o +obj-$(CONFIG_MACH_BEE) += board-bee-rfkill.o board-bee-mmc.o board-bee-wifi.o clock.o # MSM7227 boards obj-$(CONFIG_MACH_LEGEND) += board-legend-rfkill.o obj-$(CONFIG_MACH_LEGEND) += board-legend.o board-legend-keypad.o board-legend-panel.o -obj-$(CONFIG_MACH_LEGEND) += board-legend-mmc.o board-legend-wifi.o board-legend-microp.o +obj-$(CONFIG_MACH_LEGEND) += board-legend-mmc.o board-legend-wifi.o board-legend-microp.o clock.o obj-$(CONFIG_MACH_LATTE) += board-latte-rfkill.o obj-$(CONFIG_MACH_LATTE) += board-latte.o board-latte-keypad.o board-latte-panel.o obj-$(CONFIG_MACH_LATTE) += board-latte-mmc.o board-latte-wifi.o board-latte-microp.o -obj-$(CONFIG_MACH_LIBERTY) += board-liberty-rfkill.o htc_bluetooth.o +obj-$(CONFIG_MACH_LIBERTY) += board-liberty-rfkill.o htc_bluetooth.o clock.o obj-$(CONFIG_MACH_LIBERTY) += board-liberty.o board-liberty-keypad.o board-liberty-panel.o -obj-$(CONFIG_MACH_LIBERTY) += board-liberty-mmc.o board-liberty-wifi.o board-liberty-microp.o +obj-$(CONFIG_MACH_LIBERTY) += board-liberty-mmc.o board-liberty-wifi.o board-liberty-microp.o clock.o # MSM7600 boards obj-$(CONFIG_MACH_DESIREC) += board-desirec.o board-desirec-panel.o board-desirec-keypad.o @@ -188,7 +187,7 @@ obj-$(CONFIG_MACH_DESIREC) += board-desirec-rfkill.o obj-$(CONFIG_MACH_DESIREC) += board-desirec-mmc.o board-desirec-wifi.o htc_wifi_nvs.o obj-$(CONFIG_MACH_HEROC) += board-heroc.o board-heroc-panel.o board-heroc-keypad.o obj-$(CONFIG_MACH_HEROC) += board-heroc-rfkill.o -obj-$(CONFIG_MACH_HEROC) += board-heroc-mmc.o board-heroc-wifi.o htc_wifi_nvs.o +obj-$(CONFIG_MACH_HEROC) += board-heroc-mmc.o board-heroc-wifi.o htc_wifi_nvs.o clock.o obj-$(CONFIG_ARCH_MSM7X00A) += msm_vibrator.o devices_htc.o obj-$(CONFIG_ARCH_MSM7225) += msm_vibrator.o devices_htc.o htc_wifi_nvs.o htc_awb_cal.o htc_bluetooth.o diff --git a/arch/arm/mach-msm/clock-wince.c b/arch/arm/mach-msm/clock-wince.c new file mode 100644 index 00000000..8d2527c7 --- /dev/null +++ b/arch/arm/mach-msm/clock-wince.c @@ -0,0 +1,1190 @@ +/* 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 +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "clock.h" +#if defined(CONFIG_MSM_AMSS_VERSION_WINCE) +//#include "dex_comm.h" +#endif +#include "proc_comm.h" + +//#define ENABLE_CLOCK_INFO 1 + +static DEFINE_MUTEX(clocks_mutex); +static DEFINE_SPINLOCK(clocks_lock); +static LIST_HEAD(clocks); + +enum { + DEBUG_UNKNOWN_ID = 1<<0, + DEBUG_UNKNOWN_FREQ = 1<<1, + DEBUG_MDNS = 1<<2, + DEBUG_UNKNOWN_CMD = 1<<3, +}; +static int debug_mask=DEBUG_MDNS; +module_param_named(debug_mask, debug_mask, int, S_IRUGO | S_IWUSR | S_IWGRP); + +#if 1 +#define D(x...) printk(KERN_DEBUG "clock-wince: " x) +#else +#define D(x...) do {} while (0) +#endif + +struct mdns_clock_params +{ + unsigned long freq; + uint32_t calc_freq; + uint32_t md; + uint32_t ns; + uint32_t pll_freq; + uint32_t clk_id; +}; + +struct msm_clock_params +{ + unsigned clk_id; + uint32_t glbl; // Whitch config reg GLBL_CLK_ENA or GLBL_CLK_ENA_2 + unsigned idx; + unsigned offset; // Offset points to .ns register + unsigned ns_only; // value to fill in ns register, rather than using mdns_clock_params look-up table + char *name; +}; + +static int max_clk_rate[NR_CLKS], min_clk_rate[NR_CLKS]; + +#define GLBL_CLK_ENA ((uint32_t)MSM_CLK_CTL_BASE) +#define GLBL_CLK_ENA_2 ((uint32_t)MSM_CLK_CTL_BASE + 0x220) + +#if defined(CONFIG_ARCH_QSD8X50) +#define PLLn_BASE(n) (MSM_CLK_CTL_BASE + 0x300 + 32 * (n)) +#else +#define PLLn_BASE(n) (MSM_CLK_CTL_BASE + 0x300 + 28 * (n)) +#endif +#define TCX0 19200000 // Hz +#define PLL_FREQ(l, m, n) (TCX0 * (l) + TCX0 * (m) / (n)) + +static unsigned int pll_get_rate(int n) +{ + unsigned int mode, L, M, N, freq; + + if (n == -1) return TCX0; +#if defined(CONFIG_ARCH_QSD8X50) + if (n > 1) +#else + if (n > 3) +#endif + return 0; + else + { + mode = readl(PLLn_BASE(n) + 0x0); + L = readl(PLLn_BASE(n) + 0x4); + M = readl(PLLn_BASE(n) + 0x8); + N = readl(PLLn_BASE(n) + 0xc); + freq = PLL_FREQ(L, M, N); + printk(KERN_INFO "PLL%d: MODE=%08x L=%08x M=%08x N=%08x freq=%u Hz (%u MHz)\n", + n, mode, L, M, N, freq, freq / 1000000); \ + } + + return freq; +} + +static unsigned int idx2pll(uint32_t idx) +{ + int ret; + + switch(idx) + { + case 0: /* TCX0 */ + ret=-1; + break; + case 1: /* PLL1 */ + ret=1; + break; + case 4: /* PLL0 */ + ret=0; + break; + default: + ret=4; /* invalid */ + } + + return ret; +} +static struct msm_clock_params msm_clock_parameters[] = { + // Full ena/md/ns clock + { .clk_id = SDC1_CLK, .glbl = GLBL_CLK_ENA, .idx = 7, .offset = 0xa4, .name="SDC1_CLK",}, + { .clk_id = SDC2_CLK, .glbl = GLBL_CLK_ENA, .idx = 8, .offset = 0xac, .name="SDC2_CLK",}, +#if defined(CONFIG_ARCH_QSD8X50) + { .clk_id = SDC3_CLK, .glbl = GLBL_CLK_ENA, .idx = 27, .offset = 0x3d8, .name="SDC3_CLK",}, + { .clk_id = SDC4_CLK, .glbl = GLBL_CLK_ENA, .idx = 28, .offset = 0x3e0, .name="SDC4_CLK",}, +#else + { .clk_id = SDC3_CLK, .glbl = GLBL_CLK_ENA, .idx = 27, .offset = 0xb4, .name="SDC3_CLK",}, + { .clk_id = SDC4_CLK, .glbl = GLBL_CLK_ENA, .idx = 28, .offset = 0xbc, .name="SDC4_CLK",}, +#endif +#if defined(CONFIG_ARCH_QSD8X50) + { .clk_id = UART1DM_CLK, .glbl = GLBL_CLK_ENA, .idx = 17, .offset = 0x124, .name="UART1DM_CLK",}, + { .clk_id = UART2DM_CLK, .glbl = GLBL_CLK_ENA, .idx = 26, .offset = 0x12c, .name="UART2DM_CLK",}, + { .clk_id = USB_HS_CLK, .glbl = GLBL_CLK_ENA_2, .idx = 7, .offset = 0x3e8, .ns_only = 0xb41, .name="USB_HS_CLK",}, +#else + { .clk_id = UART1DM_CLK, .glbl = GLBL_CLK_ENA, .idx = 17, .offset = 0xd4, .name="UART1DM_CLK",}, + { .clk_id = UART2DM_CLK, .glbl = GLBL_CLK_ENA, .idx = 26, .offset = 0xdc, .name="UART2DM_CLK",}, + { .clk_id = USB_HS_CLK, .glbl = GLBL_CLK_ENA, .idx = 25, .offset = 0x2c0, .ns_only = 0xb00, .name="USB_HS_CLK",}, +#endif + // these both enable the GRP and IMEM clocks. + { .clk_id = GRP_CLK, .glbl = GLBL_CLK_ENA, .idx = 3, .offset = 0x84, .ns_only = 0xa80, .name="GRP_CLK", }, + { .clk_id = IMEM_CLK, .glbl = GLBL_CLK_ENA, .idx = 3, .offset = 0x84, .ns_only = 0xa80, .name="IMEM_CLK", }, + + + // MD/NS only; offset = Ns reg +#if defined(CONFIG_ARCH_QSD8X50) + { .clk_id = VFE_CLK, .glbl = GLBL_CLK_ENA, .idx = 2, .offset = 0x40, .name="VFE_CLK", }, +#else + { .clk_id = VFE_CLK, .offset = 0x44, .name="VFE_CLK", }, +#endif + + // Enable bit only; bit = 1U << idx + { .clk_id = MDP_CLK, .glbl = GLBL_CLK_ENA, .idx = 9, .name="MDP_CLK",}, + + // NS-reg only; offset = Ns reg, ns_only = Ns value +#if defined(CONFIG_ARCH_QSD8X50) + { .clk_id = GP_CLK, .glbl = GLBL_CLK_ENA, .offset = 0x58, .ns_only = 0x800, .name="GP_CLK" }, +#else + { .clk_id = GP_CLK, .offset = 0x5c, .ns_only = 0xa06, .name="GP_CLK" }, +#endif + +#if defined(CONFIG_ARCH_QSD8X50) + { .clk_id = PMDH_CLK, .glbl = GLBL_CLK_ENA_2, .idx = 4, .offset = 0x8c, .ns_only = 0x00c, .name="PMDH_CLK"}, +#else + { .clk_id = PMDH_CLK, .offset = 0x8c, .ns_only = 0xa0c, .name="PMDH_CLK"}, +#endif + +#if defined(CONFIG_ARCH_QSD8X50) + { .clk_id = I2C_CLK, .offset = 0x64, .ns_only = 0xa00, .name="I2C_CLK"}, +#else + { .clk_id = I2C_CLK, .offset = 0x68, .ns_only = 0xa00, .name="I2C_CLK"}, +#endif + +#if defined(CONFIG_ARCH_QSD8X50) + { .clk_id = SPI_CLK, .glbl = GLBL_CLK_ENA_2, .idx = 13, .offset = 0x14c, .ns_only = 0xa08, .name="SPI_CLK"}, +#endif + +#if defined(CONFIG_ARCH_QSD8X50) +// { .clk_id = UART1_CLK, .offset = 0xc0, .ns_only = 0xa00, .name="UART1_CLK"}, +#else +// { .clk_id = UART1_CLK, .offset = 0xe0, .ns_only = 0xa00, .name="UART1_CLK"}, +#endif +}; + +// This formula is used to generate md and ns reg values +#define MSM_CLOCK_REG(frequency,M,N,D,PRE,a5,SRC,MNE,pll_frequency) { \ + .freq = (frequency), \ + .md = ((0xffff & (M)) << 16) | (0xffff & ~((D) << 1)), \ + .ns = ((0xffff & ~((N) - (M))) << 16) \ + | ((0xff & (0xa | (MNE))) << 8) \ + | ((0x7 & (a5)) << 5) \ + | ((0x3 & (PRE)) << 3) \ + | (0x7 & (SRC)), \ + .pll_freq = (pll_frequency), \ + .calc_freq = 1000*((pll_frequency/1000)*M/((PRE+1)*N)), \ +} + +struct mdns_clock_params msm_clock_freq_parameters[] = { + + MSM_CLOCK_REG( 144000, 3, 0x64, 0x32, 3, 3, 0, 1, 19200000), /* SD, 144kHz */ + MSM_CLOCK_REG( 400000, 1, 0x30, 0x15, 0, 3, 0, 1, 19200000), /* SD, 400kHz */ +#if 0 /* wince uses this clock setting for UART2DM */ + MSM_CLOCK_REG( 1843200, 3, 0x64, 0x32, 3, 2, 4, 1, 245760000), /* 115200*16=1843200 */ +// MSM_CLOCK_REG( , 2, 0xc8, 0x64, 3, 2, 1, 1, 768888888), /* 1.92MHz for 120000 bps */ +#else + MSM_CLOCK_REG( 7372800, 3, 0x64, 0x32, 0, 2, 4, 1, 245760000), /* 460800*16, will be divided by 4 for 115200 */ +#endif + MSM_CLOCK_REG(12000000, 1, 0x20, 0x10, 1, 3, 1, 1, 768000000), /* SD, 12MHz */ + MSM_CLOCK_REG(14745600, 3, 0x32, 0x19, 0, 2, 4, 1, 245760000), /* BT, 921600 (*16)*/ + MSM_CLOCK_REG(19200000, 1, 0x0a, 0x05, 3, 3, 1, 1, 768000000), /* SD, 19.2MHz */ + MSM_CLOCK_REG(24000000, 1, 0x10, 0x08, 1, 3, 1, 1, 768000000), /* SD, 24MHz */ + MSM_CLOCK_REG(24576000, 1, 0x0a, 0x05, 0, 2, 4, 1, 245760000), /* SD, 24,576000MHz */ + MSM_CLOCK_REG(25000000, 14, 0xd7, 0x6b, 1, 3, 1, 1, 768000000), /* SD, 25MHz */ + MSM_CLOCK_REG(32000000, 1, 0x0c, 0x06, 1, 3, 1, 1, 768000000), /* SD, 32MHz */ + MSM_CLOCK_REG(48000000, 1, 0x08, 0x04, 1, 3, 1, 1, 768000000), /* SD, 48MHz */ + MSM_CLOCK_REG(50000000, 25, 0xc0, 0x60, 1, 3, 1, 1, 768000000), /* SD, 50MHz */ + MSM_CLOCK_REG(58982400, 6, 0x19, 0x0c, 0, 2, 4, 1, 245760000), /* BT, 3686400 (*16) */ + MSM_CLOCK_REG(64000000,0x19, 0x60, 0x30, 0, 2, 4, 1, 245760000), /* BT, 4000000 (*16) */ +}; + +static void set_grp_clk( int on ) +{ + if ( on != 0 ) + { + //axi_reset + writel(readl(MSM_CLK_CTL_BASE+0x208) |0x20, MSM_CLK_CTL_BASE+0x208); //AXI_RESET + //row_reset + writel(readl(MSM_CLK_CTL_BASE+0x214) |0x20000, MSM_CLK_CTL_BASE+0x214); //ROW_RESET + //vdd_grp gfs_ctl + writel( 0x11f, MSM_CLK_CTL_BASE+0x284); //VDD_GRP_GFS_CTL + // very rough delay + mdelay(20); + //grp NS + writel(readl(MSM_CLK_CTL_BASE+0x84) |0x800, MSM_CLK_CTL_BASE+0x84); //GRP_NS_REG + writel(readl(MSM_CLK_CTL_BASE+0x84) |0x80, MSM_CLK_CTL_BASE+0x84); //GRP_NS_REG + writel(readl(MSM_CLK_CTL_BASE+0x84) |0x200, MSM_CLK_CTL_BASE+0x84); //GRP_NS_REG + //grp idx + writel(readl(MSM_CLK_CTL_BASE) |0x8, MSM_CLK_CTL_BASE); + //grp clk ramp + writel(readl(MSM_CLK_CTL_BASE+0x290) &(~(0x4)), MSM_CLK_CTL_BASE+0x290); //MSM_RAIL_CLAMP_IO + //Suppress bit 0 of grp MD (?!?) + writel(readl(MSM_CLK_CTL_BASE+0x80) &(~(0x1)), MSM_CLK_CTL_BASE+0x80); //PRPH_WEB_NS_REG + //axi_reset + writel(readl(MSM_CLK_CTL_BASE+0x208) &(~(0x20)), MSM_CLK_CTL_BASE+0x208); //AXI_RESET + //row_reset +#if defined(CONFIG_ARCH_QSD8X50) + writel(readl(MSM_CLK_CTL_BASE+0x218) &(~(0x20000)), MSM_CLK_CTL_BASE+0x218); //ROW_RESET +#else + writel(readl(MSM_CLK_CTL_BASE+0x214) &(~(0x20000)), MSM_CLK_CTL_BASE+0x214); //ROW_RESET +#endif + } + else + { + //grp NS + writel(readl(MSM_CLK_CTL_BASE+0x84) |0x800, MSM_CLK_CTL_BASE+0x84); //GRP_NS_REG + writel(readl(MSM_CLK_CTL_BASE+0x84) |0x80, MSM_CLK_CTL_BASE+0x84); //GRP_NS_REG + writel(readl(MSM_CLK_CTL_BASE+0x84) |0x200, MSM_CLK_CTL_BASE+0x84); //GRP_NS_REG + //grp idx + writel(readl(MSM_CLK_CTL_BASE) |0x8, MSM_CLK_CTL_BASE); + //grp MD + writel(readl(MSM_CLK_CTL_BASE+0x80) |0x1, MSM_CLK_CTL_BASE+0x80); //PRPH_WEB_NS_REG + int i = 0; + int status = 0; + while ( status == 0 && i < 100) { + i++; + status = readl(MSM_CLK_CTL_BASE+0x84) & 0x1; + } + + //axi_reset + writel(readl(MSM_CLK_CTL_BASE+0x208) |0x20, MSM_CLK_CTL_BASE+0x208); //AXI_RESET + //row_reset +#if defined(CONFIG_ARCH_QSD8X50) + writel(readl(MSM_CLK_CTL_BASE+0x218) |0x20000, MSM_CLK_CTL_BASE+0x218); //ROW_RESET +#else + writel(readl(MSM_CLK_CTL_BASE+0x214) |0x20000, MSM_CLK_CTL_BASE+0x214); //ROW_RESET +#endif + //grp NS + writel(readl(MSM_CLK_CTL_BASE+0x84) &(~(0x800)), MSM_CLK_CTL_BASE+0x84); //GRP_NS_REG + writel(readl(MSM_CLK_CTL_BASE+0x84) &(~(0x80)), MSM_CLK_CTL_BASE+0x84); //GRP_NS_REG + writel(readl(MSM_CLK_CTL_BASE+0x84) &(~(0x200)), MSM_CLK_CTL_BASE+0x84); //GRP_NS_REG + //grp clk ramp + writel(readl(MSM_CLK_CTL_BASE+0x290) |0x4, MSM_CLK_CTL_BASE+0x290); //MSM_RAIL_CLAMP_IO + writel( 0x11f, MSM_CLK_CTL_BASE+0x284); //VDD_GRP_GFS_CTL + + int control = readl(MSM_CLK_CTL_BASE+0x288); //VDD_VDC_GFS_CTL + if ( control & 0x100 ) + writel(readl(MSM_CLK_CTL_BASE) &(~(0x8)), MSM_CLK_CTL_BASE); + } +} + +static inline struct msm_clock_params msm_clk_get_params(uint32_t id) +{ + int i; + struct msm_clock_params empty = { }; + for (i = 0; i < ARRAY_SIZE(msm_clock_parameters); i++) { + if (id == msm_clock_parameters[i].clk_id) { + return msm_clock_parameters[i]; + } + } + return empty; +} + +static inline uint32_t msm_clk_enable_bit(uint32_t id) +{ + struct msm_clock_params params; + params = msm_clk_get_params(id); + if (!params.idx) return 0; + return 1U << params.idx; +} + +static inline uint32_t msm_clk_get_glbl(uint32_t id) +{ + struct msm_clock_params params; + params = msm_clk_get_params(id); + if (!params.glbl) return 0; + return params.glbl; +} + +static inline unsigned msm_clk_reg_offset(uint32_t id) +{ + struct msm_clock_params params; + params = msm_clk_get_params(id); + return params.offset; +} + +static int set_mdns_host_clock(uint32_t id, unsigned long freq) +{ + int n; + unsigned offset; + int retval; + bool found; + struct msm_clock_params params; + uint32_t nsreg; + found = 0; + retval = -EINVAL; + + params = msm_clk_get_params(id); + offset = params.offset; + + if(debug_mask&DEBUG_MDNS) + D("set mdns: %u, %lu; bitidx=%u, offset=%x, ns=%x\n", id, freq, + params.idx, params.offset, params.ns_only); + + if (!params.offset) + { + printk(KERN_WARNING "%s: FIXME! Don't know how to set clock %u - no known Md/Ns reg\n", __func__, id); + return -ENOTSUPP; + } + + // Turn off clock-enable bit if supported + if (params.idx > 0 && params.glbl > 0) + writel(readl(params.glbl) & ~(1U << params.idx), params.glbl); + + if (params.ns_only > 0) + { + nsreg = readl(MSM_CLK_CTL_BASE + offset) & 0xfffff000; + writel( nsreg | params.ns_only, MSM_CLK_CTL_BASE + offset); + + found = 1; + retval = 0; + + } else { + for (n = ARRAY_SIZE(msm_clock_freq_parameters)-1; n >= 0; n--) { + if (freq >= msm_clock_freq_parameters[n].freq) { + // This clock requires MD and NS regs to set frequency: + writel(msm_clock_freq_parameters[n].md, MSM_CLK_CTL_BASE + offset - 4); + writel(msm_clock_freq_parameters[n].ns, MSM_CLK_CTL_BASE + offset); +// msleep(5); + if(debug_mask&DEBUG_MDNS) + D("%s: %u, freq=%lu calc_freq=%u pll%d=%u expected pll =%u\n", __func__, id, + msm_clock_freq_parameters[n].freq, + msm_clock_freq_parameters[n].calc_freq, + msm_clock_freq_parameters[n].ns&7, + pll_get_rate(idx2pll(msm_clock_freq_parameters[n].ns&7)), + msm_clock_freq_parameters[n].pll_freq ); + retval = 0; + found = 1; + break; + } + } + } + + // Turn clock-enable bit back on, if supported + if (params.idx > 0 && params.glbl > 0) + writel(readl(params.glbl) | (1U << params.idx), params.glbl); + + if (!found && debug_mask&DEBUG_UNKNOWN_FREQ) { + printk(KERN_WARNING "clock-wince: FIXME! set_sdcc_host_clock could not " + "find suitable parameter for freq %lu\n", freq); + } + +// return retval; + return 0; +} + +static unsigned long get_mdns_host_clock(uint32_t id) +{ + int n; + unsigned offset; + uint32_t mdreg; + uint32_t nsreg; + unsigned long freq = 0; + + offset = msm_clk_reg_offset(id); + if (offset == 0) + return -EINVAL; + + mdreg = readl(MSM_CLK_CTL_BASE + offset - 4); + nsreg = readl(MSM_CLK_CTL_BASE + offset); + + for (n = 0; n < ARRAY_SIZE(msm_clock_freq_parameters); n++) { + if (msm_clock_freq_parameters[n].md == mdreg && + msm_clock_freq_parameters[n].ns == nsreg) { + freq = msm_clock_freq_parameters[n].freq; + break; + } + } + + return freq; +} + +static int new_clk_set_rate(uint32_t id, unsigned long rate) +{ + unsigned clk = -1; + unsigned speed = 0; + switch (id) + { + case ICODEC_RX_CLK: + if (rate > 11289600) speed = 9; + else if (rate > 8192000) speed = 8; + else if (rate > 6144000) speed = 7; + else if (rate > 5644800) speed = 6; + else if (rate > 4096000) speed = 5; + else if (rate > 3072000) speed = 4; + else if (rate > 2822400) speed = 3; + else if (rate > 2048000) speed = 2; + else speed = 1; + clk = 50; + break; + case ICODEC_TX_CLK: + if (rate > 11289600) speed = 9; + else if (rate > 8192000) speed = 8; + else if (rate > 6144000) speed = 7; + else if (rate > 5644800) speed = 6; + else if (rate > 4096000) speed = 5; + else if (rate > 3072000) speed = 4; + else if (rate > 2822400) speed = 3; + else if (rate > 2048000) speed = 2; + else speed = 1; + clk = 52; + break; + case ECODEC_CLK: + if (rate > 2048000) speed = 3; + else if (rate > 128000) speed = 2; + else speed = 1; + clk = 42; + break; + case SDAC_MCLK: + if (rate > 1411200) speed = 9; + else if (rate > 1024000) speed = 8; + else if (rate > 768000) speed = 7; + else if (rate > 705600) speed = 6; + else if (rate > 512000) speed = 5; + else if (rate > 384000) speed = 4; + else if (rate > 352800) speed = 3; + else if (rate > 256000) speed = 2; + else speed = 1; + clk = 64; + break; + + case UART1DM_CLK: + if (rate > 61440000) speed = 15; + else if (rate > 58982400) speed = 14; + else if (rate > 56000000) speed = 13; + else if (rate > 51200000) speed = 12; + else if (rate > 48000000) speed = 11; + else if (rate > 40000000) speed = 10; + else if (rate > 32000000) speed = 9; + else if (rate > 24000000) speed = 8; + else if (rate > 16000000) speed = 7; + else if (rate > 15360000) speed = 6; + else if (rate > 14745600) speed = 5; + else if (rate > 7680000) speed = 4; + else if (rate > 7372800) speed = 3; + else if (rate > 3840000) speed = 2; + else speed = 1; + clk = 78; + break; + case UART2DM_CLK: + if (rate > 61440000) speed = 15; + else if (rate > 58982400) speed = 14; + else if (rate > 56000000) speed = 13; + else if (rate > 51200000) speed = 12; + else if (rate > 48000000) speed = 11; + else if (rate > 40000000) speed = 10; + else if (rate > 32000000) speed = 9; + else if (rate > 24000000) speed = 8; + else if (rate > 16000000) speed = 7; + else if (rate > 15360000) speed = 6; + else if (rate > 14745600) speed = 5; + else if (rate > 7680000) speed = 4; + else if (rate > 7372800) speed = 3; + else if (rate > 3840000) speed = 2; + else speed = 1; + clk = 80; + break; + + + case VFE_MDC_CLK: + if (rate == 96000000) speed = 37; + else if (rate == 48000000) speed = 32; + else if (rate == 24000000) speed = 22; + else if (rate == 12000000) speed = 14; + else if (rate == 6000000) speed = 6; + else if (rate == 3000000) speed = 1; + else + { + printk("wrong MDC clock %d\n", rate); + return 0; + } + clk = 40; + break; + + case VFE_CLK: + if (rate == 36000000) speed = 1; + else if (rate == 48000000) speed = 2; + else if (rate == 64000000) speed = 3; + else if (rate == 78000000) speed = 4; + else if (rate == 96000000) speed = 5; + else + { + printk("wrong clock %d\n", rate); + return 0; + } + clk = 41; + break; + + case SPI_CLK: + if (rate > 15360000) speed = 5; + else if (rate > 9600000) speed = 4; + else if (rate > 4800000) speed = 3; + else if (rate > 960000) speed = 2; + else speed = 1; + clk = 95; + break; + + /* + case SDC1_CLK: + clk = 66; + break; + case SDC2_CLK: + clk = 67; + break; + case SDC3_CLK: + clk = 68; + break; + case SDC4_CLK: + clk = 69; + break; + + case MDP_CLK: + clk = 9; + break; */ + default: + return -1; + } + +#ifdef ENABLE_CLOCK_INFO + printk("clk_rate %d : %d\n", clk, speed); +#endif + msm_proc_comm(PCOM_CLK_REGIME_SEC_SEL_SPEED, &clk, &speed); + return 0; +} + +static int new_clk_enable(uint32_t id) +{ + unsigned clk = -1; + switch (id) + { + case ICODEC_RX_CLK: + clk = 50; + break; + case ICODEC_TX_CLK: + clk = 52; + break; + case ECODEC_CLK: + clk = 42; + break; + case SDAC_MCLK: + clk = 64; + break; + case IMEM_CLK: + clk = 55; + break; + case GRP_CLK: + clk = 56; + break; + case ADM_CLK: + clk = 19; + break; + + case UART1DM_CLK: + clk = 78; + break; + case UART2DM_CLK: + clk = 80; + break; + + case VFE_AXI_CLK: + clk = 24; + break; + case VFE_MDC_CLK: + clk = 40; + break; + case VFE_CLK: + clk = 41; + break; + case MDC_CLK: + clk = 53; // ?? + break; + + case SPI_CLK: + clk = 95; + break; + + case MDP_CLK: + clk = 9; + break; + /* + case SDC1_CLK: + clk = 66; + break; + case SDC2_CLK: + clk = 67; + break; + case SDC3_CLK: + clk = 68; + break; + case SDC4_CLK: + clk = 69; + break; + + +*/ + default: + return -1; + } + +#ifdef ENABLE_CLOCK_INFO + printk("clk_on %d\n", clk); +#endif + msm_proc_comm(PCOM_CLK_REGIME_SEC_ENABLE, &clk, 0); + return 0; +} + +static int new_clk_disable(uint32_t id) +{ + unsigned clk = -1; + switch (id) + { + case ICODEC_RX_CLK: + clk = 50; + break; + case ICODEC_TX_CLK: + clk = 52; + break; + case ECODEC_CLK: + clk = 42; + break; + case SDAC_MCLK: + clk = 64; + break; + case IMEM_CLK: + clk = 55; + break; + case GRP_CLK: + clk = 56; + break; + case ADM_CLK: + clk = 19; + break; + + case UART1DM_CLK: + clk = 78; + break; + case UART2DM_CLK: + clk = 80; + break; + + case VFE_AXI_CLK: + clk = 24; + break; + case VFE_MDC_CLK: + clk = 40; + break; + case VFE_CLK: + clk = 41; + break; + case MDC_CLK: + clk = 53; // WTF?? + break; + + case SPI_CLK: + clk = 95; + break; + + case MDP_CLK: + clk = 9; + break; + + /* + case SDC1_CLK: + clk = 66; + break; + case SDC2_CLK: + clk = 67; + break; + case SDC3_CLK: + clk = 68; + break; + case SDC4_CLK: + clk = 69; + break; + + case MDP_CLK: + clk = 9; + break; +*/ + default: + return -1; + } + +#ifdef ENABLE_CLOCK_INFO + printk("clk_off %d\n", clk); +#endif + msm_proc_comm(PCOM_CLK_REGIME_SEC_DISABLE, &clk, 0); + return 0; +} + + +static int new_clk_set_flags(uint32_t id, unsigned long flags) +{ + if (id == VFE_CLK) + { + // INTERNAL 0x00000100 << 1 + if (flags == (0x00000100 << 1)) + { + uint32_t f = 0; + msm_proc_comm(PCOM_CLK_REGIME_SEC_SEL_VFE_SRC, &f, 0); +#ifdef ENABLE_CLOCK_INFO + printk("internal VFE source\n"); +#endif + return 0; + } + // EXTERNAL 0x00000100 + else if (flags == 0x00000100) + { + uint32_t f = 1; + msm_proc_comm(PCOM_CLK_REGIME_SEC_SEL_VFE_SRC, &f, 0); +#ifdef ENABLE_CLOCK_INFO + printk("external VFE source\n"); +#endif + return 0; + } + } + return -1; +} + + +////////////////////////////////////////////////////////// + +static int pc_clk_enable(uint32_t id) +{ + struct msm_clock_params params; + int r; + + r = new_clk_enable(id); + if (r != -1) return r; + + params = msm_clk_get_params(id); + + //XXX: too spammy, extreme debugging only: D(KERN_DEBUG "%s: %d\n", __func__, id); + + if ( id == IMEM_CLK || id == GRP_CLK ) + { + set_grp_clk( 1 ); + writel(readl(params.glbl) | (1U << params.idx), params.glbl); + return 0; + } + + if (params.idx > 0 && params.glbl > 0) + { + writel(readl(params.glbl) | (1U << params.idx), params.glbl); + return 0; + } else if (params.ns_only > 0 && params.offset) + { + writel((readl(MSM_CLK_CTL_BASE + params.offset) &0xfffff000) | params.ns_only, MSM_CLK_CTL_BASE + params.offset); + return 0; + } + if(debug_mask&DEBUG_UNKNOWN_ID) + printk(KERN_WARNING "%s: FIXME! enabling a clock that doesn't have an ena bit " + "or ns-only offset: %u\n", __func__, id); + + return 0; +} + +static void pc_clk_disable(uint32_t id) +{ + struct msm_clock_params params; + params = msm_clk_get_params(id); + int r; + + r = new_clk_disable(id); + if (r != -1) return; + + //XXX: D(KERN_DEBUG "%s: %d\n", __func__, id); + + if ( id == IMEM_CLK || id == GRP_CLK ) + { + set_grp_clk( 1 ); + writel(readl(params.glbl) & ~(1U << params.idx), params.glbl); + return; + } + + if (params.idx > 0 && params.glbl > 0) + { + writel(readl(params.glbl) & ~(1U << params.idx), params.glbl); + } else if (params.ns_only > 0 && params.offset) + { + writel(readl(MSM_CLK_CTL_BASE + params.offset) & 0xfffff000, MSM_CLK_CTL_BASE + params.offset); + } else { + if(debug_mask&DEBUG_UNKNOWN_ID) + printk(KERN_WARNING "%s: FIXME! disabling a clock that doesn't have an " + "ena bit: %u\n", __func__, id); + } +} + +static int pc_clk_set_rate(uint32_t id, unsigned long rate) +{ + int retval; + retval = 0; + int r; + + r = new_clk_set_rate(id, rate); + if (r != -1) return r; + + if(DEBUG_MDNS) + D("%s: id=%u rate=%lu\n", __func__, id, rate); + + retval = set_mdns_host_clock(id, rate); + + return retval; +} + +static int pc_clk_set_min_rate(uint32_t id, unsigned long rate) +{ + if (id < NR_CLKS) + min_clk_rate[id]=rate; + else if(debug_mask&DEBUG_UNKNOWN_ID) + printk(KERN_WARNING " FIXME! clk_set_min_rate not implemented; %u:%lu NR_CLKS=%d\n", id, rate, NR_CLKS); + + return 0; +} + +static int pc_clk_set_max_rate(uint32_t id, unsigned long rate) +{ + if (id < NR_CLKS) + max_clk_rate[id]=rate; + else if(debug_mask&DEBUG_UNKNOWN_ID) + printk(KERN_WARNING " FIXME! clk_set_min_rate not implemented; %u:%lu NR_CLKS=%d\n", id, rate, NR_CLKS); + + return 0; +} + +static unsigned long pc_clk_get_rate(uint32_t id) +{ + unsigned long rate = 0; + + switch (id) { + /* known MD/NS clocks, MSM_CLK dump and arm/mach-msm/clock-7x30.c */ + case SDC1_CLK: + case SDC2_CLK: + case SDC3_CLK: + case SDC4_CLK: + case UART1DM_CLK: + case UART2DM_CLK: + case USB_HS_CLK: + case SDAC_CLK: + case TV_DAC_CLK: + case TV_ENC_CLK: + case USB_OTG_CLK: + rate = get_mdns_host_clock(id); + break; + + case SDC1_PCLK: + case SDC2_PCLK: + case SDC3_PCLK: + case SDC4_PCLK: + rate = 64000000; /* g1 value */ + break; + + default: + //TODO: support all clocks + if(debug_mask&DEBUG_UNKNOWN_ID) + printk("%s: unknown clock: id=%u\n", __func__, id); + rate = 0; + } + + return rate; +} + +static int pc_clk_set_flags(uint32_t id, unsigned long flags) +{ + int r; + + r = new_clk_set_flags(id, flags); + if (r != -1) return r; + + if(debug_mask&DEBUG_UNKNOWN_CMD) + printk(KERN_WARNING "%s not implemented for clock: id=%u, flags=%lu\n", __func__, id, flags); + return 0; +} + +static int pc_clk_is_enabled(uint32_t id) +{ + int is_enabled = 0; + unsigned bit; + uint32_t glbl; + glbl = msm_clk_get_glbl(id); + bit = msm_clk_enable_bit(id); + if (bit > 0 && glbl>0) + { + is_enabled = (readl(glbl) & bit) != 0; + } + //XXX: is this necessary? + if (id==SDC1_PCLK || id==SDC2_PCLK || id==SDC3_PCLK || id==SDC4_PCLK) + is_enabled = 1; + return is_enabled; +} + +static int pc_pll_request(unsigned id, unsigned on) +{ + if(debug_mask&DEBUG_UNKNOWN_CMD) + printk(KERN_WARNING "%s not implemented for PLL=%u\n", __func__, id); + + return 0; +} + +/* + * 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; + if (clk->id == ACPU_CLK) + { + return -ENOTSUPP; + } + 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_MAX_TO_SET) { + ret = pc_clk_set_max_rate(clk->id, rate); + if (ret) + return ret; + } + if (clk->flags & CLKFLAG_USE_MIN_TO_SET) { + ret = pc_clk_set_min_rate(clk->id, rate); + if (ret) + return ret; + } + + if (clk->flags & CLKFLAG_USE_MAX_TO_SET || + clk->flags & CLKFLAG_USE_MIN_TO_SET) + return ret; + + 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) +{ + struct clk *clk; + + spin_lock_init(&clocks_lock); + mutex_lock(&clocks_mutex); + for (clk = msm_clocks; clk && clk->name; clk++) { + list_add_tail(&clk->list, &clocks); + } + mutex_unlock(&clocks_mutex); +} + +void clk_enter_sleep(int from_idle) +{ +} + +void clk_exit_sleep(void) +{ +} + +int clks_print_running(void) +{ + struct clk *clk; + int clk_on_count = 0; + char buf[100]; + char *pbuf = buf; + int size = sizeof(buf); + int wr; + unsigned long flags; + + spin_lock_irqsave(&clocks_lock, flags); + + list_for_each_entry(clk, &clocks, list) { + if (clk->count) { + clk_on_count++; + wr = snprintf(pbuf, size, " %s", clk->name); + if (wr >= size) + break; + pbuf += wr; + size -= wr; + } + } + if (clk_on_count) + pr_info("clocks on:%s\n", buf); + + spin_unlock_irqrestore(&clocks_lock, flags); + return !clk_on_count; +} +EXPORT_SYMBOL(clks_print_running); + +int clks_allow_tcxo_locked(void) +{ + struct clk *clk; + struct hlist_node *pos; + unsigned long flags; + + spin_lock_irqsave(&clocks_lock, flags); + list_for_each_entry(clk, &clocks, list) { + if (clk->count) + return 0; + } + + spin_unlock_irqrestore(&clocks_lock, flags); + return 1; +} +EXPORT_SYMBOL(clks_allow_tcxo_locked); + +int clks_allow_tcxo_locked_debug(void) +{ + struct clk *clk; + int clk_on_count = 0; + unsigned long flags; + + spin_lock_irqsave(&clocks_lock, flags); + + list_for_each_entry(clk, &clocks, list) { + if (clk->count) { + pr_info("%s: '%s' not off.\n", __func__, clk->name); + clk_on_count++; + } + } + pr_info("%s: %d clks are on.\n", __func__, clk_on_count); + + spin_unlock_irqrestore(&clocks_lock, flags); + return !clk_on_count; +} +EXPORT_SYMBOL(clks_allow_tcxo_locked_debug); + + +/* 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 && clk->id != MDP_CLK) { + 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); + + // reset imem config, I guess all devices need this so somewhere here would be good. + // it needs to be moved to somewhere else. + //writel( 0, MSM_IMEM_BASE ); // IMEM addresses have to ve checked and enabled + //pr_info("reset imem_config\n"); + return 0; +} + +late_initcall(clock_late_init);