2019-12-09 10:41:44

by Shubhrajyoti Datta

[permalink] [raw]
Subject: [PATCH 1/4] i2c: cadence: Fix error printing in case of defer

From: Shubhrajyoti Datta <[email protected]>

Do not print error in case of EPROBE_DEFER.

Signed-off-by: Shubhrajyoti Datta <[email protected]>
---
drivers/i2c/busses/i2c-cadence.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/drivers/i2c/busses/i2c-cadence.c b/drivers/i2c/busses/i2c-cadence.c
index 1ffd21a..7b989a2 100644
--- a/drivers/i2c/busses/i2c-cadence.c
+++ b/drivers/i2c/busses/i2c-cadence.c
@@ -924,7 +924,8 @@ static int cdns_i2c_probe(struct platform_device *pdev)

id->clk = devm_clk_get(&pdev->dev, NULL);
if (IS_ERR(id->clk)) {
- dev_err(&pdev->dev, "input clock not found.\n");
+ if (PTR_ERR(id->clk) != -EPROBE_DEFER)
+ dev_err(&pdev->dev, "input clock not found.\n");
return PTR_ERR(id->clk);
}
ret = clk_prepare_enable(id->clk);
--
2.1.1


2019-12-09 10:43:33

by Shubhrajyoti Datta

[permalink] [raw]
Subject: [PATCH 3/4] i2c: cadence: Implement save restore

From: Shubhrajyoti Datta <[email protected]>

Implement save restore for i2c module.
Since we have only a couple of registers
an unconditional restore is done.

Acked-by: Michal Simek <[email protected]>
Signed-off-by: Shubhrajyoti Datta <[email protected]>
Signed-off-by: Michal Simek <[email protected]>
Signed-off-by: Shubhrajyoti Datta <[email protected]>
---
drivers/i2c/busses/i2c-cadence.c | 41 ++++++++++++++++++++++++++--------------
1 file changed, 27 insertions(+), 14 deletions(-)

diff --git a/drivers/i2c/busses/i2c-cadence.c b/drivers/i2c/busses/i2c-cadence.c
index 08427e9..8a2983e 100644
--- a/drivers/i2c/busses/i2c-cadence.c
+++ b/drivers/i2c/busses/i2c-cadence.c
@@ -138,6 +138,7 @@
* @clk: Pointer to struct clk
* @clk_rate_change_nb: Notifier block for clock rate changes
* @quirks: flag for broken hold bit usage in r1p10
+ * @ctrl_reg: Cached value of the control register.
*/
struct cdns_i2c {
struct device *dev;
@@ -158,6 +159,7 @@ struct cdns_i2c {
struct clk *clk;
struct notifier_block clk_rate_change_nb;
u32 quirks;
+ u32 ctrl_reg;
};

struct cdns_platform_data {
@@ -748,12 +750,11 @@ static int cdns_i2c_setclk(unsigned long clk_in, struct cdns_i2c *id)
if (ret)
return ret;

- ctrl_reg = cdns_i2c_readreg(CDNS_I2C_CR_OFFSET);
+ ctrl_reg = id->ctrl_reg;
ctrl_reg &= ~(CDNS_I2C_CR_DIVA_MASK | CDNS_I2C_CR_DIVB_MASK);
ctrl_reg |= ((div_a << CDNS_I2C_CR_DIVA_SHIFT) |
(div_b << CDNS_I2C_CR_DIVB_SHIFT));
- cdns_i2c_writereg(ctrl_reg, CDNS_I2C_CR_OFFSET);
-
+ id->ctrl_reg = ctrl_reg;
return 0;
}

@@ -837,6 +838,26 @@ static int __maybe_unused cdns_i2c_runtime_suspend(struct device *dev)
}

/**
+ * cdns_i2c_init - Controller initialisation
+ * @id: Device private data structure
+ *
+ * Initialise the i2c controller.
+ *
+ */
+static void cdns_i2c_init(struct cdns_i2c *id)
+{
+ cdns_i2c_writereg(id->ctrl_reg, CDNS_I2C_CR_OFFSET);
+ /*
+ * Cadence I2C controller has a bug wherein it generates
+ * invalid read transaction after HW timeout in master receiver mode.
+ * HW timeout is not used by this driver and the interrupt is disabled.
+ * But the feature itself cannot be disabled. Hence maximum value
+ * is written to this register to reduce the chances of error.
+ */
+ cdns_i2c_writereg(CDNS_I2C_TIMEOUT_MAX, CDNS_I2C_TIME_OUT_OFFSET);
+}
+
+/**
* cdns_i2c_runtime_resume - Runtime resume
* @dev: Address of the platform_device structure
*
@@ -854,6 +875,7 @@ static int __maybe_unused cdns_i2c_runtime_resume(struct device *dev)
dev_err(dev, "Cannot enable clock.\n");
return ret;
}
+ cdns_i2c_init(xi2c);

return 0;
}
@@ -947,8 +969,7 @@ static int cdns_i2c_probe(struct platform_device *pdev)
if (ret || (id->i2c_clk > CDNS_I2C_SPEED_MAX))
id->i2c_clk = CDNS_I2C_SPEED_DEFAULT;

- cdns_i2c_writereg(CDNS_I2C_CR_ACK_EN | CDNS_I2C_CR_NEA | CDNS_I2C_CR_MS,
- CDNS_I2C_CR_OFFSET);
+ id->ctrl_reg = CDNS_I2C_CR_ACK_EN | CDNS_I2C_CR_NEA | CDNS_I2C_CR_MS;

ret = cdns_i2c_setclk(id->input_clk, id);
if (ret) {
@@ -963,15 +984,7 @@ static int cdns_i2c_probe(struct platform_device *pdev)
dev_err(&pdev->dev, "cannot get irq %d\n", id->irq);
goto err_clk_dis;
}
-
- /*
- * Cadence I2C controller has a bug wherein it generates
- * invalid read transaction after HW timeout in master receiver mode.
- * HW timeout is not used by this driver and the interrupt is disabled.
- * But the feature itself cannot be disabled. Hence maximum value
- * is written to this register to reduce the chances of error.
- */
- cdns_i2c_writereg(CDNS_I2C_TIMEOUT_MAX, CDNS_I2C_TIME_OUT_OFFSET);
+ cdns_i2c_init(id);

ret = i2c_add_adapter(&id->adap);
if (ret < 0)
--
2.1.1

2019-12-09 10:51:06

by Shubhrajyoti Datta

[permalink] [raw]
Subject: [PATCH 4/4] i2c: cadence: Recover bus after controller reset

From: Chirag Parekh <[email protected]>

This will save from potential lock-up caused when I2c master controller
resets in the middle of transfer and the slave is holding SDA line to
transmit more data.

Signed-off-by: Chirag Parekh <[email protected]>
Signed-off-by: Michal Simek <[email protected]>
Signed-off-by: Nava kishore Manne <[email protected]>
Signed-off-by: Shubhrajyoti Datta <[email protected]>
---
drivers/i2c/busses/i2c-cadence.c | 101 +++++++++++++++++++++++++++++++++++++++
1 file changed, 101 insertions(+)

diff --git a/drivers/i2c/busses/i2c-cadence.c b/drivers/i2c/busses/i2c-cadence.c
index 8a2983e..e11e986 100644
--- a/drivers/i2c/busses/i2c-cadence.c
+++ b/drivers/i2c/busses/i2c-cadence.c
@@ -7,13 +7,16 @@

#include <linux/clk.h>
#include <linux/delay.h>
+#include <linux/gpio/consumer.h>
#include <linux/i2c.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/of.h>
+#include <linux/of_gpio.h>
#include <linux/pm_runtime.h>
+#include <linux/pinctrl/consumer.h>

/* Register offsets for the I2C device. */
#define CDNS_I2C_CR_OFFSET 0x00 /* Control Register, RW */
@@ -139,6 +142,10 @@
* @clk_rate_change_nb: Notifier block for clock rate changes
* @quirks: flag for broken hold bit usage in r1p10
* @ctrl_reg: Cached value of the control register.
+ * @rinfo: Structure holding recovery information.
+ * @pinctrl: Pin control state holder.
+ * @pinctrl_pins_default: Default pin control state.
+ * @pinctrl_pins_gpio: GPIO pin control state.
*/
struct cdns_i2c {
struct device *dev;
@@ -160,6 +167,10 @@ struct cdns_i2c {
struct notifier_block clk_rate_change_nb;
u32 quirks;
u32 ctrl_reg;
+ struct i2c_bus_recovery_info rinfo;
+ struct pinctrl *pinctrl;
+ struct pinctrl_state *pinctrl_pins_default;
+ struct pinctrl_state *pinctrl_pins_gpio;
};

struct cdns_platform_data {
@@ -544,6 +555,7 @@ static int cdns_i2c_process_msg(struct cdns_i2c *id, struct i2c_msg *msg,
/* Wait for the signal of completion */
time_left = wait_for_completion_timeout(&id->xfer_done, adap->timeout);
if (time_left == 0) {
+ i2c_recover_bus(adap);
cdns_i2c_master_reset(adap);
dev_err(id->adap.dev.parent,
"timeout waiting on completion\n");
@@ -880,6 +892,88 @@ static int __maybe_unused cdns_i2c_runtime_resume(struct device *dev)
return 0;
}

+/**
+ * cdns_i2c_prepare_recovery - Withhold recovery state
+ * @adapter: Pointer to i2c adapter
+ *
+ * This function is called to prepare for recovery.
+ * It changes the state of pins from SCL/SDA to GPIO.
+ */
+static void cdns_i2c_prepare_recovery(struct i2c_adapter *adapter)
+{
+ struct cdns_i2c *p_cdns_i2c;
+
+ p_cdns_i2c = container_of(adapter, struct cdns_i2c, adap);
+
+ /* Setting pin state as gpio */
+ pinctrl_select_state(p_cdns_i2c->pinctrl,
+ p_cdns_i2c->pinctrl_pins_gpio);
+}
+
+/**
+ * cdns_i2c_unprepare_recovery - Release recovery state
+ * @adapter: Pointer to i2c adapter
+ *
+ * This function is called on exiting recovery. It reverts
+ * the state of pins from GPIO to SCL/SDA.
+ */
+static void cdns_i2c_unprepare_recovery(struct i2c_adapter *adapter)
+{
+ struct cdns_i2c *p_cdns_i2c;
+
+ p_cdns_i2c = container_of(adapter, struct cdns_i2c, adap);
+
+ /* Setting pin state to default(i2c) */
+ pinctrl_select_state(p_cdns_i2c->pinctrl,
+ p_cdns_i2c->pinctrl_pins_default);
+}
+
+/**
+ * cdns_i2c_init_recovery_info - Initialize I2C bus recovery
+ * @pid: Pointer to cdns i2c structure
+ * @pdev: Handle to the platform device structure
+ *
+ * This function does required initialization for i2c bus
+ * recovery. It registers three functions for prepare,
+ * recover and unprepare
+ *
+ * Return: 0 on Success, negative error otherwise.
+ */
+static int cdns_i2c_init_recovery_info(struct cdns_i2c *pid,
+ struct platform_device *pdev)
+{
+ struct i2c_bus_recovery_info *rinfo = &pid->rinfo;
+
+ pid->pinctrl_pins_default = pinctrl_lookup_state(pid->pinctrl,
+ PINCTRL_STATE_DEFAULT);
+ pid->pinctrl_pins_gpio = pinctrl_lookup_state(pid->pinctrl, "gpio");
+
+ /* Fetches GPIO pins */
+ rinfo->sda_gpiod = devm_gpiod_get(&pdev->dev, "sda-gpios", 0);
+ rinfo->scl_gpiod = devm_gpiod_get(&pdev->dev, "scl-gpios", 0);
+
+ /* if GPIO driver isn't ready yet, deffer probe */
+ if (PTR_ERR(rinfo->sda_gpiod) == -EPROBE_DEFER ||
+ PTR_ERR(rinfo->scl_gpiod) == -EPROBE_DEFER)
+ return -EPROBE_DEFER;
+
+ /* Validates fetched information */
+ if (IS_ERR(rinfo->sda_gpiod) ||
+ IS_ERR(rinfo->scl_gpiod) ||
+ IS_ERR(pid->pinctrl_pins_default) ||
+ IS_ERR(pid->pinctrl_pins_gpio)) {
+ dev_dbg(&pdev->dev, "recovery information incomplete\n");
+ return 0;
+ }
+
+ rinfo->prepare_recovery = cdns_i2c_prepare_recovery;
+ rinfo->unprepare_recovery = cdns_i2c_unprepare_recovery;
+ rinfo->recover_bus = i2c_generic_scl_recovery;
+ pid->adap.bus_recovery_info = rinfo;
+
+ return 0;
+}
+
static const struct dev_pm_ops cdns_i2c_dev_pm_ops = {
SET_RUNTIME_PM_OPS(cdns_i2c_runtime_suspend,
cdns_i2c_runtime_resume, NULL)
@@ -926,6 +1020,13 @@ static int cdns_i2c_probe(struct platform_device *pdev)
id->quirks = data->quirks;
}

+ id->pinctrl = devm_pinctrl_get(&pdev->dev);
+ if (!IS_ERR(id->pinctrl)) {
+ ret = cdns_i2c_init_recovery_info(id, pdev);
+ if (ret)
+ return ret;
+ }
+
r_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
id->membase = devm_ioremap_resource(&pdev->dev, r_mem);
if (IS_ERR(id->membase))
--
2.1.1

2019-12-09 10:51:24

by Shubhrajyoti Datta

[permalink] [raw]
Subject: [PATCH 2/4] i2c: cadence: Fix power management order of operations

From: Topi Kuutela <[email protected]>

E.g. pm_runtime_set_active must be called while the power
management system is disabled. Fixes extra hanging clk_enable.

Signed-off-by: Topi Kuutela <[email protected]>
Acked-by: Sören Brinkmann <[email protected]>
Signed-off-by: Michal Simek <[email protected]>
Signed-off-by: Shubhrajyoti Datta <[email protected]>
---
drivers/i2c/busses/i2c-cadence.c | 9 ++++++---
1 file changed, 6 insertions(+), 3 deletions(-)

diff --git a/drivers/i2c/busses/i2c-cadence.c b/drivers/i2c/busses/i2c-cadence.c
index 7b989a2..08427e9 100644
--- a/drivers/i2c/busses/i2c-cadence.c
+++ b/drivers/i2c/busses/i2c-cadence.c
@@ -932,10 +932,10 @@ static int cdns_i2c_probe(struct platform_device *pdev)
if (ret)
dev_err(&pdev->dev, "Unable to enable clock.\n");

- pm_runtime_enable(id->dev);
pm_runtime_set_autosuspend_delay(id->dev, CNDS_I2C_PM_TIMEOUT);
pm_runtime_use_autosuspend(id->dev);
pm_runtime_set_active(id->dev);
+ pm_runtime_enable(id->dev);

id->clk_rate_change_nb.notifier_call = cdns_i2c_clk_notifier_cb;
if (clk_notifier_register(id->clk, &id->clk_rate_change_nb))
@@ -984,8 +984,8 @@ static int cdns_i2c_probe(struct platform_device *pdev)

err_clk_dis:
clk_disable_unprepare(id->clk);
- pm_runtime_set_suspended(&pdev->dev);
pm_runtime_disable(&pdev->dev);
+ pm_runtime_set_suspended(&pdev->dev);
return ret;
}

@@ -1001,10 +1001,13 @@ static int cdns_i2c_remove(struct platform_device *pdev)
{
struct cdns_i2c *id = platform_get_drvdata(pdev);

+ pm_runtime_disable(&pdev->dev);
+ pm_runtime_set_suspended(&pdev->dev);
+ pm_runtime_dont_use_autosuspend(&pdev->dev);
+
i2c_del_adapter(&id->adap);
clk_notifier_unregister(id->clk, &id->clk_rate_change_nb);
clk_disable_unprepare(id->clk);
- pm_runtime_disable(&pdev->dev);

return 0;
}
--
2.1.1

2020-01-30 08:15:59

by Wolfram Sang

[permalink] [raw]
Subject: Re: [PATCH 1/4] i2c: cadence: Fix error printing in case of defer

On Mon, Dec 09, 2019 at 04:10:49PM +0530, [email protected] wrote:
> From: Shubhrajyoti Datta <[email protected]>
>
> Do not print error in case of EPROBE_DEFER.
>
> Signed-off-by: Shubhrajyoti Datta <[email protected]>

Applied to for-next, thanks!


Attachments:
(No filename) (297.00 B)
signature.asc (849.00 B)
Download all attachments

2020-01-30 08:18:01

by Wolfram Sang

[permalink] [raw]
Subject: Re: [PATCH 2/4] i2c: cadence: Fix power management order of operations

On Mon, Dec 09, 2019 at 04:10:50PM +0530, [email protected] wrote:
> From: Topi Kuutela <[email protected]>
>
> E.g. pm_runtime_set_active must be called while the power
> management system is disabled. Fixes extra hanging clk_enable.
>
> Signed-off-by: Topi Kuutela <[email protected]>
> Acked-by: Sören Brinkmann <[email protected]>
> Signed-off-by: Michal Simek <[email protected]>
> Signed-off-by: Shubhrajyoti Datta <[email protected]>

Applied to for-next, thanks!


Attachments:
(No filename) (536.00 B)
signature.asc (849.00 B)
Download all attachments

2020-01-30 08:23:11

by Wolfram Sang

[permalink] [raw]
Subject: Re: [PATCH 3/4] i2c: cadence: Implement save restore

On Mon, Dec 09, 2019 at 04:10:51PM +0530, [email protected] wrote:
> From: Shubhrajyoti Datta <[email protected]>
>
> Implement save restore for i2c module.
> Since we have only a couple of registers
> an unconditional restore is done.

The patch description misses an explanation *why* this is needed. From a
distance looks like a bugfix, so a Fixes tag may be needed, too.

>
> Acked-by: Michal Simek <[email protected]>
> Signed-off-by: Shubhrajyoti Datta <[email protected]>
> Signed-off-by: Michal Simek <[email protected]>
> Signed-off-by: Shubhrajyoti Datta <[email protected]>

This is messy. Ack + SoB from Michal. Two xilinx-SoBs from you. Please
fix.


Attachments:
(No filename) (733.00 B)
signature.asc (849.00 B)
Download all attachments