Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 14dd1ff0 authored by David Brownell's avatar David Brownell Committed by Linus Torvalds
Browse files

memory_accessor: implement the new memory_accessor interfaces for SPI EEPROMs



- Define new setup() hook to export the accessor
 - Implement accessor methods

Moves some error checking out of the sysfs interface code into the layer
below it, which is now shared by both sysfs and memory access code.

Signed-off-by: default avatarDavid Brownell <dbrownell@users.sourceforge.net>
Signed-off-by: default avatarKevin Hilman <khilman@deeprootsystems.com>
Cc: Jean Delvare <khali@linux-fr.org>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent 7274ec8b
Loading
Loading
Loading
Loading
+44 −14
Original line number Original line Diff line number Diff line
@@ -30,6 +30,7 @@


struct at25_data {
struct at25_data {
	struct spi_device	*spi;
	struct spi_device	*spi;
	struct memory_accessor	mem;
	struct mutex		lock;
	struct mutex		lock;
	struct spi_eeprom	chip;
	struct spi_eeprom	chip;
	struct bin_attribute	bin;
	struct bin_attribute	bin;
@@ -75,6 +76,13 @@ at25_ee_read(
	struct spi_transfer	t[2];
	struct spi_transfer	t[2];
	struct spi_message	m;
	struct spi_message	m;


	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 = command;
	*cp++ = AT25_READ;
	*cp++ = AT25_READ;


@@ -127,13 +135,6 @@ at25_bin_read(struct kobject *kobj, struct bin_attribute *bin_attr,
	dev = container_of(kobj, struct device, kobj);
	dev = container_of(kobj, struct device, kobj);
	at25 = dev_get_drvdata(dev);
	at25 = dev_get_drvdata(dev);


	if (unlikely(off >= at25->bin.size))
		return 0;
	if ((off + count) > at25->bin.size)
		count = at25->bin.size - off;
	if (unlikely(!count))
		return count;

	return at25_ee_read(at25, buf, off, count);
	return at25_ee_read(at25, buf, off, count);
}
}


@@ -146,6 +147,13 @@ at25_ee_write(struct at25_data *at25, char *buf, loff_t off, size_t count)
	unsigned		buf_size;
	unsigned		buf_size;
	u8			*bounce;
	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 */
	/* Temp buffer starts with command and address */
	buf_size = at25->chip.page_size;
	buf_size = at25->chip.page_size;
	if (buf_size > io_limit)
	if (buf_size > io_limit)
@@ -253,18 +261,31 @@ at25_bin_write(struct kobject *kobj, struct bin_attribute *bin_attr,
	dev = container_of(kobj, struct device, kobj);
	dev = container_of(kobj, struct device, kobj);
	at25 = dev_get_drvdata(dev);
	at25 = dev_get_drvdata(dev);


	if (unlikely(off >= at25->bin.size))
		return -EFBIG;
	if ((off + count) > at25->bin.size)
		count = at25->bin.size - off;
	if (unlikely(!count))
		return count;

	return at25_ee_write(at25, buf, off, count);
	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, 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)
static int at25_probe(struct spi_device *spi)
{
{
	struct at25_data	*at25 = NULL;
	struct at25_data	*at25 = NULL;
@@ -317,6 +338,10 @@ static int at25_probe(struct spi_device *spi)
	at25->addrlen = addrlen;
	at25->addrlen = addrlen;


	/* Export the EEPROM bytes through sysfs, since that's convenient.
	/* 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
	 * Default to root-only access to the data; EEPROMs often hold data
	 * that's sensitive for read and/or write, like ethernet addresses,
	 * that's sensitive for read and/or write, like ethernet addresses,
	 * security codes, board-specific manufacturing calibrations, etc.
	 * security codes, board-specific manufacturing calibrations, etc.
@@ -324,17 +349,22 @@ static int at25_probe(struct spi_device *spi)
	at25->bin.attr.name = "eeprom";
	at25->bin.attr.name = "eeprom";
	at25->bin.attr.mode = S_IRUSR;
	at25->bin.attr.mode = S_IRUSR;
	at25->bin.read = at25_bin_read;
	at25->bin.read = at25_bin_read;
	at25->mem.read = at25_mem_read;


	at25->bin.size = at25->chip.byte_len;
	at25->bin.size = at25->chip.byte_len;
	if (!(chip->flags & EE_READONLY)) {
	if (!(chip->flags & EE_READONLY)) {
		at25->bin.write = at25_bin_write;
		at25->bin.write = at25_bin_write;
		at25->bin.attr.mode |= S_IWUSR;
		at25->bin.attr.mode |= S_IWUSR;
		at25->mem.write = at25_mem_write;
	}
	}


	err = sysfs_create_bin_file(&spi->dev.kobj, &at25->bin);
	err = sysfs_create_bin_file(&spi->dev.kobj, &at25->bin);
	if (err)
	if (err)
		goto fail;
		goto fail;


	if (chip->setup)
		chip->setup(&at25->mem, chip->context);

	dev_info(&spi->dev, "%Zd %s %s eeprom%s, pagesize %u\n",
	dev_info(&spi->dev, "%Zd %s %s eeprom%s, pagesize %u\n",
		(at25->bin.size < 1024)
		(at25->bin.size < 1024)
			? at25->bin.size
			? at25->bin.size
+6 −0
Original line number Original line Diff line number Diff line
#ifndef __LINUX_SPI_EEPROM_H
#ifndef __LINUX_SPI_EEPROM_H
#define __LINUX_SPI_EEPROM_H
#define __LINUX_SPI_EEPROM_H


#include <linux/memory.h>

/*
/*
 * Put one of these structures in platform_data for SPI EEPROMS handled
 * Put one of these structures in platform_data for SPI EEPROMS handled
 * by the "at25" driver.  On SPI, most EEPROMS understand the same core
 * by the "at25" driver.  On SPI, most EEPROMS understand the same core
@@ -17,6 +19,10 @@ struct spi_eeprom {
#define	EE_ADDR2	0x0002			/* 16 bit addrs */
#define	EE_ADDR2	0x0002			/* 16 bit addrs */
#define	EE_ADDR3	0x0004			/* 24 bit addrs */
#define	EE_ADDR3	0x0004			/* 24 bit addrs */
#define	EE_READONLY	0x0008			/* disallow writes */
#define	EE_READONLY	0x0008			/* disallow writes */

	/* for exporting this chip's data to other kernel code */
	void (*setup)(struct memory_accessor *mem, void *context);
	void *context;
};
};


#endif /* __LINUX_SPI_EEPROM_H */
#endif /* __LINUX_SPI_EEPROM_H */