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: Heiner Kallweit <hkallweit1@gmail.com>
Signed-off-by: Bartosz Golaszewski <brgl@bgdev.pl>
This commit is contained in:
Heiner Kallweit 2017-11-28 21:51:40 +01:00 committed by Bartosz Golaszewski
parent 30a7acd573
commit 5c01525847
2 changed files with 45 additions and 13 deletions

View File

@ -4,6 +4,7 @@ config EEPROM_AT24
tristate "I2C EEPROMs / RAMs / ROMs from most vendors" tristate "I2C EEPROMs / RAMs / ROMs from most vendors"
depends on I2C && SYSFS depends on I2C && SYSFS
select NVMEM select NVMEM
select REGMAP_I2C
help help
Enable this driver to get read/write support to most I2C EEPROMs Enable this driver to get read/write support to most I2C EEPROMs
and compatible devices like FRAMs, SRAMs, ROMs etc. After you and compatible devices like FRAMs, SRAMs, ROMs etc. After you

View File

@ -24,6 +24,7 @@
#include <linux/acpi.h> #include <linux/acpi.h>
#include <linux/i2c.h> #include <linux/i2c.h>
#include <linux/nvmem-provider.h> #include <linux/nvmem-provider.h>
#include <linux/regmap.h>
#include <linux/platform_data/at24.h> #include <linux/platform_data/at24.h>
#include <linux/pm_runtime.h> #include <linux/pm_runtime.h>
@ -55,6 +56,11 @@
* which won't work on pure SMBus systems. * which won't work on pure SMBus systems.
*/ */
struct at24_client {
struct i2c_client *client;
struct regmap *regmap;
};
struct at24_data { struct at24_data {
struct at24_platform_data chip; struct at24_platform_data chip;
int use_smbus; int use_smbus;
@ -81,7 +87,7 @@ struct at24_data {
* Some chips tie up multiple I2C addresses; dummy devices reserve * Some chips tie up multiple I2C addresses; dummy devices reserve
* them for us, and we'll use them with SMBus calls. * 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; *offset &= 0xff;
} }
return at24->client[i]; return at24->client[i].client;
} }
static ssize_t at24_eeprom_read_smbus(struct at24_data *at24, char *buf, 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) static int at24_read(void *priv, unsigned int off, void *val, size_t count)
{ {
struct at24_data *at24 = priv; struct at24_data *at24 = priv;
struct device *dev = &at24->client[0]->dev; struct device *dev = &at24->client[0].client->dev;
char *buf = val; char *buf = val;
int ret; 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) static int at24_write(void *priv, unsigned int off, void *val, size_t count)
{ {
struct at24_data *at24 = priv; struct at24_data *at24 = priv;
struct device *dev = &at24->client[0]->dev; struct device *dev = &at24->client[0].client->dev;
char *buf = val; char *buf = val;
int ret; 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) static int at24_probe(struct i2c_client *client, const struct i2c_device_id *id)
{ {
struct at24_platform_data chip; 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; struct at24_data *at24;
int err; int err;
unsigned i, num_addresses; unsigned i, num_addresses;
const struct regmap_config *config;
u8 test_byte; u8 test_byte;
if (client->dev.platform_data) { 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, num_addresses = DIV_ROUND_UP(chip.byte_len,
(chip.flags & AT24_FLAG_ADDR16) ? 65536 : 256); (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) + 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) if (!at24)
return -ENOMEM; return -ENOMEM;
@ -788,6 +810,11 @@ static int at24_probe(struct i2c_client *client, const struct i2c_device_id *id)
at24->chip = chip; at24->chip = chip;
at24->num_addresses = num_addresses; 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)) { if ((chip.flags & AT24_FLAG_SERIAL) && (chip.flags & AT24_FLAG_MAC)) {
dev_err(&client->dev, dev_err(&client->dev,
"invalid device data - cannot have both AT24_FLAG_SERIAL & AT24_FLAG_MAC."); "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 */ /* use dummy devices for multiple-address chips */
for (i = 1; i < num_addresses; i++) { 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); client->addr + i);
if (!at24->client[i]) { if (!at24->client[i].client) {
dev_err(&client->dev, "address 0x%02x unavailable\n", dev_err(&client->dev, "address 0x%02x unavailable\n",
client->addr + i); client->addr + i);
err = -EADDRINUSE; err = -EADDRINUSE;
goto err_clients; 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); 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: err_clients:
for (i = 1; i < num_addresses; i++) for (i = 1; i < num_addresses; i++)
if (at24->client[i]) if (at24->client[i].client)
i2c_unregister_device(at24->client[i]); i2c_unregister_device(at24->client[i].client);
pm_runtime_disable(&client->dev); pm_runtime_disable(&client->dev);
@ -923,7 +954,7 @@ static int at24_remove(struct i2c_client *client)
nvmem_unregister(at24->nvmem); nvmem_unregister(at24->nvmem);
for (i = 1; i < at24->num_addresses; i++) 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_disable(&client->dev);
pm_runtime_set_suspended(&client->dev); pm_runtime_set_suspended(&client->dev);