i2c: cadence: Implement save restore
The zynqmp platform now supports chip-off so the registers can lose context. Implement save restore for i2c module. Since we have only a couple of registers an unconditional restore is done. Acked-by: Michal Simek <michal.simek@xilinx.com> Signed-off-by: Shubhrajyoti Datta <shubhrajyoti.datta@xilinx.com> Signed-off-by: Wolfram Sang <wsa@kernel.org>
This commit is contained in:
parent
661e8a88e8
commit
8b51a8e644
1 changed files with 27 additions and 11 deletions
|
@ -178,6 +178,7 @@ enum cdns_i2c_slave_state {
|
||||||
* @clk: Pointer to struct clk
|
* @clk: Pointer to struct clk
|
||||||
* @clk_rate_change_nb: Notifier block for clock rate changes
|
* @clk_rate_change_nb: Notifier block for clock rate changes
|
||||||
* @quirks: flag for broken hold bit usage in r1p10
|
* @quirks: flag for broken hold bit usage in r1p10
|
||||||
|
* @ctrl_reg: Cached value of the control register.
|
||||||
* @ctrl_reg_diva_divb: value of fields DIV_A and DIV_B from CR register
|
* @ctrl_reg_diva_divb: value of fields DIV_A and DIV_B from CR register
|
||||||
* @slave: Registered slave instance.
|
* @slave: Registered slave instance.
|
||||||
* @dev_mode: I2C operating role(master/slave).
|
* @dev_mode: I2C operating role(master/slave).
|
||||||
|
@ -202,6 +203,7 @@ struct cdns_i2c {
|
||||||
struct clk *clk;
|
struct clk *clk;
|
||||||
struct notifier_block clk_rate_change_nb;
|
struct notifier_block clk_rate_change_nb;
|
||||||
u32 quirks;
|
u32 quirks;
|
||||||
|
u32 ctrl_reg;
|
||||||
#if IS_ENABLED(CONFIG_I2C_SLAVE)
|
#if IS_ENABLED(CONFIG_I2C_SLAVE)
|
||||||
u16 ctrl_reg_diva_divb;
|
u16 ctrl_reg_diva_divb;
|
||||||
struct i2c_client *slave;
|
struct i2c_client *slave;
|
||||||
|
@ -1071,10 +1073,11 @@ static int cdns_i2c_setclk(unsigned long clk_in, struct cdns_i2c *id)
|
||||||
if (ret)
|
if (ret)
|
||||||
return 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 &= ~(CDNS_I2C_CR_DIVA_MASK | CDNS_I2C_CR_DIVB_MASK);
|
||||||
ctrl_reg |= ((div_a << CDNS_I2C_CR_DIVA_SHIFT) |
|
ctrl_reg |= ((div_a << CDNS_I2C_CR_DIVA_SHIFT) |
|
||||||
(div_b << CDNS_I2C_CR_DIVB_SHIFT));
|
(div_b << CDNS_I2C_CR_DIVB_SHIFT));
|
||||||
|
id->ctrl_reg = ctrl_reg;
|
||||||
cdns_i2c_writereg(ctrl_reg, CDNS_I2C_CR_OFFSET);
|
cdns_i2c_writereg(ctrl_reg, CDNS_I2C_CR_OFFSET);
|
||||||
#if IS_ENABLED(CONFIG_I2C_SLAVE)
|
#if IS_ENABLED(CONFIG_I2C_SLAVE)
|
||||||
id->ctrl_reg_diva_divb = ctrl_reg & (CDNS_I2C_CR_DIVA_MASK |
|
id->ctrl_reg_diva_divb = ctrl_reg & (CDNS_I2C_CR_DIVA_MASK |
|
||||||
|
@ -1162,6 +1165,26 @@ static int __maybe_unused cdns_i2c_runtime_suspend(struct device *dev)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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
|
* cdns_i2c_runtime_resume - Runtime resume
|
||||||
* @dev: Address of the platform_device structure
|
* @dev: Address of the platform_device structure
|
||||||
|
@ -1180,6 +1203,7 @@ static int __maybe_unused cdns_i2c_runtime_resume(struct device *dev)
|
||||||
dev_err(dev, "Cannot enable clock.\n");
|
dev_err(dev, "Cannot enable clock.\n");
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
cdns_i2c_init(xi2c);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -1279,7 +1303,7 @@ static int cdns_i2c_probe(struct platform_device *pdev)
|
||||||
id->dev_mode = CDNS_I2C_MODE_MASTER;
|
id->dev_mode = CDNS_I2C_MODE_MASTER;
|
||||||
id->slave_state = CDNS_I2C_SLAVE_STATE_IDLE;
|
id->slave_state = CDNS_I2C_SLAVE_STATE_IDLE;
|
||||||
#endif
|
#endif
|
||||||
cdns_i2c_writereg(CDNS_I2C_CR_MASTER_EN_MASK, 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);
|
ret = cdns_i2c_setclk(id->input_clk, id);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
|
@ -1294,15 +1318,7 @@ static int cdns_i2c_probe(struct platform_device *pdev)
|
||||||
dev_err(&pdev->dev, "cannot get irq %d\n", id->irq);
|
dev_err(&pdev->dev, "cannot get irq %d\n", id->irq);
|
||||||
goto err_clk_dis;
|
goto err_clk_dis;
|
||||||
}
|
}
|
||||||
|
cdns_i2c_init(id);
|
||||||
/*
|
|
||||||
* 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);
|
|
||||||
|
|
||||||
ret = i2c_add_adapter(&id->adap);
|
ret = i2c_add_adapter(&id->adap);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
|
|
Loading…
Add table
Reference in a new issue