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

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
......@@ -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
......
......@@ -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>;
......
......@@ -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>;
/* ... */
......
// 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),
},
......
......@@ -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);
......
......@@ -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;
};
......
......@@ -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;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment