linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 00/14] eeprom: at24: driver rework and at24cs/at24mac support
@ 2016-05-29 21:53 Bartosz Golaszewski
  2016-05-29 21:53 ` [PATCH 01/14] eeprom: at24: improve the device_id table readability Bartosz Golaszewski
                   ` (14 more replies)
  0 siblings, 15 replies; 16+ messages in thread
From: Bartosz Golaszewski @ 2016-05-29 21:53 UTC (permalink / raw)
  To: Wolfram Sang, linux-i2c, LKML, Andrew Lunn, Srinivas Kandagatla,
	Maxime Ripard, GregKH
  Cc: Bartosz Golaszewski

Chips from the at24cs EEPROM series have an additional read-only
memory area containing a factory pre-programmed serial number. In
order to access it, a dummy write must be executed before reading
the serial number bytes.

Chips from the at24mac familiy, apart from the serial number, have
a second special memory area containing a factory programmed
EUI-48/EUI64 mac address.

The read-only serial/mac memory area is accessible on a different i2c
slave address (addr + 0x08). This patchset makes it possible to
instantiate a separate at24 device on this second address and access
the read-only area through the regular eeprom sysfs attribute or the
new nvmem subsystem.

This series also contains several patches refactoring the driver code.
Most notably: the low-level read/write routines are split into more
specialized, smaller functions that no longer perform functionality
checks at runtime.

Minor readability tweaks are also included.

Tested with at24cs32 and at24cs02 chips (for both 16 and 8 bit address
pointers). I have no means of testing the support for at24mac chips, I
relied solely on the datasheet.

Bartosz Golaszewski (14):
  eeprom: at24: improve the device_id table readability
  eeprom: at24: move at24_read() below at24_eeprom_write()
  eeprom: at24: coding style fixes
  eeprom: at24: call read/write functions via function pointers
  eeprom: at24: hide the read/write loop behind a macro
  eeprom: at24: split at24_eeprom_read() into specialized functions
  eeprom: at24: split at24_eeprom_write() into specialized functions
  eeprom: at24: platform_data: use BIT() macro
  eeprom: at24: platform_data: add serial number flag
  eeprom: at24: support reading the serial number
  eeprom: at24: add the at24cs series to the list of supported devices
  eeprom: at24: platform_data: add at24mac series flag
  eeprom: at24: add support for at24mac series
  eeprom: at24: add at24mac chips to the list of supported devices

 drivers/misc/eeprom/at24.c         | 498 +++++++++++++++++++++++++------------
 include/linux/platform_data/at24.h |  11 +-
 2 files changed, 350 insertions(+), 159 deletions(-)

-- 
2.7.4

^ permalink raw reply	[flat|nested] 16+ messages in thread

* [PATCH 01/14] eeprom: at24: improve the device_id table readability
  2016-05-29 21:53 [PATCH 00/14] eeprom: at24: driver rework and at24cs/at24mac support Bartosz Golaszewski
@ 2016-05-29 21:53 ` Bartosz Golaszewski
  2016-05-29 21:53 ` [PATCH 02/14] eeprom: at24: move at24_read() below at24_eeprom_write() Bartosz Golaszewski
                   ` (13 subsequent siblings)
  14 siblings, 0 replies; 16+ messages in thread
From: Bartosz Golaszewski @ 2016-05-29 21:53 UTC (permalink / raw)
  To: Wolfram Sang, linux-i2c, LKML, Andrew Lunn, Srinivas Kandagatla,
	Maxime Ripard, GregKH
  Cc: Bartosz Golaszewski

As part of the preparation for introducing support for more chips,
improve the readability of the device table by separating columns
with tabs.

Signed-off-by: Bartosz Golaszewski <bgolaszewski@baylibre.com>
---
 drivers/misc/eeprom/at24.c | 28 ++++++++++++++--------------
 1 file changed, 14 insertions(+), 14 deletions(-)

diff --git a/drivers/misc/eeprom/at24.c b/drivers/misc/eeprom/at24.c
index 9ceb63b..411600d 100644
--- a/drivers/misc/eeprom/at24.c
+++ b/drivers/misc/eeprom/at24.c
@@ -111,23 +111,23 @@ MODULE_PARM_DESC(write_timeout, "Time (in ms) to try writes (default 25)");
 
 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) },
+	{ "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) },
+	{ "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) },
+	{ "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) },
+	{ "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 */ }
 };
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH 02/14] eeprom: at24: move at24_read() below at24_eeprom_write()
  2016-05-29 21:53 [PATCH 00/14] eeprom: at24: driver rework and at24cs/at24mac support Bartosz Golaszewski
  2016-05-29 21:53 ` [PATCH 01/14] eeprom: at24: improve the device_id table readability Bartosz Golaszewski
@ 2016-05-29 21:53 ` Bartosz Golaszewski
  2016-05-29 21:53 ` [PATCH 03/14] eeprom: at24: coding style fixes Bartosz Golaszewski
                   ` (12 subsequent siblings)
  14 siblings, 0 replies; 16+ messages in thread
From: Bartosz Golaszewski @ 2016-05-29 21:53 UTC (permalink / raw)
  To: Wolfram Sang, linux-i2c, LKML, Andrew Lunn, Srinivas Kandagatla,
	Maxime Ripard, GregKH
  Cc: Bartosz Golaszewski

In preparation for splitting at24_eeprom_write() & at24_eeprom_read()
into smaller, specialized routines move at24_read() below, so that it
won't be intertwined with the low-level EEPROM accessors.

Signed-off-by: Bartosz Golaszewski <bgolaszewski@baylibre.com>
---
 drivers/misc/eeprom/at24.c | 64 +++++++++++++++++++++++-----------------------
 1 file changed, 32 insertions(+), 32 deletions(-)

diff --git a/drivers/misc/eeprom/at24.c b/drivers/misc/eeprom/at24.c
index 411600d..e12d76f 100644
--- a/drivers/misc/eeprom/at24.c
+++ b/drivers/misc/eeprom/at24.c
@@ -249,38 +249,6 @@ static ssize_t at24_eeprom_read(struct at24_data *at24, char *buf,
 	return -ETIMEDOUT;
 }
 
-static int at24_read(void *priv, unsigned int off, void *val, size_t count)
-{
-	struct at24_data *at24 = priv;
-	char *buf = val;
-
-	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) {
-		int	status;
-
-		status = at24_eeprom_read(at24, buf, off, count);
-		if (status < 0) {
-			mutex_unlock(&at24->lock);
-			return status;
-		}
-		buf += status;
-		off += status;
-		count -= status;
-	}
-
-	mutex_unlock(&at24->lock);
-
-	return 0;
-}
-
 /*
  * Note that if the hardware write-protect pin is pulled high, the whole
  * chip is normally write protected. But there are plenty of product
@@ -366,6 +334,38 @@ static ssize_t at24_eeprom_write(struct at24_data *at24, const char *buf,
 	return -ETIMEDOUT;
 }
 
+static int at24_read(void *priv, unsigned int off, void *val, size_t count)
+{
+	struct at24_data *at24 = priv;
+	char *buf = val;
+
+	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) {
+		int	status;
+
+		status = at24_eeprom_read(at24, buf, off, count);
+		if (status < 0) {
+			mutex_unlock(&at24->lock);
+			return status;
+		}
+		buf += status;
+		off += status;
+		count -= status;
+	}
+
+	mutex_unlock(&at24->lock);
+
+	return 0;
+}
+
 static int at24_write(void *priv, unsigned int off, void *val, size_t count)
 {
 	struct at24_data *at24 = priv;
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH 03/14] eeprom: at24: coding style fixes
  2016-05-29 21:53 [PATCH 00/14] eeprom: at24: driver rework and at24cs/at24mac support Bartosz Golaszewski
  2016-05-29 21:53 ` [PATCH 01/14] eeprom: at24: improve the device_id table readability Bartosz Golaszewski
  2016-05-29 21:53 ` [PATCH 02/14] eeprom: at24: move at24_read() below at24_eeprom_write() Bartosz Golaszewski
@ 2016-05-29 21:53 ` Bartosz Golaszewski
  2016-05-29 21:53 ` [PATCH 04/14] eeprom: at24: call read/write functions via function pointers Bartosz Golaszewski
                   ` (11 subsequent siblings)
  14 siblings, 0 replies; 16+ messages in thread
From: Bartosz Golaszewski @ 2016-05-29 21:53 UTC (permalink / raw)
  To: Wolfram Sang, linux-i2c, LKML, Andrew Lunn, Srinivas Kandagatla,
	Maxime Ripard, GregKH
  Cc: Bartosz Golaszewski

Align the arguments in broken lines with the arguments list's opening
brackets and make checkpatch.pl happy by converting 'unsigned' into
'unsigned int'.

Signed-off-by: Bartosz Golaszewski <bgolaszewski@baylibre.com>
---
 drivers/misc/eeprom/at24.c | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)

diff --git a/drivers/misc/eeprom/at24.c b/drivers/misc/eeprom/at24.c
index e12d76f..564a201 100644
--- a/drivers/misc/eeprom/at24.c
+++ b/drivers/misc/eeprom/at24.c
@@ -147,7 +147,7 @@ MODULE_DEVICE_TABLE(acpi, at24_acpi_ids);
  * Assumes that sanity checks for offset happened at sysfs-layer.
  */
 static struct i2c_client *at24_translate_offset(struct at24_data *at24,
-		unsigned *offset)
+						unsigned int *offset)
 {
 	unsigned i;
 
@@ -163,7 +163,7 @@ static struct i2c_client *at24_translate_offset(struct at24_data *at24,
 }
 
 static ssize_t at24_eeprom_read(struct at24_data *at24, char *buf,
-		unsigned offset, size_t count)
+				unsigned int offset, size_t count)
 {
 	struct i2c_msg msg[2];
 	u8 msgbuf[2];
@@ -258,7 +258,7 @@ static ssize_t at24_eeprom_read(struct at24_data *at24, char *buf,
  * writes at most one page.
  */
 static ssize_t at24_eeprom_write(struct at24_data *at24, const char *buf,
-		unsigned offset, size_t count)
+				 unsigned int offset, size_t count)
 {
 	struct i2c_client *client;
 	struct i2c_msg msg;
@@ -400,7 +400,7 @@ static int at24_write(void *priv, unsigned int off, void *val, size_t count)
 
 #ifdef CONFIG_OF
 static void at24_get_ofdata(struct i2c_client *client,
-		struct at24_platform_data *chip)
+			    struct at24_platform_data *chip)
 {
 	const __be32 *val;
 	struct device_node *node = client->dev.of_node;
@@ -415,7 +415,7 @@ static void at24_get_ofdata(struct i2c_client *client,
 }
 #else
 static void at24_get_ofdata(struct i2c_client *client,
-		struct at24_platform_data *chip)
+			    struct at24_platform_data *chip)
 { }
 #endif /* CONFIG_OF */
 
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH 04/14] eeprom: at24: call read/write functions via function pointers
  2016-05-29 21:53 [PATCH 00/14] eeprom: at24: driver rework and at24cs/at24mac support Bartosz Golaszewski
                   ` (2 preceding siblings ...)
  2016-05-29 21:53 ` [PATCH 03/14] eeprom: at24: coding style fixes Bartosz Golaszewski
@ 2016-05-29 21:53 ` Bartosz Golaszewski
  2016-05-29 21:53 ` [PATCH 05/14] eeprom: at24: hide the read/write loop behind a macro Bartosz Golaszewski
                   ` (10 subsequent siblings)
  14 siblings, 0 replies; 16+ messages in thread
From: Bartosz Golaszewski @ 2016-05-29 21:53 UTC (permalink / raw)
  To: Wolfram Sang, linux-i2c, LKML, Andrew Lunn, Srinivas Kandagatla,
	Maxime Ripard, GregKH
  Cc: Bartosz Golaszewski

The first step in simplifying the read and write functions is to call
them via function pointers stored in at24_data. When we eventually
split the routines into smaller ones (depending on whether they use
smbus or i2c operations) we'll simply assign them to said pointers
instead of checking the flags at runtime every time we read/write.

Signed-off-by: Bartosz Golaszewski <bgolaszewski@baylibre.com>
---
 drivers/misc/eeprom/at24.c | 11 +++++++++--
 1 file changed, 9 insertions(+), 2 deletions(-)

diff --git a/drivers/misc/eeprom/at24.c b/drivers/misc/eeprom/at24.c
index 564a201..0621937 100644
--- a/drivers/misc/eeprom/at24.c
+++ b/drivers/misc/eeprom/at24.c
@@ -58,6 +58,10 @@ struct at24_data {
 	int use_smbus;
 	int use_smbus_write;
 
+	ssize_t (*read_func)(struct at24_data *, char *, unsigned int, size_t);
+	ssize_t (*write_func)(struct at24_data *,
+			      const char *, unsigned int, size_t);
+
 	/*
 	 * Lock protects against activities from other Linux tasks,
 	 * but not from changes by other I2C masters.
@@ -351,7 +355,7 @@ static int at24_read(void *priv, unsigned int off, void *val, size_t count)
 	while (count) {
 		int	status;
 
-		status = at24_eeprom_read(at24, buf, off, count);
+		status = at24->read_func(at24, buf, off, count);
 		if (status < 0) {
 			mutex_unlock(&at24->lock);
 			return status;
@@ -383,7 +387,7 @@ static int at24_write(void *priv, unsigned int off, void *val, size_t count)
 	while (count) {
 		int status;
 
-		status = at24_eeprom_write(at24, buf, off, count);
+		status = at24->write_func(at24, buf, off, count);
 		if (status < 0) {
 			mutex_unlock(&at24->lock);
 			return status;
@@ -518,6 +522,9 @@ static int at24_probe(struct i2c_client *client, const struct i2c_device_id *id)
 	at24->chip = chip;
 	at24->num_addresses = num_addresses;
 
+	at24->read_func = at24_eeprom_read;
+	at24->write_func = at24_eeprom_write;
+
 	writable = !(chip.flags & AT24_FLAG_READONLY);
 	if (writable) {
 		if (!use_smbus || use_smbus_write) {
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH 05/14] eeprom: at24: hide the read/write loop behind a macro
  2016-05-29 21:53 [PATCH 00/14] eeprom: at24: driver rework and at24cs/at24mac support Bartosz Golaszewski
                   ` (3 preceding siblings ...)
  2016-05-29 21:53 ` [PATCH 04/14] eeprom: at24: call read/write functions via function pointers Bartosz Golaszewski
@ 2016-05-29 21:53 ` Bartosz Golaszewski
  2016-05-29 21:53 ` [PATCH 06/14] eeprom: at24: split at24_eeprom_read() into specialized functions Bartosz Golaszewski
                   ` (9 subsequent siblings)
  14 siblings, 0 replies; 16+ messages in thread
From: Bartosz Golaszewski @ 2016-05-29 21:53 UTC (permalink / raw)
  To: Wolfram Sang, linux-i2c, LKML, Andrew Lunn, Srinivas Kandagatla,
	Maxime Ripard, GregKH
  Cc: Bartosz Golaszewski

Before splitting the read/write routines into smaller, more
specialized functions, unduplicate some code in advance.

Use a 'for' loop instead of 'do while' when waiting for the previous
write to complete and hide it behind a macro.

Signed-off-by: Bartosz Golaszewski <bgolaszewski@baylibre.com>
---
 drivers/misc/eeprom/at24.c | 42 ++++++++++++++++++++----------------------
 1 file changed, 20 insertions(+), 22 deletions(-)

diff --git a/drivers/misc/eeprom/at24.c b/drivers/misc/eeprom/at24.c
index 0621937..2efb572 100644
--- a/drivers/misc/eeprom/at24.c
+++ b/drivers/misc/eeprom/at24.c
@@ -113,6 +113,22 @@ MODULE_PARM_DESC(write_timeout, "Time (in ms) to try writes (default 25)");
 	((1 << AT24_SIZE_FLAGS | (_flags)) 		\
 	    << AT24_SIZE_BYTELEN | ilog2(_len))
 
+/*
+ * Both reads and writes fail if the previous write didn't complete yet. This
+ * macro loops a few times waiting at least long enough for one entire page
+ * write to work.
+ *
+ * It takes two parameters: a variable in which the future timeout in jiffies
+ * will be stored and a temporary variable holding the time of the last
+ * iteration of processing the request. Both should be unsigned integers
+ * holding at least 32 bits.
+ */
+#define loop_until_timeout(tout, op_time)				\
+	for (tout = jiffies + msecs_to_jiffies(write_timeout),		\
+		op_time = jiffies;					\
+	     time_before(op_time, tout);				\
+	     usleep_range(1000, 1500), op_time = jiffies)
+
 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) },
@@ -225,14 +241,7 @@ static ssize_t at24_eeprom_read(struct at24_data *at24, char *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;
+	loop_until_timeout(timeout, read_time) {
 		if (at24->use_smbus) {
 			status = i2c_smbus_read_i2c_block_data_or_emulated(client, offset,
 									   count, buf);
@@ -246,9 +255,7 @@ static ssize_t at24_eeprom_read(struct at24_data *at24, char *buf,
 
 		if (status == count)
 			return count;
-
-		usleep_range(1000, 1500);
-	} while (time_before(read_time, timeout));
+	}
 
 	return -ETIMEDOUT;
 }
@@ -299,14 +306,7 @@ static ssize_t at24_eeprom_write(struct at24_data *at24, const char *buf,
 		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;
+	loop_until_timeout(timeout, write_time) {
 		if (at24->use_smbus_write) {
 			switch (at24->use_smbus_write) {
 			case I2C_SMBUS_I2C_BLOCK_DATA:
@@ -331,9 +331,7 @@ static ssize_t at24_eeprom_write(struct at24_data *at24, const char *buf,
 
 		if (status == count)
 			return count;
-
-		usleep_range(1000, 1500);
-	} while (time_before(write_time, timeout));
+	}
 
 	return -ETIMEDOUT;
 }
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH 06/14] eeprom: at24: split at24_eeprom_read() into specialized functions
  2016-05-29 21:53 [PATCH 00/14] eeprom: at24: driver rework and at24cs/at24mac support Bartosz Golaszewski
                   ` (4 preceding siblings ...)
  2016-05-29 21:53 ` [PATCH 05/14] eeprom: at24: hide the read/write loop behind a macro Bartosz Golaszewski
@ 2016-05-29 21:53 ` Bartosz Golaszewski
  2016-05-29 21:53 ` [PATCH 07/14] eeprom: at24: split at24_eeprom_write() " Bartosz Golaszewski
                   ` (8 subsequent siblings)
  14 siblings, 0 replies; 16+ messages in thread
From: Bartosz Golaszewski @ 2016-05-29 21:53 UTC (permalink / raw)
  To: Wolfram Sang, linux-i2c, LKML, Andrew Lunn, Srinivas Kandagatla,
	Maxime Ripard, GregKH
  Cc: Bartosz Golaszewski

Split at24_eeprom_read() into two smaller functions - one for the
i2c operations and one for the smbus extensions. Assign them in
at24_probe() depending on the bus capabilities.

Also: in order to avoid duplications move the comments related to
offset calculations above the at24_translate_offset() routine.

Signed-off-by: Bartosz Golaszewski <bgolaszewski@baylibre.com>
---
 drivers/misc/eeprom/at24.c | 125 +++++++++++++++++++++++++--------------------
 1 file changed, 71 insertions(+), 54 deletions(-)

diff --git a/drivers/misc/eeprom/at24.c b/drivers/misc/eeprom/at24.c
index 2efb572..e7db137 100644
--- a/drivers/misc/eeprom/at24.c
+++ b/drivers/misc/eeprom/at24.c
@@ -165,6 +165,19 @@ MODULE_DEVICE_TABLE(acpi, at24_acpi_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.
+ *
+ * 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.
+ *
+ * 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.
  */
 static struct i2c_client *at24_translate_offset(struct at24_data *at24,
 						unsigned int *offset)
@@ -182,74 +195,77 @@ static struct i2c_client *at24_translate_offset(struct at24_data *at24,
 	return at24->client[i];
 }
 
-static ssize_t at24_eeprom_read(struct at24_data *at24, char *buf,
-				unsigned int offset, size_t count)
+static ssize_t at24_eeprom_read_smbus(struct at24_data *at24, char *buf,
+				      unsigned int offset, size_t count)
 {
-	struct i2c_msg msg[2];
-	u8 msgbuf[2];
+	unsigned long timeout, read_time;
 	struct i2c_client *client;
+	int status;
+
+	client = at24_translate_offset(at24, &offset);
+
+	if (count > io_limit)
+		count = io_limit;
+
+	/* Smaller eeproms can work given some SMBus extension calls */
+	if (count > I2C_SMBUS_BLOCK_MAX)
+		count = I2C_SMBUS_BLOCK_MAX;
+
+	loop_until_timeout(timeout, read_time) {
+		status = i2c_smbus_read_i2c_block_data_or_emulated(client,
+								   offset,
+								   count, buf);
+
+		dev_dbg(&client->dev, "read %zu@%d --> %d (%ld)\n",
+				count, offset, status, jiffies);
+
+		if (status == count)
+			return count;
+	}
+
+	return -ETIMEDOUT;
+}
+
+static ssize_t at24_eeprom_read_i2c(struct at24_data *at24, char *buf,
+				    unsigned int offset, size_t count)
+{
 	unsigned long timeout, read_time;
+	struct i2c_client *client;
+	struct i2c_msg msg[2];
 	int status, i;
+	u8 msgbuf[2];
 
 	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;
 
-	if (at24->use_smbus) {
-		/* Smaller eeproms can work given some SMBus extension calls */
-		if (count > I2C_SMBUS_BLOCK_MAX)
-			count = I2C_SMBUS_BLOCK_MAX;
-	} else {
-		/*
-		 * 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;
+	/*
+	 * 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[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;
-	}
+	msg[1].addr = client->addr;
+	msg[1].flags = I2C_M_RD;
+	msg[1].buf = buf;
+	msg[1].len = count;
 
 	loop_until_timeout(timeout, read_time) {
-		if (at24->use_smbus) {
-			status = i2c_smbus_read_i2c_block_data_or_emulated(client, offset,
-									   count, buf);
-		} else {
-			status = i2c_transfer(client->adapter, msg, 2);
-			if (status == 2)
-				status = count;
-		}
+		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);
 
@@ -520,7 +536,8 @@ static int at24_probe(struct i2c_client *client, const struct i2c_device_id *id)
 	at24->chip = chip;
 	at24->num_addresses = num_addresses;
 
-	at24->read_func = at24_eeprom_read;
+	at24->read_func = at24->use_smbus ? at24_eeprom_read_smbus
+					  : at24_eeprom_read_i2c;
 	at24->write_func = at24_eeprom_write;
 
 	writable = !(chip.flags & AT24_FLAG_READONLY);
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH 07/14] eeprom: at24: split at24_eeprom_write() into specialized functions
  2016-05-29 21:53 [PATCH 00/14] eeprom: at24: driver rework and at24cs/at24mac support Bartosz Golaszewski
                   ` (5 preceding siblings ...)
  2016-05-29 21:53 ` [PATCH 06/14] eeprom: at24: split at24_eeprom_read() into specialized functions Bartosz Golaszewski
@ 2016-05-29 21:53 ` Bartosz Golaszewski
  2016-05-29 21:53 ` [PATCH 08/14] eeprom: at24: platform_data: use BIT() macro Bartosz Golaszewski
                   ` (7 subsequent siblings)
  14 siblings, 0 replies; 16+ messages in thread
From: Bartosz Golaszewski @ 2016-05-29 21:53 UTC (permalink / raw)
  To: Wolfram Sang, linux-i2c, LKML, Andrew Lunn, Srinivas Kandagatla,
	Maxime Ripard, GregKH
  Cc: Bartosz Golaszewski

Split at24_eeprom_write() into three smaller functions - one for the
i2c operations and two for the smbus extensions (separate routines for
block and byte transfers). Assign them in at24_probe() depending on
the bus capabilities.

Also: in order to avoid duplications move code adjusting the count
argument into a separate function and use it for i2c and smbus block
writes (no need for a roll-over for byte writes as we're always
writing one byte).

Signed-off-by: Bartosz Golaszewski <bgolaszewski@baylibre.com>
---
 drivers/misc/eeprom/at24.c | 134 ++++++++++++++++++++++++++++++---------------
 1 file changed, 91 insertions(+), 43 deletions(-)

diff --git a/drivers/misc/eeprom/at24.c b/drivers/misc/eeprom/at24.c
index e7db137..6acf35a 100644
--- a/drivers/misc/eeprom/at24.c
+++ b/drivers/misc/eeprom/at24.c
@@ -281,21 +281,15 @@ static ssize_t at24_eeprom_read_i2c(struct at24_data *at24, char *buf,
  * 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.
+ * We only use page mode writes; the alternative is sloooow. These routines
+ * write at most one page.
  */
-static ssize_t at24_eeprom_write(struct at24_data *at24, const char *buf,
-				 unsigned int offset, size_t count)
+
+static size_t at24_adjust_write_count(struct at24_data *at24,
+				      unsigned int offset, size_t count)
 {
-	struct i2c_client *client;
-	struct i2c_msg msg;
-	ssize_t status = 0;
-	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;
@@ -305,43 +299,90 @@ static ssize_t at24_eeprom_write(struct at24_data *at24, const char *buf,
 	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;
+	return count;
+}
+
+static ssize_t at24_eeprom_write_smbus_block(struct at24_data *at24,
+					     const char *buf,
+					     unsigned int offset, size_t count)
+{
+	unsigned long timeout, write_time;
+	struct i2c_client *client;
+	ssize_t status = 0;
+
+	client = at24_translate_offset(at24, &offset);
+	count = at24_adjust_write_count(at24, offset, count);
 
-		msg.addr = client->addr;
-		msg.flags = 0;
+	loop_until_timeout(timeout, write_time) {
+		status = i2c_smbus_write_i2c_block_data(client,
+							offset, count, buf);
+		if (status == 0)
+			status = count;
 
-		/* 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;
+		dev_dbg(&client->dev, "write %zu@%d --> %zd (%ld)\n",
+				count, offset, status, jiffies);
 
-		msg.buf[i++] = offset;
-		memcpy(&msg.buf[i], buf, count);
-		msg.len = i + count;
+		if (status == count)
+			return count;
 	}
 
+	return -ETIMEDOUT;
+}
+
+static ssize_t at24_eeprom_write_smbus_byte(struct at24_data *at24,
+					    const char *buf,
+					    unsigned int offset, size_t count)
+{
+	unsigned long timeout, write_time;
+	struct i2c_client *client;
+	ssize_t status = 0;
+
+	client = at24_translate_offset(at24, &offset);
+
 	loop_until_timeout(timeout, write_time) {
-		if (at24->use_smbus_write) {
-			switch (at24->use_smbus_write) {
-			case I2C_SMBUS_I2C_BLOCK_DATA:
-				status = i2c_smbus_write_i2c_block_data(client,
-						offset, count, buf);
-				break;
-			case I2C_SMBUS_BYTE_DATA:
-				status = i2c_smbus_write_byte_data(client,
-						offset, buf[0]);
-				break;
-			}
-
-			if (status == 0)
-				status = count;
-		} else {
-			status = i2c_transfer(client->adapter, &msg, 1);
-			if (status == 1)
-				status = count;
-		}
+		status = i2c_smbus_write_byte_data(client, offset, buf[0]);
+		if (status == 0)
+			status = count;
+
+		dev_dbg(&client->dev, "write %zu@%d --> %zd (%ld)\n",
+				count, offset, status, jiffies);
+
+		if (status == count)
+			return count;
+	}
+
+	return -ETIMEDOUT;
+}
+
+static ssize_t at24_eeprom_write_i2c(struct at24_data *at24, const char *buf,
+				     unsigned int offset, size_t count)
+{
+	unsigned long timeout, write_time;
+	struct i2c_client *client;
+	struct i2c_msg msg;
+	ssize_t status = 0;
+	int i = 0;
+
+	client = at24_translate_offset(at24, &offset);
+	count = at24_adjust_write_count(at24, offset, count);
+
+	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;
+
+	loop_until_timeout(timeout, write_time) {
+		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);
 
@@ -538,7 +579,14 @@ static int at24_probe(struct i2c_client *client, const struct i2c_device_id *id)
 
 	at24->read_func = at24->use_smbus ? at24_eeprom_read_smbus
 					  : at24_eeprom_read_i2c;
-	at24->write_func = at24_eeprom_write;
+	if (at24->use_smbus) {
+		if (at24->use_smbus_write == I2C_SMBUS_I2C_BLOCK_DATA)
+			at24->write_func = at24_eeprom_write_smbus_block;
+		else
+			at24->write_func = at24_eeprom_write_smbus_byte;
+	} else {
+		at24->write_func = at24_eeprom_write_i2c;
+	}
 
 	writable = !(chip.flags & AT24_FLAG_READONLY);
 	if (writable) {
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH 08/14] eeprom: at24: platform_data: use BIT() macro
  2016-05-29 21:53 [PATCH 00/14] eeprom: at24: driver rework and at24cs/at24mac support Bartosz Golaszewski
                   ` (6 preceding siblings ...)
  2016-05-29 21:53 ` [PATCH 07/14] eeprom: at24: split at24_eeprom_write() " Bartosz Golaszewski
@ 2016-05-29 21:53 ` Bartosz Golaszewski
  2016-05-29 21:53 ` [PATCH 09/14] eeprom: at24: platform_data: add serial number flag Bartosz Golaszewski
                   ` (6 subsequent siblings)
  14 siblings, 0 replies; 16+ messages in thread
From: Bartosz Golaszewski @ 2016-05-29 21:53 UTC (permalink / raw)
  To: Wolfram Sang, linux-i2c, LKML, Andrew Lunn, Srinivas Kandagatla,
	Maxime Ripard, GregKH
  Cc: Bartosz Golaszewski

Use BIT() macro to replace the 0xXX constants in platform_data flags
definitions.

Signed-off-by: Bartosz Golaszewski <bgolaszewski@baylibre.com>
---
 include/linux/platform_data/at24.h | 9 +++++----
 1 file changed, 5 insertions(+), 4 deletions(-)

diff --git a/include/linux/platform_data/at24.h b/include/linux/platform_data/at24.h
index dc9a13e..d5e9024 100644
--- a/include/linux/platform_data/at24.h
+++ b/include/linux/platform_data/at24.h
@@ -10,6 +10,7 @@
 
 #include <linux/types.h>
 #include <linux/nvmem-consumer.h>
+#include <linux/bitops.h>
 
 /**
  * struct at24_platform_data - data to set up at24 (generic eeprom) driver
@@ -43,10 +44,10 @@ struct at24_platform_data {
 	u32		byte_len;		/* size (sum of all addr) */
 	u16		page_size;		/* for writes */
 	u8		flags;
-#define AT24_FLAG_ADDR16	0x80	/* address pointer is 16 bit */
-#define AT24_FLAG_READONLY	0x40	/* sysfs-entry will be read-only */
-#define AT24_FLAG_IRUGO		0x20	/* sysfs-entry will be world-readable */
-#define AT24_FLAG_TAKE8ADDR	0x10	/* take always 8 addresses (24c00) */
+#define AT24_FLAG_ADDR16	BIT(7)	/* address pointer is 16 bit */
+#define AT24_FLAG_READONLY	BIT(6)	/* sysfs-entry will be read-only */
+#define AT24_FLAG_IRUGO		BIT(5)	/* sysfs-entry will be world-readable */
+#define AT24_FLAG_TAKE8ADDR	BIT(4)	/* take always 8 addresses (24c00) */
 
 	void		(*setup)(struct nvmem_device *nvmem, void *context);
 	void		*context;
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH 09/14] eeprom: at24: platform_data: add serial number flag
  2016-05-29 21:53 [PATCH 00/14] eeprom: at24: driver rework and at24cs/at24mac support Bartosz Golaszewski
                   ` (7 preceding siblings ...)
  2016-05-29 21:53 ` [PATCH 08/14] eeprom: at24: platform_data: use BIT() macro Bartosz Golaszewski
@ 2016-05-29 21:53 ` Bartosz Golaszewski
  2016-05-29 21:53 ` [PATCH 10/14] eeprom: at24: support reading the serial number Bartosz Golaszewski
                   ` (5 subsequent siblings)
  14 siblings, 0 replies; 16+ messages in thread
From: Bartosz Golaszewski @ 2016-05-29 21:53 UTC (permalink / raw)
  To: Wolfram Sang, linux-i2c, LKML, Andrew Lunn, Srinivas Kandagatla,
	Maxime Ripard, GregKH
  Cc: Bartosz Golaszewski

In preparation for supporting the at24cs EEPROM series add a new flag
to the at24 platform data. When set, it should tell the driver that
the chip has an additional read-only memory area that holds a factory
pre-programmed serial number.

Signed-off-by: Bartosz Golaszewski <bgolaszewski@baylibre.com>
---
 include/linux/platform_data/at24.h | 1 +
 1 file changed, 1 insertion(+)

diff --git a/include/linux/platform_data/at24.h b/include/linux/platform_data/at24.h
index d5e9024..fe0507e 100644
--- a/include/linux/platform_data/at24.h
+++ b/include/linux/platform_data/at24.h
@@ -48,6 +48,7 @@ struct at24_platform_data {
 #define AT24_FLAG_READONLY	BIT(6)	/* sysfs-entry will be read-only */
 #define AT24_FLAG_IRUGO		BIT(5)	/* sysfs-entry will be world-readable */
 #define AT24_FLAG_TAKE8ADDR	BIT(4)	/* take always 8 addresses (24c00) */
+#define AT24_FLAG_SERIAL	BIT(3)	/* factory-programmed serial number */
 
 	void		(*setup)(struct nvmem_device *nvmem, void *context);
 	void		*context;
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH 10/14] eeprom: at24: support reading the serial number
  2016-05-29 21:53 [PATCH 00/14] eeprom: at24: driver rework and at24cs/at24mac support Bartosz Golaszewski
                   ` (8 preceding siblings ...)
  2016-05-29 21:53 ` [PATCH 09/14] eeprom: at24: platform_data: add serial number flag Bartosz Golaszewski
@ 2016-05-29 21:53 ` Bartosz Golaszewski
  2016-05-29 21:53 ` [PATCH 11/14] eeprom: at24: add the at24cs series to the list of supported devices Bartosz Golaszewski
                   ` (4 subsequent siblings)
  14 siblings, 0 replies; 16+ messages in thread
From: Bartosz Golaszewski @ 2016-05-29 21:53 UTC (permalink / raw)
  To: Wolfram Sang, linux-i2c, LKML, Andrew Lunn, Srinivas Kandagatla,
	Maxime Ripard, GregKH
  Cc: Bartosz Golaszewski

The at24cs series EEPROM chips have an additional read-only memory area
containing a factory pre-programmed serial number. In order to access
it, one has to perform a dummy write before reading the serial number
bytes.

Add a function that allows to access the serial number and assign it
to at24->read_func if the chip allows serial number read operations
and the driver was passed the relevant flag for this device.

Signed-off-by: Bartosz Golaszewski <bgolaszewski@baylibre.com>
---
 drivers/misc/eeprom/at24.c | 62 ++++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 60 insertions(+), 2 deletions(-)

diff --git a/drivers/misc/eeprom/at24.c b/drivers/misc/eeprom/at24.c
index 6acf35a..29bbdad 100644
--- a/drivers/misc/eeprom/at24.c
+++ b/drivers/misc/eeprom/at24.c
@@ -276,6 +276,59 @@ static ssize_t at24_eeprom_read_i2c(struct at24_data *at24, char *buf,
 	return -ETIMEDOUT;
 }
 
+static ssize_t at24_eeprom_read_serial(struct at24_data *at24, char *buf,
+				       unsigned int offset, size_t count)
+{
+	unsigned long timeout, read_time;
+	struct i2c_client *client;
+	struct i2c_msg msg[2];
+	u8 addrbuf[2];
+	int status;
+
+	client = at24_translate_offset(at24, &offset);
+
+	memset(msg, 0, sizeof(msg));
+	msg[0].addr = client->addr;
+	msg[0].buf = addrbuf;
+
+	/*
+	 * The address pointer of the device is shared between the regular
+	 * EEPROM array and the serial number block. The dummy write (part of
+	 * the sequential read protocol) ensures the address pointer is reset
+	 * to the desired position.
+	 */
+	if (at24->chip.flags & AT24_FLAG_ADDR16) {
+		/*
+		 * For 16 bit address pointers, the word address must contain
+		 * a '10' sequence in bits 11 and 10 regardless of the
+		 * intended position of the address pointer.
+		 */
+		addrbuf[0] = 0x08;
+		addrbuf[1] = offset;
+		msg[0].len = 2;
+	} else {
+		/*
+		 * Otherwise the word address must begin with a '10' sequence,
+		 * regardless of the intended address.
+		 */
+		addrbuf[0] = 0x80 + offset;
+		msg[0].len = 1;
+	}
+
+	msg[1].addr = client->addr;
+	msg[1].flags = I2C_M_RD;
+	msg[1].buf = buf;
+	msg[1].len = count;
+
+	loop_until_timeout(timeout, read_time) {
+		status = i2c_transfer(client->adapter, msg, 2);
+		if (status == 2)
+			return count;
+	}
+
+	return -ETIMEDOUT;
+}
+
 /*
  * Note that if the hardware write-protect pin is pulled high, the whole
  * chip is normally write protected. But there are plenty of product
@@ -577,8 +630,13 @@ static int at24_probe(struct i2c_client *client, const struct i2c_device_id *id)
 	at24->chip = chip;
 	at24->num_addresses = num_addresses;
 
-	at24->read_func = at24->use_smbus ? at24_eeprom_read_smbus
-					  : at24_eeprom_read_i2c;
+	if (chip.flags & AT24_FLAG_SERIAL) {
+		at24->read_func = at24_eeprom_read_serial;
+	} else {
+		at24->read_func = at24->use_smbus ? at24_eeprom_read_smbus
+						  : at24_eeprom_read_i2c;
+	}
+
 	if (at24->use_smbus) {
 		if (at24->use_smbus_write == I2C_SMBUS_I2C_BLOCK_DATA)
 			at24->write_func = at24_eeprom_write_smbus_block;
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH 11/14] eeprom: at24: add the at24cs series to the list of supported devices
  2016-05-29 21:53 [PATCH 00/14] eeprom: at24: driver rework and at24cs/at24mac support Bartosz Golaszewski
                   ` (9 preceding siblings ...)
  2016-05-29 21:53 ` [PATCH 10/14] eeprom: at24: support reading the serial number Bartosz Golaszewski
@ 2016-05-29 21:53 ` Bartosz Golaszewski
  2016-05-29 21:53 ` [PATCH 12/14] eeprom: at24: platform_data: add at24mac series flag Bartosz Golaszewski
                   ` (3 subsequent siblings)
  14 siblings, 0 replies; 16+ messages in thread
From: Bartosz Golaszewski @ 2016-05-29 21:53 UTC (permalink / raw)
  To: Wolfram Sang, linux-i2c, LKML, Andrew Lunn, Srinivas Kandagatla,
	Maxime Ripard, GregKH
  Cc: Bartosz Golaszewski

The infrastructure for reading of the factory-programmed serial number
for at24cs EEPROM series is now in place. Add the chips that are actually
equipped with the serial number memory area to the list of supported
devices.

The chips from the at24cs family have two memory areas - a regular
read-write block and a read-only area containing the serial number.

The latter is visible on a different slave address (the address of the
rw memory block + 0x08). In order to access both blocks the user needs
to instantiate a regular at24c device for the rw block address and a
corresponding at24cs device on the serial number block address.

Signed-off-by: Bartosz Golaszewski <bgolaszewski@baylibre.com>
---
 drivers/misc/eeprom/at24.c | 18 ++++++++++++++++++
 1 file changed, 18 insertions(+)

diff --git a/drivers/misc/eeprom/at24.c b/drivers/misc/eeprom/at24.c
index 29bbdad..0b5240d 100644
--- a/drivers/misc/eeprom/at24.c
+++ b/drivers/misc/eeprom/at24.c
@@ -134,16 +134,34 @@ static const struct i2c_device_id at24_ids[] = {
 	{ "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) },
+	{ "24cs01",	AT24_DEVICE_MAGIC(128 / 8,
+				AT24_FLAG_SERIAL | AT24_FLAG_READONLY) },
 	{ "24c02",	AT24_DEVICE_MAGIC(2048 / 8,	0) },
+	{ "24cs02",	AT24_DEVICE_MAGIC(128 / 8,
+				AT24_FLAG_SERIAL | AT24_FLAG_READONLY) },
 	/* 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) },
+	{ "24cs04",	AT24_DEVICE_MAGIC(128 / 8,
+				AT24_FLAG_SERIAL | AT24_FLAG_READONLY) },
 	/* 24rf08 quirk is handled at i2c-core */
 	{ "24c08",	AT24_DEVICE_MAGIC(8192 / 8,	0) },
+	{ "24cs08",	AT24_DEVICE_MAGIC(128 / 8,
+				AT24_FLAG_SERIAL | AT24_FLAG_READONLY) },
 	{ "24c16",	AT24_DEVICE_MAGIC(16384 / 8,	0) },
+	{ "24cs16",	AT24_DEVICE_MAGIC(128 / 8,
+				AT24_FLAG_SERIAL | AT24_FLAG_READONLY) },
 	{ "24c32",	AT24_DEVICE_MAGIC(32768 / 8,	AT24_FLAG_ADDR16) },
+	{ "24cs32",	AT24_DEVICE_MAGIC(128 / 8,
+				AT24_FLAG_ADDR16 |
+				AT24_FLAG_SERIAL |
+				AT24_FLAG_READONLY) },
 	{ "24c64",	AT24_DEVICE_MAGIC(65536 / 8,	AT24_FLAG_ADDR16) },
+	{ "24cs64",	AT24_DEVICE_MAGIC(128 / 8,
+				AT24_FLAG_ADDR16 |
+				AT24_FLAG_SERIAL |
+				AT24_FLAG_READONLY) },
 	{ "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) },
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH 12/14] eeprom: at24: platform_data: add at24mac series flag
  2016-05-29 21:53 [PATCH 00/14] eeprom: at24: driver rework and at24cs/at24mac support Bartosz Golaszewski
                   ` (10 preceding siblings ...)
  2016-05-29 21:53 ` [PATCH 11/14] eeprom: at24: add the at24cs series to the list of supported devices Bartosz Golaszewski
@ 2016-05-29 21:53 ` Bartosz Golaszewski
  2016-05-29 21:53 ` [PATCH 13/14] eeprom: at24: add support for at24mac series Bartosz Golaszewski
                   ` (2 subsequent siblings)
  14 siblings, 0 replies; 16+ messages in thread
From: Bartosz Golaszewski @ 2016-05-29 21:53 UTC (permalink / raw)
  To: Wolfram Sang, linux-i2c, LKML, Andrew Lunn, Srinivas Kandagatla,
	Maxime Ripard, GregKH
  Cc: Bartosz Golaszewski

As part of supporting the at24mac series add a new flag to the at24
platform data. When set, it indicates that this chip exposes the
factory-programmed EUI-48 or EUI-64 address.

Signed-off-by: Bartosz Golaszewski <bgolaszewski@baylibre.com>
---
 include/linux/platform_data/at24.h | 1 +
 1 file changed, 1 insertion(+)

diff --git a/include/linux/platform_data/at24.h b/include/linux/platform_data/at24.h
index fe0507e..80e4239 100644
--- a/include/linux/platform_data/at24.h
+++ b/include/linux/platform_data/at24.h
@@ -49,6 +49,7 @@ struct at24_platform_data {
 #define AT24_FLAG_IRUGO		BIT(5)	/* sysfs-entry will be world-readable */
 #define AT24_FLAG_TAKE8ADDR	BIT(4)	/* take always 8 addresses (24c00) */
 #define AT24_FLAG_SERIAL	BIT(3)	/* factory-programmed serial number */
+#define AT24_FLAG_MAC		BIT(2)	/* factory-programmed mac address */
 
 	void		(*setup)(struct nvmem_device *nvmem, void *context);
 	void		*context;
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH 13/14] eeprom: at24: add support for at24mac series
  2016-05-29 21:53 [PATCH 00/14] eeprom: at24: driver rework and at24cs/at24mac support Bartosz Golaszewski
                   ` (11 preceding siblings ...)
  2016-05-29 21:53 ` [PATCH 12/14] eeprom: at24: platform_data: add at24mac series flag Bartosz Golaszewski
@ 2016-05-29 21:53 ` Bartosz Golaszewski
  2016-05-29 21:53 ` [PATCH 14/14] eeprom: at24: add at24mac chips to the list of supported devices Bartosz Golaszewski
  2016-07-06 15:04 ` [PATCH 00/14] eeprom: at24: driver rework and at24cs/at24mac support Bartosz Golaszewski
  14 siblings, 0 replies; 16+ messages in thread
From: Bartosz Golaszewski @ 2016-05-29 21:53 UTC (permalink / raw)
  To: Wolfram Sang, linux-i2c, LKML, Andrew Lunn, Srinivas Kandagatla,
	Maxime Ripard, GregKH
  Cc: Bartosz Golaszewski

Add a new read function to the at24 driver allowing to retrieve the
factory-programmed mac address embedded in chips from the at24mac
family.

These chips can be instantiated similarily to the at24cs family,
except that there's no way of having access to both the serial number
and the mac address at the same time - the user must instantiate
either an at24cs or at24mac device as both special memory areas are
accessible on the same slave address.

Signed-off-by: Bartosz Golaszewski <bgolaszewski@baylibre.com>
---
 drivers/misc/eeprom/at24.c | 38 ++++++++++++++++++++++++++++++++++++++
 1 file changed, 38 insertions(+)

diff --git a/drivers/misc/eeprom/at24.c b/drivers/misc/eeprom/at24.c
index 0b5240d..b3afe15 100644
--- a/drivers/misc/eeprom/at24.c
+++ b/drivers/misc/eeprom/at24.c
@@ -347,6 +347,36 @@ static ssize_t at24_eeprom_read_serial(struct at24_data *at24, char *buf,
 	return -ETIMEDOUT;
 }
 
+static ssize_t at24_eeprom_read_mac(struct at24_data *at24, char *buf,
+				    unsigned int offset, size_t count)
+{
+	unsigned long timeout, read_time;
+	struct i2c_client *client;
+	struct i2c_msg msg[2];
+	u8 addrbuf[2];
+	int status;
+
+	client = at24_translate_offset(at24, &offset);
+
+	memset(msg, 0, sizeof(msg));
+	msg[0].addr = client->addr;
+	msg[0].buf = addrbuf;
+	addrbuf[0] = 0x90 + offset;
+	msg[0].len = 1;
+	msg[1].addr = client->addr;
+	msg[1].flags = I2C_M_RD;
+	msg[1].buf = buf;
+	msg[1].len = count;
+
+	loop_until_timeout(timeout, read_time) {
+		status = i2c_transfer(client->adapter, msg, 2);
+		if (status == 2)
+			return count;
+	}
+
+	return -ETIMEDOUT;
+}
+
 /*
  * Note that if the hardware write-protect pin is pulled high, the whole
  * chip is normally write protected. But there are plenty of product
@@ -648,8 +678,16 @@ static int at24_probe(struct i2c_client *client, const struct i2c_device_id *id)
 	at24->chip = chip;
 	at24->num_addresses = num_addresses;
 
+	if ((chip.flags & AT24_FLAG_SERIAL) && (chip.flags & AT24_FLAG_MAC)) {
+		dev_err(&client->dev,
+			"invalid device data - cannot have both AT24_FLAG_SERIAL & AT24_FLAG_MAC.");
+		return -EINVAL;
+	}
+
 	if (chip.flags & AT24_FLAG_SERIAL) {
 		at24->read_func = at24_eeprom_read_serial;
+	} else if (chip.flags & AT24_FLAG_MAC) {
+		at24->read_func = at24_eeprom_read_mac;
 	} else {
 		at24->read_func = at24->use_smbus ? at24_eeprom_read_smbus
 						  : at24_eeprom_read_i2c;
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH 14/14] eeprom: at24: add at24mac chips to the list of supported devices
  2016-05-29 21:53 [PATCH 00/14] eeprom: at24: driver rework and at24cs/at24mac support Bartosz Golaszewski
                   ` (12 preceding siblings ...)
  2016-05-29 21:53 ` [PATCH 13/14] eeprom: at24: add support for at24mac series Bartosz Golaszewski
@ 2016-05-29 21:53 ` Bartosz Golaszewski
  2016-07-06 15:04 ` [PATCH 00/14] eeprom: at24: driver rework and at24cs/at24mac support Bartosz Golaszewski
  14 siblings, 0 replies; 16+ messages in thread
From: Bartosz Golaszewski @ 2016-05-29 21:53 UTC (permalink / raw)
  To: Wolfram Sang, linux-i2c, LKML, Andrew Lunn, Srinivas Kandagatla,
	Maxime Ripard, GregKH
  Cc: Bartosz Golaszewski

Now with the infrastructure for reading the factory-programmed mac
address in place, add the two available chips from the at24mac
family: at24mac402 and at24mac602 to the device ID list.

Signed-off-by: Bartosz Golaszewski <bgolaszewski@baylibre.com>
---
 drivers/misc/eeprom/at24.c | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/drivers/misc/eeprom/at24.c b/drivers/misc/eeprom/at24.c
index b3afe15..0b8fafdb 100644
--- a/drivers/misc/eeprom/at24.c
+++ b/drivers/misc/eeprom/at24.c
@@ -139,6 +139,10 @@ static const struct i2c_device_id at24_ids[] = {
 	{ "24c02",	AT24_DEVICE_MAGIC(2048 / 8,	0) },
 	{ "24cs02",	AT24_DEVICE_MAGIC(128 / 8,
 				AT24_FLAG_SERIAL | AT24_FLAG_READONLY) },
+	{ "24mac402",	AT24_DEVICE_MAGIC(48 / 8,
+				AT24_FLAG_MAC | AT24_FLAG_READONLY) },
+	{ "24mac602",	AT24_DEVICE_MAGIC(64 / 8,
+				AT24_FLAG_MAC | AT24_FLAG_READONLY) },
 	/* spd is a 24c02 in memory DIMMs */
 	{ "spd",	AT24_DEVICE_MAGIC(2048 / 8,
 				AT24_FLAG_READONLY | AT24_FLAG_IRUGO) },
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 16+ messages in thread

* Re: [PATCH 00/14] eeprom: at24: driver rework and at24cs/at24mac support
  2016-05-29 21:53 [PATCH 00/14] eeprom: at24: driver rework and at24cs/at24mac support Bartosz Golaszewski
                   ` (13 preceding siblings ...)
  2016-05-29 21:53 ` [PATCH 14/14] eeprom: at24: add at24mac chips to the list of supported devices Bartosz Golaszewski
@ 2016-07-06 15:04 ` Bartosz Golaszewski
  14 siblings, 0 replies; 16+ messages in thread
From: Bartosz Golaszewski @ 2016-07-06 15:04 UTC (permalink / raw)
  To: Wolfram Sang, linux-i2c, LKML, Andrew Lunn, Srinivas Kandagatla,
	Maxime Ripard, GregKH
  Cc: Bartosz Golaszewski

2016-05-29 23:53 GMT+02:00 Bartosz Golaszewski <bgolaszewski@baylibre.com>:
> Chips from the at24cs EEPROM series have an additional read-only
> memory area containing a factory pre-programmed serial number. In
> order to access it, a dummy write must be executed before reading
> the serial number bytes.
>
> Chips from the at24mac familiy, apart from the serial number, have
> a second special memory area containing a factory programmed
> EUI-48/EUI64 mac address.
>
> The read-only serial/mac memory area is accessible on a different i2c
> slave address (addr + 0x08). This patchset makes it possible to
> instantiate a separate at24 device on this second address and access
> the read-only area through the regular eeprom sysfs attribute or the
> new nvmem subsystem.
>
> This series also contains several patches refactoring the driver code.
> Most notably: the low-level read/write routines are split into more
> specialized, smaller functions that no longer perform functionality
> checks at runtime.
>
> Minor readability tweaks are also included.
>
> Tested with at24cs32 and at24cs02 chips (for both 16 and 8 bit address
> pointers). I have no means of testing the support for at24mac chips, I
> relied solely on the datasheet.
>
> Bartosz Golaszewski (14):
>   eeprom: at24: improve the device_id table readability
>   eeprom: at24: move at24_read() below at24_eeprom_write()
>   eeprom: at24: coding style fixes
>   eeprom: at24: call read/write functions via function pointers
>   eeprom: at24: hide the read/write loop behind a macro
>   eeprom: at24: split at24_eeprom_read() into specialized functions
>   eeprom: at24: split at24_eeprom_write() into specialized functions
>   eeprom: at24: platform_data: use BIT() macro
>   eeprom: at24: platform_data: add serial number flag
>   eeprom: at24: support reading the serial number
>   eeprom: at24: add the at24cs series to the list of supported devices
>   eeprom: at24: platform_data: add at24mac series flag
>   eeprom: at24: add support for at24mac series
>   eeprom: at24: add at24mac chips to the list of supported devices
>
>  drivers/misc/eeprom/at24.c         | 498 +++++++++++++++++++++++++------------
>  include/linux/platform_data/at24.h |  11 +-
>  2 files changed, 350 insertions(+), 159 deletions(-)
>
> --
> 2.7.4
>

Gentle ping.

Any chance of getting this series picked up for 4.8?

Thanks,
Bartosz Golaszewski

^ permalink raw reply	[flat|nested] 16+ messages in thread

end of thread, other threads:[~2016-07-06 15:04 UTC | newest]

Thread overview: 16+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-05-29 21:53 [PATCH 00/14] eeprom: at24: driver rework and at24cs/at24mac support Bartosz Golaszewski
2016-05-29 21:53 ` [PATCH 01/14] eeprom: at24: improve the device_id table readability Bartosz Golaszewski
2016-05-29 21:53 ` [PATCH 02/14] eeprom: at24: move at24_read() below at24_eeprom_write() Bartosz Golaszewski
2016-05-29 21:53 ` [PATCH 03/14] eeprom: at24: coding style fixes Bartosz Golaszewski
2016-05-29 21:53 ` [PATCH 04/14] eeprom: at24: call read/write functions via function pointers Bartosz Golaszewski
2016-05-29 21:53 ` [PATCH 05/14] eeprom: at24: hide the read/write loop behind a macro Bartosz Golaszewski
2016-05-29 21:53 ` [PATCH 06/14] eeprom: at24: split at24_eeprom_read() into specialized functions Bartosz Golaszewski
2016-05-29 21:53 ` [PATCH 07/14] eeprom: at24: split at24_eeprom_write() " Bartosz Golaszewski
2016-05-29 21:53 ` [PATCH 08/14] eeprom: at24: platform_data: use BIT() macro Bartosz Golaszewski
2016-05-29 21:53 ` [PATCH 09/14] eeprom: at24: platform_data: add serial number flag Bartosz Golaszewski
2016-05-29 21:53 ` [PATCH 10/14] eeprom: at24: support reading the serial number Bartosz Golaszewski
2016-05-29 21:53 ` [PATCH 11/14] eeprom: at24: add the at24cs series to the list of supported devices Bartosz Golaszewski
2016-05-29 21:53 ` [PATCH 12/14] eeprom: at24: platform_data: add at24mac series flag Bartosz Golaszewski
2016-05-29 21:53 ` [PATCH 13/14] eeprom: at24: add support for at24mac series Bartosz Golaszewski
2016-05-29 21:53 ` [PATCH 14/14] eeprom: at24: add at24mac chips to the list of supported devices Bartosz Golaszewski
2016-07-06 15:04 ` [PATCH 00/14] eeprom: at24: driver rework and at24cs/at24mac support Bartosz Golaszewski

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).