FM: Add support to configure the spur Rotation table

- Add support to configure the FM SOC spur table.

Change-Id: I817268be67f29dfb6862314dc90a915c01f40342
CRs-Fixed: 664779
diff --git a/jni/android_hardware_fm.cpp b/jni/android_hardware_fm.cpp
index 46ae7c4..505efb8 100644
--- a/jni/android_hardware_fm.cpp
+++ b/jni/android_hardware_fm.cpp
@@ -53,6 +53,7 @@
 #define V4L2_CID_PRIVATE_IRIS_SET_CALIBRATION           (V4L2_CTRL_CLASS_USER + 0x92A)
 #define V4L2_CID_PRIVATE_TAVARUA_ON_CHANNEL_THRESHOLD   (V4L2_CTRL_CLASS_USER + 0x92B)
 #define V4L2_CID_PRIVATE_TAVARUA_OFF_CHANNEL_THRESHOLD  (V4L2_CTRL_CLASS_USER + 0x92C)
+#define V4L2_CID_PRIVATE_IRIS_SET_SPURTABLE             (V4L2_CTRL_CLASS_USER + 0x92D)
 #define TX_RT_LENGTH       63
 #define WAIT_TIMEOUT 200000 /* 200*1000us */
 #define TX_RT_DELIMITER    0x0d
@@ -736,6 +737,45 @@
     return FM_JNI_SUCCESS;
 }
 
+/* native interface */
+static jint android_hardware_fmradio_FmReceiverJNI_setSpurDataNative
+ (JNIEnv * env, jobject thiz, jint fd, jshortArray buff, jint count)
+{
+    ALOGE("entered JNI's setSpurDataNative\n");
+    int err, i = 0;
+    struct v4l2_ext_control ext_ctl;
+    struct v4l2_ext_controls v4l2_ctls;
+    uint8_t *data;
+    short *spur_data = env->GetShortArrayElements(buff, NULL);
+    if (spur_data == NULL) {
+        ALOGE("Spur data is NULL\n");
+        return FM_JNI_FAILURE;
+    }
+    data = (uint8_t *) malloc(count);
+    if (data == NULL) {
+        ALOGE("Allocation failed for data\n");
+        return FM_JNI_FAILURE;
+    }
+    for(i = 0; i < count; i++)
+        data[i] = (uint8_t) spur_data[i];
+
+    ext_ctl.id = V4L2_CID_PRIVATE_IRIS_SET_SPURTABLE;
+    ext_ctl.string = (char*)data;
+    ext_ctl.size = count;
+    v4l2_ctls.ctrl_class = V4L2_CTRL_CLASS_USER;
+    v4l2_ctls.count   = 1;
+    v4l2_ctls.controls  = &ext_ctl;
+
+    err = ioctl(fd, VIDIOC_S_EXT_CTRLS, &v4l2_ctls );
+    if (err < 0){
+        ALOGE("Set ioctl failed\n");
+        free(data);
+        return FM_JNI_FAILURE;
+    }
+    free(data);
+    return FM_JNI_SUCCESS;
+}
+
 /*
  * JNI registration.
  */
@@ -795,7 +835,8 @@
             (void*)android_hardware_fmradio_FmReceiverJNI_SetCalibrationNative},
         { "configureSpurTable", "(I)I",
             (void*)android_hardware_fmradio_FmReceiverJNI_configureSpurTable},
-
+        { "setSpurDataNative", "(I[SI)I",
+            (void*)android_hardware_fmradio_FmReceiverJNI_setSpurDataNative},
 };
 
 int register_android_hardware_fm_fmradio(JNIEnv* env)
diff --git a/qcom/fmradio/FmConfig.java b/qcom/fmradio/FmConfig.java
index 3044cc2..728d1d3 100644
--- a/qcom/fmradio/FmConfig.java
+++ b/qcom/fmradio/FmConfig.java
@@ -30,7 +30,7 @@
 
 import android.util.Log;
 import android.os.SystemProperties;
-
+import java.util.List;
 
 /**
  *
@@ -47,6 +47,9 @@
      private static final int V4L2_CID_PRIVATE_TAVARUA_SPACING        = V4L2_CID_PRIVATE_BASE + 14;
      private static final int V4L2_CID_PRIVATE_TAVARUA_SRCH_ALGORITHM = V4L2_CID_PRIVATE_BASE + 0x2B;
 
+     private static final int each_Spur_entry_size = 16;
+     public static final int no_Of_Spurs_For_Entry = 3;
+
      private static final String TAG = "FmConfig";
 
 
@@ -91,6 +94,54 @@
      */
     private int mBandUpperLimit;
 
+    public static boolean fmSpurConfig(int fd) {
+        SpurFileParser parser = new SpurFileParser();
+        SpurTable t;
+        int freq = 0, i = 0, j = 0;
+        byte no_of_spur_freq = 0;
+        int rotation_value = 0;
+        int re;
+
+        t = parser.GetSpurTable("/etc/fm/SpurTableFile.txt");
+        List <Spur> list = t.GetSpurList();
+        no_of_spur_freq = t.GetspurNoOfFreq();
+        short [] buff = new short[2 + (no_of_spur_freq * each_Spur_entry_size)];
+        buff[0] = t.GetMode();
+        buff[1] = no_of_spur_freq;
+        for(i = 0; i < no_of_spur_freq; i++) {
+            List <Spur> spur = t.GetSpurList();
+            freq = spur.get(i).getSpurFreq();
+            buff[(i * each_Spur_entry_size) + 2] = (short)(freq & 0xff);
+            buff[(i * each_Spur_entry_size) + 3] = (short)((freq >> 8) & 0xff);
+            buff[(i * each_Spur_entry_size) + 4] = (short)((freq >> 16) & 0xff);
+            buff[(i * each_Spur_entry_size) + 5] = spur.get(i).getNoOfSpursToTrack();
+            List <SpurDetails> spurDetails =
+                                spur.get(i).getSpurDetailsList();
+            for(j = 0; j < no_Of_Spurs_For_Entry; j++) {
+                rotation_value = spurDetails.get(j).getRotationValue();
+                buff[(j * 4) + 6 + (i * each_Spur_entry_size)]  =
+                                        (short)(rotation_value & 0xff);
+                buff[(j * 4) + 7 + (i * each_Spur_entry_size)]  =
+                                 (short)((rotation_value >> 8) & 0xff);
+                buff[(j * 4) + 8 + (i * each_Spur_entry_size)]  =
+                                (short)((rotation_value >> 12) & 0xff);
+                buff[(j * 4) + 8 + (i * each_Spur_entry_size)] |=
+                 (short)(spurDetails.get(j).getLsbOfIntegrationLength() << 4);
+                buff[(j * 4) + 8 + (i * each_Spur_entry_size)] |=
+                      (short)(spurDetails.get(j).getFilterCoefficeint() << 5);
+                buff[(j * 4) + 8 + (i * each_Spur_entry_size)] |=
+                    (short)(spurDetails.get(j).getIsEnableSpur() << 7);
+                buff[(j * 4) + 9 + (i * each_Spur_entry_size)]  =
+                              (short)spurDetails.get(j).getSpurLevel();
+            }
+        }
+        re = FmReceiverJNI.setSpurDataNative(fd, buff,
+                        (2 + (no_of_spur_freq * each_Spur_entry_size)));
+        if (re < 0)
+            return false;
+        return true;
+    }
+
     public int getRadioBand(){
         return mRadioBand;
     }
diff --git a/qcom/fmradio/FmReceiver.java b/qcom/fmradio/FmReceiver.java
index b1bdb31..832cb29 100644
--- a/qcom/fmradio/FmReceiver.java
+++ b/qcom/fmradio/FmReceiver.java
@@ -259,6 +259,8 @@
 
    private static final int V4L2_CID_PRIVATE_BASE = 0x8000000;
    private static final int V4L2_CID_PRIVATE_TAVARUA_SIGNAL_TH = V4L2_CID_PRIVATE_BASE + 8;
+   private static final int V4L2_CTRL_CLASS_USER = 0x00980000;
+   private static final int V4L2_CID_PRIVATE_IRIS_GET_SPUR_TBL = (V4L2_CTRL_CLASS_USER + 0x92E);
 
 
    private static final int TAVARUA_BUF_SRCH_LIST=0;
@@ -2535,4 +2537,48 @@
    {
        return mControl.configureSpurTable(sFd);
    }
+
+   public static int getSpurConfiguration(int freq)
+   {
+       int retval;
+
+       retval = FmReceiverJNI.setControlNative(sFd, V4L2_CID_PRIVATE_IRIS_GET_SPUR_TBL, freq);
+
+        if (retval !=0)
+            Log.d(TAG, "Failed/No Spurs for " +freq);
+       return retval;
+   }
+
+   public static void getSpurTableData()
+   {
+     int freq;
+     byte no_of_spurs;
+     int rotation_value;
+     byte lsbOfLen;
+     byte filterCoe;
+     byte isEnbale;
+     byte [] buff = new byte[STD_BUF_SIZE];
+     int i = 0;
+     FmReceiverJNI.getBufferNative(sFd, buff, 13);
+
+     freq = buff[0] & 0xFF;
+     freq |= ((buff[1] & 0xFF) << 8);
+     freq |= ((buff[2] & 0xFF) << 16);
+     Log.d (TAG, "freq = " +freq);
+     no_of_spurs =  buff[3];
+     Log.d (TAG, "no_of_spurs = " + no_of_spurs);
+     for(i = 0; i < FmConfig.no_Of_Spurs_For_Entry; i++) {
+         rotation_value =  buff[(i * 4) + 4] & 0xFF;
+         rotation_value |= ((buff[(i * 4) + 5] & 0xFF) << 8);
+         rotation_value |= ((buff[(i * 4) + 6] & 0x0F) << 12);
+         Log.d (TAG, "rotation_value = " +rotation_value);
+         lsbOfLen = (byte) (((buff[(i * 4) + 6] & 0xF0) >> 4) & 0x01);
+         Log.d (TAG, "lsbOfLen = "+lsbOfLen);
+         filterCoe = (byte) (((buff[(i * 4) + 6] & 0xF0) >> 5) & 0x03);
+         Log.d (TAG, "filterCoe = " +filterCoe);
+         isEnbale = (byte) (((buff[(i * 4) + 6] & 0xF0) >> 7) & 0x01);
+         Log.d (TAG, "spur level: " +buff[(i * 4) + 7]);
+     }
+     return;
+   }
 }
diff --git a/qcom/fmradio/FmReceiverJNI.java b/qcom/fmradio/FmReceiverJNI.java
index 3c779c2..db75ccb 100644
--- a/qcom/fmradio/FmReceiverJNI.java
+++ b/qcom/fmradio/FmReceiverJNI.java
@@ -282,4 +282,12 @@
      *         {@link #FM_JNI_FAILURE}
      */
     static native int configureSpurTable(int fd);
+
+    /**
+     * native method: Configures the new spur table
+     * @param fd file descriptor of device
+     * @return {@link #FM_JNI_SUCCESS}
+     *         {@link #FM_JNI_FAILURE}
+     */
+    static native int setSpurDataNative(int fd, short  buff[], int len);
 }
diff --git a/qcom/fmradio/FmRxEventListner.java b/qcom/fmradio/FmRxEventListner.java
index 865aac7..de39d91 100644
--- a/qcom/fmradio/FmRxEventListner.java
+++ b/qcom/fmradio/FmRxEventListner.java
@@ -230,6 +230,10 @@
                                 Log.d(TAG, "got eRT event");
                                 cb.FmRxEvERTInfo();
                                 break;
+                            case 22:
+                                Log.d(TAG, "got IRIS_EVT_SPUR_TBL event");
+                                FmReceiver.getSpurTableData();
+                                break;
                             default:
                                 Log.d(TAG, "Unknown event");
                                 break;
diff --git a/qcom/fmradio/FmTransceiver.java b/qcom/fmradio/FmTransceiver.java
index 20f0544..fa2378e 100644
--- a/qcom/fmradio/FmTransceiver.java
+++ b/qcom/fmradio/FmTransceiver.java
@@ -29,6 +29,7 @@
 
 package qcom.fmradio;
 import android.util.Log;
+import java.io.File;
 
 /** <code>FmTransceiver</code> is the superclass of classes
  * <code>FmReceiver</code> and <code>FmTransmitter</code>
@@ -406,6 +407,12 @@
       if( !acquire("/dev/radio0")){
          return false;
       }
+      if (new File("/etc/fm/SpurTableFile.txt").isFile()) {
+          Log.d(TAG, "Send Spur roation table");
+          FmConfig.fmSpurConfig(sFd);
+      } else {
+          Log.d(TAG, "No existing file to do spur configuration");
+      }
       Log.d(TAG, "turning on " + device);
       mControl.fmOn(sFd, device);
 
diff --git a/qcom/fmradio/Spur.java b/qcom/fmradio/Spur.java
new file mode 100644
index 0000000..d60d4e9
--- /dev/null
+++ b/qcom/fmradio/Spur.java
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 2014, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *        * Redistributions of source code must retain the above copyright
+ *            notice, this list of conditions and the following disclaimer.
+ *        * Redistributions in binary form must reproduce the above copyright
+ *            notice, this list of conditions and the following disclaimer in the
+ *            documentation and/or other materials provided with the distribution.
+ *        * Neither the name of The Linux Foundation nor
+ *            the names of its contributors may be used to endorse or promote
+ *            products derived from this software without specific prior written
+ *            permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NON-INFRINGEMENT ARE DISCLAIMED.    IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package qcom.fmradio;
+import java.util.ArrayList;
+import java.util.List;
+
+public class Spur {
+
+    private int SpurFreq;
+    private byte NoOfSpursToTrack;
+    private List <SpurDetails> spurDetailsList;
+
+    Spur() {
+
+    }
+
+    Spur(int SpurFreq, byte NoOfSpursToTrack,
+         List <SpurDetails> spurDetailsList) {
+
+        this.SpurFreq = SpurFreq;
+        this.NoOfSpursToTrack = NoOfSpursToTrack;
+        this.spurDetailsList = spurDetailsList;
+    }
+
+    public int getSpurFreq() {
+        return SpurFreq;
+    }
+
+    public void setSpurFreq(int spurFreq) {
+        SpurFreq = spurFreq;
+    }
+
+    public byte getNoOfSpursToTrack() {
+        return NoOfSpursToTrack;
+    }
+
+    public void setNoOfSpursToTrack(byte noOfSpursToTrack) {
+        NoOfSpursToTrack = noOfSpursToTrack;
+    }
+
+    public List<SpurDetails> getSpurDetailsList() {
+        return spurDetailsList;
+    }
+
+    public void setSpurDetailsList(List<SpurDetails> spurDetailsList) {
+        this.spurDetailsList = spurDetailsList;
+    }
+
+    public void addSpurDetails(SpurDetails spurDetails) {
+        if (spurDetailsList == null) {
+            spurDetailsList = new ArrayList<SpurDetails>();
+        }
+        spurDetailsList.add(spurDetails);
+    }
+
+}
+
diff --git a/qcom/fmradio/SpurDetails.java b/qcom/fmradio/SpurDetails.java
new file mode 100644
index 0000000..2683b1c
--- /dev/null
+++ b/qcom/fmradio/SpurDetails.java
@@ -0,0 +1,105 @@
+/*
+ * Copyright (c) 2014, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *        * Redistributions of source code must retain the above copyright
+ *            notice, this list of conditions and the following disclaimer.
+ *        * Redistributions in binary form must reproduce the above copyright
+ *            notice, this list of conditions and the following disclaimer in the
+ *            documentation and/or other materials provided with the distribution.
+ *        * Neither the name of The Linux Foundation nor
+ *            the names of its contributors may be used to endorse or promote
+ *            products derived from this software without specific prior written
+ *            permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NON-INFRINGEMENT ARE DISCLAIMED.    IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package qcom.fmradio;
+
+import java.util.List;
+
+public class SpurDetails {
+
+    private int RotationValue;
+    private byte LsbOfIntegrationLength;
+    private byte FilterCoefficeint;
+    private byte IsEnableSpur;
+    private byte SpurLevel;
+
+
+    public int getRotationValue() {
+        return RotationValue;
+    }
+
+    public void setRotationValue(int rotationValue) {
+        RotationValue = rotationValue;
+    }
+
+    public byte getLsbOfIntegrationLength() {
+        return LsbOfIntegrationLength;
+    }
+
+    public void setLsbOfIntegrationLength(byte lsbOfIntegrationLength) {
+        LsbOfIntegrationLength = lsbOfIntegrationLength;
+    }
+
+    public byte getFilterCoefficeint() {
+        return FilterCoefficeint;
+    }
+
+    public void setFilterCoefficeint(byte filterCoefficeint) {
+        FilterCoefficeint = filterCoefficeint;
+    }
+
+    public byte getIsEnableSpur() {
+        return IsEnableSpur;
+    }
+
+    public void setIsEnableSpur(byte isEnableSpur) {
+        IsEnableSpur = isEnableSpur;
+    }
+
+    public byte getSpurLevel() {
+        return SpurLevel;
+    }
+
+    public void setSpurLevel(byte spurLevel) {
+        SpurLevel = spurLevel;
+    }
+
+    SpurDetails(int RotationValue, byte LsbOfIntegrationLength,
+                byte FilterCoefficeint, byte IsEnableSpur, byte SpurLevel) {
+
+        this.RotationValue = RotationValue;
+        this.LsbOfIntegrationLength = LsbOfIntegrationLength;
+        this.IsEnableSpur = IsEnableSpur;
+        this.SpurLevel = SpurLevel;
+    }
+
+    public SpurDetails() {
+
+    }
+
+    public SpurDetails(SpurDetails spurDetails) {
+        if (spurDetails != null) {
+            this.RotationValue = spurDetails.RotationValue;
+            this.LsbOfIntegrationLength =
+                          spurDetails.LsbOfIntegrationLength;
+            this.IsEnableSpur = spurDetails.IsEnableSpur;
+            this.SpurLevel = spurDetails.SpurLevel;
+        }
+    }
+
+}
diff --git a/qcom/fmradio/SpurFileFormatConst.java b/qcom/fmradio/SpurFileFormatConst.java
new file mode 100644
index 0000000..e9c03aa
--- /dev/null
+++ b/qcom/fmradio/SpurFileFormatConst.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2014, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *        * Redistributions of source code must retain the above copyright
+ *            notice, this list of conditions and the following disclaimer.
+ *        * Redistributions in binary form must reproduce the above copyright
+ *            notice, this list of conditions and the following disclaimer in the
+ *            documentation and/or other materials provided with the distribution.
+ *        * Neither the name of The Linux Foundation nor
+ *            the names of its contributors may be used to endorse or promote
+ *            products derived from this software without specific prior written
+ *            permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NON-INFRINGEMENT ARE DISCLAIMED.    IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package qcom.fmradio;
+
+import java.util.regex.Pattern;
+
+public final class SpurFileFormatConst {
+    public static final String SPUR_MODE = "Mode";
+    public static final String SPUR_NUM_ENTRY = "SpurNumEntry";
+    public static final String SPUR_FREQ = "SpurFreq";
+    public static final String SPUR_NO_OF = "NoOfSpursToTrack";
+    public static final String SPUR_ROTATION_VALUE = "RotationValue";
+    public static final String SPUR_LSB_LENGTH = "LsbOfIntegrationLength";
+    public static final String SPUR_FILTER_COEFF = "FilterCoefficeint";
+    public static final String SPUR_IS_ENABLE = "IsEnableSpur";
+    public static final String SPUR_LEVEL = "SpurLevel";
+    public static final char COMMENT = '#';
+    public static final char DELIMETER = '=';
+    public static final Pattern SPACE_PATTERN = Pattern.compile("\\s");
+    public static int SPUR_DETAILS_FOR_EACH_FREQ_CNT = 5;
+
+    public enum LineType {
+        EMPTY_LINE,
+        SPUR_MODE_LINE,
+        SPUR_N_ENTRY_LINE,
+        SPUR_FR_LINE,
+        SPUR_NO_OF_LINE,
+        SPUR_ROT0_LINE,
+        SPUR_LSB0_LINE,
+        SPUR_FILTER0_LINE,
+        SPUR_ENABLE0_LINE,
+        SPUR_LEVEL0_LINE,
+    }
+}
diff --git a/qcom/fmradio/SpurFileParser.java b/qcom/fmradio/SpurFileParser.java
new file mode 100644
index 0000000..d9f494e
--- /dev/null
+++ b/qcom/fmradio/SpurFileParser.java
@@ -0,0 +1,227 @@
+/*
+ * Copyright (c) 2014, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *        * Redistributions of source code must retain the above copyright
+ *            notice, this list of conditions and the following disclaimer.
+ *        * Redistributions in binary form must reproduce the above copyright
+ *            notice, this list of conditions and the following disclaimer in the
+ *            documentation and/or other materials provided with the distribution.
+ *        * Neither the name of The Linux Foundation nor
+ *            the names of its contributors may be used to endorse or promote
+ *            products derived from this software without specific prior written
+ *            permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NON-INFRINGEMENT ARE DISCLAIMED.    IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package qcom.fmradio;
+
+import java.io.BufferedReader;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.Reader;
+import java.util.regex.Matcher;
+import android.util.Log;
+import qcom.fmradio.SpurFileFormatConst.LineType;
+
+public class SpurFileParser implements SpurFileParserInterface {
+
+    private static final String TAG = "SPUR";
+
+    private boolean parse(BufferedReader reader, SpurTable t) {
+        int entryFound = 0;
+
+        if (t == null ) {
+            return false;
+        }
+
+        if ((reader != null)) {
+            String line;
+            LineType lastLine = LineType.EMPTY_LINE;
+            int indexEqual;
+            int SpurFreq = 0;
+            byte NoOfSpursToTrack = 0;
+            int RotationValue = 0;
+            byte LsbOfIntegrationLength = 0;
+            byte FilterCoefficeint = 0;
+            byte IsEnableSpur = 0;
+            byte spurLevel = 0;
+            byte noOfSpursFreq = 0;
+            byte mode;
+            byte freqCnt = 0;
+
+            try {
+                 while(reader.ready() && (line = reader.readLine()) != null) {
+                     line = removeSpaces(line);
+                     System.out.println("line : " + line);
+                     if (lineIsComment(line)) {
+                         continue;
+                     }
+                     if ((entryFound == 2) && (freqCnt <= noOfSpursFreq)) {
+                         if ((lastLine == LineType.EMPTY_LINE) &&
+                              lineIsOfType(line, SpurFileFormatConst.SPUR_FREQ)) {
+
+                             indexEqual = line.indexOf(SpurFileFormatConst.DELIMETER);
+                             SpurFreq = Integer.parseInt(line.substring(indexEqual + 1));
+                             lastLine = LineType.SPUR_FR_LINE;
+                             freqCnt++;
+                         } else if((lastLine == LineType.SPUR_FR_LINE) &&
+                                    lineIsOfType(line, SpurFileFormatConst.SPUR_NO_OF)) {
+
+                             indexEqual = line.indexOf(SpurFileFormatConst.DELIMETER);
+                             NoOfSpursToTrack = Byte.parseByte(line.substring(indexEqual + 1));
+                             Spur spur = new Spur();
+                             spur.setSpurFreq(SpurFreq);
+                             spur.setNoOfSpursToTrack(NoOfSpursToTrack);
+                             for(int i = 0; i < 3; i++) {
+                                 SpurDetails spurDetails = new SpurDetails();
+                                 for(int j = 0; (reader.ready()) &&
+                                   (j < SpurFileFormatConst.SPUR_DETAILS_FOR_EACH_FREQ_CNT); j++) {
+
+                                     line = reader.readLine();
+                                     line = removeSpaces(line);
+                                     System.out.println("inside line: " + line);
+                                     if (lineIsOfType(line,
+                                            (SpurFileFormatConst.SPUR_ROTATION_VALUE + i))) {
+
+                                         indexEqual = line.indexOf(SpurFileFormatConst.DELIMETER);
+                                         RotationValue = Integer.parseInt(
+                                                            line.substring(indexEqual + 1));
+                                         spurDetails.setRotationValue(RotationValue);
+                                     } else if(lineIsOfType(line,
+                                             SpurFileFormatConst.SPUR_LSB_LENGTH + i)) {
+
+                                         indexEqual = line.indexOf(SpurFileFormatConst.DELIMETER);
+                                         LsbOfIntegrationLength = Byte.parseByte(
+                                                            line.substring(indexEqual + 1));
+                                         spurDetails.setLsbOfIntegrationLength(
+                                                                    LsbOfIntegrationLength);
+                                     } else if(lineIsOfType(line,
+                                             SpurFileFormatConst.SPUR_FILTER_COEFF + i)) {
+
+                                         indexEqual = line.indexOf(SpurFileFormatConst.DELIMETER);
+                                         FilterCoefficeint = Byte.parseByte(
+                                                            line.substring(indexEqual + 1));
+                                         spurDetails.setFilterCoefficeint(FilterCoefficeint);
+                                     } else if(lineIsOfType(line,
+                                             SpurFileFormatConst.SPUR_IS_ENABLE + i)) {
+
+                                         indexEqual = line.indexOf(SpurFileFormatConst.DELIMETER);
+                                         IsEnableSpur = Byte.parseByte(
+                                                         line.substring(indexEqual + 1));
+                                         spurDetails.setIsEnableSpur(IsEnableSpur);
+                                     } else if(lineIsOfType(line,
+                                             SpurFileFormatConst.SPUR_LEVEL + i)) {
+
+                                         indexEqual = line.indexOf(SpurFileFormatConst.DELIMETER);
+                                         spurLevel = Byte.parseByte(line.substring(indexEqual + 1));
+                                         spurDetails.setSpurLevel(spurLevel);
+                                     }
+                                 }
+                                 spur.addSpurDetails(spurDetails);
+                             }
+                             t.InsertSpur(spur);
+                             lastLine = LineType.EMPTY_LINE;
+                         } else {
+                             return false;
+                         }
+                     } else if(entryFound == 1) {
+                         if (lineIsOfType(line, SpurFileFormatConst.SPUR_NUM_ENTRY)) {
+                             indexEqual = line.indexOf(SpurFileFormatConst.DELIMETER);
+                             noOfSpursFreq = Byte.parseByte(line.substring(indexEqual + 1));
+                             t.SetspurNoOfFreq(noOfSpursFreq);
+                             entryFound++;
+                         } else {
+                               return false;
+                         }
+                     } else {
+                         if (lineIsOfType(line, SpurFileFormatConst.SPUR_MODE)) {
+                             indexEqual = line.indexOf(SpurFileFormatConst.DELIMETER);
+                             mode = Byte.parseByte(line.substring(indexEqual + 1));
+                             t.SetMode(mode);
+                             entryFound++;
+                         } else {
+                             return false;
+                         }
+                     }
+                 } // END of while
+            } catch (NumberFormatException e) {
+                 Log.d(TAG, "NumberFormatException");
+                 e.printStackTrace();
+                 return false;
+            } catch (IOException e) {
+                 Log.d(TAG, "IOException");
+                 e.printStackTrace();
+                 return false;
+            }
+        } else {
+            return false;
+        }
+        return true;
+    }
+
+    private String removeSpaces(String s) {
+        Matcher matcher = SpurFileFormatConst.SPACE_PATTERN.matcher(s);
+        String newLine = matcher.replaceAll("");
+        return newLine;
+    }
+
+    private boolean lineIsOfType(String line, String lineType) {
+        int indexEqual;
+
+        try {
+             indexEqual = line.indexOf(SpurFileFormatConst.DELIMETER);
+             if ((indexEqual >= 0) && indexEqual < line.length()) {
+                 if (line.startsWith(lineType)) {
+                     int num = Integer.parseInt(line.substring(indexEqual + 1));
+                 } else {
+                     return false;
+                 }
+             } else {
+                 return false;
+             }
+        } catch (NumberFormatException e) {
+             return false;
+        }
+        return true;
+    }
+
+    private boolean lineIsComment(String s) {
+        if ((s == null) || (s == "") || (s == " ") || s.length() == 0) {
+            return true;
+        } else if(s.charAt(0) == SpurFileFormatConst.COMMENT) {
+            return true;
+        } else {
+            return false;
+        }
+    }
+
+    @Override
+    public SpurTable GetSpurTable(String fileName) {
+        BufferedReader reader = null;
+        SpurTable t = new SpurTable();
+        try {
+             reader = new BufferedReader(new InputStreamReader(new FileInputStream(fileName)));
+             parse(reader, t);
+             reader.close();
+        } catch (IOException e) {
+             e.printStackTrace();
+        }
+        return t;
+    }
+
+}
diff --git a/qcom/fmradio/SpurFileParserInterface.java b/qcom/fmradio/SpurFileParserInterface.java
new file mode 100644
index 0000000..e151769
--- /dev/null
+++ b/qcom/fmradio/SpurFileParserInterface.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2014, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *        * Redistributions of source code must retain the above copyright
+ *            notice, this list of conditions and the following disclaimer.
+ *        * Redistributions in binary form must reproduce the above copyright
+ *            notice, this list of conditions and the following disclaimer in the
+ *            documentation and/or other materials provided with the distribution.
+ *        * Neither the name of The Linux Foundation nor
+ *            the names of its contributors may be used to endorse or promote
+ *            products derived from this software without specific prior written
+ *            permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NON-INFRINGEMENT ARE DISCLAIMED.    IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package qcom.fmradio;
+
+public interface SpurFileParserInterface {
+
+    SpurTable GetSpurTable(String fileName);
+}
diff --git a/qcom/fmradio/SpurTable.java b/qcom/fmradio/SpurTable.java
new file mode 100644
index 0000000..fd65c58
--- /dev/null
+++ b/qcom/fmradio/SpurTable.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2014, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *        * Redistributions of source code must retain the above copyright
+ *            notice, this list of conditions and the following disclaimer.
+ *        * Redistributions in binary form must reproduce the above copyright
+ *            notice, this list of conditions and the following disclaimer in the
+ *            documentation and/or other materials provided with the distribution.
+ *        * Neither the name of The Linux Foundation nor
+ *            the names of its contributors may be used to endorse or promote
+ *            products derived from this software without specific prior written
+ *            permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NON-INFRINGEMENT ARE DISCLAIMED.    IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package qcom.fmradio;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class SpurTable {
+
+    private byte mode;
+    private byte spurNoOfFreq;
+    private List <Spur> spurs;
+
+    SpurTable() {
+        this.mode = -1;
+        this.spurNoOfFreq = 0;
+        this.spurs = null;
+    }
+
+    public List <Spur> GetSpurList() {
+        return spurs;
+    }
+
+    public void SetspurNoOfFreq(byte spurNoOfFreq) {
+        this.spurNoOfFreq = spurNoOfFreq;
+    }
+
+    public void SetMode(byte mode) {
+        this.mode = mode;
+    }
+
+    public void InsertSpur(Spur s) {
+        if (spurs == null) {
+            spurs = new ArrayList<Spur>();
+        }
+        spurs.add(s);
+    }
+
+    public byte GetMode() {
+        return mode;
+    }
+
+    public byte GetspurNoOfFreq() {
+        return spurNoOfFreq;
+    }
+}