|  |  | 
|  | /* | 
|  | * drivers/i2c/aml_i2c.c | 
|  | * | 
|  | * Copyright (C) 2015 Amlogic, Inc. All rights reserved. | 
|  | * | 
|  | * This program is free software; you can redistribute it and/or modify | 
|  | * it under the terms of the GNU General Public License as published by | 
|  | * the Free Software Foundation; either version 2 of the License, or | 
|  | * (at your option) any later version. | 
|  | * | 
|  | * This program is distributed in the hope that it will be useful, but WITHOUT | 
|  | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | 
|  | * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for | 
|  | * more details. | 
|  | * | 
|  | * You should have received a copy of the GNU General Public License along | 
|  | * with this program; if not, write to the Free Software Foundation, Inc., | 
|  | * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. | 
|  | */ | 
|  |  | 
|  | #include <common.h> | 
|  | #include <dm.h> | 
|  | #include <errno.h> | 
|  | #include <fdtdec.h> | 
|  | #include <i2c.h> | 
|  | #include <linux/types.h> | 
|  | //#include <linux/mtd/compat.h> | 
|  | #include <asm-generic/errno.h> | 
|  |  | 
|  | #include <asm/arch/clock.h> | 
|  | #include <asm/arch/i2c.h> | 
|  | #include <asm/arch/io.h> | 
|  |  | 
|  | #include <aml_i2c.h> | 
|  |  | 
|  | #define HAS_AO_MODULE | 
|  | #define AML_I2C_CTRL_CLK_DELAY_MASK    (0x3FF) | 
|  | #define AML_I2C_SLAVE_ADDR_MASK        (0xFF) | 
|  | #define AML_I2C_SLAVE_ADDR_MASK_7BIT   (0x7F) | 
|  |  | 
|  | #define AML_I2C_ASSERT(X)							\ | 
|  | do {												\ | 
|  | if (unlikely(!(X))) {							\ | 
|  | printf("\n");								\ | 
|  | printf("CacheFiles: Assertion failed\n");	\ | 
|  | BUG();										\ | 
|  | }												\ | 
|  | } while (0) | 
|  |  | 
|  |  | 
|  | #define AML_I2C_DBG(level,fmt,args... ) do { \ | 
|  | if (g_aml_i2c_data.i2c_debug > level) 	 \ | 
|  | printf(fmt,##args); 				 \ | 
|  | }while(0) | 
|  |  | 
|  | extern struct aml_i2c_platform g_aml_i2c_plat; | 
|  | struct aml_i2c_platform *g_i2c_ports; | 
|  | static unsigned char g_bAmlogicI2CInitialized = 0; //I2C initialized flag | 
|  | static unsigned char g_cur_bus_num = 0; | 
|  |  | 
|  | static struct aml_i2c g_aml_i2c_data = { | 
|  | .i2c_debug     = 0, | 
|  | .cur_slave_addr= 0, | 
|  | .wait_count    = 0, | 
|  | .wait_ack_interval = 0, | 
|  | .wait_read_interval= 0, | 
|  | .wait_xfer_interval= 0, | 
|  | .master_no = 0, | 
|  | .msg_flags = 0, | 
|  | .ops       = 0, | 
|  | .master_regs = 0, | 
|  | .reg_base    = 0, | 
|  | .use_pio     = 0, | 
|  | .master_i2c_speed= 0, | 
|  | }; | 
|  |  | 
|  | static void aml_i2c_set_clk(struct aml_i2c *i2c) | 
|  | { | 
|  | AML_I2C_DBG(1, "FILE:%s:%d, FUNC:%s\n", __FILE__,__LINE__,__func__); | 
|  | unsigned int i2c_clock_set; | 
|  | unsigned int sys_clk; | 
|  | volatile struct aml_i2c_reg_ctrl* ctrl; | 
|  | //have not thought about sleep mode, sleep mode is low system clock | 
|  | sys_clk = get_clk81(); | 
|  | AML_I2C_DBG(1, "clk81 is 0x%x\n", sys_clk); | 
|  |  | 
|  | i2c_clock_set = sys_clk / i2c->master_i2c_speed; | 
|  |  | 
|  | AML_I2C_DBG(1, "i2c->master_i2c_speed is 0x%x\n", i2c->master_i2c_speed); | 
|  | #if 1 | 
|  | i2c_clock_set >>= 1; | 
|  | ctrl = (struct aml_i2c_reg_ctrl*)&(i2c->master_regs->i2c_ctrl); | 
|  | if (i2c_clock_set > 0xfff) i2c_clock_set = 0xfff; | 
|  | ctrl->clk_delay = i2c_clock_set & 0x3ff; | 
|  | ctrl->clk_delay_ext = i2c_clock_set >> 10; | 
|  | i2c->master_regs->i2c_slave_addr &= ~(0xfff<<16); | 
|  | i2c->master_regs->i2c_slave_addr |= (i2c_clock_set>>1)<<16; | 
|  | i2c->master_regs->i2c_slave_addr |= 1<<28; | 
|  | i2c->master_regs->i2c_slave_addr &= ~(0x3f<<8); //no filter on scl&sda | 
|  | #else | 
|  | i2c_clock_set >>= 2; | 
|  |  | 
|  | AML_I2C_DBG(1, "i2c_clock_set is 0x%x\n", i2c_clock_set); | 
|  |  | 
|  | ctrl = (struct aml_i2c_reg_ctrl*)&(i2c->master_regs->i2c_ctrl); | 
|  | ctrl->clk_delay = i2c_clock_set & AML_I2C_CTRL_CLK_DELAY_MASK; | 
|  | #endif | 
|  | } | 
|  |  | 
|  | static void aml_i2c_set_platform_data(struct aml_i2c *i2c, | 
|  | struct aml_i2c_platform *plat) | 
|  | { | 
|  | AML_I2C_DBG(1, "FILE:%s:%d, FUNC:%s\n", __FILE__,__LINE__,__func__); | 
|  | i2c->master_i2c_speed = plat->master_i2c_speed; | 
|  | i2c->wait_count = plat->wait_count; | 
|  | i2c->wait_ack_interval = plat->wait_ack_interval; | 
|  | i2c->wait_read_interval = plat->wait_read_interval; | 
|  | i2c->wait_xfer_interval = plat->wait_xfer_interval; | 
|  |  | 
|  | if (I2C_MASTER_A == i2c->master_no) { | 
|  | i2c->master_pinmux.scl_reg = plat->master_a_pinmux.scl_reg; | 
|  | i2c->master_pinmux.scl_bit = plat->master_a_pinmux.scl_bit; | 
|  | i2c->master_pinmux.sda_reg = plat->master_a_pinmux.sda_reg; | 
|  | i2c->master_pinmux.sda_bit = plat->master_a_pinmux.sda_bit; | 
|  | } | 
|  | else if(I2C_MASTER_B == i2c->master_no){ | 
|  | i2c->master_pinmux.scl_reg = plat->master_b_pinmux.scl_reg; | 
|  | i2c->master_pinmux.scl_bit = plat->master_b_pinmux.scl_bit; | 
|  | i2c->master_pinmux.sda_reg = plat->master_b_pinmux.sda_reg; | 
|  | i2c->master_pinmux.sda_bit = plat->master_b_pinmux.sda_bit; | 
|  | } | 
|  | else if(I2C_MASTER_C == i2c->master_no){ | 
|  | i2c->master_pinmux.scl_reg = plat->master_c_pinmux.scl_reg; | 
|  | i2c->master_pinmux.scl_bit = plat->master_c_pinmux.scl_bit; | 
|  | i2c->master_pinmux.sda_reg = plat->master_c_pinmux.sda_reg; | 
|  | i2c->master_pinmux.sda_bit = plat->master_c_pinmux.sda_bit; | 
|  | } | 
|  | else if(I2C_MASTER_D == i2c->master_no){ | 
|  | i2c->master_pinmux.scl_reg = plat->master_d_pinmux.scl_reg; | 
|  | i2c->master_pinmux.scl_bit = plat->master_d_pinmux.scl_bit; | 
|  | i2c->master_pinmux.sda_reg = plat->master_d_pinmux.sda_reg; | 
|  | i2c->master_pinmux.sda_bit = plat->master_d_pinmux.sda_bit; | 
|  | } | 
|  | #ifdef HAS_AO_MODULE | 
|  | else if(I2C_MASTER_AO == i2c->master_no){ | 
|  | i2c->master_pinmux.scl_reg = plat->master_ao_pinmux.scl_reg; | 
|  | i2c->master_pinmux.scl_bit = plat->master_ao_pinmux.scl_bit; | 
|  | i2c->master_pinmux.sda_reg = plat->master_ao_pinmux.sda_reg; | 
|  | i2c->master_pinmux.sda_bit = plat->master_ao_pinmux.sda_bit; | 
|  | } | 
|  | #endif | 
|  | } | 
|  |  | 
|  | static void aml_i2c_pinmux_master(struct aml_i2c *i2c) | 
|  | { | 
|  | AML_I2C_DBG(1, "FILE:%s:%d, FUNC:%s\n", __FILE__,__LINE__,__func__); | 
|  | unsigned int scl_pinmux; | 
|  | unsigned int sda_pinmux; | 
|  |  | 
|  | scl_pinmux = readl(i2c->master_pinmux.scl_reg); | 
|  | scl_pinmux |= i2c->master_pinmux.scl_bit; | 
|  | writel(scl_pinmux, i2c->master_pinmux.scl_reg); | 
|  |  | 
|  | sda_pinmux = readl(i2c->master_pinmux.sda_reg); | 
|  | sda_pinmux |= i2c->master_pinmux.sda_bit; | 
|  | writel(sda_pinmux, i2c->master_pinmux.sda_reg); | 
|  | } | 
|  |  | 
|  | static void aml_i2c_dbg(struct aml_i2c *i2c) | 
|  | { | 
|  | AML_I2C_DBG(1, "FILE:%s:%d, FUNC:%s\n", __FILE__,__LINE__,__func__); | 
|  | int i; | 
|  | struct aml_i2c_reg_ctrl* ctrl; | 
|  |  | 
|  | if (i2c->i2c_debug == 0) | 
|  | return ; | 
|  |  | 
|  | printf( "i2c_slave_addr:  0x%x\n", | 
|  | i2c->master_regs->i2c_slave_addr); | 
|  | printf( "i2c_token_list_0:  0x%x\n", | 
|  | i2c->master_regs->i2c_token_list_0); | 
|  | printf( "i2c_token_list_1:  0x%x\n", | 
|  | i2c->master_regs->i2c_token_list_1); | 
|  | printf( "i2c_token_wdata_0:  0x%x\n", | 
|  | i2c->master_regs->i2c_token_wdata_0); | 
|  | printf( "i2c_token_wdata_1:  0x%x\n", | 
|  | i2c->master_regs->i2c_token_wdata_1); | 
|  | printf( "i2c_token_rdata_0:  0x%x\n", | 
|  | i2c->master_regs->i2c_token_rdata_0); | 
|  | printf( "i2c_token_rdata_1:  0x%x\n", | 
|  | i2c->master_regs->i2c_token_rdata_1); | 
|  | for (i=0; i<AML_I2C_MAX_TOKENS; i++) | 
|  | printf("token_tag[%d]  %d\n", i, i2c->token_tag[i]); | 
|  |  | 
|  | ctrl = ((struct aml_i2c_reg_ctrl*)&(i2c->master_regs->i2c_ctrl)); | 
|  | printf( "i2c_ctrl:  0x%x\n", i2c->master_regs->i2c_ctrl); | 
|  | printf( "ctrl.rdsda  0x%x\n", ctrl->rdsda); | 
|  | printf( "ctrl.rdscl  0x%x\n", ctrl->rdscl); | 
|  | printf( "ctrl.wrsda  0x%x\n", ctrl->wrsda); | 
|  | printf( "ctrl.wrscl  0x%x\n", ctrl->wrscl); | 
|  | printf( "ctrl.manual_en  0x%x\n", ctrl->manual_en); | 
|  | printf( "ctrl.clk_delay  0x%x\n", ctrl->clk_delay); | 
|  | printf( "ctrl.rd_data_cnt  0x%x\n", ctrl->rd_data_cnt); | 
|  | printf( "ctrl.cur_token  0x%x\n", ctrl->cur_token); | 
|  | printf( "ctrl.error  0x%x\n", ctrl->error); | 
|  | printf( "ctrl.status  0x%x\n", ctrl->status); | 
|  | printf( "ctrl.ack_ignore  0x%x\n", ctrl->ack_ignore); | 
|  | printf( "ctrl.start  0x%x\n", ctrl->start); | 
|  |  | 
|  | } | 
|  |  | 
|  | static void aml_i2c_clear_token_list(struct aml_i2c *i2c) | 
|  | { | 
|  | AML_I2C_DBG(1, "FILE:%s:%d, FUNC:%s\n", __FILE__,__LINE__,__func__); | 
|  | i2c->master_regs->i2c_token_list_0 = 0; | 
|  | i2c->master_regs->i2c_token_list_1 = 0; | 
|  | memset(i2c->token_tag, TOKEN_END, AML_I2C_MAX_TOKENS); | 
|  | } | 
|  |  | 
|  | static void aml_i2c_set_token_list(struct aml_i2c *i2c) | 
|  | { | 
|  | AML_I2C_DBG(1, "FILE:%s:%d, FUNC:%s\n", __FILE__,__LINE__,__func__); | 
|  | int i; | 
|  | unsigned int token_reg=0; | 
|  |  | 
|  | for (i=0; i<AML_I2C_MAX_TOKENS; i++) | 
|  | token_reg |= i2c->token_tag[i]<<(i*4); | 
|  |  | 
|  | i2c->master_regs->i2c_token_list_0=token_reg; | 
|  | } | 
|  |  | 
|  | static void aml_i2c_hw_init(struct aml_i2c *i2c, unsigned int use_pio) | 
|  | { | 
|  | AML_I2C_DBG(1, "FILE:%s:%d, FUNC:%s\n", __FILE__,__LINE__,__func__); | 
|  | struct aml_i2c_reg_ctrl* ctrl; | 
|  |  | 
|  | aml_i2c_set_clk(i2c); | 
|  |  | 
|  | /*manual mode*/ | 
|  | if (use_pio) { | 
|  | ctrl = (struct aml_i2c_reg_ctrl*)&(i2c->master_regs->i2c_ctrl); | 
|  | ctrl->manual_en = 1; | 
|  | } | 
|  | } | 
|  |  | 
|  | static int aml_i2c_check_error(struct aml_i2c *i2c) | 
|  | { | 
|  | AML_I2C_DBG(1, "FILE:%s:%d, FUNC:%s\n", __FILE__,__LINE__,__func__); | 
|  | struct aml_i2c_reg_ctrl* ctrl; | 
|  | ctrl = (struct aml_i2c_reg_ctrl*)&(i2c->master_regs->i2c_ctrl); | 
|  |  | 
|  | if (ctrl->error) | 
|  | { | 
|  | //printf( "ctrl.cur_token  0x%x\n", ctrl->cur_token); | 
|  | return -EIO; | 
|  | } | 
|  | else | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | /*poll status*/ | 
|  | static int aml_i2c_wait_ack(struct aml_i2c *i2c) | 
|  | { | 
|  | AML_I2C_DBG(1, "FILE:%s:%d, FUNC:%s\n", __FILE__,__LINE__,__func__); | 
|  | int i; | 
|  | struct aml_i2c_reg_ctrl* ctrl; | 
|  |  | 
|  | for (i=0; i<i2c->wait_count; i++) { | 
|  | udelay(i2c->wait_ack_interval); | 
|  | ctrl = (struct aml_i2c_reg_ctrl*)&(i2c->master_regs->i2c_ctrl); | 
|  | if (I2C_IDLE == ctrl->status) | 
|  | return aml_i2c_check_error(i2c); | 
|  | } | 
|  |  | 
|  | return -ETIMEDOUT; | 
|  | } | 
|  |  | 
|  | static void aml_i2c_get_read_data(struct aml_i2c *i2c, unsigned char *buf, | 
|  | size_t len) | 
|  | { | 
|  | AML_I2C_DBG(1, "FILE:%s:%d, FUNC:%s\n", __FILE__,__LINE__,__func__); | 
|  | int i; | 
|  | unsigned long rdata0 = i2c->master_regs->i2c_token_rdata_0; | 
|  | unsigned long rdata1 = i2c->master_regs->i2c_token_rdata_1; | 
|  |  | 
|  | for (i = 0; i< min_t(size_t, len, AML_I2C_MAX_TOKENS>>1); i++) | 
|  | *buf++ = (rdata0 >> (i*8)) & 0xff; | 
|  |  | 
|  | for (i = 4; i< min_t(size_t, len, AML_I2C_MAX_TOKENS); i++) | 
|  | *buf++ = (rdata1 >> ((i - (AML_I2C_MAX_TOKENS>>1))*8)) & 0xff; | 
|  | } | 
|  |  | 
|  | static void aml_i2c_fill_data(struct aml_i2c *i2c, unsigned char *buf, | 
|  | size_t len) | 
|  | { | 
|  | AML_I2C_DBG(1, "FILE:%s:%d, FUNC:%s\n", __FILE__,__LINE__,__func__); | 
|  | int i; | 
|  | unsigned int wdata0 = 0; | 
|  | unsigned int wdata1 = 0; | 
|  |  | 
|  | for (i = 0; i< min_t(size_t, len, AML_I2C_MAX_TOKENS>>1); i++) | 
|  | wdata0 |= (*buf++) << (i*8); | 
|  |  | 
|  | for (i = 4; i< min_t(size_t, len, AML_I2C_MAX_TOKENS); i++) | 
|  | wdata1 |= (*buf++) << ((i - (AML_I2C_MAX_TOKENS>>1))*8); | 
|  |  | 
|  | i2c->master_regs->i2c_token_wdata_0 = wdata0; | 
|  | i2c->master_regs->i2c_token_wdata_1 = wdata1; | 
|  | } | 
|  |  | 
|  | static void aml_i2c_xfer_prepare(struct aml_i2c *i2c) | 
|  | { | 
|  | AML_I2C_DBG(1, "FILE:%s:%d, FUNC:%s\n", __FILE__,__LINE__,__func__); | 
|  | aml_i2c_pinmux_master(i2c); | 
|  | aml_i2c_set_clk(i2c); | 
|  | } | 
|  |  | 
|  | static void aml_i2c_start_token_xfer(struct aml_i2c *i2c) | 
|  | { | 
|  | AML_I2C_DBG(1, "FILE:%s:%d, FUNC:%s\n", __FILE__,__LINE__,__func__); | 
|  |  | 
|  | i2c->master_regs->i2c_ctrl &= ~1;  /*clear*/ | 
|  | i2c->master_regs->i2c_ctrl |= 1;   /*set*/ | 
|  |  | 
|  | udelay(i2c->wait_xfer_interval); | 
|  | } | 
|  |  | 
|  | /*Amlogic I2C controller will send write data with slave addr in the token list, | 
|  | and set addr into addr reg is enough*/ | 
|  | static int aml_i2c_do_address(struct aml_i2c *i2c, unsigned int addr) | 
|  | { | 
|  | AML_I2C_DBG(1, "FILE:%s:%d, FUNC:%s\n", __FILE__,__LINE__,__func__); | 
|  |  | 
|  | i2c->cur_slave_addr = addr & AML_I2C_SLAVE_ADDR_MASK_7BIT; | 
|  | #if 1 | 
|  | i2c->master_regs->i2c_slave_addr &=(~AML_I2C_SLAVE_ADDR_MASK); | 
|  |  | 
|  | i2c->master_regs->i2c_slave_addr |=(i2c->cur_slave_addr<<1); | 
|  | #else | 
|  | i2c->master_regs->i2c_slave_addr = i2c->cur_slave_addr<<1; | 
|  | #endif | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | static void aml_i2c_stop(struct aml_i2c *i2c) | 
|  | { | 
|  | AML_I2C_DBG(1, "FILE:%s:%d, FUNC:%s\n", __FILE__,__LINE__,__func__); | 
|  | // aml_i2c_clear_token_list(i2c); | 
|  | // i2c->token_tag[0]=TOKEN_STOP; | 
|  | // aml_i2c_set_token_list(i2c); | 
|  | // aml_i2c_start_token_xfer(i2c); | 
|  | // aml_i2c_wait_ack(i2c); | 
|  | struct aml_i2c_reg_ctrl* ctrl; | 
|  | ctrl = (struct aml_i2c_reg_ctrl*)&(i2c->master_regs->i2c_ctrl); | 
|  | if (!ctrl->error) { | 
|  | AML_I2C_DBG(1, "FILE1:%s:%d, FUNC:%s\n", __FILE__,__LINE__,__func__); | 
|  | aml_i2c_clear_token_list(i2c); | 
|  | i2c->token_tag[0]=TOKEN_STOP; | 
|  | aml_i2c_set_token_list(i2c); | 
|  | aml_i2c_start_token_xfer(i2c); | 
|  | aml_i2c_wait_ack(i2c); | 
|  | } | 
|  | } | 
|  |  | 
|  | static long aml_i2c_read(struct aml_i2c *i2c, unsigned char *buf, | 
|  | size_t len) | 
|  | { | 
|  | AML_I2C_DBG(1, "FILE:%s:%d, FUNC:%s\n", __FILE__,__LINE__,__func__); | 
|  | int i; | 
|  | int ret; | 
|  | size_t rd_len; | 
|  | int tagnum=0; | 
|  |  | 
|  | aml_i2c_clear_token_list(i2c); | 
|  |  | 
|  | if (!(i2c->msg_flags & I2C_M_NOSTART)) { | 
|  | i2c->token_tag[tagnum++]=TOKEN_START; | 
|  | i2c->token_tag[tagnum++]=TOKEN_SLAVE_ADDR_READ; | 
|  |  | 
|  | aml_i2c_set_token_list(i2c); | 
|  | aml_i2c_dbg(i2c); | 
|  | aml_i2c_start_token_xfer(i2c); | 
|  |  | 
|  | udelay(i2c->wait_ack_interval); | 
|  |  | 
|  | ret = aml_i2c_wait_ack(i2c); | 
|  | if (ret<0) | 
|  | return ret; | 
|  | aml_i2c_clear_token_list(i2c); | 
|  | } | 
|  |  | 
|  | while (len) { | 
|  | tagnum = 0; | 
|  | rd_len = min_t(size_t, len, AML_I2C_MAX_TOKENS); | 
|  | if (rd_len == 1) | 
|  | i2c->token_tag[tagnum++]=TOKEN_DATA_LAST; | 
|  | else{ | 
|  | for (i=0; i<rd_len-1; i++) | 
|  | i2c->token_tag[tagnum++]=TOKEN_DATA; | 
|  | if (len > rd_len) | 
|  | i2c->token_tag[tagnum++]=TOKEN_DATA; | 
|  | else | 
|  | i2c->token_tag[tagnum++]=TOKEN_DATA_LAST; | 
|  | } | 
|  | aml_i2c_set_token_list(i2c); | 
|  | aml_i2c_dbg(i2c); | 
|  | aml_i2c_start_token_xfer(i2c); | 
|  |  | 
|  | udelay(i2c->wait_ack_interval); | 
|  |  | 
|  | ret = aml_i2c_wait_ack(i2c); | 
|  | if (ret<0) | 
|  | return ret; | 
|  |  | 
|  | aml_i2c_get_read_data(i2c, buf, rd_len); | 
|  | len -= rd_len; | 
|  | buf += rd_len; | 
|  |  | 
|  | aml_i2c_dbg(i2c); | 
|  | udelay(i2c->wait_read_interval); | 
|  | aml_i2c_clear_token_list(i2c); | 
|  | } | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | static long aml_i2c_write(struct aml_i2c *i2c, unsigned char *buf, | 
|  | size_t len) | 
|  | { | 
|  | AML_I2C_DBG(1, "FILE:%s:%d, FUNC:%s\n", __FILE__,__LINE__,__func__); | 
|  | int i; | 
|  | int ret; | 
|  | size_t wr_len; | 
|  | int tagnum=0; | 
|  |  | 
|  | aml_i2c_clear_token_list(i2c); | 
|  |  | 
|  | if (!(i2c->msg_flags & I2C_M_NOSTART)) { | 
|  | i2c->token_tag[tagnum++]=TOKEN_START; | 
|  | i2c->token_tag[tagnum++]=TOKEN_SLAVE_ADDR_WRITE; | 
|  | } | 
|  | while (len) { | 
|  | wr_len = min_t(size_t, len, AML_I2C_MAX_TOKENS-tagnum); | 
|  | for (i=0; i<wr_len; i++) | 
|  | i2c->token_tag[tagnum++]=TOKEN_DATA; | 
|  |  | 
|  | aml_i2c_set_token_list(i2c); | 
|  |  | 
|  | aml_i2c_fill_data(i2c, buf, wr_len); | 
|  |  | 
|  | aml_i2c_dbg(i2c); | 
|  | aml_i2c_start_token_xfer(i2c); | 
|  |  | 
|  | len -= wr_len; | 
|  | buf += wr_len; | 
|  | tagnum = 0; | 
|  |  | 
|  | ret = aml_i2c_wait_ack(i2c); | 
|  | if (ret<0) | 
|  | return ret; | 
|  |  | 
|  | aml_i2c_clear_token_list(i2c); | 
|  | } | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | static struct aml_i2c_ops g_aml_i2c_m1_ops = { | 
|  | .xfer_prepare = aml_i2c_xfer_prepare, | 
|  | .read 		  = aml_i2c_read, | 
|  | .write 		  = aml_i2c_write, | 
|  | .do_address	  = aml_i2c_do_address, | 
|  | .stop		  = aml_i2c_stop, | 
|  | }; | 
|  |  | 
|  | /*General i2c master transfer*/ | 
|  | int aml_i2c_xfer(struct i2c_msg *msgs, | 
|  | int num) | 
|  | { | 
|  | AML_I2C_DBG(1, "FILE:%s:%d, FUNC:%s\n", __FILE__,__LINE__,__func__); | 
|  |  | 
|  | if (0 == g_bAmlogicI2CInitialized) { | 
|  | return -ENXIO; //device not initialized | 
|  | } | 
|  |  | 
|  | struct aml_i2c *i2c = &g_aml_i2c_data; | 
|  | struct i2c_msg * p=0; | 
|  | unsigned int i; | 
|  | unsigned int ret=0; | 
|  |  | 
|  | i2c->ops->xfer_prepare(i2c); | 
|  |  | 
|  | for (i = 0; !ret && i < num; i++) { | 
|  | p = &msgs[i]; | 
|  | i2c->msg_flags = p->flags; | 
|  | ret = i2c->ops->do_address(i2c, p->addr); | 
|  | if (ret || !p->len) | 
|  | { | 
|  | continue; | 
|  | } | 
|  | if (p->flags & I2C_M_RD) | 
|  | ret = i2c->ops->read(i2c, p->buf, p->len); | 
|  | else | 
|  | ret = i2c->ops->write(i2c, p->buf, p->len); | 
|  | } | 
|  |  | 
|  | i2c->ops->stop(i2c); | 
|  |  | 
|  |  | 
|  | if (p->flags & I2C_M_RD) { | 
|  | AML_I2C_DBG(0, "read "); | 
|  | } | 
|  | else { | 
|  | AML_I2C_DBG(0, "write "); | 
|  | } | 
|  | for (i=0;i<p->len;i++) | 
|  | AML_I2C_DBG(0, "%x-",*(p->buf)++); | 
|  | AML_I2C_DBG(0, "\n"); | 
|  |  | 
|  | /* Return the number of messages processed, or the error code*/ | 
|  | if (ret == 0) | 
|  | return num; | 
|  | else { | 
|  | printf("[aml_i2c_xfer] error ret = %d \t", ret); | 
|  | printf("i2c master %s current slave addr is 0x%x\n", | 
|  | i2c->master_no?"a":"b", i2c->cur_slave_addr); | 
|  | return ret; | 
|  | } | 
|  | } | 
|  | /*General i2c master transfer 100k*/ | 
|  | int aml_i2c_xfer_slow(struct i2c_msg *msgs, | 
|  | int num) | 
|  | { | 
|  | AML_I2C_DBG(1, "FILE:%s:%d, FUNC:%s\n", __FILE__,__LINE__,__func__); | 
|  | struct aml_i2c *i2c = &g_aml_i2c_data; | 
|  | struct i2c_msg * p=0; | 
|  | unsigned int i; | 
|  | unsigned int ret=0; | 
|  | unsigned int last_speed = i2c->master_i2c_speed; | 
|  |  | 
|  |  | 
|  | i2c->master_i2c_speed = AML_I2C_SPPED_100K;/* change speed in i2c->lock*/ | 
|  | i2c->ops->xfer_prepare(i2c); | 
|  |  | 
|  | for (i = 0; !ret && i < num; i++) { | 
|  | p = &msgs[i]; | 
|  | i2c->msg_flags = p->flags; | 
|  | //ret = i2c->ops->do_address(i2c, p->addr, p->buf, p->flags & I2C_M_RD, p->len); | 
|  | ret = i2c->ops->do_address(i2c, p->addr); | 
|  | if (ret || !p->len) | 
|  | continue; | 
|  | if (p->flags & I2C_M_RD) | 
|  | ret = i2c->ops->read(i2c, p->buf, p->len); | 
|  | else | 
|  | ret = i2c->ops->write(i2c, p->buf, p->len); | 
|  | } | 
|  |  | 
|  | i2c->ops->stop(i2c); | 
|  |  | 
|  |  | 
|  | AML_I2C_DBG(0, "aml_i2c_xfer_slow"); | 
|  | if (p->flags & I2C_M_RD) { | 
|  | AML_I2C_DBG(0, "read "); | 
|  | } | 
|  | else { | 
|  | AML_I2C_DBG(0, "write "); | 
|  | } | 
|  | for (i=0;i<p->len;i++) | 
|  | AML_I2C_DBG(0, "%x-",*(p->buf)++); | 
|  | AML_I2C_DBG(0, "\n"); | 
|  |  | 
|  | i2c->master_i2c_speed = last_speed; | 
|  | /* Return the number of messages processed, or the error code*/ | 
|  | if (ret == 0) | 
|  | return num; | 
|  | else | 
|  | return ret; | 
|  | } | 
|  |  | 
|  |  | 
|  | /***************i2c class****************/ | 
|  |  | 
|  | __attribute__((unused))  static ssize_t show_i2c_debug(void) | 
|  | { | 
|  | struct aml_i2c *i2c = &g_aml_i2c_data; | 
|  | printf("i2c debug is 0x%x\n", i2c->i2c_debug); | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | __attribute__((unused))  static ssize_t show_i2c_info(void) | 
|  | { | 
|  | struct aml_i2c *i2c = &g_aml_i2c_data; | 
|  | struct aml_i2c_reg_ctrl* ctrl; | 
|  |  | 
|  | printf( "i2c master %s current slave addr is 0x%x\n", | 
|  | i2c->master_no?"b":"a", i2c->cur_slave_addr); | 
|  | printf( "wait ack timeout is 0x%x\n", | 
|  | i2c->wait_count * i2c->wait_ack_interval); | 
|  | printf( "master regs base is 0x%lx \n", | 
|  | (unsigned long)(i2c->master_regs)); | 
|  |  | 
|  | ctrl = ((struct aml_i2c_reg_ctrl*)&(i2c->master_regs->i2c_ctrl)); | 
|  | printf( "i2c_ctrl:  0x%x\n", i2c->master_regs->i2c_ctrl); | 
|  | printf( "ctrl.rdsda  0x%x\n", ctrl->rdsda); | 
|  | printf( "ctrl.rdscl  0x%x\n", ctrl->rdscl); | 
|  | printf( "ctrl.wrsda  0x%x\n", ctrl->wrsda); | 
|  | printf( "ctrl.wrscl  0x%x\n", ctrl->wrscl); | 
|  | printf( "ctrl.manual_en  0x%x\n", ctrl->manual_en); | 
|  | printf( "ctrl.clk_delay  0x%x\n", ctrl->clk_delay); | 
|  | printf( "ctrl.rd_data_cnt  0x%x\n", ctrl->rd_data_cnt); | 
|  | printf( "ctrl.cur_token  0x%x\n", ctrl->cur_token); | 
|  | printf( "ctrl.error  0x%x\n", ctrl->error); | 
|  | printf( "ctrl.status  0x%x\n", ctrl->status); | 
|  | printf( "ctrl.ack_ignore  0x%x\n", ctrl->ack_ignore); | 
|  | printf( "ctrl.start  0x%x\n", ctrl->start); | 
|  |  | 
|  | printf( "i2c_slave_addr:  0x%x\n", | 
|  | i2c->master_regs->i2c_slave_addr); | 
|  | printf( "i2c_token_list_0:  0x%x\n", | 
|  | i2c->master_regs->i2c_token_list_0); | 
|  | printf( "i2c_token_list_1:  0x%x\n", | 
|  | i2c->master_regs->i2c_token_list_1); | 
|  | printf( "i2c_token_wdata_0:  0x%x\n", | 
|  | i2c->master_regs->i2c_token_wdata_0); | 
|  | printf( "i2c_token_wdata_1:  0x%x\n", | 
|  | i2c->master_regs->i2c_token_wdata_1); | 
|  | printf( "i2c_token_rdata_0:  0x%x\n", | 
|  | i2c->master_regs->i2c_token_rdata_0); | 
|  | printf( "i2c_token_rdata_1:  0x%x\n", | 
|  | i2c->master_regs->i2c_token_rdata_1); | 
|  |  | 
|  | printf( "master pinmux\n"); | 
|  | printf( "scl_reg:  0x%lx\n", i2c->master_pinmux.scl_reg); | 
|  | printf( "scl_bit:  0x%x\n", i2c->master_pinmux.scl_bit); | 
|  | printf( "sda_reg:  0x%lx\n", i2c->master_pinmux.sda_reg); | 
|  | printf( "sda_bit:  0x%x\n", i2c->master_pinmux.sda_bit); | 
|  |  | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | static const unsigned long g_aml_i2c_reg_start[] = { | 
|  | [0] = MESON_I2C_MASTER_AO_START,/*master a*/ | 
|  | [1] = MESON_I2C_MASTER_A_START,/*master a*/ | 
|  | [2] = MESON_I2C_MASTER_B_START,/*master b*/ | 
|  | [3] = MESON_I2C_MASTER_C_START,/*master b*/ | 
|  | [4] = MESON_I2C_MASTER_D_START,/*master b*/ | 
|  | //    [2] = MESON_I2C_SLAVE_START,/*slave*/ | 
|  |  | 
|  | #ifdef HAS_AO_MODULE | 
|  | [3] = MESON_I2C_MASTER_AO_START,/*master ao*/ | 
|  | #endif | 
|  | }; | 
|  |  | 
|  | int aml_i2c_init_port(struct aml_i2c_platform *plat) | 
|  | { | 
|  |  | 
|  | struct aml_i2c *i2c = &g_aml_i2c_data; | 
|  |  | 
|  | if (plat == NULL) | 
|  | { | 
|  | printf("\nERROR! struct aml_i2c_platform *plat is a NULL pointer!\n"); | 
|  | return	-1; | 
|  | } | 
|  |  | 
|  | i2c->ops = &g_aml_i2c_m1_ops; | 
|  | i2c->master_no = plat->master_no; | 
|  |  | 
|  | i2c->use_pio = plat->use_pio; | 
|  | AML_I2C_ASSERT(i2c->master_no <= 4); | 
|  |  | 
|  | /*master a or master b*/ | 
|  | if (i2c->master_no >= ARRAY_SIZE(g_aml_i2c_reg_start)) | 
|  | { | 
|  | printf("\nERROR!	overflow: i2c->master_no = %d\n", i2c->master_no); | 
|  | return	-1; | 
|  | } | 
|  |  | 
|  | printf("%s init regs for %d\n", __func__, i2c->master_no); | 
|  | i2c->master_regs = (struct aml_i2c_reg_master __iomem*)(g_aml_i2c_reg_start[i2c->master_no]); | 
|  |  | 
|  | AML_I2C_ASSERT(i2c->master_regs); | 
|  | AML_I2C_ASSERT(plat); | 
|  |  | 
|  | aml_i2c_set_platform_data(i2c, plat); | 
|  | aml_i2c_xfer_prepare(i2c); | 
|  |  | 
|  | aml_i2c_hw_init(i2c , i2c->use_pio); | 
|  |  | 
|  | g_bAmlogicI2CInitialized = 1; | 
|  |  | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | int aml_i2c_init(void) | 
|  | { | 
|  | return aml_i2c_init_port(g_i2c_ports + g_cur_bus_num); | 
|  | } | 
|  |  | 
|  | /***************************** | 
|  | ** add by wch for cmd_i2c ** | 
|  | ****************************/ | 
|  | /* | 
|  | * i2c read cmd | 
|  | */ | 
|  | int i2c_read(uchar chip, uint addr, int alen, uchar *buffer, int len) | 
|  | { | 
|  | int ret = 0; | 
|  |  | 
|  | /* | 
|  | * I2C data address within the chip.  This can be 1 or | 
|  | * 2 bytes long.  Some day it might be 3 bytes long :-). | 
|  | * here,if it has 2 bytes long at most. | 
|  | */ | 
|  | uint8_t devaddr[2]; | 
|  |  | 
|  | switch (alen) | 
|  | { | 
|  | case 0:							 //NO I2C data address within the chip. | 
|  | puts ("'*.0' shows no i2c data or register address within the chip. \n"); | 
|  | return -1; | 
|  | break; | 
|  |  | 
|  | case 1:							 //I2C data address:1 byte long within the chip. | 
|  | if (addr>0xff) | 
|  | { | 
|  | puts ("'*.1' shows i2c data or register address 1 byte long within the chip. \n"); | 
|  | return -1; | 
|  | } | 
|  | else | 
|  | devaddr[0] = addr & 0xff; | 
|  | break; | 
|  |  | 
|  | case 2: | 
|  | #if 0 | 
|  | //I2C data address:2 bytes long within the chip. | 
|  | if (addr>0xffff || addr<0x1ff) | 
|  | { | 
|  | puts ("'*.2' shows i2c data or register address 2 bytes long within the chip. \n"); | 
|  | return -1; | 
|  | } | 
|  | else | 
|  | #endif | 
|  | { | 
|  | devaddr[0] = addr & 0xff; | 
|  | devaddr[1] = (addr >> 8) & 0xff; | 
|  | } | 
|  | break; | 
|  |  | 
|  | case 3:							 //I2C data address:3 bytes long within the chip. | 
|  | //Here,if it has 2 bytes long at most. | 
|  | puts ("Here,we have set i2c data address or register address 2 bytes long at most.\n"); | 
|  | return -1; | 
|  | break; | 
|  | } | 
|  |  | 
|  |  | 
|  | struct i2c_msg msg[] = { | 
|  | { | 
|  | .addr = chip, | 
|  | .flags = 0, | 
|  | .len = alen,             //I2C data address length. | 
|  | .buf = devaddr, | 
|  | }, | 
|  | { | 
|  | .addr = chip, | 
|  | .flags = 1, | 
|  | .len = len,              //read len bytes from I2C data address. | 
|  | .buf = buffer, | 
|  | } | 
|  | }; | 
|  |  | 
|  | ret = aml_i2c_xfer((struct i2c_msg *)msg, 2); | 
|  | if (ret < 0) { | 
|  | printf("%s: i2c transfer failed\n", __FUNCTION__); | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | /* | 
|  | printf("chip=0x%x,addr=0x%x,alen=%d,len=%d",chip,addr,alen,len); | 
|  | for (ret=0;ret<len;ret++) | 
|  | printf(",buffer[%d]=0x%x",ret,*buffer++); | 
|  | printf("\n"); | 
|  | */ | 
|  |  | 
|  | return 0; | 
|  | } | 
|  |  | 
|  |  | 
|  |  | 
|  | /* | 
|  | * i2c write cmd | 
|  | */ | 
|  | int i2c_write(unsigned char chip, unsigned int addr, int alen,unsigned char *buffer, int len) | 
|  | { | 
|  | int ret; | 
|  | int length = 0; | 
|  | uint8_t buff[3]; | 
|  |  | 
|  | /* | 
|  | * I2C data address within the chip.  This can be 1 or | 
|  | * 2 bytes long.  Some day it might be 3 bytes long :-). | 
|  | * here,if it has 2 bytes long at most. | 
|  | */ | 
|  | uint8_t devaddr[2] = {0}; | 
|  |  | 
|  | switch (alen) | 
|  | { | 
|  | case 0:							//NO I2C data address within the chip. | 
|  | puts ("'*.0' shows no i2c data or register address within the chip. \n"); | 
|  | return -1; | 
|  | break; | 
|  |  | 
|  | case 1:							//I2C data address:1 byte long within the chip. | 
|  | if (addr>0xff) | 
|  | { | 
|  | puts ("'*.1' shows i2c data or register address 1 byte long within the chip. \n"); | 
|  | return -1; | 
|  | } | 
|  | else | 
|  | devaddr[0] = addr & 0xff; | 
|  | break; | 
|  |  | 
|  | case 2: | 
|  | #if 0 | 
|  | //I2C data address:2 bytes long within the chip. | 
|  | if (addr>0xffff || addr<0x1ff) | 
|  | { | 
|  | puts ("'*.2' shows i2c data or register address 2 bytes long within the chip. \n"); | 
|  | return -1; | 
|  | } | 
|  | else | 
|  | #endif | 
|  | { | 
|  | devaddr[0] = addr & 0xff; | 
|  | devaddr[1] = (addr >> 8) & 0xff; | 
|  | } | 
|  | break; | 
|  |  | 
|  | case 3:							//I2C data address:3 bytes long within the chip. | 
|  | //Here,if it has 2 bytes long at most. | 
|  | puts ("Here,we have set i2c data address or register address 2 bytes long at most.\n"); | 
|  | return -1; | 
|  | break; | 
|  | } | 
|  |  | 
|  | if (len == 1) | 
|  | { | 
|  | switch (alen) | 
|  | { | 
|  |  | 
|  | case 1: | 
|  | buff[0] = devaddr[0]; | 
|  | buff[1] = *buffer; | 
|  | length = 2; | 
|  | break; | 
|  |  | 
|  | case 2: | 
|  | buff[0] = devaddr[0]; | 
|  | buff[1] = devaddr[1]; | 
|  | buff[2] = *buffer; | 
|  | length = 3; | 
|  | break; | 
|  | /* | 
|  | case 3: | 
|  | //when i2c data address or register address 3 bytes long ,here should be completed. | 
|  | break; | 
|  | */ | 
|  |  | 
|  | } | 
|  |  | 
|  | struct i2c_msg msg[] = { | 
|  | { | 
|  | .addr = chip, | 
|  | .flags = 0, | 
|  | .len = length, | 
|  | .buf = buff, | 
|  | } | 
|  | }; | 
|  |  | 
|  | ret = aml_i2c_xfer((struct i2c_msg *)msg, 1); | 
|  | if (ret < 0) { | 
|  | printf("%s: i2c transfer failed\n", __FUNCTION__); | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | } | 
|  | else | 
|  | { | 
|  | /* | 
|  | * This section may be modified when len > 1. | 
|  | */ | 
|  | printf("I2C write data length is %d. \n",len); | 
|  | return -1; | 
|  | } | 
|  |  | 
|  |  | 
|  |  | 
|  | return 0; | 
|  | } | 
|  |  | 
|  |  | 
|  |  | 
|  | /* | 
|  | * i2c probe cmd | 
|  | * return 0:i2c probe ok, non 0:i2c probe failed. | 
|  | */ | 
|  | int i2c_probe(uchar chip) | 
|  | { | 
|  | int ret; | 
|  | unsigned int addr=0x00;		//i2c data or register address | 
|  | struct aml_i2c *i2c = &g_aml_i2c_data; | 
|  | struct i2c_msg * p=0; | 
|  |  | 
|  | struct i2c_msg msg[] = { | 
|  | { | 
|  | .addr = chip, | 
|  | .flags = 0,			//write | 
|  | .len = 1, | 
|  | .buf = (unsigned char *)&addr, | 
|  | } | 
|  | }; | 
|  |  | 
|  |  | 
|  | i2c->ops->xfer_prepare(i2c); | 
|  |  | 
|  |  | 
|  | p = &msg[0]; | 
|  | i2c->msg_flags = p->flags; | 
|  | ret = i2c->ops->do_address(i2c, p->addr); | 
|  |  | 
|  | if (p->flags & I2C_M_RD) | 
|  | ret = i2c->ops->read(i2c, p->buf, p->len); | 
|  | else | 
|  | ret = i2c->ops->write(i2c, p->buf, p->len); | 
|  |  | 
|  | i2c->ops->stop(i2c); | 
|  |  | 
|  | if (ret == 0) | 
|  | return 0;          	 	//This chip valid. | 
|  | else | 
|  | return ret;         	//This chip invalid. | 
|  | } | 
|  |  | 
|  |  | 
|  |  | 
|  | /* | 
|  | * i2c reset cmd | 
|  | */ | 
|  | void i2c_init(int speed, int slaveaddr) | 
|  | { | 
|  | #define AML_I2C_SPPED_400K 400000		 //The initial value of amlogic i2c speed | 
|  |  | 
|  | if (g_i2c_ports == NULL) { | 
|  | g_i2c_ports = &g_aml_i2c_plat; | 
|  | g_cur_bus_num = 0; | 
|  | } | 
|  | aml_i2c_init(); | 
|  | } | 
|  |  | 
|  | void i2c_plat_init(void) | 
|  | { | 
|  | if (g_i2c_ports == NULL) { | 
|  | g_i2c_ports = &g_aml_i2c_plat; | 
|  | g_cur_bus_num = 0; | 
|  | } | 
|  | } | 
|  |  | 
|  |  | 
|  |  | 
|  | /* | 
|  | * i2c speed cmd | 
|  | * get i2c speed | 
|  | */ | 
|  | unsigned int i2c_get_bus_speed(void) | 
|  | { | 
|  |  | 
|  | return g_i2c_ports[g_cur_bus_num].master_i2c_speed; | 
|  | } | 
|  |  | 
|  |  | 
|  |  | 
|  | /* | 
|  | * i2c speed xxx cmd | 
|  | * set i2c speed | 
|  | */ | 
|  | int i2c_set_bus_speed(unsigned int speed) | 
|  | { | 
|  | /* | 
|  | #define AML_I2C_SPPED_50K			50000 | 
|  | #define AML_I2C_SPPED_100K			100000 | 
|  | #define AML_I2C_SPPED_200K			200000 | 
|  | #define AML_I2C_SPPED_300K			300000 | 
|  | #define AML_I2C_SPPED_400K			400000 | 
|  | */ | 
|  | if ((speed == 50000) || (speed == 100000) || (speed == 200000) || (speed == 300000) || (speed == 400000)) | 
|  | { | 
|  | g_i2c_ports[g_cur_bus_num].master_i2c_speed = speed; | 
|  | aml_i2c_init(); | 
|  | return 0; | 
|  | } | 
|  | else | 
|  | { | 
|  | printf("The I2C speed setting don't match,should choose:50000,100000,200000,300000 or 400000.\n"); | 
|  | return -1; | 
|  | } | 
|  |  | 
|  | } | 
|  | #if defined(CONFIG_CMD_EEPROM) | 
|  | int i2c_eeprom_write(unsigned char chip, unsigned int addr, int alen,unsigned char *buffer, int len) | 
|  | { | 
|  | int i, err; | 
|  | struct aml_i2c *i2c = &g_aml_i2c_data; | 
|  | unsigned char buf[4]; | 
|  |  | 
|  | if (alen > 4) return -1; | 
|  | for (i=0; i<alen; i++) { | 
|  | buf[i] = addr&0xff; | 
|  | addr >>= 8; | 
|  | } | 
|  |  | 
|  | i2c->msg_flags = 0; | 
|  | i2c->ops->xfer_prepare(i2c); | 
|  | i2c->ops->do_address(i2c, chip); | 
|  | err = i2c->ops->write(i2c, buf, alen); | 
|  | if (!err) { | 
|  | i2c->msg_flags |= I2C_M_NOSTART; | 
|  | err = i2c->ops->write(i2c, buffer, len); | 
|  | } | 
|  | i2c->ops->stop(i2c); | 
|  | return err; | 
|  | } | 
|  | #endif | 
|  |  | 
|  | /*General i2c master transfer,it can Send to a specific master control*/ | 
|  | int aml_i2c_transfer(int adap_num,struct i2c_msg *msgs, | 
|  | int num) | 
|  | { | 
|  | AML_I2C_DBG(1, "FILE:%s:%d, FUNC:%s\n", __FILE__,__LINE__,__func__); | 
|  |  | 
|  | if (0 == g_bAmlogicI2CInitialized) { | 
|  | return -ENXIO; //device not initialized | 
|  | } | 
|  |  | 
|  | g_aml_i2c_data.master_no = adap_num; | 
|  | struct aml_i2c *i2c = &g_aml_i2c_data; | 
|  | i2c->master_regs = (struct aml_i2c_reg_master __iomem*)(g_aml_i2c_reg_start[i2c->master_no]); | 
|  | struct i2c_msg * p=0; | 
|  | unsigned int i; | 
|  | unsigned int ret=0; | 
|  |  | 
|  | i2c->ops->xfer_prepare(i2c); | 
|  |  | 
|  | for (i = 0; !ret && i < num; i++) { | 
|  | p = &msgs[i]; | 
|  | i2c->msg_flags = p->flags; | 
|  | ret = i2c->ops->do_address(i2c, p->addr); | 
|  | if (ret || !p->len) | 
|  | { | 
|  | continue; | 
|  | } | 
|  | if (p->flags & I2C_M_RD) | 
|  | ret = i2c->ops->read(i2c, p->buf, p->len); | 
|  | else | 
|  | ret = i2c->ops->write(i2c, p->buf, p->len); | 
|  | } | 
|  |  | 
|  | i2c->ops->stop(i2c); | 
|  |  | 
|  |  | 
|  | if (p->flags & I2C_M_RD) { | 
|  | AML_I2C_DBG(0, "read "); | 
|  | } | 
|  | else { | 
|  | AML_I2C_DBG(0, "write "); | 
|  | } | 
|  | for (i=0;i<p->len;i++) | 
|  | AML_I2C_DBG(0, "%x-",*(p->buf)++); | 
|  | AML_I2C_DBG(0, "\n"); | 
|  |  | 
|  | /* Return the number of messages processed, or the error code*/ | 
|  | if (ret == 0) | 
|  | return num; | 
|  | else { | 
|  | printf("[aml_i2c_xfer] error ret = %d \t", ret); | 
|  | printf("i2c master %s current slave addr is 0x%x\n", | 
|  | i2c->master_no?"a":"b", i2c->cur_slave_addr); | 
|  | return ret; | 
|  | } | 
|  | } | 
|  | unsigned int i2c_get_bus_num() | 
|  | { | 
|  | return g_i2c_ports[g_cur_bus_num].master_no; | 
|  | } | 
|  | /* | 
|  | * cmd: i2c dev | 
|  | */ | 
|  | int i2c_set_bus_num(unsigned int busnum) | 
|  | { | 
|  | int i = 0; | 
|  | for (;g_i2c_ports[i].master_i2c_speed > 0;i++) { | 
|  | if (g_i2c_ports[i].master_no == busnum) { | 
|  | g_cur_bus_num = i; | 
|  | break; | 
|  | } | 
|  | } | 
|  | if (g_i2c_ports[i].master_i2c_speed == 0 ) { | 
|  | printf("%s no %d busnum enable\n", __func__, busnum); | 
|  | return 0; | 
|  | } | 
|  | printf("%s i2c sel %d bus\n", __func__, busnum); | 
|  | aml_i2c_init_port(&g_i2c_ports[i]); | 
|  | return 0; | 
|  | } | 
|  | void aml_i2c_set_ports(struct aml_i2c_platform *i2c_plat) | 
|  | { | 
|  | g_i2c_ports = i2c_plat; | 
|  | aml_i2c_init(); | 
|  | } |