audio: TFA9887 driver
Vinod Subbarayalu [Wed, 14 Nov 2012 23:10:53 +0000 (15:10 -0800)]
Change-Id: I415485bb8aa6723c98d2991df9456eea49a65e7f
Signed-off-by: Vinod Subbarayalu <vsubbarayalu@nvidia.com>
(cherry picked from commit 69f4d8348cccc232b82fbcc26b8ff49efcbb0b4c)
Reviewed-on: http://git-master/r/166415
Reviewed-by: Scott Peterson <speterson@nvidia.com>

arch/arm/mach-tegra/board-roth.c
drivers/misc/Makefile
drivers/misc/tfa9887.c [new file with mode: 0644]
include/linux/tfa9887.h [new file with mode: 0644]
sound/soc/tegra/tegra_rt5640.c

index 430de58..29b5e2b 100644 (file)
@@ -41,7 +41,6 @@
 #include <linux/leds.h>
 #include <linux/i2c/at24.h>
 #include <linux/of_platform.h>
-
 #include <asm/hardware/gic.h>
 
 #include <mach/clk.h>
@@ -207,6 +206,14 @@ static struct tegra_i2c_platform_data roth_i2c5_platform_data = {
 static struct i2c_board_info __initdata rt5640_board_info = {
        I2C_BOARD_INFO("rt5640", 0x1c),
 };
+
+static struct i2c_board_info __initdata roth_codec_tfa9887R_info = {
+       I2C_BOARD_INFO("tfa9887R", 0x37),
+};
+
+static struct i2c_board_info __initdata roth_codec_tfa9887L_info = {
+       I2C_BOARD_INFO("tfa9887L", 0x36),
+};
 #endif
 
 static void roth_i2c_init(void)
@@ -224,6 +231,8 @@ static void roth_i2c_init(void)
        platform_device_register(&tegra11_i2c_device1);
 
        i2c_register_board_info(0, &rt5640_board_info, 1);
+       i2c_register_board_info(0, &roth_codec_tfa9887R_info, 1);
+       i2c_register_board_info(0, &roth_codec_tfa9887L_info, 1);
 }
 
 static struct platform_device *roth_uart_devices[] __initdata = {
index 2090195..dd36277 100644 (file)
@@ -65,3 +65,4 @@ obj-$(CONFIG_APANIC)          += apanic.o
 obj-$(CONFIG_THERM_EST)                += therm_est.o
 obj-$(CONFIG_TEGRA_THROUGHPUT) += tegra-throughput.o
 obj-$(CONFIG_SND_SOC_TEGRA_CS42L73)    += a2220.o
+obj-y                          += tfa9887.o
diff --git a/drivers/misc/tfa9887.c b/drivers/misc/tfa9887.c
new file mode 100644 (file)
index 0000000..b7a09b2
--- /dev/null
@@ -0,0 +1,1018 @@
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/i2c.h>
+#include <linux/regmap.h>
+#include <linux/tfa9887.h>
+#include <sound/initval.h>
+#include <linux/sysfs.h>
+#include <linux/miscdevice.h>
+
+static ssize_t tfa9887_cal_show(struct kobject *kobj,
+               struct kobj_attribute *attr, char *buf);
+
+static ssize_t tfa9887_cal_store(struct kobject *kobj,
+               struct kobj_attribute *attr, const char *buf, size_t count);
+
+static ssize_t tfa9887_config_show(struct kobject *kobj,
+               struct kobj_attribute *attr, char *buf);
+
+static ssize_t tfa9887_config_store(struct kobject *kobj,
+               struct kobj_attribute *attr, const char *buf, size_t count);
+
+static ssize_t tfa9887_vol_show(struct kobject *kobj,
+               struct kobj_attribute *attr, char *buf);
+
+static ssize_t tfa9887_vol_store(struct kobject *kobj,
+               struct kobj_attribute *attr, const char *buf, size_t count);
+
+
+static struct kobj_attribute tfa9887_config =
+               __ATTR(config, 0640, tfa9887_config_show, tfa9887_config_store);
+
+static struct kobj_attribute tfa9887_cal =
+               __ATTR(cal, 0640, tfa9887_cal_show, tfa9887_cal_store);
+
+static struct kobj_attribute tfa9887_vol =
+               __ATTR(vol, 0640, tfa9887_vol_show, tfa9887_vol_store);
+
+static struct kobject *tfa9887_kobj;
+
+static struct tfa9887_priv *tfa9887R, *tfa9887L;
+
+/* begin binary data: */
+unsigned char coldpatch_data[] = {/* 10 */
+0x08,0x00,0x70,0x00,0x07,0x81,0x00,0x00,0x00,0x01
+};
+/* end binary data. size = 10 bytes */
+
+/* begin binary data: */
+unsigned char n1d2_data[] = {/* 2224 */
+ 0x03,0x00,0x70,0x00,0x01,0xFB,0x00,0x71,0x40,0x00,0x6A,0x7E,0xFD,0x04,0x3A
+,0x91,0x00,0xC7,0x6A,0x3F,0x42,0x90,0x3A,0x92,0xFF,0xE9,0x71,0x24,0x58,0x7F
+,0x30,0x60,0x00,0x80,0x3B,0x80,0x00,0xB6,0xB8,0xA2,0xD5,0x7C,0xB5,0x00,0x54
+,0xBE,0x38,0x20,0x0A,0x6F,0xB5,0x00,0x76,0x08,0x30,0x12,0x00,0x00,0xB5,0x00
+,0x40,0x00,0xA0,0x00,0xD5,0x3C,0xB5,0x00,0x40,0x40,0x3A,0x9A,0xFF,0x50,0xB5
+,0x00,0x44,0x18,0x38,0x08,0x22,0x13,0xB5,0x00,0x42,0x90,0x3A,0x80,0x00,0x3E
+,0xD0,0x24,0x42,0x80,0xB5,0x00,0x7E,0x9C,0x82,0x14,0x7E,0x9C,0x3B,0x47,0x40
+,0x1F,0x3A,0x83,0x00,0x07,0x9B,0xC5,0x61,0x40,0x9B,0xC6,0x55,0x3D,0x3A,0x92
+,0x00,0x09,0xB5,0x00,0x42,0x10,0xD0,0x24,0x7E,0x9C,0x70,0xA0,0x7E,0x9C,0xB5
+,0x00,0x42,0x00,0x3A,0x80,0x00,0x9B,0xD0,0x24,0x54,0x7C,0x30,0x70,0x00,0x80
+,0xB5,0x00,0x61,0x40,0x3B,0x80,0x00,0xA9,0x90,0xD9,0x62,0x09,0x7F,0x4E,0x54
+,0xBC,0x6A,0x1F,0x4C,0x08,0x3B,0x80,0x01,0x0E,0x30,0x50,0x00,0x80,0xB5,0x00
+,0x58,0x3F,0x3C,0xD8,0x03,0x00,0x8B,0x80,0x7D,0x7C,0xB5,0x00,0x7E,0x9C,0x98
+,0x99,0xFD,0x06,0x9B,0x0C,0x52,0x7B,0xA6,0x18,0x58,0x7A,0x39,0x02,0x22,0x1C
+,0x30,0x90,0x00,0xD8,0x30,0xB0,0x20,0x94,0x30,0xA0,0x00,0xE4,0x20,0x03,0x40
+,0x40,0xA8,0x00,0xD4,0xFC,0xB5,0x00,0x5A,0x7D,0x62,0x08,0x66,0x0B,0x3A,0x31
+,0xFF,0xFE,0x3B,0x80,0x02,0x08,0x9B,0xC0,0xD5,0x7F,0x80,0xB0,0x54,0xBC,0x3A
+,0x89,0x00,0x04,0xFB,0x00,0x71,0x40,0x3E,0x6A,0x9F,0xD5,0xBE,0x6A,0x7E,0x44
+,0x51,0x3A,0x9B,0x00,0x05,0xB5,0x00,0x52,0xFC,0x30,0x90,0x00,0xD8,0x30,0xA0
+,0x00,0xE4,0x30,0xB0,0x20,0x94,0x20,0x03,0x40,0x50,0x6A,0x7E,0xD2,0x3D,0x80
+,0xB0,0x66,0x0B,0xB5,0x00,0x44,0x10,0x3A,0x31,0xFF,0xFE,0x3B,0x80,0x02,0x08
+,0x9B,0xC0,0xD5,0x7F,0x6A,0xDF,0x54,0xBD,0x3A,0x89,0x00,0x04,0x62,0x28,0xD5
+,0x3F,0x3A,0x9B,0x00,0x05,0xB5,0x00,0x54,0xFD,0x9B,0xAC,0x52,0x3C,0xA6,0x12
+,0xD2,0x3B,0x39,0x02,0x22,0x1C,0xA6,0x52,0xD8,0x3A,0xA8,0x00,0xFE,0x9C,0x3C
+,0xD8,0x03,0x00,0xA9,0x01,0x7D,0x7A,0xB5,0x00,0x61,0x34,0x71,0x44,0x7D,0x03
+,0x6A,0x7E,0xC4,0x08,0xB5,0x00,0x58,0x7F,0x30,0x50,0x00,0x80,0x3B,0x80,0x01
+,0x25,0xB5,0x00,0x55,0x7E,0x6A,0xDE,0xD5,0x3E,0x62,0x4C,0xC4,0x11,0x38,0x20
+,0x0A,0x6F,0x6A,0xFE,0xE1,0x50,0xB5,0x00,0x55,0x7E,0x30,0x40,0x00,0x80,0x3B
+,0x80,0x01,0x00,0xB0,0xB2,0xF6,0x00,0x6A,0x1F,0x54,0xBD,0x3B,0x80,0x01,0x00
+,0x9B,0xA6,0xFE,0x9C,0xB5,0x00,0x58,0x3F,0x3C,0xD8,0x03,0x00,0x8B,0x80,0x7D
+,0x7D,0xB5,0x00,0x7E,0x9C,0x38,0x08,0x0A,0x6F,0x9B,0xA6,0x7D,0x04,0xB0,0xB6
+,0x62,0x88,0x69,0x7E,0xC4,0x08,0x6A,0xBF,0x54,0xFC,0xB5,0x00,0x58,0x7F,0x3B
+,0x80,0x01,0x25,0x30,0x50,0x00,0x80,0x69,0x5E,0xD5,0x3C,0x72,0x02,0xC4,0x11
+,0x6A,0x1F,0x76,0x40,0x30,0x40,0x00,0x80,0x3B,0x80,0x01,0x00,0xB0,0xB2,0xD5
+,0x7C,0xFB,0x00,0x71,0x40,0x7C,0x9B,0xA6,0xD4,0x3E,0xB5,0x00,0x54,0xBC,0x3B
+,0x80,0x01,0x00,0x3A,0x80,0x00,0x80,0xB5,0x00,0x58,0x3F,0x3C,0xD8,0x03,0x00
+,0x8B,0x80,0x7D,0x7C,0xB5,0x00,0x7E,0x9C,0x9B,0x86,0x7D,0x04,0x38,0x0A,0x0A
+,0x6F,0xB0,0xB2,0xD4,0x7E,0x6A,0x7E,0x52,0xFD,0x71,0x04,0xD8,0x7F,0x3B,0x80
+,0x01,0x25,0x30,0x50,0x00,0x80,0x69,0x5E,0xD5,0x3E,0x72,0x02,0xC4,0x11,0x6A
+,0xBE,0xD4,0xBC,0x30,0x40,0x00,0x80,0x3B,0x80,0x01,0x00,0xB0,0xB2,0xF6,0x00
+,0xB5,0x00,0x54,0x3C,0x3A,0x88,0x00,0x80,0xB5,0x00,0x54,0x3D,0x3B,0x80,0x01
+,0x00,0x9B,0xA6,0xFE,0x9C,0xB5,0x00,0x58,0x3F,0x3C,0xD8,0x03,0x00,0x8B,0x80
+,0x7D,0x7C,0xB5,0x00,0x7E,0x9C,0x3A,0x88,0x00,0x0A,0x9B,0x8C,0x42,0x88,0xA6
+,0x56,0x7D,0x05,0x39,0x02,0x22,0x20,0xAA,0x08,0xC4,0x00,0x3A,0x89,0x00,0xA6
+,0xBA,0x41,0x58,0x7B,0x6E,0x3F,0x54,0x7C,0x3B,0x80,0x13,0x20,0xBA,0x20,0xDA
+,0x7D,0x6D,0x5E,0xD0,0xBE,0x3A,0x81,0x00,0x18,0x82,0x04,0x7E,0x40,0x3A,0x90
+,0xFF,0xFA,0xBF,0x10,0x4C,0x90,0xBB,0x00,0x55,0x7D,0x31,0x80,0x20,0xAF,0x3B
+,0x80,0x01,0x07,0x9B,0xA2,0xCA,0x48,0x7F,0x4E,0x54,0xBD,0xB5,0x00,0x4C,0x88
+,0x3A,0x91,0xFF,0x43,0xB5,0x00,0x42,0x90,0x96,0xF4,0xD5,0xBC,0x3A,0x81,0xFF
+,0x41,0x3A,0x93,0x00,0x29,0x61,0x48,0xFD,0xA9,0x3A,0x88,0x00,0xAF,0x61,0x8A
+,0x72,0xE8,0x6A,0x7E,0xC4,0x00,0x30,0x40,0x00,0x80,0x30,0x70,0x02,0xBC,0xFB
+,0x00,0x71,0x40,0xBA,0x3B,0x80,0x1C,0x5A,0xB5,0x00,0x55,0x7C,0xB5,0x00,0x54
+,0x3D,0x3A,0x88,0x00,0x0F,0x62,0x24,0x44,0x0A,0x3A,0x91,0xFF,0x4F,0x30,0x50
+,0x00,0x80,0x3B,0x80,0x01,0x25,0xB5,0x00,0x55,0x7D,0x6A,0xDE,0x54,0xBD,0x3A
+,0x81,0xFF,0xF3,0x72,0x22,0xC2,0x84,0x30,0xA0,0x0A,0x70,0x61,0x04,0x42,0x98
+,0x7F,0x2C,0x76,0x91,0x38,0x00,0x22,0x08,0x61,0x88,0x40,0x48,0x69,0x3F,0x54
+,0x7D,0xB5,0x00,0x52,0xFF,0x3B,0x80,0x1B,0x5B,0x38,0x0D,0x0A,0x6F,0x30,0x00
+,0x00,0x20,0xB9,0x00,0x54,0x3D,0x9B,0x2B,0x55,0x3C,0xB0,0x04,0x52,0xBE,0x38
+,0x08,0x22,0x01,0xA6,0xD0,0x52,0x3F,0x3A,0x80,0x00,0x0F,0x8B,0x80,0x42,0x50
+,0x9B,0xA2,0x42,0xC0,0x3A,0x88,0x00,0xB4,0xB5,0x00,0x53,0x7C,0x31,0x1F,0xFF
+,0xE9,0x69,0x3F,0x44,0x0D,0x3B,0x80,0x01,0x25,0xB5,0x00,0x54,0xFD,0x7F,0x4E
+,0x54,0x3D,0xB5,0x00,0x44,0x00,0x3B,0x80,0x01,0x25,0x9B,0xA7,0x7E,0x9C,0x7D
+,0x8C,0x54,0x3D,0x7C,0x24,0xC4,0x85,0x6A,0x3E,0xD2,0xBC,0x61,0x64,0x44,0x00
+,0x3B,0x80,0x02,0xE4,0x30,0x50,0x00,0x80,0x9B,0xA2,0x52,0x3E,0x90,0x90,0xD4
+,0xBD,0xA2,0x12,0xFB,0x24,0xB5,0x00,0x4C,0x8D,0x3B,0x44,0x40,0xDA,0x31,0x10
+,0x00,0x1C,0xB5,0x00,0x4C,0xCD,0xB5,0x00,0x58,0x3B,0x3C,0xD8,0x03,0x00,0x8B
+,0x80,0x7D,0x7B,0xB5,0x00,0x7E,0x9C,0x6C,0x3F,0xFD,0x02,0x3B,0x80,0x10,0xA5
+,0xB5,0x00,0x54,0x7E,0xB5,0x00,0x54,0x3E,0x3A,0x98,0x00,0x5C,0xFB,0x00,0x71
+,0x40,0xF8,0x30,0x40,0x00,0x82,0x7F,0x2C,0xC2,0x59,0x3A,0xAB,0xFF,0xDE,0x7F
+,0x2C,0x78,0x6B,0x39,0x00,0x22,0x20,0x64,0x24,0x4A,0x49,0x3A,0x91,0xFF,0xFA
+,0x7F,0x30,0x79,0x14,0x3A,0x84,0x00,0x1A,0x3A,0xB0,0xFF,0xC4,0x30,0x45,0x00
+,0x00,0x61,0x20,0x78,0xF5,0x30,0x11,0x00,0x00,0x38,0x04,0x22,0x01,0x38,0x10
+,0x26,0x91,0x60,0xA8,0x40,0xE8,0x7F,0x2C,0x42,0x70,0x3B,0x80,0x40,0x59,0x3A
+,0x8B,0xFF,0xF2,0xB5,0x00,0x58,0x3F,0x3C,0xD8,0x03,0x00,0x8B,0x80,0x7D,0x7E
+,0xB5,0x00,0x7E,0x9C,0x3C,0xD0,0x00,0x8E,0x3C,0xCB,0xFF,0xB4,0x82,0x14,0x52
+,0xF6,0x6C,0x3C,0xD4,0x78,0xB5,0x00,0x55,0xFA,0x3B,0x46,0x41,0x1C,0x95,0xD4
+,0xF9,0x1A,0xB5,0x00,0x53,0x77,0xB5,0x00,0x52,0xB6,0x3C,0xC5,0x41,0x1B,0x6A
+,0x5C,0x62,0x0C,0x61,0x84,0xFE,0x9C,0x7F,0x20,0xC3,0x41,0x3C,0xC9,0xFF,0x72
+,0x30,0xA0,0x02,0x17,0x9B,0xA0,0xE2,0x0B,0x9B,0xC0,0xD6,0x7B,0x9B,0x00,0xD4
+,0xFC,0x8B,0x80,0x55,0x7D,0x30,0xB0,0x21,0x2C,0x73,0x05,0xD3,0xB7,0xB5,0x00
+,0x52,0x7F,0x3B,0x80,0x01,0xDA,0x3A,0x31,0xFF,0xFE,0x6A,0x1E,0x54,0xBA,0x7C
+,0x01,0x78,0x4A,0x6A,0x7E,0x52,0xB7,0x3B,0x80,0x01,0x00,0xB5,0x00,0x54,0x7A
+,0x9B,0xC0,0xD2,0xBF,0x90,0x94,0xD5,0x3D,0x3A,0x92,0x00,0x04,0x92,0x11,0xD5
+,0xBE,0x6A,0x1E,0x54,0xBA,0x3A,0x9B,0x00,0x05,0x7C,0x27,0x78,0x06,0xB5,0x00
+,0x55,0x7D,0x3B,0x44,0x41,0x23,0x80,0x18,0x54,0x7A,0xFB,0x00,0x71,0x41,0x36
+,0x80,0xB8,0x54,0xFC,0xB5,0x00,0x52,0xB6,0x82,0x14,0x7E,0x9C,0x3B,0x46,0x41
+,0x42,0x6A,0x5D,0xD4,0x38,0x3C,0xC5,0x41,0x3F,0xB5,0x00,0x43,0x0B,0x94,0x18
+,0xFE,0x9C,0xB5,0x00,0x43,0x0B,0x94,0x18,0xC0,0x41,0x3B,0x00,0x41,0x43,0xB5
+,0x00,0x58,0x39,0xB5,0x00,0x58,0x39,0x3C,0xD8,0x03,0x00,0x8B,0x80,0x7E,0x9C
+,0x3C,0xD0,0xFF,0x72,0x71,0x65,0x7D,0x2B,0x6A,0x7B,0xC2,0x91,0x6A,0xBC,0x62
+,0x4B,0x6A,0x3D,0xD2,0xF9,0xB5,0x00,0x58,0x7C,0x3B,0x80,0x16,0x94,0xB5,0x00
+,0x54,0xFA,0x7C,0x44,0xD4,0xB9,0x6A,0x1C,0x42,0x91,0x61,0xC0,0x7E,0x9C,0x6A
+,0xBE,0xD4,0xB7,0x3B,0x80,0x00,0xA9,0x9B,0xC3,0x62,0x09,0x6A,0xDC,0x54,0x3D
+,0x3A,0x90,0x00,0x10,0x61,0xCC,0x42,0x80,0x6A,0xBE,0xD4,0xBB,0x3B,0x80,0x00
+,0xA9,0x9B,0xC3,0x62,0x09,0x9B,0xA0,0xD4,0x38,0x3A,0x88,0x00,0x96,0x66,0x04
+,0x45,0x0A,0x79,0x40,0xC3,0x80,0x3A,0x89,0xFF,0x6B,0x80,0x18,0x54,0x3B,0xB5
+,0x00,0x54,0xFE,0x3B,0x80,0x02,0x8F,0x80,0xD4,0x74,0x57,0x7F,0x4E,0x54,0xBE
+,0xB5,0x00,0x42,0x88,0x3A,0x81,0x00,0x5B,0x6A,0x3F,0xD4,0xBB,0x3B,0x80,0x01
+,0x00,0x3C,0xC8,0xFF,0xD7,0x7F,0x4E,0x54,0xBF,0xB5,0x00,0x42,0x88,0x82,0x14
+,0x54,0x3A,0x3A,0x80,0x00,0x5C,0x3B,0x43,0x41,0x7C,0x6A,0x3C,0x55,0x38,0x3A
+,0x8A,0x00,0x95,0x31,0x1F,0xFF,0x6A,0x9B,0xA0,0xCC,0x0D,0x6A,0x7F,0xC3,0x90
+,0x6A,0x1B,0xF2,0x81,0xB5,0x00,0x74,0x57,0xFB,0x00,0x71,0x41,0x74,0x30,0xA0
+,0x0E,0xBA,0x3B,0x80,0x02,0x8F,0x80,0x18,0x61,0x85,0x6A,0x5D,0xD5,0x3F,0x3B
+,0x80,0x1A,0x0A,0x3C,0xC8,0xFF,0xD7,0x3B,0x00,0x41,0x7D,0xB5,0x00,0x54,0xBD
+,0xB5,0x00,0x54,0xBD,0x61,0x44,0x7E,0x9C,0x98,0xB5,0x54,0xBE,0xB5,0x00,0x7E
+,0x9C,0x82,0x14,0x43,0x08,0x3B,0x63,0x41,0x86,0xB5,0x00,0x54,0x37,0x3B,0x80
+,0x01,0x00,0x80,0xB8,0x74,0x57,0x3B,0x20,0x41,0x8F,0x6A,0x1D,0x54,0xB9,0x3A
+,0x89,0x00,0x22,0x3A,0x80,0x00,0x14,0x61,0xC4,0x42,0x80,0xD0,0x6C,0x74,0x57
+,0x30,0xA0,0x07,0xA1,0x94,0x03,0xD4,0x37,0x3B,0x80,0x00,0x14,0xB5,0x00,0x61
+,0x40,0x9B,0xA0,0xD4,0xBE,0x3A,0x81,0x00,0x97,0x61,0xC4,0x45,0x04,0x31,0x0F
+,0xFF,0x6A,0x6A,0x3C,0xCC,0x05,0x6A,0x5B,0xF2,0x81,0xB5,0x00,0x74,0x17,0x3B
+,0x80,0x02,0x8F,0x80,0x18,0x61,0x85,0x6A,0x5D,0xD5,0x39,0xB5,0x00,0x54,0x37
+,0x3B,0x80,0x17,0x99,0xB5,0x00,0x7E,0x9C,0x92,0x13,0xD4,0xB8,0x3B,0x62,0x41
+,0xB4,0x8B,0x80,0x42,0x88,0x90,0xB7,0xF8,0x0B,0xB2,0xD2,0xC2,0x80,0x92,0x17
+,0xC3,0x48,0x3B,0x42,0x41,0xB2,0xB5,0x00,0x54,0x3A,0x3A,0x90,0x00,0x5D,0xB5
+,0x00,0x43,0x10,0x82,0x18,0x7E,0x9C,0x3B,0x66,0x41,0xB2,0x3A,0x88,0x00,0x5E
+,0xB5,0x00,0x43,0x08,0x90,0xD8,0xFE,0x9C,0xA2,0x1A,0xC3,0x48,0x3B,0x66,0x41
+,0xB0,0x6C,0x1E,0x7E,0x4A,0x3B,0x00,0x41,0xB5,0xB5,0x00,0x7E,0x48,0x3B,0x00
+,0x41,0xB5,0xB5,0x00,0x58,0x3C,0x4B,0x00,0x71,0x41,0xB2,0x3B,0x00,0x41,0xB5
+,0xB5,0x00,0x58,0x3C,0x9B,0x9F,0xD8,0x3C,0x3C,0xD8,0x03,0x00,0x7F,0x4E,0x7D
+,0x55,0x39,0x84,0x80,0x02,0x39,0x86,0x80,0x02,0x30,0x40,0x01,0x00,0xA8,0x1E
+,0x7E,0x9C,0xA2,0x02,0x7E,0x9C,0x3B,0x43,0x41,0xC1,0x30,0x10,0x01,0xFF,0xA8
+,0x38,0xFE,0x9C,0x30,0x4F,0xFE,0x00,0xA9,0x26,0x7E,0x9C,0x3C,0xD8,0x03,0x00
+,0x9B,0x99,0x7E,0x9C,0xA0,0x86,0x7E,0x9C,0x93,0x00,0x71,0x41,0xDB,0x72,0x28
+,0x7B,0x01,0x32,0x00,0x40,0xA0,0x32,0x40,0x40,0xC0,0x32,0x80,0x41,0x00,0x7D
+,0xC1,0xFC,0x04,0x3B,0x00,0x41,0xF8,0x8B,0x20,0x68,0x60,0x38,0x14,0x00,0xD2
+,0x38,0x12,0x00,0xD5,0x38,0x10,0x00,0xD4,0x82,0x10,0x7E,0x9C,0x3B,0x45,0x41
+,0xF0,0x38,0x30,0x00,0xCF,0xB5,0x00,0x62,0xD8,0x60,0x09,0xE3,0x0A,0x60,0x24
+,0x78,0xDB,0x71,0xA5,0x40,0x1A,0x60,0x00,0x40,0x52,0x60,0x0C,0x40,0x50,0x3B
+,0x00,0x41,0xF2,0xB5,0x00,0x40,0x68,0x7F,0x29,0xE3,0x0A,0x7F,0x28,0x7E,0x48
+,0x90,0x24,0x81,0xA3,0x60,0x07,0xCC,0xA7,0x38,0x11,0x00,0xD4,0x38,0x31,0x00
+,0xCF,0x38,0x19,0x00,0xD2,0x38,0x13,0x00,0xD5,0x38,0x00,0x00,0xEF,0xA2,0x04
+,0x7E,0x9C,0x3B,0x64,0x41,0xE2,0x38,0x10,0x00,0xD4,0x38,0x20,0x00,0xA2,0x3C
+,0xD8,0x03,0x00,0xB5,0x00,0x42,0x07,0x03,0x00,0x70,0x00,0x03,0x21,0x00,0x71
+,0x0A,0x6F,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x01,0x00,0x00,0x01,0x00
+,0x00,0x02,0x00,0x00,0x02,0x00,0x00,0x02,0x00,0x00,0x06,0x00,0x00,0x06,0x00
+,0x00,0x06,0x03,0x00,0x70,0x00,0x05,0x03,0x00,0x70,0x00,0x07,0x7B,0x00,0x71
+,0x03,0x00,0x00,0x00,0x01,0x00,0x1B,0xA7,0x00,0x40,0x00,0x00,0x3B,0x80,0x00
+,0x00,0x01,0x00,0x03,0xE7,0x00,0x40,0x2E,0x00,0x3B,0x80,0x00,0x00,0x01,0x00
+,0x0B,0x0D,0x00,0x40,0x59,0x00,0x3B,0x80,0x00,0x00,0x01,0x00,0x0B,0x23,0x00
+,0x40,0x6E,0x00,0x3B,0x80,0x00,0x00,0x01,0x00,0x0B,0xAB,0x00,0x40,0x84,0x00
+,0x3B,0x80,0x00,0x00,0x01,0x00,0x0D,0xF5,0x00,0x40,0x9A,0x00,0x3B,0x80,0x00
+,0x00,0x01,0x00,0x0D,0x24,0x00,0x41,0x46,0x00,0x3B,0x80,0x00,0x00,0x01,0x00
+,0x0A,0x6B,0x00,0x40,0xF3,0x00,0x3B,0x80,0x00,0x00,0x01,0x00,0x05,0xC6,0x00
+,0x41,0x0F,0x00,0x3B,0x80,0x00,0x00,0x01,0x00,0x05,0x7B,0x00,0x41,0xB7,0x00
+,0x3B,0x80,0x03,0x00,0x70,0x00,0x00,0x23,0x00,0x70,0x00,0x02,0x00,0x01,0x00
+,0x80,0x03,0x00,0x00,0x19,0x00,0x00,0x17,0x00,0x00,0x16,0x00,0x00,0x1D,0x00
+,0x00,0x1B,0x00,0x00,0x1B,0x00,0x00,0x1E,0x00,0x00,0x1C,0x00,0x00,0x1C,0x03
+,0x00,0x70,0x01,0x12
+};
+/* end binary data. size = 2224 bytes */
+
+/* begin binary data: */
+unsigned char speaker_data[] = { /* 423 */
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+,0xFF,0xFC,0x03,0xFF,0xF8,0x41,0xFF,0xFD,0x44,0xFF,0xFD,0x9A,0x00,0x04,0xCA
+,0xFF,0xFB,0xD7,0x00,0x02,0x1A,0x00,0x01,0x28,0xFF,0xFF,0xBE,0xFF,0xF7,0x7D
+,0xFF,0xFD,0x0C,0xFF,0xF9,0x11,0x00,0x02,0x4A,0x00,0x00,0xF4,0xFF,0xF6,0x91
+,0x00,0x03,0x83,0x00,0x05,0xA7,0xFF,0xFA,0x1E,0xFF,0xFE,0x25,0xFF,0xF9,0xC4
+,0xFF,0xF8,0x65,0xFF,0xFE,0x43,0xFF,0xFC,0x41,0xFF,0xFD,0xDD,0xFF,0xFD,0xCD
+,0x00,0x03,0x15,0x00,0x01,0x9E,0xFF,0xF7,0x79,0xFF,0xF7,0x8B,0xFF,0xFF,0x1F
+,0xFF,0xFA,0x1A,0xFF,0xFB,0x89,0xFF,0xF8,0x78,0x00,0x02,0x91,0xFF,0xFF,0xBB
+,0xFF,0xFB,0x13,0x00,0x03,0x01,0x00,0x01,0x84,0xFF,0xF8,0x5D,0xFF,0xF1,0x38
+,0xFF,0xFE,0xEA,0xFF,0xF7,0x12,0x00,0x02,0xED,0xFF,0xFB,0x8D,0x00,0x00,0xF5
+,0x00,0x02,0x62,0xFF,0xF7,0xE0,0xFF,0xFA,0x0D,0xFF,0xFE,0x76,0xFF,0xFD,0xFC
+,0xFF,0xF8,0x46,0xFF,0xF5,0x6C,0xFF,0xFB,0xCA,0x00,0x00,0x8E,0xFF,0xF7,0xF0
+,0xFF,0xFB,0xD4,0xFF,0xFC,0x6C,0x00,0x00,0x0D,0x00,0x06,0xE1,0x00,0x02,0x5D
+,0xFF,0xF6,0x23,0xFF,0xF9,0x7E,0xFF,0xF7,0x51,0xFF,0xF1,0xE1,0xFF,0xF9,0xD8
+,0xFF,0xEE,0xC5,0xFF,0xFB,0x11,0x00,0x0A,0xC3,0x00,0x18,0x1C,0x00,0x24,0x81
+,0x00,0x1B,0x9C,0x00,0x01,0xF7,0xFF,0xF1,0xF7,0xFF,0xCF,0x95,0xFF,0xBD,0x0D
+,0xFF,0xB3,0x57,0xFF,0xDE,0xD5,0xFF,0xFD,0xCB,0x00,0x35,0x80,0x00,0x67,0x11
+,0x00,0x7C,0x80,0x00,0x63,0x57,0x00,0x32,0x02,0xFF,0xBF,0x6F,0xFF,0xA6,0xD4
+,0x07,0x23,0x71,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x4F,0x70,0x1D
+,0x66,0x66,0x66,0x26,0x66,0x66,0x26,0x66,0x66,0x24,0xCC,0xCD,0x1E,0x66,0x67
+,0x00,0x02,0xE7,0x00,0x02,0xE7,0x04,0x00,0x00,0x00,0x45,0x1F,0x19,0x00,0x00
+,0x03,0x7B,0x4A
+};
+/* end binary data. size = 423 bytes */
+
+/* begin binary data: */
+unsigned char preset_data[] = { /* 87 */
+ 0x00,0x00,0x00,0x00,0x00,0xFA,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x1F,0x40
+,0x00,0x00,0x00,0x00,0x01,0x2C,0x01,0x47,0xAE,0x00,0x2B,0xB0,0x00,0x00,0x00
+,0x00,0x20,0xC5,0x00,0x80,0x00,0x00,0x00,0x00,0x0F,0x00,0x00,0x08,0x00,0x00
+,0x08,0x00,0x00,0x05,0x00,0x00,0x00,0x80,0x00,0x00,0x0C,0xCD,0x00,0x80,0x00
+,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x21
+,0x08,0x00,0x00,0x08,0x00,0x00,0x00,0x0C,0xCD,0x00,0x00,0x03
+};
+/* end binary data. size = 87 bytes */
+
+/* begin binary data: */
+unsigned char config_data[] = { /* 165 */
+ 0x09,0xF3,0x33,0x01,0x3E,0x66,0x00,0x51,0xEC,0x00,0x00,0x14,0x00,0x00,0x02
+,0x1A,0xDB,0xA7,0x1B,0x36,0x15,0x1C,0x4E,0xAD,0x00,0x00,0x00,0x00,0x00,0x01
+,0x00,0x00,0x02,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x21,0x00,0x00,0x21
+,0x00,0x00,0x00,0x00,0x00,0xFA,0x00,0x00,0x01,0x00,0x00,0x02,0x00,0x00,0x01
+,0x00,0x00,0x01,0x00,0x00,0x01,0x00,0x80,0x00,0x01,0x40,0x00,0x00,0x03,0x47
+,0x01,0x47,0xAE,0x00,0x19,0x9A,0x00,0x00,0x00,0x00,0x40,0x00,0x00,0x80,0x00
+,0x00,0x00,0x01,0x05,0x00,0x00,0x00,0x80,0x00,0x00,0x0F,0xFF,0x07,0xC2,0x8F
+,0x00,0x10,0x00,0x08,0x00,0x00,0x00,0x40,0x00,0x00,0x00,0x80,0x00,0x00,0x01
+,0x00,0x00,0x01,0x01,0x47,0xAE,0x00,0x00,0x40,0x00,0x00,0x00,0x19,0x99,0x9A
+,0x00,0x80,0x00,0x00,0x00,0x02,0x00,0x00,0x10,0x00,0x00,0x02,0x00,0x00,0x30
+,0xEC,0x00,0x00,0x00,0x03,0xD7,0x01,0x00,0x00,0x08,0x00,0x00,0x01,0x00,0x00
+};
+/* end binary data. size = 165 bytes */
+
+
+void convertBytes2Data(int num_bytes, const unsigned char bytes[], int data[])
+{
+        int i; /* index for data */
+        int k; /* index for bytes */
+        int d;
+        int num_data = num_bytes/3;
+
+        for (i = 0, k = 0; i < num_data; ++i, k += 3) {
+                d = (bytes[k] << 16) | (bytes[k+1] << 8) | (bytes[k+2]);
+                if (bytes[k] & 0x80) {/* sign bit was set*/
+                        d = - ((1<<24)-d);
+                }
+                data[i] = d;
+        }
+}
+
+int ProcessPatchFile(struct tfa9887_priv *tfa9887, int length, const unsigned char* bytes)
+{
+       unsigned int size;
+       int index = 0;
+       unsigned char buffer[MAX_I2C_LENGTH];
+       int error;
+        int value = 0;
+        unsigned int status;
+
+       error = Tfa9887_ReadRegister(tfa9887, TFA9887_STATUS, &status);
+       if (error == Tfa9887_Error_Ok) {
+               if ( (status & 0x0043) != 0x0043) {
+                       /* one of Vddd, PLL and clocks not ok */
+                       error = -1;
+               }
+       }
+       pr_info("tfa status %u\n",status);
+       error = DspReadMem(tfa9887, 0x2210, 1, &value);
+       pr_info("tfa Version  %x\n",value);
+       while (index < length) {
+               /* extract little endian length */
+               size = bytes[index] + bytes[index+1] * 256;
+               index += 2;
+               if ( (index + size) > length) {
+                       /* too big, outside the buffer, error in the input data */
+                       return -1;
+               }
+               memcpy(buffer, bytes + index, size);
+               error = regmap_raw_write(tfa9887->regmap, buffer[0], &buffer[1] ,(size -1) * 2);
+               if (error != Tfa9887_Error_Ok) {
+                       break;
+               }
+               index += size;
+       }
+       return error;
+}
+
+int DspReadMem(struct tfa9887_priv *tfa9887, unsigned short start_offset, int num_words, int *pValues)
+{
+       unsigned int cf_ctrl; /* the value to sent to the CF_CONTROLS register */
+       unsigned char bytes[MAX_I2C_LENGTH];
+       int burst_size; /* number of words per burst size */
+       int bytes_per_word=3;
+       int num_bytes;
+       int* p;
+       int error;
+       /* first set DMEM and AIF, leaving other bits intact */
+       error = Tfa9887_ReadRegister(tfa9887, TFA9887_CF_CONTROLS, &cf_ctrl);
+       if (error != Tfa9887_Error_Ok) {
+               return error;
+       }
+       cf_ctrl &= ~0x000E; /* clear AIF & DMEM */
+       cf_ctrl |= (Tfa9887_DMEM_XMEM<<1); /* set DMEM, leave AIF cleared for autoincrement */
+       error = Tfa9887_WriteRegister(tfa9887, TFA9887_CF_CONTROLS, cf_ctrl);
+       if (error != Tfa9887_Error_Ok) {
+               return error;
+       }
+       error = Tfa9887_WriteRegister(tfa9887, TFA9887_CF_MAD, start_offset);
+       if (error != Tfa9887_Error_Ok) {
+               return error;
+       }
+       
+       num_bytes = num_words*bytes_per_word;
+       p=pValues;
+       for (; num_bytes > 0; ) {
+               burst_size = ROUND_DOWN(MAX_I2C_LENGTH, bytes_per_word);
+               if (num_bytes < burst_size) {
+                       burst_size = num_bytes;
+               }
+
+               error = regmap_raw_read(tfa9887->regmap, TFA9887_CF_MEM, bytes,burst_size * 2);
+               if (error != Tfa9887_Error_Ok) {
+                       return error;
+               }
+               convertBytes2Data(burst_size, bytes, p);
+               num_bytes -= burst_size;
+               p += burst_size/bytes_per_word;
+       }
+       return Tfa9887_Error_Ok;
+}
+
+int DspWriteMem(struct tfa9887_priv *tfa9887, unsigned int address, int value)
+{
+       unsigned int cf_ctrl; /* the value to sent to the CF_CONTROLS register */
+       unsigned int bytes[3];
+       int error;
+       /* first set DMEM and AIF, leaving other bits intact */
+       error = Tfa9887_ReadRegister(tfa9887, TFA9887_CF_CONTROLS, &cf_ctrl);
+       if (error != Tfa9887_Error_Ok) {
+               return error;
+       }
+       cf_ctrl &= ~0x000E; /* clear AIF & DMEM */
+       cf_ctrl |= (Tfa9887_DMEM_XMEM<<1); /* set DMEM, leave AIF cleared for autoincrement */
+       error = Tfa9887_WriteRegister(tfa9887, TFA9887_CF_CONTROLS, cf_ctrl);
+       if (error != Tfa9887_Error_Ok) {
+               return error;
+       }
+       error = Tfa9887_WriteRegister(tfa9887, TFA9887_CF_MAD, address);
+       if (error != Tfa9887_Error_Ok) {
+               return error;
+       }
+       //convertData2Bytes(1, &value, bytes);
+       error = regmap_raw_write(tfa9887->regmap, TFA9887_CF_MEM,bytes, 3 * 2);
+       if (error != Tfa9887_Error_Ok) {
+               return error;
+       }
+       return Tfa9887_Error_Ok;
+
+}
+
+int DspSetParam(struct tfa9887_priv *tfa9887,unsigned char module_id, unsigned char param_id, int num_bytes, const unsigned char *data)
+{
+
+       int error;
+       unsigned int cf_ctrl = 0x0002; /* the value to be sent to the CF_CONTROLS register: cf_req=00000000, cf_int=0, cf_aif=0, cf_dmem=XMEM=01, cf_rst_dsp=0 */
+       unsigned int cf_mad = 0x0001; /* memory address to be accessed (0 : Status, 1 : ID, 2 : parameters) */
+        unsigned int cf_status; /* the contents of the CF_STATUS register */
+       unsigned int id[3];
+       int tries = 0;
+       error = Tfa9887_WriteRegister(tfa9887, TFA9887_CF_CONTROLS, cf_ctrl);
+       if (error == Tfa9887_Error_Ok) {
+               error = Tfa9887_WriteRegister(tfa9887, TFA9887_CF_MAD, cf_mad);
+       }
+       if (error == Tfa9887_Error_Ok) {
+               id[0] = 0;
+               id[1] = module_id+128;
+               id[2] = param_id;
+               error = regmap_raw_write(tfa9887->regmap, TFA9887_CF_MEM,id, 3*2);
+       }
+       if (error == Tfa9887_Error_Ok) {
+               error = regmap_raw_write(tfa9887->regmap, TFA9887_CF_MEM, data, num_bytes*2);
+       }
+
+       cf_ctrl |= (1<<8) | (1<<4); /* set the cf_req1 and cf_int bit */
+       error = Tfa9887_WriteRegister(tfa9887, TFA9887_CF_CONTROLS, cf_ctrl);
+       pr_info("Writing TFA9887_CF_MEM %d \n",error);
+
+       do {
+               error = Tfa9887_ReadRegister(tfa9887, TFA9887_CF_STATUS, &cf_status);
+               tries++;
+       } while ( (error==Tfa9887_Error_Ok) && ((cf_status & 0x0100) == 0) && (tries < 10) ); /* don't wait forever, DSP is pretty quick to respond (< 1ms) */
+
+       if (tries >= 10) {
+               /* something wrong with communication with DSP */
+               pr_info("Setparam something wrong\n");
+               error = -1;
+       }
+       return error;
+}
+
+int DspGetParam(struct tfa9887_priv *tfa9887, unsigned char module_id, unsigned char param_id, int num_bytes, const unsigned char *data)
+{
+
+       unsigned int cf_ctrl = 0x0002; /* the value to be sent to the CF_CONTROLS register: cf_req=00000000, cf_int=0, cf_aif=0, cf_dmem=XMEM=01, cf_rst_dsp=0 */
+       unsigned int cf_mad = 0x0001; /* memory address to be accessed (0 : Status, 1 : ID, 2 : parameters) */
+       unsigned int cf_status; /* the contents of the CF_STATUS register */
+       int error;
+        int tries = 0;
+        unsigned int id[3];
+
+       error = Tfa9887_WriteRegister(tfa9887, TFA9887_CF_CONTROLS, cf_ctrl);
+
+       if (error == Tfa9887_Error_Ok) {
+               error = Tfa9887_WriteRegister(tfa9887, TFA9887_CF_MAD, cf_mad);
+       }
+
+       if (error == Tfa9887_Error_Ok) {
+               id[0] = 0;
+               id[1] = module_id+128;
+               id[2] = param_id;
+               /* only try MEM once, if error, need to resend mad as well */
+               error = regmap_raw_write(tfa9887->regmap, TFA9887_CF_MEM, id, 3*2);
+       }
+       /* 2) wake up the DSP and let it process the data */
+       if (error == Tfa9887_Error_Ok) {
+               cf_ctrl |= (1<<8) | (1<<4); /* set the cf_req1 and cf_int bit */
+               error = Tfa9887_WriteRegister(tfa9887, TFA9887_CF_CONTROLS, cf_ctrl);
+       }
+
+       /* 3) wait for the ack */
+       if (error == Tfa9887_Error_Ok) {
+               do {
+                       error = Tfa9887_ReadRegister(tfa9887, TFA9887_CF_STATUS, &cf_status);
+                       tries++;
+               } while ( (error==Tfa9887_Error_Ok) && ((cf_status & 0x0100) == 0) && (tries < 10) ); /* don't wait forever, DSP is pretty quick to respond (< 1ms) */
+
+               if (tries >= 10) {
+                       /* something wrong with communication with DSP */
+                       pr_info("Something wrong with DSP\n");
+                       return -1;
+               }
+       }
+       /* 5) read the resulting data */
+       if (error == Tfa9887_Error_Ok) {
+               cf_mad = 0x0002; /* memory address to be accessed (0 : Status, 1 : ID, 2 : parameters) */
+               error = Tfa9887_WriteRegister(tfa9887, TFA9887_CF_MAD, cf_mad);
+       }
+
+       if (error == Tfa9887_Error_Ok) {
+               error = regmap_raw_read(tfa9887->regmap, TFA9887_CF_MEM,data,num_bytes*2);
+       }
+       return error;
+}
+
+int Tfa9887_WriteRegister(struct tfa9887_priv *tfa9887, unsigned int subaddress, unsigned int value)
+{
+        int error = regmap_write(tfa9887->regmap,subaddress,value);
+        return error;
+}
+
+int Tfa9887_ReadRegister(struct tfa9887_priv *tfa9887, unsigned int subaddress, unsigned int* pValue)
+{
+        int error = regmap_read(tfa9887->regmap,subaddress,pValue);
+        return error;
+}
+
+int Tfa9887_Init(void)
+{
+       int error = 0;
+       if(tfa9887R->deviceInit)
+               error = Init(tfa9887R);
+       if(tfa9887L->deviceInit)
+               error = Init(tfa9887L);
+        if (error != 0)
+               pr_info("Failed to Init tfa\n");
+       return error;
+}
+
+int coldStarup(struct tfa9887_priv *tfa9887)
+{
+       int error,volume_value;
+        unsigned int value;
+
+        error = Tfa9887_WriteRegister(tfa9887, 0x09, 0x0002);
+        if (Tfa9887_Error_Ok == error) {
+                error = Tfa9887_ReadRegister(tfa9887, 0x09, &value);
+        }
+        if (Tfa9887_Error_Ok == error) {
+                /* DSP must be in control of the amplifier to avoid plops */
+                value |= TFA9887_SYSCTRL_SEL_ENBL_AMP;
+                error = Tfa9887_WriteRegister(tfa9887, 0x09, value);
+        }
+
+        /* some other registers must be set for optimal amplifier behaviour */
+        if (Tfa9887_Error_Ok == error) {
+                error = Tfa9887_WriteRegister(tfa9887, 0x40, 0x5A6B);
+        }
+        if (Tfa9887_Error_Ok == error) {
+                error = Tfa9887_WriteRegister(tfa9887, 0x05, 0x13AB);
+        }
+        if (Tfa9887_Error_Ok == error) {
+                error = Tfa9887_WriteRegister(tfa9887, 0x06, 0x001F);
+        }
+        if (Tfa9887_Error_Ok == error) {
+                error = Tfa9887_WriteRegister(tfa9887,
+                TFA9887_SPKR_CALIBRATION, 0x0C4F); /*  adjusted to mandatory defaults */
+        }
+        if (Tfa9887_Error_Ok == error) {
+                error = Tfa9887_WriteRegister(tfa9887, 0x09, 0x025D);
+        }
+        if (Tfa9887_Error_Ok == error) {
+                error = Tfa9887_WriteRegister(tfa9887, 0x0A, 0x3EC3);
+        }
+        if (Tfa9887_Error_Ok == error) {
+                error = Tfa9887_WriteRegister(tfa9887, 0x41, 0x0308);
+        }
+        if (Tfa9887_Error_Ok == error) {
+                error = Tfa9887_WriteRegister(tfa9887, 0x48, 0x0180);
+        }
+        if (Tfa9887_Error_Ok == error) {
+                error = Tfa9887_WriteRegister(tfa9887, 0x49, 0x0E82);
+        }
+        if (Tfa9887_Error_Ok == error) {
+                error = Tfa9887_WriteRegister(tfa9887, 0x52, 0x0000);
+        }
+        if (Tfa9887_Error_Ok == error) {
+                error = Tfa9887_WriteRegister(tfa9887, 0x40, 0x0000);
+        }
+        //Set Sampling Frequency
+        error = Tfa9887_ReadRegister(tfa9887, TFA9887_I2S_CONTROL, &value);
+        if (error == Tfa9887_Error_Ok) {
+                // clear the 4 bits first
+                value &= (~(0xF<<TFA9887_I2SCTRL_RATE_SHIFT));
+
+                value |= TFA9887_I2SCTRL_RATE_48000;
+                error = Tfa9887_WriteRegister(tfa9887, TFA9887_I2S_CONTROL, value);
+        }
+        //SelectAmplifierInput
+        error = Tfa9887_ReadRegister(tfa9887, TFA9887_I2S_CONTROL, &value);
+        if (error == Tfa9887_Error_Ok) {
+                // clear the 2 bits first
+                value &= ~(0x3<<TFA9887_I2SCTRL_INPUT_SEL_SHIFT);
+
+                value |=(0x2<<TFA9887_I2SCTRL_INPUT_SEL_SHIFT);
+                error = Tfa9887_WriteRegister(tfa9887, TFA9887_I2S_CONTROL, value);
+        }
+        //Set Max Volume
+        error = Tfa9887_ReadRegister(tfa9887, TFA9887_AUDIO_CONTROL, &value);
+        if(error == Tfa9887_Error_Ok) {
+                volume_value = 2;
+                value = (value&0x00FF) | (unsigned int)(volume_value<<8);
+                error = Tfa9887_WriteRegister(tfa9887, TFA9887_AUDIO_CONTROL, value);
+        }
+
+        //PowerUp
+       error = Tfa9887_ReadRegister(tfa9887, TFA9887_SYSTEM_CONTROL, &value);
+        if(error == Tfa9887_Error_Ok) {
+                value &= ~(TFA9887_SYSCTRL_POWERDOWN);
+                error = Tfa9887_WriteRegister(tfa9887, TFA9887_SYSTEM_CONTROL, value);
+        }
+
+        //Firmware
+        error = ProcessPatchFile(tfa9887, 10, coldpatch_data);
+        error = ProcessPatchFile(tfa9887, 2224, n1d2_data);
+
+       return error;
+}
+
+int Init(struct tfa9887_priv *tfa9887)
+{
+       int error;
+       unsigned int value;
+
+       error = coldStarup(tfa9887);
+        if(error != Tfa9887_Error_Ok) {
+               pr_info("ColdStartup Failed\n");
+       }
+
+        //error = loadSettings(tfa9887);
+        if(error != Tfa9887_Error_Ok) {
+                pr_info("Loading Settings Failed\n");
+        }
+
+        error = stereoRouting(tfa9887);
+
+        if(error != Tfa9887_Error_Ok) {
+                pr_info("Stereo routing Failed\n");
+        }
+
+         //SetConfigured
+        error = Tfa9887_ReadRegister(tfa9887, TFA9887_SYSTEM_CONTROL, &value);
+        if(error == Tfa9887_Error_Ok)
+        {
+                value |= TFA9887_SYSCTRL_CONFIGURED;
+                error = Tfa9887_WriteRegister(tfa9887, TFA9887_SYSTEM_CONTROL, value);
+        }
+         //PowerDown
+        if(error == Tfa9887_Error_Ok)
+        {
+                error = Tfa9887_ReadRegister(tfa9887, TFA9887_SYSTEM_CONTROL, &value);
+                value |= TFA9887_SYSCTRL_POWERDOWN;
+                error = Tfa9887_WriteRegister(tfa9887, TFA9887_SYSTEM_CONTROL, value);
+        }
+        return error;
+}
+
+
+int loadSettings(struct tfa9887_priv *tfa9887)
+{
+       int error;
+        //Load settings
+        error = DspSetParam(tfa9887,MODULE_SPEAKERBOOST, PARAM_SET_LSMODEL, 423, speaker_data);
+        error = DspSetParam(tfa9887, MODULE_SPEAKERBOOST, PARAM_SET_CONFIG, 165, config_data);
+        error = DspSetParam(tfa9887, MODULE_SPEAKERBOOST, PARAM_SET_PRESET, 87, preset_data);
+       return error;
+}
+
+int stereoRouting(struct tfa9887_priv *tfa9887)
+{
+        int error;
+        unsigned int value;
+        if(tfa9887 == tfa9887L) {
+                //select channel
+                error = Tfa9887_ReadRegister(tfa9887, TFA9887_I2S_CONTROL, &value);
+                // clear the 2 bits first
+                value &= ~(0x3<<TFA9887_I2SCTRL_CHANSEL_SHIFT);
+
+                value |=(1<<TFA9887_I2SCTRL_CHANSEL_SHIFT);
+                error = Tfa9887_WriteRegister(tfa9887, TFA9887_I2S_CONTROL, value);
+
+                //select ouput left for gain
+                error = Tfa9887_ReadRegister(tfa9887, TFA9887_I2S_SEL, &value);
+                value &= ~(0x7<<TFA9887_I2SSEL_I2SOUT_LEFT_SHIFT);
+                value |=(1<<TFA9887_I2SSEL_I2SOUT_LEFT_SHIFT);
+                error = Tfa9887_WriteRegister(tfa9887, TFA9887_I2S_SEL, value);
+                //Select stereo gain
+                error = Tfa9887_ReadRegister(tfa9887, TFA9887_I2S_CONTROL, &value);
+                value &= ~(0x1<<TFA9887_I2SCTRL_DATAI2_SHIFT);
+                value |=(1<<TFA9887_I2SCTRL_DATAI2_SHIFT);
+                error = Tfa9887_WriteRegister(tfa9887, TFA9887_I2S_CONTROL, value);
+
+                //select output right for current sense
+                error = Tfa9887_ReadRegister(tfa9887, TFA9887_I2S_SEL, &value);
+                value &= ~(0x7<<TFA9887_I2SSEL_I2SOUT_RIGHT_SHIFT);
+                value |=(0<<TFA9887_I2SSEL_I2SOUT_RIGHT_SHIFT);
+                error = Tfa9887_WriteRegister(tfa9887, TFA9887_I2S_SEL, value);
+                error = Tfa9887_WriteRegister(tfa9887, TFA9887_I2S_SEL, value);
+                pr_info("Tfa inside left\n");
+
+         }
+         else if (tfa9887 == tfa9887R) {
+                // clear the 2 bits first
+                error = Tfa9887_ReadRegister(tfa9887, TFA9887_I2S_CONTROL, &value);
+                value &= ~(0x3<<TFA9887_I2SCTRL_CHANSEL_SHIFT);
+
+                value |=(2<<TFA9887_I2SCTRL_CHANSEL_SHIFT);
+                error = Tfa9887_WriteRegister(tfa9887, TFA9887_I2S_CONTROL, value);
+
+                error = Tfa9887_ReadRegister(tfa9887, TFA9887_I2S_SEL, &value);
+                value &= ~(0x7<<TFA9887_I2SSEL_I2SOUT_RIGHT_SHIFT);
+                value |=(1<<TFA9887_I2SSEL_I2SOUT_RIGHT_SHIFT);
+                error = Tfa9887_WriteRegister(tfa9887, TFA9887_I2S_SEL, value);
+
+                error = Tfa9887_ReadRegister(tfa9887, TFA9887_I2S_CONTROL, &value);
+                value &= ~(0x1<<TFA9887_I2SCTRL_DATAI2_SHIFT);
+                value |=(0<<TFA9887_I2SCTRL_DATAI2_SHIFT);
+                error = Tfa9887_WriteRegister(tfa9887, TFA9887_I2S_CONTROL, value);
+
+                error = Tfa9887_ReadRegister(tfa9887, TFA9887_I2S_SEL, &value);
+                value &= ~(0x7<<TFA9887_I2SSEL_I2SOUT_LEFT_SHIFT);
+                value |=(0<<TFA9887_I2SSEL_I2SOUT_LEFT_SHIFT);
+                error = Tfa9887_WriteRegister(tfa9887, TFA9887_I2S_SEL, value);
+                pr_info("tfa inside right\n");
+
+        }
+        else
+        {
+               error = -1;
+       }
+       return error;
+}
+
+int Tfa9887_Powerdown(int powerdown)
+{
+       int error = 0;
+       if(tfa9887R->deviceInit)
+               error = Powerdown(tfa9887R, powerdown);
+        if(tfa9887L->deviceInit)
+               error = Powerdown(tfa9887L, powerdown); 
+       return error;
+}
+
+EXPORT_SYMBOL(Tfa9887_Powerdown);
+
+int Powerdown(struct tfa9887_priv *tfa9887, int powerdown)
+{
+       int error;
+       unsigned int value;
+
+       /* read the SystemControl register, modify the bit and write again */
+       error = Tfa9887_ReadRegister(tfa9887, TFA9887_SYSTEM_CONTROL, &value);
+       if (error != Tfa9887_Error_Ok) {
+               return error;
+        }
+
+       switch(powerdown) {
+               case 1:
+                       value |= TFA9887_SYSCTRL_POWERDOWN;
+                       break;
+                case 0:
+                       value &= ~(TFA9887_SYSCTRL_POWERDOWN);
+                       break;
+                default:
+                return -1;
+        }
+        error = Tfa9887_WriteRegister(tfa9887, TFA9887_SYSTEM_CONTROL, value);
+        return error;
+}
+
+bool tfa9887_readable_register(struct device *dev, unsigned int reg)
+{
+        return true;
+}
+
+bool tfa9887_volatile_register(struct device *dev, unsigned int reg)
+{
+        return true;
+}
+
+static const struct regmap_config tfa9887_regmap = {
+       .reg_bits = 8,
+       .val_bits = 16,
+       .volatile_reg = tfa9887_volatile_register,
+       .readable_reg = tfa9887_readable_register,
+       .cache_type = REGCACHE_RBTREE,
+};
+
+static ssize_t tfa9887_cal_show(struct kobject *kobj,
+               struct kobj_attribute *attr, char *buf)
+{
+       printk("!tfa9887_cal_show\n");
+       return 0;
+}
+
+static ssize_t tfa9887_cal_store(struct kobject *kobj,
+       struct kobj_attribute *attr, const char *buf, size_t count)
+{
+       ssize_t ret = count;
+
+       printk("+tfa9887_cal_store: %p, %d\n", buf, count);
+
+       if (!buf || !count) {
+               ret = -EINVAL;
+               goto fail;
+       }
+
+fail:
+       printk("-tfa9887_cal_store: %d\n", count);
+       return ret;
+}
+
+
+static ssize_t tfa9887_config_show(struct kobject *kobj,
+               struct kobj_attribute *attr, char *buf)
+{
+       printk("!tfa9887_config_show\n");
+       return 0;
+}
+
+static ssize_t tfa9887_config_store(struct kobject *kobj,
+       struct kobj_attribute *attr, const char *buf, size_t count)
+{
+       ssize_t ret = count;
+
+       printk("+tfa9887_config_store: %p, %d\n", buf, count);
+
+       if (!buf || !count) {
+               ret = -EINVAL;
+               goto fail;
+       }
+
+fail:
+       printk("-tfa9887_config_store: %d\n", count);
+       return ret;
+}
+
+static ssize_t tfa9887_vol_show(struct kobject *kobj,
+               struct kobj_attribute *attr, char *buf)
+{
+       printk("!tfa9887_vol_show\n");
+       return 0;
+}
+
+static ssize_t tfa9887_vol_store(struct kobject *kobj,
+       struct kobj_attribute *attr, const char *buf, size_t count)
+{
+       ssize_t ret = count;
+
+       printk("+tfa9887_vol_store: %p, %d\n", buf, count);
+
+       if (!buf || !count) {
+               ret = -EINVAL;
+               goto fail;
+       }
+
+fail:
+       printk("-tfa9887_vol_store: %d\n", count);
+       return ret;
+}
+
+static __devinit int tfa9887R_i2c_probe(struct i2c_client *i2c,
+                                     const struct i2c_device_id *id)
+{
+       unsigned int val;
+       int ret;
+
+       pr_info("tfa9887R_i2c_probe\n");
+       tfa9887R = devm_kzalloc(&i2c->dev,  sizeof(struct tfa9887_priv),
+                             GFP_KERNEL);
+       if (tfa9887R == NULL)
+               return -ENOMEM;
+       tfa9887R->regmap = regmap_init_i2c(i2c, &tfa9887_regmap);
+       if (IS_ERR(tfa9887R->regmap)) {
+               ret = PTR_ERR(tfa9887R->regmap);
+               dev_err(&i2c->dev, "Failed to allocate register map: %d\n",
+                       ret);
+               return ret;
+       }
+
+       i2c_set_clientdata(i2c, tfa9887R);
+       tfa9887R->irq = i2c->irq;
+       ret = regmap_read(tfa9887R->regmap, TFA9887_REVISIONNUMBER, &val);
+       if (ret != 0) {
+               dev_err(&i2c->dev, "Failed to read chip revision: %d\n", ret);
+               goto err;
+       }
+       dev_info(&i2c->dev, "TFA9887 revision %d\n",val);
+       tfa9887_kobj = kobject_create_and_add("tfa9887", kernel_kobj);
+
+       ret = sysfs_create_file(tfa9887_kobj, &tfa9887_config);
+       printk("tfa9887_add_sysfs ret=%d",ret);
+       if (ret != 0) {
+                dev_err(&i2c->dev, "Failed to add sysfs: %d\n", ret);
+               goto err;
+       }
+       ret = sysfs_create_file(tfa9887_kobj, &tfa9887_cal);
+       printk("tfa9887_add_sysfs ret=%d",ret);
+       if (ret != 0) {
+                dev_err(&i2c->dev, "Failed to add sysfs: %d\n", ret);
+               goto err;
+       }
+       ret = sysfs_create_file(tfa9887_kobj, &tfa9887_vol);
+       printk("tfa9887_add_sysfs ret=%d",ret);
+       if (ret != 0) {
+                dev_err(&i2c->dev, "Failed to add sysfs: %d\n", ret);
+               goto err;
+       }
+       tfa9887R->deviceInit = true;
+       return 0;
+err:
+       regmap_exit(tfa9887R->regmap);
+       return ret;
+}
+
+static __devexit int tfa9887R_i2c_remove(struct i2c_client *client)
+{
+       struct tfa9887_priv *tfa9887R = i2c_get_clientdata(client);
+       regmap_exit(tfa9887R->regmap);
+       sysfs_remove_file(tfa9887_kobj, &tfa9887_config);
+       sysfs_remove_file(tfa9887_kobj, &tfa9887_cal);
+       sysfs_remove_file(tfa9887_kobj, &tfa9887_vol);
+       kobject_del(tfa9887_kobj);
+       return 0;
+}
+
+static const struct of_device_id tfa9887R_of_match[] = {
+       { .compatible = "nxp,tfa9887R", },
+       {},
+};
+MODULE_DEVICE_TABLE(of, tfa9887R_of_match);
+
+static const struct i2c_device_id tfa9887R_i2c_id[] = {
+       { "tfa9887R", 0 },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, tfa9887R_i2c_id);
+
+static struct i2c_driver tfa9887R_i2c_driver = {
+        .driver = {
+        .name = "tfa9887R",
+        .owner = THIS_MODULE,
+        .of_match_table = tfa9887R_of_match,
+        },
+        .probe =    tfa9887R_i2c_probe,
+        .remove =   __devexit_p(tfa9887R_i2c_remove),
+        .id_table = tfa9887R_i2c_id,
+};
+
+static __devinit int tfa9887L_i2c_probe(struct i2c_client *i2c,
+                                     const struct i2c_device_id *id)
+{
+       unsigned int val;
+       int ret;
+
+       pr_info("tfa9887L_i2c_probe\n");
+       tfa9887L = devm_kzalloc(&i2c->dev,  sizeof(struct tfa9887_priv),
+                             GFP_KERNEL);
+       if (tfa9887L == NULL)
+               return -ENOMEM;
+       tfa9887L->regmap = regmap_init_i2c(i2c, &tfa9887_regmap);
+       if (IS_ERR(tfa9887L->regmap)) {
+               ret = PTR_ERR(tfa9887L->regmap);
+               dev_err(&i2c->dev, "Failed to allocate register map: %d\n",
+                       ret);
+               return ret;
+       }
+
+       i2c_set_clientdata(i2c, tfa9887L);
+       tfa9887L->irq = i2c->irq;
+       ret = regmap_read(tfa9887L->regmap, TFA9887_REVISIONNUMBER, &val);
+       if (ret != 0) {
+               dev_err(&i2c->dev, "Failed to read chip revision: %d\n", ret);
+               goto err;
+       }
+       dev_info(&i2c->dev, "TFA9887 revision %d\n",val);
+       tfa9887L->deviceInit = true;    
+       return 0;
+err:
+       regmap_exit(tfa9887L->regmap);
+       return ret;
+}
+
+static __devexit int tfa9887L_i2c_remove(struct i2c_client *client)
+{
+       struct tfa9887_priv *tfa9887L = i2c_get_clientdata(client);
+       regmap_exit(tfa9887L->regmap);
+       return 0;
+}
+
+static const struct of_device_id tfa9887L_of_match[] = {
+       { .compatible = "nxp,tfa9887L", },
+       {},
+};
+MODULE_DEVICE_TABLE(of, tfa9887L_of_match);
+
+static const struct i2c_device_id tfa9887L_i2c_id[] = {
+       { "tfa9887L", 0 },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, tfa9887L_i2c_id);
+
+static struct i2c_driver tfa9887L_i2c_driver = {
+        .driver = {
+        .name = "tfa9887L",
+        .owner = THIS_MODULE,
+        .of_match_table = tfa9887L_of_match,
+        },
+        .probe =    tfa9887L_i2c_probe,
+        .remove =   __devexit_p(tfa9887L_i2c_remove),
+        .id_table = tfa9887L_i2c_id,
+};
+
+static int __init tfa9887_modinit(void)
+{
+        int ret = 0;
+        ret = i2c_add_driver(&tfa9887R_i2c_driver);
+        if (ret != 0) {
+        printk(KERN_ERR "Failed to register tfa9887 I2C driver: %d\n",
+           ret);
+        }
+        ret = i2c_add_driver(&tfa9887L_i2c_driver);
+        if (ret != 0) {
+        printk(KERN_ERR "Failed to register tfa9887 I2C driver: %d\n",
+           ret);
+        }
+        return ret;
+}
+module_init(tfa9887_modinit);
+
+static void __exit tfa9887_exit(void)
+{
+        i2c_del_driver(&tfa9887R_i2c_driver);
+        i2c_del_driver(&tfa9887L_i2c_driver);
+}
+module_exit(tfa9887_exit);
+
diff --git a/include/linux/tfa9887.h b/include/linux/tfa9887.h
new file mode 100644 (file)
index 0000000..bf22b47
--- /dev/null
@@ -0,0 +1,289 @@
+
+#ifndef __LINUX_TFA9887_H
+#define __LINUX_TFA9887_H
+
+struct tfa9887_priv {
+        struct regmap *regmap;
+        int irq;
+        bool deviceInit;
+};
+
+int Tfa9887_Powerdown(int powerdown);
+
+int Powerdown(struct tfa9887_priv *tfa9887, int powerdown);
+
+int Tfa9887_WriteRegister(struct tfa9887_priv *tfa9887, unsigned int subaddress, unsigned int value);
+
+int Tfa9887_ReadRegister(struct tfa9887_priv *tfa9887, unsigned int subaddress, unsigned int *pValue);
+
+int Tfa9887_Init(void);
+
+int Init(struct tfa9887_priv *tfa9887);
+
+int Tfa9887_ReadRegister(struct tfa9887_priv *tfa9887, unsigned int subaddress, unsigned int *pValue);
+
+int Tfa9887_WriteRegister(struct tfa9887_priv *tfa9887, unsigned int subaddress, unsigned int value);
+
+int ProcessPatchFile(struct tfa9887_priv *tfa9887, int length, const unsigned char *bytes);
+
+int DspGetParam(struct tfa9887_priv *tfa9887, unsigned char module_id, unsigned char param_id, int num_bytes, const unsigned char *data);
+
+int DspSetParam(struct tfa9887_priv *tfa9887,unsigned char module_id, unsigned char param_id, int num_bytes, const unsigned char *data);
+
+int DspWriteMem(struct tfa9887_priv *tfa9887, unsigned int address, int value);
+
+int DspReadMem(struct tfa9887_priv *tfa9887, unsigned short start_offset, int num_words, int *pValues);
+
+int coldStarup(struct tfa9887_priv *tfa9887);
+
+int loadSettings(struct tfa9887_priv *tfa9887);
+
+int stereoRouting(struct tfa9887_priv *tfa9887);
+
+typedef enum Tfa9887_AmpInputSel {
+       Tfa9887_AmpInputSel_I2SLeft,
+       Tfa9887_AmpInputSel_I2SRight,
+       Tfa9887_AmpInputSel_DSP
+} Tfa9887_AmpInputSel_t;
+
+typedef enum Tfa9887_OutputSel {
+       Tfa9887_I2SOutputSel_CurrentSense,
+       Tfa9887_I2SOutputSel_DSP_Gain,
+       Tfa9887_I2SOutputSel_DSP_AEC,
+       Tfa9887_I2SOutputSel_Amp,
+       Tfa9887_I2SOutputSel_DataI3R,
+       Tfa9887_I2SOutputSel_DataI3L,
+       Tfa9887_I2SOutputSel_DcdcFFwdCur,
+} Tfa9887_OutputSel_t;
+
+typedef enum Tfa9887_StereoGainSel {
+       Tfa9887_StereoGainSel_Left,
+       Tfa9887_StereoGainSel_Right
+} Tfa9887_StereoGainSel_t;
+
+#define TFA9887_SPEAKERPARAMETER_LENGTH 423
+typedef unsigned char Tfa9887_SpeakerParameters_t[TFA9887_SPEAKERPARAMETER_LENGTH];
+
+#define TFA9887_CONFIG_LENGTH 165
+typedef unsigned char Tfa9887_Config_t[TFA9887_CONFIG_LENGTH];
+
+#define TFA9887_PRESET_LENGTH    87
+typedef unsigned char Tfa9887_Preset_t[TFA9887_PRESET_LENGTH];
+
+#define TFA9887_MAXPATCH_LENGTH (3*1024)
+
+
+/* the number of biquads supported */
+#define TFA9887_BIQUAD_NUM              10
+
+#define Tfa9887_Error_Ok       0
+
+typedef enum Tfa9887_SpeakerType {
+       Tfa9887_Speaker_FreeSpeaker=0,
+       Tfa9887_Speaker_RA11x15,
+       Tfa9887_Speaker_RA13x18,
+       Tfa9887_Speaker_RA9x13,
+
+       Tfa9887_Speaker_Max
+
+} Tfa9887_SpeakerType_t;
+
+
+typedef enum Tfa9887_Channel {
+       Tfa9887_Channel_L,
+       Tfa9887_Channel_R,
+       Tfa9887_Channel_L_R,
+       Tfa9887_Channel_Stereo
+} Tfa9887_Channel_t;
+
+typedef enum Tfa9887_Mute {
+       Tfa9887_Mute_Off,
+       Tfa9887_Mute_Digital,
+       Tfa9887_Mute_Amplifier
+} Tfa9887_Mute_t;
+
+
+typedef enum Tfa9887_SpeakerBoostStatusFlags
+{
+       Tfa9887_SpeakerBoost_Activity=0         ,               /* Input signal activity. */
+       Tfa9887_SpeakerBoost_S_Ctrl                             ,               /* S Control triggers the limiter */
+       Tfa9887_SpeakerBoost_Muted                        ,             /* 1 when signal is muted */
+       Tfa9887_SpeakerBoost_X_Ctrl                     ,               /* X Control triggers the limiter */
+       Tfa9887_SpeakerBoost_T_Ctrl                     ,               /* T Control triggers the limiter */
+       Tfa9887_SpeakerBoost_NewModel                   ,               /* New model is available */
+       Tfa9887_SpeakerBoost_VolumeRdy          ,               /* 0 means stable volume, 1 means volume is still smoothing */
+       Tfa9887_SpeakerBoost_Damaged                    ,               /* Speaker Damage detected  */
+       Tfa9887_SpeakerBoost_SignalClipping             /* Input Signal clipping detected */
+} Tfa9887_SpeakerBoostStatusFlags_t ;
+
+typedef struct Tfa9887_SpeakerBoost_StateInfo
+{
+       float   agcGain;                        /* Current AGC Gain value */
+       float   limGain;                        /* Current Limiter Gain value */
+       float   sMax;                             /* Current Clip/Lim threshold */
+       int             T;                                        /* Current Speaker Temperature value */
+       int       statusFlag;           /* Masked bit word, see Tfa9887_SpeakerBoostStatusFlags */
+       float   X1;                                       /* Current estimated Excursion value caused by Speakerboost gain control */
+       float   X2;                                       /* Current estimated Excursion value caused by manual gain setting */
+       float Re;           /* Current Loudspeaker blocked resistance */
+} Tfa9887_SpeakerBoost_StateInfo_t;
+
+typedef unsigned char subaddress_t;
+
+#define TFA9887_I2S_CONTROL    (subaddress_t)0x04
+#define TFA9887_AUDIO_CONTROL  (subaddress_t)0x06
+#define TFA9887_SYSTEM_CONTROL (subaddress_t)0x09
+#define TFA9887_I2S_SEL        (subaddress_t)0x0A
+//#define TFA9887_CF_CONTROLS    (subaddress_t)0x70 //TODO cleanup reg defs
+//#define TFA9887_CF_MAD         (subaddress_t)0x71
+//#define TFA9887_CF_MEM         (subaddress_t)0x72
+//#define TFA9887_CF_STATUS      (subaddress_t)0x73
+
+
+/* REVISION values */
+#define TFA9887_REV_N1C       0x11
+#define TFA9887_REV_N1D       0x12
+
+
+/* I2S_CONTROL bits */
+#define TFA9887_I2SCTRL_RATE_SHIFT (12)
+#define TFA9887_I2SCTRL_RATE_08000 (0<<TFA9887_I2SCTRL_RATE_SHIFT)
+#define TFA9887_I2SCTRL_RATE_11025 (1<<TFA9887_I2SCTRL_RATE_SHIFT)
+#define TFA9887_I2SCTRL_RATE_12000 (2<<TFA9887_I2SCTRL_RATE_SHIFT)
+#define TFA9887_I2SCTRL_RATE_16000 (3<<TFA9887_I2SCTRL_RATE_SHIFT)
+#define TFA9887_I2SCTRL_RATE_22050 (4<<TFA9887_I2SCTRL_RATE_SHIFT)
+#define TFA9887_I2SCTRL_RATE_24000 (5<<TFA9887_I2SCTRL_RATE_SHIFT)
+#define TFA9887_I2SCTRL_RATE_32000 (6<<TFA9887_I2SCTRL_RATE_SHIFT)
+#define TFA9887_I2SCTRL_RATE_44100 (7<<TFA9887_I2SCTRL_RATE_SHIFT)
+#define TFA9887_I2SCTRL_RATE_48000 (8<<TFA9887_I2SCTRL_RATE_SHIFT)
+
+#define TFA9887_I2SCTRL_CHANSEL_SHIFT      3
+#define TFA9887_I2SCTRL_INPUT_SEL_SHIFT    6
+
+#define TFA9887_I2SCTRL_DATAI2_SHIFT      5
+
+#define TFA9887_I2SSEL_I2SOUT_LEFT_SHIFT  0
+#define TFA9887_I2SSEL_I2SOUT_RIGHT_SHIFT 3
+
+
+/* SYSTEM CONTROL bits */
+#define TFA9887_SYSCTRL_POWERDOWN    (1<<0)
+#define TFA9887_SYSCTRL_RESETI2C     (1<<1)
+#define TFA9887_SYSCTRL_ENBL_AMP     (1<<3)
+#define TFA9887_SYSCTRL_CONFIGURED   (1<<5)
+#define TFA9887_SYSCTRL_SEL_ENBL_AMP (1<<6)
+
+/* Audio control bits */
+#define TFA9887_AUDIOCTRL_MUTE       (1<<5)
+
+/* modules */
+#define MODULE_SPEAKERBOOST  1
+
+/* RPC commands */
+#define PARAM_SET_LSMODEL        0x06  // Load a full model into SpeakerBoost.
+#define PARAM_SET_LSMODEL_SEL    0x07  // Select one of the default models present in Tfa9887 ROM.
+#define PARAM_SET_EQ                    0x0A  // 2 Equaliser Filters.
+#define PARAM_SET_PRESET         0x0D  // Load a preset
+#define PARAM_SET_CONFIG                0x0E  // Load a config
+
+#define PARAM_GET_RE0            0x85  /* gets the speaker calibration impedance (@25 degrees celsius) */
+#define PARAM_GET_LSMODEL        0x86  // Gets current LoudSpeaker Model.
+#define PARAM_GET_STATE                                         0xC0
+
+/* RPC Status results */
+#define STATUS_OK                  0
+#define STATUS_INVALID_MODULE_ID   2
+#define STATUS_INVALID_PARAM_ID    3
+#define STATUS_INVALID_INFO_ID     4
+
+
+/* the maximum message length in the communication with the DSP */
+#define MAX_PARAM_SIZE (145*3)
+
+#define MIN(a,b) ((a)<(b)?(a):(b))
+#define ROUND_DOWN(a,n) (((a)/(n))*(n))
+
+/* maximum number of bytes in 1 I2C write transaction */
+#define MAX_I2C_LENGTH                 254
+
+#define TFA9887_CF_RESET  1
+/* possible memory values for DMEM in CF_CONTROLs */
+typedef enum {
+       Tfa9887_DMEM_PMEM=0,
+       Tfa9887_DMEM_XMEM=1,
+       Tfa9887_DMEM_YMEM=2,
+       Tfa9887_DMEM_IOMEM=3,
+} Tfa9887_DMEM_e;
+
+
+#define MODULE_BIQUADFILTERBANK 2
+#define BIQUAD_PARAM_SET_COEFF  1
+#define BIQUAD_COEFF_SIZE       6
+
+#define EQ_COEFF_SIZE           7
+
+/* the number of elements in Tfa9887_SpeakerBoost_StateInfo */
+#define STATE_SIZE             8
+
+#define SPKRBST_HEADROOM                        7                                                                              /* Headroom applied to the main input signal */
+#define SPKRBST_AGCGAIN_EXP                    SPKRBST_HEADROOM          /* Exponent used for AGC Gain related variables */
+#define SPKRBST_TEMPERATURE_EXP     9
+#define SPKRBST_LIMGAIN_EXP                        4                                        /* Exponent used for Gain Corection related variables */
+#define SPKRBST_TIMECTE_EXP         1
+
+
+
+//Tfa_Registers.h
+#define TFA9887_STATUS         (unsigned int)0x00
+
+#define TFA9887_MTP            (unsigned int)0x80
+
+/* STATUS bits */
+#define TFA9887_STATUS_VDDS       (1<<0) /*  */
+#define TFA9887_STATUS_PLLS       (1<<1) /* plls locked */
+#define TFA9887_STATUS_OTDS       (1<<2) /*  */
+#define TFA9887_STATUS_OVDS       (1<<3) /*  */
+#define TFA9887_STATUS_UVDS       (1<<4) /*  */
+#define TFA9887_STATUS_OCDS       (1<<5) /*  */
+#define TFA9887_STATUS_CLKS       (1<<6) /* clocks stable */
+//
+//
+#define TFA9887_STATUS_DCCS       (1<<9) /*  */
+
+#define TFA9887_STATUS_ACS        (1<<11) /* cold started */
+#define TFA9887_STATUS_SWS        (1<<12) /* amplifier switching */
+
+/* MTP bits */
+#define TFA9887_MTP_MTPOTC        (1<<0)  /* one time calibration */
+#define TFA9887_MTP_MTPEX         (1<<1)  /* one time calibration done */
+
+/*
+ * generated defines
+ */
+#define TFA9887_STATUSREG (0x00)
+#define TFA9887_BATTERYVOLTAGE (0x01)
+#define TFA9887_TEMPERATURE (0x02)
+#define TFA9887_I2SREG (0x04)
+#define TFA9887_BAT_PROT (0x05)
+#define TFA9887_AUDIO_CTR (0x06)
+#define TFA9887_DCDCBOOST (0x07)
+#define TFA9887_SPKR_CALIBRATION (0x08)
+#define TFA9887_SYS_CTRL (0x09)
+#define TFA9887_I2S_SEL_REG (0x0a)
+#define TFA9887_REVISIONNUMBER (0x03)
+#define TFA9887_HIDE_UNHIDE_KEY (0x40)
+#define TFA9887_PWM_CONTROL (0x41)
+#define TFA9887_CURRENTSENSE1 (0x46)
+#define TFA9887_CURRENTSENSE2 (0x47)
+#define TFA9887_CURRENTSENSE3 (0x48)
+#define TFA9887_CURRENTSENSE4 (0x49)
+#define TFA9887_ABISTTEST (0x4c)
+#define TFA9887_RESERVE1 (0x0c)
+#define TFA9887_MTP_COPY (0x62)
+#define TFA9887_CF_CONTROLS (0x70)
+#define TFA9887_CF_MAD (0x71)
+#define TFA9887_CF_MEM (0x72)
+#define TFA9887_CF_STATUS (0x73)
+#define TFA9887_RESERVE2 (0x0d)
+
+#endif
index ded4739..e2815c7 100644 (file)
 #include <sound/pcm.h>
 #include <sound/pcm_params.h>
 #include <sound/soc.h>
-
 #include "../codecs/rt5639.h"
 #include "../codecs/rt5640.h"
 
 #include "tegra_pcm.h"
 #include "tegra_asoc_utils.h"
+#include <linux/tfa9887.h>
+#include "tegra30_ahub.h"
+#include "tegra30_i2s.h"
 
 #define DRV_NAME "tegra-snd-rt5640"
 
@@ -87,8 +89,11 @@ static int tegra_rt5640_hw_params(struct snd_pcm_substream *substream,
        struct snd_soc_card *card = codec->card;
        struct tegra_rt5640 *machine = snd_soc_card_get_drvdata(card);
        struct tegra_asoc_platform_data *pdata = machine->pdata;
+       struct tegra30_i2s *i2s = snd_soc_dai_get_drvdata(cpu_dai);
        int srate, mclk, i2s_daifmt;
        int err, rate;
+       static unsigned initTfa = 0;
+       int dcnt = 10;
 
        srate = params_rate(params);
        mclk = 256 * srate;
@@ -149,7 +154,32 @@ static int tegra_rt5640_hw_params(struct snd_pcm_substream *substream,
                dev_err(card->dev, "codec_dai clock not set\n");
                return err;
        }
+       if(machine_is_roth()) {
+               if(initTfa == 1) {
+                       tegra30_ahub_enable_clocks();
+                       clk_enable(i2s->clk_i2s);
+                       tegra30_ahub_enable_tx_fifo(i2s->txcif);
+                       i2s->reg_ctrl |= TEGRA30_I2S_CTRL_XFER_EN_TX;
+                       #ifdef CONFIG_PM
+                       i2s->reg_cache[TEGRA30_I2S_CTRL >> 2] = i2s->reg_ctrl;
+                       #endif
+                       __raw_writel(i2s->reg_ctrl, i2s->regs + TEGRA30_I2S_CTRL);
+                       pr_info("INIT TFA\n");
+                       Tfa9887_Init();
+                       i2s->reg_ctrl &= ~TEGRA30_I2S_CTRL_XFER_EN_TX;
+                       #ifdef CONFIG_PM
+                       i2s->reg_cache[TEGRA30_I2S_CTRL >> 2] = i2s->reg_ctrl;
+                       #endif
+                       __raw_writel(i2s->reg_ctrl, i2s->regs + TEGRA30_I2S_CTRL);
+                       while (tegra30_ahub_tx_fifo_is_enabled(i2s->id) && dcnt--)
+                               udelay(100);
+                       clk_disable(i2s->clk_i2s);
+                       tegra30_ahub_disable_clocks();
+                       tegra30_ahub_disable_tx_fifo(i2s->txcif);
 
+               }
+               initTfa++;
+       }
        return 0;
 }
 
@@ -409,12 +439,21 @@ static int tegra_rt5640_event_int_spk(struct snd_soc_dapm_widget *w,
        struct tegra_asoc_platform_data *pdata = machine->pdata;
 
        if (machine->spk_reg) {
-               if (SND_SOC_DAPM_EVENT_ON(event))
+               if (SND_SOC_DAPM_EVENT_ON(event)) {
                        regulator_enable(machine->spk_reg);
-               else
+               }
+               else {
                        regulator_disable(machine->spk_reg);
+               }
+       }
+       if(machine_is_roth()) {
+               if (SND_SOC_DAPM_EVENT_ON(event)) {
+                       Tfa9887_Powerdown(0);
+               }
+               else {
+                       Tfa9887_Powerdown(1);
+               }
        }
-
        if (!(machine->gpio_requested & GPIO_SPKR_EN))
                return 0;