Re: [PATCH] i2c: eeprom: at24: Provide an EEPROM framework interface

From: Maxime Ripard
Date: Wed May 13 2015 - 16:40:12 EST


Hi Pantelis,

On Wed, May 13, 2015 at 10:38:17AM +0300, Pantelis Antoniou wrote:
> For DT and in-kernel users there is no interface to the
> at24 EEPROMs so provide an EEPROM framework interface.
>
> This allows us to use AT24 based EEPROMs and reference them
> from within the DT tree.
>
> Signed-off-by: Pantelis Antoniou <pantelis.antoniou@xxxxxxxxxxxx>

You should probably mention that the EEPROM framework hasn't been
merged yet.

> ---
> drivers/misc/eeprom/at24.c | 222 +++++++++++++++++++++++++++++++++++----------
> 1 file changed, 174 insertions(+), 48 deletions(-)
>
> diff --git a/drivers/misc/eeprom/at24.c b/drivers/misc/eeprom/at24.c
> index 2d3db81..afa719a 100644
> --- a/drivers/misc/eeprom/at24.c
> +++ b/drivers/misc/eeprom/at24.c
> @@ -3,6 +3,7 @@
> *
> * Copyright (C) 2005-2007 David Brownell
> * Copyright (C) 2008 Wolfram Sang, Pengutronix
> + * Copyright (C) 2015 Pantelis Antoniou, Konsulko Group
> *
> * 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
> @@ -23,6 +24,9 @@
> #include <linux/of.h>
> #include <linux/i2c.h>
> #include <linux/platform_data/at24.h>
> +#include <linux/regmap.h>
> +#include <linux/eeprom-provider.h>
> +#include <linux/io.h>
>
> /*
> * I2C EEPROMs from most vendors are inexpensive and mostly interchangeable.
> @@ -63,12 +67,16 @@ struct at24_data {
> * but not from changes by other I2C masters.
> */
> struct mutex lock;
> - struct bin_attribute bin;
>
> u8 *writebuf;
> unsigned write_max;
> unsigned num_addresses;
>
> + struct regmap_config *regmap_config;
> + struct regmap *regmap;
> + struct eeprom_config *eeprom_config;
> + struct eeprom_device *eeprom_dev;
> +
> /*
> * Some chips tie up multiple I2C addresses; dummy devices reserve
> * them for us, and we'll use them with SMBus calls.
> @@ -131,6 +139,8 @@ static const struct i2c_device_id at24_ids[] = {
> };
> MODULE_DEVICE_TABLE(i2c, at24_ids);
>
> +static DEFINE_IDA(at24_ida);
> +
> /*-------------------------------------------------------------------------*/
>
> /*
> @@ -301,17 +311,6 @@ static ssize_t at24_read(struct at24_data *at24,
> 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
> @@ -432,21 +431,10 @@ static ssize_t at24_write(struct at24_data *at24, const char *buf, loff_t off,
> 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;
> -
> - if (unlikely(off >= attr->size))
> - return -EFBIG;
> -
> - at24 = dev_get_drvdata(container_of(kobj, struct device, kobj));
> - return at24_write(at24, buf, off, count);
> -}
> -
> /*-------------------------------------------------------------------------*/
>
> +/* panto: using the EEPROM framework macc is superfluous */
> +

Is it? it was kind of one of the point to be able to remove the memory
accessors stuff (which is only used by that driver btw).

> /*
> * This lets other kernel code access the eeprom data. For example, it
> * might hold a board's Ethernet address, or board-specific calibration
> @@ -492,6 +480,91 @@ static void at24_get_ofdata(struct i2c_client *client,
> { }
> #endif /* CONFIG_OF */
>
> +static int regmap_at24_read(void *context,
> + const void *reg, size_t reg_size,
> + void *val, size_t val_size)
> +{
> + struct i2c_client *client = context;
> + struct at24_data *at24;
> + unsigned int offset;
> + int ret;
> +
> + /* reg bits is hardcoded to 32 bits */
> + BUG_ON(reg_size != 4);
> + offset = __raw_readl(reg);
> +
> + at24 = i2c_get_clientdata(client);
> + if (at24 == NULL)
> + return -ENODEV;
> +
> + /* val bytes is always 1 */
> + BUG_ON(at24->regmap_config->val_bits != 8);
> +
> + ret = at24_read(at24, val, offset, val_size);
> + if (ret < 0)
> + return ret;
> + if (ret != val_size)
> + return -EINVAL;
> +
> + return 0;
> +}
> +
> +static int regmap_at24_gather_write(void *context,
> + const void *reg, size_t reg_size,
> + const void *val, size_t val_size)
> +{
> + struct i2c_client *client = context;
> + struct at24_data *at24;
> + unsigned int offset;
> + int ret;
> +
> + at24 = i2c_get_clientdata(client);
> + if (at24 == NULL)
> + return -ENODEV;
> +
> + BUG_ON(reg_size != 4);
> + offset = __raw_readl(reg);
> +
> + /* val bytes is always 1 */
> + BUG_ON(at24->regmap_config->val_bits != 8);
> +
> + ret = at24_write(at24, val, offset, val_size);
> + if (ret < 0)
> + return ret;
> + if (ret != val_size)
> + return -EINVAL;
> +
> + return 0;
> +}
> +
> +static int regmap_at24_write(void *context, const void *data, size_t count)
> +{
> + struct i2c_client *client = context;
> + struct at24_data *at24;
> + unsigned int reg_bytes, offset;
> +
> + at24 = i2c_get_clientdata(client);
> + if (at24 == NULL)
> + return -ENODEV;
> +
> + reg_bytes = at24->regmap_config->reg_bits / 8;
> + offset = reg_bytes;
> +
> + BUG_ON(reg_bytes != 4);
> + BUG_ON(count <= offset);
> +
> + return regmap_at24_gather_write(context, data, reg_bytes,
> + data + offset, count - offset);
> +}
> +
> +static struct regmap_bus regmap_at24_bus = {
> + .read = regmap_at24_read,
> + .write = regmap_at24_write,
> + .gather_write = regmap_at24_gather_write,
> + .reg_format_endian_default = REGMAP_ENDIAN_NATIVE,
> + .val_format_endian_default = REGMAP_ENDIAN_NATIVE,

I wouldn't expect the content of the EEPROM to change of endianness
when we change the kernel's.

Maxime

--
Maxime Ripard, Free Electrons
Embedded Linux, Kernel and Android engineering
http://free-electrons.com

Attachment: signature.asc
Description: Digital signature