[K3 Note Original Android Development] daniel_hk:
Build a fully working kernel for K3-Note

In the past few years, many excellent price/performance phones would use MTK chips. Last year, I got a K3Note from a friend. At that time, mt6752 and 2G/16G was approaching the top ranking performance. Lenovo had development updates and it could more or less keep up with the current Android. Seemed no immediate needs for a custom ROM. This summer, the last development update was out. I started gathering some info. Sadly, every bit of info. I got were old, incomplete or for other devices. Kernel source is the basic Linux requirement. We can get it in the Lenovo support. Having been playing with custom ROMs for three years, I thought I saw everything. MTK and Lenovo show me there is another level below... :eek:

All kernel sources I've tried so far, no matter how messy and ugly in coding, could at least be built and replaced the one in the stock ROM. The one from Lenovo told me otherwise... If you follow the instruction and build it right away, it won't even boot! It's OK that MTK use the headers. If you like problem solving, it could be fun too. After a few recoveries by the AIO flash tool, I finally built a bootable one. The joy lasted a minutes after it boot up. It just hanged shortly. Dumping the log and kmsg would easily tell you why. The device "/dev/tfa9897" was missing! That means there was something missing in the source! That's why there were only few ROMs and mostly (I think all) were using pre-built kernels from stock ROMs. How can anyone survive without audio in a phone! :mad:

Some people are developing/supporting other devices with MTK chips, or even other Lenovo devices. They don't have big issues. I can only conclude that the team releasing the K3 Note kernel source are the prime culprit. I don't know who made that evil decision to deliberately remove that part from the source! Their action just disgraced the brand and their products. Besides cursing, I would thank them. They really piss me off and force me to learn how to write my own driver!

After a desperate and sweaty week, I finally made it work. Thanks to the open source community. I don't need to do everything from scratch. I'm now sharing my experiences here. If there are similar situation in other devices. You are welcome to use and share my experiences. Don't keep it to yourself, share yours too! Just tell those stupid, selfish and idiotic "so call developers" they are not welcome to the open source community...

To other developers, the door is opened now. With the working kernel source, we have the chance to go beyond Marshmallow. I look forward to seeing more custom ROMs for K3-Note. Cheers! :D

Unleash the existing issues:

There is a file Android.mk in the root of the kernel. Clearly it's from MTK and was there for some time. Even though we don't need it, there are many good info. for us.

I. MTK Headers

MTK devices' bootloader require the ramdisk (initramfs) and kernel to have a header. Before packing it to boot.img, you have to add the header first. Otherwise, it won't boot.

The size of the header is 512 bytes and its format is:

(key)+(size)+(name)+(fill)

key: 　 4 bytes 　 　 　　　　= 0x88 0x16 0x88 0x58

size: 　4 bytes little endian int = size of the file followed

name: 32 bytes c string 　 　　in [KERNEL|BOOTFS|RECOVERY]

KERNEL = the file is kernel binary

BOOTFS = the file is initramfs (ramdisk)

RECOVERY = the file is recovery ramdisk

fill: 472 bytes of 0xFF to fill the header to 512 bytes

Tools

The mkimage, I think MTK provided it.

To add header to an image:

./mkimage <img file> [KERNEL|ROOTFS|RECOVERY] > <out img>

Pearl scripts mtk-tools by [MENTION=455439]bgcngm[/MENTION]

unpack-MTK.pl issue:

If the cmdline has more than one entries (seperate by space), it would make the subsequent repack failed. I double quoted the cmdline in unpack_boot().

repack-MTK.pl issue:

After a few fails, I found that the repack-MTK.pl is no longer working for K3-Note. I don't know if its POSIX, my version of cpio or else. The bootloader just fail to recognize the cpio and reboot to recovery. last_kmsg would shows "restorecon failed: init". I rewrote the repack_boot(). I used mkimge to add header and mkbootfs to pack the ramdisk. The script is simplified and it is working now. I called it View attachment 3908620. The utilities mkimage, mkbootfs and mkbootimg are grouped in the bin folder. Already take care different platform but I only have the Linux version of mkimage and mkbootfs in hand. If you're in different platfrom, you may put the executable for your platforms in bin.

II. The mt6752 kernel requires dtb

The kernel binary for mt6752 requires the dtb image being attached at the end.

Building the kernel

Build alone:

In this case, both Image.gz and Image.gz-dtb (or zImage and zImage-dtb for 32 bits) will be created at <output path>arch/arm64/boot

After that, you may use the the above mentioned repack-MTK.pl to repack the boot.img with your ramdisk.

Build in a custom ROM: (eg. omni or cm)

I have been building Omni for other devices so I used omni to build. I had created a device tree for aio_otfp_m (the name in build.prop of the stock ROM).

The file build/core/task/kernel.mk which most custom ROM have would do the job. The default dtbs in kernel.mk was for Qualcomm. It would not build the Image.gz-dtb we needed. Some changes were required.

Here is the View attachment 3908636 for Omni's build. Following the same commit, it would work for CM too. A build flag TARGET_MTK_KERNEL is added. Put it in BoardConfig.mk and set it to true for mt6752 (or other MTK) kernel.

To pack the kernel to boot.img we need a BOARD_CUSTOM_BOOTIMG_MK. If your ROM doesn't have BOARD_CUSTOM_BOOTIMG_MK support (eg. stock AOSP). You need to modify build/core/Makefile to make it work or build the kernel separately and included to your ROM as a pre-built kernel. Here is the View attachment 3908662 I made:

Note: With this bootimg.mk, <out path>/target/product/aio_otfp_m/kernel would include the header and ready for repacking.

III. Where is the tfa9897 driver?!

When we managed to build a bootable kernel, the joy might last for a minute! It just stucked at certain point. Log and kmsg showed that it couldn't find the device /dev/tfa9897. If we rename the the folder /system/etc/tfa9897, it would boot up and everything seems normal. What a hell is going on! How can any phone survive without audio! That kind of questions and scraming were all over my head. After a few searches, the picture was clear. Most of the developer were stucked and forced to quit at that point. It really pissed me off and I want to find out why. The deeper I dug the more I was convinced that it was deliberately removed. There were traces in the older sources that it was there. At that moment, I decided to "make it right"! I searched the nxp website. All I got was the pdf spec. I searched github and the linux communities. I found some drivers/codecs for tfa98xx and a few smartpa drivers for tfa98xx too. I then looked into the stock ROM's sysfs.

shell@aio_otfp_m: $ cd /sys
shell@aio_otfp_m:/sys $ find -name tfa*
./bus/i2c/drivers/tfa9897
./bus/platform/devices/tfa9897.36
./bus/platform/drivers/tfa9897
./bus/platform/drivers/tfa9897/tfa9897.36
./devices/bus.2/tfa9897.36
./devices/virtual/misc/tfa9897
./class/misc/tfa9897
shell@aio_otfp_m: $ cd /sys/devices/bus.2/tfa9897.36
shell@aio_otfp_m:/sys/devices/bus.2/tfa9897.36 $ ls -l
lrwxrwxrwx root root 2016-10-11 23:16 driver -> ../../../bus/platform/drivers/tfa9897
-r--r--r-- root root 4096 2016-10-11 23:16 modalias
drwxr-xr-x root root 2016-10-11 23:16 power
lrwxrwxrwx root root 2016-10-11 23:16 subsystem -> ../../../bus/platform
-rw-r--r-- root root 4096 2016-10-11 23:16 uevent
shell@aio_otfp_m:/sys/devices/bus.2/tfa9897.36 $ cat uevent
DRIVER=tfa9897
OF_NAME=tfa9897
OF_FULLNAME=/bus/tfa9897@0
OF_COMPATIBLE_0=mediatek,tfa9897
OF_COMPATIBLE_N=1
MODALIAS=of:Ntfa9897T<NULL>Cmediatek,tfa9897

In the first kernel I built, after rename /system/etc/tfa98xx, I got this
./bus/platform/devices/tfa9897.36
./devices/bus.2/tfa9897.36

With dummy driver I built later, I got this
./bus/platform/devices/tfa9897.36
./bus/platform/drivers/tfa9897
./devices/bus.2/tfa9897.36
./devices/virtual/misc/tfa9897
./class/misc/tfa9897
shell@aio_otfp_m:/sys/devices/bus.2/tfa9897.36 $ cat uevent
OF_NAME=tfa9897
OF_FULLNAME=/bus/tfa9897@0
OF_COMPATIBLE_0=mediatek,tfa9897
OF_COMPATIBLE_N=1
MODALIAS=of:Ntfa9897T<NULL>Cmediatek,tfa9897

A misc driver, a platform driver and a i2c driver were missing! I didn't know why it was so complicated. I decided to write a dummy misc driver to see what's going on. I repacked the kernel I built and the stock ramdisk to boot.img. Flash it to the BOOT partition with TWRP.

Here was the View attachment 3908621. I included it in the sound/soc/mediatek/Makefile

With the dummy driver, I can boot up and everything seems normal. After a while, the system might hang.

I studied the kmsg and found the following:

1) The two .cnt files in /system/etc/tfa9897 are the same. I think it's the default settings of the chip.

2) At start, libtfa9897_interface.so check which chip inside and download the corresponding .cnt via /dev/misc/tfa9897's write.

3) Each time before data was send to /dev/misc/tfa9897, unlocked_ioctl was called

4) As I see no codec under the name tfa98xx, I think the codec was not in the kerenl as some qualcomm kernel would do

Tfa98xx drivers for Qualcomm devices all carried codecs. I found a few nxp smartpa drivers in a devices with mt6595 cpu (forgot which manufacturer). None of them seems fit all the requirements. The closest would be the one for tfa9800 which was the ancestor of tfa9897. After a few trials, I finally pull everything together and come up with a driver that produce the same sysfs structure as the stock kernel.

1) There is the misc device

2) There is a platform driver

3) An I2C driver which was created at probe

Here is the initial driver View attachment 3908622. I put it in sound/soc/mediatek/nxp_tfa9897. As its for an Android Linux kernel, I used AOSP's GNU GPL.

There were still missing GPIO's which was the dead end. The stock driver don't have entries in dts so functions like of_property_read_u32_index() would return null...

After studying for a while, I found that the GPIO is in a codegen.dws file. With tools/dct/DrvGen to browser drivers/misc/mediatek/mach/mt6752/aio_otfp_m/dct/dct/codegen.dws. I found something similar. Eventually, I found the generated header files in out/target/product/aio_otfp_m/obj/KERNEL_OBJ/drivers/misc/mediatek/mach/mt6752/aio_otfp_m/dct/dct/inc

Here are the related GPIOs I copied from cust_gpio_usage.h. I then dump the values from the phone on stock ROM.

#define GPIO_SMARTPA_LDO_EN_PIN	(GPIO118 | 0x80000000)
#define GPIO_SMARTPA_LDO_EN_PIN_M_GPIO	GPIO_MODE_00
#define GPIO_SMARTPA_LDO_EN_PIN_M_EINT	GPIO_MODE_04
#define GPIO_SMARTPA_LDO_EN_PIN_M_DPI_D	GPIO_MODE_01
#define GPIO_SMARTPA_LDO_EN_PIN_M_DBG_MON_B	GPIO_MODE_07

#define GPIO_SMARTPA_EINT_PIN	(GPIO123 | 0x80000000)
#define GPIO_SMARTPA_EINT_PIN_M_GPIO	GPIO_MODE_00
#define GPIO_SMARTPA_EINT_PIN_M_EINT	GPIO_MODE_04
#define GPIO_SMARTPA_EINT_PIN_M_DBG_MON_B	GPIO_MODE_07

#define GPIO_SMARTPA_RST_PIN	(GPIO125 | 0x80000000)
#define GPIO_SMARTPA_RST_PIN_M_GPIO	GPIO_MODE_00
#define GPIO_SMARTPA_RST_PIN_M_CLK	GPIO_MODE_03
#define GPIO_SMARTPA_RST_PIN_M_EINT	GPIO_MODE_04
#define GPIO_SMARTPA_RST_PIN_M_DBG_MON_B	GPIO_MODE_07

#define GPIO_SMARTPA_I2S_BCK_PIN	(GPIO127 | 0x80000000)
#define GPIO_SMARTPA_I2S_BCK_PIN_M_GPIO	GPIO_MODE_00
#define GPIO_SMARTPA_I2S_BCK_PIN_M_EINT	GPIO_MODE_04
#define GPIO_SMARTPA_I2S_BCK_PIN_M_I2S3_BCK	GPIO_MODE_02
#define GPIO_SMARTPA_I2S_BCK_PIN_M_DBG_MON_B	GPIO_MODE_07

#define GPIO_SMARTPA_I2S_WS_PIN	(GPIO128 | 0x80000000)
#define GPIO_SMARTPA_I2S_WS_PIN_M_GPIO	GPIO_MODE_00
#define GPIO_SMARTPA_I2S_WS_PIN_M_EINT	GPIO_MODE_04
#define GPIO_SMARTPA_I2S_WS_PIN_M_I2S3_LRCK	GPIO_MODE_02
#define GPIO_SMARTPA_I2S_WS_PIN_M_DBG_MON_B	GPIO_MODE_07

#define GPIO_SMARTPA_I2S_DOUT_PIN	(GPIO129 | 0x80000000)
#define GPIO_SMARTPA_I2S_DOUT_PIN_M_GPIO	GPIO_MODE_00
#define GPIO_SMARTPA_I2S_DOUT_PIN_M_EINT	GPIO_MODE_04
#define GPIO_SMARTPA_I2S_DOUT_PIN_M_DPI_VSYNC	GPIO_MODE_01
#define GPIO_SMARTPA_I2S_DOUT_PIN_M_I2S3_DO	GPIO_MODE_02
#define GPIO_SMARTPA_I2S_DOUT_PIN_M_DBG_SDA	GPIO_MODE_03
#define GPIO_SMARTPA_I2S_DOUT_PIN_M_DBG_MON_B	GPIO_MODE_07

#define GPIO_SMARTPA_I2S_DIN_PIN	(GPIO133 | 0x80000000)
#define GPIO_SMARTPA_I2S_DIN_PIN_M_GPIO	GPIO_MODE_00
#define GPIO_SMARTPA_I2S_DIN_PIN_M_CLK	GPIO_MODE_03
#define GPIO_SMARTPA_I2S_DIN_PIN_M_EINT	GPIO_MODE_04
#define GPIO_SMARTPA_I2S_DIN_PIN_M_I2S0_DI	GPIO_MODE_01
#define GPIO_SMARTPA_I2S_DIN_PIN_M_AGPS_SYNC	GPIO_MODE_02
#define GPIO_SMARTPA_I2S_DIN_PIN_M_DBG_MON_B	GPIO_MODE_07

Values from the phone:
shell@aio_otfp_m:/ $ cd /sys
shell@aio_otfp_m:/sys $ find -name *gpio*
find: No ./fs/cgroup: Permission denied
./bus/platform/devices/10001e00.gpio
./bus/platform/drivers/mt-gpio
./devices/bus.2/10001e00.gpio
./devices/virtual/misc/mtgpio
./class/misc/mtgpio
find: No ./power/tuxonice: Permission denied
./kernel/debug/tracing/events/gpio
./kernel/debug/tracing/events/gpio/gpio_direction
./kernel/debug/tracing/events/gpio/gpio_value
./kernel/debug/gpio
./module/mt_sleep/parameters/slp_dump_gpio
shell@aio_otfp_m:/sys $ cd /sys/devices/virtual/misc/mtgpio <
shell@aio_otfp_m:/sys/devices/virtual/misc/mtgpio $ ls -l
-r--r--r-- root root 4096 2016-10-18 11:28 dev
-rw-rw-r-- root root 4096 2016-10-18 11:28 pin
drwxr-xr-x root root 2016-10-18 11:28 power
lrwxrwxrwx root root 2016-10-18 11:28 subsystem -> ../../../../class/misc
-rw-r--r-- root root 4096 2016-10-18 11:28 uevent
shell@aio_otfp_m:/sys/devices/virtual/misc/mtgpio $ cat pin
PIN: [MODE] [PULL_SEL] [DIN] [DOUT] [PULL EN] [DIR] [IES] [SMT]
0:10001111
...
118:01111110
...
123:41001010
...
125:00000110
...
127:20000110
128:20000110
129:20000110
...
133:10001010

After consulting the pdf spec. for tfa9800 and tfa9897, I had a clearer picture what these vaules were.

Now I had the GPIO and the init values. All the blanks were filled in View attachment 3908623

Everything seems reasonable now but still doesn't work... frustrated! :(

Here is the View attachment 3908635

My kmsg:
4,3670,9868743,-; (3)[287:mediaserver]Audio_Mic1_Mode_Select_Set()
4,3671,9868756,-; (3)[287:mediaserver]Audio_Mic1_Mode_Select_Set() mAudio_Analog_Mic1_mode = 0
4,3672,9868846,-; (3)[287:mediaserver]Audio_Mic2_Mode_Select_Set()
4,3673,9868852,-; (3)[287:mediaserver]Audio_Mic2_Mode_Select_Set() mAudio_Analog_Mic2_mode = 0
4,3674,9868930,-; (3)[287:mediaserver]Audio_Mic3_Mode_Select_Set()
4,3675,9868937,-; (3)[287:mediaserver]Audio_Mic3_Mode_Select_Set() mAudio_Analog_Mic3_mode = 0
4,3676,9869017,-; (3)[287:mediaserver]Audio_Mic4_Mode_Select_Set()
4,3677,9869023,-; (3)[287:mediaserver]Audio_Mic4_Mode_Select_Set() mAudio_Analog_Mic4_mode = 0
4,3678,9869169,-; (3)[287:mediaserver]+Audio_i2s0_hdoutput_Set()
4,3679,9869177,-;-(3)[287:mediaserver]-----------AudDrv_Clk_On, Aud_AFE_Clk_cntr:0
4,3680,9869193,-; (3)[287:mediaserver]+EnableApll1 bEnable = 1 APLL1State = 0
4,3681,9869203,-; (3)[287:mediaserver]+AudDrv_APLL22M_Clk_On enable_clock ADC clk(0)
4,3682,9869248,-; (3)[287:mediaserver]-EnableApll1 bEnable = 1
4,3683,9869255,-; (3)[287:mediaserver]+EnableApll2 bEnable = 1 APLL2State = 0
4,3684,9869262,-; (3)[287:mediaserver]+AudDrv_APLL24M_Clk_On enable_clock ADC clk(0)
4,3685,9869305,-; (3)[287:mediaserver]-EnableApll2 bEnable = 1
4,3686,9869312,-; (3)[287:mediaserver]EnableI2SDivPower Diveder_name = 8 bEnable = 1
4,3687,9869320,-; (3)[287:mediaserver]GetI2SDivCounter Diveder_name = 8 index = 0 mAPLL1I2SDividercounter[index] = 0
4,3688,9869327,-; (3)[287:mediaserver]EnableI2SDivPower Diveder_name = 8 bEnable = 1
4,3689,9869334,-; (3)[287:mediaserver]EnableI2SDivPower Diveder_name = 16 bEnable = 1
4,3690,9869341,-; (3)[287:mediaserver]GetI2SDivCounter Diveder_name = 16 index = 0 mAPLL2I2SDividercounter[index] = 0
4,3691,9869348,-; (3)[287:mediaserver]EnableI2SDivPower Diveder_name = 16 bEnable = 1
4,3692,9869355,-;-(3)[287:mediaserver]------------AudDrv_Clk_Off, Aud_AFE_Clk_cntr:0
4,3693,9869385,-;-(3)[287:mediaserver]-----------AudDrv_Clk_On, Aud_AFE_Clk_cntr:0
4,3694,9869394,-; (3)[287:mediaserver]Audio_i2s0_SideGen_Set() samplerate = 0, mi2s0_hdoutput_control = 1, mi2s0_extcodec_echoref_control = 0
4,3695,9869404,-; (3)[287:mediaserver]SetMemoryPathEnable Aud_block = 16 bEnable = 1
4,3696,9869411,-; (3)[287:mediaserver]SetMemoryPathEnable Aud_block = 16 mAudioMEMIF[Aud_block]->mUserCount = 1
3,3697,9875980,-; (3)[287:mediaserver]AudDrv_tfa9897_ioctl: cmd = 0x703 arg = 52
3,3697,9875982,-; (3)[287:mediaserver]ERROR,627: id=2,addr: 36, transfer error
3,3698,9875994,-; (3)[287:mediaserver]ERROR,633: I2C_ACKERR
3,3697,9875996,-; (3)[287:mediaserver]AudDrv_tfa9897_ioctl: cmd = 0x703 arg = 52
3,3699,9876163,-; (3)[287:mediaserver]ERROR,627: id=2,addr: 36, transfer error
3,3700,9876170,-; (3)[287:mediaserver]ERROR,633: I2C_ACKERR
3,3697,9876178,-; (3)[287:mediaserver]AudDrv_tfa9897_ioctl: cmd = 0x703 arg = 52
3,3701,9877681,-; (2)[287:mediaserver]ERROR,627: id=2,addr: 36, transfer error
3,3702,9877694,-; (2)[287:mediaserver]ERROR,633: I2C_ACKERR
3,3697,9877701,-; (3)[287:mediaserver]AudDrv_tfa9897_ioctl: cmd = 0x703 arg = 52
3,3703,9877993,-; (2)[287:mediaserver]ERROR,627: id=2,addr: 36, transfer error
3,3704,9878004,-; (2)[287:mediaserver]ERROR,633: I2C_ACKERR
3,3697,9878010,-; (3)[287:mediaserver]AudDrv_tfa9897_ioctl: cmd = 0x703 arg = 52
3,3705,9878225,-; (2)[287:mediaserver]ERROR,627: id=2,addr: 36, transfer error
3,3706,9878235,-; (2)[287:mediaserver]ERROR,633: I2C_ACKERR
4,3707,9883522,-; (2)[287:mediaserver]Audio_i2s0_SideGen_Set() samplerate = 0, mi2s0_hdoutput_control = 1, mi2s0_extcodec_echoref_control = 0

It's been a week and I knew it's almost there. 36 was a decimal number which seemed not related to the i2c address. I had tried a few possible values. In the spec. for tfa9800 (tfa9897 didn't have this info. I assumed its the same as tfa9800), 0x68-0x6f are the 4 registers with the LSB indicates r/w. Shift right 1 would become 0x34-0x37. Pretty sure 52(0x34) was the i2c device address of the tfa9897. I suspected libtfa9897_interface.so didn't got this value in probe. Since no matter what value I put in Tfa9897_dev, it always send 52(0x34) to AudDrv_tfa9897_ioctl. After cool it down for a day, I studied the sysfs in stock ROM again. What really were on the i2c bus?

shell@aio_otfp_m:/ $ cd /sys
shell@aio_otfp_m:/sys $ find -name tfa*
find: No ./fs/cgroup: Permission denied
./bus/i2c/drivers/tfa9897
./bus/platform/devices/tfa9897.36
./bus/platform/drivers/tfa9897
./bus/platform/drivers/tfa9897/tfa9897.36
./devices/bus.2/tfa9897.36
./devices/virtual/misc/tfa9897
./class/misc/tfa9897
find: No ./power/tuxonice: Permission denied
shell@aio_otfp_m:/ $ cd /sys/bus/i2c
shell@aio_otfp_m:/sys/bus/i2c $ ls -l
drwxr-xr-x root root 2016-10-17 23:01 devices
drwxr-xr-x root root 2016-10-17 23:01 drivers
-rw-r--r-- root root 4096 2016-10-17 23:01 drivers_autoprobe
--w------- root root 4096 2016-10-17 23:01 drivers_probe
--w------- root root 4096 2016-10-17 23:01 uevent
shell@aio_otfp_m:/sys/bus/i2c $ cd devices
shell@aio_otfp_m:/sys/bus/i2c/devices $ ls -l
lrwxrwxrwx root root 2016-10-17 23:01 0-0036 -> ../../../devices/bus.2/11007000.I2C0/i2c-0/0-0036
lrwxrwxrwx root root 2016-10-17 23:01 0-003e -> ../../../devices/bus.2/11007000.I2C0/i2c-0/0-003e
lrwxrwxrwx root root 2016-10-17 23:01 0-005d -> ../../../devices/bus.2/11007000.I2C0/i2c-0/0-005d
lrwxrwxrwx root root 2016-10-17 23:01 0-0064 -> ../../../devices/bus.2/11007000.I2C0/i2c-0/0-0064
lrwxrwxrwx root root 2016-10-17 23:01 0-006b -> ../../../devices/bus.2/11007000.I2C0/i2c-0/0-006b
lrwxrwxrwx root root 2016-10-17 23:01 0-0075 -> ../../../devices/bus.2/11007000.I2C0/i2c-0/0-0075
lrwxrwxrwx root root 2016-10-17 23:01 1-000d -> ../../../devices/bus.2/11008000.I2C1/i2c-1/1-000d
lrwxrwxrwx root root 2016-10-17 23:01 1-0018 -> ../../../devices/bus.2/11008000.I2C1/i2c-1/1-0018
lrwxrwxrwx root root 2016-10-17 23:01 1-0028 -> ../../../devices/bus.2/11008000.I2C1/i2c-1/1-0028
lrwxrwxrwx root root 2016-10-17 23:01 1-002e -> ../../../devices/bus.2/11008000.I2C1/i2c-1/1-002e
lrwxrwxrwx root root 2016-10-17 23:01 1-0034 -> ../../../devices/bus.2/11008000.I2C1/i2c-1/1-0034
lrwxrwxrwx root root 2016-10-17 23:01 1-0049 -> ../../../devices/bus.2/11008000.I2C1/i2c-1/1-0049
lrwxrwxrwx root root 2016-10-17 23:01 1-0068 -> ../../../devices/bus.2/11008000.I2C1/i2c-1/1-0068
lrwxrwxrwx root root 2016-10-17 23:01 1-0077 -> ../../../devices/bus.2/11008000.I2C1/i2c-1/1-0077
lrwxrwxrwx root root 2016-10-17 23:01 2-006b -> ../../../devices/bus.2/10059c00.SCP_I2C2/i2c-2/2-006b
lrwxrwxrwx root root 2016-10-17 23:01 3-0010 -> ../../../devices/bus.2/11009000.I2C2/i2c-3/3-0010
lrwxrwxrwx root root 2016-10-17 23:01 3-0018 -> ../../../devices/bus.2/11009000.I2C2/i2c-3/3-0018
lrwxrwxrwx root root 2016-10-17 23:01 3-001a -> ../../../devices/bus.2/11009000.I2C2/i2c-3/3-001a
lrwxrwxrwx root root 2016-10-17 23:01 3-007f -> ../../../devices/bus.2/11009000.I2C2/i2c-3/3-007f
lrwxrwxrwx root root 2016-10-17 23:01 i2c-0 -> ../../../devices/bus.2/11007000.I2C0/i2c-0
lrwxrwxrwx root root 2016-10-17 23:01 i2c-1 -> ../../../devices/bus.2/11008000.I2C1/i2c-1
lrwxrwxrwx root root 2016-10-17 23:01 i2c-2 -> ../../../devices/bus.2/10059c00.SCP_I2C2/i2c-2
lrwxrwxrwx root root 2016-10-17 23:01 i2c-3 -> ../../../devices/bus.2/11009000.I2C2/i2c-3
shell@aio_otfp_m:/sys/bus/i2c/devices $ cd ../drivers/tfa98*
shell@aio_otfp_m:/sys/bus/i2c/drivers/tfa9897 $ ls -l
lrwxrwxrwx root root 2016-10-17 23:02 1-0034 -> ../../../../devices/bus.2/11008000.I2C1/i2c-1/1-0034
--w------- root root 4096 2016-10-17 23:02 bind
--w------- root root 4096 2016-10-17 23:02 uevent
--w------- root root 4096 2016-10-17 23:02 unbind

It's quite clear that .36 was not related to i2c address. Tfa9897 was on i2c bus#2 and address#0x34.

I suddenly remembered a constant TFA_I2C_CHANNEL. It was set to (2) in every drivers I found. I was thinking it meant bus# but it didn't. I notice the line "...devices/bus.2/11008000.I2C1/i2c-1/1-0034". Seems 0x34 was in channel 1. So I changed TFA_I2C_CHANNEL to (1) and rebuilt...

OMG, Yes! It work!!! Audio is working now! I've tested for a few days. Everything else seems working the same as the stock kernel.

I updated the kernel to 3.10.103 and added the MTK_I2C_EXTENSION support. The final working version is in my github. Everything is ready now. Cheers! :highfive:

Source:　https://github.com/danielhk/android_kernel_lenovo_aio_otfp_m

Download:　AndroidFileHost,　DevHost,　百度网盘

Installation:

** backup your current /boot partition first **

Since only the /boot partition is replaced, you don't need to wipe anything before or after flashing. If you are rooted, it will also be preserved. (SuperSU 2.52 is recommended, newer systemless SuperSU might not work)

1. Flash zip in Recovery (TWRP is recommended)

2. Use AIO Flash tool (Lenovo's AIO_Upgrade_Tools_v5.1436.00.000 is recommended)

Newer AIO Flash tool might fail to boot

Change Log:

[COLOR="Blue"][B]version m1:[/B][/COLOR]
[COLOR="Blue"][B]2016/10/25 - v3[/B][/COLOR]
- alsps: use drvier from 3.10.61
[COLOR="Blue"][B]2016/10/24 - v2[/B][/COLOR]
- ramdisk: reinstate some services in init.mt6752.rc
[COLOR="Blue"][B]2016/10/19[/B][/COLOR]
- upgrade to linux-3.10.103
- Fix the CONFIG_TOUCHSCREEN_MTK_HD bug in touchpanel/GT9XX_aio/tpd_custom_gt9xx.h
- Fix a few unreasonable warnings
- Remove duplicated lines in scripts/drvgen/drvgen.mk
- use dtb image: aio_otfp_m
- Add the audio driver tfa9897
- Add MTK_I2C_EXTENSION support (DMA mode i2c for tfa9897)
- ramdisk: remove unnecessary files
- ramdisk: remove duplicate services in init.modem.rc
- ramdisk: remove duplicate entries in init.rc
- ramdisk: sepolicy ready for ROOT