i2c: rcar: add HostNotify support

The I2C core can now utilize a slave interface to handle SMBus
HostNotify events. Enable it in this driver.

Signed-off-by: Wolfram Sang <wsa+renesas@sang-engineering.com>
Signed-off-by: Wolfram Sang <wsa@kernel.org>
This commit is contained in:
Wolfram Sang
2020-09-10 11:11:18 +02:00
committed by Wolfram Sang
parent a8335c64c5
commit c4651f11d0
2 changed files with 29 additions and 3 deletions

View File

@ -1181,6 +1181,7 @@ config I2C_RCAR
tristate "Renesas R-Car I2C Controller" tristate "Renesas R-Car I2C Controller"
depends on ARCH_RENESAS || COMPILE_TEST depends on ARCH_RENESAS || COMPILE_TEST
select I2C_SLAVE select I2C_SLAVE
select I2C_SMBUS
select RESET_CONTROLLER if ARCH_RCAR_GEN3 select RESET_CONTROLLER if ARCH_RCAR_GEN3
help help
If you say yes to this option, support will be included for the If you say yes to this option, support will be included for the

View File

@ -21,6 +21,7 @@
#include <linux/io.h> #include <linux/io.h>
#include <linux/iopoll.h> #include <linux/iopoll.h>
#include <linux/i2c.h> #include <linux/i2c.h>
#include <linux/i2c-smbus.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/of_device.h> #include <linux/of_device.h>
@ -106,10 +107,11 @@
#define ID_ARBLOST (1 << 3) #define ID_ARBLOST (1 << 3)
#define ID_NACK (1 << 4) #define ID_NACK (1 << 4)
/* persistent flags */ /* persistent flags */
#define ID_P_HOST_NOTIFY BIT(28)
#define ID_P_REP_AFTER_RD BIT(29) #define ID_P_REP_AFTER_RD BIT(29)
#define ID_P_NO_RXDMA BIT(30) /* HW forbids RXDMA sometimes */ #define ID_P_NO_RXDMA BIT(30) /* HW forbids RXDMA sometimes */
#define ID_P_PM_BLOCKED BIT(31) #define ID_P_PM_BLOCKED BIT(31)
#define ID_P_MASK GENMASK(31, 29) #define ID_P_MASK GENMASK(31, 28)
enum rcar_i2c_type { enum rcar_i2c_type {
I2C_RCAR_GEN1, I2C_RCAR_GEN1,
@ -141,6 +143,8 @@ struct rcar_i2c_priv {
struct reset_control *rstc; struct reset_control *rstc;
int irq; int irq;
struct i2c_client *host_notify_client;
}; };
#define rcar_i2c_priv_to_dev(p) ((p)->adap.dev.parent) #define rcar_i2c_priv_to_dev(p) ((p)->adap.dev.parent)
@ -875,14 +879,21 @@ static int rcar_unreg_slave(struct i2c_client *slave)
static u32 rcar_i2c_func(struct i2c_adapter *adap) static u32 rcar_i2c_func(struct i2c_adapter *adap)
{ {
struct rcar_i2c_priv *priv = i2c_get_adapdata(adap);
/* /*
* This HW can't do: * This HW can't do:
* I2C_SMBUS_QUICK (setting FSB during START didn't work) * I2C_SMBUS_QUICK (setting FSB during START didn't work)
* I2C_M_NOSTART (automatically sends address after START) * I2C_M_NOSTART (automatically sends address after START)
* I2C_M_IGNORE_NAK (automatically sends STOP after NAK) * I2C_M_IGNORE_NAK (automatically sends STOP after NAK)
*/ */
return I2C_FUNC_I2C | I2C_FUNC_SLAVE | u32 func = I2C_FUNC_I2C | I2C_FUNC_SLAVE |
(I2C_FUNC_SMBUS_EMUL & ~I2C_FUNC_SMBUS_QUICK); (I2C_FUNC_SMBUS_EMUL & ~I2C_FUNC_SMBUS_QUICK);
if (priv->flags & ID_P_HOST_NOTIFY)
func |= I2C_FUNC_SMBUS_HOST_NOTIFY;
return func;
} }
static const struct i2c_algorithm rcar_i2c_algo = { static const struct i2c_algorithm rcar_i2c_algo = {
@ -982,6 +993,8 @@ static int rcar_i2c_probe(struct platform_device *pdev)
else else
pm_runtime_put(dev); pm_runtime_put(dev);
if (of_property_read_bool(dev->of_node, "smbus"))
priv->flags |= ID_P_HOST_NOTIFY;
priv->irq = platform_get_irq(pdev, 0); priv->irq = platform_get_irq(pdev, 0);
ret = devm_request_irq(dev, priv->irq, rcar_i2c_irq, 0, dev_name(dev), priv); ret = devm_request_irq(dev, priv->irq, rcar_i2c_irq, 0, dev_name(dev), priv);
@ -996,10 +1009,20 @@ static int rcar_i2c_probe(struct platform_device *pdev)
if (ret < 0) if (ret < 0)
goto out_pm_disable; goto out_pm_disable;
if (priv->flags & ID_P_HOST_NOTIFY) {
priv->host_notify_client = i2c_new_slave_host_notify_device(adap);
if (IS_ERR(priv->host_notify_client)) {
ret = PTR_ERR(priv->host_notify_client);
goto out_del_device;
}
}
dev_info(dev, "probed\n"); dev_info(dev, "probed\n");
return 0; return 0;
out_del_device:
i2c_del_adapter(&priv->adap);
out_pm_put: out_pm_put:
pm_runtime_put(dev); pm_runtime_put(dev);
out_pm_disable: out_pm_disable:
@ -1012,6 +1035,8 @@ static int rcar_i2c_remove(struct platform_device *pdev)
struct rcar_i2c_priv *priv = platform_get_drvdata(pdev); struct rcar_i2c_priv *priv = platform_get_drvdata(pdev);
struct device *dev = &pdev->dev; struct device *dev = &pdev->dev;
if (priv->host_notify_client)
i2c_free_slave_host_notify_device(priv->host_notify_client);
i2c_del_adapter(&priv->adap); i2c_del_adapter(&priv->adap);
rcar_i2c_release_dma(priv); rcar_i2c_release_dma(priv);
if (priv->flags & ID_P_PM_BLOCKED) if (priv->flags & ID_P_PM_BLOCKED)