summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorWolfram Sang <wsa@the-dreams.de>2020-01-29 21:56:36 +0100
committerWolfram Sang <wsa@the-dreams.de>2020-01-29 21:56:36 +0100
commit6810df46c41879eba8437ab020c7abf5d1db827e (patch)
treea9af691033e81bd6396a63b29a323296df69c2bf
parent878508aed4776a5b08dcc000d33a01a42e3fd07d (diff)
parentcd5676db0574cc1c0b234bc3b17565b07290aa72 (diff)
Merge tag 'at24-updates-for-v5.6' of git://git.kernel.org/pub/scm/linux/kernel/git/brgl/linux into i2c/for-5.6
at24 updates for linux v5.6 - minor maintenance: update the license tag, sort headers - move support for the write-protect pin into nvmem core - add a reference to the new wp-gpios property in nvmem to at25 bindings - add support for regulator and pm_runtime control
-rw-r--r--Documentation/devicetree/bindings/eeprom/at24.yaml9
-rw-r--r--Documentation/devicetree/bindings/eeprom/at25.txt2
-rw-r--r--Documentation/devicetree/bindings/nvmem/nvmem.yaml11
-rw-r--r--drivers/misc/eeprom/at24.c72
-rw-r--r--drivers/nvmem/core.c19
-rw-r--r--drivers/nvmem/nvmem.h2
-rw-r--r--include/linux/nvmem-provider.h3
7 files changed, 91 insertions, 27 deletions
diff --git a/Documentation/devicetree/bindings/eeprom/at24.yaml b/Documentation/devicetree/bindings/eeprom/at24.yaml
index e8778560d966..0f6d8db18d6c 100644
--- a/Documentation/devicetree/bindings/eeprom/at24.yaml
+++ b/Documentation/devicetree/bindings/eeprom/at24.yaml
@@ -145,10 +145,7 @@ properties:
over reads to the next slave address. Please consult the manual of
your device.
- wp-gpios:
- description:
- GPIO to which the write-protect pin of the chip is connected.
- maxItems: 1
+ wp-gpios: true
address-width:
allOf:
@@ -167,6 +164,10 @@ properties:
minimum: 1
maximum: 8
+ vcc-supply:
+ description:
+ phandle of the regulator that provides the supply voltage.
+
required:
- compatible
- reg
diff --git a/Documentation/devicetree/bindings/eeprom/at25.txt b/Documentation/devicetree/bindings/eeprom/at25.txt
index 42577dd113dd..fcacd97abd0a 100644
--- a/Documentation/devicetree/bindings/eeprom/at25.txt
+++ b/Documentation/devicetree/bindings/eeprom/at25.txt
@@ -20,6 +20,7 @@ Optional properties:
- spi-cpha : SPI shifted clock phase, as per spi-bus bindings.
- spi-cpol : SPI inverse clock polarity, as per spi-bus bindings.
- read-only : this parameter-less property disables writes to the eeprom
+- wp-gpios : GPIO to which the write-protect pin of the chip is connected
Obsolete legacy properties can be used in place of "size", "pagesize",
"address-width", and "read-only":
@@ -36,6 +37,7 @@ Example:
spi-max-frequency = <5000000>;
spi-cpha;
spi-cpol;
+ wp-gpios = <&gpio1 3 0>;
pagesize = <64>;
size = <32768>;
diff --git a/Documentation/devicetree/bindings/nvmem/nvmem.yaml b/Documentation/devicetree/bindings/nvmem/nvmem.yaml
index 1c75a059206c..b43c6c65294e 100644
--- a/Documentation/devicetree/bindings/nvmem/nvmem.yaml
+++ b/Documentation/devicetree/bindings/nvmem/nvmem.yaml
@@ -34,6 +34,14 @@ properties:
description:
Mark the provider as read only.
+ wp-gpios:
+ description:
+ GPIO to which the write-protect pin of the chip is connected.
+ The write-protect GPIO is asserted, when it's driven high
+ (logical '1') to block the write operation. It's deasserted,
+ when it's driven low (logical '0') to allow writing.
+ maxItems: 1
+
patternProperties:
"^.*@[0-9a-f]+$":
type: object
@@ -63,9 +71,12 @@ patternProperties:
examples:
- |
+ #include <dt-bindings/gpio/gpio.h>
+
qfprom: eeprom@700000 {
#address-cells = <1>;
#size-cells = <1>;
+ wp-gpios = <&gpio1 3 GPIO_ACTIVE_HIGH>;
/* ... */
diff --git a/drivers/misc/eeprom/at24.c b/drivers/misc/eeprom/at24.c
index 0681d5fdd538..031eb64549af 100644
--- a/drivers/misc/eeprom/at24.c
+++ b/drivers/misc/eeprom/at24.c
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0+
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* at24.c - handle most I2C EEPROMs
*
@@ -6,23 +6,23 @@
* Copyright (C) 2008 Wolfram Sang, Pengutronix
*/
-#include <linux/kernel.h>
+#include <linux/acpi.h>
+#include <linux/bitops.h>
+#include <linux/delay.h>
+#include <linux/i2c.h>
#include <linux/init.h>
+#include <linux/jiffies.h>
+#include <linux/kernel.h>
+#include <linux/mod_devicetable.h>
#include <linux/module.h>
-#include <linux/of_device.h>
-#include <linux/slab.h>
-#include <linux/delay.h>
#include <linux/mutex.h>
-#include <linux/mod_devicetable.h>
-#include <linux/bitops.h>
-#include <linux/jiffies.h>
-#include <linux/property.h>
-#include <linux/acpi.h>
-#include <linux/i2c.h>
#include <linux/nvmem-provider.h>
-#include <linux/regmap.h>
+#include <linux/of_device.h>
#include <linux/pm_runtime.h>
-#include <linux/gpio/consumer.h>
+#include <linux/property.h>
+#include <linux/regmap.h>
+#include <linux/regulator/consumer.h>
+#include <linux/slab.h>
/* Address pointer is 16 bit. */
#define AT24_FLAG_ADDR16 BIT(7)
@@ -88,8 +88,7 @@ struct at24_data {
u8 flags;
struct nvmem_device *nvmem;
-
- struct gpio_desc *wp_gpio;
+ struct regulator *vcc_reg;
/*
* Some chips tie up multiple I2C addresses; dummy devices reserve
@@ -457,12 +456,10 @@ static int at24_write(void *priv, unsigned int off, void *val, size_t count)
* from this host, but not from other I2C masters.
*/
mutex_lock(&at24->lock);
- gpiod_set_value_cansleep(at24->wp_gpio, 0);
while (count) {
ret = at24_regmap_write(at24, buf, off, count);
if (ret < 0) {
- gpiod_set_value_cansleep(at24->wp_gpio, 1);
mutex_unlock(&at24->lock);
pm_runtime_put(dev);
return ret;
@@ -472,7 +469,6 @@ static int at24_write(void *priv, unsigned int off, void *val, size_t count)
count -= ret;
}
- gpiod_set_value_cansleep(at24->wp_gpio, 1);
mutex_unlock(&at24->lock);
pm_runtime_put(dev);
@@ -662,9 +658,9 @@ static int at24_probe(struct i2c_client *client)
at24->client[0].client = client;
at24->client[0].regmap = regmap;
- at24->wp_gpio = devm_gpiod_get_optional(dev, "wp", GPIOD_OUT_HIGH);
- if (IS_ERR(at24->wp_gpio))
- return PTR_ERR(at24->wp_gpio);
+ at24->vcc_reg = devm_regulator_get(dev, "vcc");
+ if (IS_ERR(at24->vcc_reg))
+ return PTR_ERR(at24->vcc_reg);
writable = !(flags & AT24_FLAG_READONLY);
if (writable) {
@@ -701,6 +697,12 @@ static int at24_probe(struct i2c_client *client)
i2c_set_clientdata(client, at24);
+ err = regulator_enable(at24->vcc_reg);
+ if (err) {
+ dev_err(dev, "Failed to enable vcc regulator\n");
+ return err;
+ }
+
/* enable runtime pm */
pm_runtime_set_active(dev);
pm_runtime_enable(dev);
@@ -713,6 +715,7 @@ static int at24_probe(struct i2c_client *client)
pm_runtime_idle(dev);
if (err) {
pm_runtime_disable(dev);
+ regulator_disable(at24->vcc_reg);
return -ENODEV;
}
@@ -728,15 +731,42 @@ static int at24_probe(struct i2c_client *client)
static int at24_remove(struct i2c_client *client)
{
+ struct at24_data *at24 = i2c_get_clientdata(client);
+
pm_runtime_disable(&client->dev);
+ if (!pm_runtime_status_suspended(&client->dev))
+ regulator_disable(at24->vcc_reg);
pm_runtime_set_suspended(&client->dev);
return 0;
}
+static int __maybe_unused at24_suspend(struct device *dev)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct at24_data *at24 = i2c_get_clientdata(client);
+
+ return regulator_disable(at24->vcc_reg);
+}
+
+static int __maybe_unused at24_resume(struct device *dev)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct at24_data *at24 = i2c_get_clientdata(client);
+
+ return regulator_enable(at24->vcc_reg);
+}
+
+static const struct dev_pm_ops at24_pm_ops = {
+ SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
+ pm_runtime_force_resume)
+ SET_RUNTIME_PM_OPS(at24_suspend, at24_resume, NULL)
+};
+
static struct i2c_driver at24_driver = {
.driver = {
.name = "at24",
+ .pm = &at24_pm_ops,
.of_match_table = at24_of_match,
.acpi_match_table = ACPI_PTR(at24_acpi_ids),
},
diff --git a/drivers/nvmem/core.c b/drivers/nvmem/core.c
index 9f1ee9c766ec..408ce702347e 100644
--- a/drivers/nvmem/core.c
+++ b/drivers/nvmem/core.c
@@ -15,6 +15,7 @@
#include <linux/module.h>
#include <linux/nvmem-consumer.h>
#include <linux/nvmem-provider.h>
+#include <linux/gpio/consumer.h>
#include <linux/of.h>
#include <linux/slab.h>
#include "nvmem.h"
@@ -54,8 +55,14 @@ static int nvmem_reg_read(struct nvmem_device *nvmem, unsigned int offset,
static int nvmem_reg_write(struct nvmem_device *nvmem, unsigned int offset,
void *val, size_t bytes)
{
- if (nvmem->reg_write)
- return nvmem->reg_write(nvmem->priv, offset, val, bytes);
+ int ret;
+
+ if (nvmem->reg_write) {
+ gpiod_set_value_cansleep(nvmem->wp_gpio, 0);
+ ret = nvmem->reg_write(nvmem->priv, offset, val, bytes);
+ gpiod_set_value_cansleep(nvmem->wp_gpio, 1);
+ return ret;
+ }
return -EINVAL;
}
@@ -338,6 +345,14 @@ struct nvmem_device *nvmem_register(const struct nvmem_config *config)
kfree(nvmem);
return ERR_PTR(rval);
}
+ if (config->wp_gpio)
+ nvmem->wp_gpio = config->wp_gpio;
+ else
+ nvmem->wp_gpio = gpiod_get_optional(config->dev, "wp",
+ GPIOD_OUT_HIGH);
+ if (IS_ERR(nvmem->wp_gpio))
+ return ERR_CAST(nvmem->wp_gpio);
+
kref_init(&nvmem->refcnt);
INIT_LIST_HEAD(&nvmem->cells);
diff --git a/drivers/nvmem/nvmem.h b/drivers/nvmem/nvmem.h
index eb8ed7121fa3..be0d66d75c8a 100644
--- a/drivers/nvmem/nvmem.h
+++ b/drivers/nvmem/nvmem.h
@@ -9,6 +9,7 @@
#include <linux/list.h>
#include <linux/nvmem-consumer.h>
#include <linux/nvmem-provider.h>
+#include <linux/gpio/consumer.h>
struct nvmem_device {
struct module *owner;
@@ -26,6 +27,7 @@ struct nvmem_device {
struct list_head cells;
nvmem_reg_read_t reg_read;
nvmem_reg_write_t reg_write;
+ struct gpio_desc *wp_gpio;
void *priv;
};
diff --git a/include/linux/nvmem-provider.h b/include/linux/nvmem-provider.h
index fe051323be0a..6d6f8e5d24c9 100644
--- a/include/linux/nvmem-provider.h
+++ b/include/linux/nvmem-provider.h
@@ -11,6 +11,7 @@
#include <linux/err.h>
#include <linux/errno.h>
+#include <linux/gpio/consumer.h>
struct nvmem_device;
struct nvmem_cell_info;
@@ -45,6 +46,7 @@ enum nvmem_type {
* @word_size: Minimum read/write access granularity.
* @stride: Minimum read/write access stride.
* @priv: User context passed to read/write callbacks.
+ * @wp-gpio: Write protect pin
*
* Note: A default "nvmem<id>" name will be assigned to the device if
* no name is specified in its configuration. In such case "<id>" is
@@ -58,6 +60,7 @@ struct nvmem_config {
const char *name;
int id;
struct module *owner;
+ struct gpio_desc *wp_gpio;
const struct nvmem_cell_info *cells;
int ncells;
enum nvmem_type type;