diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2017-11-14 17:52:21 -0800 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2017-11-14 17:52:21 -0800 |
commit | 4008e6a9bcee2f3b61bb11951de0fb0ed764cb91 (patch) | |
tree | e7e3202d6d156acb57845a1824c9a8249f288c53 /drivers/misc/eeprom | |
parent | 6aa2f9441f1ef21f10c41f45e6453b135e9cd736 (diff) | |
parent | d82e99a6f9b38cb1a044b4cd979bd49fd3f67cd2 (diff) |
Merge branch 'i2c/for-4.15' of ssh://gitolite.kernel.org/pub/scm/linux/kernel/git/wsa/linux
Pull i2c updates from Wolfram Sang:
"This contains two bigger than usual tree-wide changes this time. They
all have proper acks, caused no merge conflicts in linux-next where
they have been for a while. They are namely:
- to-gpiod conversion of the i2c-gpio driver and its users (touching
arch/* and drivers/mfd/*)
- adding a sbs-manager based on I2C core updates to SMBus alerts
(touching drivers/power/*)
Other notable changes:
- i2c_boardinfo can now carry a dev_name to be used when the device
is created. This is because some devices in ACPI world need fixed
names to find the regulators.
- the designware driver got a long discussed overhaul of its PM
handling. img-scb and davinci got PM support, too.
- at24 driver has way better OF support. And it has a new maintainer.
Thanks Bartosz for stepping up!
The rest is regular driver updates and fixes"
* 'i2c/for-4.15' of ssh://gitolite.kernel.org/pub/scm/linux/kernel/git/wsa/linux: (55 commits)
ARM: sa1100: simpad: Correct I2C GPIO offsets
i2c: aspeed: Deassert reset in probe
eeprom: at24: Add OF device ID table
MAINTAINERS: new maintainer for AT24 driver
i2c: nuc900: remove platform_data, too
i2c: thunderx: Remove duplicate NULL check
i2c: taos-evm: Remove duplicate NULL check
i2c: Make i2c_unregister_device() NULL-aware
i2c: xgene-slimpro: Support v2
i2c: mpc: remove useless variable initialization
i2c: omap: Trigger bus recovery in lockup case
i2c: gpio: Add support for named gpios in DT
dt-bindings: i2c: i2c-gpio: Add support for named gpios
i2c: gpio: Local vars in probe
i2c: gpio: Augment all boardfiles to use open drain
i2c: gpio: Enforce open drain through gpiolib
gpio: Make it possible for consumers to enforce open drain
i2c: gpio: Convert to use descriptors
power: supply: sbs-message: fix some code style issues
power: supply: sbs-battery: remove unchecked return var
...
Diffstat (limited to 'drivers/misc/eeprom')
-rw-r--r-- | drivers/misc/eeprom/at24.c | 112 |
1 files changed, 111 insertions, 1 deletions
diff --git a/drivers/misc/eeprom/at24.c b/drivers/misc/eeprom/at24.c index 764ff5df0dbc..e0b4b36ef010 100644 --- a/drivers/misc/eeprom/at24.c +++ b/drivers/misc/eeprom/at24.c @@ -12,6 +12,7 @@ #include <linux/kernel.h> #include <linux/init.h> #include <linux/module.h> +#include <linux/of_device.h> #include <linux/slab.h> #include <linux/delay.h> #include <linux/mutex.h> @@ -24,6 +25,7 @@ #include <linux/i2c.h> #include <linux/nvmem-provider.h> #include <linux/platform_data/at24.h> +#include <linux/pm_runtime.h> /* * I2C EEPROMs from most vendors are inexpensive and mostly interchangeable. @@ -175,6 +177,64 @@ static const struct i2c_device_id at24_ids[] = { }; MODULE_DEVICE_TABLE(i2c, at24_ids); +static const struct of_device_id at24_of_match[] = { + { + .compatible = "atmel,24c00", + .data = (void *)AT24_DEVICE_MAGIC(128 / 8, AT24_FLAG_TAKE8ADDR) + }, + { + .compatible = "atmel,24c01", + .data = (void *)AT24_DEVICE_MAGIC(1024 / 8, 0) + }, + { + .compatible = "atmel,24c02", + .data = (void *)AT24_DEVICE_MAGIC(2048 / 8, 0) + }, + { + .compatible = "atmel,spd", + .data = (void *)AT24_DEVICE_MAGIC(2048 / 8, + AT24_FLAG_READONLY | AT24_FLAG_IRUGO) + }, + { + .compatible = "atmel,24c04", + .data = (void *)AT24_DEVICE_MAGIC(4096 / 8, 0) + }, + { + .compatible = "atmel,24c08", + .data = (void *)AT24_DEVICE_MAGIC(8192 / 8, 0) + }, + { + .compatible = "atmel,24c16", + .data = (void *)AT24_DEVICE_MAGIC(16384 / 8, 0) + }, + { + .compatible = "atmel,24c32", + .data = (void *)AT24_DEVICE_MAGIC(32768 / 8, AT24_FLAG_ADDR16) + }, + { + .compatible = "atmel,24c64", + .data = (void *)AT24_DEVICE_MAGIC(65536 / 8, AT24_FLAG_ADDR16) + }, + { + .compatible = "atmel,24c128", + .data = (void *)AT24_DEVICE_MAGIC(131072 / 8, AT24_FLAG_ADDR16) + }, + { + .compatible = "atmel,24c256", + .data = (void *)AT24_DEVICE_MAGIC(262144 / 8, AT24_FLAG_ADDR16) + }, + { + .compatible = "atmel,24c512", + .data = (void *)AT24_DEVICE_MAGIC(524288 / 8, AT24_FLAG_ADDR16) + }, + { + .compatible = "atmel,24c1024", + .data = (void *)AT24_DEVICE_MAGIC(1048576 / 8, AT24_FLAG_ADDR16) + }, + { }, +}; +MODULE_DEVICE_TABLE(of, at24_of_match); + static const struct acpi_device_id at24_acpi_ids[] = { { "INT3499", AT24_DEVICE_MAGIC(8192 / 8, 0) }, { } @@ -501,11 +561,21 @@ 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 i2c_client *client; char *buf = val; + int ret; if (unlikely(!count)) return count; + client = at24_translate_offset(at24, &off); + + ret = pm_runtime_get_sync(&client->dev); + if (ret < 0) { + pm_runtime_put_noidle(&client->dev); + return ret; + } + /* * Read data from chip, protecting against concurrent updates * from this host, but not from other I2C masters. @@ -518,6 +588,7 @@ static int at24_read(void *priv, unsigned int off, void *val, size_t count) status = at24->read_func(at24, buf, off, count); if (status < 0) { mutex_unlock(&at24->lock); + pm_runtime_put(&client->dev); return status; } buf += status; @@ -527,17 +598,29 @@ static int at24_read(void *priv, unsigned int off, void *val, size_t count) mutex_unlock(&at24->lock); + pm_runtime_put(&client->dev); + return 0; } static int at24_write(void *priv, unsigned int off, void *val, size_t count) { struct at24_data *at24 = priv; + struct i2c_client *client; char *buf = val; + int ret; if (unlikely(!count)) return -EINVAL; + client = at24_translate_offset(at24, &off); + + ret = pm_runtime_get_sync(&client->dev); + if (ret < 0) { + pm_runtime_put_noidle(&client->dev); + return ret; + } + /* * Write data to chip, protecting against concurrent updates * from this host, but not from other I2C masters. @@ -550,6 +633,7 @@ static int at24_write(void *priv, unsigned int off, void *val, size_t count) status = at24->write_func(at24, buf, off, count); if (status < 0) { mutex_unlock(&at24->lock); + pm_runtime_put(&client->dev); return status; } buf += status; @@ -559,6 +643,8 @@ static int at24_write(void *priv, unsigned int off, void *val, size_t count) mutex_unlock(&at24->lock); + pm_runtime_put(&client->dev); + return 0; } @@ -570,6 +656,10 @@ static void at24_get_pdata(struct device *dev, struct at24_platform_data *chip) if (device_property_present(dev, "read-only")) chip->flags |= AT24_FLAG_READONLY; + err = device_property_read_u32(dev, "size", &val); + if (!err) + chip->byte_len = val; + err = device_property_read_u32(dev, "pagesize", &val); if (!err) { chip->page_size = val; @@ -598,7 +688,16 @@ static int at24_probe(struct i2c_client *client, const struct i2c_device_id *id) if (client->dev.platform_data) { chip = *(struct at24_platform_data *)client->dev.platform_data; } else { - if (id) { + /* + * The I2C core allows OF nodes compatibles to match against the + * I2C device ID table as a fallback, so check not only if an OF + * node is present but also if it matches an OF device ID entry. + */ + if (client->dev.of_node && + of_match_device(at24_of_match, &client->dev)) { + magic = (kernel_ulong_t) + of_device_get_match_data(&client->dev); + } else if (id) { magic = id->driver_data; } else { const struct acpi_device_id *aid; @@ -739,11 +838,16 @@ static int at24_probe(struct i2c_client *client, const struct i2c_device_id *id) i2c_set_clientdata(client, at24); + /* enable runtime pm */ + pm_runtime_set_active(&client->dev); + pm_runtime_enable(&client->dev); + /* * Perform a one-byte test read to verify that the * chip is functional. */ err = at24_read(at24, 0, &test_byte, 1); + pm_runtime_idle(&client->dev); if (err) { err = -ENODEV; goto err_clients; @@ -791,6 +895,8 @@ err_clients: if (at24->client[i]) i2c_unregister_device(at24->client[i]); + pm_runtime_disable(&client->dev); + return err; } @@ -806,6 +912,9 @@ static int at24_remove(struct i2c_client *client) for (i = 1; i < at24->num_addresses; i++) i2c_unregister_device(at24->client[i]); + pm_runtime_disable(&client->dev); + pm_runtime_set_suspended(&client->dev); + return 0; } @@ -814,6 +923,7 @@ static int at24_remove(struct i2c_client *client) static struct i2c_driver at24_driver = { .driver = { .name = "at24", + .of_match_table = at24_of_match, .acpi_match_table = ACPI_PTR(at24_acpi_ids), }, .probe = at24_probe, |