最近花了点时间在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
#include
#include
+#include
+#include
+#include
+
/*
*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
#include
#include
#include
#include
#include
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");
}
效果展示: