Commit 6810df46 authored by Wolfram Sang's avatar Wolfram Sang
Browse files

Merge tag 'at24-updates-for-v5.6' of...

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
parents 878508ae cd5676db
Loading
Loading
Loading
Loading
+5 −4
Original line number Diff line number Diff line
@@ -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
+2 −0
Original line number Diff line number Diff line
@@ -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>;
+11 −0
Original line number Diff line number Diff line
@@ -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>;

          /* ... */

+51 −21
Original line number Diff line number Diff line
// 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),
	},
+17 −2
Original line number Diff line number Diff line
@@ -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);
Loading