diff options
author | Vinod Subbarayalu <vsubbarayalu@nvidia.com> | 2012-11-14 15:10:53 -0800 |
---|---|---|
committer | Simone Willett <swillett@nvidia.com> | 2012-11-28 18:33:20 -0800 |
commit | c8553f1cca402431546f3e21443836cbb10d7039 (patch) | |
tree | 9dc16d1c8ab76729bacca631211779901e49aea7 | |
parent | ae9410ead91f4edf99db3d02268511d43a88f667 (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.c | 11 | ||||
-rw-r--r-- | drivers/misc/Makefile | 1 | ||||
-rw-r--r-- | drivers/misc/tfa9887.c | 1018 | ||||
-rw-r--r-- | include/linux/tfa9887.h | 289 | ||||
-rw-r--r-- | sound/soc/tegra/tegra_rt5640.c | 47 |
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; |