This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

i2c read and i2c write ploblem for AM335x sitara board which is ruuning on Android 4.2.2(JB)

Hi all,

I'm trying to communicate with a M24256-BW EEPROM via I2C on Android 4.2 platform(kernel version 3.2). Device address is 0x57. Probing the device is successful.  I have build the i2c msgs and generated the i2c transactions using i2c_transfer. I have attached the code and logs with this mail.

The read and write methods are not providing the expected results. Please can anyone help me out on this???

0451.m24256_eeprom_14_6_15.c


/***
  aei_m24256_eeprom.c 

 **/

#include<linux/kernel.h>
#include<linux/init.h>
#include<linux/module.h>
#include<linux/i2c.h>
#include<linux/slab.h>
#include<linux/delay.h>

#include <config/eeprom/aei_m24256_eeprom.h>



/*
 */

struct m24256_eeprom_device {
//	struct m24256_platform_data chip;
	struct mutex lock;
	struct i2c_client *i2c_client;
};

static struct m24256_eeprom_device *m24256_eeprom_priv;




static const struct i2c_device_id m24256_ids[] = {
	{ "m24256-bw", 0 },
	{ /* END OF LIST */ }
};
MODULE_DEVICE_TABLE(i2c, m24256_ids);





/* -----------------------------------------------------------------------------------------------------*/
/* I2c m24256 eeprom read smb*/
#if 0
static u8 m24256_eeprom_read (struct m24256_eeprom_device *m24256_eeprom_priv, int reg)
{
    u16 i2c_ret;

	//mutex_lock();
    i2c_ret = i2c_smbus_read_word_data(m24256_eeprom_priv->client, reg);

    if (i2c_ret < 0) 
	{
                printk(KERN_INFO "%s: m24256 eeprom read reg error : Reg =0x%x error= 0x%x\n", __func__, reg,i2c_ret);
                return -EIO;
    }
    else 
	{
        printk(KERN_INFO "%s: m24256 eeprom read success: Reg 0x%x Value= 0x%x\n", __func__, reg, i2c_ret);
    }
	//mutex_unlock();
        return i2c_ret;
}


/* -----------------------------------------------------------------------------------------------------*/
/* I2C m24256 write i2c smb*/
static unsigned int m24256_eeprom_write(struct m24256_eeprom_device *m24256_eeprom_priv, int reg, u16 value)
{
    int i2c_ret;
   

    i2c_ret = i2c_smbus_write_word_data(m24256_eeprom_priv->client, reg, value);
    if (i2c_ret < 0)
    {
        printk(KERN_INFO "%s: m24256 eeprom write error i2c_ret = %d\n",__func__, i2c_ret );
                                return -EIO;
    }
    else
    {
        printk(KERN_INFO "%s: m24256 eeprom write Success Reg/mem location = 0x%x value=0x%x\n",__func__, reg,value);
    }      
    return 0;
}

#endif 

/* -----------------------------------------------------------------------------------------------------*/
# if 1
/* I2c m24256 eeprom read  using i2c msg*/
static int m24256_eeprom_read (struct m24256_eeprom_device *m24256_eeprom_priv, u8 reg, int bytes, void *dest)
{
    struct i2c_client *i2c = m24256_eeprom_priv->i2c_client;
	struct i2c_msg xfer[2];
	int ret;
	

	/* Write register */
	xfer[0].addr = i2c->addr;
	xfer[0].flags = 0;
	xfer[0].len = 1;
	xfer[0].buf = &reg;

	/* Read data */
	xfer[1].addr = i2c->addr;
	xfer[1].flags = I2C_M_RD;
	xfer[1].len = bytes;
	xfer[1].buf = dest;

	ret = i2c_transfer(i2c->adapter, xfer, 2);

	if (ret == 2)
		ret = 0;
	else if (ret >= 0)
		ret = -EIO;

	return ret;	
}

#define M24256_MAX_MEMORY (64)  //32
/* -----------------------------------------------------------------------------------------------------*/
/* I2C m24256 write i2c msg*/
static int m24256_eeprom_write(struct m24256_eeprom_device *m24256_eeprom_priv, u8 reg, int bytes, void *src)
{
 
    struct i2c_client *i2c = m24256_eeprom_priv->i2c_client;
	/* we add 1 byte for device register */
	u8 msg[M24256_MAX_MEMORY + 1];
	int ret;

	if (bytes > M24256_MAX_MEMORY)
		return -EINVAL;

	msg[0] = reg;
	memcpy(&msg[1], src, bytes);

	ret = i2c_master_send(i2c, msg, bytes + 1);
	if (ret < 0)
		return ret;
	if (ret != bytes + 1)
		return -EIO;
	return 0;
}

#endif 



static int m24256_probe(struct i2c_client *client, const struct i2c_device_id *id)
{
//	struct m24256_platform_data pdata;
	int use_smbus;
	int err=0;
	unsigned char buf;
	u8 writebuf=0xaa;
  
	printk("\n**************************** m24256 probe method*********************%d\n",__LINE__);
#if 0
    if (client->dev.platform_data) {
		pdata = *(struct m24256_platform_data *)client->dev.platform_data;
	}
	else
	{
	  err=-ENODEV;
	  goto err_out;
	}
#endif	


	m24256_eeprom_priv=kzalloc(sizeof(struct m24256_eeprom_device),GFP_KERNEL);

	if(!m24256_eeprom_priv)
	{ 	
	  printk("\n**************************** m24256_eeprom priv failed to allocate*********************%d\n",__LINE__);
	}

	m24256_eeprom_priv->i2c_client=client;



	/* Use I2C operations unless we're stuck with SMBus extensions. */
	if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
	  
	  printk("\n***********i2c fuctionality %d\n",__LINE__);
	  
	/*	if (chip.flags & AT24_FLAG_ADDR16) {
			err = -EPFNOSUPPORT;
			goto err_out;
		}*/
		if (i2c_check_functionality(client->adapter,
				I2C_FUNC_SMBUS_READ_I2C_BLOCK)) {
			use_smbus = I2C_SMBUS_I2C_BLOCK_DATA;
	  	printk("\n***********i2c fuctionality %d: i2c block data use_smbus=%d\n",__LINE__,use_smbus);
		} else if (i2c_check_functionality(client->adapter,
				I2C_FUNC_SMBUS_READ_WORD_DATA)) {
			use_smbus = I2C_SMBUS_WORD_DATA;
	  	printk("\n***********i2c fuctionality %d: i2c block data use_smbus=%d\n",__LINE__,use_smbus);
		} else if (i2c_check_functionality(client->adapter,
				I2C_FUNC_SMBUS_READ_BYTE_DATA)) {
			use_smbus = I2C_SMBUS_BYTE_DATA;
	  	printk("\n***********i2c fuctionality %d: i2c block data use_smbus=%d\n",__LINE__,use_smbus);
		} else {
			err = -EPFNOSUPPORT;
	  	printk("\n***********i2c fuctionality %d: i2c block data use_smbus=%d\n",__LINE__,use_smbus);
			goto err_out;
		}
	}

   
	i2c_set_clientdata(client, m24256_eeprom_priv);
    
	mdelay(40);

	err=m24256_eeprom_read(m24256_eeprom_priv,0x00,1,&buf);
	if(err==0)
	{	  
        printk("\n***************read success******data=%x\n",buf);
	}
	else
	{
        printk("\n***************read fail err=%x\n",err);

	}  

	mdelay(10);
	err=m24256_eeprom_write(m24256_eeprom_priv,0x00,1,&writebuf);
	if(err)
	{	  
        printk("\n***************write failed *****errror=%x\n",err);
	}
	else
	{
        printk("\n***************write success err=%x\n",err);

	}  

	mdelay(10);
	err=m24256_eeprom_read(m24256_eeprom_priv,0x00,1,&buf);
	if(err==0)
	{	  
        printk("\n***************read success***after write****data=%x\n",buf);
	}
	else
	{
        printk("\n:***************read fail after write erro=%x\n",err);
    }


	return 0;
err_out:
	dev_dbg(&client->dev, "probe error %d\n", err);
	return err;
}


static int __devexit m24256_remove(struct i2c_client *client)
{


    i2c_unregister_device(client);

	return 0;
}












/**********************************************************************************/

static struct i2c_driver m24256_driver = {
	.driver = {
		.name = "m24256-bw",
		.owner = THIS_MODULE,
	},
	.probe = m24256_probe,
	.remove = __devexit_p(m24256_remove),
	.id_table = m24256_ids,  //TODO:
};






static int __init m24256_eeprom_init(void)
{
  int ret=0;
  printk("\nask:**************************** eeprom init*********************\n");
  ret=i2c_add_driver(&m24256_driver);
  if(ret!=0)
  {
    printk(KERN_ERR "Failed to register m24256 eeprom device %x\n",ret);
  }
  return ret;  
}

static void __exit m24256_eeprom_exit(void)
{
  printk("\nask: **************************** eeprom exit ************************\n");
  i2c_del_driver(&m24256_driver);
}  


module_init(m24256_eeprom_init);
module_exit(m24256_eeprom_exit);
MODULE_DESCRIPTION("Driver for m24256 I2C EEPROMs ST");
MODULE_AUTHOR("ask:");
MODULE_LICENSE("GPL");

read and write console logs:

*****************************************************************************************************

[    1.811035] loop: module loaded
[    1.814483] i2c-core: driver [tsl2550] using legacy suspend method
[    1.820983] i2c-core: driver [tsl2550] using legacy resume method
[    1.827331] i2c-core: driver [tsl2550] registered
[    1.832305] i2c-core: driver [at24] registered
[    1.836944]
[    1.836944] ask:**************************** eeprom init*********************
[    1.846008] m24256-bw 2-0057: probe
[    1.849670]
[    1.849670] :**************************** m24256 probe method*********************160
[    1.899780] i2c i2c-2: master_xfer[0] W, addr=0x57, len=1
[    1.905426] i2c i2c-2: master_xfer[1] R, addr=0x57, len=1
[    1.911590]
[    1.911590] :***************read success******data=ff
[    1.928833] i2c i2c-2: master_xfer[0] W, addr=0x57, len=2
[    1.934783]
[    1.934783] :***************write success err=0
[    1.951507] i2c i2c-2: master_xfer[0] W, addr=0x57, len=1
[    1.957153] i2c i2c-2: master_xfer[1] R, addr=0x57, len=1
[    1.963195]
[    1.963226] :***************read success***after write****data=ff
[    1.971618] i2c-core: driver [m24256-bw] registered
[    1.976806] (stk) :sysfs entries created
****************************************************************************************************************************

Thanks in advance.

  • Moving this to the Android forum.

  • Hello,

    From your program output, it seems the i2c probe works fine so it should not be a muxing problem.
    You can take a look at i2c-tools[1] to understand how to do reads and writes; we have successfully tested it on the AM335x with few i2c devices.
    You can also compile it for Android and try to communicate with your i2c device.

    [1] www.lm-sensors.org/.../I2CTools

  • Hi,

    Thanks for your reply.

    As part of debugging here is the sub tasks which has been done.

    1. Enabled the i2c core logs in the kernel and verified, nothing was not failed at i2c protocol level.
    2. Cross compiled the i2c tools(i2cdetect,i2cget, i2cset) for an android platform and verified. Probing status noticed in the i2cdetect command output,
    but i2cget and i2cset are not giving the expected behavior.  Using the same tools I could able to set and get the register values of the slave device(example tps6910) which present on the same bus.
    3.  Verified using the i2c sub system present in the U-boot bootloader, and there is no expected behavior.

    The only thing which has been left is debugging at hardware level, I have to probe the i2c sda and scl lines using CRO.

    One thing which I confused and I wanted to ask you w.r.to mux settings.

    Here is the mux settings tried in the code.

    Case1:

    /* I2C1 */
    static struct pinmux_config i2c1_pin_mux[] = {
        {"spi0_d1.i2c1_sda",    OMAP_MUX_MODE2 | AM33XX_SLEWCTRL_SLOW |
                        AM33XX_PULL_UP | AM33XX_INPUT_EN},
        {"spi0_cs0.i2c1_scl",   OMAP_MUX_MODE2 | AM33XX_SLEWCTRL_SLOW |
                        AM33XX_PULL_UP | AM33XX_INPUT_EN},
        {NULL, 0},
    };

    Case2:

    static struct pinmux_config i2c1_pin_mux[] = {
            {"spi0_d1.i2c1_sda",    OMAP_MUX_MODE2 | AM33XX_SLEWCTRL_SLOW |
                                            AM33XX_PULL_ENBL | AM33XX_INPUT_EN},
            {"spi0_cs0.i2c1_scl",   OMAP_MUX_MODE2 | AM33XX_SLEWCTRL_SLOW |
                                            AM33XX_PULL_ENBL | AM33XX_INPUT_EN},
            {NULL, 0},
    };

    The macros present in mux.h file are

    * am33xx specific mux bit defines */
    #define AM33XX_SLEWCTRL_FAST        (0 << 6)
    #define AM33XX_SLEWCTRL_SLOW        (1 << 6)
    #define AM33XX_INPUT_EN            (1 << 5)
    #define AM33XX_PULL_UP            (1 << 4)
    /* bit 3: 0 - enable, 1 - disable for pull enable */
    #define AM33XX_PULL_DISA        (1 << 3)
    #define AM33XX_PULL_ENBL        (0 << 3)

    /* Definition of output pin could have pull disabled, but
     * this has not been done due to two reasons
     * 1. AM33XX_MUX will take care of it
     * 2. If pull was disabled for out macro, combining out & in pull on macros
     *    would disable pull resistor and AM33XX_MUX cannot take care of the
     *    correct pull setting and unintentionally pull would get disabled
     */
    #define    AM33XX_PIN_OUTPUT        (0)
    #define    AM33XX_PIN_OUTPUT_PULLUP    (AM33XX_PULL_UP)
    #define    AM33XX_PIN_INPUT        (AM33XX_INPUT_EN | AM33XX_PULL_DISA)
    #define    AM33XX_PIN_INPUT_PULLUP        (AM33XX_INPUT_EN | AM33XX_PULL_UP)
    #define    AM33XX_PIN_INPUT_PULLDOWN    (AM33XX_INPUT_EN)

    /* Active pin states */
    #define OMAP_PIN_OUTPUT            0
    #define OMAP_PIN_INPUT            OMAP_INPUT_EN
    #define OMAP_PIN_INPUT_PULLUP        (OMAP_PULL_ENA | OMAP_INPUT_EN \
                            | OMAP_PULL_UP)
    #define OMAP_PIN_INPUT_PULLDOWN        (OMAP_PULL_ENA | OMAP_INPUT_EN)

      As per the AM335x TRM  we have to use the case1 as a mux settings.  It is very strange even if I use the case2 settings also it is working fine with other i2c slave devices. Please can you clarify on the same. Thanks in advance.

  • Hello,

    If it works with the tps6910 then you shouldn't have a muxing problem on the OMAP side.
    Using a logic analyzer will greatly help you to debug; you can also check the Vcc level, if your chip hasn't an address conflict with other devices on the same bus and if the EEPROM pins are correctly wired (for example, the Write Control).