intel_scu_ipc: calculate divisor for osc clk
authorTuukka Toivonen <tuukka.toivonen@intel.com>
Wed, 14 Dec 2011 15:11:28 +0000 (17:11 +0200)
committerbuildbot <buildbot@intel.com>
Thu, 26 Jan 2012 08:24:49 +0000 (00:24 -0800)
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 <tuukka.toivonen@intel.com>
Reviewed-on: http://android.intel.com:8080/32620
Reviewed-by: Koski, Anttu <anttu.koski@intel.com>
Tested-by: Koski, Anttu <anttu.koski@intel.com>
Reviewed-by: buildbot <buildbot@intel.com>
Tested-by: buildbot <buildbot@intel.com>
arch/x86/include/asm/intel_scu_ipc.h
arch/x86/platform/mrst/mrst.c
drivers/platform/x86/intel_scu_ipc.c

index 7c365a2..5f3a724 100644 (file)
@@ -2,6 +2,7 @@
 #define  _ASM_X86_INTEL_SCU_IPC_H_
 
 #include <linux/notifier.h>
+#include <asm/mrst.h>
 
 /* 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
index 97df1cd..c3250a4 100644 (file)
@@ -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;
index f70ad85..55b47c8 100644 (file)
@@ -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