Linux驱动之eeprom,I2C,SPI

来源:互联网 发布:excel删除重复数据的行 编辑:程序博客网 时间:2024/06/01 12:35

好久没有写过博客了,今天先补一篇吧,之前在做项目的时候,用模拟SPI驱动一个模块,结果没成功,因为项目时间紧,所以,就搞别的了,然而它一直是一道坎儿,不看憋得慌,

昨天看周立功的嵌入式Linux开发教程(下册),里面有提到SPI的驱动模板,于是看了一下,还真是有,非常高兴,因为我很早之前找了一个2000多行的模板,不太清晰,

这个才短短的400多行,所以,感觉这个挺好的,现在分享给大家,当然大家也可以去drivers目录下自己找需要的驱动模板,我这里是找的EEPROM的,它在drivers/misc目录下,

废话不多说,下面,介绍两种关于EEPROM的驱动方式,一种是I2C的,一种是SPI的.


I2C------eeprom驱动:

/* * at24.c - handle most I2C EEPROMs * * Copyright (C) 2005-2007 David Brownell * Copyright (C) 2008 Wolfram Sang, Pengutronix * * 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. */#include <linux/kernel.h>#include <linux/init.h>#include <linux/module.h>#include <linux/slab.h>#include <linux/delay.h>#include <linux/mutex.h>#include <linux/sysfs.h>#include <linux/mod_devicetable.h>#include <linux/log2.h>#include <linux/bitops.h>#include <linux/jiffies.h>#include <linux/of.h>#include <linux/i2c.h>#include <linux/i2c/at24.h>/* * I2C EEPROMs from most vendors are inexpensive and mostly interchangeable. * Differences between different vendor product lines (like Atmel AT24C or * MicroChip 24LC, etc) won't much matter for typical read/write access. * There are also I2C RAM chips, likewise interchangeable. One example * would be the PCF8570, which acts like a 24c02 EEPROM (256 bytes). * * However, misconfiguration can lose data. "Set 16-bit memory address" * to a part with 8-bit addressing will overwrite data. Writing with too * big a page size also loses data. And it's not safe to assume that the * conventional addresses 0x50..0x57 only hold eeproms; a PCF8563 RTC * uses 0x51, for just one example. * * Accordingly, explicit board-specific configuration data should be used * in almost all cases. (One partial exception is an SMBus used to access * "SPD" data for DRAM sticks. Those only use 24c02 EEPROMs.) * * So this driver uses "new style" I2C driver binding, expecting to be * told what devices exist. That may be in arch/X/mach-Y/board-Z.c or * similar kernel-resident tables; or, configuration data coming from * a bootloader. * * Other than binding model, current differences from "eeprom" driver are * that this one handles write access and isn't restricted to 24c02 devices. * It also handles larger devices (32 kbit and up) with two-byte addresses, * which won't work on pure SMBus systems. */struct at24_data {struct at24_platform_data chip;struct memory_accessor macc;int use_smbus;/* * Lock protects against activities from other Linux tasks, * but not from changes by other I2C masters. */struct mutex lock;struct bin_attribute bin;u8 *writebuf;unsigned write_max;unsigned num_addresses;/* * Some chips tie up multiple I2C addresses; dummy devices reserve * them for us, and we'll use them with SMBus calls. */struct i2c_client *client[];};/* * This parameter is to help this driver avoid blocking other drivers out * of I2C for potentially troublesome amounts of time. With a 100 kHz I2C * clock, one 256 byte read takes about 1/43 second which is excessive; * but the 1/170 second it takes at 400 kHz may be quite reasonable; and * at 1 MHz (Fm+) a 1/430 second delay could easily be invisible. * * This value is forced to be a power of two so that writes align on pages. */static unsigned io_limit = 128;module_param(io_limit, uint, 0);MODULE_PARM_DESC(io_limit, "Maximum bytes per I/O (default 128)");/* * Specs often allow 5 msec for a page write, sometimes 20 msec; * it's important to recover from write timeouts. */static unsigned write_timeout = 25;module_param(write_timeout, uint, 0);MODULE_PARM_DESC(write_timeout, "Time (in ms) to try writes (default 25)");#define AT24_SIZE_BYTELEN 5#define AT24_SIZE_FLAGS 8#define AT24_BITMASK(x) (BIT(x) - 1)/* create non-zero magic value for given eeprom parameters */#define AT24_DEVICE_MAGIC(_len, _flags) \((1 << AT24_SIZE_FLAGS | (_flags)) \    << AT24_SIZE_BYTELEN | ilog2(_len))static const struct i2c_device_id at24_ids[] = {/* needs 8 addresses as A0-A2 are ignored */{ "24c00", AT24_DEVICE_MAGIC(128 / 8, AT24_FLAG_TAKE8ADDR) },/* old variants can't be handled with this generic entry! */{ "24c01", AT24_DEVICE_MAGIC(1024 / 8, 0) },{ "24c02", AT24_DEVICE_MAGIC(2048 / 8, 0) },/* spd is a 24c02 in memory DIMMs */{ "spd", AT24_DEVICE_MAGIC(2048 / 8,AT24_FLAG_READONLY | AT24_FLAG_IRUGO) },{ "24c04", AT24_DEVICE_MAGIC(4096 / 8, 0) },/* 24rf08 quirk is handled at i2c-core */{ "24c08", AT24_DEVICE_MAGIC(8192 / 8, 0) },{ "24c16", AT24_DEVICE_MAGIC(16384 / 8, 0) },{ "24c32", AT24_DEVICE_MAGIC(32768 / 8, AT24_FLAG_ADDR16) },{ "24c64", AT24_DEVICE_MAGIC(65536 / 8, AT24_FLAG_ADDR16) },{ "24c128", AT24_DEVICE_MAGIC(131072 / 8, AT24_FLAG_ADDR16) },{ "24c256", AT24_DEVICE_MAGIC(262144 / 8, AT24_FLAG_ADDR16) },{ "24c512", AT24_DEVICE_MAGIC(524288 / 8, AT24_FLAG_ADDR16) },{ "24c1024", AT24_DEVICE_MAGIC(1048576 / 8, AT24_FLAG_ADDR16) },{ "at24", 0 },{ /* END OF LIST */ }};MODULE_DEVICE_TABLE(i2c, at24_ids);/*-------------------------------------------------------------------------*//* * This routine supports chips which consume multiple I2C addresses. It * computes the addressing information to be used for a given r/w request. * Assumes that sanity checks for offset happened at sysfs-layer. */static struct i2c_client *at24_translate_offset(struct at24_data *at24,unsigned *offset){unsigned i;if (at24->chip.flags & AT24_FLAG_ADDR16) {i = *offset >> 16;*offset &= 0xffff;} else {i = *offset >> 8;*offset &= 0xff;}return at24->client[i];}static ssize_t at24_eeprom_read(struct at24_data *at24, char *buf,unsigned offset, size_t count){struct i2c_msg msg[2];u8 msgbuf[2];struct i2c_client *client;unsigned long timeout, read_time;int status, i;memset(msg, 0, sizeof(msg));/* * REVISIT some multi-address chips don't rollover page reads to * the next slave address, so we may need to truncate the count. * Those chips might need another quirk flag. * * If the real hardware used four adjacent 24c02 chips and that * were misconfigured as one 24c08, that would be a similar effect: * one "eeprom" file not four, but larger reads would fail when * they crossed certain pages. *//* * Slave address and byte offset derive from the offset. Always * set the byte address; on a multi-master board, another master * may have changed the chip's "current" address pointer. */client = at24_translate_offset(at24, &offset);if (count > io_limit)count = io_limit;switch (at24->use_smbus) {case I2C_SMBUS_I2C_BLOCK_DATA:/* Smaller eeproms can work given some SMBus extension calls */if (count > I2C_SMBUS_BLOCK_MAX)count = I2C_SMBUS_BLOCK_MAX;break;case I2C_SMBUS_WORD_DATA:count = 2;break;case I2C_SMBUS_BYTE_DATA:count = 1;break;default:/* * When we have a better choice than SMBus calls, use a * combined I2C message. Write address; then read up to * io_limit data bytes. Note that read page rollover helps us * here (unlike writes). msgbuf is u8 and will cast to our * needs. */i = 0;if (at24->chip.flags & AT24_FLAG_ADDR16)msgbuf[i++] = offset >> 8;msgbuf[i++] = offset;msg[0].addr = client->addr;msg[0].buf = msgbuf;msg[0].len = i;msg[1].addr = client->addr;msg[1].flags = I2C_M_RD;msg[1].buf = buf;msg[1].len = count;}/* * Reads fail if the previous write didn't complete yet. We may * loop a few times until this one succeeds, waiting at least * long enough for one entire page write to work. */timeout = jiffies + msecs_to_jiffies(write_timeout);do {read_time = jiffies;switch (at24->use_smbus) {case I2C_SMBUS_I2C_BLOCK_DATA:status = i2c_smbus_read_i2c_block_data(client, offset,count, buf);break;case I2C_SMBUS_WORD_DATA:status = i2c_smbus_read_word_data(client, offset);if (status >= 0) {buf[0] = status & 0xff;buf[1] = status >> 8;status = count;}break;case I2C_SMBUS_BYTE_DATA:status = i2c_smbus_read_byte_data(client, offset);if (status >= 0) {buf[0] = status;status = count;}break;default:status = i2c_transfer(client->adapter, msg, 2);if (status == 2)status = count;}dev_dbg(&client->dev, "read %zu@%d --> %d (%ld)\n",count, offset, status, jiffies);if (status == count)return count;/* REVISIT: at HZ=100, this is sloooow */msleep(1);} while (time_before(read_time, timeout));return -ETIMEDOUT;}static ssize_t at24_read(struct at24_data *at24,char *buf, loff_t off, size_t count){ssize_t retval = 0;if (unlikely(!count))return count;/* * Read data from chip, protecting against concurrent updates * from this host, but not from other I2C masters. */mutex_lock(&at24->lock);while (count) {ssize_tstatus;status = at24_eeprom_read(at24, buf, off, count);if (status <= 0) {if (retval == 0)retval = status;break;}buf += status;off += status;count -= status;retval += status;}mutex_unlock(&at24->lock);return retval;}static ssize_t at24_bin_read(struct file *filp, struct kobject *kobj,struct bin_attribute *attr,char *buf, loff_t off, size_t count){struct at24_data *at24;at24 = dev_get_drvdata(container_of(kobj, struct device, kobj));return at24_read(at24, buf, off, count);}/* * Note that if the hardware write-protect pin is pulled high, the whole * chip is normally write protected. But there are plenty of product * variants here, including OTP fuses and partial chip protect. * * We only use page mode writes; the alternative is sloooow. This routine * writes at most one page. */static ssize_t at24_eeprom_write(struct at24_data *at24, const char *buf,unsigned offset, size_t count){struct i2c_client *client;struct i2c_msg msg;ssize_t status;unsigned long timeout, write_time;unsigned next_page;/* Get corresponding I2C address and adjust offset */client = at24_translate_offset(at24, &offset);/* write_max is at most a page */if (count > at24->write_max)count = at24->write_max;/* Never roll over backwards, to the start of this page */next_page = roundup(offset + 1, at24->chip.page_size);if (offset + count > next_page)count = next_page - offset;/* If we'll use I2C calls for I/O, set up the message */if (!at24->use_smbus) {int i = 0;msg.addr = client->addr;msg.flags = 0;/* msg.buf is u8 and casts will mask the values */msg.buf = at24->writebuf;if (at24->chip.flags & AT24_FLAG_ADDR16)msg.buf[i++] = offset >> 8;msg.buf[i++] = offset;memcpy(&msg.buf[i], buf, count);msg.len = i + count;}/* * Writes fail if the previous one didn't complete yet. We may * loop a few times until this one succeeds, waiting at least * long enough for one entire page write to work. */timeout = jiffies + msecs_to_jiffies(write_timeout);do {write_time = jiffies;if (at24->use_smbus) {status = i2c_smbus_write_i2c_block_data(client,offset, count, buf);if (status == 0)status = count;} else {status = i2c_transfer(client->adapter, &msg, 1);if (status == 1)status = count;}dev_dbg(&client->dev, "write %zu@%d --> %zd (%ld)\n",count, offset, status, jiffies);if (status == count)return count;/* REVISIT: at HZ=100, this is sloooow */msleep(1);} while (time_before(write_time, timeout));return -ETIMEDOUT;}static ssize_t at24_write(struct at24_data *at24, const char *buf, loff_t off,  size_t count){ssize_t retval = 0;if (unlikely(!count))return count;/* * Write data to chip, protecting against concurrent updates * from this host, but not from other I2C masters. */mutex_lock(&at24->lock);while (count) {ssize_tstatus;status = at24_eeprom_write(at24, buf, off, count);if (status <= 0) {if (retval == 0)retval = status;break;}buf += status;off += status;count -= status;retval += status;}mutex_unlock(&at24->lock);return retval;}static ssize_t at24_bin_write(struct file *filp, struct kobject *kobj,struct bin_attribute *attr,char *buf, loff_t off, size_t count){struct at24_data *at24;at24 = dev_get_drvdata(container_of(kobj, struct device, kobj));return at24_write(at24, buf, off, count);}/*-------------------------------------------------------------------------*//* * This lets other kernel code access the eeprom data. For example, it * might hold a board's Ethernet address, or board-specific calibration * data generated on the manufacturing floor. */static ssize_t at24_macc_read(struct memory_accessor *macc, char *buf, off_t offset, size_t count){struct at24_data *at24 = container_of(macc, struct at24_data, macc);return at24_read(at24, buf, offset, count);}static ssize_t at24_macc_write(struct memory_accessor *macc, const char *buf,  off_t offset, size_t count){struct at24_data *at24 = container_of(macc, struct at24_data, macc);return at24_write(at24, buf, offset, count);}/*-------------------------------------------------------------------------*/#ifdef CONFIG_OFstatic void at24_get_ofdata(struct i2c_client *client,struct at24_platform_data *chip){const __be32 *val;struct device_node *node = client->dev.of_node;if (node) {if (of_get_property(node, "read-only", NULL))chip->flags |= AT24_FLAG_READONLY;val = of_get_property(node, "pagesize", NULL);if (val)chip->page_size = be32_to_cpup(val);}}#elsestatic void at24_get_ofdata(struct i2c_client *client,struct at24_platform_data *chip){ }#endif /* CONFIG_OF */static int at24_probe(struct i2c_client *client, const struct i2c_device_id *id){struct at24_platform_data chip;bool writable;int use_smbus = 0;struct at24_data *at24;int err;unsigned i, num_addresses;kernel_ulong_t magic;if (client->dev.platform_data) {chip = *(struct at24_platform_data *)client->dev.platform_data;} else {if (!id->driver_data) {err = -ENODEV;goto err_out;}magic = id->driver_data;chip.byte_len = BIT(magic & AT24_BITMASK(AT24_SIZE_BYTELEN));magic >>= AT24_SIZE_BYTELEN;chip.flags = magic & AT24_BITMASK(AT24_SIZE_FLAGS);/* * This is slow, but we can't know all eeproms, so we better * play safe. Specifying custom eeprom-types via platform_data * is recommended anyhow. */chip.page_size = 1;/* update chipdata if OF is present */at24_get_ofdata(client, &chip);chip.setup = NULL;chip.context = NULL;}if (!is_power_of_2(chip.byte_len))dev_warn(&client->dev,"byte_len looks suspicious (no power of 2)!\n");if (!chip.page_size) {dev_err(&client->dev, "page_size must not be 0!\n");err = -EINVAL;goto err_out;}if (!is_power_of_2(chip.page_size))dev_warn(&client->dev,"page_size looks suspicious (no power of 2)!\n");/* Use I2C operations unless we're stuck with SMBus extensions. */if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {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;} else if (i2c_check_functionality(client->adapter,I2C_FUNC_SMBUS_READ_WORD_DATA)) {use_smbus = I2C_SMBUS_WORD_DATA;} else if (i2c_check_functionality(client->adapter,I2C_FUNC_SMBUS_READ_BYTE_DATA)) {use_smbus = I2C_SMBUS_BYTE_DATA;} else {err = -EPFNOSUPPORT;goto err_out;}}if (chip.flags & AT24_FLAG_TAKE8ADDR)num_addresses = 8;elsenum_addresses =DIV_ROUND_UP(chip.byte_len,(chip.flags & AT24_FLAG_ADDR16) ? 65536 : 256);at24 = kzalloc(sizeof(struct at24_data) +num_addresses * sizeof(struct i2c_client *), GFP_KERNEL);if (!at24) {err = -ENOMEM;goto err_out;}mutex_init(&at24->lock);at24->use_smbus = use_smbus;at24->chip = chip;at24->num_addresses = num_addresses;/* * Export the EEPROM bytes through sysfs, since that's convenient. * By default, only root should see the data (maybe passwords etc) */sysfs_bin_attr_init(&at24->bin);at24->bin.attr.name = "eeprom";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;at24->macc.read = at24_macc_read;writable = !(chip.flags & AT24_FLAG_READONLY);if (writable) {if (!use_smbus || i2c_check_functionality(client->adapter,I2C_FUNC_SMBUS_WRITE_I2C_BLOCK)) {unsigned write_max = chip.page_size;at24->macc.write = at24_macc_write;at24->bin.write = at24_bin_write;at24->bin.attr.mode |= S_IWUSR;if (write_max > io_limit)write_max = io_limit;if (use_smbus && write_max > I2C_SMBUS_BLOCK_MAX)write_max = I2C_SMBUS_BLOCK_MAX;at24->write_max = write_max;/* buffer (data + address at the beginning) */at24->writebuf = kmalloc(write_max + 2, GFP_KERNEL);if (!at24->writebuf) {err = -ENOMEM;goto err_struct;}} else {dev_warn(&client->dev,"cannot write due to controller restrictions.");}}at24->client[0] = client;/* use dummy devices for multiple-address chips */for (i = 1; i < num_addresses; i++) {at24->client[i] = i2c_new_dummy(client->adapter,client->addr + i);if (!at24->client[i]) {dev_err(&client->dev, "address 0x%02x unavailable\n",client->addr + i);err = -EADDRINUSE;goto err_clients;}}err = sysfs_create_bin_file(&client->dev.kobj, &at24->bin);if (err)goto err_clients;i2c_set_clientdata(client, at24);dev_info(&client->dev, "%zu byte %s EEPROM, %s, %u bytes/write\n",at24->bin.size, client->name,writable ? "writable" : "read-only", at24->write_max);if (use_smbus == I2C_SMBUS_WORD_DATA ||    use_smbus == I2C_SMBUS_BYTE_DATA) {dev_notice(&client->dev, "Falling back to %s reads, "   "performance will suffer\n", use_smbus ==   I2C_SMBUS_WORD_DATA ? "word" : "byte");}/* export data to kernel code */if (chip.setup)chip.setup(&at24->macc, chip.context);return 0;err_clients:for (i = 1; i < num_addresses; i++)if (at24->client[i])i2c_unregister_device(at24->client[i]);kfree(at24->writebuf);err_struct:kfree(at24);err_out:dev_dbg(&client->dev, "probe error %d\n", err);return err;}static int __devexit at24_remove(struct i2c_client *client){struct at24_data *at24;int i;at24 = i2c_get_clientdata(client);sysfs_remove_bin_file(&client->dev.kobj, &at24->bin);for (i = 1; i < at24->num_addresses; i++)i2c_unregister_device(at24->client[i]);kfree(at24->writebuf);kfree(at24);return 0;}/*-------------------------------------------------------------------------*/static struct i2c_driver at24_driver = {.driver = {.name = "at24",.owner = THIS_MODULE,},.probe = at24_probe,.remove = __devexit_p(at24_remove),.id_table = at24_ids,};static int __init at24_init(void){if (!io_limit) {pr_err("at24: io_limit must not be 0!\n");return -EINVAL;}io_limit = rounddown_pow_of_two(io_limit);return i2c_add_driver(&at24_driver);}module_init(at24_init);static void __exit at24_exit(void){i2c_del_driver(&at24_driver);}module_exit(at24_exit);MODULE_DESCRIPTION("Driver for most I2C EEPROMs");MODULE_AUTHOR("David Brownell and Wolfram Sang");MODULE_LICENSE("GPL");

以上是一个完整的I2C驱动,下面的是SPI版的,SPI版和I2C版的不同在于型号,I2C的是at24,SPI的则是at25:

/* * at25.c -- support most SPI EEPROMs, such as Atmel AT25 models * * Copyright (C) 2006 David Brownell * * 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. */#include <linux/kernel.h>#include <linux/init.h>#include <linux/module.h>#include <linux/slab.h>#include <linux/delay.h>#include <linux/device.h>#include <linux/sched.h>#include <linux/spi/spi.h>#include <linux/spi/eeprom.h>/* * NOTE: this is an *EEPROM* driver.  The vagaries of product naming * mean that some AT25 products are EEPROMs, and others are FLASH. * Handle FLASH chips with the drivers/mtd/devices/m25p80.c driver, * not this one! */struct at25_data {struct spi_device*spi;struct memory_accessormem;struct mutexlock;struct spi_eepromchip;struct bin_attributebin;unsignedaddrlen;};#defineAT25_WREN0x06/* latch the write enable */#defineAT25_WRDI0x04/* reset the write enable */#defineAT25_RDSR0x05/* read status register */#defineAT25_WRSR0x01/* write status register */#defineAT25_READ0x03/* read byte(s) */#defineAT25_WRITE0x02/* write byte(s)/sector */#defineAT25_SR_nRDY0x01/* nRDY = write-in-progress */#defineAT25_SR_WEN0x02/* write enable (latched) */#defineAT25_SR_BP00x04/* BP for software writeprotect */#defineAT25_SR_BP10x08#defineAT25_SR_WPEN0x80/* writeprotect enable */#define EE_MAXADDRLEN3/* 24 bit addresses, up to 2 MBytes *//* Specs often allow 5 msec for a page write, sometimes 20 msec; * it's important to recover from write timeouts. */#defineEE_TIMEOUT25/*-------------------------------------------------------------------------*/#defineio_limitPAGE_SIZE/* bytes */static ssize_tat25_ee_read(struct at25_data*at25,char*buf,unsignedoffset,size_tcount){u8command[EE_MAXADDRLEN + 1];u8*cp;ssize_tstatus;struct spi_transfert[2];struct spi_messagem;if (unlikely(offset >= at25->bin.size))return 0;if ((offset + count) > at25->bin.size)count = at25->bin.size - offset;if (unlikely(!count))return count;cp = command;*cp++ = AT25_READ;/* 8/16/24-bit address is written MSB first */switch (at25->addrlen) {default:/* case 3 */*cp++ = offset >> 16;case 2:*cp++ = offset >> 8;case 1:case 0:/* can't happen: for better codegen */*cp++ = offset >> 0;}spi_message_init(&m);memset(t, 0, sizeof t);t[0].tx_buf = command;t[0].len = at25->addrlen + 1;spi_message_add_tail(&t[0], &m);t[1].rx_buf = buf;t[1].len = count;spi_message_add_tail(&t[1], &m);mutex_lock(&at25->lock);/* Read it all at once. * * REVISIT that's potentially a problem with large chips, if * other devices on the bus need to be accessed regularly or * this chip is clocked very slowly */status = spi_sync(at25->spi, &m);dev_dbg(&at25->spi->dev,"read %Zd bytes at %d --> %d\n",count, offset, (int) status);mutex_unlock(&at25->lock);return status ? status : count;}static ssize_tat25_bin_read(struct file *filp, struct kobject *kobj,      struct bin_attribute *bin_attr,      char *buf, loff_t off, size_t count){struct device*dev;struct at25_data*at25;dev = container_of(kobj, struct device, kobj);at25 = dev_get_drvdata(dev);return at25_ee_read(at25, buf, off, count);}static ssize_tat25_ee_write(struct at25_data *at25, const char *buf, loff_t off,      size_t count){ssize_tstatus = 0;unsignedwritten = 0;unsignedbuf_size;u8*bounce;if (unlikely(off >= at25->bin.size))return -EFBIG;if ((off + count) > at25->bin.size)count = at25->bin.size - off;if (unlikely(!count))return count;/* Temp buffer starts with command and address */buf_size = at25->chip.page_size;if (buf_size > io_limit)buf_size = io_limit;bounce = kmalloc(buf_size + at25->addrlen + 1, GFP_KERNEL);if (!bounce)return -ENOMEM;/* For write, rollover is within the page ... so we write at * most one page, then manually roll over to the next page. */bounce[0] = AT25_WRITE;mutex_lock(&at25->lock);do {unsigned longtimeout, retries;unsignedsegment;unsignedoffset = (unsigned) off;u8*cp = bounce + 1;intsr;*cp = AT25_WREN;status = spi_write(at25->spi, cp, 1);if (status < 0) {dev_dbg(&at25->spi->dev, "WREN --> %d\n",(int) status);break;}/* 8/16/24-bit address is written MSB first */switch (at25->addrlen) {default:/* case 3 */*cp++ = offset >> 16;case 2:*cp++ = offset >> 8;case 1:case 0:/* can't happen: for better codegen */*cp++ = offset >> 0;}/* Write as much of a page as we can */segment = buf_size - (offset % buf_size);if (segment > count)segment = count;memcpy(cp, buf, segment);status = spi_write(at25->spi, bounce,segment + at25->addrlen + 1);dev_dbg(&at25->spi->dev,"write %u bytes at %u --> %d\n",segment, offset, (int) status);if (status < 0)break;/* REVISIT this should detect (or prevent) failed writes * to readonly sections of the EEPROM... *//* Wait for non-busy status */timeout = jiffies + msecs_to_jiffies(EE_TIMEOUT);retries = 0;do {sr = spi_w8r8(at25->spi, AT25_RDSR);if (sr < 0 || (sr & AT25_SR_nRDY)) {dev_dbg(&at25->spi->dev,"rdsr --> %d (%02x)\n", sr, sr);/* at HZ=100, this is sloooow */msleep(1);continue;}if (!(sr & AT25_SR_nRDY))break;} while (retries++ < 3 || time_before_eq(jiffies, timeout));if ((sr < 0) || (sr & AT25_SR_nRDY)) {dev_err(&at25->spi->dev,"write %d bytes offset %d, ""timeout after %u msecs\n",segment, offset,jiffies_to_msecs(jiffies -(timeout - EE_TIMEOUT)));status = -ETIMEDOUT;break;}off += segment;buf += segment;count -= segment;written += segment;} while (count > 0);mutex_unlock(&at25->lock);kfree(bounce);return written ? written : status;}static ssize_tat25_bin_write(struct file *filp, struct kobject *kobj,       struct bin_attribute *bin_attr,       char *buf, loff_t off, size_t count){struct device*dev;struct at25_data*at25;dev = container_of(kobj, struct device, kobj);at25 = dev_get_drvdata(dev);return at25_ee_write(at25, buf, off, count);}/*-------------------------------------------------------------------------*//* Let in-kernel code access the eeprom data. */static ssize_t at25_mem_read(struct memory_accessor *mem, char *buf, off_t offset, size_t count){struct at25_data *at25 = container_of(mem, struct at25_data, mem);return at25_ee_read(at25, buf, offset, count);}static ssize_t at25_mem_write(struct memory_accessor *mem, const char *buf,  off_t offset, size_t count){struct at25_data *at25 = container_of(mem, struct at25_data, mem);return at25_ee_write(at25, buf, offset, count);}/*-------------------------------------------------------------------------*/static int at25_probe(struct spi_device *spi){struct at25_data*at25 = NULL;const struct spi_eeprom *chip;interr;intsr;intaddrlen;/* Chip description */chip = spi->dev.platform_data;if (!chip) {dev_dbg(&spi->dev, "no chip description\n");err = -ENODEV;goto fail;}/* For now we only support 8/16/24 bit addressing */if (chip->flags & EE_ADDR1)addrlen = 1;else if (chip->flags & EE_ADDR2)addrlen = 2;else if (chip->flags & EE_ADDR3)addrlen = 3;else {dev_dbg(&spi->dev, "unsupported address type\n");err = -EINVAL;goto fail;}/* Ping the chip ... the status register is pretty portable, * unlike probing manufacturer IDs.  We do expect that system * firmware didn't write it in the past few milliseconds! */sr = spi_w8r8(spi, AT25_RDSR);if (sr < 0 || sr & AT25_SR_nRDY) {dev_dbg(&spi->dev, "rdsr --> %d (%02x)\n", sr, sr);err = -ENXIO;goto fail;}if (!(at25 = kzalloc(sizeof *at25, GFP_KERNEL))) {err = -ENOMEM;goto fail;}mutex_init(&at25->lock);at25->chip = *chip;at25->spi = spi_dev_get(spi);dev_set_drvdata(&spi->dev, at25);at25->addrlen = addrlen;/* Export the EEPROM bytes through sysfs, since that's convenient. * And maybe to other kernel code; it might hold a board's Ethernet * address, or board-specific calibration data generated on the * manufacturing floor. * * Default to root-only access to the data; EEPROMs often hold data * that's sensitive for read and/or write, like ethernet addresses, * security codes, board-specific manufacturing calibrations, etc. */sysfs_bin_attr_init(&at25->bin);at25->bin.attr.name = "eeprom";at25->bin.attr.mode = S_IRUSR;at25->bin.read = at25_bin_read;at25->mem.read = at25_mem_read;at25->bin.size = at25->chip.byte_len;if (!(chip->flags & EE_READONLY)) {at25->bin.write = at25_bin_write;at25->bin.attr.mode |= S_IWUSR;at25->mem.write = at25_mem_write;}err = sysfs_create_bin_file(&spi->dev.kobj, &at25->bin);if (err)goto fail;if (chip->setup)chip->setup(&at25->mem, chip->context);dev_info(&spi->dev, "%Zd %s %s eeprom%s, pagesize %u\n",(at25->bin.size < 1024)? at25->bin.size: (at25->bin.size / 1024),(at25->bin.size < 1024) ? "Byte" : "KByte",at25->chip.name,(chip->flags & EE_READONLY) ? " (readonly)" : "",at25->chip.page_size);return 0;fail:dev_dbg(&spi->dev, "probe err %d\n", err);kfree(at25);return err;}static int __devexit at25_remove(struct spi_device *spi){struct at25_data*at25;at25 = dev_get_drvdata(&spi->dev);sysfs_remove_bin_file(&spi->dev.kobj, &at25->bin);kfree(at25);return 0;}/*-------------------------------------------------------------------------*/static struct spi_driver at25_driver = {.driver = {.name= "at25",.owner= THIS_MODULE,},.probe= at25_probe,.remove= __devexit_p(at25_remove),};static int __init at25_init(void){return spi_register_driver(&at25_driver);}module_init(at25_init);static void __exit at25_exit(void){spi_unregister_driver(&at25_driver);}module_exit(at25_exit);MODULE_DESCRIPTION("Driver for most SPI EEPROMs");MODULE_AUTHOR("David Brownell");MODULE_LICENSE("GPL");MODULE_ALIAS("spi:at25");

文件里还有makefile和Kconfig,这里就不贴出来了,有兴趣大家可以自己去看,..\..\..\Linux l\linux-3.0.8\drivers\misc\eeprom