From 88810d3466afe40bfc6d8ce5df5a983116a4ebf0 Mon Sep 17 00:00:00 2001 From: Tuukka Toivonen Date: Wed, 14 Dec 2011 17:11:28 +0200 Subject: [PATCH] intel_scu_ipc: calculate divisor for osc clk BZ: 16972 20596 Accept requested frequency as parameter to intel_scu_ipc_osc_clk() when a clock is enabled. The base frequency varies between different platforms so take it into account in the calculations. Also fix any calls to intel_scu_ipc_osc_clk() to provide the requested frequency. Change-Id: Id1ca4f1067e766de744543018fe5427db2de0b75 Signed-off-by: Tuukka Toivonen Reviewed-on: http://android.intel.com:8080/32620 Reviewed-by: Koski, Anttu Tested-by: Koski, Anttu Reviewed-by: buildbot Tested-by: buildbot --- arch/x86/include/asm/intel_scu_ipc.h | 44 ++++++++---------------------------- arch/x86/platform/mrst/mrst.c | 9 +++++--- drivers/platform/x86/intel_scu_ipc.c | 37 ++++++++++++++++++++++++++++++ 3 files changed, 53 insertions(+), 37 deletions(-) diff --git a/arch/x86/include/asm/intel_scu_ipc.h b/arch/x86/include/asm/intel_scu_ipc.h index 7c365a2..5f3a724 100644 --- a/arch/x86/include/asm/intel_scu_ipc.h +++ b/arch/x86/include/asm/intel_scu_ipc.h @@ -2,6 +2,7 @@ #define _ASM_X86_INTEL_SCU_IPC_H_ #include +#include /* IPC defines the following message types */ #define IPCMSG_BATTERY 0xEF /* Coulomb Counter Accumulator */ @@ -15,6 +16,7 @@ #define IPCMSG_VRTC 0xFA /* Set vRTC device */ #define IPCMSG_FW_UPDATE 0xFE /* Firmware update */ #define IPCMSG_PCNTRL 0xFF /* Power controller unit read/write */ +#define IPCMSG_OSC_CLK 0xE6 /* Turn on/off osc clock */ #define IPC_CMD_UMIP_RD 0 #define IPC_CMD_UMIP_WR 1 @@ -91,6 +93,14 @@ int intel_scu_ipc_read_oshob(u8 *data, int len, int offset); /* OSNIB-OS No Init Buffer write */ int intel_scu_ipc_write_osnib(u8 *data, int len, int offset, u32 mask); +/* Penwell has 4 osc clocks */ +#define OSC_CLK_AUDIO 0 /* Audio */ +#define OSC_CLK_CAM0 1 /* Primary camera */ +#define OSC_CLK_CAM1 2 /* Secondary camera */ +#define OSC_CLK_DISP 3 /* Display buffer */ + +int intel_scu_ipc_osc_clk(u8 clk, unsigned int khz); + extern struct blocking_notifier_head intel_scu_notifier; static inline void intel_scu_notifier_add(struct notifier_block *nb) @@ -129,38 +139,4 @@ static inline int intel_scu_ipc_msic_vprog2(int on) on ? MSIC_VPROG_ON : MSIC_VPROG_OFF); } -#define IPCMSG_OSC_CLK 0xE6 /* Turn on/off osc clock */ - -/* - * Penwell has 4 osc clocks: - * 0: AUDIO - * 1,2: CAMERA SENSORS - * 3: DISP_BUF_CLK - */ -#define OSC_CLK_CAM0 1 -#define OSC_CLK_CAM1 2 - -/* SCU IPC COMMAND(osc clk on/off) definition: - * ipc_wbuf[0] = clock to act on {0, 1, 2, 3} - * ipc_wbuf[1] = - * bit 0 - 1:on 0:off - * bit 1 - if 1, read divider setting from bits 3:2 as follows: - * bit [3:2] - 00: clk/1, 01: clk/2, 10: clk/4, 11: reserved - */ -static inline int intel_scu_ipc_osc_clk(u8 clk, u8 on) -{ - u8 ipc_wbuf[16]; - int ipc_ret; - - ipc_wbuf[0] = clk & 0x3; - ipc_wbuf[1] = on & 1; /* no divider */ - - ipc_ret = intel_scu_ipc_command(IPCMSG_OSC_CLK, 0, - (u32 *)ipc_wbuf, 2, NULL, 0); - if (ipc_ret != 0) - pr_err("%s: failed to set osc clk(%d) output\n", __func__, clk); - - return ipc_ret; -} - #endif diff --git a/arch/x86/platform/mrst/mrst.c b/arch/x86/platform/mrst/mrst.c index 97df1cd..c3250a4 100644 --- a/arch/x86/platform/mrst/mrst.c +++ b/arch/x86/platform/mrst/mrst.c @@ -1232,7 +1232,8 @@ static int mt9e013_gpio_ctrl(struct v4l2_subdev *sd, int flag) static int mt9e013_flisclk_ctrl(struct v4l2_subdev *sd, int flag) { - return intel_scu_ipc_osc_clk(OSC_CLK_CAM0, flag); + static const unsigned int clock_khz = 19200; + return intel_scu_ipc_osc_clk(OSC_CLK_CAM0, flag ? clock_khz : 0); } static int mt9e013_power_ctrl(struct v4l2_subdev *sd, int flag) @@ -1332,7 +1333,8 @@ static int ov8830_gpio_ctrl(struct v4l2_subdev *sd, int flag) static int ov8830_flisclk_ctrl(struct v4l2_subdev *sd, int flag) { - return intel_scu_ipc_osc_clk(OSC_CLK_CAM0, flag); + static const unsigned int clock_khz = 19200; + return intel_scu_ipc_osc_clk(OSC_CLK_CAM0, flag ? clock_khz : 0); } static int ov8830_power_ctrl(struct v4l2_subdev *sd, int flag) @@ -1410,7 +1412,8 @@ static int mt9m114_gpio_ctrl(struct v4l2_subdev *sd, int flag) static int mt9m114_flisclk_ctrl(struct v4l2_subdev *sd, int flag) { - return intel_scu_ipc_osc_clk(OSC_CLK_CAM1, flag); + static const unsigned int clock_khz = 19200; + return intel_scu_ipc_osc_clk(OSC_CLK_CAM1, flag ? clock_khz : 0); } static int mt9e013_reset; diff --git a/drivers/platform/x86/intel_scu_ipc.c b/drivers/platform/x86/intel_scu_ipc.c index f70ad85..55b47c8 100644 --- a/drivers/platform/x86/intel_scu_ipc.c +++ b/drivers/platform/x86/intel_scu_ipc.c @@ -2176,6 +2176,43 @@ exit: } EXPORT_SYMBOL_GPL(intel_scu_ipc_write_osnib); +int intel_scu_ipc_osc_clk(u8 clk, unsigned int khz) +{ + /* SCU IPC COMMAND(osc clk on/off) definition: + * ipc_wbuf[0] = clock to act on {0, 1, 2, 3} + * ipc_wbuf[1] = + * bit 0 - 1:on 0:off + * bit 1 - if 1, read divider setting from bits 3:2 as follows: + * bit [3:2] - 00: clk/1, 01: clk/2, 10: clk/4, 11: reserved + */ + unsigned int base_freq; + unsigned int div; + u8 ipc_wbuf[16]; + int ipc_ret; + + if (clk > 3) + return -EINVAL; + + ipc_wbuf[0] = clk; + ipc_wbuf[1] = 0; + if (khz) { + base_freq = mrst_identify_cpu() == MRST_CPU_CHIP_CLOVERVIEW ? + 38400 : 19200; + div = base_freq / khz - 1; + if (div >= 3 || (div + 1) * khz != base_freq) + return -EINVAL; /* Allow only exact frequencies */ + ipc_wbuf[1] = 0x03 | (div << 2); + } + + ipc_ret = intel_scu_ipc_command(IPCMSG_OSC_CLK, 0, + (u32 *)ipc_wbuf, 2, NULL, 0); + if (ipc_ret != 0) + pr_err("%s: failed to set osc clk(%d) output\n", __func__, clk); + + return ipc_ret; +} +EXPORT_SYMBOL_GPL(intel_scu_ipc_osc_clk); + /* * Interrupt handler gets called when ioc bit of IPC_COMMAND_REG set to 1 * When ioc bit is set to 1, caller api must wait for interrupt handler called -- 2.7.4