summaryrefslogtreecommitdiffstats
path: root/target/linux/realtek/files/drivers/serial/i2c_alc5628.c
diff options
context:
space:
mode:
Diffstat (limited to 'target/linux/realtek/files/drivers/serial/i2c_alc5628.c')
-rw-r--r--target/linux/realtek/files/drivers/serial/i2c_alc5628.c344
1 files changed, 344 insertions, 0 deletions
diff --git a/target/linux/realtek/files/drivers/serial/i2c_alc5628.c b/target/linux/realtek/files/drivers/serial/i2c_alc5628.c
new file mode 100644
index 000000000..6568ff791
--- /dev/null
+++ b/target/linux/realtek/files/drivers/serial/i2c_alc5628.c
@@ -0,0 +1,344 @@
+#ifndef __BOOTCODE__
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/version.h>
+#include <platform.h> // GPIO_ABCD_IRQ, PABCD_ISR
+#include <asm/delay.h>
+#endif
+
+#ifdef __BOOTCODE__
+#define ENODEV 19 /* No such device */
+#define __init
+#endif
+
+#if defined( LINUX_VERSION_CODE ) && (LINUX_VERSION_CODE == KERNEL_VERSION(2,6,30))
+#define LINUX_KERNEL_VERSION_2_6_30 1
+#endif
+
+#ifdef LINUX_KERNEL_VERSION_2_6_30
+#include "bspchip.h" // BSP_GPIO_EFGH_IRQ
+#endif
+
+
+// ------------------------------------------------------------------
+// ------------------------------------------------------------------
+// Basic setup information
+
+
+// ------------------------------------------------------------------
+// ------------------------------------------------------------------
+// I2C level function
+
+#ifndef __BOOTCODE__
+#include "i2c.h"
+#else
+#include "i2c.h"
+#endif
+
+#define I2C_GPIO_ID( port, pin ) ( ( ( port - 'A' ) << 16 ) | ( pin ) )
+
+#ifdef CONFIG_SND_RTL8197D_SOC_ALC5628
+#define ALC5628_SCL I2C_GPIO_ID( 'G', 4 ) // SCL = G4
+#define ALC5628_SDA I2C_GPIO_ID( 'G', 6 ) // SDA = G6
+#endif
+
+#define ALC5628_I2C_ADDR 0x30
+#define ALC5628_I2C_WRITE 0x00
+#define ALC5628_I2C_READ 0x01
+
+static i2c_dev_t alc5628_i2c_dev = {
+ .sclk = ALC5628_SCL,
+ .sdio = ALC5628_SDA,
+};
+
+// Register address byte
+// 7 : not used
+// 6~3: A[3:0] UART's internal register select
+// 2~1: channel select: CH1 = 0?!, CH0 = 0
+// 0 : not used
+#define MK_SC16IS7X0_REG_ADDR( uart_reg ) ( ( uart_reg & 0x0F ) << 3 )
+
+unsigned int serial_in_i2c(unsigned int addr, int offset)
+{
+ unsigned short int data_hibyte=0;
+ unsigned short int data_lowbyte=0;
+ unsigned short int data;
+
+ //printk( "serial_in_i2c(%X):%X\n", addr, offset );
+
+ if( addr != ALC5628_I2C_ADDR )
+ return 0;
+
+ // start
+ i2c_start_condition( &alc5628_i2c_dev );
+
+ // addr + write
+ i2c_serial_write_byte( &alc5628_i2c_dev, ALC5628_I2C_ADDR |
+ ALC5628_I2C_WRITE );
+
+ // read ACK
+ if( i2c_ACK( &alc5628_i2c_dev ) != 0 )
+ return 0;
+
+ // write register address
+ i2c_serial_write_byte( &alc5628_i2c_dev, offset );
+
+ // read ACK
+ if( i2c_ACK( &alc5628_i2c_dev ) != 0 )
+ return 0;
+
+ // start
+ i2c_start_condition( &alc5628_i2c_dev );
+
+ // addr + read
+ i2c_serial_write_byte( &alc5628_i2c_dev, ALC5628_I2C_ADDR |
+ ALC5628_I2C_READ );
+
+ // read ACK
+ if( i2c_ACK( &alc5628_i2c_dev ) != 0 )
+ return 0;
+
+ // read data_hibyte
+ i2c_serial_read( &alc5628_i2c_dev, &data_hibyte );
+
+ //write ACK
+ i2c_ACK_w(&alc5628_i2c_dev, 0);
+
+ // read data_lowbyte
+ i2c_serial_read( &alc5628_i2c_dev, &data_lowbyte );
+
+ data = (data_hibyte<<8) | data_lowbyte;
+
+ // write negative-ACK
+ i2c_ACK_w( &alc5628_i2c_dev, 1 );
+
+ // stop
+ i2c_stop_condition( &alc5628_i2c_dev );
+
+ //printk( "in[%X]\n", data );
+
+ return data;
+}
+EXPORT_SYMBOL_GPL(serial_in_i2c);
+
+unsigned int serial_out_i2c(unsigned int addr, int offset, int value)
+{
+ //printk( "serial_out_i2c(%X):%X,%X\n", addr, offset, value );
+ unsigned short int data_hibyte;
+ unsigned short int data_lowbyte;
+
+ data_hibyte =(unsigned char) (value>>8);
+ data_lowbyte =(unsigned char) (value & 0xff);
+
+ if( addr != ALC5628_I2C_ADDR )
+ return 0;
+ //printk("(%d)", __LINE__);
+ // start
+ i2c_start_condition( &alc5628_i2c_dev );
+
+ // addr + write
+ i2c_serial_write_byte( &alc5628_i2c_dev, ALC5628_I2C_ADDR | ALC5628_I2C_WRITE );
+
+ // read ACK
+ if( i2c_ACK( &alc5628_i2c_dev ) != 0 )
+ return 0;
+ //printk("(%d)", __LINE__);
+ // write register address
+ i2c_serial_write_byte( &alc5628_i2c_dev, offset );
+
+ // read ACK
+ if( i2c_ACK( &alc5628_i2c_dev ) != 0 )
+ return 0;
+ //printk("(%d)", __LINE__);
+ // write data hibyte
+ i2c_serial_write_byte( &alc5628_i2c_dev, data_hibyte );
+
+ // read ACK
+ if( i2c_ACK( &alc5628_i2c_dev ) != 0 )
+ return 0;
+ //printk("(%d)", __LINE__);
+ // write data lowbyte
+ i2c_serial_write_byte( &alc5628_i2c_dev, data_lowbyte );
+
+ // read ACK
+ if( i2c_ACK( &alc5628_i2c_dev ) != 0 )
+ return 0;
+ //printk("(%d)", __LINE__);
+ // stop
+ i2c_stop_condition( &alc5628_i2c_dev );
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(serial_out_i2c);
+
+static void __init alc5628_init_i2c( void )
+{
+ int temp;
+ // init SCL / SDA
+ i2c_init_SCL_SDA( &alc5628_i2c_dev );
+
+ serial_in_i2c( ALC5628_I2C_ADDR, 0 ); // avoid NO ACK at first time access
+
+ serial_out_i2c( ALC5628_I2C_ADDR, 0x0, 0x707 );
+ serial_out_i2c( ALC5628_I2C_ADDR, 0x0, 0x707 );
+
+ serial_in_i2c( ALC5628_I2C_ADDR, 0 );
+ serial_in_i2c( ALC5628_I2C_ADDR, 0 );
+
+
+// enable playback
+ temp = serial_in_i2c( ALC5628_I2C_ADDR, 0x3E );
+ serial_out_i2c( ALC5628_I2C_ADDR, 0x3E, (temp) | 0x8000 );
+
+ temp = serial_in_i2c( ALC5628_I2C_ADDR, 0x3C );
+ serial_out_i2c( ALC5628_I2C_ADDR, 0x3C, (temp) | 0x2000 );
+
+ temp = serial_in_i2c( ALC5628_I2C_ADDR, 0x3C );
+ serial_out_i2c( ALC5628_I2C_ADDR, 0x3C, (temp) | 0x7F0 );
+
+ temp = serial_in_i2c( ALC5628_I2C_ADDR, 0x3A );
+ serial_out_i2c( ALC5628_I2C_ADDR, 0x3A, (temp) | 0x8030 );
+
+ temp = serial_in_i2c( ALC5628_I2C_ADDR, 0x3E );
+ serial_out_i2c( ALC5628_I2C_ADDR, 0x3E, (temp) | 0x600 );
+
+ temp = serial_in_i2c( ALC5628_I2C_ADDR, 0x0C );
+ serial_out_i2c( ALC5628_I2C_ADDR, 0x0C, (temp&(~0xBFBF)) | 0x1010 );
+
+
+ temp = serial_in_i2c( ALC5628_I2C_ADDR, 0x1C );
+ serial_out_i2c( ALC5628_I2C_ADDR, 0x1C, (temp) | 0x300 );
+
+// temp = serial_in_i2c( ALC5628_I2C_ADDR, 0x0C );
+// serial_out_i2c( ALC5628_I2C_ADDR, 0x0C, (temp&(~0xBFBF)) | 0x1010 );
+
+
+ temp = serial_in_i2c( ALC5628_I2C_ADDR, 0 );
+ //printk("reg0=%x\n", temp);
+
+ temp = serial_in_i2c( ALC5628_I2C_ADDR, 0x2 );
+ //printk("reg2=%x\n", temp);
+
+ serial_out_i2c( ALC5628_I2C_ADDR, 0x2, 0x0 );
+
+ temp = serial_in_i2c( ALC5628_I2C_ADDR, 0x2 );
+ //printk("reg2=%x\n", temp);
+
+ serial_out_i2c( ALC5628_I2C_ADDR, 0x2, 0xFFFF );
+
+ temp = serial_in_i2c( ALC5628_I2C_ADDR, 0x2 );
+ //printk("reg2=%x\n", temp);
+
+
+
+ temp = serial_in_i2c( ALC5628_I2C_ADDR, 0x4 );
+ //printk("reg4=%x\n", temp);
+
+ serial_out_i2c( ALC5628_I2C_ADDR, 0x4, 0x0 );
+
+ temp = serial_in_i2c( ALC5628_I2C_ADDR, 0x4 );
+ //printk("reg4=%x\n", temp);
+
+ temp = serial_in_i2c( ALC5628_I2C_ADDR, 0xA );
+ //printk("regA=%x\n", temp);
+
+ temp = serial_in_i2c( ALC5628_I2C_ADDR, 0xC );
+ //printk("regC=%x\n", temp);
+
+ temp = serial_in_i2c( ALC5628_I2C_ADDR, 0x16 );
+ //printk("reg16=%x\n", temp);
+
+ temp = serial_in_i2c( ALC5628_I2C_ADDR, 0x1C );
+ //printk("reg1C=%x\n", temp);
+
+ temp = serial_in_i2c( ALC5628_I2C_ADDR, 0x34 );
+ //printk("reg34=%x\n", temp);
+
+ temp = serial_in_i2c( ALC5628_I2C_ADDR, 0x38 );
+ //printk("reg38=%x\n", temp);
+
+ temp = serial_in_i2c( ALC5628_I2C_ADDR, 0x3A );
+ //printk("reg3A=%x\n", temp);
+
+ temp = serial_in_i2c( ALC5628_I2C_ADDR, 0x3C );
+ //printk("reg3C=%x\n", temp);
+
+ temp = serial_in_i2c( ALC5628_I2C_ADDR, 0x3E );
+ //printk("reg3E=%x\n", temp);
+
+ temp = serial_in_i2c( ALC5628_I2C_ADDR, 0x40 );
+ //printk("reg40=%x\n", temp);
+
+ temp = serial_in_i2c( ALC5628_I2C_ADDR, 0x42 );
+ //printk("reg42=%x\n", temp);
+
+ temp = serial_in_i2c( ALC5628_I2C_ADDR, 0x44 );
+ //printk("reg44=%x\n", temp);
+
+ temp = serial_in_i2c( ALC5628_I2C_ADDR, 0x5A );
+ //printk("reg5A=%x\n", temp);
+
+ temp = serial_in_i2c( ALC5628_I2C_ADDR, 0x5C );
+ //printk("reg5C=%x\n", temp);
+
+ temp = serial_in_i2c( ALC5628_I2C_ADDR, 0x5E );
+ //printk("reg5E=%x\n", temp);
+
+ temp = serial_in_i2c( ALC5628_I2C_ADDR, 0x68 );
+ //printk("reg68=%x\n", temp);
+
+ temp = serial_in_i2c( ALC5628_I2C_ADDR, 0x6A );
+ //printk("reg6A=%x\n", temp);
+
+ temp = serial_in_i2c( ALC5628_I2C_ADDR, 0x6C );
+ //printk("reg6C=%x\n", temp);
+}
+
+// ------------------------------------------------------------------
+// ------------------------------------------------------------------
+// Early printk or bootcode
+
+#define rtlRegRead(addr) \
+ (*(volatile u32 *)addr)
+
+#define rtlRegWrite(addr, val) \
+ ((*(volatile u32 *)addr) = (val))
+
+static inline u32 rtlRegMask(u32 addr, u32 mask, u32 value)
+{
+ u32 reg;
+
+ reg = rtlRegRead(addr);
+ reg &= ~mask;
+ reg |= value & mask;
+ rtlRegWrite(addr, reg);
+ reg = rtlRegRead(addr); /* flush write to the hardware */
+
+ return reg;
+}
+
+static int __init alc5628_init(void)
+{
+ int ret;
+ rtlRegMask(0xb8000010, 0x03DCB000, 0x01DCB000);//enable iis controller clock
+ rtlRegMask(0xb8000058, 0x00000001, 0x00000001);//enable 24p576mHz clock
+
+ /* Configure the I2S pins in correct mode */
+#if 1 // set the jtag as iis-audio
+ rtlRegMask(0xb8000040, 0x00000007, 0x00000003);//change pin mux to iis-voice pin
+#else // set the led-phase or lec-sig as iis-audio
+ rtlRegMask(0xb8000044, 0x001F80DB, 0x00000049);//change pin mux to iis-voice pin
+#endif
+
+ alc5628_init_i2c();
+
+ return 0;
+}
+
+#ifndef __BOOTCODE__
+module_init(alc5628_init);
+
+MODULE_AUTHOR("Realtek");
+MODULE_DESCRIPTION("i2c driver for ALC5628");
+MODULE_LICENSE("GPL");
+#endif \ No newline at end of file