|
@@ -49,6 +49,7 @@
|
|
#include <linux/of.h>
|
|
#include <linux/of.h>
|
|
#include <linux/of_device.h>
|
|
#include <linux/of_device.h>
|
|
#include <linux/of_dma.h>
|
|
#include <linux/of_dma.h>
|
|
|
|
+#include <linux/of_gpio.h>
|
|
#include <linux/platform_data/i2c-imx.h>
|
|
#include <linux/platform_data/i2c-imx.h>
|
|
#include <linux/platform_device.h>
|
|
#include <linux/platform_device.h>
|
|
#include <linux/sched.h>
|
|
#include <linux/sched.h>
|
|
@@ -207,6 +208,11 @@ struct imx_i2c_struct {
|
|
unsigned int cur_clk;
|
|
unsigned int cur_clk;
|
|
unsigned int bitrate;
|
|
unsigned int bitrate;
|
|
const struct imx_i2c_hwdata *hwdata;
|
|
const struct imx_i2c_hwdata *hwdata;
|
|
|
|
+ struct i2c_bus_recovery_info rinfo;
|
|
|
|
+
|
|
|
|
+ struct pinctrl *pinctrl;
|
|
|
|
+ struct pinctrl_state *pinctrl_pins_default;
|
|
|
|
+ struct pinctrl_state *pinctrl_pins_gpio;
|
|
|
|
|
|
struct imx_i2c_dma *dma;
|
|
struct imx_i2c_dma *dma;
|
|
};
|
|
};
|
|
@@ -896,6 +902,13 @@ static int i2c_imx_xfer(struct i2c_adapter *adapter,
|
|
|
|
|
|
/* Start I2C transfer */
|
|
/* Start I2C transfer */
|
|
result = i2c_imx_start(i2c_imx);
|
|
result = i2c_imx_start(i2c_imx);
|
|
|
|
+ if (result) {
|
|
|
|
+ if (i2c_imx->adapter.bus_recovery_info) {
|
|
|
|
+ i2c_recover_bus(&i2c_imx->adapter);
|
|
|
|
+ result = i2c_imx_start(i2c_imx);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
if (result)
|
|
if (result)
|
|
goto fail0;
|
|
goto fail0;
|
|
|
|
|
|
@@ -956,6 +969,55 @@ fail0:
|
|
return (result < 0) ? result : num;
|
|
return (result < 0) ? result : num;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+static void i2c_imx_prepare_recovery(struct i2c_adapter *adap)
|
|
|
|
+{
|
|
|
|
+ struct imx_i2c_struct *i2c_imx;
|
|
|
|
+
|
|
|
|
+ i2c_imx = container_of(adap, struct imx_i2c_struct, adapter);
|
|
|
|
+
|
|
|
|
+ pinctrl_select_state(i2c_imx->pinctrl, i2c_imx->pinctrl_pins_gpio);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static void i2c_imx_unprepare_recovery(struct i2c_adapter *adap)
|
|
|
|
+{
|
|
|
|
+ struct imx_i2c_struct *i2c_imx;
|
|
|
|
+
|
|
|
|
+ i2c_imx = container_of(adap, struct imx_i2c_struct, adapter);
|
|
|
|
+
|
|
|
|
+ pinctrl_select_state(i2c_imx->pinctrl, i2c_imx->pinctrl_pins_default);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static void i2c_imx_init_recovery_info(struct imx_i2c_struct *i2c_imx,
|
|
|
|
+ struct platform_device *pdev)
|
|
|
|
+{
|
|
|
|
+ struct i2c_bus_recovery_info *rinfo = &i2c_imx->rinfo;
|
|
|
|
+
|
|
|
|
+ i2c_imx->pinctrl_pins_default = pinctrl_lookup_state(i2c_imx->pinctrl,
|
|
|
|
+ PINCTRL_STATE_DEFAULT);
|
|
|
|
+ i2c_imx->pinctrl_pins_gpio = pinctrl_lookup_state(i2c_imx->pinctrl,
|
|
|
|
+ "gpio");
|
|
|
|
+ rinfo->sda_gpio = of_get_named_gpio_flags(pdev->dev.of_node,
|
|
|
|
+ "sda-gpios", 0, NULL);
|
|
|
|
+ rinfo->scl_gpio = of_get_named_gpio_flags(pdev->dev.of_node,
|
|
|
|
+ "scl-gpios", 0, NULL);
|
|
|
|
+
|
|
|
|
+ if (!gpio_is_valid(rinfo->sda_gpio) ||
|
|
|
|
+ !gpio_is_valid(rinfo->scl_gpio) ||
|
|
|
|
+ IS_ERR(i2c_imx->pinctrl_pins_default) ||
|
|
|
|
+ IS_ERR(i2c_imx->pinctrl_pins_gpio)) {
|
|
|
|
+ dev_dbg(&pdev->dev, "recovery information incomplete\n");
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ dev_dbg(&pdev->dev, "using scl-gpio %d and sda-gpio %d for recovery\n",
|
|
|
|
+ rinfo->sda_gpio, rinfo->scl_gpio);
|
|
|
|
+
|
|
|
|
+ rinfo->prepare_recovery = i2c_imx_prepare_recovery;
|
|
|
|
+ rinfo->unprepare_recovery = i2c_imx_unprepare_recovery;
|
|
|
|
+ rinfo->recover_bus = i2c_generic_gpio_recovery;
|
|
|
|
+ i2c_imx->adapter.bus_recovery_info = rinfo;
|
|
|
|
+}
|
|
|
|
+
|
|
static u32 i2c_imx_func(struct i2c_adapter *adapter)
|
|
static u32 i2c_imx_func(struct i2c_adapter *adapter)
|
|
{
|
|
{
|
|
return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL
|
|
return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL
|
|
@@ -1023,6 +1085,13 @@ static int i2c_imx_probe(struct platform_device *pdev)
|
|
dev_err(&pdev->dev, "can't enable I2C clock\n");
|
|
dev_err(&pdev->dev, "can't enable I2C clock\n");
|
|
return ret;
|
|
return ret;
|
|
}
|
|
}
|
|
|
|
+
|
|
|
|
+ i2c_imx->pinctrl = devm_pinctrl_get(&pdev->dev);
|
|
|
|
+ if (IS_ERR(i2c_imx->pinctrl)) {
|
|
|
|
+ ret = PTR_ERR(i2c_imx->pinctrl);
|
|
|
|
+ goto clk_disable;
|
|
|
|
+ }
|
|
|
|
+
|
|
/* Request IRQ */
|
|
/* Request IRQ */
|
|
ret = devm_request_irq(&pdev->dev, irq, i2c_imx_isr, 0,
|
|
ret = devm_request_irq(&pdev->dev, irq, i2c_imx_isr, 0,
|
|
pdev->name, i2c_imx);
|
|
pdev->name, i2c_imx);
|
|
@@ -1056,6 +1125,8 @@ static int i2c_imx_probe(struct platform_device *pdev)
|
|
goto clk_disable;
|
|
goto clk_disable;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ i2c_imx_init_recovery_info(i2c_imx, pdev);
|
|
|
|
+
|
|
/* Set up platform driver data */
|
|
/* Set up platform driver data */
|
|
platform_set_drvdata(pdev, i2c_imx);
|
|
platform_set_drvdata(pdev, i2c_imx);
|
|
clk_disable_unprepare(i2c_imx->clk);
|
|
clk_disable_unprepare(i2c_imx->clk);
|