diff options
Diffstat (limited to 'drivers/i2c/busses/i2c-qcom-cci.c')
| -rw-r--r-- | drivers/i2c/busses/i2c-qcom-cci.c | 187 |
1 files changed, 130 insertions, 57 deletions
diff --git a/drivers/i2c/busses/i2c-qcom-cci.c b/drivers/i2c/busses/i2c-qcom-cci.c index c1de8eb66169..884055df1560 100644 --- a/drivers/i2c/busses/i2c-qcom-cci.c +++ b/drivers/i2c/busses/i2c-qcom-cci.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 // Copyright (c) 2012-2016, The Linux Foundation. All rights reserved. -// Copyright (c) 2017-20 Linaro Limited. +// Copyright (c) 2017-2022 Linaro Limited. #include <linux/clk.h> #include <linux/completion.h> @@ -120,7 +120,6 @@ struct cci_data { unsigned int num_masters; struct i2c_adapter_quirks quirks; u16 queue_size[NUM_QUEUES]; - unsigned long cci_clk_rate; struct hw_params params[3]; }; @@ -451,7 +450,6 @@ static int cci_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num) ret = num; err: - pm_runtime_mark_last_busy(cci->dev); pm_runtime_put_autosuspend(cci->dev); return ret; @@ -463,8 +461,8 @@ static u32 cci_func(struct i2c_adapter *adap) } static const struct i2c_algorithm cci_algo = { - .master_xfer = cci_xfer, - .functionality = cci_func, + .xfer = cci_xfer, + .functionality = cci_func, }; static int cci_enable_clocks(struct cci *cci) @@ -509,7 +507,6 @@ static int __maybe_unused cci_suspend(struct device *dev) static int __maybe_unused cci_resume(struct device *dev) { cci_resume_runtime(dev); - pm_runtime_mark_last_busy(dev); pm_request_autosuspend(dev); return 0; @@ -523,7 +520,6 @@ static const struct dev_pm_ops qcom_cci_pm = { static int cci_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; - unsigned long cci_clk_rate = 0; struct device_node *child; struct resource *r; struct cci *cci; @@ -541,6 +537,7 @@ static int cci_probe(struct platform_device *pdev) return -ENOENT; for_each_available_child_of_node(dev->of_node, child) { + struct cci_master *master; u32 idx; ret = of_property_read_u32(child, "reg", &idx); @@ -555,61 +552,44 @@ static int cci_probe(struct platform_device *pdev) continue; } - cci->master[idx].adap.quirks = &cci->data->quirks; - cci->master[idx].adap.algo = &cci_algo; - cci->master[idx].adap.dev.parent = dev; - cci->master[idx].adap.dev.of_node = child; - cci->master[idx].master = idx; - cci->master[idx].cci = cci; + master = &cci->master[idx]; + master->adap.quirks = &cci->data->quirks; + master->adap.algo = &cci_algo; + master->adap.dev.parent = dev; + master->adap.dev.of_node = of_node_get(child); + master->master = idx; + master->cci = cci; - i2c_set_adapdata(&cci->master[idx].adap, &cci->master[idx]); - snprintf(cci->master[idx].adap.name, - sizeof(cci->master[idx].adap.name), "Qualcomm-CCI"); + i2c_set_adapdata(&master->adap, master); + snprintf(master->adap.name, sizeof(master->adap.name), "Qualcomm-CCI"); - cci->master[idx].mode = I2C_MODE_STANDARD; + master->mode = I2C_MODE_STANDARD; ret = of_property_read_u32(child, "clock-frequency", &val); if (!ret) { if (val == I2C_MAX_FAST_MODE_FREQ) - cci->master[idx].mode = I2C_MODE_FAST; + master->mode = I2C_MODE_FAST; else if (val == I2C_MAX_FAST_MODE_PLUS_FREQ) - cci->master[idx].mode = I2C_MODE_FAST_PLUS; + master->mode = I2C_MODE_FAST_PLUS; } - init_completion(&cci->master[idx].irq_complete); + init_completion(&master->irq_complete); } /* Memory */ - r = platform_get_resource(pdev, IORESOURCE_MEM, 0); - cci->base = devm_ioremap_resource(dev, r); + cci->base = devm_platform_get_and_ioremap_resource(pdev, 0, &r); if (IS_ERR(cci->base)) return PTR_ERR(cci->base); /* Clocks */ ret = devm_clk_bulk_get_all(dev, &cci->clocks); - if (ret < 1) { - dev_err(dev, "failed to get clocks %d\n", ret); - return ret; - } + if (ret < 0) + return dev_err_probe(dev, ret, "failed to get clocks\n"); + else if (!ret) + return dev_err_probe(dev, -EINVAL, "not enough clocks in DT\n"); cci->nclocks = ret; - /* Retrieve CCI clock rate */ - for (i = 0; i < cci->nclocks; i++) { - if (!strcmp(cci->clocks[i].id, "cci")) { - cci_clk_rate = clk_get_rate(cci->clocks[i].clk); - break; - } - } - - if (cci_clk_rate != cci->data->cci_clk_rate) { - /* cci clock set by the bootloader or via assigned clock rate - * in DT. - */ - dev_warn(dev, "Found %lu cci clk rate while %lu was expected\n", - cci_clk_rate, cci->data->cci_clk_rate); - } - ret = cci_enable_clocks(cci); if (ret < 0) return ret; @@ -638,26 +618,33 @@ static int cci_probe(struct platform_device *pdev) if (ret < 0) goto error; + pm_runtime_set_autosuspend_delay(dev, MSEC_PER_SEC); + pm_runtime_use_autosuspend(dev); + pm_runtime_set_active(dev); + pm_runtime_enable(dev); + for (i = 0; i < cci->data->num_masters; i++) { if (!cci->master[i].cci) continue; ret = i2c_add_adapter(&cci->master[i].adap); - if (ret < 0) + if (ret < 0) { + of_node_put(cci->master[i].adap.dev.of_node); goto error_i2c; + } } - pm_runtime_set_autosuspend_delay(dev, MSEC_PER_SEC); - pm_runtime_use_autosuspend(dev); - pm_runtime_set_active(dev); - pm_runtime_enable(dev); - return 0; error_i2c: - for (; i >= 0; i--) { - if (cci->master[i].cci) + pm_runtime_disable(dev); + pm_runtime_dont_use_autosuspend(dev); + + for (--i ; i >= 0; i--) { + if (cci->master[i].cci) { i2c_del_adapter(&cci->master[i].adap); + of_node_put(cci->master[i].adap.dev.of_node); + } } error: disable_irq(cci->irq); @@ -667,22 +654,22 @@ disable_clocks: return ret; } -static int cci_remove(struct platform_device *pdev) +static void cci_remove(struct platform_device *pdev) { struct cci *cci = platform_get_drvdata(pdev); int i; for (i = 0; i < cci->data->num_masters; i++) { - if (cci->master[i].cci) + if (cci->master[i].cci) { i2c_del_adapter(&cci->master[i].adap); + of_node_put(cci->master[i].adap.dev.of_node); + } cci_halt(cci, i); } disable_irq(cci->irq); pm_runtime_disable(&pdev->dev); pm_runtime_set_suspended(&pdev->dev); - - return 0; } static const struct cci_data cci_v1_data = { @@ -692,7 +679,39 @@ static const struct cci_data cci_v1_data = { .max_write_len = 10, .max_read_len = 12, }, - .cci_clk_rate = 19200000, + .params[I2C_MODE_STANDARD] = { + .thigh = 78, + .tlow = 114, + .tsu_sto = 28, + .tsu_sta = 28, + .thd_dat = 10, + .thd_sta = 77, + .tbuf = 118, + .scl_stretch_en = 0, + .trdhld = 6, + .tsp = 1 + }, + .params[I2C_MODE_FAST] = { + .thigh = 20, + .tlow = 28, + .tsu_sto = 21, + .tsu_sta = 21, + .thd_dat = 13, + .thd_sta = 18, + .tbuf = 32, + .scl_stretch_en = 0, + .trdhld = 6, + .tsp = 3 + }, +}; + +static const struct cci_data cci_v1_5_data = { + .num_masters = 2, + .queue_size = { 64, 16 }, + .quirks = { + .max_write_len = 10, + .max_read_len = 12, + }, .params[I2C_MODE_STANDARD] = { .thigh = 78, .tlow = 114, @@ -726,7 +745,6 @@ static const struct cci_data cci_v2_data = { .max_write_len = 11, .max_read_len = 12, }, - .cci_clk_rate = 37500000, .params[I2C_MODE_STANDARD] = { .thigh = 201, .tlow = 174, @@ -765,11 +783,66 @@ static const struct cci_data cci_v2_data = { }, }; +static const struct cci_data cci_msm8953_data = { + .num_masters = 2, + .queue_size = { 64, 16 }, + .quirks = { + .max_write_len = 11, + .max_read_len = 12, + }, + .params[I2C_MODE_STANDARD] = { + .thigh = 78, + .tlow = 114, + .tsu_sto = 28, + .tsu_sta = 28, + .thd_dat = 10, + .thd_sta = 77, + .tbuf = 118, + .scl_stretch_en = 0, + .trdhld = 6, + .tsp = 1 + }, + .params[I2C_MODE_FAST] = { + .thigh = 20, + .tlow = 28, + .tsu_sto = 21, + .tsu_sta = 21, + .thd_dat = 13, + .thd_sta = 18, + .tbuf = 32, + .scl_stretch_en = 0, + .trdhld = 6, + .tsp = 3 + }, + .params[I2C_MODE_FAST_PLUS] = { + .thigh = 16, + .tlow = 22, + .tsu_sto = 17, + .tsu_sta = 18, + .thd_dat = 16, + .thd_sta = 15, + .tbuf = 19, + .scl_stretch_en = 1, + .trdhld = 3, + .tsp = 3 + }, +}; + static const struct of_device_id cci_dt_match[] = { - { .compatible = "qcom,msm8916-cci", .data = &cci_v1_data}, + { .compatible = "qcom,msm8226-cci", .data = &cci_v1_data}, + { .compatible = "qcom,msm8953-cci", .data = &cci_msm8953_data}, + { .compatible = "qcom,msm8974-cci", .data = &cci_v1_5_data}, { .compatible = "qcom,msm8996-cci", .data = &cci_v2_data}, + + + /* + * Legacy compatibles kept for backwards compatibility. + * Do not add any new ones unless they introduce a new config + */ + { .compatible = "qcom,msm8916-cci", .data = &cci_v1_data}, { .compatible = "qcom,sdm845-cci", .data = &cci_v2_data}, { .compatible = "qcom,sm8250-cci", .data = &cci_v2_data}, + { .compatible = "qcom,sm8450-cci", .data = &cci_v2_data}, {} }; MODULE_DEVICE_TABLE(of, cci_dt_match); |
