Eeprom(at24c04)调试小记

最近花了点时间在android平台调试了一下eeprom,做下记录,供同学们参考。该文基于原生驱动(kernel/msm-3.18/drivers/misc/eeprom/at24.c)做的调试。

内核代码修改:

diff--gita/kernel/msm-3.18/arch/arm/boot/dts/qcom/msm8917-qrd.dtsib/kernel/msm-3.18/arch/arm/boot/dts/qcom/msm8917-qrd.dtsi

old mode 100644

new mode 100755

index 0cad9a8..216345e

---a/kernel/msm-3.18/arch/arm/boot/dts/qcom/msm8917-qrd.dtsi

+++b/kernel/msm-3.18/arch/arm/boot/dts/qcom/msm8917-qrd.dtsi

@@ -256,6 +256,18 @@

       };

       

 };

+

+&i2c_5 {

+

+      at24c04@50 {                

+               compatible ="atmel,24c04";   

+               vdd-supply =<&pm8917_l23>;

+               reg = <0x50>;                

+      };

+      

+};

+

diff --gita/kernel/msm-3.18/drivers/misc/eeprom/at24.cb/kernel/msm-3.18/drivers/misc/eeprom/at24.c

old mode 100644

new mode 100755

index ca5a127..bf58efc

---a/kernel/msm-3.18/drivers/misc/eeprom/at24.c

+++b/kernel/msm-3.18/drivers/misc/eeprom/at24.c

@@ -23,6 +23,10 @@

 #include <linux/of.h>

 #include <linux/i2c.h>

 #include <linux/platform_data/at24.h>

+#include<linux/regulator/consumer.h>

+#include <linux/gpio.h>

+#include <linux/of_gpio.h>

+

 /*

  *I2C EEPROMs from most vendors are inexpensive and mostly interchangeable.

@@ -130,6 +134,82 @@ static const structi2c_device_id at24_ids[] = {

 };

 MODULE_DEVICE_TABLE(i2c, at24_ids);

+

+

+struct sensor_regulator {

+      struct regulator *vreg;

+      const char *name;

+      u32     min_uV;

+       u32    max_uV;

+};

+

+static struct sensor_regulatorat24c04_vreg[] = {

+      {NULL, "vdd", 1800000, 1800000},

+};

+

+

+static int at24c04_config_regulator(structi2c_client *client, bool on)

+{

+      int rc = 0, i;

+      int num_vreg = sizeof(at24c04_vreg)/sizeof(struct sensor_regulator);

+

+      if (on) {

+               for (i = 0; i < num_vreg;i++) {

+                       at24c04_vreg[i].vreg =regulator_get(&client->dev,

+                                      at24c04_vreg[i].name);

+                       if(IS_ERR(at24c04_vreg[i].vreg)) {

+                               rc =PTR_ERR(at24c04_vreg[i].vreg);

+                              dev_err(&client->dev, "%s:regulator get failedrc=%d\n",

+                                              __func__, rc);

+                              at24c04_vreg[i].vreg = NULL;

+                               goto error_vdd;

+                       }

+                       if (regulator_count_voltages(at24c04_vreg[i].vreg)> 0) {

+                               rc =regulator_set_voltage(at24c04_vreg[i].vreg,

+                                      at24c04_vreg[i].min_uV, at24c04_vreg[i].max_uV);

+                               if (rc) {

+                                      dev_err(&client->dev,"%s:set_voltage failed rc=%d\n",

+                                                      __func__, rc);

+                                      regulator_put(at24c04_vreg[i].vreg);

+                                      at24c04_vreg[i].vreg = NULL;

+                                       gotoerror_vdd;

+                               }

+                       }

+                       rc =regulator_enable(at24c04_vreg[i].vreg);

+                       if (rc) {

+                              dev_err(&client->dev, "%s: regulator_enable failed rc=%d\n",

+                                              __func__, rc);

+                               if(regulator_count_voltages(at24c04_vreg[i].vreg)

+                                              > 0) {

+                                      regulator_set_voltage(at24c04_vreg[i].vreg,

+                                                      0, at24c04_vreg[i].max_uV);

+                               }

+                              regulator_put(at24c04_vreg[i].vreg);

+                              at24c04_vreg[i].vreg = NULL;

+                               goto error_vdd;

+                       }

+               }

+               return rc;

+      } else {

+               i = num_vreg;

+      }

+error_vdd:

+      while (--i >= 0) {

+               if(!IS_ERR_OR_NULL(at24c04_vreg[i].vreg)) {

+                       if(regulator_count_voltages(

+                               at24c04_vreg[i].vreg)> 0) {

+                              regulator_set_voltage(at24c04_vreg[i].vreg, 0,

+                                              at24c04_vreg[i].max_uV);

+                       }

+                      regulator_disable(at24c04_vreg[i].vreg);

+                      regulator_put(at24c04_vreg[i].vreg);

+                       at24c04_vreg[i].vreg =NULL;

+               }

+      }

+      return rc;

+}

+

 /*-------------------------------------------------------------------------*/

 /*

@@ -142,6 +222,8 @@ static structi2c_client *at24_translate_offset(struct at24_data *at24,

 {

       unsigned i;


       if (at24->chip.flags & AT24_FLAG_ADDR16) {

                i = *offset >> 16;

                *offset &= 0xffff;

@@ -162,6 +244,8 @@ static ssize_tat24_eeprom_read(struct at24_data *at24, char *buf,

       unsigned long timeout, read_time;

       int status, i;


       memset(msg, 0, sizeof(msg));

       /*

@@ -253,7 +337,7 @@ static ssize_tat24_eeprom_read(struct at24_data *at24, char *buf,

                        if (status == 2)

                                status = count;

                }

-               dev_dbg(&client->dev,"read %zu@%d --> %d (%ld)\n",

+               pr_err("read%zu@%d --> %d (%ld)\n",

                                count, offset,status, jiffies);

                if (status == count)

@@ -271,6 +355,8 @@ static ssize_tat24_read(struct at24_data *at24,

 {

       ssize_t retval = 0;


       if (unlikely(!count))

                return count;

@@ -305,6 +391,7 @@ static ssize_tat24_bin_read(struct file *filp, struct kobject *kobj,

                char *buf, loff_t off, size_tcount)

 {

       struct at24_data *at24;


       at24 = dev_get_drvdata(container_of(kobj, struct device, kobj));

       return at24_read(at24, buf, off, count);

@@ -328,6 +415,8 @@ static ssize_tat24_eeprom_write(struct at24_data *at24, const char *buf,

       unsigned long timeout, write_time;

       unsigned next_page;


       /* Get corresponding I2C address and adjust offset */

       client = at24_translate_offset(at24, &offset);

@@ -375,7 +464,8 @@ static ssize_tat24_eeprom_write(struct at24_data *at24, const char *buf,

                        if (status == 1)

                                status = count;

                }

-               dev_dbg(&client->dev,"write %zu@%d --> %zd (%ld)\n",

+               mdelay(10);


                if (status == count)

@@ -392,6 +482,7 @@ static ssize_tat24_write(struct at24_data *at24, const char *buf, loff_t off,

                          size_t count)

 {

       ssize_t retval = 0;


       if (unlikely(!count))

                return count;

@@ -427,6 +518,7 @@ static ssize_tat24_bin_write(struct file *filp, struct kobject *kobj,

                char *buf, loff_t off, size_tcount)

 {

       struct at24_data *at24;


       if (unlikely(off >= attr->size))

                return -EFBIG;

@@ -447,6 +539,7 @@ static ssize_tat24_macc_read(struct memory_accessor *macc, char *buf,

                         off_t offset, size_tcount)

 {

       struct at24_data *at24 = container_of(macc, struct at24_data, macc);


       return at24_read(at24, buf, offset, count);

 }

@@ -455,6 +548,7 @@ static ssize_tat24_macc_write(struct memory_accessor *macc, const char *buf,

                          off_t offset, size_tcount)

 {

       struct at24_data *at24 = container_of(macc, struct at24_data, macc);


        return at24_write(at24, buf, offset,count);

 }

@@ -491,6 +585,17 @@ static intat24_probe(struct i2c_client *client, const struct i2c_device_id *id)

       int err;

       unsigned i, num_addresses;

       kernel_ulong_t magic;


+

+      if (gpio_is_valid(50)) { 

+               err = gpio_request(50,"at24c04_wp"); 

+               if (err) { 

+                       printk("Unable torequest at24c04_wp gpio\n"); 

+                       } 

+               err =gpio_direction_output(50,0); 

+               }

       if (client->dev.platform_data) {

                chip = *(structat24_platform_data *)client->dev.platform_data;

@@ -571,6 +676,9 @@ static int at24_probe(structi2c_client *client, const struct i2c_device_id *id)

       at24->bin.attr.mode = chip.flags & AT24_FLAG_IRUGO ? S_IRUGO :S_IRUSR;

       at24->bin.read = at24_bin_read;

       at24->bin.size = chip.byte_len;

+      

+      

+      at24c04_config_regulator(client, 1);

       at24->macc.read = at24_macc_read;

@@ -623,7 +731,7 @@ static intat24_probe(struct i2c_client *client, const struct i2c_device_id *id)

       i2c_set_clientdata(client, at24);

-      dev_info(&client->dev, "%zu byte %s EEPROM, %s, %ubytes/write\n",

+      dev_info(&client->dev, " %zu byte %s EEPROM, %s, %ubytes/write\n",

                at24->bin.size,client->name,

                writable ? "writable": "read-only", at24->write_max);

       if (use_smbus == I2C_SMBUS_WORD_DATA ||

@@ -663,7 +771,7 @@ static intat24_remove(struct i2c_client *client)

 /*-------------------------------------------------------------------------*/

 static const struct of_device_idat24_of_match[] = {

-      { .compatible = "atmel,24c32", },

+      { .compatible = "atmel,24c04", },

       { }

 };

 MODULE_DEVICE_TABLE(of, at24_of_match);

(END)

以上有三点要做特别说明:

1、  原来的compatible是24c32,这里不要偷懒,一定要改成24c04,dtsi里也要设成24c04。

static const struct of_device_idat24_of_match[] = {

-      { .compatible = "atmel,24c32", },

+      { .compatible = "atmel,24c04", },

       { }

2、  WP管脚要设成低电平才能写:

+      if (gpio_is_valid(50)) { 

+               err = gpio_request(50,"at24c04_wp"); 

+               if (err) { 

+                       printk("Unable torequest at24c04_wp gpio\n"); 

+                       } 

+               err =gpio_direction_output(50,0); 

+               }

3、  在写函数里要加延时,不然会报I2C无ACK,(秉着一种严谨的态度,不给任何挑剔的机会):

-               dev_dbg(&client->dev,"write %zu@%d --> %zd (%ld)\n",

+               mdelay(10);

+               pr_err("write%zu@%d --> %zd (%ld)\n",

                                count, offset, status, jiffies);

最后上测试代码:

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

* 档名:at24c04-test.c

* 作者:[email protected]

* 日期:2018/07/11

* 描述:使用android内核提供的at24.c驱动读写板载AT24C04

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

#include <stdio.h>

#include <fcntl.h>

#include <sys/ioctl.h>

#include <linux/types.h>

#include <unistd.h>

#include <time.h>

int main()

{

         intfd;

         inti;

         charwrite_data[8] = {

                   'A',0x3A,0x3B,0x3C,0x3D,0x3E,0x3F,0x40

         };

         charread_data[256] = {0};

         fd= open("/sys/bus/i2c/devices/5-0050/eeprom",O_RDWR);//这里需要改成你平台的路径

         lseek(fd,0,SEEK_SET);

         write(fd,write_data,8);

         usleep(20000);

         lseek(fd,0,SEEK_SET);

         read(fd,read_data,8);

        

         usleep(20000);

         for(i=0;i<8;i++)

         {

                   if(i%16== 0)

                            printf("\n");

                   printf("%02x",read_data[i]);

         }

         printf("\n");

}

效果展示:


猜你喜欢

转载自blog.csdn.net/dncser/article/details/80937394