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

Commit 5c015258 authored by Heiner Kallweit's avatar Heiner Kallweit Committed by Bartosz Golaszewski
Browse files

eeprom: at24: add basic regmap_i2c support



This patch adds basic regmap support to be used by subsequent
patches of this series.

Signed-off-by: default avatarHeiner Kallweit <hkallweit1@gmail.com>
Signed-off-by: default avatarBartosz Golaszewski <brgl@bgdev.pl>
parent 30a7acd5
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -4,6 +4,7 @@ config EEPROM_AT24
	tristate "I2C EEPROMs / RAMs / ROMs from most vendors"
	depends on I2C && SYSFS
	select NVMEM
	select REGMAP_I2C
	help
	  Enable this driver to get read/write support to most I2C EEPROMs
	  and compatible devices like FRAMs, SRAMs, ROMs etc. After you
+44 −13
Original line number Diff line number Diff line
@@ -24,6 +24,7 @@
#include <linux/acpi.h>
#include <linux/i2c.h>
#include <linux/nvmem-provider.h>
#include <linux/regmap.h>
#include <linux/platform_data/at24.h>
#include <linux/pm_runtime.h>

@@ -55,6 +56,11 @@
 * which won't work on pure SMBus systems.
 */

struct at24_client {
	struct i2c_client *client;
	struct regmap *regmap;
};

struct at24_data {
	struct at24_platform_data chip;
	int use_smbus;
@@ -81,7 +87,7 @@ struct at24_data {
	 * 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[];
	struct at24_client client[];
};

/*
@@ -274,7 +280,7 @@ static struct i2c_client *at24_translate_offset(struct at24_data *at24,
		*offset &= 0xff;
	}

	return at24->client[i];
	return at24->client[i].client;
}

static ssize_t at24_eeprom_read_smbus(struct at24_data *at24, char *buf,
@@ -562,7 +568,7 @@ static ssize_t at24_eeprom_write_i2c(struct at24_data *at24, const char *buf,
static int at24_read(void *priv, unsigned int off, void *val, size_t count)
{
	struct at24_data *at24 = priv;
	struct device *dev = &at24->client[0]->dev;
	struct device *dev = &at24->client[0].client->dev;
	char *buf = val;
	int ret;

@@ -608,7 +614,7 @@ static int at24_read(void *priv, unsigned int off, void *val, size_t count)
static int at24_write(void *priv, unsigned int off, void *val, size_t count)
{
	struct at24_data *at24 = priv;
	struct device *dev = &at24->client[0]->dev;
	struct device *dev = &at24->client[0].client->dev;
	char *buf = val;
	int ret;

@@ -676,6 +682,16 @@ static void at24_get_pdata(struct device *dev, struct at24_platform_data *chip)
	}
}

static const struct regmap_config regmap_config_8 = {
	.reg_bits = 8,
	.val_bits = 8,
};

static const struct regmap_config regmap_config_16 = {
	.reg_bits = 16,
	.val_bits = 8,
};

static int at24_probe(struct i2c_client *client, const struct i2c_device_id *id)
{
	struct at24_platform_data chip;
@@ -686,6 +702,7 @@ static int at24_probe(struct i2c_client *client, const struct i2c_device_id *id)
	struct at24_data *at24;
	int err;
	unsigned i, num_addresses;
	const struct regmap_config *config;
	u8 test_byte;

	if (client->dev.platform_data) {
@@ -777,8 +794,13 @@ static int at24_probe(struct i2c_client *client, const struct i2c_device_id *id)
		num_addresses =	DIV_ROUND_UP(chip.byte_len,
			(chip.flags & AT24_FLAG_ADDR16) ? 65536 : 256);

	if (chip.flags & AT24_FLAG_ADDR16)
		config = &regmap_config_16;
	else
		config = &regmap_config_8;

	at24 = devm_kzalloc(&client->dev, sizeof(struct at24_data) +
		num_addresses * sizeof(struct i2c_client *), GFP_KERNEL);
		num_addresses * sizeof(struct at24_client), GFP_KERNEL);
	if (!at24)
		return -ENOMEM;

@@ -788,6 +810,11 @@ static int at24_probe(struct i2c_client *client, const struct i2c_device_id *id)
	at24->chip = chip;
	at24->num_addresses = num_addresses;

	at24->client[0].client = client;
	at24->client[0].regmap = devm_regmap_init_i2c(client, config);
	if (IS_ERR(at24->client[0].regmap))
		return PTR_ERR(at24->client[0].regmap);

	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.");
@@ -835,18 +862,22 @@ static int at24_probe(struct i2c_client *client, const struct i2c_device_id *id)
		}
	}

	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,
		at24->client[i].client = i2c_new_dummy(client->adapter,
						       client->addr + i);
		if (!at24->client[i]) {
		if (!at24->client[i].client) {
			dev_err(&client->dev, "address 0x%02x unavailable\n",
					client->addr + i);
			err = -EADDRINUSE;
			goto err_clients;
		}
		at24->client[i].regmap = devm_regmap_init_i2c(
					at24->client[i].client, config);
		if (IS_ERR(at24->client[i].regmap)) {
			err = PTR_ERR(at24->client[i].regmap);
			goto err_clients;
		}
	}

	i2c_set_clientdata(client, at24);
@@ -905,8 +936,8 @@ static int at24_probe(struct i2c_client *client, const struct i2c_device_id *id)

err_clients:
	for (i = 1; i < num_addresses; i++)
		if (at24->client[i])
			i2c_unregister_device(at24->client[i]);
		if (at24->client[i].client)
			i2c_unregister_device(at24->client[i].client);

	pm_runtime_disable(&client->dev);

@@ -923,7 +954,7 @@ static int at24_remove(struct i2c_client *client)
	nvmem_unregister(at24->nvmem);

	for (i = 1; i < at24->num_addresses; i++)
		i2c_unregister_device(at24->client[i]);
		i2c_unregister_device(at24->client[i].client);

	pm_runtime_disable(&client->dev);
	pm_runtime_set_suspended(&client->dev);