Skip to content
Snippets Groups Projects
i2c-imx.c 49.9 KiB
Newer Older
		result = i2c_imx_trx_complete(i2c_imx, atomic);
Darius Augulis's avatar
Darius Augulis committed
		if (result)
			return result;
		/*
		 * First byte is the length of remaining packet
		 * in the SMBus block data read. Add it to
		 * msgs->len.
		 */
		if ((!i) && block_data) {
			len = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2DR);
			if ((len == 0) || (len > I2C_SMBUS_BLOCK_MAX))
				return -EPROTO;
			dev_dbg(&i2c_imx->adapter.dev,
				"<%s> read length: 0x%X\n",
				__func__, len);
			msgs->len += len;
		}
Darius Augulis's avatar
Darius Augulis committed
		if (i == (msgs->len - 1)) {
			if (is_lastmsg) {
				/*
				 * It must generate STOP before read I2DR to prevent
				 * controller from generating another clock cycle
				 */
				dev_dbg(&i2c_imx->adapter.dev,
					"<%s> clear MSTA\n", __func__);
				temp = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2CR);
				if (!(temp & I2CR_MSTA))
					i2c_imx->stopped =  1;
				temp &= ~(I2CR_MSTA | I2CR_MTX);
				imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2CR);
				if (!i2c_imx->stopped)
					i2c_imx_bus_busy(i2c_imx, 0, atomic);
			} else {
				/*
				 * For i2c master receiver repeat restart operation like:
				 * read -> repeat MSTA -> read/write
				 * The controller must set MTX before read the last byte in
				 * the first read operation, otherwise the first read cost
				 * one extra clock cycle.
				 */
				temp = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2CR);
				imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2CR);
Darius Augulis's avatar
Darius Augulis committed
		} else if (i == (msgs->len - 2)) {
			dev_dbg(&i2c_imx->adapter.dev,
				"<%s> set TXAK\n", __func__);
			temp = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2CR);
Darius Augulis's avatar
Darius Augulis committed
			temp |= I2CR_TXAK;
			imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2CR);
Darius Augulis's avatar
Darius Augulis committed
		}
		if ((!i) && block_data)
			msgs->buf[0] = len;
		else
			msgs->buf[i] = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2DR);
Darius Augulis's avatar
Darius Augulis committed
		dev_dbg(&i2c_imx->adapter.dev,
			"<%s> read byte: B%d=0x%X\n",
			__func__, i, msgs->buf[i]);
	}
	return 0;
}

static int i2c_imx_xfer_common(struct i2c_adapter *adapter,
			       struct i2c_msg *msgs, int num, bool atomic)
Darius Augulis's avatar
Darius Augulis committed
{
	unsigned int i, temp;
	int result;
Darius Augulis's avatar
Darius Augulis committed
	struct imx_i2c_struct *i2c_imx = i2c_get_adapdata(adapter);

	dev_dbg(&i2c_imx->adapter.dev, "<%s>\n", __func__);

	/* Start I2C transfer */
	result = i2c_imx_start(i2c_imx, atomic);
	if (result) {
		/*
		 * Bus recovery uses gpiod_get_value_cansleep() which is not
		 * allowed within atomic context.
		 */
		if (!atomic && i2c_imx->adapter.bus_recovery_info) {
			i2c_recover_bus(&i2c_imx->adapter);
			result = i2c_imx_start(i2c_imx, atomic);
Darius Augulis's avatar
Darius Augulis committed
	if (result)
		goto fail0;

	/* read/write data */
	for (i = 0; i < num; i++) {
		if (i == num - 1)
			is_lastmsg = true;

Darius Augulis's avatar
Darius Augulis committed
		if (i) {
			dev_dbg(&i2c_imx->adapter.dev,
				"<%s> repeated start\n", __func__);
			temp = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2CR);
Darius Augulis's avatar
Darius Augulis committed
			temp |= I2CR_RSTA;
			imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2CR);
			result = i2c_imx_bus_busy(i2c_imx, 1, atomic);
			if (result)
				goto fail0;
Darius Augulis's avatar
Darius Augulis committed
		}
		dev_dbg(&i2c_imx->adapter.dev,
			"<%s> transfer message: %d\n", __func__, i);
		/* write/read data */
#ifdef CONFIG_I2C_DEBUG_BUS
		temp = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2CR);
		dev_dbg(&i2c_imx->adapter.dev,
			"<%s> CONTROL: IEN=%d, IIEN=%d, MSTA=%d, MTX=%d, TXAK=%d, RSTA=%d\n",
			__func__,
Darius Augulis's avatar
Darius Augulis committed
			(temp & I2CR_IEN ? 1 : 0), (temp & I2CR_IIEN ? 1 : 0),
			(temp & I2CR_MSTA ? 1 : 0), (temp & I2CR_MTX ? 1 : 0),
			(temp & I2CR_TXAK ? 1 : 0), (temp & I2CR_RSTA ? 1 : 0));
		temp = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2SR);
Darius Augulis's avatar
Darius Augulis committed
		dev_dbg(&i2c_imx->adapter.dev,
			"<%s> STATUS: ICF=%d, IAAS=%d, IBB=%d, IAL=%d, SRW=%d, IIF=%d, RXAK=%d\n",
			__func__,
Darius Augulis's avatar
Darius Augulis committed
			(temp & I2SR_ICF ? 1 : 0), (temp & I2SR_IAAS ? 1 : 0),
			(temp & I2SR_IBB ? 1 : 0), (temp & I2SR_IAL ? 1 : 0),
			(temp & I2SR_SRW ? 1 : 0), (temp & I2SR_IIF ? 1 : 0),
			(temp & I2SR_RXAK ? 1 : 0));
#endif
		if (msgs[i].flags & I2C_M_RD) {
			result = i2c_imx_read(i2c_imx, &msgs[i], is_lastmsg, atomic);
		} else {
			if (!atomic &&
			    i2c_imx->dma && msgs[i].len >= DMA_THRESHOLD)
				result = i2c_imx_dma_write(i2c_imx, &msgs[i]);
			else
				result = i2c_imx_write(i2c_imx, &msgs[i], atomic);
		if (result)
			goto fail0;
Darius Augulis's avatar
Darius Augulis committed
	}

fail0:
	/* Stop I2C transfer */
	i2c_imx_stop(i2c_imx, atomic);
Darius Augulis's avatar
Darius Augulis committed
	dev_dbg(&i2c_imx->adapter.dev, "<%s> exit with: %s: %d\n", __func__,
		(result < 0) ? "error" : "success msg",
			(result < 0) ? result : num);
#if IS_ENABLED(CONFIG_I2C_SLAVE)
	/* After data is transfered, switch to slave mode(as a receiver) */
	if (i2c_imx->slave) {
	    if (i2c_imx_slave_init(i2c_imx) < 0)
		dev_err(&i2c_imx->adapter.dev, "failed to switch to slave mode");
	}
#endif

Darius Augulis's avatar
Darius Augulis committed
	return (result < 0) ? result : num;
}

/*
 * Based on the I2C specification, if the data line (SDA) is
 * stuck low, the master should send nine  * clock pulses.
 * The I2C slave device that held the bus low should release it
 * sometime within  * those nine clocks. Due to this erratum,
 * the I2C controller cannot generate nine clock pulses.
 */
static int i2c_imx_recovery_for_layerscape(struct imx_i2c_struct *i2c_imx)
{
	u32 pmuxcr = 0;
	int ret;
	unsigned int i, temp;

	/* configure IICx_SCL/GPIO pin as a GPIO */
	if (i2c_imx->need_set_pmuxcr == 1) {
		pmuxcr = ioread32be(i2c_imx->pmuxcr_addr);
		if (i2c_imx->pmuxcr_endian == BIG_ENDIAN)
			iowrite32be(i2c_imx->pmuxcr_set|pmuxcr,
				    i2c_imx->pmuxcr_addr);
		else
			iowrite32(i2c_imx->pmuxcr_set|pmuxcr,
				  i2c_imx->pmuxcr_addr);
	}

	ret = gpio_request(i2c_imx->gpio, i2c_imx->adapter.name);
	if (ret) {
		dev_err(&i2c_imx->adapter.dev,
			"can't get gpio: %d\n", ret);
		return ret;
	}

	/* Configure GPIO pin as an output and open drain. */
	gpio_direction_output(i2c_imx->gpio, 1);
	udelay(10);

	/* Write data to generate 9 pulses */
	for (i = 0; i < 9; i++) {
		gpio_set_value(i2c_imx->gpio, 1);
		udelay(10);
		gpio_set_value(i2c_imx->gpio, 0);
		udelay(10);
	}
	/* ensure that the last level sent is always high */
	gpio_set_value(i2c_imx->gpio, 1);

	/*
	 * Set I2Cx_IBCR = 0h00 to generate a STOP
	 */
	imx_i2c_write_reg(i2c_imx->hwdata->i2cr_ien_opcode, i2c_imx, IMX_I2C_I2CR);

	/*
	 * Set I2Cx_IBCR = 0h80 to reset the I2Cx controller
	 */
	imx_i2c_write_reg(i2c_imx->hwdata->i2cr_ien_opcode | I2CR_IEN, i2c_imx, IMX_I2C_I2CR);

	/* Restore the saved value of the register SCFG_RCWPMUXCR0 */
	if (i2c_imx->need_set_pmuxcr == 1) {
		if (i2c_imx->pmuxcr_endian == BIG_ENDIAN)
			iowrite32be(pmuxcr, i2c_imx->pmuxcr_addr);
		else
			iowrite32(pmuxcr, i2c_imx->pmuxcr_addr);
	}
	/*
	 * Set I2C_IBSR[IBAL] to clear the IBAL bit if-
	 * I2C_IBSR[IBAL] = 1
	 */
	temp = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2SR);
	if (temp & I2SR_IAL)
		i2c_imx_clr_al_bit(temp, i2c_imx);

	return 0;
}

static int i2c_imx_xfer(struct i2c_adapter *adapter,
			struct i2c_msg *msgs, int num)
{
	struct imx_i2c_struct *i2c_imx = i2c_get_adapdata(adapter);
	bool enable_runtime_pm = false;
	if (!pm_runtime_enabled(i2c_imx->adapter.dev.parent)) {
		pm_runtime_enable(i2c_imx->adapter.dev.parent);
		enable_runtime_pm = true;
	}

	result = pm_runtime_get_sync(i2c_imx->adapter.dev.parent);
	if (result < 0) {
		if (enable_runtime_pm)
			pm_runtime_disable(i2c_imx->adapter.dev.parent);
	/*
	 * workaround for ERR010027: ensure that the I2C BUS is idle
	 * before switching to master mode and attempting a Start cycle
	 */
	result =  i2c_imx_bus_busy(i2c_imx, 0, false);
	if (result) {
		/* timeout */
		if ((result == -ETIMEDOUT) && (i2c_imx->layerscape_bus_recover == 1))
			i2c_imx_recovery_for_layerscape(i2c_imx);
		else {
			if (enable_runtime_pm)
				pm_runtime_disable(i2c_imx->adapter.dev.parent);
			return result;
		}
	}

	result = i2c_imx_xfer_common(adapter, msgs, num, false);

	pm_runtime_mark_last_busy(i2c_imx->adapter.dev.parent);
	pm_runtime_put_autosuspend(i2c_imx->adapter.dev.parent);

	if (enable_runtime_pm)
		pm_runtime_disable(i2c_imx->adapter.dev.parent);

	return result;
}

static int i2c_imx_xfer_atomic(struct i2c_adapter *adapter,
			       struct i2c_msg *msgs, int num)
{
	struct imx_i2c_struct *i2c_imx = i2c_get_adapdata(adapter);
	int result;

	result = clk_enable(i2c_imx->clk);
	if (result)
		return result;

	result = i2c_imx_xfer_common(adapter, msgs, num, true);

	clk_disable(i2c_imx->clk);

	return result;
}

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);
}

/*
 * We switch SCL and SDA to their GPIO function and do some bitbanging
 * for bus recovery. These alternative pinmux settings can be
 * described in the device tree by a separate pinctrl state "gpio". If
 * this is missing this is not a big problem, the only implication is
 * that we can't do bus recovery.
 */
static int 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 = devm_pinctrl_get(&pdev->dev);
	if (!i2c_imx->pinctrl || IS_ERR(i2c_imx->pinctrl)) {
		dev_info(&pdev->dev, "can't get pinctrl, bus recovery not supported\n");
		return PTR_ERR(i2c_imx->pinctrl);
	}

	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_gpiod = devm_gpiod_get(&pdev->dev, "sda", GPIOD_IN);
	rinfo->scl_gpiod = devm_gpiod_get(&pdev->dev, "scl", GPIOD_OUT_HIGH_OPEN_DRAIN);
	if (PTR_ERR(rinfo->sda_gpiod) == -EPROBE_DEFER ||
	    PTR_ERR(rinfo->scl_gpiod) == -EPROBE_DEFER) {
	} else if (IS_ERR(rinfo->sda_gpiod) ||
		   IS_ERR(rinfo->scl_gpiod) ||
		   IS_ERR(i2c_imx->pinctrl_pins_default) ||
		   IS_ERR(i2c_imx->pinctrl_pins_gpio)) {
		dev_dbg(&pdev->dev, "recovery information incomplete\n");
	dev_dbg(&pdev->dev, "using scl%s for recovery\n",
		rinfo->sda_gpiod ? ",sda" : "");

	rinfo->prepare_recovery = i2c_imx_prepare_recovery;
	rinfo->unprepare_recovery = i2c_imx_unprepare_recovery;
	rinfo->recover_bus = i2c_generic_scl_recovery;
	i2c_imx->adapter.bus_recovery_info = rinfo;
/*
 * switch SCL and SDA to their GPIO function and do some bitbanging
 * for bus recovery.
 * There are platforms such as Layerscape that don't support pinctrl, so add
 * workaround for layerscape, it has no effect for other platforms.
 */
static int i2c_imx_init_recovery_for_layerscape(
		struct imx_i2c_struct *i2c_imx,
		struct platform_device *pdev)
{
	const struct of_device_id *of_id;
	struct device_node *np		= pdev->dev.of_node;
	struct pinmux_cfg		*pinmux_cfg;
	struct device_node *scfg_node;
	void __iomem *scfg_base = NULL;

	i2c_imx->gpio = of_get_named_gpio(np, "scl-gpios", 0);
	if (!gpio_is_valid(i2c_imx->gpio)) {
		dev_info(&pdev->dev, "scl-gpios not found\n");
		return 0;
	}
	pinmux_cfg = devm_kzalloc(&pdev->dev, sizeof(*pinmux_cfg), GFP_KERNEL);
	if (!pinmux_cfg)
		return -ENOMEM;

	i2c_imx->need_set_pmuxcr = 0;
	of_id = of_match_node(pinmux_of_match, np);
	if (of_id) {
		pinmux_cfg = (struct pinmux_cfg *)of_id->data;
		i2c_imx->pmuxcr_endian = pinmux_cfg->endian;
		i2c_imx->pmuxcr_set = pinmux_cfg->pmuxcr_set_bit;
		scfg_node = of_find_matching_node(NULL, scfg_device_ids);
		if (scfg_node) {
			scfg_base = of_iomap(scfg_node, 0);
			if (scfg_base) {
				i2c_imx->pmuxcr_addr = scfg_base + pinmux_cfg->pmuxcr_offset;
				i2c_imx->need_set_pmuxcr = 1;
			}
		}
	}
	i2c_imx->layerscape_bus_recover = 1;
	return 0;
}

Darius Augulis's avatar
Darius Augulis committed
static u32 i2c_imx_func(struct i2c_adapter *adapter)
{
	return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL
		| I2C_FUNC_SMBUS_READ_BLOCK_DATA;
#if IS_ENABLED(CONFIG_I2C_SLAVE)
static int i2c_imx_slave_init(struct imx_i2c_struct *i2c_imx)
{
	int temp;

	/* Resume */
	temp = pm_runtime_get_sync(i2c_imx->adapter.dev.parent);
	if (temp < 0) {
		dev_err(&i2c_imx->adapter.dev, "failed to resume i2c controller");
		return temp;
	}

	/* Set slave addr. */
	imx_i2c_write_reg((i2c_imx->slave->addr << 1), i2c_imx, IMX_I2C_IADR);

	i2c_imx_reset_regs(i2c_imx);

	/* Enable module */
	temp = i2c_imx->hwdata->i2cr_ien_opcode;
	imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2CR);

	/* Enable interrupt from i2c module */
	temp |= I2CR_IIEN;
	imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2CR);

	/* Wait controller to be stable */
	usleep_range(50, 150);
	return 0;
}

static irqreturn_t i2c_imx_slave_isr(struct imx_i2c_struct *i2c_imx, unsigned int status, unsigned int ctl)
{
	u8 value;

	if (status & I2SR_IAL) { /* Arbitration lost */
		i2c_imx_clr_al_bit(status | I2SR_IIF, i2c_imx);
	} else if (status & I2SR_IAAS) { /* Addressed as a slave */
		if (status & I2SR_SRW) { /* Master wants to read from us*/
			dev_dbg(&i2c_imx->adapter.dev, "read requested");
			i2c_slave_event(i2c_imx->slave, I2C_SLAVE_READ_REQUESTED, &value);

			/* Slave transmit */
			ctl |= I2CR_MTX;
			imx_i2c_write_reg(ctl, i2c_imx, IMX_I2C_I2CR);

			/* Send data */
			imx_i2c_write_reg(value, i2c_imx, IMX_I2C_I2DR);
		} else { /* Master wants to write to us */
			dev_dbg(&i2c_imx->adapter.dev, "write requested");
			i2c_slave_event(i2c_imx->slave,	I2C_SLAVE_WRITE_REQUESTED, &value);

			/* Slave receive */
			ctl &= ~I2CR_MTX;
			imx_i2c_write_reg(ctl, i2c_imx, IMX_I2C_I2CR);
			/* Dummy read */
			imx_i2c_read_reg(i2c_imx, IMX_I2C_I2DR);
		}
	} else if (!(ctl & I2CR_MTX)) { /* Receive mode */
			if (status & I2SR_IBB) { /* No STOP signal detected */
				ctl &= ~I2CR_MTX;
				imx_i2c_write_reg(ctl, i2c_imx, IMX_I2C_I2CR);

				value = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2DR);
				i2c_slave_event(i2c_imx->slave,	I2C_SLAVE_WRITE_RECEIVED, &value);
			} else { /* STOP signal is detected */
				dev_dbg(&i2c_imx->adapter.dev,
					"STOP signal detected");
				i2c_slave_event(i2c_imx->slave, I2C_SLAVE_STOP, &value);
			}
	} else if (!(status & I2SR_RXAK)) {	/* Transmit mode received ACK */
		ctl |= I2CR_MTX;
		imx_i2c_write_reg(ctl, i2c_imx, IMX_I2C_I2CR);

		i2c_slave_event(i2c_imx->slave,	I2C_SLAVE_READ_PROCESSED, &value);

		imx_i2c_write_reg(value, i2c_imx, IMX_I2C_I2DR);
	} else { /* Transmit mode received NAK */
		ctl &= ~I2CR_MTX;
		imx_i2c_write_reg(ctl, i2c_imx, IMX_I2C_I2CR);
		imx_i2c_read_reg(i2c_imx, IMX_I2C_I2DR);
		i2c_slave_event(i2c_imx->slave, I2C_SLAVE_STOP, &value);
	return IRQ_HANDLED;
}

static int i2c_imx_reg_slave(struct i2c_client *client)
{
	struct imx_i2c_struct *i2c_imx = i2c_get_adapdata(client->adapter);
	int ret;
	if (i2c_imx->slave)
		return -EBUSY;

	i2c_imx->slave = client;

	ret = i2c_imx_slave_init(i2c_imx);
	if (ret < 0)
		dev_err(&i2c_imx->adapter.dev, "failed to switch to slave mode");

	return ret;
}

static int i2c_imx_unreg_slave(struct i2c_client *client)
{
	struct imx_i2c_struct *i2c_imx = i2c_get_adapdata(client->adapter);
	int ret;

	if (!i2c_imx->slave)
		return -EINVAL;

	/* Reset slave address. */
	imx_i2c_write_reg(0, i2c_imx, IMX_I2C_IADR);

	i2c_imx_reset_regs(i2c_imx);

	i2c_imx->slave = NULL;

	/* Suspend */
	ret = pm_runtime_put_sync(i2c_imx->adapter.dev.parent);
	if (ret < 0)
		dev_err(&i2c_imx->adapter.dev, "failed to suspend i2c controller");

	return ret;
}
#endif

static const struct i2c_algorithm i2c_imx_algo = {
	.master_xfer = i2c_imx_xfer,
	.master_xfer_atomic = i2c_imx_xfer_atomic,
	.functionality = i2c_imx_func,
#if IS_ENABLED(CONFIG_I2C_SLAVE)
	.reg_slave	= i2c_imx_reg_slave,
	.unreg_slave	= i2c_imx_unreg_slave,
#endif
static irqreturn_t i2c_imx_isr(int irq, void *dev_id)
{
	struct imx_i2c_struct *i2c_imx = dev_id;
	unsigned int ctl, status;

	status = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2SR);
	ctl = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2CR);

	if (status & I2SR_IIF) {
		i2c_imx_clr_if_bit(status, i2c_imx);
#if IS_ENABLED(CONFIG_I2C_SLAVE)
		if (i2c_imx->slave && !(ctl & I2CR_MSTA)) {
			return i2c_imx_slave_isr(i2c_imx, status, ctl);
		}
		return i2c_imx_master_isr(i2c_imx, status);
static int i2c_imx_probe(struct platform_device *pdev)
Darius Augulis's avatar
Darius Augulis committed
{
	struct imx_i2c_struct *i2c_imx;
	struct resource *res;
Jingoo Han's avatar
Jingoo Han committed
	struct imxi2c_platform_data *pdata = dev_get_platdata(&pdev->dev);
Darius Augulis's avatar
Darius Augulis committed
	void __iomem *base;
	int irq, ret;
	dma_addr_t phy_addr;
	const struct imx_i2c_hwdata *match;
Darius Augulis's avatar
Darius Augulis committed

	dev_dbg(&pdev->dev, "<%s>\n", __func__);

	irq = platform_get_irq(pdev, 0);
	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
	base = devm_ioremap_resource(&pdev->dev, res);
	if (IS_ERR(base))
		return PTR_ERR(base);
	phy_addr = (dma_addr_t)res->start;
	i2c_imx = devm_kzalloc(&pdev->dev, sizeof(*i2c_imx), GFP_KERNEL);
	if (!i2c_imx)
		return -ENOMEM;
	match = device_get_match_data(&pdev->dev);
	if (match)
		i2c_imx->hwdata = match;
		i2c_imx->hwdata = (struct imx_i2c_hwdata *)
				platform_get_device_id(pdev)->driver_data;
Darius Augulis's avatar
Darius Augulis committed
	/* Setup i2c_imx driver structure */
	strlcpy(i2c_imx->adapter.name, pdev->name, sizeof(i2c_imx->adapter.name));
Darius Augulis's avatar
Darius Augulis committed
	i2c_imx->adapter.owner		= THIS_MODULE;
	i2c_imx->adapter.algo		= &i2c_imx_algo;
	i2c_imx->adapter.dev.parent	= &pdev->dev;
	i2c_imx->adapter.nr		= pdev->id;
	i2c_imx->adapter.dev.of_node	= pdev->dev.of_node;
Darius Augulis's avatar
Darius Augulis committed
	i2c_imx->base			= base;
	ACPI_COMPANION_SET(&i2c_imx->adapter.dev, ACPI_COMPANION(&pdev->dev));
Darius Augulis's avatar
Darius Augulis committed

	/* Get I2C clock */
	i2c_imx->clk = devm_clk_get(&pdev->dev, NULL);
	if (IS_ERR(i2c_imx->clk))
		return dev_err_probe(&pdev->dev, PTR_ERR(i2c_imx->clk),
				     "can't get I2C clock\n");
	ret = clk_prepare_enable(i2c_imx->clk);
	if (ret) {
		dev_err(&pdev->dev, "can't enable I2C clock, ret=%d\n", ret);
Darius Augulis's avatar
Darius Augulis committed
	/* Init queue */
	init_waitqueue_head(&i2c_imx->queue);

	/* Set up adapter data */
	i2c_set_adapdata(&i2c_imx->adapter, i2c_imx);

	/* Set up platform driver data */
	platform_set_drvdata(pdev, i2c_imx);

	pm_runtime_set_autosuspend_delay(&pdev->dev, I2C_PM_TIMEOUT);
	pm_runtime_use_autosuspend(&pdev->dev);
	pm_runtime_set_active(&pdev->dev);
	pm_runtime_enable(&pdev->dev);

	ret = pm_runtime_get_sync(&pdev->dev);
	if (ret < 0)
		goto rpm_disable;

	ret = request_threaded_irq(irq, i2c_imx_isr, NULL,
				   IRQF_SHARED | IRQF_NO_SUSPEND,
				   pdev->name, i2c_imx);
	if (ret) {
		dev_err(&pdev->dev, "can't claim irq %d\n", irq);
		goto rpm_disable;
	}

Darius Augulis's avatar
Darius Augulis committed
	/* Set up clock divider */
	i2c_imx->bitrate = I2C_MAX_STANDARD_MODE_FREQ;
	ret = of_property_read_u32(pdev->dev.of_node,
				   "clock-frequency", &i2c_imx->bitrate);
	if (ret < 0 && pdata && pdata->bitrate)
		i2c_imx->bitrate = pdata->bitrate;
	i2c_imx->clk_change_nb.notifier_call = i2c_imx_clk_notifier_call;
	clk_notifier_register(i2c_imx->clk, &i2c_imx->clk_change_nb);
	ret = i2c_imx_set_clk(i2c_imx, clk_get_rate(i2c_imx->clk));
	if (ret < 0) {
		dev_err(&pdev->dev, "can't get I2C clock\n");
		goto clk_notifier_unregister;
	}
	/*
	 * This limit caused by an i.MX7D hardware issue(e7805 in Errata).
	 * If there is no limit, when the bitrate set up to 400KHz, it will
	 * cause the SCK low level period less than 1.3us.
	 */
	if (is_imx7d_i2c(i2c_imx) && i2c_imx->bitrate > IMX_I2C_MAX_E_BIT_RATE)
		i2c_imx->bitrate = IMX_I2C_MAX_E_BIT_RATE;

	i2c_imx_reset_regs(i2c_imx);
	/* Init optional bus recovery */
	if (of_match_node(pinmux_of_match, pdev->dev.of_node))
		ret = i2c_imx_init_recovery_for_layerscape(i2c_imx, pdev);
	else
		ret = i2c_imx_init_recovery_info(i2c_imx, pdev);

	/* Give it another chance if pinctrl used is not ready yet */
	if (ret == -EPROBE_DEFER)
		goto clk_notifier_unregister;
Darius Augulis's avatar
Darius Augulis committed
	/* Add I2C adapter */
	ret = i2c_add_numbered_adapter(&i2c_imx->adapter);
		goto clk_notifier_unregister;
	pm_runtime_mark_last_busy(&pdev->dev);
	pm_runtime_put_autosuspend(&pdev->dev);
	dev_dbg(&i2c_imx->adapter.dev, "claimed irq %d\n", irq);
	dev_dbg(&i2c_imx->adapter.dev, "device resources: %pR\n", res);
Darius Augulis's avatar
Darius Augulis committed
	dev_dbg(&i2c_imx->adapter.dev, "adapter name: \"%s\"\n",
		i2c_imx->adapter.name);
	dev_info(&i2c_imx->adapter.dev, "IMX I2C adapter registered\n");
	/* Init DMA config if supported */
	ret = i2c_imx_dma_request(i2c_imx, phy_addr);
	if (ret == -EPROBE_DEFER)
		goto i2c_adapter_remove;
Darius Augulis's avatar
Darius Augulis committed
	return 0;   /* Return OK */
i2c_adapter_remove:
	i2c_del_adapter(&i2c_imx->adapter);
clk_notifier_unregister:
	clk_notifier_unregister(i2c_imx->clk, &i2c_imx->clk_change_nb);
rpm_disable:
	pm_runtime_put_noidle(&pdev->dev);
	pm_runtime_disable(&pdev->dev);
	pm_runtime_set_suspended(&pdev->dev);
	pm_runtime_dont_use_autosuspend(&pdev->dev);
	clk_disable_unprepare(i2c_imx->clk);
	return ret;
static int i2c_imx_remove(struct platform_device *pdev)
Darius Augulis's avatar
Darius Augulis committed
{
	struct imx_i2c_struct *i2c_imx = platform_get_drvdata(pdev);

	ret = pm_runtime_get_sync(&pdev->dev);
	if (ret < 0)
		return ret;
Darius Augulis's avatar
Darius Augulis committed

	/* remove adapter */
	dev_dbg(&i2c_imx->adapter.dev, "adapter removed\n");
	i2c_del_adapter(&i2c_imx->adapter);

	if (i2c_imx->dma)
		i2c_imx_dma_free(i2c_imx);

Darius Augulis's avatar
Darius Augulis committed
	/* setup chip registers to defaults */
	imx_i2c_write_reg(0, i2c_imx, IMX_I2C_IADR);
	imx_i2c_write_reg(0, i2c_imx, IMX_I2C_IFDR);
	imx_i2c_write_reg(0, i2c_imx, IMX_I2C_I2CR);
	imx_i2c_write_reg(0, i2c_imx, IMX_I2C_I2SR);
	clk_notifier_unregister(i2c_imx->clk, &i2c_imx->clk_change_nb);
	irq = platform_get_irq(pdev, 0);
	if (irq >= 0)
		free_irq(irq, i2c_imx);
	clk_disable_unprepare(i2c_imx->clk);

	pm_runtime_put_noidle(&pdev->dev);
	pm_runtime_disable(&pdev->dev);

	return 0;
}

static int __maybe_unused i2c_imx_runtime_suspend(struct device *dev)
	struct imx_i2c_struct *i2c_imx = dev_get_drvdata(dev);
	clk_disable_unprepare(i2c_imx->clk);
	pinctrl_pm_select_sleep_state(dev);
Darius Augulis's avatar
Darius Augulis committed
	return 0;
}

static int __maybe_unused i2c_imx_runtime_resume(struct device *dev)
	struct imx_i2c_struct *i2c_imx = dev_get_drvdata(dev);
	pinctrl_pm_select_default_state(dev);
	ret = clk_prepare_enable(i2c_imx->clk);
	if (ret)
		dev_err(dev, "can't enable I2C clock, ret=%d\n", ret);

	return ret;
}

static int i2c_imx_suspend(struct device *dev)
{
	pinctrl_pm_select_sleep_state(dev);
	return 0;
}

static int i2c_imx_resume(struct device *dev)
{
	pinctrl_pm_select_default_state(dev);
	return 0;
}

static const struct dev_pm_ops i2c_imx_pm_ops = {
	SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(i2c_imx_suspend, i2c_imx_resume)
	SET_RUNTIME_PM_OPS(i2c_imx_runtime_suspend,
			   i2c_imx_runtime_resume, NULL)
};

Darius Augulis's avatar
Darius Augulis committed
static struct platform_driver i2c_imx_driver = {
	.probe = i2c_imx_probe,
	.remove = i2c_imx_remove,
	.driver = {
		.name = DRIVER_NAME,
		.pm = &i2c_imx_pm_ops,
		.of_match_table = i2c_imx_dt_ids,
		.acpi_match_table = i2c_imx_acpi_ids,
	.id_table = imx_i2c_devtype,
Darius Augulis's avatar
Darius Augulis committed
};

static int __init i2c_adap_imx_init(void)
{
	return platform_driver_register(&i2c_imx_driver);
Darius Augulis's avatar
Darius Augulis committed
}
subsys_initcall(i2c_adap_imx_init);
Darius Augulis's avatar
Darius Augulis committed

static void __exit i2c_adap_imx_exit(void)
{
	platform_driver_unregister(&i2c_imx_driver);
}
module_exit(i2c_adap_imx_exit);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("Darius Augulis");
MODULE_DESCRIPTION("I2C adapter driver for IMX I2C bus");
MODULE_ALIAS("platform:" DRIVER_NAME);