From d415a6ce86aec8fe57615cabd0e17c188cb634b0 Mon Sep 17 00:00:00 2001 From: David Wu Date: Mon, 25 Jul 2022 12:21:18 +0800 Subject: [PATCH] i2c: rk3x: Add acpi support for rk3x Use acpi_device_uid() to get i2c bus number for acpi device. Signed-off-by: David Wu Change-Id: Ib7dabbbd2bd781962ee822e6b9b1f12c962aa5e2 --- drivers/i2c/busses/i2c-rk3x.c | 115 ++++++++++++++++++++++++---------- 1 file changed, 82 insertions(+), 33 deletions(-) diff --git a/drivers/i2c/busses/i2c-rk3x.c b/drivers/i2c/busses/i2c-rk3x.c index ce4adafc46a3..17766c20779e 100644 --- a/drivers/i2c/busses/i2c-rk3x.c +++ b/drivers/i2c/busses/i2c-rk3x.c @@ -6,6 +6,7 @@ * based on the patches by Rockchip Inc. */ +#include #include #include #include @@ -1315,6 +1316,45 @@ static unsigned int rk3x_i2c_get_version(struct rk3x_i2c *i2c) return version; } +static int rk3x_i2c_of_get_bus_id(struct device *dev, struct rk3x_i2c *priv) +{ + int bus_id = -1; + + if (IS_ENABLED(CONFIG_OF) && dev->of_node) + bus_id = of_alias_get_id(dev->of_node, "i2c"); + + return bus_id; +} + +#ifdef CONFIG_ACPI +static int rk3x_i2c_acpi_get_bus_id(struct device *dev, struct rk3x_i2c *priv) +{ + struct acpi_device *adev; + unsigned long bus_id = -1; + const char *uid; + int ret; + + adev = ACPI_COMPANION(dev); + if (!adev) + return -ENXIO; + + uid = acpi_device_uid(adev); + if (!uid || !(*uid)) { + dev_err(dev, "Cannot retrieve UID\n"); + return -ENODEV; + } + + ret = kstrtoul(uid, 0, &bus_id); + + return !ret ? bus_id : -ERANGE; +} +#else +static int rk3x_i2c_acpi_get_bus_id(struct device *dev, struct rk3x_i2c *priv) +{ + return -ENOENT; +} +#endif /* CONFIG_ACPI */ + static __maybe_unused int rk3x_i2c_suspend_noirq(struct device *dev) { struct rk3x_i2c *i2c = dev_get_drvdata(dev); @@ -1435,8 +1475,8 @@ static void rk3x_i2c_tb_cb(void *data) static int rk3x_i2c_probe(struct platform_device *pdev) { + struct fwnode_handle *fw = dev_fwnode(&pdev->dev); struct device_node *np = pdev->dev.of_node; - const struct of_device_id *match; struct rk3x_i2c *i2c; int ret = 0; u32 value; @@ -1447,8 +1487,16 @@ static int rk3x_i2c_probe(struct platform_device *pdev) if (!i2c) return -ENOMEM; - match = of_match_node(rk3x_i2c_match, np); - i2c->soc_data = match->data; + i2c->soc_data = (struct rk3x_i2c_soc_data *)device_get_match_data(&pdev->dev); + + ret = rk3x_i2c_acpi_get_bus_id(&pdev->dev, i2c); + if (ret < 0) { + ret = rk3x_i2c_of_get_bus_id(&pdev->dev, i2c); + if (ret < 0) + return ret; + } + + i2c->adap.nr = ret; /* use common interface to get I2C timing properties */ i2c_parse_fw_timings(&pdev->dev, &i2c->t, true); @@ -1457,9 +1505,10 @@ static int rk3x_i2c_probe(struct platform_device *pdev) i2c->adap.owner = THIS_MODULE; i2c->adap.algo = &rk3x_i2c_algorithm; i2c->adap.retries = 3; - i2c->adap.dev.of_node = np; + i2c->adap.dev.of_node = pdev->dev.of_node; i2c->adap.algo_data = i2c; i2c->adap.dev.parent = &pdev->dev; + i2c->adap.dev.fwnode = fw; i2c->dev = &pdev->dev; @@ -1487,14 +1536,7 @@ static int rk3x_i2c_probe(struct platform_device *pdev) grf = syscon_regmap_lookup_by_phandle(np, "rockchip,grf"); if (!IS_ERR(grf)) { - int bus_nr; - - /* Try to set the I2C adapter number from dt */ - bus_nr = of_alias_get_id(np, "i2c"); - if (bus_nr < 0) { - dev_err(&pdev->dev, "rk3x-i2c needs i2cX alias"); - return -EINVAL; - } + int bus_nr = i2c->adap.nr; if (i2c->soc_data == &rv1108_soc_data && bus_nr == 2) /* rv1108 i2c2 set grf offset-0x408, bit-10 */ @@ -1541,23 +1583,25 @@ static int rk3x_i2c_probe(struct platform_device *pdev) platform_set_drvdata(pdev, i2c); - if (i2c->soc_data->calc_timings == rk3x_i2c_v0_calc_timings) { - /* Only one clock to use for bus clock and peripheral clock */ - i2c->clk = devm_clk_get(&pdev->dev, NULL); - i2c->pclk = i2c->clk; - } else { - i2c->clk = devm_clk_get(&pdev->dev, "i2c"); - i2c->pclk = devm_clk_get(&pdev->dev, "pclk"); + if (!has_acpi_companion(&pdev->dev)) { + if (i2c->soc_data->calc_timings == rk3x_i2c_v0_calc_timings) { + /* Only one clock to use for bus clock and peripheral clock */ + i2c->clk = devm_clk_get(&pdev->dev, NULL); + i2c->pclk = i2c->clk; + } else { + i2c->clk = devm_clk_get(&pdev->dev, "i2c"); + i2c->pclk = devm_clk_get(&pdev->dev, "pclk"); + } + + if (IS_ERR(i2c->clk)) + return dev_err_probe(&pdev->dev, PTR_ERR(i2c->clk), + "Can't get bus clk\n"); + + if (IS_ERR(i2c->pclk)) + return dev_err_probe(&pdev->dev, PTR_ERR(i2c->pclk), + "Can't get periph clk\n"); } - if (IS_ERR(i2c->clk)) - return dev_err_probe(&pdev->dev, PTR_ERR(i2c->clk), - "Can't get bus clk\n"); - - if (IS_ERR(i2c->pclk)) - return dev_err_probe(&pdev->dev, PTR_ERR(i2c->pclk), - "Can't get periph clk\n"); - ret = clk_prepare(i2c->clk); if (ret < 0) { dev_err(&pdev->dev, "Can't prepare bus clk: %d\n", ret); @@ -1569,20 +1613,25 @@ static int rk3x_i2c_probe(struct platform_device *pdev) goto err_clk; } - i2c->clk_rate_nb.notifier_call = rk3x_i2c_clk_notifier_cb; - ret = clk_notifier_register(i2c->clk, &i2c->clk_rate_nb); - if (ret != 0) { - dev_err(&pdev->dev, "Unable to register clock notifier\n"); - goto err_pclk; + if (i2c->clk) { + i2c->clk_rate_nb.notifier_call = rk3x_i2c_clk_notifier_cb; + ret = clk_notifier_register(i2c->clk, &i2c->clk_rate_nb); + if (ret != 0) { + dev_err(&pdev->dev, "Unable to register clock notifier\n"); + goto err_pclk; + } } clk_rate = clk_get_rate(i2c->clk); + if (!clk_rate) + device_property_read_u32(&pdev->dev, "i2c,clk-rate", (u32 *)&clk_rate); + rk3x_i2c_adapt_div(i2c, clk_rate); if (rk3x_i2c_get_version(i2c) >= RK_I2C_VERSION5) i2c->autostop_supported = true; - ret = i2c_add_adapter(&i2c->adap); + ret = i2c_add_numbered_adapter(&i2c->adap); if (ret < 0) goto err_clk_notifier;