Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit fdee88f0 authored by Kyle Yan's avatar Kyle Yan Committed by Gerrit - the friendly Code Review server
Browse files

Merge "i2c: qcom: geni: Clock and GPIO management for GENI I2C controller" into msm-4.9

parents d4a6bba2 b44003bf
Loading
Loading
Loading
Loading
+11 −0
Original line number Diff line number Diff line
@@ -6,6 +6,10 @@ Required properties:
   * "qcom,i2c-geni.
 - reg: Should contain QUP register address and length.
 - interrupts: Should contain I2C interrupt.
 - clocks: Serial engine core clock, and AHB clocks needed by the device.
 - pinctrl-names/pinctrl-0/1: The GPIOs assigned to this core. The names
   should be "active" and "sleep" for the pin confuguration when core is active
   or when entering sleep state.
 - #address-cells: Should be <1> Address cells for i2c device address
 - #size-cells: Should be <0> as i2c addresses have no size component

@@ -17,6 +21,13 @@ i2c@a94000 {
	compatible = "qcom,i2c-geni";
	reg = <0xa94000 0x4000>;
	interrupts = <GIC_SPI 358 0>;
	clock-names = "se-clk", "m-ahb", "s-ahb";
	clocks = <&clock_gcc GCC_QUPV3_WRAP0_S5_CLK>,
		<&clock_gcc GCC_QUPV3_WRAP_0_M_AHB_CLK>,
		<&clock_gcc GCC_QUPV3_WRAP_0_S_AHB_CLK>;
	pinctrl-names = "default", "sleep";
	pinctrl-0 = <&qup_1_i2c_5_active>;
	pinctrl-1 = <&qup_1_i2c_5_sleep>;
	#address-cells = <1>;
	#size-cells = <0>;
};
+105 −10
Original line number Diff line number Diff line
@@ -21,6 +21,7 @@
#include <linux/module.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/qcom-geni-se.h>

#define SE_I2C_TX_TRANS_LEN		(0x26C)
@@ -57,6 +58,7 @@ struct geni_i2c_dev {
	struct i2c_adapter adap;
	struct completion xfer;
	struct i2c_msg *cur;
	struct se_geni_rsc i2c_rsc;
	int cur_wr;
	int cur_rd;
};
@@ -153,7 +155,15 @@ static int geni_i2c_xfer(struct i2c_adapter *adap,
	gi2c->err = 0;
	gi2c->cur = &msgs[0];
	reinit_completion(&gi2c->xfer);
	enable_irq(gi2c->irq);
	ret = pm_runtime_get_sync(gi2c->dev);
	if (ret < 0) {
		dev_err(gi2c->dev, "error turning SE resources:%d\n", ret);
		pm_runtime_put_noidle(gi2c->dev);
		/* Set device in suspended since resume failed */
		pm_runtime_set_suspended(gi2c->dev);
		return ret;
	}
	geni_se_init(gi2c->base, FIFO_MODE, 0xF, 0x10);
	qcom_geni_i2c_conf(gi2c->base, 0, 2);
	se_config_packing(gi2c->base, 8, 4, true);
	dev_dbg(gi2c->dev, "i2c xfer:num:%d, msgs:len:%d,flg:%d\n",
@@ -206,7 +216,7 @@ static int geni_i2c_xfer(struct i2c_adapter *adap,
	}
	if (ret == 0)
		ret = i;
	disable_irq(gi2c->irq);
	pm_runtime_put_sync(gi2c->dev);
	gi2c->cur = NULL;
	gi2c->err = 0;
	dev_dbg(gi2c->dev, "i2c txn ret:%d\n", ret);
@@ -239,10 +249,54 @@ static int geni_i2c_probe(struct platform_device *pdev)
	if (!res)
		return -EINVAL;

	gi2c->i2c_rsc.se_clk = devm_clk_get(&pdev->dev, "se-clk");
	if (IS_ERR(gi2c->i2c_rsc.se_clk)) {
		ret = PTR_ERR(gi2c->i2c_rsc.se_clk);
		dev_err(&pdev->dev, "Err getting SE Core clk %d\n", ret);
		return ret;
	}

	gi2c->i2c_rsc.m_ahb_clk = devm_clk_get(&pdev->dev, "m-ahb");
	if (IS_ERR(gi2c->i2c_rsc.m_ahb_clk)) {
		ret = PTR_ERR(gi2c->i2c_rsc.m_ahb_clk);
		dev_err(&pdev->dev, "Err getting M AHB clk %d\n", ret);
		return ret;
	}

	gi2c->i2c_rsc.s_ahb_clk = devm_clk_get(&pdev->dev, "s-ahb");
	if (IS_ERR(gi2c->i2c_rsc.s_ahb_clk)) {
		ret = PTR_ERR(gi2c->i2c_rsc.s_ahb_clk);
		dev_err(&pdev->dev, "Err getting S AHB clk %d\n", ret);
		return ret;
	}

	gi2c->base = devm_ioremap_resource(gi2c->dev, res);
	if (IS_ERR(gi2c->base))
		return PTR_ERR(gi2c->base);

	gi2c->i2c_rsc.geni_pinctrl = devm_pinctrl_get(&pdev->dev);
	if (IS_ERR_OR_NULL(gi2c->i2c_rsc.geni_pinctrl)) {
		dev_err(&pdev->dev, "No pinctrl config specified\n");
		ret = PTR_ERR(gi2c->i2c_rsc.geni_pinctrl);
		return ret;
	}
	gi2c->i2c_rsc.geni_gpio_active =
		pinctrl_lookup_state(gi2c->i2c_rsc.geni_pinctrl,
							PINCTRL_DEFAULT);
	if (IS_ERR_OR_NULL(gi2c->i2c_rsc.geni_gpio_active)) {
		dev_err(&pdev->dev, "No default config specified\n");
		ret = PTR_ERR(gi2c->i2c_rsc.geni_gpio_active);
		return ret;
	}
	gi2c->i2c_rsc.geni_gpio_sleep =
		pinctrl_lookup_state(gi2c->i2c_rsc.geni_pinctrl,
							PINCTRL_SLEEP);
	if (IS_ERR_OR_NULL(gi2c->i2c_rsc.geni_gpio_sleep)) {
		dev_err(&pdev->dev, "No sleep config specified\n");
		ret = PTR_ERR(gi2c->i2c_rsc.geni_gpio_sleep);
		return ret;
	}

	gi2c->irq = platform_get_irq(pdev, 0);
	if (gi2c->irq < 0) {
		dev_err(gi2c->dev, "IRQ error for i2c-geni\n");
@@ -266,8 +320,9 @@ static int geni_i2c_probe(struct platform_device *pdev)

	strlcpy(gi2c->adap.name, "Geni-I2C", sizeof(gi2c->adap.name));

	pm_runtime_set_suspended(gi2c->dev);
	pm_runtime_enable(gi2c->dev);
	i2c_add_adapter(&gi2c->adap);
	geni_se_init(gi2c->base, FIFO_MODE, 0xF, 0x10);

	return 0;
}
@@ -276,27 +331,67 @@ static int geni_i2c_remove(struct platform_device *pdev)
{
	struct geni_i2c_dev *gi2c = platform_get_drvdata(pdev);

	disable_irq(gi2c->irq);
	pm_runtime_disable(gi2c->dev);
	i2c_del_adapter(&gi2c->adap);
	return 0;
}

#ifdef CONFIG_PM_SLEEP
static int geni_i2c_suspend(struct device *device)
static int geni_i2c_resume_noirq(struct device *device)
{
	return 0;
}

#ifdef CONFIG_PM
static int geni_i2c_runtime_suspend(struct device *dev)
{
	struct geni_i2c_dev *gi2c = dev_get_drvdata(dev);

	disable_irq(gi2c->irq);
	se_geni_resources_off(&gi2c->i2c_rsc);
	return 0;
}

static int geni_i2c_runtime_resume(struct device *dev)
{
	int ret;
	struct geni_i2c_dev *gi2c = dev_get_drvdata(dev);

	ret = se_geni_resources_on(&gi2c->i2c_rsc);
	if (ret)
		return ret;

	enable_irq(gi2c->irq);
	return 0;
}

static int geni_i2c_suspend_noirq(struct device *device)
{
	if (!pm_runtime_status_suspended(device))
		return -EBUSY;
	return 0;
}
#else
static int geni_i2c_runtime_suspend(struct device *dev)
{
	return 0;
}

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

static int geni_i2c_resume(struct device *device)
static int geni_i2c_suspend_noirq(struct device *device)
{
	return 0;
}
#endif

static const struct dev_pm_ops geni_i2c_pm_ops = {
	SET_SYSTEM_SLEEP_PM_OPS(
		geni_i2c_suspend,
		geni_i2c_resume)
	.suspend_noirq		= geni_i2c_suspend_noirq,
	.resume_noirq		= geni_i2c_resume_noirq,
	.runtime_suspend	= geni_i2c_runtime_suspend,
	.runtime_resume		= geni_i2c_runtime_resume,
};

static const struct of_device_id geni_i2c_dt_match[] = {