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 -----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEEFp3rbAvDxGAT0sefEacuoBRx13IFAl4rHlAACgkQEacuoBRx 13J9Ug//dprb3sJZDiFrktJBVgCJ8+6l88gXwrkTNDGXGnrE3W4YGA12YO8NQPFR hGHLegV+LZCSebcxL7iY69UCMMCLQ5cGKUMXfIJqJQfSBV8em1+81DMHSFh0kJPn jVgPo4JAqq0JJPuXz7YQnqtJtksSsBVvxbglm7dSXpF61eqnFEO/Xi80IM3uoqSK 1FMgu+2PweH4CYPL272bgwRLFLGyzQaI8EQhCvzov+ye8Z1ctVXUmjojmtZCanTM 1XLTBdwNJKd6ogFpD6YGGBBg53mgANDY4P++DxO7yk7QjhyaculbDPDp43KvJcnO QR7PswnMT+78KmJOtxsShLMUCoaNe7aSgq+luby0Zdb2KwZY/K9gOUN6XbsqppEY qH3pQdzRZ6k8jZL8QWjemZ1g1B4z6qfbR10k0F5yg8bzXDFlpaRja2wFV63YZk6k ld9BHfGss/mR7XztfM4/Tb7Cj5asV6jnX4LGWvK4Va1UZE69QeUKTXYVQIc5v/fB hCzkYPW496Yoh0i785eJMwJ5PgwhYhXK+b/panMibFwGttIMxKf/sKejLeOxsMTv z20awOCCdo1soCcci6YkOrjN1Lj2EViWg/i0oWsV1FxkKUkPzR3fXRrPgSp0zZ7e vKIjU3Ej9QQyuMOxguVm2gB9gj6hB7oTBBlgNb1uQ7Zf1f9Z18Q= =jh24 -----END PGP SIGNATURE----- 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
This commit is contained in:
commit
6810df46c4
|
@ -145,10 +145,7 @@ properties:
|
||||||
over reads to the next slave address. Please consult the manual of
|
over reads to the next slave address. Please consult the manual of
|
||||||
your device.
|
your device.
|
||||||
|
|
||||||
wp-gpios:
|
wp-gpios: true
|
||||||
description:
|
|
||||||
GPIO to which the write-protect pin of the chip is connected.
|
|
||||||
maxItems: 1
|
|
||||||
|
|
||||||
address-width:
|
address-width:
|
||||||
allOf:
|
allOf:
|
||||||
|
@ -167,6 +164,10 @@ properties:
|
||||||
minimum: 1
|
minimum: 1
|
||||||
maximum: 8
|
maximum: 8
|
||||||
|
|
||||||
|
vcc-supply:
|
||||||
|
description:
|
||||||
|
phandle of the regulator that provides the supply voltage.
|
||||||
|
|
||||||
required:
|
required:
|
||||||
- compatible
|
- compatible
|
||||||
- reg
|
- reg
|
||||||
|
|
|
@ -20,6 +20,7 @@ Optional properties:
|
||||||
- spi-cpha : SPI shifted clock phase, as per spi-bus bindings.
|
- spi-cpha : SPI shifted clock phase, as per spi-bus bindings.
|
||||||
- spi-cpol : SPI inverse clock polarity, 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
|
- 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",
|
Obsolete legacy properties can be used in place of "size", "pagesize",
|
||||||
"address-width", and "read-only":
|
"address-width", and "read-only":
|
||||||
|
@ -36,6 +37,7 @@ Example:
|
||||||
spi-max-frequency = <5000000>;
|
spi-max-frequency = <5000000>;
|
||||||
spi-cpha;
|
spi-cpha;
|
||||||
spi-cpol;
|
spi-cpol;
|
||||||
|
wp-gpios = <&gpio1 3 0>;
|
||||||
|
|
||||||
pagesize = <64>;
|
pagesize = <64>;
|
||||||
size = <32768>;
|
size = <32768>;
|
||||||
|
|
|
@ -34,6 +34,14 @@ properties:
|
||||||
description:
|
description:
|
||||||
Mark the provider as read only.
|
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:
|
patternProperties:
|
||||||
"^.*@[0-9a-f]+$":
|
"^.*@[0-9a-f]+$":
|
||||||
type: object
|
type: object
|
||||||
|
@ -63,9 +71,12 @@ patternProperties:
|
||||||
|
|
||||||
examples:
|
examples:
|
||||||
- |
|
- |
|
||||||
|
#include <dt-bindings/gpio/gpio.h>
|
||||||
|
|
||||||
qfprom: eeprom@700000 {
|
qfprom: eeprom@700000 {
|
||||||
#address-cells = <1>;
|
#address-cells = <1>;
|
||||||
#size-cells = <1>;
|
#size-cells = <1>;
|
||||||
|
wp-gpios = <&gpio1 3 GPIO_ACTIVE_HIGH>;
|
||||||
|
|
||||||
/* ... */
|
/* ... */
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
// SPDX-License-Identifier: GPL-2.0+
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
/*
|
/*
|
||||||
* at24.c - handle most I2C EEPROMs
|
* at24.c - handle most I2C EEPROMs
|
||||||
*
|
*
|
||||||
|
@ -6,23 +6,23 @@
|
||||||
* Copyright (C) 2008 Wolfram Sang, Pengutronix
|
* Copyright (C) 2008 Wolfram Sang, Pengutronix
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#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>
|
|
||||||
#include <linux/mod_devicetable.h>
|
|
||||||
#include <linux/bitops.h>
|
|
||||||
#include <linux/jiffies.h>
|
|
||||||
#include <linux/property.h>
|
|
||||||
#include <linux/acpi.h>
|
#include <linux/acpi.h>
|
||||||
|
#include <linux/bitops.h>
|
||||||
|
#include <linux/delay.h>
|
||||||
#include <linux/i2c.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/mutex.h>
|
||||||
#include <linux/nvmem-provider.h>
|
#include <linux/nvmem-provider.h>
|
||||||
#include <linux/regmap.h>
|
#include <linux/of_device.h>
|
||||||
#include <linux/pm_runtime.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. */
|
/* Address pointer is 16 bit. */
|
||||||
#define AT24_FLAG_ADDR16 BIT(7)
|
#define AT24_FLAG_ADDR16 BIT(7)
|
||||||
|
@ -88,8 +88,7 @@ struct at24_data {
|
||||||
u8 flags;
|
u8 flags;
|
||||||
|
|
||||||
struct nvmem_device *nvmem;
|
struct nvmem_device *nvmem;
|
||||||
|
struct regulator *vcc_reg;
|
||||||
struct gpio_desc *wp_gpio;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Some chips tie up multiple I2C addresses; dummy devices reserve
|
* 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.
|
* from this host, but not from other I2C masters.
|
||||||
*/
|
*/
|
||||||
mutex_lock(&at24->lock);
|
mutex_lock(&at24->lock);
|
||||||
gpiod_set_value_cansleep(at24->wp_gpio, 0);
|
|
||||||
|
|
||||||
while (count) {
|
while (count) {
|
||||||
ret = at24_regmap_write(at24, buf, off, count);
|
ret = at24_regmap_write(at24, buf, off, count);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
gpiod_set_value_cansleep(at24->wp_gpio, 1);
|
|
||||||
mutex_unlock(&at24->lock);
|
mutex_unlock(&at24->lock);
|
||||||
pm_runtime_put(dev);
|
pm_runtime_put(dev);
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -472,7 +469,6 @@ static int at24_write(void *priv, unsigned int off, void *val, size_t count)
|
||||||
count -= ret;
|
count -= ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
gpiod_set_value_cansleep(at24->wp_gpio, 1);
|
|
||||||
mutex_unlock(&at24->lock);
|
mutex_unlock(&at24->lock);
|
||||||
|
|
||||||
pm_runtime_put(dev);
|
pm_runtime_put(dev);
|
||||||
|
@ -662,9 +658,9 @@ static int at24_probe(struct i2c_client *client)
|
||||||
at24->client[0].client = client;
|
at24->client[0].client = client;
|
||||||
at24->client[0].regmap = regmap;
|
at24->client[0].regmap = regmap;
|
||||||
|
|
||||||
at24->wp_gpio = devm_gpiod_get_optional(dev, "wp", GPIOD_OUT_HIGH);
|
at24->vcc_reg = devm_regulator_get(dev, "vcc");
|
||||||
if (IS_ERR(at24->wp_gpio))
|
if (IS_ERR(at24->vcc_reg))
|
||||||
return PTR_ERR(at24->wp_gpio);
|
return PTR_ERR(at24->vcc_reg);
|
||||||
|
|
||||||
writable = !(flags & AT24_FLAG_READONLY);
|
writable = !(flags & AT24_FLAG_READONLY);
|
||||||
if (writable) {
|
if (writable) {
|
||||||
|
@ -701,6 +697,12 @@ static int at24_probe(struct i2c_client *client)
|
||||||
|
|
||||||
i2c_set_clientdata(client, at24);
|
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 */
|
/* enable runtime pm */
|
||||||
pm_runtime_set_active(dev);
|
pm_runtime_set_active(dev);
|
||||||
pm_runtime_enable(dev);
|
pm_runtime_enable(dev);
|
||||||
|
@ -713,6 +715,7 @@ static int at24_probe(struct i2c_client *client)
|
||||||
pm_runtime_idle(dev);
|
pm_runtime_idle(dev);
|
||||||
if (err) {
|
if (err) {
|
||||||
pm_runtime_disable(dev);
|
pm_runtime_disable(dev);
|
||||||
|
regulator_disable(at24->vcc_reg);
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -728,15 +731,42 @@ static int at24_probe(struct i2c_client *client)
|
||||||
|
|
||||||
static int at24_remove(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);
|
pm_runtime_disable(&client->dev);
|
||||||
|
if (!pm_runtime_status_suspended(&client->dev))
|
||||||
|
regulator_disable(at24->vcc_reg);
|
||||||
pm_runtime_set_suspended(&client->dev);
|
pm_runtime_set_suspended(&client->dev);
|
||||||
|
|
||||||
return 0;
|
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 = {
|
static struct i2c_driver at24_driver = {
|
||||||
.driver = {
|
.driver = {
|
||||||
.name = "at24",
|
.name = "at24",
|
||||||
|
.pm = &at24_pm_ops,
|
||||||
.of_match_table = at24_of_match,
|
.of_match_table = at24_of_match,
|
||||||
.acpi_match_table = ACPI_PTR(at24_acpi_ids),
|
.acpi_match_table = ACPI_PTR(at24_acpi_ids),
|
||||||
},
|
},
|
||||||
|
|
|
@ -15,6 +15,7 @@
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
#include <linux/nvmem-consumer.h>
|
#include <linux/nvmem-consumer.h>
|
||||||
#include <linux/nvmem-provider.h>
|
#include <linux/nvmem-provider.h>
|
||||||
|
#include <linux/gpio/consumer.h>
|
||||||
#include <linux/of.h>
|
#include <linux/of.h>
|
||||||
#include <linux/slab.h>
|
#include <linux/slab.h>
|
||||||
#include "nvmem.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,
|
static int nvmem_reg_write(struct nvmem_device *nvmem, unsigned int offset,
|
||||||
void *val, size_t bytes)
|
void *val, size_t bytes)
|
||||||
{
|
{
|
||||||
if (nvmem->reg_write)
|
int ret;
|
||||||
return nvmem->reg_write(nvmem->priv, offset, val, bytes);
|
|
||||||
|
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;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
@ -338,6 +345,14 @@ struct nvmem_device *nvmem_register(const struct nvmem_config *config)
|
||||||
kfree(nvmem);
|
kfree(nvmem);
|
||||||
return ERR_PTR(rval);
|
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);
|
kref_init(&nvmem->refcnt);
|
||||||
INIT_LIST_HEAD(&nvmem->cells);
|
INIT_LIST_HEAD(&nvmem->cells);
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
#include <linux/list.h>
|
#include <linux/list.h>
|
||||||
#include <linux/nvmem-consumer.h>
|
#include <linux/nvmem-consumer.h>
|
||||||
#include <linux/nvmem-provider.h>
|
#include <linux/nvmem-provider.h>
|
||||||
|
#include <linux/gpio/consumer.h>
|
||||||
|
|
||||||
struct nvmem_device {
|
struct nvmem_device {
|
||||||
struct module *owner;
|
struct module *owner;
|
||||||
|
@ -26,6 +27,7 @@ struct nvmem_device {
|
||||||
struct list_head cells;
|
struct list_head cells;
|
||||||
nvmem_reg_read_t reg_read;
|
nvmem_reg_read_t reg_read;
|
||||||
nvmem_reg_write_t reg_write;
|
nvmem_reg_write_t reg_write;
|
||||||
|
struct gpio_desc *wp_gpio;
|
||||||
void *priv;
|
void *priv;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -11,6 +11,7 @@
|
||||||
|
|
||||||
#include <linux/err.h>
|
#include <linux/err.h>
|
||||||
#include <linux/errno.h>
|
#include <linux/errno.h>
|
||||||
|
#include <linux/gpio/consumer.h>
|
||||||
|
|
||||||
struct nvmem_device;
|
struct nvmem_device;
|
||||||
struct nvmem_cell_info;
|
struct nvmem_cell_info;
|
||||||
|
@ -45,6 +46,7 @@ enum nvmem_type {
|
||||||
* @word_size: Minimum read/write access granularity.
|
* @word_size: Minimum read/write access granularity.
|
||||||
* @stride: Minimum read/write access stride.
|
* @stride: Minimum read/write access stride.
|
||||||
* @priv: User context passed to read/write callbacks.
|
* @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
|
* 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
|
* no name is specified in its configuration. In such case "<id>" is
|
||||||
|
@ -58,6 +60,7 @@ struct nvmem_config {
|
||||||
const char *name;
|
const char *name;
|
||||||
int id;
|
int id;
|
||||||
struct module *owner;
|
struct module *owner;
|
||||||
|
struct gpio_desc *wp_gpio;
|
||||||
const struct nvmem_cell_info *cells;
|
const struct nvmem_cell_info *cells;
|
||||||
int ncells;
|
int ncells;
|
||||||
enum nvmem_type type;
|
enum nvmem_type type;
|
||||||
|
|
Loading…
Reference in a new issue