summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVinod Subbarayalu <vsubbarayalu@nvidia.com>2012-11-14 15:10:53 -0800
committerSimone Willett <swillett@nvidia.com>2012-11-28 18:33:20 -0800
commitc8553f1cca402431546f3e21443836cbb10d7039 (patch)
tree9dc16d1c8ab76729bacca631211779901e49aea7
parentae9410ead91f4edf99db3d02268511d43a88f667 (diff)
audio: TFA9887 driver
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>
-rw-r--r--arch/arm/mach-tegra/board-roth.c11
-rw-r--r--drivers/misc/Makefile1
-rw-r--r--drivers/misc/tfa9887.c1018
-rw-r--r--include/linux/tfa9887.h289
-rw-r--r--sound/soc/tegra/tegra_rt5640.c47
5 files changed, 1361 insertions, 5 deletions
diff --git a/arch/arm/mach-tegra/board-roth.c b/arch/arm/mach-tegra/board-roth.c
index 430de581c7a4..29b5e2bfe1b0 100644
--- a/arch/arm/mach-tegra/board-roth.c
+++ b/arch/arm/mach-tegra/board-roth.c
@@ -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 = {
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
index 209019569fe6..dd3627729cc7 100644
--- a/drivers/misc/Makefile
+++ b/drivers/misc/Makefile
@@ -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
index 000000000000..b7a09b20cb0a
--- /dev/null
+++ b/drivers/misc/tfa9887.c
@@ -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
index 000000000000..bf22b47f4c5b
--- /dev/null
+++ b/include/linux/tfa9887.h
@@ -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
diff --git a/sound/soc/tegra/tegra_rt5640.c b/sound/soc/tegra/tegra_rt5640.c
index ded47398b10b..e2815c7793c6 100644
--- a/sound/soc/tegra/tegra_rt5640.c
+++ b/sound/soc/tegra/tegra_rt5640.c
@@ -48,12 +48,14 @@
#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;