From a3e9625ec0c523cba3847ae21c382ae745e71d19 Mon Sep 17 00:00:00 2001 From: Jinjie Ruan Date: Fri, 25 Aug 2023 18:57:44 +0800 Subject: [PATCH 001/326] iio: adc: mt6577_auxadc: Use devm_clk_get_enabled() helper function The devm_clk_get_enabled() helper: - calls devm_clk_get() - calls clk_prepare_enable() and registers what is needed in order to call clk_disable_unprepare() when needed, as a managed resource. This simplifies the code. Signed-off-by: Jinjie Ruan Link: https://lore.kernel.org/r/20230825105746.2999548-3-ruanjinjie@huawei.com Signed-off-by: Jonathan Cameron --- drivers/iio/adc/mt6577_auxadc.c | 17 +++-------------- 1 file changed, 3 insertions(+), 14 deletions(-) diff --git a/drivers/iio/adc/mt6577_auxadc.c b/drivers/iio/adc/mt6577_auxadc.c index 0e134777bdd2..ea42fd7a8c99 100644 --- a/drivers/iio/adc/mt6577_auxadc.c +++ b/drivers/iio/adc/mt6577_auxadc.c @@ -270,23 +270,16 @@ static int mt6577_auxadc_probe(struct platform_device *pdev) return PTR_ERR(adc_dev->reg_base); } - adc_dev->adc_clk = devm_clk_get(&pdev->dev, "main"); + adc_dev->adc_clk = devm_clk_get_enabled(&pdev->dev, "main"); if (IS_ERR(adc_dev->adc_clk)) { - dev_err(&pdev->dev, "failed to get auxadc clock\n"); - return PTR_ERR(adc_dev->adc_clk); - } - - ret = clk_prepare_enable(adc_dev->adc_clk); - if (ret) { dev_err(&pdev->dev, "failed to enable auxadc clock\n"); - return ret; + return PTR_ERR(adc_dev->adc_clk); } adc_clk_rate = clk_get_rate(adc_dev->adc_clk); if (!adc_clk_rate) { - ret = -EINVAL; dev_err(&pdev->dev, "null clock rate\n"); - goto err_disable_clk; + return -EINVAL; } adc_dev->dev_comp = device_get_match_data(&pdev->dev); @@ -310,8 +303,6 @@ static int mt6577_auxadc_probe(struct platform_device *pdev) err_power_off: mt6577_auxadc_mod_reg(adc_dev->reg_base + MT6577_AUXADC_MISC, 0, MT6577_AUXADC_PDN_EN); -err_disable_clk: - clk_disable_unprepare(adc_dev->adc_clk); return ret; } @@ -325,8 +316,6 @@ static int mt6577_auxadc_remove(struct platform_device *pdev) mt6577_auxadc_mod_reg(adc_dev->reg_base + MT6577_AUXADC_MISC, 0, MT6577_AUXADC_PDN_EN); - clk_disable_unprepare(adc_dev->adc_clk); - return 0; } From 3878ae2a1a7636be7009e20b48d4fc00adab8cf4 Mon Sep 17 00:00:00 2001 From: Jinjie Ruan Date: Sat, 26 Aug 2023 14:27:31 +0800 Subject: [PATCH 002/326] iio: adc: spear_adc: Use device managed function The devm_clk_get_enabled() helper: - calls devm_clk_get() - calls clk_prepare_enable() and registers what is needed in order to call clk_disable_unprepare() when needed, as a managed resource. Switch to devm_iio_device_register() and drop the remove function. This simplifies the code. Signed-off-by: Jinjie Ruan Link: https://lore.kernel.org/r/20230826062733.3714169-2-ruanjinjie@huawei.com Signed-off-by: Jonathan Cameron --- drivers/iio/adc/spear_adc.c | 43 +++++++------------------------------ 1 file changed, 8 insertions(+), 35 deletions(-) diff --git a/drivers/iio/adc/spear_adc.c b/drivers/iio/adc/spear_adc.c index ad54ef798109..d24adacfdf53 100644 --- a/drivers/iio/adc/spear_adc.c +++ b/drivers/iio/adc/spear_adc.c @@ -297,36 +297,27 @@ static int spear_adc_probe(struct platform_device *pdev) st->adc_base_spear3xx = (struct adc_regs_spear3xx __iomem *)st->adc_base_spear6xx; - st->clk = devm_clk_get(dev, NULL); + st->clk = devm_clk_get_enabled(dev, NULL); if (IS_ERR(st->clk)) { - dev_err(dev, "failed getting clock\n"); + dev_err(dev, "failed enabling clock\n"); return PTR_ERR(st->clk); } - ret = clk_prepare_enable(st->clk); - if (ret) { - dev_err(dev, "failed enabling clock\n"); - return ret; - } - irq = platform_get_irq(pdev, 0); - if (irq < 0) { - ret = irq; - goto errout2; - } + if (irq < 0) + return irq; ret = devm_request_irq(dev, irq, spear_adc_isr, 0, SPEAR_ADC_MOD_NAME, st); if (ret < 0) { dev_err(dev, "failed requesting interrupt\n"); - goto errout2; + return ret; } if (of_property_read_u32(np, "sampling-frequency", &st->sampling_freq)) { dev_err(dev, "sampling-frequency missing in DT\n"); - ret = -EINVAL; - goto errout2; + return -EINVAL; } /* @@ -343,8 +334,6 @@ static int spear_adc_probe(struct platform_device *pdev) spear_adc_configure(st); - platform_set_drvdata(pdev, indio_dev); - init_completion(&st->completion); indio_dev->name = SPEAR_ADC_MOD_NAME; @@ -353,27 +342,12 @@ static int spear_adc_probe(struct platform_device *pdev) indio_dev->channels = spear_adc_iio_channels; indio_dev->num_channels = ARRAY_SIZE(spear_adc_iio_channels); - ret = iio_device_register(indio_dev); + ret = devm_iio_device_register(dev, indio_dev); if (ret) - goto errout2; + return ret; dev_info(dev, "SPEAR ADC driver loaded, IRQ %d\n", irq); - return 0; - -errout2: - clk_disable_unprepare(st->clk); - return ret; -} - -static int spear_adc_remove(struct platform_device *pdev) -{ - struct iio_dev *indio_dev = platform_get_drvdata(pdev); - struct spear_adc_state *st = iio_priv(indio_dev); - - iio_device_unregister(indio_dev); - clk_disable_unprepare(st->clk); - return 0; } @@ -387,7 +361,6 @@ MODULE_DEVICE_TABLE(of, spear_adc_dt_ids); static struct platform_driver spear_adc_driver = { .probe = spear_adc_probe, - .remove = spear_adc_remove, .driver = { .name = SPEAR_ADC_MOD_NAME, .of_match_table = of_match_ptr(spear_adc_dt_ids), From b564b99de79cdc87008dab3b19ae67a011f3f2fa Mon Sep 17 00:00:00 2001 From: Jinjie Ruan Date: Sat, 26 Aug 2023 14:27:32 +0800 Subject: [PATCH 003/326] iio: adc: spear_adc: Use dev_err_probe() Use the dev_err_probe() helper to simplify error handling during probe. This also handle scenario, when EDEFER is returned and useless error is printed. Signed-off-by: Jinjie Ruan Link: https://lore.kernel.org/r/20230826062733.3714169-3-ruanjinjie@huawei.com Signed-off-by: Jonathan Cameron --- drivers/iio/adc/spear_adc.c | 27 +++++++++++---------------- 1 file changed, 11 insertions(+), 16 deletions(-) diff --git a/drivers/iio/adc/spear_adc.c b/drivers/iio/adc/spear_adc.c index d24adacfdf53..71362c2ddf89 100644 --- a/drivers/iio/adc/spear_adc.c +++ b/drivers/iio/adc/spear_adc.c @@ -274,10 +274,9 @@ static int spear_adc_probe(struct platform_device *pdev) int irq; indio_dev = devm_iio_device_alloc(dev, sizeof(struct spear_adc_state)); - if (!indio_dev) { - dev_err(dev, "failed allocating iio device\n"); - return -ENOMEM; - } + if (!indio_dev) + return dev_err_probe(dev, -ENOMEM, + "failed allocating iio device\n"); st = iio_priv(indio_dev); @@ -298,10 +297,9 @@ static int spear_adc_probe(struct platform_device *pdev) (struct adc_regs_spear3xx __iomem *)st->adc_base_spear6xx; st->clk = devm_clk_get_enabled(dev, NULL); - if (IS_ERR(st->clk)) { - dev_err(dev, "failed enabling clock\n"); - return PTR_ERR(st->clk); - } + if (IS_ERR(st->clk)) + return dev_err_probe(dev, PTR_ERR(st->clk), + "failed enabling clock\n"); irq = platform_get_irq(pdev, 0); if (irq < 0) @@ -309,16 +307,13 @@ static int spear_adc_probe(struct platform_device *pdev) ret = devm_request_irq(dev, irq, spear_adc_isr, 0, SPEAR_ADC_MOD_NAME, st); - if (ret < 0) { - dev_err(dev, "failed requesting interrupt\n"); - return ret; - } + if (ret < 0) + return dev_err_probe(dev, ret, "failed requesting interrupt\n"); if (of_property_read_u32(np, "sampling-frequency", - &st->sampling_freq)) { - dev_err(dev, "sampling-frequency missing in DT\n"); - return -EINVAL; - } + &st->sampling_freq)) + return dev_err_probe(dev, -EINVAL, + "sampling-frequency missing in DT\n"); /* * Optional avg_samples defaults to 0, resulting in single data From 8cbba23e43eb182c75656c0dba40f890feea6400 Mon Sep 17 00:00:00 2001 From: Jinjie Ruan Date: Sat, 26 Aug 2023 11:54:01 +0800 Subject: [PATCH 004/326] iio: adc: mt6577_auxadc: Simplify with dev_err_probe() Use the dev_err_probe() helper to simplify error handling during probe. This also handle scenario, when EDEFER is returned and useless error is printed. Signed-off-by: Jinjie Ruan Suggested-by: Jonathan Cameron Link: https://lore.kernel.org/r/20230826035402.3512033-2-ruanjinjie@huawei.com Signed-off-by: Jonathan Cameron --- drivers/iio/adc/mt6577_auxadc.c | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/drivers/iio/adc/mt6577_auxadc.c b/drivers/iio/adc/mt6577_auxadc.c index ea42fd7a8c99..935cf560e238 100644 --- a/drivers/iio/adc/mt6577_auxadc.c +++ b/drivers/iio/adc/mt6577_auxadc.c @@ -265,22 +265,18 @@ static int mt6577_auxadc_probe(struct platform_device *pdev) indio_dev->num_channels = ARRAY_SIZE(mt6577_auxadc_iio_channels); adc_dev->reg_base = devm_platform_ioremap_resource(pdev, 0); - if (IS_ERR(adc_dev->reg_base)) { - dev_err(&pdev->dev, "failed to get auxadc base address\n"); - return PTR_ERR(adc_dev->reg_base); - } + if (IS_ERR(adc_dev->reg_base)) + return dev_err_probe(&pdev->dev, PTR_ERR(adc_dev->reg_base), + "failed to get auxadc base address\n"); adc_dev->adc_clk = devm_clk_get_enabled(&pdev->dev, "main"); - if (IS_ERR(adc_dev->adc_clk)) { - dev_err(&pdev->dev, "failed to enable auxadc clock\n"); - return PTR_ERR(adc_dev->adc_clk); - } + if (IS_ERR(adc_dev->adc_clk)) + return dev_err_probe(&pdev->dev, PTR_ERR(adc_dev->adc_clk), + "failed to enable auxadc clock\n"); adc_clk_rate = clk_get_rate(adc_dev->adc_clk); - if (!adc_clk_rate) { - dev_err(&pdev->dev, "null clock rate\n"); - return -EINVAL; - } + if (!adc_clk_rate) + return dev_err_probe(&pdev->dev, -EINVAL, "null clock rate\n"); adc_dev->dev_comp = device_get_match_data(&pdev->dev); From a2d518fbe3760f66576a5c4f627aa3f126271c8b Mon Sep 17 00:00:00 2001 From: Jinjie Ruan Date: Sat, 26 Aug 2023 11:54:02 +0800 Subject: [PATCH 005/326] iio: adc: mt6577_auxadc: Simplify with device managed function Add a device managed hook, via devm_add_action_or_reset() and mt6577_power_off(), to power off on device detach. Replace iio_device_register() by devm_iio_device_register() and remove the mt6577_auxadc_remove() function used to unregister the device and power off the device. Remove platform_set_drvdata() from the probe function, since platform_get_drvdata() is not used anymore. Remove mt6577_auxadc_mod_reg() call from the probe function error path. Signed-off-by: Jinjie Ruan Link: https://lore.kernel.org/r/20230826035402.3512033-3-ruanjinjie@huawei.com Signed-off-by: Jonathan Cameron --- drivers/iio/adc/mt6577_auxadc.c | 40 +++++++++++++-------------------- 1 file changed, 15 insertions(+), 25 deletions(-) diff --git a/drivers/iio/adc/mt6577_auxadc.c b/drivers/iio/adc/mt6577_auxadc.c index 935cf560e238..370b84c2d0ba 100644 --- a/drivers/iio/adc/mt6577_auxadc.c +++ b/drivers/iio/adc/mt6577_auxadc.c @@ -246,6 +246,14 @@ static int mt6577_auxadc_suspend(struct device *dev) return 0; } +static void mt6577_power_off(void *data) +{ + struct mt6577_auxadc_device *adc_dev = data; + + mt6577_auxadc_mod_reg(adc_dev->reg_base + MT6577_AUXADC_MISC, + 0, MT6577_AUXADC_PDN_EN); +} + static int mt6577_auxadc_probe(struct platform_device *pdev) { struct mt6577_auxadc_device *adc_dev; @@ -286,31 +294,14 @@ static int mt6577_auxadc_probe(struct platform_device *pdev) MT6577_AUXADC_PDN_EN, 0); mdelay(MT6577_AUXADC_POWER_READY_MS); - platform_set_drvdata(pdev, indio_dev); + ret = devm_add_action_or_reset(&pdev->dev, mt6577_power_off, adc_dev); + if (ret) + return dev_err_probe(&pdev->dev, ret, + "Failed to add action to managed power off\n"); - ret = iio_device_register(indio_dev); - if (ret < 0) { - dev_err(&pdev->dev, "failed to register iio device\n"); - goto err_power_off; - } - - return 0; - -err_power_off: - mt6577_auxadc_mod_reg(adc_dev->reg_base + MT6577_AUXADC_MISC, - 0, MT6577_AUXADC_PDN_EN); - return ret; -} - -static int mt6577_auxadc_remove(struct platform_device *pdev) -{ - struct iio_dev *indio_dev = platform_get_drvdata(pdev); - struct mt6577_auxadc_device *adc_dev = iio_priv(indio_dev); - - iio_device_unregister(indio_dev); - - mt6577_auxadc_mod_reg(adc_dev->reg_base + MT6577_AUXADC_MISC, - 0, MT6577_AUXADC_PDN_EN); + ret = devm_iio_device_register(&pdev->dev, indio_dev); + if (ret < 0) + return dev_err_probe(&pdev->dev, ret, "failed to register iio device\n"); return 0; } @@ -337,7 +328,6 @@ static struct platform_driver mt6577_auxadc_driver = { .pm = pm_sleep_ptr(&mt6577_auxadc_pm_ops), }, .probe = mt6577_auxadc_probe, - .remove = mt6577_auxadc_remove, }; module_platform_driver(mt6577_auxadc_driver); From 5ff46635e4c51a2aeafb50a06c36bfdd0cda4203 Mon Sep 17 00:00:00 2001 From: Jinjie Ruan Date: Fri, 25 Aug 2023 17:56:12 +0800 Subject: [PATCH 006/326] staging: iio: Use devm_clk_get_enabled() helper function The devm_clk_get_enabled() helper: - calls devm_clk_get() - calls clk_prepare_enable() and registers what is needed in order to call clk_disable_unprepare() when needed, as a managed resource. This simplifies the code and avoids the need of a dedicated function used with devm_add_action_or_reset(). Signed-off-by: Jinjie Ruan Link: https://lore.kernel.org/r/20230825095612.2972892-1-ruanjinjie@huawei.com Signed-off-by: Jonathan Cameron --- drivers/staging/iio/frequency/ad9832.c | 15 +------------ drivers/staging/iio/frequency/ad9834.c | 21 ++---------------- .../staging/iio/impedance-analyzer/ad5933.c | 22 ++----------------- 3 files changed, 5 insertions(+), 53 deletions(-) diff --git a/drivers/staging/iio/frequency/ad9832.c b/drivers/staging/iio/frequency/ad9832.c index 6f9eebd6c7ee..6c390c4eb26d 100644 --- a/drivers/staging/iio/frequency/ad9832.c +++ b/drivers/staging/iio/frequency/ad9832.c @@ -299,11 +299,6 @@ static void ad9832_reg_disable(void *reg) regulator_disable(reg); } -static void ad9832_clk_disable(void *clk) -{ - clk_disable_unprepare(clk); -} - static int ad9832_probe(struct spi_device *spi) { struct ad9832_platform_data *pdata = dev_get_platdata(&spi->dev); @@ -350,18 +345,10 @@ static int ad9832_probe(struct spi_device *spi) if (ret) return ret; - st->mclk = devm_clk_get(&spi->dev, "mclk"); + st->mclk = devm_clk_get_enabled(&spi->dev, "mclk"); if (IS_ERR(st->mclk)) return PTR_ERR(st->mclk); - ret = clk_prepare_enable(st->mclk); - if (ret < 0) - return ret; - - ret = devm_add_action_or_reset(&spi->dev, ad9832_clk_disable, st->mclk); - if (ret) - return ret; - st->spi = spi; mutex_init(&st->lock); diff --git a/drivers/staging/iio/frequency/ad9834.c b/drivers/staging/iio/frequency/ad9834.c index 285df0e489a6..a7a5cdcc6590 100644 --- a/drivers/staging/iio/frequency/ad9834.c +++ b/drivers/staging/iio/frequency/ad9834.c @@ -394,13 +394,6 @@ static void ad9834_disable_reg(void *data) regulator_disable(reg); } -static void ad9834_disable_clk(void *data) -{ - struct clk *clk = data; - - clk_disable_unprepare(clk); -} - static int ad9834_probe(struct spi_device *spi) { struct ad9834_state *st; @@ -429,22 +422,12 @@ static int ad9834_probe(struct spi_device *spi) } st = iio_priv(indio_dev); mutex_init(&st->lock); - st->mclk = devm_clk_get(&spi->dev, NULL); + st->mclk = devm_clk_get_enabled(&spi->dev, NULL); if (IS_ERR(st->mclk)) { - ret = PTR_ERR(st->mclk); - return ret; - } - - ret = clk_prepare_enable(st->mclk); - if (ret) { dev_err(&spi->dev, "Failed to enable master clock\n"); - return ret; + return PTR_ERR(st->mclk); } - ret = devm_add_action_or_reset(&spi->dev, ad9834_disable_clk, st->mclk); - if (ret) - return ret; - st->spi = spi; st->devid = spi_get_device_id(spi)->driver_data; indio_dev->name = spi_get_device_id(spi)->name; diff --git a/drivers/staging/iio/impedance-analyzer/ad5933.c b/drivers/staging/iio/impedance-analyzer/ad5933.c index 46db6d91542a..e748a5d04e97 100644 --- a/drivers/staging/iio/impedance-analyzer/ad5933.c +++ b/drivers/staging/iio/impedance-analyzer/ad5933.c @@ -667,13 +667,6 @@ static void ad5933_reg_disable(void *data) regulator_disable(st->reg); } -static void ad5933_clk_disable(void *data) -{ - struct ad5933_state *st = data; - - clk_disable_unprepare(st->mclk); -} - static int ad5933_probe(struct i2c_client *client) { const struct i2c_device_id *id = i2c_client_get_device_id(client); @@ -712,23 +705,12 @@ static int ad5933_probe(struct i2c_client *client) st->vref_mv = ret / 1000; - st->mclk = devm_clk_get(&client->dev, "mclk"); + st->mclk = devm_clk_get_enabled(&client->dev, "mclk"); if (IS_ERR(st->mclk) && PTR_ERR(st->mclk) != -ENOENT) return PTR_ERR(st->mclk); - if (!IS_ERR(st->mclk)) { - ret = clk_prepare_enable(st->mclk); - if (ret < 0) - return ret; - - ret = devm_add_action_or_reset(&client->dev, - ad5933_clk_disable, - st); - if (ret) - return ret; - + if (!IS_ERR(st->mclk)) ext_clk_hz = clk_get_rate(st->mclk); - } if (ext_clk_hz) { st->mclk_hz = ext_clk_hz; From 655be10df27d98f014fd4691909e15d56834020e Mon Sep 17 00:00:00 2001 From: Marcus Folkesson Date: Tue, 22 Aug 2023 21:22:54 +0200 Subject: [PATCH 007/326] dt-bindings: iio: adc: mcp3911: add support for the whole MCP39xx family Microchip does have many similar chips, add those to the compatible string as the driver support is extended. The new supported chips are: - microchip,mcp3910 - microchip,mcp3912 - microchip,mcp3913 - microchip,mcp3914 - microchip,mcp3918 - microchip,mcp3919 Signed-off-by: Marcus Folkesson Reviewed-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20230822192259.1125792-2-marcus.folkesson@gmail.com Signed-off-by: Jonathan Cameron --- .../devicetree/bindings/iio/adc/microchip,mcp3911.yaml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Documentation/devicetree/bindings/iio/adc/microchip,mcp3911.yaml b/Documentation/devicetree/bindings/iio/adc/microchip,mcp3911.yaml index f7b3fde4115a..06951ec5f5da 100644 --- a/Documentation/devicetree/bindings/iio/adc/microchip,mcp3911.yaml +++ b/Documentation/devicetree/bindings/iio/adc/microchip,mcp3911.yaml @@ -18,7 +18,13 @@ description: | properties: compatible: enum: + - microchip,mcp3910 - microchip,mcp3911 + - microchip,mcp3912 + - microchip,mcp3913 + - microchip,mcp3914 + - microchip,mcp3918 + - microchip,mcp3919 reg: maxItems: 1 From 46d1bfa04f61eb9533859d50d33c6f1c3ef98b80 Mon Sep 17 00:00:00 2001 From: Marcus Folkesson Date: Tue, 22 Aug 2023 21:22:55 +0200 Subject: [PATCH 008/326] iio: adc: mcp3911: make use of dev_err_probe() Simplify code by switch to dev_err_probe(). Suggested-by: Andy Shevchenko Reviewed-by: Andy Shevchenko Signed-off-by: Marcus Folkesson Link: https://lore.kernel.org/r/20230822192259.1125792-3-marcus.folkesson@gmail.com Signed-off-by: Jonathan Cameron --- drivers/iio/adc/mcp3911.c | 23 +++++++---------------- 1 file changed, 7 insertions(+), 16 deletions(-) diff --git a/drivers/iio/adc/mcp3911.c b/drivers/iio/adc/mcp3911.c index 974c5bd923a6..7fb3ab4a4256 100644 --- a/drivers/iio/adc/mcp3911.c +++ b/drivers/iio/adc/mcp3911.c @@ -277,10 +277,7 @@ static int mcp3911_calc_scale_table(struct mcp3911 *adc) if (adc->vref) { ret = regulator_get_voltage(adc->vref); if (ret < 0) { - dev_err(&adc->spi->dev, - "failed to get vref voltage: %d\n", - ret); - return ret; + return dev_err_probe(&adc->spi->dev, ret, "failed to get vref voltage\n"); } ref = ret / 1000; @@ -396,10 +393,9 @@ static int mcp3911_config(struct mcp3911 *adc) if (ret) device_property_read_u32(dev, "device-addr", &adc->dev_addr); if (adc->dev_addr > 3) { - dev_err(&adc->spi->dev, - "invalid device address (%i). Must be in range 0-3.\n", - adc->dev_addr); - return -EINVAL; + return dev_err_probe(dev, -EINVAL, + "invalid device address (%i). Must be in range 0-3.\n", + adc->dev_addr); } dev_dbg(&adc->spi->dev, "use device address %i\n", adc->dev_addr); @@ -466,6 +462,7 @@ static const struct iio_trigger_ops mcp3911_trigger_ops = { static int mcp3911_probe(struct spi_device *spi) { + struct device *dev = &spi->dev; struct iio_dev *indio_dev; struct mcp3911 *adc; int ret; @@ -482,10 +479,7 @@ static int mcp3911_probe(struct spi_device *spi) if (PTR_ERR(adc->vref) == -ENODEV) { adc->vref = NULL; } else { - dev_err(&adc->spi->dev, - "failed to get regulator (%ld)\n", - PTR_ERR(adc->vref)); - return PTR_ERR(adc->vref); + return dev_err_probe(dev, PTR_ERR(adc->vref), "failed to get regulator\n"); } } else { @@ -504,10 +498,7 @@ static int mcp3911_probe(struct spi_device *spi) if (PTR_ERR(adc->clki) == -ENOENT) { adc->clki = NULL; } else { - dev_err(&adc->spi->dev, - "failed to get adc clk (%ld)\n", - PTR_ERR(adc->clki)); - return PTR_ERR(adc->clki); + return dev_err_probe(dev, PTR_ERR(adc->clki), "failed to get adc clk\n"); } } From d1f6a2ac592241215f9229e68eb951211d08695e Mon Sep 17 00:00:00 2001 From: Marcus Folkesson Date: Tue, 22 Aug 2023 21:22:56 +0200 Subject: [PATCH 009/326] iio: adc: mcp3911: simplify usage of spi->dev Replace the usage of `adc->spi->dev` with `dev` to make the code prettier. Reviewed-by: Andy Shevchenko Suggested-by: Andy Shevchenko Signed-off-by: Marcus Folkesson Link: https://lore.kernel.org/r/20230822192259.1125792-4-marcus.folkesson@gmail.com Signed-off-by: Jonathan Cameron --- drivers/iio/adc/mcp3911.c | 50 ++++++++++++++++++--------------------- 1 file changed, 23 insertions(+), 27 deletions(-) diff --git a/drivers/iio/adc/mcp3911.c b/drivers/iio/adc/mcp3911.c index 7fb3ab4a4256..31ee8d7f81de 100644 --- a/drivers/iio/adc/mcp3911.c +++ b/drivers/iio/adc/mcp3911.c @@ -269,6 +269,7 @@ out: static int mcp3911_calc_scale_table(struct mcp3911 *adc) { + struct device *dev = &adc->spi->dev; u32 ref = MCP3911_INT_VREF_MV; u32 div; int ret; @@ -277,7 +278,7 @@ static int mcp3911_calc_scale_table(struct mcp3911 *adc) if (adc->vref) { ret = regulator_get_voltage(adc->vref); if (ret < 0) { - return dev_err_probe(&adc->spi->dev, ret, "failed to get vref voltage\n"); + return dev_err_probe(dev, ret, "failed to get vref voltage\n"); } ref = ret / 1000; @@ -334,6 +335,7 @@ static irqreturn_t mcp3911_trigger_handler(int irq, void *p) struct iio_poll_func *pf = p; struct iio_dev *indio_dev = pf->indio_dev; struct mcp3911 *adc = iio_priv(indio_dev); + struct device *dev = &adc->spi->dev; struct spi_transfer xfer[] = { { .tx_buf = &adc->tx_buf, @@ -351,8 +353,7 @@ static irqreturn_t mcp3911_trigger_handler(int irq, void *p) adc->tx_buf = MCP3911_REG_READ(MCP3911_CHANNEL(0), adc->dev_addr); ret = spi_sync_transfer(adc->spi, xfer, ARRAY_SIZE(xfer)); if (ret < 0) { - dev_warn(&adc->spi->dev, - "failed to get conversion data\n"); + dev_warn(dev, "failed to get conversion data\n"); goto out; } @@ -397,7 +398,7 @@ static int mcp3911_config(struct mcp3911 *adc) "invalid device address (%i). Must be in range 0-3.\n", adc->dev_addr); } - dev_dbg(&adc->spi->dev, "use device address %i\n", adc->dev_addr); + dev_dbg(dev, "use device address %i\n", adc->dev_addr); ret = mcp3911_read(adc, MCP3911_REG_CONFIG, ®val, 2); if (ret) @@ -405,21 +406,19 @@ static int mcp3911_config(struct mcp3911 *adc) regval &= ~MCP3911_CONFIG_VREFEXT; if (adc->vref) { - dev_dbg(&adc->spi->dev, "use external voltage reference\n"); + dev_dbg(dev, "use external voltage reference\n"); regval |= FIELD_PREP(MCP3911_CONFIG_VREFEXT, 1); } else { - dev_dbg(&adc->spi->dev, - "use internal voltage reference (1.2V)\n"); + dev_dbg(dev, "use internal voltage reference (1.2V)\n"); regval |= FIELD_PREP(MCP3911_CONFIG_VREFEXT, 0); } regval &= ~MCP3911_CONFIG_CLKEXT; if (adc->clki) { - dev_dbg(&adc->spi->dev, "use external clock as clocksource\n"); + dev_dbg(dev, "use external clock as clocksource\n"); regval |= FIELD_PREP(MCP3911_CONFIG_CLKEXT, 1); } else { - dev_dbg(&adc->spi->dev, - "use crystal oscillator as clocksource\n"); + dev_dbg(dev, "use crystal oscillator as clocksource\n"); regval |= FIELD_PREP(MCP3911_CONFIG_CLKEXT, 0); } @@ -467,14 +466,14 @@ static int mcp3911_probe(struct spi_device *spi) struct mcp3911 *adc; int ret; - indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*adc)); + indio_dev = devm_iio_device_alloc(dev, sizeof(*adc)); if (!indio_dev) return -ENOMEM; adc = iio_priv(indio_dev); adc->spi = spi; - adc->vref = devm_regulator_get_optional(&adc->spi->dev, "vref"); + adc->vref = devm_regulator_get_optional(dev, "vref"); if (IS_ERR(adc->vref)) { if (PTR_ERR(adc->vref) == -ENODEV) { adc->vref = NULL; @@ -487,13 +486,12 @@ static int mcp3911_probe(struct spi_device *spi) if (ret) return ret; - ret = devm_add_action_or_reset(&spi->dev, - mcp3911_cleanup_regulator, adc->vref); + ret = devm_add_action_or_reset(dev, mcp3911_cleanup_regulator, adc->vref); if (ret) return ret; } - adc->clki = devm_clk_get_enabled(&adc->spi->dev, NULL); + adc->clki = devm_clk_get_enabled(dev, NULL); if (IS_ERR(adc->clki)) { if (PTR_ERR(adc->clki) == -ENOENT) { adc->clki = NULL; @@ -506,7 +504,7 @@ static int mcp3911_probe(struct spi_device *spi) if (ret) return ret; - if (device_property_read_bool(&adc->spi->dev, "microchip,data-ready-hiz")) + if (device_property_read_bool(dev, "microchip,data-ready-hiz")) ret = mcp3911_update(adc, MCP3911_REG_STATUSCOM, MCP3911_STATUSCOM_DRHIZ, 0, 2); else @@ -540,15 +538,14 @@ static int mcp3911_probe(struct spi_device *spi) mutex_init(&adc->lock); if (spi->irq > 0) { - adc->trig = devm_iio_trigger_alloc(&spi->dev, "%s-dev%d", - indio_dev->name, - iio_device_id(indio_dev)); + adc->trig = devm_iio_trigger_alloc(dev, "%s-dev%d", indio_dev->name, + iio_device_id(indio_dev)); if (!adc->trig) return -ENOMEM; adc->trig->ops = &mcp3911_trigger_ops; iio_trigger_set_drvdata(adc->trig, adc); - ret = devm_iio_trigger_register(&spi->dev, adc->trig); + ret = devm_iio_trigger_register(dev, adc->trig); if (ret) return ret; @@ -557,20 +554,19 @@ static int mcp3911_probe(struct spi_device *spi) * Some platforms might not allow the option to power it down so * don't enable the interrupt to avoid extra load on the system. */ - ret = devm_request_irq(&spi->dev, spi->irq, - &iio_trigger_generic_data_rdy_poll, IRQF_NO_AUTOEN | IRQF_ONESHOT, - indio_dev->name, adc->trig); + ret = devm_request_irq(dev, spi->irq, &iio_trigger_generic_data_rdy_poll, + IRQF_NO_AUTOEN | IRQF_ONESHOT, + indio_dev->name, adc->trig); if (ret) return ret; } - ret = devm_iio_triggered_buffer_setup(&spi->dev, indio_dev, - NULL, - mcp3911_trigger_handler, NULL); + ret = devm_iio_triggered_buffer_setup(dev, indio_dev, NULL, + mcp3911_trigger_handler, NULL); if (ret) return ret; - return devm_iio_device_register(&adc->spi->dev, indio_dev); + return devm_iio_device_register(dev, indio_dev); } static const struct of_device_id mcp3911_dt_ids[] = { From 7e5047334f04d2c8588ee23eadb88ad52998745b Mon Sep 17 00:00:00 2001 From: Marcus Folkesson Date: Tue, 22 Aug 2023 21:22:57 +0200 Subject: [PATCH 010/326] iio: adc: mcp3911: fix indentation The whole file does not make use of indentation properly. Do something about it. Reviewed-by: Andy Shevchenko Signed-off-by: Marcus Folkesson Link: https://lore.kernel.org/r/20230822192259.1125792-5-marcus.folkesson@gmail.com Signed-off-by: Jonathan Cameron --- drivers/iio/adc/mcp3911.c | 41 +++++++++++++++++++-------------------- 1 file changed, 20 insertions(+), 21 deletions(-) diff --git a/drivers/iio/adc/mcp3911.c b/drivers/iio/adc/mcp3911.c index 31ee8d7f81de..f9db08813645 100644 --- a/drivers/iio/adc/mcp3911.c +++ b/drivers/iio/adc/mcp3911.c @@ -33,7 +33,7 @@ #define MCP3911_GAIN_VAL(ch, val) ((val << 3 * ch) & MCP3911_GAIN_MASK(ch)) #define MCP3911_REG_STATUSCOM 0x0a -#define MCP3911_STATUSCOM_DRHIZ BIT(12) +#define MCP3911_STATUSCOM_DRHIZ BIT(12) #define MCP3911_STATUSCOM_READ GENMASK(7, 6) #define MCP3911_STATUSCOM_CH1_24WIDTH BIT(4) #define MCP3911_STATUSCOM_CH0_24WIDTH BIT(3) @@ -111,8 +111,7 @@ static int mcp3911_write(struct mcp3911 *adc, u8 reg, u32 val, u8 len) return spi_write(adc->spi, &val, len + 1); } -static int mcp3911_update(struct mcp3911 *adc, u8 reg, u32 mask, - u32 val, u8 len) +static int mcp3911_update(struct mcp3911 *adc, u8 reg, u32 mask, u32 val, u8 len) { u32 tmp; int ret; @@ -127,8 +126,8 @@ static int mcp3911_update(struct mcp3911 *adc, u8 reg, u32 mask, } static int mcp3911_write_raw_get_fmt(struct iio_dev *indio_dev, - struct iio_chan_spec const *chan, - long mask) + struct iio_chan_spec const *chan, + long mask) { switch (mask) { case IIO_CHAN_INFO_SCALE: @@ -141,9 +140,9 @@ static int mcp3911_write_raw_get_fmt(struct iio_dev *indio_dev, } static int mcp3911_read_avail(struct iio_dev *indio_dev, - struct iio_chan_spec const *chan, - const int **vals, int *type, int *length, - long info) + struct iio_chan_spec const *chan, + const int **vals, int *type, int *length, + long info) { switch (info) { case IIO_CHAN_INFO_OVERSAMPLING_RATIO: @@ -212,8 +211,8 @@ out: } static int mcp3911_write_raw(struct iio_dev *indio_dev, - struct iio_chan_spec const *channel, int val, - int val2, long mask) + struct iio_chan_spec const *channel, int val, + int val2, long mask) { struct mcp3911 *adc = iio_priv(indio_dev); int ret = -EINVAL; @@ -223,12 +222,12 @@ static int mcp3911_write_raw(struct iio_dev *indio_dev, case IIO_CHAN_INFO_SCALE: for (int i = 0; i < MCP3911_NUM_SCALES; i++) { if (val == mcp3911_scale_table[i][0] && - val2 == mcp3911_scale_table[i][1]) { + val2 == mcp3911_scale_table[i][1]) { adc->gain[channel->channel] = BIT(i); ret = mcp3911_update(adc, MCP3911_REG_GAIN, - MCP3911_GAIN_MASK(channel->channel), - MCP3911_GAIN_VAL(channel->channel, i), 1); + MCP3911_GAIN_MASK(channel->channel), + MCP3911_GAIN_VAL(channel->channel, i), 1); } } break; @@ -246,8 +245,8 @@ static int mcp3911_write_raw(struct iio_dev *indio_dev, /* Enable offset*/ ret = mcp3911_update(adc, MCP3911_REG_STATUSCOM, - MCP3911_STATUSCOM_EN_OFFCAL, - MCP3911_STATUSCOM_EN_OFFCAL, 2); + MCP3911_STATUSCOM_EN_OFFCAL, + MCP3911_STATUSCOM_EN_OFFCAL, 2); break; case IIO_CHAN_INFO_OVERSAMPLING_RATIO: @@ -255,7 +254,7 @@ static int mcp3911_write_raw(struct iio_dev *indio_dev, if (val == mcp3911_osr_table[i]) { val = FIELD_PREP(MCP3911_CONFIG_OSR, i); ret = mcp3911_update(adc, MCP3911_REG_CONFIG, MCP3911_CONFIG_OSR, - val, 2); + val, 2); break; } } @@ -506,10 +505,10 @@ static int mcp3911_probe(struct spi_device *spi) if (device_property_read_bool(dev, "microchip,data-ready-hiz")) ret = mcp3911_update(adc, MCP3911_REG_STATUSCOM, MCP3911_STATUSCOM_DRHIZ, - 0, 2); + 0, 2); else ret = mcp3911_update(adc, MCP3911_REG_STATUSCOM, MCP3911_STATUSCOM_DRHIZ, - MCP3911_STATUSCOM_DRHIZ, 2); + MCP3911_STATUSCOM_DRHIZ, 2); if (ret) return ret; @@ -517,12 +516,12 @@ static int mcp3911_probe(struct spi_device *spi) if (ret) return ret; - /* Set gain to 1 for all channels */ + /* Set gain to 1 for all channels */ for (int i = 0; i < MCP3911_NUM_CHANNELS; i++) { adc->gain[i] = 1; ret = mcp3911_update(adc, MCP3911_REG_GAIN, - MCP3911_GAIN_MASK(i), - MCP3911_GAIN_VAL(i, 0), 1); + MCP3911_GAIN_MASK(i), + MCP3911_GAIN_VAL(i, 0), 1); if (ret) return ret; } From 593d73629a441bccad21a5bffc126df8f9280831 Mon Sep 17 00:00:00 2001 From: Marcus Folkesson Date: Tue, 22 Aug 2023 21:22:58 +0200 Subject: [PATCH 011/326] iio: adc: mcp3911: avoid ambiguity parameters in macros Name macro parameters after what they represent instead of 'x' and make sure the evaluation of that will have no side effects. Reviewed-by: Andy Shevchenko Signed-off-by: Marcus Folkesson Link: https://lore.kernel.org/r/20230822192259.1125792-6-marcus.folkesson@gmail.com Signed-off-by: Jonathan Cameron --- drivers/iio/adc/mcp3911.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/iio/adc/mcp3911.c b/drivers/iio/adc/mcp3911.c index f9db08813645..281cc1211fd6 100644 --- a/drivers/iio/adc/mcp3911.c +++ b/drivers/iio/adc/mcp3911.c @@ -29,8 +29,8 @@ #define MCP3911_REG_MOD 0x06 #define MCP3911_REG_PHASE 0x07 #define MCP3911_REG_GAIN 0x09 -#define MCP3911_GAIN_MASK(ch) (GENMASK(2, 0) << 3 * ch) -#define MCP3911_GAIN_VAL(ch, val) ((val << 3 * ch) & MCP3911_GAIN_MASK(ch)) +#define MCP3911_GAIN_MASK(ch) (GENMASK(2, 0) << 3 * (ch)) +#define MCP3911_GAIN_VAL(ch, val) ((val << 3 * (ch)) & MCP3911_GAIN_MASK(ch)) #define MCP3911_REG_STATUSCOM 0x0a #define MCP3911_STATUSCOM_DRHIZ BIT(12) @@ -51,8 +51,8 @@ #define MCP3911_REG_GAINCAL_CH1 0x17 #define MCP3911_REG_VREFCAL 0x1a -#define MCP3911_CHANNEL(x) (MCP3911_REG_CHANNEL0 + x * 3) -#define MCP3911_OFFCAL(x) (MCP3911_REG_OFFCAL_CH0 + x * 6) +#define MCP3911_CHANNEL(ch) (MCP3911_REG_CHANNEL0 + (ch) * 3) +#define MCP3911_OFFCAL(ch) (MCP3911_REG_OFFCAL_CH0 + (ch) * 6) /* Internal voltage reference in mV */ #define MCP3911_INT_VREF_MV 1200 From 732ad34260d367661e2f20a5c5a4d54dbc856ac4 Mon Sep 17 00:00:00 2001 From: Marcus Folkesson Date: Tue, 22 Aug 2023 21:22:59 +0200 Subject: [PATCH 012/326] iio: adc: mcp3911: add support for the whole MCP39xx family Microchip does have many similar chips, add support for those. The new supported chips are: - microchip,mcp3910 - microchip,mcp3912 - microchip,mcp3913 - microchip,mcp3914 - microchip,mcp3918 - microchip,mcp3919 Signed-off-by: Marcus Folkesson Reviewed-by: Andy Shevchenko Link: https://lore.kernel.org/r/20230822192259.1125792-7-marcus.folkesson@gmail.com Signed-off-by: Jonathan Cameron --- drivers/iio/adc/Kconfig | 6 +- drivers/iio/adc/mcp3911.c | 466 +++++++++++++++++++++++++++++++++----- 2 files changed, 415 insertions(+), 57 deletions(-) diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig index 517b3db114b8..432d3f9bfde1 100644 --- a/drivers/iio/adc/Kconfig +++ b/drivers/iio/adc/Kconfig @@ -785,8 +785,10 @@ config MCP3911 select IIO_BUFFER select IIO_TRIGGERED_BUFFER help - Say yes here to build support for Microchip Technology's MCP3911 - analog to digital converter. + Say yes here to build support for one of the following + Microchip Technology's analog to digital converters: + MCP3910, MCP3911, MCP3912, MCP3913, MCP3914, + MCP3918 and MCP3919. This driver can also be built as a module. If so, the module will be called mcp3911. diff --git a/drivers/iio/adc/mcp3911.c b/drivers/iio/adc/mcp3911.c index 281cc1211fd6..d864558bc087 100644 --- a/drivers/iio/adc/mcp3911.c +++ b/drivers/iio/adc/mcp3911.c @@ -61,12 +61,56 @@ #define MCP3911_REG_WRITE(reg, id) ((((reg) << 1) | ((id) << 6) | (0 << 0)) & 0xff) #define MCP3911_REG_MASK GENMASK(4, 1) -#define MCP3911_NUM_CHANNELS 2 #define MCP3911_NUM_SCALES 6 +/* Registers compatible with MCP3910 */ +#define MCP3910_REG_STATUSCOM 0x0c +#define MCP3910_STATUSCOM_READ GENMASK(23, 22) +#define MCP3910_STATUSCOM_DRHIZ BIT(20) + +#define MCP3910_REG_GAIN 0x0b + +#define MCP3910_REG_CONFIG0 0x0d +#define MCP3910_CONFIG0_EN_OFFCAL BIT(23) +#define MCP3910_CONFIG0_OSR GENMASK(15, 13) + +#define MCP3910_REG_CONFIG1 0x0e +#define MCP3910_CONFIG1_CLKEXT BIT(6) +#define MCP3910_CONFIG1_VREFEXT BIT(7) + +#define MCP3910_REG_OFFCAL_CH0 0x0f +#define MCP3910_OFFCAL(ch) (MCP3910_REG_OFFCAL_CH0 + (ch) * 6) + +/* Maximal number of channels used by the MCP39XX family */ +#define MCP39XX_MAX_NUM_CHANNELS 8 + static const int mcp3911_osr_table[] = { 32, 64, 128, 256, 512, 1024, 2048, 4096 }; static u32 mcp3911_scale_table[MCP3911_NUM_SCALES][2]; +enum mcp3911_id { + MCP3910, + MCP3911, + MCP3912, + MCP3913, + MCP3914, + MCP3918, + MCP3919, +}; + +struct mcp3911; +struct mcp3911_chip_info { + const struct iio_chan_spec *channels; + unsigned int num_channels; + + int (*config)(struct mcp3911 *adc); + int (*get_osr)(struct mcp3911 *adc, u32 *val); + int (*set_osr)(struct mcp3911 *adc, u32 val); + int (*enable_offset)(struct mcp3911 *adc, bool enable); + int (*get_offset)(struct mcp3911 *adc, int channel, int *val); + int (*set_offset)(struct mcp3911 *adc, int channel, int val); + int (*set_scale)(struct mcp3911 *adc, int channel, u32 val); +}; + struct mcp3911 { struct spi_device *spi; struct mutex lock; @@ -74,14 +118,15 @@ struct mcp3911 { struct clk *clki; u32 dev_addr; struct iio_trigger *trig; - u32 gain[MCP3911_NUM_CHANNELS]; + u32 gain[MCP39XX_MAX_NUM_CHANNELS]; + const struct mcp3911_chip_info *chip; struct { - u32 channels[MCP3911_NUM_CHANNELS]; + u32 channels[MCP39XX_MAX_NUM_CHANNELS]; s64 ts __aligned(8); } scan; u8 tx_buf __aligned(IIO_DMA_MINALIGN); - u8 rx_buf[MCP3911_NUM_CHANNELS * 3]; + u8 rx_buf[MCP39XX_MAX_NUM_CHANNELS * 3]; }; static int mcp3911_read(struct mcp3911 *adc, u8 reg, u32 *val, u8 len) @@ -125,6 +170,112 @@ static int mcp3911_update(struct mcp3911 *adc, u8 reg, u32 mask, u32 val, u8 len return mcp3911_write(adc, reg, val, len); } +static int mcp3910_enable_offset(struct mcp3911 *adc, bool enable) +{ + unsigned int mask = MCP3910_CONFIG0_EN_OFFCAL; + unsigned int value = enable ? mask : 0; + + return mcp3911_update(adc, MCP3910_REG_CONFIG0, mask, value, 3); +} + +static int mcp3910_get_offset(struct mcp3911 *adc, int channel, int *val) +{ + return mcp3911_read(adc, MCP3910_OFFCAL(channel), val, 3); +} + +static int mcp3910_set_offset(struct mcp3911 *adc, int channel, int val) +{ + int ret; + + ret = mcp3911_write(adc, MCP3910_OFFCAL(channel), val, 3); + if (ret) + return ret; + + return adc->chip->enable_offset(adc, 1); +} + +static int mcp3911_enable_offset(struct mcp3911 *adc, bool enable) +{ + unsigned int mask = MCP3911_STATUSCOM_EN_OFFCAL; + unsigned int value = enable ? mask : 0; + + return mcp3911_update(adc, MCP3911_REG_STATUSCOM, mask, value, 2); +} + +static int mcp3911_get_offset(struct mcp3911 *adc, int channel, int *val) +{ + return mcp3911_read(adc, MCP3911_OFFCAL(channel), val, 3); +} + +static int mcp3911_set_offset(struct mcp3911 *adc, int channel, int val) +{ + int ret; + + ret = mcp3911_write(adc, MCP3911_OFFCAL(channel), val, 3); + if (ret) + return ret; + + return adc->chip->enable_offset(adc, 1); +} + +static int mcp3910_get_osr(struct mcp3911 *adc, u32 *val) +{ + int ret; + unsigned int osr; + + ret = mcp3911_read(adc, MCP3910_REG_CONFIG0, val, 3); + if (ret) + return ret; + + osr = FIELD_GET(MCP3910_CONFIG0_OSR, *val); + *val = 32 << osr; + return 0; +} + +static int mcp3910_set_osr(struct mcp3911 *adc, u32 val) +{ + unsigned int osr = FIELD_PREP(MCP3910_CONFIG0_OSR, val); + unsigned int mask = MCP3910_CONFIG0_OSR; + + return mcp3911_update(adc, MCP3910_REG_CONFIG0, mask, osr, 3); +} + +static int mcp3911_set_osr(struct mcp3911 *adc, u32 val) +{ + unsigned int osr = FIELD_PREP(MCP3911_CONFIG_OSR, val); + unsigned int mask = MCP3911_CONFIG_OSR; + + return mcp3911_update(adc, MCP3911_REG_CONFIG, mask, osr, 2); +} + +static int mcp3911_get_osr(struct mcp3911 *adc, u32 *val) +{ + int ret; + unsigned int osr; + + ret = mcp3911_read(adc, MCP3911_REG_CONFIG, val, 2); + if (ret) + return ret; + + osr = FIELD_GET(MCP3911_CONFIG_OSR, *val); + *val = 32 << osr; + return ret; +} + +static int mcp3910_set_scale(struct mcp3911 *adc, int channel, u32 val) +{ + return mcp3911_update(adc, MCP3910_REG_GAIN, + MCP3911_GAIN_MASK(channel), + MCP3911_GAIN_VAL(channel, val), 3); +} + +static int mcp3911_set_scale(struct mcp3911 *adc, int channel, u32 val) +{ + return mcp3911_update(adc, MCP3911_REG_GAIN, + MCP3911_GAIN_MASK(channel), + MCP3911_GAIN_VAL(channel, val), 1); +} + static int mcp3911_write_raw_get_fmt(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, long mask) @@ -181,20 +332,18 @@ static int mcp3911_read_raw(struct iio_dev *indio_dev, break; case IIO_CHAN_INFO_OFFSET: - ret = mcp3911_read(adc, - MCP3911_OFFCAL(channel->channel), val, 3); + + ret = adc->chip->get_offset(adc, channel->channel, val); if (ret) goto out; ret = IIO_VAL_INT; break; case IIO_CHAN_INFO_OVERSAMPLING_RATIO: - ret = mcp3911_read(adc, MCP3911_REG_CONFIG, val, 2); + ret = adc->chip->get_osr(adc, val); if (ret) goto out; - *val = FIELD_GET(MCP3911_CONFIG_OSR, *val); - *val = 32 << *val; ret = IIO_VAL_INT; break; @@ -225,9 +374,7 @@ static int mcp3911_write_raw(struct iio_dev *indio_dev, val2 == mcp3911_scale_table[i][1]) { adc->gain[channel->channel] = BIT(i); - ret = mcp3911_update(adc, MCP3911_REG_GAIN, - MCP3911_GAIN_MASK(channel->channel), - MCP3911_GAIN_VAL(channel->channel, i), 1); + ret = adc->chip->set_scale(adc, channel->channel, i); } } break; @@ -237,24 +384,13 @@ static int mcp3911_write_raw(struct iio_dev *indio_dev, goto out; } - /* Write offset */ - ret = mcp3911_write(adc, MCP3911_OFFCAL(channel->channel), val, - 3); - if (ret) - goto out; - - /* Enable offset*/ - ret = mcp3911_update(adc, MCP3911_REG_STATUSCOM, - MCP3911_STATUSCOM_EN_OFFCAL, - MCP3911_STATUSCOM_EN_OFFCAL, 2); + ret = adc->chip->set_offset(adc, channel->channel, val); break; case IIO_CHAN_INFO_OVERSAMPLING_RATIO: for (int i = 0; i < ARRAY_SIZE(mcp3911_osr_table); i++) { if (val == mcp3911_osr_table[i]) { - val = FIELD_PREP(MCP3911_CONFIG_OSR, i); - ret = mcp3911_update(adc, MCP3911_REG_CONFIG, MCP3911_CONFIG_OSR, - val, 2); + ret = adc->chip->set_osr(adc, i); break; } } @@ -323,12 +459,60 @@ static int mcp3911_calc_scale_table(struct mcp3911 *adc) }, \ } +static const struct iio_chan_spec mcp3910_channels[] = { + MCP3911_CHAN(0), + MCP3911_CHAN(1), + IIO_CHAN_SOFT_TIMESTAMP(2), +}; + static const struct iio_chan_spec mcp3911_channels[] = { MCP3911_CHAN(0), MCP3911_CHAN(1), IIO_CHAN_SOFT_TIMESTAMP(2), }; +static const struct iio_chan_spec mcp3912_channels[] = { + MCP3911_CHAN(0), + MCP3911_CHAN(1), + MCP3911_CHAN(2), + MCP3911_CHAN(3), + IIO_CHAN_SOFT_TIMESTAMP(4), +}; + +static const struct iio_chan_spec mcp3913_channels[] = { + MCP3911_CHAN(0), + MCP3911_CHAN(1), + MCP3911_CHAN(2), + MCP3911_CHAN(3), + MCP3911_CHAN(4), + MCP3911_CHAN(5), + IIO_CHAN_SOFT_TIMESTAMP(6), +}; + +static const struct iio_chan_spec mcp3914_channels[] = { + MCP3911_CHAN(0), + MCP3911_CHAN(1), + MCP3911_CHAN(2), + MCP3911_CHAN(3), + MCP3911_CHAN(4), + MCP3911_CHAN(5), + MCP3911_CHAN(6), + MCP3911_CHAN(7), + IIO_CHAN_SOFT_TIMESTAMP(8), +}; + +static const struct iio_chan_spec mcp3918_channels[] = { + MCP3911_CHAN(0), + IIO_CHAN_SOFT_TIMESTAMP(1), +}; + +static const struct iio_chan_spec mcp3919_channels[] = { + MCP3911_CHAN(0), + MCP3911_CHAN(1), + MCP3911_CHAN(2), + IIO_CHAN_SOFT_TIMESTAMP(3), +}; + static irqreturn_t mcp3911_trigger_handler(int irq, void *p) { struct iio_poll_func *pf = p; @@ -341,7 +525,7 @@ static irqreturn_t mcp3911_trigger_handler(int irq, void *p) .len = 1, }, { .rx_buf = adc->rx_buf, - .len = sizeof(adc->rx_buf), + .len = (adc->chip->num_channels - 1) * 3, }, }; int scan_index; @@ -384,21 +568,6 @@ static int mcp3911_config(struct mcp3911 *adc) u32 regval; int ret; - ret = device_property_read_u32(dev, "microchip,device-addr", &adc->dev_addr); - - /* - * Fallback to "device-addr" due to historical mismatch between - * dt-bindings and implementation - */ - if (ret) - device_property_read_u32(dev, "device-addr", &adc->dev_addr); - if (adc->dev_addr > 3) { - return dev_err_probe(dev, -EINVAL, - "invalid device address (%i). Must be in range 0-3.\n", - adc->dev_addr); - } - dev_dbg(dev, "use device address %i\n", adc->dev_addr); - ret = mcp3911_read(adc, MCP3911_REG_CONFIG, ®val, 2); if (ret) return ret; @@ -433,7 +602,97 @@ static int mcp3911_config(struct mcp3911 *adc) regval &= ~MCP3911_STATUSCOM_READ; regval |= FIELD_PREP(MCP3911_STATUSCOM_READ, 0x02); - return mcp3911_write(adc, MCP3911_REG_STATUSCOM, regval, 2); + regval &= ~MCP3911_STATUSCOM_DRHIZ; + if (device_property_read_bool(dev, "microchip,data-ready-hiz")) + regval |= FIELD_PREP(MCP3911_STATUSCOM_DRHIZ, 0); + else + regval |= FIELD_PREP(MCP3911_STATUSCOM_DRHIZ, 1); + + /* Disable offset to ignore any old values in offset register */ + regval &= ~MCP3911_STATUSCOM_EN_OFFCAL; + + ret = mcp3911_write(adc, MCP3911_REG_STATUSCOM, regval, 2); + if (ret) + return ret; + + /* Set gain to 1 for all channels */ + ret = mcp3911_read(adc, MCP3911_REG_GAIN, ®val, 1); + if (ret) + return ret; + + for (int i = 0; i < adc->chip->num_channels - 1; i++) { + adc->gain[i] = 1; + regval &= ~MCP3911_GAIN_MASK(i); + } + + return mcp3911_write(adc, MCP3911_REG_GAIN, regval, 1); +} + +static int mcp3910_config(struct mcp3911 *adc) +{ + struct device *dev = &adc->spi->dev; + u32 regval; + int ret; + + ret = mcp3911_read(adc, MCP3910_REG_CONFIG1, ®val, 3); + if (ret) + return ret; + + regval &= ~MCP3910_CONFIG1_VREFEXT; + if (adc->vref) { + dev_dbg(dev, "use external voltage reference\n"); + regval |= FIELD_PREP(MCP3910_CONFIG1_VREFEXT, 1); + } else { + dev_dbg(dev, "use internal voltage reference (1.2V)\n"); + regval |= FIELD_PREP(MCP3910_CONFIG1_VREFEXT, 0); + } + + regval &= ~MCP3910_CONFIG1_CLKEXT; + if (adc->clki) { + dev_dbg(dev, "use external clock as clocksource\n"); + regval |= FIELD_PREP(MCP3910_CONFIG1_CLKEXT, 1); + } else { + dev_dbg(dev, "use crystal oscillator as clocksource\n"); + regval |= FIELD_PREP(MCP3910_CONFIG1_CLKEXT, 0); + } + + ret = mcp3911_write(adc, MCP3910_REG_CONFIG1, regval, 3); + if (ret) + return ret; + + ret = mcp3911_read(adc, MCP3910_REG_STATUSCOM, ®val, 3); + if (ret) + return ret; + + /* Address counter incremented, cycle through register types */ + regval &= ~MCP3910_STATUSCOM_READ; + regval |= FIELD_PREP(MCP3910_STATUSCOM_READ, 0x02); + + regval &= ~MCP3910_STATUSCOM_DRHIZ; + if (device_property_read_bool(dev, "microchip,data-ready-hiz")) + regval |= FIELD_PREP(MCP3910_STATUSCOM_DRHIZ, 0); + else + regval |= FIELD_PREP(MCP3910_STATUSCOM_DRHIZ, 1); + + ret = mcp3911_write(adc, MCP3910_REG_STATUSCOM, regval, 3); + if (ret) + return ret; + + /* Set gain to 1 for all channels */ + ret = mcp3911_read(adc, MCP3910_REG_GAIN, ®val, 3); + if (ret) + return ret; + + for (int i = 0; i < adc->chip->num_channels - 1; i++) { + adc->gain[i] = 1; + regval &= ~MCP3911_GAIN_MASK(i); + } + ret = mcp3911_write(adc, MCP3910_REG_GAIN, regval, 3); + if (ret) + return ret; + + /* Disable offset to ignore any old values in offset register */ + return adc->chip->enable_offset(adc, 0); } static void mcp3911_cleanup_regulator(void *vref) @@ -471,6 +730,7 @@ static int mcp3911_probe(struct spi_device *spi) adc = iio_priv(indio_dev); adc->spi = spi; + adc->chip = spi_get_device_match_data(spi); adc->vref = devm_regulator_get_optional(dev, "vref"); if (IS_ERR(adc->vref)) { @@ -499,16 +759,21 @@ static int mcp3911_probe(struct spi_device *spi) } } - ret = mcp3911_config(adc); + /* + * Fallback to "device-addr" due to historical mismatch between + * dt-bindings and implementation. + */ + ret = device_property_read_u32(dev, "microchip,device-addr", &adc->dev_addr); if (ret) - return ret; + device_property_read_u32(dev, "device-addr", &adc->dev_addr); + if (adc->dev_addr > 3) { + return dev_err_probe(dev, -EINVAL, + "invalid device address (%i). Must be in range 0-3.\n", + adc->dev_addr); + } + dev_dbg(dev, "use device address %i\n", adc->dev_addr); - if (device_property_read_bool(dev, "microchip,data-ready-hiz")) - ret = mcp3911_update(adc, MCP3911_REG_STATUSCOM, MCP3911_STATUSCOM_DRHIZ, - 0, 2); - else - ret = mcp3911_update(adc, MCP3911_REG_STATUSCOM, MCP3911_STATUSCOM_DRHIZ, - MCP3911_STATUSCOM_DRHIZ, 2); + ret = adc->chip->config(adc); if (ret) return ret; @@ -517,7 +782,7 @@ static int mcp3911_probe(struct spi_device *spi) return ret; /* Set gain to 1 for all channels */ - for (int i = 0; i < MCP3911_NUM_CHANNELS; i++) { + for (int i = 0; i < adc->chip->num_channels - 1; i++) { adc->gain[i] = 1; ret = mcp3911_update(adc, MCP3911_REG_GAIN, MCP3911_GAIN_MASK(i), @@ -531,8 +796,8 @@ static int mcp3911_probe(struct spi_device *spi) indio_dev->info = &mcp3911_info; spi_set_drvdata(spi, indio_dev); - indio_dev->channels = mcp3911_channels; - indio_dev->num_channels = ARRAY_SIZE(mcp3911_channels); + indio_dev->channels = adc->chip->channels; + indio_dev->num_channels = adc->chip->num_channels; mutex_init(&adc->lock); @@ -568,14 +833,105 @@ static int mcp3911_probe(struct spi_device *spi) return devm_iio_device_register(dev, indio_dev); } +static const struct mcp3911_chip_info mcp3911_chip_info[] = { + [MCP3910] = { + .channels = mcp3910_channels, + .num_channels = ARRAY_SIZE(mcp3910_channels), + .config = mcp3910_config, + .get_osr = mcp3910_get_osr, + .set_osr = mcp3910_set_osr, + .enable_offset = mcp3910_enable_offset, + .get_offset = mcp3910_get_offset, + .set_offset = mcp3910_set_offset, + .set_scale = mcp3910_set_scale, + }, + [MCP3911] = { + .channels = mcp3911_channels, + .num_channels = ARRAY_SIZE(mcp3911_channels), + .config = mcp3911_config, + .get_osr = mcp3911_get_osr, + .set_osr = mcp3911_set_osr, + .enable_offset = mcp3911_enable_offset, + .get_offset = mcp3911_get_offset, + .set_offset = mcp3911_set_offset, + .set_scale = mcp3911_set_scale, + }, + [MCP3912] = { + .channels = mcp3912_channels, + .num_channels = ARRAY_SIZE(mcp3912_channels), + .config = mcp3910_config, + .get_osr = mcp3910_get_osr, + .set_osr = mcp3910_set_osr, + .enable_offset = mcp3910_enable_offset, + .get_offset = mcp3910_get_offset, + .set_offset = mcp3910_set_offset, + .set_scale = mcp3910_set_scale, + }, + [MCP3913] = { + .channels = mcp3913_channels, + .num_channels = ARRAY_SIZE(mcp3913_channels), + .config = mcp3910_config, + .get_osr = mcp3910_get_osr, + .set_osr = mcp3910_set_osr, + .enable_offset = mcp3910_enable_offset, + .get_offset = mcp3910_get_offset, + .set_offset = mcp3910_set_offset, + .set_scale = mcp3910_set_scale, + }, + [MCP3914] = { + .channels = mcp3914_channels, + .num_channels = ARRAY_SIZE(mcp3914_channels), + .config = mcp3910_config, + .get_osr = mcp3910_get_osr, + .set_osr = mcp3910_set_osr, + .enable_offset = mcp3910_enable_offset, + .get_offset = mcp3910_get_offset, + .set_offset = mcp3910_set_offset, + .set_scale = mcp3910_set_scale, + }, + [MCP3918] = { + .channels = mcp3918_channels, + .num_channels = ARRAY_SIZE(mcp3918_channels), + .config = mcp3910_config, + .get_osr = mcp3910_get_osr, + .set_osr = mcp3910_set_osr, + .enable_offset = mcp3910_enable_offset, + .get_offset = mcp3910_get_offset, + .set_offset = mcp3910_set_offset, + .set_scale = mcp3910_set_scale, + }, + [MCP3919] = { + .channels = mcp3919_channels, + .num_channels = ARRAY_SIZE(mcp3919_channels), + .config = mcp3910_config, + .get_osr = mcp3910_get_osr, + .set_osr = mcp3910_set_osr, + .enable_offset = mcp3910_enable_offset, + .get_offset = mcp3910_get_offset, + .set_offset = mcp3910_set_offset, + .set_scale = mcp3910_set_scale, + }, +}; static const struct of_device_id mcp3911_dt_ids[] = { - { .compatible = "microchip,mcp3911" }, + { .compatible = "microchip,mcp3910", .data = &mcp3911_chip_info[MCP3910] }, + { .compatible = "microchip,mcp3911", .data = &mcp3911_chip_info[MCP3911] }, + { .compatible = "microchip,mcp3912", .data = &mcp3911_chip_info[MCP3912] }, + { .compatible = "microchip,mcp3913", .data = &mcp3911_chip_info[MCP3913] }, + { .compatible = "microchip,mcp3914", .data = &mcp3911_chip_info[MCP3914] }, + { .compatible = "microchip,mcp3918", .data = &mcp3911_chip_info[MCP3918] }, + { .compatible = "microchip,mcp3919", .data = &mcp3911_chip_info[MCP3919] }, { } }; MODULE_DEVICE_TABLE(of, mcp3911_dt_ids); static const struct spi_device_id mcp3911_id[] = { - { "mcp3911", 0 }, + { "mcp3910", (kernel_ulong_t)&mcp3911_chip_info[MCP3910] }, + { "mcp3911", (kernel_ulong_t)&mcp3911_chip_info[MCP3911] }, + { "mcp3912", (kernel_ulong_t)&mcp3911_chip_info[MCP3912] }, + { "mcp3913", (kernel_ulong_t)&mcp3911_chip_info[MCP3913] }, + { "mcp3914", (kernel_ulong_t)&mcp3911_chip_info[MCP3914] }, + { "mcp3918", (kernel_ulong_t)&mcp3911_chip_info[MCP3918] }, + { "mcp3919", (kernel_ulong_t)&mcp3911_chip_info[MCP3919] }, { } }; MODULE_DEVICE_TABLE(spi, mcp3911_id); From da2737c96b6bf5f4090979b0dddd998b7b5b4362 Mon Sep 17 00:00:00 2001 From: Andreas Kemnade Date: Sun, 20 Aug 2023 14:32:29 +0200 Subject: [PATCH 013/326] dt-bindings: iio: adc: Add TI TWL603X GPADC Document TI TWL603X GPADC devicetree bindings. A driver is already there, the compatibles are used, but not documented. Signed-off-by: Andreas Kemnade Reviewed-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20230820123229.530371-1-andreas@kemnade.info Signed-off-by: Jonathan Cameron --- .../bindings/iio/adc/ti,twl6030-gpadc.yaml | 43 +++++++++++++++++++ 1 file changed, 43 insertions(+) create mode 100644 Documentation/devicetree/bindings/iio/adc/ti,twl6030-gpadc.yaml diff --git a/Documentation/devicetree/bindings/iio/adc/ti,twl6030-gpadc.yaml b/Documentation/devicetree/bindings/iio/adc/ti,twl6030-gpadc.yaml new file mode 100644 index 000000000000..e779a8986e0b --- /dev/null +++ b/Documentation/devicetree/bindings/iio/adc/ti,twl6030-gpadc.yaml @@ -0,0 +1,43 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/iio/adc/ti,twl6030-gpadc.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: GPADC subsystem in the TWL6030 power module + +maintainers: + - Andreas Kemnade + +description: + The GPADC subsystem in the TWL603X consists of a 10-bit ADC + combined with a 15-input analog multiplexer in the TWL6030 resp. a + 19-input analog muliplexer in the TWL6032. + +properties: + compatible: + enum: + - ti,twl6030-gpadc + - ti,twl6032-gpadc + + interrupts: + maxItems: 1 + + "#io-channel-cells": + const: 1 + +required: + - compatible + - interrupts + - "#io-channel-cells" + +additionalProperties: false + +examples: + - | + gpadc { + compatible = "ti,twl6030-gpadc"; + interrupts = <3>; + #io-channel-cells = <1>; + }; +... From 9979cc64853b598518a485c2e554657d5c7a00c8 Mon Sep 17 00:00:00 2001 From: Jinjie Ruan Date: Mon, 28 Aug 2023 14:27:16 +0800 Subject: [PATCH 014/326] iio: frequency: adf4350: Use device managed functions and fix power down issue. The devm_clk_get_enabled() helper: - calls devm_clk_get() - calls clk_prepare_enable() and registers what is needed in order to call clk_disable_unprepare() when needed, as a managed resource. Also replace devm_regulator_get() and regulator_enable() with devm_regulator_get_enable() helper and remove regulator_disable(). Replace iio_device_register() with devm_iio_device_register() and remove iio_device_unregister(). And st->reg is not used anymore, so remove it. As Jonathan pointed out, couple of things that are wrong: 1) The device is powered down 'before' we unregister it with the subsystem and as such userspace interfaces are still exposed which probably won't do the right thing if the chip is powered down. 2) This isn't done in the error paths in probe. To solve this problem, register a new callback adf4350_power_down() with devm_add_action_or_reset(), to enable software power down in both error and device detach path. So the remove function can be removed. Remove spi_set_drvdata() from the probe function, since spi_get_drvdata() is not used anymore. Fixes: e31166f0fd48 ("iio: frequency: New driver for Analog Devices ADF4350/ADF4351 Wideband Synthesizers") Signed-off-by: Jinjie Ruan Link: https://lore.kernel.org/r/20230828062717.2310219-1-ruanjinjie@huawei.com Signed-off-by: Jonathan Cameron --- drivers/iio/frequency/adf4350.c | 75 ++++++++++----------------------- 1 file changed, 23 insertions(+), 52 deletions(-) diff --git a/drivers/iio/frequency/adf4350.c b/drivers/iio/frequency/adf4350.c index 85e289700c3c..4abf80f75ef5 100644 --- a/drivers/iio/frequency/adf4350.c +++ b/drivers/iio/frequency/adf4350.c @@ -33,7 +33,6 @@ enum { struct adf4350_state { struct spi_device *spi; - struct regulator *reg; struct gpio_desc *lock_detect_gpiod; struct adf4350_platform_data *pdata; struct clk *clk; @@ -469,6 +468,15 @@ static struct adf4350_platform_data *adf4350_parse_dt(struct device *dev) return pdata; } +static void adf4350_power_down(void *data) +{ + struct iio_dev *indio_dev = data; + struct adf4350_state *st = iio_priv(indio_dev); + + st->regs[ADF4350_REG2] |= ADF4350_REG2_POWER_DOWN_EN; + adf4350_sync_config(st); +} + static int adf4350_probe(struct spi_device *spi) { struct adf4350_platform_data *pdata; @@ -491,31 +499,21 @@ static int adf4350_probe(struct spi_device *spi) } if (!pdata->clkin) { - clk = devm_clk_get(&spi->dev, "clkin"); + clk = devm_clk_get_enabled(&spi->dev, "clkin"); if (IS_ERR(clk)) - return -EPROBE_DEFER; - - ret = clk_prepare_enable(clk); - if (ret < 0) - return ret; + return PTR_ERR(clk); } indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st)); - if (indio_dev == NULL) { - ret = -ENOMEM; - goto error_disable_clk; - } + if (indio_dev == NULL) + return -ENOMEM; st = iio_priv(indio_dev); - st->reg = devm_regulator_get(&spi->dev, "vcc"); - if (!IS_ERR(st->reg)) { - ret = regulator_enable(st->reg); - if (ret) - goto error_disable_clk; - } + ret = devm_regulator_get_enable(&spi->dev, "vcc"); + if (ret) + return ret; - spi_set_drvdata(spi, indio_dev); st->spi = spi; st->pdata = pdata; @@ -544,47 +542,21 @@ static int adf4350_probe(struct spi_device *spi) st->lock_detect_gpiod = devm_gpiod_get_optional(&spi->dev, NULL, GPIOD_IN); - if (IS_ERR(st->lock_detect_gpiod)) { - ret = PTR_ERR(st->lock_detect_gpiod); - goto error_disable_reg; - } + if (IS_ERR(st->lock_detect_gpiod)) + return PTR_ERR(st->lock_detect_gpiod); if (pdata->power_up_frequency) { ret = adf4350_set_freq(st, pdata->power_up_frequency); if (ret) - goto error_disable_reg; + return ret; } - ret = iio_device_register(indio_dev); + ret = devm_add_action_or_reset(&spi->dev, adf4350_power_down, indio_dev); if (ret) - goto error_disable_reg; + return dev_err_probe(&spi->dev, ret, + "Failed to add action to managed power down\n"); - return 0; - -error_disable_reg: - if (!IS_ERR(st->reg)) - regulator_disable(st->reg); -error_disable_clk: - clk_disable_unprepare(clk); - - return ret; -} - -static void adf4350_remove(struct spi_device *spi) -{ - struct iio_dev *indio_dev = spi_get_drvdata(spi); - struct adf4350_state *st = iio_priv(indio_dev); - struct regulator *reg = st->reg; - - st->regs[ADF4350_REG2] |= ADF4350_REG2_POWER_DOWN_EN; - adf4350_sync_config(st); - - iio_device_unregister(indio_dev); - - clk_disable_unprepare(st->clk); - - if (!IS_ERR(reg)) - regulator_disable(reg); + return devm_iio_device_register(&spi->dev, indio_dev); } static const struct of_device_id adf4350_of_match[] = { @@ -607,7 +579,6 @@ static struct spi_driver adf4350_driver = { .of_match_table = adf4350_of_match, }, .probe = adf4350_probe, - .remove = adf4350_remove, .id_table = adf4350_id, }; module_spi_driver(adf4350_driver); From 449635ec210eb50ee5d11be934350d994080ff40 Mon Sep 17 00:00:00 2001 From: Jinjie Ruan Date: Mon, 28 Aug 2023 14:45:44 +0800 Subject: [PATCH 015/326] iio: adc: at91_adc: Use devm_request_irq() helper function Use devm_request_irq() to request the interrupt, so we can avoid having to manually clean this up. Signed-off-by: Jinjie Ruan Link: https://lore.kernel.org/r/20230828064546.2383857-2-ruanjinjie@huawei.com Signed-off-by: Jonathan Cameron --- drivers/iio/adc/at91_adc.c | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/drivers/iio/adc/at91_adc.c b/drivers/iio/adc/at91_adc.c index de6650f9c4b1..771ad5c4a131 100644 --- a/drivers/iio/adc/at91_adc.c +++ b/drivers/iio/adc/at91_adc.c @@ -1077,11 +1077,13 @@ static int at91_adc_probe(struct platform_device *pdev) at91_adc_writel(st, AT91_ADC_IDR, 0xFFFFFFFF); if (st->caps->has_tsmr) - ret = request_irq(st->irq, at91_adc_9x5_interrupt, 0, - pdev->dev.driver->name, idev); + ret = devm_request_irq(&pdev->dev, st->irq, + at91_adc_9x5_interrupt, 0, + pdev->dev.driver->name, idev); else - ret = request_irq(st->irq, at91_adc_rl_interrupt, 0, - pdev->dev.driver->name, idev); + ret = devm_request_irq(&pdev->dev, st->irq, + at91_adc_rl_interrupt, 0, + pdev->dev.driver->name, idev); if (ret) { dev_err(&pdev->dev, "Failed to allocate IRQ.\n"); return ret; @@ -1090,15 +1092,14 @@ static int at91_adc_probe(struct platform_device *pdev) st->clk = devm_clk_get(&pdev->dev, "adc_clk"); if (IS_ERR(st->clk)) { dev_err(&pdev->dev, "Failed to get the clock.\n"); - ret = PTR_ERR(st->clk); - goto error_free_irq; + return PTR_ERR(st->clk); } ret = clk_prepare_enable(st->clk); if (ret) { dev_err(&pdev->dev, "Could not prepare or enable the clock.\n"); - goto error_free_irq; + return ret; } st->adc_clk = devm_clk_get(&pdev->dev, "adc_op_clk"); @@ -1211,8 +1212,6 @@ error_disable_adc_clk: clk_disable_unprepare(st->adc_clk); error_disable_clk: clk_disable_unprepare(st->clk); -error_free_irq: - free_irq(st->irq, idev); return ret; } @@ -1230,7 +1229,6 @@ static int at91_adc_remove(struct platform_device *pdev) } clk_disable_unprepare(st->adc_clk); clk_disable_unprepare(st->clk); - free_irq(st->irq, idev); return 0; } From 892de7031e905f242ea4e851abe5f4f7222e7455 Mon Sep 17 00:00:00 2001 From: Jinjie Ruan Date: Mon, 28 Aug 2023 14:45:45 +0800 Subject: [PATCH 016/326] iio: adc: at91_adc: Use devm_clk_get_enabled() helper function The devm_clk_get_enabled() helper: - calls devm_clk_get() - calls clk_prepare_enable() and registers what is needed in order to call clk_disable_unprepare() when needed, as a managed resource. This simplifies the code. Signed-off-by: Jinjie Ruan Link: https://lore.kernel.org/r/20230828064546.2383857-3-ruanjinjie@huawei.com Signed-off-by: Jonathan Cameron --- drivers/iio/adc/at91_adc.c | 40 ++++++++++---------------------------- 1 file changed, 10 insertions(+), 30 deletions(-) diff --git a/drivers/iio/adc/at91_adc.c b/drivers/iio/adc/at91_adc.c index 771ad5c4a131..e5610722ce0b 100644 --- a/drivers/iio/adc/at91_adc.c +++ b/drivers/iio/adc/at91_adc.c @@ -1089,31 +1089,18 @@ static int at91_adc_probe(struct platform_device *pdev) return ret; } - st->clk = devm_clk_get(&pdev->dev, "adc_clk"); + st->clk = devm_clk_get_enabled(&pdev->dev, "adc_clk"); if (IS_ERR(st->clk)) { - dev_err(&pdev->dev, "Failed to get the clock.\n"); + dev_err(&pdev->dev, + "Could not prepare or enable the clock.\n"); return PTR_ERR(st->clk); } - ret = clk_prepare_enable(st->clk); - if (ret) { - dev_err(&pdev->dev, - "Could not prepare or enable the clock.\n"); - return ret; - } - - st->adc_clk = devm_clk_get(&pdev->dev, "adc_op_clk"); + st->adc_clk = devm_clk_get_enabled(&pdev->dev, "adc_op_clk"); if (IS_ERR(st->adc_clk)) { - dev_err(&pdev->dev, "Failed to get the ADC clock.\n"); - ret = PTR_ERR(st->adc_clk); - goto error_disable_clk; - } - - ret = clk_prepare_enable(st->adc_clk); - if (ret) { dev_err(&pdev->dev, "Could not prepare or enable the ADC clock.\n"); - goto error_disable_clk; + return PTR_ERR(st->adc_clk); } /* @@ -1132,8 +1119,7 @@ static int at91_adc_probe(struct platform_device *pdev) if (!st->startup_time) { dev_err(&pdev->dev, "No startup time available.\n"); - ret = -EINVAL; - goto error_disable_adc_clk; + return -EINVAL; } ticks = (*st->caps->calc_startup_ticks)(st->startup_time, adc_clk_khz); @@ -1161,7 +1147,7 @@ static int at91_adc_probe(struct platform_device *pdev) ret = at91_adc_channel_init(idev); if (ret < 0) { dev_err(&pdev->dev, "Couldn't initialize the channels.\n"); - goto error_disable_adc_clk; + return ret; } init_waitqueue_head(&st->wq_data_avail); @@ -1176,19 +1162,19 @@ static int at91_adc_probe(struct platform_device *pdev) ret = at91_adc_buffer_init(idev); if (ret < 0) { dev_err(&pdev->dev, "Couldn't initialize the buffer.\n"); - goto error_disable_adc_clk; + return ret; } ret = at91_adc_trigger_init(idev); if (ret < 0) { dev_err(&pdev->dev, "Couldn't setup the triggers.\n"); at91_adc_buffer_remove(idev); - goto error_disable_adc_clk; + return ret; } } else { ret = at91_ts_register(idev, pdev); if (ret) - goto error_disable_adc_clk; + return ret; at91_ts_hw_init(idev, adc_clk_khz); } @@ -1208,10 +1194,6 @@ error_iio_device_register: } else { at91_ts_unregister(st); } -error_disable_adc_clk: - clk_disable_unprepare(st->adc_clk); -error_disable_clk: - clk_disable_unprepare(st->clk); return ret; } @@ -1227,8 +1209,6 @@ static int at91_adc_remove(struct platform_device *pdev) } else { at91_ts_unregister(st); } - clk_disable_unprepare(st->adc_clk); - clk_disable_unprepare(st->clk); return 0; } From 974a6c27b4d707f75d283805e7fc8aa54686f198 Mon Sep 17 00:00:00 2001 From: Jinjie Ruan Date: Mon, 28 Aug 2023 14:45:46 +0800 Subject: [PATCH 017/326] iio: adc: at91_adc: Simplify with dev_err_probe() Use the dev_err_probe() helper to simplify error handling during probe. This also handle scenario, when EDEFER is returned and useless error is printed. Signed-off-by: Jinjie Ruan Link: https://lore.kernel.org/r/20230828064546.2383857-4-ruanjinjie@huawei.com Signed-off-by: Jonathan Cameron --- drivers/iio/adc/at91_adc.c | 66 ++++++++++++++++---------------------- 1 file changed, 27 insertions(+), 39 deletions(-) diff --git a/drivers/iio/adc/at91_adc.c b/drivers/iio/adc/at91_adc.c index e5610722ce0b..200c4599530b 100644 --- a/drivers/iio/adc/at91_adc.c +++ b/drivers/iio/adc/at91_adc.c @@ -1013,28 +1013,25 @@ static int at91_adc_probe(struct platform_device *pdev) st->use_external = of_property_read_bool(node, "atmel,adc-use-external-triggers"); - if (of_property_read_u32(node, "atmel,adc-channels-used", &prop)) { - dev_err(&idev->dev, "Missing adc-channels-used property in the DT.\n"); - return -EINVAL; - } + if (of_property_read_u32(node, "atmel,adc-channels-used", &prop)) + return dev_err_probe(&idev->dev, -EINVAL, + "Missing adc-channels-used property in the DT.\n"); st->channels_mask = prop; st->sleep_mode = of_property_read_bool(node, "atmel,adc-sleep-mode"); - if (of_property_read_u32(node, "atmel,adc-startup-time", &prop)) { - dev_err(&idev->dev, "Missing adc-startup-time property in the DT.\n"); - return -EINVAL; - } + if (of_property_read_u32(node, "atmel,adc-startup-time", &prop)) + return dev_err_probe(&idev->dev, -EINVAL, + "Missing adc-startup-time property in the DT.\n"); st->startup_time = prop; prop = 0; of_property_read_u32(node, "atmel,adc-sample-hold-time", &prop); st->sample_hold_time = prop; - if (of_property_read_u32(node, "atmel,adc-vref", &prop)) { - dev_err(&idev->dev, "Missing adc-vref property in the DT.\n"); - return -EINVAL; - } + if (of_property_read_u32(node, "atmel,adc-vref", &prop)) + return dev_err_probe(&idev->dev, -EINVAL, + "Missing adc-vref property in the DT.\n"); st->vref_mv = prop; st->res = st->caps->high_res_bits; @@ -1069,7 +1066,6 @@ static int at91_adc_probe(struct platform_device *pdev) if (IS_ERR(st->reg_base)) return PTR_ERR(st->reg_base); - /* * Disable all IRQs before setting up the handler */ @@ -1084,24 +1080,19 @@ static int at91_adc_probe(struct platform_device *pdev) ret = devm_request_irq(&pdev->dev, st->irq, at91_adc_rl_interrupt, 0, pdev->dev.driver->name, idev); - if (ret) { - dev_err(&pdev->dev, "Failed to allocate IRQ.\n"); - return ret; - } + if (ret) + return dev_err_probe(&pdev->dev, ret, + "Failed to allocate IRQ.\n"); st->clk = devm_clk_get_enabled(&pdev->dev, "adc_clk"); - if (IS_ERR(st->clk)) { - dev_err(&pdev->dev, - "Could not prepare or enable the clock.\n"); - return PTR_ERR(st->clk); - } + if (IS_ERR(st->clk)) + return dev_err_probe(&pdev->dev, PTR_ERR(st->clk), + "Could not prepare or enable the clock.\n"); st->adc_clk = devm_clk_get_enabled(&pdev->dev, "adc_op_clk"); - if (IS_ERR(st->adc_clk)) { - dev_err(&pdev->dev, - "Could not prepare or enable the ADC clock.\n"); - return PTR_ERR(st->adc_clk); - } + if (IS_ERR(st->adc_clk)) + return dev_err_probe(&pdev->dev, PTR_ERR(st->adc_clk), + "Could not prepare or enable the ADC clock.\n"); /* * Prescaler rate computation using the formula from the Atmel's @@ -1117,10 +1108,9 @@ static int at91_adc_probe(struct platform_device *pdev) prsc = (mstrclk / (2 * adc_clk)) - 1; - if (!st->startup_time) { - dev_err(&pdev->dev, "No startup time available.\n"); - return -EINVAL; - } + if (!st->startup_time) + return dev_err_probe(&pdev->dev, -EINVAL, + "No startup time available.\n"); ticks = (*st->caps->calc_startup_ticks)(st->startup_time, adc_clk_khz); /* @@ -1145,10 +1135,9 @@ static int at91_adc_probe(struct platform_device *pdev) /* Setup the ADC channels available on the board */ ret = at91_adc_channel_init(idev); - if (ret < 0) { - dev_err(&pdev->dev, "Couldn't initialize the channels.\n"); - return ret; - } + if (ret < 0) + return dev_err_probe(&pdev->dev, ret, + "Couldn't initialize the channels.\n"); init_waitqueue_head(&st->wq_data_avail); mutex_init(&st->lock); @@ -1160,10 +1149,9 @@ static int at91_adc_probe(struct platform_device *pdev) */ if (!st->touchscreen_type) { ret = at91_adc_buffer_init(idev); - if (ret < 0) { - dev_err(&pdev->dev, "Couldn't initialize the buffer.\n"); - return ret; - } + if (ret < 0) + return dev_err_probe(&pdev->dev, ret, + "Couldn't initialize the buffer.\n"); ret = at91_adc_trigger_init(idev); if (ret < 0) { From 0f8eaeda7659d02063278c7eb72bbcd2d2819375 Mon Sep 17 00:00:00 2001 From: Biju Das Date: Fri, 18 Aug 2023 19:40:32 +0100 Subject: [PATCH 018/326] iio: accel: mma8452: Convert enum->pointer for data in the ID table Convert enum->pointer for data in the ID table, so that device_get_match_data() can do match against OF/ACPI/I2C tables, once i2c bus type match support added to it. Replace enum->struct *mma_chip_info for data in the ID table and simplify mma8452_probe() by replacing device_get_match_data() with i2c_get_match_data(). Signed-off-by: Biju Das Reviewed-by: Hans de Goede Link: https://lore.kernel.org/r/20230818184033.335502-2-biju.das.jz@bp.renesas.com Signed-off-by: Jonathan Cameron --- drivers/iio/accel/mma8452.c | 26 ++++++++++---------------- 1 file changed, 10 insertions(+), 16 deletions(-) diff --git a/drivers/iio/accel/mma8452.c b/drivers/iio/accel/mma8452.c index f42a88711486..5864ad726e97 100644 --- a/drivers/iio/accel/mma8452.c +++ b/drivers/iio/accel/mma8452.c @@ -1547,7 +1547,6 @@ MODULE_DEVICE_TABLE(of, mma8452_dt_ids); static int mma8452_probe(struct i2c_client *client) { - const struct i2c_device_id *id = i2c_client_get_device_id(client); struct mma8452_data *data; struct iio_dev *indio_dev; int ret; @@ -1560,15 +1559,10 @@ static int mma8452_probe(struct i2c_client *client) data->client = client; mutex_init(&data->lock); - data->chip_info = device_get_match_data(&client->dev); - if (!data->chip_info) { - if (id) { - data->chip_info = &mma_chip_info_table[id->driver_data]; - } else { - dev_err(&client->dev, "unknown device model\n"); - return -ENODEV; - } - } + data->chip_info = i2c_get_match_data(client); + if (!data->chip_info) + return dev_err_probe(&client->dev, -ENODEV, + "unknown device model\n"); ret = iio_read_mount_matrix(&client->dev, &data->orientation); if (ret) @@ -1830,12 +1824,12 @@ static const struct dev_pm_ops mma8452_pm_ops = { }; static const struct i2c_device_id mma8452_id[] = { - { "mma8451", mma8451 }, - { "mma8452", mma8452 }, - { "mma8453", mma8453 }, - { "mma8652", mma8652 }, - { "mma8653", mma8653 }, - { "fxls8471", fxls8471 }, + { "mma8451", (kernel_ulong_t)&mma_chip_info_table[mma8451] }, + { "mma8452", (kernel_ulong_t)&mma_chip_info_table[mma8452] }, + { "mma8453", (kernel_ulong_t)&mma_chip_info_table[mma8453] }, + { "mma8652", (kernel_ulong_t)&mma_chip_info_table[mma8652] }, + { "mma8653", (kernel_ulong_t)&mma_chip_info_table[mma8653] }, + { "fxls8471", (kernel_ulong_t)&mma_chip_info_table[fxls8471] }, { } }; MODULE_DEVICE_TABLE(i2c, mma8452_id); From 6915f0b98b71e5f6a5e49b0ec3ab98a387cef0f3 Mon Sep 17 00:00:00 2001 From: Biju Das Date: Fri, 18 Aug 2023 19:40:33 +0100 Subject: [PATCH 019/326] iio: accel: mma8452: Sort match tables Sort ID table alphabetically by name and OF table by compatible. Suggested-by: Andy Shevchenko Signed-off-by: Biju Das Reviewed-by: Andy Shevchenko Link: https://lore.kernel.org/r/20230818184033.335502-3-biju.das.jz@bp.renesas.com Signed-off-by: Jonathan Cameron --- drivers/iio/accel/mma8452.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/iio/accel/mma8452.c b/drivers/iio/accel/mma8452.c index 5864ad726e97..d3fd0318e47b 100644 --- a/drivers/iio/accel/mma8452.c +++ b/drivers/iio/accel/mma8452.c @@ -1535,12 +1535,12 @@ static int mma8452_reset(struct i2c_client *client) } static const struct of_device_id mma8452_dt_ids[] = { + { .compatible = "fsl,fxls8471", .data = &mma_chip_info_table[fxls8471] }, { .compatible = "fsl,mma8451", .data = &mma_chip_info_table[mma8451] }, { .compatible = "fsl,mma8452", .data = &mma_chip_info_table[mma8452] }, { .compatible = "fsl,mma8453", .data = &mma_chip_info_table[mma8453] }, { .compatible = "fsl,mma8652", .data = &mma_chip_info_table[mma8652] }, { .compatible = "fsl,mma8653", .data = &mma_chip_info_table[mma8653] }, - { .compatible = "fsl,fxls8471", .data = &mma_chip_info_table[fxls8471] }, { } }; MODULE_DEVICE_TABLE(of, mma8452_dt_ids); @@ -1824,12 +1824,12 @@ static const struct dev_pm_ops mma8452_pm_ops = { }; static const struct i2c_device_id mma8452_id[] = { + { "fxls8471", (kernel_ulong_t)&mma_chip_info_table[fxls8471] }, { "mma8451", (kernel_ulong_t)&mma_chip_info_table[mma8451] }, { "mma8452", (kernel_ulong_t)&mma_chip_info_table[mma8452] }, { "mma8453", (kernel_ulong_t)&mma_chip_info_table[mma8453] }, { "mma8652", (kernel_ulong_t)&mma_chip_info_table[mma8652] }, { "mma8653", (kernel_ulong_t)&mma_chip_info_table[mma8653] }, - { "fxls8471", (kernel_ulong_t)&mma_chip_info_table[fxls8471] }, { } }; MODULE_DEVICE_TABLE(i2c, mma8452_id); From 2b0ddc83dcb51737ef52fb1f42ec651a94aafa2c Mon Sep 17 00:00:00 2001 From: Biju Das Date: Fri, 18 Aug 2023 20:04:29 +0100 Subject: [PATCH 020/326] iio: chemical: vz89x: Convert enum->pointer for data in the match tables Convert enum->pointer for data in the match tables, so that device_get_match_data() can do match against OF/ACPI/I2C tables, once i2c bus type match support added to it. Replace enum->struct *vz89x_chip_data for data in the match table. Simplify the probe() by replacing device_get_match_data() and ID lookup for retrieving data by i2c_get_match_data(). Signed-off-by: Biju Das Reviewed-by: Andy Shevchenko Link: https://lore.kernel.org/r/20230818190429.338065-1-biju.das.jz@bp.renesas.com Signed-off-by: Jonathan Cameron --- drivers/iio/chemical/vz89x.c | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/drivers/iio/chemical/vz89x.c b/drivers/iio/chemical/vz89x.c index 13555f4f401a..5b358bcd311b 100644 --- a/drivers/iio/chemical/vz89x.c +++ b/drivers/iio/chemical/vz89x.c @@ -342,19 +342,17 @@ static const struct vz89x_chip_data vz89x_chips[] = { }; static const struct of_device_id vz89x_dt_ids[] = { - { .compatible = "sgx,vz89x", .data = (void *) VZ89X }, - { .compatible = "sgx,vz89te", .data = (void *) VZ89TE }, + { .compatible = "sgx,vz89x", .data = &vz89x_chips[VZ89X] }, + { .compatible = "sgx,vz89te", .data = &vz89x_chips[VZ89TE] }, { } }; MODULE_DEVICE_TABLE(of, vz89x_dt_ids); static int vz89x_probe(struct i2c_client *client) { - const struct i2c_device_id *id = i2c_client_get_device_id(client); struct device *dev = &client->dev; struct iio_dev *indio_dev; struct vz89x_data *data; - int chip_id; indio_dev = devm_iio_device_alloc(dev, sizeof(*data)); if (!indio_dev) @@ -369,14 +367,10 @@ static int vz89x_probe(struct i2c_client *client) else return -EOPNOTSUPP; - if (!dev_fwnode(dev)) - chip_id = id->driver_data; - else - chip_id = (unsigned long)device_get_match_data(dev); + data->chip = i2c_get_match_data(client); i2c_set_clientdata(client, indio_dev); data->client = client; - data->chip = &vz89x_chips[chip_id]; data->last_update = jiffies - HZ; mutex_init(&data->lock); @@ -391,8 +385,8 @@ static int vz89x_probe(struct i2c_client *client) } static const struct i2c_device_id vz89x_id[] = { - { "vz89x", VZ89X }, - { "vz89te", VZ89TE }, + { "vz89x", (kernel_ulong_t)&vz89x_chips[VZ89X] }, + { "vz89te", (kernel_ulong_t)&vz89x_chips[VZ89TE] }, { } }; MODULE_DEVICE_TABLE(i2c, vz89x_id); From ab3555b4b5b08fb03b8da904cc3fedbba91560df Mon Sep 17 00:00:00 2001 From: Biju Das Date: Fri, 18 Aug 2023 19:55:31 +0100 Subject: [PATCH 021/326] iio: chemical: atlas-sensor: Convert enum->pointer for data in the match tables Convert enum->pointer for data in the match tables, so that device_get_match_data() can do match against OF/ACPI/I2C tables, once i2c bus type match support added to it. Replace enum->struct *atlas_device for data in the match table. Simplify the probe() by replacing device_get_match_data() and ID lookup for retrieving data by i2c_get_match_data(). While at it, add const qualifier to struct atlas_device and drop inner trailing commas from OF table. Signed-off-by: Biju Das Reviewed-by: Andy Shevchenko Link: https://lore.kernel.org/r/20230818185531.336672-1-biju.das.jz@bp.renesas.com Signed-off-by: Jonathan Cameron --- drivers/iio/chemical/atlas-sensor.c | 32 +++++++++++++---------------- 1 file changed, 14 insertions(+), 18 deletions(-) diff --git a/drivers/iio/chemical/atlas-sensor.c b/drivers/iio/chemical/atlas-sensor.c index fb15bb216019..baf93e5e3ca7 100644 --- a/drivers/iio/chemical/atlas-sensor.c +++ b/drivers/iio/chemical/atlas-sensor.c @@ -87,7 +87,7 @@ enum { struct atlas_data { struct i2c_client *client; struct iio_trigger *trig; - struct atlas_device *chip; + const struct atlas_device *chip; struct regmap *regmap; struct irq_work work; unsigned int interrupt_enabled; @@ -353,7 +353,7 @@ struct atlas_device { int delay; }; -static struct atlas_device atlas_devices[] = { +static const struct atlas_device atlas_devices[] = { [ATLAS_PH_SM] = { .channels = atlas_ph_channels, .num_channels = 3, @@ -589,30 +589,29 @@ static const struct iio_info atlas_info = { }; static const struct i2c_device_id atlas_id[] = { - { "atlas-ph-sm", ATLAS_PH_SM }, - { "atlas-ec-sm", ATLAS_EC_SM }, - { "atlas-orp-sm", ATLAS_ORP_SM }, - { "atlas-do-sm", ATLAS_DO_SM }, - { "atlas-rtd-sm", ATLAS_RTD_SM }, + { "atlas-ph-sm", (kernel_ulong_t)&atlas_devices[ATLAS_PH_SM] }, + { "atlas-ec-sm", (kernel_ulong_t)&atlas_devices[ATLAS_EC_SM] }, + { "atlas-orp-sm", (kernel_ulong_t)&atlas_devices[ATLAS_ORP_SM] }, + { "atlas-do-sm", (kernel_ulong_t)&atlas_devices[ATLAS_DO_SM] }, + { "atlas-rtd-sm", (kernel_ulong_t)&atlas_devices[ATLAS_RTD_SM] }, {} }; MODULE_DEVICE_TABLE(i2c, atlas_id); static const struct of_device_id atlas_dt_ids[] = { - { .compatible = "atlas,ph-sm", .data = (void *)ATLAS_PH_SM, }, - { .compatible = "atlas,ec-sm", .data = (void *)ATLAS_EC_SM, }, - { .compatible = "atlas,orp-sm", .data = (void *)ATLAS_ORP_SM, }, - { .compatible = "atlas,do-sm", .data = (void *)ATLAS_DO_SM, }, - { .compatible = "atlas,rtd-sm", .data = (void *)ATLAS_RTD_SM, }, + { .compatible = "atlas,ph-sm", .data = &atlas_devices[ATLAS_PH_SM] }, + { .compatible = "atlas,ec-sm", .data = &atlas_devices[ATLAS_EC_SM] }, + { .compatible = "atlas,orp-sm", .data = &atlas_devices[ATLAS_ORP_SM] }, + { .compatible = "atlas,do-sm", .data = &atlas_devices[ATLAS_DO_SM] }, + { .compatible = "atlas,rtd-sm", .data = &atlas_devices[ATLAS_RTD_SM] }, { } }; MODULE_DEVICE_TABLE(of, atlas_dt_ids); static int atlas_probe(struct i2c_client *client) { - const struct i2c_device_id *id = i2c_client_get_device_id(client); struct atlas_data *data; - struct atlas_device *chip; + const struct atlas_device *chip; struct iio_trigger *trig; struct iio_dev *indio_dev; int ret; @@ -621,10 +620,7 @@ static int atlas_probe(struct i2c_client *client) if (!indio_dev) return -ENOMEM; - if (!dev_fwnode(&client->dev)) - chip = &atlas_devices[id->driver_data]; - else - chip = &atlas_devices[(unsigned long)device_get_match_data(&client->dev)]; + chip = i2c_get_match_data(client); indio_dev->info = &atlas_info; indio_dev->name = ATLAS_DRV_NAME; From 7f8643aa5e0fbf540eeba412fc2a7d4dfc2f22f8 Mon Sep 17 00:00:00 2001 From: Biju Das Date: Fri, 18 Aug 2023 19:31:28 +0100 Subject: [PATCH 022/326] iio: chemical: atlas-ezo-sensor: Simplify probe() Simplify the probe() by replacing device_get_match_data() and ID lookup match by i2c_get_match_data() as we have similar I2C and DT-based matching table. Signed-off-by: Biju Das Reviewed-by: Andy Shevchenko Link: https://lore.kernel.org/r/20230818183128.334233-1-biju.das.jz@bp.renesas.com Signed-off-by: Jonathan Cameron --- drivers/iio/chemical/atlas-ezo-sensor.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/drivers/iio/chemical/atlas-ezo-sensor.c b/drivers/iio/chemical/atlas-ezo-sensor.c index 8fc926a2d33b..761a853a4d17 100644 --- a/drivers/iio/chemical/atlas-ezo-sensor.c +++ b/drivers/iio/chemical/atlas-ezo-sensor.c @@ -203,7 +203,6 @@ MODULE_DEVICE_TABLE(of, atlas_ezo_dt_ids); static int atlas_ezo_probe(struct i2c_client *client) { - const struct i2c_device_id *id = i2c_client_get_device_id(client); const struct atlas_ezo_device *chip; struct atlas_ezo_data *data; struct iio_dev *indio_dev; @@ -212,10 +211,7 @@ static int atlas_ezo_probe(struct i2c_client *client) if (!indio_dev) return -ENOMEM; - if (dev_fwnode(&client->dev)) - chip = device_get_match_data(&client->dev); - else - chip = (const struct atlas_ezo_device *)id->driver_data; + chip = i2c_get_match_data(client); if (!chip) return -EINVAL; From 21fd3b1373f65c6a9d910642ecef194a077d1624 Mon Sep 17 00:00:00 2001 From: Biju Das Date: Fri, 18 Aug 2023 18:58:19 +0100 Subject: [PATCH 023/326] iio: proximity: sx9310: Convert enum->pointer for match data table Convert enum->pointer for data in match data table, so that device_get_match_data() can do match against OF/ACPI/I2C tables, once i2c bus type match support added to it. Add struct sx931x_info and replace enum->sx931x_info in the match table and simplify sx9310_check_whoami(). Signed-off-by: Biju Das Reviewed-by: Andy Shevchenko Reviewed-by: Stephen Boyd Link: https://lore.kernel.org/r/20230818175819.325663-1-biju.das.jz@bp.renesas.com Signed-off-by: Jonathan Cameron --- drivers/iio/proximity/sx9310.c | 46 +++++++++++++++++++--------------- 1 file changed, 26 insertions(+), 20 deletions(-) diff --git a/drivers/iio/proximity/sx9310.c b/drivers/iio/proximity/sx9310.c index d977aacb7491..0d230a0dff56 100644 --- a/drivers/iio/proximity/sx9310.c +++ b/drivers/iio/proximity/sx9310.c @@ -159,6 +159,11 @@ static_assert(SX9310_NUM_CHANNELS <= SX_COMMON_MAX_NUM_CHANNELS); } #define SX9310_CHANNEL(idx) SX9310_NAMED_CHANNEL(idx, NULL) +struct sx931x_info { + const char *name; + unsigned int whoami; +}; + static const struct iio_chan_spec sx9310_channels[] = { SX9310_CHANNEL(0), /* CS0 */ SX9310_CHANNEL(1), /* CS1 */ @@ -902,7 +907,7 @@ static int sx9310_check_whoami(struct device *dev, struct iio_dev *indio_dev) { struct sx_common_data *data = iio_priv(indio_dev); - unsigned int long ddata; + const struct sx931x_info *ddata; unsigned int whoami; int ret; @@ -910,20 +915,11 @@ static int sx9310_check_whoami(struct device *dev, if (ret) return ret; - ddata = (uintptr_t)device_get_match_data(dev); - if (ddata != whoami) - return -EINVAL; - - switch (whoami) { - case SX9310_WHOAMI_VALUE: - indio_dev->name = "sx9310"; - break; - case SX9311_WHOAMI_VALUE: - indio_dev->name = "sx9311"; - break; - default: + ddata = device_get_match_data(dev); + if (ddata->whoami != whoami) return -ENODEV; - } + + indio_dev->name = ddata->name; return 0; } @@ -1015,23 +1011,33 @@ out: static DEFINE_SIMPLE_DEV_PM_OPS(sx9310_pm_ops, sx9310_suspend, sx9310_resume); +static const struct sx931x_info sx9310_info = { + .name = "sx9310", + .whoami = SX9310_WHOAMI_VALUE, +}; + +static const struct sx931x_info sx9311_info = { + .name = "sx9311", + .whoami = SX9311_WHOAMI_VALUE, +}; + static const struct acpi_device_id sx9310_acpi_match[] = { - { "STH9310", SX9310_WHOAMI_VALUE }, - { "STH9311", SX9311_WHOAMI_VALUE }, + { "STH9310", (kernel_ulong_t)&sx9310_info }, + { "STH9311", (kernel_ulong_t)&sx9311_info }, {} }; MODULE_DEVICE_TABLE(acpi, sx9310_acpi_match); static const struct of_device_id sx9310_of_match[] = { - { .compatible = "semtech,sx9310", (void *)SX9310_WHOAMI_VALUE }, - { .compatible = "semtech,sx9311", (void *)SX9311_WHOAMI_VALUE }, + { .compatible = "semtech,sx9310", &sx9310_info }, + { .compatible = "semtech,sx9311", &sx9311_info }, {} }; MODULE_DEVICE_TABLE(of, sx9310_of_match); static const struct i2c_device_id sx9310_id[] = { - { "sx9310", SX9310_WHOAMI_VALUE }, - { "sx9311", SX9311_WHOAMI_VALUE }, + { "sx9310", (kernel_ulong_t)&sx9310_info }, + { "sx9311", (kernel_ulong_t)&sx9311_info }, {} }; MODULE_DEVICE_TABLE(i2c, sx9310_id); From 17dc571687c5cc60e88fe29a33da0b9c64647086 Mon Sep 17 00:00:00 2001 From: Biju Das Date: Fri, 18 Aug 2023 18:39:06 +0100 Subject: [PATCH 024/326] iio: dac: ti-dac5571: Use i2c_get_match_data() Replace device_get_match_data() and id lookup for retrieving match data by i2c_get_match_data() by converting enum->pointer for data in the match table. Signed-off-by: Biju Das Link: https://lore.kernel.org/r/20230818173907.323640-2-biju.das.jz@bp.renesas.com Signed-off-by: Jonathan Cameron --- drivers/iio/dac/ti-dac5571.c | 48 ++++++++++++++++-------------------- 1 file changed, 21 insertions(+), 27 deletions(-) diff --git a/drivers/iio/dac/ti-dac5571.c b/drivers/iio/dac/ti-dac5571.c index bab11b9adc25..2bb3f76569ee 100644 --- a/drivers/iio/dac/ti-dac5571.c +++ b/drivers/iio/dac/ti-dac5571.c @@ -313,7 +313,6 @@ static int dac5571_probe(struct i2c_client *client) const struct dac5571_spec *spec; struct dac5571_data *data; struct iio_dev *indio_dev; - enum chip_id chip_id; int ret, i; indio_dev = devm_iio_device_alloc(dev, sizeof(*data)); @@ -329,12 +328,7 @@ static int dac5571_probe(struct i2c_client *client) indio_dev->modes = INDIO_DIRECT_MODE; indio_dev->channels = dac5571_channels; - if (dev_fwnode(dev)) - chip_id = (uintptr_t)device_get_match_data(dev); - else - chip_id = id->driver_data; - - spec = &dac5571_spec[chip_id]; + spec = i2c_get_match_data(client); indio_dev->num_channels = spec->num_channels; data->spec = spec; @@ -392,31 +386,31 @@ static void dac5571_remove(struct i2c_client *i2c) } static const struct of_device_id dac5571_of_id[] = { - {.compatible = "ti,dac5571", .data = (void *)single_8bit}, - {.compatible = "ti,dac6571", .data = (void *)single_10bit}, - {.compatible = "ti,dac7571", .data = (void *)single_12bit}, - {.compatible = "ti,dac5574", .data = (void *)quad_8bit}, - {.compatible = "ti,dac6574", .data = (void *)quad_10bit}, - {.compatible = "ti,dac7574", .data = (void *)quad_12bit}, - {.compatible = "ti,dac5573", .data = (void *)quad_8bit}, - {.compatible = "ti,dac6573", .data = (void *)quad_10bit}, - {.compatible = "ti,dac7573", .data = (void *)quad_12bit}, - {.compatible = "ti,dac121c081", .data = (void *)single_12bit}, + {.compatible = "ti,dac5571", .data = &dac5571_spec[single_8bit] }, + {.compatible = "ti,dac6571", .data = &dac5571_spec[single_10bit] }, + {.compatible = "ti,dac7571", .data = &dac5571_spec[single_12bit] }, + {.compatible = "ti,dac5574", .data = &dac5571_spec[quad_8bit] }, + {.compatible = "ti,dac6574", .data = &dac5571_spec[quad_10bit] }, + {.compatible = "ti,dac7574", .data = &dac5571_spec[quad_12bit] }, + {.compatible = "ti,dac5573", .data = &dac5571_spec[quad_8bit] }, + {.compatible = "ti,dac6573", .data = &dac5571_spec[quad_10bit] }, + {.compatible = "ti,dac7573", .data = &dac5571_spec[quad_12bit] }, + {.compatible = "ti,dac121c081", .data = &dac5571_spec[single_12bit] }, {} }; MODULE_DEVICE_TABLE(of, dac5571_of_id); static const struct i2c_device_id dac5571_id[] = { - {"dac5571", single_8bit}, - {"dac6571", single_10bit}, - {"dac7571", single_12bit}, - {"dac5574", quad_8bit}, - {"dac6574", quad_10bit}, - {"dac7574", quad_12bit}, - {"dac5573", quad_8bit}, - {"dac6573", quad_10bit}, - {"dac7573", quad_12bit}, - {"dac121c081", single_12bit}, + {"dac5571", (kernel_ulong_t)&dac5571_spec[single_8bit] }, + {"dac6571", (kernel_ulong_t)&dac5571_spec[single_10bit] }, + {"dac7571", (kernel_ulong_t)&dac5571_spec[single_12bit] }, + {"dac5574", (kernel_ulong_t)&dac5571_spec[quad_8bit] }, + {"dac6574", (kernel_ulong_t)&dac5571_spec[quad_10bit] }, + {"dac7574", (kernel_ulong_t)&dac5571_spec[quad_12bit] }, + {"dac5573", (kernel_ulong_t)&dac5571_spec[quad_8bit] }, + {"dac6573", (kernel_ulong_t)&dac5571_spec[quad_10bit] }, + {"dac7573", (kernel_ulong_t)&dac5571_spec[quad_12bit] }, + {"dac121c081", (kernel_ulong_t)&dac5571_spec[single_12bit] }, {} }; MODULE_DEVICE_TABLE(i2c, dac5571_id); From 541d803abf33caa7243c99361a47f7b998966815 Mon Sep 17 00:00:00 2001 From: Biju Das Date: Fri, 18 Aug 2023 18:39:07 +0100 Subject: [PATCH 025/326] iio: dac: ti-dac5571: Sort match tables Sort ID table alphabetically by name and OF table by compatible for single_*bit enums. Suggested-by: Andy Shevchenko Signed-off-by: Biju Das Reviewed-by: Laurent Pinchart Link: https://lore.kernel.org/r/20230818173907.323640-3-biju.das.jz@bp.renesas.com Signed-off-by: Jonathan Cameron --- drivers/iio/dac/ti-dac5571.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/iio/dac/ti-dac5571.c b/drivers/iio/dac/ti-dac5571.c index 2bb3f76569ee..efb1269a77c1 100644 --- a/drivers/iio/dac/ti-dac5571.c +++ b/drivers/iio/dac/ti-dac5571.c @@ -386,6 +386,7 @@ static void dac5571_remove(struct i2c_client *i2c) } static const struct of_device_id dac5571_of_id[] = { + {.compatible = "ti,dac121c081", .data = &dac5571_spec[single_12bit] }, {.compatible = "ti,dac5571", .data = &dac5571_spec[single_8bit] }, {.compatible = "ti,dac6571", .data = &dac5571_spec[single_10bit] }, {.compatible = "ti,dac7571", .data = &dac5571_spec[single_12bit] }, @@ -395,12 +396,12 @@ static const struct of_device_id dac5571_of_id[] = { {.compatible = "ti,dac5573", .data = &dac5571_spec[quad_8bit] }, {.compatible = "ti,dac6573", .data = &dac5571_spec[quad_10bit] }, {.compatible = "ti,dac7573", .data = &dac5571_spec[quad_12bit] }, - {.compatible = "ti,dac121c081", .data = &dac5571_spec[single_12bit] }, {} }; MODULE_DEVICE_TABLE(of, dac5571_of_id); static const struct i2c_device_id dac5571_id[] = { + {"dac121c081", (kernel_ulong_t)&dac5571_spec[single_12bit] }, {"dac5571", (kernel_ulong_t)&dac5571_spec[single_8bit] }, {"dac6571", (kernel_ulong_t)&dac5571_spec[single_10bit] }, {"dac7571", (kernel_ulong_t)&dac5571_spec[single_12bit] }, @@ -410,7 +411,6 @@ static const struct i2c_device_id dac5571_id[] = { {"dac5573", (kernel_ulong_t)&dac5571_spec[quad_8bit] }, {"dac6573", (kernel_ulong_t)&dac5571_spec[quad_10bit] }, {"dac7573", (kernel_ulong_t)&dac5571_spec[quad_12bit] }, - {"dac121c081", (kernel_ulong_t)&dac5571_spec[single_12bit] }, {} }; MODULE_DEVICE_TABLE(i2c, dac5571_id); From 72d365398d96293291abdab23ab6be08e86001fa Mon Sep 17 00:00:00 2001 From: Biju Das Date: Sat, 12 Aug 2023 07:57:40 +0100 Subject: [PATCH 026/326] iio: magnetometer: yamaha-yas530: Use i2c_get_match_data() Simplify the probe() by replacing device_get_match_data() with i2c_get_match_data(). Signed-off-by: Biju Das Reviewed-by: Andy Shevchenko Link: https://lore.kernel.org/r/20230812065741.20990-2-biju.das.jz@bp.renesas.com Signed-off-by: Jonathan Cameron --- drivers/iio/magnetometer/yamaha-yas530.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/iio/magnetometer/yamaha-yas530.c b/drivers/iio/magnetometer/yamaha-yas530.c index c5e485bfc6fc..7b041bb38693 100644 --- a/drivers/iio/magnetometer/yamaha-yas530.c +++ b/drivers/iio/magnetometer/yamaha-yas530.c @@ -1434,9 +1434,7 @@ static int yas5xx_probe(struct i2c_client *i2c) goto assert_reset; } - ci = device_get_match_data(dev); - if (!ci) - ci = (const struct yas5xx_chip_info *)id->driver_data; + ci = i2c_get_match_data(i2c); yas5xx->chip_info = ci; ret = regmap_read(yas5xx->map, YAS5XX_DEVICE_ID, &id_check); From 9f6001e390927aa3173cfd4c7d325b8f1d93ccf8 Mon Sep 17 00:00:00 2001 From: Biju Das Date: Sat, 12 Aug 2023 08:24:19 +0100 Subject: [PATCH 027/326] iio: adc: max1363: Use i2c_get_match_data() Replace device_get_match_data() and i2c_match_id() by i2c_get_match_data() by making similar I2C and DT-based matching table. Signed-off-by: Biju Das Link: https://lore.kernel.org/r/20230812072419.42645-1-biju.das.jz@bp.renesas.com Signed-off-by: Jonathan Cameron --- drivers/iio/adc/max1363.c | 87 ++++++++++++++++++++------------------- 1 file changed, 45 insertions(+), 42 deletions(-) diff --git a/drivers/iio/adc/max1363.c b/drivers/iio/adc/max1363.c index b31581616ce3..7c2a98b8c3a9 100644 --- a/drivers/iio/adc/max1363.c +++ b/drivers/iio/adc/max1363.c @@ -1599,9 +1599,7 @@ static int max1363_probe(struct i2c_client *client) if (ret) return ret; - st->chip_info = device_get_match_data(&client->dev); - if (!st->chip_info) - st->chip_info = &max1363_chip_info_tbl[id->driver_data]; + st->chip_info = i2c_get_match_data(client); st->client = client; st->vref_uv = st->chip_info->int_vref_mv * 1000; @@ -1669,46 +1667,51 @@ static int max1363_probe(struct i2c_client *client) return devm_iio_device_register(&client->dev, indio_dev); } +#define MAX1363_ID_TABLE(_name, cfg) { \ + .name = _name, \ + .driver_data = (kernel_ulong_t)&max1363_chip_info_tbl[cfg], \ +} + static const struct i2c_device_id max1363_id[] = { - { "max1361", max1361 }, - { "max1362", max1362 }, - { "max1363", max1363 }, - { "max1364", max1364 }, - { "max1036", max1036 }, - { "max1037", max1037 }, - { "max1038", max1038 }, - { "max1039", max1039 }, - { "max1136", max1136 }, - { "max1137", max1137 }, - { "max1138", max1138 }, - { "max1139", max1139 }, - { "max1236", max1236 }, - { "max1237", max1237 }, - { "max1238", max1238 }, - { "max1239", max1239 }, - { "max11600", max11600 }, - { "max11601", max11601 }, - { "max11602", max11602 }, - { "max11603", max11603 }, - { "max11604", max11604 }, - { "max11605", max11605 }, - { "max11606", max11606 }, - { "max11607", max11607 }, - { "max11608", max11608 }, - { "max11609", max11609 }, - { "max11610", max11610 }, - { "max11611", max11611 }, - { "max11612", max11612 }, - { "max11613", max11613 }, - { "max11614", max11614 }, - { "max11615", max11615 }, - { "max11616", max11616 }, - { "max11617", max11617 }, - { "max11644", max11644 }, - { "max11645", max11645 }, - { "max11646", max11646 }, - { "max11647", max11647 }, - {} + MAX1363_ID_TABLE("max1361", max1361), + MAX1363_ID_TABLE("max1362", max1362), + MAX1363_ID_TABLE("max1363", max1363), + MAX1363_ID_TABLE("max1364", max1364), + MAX1363_ID_TABLE("max1036", max1036), + MAX1363_ID_TABLE("max1037", max1037), + MAX1363_ID_TABLE("max1038", max1038), + MAX1363_ID_TABLE("max1039", max1039), + MAX1363_ID_TABLE("max1136", max1136), + MAX1363_ID_TABLE("max1137", max1137), + MAX1363_ID_TABLE("max1138", max1138), + MAX1363_ID_TABLE("max1139", max1139), + MAX1363_ID_TABLE("max1236", max1236), + MAX1363_ID_TABLE("max1237", max1237), + MAX1363_ID_TABLE("max1238", max1238), + MAX1363_ID_TABLE("max1239", max1239), + MAX1363_ID_TABLE("max11600", max11600), + MAX1363_ID_TABLE("max11601", max11601), + MAX1363_ID_TABLE("max11602", max11602), + MAX1363_ID_TABLE("max11603", max11603), + MAX1363_ID_TABLE("max11604", max11604), + MAX1363_ID_TABLE("max11605", max11605), + MAX1363_ID_TABLE("max11606", max11606), + MAX1363_ID_TABLE("max11607", max11607), + MAX1363_ID_TABLE("max11608", max11608), + MAX1363_ID_TABLE("max11609", max11609), + MAX1363_ID_TABLE("max11610", max11610), + MAX1363_ID_TABLE("max11611", max11611), + MAX1363_ID_TABLE("max11612", max11612), + MAX1363_ID_TABLE("max11613", max11613), + MAX1363_ID_TABLE("max11614", max11614), + MAX1363_ID_TABLE("max11615", max11615), + MAX1363_ID_TABLE("max11616", max11616), + MAX1363_ID_TABLE("max11617", max11617), + MAX1363_ID_TABLE("max11644", max11644), + MAX1363_ID_TABLE("max11645", max11645), + MAX1363_ID_TABLE("max11646", max11646), + MAX1363_ID_TABLE("max11647", max11647), + { /* sentinel */ } }; MODULE_DEVICE_TABLE(i2c, max1363_id); From fe11e389117a6d98a8a5c894f69975877c612d67 Mon Sep 17 00:00:00 2001 From: Biju Das Date: Sat, 12 Aug 2023 15:10:44 +0100 Subject: [PATCH 028/326] iio: accel: bma180: Convert enum->pointer for data in the match table Convert enum->pointer for data in the match table, so that device_get_match_data() can do match against OF/ACPI/I2C tables, once i2c bus type match support added to it. Replace enum->struct *bma180_part_info for data in the match table and simplify bma180_probe(). Signed-off-by: Biju Das Reviewed-by: Andy Shevchenko Link: https://lore.kernel.org/r/20230812141044.151520-1-biju.das.jz@bp.renesas.com Signed-off-by: Jonathan Cameron --- drivers/iio/accel/bma180.c | 27 +++++++++++---------------- 1 file changed, 11 insertions(+), 16 deletions(-) diff --git a/drivers/iio/accel/bma180.c b/drivers/iio/accel/bma180.c index 13439f52d26d..ab4fccb24b6c 100644 --- a/drivers/iio/accel/bma180.c +++ b/drivers/iio/accel/bma180.c @@ -926,7 +926,6 @@ static int bma180_probe(struct i2c_client *client) struct device *dev = &client->dev; struct bma180_data *data; struct iio_dev *indio_dev; - enum chip_ids chip; int ret; indio_dev = devm_iio_device_alloc(dev, sizeof(*data)); @@ -936,11 +935,7 @@ static int bma180_probe(struct i2c_client *client) data = iio_priv(indio_dev); i2c_set_clientdata(client, indio_dev); data->client = client; - if (client->dev.of_node) - chip = (uintptr_t)of_device_get_match_data(dev); - else - chip = id->driver_data; - data->part_info = &bma180_part_info[chip]; + data->part_info = i2c_get_match_data(client); ret = iio_read_mount_matrix(dev, &data->orientation); if (ret) @@ -1092,11 +1087,11 @@ static int bma180_resume(struct device *dev) static DEFINE_SIMPLE_DEV_PM_OPS(bma180_pm_ops, bma180_suspend, bma180_resume); static const struct i2c_device_id bma180_ids[] = { - { "bma023", BMA023 }, - { "bma150", BMA150 }, - { "bma180", BMA180 }, - { "bma250", BMA250 }, - { "smb380", BMA150 }, + { "bma023", (kernel_ulong_t)&bma180_part_info[BMA023] }, + { "bma150", (kernel_ulong_t)&bma180_part_info[BMA150] }, + { "bma180", (kernel_ulong_t)&bma180_part_info[BMA180] }, + { "bma250", (kernel_ulong_t)&bma180_part_info[BMA250] }, + { "smb380", (kernel_ulong_t)&bma180_part_info[BMA150] }, { } }; @@ -1105,23 +1100,23 @@ MODULE_DEVICE_TABLE(i2c, bma180_ids); static const struct of_device_id bma180_of_match[] = { { .compatible = "bosch,bma023", - .data = (void *)BMA023 + .data = &bma180_part_info[BMA023] }, { .compatible = "bosch,bma150", - .data = (void *)BMA150 + .data = &bma180_part_info[BMA150] }, { .compatible = "bosch,bma180", - .data = (void *)BMA180 + .data = &bma180_part_info[BMA180] }, { .compatible = "bosch,bma250", - .data = (void *)BMA250 + .data = &bma180_part_info[BMA250] }, { .compatible = "bosch,smb380", - .data = (void *)BMA150 + .data = &bma180_part_info[BMA150] }, { } }; From 4545d4777d9ede0f8061edf9a08c842d719c0fe6 Mon Sep 17 00:00:00 2001 From: Biju Das Date: Sat, 12 Aug 2023 17:22:22 +0100 Subject: [PATCH 029/326] iio: mlx90614: Use i2c_get_match_data() Replace device_get_match_data()->i2c_get_match_data() to extend matching support for ID table. Signed-off-by: Biju Das Acked-by: "Crt Mori " Link: https://lore.kernel.org/r/20230812162222.200004-1-biju.das.jz@bp.renesas.com Signed-off-by: Jonathan Cameron --- drivers/iio/temperature/mlx90614.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/iio/temperature/mlx90614.c b/drivers/iio/temperature/mlx90614.c index 07bb5df24ab3..740018d4b3df 100644 --- a/drivers/iio/temperature/mlx90614.c +++ b/drivers/iio/temperature/mlx90614.c @@ -600,7 +600,7 @@ static int mlx90614_probe(struct i2c_client *client) data->client = client; mutex_init(&data->lock); data->wakeup_gpio = mlx90614_probe_wakeup(client); - data->chip_info = device_get_match_data(&client->dev); + data->chip_info = i2c_get_match_data(client); mlx90614_wakeup(data); From 4f9ea93afde190a0f906ee624fc9a45cf784551b Mon Sep 17 00:00:00 2001 From: Biju Das Date: Fri, 18 Aug 2023 08:55:56 +0100 Subject: [PATCH 030/326] iio: magnetometer: ak8975: Convert enum->pointer for data in the match tables Convert enum->pointer for data in the match tables to simplify the probe() by replacing device_get_match_data() and i2c_client_get_device_id by i2c_get_match_data() as we have similar I2C, ACPI and DT matching table. Signed-off-by: Biju Das Reviewed-by: Andy Shevchenko Link: https://lore.kernel.org/r/20230818075600.24277-2-biju.das.jz@bp.renesas.com Signed-off-by: Jonathan Cameron --- drivers/iio/magnetometer/ak8975.c | 75 +++++++++++++------------------ 1 file changed, 30 insertions(+), 45 deletions(-) diff --git a/drivers/iio/magnetometer/ak8975.c b/drivers/iio/magnetometer/ak8975.c index eb706d0bf70b..104798549de1 100644 --- a/drivers/iio/magnetometer/ak8975.c +++ b/drivers/iio/magnetometer/ak8975.c @@ -813,13 +813,13 @@ static const struct iio_info ak8975_info = { }; static const struct acpi_device_id ak_acpi_match[] = { - {"AK8975", AK8975}, - {"AK8963", AK8963}, - {"INVN6500", AK8963}, - {"AK009911", AK09911}, - {"AK09911", AK09911}, - {"AKM9911", AK09911}, - {"AK09912", AK09912}, + {"AK8975", (kernel_ulong_t)&ak_def_array[AK8975] }, + {"AK8963", (kernel_ulong_t)&ak_def_array[AK8963] }, + {"INVN6500", (kernel_ulong_t)&ak_def_array[AK8963] }, + {"AK009911", (kernel_ulong_t)&ak_def_array[AK09911] }, + {"AK09911", (kernel_ulong_t)&ak_def_array[AK09911] }, + {"AKM9911", (kernel_ulong_t)&ak_def_array[AK09911] }, + {"AK09912", (kernel_ulong_t)&ak_def_array[AK09912] }, { } }; MODULE_DEVICE_TABLE(acpi, ak_acpi_match); @@ -883,10 +883,7 @@ static int ak8975_probe(struct i2c_client *client) struct iio_dev *indio_dev; struct gpio_desc *eoc_gpiod; struct gpio_desc *reset_gpiod; - const void *match; - unsigned int i; int err; - enum asahi_compass_chipset chipset; const char *name = NULL; /* @@ -928,27 +925,15 @@ static int ak8975_probe(struct i2c_client *client) return err; /* id will be NULL when enumerated via ACPI */ - match = device_get_match_data(&client->dev); - if (match) { - chipset = (uintptr_t)match; - name = dev_name(&client->dev); - } else if (id) { - chipset = (enum asahi_compass_chipset)(id->driver_data); - name = id->name; - } else - return -ENOSYS; - - for (i = 0; i < ARRAY_SIZE(ak_def_array); i++) - if (ak_def_array[i].type == chipset) - break; - - if (i == ARRAY_SIZE(ak_def_array)) { - dev_err(&client->dev, "AKM device type unsupported: %d\n", - chipset); + data->def = i2c_get_match_data(client); + if (!data->def) return -ENODEV; - } - data->def = &ak_def_array[i]; + /* If enumerated via firmware node, fix the ABI */ + if (dev_fwnode(&client->dev)) + name = dev_name(&client->dev); + else + name = id->name; /* Fetch the regulators */ data->vdd = devm_regulator_get(&client->dev, "vdd"); @@ -1077,28 +1062,28 @@ static DEFINE_RUNTIME_DEV_PM_OPS(ak8975_dev_pm_ops, ak8975_runtime_suspend, ak8975_runtime_resume, NULL); static const struct i2c_device_id ak8975_id[] = { - {"ak8975", AK8975}, - {"ak8963", AK8963}, - {"AK8963", AK8963}, - {"ak09911", AK09911}, - {"ak09912", AK09912}, - {"ak09916", AK09916}, + {"ak8975", (kernel_ulong_t)&ak_def_array[AK8975] }, + {"ak8963", (kernel_ulong_t)&ak_def_array[AK8963] }, + {"AK8963", (kernel_ulong_t)&ak_def_array[AK8963] }, + {"ak09911", (kernel_ulong_t)&ak_def_array[AK09911] }, + {"ak09912", (kernel_ulong_t)&ak_def_array[AK09912] }, + {"ak09916", (kernel_ulong_t)&ak_def_array[AK09916] }, {} }; MODULE_DEVICE_TABLE(i2c, ak8975_id); static const struct of_device_id ak8975_of_match[] = { - { .compatible = "asahi-kasei,ak8975", }, - { .compatible = "ak8975", }, - { .compatible = "asahi-kasei,ak8963", }, - { .compatible = "ak8963", }, - { .compatible = "asahi-kasei,ak09911", }, - { .compatible = "ak09911", }, - { .compatible = "asahi-kasei,ak09912", }, - { .compatible = "ak09912", }, - { .compatible = "asahi-kasei,ak09916", }, - { .compatible = "ak09916", }, + { .compatible = "asahi-kasei,ak8975", .data = &ak_def_array[AK8975] }, + { .compatible = "ak8975", .data = &ak_def_array[AK8975] }, + { .compatible = "asahi-kasei,ak8963", .data = &ak_def_array[AK8963] }, + { .compatible = "ak8963", .data = &ak_def_array[AK8963] }, + { .compatible = "asahi-kasei,ak09911", .data = &ak_def_array[AK09911] }, + { .compatible = "ak09911", .data = &ak_def_array[AK09911] }, + { .compatible = "asahi-kasei,ak09912", .data = &ak_def_array[AK09912] }, + { .compatible = "ak09912", .data = &ak_def_array[AK09912] }, + { .compatible = "asahi-kasei,ak09916", .data = &ak_def_array[AK09916] }, + { .compatible = "ak09916", .data = &ak_def_array[AK09916] }, {} }; MODULE_DEVICE_TABLE(of, ak8975_of_match); From 680b2f21c31d4e0af10cf0f732c2c972a8d7489d Mon Sep 17 00:00:00 2001 From: Biju Das Date: Fri, 18 Aug 2023 08:55:57 +0100 Subject: [PATCH 031/326] iio: magnetometer: ak8975: Sort ID and ACPI tables Sort ID table alphabetically by name and ACPI table by HID. While at it, drop blank line before ID table. Suggested-by: Andy Shevchenko Signed-off-by: Biju Das Reviewed-by: Andy Shevchenko Link: https://lore.kernel.org/r/20230818075600.24277-3-biju.das.jz@bp.renesas.com Signed-off-by: Jonathan Cameron --- drivers/iio/magnetometer/ak8975.c | 31 +++++++++++++++---------------- 1 file changed, 15 insertions(+), 16 deletions(-) diff --git a/drivers/iio/magnetometer/ak8975.c b/drivers/iio/magnetometer/ak8975.c index 104798549de1..8cfceb007936 100644 --- a/drivers/iio/magnetometer/ak8975.c +++ b/drivers/iio/magnetometer/ak8975.c @@ -812,18 +812,6 @@ static const struct iio_info ak8975_info = { .read_raw = &ak8975_read_raw, }; -static const struct acpi_device_id ak_acpi_match[] = { - {"AK8975", (kernel_ulong_t)&ak_def_array[AK8975] }, - {"AK8963", (kernel_ulong_t)&ak_def_array[AK8963] }, - {"INVN6500", (kernel_ulong_t)&ak_def_array[AK8963] }, - {"AK009911", (kernel_ulong_t)&ak_def_array[AK09911] }, - {"AK09911", (kernel_ulong_t)&ak_def_array[AK09911] }, - {"AKM9911", (kernel_ulong_t)&ak_def_array[AK09911] }, - {"AK09912", (kernel_ulong_t)&ak_def_array[AK09912] }, - { } -}; -MODULE_DEVICE_TABLE(acpi, ak_acpi_match); - static void ak8975_fill_buffer(struct iio_dev *indio_dev) { struct ak8975_data *data = iio_priv(indio_dev); @@ -1061,16 +1049,27 @@ static int ak8975_runtime_resume(struct device *dev) static DEFINE_RUNTIME_DEV_PM_OPS(ak8975_dev_pm_ops, ak8975_runtime_suspend, ak8975_runtime_resume, NULL); -static const struct i2c_device_id ak8975_id[] = { - {"ak8975", (kernel_ulong_t)&ak_def_array[AK8975] }, - {"ak8963", (kernel_ulong_t)&ak_def_array[AK8963] }, +static const struct acpi_device_id ak_acpi_match[] = { {"AK8963", (kernel_ulong_t)&ak_def_array[AK8963] }, + {"AK8975", (kernel_ulong_t)&ak_def_array[AK8975] }, + {"AK009911", (kernel_ulong_t)&ak_def_array[AK09911] }, + {"AK09911", (kernel_ulong_t)&ak_def_array[AK09911] }, + {"AK09912", (kernel_ulong_t)&ak_def_array[AK09912] }, + {"AKM9911", (kernel_ulong_t)&ak_def_array[AK09911] }, + {"INVN6500", (kernel_ulong_t)&ak_def_array[AK8963] }, + { } +}; +MODULE_DEVICE_TABLE(acpi, ak_acpi_match); + +static const struct i2c_device_id ak8975_id[] = { + {"AK8963", (kernel_ulong_t)&ak_def_array[AK8963] }, + {"ak8963", (kernel_ulong_t)&ak_def_array[AK8963] }, + {"ak8975", (kernel_ulong_t)&ak_def_array[AK8975] }, {"ak09911", (kernel_ulong_t)&ak_def_array[AK09911] }, {"ak09912", (kernel_ulong_t)&ak_def_array[AK09912] }, {"ak09916", (kernel_ulong_t)&ak_def_array[AK09916] }, {} }; - MODULE_DEVICE_TABLE(i2c, ak8975_id); static const struct of_device_id ak8975_of_match[] = { From 711fb79a1ea8e79dc600f25d9f8c1ac25870b4de Mon Sep 17 00:00:00 2001 From: Biju Das Date: Fri, 18 Aug 2023 08:55:58 +0100 Subject: [PATCH 032/326] dt-bindings: iio: magnetometer: asahi-kasei,ak8975: Drop deprecated enums Drop deprecated enums from bindings as it is been here for a long time. Signed-off-by: Biju Das Acked-by: Rob Herring Reviewed-by: Geert Uytterhoeven Link: https://lore.kernel.org/r/20230818075600.24277-4-biju.das.jz@bp.renesas.com Signed-off-by: Jonathan Cameron --- .../bindings/iio/magnetometer/asahi-kasei,ak8975.yaml | 7 ------- 1 file changed, 7 deletions(-) diff --git a/Documentation/devicetree/bindings/iio/magnetometer/asahi-kasei,ak8975.yaml b/Documentation/devicetree/bindings/iio/magnetometer/asahi-kasei,ak8975.yaml index 9790f75fc669..ee77558e9800 100644 --- a/Documentation/devicetree/bindings/iio/magnetometer/asahi-kasei,ak8975.yaml +++ b/Documentation/devicetree/bindings/iio/magnetometer/asahi-kasei,ak8975.yaml @@ -18,13 +18,6 @@ properties: - asahi-kasei,ak09911 - asahi-kasei,ak09912 - asahi-kasei,ak09916 - - enum: - - ak8975 - - ak8963 - - ak09911 - - ak09912 - - ak09916 - deprecated: true reg: maxItems: 1 From 77865a8f9f7085a51188b3fb95368c73a7dd12f3 Mon Sep 17 00:00:00 2001 From: Michael Hennerich Date: Wed, 16 Aug 2023 14:09:05 +0300 Subject: [PATCH 033/326] iio: amplifiers: hmc425a: Add Support HMC540S 4-bit Attenuator This adds support for the Analog Devices HMC540s 1 dB LSB Silicon MMIC 4-Bit Digital Positive Control Attenuator, 0.1 - 8 GHz Signed-off-by: Michael Hennerich Signed-off-by: Ana-Maria Cusco Link: https://lore.kernel.org/r/20230816110906.144540-1-ana-maria.cusco@analog.com Signed-off-by: Jonathan Cameron --- drivers/iio/amplifiers/hmc425a.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/drivers/iio/amplifiers/hmc425a.c b/drivers/iio/amplifiers/hmc425a.c index 108f0f1685ef..e87d35d50a95 100644 --- a/drivers/iio/amplifiers/hmc425a.c +++ b/drivers/iio/amplifiers/hmc425a.c @@ -21,6 +21,7 @@ enum hmc425a_type { ID_HMC425A, + ID_HMC540S, }; struct hmc425a_chip_info { @@ -70,6 +71,9 @@ static int hmc425a_read_raw(struct iio_dev *indio_dev, case ID_HMC425A: gain = ~code * -500; break; + case ID_HMC540S: + gain = ~code * -1000; + break; } *val = gain / 1000; @@ -106,6 +110,9 @@ static int hmc425a_write_raw(struct iio_dev *indio_dev, case ID_HMC425A: code = ~((abs(gain) / 500) & 0x3F); break; + case ID_HMC540S: + code = ~((abs(gain) / 1000) & 0xF); + break; } mutex_lock(&st->lock); @@ -157,6 +164,7 @@ static const struct iio_chan_spec hmc425a_channels[] = { /* Match table for of_platform binding */ static const struct of_device_id hmc425a_of_match[] = { { .compatible = "adi,hmc425a", .data = (void *)ID_HMC425A }, + { .compatible = "adi,hmc540s", .data = (void *)ID_HMC540S }, {}, }; MODULE_DEVICE_TABLE(of, hmc425a_of_match); @@ -171,6 +179,15 @@ static struct hmc425a_chip_info hmc425a_chip_info_tbl[] = { .gain_max = 0, .default_gain = -0x40, /* set default gain -31.5db*/ }, + [ID_HMC540S] = { + .name = "hmc540s", + .channels = hmc425a_channels, + .num_channels = ARRAY_SIZE(hmc425a_channels), + .num_gpios = 4, + .gain_min = -15000, + .gain_max = 0, + .default_gain = -0x10, /* set default gain -15.0db*/ + }, }; static int hmc425a_probe(struct platform_device *pdev) From 20f87a9a26bea28df91506f3c2747e636d5d589c Mon Sep 17 00:00:00 2001 From: Ana-Maria Cusco Date: Wed, 16 Aug 2023 14:09:06 +0300 Subject: [PATCH 034/326] dt-bindings: iio: hmc425a: add entry for HMC540S Added support for HMC540SLP3E broadband 4-bit Silicon IC digital attenuator with a 15 dB control range and wide frequency coverage (0.1 to 8 GHz). Signed-off-by: Ana-Maria Cusco Acked-by: Conor Dooley Link: https://lore.kernel.org/r/20230816110906.144540-2-ana-maria.cusco@analog.com Signed-off-by: Jonathan Cameron --- .../bindings/iio/amplifiers/adi,hmc425a.yaml | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/Documentation/devicetree/bindings/iio/amplifiers/adi,hmc425a.yaml b/Documentation/devicetree/bindings/iio/amplifiers/adi,hmc425a.yaml index 9fda56fa49c3..2ee6080deac7 100644 --- a/Documentation/devicetree/bindings/iio/amplifiers/adi,hmc425a.yaml +++ b/Documentation/devicetree/bindings/iio/amplifiers/adi,hmc425a.yaml @@ -4,20 +4,26 @@ $id: http://devicetree.org/schemas/iio/amplifiers/adi,hmc425a.yaml# $schema: http://devicetree.org/meta-schemas/core.yaml# -title: HMC425A 6-bit Digital Step Attenuator +title: Analog Devices HMC425A and similar Digital Step Attenuators maintainers: - Michael Hennerich description: | - Digital Step Attenuator IIO device with gpio interface. + Digital Step Attenuator IIO devices with gpio interface. + Offer various frequency and attenuation ranges. HMC425A 0.5 dB LSB GaAs MMIC 6-BIT DIGITAL POSITIVE CONTROL ATTENUATOR, 2.2 - 8.0 GHz - https://www.analog.com/media/en/technical-documentation/data-sheets/hmc425A.pdf + https://www.analog.com/media/en/technical-documentation/data-sheets/hmc425A.pdf + + HMC540S 1 dB LSB Silicon MMIC 4-Bit Digital Positive Control Attenuator, 0.1 - 8 GHz + https://www.analog.com/media/en/technical-documentation/data-sheets/hmc540s.pdf + properties: compatible: enum: - adi,hmc425a + - adi,hmc540s vcc-supply: true From 8c89edc1ac9e3be816cd37e0df2afe040283a9d3 Mon Sep 17 00:00:00 2001 From: Biju Das Date: Sat, 12 Aug 2023 17:57:30 +0100 Subject: [PATCH 035/326] iio: chemical: sgp30: Convert enum->pointer for data in the match tables Convert enum->pointer for data in the match tables, so that device_get_match_data() can do match against OF/ACPI/I2C tables, once i2c bus type match support added to it. Add product_id variable to struct sgp_device and remove the local variable product_id in probe() and replace enum->struct *sgp_device for data in the match table. Simplify theprobe() by replacing device_get_match_data() and ID lookup for retrieving data by i2c_get_match_data(). Signed-off-by: Biju Das Reviewed-by: Andy Shevchenko Link: https://lore.kernel.org/r/20230812165730.216180-1-biju.das.jz@bp.renesas.com Signed-off-by: Jonathan Cameron --- drivers/iio/chemical/sgp30.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/drivers/iio/chemical/sgp30.c b/drivers/iio/chemical/sgp30.c index b509cff9ce37..21730d62b5c8 100644 --- a/drivers/iio/chemical/sgp30.c +++ b/drivers/iio/chemical/sgp30.c @@ -114,6 +114,7 @@ struct sgp_data { }; struct sgp_device { + unsigned long product_id; const struct iio_chan_spec *channels; int num_channels; }; @@ -182,10 +183,12 @@ static const struct iio_chan_spec sgpc3_channels[] = { static const struct sgp_device sgp_devices[] = { [SGP30] = { + .product_id = SGP30, .channels = sgp30_channels, .num_channels = ARRAY_SIZE(sgp30_channels), }, [SGPC3] = { + .product_id = SGPC3, .channels = sgpc3_channels, .num_channels = ARRAY_SIZE(sgpc3_channels), }, @@ -491,28 +494,25 @@ static const struct iio_info sgp_info = { }; static const struct of_device_id sgp_dt_ids[] = { - { .compatible = "sensirion,sgp30", .data = (void *)SGP30 }, - { .compatible = "sensirion,sgpc3", .data = (void *)SGPC3 }, + { .compatible = "sensirion,sgp30", .data = &sgp_devices[SGP30] }, + { .compatible = "sensirion,sgpc3", .data = &sgp_devices[SGPC3] }, { } }; static int sgp_probe(struct i2c_client *client) { const struct i2c_device_id *id = i2c_client_get_device_id(client); + const struct sgp_device *match_data; struct device *dev = &client->dev; struct iio_dev *indio_dev; struct sgp_data *data; - unsigned long product_id; int ret; indio_dev = devm_iio_device_alloc(dev, sizeof(*data)); if (!indio_dev) return -ENOMEM; - if (dev_fwnode(dev)) - product_id = (unsigned long)device_get_match_data(dev); - else - product_id = id->driver_data; + match_data = i2c_get_match_data(client); data = iio_priv(indio_dev); i2c_set_clientdata(client, indio_dev); @@ -528,15 +528,15 @@ static int sgp_probe(struct i2c_client *client) data->feature_set = be16_to_cpu(data->buffer.raw_words[0].value); - ret = sgp_check_compat(data, product_id); + ret = sgp_check_compat(data, match_data->product_id); if (ret) return ret; indio_dev->info = &sgp_info; indio_dev->name = id->name; indio_dev->modes = INDIO_DIRECT_MODE; - indio_dev->channels = sgp_devices[product_id].channels; - indio_dev->num_channels = sgp_devices[product_id].num_channels; + indio_dev->channels = match_data->channels; + indio_dev->num_channels = match_data->num_channels; sgp_init(data); @@ -562,8 +562,8 @@ static void sgp_remove(struct i2c_client *client) } static const struct i2c_device_id sgp_id[] = { - { "sgp30", SGP30 }, - { "sgpc3", SGPC3 }, + { "sgp30", (kernel_ulong_t)&sgp_devices[SGP30] }, + { "sgpc3", (kernel_ulong_t)&sgp_devices[SGPC3] }, { } }; From 0f5cecd14f42a2cbd10f7670c025dfb98a817f7b Mon Sep 17 00:00:00 2001 From: Biju Das Date: Sat, 12 Aug 2023 15:41:06 +0100 Subject: [PATCH 036/326] iio: potentiometer: ds1803: Convert enum->pointer for data in the ID table Convert enum->pointer for data in the ID table, so that device_get_match_data() can do match against OF/ACPI/I2C tables, once i2c bus type match support added to it. Replace enum->struct *ds1803_cfg for data in the ID table and simplify ds1803_probe() by replacing device_get_match_data() with i2c_get_match_data(). Signed-off-by: Biju Das Reviewed-by: Andy Shevchenko Link: https://lore.kernel.org/r/20230812144106.163355-1-biju.das.jz@bp.renesas.com Signed-off-by: Jonathan Cameron --- drivers/iio/potentiometer/ds1803.c | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/drivers/iio/potentiometer/ds1803.c b/drivers/iio/potentiometer/ds1803.c index fc183e0790da..e0526dd0e3cb 100644 --- a/drivers/iio/potentiometer/ds1803.c +++ b/drivers/iio/potentiometer/ds1803.c @@ -204,7 +204,6 @@ static const struct iio_info ds1803_info = { static int ds1803_probe(struct i2c_client *client) { - const struct i2c_device_id *id = i2c_client_get_device_id(client); struct device *dev = &client->dev; struct ds1803_data *data; struct iio_dev *indio_dev; @@ -217,9 +216,7 @@ static int ds1803_probe(struct i2c_client *client) data = iio_priv(indio_dev); data->client = client; - data->cfg = device_get_match_data(dev); - if (!data->cfg) - data->cfg = &ds1803_cfg[id->driver_data]; + data->cfg = i2c_get_match_data(client); indio_dev->info = &ds1803_info; indio_dev->channels = data->cfg->channels; @@ -239,10 +236,10 @@ static const struct of_device_id ds1803_dt_ids[] = { MODULE_DEVICE_TABLE(of, ds1803_dt_ids); static const struct i2c_device_id ds1803_id[] = { - { "ds1803-010", DS1803_010 }, - { "ds1803-050", DS1803_050 }, - { "ds1803-100", DS1803_100 }, - { "ds3502", DS3502 }, + { "ds1803-010", (kernel_ulong_t)&ds1803_cfg[DS1803_010] }, + { "ds1803-050", (kernel_ulong_t)&ds1803_cfg[DS1803_050] }, + { "ds1803-100", (kernel_ulong_t)&ds1803_cfg[DS1803_100] }, + { "ds3502", (kernel_ulong_t)&ds1803_cfg[DS3502] }, {} }; MODULE_DEVICE_TABLE(i2c, ds1803_id); From c4153b5720e62be957f3497049cb2706f0b8a5b1 Mon Sep 17 00:00:00 2001 From: Biju Das Date: Sat, 12 Aug 2023 16:08:38 +0100 Subject: [PATCH 037/326] iio: potentiometer: ad5110: Use i2c_get_match_data() Replace device_get_match_data()->i2c_get_match_data by making similar I2C and DT-based matching table to extend matching support for ID table. Signed-off-by: Biju Das Link: https://lore.kernel.org/r/20230812150838.185055-1-biju.das.jz@bp.renesas.com Signed-off-by: Jonathan Cameron --- drivers/iio/potentiometer/ad5110.c | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/drivers/iio/potentiometer/ad5110.c b/drivers/iio/potentiometer/ad5110.c index 991e745c4f93..aaf02cc7aeba 100644 --- a/drivers/iio/potentiometer/ad5110.c +++ b/drivers/iio/potentiometer/ad5110.c @@ -278,14 +278,19 @@ static const struct of_device_id ad5110_of_match[] = { }; MODULE_DEVICE_TABLE(of, ad5110_of_match); +#define AD5110_ID_TABLE(_name, cfg) { \ + .name = _name, \ + .driver_data = (kernel_ulong_t)&ad5110_cfg[cfg], \ +} + static const struct i2c_device_id ad5110_id[] = { - { "ad5110-10", AD5110_10 }, - { "ad5110-80", AD5110_80 }, - { "ad5112-05", AD5112_05 }, - { "ad5112-10", AD5112_10 }, - { "ad5112-80", AD5112_80 }, - { "ad5114-10", AD5114_10 }, - { "ad5114-80", AD5114_80 }, + AD5110_ID_TABLE("ad5110-10", AD5110_10), + AD5110_ID_TABLE("ad5110-80", AD5110_80), + AD5110_ID_TABLE("ad5112-05", AD5112_05), + AD5110_ID_TABLE("ad5112-10", AD5112_10), + AD5110_ID_TABLE("ad5112-80", AD5112_80), + AD5110_ID_TABLE("ad5114-10", AD5114_10), + AD5110_ID_TABLE("ad5114-80", AD5114_80), { } }; MODULE_DEVICE_TABLE(i2c, ad5110_id); @@ -305,7 +310,7 @@ static int ad5110_probe(struct i2c_client *client) data->client = client; mutex_init(&data->lock); data->enable = 1; - data->cfg = device_get_match_data(dev); + data->cfg = i2c_get_match_data(client); /* refresh RDAC register with EEPROM */ ret = ad5110_write(data, AD5110_RESET, 0); From 5a4ef20aab63dacdce77c97eaf1847355cc9e66e Mon Sep 17 00:00:00 2001 From: Biju Das Date: Sat, 12 Aug 2023 16:19:08 +0100 Subject: [PATCH 038/326] iio: light: opt4001: Use i2c_get_match_data() Replace device_get_match_data()->i2c_get_match_data() to extend matching support for ID table. Signed-off-by: Biju Das Reviewed-by: Stefan Windfeldt-Prytz Tested-by: Stefan Windfeldt-Prytz Link: https://lore.kernel.org/r/20230812151908.188696-1-biju.das.jz@bp.renesas.com Signed-off-by: Jonathan Cameron --- drivers/iio/light/opt4001.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/iio/light/opt4001.c b/drivers/iio/light/opt4001.c index 502946bf9f94..6cf60151b3d8 100644 --- a/drivers/iio/light/opt4001.c +++ b/drivers/iio/light/opt4001.c @@ -412,7 +412,7 @@ static int opt4001_probe(struct i2c_client *client) if (dev_id != OPT4001_DEVICE_ID_VAL) dev_warn(&client->dev, "Device ID: %#04x unknown\n", dev_id); - chip->chip_info = device_get_match_data(&client->dev); + chip->chip_info = i2c_get_match_data(client); indio_dev->channels = opt4001_channels; indio_dev->num_channels = ARRAY_SIZE(opt4001_channels); From fc1d297b928b98f2290c1d80f6bb7ff12d278a3a Mon Sep 17 00:00:00 2001 From: Biju Das Date: Sat, 12 Aug 2023 17:11:54 +0100 Subject: [PATCH 039/326] iio: temperature: tmp117: Convert enum->pointer for data in the match tables Convert enum->pointer for data in the match tables, so that device_get_match_data() can do match against OF/ACPI/I2C tables, once i2c bus type match support added to it. Add struct tmp11x_info and replace enum->struct *tmp11x_info for data in the match table. Drop tmp117_identify() and simplify tmp117_probe() by replacing device_get_match_data() and id lookup for retrieving data by i2c_get_match_data(). Signed-off-by: Biju Das Reviewed-by: Marco Felsch Link: https://lore.kernel.org/r/20230812161154.196555-1-biju.das.jz@bp.renesas.com Signed-off-by: Jonathan Cameron --- drivers/iio/temperature/tmp117.c | 94 +++++++++++++++----------------- 1 file changed, 44 insertions(+), 50 deletions(-) diff --git a/drivers/iio/temperature/tmp117.c b/drivers/iio/temperature/tmp117.c index fc02f491688b..059953015ae7 100644 --- a/drivers/iio/temperature/tmp117.c +++ b/drivers/iio/temperature/tmp117.c @@ -42,6 +42,12 @@ struct tmp117_data { s16 calibbias; }; +struct tmp11x_info { + const char *name; + struct iio_chan_spec const *channels; + int num_channels; +}; + static int tmp117_read_raw(struct iio_dev *indio_dev, struct iio_chan_spec const *channel, int *val, int *val2, long mask) @@ -119,57 +125,54 @@ static const struct iio_chan_spec tmp116_channels[] = { }, }; +static const struct tmp11x_info tmp116_channels_info = { + .name = "tmp116", + .channels = tmp116_channels, + .num_channels = ARRAY_SIZE(tmp116_channels) +}; + +static const struct tmp11x_info tmp117_channels_info = { + .name = "tmp117", + .channels = tmp117_channels, + .num_channels = ARRAY_SIZE(tmp117_channels) +}; + static const struct iio_info tmp117_info = { .read_raw = tmp117_read_raw, .write_raw = tmp117_write_raw, }; -static int tmp117_identify(struct i2c_client *client) +static int tmp117_probe(struct i2c_client *client) { - const struct i2c_device_id *id; - unsigned long match_data; + const struct tmp11x_info *match_data; + struct tmp117_data *data; + struct iio_dev *indio_dev; int dev_id; + if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_WORD_DATA)) + return -EOPNOTSUPP; + dev_id = i2c_smbus_read_word_swapped(client, TMP117_REG_DEVICE_ID); if (dev_id < 0) return dev_id; switch (dev_id) { case TMP116_DEVICE_ID: + match_data = &tmp116_channels_info; + break; case TMP117_DEVICE_ID: - return dev_id; + match_data = &tmp117_channels_info; + break; + default: + dev_info(&client->dev, + "Unknown device id (0x%x), use fallback compatible\n", + dev_id); + match_data = i2c_get_match_data(client); } - dev_info(&client->dev, "Unknown device id (0x%x), use fallback compatible\n", - dev_id); - - match_data = (uintptr_t)device_get_match_data(&client->dev); - if (match_data) - return match_data; - - id = i2c_client_get_device_id(client); - if (id) - return id->driver_data; - - dev_err(&client->dev, "Failed to identify unsupported device\n"); - - return -ENODEV; -} - -static int tmp117_probe(struct i2c_client *client) -{ - struct tmp117_data *data; - struct iio_dev *indio_dev; - int ret, dev_id; - - if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_WORD_DATA)) - return -EOPNOTSUPP; - - ret = tmp117_identify(client); - if (ret < 0) - return ret; - - dev_id = ret; + if (!match_data) + return dev_err_probe(&client->dev, -ENODEV, + "Failed to identify unsupported device\n"); indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data)); if (!indio_dev) @@ -181,33 +184,24 @@ static int tmp117_probe(struct i2c_client *client) indio_dev->modes = INDIO_DIRECT_MODE; indio_dev->info = &tmp117_info; + indio_dev->channels = match_data->channels; + indio_dev->num_channels = match_data->num_channels; + indio_dev->name = match_data->name; - switch (dev_id) { - case TMP116_DEVICE_ID: - indio_dev->channels = tmp116_channels; - indio_dev->num_channels = ARRAY_SIZE(tmp116_channels); - indio_dev->name = "tmp116"; - break; - case TMP117_DEVICE_ID: - indio_dev->channels = tmp117_channels; - indio_dev->num_channels = ARRAY_SIZE(tmp117_channels); - indio_dev->name = "tmp117"; - break; - } return devm_iio_device_register(&client->dev, indio_dev); } static const struct of_device_id tmp117_of_match[] = { - { .compatible = "ti,tmp116", .data = (void *)TMP116_DEVICE_ID }, - { .compatible = "ti,tmp117", .data = (void *)TMP117_DEVICE_ID }, + { .compatible = "ti,tmp116", .data = &tmp116_channels_info }, + { .compatible = "ti,tmp117", .data = &tmp117_channels_info }, { } }; MODULE_DEVICE_TABLE(of, tmp117_of_match); static const struct i2c_device_id tmp117_id[] = { - { "tmp116", TMP116_DEVICE_ID }, - { "tmp117", TMP117_DEVICE_ID }, + { "tmp116", (kernel_ulong_t)&tmp116_channels_info }, + { "tmp117", (kernel_ulong_t)&tmp117_channels_info }, { } }; MODULE_DEVICE_TABLE(i2c, tmp117_id); From 4eaf928622abc5dabc9b42a0de4dafbe29ddf491 Mon Sep 17 00:00:00 2001 From: Yue Haibing Date: Fri, 11 Aug 2023 17:57:01 +0800 Subject: [PATCH 040/326] iio: Remove unused declarations Commit 0f3a8c3f34f7 ("iio: Add support for creating IIO devices via configfs") declared but never implemented iio_sw_device_type_configfs_{un}register(). Commit b662f809d410 ("iio: core: Introduce IIO software triggers") declared but never implemented iio_sw_trigger_type_configfs_{un}register(). Commit a3e0b51884ee ("iio: accel: add support for FXLS8962AF/FXLS8964AF accelerometers") declared but never implemented fxls8962af_core_remove(). Commit 8dedcc3eee3a ("iio: core: centralize ioctl() calls to the main chardev") declared but never implemented iio_device_ioctl(). Commit d430f3c36ca6 ("iio: imu: inv_mpu6050: Use regmap instead of i2c specific functions") removed inv_mpu6050_write_reg() but not its declaration. Signed-off-by: Yue Haibing Link: https://lore.kernel.org/r/20230811095701.35372-1-yuehaibing@huawei.com Signed-off-by: Jonathan Cameron --- drivers/iio/accel/fxls8962af.h | 1 - drivers/iio/iio_core.h | 3 --- drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h | 1 - include/linux/iio/sw_device.h | 3 --- include/linux/iio/sw_trigger.h | 3 --- 5 files changed, 11 deletions(-) diff --git a/drivers/iio/accel/fxls8962af.h b/drivers/iio/accel/fxls8962af.h index 9cbe98c3ba9a..6eaa2803b26f 100644 --- a/drivers/iio/accel/fxls8962af.h +++ b/drivers/iio/accel/fxls8962af.h @@ -14,7 +14,6 @@ enum { }; int fxls8962af_core_probe(struct device *dev, struct regmap *regmap, int irq); -int fxls8962af_core_remove(struct device *dev); extern const struct dev_pm_ops fxls8962af_pm_ops; extern const struct regmap_config fxls8962af_i2c_regmap_conf; diff --git a/drivers/iio/iio_core.h b/drivers/iio/iio_core.h index 501e286702ef..1a38b1915e7a 100644 --- a/drivers/iio/iio_core.h +++ b/drivers/iio/iio_core.h @@ -30,9 +30,6 @@ struct iio_ioctl_handler { unsigned int cmd, unsigned long arg); }; -long iio_device_ioctl(struct iio_dev *indio_dev, struct file *filp, - unsigned int cmd, unsigned long arg); - void iio_device_ioctl_handler_register(struct iio_dev *indio_dev, struct iio_ioctl_handler *h); void iio_device_ioctl_handler_unregister(struct iio_ioctl_handler *h); diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h b/drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h index ed5a96e78df0..95f548235de7 100644 --- a/drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h +++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h @@ -464,7 +464,6 @@ int inv_mpu6050_probe_trigger(struct iio_dev *indio_dev, int irq_type); int inv_mpu6050_prepare_fifo(struct inv_mpu6050_state *st, bool enable); int inv_mpu6050_switch_engine(struct inv_mpu6050_state *st, bool en, unsigned int mask); -int inv_mpu6050_write_reg(struct inv_mpu6050_state *st, int reg, u8 val); int inv_mpu_acpi_create_mux_client(struct i2c_client *client); void inv_mpu_acpi_delete_mux_client(struct i2c_client *client); int inv_mpu_core_probe(struct regmap *regmap, int irq, const char *name, diff --git a/include/linux/iio/sw_device.h b/include/linux/iio/sw_device.h index eff1e6b2595c..0f7fe7b522e3 100644 --- a/include/linux/iio/sw_device.h +++ b/include/linux/iio/sw_device.h @@ -51,9 +51,6 @@ void iio_unregister_sw_device_type(struct iio_sw_device_type *dt); struct iio_sw_device *iio_sw_device_create(const char *, const char *); void iio_sw_device_destroy(struct iio_sw_device *); -int iio_sw_device_type_configfs_register(struct iio_sw_device_type *dt); -void iio_sw_device_type_configfs_unregister(struct iio_sw_device_type *dt); - static inline void iio_swd_group_init_type_name(struct iio_sw_device *d, const char *name, diff --git a/include/linux/iio/sw_trigger.h b/include/linux/iio/sw_trigger.h index 47de2443e984..bc77f88df303 100644 --- a/include/linux/iio/sw_trigger.h +++ b/include/linux/iio/sw_trigger.h @@ -51,9 +51,6 @@ void iio_unregister_sw_trigger_type(struct iio_sw_trigger_type *tt); struct iio_sw_trigger *iio_sw_trigger_create(const char *, const char *); void iio_sw_trigger_destroy(struct iio_sw_trigger *); -int iio_sw_trigger_type_configfs_register(struct iio_sw_trigger_type *tt); -void iio_sw_trigger_type_configfs_unregister(struct iio_sw_trigger_type *tt); - static inline void iio_swt_group_init_type_name(struct iio_sw_trigger *t, const char *name, From b1209cf096358cfb9c538def71ff039fcb8631bd Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 8 Aug 2023 19:42:04 +0300 Subject: [PATCH 041/326] iio: accel: kionix-kx022a: Use correct header(s) instead of string_helpers.h There is nothing from string_helpers.h used in the driver, correct the header inclusion block accordingly. Signed-off-by: Andy Shevchenko Acked-by: Matti Vaittinen Link: https://lore.kernel.org/r/20230808164204.66818-1-andriy.shevchenko@linux.intel.com Signed-off-by: Jonathan Cameron --- drivers/iio/accel/kionix-kx022a.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/iio/accel/kionix-kx022a.c b/drivers/iio/accel/kionix-kx022a.c index 4ea3c6718ed4..f164b09520c9 100644 --- a/drivers/iio/accel/kionix-kx022a.c +++ b/drivers/iio/accel/kionix-kx022a.c @@ -15,7 +15,7 @@ #include #include #include -#include +#include #include #include From de39695dd1fb753a6040053483213ebe7a960af2 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 8 Aug 2023 19:41:52 +0300 Subject: [PATCH 042/326] iio: accel: msa311: Use correct header(s) instead of string_helpers.h There is nothing from string_helpers.h used in the driver, correct the header inclusion block accordingly. Signed-off-by: Andy Shevchenko Reviewed-by: Dmitry Rokosov Link: https://lore.kernel.org/r/20230808164152.66748-1-andriy.shevchenko@linux.intel.com Signed-off-by: Jonathan Cameron --- drivers/iio/accel/msa311.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/iio/accel/msa311.c b/drivers/iio/accel/msa311.c index 6ddcc3c2f840..b8ddbfd98f11 100644 --- a/drivers/iio/accel/msa311.c +++ b/drivers/iio/accel/msa311.c @@ -33,7 +33,7 @@ #include #include #include -#include +#include #include #include From 8c337436e6da6ac1dcc2d2f990489c9ebfe429f1 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 8 Aug 2023 19:41:37 +0300 Subject: [PATCH 043/326] iio: dac: stm32-dac: Use correct header(s) instead of string_helpers.h There is nothing from string_helpers.h used in the driver, correct the header inclusion block accordingly. Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20230808164137.66663-1-andriy.shevchenko@linux.intel.com Signed-off-by: Jonathan Cameron --- drivers/iio/dac/stm32-dac.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/iio/dac/stm32-dac.c b/drivers/iio/dac/stm32-dac.c index 15eb44075107..3cab28c7ee3b 100644 --- a/drivers/iio/dac/stm32-dac.c +++ b/drivers/iio/dac/stm32-dac.c @@ -11,12 +11,13 @@ #include #include #include +#include #include #include #include #include #include -#include +#include #include "stm32-dac-core.h" From 744f4990ee0519ebef21fa7db094240bbaf3d746 Mon Sep 17 00:00:00 2001 From: Ramona Bolboaca Date: Tue, 8 Aug 2023 10:50:57 +0300 Subject: [PATCH 044/326] iio: Add IIO_DELTA_ANGL channel type The delta angle is defined as a piece-wise integration of angular velocity data. The delta angle represents the amount of angular displacement between two consecutive measurements and it is measured in radians. In order to track the total angular displacement during a desired period of time, simply sum-up the delta angle samples acquired during that time. IIO currently does not offer a suitable channel type for this type of measurements hence this patch adds it. Signed-off-by: Ramona Bolboaca Reviewed-by: Nuno Sa Link: https://lore.kernel.org/r/20230808075059.645525-2-ramona.bolboaca@analog.com Signed-off-by: Jonathan Cameron --- Documentation/ABI/testing/sysfs-bus-iio | 22 ++++++++++++++++++++++ drivers/iio/industrialio-core.c | 1 + include/uapi/linux/iio/types.h | 1 + tools/iio/iio_event_monitor.c | 2 ++ 4 files changed, 26 insertions(+) diff --git a/Documentation/ABI/testing/sysfs-bus-iio b/Documentation/ABI/testing/sysfs-bus-iio index a2854dc9a839..363dd4b09930 100644 --- a/Documentation/ABI/testing/sysfs-bus-iio +++ b/Documentation/ABI/testing/sysfs-bus-iio @@ -279,6 +279,20 @@ Description: but should match other such assignments on device). Units after application of scale and offset are m/s^2. +What: /sys/bus/iio/devices/iio:deviceX/in_deltaangl_x_raw +What: /sys/bus/iio/devices/iio:deviceX/in_deltaangl_y_raw +What: /sys/bus/iio/devices/iio:deviceX/in_deltaangl_z_raw +KernelVersion: 6.5 +Contact: linux-iio@vger.kernel.org +Description: + Angular displacement between two consecutive samples on x, y or + z (may be arbitrarily assigned but should match other such + assignments on device). + In order to compute the total angular displacement during a + desired period of time, the application should sum-up the delta + angle samples acquired during that time. + Units after application of scale and offset are radians. + What: /sys/bus/iio/devices/iio:deviceX/in_angl_raw What: /sys/bus/iio/devices/iio:deviceX/in_anglY_raw KernelVersion: 4.17 @@ -461,6 +475,7 @@ What: /sys/bus/iio/devices/iio:deviceX/in_humidityrelative_scale What: /sys/bus/iio/devices/iio:deviceX/in_velocity_sqrt(x^2+y^2+z^2)_scale What: /sys/bus/iio/devices/iio:deviceX/in_illuminance_scale What: /sys/bus/iio/devices/iio:deviceX/in_countY_scale +What: /sys/bus/iio/devices/iio:deviceX/in_deltaangl_scale What: /sys/bus/iio/devices/iio:deviceX/in_angl_scale What: /sys/bus/iio/devices/iio:deviceX/in_intensity_x_scale What: /sys/bus/iio/devices/iio:deviceX/in_intensity_y_scale @@ -1332,6 +1347,9 @@ Description: What: /sys/.../iio:deviceX/bufferY/in_accel_x_en What: /sys/.../iio:deviceX/bufferY/in_accel_y_en What: /sys/.../iio:deviceX/bufferY/in_accel_z_en +What: /sys/.../iio:deviceX/bufferY/in_deltaangl_x_en +What: /sys/.../iio:deviceX/bufferY/in_deltaangl_y_en +What: /sys/.../iio:deviceX/bufferY/in_deltaangl_z_en What: /sys/.../iio:deviceX/bufferY/in_anglvel_x_en What: /sys/.../iio:deviceX/bufferY/in_anglvel_y_en What: /sys/.../iio:deviceX/bufferY/in_anglvel_z_en @@ -1362,6 +1380,7 @@ Description: Scan element control for triggered data capture. What: /sys/.../iio:deviceX/bufferY/in_accel_type +What: /sys/.../iio:deviceX/bufferY/in_deltaangl_type What: /sys/.../iio:deviceX/bufferY/in_anglvel_type What: /sys/.../iio:deviceX/bufferY/in_magn_type What: /sys/.../iio:deviceX/bufferY/in_incli_type @@ -1416,6 +1435,9 @@ What: /sys/.../iio:deviceX/bufferY/in_voltage_q_index What: /sys/.../iio:deviceX/bufferY/in_accel_x_index What: /sys/.../iio:deviceX/bufferY/in_accel_y_index What: /sys/.../iio:deviceX/bufferY/in_accel_z_index +What: /sys/.../iio:deviceX/bufferY/in_deltaangl_x_index +What: /sys/.../iio:deviceX/bufferY/in_deltaangl_y_index +What: /sys/.../iio:deviceX/bufferY/in_deltaangl_z_index What: /sys/.../iio:deviceX/bufferY/in_anglvel_x_index What: /sys/.../iio:deviceX/bufferY/in_anglvel_y_index What: /sys/.../iio:deviceX/bufferY/in_anglvel_z_index diff --git a/drivers/iio/industrialio-core.c b/drivers/iio/industrialio-core.c index d752e9c0499b..11a65030186d 100644 --- a/drivers/iio/industrialio-core.c +++ b/drivers/iio/industrialio-core.c @@ -90,6 +90,7 @@ static const char * const iio_chan_type_name_spec[] = { [IIO_POSITIONRELATIVE] = "positionrelative", [IIO_PHASE] = "phase", [IIO_MASSCONCENTRATION] = "massconcentration", + [IIO_DELTA_ANGL] = "deltaangl", }; static const char * const iio_modifier_names[] = { diff --git a/include/uapi/linux/iio/types.h b/include/uapi/linux/iio/types.h index c79f2f046a0b..55666a17d311 100644 --- a/include/uapi/linux/iio/types.h +++ b/include/uapi/linux/iio/types.h @@ -47,6 +47,7 @@ enum iio_chan_type { IIO_POSITIONRELATIVE, IIO_PHASE, IIO_MASSCONCENTRATION, + IIO_DELTA_ANGL, }; enum iio_modifier { diff --git a/tools/iio/iio_event_monitor.c b/tools/iio/iio_event_monitor.c index 0a5c2bb60030..3505450060e6 100644 --- a/tools/iio/iio_event_monitor.c +++ b/tools/iio/iio_event_monitor.c @@ -59,6 +59,7 @@ static const char * const iio_chan_type_name_spec[] = { [IIO_POSITIONRELATIVE] = "positionrelative", [IIO_PHASE] = "phase", [IIO_MASSCONCENTRATION] = "massconcentration", + [IIO_DELTA_ANGL] = "deltaangl", }; static const char * const iio_ev_type_text[] = { @@ -173,6 +174,7 @@ static bool event_is_known(struct iio_event_data *event) case IIO_POSITIONRELATIVE: case IIO_PHASE: case IIO_MASSCONCENTRATION: + case IIO_DELTA_ANGL: break; default: return false; From 94a39f2c443b3fc5efe31a68502991020eefa3d2 Mon Sep 17 00:00:00 2001 From: Ramona Bolboaca Date: Tue, 8 Aug 2023 10:50:58 +0300 Subject: [PATCH 045/326] iio: Add IIO_DELTA_VELOCITY channel type The delta velocity is defined as a piece-wise integration of acceleration data. The delta velocity represents the linear velocity change between two consecutive measurements and it is measured in m / s (meters per second). In order to track the total linear velocity change during a desired period of time, simply sum-up the delta velocity samples acquired during that time. IIO currently does not offer a suitable channel type for this type of measurements hence this patch adds it. Signed-off-by: Ramona Bolboaca Reviewed-by: Nuno Sa Link: https://lore.kernel.org/r/20230808075059.645525-3-ramona.bolboaca@analog.com Signed-off-by: Jonathan Cameron --- Documentation/ABI/testing/sysfs-bus-iio | 23 +++++++++++++++++++++++ drivers/iio/industrialio-core.c | 1 + include/uapi/linux/iio/types.h | 1 + tools/iio/iio_event_monitor.c | 2 ++ 4 files changed, 27 insertions(+) diff --git a/Documentation/ABI/testing/sysfs-bus-iio b/Documentation/ABI/testing/sysfs-bus-iio index 363dd4b09930..59968b745518 100644 --- a/Documentation/ABI/testing/sysfs-bus-iio +++ b/Documentation/ABI/testing/sysfs-bus-iio @@ -293,6 +293,21 @@ Description: angle samples acquired during that time. Units after application of scale and offset are radians. +What: /sys/bus/iio/devices/iio:deviceX/in_deltavelocity_x_raw +What: /sys/bus/iio/devices/iio:deviceX/in_deltavelocity_y_raw +What: /sys/bus/iio/devices/iio:deviceX/in_deltavelocity_z_raw +KernelVersion: 6.5 +Contact: linux-iio@vger.kernel.org +Description: + The linear velocity change between two consecutive samples on x, + y or z (may be arbitrarily assigned but should match other such + assignments on device). + In order to compute the total linear velocity change during a + desired period of time, the application should sum-up the delta + velocity samples acquired during that time. + Units after application of scale and offset are meters per + second. + What: /sys/bus/iio/devices/iio:deviceX/in_angl_raw What: /sys/bus/iio/devices/iio:deviceX/in_anglY_raw KernelVersion: 4.17 @@ -476,6 +491,7 @@ What: /sys/bus/iio/devices/iio:deviceX/in_velocity_sqrt(x^2+y^2+z^2)_scale What: /sys/bus/iio/devices/iio:deviceX/in_illuminance_scale What: /sys/bus/iio/devices/iio:deviceX/in_countY_scale What: /sys/bus/iio/devices/iio:deviceX/in_deltaangl_scale +What: /sys/bus/iio/devices/iio:deviceX/in_deltavelocity_scale What: /sys/bus/iio/devices/iio:deviceX/in_angl_scale What: /sys/bus/iio/devices/iio:deviceX/in_intensity_x_scale What: /sys/bus/iio/devices/iio:deviceX/in_intensity_y_scale @@ -1350,6 +1366,9 @@ What: /sys/.../iio:deviceX/bufferY/in_accel_z_en What: /sys/.../iio:deviceX/bufferY/in_deltaangl_x_en What: /sys/.../iio:deviceX/bufferY/in_deltaangl_y_en What: /sys/.../iio:deviceX/bufferY/in_deltaangl_z_en +What: /sys/.../iio:deviceX/bufferY/in_deltavelocity_x_en +What: /sys/.../iio:deviceX/bufferY/in_deltavelocity_y_en +What: /sys/.../iio:deviceX/bufferY/in_deltavelocity_z_en What: /sys/.../iio:deviceX/bufferY/in_anglvel_x_en What: /sys/.../iio:deviceX/bufferY/in_anglvel_y_en What: /sys/.../iio:deviceX/bufferY/in_anglvel_z_en @@ -1381,6 +1400,7 @@ Description: What: /sys/.../iio:deviceX/bufferY/in_accel_type What: /sys/.../iio:deviceX/bufferY/in_deltaangl_type +What: /sys/.../iio:deviceX/bufferY/in_deltavelocity_type What: /sys/.../iio:deviceX/bufferY/in_anglvel_type What: /sys/.../iio:deviceX/bufferY/in_magn_type What: /sys/.../iio:deviceX/bufferY/in_incli_type @@ -1438,6 +1458,9 @@ What: /sys/.../iio:deviceX/bufferY/in_accel_z_index What: /sys/.../iio:deviceX/bufferY/in_deltaangl_x_index What: /sys/.../iio:deviceX/bufferY/in_deltaangl_y_index What: /sys/.../iio:deviceX/bufferY/in_deltaangl_z_index +What: /sys/.../iio:deviceX/bufferY/in_deltavelocity_x_index +What: /sys/.../iio:deviceX/bufferY/in_deltavelocity_y_index +What: /sys/.../iio:deviceX/bufferY/in_deltavelocity_z_index What: /sys/.../iio:deviceX/bufferY/in_anglvel_x_index What: /sys/.../iio:deviceX/bufferY/in_anglvel_y_index What: /sys/.../iio:deviceX/bufferY/in_anglvel_z_index diff --git a/drivers/iio/industrialio-core.c b/drivers/iio/industrialio-core.c index 11a65030186d..2ea0bf08caf3 100644 --- a/drivers/iio/industrialio-core.c +++ b/drivers/iio/industrialio-core.c @@ -91,6 +91,7 @@ static const char * const iio_chan_type_name_spec[] = { [IIO_PHASE] = "phase", [IIO_MASSCONCENTRATION] = "massconcentration", [IIO_DELTA_ANGL] = "deltaangl", + [IIO_DELTA_VELOCITY] = "deltavelocity", }; static const char * const iio_modifier_names[] = { diff --git a/include/uapi/linux/iio/types.h b/include/uapi/linux/iio/types.h index 55666a17d311..9a341bd07702 100644 --- a/include/uapi/linux/iio/types.h +++ b/include/uapi/linux/iio/types.h @@ -48,6 +48,7 @@ enum iio_chan_type { IIO_PHASE, IIO_MASSCONCENTRATION, IIO_DELTA_ANGL, + IIO_DELTA_VELOCITY, }; enum iio_modifier { diff --git a/tools/iio/iio_event_monitor.c b/tools/iio/iio_event_monitor.c index 3505450060e6..7e6761612246 100644 --- a/tools/iio/iio_event_monitor.c +++ b/tools/iio/iio_event_monitor.c @@ -60,6 +60,7 @@ static const char * const iio_chan_type_name_spec[] = { [IIO_PHASE] = "phase", [IIO_MASSCONCENTRATION] = "massconcentration", [IIO_DELTA_ANGL] = "deltaangl", + [IIO_DELTA_VELOCITY] = "deltavelocity", }; static const char * const iio_ev_type_text[] = { @@ -175,6 +176,7 @@ static bool event_is_known(struct iio_event_data *event) case IIO_PHASE: case IIO_MASSCONCENTRATION: case IIO_DELTA_ANGL: + case IIO_DELTA_VELOCITY: break; default: return false; From 8f6bc87d67c0309a98546d933bfefd2837154c8e Mon Sep 17 00:00:00 2001 From: Ramona Bolboaca Date: Tue, 8 Aug 2023 10:50:59 +0300 Subject: [PATCH 046/326] iio: imu: adis16475.c: Add delta angle and delta velocity channels Add support for delta angle and delta velocity raw and buffer readings to adis16475 driver. Signed-off-by: Ramona Bolboaca Reviewed-by: Nuno Sa Link: https://lore.kernel.org/r/20230808075059.645525-4-ramona.bolboaca@analog.com Signed-off-by: Jonathan Cameron --- drivers/iio/imu/adis16475.c | 165 +++++++++++++++++++++++++++++++----- 1 file changed, 146 insertions(+), 19 deletions(-) diff --git a/drivers/iio/imu/adis16475.c b/drivers/iio/imu/adis16475.c index 17275a53ca2c..00e4e09cdafb 100644 --- a/drivers/iio/imu/adis16475.c +++ b/drivers/iio/imu/adis16475.c @@ -31,6 +31,12 @@ #define ADIS16475_REG_Y_ACCEL_L 0x14 #define ADIS16475_REG_Z_ACCEL_L 0x18 #define ADIS16475_REG_TEMP_OUT 0x1c +#define ADIS16475_REG_X_DELTANG_L 0x24 +#define ADIS16475_REG_Y_DELTANG_L 0x28 +#define ADIS16475_REG_Z_DELTANG_L 0x2C +#define ADIS16475_REG_X_DELTVEL_L 0x30 +#define ADIS16475_REG_Y_DELTVEL_L 0x34 +#define ADIS16475_REG_Z_DELTVEL_L 0x38 #define ADIS16475_REG_X_GYRO_BIAS_L 0x40 #define ADIS16475_REG_Y_GYRO_BIAS_L 0x44 #define ADIS16475_REG_Z_GYRO_BIAS_L 0x48 @@ -55,6 +61,7 @@ #define ADIS16475_REG_PROD_ID 0x72 #define ADIS16475_REG_SERIAL_NUM 0x74 #define ADIS16475_REG_FLASH_CNT 0x7c +#define ADIS16500_BURST_DATA_SEL_MASK BIT(8) #define ADIS16500_BURST32_MASK BIT(9) #define ADIS16500_BURST32(x) FIELD_PREP(ADIS16500_BURST32_MASK, x) /* number of data elements in burst mode */ @@ -65,6 +72,8 @@ #define ADIS16475_BURST_MAX_SPEED 1000000 #define ADIS16475_LSB_DEC_MASK BIT(0) #define ADIS16475_LSB_FIR_MASK BIT(1) +#define ADIS16500_BURST_DATA_SEL_0_CHN_MASK GENMASK(5, 0) +#define ADIS16500_BURST_DATA_SEL_1_CHN_MASK GENMASK(12, 7) enum { ADIS16475_SYNC_DIRECT = 1, @@ -84,16 +93,20 @@ struct adis16475_chip_info { const struct adis16475_sync *sync; const struct adis_data adis_data; const char *name; +#define ADIS16475_HAS_BURST32 BIT(0) +#define ADIS16475_HAS_BURST_DELTA_DATA BIT(1) + const long flags; u32 num_channels; u32 gyro_max_val; u32 gyro_max_scale; u32 accel_max_val; u32 accel_max_scale; u32 temp_scale; + u32 deltang_max_val; + u32 deltvel_max_val; u32 int_clk; u16 max_dec; u8 num_sync; - bool has_burst32; }; struct adis16475 { @@ -115,6 +128,12 @@ enum { ADIS16475_SCAN_ACCEL_Y, ADIS16475_SCAN_ACCEL_Z, ADIS16475_SCAN_TEMP, + ADIS16475_SCAN_DELTANG_X, + ADIS16475_SCAN_DELTANG_Y, + ADIS16475_SCAN_DELTANG_Z, + ADIS16475_SCAN_DELTVEL_X, + ADIS16475_SCAN_DELTVEL_Y, + ADIS16475_SCAN_DELTVEL_Z, }; static bool low_rate_allow; @@ -451,6 +470,14 @@ static int adis16475_read_raw(struct iio_dev *indio_dev, case IIO_TEMP: *val = st->info->temp_scale; return IIO_VAL_INT; + case IIO_DELTA_ANGL: + *val = st->info->deltang_max_val; + *val2 = 31; + return IIO_VAL_FRACTIONAL_LOG2; + case IIO_DELTA_VELOCITY: + *val = st->info->deltvel_max_val; + *val2 = 31; + return IIO_VAL_FRACTIONAL_LOG2; default: return -EINVAL; } @@ -551,6 +578,32 @@ static int adis16475_write_raw(struct iio_dev *indio_dev, }, \ } +#define ADIS16475_MOD_CHAN_DELTA(_type, _mod, _address, _si, _r_bits, _s_bits) { \ + .type = (_type), \ + .modified = 1, \ + .channel2 = (_mod), \ + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ + .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \ + .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ) | \ + BIT(IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY), \ + .address = (_address), \ + .scan_index = _si, \ + .scan_type = { \ + .sign = 's', \ + .realbits = (_r_bits), \ + .storagebits = (_s_bits), \ + .endianness = IIO_BE, \ + }, \ + } + +#define ADIS16475_DELTANG_CHAN(_mod) \ + ADIS16475_MOD_CHAN_DELTA(IIO_DELTA_ANGL, IIO_MOD_ ## _mod, \ + ADIS16475_REG_ ## _mod ## _DELTANG_L, ADIS16475_SCAN_DELTANG_ ## _mod, 32, 32) + +#define ADIS16475_DELTVEL_CHAN(_mod) \ + ADIS16475_MOD_CHAN_DELTA(IIO_DELTA_VELOCITY, IIO_MOD_ ## _mod, \ + ADIS16475_REG_ ## _mod ## _DELTVEL_L, ADIS16475_SCAN_DELTVEL_ ## _mod, 32, 32) + static const struct iio_chan_spec adis16475_channels[] = { ADIS16475_GYRO_CHANNEL(X), ADIS16475_GYRO_CHANNEL(Y), @@ -559,7 +612,13 @@ static const struct iio_chan_spec adis16475_channels[] = { ADIS16475_ACCEL_CHANNEL(Y), ADIS16475_ACCEL_CHANNEL(Z), ADIS16475_TEMP_CHANNEL(), - IIO_CHAN_SOFT_TIMESTAMP(7) + ADIS16475_DELTANG_CHAN(X), + ADIS16475_DELTANG_CHAN(Y), + ADIS16475_DELTANG_CHAN(Z), + ADIS16475_DELTVEL_CHAN(X), + ADIS16475_DELTVEL_CHAN(Y), + ADIS16475_DELTVEL_CHAN(Z), + IIO_CHAN_SOFT_TIMESTAMP(13) }; enum adis16475_variant { @@ -662,6 +721,8 @@ static const struct adis16475_chip_info adis16475_chip_info[] = { .accel_max_val = 1, .accel_max_scale = IIO_M_S_2_TO_G(800 << 16), .temp_scale = 100, + .deltang_max_val = IIO_DEGREE_TO_RAD(2160), + .deltvel_max_val = 400, .int_clk = 2000, .max_dec = 1999, .sync = adis16475_sync_mode, @@ -677,6 +738,8 @@ static const struct adis16475_chip_info adis16475_chip_info[] = { .accel_max_val = 1, .accel_max_scale = IIO_M_S_2_TO_G(4000 << 16), .temp_scale = 100, + .deltang_max_val = IIO_DEGREE_TO_RAD(360), + .deltvel_max_val = 100, .int_clk = 2000, .max_dec = 1999, .sync = adis16475_sync_mode, @@ -692,6 +755,8 @@ static const struct adis16475_chip_info adis16475_chip_info[] = { .accel_max_val = 1, .accel_max_scale = IIO_M_S_2_TO_G(4000 << 16), .temp_scale = 100, + .deltang_max_val = IIO_DEGREE_TO_RAD(720), + .deltvel_max_val = 100, .int_clk = 2000, .max_dec = 1999, .sync = adis16475_sync_mode, @@ -707,6 +772,8 @@ static const struct adis16475_chip_info adis16475_chip_info[] = { .accel_max_val = 1, .accel_max_scale = IIO_M_S_2_TO_G(4000 << 16), .temp_scale = 100, + .deltang_max_val = IIO_DEGREE_TO_RAD(2160), + .deltvel_max_val = 100, .int_clk = 2000, .max_dec = 1999, .sync = adis16475_sync_mode, @@ -722,11 +789,13 @@ static const struct adis16475_chip_info adis16475_chip_info[] = { .accel_max_val = 1, .accel_max_scale = IIO_M_S_2_TO_G(800 << 16), .temp_scale = 100, + .deltang_max_val = IIO_DEGREE_TO_RAD(360), + .deltvel_max_val = 400, .int_clk = 2000, .max_dec = 1999, .sync = adis16475_sync_mode, .num_sync = ARRAY_SIZE(adis16475_sync_mode), - .has_burst32 = true, + .flags = ADIS16475_HAS_BURST32 | ADIS16475_HAS_BURST_DELTA_DATA, .adis_data = ADIS16475_DATA(16477, &adis16475_timeouts), }, [ADIS16477_2] = { @@ -738,11 +807,13 @@ static const struct adis16475_chip_info adis16475_chip_info[] = { .accel_max_val = 1, .accel_max_scale = IIO_M_S_2_TO_G(800 << 16), .temp_scale = 100, + .deltang_max_val = IIO_DEGREE_TO_RAD(720), + .deltvel_max_val = 400, .int_clk = 2000, .max_dec = 1999, .sync = adis16475_sync_mode, .num_sync = ARRAY_SIZE(adis16475_sync_mode), - .has_burst32 = true, + .flags = ADIS16475_HAS_BURST32 | ADIS16475_HAS_BURST_DELTA_DATA, .adis_data = ADIS16475_DATA(16477, &adis16475_timeouts), }, [ADIS16477_3] = { @@ -754,11 +825,13 @@ static const struct adis16475_chip_info adis16475_chip_info[] = { .accel_max_val = 1, .accel_max_scale = IIO_M_S_2_TO_G(800 << 16), .temp_scale = 100, + .deltang_max_val = IIO_DEGREE_TO_RAD(2160), + .deltvel_max_val = 400, .int_clk = 2000, .max_dec = 1999, .sync = adis16475_sync_mode, .num_sync = ARRAY_SIZE(adis16475_sync_mode), - .has_burst32 = true, + .flags = ADIS16475_HAS_BURST32 | ADIS16475_HAS_BURST_DELTA_DATA, .adis_data = ADIS16475_DATA(16477, &adis16475_timeouts), }, [ADIS16465_1] = { @@ -770,6 +843,8 @@ static const struct adis16475_chip_info adis16475_chip_info[] = { .accel_max_val = 1, .accel_max_scale = IIO_M_S_2_TO_G(4000 << 16), .temp_scale = 100, + .deltang_max_val = IIO_DEGREE_TO_RAD(360), + .deltvel_max_val = 100, .int_clk = 2000, .max_dec = 1999, .sync = adis16475_sync_mode, @@ -785,6 +860,8 @@ static const struct adis16475_chip_info adis16475_chip_info[] = { .accel_max_val = 1, .accel_max_scale = IIO_M_S_2_TO_G(4000 << 16), .temp_scale = 100, + .deltang_max_val = IIO_DEGREE_TO_RAD(720), + .deltvel_max_val = 100, .int_clk = 2000, .max_dec = 1999, .sync = adis16475_sync_mode, @@ -800,6 +877,8 @@ static const struct adis16475_chip_info adis16475_chip_info[] = { .accel_max_val = 1, .accel_max_scale = IIO_M_S_2_TO_G(4000 << 16), .temp_scale = 100, + .deltang_max_val = IIO_DEGREE_TO_RAD(2160), + .deltvel_max_val = 100, .int_clk = 2000, .max_dec = 1999, .sync = adis16475_sync_mode, @@ -815,6 +894,8 @@ static const struct adis16475_chip_info adis16475_chip_info[] = { .accel_max_val = 1, .accel_max_scale = IIO_M_S_2_TO_G(800 << 16), .temp_scale = 100, + .deltang_max_val = IIO_DEGREE_TO_RAD(360), + .deltvel_max_val = 400, .int_clk = 2000, .max_dec = 1999, .sync = adis16475_sync_mode, @@ -830,6 +911,8 @@ static const struct adis16475_chip_info adis16475_chip_info[] = { .accel_max_val = 1, .accel_max_scale = IIO_M_S_2_TO_G(800 << 16), .temp_scale = 100, + .deltang_max_val = IIO_DEGREE_TO_RAD(720), + .deltvel_max_val = 400, .int_clk = 2000, .max_dec = 1999, .sync = adis16475_sync_mode, @@ -845,6 +928,8 @@ static const struct adis16475_chip_info adis16475_chip_info[] = { .accel_max_val = 1, .accel_max_scale = IIO_M_S_2_TO_G(800 << 16), .temp_scale = 100, + .deltang_max_val = IIO_DEGREE_TO_RAD(2160), + .deltvel_max_val = 400, .int_clk = 2000, .max_dec = 1999, .sync = adis16475_sync_mode, @@ -860,12 +945,14 @@ static const struct adis16475_chip_info adis16475_chip_info[] = { .accel_max_val = 392, .accel_max_scale = 32000 << 16, .temp_scale = 100, + .deltang_max_val = IIO_DEGREE_TO_RAD(2160), + .deltvel_max_val = 400, .int_clk = 2000, .max_dec = 1999, .sync = adis16475_sync_mode, /* pulse sync not supported */ .num_sync = ARRAY_SIZE(adis16475_sync_mode) - 1, - .has_burst32 = true, + .flags = ADIS16475_HAS_BURST32 | ADIS16475_HAS_BURST_DELTA_DATA, .adis_data = ADIS16475_DATA(16500, &adis1650x_timeouts), }, [ADIS16505_1] = { @@ -877,12 +964,14 @@ static const struct adis16475_chip_info adis16475_chip_info[] = { .accel_max_val = 78, .accel_max_scale = 32000 << 16, .temp_scale = 100, + .deltang_max_val = IIO_DEGREE_TO_RAD(360), + .deltvel_max_val = 100, .int_clk = 2000, .max_dec = 1999, .sync = adis16475_sync_mode, /* pulse sync not supported */ .num_sync = ARRAY_SIZE(adis16475_sync_mode) - 1, - .has_burst32 = true, + .flags = ADIS16475_HAS_BURST32 | ADIS16475_HAS_BURST_DELTA_DATA, .adis_data = ADIS16475_DATA(16505, &adis1650x_timeouts), }, [ADIS16505_2] = { @@ -894,12 +983,14 @@ static const struct adis16475_chip_info adis16475_chip_info[] = { .accel_max_val = 78, .accel_max_scale = 32000 << 16, .temp_scale = 100, + .deltang_max_val = IIO_DEGREE_TO_RAD(720), + .deltvel_max_val = 100, .int_clk = 2000, .max_dec = 1999, .sync = adis16475_sync_mode, /* pulse sync not supported */ .num_sync = ARRAY_SIZE(adis16475_sync_mode) - 1, - .has_burst32 = true, + .flags = ADIS16475_HAS_BURST32 | ADIS16475_HAS_BURST_DELTA_DATA, .adis_data = ADIS16475_DATA(16505, &adis1650x_timeouts), }, [ADIS16505_3] = { @@ -911,12 +1002,14 @@ static const struct adis16475_chip_info adis16475_chip_info[] = { .accel_max_val = 78, .accel_max_scale = 32000 << 16, .temp_scale = 100, + .deltang_max_val = IIO_DEGREE_TO_RAD(2160), + .deltvel_max_val = 100, .int_clk = 2000, .max_dec = 1999, .sync = adis16475_sync_mode, /* pulse sync not supported */ .num_sync = ARRAY_SIZE(adis16475_sync_mode) - 1, - .has_burst32 = true, + .flags = ADIS16475_HAS_BURST32 | ADIS16475_HAS_BURST_DELTA_DATA, .adis_data = ADIS16475_DATA(16505, &adis1650x_timeouts), }, [ADIS16507_1] = { @@ -928,12 +1021,14 @@ static const struct adis16475_chip_info adis16475_chip_info[] = { .accel_max_val = 392, .accel_max_scale = 32000 << 16, .temp_scale = 100, + .deltang_max_val = IIO_DEGREE_TO_RAD(360), + .deltvel_max_val = 400, .int_clk = 2000, .max_dec = 1999, .sync = adis16475_sync_mode, /* pulse sync not supported */ .num_sync = ARRAY_SIZE(adis16475_sync_mode) - 1, - .has_burst32 = true, + .flags = ADIS16475_HAS_BURST32 | ADIS16475_HAS_BURST_DELTA_DATA, .adis_data = ADIS16475_DATA(16507, &adis1650x_timeouts), }, [ADIS16507_2] = { @@ -945,12 +1040,14 @@ static const struct adis16475_chip_info adis16475_chip_info[] = { .accel_max_val = 392, .accel_max_scale = 32000 << 16, .temp_scale = 100, + .deltang_max_val = IIO_DEGREE_TO_RAD(720), + .deltvel_max_val = 400, .int_clk = 2000, .max_dec = 1999, .sync = adis16475_sync_mode, /* pulse sync not supported */ .num_sync = ARRAY_SIZE(adis16475_sync_mode) - 1, - .has_burst32 = true, + .flags = ADIS16475_HAS_BURST32 | ADIS16475_HAS_BURST_DELTA_DATA, .adis_data = ADIS16475_DATA(16507, &adis1650x_timeouts), }, [ADIS16507_3] = { @@ -962,20 +1059,47 @@ static const struct adis16475_chip_info adis16475_chip_info[] = { .accel_max_val = 392, .accel_max_scale = 32000 << 16, .temp_scale = 100, + .deltang_max_val = IIO_DEGREE_TO_RAD(2160), + .deltvel_max_val = 400, .int_clk = 2000, .max_dec = 1999, .sync = adis16475_sync_mode, /* pulse sync not supported */ .num_sync = ARRAY_SIZE(adis16475_sync_mode) - 1, - .has_burst32 = true, + .flags = ADIS16475_HAS_BURST32 | ADIS16475_HAS_BURST_DELTA_DATA, .adis_data = ADIS16475_DATA(16507, &adis1650x_timeouts), }, }; +static int adis16475_update_scan_mode(struct iio_dev *indio_dev, + const unsigned long *scan_mask) +{ + u16 en; + int ret; + struct adis16475 *st = iio_priv(indio_dev); + + if (st->info->flags & ADIS16475_HAS_BURST_DELTA_DATA) { + if ((*scan_mask & ADIS16500_BURST_DATA_SEL_0_CHN_MASK) && + (*scan_mask & ADIS16500_BURST_DATA_SEL_1_CHN_MASK)) + return -EINVAL; + if (*scan_mask & ADIS16500_BURST_DATA_SEL_0_CHN_MASK) + en = FIELD_PREP(ADIS16500_BURST_DATA_SEL_MASK, 0); + else + en = FIELD_PREP(ADIS16500_BURST_DATA_SEL_MASK, 1); + + ret = __adis_update_bits(&st->adis, ADIS16475_REG_MSG_CTRL, + ADIS16500_BURST_DATA_SEL_MASK, en); + if (ret) + return ret; + } + + return adis_update_scan_mode(indio_dev, scan_mask); +} + static const struct iio_info adis16475_info = { .read_raw = &adis16475_read_raw, .write_raw = &adis16475_write_raw, - .update_scan_mode = adis_update_scan_mode, + .update_scan_mode = adis16475_update_scan_mode, .debugfs_reg_access = adis_debugfs_reg_access, }; @@ -998,7 +1122,7 @@ static void adis16475_burst32_check(struct adis16475 *st) int ret; struct adis *adis = &st->adis; - if (!st->info->has_burst32) + if (!(st->info->flags & ADIS16475_HAS_BURST32)) return; if (st->lsb_flag && !st->burst32) { @@ -1044,7 +1168,7 @@ static irqreturn_t adis16475_trigger_handler(int irq, void *p) struct iio_dev *indio_dev = pf->indio_dev; struct adis16475 *st = iio_priv(indio_dev); struct adis *adis = &st->adis; - int ret, bit, i = 0; + int ret, bit, buff_offset = 0, i = 0; __be16 *buffer; u16 crc; bool valid; @@ -1074,6 +1198,9 @@ static irqreturn_t adis16475_trigger_handler(int irq, void *p) case ADIS16475_SCAN_TEMP: st->data[i++] = buffer[offset]; break; + case ADIS16475_SCAN_DELTANG_X ... ADIS16475_SCAN_DELTVEL_Z: + buff_offset = ADIS16475_SCAN_DELTANG_X; + fallthrough; case ADIS16475_SCAN_GYRO_X ... ADIS16475_SCAN_ACCEL_Z: /* * The first 2 bytes on the received data are the @@ -1081,18 +1208,18 @@ static irqreturn_t adis16475_trigger_handler(int irq, void *p) */ if (st->burst32) { /* upper 16 */ - st->data[i++] = buffer[bit * 2 + 2]; + st->data[i++] = buffer[(bit - buff_offset) * 2 + 2]; /* lower 16 */ - st->data[i++] = buffer[bit * 2 + 1]; + st->data[i++] = buffer[(bit - buff_offset) * 2 + 1]; } else { - st->data[i++] = buffer[bit + 1]; + st->data[i++] = buffer[(bit - buff_offset) + 1]; /* * Don't bother in doing the manual read if the * device supports burst32. burst32 will be * enabled in the next call to * adis16475_burst32_check()... */ - if (st->lsb_flag && !st->info->has_burst32) { + if (st->lsb_flag && !(st->info->flags & ADIS16475_HAS_BURST32)) { u16 val = 0; const u32 reg = ADIS16475_REG_X_GYRO_L + bit * 4; From 3a23b384e7e3d64d5587ad10729a34d4f761517e Mon Sep 17 00:00:00 2001 From: Zhang Shurong Date: Sat, 15 Jul 2023 23:55:50 +0800 Subject: [PATCH 047/326] iio: adc: stm32-adc: harden against NULL pointer deref in stm32_adc_probe() of_match_device() may fail and returns a NULL pointer. In practice there is no known reasonable way to trigger this, but in case one is added in future, harden the code by adding the check Signed-off-by: Zhang Shurong Link: https://lore.kernel.org/r/tencent_994DA85912C937E3B5405BA960B31ED90A08@qq.com Signed-off-by: Jonathan Cameron --- drivers/iio/adc/stm32-adc-core.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/drivers/iio/adc/stm32-adc-core.c b/drivers/iio/adc/stm32-adc-core.c index 2f082006550f..bbd5bdd732f0 100644 --- a/drivers/iio/adc/stm32-adc-core.c +++ b/drivers/iio/adc/stm32-adc-core.c @@ -708,6 +708,8 @@ static int stm32_adc_probe(struct platform_device *pdev) struct stm32_adc_priv *priv; struct device *dev = &pdev->dev; struct device_node *np = pdev->dev.of_node; + const struct of_device_id *of_id; + struct resource *res; u32 max_rate; int ret; @@ -720,8 +722,11 @@ static int stm32_adc_probe(struct platform_device *pdev) return -ENOMEM; platform_set_drvdata(pdev, &priv->common); - priv->cfg = (const struct stm32_adc_priv_cfg *) - of_match_device(dev->driver->of_match_table, dev)->data; + of_id = of_match_device(dev->driver->of_match_table, dev); + if (!of_id) + return -ENODEV; + + priv->cfg = (const struct stm32_adc_priv_cfg *)of_id->data; priv->nb_adc_max = priv->cfg->num_adcs; spin_lock_init(&priv->common.lock); From 8aa6e6682f3624dca0cfbc3824e2d9937e58ca59 Mon Sep 17 00:00:00 2001 From: Antoniu Miclaus Date: Wed, 30 Aug 2023 12:43:14 +0300 Subject: [PATCH 048/326] iio: addac: ad74413r: fix function prefix typo Use complete device name prefix in the input current offset getter function. Signed-off-by: Antoniu Miclaus Reviewed-by: Nuno Sa Link: https://lore.kernel.org/r/20230830094314.26353-1-antoniu.miclaus@analog.com Signed-off-by: Jonathan Cameron --- drivers/iio/addac/ad74413r.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/iio/addac/ad74413r.c b/drivers/iio/addac/ad74413r.c index 6b0e8218f150..75216ece7ad6 100644 --- a/drivers/iio/addac/ad74413r.c +++ b/drivers/iio/addac/ad74413r.c @@ -705,8 +705,8 @@ static int ad74413r_get_input_current_scale(struct ad74413r_state *st, return IIO_VAL_FRACTIONAL; } -static int ad74413_get_input_current_offset(struct ad74413r_state *st, - unsigned int channel, int *val) +static int ad74413r_get_input_current_offset(struct ad74413r_state *st, + unsigned int channel, int *val) { unsigned int range; int voltage_range; @@ -991,7 +991,7 @@ static int ad74413r_read_raw(struct iio_dev *indio_dev, return ad74413r_get_input_voltage_offset(st, chan->channel, val); case IIO_CURRENT: - return ad74413_get_input_current_offset(st, + return ad74413r_get_input_current_offset(st, chan->channel, val); default: return -EINVAL; From 0679ea0be2c86e384bc7fef46ef94cdd0aa73aa3 Mon Sep 17 00:00:00 2001 From: Liam Beguin Date: Mon, 28 Aug 2023 22:41:34 -0400 Subject: [PATCH 049/326] dt-bindings: iio: adc: add lltc,ltc2309 bindings Add devicetree bindings for the Linear Technology LTC2309 ADC driver. Reviewed-by: Krzysztof Kozlowski Signed-off-by: Liam Beguin Link: https://lore.kernel.org/r/20230828-ltc2309-v3-1-338b3a8fab8b@gmail.com Signed-off-by: Jonathan Cameron --- .../bindings/iio/adc/lltc,ltc2497.yaml | 20 ++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/Documentation/devicetree/bindings/iio/adc/lltc,ltc2497.yaml b/Documentation/devicetree/bindings/iio/adc/lltc,ltc2497.yaml index 875f394576c2..5cc6a9684077 100644 --- a/Documentation/devicetree/bindings/iio/adc/lltc,ltc2497.yaml +++ b/Documentation/devicetree/bindings/iio/adc/lltc,ltc2497.yaml @@ -4,21 +4,31 @@ $id: http://devicetree.org/schemas/iio/adc/lltc,ltc2497.yaml# $schema: http://devicetree.org/meta-schemas/core.yaml# -title: Linear Technology / Analog Devices LTC2497 ADC +title: Linear Technology / Analog Devices LTC2497 and LTC2309 ADC maintainers: - Michael Hennerich + - Liam Beguin description: | - 16bit ADC supporting up to 16 single ended or 8 differential inputs. - I2C interface. + LTC2309: + low noise, low power, 8-channel, 12-bit successive approximation ADC with an + I2C compatible serial interface. - https://www.analog.com/media/en/technical-documentation/data-sheets/2497fb.pdf - https://www.analog.com/media/en/technical-documentation/data-sheets/2499fe.pdf + https://www.analog.com/media/en/technical-documentation/data-sheets/2309fd.pdf + + LTC2497: + LTC2499: + 16bit ADC supporting up to 16 single ended or 8 differential inputs. + I2C interface. + + https://www.analog.com/media/en/technical-documentation/data-sheets/2497fb.pdf + https://www.analog.com/media/en/technical-documentation/data-sheets/2499fe.pdf properties: compatible: enum: + - lltc,ltc2309 - lltc,ltc2497 - lltc,ltc2499 From 733e0fed9c275b7d9e07041cfca8b221c71e3bd2 Mon Sep 17 00:00:00 2001 From: Liam Beguin Date: Mon, 28 Aug 2023 22:41:35 -0400 Subject: [PATCH 050/326] iio: adc: add ltc2309 support The LTC2309 is an 8-Channel, 12-Bit SAR ADC with an I2C Interface. This implements support for all single-ended and differential channels, in unipolar mode only. Signed-off-by: Liam Beguin Link: https://lore.kernel.org/r/20230828-ltc2309-v3-2-338b3a8fab8b@gmail.com Signed-off-by: Jonathan Cameron --- drivers/iio/adc/Kconfig | 10 ++ drivers/iio/adc/Makefile | 1 + drivers/iio/adc/ltc2309.c | 246 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 257 insertions(+) create mode 100644 drivers/iio/adc/ltc2309.c diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig index 432d3f9bfde1..bb3786745ab6 100644 --- a/drivers/iio/adc/Kconfig +++ b/drivers/iio/adc/Kconfig @@ -607,6 +607,16 @@ config LPC32XX_ADC activate only one via device tree selection. Provides direct access via sysfs. +config LTC2309 + tristate "Linear Technology LTC2309 ADC driver" + depends on I2C + help + Say yes here to build support for Linear Technology LTC2309, a low + noise, low power, 8-channel, 12-bit SAR ADC + + This driver can also be built as a module. If so, the module will + be called ltc2309. + config LTC2471 tristate "Linear Technology LTC2471 and LTC2473 ADC driver" depends on I2C diff --git a/drivers/iio/adc/Makefile b/drivers/iio/adc/Makefile index 2facf979327d..2d5b2a181380 100644 --- a/drivers/iio/adc/Makefile +++ b/drivers/iio/adc/Makefile @@ -56,6 +56,7 @@ obj-$(CONFIG_INTEL_MRFLD_ADC) += intel_mrfld_adc.o obj-$(CONFIG_LP8788_ADC) += lp8788_adc.o obj-$(CONFIG_LPC18XX_ADC) += lpc18xx_adc.o obj-$(CONFIG_LPC32XX_ADC) += lpc32xx_adc.o +obj-$(CONFIG_LTC2309) += ltc2309.o obj-$(CONFIG_LTC2471) += ltc2471.o obj-$(CONFIG_LTC2485) += ltc2485.o obj-$(CONFIG_LTC2496) += ltc2496.o ltc2497-core.o diff --git a/drivers/iio/adc/ltc2309.c b/drivers/iio/adc/ltc2309.c new file mode 100644 index 000000000000..8b3a89c1b840 --- /dev/null +++ b/drivers/iio/adc/ltc2309.c @@ -0,0 +1,246 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * The LTC2309 is an 8-Channel, 12-Bit SAR ADC with an I2C Interface. + * + * Datasheet: + * https://www.analog.com/media/en/technical-documentation/data-sheets/2309fd.pdf + * + * Copyright (c) 2023, Liam Beguin + */ +#include +#include +#include +#include +#include +#include +#include + +#define LTC2309_ADC_RESOLUTION 12 + +#define LTC2309_DIN_CH_MASK GENMASK(7, 4) +#define LTC2309_DIN_SDN BIT(7) +#define LTC2309_DIN_OSN BIT(6) +#define LTC2309_DIN_S1 BIT(5) +#define LTC2309_DIN_S0 BIT(4) +#define LTC2309_DIN_UNI BIT(3) +#define LTC2309_DIN_SLEEP BIT(2) + +/** + * struct ltc2309 - internal device data structure + * @dev: Device reference + * @client: I2C reference + * @vref: External reference source + * @lock: Lock to serialize data access + * @vref_mv: Internal voltage reference + */ +struct ltc2309 { + struct device *dev; + struct i2c_client *client; + struct regulator *vref; + struct mutex lock; /* serialize data access */ + int vref_mv; +}; + +/* Order matches expected channel address, See datasheet Table 1. */ +enum ltc2309_channels { + LTC2309_CH0_CH1 = 0, + LTC2309_CH2_CH3, + LTC2309_CH4_CH5, + LTC2309_CH6_CH7, + LTC2309_CH1_CH0, + LTC2309_CH3_CH2, + LTC2309_CH5_CH4, + LTC2309_CH7_CH6, + LTC2309_CH0, + LTC2309_CH2, + LTC2309_CH4, + LTC2309_CH6, + LTC2309_CH1, + LTC2309_CH3, + LTC2309_CH5, + LTC2309_CH7, +}; + +#define LTC2309_CHAN(_chan, _addr) { \ + .type = IIO_VOLTAGE, \ + .indexed = 1, \ + .address = _addr, \ + .channel = _chan, \ + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ + .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \ +} + +#define LTC2309_DIFF_CHAN(_chan, _chan2, _addr) { \ + .type = IIO_VOLTAGE, \ + .differential = 1, \ + .indexed = 1, \ + .address = _addr, \ + .channel = _chan, \ + .channel2 = _chan2, \ + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ + .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \ +} + +static const struct iio_chan_spec ltc2309_channels[] = { + LTC2309_CHAN(0, LTC2309_CH0), + LTC2309_CHAN(1, LTC2309_CH1), + LTC2309_CHAN(2, LTC2309_CH2), + LTC2309_CHAN(3, LTC2309_CH3), + LTC2309_CHAN(4, LTC2309_CH4), + LTC2309_CHAN(5, LTC2309_CH5), + LTC2309_CHAN(6, LTC2309_CH6), + LTC2309_CHAN(7, LTC2309_CH7), + LTC2309_DIFF_CHAN(0, 1, LTC2309_CH0_CH1), + LTC2309_DIFF_CHAN(2, 3, LTC2309_CH2_CH3), + LTC2309_DIFF_CHAN(4, 5, LTC2309_CH4_CH5), + LTC2309_DIFF_CHAN(6, 7, LTC2309_CH6_CH7), + LTC2309_DIFF_CHAN(1, 0, LTC2309_CH1_CH0), + LTC2309_DIFF_CHAN(3, 2, LTC2309_CH3_CH2), + LTC2309_DIFF_CHAN(5, 4, LTC2309_CH5_CH4), + LTC2309_DIFF_CHAN(7, 6, LTC2309_CH7_CH6), +}; + +static int ltc2309_read_raw_channel(struct ltc2309 *ltc2309, + unsigned long address, int *val) +{ + int ret; + u16 buf; + u8 din; + + din = FIELD_PREP(LTC2309_DIN_CH_MASK, address & 0x0f) | + FIELD_PREP(LTC2309_DIN_UNI, 1) | + FIELD_PREP(LTC2309_DIN_SLEEP, 0); + + ret = i2c_smbus_write_byte(ltc2309->client, din); + if (ret < 0) { + dev_err(ltc2309->dev, "i2c command failed: %pe\n", + ERR_PTR(ret)); + return ret; + } + + ret = i2c_master_recv(ltc2309->client, (char *)&buf, 2); + if (ret < 0) { + dev_err(ltc2309->dev, "i2c read failed: %pe\n", ERR_PTR(ret)); + return ret; + } + + *val = be16_to_cpu(buf) >> 4; + + return ret; +} + +static int ltc2309_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, int *val, + int *val2, long mask) +{ + struct ltc2309 *ltc2309 = iio_priv(indio_dev); + int ret; + + switch (mask) { + case IIO_CHAN_INFO_RAW: + mutex_lock(<c2309->lock); + ret = ltc2309_read_raw_channel(ltc2309, chan->address, val); + mutex_unlock(<c2309->lock); + if (ret < 0) + return -EINVAL; + return IIO_VAL_INT; + case IIO_CHAN_INFO_SCALE: + *val = ltc2309->vref_mv; + *val2 = LTC2309_ADC_RESOLUTION; + return IIO_VAL_FRACTIONAL_LOG2; + default: + return -EINVAL; + } +} + +static const struct iio_info ltc2309_info = { + .read_raw = ltc2309_read_raw, +}; + +static void ltc2309_regulator_disable(void *regulator) +{ + regulator_disable(regulator); +} + +static int ltc2309_probe(struct i2c_client *client) +{ + struct iio_dev *indio_dev; + struct ltc2309 *ltc2309; + int ret; + + indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*ltc2309)); + if (!indio_dev) + return -ENOMEM; + + ltc2309 = iio_priv(indio_dev); + ltc2309->dev = &indio_dev->dev; + ltc2309->client = client; + ltc2309->vref_mv = 4096; /* Default to the internal ref */ + + indio_dev->name = "ltc2309"; + indio_dev->modes = INDIO_DIRECT_MODE; + indio_dev->channels = ltc2309_channels; + indio_dev->num_channels = ARRAY_SIZE(ltc2309_channels); + indio_dev->info = <c2309_info; + + ltc2309->vref = devm_regulator_get_optional(&client->dev, "vref"); + if (IS_ERR(ltc2309->vref)) { + ret = PTR_ERR(ltc2309->vref); + if (ret == -ENODEV) + ltc2309->vref = NULL; + else + return ret; + } + + if (ltc2309->vref) { + ret = regulator_enable(ltc2309->vref); + if (ret) + return dev_err_probe(ltc2309->dev, ret, + "failed to enable vref\n"); + + ret = devm_add_action_or_reset(ltc2309->dev, + ltc2309_regulator_disable, + ltc2309->vref); + if (ret) { + return dev_err_probe(ltc2309->dev, ret, + "failed to add regulator_disable action: %d\n", + ret); + } + + ret = regulator_get_voltage(ltc2309->vref); + if (ret < 0) + return ret; + + ltc2309->vref_mv = ret / 1000; + } + + mutex_init(<c2309->lock); + + return devm_iio_device_register(&client->dev, indio_dev); +} + +static const struct of_device_id ltc2309_of_match[] = { + { .compatible = "lltc,ltc2309" }, + { } +}; +MODULE_DEVICE_TABLE(of, ltc2309_of_match); + +static const struct i2c_device_id ltc2309_id[] = { + { "ltc2309" }, + { } +}; +MODULE_DEVICE_TABLE(i2c, ltc2309_id); + +static struct i2c_driver ltc2309_driver = { + .driver = { + .name = "ltc2309", + .of_match_table = ltc2309_of_match, + }, + .probe = ltc2309_probe, + .id_table = ltc2309_id, +}; +module_i2c_driver(ltc2309_driver); + +MODULE_AUTHOR("Liam Beguin "); +MODULE_DESCRIPTION("Linear Technology LTC2309 ADC"); +MODULE_LICENSE("GPL v2"); From df2ece7aec158bd2b62a75b37bcc230bbd2695f4 Mon Sep 17 00:00:00 2001 From: Marius Cristea Date: Tue, 29 Aug 2023 18:41:32 +0300 Subject: [PATCH 051/326] dt-bindings: iio: adc: adding MCP3564 ADC This is the device tree schema for iio driver for Microchip family of 153.6 ksps, Low-Noise 16/24-Bit Delta-Sigma ADCs with an SPI interface (Microchip's MCP3461, MCP3462, MCP3464, MCP3461R, MCP3462R, MCP3464R, MCP3561, MCP3562, MCP3564, MCP3561R, MCP3562R and MCP3564R analog to digital converters). Signed-off-by: Marius Cristea Reviewed-by: Conor Dooley Link: https://lore.kernel.org/r/20230829154133.40716-2-marius.cristea@microchip.com Signed-off-by: Jonathan Cameron --- .../bindings/iio/adc/microchip,mcp3564.yaml | 205 ++++++++++++++++++ 1 file changed, 205 insertions(+) create mode 100644 Documentation/devicetree/bindings/iio/adc/microchip,mcp3564.yaml diff --git a/Documentation/devicetree/bindings/iio/adc/microchip,mcp3564.yaml b/Documentation/devicetree/bindings/iio/adc/microchip,mcp3564.yaml new file mode 100644 index 000000000000..675319276197 --- /dev/null +++ b/Documentation/devicetree/bindings/iio/adc/microchip,mcp3564.yaml @@ -0,0 +1,205 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/iio/adc/microchip,mcp3564.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Microchip MCP346X and MCP356X ADC Family + +maintainers: + - Marius Cristea + +description: | + Bindings for the Microchip family of 153.6 ksps, Low-Noise 16/24-Bit + Delta-Sigma ADCs with an SPI interface. Datasheet can be found here: + Datasheet for MCP3561, MCP3562, MCP3564 can be found here: + https://ww1.microchip.com/downloads/aemDocuments/documents/MSLD/ProductDocuments/DataSheets/MCP3561-2-4-Family-Data-Sheet-DS20006181C.pdf + Datasheet for MCP3561R, MCP3562R, MCP3564R can be found here: + https://ww1.microchip.com/downloads/aemDocuments/documents/APID/ProductDocuments/DataSheets/MCP3561_2_4R-Data-Sheet-DS200006391C.pdf + Datasheet for MCP3461, MCP3462, MCP3464 can be found here: + https://ww1.microchip.com/downloads/aemDocuments/documents/APID/ProductDocuments/DataSheets/MCP3461-2-4-Two-Four-Eight-Channel-153.6-ksps-Low-Noise-16-Bit-Delta-Sigma-ADC-Data-Sheet-20006180D.pdf + Datasheet for MCP3461R, MCP3462R, MCP3464R can be found here: + https://ww1.microchip.com/downloads/aemDocuments/documents/APID/ProductDocuments/DataSheets/MCP3461-2-4R-Family-Data-Sheet-DS20006404C.pdf + +properties: + compatible: + enum: + - microchip,mcp3461 + - microchip,mcp3462 + - microchip,mcp3464 + - microchip,mcp3461r + - microchip,mcp3462r + - microchip,mcp3464r + - microchip,mcp3561 + - microchip,mcp3562 + - microchip,mcp3564 + - microchip,mcp3561r + - microchip,mcp3562r + - microchip,mcp3564r + + reg: + maxItems: 1 + + spi-max-frequency: + maximum: 20000000 + + spi-cpha: true + + spi-cpol: true + + vdd-supply: true + + avdd-supply: true + + clocks: + description: + Phandle and clock identifier for external sampling clock. + If not specified, the internal crystal oscillator will be used. + maxItems: 1 + + interrupts: + description: IRQ line of the ADC + maxItems: 1 + + drive-open-drain: + description: + Whether to drive the IRQ signal as push-pull (default) or open-drain. Note + that the device requires this pin to become "high", otherwise it will stop + converting. + type: boolean + + vref-supply: + description: + Some devices have a specific reference voltage supplied on a different + pin to the other supplies. Needed to be able to establish channel scaling + unless there is also an internal reference available (e.g. mcp3564r). In + case of "r" devices (e. g. mcp3564r), if it does not exists the internal + reference will be used. + + microchip,hw-device-address: + $ref: /schemas/types.yaml#/definitions/uint32 + minimum: 0 + maximum: 3 + description: + The address is set on a per-device basis by fuses in the factory, + configured on request. If not requested, the fuses are set for 0x1. + The device address is part of the device markings to avoid + potential confusion. This address is coded on two bits, so four possible + addresses are available when multiple devices are present on the same + SPI bus with only one Chip Select line for all devices. + Each device communication starts by a CS falling edge, followed by the + clocking of the device address (BITS[7:6] - top two bits of COMMAND BYTE + which is first one on the wire). + + "#io-channel-cells": + const: 1 + + "#address-cells": + const: 1 + + "#size-cells": + const: 0 + +patternProperties: + "^channel@([0-9]|([1-7][0-9]))$": + $ref: adc.yaml + type: object + unevaluatedProperties: false + description: Represents the external channels which are connected to the ADC. + + properties: + reg: + description: The channel number in single-ended and differential mode. + minimum: 0 + maximum: 79 + + required: + - reg + +dependencies: + spi-cpol: [ spi-cpha ] + spi-cpha: [ spi-cpol ] + +required: + - compatible + - reg + - microchip,hw-device-address + - spi-max-frequency + +allOf: + - $ref: /schemas/spi/spi-peripheral-props.yaml# + - # External vref, no internal reference + if: + properties: + compatible: + contains: + enum: + - microchip,mcp3461 + - microchip,mcp3462 + - microchip,mcp3464 + - microchip,mcp3561 + - microchip,mcp3562 + - microchip,mcp3564 + then: + required: + - vref-supply + +unevaluatedProperties: false + +examples: + - | + spi { + #address-cells = <1>; + #size-cells = <0>; + + adc@0 { + compatible = "microchip,mcp3564r"; + reg = <0>; + vref-supply = <&vref_reg>; + spi-cpha; + spi-cpol; + spi-max-frequency = <10000000>; + microchip,hw-device-address = <1>; + + #address-cells = <1>; + #size-cells = <0>; + + channel@0 { + /* CH0 to AGND */ + reg = <0>; + label = "CH0"; + }; + + channel@1 { + /* CH1 to AGND */ + reg = <1>; + label = "CH1"; + }; + + /* diff-channels */ + channel@11 { + reg = <11>; + + /* CN0, CN1 */ + diff-channels = <0 1>; + label = "CH0_CH1"; + }; + + channel@22 { + reg = <0x22>; + + /* CN1, CN2 */ + diff-channels = <1 2>; + label = "CH1_CH3"; + }; + + channel@23 { + reg = <0x23>; + + /* CN1, CN3 */ + diff-channels = <1 3>; + label = "CH1_CH3"; + }; + }; + }; +... From 33ec3e5fc1ea0e0c5c93425170602533c07f55d4 Mon Sep 17 00:00:00 2001 From: Marius Cristea Date: Tue, 29 Aug 2023 18:41:33 +0300 Subject: [PATCH 052/326] iio: adc: adding support for MCP3564 ADC This is the iio driver for Microchip family of 153.6 ksps, Low-Noise 16/24-Bit Delta-Sigma ADCs with an SPI interface (Microchip's MCP3461, MCP3462, MCP3464, MCP3461R, MCP3462R, MCP3464R, MCP3561, MCP3562, MCP3564, MCP3561R, MCP3562R and MCP3564R analog to digital converters). Signed-off-by: Marius Cristea Link: https://lore.kernel.org/r/20230829154133.40716-3-marius.cristea@microchip.com Signed-off-by: Jonathan Cameron --- .../ABI/testing/sysfs-bus-iio-adc-mcp3564 | 53 + MAINTAINERS | 7 + drivers/iio/adc/Kconfig | 13 + drivers/iio/adc/Makefile | 1 + drivers/iio/adc/mcp3564.c | 1516 +++++++++++++++++ 5 files changed, 1590 insertions(+) create mode 100644 Documentation/ABI/testing/sysfs-bus-iio-adc-mcp3564 create mode 100644 drivers/iio/adc/mcp3564.c diff --git a/Documentation/ABI/testing/sysfs-bus-iio-adc-mcp3564 b/Documentation/ABI/testing/sysfs-bus-iio-adc-mcp3564 new file mode 100644 index 000000000000..b168aa44b233 --- /dev/null +++ b/Documentation/ABI/testing/sysfs-bus-iio-adc-mcp3564 @@ -0,0 +1,53 @@ +What: /sys/bus/iio/devices/iio:deviceX/boost_current_gain +KernelVersion: 6.4 +Contact: linux-iio@vger.kernel.org +Description: + This attribute is used to set the gain of the biasing current + circuit of the Delta-Sigma modulator. The different BOOST + settings are applied to the entire modulator circuit, including + the voltage reference buffers. + +What: /sys/bus/iio/devices/iio:deviceX/boost_current_gain_available +KernelVersion: 6.4 +Contact: linux-iio@vger.kernel.org +Description: + Reading returns a list with the possible gain values for + the current biasing circuit of the Delta-Sigma modulator. + +What: /sys/bus/iio/devices/iio:deviceX/auto_zeroing_mux_enable +KernelVersion: 6.4 +Contact: linux-iio@vger.kernel.org +Description: + This attribute is used to enable the analog input multiplexer + auto-zeroing algorithm (the input multiplexer and the ADC + include an offset cancellation algorithm that cancels the offset + contribution of the ADC). When the offset cancellation algorithm + is enabled, ADC takes two conversions, one with the differential + input as VIN+/VIN-, one with VIN+/VIN- inverted. In this case the + conversion time is multiplied by two compared to the default + case where the algorithm is disabled. This technique allows the + cancellation of the ADC offset error and the achievement of + ultra-low offset without any digital calibration. The resulting + offset is the residue of the difference between the two + conversions, which is on the order of magnitude of the noise + floor. This offset is effectively canceled at every conversion, + so the residual offset error temperature drift is extremely low. + Write '1' to enable it, write '0' to disable it. + +What: /sys/bus/iio/devices/iio:deviceX/auto_zeroing_ref_enable +KernelVersion: 6.4 +Contact: linux-iio@vger.kernel.org +Description: + This attribute is used to enable the chopping algorithm for the + internal voltage reference buffer. This setting has no effect + when external voltage reference is selected. + Internal voltage reference buffer injects a certain quantity of + 1/f noise into the system that can be modulated with the + incoming input signals and can limit the SNR performance at + higher Oversampling Ratio values (over 256). To overcome this + limitation, the buffer includes an auto-zeroing algorithm that + greatly reduces (cancels out) the 1/f noise and cancels the + offset value of the reference buffer. As a result, the SNR of + the system is not affected by this 1/f noise component of the + reference buffer, even at maximum oversampling ratio values. + Write '1' to enable it, write '0' to disable it. diff --git a/MAINTAINERS b/MAINTAINERS index 90f13281d297..337a4244ee30 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -14019,6 +14019,13 @@ S: Supported F: Documentation/devicetree/bindings/regulator/mcp16502-regulator.txt F: drivers/regulator/mcp16502.c +MICROCHIP MCP3564 ADC DRIVER +M: Marius Cristea +L: linux-iio@vger.kernel.org +S: Supported +F: Documentation/devicetree/bindings/iio/adc/microchip,mcp3564.yaml +F: drivers/iio/adc/mcp3564.c + MICROCHIP MCP3911 ADC DRIVER M: Marcus Folkesson M: Kent Gustavsson diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig index bb3786745ab6..35f9867da12c 100644 --- a/drivers/iio/adc/Kconfig +++ b/drivers/iio/adc/Kconfig @@ -789,6 +789,19 @@ config MCP3422 This driver can also be built as a module. If so, the module will be called mcp3422. +config MCP3564 + tristate "Microchip Technology MCP3461/2/4/R, MCP3561/2/4/R driver" + depends on SPI + depends on IIO + help + Say yes here to build support for Microchip Technology's MCP3461, + MCP3462, MCP3464, MCP3461R, MCP3462R, MCP3464R, MCP3561, MCP3562, + MCP3564, MCP3561R, MCP3562R and MCP3564R analog to digital + converters. + + This driver can also be built as a module. If so, the module will be + called mcp3564. + config MCP3911 tristate "Microchip Technology MCP3911 driver" depends on SPI diff --git a/drivers/iio/adc/Makefile b/drivers/iio/adc/Makefile index 2d5b2a181380..bee11d442af4 100644 --- a/drivers/iio/adc/Makefile +++ b/drivers/iio/adc/Makefile @@ -72,6 +72,7 @@ obj-$(CONFIG_MAX77541_ADC) += max77541-adc.o obj-$(CONFIG_MAX9611) += max9611.o obj-$(CONFIG_MCP320X) += mcp320x.o obj-$(CONFIG_MCP3422) += mcp3422.o +obj-$(CONFIG_MCP3564) += mcp3564.o obj-$(CONFIG_MCP3911) += mcp3911.o obj-$(CONFIG_MEDIATEK_MT6360_ADC) += mt6360-adc.o obj-$(CONFIG_MEDIATEK_MT6370_ADC) += mt6370-adc.o diff --git a/drivers/iio/adc/mcp3564.c b/drivers/iio/adc/mcp3564.c new file mode 100644 index 000000000000..64145f4ae55c --- /dev/null +++ b/drivers/iio/adc/mcp3564.c @@ -0,0 +1,1516 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * IIO driver for MCP356X/MCP356XR and MCP346X/MCP346XR series ADC chip family + * + * Copyright (C) 2022-2023 Microchip Technology Inc. and its subsidiaries + * + * Author: Marius Cristea + * + * Datasheet for MCP3561, MCP3562, MCP3564 can be found here: + * https://ww1.microchip.com/downloads/aemDocuments/documents/MSLD/ProductDocuments/DataSheets/MCP3561-2-4-Family-Data-Sheet-DS20006181C.pdf + * Datasheet for MCP3561R, MCP3562R, MCP3564R can be found here: + * https://ww1.microchip.com/downloads/aemDocuments/documents/APID/ProductDocuments/DataSheets/MCP3561_2_4R-Data-Sheet-DS200006391C.pdf + * Datasheet for MCP3461, MCP3462, MCP3464 can be found here: + * https://ww1.microchip.com/downloads/aemDocuments/documents/APID/ProductDocuments/DataSheets/MCP3461-2-4-Two-Four-Eight-Channel-153.6-ksps-Low-Noise-16-Bit-Delta-Sigma-ADC-Data-Sheet-20006180D.pdf + * Datasheet for MCP3461R, MCP3462R, MCP3464R can be found here: + * https://ww1.microchip.com/downloads/aemDocuments/documents/APID/ProductDocuments/DataSheets/MCP3461-2-4R-Family-Data-Sheet-DS20006404C.pdf + */ + +#include +#include +#include +#include +#include +#include + +#include +#include + +#define MCP3564_ADCDATA_REG 0x00 + +#define MCP3564_CONFIG0_REG 0x01 +#define MCP3564_CONFIG0_ADC_MODE_MASK GENMASK(1, 0) +/* Current Source/Sink Selection Bits for Sensor Bias */ +#define MCP3564_CONFIG0_CS_SEL_MASK GENMASK(3, 2) +/* Internal clock is selected and AMCLK is present on the analog master clock output pin */ +#define MCP3564_CONFIG0_USE_INT_CLK_OUTPUT_EN 0x03 +/* Internal clock is selected and no clock output is present on the CLK pin */ +#define MCP3564_CONFIG0_USE_INT_CLK 0x02 +/* External digital clock */ +#define MCP3564_CONFIG0_USE_EXT_CLK 0x01 +/* External digital clock (default) */ +#define MCP3564_CONFIG0_USE_EXT_CLK_DEFAULT 0x00 +#define MCP3564_CONFIG0_CLK_SEL_MASK GENMASK(5, 4) +#define MCP3456_CONFIG0_BIT6_DEFAULT BIT(6) +#define MCP3456_CONFIG0_VREF_MASK BIT(7) + +#define MCP3564_CONFIG1_REG 0x02 +#define MCP3564_CONFIG1_OVERSPL_RATIO_MASK GENMASK(5, 2) + +#define MCP3564_CONFIG2_REG 0x03 +#define MCP3564_CONFIG2_AZ_REF_MASK BIT(1) +#define MCP3564_CONFIG2_AZ_MUX_MASK BIT(2) + +#define MCP3564_CONFIG2_HARDWARE_GAIN_MASK GENMASK(5, 3) +#define MCP3564_DEFAULT_HARDWARE_GAIN 0x01 +#define MCP3564_CONFIG2_BOOST_CURRENT_MASK GENMASK(7, 6) + +#define MCP3564_CONFIG3_REG 0x04 +#define MCP3464_CONFIG3_EN_GAINCAL_MASK BIT(0) +#define MCP3464_CONFIG3_EN_OFFCAL_MASK BIT(1) +#define MCP3464_CONFIG3_EN_CRCCOM_MASK BIT(2) +#define MCP3464_CONFIG3_CRC_FORMAT_MASK BIT(3) +/* + * ADC Output Data Format 32-bit (25-bit right justified data + Channel ID): + * CHID[3:0] + SGN extension (4 bits) + 24-bit ADC data. + * It allows overrange with the SGN extension. + */ +#define MCP3464_CONFIG3_DATA_FMT_32B_WITH_CH_ID 3 +/* + * ADC Output Data Format 32-bit (25-bit right justified data): + * SGN extension (8-bit) + 24-bit ADC data. + * It allows overrange with the SGN extension. + */ +#define MCP3464_CONFIG3_DATA_FMT_32B_SGN_EXT 2 +/* + * ADC Output Data Format 32-bit (24-bit left justified data): + * 24-bit ADC data + 0x00 (8-bit). + * It does not allow overrange (ADC code locked to 0xFFFFFF or 0x800000). + */ +#define MCP3464_CONFIG3_DATA_FMT_32B_LEFT_JUSTIFIED 1 +/* + * ADC Output Data Format 24-bit (default ADC coding): + * 24-bit ADC data. + * It does not allow overrange (ADC code locked to 0xFFFFFF or 0x800000). + */ +#define MCP3464_CONFIG3_DATA_FMT_24B 0 +#define MCP3464_CONFIG3_DATA_FORMAT_MASK GENMASK(5, 4) + +/* Continuous Conversion mode or continuous conversion cycle in SCAN mode. */ +#define MCP3464_CONFIG3_CONV_MODE_CONTINUOUS 3 +/* + * One-shot conversion or one-shot cycle in SCAN mode. It sets ADC_MODE[1:0] to ‘10’ + * (standby) at the end of the conversion or at the end of the conversion cycle in SCAN mode. + */ +#define MCP3464_CONFIG3_CONV_MODE_ONE_SHOT_STANDBY 2 +/* + * One-shot conversion or one-shot cycle in SCAN mode. It sets ADC_MODE[1:0] to ‘0x’ (ADC + * Shutdown) at the end of the conversion or at the end of the conversion cycle in SCAN + * mode (default). + */ +#define MCP3464_CONFIG3_CONV_MODE_ONE_SHOT_SHUTDOWN 0 +#define MCP3464_CONFIG3_CONV_MODE_MASK GENMASK(7, 6) + +#define MCP3564_IRQ_REG 0x05 +#define MCP3464_EN_STP_MASK BIT(0) +#define MCP3464_EN_FASTCMD_MASK BIT(1) +#define MCP3464_IRQ_MODE_0_MASK BIT(2) +#define MCP3464_IRQ_MODE_1_MASK BIT(3) +#define MCP3564_POR_STATUS_MASK BIT(4) +#define MCP3564_CRCCFG_STATUS_MASK BIT(5) +#define MCP3564_DATA_READY_MASK BIT(6) + +#define MCP3564_MUX_REG 0x06 +#define MCP3564_MUX_VIN_P_MASK GENMASK(7, 4) +#define MCP3564_MUX_VIN_N_MASK GENMASK(3, 0) +#define MCP3564_MUX_SET(x, y) (FIELD_PREP(MCP3564_MUX_VIN_P_MASK, (x)) | \ + FIELD_PREP(MCP3564_MUX_VIN_N_MASK, (y))) + +#define MCP3564_SCAN_REG 0x07 +#define MCP3564_SCAN_CH_SEL_MASK GENMASK(15, 0) +#define MCP3564_SCAN_CH_SEL_SET(x) FIELD_PREP(MCP3564_SCAN_CH_SEL_MASK, (x)) +#define MCP3564_SCAN_DELAY_TIME_MASK GENMASK(23, 21) +#define MCP3564_SCAN_DELAY_TIME_SET(x) FIELD_PREP(MCP3564_SCAN_DELAY_TIME_MASK, (x)) +#define MCP3564_SCAN_DEFAULT_VALUE 0 + +#define MCP3564_TIMER_REG 0x08 +#define MCP3564_TIMER_DEFAULT_VALUE 0 + +#define MCP3564_OFFSETCAL_REG 0x09 +#define MCP3564_DEFAULT_OFFSETCAL 0 + +#define MCP3564_GAINCAL_REG 0x0A +#define MCP3564_DEFAULT_GAINCAL 0x00800000 + +#define MCP3564_RESERVED_B_REG 0x0B + +#define MCP3564_RESERVED_C_REG 0x0C +#define MCP3564_C_REG_DEFAULT 0x50 +#define MCP3564R_C_REG_DEFAULT 0x30 + +#define MCP3564_LOCK_REG 0x0D +#define MCP3564_LOCK_WRITE_ACCESS_PASSWORD 0xA5 +#define MCP3564_RESERVED_E_REG 0x0E +#define MCP3564_CRCCFG_REG 0x0F + +#define MCP3564_CMD_HW_ADDR_MASK GENMASK(7, 6) +#define MCP3564_CMD_ADDR_MASK GENMASK(5, 2) + +#define MCP3564_HW_ADDR_MASK GENMASK(1, 0) + +#define MCP3564_FASTCMD_START 0x0A +#define MCP3564_FASTCMD_RESET 0x0E + +#define MCP3461_HW_ID 0x0008 +#define MCP3462_HW_ID 0x0009 +#define MCP3464_HW_ID 0x000B + +#define MCP3561_HW_ID 0x000C +#define MCP3562_HW_ID 0x000D +#define MCP3564_HW_ID 0x000F +#define MCP3564_HW_ID_MASK GENMASK(3, 0) + +#define MCP3564R_INT_VREF_MV 2400 + +#define MCP3564_DATA_READY_TIMEOUT_MS 2000 + +#define MCP3564_MAX_PGA 8 +#define MCP3564_MAX_BURNOUT_IDX 4 +#define MCP3564_MAX_CHANNELS 66 + +enum mcp3564_ids { + mcp3461, + mcp3462, + mcp3464, + mcp3561, + mcp3562, + mcp3564, + mcp3461r, + mcp3462r, + mcp3464r, + mcp3561r, + mcp3562r, + mcp3564r, +}; + +enum mcp3564_delay_time { + MCP3564_NO_DELAY, + MCP3564_DELAY_8_DMCLK, + MCP3564_DELAY_16_DMCLK, + MCP3564_DELAY_32_DMCLK, + MCP3564_DELAY_64_DMCLK, + MCP3564_DELAY_128_DMCLK, + MCP3564_DELAY_256_DMCLK, + MCP3564_DELAY_512_DMCLK +}; + +enum mcp3564_adc_conversion_mode { + MCP3564_ADC_MODE_DEFAULT, + MCP3564_ADC_MODE_SHUTDOWN, + MCP3564_ADC_MODE_STANDBY, + MCP3564_ADC_MODE_CONVERSION +}; + +enum mcp3564_adc_bias_current { + MCP3564_BOOST_CURRENT_x0_50, + MCP3564_BOOST_CURRENT_x0_66, + MCP3564_BOOST_CURRENT_x1_00, + MCP3564_BOOST_CURRENT_x2_00 +}; + +enum mcp3564_burnout { + MCP3564_CONFIG0_CS_SEL_0_0_uA, + MCP3564_CONFIG0_CS_SEL_0_9_uA, + MCP3564_CONFIG0_CS_SEL_3_7_uA, + MCP3564_CONFIG0_CS_SEL_15_uA +}; + +enum mcp3564_channel_names { + MCP3564_CH0, + MCP3564_CH1, + MCP3564_CH2, + MCP3564_CH3, + MCP3564_CH4, + MCP3564_CH5, + MCP3564_CH6, + MCP3564_CH7, + MCP3564_AGND, + MCP3564_AVDD, + MCP3564_RESERVED, /* do not use */ + MCP3564_REFIN_POZ, + MCP3564_REFIN_NEG, + MCP3564_TEMP_DIODE_P, + MCP3564_TEMP_DIODE_M, + MCP3564_INTERNAL_VCM, +}; + +enum mcp3564_oversampling { + MCP3564_OVERSAMPLING_RATIO_32, + MCP3564_OVERSAMPLING_RATIO_64, + MCP3564_OVERSAMPLING_RATIO_128, + MCP3564_OVERSAMPLING_RATIO_256, + MCP3564_OVERSAMPLING_RATIO_512, + MCP3564_OVERSAMPLING_RATIO_1024, + MCP3564_OVERSAMPLING_RATIO_2048, + MCP3564_OVERSAMPLING_RATIO_4096, + MCP3564_OVERSAMPLING_RATIO_8192, + MCP3564_OVERSAMPLING_RATIO_16384, + MCP3564_OVERSAMPLING_RATIO_20480, + MCP3564_OVERSAMPLING_RATIO_24576, + MCP3564_OVERSAMPLING_RATIO_40960, + MCP3564_OVERSAMPLING_RATIO_49152, + MCP3564_OVERSAMPLING_RATIO_81920, + MCP3564_OVERSAMPLING_RATIO_98304 +}; + +static const unsigned int mcp3564_oversampling_avail[] = { + [MCP3564_OVERSAMPLING_RATIO_32] = 32, + [MCP3564_OVERSAMPLING_RATIO_64] = 64, + [MCP3564_OVERSAMPLING_RATIO_128] = 128, + [MCP3564_OVERSAMPLING_RATIO_256] = 256, + [MCP3564_OVERSAMPLING_RATIO_512] = 512, + [MCP3564_OVERSAMPLING_RATIO_1024] = 1024, + [MCP3564_OVERSAMPLING_RATIO_2048] = 2048, + [MCP3564_OVERSAMPLING_RATIO_4096] = 4096, + [MCP3564_OVERSAMPLING_RATIO_8192] = 8192, + [MCP3564_OVERSAMPLING_RATIO_16384] = 16384, + [MCP3564_OVERSAMPLING_RATIO_20480] = 20480, + [MCP3564_OVERSAMPLING_RATIO_24576] = 24576, + [MCP3564_OVERSAMPLING_RATIO_40960] = 40960, + [MCP3564_OVERSAMPLING_RATIO_49152] = 49152, + [MCP3564_OVERSAMPLING_RATIO_81920] = 81920, + [MCP3564_OVERSAMPLING_RATIO_98304] = 98304 +}; + +/* + * Current Source/Sink Selection Bits for Sensor Bias (source on VIN+/sink on VIN-) + */ +static const int mcp3564_burnout_avail[][2] = { + [MCP3564_CONFIG0_CS_SEL_0_0_uA] = { 0, 0 }, + [MCP3564_CONFIG0_CS_SEL_0_9_uA] = { 0, 900 }, + [MCP3564_CONFIG0_CS_SEL_3_7_uA] = { 0, 3700 }, + [MCP3564_CONFIG0_CS_SEL_15_uA] = { 0, 15000 } +}; + +/* + * BOOST[1:0]: ADC Bias Current Selection + */ +static const char * const mcp3564_boost_current_avail[] = { + [MCP3564_BOOST_CURRENT_x0_50] = "0.5", + [MCP3564_BOOST_CURRENT_x0_66] = "0.66", + [MCP3564_BOOST_CURRENT_x1_00] = "1", + [MCP3564_BOOST_CURRENT_x2_00] = "2", +}; + +/* + * Calibration bias values + */ +static const int mcp3564_calib_bias[] = { + -8388608, /* min: -2^23 */ + 1, /* step: 1 */ + 8388607 /* max: 2^23 - 1 */ +}; + +/* + * Calibration scale values + * The Gain Error Calibration register (GAINCAL) is an + * unsigned 24-bit register that holds the digital gain error + * calibration value, GAINCAL which could be calculated by + * GAINCAL (V/V) = (GAINCAL[23:0])/8388608 + * The gain error calibration value range in equivalent voltage is [0; 2-2^(-23)] + */ +static const unsigned int mcp3564_calib_scale[] = { + 0, /* min: 0 */ + 1, /* step: 1/8388608 */ + 16777215 /* max: 2 - 2^(-23) */ +}; + +/* Programmable hardware gain x1/3, x1, x2, x4, x8, x16, x32, x64 */ +static const int mcp3564_hwgain_frac[] = { + 3, 10, + 1, 1, + 2, 1, + 4, 1, + 8, 1, + 16, 1, + 32, 1, + 64, 1 +}; + +static const char *mcp3564_channel_labels[2] = { + "burnout_current", "temperature", +}; + +/** + * struct mcp3564_chip_info - chip specific data + * @name: device name + * @num_channels: number of channels + * @resolution: ADC resolution + * @have_vref: does the hardware have an internal voltage reference? + */ +struct mcp3564_chip_info { + const char *name; + unsigned int num_channels; + unsigned int resolution; + bool have_vref; +}; + +/** + * struct mcp3564_state - working data for a ADC device + * @chip_info: chip specific data + * @spi: SPI device structure + * @vref: the regulator device used as a voltage reference in case + * external voltage reference is used + * @vref_mv: voltage reference value in miliVolts + * @lock: synchronize access to driver's state members + * @dev_addr: hardware device address + * @oversampling: the index inside oversampling list of the ADC + * @hwgain: the index inside hardware gain list of the ADC + * @scale_tbls: table with precalculated scale + * @calib_bias: calibration bias value + * @calib_scale: calibration scale value + * @current_boost_mode: the index inside current boost list of the ADC + * @burnout_mode: the index inside current bias list of the ADC + * @auto_zeroing_mux: set if ADC auto-zeroing algorithm is enabled + * @auto_zeroing_ref: set if ADC auto-Zeroing Reference Buffer Setting is enabled + * @have_vref: does the ADC have an internal voltage reference? + * @labels: table with channels labels + */ +struct mcp3564_state { + const struct mcp3564_chip_info *chip_info; + struct spi_device *spi; + struct regulator *vref; + unsigned short vref_mv; + struct mutex lock; /* Synchronize access to driver's state members */ + u8 dev_addr; + enum mcp3564_oversampling oversampling; + unsigned int hwgain; + unsigned int scale_tbls[MCP3564_MAX_PGA][2]; + int calib_bias; + int calib_scale; + unsigned int current_boost_mode; + enum mcp3564_burnout burnout_mode; + bool auto_zeroing_mux; + bool auto_zeroing_ref; + bool have_vref; + const char *labels[MCP3564_MAX_CHANNELS]; +}; + +static inline u8 mcp3564_cmd_write(u8 chip_addr, u8 reg) +{ + return FIELD_PREP(MCP3564_CMD_HW_ADDR_MASK, chip_addr) | + FIELD_PREP(MCP3564_CMD_ADDR_MASK, reg) | + BIT(1); +} + +static inline u8 mcp3564_cmd_read(u8 chip_addr, u8 reg) +{ + return FIELD_PREP(MCP3564_CMD_HW_ADDR_MASK, chip_addr) | + FIELD_PREP(MCP3564_CMD_ADDR_MASK, reg) | + BIT(0); +} + +static int mcp3564_read_8bits(struct mcp3564_state *adc, u8 reg, u8 *val) +{ + int ret; + u8 tx_buf; + u8 rx_buf; + + tx_buf = mcp3564_cmd_read(adc->dev_addr, reg); + + ret = spi_write_then_read(adc->spi, &tx_buf, sizeof(tx_buf), + &rx_buf, sizeof(rx_buf)); + *val = rx_buf; + + return ret; +} + +static int mcp3564_read_16bits(struct mcp3564_state *adc, u8 reg, u16 *val) +{ + int ret; + u8 tx_buf; + __be16 rx_buf; + + tx_buf = mcp3564_cmd_read(adc->dev_addr, reg); + + ret = spi_write_then_read(adc->spi, &tx_buf, sizeof(tx_buf), + &rx_buf, sizeof(rx_buf)); + *val = be16_to_cpu(rx_buf); + + return ret; +} + +static int mcp3564_read_32bits(struct mcp3564_state *adc, u8 reg, u32 *val) +{ + int ret; + u8 tx_buf; + __be32 rx_buf; + + tx_buf = mcp3564_cmd_read(adc->dev_addr, reg); + + ret = spi_write_then_read(adc->spi, &tx_buf, sizeof(tx_buf), + &rx_buf, sizeof(rx_buf)); + *val = be32_to_cpu(rx_buf); + + return ret; +} + +static int mcp3564_write_8bits(struct mcp3564_state *adc, u8 reg, u8 val) +{ + u8 tx_buf[2]; + + tx_buf[0] = mcp3564_cmd_write(adc->dev_addr, reg); + tx_buf[1] = val; + + return spi_write_then_read(adc->spi, tx_buf, sizeof(tx_buf), NULL, 0); +} + +static int mcp3564_write_24bits(struct mcp3564_state *adc, u8 reg, u32 val) +{ + __be32 val_be; + + val |= (mcp3564_cmd_write(adc->dev_addr, reg) << 24); + val_be = cpu_to_be32(val); + + return spi_write_then_read(adc->spi, &val_be, sizeof(val_be), NULL, 0); +} + +static int mcp3564_fast_cmd(struct mcp3564_state *adc, u8 fast_cmd) +{ + u8 val; + + val = FIELD_PREP(MCP3564_CMD_HW_ADDR_MASK, adc->dev_addr) | + FIELD_PREP(MCP3564_CMD_ADDR_MASK, fast_cmd); + + return spi_write_then_read(adc->spi, &val, 1, NULL, 0); +} + +static int mcp3564_update_8bits(struct mcp3564_state *adc, u8 reg, u32 mask, u8 val) +{ + u8 tmp; + int ret; + + val &= mask; + + ret = mcp3564_read_8bits(adc, reg, &tmp); + if (ret < 0) + return ret; + + tmp &= ~mask; + tmp |= val; + + return mcp3564_write_8bits(adc, reg, tmp); +} + +static int mcp3564_set_current_boost_mode(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, + unsigned int mode) +{ + struct mcp3564_state *adc = iio_priv(indio_dev); + int ret; + + dev_dbg(&indio_dev->dev, "%s: %d\n", __func__, mode); + + mutex_lock(&adc->lock); + ret = mcp3564_update_8bits(adc, MCP3564_CONFIG2_REG, MCP3564_CONFIG2_BOOST_CURRENT_MASK, + FIELD_PREP(MCP3564_CONFIG2_BOOST_CURRENT_MASK, mode)); + + if (ret) + dev_err(&indio_dev->dev, "Failed to configure CONFIG2 register\n"); + else + adc->current_boost_mode = mode; + + mutex_unlock(&adc->lock); + + return ret; +} + +static int mcp3564_get_current_boost_mode(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan) +{ + struct mcp3564_state *adc = iio_priv(indio_dev); + + return adc->current_boost_mode; +} + +static const struct iio_enum mcp3564_current_boost_mode_enum = { + .items = mcp3564_boost_current_avail, + .num_items = ARRAY_SIZE(mcp3564_boost_current_avail), + .set = mcp3564_set_current_boost_mode, + .get = mcp3564_get_current_boost_mode, +}; + +static const struct iio_chan_spec_ext_info mcp3564_ext_info[] = { + IIO_ENUM("boost_current_gain", IIO_SHARED_BY_ALL, &mcp3564_current_boost_mode_enum), + { + .name = "boost_current_gain_available", + .shared = IIO_SHARED_BY_ALL, + .read = iio_enum_available_read, + .private = (uintptr_t)&mcp3564_current_boost_mode_enum, + }, + { } +}; + +static ssize_t mcp3564_auto_zeroing_mux_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct iio_dev *indio_dev = dev_to_iio_dev(dev); + struct mcp3564_state *adc = iio_priv(indio_dev); + + return sysfs_emit(buf, "%d\n", adc->auto_zeroing_mux); +} + +static ssize_t mcp3564_auto_zeroing_mux_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t len) +{ + struct iio_dev *indio_dev = dev_to_iio_dev(dev); + struct mcp3564_state *adc = iio_priv(indio_dev); + bool auto_zero; + int ret; + + ret = kstrtobool(buf, &auto_zero); + if (ret) + return ret; + + mutex_lock(&adc->lock); + ret = mcp3564_update_8bits(adc, MCP3564_CONFIG2_REG, MCP3564_CONFIG2_AZ_MUX_MASK, + FIELD_PREP(MCP3564_CONFIG2_AZ_MUX_MASK, auto_zero)); + + if (ret) + dev_err(&indio_dev->dev, "Failed to update CONFIG2 register\n"); + else + adc->auto_zeroing_mux = auto_zero; + + mutex_unlock(&adc->lock); + + return ret ? ret : len; +} + +static ssize_t mcp3564_auto_zeroing_ref_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct iio_dev *indio_dev = dev_to_iio_dev(dev); + struct mcp3564_state *adc = iio_priv(indio_dev); + + return sysfs_emit(buf, "%d\n", adc->auto_zeroing_ref); +} + +static ssize_t mcp3564_auto_zeroing_ref_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t len) +{ + struct iio_dev *indio_dev = dev_to_iio_dev(dev); + struct mcp3564_state *adc = iio_priv(indio_dev); + bool auto_zero; + int ret; + + ret = kstrtobool(buf, &auto_zero); + if (ret) + return ret; + + mutex_lock(&adc->lock); + ret = mcp3564_update_8bits(adc, MCP3564_CONFIG2_REG, MCP3564_CONFIG2_AZ_REF_MASK, + FIELD_PREP(MCP3564_CONFIG2_AZ_REF_MASK, auto_zero)); + + if (ret) + dev_err(&indio_dev->dev, "Failed to update CONFIG2 register\n"); + else + adc->auto_zeroing_ref = auto_zero; + + mutex_unlock(&adc->lock); + + return ret ? ret : len; +} + +static const struct iio_chan_spec mcp3564_channel_template = { + .type = IIO_VOLTAGE, + .indexed = 1, + .differential = 1, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), + .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SCALE) | + BIT(IIO_CHAN_INFO_CALIBSCALE) | + BIT(IIO_CHAN_INFO_CALIBBIAS) | + BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), + .info_mask_shared_by_all_available = BIT(IIO_CHAN_INFO_SCALE) | + BIT(IIO_CHAN_INFO_CALIBSCALE) | + BIT(IIO_CHAN_INFO_CALIBBIAS) | + BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), + .ext_info = mcp3564_ext_info, +}; + +static const struct iio_chan_spec mcp3564_temp_channel_template = { + .type = IIO_TEMP, + .channel = 0, + .address = ((MCP3564_TEMP_DIODE_P << 4) | MCP3564_TEMP_DIODE_M), + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), + .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SCALE) | + BIT(IIO_CHAN_INFO_CALIBSCALE) | + BIT(IIO_CHAN_INFO_CALIBBIAS) | + BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), + .info_mask_shared_by_all_available = BIT(IIO_CHAN_INFO_SCALE) | + BIT(IIO_CHAN_INFO_CALIBSCALE) | + BIT(IIO_CHAN_INFO_CALIBBIAS) | + BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), +}; + +static const struct iio_chan_spec mcp3564_burnout_channel_template = { + .type = IIO_CURRENT, + .output = true, + .channel = 0, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), + .info_mask_separate_available = BIT(IIO_CHAN_INFO_RAW), +}; + +/* + * Number of channels could be calculated: + * num_channels = single_ended_input + differential_input + temperature + burnout + * Eg. for MCP3561 (only 2 channels available: CH0 and CH1) + * single_ended_input = (CH0 - GND), (CH1 - GND) = 2 + * differential_input = (CH0 - CH1), (CH0 - CH0) = 2 + * num_channels = 2 + 2 + 2 + * Generic formula is: + * num_channels = P^R(Number_of_single_ended_channels, 2) + 2 (temperature + burnout channels) + * P^R(Number_of_single_ended_channels, 2) is Permutations with Replacement of + * Number_of_single_ended_channels taken by 2 + */ +static const struct mcp3564_chip_info mcp3564_chip_infos_tbl[] = { + [mcp3461] = { + .name = "mcp3461", + .num_channels = 6, + .resolution = 16, + .have_vref = false, + }, + [mcp3462] = { + .name = "mcp3462", + .num_channels = 18, + .resolution = 16, + .have_vref = false, + }, + [mcp3464] = { + .name = "mcp3464", + .num_channels = 66, + .resolution = 16, + .have_vref = false, + }, + [mcp3561] = { + .name = "mcp3561", + .num_channels = 6, + .resolution = 24, + .have_vref = false, + }, + [mcp3562] = { + .name = "mcp3562", + .num_channels = 18, + .resolution = 24, + .have_vref = false, + }, + [mcp3564] = { + .name = "mcp3564", + .num_channels = 66, + .resolution = 24, + .have_vref = false, + }, + [mcp3461r] = { + .name = "mcp3461r", + .num_channels = 6, + .resolution = 16, + .have_vref = false, + }, + [mcp3462r] = { + .name = "mcp3462r", + .num_channels = 18, + .resolution = 16, + .have_vref = true, + }, + [mcp3464r] = { + .name = "mcp3464r", + .num_channels = 66, + .resolution = 16, + .have_vref = true, + }, + [mcp3561r] = { + .name = "mcp3561r", + .num_channels = 6, + .resolution = 24, + .have_vref = true, + }, + [mcp3562r] = { + .name = "mcp3562r", + .num_channels = 18, + .resolution = 24, + .have_vref = true, + }, + [mcp3564r] = { + .name = "mcp3564r", + .num_channels = 66, + .resolution = 24, + .have_vref = true, + }, +}; + +static int mcp3564_read_single_value(struct iio_dev *indio_dev, + struct iio_chan_spec const *channel, + int *val) +{ + struct mcp3564_state *adc = iio_priv(indio_dev); + int ret; + u8 tmp; + int ret_read = 0; + + ret = mcp3564_write_8bits(adc, MCP3564_MUX_REG, channel->address); + if (ret) + return ret; + + /* Start ADC Conversion using fast command (overwrites ADC_MODE[1:0] = 11) */ + ret = mcp3564_fast_cmd(adc, MCP3564_FASTCMD_START); + if (ret) + return ret; + + /* + * Check if the conversion is ready. If not, wait a little bit, and + * in case of timeout exit with an error. + */ + ret = read_poll_timeout(mcp3564_read_8bits, ret_read, + ret_read || !(tmp & MCP3564_DATA_READY_MASK), + 20000, MCP3564_DATA_READY_TIMEOUT_MS * 1000, true, + adc, MCP3564_IRQ_REG, &tmp); + + /* failed to read status register */ + if (ret_read) + return ret_read; + + if (ret) + return ret; + + if (tmp & MCP3564_DATA_READY_MASK) + /* failing to finish conversion */ + return -EBUSY; + + return mcp3564_read_32bits(adc, MCP3564_ADCDATA_REG, val); +} + +static int mcp3564_read_avail(struct iio_dev *indio_dev, + struct iio_chan_spec const *channel, + const int **vals, int *type, + int *length, long mask) +{ + struct mcp3564_state *adc = iio_priv(indio_dev); + + switch (mask) { + case IIO_CHAN_INFO_RAW: + if (!channel->output) + return -EINVAL; + + *vals = mcp3564_burnout_avail[0]; + *length = ARRAY_SIZE(mcp3564_burnout_avail) * 2; + *type = IIO_VAL_INT_PLUS_MICRO; + return IIO_AVAIL_LIST; + case IIO_CHAN_INFO_OVERSAMPLING_RATIO: + *vals = mcp3564_oversampling_avail; + *length = ARRAY_SIZE(mcp3564_oversampling_avail); + *type = IIO_VAL_INT; + return IIO_AVAIL_LIST; + case IIO_CHAN_INFO_SCALE: + *vals = (int *)adc->scale_tbls; + *length = ARRAY_SIZE(adc->scale_tbls) * 2; + *type = IIO_VAL_INT_PLUS_NANO; + return IIO_AVAIL_LIST; + case IIO_CHAN_INFO_CALIBBIAS: + *vals = mcp3564_calib_bias; + *type = IIO_VAL_INT; + return IIO_AVAIL_RANGE; + case IIO_CHAN_INFO_CALIBSCALE: + *vals = mcp3564_calib_scale; + *type = IIO_VAL_INT; + return IIO_AVAIL_RANGE; + default: + return -EINVAL; + } +} + +static int mcp3564_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *channel, + int *val, int *val2, long mask) +{ + struct mcp3564_state *adc = iio_priv(indio_dev); + int ret; + + switch (mask) { + case IIO_CHAN_INFO_RAW: + if (channel->output) { + mutex_lock(&adc->lock); + *val = mcp3564_burnout_avail[adc->burnout_mode][0]; + *val2 = mcp3564_burnout_avail[adc->burnout_mode][1]; + mutex_unlock(&adc->lock); + return IIO_VAL_INT_PLUS_MICRO; + } + + ret = mcp3564_read_single_value(indio_dev, channel, val); + if (ret) + return -EINVAL; + return IIO_VAL_INT; + case IIO_CHAN_INFO_SCALE: + mutex_lock(&adc->lock); + *val = adc->scale_tbls[adc->hwgain][0]; + *val2 = adc->scale_tbls[adc->hwgain][1]; + mutex_unlock(&adc->lock); + return IIO_VAL_INT_PLUS_NANO; + case IIO_CHAN_INFO_OVERSAMPLING_RATIO: + *val = mcp3564_oversampling_avail[adc->oversampling]; + return IIO_VAL_INT; + case IIO_CHAN_INFO_CALIBBIAS: + *val = adc->calib_bias; + return IIO_VAL_INT; + case IIO_CHAN_INFO_CALIBSCALE: + *val = adc->calib_scale; + return IIO_VAL_INT; + default: + return -EINVAL; + } +} + +static int mcp3564_write_raw_get_fmt(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + long info) +{ + switch (info) { + case IIO_CHAN_INFO_RAW: + return IIO_VAL_INT_PLUS_MICRO; + case IIO_CHAN_INFO_CALIBBIAS: + case IIO_CHAN_INFO_CALIBSCALE: + case IIO_CHAN_INFO_OVERSAMPLING_RATIO: + return IIO_VAL_INT; + case IIO_CHAN_INFO_SCALE: + return IIO_VAL_INT_PLUS_NANO; + default: + return -EINVAL; + } +} + +static int mcp3564_write_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *channel, int val, + int val2, long mask) +{ + struct mcp3564_state *adc = iio_priv(indio_dev); + int tmp; + unsigned int hwgain; + enum mcp3564_burnout burnout; + int ret = 0; + + switch (mask) { + case IIO_CHAN_INFO_RAW: + if (!channel->output) + return -EINVAL; + + for (burnout = 0; burnout < MCP3564_MAX_BURNOUT_IDX; burnout++) + if (val == mcp3564_burnout_avail[burnout][0] && + val2 == mcp3564_burnout_avail[burnout][1]) + break; + + if (burnout == MCP3564_MAX_BURNOUT_IDX) + return -EINVAL; + + if (burnout == adc->burnout_mode) + return ret; + + mutex_lock(&adc->lock); + ret = mcp3564_update_8bits(adc, MCP3564_CONFIG0_REG, + MCP3564_CONFIG0_CS_SEL_MASK, + FIELD_PREP(MCP3564_CONFIG0_CS_SEL_MASK, burnout)); + + if (ret) + dev_err(&indio_dev->dev, "Failed to configure burnout current\n"); + else + adc->burnout_mode = burnout; + mutex_unlock(&adc->lock); + return ret; + case IIO_CHAN_INFO_CALIBBIAS: + if (val < mcp3564_calib_bias[0] && val > mcp3564_calib_bias[2]) + return -EINVAL; + + mutex_lock(&adc->lock); + ret = mcp3564_write_24bits(adc, MCP3564_OFFSETCAL_REG, val); + if (!ret) + adc->calib_bias = val; + mutex_unlock(&adc->lock); + return ret; + case IIO_CHAN_INFO_CALIBSCALE: + if (val < mcp3564_calib_scale[0] && val > mcp3564_calib_scale[2]) + return -EINVAL; + + if (adc->calib_scale == val) + return ret; + + mutex_lock(&adc->lock); + ret = mcp3564_write_24bits(adc, MCP3564_GAINCAL_REG, val); + if (!ret) + adc->calib_scale = val; + mutex_unlock(&adc->lock); + return ret; + case IIO_CHAN_INFO_OVERSAMPLING_RATIO: + if (val < 0) + return -EINVAL; + + tmp = find_closest(val, mcp3564_oversampling_avail, + ARRAY_SIZE(mcp3564_oversampling_avail)); + + if (adc->oversampling == tmp) + return ret; + + mutex_lock(&adc->lock); + ret = mcp3564_update_8bits(adc, MCP3564_CONFIG1_REG, + MCP3564_CONFIG1_OVERSPL_RATIO_MASK, + FIELD_PREP(MCP3564_CONFIG1_OVERSPL_RATIO_MASK, + adc->oversampling)); + if (!ret) + adc->oversampling = tmp; + mutex_unlock(&adc->lock); + return ret; + case IIO_CHAN_INFO_SCALE: + for (hwgain = 0; hwgain < MCP3564_MAX_PGA; hwgain++) + if (val == adc->scale_tbls[hwgain][0] && + val2 == adc->scale_tbls[hwgain][1]) + break; + + if (hwgain == MCP3564_MAX_PGA) + return -EINVAL; + + if (hwgain == adc->hwgain) + return ret; + + mutex_lock(&adc->lock); + ret = mcp3564_update_8bits(adc, MCP3564_CONFIG2_REG, + MCP3564_CONFIG2_HARDWARE_GAIN_MASK, + FIELD_PREP(MCP3564_CONFIG2_HARDWARE_GAIN_MASK, hwgain)); + if (!ret) + adc->hwgain = hwgain; + + mutex_unlock(&adc->lock); + return ret; + default: + return -EINVAL; + } +} + +static int mcp3564_read_label(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, char *label) +{ + struct mcp3564_state *adc = iio_priv(indio_dev); + + return sprintf(label, "%s\n", adc->labels[chan->scan_index]); +} + +static int mcp3564_parse_fw_children(struct iio_dev *indio_dev) +{ + struct mcp3564_state *adc = iio_priv(indio_dev); + struct device *dev = &adc->spi->dev; + struct iio_chan_spec *channels; + struct fwnode_handle *child; + struct iio_chan_spec chanspec = mcp3564_channel_template; + struct iio_chan_spec temp_chanspec = mcp3564_temp_channel_template; + struct iio_chan_spec burnout_chanspec = mcp3564_burnout_channel_template; + int chan_idx = 0; + unsigned int num_ch; + u32 inputs[2]; + const char *node_name; + const char *label; + int ret; + + num_ch = device_get_child_node_count(dev); + if (num_ch == 0) + return dev_err_probe(&indio_dev->dev, -ENODEV, + "FW has no channels defined\n"); + + /* Reserve space for burnout and temperature channel */ + num_ch += 2; + + if (num_ch > adc->chip_info->num_channels) + return dev_err_probe(dev, -EINVAL, "Too many channels %d > %d\n", + num_ch, adc->chip_info->num_channels); + + channels = devm_kcalloc(dev, num_ch, sizeof(*channels), GFP_KERNEL); + if (!channels) + return dev_err_probe(dev, -ENOMEM, "Can't allocate memory\n"); + + device_for_each_child_node(dev, child) { + node_name = fwnode_get_name(child); + + if (fwnode_property_present(child, "diff-channels")) { + ret = fwnode_property_read_u32_array(child, + "diff-channels", + inputs, + ARRAY_SIZE(inputs)); + chanspec.differential = 1; + } else { + ret = fwnode_property_read_u32(child, "reg", &inputs[0]); + + chanspec.differential = 0; + inputs[1] = MCP3564_AGND; + } + if (ret) { + fwnode_handle_put(child); + return ret; + } + + if (inputs[0] > MCP3564_INTERNAL_VCM || + inputs[1] > MCP3564_INTERNAL_VCM) { + fwnode_handle_put(child); + return dev_err_probe(&indio_dev->dev, -EINVAL, + "Channel index > %d, for %s\n", + MCP3564_INTERNAL_VCM + 1, + node_name); + } + + chanspec.address = (inputs[0] << 4) | inputs[1]; + chanspec.channel = inputs[0]; + chanspec.channel2 = inputs[1]; + chanspec.scan_index = chan_idx; + + if (fwnode_property_present(child, "label")) { + fwnode_property_read_string(child, "label", &label); + adc->labels[chan_idx] = label; + } + + channels[chan_idx] = chanspec; + chan_idx++; + } + + /* Add burnout current channel */ + burnout_chanspec.scan_index = chan_idx; + channels[chan_idx] = burnout_chanspec; + adc->labels[chan_idx] = mcp3564_channel_labels[0]; + chanspec.scan_index = chan_idx; + chan_idx++; + + /* Add temperature channel */ + temp_chanspec.scan_index = chan_idx; + channels[chan_idx] = temp_chanspec; + adc->labels[chan_idx] = mcp3564_channel_labels[1]; + chan_idx++; + + indio_dev->num_channels = chan_idx; + indio_dev->channels = channels; + + return 0; +} + +static void mcp3564_disable_reg(void *reg) +{ + regulator_disable(reg); +} + +static void mcp3564_fill_scale_tbls(struct mcp3564_state *adc) +{ + unsigned int pow = adc->chip_info->resolution - 1; + int ref; + unsigned int i; + int tmp0; + u64 tmp1; + + for (i = 0; i < MCP3564_MAX_PGA; i++) { + ref = adc->vref_mv; + tmp1 = shift_right((u64)ref * NANO, pow); + div_u64_rem(tmp1, NANO, &tmp0); + + tmp1 = tmp1 * mcp3564_hwgain_frac[(2 * i) + 1]; + tmp0 = (int)div_u64(tmp1, mcp3564_hwgain_frac[2 * i]); + + adc->scale_tbls[i][1] = tmp0; + } +} + +static int mcp3564_config(struct iio_dev *indio_dev) +{ + struct mcp3564_state *adc = iio_priv(indio_dev); + struct device *dev = &adc->spi->dev; + const struct spi_device_id *dev_id; + u8 tmp_reg; + u16 tmp_u16; + enum mcp3564_ids ids; + int ret = 0; + unsigned int tmp = 0x01; + bool err = true; + + /* + * The address is set on a per-device basis by fuses in the factory, + * configured on request. If not requested, the fuses are set for 0x1. + * The device address is part of the device markings to avoid + * potential confusion. This address is coded on two bits, so four possible + * addresses are available when multiple devices are present on the same + * SPI bus with only one Chip Select line for all devices. + */ + device_property_read_u32(dev, "microchip,hw-device-address", &tmp); + + if (tmp > 3) { + dev_err_probe(dev, tmp, + "invalid device address. Must be in range 0-3.\n"); + return -EINVAL; + } + + adc->dev_addr = FIELD_GET(MCP3564_HW_ADDR_MASK, tmp); + + dev_dbg(dev, "use HW device address %i\n", adc->dev_addr); + + ret = mcp3564_read_8bits(adc, MCP3564_RESERVED_C_REG, &tmp_reg); + if (ret < 0) + return ret; + + switch (tmp_reg) { + case MCP3564_C_REG_DEFAULT: + adc->have_vref = false; + break; + case MCP3564R_C_REG_DEFAULT: + adc->have_vref = true; + break; + default: + dev_info(dev, "Unknown chip found: %d\n", tmp_reg); + err = true; + } + + if (!err) { + ret = mcp3564_read_16bits(adc, MCP3564_RESERVED_E_REG, &tmp_u16); + if (ret < 0) + return ret; + + switch (tmp_u16 & MCP3564_HW_ID_MASK) { + case MCP3461_HW_ID: + if (adc->have_vref) + ids = mcp3461r; + else + ids = mcp3461; + break; + case MCP3462_HW_ID: + if (adc->have_vref) + ids = mcp3462r; + else + ids = mcp3462; + break; + case MCP3464_HW_ID: + if (adc->have_vref) + ids = mcp3464r; + else + ids = mcp3464; + break; + case MCP3561_HW_ID: + if (adc->have_vref) + ids = mcp3561r; + else + ids = mcp3561; + break; + case MCP3562_HW_ID: + if (adc->have_vref) + ids = mcp3562r; + else + ids = mcp3562; + break; + case MCP3564_HW_ID: + if (adc->have_vref) + ids = mcp3564r; + else + ids = mcp3564; + break; + default: + dev_info(dev, "Unknown chip found: %d\n", tmp_u16); + err = true; + } + } + + if (err) { + /* + * If failed to identify the hardware based on internal registers, + * try using fallback compatible in device tree to deal with some newer part number. + */ + adc->chip_info = spi_get_device_match_data(adc->spi); + if (!adc->chip_info) { + dev_id = spi_get_device_id(adc->spi); + adc->chip_info = (const struct mcp3564_chip_info *)dev_id->driver_data; + } + + adc->have_vref = adc->chip_info->have_vref; + } else { + adc->chip_info = &mcp3564_chip_infos_tbl[ids]; + } + + dev_dbg(dev, "Found %s chip\n", adc->chip_info->name); + + adc->vref = devm_regulator_get_optional(dev, "vref"); + if (IS_ERR(adc->vref)) { + if (PTR_ERR(adc->vref) != -ENODEV) + return dev_err_probe(dev, PTR_ERR(adc->vref), + "failed to get regulator\n"); + + /* Check if chip has internal vref */ + if (!adc->have_vref) + return dev_err_probe(dev, PTR_ERR(adc->vref), + "Unknown Vref\n"); + adc->vref = NULL; + dev_dbg(dev, "%s: Using internal Vref\n", __func__); + } else { + ret = regulator_enable(adc->vref); + if (ret) + return ret; + + ret = devm_add_action_or_reset(dev, mcp3564_disable_reg, + adc->vref); + if (ret) + return ret; + + dev_dbg(dev, "%s: Using External Vref\n", __func__); + + ret = regulator_get_voltage(adc->vref); + if (ret < 0) + return dev_err_probe(dev, ret, + "Failed to read vref regulator\n"); + + adc->vref_mv = ret / MILLI; + } + + ret = mcp3564_parse_fw_children(indio_dev); + if (ret) + return ret; + + /* + * Command sequence that ensures a recovery with the desired settings + * in any cases of loss-of-power scenario (Full Chip Reset): + * - Write LOCK register to 0xA5 + * - Write IRQ register to 0x03 + * - Send "Device Full Reset" fast command + * - Wait 1ms for "Full Reset" to complete + */ + ret = mcp3564_write_8bits(adc, MCP3564_LOCK_REG, MCP3564_LOCK_WRITE_ACCESS_PASSWORD); + if (ret) + return ret; + + ret = mcp3564_write_8bits(adc, MCP3564_IRQ_REG, 0x03); + if (ret) + return ret; + + ret = mcp3564_fast_cmd(adc, MCP3564_FASTCMD_RESET); + if (ret) + return ret; + + /* + * After Full reset wait some time to be able to fully reset the part and place + * it back in a default configuration. + * From datasheet: POR (Power On Reset Time) is ~1us + * 1ms should be enough. + */ + mdelay(1); + + /* set a gain of 1x for GAINCAL */ + ret = mcp3564_write_24bits(adc, MCP3564_GAINCAL_REG, MCP3564_DEFAULT_GAINCAL); + if (ret) + return ret; + + adc->calib_scale = MCP3564_DEFAULT_GAINCAL; + + ret = mcp3564_write_24bits(adc, MCP3564_OFFSETCAL_REG, MCP3564_DEFAULT_OFFSETCAL); + if (ret) + return ret; + + ret = mcp3564_write_24bits(adc, MCP3564_TIMER_REG, MCP3564_TIMER_DEFAULT_VALUE); + if (ret) + return ret; + + ret = mcp3564_write_24bits(adc, MCP3564_SCAN_REG, + MCP3564_SCAN_DELAY_TIME_SET(MCP3564_NO_DELAY) | + MCP3564_SCAN_CH_SEL_SET(MCP3564_SCAN_DEFAULT_VALUE)); + if (ret) + return ret; + + ret = mcp3564_write_8bits(adc, MCP3564_MUX_REG, MCP3564_MUX_SET(MCP3564_CH0, MCP3564_CH1)); + if (ret) + return ret; + + ret = mcp3564_write_8bits(adc, MCP3564_IRQ_REG, + FIELD_PREP(MCP3464_EN_FASTCMD_MASK, 1) | + FIELD_PREP(MCP3464_EN_STP_MASK, 1)); + if (ret) + return ret; + + tmp_reg = FIELD_PREP(MCP3464_CONFIG3_CONV_MODE_MASK, + MCP3464_CONFIG3_CONV_MODE_ONE_SHOT_STANDBY); + tmp_reg |= FIELD_PREP(MCP3464_CONFIG3_DATA_FORMAT_MASK, + MCP3464_CONFIG3_DATA_FMT_32B_SGN_EXT); + tmp_reg |= MCP3464_CONFIG3_EN_OFFCAL_MASK; + tmp_reg |= MCP3464_CONFIG3_EN_GAINCAL_MASK; + + ret = mcp3564_write_8bits(adc, MCP3564_CONFIG3_REG, tmp_reg); + if (ret) + return ret; + + tmp_reg = FIELD_PREP(MCP3564_CONFIG2_BOOST_CURRENT_MASK, MCP3564_BOOST_CURRENT_x1_00); + tmp_reg |= FIELD_PREP(MCP3564_CONFIG2_HARDWARE_GAIN_MASK, 0x01); + tmp_reg |= FIELD_PREP(MCP3564_CONFIG2_AZ_MUX_MASK, 1); + + ret = mcp3564_write_8bits(adc, MCP3564_CONFIG2_REG, tmp_reg); + if (ret) + return ret; + + adc->hwgain = 0x01; + adc->auto_zeroing_mux = true; + adc->auto_zeroing_ref = false; + adc->current_boost_mode = MCP3564_BOOST_CURRENT_x1_00; + + tmp_reg = FIELD_PREP(MCP3564_CONFIG1_OVERSPL_RATIO_MASK, MCP3564_OVERSAMPLING_RATIO_98304); + + ret = mcp3564_write_8bits(adc, MCP3564_CONFIG1_REG, tmp_reg); + if (ret) + return ret; + + adc->oversampling = MCP3564_OVERSAMPLING_RATIO_98304; + + tmp_reg = FIELD_PREP(MCP3564_CONFIG0_ADC_MODE_MASK, MCP3564_ADC_MODE_STANDBY); + tmp_reg |= FIELD_PREP(MCP3564_CONFIG0_CS_SEL_MASK, MCP3564_CONFIG0_CS_SEL_0_0_uA); + tmp_reg |= FIELD_PREP(MCP3564_CONFIG0_CLK_SEL_MASK, MCP3564_CONFIG0_USE_INT_CLK); + tmp_reg |= MCP3456_CONFIG0_BIT6_DEFAULT; + + if (!adc->vref) { + tmp_reg |= FIELD_PREP(MCP3456_CONFIG0_VREF_MASK, 1); + adc->vref_mv = MCP3564R_INT_VREF_MV; + } + + ret = mcp3564_write_8bits(adc, MCP3564_CONFIG0_REG, tmp_reg); + + adc->burnout_mode = MCP3564_CONFIG0_CS_SEL_0_0_uA; + + return ret; +} + +static IIO_DEVICE_ATTR(auto_zeroing_ref_enable, 0644, + mcp3564_auto_zeroing_ref_show, + mcp3564_auto_zeroing_ref_store, 0); + +static IIO_DEVICE_ATTR(auto_zeroing_mux_enable, 0644, + mcp3564_auto_zeroing_mux_show, + mcp3564_auto_zeroing_mux_store, 0); + +static struct attribute *mcp3564_attributes[] = { + &iio_dev_attr_auto_zeroing_mux_enable.dev_attr.attr, + NULL +}; + +static struct attribute *mcp3564r_attributes[] = { + &iio_dev_attr_auto_zeroing_mux_enable.dev_attr.attr, + &iio_dev_attr_auto_zeroing_ref_enable.dev_attr.attr, + NULL +}; + +static struct attribute_group mcp3564_attribute_group = { + .attrs = mcp3564_attributes, +}; + +static struct attribute_group mcp3564r_attribute_group = { + .attrs = mcp3564r_attributes, +}; + +static const struct iio_info mcp3564_info = { + .read_raw = mcp3564_read_raw, + .read_avail = mcp3564_read_avail, + .write_raw = mcp3564_write_raw, + .write_raw_get_fmt = mcp3564_write_raw_get_fmt, + .read_label = mcp3564_read_label, + .attrs = &mcp3564_attribute_group, +}; + +static const struct iio_info mcp3564r_info = { + .read_raw = mcp3564_read_raw, + .read_avail = mcp3564_read_avail, + .write_raw = mcp3564_write_raw, + .write_raw_get_fmt = mcp3564_write_raw_get_fmt, + .read_label = mcp3564_read_label, + .attrs = &mcp3564r_attribute_group, +}; + +static int mcp3564_probe(struct spi_device *spi) +{ + int ret; + struct iio_dev *indio_dev; + struct mcp3564_state *adc; + + indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*adc)); + if (!indio_dev) { + dev_err_probe(&indio_dev->dev, PTR_ERR(indio_dev), + "Can't allocate iio device\n"); + return -ENOMEM; + } + + adc = iio_priv(indio_dev); + adc->spi = spi; + + dev_dbg(&spi->dev, "%s: probe(spi = 0x%p)\n", __func__, spi); + + /* + * Do any chip specific initialization, e.g: + * read/write some registers + * enable/disable certain channels + * change the sampling rate to the requested value + */ + ret = mcp3564_config(indio_dev); + if (ret) + return dev_err_probe(&spi->dev, ret, + "Can't configure MCP356X device\n"); + + dev_dbg(&spi->dev, "%s: Vref (mV): %d\n", __func__, adc->vref_mv); + + mcp3564_fill_scale_tbls(adc); + + indio_dev->name = adc->chip_info->name; + indio_dev->modes = INDIO_DIRECT_MODE; + + if (!adc->vref) + indio_dev->info = &mcp3564r_info; + else + indio_dev->info = &mcp3564_info; + + mutex_init(&adc->lock); + + ret = devm_iio_device_register(&spi->dev, indio_dev); + if (ret) + return dev_err_probe(&spi->dev, ret, + "Can't register IIO device\n"); + + return 0; +} + +static const struct of_device_id mcp3564_dt_ids[] = { + { .compatible = "microchip,mcp3461", .data = &mcp3564_chip_infos_tbl[mcp3461] }, + { .compatible = "microchip,mcp3462", .data = &mcp3564_chip_infos_tbl[mcp3462] }, + { .compatible = "microchip,mcp3464", .data = &mcp3564_chip_infos_tbl[mcp3464] }, + { .compatible = "microchip,mcp3561", .data = &mcp3564_chip_infos_tbl[mcp3561] }, + { .compatible = "microchip,mcp3562", .data = &mcp3564_chip_infos_tbl[mcp3562] }, + { .compatible = "microchip,mcp3564", .data = &mcp3564_chip_infos_tbl[mcp3564] }, + { .compatible = "microchip,mcp3461r", .data = &mcp3564_chip_infos_tbl[mcp3461r] }, + { .compatible = "microchip,mcp3462r", .data = &mcp3564_chip_infos_tbl[mcp3462r] }, + { .compatible = "microchip,mcp3464r", .data = &mcp3564_chip_infos_tbl[mcp3464r] }, + { .compatible = "microchip,mcp3561r", .data = &mcp3564_chip_infos_tbl[mcp3561r] }, + { .compatible = "microchip,mcp3562r", .data = &mcp3564_chip_infos_tbl[mcp3562r] }, + { .compatible = "microchip,mcp3564r", .data = &mcp3564_chip_infos_tbl[mcp3564r] }, + { } +}; +MODULE_DEVICE_TABLE(of, mcp3564_dt_ids); + +static const struct spi_device_id mcp3564_id[] = { + { "mcp3461", (kernel_ulong_t)&mcp3564_chip_infos_tbl[mcp3461] }, + { "mcp3462", (kernel_ulong_t)&mcp3564_chip_infos_tbl[mcp3462] }, + { "mcp3464", (kernel_ulong_t)&mcp3564_chip_infos_tbl[mcp3464] }, + { "mcp3561", (kernel_ulong_t)&mcp3564_chip_infos_tbl[mcp3561] }, + { "mcp3562", (kernel_ulong_t)&mcp3564_chip_infos_tbl[mcp3562] }, + { "mcp3564", (kernel_ulong_t)&mcp3564_chip_infos_tbl[mcp3564] }, + { "mcp3461r", (kernel_ulong_t)&mcp3564_chip_infos_tbl[mcp3461r] }, + { "mcp3462r", (kernel_ulong_t)&mcp3564_chip_infos_tbl[mcp3462r] }, + { "mcp3464r", (kernel_ulong_t)&mcp3564_chip_infos_tbl[mcp3464r] }, + { "mcp3561r", (kernel_ulong_t)&mcp3564_chip_infos_tbl[mcp3561r] }, + { "mcp3562r", (kernel_ulong_t)&mcp3564_chip_infos_tbl[mcp3562r] }, + { "mcp3564r", (kernel_ulong_t)&mcp3564_chip_infos_tbl[mcp3564r] }, + { } +}; +MODULE_DEVICE_TABLE(spi, mcp3564_id); + +static struct spi_driver mcp3564_driver = { + .driver = { + .name = "mcp3564", + .of_match_table = mcp3564_dt_ids, + }, + .probe = mcp3564_probe, + .id_table = mcp3564_id, +}; + +module_spi_driver(mcp3564_driver); + +MODULE_AUTHOR("Marius Cristea "); +MODULE_DESCRIPTION("Microchip MCP346x/MCP346xR and MCP356x/MCP346xR ADCs"); +MODULE_LICENSE("GPL v2"); From 17f961a6555ae38490cfcc39f12c0c014cbd2617 Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Thu, 31 Aug 2023 20:25:02 +0200 Subject: [PATCH 053/326] iio: adc: ti-ads1015: Add edge trigger support The comparator generates an edge on the IRQ like and stays in the configured state until cleared. Support edge triggered IRQs as well as not all controllers do support level triggered IRQ. Signed-off-by: Marek Vasut Link: https://lore.kernel.org/r/20230831182502.154899-1-marex@denx.de Signed-off-by: Jonathan Cameron --- drivers/iio/adc/ti-ads1015.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/iio/adc/ti-ads1015.c b/drivers/iio/adc/ti-ads1015.c index 075c75a87544..addee45ed40a 100644 --- a/drivers/iio/adc/ti-ads1015.c +++ b/drivers/iio/adc/ti-ads1015.c @@ -1047,11 +1047,13 @@ static int ads1015_probe(struct i2c_client *client) 1 << ADS1015_CFG_COMP_LAT_SHIFT; switch (irq_trig) { + case IRQF_TRIGGER_FALLING: case IRQF_TRIGGER_LOW: cfg_comp |= ADS1015_CFG_COMP_POL_LOW << ADS1015_CFG_COMP_POL_SHIFT; break; case IRQF_TRIGGER_HIGH: + case IRQF_TRIGGER_RISING: cfg_comp |= ADS1015_CFG_COMP_POL_HIGH << ADS1015_CFG_COMP_POL_SHIFT; break; From 5793ddcf1f8bf90bfe13b1757a1350d6482a4474 Mon Sep 17 00:00:00 2001 From: Biju Das Date: Sat, 2 Sep 2023 17:26:33 +0100 Subject: [PATCH 054/326] iio: adc: ti-adc081c: Simplify probe() Simpilfy probe() by replacing of_device_get_match_data() and id lookup for retrieving match data by using i2c_get_match_data() by making similar OF/I2C/ACPI match tables. Signed-off-by: Biju Das Link: https://lore.kernel.org/r/20230902162633.50546-1-biju.das.jz@bp.renesas.com Signed-off-by: Jonathan Cameron --- drivers/iio/adc/ti-adc081c.c | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/drivers/iio/adc/ti-adc081c.c b/drivers/iio/adc/ti-adc081c.c index 50c450e7a55f..6c2cb3dabbbf 100644 --- a/drivers/iio/adc/ti-adc081c.c +++ b/drivers/iio/adc/ti-adc081c.c @@ -154,7 +154,6 @@ static void adc081c_reg_disable(void *reg) static int adc081c_probe(struct i2c_client *client) { - const struct i2c_device_id *id = i2c_client_get_device_id(client); struct iio_dev *iio; struct adc081c *adc; const struct adcxx1c_model *model; @@ -163,10 +162,7 @@ static int adc081c_probe(struct i2c_client *client) if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_WORD_DATA)) return -EOPNOTSUPP; - if (dev_fwnode(&client->dev)) - model = device_get_match_data(&client->dev); - else - model = &adcxx1c_models[id->driver_data]; + model = i2c_get_match_data(client); iio = devm_iio_device_alloc(&client->dev, sizeof(*adc)); if (!iio) @@ -207,9 +203,9 @@ static int adc081c_probe(struct i2c_client *client) } static const struct i2c_device_id adc081c_id[] = { - { "adc081c", ADC081C }, - { "adc101c", ADC101C }, - { "adc121c", ADC121C }, + { "adc081c", (kernel_ulong_t)&adcxx1c_models[ADC081C] }, + { "adc101c", (kernel_ulong_t)&adcxx1c_models[ADC101C] }, + { "adc121c", (kernel_ulong_t)&adcxx1c_models[ADC121C] }, { } }; MODULE_DEVICE_TABLE(i2c, adc081c_id); From f6b1737921dd38919a6d25826a953bd6d04c8c4b Mon Sep 17 00:00:00 2001 From: Biju Das Date: Sat, 2 Sep 2023 17:32:33 +0100 Subject: [PATCH 055/326] iio: adc: ti-ads1015: Simplify probe() Simpilfy probe() by replacing device_get_match_data() and id lookup for retrieving match data by using i2c_get_match_data(). Signed-off-by: Biju Das Link: https://lore.kernel.org/r/20230902163233.56449-1-biju.das.jz@bp.renesas.com Signed-off-by: Jonathan Cameron --- drivers/iio/adc/ti-ads1015.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/drivers/iio/adc/ti-ads1015.c b/drivers/iio/adc/ti-ads1015.c index addee45ed40a..6799ea49dbc7 100644 --- a/drivers/iio/adc/ti-ads1015.c +++ b/drivers/iio/adc/ti-ads1015.c @@ -976,16 +976,13 @@ static int ads1015_set_conv_mode(struct ads1015_data *data, int mode) static int ads1015_probe(struct i2c_client *client) { - const struct i2c_device_id *id = i2c_client_get_device_id(client); const struct ads1015_chip_data *chip; struct iio_dev *indio_dev; struct ads1015_data *data; int ret; int i; - chip = device_get_match_data(&client->dev); - if (!chip) - chip = (const struct ads1015_chip_data *)id->driver_data; + chip = i2c_get_match_data(client); if (!chip) return dev_err_probe(&client->dev, -EINVAL, "Unknown chip\n"); From 6c70012df1f39bb9bd015b6b6383f66cde95bc94 Mon Sep 17 00:00:00 2001 From: Biju Das Date: Sat, 2 Sep 2023 18:05:29 +0100 Subject: [PATCH 056/326] iio: adc: ltc2497: Simplify probe() Simpilfy probe() by replacing device_get_match_data() and id lookup for retrieving match data by using i2c_get_match_data(). Signed-off-by: Biju Das Link: https://lore.kernel.org/r/20230902170529.62297-1-biju.das.jz@bp.renesas.com Signed-off-by: Jonathan Cameron --- drivers/iio/adc/ltc2497.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/drivers/iio/adc/ltc2497.c b/drivers/iio/adc/ltc2497.c index 5bdd40729611..6401a7727c31 100644 --- a/drivers/iio/adc/ltc2497.c +++ b/drivers/iio/adc/ltc2497.c @@ -95,7 +95,6 @@ static int ltc2497_result_and_measure(struct ltc2497core_driverdata *ddata, static int ltc2497_probe(struct i2c_client *client) { - const struct i2c_device_id *id = i2c_client_get_device_id(client); const struct ltc2497_chip_info *chip_info; struct iio_dev *indio_dev; struct ltc2497_driverdata *st; @@ -115,9 +114,7 @@ static int ltc2497_probe(struct i2c_client *client) st->client = client; st->common_ddata.result_and_measure = ltc2497_result_and_measure; - chip_info = device_get_match_data(dev); - if (!chip_info) - chip_info = (const struct ltc2497_chip_info *)id->driver_data; + chip_info = i2c_get_match_data(client); st->common_ddata.chip_info = chip_info; resolution = chip_info->resolution; From 7d0ba6dbf8356d20b69cfd042800d5d51ac00bd7 Mon Sep 17 00:00:00 2001 From: Biju Das Date: Sun, 3 Sep 2023 10:00:50 +0100 Subject: [PATCH 057/326] iio: accel: adxl345: Convert enum->pointer for data in match data table Convert enum->pointer for data in match data table, so that device_get_match_data() can do match against OF/ACPI/I2C tables, once i2c bus type match support added to it. Add struct adxl345_chip_info and replace enum->adxl345_chip_info in the match table and simplify adxl345_probe(). Signed-off-by: Biju Das Link: https://lore.kernel.org/r/20230903090051.39274-2-biju.das.jz@bp.renesas.com Signed-off-by: Jonathan Cameron --- drivers/iio/accel/adxl345.h | 5 +++++ drivers/iio/accel/adxl345_core.c | 24 ++++++------------------ drivers/iio/accel/adxl345_i2c.c | 20 +++++++++++++++----- drivers/iio/accel/adxl345_spi.c | 20 +++++++++++++++----- 4 files changed, 41 insertions(+), 28 deletions(-) diff --git a/drivers/iio/accel/adxl345.h b/drivers/iio/accel/adxl345.h index d7e67cb08538..826e0575ae79 100644 --- a/drivers/iio/accel/adxl345.h +++ b/drivers/iio/accel/adxl345.h @@ -13,6 +13,11 @@ enum adxl345_device_type { ADXL375 = 2, }; +struct adxl345_chip_info { + const char *name; + unsigned int type; +}; + int adxl345_core_probe(struct device *dev, struct regmap *regmap); #endif /* _ADXL345_H_ */ diff --git a/drivers/iio/accel/adxl345_core.c b/drivers/iio/accel/adxl345_core.c index 1919e0089c11..28f77b5de47d 100644 --- a/drivers/iio/accel/adxl345_core.c +++ b/drivers/iio/accel/adxl345_core.c @@ -61,9 +61,9 @@ static const int adxl345_uscale = 38300; static const int adxl375_uscale = 480000; struct adxl345_data { + const struct adxl345_chip_info *info; struct regmap *regmap; u8 data_range; - enum adxl345_device_type type; }; #define ADXL345_CHANNEL(index, axis) { \ @@ -110,7 +110,7 @@ static int adxl345_read_raw(struct iio_dev *indio_dev, return IIO_VAL_INT; case IIO_CHAN_INFO_SCALE: *val = 0; - switch (data->type) { + switch (data->info->type) { case ADXL345: *val2 = adxl345_uscale; break; @@ -222,25 +222,11 @@ static void adxl345_powerdown(void *regmap) int adxl345_core_probe(struct device *dev, struct regmap *regmap) { - enum adxl345_device_type type; struct adxl345_data *data; struct iio_dev *indio_dev; - const char *name; u32 regval; int ret; - type = (uintptr_t)device_get_match_data(dev); - switch (type) { - case ADXL345: - name = "adxl345"; - break; - case ADXL375: - name = "adxl375"; - break; - default: - return -EINVAL; - } - ret = regmap_read(regmap, ADXL345_REG_DEVID, ®val); if (ret < 0) return dev_err_probe(dev, ret, "Error reading device ID\n"); @@ -255,16 +241,18 @@ int adxl345_core_probe(struct device *dev, struct regmap *regmap) data = iio_priv(indio_dev); data->regmap = regmap; - data->type = type; /* Enable full-resolution mode */ data->data_range = ADXL345_DATA_FORMAT_FULL_RES; + data->info = device_get_match_data(dev); + if (!data->info) + return -ENODEV; ret = regmap_write(data->regmap, ADXL345_REG_DATA_FORMAT, data->data_range); if (ret < 0) return dev_err_probe(dev, ret, "Failed to set data range\n"); - indio_dev->name = name; + indio_dev->name = data->info->name; indio_dev->info = &adxl345_info; indio_dev->modes = INDIO_DIRECT_MODE; indio_dev->channels = adxl345_channels; diff --git a/drivers/iio/accel/adxl345_i2c.c b/drivers/iio/accel/adxl345_i2c.c index e47d12f19602..8cb6254297f7 100644 --- a/drivers/iio/accel/adxl345_i2c.c +++ b/drivers/iio/accel/adxl345_i2c.c @@ -30,22 +30,32 @@ static int adxl345_i2c_probe(struct i2c_client *client) return adxl345_core_probe(&client->dev, regmap); } +static const struct adxl345_chip_info adxl345_i2c_info = { + .name = "adxl345", + .type = ADXL345, +}; + +static const struct adxl345_chip_info adxl375_i2c_info = { + .name = "adxl375", + .type = ADXL375, +}; + static const struct i2c_device_id adxl345_i2c_id[] = { - { "adxl345", ADXL345 }, - { "adxl375", ADXL375 }, + { "adxl345", (kernel_ulong_t)&adxl345_i2c_info }, + { "adxl375", (kernel_ulong_t)&adxl375_i2c_info }, { } }; MODULE_DEVICE_TABLE(i2c, adxl345_i2c_id); static const struct of_device_id adxl345_of_match[] = { - { .compatible = "adi,adxl345", .data = (const void *)ADXL345 }, - { .compatible = "adi,adxl375", .data = (const void *)ADXL375 }, + { .compatible = "adi,adxl345", .data = &adxl345_i2c_info }, + { .compatible = "adi,adxl375", .data = &adxl375_i2c_info }, { } }; MODULE_DEVICE_TABLE(of, adxl345_of_match); static const struct acpi_device_id adxl345_acpi_match[] = { - { "ADS0345", ADXL345 }, + { "ADS0345", (kernel_ulong_t)&adxl345_i2c_info }, { } }; MODULE_DEVICE_TABLE(acpi, adxl345_acpi_match); diff --git a/drivers/iio/accel/adxl345_spi.c b/drivers/iio/accel/adxl345_spi.c index aaade5808657..ede9b9496158 100644 --- a/drivers/iio/accel/adxl345_spi.c +++ b/drivers/iio/accel/adxl345_spi.c @@ -36,22 +36,32 @@ static int adxl345_spi_probe(struct spi_device *spi) return adxl345_core_probe(&spi->dev, regmap); } +static const struct adxl345_chip_info adxl345_spi_info = { + .name = "adxl345", + .type = ADXL345, +}; + +static const struct adxl345_chip_info adxl375_spi_info = { + .name = "adxl375", + .type = ADXL375, +}; + static const struct spi_device_id adxl345_spi_id[] = { - { "adxl345", ADXL345 }, - { "adxl375", ADXL375 }, + { "adxl345", (kernel_ulong_t)&adxl345_spi_info }, + { "adxl375", (kernel_ulong_t)&adxl375_spi_info }, { } }; MODULE_DEVICE_TABLE(spi, adxl345_spi_id); static const struct of_device_id adxl345_of_match[] = { - { .compatible = "adi,adxl345", .data = (const void *)ADXL345 }, - { .compatible = "adi,adxl375", .data = (const void *)ADXL375 }, + { .compatible = "adi,adxl345", .data = &adxl345_spi_info }, + { .compatible = "adi,adxl375", .data = &adxl375_spi_info }, { } }; MODULE_DEVICE_TABLE(of, adxl345_of_match); static const struct acpi_device_id adxl345_acpi_match[] = { - { "ADS0345", ADXL345 }, + { "ADS0345", (kernel_ulong_t)&adxl345_spi_info }, { } }; MODULE_DEVICE_TABLE(acpi, adxl345_acpi_match); From dcc3ac1381eff05e4ab546a42798dd6837b295a7 Mon Sep 17 00:00:00 2001 From: Biju Das Date: Sun, 3 Sep 2023 10:00:51 +0100 Subject: [PATCH 058/326] iio: accel: adxl345: Simplify adxl345_read_raw() Simplify adxl345_read_raw() by adding uscale variable to struct adxl345_chip_info. Also convert variables adxl3{4,7}5_uscale to macros and use it in OF/ACPI/ID match table. Drop enum adxl345_device_type as there is no user. Signed-off-by: Biju Das Link: https://lore.kernel.org/r/20230903090051.39274-3-biju.das.jz@bp.renesas.com Signed-off-by: Jonathan Cameron --- drivers/iio/accel/adxl345.h | 20 +++++++++++++++----- drivers/iio/accel/adxl345_core.c | 25 +------------------------ drivers/iio/accel/adxl345_i2c.c | 4 ++-- drivers/iio/accel/adxl345_spi.c | 4 ++-- 4 files changed, 20 insertions(+), 33 deletions(-) diff --git a/drivers/iio/accel/adxl345.h b/drivers/iio/accel/adxl345.h index 826e0575ae79..284bd387ce69 100644 --- a/drivers/iio/accel/adxl345.h +++ b/drivers/iio/accel/adxl345.h @@ -8,14 +8,24 @@ #ifndef _ADXL345_H_ #define _ADXL345_H_ -enum adxl345_device_type { - ADXL345 = 1, - ADXL375 = 2, -}; +/* + * In full-resolution mode, scale factor is maintained at ~4 mg/LSB + * in all g ranges. + * + * At +/- 16g with 13-bit resolution, scale is computed as: + * (16 + 16) * 9.81 / (2^13 - 1) = 0.0383 + */ +#define ADXL345_USCALE 38300 + +/* + * The Datasheet lists a resolution of Resolution is ~49 mg per LSB. That's + * ~480mm/s**2 per LSB. + */ +#define ADXL375_USCALE 480000 struct adxl345_chip_info { const char *name; - unsigned int type; + int uscale; }; int adxl345_core_probe(struct device *dev, struct regmap *regmap); diff --git a/drivers/iio/accel/adxl345_core.c b/drivers/iio/accel/adxl345_core.c index 28f77b5de47d..8bd30a23ed3b 100644 --- a/drivers/iio/accel/adxl345_core.c +++ b/drivers/iio/accel/adxl345_core.c @@ -45,21 +45,6 @@ #define ADXL345_DEVID 0xE5 -/* - * In full-resolution mode, scale factor is maintained at ~4 mg/LSB - * in all g ranges. - * - * At +/- 16g with 13-bit resolution, scale is computed as: - * (16 + 16) * 9.81 / (2^13 - 1) = 0.0383 - */ -static const int adxl345_uscale = 38300; - -/* - * The Datasheet lists a resolution of Resolution is ~49 mg per LSB. That's - * ~480mm/s**2 per LSB. - */ -static const int adxl375_uscale = 480000; - struct adxl345_data { const struct adxl345_chip_info *info; struct regmap *regmap; @@ -110,15 +95,7 @@ static int adxl345_read_raw(struct iio_dev *indio_dev, return IIO_VAL_INT; case IIO_CHAN_INFO_SCALE: *val = 0; - switch (data->info->type) { - case ADXL345: - *val2 = adxl345_uscale; - break; - case ADXL375: - *val2 = adxl375_uscale; - break; - } - + *val2 = data->info->uscale; return IIO_VAL_INT_PLUS_MICRO; case IIO_CHAN_INFO_CALIBBIAS: ret = regmap_read(data->regmap, diff --git a/drivers/iio/accel/adxl345_i2c.c b/drivers/iio/accel/adxl345_i2c.c index 8cb6254297f7..a3084b0a8f78 100644 --- a/drivers/iio/accel/adxl345_i2c.c +++ b/drivers/iio/accel/adxl345_i2c.c @@ -32,12 +32,12 @@ static int adxl345_i2c_probe(struct i2c_client *client) static const struct adxl345_chip_info adxl345_i2c_info = { .name = "adxl345", - .type = ADXL345, + .uscale = ADXL345_USCALE, }; static const struct adxl345_chip_info adxl375_i2c_info = { .name = "adxl375", - .type = ADXL375, + .uscale = ADXL375_USCALE, }; static const struct i2c_device_id adxl345_i2c_id[] = { diff --git a/drivers/iio/accel/adxl345_spi.c b/drivers/iio/accel/adxl345_spi.c index ede9b9496158..93ca349f1780 100644 --- a/drivers/iio/accel/adxl345_spi.c +++ b/drivers/iio/accel/adxl345_spi.c @@ -38,12 +38,12 @@ static int adxl345_spi_probe(struct spi_device *spi) static const struct adxl345_chip_info adxl345_spi_info = { .name = "adxl345", - .type = ADXL345, + .uscale = ADXL345_USCALE, }; static const struct adxl345_chip_info adxl375_spi_info = { .name = "adxl375", - .type = ADXL375, + .uscale = ADXL375_USCALE, }; static const struct spi_device_id adxl345_spi_id[] = { From 002d546fff4f83648903eada2b6226d314374fdb Mon Sep 17 00:00:00 2001 From: Biju Das Date: Sun, 3 Sep 2023 12:55:45 +0100 Subject: [PATCH 059/326] iio: dac: mcp4725: Replace variable 'id' from struct mcp4725_data Replace the variable 'id' from struct mcp4725_data with local variable chip_id in probe() as the id variable is not used elsewhere in the driver. Signed-off-by: Biju Das Link: https://lore.kernel.org/r/20230903115548.59306-2-biju.das.jz@bp.renesas.com Signed-off-by: Jonathan Cameron --- drivers/iio/dac/mcp4725.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/drivers/iio/dac/mcp4725.c b/drivers/iio/dac/mcp4725.c index f4a3124d29f2..33a61f65bc25 100644 --- a/drivers/iio/dac/mcp4725.c +++ b/drivers/iio/dac/mcp4725.c @@ -32,7 +32,6 @@ struct mcp4725_data { struct i2c_client *client; - int id; unsigned ref_mode; bool vref_buffered; u16 dac_value; @@ -387,6 +386,7 @@ static int mcp4725_probe(struct i2c_client *client) struct mcp4725_data *data; struct iio_dev *indio_dev; struct mcp4725_platform_data *pdata, pdata_dt; + int chip_id; u8 inbuf[4]; u8 pd; u8 ref; @@ -399,9 +399,9 @@ static int mcp4725_probe(struct i2c_client *client) i2c_set_clientdata(client, indio_dev); data->client = client; if (dev_fwnode(&client->dev)) - data->id = (uintptr_t)device_get_match_data(&client->dev); + chip_id = (uintptr_t)device_get_match_data(&client->dev); else - data->id = id->driver_data; + chip_id = id->driver_data; pdata = dev_get_platdata(&client->dev); if (!pdata) { @@ -414,7 +414,7 @@ static int mcp4725_probe(struct i2c_client *client) pdata = &pdata_dt; } - if (data->id == MCP4725 && pdata->use_vref) { + if (chip_id == MCP4725 && pdata->use_vref) { dev_err(&client->dev, "external reference is unavailable on MCP4725"); return -EINVAL; @@ -455,12 +455,12 @@ static int mcp4725_probe(struct i2c_client *client) indio_dev->name = id->name; indio_dev->info = &mcp4725_info; - indio_dev->channels = &mcp472x_channel[id->driver_data]; + indio_dev->channels = &mcp472x_channel[chip_id]; indio_dev->num_channels = 1; indio_dev->modes = INDIO_DIRECT_MODE; /* read current DAC value and settings */ - err = i2c_master_recv(client, inbuf, data->id == MCP4725 ? 3 : 4); + err = i2c_master_recv(client, inbuf, chip_id == MCP4725 ? 3 : 4); if (err < 0) { dev_err(&client->dev, "failed to read DAC value"); @@ -470,10 +470,10 @@ static int mcp4725_probe(struct i2c_client *client) data->powerdown = pd > 0; data->powerdown_mode = pd ? pd - 1 : 2; /* largest resistor to gnd */ data->dac_value = (inbuf[1] << 4) | (inbuf[2] >> 4); - if (data->id == MCP4726) + if (chip_id == MCP4726) ref = (inbuf[3] >> 3) & 0x3; - if (data->id == MCP4726 && ref != data->ref_mode) { + if (chip_id == MCP4726 && ref != data->ref_mode) { dev_info(&client->dev, "voltage reference mode differs (conf: %u, eeprom: %u), setting %u", data->ref_mode, ref, data->ref_mode); From 18bdc686c1519e067dc80ec0015da52e2bd628b9 Mon Sep 17 00:00:00 2001 From: Biju Das Date: Sun, 3 Sep 2023 12:55:46 +0100 Subject: [PATCH 060/326] iio: dac: mcp4725: Use i2c_get_match_data() Add struct mcp4725_chip_info with chan_spec and chip_id variable. After this simplify probe() by replacing device_get_match_data() and id lookup for retrieving match data by i2c_get_match_data() by converting enum->pointer for data in the match table. Signed-off-by: Biju Das Link: https://lore.kernel.org/r/20230903115548.59306-3-biju.das.jz@bp.renesas.com Signed-off-by: Jonathan Cameron --- drivers/iio/dac/mcp4725.c | 40 +++++++++++++++++++++++++-------------- 1 file changed, 26 insertions(+), 14 deletions(-) diff --git a/drivers/iio/dac/mcp4725.c b/drivers/iio/dac/mcp4725.c index 33a61f65bc25..fe8981ec7923 100644 --- a/drivers/iio/dac/mcp4725.c +++ b/drivers/iio/dac/mcp4725.c @@ -30,6 +30,11 @@ #define MCP472X_REF_VREF_UNBUFFERED 0x02 #define MCP472X_REF_VREF_BUFFERED 0x03 +struct mcp4725_chip_info { + const struct iio_chan_spec *chan_spec; + unsigned int chip_id; +}; + struct mcp4725_data { struct i2c_client *client; unsigned ref_mode; @@ -383,10 +388,10 @@ static int mcp4725_probe_dt(struct device *dev, static int mcp4725_probe(struct i2c_client *client) { const struct i2c_device_id *id = i2c_client_get_device_id(client); + const struct mcp4725_chip_info *info; struct mcp4725_data *data; struct iio_dev *indio_dev; struct mcp4725_platform_data *pdata, pdata_dt; - int chip_id; u8 inbuf[4]; u8 pd; u8 ref; @@ -398,10 +403,7 @@ static int mcp4725_probe(struct i2c_client *client) data = iio_priv(indio_dev); i2c_set_clientdata(client, indio_dev); data->client = client; - if (dev_fwnode(&client->dev)) - chip_id = (uintptr_t)device_get_match_data(&client->dev); - else - chip_id = id->driver_data; + info = i2c_get_match_data(client); pdata = dev_get_platdata(&client->dev); if (!pdata) { @@ -414,7 +416,7 @@ static int mcp4725_probe(struct i2c_client *client) pdata = &pdata_dt; } - if (chip_id == MCP4725 && pdata->use_vref) { + if (info->chip_id == MCP4725 && pdata->use_vref) { dev_err(&client->dev, "external reference is unavailable on MCP4725"); return -EINVAL; @@ -455,12 +457,12 @@ static int mcp4725_probe(struct i2c_client *client) indio_dev->name = id->name; indio_dev->info = &mcp4725_info; - indio_dev->channels = &mcp472x_channel[chip_id]; + indio_dev->channels = info->chan_spec; indio_dev->num_channels = 1; indio_dev->modes = INDIO_DIRECT_MODE; /* read current DAC value and settings */ - err = i2c_master_recv(client, inbuf, chip_id == MCP4725 ? 3 : 4); + err = i2c_master_recv(client, inbuf, info->chip_id == MCP4725 ? 3 : 4); if (err < 0) { dev_err(&client->dev, "failed to read DAC value"); @@ -470,10 +472,10 @@ static int mcp4725_probe(struct i2c_client *client) data->powerdown = pd > 0; data->powerdown_mode = pd ? pd - 1 : 2; /* largest resistor to gnd */ data->dac_value = (inbuf[1] << 4) | (inbuf[2] >> 4); - if (chip_id == MCP4726) + if (info->chip_id == MCP4726) ref = (inbuf[3] >> 3) & 0x3; - if (chip_id == MCP4726 && ref != data->ref_mode) { + if (info->chip_id == MCP4726 && ref != data->ref_mode) { dev_info(&client->dev, "voltage reference mode differs (conf: %u, eeprom: %u), setting %u", data->ref_mode, ref, data->ref_mode); @@ -510,9 +512,19 @@ static void mcp4725_remove(struct i2c_client *client) regulator_disable(data->vdd_reg); } +static const struct mcp4725_chip_info mcp4725 = { + .chan_spec = &mcp472x_channel[MCP4725], + .chip_id = MCP4725, +}; + +static const struct mcp4725_chip_info mcp4726 = { + .chan_spec = &mcp472x_channel[MCP4726], + .chip_id = MCP4726, +}; + static const struct i2c_device_id mcp4725_id[] = { - { "mcp4725", MCP4725 }, - { "mcp4726", MCP4726 }, + { "mcp4725", (kernel_ulong_t)&mcp4725 }, + { "mcp4726", (kernel_ulong_t)&mcp4726 }, { } }; MODULE_DEVICE_TABLE(i2c, mcp4725_id); @@ -520,11 +532,11 @@ MODULE_DEVICE_TABLE(i2c, mcp4725_id); static const struct of_device_id mcp4725_of_match[] = { { .compatible = "microchip,mcp4725", - .data = (void *)MCP4725 + .data = &mcp4725 }, { .compatible = "microchip,mcp4726", - .data = (void *)MCP4726 + .data = &mcp4726 }, { } }; From 155da070b4388ed53f058259923f46740a51afde Mon Sep 17 00:00:00 2001 From: Biju Das Date: Sun, 3 Sep 2023 12:55:47 +0100 Subject: [PATCH 061/326] iio: dac: mcp4725: Add use_ext_ref_voltage to struct mcp4725_chip_info The MCP4725 has external voltage reference compared MCP4725 which has reference embeedded in eeprom. Add use_ext_ref_voltage variable to struct mcp4725_chip_info to handle this difference. Signed-off-by: Biju Das Link: https://lore.kernel.org/r/20230903115548.59306-4-biju.das.jz@bp.renesas.com Signed-off-by: Jonathan Cameron --- drivers/iio/dac/mcp4725.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/drivers/iio/dac/mcp4725.c b/drivers/iio/dac/mcp4725.c index fe8981ec7923..9cbea6f223e4 100644 --- a/drivers/iio/dac/mcp4725.c +++ b/drivers/iio/dac/mcp4725.c @@ -33,6 +33,7 @@ struct mcp4725_chip_info { const struct iio_chan_spec *chan_spec; unsigned int chip_id; + bool use_ext_ref_voltage; }; struct mcp4725_data { @@ -416,7 +417,7 @@ static int mcp4725_probe(struct i2c_client *client) pdata = &pdata_dt; } - if (info->chip_id == MCP4725 && pdata->use_vref) { + if (info->use_ext_ref_voltage && pdata->use_vref) { dev_err(&client->dev, "external reference is unavailable on MCP4725"); return -EINVAL; @@ -472,10 +473,10 @@ static int mcp4725_probe(struct i2c_client *client) data->powerdown = pd > 0; data->powerdown_mode = pd ? pd - 1 : 2; /* largest resistor to gnd */ data->dac_value = (inbuf[1] << 4) | (inbuf[2] >> 4); - if (info->chip_id == MCP4726) + if (!info->use_ext_ref_voltage) ref = (inbuf[3] >> 3) & 0x3; - if (info->chip_id == MCP4726 && ref != data->ref_mode) { + if (!info->use_ext_ref_voltage && ref != data->ref_mode) { dev_info(&client->dev, "voltage reference mode differs (conf: %u, eeprom: %u), setting %u", data->ref_mode, ref, data->ref_mode); @@ -515,6 +516,7 @@ static void mcp4725_remove(struct i2c_client *client) static const struct mcp4725_chip_info mcp4725 = { .chan_spec = &mcp472x_channel[MCP4725], .chip_id = MCP4725, + .use_ext_ref_voltage = true, }; static const struct mcp4725_chip_info mcp4726 = { From c377e2febd91e21782f9106e663937f0629f39f1 Mon Sep 17 00:00:00 2001 From: Biju Das Date: Sun, 3 Sep 2023 12:55:48 +0100 Subject: [PATCH 062/326] iio: dac: mcp4725: Add dac_reg_offset to struct mcp4725_chip_info The MCP4725 has a register offset '3' for reading DAC value compared to '4' for MCP4726. Add dac_reg_offset variable to struct mcp4725_chip_info to handle this difference. Drop chip_id from struct mcp4725_chip_info as it is unused. Signed-off-by: Biju Das Link: https://lore.kernel.org/r/20230903115548.59306-5-biju.das.jz@bp.renesas.com Signed-off-by: Jonathan Cameron --- drivers/iio/dac/mcp4725.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/iio/dac/mcp4725.c b/drivers/iio/dac/mcp4725.c index 9cbea6f223e4..25bb1c0490af 100644 --- a/drivers/iio/dac/mcp4725.c +++ b/drivers/iio/dac/mcp4725.c @@ -32,7 +32,7 @@ struct mcp4725_chip_info { const struct iio_chan_spec *chan_spec; - unsigned int chip_id; + u8 dac_reg_offset; bool use_ext_ref_voltage; }; @@ -463,7 +463,7 @@ static int mcp4725_probe(struct i2c_client *client) indio_dev->modes = INDIO_DIRECT_MODE; /* read current DAC value and settings */ - err = i2c_master_recv(client, inbuf, info->chip_id == MCP4725 ? 3 : 4); + err = i2c_master_recv(client, inbuf, info->dac_reg_offset); if (err < 0) { dev_err(&client->dev, "failed to read DAC value"); @@ -515,13 +515,13 @@ static void mcp4725_remove(struct i2c_client *client) static const struct mcp4725_chip_info mcp4725 = { .chan_spec = &mcp472x_channel[MCP4725], - .chip_id = MCP4725, + .dac_reg_offset = 3, .use_ext_ref_voltage = true, }; static const struct mcp4725_chip_info mcp4726 = { .chan_spec = &mcp472x_channel[MCP4726], - .chip_id = MCP4726, + .dac_reg_offset = 4, }; static const struct i2c_device_id mcp4725_id[] = { From 22da192f43f7d302d02644efa192ba5a05d935c9 Mon Sep 17 00:00:00 2001 From: Biju Das Date: Sun, 3 Sep 2023 15:59:26 +0100 Subject: [PATCH 063/326] iio: pressure: ms5637: Use i2c_get_match_data() Simplify probe() by replacing id lookup for retrieving match data and device_get_match_data() by i2c_get_match_data(). Signed-off-by: Biju Das Reviewed-by: Andy Shevchenko Link: https://lore.kernel.org/r/20230903145926.66855-1-biju.das.jz@bp.renesas.com Signed-off-by: Jonathan Cameron --- drivers/iio/pressure/ms5637.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/drivers/iio/pressure/ms5637.c b/drivers/iio/pressure/ms5637.c index 9b3abffb724b..ac30d76285d1 100644 --- a/drivers/iio/pressure/ms5637.c +++ b/drivers/iio/pressure/ms5637.c @@ -144,7 +144,6 @@ static const struct iio_info ms5637_info = { static int ms5637_probe(struct i2c_client *client) { - const struct i2c_device_id *id = i2c_client_get_device_id(client); const struct ms_tp_data *data; struct ms_tp_dev *dev_data; struct iio_dev *indio_dev; @@ -159,10 +158,7 @@ static int ms5637_probe(struct i2c_client *client) return -EOPNOTSUPP; } - if (id) - data = (const struct ms_tp_data *)id->driver_data; - else - data = device_get_match_data(&client->dev); + data = i2c_get_match_data(client); if (!data) return -EINVAL; From e670bfe2736d3bd4436d160d37544e029f2aa813 Mon Sep 17 00:00:00 2001 From: Antoniu Miclaus Date: Mon, 11 Sep 2023 17:29:50 +0300 Subject: [PATCH 064/326] iio: addac: ad74413r: update channel function set MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit According to the datasheet switching to a new channel function implies multiple steps. All functions must be selected for a minimum of 130 μs before changing to another function. The DAC_CODEx registers are not reset by changing channel functions. Prior to changing channel functions, it is recommended to set the DAC code to 0x0000 via the DAC_CODEx registers. Set the channel function to high impedance via the CH_FUNC_SETUPx registers before transitioning to the new channel function. After the new channel function is configured, it is recommended to wait 150 μs before updating the DAC code. Even though the channel switch is done at only at probe, where a device reset is performed, that does not guarantee that the steps prior changing to new channel function should be neglected. Signed-off-by: Antoniu Miclaus Link: https://lore.kernel.org/r/20230911142950.216687-1-antoniu.miclaus@analog.com Signed-off-by: Jonathan Cameron --- drivers/iio/addac/ad74413r.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/drivers/iio/addac/ad74413r.c b/drivers/iio/addac/ad74413r.c index 75216ece7ad6..7af3e4b8fe3b 100644 --- a/drivers/iio/addac/ad74413r.c +++ b/drivers/iio/addac/ad74413r.c @@ -441,12 +441,30 @@ static int ad74413r_set_channel_function(struct ad74413r_state *st, { int ret; + ret = regmap_update_bits(st->regmap, + AD74413R_REG_CH_FUNC_SETUP_X(channel), + AD74413R_CH_FUNC_SETUP_MASK, + CH_FUNC_HIGH_IMPEDANCE); + if (ret) + return ret; + + /* Set DAC code to 0 prior to changing channel function */ + ret = ad74413r_set_channel_dac_code(st, channel, 0); + if (ret) + return ret; + + /* Delay required before transition to new desired mode */ + usleep_range(130, 150); + ret = regmap_update_bits(st->regmap, AD74413R_REG_CH_FUNC_SETUP_X(channel), AD74413R_CH_FUNC_SETUP_MASK, func); if (ret) return ret; + /* Delay required before updating the new DAC code */ + usleep_range(150, 170); + if (func == CH_FUNC_CURRENT_INPUT_LOOP_POWER) ret = regmap_set_bits(st->regmap, AD74413R_REG_ADC_CONFIG_X(channel), From 9dc03309fe9ba9f9b26a37b2dd4fa2d5111a1ccf Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sun, 10 Sep 2023 07:09:03 -0700 Subject: [PATCH 065/326] iio: ad4310: Replace devm_clk_register() with devm_clk_hw_register() The devm_clk_register() is deprecated and devm_clk_hw_register() should be used as a replacement. Switching to the clk_hw interface also allows to use the built-in device managed version of registering the clock provider. The non-clk_hw interface does not have a device managed version. Signed-off-by: Lars-Peter Clausen Reviewed-by: Nuno Sa Link: https://lore.kernel.org/r/20230910140903.551081-1-lars@metafoo.de Signed-off-by: Jonathan Cameron --- drivers/iio/adc/ad4130.c | 15 +++------------ 1 file changed, 3 insertions(+), 12 deletions(-) diff --git a/drivers/iio/adc/ad4130.c b/drivers/iio/adc/ad4130.c index 5a5dd5e87ffc..feb86fe6c422 100644 --- a/drivers/iio/adc/ad4130.c +++ b/drivers/iio/adc/ad4130.c @@ -1817,18 +1817,12 @@ static const struct clk_ops ad4130_int_clk_ops = { .unprepare = ad4130_int_clk_unprepare, }; -static void ad4130_clk_del_provider(void *of_node) -{ - of_clk_del_provider(of_node); -} - static int ad4130_setup_int_clk(struct ad4130_state *st) { struct device *dev = &st->spi->dev; struct device_node *of_node = dev_of_node(dev); struct clk_init_data init; const char *clk_name; - struct clk *clk; int ret; if (st->int_pin_sel == AD4130_INT_PIN_CLK || @@ -1845,15 +1839,12 @@ static int ad4130_setup_int_clk(struct ad4130_state *st) init.ops = &ad4130_int_clk_ops; st->int_clk_hw.init = &init; - clk = devm_clk_register(dev, &st->int_clk_hw); - if (IS_ERR(clk)) - return PTR_ERR(clk); - - ret = of_clk_add_provider(of_node, of_clk_src_simple_get, clk); + ret = devm_clk_hw_register(dev, &st->int_clk_hw); if (ret) return ret; - return devm_add_action_or_reset(dev, ad4130_clk_del_provider, of_node); + return devm_of_clk_add_hw_provider(dev, of_clk_hw_simple_get, + &st->int_clk_hw); } static int ad4130_setup(struct iio_dev *indio_dev) From 66fe531268f274310a052603fc298f6cc177489b Mon Sep 17 00:00:00 2001 From: William Breathitt Gray Date: Sat, 16 Sep 2023 07:20:31 -0400 Subject: [PATCH 066/326] iio: addac: stx104: Add 8254 Counter/Timer support The STX104 features an 8254 Counter/Timer chip providing three counter/timers which can be used for frequency measurement, frequency output, pulse width modulation, pulse width measurement, event count, etc. The STX104 provides a register bank selection to bank select between the 8254 Bank and the Indexed Register Array Bank; the Indexed Register Array is not utilized by this driver, so the 8254 Bank is selected unconditionally. Signed-off-by: William Breathitt Gray Link: https://lore.kernel.org/r/20230916112031.3634-1-william.gray@linaro.org Signed-off-by: Jonathan Cameron --- drivers/iio/addac/Kconfig | 1 + drivers/iio/addac/stx104.c | 61 ++++++++++++++++++++++++++++++++++++-- 2 files changed, 60 insertions(+), 2 deletions(-) diff --git a/drivers/iio/addac/Kconfig b/drivers/iio/addac/Kconfig index 877f9124803c..b2623881f0ec 100644 --- a/drivers/iio/addac/Kconfig +++ b/drivers/iio/addac/Kconfig @@ -38,6 +38,7 @@ config STX104 select REGMAP_MMIO select GPIOLIB select GPIO_REGMAP + select I8254 help Say yes here to build support for the Apex Embedded Systems STX104 integrated analog PC/104 card. diff --git a/drivers/iio/addac/stx104.c b/drivers/iio/addac/stx104.c index d1f7ce033b46..6946a65512ca 100644 --- a/drivers/iio/addac/stx104.c +++ b/drivers/iio/addac/stx104.c @@ -8,6 +8,7 @@ #include #include #include +#include #include #include #include @@ -55,6 +56,7 @@ MODULE_PARM_DESC(base, "Apex Embedded Systems STX104 base addresses"); #define STX104_ADC_STATUS (STX104_AIO_BASE + 0x8) #define STX104_ADC_CONTROL (STX104_AIO_BASE + 0x9) #define STX104_ADC_CONFIGURATION (STX104_AIO_BASE + 0x11) +#define STX104_I8254_BASE (STX104_AIO_BASE + 0x12) #define STX104_AIO_DATA_STRIDE 2 #define STX104_DAC_OFFSET(_channel) (STX104_DAC_BASE + STX104_AIO_DATA_STRIDE * (_channel)) @@ -77,6 +79,7 @@ MODULE_PARM_DESC(base, "Apex Embedded Systems STX104 base addresses"); /* ADC Configuration */ #define STX104_GAIN GENMASK(1, 0) #define STX104_ADBU BIT(2) +#define STX104_RBK GENMASK(7, 4) #define STX104_BIPOLAR 0 #define STX104_GAIN_X1 0 #define STX104_GAIN_X2 1 @@ -168,6 +171,32 @@ static const struct regmap_config dio_regmap_config = { .io_port = true, }; +static const struct regmap_range pit_wr_ranges[] = { + regmap_reg_range(0x0, 0x3), +}; +static const struct regmap_range pit_rd_ranges[] = { + regmap_reg_range(0x0, 0x2), +}; +static const struct regmap_access_table pit_wr_table = { + .yes_ranges = pit_wr_ranges, + .n_yes_ranges = ARRAY_SIZE(pit_wr_ranges), +}; +static const struct regmap_access_table pit_rd_table = { + .yes_ranges = pit_rd_ranges, + .n_yes_ranges = ARRAY_SIZE(pit_rd_ranges), +}; + +static const struct regmap_config pit_regmap_config = { + .name = "i8254", + .reg_bits = 8, + .reg_stride = 1, + .reg_base = STX104_I8254_BASE, + .val_bits = 8, + .io_port = true, + .wr_table = &pit_wr_table, + .rd_table = &pit_rd_table, +}; + static int stx104_read_raw(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, int *val, int *val2, long mask) { @@ -339,6 +368,21 @@ static const char *stx104_names[STX104_NGPIO] = { "DIN0", "DIN1", "DIN2", "DIN3", "DOUT0", "DOUT1", "DOUT2", "DOUT3" }; +static int bank_select_i8254(struct regmap *map) +{ + const u8 select_i8254[] = { 0x3, 0xB, 0xA }; + size_t i; + int err; + + for (i = 0; i < ARRAY_SIZE(select_i8254); i++) { + err = regmap_write_bits(map, STX104_ADC_CONFIGURATION, STX104_RBK, select_i8254[i]); + if (err) + return err; + } + + return 0; +} + static int stx104_init_hw(struct stx104_iio *const priv) { int err; @@ -361,7 +405,7 @@ static int stx104_init_hw(struct stx104_iio *const priv) if (err) return err; - return 0; + return bank_select_i8254(priv->aio_ctl_map); } static int stx104_probe(struct device *dev, unsigned int id) @@ -369,6 +413,7 @@ static int stx104_probe(struct device *dev, unsigned int id) struct iio_dev *indio_dev; struct stx104_iio *priv; struct gpio_regmap_config gpio_config; + struct i8254_regmap_config pit_config; void __iomem *stx104_base; struct regmap *aio_ctl_map; struct regmap *aio_data_map; @@ -406,6 +451,11 @@ static int stx104_probe(struct device *dev, unsigned int id) return dev_err_probe(dev, PTR_ERR(dio_map), "Unable to initialize dio register map\n"); + pit_config.map = devm_regmap_init_mmio(dev, stx104_base, &pit_regmap_config); + if (IS_ERR(pit_config.map)) + return dev_err_probe(dev, PTR_ERR(pit_config.map), + "Unable to initialize i8254 register map\n"); + priv = iio_priv(indio_dev); priv->aio_ctl_map = aio_ctl_map; priv->aio_data_map = aio_data_map; @@ -449,7 +499,13 @@ static int stx104_probe(struct device *dev, unsigned int id) .drvdata = dio_map, }; - return PTR_ERR_OR_ZERO(devm_gpio_regmap_register(dev, &gpio_config)); + err = PTR_ERR_OR_ZERO(devm_gpio_regmap_register(dev, &gpio_config)); + if (err) + return err; + + pit_config.parent = dev; + + return devm_i8254_regmap_register(dev, &pit_config); } static struct isa_driver stx104_driver = { @@ -464,3 +520,4 @@ module_isa_driver(stx104_driver, num_stx104); MODULE_AUTHOR("William Breathitt Gray "); MODULE_DESCRIPTION("Apex Embedded Systems STX104 IIO driver"); MODULE_LICENSE("GPL v2"); +MODULE_IMPORT_NS(I8254); From 377dddbe53b941fdc4babbf177c47659de68eeef Mon Sep 17 00:00:00 2001 From: Mehdi Djait Date: Sat, 16 Sep 2023 14:38:47 +0200 Subject: [PATCH 067/326] dt-bindings: iio: Add KX132-1211 accelerometer Extend the kionix,kx022a.yaml file to support the kx132-1211 device Acked-by: Krzysztof Kozlowski Acked-by: Matti Vaittinen Signed-off-by: Mehdi Djait Link: https://lore.kernel.org/r/735004c624082aead6e08ae37ea4fc086b11cf86.1694867379.git.mehdi.djait.k@gmail.com Signed-off-by: Jonathan Cameron --- .../devicetree/bindings/iio/accel/kionix,kx022a.yaml | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/Documentation/devicetree/bindings/iio/accel/kionix,kx022a.yaml b/Documentation/devicetree/bindings/iio/accel/kionix,kx022a.yaml index 986df1a6ff0a..034b69614416 100644 --- a/Documentation/devicetree/bindings/iio/accel/kionix,kx022a.yaml +++ b/Documentation/devicetree/bindings/iio/accel/kionix,kx022a.yaml @@ -4,19 +4,21 @@ $id: http://devicetree.org/schemas/iio/accel/kionix,kx022a.yaml# $schema: http://devicetree.org/meta-schemas/core.yaml# -title: ROHM/Kionix KX022A Accelerometer +title: ROHM/Kionix KX022A and KX132-1211 Accelerometers maintainers: - Matti Vaittinen description: | - KX022A is a 3-axis accelerometer supporting +/- 2G, 4G, 8G and 16G ranges, - output data-rates from 0.78Hz to 1600Hz and a hardware-fifo buffering. - KX022A can be accessed either via I2C or SPI. + KX022A and KX132-1211 are 3-axis accelerometers supporting +/- 2G, 4G, 8G and + 16G ranges, variable output data-rates and a hardware-fifo buffering. + KX022A and KX132-1211 can be accessed either via I2C or SPI. properties: compatible: - const: kionix,kx022a + enum: + - kionix,kx022a + - kionix,kx132-1211 reg: maxItems: 1 From cfdb1e2875321bdda0a8f0246bcf1d3cbfdd0b09 Mon Sep 17 00:00:00 2001 From: Mehdi Djait Date: Sat, 16 Sep 2023 14:38:48 +0200 Subject: [PATCH 068/326] iio: accel: kionix-kx022a: Remove blank lines Remove blank lines pointed out by the checkpatch script Reviewed-by: Andy Shevchenko Reviewed-by: Matti Vaittinen Signed-off-by: Mehdi Djait Link: https://lore.kernel.org/r/3489099f653491e97b13b8f19fe86635b03020c8.1694867379.git.mehdi.djait.k@gmail.com Signed-off-by: Jonathan Cameron --- drivers/iio/accel/kionix-kx022a.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/iio/accel/kionix-kx022a.c b/drivers/iio/accel/kionix-kx022a.c index f164b09520c9..2f1e7da25460 100644 --- a/drivers/iio/accel/kionix-kx022a.c +++ b/drivers/iio/accel/kionix-kx022a.c @@ -341,7 +341,6 @@ static int kx022a_turn_on_off_unlocked(struct kx022a_data *data, bool on) dev_err(data->dev, "Turn %s fail %d\n", str_on_off(on), ret); return ret; - } static int kx022a_turn_off_lock(struct kx022a_data *data) @@ -1110,7 +1109,6 @@ int kx022a_probe_internal(struct device *dev) if (ret) return dev_err_probe(data->dev, ret, "Could not request IRQ\n"); - ret = devm_iio_trigger_register(dev, indio_trig); if (ret) return dev_err_probe(data->dev, ret, From 8abacef3b7fb6dd7054c0b327390ae8e1087f9e5 Mon Sep 17 00:00:00 2001 From: Mehdi Djait Date: Sat, 16 Sep 2023 14:38:49 +0200 Subject: [PATCH 069/326] iio: accel: kionix-kx022a: Warn on failed matches and assume compatibility Avoid error returns on a failure to match and instead just warn with assumption that we have a correct dt-binding telling us that some new device with a different ID is backwards compatible. Acked-by: Matti Vaittinen Signed-off-by: Mehdi Djait Link: https://lore.kernel.org/r/b587cfec2f3350623277005f62121864bee857c7.1694867379.git.mehdi.djait.k@gmail.com Signed-off-by: Jonathan Cameron --- drivers/iio/accel/kionix-kx022a.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/iio/accel/kionix-kx022a.c b/drivers/iio/accel/kionix-kx022a.c index 2f1e7da25460..5a144f86c634 100644 --- a/drivers/iio/accel/kionix-kx022a.c +++ b/drivers/iio/accel/kionix-kx022a.c @@ -1025,10 +1025,8 @@ int kx022a_probe_internal(struct device *dev) if (ret) return dev_err_probe(dev, ret, "Failed to access sensor\n"); - if (chip_id != KX022A_ID) { - dev_err(dev, "unsupported device 0x%x\n", chip_id); - return -EINVAL; - } + if (chip_id != KX022A_ID) + dev_warn(dev, "unknown device 0x%x\n", chip_id); irq = fwnode_irq_get_byname(fwnode, "INT1"); if (irq > 0) { From 13d5398a8eebcb19e3424979658d97fbe1b21891 Mon Sep 17 00:00:00 2001 From: Mehdi Djait Date: Sat, 16 Sep 2023 14:38:50 +0200 Subject: [PATCH 070/326] iio: accel: kionix-kx022a: Add an i2c_device_id table Add the missing i2c device id. Acked-by: Matti Vaittinen Signed-off-by: Mehdi Djait Link: https://lore.kernel.org/r/61b43bbf35d602eac34b6d81b4d1b2d7ba39786f.1694867379.git.mehdi.djait.k@gmail.com Signed-off-by: Jonathan Cameron --- drivers/iio/accel/kionix-kx022a-i2c.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/iio/accel/kionix-kx022a-i2c.c b/drivers/iio/accel/kionix-kx022a-i2c.c index b0ac78e85dad..c0d0b69680f9 100644 --- a/drivers/iio/accel/kionix-kx022a-i2c.c +++ b/drivers/iio/accel/kionix-kx022a-i2c.c @@ -30,6 +30,12 @@ static int kx022a_i2c_probe(struct i2c_client *i2c) return kx022a_probe_internal(dev); } +static const struct i2c_device_id kx022a_i2c_id[] = { + { .name = "kx022a" }, + { } +}; +MODULE_DEVICE_TABLE(i2c, kx022a_i2c_id); + static const struct of_device_id kx022a_of_match[] = { { .compatible = "kionix,kx022a", }, { } @@ -43,6 +49,7 @@ static struct i2c_driver kx022a_i2c_driver = { .probe_type = PROBE_PREFER_ASYNCHRONOUS, }, .probe = kx022a_i2c_probe, + .id_table = kx022a_i2c_id, }; module_i2c_driver(kx022a_i2c_driver); From e7123a4dfcd732c4d10620748588e3715f362802 Mon Sep 17 00:00:00 2001 From: Mehdi Djait Date: Sat, 16 Sep 2023 14:38:51 +0200 Subject: [PATCH 071/326] iio: accel: kionix-kx022a: Refactor driver and add chip_info structure Add the chip_info structure to the driver's private data to hold all the device specific infos. Refactor the kx022a driver implementation to make it more generic and extensible. Acked-by: Matti Vaittinen Signed-off-by: Mehdi Djait Link: https://lore.kernel.org/r/7a31d0cdefba15d7c791252ec8bc5db553b3996b.1694867379.git.mehdi.djait.k@gmail.com Signed-off-by: Jonathan Cameron --- drivers/iio/accel/kionix-kx022a-i2c.c | 13 ++- drivers/iio/accel/kionix-kx022a-spi.c | 13 ++- drivers/iio/accel/kionix-kx022a.c | 117 +++++++++++++++++--------- drivers/iio/accel/kionix-kx022a.h | 52 +++++++++++- 4 files changed, 143 insertions(+), 52 deletions(-) diff --git a/drivers/iio/accel/kionix-kx022a-i2c.c b/drivers/iio/accel/kionix-kx022a-i2c.c index c0d0b69680f9..2fdc4c1ab93f 100644 --- a/drivers/iio/accel/kionix-kx022a-i2c.c +++ b/drivers/iio/accel/kionix-kx022a-i2c.c @@ -15,6 +15,7 @@ static int kx022a_i2c_probe(struct i2c_client *i2c) { struct device *dev = &i2c->dev; + const struct kx022a_chip_info *chip_info; struct regmap *regmap; if (!i2c->irq) { @@ -22,22 +23,26 @@ static int kx022a_i2c_probe(struct i2c_client *i2c) return -EINVAL; } - regmap = devm_regmap_init_i2c(i2c, &kx022a_regmap); + chip_info = i2c_get_match_data(i2c); + if (!chip_info) + return -EINVAL; + + regmap = devm_regmap_init_i2c(i2c, chip_info->regmap_config); if (IS_ERR(regmap)) return dev_err_probe(dev, PTR_ERR(regmap), "Failed to initialize Regmap\n"); - return kx022a_probe_internal(dev); + return kx022a_probe_internal(dev, chip_info); } static const struct i2c_device_id kx022a_i2c_id[] = { - { .name = "kx022a" }, + { .name = "kx022a", .driver_data = (kernel_ulong_t)&kx022a_chip_info }, { } }; MODULE_DEVICE_TABLE(i2c, kx022a_i2c_id); static const struct of_device_id kx022a_of_match[] = { - { .compatible = "kionix,kx022a", }, + { .compatible = "kionix,kx022a", .data = &kx022a_chip_info }, { } }; MODULE_DEVICE_TABLE(of, kx022a_of_match); diff --git a/drivers/iio/accel/kionix-kx022a-spi.c b/drivers/iio/accel/kionix-kx022a-spi.c index f45a46899a5f..c21494ade157 100644 --- a/drivers/iio/accel/kionix-kx022a-spi.c +++ b/drivers/iio/accel/kionix-kx022a-spi.c @@ -15,6 +15,7 @@ static int kx022a_spi_probe(struct spi_device *spi) { struct device *dev = &spi->dev; + const struct kx022a_chip_info *chip_info; struct regmap *regmap; if (!spi->irq) { @@ -22,22 +23,26 @@ static int kx022a_spi_probe(struct spi_device *spi) return -EINVAL; } - regmap = devm_regmap_init_spi(spi, &kx022a_regmap); + chip_info = spi_get_device_match_data(spi); + if (!chip_info) + return -EINVAL; + + regmap = devm_regmap_init_spi(spi, chip_info->regmap_config); if (IS_ERR(regmap)) return dev_err_probe(dev, PTR_ERR(regmap), "Failed to initialize Regmap\n"); - return kx022a_probe_internal(dev); + return kx022a_probe_internal(dev, chip_info); } static const struct spi_device_id kx022a_id[] = { - { "kx022a" }, + { .name = "kx022a", .driver_data = (kernel_ulong_t)&kx022a_chip_info }, { } }; MODULE_DEVICE_TABLE(spi, kx022a_id); static const struct of_device_id kx022a_of_match[] = { - { .compatible = "kionix,kx022a", }, + { .compatible = "kionix,kx022a", .data = &kx022a_chip_info }, { } }; MODULE_DEVICE_TABLE(of, kx022a_of_match); diff --git a/drivers/iio/accel/kionix-kx022a.c b/drivers/iio/accel/kionix-kx022a.c index 5a144f86c634..448f1019e5bf 100644 --- a/drivers/iio/accel/kionix-kx022a.c +++ b/drivers/iio/accel/kionix-kx022a.c @@ -48,7 +48,7 @@ enum { KX022A_STATE_FIFO, }; -/* Regmap configs */ +/* kx022a Regmap configs */ static const struct regmap_range kx022a_volatile_ranges[] = { { .range_min = KX022A_REG_XHP_L, @@ -138,7 +138,7 @@ static const struct regmap_access_table kx022a_nir_regs = { .n_yes_ranges = ARRAY_SIZE(kx022a_noinc_read_ranges), }; -const struct regmap_config kx022a_regmap = { +static const struct regmap_config kx022a_regmap_config = { .reg_bits = 8, .val_bits = 8, .volatile_table = &kx022a_volatile_regs, @@ -149,10 +149,10 @@ const struct regmap_config kx022a_regmap = { .max_register = KX022A_MAX_REGISTER, .cache_type = REGCACHE_RBTREE, }; -EXPORT_SYMBOL_NS_GPL(kx022a_regmap, IIO_KX022A); struct kx022a_data { struct regmap *regmap; + const struct kx022a_chip_info *chip_info; struct iio_trigger *trig; struct device *dev; struct iio_mount_matrix orientation; @@ -175,6 +175,8 @@ struct kx022a_data { struct mutex mutex; u8 watermark; + __le16 *fifo_buffer; + /* 3 x 16bit accel data + timestamp */ __le16 buffer[8] __aligned(IIO_DMA_MINALIGN); struct { @@ -208,7 +210,7 @@ static const struct iio_chan_spec_ext_info kx022a_ext_info[] = { { } }; -#define KX022A_ACCEL_CHAN(axis, index) \ +#define KX022A_ACCEL_CHAN(axis, reg, index) \ { \ .type = IIO_ACCEL, \ .modified = 1, \ @@ -220,7 +222,7 @@ static const struct iio_chan_spec_ext_info kx022a_ext_info[] = { BIT(IIO_CHAN_INFO_SCALE) | \ BIT(IIO_CHAN_INFO_SAMP_FREQ), \ .ext_info = kx022a_ext_info, \ - .address = KX022A_REG_##axis##OUT_L, \ + .address = reg, \ .scan_index = index, \ .scan_type = { \ .sign = 's', \ @@ -231,9 +233,9 @@ static const struct iio_chan_spec_ext_info kx022a_ext_info[] = { } static const struct iio_chan_spec kx022a_channels[] = { - KX022A_ACCEL_CHAN(X, 0), - KX022A_ACCEL_CHAN(Y, 1), - KX022A_ACCEL_CHAN(Z, 2), + KX022A_ACCEL_CHAN(X, KX022A_REG_XOUT_L, 0), + KX022A_ACCEL_CHAN(Y, KX022A_REG_YOUT_L, 1), + KX022A_ACCEL_CHAN(Z, KX022A_REG_ZOUT_L, 2), IIO_CHAN_SOFT_TIMESTAMP(3), }; @@ -332,10 +334,10 @@ static int kx022a_turn_on_off_unlocked(struct kx022a_data *data, bool on) int ret; if (on) - ret = regmap_set_bits(data->regmap, KX022A_REG_CNTL, + ret = regmap_set_bits(data->regmap, data->chip_info->cntl, KX022A_MASK_PC1); else - ret = regmap_clear_bits(data->regmap, KX022A_REG_CNTL, + ret = regmap_clear_bits(data->regmap, data->chip_info->cntl, KX022A_MASK_PC1); if (ret) dev_err(data->dev, "Turn %s fail %d\n", str_on_off(on), ret); @@ -402,7 +404,7 @@ static int kx022a_write_raw(struct iio_dev *idev, break; ret = regmap_update_bits(data->regmap, - KX022A_REG_ODCNTL, + data->chip_info->odcntl, KX022A_MASK_ODR, n); data->odr_ns = kx022a_odrs[n]; kx022a_turn_on_unlock(data); @@ -423,7 +425,7 @@ static int kx022a_write_raw(struct iio_dev *idev, if (ret) break; - ret = regmap_update_bits(data->regmap, KX022A_REG_CNTL, + ret = regmap_update_bits(data->regmap, data->chip_info->cntl, KX022A_MASK_GSEL, n << KX022A_GSEL_SHIFT); kx022a_turn_on_unlock(data); @@ -445,7 +447,7 @@ static int kx022a_fifo_set_wmi(struct kx022a_data *data) threshold = data->watermark; - return regmap_update_bits(data->regmap, KX022A_REG_BUF_CNTL1, + return regmap_update_bits(data->regmap, data->chip_info->buf_cntl1, KX022A_MASK_WM_TH, threshold); } @@ -488,7 +490,7 @@ static int kx022a_read_raw(struct iio_dev *idev, return ret; case IIO_CHAN_INFO_SAMP_FREQ: - ret = regmap_read(data->regmap, KX022A_REG_ODCNTL, ®val); + ret = regmap_read(data->regmap, data->chip_info->odcntl, ®val); if (ret) return ret; @@ -503,7 +505,7 @@ static int kx022a_read_raw(struct iio_dev *idev, return IIO_VAL_INT_PLUS_MICRO; case IIO_CHAN_INFO_SCALE: - ret = regmap_read(data->regmap, KX022A_REG_CNTL, ®val); + ret = regmap_read(data->regmap, data->chip_info->cntl, ®val); if (ret < 0) return ret; @@ -519,8 +521,7 @@ static int kx022a_set_watermark(struct iio_dev *idev, unsigned int val) { struct kx022a_data *data = iio_priv(idev); - if (val > KX022A_FIFO_LENGTH) - val = KX022A_FIFO_LENGTH; + val = min(data->chip_info->fifo_length, val); mutex_lock(&data->mutex); data->watermark = val; @@ -581,7 +582,7 @@ static int kx022a_drop_fifo_contents(struct kx022a_data *data) */ data->timestamp = 0; - return regmap_write(data->regmap, KX022A_REG_BUF_CLEAR, 0x0); + return regmap_write(data->regmap, data->chip_info->buf_clear, 0x0); } static int __kx022a_fifo_flush(struct iio_dev *idev, unsigned int samples, @@ -589,7 +590,6 @@ static int __kx022a_fifo_flush(struct iio_dev *idev, unsigned int samples, { struct kx022a_data *data = iio_priv(idev); struct device *dev = regmap_get_device(data->regmap); - __le16 buffer[KX022A_FIFO_LENGTH * 3]; uint64_t sample_period; int count, fifo_bytes; bool renable = false; @@ -668,13 +668,13 @@ static int __kx022a_fifo_flush(struct iio_dev *idev, unsigned int samples, } fifo_bytes = count * KX022A_FIFO_SAMPLES_SIZE_BYTES; - ret = regmap_noinc_read(data->regmap, KX022A_REG_BUF_READ, - &buffer[0], fifo_bytes); + ret = regmap_noinc_read(data->regmap, data->chip_info->buf_read, + data->fifo_buffer, fifo_bytes); if (ret) goto renable_out; for (i = 0; i < count; i++) { - __le16 *sam = &buffer[i * 3]; + __le16 *sam = &data->fifo_buffer[i * 3]; __le16 *chs; int bit; @@ -721,10 +721,10 @@ static const struct iio_info kx022a_info = { static int kx022a_set_drdy_irq(struct kx022a_data *data, bool en) { if (en) - return regmap_set_bits(data->regmap, KX022A_REG_CNTL, + return regmap_set_bits(data->regmap, data->chip_info->cntl, KX022A_MASK_DRDY); - return regmap_clear_bits(data->regmap, KX022A_REG_CNTL, + return regmap_clear_bits(data->regmap, data->chip_info->cntl, KX022A_MASK_DRDY); } @@ -759,7 +759,7 @@ static int kx022a_fifo_disable(struct kx022a_data *data) if (ret) goto unlock_out; - ret = regmap_clear_bits(data->regmap, KX022A_REG_BUF_CNTL2, + ret = regmap_clear_bits(data->regmap, data->chip_info->buf_cntl2, KX022A_MASK_BUF_EN); if (ret) goto unlock_out; @@ -768,6 +768,8 @@ static int kx022a_fifo_disable(struct kx022a_data *data) kx022a_drop_fifo_contents(data); + kfree(data->fifo_buffer); + return kx022a_turn_on_unlock(data); unlock_out: @@ -790,6 +792,12 @@ static int kx022a_fifo_enable(struct kx022a_data *data) { int ret; + data->fifo_buffer = kmalloc_array(data->chip_info->fifo_length, + KX022A_FIFO_SAMPLES_SIZE_BYTES, + GFP_KERNEL); + if (!data->fifo_buffer) + return -ENOMEM; + ret = kx022a_turn_off_lock(data); if (ret) return ret; @@ -800,7 +808,7 @@ static int kx022a_fifo_enable(struct kx022a_data *data) goto unlock_out; /* Enable buffer */ - ret = regmap_set_bits(data->regmap, KX022A_REG_BUF_CNTL2, + ret = regmap_set_bits(data->regmap, data->chip_info->buf_cntl2, KX022A_MASK_BUF_EN); if (ret) goto unlock_out; @@ -846,7 +854,7 @@ static irqreturn_t kx022a_trigger_handler(int irq, void *p) struct kx022a_data *data = iio_priv(idev); int ret; - ret = regmap_bulk_read(data->regmap, KX022A_REG_XOUT_L, data->buffer, + ret = regmap_bulk_read(data->regmap, data->chip_info->xout_l, data->buffer, KX022A_FIFO_SAMPLES_SIZE_BYTES); if (ret < 0) goto err_read; @@ -894,7 +902,7 @@ static irqreturn_t kx022a_irq_thread_handler(int irq, void *private) if (data->state & KX022A_STATE_FIFO) { int ok; - ok = __kx022a_fifo_flush(idev, KX022A_FIFO_LENGTH, true); + ok = __kx022a_fifo_flush(idev, data->chip_info->fifo_length, true); if (ok > 0) ret = IRQ_HANDLED; } @@ -947,7 +955,7 @@ static int kx022a_chip_init(struct kx022a_data *data) int ret, val; /* Reset the senor */ - ret = regmap_write(data->regmap, KX022A_REG_CNTL2, KX022A_MASK_SRST); + ret = regmap_write(data->regmap, data->chip_info->cntl2, KX022A_MASK_SRST); if (ret) return ret; @@ -957,7 +965,7 @@ static int kx022a_chip_init(struct kx022a_data *data) */ msleep(1); - ret = regmap_read_poll_timeout(data->regmap, KX022A_REG_CNTL2, val, + ret = regmap_read_poll_timeout(data->regmap, data->chip_info->cntl2, val, !(val & KX022A_MASK_SRST), KX022A_SOFT_RESET_WAIT_TIME_US, KX022A_SOFT_RESET_TOTAL_WAIT_TIME_US); @@ -967,14 +975,14 @@ static int kx022a_chip_init(struct kx022a_data *data) return ret; } - ret = regmap_reinit_cache(data->regmap, &kx022a_regmap); + ret = regmap_reinit_cache(data->regmap, data->chip_info->regmap_config); if (ret) { dev_err(data->dev, "Failed to reinit reg cache\n"); return ret; } /* set data res 16bit */ - ret = regmap_set_bits(data->regmap, KX022A_REG_BUF_CNTL2, + ret = regmap_set_bits(data->regmap, data->chip_info->buf_cntl2, KX022A_MASK_BRES16); if (ret) { dev_err(data->dev, "Failed to set data resolution\n"); @@ -984,7 +992,31 @@ static int kx022a_chip_init(struct kx022a_data *data) return kx022a_prepare_irq_pin(data); } -int kx022a_probe_internal(struct device *dev) +const struct kx022a_chip_info kx022a_chip_info = { + .name = "kx022-accel", + .regmap_config = &kx022a_regmap_config, + .channels = kx022a_channels, + .num_channels = ARRAY_SIZE(kx022a_channels), + .fifo_length = KX022A_FIFO_LENGTH, + .who = KX022A_REG_WHO, + .id = KX022A_ID, + .cntl = KX022A_REG_CNTL, + .cntl2 = KX022A_REG_CNTL2, + .odcntl = KX022A_REG_ODCNTL, + .buf_cntl1 = KX022A_REG_BUF_CNTL1, + .buf_cntl2 = KX022A_REG_BUF_CNTL2, + .buf_clear = KX022A_REG_BUF_CLEAR, + .buf_status1 = KX022A_REG_BUF_STATUS_1, + .buf_read = KX022A_REG_BUF_READ, + .inc1 = KX022A_REG_INC1, + .inc4 = KX022A_REG_INC4, + .inc5 = KX022A_REG_INC5, + .inc6 = KX022A_REG_INC6, + .xout_l = KX022A_REG_XOUT_L, +}; +EXPORT_SYMBOL_NS_GPL(kx022a_chip_info, IIO_KX022A); + +int kx022a_probe_internal(struct device *dev, const struct kx022a_chip_info *chip_info) { static const char * const regulator_names[] = {"io-vdd", "vdd"}; struct iio_trigger *indio_trig; @@ -1011,6 +1043,7 @@ int kx022a_probe_internal(struct device *dev) return -ENOMEM; data = iio_priv(idev); + data->chip_info = chip_info; /* * VDD is the analog and digital domain voltage supply and @@ -1021,24 +1054,24 @@ int kx022a_probe_internal(struct device *dev) if (ret && ret != -ENODEV) return dev_err_probe(dev, ret, "failed to enable regulator\n"); - ret = regmap_read(regmap, KX022A_REG_WHO, &chip_id); + ret = regmap_read(regmap, chip_info->who, &chip_id); if (ret) return dev_err_probe(dev, ret, "Failed to access sensor\n"); - if (chip_id != KX022A_ID) + if (chip_id != chip_info->id) dev_warn(dev, "unknown device 0x%x\n", chip_id); irq = fwnode_irq_get_byname(fwnode, "INT1"); if (irq > 0) { - data->inc_reg = KX022A_REG_INC1; - data->ien_reg = KX022A_REG_INC4; + data->inc_reg = chip_info->inc1; + data->ien_reg = chip_info->inc4; } else { irq = fwnode_irq_get_byname(fwnode, "INT2"); if (irq < 0) return dev_err_probe(dev, irq, "No suitable IRQ\n"); - data->inc_reg = KX022A_REG_INC5; - data->ien_reg = KX022A_REG_INC6; + data->inc_reg = chip_info->inc5; + data->ien_reg = chip_info->inc6; } data->regmap = regmap; @@ -1047,9 +1080,9 @@ int kx022a_probe_internal(struct device *dev) data->odr_ns = KX022A_DEFAULT_PERIOD_NS; mutex_init(&data->mutex); - idev->channels = kx022a_channels; - idev->num_channels = ARRAY_SIZE(kx022a_channels); - idev->name = "kx022-accel"; + idev->channels = chip_info->channels; + idev->num_channels = chip_info->num_channels; + idev->name = chip_info->name; idev->info = &kx022a_info; idev->modes = INDIO_DIRECT_MODE | INDIO_BUFFER_SOFTWARE; idev->available_scan_masks = kx022a_scan_masks; diff --git a/drivers/iio/accel/kionix-kx022a.h b/drivers/iio/accel/kionix-kx022a.h index 12424649d438..92f69c33a53b 100644 --- a/drivers/iio/accel/kionix-kx022a.h +++ b/drivers/iio/accel/kionix-kx022a.h @@ -76,7 +76,55 @@ struct device; -int kx022a_probe_internal(struct device *dev); -extern const struct regmap_config kx022a_regmap; +/** + * struct kx022a_chip_info - Kionix accelerometer chip specific information + * + * @name: name of the device + * @regmap_config: pointer to register map configuration + * @channels: pointer to iio_chan_spec array + * @num_channels: number of iio_chan_spec channels + * @fifo_length: number of 16-bit samples in a full buffer + * @who: WHO_AM_I register + * @id: WHO_AM_I register value + * @cntl: control register 1 + * @cntl2: control register 2 + * @odcntl: output data control register + * @buf_cntl1: buffer control register 1 + * @buf_cntl2: buffer control register 2 + * @buf_clear: buffer clear register + * @buf_status1: buffer status register 1 + * @buf_read: buffer read register + * @inc1: interrupt control register 1 + * @inc4: interrupt control register 4 + * @inc5: interrupt control register 5 + * @inc6: interrupt control register 6 + * @xout_l: x-axis output least significant byte + */ +struct kx022a_chip_info { + const char *name; + const struct regmap_config *regmap_config; + const struct iio_chan_spec *channels; + unsigned int num_channels; + unsigned int fifo_length; + u8 who; + u8 id; + u8 cntl; + u8 cntl2; + u8 odcntl; + u8 buf_cntl1; + u8 buf_cntl2; + u8 buf_clear; + u8 buf_status1; + u8 buf_read; + u8 inc1; + u8 inc4; + u8 inc5; + u8 inc6; + u8 xout_l; +}; + +int kx022a_probe_internal(struct device *dev, const struct kx022a_chip_info *chip_info); + +extern const struct kx022a_chip_info kx022a_chip_info; #endif From 774c3fabc9ff5fd10e779a4322ee4cbc36272c07 Mon Sep 17 00:00:00 2001 From: Mehdi Djait Date: Sat, 16 Sep 2023 14:38:52 +0200 Subject: [PATCH 072/326] iio: accel: kionix-kx022a: Add a function to retrieve number of bytes in buffer Since Kionix accelerometers use various numbers of bits to report data, a device-specific function is required. Implement the function as a callback in the device-specific chip_info structure Reviewed-by: Matti Vaittinen Signed-off-by: Mehdi Djait Link: https://lore.kernel.org/r/9c550fb28e34915d473e379f812c7753f7643bae.1694867379.git.mehdi.djait.k@gmail.com Signed-off-by: Jonathan Cameron --- drivers/iio/accel/kionix-kx022a.c | 28 ++++++++++++++++++---------- drivers/iio/accel/kionix-kx022a.h | 6 ++++++ 2 files changed, 24 insertions(+), 10 deletions(-) diff --git a/drivers/iio/accel/kionix-kx022a.c b/drivers/iio/accel/kionix-kx022a.c index 448f1019e5bf..cc7134b1183b 100644 --- a/drivers/iio/accel/kionix-kx022a.c +++ b/drivers/iio/accel/kionix-kx022a.c @@ -585,26 +585,33 @@ static int kx022a_drop_fifo_contents(struct kx022a_data *data) return regmap_write(data->regmap, data->chip_info->buf_clear, 0x0); } +static int kx022a_get_fifo_bytes_available(struct kx022a_data *data) +{ + int ret, fifo_bytes; + + ret = regmap_read(data->regmap, KX022A_REG_BUF_STATUS_1, &fifo_bytes); + if (ret) { + dev_err(data->dev, "Error reading buffer status\n"); + return ret; + } + + if (fifo_bytes == KX022A_FIFO_FULL_VALUE) + return KX022A_FIFO_MAX_BYTES; + + return fifo_bytes; +} + static int __kx022a_fifo_flush(struct iio_dev *idev, unsigned int samples, bool irq) { struct kx022a_data *data = iio_priv(idev); - struct device *dev = regmap_get_device(data->regmap); uint64_t sample_period; int count, fifo_bytes; bool renable = false; int64_t tstamp; int ret, i; - ret = regmap_read(data->regmap, KX022A_REG_BUF_STATUS_1, &fifo_bytes); - if (ret) { - dev_err(dev, "Error reading buffer status\n"); - return ret; - } - - /* Let's not overflow if we for some reason get bogus value from i2c */ - if (fifo_bytes == KX022A_FIFO_FULL_VALUE) - fifo_bytes = KX022A_FIFO_MAX_BYTES; + fifo_bytes = data->chip_info->get_fifo_bytes_available(data); if (fifo_bytes % KX022A_FIFO_SAMPLES_SIZE_BYTES) dev_warn(data->dev, "Bad FIFO alignment. Data may be corrupt\n"); @@ -1013,6 +1020,7 @@ const struct kx022a_chip_info kx022a_chip_info = { .inc5 = KX022A_REG_INC5, .inc6 = KX022A_REG_INC6, .xout_l = KX022A_REG_XOUT_L, + .get_fifo_bytes_available = kx022a_get_fifo_bytes_available, }; EXPORT_SYMBOL_NS_GPL(kx022a_chip_info, IIO_KX022A); diff --git a/drivers/iio/accel/kionix-kx022a.h b/drivers/iio/accel/kionix-kx022a.h index 92f69c33a53b..7ca48e6f2c49 100644 --- a/drivers/iio/accel/kionix-kx022a.h +++ b/drivers/iio/accel/kionix-kx022a.h @@ -76,6 +76,8 @@ struct device; +struct kx022a_data; + /** * struct kx022a_chip_info - Kionix accelerometer chip specific information * @@ -99,6 +101,9 @@ struct device; * @inc5: interrupt control register 5 * @inc6: interrupt control register 6 * @xout_l: x-axis output least significant byte + * @get_fifo_bytes_available: function pointer to get amount of acceleration + * data bytes currently stored in the sensor's FIFO + * buffer */ struct kx022a_chip_info { const char *name; @@ -121,6 +126,7 @@ struct kx022a_chip_info { u8 inc5; u8 inc6; u8 xout_l; + int (*get_fifo_bytes_available)(struct kx022a_data *); }; int kx022a_probe_internal(struct device *dev, const struct kx022a_chip_info *chip_info); From e631f61f76329644dd4e88e83d6cca5c0b138949 Mon Sep 17 00:00:00 2001 From: Mehdi Djait Date: Sat, 16 Sep 2023 14:38:53 +0200 Subject: [PATCH 073/326] iio: accel: Add support for Kionix/ROHM KX132-1211 accelerometer MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Kionix KX132-1211 is a tri-axis 16-bit accelerometer that can support ranges from ±2G to ±16G, digital output through I²C/SPI. Add support for basic accelerometer features such as reading acceleration via IIO using raw reads, triggered buffer (data-ready), or the WMI IRQ. Datasheet: https://kionixfs.azureedge.net/en/document/KX132-1211-Technical-Reference-Manual-Rev-5.0.pdf Acked-by: Matti Vaittinen Reviewed-by: Andy Shevchenko Signed-off-by: Mehdi Djait Link: https://lore.kernel.org/r/389a7d6100ff2e71b1c5d60bebe662d09435996a.1694867379.git.mehdi.djait.k@gmail.com Signed-off-by: Jonathan Cameron --- drivers/iio/accel/Kconfig | 10 +- drivers/iio/accel/kionix-kx022a-i2c.c | 2 + drivers/iio/accel/kionix-kx022a-spi.c | 2 + drivers/iio/accel/kionix-kx022a.c | 164 ++++++++++++++++++++++++++ drivers/iio/accel/kionix-kx022a.h | 54 +++++++++ 5 files changed, 228 insertions(+), 4 deletions(-) diff --git a/drivers/iio/accel/Kconfig b/drivers/iio/accel/Kconfig index b6b45d359f28..373257d64a7e 100644 --- a/drivers/iio/accel/Kconfig +++ b/drivers/iio/accel/Kconfig @@ -418,8 +418,9 @@ config IIO_KX022A_SPI select IIO_KX022A select REGMAP_SPI help - Enable support for the Kionix KX022A digital tri-axis - accelerometer connected to I2C interface. + Enable support for the Kionix digital tri-axis accelerometers + connected to SPI interface. Supported devices are: + KX022A, KX132-1211 config IIO_KX022A_I2C tristate "Kionix KX022A tri-axis digital accelerometer I2C interface" @@ -427,8 +428,9 @@ config IIO_KX022A_I2C select IIO_KX022A select REGMAP_I2C help - Enable support for the Kionix KX022A digital tri-axis - accelerometer connected to I2C interface. + Enable support for the Kionix digital tri-axis accelerometers + connected to I2C interface. Supported devices are: + KX022A, KX132-1211 config KXSD9 tristate "Kionix KXSD9 Accelerometer Driver" diff --git a/drivers/iio/accel/kionix-kx022a-i2c.c b/drivers/iio/accel/kionix-kx022a-i2c.c index 2fdc4c1ab93f..fc53e527cae0 100644 --- a/drivers/iio/accel/kionix-kx022a-i2c.c +++ b/drivers/iio/accel/kionix-kx022a-i2c.c @@ -37,12 +37,14 @@ static int kx022a_i2c_probe(struct i2c_client *i2c) static const struct i2c_device_id kx022a_i2c_id[] = { { .name = "kx022a", .driver_data = (kernel_ulong_t)&kx022a_chip_info }, + { .name = "kx132-1211", .driver_data = (kernel_ulong_t)&kx132_chip_info }, { } }; MODULE_DEVICE_TABLE(i2c, kx022a_i2c_id); static const struct of_device_id kx022a_of_match[] = { { .compatible = "kionix,kx022a", .data = &kx022a_chip_info }, + { .compatible = "kionix,kx132-1211", .data = &kx132_chip_info }, { } }; MODULE_DEVICE_TABLE(of, kx022a_of_match); diff --git a/drivers/iio/accel/kionix-kx022a-spi.c b/drivers/iio/accel/kionix-kx022a-spi.c index c21494ade157..e7878ba67827 100644 --- a/drivers/iio/accel/kionix-kx022a-spi.c +++ b/drivers/iio/accel/kionix-kx022a-spi.c @@ -37,12 +37,14 @@ static int kx022a_spi_probe(struct spi_device *spi) static const struct spi_device_id kx022a_id[] = { { .name = "kx022a", .driver_data = (kernel_ulong_t)&kx022a_chip_info }, + { .name = "kx132-1211", .driver_data = (kernel_ulong_t)&kx132_chip_info }, { } }; MODULE_DEVICE_TABLE(spi, kx022a_id); static const struct of_device_id kx022a_of_match[] = { { .compatible = "kionix,kx022a", .data = &kx022a_chip_info }, + { .compatible = "kionix,kx132-1211", .data = &kx132_chip_info }, { } }; MODULE_DEVICE_TABLE(of, kx022a_of_match); diff --git a/drivers/iio/accel/kionix-kx022a.c b/drivers/iio/accel/kionix-kx022a.c index cc7134b1183b..c5b555094e60 100644 --- a/drivers/iio/accel/kionix-kx022a.c +++ b/drivers/iio/accel/kionix-kx022a.c @@ -150,6 +150,117 @@ static const struct regmap_config kx022a_regmap_config = { .cache_type = REGCACHE_RBTREE, }; +/* Regmap configs kx132 */ +static const struct regmap_range kx132_volatile_ranges[] = { + { + .range_min = KX132_REG_XADP_L, + .range_max = KX132_REG_COTR, + }, { + .range_min = KX132_REG_TSCP, + .range_max = KX132_REG_INT_REL, + }, { + /* The reset bit will be cleared by sensor */ + .range_min = KX132_REG_CNTL2, + .range_max = KX132_REG_CNTL2, + }, { + .range_min = KX132_REG_CNTL5, + .range_max = KX132_REG_CNTL5, + }, { + .range_min = KX132_REG_BUF_STATUS_1, + .range_max = KX132_REG_BUF_READ, + }, +}; + +static const struct regmap_access_table kx132_volatile_regs = { + .yes_ranges = &kx132_volatile_ranges[0], + .n_yes_ranges = ARRAY_SIZE(kx132_volatile_ranges), +}; + +static const struct regmap_range kx132_precious_ranges[] = { + { + .range_min = KX132_REG_INT_REL, + .range_max = KX132_REG_INT_REL, + }, +}; + +static const struct regmap_access_table kx132_precious_regs = { + .yes_ranges = &kx132_precious_ranges[0], + .n_yes_ranges = ARRAY_SIZE(kx132_precious_ranges), +}; + +static const struct regmap_range kx132_read_only_ranges[] = { + { + .range_min = KX132_REG_XADP_L, + .range_max = KX132_REG_INT_REL, + }, { + .range_min = KX132_REG_BUF_STATUS_1, + .range_max = KX132_REG_BUF_STATUS_2, + }, { + .range_min = KX132_REG_BUF_READ, + .range_max = KX132_REG_BUF_READ, + }, { + /* Kionix reserved registers: should not be written */ + .range_min = 0x28, + .range_max = 0x28, + }, { + .range_min = 0x35, + .range_max = 0x36, + }, { + .range_min = 0x3c, + .range_max = 0x48, + }, { + .range_min = 0x4e, + .range_max = 0x5c, + }, { + .range_min = 0x77, + .range_max = 0x7f, + }, +}; + +static const struct regmap_access_table kx132_ro_regs = { + .no_ranges = &kx132_read_only_ranges[0], + .n_no_ranges = ARRAY_SIZE(kx132_read_only_ranges), +}; + +static const struct regmap_range kx132_write_only_ranges[] = { + { + .range_min = KX132_REG_SELF_TEST, + .range_max = KX132_REG_SELF_TEST, + }, { + .range_min = KX132_REG_BUF_CLEAR, + .range_max = KX132_REG_BUF_CLEAR, + }, +}; + +static const struct regmap_access_table kx132_wo_regs = { + .no_ranges = &kx132_write_only_ranges[0], + .n_no_ranges = ARRAY_SIZE(kx132_write_only_ranges), +}; + +static const struct regmap_range kx132_noinc_read_ranges[] = { + { + .range_min = KX132_REG_BUF_READ, + .range_max = KX132_REG_BUF_READ, + }, +}; + +static const struct regmap_access_table kx132_nir_regs = { + .yes_ranges = &kx132_noinc_read_ranges[0], + .n_yes_ranges = ARRAY_SIZE(kx132_noinc_read_ranges), +}; + +static const struct regmap_config kx132_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + .volatile_table = &kx132_volatile_regs, + .rd_table = &kx132_wo_regs, + .wr_table = &kx132_ro_regs, + .rd_noinc_table = &kx132_nir_regs, + .precious_table = &kx132_precious_regs, + .max_register = KX132_MAX_REGISTER, + .cache_type = REGCACHE_RBTREE, +}; + struct kx022a_data { struct regmap *regmap; const struct kx022a_chip_info *chip_info; @@ -239,6 +350,13 @@ static const struct iio_chan_spec kx022a_channels[] = { IIO_CHAN_SOFT_TIMESTAMP(3), }; +static const struct iio_chan_spec kx132_channels[] = { + KX022A_ACCEL_CHAN(X, KX132_REG_XOUT_L, 0), + KX022A_ACCEL_CHAN(Y, KX132_REG_YOUT_L, 1), + KX022A_ACCEL_CHAN(Z, KX132_REG_ZOUT_L, 2), + IIO_CHAN_SOFT_TIMESTAMP(3), +}; + /* * The sensor HW can support ODR up to 1600 Hz, which is beyond what most of the * Linux CPUs can handle without dropping samples. Also, the low power mode is @@ -601,6 +719,26 @@ static int kx022a_get_fifo_bytes_available(struct kx022a_data *data) return fifo_bytes; } +static int kx132_get_fifo_bytes_available(struct kx022a_data *data) +{ + __le16 buf_status; + int ret, fifo_bytes; + + ret = regmap_bulk_read(data->regmap, data->chip_info->buf_status1, + &buf_status, sizeof(buf_status)); + if (ret) { + dev_err(data->dev, "Error reading buffer status\n"); + return ret; + } + + fifo_bytes = le16_to_cpu(buf_status); + fifo_bytes &= data->chip_info->buf_smp_lvl_mask; + fifo_bytes = min((unsigned int)fifo_bytes, data->chip_info->fifo_length * + KX022A_FIFO_SAMPLES_SIZE_BYTES); + + return fifo_bytes; +} + static int __kx022a_fifo_flush(struct iio_dev *idev, unsigned int samples, bool irq) { @@ -1024,6 +1162,32 @@ const struct kx022a_chip_info kx022a_chip_info = { }; EXPORT_SYMBOL_NS_GPL(kx022a_chip_info, IIO_KX022A); +const struct kx022a_chip_info kx132_chip_info = { + .name = "kx132-1211", + .regmap_config = &kx132_regmap_config, + .channels = kx132_channels, + .num_channels = ARRAY_SIZE(kx132_channels), + .fifo_length = KX132_FIFO_LENGTH, + .who = KX132_REG_WHO, + .id = KX132_ID, + .cntl = KX132_REG_CNTL, + .cntl2 = KX132_REG_CNTL2, + .odcntl = KX132_REG_ODCNTL, + .buf_cntl1 = KX132_REG_BUF_CNTL1, + .buf_cntl2 = KX132_REG_BUF_CNTL2, + .buf_clear = KX132_REG_BUF_CLEAR, + .buf_status1 = KX132_REG_BUF_STATUS_1, + .buf_smp_lvl_mask = KX132_MASK_BUF_SMP_LVL, + .buf_read = KX132_REG_BUF_READ, + .inc1 = KX132_REG_INC1, + .inc4 = KX132_REG_INC4, + .inc5 = KX132_REG_INC5, + .inc6 = KX132_REG_INC6, + .xout_l = KX132_REG_XOUT_L, + .get_fifo_bytes_available = kx132_get_fifo_bytes_available, +}; +EXPORT_SYMBOL_NS_GPL(kx132_chip_info, IIO_KX022A); + int kx022a_probe_internal(struct device *dev, const struct kx022a_chip_info *chip_info) { static const char * const regulator_names[] = {"io-vdd", "vdd"}; diff --git a/drivers/iio/accel/kionix-kx022a.h b/drivers/iio/accel/kionix-kx022a.h index 7ca48e6f2c49..35c548ae7eff 100644 --- a/drivers/iio/accel/kionix-kx022a.h +++ b/drivers/iio/accel/kionix-kx022a.h @@ -74,6 +74,57 @@ #define KX022A_REG_SELF_TEST 0x60 #define KX022A_MAX_REGISTER 0x60 +#define KX132_REG_WHO 0x13 +#define KX132_ID 0x3d + +#define KX132_FIFO_LENGTH 86 + +#define KX132_REG_CNTL 0x1b +#define KX132_REG_CNTL2 0x1c +#define KX132_REG_CNTL5 0x1f +#define KX132_MASK_RES BIT(6) +#define KX132_GSEL_2 0x0 +#define KX132_GSEL_4 BIT(3) +#define KX132_GSEL_8 BIT(4) +#define KX132_GSEL_16 GENMASK(4, 3) + +#define KX132_REG_INS2 0x17 +#define KX132_MASK_INS2_WMI BIT(5) + +#define KX132_REG_XADP_L 0x02 +#define KX132_REG_XOUT_L 0x08 +#define KX132_REG_YOUT_L 0x0a +#define KX132_REG_ZOUT_L 0x0c +#define KX132_REG_COTR 0x12 +#define KX132_REG_TSCP 0x14 +#define KX132_REG_INT_REL 0x1a + +#define KX132_REG_ODCNTL 0x21 + +#define KX132_REG_BTS_WUF_TH 0x4a + +#define KX132_REG_BUF_CNTL1 0x5e +#define KX132_REG_BUF_CNTL2 0x5f +#define KX132_REG_BUF_STATUS_1 0x60 +#define KX132_REG_BUF_STATUS_2 0x61 +#define KX132_MASK_BUF_SMP_LVL GENMASK(9, 0) +#define KX132_REG_BUF_CLEAR 0x62 +#define KX132_REG_BUF_READ 0x63 +#define KX132_ODR_SHIFT 3 +#define KX132_FIFO_MAX_WMI_TH 86 + +#define KX132_REG_INC1 0x22 +#define KX132_REG_INC5 0x26 +#define KX132_REG_INC6 0x27 +#define KX132_IPOL_LOW 0 +#define KX132_IPOL_HIGH KX022A_MASK_IPOL +#define KX132_ITYP_PULSE KX022A_MASK_ITYP + +#define KX132_REG_INC4 0x25 + +#define KX132_REG_SELF_TEST 0x5d +#define KX132_MAX_REGISTER 0x76 + struct device; struct kx022a_data; @@ -86,6 +137,7 @@ struct kx022a_data; * @channels: pointer to iio_chan_spec array * @num_channels: number of iio_chan_spec channels * @fifo_length: number of 16-bit samples in a full buffer + * @buf_smp_lvl_mask: buffer sample level mask * @who: WHO_AM_I register * @id: WHO_AM_I register value * @cntl: control register 1 @@ -111,6 +163,7 @@ struct kx022a_chip_info { const struct iio_chan_spec *channels; unsigned int num_channels; unsigned int fifo_length; + u16 buf_smp_lvl_mask; u8 who; u8 id; u8 cntl; @@ -132,5 +185,6 @@ struct kx022a_chip_info { int kx022a_probe_internal(struct device *dev, const struct kx022a_chip_info *chip_info); extern const struct kx022a_chip_info kx022a_chip_info; +extern const struct kx022a_chip_info kx132_chip_info; #endif From 53cb25c97be2fb859166f14c862f4d09e3c1e0c9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Tue, 19 Sep 2023 19:48:43 +0200 Subject: [PATCH 074/326] iio: accel: hid-sensor-accel-3d: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new() which already returns void. Eventually after all drivers are converted, .remove_new() will be renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20230919174931.1417681-2-u.kleine-koenig@pengutronix.de Signed-off-by: Jonathan Cameron --- drivers/iio/accel/hid-sensor-accel-3d.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/iio/accel/hid-sensor-accel-3d.c b/drivers/iio/accel/hid-sensor-accel-3d.c index 5eac7ea19993..9b7a73a4c48a 100644 --- a/drivers/iio/accel/hid-sensor-accel-3d.c +++ b/drivers/iio/accel/hid-sensor-accel-3d.c @@ -422,7 +422,7 @@ error_remove_trigger: } /* Function to deinitialize the processing for usage id */ -static int hid_accel_3d_remove(struct platform_device *pdev) +static void hid_accel_3d_remove(struct platform_device *pdev) { struct hid_sensor_hub_device *hsdev = pdev->dev.platform_data; struct iio_dev *indio_dev = platform_get_drvdata(pdev); @@ -431,8 +431,6 @@ static int hid_accel_3d_remove(struct platform_device *pdev) sensor_hub_remove_callback(hsdev, hsdev->usage); iio_device_unregister(indio_dev); hid_sensor_remove_trigger(indio_dev, &accel_state->common_attributes); - - return 0; } static const struct platform_device_id hid_accel_3d_ids[] = { @@ -454,7 +452,7 @@ static struct platform_driver hid_accel_3d_platform_driver = { .pm = &hid_sensor_pm_ops, }, .probe = hid_accel_3d_probe, - .remove = hid_accel_3d_remove, + .remove_new = hid_accel_3d_remove, }; module_platform_driver(hid_accel_3d_platform_driver); From 9cb1bcd4ea25b16035cb02b00b6c79d23a3a90f4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Tue, 19 Sep 2023 19:48:44 +0200 Subject: [PATCH 075/326] iio: adc: ab8500-gpadc: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new() which already returns void. Eventually after all drivers are converted, .remove_new() will be renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20230919174931.1417681-3-u.kleine-koenig@pengutronix.de Signed-off-by: Jonathan Cameron --- drivers/iio/adc/ab8500-gpadc.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/iio/adc/ab8500-gpadc.c b/drivers/iio/adc/ab8500-gpadc.c index 3b1bdd0b531d..80645fee79a4 100644 --- a/drivers/iio/adc/ab8500-gpadc.c +++ b/drivers/iio/adc/ab8500-gpadc.c @@ -1179,7 +1179,7 @@ out_dis_pm: return ret; } -static int ab8500_gpadc_remove(struct platform_device *pdev) +static void ab8500_gpadc_remove(struct platform_device *pdev) { struct iio_dev *indio_dev = platform_get_drvdata(pdev); struct ab8500_gpadc *gpadc = iio_priv(indio_dev); @@ -1188,8 +1188,6 @@ static int ab8500_gpadc_remove(struct platform_device *pdev) pm_runtime_put_noidle(gpadc->dev); pm_runtime_disable(gpadc->dev); regulator_disable(gpadc->vddadc); - - return 0; } static DEFINE_RUNTIME_DEV_PM_OPS(ab8500_gpadc_pm_ops, @@ -1198,7 +1196,7 @@ static DEFINE_RUNTIME_DEV_PM_OPS(ab8500_gpadc_pm_ops, static struct platform_driver ab8500_gpadc_driver = { .probe = ab8500_gpadc_probe, - .remove = ab8500_gpadc_remove, + .remove_new = ab8500_gpadc_remove, .driver = { .name = "ab8500-gpadc", .pm = pm_ptr(&ab8500_gpadc_pm_ops), From e5e92308c4691e39f57f3352ffd094ead4f4b569 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Tue, 19 Sep 2023 19:48:45 +0200 Subject: [PATCH 076/326] iio: adc: at91-sama5d2: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new() which already returns void. Eventually after all drivers are converted, .remove_new() will be renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20230919174931.1417681-4-u.kleine-koenig@pengutronix.de Signed-off-by: Jonathan Cameron --- drivers/iio/adc/at91-sama5d2_adc.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/iio/adc/at91-sama5d2_adc.c b/drivers/iio/adc/at91-sama5d2_adc.c index df67b63ccf69..d7fd21e7c6e2 100644 --- a/drivers/iio/adc/at91-sama5d2_adc.c +++ b/drivers/iio/adc/at91-sama5d2_adc.c @@ -2486,7 +2486,7 @@ reg_disable: return ret; } -static int at91_adc_remove(struct platform_device *pdev) +static void at91_adc_remove(struct platform_device *pdev) { struct iio_dev *indio_dev = platform_get_drvdata(pdev); struct at91_adc_state *st = iio_priv(indio_dev); @@ -2501,8 +2501,6 @@ static int at91_adc_remove(struct platform_device *pdev) regulator_disable(st->vref); regulator_disable(st->reg); - - return 0; } static int at91_adc_suspend(struct device *dev) @@ -2627,7 +2625,7 @@ MODULE_DEVICE_TABLE(of, at91_adc_dt_match); static struct platform_driver at91_adc_driver = { .probe = at91_adc_probe, - .remove = at91_adc_remove, + .remove_new = at91_adc_remove, .driver = { .name = "at91-sama5d2_adc", .of_match_table = at91_adc_dt_match, From 3624d5fd3be2e3320b96086dc2c5e6c57255b333 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Tue, 19 Sep 2023 19:48:46 +0200 Subject: [PATCH 077/326] iio: adc: at91: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new() which already returns void. Eventually after all drivers are converted, .remove_new() will be renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20230919174931.1417681-5-u.kleine-koenig@pengutronix.de Signed-off-by: Jonathan Cameron --- drivers/iio/adc/at91_adc.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/iio/adc/at91_adc.c b/drivers/iio/adc/at91_adc.c index 200c4599530b..eb501e3c86a5 100644 --- a/drivers/iio/adc/at91_adc.c +++ b/drivers/iio/adc/at91_adc.c @@ -1185,7 +1185,7 @@ error_iio_device_register: return ret; } -static int at91_adc_remove(struct platform_device *pdev) +static void at91_adc_remove(struct platform_device *pdev) { struct iio_dev *idev = platform_get_drvdata(pdev); struct at91_adc_state *st = iio_priv(idev); @@ -1197,8 +1197,6 @@ static int at91_adc_remove(struct platform_device *pdev) } else { at91_ts_unregister(st); } - - return 0; } static int at91_adc_suspend(struct device *dev) @@ -1348,7 +1346,7 @@ MODULE_DEVICE_TABLE(of, at91_adc_dt_ids); static struct platform_driver at91_adc_driver = { .probe = at91_adc_probe, - .remove = at91_adc_remove, + .remove_new = at91_adc_remove, .driver = { .name = DRIVER_NAME, .of_match_table = at91_adc_dt_ids, From 5ff1f754009b00a2352e17c22f224e9d77dc6fa9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Tue, 19 Sep 2023 19:48:47 +0200 Subject: [PATCH 078/326] iio: adc: axp20x: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new() which already returns void. Eventually after all drivers are converted, .remove_new() will be renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20230919174931.1417681-6-u.kleine-koenig@pengutronix.de Signed-off-by: Jonathan Cameron --- drivers/iio/adc/axp20x_adc.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/iio/adc/axp20x_adc.c b/drivers/iio/adc/axp20x_adc.c index 75bda94dbce1..d6c51b0f48e3 100644 --- a/drivers/iio/adc/axp20x_adc.c +++ b/drivers/iio/adc/axp20x_adc.c @@ -745,7 +745,7 @@ fail_map: return ret; } -static int axp20x_remove(struct platform_device *pdev) +static void axp20x_remove(struct platform_device *pdev) { struct iio_dev *indio_dev = platform_get_drvdata(pdev); struct axp20x_adc_iio *info = iio_priv(indio_dev); @@ -757,8 +757,6 @@ static int axp20x_remove(struct platform_device *pdev) if (info->data->adc_en2_mask) regmap_write(info->regmap, AXP20X_ADC_EN2, 0); - - return 0; } static struct platform_driver axp20x_adc_driver = { @@ -768,7 +766,7 @@ static struct platform_driver axp20x_adc_driver = { }, .id_table = axp20x_adc_id_match, .probe = axp20x_probe, - .remove = axp20x_remove, + .remove_new = axp20x_remove, }; module_platform_driver(axp20x_adc_driver); From bf7c022b58e3e62087d563b8b69ba8354bde1fe0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Tue, 19 Sep 2023 19:48:48 +0200 Subject: [PATCH 079/326] iio: adc: bcm_iproc: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new() which already returns void. Eventually after all drivers are converted, .remove_new() will be renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Reviewed-by: Florian Fainelli Link: https://lore.kernel.org/r/20230919174931.1417681-7-u.kleine-koenig@pengutronix.de Signed-off-by: Jonathan Cameron --- drivers/iio/adc/bcm_iproc_adc.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/iio/adc/bcm_iproc_adc.c b/drivers/iio/adc/bcm_iproc_adc.c index 0d6885413a7e..5bc514bd5ebc 100644 --- a/drivers/iio/adc/bcm_iproc_adc.c +++ b/drivers/iio/adc/bcm_iproc_adc.c @@ -594,7 +594,7 @@ err_adc_enable: return ret; } -static int iproc_adc_remove(struct platform_device *pdev) +static void iproc_adc_remove(struct platform_device *pdev) { struct iio_dev *indio_dev = platform_get_drvdata(pdev); struct iproc_adc_priv *adc_priv = iio_priv(indio_dev); @@ -602,8 +602,6 @@ static int iproc_adc_remove(struct platform_device *pdev) iio_device_unregister(indio_dev); iproc_adc_disable(indio_dev); clk_disable_unprepare(adc_priv->adc_clk); - - return 0; } static const struct of_device_id iproc_adc_of_match[] = { @@ -614,7 +612,7 @@ MODULE_DEVICE_TABLE(of, iproc_adc_of_match); static struct platform_driver iproc_adc_driver = { .probe = iproc_adc_probe, - .remove = iproc_adc_remove, + .remove_new = iproc_adc_remove, .driver = { .name = "iproc-static-adc", .of_match_table = iproc_adc_of_match, From cb299d2a561dfd6816d120deac096562d5f111b5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Tue, 19 Sep 2023 19:48:49 +0200 Subject: [PATCH 080/326] iio: adc: dln2: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new() which already returns void. Eventually after all drivers are converted, .remove_new() will be renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20230919174931.1417681-8-u.kleine-koenig@pengutronix.de Signed-off-by: Jonathan Cameron --- drivers/iio/adc/dln2-adc.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/iio/adc/dln2-adc.c b/drivers/iio/adc/dln2-adc.c index 97d162a3cba4..06cfbbabaf8d 100644 --- a/drivers/iio/adc/dln2-adc.c +++ b/drivers/iio/adc/dln2-adc.c @@ -691,19 +691,18 @@ unregister_event: return ret; } -static int dln2_adc_remove(struct platform_device *pdev) +static void dln2_adc_remove(struct platform_device *pdev) { struct iio_dev *indio_dev = platform_get_drvdata(pdev); iio_device_unregister(indio_dev); dln2_unregister_event_cb(pdev, DLN2_ADC_CONDITION_MET_EV); - return 0; } static struct platform_driver dln2_adc_driver = { .driver.name = DLN2_ADC_MOD_NAME, .probe = dln2_adc_probe, - .remove = dln2_adc_remove, + .remove_new = dln2_adc_remove, }; module_platform_driver(dln2_adc_driver); From b8943902874c363ea48c101838baf4933c44836b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Tue, 19 Sep 2023 19:48:50 +0200 Subject: [PATCH 081/326] iio: adc: ep93xx: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new() which already returns void. Eventually after all drivers are converted, .remove_new() will be renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Acked-by: Alexander Sverdlin Link: https://lore.kernel.org/r/20230919174931.1417681-9-u.kleine-koenig@pengutronix.de Signed-off-by: Jonathan Cameron --- drivers/iio/adc/ep93xx_adc.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/iio/adc/ep93xx_adc.c b/drivers/iio/adc/ep93xx_adc.c index a35e6cead67d..971942ce4c66 100644 --- a/drivers/iio/adc/ep93xx_adc.c +++ b/drivers/iio/adc/ep93xx_adc.c @@ -217,15 +217,13 @@ static int ep93xx_adc_probe(struct platform_device *pdev) return ret; } -static int ep93xx_adc_remove(struct platform_device *pdev) +static void ep93xx_adc_remove(struct platform_device *pdev) { struct iio_dev *iiodev = platform_get_drvdata(pdev); struct ep93xx_adc_priv *priv = iio_priv(iiodev); iio_device_unregister(iiodev); clk_disable_unprepare(priv->clk); - - return 0; } static const struct of_device_id ep93xx_adc_of_ids[] = { @@ -240,7 +238,7 @@ static struct platform_driver ep93xx_adc_driver = { .of_match_table = ep93xx_adc_of_ids, }, .probe = ep93xx_adc_probe, - .remove = ep93xx_adc_remove, + .remove_new = ep93xx_adc_remove, }; module_platform_driver(ep93xx_adc_driver); From 5c5b7b3f9e89a522ef026fc38c53e1827a731959 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Tue, 19 Sep 2023 19:48:51 +0200 Subject: [PATCH 082/326] iio: adc: exynos: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new() which already returns void. Eventually after all drivers are converted, .remove_new() will be renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20230919174931.1417681-10-u.kleine-koenig@pengutronix.de Signed-off-by: Jonathan Cameron --- drivers/iio/adc/exynos_adc.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/iio/adc/exynos_adc.c b/drivers/iio/adc/exynos_adc.c index cff1ba57fb16..eb7a2dd59517 100644 --- a/drivers/iio/adc/exynos_adc.c +++ b/drivers/iio/adc/exynos_adc.c @@ -946,7 +946,7 @@ err_disable_reg: return ret; } -static int exynos_adc_remove(struct platform_device *pdev) +static void exynos_adc_remove(struct platform_device *pdev) { struct iio_dev *indio_dev = platform_get_drvdata(pdev); struct exynos_adc *info = iio_priv(indio_dev); @@ -964,8 +964,6 @@ static int exynos_adc_remove(struct platform_device *pdev) exynos_adc_disable_clk(info); exynos_adc_unprepare_clk(info); regulator_disable(info->vdd); - - return 0; } static int exynos_adc_suspend(struct device *dev) @@ -1006,7 +1004,7 @@ static DEFINE_SIMPLE_DEV_PM_OPS(exynos_adc_pm_ops, exynos_adc_suspend, static struct platform_driver exynos_adc_driver = { .probe = exynos_adc_probe, - .remove = exynos_adc_remove, + .remove_new = exynos_adc_remove, .driver = { .name = "exynos-adc", .of_match_table = exynos_adc_match, From cfac92804fd394a1b9d962825b12c989c56e4149 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Tue, 19 Sep 2023 19:48:52 +0200 Subject: [PATCH 083/326] iio: adc: fsl-imx25-gcq: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new() which already returns void. Eventually after all drivers are converted, .remove_new() will be renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20230919174931.1417681-11-u.kleine-koenig@pengutronix.de Signed-off-by: Jonathan Cameron --- drivers/iio/adc/fsl-imx25-gcq.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/iio/adc/fsl-imx25-gcq.c b/drivers/iio/adc/fsl-imx25-gcq.c index 551e83ae573c..68c813de0605 100644 --- a/drivers/iio/adc/fsl-imx25-gcq.c +++ b/drivers/iio/adc/fsl-imx25-gcq.c @@ -384,7 +384,7 @@ err_regulator_disable: return ret; } -static int mx25_gcq_remove(struct platform_device *pdev) +static void mx25_gcq_remove(struct platform_device *pdev) { struct iio_dev *indio_dev = platform_get_drvdata(pdev); struct mx25_gcq_priv *priv = iio_priv(indio_dev); @@ -397,8 +397,6 @@ static int mx25_gcq_remove(struct platform_device *pdev) if (priv->vref[i]) regulator_disable(priv->vref[i]); } - - return 0; } static const struct of_device_id mx25_gcq_ids[] = { @@ -413,7 +411,7 @@ static struct platform_driver mx25_gcq_driver = { .of_match_table = mx25_gcq_ids, }, .probe = mx25_gcq_probe, - .remove = mx25_gcq_remove, + .remove_new = mx25_gcq_remove, }; module_platform_driver(mx25_gcq_driver); From b7962fc9a5130842786b141a8d9bbaae347d94af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Tue, 19 Sep 2023 19:48:53 +0200 Subject: [PATCH 084/326] iio: adc: hx711: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new() which already returns void. Eventually after all drivers are converted, .remove_new() will be renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20230919174931.1417681-12-u.kleine-koenig@pengutronix.de Signed-off-by: Jonathan Cameron --- drivers/iio/adc/hx711.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/iio/adc/hx711.c b/drivers/iio/adc/hx711.c index f7ee856a6b8b..c80c55fb8c6c 100644 --- a/drivers/iio/adc/hx711.c +++ b/drivers/iio/adc/hx711.c @@ -580,7 +580,7 @@ error_regulator: return ret; } -static int hx711_remove(struct platform_device *pdev) +static void hx711_remove(struct platform_device *pdev) { struct hx711_data *hx711_data; struct iio_dev *indio_dev; @@ -593,8 +593,6 @@ static int hx711_remove(struct platform_device *pdev) iio_triggered_buffer_cleanup(indio_dev); regulator_disable(hx711_data->reg_avdd); - - return 0; } static const struct of_device_id of_hx711_match[] = { @@ -606,7 +604,7 @@ MODULE_DEVICE_TABLE(of, of_hx711_match); static struct platform_driver hx711_driver = { .probe = hx711_probe, - .remove = hx711_remove, + .remove_new = hx711_remove, .driver = { .name = "hx711-gpio", .of_match_table = of_hx711_match, From 7ed89f54f62f8318a65049954a8929ea98c2fe19 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Tue, 19 Sep 2023 19:48:54 +0200 Subject: [PATCH 085/326] iio: adc: imx8qxp: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new() which already returns void. Eventually after all drivers are converted, .remove_new() will be renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20230919174931.1417681-13-u.kleine-koenig@pengutronix.de Signed-off-by: Jonathan Cameron --- drivers/iio/adc/imx8qxp-adc.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/iio/adc/imx8qxp-adc.c b/drivers/iio/adc/imx8qxp-adc.c index f5a0fc9e64c5..a180c6974d5b 100644 --- a/drivers/iio/adc/imx8qxp-adc.c +++ b/drivers/iio/adc/imx8qxp-adc.c @@ -404,7 +404,7 @@ error_regulator_disable: return ret; } -static int imx8qxp_adc_remove(struct platform_device *pdev) +static void imx8qxp_adc_remove(struct platform_device *pdev) { struct iio_dev *indio_dev = platform_get_drvdata(pdev); struct imx8qxp_adc *adc = iio_priv(indio_dev); @@ -422,8 +422,6 @@ static int imx8qxp_adc_remove(struct platform_device *pdev) pm_runtime_disable(dev); pm_runtime_put_noidle(dev); - - return 0; } static int imx8qxp_adc_runtime_suspend(struct device *dev) @@ -489,7 +487,7 @@ MODULE_DEVICE_TABLE(of, imx8qxp_adc_match); static struct platform_driver imx8qxp_adc_driver = { .probe = imx8qxp_adc_probe, - .remove = imx8qxp_adc_remove, + .remove_new = imx8qxp_adc_remove, .driver = { .name = ADC_DRIVER_NAME, .of_match_table = imx8qxp_adc_match, From 71e79bb48f2dd8147e13d574894c6b9641d843b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Tue, 19 Sep 2023 19:48:55 +0200 Subject: [PATCH 086/326] iio: adc: imx93: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new() which already returns void. Eventually after all drivers are converted, .remove_new() will be renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20230919174931.1417681-14-u.kleine-koenig@pengutronix.de Signed-off-by: Jonathan Cameron --- drivers/iio/adc/imx93_adc.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/iio/adc/imx93_adc.c b/drivers/iio/adc/imx93_adc.c index dce9ec91e4a7..9bb1e4ba1aee 100644 --- a/drivers/iio/adc/imx93_adc.c +++ b/drivers/iio/adc/imx93_adc.c @@ -392,7 +392,7 @@ error_regulator_disable: return ret; } -static int imx93_adc_remove(struct platform_device *pdev) +static void imx93_adc_remove(struct platform_device *pdev) { struct iio_dev *indio_dev = platform_get_drvdata(pdev); struct imx93_adc *adc = iio_priv(indio_dev); @@ -410,8 +410,6 @@ static int imx93_adc_remove(struct platform_device *pdev) free_irq(adc->irq, adc); clk_disable_unprepare(adc->ipg_clk); regulator_disable(adc->vref); - - return 0; } static int imx93_adc_runtime_suspend(struct device *dev) @@ -468,7 +466,7 @@ MODULE_DEVICE_TABLE(of, imx93_adc_match); static struct platform_driver imx93_adc_driver = { .probe = imx93_adc_probe, - .remove = imx93_adc_remove, + .remove_new = imx93_adc_remove, .driver = { .name = IMX93_ADC_DRIVER_NAME, .of_match_table = imx93_adc_match, From c0fe02aa5e69f3c09f72b943b8d0ad24c00d9a3f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Tue, 19 Sep 2023 19:48:56 +0200 Subject: [PATCH 087/326] iio: adc: meson_saradc: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new() which already returns void. Eventually after all drivers are converted, .remove_new() will be renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20230919174931.1417681-15-u.kleine-koenig@pengutronix.de Signed-off-by: Jonathan Cameron --- drivers/iio/adc/meson_saradc.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/iio/adc/meson_saradc.c b/drivers/iio/adc/meson_saradc.c index 320e3e7e3d4d..a40986fb285c 100644 --- a/drivers/iio/adc/meson_saradc.c +++ b/drivers/iio/adc/meson_saradc.c @@ -1437,15 +1437,13 @@ err: return ret; } -static int meson_sar_adc_remove(struct platform_device *pdev) +static void meson_sar_adc_remove(struct platform_device *pdev) { struct iio_dev *indio_dev = platform_get_drvdata(pdev); iio_device_unregister(indio_dev); meson_sar_adc_hw_disable(indio_dev); - - return 0; } static int meson_sar_adc_suspend(struct device *dev) @@ -1480,7 +1478,7 @@ static DEFINE_SIMPLE_DEV_PM_OPS(meson_sar_adc_pm_ops, static struct platform_driver meson_sar_adc_driver = { .probe = meson_sar_adc_probe, - .remove = meson_sar_adc_remove, + .remove_new = meson_sar_adc_remove, .driver = { .name = "meson-saradc", .of_match_table = meson_sar_adc_of_match, From 9e7e402055bd9d611f1779df1dd2758668cefb3a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Tue, 19 Sep 2023 19:48:57 +0200 Subject: [PATCH 088/326] iio: adc: mp2629: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new() which already returns void. Eventually after all drivers are converted, .remove_new() will be renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20230919174931.1417681-16-u.kleine-koenig@pengutronix.de Signed-off-by: Jonathan Cameron --- drivers/iio/adc/mp2629_adc.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/iio/adc/mp2629_adc.c b/drivers/iio/adc/mp2629_adc.c index 88e947f300cf..7c66c2cd5be2 100644 --- a/drivers/iio/adc/mp2629_adc.c +++ b/drivers/iio/adc/mp2629_adc.c @@ -171,7 +171,7 @@ fail_disable: return ret; } -static int mp2629_adc_remove(struct platform_device *pdev) +static void mp2629_adc_remove(struct platform_device *pdev) { struct iio_dev *indio_dev = platform_get_drvdata(pdev); struct mp2629_adc *info = iio_priv(indio_dev); @@ -184,8 +184,6 @@ static int mp2629_adc_remove(struct platform_device *pdev) MP2629_ADC_CONTINUOUS, 0); regmap_update_bits(info->regmap, MP2629_REG_ADC_CTRL, MP2629_ADC_START, 0); - - return 0; } static const struct of_device_id mp2629_adc_of_match[] = { @@ -200,7 +198,7 @@ static struct platform_driver mp2629_adc_driver = { .of_match_table = mp2629_adc_of_match, }, .probe = mp2629_adc_probe, - .remove = mp2629_adc_remove, + .remove_new = mp2629_adc_remove, }; module_platform_driver(mp2629_adc_driver); From a72e156f53095b1893a9a133744e454879992f76 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Tue, 19 Sep 2023 19:48:58 +0200 Subject: [PATCH 089/326] iio: adc: mxs-lradc: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new() which already returns void. Eventually after all drivers are converted, .remove_new() will be renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20230919174931.1417681-17-u.kleine-koenig@pengutronix.de Signed-off-by: Jonathan Cameron --- drivers/iio/adc/mxs-lradc-adc.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/iio/adc/mxs-lradc-adc.c b/drivers/iio/adc/mxs-lradc-adc.c index a50f39143d3e..2e60c10ee4ff 100644 --- a/drivers/iio/adc/mxs-lradc-adc.c +++ b/drivers/iio/adc/mxs-lradc-adc.c @@ -807,7 +807,7 @@ err_trig: return ret; } -static int mxs_lradc_adc_remove(struct platform_device *pdev) +static void mxs_lradc_adc_remove(struct platform_device *pdev) { struct iio_dev *iio = platform_get_drvdata(pdev); struct mxs_lradc_adc *adc = iio_priv(iio); @@ -816,8 +816,6 @@ static int mxs_lradc_adc_remove(struct platform_device *pdev) mxs_lradc_adc_hw_stop(adc); iio_triggered_buffer_cleanup(iio); mxs_lradc_adc_trigger_remove(iio); - - return 0; } static struct platform_driver mxs_lradc_adc_driver = { @@ -825,7 +823,7 @@ static struct platform_driver mxs_lradc_adc_driver = { .name = "mxs-lradc-adc", }, .probe = mxs_lradc_adc_probe, - .remove = mxs_lradc_adc_remove, + .remove_new = mxs_lradc_adc_remove, }; module_platform_driver(mxs_lradc_adc_driver); From 5253a5cc7709688b9a000f7928bfaa3366d0af98 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Tue, 19 Sep 2023 19:48:59 +0200 Subject: [PATCH 090/326] iio: adc: npcm: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new() which already returns void. Eventually after all drivers are converted, .remove_new() will be renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20230919174931.1417681-18-u.kleine-koenig@pengutronix.de Signed-off-by: Jonathan Cameron --- drivers/iio/adc/npcm_adc.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/iio/adc/npcm_adc.c b/drivers/iio/adc/npcm_adc.c index 3d9207c160eb..3a55465951e7 100644 --- a/drivers/iio/adc/npcm_adc.c +++ b/drivers/iio/adc/npcm_adc.c @@ -320,7 +320,7 @@ err_disable_clk: return ret; } -static int npcm_adc_remove(struct platform_device *pdev) +static void npcm_adc_remove(struct platform_device *pdev) { struct iio_dev *indio_dev = platform_get_drvdata(pdev); struct npcm_adc *info = iio_priv(indio_dev); @@ -333,13 +333,11 @@ static int npcm_adc_remove(struct platform_device *pdev) if (!IS_ERR(info->vref)) regulator_disable(info->vref); clk_disable_unprepare(info->adc_clk); - - return 0; } static struct platform_driver npcm_adc_driver = { .probe = npcm_adc_probe, - .remove = npcm_adc_remove, + .remove_new = npcm_adc_remove, .driver = { .name = "npcm_adc", .of_match_table = npcm_adc_match, From 0de6e194459168c804816abb08e9d955da73b40c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Tue, 19 Sep 2023 19:49:00 +0200 Subject: [PATCH 091/326] iio: adc: qcom-pm8xxx-xoadc: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new() which already returns void. Eventually after all drivers are converted, .remove_new() will be renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Reviewed-by: Konrad Dybcio Link: https://lore.kernel.org/r/20230919174931.1417681-19-u.kleine-koenig@pengutronix.de Signed-off-by: Jonathan Cameron --- drivers/iio/adc/qcom-pm8xxx-xoadc.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/iio/adc/qcom-pm8xxx-xoadc.c b/drivers/iio/adc/qcom-pm8xxx-xoadc.c index 64a3aeb6261c..01c5586df56d 100644 --- a/drivers/iio/adc/qcom-pm8xxx-xoadc.c +++ b/drivers/iio/adc/qcom-pm8xxx-xoadc.c @@ -957,7 +957,7 @@ out_disable_vref: return ret; } -static int pm8xxx_xoadc_remove(struct platform_device *pdev) +static void pm8xxx_xoadc_remove(struct platform_device *pdev) { struct iio_dev *indio_dev = platform_get_drvdata(pdev); struct pm8xxx_xoadc *adc = iio_priv(indio_dev); @@ -965,8 +965,6 @@ static int pm8xxx_xoadc_remove(struct platform_device *pdev) iio_device_unregister(indio_dev); regulator_disable(adc->vref); - - return 0; } static const struct xoadc_variant pm8018_variant = { @@ -1019,7 +1017,7 @@ static struct platform_driver pm8xxx_xoadc_driver = { .of_match_table = pm8xxx_xoadc_id_table, }, .probe = pm8xxx_xoadc_probe, - .remove = pm8xxx_xoadc_remove, + .remove_new = pm8xxx_xoadc_remove, }; module_platform_driver(pm8xxx_xoadc_driver); From e785bace1a77a31c3853f01735e651c9c2b43b03 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Tue, 19 Sep 2023 19:49:01 +0200 Subject: [PATCH 092/326] iio: adc: rcar-gyroadc: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new() which already returns void. Eventually after all drivers are converted, .remove_new() will be renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20230919174931.1417681-20-u.kleine-koenig@pengutronix.de Signed-off-by: Jonathan Cameron --- drivers/iio/adc/rcar-gyroadc.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/iio/adc/rcar-gyroadc.c b/drivers/iio/adc/rcar-gyroadc.c index b8972f673c9d..d524f2e8e927 100644 --- a/drivers/iio/adc/rcar-gyroadc.c +++ b/drivers/iio/adc/rcar-gyroadc.c @@ -559,7 +559,7 @@ err_clk_if_enable: return ret; } -static int rcar_gyroadc_remove(struct platform_device *pdev) +static void rcar_gyroadc_remove(struct platform_device *pdev) { struct iio_dev *indio_dev = platform_get_drvdata(pdev); struct rcar_gyroadc *priv = iio_priv(indio_dev); @@ -573,8 +573,6 @@ static int rcar_gyroadc_remove(struct platform_device *pdev) pm_runtime_set_suspended(dev); clk_disable_unprepare(priv->clk); rcar_gyroadc_deinit_supplies(indio_dev); - - return 0; } static int rcar_gyroadc_suspend(struct device *dev) @@ -603,7 +601,7 @@ static const struct dev_pm_ops rcar_gyroadc_pm_ops = { static struct platform_driver rcar_gyroadc_driver = { .probe = rcar_gyroadc_probe, - .remove = rcar_gyroadc_remove, + .remove_new = rcar_gyroadc_remove, .driver = { .name = DRIVER_NAME, .of_match_table = rcar_gyroadc_match, From eedcd8c7327f27924048ebdf2532ee7004c668e4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Tue, 19 Sep 2023 19:49:02 +0200 Subject: [PATCH 093/326] iio: adc: stm32-adc-core: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new() which already returns void. Eventually after all drivers are converted, .remove_new() will be renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20230919174931.1417681-21-u.kleine-koenig@pengutronix.de Signed-off-by: Jonathan Cameron --- drivers/iio/adc/stm32-adc-core.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/iio/adc/stm32-adc-core.c b/drivers/iio/adc/stm32-adc-core.c index bbd5bdd732f0..c19506b0aac8 100644 --- a/drivers/iio/adc/stm32-adc-core.c +++ b/drivers/iio/adc/stm32-adc-core.c @@ -819,7 +819,7 @@ err_pm_stop: return ret; } -static int stm32_adc_remove(struct platform_device *pdev) +static void stm32_adc_remove(struct platform_device *pdev) { struct stm32_adc_common *common = platform_get_drvdata(pdev); struct stm32_adc_priv *priv = to_stm32_adc_priv(common); @@ -831,8 +831,6 @@ static int stm32_adc_remove(struct platform_device *pdev) pm_runtime_disable(&pdev->dev); pm_runtime_set_suspended(&pdev->dev); pm_runtime_put_noidle(&pdev->dev); - - return 0; } static int stm32_adc_core_runtime_suspend(struct device *dev) @@ -913,7 +911,7 @@ MODULE_DEVICE_TABLE(of, stm32_adc_of_match); static struct platform_driver stm32_adc_driver = { .probe = stm32_adc_probe, - .remove = stm32_adc_remove, + .remove_new = stm32_adc_remove, .driver = { .name = "stm32-adc-core", .of_match_table = stm32_adc_of_match, From da8431b4fd160ac9f13c8ca2bef04d89ff559a67 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Tue, 19 Sep 2023 19:49:03 +0200 Subject: [PATCH 094/326] iio: adc: stm32-adc: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new() which already returns void. Eventually after all drivers are converted, .remove_new() will be renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20230919174931.1417681-22-u.kleine-koenig@pengutronix.de Signed-off-by: Jonathan Cameron --- drivers/iio/adc/stm32-adc.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/iio/adc/stm32-adc.c b/drivers/iio/adc/stm32-adc.c index f7613efb870d..25a912805439 100644 --- a/drivers/iio/adc/stm32-adc.c +++ b/drivers/iio/adc/stm32-adc.c @@ -2513,7 +2513,7 @@ err_dma_disable: return ret; } -static int stm32_adc_remove(struct platform_device *pdev) +static void stm32_adc_remove(struct platform_device *pdev) { struct iio_dev *indio_dev = platform_get_drvdata(pdev); struct stm32_adc *adc = iio_priv(indio_dev); @@ -2532,8 +2532,6 @@ static int stm32_adc_remove(struct platform_device *pdev) adc->rx_buf, adc->rx_dma_buf); dma_release_channel(adc->dma_chan); } - - return 0; } static int stm32_adc_suspend(struct device *dev) @@ -2659,7 +2657,7 @@ MODULE_DEVICE_TABLE(of, stm32_adc_of_match); static struct platform_driver stm32_adc_driver = { .probe = stm32_adc_probe, - .remove = stm32_adc_remove, + .remove_new = stm32_adc_remove, .driver = { .name = "stm32-adc", .of_match_table = stm32_adc_of_match, From cd918e75b42e24bac86d1b33118b936cff3bb3bd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Tue, 19 Sep 2023 19:49:04 +0200 Subject: [PATCH 095/326] iio: adc: stm32-dfsdm-adc: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new() which already returns void. Eventually after all drivers are converted, .remove_new() will be renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20230919174931.1417681-23-u.kleine-koenig@pengutronix.de Signed-off-by: Jonathan Cameron --- drivers/iio/adc/stm32-dfsdm-adc.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/iio/adc/stm32-dfsdm-adc.c b/drivers/iio/adc/stm32-dfsdm-adc.c index b5cc43d12b6f..ca08ae3108b2 100644 --- a/drivers/iio/adc/stm32-dfsdm-adc.c +++ b/drivers/iio/adc/stm32-dfsdm-adc.c @@ -1620,7 +1620,7 @@ err_cleanup: return ret; } -static int stm32_dfsdm_adc_remove(struct platform_device *pdev) +static void stm32_dfsdm_adc_remove(struct platform_device *pdev) { struct iio_dev *indio_dev = platform_get_drvdata(pdev); struct stm32_dfsdm_adc *adc = iio_priv(indio_dev); @@ -1629,8 +1629,6 @@ static int stm32_dfsdm_adc_remove(struct platform_device *pdev) of_platform_depopulate(&pdev->dev); iio_device_unregister(indio_dev); stm32_dfsdm_dma_release(indio_dev); - - return 0; } static int stm32_dfsdm_adc_suspend(struct device *dev) @@ -1677,7 +1675,7 @@ static struct platform_driver stm32_dfsdm_adc_driver = { .pm = pm_sleep_ptr(&stm32_dfsdm_adc_pm_ops), }, .probe = stm32_dfsdm_adc_probe, - .remove = stm32_dfsdm_adc_remove, + .remove_new = stm32_dfsdm_adc_remove, }; module_platform_driver(stm32_dfsdm_adc_driver); From 259fbaecb7b56c202ff4fae9a4ad98df3de28b22 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Tue, 19 Sep 2023 19:49:05 +0200 Subject: [PATCH 096/326] iio: adc: stm32-dfsdm-core: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new() which already returns void. Eventually after all drivers are converted, .remove_new() will be renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20230919174931.1417681-24-u.kleine-koenig@pengutronix.de Signed-off-by: Jonathan Cameron --- drivers/iio/adc/stm32-dfsdm-core.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/iio/adc/stm32-dfsdm-core.c b/drivers/iio/adc/stm32-dfsdm-core.c index 0f6ebb3061a0..a05d978b8cb8 100644 --- a/drivers/iio/adc/stm32-dfsdm-core.c +++ b/drivers/iio/adc/stm32-dfsdm-core.c @@ -436,7 +436,7 @@ pm_put: return ret; } -static int stm32_dfsdm_core_remove(struct platform_device *pdev) +static void stm32_dfsdm_core_remove(struct platform_device *pdev) { struct stm32_dfsdm *dfsdm = platform_get_drvdata(pdev); @@ -446,8 +446,6 @@ static int stm32_dfsdm_core_remove(struct platform_device *pdev) pm_runtime_set_suspended(&pdev->dev); pm_runtime_put_noidle(&pdev->dev); stm32_dfsdm_clk_disable_unprepare(dfsdm); - - return 0; } static int stm32_dfsdm_core_suspend(struct device *dev) @@ -508,7 +506,7 @@ static const struct dev_pm_ops stm32_dfsdm_core_pm_ops = { static struct platform_driver stm32_dfsdm_driver = { .probe = stm32_dfsdm_probe, - .remove = stm32_dfsdm_core_remove, + .remove_new = stm32_dfsdm_core_remove, .driver = { .name = "stm32-dfsdm", .of_match_table = stm32_dfsdm_of_match, From 794c760fd3da939db6fdd903d190a68838b86aa3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Tue, 19 Sep 2023 19:49:06 +0200 Subject: [PATCH 097/326] iio: adc: sun4i-gpadc-iio: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new() which already returns void. Eventually after all drivers are converted, .remove_new() will be renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Acked-by: Jernej Skrabec Link: https://lore.kernel.org/r/20230919174931.1417681-25-u.kleine-koenig@pengutronix.de Signed-off-by: Jonathan Cameron --- drivers/iio/adc/sun4i-gpadc-iio.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/drivers/iio/adc/sun4i-gpadc-iio.c b/drivers/iio/adc/sun4i-gpadc-iio.c index 25bba96367a8..100ecced5fc1 100644 --- a/drivers/iio/adc/sun4i-gpadc-iio.c +++ b/drivers/iio/adc/sun4i-gpadc-iio.c @@ -669,7 +669,7 @@ err_map: return ret; } -static int sun4i_gpadc_remove(struct platform_device *pdev) +static void sun4i_gpadc_remove(struct platform_device *pdev) { struct iio_dev *indio_dev = platform_get_drvdata(pdev); struct sun4i_gpadc_iio *info = iio_priv(indio_dev); @@ -678,12 +678,10 @@ static int sun4i_gpadc_remove(struct platform_device *pdev) pm_runtime_disable(&pdev->dev); if (!IS_ENABLED(CONFIG_THERMAL_OF)) - return 0; + return; if (!info->no_irq) iio_map_array_unregister(indio_dev); - - return 0; } static const struct platform_device_id sun4i_gpadc_id[] = { @@ -702,7 +700,7 @@ static struct platform_driver sun4i_gpadc_driver = { }, .id_table = sun4i_gpadc_id, .probe = sun4i_gpadc_probe, - .remove = sun4i_gpadc_remove, + .remove_new = sun4i_gpadc_remove, }; MODULE_DEVICE_TABLE(of, sun4i_gpadc_of_id); From e4bd0e6040e93f4895371abd4fca7291a5c5e9ef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Tue, 19 Sep 2023 19:49:07 +0200 Subject: [PATCH 098/326] iio: adc: ti_am335x_adc: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new() which already returns void. Eventually after all drivers are converted, .remove_new() will be renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20230919174931.1417681-26-u.kleine-koenig@pengutronix.de Signed-off-by: Jonathan Cameron --- drivers/iio/adc/ti_am335x_adc.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/iio/adc/ti_am335x_adc.c b/drivers/iio/adc/ti_am335x_adc.c index 8db7a01cb5fb..c755e8cd5220 100644 --- a/drivers/iio/adc/ti_am335x_adc.c +++ b/drivers/iio/adc/ti_am335x_adc.c @@ -681,7 +681,7 @@ err_dma: return err; } -static int tiadc_remove(struct platform_device *pdev) +static void tiadc_remove(struct platform_device *pdev) { struct iio_dev *indio_dev = platform_get_drvdata(pdev); struct tiadc_device *adc_dev = iio_priv(indio_dev); @@ -697,8 +697,6 @@ static int tiadc_remove(struct platform_device *pdev) step_en = get_adc_step_mask(adc_dev); am335x_tsc_se_clr(adc_dev->mfd_tscadc, step_en); - - return 0; } static int tiadc_suspend(struct device *dev) @@ -747,7 +745,7 @@ static struct platform_driver tiadc_driver = { .of_match_table = ti_adc_dt_ids, }, .probe = tiadc_probe, - .remove = tiadc_remove, + .remove_new = tiadc_remove, }; module_platform_driver(tiadc_driver); From 30ff88e96b5e9ff1d190bbce6caa80a2265d9a43 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Tue, 19 Sep 2023 19:49:08 +0200 Subject: [PATCH 099/326] iio: adc: twl4030-madc: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new() which already returns void. Eventually after all drivers are converted, .remove_new() will be renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20230919174931.1417681-27-u.kleine-koenig@pengutronix.de Signed-off-by: Jonathan Cameron --- drivers/iio/adc/twl4030-madc.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/iio/adc/twl4030-madc.c b/drivers/iio/adc/twl4030-madc.c index c279c4f2c9b7..4a247ca25a44 100644 --- a/drivers/iio/adc/twl4030-madc.c +++ b/drivers/iio/adc/twl4030-madc.c @@ -892,7 +892,7 @@ err_current_generator: return ret; } -static int twl4030_madc_remove(struct platform_device *pdev) +static void twl4030_madc_remove(struct platform_device *pdev) { struct iio_dev *iio_dev = platform_get_drvdata(pdev); struct twl4030_madc_data *madc = iio_priv(iio_dev); @@ -903,8 +903,6 @@ static int twl4030_madc_remove(struct platform_device *pdev) twl4030_madc_set_power(madc, 0); regulator_disable(madc->usb3v1); - - return 0; } #ifdef CONFIG_OF @@ -917,7 +915,7 @@ MODULE_DEVICE_TABLE(of, twl_madc_of_match); static struct platform_driver twl4030_madc_driver = { .probe = twl4030_madc_probe, - .remove = twl4030_madc_remove, + .remove_new = twl4030_madc_remove, .driver = { .name = "twl4030_madc", .of_match_table = of_match_ptr(twl_madc_of_match), From d355c20e710edf9242c5e5ef5fad42ed79786046 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Tue, 19 Sep 2023 19:49:09 +0200 Subject: [PATCH 100/326] iio: adc: twl6030-gpadc: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new() which already returns void. Eventually after all drivers are converted, .remove_new() will be renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20230919174931.1417681-28-u.kleine-koenig@pengutronix.de Signed-off-by: Jonathan Cameron --- drivers/iio/adc/twl6030-gpadc.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/iio/adc/twl6030-gpadc.c b/drivers/iio/adc/twl6030-gpadc.c index 32873fb5f367..224e9cb5e147 100644 --- a/drivers/iio/adc/twl6030-gpadc.c +++ b/drivers/iio/adc/twl6030-gpadc.c @@ -968,14 +968,12 @@ static int twl6030_gpadc_probe(struct platform_device *pdev) return iio_device_register(indio_dev); } -static int twl6030_gpadc_remove(struct platform_device *pdev) +static void twl6030_gpadc_remove(struct platform_device *pdev) { struct iio_dev *indio_dev = platform_get_drvdata(pdev); twl6030_gpadc_disable_irq(TWL6030_GPADC_RT_SW1_EOC_MASK); iio_device_unregister(indio_dev); - - return 0; } static int twl6030_gpadc_suspend(struct device *pdev) @@ -1007,7 +1005,7 @@ static DEFINE_SIMPLE_DEV_PM_OPS(twl6030_gpadc_pm_ops, twl6030_gpadc_suspend, static struct platform_driver twl6030_gpadc_driver = { .probe = twl6030_gpadc_probe, - .remove = twl6030_gpadc_remove, + .remove_new = twl6030_gpadc_remove, .driver = { .name = DRIVER_NAME, .pm = pm_sleep_ptr(&twl6030_gpadc_pm_ops), From aec6dbe61f2b01b572cc85643eaf0095b8c66bbf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Tue, 19 Sep 2023 19:49:10 +0200 Subject: [PATCH 101/326] iio: adc: vf610_adc: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new() which already returns void. Eventually after all drivers are converted, .remove_new() will be renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20230919174931.1417681-29-u.kleine-koenig@pengutronix.de Signed-off-by: Jonathan Cameron --- drivers/iio/adc/vf610_adc.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/iio/adc/vf610_adc.c b/drivers/iio/adc/vf610_adc.c index ae31aafd2653..e4548df3f8fb 100644 --- a/drivers/iio/adc/vf610_adc.c +++ b/drivers/iio/adc/vf610_adc.c @@ -916,7 +916,7 @@ error_adc_clk_enable: return ret; } -static int vf610_adc_remove(struct platform_device *pdev) +static void vf610_adc_remove(struct platform_device *pdev) { struct iio_dev *indio_dev = platform_get_drvdata(pdev); struct vf610_adc *info = iio_priv(indio_dev); @@ -925,8 +925,6 @@ static int vf610_adc_remove(struct platform_device *pdev) iio_triggered_buffer_cleanup(indio_dev); regulator_disable(info->vref); clk_disable_unprepare(info->clk); - - return 0; } static int vf610_adc_suspend(struct device *dev) @@ -974,7 +972,7 @@ static DEFINE_SIMPLE_DEV_PM_OPS(vf610_adc_pm_ops, vf610_adc_suspend, static struct platform_driver vf610_adc_driver = { .probe = vf610_adc_probe, - .remove = vf610_adc_remove, + .remove_new = vf610_adc_remove, .driver = { .name = DRIVER_NAME, .of_match_table = vf610_adc_match, From 3de9b0729567c873571090287baf45957efd5ba9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Tue, 19 Sep 2023 19:49:11 +0200 Subject: [PATCH 102/326] iio: dac: dpot-dac: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new() which already returns void. Eventually after all drivers are converted, .remove_new() will be renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20230919174931.1417681-30-u.kleine-koenig@pengutronix.de Signed-off-by: Jonathan Cameron --- drivers/iio/dac/dpot-dac.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/iio/dac/dpot-dac.c b/drivers/iio/dac/dpot-dac.c index 83ce9489259c..7332064d0852 100644 --- a/drivers/iio/dac/dpot-dac.c +++ b/drivers/iio/dac/dpot-dac.c @@ -226,15 +226,13 @@ disable_reg: return ret; } -static int dpot_dac_remove(struct platform_device *pdev) +static void dpot_dac_remove(struct platform_device *pdev) { struct iio_dev *indio_dev = platform_get_drvdata(pdev); struct dpot_dac *dac = iio_priv(indio_dev); iio_device_unregister(indio_dev); regulator_disable(dac->vref); - - return 0; } static const struct of_device_id dpot_dac_match[] = { @@ -245,7 +243,7 @@ MODULE_DEVICE_TABLE(of, dpot_dac_match); static struct platform_driver dpot_dac_driver = { .probe = dpot_dac_probe, - .remove = dpot_dac_remove, + .remove_new = dpot_dac_remove, .driver = { .name = "iio-dpot-dac", .of_match_table = dpot_dac_match, From b4785a25a969bc53773c6abb89f3592b7fd4fe9e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Tue, 19 Sep 2023 19:49:12 +0200 Subject: [PATCH 103/326] iio: dac: lpc18xx_dac: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new() which already returns void. Eventually after all drivers are converted, .remove_new() will be renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20230919174931.1417681-31-u.kleine-koenig@pengutronix.de Signed-off-by: Jonathan Cameron --- drivers/iio/dac/lpc18xx_dac.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/iio/dac/lpc18xx_dac.c b/drivers/iio/dac/lpc18xx_dac.c index 60467c6f2c6e..b3aa4443a6a4 100644 --- a/drivers/iio/dac/lpc18xx_dac.c +++ b/drivers/iio/dac/lpc18xx_dac.c @@ -165,7 +165,7 @@ dis_reg: return ret; } -static int lpc18xx_dac_remove(struct platform_device *pdev) +static void lpc18xx_dac_remove(struct platform_device *pdev) { struct iio_dev *indio_dev = platform_get_drvdata(pdev); struct lpc18xx_dac *dac = iio_priv(indio_dev); @@ -175,8 +175,6 @@ static int lpc18xx_dac_remove(struct platform_device *pdev) writel(0, dac->base + LPC18XX_DAC_CTRL); clk_disable_unprepare(dac->clk); regulator_disable(dac->vref); - - return 0; } static const struct of_device_id lpc18xx_dac_match[] = { @@ -187,7 +185,7 @@ MODULE_DEVICE_TABLE(of, lpc18xx_dac_match); static struct platform_driver lpc18xx_dac_driver = { .probe = lpc18xx_dac_probe, - .remove = lpc18xx_dac_remove, + .remove_new = lpc18xx_dac_remove, .driver = { .name = "lpc18xx-dac", .of_match_table = lpc18xx_dac_match, From b5821e60388428226cc1e7cfe0543f7e190fa4fc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Tue, 19 Sep 2023 19:49:13 +0200 Subject: [PATCH 104/326] iio: dac: stm32-dac-core: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new() which already returns void. Eventually after all drivers are converted, .remove_new() will be renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20230919174931.1417681-32-u.kleine-koenig@pengutronix.de Signed-off-by: Jonathan Cameron --- drivers/iio/dac/stm32-dac-core.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/iio/dac/stm32-dac-core.c b/drivers/iio/dac/stm32-dac-core.c index 83bf184e3adc..15abe048729e 100644 --- a/drivers/iio/dac/stm32-dac-core.c +++ b/drivers/iio/dac/stm32-dac-core.c @@ -183,7 +183,7 @@ err_pm_stop: return ret; } -static int stm32_dac_remove(struct platform_device *pdev) +static void stm32_dac_remove(struct platform_device *pdev) { pm_runtime_get_sync(&pdev->dev); of_platform_depopulate(&pdev->dev); @@ -191,8 +191,6 @@ static int stm32_dac_remove(struct platform_device *pdev) pm_runtime_disable(&pdev->dev); pm_runtime_set_suspended(&pdev->dev); pm_runtime_put_noidle(&pdev->dev); - - return 0; } static int stm32_dac_core_resume(struct device *dev) @@ -249,7 +247,7 @@ MODULE_DEVICE_TABLE(of, stm32_dac_of_match); static struct platform_driver stm32_dac_driver = { .probe = stm32_dac_probe, - .remove = stm32_dac_remove, + .remove_new = stm32_dac_remove, .driver = { .name = "stm32-dac-core", .of_match_table = stm32_dac_of_match, From 85a32a0ae2212ccbf8551993e494d68dbfc059ef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Tue, 19 Sep 2023 19:49:14 +0200 Subject: [PATCH 105/326] iio: dac: stm32-dac: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new() which already returns void. Eventually after all drivers are converted, .remove_new() will be renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20230919174931.1417681-33-u.kleine-koenig@pengutronix.de Signed-off-by: Jonathan Cameron --- drivers/iio/dac/stm32-dac.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/iio/dac/stm32-dac.c b/drivers/iio/dac/stm32-dac.c index 3cab28c7ee3b..5a722f307e7e 100644 --- a/drivers/iio/dac/stm32-dac.c +++ b/drivers/iio/dac/stm32-dac.c @@ -362,7 +362,7 @@ err_pm_put: return ret; } -static int stm32_dac_remove(struct platform_device *pdev) +static void stm32_dac_remove(struct platform_device *pdev) { struct iio_dev *indio_dev = platform_get_drvdata(pdev); @@ -371,8 +371,6 @@ static int stm32_dac_remove(struct platform_device *pdev) pm_runtime_disable(&pdev->dev); pm_runtime_set_suspended(&pdev->dev); pm_runtime_put_noidle(&pdev->dev); - - return 0; } static int stm32_dac_suspend(struct device *dev) @@ -400,7 +398,7 @@ MODULE_DEVICE_TABLE(of, stm32_dac_of_match); static struct platform_driver stm32_dac_driver = { .probe = stm32_dac_probe, - .remove = stm32_dac_remove, + .remove_new = stm32_dac_remove, .driver = { .name = "stm32-dac", .of_match_table = stm32_dac_of_match, From cf22fc5566ccf1b23c4a5489912e6e406a0377fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Tue, 19 Sep 2023 19:49:15 +0200 Subject: [PATCH 106/326] iio: dac: vf610: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new() which already returns void. Eventually after all drivers are converted, .remove_new() will be renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20230919174931.1417681-34-u.kleine-koenig@pengutronix.de Signed-off-by: Jonathan Cameron --- drivers/iio/dac/vf610_dac.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/iio/dac/vf610_dac.c b/drivers/iio/dac/vf610_dac.c index fc182250c622..de73bc5a1c93 100644 --- a/drivers/iio/dac/vf610_dac.c +++ b/drivers/iio/dac/vf610_dac.c @@ -231,7 +231,7 @@ error_iio_device_register: return ret; } -static int vf610_dac_remove(struct platform_device *pdev) +static void vf610_dac_remove(struct platform_device *pdev) { struct iio_dev *indio_dev = platform_get_drvdata(pdev); struct vf610_dac *info = iio_priv(indio_dev); @@ -239,8 +239,6 @@ static int vf610_dac_remove(struct platform_device *pdev) iio_device_unregister(indio_dev); vf610_dac_exit(info); clk_disable_unprepare(info->clk); - - return 0; } static int vf610_dac_suspend(struct device *dev) @@ -274,7 +272,7 @@ static DEFINE_SIMPLE_DEV_PM_OPS(vf610_dac_pm_ops, vf610_dac_suspend, static struct platform_driver vf610_dac_driver = { .probe = vf610_dac_probe, - .remove = vf610_dac_remove, + .remove_new = vf610_dac_remove, .driver = { .name = "vf610-dac", .of_match_table = vf610_dac_match, From 3a8799735b406919b28f0539a1234fe8a895bd88 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Tue, 19 Sep 2023 19:49:16 +0200 Subject: [PATCH 107/326] iio: gyro: hid-sensor-gyro-3d: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new() which already returns void. Eventually after all drivers are converted, .remove_new() will be renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20230919174931.1417681-35-u.kleine-koenig@pengutronix.de Signed-off-by: Jonathan Cameron --- drivers/iio/gyro/hid-sensor-gyro-3d.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/iio/gyro/hid-sensor-gyro-3d.c b/drivers/iio/gyro/hid-sensor-gyro-3d.c index 698c50da1f10..59a38bf9459b 100644 --- a/drivers/iio/gyro/hid-sensor-gyro-3d.c +++ b/drivers/iio/gyro/hid-sensor-gyro-3d.c @@ -359,7 +359,7 @@ error_remove_trigger: } /* Function to deinitialize the processing for usage id */ -static int hid_gyro_3d_remove(struct platform_device *pdev) +static void hid_gyro_3d_remove(struct platform_device *pdev) { struct hid_sensor_hub_device *hsdev = pdev->dev.platform_data; struct iio_dev *indio_dev = platform_get_drvdata(pdev); @@ -368,8 +368,6 @@ static int hid_gyro_3d_remove(struct platform_device *pdev) sensor_hub_remove_callback(hsdev, HID_USAGE_SENSOR_GYRO_3D); iio_device_unregister(indio_dev); hid_sensor_remove_trigger(indio_dev, &gyro_state->common_attributes); - - return 0; } static const struct platform_device_id hid_gyro_3d_ids[] = { @@ -388,7 +386,7 @@ static struct platform_driver hid_gyro_3d_platform_driver = { .pm = &hid_sensor_pm_ops, }, .probe = hid_gyro_3d_probe, - .remove = hid_gyro_3d_remove, + .remove_new = hid_gyro_3d_remove, }; module_platform_driver(hid_gyro_3d_platform_driver); From b06ab8c8ac9da9d03cec61678fe04404450ee76a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Tue, 19 Sep 2023 19:49:17 +0200 Subject: [PATCH 108/326] iio: humidity: hid-sensor-humidity: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new() which already returns void. Eventually after all drivers are converted, .remove_new() will be renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20230919174931.1417681-36-u.kleine-koenig@pengutronix.de Signed-off-by: Jonathan Cameron --- drivers/iio/humidity/hid-sensor-humidity.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/iio/humidity/hid-sensor-humidity.c b/drivers/iio/humidity/hid-sensor-humidity.c index fa0fe404a70a..bf6d2636a85e 100644 --- a/drivers/iio/humidity/hid-sensor-humidity.c +++ b/drivers/iio/humidity/hid-sensor-humidity.c @@ -260,7 +260,7 @@ error_remove_trigger: } /* Function to deinitialize the processing for usage id */ -static int hid_humidity_remove(struct platform_device *pdev) +static void hid_humidity_remove(struct platform_device *pdev) { struct hid_sensor_hub_device *hsdev = dev_get_platdata(&pdev->dev); struct iio_dev *indio_dev = platform_get_drvdata(pdev); @@ -269,8 +269,6 @@ static int hid_humidity_remove(struct platform_device *pdev) iio_device_unregister(indio_dev); sensor_hub_remove_callback(hsdev, HID_USAGE_SENSOR_HUMIDITY); hid_sensor_remove_trigger(indio_dev, &humid_st->common_attributes); - - return 0; } static const struct platform_device_id hid_humidity_ids[] = { @@ -289,7 +287,7 @@ static struct platform_driver hid_humidity_platform_driver = { .pm = &hid_sensor_pm_ops, }, .probe = hid_humidity_probe, - .remove = hid_humidity_remove, + .remove_new = hid_humidity_remove, }; module_platform_driver(hid_humidity_platform_driver); From 3e1e6787dc4b42c09a23cfe4e898b01f5a07b559 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Tue, 19 Sep 2023 19:49:18 +0200 Subject: [PATCH 109/326] iio: light: cm3605: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new() which already returns void. Eventually after all drivers are converted, .remove_new() will be renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20230919174931.1417681-37-u.kleine-koenig@pengutronix.de Signed-off-by: Jonathan Cameron --- drivers/iio/light/cm3605.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/iio/light/cm3605.c b/drivers/iio/light/cm3605.c index e7f0b81b7f5a..22a63a89f289 100644 --- a/drivers/iio/light/cm3605.c +++ b/drivers/iio/light/cm3605.c @@ -266,7 +266,7 @@ out_disable_vdd: return ret; } -static int cm3605_remove(struct platform_device *pdev) +static void cm3605_remove(struct platform_device *pdev) { struct iio_dev *indio_dev = platform_get_drvdata(pdev); struct cm3605 *cm3605 = iio_priv(indio_dev); @@ -276,8 +276,6 @@ static int cm3605_remove(struct platform_device *pdev) gpiod_set_value_cansleep(cm3605->aset, 0); iio_device_unregister(indio_dev); regulator_disable(cm3605->vdd); - - return 0; } static int cm3605_pm_suspend(struct device *dev) @@ -320,7 +318,7 @@ static struct platform_driver cm3605_driver = { .pm = pm_sleep_ptr(&cm3605_dev_pm_ops), }, .probe = cm3605_probe, - .remove = cm3605_remove, + .remove_new = cm3605_remove, }; module_platform_driver(cm3605_driver); From b428adb4113b20f123bf467a909332824048b741 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Tue, 19 Sep 2023 19:49:19 +0200 Subject: [PATCH 110/326] iio: light: hid-sensor-als: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new() which already returns void. Eventually after all drivers are converted, .remove_new() will be renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20230919174931.1417681-38-u.kleine-koenig@pengutronix.de Signed-off-by: Jonathan Cameron --- drivers/iio/light/hid-sensor-als.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/iio/light/hid-sensor-als.c b/drivers/iio/light/hid-sensor-als.c index eb1aedad7edc..cb76841ec0ce 100644 --- a/drivers/iio/light/hid-sensor-als.c +++ b/drivers/iio/light/hid-sensor-als.c @@ -347,7 +347,7 @@ error_remove_trigger: } /* Function to deinitialize the processing for usage id */ -static int hid_als_remove(struct platform_device *pdev) +static void hid_als_remove(struct platform_device *pdev) { struct hid_sensor_hub_device *hsdev = pdev->dev.platform_data; struct iio_dev *indio_dev = platform_get_drvdata(pdev); @@ -356,8 +356,6 @@ static int hid_als_remove(struct platform_device *pdev) sensor_hub_remove_callback(hsdev, hsdev->usage); iio_device_unregister(indio_dev); hid_sensor_remove_trigger(indio_dev, &als_state->common_attributes); - - return 0; } static const struct platform_device_id hid_als_ids[] = { @@ -380,7 +378,7 @@ static struct platform_driver hid_als_platform_driver = { .pm = &hid_sensor_pm_ops, }, .probe = hid_als_probe, - .remove = hid_als_remove, + .remove_new = hid_als_remove, }; module_platform_driver(hid_als_platform_driver); From c707ccc7005475764ee0f2438055e2592c3d5138 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Tue, 19 Sep 2023 19:49:20 +0200 Subject: [PATCH 111/326] iio: light: hid-sensor-prox: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new() which already returns void. Eventually after all drivers are converted, .remove_new() will be renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20230919174931.1417681-39-u.kleine-koenig@pengutronix.de Signed-off-by: Jonathan Cameron --- drivers/iio/light/hid-sensor-prox.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/iio/light/hid-sensor-prox.c b/drivers/iio/light/hid-sensor-prox.c index a47591e1bad9..26c481d2998c 100644 --- a/drivers/iio/light/hid-sensor-prox.c +++ b/drivers/iio/light/hid-sensor-prox.c @@ -313,7 +313,7 @@ error_remove_trigger: } /* Function to deinitialize the processing for usage id */ -static int hid_prox_remove(struct platform_device *pdev) +static void hid_prox_remove(struct platform_device *pdev) { struct hid_sensor_hub_device *hsdev = pdev->dev.platform_data; struct iio_dev *indio_dev = platform_get_drvdata(pdev); @@ -322,8 +322,6 @@ static int hid_prox_remove(struct platform_device *pdev) sensor_hub_remove_callback(hsdev, hsdev->usage); iio_device_unregister(indio_dev); hid_sensor_remove_trigger(indio_dev, &prox_state->common_attributes); - - return 0; } static const struct platform_device_id hid_prox_ids[] = { @@ -346,7 +344,7 @@ static struct platform_driver hid_prox_platform_driver = { .pm = &hid_sensor_pm_ops, }, .probe = hid_prox_probe, - .remove = hid_prox_remove, + .remove_new = hid_prox_remove, }; module_platform_driver(hid_prox_platform_driver); From 4235ac7e6f9650ab07bbcd7c33c46a2a70f6ca56 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Tue, 19 Sep 2023 19:49:21 +0200 Subject: [PATCH 112/326] iio: light: lm3533-als: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new() which already returns void. Eventually after all drivers are converted, .remove_new() will be renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20230919174931.1417681-40-u.kleine-koenig@pengutronix.de Signed-off-by: Jonathan Cameron --- drivers/iio/light/lm3533-als.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/iio/light/lm3533-als.c b/drivers/iio/light/lm3533-als.c index 827bc25269e9..7800f7fa51b7 100644 --- a/drivers/iio/light/lm3533-als.c +++ b/drivers/iio/light/lm3533-als.c @@ -895,7 +895,7 @@ err_free_irq: return ret; } -static int lm3533_als_remove(struct platform_device *pdev) +static void lm3533_als_remove(struct platform_device *pdev) { struct iio_dev *indio_dev = platform_get_drvdata(pdev); struct lm3533_als *als = iio_priv(indio_dev); @@ -905,8 +905,6 @@ static int lm3533_als_remove(struct platform_device *pdev) lm3533_als_disable(als); if (als->irq) free_irq(als->irq, indio_dev); - - return 0; } static struct platform_driver lm3533_als_driver = { @@ -914,7 +912,7 @@ static struct platform_driver lm3533_als_driver = { .name = "lm3533-als", }, .probe = lm3533_als_probe, - .remove = lm3533_als_remove, + .remove_new = lm3533_als_remove, }; module_platform_driver(lm3533_als_driver); From 622adde5e54de35eaca7ff065ef2970b8495fffd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Tue, 19 Sep 2023 19:49:22 +0200 Subject: [PATCH 113/326] iio: magnetometer: hid-sensor-magn-3d: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new() which already returns void. Eventually after all drivers are converted, .remove_new() will be renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20230919174931.1417681-41-u.kleine-koenig@pengutronix.de Signed-off-by: Jonathan Cameron --- drivers/iio/magnetometer/hid-sensor-magn-3d.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/iio/magnetometer/hid-sensor-magn-3d.c b/drivers/iio/magnetometer/hid-sensor-magn-3d.c index e85a3a8eea90..5c795a430d09 100644 --- a/drivers/iio/magnetometer/hid-sensor-magn-3d.c +++ b/drivers/iio/magnetometer/hid-sensor-magn-3d.c @@ -547,7 +547,7 @@ error_remove_trigger: } /* Function to deinitialize the processing for usage id */ -static int hid_magn_3d_remove(struct platform_device *pdev) +static void hid_magn_3d_remove(struct platform_device *pdev) { struct hid_sensor_hub_device *hsdev = pdev->dev.platform_data; struct iio_dev *indio_dev = platform_get_drvdata(pdev); @@ -556,8 +556,6 @@ static int hid_magn_3d_remove(struct platform_device *pdev) sensor_hub_remove_callback(hsdev, HID_USAGE_SENSOR_COMPASS_3D); iio_device_unregister(indio_dev); hid_sensor_remove_trigger(indio_dev, &magn_state->magn_flux_attributes); - - return 0; } static const struct platform_device_id hid_magn_3d_ids[] = { @@ -576,7 +574,7 @@ static struct platform_driver hid_magn_3d_platform_driver = { .pm = &hid_sensor_pm_ops, }, .probe = hid_magn_3d_probe, - .remove = hid_magn_3d_remove, + .remove_new = hid_magn_3d_remove, }; module_platform_driver(hid_magn_3d_platform_driver); From 44b25cf7195e953a8f56d3928e62133cd2ef790e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Tue, 19 Sep 2023 19:49:23 +0200 Subject: [PATCH 114/326] iio: orientation: hid-sensor-incl-3d: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new() which already returns void. Eventually after all drivers are converted, .remove_new() will be renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20230919174931.1417681-42-u.kleine-koenig@pengutronix.de Signed-off-by: Jonathan Cameron --- drivers/iio/orientation/hid-sensor-incl-3d.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/iio/orientation/hid-sensor-incl-3d.c b/drivers/iio/orientation/hid-sensor-incl-3d.c index ba5b581d5b25..8943d5c78bc0 100644 --- a/drivers/iio/orientation/hid-sensor-incl-3d.c +++ b/drivers/iio/orientation/hid-sensor-incl-3d.c @@ -383,7 +383,7 @@ error_remove_trigger: } /* Function to deinitialize the processing for usage id */ -static int hid_incl_3d_remove(struct platform_device *pdev) +static void hid_incl_3d_remove(struct platform_device *pdev) { struct hid_sensor_hub_device *hsdev = pdev->dev.platform_data; struct iio_dev *indio_dev = platform_get_drvdata(pdev); @@ -392,8 +392,6 @@ static int hid_incl_3d_remove(struct platform_device *pdev) sensor_hub_remove_callback(hsdev, HID_USAGE_SENSOR_INCLINOMETER_3D); iio_device_unregister(indio_dev); hid_sensor_remove_trigger(indio_dev, &incl_state->common_attributes); - - return 0; } static const struct platform_device_id hid_incl_3d_ids[] = { @@ -412,7 +410,7 @@ static struct platform_driver hid_incl_3d_platform_driver = { .pm = &hid_sensor_pm_ops, }, .probe = hid_incl_3d_probe, - .remove = hid_incl_3d_remove, + .remove_new = hid_incl_3d_remove, }; module_platform_driver(hid_incl_3d_platform_driver); From d93837b8d4331af9d5d270e36d2dcb7273c24eee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Tue, 19 Sep 2023 19:49:24 +0200 Subject: [PATCH 115/326] iio: orientation: hid-sensor-rotation: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new() which already returns void. Eventually after all drivers are converted, .remove_new() will be renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20230919174931.1417681-43-u.kleine-koenig@pengutronix.de Signed-off-by: Jonathan Cameron --- drivers/iio/orientation/hid-sensor-rotation.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/iio/orientation/hid-sensor-rotation.c b/drivers/iio/orientation/hid-sensor-rotation.c index a033699910e8..5e8cadd5177a 100644 --- a/drivers/iio/orientation/hid-sensor-rotation.c +++ b/drivers/iio/orientation/hid-sensor-rotation.c @@ -327,7 +327,7 @@ error_remove_trigger: } /* Function to deinitialize the processing for usage id */ -static int hid_dev_rot_remove(struct platform_device *pdev) +static void hid_dev_rot_remove(struct platform_device *pdev) { struct hid_sensor_hub_device *hsdev = pdev->dev.platform_data; struct iio_dev *indio_dev = platform_get_drvdata(pdev); @@ -336,8 +336,6 @@ static int hid_dev_rot_remove(struct platform_device *pdev) sensor_hub_remove_callback(hsdev, hsdev->usage); iio_device_unregister(indio_dev); hid_sensor_remove_trigger(indio_dev, &rot_state->common_attributes); - - return 0; } static const struct platform_device_id hid_dev_rot_ids[] = { @@ -364,7 +362,7 @@ static struct platform_driver hid_dev_rot_platform_driver = { .pm = &hid_sensor_pm_ops, }, .probe = hid_dev_rot_probe, - .remove = hid_dev_rot_remove, + .remove_new = hid_dev_rot_remove, }; module_platform_driver(hid_dev_rot_platform_driver); From 94f2dab24ee87b4322a7c9e60959391717368e5e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Tue, 19 Sep 2023 19:49:25 +0200 Subject: [PATCH 116/326] iio: position: hid-sensor-custom-intel-hinge: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new() which already returns void. Eventually after all drivers are converted, .remove_new() will be renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20230919174931.1417681-44-u.kleine-koenig@pengutronix.de Signed-off-by: Jonathan Cameron --- drivers/iio/position/hid-sensor-custom-intel-hinge.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/iio/position/hid-sensor-custom-intel-hinge.c b/drivers/iio/position/hid-sensor-custom-intel-hinge.c index 07c30d217255..76e173850a35 100644 --- a/drivers/iio/position/hid-sensor-custom-intel-hinge.c +++ b/drivers/iio/position/hid-sensor-custom-intel-hinge.c @@ -342,7 +342,7 @@ error_remove_trigger: } /* Function to deinitialize the processing for usage id */ -static int hid_hinge_remove(struct platform_device *pdev) +static void hid_hinge_remove(struct platform_device *pdev) { struct hid_sensor_hub_device *hsdev = pdev->dev.platform_data; struct iio_dev *indio_dev = platform_get_drvdata(pdev); @@ -351,8 +351,6 @@ static int hid_hinge_remove(struct platform_device *pdev) iio_device_unregister(indio_dev); sensor_hub_remove_callback(hsdev, hsdev->usage); hid_sensor_remove_trigger(indio_dev, &st->common_attributes); - - return 0; } static const struct platform_device_id hid_hinge_ids[] = { @@ -371,7 +369,7 @@ static struct platform_driver hid_hinge_platform_driver = { .pm = &hid_sensor_pm_ops, }, .probe = hid_hinge_probe, - .remove = hid_hinge_remove, + .remove_new = hid_hinge_remove, }; module_platform_driver(hid_hinge_platform_driver); From 23c81c1098ae4569aecca4d2040ee9d144e804f7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Tue, 19 Sep 2023 19:49:26 +0200 Subject: [PATCH 117/326] iio: pressure: hid-sensor: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new() which already returns void. Eventually after all drivers are converted, .remove_new() will be renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20230919174931.1417681-45-u.kleine-koenig@pengutronix.de Signed-off-by: Jonathan Cameron --- drivers/iio/pressure/hid-sensor-press.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/iio/pressure/hid-sensor-press.c b/drivers/iio/pressure/hid-sensor-press.c index a9215eb32d70..956045e2db29 100644 --- a/drivers/iio/pressure/hid-sensor-press.c +++ b/drivers/iio/pressure/hid-sensor-press.c @@ -323,7 +323,7 @@ error_remove_trigger: } /* Function to deinitialize the processing for usage id */ -static int hid_press_remove(struct platform_device *pdev) +static void hid_press_remove(struct platform_device *pdev) { struct hid_sensor_hub_device *hsdev = pdev->dev.platform_data; struct iio_dev *indio_dev = platform_get_drvdata(pdev); @@ -332,8 +332,6 @@ static int hid_press_remove(struct platform_device *pdev) sensor_hub_remove_callback(hsdev, HID_USAGE_SENSOR_PRESSURE); iio_device_unregister(indio_dev); hid_sensor_remove_trigger(indio_dev, &press_state->common_attributes); - - return 0; } static const struct platform_device_id hid_press_ids[] = { @@ -352,7 +350,7 @@ static struct platform_driver hid_press_platform_driver = { .pm = &hid_sensor_pm_ops, }, .probe = hid_press_probe, - .remove = hid_press_remove, + .remove_new = hid_press_remove, }; module_platform_driver(hid_press_platform_driver); From 2df694f710d29d6c9d10f09cd368d2f544c7ba4c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Tue, 19 Sep 2023 19:49:27 +0200 Subject: [PATCH 118/326] iio: proximity: cros_ec_mkbp: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new() which already returns void. Eventually after all drivers are converted, .remove_new() will be renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Reviewed-by: Tzung-Bi Shih Link: https://lore.kernel.org/r/20230919174931.1417681-46-u.kleine-koenig@pengutronix.de Signed-off-by: Jonathan Cameron --- drivers/iio/proximity/cros_ec_mkbp_proximity.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/iio/proximity/cros_ec_mkbp_proximity.c b/drivers/iio/proximity/cros_ec_mkbp_proximity.c index 571ea1812246..4df506bb8b38 100644 --- a/drivers/iio/proximity/cros_ec_mkbp_proximity.c +++ b/drivers/iio/proximity/cros_ec_mkbp_proximity.c @@ -239,15 +239,13 @@ static int cros_ec_mkbp_proximity_probe(struct platform_device *pdev) return 0; } -static int cros_ec_mkbp_proximity_remove(struct platform_device *pdev) +static void cros_ec_mkbp_proximity_remove(struct platform_device *pdev) { struct cros_ec_mkbp_proximity_data *data = platform_get_drvdata(pdev); struct cros_ec_device *ec = data->ec; blocking_notifier_chain_unregister(&ec->event_notifier, &data->notifier); - - return 0; } static const struct of_device_id cros_ec_mkbp_proximity_of_match[] = { @@ -263,7 +261,7 @@ static struct platform_driver cros_ec_mkbp_proximity_driver = { .pm = pm_sleep_ptr(&cros_ec_mkbp_proximity_pm_ops), }, .probe = cros_ec_mkbp_proximity_probe, - .remove = cros_ec_mkbp_proximity_remove, + .remove_new = cros_ec_mkbp_proximity_remove, }; module_platform_driver(cros_ec_mkbp_proximity_driver); From 4abfc97db98be23f33c5b003d13bbb02c8fde679 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Tue, 19 Sep 2023 19:49:28 +0200 Subject: [PATCH 119/326] iio: proximity: srf04: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new() which already returns void. Eventually after all drivers are converted, .remove_new() will be renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20230919174931.1417681-47-u.kleine-koenig@pengutronix.de Signed-off-by: Jonathan Cameron --- drivers/iio/proximity/srf04.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/iio/proximity/srf04.c b/drivers/iio/proximity/srf04.c index faf2f806ce80..86c57672fc7e 100644 --- a/drivers/iio/proximity/srf04.c +++ b/drivers/iio/proximity/srf04.c @@ -344,7 +344,7 @@ static int srf04_probe(struct platform_device *pdev) return ret; } -static int srf04_remove(struct platform_device *pdev) +static void srf04_remove(struct platform_device *pdev) { struct iio_dev *indio_dev = platform_get_drvdata(pdev); struct srf04_data *data = iio_priv(indio_dev); @@ -355,8 +355,6 @@ static int srf04_remove(struct platform_device *pdev) pm_runtime_disable(data->dev); pm_runtime_set_suspended(data->dev); } - - return 0; } static int srf04_pm_runtime_suspend(struct device *dev) @@ -391,7 +389,7 @@ static const struct dev_pm_ops srf04_pm_ops = { static struct platform_driver srf04_driver = { .probe = srf04_probe, - .remove = srf04_remove, + .remove_new = srf04_remove, .driver = { .name = "srf04-gpio", .of_match_table = of_srf04_match, From f55891730682f3e2d7401de6f52eddb1338107cb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Tue, 19 Sep 2023 19:49:29 +0200 Subject: [PATCH 120/326] iio: temperature: hid-sensor: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new() which already returns void. Eventually after all drivers are converted, .remove_new() will be renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20230919174931.1417681-48-u.kleine-koenig@pengutronix.de Signed-off-by: Jonathan Cameron --- drivers/iio/temperature/hid-sensor-temperature.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/iio/temperature/hid-sensor-temperature.c b/drivers/iio/temperature/hid-sensor-temperature.c index d40f235af1d4..0143fd478933 100644 --- a/drivers/iio/temperature/hid-sensor-temperature.c +++ b/drivers/iio/temperature/hid-sensor-temperature.c @@ -257,7 +257,7 @@ error_remove_trigger: } /* Function to deinitialize the processing for usage id */ -static int hid_temperature_remove(struct platform_device *pdev) +static void hid_temperature_remove(struct platform_device *pdev) { struct hid_sensor_hub_device *hsdev = dev_get_platdata(&pdev->dev); struct iio_dev *indio_dev = platform_get_drvdata(pdev); @@ -265,8 +265,6 @@ static int hid_temperature_remove(struct platform_device *pdev) sensor_hub_remove_callback(hsdev, HID_USAGE_SENSOR_TEMPERATURE); hid_sensor_remove_trigger(indio_dev, &temp_st->common_attributes); - - return 0; } static const struct platform_device_id hid_temperature_ids[] = { @@ -285,7 +283,7 @@ static struct platform_driver hid_temperature_platform_driver = { .pm = &hid_sensor_pm_ops, }, .probe = hid_temperature_probe, - .remove = hid_temperature_remove, + .remove_new = hid_temperature_remove, }; module_platform_driver(hid_temperature_platform_driver); From 548eb81d7bfcf48370f4a82483f6ed0f1378b719 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Tue, 19 Sep 2023 19:49:30 +0200 Subject: [PATCH 121/326] iio: trigger: iio-trig-interrupt: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new() which already returns void. Eventually after all drivers are converted, .remove_new() will be renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20230919174931.1417681-49-u.kleine-koenig@pengutronix.de Signed-off-by: Jonathan Cameron --- drivers/iio/trigger/iio-trig-interrupt.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/iio/trigger/iio-trig-interrupt.c b/drivers/iio/trigger/iio-trig-interrupt.c index 5f49cd105fae..dec256bfbd73 100644 --- a/drivers/iio/trigger/iio-trig-interrupt.c +++ b/drivers/iio/trigger/iio-trig-interrupt.c @@ -81,7 +81,7 @@ error_ret: return ret; } -static int iio_interrupt_trigger_remove(struct platform_device *pdev) +static void iio_interrupt_trigger_remove(struct platform_device *pdev) { struct iio_trigger *trig; struct iio_interrupt_trigger_info *trig_info; @@ -92,13 +92,11 @@ static int iio_interrupt_trigger_remove(struct platform_device *pdev) free_irq(trig_info->irq, trig); kfree(trig_info); iio_trigger_free(trig); - - return 0; } static struct platform_driver iio_interrupt_trigger_driver = { .probe = iio_interrupt_trigger_probe, - .remove = iio_interrupt_trigger_remove, + .remove_new = iio_interrupt_trigger_remove, .driver = { .name = "iio_interrupt_trigger", }, From e377df03082b36f748894904c990617682b8cec6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Tue, 19 Sep 2023 19:49:31 +0200 Subject: [PATCH 122/326] iio: trigger: stm32-timer: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new() which already returns void. Eventually after all drivers are converted, .remove_new() will be renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20230919174931.1417681-50-u.kleine-koenig@pengutronix.de Signed-off-by: Jonathan Cameron --- drivers/iio/trigger/stm32-timer-trigger.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/iio/trigger/stm32-timer-trigger.c b/drivers/iio/trigger/stm32-timer-trigger.c index 3643c4afae67..d76444030a28 100644 --- a/drivers/iio/trigger/stm32-timer-trigger.c +++ b/drivers/iio/trigger/stm32-timer-trigger.c @@ -809,7 +809,7 @@ static int stm32_timer_trigger_probe(struct platform_device *pdev) return 0; } -static int stm32_timer_trigger_remove(struct platform_device *pdev) +static void stm32_timer_trigger_remove(struct platform_device *pdev) { struct stm32_timer_trigger *priv = platform_get_drvdata(pdev); u32 val; @@ -824,8 +824,6 @@ static int stm32_timer_trigger_remove(struct platform_device *pdev) if (priv->enabled) clk_disable(priv->clk); - - return 0; } static int stm32_timer_trigger_suspend(struct device *dev) @@ -904,7 +902,7 @@ MODULE_DEVICE_TABLE(of, stm32_trig_of_match); static struct platform_driver stm32_timer_trigger_driver = { .probe = stm32_timer_trigger_probe, - .remove = stm32_timer_trigger_remove, + .remove_new = stm32_timer_trigger_remove, .driver = { .name = "stm32-timer-trigger", .of_match_table = stm32_trig_of_match, From 2da980fd5dcb5345a1c072fd29a04130631913c0 Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Thu, 21 Sep 2023 21:24:20 +0200 Subject: [PATCH 123/326] dt-bindings: iio: adc: ti,ads1015: Document optional interrupt line The ADS1015 can have optional IRQ line connected, document it in the DT bindings. Signed-off-by: Marek Vasut Acked-by: Conor Dooley Link: https://lore.kernel.org/r/20230921192420.70643-1-marex@denx.de Signed-off-by: Jonathan Cameron --- Documentation/devicetree/bindings/iio/adc/ti,ads1015.yaml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Documentation/devicetree/bindings/iio/adc/ti,ads1015.yaml b/Documentation/devicetree/bindings/iio/adc/ti,ads1015.yaml index e004659099c1..d605999ffe28 100644 --- a/Documentation/devicetree/bindings/iio/adc/ti,ads1015.yaml +++ b/Documentation/devicetree/bindings/iio/adc/ti,ads1015.yaml @@ -23,6 +23,9 @@ properties: reg: maxItems: 1 + interrupts: + maxItems: 1 + "#address-cells": const: 1 From 57d3909596f9941c7d0777004994438df1b5ba0a Mon Sep 17 00:00:00 2001 From: Andy Shen Shen Date: Thu, 21 Sep 2023 11:14:44 +0800 Subject: [PATCH 124/326] iio: adc: palmas_gpadc: Drop duplicated the in comment. In line 460 of the palmas_gpadc.c file, fix kernel comment errors. Signed-off-by: Andy Shen Shen Link: https://lore.kernel.org/r/20230921031444.63594-1-shengaoya@inspur.com Signed-off-by: Jonathan Cameron --- drivers/iio/adc/palmas_gpadc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/iio/adc/palmas_gpadc.c b/drivers/iio/adc/palmas_gpadc.c index e202ea18af10..203cbbc70719 100644 --- a/drivers/iio/adc/palmas_gpadc.c +++ b/drivers/iio/adc/palmas_gpadc.c @@ -457,7 +457,7 @@ static int palmas_gpadc_get_calibrated_code(struct palmas_gpadc *adc, * * The gain error include both gain error, as specified in the datasheet, and * the gain error drift. These paramenters vary depending on device and whether - * the the channel is calibrated (trimmed) or not. + * the channel is calibrated (trimmed) or not. */ static int palmas_gpadc_threshold_with_tolerance(int val, const int INL, const int gain_error, From 286d528bf0fae9f334fba857825b9701df1675b2 Mon Sep 17 00:00:00 2001 From: Basavaraj Natikar Date: Tue, 19 Sep 2023 13:40:46 +0530 Subject: [PATCH 125/326] iio: hid-sensor-als: Use channel index to support more hub attributes Sensor hub attributes can be extended to support more channels. Repeat the reading for the two existing channels and store them separately. It still operates in the same manner as before where there was just one entry. So in order to support more sensor hub attributes for ALS use channel index to get specific sensor hub attributes. Signed-off-by: Basavaraj Natikar Acked-by: Srinivas Pandruvada Link: https://lore.kernel.org/r/20230919081054.2050714-2-Basavaraj.Natikar@amd.com Signed-off-by: Jonathan Cameron --- drivers/iio/light/hid-sensor-als.c | 34 ++++++++++++++++-------------- 1 file changed, 18 insertions(+), 16 deletions(-) diff --git a/drivers/iio/light/hid-sensor-als.c b/drivers/iio/light/hid-sensor-als.c index eb1aedad7edc..efb1f8862b28 100644 --- a/drivers/iio/light/hid-sensor-als.c +++ b/drivers/iio/light/hid-sensor-als.c @@ -24,7 +24,7 @@ enum { struct als_state { struct hid_sensor_hub_callbacks callbacks; struct hid_sensor_common common_attributes; - struct hid_sensor_hub_attribute_info als_illum; + struct hid_sensor_hub_attribute_info als[CHANNEL_SCAN_INDEX_MAX]; struct { u32 illum[CHANNEL_SCAN_INDEX_MAX]; u64 timestamp __aligned(8); @@ -99,8 +99,8 @@ static int als_read_raw(struct iio_dev *indio_dev, switch (chan->scan_index) { case CHANNEL_SCAN_INDEX_INTENSITY: case CHANNEL_SCAN_INDEX_ILLUM: - report_id = als_state->als_illum.report_id; - min = als_state->als_illum.logical_minimum; + report_id = als_state->als[chan->scan_index].report_id; + min = als_state->als[chan->scan_index].logical_minimum; address = HID_USAGE_SENSOR_LIGHT_ILLUM; break; default: @@ -242,22 +242,24 @@ static int als_parse_report(struct platform_device *pdev, struct als_state *st) { int ret; + int i; - ret = sensor_hub_input_get_attribute_info(hsdev, HID_INPUT_REPORT, - usage_id, - HID_USAGE_SENSOR_LIGHT_ILLUM, - &st->als_illum); - if (ret < 0) - return ret; - als_adjust_channel_bit_mask(channels, CHANNEL_SCAN_INDEX_INTENSITY, - st->als_illum.size); - als_adjust_channel_bit_mask(channels, CHANNEL_SCAN_INDEX_ILLUM, - st->als_illum.size); + for (i = 0; i <= CHANNEL_SCAN_INDEX_ILLUM; ++i) { + ret = sensor_hub_input_get_attribute_info(hsdev, + HID_INPUT_REPORT, + usage_id, + HID_USAGE_SENSOR_LIGHT_ILLUM, + &st->als[i]); + if (ret < 0) + return ret; + als_adjust_channel_bit_mask(channels, i, st->als[i].size); - dev_dbg(&pdev->dev, "als %x:%x\n", st->als_illum.index, - st->als_illum.report_id); + dev_dbg(&pdev->dev, "als %x:%x\n", st->als[i].index, + st->als[i].report_id); + } - st->scale_precision = hid_sensor_format_scale(usage_id, &st->als_illum, + st->scale_precision = hid_sensor_format_scale(usage_id, + &st->als[CHANNEL_SCAN_INDEX_INTENSITY], &st->scale_pre_decml, &st->scale_post_decml); return ret; From 42f311751102ef4884ae7352d7e85bd97280d2d3 Mon Sep 17 00:00:00 2001 From: Basavaraj Natikar Date: Tue, 19 Sep 2023 13:40:47 +0530 Subject: [PATCH 126/326] iio: Add channel type light color temperature In most cases, ambient color sensors also support light color temperature, which is measured in kelvin. Thus, add channel type light color temperature. Signed-off-by: Basavaraj Natikar Link: https://lore.kernel.org/r/20230919081054.2050714-3-Basavaraj.Natikar@amd.com Signed-off-by: Jonathan Cameron --- Documentation/ABI/testing/sysfs-bus-iio | 7 +++++++ drivers/iio/industrialio-core.c | 1 + include/uapi/linux/iio/types.h | 1 + tools/iio/iio_event_monitor.c | 2 ++ 4 files changed, 11 insertions(+) diff --git a/Documentation/ABI/testing/sysfs-bus-iio b/Documentation/ABI/testing/sysfs-bus-iio index a2854dc9a839..4cf7ed9ca57b 100644 --- a/Documentation/ABI/testing/sysfs-bus-iio +++ b/Documentation/ABI/testing/sysfs-bus-iio @@ -2179,3 +2179,10 @@ Contact: linux-iio@vger.kernel.org Description: Number of conditions that must occur, during a running period, before an event is generated. + +What: /sys/bus/iio/devices/iio:deviceX/in_colortemp_raw +KernelVersion: 6.7 +Contact: linux-iio@vger.kernel.org +Description: + Represents light color temperature, which measures light color + temperature in Kelvin. diff --git a/drivers/iio/industrialio-core.c b/drivers/iio/industrialio-core.c index d752e9c0499b..cba942cadf97 100644 --- a/drivers/iio/industrialio-core.c +++ b/drivers/iio/industrialio-core.c @@ -90,6 +90,7 @@ static const char * const iio_chan_type_name_spec[] = { [IIO_POSITIONRELATIVE] = "positionrelative", [IIO_PHASE] = "phase", [IIO_MASSCONCENTRATION] = "massconcentration", + [IIO_COLORTEMP] = "colortemp", }; static const char * const iio_modifier_names[] = { diff --git a/include/uapi/linux/iio/types.h b/include/uapi/linux/iio/types.h index c79f2f046a0b..08c20e540c13 100644 --- a/include/uapi/linux/iio/types.h +++ b/include/uapi/linux/iio/types.h @@ -47,6 +47,7 @@ enum iio_chan_type { IIO_POSITIONRELATIVE, IIO_PHASE, IIO_MASSCONCENTRATION, + IIO_COLORTEMP, }; enum iio_modifier { diff --git a/tools/iio/iio_event_monitor.c b/tools/iio/iio_event_monitor.c index 0a5c2bb60030..a63741e43ddf 100644 --- a/tools/iio/iio_event_monitor.c +++ b/tools/iio/iio_event_monitor.c @@ -59,6 +59,7 @@ static const char * const iio_chan_type_name_spec[] = { [IIO_POSITIONRELATIVE] = "positionrelative", [IIO_PHASE] = "phase", [IIO_MASSCONCENTRATION] = "massconcentration", + [IIO_COLORTEMP] = "colortemp", }; static const char * const iio_ev_type_text[] = { @@ -173,6 +174,7 @@ static bool event_is_known(struct iio_event_data *event) case IIO_POSITIONRELATIVE: case IIO_PHASE: case IIO_MASSCONCENTRATION: + case IIO_COLORTEMP: break; default: return false; From 5f05285df691b1e82108eead7165feae238c95ef Mon Sep 17 00:00:00 2001 From: Basavaraj Natikar Date: Tue, 19 Sep 2023 13:40:48 +0530 Subject: [PATCH 127/326] iio: hid-sensor-als: Add light color temperature support In most cases, ambient color sensors also support light color temperature. As a result, add support of light color temperature. Signed-off-by: Basavaraj Natikar Acked-by: Srinivas Pandruvada Link: https://lore.kernel.org/r/20230919081054.2050714-4-Basavaraj.Natikar@amd.com Signed-off-by: Jonathan Cameron --- drivers/iio/light/hid-sensor-als.c | 37 ++++++++++++++++++++++++++++-- include/linux/hid-sensor-ids.h | 1 + 2 files changed, 36 insertions(+), 2 deletions(-) diff --git a/drivers/iio/light/hid-sensor-als.c b/drivers/iio/light/hid-sensor-als.c index efb1f8862b28..16a3f1941c27 100644 --- a/drivers/iio/light/hid-sensor-als.c +++ b/drivers/iio/light/hid-sensor-als.c @@ -14,8 +14,9 @@ #include "../common/hid-sensors/hid-sensor-trigger.h" enum { - CHANNEL_SCAN_INDEX_INTENSITY = 0, - CHANNEL_SCAN_INDEX_ILLUM = 1, + CHANNEL_SCAN_INDEX_INTENSITY, + CHANNEL_SCAN_INDEX_ILLUM, + CHANNEL_SCAN_INDEX_COLOR_TEMP, CHANNEL_SCAN_INDEX_MAX }; @@ -65,6 +66,16 @@ static const struct iio_chan_spec als_channels[] = { BIT(IIO_CHAN_INFO_HYSTERESIS_RELATIVE), .scan_index = CHANNEL_SCAN_INDEX_ILLUM, }, + { + .type = IIO_COLORTEMP, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), + .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_OFFSET) | + BIT(IIO_CHAN_INFO_SCALE) | + BIT(IIO_CHAN_INFO_SAMP_FREQ) | + BIT(IIO_CHAN_INFO_HYSTERESIS) | + BIT(IIO_CHAN_INFO_HYSTERESIS_RELATIVE), + .scan_index = CHANNEL_SCAN_INDEX_COLOR_TEMP, + }, IIO_CHAN_SOFT_TIMESTAMP(CHANNEL_SCAN_INDEX_TIMESTAMP) }; @@ -103,6 +114,11 @@ static int als_read_raw(struct iio_dev *indio_dev, min = als_state->als[chan->scan_index].logical_minimum; address = HID_USAGE_SENSOR_LIGHT_ILLUM; break; + case CHANNEL_SCAN_INDEX_COLOR_TEMP: + report_id = als_state->als[chan->scan_index].report_id; + min = als_state->als[chan->scan_index].logical_minimum; + address = HID_USAGE_SENSOR_LIGHT_COLOR_TEMPERATURE; + break; default: report_id = -1; break; @@ -223,6 +239,10 @@ static int als_capture_sample(struct hid_sensor_hub_device *hsdev, als_state->scan.illum[CHANNEL_SCAN_INDEX_ILLUM] = sample_data; ret = 0; break; + case HID_USAGE_SENSOR_LIGHT_COLOR_TEMPERATURE: + als_state->scan.illum[CHANNEL_SCAN_INDEX_COLOR_TEMP] = sample_data; + ret = 0; + break; case HID_USAGE_SENSOR_TIME_TIMESTAMP: als_state->timestamp = hid_sensor_convert_timestamp(&als_state->common_attributes, *(s64 *)raw_data); @@ -258,6 +278,19 @@ static int als_parse_report(struct platform_device *pdev, st->als[i].report_id); } + ret = sensor_hub_input_get_attribute_info(hsdev, HID_INPUT_REPORT, + usage_id, + HID_USAGE_SENSOR_LIGHT_COLOR_TEMPERATURE, + &st->als[CHANNEL_SCAN_INDEX_COLOR_TEMP]); + if (ret < 0) + return ret; + als_adjust_channel_bit_mask(channels, CHANNEL_SCAN_INDEX_COLOR_TEMP, + st->als[CHANNEL_SCAN_INDEX_COLOR_TEMP].size); + + dev_dbg(&pdev->dev, "als %x:%x\n", + st->als[CHANNEL_SCAN_INDEX_COLOR_TEMP].index, + st->als[CHANNEL_SCAN_INDEX_COLOR_TEMP].report_id); + st->scale_precision = hid_sensor_format_scale(usage_id, &st->als[CHANNEL_SCAN_INDEX_INTENSITY], &st->scale_pre_decml, &st->scale_post_decml); diff --git a/include/linux/hid-sensor-ids.h b/include/linux/hid-sensor-ids.h index 13b1e65fbdcc..8af4fb3e0254 100644 --- a/include/linux/hid-sensor-ids.h +++ b/include/linux/hid-sensor-ids.h @@ -21,6 +21,7 @@ #define HID_USAGE_SENSOR_ALS 0x200041 #define HID_USAGE_SENSOR_DATA_LIGHT 0x2004d0 #define HID_USAGE_SENSOR_LIGHT_ILLUM 0x2004d1 +#define HID_USAGE_SENSOR_LIGHT_COLOR_TEMPERATURE 0x2004d2 /* PROX (200011) */ #define HID_USAGE_SENSOR_PROX 0x200011 From 908fee511ced79537b78db60f9b9bdb2f537679a Mon Sep 17 00:00:00 2001 From: Basavaraj Natikar Date: Tue, 19 Sep 2023 13:40:49 +0530 Subject: [PATCH 128/326] HID: amd_sfh: Add support for light color temperature In most cases, ambient color sensors also support light color temperature. As a result, add support of light color temperature. Signed-off-by: Basavaraj Natikar Acked-by: Jiri Kosina Link: https://lore.kernel.org/r/20230919081054.2050714-5-Basavaraj.Natikar@amd.com Signed-off-by: Jonathan Cameron --- drivers/hid/amd-sfh-hid/hid_descriptor/amd_sfh_hid_desc.c | 4 ++++ drivers/hid/amd-sfh-hid/hid_descriptor/amd_sfh_hid_desc.h | 1 + .../amd-sfh-hid/hid_descriptor/amd_sfh_hid_report_desc.h | 7 +++++++ 3 files changed, 12 insertions(+) diff --git a/drivers/hid/amd-sfh-hid/hid_descriptor/amd_sfh_hid_desc.c b/drivers/hid/amd-sfh-hid/hid_descriptor/amd_sfh_hid_desc.c index 8716a05950c8..b7e732ec4806 100644 --- a/drivers/hid/amd-sfh-hid/hid_descriptor/amd_sfh_hid_desc.c +++ b/drivers/hid/amd-sfh-hid/hid_descriptor/amd_sfh_hid_desc.c @@ -257,6 +257,10 @@ static u8 get_input_report(u8 current_index, int sensor_idx, int report_id, else als_input.illuminance_value = (int)sensor_virt_addr[0] / AMD_SFH_FW_MULTIPLIER; + + if (sensor_idx == ACS_IDX) + als_input.light_color_temp = sensor_virt_addr[1]; + report_size = sizeof(als_input); memcpy(input_report, &als_input, sizeof(als_input)); break; diff --git a/drivers/hid/amd-sfh-hid/hid_descriptor/amd_sfh_hid_desc.h b/drivers/hid/amd-sfh-hid/hid_descriptor/amd_sfh_hid_desc.h index ebd55675eb62..a7fc50deca4d 100644 --- a/drivers/hid/amd-sfh-hid/hid_descriptor/amd_sfh_hid_desc.h +++ b/drivers/hid/amd-sfh-hid/hid_descriptor/amd_sfh_hid_desc.h @@ -99,6 +99,7 @@ struct als_input_report { struct common_input_property common_property; /* values specific to this sensor */ int illuminance_value; + int light_color_temp; } __packed; struct hpd_feature_report { diff --git a/drivers/hid/amd-sfh-hid/hid_descriptor/amd_sfh_hid_report_desc.h b/drivers/hid/amd-sfh-hid/hid_descriptor/amd_sfh_hid_report_desc.h index 697f2791ea9c..26e994e54ded 100644 --- a/drivers/hid/amd-sfh-hid/hid_descriptor/amd_sfh_hid_report_desc.h +++ b/drivers/hid/amd-sfh-hid/hid_descriptor/amd_sfh_hid_report_desc.h @@ -641,6 +641,13 @@ static const u8 als_report_descriptor[] = { 0x75, 32, /* HID report size(32) */ 0x95, 1, /* HID report count (1) */ 0X81, 0x02, /* HID Input (Data_Arr_Abs) */ +0x0A, 0xD2, 0x04, /* HID usage sensor data light temperature */ +0x17, 0x00, 0x00, 0x01, 0x80, /* HID logical Min_32 */ +0x27, 0xFF, 0xFF, 0xFF, 0x7F, /* HID logical Max_32 */ +0x55, 0x0, /* HID unit exponent(0x0) */ +0x75, 32, /* HID report size(32) */ +0x95, 1, /* HID report count (1) */ +0X81, 0x02, /* HID Input (Data_Arr_Abs) */ 0xC0 /* HID end collection */ }; From 82cdcdf227f3965cce3ac94bc2e473e9c898f402 Mon Sep 17 00:00:00 2001 From: Basavaraj Natikar Date: Tue, 19 Sep 2023 13:40:50 +0530 Subject: [PATCH 129/326] HID: amd_sfh: Add support for SFH1.1 light color temperature In most cases, ambient color sensors also support light color temperature. As a result, add support of light color temperature for SFH1.1. Signed-off-by: Basavaraj Natikar Acked-by: Jiri Kosina Link: https://lore.kernel.org/r/20230919081054.2050714-6-Basavaraj.Natikar@amd.com Signed-off-by: Jonathan Cameron --- drivers/hid/amd-sfh-hid/sfh1_1/amd_sfh_desc.c | 6 ++++++ drivers/hid/amd-sfh-hid/sfh1_1/amd_sfh_interface.h | 13 +++++++++++++ 2 files changed, 19 insertions(+) diff --git a/drivers/hid/amd-sfh-hid/sfh1_1/amd_sfh_desc.c b/drivers/hid/amd-sfh-hid/sfh1_1/amd_sfh_desc.c index 06bdcf072d10..f100aaafa167 100644 --- a/drivers/hid/amd-sfh-hid/sfh1_1/amd_sfh_desc.c +++ b/drivers/hid/amd-sfh-hid/sfh1_1/amd_sfh_desc.c @@ -188,6 +188,7 @@ static u8 get_input_rep(u8 current_index, int sensor_idx, int report_id, struct sfh_mag_data mag_data; struct sfh_als_data als_data; struct hpd_status hpdstatus; + struct sfh_base_info binfo; void __iomem *sensoraddr; u8 report_size = 0; @@ -235,6 +236,11 @@ static u8 get_input_rep(u8 current_index, int sensor_idx, int report_id, memcpy_fromio(&als_data, sensoraddr, sizeof(struct sfh_als_data)); get_common_inputs(&als_input.common_property, report_id); als_input.illuminance_value = float_to_int(als_data.lux); + + memcpy_fromio(&binfo, mp2->vsbase, sizeof(struct sfh_base_info)); + if (binfo.sbase.s_prop[ALS_IDX].sf.feat & 0x2) + als_input.light_color_temp = als_data.light_color_temp; + report_size = sizeof(als_input); memcpy(input_report, &als_input, sizeof(als_input)); break; diff --git a/drivers/hid/amd-sfh-hid/sfh1_1/amd_sfh_interface.h b/drivers/hid/amd-sfh-hid/sfh1_1/amd_sfh_interface.h index 9d31d5b510eb..6f6f5db150c3 100644 --- a/drivers/hid/amd-sfh-hid/sfh1_1/amd_sfh_interface.h +++ b/drivers/hid/amd-sfh-hid/sfh1_1/amd_sfh_interface.h @@ -88,6 +88,16 @@ struct sfh_sensor_list { }; }; +struct sfh_sensor_prop { + union { + u32 sprop; + struct { + u32 elist : 16; + u32 feat : 16; + } sf; + }; +}; + struct sfh_base_info { union { u32 sfh_base[24]; @@ -95,6 +105,8 @@ struct sfh_base_info { struct sfh_platform_info plat_info; struct sfh_firmware_info fw_info; struct sfh_sensor_list s_list; + u32 rsvd; + struct sfh_sensor_prop s_prop[16]; } sbase; }; }; @@ -134,6 +146,7 @@ struct sfh_mag_data { struct sfh_als_data { struct sfh_common_data commondata; u32 lux; + u32 light_color_temp; }; struct hpd_status { From 06790d4c69d1851573baa4459e5bf6ac986cb0eb Mon Sep 17 00:00:00 2001 From: Basavaraj Natikar Date: Tue, 19 Sep 2023 13:40:51 +0530 Subject: [PATCH 130/326] iio: Add channel type for chromaticity In most cases, ambient color sensors also support the x and y light colors, which represent the coordinates on the CIE 1931 chromaticity diagram. Thus, add channel type for chromaticity. Signed-off-by: Basavaraj Natikar Link: https://lore.kernel.org/r/20230919081054.2050714-7-Basavaraj.Natikar@amd.com Signed-off-by: Jonathan Cameron --- Documentation/ABI/testing/sysfs-bus-iio | 8 ++++++++ drivers/iio/industrialio-core.c | 1 + include/uapi/linux/iio/types.h | 1 + tools/iio/iio_event_monitor.c | 2 ++ 4 files changed, 12 insertions(+) diff --git a/Documentation/ABI/testing/sysfs-bus-iio b/Documentation/ABI/testing/sysfs-bus-iio index 4cf7ed9ca57b..0c9389ad3709 100644 --- a/Documentation/ABI/testing/sysfs-bus-iio +++ b/Documentation/ABI/testing/sysfs-bus-iio @@ -2186,3 +2186,11 @@ Contact: linux-iio@vger.kernel.org Description: Represents light color temperature, which measures light color temperature in Kelvin. + +What: /sys/bus/iio/devices/iio:deviceX/in_chromaticity_x_raw +What: /sys/bus/iio/devices/iio:deviceX/in_chromaticity_y_raw +KernelVersion: 6.7 +Contact: linux-iio@vger.kernel.org +Description: + The x and y light color coordinate on the CIE 1931 chromaticity + diagram. diff --git a/drivers/iio/industrialio-core.c b/drivers/iio/industrialio-core.c index cba942cadf97..6dc4d2b296bb 100644 --- a/drivers/iio/industrialio-core.c +++ b/drivers/iio/industrialio-core.c @@ -91,6 +91,7 @@ static const char * const iio_chan_type_name_spec[] = { [IIO_PHASE] = "phase", [IIO_MASSCONCENTRATION] = "massconcentration", [IIO_COLORTEMP] = "colortemp", + [IIO_CHROMATICITY] = "chromaticity", }; static const char * const iio_modifier_names[] = { diff --git a/include/uapi/linux/iio/types.h b/include/uapi/linux/iio/types.h index 08c20e540c13..4832c611c027 100644 --- a/include/uapi/linux/iio/types.h +++ b/include/uapi/linux/iio/types.h @@ -48,6 +48,7 @@ enum iio_chan_type { IIO_PHASE, IIO_MASSCONCENTRATION, IIO_COLORTEMP, + IIO_CHROMATICITY, }; enum iio_modifier { diff --git a/tools/iio/iio_event_monitor.c b/tools/iio/iio_event_monitor.c index a63741e43ddf..a28a86f2bd5b 100644 --- a/tools/iio/iio_event_monitor.c +++ b/tools/iio/iio_event_monitor.c @@ -60,6 +60,7 @@ static const char * const iio_chan_type_name_spec[] = { [IIO_PHASE] = "phase", [IIO_MASSCONCENTRATION] = "massconcentration", [IIO_COLORTEMP] = "colortemp", + [IIO_CHROMATICITY] = "chromaticity", }; static const char * const iio_ev_type_text[] = { @@ -175,6 +176,7 @@ static bool event_is_known(struct iio_event_data *event) case IIO_PHASE: case IIO_MASSCONCENTRATION: case IIO_COLORTEMP: + case IIO_CHROMATICITY: break; default: return false; From ee3710f39f9d0ae5137a866138d005fe1ad18132 Mon Sep 17 00:00:00 2001 From: Basavaraj Natikar Date: Tue, 19 Sep 2023 13:40:52 +0530 Subject: [PATCH 131/326] iio: hid-sensor-als: Add light chromaticity support In most cases, ambient color sensors also support the x and y light colors, which represent the coordinates on the CIE 1931 chromaticity diagram. Thus, add light chromaticity x and y. Signed-off-by: Basavaraj Natikar Acked-by: Srinivas Pandruvada Link: https://lore.kernel.org/r/20230919081054.2050714-8-Basavaraj.Natikar@amd.com Signed-off-by: Jonathan Cameron --- drivers/iio/light/hid-sensor-als.c | 63 ++++++++++++++++++++++++++++++ include/linux/hid-sensor-ids.h | 3 ++ 2 files changed, 66 insertions(+) diff --git a/drivers/iio/light/hid-sensor-als.c b/drivers/iio/light/hid-sensor-als.c index 16a3f1941c27..c9d114ff080a 100644 --- a/drivers/iio/light/hid-sensor-als.c +++ b/drivers/iio/light/hid-sensor-als.c @@ -17,6 +17,8 @@ enum { CHANNEL_SCAN_INDEX_INTENSITY, CHANNEL_SCAN_INDEX_ILLUM, CHANNEL_SCAN_INDEX_COLOR_TEMP, + CHANNEL_SCAN_INDEX_CHROMATICITY_X, + CHANNEL_SCAN_INDEX_CHROMATICITY_Y, CHANNEL_SCAN_INDEX_MAX }; @@ -76,6 +78,30 @@ static const struct iio_chan_spec als_channels[] = { BIT(IIO_CHAN_INFO_HYSTERESIS_RELATIVE), .scan_index = CHANNEL_SCAN_INDEX_COLOR_TEMP, }, + { + .type = IIO_CHROMATICITY, + .modified = 1, + .channel2 = IIO_MOD_X, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), + .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_OFFSET) | + BIT(IIO_CHAN_INFO_SCALE) | + BIT(IIO_CHAN_INFO_SAMP_FREQ) | + BIT(IIO_CHAN_INFO_HYSTERESIS) | + BIT(IIO_CHAN_INFO_HYSTERESIS_RELATIVE), + .scan_index = CHANNEL_SCAN_INDEX_CHROMATICITY_X, + }, + { + .type = IIO_CHROMATICITY, + .modified = 1, + .channel2 = IIO_MOD_Y, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), + .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_OFFSET) | + BIT(IIO_CHAN_INFO_SCALE) | + BIT(IIO_CHAN_INFO_SAMP_FREQ) | + BIT(IIO_CHAN_INFO_HYSTERESIS) | + BIT(IIO_CHAN_INFO_HYSTERESIS_RELATIVE), + .scan_index = CHANNEL_SCAN_INDEX_CHROMATICITY_Y, + }, IIO_CHAN_SOFT_TIMESTAMP(CHANNEL_SCAN_INDEX_TIMESTAMP) }; @@ -119,6 +145,16 @@ static int als_read_raw(struct iio_dev *indio_dev, min = als_state->als[chan->scan_index].logical_minimum; address = HID_USAGE_SENSOR_LIGHT_COLOR_TEMPERATURE; break; + case CHANNEL_SCAN_INDEX_CHROMATICITY_X: + report_id = als_state->als[chan->scan_index].report_id; + min = als_state->als[chan->scan_index].logical_minimum; + address = HID_USAGE_SENSOR_LIGHT_CHROMATICITY_X; + break; + case CHANNEL_SCAN_INDEX_CHROMATICITY_Y: + report_id = als_state->als[chan->scan_index].report_id; + min = als_state->als[chan->scan_index].logical_minimum; + address = HID_USAGE_SENSOR_LIGHT_CHROMATICITY_Y; + break; default: report_id = -1; break; @@ -243,6 +279,14 @@ static int als_capture_sample(struct hid_sensor_hub_device *hsdev, als_state->scan.illum[CHANNEL_SCAN_INDEX_COLOR_TEMP] = sample_data; ret = 0; break; + case HID_USAGE_SENSOR_LIGHT_CHROMATICITY_X: + als_state->scan.illum[CHANNEL_SCAN_INDEX_CHROMATICITY_X] = sample_data; + ret = 0; + break; + case HID_USAGE_SENSOR_LIGHT_CHROMATICITY_Y: + als_state->scan.illum[CHANNEL_SCAN_INDEX_CHROMATICITY_Y] = sample_data; + ret = 0; + break; case HID_USAGE_SENSOR_TIME_TIMESTAMP: als_state->timestamp = hid_sensor_convert_timestamp(&als_state->common_attributes, *(s64 *)raw_data); @@ -291,6 +335,25 @@ static int als_parse_report(struct platform_device *pdev, st->als[CHANNEL_SCAN_INDEX_COLOR_TEMP].index, st->als[CHANNEL_SCAN_INDEX_COLOR_TEMP].report_id); + for (i = 0; i < 2; i++) { + int next_scan_index = CHANNEL_SCAN_INDEX_CHROMATICITY_X + i; + + ret = sensor_hub_input_get_attribute_info(hsdev, + HID_INPUT_REPORT, usage_id, + HID_USAGE_SENSOR_LIGHT_CHROMATICITY_X + i, + &st->als[next_scan_index]); + if (ret < 0) + return ret; + + als_adjust_channel_bit_mask(channels, + CHANNEL_SCAN_INDEX_CHROMATICITY_X + i, + st->als[next_scan_index].size); + + dev_dbg(&pdev->dev, "als %x:%x\n", + st->als[next_scan_index].index, + st->als[next_scan_index].report_id); + } + st->scale_precision = hid_sensor_format_scale(usage_id, &st->als[CHANNEL_SCAN_INDEX_INTENSITY], &st->scale_pre_decml, &st->scale_post_decml); diff --git a/include/linux/hid-sensor-ids.h b/include/linux/hid-sensor-ids.h index 8af4fb3e0254..6730ee900ee1 100644 --- a/include/linux/hid-sensor-ids.h +++ b/include/linux/hid-sensor-ids.h @@ -22,6 +22,9 @@ #define HID_USAGE_SENSOR_DATA_LIGHT 0x2004d0 #define HID_USAGE_SENSOR_LIGHT_ILLUM 0x2004d1 #define HID_USAGE_SENSOR_LIGHT_COLOR_TEMPERATURE 0x2004d2 +#define HID_USAGE_SENSOR_LIGHT_CHROMATICITY 0x2004d3 +#define HID_USAGE_SENSOR_LIGHT_CHROMATICITY_X 0x2004d4 +#define HID_USAGE_SENSOR_LIGHT_CHROMATICITY_Y 0x2004d5 /* PROX (200011) */ #define HID_USAGE_SENSOR_PROX 0x200011 From 3244d44a7c5e6961d79eafa44370ff13c909d670 Mon Sep 17 00:00:00 2001 From: Basavaraj Natikar Date: Tue, 19 Sep 2023 13:40:53 +0530 Subject: [PATCH 132/326] HID: amd_sfh: Add light chromaticity support In most cases, ambient color sensors also support the x and y light colors, which represent the coordinates on the CIE 1931 chromaticity diagram. Thus, add light chromaticity x and y. Signed-off-by: Basavaraj Natikar Acked-by: Jiri Kosina Link: https://lore.kernel.org/r/20230919081054.2050714-9-Basavaraj.Natikar@amd.com Signed-off-by: Jonathan Cameron --- .../amd-sfh-hid/hid_descriptor/amd_sfh_hid_desc.c | 5 ++++- .../amd-sfh-hid/hid_descriptor/amd_sfh_hid_desc.h | 2 ++ .../hid_descriptor/amd_sfh_hid_report_desc.h | 14 ++++++++++++++ 3 files changed, 20 insertions(+), 1 deletion(-) diff --git a/drivers/hid/amd-sfh-hid/hid_descriptor/amd_sfh_hid_desc.c b/drivers/hid/amd-sfh-hid/hid_descriptor/amd_sfh_hid_desc.c index b7e732ec4806..ef1f9be8b893 100644 --- a/drivers/hid/amd-sfh-hid/hid_descriptor/amd_sfh_hid_desc.c +++ b/drivers/hid/amd-sfh-hid/hid_descriptor/amd_sfh_hid_desc.c @@ -258,8 +258,11 @@ static u8 get_input_report(u8 current_index, int sensor_idx, int report_id, als_input.illuminance_value = (int)sensor_virt_addr[0] / AMD_SFH_FW_MULTIPLIER; - if (sensor_idx == ACS_IDX) + if (sensor_idx == ACS_IDX) { als_input.light_color_temp = sensor_virt_addr[1]; + als_input.chromaticity_x_value = sensor_virt_addr[2]; + als_input.chromaticity_y_value = sensor_virt_addr[3]; + } report_size = sizeof(als_input); memcpy(input_report, &als_input, sizeof(als_input)); diff --git a/drivers/hid/amd-sfh-hid/hid_descriptor/amd_sfh_hid_desc.h b/drivers/hid/amd-sfh-hid/hid_descriptor/amd_sfh_hid_desc.h index a7fc50deca4d..882434b1501f 100644 --- a/drivers/hid/amd-sfh-hid/hid_descriptor/amd_sfh_hid_desc.h +++ b/drivers/hid/amd-sfh-hid/hid_descriptor/amd_sfh_hid_desc.h @@ -100,6 +100,8 @@ struct als_input_report { /* values specific to this sensor */ int illuminance_value; int light_color_temp; + int chromaticity_x_value; + int chromaticity_y_value; } __packed; struct hpd_feature_report { diff --git a/drivers/hid/amd-sfh-hid/hid_descriptor/amd_sfh_hid_report_desc.h b/drivers/hid/amd-sfh-hid/hid_descriptor/amd_sfh_hid_report_desc.h index 26e994e54ded..67ec2d6a417d 100644 --- a/drivers/hid/amd-sfh-hid/hid_descriptor/amd_sfh_hid_report_desc.h +++ b/drivers/hid/amd-sfh-hid/hid_descriptor/amd_sfh_hid_report_desc.h @@ -648,6 +648,20 @@ static const u8 als_report_descriptor[] = { 0x75, 32, /* HID report size(32) */ 0x95, 1, /* HID report count (1) */ 0X81, 0x02, /* HID Input (Data_Arr_Abs) */ +0x0A, 0xD4, 0x04, /* HID usage sensor data light chromaticity_x */ +0x17, 0x00, 0x00, 0x01, 0x80, /* HID logical Min_32 */ +0x27, 0xFF, 0xFF, 0xFF, 0x7F, /* HID logical Max_32 */ +0x55, 0x0, /* HID unit exponent(0x0) */ +0x75, 32, /* HID report size(32) */ +0x95, 1, /* HID report count(1) */ +0X81, 0x02, /* HID Input (Data_Var_Abs) */ +0x0A, 0xD5, 0x04, /* HID usage sensor data light chromaticity_y */ +0x17, 0x00, 0x00, 0x01, 0x80, /* HID logical Min_32 */ +0x27, 0xFF, 0xFF, 0xFF, 0x7F, /* HID logical Max_32 */ +0x55, 0x0, /* HID unit exponent(0x0) */ +0x75, 32, /* HID report size(32) */ +0x95, 1, /* HID report count (1) */ +0X81, 0x02, /* HID Input (Data_Var_Abs) */ 0xC0 /* HID end collection */ }; From c6c97210e27237438689611980f8a7b87bcc79bf Mon Sep 17 00:00:00 2001 From: Basavaraj Natikar Date: Tue, 19 Sep 2023 13:40:54 +0530 Subject: [PATCH 133/326] HID: amd_sfh: Add light chromaticity for SFH1.1 In most cases, ambient color sensors also support the x and y light colors, which represent the coordinates on the CIE 1931 chromaticity diagram. Thus, add light chromaticity x and y for SFH1.1. Signed-off-by: Basavaraj Natikar Acked-by: Jiri Kosina Link: https://lore.kernel.org/r/20230919081054.2050714-10-Basavaraj.Natikar@amd.com Signed-off-by: Jonathan Cameron --- drivers/hid/amd-sfh-hid/sfh1_1/amd_sfh_desc.c | 5 ++++- drivers/hid/amd-sfh-hid/sfh1_1/amd_sfh_interface.h | 2 ++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/hid/amd-sfh-hid/sfh1_1/amd_sfh_desc.c b/drivers/hid/amd-sfh-hid/sfh1_1/amd_sfh_desc.c index f100aaafa167..8a037de08e92 100644 --- a/drivers/hid/amd-sfh-hid/sfh1_1/amd_sfh_desc.c +++ b/drivers/hid/amd-sfh-hid/sfh1_1/amd_sfh_desc.c @@ -238,8 +238,11 @@ static u8 get_input_rep(u8 current_index, int sensor_idx, int report_id, als_input.illuminance_value = float_to_int(als_data.lux); memcpy_fromio(&binfo, mp2->vsbase, sizeof(struct sfh_base_info)); - if (binfo.sbase.s_prop[ALS_IDX].sf.feat & 0x2) + if (binfo.sbase.s_prop[ALS_IDX].sf.feat & 0x2) { als_input.light_color_temp = als_data.light_color_temp; + als_input.chromaticity_x_value = float_to_int(als_data.chromaticity_x); + als_input.chromaticity_y_value = float_to_int(als_data.chromaticity_y); + } report_size = sizeof(als_input); memcpy(input_report, &als_input, sizeof(als_input)); diff --git a/drivers/hid/amd-sfh-hid/sfh1_1/amd_sfh_interface.h b/drivers/hid/amd-sfh-hid/sfh1_1/amd_sfh_interface.h index 6f6f5db150c3..656c3e95ef8c 100644 --- a/drivers/hid/amd-sfh-hid/sfh1_1/amd_sfh_interface.h +++ b/drivers/hid/amd-sfh-hid/sfh1_1/amd_sfh_interface.h @@ -147,6 +147,8 @@ struct sfh_als_data { struct sfh_common_data commondata; u32 lux; u32 light_color_temp; + u32 chromaticity_x; + u32 chromaticity_y; }; struct hpd_status { From efea15e3c65d96bac17a4d8104e3fff7c07cc910 Mon Sep 17 00:00:00 2001 From: Marius Cristea Date: Mon, 18 Sep 2023 10:56:33 +0300 Subject: [PATCH 134/326] iio: adc: MCP3564: fix the static checker warning MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The patch 33ec3e5fc1ea: "iio: adc: adding support for MCP3564 ADC" from Aug 29, 2023 (linux-next), leads to the following Smatch static checker warning:         drivers/iio/adc/mcp3564.c:1426 mcp3564_probe()         warn: address of NULL pointer 'indio_dev' drivers/iio/adc/mcp3564.c 1421 struct iio_dev *indio_dev; 1422 struct mcp3564_state *adc; 1423 1424 indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*adc)); 1425 if (!indio_dev) { --> 1426 dev_err_probe(&indio_dev->dev, PTR_ERR(indio_dev), ^^^^^^^^^^^^^^^ Fixes: 33ec3e5fc1ea (iio: adc: adding support for MCP3564 ADC) Signed-off-by: Marius Cristea Link: https://lore.kernel.org/r/20230918075633.1884-1-marius.cristea@microchip.com Signed-off-by: Jonathan Cameron --- drivers/iio/adc/mcp3564.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/drivers/iio/adc/mcp3564.c b/drivers/iio/adc/mcp3564.c index 64145f4ae55c..9ede1a5d5d7b 100644 --- a/drivers/iio/adc/mcp3564.c +++ b/drivers/iio/adc/mcp3564.c @@ -1422,11 +1422,8 @@ static int mcp3564_probe(struct spi_device *spi) struct mcp3564_state *adc; indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*adc)); - if (!indio_dev) { - dev_err_probe(&indio_dev->dev, PTR_ERR(indio_dev), - "Can't allocate iio device\n"); + if (!indio_dev) return -ENOMEM; - } adc = iio_priv(indio_dev); adc->spi = spi; From c78a96ab0f52a12b344882241019dd9070aa988c Mon Sep 17 00:00:00 2001 From: David Lechner Date: Thu, 21 Sep 2023 09:43:44 -0500 Subject: [PATCH 135/326] staging: iio: resolver: ad2s1210: fix ad2s1210_show_fault When reading the fault attribute, an empty string was printed if the fault register value was non-zero. This is fixed by checking that the return value is less than zero instead of not zero. Also always print two hex digits while we are touching this line. Signed-off-by: David Lechner Link: https://lore.kernel.org/r/20230921144400.62380-4-dlechner@baylibre.com Signed-off-by: Jonathan Cameron --- drivers/staging/iio/resolver/ad2s1210.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/staging/iio/resolver/ad2s1210.c b/drivers/staging/iio/resolver/ad2s1210.c index 06de5823eb8e..7fb2d9e3196f 100644 --- a/drivers/staging/iio/resolver/ad2s1210.c +++ b/drivers/staging/iio/resolver/ad2s1210.c @@ -393,7 +393,7 @@ static ssize_t ad2s1210_show_fault(struct device *dev, ret = ad2s1210_config_read(st, AD2S1210_REG_FAULT); mutex_unlock(&st->lock); - return ret ? ret : sprintf(buf, "0x%x\n", ret); + return ret < 0 ? ret : sprintf(buf, "0x%02x\n", ret); } static ssize_t ad2s1210_clear_fault(struct device *dev, From 5e99f692d4e32e3250ab18d511894ca797407aec Mon Sep 17 00:00:00 2001 From: David Lechner Date: Thu, 21 Sep 2023 09:43:45 -0500 Subject: [PATCH 136/326] staging: iio: resolver: ad2s1210: fix not restoring sample gpio in channel read In theory, this code path should not be reachable because of the previous switch statement. But just in case we should make sure we are restoring the SAMPLE gpio to its original state before returning in addition to releasing the mutex lock. Signed-off-by: David Lechner Link: https://lore.kernel.org/r/20230921144400.62380-5-dlechner@baylibre.com Signed-off-by: Jonathan Cameron --- drivers/staging/iio/resolver/ad2s1210.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/staging/iio/resolver/ad2s1210.c b/drivers/staging/iio/resolver/ad2s1210.c index 7fb2d9e3196f..f695ca0547e4 100644 --- a/drivers/staging/iio/resolver/ad2s1210.c +++ b/drivers/staging/iio/resolver/ad2s1210.c @@ -510,8 +510,8 @@ static int ad2s1210_read_raw(struct iio_dev *indio_dev, ret = IIO_VAL_INT; break; default: - mutex_unlock(&st->lock); - return -EINVAL; + ret = -EINVAL; + break; } error_ret: From 7fe2d05cee46b1c4d9f1efaeab08cc31a0dfff60 Mon Sep 17 00:00:00 2001 From: David Lechner Date: Fri, 29 Sep 2023 12:23:07 -0500 Subject: [PATCH 137/326] staging: iio: resolver: ad2s1210: fix use before initialization This fixes a use before initialization in ad2s1210_probe(). The ad2s1210_setup_gpios() function uses st->sdev but it was being called before this field was initialized. Signed-off-by: David Lechner Link: https://lore.kernel.org/r/20230929-ad2s1210-mainline-v3-2-fa4364281745@baylibre.com Signed-off-by: Jonathan Cameron --- drivers/staging/iio/resolver/ad2s1210.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/staging/iio/resolver/ad2s1210.c b/drivers/staging/iio/resolver/ad2s1210.c index f695ca0547e4..3f08b59f4e19 100644 --- a/drivers/staging/iio/resolver/ad2s1210.c +++ b/drivers/staging/iio/resolver/ad2s1210.c @@ -658,9 +658,6 @@ static int ad2s1210_probe(struct spi_device *spi) if (!indio_dev) return -ENOMEM; st = iio_priv(indio_dev); - ret = ad2s1210_setup_gpios(st); - if (ret < 0) - return ret; spi_set_drvdata(spi, indio_dev); @@ -671,6 +668,10 @@ static int ad2s1210_probe(struct spi_device *spi) st->resolution = 12; st->fexcit = AD2S1210_DEF_EXCIT; + ret = ad2s1210_setup_gpios(st); + if (ret < 0) + return ret; + indio_dev->info = &ad2s1210_info; indio_dev->modes = INDIO_DIRECT_MODE; indio_dev->channels = ad2s1210_channels; From 9829ebacea804ad4b5d1a74a8d94a1f843505546 Mon Sep 17 00:00:00 2001 From: David Lechner Date: Fri, 29 Sep 2023 12:23:08 -0500 Subject: [PATCH 138/326] staging: iio: resolver: ad2s1210: remove call to spi_setup() This removes the call to spi_setup() in the ad2s1210 driver. Setting MODE_3 was incorrect. It should be MODE_1 but we can let the device tree select this and avoid the need to call spi_setup(). Signed-off-by: David Lechner Link: https://lore.kernel.org/r/20230929-ad2s1210-mainline-v3-3-fa4364281745@baylibre.com Signed-off-by: Jonathan Cameron --- drivers/staging/iio/resolver/ad2s1210.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/staging/iio/resolver/ad2s1210.c b/drivers/staging/iio/resolver/ad2s1210.c index 3f08b59f4e19..8fde08887f7f 100644 --- a/drivers/staging/iio/resolver/ad2s1210.c +++ b/drivers/staging/iio/resolver/ad2s1210.c @@ -683,8 +683,6 @@ static int ad2s1210_probe(struct spi_device *spi) return ret; st->fclkin = spi->max_speed_hz; - spi->mode = SPI_MODE_3; - spi_setup(spi); ad2s1210_initial(st); return 0; From 3c1f41d5f320a001507257ca3504716e8f8bc00c Mon Sep 17 00:00:00 2001 From: David Lechner Date: Fri, 29 Sep 2023 12:23:09 -0500 Subject: [PATCH 139/326] staging: iio: resolver: ad2s1210: check return of ad2s1210_initial() This adds a check to the return value of ad2s1210_initial() since it can fail. The call is also moved before devm_iio_device_register() so that we don't have to unregister the device if it fails. Signed-off-by: David Lechner Link: https://lore.kernel.org/r/20230929-ad2s1210-mainline-v3-4-fa4364281745@baylibre.com Signed-off-by: Jonathan Cameron --- drivers/staging/iio/resolver/ad2s1210.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/staging/iio/resolver/ad2s1210.c b/drivers/staging/iio/resolver/ad2s1210.c index 8fde08887f7f..b5e071d7c5fd 100644 --- a/drivers/staging/iio/resolver/ad2s1210.c +++ b/drivers/staging/iio/resolver/ad2s1210.c @@ -672,6 +672,10 @@ static int ad2s1210_probe(struct spi_device *spi) if (ret < 0) return ret; + ret = ad2s1210_initial(st); + if (ret < 0) + return ret; + indio_dev->info = &ad2s1210_info; indio_dev->modes = INDIO_DIRECT_MODE; indio_dev->channels = ad2s1210_channels; @@ -683,7 +687,6 @@ static int ad2s1210_probe(struct spi_device *spi) return ret; st->fclkin = spi->max_speed_hz; - ad2s1210_initial(st); return 0; } From f434eac79bee6e44d7d46113391e55d9157cbc65 Mon Sep 17 00:00:00 2001 From: David Lechner Date: Fri, 29 Sep 2023 12:23:10 -0500 Subject: [PATCH 140/326] staging: iio: resolver: ad2s1210: remove spi_set_drvdata() Since we never call spi_get_drvdata(), we can remove spi_set_drvdata(). Signed-off-by: David Lechner Link: https://lore.kernel.org/r/20230929-ad2s1210-mainline-v3-5-fa4364281745@baylibre.com Signed-off-by: Jonathan Cameron --- drivers/staging/iio/resolver/ad2s1210.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/staging/iio/resolver/ad2s1210.c b/drivers/staging/iio/resolver/ad2s1210.c index b5e071d7c5fd..28015322f562 100644 --- a/drivers/staging/iio/resolver/ad2s1210.c +++ b/drivers/staging/iio/resolver/ad2s1210.c @@ -659,8 +659,6 @@ static int ad2s1210_probe(struct spi_device *spi) return -ENOMEM; st = iio_priv(indio_dev); - spi_set_drvdata(spi, indio_dev); - mutex_init(&st->lock); st->sdev = spi; st->hysteresis = true; From acbfaee17014811d96d9094ce2fb723384dfc009 Mon Sep 17 00:00:00 2001 From: David Lechner Date: Fri, 29 Sep 2023 12:23:11 -0500 Subject: [PATCH 141/326] staging: iio: resolver: ad2s1210: sort imports There are quite a few imports and we will be adding more so it will make it easier to read if they are sorted. Signed-off-by: David Lechner Link: https://lore.kernel.org/r/20230929-ad2s1210-mainline-v3-6-fa4364281745@baylibre.com Signed-off-by: Jonathan Cameron --- drivers/staging/iio/resolver/ad2s1210.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/staging/iio/resolver/ad2s1210.c b/drivers/staging/iio/resolver/ad2s1210.c index 28015322f562..832f86bf15e5 100644 --- a/drivers/staging/iio/resolver/ad2s1210.c +++ b/drivers/staging/iio/resolver/ad2s1210.c @@ -4,16 +4,16 @@ * * Copyright (c) 2010-2010 Analog Devices Inc. */ -#include -#include -#include -#include -#include -#include -#include #include +#include #include #include +#include +#include +#include +#include +#include +#include #include #include From 1b6eba71cae261d504d5826897a22a9a45f200d2 Mon Sep 17 00:00:00 2001 From: David Lechner Date: Fri, 29 Sep 2023 12:23:12 -0500 Subject: [PATCH 142/326] staging: iio: resolver: ad2s1210: always use 16-bit value for raw read This removes the special handling for resolutions lower than 16 bits. This will allow us to use a fixed scale independent of the resolution. A new sample field is added to store the raw data instead of reusing the config mode rx buffer so that we don't have to do a cast or worry about unaligned access. Also, for the record, according to the datasheet, the logic for the special handling based on hysteresis that was removed was incorrect. Signed-off-by: David Lechner Link: https://lore.kernel.org/r/20230929-ad2s1210-mainline-v3-7-fa4364281745@baylibre.com Signed-off-by: Jonathan Cameron --- drivers/staging/iio/resolver/ad2s1210.c | 24 ++++++++---------------- 1 file changed, 8 insertions(+), 16 deletions(-) diff --git a/drivers/staging/iio/resolver/ad2s1210.c b/drivers/staging/iio/resolver/ad2s1210.c index 832f86bf15e5..f9774dff2df4 100644 --- a/drivers/staging/iio/resolver/ad2s1210.c +++ b/drivers/staging/iio/resolver/ad2s1210.c @@ -95,7 +95,11 @@ struct ad2s1210_state { bool hysteresis; u8 resolution; enum ad2s1210_mode mode; - u8 rx[2] __aligned(IIO_DMA_MINALIGN); + /** For reading raw sample value via SPI. */ + __be16 sample __aligned(IIO_DMA_MINALIGN); + /** SPI transmit buffer. */ + u8 rx[2]; + /** SPI receive buffer. */ u8 tx[2]; }; @@ -464,10 +468,7 @@ static int ad2s1210_read_raw(struct iio_dev *indio_dev, long m) { struct ad2s1210_state *st = iio_priv(indio_dev); - u16 negative; int ret = 0; - u16 pos; - s16 vel; mutex_lock(&st->lock); gpiod_set_value(st->gpios[AD2S1210_SAMPLE], 0); @@ -487,26 +488,17 @@ static int ad2s1210_read_raw(struct iio_dev *indio_dev, } if (ret < 0) goto error_ret; - ret = spi_read(st->sdev, st->rx, 2); + ret = spi_read(st->sdev, &st->sample, 2); if (ret < 0) goto error_ret; switch (chan->type) { case IIO_ANGL: - pos = be16_to_cpup((__be16 *)st->rx); - if (st->hysteresis) - pos >>= 16 - st->resolution; - *val = pos; + *val = be16_to_cpu(st->sample); ret = IIO_VAL_INT; break; case IIO_ANGL_VEL: - vel = be16_to_cpup((__be16 *)st->rx); - vel >>= 16 - st->resolution; - if (vel & 0x8000) { - negative = (0xffff >> st->resolution) << st->resolution; - vel |= negative; - } - *val = vel; + *val = (s16)be16_to_cpu(st->sample); ret = IIO_VAL_INT; break; default: From 4623b414e68bb57ce30fe286ca932202fc438a16 Mon Sep 17 00:00:00 2001 From: David Lechner Date: Fri, 29 Sep 2023 12:23:13 -0500 Subject: [PATCH 143/326] staging: iio: resolver: ad2s1210: implement IIO_CHAN_INFO_SCALE This adds an implementation of IIO_CHAN_INFO_SCALE to the ad2s1210 resolver driver. This allows userspace to get the scale factor for the raw values. Signed-off-by: David Lechner Link: https://lore.kernel.org/r/20230929-ad2s1210-mainline-v3-8-fa4364281745@baylibre.com Signed-off-by: Jonathan Cameron --- drivers/staging/iio/resolver/ad2s1210.c | 53 +++++++++++++++++++++---- 1 file changed, 45 insertions(+), 8 deletions(-) diff --git a/drivers/staging/iio/resolver/ad2s1210.c b/drivers/staging/iio/resolver/ad2s1210.c index f9774dff2df4..a710598a64f0 100644 --- a/drivers/staging/iio/resolver/ad2s1210.c +++ b/drivers/staging/iio/resolver/ad2s1210.c @@ -461,13 +461,10 @@ error_ret: return ret < 0 ? ret : len; } -static int ad2s1210_read_raw(struct iio_dev *indio_dev, - struct iio_chan_spec const *chan, - int *val, - int *val2, - long m) +static int ad2s1210_single_conversion(struct ad2s1210_state *st, + struct iio_chan_spec const *chan, + int *val) { - struct ad2s1210_state *st = iio_priv(indio_dev); int ret = 0; mutex_lock(&st->lock); @@ -514,6 +511,44 @@ error_ret: return ret; } +static const int ad2s1210_velocity_scale[] = { + 17089132, /* 8.192MHz / (2*pi * 2500 / 2^15) */ + 42722830, /* 8.192MHz / (2*pi * 1000 / 2^15) */ + 85445659, /* 8.192MHz / (2*pi * 500 / 2^15) */ + 341782638, /* 8.192MHz / (2*pi * 125 / 2^15) */ +}; + +static int ad2s1210_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int *val, + int *val2, + long mask) +{ + struct ad2s1210_state *st = iio_priv(indio_dev); + + switch (mask) { + case IIO_CHAN_INFO_RAW: + return ad2s1210_single_conversion(st, chan, val); + case IIO_CHAN_INFO_SCALE: + switch (chan->type) { + case IIO_ANGL: + /* approx 0.3 arc min converted to radians */ + *val = 0; + *val2 = 95874; + return IIO_VAL_INT_PLUS_NANO; + case IIO_ANGL_VEL: + *val = st->fclkin; + *val2 = ad2s1210_velocity_scale[st->resolution]; + return IIO_VAL_FRACTIONAL; + default: + return -EINVAL; + } + + default: + return -EINVAL; + } +} + static IIO_DEVICE_ATTR(fclkin, 0644, ad2s1210_show_fclkin, ad2s1210_store_fclkin, 0); static IIO_DEVICE_ATTR(fexcit, 0644, @@ -552,12 +587,14 @@ static const struct iio_chan_spec ad2s1210_channels[] = { .type = IIO_ANGL, .indexed = 1, .channel = 0, - .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | + BIT(IIO_CHAN_INFO_SCALE), }, { .type = IIO_ANGL_VEL, .indexed = 1, .channel = 0, - .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | + BIT(IIO_CHAN_INFO_SCALE), } }; From 68d319571b8fee7b4135b118ad4733b4469ccaf0 Mon Sep 17 00:00:00 2001 From: David Lechner Date: Fri, 29 Sep 2023 12:23:14 -0500 Subject: [PATCH 144/326] staging: iio: resolver: ad2s1210: use devicetree to get CLKIN rate This removes the fclkin sysfs attribute and replaces it with getting the CLKIN clock rate using the clk subsystem (i.e. from the devicetree). CLKIN comes from an external oscillator that is connected directly to the AD2S1210 chip, so users of the sysfs attributes should not need to be concerned with this. The fclkin field (the datasheet name) is renamed to clkin_hz to be more obvious that it is a frequency in Hz. Signed-off-by: David Lechner Link: https://lore.kernel.org/r/20230929-ad2s1210-mainline-v3-9-fa4364281745@baylibre.com Signed-off-by: Jonathan Cameron --- drivers/staging/iio/resolver/Kconfig | 1 + drivers/staging/iio/resolver/ad2s1210.c | 81 +++++++++---------------- 2 files changed, 30 insertions(+), 52 deletions(-) diff --git a/drivers/staging/iio/resolver/Kconfig b/drivers/staging/iio/resolver/Kconfig index 6d1e2622e0b0..bebb35822c9e 100644 --- a/drivers/staging/iio/resolver/Kconfig +++ b/drivers/staging/iio/resolver/Kconfig @@ -7,6 +7,7 @@ menu "Resolver to digital converters" config AD2S1210 tristate "Analog Devices ad2s1210 driver" depends on SPI + depends on COMMON_CLK depends on GPIOLIB || COMPILE_TEST help Say yes here to build support for Analog Devices spi resolver diff --git a/drivers/staging/iio/resolver/ad2s1210.c b/drivers/staging/iio/resolver/ad2s1210.c index a710598a64f0..c8723b6f3a3b 100644 --- a/drivers/staging/iio/resolver/ad2s1210.c +++ b/drivers/staging/iio/resolver/ad2s1210.c @@ -3,7 +3,9 @@ * ad2s1210.c support for the ADI Resolver to Digital Converters: AD2S1210 * * Copyright (c) 2010-2010 Analog Devices Inc. + * Copyright (c) 2023 BayLibre, SAS */ +#include #include #include #include @@ -90,7 +92,8 @@ struct ad2s1210_state { struct mutex lock; struct spi_device *sdev; struct gpio_desc *gpios[5]; - unsigned int fclkin; + /** The external oscillator frequency in Hz. */ + unsigned long clkin_hz; unsigned int fexcit; bool hysteresis; u8 resolution; @@ -165,7 +168,7 @@ int ad2s1210_update_frequency_control_word(struct ad2s1210_state *st) int ret; unsigned char fcw; - fcw = (unsigned char)(st->fexcit * (1 << 15) / st->fclkin); + fcw = (unsigned char)(st->fexcit * (1 << 15) / st->clkin_hz); if (fcw < AD2S1210_MIN_FCW || fcw > AD2S1210_MAX_FCW) { dev_err(&st->sdev->dev, "ad2s1210: FCW out of range\n"); return -ERANGE; @@ -201,45 +204,6 @@ static inline int ad2s1210_soft_reset(struct ad2s1210_state *st) return ad2s1210_config_write(st, 0x0); } -static ssize_t ad2s1210_show_fclkin(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - struct ad2s1210_state *st = iio_priv(dev_to_iio_dev(dev)); - - return sprintf(buf, "%u\n", st->fclkin); -} - -static ssize_t ad2s1210_store_fclkin(struct device *dev, - struct device_attribute *attr, - const char *buf, - size_t len) -{ - struct ad2s1210_state *st = iio_priv(dev_to_iio_dev(dev)); - unsigned int fclkin; - int ret; - - ret = kstrtouint(buf, 10, &fclkin); - if (ret) - return ret; - if (fclkin < AD2S1210_MIN_CLKIN || fclkin > AD2S1210_MAX_CLKIN) { - dev_err(dev, "ad2s1210: fclkin out of range\n"); - return -EINVAL; - } - - mutex_lock(&st->lock); - st->fclkin = fclkin; - - ret = ad2s1210_update_frequency_control_word(st); - if (ret < 0) - goto error_ret; - ret = ad2s1210_soft_reset(st); -error_ret: - mutex_unlock(&st->lock); - - return ret < 0 ? ret : len; -} - static ssize_t ad2s1210_show_fexcit(struct device *dev, struct device_attribute *attr, char *buf) @@ -537,7 +501,7 @@ static int ad2s1210_read_raw(struct iio_dev *indio_dev, *val2 = 95874; return IIO_VAL_INT_PLUS_NANO; case IIO_ANGL_VEL: - *val = st->fclkin; + *val = st->clkin_hz; *val2 = ad2s1210_velocity_scale[st->resolution]; return IIO_VAL_FRACTIONAL; default: @@ -549,8 +513,6 @@ static int ad2s1210_read_raw(struct iio_dev *indio_dev, } } -static IIO_DEVICE_ATTR(fclkin, 0644, - ad2s1210_show_fclkin, ad2s1210_store_fclkin, 0); static IIO_DEVICE_ATTR(fexcit, 0644, ad2s1210_show_fexcit, ad2s1210_store_fexcit, 0); static IIO_DEVICE_ATTR(control, 0644, @@ -599,7 +561,6 @@ static const struct iio_chan_spec ad2s1210_channels[] = { }; static struct attribute *ad2s1210_attributes[] = { - &iio_dev_attr_fclkin.dev_attr.attr, &iio_dev_attr_fexcit.dev_attr.attr, &iio_dev_attr_control.dev_attr.attr, &iio_dev_attr_bits.dev_attr.attr, @@ -657,6 +618,24 @@ static const struct iio_info ad2s1210_info = { .attrs = &ad2s1210_attribute_group, }; +static int ad2s1210_setup_clocks(struct ad2s1210_state *st) +{ + struct device *dev = &st->sdev->dev; + struct clk *clk; + + clk = devm_clk_get_enabled(dev, NULL); + if (IS_ERR(clk)) + return dev_err_probe(dev, PTR_ERR(clk), "failed to get clock\n"); + + st->clkin_hz = clk_get_rate(clk); + if (st->clkin_hz < AD2S1210_MIN_CLKIN || st->clkin_hz > AD2S1210_MAX_CLKIN) + return dev_err_probe(dev, -EINVAL, + "clock frequency out of range: %lu\n", + st->clkin_hz); + + return 0; +} + static int ad2s1210_setup_gpios(struct ad2s1210_state *st) { struct spi_device *spi = st->sdev; @@ -695,6 +674,10 @@ static int ad2s1210_probe(struct spi_device *spi) st->resolution = 12; st->fexcit = AD2S1210_DEF_EXCIT; + ret = ad2s1210_setup_clocks(st); + if (ret < 0) + return ret; + ret = ad2s1210_setup_gpios(st); if (ret < 0) return ret; @@ -709,13 +692,7 @@ static int ad2s1210_probe(struct spi_device *spi) indio_dev->num_channels = ARRAY_SIZE(ad2s1210_channels); indio_dev->name = spi_get_device_id(spi)->name; - ret = devm_iio_device_register(&spi->dev, indio_dev); - if (ret) - return ret; - - st->fclkin = spi->max_speed_hz; - - return 0; + return devm_iio_device_register(&spi->dev, indio_dev); } static const struct of_device_id ad2s1210_of_match[] = { From b3689e14415a874630f0894d8c3ac7ea01603d57 Mon Sep 17 00:00:00 2001 From: David Lechner Date: Fri, 29 Sep 2023 12:23:15 -0500 Subject: [PATCH 145/326] staging: iio: resolver: ad2s1210: use regmap for config registers This makes use of the regmap API to read and write the configuration registers. This simplifies code quite a bit and makes it safer (previously, it was easy to write a bad value to the config registers which causes the chip to lock up and need to be reset). This chip has multiple modes of operation. In normal mode, we do not use regmap since there is no addressing - data is just bitshifted out during the SPI read. In config mode, we use regmap since it requires writing the address (with read/write flag) before reading and writing. We don't use the lock provided by the regmap because we need to also synchronize with the normal mode SPI reads and with the various GPIOs. There is also a quirk when reading registers (other than the fault register). If the address/data bit is set in the value read, then it indicates there is a configuration parity error and the data is not valid. Previously, this was checked in a few places, but not consistently. Now, we always check it in the regmap read function. Signed-off-by: David Lechner Link: https://lore.kernel.org/r/20230929-ad2s1210-mainline-v3-10-fa4364281745@baylibre.com Signed-off-by: Jonathan Cameron --- drivers/staging/iio/resolver/ad2s1210.c | 269 ++++++++++++++---------- 1 file changed, 160 insertions(+), 109 deletions(-) diff --git a/drivers/staging/iio/resolver/ad2s1210.c b/drivers/staging/iio/resolver/ad2s1210.c index c8723b6f3a3b..0663a51d04ad 100644 --- a/drivers/staging/iio/resolver/ad2s1210.c +++ b/drivers/staging/iio/resolver/ad2s1210.c @@ -5,6 +5,8 @@ * Copyright (c) 2010-2010 Analog Devices Inc. * Copyright (c) 2023 BayLibre, SAS */ +#include +#include #include #include #include @@ -12,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -22,21 +25,17 @@ #define DRV_NAME "ad2s1210" -#define AD2S1210_DEF_CONTROL 0x7E +/* control register flags */ +#define AD2S1210_ADDRESS_DATA BIT(7) +#define AD2S1210_PHASE_LOCK_RANGE_44 BIT(5) +#define AD2S1210_ENABLE_HYSTERESIS BIT(4) +#define AD2S1210_SET_ENRES GENMASK(3, 2) +#define AD2S1210_SET_RES GENMASK(1, 0) -#define AD2S1210_MSB_IS_HIGH 0x80 -#define AD2S1210_MSB_IS_LOW 0x7F -#define AD2S1210_PHASE_LOCK_RANGE_44 0x20 -#define AD2S1210_ENABLE_HYSTERESIS 0x10 -#define AD2S1210_SET_ENRES1 0x08 -#define AD2S1210_SET_ENRES0 0x04 -#define AD2S1210_SET_RES1 0x02 -#define AD2S1210_SET_RES0 0x01 - -#define AD2S1210_SET_RESOLUTION (AD2S1210_SET_RES1 | AD2S1210_SET_RES0) - -#define AD2S1210_REG_POSITION 0x80 -#define AD2S1210_REG_VELOCITY 0x82 +#define AD2S1210_REG_POSITION_MSB 0x80 +#define AD2S1210_REG_POSITION_LSB 0x81 +#define AD2S1210_REG_VELOCITY_MSB 0x82 +#define AD2S1210_REG_VELOCITY_LSB 0x83 #define AD2S1210_REG_LOS_THRD 0x88 #define AD2S1210_REG_DOS_OVR_THRD 0x89 #define AD2S1210_REG_DOS_MIS_THRD 0x8A @@ -92,6 +91,8 @@ struct ad2s1210_state { struct mutex lock; struct spi_device *sdev; struct gpio_desc *gpios[5]; + /** Used to access config registers. */ + struct regmap *regmap; /** The external oscillator frequency in Hz. */ unsigned long clkin_hz; unsigned int fexcit; @@ -120,24 +121,16 @@ static inline void ad2s1210_set_mode(enum ad2s1210_mode mode, st->mode = mode; } -/* write 1 bytes (address or data) to the chip */ -static int ad2s1210_config_write(struct ad2s1210_state *st, u8 data) -{ - int ret; - - ad2s1210_set_mode(MOD_CONFIG, st); - st->tx[0] = data; - ret = spi_write(st->sdev, st->tx, 1); - if (ret < 0) - return ret; - - return 0; -} - -/* read value from one of the registers */ -static int ad2s1210_config_read(struct ad2s1210_state *st, - unsigned char address) +/* + * Writes the given data to the given register address. + * + * If the mode is configurable, the device will first be placed in + * configuration mode. + */ +static int ad2s1210_regmap_reg_write(void *context, unsigned int reg, + unsigned int val) { + struct ad2s1210_state *st = context; struct spi_transfer xfers[] = { { .len = 1, @@ -150,22 +143,71 @@ static int ad2s1210_config_read(struct ad2s1210_state *st, .tx_buf = &st->tx[1], }, }; - int ret = 0; + + /* values can only be 7 bits, the MSB indicates an address */ + if (val & ~0x7F) + return -EINVAL; + + st->tx[0] = reg; + st->tx[1] = val; ad2s1210_set_mode(MOD_CONFIG, st); - st->tx[0] = address | AD2S1210_MSB_IS_HIGH; + + return spi_sync_transfer(st->sdev, xfers, ARRAY_SIZE(xfers)); +} + +/* + * Reads value from one of the registers. + * + * If the mode is configurable, the device will first be placed in + * configuration mode. + */ +static int ad2s1210_regmap_reg_read(void *context, unsigned int reg, + unsigned int *val) +{ + struct ad2s1210_state *st = context; + struct spi_transfer xfers[] = { + { + .len = 1, + .rx_buf = &st->rx[0], + .tx_buf = &st->tx[0], + .cs_change = 1, + }, { + .len = 1, + .rx_buf = &st->rx[1], + .tx_buf = &st->tx[1], + }, + }; + int ret; + + ad2s1210_set_mode(MOD_CONFIG, st); + st->tx[0] = reg; + /* + * Must be valid register address here otherwise this could write data. + * It doesn't matter which one. + */ st->tx[1] = AD2S1210_REG_FAULT; - ret = spi_sync_transfer(st->sdev, xfers, 2); + + ret = spi_sync_transfer(st->sdev, xfers, ARRAY_SIZE(xfers)); if (ret < 0) return ret; - return st->rx[1]; + /* + * If the D7 bit is set on any read/write register, it indicates a + * parity error. The fault register is read-only and the D7 bit means + * something else there. + */ + if (reg != AD2S1210_REG_FAULT && st->rx[1] & AD2S1210_ADDRESS_DATA) + return -EBADMSG; + + *val = st->rx[1]; + + return 0; } static inline int ad2s1210_update_frequency_control_word(struct ad2s1210_state *st) { - int ret; unsigned char fcw; fcw = (unsigned char)(st->fexcit * (1 << 15) / st->clkin_hz); @@ -174,11 +216,7 @@ int ad2s1210_update_frequency_control_word(struct ad2s1210_state *st) return -ERANGE; } - ret = ad2s1210_config_write(st, AD2S1210_REG_EXCIT_FREQ); - if (ret < 0) - return ret; - - return ad2s1210_config_write(st, fcw); + return regmap_write(st->regmap, AD2S1210_REG_EXCIT_FREQ, fcw); } static const int ad2s1210_res_pins[4][2] = { @@ -195,13 +233,7 @@ static inline void ad2s1210_set_resolution_pin(struct ad2s1210_state *st) static inline int ad2s1210_soft_reset(struct ad2s1210_state *st) { - int ret; - - ret = ad2s1210_config_write(st, AD2S1210_REG_SOFT_RESET); - if (ret < 0) - return ret; - - return ad2s1210_config_write(st, 0x0); + return regmap_write(st->regmap, AD2S1210_REG_SOFT_RESET, 0); } static ssize_t ad2s1210_show_fexcit(struct device *dev, @@ -246,12 +278,13 @@ static ssize_t ad2s1210_show_control(struct device *dev, char *buf) { struct ad2s1210_state *st = iio_priv(dev_to_iio_dev(dev)); + unsigned int value; int ret; mutex_lock(&st->lock); - ret = ad2s1210_config_read(st, AD2S1210_REG_CONTROL); + ret = regmap_read(st->regmap, AD2S1210_REG_CONTROL, &value); mutex_unlock(&st->lock); - return ret < 0 ? ret : sprintf(buf, "0x%x\n", ret); + return ret < 0 ? ret : sprintf(buf, "0x%x\n", value); } static ssize_t ad2s1210_store_control(struct device *dev, @@ -268,25 +301,13 @@ static ssize_t ad2s1210_store_control(struct device *dev, return -EINVAL; mutex_lock(&st->lock); - ret = ad2s1210_config_write(st, AD2S1210_REG_CONTROL); - if (ret < 0) - goto error_ret; - data = udata & AD2S1210_MSB_IS_LOW; - ret = ad2s1210_config_write(st, data); + data = udata & ~AD2S1210_ADDRESS_DATA; + ret = regmap_write(st->regmap, AD2S1210_REG_CONTROL, data); if (ret < 0) goto error_ret; - ret = ad2s1210_config_read(st, AD2S1210_REG_CONTROL); - if (ret < 0) - goto error_ret; - if (ret & AD2S1210_MSB_IS_HIGH) { - ret = -EIO; - dev_err(dev, - "ad2s1210: write control register fail\n"); - goto error_ret; - } st->resolution = - ad2s1210_resolution_value[data & AD2S1210_SET_RESOLUTION]; + ad2s1210_resolution_value[data & AD2S1210_SET_RES]; ad2s1210_set_resolution_pin(st); ret = len; st->hysteresis = !!(data & AD2S1210_ENABLE_HYSTERESIS); @@ -319,30 +340,17 @@ static ssize_t ad2s1210_store_resolution(struct device *dev, dev_err(dev, "ad2s1210: resolution out of range\n"); return -EINVAL; } + + data = (udata - 10) >> 1; + mutex_lock(&st->lock); - ret = ad2s1210_config_read(st, AD2S1210_REG_CONTROL); + ret = regmap_update_bits(st->regmap, AD2S1210_REG_CONTROL, + AD2S1210_SET_RES, data); if (ret < 0) goto error_ret; - data = ret; - data &= ~AD2S1210_SET_RESOLUTION; - data |= (udata - 10) >> 1; - ret = ad2s1210_config_write(st, AD2S1210_REG_CONTROL); - if (ret < 0) - goto error_ret; - ret = ad2s1210_config_write(st, data & AD2S1210_MSB_IS_LOW); - if (ret < 0) - goto error_ret; - ret = ad2s1210_config_read(st, AD2S1210_REG_CONTROL); - if (ret < 0) - goto error_ret; - data = ret; - if (data & AD2S1210_MSB_IS_HIGH) { - ret = -EIO; - dev_err(dev, "ad2s1210: setting resolution fail\n"); - goto error_ret; - } + st->resolution = - ad2s1210_resolution_value[data & AD2S1210_SET_RESOLUTION]; + ad2s1210_resolution_value[data & AD2S1210_SET_RES]; ad2s1210_set_resolution_pin(st); ret = len; error_ret: @@ -355,13 +363,14 @@ static ssize_t ad2s1210_show_fault(struct device *dev, struct device_attribute *attr, char *buf) { struct ad2s1210_state *st = iio_priv(dev_to_iio_dev(dev)); + unsigned int value; int ret; mutex_lock(&st->lock); - ret = ad2s1210_config_read(st, AD2S1210_REG_FAULT); + ret = regmap_read(st->regmap, AD2S1210_REG_FAULT, &value); mutex_unlock(&st->lock); - return ret < 0 ? ret : sprintf(buf, "0x%02x\n", ret); + return ret < 0 ? ret : sprintf(buf, "0x%02x\n", value); } static ssize_t ad2s1210_clear_fault(struct device *dev, @@ -370,6 +379,7 @@ static ssize_t ad2s1210_clear_fault(struct device *dev, size_t len) { struct ad2s1210_state *st = iio_priv(dev_to_iio_dev(dev)); + unsigned int value; int ret; mutex_lock(&st->lock); @@ -377,7 +387,7 @@ static ssize_t ad2s1210_clear_fault(struct device *dev, /* delay (2 * tck + 20) nano seconds */ udelay(1); gpiod_set_value(st->gpios[AD2S1210_SAMPLE], 1); - ret = ad2s1210_config_read(st, AD2S1210_REG_FAULT); + ret = regmap_read(st->regmap, AD2S1210_REG_FAULT, &value); if (ret < 0) goto error_ret; gpiod_set_value(st->gpios[AD2S1210_SAMPLE], 0); @@ -394,13 +404,14 @@ static ssize_t ad2s1210_show_reg(struct device *dev, { struct ad2s1210_state *st = iio_priv(dev_to_iio_dev(dev)); struct iio_dev_attr *iattr = to_iio_dev_attr(attr); + unsigned int value; int ret; mutex_lock(&st->lock); - ret = ad2s1210_config_read(st, iattr->address); + ret = regmap_read(st->regmap, iattr->address, &value); mutex_unlock(&st->lock); - return ret < 0 ? ret : sprintf(buf, "%d\n", ret); + return ret < 0 ? ret : sprintf(buf, "%d\n", value); } static ssize_t ad2s1210_store_reg(struct device *dev, @@ -415,12 +426,9 @@ static ssize_t ad2s1210_store_reg(struct device *dev, ret = kstrtou8(buf, 10, &data); if (ret) return -EINVAL; + mutex_lock(&st->lock); - ret = ad2s1210_config_write(st, iattr->address); - if (ret < 0) - goto error_ret; - ret = ad2s1210_config_write(st, data & AD2S1210_MSB_IS_LOW); -error_ret: + ret = regmap_write(st->regmap, iattr->address, data); mutex_unlock(&st->lock); return ret < 0 ? ret : len; } @@ -587,22 +595,15 @@ static int ad2s1210_initial(struct ad2s1210_state *st) mutex_lock(&st->lock); ad2s1210_set_resolution_pin(st); - ret = ad2s1210_config_write(st, AD2S1210_REG_CONTROL); - if (ret < 0) - goto error_ret; - data = AD2S1210_DEF_CONTROL & ~(AD2S1210_SET_RESOLUTION); - data |= (st->resolution - 10) >> 1; - ret = ad2s1210_config_write(st, data); - if (ret < 0) - goto error_ret; - ret = ad2s1210_config_read(st, AD2S1210_REG_CONTROL); - if (ret < 0) - goto error_ret; + /* Use default config register value plus resolution from devicetree. */ + data = FIELD_PREP(AD2S1210_PHASE_LOCK_RANGE_44, 1); + data |= FIELD_PREP(AD2S1210_ENABLE_HYSTERESIS, 1); + data |= FIELD_PREP(AD2S1210_SET_ENRES, 0x3); + data |= FIELD_PREP(AD2S1210_SET_RES, (st->resolution - 10) >> 1); - if (ret & AD2S1210_MSB_IS_HIGH) { - ret = -EIO; + ret = regmap_write(st->regmap, AD2S1210_REG_CONTROL, data); + if (ret < 0) goto error_ret; - } ret = ad2s1210_update_frequency_control_word(st); if (ret < 0) @@ -656,6 +657,52 @@ static int ad2s1210_setup_gpios(struct ad2s1210_state *st) return 0; } +static const struct regmap_range ad2s1210_regmap_readable_ranges[] = { + regmap_reg_range(AD2S1210_REG_POSITION_MSB, AD2S1210_REG_VELOCITY_LSB), + regmap_reg_range(AD2S1210_REG_LOS_THRD, AD2S1210_REG_LOT_LOW_THRD), + regmap_reg_range(AD2S1210_REG_EXCIT_FREQ, AD2S1210_REG_CONTROL), + regmap_reg_range(AD2S1210_REG_FAULT, AD2S1210_REG_FAULT), +}; + +static const struct regmap_access_table ad2s1210_regmap_rd_table = { + .yes_ranges = ad2s1210_regmap_readable_ranges, + .n_yes_ranges = ARRAY_SIZE(ad2s1210_regmap_readable_ranges), +}; + +static const struct regmap_range ad2s1210_regmap_writeable_ranges[] = { + regmap_reg_range(AD2S1210_REG_LOS_THRD, AD2S1210_REG_LOT_LOW_THRD), + regmap_reg_range(AD2S1210_REG_EXCIT_FREQ, AD2S1210_REG_CONTROL), + regmap_reg_range(AD2S1210_REG_SOFT_RESET, AD2S1210_REG_SOFT_RESET), + regmap_reg_range(AD2S1210_REG_FAULT, AD2S1210_REG_FAULT), +}; + +static const struct regmap_access_table ad2s1210_regmap_wr_table = { + .yes_ranges = ad2s1210_regmap_writeable_ranges, + .n_yes_ranges = ARRAY_SIZE(ad2s1210_regmap_writeable_ranges), +}; + +static int ad2s1210_setup_regmap(struct ad2s1210_state *st) +{ + struct device *dev = &st->sdev->dev; + const struct regmap_config config = { + .reg_bits = 8, + .val_bits = 8, + .disable_locking = true, + .reg_read = ad2s1210_regmap_reg_read, + .reg_write = ad2s1210_regmap_reg_write, + .rd_table = &ad2s1210_regmap_rd_table, + .wr_table = &ad2s1210_regmap_wr_table, + .can_sleep = true, + }; + + st->regmap = devm_regmap_init(dev, NULL, st, &config); + if (IS_ERR(st->regmap)) + return dev_err_probe(dev, PTR_ERR(st->regmap), + "failed to allocate register map\n"); + + return 0; +} + static int ad2s1210_probe(struct spi_device *spi) { struct iio_dev *indio_dev; @@ -682,6 +729,10 @@ static int ad2s1210_probe(struct spi_device *spi) if (ret < 0) return ret; + ret = ad2s1210_setup_regmap(st); + if (ret < 0) + return ret; + ret = ad2s1210_initial(st); if (ret < 0) return ret; From 569dc8054e702f504bd8d07e2c4e315b2097d746 Mon Sep 17 00:00:00 2001 From: David Lechner Date: Fri, 29 Sep 2023 12:23:16 -0500 Subject: [PATCH 146/326] staging: iio: resolver: ad2s1210: add debugfs reg access This add an implementation of debugfs_reg_access for the AD2S1210 driver. Signed-off-by: David Lechner Link: https://lore.kernel.org/r/20230929-ad2s1210-mainline-v3-11-fa4364281745@baylibre.com Signed-off-by: Jonathan Cameron --- drivers/staging/iio/resolver/ad2s1210.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/drivers/staging/iio/resolver/ad2s1210.c b/drivers/staging/iio/resolver/ad2s1210.c index 0663a51d04ad..31415fbb6384 100644 --- a/drivers/staging/iio/resolver/ad2s1210.c +++ b/drivers/staging/iio/resolver/ad2s1210.c @@ -614,9 +614,29 @@ error_ret: return ret; } +static int ad2s1210_debugfs_reg_access(struct iio_dev *indio_dev, + unsigned int reg, unsigned int writeval, + unsigned int *readval) +{ + struct ad2s1210_state *st = iio_priv(indio_dev); + int ret; + + mutex_lock(&st->lock); + + if (readval) + ret = regmap_read(st->regmap, reg, readval); + else + ret = regmap_write(st->regmap, reg, writeval); + + mutex_unlock(&st->lock); + + return ret; +} + static const struct iio_info ad2s1210_info = { .read_raw = ad2s1210_read_raw, .attrs = &ad2s1210_attribute_group, + .debugfs_reg_access = &ad2s1210_debugfs_reg_access, }; static int ad2s1210_setup_clocks(struct ad2s1210_state *st) From 8ab5bf1a2264e380635913bc9ac72d1ab55088c0 Mon Sep 17 00:00:00 2001 From: David Lechner Date: Fri, 29 Sep 2023 12:23:17 -0500 Subject: [PATCH 147/326] staging: iio: resolver: ad2s1210: remove config attribute This removes the config register sysfs attribute. Writing to the config register directly can be dangerous and userspace should not need to have to know the register layout. This register can still be accessed though debugfs if needed. We can add new attributes to set specific flags in the config register in the future if needed (e.g. `enable_hysterisis` and `phase_lock_range`). Signed-off-by: David Lechner Link: https://lore.kernel.org/r/20230929-ad2s1210-mainline-v3-12-fa4364281745@baylibre.com Signed-off-by: Jonathan Cameron --- drivers/staging/iio/resolver/ad2s1210.c | 47 ------------------------- 1 file changed, 47 deletions(-) diff --git a/drivers/staging/iio/resolver/ad2s1210.c b/drivers/staging/iio/resolver/ad2s1210.c index 31415fbb6384..2b9377447f6a 100644 --- a/drivers/staging/iio/resolver/ad2s1210.c +++ b/drivers/staging/iio/resolver/ad2s1210.c @@ -273,50 +273,6 @@ error_ret: return ret < 0 ? ret : len; } -static ssize_t ad2s1210_show_control(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - struct ad2s1210_state *st = iio_priv(dev_to_iio_dev(dev)); - unsigned int value; - int ret; - - mutex_lock(&st->lock); - ret = regmap_read(st->regmap, AD2S1210_REG_CONTROL, &value); - mutex_unlock(&st->lock); - return ret < 0 ? ret : sprintf(buf, "0x%x\n", value); -} - -static ssize_t ad2s1210_store_control(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t len) -{ - struct ad2s1210_state *st = iio_priv(dev_to_iio_dev(dev)); - unsigned char udata; - unsigned char data; - int ret; - - ret = kstrtou8(buf, 16, &udata); - if (ret) - return -EINVAL; - - mutex_lock(&st->lock); - data = udata & ~AD2S1210_ADDRESS_DATA; - ret = regmap_write(st->regmap, AD2S1210_REG_CONTROL, data); - if (ret < 0) - goto error_ret; - - st->resolution = - ad2s1210_resolution_value[data & AD2S1210_SET_RES]; - ad2s1210_set_resolution_pin(st); - ret = len; - st->hysteresis = !!(data & AD2S1210_ENABLE_HYSTERESIS); - -error_ret: - mutex_unlock(&st->lock); - return ret; -} - static ssize_t ad2s1210_show_resolution(struct device *dev, struct device_attribute *attr, char *buf) @@ -523,8 +479,6 @@ static int ad2s1210_read_raw(struct iio_dev *indio_dev, static IIO_DEVICE_ATTR(fexcit, 0644, ad2s1210_show_fexcit, ad2s1210_store_fexcit, 0); -static IIO_DEVICE_ATTR(control, 0644, - ad2s1210_show_control, ad2s1210_store_control, 0); static IIO_DEVICE_ATTR(bits, 0644, ad2s1210_show_resolution, ad2s1210_store_resolution, 0); static IIO_DEVICE_ATTR(fault, 0644, @@ -570,7 +524,6 @@ static const struct iio_chan_spec ad2s1210_channels[] = { static struct attribute *ad2s1210_attributes[] = { &iio_dev_attr_fexcit.dev_attr.attr, - &iio_dev_attr_control.dev_attr.attr, &iio_dev_attr_bits.dev_attr.attr, &iio_dev_attr_fault.dev_attr.attr, &iio_dev_attr_los_thrd.dev_attr.attr, From 78510a4db873bea115ccfb88a9493c1465105733 Mon Sep 17 00:00:00 2001 From: Jorge Sanjuan Garcia Date: Wed, 6 Sep 2023 11:49:28 +0000 Subject: [PATCH 148/326] mcb: use short version for function pointer for mcb_free_bus Just a style change so that the device release callbacks are defined in the same way for devices in mcb_bus and mcb_device. Signed-off-by: Jorge Sanjuan Garcia Co-developed-by: Jose Javier Rodriguez Barbarin Signed-off-by: Jose Javier Rodriguez Barbarin Link: https://lore.kernel.org/r/20230906114901.63174-3-JoseJavier.Rodriguez@duagon.com Signed-off-by: Greg Kroah-Hartman --- drivers/mcb/mcb-core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/mcb/mcb-core.c b/drivers/mcb/mcb-core.c index 978fdfc19a06..f6374c697956 100644 --- a/drivers/mcb/mcb-core.c +++ b/drivers/mcb/mcb-core.c @@ -288,7 +288,7 @@ struct mcb_bus *mcb_alloc_bus(struct device *carrier) bus->dev.parent = carrier; bus->dev.bus = &mcb_bus_type; bus->dev.type = &mcb_carrier_device_type; - bus->dev.release = &mcb_free_bus; + bus->dev.release = mcb_free_bus; dev_set_name(&bus->dev, "mcb:%d", bus_nr); rc = device_add(&bus->dev); From bcdf91c9f9077d24153258faa4942512a340d399 Mon Sep 17 00:00:00 2001 From: Justin Stitt Date: Wed, 27 Sep 2023 05:37:06 +0000 Subject: [PATCH 149/326] eeprom: idt_89hpesx: replace open-coded kmemdup_nul A malloc + strncpy + manual NUL_termination is just kmemdup_nul. Let's use this interface as it is less error-prone and more readable. Also drop `csraddr_len` as it is just used in a single place and we can just do the arithmetic in-line. Link: https://www.kernel.org/doc/html/latest/process/deprecated.html#strncpy-on-nul-terminated-strings [1] Link: https://github.com/KSPP/linux/issues/90 Cc: linux-hardening@vger.kernel.org Cc: Kees Cook Signed-off-by: Justin Stitt Reviewed-by: Kees Cook Link: https://lore.kernel.org/r/20230927-strncpy-drivers-misc-eeprom-idt_89hpesx-c-v1-1-08e3d45b8c05@google.com Signed-off-by: Greg Kroah-Hartman --- drivers/misc/eeprom/idt_89hpesx.c | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/drivers/misc/eeprom/idt_89hpesx.c b/drivers/misc/eeprom/idt_89hpesx.c index 1d1f30b5c426..d807d08e2614 100644 --- a/drivers/misc/eeprom/idt_89hpesx.c +++ b/drivers/misc/eeprom/idt_89hpesx.c @@ -905,7 +905,7 @@ static ssize_t idt_dbgfs_csr_write(struct file *filep, const char __user *ubuf, { struct idt_89hpesx_dev *pdev = filep->private_data; char *colon_ch, *csraddr_str, *csrval_str; - int ret, csraddr_len; + int ret; u32 csraddr, csrval; char *buf; @@ -927,21 +927,16 @@ static ssize_t idt_dbgfs_csr_write(struct file *filep, const char __user *ubuf, * no new CSR value */ if (colon_ch != NULL) { - csraddr_len = colon_ch - buf; - csraddr_str = - kmalloc(csraddr_len + 1, GFP_KERNEL); + /* Copy the register address to the substring buffer */ + csraddr_str = kmemdup_nul(buf, colon_ch - buf, GFP_KERNEL); if (csraddr_str == NULL) { ret = -ENOMEM; goto free_buf; } - /* Copy the register address to the substring buffer */ - strncpy(csraddr_str, buf, csraddr_len); - csraddr_str[csraddr_len] = '\0'; /* Register value must follow the colon */ csrval_str = colon_ch + 1; } else /* if (str_colon == NULL) */ { csraddr_str = (char *)buf; /* Just to shut warning up */ - csraddr_len = strnlen(csraddr_str, count); csrval_str = NULL; } From 0113a99b8a75f307439c2950cec5b5dab818f35c Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Sun, 24 Sep 2023 23:49:09 +0200 Subject: [PATCH 150/326] eeprom: Remove deprecated legacy eeprom driver Driver was marked deprecated 4 years ago, so it's time to remove it. This driver is the only i2c client driver using class I2C_CLASS_SPD. Apparently, as a follow-up step, we can remove I2C_CLASS_SPD altogether. Signed-off-by: Heiner Kallweit Reviewed-by: Jean Delvare Link: https://lore.kernel.org/r/18241458-52db-4537-bead-d570801253c3@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/misc/eeprom/Kconfig | 14 --- drivers/misc/eeprom/Makefile | 1 - drivers/misc/eeprom/eeprom.c | 214 ----------------------------------- 3 files changed, 229 deletions(-) delete mode 100644 drivers/misc/eeprom/eeprom.c diff --git a/drivers/misc/eeprom/Kconfig b/drivers/misc/eeprom/Kconfig index 2d240bfa819f..4e61ac18cc96 100644 --- a/drivers/misc/eeprom/Kconfig +++ b/drivers/misc/eeprom/Kconfig @@ -46,20 +46,6 @@ config EEPROM_AT25 This driver can also be built as a module. If so, the module will be called at25. -config EEPROM_LEGACY - tristate "Old I2C EEPROM reader (DEPRECATED)" - depends on I2C && SYSFS - help - If you say yes here you get read-only access to the EEPROM data - available on modern memory DIMMs and Sony Vaio laptops via I2C. Such - EEPROMs could theoretically be available on other devices as well. - - This driver is deprecated and will be removed soon, please use the - better at24 driver instead. - - This driver can also be built as a module. If so, the module - will be called eeprom. - config EEPROM_MAX6875 tristate "Maxim MAX6874/5 power supply supervisor" depends on I2C diff --git a/drivers/misc/eeprom/Makefile b/drivers/misc/eeprom/Makefile index a9b4b6579b75..65794e526d5d 100644 --- a/drivers/misc/eeprom/Makefile +++ b/drivers/misc/eeprom/Makefile @@ -1,7 +1,6 @@ # SPDX-License-Identifier: GPL-2.0 obj-$(CONFIG_EEPROM_AT24) += at24.o obj-$(CONFIG_EEPROM_AT25) += at25.o -obj-$(CONFIG_EEPROM_LEGACY) += eeprom.o obj-$(CONFIG_EEPROM_MAX6875) += max6875.o obj-$(CONFIG_EEPROM_93CX6) += eeprom_93cx6.o obj-$(CONFIG_EEPROM_93XX46) += eeprom_93xx46.o diff --git a/drivers/misc/eeprom/eeprom.c b/drivers/misc/eeprom/eeprom.c deleted file mode 100644 index ccb7c2f7ee2f..000000000000 --- a/drivers/misc/eeprom/eeprom.c +++ /dev/null @@ -1,214 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * Copyright (C) 1998, 1999 Frodo Looijaard and - * Philip Edelbrock - * Copyright (C) 2003 Greg Kroah-Hartman - * Copyright (C) 2003 IBM Corp. - * Copyright (C) 2004 Jean Delvare - */ - -#include -#include -#include -#include -#include -#include -#include - -/* Addresses to scan */ -static const unsigned short normal_i2c[] = { 0x50, 0x51, 0x52, 0x53, 0x54, - 0x55, 0x56, 0x57, I2C_CLIENT_END }; - - -/* Size of EEPROM in bytes */ -#define EEPROM_SIZE 256 - -/* possible types of eeprom devices */ -enum eeprom_nature { - UNKNOWN, - VAIO, -}; - -/* Each client has this additional data */ -struct eeprom_data { - struct mutex update_lock; - u8 valid; /* bitfield, bit!=0 if slice is valid */ - unsigned long last_updated[8]; /* In jiffies, 8 slices */ - u8 data[EEPROM_SIZE]; /* Register values */ - enum eeprom_nature nature; -}; - - -static void eeprom_update_client(struct i2c_client *client, u8 slice) -{ - struct eeprom_data *data = i2c_get_clientdata(client); - int i; - - mutex_lock(&data->update_lock); - - if (!(data->valid & (1 << slice)) || - time_after(jiffies, data->last_updated[slice] + 300 * HZ)) { - dev_dbg(&client->dev, "Starting eeprom update, slice %u\n", slice); - - if (i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_READ_I2C_BLOCK)) { - for (i = slice << 5; i < (slice + 1) << 5; i += 32) - if (i2c_smbus_read_i2c_block_data(client, i, - 32, data->data + i) - != 32) - goto exit; - } else { - for (i = slice << 5; i < (slice + 1) << 5; i += 2) { - int word = i2c_smbus_read_word_data(client, i); - if (word < 0) - goto exit; - data->data[i] = word & 0xff; - data->data[i + 1] = word >> 8; - } - } - data->last_updated[slice] = jiffies; - data->valid |= (1 << slice); - } -exit: - mutex_unlock(&data->update_lock); -} - -static ssize_t eeprom_read(struct file *filp, struct kobject *kobj, - struct bin_attribute *bin_attr, - char *buf, loff_t off, size_t count) -{ - struct i2c_client *client = kobj_to_i2c_client(kobj); - struct eeprom_data *data = i2c_get_clientdata(client); - u8 slice; - - /* Only refresh slices which contain requested bytes */ - for (slice = off >> 5; slice <= (off + count - 1) >> 5; slice++) - eeprom_update_client(client, slice); - - /* Hide Vaio private settings to regular users: - - BIOS passwords: bytes 0x00 to 0x0f - - UUID: bytes 0x10 to 0x1f - - Serial number: 0xc0 to 0xdf */ - if (data->nature == VAIO && !capable(CAP_SYS_ADMIN)) { - int i; - - for (i = 0; i < count; i++) { - if ((off + i <= 0x1f) || - (off + i >= 0xc0 && off + i <= 0xdf)) - buf[i] = 0; - else - buf[i] = data->data[off + i]; - } - } else { - memcpy(buf, &data->data[off], count); - } - - return count; -} - -static const struct bin_attribute eeprom_attr = { - .attr = { - .name = "eeprom", - .mode = S_IRUGO, - }, - .size = EEPROM_SIZE, - .read = eeprom_read, -}; - -/* Return 0 if detection is successful, -ENODEV otherwise */ -static int eeprom_detect(struct i2c_client *client, struct i2c_board_info *info) -{ - struct i2c_adapter *adapter = client->adapter; - - /* EDID EEPROMs are often 24C00 EEPROMs, which answer to all - addresses 0x50-0x57, but we only care about 0x50. So decline - attaching to addresses >= 0x51 on DDC buses */ - if (!(adapter->class & I2C_CLASS_SPD) && client->addr >= 0x51) - return -ENODEV; - - /* There are four ways we can read the EEPROM data: - (1) I2C block reads (faster, but unsupported by most adapters) - (2) Word reads (128% overhead) - (3) Consecutive byte reads (88% overhead, unsafe) - (4) Regular byte data reads (265% overhead) - The third and fourth methods are not implemented by this driver - because all known adapters support one of the first two. */ - if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_READ_WORD_DATA) - && !i2c_check_functionality(adapter, I2C_FUNC_SMBUS_READ_I2C_BLOCK)) - return -ENODEV; - - strscpy(info->type, "eeprom", I2C_NAME_SIZE); - - return 0; -} - -static int eeprom_probe(struct i2c_client *client) -{ - struct i2c_adapter *adapter = client->adapter; - struct eeprom_data *data; - - data = devm_kzalloc(&client->dev, sizeof(struct eeprom_data), - GFP_KERNEL); - if (!data) - return -ENOMEM; - - memset(data->data, 0xff, EEPROM_SIZE); - i2c_set_clientdata(client, data); - mutex_init(&data->update_lock); - data->nature = UNKNOWN; - - /* Detect the Vaio nature of EEPROMs. - We use the "PCG-" or "VGN-" prefix as the signature. */ - if (client->addr == 0x57 - && i2c_check_functionality(adapter, I2C_FUNC_SMBUS_READ_BYTE_DATA)) { - char name[4]; - - name[0] = i2c_smbus_read_byte_data(client, 0x80); - name[1] = i2c_smbus_read_byte_data(client, 0x81); - name[2] = i2c_smbus_read_byte_data(client, 0x82); - name[3] = i2c_smbus_read_byte_data(client, 0x83); - - if (!memcmp(name, "PCG-", 4) || !memcmp(name, "VGN-", 4)) { - dev_info(&client->dev, "Vaio EEPROM detected, " - "enabling privacy protection\n"); - data->nature = VAIO; - } - } - - /* Let the users know they are using deprecated driver */ - dev_notice(&client->dev, - "eeprom driver is deprecated, please use at24 instead\n"); - - /* create the sysfs eeprom file */ - return sysfs_create_bin_file(&client->dev.kobj, &eeprom_attr); -} - -static void eeprom_remove(struct i2c_client *client) -{ - sysfs_remove_bin_file(&client->dev.kobj, &eeprom_attr); -} - -static const struct i2c_device_id eeprom_id[] = { - { "eeprom", 0 }, - { } -}; - -static struct i2c_driver eeprom_driver = { - .driver = { - .name = "eeprom", - }, - .probe = eeprom_probe, - .remove = eeprom_remove, - .id_table = eeprom_id, - - .class = I2C_CLASS_DDC | I2C_CLASS_SPD, - .detect = eeprom_detect, - .address_list = normal_i2c, -}; - -module_i2c_driver(eeprom_driver); - -MODULE_AUTHOR("Frodo Looijaard and " - "Philip Edelbrock and " - "Greg Kroah-Hartman "); -MODULE_DESCRIPTION("I2C EEPROM driver"); -MODULE_LICENSE("GPL"); From 4d08c3d12b61022501989f9f071514d2d6f77c47 Mon Sep 17 00:00:00 2001 From: Jinjie Ruan Date: Wed, 23 Aug 2023 11:50:20 +0800 Subject: [PATCH 151/326] misc: st_core: Do not call kfree_skb() under spin_lock_irqsave() It is not allowed to call kfree_skb() from hardware interrupt context or with hardware interrupts being disabled. So replace kfree_skb() with dev_kfree_skb_irq() under spin_lock_irqsave(). Compile tested only. Fixes: 53618cc1e51e ("Staging: sources for ST core") Signed-off-by: Jinjie Ruan Link: https://lore.kernel.org/r/20230823035020.1281892-1-ruanjinjie@huawei.com Signed-off-by: Greg Kroah-Hartman --- drivers/misc/ti-st/st_core.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/misc/ti-st/st_core.c b/drivers/misc/ti-st/st_core.c index c1a134bd8ba7..b878431553ab 100644 --- a/drivers/misc/ti-st/st_core.c +++ b/drivers/misc/ti-st/st_core.c @@ -15,6 +15,7 @@ #include #include +#include /* * function pointer pointing to either, @@ -429,7 +430,7 @@ static void st_int_enqueue(struct st_data_s *st_gdata, struct sk_buff *skb) case ST_LL_AWAKE_TO_ASLEEP: pr_err("ST LL is illegal state(%ld)," "purging received skb.", st_ll_getstate(st_gdata)); - kfree_skb(skb); + dev_kfree_skb_irq(skb); break; case ST_LL_ASLEEP: skb_queue_tail(&st_gdata->tx_waitq, skb); @@ -438,7 +439,7 @@ static void st_int_enqueue(struct st_data_s *st_gdata, struct sk_buff *skb) default: pr_err("ST LL is illegal state(%ld)," "purging received skb.", st_ll_getstate(st_gdata)); - kfree_skb(skb); + dev_kfree_skb_irq(skb); break; } @@ -492,7 +493,7 @@ void st_tx_wakeup(struct st_data_s *st_data) spin_unlock_irqrestore(&st_data->lock, flags); break; } - kfree_skb(skb); + dev_kfree_skb_irq(skb); spin_unlock_irqrestore(&st_data->lock, flags); } /* if wake-up is set in another context- restart sending */ From 3c69d52e3e12f0330c554c9c6e5498c436c86f4b Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Fri, 22 Sep 2023 10:50:58 -0700 Subject: [PATCH 152/326] misc: bcm-vk: Annotate struct bcm_vk_wkent with __counted_by Prepare for the coming implementation by GCC and Clang of the __counted_by attribute. Flexible array members annotated with __counted_by can have their accesses bounds-checked at run-time checking via CONFIG_UBSAN_BOUNDS (for array indexing) and CONFIG_FORTIFY_SOURCE (for strcpy/memcpy-family functions). As found with Coccinelle[1], add __counted_by for struct bcm_vk_wkent. Additionally, since the element count member must be set before accessing the annotated flexible array member, move its initialization earlier. [1] https://github.com/kees/kernel-tools/blob/trunk/coccinelle/examples/counted_by.cocci Cc: Scott Branden Cc: Broadcom internal kernel review list Cc: Arnd Bergmann Cc: Greg Kroah-Hartman Signed-off-by: Kees Cook Reviewed-by: "Gustavo A. R. Silva" Link: https://lore.kernel.org/r/20230922175057.work.558-kees@kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/misc/bcm-vk/bcm_vk_msg.c | 2 +- drivers/misc/bcm-vk/bcm_vk_msg.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/misc/bcm-vk/bcm_vk_msg.c b/drivers/misc/bcm-vk/bcm_vk_msg.c index e17d81231ea6..1f42d1d5a630 100644 --- a/drivers/misc/bcm-vk/bcm_vk_msg.c +++ b/drivers/misc/bcm-vk/bcm_vk_msg.c @@ -703,12 +703,12 @@ int bcm_vk_send_shutdown_msg(struct bcm_vk *vk, u32 shut_type, entry = kzalloc(struct_size(entry, to_v_msg, 1), GFP_KERNEL); if (!entry) return -ENOMEM; + entry->to_v_blks = 1; /* always 1 block */ /* fill up necessary data */ entry->to_v_msg[0].function_id = VK_FID_SHUTDOWN; set_q_num(&entry->to_v_msg[0], q_num); set_msg_id(&entry->to_v_msg[0], VK_SIMPLEX_MSG_ID); - entry->to_v_blks = 1; /* always 1 block */ entry->to_v_msg[0].cmd = shut_type; entry->to_v_msg[0].arg = pid; diff --git a/drivers/misc/bcm-vk/bcm_vk_msg.h b/drivers/misc/bcm-vk/bcm_vk_msg.h index 56784c8896d8..157495e48f15 100644 --- a/drivers/misc/bcm-vk/bcm_vk_msg.h +++ b/drivers/misc/bcm-vk/bcm_vk_msg.h @@ -116,7 +116,7 @@ struct bcm_vk_wkent { u32 usr_msg_id; u32 to_v_blks; u32 seq_num; - struct vk_msg_blk to_v_msg[]; + struct vk_msg_blk to_v_msg[] __counted_by(to_v_blks); }; /* queue stats counters */ From bd4da04c79346cc7e6b2d4e158adb7d2a4bac53b Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Sat, 30 Sep 2023 15:14:28 -0700 Subject: [PATCH 153/326] mei: fix doc typos Fix grammar and punctuation. Signed-off-by: Randy Dunlap Cc: Tomas Winkler Cc: Greg Kroah-Hartman Link: https://lore.kernel.org/r/20230930221428.18463-3-rdunlap@infradead.org Signed-off-by: Greg Kroah-Hartman --- include/uapi/linux/mei.h | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/include/uapi/linux/mei.h b/include/uapi/linux/mei.h index 6e57743628c0..171c5cce3641 100644 --- a/include/uapi/linux/mei.h +++ b/include/uapi/linux/mei.h @@ -14,8 +14,8 @@ * FW Client (given by UUID). This opens a communication channel * between a host client and a FW client. From this point every read and write * will communicate with the associated FW client. - * Only in close() (file_operation release()) the communication between - * the clients is disconnected + * Only in close() (file_operation release()) is the communication between + * the clients disconnected. * * The IOCTL argument is a struct with a union that contains * the input parameter and the output parameter for this IOCTL. @@ -51,7 +51,7 @@ struct mei_connect_client_data { * DOC: set and unset event notification for a connected client * * The IOCTL argument is 1 for enabling event notification and 0 for - * disabling the service + * disabling the service. * Return: -EOPNOTSUPP if the devices doesn't support the feature */ #define IOCTL_MEI_NOTIFY_SET _IOW('H', 0x02, __u32) @@ -59,8 +59,8 @@ struct mei_connect_client_data { /** * DOC: retrieve notification * - * The IOCTL output argument is 1 if an event was is pending and 0 otherwise - * the ioctl has to be called in order to acknowledge pending event + * The IOCTL output argument is 1 if an event was pending and 0 otherwise. + * The ioctl has to be called in order to acknowledge pending event. * * Return: -EOPNOTSUPP if the devices doesn't support the feature */ @@ -98,14 +98,14 @@ struct mei_connect_client_data_vtag { * FW Client (given by UUID), and virtual tag (vtag). * The IOCTL opens a communication channel between a host client and * a FW client on a tagged channel. From this point on, every read - * and write will communicate with the associated FW client with + * and write will communicate with the associated FW client * on the tagged channel. * Upone close() the communication is terminated. * * The IOCTL argument is a struct with a union that contains * the input parameter and the output parameter for this IOCTL. * - * The input parameter is UUID of the FW Client, a vtag [0,255] + * The input parameter is UUID of the FW Client, a vtag [0,255]. * The output parameter is the properties of the FW client * (FW protocool version and max message size). * From 2801badd26540ecc9c93f6007e2d6e5030246d76 Mon Sep 17 00:00:00 2001 From: Justin Stitt Date: Wed, 27 Sep 2023 05:52:14 +0000 Subject: [PATCH 154/326] ibmvmc: replace deprecated strncpy with strscpy `strncpy` is deprecated for use on NUL-terminated destination strings [1] and as such we should prefer more robust and less ambiguous string interfaces. A suitable replacement is `strscpy` [2] due to the fact that it guarantees NUL-termination on the destination buffer without unnecessarily NUL-padding. Link: https://www.kernel.org/doc/html/latest/process/deprecated.html#strncpy-on-nul-terminated-strings [1] Link: https://manpages.debian.org/testing/linux-manual-4.8/strscpy.9.en.html [2] Link: https://github.com/KSPP/linux/issues/90 Cc: linux-hardening@vger.kernel.org Signed-off-by: Justin Stitt Reviewed-by: Kees Cook Link: https://lore.kernel.org/r/20230927-strncpy-drivers-misc-ibmvmc-c-v1-1-29f56cd3a269@google.com Signed-off-by: Greg Kroah-Hartman --- drivers/misc/ibmvmc.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/misc/ibmvmc.c b/drivers/misc/ibmvmc.c index 2101eb12bcba..6d9ed9325f9f 100644 --- a/drivers/misc/ibmvmc.c +++ b/drivers/misc/ibmvmc.c @@ -1249,9 +1249,7 @@ static long ibmvmc_ioctl_sethmcid(struct ibmvmc_file_session *session, return -EIO; } - /* Make sure buffer is NULL terminated before trying to print it */ - memset(print_buffer, 0, HMC_ID_LEN + 1); - strncpy(print_buffer, hmc->hmc_id, HMC_ID_LEN); + strscpy(print_buffer, hmc->hmc_id, sizeof(print_buffer)); pr_info("ibmvmc: sethmcid: Set HMC ID: \"%s\"\n", print_buffer); memcpy(buffer->real_addr_local, hmc->hmc_id, HMC_ID_LEN); From 14388ec0052c14640bf805dee55372f92557c6d9 Mon Sep 17 00:00:00 2001 From: Justin Stitt Date: Tue, 3 Oct 2023 22:23:07 +0000 Subject: [PATCH 155/326] drivers: misc: ti-st: replace deprecated strncpy with strscpy `strncpy` is deprecated for use on NUL-terminated destination strings [1] and as such we should prefer more robust and less ambiguous string interfaces. We expect both `kim_data->dev_name` and `kim_gdata->dev_name` to be NUL-terminated. `kim_data->dev_name` seems to not require NUL-padding. `kim_gdata` is already zero-allocated and as such does not require NUL-padding: | kim_gdata = kzalloc(sizeof(struct kim_data_s), GFP_KERNEL); Considering the above, a suitable replacement is `strscpy` [2] due to the fact that it guarantees NUL-termination on the destination buffer without unnecessarily NUL-padding. Let's also opt to use the more idiomatic strscpy usage of: strscpy(dest, src, sizeof(dest)) Link: https://www.kernel.org/doc/html/latest/process/deprecated.html#strncpy-on-nul-terminated-strings [1] Link: https://manpages.debian.org/testing/linux-manual-4.8/strscpy.9.en.html [2] Link: https://github.com/KSPP/linux/issues/90 Cc: linux-hardening@vger.kernel.org Signed-off-by: Justin Stitt Reviewed-by: Kees Cook Link: https://lore.kernel.org/r/20231003-strncpy-drivers-misc-ti-st-st_kim-c-v2-1-79630447b0a1@google.com Signed-off-by: Greg Kroah-Hartman --- drivers/misc/ti-st/st_kim.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/misc/ti-st/st_kim.c b/drivers/misc/ti-st/st_kim.c index fe682e0553b2..4b1be0bb6ac0 100644 --- a/drivers/misc/ti-st/st_kim.c +++ b/drivers/misc/ti-st/st_kim.c @@ -590,7 +590,7 @@ static ssize_t store_dev_name(struct device *dev, { struct kim_data_s *kim_data = dev_get_drvdata(dev); pr_debug("storing dev name >%s<", buf); - strncpy(kim_data->dev_name, buf, count); + strscpy(kim_data->dev_name, buf, sizeof(kim_data->dev_name)); pr_debug("stored dev name >%s<", kim_data->dev_name); return count; } @@ -751,7 +751,8 @@ static int kim_probe(struct platform_device *pdev) } /* copying platform data */ - strncpy(kim_gdata->dev_name, pdata->dev_name, UART_DEV_NAME_LEN); + strscpy(kim_gdata->dev_name, pdata->dev_name, + sizeof(kim_gdata->dev_name)); kim_gdata->flow_cntrl = pdata->flow_cntrl; kim_gdata->baud_rate = pdata->baud_rate; pr_info("sysfs entries created\n"); From 7b79e3d2c6333f410a9dc2e61f987120315f09c0 Mon Sep 17 00:00:00 2001 From: Ian Abbott Date: Wed, 13 Sep 2023 18:07:00 +0100 Subject: [PATCH 156/326] comedi: Correct dependencies for COMEDI_NI_PCIDIO The ni_pcidio module does not depend on the comedi_8255 module, so change the `COMEDI_NI_PCIDIO` configuration option to not select `COMEDI_8255` and remove the inherited dependency on `HAS_IOPORT`. Cc: Arnd Bergmann Cc: Niklas Schnelle Signed-off-by: Ian Abbott Link: https://lore.kernel.org/r/20230913170712.111719-2-abbotti@mev.co.uk Signed-off-by: Greg Kroah-Hartman --- drivers/comedi/Kconfig | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/comedi/Kconfig b/drivers/comedi/Kconfig index 9af280735cba..536101f68e0f 100644 --- a/drivers/comedi/Kconfig +++ b/drivers/comedi/Kconfig @@ -1042,7 +1042,6 @@ config COMEDI_NI_PCIDIO tristate "NI PCI-DIO32HS, PCI-6533, PCI-6534 support" depends on HAS_DMA select COMEDI_MITE - select COMEDI_8255 help Enable support for National Instruments PCI-DIO-32HS, PXI-6533, PCI-6533 and PCI-6534 From c62f5032f72a745542aa6a7e777c7819c96adfbe Mon Sep 17 00:00:00 2001 From: Ian Abbott Date: Wed, 13 Sep 2023 18:07:01 +0100 Subject: [PATCH 157/326] comedi: comedi_8254: Use a call-back function for register access Rework the comedi_8254 module to use a call-back function for register access. This will make it easier to isolate the parts that will depend on the `CONFIG_HAS_IOPORT` macro being defined and also allows the possibility of supplying an external callback function during initialization by a variant of the `comedi_8254_init()` and `comedi_8254_mm_init()` functions, although that has not been implemented yet. The `struct comedi_8254` members have been changed to use a pointer to a callback function and a context of type `unsigned long`. The `comedi_8254_init()` and `comedi_8254_mm_init()` functions use an internal callback function and set the context to the base address of the registers (for `comedi_8254_mm_init()` that involves converting a `void __iomem *` to `unsigned long`). A minor change to `dio200_subdev_8254_offset()` in the amplc_dio200_common module has been made due to the changes in `struct comedi_8254`. Cc: Arnd Bergmann Cc: Niklas Schnelle Signed-off-by: Ian Abbott Link: https://lore.kernel.org/r/20230913170712.111719-3-abbotti@mev.co.uk Signed-off-by: Greg Kroah-Hartman --- drivers/comedi/drivers/amplc_dio200_common.c | 4 +- drivers/comedi/drivers/comedi_8254.c | 179 +++++++++++++------ include/linux/comedi/comedi_8254.h | 22 ++- 3 files changed, 145 insertions(+), 60 deletions(-) diff --git a/drivers/comedi/drivers/amplc_dio200_common.c b/drivers/comedi/drivers/amplc_dio200_common.c index ff651f2eb86c..2c1507a23f8a 100644 --- a/drivers/comedi/drivers/amplc_dio200_common.c +++ b/drivers/comedi/drivers/amplc_dio200_common.c @@ -149,9 +149,9 @@ static unsigned int dio200_subdev_8254_offset(struct comedi_device *dev, /* get the offset that was passed to comedi_8254_*_init() */ if (dev->mmio) - offset = i8254->mmio - dev->mmio; + offset = (void __iomem *)i8254->context - dev->mmio; else - offset = i8254->iobase - dev->iobase; + offset = i8254->context - dev->iobase; /* remove the shift that was added for PCIe boards */ if (board->is_pcie) diff --git a/drivers/comedi/drivers/comedi_8254.c b/drivers/comedi/drivers/comedi_8254.c index b4185c1b2695..3f8657fc7ee5 100644 --- a/drivers/comedi/drivers/comedi_8254.c +++ b/drivers/comedi/drivers/comedi_8254.c @@ -119,61 +119,99 @@ #include #include +static unsigned int i8254_io8_cb(struct comedi_8254 *i8254, int dir, + unsigned int reg, unsigned int val) +{ + unsigned long iobase = i8254->context; + unsigned int reg_offset = (reg * I8254_IO8) << i8254->regshift; + + if (dir) { + outb(val, iobase + reg_offset); + return 0; + } else { + return inb(iobase + reg_offset); + } +} + +static unsigned int i8254_io16_cb(struct comedi_8254 *i8254, int dir, + unsigned int reg, unsigned int val) +{ + unsigned long iobase = i8254->context; + unsigned int reg_offset = (reg * I8254_IO16) << i8254->regshift; + + if (dir) { + outw(val, iobase + reg_offset); + return 0; + } else { + return inw(iobase + reg_offset); + } +} + +static unsigned int i8254_io32_cb(struct comedi_8254 *i8254, int dir, + unsigned int reg, unsigned int val) +{ + unsigned long iobase = i8254->context; + unsigned int reg_offset = (reg * I8254_IO32) << i8254->regshift; + + if (dir) { + outl(val, iobase + reg_offset); + return 0; + } else { + return inl(iobase + reg_offset); + } +} + +static unsigned int i8254_mmio8_cb(struct comedi_8254 *i8254, int dir, + unsigned int reg, unsigned int val) +{ + void __iomem *mmiobase = (void __iomem *)i8254->context; + unsigned int reg_offset = (reg * I8254_IO8) << i8254->regshift; + + if (dir) { + writeb(val, mmiobase + reg_offset); + return 0; + } else { + return readb(mmiobase + reg_offset); + } +} + +static unsigned int i8254_mmio16_cb(struct comedi_8254 *i8254, int dir, + unsigned int reg, unsigned int val) +{ + void __iomem *mmiobase = (void __iomem *)i8254->context; + unsigned int reg_offset = (reg * I8254_IO16) << i8254->regshift; + + if (dir) { + writew(val, mmiobase + reg_offset); + return 0; + } else { + return readw(mmiobase + reg_offset); + } +} + +static unsigned int i8254_mmio32_cb(struct comedi_8254 *i8254, int dir, + unsigned int reg, unsigned int val) +{ + void __iomem *mmiobase = (void __iomem *)i8254->context; + unsigned int reg_offset = (reg * I8254_IO32) << i8254->regshift; + + if (dir) { + writel(val, mmiobase + reg_offset); + return 0; + } else { + return readl(mmiobase + reg_offset); + } +} + static unsigned int __i8254_read(struct comedi_8254 *i8254, unsigned int reg) { - unsigned int reg_offset = (reg * i8254->iosize) << i8254->regshift; - unsigned int val; - - switch (i8254->iosize) { - default: - case I8254_IO8: - if (i8254->mmio) - val = readb(i8254->mmio + reg_offset); - else - val = inb(i8254->iobase + reg_offset); - break; - case I8254_IO16: - if (i8254->mmio) - val = readw(i8254->mmio + reg_offset); - else - val = inw(i8254->iobase + reg_offset); - break; - case I8254_IO32: - if (i8254->mmio) - val = readl(i8254->mmio + reg_offset); - else - val = inl(i8254->iobase + reg_offset); - break; - } - return val & 0xff; + return 0xff & i8254->iocb(i8254, 0, reg, 0); } static void __i8254_write(struct comedi_8254 *i8254, unsigned int val, unsigned int reg) { - unsigned int reg_offset = (reg * i8254->iosize) << i8254->regshift; - - switch (i8254->iosize) { - default: - case I8254_IO8: - if (i8254->mmio) - writeb(val, i8254->mmio + reg_offset); - else - outb(val, i8254->iobase + reg_offset); - break; - case I8254_IO16: - if (i8254->mmio) - writew(val, i8254->mmio + reg_offset); - else - outw(val, i8254->iobase + reg_offset); - break; - case I8254_IO32: - if (i8254->mmio) - writel(val, i8254->mmio + reg_offset); - else - outl(val, i8254->iobase + reg_offset); - break; - } + i8254->iocb(i8254, 1, reg, val); } /** @@ -571,8 +609,8 @@ void comedi_8254_subdevice_init(struct comedi_subdevice *s, } EXPORT_SYMBOL_GPL(comedi_8254_subdevice_init); -static struct comedi_8254 *__i8254_init(unsigned long iobase, - void __iomem *mmio, +static struct comedi_8254 *__i8254_init(comedi_8254_iocb_fn *iocb, + unsigned long context, unsigned int osc_base, unsigned int iosize, unsigned int regshift) @@ -585,12 +623,15 @@ static struct comedi_8254 *__i8254_init(unsigned long iobase, iosize == I8254_IO32)) return NULL; + if (!iocb) + return NULL; + i8254 = kzalloc(sizeof(*i8254), GFP_KERNEL); if (!i8254) return NULL; - i8254->iobase = iobase; - i8254->mmio = mmio; + i8254->iocb = iocb; + i8254->context = context; i8254->iosize = iosize; i8254->regshift = regshift; @@ -617,7 +658,22 @@ struct comedi_8254 *comedi_8254_init(unsigned long iobase, unsigned int iosize, unsigned int regshift) { - return __i8254_init(iobase, NULL, osc_base, iosize, regshift); + comedi_8254_iocb_fn *iocb; + + switch (iosize) { + case I8254_IO8: + iocb = i8254_io8_cb; + break; + case I8254_IO16: + iocb = i8254_io16_cb; + break; + case I8254_IO32: + iocb = i8254_io32_cb; + break; + default: + return NULL; + } + return __i8254_init(iocb, iobase, osc_base, iosize, regshift); } EXPORT_SYMBOL_GPL(comedi_8254_init); @@ -634,7 +690,22 @@ struct comedi_8254 *comedi_8254_mm_init(void __iomem *mmio, unsigned int iosize, unsigned int regshift) { - return __i8254_init(0, mmio, osc_base, iosize, regshift); + comedi_8254_iocb_fn *iocb; + + switch (iosize) { + case I8254_IO8: + iocb = i8254_mmio8_cb; + break; + case I8254_IO16: + iocb = i8254_mmio16_cb; + break; + case I8254_IO32: + iocb = i8254_mmio32_cb; + break; + default: + return NULL; + } + return __i8254_init(iocb, (unsigned long)mmio, osc_base, iosize, regshift); } EXPORT_SYMBOL_GPL(comedi_8254_mm_init); diff --git a/include/linux/comedi/comedi_8254.h b/include/linux/comedi/comedi_8254.h index d8264417e53c..18d12321c87d 100644 --- a/include/linux/comedi/comedi_8254.h +++ b/include/linux/comedi/comedi_8254.h @@ -57,10 +57,24 @@ struct comedi_subdevice; /* counter maps zero to 0x10000 */ #define I8254_MAX_COUNT 0x10000 +struct comedi_8254; + +/** + * typedef comedi_8254_iocb_fn - call-back function type for 8254 register access + * @i8254: pointer to struct comedi_8254 + * @dir: direction (0 = read, 1 = write) + * @reg: register number + * @val: value to write + * + * Return: Register value when reading, 0 when writing. + */ +typedef unsigned int comedi_8254_iocb_fn(struct comedi_8254 *i8254, int dir, + unsigned int reg, unsigned int val); + /** * struct comedi_8254 - private data used by this module - * @iobase: PIO base address of the registers (in/out) - * @mmio: MMIO base address of the registers (read/write) + * @iocb: I/O call-back function for register access + * @context: context for register access (e.g. a base address) * @iosize: I/O size used to access the registers (b/w/l) * @regshift: register gap shift * @osc_base: cascaded oscillator speed in ns @@ -76,8 +90,8 @@ struct comedi_subdevice; * @insn_config: driver specific (*insn_config) callback */ struct comedi_8254 { - unsigned long iobase; - void __iomem *mmio; + comedi_8254_iocb_fn *iocb; + unsigned long context; unsigned int iosize; unsigned int regshift; unsigned int osc_base; From fade5e5b0b2a2cc3855f64be6407b0bdcd837714 Mon Sep 17 00:00:00 2001 From: Ian Abbott Date: Wed, 13 Sep 2023 18:07:02 +0100 Subject: [PATCH 158/326] comedi: comedi_8254: Replace comedi_8254_init() and comedi_8254_mm_init() `comedi_8254_init()` and `comedi_8254_mm_init()` return `NULL` on failure, but the failure is not necessarily due to lack of memory. Change them to return an `ERR_PTR` value on failure and rename the functions to make it obvious the API has changed. `comedi_8254_init()` has been replaced with `comedi_8254_io_alloc()`, and `comedi_8254_mm_init()` has been replaced with `comedi_8254_mm_alloc()`. Cc: Arnd Bergmann Cc: Niklas Schnelle Signed-off-by: Ian Abbott Link: https://lore.kernel.org/r/20230913170712.111719-4-abbotti@mev.co.uk Signed-off-by: Greg Kroah-Hartman --- drivers/comedi/drivers.c | 3 +- drivers/comedi/drivers/adl_pci9111.c | 8 +-- drivers/comedi/drivers/adl_pci9118.c | 8 +-- drivers/comedi/drivers/adv_pci1710.c | 8 +-- drivers/comedi/drivers/adv_pci_dio.c | 10 ++-- drivers/comedi/drivers/aio_aio12_8.c | 8 +-- drivers/comedi/drivers/amplc_dio200_common.c | 12 ++--- drivers/comedi/drivers/amplc_pci224.c | 8 +-- drivers/comedi/drivers/amplc_pci230.c | 8 +-- drivers/comedi/drivers/cb_das16_cs.c | 8 +-- drivers/comedi/drivers/cb_pcidas.c | 21 ++++---- drivers/comedi/drivers/cb_pcimdas.c | 10 ++-- drivers/comedi/drivers/comedi_8254.c | 55 +++++++++++--------- drivers/comedi/drivers/das08.c | 9 ++-- drivers/comedi/drivers/das16.c | 8 +-- drivers/comedi/drivers/das16m1.c | 20 +++---- drivers/comedi/drivers/das1800.c | 8 +-- drivers/comedi/drivers/das6402.c | 8 +-- drivers/comedi/drivers/das800.c | 8 +-- drivers/comedi/drivers/me4000.c | 6 +-- drivers/comedi/drivers/ni_at_a2150.c | 8 +-- drivers/comedi/drivers/ni_at_ao.c | 8 +-- drivers/comedi/drivers/ni_labpc_common.c | 38 +++++++------- drivers/comedi/drivers/pcl711.c | 8 +-- drivers/comedi/drivers/pcl812.c | 10 ++-- drivers/comedi/drivers/pcl816.c | 8 +-- drivers/comedi/drivers/pcl818.c | 8 +-- drivers/comedi/drivers/rtd520.c | 6 +-- include/linux/comedi/comedi_8254.h | 16 +++--- 29 files changed, 179 insertions(+), 165 deletions(-) diff --git a/drivers/comedi/drivers.c b/drivers/comedi/drivers.c index d4e2ed709bfc..376130bfba8a 100644 --- a/drivers/comedi/drivers.c +++ b/drivers/comedi/drivers.c @@ -177,7 +177,8 @@ static void comedi_device_detach_cleanup(struct comedi_device *dev) dev->n_subdevices = 0; } kfree(dev->private); - kfree(dev->pacer); + if (!IS_ERR(dev->pacer)) + kfree(dev->pacer); dev->private = NULL; dev->pacer = NULL; dev->driver = NULL; diff --git a/drivers/comedi/drivers/adl_pci9111.c b/drivers/comedi/drivers/adl_pci9111.c index c50f94272a74..086d93f40cb9 100644 --- a/drivers/comedi/drivers/adl_pci9111.c +++ b/drivers/comedi/drivers/adl_pci9111.c @@ -647,10 +647,10 @@ static int pci9111_auto_attach(struct comedi_device *dev, dev->irq = pcidev->irq; } - dev->pacer = comedi_8254_init(dev->iobase + PCI9111_8254_BASE_REG, - I8254_OSC_BASE_2MHZ, I8254_IO16, 0); - if (!dev->pacer) - return -ENOMEM; + dev->pacer = comedi_8254_io_alloc(dev->iobase + PCI9111_8254_BASE_REG, + I8254_OSC_BASE_2MHZ, I8254_IO16, 0); + if (IS_ERR(dev->pacer)) + return PTR_ERR(dev->pacer); ret = comedi_alloc_subdevices(dev, 4); if (ret) diff --git a/drivers/comedi/drivers/adl_pci9118.c b/drivers/comedi/drivers/adl_pci9118.c index 9a816c718303..a76e2666d583 100644 --- a/drivers/comedi/drivers/adl_pci9118.c +++ b/drivers/comedi/drivers/adl_pci9118.c @@ -1524,10 +1524,10 @@ static int pci9118_common_attach(struct comedi_device *dev, devpriv->iobase_a = pci_resource_start(pcidev, 0); dev->iobase = pci_resource_start(pcidev, 2); - dev->pacer = comedi_8254_init(dev->iobase + PCI9118_TIMER_BASE, - I8254_OSC_BASE_4MHZ, I8254_IO32, 0); - if (!dev->pacer) - return -ENOMEM; + dev->pacer = comedi_8254_io_alloc(dev->iobase + PCI9118_TIMER_BASE, + I8254_OSC_BASE_4MHZ, I8254_IO32, 0); + if (IS_ERR(dev->pacer)) + return PTR_ERR(dev->pacer); pci9118_reset(dev); diff --git a/drivers/comedi/drivers/adv_pci1710.c b/drivers/comedi/drivers/adv_pci1710.c index 4f2639968260..c49b0f1f5228 100644 --- a/drivers/comedi/drivers/adv_pci1710.c +++ b/drivers/comedi/drivers/adv_pci1710.c @@ -767,10 +767,10 @@ static int pci1710_auto_attach(struct comedi_device *dev, return ret; dev->iobase = pci_resource_start(pcidev, 2); - dev->pacer = comedi_8254_init(dev->iobase + PCI171X_TIMER_BASE, - I8254_OSC_BASE_10MHZ, I8254_IO16, 0); - if (!dev->pacer) - return -ENOMEM; + dev->pacer = comedi_8254_io_alloc(dev->iobase + PCI171X_TIMER_BASE, + I8254_OSC_BASE_10MHZ, I8254_IO16, 0); + if (IS_ERR(dev->pacer)) + return PTR_ERR(dev->pacer); n_subdevices = 1; /* all boards have analog inputs */ if (board->has_ao) diff --git a/drivers/comedi/drivers/adv_pci_dio.c b/drivers/comedi/drivers/adv_pci_dio.c index efa3e46b554b..0319d8c7ee47 100644 --- a/drivers/comedi/drivers/adv_pci_dio.c +++ b/drivers/comedi/drivers/adv_pci_dio.c @@ -664,11 +664,11 @@ static int pci_dio_auto_attach(struct comedi_device *dev, if (board->timer_regbase) { s = &dev->subdevices[subdev++]; - dev->pacer = comedi_8254_init(dev->iobase + - board->timer_regbase, - 0, I8254_IO8, 0); - if (!dev->pacer) - return -ENOMEM; + dev->pacer = + comedi_8254_io_alloc(dev->iobase + board->timer_regbase, + 0, I8254_IO8, 0); + if (IS_ERR(dev->pacer)) + return PTR_ERR(dev->pacer); comedi_8254_subdevice_init(s, dev->pacer); } diff --git a/drivers/comedi/drivers/aio_aio12_8.c b/drivers/comedi/drivers/aio_aio12_8.c index 30b8a32204d8..f9d40fa3d3a9 100644 --- a/drivers/comedi/drivers/aio_aio12_8.c +++ b/drivers/comedi/drivers/aio_aio12_8.c @@ -206,10 +206,10 @@ static int aio_aio12_8_attach(struct comedi_device *dev, if (ret) return ret; - dev->pacer = comedi_8254_init(dev->iobase + AIO12_8_8254_BASE_REG, - 0, I8254_IO8, 0); - if (!dev->pacer) - return -ENOMEM; + dev->pacer = comedi_8254_io_alloc(dev->iobase + AIO12_8_8254_BASE_REG, + 0, I8254_IO8, 0); + if (IS_ERR(dev->pacer)) + return PTR_ERR(dev->pacer); ret = comedi_alloc_subdevices(dev, 4); if (ret) diff --git a/drivers/comedi/drivers/amplc_dio200_common.c b/drivers/comedi/drivers/amplc_dio200_common.c index 2c1507a23f8a..19166cb26f5e 100644 --- a/drivers/comedi/drivers/amplc_dio200_common.c +++ b/drivers/comedi/drivers/amplc_dio200_common.c @@ -556,14 +556,14 @@ static int dio200_subdev_8254_init(struct comedi_device *dev, } if (dev->mmio) { - i8254 = comedi_8254_mm_init(dev->mmio + offset, - 0, I8254_IO8, regshift); + i8254 = comedi_8254_mm_alloc(dev->mmio + offset, + 0, I8254_IO8, regshift); } else { - i8254 = comedi_8254_init(dev->iobase + offset, - 0, I8254_IO8, regshift); + i8254 = comedi_8254_io_alloc(dev->iobase + offset, + 0, I8254_IO8, regshift); } - if (!i8254) - return -ENOMEM; + if (IS_ERR(i8254)) + return PTR_ERR(i8254); comedi_8254_subdevice_init(s, i8254); diff --git a/drivers/comedi/drivers/amplc_pci224.c b/drivers/comedi/drivers/amplc_pci224.c index 5a04e55daeea..1373637c2ca2 100644 --- a/drivers/comedi/drivers/amplc_pci224.c +++ b/drivers/comedi/drivers/amplc_pci224.c @@ -1051,10 +1051,10 @@ pci224_auto_attach(struct comedi_device *dev, unsigned long context_model) outw(devpriv->daccon | PCI224_DACCON_FIFORESET, dev->iobase + PCI224_DACCON); - dev->pacer = comedi_8254_init(devpriv->iobase1 + PCI224_Z2_BASE, - I8254_OSC_BASE_10MHZ, I8254_IO8, 0); - if (!dev->pacer) - return -ENOMEM; + dev->pacer = comedi_8254_io_alloc(devpriv->iobase1 + PCI224_Z2_BASE, + I8254_OSC_BASE_10MHZ, I8254_IO8, 0); + if (IS_ERR(dev->pacer)) + return PTR_ERR(dev->pacer); ret = comedi_alloc_subdevices(dev, 1); if (ret) diff --git a/drivers/comedi/drivers/amplc_pci230.c b/drivers/comedi/drivers/amplc_pci230.c index 92ba8b8c0172..783da73877b9 100644 --- a/drivers/comedi/drivers/amplc_pci230.c +++ b/drivers/comedi/drivers/amplc_pci230.c @@ -2475,10 +2475,10 @@ static int pci230_auto_attach(struct comedi_device *dev, dev->irq = pci_dev->irq; } - dev->pacer = comedi_8254_init(dev->iobase + PCI230_Z2_CT_BASE, - 0, I8254_IO8, 0); - if (!dev->pacer) - return -ENOMEM; + dev->pacer = comedi_8254_io_alloc(dev->iobase + PCI230_Z2_CT_BASE, + 0, I8254_IO8, 0); + if (IS_ERR(dev->pacer)) + return PTR_ERR(dev->pacer); rc = comedi_alloc_subdevices(dev, 3); if (rc) diff --git a/drivers/comedi/drivers/cb_das16_cs.c b/drivers/comedi/drivers/cb_das16_cs.c index 8e0d2fa5f95d..306208a0695b 100644 --- a/drivers/comedi/drivers/cb_das16_cs.c +++ b/drivers/comedi/drivers/cb_das16_cs.c @@ -363,10 +363,10 @@ static int das16cs_auto_attach(struct comedi_device *dev, if (!devpriv) return -ENOMEM; - dev->pacer = comedi_8254_init(dev->iobase + DAS16CS_TIMER_BASE, - I8254_OSC_BASE_10MHZ, I8254_IO16, 0); - if (!dev->pacer) - return -ENOMEM; + dev->pacer = comedi_8254_io_alloc(dev->iobase + DAS16CS_TIMER_BASE, + I8254_OSC_BASE_10MHZ, I8254_IO16, 0); + if (IS_ERR(dev->pacer)) + return PTR_ERR(dev->pacer); ret = comedi_alloc_subdevices(dev, 4); if (ret) diff --git a/drivers/comedi/drivers/cb_pcidas.c b/drivers/comedi/drivers/cb_pcidas.c index 0c7576b967fc..7a6cd681e932 100644 --- a/drivers/comedi/drivers/cb_pcidas.c +++ b/drivers/comedi/drivers/cb_pcidas.c @@ -1288,16 +1288,16 @@ static int cb_pcidas_auto_attach(struct comedi_device *dev, } dev->irq = pcidev->irq; - dev->pacer = comedi_8254_init(dev->iobase + PCIDAS_AI_8254_BASE, - I8254_OSC_BASE_10MHZ, I8254_IO8, 0); - if (!dev->pacer) - return -ENOMEM; + dev->pacer = comedi_8254_io_alloc(dev->iobase + PCIDAS_AI_8254_BASE, + I8254_OSC_BASE_10MHZ, I8254_IO8, 0); + if (IS_ERR(dev->pacer)) + return PTR_ERR(dev->pacer); - devpriv->ao_pacer = comedi_8254_init(dev->iobase + PCIDAS_AO_8254_BASE, - I8254_OSC_BASE_10MHZ, - I8254_IO8, 0); - if (!devpriv->ao_pacer) - return -ENOMEM; + devpriv->ao_pacer = + comedi_8254_io_alloc(dev->iobase + PCIDAS_AO_8254_BASE, + I8254_OSC_BASE_10MHZ, I8254_IO8, 0); + if (IS_ERR(devpriv->ao_pacer)) + return PTR_ERR(devpriv->ao_pacer); ret = comedi_alloc_subdevices(dev, 7); if (ret) @@ -1453,7 +1453,8 @@ static void cb_pcidas_detach(struct comedi_device *dev) if (devpriv->amcc) outl(INTCSR_INBOX_INTR_STATUS, devpriv->amcc + AMCC_OP_REG_INTCSR); - kfree(devpriv->ao_pacer); + if (!IS_ERR(devpriv->ao_pacer)) + kfree(devpriv->ao_pacer); } comedi_pci_detach(dev); } diff --git a/drivers/comedi/drivers/cb_pcimdas.c b/drivers/comedi/drivers/cb_pcimdas.c index 8bdb00774f11..5816ef65ed5f 100644 --- a/drivers/comedi/drivers/cb_pcimdas.c +++ b/drivers/comedi/drivers/cb_pcimdas.c @@ -364,11 +364,11 @@ static int cb_pcimdas_auto_attach(struct comedi_device *dev, devpriv->BADR3 = pci_resource_start(pcidev, 3); dev->iobase = pci_resource_start(pcidev, 4); - dev->pacer = comedi_8254_init(devpriv->BADR3 + PCIMDAS_8254_BASE, - cb_pcimdas_pacer_clk(dev), - I8254_IO8, 0); - if (!dev->pacer) - return -ENOMEM; + dev->pacer = comedi_8254_io_alloc(devpriv->BADR3 + PCIMDAS_8254_BASE, + cb_pcimdas_pacer_clk(dev), + I8254_IO8, 0); + if (IS_ERR(dev->pacer)) + return PTR_ERR(dev->pacer); ret = comedi_alloc_subdevices(dev, 6); if (ret) diff --git a/drivers/comedi/drivers/comedi_8254.c b/drivers/comedi/drivers/comedi_8254.c index 3f8657fc7ee5..696596944506 100644 --- a/drivers/comedi/drivers/comedi_8254.c +++ b/drivers/comedi/drivers/comedi_8254.c @@ -24,14 +24,17 @@ * * This module provides the following basic functions: * - * comedi_8254_init() / comedi_8254_mm_init() + * comedi_8254_io_alloc() / comedi_8254_mm_alloc() * Initializes this module to access the 8254 registers. The _mm version - * sets up the module for MMIO register access the other for PIO access. - * The pointer returned from these functions is normally stored in the - * comedi_device dev->pacer and will be freed by the comedi core during - * the driver (*detach). If a driver has multiple 8254 devices, they need - * to be stored in the drivers private data and freed when the driver is - * detached. + * sets up the module for MMIO register access; the _io version sets it + * up for PIO access. These functions return a pointer to a struct + * comedi_8254 on success, or an ERR_PTR value on failure. The pointer + * returned from these functions is normally stored in the comedi_device + * dev->pacer and will be freed by the comedi core during the driver + * (*detach). If a driver has multiple 8254 devices, they need to be + * stored in the drivers private data and freed when the driver is + * detached. If the ERR_PTR value is stored, code should check the + * pointer value with !IS_ERR(pointer) before freeing. * * NOTE: The counters are reset by setting them to I8254_MODE0 as part of * this initialization. @@ -621,14 +624,14 @@ static struct comedi_8254 *__i8254_init(comedi_8254_iocb_fn *iocb, /* sanity check that the iosize is valid */ if (!(iosize == I8254_IO8 || iosize == I8254_IO16 || iosize == I8254_IO32)) - return NULL; + return ERR_PTR(-EINVAL); if (!iocb) - return NULL; + return ERR_PTR(-EINVAL); i8254 = kzalloc(sizeof(*i8254), GFP_KERNEL); if (!i8254) - return NULL; + return ERR_PTR(-ENOMEM); i8254->iocb = iocb; i8254->context = context; @@ -646,17 +649,19 @@ static struct comedi_8254 *__i8254_init(comedi_8254_iocb_fn *iocb, } /** - * comedi_8254_init - allocate and initialize the 8254 device for pio access + * comedi_8254_io_alloc - allocate and initialize the 8254 device for pio access * @iobase: port I/O base address * @osc_base: base time of the counter in ns * OPTIONAL - only used by comedi_8254_cascade_ns_to_timer() * @iosize: I/O register size * @regshift: register gap shift + * + * Return: A pointer to a struct comedi_8254 or an ERR_PTR value. */ -struct comedi_8254 *comedi_8254_init(unsigned long iobase, - unsigned int osc_base, - unsigned int iosize, - unsigned int regshift) +struct comedi_8254 *comedi_8254_io_alloc(unsigned long iobase, + unsigned int osc_base, + unsigned int iosize, + unsigned int regshift) { comedi_8254_iocb_fn *iocb; @@ -671,24 +676,26 @@ struct comedi_8254 *comedi_8254_init(unsigned long iobase, iocb = i8254_io32_cb; break; default: - return NULL; + return ERR_PTR(-EINVAL); } return __i8254_init(iocb, iobase, osc_base, iosize, regshift); } -EXPORT_SYMBOL_GPL(comedi_8254_init); +EXPORT_SYMBOL_GPL(comedi_8254_io_alloc); /** - * comedi_8254_mm_init - allocate and initialize the 8254 device for mmio access + * comedi_8254_mm_alloc - allocate and initialize the 8254 device for mmio access * @mmio: memory mapped I/O base address * @osc_base: base time of the counter in ns * OPTIONAL - only used by comedi_8254_cascade_ns_to_timer() * @iosize: I/O register size * @regshift: register gap shift + * + * Return: A pointer to a struct comedi_8254 or an ERR_PTR value. */ -struct comedi_8254 *comedi_8254_mm_init(void __iomem *mmio, - unsigned int osc_base, - unsigned int iosize, - unsigned int regshift) +struct comedi_8254 *comedi_8254_mm_alloc(void __iomem *mmio, + unsigned int osc_base, + unsigned int iosize, + unsigned int regshift) { comedi_8254_iocb_fn *iocb; @@ -703,11 +710,11 @@ struct comedi_8254 *comedi_8254_mm_init(void __iomem *mmio, iocb = i8254_mmio32_cb; break; default: - return NULL; + return ERR_PTR(-EINVAL); } return __i8254_init(iocb, (unsigned long)mmio, osc_base, iosize, regshift); } -EXPORT_SYMBOL_GPL(comedi_8254_mm_init); +EXPORT_SYMBOL_GPL(comedi_8254_mm_alloc); static int __init comedi_8254_module_init(void) { diff --git a/drivers/comedi/drivers/das08.c b/drivers/comedi/drivers/das08.c index f8ab3af2e391..6a3b5411aa90 100644 --- a/drivers/comedi/drivers/das08.c +++ b/drivers/comedi/drivers/das08.c @@ -439,10 +439,11 @@ int das08_common_attach(struct comedi_device *dev, unsigned long iobase) /* Counter subdevice (8254) */ s = &dev->subdevices[5]; if (board->i8254_offset) { - dev->pacer = comedi_8254_init(dev->iobase + board->i8254_offset, - 0, I8254_IO8, 0); - if (!dev->pacer) - return -ENOMEM; + dev->pacer = + comedi_8254_io_alloc(dev->iobase + board->i8254_offset, + 0, I8254_IO8, 0); + if (IS_ERR(dev->pacer)) + return PTR_ERR(dev->pacer); comedi_8254_subdevice_init(s, dev->pacer); } else { diff --git a/drivers/comedi/drivers/das16.c b/drivers/comedi/drivers/das16.c index 728dc02156c8..bfe8811be1b5 100644 --- a/drivers/comedi/drivers/das16.c +++ b/drivers/comedi/drivers/das16.c @@ -1067,10 +1067,10 @@ static int das16_attach(struct comedi_device *dev, struct comedi_devconfig *it) osc_base = I8254_OSC_BASE_1MHZ / it->options[3]; } - dev->pacer = comedi_8254_init(dev->iobase + DAS16_TIMER_BASE_REG, - osc_base, I8254_IO8, 0); - if (!dev->pacer) - return -ENOMEM; + dev->pacer = comedi_8254_io_alloc(dev->iobase + DAS16_TIMER_BASE_REG, + osc_base, I8254_IO8, 0); + if (IS_ERR(dev->pacer)) + return PTR_ERR(dev->pacer); das16_alloc_dma(dev, it->options[2]); diff --git a/drivers/comedi/drivers/das16m1.c b/drivers/comedi/drivers/das16m1.c index 275effb77746..ff9c5a8897bd 100644 --- a/drivers/comedi/drivers/das16m1.c +++ b/drivers/comedi/drivers/das16m1.c @@ -529,15 +529,16 @@ static int das16m1_attach(struct comedi_device *dev, dev->irq = it->options[1]; } - dev->pacer = comedi_8254_init(dev->iobase + DAS16M1_8254_IOBASE2, - I8254_OSC_BASE_10MHZ, I8254_IO8, 0); - if (!dev->pacer) - return -ENOMEM; + dev->pacer = comedi_8254_io_alloc(dev->iobase + DAS16M1_8254_IOBASE2, + I8254_OSC_BASE_10MHZ, I8254_IO8, 0); + if (IS_ERR(dev->pacer)) + return PTR_ERR(dev->pacer); - devpriv->counter = comedi_8254_init(dev->iobase + DAS16M1_8254_IOBASE1, - 0, I8254_IO8, 0); - if (!devpriv->counter) - return -ENOMEM; + devpriv->counter = + comedi_8254_io_alloc(dev->iobase + DAS16M1_8254_IOBASE1, + 0, I8254_IO8, 0); + if (IS_ERR(devpriv->counter)) + return PTR_ERR(devpriv->counter); ret = comedi_alloc_subdevices(dev, 4); if (ret) @@ -603,7 +604,8 @@ static void das16m1_detach(struct comedi_device *dev) if (devpriv) { if (devpriv->extra_iobase) release_region(devpriv->extra_iobase, DAS16M1_SIZE2); - kfree(devpriv->counter); + if (!IS_ERR(devpriv->counter)) + kfree(devpriv->counter); } comedi_legacy_detach(dev); } diff --git a/drivers/comedi/drivers/das1800.c b/drivers/comedi/drivers/das1800.c index f09608c0f4ff..7117c67aee7e 100644 --- a/drivers/comedi/drivers/das1800.c +++ b/drivers/comedi/drivers/das1800.c @@ -1233,10 +1233,10 @@ static int das1800_attach(struct comedi_device *dev, if (!devpriv->fifo_buf) return -ENOMEM; - dev->pacer = comedi_8254_init(dev->iobase + DAS1800_COUNTER, - I8254_OSC_BASE_5MHZ, I8254_IO8, 0); - if (!dev->pacer) - return -ENOMEM; + dev->pacer = comedi_8254_io_alloc(dev->iobase + DAS1800_COUNTER, + I8254_OSC_BASE_5MHZ, I8254_IO8, 0); + if (IS_ERR(dev->pacer)) + return PTR_ERR(dev->pacer); ret = comedi_alloc_subdevices(dev, 4); if (ret) diff --git a/drivers/comedi/drivers/das6402.c b/drivers/comedi/drivers/das6402.c index 1af394591e74..68f95330de45 100644 --- a/drivers/comedi/drivers/das6402.c +++ b/drivers/comedi/drivers/das6402.c @@ -590,10 +590,10 @@ static int das6402_attach(struct comedi_device *dev, } } - dev->pacer = comedi_8254_init(dev->iobase + DAS6402_TIMER_BASE, - I8254_OSC_BASE_10MHZ, I8254_IO8, 0); - if (!dev->pacer) - return -ENOMEM; + dev->pacer = comedi_8254_io_alloc(dev->iobase + DAS6402_TIMER_BASE, + I8254_OSC_BASE_10MHZ, I8254_IO8, 0); + if (IS_ERR(dev->pacer)) + return PTR_ERR(dev->pacer); ret = comedi_alloc_subdevices(dev, 4); if (ret) diff --git a/drivers/comedi/drivers/das800.c b/drivers/comedi/drivers/das800.c index 4ca33f46eaa7..300775523031 100644 --- a/drivers/comedi/drivers/das800.c +++ b/drivers/comedi/drivers/das800.c @@ -672,10 +672,10 @@ static int das800_attach(struct comedi_device *dev, struct comedi_devconfig *it) dev->irq = irq; } - dev->pacer = comedi_8254_init(dev->iobase + DAS800_8254, - I8254_OSC_BASE_1MHZ, I8254_IO8, 0); - if (!dev->pacer) - return -ENOMEM; + dev->pacer = comedi_8254_io_alloc(dev->iobase + DAS800_8254, + I8254_OSC_BASE_1MHZ, I8254_IO8, 0); + if (IS_ERR(dev->pacer)) + return PTR_ERR(dev->pacer); ret = comedi_alloc_subdevices(dev, 3); if (ret) diff --git a/drivers/comedi/drivers/me4000.c b/drivers/comedi/drivers/me4000.c index 9aea02b86ed9..7dd3a0071863 100644 --- a/drivers/comedi/drivers/me4000.c +++ b/drivers/comedi/drivers/me4000.c @@ -1209,9 +1209,9 @@ static int me4000_auto_attach(struct comedi_device *dev, if (!timer_base) return -ENODEV; - dev->pacer = comedi_8254_init(timer_base, 0, I8254_IO8, 0); - if (!dev->pacer) - return -ENOMEM; + dev->pacer = comedi_8254_io_alloc(timer_base, 0, I8254_IO8, 0); + if (IS_ERR(dev->pacer)) + return PTR_ERR(dev->pacer); comedi_8254_subdevice_init(s, dev->pacer); } else { diff --git a/drivers/comedi/drivers/ni_at_a2150.c b/drivers/comedi/drivers/ni_at_a2150.c index df8d219e6723..e4e5a0ebd195 100644 --- a/drivers/comedi/drivers/ni_at_a2150.c +++ b/drivers/comedi/drivers/ni_at_a2150.c @@ -707,10 +707,10 @@ static int a2150_attach(struct comedi_device *dev, struct comedi_devconfig *it) /* an IRQ and DMA are required to support async commands */ a2150_alloc_irq_and_dma(dev, it); - dev->pacer = comedi_8254_init(dev->iobase + I8253_BASE_REG, - 0, I8254_IO8, 0); - if (!dev->pacer) - return -ENOMEM; + dev->pacer = comedi_8254_io_alloc(dev->iobase + I8253_BASE_REG, + 0, I8254_IO8, 0); + if (IS_ERR(dev->pacer)) + return PTR_ERR(dev->pacer); ret = comedi_alloc_subdevices(dev, 1); if (ret) diff --git a/drivers/comedi/drivers/ni_at_ao.c b/drivers/comedi/drivers/ni_at_ao.c index 9f3147b72aa8..9cf6b4ff6b65 100644 --- a/drivers/comedi/drivers/ni_at_ao.c +++ b/drivers/comedi/drivers/ni_at_ao.c @@ -303,10 +303,10 @@ static int atao_attach(struct comedi_device *dev, struct comedi_devconfig *it) if (!devpriv) return -ENOMEM; - dev->pacer = comedi_8254_init(dev->iobase + ATAO_82C53_BASE, - 0, I8254_IO8, 0); - if (!dev->pacer) - return -ENOMEM; + dev->pacer = comedi_8254_io_alloc(dev->iobase + ATAO_82C53_BASE, + 0, I8254_IO8, 0); + if (IS_ERR(dev->pacer)) + return PTR_ERR(dev->pacer); ret = comedi_alloc_subdevices(dev, 4); if (ret) diff --git a/drivers/comedi/drivers/ni_labpc_common.c b/drivers/comedi/drivers/ni_labpc_common.c index 763249653228..eb8f6431276a 100644 --- a/drivers/comedi/drivers/ni_labpc_common.c +++ b/drivers/comedi/drivers/ni_labpc_common.c @@ -1222,24 +1222,24 @@ int labpc_common_attach(struct comedi_device *dev, } if (dev->mmio) { - dev->pacer = comedi_8254_mm_init(dev->mmio + COUNTER_B_BASE_REG, - I8254_OSC_BASE_2MHZ, - I8254_IO8, 0); - devpriv->counter = comedi_8254_mm_init(dev->mmio + - COUNTER_A_BASE_REG, - I8254_OSC_BASE_2MHZ, - I8254_IO8, 0); + dev->pacer = + comedi_8254_mm_alloc(dev->mmio + COUNTER_B_BASE_REG, + I8254_OSC_BASE_2MHZ, I8254_IO8, 0); + devpriv->counter = + comedi_8254_mm_alloc(dev->mmio + COUNTER_A_BASE_REG, + I8254_OSC_BASE_2MHZ, I8254_IO8, 0); } else { - dev->pacer = comedi_8254_init(dev->iobase + COUNTER_B_BASE_REG, - I8254_OSC_BASE_2MHZ, - I8254_IO8, 0); - devpriv->counter = comedi_8254_init(dev->iobase + - COUNTER_A_BASE_REG, - I8254_OSC_BASE_2MHZ, - I8254_IO8, 0); + dev->pacer = + comedi_8254_io_alloc(dev->iobase + COUNTER_B_BASE_REG, + I8254_OSC_BASE_2MHZ, I8254_IO8, 0); + devpriv->counter = + comedi_8254_io_alloc(dev->iobase + COUNTER_A_BASE_REG, + I8254_OSC_BASE_2MHZ, I8254_IO8, 0); } - if (!dev->pacer || !devpriv->counter) - return -ENOMEM; + if (IS_ERR(dev->pacer)) + return PTR_ERR(dev->pacer); + if (IS_ERR(devpriv->counter)) + return PTR_ERR(devpriv->counter); ret = comedi_alloc_subdevices(dev, 5); if (ret) @@ -1341,8 +1341,10 @@ void labpc_common_detach(struct comedi_device *dev) { struct labpc_private *devpriv = dev->private; - if (devpriv) - kfree(devpriv->counter); + if (devpriv) { + if (!IS_ERR(devpriv->counter)) + kfree(devpriv->counter); + } } EXPORT_SYMBOL_GPL(labpc_common_detach); diff --git a/drivers/comedi/drivers/pcl711.c b/drivers/comedi/drivers/pcl711.c index 05172c553c8a..0cf3917defe7 100644 --- a/drivers/comedi/drivers/pcl711.c +++ b/drivers/comedi/drivers/pcl711.c @@ -429,10 +429,10 @@ static int pcl711_attach(struct comedi_device *dev, struct comedi_devconfig *it) dev->irq = it->options[1]; } - dev->pacer = comedi_8254_init(dev->iobase + PCL711_TIMER_BASE, - I8254_OSC_BASE_2MHZ, I8254_IO8, 0); - if (!dev->pacer) - return -ENOMEM; + dev->pacer = comedi_8254_io_alloc(dev->iobase + PCL711_TIMER_BASE, + I8254_OSC_BASE_2MHZ, I8254_IO8, 0); + if (IS_ERR(dev->pacer)) + return PTR_ERR(dev->pacer); ret = comedi_alloc_subdevices(dev, 4); if (ret) diff --git a/drivers/comedi/drivers/pcl812.c b/drivers/comedi/drivers/pcl812.c index 70dbc129fcf5..0df639c6a595 100644 --- a/drivers/comedi/drivers/pcl812.c +++ b/drivers/comedi/drivers/pcl812.c @@ -1143,11 +1143,11 @@ static int pcl812_attach(struct comedi_device *dev, struct comedi_devconfig *it) return ret; if (board->irq_bits) { - dev->pacer = comedi_8254_init(dev->iobase + PCL812_TIMER_BASE, - I8254_OSC_BASE_2MHZ, - I8254_IO8, 0); - if (!dev->pacer) - return -ENOMEM; + dev->pacer = + comedi_8254_io_alloc(dev->iobase + PCL812_TIMER_BASE, + I8254_OSC_BASE_2MHZ, I8254_IO8, 0); + if (IS_ERR(dev->pacer)) + return PTR_ERR(dev->pacer); if ((1 << it->options[1]) & board->irq_bits) { ret = request_irq(it->options[1], pcl812_interrupt, 0, diff --git a/drivers/comedi/drivers/pcl816.c b/drivers/comedi/drivers/pcl816.c index a5e5320be648..28d1a88c50f6 100644 --- a/drivers/comedi/drivers/pcl816.c +++ b/drivers/comedi/drivers/pcl816.c @@ -615,10 +615,10 @@ static int pcl816_attach(struct comedi_device *dev, struct comedi_devconfig *it) /* an IRQ and DMA are required to support async commands */ pcl816_alloc_irq_and_dma(dev, it); - dev->pacer = comedi_8254_init(dev->iobase + PCL816_TIMER_BASE, - I8254_OSC_BASE_10MHZ, I8254_IO8, 0); - if (!dev->pacer) - return -ENOMEM; + dev->pacer = comedi_8254_io_alloc(dev->iobase + PCL816_TIMER_BASE, + I8254_OSC_BASE_10MHZ, I8254_IO8, 0); + if (IS_ERR(dev->pacer)) + return PTR_ERR(dev->pacer); ret = comedi_alloc_subdevices(dev, 4); if (ret) diff --git a/drivers/comedi/drivers/pcl818.c b/drivers/comedi/drivers/pcl818.c index 29e503de8267..4127adcfb229 100644 --- a/drivers/comedi/drivers/pcl818.c +++ b/drivers/comedi/drivers/pcl818.c @@ -1015,10 +1015,10 @@ static int pcl818_attach(struct comedi_device *dev, struct comedi_devconfig *it) else osc_base = I8254_OSC_BASE_1MHZ; - dev->pacer = comedi_8254_init(dev->iobase + PCL818_TIMER_BASE, - osc_base, I8254_IO8, 0); - if (!dev->pacer) - return -ENOMEM; + dev->pacer = comedi_8254_io_alloc(dev->iobase + PCL818_TIMER_BASE, + osc_base, I8254_IO8, 0); + if (IS_ERR(dev->pacer)) + return PTR_ERR(dev->pacer); /* max sampling speed */ devpriv->ns_min = board->ns_min; diff --git a/drivers/comedi/drivers/rtd520.c b/drivers/comedi/drivers/rtd520.c index 7e0ec1a2a2ca..44bb0decd7a4 100644 --- a/drivers/comedi/drivers/rtd520.c +++ b/drivers/comedi/drivers/rtd520.c @@ -1289,9 +1289,9 @@ static int rtd_auto_attach(struct comedi_device *dev, /* 8254 Timer/Counter subdevice */ s = &dev->subdevices[3]; - dev->pacer = comedi_8254_mm_init(dev->mmio + LAS0_8254_TIMER_BASE, - RTD_CLOCK_BASE, I8254_IO8, 2); - if (!dev->pacer) + dev->pacer = comedi_8254_mm_alloc(dev->mmio + LAS0_8254_TIMER_BASE, + RTD_CLOCK_BASE, I8254_IO8, 2); + if (IS_ERR(dev->pacer)) return -ENOMEM; comedi_8254_subdevice_init(s, dev->pacer); diff --git a/include/linux/comedi/comedi_8254.h b/include/linux/comedi/comedi_8254.h index 18d12321c87d..393ccb301028 100644 --- a/include/linux/comedi/comedi_8254.h +++ b/include/linux/comedi/comedi_8254.h @@ -136,13 +136,13 @@ void comedi_8254_set_busy(struct comedi_8254 *i8254, void comedi_8254_subdevice_init(struct comedi_subdevice *s, struct comedi_8254 *i8254); -struct comedi_8254 *comedi_8254_init(unsigned long iobase, - unsigned int osc_base, - unsigned int iosize, - unsigned int regshift); -struct comedi_8254 *comedi_8254_mm_init(void __iomem *mmio, - unsigned int osc_base, - unsigned int iosize, - unsigned int regshift); +struct comedi_8254 *comedi_8254_io_alloc(unsigned long iobase, + unsigned int osc_base, + unsigned int iosize, + unsigned int regshift); +struct comedi_8254 *comedi_8254_mm_alloc(void __iomem *mmio, + unsigned int osc_base, + unsigned int iosize, + unsigned int regshift); #endif /* _COMEDI_8254_H */ From 90d256757e0bffd7a9beafd7c2bdc40a0236f9ec Mon Sep 17 00:00:00 2001 From: Ian Abbott Date: Wed, 13 Sep 2023 18:07:03 +0100 Subject: [PATCH 159/326] comedi: comedi_8254: Conditionally remove I/O port support The comedi_8254 module supports both port I/O and memory-mapped I/O. In a future patch, the port I/O functions (`inb()`, `outb()`, and friends) will only be declared if the `HAS_IOPORT` configuration option is enabled. Conditionally compile the parts of the module that use port I/O so they are compiled if and only if the `CONFIG_HAS_IOPORT` macro is defined, so that it can still be built if the port I/O functions have not been declared. If `CONFIG_HAS_IOPORT` is undefined, replace the GPL-exported `comedi_8254_io_alloc()` function with a dummy static inline version that just returns `ERR_PTR(-ENXIO)`. Cc: Arnd Bergmann Cc: Niklas Schnelle Signed-off-by: Ian Abbott Link: https://lore.kernel.org/r/20230913170712.111719-5-abbotti@mev.co.uk Signed-off-by: Greg Kroah-Hartman --- drivers/comedi/drivers/comedi_8254.c | 8 ++++++++ include/linux/comedi/comedi_8254.h | 13 +++++++++++++ 2 files changed, 21 insertions(+) diff --git a/drivers/comedi/drivers/comedi_8254.c b/drivers/comedi/drivers/comedi_8254.c index 696596944506..6beca2a6d66e 100644 --- a/drivers/comedi/drivers/comedi_8254.c +++ b/drivers/comedi/drivers/comedi_8254.c @@ -122,6 +122,8 @@ #include #include +#ifdef CONFIG_HAS_IOPORT + static unsigned int i8254_io8_cb(struct comedi_8254 *i8254, int dir, unsigned int reg, unsigned int val) { @@ -164,6 +166,8 @@ static unsigned int i8254_io32_cb(struct comedi_8254 *i8254, int dir, } } +#endif /* CONFIG_HAS_IOPORT */ + static unsigned int i8254_mmio8_cb(struct comedi_8254 *i8254, int dir, unsigned int reg, unsigned int val) { @@ -648,6 +652,8 @@ static struct comedi_8254 *__i8254_init(comedi_8254_iocb_fn *iocb, return i8254; } +#ifdef CONFIG_HAS_IOPORT + /** * comedi_8254_io_alloc - allocate and initialize the 8254 device for pio access * @iobase: port I/O base address @@ -682,6 +688,8 @@ struct comedi_8254 *comedi_8254_io_alloc(unsigned long iobase, } EXPORT_SYMBOL_GPL(comedi_8254_io_alloc); +#endif /* CONFIG_HAS_IOPORT */ + /** * comedi_8254_mm_alloc - allocate and initialize the 8254 device for mmio access * @mmio: memory mapped I/O base address diff --git a/include/linux/comedi/comedi_8254.h b/include/linux/comedi/comedi_8254.h index 393ccb301028..d527f04400df 100644 --- a/include/linux/comedi/comedi_8254.h +++ b/include/linux/comedi/comedi_8254.h @@ -12,6 +12,8 @@ #define _COMEDI_8254_H #include +#include +#include struct comedi_device; struct comedi_insn; @@ -136,10 +138,21 @@ void comedi_8254_set_busy(struct comedi_8254 *i8254, void comedi_8254_subdevice_init(struct comedi_subdevice *s, struct comedi_8254 *i8254); +#ifdef CONFIG_HAS_IOPORT struct comedi_8254 *comedi_8254_io_alloc(unsigned long iobase, unsigned int osc_base, unsigned int iosize, unsigned int regshift); +#else +static inline struct comedi_8254 *comedi_8254_io_alloc(unsigned long iobase, + unsigned int osc_base, + unsigned int iosize, + unsigned int regshift) +{ + return ERR_PTR(-ENXIO); +} +#endif + struct comedi_8254 *comedi_8254_mm_alloc(void __iomem *mmio, unsigned int osc_base, unsigned int iosize, From 0ccb86a690c52d047b6cafa0f7f99805bf6eeb4e Mon Sep 17 00:00:00 2001 From: Ian Abbott Date: Wed, 13 Sep 2023 18:07:04 +0100 Subject: [PATCH 160/326] comedi: 8255_pci: Conditionally remove devices that use port I/O In a future patch, the port I/O functions (`inb()`, `outb()`, and friends will only be declared in the `HAS_IOPORT` configuration option is enabled. The 8255_pci module supports PCI digital I/O devices from various manufacturers that consist of one or more 8255 Programmable Peripheral Interface chips (or equivalent hardware) to provide their digital I/O ports. Some of the devices use port I/O and some only use memory-mapped I/O. Conditionally compile in support for the devices that need port I/O if and only if the `CONFIG_HAS_IOPORT` macro is defined. Change `pci_8255_auto_attach()` to return an error if the device actually requires port I/O (based on the PCI BAR resource flags) but the `HAS_IOPORT` configuration is not enabled. Cc: Arnd Bergmann Cc: Niklas Schnelle Signed-off-by: Ian Abbott Link: https://lore.kernel.org/r/20230913170712.111719-6-abbotti@mev.co.uk Signed-off-by: Greg Kroah-Hartman --- drivers/comedi/drivers/8255_pci.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/drivers/comedi/drivers/8255_pci.c b/drivers/comedi/drivers/8255_pci.c index 0fec048e3a53..9ad52e9f5427 100644 --- a/drivers/comedi/drivers/8255_pci.c +++ b/drivers/comedi/drivers/8255_pci.c @@ -57,6 +57,7 @@ #include enum pci_8255_boardid { +#ifdef CONFIG_HAS_IOPORT BOARD_ADLINK_PCI7224, BOARD_ADLINK_PCI7248, BOARD_ADLINK_PCI7296, @@ -65,6 +66,7 @@ enum pci_8255_boardid { BOARD_CB_PCIDIO48H_OLD, BOARD_CB_PCIDIO48H_NEW, BOARD_CB_PCIDIO96H, +#endif /* CONFIG_HAS_IOPORT */ BOARD_NI_PCIDIO96, BOARD_NI_PCIDIO96B, BOARD_NI_PXI6508, @@ -82,6 +84,7 @@ struct pci_8255_boardinfo { }; static const struct pci_8255_boardinfo pci_8255_boards[] = { +#ifdef CONFIG_HAS_IOPORT [BOARD_ADLINK_PCI7224] = { .name = "adl_pci-7224", .dio_badr = 2, @@ -122,6 +125,7 @@ static const struct pci_8255_boardinfo pci_8255_boards[] = { .dio_badr = 2, .n_8255 = 4, }, +#endif /* CONFIG_HAS_IOPORT */ [BOARD_NI_PCIDIO96] = { .name = "ni_pci-dio-96", .dio_badr = 1, @@ -219,8 +223,11 @@ static int pci_8255_auto_attach(struct comedi_device *dev, dev->mmio = pci_ioremap_bar(pcidev, board->dio_badr); if (!dev->mmio) return -ENOMEM; - } else { + } else if (IS_ENABLED(CONFIG_HAS_IOPORT)) { dev->iobase = pci_resource_start(pcidev, board->dio_badr); + } else { + dev_err(dev->class_dev, "error! need I/O port support\n"); + return -ENXIO; } /* @@ -259,6 +266,7 @@ static int pci_8255_pci_probe(struct pci_dev *dev, } static const struct pci_device_id pci_8255_pci_table[] = { +#ifdef CONFIG_HAS_IOPORT { PCI_VDEVICE(ADLINK, 0x7224), BOARD_ADLINK_PCI7224 }, { PCI_VDEVICE(ADLINK, 0x7248), BOARD_ADLINK_PCI7248 }, { PCI_VDEVICE(ADLINK, 0x7296), BOARD_ADLINK_PCI7296 }, @@ -269,6 +277,7 @@ static const struct pci_device_id pci_8255_pci_table[] = { { PCI_DEVICE_SUB(PCI_VENDOR_ID_CB, 0x000b, PCI_VENDOR_ID_CB, 0x000b), .driver_data = BOARD_CB_PCIDIO48H_NEW }, { PCI_VDEVICE(CB, 0x0017), BOARD_CB_PCIDIO96H }, +#endif /* CONFIG_HAS_IOPORT */ { PCI_VDEVICE(NI, 0x0160), BOARD_NI_PCIDIO96 }, { PCI_VDEVICE(NI, 0x1630), BOARD_NI_PCIDIO96B }, { PCI_VDEVICE(NI, 0x13c0), BOARD_NI_PXI6508 }, From 5c57b1ccecc72738d4b9be2dfcdfb9001be76bd7 Mon Sep 17 00:00:00 2001 From: Ian Abbott Date: Wed, 13 Sep 2023 18:07:05 +0100 Subject: [PATCH 161/326] comedi: comedi_8255: Rework subdevice initialization functions Comedi drivers can initialize an 8255 subdevice in I/O space by calling `subdev_8255_init()`, or in memory-mapped I/O space by calling `subdev_8255_mm_init()`, or by supplying a call-back function pointer and context to either of those functions. Change it so that a new function `subdev_8255_cb_init()` shall be called instead when supplying a callback function and context, and remove the call-back function parameter from `subdev_8255_init()` and `subdev_8255_mm_init()`. Also rename `subdev_8255_init()` to `subdev_8255_io_init()`. The parameters are changing, so might as well rename it at the same time. Also rename the `regbase` member of `struct subdev_8255_private` to `context` since this holds the context for the call-back function call. Cc: Arnd Bergmann Cc: Niklas Schnelle Signed-off-by: Ian Abbott Link: https://lore.kernel.org/r/20230913170712.111719-7-abbotti@mev.co.uk Signed-off-by: Greg Kroah-Hartman --- drivers/comedi/drivers/8255.c | 2 +- drivers/comedi/drivers/8255_pci.c | 4 +- drivers/comedi/drivers/adv_pci_dio.c | 4 +- drivers/comedi/drivers/aio_aio12_8.c | 2 +- drivers/comedi/drivers/amplc_pc236_common.c | 2 +- drivers/comedi/drivers/amplc_pci230.c | 2 +- drivers/comedi/drivers/cb_pcidas.c | 2 +- drivers/comedi/drivers/cb_pcidas64.c | 7 +- drivers/comedi/drivers/cb_pcidda.c | 2 +- drivers/comedi/drivers/cb_pcimdas.c | 2 +- drivers/comedi/drivers/cb_pcimdda.c | 2 +- drivers/comedi/drivers/comedi_8255.c | 127 +++++++++----------- drivers/comedi/drivers/daqboard2000.c | 4 +- drivers/comedi/drivers/das08.c | 2 +- drivers/comedi/drivers/das16.c | 2 +- drivers/comedi/drivers/das16m1.c | 2 +- drivers/comedi/drivers/dmm32at.c | 3 +- drivers/comedi/drivers/ni_atmio16d.c | 2 +- drivers/comedi/drivers/ni_daq_dio24.c | 2 +- drivers/comedi/drivers/ni_labpc_common.c | 4 +- drivers/comedi/drivers/ni_mio_common.c | 4 +- drivers/comedi/drivers/pcl724.c | 6 +- drivers/comedi/drivers/pcm3724.c | 2 +- include/linux/comedi/comedi_8255.h | 13 +- 24 files changed, 98 insertions(+), 106 deletions(-) diff --git a/drivers/comedi/drivers/8255.c b/drivers/comedi/drivers/8255.c index ced8ea09d4fa..f45f7bd1c61a 100644 --- a/drivers/comedi/drivers/8255.c +++ b/drivers/comedi/drivers/8255.c @@ -80,7 +80,7 @@ static int dev_8255_attach(struct comedi_device *dev, if (ret) { s->type = COMEDI_SUBD_UNUSED; } else { - ret = subdev_8255_init(dev, s, NULL, iobase); + ret = subdev_8255_io_init(dev, s, iobase); if (ret) { /* * Release the I/O port region here, as the diff --git a/drivers/comedi/drivers/8255_pci.c b/drivers/comedi/drivers/8255_pci.c index 9ad52e9f5427..8498cabe4d91 100644 --- a/drivers/comedi/drivers/8255_pci.c +++ b/drivers/comedi/drivers/8255_pci.c @@ -242,9 +242,9 @@ static int pci_8255_auto_attach(struct comedi_device *dev, for (i = 0; i < board->n_8255; i++) { s = &dev->subdevices[i]; if (dev->mmio) - ret = subdev_8255_mm_init(dev, s, NULL, i * I8255_SIZE); + ret = subdev_8255_mm_init(dev, s, i * I8255_SIZE); else - ret = subdev_8255_init(dev, s, NULL, i * I8255_SIZE); + ret = subdev_8255_io_init(dev, s, i * I8255_SIZE); if (ret) return ret; } diff --git a/drivers/comedi/drivers/adv_pci_dio.c b/drivers/comedi/drivers/adv_pci_dio.c index 0319d8c7ee47..ca8054504760 100644 --- a/drivers/comedi/drivers/adv_pci_dio.c +++ b/drivers/comedi/drivers/adv_pci_dio.c @@ -642,8 +642,8 @@ static int pci_dio_auto_attach(struct comedi_device *dev, for (j = 0; j < d->chans; j++) { s = &dev->subdevices[subdev++]; - ret = subdev_8255_init(dev, s, NULL, - d->addr + j * I8255_SIZE); + ret = subdev_8255_io_init(dev, s, + d->addr + j * I8255_SIZE); if (ret) return ret; } diff --git a/drivers/comedi/drivers/aio_aio12_8.c b/drivers/comedi/drivers/aio_aio12_8.c index f9d40fa3d3a9..227a86a3a760 100644 --- a/drivers/comedi/drivers/aio_aio12_8.c +++ b/drivers/comedi/drivers/aio_aio12_8.c @@ -247,7 +247,7 @@ static int aio_aio12_8_attach(struct comedi_device *dev, /* Digital I/O subdevice (8255) */ s = &dev->subdevices[2]; - ret = subdev_8255_init(dev, s, NULL, AIO12_8_8255_BASE_REG); + ret = subdev_8255_io_init(dev, s, AIO12_8_8255_BASE_REG); if (ret) return ret; diff --git a/drivers/comedi/drivers/amplc_pc236_common.c b/drivers/comedi/drivers/amplc_pc236_common.c index 9f4f89b1ef23..326ca72c24ec 100644 --- a/drivers/comedi/drivers/amplc_pc236_common.c +++ b/drivers/comedi/drivers/amplc_pc236_common.c @@ -147,7 +147,7 @@ int amplc_pc236_common_attach(struct comedi_device *dev, unsigned long iobase, s = &dev->subdevices[0]; /* digital i/o subdevice (8255) */ - ret = subdev_8255_init(dev, s, NULL, 0x00); + ret = subdev_8255_io_init(dev, s, 0x00); if (ret) return ret; diff --git a/drivers/comedi/drivers/amplc_pci230.c b/drivers/comedi/drivers/amplc_pci230.c index 783da73877b9..c74209c2e83a 100644 --- a/drivers/comedi/drivers/amplc_pci230.c +++ b/drivers/comedi/drivers/amplc_pci230.c @@ -2529,7 +2529,7 @@ static int pci230_auto_attach(struct comedi_device *dev, s = &dev->subdevices[2]; /* digital i/o subdevice */ if (board->have_dio) { - rc = subdev_8255_init(dev, s, NULL, PCI230_PPI_X_BASE); + rc = subdev_8255_io_init(dev, s, PCI230_PPI_X_BASE); if (rc) return rc; } else { diff --git a/drivers/comedi/drivers/cb_pcidas.c b/drivers/comedi/drivers/cb_pcidas.c index 7a6cd681e932..8bb9b0623869 100644 --- a/drivers/comedi/drivers/cb_pcidas.c +++ b/drivers/comedi/drivers/cb_pcidas.c @@ -1352,7 +1352,7 @@ static int cb_pcidas_auto_attach(struct comedi_device *dev, /* 8255 */ s = &dev->subdevices[2]; - ret = subdev_8255_init(dev, s, NULL, PCIDAS_8255_BASE); + ret = subdev_8255_io_init(dev, s, PCIDAS_8255_BASE); if (ret) return ret; diff --git a/drivers/comedi/drivers/cb_pcidas64.c b/drivers/comedi/drivers/cb_pcidas64.c index ca6038a25f26..ff19fc3859e4 100644 --- a/drivers/comedi/drivers/cb_pcidas64.c +++ b/drivers/comedi/drivers/cb_pcidas64.c @@ -3877,11 +3877,10 @@ static int setup_subdevices(struct comedi_device *dev) s = &dev->subdevices[4]; if (board->has_8255) { if (board->layout == LAYOUT_4020) { - ret = subdev_8255_init(dev, s, dio_callback_4020, - I8255_4020_REG); + ret = subdev_8255_cb_init(dev, s, dio_callback_4020, + I8255_4020_REG); } else { - ret = subdev_8255_mm_init(dev, s, NULL, - DIO_8255_OFFSET); + ret = subdev_8255_mm_init(dev, s, DIO_8255_OFFSET); } if (ret) return ret; diff --git a/drivers/comedi/drivers/cb_pcidda.c b/drivers/comedi/drivers/cb_pcidda.c index c52204a6bda4..c353d0f87da9 100644 --- a/drivers/comedi/drivers/cb_pcidda.c +++ b/drivers/comedi/drivers/cb_pcidda.c @@ -365,7 +365,7 @@ static int cb_pcidda_auto_attach(struct comedi_device *dev, /* two 8255 digital io subdevices */ for (i = 0; i < 2; i++) { s = &dev->subdevices[1 + i]; - ret = subdev_8255_init(dev, s, NULL, i * I8255_SIZE); + ret = subdev_8255_io_init(dev, s, i * I8255_SIZE); if (ret) return ret; } diff --git a/drivers/comedi/drivers/cb_pcimdas.c b/drivers/comedi/drivers/cb_pcimdas.c index 5816ef65ed5f..641c30df392e 100644 --- a/drivers/comedi/drivers/cb_pcimdas.c +++ b/drivers/comedi/drivers/cb_pcimdas.c @@ -405,7 +405,7 @@ static int cb_pcimdas_auto_attach(struct comedi_device *dev, /* Digital I/O subdevice */ s = &dev->subdevices[2]; - ret = subdev_8255_init(dev, s, NULL, PCIMDAS_8255_BASE); + ret = subdev_8255_io_init(dev, s, PCIMDAS_8255_BASE); if (ret) return ret; diff --git a/drivers/comedi/drivers/cb_pcimdda.c b/drivers/comedi/drivers/cb_pcimdda.c index bf8093a10315..541b5742bb1b 100644 --- a/drivers/comedi/drivers/cb_pcimdda.c +++ b/drivers/comedi/drivers/cb_pcimdda.c @@ -154,7 +154,7 @@ static int cb_pcimdda_auto_attach(struct comedi_device *dev, s = &dev->subdevices[1]; /* digital i/o subdevice */ - return subdev_8255_init(dev, s, NULL, PCIMDDA_8255_BASE_REG); + return subdev_8255_io_init(dev, s, PCIMDDA_8255_BASE_REG); } static struct comedi_driver cb_pcimdda_driver = { diff --git a/drivers/comedi/drivers/comedi_8255.c b/drivers/comedi/drivers/comedi_8255.c index 5562b9cd0a17..28fd9d8c95cc 100644 --- a/drivers/comedi/drivers/comedi_8255.c +++ b/drivers/comedi/drivers/comedi_8255.c @@ -33,9 +33,9 @@ #include struct subdev_8255_private { - unsigned long regbase; + unsigned long context; int (*io)(struct comedi_device *dev, int dir, int port, int data, - unsigned long regbase); + unsigned long context); }; static int subdev_8255_io(struct comedi_device *dev, @@ -64,7 +64,7 @@ static int subdev_8255_insn(struct comedi_device *dev, unsigned int *data) { struct subdev_8255_private *spriv = s->private; - unsigned long regbase = spriv->regbase; + unsigned long context = spriv->context; unsigned int mask; unsigned int v; @@ -72,18 +72,18 @@ static int subdev_8255_insn(struct comedi_device *dev, if (mask) { if (mask & 0xff) spriv->io(dev, 1, I8255_DATA_A_REG, - s->state & 0xff, regbase); + s->state & 0xff, context); if (mask & 0xff00) spriv->io(dev, 1, I8255_DATA_B_REG, - (s->state >> 8) & 0xff, regbase); + (s->state >> 8) & 0xff, context); if (mask & 0xff0000) spriv->io(dev, 1, I8255_DATA_C_REG, - (s->state >> 16) & 0xff, regbase); + (s->state >> 16) & 0xff, context); } - v = spriv->io(dev, 0, I8255_DATA_A_REG, 0, regbase); - v |= (spriv->io(dev, 0, I8255_DATA_B_REG, 0, regbase) << 8); - v |= (spriv->io(dev, 0, I8255_DATA_C_REG, 0, regbase) << 16); + v = spriv->io(dev, 0, I8255_DATA_A_REG, 0, context); + v |= (spriv->io(dev, 0, I8255_DATA_B_REG, 0, context) << 8); + v |= (spriv->io(dev, 0, I8255_DATA_C_REG, 0, context) << 16); data[1] = v; @@ -94,7 +94,7 @@ static void subdev_8255_do_config(struct comedi_device *dev, struct comedi_subdevice *s) { struct subdev_8255_private *spriv = s->private; - unsigned long regbase = spriv->regbase; + unsigned long context = spriv->context; int config; config = I8255_CTRL_CW; @@ -108,7 +108,7 @@ static void subdev_8255_do_config(struct comedi_device *dev, if (!(s->io_bits & 0xf00000)) config |= I8255_CTRL_C_HI_IO; - spriv->io(dev, 1, I8255_CTRL_REG, config, regbase); + spriv->io(dev, 1, I8255_CTRL_REG, config, context); } static int subdev_8255_insn_config(struct comedi_device *dev, @@ -142,23 +142,19 @@ static int __subdev_8255_init(struct comedi_device *dev, struct comedi_subdevice *s, int (*io)(struct comedi_device *dev, int dir, int port, int data, - unsigned long regbase), - unsigned long regbase, - bool is_mmio) + unsigned long context), + unsigned long context) { struct subdev_8255_private *spriv; + if (!io) + return -EINVAL; + spriv = comedi_alloc_spriv(s, sizeof(*spriv)); if (!spriv) return -ENOMEM; - if (io) - spriv->io = io; - else if (is_mmio) - spriv->io = subdev_8255_mmio; - else - spriv->io = subdev_8255_io; - spriv->regbase = regbase; + spriv->context = context; s->type = COMEDI_SUBD_DIO; s->subdev_flags = SDF_READABLE | SDF_WRITABLE; @@ -174,88 +170,83 @@ static int __subdev_8255_init(struct comedi_device *dev, } /** - * subdev_8255_init - initialize DIO subdevice for driving I/O mapped 8255 + * subdev_8255_io_init - initialize DIO subdevice for driving I/O mapped 8255 * @dev: comedi device owning subdevice * @s: comedi subdevice to initialize - * @io: (optional) register I/O call-back function - * @regbase: offset of 8255 registers from dev->iobase, or call-back context + * @regbase: offset of 8255 registers from dev->iobase * * Initializes a comedi subdevice as a DIO subdevice driving an 8255 chip. * - * If the optional I/O call-back function is provided, its prototype is of - * the following form: - * - * int my_8255_callback(struct comedi_device *dev, int dir, int port, - * int data, unsigned long regbase); - * - * where 'dev', and 'regbase' match the values passed to this function, - * 'port' is the 8255 port number 0 to 3 (including the control port), 'dir' - * is the direction (0 for read, 1 for write) and 'data' is the value to be - * written. It should return 0 if writing or the value read if reading. - * - * If the optional I/O call-back function is not provided, an internal - * call-back function is used which uses consecutive I/O port addresses - * starting at dev->iobase + regbase. - * * Return: -ENOMEM if failed to allocate memory, zero on success. */ -int subdev_8255_init(struct comedi_device *dev, struct comedi_subdevice *s, - int (*io)(struct comedi_device *dev, int dir, int port, - int data, unsigned long regbase), +int subdev_8255_io_init(struct comedi_device *dev, struct comedi_subdevice *s, unsigned long regbase) { - return __subdev_8255_init(dev, s, io, regbase, false); + return __subdev_8255_init(dev, s, subdev_8255_io, regbase); } -EXPORT_SYMBOL_GPL(subdev_8255_init); +EXPORT_SYMBOL_GPL(subdev_8255_io_init); /** * subdev_8255_mm_init - initialize DIO subdevice for driving mmio-mapped 8255 * @dev: comedi device owning subdevice * @s: comedi subdevice to initialize - * @io: (optional) register I/O call-back function - * @regbase: offset of 8255 registers from dev->mmio, or call-back context + * @regbase: offset of 8255 registers from dev->mmio * * Initializes a comedi subdevice as a DIO subdevice driving an 8255 chip. * - * If the optional I/O call-back function is provided, its prototype is of - * the following form: - * - * int my_8255_callback(struct comedi_device *dev, int dir, int port, - * int data, unsigned long regbase); - * - * where 'dev', and 'regbase' match the values passed to this function, - * 'port' is the 8255 port number 0 to 3 (including the control port), 'dir' - * is the direction (0 for read, 1 for write) and 'data' is the value to be - * written. It should return 0 if writing or the value read if reading. - * - * If the optional I/O call-back function is not provided, an internal - * call-back function is used which uses consecutive MMIO virtual addresses - * starting at dev->mmio + regbase. - * * Return: -ENOMEM if failed to allocate memory, zero on success. */ int subdev_8255_mm_init(struct comedi_device *dev, struct comedi_subdevice *s, - int (*io)(struct comedi_device *dev, int dir, int port, - int data, unsigned long regbase), unsigned long regbase) { - return __subdev_8255_init(dev, s, io, regbase, true); + return __subdev_8255_init(dev, s, subdev_8255_mmio, regbase); } EXPORT_SYMBOL_GPL(subdev_8255_mm_init); +/** + * subdev_8255_cb_init - initialize DIO subdevice for driving callback-mapped 8255 + * @dev: comedi device owning subdevice + * @s: comedi subdevice to initialize + * @io: register I/O call-back function + * @context: call-back context + * + * Initializes a comedi subdevice as a DIO subdevice driving an 8255 chip. + * + * The prototype of the I/O call-back function is of the following form: + * + * int my_8255_callback(struct comedi_device *dev, int dir, int port, + * int data, unsigned long context); + * + * where 'dev', and 'context' match the values passed to this function, + * 'port' is the 8255 port number 0 to 3 (including the control port), 'dir' + * is the direction (0 for read, 1 for write) and 'data' is the value to be + * written. It should return 0 if writing or the value read if reading. + * + * + * Return: -ENOMEM if failed to allocate memory, zero on success. + */ +int subdev_8255_cb_init(struct comedi_device *dev, struct comedi_subdevice *s, + int (*io)(struct comedi_device *dev, int dir, int port, + int data, unsigned long context), + unsigned long context) +{ + return __subdev_8255_init(dev, s, io, context); +} +EXPORT_SYMBOL_GPL(subdev_8255_cb_init); + /** * subdev_8255_regbase - get offset of 8255 registers or call-back context * @s: comedi subdevice * - * Returns the 'regbase' parameter that was previously passed to - * subdev_8255_init() or subdev_8255_mm_init() to set up the subdevice. - * Only valid if the subdevice was set up successfully. + * Returns the 'regbase' or 'context' parameter that was previously passed to + * subdev_8255_io_init(), subdev_8255_mm_init(), or subdev_8255_cb_init() to + * set up the subdevice. Only valid if the subdevice was set up successfully. */ unsigned long subdev_8255_regbase(struct comedi_subdevice *s) { struct subdev_8255_private *spriv = s->private; - return spriv->regbase; + return spriv->context; } EXPORT_SYMBOL_GPL(subdev_8255_regbase); diff --git a/drivers/comedi/drivers/daqboard2000.c b/drivers/comedi/drivers/daqboard2000.c index c0a4e1b06fb3..897bf46b95ee 100644 --- a/drivers/comedi/drivers/daqboard2000.c +++ b/drivers/comedi/drivers/daqboard2000.c @@ -738,8 +738,8 @@ static int db2k_auto_attach(struct comedi_device *dev, unsigned long context) return result; s = &dev->subdevices[2]; - return subdev_8255_init(dev, s, db2k_8255_cb, - DB2K_REG_DIO_P2_EXP_IO_8_BIT); + return subdev_8255_cb_init(dev, s, db2k_8255_cb, + DB2K_REG_DIO_P2_EXP_IO_8_BIT); } static void db2k_detach(struct comedi_device *dev) diff --git a/drivers/comedi/drivers/das08.c b/drivers/comedi/drivers/das08.c index 6a3b5411aa90..5d5b9174f88a 100644 --- a/drivers/comedi/drivers/das08.c +++ b/drivers/comedi/drivers/das08.c @@ -429,7 +429,7 @@ int das08_common_attach(struct comedi_device *dev, unsigned long iobase) s = &dev->subdevices[4]; /* 8255 */ if (board->i8255_offset != 0) { - ret = subdev_8255_init(dev, s, NULL, board->i8255_offset); + ret = subdev_8255_io_init(dev, s, board->i8255_offset); if (ret) return ret; } else { diff --git a/drivers/comedi/drivers/das16.c b/drivers/comedi/drivers/das16.c index bfe8811be1b5..4ed56a02150e 100644 --- a/drivers/comedi/drivers/das16.c +++ b/drivers/comedi/drivers/das16.c @@ -1145,7 +1145,7 @@ static int das16_attach(struct comedi_device *dev, struct comedi_devconfig *it) /* 8255 Digital I/O subdevice */ if (board->has_8255) { s = &dev->subdevices[4]; - ret = subdev_8255_init(dev, s, NULL, board->i8255_offset); + ret = subdev_8255_io_init(dev, s, board->i8255_offset); if (ret) return ret; } diff --git a/drivers/comedi/drivers/das16m1.c b/drivers/comedi/drivers/das16m1.c index ff9c5a8897bd..b8ea737ad3d1 100644 --- a/drivers/comedi/drivers/das16m1.c +++ b/drivers/comedi/drivers/das16m1.c @@ -583,7 +583,7 @@ static int das16m1_attach(struct comedi_device *dev, /* Digital I/O subdevice (8255) */ s = &dev->subdevices[3]; - ret = subdev_8255_init(dev, s, NULL, DAS16M1_8255_IOBASE); + ret = subdev_8255_io_init(dev, s, DAS16M1_8255_IOBASE); if (ret) return ret; diff --git a/drivers/comedi/drivers/dmm32at.c b/drivers/comedi/drivers/dmm32at.c index fe023c722aa3..644e3b643c79 100644 --- a/drivers/comedi/drivers/dmm32at.c +++ b/drivers/comedi/drivers/dmm32at.c @@ -599,7 +599,8 @@ static int dmm32at_attach(struct comedi_device *dev, /* Digital I/O subdevice */ s = &dev->subdevices[2]; - return subdev_8255_init(dev, s, dmm32at_8255_io, DMM32AT_8255_IOBASE); + return subdev_8255_cb_init(dev, s, dmm32at_8255_io, + DMM32AT_8255_IOBASE); } static struct comedi_driver dmm32at_driver = { diff --git a/drivers/comedi/drivers/ni_atmio16d.c b/drivers/comedi/drivers/ni_atmio16d.c index 9fa902529a8e..e5e7cc423c87 100644 --- a/drivers/comedi/drivers/ni_atmio16d.c +++ b/drivers/comedi/drivers/ni_atmio16d.c @@ -677,7 +677,7 @@ static int atmio16d_attach(struct comedi_device *dev, /* 8255 subdevice */ s = &dev->subdevices[3]; if (board->has_8255) { - ret = subdev_8255_init(dev, s, NULL, 0x00); + ret = subdev_8255_io_init(dev, s, 0x00); if (ret) return ret; } else { diff --git a/drivers/comedi/drivers/ni_daq_dio24.c b/drivers/comedi/drivers/ni_daq_dio24.c index 487733111023..9419caf02edc 100644 --- a/drivers/comedi/drivers/ni_daq_dio24.c +++ b/drivers/comedi/drivers/ni_daq_dio24.c @@ -45,7 +45,7 @@ static int dio24_auto_attach(struct comedi_device *dev, /* 8255 dio */ s = &dev->subdevices[0]; - return subdev_8255_init(dev, s, NULL, 0x00); + return subdev_8255_io_init(dev, s, 0x00); } static struct comedi_driver driver_dio24 = { diff --git a/drivers/comedi/drivers/ni_labpc_common.c b/drivers/comedi/drivers/ni_labpc_common.c index eb8f6431276a..5d5c1d0e9cb6 100644 --- a/drivers/comedi/drivers/ni_labpc_common.c +++ b/drivers/comedi/drivers/ni_labpc_common.c @@ -1287,9 +1287,9 @@ int labpc_common_attach(struct comedi_device *dev, /* 8255 dio */ s = &dev->subdevices[2]; if (dev->mmio) - ret = subdev_8255_mm_init(dev, s, NULL, DIO_BASE_REG); + ret = subdev_8255_mm_init(dev, s, DIO_BASE_REG); else - ret = subdev_8255_init(dev, s, NULL, DIO_BASE_REG); + ret = subdev_8255_io_init(dev, s, DIO_BASE_REG); if (ret) return ret; diff --git a/drivers/comedi/drivers/ni_mio_common.c b/drivers/comedi/drivers/ni_mio_common.c index d39998565808..638be08b43e4 100644 --- a/drivers/comedi/drivers/ni_mio_common.c +++ b/drivers/comedi/drivers/ni_mio_common.c @@ -6137,8 +6137,8 @@ static int ni_E_init(struct comedi_device *dev, /* 8255 device */ s = &dev->subdevices[NI_8255_DIO_SUBDEV]; if (board->has_8255) { - ret = subdev_8255_init(dev, s, ni_8255_callback, - NI_E_8255_BASE); + ret = subdev_8255_cb_init(dev, s, ni_8255_callback, + NI_E_8255_BASE); if (ret) return ret; } else { diff --git a/drivers/comedi/drivers/pcl724.c b/drivers/comedi/drivers/pcl724.c index 948a0576c9ef..00474710b81f 100644 --- a/drivers/comedi/drivers/pcl724.c +++ b/drivers/comedi/drivers/pcl724.c @@ -124,10 +124,10 @@ static int pcl724_attach(struct comedi_device *dev, s = &dev->subdevices[i]; if (board->is_pet48) { iobase = dev->iobase + (i * 0x1000); - ret = subdev_8255_init(dev, s, pcl724_8255mapped_io, - iobase); + ret = subdev_8255_cb_init(dev, s, pcl724_8255mapped_io, + iobase); } else { - ret = subdev_8255_init(dev, s, NULL, i * I8255_SIZE); + ret = subdev_8255_io_init(dev, s, i * I8255_SIZE); } if (ret) return ret; diff --git a/drivers/comedi/drivers/pcm3724.c b/drivers/comedi/drivers/pcm3724.c index ca8bef54dacc..fb41de3baef8 100644 --- a/drivers/comedi/drivers/pcm3724.c +++ b/drivers/comedi/drivers/pcm3724.c @@ -204,7 +204,7 @@ static int pcm3724_attach(struct comedi_device *dev, for (i = 0; i < dev->n_subdevices; i++) { s = &dev->subdevices[i]; - ret = subdev_8255_init(dev, s, NULL, i * I8255_SIZE); + ret = subdev_8255_io_init(dev, s, i * I8255_SIZE); if (ret) return ret; s->insn_config = subdev_3724_insn_config; diff --git a/include/linux/comedi/comedi_8255.h b/include/linux/comedi/comedi_8255.h index b2a5bc6b3a49..b396fcfbf8b0 100644 --- a/include/linux/comedi/comedi_8255.h +++ b/include/linux/comedi/comedi_8255.h @@ -27,16 +27,17 @@ struct comedi_device; struct comedi_subdevice; -int subdev_8255_init(struct comedi_device *dev, struct comedi_subdevice *s, - int (*io)(struct comedi_device *dev, int dir, int port, - int data, unsigned long regbase), - unsigned long regbase); +int subdev_8255_io_init(struct comedi_device *dev, struct comedi_subdevice *s, + unsigned long regbase); int subdev_8255_mm_init(struct comedi_device *dev, struct comedi_subdevice *s, - int (*io)(struct comedi_device *dev, int dir, int port, - int data, unsigned long regbase), unsigned long regbase); +int subdev_8255_cb_init(struct comedi_device *dev, struct comedi_subdevice *s, + int (*io)(struct comedi_device *dev, int dir, int port, + int data, unsigned long context), + unsigned long context); + unsigned long subdev_8255_regbase(struct comedi_subdevice *s); #endif From 7187a0939a1773e6a2663a02a6c456047a5e6289 Mon Sep 17 00:00:00 2001 From: Ian Abbott Date: Wed, 13 Sep 2023 18:07:06 +0100 Subject: [PATCH 162/326] comedi: comedi_8255: Conditionally remove I/O port support In a future patch, the port I/O functions (`inb()`, `outb()`, and friends will only be declared in the `HAS_IOPORT` configuration option is enabled. The comedi_8255 module supports both port I/O and memory-mapped I/O. Conditionally compile the parts of the module that use port I/O if and only if the `CONFIG_HAS_IOPORT` macro is defined so that it can still be built if the port I/O functions have not been declared. If the `CONFIG_HAS_IOPORT` macro is undefined, replace the GPL-exported `subdev_8255_io_init()` function with a dummy static inline version that just returns `-ENXIO`. Cc: Arnd Bergmann Cc: Niklas Schnelle Signed-off-by: Ian Abbott Link: https://lore.kernel.org/r/20230913170712.111719-8-abbotti@mev.co.uk Signed-off-by: Greg Kroah-Hartman --- drivers/comedi/drivers/comedi_8255.c | 8 ++++++++ include/linux/comedi/comedi_8255.h | 11 +++++++++++ 2 files changed, 19 insertions(+) diff --git a/drivers/comedi/drivers/comedi_8255.c b/drivers/comedi/drivers/comedi_8255.c index 28fd9d8c95cc..e4974b508328 100644 --- a/drivers/comedi/drivers/comedi_8255.c +++ b/drivers/comedi/drivers/comedi_8255.c @@ -38,6 +38,8 @@ struct subdev_8255_private { unsigned long context); }; +#ifdef CONFIG_HAS_IOPORT + static int subdev_8255_io(struct comedi_device *dev, int dir, int port, int data, unsigned long regbase) { @@ -48,6 +50,8 @@ static int subdev_8255_io(struct comedi_device *dev, return inb(dev->iobase + regbase + port); } +#endif /* CONFIG_HAS_IOPORT */ + static int subdev_8255_mmio(struct comedi_device *dev, int dir, int port, int data, unsigned long regbase) { @@ -169,6 +173,8 @@ static int __subdev_8255_init(struct comedi_device *dev, return 0; } +#ifdef CONFIG_HAS_IOPORT + /** * subdev_8255_io_init - initialize DIO subdevice for driving I/O mapped 8255 * @dev: comedi device owning subdevice @@ -186,6 +192,8 @@ int subdev_8255_io_init(struct comedi_device *dev, struct comedi_subdevice *s, } EXPORT_SYMBOL_GPL(subdev_8255_io_init); +#endif /* CONFIG_HAS_IOPORT */ + /** * subdev_8255_mm_init - initialize DIO subdevice for driving mmio-mapped 8255 * @dev: comedi device owning subdevice diff --git a/include/linux/comedi/comedi_8255.h b/include/linux/comedi/comedi_8255.h index b396fcfbf8b0..d24a69da389b 100644 --- a/include/linux/comedi/comedi_8255.h +++ b/include/linux/comedi/comedi_8255.h @@ -10,6 +10,8 @@ #ifndef _COMEDI_8255_H #define _COMEDI_8255_H +#include + #define I8255_SIZE 0x04 #define I8255_DATA_A_REG 0x00 @@ -27,8 +29,17 @@ struct comedi_device; struct comedi_subdevice; +#ifdef CONFIG_HAS_IOPORT int subdev_8255_io_init(struct comedi_device *dev, struct comedi_subdevice *s, unsigned long regbase); +#else +static inline int subdev_8255_io_init(struct comedi_device *dev, + struct comedi_subdevice *s, + unsigned long regbase) +{ + return -ENXIO; +} +#endif int subdev_8255_mm_init(struct comedi_device *dev, struct comedi_subdevice *s, unsigned long regbase); From a7b9ffd8c208d5911ba44a31e65d7c40400bbebd Mon Sep 17 00:00:00 2001 From: Ian Abbott Date: Wed, 13 Sep 2023 18:07:07 +0100 Subject: [PATCH 163/326] comedi: ni_labpc_common: Conditionally remove I/O port support In a future patch, the port I/O functions (`inb()`, `outb()`, and friends will only be declared in the `HAS_IOPORT` configuration option is enabled. The ni_labpc_common module is used by the ni_labpc module (for ISA cards), the ni_labpc_cs module (for PCMCIA cards), and the ni_labpc_pci module (for PCI cards). The ISA and PCMCIA cards use port I/O and the PCI cards use memory-mapped I/O. Conditionally compile the parts of the module that use the port I/O functions so they are compiled if and only if the `CONFIG_HAS_IOPORT` macro is defined, so that the module can be built if the port I/O functions have not been declared. Add a run-time check in the `labpc_common_attach()` to return an error if the comedi device wants to use port I/O when the `CONFIG_HAS_IOPORT` macro is undefined. The changes allow the module to be built even if the port I/O functions have not been declared. Cc: Arnd Bergmann Cc: Niklas Schnelle Signed-off-by: Ian Abbott Link: https://lore.kernel.org/r/20230913170712.111719-9-abbotti@mev.co.uk Signed-off-by: Greg Kroah-Hartman --- drivers/comedi/drivers/ni_labpc_common.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/drivers/comedi/drivers/ni_labpc_common.c b/drivers/comedi/drivers/ni_labpc_common.c index 5d5c1d0e9cb6..7e0ce0ce0adf 100644 --- a/drivers/comedi/drivers/ni_labpc_common.c +++ b/drivers/comedi/drivers/ni_labpc_common.c @@ -78,6 +78,9 @@ static const struct comedi_lrange range_labpc_ao = { * functions that do inb/outb and readb/writeb so we can use * function pointers to decide which to use */ + +#ifdef CONFIG_HAS_IOPORT + static unsigned int labpc_inb(struct comedi_device *dev, unsigned long reg) { return inb(dev->iobase + reg); @@ -89,6 +92,8 @@ static void labpc_outb(struct comedi_device *dev, outb(byte, dev->iobase + reg); } +#endif /* CONFIG_HAS_IOPORT */ + static unsigned int labpc_readb(struct comedi_device *dev, unsigned long reg) { return readb(dev->mmio + reg); @@ -1200,8 +1205,12 @@ int labpc_common_attach(struct comedi_device *dev, devpriv->read_byte = labpc_readb; devpriv->write_byte = labpc_writeb; } else { +#ifdef CONFIG_HAS_IOPORT devpriv->read_byte = labpc_inb; devpriv->write_byte = labpc_outb; +#else + return -ENXIO; +#endif } /* initialize board's command registers */ From 4e1bd6724b854808aa3b94f17f5c27da59a34ff4 Mon Sep 17 00:00:00 2001 From: Ian Abbott Date: Wed, 13 Sep 2023 18:07:08 +0100 Subject: [PATCH 164/326] comedi: ni_mio_common: Conditionally use I/O port or MMIO In a future patch, the port I/O functions (`inb()`, `outb()`, and friends will only be declared in the `HAS_IOPORT` configuration option is enabled. The "ni_mio_common.c" file contains calls to both port I/O functions and memory-mapped I/O functions. The file is `#include`d by "ni_atmio.c", "ni_mio_cs.c", and "ni_pcimio.c" for the ni_atmio, ni_mio_cs, and ni_pcimio modules, respectively. Only "ni_pcimio.c" defines the `PCIDMA` macro before including "ni_mio_common.c" and various bits of code in "ni_mio_common.c" is conditionally compiled according to whether that macro is defined or not. Currently, the port I/O function calls are compiled in regardless of whether the `PCIDMA` macro is defined or not. However, the fact is that the ni_atmio and ni_mio_cs modules will never call the memory-mapped I/O functions, and the ni_pcimio module will never call the port I/O functions. Calls to the port I/O and memory-mapped I/O functions is confined to the `ni_writel()`, `ni_writew()`, `ni_writeb()`, `ni_readl()`, `ni_readw()`, and `ni_readb()` functions which do a run-time test to decide whether to call the port I/O functions or the memory-mapped I/O functions. Conditionally compile two variants of the functions so they only call the port I/O functions if the `PCIDMA` macro is undefined (for the ni_atmio and ni_mio_cs modules), and only call the memory-mapped I/O functions if the `PCIDMA` macro is defined (for the ni_pcimio module). Add a run-time check in the `ni_E_init()` function to return an error if the comedi device has been set up to use port I/O if `PCIDMA` is defined, or has been set up to use memory-mapped I/O if `PCIDMA` is not defined. The changes make it possible to build the ni_pcimio module even if the port I/O functions have not been declared. (The ni_atmio and ni_mio_cs modules do still require the port I/O functions to be declared.) Cc: Arnd Bergmann Cc: Niklas Schnelle Signed-off-by: Ian Abbott Link: https://lore.kernel.org/r/20230913170712.111719-10-abbotti@mev.co.uk Signed-off-by: Greg Kroah-Hartman --- drivers/comedi/drivers/ni_mio_common.c | 70 ++++++++++++++++++-------- 1 file changed, 50 insertions(+), 20 deletions(-) diff --git a/drivers/comedi/drivers/ni_mio_common.c b/drivers/comedi/drivers/ni_mio_common.c index 638be08b43e4..980f309d6de7 100644 --- a/drivers/comedi/drivers/ni_mio_common.c +++ b/drivers/comedi/drivers/ni_mio_common.c @@ -46,6 +46,12 @@ #include #include "mite.h" +#ifdef PCIDMA +#define IS_PCIMIO 1 +#else +#define IS_PCIMIO 0 +#endif + /* A timeout count */ #define NI_TIMEOUT 1000 @@ -219,54 +225,72 @@ enum timebase_nanoseconds { static const int num_adc_stages_611x = 3; +#ifdef PCIDMA + static void ni_writel(struct comedi_device *dev, unsigned int data, int reg) { - if (dev->mmio) - writel(data, dev->mmio + reg); - else - outl(data, dev->iobase + reg); + writel(data, dev->mmio + reg); } static void ni_writew(struct comedi_device *dev, unsigned int data, int reg) { - if (dev->mmio) - writew(data, dev->mmio + reg); - else - outw(data, dev->iobase + reg); + writew(data, dev->mmio + reg); } static void ni_writeb(struct comedi_device *dev, unsigned int data, int reg) { - if (dev->mmio) - writeb(data, dev->mmio + reg); - else - outb(data, dev->iobase + reg); + writeb(data, dev->mmio + reg); } static unsigned int ni_readl(struct comedi_device *dev, int reg) { - if (dev->mmio) - return readl(dev->mmio + reg); + return readl(dev->mmio + reg); +} +static unsigned int ni_readw(struct comedi_device *dev, int reg) +{ + return readw(dev->mmio + reg); +} + +static unsigned int ni_readb(struct comedi_device *dev, int reg) +{ + return readb(dev->mmio + reg); +} + +#else /* PCIDMA */ + +static void ni_writel(struct comedi_device *dev, unsigned int data, int reg) +{ + outl(data, dev->iobase + reg); +} + +static void ni_writew(struct comedi_device *dev, unsigned int data, int reg) +{ + outw(data, dev->iobase + reg); +} + +static void ni_writeb(struct comedi_device *dev, unsigned int data, int reg) +{ + outb(data, dev->iobase + reg); +} + +static unsigned int ni_readl(struct comedi_device *dev, int reg) +{ return inl(dev->iobase + reg); } static unsigned int ni_readw(struct comedi_device *dev, int reg) { - if (dev->mmio) - return readw(dev->mmio + reg); - return inw(dev->iobase + reg); } static unsigned int ni_readb(struct comedi_device *dev, int reg) { - if (dev->mmio) - return readb(dev->mmio + reg); - return inb(dev->iobase + reg); } +#endif /* PCIDMA */ + /* * We automatically take advantage of STC registers that can be * read/written directly in the I/O space of the board. @@ -5977,6 +6001,12 @@ static int ni_E_init(struct comedi_device *dev, int i; const char *dev_family = devpriv->is_m_series ? "ni_mseries" : "ni_eseries"; + if (!IS_PCIMIO != !dev->mmio) { + dev_err(dev->class_dev, + "%s: bug! %s device not supported.\n", + KBUILD_MODNAME, board->name); + return -ENXIO; + } /* prepare the device for globally-named routes. */ if (ni_assign_device_routes(dev_family, board->name, From 772dcada0e733a567ad90cca7165c5fef2a1171c Mon Sep 17 00:00:00 2001 From: Ian Abbott Date: Wed, 13 Sep 2023 18:07:09 +0100 Subject: [PATCH 165/326] comedi: amplc_dio200_pci: Conditionally remove devices that use port I/O In a future patch, the port I/O functions (`inb()`, `outb()`, and friends will only be declared in the `HAS_IOPORT` configuration option is enabled. The amplc_dio200_pci module supports various Amplicon PCI and PCI Express devices. Some of the supported devices (the PCI ones) use port I/O, and some of them (the PCIe ones) only use memory-mapped I/O. Conditionally compile in support for the devices that need port I/O if and only if the `CONFIG_HAS_IOPORT` macro is defined. Add a run-time check in `dio200_pci_auto_attach()` to return an error if the device actually requires port I/O (based on the PCI BAR resource flags) but the `HAS_IOPORT` configuration option is not enabled. Cc: Arnd Bergmann Cc: Niklas Schnelle Signed-off-by: Ian Abbott Link: https://lore.kernel.org/r/20230913170712.111719-11-abbotti@mev.co.uk Signed-off-by: Greg Kroah-Hartman --- drivers/comedi/drivers/amplc_dio200_pci.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/drivers/comedi/drivers/amplc_dio200_pci.c b/drivers/comedi/drivers/amplc_dio200_pci.c index 527994d82a1f..cb5b328a28e3 100644 --- a/drivers/comedi/drivers/amplc_dio200_pci.c +++ b/drivers/comedi/drivers/amplc_dio200_pci.c @@ -223,14 +223,17 @@ */ enum dio200_pci_model { +#ifdef CONFIG_HAS_IOPORT pci215_model, pci272_model, +#endif /* CONFIG_HAS_IOPORT */ pcie215_model, pcie236_model, pcie296_model }; static const struct dio200_board dio200_pci_boards[] = { +#ifdef CONFIG_HAS_IOPORT [pci215_model] = { .name = "pci215", .mainbar = 2, @@ -252,6 +255,7 @@ static const struct dio200_board dio200_pci_boards[] = { .sdinfo = { 0x00, 0x08, 0x10, 0x3f }, .has_int_sce = true, }, +#endif /* CONFIG_HAS_IOPORT */ [pcie215_model] = { .name = "pcie215", .mainbar = 1, @@ -364,8 +368,12 @@ static int dio200_pci_auto_attach(struct comedi_device *dev, "error! cannot remap registers\n"); return -ENOMEM; } - } else { + } else if (IS_ENABLED(CONFIG_HAS_IOPORT)) { dev->iobase = pci_resource_start(pci_dev, bar); + } else { + dev_err(dev->class_dev, + "error! need I/O port support\n"); + return -ENXIO; } if (board->is_pcie) { @@ -385,8 +393,10 @@ static struct comedi_driver dio200_pci_comedi_driver = { }; static const struct pci_device_id dio200_pci_table[] = { +#ifdef CONFIG_HAS_IOPORT { PCI_VDEVICE(AMPLICON, 0x000b), pci215_model }, { PCI_VDEVICE(AMPLICON, 0x000a), pci272_model }, +#endif /* CONFIG_HAS_IOPORT */ { PCI_VDEVICE(AMPLICON, 0x0011), pcie236_model }, { PCI_VDEVICE(AMPLICON, 0x0012), pcie215_model }, { PCI_VDEVICE(AMPLICON, 0x0014), pcie296_model }, From a3f2b80847e2b4dd7180872e69b84d515174c236 Mon Sep 17 00:00:00 2001 From: Ian Abbott Date: Wed, 13 Sep 2023 18:07:10 +0100 Subject: [PATCH 166/326] comedi: amplc_dio200_common: Refactor register access functions The `dio200_read8()`, `dio200_write8()`, `dio200_read32()` and `dio200_write32()` functions apply a right-shift to the register offset for some devices and then perform the actual register access. Factor the register access part out to new functions `dio200___read8()`, `dio200___write8()`, `dio200___read32()`, and `dio200___write32()`. This will reduce duplicated code in a subsequent patch that will conditionally compile support for port I/O as part of the `HAS_IOPORT` changes. Cc: Arnd Bergmann Cc: Niklas Schnelle Signed-off-by: Ian Abbott Link: https://lore.kernel.org/r/20230913170712.111719-12-abbotti@mev.co.uk Signed-off-by: Greg Kroah-Hartman --- drivers/comedi/drivers/amplc_dio200_common.c | 52 ++++++++++++++------ 1 file changed, 38 insertions(+), 14 deletions(-) diff --git a/drivers/comedi/drivers/amplc_dio200_common.c b/drivers/comedi/drivers/amplc_dio200_common.c index 19166cb26f5e..e6d63e89e7bf 100644 --- a/drivers/comedi/drivers/amplc_dio200_common.c +++ b/drivers/comedi/drivers/amplc_dio200_common.c @@ -86,6 +86,40 @@ struct dio200_subdev_intr { unsigned int active:1; }; +static unsigned char dio200___read8(struct comedi_device *dev, + unsigned int offset) +{ + if (dev->mmio) + return readb(dev->mmio + offset); + return inb(dev->iobase + offset); +} + +static void dio200___write8(struct comedi_device *dev, + unsigned int offset, unsigned char val) +{ + if (dev->mmio) + writeb(val, dev->mmio + offset); + else + outb(val, dev->iobase + offset); +} + +static unsigned int dio200___read32(struct comedi_device *dev, + unsigned int offset) +{ + if (dev->mmio) + return readl(dev->mmio + offset); + return inl(dev->iobase + offset); +} + +static void dio200___write32(struct comedi_device *dev, + unsigned int offset, unsigned int val) +{ + if (dev->mmio) + writel(val, dev->mmio + offset); + else + outl(val, dev->iobase + offset); +} + static unsigned char dio200_read8(struct comedi_device *dev, unsigned int offset) { @@ -94,9 +128,7 @@ static unsigned char dio200_read8(struct comedi_device *dev, if (board->is_pcie) offset <<= 3; - if (dev->mmio) - return readb(dev->mmio + offset); - return inb(dev->iobase + offset); + return dio200___read8(dev, offset); } static void dio200_write8(struct comedi_device *dev, @@ -107,10 +139,7 @@ static void dio200_write8(struct comedi_device *dev, if (board->is_pcie) offset <<= 3; - if (dev->mmio) - writeb(val, dev->mmio + offset); - else - outb(val, dev->iobase + offset); + dio200___write8(dev, offset, val); } static unsigned int dio200_read32(struct comedi_device *dev, @@ -121,9 +150,7 @@ static unsigned int dio200_read32(struct comedi_device *dev, if (board->is_pcie) offset <<= 3; - if (dev->mmio) - return readl(dev->mmio + offset); - return inl(dev->iobase + offset); + return dio200___read32(dev, offset); } static void dio200_write32(struct comedi_device *dev, @@ -134,10 +161,7 @@ static void dio200_write32(struct comedi_device *dev, if (board->is_pcie) offset <<= 3; - if (dev->mmio) - writel(val, dev->mmio + offset); - else - outl(val, dev->iobase + offset); + dio200___write32(dev, offset, val); } static unsigned int dio200_subdev_8254_offset(struct comedi_device *dev, From 88dd4797746ff93093728a48dd9a88cff95f4ca0 Mon Sep 17 00:00:00 2001 From: Ian Abbott Date: Wed, 13 Sep 2023 18:07:11 +0100 Subject: [PATCH 167/326] comedi: amplc_dio200_common: Conditionally remove I/O port support In a future patch, the port I/O functions (`inb()`, `outb()`, and friends will only be declared in the `HAS_IOPORT` configuration option is enabled. The amplc_dio200_common module is used by the amplc_dio200 module (for ISA cards) and the amplc_dio200_pci module (for PCI and PCI Express cards). It supports both port I/O and memory-mapped I/O. Port I/O and memory-mapped I/O is confined to the `dio200___read8()`, `dio200___read32()`, `dio200___write8()` and `dio200___write32()` functions. Conditionally compile two versions of those functions. If the `CONFIG_HAS_IOPORT` macro is defined, call either the port I/O or memory mapped I/O functions depending on the `mmio` member of the `struct comedi_device`. If the `CONFIG_HAS_IOPORT` macro is undefined only call the memory-mapped I/O functions. Add a run-time check to `amplc_dio200_common_attach()` to return an error if the device wants to use port I/O when the `CONFIG_HAS_IOPORT` macro is undefined. The changes allow the module to be built even if the port I/O functions have not been declared. Cc: Arnd Bergmann Cc: Niklas Schnelle Signed-off-by: Ian Abbott Link: https://lore.kernel.org/r/20230913170712.111719-13-abbotti@mev.co.uk Signed-off-by: Greg Kroah-Hartman --- drivers/comedi/drivers/amplc_dio200_common.c | 36 ++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/drivers/comedi/drivers/amplc_dio200_common.c b/drivers/comedi/drivers/amplc_dio200_common.c index e6d63e89e7bf..b1a9b4c4a185 100644 --- a/drivers/comedi/drivers/amplc_dio200_common.c +++ b/drivers/comedi/drivers/amplc_dio200_common.c @@ -86,6 +86,8 @@ struct dio200_subdev_intr { unsigned int active:1; }; +#ifdef CONFIG_HAS_IOPORT + static unsigned char dio200___read8(struct comedi_device *dev, unsigned int offset) { @@ -120,6 +122,34 @@ static void dio200___write32(struct comedi_device *dev, outl(val, dev->iobase + offset); } +#else /* CONFIG_HAS_IOPORT */ + +static unsigned char dio200___read8(struct comedi_device *dev, + unsigned int offset) +{ + return readb(dev->mmio + offset); +} + +static void dio200___write8(struct comedi_device *dev, + unsigned int offset, unsigned char val) +{ + writeb(val, dev->mmio + offset); +} + +static unsigned int dio200___read32(struct comedi_device *dev, + unsigned int offset) +{ + return readl(dev->mmio + offset); +} + +static void dio200___write32(struct comedi_device *dev, + unsigned int offset, unsigned int val) +{ + writel(val, dev->mmio + offset); +} + +#endif /* CONFIG_HAS_IOPORT */ + static unsigned char dio200_read8(struct comedi_device *dev, unsigned int offset) { @@ -803,6 +833,12 @@ int amplc_dio200_common_attach(struct comedi_device *dev, unsigned int irq, unsigned int n; int ret; + if (!IS_ENABLED(CONFIG_HAS_IOPORT) && !dev->mmio) { + dev_err(dev->class_dev, + "error! need I/O port support\n"); + return -ENXIO; + } + ret = comedi_alloc_subdevices(dev, board->n_subdevs); if (ret) return ret; From e6c1ccaa711aeca0191f9d9f036e688a2c52ab8c Mon Sep 17 00:00:00 2001 From: Ian Abbott Date: Wed, 13 Sep 2023 18:07:12 +0100 Subject: [PATCH 168/326] comedi: add HAS_IOPORT dependencies again In a future patch HAS_IOPORT=n will result in inb()/outb() and friends not being declared. We thus need to add HAS_IOPORT as dependency for those drivers using them. This was previously done in commit b5c75b68b7de ("comedi: add HAS_IOPORT dependencies"), but that has been reverted because it made it impossible to select configuration options for several comedi drivers. This is a do-over that avoids that. Since the original patch, modifications have been made to various comedi modules so that they can still be built even if the port I/O functions have not been declared, so the configuration options for building those modules no longer need to depend on HAS_IOPORT. Make the COMEDI_ISA_DRIVERS menu option (which allows configuration options for ISA and PC/104 drivers to be selected) depend on HAS_IOPORT, and also depend on ISA || ISA_BUS || PC104. Co-developed-by: Arnd Bergmann Signed-off-by: Arnd Bergmann Co-developed-by: Niklas Schnelle Signed-off-by: Niklas Schnelle Cc: Arnd Bergmann Cc: Niklas Schnelle Signed-off-by: Ian Abbott Link: https://lore.kernel.org/r/20230913170712.111719-14-abbotti@mev.co.uk Signed-off-by: Greg Kroah-Hartman --- drivers/comedi/Kconfig | 44 +++++++++++++++++++++++++++++++++++++++++- 1 file changed, 43 insertions(+), 1 deletion(-) diff --git a/drivers/comedi/Kconfig b/drivers/comedi/Kconfig index 536101f68e0f..93c68a40a17b 100644 --- a/drivers/comedi/Kconfig +++ b/drivers/comedi/Kconfig @@ -67,6 +67,7 @@ config COMEDI_TEST config COMEDI_PARPORT tristate "Parallel port support" + depends on HAS_IOPORT help Enable support for the standard parallel port. A cheap and easy way to get a few more digital I/O lines. Steal @@ -79,6 +80,7 @@ config COMEDI_PARPORT config COMEDI_SSV_DNP tristate "SSV Embedded Systems DIL/Net-PC support" depends on X86_32 || COMPILE_TEST + depends on HAS_IOPORT help Enable support for SSV Embedded Systems DIL/Net-PC @@ -89,6 +91,8 @@ endif # COMEDI_MISC_DRIVERS menuconfig COMEDI_ISA_DRIVERS bool "Comedi ISA and PC/104 drivers" + depends on ISA || ISA_BUS || PC104 + depends on HAS_IOPORT help Enable comedi ISA and PC/104 drivers to be built @@ -589,6 +593,7 @@ config COMEDI_8255_PCI config COMEDI_ADDI_WATCHDOG tristate + depends on HAS_IOPORT help Provides support for the watchdog subdevice found on many ADDI-DATA boards. This module will be automatically selected when needed. The @@ -596,6 +601,7 @@ config COMEDI_ADDI_WATCHDOG config COMEDI_ADDI_APCI_1032 tristate "ADDI-DATA APCI_1032 support" + depends on HAS_IOPORT help Enable support for ADDI-DATA APCI_1032 cards @@ -604,6 +610,7 @@ config COMEDI_ADDI_APCI_1032 config COMEDI_ADDI_APCI_1500 tristate "ADDI-DATA APCI_1500 support" + depends on HAS_IOPORT help Enable support for ADDI-DATA APCI_1500 cards @@ -612,6 +619,7 @@ config COMEDI_ADDI_APCI_1500 config COMEDI_ADDI_APCI_1516 tristate "ADDI-DATA APCI-1016/1516/2016 support" + depends on HAS_IOPORT select COMEDI_ADDI_WATCHDOG help Enable support for ADDI-DATA APCI-1016, APCI-1516 and APCI-2016 boards. @@ -623,6 +631,7 @@ config COMEDI_ADDI_APCI_1516 config COMEDI_ADDI_APCI_1564 tristate "ADDI-DATA APCI_1564 support" + depends on HAS_IOPORT select COMEDI_ADDI_WATCHDOG help Enable support for ADDI-DATA APCI_1564 cards @@ -632,6 +641,7 @@ config COMEDI_ADDI_APCI_1564 config COMEDI_ADDI_APCI_16XX tristate "ADDI-DATA APCI_16xx support" + depends on HAS_IOPORT help Enable support for ADDI-DATA APCI_16xx cards @@ -640,6 +650,7 @@ config COMEDI_ADDI_APCI_16XX config COMEDI_ADDI_APCI_2032 tristate "ADDI-DATA APCI_2032 support" + depends on HAS_IOPORT select COMEDI_ADDI_WATCHDOG help Enable support for ADDI-DATA APCI_2032 cards @@ -649,6 +660,7 @@ config COMEDI_ADDI_APCI_2032 config COMEDI_ADDI_APCI_2200 tristate "ADDI-DATA APCI_2200 support" + depends on HAS_IOPORT select COMEDI_ADDI_WATCHDOG help Enable support for ADDI-DATA APCI_2200 cards @@ -658,6 +670,7 @@ config COMEDI_ADDI_APCI_2200 config COMEDI_ADDI_APCI_3120 tristate "ADDI-DATA APCI_3120/3001 support" + depends on HAS_IOPORT depends on HAS_DMA help Enable support for ADDI-DATA APCI_3120/3001 cards @@ -667,6 +680,7 @@ config COMEDI_ADDI_APCI_3120 config COMEDI_ADDI_APCI_3501 tristate "ADDI-DATA APCI_3501 support" + depends on HAS_IOPORT help Enable support for ADDI-DATA APCI_3501 cards @@ -675,6 +689,7 @@ config COMEDI_ADDI_APCI_3501 config COMEDI_ADDI_APCI_3XXX tristate "ADDI-DATA APCI_3xxx support" + depends on HAS_IOPORT help Enable support for ADDI-DATA APCI_3xxx cards @@ -683,6 +698,7 @@ config COMEDI_ADDI_APCI_3XXX config COMEDI_ADL_PCI6208 tristate "ADLink PCI-6208A support" + depends on HAS_IOPORT help Enable support for ADLink PCI-6208A cards @@ -691,6 +707,7 @@ config COMEDI_ADL_PCI6208 config COMEDI_ADL_PCI7X3X tristate "ADLink PCI-723X/743X isolated digital i/o board support" + depends on HAS_IOPORT help Enable support for ADlink PCI-723X/743X isolated digital i/o boards. Supported boards include the 32-channel PCI-7230 (16 in/16 out), @@ -702,6 +719,7 @@ config COMEDI_ADL_PCI7X3X config COMEDI_ADL_PCI8164 tristate "ADLink PCI-8164 4 Axes Motion Control board support" + depends on HAS_IOPORT help Enable support for ADlink PCI-8164 4 Axes Motion Control board @@ -710,6 +728,7 @@ config COMEDI_ADL_PCI8164 config COMEDI_ADL_PCI9111 tristate "ADLink PCI-9111HR support" + depends on HAS_IOPORT select COMEDI_8254 help Enable support for ADlink PCI9111 cards @@ -719,6 +738,7 @@ config COMEDI_ADL_PCI9111 config COMEDI_ADL_PCI9118 tristate "ADLink PCI-9118DG, PCI-9118HG, PCI-9118HR support" + depends on HAS_IOPORT depends on HAS_DMA select COMEDI_8254 help @@ -729,6 +749,7 @@ config COMEDI_ADL_PCI9118 config COMEDI_ADV_PCI1710 tristate "Advantech PCI-171x and PCI-1731 support" + depends on HAS_IOPORT select COMEDI_8254 help Enable support for Advantech PCI-1710, PCI-1710HG, PCI-1711, @@ -739,6 +760,7 @@ config COMEDI_ADV_PCI1710 config COMEDI_ADV_PCI1720 tristate "Advantech PCI-1720 support" + depends on HAS_IOPORT help Enable support for Advantech PCI-1720 Analog Output board. @@ -747,6 +769,7 @@ config COMEDI_ADV_PCI1720 config COMEDI_ADV_PCI1723 tristate "Advantech PCI-1723 support" + depends on HAS_IOPORT help Enable support for Advantech PCI-1723 cards @@ -755,6 +778,7 @@ config COMEDI_ADV_PCI1723 config COMEDI_ADV_PCI1724 tristate "Advantech PCI-1724U support" + depends on HAS_IOPORT help Enable support for Advantech PCI-1724U cards. These are 32-channel analog output cards with voltage and current loop output ranges and @@ -765,6 +789,7 @@ config COMEDI_ADV_PCI1724 config COMEDI_ADV_PCI1760 tristate "Advantech PCI-1760 support" + depends on HAS_IOPORT help Enable support for Advantech PCI-1760 board. @@ -773,6 +798,7 @@ config COMEDI_ADV_PCI1760 config COMEDI_ADV_PCI_DIO tristate "Advantech PCI DIO card support" + depends on HAS_IOPORT select COMEDI_8254 select COMEDI_8255 help @@ -796,6 +822,7 @@ config COMEDI_AMPLC_DIO200_PCI config COMEDI_AMPLC_PC236_PCI tristate "Amplicon PCI236 DIO board support" + depends on HAS_IOPORT select COMEDI_AMPLC_PC236 help Enable support for Amplicon PCI236 DIO board. @@ -805,6 +832,7 @@ config COMEDI_AMPLC_PC236_PCI config COMEDI_AMPLC_PC263_PCI tristate "Amplicon PCI263 relay board support" + depends on HAS_IOPORT help Enable support for Amplicon PCI263 relay board. This is a PCI board with 16 reed relay output channels. @@ -814,6 +842,7 @@ config COMEDI_AMPLC_PC263_PCI config COMEDI_AMPLC_PCI224 tristate "Amplicon PCI224 and PCI234 support" + depends on HAS_IOPORT select COMEDI_8254 help Enable support for Amplicon PCI224 and PCI234 AO boards @@ -823,6 +852,7 @@ config COMEDI_AMPLC_PCI224 config COMEDI_AMPLC_PCI230 tristate "Amplicon PCI230 and PCI260 support" + depends on HAS_IOPORT select COMEDI_8254 select COMEDI_8255 help @@ -834,6 +864,7 @@ config COMEDI_AMPLC_PCI230 config COMEDI_CONTEC_PCI_DIO tristate "Contec PIO1616L digital I/O board support" + depends on HAS_IOPORT help Enable support for the Contec PIO1616L digital I/O board @@ -842,6 +873,7 @@ config COMEDI_CONTEC_PCI_DIO config COMEDI_DAS08_PCI tristate "DAS-08 PCI support" + depends on HAS_IOPORT select COMEDI_DAS08 help Enable support for PCI DAS-08 cards. @@ -861,6 +893,7 @@ config COMEDI_DT3000 config COMEDI_DYNA_PCI10XX tristate "Dynalog PCI DAQ series support" + depends on HAS_IOPORT help Enable support for Dynalog PCI DAQ series PCI-1050 @@ -911,6 +944,7 @@ config COMEDI_JR3_PCI config COMEDI_KE_COUNTER tristate "Kolter-Electronic PCI Counter 1 card support" + depends on HAS_IOPORT help Enable support for Kolter-Electronic PCI Counter 1 cards @@ -929,6 +963,7 @@ config COMEDI_CB_PCIDAS64 config COMEDI_CB_PCIDAS tristate "MeasurementComputing PCI-DAS support" + depends on HAS_IOPORT select COMEDI_8254 select COMEDI_8255 help @@ -942,6 +977,7 @@ config COMEDI_CB_PCIDAS config COMEDI_CB_PCIDDA tristate "MeasurementComputing PCI-DDA series support" + depends on HAS_IOPORT select COMEDI_8255 help Enable support for ComputerBoards/MeasurementComputing PCI-DDA @@ -953,6 +989,7 @@ config COMEDI_CB_PCIDDA config COMEDI_CB_PCIMDAS tristate "MeasurementComputing PCIM-DAS1602/16, PCIe-DAS1602/16 support" + depends on HAS_IOPORT select COMEDI_8254 select COMEDI_8255 help @@ -964,6 +1001,7 @@ config COMEDI_CB_PCIMDAS config COMEDI_CB_PCIMDDA tristate "MeasurementComputing PCIM-DDA06-16 support" + depends on HAS_IOPORT select COMEDI_8255 help Enable support for ComputerBoards/MeasurementComputing PCIM-DDA06-16 @@ -973,6 +1011,7 @@ config COMEDI_CB_PCIMDDA config COMEDI_ME4000 tristate "Meilhaus ME-4000 support" + depends on HAS_IOPORT select COMEDI_8254 help Enable support for Meilhaus PCI data acquisition cards @@ -1102,7 +1141,7 @@ endif # COMEDI_PCI_DRIVERS menuconfig COMEDI_PCMCIA_DRIVERS tristate "Comedi PCMCIA drivers" - depends on PCMCIA + depends on PCMCIA && HAS_IOPORT help Enable support for comedi PCMCIA drivers. @@ -1253,6 +1292,7 @@ config COMEDI_8255 config COMEDI_8255_SA tristate "Standalone 8255 support" + depends on HAS_IOPORT select COMEDI_8255 help Enable support for 8255 digital I/O as a standalone driver. @@ -1289,10 +1329,12 @@ config COMEDI_AMPLC_DIO200 config COMEDI_AMPLC_PC236 tristate + depends on HAS_IOPORT select COMEDI_8255 config COMEDI_DAS08 tristate + depends on HAS_IOPORT select COMEDI_8254 select COMEDI_8255 From 77f048bcbf07f7dc961f3b2b7815038b5405ec60 Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Sat, 30 Sep 2023 11:14:47 +0200 Subject: [PATCH 169/326] comedi: Annotate struct comedi_lrange with __counted_by Prepare for the coming implementation by GCC and Clang of the __counted_by attribute. Flexible array members annotated with __counted_by can have their accesses bounds-checked at run-time checking via CONFIG_UBSAN_BOUNDS (for array indexing) and CONFIG_FORTIFY_SOURCE (for strcpy/memcpy-family functions). Signed-off-by: Christophe JAILLET Reviewed-by: Kees Cook Reviewed-by: "Gustavo A. R. Silva" Link: https://lore.kernel.org/r/5c3b7459b820e22e2ac6ce892d4aadcc119cc919.1696065263.git.christophe.jaillet@wanadoo.fr Signed-off-by: Greg Kroah-Hartman --- include/linux/comedi/comedidev.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/linux/comedi/comedidev.h b/include/linux/comedi/comedidev.h index 0a1150900ef3..c08416a7364b 100644 --- a/include/linux/comedi/comedidev.h +++ b/include/linux/comedi/comedidev.h @@ -633,7 +633,7 @@ extern const struct comedi_lrange range_unknown; */ struct comedi_lrange { int length; - struct comedi_krange range[]; + struct comedi_krange range[] __counted_by(length); }; /** From 6f17027cc48793b9e6631fe0e52fee1af0e8b7e0 Mon Sep 17 00:00:00 2001 From: Kuan-Wei Chiu Date: Mon, 4 Sep 2023 04:42:50 +0800 Subject: [PATCH 170/326] binderfs: fix typo in binderfs.c The word "wich" was corrected to "which" for spelling accuracy. Signed-off-by: Kuan-Wei Chiu Acked-by: Carlos Llamas Link: https://lore.kernel.org/r/20230903204250.2697370-1-visitorckw@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/android/binderfs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/android/binderfs.c b/drivers/android/binderfs.c index 81effec17b3d..ae2a8413ec12 100644 --- a/drivers/android/binderfs.c +++ b/drivers/android/binderfs.c @@ -93,7 +93,7 @@ bool is_binderfs_device(const struct inode *inode) /** * binderfs_binder_device_create - allocate inode from super block of a * binderfs mount - * @ref_inode: inode from wich the super block will be taken + * @ref_inode: inode from which the super block will be taken * @userp: buffer to copy information about new device for userspace to * @req: struct binderfs_device as copied from userspace * From 1b6f457b835447a787a729dbd421653f865921d0 Mon Sep 17 00:00:00 2001 From: Justin Stitt Date: Wed, 27 Sep 2023 05:20:58 +0000 Subject: [PATCH 171/326] c2port: replace deprecated strncpy with strscpy `strncpy` is deprecated for use on NUL-terminated destination strings [1] and as such we should prefer more robust and less ambiguous string interfaces. We expect `c2dev->name` to be NUL-terminated based on its usage with format strings: | dev_info(c2dev->dev, "C2 port %s removed\n", c2dev->name); Moreover, NUL-padding is _not_ required as c2dev is zero-allocated: | c2dev = kzalloc(sizeof(struct c2port_device), GFP_KERNEL); Considering the above, a suitable replacement is `strscpy` [2] due to the fact that it guarantees NUL-termination on the destination buffer without unnecessarily NUL-padding. Let's also drop `C2PORT_NAME_LEN - 1` for `sizeof(dest)` which is more idiomatic strscpy usage. Link: https://www.kernel.org/doc/html/latest/process/deprecated.html#strncpy-on-nul-terminated-strings [1] Link: https://manpages.debian.org/testing/linux-manual-4.8/strscpy.9.en.html [2] Link: https://github.com/KSPP/linux/issues/90 Cc: linux-hardening@vger.kernel.org Signed-off-by: Justin Stitt Reviewed-by: Arnd Bergmann Link: https://lore.kernel.org/r/20230927-strncpy-drivers-misc-c2port-core-c-v1-1-978f6d220a54@google.com Signed-off-by: Greg Kroah-Hartman --- drivers/misc/c2port/core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/misc/c2port/core.c b/drivers/misc/c2port/core.c index f574c83b82cf..2bb1dd2511f9 100644 --- a/drivers/misc/c2port/core.c +++ b/drivers/misc/c2port/core.c @@ -923,7 +923,7 @@ struct c2port_device *c2port_device_register(char *name, } dev_set_drvdata(c2dev->dev, c2dev); - strncpy(c2dev->name, name, C2PORT_NAME_LEN - 1); + strscpy(c2dev->name, name, sizeof(c2dev->name)); c2dev->ops = ops; mutex_init(&c2dev->mutex); From 2953fa030690bdca0b14ab641c8e8c1df002aa51 Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Fri, 22 Sep 2023 10:53:48 -0700 Subject: [PATCH 172/326] hpet: Annotate struct hpets with __counted_by Prepare for the coming implementation by GCC and Clang of the __counted_by attribute. Flexible array members annotated with __counted_by can have their accesses bounds-checked at run-time checking via CONFIG_UBSAN_BOUNDS (for array indexing) and CONFIG_FORTIFY_SOURCE (for strcpy/memcpy-family functions). As found with Coccinelle[1], add __counted_by for struct hpets. [1] https://github.com/kees/kernel-tools/blob/trunk/coccinelle/examples/counted_by.cocci Cc: Clemens Ladisch Cc: Arnd Bergmann Cc: Greg Kroah-Hartman Signed-off-by: Kees Cook Reviewed-by: "Gustavo A. R. Silva" Link: https://lore.kernel.org/r/20230922175348.work.056-kees@kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/char/hpet.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/char/hpet.c b/drivers/char/hpet.c index ee71376f174b..0176a76cf0fe 100644 --- a/drivers/char/hpet.c +++ b/drivers/char/hpet.c @@ -111,7 +111,7 @@ struct hpets { unsigned long hp_delta; unsigned int hp_ntimer; unsigned int hp_which; - struct hpet_dev hp_dev[]; + struct hpet_dev hp_dev[] __counted_by(hp_ntimer); }; static struct hpets *hpets; From 19e3e6cdfdc73400eb68d1102cdbad4f9493f474 Mon Sep 17 00:00:00 2001 From: Justin Stitt Date: Mon, 18 Sep 2023 05:30:15 +0000 Subject: [PATCH 173/326] accessibility: speakup: refactor deprecated strncpy `strncpy` is deprecated for use on NUL-terminated destination strings [1]. Let's refactor this function to just use synth_write(). Link: www.kernel.org/doc/html/latest/process/deprecated.html#strncpy-on-nul-terminated-strings[1] Link: https://manpages.debian.org/testing/linux-manual-4.8/strscpy.9.en.html [2] Link: https://github.com/KSPP/linux/issues/90 Cc: linux-hardening@vger.kernel.org Signed-off-by: Justin Stitt Suggested-by: Kees Cook Reviewed-by: Kees Cook Tested-by: Samuel Thibault Link: https://lore.kernel.org/r/20230918-strncpy-drivers-accessibility-speakup-kobjects-c-v2-1-d5b1976c5dbf@google.com Signed-off-by: Greg Kroah-Hartman --- drivers/accessibility/speakup/kobjects.c | 25 +++++++++++------------- 1 file changed, 11 insertions(+), 14 deletions(-) diff --git a/drivers/accessibility/speakup/kobjects.c b/drivers/accessibility/speakup/kobjects.c index a7522d409802..0dfdb6608e02 100644 --- a/drivers/accessibility/speakup/kobjects.c +++ b/drivers/accessibility/speakup/kobjects.c @@ -413,27 +413,24 @@ static ssize_t synth_direct_store(struct kobject *kobj, struct kobj_attribute *attr, const char *buf, size_t count) { - u_char tmp[256]; - int len; - int bytes; - const char *ptr = buf; + char *unescaped; unsigned long flags; if (!synth) return -EPERM; - len = strlen(buf); + unescaped = kstrdup(buf, GFP_KERNEL); + if (!unescaped) + return -ENOMEM; + + string_unescape_any_inplace(unescaped); + spin_lock_irqsave(&speakup_info.spinlock, flags); - while (len > 0) { - bytes = min_t(size_t, len, 250); - strncpy(tmp, ptr, bytes); - tmp[bytes] = '\0'; - string_unescape_any_inplace(tmp); - synth_printf("%s", tmp); - ptr += bytes; - len -= bytes; - } + synth_write(unescaped, strlen(unescaped)); spin_unlock_irqrestore(&speakup_info.spinlock, flags); + + kfree(unescaped); + return count; } From 1b057bd800c3ea0c926191d7950cd2365eddc9bb Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Tue, 19 Sep 2023 09:37:42 +0200 Subject: [PATCH 174/326] drivers/char/mem: implement splice() for /dev/zero, /dev/full This allows splicing zeroed pages into a pipe, and allows discarding pages from a pipe by splicing them to /dev/zero. Writing to /dev/zero should have the same effect as writing to /dev/null, and a "splice_write" implementation exists only for /dev/null. (The /dev/zero splice_read implementation could be optimized by pushing references to the global zero page to the pipe, but that's an optimization for another day.) Signed-off-by: Max Kellermann Link: https://lore.kernel.org/r/20230919073743.1066313-1-max.kellermann@ionos.com Signed-off-by: Greg Kroah-Hartman --- drivers/char/mem.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/char/mem.c b/drivers/char/mem.c index 1052b0f2d4cf..263c19cd6fb9 100644 --- a/drivers/char/mem.c +++ b/drivers/char/mem.c @@ -640,6 +640,7 @@ static int open_port(struct inode *inode, struct file *filp) #define full_lseek null_lseek #define write_zero write_null #define write_iter_zero write_iter_null +#define splice_write_zero splice_write_null #define open_mem open_port static const struct file_operations __maybe_unused mem_fops = { @@ -677,6 +678,8 @@ static const struct file_operations zero_fops = { .read_iter = read_iter_zero, .read = read_zero, .write_iter = write_iter_zero, + .splice_read = copy_splice_read, + .splice_write = splice_write_zero, .mmap = mmap_zero, .get_unmapped_area = get_unmapped_area_zero, #ifndef CONFIG_MMU @@ -688,6 +691,7 @@ static const struct file_operations full_fops = { .llseek = full_lseek, .read_iter = read_iter_zero, .write = write_full, + .splice_read = copy_splice_read, }; static const struct memdev { From 4f01342464a8a99bf0cbb45a3ce4cf44a8baa1c5 Mon Sep 17 00:00:00 2001 From: Hugo Villeneuve Date: Mon, 11 Sep 2023 16:36:30 -0400 Subject: [PATCH 175/326] Documentation: stable: clarify patch series prerequisites Add some clarifications for patches that have dependencies within the patch series. Signed-off-by: Hugo Villeneuve Rule: add Link: https://lore.kernel.org/stable/20230911203628.20068-1-hugo%40hugovil.com Link: https://lore.kernel.org/r/20230911203628.20068-1-hugo@hugovil.com Signed-off-by: Greg Kroah-Hartman --- Documentation/process/stable-kernel-rules.rst | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/Documentation/process/stable-kernel-rules.rst b/Documentation/process/stable-kernel-rules.rst index 41f1e07abfdf..1704f1c686d0 100644 --- a/Documentation/process/stable-kernel-rules.rst +++ b/Documentation/process/stable-kernel-rules.rst @@ -101,6 +101,19 @@ comment: git cherry-pick fd21073 git cherry-pick + Note that for a patch series, you do not have to list as prerequisites the + patches present in the series itself. For example, if you have the following + patch series: + + .. code-block:: none + + patch1 + patch2 + + where patch2 depends on patch1, you do not have to list patch1 as + prerequisite of patch2 if you have already marked patch1 for stable + inclusion. + * For patches that may have kernel version prerequisites specify them using the following format in the sign-off area: From d712d205210c494c29f33dc1d1f2ce4d7448faa9 Mon Sep 17 00:00:00 2001 From: Ivan Orlov Date: Thu, 10 Aug 2023 23:51:03 +0400 Subject: [PATCH 176/326] rapidio: make all 'class' structures const Now that the driver core allows for struct class to be in read-only memory, making all 'class' structures to be declared at build time placing them into read-only memory, instead of having to be dynamically allocated at load time. Suggested-by: Greg Kroah-Hartman Signed-off-by: Ivan Orlov Link: https://lore.kernel.org/r/20230810195103.27069-1-ivan.orlov0322@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/rapidio/devices/rio_mport_cdev.c | 16 +++++++++------- drivers/rapidio/rio_cm.c | 18 ++++++++++-------- 2 files changed, 19 insertions(+), 15 deletions(-) diff --git a/drivers/rapidio/devices/rio_mport_cdev.c b/drivers/rapidio/devices/rio_mport_cdev.c index a115730ebf14..27afbb9d544b 100644 --- a/drivers/rapidio/devices/rio_mport_cdev.c +++ b/drivers/rapidio/devices/rio_mport_cdev.c @@ -250,7 +250,9 @@ static DEFINE_MUTEX(mport_devs_lock); static DECLARE_WAIT_QUEUE_HEAD(mport_cdev_wait); #endif -static struct class *dev_class; +static const struct class dev_class = { + .name = DRV_NAME, +}; static dev_t dev_number; static void mport_release_mapping(struct kref *ref); @@ -2379,7 +2381,7 @@ static struct mport_dev *mport_cdev_add(struct rio_mport *mport) device_initialize(&md->dev); md->dev.devt = MKDEV(MAJOR(dev_number), mport->id); - md->dev.class = dev_class; + md->dev.class = &dev_class; md->dev.parent = &mport->dev; md->dev.release = mport_device_release; dev_set_name(&md->dev, DEV_NAME "%d", mport->id); @@ -2600,10 +2602,10 @@ static int __init mport_init(void) int ret; /* Create device class needed by udev */ - dev_class = class_create(DRV_NAME); - if (IS_ERR(dev_class)) { + ret = class_register(&dev_class); + if (ret) { rmcd_error("Unable to create " DRV_NAME " class"); - return PTR_ERR(dev_class); + return ret; } ret = alloc_chrdev_region(&dev_number, 0, RIO_MAX_MPORTS, DRV_NAME); @@ -2624,7 +2626,7 @@ static int __init mport_init(void) err_cli: unregister_chrdev_region(dev_number, RIO_MAX_MPORTS); err_chr: - class_destroy(dev_class); + class_unregister(&dev_class); return ret; } @@ -2634,7 +2636,7 @@ err_chr: static void __exit mport_exit(void) { class_interface_unregister(&rio_mport_interface); - class_destroy(dev_class); + class_unregister(&dev_class); unregister_chrdev_region(dev_number, RIO_MAX_MPORTS); } diff --git a/drivers/rapidio/rio_cm.c b/drivers/rapidio/rio_cm.c index 49f8d111e546..9135227301c8 100644 --- a/drivers/rapidio/rio_cm.c +++ b/drivers/rapidio/rio_cm.c @@ -233,7 +233,9 @@ static DEFINE_IDR(ch_idr); static LIST_HEAD(cm_dev_list); static DECLARE_RWSEM(rdev_sem); -static struct class *dev_class; +static const struct class dev_class = { + .name = DRV_NAME, +}; static unsigned int dev_major; static unsigned int dev_minor_base; static dev_t dev_number; @@ -2072,7 +2074,7 @@ static int riocm_cdev_add(dev_t devno) return ret; } - riocm_cdev.dev = device_create(dev_class, NULL, devno, NULL, DEV_NAME); + riocm_cdev.dev = device_create(&dev_class, NULL, devno, NULL, DEV_NAME); if (IS_ERR(riocm_cdev.dev)) { cdev_del(&riocm_cdev.cdev); return PTR_ERR(riocm_cdev.dev); @@ -2293,15 +2295,15 @@ static int __init riocm_init(void) int ret; /* Create device class needed by udev */ - dev_class = class_create(DRV_NAME); - if (IS_ERR(dev_class)) { + ret = class_register(&dev_class); + if (ret) { riocm_error("Cannot create " DRV_NAME " class"); - return PTR_ERR(dev_class); + return ret; } ret = alloc_chrdev_region(&dev_number, 0, 1, DRV_NAME); if (ret) { - class_destroy(dev_class); + class_unregister(&dev_class); return ret; } @@ -2349,7 +2351,7 @@ err_cl: class_interface_unregister(&rio_mport_interface); err_reg: unregister_chrdev_region(dev_number, 1); - class_destroy(dev_class); + class_unregister(&dev_class); return ret; } @@ -2364,7 +2366,7 @@ static void __exit riocm_exit(void) device_unregister(riocm_cdev.dev); cdev_del(&(riocm_cdev.cdev)); - class_destroy(dev_class); + class_unregister(&dev_class); unregister_chrdev_region(dev_number, 1); } From 168115f989311867b48292f4f056eb2f96cef67b Mon Sep 17 00:00:00 2001 From: David Lechner Date: Fri, 29 Sep 2023 12:23:18 -0500 Subject: [PATCH 177/326] staging: iio: resolver: ad2s1210: rework gpios - Remove "adi," prefix from gpio names. - Sample gpio is now expected to be active low. - Convert A0 and A1 gpios to "mode-gpios" gpio array. - Convert RES0 and RES1 gpios to "resolution-gpios" gpio array. - Remove extraneous lookup tables. - Remove unused mode field from state struct. - Swap argument order of ad2s1210_set_mode() while we are touching this. Signed-off-by: David Lechner Link: https://lore.kernel.org/r/20230929-ad2s1210-mainline-v3-13-fa4364281745@baylibre.com Signed-off-by: Jonathan Cameron --- drivers/staging/iio/resolver/ad2s1210.c | 162 ++++++++++++------------ 1 file changed, 84 insertions(+), 78 deletions(-) diff --git a/drivers/staging/iio/resolver/ad2s1210.c b/drivers/staging/iio/resolver/ad2s1210.c index 2b9377447f6a..5744f1673cba 100644 --- a/drivers/staging/iio/resolver/ad2s1210.c +++ b/drivers/staging/iio/resolver/ad2s1210.c @@ -58,39 +58,21 @@ #define AD2S1210_DEF_EXCIT 10000 enum ad2s1210_mode { - MOD_POS = 0, - MOD_VEL, - MOD_CONFIG, - MOD_RESERVED, + MOD_POS = 0b00, + MOD_VEL = 0b01, + MOD_RESERVED = 0b10, + MOD_CONFIG = 0b11, }; -enum ad2s1210_gpios { - AD2S1210_SAMPLE, - AD2S1210_A0, - AD2S1210_A1, - AD2S1210_RES0, - AD2S1210_RES1, -}; - -struct ad2s1210_gpio { - const char *name; - unsigned long flags; -}; - -static const struct ad2s1210_gpio gpios[] = { - [AD2S1210_SAMPLE] = { .name = "adi,sample", .flags = GPIOD_OUT_LOW }, - [AD2S1210_A0] = { .name = "adi,a0", .flags = GPIOD_OUT_LOW }, - [AD2S1210_A1] = { .name = "adi,a1", .flags = GPIOD_OUT_LOW }, - [AD2S1210_RES0] = { .name = "adi,res0", .flags = GPIOD_OUT_LOW }, - [AD2S1210_RES1] = { .name = "adi,res1", .flags = GPIOD_OUT_LOW }, -}; - -static const unsigned int ad2s1210_resolution_value[] = { 10, 12, 14, 16 }; - struct ad2s1210_state { struct mutex lock; struct spi_device *sdev; - struct gpio_desc *gpios[5]; + /** GPIO pin connected to SAMPLE line. */ + struct gpio_desc *sample_gpio; + /** GPIO pins connected to A0 and A1 lines. */ + struct gpio_descs *mode_gpios; + /** GPIO pins connected to RES0 and RES1 lines. */ + struct gpio_descs *resolution_gpios; /** Used to access config registers. */ struct regmap *regmap; /** The external oscillator frequency in Hz. */ @@ -98,7 +80,6 @@ struct ad2s1210_state { unsigned int fexcit; bool hysteresis; u8 resolution; - enum ad2s1210_mode mode; /** For reading raw sample value via SPI. */ __be16 sample __aligned(IIO_DMA_MINALIGN); /** SPI transmit buffer. */ @@ -107,18 +88,15 @@ struct ad2s1210_state { u8 tx[2]; }; -static const int ad2s1210_mode_vals[4][2] = { - [MOD_POS] = { 0, 0 }, - [MOD_VEL] = { 0, 1 }, - [MOD_CONFIG] = { 1, 1 }, -}; - -static inline void ad2s1210_set_mode(enum ad2s1210_mode mode, - struct ad2s1210_state *st) +static int ad2s1210_set_mode(struct ad2s1210_state *st, enum ad2s1210_mode mode) { - gpiod_set_value(st->gpios[AD2S1210_A0], ad2s1210_mode_vals[mode][0]); - gpiod_set_value(st->gpios[AD2S1210_A1], ad2s1210_mode_vals[mode][1]); - st->mode = mode; + struct gpio_descs *gpios = st->mode_gpios; + DECLARE_BITMAP(bitmap, 2); + + bitmap[0] = mode; + + return gpiod_set_array_value(gpios->ndescs, gpios->desc, gpios->info, + bitmap); } /* @@ -143,6 +121,7 @@ static int ad2s1210_regmap_reg_write(void *context, unsigned int reg, .tx_buf = &st->tx[1], }, }; + int ret; /* values can only be 7 bits, the MSB indicates an address */ if (val & ~0x7F) @@ -151,7 +130,9 @@ static int ad2s1210_regmap_reg_write(void *context, unsigned int reg, st->tx[0] = reg; st->tx[1] = val; - ad2s1210_set_mode(MOD_CONFIG, st); + ret = ad2s1210_set_mode(st, MOD_CONFIG); + if (ret < 0) + return ret; return spi_sync_transfer(st->sdev, xfers, ARRAY_SIZE(xfers)); } @@ -180,7 +161,10 @@ static int ad2s1210_regmap_reg_read(void *context, unsigned int reg, }; int ret; - ad2s1210_set_mode(MOD_CONFIG, st); + ret = ad2s1210_set_mode(st, MOD_CONFIG); + if (ret < 0) + return ret; + st->tx[0] = reg; /* * Must be valid register address here otherwise this could write data. @@ -219,16 +203,16 @@ int ad2s1210_update_frequency_control_word(struct ad2s1210_state *st) return regmap_write(st->regmap, AD2S1210_REG_EXCIT_FREQ, fcw); } -static const int ad2s1210_res_pins[4][2] = { - { 0, 0 }, {0, 1}, {1, 0}, {1, 1} -}; - -static inline void ad2s1210_set_resolution_pin(struct ad2s1210_state *st) +static int ad2s1210_set_resolution_gpios(struct ad2s1210_state *st, + u8 resolution) { - gpiod_set_value(st->gpios[AD2S1210_RES0], - ad2s1210_res_pins[(st->resolution - 10) / 2][0]); - gpiod_set_value(st->gpios[AD2S1210_RES1], - ad2s1210_res_pins[(st->resolution - 10) / 2][1]); + struct gpio_descs *gpios = st->resolution_gpios; + DECLARE_BITMAP(bitmap, 2); + + bitmap[0] = (resolution - 10) >> 1; + + return gpiod_set_array_value(gpios->ndescs, gpios->desc, gpios->info, + bitmap); } static inline int ad2s1210_soft_reset(struct ad2s1210_state *st) @@ -305,10 +289,13 @@ static ssize_t ad2s1210_store_resolution(struct device *dev, if (ret < 0) goto error_ret; - st->resolution = - ad2s1210_resolution_value[data & AD2S1210_SET_RES]; - ad2s1210_set_resolution_pin(st); + ret = ad2s1210_set_resolution_gpios(st, udata); + if (ret < 0) + goto error_ret; + + st->resolution = udata; ret = len; + error_ret: mutex_unlock(&st->lock); return ret; @@ -339,15 +326,19 @@ static ssize_t ad2s1210_clear_fault(struct device *dev, int ret; mutex_lock(&st->lock); - gpiod_set_value(st->gpios[AD2S1210_SAMPLE], 0); + + gpiod_set_value(st->sample_gpio, 1); /* delay (2 * tck + 20) nano seconds */ udelay(1); - gpiod_set_value(st->gpios[AD2S1210_SAMPLE], 1); + gpiod_set_value(st->sample_gpio, 0); + ret = regmap_read(st->regmap, AD2S1210_REG_FAULT, &value); if (ret < 0) goto error_ret; - gpiod_set_value(st->gpios[AD2S1210_SAMPLE], 0); - gpiod_set_value(st->gpios[AD2S1210_SAMPLE], 1); + + gpiod_set_value(st->sample_gpio, 1); + gpiod_set_value(st->sample_gpio, 0); + error_ret: mutex_unlock(&st->lock); @@ -393,19 +384,19 @@ static int ad2s1210_single_conversion(struct ad2s1210_state *st, struct iio_chan_spec const *chan, int *val) { - int ret = 0; + int ret; mutex_lock(&st->lock); - gpiod_set_value(st->gpios[AD2S1210_SAMPLE], 0); + gpiod_set_value(st->sample_gpio, 1); /* delay (6 * tck + 20) nano seconds */ udelay(1); switch (chan->type) { case IIO_ANGL: - ad2s1210_set_mode(MOD_POS, st); + ret = ad2s1210_set_mode(st, MOD_POS); break; case IIO_ANGL_VEL: - ad2s1210_set_mode(MOD_VEL, st); + ret = ad2s1210_set_mode(st, MOD_VEL); break; default: ret = -EINVAL; @@ -432,7 +423,7 @@ static int ad2s1210_single_conversion(struct ad2s1210_state *st, } error_ret: - gpiod_set_value(st->gpios[AD2S1210_SAMPLE], 1); + gpiod_set_value(st->sample_gpio, 0); /* delay (2 * tck + 20) nano seconds */ udelay(1); mutex_unlock(&st->lock); @@ -546,7 +537,9 @@ static int ad2s1210_initial(struct ad2s1210_state *st) int ret; mutex_lock(&st->lock); - ad2s1210_set_resolution_pin(st); + ret = ad2s1210_set_resolution_gpios(st, st->resolution); + if (ret < 0) + goto error_ret; /* Use default config register value plus resolution from devicetree. */ data = FIELD_PREP(AD2S1210_PHASE_LOCK_RANGE_44, 1); @@ -612,20 +605,34 @@ static int ad2s1210_setup_clocks(struct ad2s1210_state *st) static int ad2s1210_setup_gpios(struct ad2s1210_state *st) { - struct spi_device *spi = st->sdev; - int i, ret; + struct device *dev = &st->sdev->dev; - for (i = 0; i < ARRAY_SIZE(gpios); i++) { - st->gpios[i] = devm_gpiod_get(&spi->dev, gpios[i].name, - gpios[i].flags); - if (IS_ERR(st->gpios[i])) { - ret = PTR_ERR(st->gpios[i]); - dev_err(&spi->dev, - "ad2s1210: failed to request %s GPIO: %d\n", - gpios[i].name, ret); - return ret; - } - } + /* should not be sampling on startup */ + st->sample_gpio = devm_gpiod_get(dev, "sample", GPIOD_OUT_LOW); + if (IS_ERR(st->sample_gpio)) + return dev_err_probe(dev, PTR_ERR(st->sample_gpio), + "failed to request sample GPIO\n"); + + /* both pins high means that we start in config mode */ + st->mode_gpios = devm_gpiod_get_array(dev, "mode", GPIOD_OUT_HIGH); + if (IS_ERR(st->mode_gpios)) + return dev_err_probe(dev, PTR_ERR(st->mode_gpios), + "failed to request mode GPIOs\n"); + + if (st->mode_gpios->ndescs != 2) + return dev_err_probe(dev, -EINVAL, + "requires exactly 2 mode-gpios\n"); + + /* both pins high means that we start with 16-bit resolution */ + st->resolution_gpios = devm_gpiod_get_array(dev, "resolution", + GPIOD_OUT_HIGH); + if (IS_ERR(st->resolution_gpios)) + return dev_err_probe(dev, PTR_ERR(st->resolution_gpios), + "failed to request resolution GPIOs\n"); + + if (st->resolution_gpios->ndescs != 2) + return dev_err_probe(dev, -EINVAL, + "requires exactly 2 resolution-gpios\n"); return 0; } @@ -690,7 +697,6 @@ static int ad2s1210_probe(struct spi_device *spi) mutex_init(&st->lock); st->sdev = spi; st->hysteresis = true; - st->mode = MOD_CONFIG; st->resolution = 12; st->fexcit = AD2S1210_DEF_EXCIT; From de69623c7cc7b960ee5bec134707bf6567199fc9 Mon Sep 17 00:00:00 2001 From: David Lechner Date: Fri, 29 Sep 2023 12:23:20 -0500 Subject: [PATCH 178/326] staging: iio: resolver: ad2s1210: refactor setting excitation frequency This combines the ad2s1210_update_frequency_control_word() and ad2s1210_soft_reset() functions into a single function since they both have to be called together. (The software reset does not reset any configuration registers, it only updates the excitation output and resets the tracking loop.) Also clean up a few things while touching this: - move AD2S1210_DEF_EXCIT macro with similar macros - remove unnecessary dev_err() calls Signed-off-by: David Lechner Link: https://lore.kernel.org/r/20230929-ad2s1210-mainline-v3-15-fa4364281745@baylibre.com Signed-off-by: Jonathan Cameron --- drivers/staging/iio/resolver/ad2s1210.c | 66 +++++++++++++------------ 1 file changed, 34 insertions(+), 32 deletions(-) diff --git a/drivers/staging/iio/resolver/ad2s1210.c b/drivers/staging/iio/resolver/ad2s1210.c index 5744f1673cba..2b728863a3ff 100644 --- a/drivers/staging/iio/resolver/ad2s1210.c +++ b/drivers/staging/iio/resolver/ad2s1210.c @@ -51,12 +51,11 @@ #define AD2S1210_MIN_CLKIN 6144000 #define AD2S1210_MAX_CLKIN 10240000 #define AD2S1210_MIN_EXCIT 2000 +#define AD2S1210_DEF_EXCIT 10000 #define AD2S1210_MAX_EXCIT 20000 #define AD2S1210_MIN_FCW 0x4 #define AD2S1210_MAX_FCW 0x50 -#define AD2S1210_DEF_EXCIT 10000 - enum ad2s1210_mode { MOD_POS = 0b00, MOD_VEL = 0b01, @@ -189,18 +188,32 @@ static int ad2s1210_regmap_reg_read(void *context, unsigned int reg, return 0; } -static inline -int ad2s1210_update_frequency_control_word(struct ad2s1210_state *st) +/* + * Sets the excitation frequency and performs software reset. + * + * Must be called with lock held. + */ +static int ad2s1210_reinit_excitation_frequency(struct ad2s1210_state *st, + u16 fexcit) { - unsigned char fcw; + int ret; + u8 fcw; - fcw = (unsigned char)(st->fexcit * (1 << 15) / st->clkin_hz); - if (fcw < AD2S1210_MIN_FCW || fcw > AD2S1210_MAX_FCW) { - dev_err(&st->sdev->dev, "ad2s1210: FCW out of range\n"); + fcw = fexcit * (1 << 15) / st->clkin_hz; + if (fcw < AD2S1210_MIN_FCW || fcw > AD2S1210_MAX_FCW) return -ERANGE; - } - return regmap_write(st->regmap, AD2S1210_REG_EXCIT_FREQ, fcw); + ret = regmap_write(st->regmap, AD2S1210_REG_EXCIT_FREQ, fcw); + if (ret < 0) + return ret; + + st->fexcit = fexcit; + + /* + * Software reset reinitializes the excitation frequency output. + * It does not reset any of the configuration registers. + */ + return regmap_write(st->regmap, AD2S1210_REG_SOFT_RESET, 0); } static int ad2s1210_set_resolution_gpios(struct ad2s1210_state *st, @@ -215,11 +228,6 @@ static int ad2s1210_set_resolution_gpios(struct ad2s1210_state *st, bitmap); } -static inline int ad2s1210_soft_reset(struct ad2s1210_state *st) -{ - return regmap_write(st->regmap, AD2S1210_REG_SOFT_RESET, 0); -} - static ssize_t ad2s1210_show_fexcit(struct device *dev, struct device_attribute *attr, char *buf) @@ -234,27 +242,24 @@ static ssize_t ad2s1210_store_fexcit(struct device *dev, const char *buf, size_t len) { struct ad2s1210_state *st = iio_priv(dev_to_iio_dev(dev)); - unsigned int fexcit; + u16 fexcit; int ret; - ret = kstrtouint(buf, 10, &fexcit); - if (ret < 0) - return ret; - if (fexcit < AD2S1210_MIN_EXCIT || fexcit > AD2S1210_MAX_EXCIT) { - dev_err(dev, - "ad2s1210: excitation frequency out of range\n"); + ret = kstrtou16(buf, 10, &fexcit); + if (ret < 0 || fexcit < AD2S1210_MIN_EXCIT || fexcit > AD2S1210_MAX_EXCIT) return -EINVAL; - } + mutex_lock(&st->lock); - st->fexcit = fexcit; - ret = ad2s1210_update_frequency_control_word(st); + ret = ad2s1210_reinit_excitation_frequency(st, fexcit); if (ret < 0) goto error_ret; - ret = ad2s1210_soft_reset(st); + + ret = len; + error_ret: mutex_unlock(&st->lock); - return ret < 0 ? ret : len; + return ret; } static ssize_t ad2s1210_show_resolution(struct device *dev, @@ -551,10 +556,8 @@ static int ad2s1210_initial(struct ad2s1210_state *st) if (ret < 0) goto error_ret; - ret = ad2s1210_update_frequency_control_word(st); - if (ret < 0) - goto error_ret; - ret = ad2s1210_soft_reset(st); + ret = ad2s1210_reinit_excitation_frequency(st, AD2S1210_DEF_EXCIT); + error_ret: mutex_unlock(&st->lock); return ret; @@ -698,7 +701,6 @@ static int ad2s1210_probe(struct spi_device *spi) st->sdev = spi; st->hysteresis = true; st->resolution = 12; - st->fexcit = AD2S1210_DEF_EXCIT; ret = ad2s1210_setup_clocks(st); if (ret < 0) From 500d7640f63d557c397f74b7d5bf8c81377b50b3 Mon Sep 17 00:00:00 2001 From: David Lechner Date: Fri, 29 Sep 2023 12:23:21 -0500 Subject: [PATCH 179/326] staging: iio: resolver: ad2s1210: read excitation frequency from control register This modifies the ad2s1210_show_fexcit() function to read the excitation frequency from the control register. This way we don't have to keep track of the value and don't risk returning a stale value. Signed-off-by: David Lechner Link: https://lore.kernel.org/r/20230929-ad2s1210-mainline-v3-16-fa4364281745@baylibre.com Signed-off-by: Jonathan Cameron --- drivers/staging/iio/resolver/ad2s1210.c | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/drivers/staging/iio/resolver/ad2s1210.c b/drivers/staging/iio/resolver/ad2s1210.c index 2b728863a3ff..67d8af0dd7ae 100644 --- a/drivers/staging/iio/resolver/ad2s1210.c +++ b/drivers/staging/iio/resolver/ad2s1210.c @@ -76,7 +76,6 @@ struct ad2s1210_state { struct regmap *regmap; /** The external oscillator frequency in Hz. */ unsigned long clkin_hz; - unsigned int fexcit; bool hysteresis; u8 resolution; /** For reading raw sample value via SPI. */ @@ -207,8 +206,6 @@ static int ad2s1210_reinit_excitation_frequency(struct ad2s1210_state *st, if (ret < 0) return ret; - st->fexcit = fexcit; - /* * Software reset reinitializes the excitation frequency output. * It does not reset any of the configuration registers. @@ -233,8 +230,22 @@ static ssize_t ad2s1210_show_fexcit(struct device *dev, char *buf) { struct ad2s1210_state *st = iio_priv(dev_to_iio_dev(dev)); + unsigned int value; + u16 fexcit; + int ret; - return sprintf(buf, "%u\n", st->fexcit); + mutex_lock(&st->lock); + ret = regmap_read(st->regmap, AD2S1210_REG_EXCIT_FREQ, &value); + if (ret < 0) + goto error_ret; + + fexcit = value * st->clkin_hz / (1 << 15); + + ret = sprintf(buf, "%u\n", fexcit); + +error_ret: + mutex_unlock(&st->lock); + return ret; } static ssize_t ad2s1210_store_fexcit(struct device *dev, From d2d1ecc67c48caf479319c4e1ab3d7896f826429 Mon Sep 17 00:00:00 2001 From: Ramona Gradinariu Date: Tue, 26 Sep 2023 11:57:21 +0300 Subject: [PATCH 180/326] iio: imu: adis16475: Add buffer padding after temp channel The temperature channel has 16-bit storage size. We need to perform the padding to have the buffer elements naturally aligned in case the temperature channel is enabled and there are any 32-bit storage size channels enabled which have a scan index higher than the temperature channel scan index. Fixes: 8f6bc87d67c0 ("iio: imu: adis16475.c: Add delta angle and delta velocity channels") Signed-off-by: Ramona Gradinariu Reviewed-by: Nuno Sa Link: https://lore.kernel.org/r/20230926085721.645687-2-ramona.gradinariu@analog.com Signed-off-by: Jonathan Cameron --- drivers/iio/imu/adis16475.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/drivers/iio/imu/adis16475.c b/drivers/iio/imu/adis16475.c index 00e4e09cdafb..9af07fec0d89 100644 --- a/drivers/iio/imu/adis16475.c +++ b/drivers/iio/imu/adis16475.c @@ -1197,6 +1197,16 @@ static irqreturn_t adis16475_trigger_handler(int irq, void *p) switch (bit) { case ADIS16475_SCAN_TEMP: st->data[i++] = buffer[offset]; + /* + * The temperature channel has 16-bit storage size. + * We need to perform the padding to have the buffer + * elements naturally aligned in case there are any + * 32-bit storage size channels enabled which have a + * scan index higher than the temperature channel scan + * index. + */ + if (*indio_dev->active_scan_mask & GENMASK(ADIS16475_SCAN_DELTVEL_Z, ADIS16475_SCAN_DELTANG_X)) + st->data[i++] = 0; break; case ADIS16475_SCAN_DELTANG_X ... ADIS16475_SCAN_DELTVEL_Z: buff_offset = ADIS16475_SCAN_DELTANG_X; From 67142d6f1e2fd97c035a42612b5b28809dc5f6ea Mon Sep 17 00:00:00 2001 From: Antoniu Miclaus Date: Tue, 26 Sep 2023 13:01:49 +0300 Subject: [PATCH 181/326] MAINTAINERS: fix Analog Devices website link The http://ez.analog.com/community/linux-device-drivers link is broken. Update website link to the new available one: https://ez.analog.com/linux-software-drivers Signed-off-by: Antoniu Miclaus Link: https://lore.kernel.org/r/20230926100149.4611-1-antoniu.miclaus@analog.com Signed-off-by: Jonathan Cameron --- MAINTAINERS | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/MAINTAINERS b/MAINTAINERS index 337a4244ee30..0782484cceb8 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1119,7 +1119,7 @@ ANALOG DEVICES INC AD4130 DRIVER M: Cosmin Tanislav L: linux-iio@vger.kernel.org S: Supported -W: http://ez.analog.com/community/linux-device-drivers +W: https://ez.analog.com/linux-software-drivers F: Documentation/ABI/testing/sysfs-bus-iio-adc-ad4130 F: Documentation/devicetree/bindings/iio/adc/adi,ad4130.yaml F: drivers/iio/adc/ad4130.c @@ -1152,7 +1152,7 @@ ANALOG DEVICES INC AD74115 DRIVER M: Cosmin Tanislav L: linux-iio@vger.kernel.org S: Supported -W: http://ez.analog.com/community/linux-device-drivers +W: https://ez.analog.com/linux-software-drivers F: Documentation/devicetree/bindings/iio/addac/adi,ad74115.yaml F: drivers/iio/addac/ad74115.c @@ -12820,7 +12820,7 @@ MAX31827 TEMPERATURE SWITCH DRIVER M: Daniel Matyas L: linux-hwmon@vger.kernel.org S: Supported -W: http://ez.analog.com/community/linux-device-drivers +W: https://ez.analog.com/linux-software-drivers F: Documentation/devicetree/bindings/hwmon/adi,max31827.yaml F: Documentation/hwmon/max31827.rst F: drivers/hwmon/max31827.c From 14114c8a747e12c169550d1806f8f87345480448 Mon Sep 17 00:00:00 2001 From: Andreas Kemnade Date: Wed, 27 Sep 2023 19:32:43 +0200 Subject: [PATCH 182/326] dt-bindings: iio: imu: mpu6050: Add level shifter Add a level shifter flag as found in ancient platform data struct: level_shifter: 0: VLogic, 1: VDD Signed-off-by: Andreas Kemnade Acked-by: Rob Herring Acked-by: Jean-Baptiste Maneyrol Link: https://lore.kernel.org/r/20230927173245.2151083-2-andreas@kemnade.info Signed-off-by: Jonathan Cameron --- .../devicetree/bindings/iio/imu/invensense,mpu6050.yaml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Documentation/devicetree/bindings/iio/imu/invensense,mpu6050.yaml b/Documentation/devicetree/bindings/iio/imu/invensense,mpu6050.yaml index 1db6952ddca5..297b8a1a7ffb 100644 --- a/Documentation/devicetree/bindings/iio/imu/invensense,mpu6050.yaml +++ b/Documentation/devicetree/bindings/iio/imu/invensense,mpu6050.yaml @@ -48,6 +48,11 @@ properties: mount-matrix: true + invensense,level-shifter: + type: boolean + description: | + From ancient platform data struct: false: VLogic, true: VDD + i2c-gate: $ref: /schemas/i2c/i2c-controller.yaml unevaluatedProperties: false From c48fb9f956081d663bc8cfe3df32c59d2e869bea Mon Sep 17 00:00:00 2001 From: Andreas Kemnade Date: Wed, 27 Sep 2023 19:32:44 +0200 Subject: [PATCH 183/326] iio: imu: mpu6050: add level shifter flag Some boards fail in magnetometer probe if level shifter flag is not set, definition was found in the vendor Linux kernel v3.0. Signed-off-by: Andreas Kemnade Reviewed-by: Andy Shevchenko Acked-by: Jean-Baptiste Maneyrol Link: https://lore.kernel.org/r/20230927173245.2151083-3-andreas@kemnade.info Signed-off-by: Jonathan Cameron --- drivers/iio/imu/inv_mpu6050/inv_mpu_aux.c | 13 +++++++++++++ drivers/iio/imu/inv_mpu6050/inv_mpu_core.c | 3 +++ drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h | 1 + 3 files changed, 17 insertions(+) diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_aux.c b/drivers/iio/imu/inv_mpu6050/inv_mpu_aux.c index 7327e5723f96..8a7f2911905a 100644 --- a/drivers/iio/imu/inv_mpu6050/inv_mpu_aux.c +++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_aux.c @@ -71,6 +71,19 @@ int inv_mpu_aux_init(const struct inv_mpu6050_state *st) unsigned int val; int ret; + /* + * Code based on the vendor Linux kernel v3.0, + * the exact meaning is unknown. + */ + if (st->chip_type == INV_MPU9150) { + unsigned int mask = BIT(7); + + val = st->level_shifter ? mask : 0; + ret = regmap_update_bits(st->map, 0x1, mask, val); + if (ret) + return ret; + } + /* configure i2c master */ val = INV_MPU6050_BITS_I2C_MST_CLK_400KHZ | INV_MPU6050_BIT_WAIT_FOR_ES; diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c b/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c index 29f906c884bd..3fbeef1a7018 100644 --- a/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c +++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #include @@ -1495,6 +1496,8 @@ int inv_mpu_core_probe(struct regmap *regmap, int irq, const char *name, st->irq = irq; st->map = regmap; + st->level_shifter = device_property_read_bool(dev, + "invensense,level-shifter"); pdata = dev_get_platdata(dev); if (!pdata) { result = iio_read_mount_matrix(dev, &st->orientation); diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h b/drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h index 95f548235de7..5950e2419ebb 100644 --- a/drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h +++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h @@ -203,6 +203,7 @@ struct inv_mpu6050_state { s32 magn_raw_to_gauss[3]; struct iio_mount_matrix magn_orient; unsigned int suspended_sensors; + bool level_shifter; u8 *data; }; From 8a76356e7db02ec7b1913db06605e70294d94672 Mon Sep 17 00:00:00 2001 From: Matti Vaittinen Date: Wed, 27 Sep 2023 11:27:41 +0300 Subject: [PATCH 184/326] iio: improve doc for available_scan_mask The available_scan_mask is an array of bitmaps representing the channels which can be simultaneously enabled by the driver. In many cases, the hardware can offer more channels than what the user is interested in obtaining. In such cases, it may be preferred that only a subset of channels are enabled, and the driver reads only a subset of the channels from the hardware. Some devices can't support all channel combinations. For example, the BM1390 pressure sensor must always read the pressure data in order to acknowledge the watermark IRQ, while reading temperature can be omitted. So, the available scan masks would be 'pressure and temperature' and 'pressure only'. When IIO searches for the scan mask it asks the driver to use, it will pick the first suitable one from the 'available_scan_mask' array. Hence, ordering the masks in the array makes a difference. We should 'prefer' reading just the pressure from the hardware (as it is a cheaper operation than reading both pressure and temperature) over reading both pressure and temperature. Hence, we should set the 'only pressure' as the first scan mask in available_scan_mask array. If we set the 'pressure and temperature' as first in the array, then the 'only temperature' will never get used as 'pressure and temperature' can always serve the user's needs. Add (minimal) kerneldoc to the 'available_scan_mask' to hint the user that the ordering of masks matters. Signed-off-by: Matti Vaittinen Link: https://lore.kernel.org/r/4e43bf0186df5c8a56b470318b4827605f9cad6c.1695727471.git.mazziesaccount@gmail.com Signed-off-by: Jonathan Cameron --- include/linux/iio/iio.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/include/linux/iio/iio.h b/include/linux/iio/iio.h index 202e55b0a28b..7bfa1b9bc8a2 100644 --- a/include/linux/iio/iio.h +++ b/include/linux/iio/iio.h @@ -556,7 +556,9 @@ struct iio_buffer_setup_ops { * and owner * @buffer: [DRIVER] any buffer present * @scan_bytes: [INTERN] num bytes captured to be fed to buffer demux - * @available_scan_masks: [DRIVER] optional array of allowed bitmasks + * @available_scan_masks: [DRIVER] optional array of allowed bitmasks. Sort the + * array in order of preference, the most preferred + * masks first. * @masklength: [INTERN] the length of the mask established from * channels * @active_scan_mask: [INTERN] union of all scan masks requested by buffers From 62593189b66ac6b5b69d2cf5b90728cc65a8fd68 Mon Sep 17 00:00:00 2001 From: Matti Vaittinen Date: Wed, 27 Sep 2023 11:27:57 +0300 Subject: [PATCH 185/326] dt-bindings: Add ROHM BM1390 pressure sensor BM1390GLV-Z is a pressure sensor which performs internal temperature compensation for the MEMS. Pressure range is from 300 hPa to 1300 hPa and sample averaging and IIR filtering is built in sensor. Temperature measurement is also supported. Add dt-bindings for the sensor. Signed-off-by: Matti Vaittinen Reviewed-by: Conor Dooley Link: https://lore.kernel.org/r/08796e6b28d2c67933b1a1a5eca0f43da322a597.1695727471.git.mazziesaccount@gmail.com Signed-off-by: Jonathan Cameron --- .../bindings/iio/pressure/rohm,bm1390.yaml | 52 +++++++++++++++++++ 1 file changed, 52 insertions(+) create mode 100644 Documentation/devicetree/bindings/iio/pressure/rohm,bm1390.yaml diff --git a/Documentation/devicetree/bindings/iio/pressure/rohm,bm1390.yaml b/Documentation/devicetree/bindings/iio/pressure/rohm,bm1390.yaml new file mode 100644 index 000000000000..7c4ca6322bf8 --- /dev/null +++ b/Documentation/devicetree/bindings/iio/pressure/rohm,bm1390.yaml @@ -0,0 +1,52 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/iio/pressure/rohm,bm1390.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: ROHM BM1390 pressure sensor + +maintainers: + - Matti Vaittinen + +description: + BM1390GLV-Z is a pressure sensor which performs internal temperature + compensation for the MEMS. Pressure range is from 300 hPa to 1300 hPa + and sample averaging and IIR filtering is built in. Temperature + measurement is also supported. + +properties: + compatible: + const: rohm,bm1390glv-z + + reg: + maxItems: 1 + + interrupts: + maxItems: 1 + + vdd-supply: true + +required: + - compatible + - reg + - vdd-supply + +additionalProperties: false + +examples: + - | + #include + i2c { + #address-cells = <1>; + #size-cells = <0>; + pressure-sensor@5d { + compatible = "rohm,bm1390glv-z"; + reg = <0x5d>; + + interrupt-parent = <&gpio1>; + interrupts = <29 IRQ_TYPE_LEVEL_LOW>; + + vdd-supply = <&vdd>; + }; + }; From 81ca5979b6ed9a2b49cf9e253a494e0777b0edf9 Mon Sep 17 00:00:00 2001 From: Matti Vaittinen Date: Wed, 27 Sep 2023 11:28:13 +0300 Subject: [PATCH 186/326] iio: pressure: Support ROHM BU1390 Support for the ROHM BM1390 pressure sensor. The BM1390GLV-Z can measure pressures ranging from 300 hPa to 1300 hPa with configurable measurement averaging and internal FIFO. The sensor does also provide temperature measurements. Sensor does also contain IIR filter implemented in HW. The data-sheet says the IIR filter can be configured to be "weak", "middle" or "strong". Some RMS noise figures are provided in data sheet but no accurate maths for the filter configurations is provided. Hence, the IIR filter configuration is not supported by this driver and the filter is configured to the "middle" setting (at least not for now). The FIFO measurement mode is only measuring the pressure and not the temperature. The driver measures temperature when FIFO is flushed and simply uses the same measured temperature value to all reported temperatures. This should not be a problem when temperature is not changing very rapidly (several degrees C / second) but allows users to get the temperature measurements from sensor without any additional logic. This driver allows the sensor to be used in two muitually exclusive ways, 1. With trigger (data-ready IRQ). In this case the FIFO is not used as we get data ready for each collected sample. Instead, for each data-ready IRQ we read the sample from sensor and push it to the IIO buffer. 2. With hardware FIFO and watermark IRQ. In this case the data-ready is not used but we enable watermark IRQ. At each watermark IRQ we go and read all samples in FIFO and push them to the IIO buffer. Signed-off-by: Matti Vaittinen Link: https://lore.kernel.org/r/4f23211e3cf248f9f48ddb2a752387bb00e9c2c4.1695727471.git.mazziesaccount@gmail.com Signed-off-by: Jonathan Cameron --- drivers/iio/pressure/Kconfig | 9 + drivers/iio/pressure/Makefile | 1 + drivers/iio/pressure/rohm-bm1390.c | 934 +++++++++++++++++++++++++++++ 3 files changed, 944 insertions(+) create mode 100644 drivers/iio/pressure/rohm-bm1390.c diff --git a/drivers/iio/pressure/Kconfig b/drivers/iio/pressure/Kconfig index 7b4c2af32852..95efa32e4289 100644 --- a/drivers/iio/pressure/Kconfig +++ b/drivers/iio/pressure/Kconfig @@ -16,6 +16,15 @@ config ABP060MG To compile this driver as a module, choose M here: the module will be called abp060mg. +config ROHM_BM1390 + tristate "ROHM BM1390GLV-Z pressure sensor driver" + depends on I2C + help + Support for the ROHM BM1390 pressure sensor. The BM1390GLV-Z + can measure pressures ranging from 300 hPa to 1300 hPa with + configurable measurement averaging and internal FIFO. The + sensor does also provide temperature measurements. + config BMP280 tristate "Bosch Sensortec BMP180/BMP280/BMP380/BMP580 pressure sensor driver" depends on (I2C || SPI_MASTER) diff --git a/drivers/iio/pressure/Makefile b/drivers/iio/pressure/Makefile index c90f77210e94..436aec7e65f3 100644 --- a/drivers/iio/pressure/Makefile +++ b/drivers/iio/pressure/Makefile @@ -5,6 +5,7 @@ # When adding new entries keep the list in alphabetical order obj-$(CONFIG_ABP060MG) += abp060mg.o +obj-$(CONFIG_ROHM_BM1390) += rohm-bm1390.o obj-$(CONFIG_BMP280) += bmp280.o bmp280-objs := bmp280-core.o bmp280-regmap.o obj-$(CONFIG_BMP280_I2C) += bmp280-i2c.o diff --git a/drivers/iio/pressure/rohm-bm1390.c b/drivers/iio/pressure/rohm-bm1390.c new file mode 100644 index 000000000000..ccaa07a569c9 --- /dev/null +++ b/drivers/iio/pressure/rohm-bm1390.c @@ -0,0 +1,934 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * BM1390 ROHM pressure sensor + * + * Copyright (c) 2023, ROHM Semiconductor. + * https://fscdn.rohm.com/en/products/databook/datasheet/ic/sensor/pressure/bm1390glv-z-e.pdf + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#define BM1390_REG_MANUFACT_ID 0x0f +#define BM1390_REG_PART_ID 0x10 +#define BM1390_REG_POWER 0x12 +#define BM1390_MASK_POWER BIT(0) +#define BM1390_POWER_ON BM1390_MASK_POWER +#define BM1390_POWER_OFF 0x00 +#define BM1390_REG_RESET 0x13 +#define BM1390_MASK_RESET BIT(0) +#define BM1390_RESET_RELEASE BM1390_MASK_RESET +#define BM1390_RESET 0x00 +#define BM1390_REG_MODE_CTRL 0x14 +#define BM1390_MASK_MEAS_MODE GENMASK(1, 0) +#define BM1390_MASK_DRDY_EN BIT(4) +#define BM1390_MASK_WMI_EN BIT(2) +#define BM1390_MASK_AVE_NUM GENMASK(7, 5) + +/* + * Data-sheet states that when the IIR is used, the AVE_NUM must be set to + * value 110b + */ +#define BM1390_IIR_AVE_NUM 0x06 +#define BM1390_REG_FIFO_CTRL 0x15 +#define BM1390_MASK_IIR_MODE GENMASK(1, 0) +#define BM1390_IIR_MODE_OFF 0x0 +#define BM1390_IIR_MODE_WEAK 0x1 +#define BM1390_IIR_MODE_MID 0x2 +#define BM1390_IIR_MODE_STRONG 0x3 + +#define BM1390_MASK_FIFO_LEN BIT(6) +#define BM1390_MASK_FIFO_EN BIT(7) +#define BM1390_WMI_MIN 2 +#define BM1390_WMI_MAX 3 + +#define BM1390_REG_FIFO_LVL 0x18 +#define BM1390_MASK_FIFO_LVL GENMASK(2, 0) +#define BM1390_REG_STATUS 0x19 +#define BM1390_REG_PRESSURE_BASE 0x1a +#define BM1390_REG_TEMP_HI 0x1d +#define BM1390_REG_TEMP_LO 0x1e +#define BM1390_MAX_REGISTER BM1390_REG_TEMP_LO + +#define BM1390_ID 0x34 + +/* Regmap configs */ +static const struct regmap_range bm1390_volatile_ranges[] = { + { + .range_min = BM1390_REG_STATUS, + .range_max = BM1390_REG_STATUS, + }, + { + .range_min = BM1390_REG_FIFO_LVL, + .range_max = BM1390_REG_TEMP_LO, + }, +}; + +static const struct regmap_access_table bm1390_volatile_regs = { + .yes_ranges = &bm1390_volatile_ranges[0], + .n_yes_ranges = ARRAY_SIZE(bm1390_volatile_ranges), +}; + +static const struct regmap_range bm1390_precious_ranges[] = { + { + .range_min = BM1390_REG_STATUS, + .range_max = BM1390_REG_STATUS, + }, +}; + +static const struct regmap_access_table bm1390_precious_regs = { + .yes_ranges = &bm1390_precious_ranges[0], + .n_yes_ranges = ARRAY_SIZE(bm1390_precious_ranges), +}; + +static const struct regmap_range bm1390_read_only_ranges[] = { + { + .range_min = BM1390_REG_MANUFACT_ID, + .range_max = BM1390_REG_PART_ID, + }, { + .range_min = BM1390_REG_FIFO_LVL, + .range_max = BM1390_REG_TEMP_LO, + }, +}; + +static const struct regmap_access_table bm1390_ro_regs = { + .no_ranges = &bm1390_read_only_ranges[0], + .n_no_ranges = ARRAY_SIZE(bm1390_read_only_ranges), +}; + +static const struct regmap_range bm1390_noinc_read_ranges[] = { + { + .range_min = BM1390_REG_PRESSURE_BASE, + .range_max = BM1390_REG_TEMP_LO, + }, +}; + +static const struct regmap_access_table bm1390_nir_regs = { + .yes_ranges = &bm1390_noinc_read_ranges[0], + .n_yes_ranges = ARRAY_SIZE(bm1390_noinc_read_ranges), +}; + +static const struct regmap_config bm1390_regmap = { + .reg_bits = 8, + .val_bits = 8, + .volatile_table = &bm1390_volatile_regs, + .wr_table = &bm1390_ro_regs, + .rd_noinc_table = &bm1390_nir_regs, + .precious_table = &bm1390_precious_regs, + .max_register = BM1390_MAX_REGISTER, + .cache_type = REGCACHE_RBTREE, + .disable_locking = true, +}; + +enum { + BM1390_STATE_SAMPLE, + BM1390_STATE_FIFO, +}; + +struct bm1390_data_buf { + u32 pressure; + __be16 temp; + s64 ts __aligned(8); +}; + +/* BM1390 has FIFO for 4 pressure samples */ +#define BM1390_FIFO_LENGTH 4 + +struct bm1390_data { + s64 timestamp, old_timestamp; + struct iio_trigger *trig; + struct regmap *regmap; + struct device *dev; + struct bm1390_data_buf buf; + int irq; + unsigned int state; + bool trigger_enabled; + u8 watermark; + + /* Prevent accessing sensor during FIFO read sequence */ + struct mutex mutex; +}; + +enum { + BM1390_CHAN_PRESSURE, + BM1390_CHAN_TEMP, +}; + +static const struct iio_chan_spec bm1390_channels[] = { + { + .type = IIO_PRESSURE, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), + /* + * When IIR is used, we must fix amount of averaged samples. + * Thus we don't allow setting oversampling ratio. + */ + .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), + .scan_index = BM1390_CHAN_PRESSURE, + .scan_type = { + .sign = 'u', + .realbits = 22, + .storagebits = 32, + .endianness = IIO_LE, + }, + }, + { + .type = IIO_TEMP, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), + .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), + .scan_index = BM1390_CHAN_TEMP, + .scan_type = { + .sign = 's', + .realbits = 16, + .storagebits = 16, + .endianness = IIO_BE, + }, + }, + IIO_CHAN_SOFT_TIMESTAMP(2), +}; + +/* + * We can't skip reading the pressure because the watermark IRQ is acked + * only when the pressure data is read from the FIFO. + */ +static const unsigned long bm1390_scan_masks[] = { + BIT(BM1390_CHAN_PRESSURE), + BIT(BM1390_CHAN_PRESSURE) | BIT(BM1390_CHAN_TEMP), + 0 +}; + +static int bm1390_read_temp(struct bm1390_data *data, int *temp) +{ + __be16 temp_raw; + int ret; + + ret = regmap_bulk_read(data->regmap, BM1390_REG_TEMP_HI, &temp_raw, + sizeof(temp_raw)); + if (ret) + return ret; + + *temp = be16_to_cpu(temp_raw); + + return 0; +} + +static int bm1390_pressure_read(struct bm1390_data *data, u32 *pressure) +{ + /* Pressure data is in 3 8-bit registers */ + u8 raw[3]; + int ret; + + ret = regmap_bulk_read(data->regmap, BM1390_REG_PRESSURE_BASE, + raw, sizeof(raw)); + if (ret < 0) + return ret; + + *pressure = (u32)(raw[2] >> 2 | raw[1] << 6 | raw[0] << 14); + + return 0; +} + + /* The enum values map directly to register bits */ +enum bm1390_meas_mode { + BM1390_MEAS_MODE_STOP = 0x0, + BM1390_MEAS_MODE_1SHOT = 0x1, + BM1390_MEAS_MODE_CONTINUOUS = 0x2, +}; + +static int bm1390_meas_set(struct bm1390_data *data, enum bm1390_meas_mode mode) +{ + return regmap_update_bits(data->regmap, BM1390_REG_MODE_CTRL, + BM1390_MASK_MEAS_MODE, mode); +} + +/* + * If the trigger is not used we just wait until the measurement has + * completed. The data-sheet says maximum measurement cycle (regardless + * the AVE_NUM) is 200 mS so let's just sleep at least that long. If speed + * is needed the trigger should be used. + */ +#define BM1390_MAX_MEAS_TIME_MS 205 + +static int bm1390_read_data(struct bm1390_data *data, + struct iio_chan_spec const *chan, int *val, int *val2) +{ + int ret, warn; + + mutex_lock(&data->mutex); + /* + * We use 'continuous mode' even for raw read because according to the + * data-sheet an one-shot mode can't be used with IIR filter. + */ + ret = bm1390_meas_set(data, BM1390_MEAS_MODE_CONTINUOUS); + if (ret) + goto unlock_out; + + switch (chan->type) { + case IIO_PRESSURE: + msleep(BM1390_MAX_MEAS_TIME_MS); + ret = bm1390_pressure_read(data, val); + break; + case IIO_TEMP: + msleep(BM1390_MAX_MEAS_TIME_MS); + ret = bm1390_read_temp(data, val); + break; + default: + ret = -EINVAL; + } + warn = bm1390_meas_set(data, BM1390_MEAS_MODE_STOP); + if (warn) + dev_warn(data->dev, "Failed to stop measurement (%d)\n", warn); +unlock_out: + mutex_unlock(&data->mutex); + + return ret; +} + +static int bm1390_read_raw(struct iio_dev *idev, + struct iio_chan_spec const *chan, + int *val, int *val2, long mask) +{ + struct bm1390_data *data = iio_priv(idev); + int ret; + + switch (mask) { + case IIO_CHAN_INFO_SCALE: + if (chan->type == IIO_TEMP) { + *val = 31; + *val2 = 250000; + + return IIO_VAL_INT_PLUS_MICRO; + } else if (chan->type == IIO_PRESSURE) { + /* + * pressure in hPa is register value divided by 2048. + * This means kPa is 1/20480 times the register value, + */ + *val = 1; + *val2 = 2048; + + return IIO_VAL_FRACTIONAL; + } + + return -EINVAL; + case IIO_CHAN_INFO_RAW: + ret = iio_device_claim_direct_mode(idev); + if (ret) + return ret; + + ret = bm1390_read_data(data, chan, val, val2); + iio_device_release_direct_mode(idev); + if (ret) + return ret; + + return IIO_VAL_INT; + default: + return -EINVAL; + } +} + +static int __bm1390_fifo_flush(struct iio_dev *idev, unsigned int samples, + s64 timestamp) +{ + /* BM1390_FIFO_LENGTH is small so we shouldn't run out of stack */ + struct bm1390_data_buf buffer[BM1390_FIFO_LENGTH]; + struct bm1390_data *data = iio_priv(idev); + int smp_lvl, ret, i, warn, dummy; + u64 sample_period; + __be16 temp = 0; + + ret = regmap_read(data->regmap, BM1390_REG_FIFO_LVL, &smp_lvl); + if (ret) + return ret; + + smp_lvl = FIELD_GET(BM1390_MASK_FIFO_LVL, smp_lvl); + if (!smp_lvl) + return 0; + + if (smp_lvl > BM1390_FIFO_LENGTH) { + /* + * The fifo holds maximum of 4 samples so valid values + * should be 0, 1, 2, 3, 4 - rest are probably bit errors + * in I2C line. Don't overflow if this happens. + */ + dev_err(data->dev, "bad FIFO level %d\n", smp_lvl); + smp_lvl = BM1390_FIFO_LENGTH; + } + + sample_period = timestamp - data->old_timestamp; + do_div(sample_period, smp_lvl); + + if (samples && smp_lvl > samples) + smp_lvl = samples; + + + /* + * After some testing it appears that the temperature is not readable + * until the FIFO access has been done after the WMI. Thus, we need + * to read the all pressure values to memory and read the temperature + * only after that. + */ + for (i = 0; i < smp_lvl; i++) { + /* + * When we start reading data from the FIFO the sensor goes to + * special FIFO reading mode. If any other register is accessed + * during the FIFO read, samples can be dropped. Prevent access + * until FIFO_LVL is read. We have mutex locked and we do also + * go performing reading of FIFO_LVL even if this read fails. + */ + if (test_bit(BM1390_CHAN_PRESSURE, idev->active_scan_mask)) { + ret = bm1390_pressure_read(data, &buffer[i].pressure); + if (ret) + break; + } + + /* + * Old timestamp is either the previous sample IRQ time, + * previous flush-time or, if this was first sample, the enable + * time. When we add a sample period to that we should get the + * best approximation of the time-stamp we are handling. + * + * Idea is to always keep the "old_timestamp" matching the + * timestamp which we are currently handling. + */ + data->old_timestamp += sample_period; + buffer[i].ts = data->old_timestamp; + } + /* Reading the FIFO_LVL closes the FIFO access sequence */ + warn = regmap_read(data->regmap, BM1390_REG_FIFO_LVL, &dummy); + if (warn) + dev_warn(data->dev, "Closing FIFO sequence failed\n"); + + if (ret) + return ret; + + if (test_bit(BM1390_CHAN_TEMP, idev->active_scan_mask)) { + ret = regmap_bulk_read(data->regmap, BM1390_REG_TEMP_HI, &temp, + sizeof(temp)); + if (ret) + return ret; + } + + if (ret) + return ret; + + for (i = 0; i < smp_lvl; i++) { + buffer[i].temp = temp; + iio_push_to_buffers(idev, &buffer[i]); + } + + return smp_lvl; +} + +static int bm1390_fifo_flush(struct iio_dev *idev, unsigned int samples) +{ + struct bm1390_data *data = iio_priv(idev); + s64 timestamp; + int ret; + + /* + * If fifo_flush is being called from IRQ handler we know the stored + * timestamp is fairly accurate for the last stored sample. If we are + * called as a result of a read operation from userspace and hence + * before the watermark interrupt was triggered, take a timestamp + * now. We can fall anywhere in between two samples so the error in this + * case is at most one sample period. + * We need to have the IRQ disabled or we risk of messing-up + * the timestamps. If we are ran from IRQ, then the + * IRQF_ONESHOT has us covered - but if we are ran by the + * user-space read we need to disable the IRQ to be on a safe + * side. We do this usng synchronous disable so that if the + * IRQ thread is being ran on other CPU we wait for it to be + * finished. + */ + + timestamp = iio_get_time_ns(idev); + mutex_lock(&data->mutex); + ret = __bm1390_fifo_flush(idev, samples, timestamp); + mutex_unlock(&data->mutex); + + return ret; +} + +static int bm1390_set_watermark(struct iio_dev *idev, unsigned int val) +{ + struct bm1390_data *data = iio_priv(idev); + + if (val < BM1390_WMI_MIN || val > BM1390_WMI_MAX) + return -EINVAL; + + mutex_lock(&data->mutex); + data->watermark = val; + mutex_unlock(&data->mutex); + + return 0; +} + +static const struct iio_info bm1390_noirq_info = { + .read_raw = &bm1390_read_raw, +}; + +static const struct iio_info bm1390_info = { + .read_raw = &bm1390_read_raw, + .hwfifo_set_watermark = bm1390_set_watermark, + .hwfifo_flush_to_buffer = bm1390_fifo_flush, +}; + +static int bm1390_chip_init(struct bm1390_data *data) +{ + int ret; + + ret = regmap_write_bits(data->regmap, BM1390_REG_POWER, + BM1390_MASK_POWER, BM1390_POWER_ON); + if (ret) + return ret; + + msleep(1); + + ret = regmap_write_bits(data->regmap, BM1390_REG_RESET, + BM1390_MASK_RESET, BM1390_RESET); + if (ret) + return ret; + + msleep(1); + + ret = regmap_write_bits(data->regmap, BM1390_REG_RESET, + BM1390_MASK_RESET, BM1390_RESET_RELEASE); + if (ret) + return ret; + + msleep(1); + + ret = regmap_reinit_cache(data->regmap, &bm1390_regmap); + if (ret) { + dev_err(data->dev, "Failed to reinit reg cache\n"); + return ret; + } + + /* + * Default to use IIR filter in "middle" mode. Also the AVE_NUM must + * be fixed when IIR is in use. + */ + ret = regmap_update_bits(data->regmap, BM1390_REG_MODE_CTRL, + BM1390_MASK_AVE_NUM, BM1390_IIR_AVE_NUM); + if (ret) + return ret; + + return regmap_update_bits(data->regmap, BM1390_REG_FIFO_CTRL, + BM1390_MASK_IIR_MODE, BM1390_IIR_MODE_MID); +} + +static int bm1390_fifo_set_wmi(struct bm1390_data *data) +{ + u8 regval; + + regval = FIELD_PREP(BM1390_MASK_FIFO_LEN, + data->watermark - BM1390_WMI_MIN); + + return regmap_update_bits(data->regmap, BM1390_REG_FIFO_CTRL, + BM1390_MASK_FIFO_LEN, regval); +} + +static int bm1390_fifo_enable(struct iio_dev *idev) +{ + struct bm1390_data *data = iio_priv(idev); + int ret; + + /* We can't do buffered stuff without IRQ as we never get WMI */ + if (data->irq <= 0) + return -EINVAL; + + mutex_lock(&data->mutex); + if (data->trigger_enabled) { + ret = -EBUSY; + goto unlock_out; + } + + /* Update watermark to HW */ + ret = bm1390_fifo_set_wmi(data); + if (ret) + goto unlock_out; + + /* Enable WMI_IRQ */ + ret = regmap_set_bits(data->regmap, BM1390_REG_MODE_CTRL, + BM1390_MASK_WMI_EN); + if (ret) + goto unlock_out; + + /* Enable FIFO */ + ret = regmap_set_bits(data->regmap, BM1390_REG_FIFO_CTRL, + BM1390_MASK_FIFO_EN); + if (ret) + goto unlock_out; + + data->state = BM1390_STATE_FIFO; + + data->old_timestamp = iio_get_time_ns(idev); + ret = bm1390_meas_set(data, BM1390_MEAS_MODE_CONTINUOUS); + +unlock_out: + mutex_unlock(&data->mutex); + + return ret; +} + +static int bm1390_fifo_disable(struct iio_dev *idev) +{ + struct bm1390_data *data = iio_priv(idev); + int ret; + + msleep(1); + + mutex_lock(&data->mutex); + ret = bm1390_meas_set(data, BM1390_MEAS_MODE_STOP); + if (ret) + goto unlock_out; + + /* Disable FIFO */ + ret = regmap_clear_bits(data->regmap, BM1390_REG_FIFO_CTRL, + BM1390_MASK_FIFO_EN); + if (ret) + goto unlock_out; + + data->state = BM1390_STATE_SAMPLE; + + /* Disable WMI_IRQ */ + ret = regmap_clear_bits(data->regmap, BM1390_REG_MODE_CTRL, + BM1390_MASK_WMI_EN); + +unlock_out: + mutex_unlock(&data->mutex); + + return ret; +} + +static int bm1390_buffer_postenable(struct iio_dev *idev) +{ + /* + * If we use data-ready trigger, then the IRQ masks should be handled by + * trigger enable and the hardware buffer is not used but we just update + * results to the IIO FIFO when data-ready triggers. + */ + if (iio_device_get_current_mode(idev) == INDIO_BUFFER_TRIGGERED) + return 0; + + return bm1390_fifo_enable(idev); +} + +static int bm1390_buffer_predisable(struct iio_dev *idev) +{ + if (iio_device_get_current_mode(idev) == INDIO_BUFFER_TRIGGERED) + return 0; + + return bm1390_fifo_disable(idev); +} + +static const struct iio_buffer_setup_ops bm1390_buffer_ops = { + .postenable = bm1390_buffer_postenable, + .predisable = bm1390_buffer_predisable, +}; + +static irqreturn_t bm1390_trigger_handler(int irq, void *p) +{ + struct iio_poll_func *pf = p; + struct iio_dev *idev = pf->indio_dev; + struct bm1390_data *data = iio_priv(idev); + int ret, status; + + /* DRDY is acked by reading status reg */ + ret = regmap_read(data->regmap, BM1390_REG_STATUS, &status); + if (ret || !status) + return IRQ_NONE; + + dev_dbg(data->dev, "DRDY trig status 0x%x\n", status); + + if (test_bit(BM1390_CHAN_PRESSURE, idev->active_scan_mask)) { + ret = bm1390_pressure_read(data, &data->buf.pressure); + if (ret) { + dev_warn(data->dev, "sample read failed %d\n", ret); + return IRQ_NONE; + } + } + + if (test_bit(BM1390_CHAN_TEMP, idev->active_scan_mask)) { + ret = regmap_bulk_read(data->regmap, BM1390_REG_TEMP_HI, + &data->buf.temp, sizeof(data->buf.temp)); + if (ret) { + dev_warn(data->dev, "temp read failed %d\n", ret); + return IRQ_HANDLED; + } + } + + iio_push_to_buffers_with_timestamp(idev, &data->buf, data->timestamp); + iio_trigger_notify_done(idev->trig); + + return IRQ_HANDLED; +} + +/* Get timestamps and wake the thread if we need to read data */ +static irqreturn_t bm1390_irq_handler(int irq, void *private) +{ + struct iio_dev *idev = private; + struct bm1390_data *data = iio_priv(idev); + + data->timestamp = iio_get_time_ns(idev); + + if (data->state == BM1390_STATE_FIFO || data->trigger_enabled) + return IRQ_WAKE_THREAD; + + return IRQ_NONE; +} + +static irqreturn_t bm1390_irq_thread_handler(int irq, void *private) +{ + struct iio_dev *idev = private; + struct bm1390_data *data = iio_priv(idev); + int ret = IRQ_NONE; + + mutex_lock(&data->mutex); + + if (data->trigger_enabled) { + iio_trigger_poll_nested(data->trig); + ret = IRQ_HANDLED; + } else if (data->state == BM1390_STATE_FIFO) { + int ok; + + ok = __bm1390_fifo_flush(idev, BM1390_FIFO_LENGTH, + data->timestamp); + if (ok > 0) + ret = IRQ_HANDLED; + } + + mutex_unlock(&data->mutex); + + return ret; +} + +static int bm1390_set_drdy_irq(struct bm1390_data *data, bool en) +{ + if (en) + return regmap_set_bits(data->regmap, BM1390_REG_MODE_CTRL, + BM1390_MASK_DRDY_EN); + return regmap_clear_bits(data->regmap, BM1390_REG_MODE_CTRL, + BM1390_MASK_DRDY_EN); +} + +static int bm1390_trigger_set_state(struct iio_trigger *trig, + bool state) +{ + struct bm1390_data *data = iio_trigger_get_drvdata(trig); + int ret = 0; + + mutex_lock(&data->mutex); + + if (data->trigger_enabled == state) + goto unlock_out; + + if (data->state == BM1390_STATE_FIFO) { + dev_warn(data->dev, "Can't set trigger when FIFO enabled\n"); + ret = -EBUSY; + goto unlock_out; + } + + data->trigger_enabled = state; + + if (state) { + ret = bm1390_meas_set(data, BM1390_MEAS_MODE_CONTINUOUS); + if (ret) + goto unlock_out; + } else { + int dummy; + + ret = bm1390_meas_set(data, BM1390_MEAS_MODE_STOP); + if (ret) + goto unlock_out; + + /* + * We need to read the status register in order to ACK the + * data-ready which may have been generated just before we + * disabled the measurement. + */ + ret = regmap_read(data->regmap, BM1390_REG_STATUS, &dummy); + if (ret) + dev_warn(data->dev, "status read failed\n"); + } + + ret = bm1390_set_drdy_irq(data, state); + +unlock_out: + mutex_unlock(&data->mutex); + + return ret; +} + +static const struct iio_trigger_ops bm1390_trigger_ops = { + .set_trigger_state = bm1390_trigger_set_state, +}; + +static int bm1390_setup_buffer(struct bm1390_data *data, struct iio_dev *idev) +{ + int ret; + + ret = devm_iio_triggered_buffer_setup(data->dev, idev, + &iio_pollfunc_store_time, + &bm1390_trigger_handler, + &bm1390_buffer_ops); + + if (ret) + return dev_err_probe(data->dev, ret, + "iio_triggered_buffer_setup FAIL\n"); + + idev->available_scan_masks = bm1390_scan_masks; + + return 0; +} + +static int bm1390_setup_trigger(struct bm1390_data *data, struct iio_dev *idev, + int irq) +{ + struct iio_trigger *itrig; + char *name; + int ret; + + itrig = devm_iio_trigger_alloc(data->dev, "%sdata-rdy-dev%d", idev->name, + iio_device_id(idev)); + if (!itrig) + return -ENOMEM; + + data->trig = itrig; + + itrig->ops = &bm1390_trigger_ops; + iio_trigger_set_drvdata(itrig, data); + + name = devm_kasprintf(data->dev, GFP_KERNEL, "%s-bm1390", + dev_name(data->dev)); + if (name == NULL) + return -ENOMEM; + + ret = devm_request_threaded_irq(data->dev, irq, bm1390_irq_handler, + &bm1390_irq_thread_handler, + IRQF_ONESHOT, name, idev); + if (ret) + return dev_err_probe(data->dev, ret, "Could not request IRQ\n"); + + + ret = devm_iio_trigger_register(data->dev, itrig); + if (ret) + return dev_err_probe(data->dev, ret, + "Trigger registration failed\n"); + + return 0; +} + +static int bm1390_probe(struct i2c_client *i2c) +{ + struct bm1390_data *data; + struct regmap *regmap; + struct iio_dev *idev; + struct device *dev; + unsigned int part_id; + int ret; + + dev = &i2c->dev; + + regmap = devm_regmap_init_i2c(i2c, &bm1390_regmap); + if (IS_ERR(regmap)) + return dev_err_probe(dev, PTR_ERR(regmap), + "Failed to initialize Regmap\n"); + + ret = devm_regulator_get_enable(dev, "vdd"); + if (ret) + return dev_err_probe(dev, ret, "Failed to get regulator\n"); + + ret = regmap_read(regmap, BM1390_REG_PART_ID, &part_id); + if (ret) + return dev_err_probe(dev, ret, "Failed to access sensor\n"); + + if (part_id != BM1390_ID) + dev_warn(dev, "unknown device 0x%x\n", part_id); + + idev = devm_iio_device_alloc(dev, sizeof(*data)); + if (!idev) + return -ENOMEM; + + data = iio_priv(idev); + data->regmap = regmap; + data->dev = dev; + data->irq = i2c->irq; + /* + * For now we just allow BM1390_WMI_MIN to BM1390_WMI_MAX and + * discard every other configuration when triggered mode is not used. + */ + data->watermark = BM1390_WMI_MAX; + mutex_init(&data->mutex); + + idev->channels = bm1390_channels; + idev->num_channels = ARRAY_SIZE(bm1390_channels); + idev->name = "bm1390"; + idev->modes = INDIO_DIRECT_MODE; + + ret = bm1390_chip_init(data); + if (ret) + return dev_err_probe(dev, ret, "sensor init failed\n"); + + ret = bm1390_setup_buffer(data, idev); + if (ret) + return ret; + + /* No trigger if we don't have IRQ for data-ready and WMI */ + if (i2c->irq > 0) { + idev->info = &bm1390_info; + idev->modes |= INDIO_BUFFER_SOFTWARE; + ret = bm1390_setup_trigger(data, idev, i2c->irq); + if (ret) + return ret; + } else { + idev->info = &bm1390_noirq_info; + } + + ret = devm_iio_device_register(dev, idev); + if (ret < 0) + return dev_err_probe(dev, ret, + "Unable to register iio device\n"); + + return 0; +} + +static const struct of_device_id bm1390_of_match[] = { + { .compatible = "rohm,bm1390glv-z" }, + {} +}; +MODULE_DEVICE_TABLE(of, bm1390_of_match); + +static const struct i2c_device_id bm1390_id[] = { + { "bm1390glv-z", }, + {} +}; +MODULE_DEVICE_TABLE(i2c, bm1390_id); + +static struct i2c_driver bm1390_driver = { + .driver = { + .name = "bm1390", + .of_match_table = bm1390_of_match, + /* + * Probing explicitly requires a few millisecond of sleep. + * Enabling the VDD regulator may include ramp up rates. + */ + .probe_type = PROBE_PREFER_ASYNCHRONOUS, + }, + .probe = bm1390_probe, + .id_table = bm1390_id, +}; +module_i2c_driver(bm1390_driver); + +MODULE_AUTHOR("Matti Vaittinen "); +MODULE_DESCRIPTION("Driver for ROHM BM1390 pressure sensor"); +MODULE_LICENSE("GPL"); From 3b4e0e9677551806766a1ffd19a4a365c10f43d9 Mon Sep 17 00:00:00 2001 From: Matti Vaittinen Date: Wed, 27 Sep 2023 11:28:29 +0300 Subject: [PATCH 187/326] MAINTAINERS: Add ROHM BM1390 Add myself as a maintainer for ROHM BM1390 pressure sensor driver. Signed-off-by: Matti Vaittinen Link: https://lore.kernel.org/r/fb19d3027ac19663789e18d4dc972a5dac0fde74.1695727471.git.mazziesaccount@gmail.com Signed-off-by: Jonathan Cameron --- MAINTAINERS | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index 0782484cceb8..4e07c032d06a 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -18570,6 +18570,12 @@ S: Maintained F: Documentation/devicetree/bindings/iio/light/bh1750.yaml F: drivers/iio/light/bh1750.c +ROHM BM1390 PRESSURE SENSOR DRIVER +M: Matti Vaittinen +L: linux-iio@vger.kernel.org +S: Supported +F: drivers/iio/pressure/rohm-bm1390.c + ROHM BU270xx LIGHT SENSOR DRIVERs M: Matti Vaittinen L: linux-iio@vger.kernel.org From 874bbd1219c70b0d14881214c9768a0e4598fad5 Mon Sep 17 00:00:00 2001 From: Alisa-Dariana Roman Date: Mon, 25 Sep 2023 00:51:46 +0300 Subject: [PATCH 188/326] iio: adc: ad7192: Use bitfield access macros Include bitfield.h and update driver to use bitfield access macros GENMASK, FIELD_PREP and FIELD_GET. Remove old macros in favor of using FIELD_PREP and masks. Change %d to %ld to match the type of FIELD_GET(). Signed-off-by: Alisa-Dariana Roman Link: https://lore.kernel.org/r/20230924215148.102491-2-alisadariana@gmail.com Signed-off-by: Jonathan Cameron --- drivers/iio/adc/ad7192.c | 73 ++++++++++++++++++++-------------------- 1 file changed, 37 insertions(+), 36 deletions(-) diff --git a/drivers/iio/adc/ad7192.c b/drivers/iio/adc/ad7192.c index 69d1103b9508..6fe3e7b7a606 100644 --- a/drivers/iio/adc/ad7192.c +++ b/drivers/iio/adc/ad7192.c @@ -6,6 +6,7 @@ */ #include +#include #include #include #include @@ -43,7 +44,7 @@ #define AD7192_COMM_WEN BIT(7) /* Write Enable */ #define AD7192_COMM_WRITE 0 /* Write Operation */ #define AD7192_COMM_READ BIT(6) /* Read Operation */ -#define AD7192_COMM_ADDR(x) (((x) & 0x7) << 3) /* Register Address */ +#define AD7192_COMM_ADDR_MASK GENMASK(5, 3) /* Register Address Mask */ #define AD7192_COMM_CREAD BIT(2) /* Continuous Read of Data Register */ /* Status Register Bit Designations (AD7192_REG_STAT) */ @@ -56,17 +57,16 @@ #define AD7192_STAT_CH1 BIT(0) /* Channel 1 */ /* Mode Register Bit Designations (AD7192_REG_MODE) */ -#define AD7192_MODE_SEL(x) (((x) & 0x7) << 21) /* Operation Mode Select */ -#define AD7192_MODE_SEL_MASK (0x7 << 21) /* Operation Mode Select Mask */ -#define AD7192_MODE_STA(x) (((x) & 0x1) << 20) /* Status Register transmission */ +#define AD7192_MODE_SEL_MASK GENMASK(23, 21) /* Operation Mode Select Mask */ #define AD7192_MODE_STA_MASK BIT(20) /* Status Register transmission Mask */ -#define AD7192_MODE_CLKSRC(x) (((x) & 0x3) << 18) /* Clock Source Select */ +#define AD7192_MODE_CLKSRC_MASK GENMASK(19, 18) /* Clock Source Select Mask */ #define AD7192_MODE_SINC3 BIT(15) /* SINC3 Filter Select */ #define AD7192_MODE_ENPAR BIT(13) /* Parity Enable */ #define AD7192_MODE_CLKDIV BIT(12) /* Clock divide by 2 (AD7190/2 only)*/ #define AD7192_MODE_SCYCLE BIT(11) /* Single cycle conversion */ #define AD7192_MODE_REJ60 BIT(10) /* 50/60Hz notch filter */ -#define AD7192_MODE_RATE(x) ((x) & 0x3FF) /* Filter Update Rate Select */ + /* Filter Update Rate Select Mask */ +#define AD7192_MODE_RATE_MASK GENMASK(9, 0) /* Mode Register: AD7192_MODE_SEL options */ #define AD7192_MODE_CONT 0 /* Continuous Conversion Mode */ @@ -92,13 +92,12 @@ #define AD7192_CONF_CHOP BIT(23) /* CHOP enable */ #define AD7192_CONF_ACX BIT(22) /* AC excitation enable(AD7195 only) */ #define AD7192_CONF_REFSEL BIT(20) /* REFIN1/REFIN2 Reference Select */ -#define AD7192_CONF_CHAN(x) ((x) << 8) /* Channel select */ -#define AD7192_CONF_CHAN_MASK (0x7FF << 8) /* Channel select mask */ +#define AD7192_CONF_CHAN_MASK GENMASK(18, 8) /* Channel select mask */ #define AD7192_CONF_BURN BIT(7) /* Burnout current enable */ #define AD7192_CONF_REFDET BIT(6) /* Reference detect enable */ #define AD7192_CONF_BUF BIT(4) /* Buffered Mode Enable */ #define AD7192_CONF_UNIPOLAR BIT(3) /* Unipolar/Bipolar Enable */ -#define AD7192_CONF_GAIN(x) ((x) & 0x7) /* Gain Select */ +#define AD7192_CONF_GAIN_MASK GENMASK(2, 0) /* Gain Select */ #define AD7192_CH_AIN1P_AIN2M BIT(0) /* AIN1(+) - AIN2(-) */ #define AD7192_CH_AIN3P_AIN4M BIT(1) /* AIN3(+) - AIN4(-) */ @@ -130,7 +129,7 @@ #define CHIPID_AD7192 0x0 #define CHIPID_AD7193 0x2 #define CHIPID_AD7195 0x6 -#define AD7192_ID_MASK 0x0F +#define AD7192_ID_MASK GENMASK(3, 0) /* GPOCON Register Bit Designations (AD7192_REG_GPOCON) */ #define AD7192_GPOCON_BPDSW BIT(6) /* Bridge power-down switch enable */ @@ -272,7 +271,7 @@ static int ad7192_set_channel(struct ad_sigma_delta *sd, unsigned int channel) struct ad7192_state *st = ad_sigma_delta_to_ad7192(sd); st->conf &= ~AD7192_CONF_CHAN_MASK; - st->conf |= AD7192_CONF_CHAN(channel); + st->conf |= FIELD_PREP(AD7192_CONF_CHAN_MASK, channel); return ad_sd_write_reg(&st->sd, AD7192_REG_CONF, 3, st->conf); } @@ -283,7 +282,7 @@ static int ad7192_set_mode(struct ad_sigma_delta *sd, struct ad7192_state *st = ad_sigma_delta_to_ad7192(sd); st->mode &= ~AD7192_MODE_SEL_MASK; - st->mode |= AD7192_MODE_SEL(mode); + st->mode |= FIELD_PREP(AD7192_MODE_SEL_MASK, mode); return ad_sd_write_reg(&st->sd, AD7192_REG_MODE, 3, st->mode); } @@ -295,7 +294,7 @@ static int ad7192_append_status(struct ad_sigma_delta *sd, bool append) int ret; mode &= ~AD7192_MODE_STA_MASK; - mode |= AD7192_MODE_STA(append); + mode |= FIELD_PREP(AD7192_MODE_STA_MASK, append); ret = ad_sd_write_reg(&st->sd, AD7192_REG_MODE, 3, mode); if (ret < 0) @@ -399,17 +398,17 @@ static int ad7192_setup(struct iio_dev *indio_dev, struct device_node *np) if (ret) return ret; - id &= AD7192_ID_MASK; + id = FIELD_GET(AD7192_ID_MASK, id); if (id != st->chip_info->chip_id) dev_warn(&st->sd.spi->dev, "device ID query failed (0x%X != 0x%X)\n", id, st->chip_info->chip_id); - st->mode = AD7192_MODE_SEL(AD7192_MODE_IDLE) | - AD7192_MODE_CLKSRC(st->clock_sel) | - AD7192_MODE_RATE(480); + st->mode = FIELD_PREP(AD7192_MODE_SEL_MASK, AD7192_MODE_IDLE) | + FIELD_PREP(AD7192_MODE_CLKSRC_MASK, st->clock_sel) | + FIELD_PREP(AD7192_MODE_RATE_MASK, 480); - st->conf = AD7192_CONF_GAIN(0); + st->conf = FIELD_PREP(AD7192_CONF_GAIN_MASK, 0); rej60_en = of_property_read_bool(np, "adi,rejection-60-Hz-enable"); if (rej60_en) @@ -455,7 +454,7 @@ static int ad7192_setup(struct iio_dev *indio_dev, struct device_node *np) for (i = 0; i < ARRAY_SIZE(st->scale_avail); i++) { scale_uv = ((u64)st->int_vref_mv * 100000000) >> (indio_dev->channels[0].scan_type.realbits - - ((st->conf & AD7192_CONF_UNIPOLAR) ? 0 : 1)); + !FIELD_GET(AD7192_CONF_UNIPOLAR, st->conf)); scale_uv >>= i; st->scale_avail[i][1] = do_div(scale_uv, 100000000) * 10; @@ -472,7 +471,7 @@ static ssize_t ad7192_show_ac_excitation(struct device *dev, struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct ad7192_state *st = iio_priv(indio_dev); - return sysfs_emit(buf, "%d\n", !!(st->conf & AD7192_CONF_ACX)); + return sysfs_emit(buf, "%ld\n", FIELD_GET(AD7192_CONF_ACX, st->conf)); } static ssize_t ad7192_show_bridge_switch(struct device *dev, @@ -482,7 +481,8 @@ static ssize_t ad7192_show_bridge_switch(struct device *dev, struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct ad7192_state *st = iio_priv(indio_dev); - return sysfs_emit(buf, "%d\n", !!(st->gpocon & AD7192_GPOCON_BPDSW)); + return sysfs_emit(buf, "%ld\n", + FIELD_GET(AD7192_GPOCON_BPDSW, st->gpocon)); } static ssize_t ad7192_set(struct device *dev, @@ -537,14 +537,14 @@ static void ad7192_get_available_filter_freq(struct ad7192_state *st, /* Formulas for filter at page 25 of the datasheet */ fadc = DIV_ROUND_CLOSEST(st->fclk, - AD7192_SYNC4_FILTER * AD7192_MODE_RATE(st->mode)); + AD7192_SYNC4_FILTER * FIELD_GET(AD7192_MODE_RATE_MASK, st->mode)); freq[0] = DIV_ROUND_CLOSEST(fadc * 240, 1024); fadc = DIV_ROUND_CLOSEST(st->fclk, - AD7192_SYNC3_FILTER * AD7192_MODE_RATE(st->mode)); + AD7192_SYNC3_FILTER * FIELD_GET(AD7192_MODE_RATE_MASK, st->mode)); freq[1] = DIV_ROUND_CLOSEST(fadc * 240, 1024); - fadc = DIV_ROUND_CLOSEST(st->fclk, AD7192_MODE_RATE(st->mode)); + fadc = DIV_ROUND_CLOSEST(st->fclk, FIELD_GET(AD7192_MODE_RATE_MASK, st->mode)); freq[2] = DIV_ROUND_CLOSEST(fadc * 230, 1024); freq[3] = DIV_ROUND_CLOSEST(fadc * 272, 1024); } @@ -665,11 +665,11 @@ static int ad7192_get_3db_filter_freq(struct ad7192_state *st) unsigned int fadc; fadc = DIV_ROUND_CLOSEST(st->fclk, - st->f_order * AD7192_MODE_RATE(st->mode)); + st->f_order * FIELD_GET(AD7192_MODE_RATE_MASK, st->mode)); - if (st->conf & AD7192_CONF_CHOP) + if (FIELD_GET(AD7192_CONF_CHOP, st->conf)) return DIV_ROUND_CLOSEST(fadc * 240, 1024); - if (st->mode & AD7192_MODE_SINC3) + if (FIELD_GET(AD7192_MODE_SINC3, st->mode)) return DIV_ROUND_CLOSEST(fadc * 272, 1024); else return DIV_ROUND_CLOSEST(fadc * 230, 1024); @@ -682,7 +682,8 @@ static int ad7192_read_raw(struct iio_dev *indio_dev, long m) { struct ad7192_state *st = iio_priv(indio_dev); - bool unipolar = !!(st->conf & AD7192_CONF_UNIPOLAR); + bool unipolar = FIELD_GET(AD7192_CONF_UNIPOLAR, st->conf); + u8 gain = FIELD_GET(AD7192_CONF_GAIN_MASK, st->conf); switch (m) { case IIO_CHAN_INFO_RAW: @@ -691,8 +692,8 @@ static int ad7192_read_raw(struct iio_dev *indio_dev, switch (chan->type) { case IIO_VOLTAGE: mutex_lock(&st->lock); - *val = st->scale_avail[AD7192_CONF_GAIN(st->conf)][0]; - *val2 = st->scale_avail[AD7192_CONF_GAIN(st->conf)][1]; + *val = st->scale_avail[gain][0]; + *val2 = st->scale_avail[gain][1]; mutex_unlock(&st->lock); return IIO_VAL_INT_PLUS_NANO; case IIO_TEMP: @@ -713,7 +714,7 @@ static int ad7192_read_raw(struct iio_dev *indio_dev, return IIO_VAL_INT; case IIO_CHAN_INFO_SAMP_FREQ: *val = st->fclk / - (st->f_order * 1024 * AD7192_MODE_RATE(st->mode)); + (st->f_order * 1024 * FIELD_GET(AD7192_MODE_RATE_MASK, st->mode)); return IIO_VAL_INT; case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY: *val = ad7192_get_3db_filter_freq(st); @@ -746,8 +747,8 @@ static int ad7192_write_raw(struct iio_dev *indio_dev, if (val2 == st->scale_avail[i][1]) { ret = 0; tmp = st->conf; - st->conf &= ~AD7192_CONF_GAIN(-1); - st->conf |= AD7192_CONF_GAIN(i); + st->conf &= ~AD7192_CONF_GAIN_MASK; + st->conf |= FIELD_PREP(AD7192_CONF_GAIN_MASK, i); if (tmp == st->conf) break; ad_sd_write_reg(&st->sd, AD7192_REG_CONF, @@ -769,8 +770,8 @@ static int ad7192_write_raw(struct iio_dev *indio_dev, break; } - st->mode &= ~AD7192_MODE_RATE(-1); - st->mode |= AD7192_MODE_RATE(div); + st->mode &= ~AD7192_MODE_RATE_MASK; + st->mode |= FIELD_PREP(AD7192_MODE_RATE_MASK, div); ad_sd_write_reg(&st->sd, AD7192_REG_MODE, 3, st->mode); break; case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY: @@ -830,7 +831,7 @@ static int ad7192_update_scan_mode(struct iio_dev *indio_dev, const unsigned lon conf &= ~AD7192_CONF_CHAN_MASK; for_each_set_bit(i, scan_mask, 8) - conf |= AD7192_CONF_CHAN(i); + conf |= FIELD_PREP(AD7192_CONF_CHAN_MASK, i); ret = ad_sd_write_reg(&st->sd, AD7192_REG_CONF, 3, conf); if (ret < 0) From e49075c7e9420b11b8e1aa8434e8790282df4a39 Mon Sep 17 00:00:00 2001 From: Alisa-Dariana Roman Date: Mon, 25 Sep 2023 00:51:47 +0300 Subject: [PATCH 189/326] iio: adc: ad7192: Improve f_order computation Instead of using the f_order member of ad7192_state, a function that computes the f_order coefficient makes more sense. This coefficient is a function of the sinc filter and chop filter states. Remove f_order member of ad7192_state structure. Instead use ad7192_compute_f_order function to compute the f_order coefficient according to the sinc filter and chop filter states passed as parameters. Add ad7192_get_f_order function that returns the current f_order coefficient of the device. Add ad7192_compute_f_adc function that computes the f_adc value according to the sinc filter and chop filter states passed as parameters. Add ad7192_get_f_adc function that returns the current f_adc value of the device. Signed-off-by: Alisa-Dariana Roman Link: https://lore.kernel.org/r/20230924215148.102491-3-alisadariana@gmail.com Signed-off-by: Jonathan Cameron --- drivers/iio/adc/ad7192.c | 62 +++++++++++++++++++++++++++++----------- 1 file changed, 46 insertions(+), 16 deletions(-) diff --git a/drivers/iio/adc/ad7192.c b/drivers/iio/adc/ad7192.c index 6fe3e7b7a606..e0be394ccb34 100644 --- a/drivers/iio/adc/ad7192.c +++ b/drivers/iio/adc/ad7192.c @@ -179,7 +179,6 @@ struct ad7192_state { struct clk *mclk; u16 int_vref_mv; u32 fclk; - u32 f_order; u32 mode; u32 conf; u32 scale_avail[8][2]; @@ -419,7 +418,6 @@ static int ad7192_setup(struct iio_dev *indio_dev, struct device_node *np) st->conf |= AD7192_CONF_REFSEL; st->conf &= ~AD7192_CONF_CHOP; - st->f_order = AD7192_NO_SYNC_FILTER; buf_en = of_property_read_bool(np, "adi,buffer-enable"); if (buf_en) @@ -530,22 +528,60 @@ static ssize_t ad7192_set(struct device *dev, return ret ? ret : len; } +static int ad7192_compute_f_order(bool sinc3_en, bool chop_en) +{ + if (!chop_en) + return 1; + + if (sinc3_en) + return AD7192_SYNC3_FILTER; + + return AD7192_SYNC4_FILTER; +} + +static int ad7192_get_f_order(struct ad7192_state *st) +{ + bool sinc3_en, chop_en; + + sinc3_en = FIELD_GET(AD7192_MODE_SINC3, st->mode); + chop_en = FIELD_GET(AD7192_CONF_CHOP, st->conf); + + return ad7192_compute_f_order(sinc3_en, chop_en); +} + +static int ad7192_compute_f_adc(struct ad7192_state *st, bool sinc3_en, + bool chop_en) +{ + unsigned int f_order = ad7192_compute_f_order(sinc3_en, chop_en); + + return DIV_ROUND_CLOSEST(st->fclk, + f_order * FIELD_GET(AD7192_MODE_RATE_MASK, st->mode)); +} + +static int ad7192_get_f_adc(struct ad7192_state *st) +{ + unsigned int f_order = ad7192_get_f_order(st); + + return DIV_ROUND_CLOSEST(st->fclk, + f_order * FIELD_GET(AD7192_MODE_RATE_MASK, st->mode)); +} + static void ad7192_get_available_filter_freq(struct ad7192_state *st, int *freq) { unsigned int fadc; /* Formulas for filter at page 25 of the datasheet */ - fadc = DIV_ROUND_CLOSEST(st->fclk, - AD7192_SYNC4_FILTER * FIELD_GET(AD7192_MODE_RATE_MASK, st->mode)); + fadc = ad7192_compute_f_adc(st, false, true); freq[0] = DIV_ROUND_CLOSEST(fadc * 240, 1024); - fadc = DIV_ROUND_CLOSEST(st->fclk, - AD7192_SYNC3_FILTER * FIELD_GET(AD7192_MODE_RATE_MASK, st->mode)); + fadc = ad7192_compute_f_adc(st, true, true); freq[1] = DIV_ROUND_CLOSEST(fadc * 240, 1024); - fadc = DIV_ROUND_CLOSEST(st->fclk, FIELD_GET(AD7192_MODE_RATE_MASK, st->mode)); + fadc = ad7192_compute_f_adc(st, false, false); freq[2] = DIV_ROUND_CLOSEST(fadc * 230, 1024); + + fadc = ad7192_compute_f_adc(st, true, false); freq[3] = DIV_ROUND_CLOSEST(fadc * 272, 1024); } @@ -628,25 +664,21 @@ static int ad7192_set_3db_filter_freq(struct ad7192_state *st, switch (idx) { case 0: - st->f_order = AD7192_SYNC4_FILTER; st->mode &= ~AD7192_MODE_SINC3; st->conf |= AD7192_CONF_CHOP; break; case 1: - st->f_order = AD7192_SYNC3_FILTER; st->mode |= AD7192_MODE_SINC3; st->conf |= AD7192_CONF_CHOP; break; case 2: - st->f_order = AD7192_NO_SYNC_FILTER; st->mode &= ~AD7192_MODE_SINC3; st->conf &= ~AD7192_CONF_CHOP; break; case 3: - st->f_order = AD7192_NO_SYNC_FILTER; st->mode |= AD7192_MODE_SINC3; st->conf &= ~AD7192_CONF_CHOP; @@ -664,8 +696,7 @@ static int ad7192_get_3db_filter_freq(struct ad7192_state *st) { unsigned int fadc; - fadc = DIV_ROUND_CLOSEST(st->fclk, - st->f_order * FIELD_GET(AD7192_MODE_RATE_MASK, st->mode)); + fadc = ad7192_get_f_adc(st); if (FIELD_GET(AD7192_CONF_CHOP, st->conf)) return DIV_ROUND_CLOSEST(fadc * 240, 1024); @@ -713,8 +744,7 @@ static int ad7192_read_raw(struct iio_dev *indio_dev, *val -= 273 * ad7192_get_temp_scale(unipolar); return IIO_VAL_INT; case IIO_CHAN_INFO_SAMP_FREQ: - *val = st->fclk / - (st->f_order * 1024 * FIELD_GET(AD7192_MODE_RATE_MASK, st->mode)); + *val = DIV_ROUND_CLOSEST(ad7192_get_f_adc(st), 1024); return IIO_VAL_INT; case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY: *val = ad7192_get_3db_filter_freq(st); @@ -764,7 +794,7 @@ static int ad7192_write_raw(struct iio_dev *indio_dev, break; } - div = st->fclk / (val * st->f_order * 1024); + div = st->fclk / (val * ad7192_get_f_order(st) * 1024); if (div < 1 || div > 1023) { ret = -EINVAL; break; From a68ad2062fb2fb227a022b0392398bb53fd75012 Mon Sep 17 00:00:00 2001 From: Matti Vaittinen Date: Thu, 28 Sep 2023 11:45:21 +0300 Subject: [PATCH 190/326] dt-bindings: iio: Add KX132ACR-LBZ accelerometer ROHM KX132ACR-LBZ is an accelerometer for industrial applications. It has a subset of KX022A functionalities, dropping support for tap, free fall and tilt detection engines. Also, the register interface is an exact subset of what is found on KX022A. Extend the kionix,kx022a.yaml file to support the KX132ACR-LBZ device Signed-off-by: Matti Vaittinen Acked-by: Conor Dooley Link: https://lore.kernel.org/r/5c9e03ffad5e6e5970d6e71fb02eab4b652e109f.1695879676.git.mazziesaccount@gmail.com Signed-off-by: Jonathan Cameron --- .../devicetree/bindings/iio/accel/kionix,kx022a.yaml | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/Documentation/devicetree/bindings/iio/accel/kionix,kx022a.yaml b/Documentation/devicetree/bindings/iio/accel/kionix,kx022a.yaml index 034b69614416..66ea894dbe55 100644 --- a/Documentation/devicetree/bindings/iio/accel/kionix,kx022a.yaml +++ b/Documentation/devicetree/bindings/iio/accel/kionix,kx022a.yaml @@ -4,21 +4,23 @@ $id: http://devicetree.org/schemas/iio/accel/kionix,kx022a.yaml# $schema: http://devicetree.org/meta-schemas/core.yaml# -title: ROHM/Kionix KX022A and KX132-1211 Accelerometers +title: ROHM/Kionix KX022A, KX132-1211 and KX132ACR-LBZ Accelerometers maintainers: - Matti Vaittinen description: | - KX022A and KX132-1211 are 3-axis accelerometers supporting +/- 2G, 4G, 8G and - 16G ranges, variable output data-rates and a hardware-fifo buffering. - KX022A and KX132-1211 can be accessed either via I2C or SPI. + KX022A, KX132ACR-LBZ and KX132-1211 are 3-axis accelerometers supporting + +/- 2G, 4G, 8G and 16G ranges, variable output data-rates and a + hardware-fifo buffering. These accelerometers can be accessed either + via I2C or SPI. properties: compatible: enum: - kionix,kx022a - kionix,kx132-1211 + - rohm,kx132acr-lbz reg: maxItems: 1 From 1c8af63782583ee9d3a95e971a26570ae3f25af6 Mon Sep 17 00:00:00 2001 From: Matti Vaittinen Date: Thu, 28 Sep 2023 11:45:39 +0300 Subject: [PATCH 191/326] iio: kx022a: Support ROHM KX132ACR-LBZ dt-bindings: iio: Add KX132ACR-LBZ accelerometer ROHM KX132ACR-LBZ is an accelerometer for industrial applications. It has a subset of KX022A functionalities, dropping support for tap, free fall and tilt detection engines. Also, the register interface is an exact subset of what is found on KX022A (except the WHO_AM_I register value). Add support for KX132ACR-LBZ. Signed-off-by: Matti Vaittinen Link: https://lore.kernel.org/r/272065b9f35b817aff86b7760ff1aaaaaaa969f5.1695879676.git.mazziesaccount@gmail.com Signed-off-by: Jonathan Cameron --- drivers/iio/accel/Kconfig | 4 ++-- drivers/iio/accel/kionix-kx022a-i2c.c | 4 +++- drivers/iio/accel/kionix-kx022a-spi.c | 4 +++- drivers/iio/accel/kionix-kx022a.c | 34 ++++++++++++++++++++++++++- drivers/iio/accel/kionix-kx022a.h | 2 ++ 5 files changed, 43 insertions(+), 5 deletions(-) diff --git a/drivers/iio/accel/Kconfig b/drivers/iio/accel/Kconfig index 373257d64a7e..f113dae59048 100644 --- a/drivers/iio/accel/Kconfig +++ b/drivers/iio/accel/Kconfig @@ -420,7 +420,7 @@ config IIO_KX022A_SPI help Enable support for the Kionix digital tri-axis accelerometers connected to SPI interface. Supported devices are: - KX022A, KX132-1211 + KX022A, KX132-1211, KX132ACR-LBZ config IIO_KX022A_I2C tristate "Kionix KX022A tri-axis digital accelerometer I2C interface" @@ -430,7 +430,7 @@ config IIO_KX022A_I2C help Enable support for the Kionix digital tri-axis accelerometers connected to I2C interface. Supported devices are: - KX022A, KX132-1211 + KX022A, KX132-1211, KX132ACR-LBZ config KXSD9 tristate "Kionix KXSD9 Accelerometer Driver" diff --git a/drivers/iio/accel/kionix-kx022a-i2c.c b/drivers/iio/accel/kionix-kx022a-i2c.c index fc53e527cae0..8a1d4fc28ddd 100644 --- a/drivers/iio/accel/kionix-kx022a-i2c.c +++ b/drivers/iio/accel/kionix-kx022a-i2c.c @@ -2,7 +2,7 @@ /* * Copyright (C) 2022 ROHM Semiconductors * - * ROHM/KIONIX KX022A accelerometer driver + * ROHM/KIONIX accelerometer driver */ #include @@ -38,6 +38,7 @@ static int kx022a_i2c_probe(struct i2c_client *i2c) static const struct i2c_device_id kx022a_i2c_id[] = { { .name = "kx022a", .driver_data = (kernel_ulong_t)&kx022a_chip_info }, { .name = "kx132-1211", .driver_data = (kernel_ulong_t)&kx132_chip_info }, + { .name = "kx132acr-lbz", .driver_data = (kernel_ulong_t)&kx132acr_chip_info }, { } }; MODULE_DEVICE_TABLE(i2c, kx022a_i2c_id); @@ -45,6 +46,7 @@ MODULE_DEVICE_TABLE(i2c, kx022a_i2c_id); static const struct of_device_id kx022a_of_match[] = { { .compatible = "kionix,kx022a", .data = &kx022a_chip_info }, { .compatible = "kionix,kx132-1211", .data = &kx132_chip_info }, + { .compatible = "rohm,kx132acr-lbz", .data = &kx132acr_chip_info }, { } }; MODULE_DEVICE_TABLE(of, kx022a_of_match); diff --git a/drivers/iio/accel/kionix-kx022a-spi.c b/drivers/iio/accel/kionix-kx022a-spi.c index e7878ba67827..f798b964d0b5 100644 --- a/drivers/iio/accel/kionix-kx022a-spi.c +++ b/drivers/iio/accel/kionix-kx022a-spi.c @@ -2,7 +2,7 @@ /* * Copyright (C) 2022 ROHM Semiconductors * - * ROHM/KIONIX KX022A accelerometer driver + * ROHM/KIONIX accelerometer driver */ #include @@ -38,6 +38,7 @@ static int kx022a_spi_probe(struct spi_device *spi) static const struct spi_device_id kx022a_id[] = { { .name = "kx022a", .driver_data = (kernel_ulong_t)&kx022a_chip_info }, { .name = "kx132-1211", .driver_data = (kernel_ulong_t)&kx132_chip_info }, + { .name = "kx132acr-lbz", .driver_data = (kernel_ulong_t)&kx132acr_chip_info }, { } }; MODULE_DEVICE_TABLE(spi, kx022a_id); @@ -45,6 +46,7 @@ MODULE_DEVICE_TABLE(spi, kx022a_id); static const struct of_device_id kx022a_of_match[] = { { .compatible = "kionix,kx022a", .data = &kx022a_chip_info }, { .compatible = "kionix,kx132-1211", .data = &kx132_chip_info }, + { .compatible = "rohm,kx132acr-lbz", .data = &kx132acr_chip_info }, { } }; MODULE_DEVICE_TABLE(of, kx022a_of_match); diff --git a/drivers/iio/accel/kionix-kx022a.c b/drivers/iio/accel/kionix-kx022a.c index c5b555094e60..60864be3a667 100644 --- a/drivers/iio/accel/kionix-kx022a.c +++ b/drivers/iio/accel/kionix-kx022a.c @@ -2,7 +2,7 @@ /* * Copyright (C) 2022 ROHM Semiconductors * - * ROHM/KIONIX KX022A accelerometer driver + * ROHM/KIONIX accelerometer driver */ #include @@ -1188,6 +1188,38 @@ const struct kx022a_chip_info kx132_chip_info = { }; EXPORT_SYMBOL_NS_GPL(kx132_chip_info, IIO_KX022A); +/* + * Despite the naming, KX132ACR-LBZ is not similar to KX132-1211 but it is + * exact subset of KX022A. KX132ACR-LBZ is meant to be used for industrial + * applications and the tap/double tap, free fall and tilt engines were + * removed. Rest of the registers and functionalities (excluding the ID + * register) are exact match to what is found in KX022. + */ +const struct kx022a_chip_info kx132acr_chip_info = { + .name = "kx132acr-lbz", + .regmap_config = &kx022a_regmap_config, + .channels = kx022a_channels, + .num_channels = ARRAY_SIZE(kx022a_channels), + .fifo_length = KX022A_FIFO_LENGTH, + .who = KX022A_REG_WHO, + .id = KX132ACR_LBZ_ID, + .cntl = KX022A_REG_CNTL, + .cntl2 = KX022A_REG_CNTL2, + .odcntl = KX022A_REG_ODCNTL, + .buf_cntl1 = KX022A_REG_BUF_CNTL1, + .buf_cntl2 = KX022A_REG_BUF_CNTL2, + .buf_clear = KX022A_REG_BUF_CLEAR, + .buf_status1 = KX022A_REG_BUF_STATUS_1, + .buf_read = KX022A_REG_BUF_READ, + .inc1 = KX022A_REG_INC1, + .inc4 = KX022A_REG_INC4, + .inc5 = KX022A_REG_INC5, + .inc6 = KX022A_REG_INC6, + .xout_l = KX022A_REG_XOUT_L, + .get_fifo_bytes_available = kx022a_get_fifo_bytes_available, +}; +EXPORT_SYMBOL_NS_GPL(kx132acr_chip_info, IIO_KX022A); + int kx022a_probe_internal(struct device *dev, const struct kx022a_chip_info *chip_info) { static const char * const regulator_names[] = {"io-vdd", "vdd"}; diff --git a/drivers/iio/accel/kionix-kx022a.h b/drivers/iio/accel/kionix-kx022a.h index 35c548ae7eff..7060438ad88c 100644 --- a/drivers/iio/accel/kionix-kx022a.h +++ b/drivers/iio/accel/kionix-kx022a.h @@ -13,6 +13,7 @@ #define KX022A_REG_WHO 0x0f #define KX022A_ID 0xc8 +#define KX132ACR_LBZ_ID 0xd8 #define KX022A_REG_CNTL2 0x19 #define KX022A_MASK_SRST BIT(7) @@ -186,5 +187,6 @@ int kx022a_probe_internal(struct device *dev, const struct kx022a_chip_info *chi extern const struct kx022a_chip_info kx022a_chip_info; extern const struct kx022a_chip_info kx132_chip_info; +extern const struct kx022a_chip_info kx132acr_chip_info; #endif From d27425d5d8b1cd930a31b92fb426cdbcbf876b10 Mon Sep 17 00:00:00 2001 From: George Stark Date: Fri, 21 Jul 2023 13:23:09 +0300 Subject: [PATCH 192/326] iio: adc: meson: improve error logging at probe stage Add log messages for errors that may occur at the probe stage Signed-off-by: George Stark Link: https://lore.kernel.org/r/20230721102413.255726-3-gnstark@sberdevices.ru Signed-off-by: Jonathan Cameron --- drivers/iio/adc/meson_saradc.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/drivers/iio/adc/meson_saradc.c b/drivers/iio/adc/meson_saradc.c index a40986fb285c..950ff13e6dde 100644 --- a/drivers/iio/adc/meson_saradc.c +++ b/drivers/iio/adc/meson_saradc.c @@ -1045,8 +1045,10 @@ static int meson_sar_adc_hw_enable(struct iio_dev *indio_dev) u32 regval; ret = meson_sar_adc_lock(indio_dev); - if (ret) + if (ret) { + dev_err(dev, "failed to lock adc\n"); goto err_lock; + } ret = regulator_enable(priv->vref); if (ret < 0) { @@ -1354,15 +1356,15 @@ static int meson_sar_adc_probe(struct platform_device *pdev) priv->regmap = devm_regmap_init_mmio(dev, base, priv->param->regmap_config); if (IS_ERR(priv->regmap)) - return PTR_ERR(priv->regmap); + return dev_err_probe(dev, PTR_ERR(priv->regmap), "failed to init regmap\n"); irq = irq_of_parse_and_map(dev->of_node, 0); if (!irq) - return -EINVAL; + return dev_err_probe(dev, -EINVAL, "failed to get irq\n"); ret = devm_request_irq(dev, irq, meson_sar_adc_irq, IRQF_SHARED, dev_name(dev), indio_dev); if (ret) - return ret; + return dev_err_probe(dev, ret, "failed to request irq\n"); priv->clkin = devm_clk_get(dev, "clkin"); if (IS_ERR(priv->clkin)) @@ -1384,7 +1386,7 @@ static int meson_sar_adc_probe(struct platform_device *pdev) if (!priv->adc_clk) { ret = meson_sar_adc_clk_init(indio_dev, base); if (ret) - return ret; + return dev_err_probe(dev, ret, "failed to init internal clk\n"); } priv->vref = devm_regulator_get(dev, "vref"); @@ -1426,8 +1428,10 @@ static int meson_sar_adc_probe(struct platform_device *pdev) platform_set_drvdata(pdev, indio_dev); ret = iio_device_register(indio_dev); - if (ret) + if (ret) { + dev_err_probe(dev, ret, "failed to register iio device\n"); goto err_hw; + } return 0; From 1731a0c492c806ba3678b6c1aa3081a77ca1abb3 Mon Sep 17 00:00:00 2001 From: Justin Stitt Date: Thu, 21 Sep 2023 04:54:00 +0000 Subject: [PATCH 193/326] iio: adc: stm32-adc: Replace deprecated strncpy() with strscpy() strncpy() is deprecated for use on NUL-terminated destination strings [1]. We should prefer more robust and less ambiguous string interfaces. We expect adc->chan_name[val] to be NUL-terminated based on ch_name's use within functions that expect NUL-terminated strings like strncmp and printf-likes: | if (!strncmp(stm32_adc_ic[i].name, ch_name, STM32_ADC_CH_SZ)) { | /* Check internal channel availability */ | switch (i) { | case STM32_ADC_INT_CH_VDDCORE: | if (!adc->cfg->regs->or_vddcore.reg) | dev_warn(&indio_dev->dev, | "%s channel not available\n", ch_name); ... There is no evidence that NUL-padding is needed either. Considering the above, a suitable replacement is strscpy() [2] due to the fact that it guarantees NUL-termination on the destination buffer without unnecessarily NUL-padding. If, for any reason, NUL-padding _is_ required we should go for `strscpy_pad`. Link: https://www.kernel.org/doc/html/latest/process/deprecated.html#strncpy-on-nul-terminated-strings [1] Link: https://manpages.debian.org/testing/linux-manual-4.8/strscpy.9.en.html [2] Link: https://github.com/KSPP/linux/issues/90 Cc: linux-hardening@vger.kernel.org Signed-off-by: Justin Stitt Reviewed-by: Kees Cook Link: https://lore.kernel.org/r/20230921-strncpy-drivers-iio-adc-stm32-adc-c-v1-1-c50eca098597@google.com Signed-off-by: Jonathan Cameron --- drivers/iio/adc/stm32-adc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/iio/adc/stm32-adc.c b/drivers/iio/adc/stm32-adc.c index 25a912805439..b5d3c9cea5c4 100644 --- a/drivers/iio/adc/stm32-adc.c +++ b/drivers/iio/adc/stm32-adc.c @@ -2209,7 +2209,7 @@ static int stm32_adc_generic_chan_init(struct iio_dev *indio_dev, ret = -EINVAL; goto err; } - strncpy(adc->chan_name[val], name, STM32_ADC_CH_SZ); + strscpy(adc->chan_name[val], name, STM32_ADC_CH_SZ); ret = stm32_adc_populate_int_ch(indio_dev, name, val); if (ret == -ENOENT) continue; From 1c61848f53180e18e725290991da453fc59c80a4 Mon Sep 17 00:00:00 2001 From: David Lechner Date: Fri, 29 Sep 2023 12:23:06 -0500 Subject: [PATCH 194/326] dt-bindings: iio: resolver: add devicetree bindings for ad2s1210 This adds new DeviceTree bindings for the Analog Devices, Inc. AD2S1210 resolver-to-digital converter. Co-developed-by: Apelete Seketeli Signed-off-by: Apelete Seketeli Signed-off-by: David Lechner Acked-by: Michael Hennerich Reviewed-by: Rob Herring Link: https://lore.kernel.org/r/20230929-ad2s1210-mainline-v3-1-fa4364281745@baylibre.com Signed-off-by: Jonathan Cameron --- .../bindings/iio/resolver/adi,ad2s1210.yaml | 177 ++++++++++++++++++ 1 file changed, 177 insertions(+) create mode 100644 Documentation/devicetree/bindings/iio/resolver/adi,ad2s1210.yaml diff --git a/Documentation/devicetree/bindings/iio/resolver/adi,ad2s1210.yaml b/Documentation/devicetree/bindings/iio/resolver/adi,ad2s1210.yaml new file mode 100644 index 000000000000..8980b3cd8337 --- /dev/null +++ b/Documentation/devicetree/bindings/iio/resolver/adi,ad2s1210.yaml @@ -0,0 +1,177 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/iio/resolver/adi,ad2s1210.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Analog Devices AD2S1210 Resolver-to-Digital Converter + +maintainers: + - Michael Hennerich + +description: | + The AD2S1210 is a complete 10-bit to 16-bit resolution tracking + resolver-to-digital converter, integrating an on-board programmable + sinusoidal oscillator that provides sine wave excitation for + resolvers. + + The AD2S1210 allows the user to read the angular position or the + angular velocity data directly from the parallel outputs or through + the serial interface. + + The mode of operation of the communication channel (parallel or serial) is + selected by the A0 and A1 input pins. In normal mode, data is latched by + toggling the SAMPLE line and can then be read directly. In configuration mode, + data is read or written using a register access scheme (address byte with + read/write flag and data byte). + + A1 A0 Result + 0 0 Normal mode - position output + 0 1 Normal mode - velocity output + 1 0 Reserved + 1 1 Configuration mode + + In normal mode, the resolution of the digital output is selected using + the RES0 and RES1 input pins. In configuration mode, the resolution is + selected by setting the RES0 and RES1 bits in the control register. + + RES1 RES0 Resolution (Bits) + 0 0 10 + 0 1 12 + 1 0 14 + 1 1 16 + + Note on SPI connections: The CS line on the AD2S1210 should hard-wired to + logic low and the WR/FSYNC line on the AD2S1210 should be connected to the + SPI CSn output of the SPI controller. + + Datasheet: + https://www.analog.com/media/en/technical-documentation/data-sheets/ad2s1210.pdf + +properties: + compatible: + const: adi,ad2s1210 + + reg: + maxItems: 1 + + spi-max-frequency: + maximum: 25000000 + + spi-cpha: true + + avdd-supply: + description: + A 4.75 to 5.25 V regulator that powers the Analog Supply Voltage (AVDD) + pin. + + dvdd-supply: + description: + A 4.75 to 5.25 V regulator that powers the Digital Supply Voltage (DVDD) + pin. + + vdrive-supply: + description: + A 2.3 to 5.25 V regulator that powers the Logic Power Supply Input + (VDrive) pin. + + clocks: + maxItems: 1 + description: External oscillator clock (CLKIN). + + reset-gpios: + description: + GPIO connected to the /RESET pin. As the line needs to be low for the + reset to be active, it should be configured as GPIO_ACTIVE_LOW. + maxItems: 1 + + sample-gpios: + description: + GPIO connected to the /SAMPLE pin. As the line needs to be low to trigger + a sample, it should be configured as GPIO_ACTIVE_LOW. + maxItems: 1 + + mode-gpios: + description: + GPIO lines connected to the A0 and A1 pins. These pins select the data + transfer mode. + minItems: 2 + maxItems: 2 + + resolution-gpios: + description: + GPIO lines connected to the RES0 and RES1 pins. These pins select the + resolution of the digital output. If omitted, it is assumed that the + RES0 and RES1 pins are hard-wired to match the assigned-resolution-bits + property. + minItems: 2 + maxItems: 2 + + fault-gpios: + description: + GPIO lines connected to the LOT and DOS pins. These pins combined indicate + the type of fault present, if any. As these pins a pulled low to indicate + a fault condition, they should be configured as GPIO_ACTIVE_LOW. + minItems: 2 + maxItems: 2 + + adi,fixed-mode: + description: + This is used to indicate the selected mode if A0 and A1 are hard-wired + instead of connected to GPIOS (i.e. mode-gpios is omitted). + $ref: /schemas/types.yaml#/definitions/string + enum: [config, velocity, position] + + assigned-resolution-bits: + description: + Resolution of the digital output required by the application. This + determines the precision of the angle and/or the maximum speed that can + be measured. If resolution-gpios is omitted, it is assumed that RES0 and + RES1 are hard-wired to match this value. + enum: [10, 12, 14, 16] + +required: + - compatible + - reg + - spi-cpha + - avdd-supply + - dvdd-supply + - vdrive-supply + - clocks + - sample-gpios + - assigned-resolution-bits + +oneOf: + - required: + - mode-gpios + - required: + - adi,fixed-mode + +allOf: + - $ref: /schemas/spi/spi-peripheral-props.yaml# + +unevaluatedProperties: false + +examples: + - | + #include + + spi { + #address-cells = <1>; + #size-cells = <0>; + + resolver@0 { + compatible = "adi,ad2s1210"; + reg = <0>; + spi-max-frequency = <20000000>; + spi-cpha; + avdd-supply = <&avdd_regulator>; + dvdd-supply = <&dvdd_regulator>; + vdrive-supply = <&vdrive_regulator>; + clocks = <&ext_osc>; + sample-gpios = <&gpio0 90 GPIO_ACTIVE_LOW>; + mode-gpios = <&gpio0 86 0>, <&gpio0 87 0>; + resolution-gpios = <&gpio0 88 0>, <&gpio0 89 0>; + assigned-resolution-bits = <16>; + }; + }; From 848f68c760ab1e14a9046ea6e45e3304ab9fa50b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Apitzsch?= Date: Sun, 1 Oct 2023 18:09:56 +0200 Subject: [PATCH 195/326] iio: magnetometer: ak8975: Fix 'Unexpected device' error MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Explicity specify array indices to fix mapping between asahi_compass_chipset and ak_def_array. While at it, remove unneeded AKXXXX. Fixes: 4f9ea93afde1 ("iio: magnetometer: ak8975: Convert enum->pointer for data in the match tables") Signed-off-by: André Apitzsch Reviewed-by: Biju Das Reviewed-by: Andy Shevchenko Link: https://lore.kernel.org/r/20231001-ak_magnetometer-v1-1-09bf3b8798a3@apitzsch.eu Signed-off-by: Jonathan Cameron --- drivers/iio/magnetometer/ak8975.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/drivers/iio/magnetometer/ak8975.c b/drivers/iio/magnetometer/ak8975.c index 8cfceb007936..dd466c5fa621 100644 --- a/drivers/iio/magnetometer/ak8975.c +++ b/drivers/iio/magnetometer/ak8975.c @@ -204,7 +204,6 @@ static long ak09912_raw_to_gauss(u16 data) /* Compatible Asahi Kasei Compass parts */ enum asahi_compass_chipset { - AKXXXX = 0, AK8975, AK8963, AK09911, @@ -248,7 +247,7 @@ struct ak_def { }; static const struct ak_def ak_def_array[] = { - { + [AK8975] = { .type = AK8975, .raw_to_gauss = ak8975_raw_to_gauss, .range = 4096, @@ -273,7 +272,7 @@ static const struct ak_def ak_def_array[] = { AK8975_REG_HYL, AK8975_REG_HZL}, }, - { + [AK8963] = { .type = AK8963, .raw_to_gauss = ak8963_09911_raw_to_gauss, .range = 8190, @@ -298,7 +297,7 @@ static const struct ak_def ak_def_array[] = { AK8975_REG_HYL, AK8975_REG_HZL}, }, - { + [AK09911] = { .type = AK09911, .raw_to_gauss = ak8963_09911_raw_to_gauss, .range = 8192, @@ -323,7 +322,7 @@ static const struct ak_def ak_def_array[] = { AK09912_REG_HYL, AK09912_REG_HZL}, }, - { + [AK09912] = { .type = AK09912, .raw_to_gauss = ak09912_raw_to_gauss, .range = 32752, @@ -348,7 +347,7 @@ static const struct ak_def ak_def_array[] = { AK09912_REG_HYL, AK09912_REG_HZL}, }, - { + [AK09916] = { .type = AK09916, .raw_to_gauss = ak09912_raw_to_gauss, .range = 32752, From 2d3dff577dd0ea8fe9637a13822f7603c4a881c8 Mon Sep 17 00:00:00 2001 From: Matti Vaittinen Date: Tue, 3 Oct 2023 12:57:47 +0300 Subject: [PATCH 196/326] tools: iio: iio_generic_buffer ensure alignment The iio_generic_buffer can return garbage values when the total size of scan data is not a multiple of the largest element in the scan. This can be demonstrated by reading a scan, consisting, for example of one 4-byte and one 2-byte element, where the 4-byte element is first in the buffer. The IIO generic buffer code does not take into account the last two padding bytes that are needed to ensure that the 4-byte data for next scan is correctly aligned. Add the padding bytes required to align the next sample with the scan size. Signed-off-by: Matti Vaittinen Fixes: e58537ccce73 ("staging: iio: update example application.") Link: https://lore.kernel.org/r/ZRvlm4ktNLu+qmlf@dc78bmyyyyyyyyyyyyydt-3.rev.dnainternet.fi Signed-off-by: Jonathan Cameron --- tools/iio/iio_generic_buffer.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/tools/iio/iio_generic_buffer.c b/tools/iio/iio_generic_buffer.c index 44bbf80f0cfd..0d0a7a19d6f9 100644 --- a/tools/iio/iio_generic_buffer.c +++ b/tools/iio/iio_generic_buffer.c @@ -54,9 +54,12 @@ enum autochan { static unsigned int size_from_channelarray(struct iio_channel_info *channels, int num_channels) { unsigned int bytes = 0; - int i = 0; + int i = 0, max = 0; + unsigned int misalignment; while (i < num_channels) { + if (channels[i].bytes > max) + max = channels[i].bytes; if (bytes % channels[i].bytes == 0) channels[i].location = bytes; else @@ -66,6 +69,14 @@ static unsigned int size_from_channelarray(struct iio_channel_info *channels, in bytes = channels[i].location + channels[i].bytes; i++; } + /* + * We want the data in next sample to also be properly aligned so + * we'll add padding at the end if needed. Adding padding only + * works for channel data which size is 2^n bytes. + */ + misalignment = bytes % max; + if (misalignment) + bytes += max - misalignment; return bytes; } From 8a590d7371f02ba37d073bed9f988f529f95a03c Mon Sep 17 00:00:00 2001 From: Stanley Chang Date: Mon, 4 Sep 2023 13:12:47 +0800 Subject: [PATCH 197/326] extcon: add Realtek DHC RTD SoC Type-C driver This patch adds the extcon driver for Realtek DHC (digital home center) RTD SoCs type-c module. This can be used to detect whether the port is configured as a downstream or upstream facing port. And notify the status of extcon to listeners. Link: https://lore.kernel.org/lkml/20230904051253.23208-2-stanley_chang@realtek.com/ Signed-off-by: Stanley Chang Signed-off-by: Chanwoo Choi --- drivers/extcon/Kconfig | 11 + drivers/extcon/Makefile | 1 + drivers/extcon/extcon-rtk-type-c.c | 1792 ++++++++++++++++++++++++++++ 3 files changed, 1804 insertions(+) create mode 100644 drivers/extcon/extcon-rtk-type-c.c diff --git a/drivers/extcon/Kconfig b/drivers/extcon/Kconfig index 8de9023c2a38..5f869eacd19a 100644 --- a/drivers/extcon/Kconfig +++ b/drivers/extcon/Kconfig @@ -191,4 +191,15 @@ config EXTCON_USBC_TUSB320 Say Y here to enable support for USB Type C cable detection extcon support using a TUSB320. +config EXTCON_RTK_TYPE_C + tristate "Realtek RTD SoC extcon Type-C Driver" + depends on ARCH_REALTEK || COMPILE_TEST + depends on TYPEC + select USB_COMMON + help + Say Y here to enable extcon support for USB Type C cable detection + when using the Realtek RTD SoC USB Type-C port. + The DHC (Digital Home Hub) RTD series SoC contains a type c module. + This driver will detect the status of the type-c port. + endif diff --git a/drivers/extcon/Makefile b/drivers/extcon/Makefile index 1b390d934ca9..f779adb5e4c7 100644 --- a/drivers/extcon/Makefile +++ b/drivers/extcon/Makefile @@ -25,3 +25,4 @@ obj-$(CONFIG_EXTCON_SM5502) += extcon-sm5502.o obj-$(CONFIG_EXTCON_USB_GPIO) += extcon-usb-gpio.o obj-$(CONFIG_EXTCON_USBC_CROS_EC) += extcon-usbc-cros-ec.o obj-$(CONFIG_EXTCON_USBC_TUSB320) += extcon-usbc-tusb320.o +obj-$(CONFIG_EXTCON_RTK_TYPE_C) += extcon-rtk-type-c.o diff --git a/drivers/extcon/extcon-rtk-type-c.c b/drivers/extcon/extcon-rtk-type-c.c new file mode 100644 index 000000000000..00465cfba23e --- /dev/null +++ b/drivers/extcon/extcon-rtk-type-c.c @@ -0,0 +1,1792 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * * extcon-rtk-type-c.c - Realtek Extcon Type C driver + * + * Copyright (C) 2023 Realtek Semiconductor Corporation + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct cc_param { + u32 rp_4p7k_code; + u32 rp_36k_code; + u32 rp_12k_code; + u32 rd_code; + u32 ra_code; + u32 vref_2p6v; + u32 vref_1p23v; + u32 vref_0p8v; + u32 vref_0p66v; + u32 vref_0p4v; + u32 vref_0p2v; + u32 vref_1_1p6v; + u32 vref_0_1p6v; +}; + +struct type_c_cfg { + int parameter_ver; /* Parameter version */ + int cc_dfp_mode; + struct cc_param cc1_param; + struct cc_param cc2_param; + + u32 debounce_val; + bool use_defalut_parameter; +}; + +struct type_c_data { + void __iomem *reg_base; + struct device *dev; + struct extcon_dev *edev; + + u32 irq; + + /* rd control GPIO only for rtd1295 */ + struct gpio_desc *rd_ctrl_gpio_desc; + + /* Parameters */ + struct type_c_cfg *type_c_cfg; + u32 dfp_mode_rp_en; + u32 ufp_mode_rd_en; + u32 cc1_code; + u32 cc2_code; + u32 cc1_vref; + u32 cc2_vref; + u32 debounce; /* 1b,1us 7f,4.7us */ + + /* type_c state */ + int connect_change; +#define CONNECT_CHANGE 1 +#define CONNECT_NO_CHANGE 0 + int cc_mode; /* cc is host or device */ +#define IN_HOST_MODE 0x10 +#define IN_DEVICE_MODE 0x20 + int is_attach; +#define IN_ATTACH 1 +#define TO_ATTACH 1 +#define IN_DETACH 0 +#define TO_DETACH 0 + int at_cc1; +#define AT_CC1 1 +#define AT_CC2 0 + + u32 int_status; + u32 cc_status; + /* protect the data member */ + spinlock_t lock; + struct delayed_work delayed_work; + + bool rd_en_at_first; + + struct dentry *debug_dir; + + struct typec_port *port; +}; + +/* Type C register offset */ +#define USB_TYPEC_CTRL_CC1_0 0x0 +#define USB_TYPEC_CTRL_CC1_1 0x4 +#define USB_TYPEC_CTRL_CC2_0 0x8 +#define USB_TYPEC_CTRL_CC2_1 0xC +#define USB_TYPEC_STS 0x10 +#define USB_TYPEC_CTRL 0x14 +#define USB_DBUS_PWR_CTRL 0x18 + +#define ENABLE_CC1 0x1 +#define ENABLE_CC2 0x2 +#define DISABLE_CC 0x0 + +/* Bit mapping USB_TYPEC_CTRL_CC1_0 and USB_TYPEC_CTRL_CC2_0 */ +#define PLR_EN BIT(29) +#define CC_SWITCH_MASK (BIT(29) | BIT(28) | BIT(27)) +#define CC_CODE_MASK (0xfffff << 7) +#define rp4pk_code(val) ((0x1f & (val)) << 22) +#define code_rp4pk(val) (((val) >> 22) & 0x1f) +#define rp36k_code(val) ((0x1f & (val)) << 17) +#define code_rp36k(val) (((val) >> 17) & 0x1f) +#define rp12k_code(val) ((0x1f & (val)) << 12) +#define code_rp12k(val) (((val) >> 12) & 0x1f) +#define rd_code(val) ((0x1f & (val)) << 7) +#define code_rd(val) (((val) >> 7) & 0x1f) +#define dfp_mode(val) ((0x3 & (val)) << 5) +#define EN_RP4P7K BIT(4) +#define EN_RP36K BIT(3) +#define EN_RP12K BIT(2) +#define EN_RD BIT(1) +#define EN_CC_DET BIT(0) + +#define CC_MODE_UFP 0x0 +#define CC_MODE_DFP_USB 0x1 +#define CC_MODE_DFP_1_5 0x2 +#define CC_MODE_DFP_3_0 0x3 + +/* + * PARAMETER_V0: + * Realtek Kylin rtd1295 + * Realtek Hercules rtd1395 + * Realtek Thor rtd1619 + * Realtek Hank rtd1319 + * Realtek Groot rtd1312c + * PARAMETER_V1: + * Realtek Stark rtd1619b + * Realtek Parker rtd1319d + * Realtek Danvers rtd1315e + */ +enum parameter_version { + PARAMETER_V0 = 0, + PARAMETER_V1 = 1, +}; + +/* Bit mapping USB_TYPEC_CTRL_CC1_1 and USB_TYPEC_CTRL_CC2_1 */ +#define V0_vref_2p6v(val) ((0xf & (val)) << 26) /* Bit 29 for groot */ +#define V0_vref_1p23v(val) ((0xf & (val)) << 22) +#define V0_vref_0p8v(val) ((0xf & (val)) << 18) +#define V0_vref_0p66v(val) ((0xf & (val)) << 14) +#define V0_vref_0p4v(val) ((0x7 & (val)) << 11) +#define V0_vref_0p2v(val) ((0x7 & (val)) << 8) +#define V0_vref_1_1p6v(val) ((0xf & (val)) << 4) +#define V0_vref_0_1p6v(val) ((0xf & (val)) << 0) + +#define V0_decode_2p6v(val) (((val) >> 26) & 0xf) /* Bit 29 for groot */ +#define V0_decode_1p23v(val) (((val) >> 22) & 0xf) +#define V0_decode_0p8v(val) (((val) >> 18) & 0xf) +#define V0_decode_0p66v(val) (((val) >> 14) & 0xf) +#define V0_decode_0p4v(val) (((val) >> 11) & 0x7) +#define V0_decode_0p2v(val) (((val) >> 8) & 0x7) +#define V0_decode_1_1p6v(val) (((val) >> 4) & 0xf) +#define V0_decode_0_1p6v(val) (((val) >> 0) & 0xf) + +/* new Bit mapping USB_TYPEC_CTRL_CC1_1 and USB_TYPEC_CTRL_CC2_1 */ +#define V1_vref_2p6v(val) ((0xf & (val)) << 28) +#define V1_vref_1p23v(val) ((0xf & (val)) << 24) +#define V1_vref_0p8v(val) ((0xf & (val)) << 20) +#define V1_vref_0p66v(val) ((0xf & (val)) << 16) +#define V1_vref_0p4v(val) ((0xf & (val)) << 12) +#define V1_vref_0p2v(val) ((0xf & (val)) << 8) +#define V1_vref_1_1p6v(val) ((0xf & (val)) << 4) +#define V1_vref_0_1p6v(val) ((0xf & (val)) << 0) + +#define V1_decode_2p6v(val) (((val) >> 28) & 0xf) +#define V1_decode_1p23v(val) (((val) >> 24) & 0xf) +#define V1_decode_0p8v(val) (((val) >> 20) & 0xf) +#define V1_decode_0p66v(val) (((val) >> 16) & 0xf) +#define V1_decode_0p4v(val) (((val) >> 12) & 0xf) +#define V1_decode_0p2v(val) (((val) >> 8) & 0xf) +#define V1_decode_1_1p6v(val) (((val) >> 4) & 0xf) +#define V1_decode_0_1p6v(val) (((val) >> 0) & 0xf) + +/* Bit mapping USB_TYPEC_STS */ +#define DET_STS 0x7 +#define CC1_DET_STS (DET_STS) +#define CC2_DET_STS (DET_STS << 3) +#define DET_STS_RA 0x1 +#define DET_STS_RD 0x3 +#define DET_STS_RP 0x1 +#define CC1_DET_STS_RA (DET_STS_RA) +#define CC1_DET_STS_RD (DET_STS_RD) +#define CC1_DET_STS_RP (DET_STS_RP) +#define CC2_DET_STS_RA (DET_STS_RA << 3) +#define CC2_DET_STS_RD (DET_STS_RD << 3) +#define CC2_DET_STS_RP (DET_STS_RP << 3) + +/* Bit mapping USB_TYPEC_CTRL */ +#define CC2_INT_EN BIT(11) +#define CC1_INT_EN BIT(10) +#define CC2_INT_STS BIT(9) +#define CC1_INT_STS BIT(8) +#define DEBOUNCE_TIME_MASK 0xff +#define DEBOUNCE_EN BIT(0) +#define ENABLE_TYPE_C_DETECT (CC1_INT_EN | CC2_INT_EN) +#define ALL_CC_INT_STS (CC1_INT_STS | CC2_INT_STS) + +/* Parameter */ +#define DETECT_TIME 50 /* ms */ + +static const unsigned int usb_type_c_cable[] = { + EXTCON_USB, + EXTCON_USB_HOST, + EXTCON_NONE, +}; + +enum usb_data_roles { + DR_NONE, + DR_HOST, + DR_DEVICE, +}; + +static const struct soc_device_attribute rtk_soc_kylin[] = { + { .family = "Realtek Kylin", }, + { /* empty */ } +}; + +static int rtd129x_switch_type_c_plug_config(struct type_c_data *type_c, + int dr_mode, int cc) +{ + void __iomem *reg = type_c->reg_base + USB_TYPEC_CTRL_CC1_0; + int val_cc; + +#define TYPE_C_EN_SWITCH BIT(29) +#define TYPE_C_TXRX_SEL (BIT(28) | BIT(27)) +#define TYPE_C_SWITCH_MASK (TYPE_C_EN_SWITCH | TYPE_C_TXRX_SEL) +#define TYPE_C_ENABLE_CC1 TYPE_C_EN_SWITCH +#define TYPE_C_ENABLE_CC2 (TYPE_C_EN_SWITCH | TYPE_C_TXRX_SEL) +#define TYPE_C_DISABLE_CC ~TYPE_C_SWITCH_MASK + + val_cc = readl(reg); + val_cc &= ~TYPE_C_SWITCH_MASK; + + if (cc == DISABLE_CC) { + val_cc &= TYPE_C_DISABLE_CC; + } else if (cc == ENABLE_CC1) { + val_cc |= TYPE_C_ENABLE_CC1; + } else if (cc == ENABLE_CC2) { + val_cc |= TYPE_C_ENABLE_CC2; + } else { + dev_err(type_c->dev, "%s: Error cc setting cc=0x%x\n", __func__, cc); + return -EINVAL; + } + writel(val_cc, reg); + + /* waiting cc stable for enable/disable */ + mdelay(1); + + dev_dbg(type_c->dev, "%s: cc=0x%x val_cc=0x%x usb_typec_ctrl_cc1_0=0x%x\n", + __func__, cc, val_cc, readl(reg)); + + return 0; +} + +static inline void switch_type_c_plug_config(struct type_c_data *type_c, + int dr_mode, int cc) +{ + int ret = 0; + + if (soc_device_match(rtk_soc_kylin)) + ret = rtd129x_switch_type_c_plug_config(type_c, dr_mode, cc); + + if (ret < 0) + dev_err(type_c->dev, "%s: Error set type c plug config\n", + __func__); +} + +static void switch_type_c_dr_mode(struct type_c_data *type_c, int dr_mode, int cc) +{ + bool is_host = false; + bool is_device = false; + bool polarity = false; + bool vbus = false; + bool ss = true; + + switch_type_c_plug_config(type_c, dr_mode, cc); + if (cc == ENABLE_CC2) + polarity = true; + + switch (dr_mode) { + case USB_DR_MODE_HOST: + is_host = true; + break; + case USB_DR_MODE_PERIPHERAL: + is_device = true; + vbus = true; + break; + default: + dev_dbg(type_c->dev, "%s dr_mode=%d ==> no host or device\n", + __func__, dr_mode); + break; + } + + dev_dbg(type_c->dev, "%s is_host=%d is_device=%d vbus=%d polarity=%d\n", + __func__, is_host, is_device, vbus, polarity); + + /* for EXTCON_USB device mode */ + extcon_set_state(type_c->edev, EXTCON_USB, is_device); + extcon_set_property(type_c->edev, EXTCON_USB, + EXTCON_PROP_USB_VBUS, + (union extcon_property_value)(int)vbus); + extcon_set_property(type_c->edev, EXTCON_USB, + EXTCON_PROP_USB_TYPEC_POLARITY, + (union extcon_property_value)(int)polarity); + extcon_set_property(type_c->edev, EXTCON_USB, + EXTCON_PROP_USB_SS, + (union extcon_property_value)(int)ss); + + /* for EXTCON_USB_HOST host mode */ + extcon_set_state(type_c->edev, EXTCON_USB_HOST, is_host); + extcon_set_property(type_c->edev, EXTCON_USB_HOST, + EXTCON_PROP_USB_VBUS, + (union extcon_property_value)(int)vbus); + extcon_set_property(type_c->edev, EXTCON_USB_HOST, + EXTCON_PROP_USB_TYPEC_POLARITY, + (union extcon_property_value)(int)polarity); + extcon_set_property(type_c->edev, EXTCON_USB_HOST, + EXTCON_PROP_USB_SS, + (union extcon_property_value)(int)ss); + + /* sync EXTCON_USB and EXTCON_USB_HOST */ + extcon_sync(type_c->edev, EXTCON_USB); + extcon_sync(type_c->edev, EXTCON_USB_HOST); + + if (type_c->port) { + switch (dr_mode) { + case USB_DR_MODE_HOST: + typec_set_data_role(type_c->port, TYPEC_HOST); + typec_set_pwr_role(type_c->port, TYPEC_SOURCE); + break; + case USB_DR_MODE_PERIPHERAL: + typec_set_data_role(type_c->port, TYPEC_DEVICE); + typec_set_pwr_role(type_c->port, TYPEC_SINK); + break; + default: + dev_dbg(type_c->dev, "%s unknown dr_mode=%d\n", + __func__, dr_mode); + break; + } + } +} + +/* connector attached/detached */ +static int connector_attached(struct type_c_data *type_c, u32 cc, int dr_mode) +{ + void __iomem *reg = type_c->reg_base + USB_TYPEC_CTRL; + + cancel_delayed_work(&type_c->delayed_work); + + switch_type_c_dr_mode(type_c, dr_mode, cc); + + writel(ENABLE_TYPE_C_DETECT | readl(reg), reg); + + return 0; +} + +static int connector_detached(struct type_c_data *type_c, u32 cc, int dr_mode) +{ + void __iomem *reg = type_c->reg_base + USB_TYPEC_CTRL; + + writel(~ENABLE_TYPE_C_DETECT & readl(reg), reg); + + switch_type_c_dr_mode(type_c, 0, cc); + + schedule_delayed_work(&type_c->delayed_work, msecs_to_jiffies(DETECT_TIME)); + + return 0; +} + +/* detect host device switch */ +static int __detect_host_device(struct type_c_data *type_c, u32 rp_or_rd_en) +{ + struct device *dev = type_c->dev; + void __iomem *reg_base = type_c->reg_base; + u32 cc1_config, cc2_config, default_ctrl; + u32 cc1_switch = 0; + + default_ctrl = readl(reg_base + USB_TYPEC_CTRL) & DEBOUNCE_TIME_MASK; + writel(default_ctrl, reg_base + USB_TYPEC_CTRL); + + cc1_config = readl(reg_base + USB_TYPEC_CTRL_CC1_0); + cc2_config = readl(reg_base + USB_TYPEC_CTRL_CC2_0); + + cc1_config &= ~EN_CC_DET; + cc2_config &= ~EN_CC_DET; + writel(cc1_config, reg_base + USB_TYPEC_CTRL_CC1_0); + writel(cc2_config, reg_base + USB_TYPEC_CTRL_CC2_0); + + if (soc_device_match(rtk_soc_kylin)) + cc1_switch = cc1_config & CC_SWITCH_MASK; + + cc1_config &= CC_CODE_MASK; + cc1_config |= rp_or_rd_en | cc1_switch; + cc2_config &= CC_CODE_MASK; + cc2_config |= rp_or_rd_en; + writel(cc2_config, reg_base + USB_TYPEC_CTRL_CC2_0); + writel(cc1_config, reg_base + USB_TYPEC_CTRL_CC1_0); + + /* For kylin to disable external rd control gpio */ + if (soc_device_match(rtk_soc_kylin)) { + struct gpio_desc *gpio = type_c->rd_ctrl_gpio_desc; + + if (gpio && gpiod_direction_output(gpio, 1)) + dev_err(dev, "%s ERROR set rd_ctrl_gpio_desc fail\n", __func__); + } + + cc1_config |= EN_CC_DET; + cc2_config |= EN_CC_DET; + writel(cc1_config, reg_base + USB_TYPEC_CTRL_CC1_0); + writel(cc2_config, reg_base + USB_TYPEC_CTRL_CC2_0); + + return 0; +} + +static int detect_device(struct type_c_data *type_c) +{ + return __detect_host_device(type_c, type_c->dfp_mode_rp_en); +} + +static int detect_host(struct type_c_data *type_c) +{ + return __detect_host_device(type_c, type_c->ufp_mode_rd_en); +} + +static int host_device_switch_detection(struct type_c_data *type_c) +{ + if (type_c->cc_mode == IN_HOST_MODE) { + type_c->cc_mode = IN_DEVICE_MODE; + detect_host(type_c); + } else { + type_c->cc_mode = IN_HOST_MODE; + detect_device(type_c); + } + + return 0; +} + +static int detect_type_c_state(struct type_c_data *type_c) +{ + struct device *dev = type_c->dev; + void __iomem *reg_base = type_c->reg_base; + u32 int_status, cc_status, cc_status_check; + unsigned long flags; + + spin_lock_irqsave(&type_c->lock, flags); + + int_status = readl(reg_base + USB_TYPEC_CTRL); + cc_status = readl(reg_base + USB_TYPEC_STS); + + type_c->connect_change = CONNECT_NO_CHANGE; + + switch (type_c->cc_mode | type_c->is_attach) { + case IN_HOST_MODE | IN_ATTACH: + if (((cc_status & CC1_DET_STS) == CC1_DET_STS) && type_c->at_cc1 == AT_CC1) { + dev_dbg(dev, "IN host mode and cc1 device detach (cc_status=0x%x)", + cc_status); + type_c->is_attach = TO_DETACH; + type_c->connect_change = CONNECT_CHANGE; + } else if (((cc_status & CC2_DET_STS) == CC2_DET_STS) && + type_c->at_cc1 == AT_CC2) { + dev_dbg(dev, "IN host mode and cc2 device detach (cc_status=0x%x)", + cc_status); + type_c->is_attach = TO_DETACH; + type_c->connect_change = CONNECT_CHANGE; + } + break; + case IN_HOST_MODE | IN_DETACH: + cc_status_check = readl(reg_base + USB_TYPEC_STS); + if (cc_status_check != (CC1_DET_STS | CC2_DET_STS)) { + if (in_interrupt()) { + /* Add delay time to avoid capacitive effect of cable. */ + mdelay(300); + } else { + spin_unlock_irqrestore(&type_c->lock, flags); + /* Add delay time to avoid capacitive effect of cable. */ + msleep(300); + spin_lock_irqsave(&type_c->lock, flags); + } + cc_status_check = readl(reg_base + USB_TYPEC_STS); + } + if (cc_status != cc_status_check) { + dev_warn(dev, "IN_HOST_MODE: cc_status (0x%x) != cc_status_check (0x%x)\n", + cc_status, cc_status_check); + cc_status = readl(reg_base + USB_TYPEC_STS); + } + + if ((cc_status & CC1_DET_STS) == CC1_DET_STS_RD) { + dev_dbg(dev, "IN host mode and cc1 device attach (cc_status=0x%x)", + cc_status); + type_c->is_attach = TO_ATTACH; + type_c->at_cc1 = AT_CC1; + type_c->connect_change = CONNECT_CHANGE; + } else if ((cc_status & CC2_DET_STS) == CC2_DET_STS_RD) { + dev_dbg(dev, "In host mode and cc2 device attach (cc_status=0x%x)", + cc_status); + type_c->is_attach = TO_ATTACH; + type_c->at_cc1 = AT_CC2; + type_c->connect_change = CONNECT_CHANGE; + } + break; + case IN_DEVICE_MODE | IN_ATTACH: + if ((cc_status & CC1_DET_STS) < CC1_DET_STS_RP || + (cc_status & CC2_DET_STS) < CC2_DET_STS_RP) { + /* Add a sw debounce to filter cc signal sent from apple pd adapter */ + mdelay(5); + cc_status_check = readl(reg_base + USB_TYPEC_STS); + + if (cc_status != cc_status_check) { + dev_dbg(dev, "IN_DEVICE_MODE: cc_status (0x%x) != cc_status_check (0x%x) maybe use a pd adapter\n", + cc_status, cc_status_check); + cc_status = cc_status_check; + } + } + + if ((cc_status & CC1_DET_STS) < CC1_DET_STS_RP && type_c->at_cc1 == AT_CC1) { + dev_dbg(dev, "IN device mode and cc1 host disconnect (cc_status=0x%x)", + cc_status); + type_c->is_attach = TO_DETACH; + type_c->connect_change = CONNECT_CHANGE; + } else if ((cc_status & CC2_DET_STS) < CC2_DET_STS_RP && + type_c->at_cc1 == AT_CC2) { + dev_dbg(dev, "IN device mode and cc2 host disconnect (cc_status=0x%x)", + cc_status); + type_c->is_attach = TO_DETACH; + type_c->connect_change = CONNECT_CHANGE; + } + break; + case IN_DEVICE_MODE | IN_DETACH: + cc_status_check = readl(reg_base + USB_TYPEC_STS); + if (cc_status_check != 0x0) { + if (in_interrupt()) { + /* Add delay time to avoid capacitive effect of cable. */ + mdelay(300); + } else { + spin_unlock_irqrestore(&type_c->lock, flags); + /* Add delay time to avoid capacitive effect of cable. */ + msleep(300); + spin_lock_irqsave(&type_c->lock, flags); + } + cc_status_check = readl(reg_base + USB_TYPEC_STS); + } + + if (cc_status != cc_status_check) { + dev_warn(dev, "IN_DEVICE_MODE: cc_status (0x%x) != cc_status_check (0x%x)\n", + cc_status, cc_status_check); + cc_status = readl(reg_base + USB_TYPEC_STS); + } + + if ((cc_status & CC1_DET_STS) >= CC1_DET_STS_RP) { + dev_dbg(dev, "IN device mode and cc1 host connect (cc_status=0x%x)", + cc_status); + type_c->at_cc1 = AT_CC1; + type_c->is_attach = TO_ATTACH; + type_c->connect_change = CONNECT_CHANGE; + } else if ((cc_status & CC2_DET_STS) >= CC2_DET_STS_RP) { + dev_dbg(dev, "IN device mode and cc2 host connect (cc_status=0x%x)", + cc_status); + type_c->at_cc1 = AT_CC2; + type_c->is_attach = TO_ATTACH; + type_c->connect_change = CONNECT_CHANGE; + } + break; + default: + dev_err(dev, "error host or device mode (cc_mode=%d, is_attach=%d) ", + type_c->cc_mode, type_c->is_attach); + } + + type_c->int_status = int_status; + type_c->cc_status = cc_status; + + spin_unlock_irqrestore(&type_c->lock, flags); + return 0; +} + +static void host_device_switch(struct work_struct *work) +{ + struct type_c_data *type_c = container_of(work, struct type_c_data, + delayed_work.work); + struct device *dev = type_c->dev; + unsigned long flags; + int connect_change = 0; + int cc_mode = 0; + int is_attach = 0; + int at_cc1 = 0; + + spin_lock_irqsave(&type_c->lock, flags); + if (type_c->connect_change) + connect_change = type_c->connect_change; + spin_unlock_irqrestore(&type_c->lock, flags); + + if (!connect_change) + detect_type_c_state(type_c); + + spin_lock_irqsave(&type_c->lock, flags); + if (type_c->connect_change) { + connect_change = type_c->connect_change; + cc_mode = type_c->cc_mode; + is_attach = type_c->is_attach; + at_cc1 = type_c->at_cc1; + type_c->connect_change = CONNECT_NO_CHANGE; + } else { + host_device_switch_detection(type_c); + + schedule_delayed_work(&type_c->delayed_work, msecs_to_jiffies(DETECT_TIME)); + } + spin_unlock_irqrestore(&type_c->lock, flags); + + if (!connect_change) + return; + + dev_dbg(dev, "%s: usb cable connection change\n", __func__); + if (cc_mode == IN_HOST_MODE) { + if (is_attach && at_cc1) + connector_attached(type_c, ENABLE_CC1, USB_DR_MODE_HOST); + else if (is_attach && !at_cc1) + connector_attached(type_c, ENABLE_CC2, USB_DR_MODE_HOST); + else + connector_detached(type_c, DISABLE_CC, USB_DR_MODE_HOST); + } else if (cc_mode == IN_DEVICE_MODE) { + if (is_attach && at_cc1) + connector_attached(type_c, ENABLE_CC1, USB_DR_MODE_PERIPHERAL); + else if (is_attach && !at_cc1) + connector_attached(type_c, ENABLE_CC2, USB_DR_MODE_PERIPHERAL); + else + connector_detached(type_c, DISABLE_CC, USB_DR_MODE_PERIPHERAL); + } else { + dev_err(dev, "Error: IN unknown mode %d to %s at %s (cc_status=0x%x)\n", + cc_mode, is_attach ? "attach" : "detach", + at_cc1 ? "cc1" : "cc2", type_c->cc_status); + } + dev_info(dev, "Connection change OK: IN %s mode to %s at %s (cc_status=0x%x)\n", + cc_mode == IN_HOST_MODE ? "host" : "device", + is_attach ? "attach" : "detach", + at_cc1 ? "cc1" : "cc2", type_c->cc_status); +} + +static irqreturn_t type_c_detect_irq(int irq, void *__data) +{ + struct type_c_data *type_c = (struct type_c_data *)__data; + struct device *dev = type_c->dev; + void __iomem *reg = type_c->reg_base + USB_TYPEC_CTRL; + unsigned long flags; + + detect_type_c_state(type_c); + + spin_lock_irqsave(&type_c->lock, flags); + + if (type_c->connect_change) { + dev_dbg(dev, "%s: IN %s mode to %s (at %s interrupt) int_status=0x%x, cc_status=0x%x", + __func__, + type_c->cc_mode == IN_HOST_MODE ? "host" : "device", + type_c->is_attach ? "attach" : "detach", + type_c->at_cc1 ? "cc1" : "cc2", + type_c->int_status, type_c->cc_status); + + /* clear interrupt status */ + writel(~ALL_CC_INT_STS & readl(reg), reg); + + cancel_delayed_work(&type_c->delayed_work); + schedule_delayed_work(&type_c->delayed_work, msecs_to_jiffies(0)); + } else { + static int local_count; + + /* if no connect_change, we keep the status to avoid status lose */ + if (local_count++ > 10) { + /* clear interrupt status */ + writel(~ALL_CC_INT_STS & readl(reg), reg); + local_count = 0; + } + } + + spin_unlock_irqrestore(&type_c->lock, flags); + + return IRQ_HANDLED; +} + +static int type_c_port_dr_set(struct typec_port *port, + enum typec_data_role role) +{ + struct type_c_data *type_c = typec_get_drvdata(port); + u32 enable_cc; + unsigned long flags; + + spin_lock_irqsave(&type_c->lock, flags); + enable_cc = type_c->at_cc1 ? ENABLE_CC1 : ENABLE_CC2; + spin_unlock_irqrestore(&type_c->lock, flags); + + if (role == TYPEC_HOST) + switch_type_c_dr_mode(type_c, USB_DR_MODE_HOST, enable_cc); + else if (role == TYPEC_DEVICE) + switch_type_c_dr_mode(type_c, USB_DR_MODE_PERIPHERAL, enable_cc); + else + switch_type_c_dr_mode(type_c, 0, DISABLE_CC); + + return 0; +} + +static const struct typec_operations type_c_port_ops = { + .dr_set = type_c_port_dr_set, +}; + +#ifdef CONFIG_DEBUG_FS +static int type_c_parameter_show(struct seq_file *s, void *unused) +{ + struct type_c_data *type_c = s->private; + struct type_c_cfg *type_c_cfg = type_c->type_c_cfg; + struct cc_param *cc_param; + unsigned long flags; + + spin_lock_irqsave(&type_c->lock, flags); + + seq_printf(s, "cc_dfp_mode %s\n", + ({ char *tmp; + switch (type_c_cfg->cc_dfp_mode) { + case CC_MODE_DFP_USB: + tmp = "CC_MODE_DFP_USB"; break; + case CC_MODE_DFP_1_5: + tmp = "CC_MODE_DFP_1_5"; break; + case CC_MODE_DFP_3_0: + tmp = "CC_MODE_DFP_3_0"; break; + default: + tmp = "?"; break; + } tmp; })); + + seq_printf(s, "dfp_mode_rp_en 0x%x\n", type_c->dfp_mode_rp_en); + seq_printf(s, "ufp_mode_rd_en 0x%x\n", type_c->ufp_mode_rd_en); + seq_printf(s, "cc1_code 0x%x\n", type_c->cc1_code); + seq_printf(s, "cc2_code 0x%x\n", type_c->cc2_code); + seq_printf(s, "cc1_vref 0x%x\n", type_c->cc1_vref); + seq_printf(s, "cc2_vref 0x%x\n", type_c->cc2_vref); + seq_printf(s, "debounce 0x%x\n", type_c->debounce); + seq_puts(s, "\n"); + + cc_param = &type_c_cfg->cc1_param; + seq_puts(s, "cc1_param:\n"); + seq_printf(s, " rp_4p7k_code 0x%x\n", cc_param->rp_4p7k_code); + seq_printf(s, " rp_36k_code 0x%x\n", cc_param->rp_36k_code); + seq_printf(s, " rp_12k_code 0x%x\n", cc_param->rp_12k_code); + seq_printf(s, " rd_code 0x%x\n", cc_param->rd_code); + seq_printf(s, " vref_2p6v 0x%x\n", cc_param->vref_2p6v); + seq_printf(s, " vref_1p23v 0x%x\n", cc_param->vref_1p23v); + seq_printf(s, " vref_0p8v 0x%x\n", cc_param->vref_0p8v); + seq_printf(s, " vref_0p66v 0x%x\n", cc_param->vref_0p66v); + seq_printf(s, " vref_0p4v 0x%x\n", cc_param->vref_0p4v); + seq_printf(s, " vref_0p2v 0x%x\n", cc_param->vref_0p2v); + seq_printf(s, " vref_1_1p6v 0x%x\n", cc_param->vref_1_1p6v); + seq_printf(s, " vref_0_1p6v 0x%x\n", cc_param->vref_0_1p6v); + + cc_param = &type_c_cfg->cc2_param; + seq_puts(s, "cc2_param:\n"); + seq_printf(s, " rp_4p7k_code 0x%x\n", cc_param->rp_4p7k_code); + seq_printf(s, " rp_36k_code 0x%x\n", cc_param->rp_36k_code); + seq_printf(s, " rp_12k_code 0x%x\n", cc_param->rp_12k_code); + seq_printf(s, " rd_code 0x%x\n", cc_param->rd_code); + seq_printf(s, " vref_2p6v 0x%x\n", cc_param->vref_2p6v); + seq_printf(s, " vref_1p23v 0x%x\n", cc_param->vref_1p23v); + seq_printf(s, " vref_0p8v 0x%x\n", cc_param->vref_0p8v); + seq_printf(s, " vref_0p66v 0x%x\n", cc_param->vref_0p66v); + seq_printf(s, " vref_0p4v 0x%x\n", cc_param->vref_0p4v); + seq_printf(s, " vref_0p2v 0x%x\n", cc_param->vref_0p2v); + seq_printf(s, " vref_1_1p6v 0x%x\n", cc_param->vref_1_1p6v); + seq_printf(s, " vref_0_1p6v 0x%x\n", cc_param->vref_0_1p6v); + + spin_unlock_irqrestore(&type_c->lock, flags); + + return 0; +} + +static int type_c_parameter_open(struct inode *inode, struct file *file) +{ + return single_open(file, type_c_parameter_show, inode->i_private); +} + +static const struct file_operations type_c_parameter_fops = { + .open = type_c_parameter_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +static int type_c_status_show(struct seq_file *s, void *unused) +{ + struct type_c_data *type_c = s->private; + unsigned long flags; + + spin_lock_irqsave(&type_c->lock, flags); + + seq_printf(s, "In %s mode %s at %s (cc_status=0x%x)\n", + type_c->cc_mode == IN_HOST_MODE ? "host" : "device", + type_c->is_attach ? "attach" : "detach", + type_c->at_cc1 ? "cc1" : "cc2", type_c->cc_status); + + seq_printf(s, "Read Register (type_c_ctrl_cc1_0=0x%x)\n", + readl(type_c->reg_base + 0x0)); + seq_printf(s, "Read Register (type_c_ctrl_cc1_1=0x%x)\n", + readl(type_c->reg_base + 0x4)); + seq_printf(s, "Read Register (type_c_ctrl_cc2_0=0x%x)\n", + readl(type_c->reg_base + 0x8)); + seq_printf(s, "Read Register (type_c_ctrl_cc2_1=0x%x)\n", + readl(type_c->reg_base + 0xc)); + seq_printf(s, "Read Register (type_c_status=0x%x)\n", + readl(type_c->reg_base + 0x10)); + seq_printf(s, "Read Register (type_c_ctrl=0x%x)\n", + readl(type_c->reg_base + 0x14)); + + spin_unlock_irqrestore(&type_c->lock, flags); + + return 0; +} + +static int type_c_status_open(struct inode *inode, struct file *file) +{ + return single_open(file, type_c_status_show, inode->i_private); +} + +static const struct file_operations type_c_status_fops = { + .open = type_c_status_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +static inline void create_debug_files(struct type_c_data *type_c) +{ + type_c->debug_dir = debugfs_create_dir("type_c", usb_debug_root); + + debugfs_create_file("parameter", 0444, type_c->debug_dir, type_c, + &type_c_parameter_fops); + + debugfs_create_file("status", 0444, type_c->debug_dir, type_c, + &type_c_status_fops); +} + +static inline void remove_debug_files(struct type_c_data *type_c) +{ + debugfs_remove_recursive(type_c->debug_dir); +} +#else +static inline void create_debug_files(struct type_c_data *type_c) { } +static inline void remove_debug_files(struct type_c_data *type_c) { } +#endif /* CONFIG_DEBUG_FS */ + +/* Init and probe */ + +static inline s8 get_value(s8 value) +{ + return (((s8)value & 0x8) ? (-(s8)(0x7 & value)) : ((s8)(value))); +} + +static int __updated_type_c_parameter_by_efuse(struct type_c_data *type_c) +{ + struct type_c_cfg *type_c_cfg = type_c->type_c_cfg; + struct cc_param *cc_param; + struct nvmem_cell *cell; + s8 cc1_4p7k = 0; + s8 cc1_12k = 0; + s8 cc1_0p2v = 0; + s8 cc1_0p8v = 0; + s8 cc1_2p6v = 0; + s8 cc1_0p66v = 0; + s8 cc1_1p23v = 0; + s8 cc2_4p7k = 0; + s8 cc2_12k = 0; + s8 cc2_0p2v = 0; + s8 cc2_0p8v = 0; + s8 cc2_2p6v = 0; + s8 cc2_0p66v = 0; + s8 cc2_1p23v = 0; + + cell = nvmem_cell_get(type_c->dev, "usb-cal"); + if (IS_ERR(cell)) { + dev_warn(type_c->dev, "%s failed to get usb-cal: %ld\n", + __func__, PTR_ERR(cell)); + } else { + unsigned char *buf; + size_t buf_size; + int value_size = 4; + int value_mask = (BIT(value_size) - 1); + + buf = nvmem_cell_read(cell, &buf_size); + + cc1_0p2v = get_value((buf[0] >> value_size * 0) & value_mask); + cc1_0p8v = get_value((buf[0] >> value_size * 1) & value_mask); + cc1_2p6v = get_value((buf[1] >> value_size * 0) & value_mask); + cc1_0p66v = get_value((buf[1] >> value_size * 1) & value_mask); + cc1_1p23v = get_value((buf[2] >> value_size * 0) & value_mask); + + cc2_0p2v = get_value((buf[3] >> value_size * 0) & value_mask); + cc2_0p8v = get_value((buf[3] >> value_size * 1) & value_mask); + cc2_2p6v = get_value((buf[4] >> value_size * 0) & value_mask); + cc2_0p66v = get_value((buf[4] >> value_size * 1) & value_mask); + cc2_1p23v = get_value((buf[5] >> value_size * 0) & value_mask); + + cc1_4p7k = get_value((buf[6] >> value_size * 0) & value_mask); + cc1_12k = get_value((buf[6] >> value_size * 1) & value_mask); + cc2_4p7k = get_value((buf[7] >> value_size * 0) & value_mask); + cc2_12k = get_value((buf[7] >> value_size * 1) & value_mask); + + kfree(buf); + nvmem_cell_put(cell); + } + + dev_dbg(type_c->dev, "check efuse cc1_4p7k=%d cc1_12k=%d cc2_4p7k=%d cc2_12k=%d\n", + cc1_4p7k, cc1_12k, cc2_4p7k, cc2_12k); + dev_dbg(type_c->dev, "check efuse cc1_0p2v=%d cc1_0p8v=%d cc1_2p6v=%d cc1_0p66v=%d cc1_1p23v=%d\n", + cc1_0p2v, cc1_0p8v, cc1_2p6v, cc1_0p66v, cc1_1p23v); + dev_dbg(type_c->dev, "check efuse cc2_0p2v=%d cc2_0p8v=%d cc2_2p6v=%d cc2_0p66v=%d cc2_1p23v=%d\n", + cc2_0p2v, cc2_0p8v, cc2_2p6v, cc2_0p66v, cc2_1p23v); + + cc_param = &type_c_cfg->cc1_param; + cc_param->rp_4p7k_code = cc_param->rp_4p7k_code + cc1_4p7k; + cc_param->rp_12k_code = cc_param->rp_12k_code + cc1_12k; + + cc_param->vref_1p23v = cc_param->vref_1p23v + cc1_1p23v; + cc_param->vref_0p66v = cc_param->vref_0p66v + cc1_0p66v; + cc_param->vref_2p6v = cc_param->vref_2p6v + cc1_2p6v; + cc_param->vref_0p8v = cc_param->vref_0p8v + cc1_0p8v; + cc_param->vref_0p2v = cc_param->vref_0p2v + cc1_0p2v; + + cc_param = &type_c_cfg->cc2_param; + cc_param->rp_4p7k_code = cc_param->rp_4p7k_code + cc2_4p7k; + cc_param->rp_12k_code = cc_param->rp_12k_code + cc2_12k; + + cc_param->vref_1p23v = cc_param->vref_1p23v + cc2_1p23v; + cc_param->vref_0p66v = cc_param->vref_0p66v + cc2_0p66v; + cc_param->vref_2p6v = cc_param->vref_2p6v + cc2_2p6v; + cc_param->vref_0p8v = cc_param->vref_0p8v + cc2_0p8v; + cc_param->vref_0p2v = cc_param->vref_0p2v + cc2_0p2v; + + return 0; +} + +static int __updated_type_c_parameter_by_efuse_v2(struct type_c_data *type_c) +{ + struct type_c_cfg *type_c_cfg = type_c->type_c_cfg; + struct cc_param *cc_param; + struct nvmem_cell *cell; + s8 cc1_4p7k = 0; + s8 cc1_12k = 0; + s8 cc1_0p2v = 0; + s8 cc1_0p8v = 0; + s8 cc1_2p6v = 0; + s8 cc1_0p66v = 0; + s8 cc1_1p23v = 0; + s8 cc2_4p7k = 0; + s8 cc2_12k = 0; + s8 cc2_0p2v = 0; + s8 cc2_0p8v = 0; + s8 cc2_2p6v = 0; + s8 cc2_0p66v = 0; + s8 cc2_1p23v = 0; + + cell = nvmem_cell_get(type_c->dev, "usb-type-c-cal"); + if (IS_ERR(cell)) { + dev_warn(type_c->dev, "%s failed to get usb-type-c-cal: %ld\n", + __func__, PTR_ERR(cell)); + } else { + unsigned char *buf; + size_t buf_size; + int value_size = 0; + int value_mask = (BIT(value_size) - 1); + + buf = nvmem_cell_read(cell, &buf_size); + + value_size = 5; + value_mask = (BIT(value_size) - 1); + cc1_4p7k = buf[0] & value_mask; + cc1_12k = buf[1] & value_mask; + cc2_4p7k = buf[2] & value_mask; + cc2_12k = buf[3] & value_mask; + + value_size = 4; + value_mask = (BIT(value_size) - 1); + cc1_0p2v = (buf[4] >> value_size * 0) & value_mask; + cc1_0p66v = (buf[4] >> value_size * 1) & value_mask; + cc1_0p8v = (buf[5] >> value_size * 0) & value_mask; + cc1_1p23v = (buf[5] >> value_size * 1) & value_mask; + cc1_2p6v = (buf[6] >> value_size * 0) & value_mask; + + cc2_0p2v = (buf[6] >> value_size * 1) & value_mask; + cc2_0p66v = (buf[7] >> value_size * 0) & value_mask; + cc2_0p8v = (buf[7] >> value_size * 1) & value_mask; + cc2_1p23v = (buf[8] >> value_size * 0) & value_mask; + cc2_2p6v = (buf[8] >> value_size * 1) & value_mask; + + kfree(buf); + nvmem_cell_put(cell); + } + + dev_dbg(type_c->dev, "check efuse v2 cc1_4p7k=%d cc1_12k=%d cc2_4p7k=%d cc2_12k=%d\n", + cc1_4p7k, cc1_12k, cc2_4p7k, cc2_12k); + dev_dbg(type_c->dev, "check efuse v2 cc1_0p2v=%d cc1_0p8v=%d cc1_2p6v=%d cc1_0p66v=%d cc1_1p23v=%d\n", + cc1_0p2v, cc1_0p8v, cc1_2p6v, cc1_0p66v, cc1_1p23v); + dev_dbg(type_c->dev, "check efuse v2 cc2_0p2v=%d cc2_0p8v=%d cc2_2p6v=%d cc2_0p66v=%d cc2_1p23v=%d\n", + cc2_0p2v, cc2_0p8v, cc2_2p6v, cc2_0p66v, cc2_1p23v); + + cc_param = &type_c_cfg->cc1_param; + if (cc1_4p7k) + cc_param->rp_4p7k_code = cc1_4p7k; + if (cc1_12k) + cc_param->rp_12k_code = cc1_12k; + + if (cc1_1p23v) + cc_param->vref_1p23v = cc1_1p23v; + if (cc1_0p66v) + cc_param->vref_0p66v = cc1_0p66v; + if (cc1_2p6v) + cc_param->vref_2p6v = cc1_2p6v; + if (cc1_0p8v) + cc_param->vref_0p8v = cc1_0p8v; + if (cc1_0p2v) + cc_param->vref_0p2v = cc1_0p2v; + + cc_param = &type_c_cfg->cc2_param; + if (cc2_4p7k) + cc_param->rp_4p7k_code = cc2_4p7k; + if (cc2_12k) + cc_param->rp_12k_code = cc2_12k; + + if (cc2_1p23v) + cc_param->vref_1p23v = cc2_1p23v; + if (cc2_0p66v) + cc_param->vref_0p66v = cc2_0p66v; + if (cc2_2p6v) + cc_param->vref_2p6v = cc2_2p6v; + if (cc2_0p8v) + cc_param->vref_0p8v = cc2_0p8v; + if (cc2_0p2v) + cc_param->vref_0p2v = cc2_0p2v; + + return 0; +} + +static void get_default_type_c_parameter(struct type_c_data *type_c) +{ + void __iomem *reg; + int val; + + type_c->dfp_mode_rp_en = dfp_mode(CC_MODE_DFP_3_0) | EN_RP4P7K; + type_c->ufp_mode_rd_en = EN_RD; + + reg = type_c->reg_base + USB_TYPEC_CTRL_CC1_0; + val = readl(reg); + type_c->cc1_code = CC_CODE_MASK & val; + + reg = type_c->reg_base + USB_TYPEC_CTRL_CC2_0; + val = readl(reg); + type_c->cc2_code = CC_CODE_MASK & val; + + reg = type_c->reg_base + USB_TYPEC_CTRL_CC1_1; + val = readl(reg); + type_c->cc1_vref = val; + + reg = type_c->reg_base + USB_TYPEC_CTRL_CC2_1; + val = readl(reg); + type_c->cc2_vref = val; + + reg = type_c->reg_base + USB_TYPEC_CTRL; + val = readl(reg); + type_c->debounce = DEBOUNCE_TIME_MASK & val; +} + +static int setup_type_c_parameter(struct type_c_data *type_c) +{ + struct type_c_cfg *type_c_cfg = type_c->type_c_cfg; + struct cc_param *cc_param; + struct soc_device_attribute rtk_soc_efuse_v1[] = { + { .family = "Realtek Phoenix",}, + { .family = "Realtek Kylin",}, + { .family = "Realtek Hercules",}, + { .family = "Realtek Thor",}, + { .family = "Realtek Hank",}, + { .family = "Realtek Groot",}, + { .family = "Realtek Stark",}, + { .family = "Realtek Parker",}, + { /* empty */ } + }; + + if (type_c_cfg->use_defalut_parameter) { + get_default_type_c_parameter(type_c); + return 0; + } + + if (soc_device_match(rtk_soc_efuse_v1)) + __updated_type_c_parameter_by_efuse(type_c); + else + __updated_type_c_parameter_by_efuse_v2(type_c); + + /* + * UFP rd vref_ufp : 1p23v, 0p66v, 0p2v + * DFP_USB rp36k vref_dfp_usb: 0_1p6v, 0p2v, unused + * DFP_1.5 rp12k vref_dfp_1_5: 1_1p6v, 0p4v, 0p2v + * DFP_3.0 rp4p7k vref_dfp_3_0: 2p6v, 0p8v, 0p2v + */ + + switch (type_c_cfg->cc_dfp_mode) { + case CC_MODE_DFP_USB: + type_c->dfp_mode_rp_en = dfp_mode(CC_MODE_DFP_USB) | EN_RP36K; + break; + case CC_MODE_DFP_1_5: + type_c->dfp_mode_rp_en = dfp_mode(CC_MODE_DFP_1_5) | EN_RP12K; + break; + case CC_MODE_DFP_3_0: + type_c->dfp_mode_rp_en = dfp_mode(CC_MODE_DFP_3_0) | EN_RP4P7K; + break; + default: + dev_err(type_c->dev, "%s: unknown cc_dfp_mode %d\n", + __func__, type_c_cfg->cc_dfp_mode); + } + + type_c->ufp_mode_rd_en = EN_RD; + + cc_param = &type_c_cfg->cc1_param; + type_c->cc1_code = rp4pk_code(cc_param->rp_4p7k_code) | + rp36k_code(cc_param->rp_36k_code) | + rp12k_code(cc_param->rp_12k_code) | + rd_code(cc_param->rd_code); + + if (type_c_cfg->parameter_ver == PARAMETER_V0) + type_c->cc1_vref = V0_vref_2p6v(cc_param->vref_2p6v) | + V0_vref_1p23v(cc_param->vref_1p23v) | + V0_vref_0p8v(cc_param->vref_0p8v) | + V0_vref_0p66v(cc_param->vref_0p66v) | + V0_vref_0p4v(cc_param->vref_0p4v) | + V0_vref_0p2v(cc_param->vref_0p2v) | + V0_vref_1_1p6v(cc_param->vref_1_1p6v) | + V0_vref_0_1p6v(cc_param->vref_0_1p6v); + else if (type_c_cfg->parameter_ver == PARAMETER_V1) + type_c->cc1_vref = V1_vref_2p6v(cc_param->vref_2p6v) | + V1_vref_1p23v(cc_param->vref_1p23v) | + V1_vref_0p8v(cc_param->vref_0p8v) | + V1_vref_0p66v(cc_param->vref_0p66v) | + V1_vref_0p4v(cc_param->vref_0p4v) | + V1_vref_0p2v(cc_param->vref_0p2v) | + V1_vref_1_1p6v(cc_param->vref_1_1p6v) | + V1_vref_0_1p6v(cc_param->vref_0_1p6v); + else + dev_err(type_c->dev, "%s: unknown parameter_ver %d\n", + __func__, type_c_cfg->parameter_ver); + + cc_param = &type_c_cfg->cc2_param; + type_c->cc2_code = rp4pk_code(cc_param->rp_4p7k_code) + | rp36k_code(cc_param->rp_36k_code) + | rp12k_code(cc_param->rp_12k_code) + | rd_code(cc_param->rd_code); + + if (type_c_cfg->parameter_ver == PARAMETER_V0) + type_c->cc2_vref = V0_vref_2p6v(cc_param->vref_2p6v) | + V0_vref_1p23v(cc_param->vref_1p23v) | + V0_vref_0p8v(cc_param->vref_0p8v) | + V0_vref_0p66v(cc_param->vref_0p66v) | + V0_vref_0p4v(cc_param->vref_0p4v) | + V0_vref_0p2v(cc_param->vref_0p2v) | + V0_vref_1_1p6v(cc_param->vref_1_1p6v) | + V0_vref_0_1p6v(cc_param->vref_0_1p6v); + else if (type_c_cfg->parameter_ver == PARAMETER_V1) + type_c->cc2_vref = V1_vref_2p6v(cc_param->vref_2p6v) | + V1_vref_1p23v(cc_param->vref_1p23v) | + V1_vref_0p8v(cc_param->vref_0p8v) | + V1_vref_0p66v(cc_param->vref_0p66v) | + V1_vref_0p4v(cc_param->vref_0p4v) | + V1_vref_0p2v(cc_param->vref_0p2v) | + V1_vref_1_1p6v(cc_param->vref_1_1p6v) | + V1_vref_0_1p6v(cc_param->vref_0_1p6v); + else + dev_err(type_c->dev, "%s: unknown parameter_ver %d\n", + __func__, type_c_cfg->parameter_ver); + + type_c->debounce = (type_c_cfg->debounce_val << 1) | DEBOUNCE_EN; + + return 0; +} + +static int extcon_rtk_type_c_init(struct type_c_data *type_c) +{ + struct device *dev = type_c->dev; + unsigned long flags; + void __iomem *reg; + int val; + + spin_lock_irqsave(&type_c->lock, flags); + + /* set parameter */ + reg = type_c->reg_base + USB_TYPEC_CTRL_CC1_0; + val = readl(reg); + val = (~CC_CODE_MASK & val) | (type_c->cc1_code & CC_CODE_MASK); + writel(val, reg); + + reg = type_c->reg_base + USB_TYPEC_CTRL_CC2_0; + val = readl(reg); + val = (~CC_CODE_MASK & val) | (type_c->cc2_code & CC_CODE_MASK); + + reg = type_c->reg_base + USB_TYPEC_CTRL_CC1_1; + writel(type_c->cc1_vref, reg); + + reg = type_c->reg_base + USB_TYPEC_CTRL_CC2_1; + writel(type_c->cc2_vref, reg); + + reg = type_c->reg_base + USB_TYPEC_CTRL; + val = readl(reg); + val = (~DEBOUNCE_TIME_MASK & val) | (type_c->debounce & DEBOUNCE_TIME_MASK); + + dev_info(dev, "First check USB_DR_MODE_PERIPHERAL"); + type_c->cc_mode = IN_DEVICE_MODE; + type_c->is_attach = IN_DETACH; + type_c->connect_change = CONNECT_NO_CHANGE; + + detect_host(type_c); + + spin_unlock_irqrestore(&type_c->lock, flags); + + schedule_delayed_work(&type_c->delayed_work, msecs_to_jiffies(0)); + + if (!type_c->port) { + struct typec_capability typec_cap = { }; + struct fwnode_handle *fwnode; + const char *buf; + int ret; + + typec_cap.revision = USB_TYPEC_REV_1_0; + typec_cap.prefer_role = TYPEC_NO_PREFERRED_ROLE; + typec_cap.driver_data = type_c; + typec_cap.ops = &type_c_port_ops; + + fwnode = device_get_named_child_node(dev, "connector"); + if (!fwnode) + return -EINVAL; + + ret = fwnode_property_read_string(fwnode, "power-role", &buf); + if (ret) { + dev_err(dev, "power-role not found: %d\n", ret); + return ret; + } + + ret = typec_find_port_power_role(buf); + if (ret < 0) + return ret; + typec_cap.type = ret; + + ret = fwnode_property_read_string(fwnode, "data-role", &buf); + if (ret) { + dev_err(dev, "data-role not found: %d\n", ret); + return ret; + } + + ret = typec_find_port_data_role(buf); + if (ret < 0) + return ret; + typec_cap.data = ret; + + type_c->port = typec_register_port(type_c->dev, &typec_cap); + if (IS_ERR(type_c->port)) + return PTR_ERR(type_c->port); + } + + return 0; +} + +static int extcon_rtk_type_c_edev_register(struct type_c_data *type_c) +{ + struct device *dev = type_c->dev; + int ret = 0; + + type_c->edev = devm_extcon_dev_allocate(dev, usb_type_c_cable); + if (IS_ERR(type_c->edev)) { + dev_err(dev, "failed to allocate extcon device\n"); + return -ENOMEM; + } + + ret = devm_extcon_dev_register(dev, type_c->edev); + if (ret < 0) { + dev_err(dev, "failed to register extcon device\n"); + return ret; + } + + extcon_set_property_capability(type_c->edev, EXTCON_USB, + EXTCON_PROP_USB_VBUS); + extcon_set_property_capability(type_c->edev, EXTCON_USB, + EXTCON_PROP_USB_TYPEC_POLARITY); + extcon_set_property_capability(type_c->edev, EXTCON_USB, + EXTCON_PROP_USB_SS); + + extcon_set_property_capability(type_c->edev, EXTCON_USB_HOST, + EXTCON_PROP_USB_VBUS); + extcon_set_property_capability(type_c->edev, EXTCON_USB_HOST, + EXTCON_PROP_USB_TYPEC_POLARITY); + extcon_set_property_capability(type_c->edev, EXTCON_USB_HOST, + EXTCON_PROP_USB_SS); + + return ret; +} + +static int extcon_rtk_type_c_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct type_c_data *type_c; + const struct type_c_cfg *type_c_cfg; + int ret = 0; + + type_c = devm_kzalloc(dev, sizeof(*type_c), GFP_KERNEL); + if (!type_c) + return -ENOMEM; + + type_c->reg_base = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(type_c->reg_base)) + return PTR_ERR(type_c->reg_base); + + type_c->dev = dev; + + type_c->irq = irq_of_parse_and_map(pdev->dev.of_node, 0); + if (type_c->irq <= 0) { + dev_err(&pdev->dev, "Type C driver with no IRQ. Check %s setup!\n", + dev_name(&pdev->dev)); + ret = -ENODEV; + goto err; + } + + ret = devm_request_irq(dev, type_c->irq, type_c_detect_irq, + IRQF_SHARED, "type_c_detect", type_c); + + spin_lock_init(&type_c->lock); + + type_c->rd_ctrl_gpio_desc = NULL; + if (soc_device_match(rtk_soc_kylin)) { + struct gpio_desc *gpio; + + gpio = fwnode_gpiod_get_index(of_fwnode_handle(dev->of_node), + "realtek,rd-ctrl-gpios", + 0, GPIOD_OUT_HIGH, "rd-ctrl-gpio"); + if (IS_ERR(gpio)) { + dev_err(dev, "Error rd_ctrl-gpios no found (err=%d)\n", + (int)PTR_ERR(gpio)); + } else { + type_c->rd_ctrl_gpio_desc = gpio; + dev_dbg(dev, "%s get rd-ctrl-gpios (id=%d) OK\n", + __func__, desc_to_gpio(gpio)); + } + } + + type_c_cfg = of_device_get_match_data(dev); + if (!type_c_cfg) { + dev_err(dev, "type_c config are not assigned!\n"); + ret = -EINVAL; + goto err; + } + + type_c->type_c_cfg = devm_kzalloc(dev, sizeof(*type_c_cfg), GFP_KERNEL); + + memcpy(type_c->type_c_cfg, type_c_cfg, sizeof(*type_c_cfg)); + + if (setup_type_c_parameter(type_c)) { + dev_err(dev, "ERROR: %s to setup type c parameter!!", __func__); + ret = -EINVAL; + goto err; + } + + INIT_DELAYED_WORK(&type_c->delayed_work, host_device_switch); + + ret = extcon_rtk_type_c_init(type_c); + if (ret) { + dev_err(dev, "%s failed to init type_c\n", __func__); + goto err; + } + + platform_set_drvdata(pdev, type_c); + + ret = extcon_rtk_type_c_edev_register(type_c); + + create_debug_files(type_c); + + return 0; + +err: + dev_err(&pdev->dev, "%s: Probe fail, %d\n", __func__, ret); + + return ret; +} + +static void extcon_rtk_type_c_remove(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct type_c_data *type_c = dev_get_drvdata(dev); + u32 default_ctrl; + unsigned long flags; + + remove_debug_files(type_c); + + if (type_c->port) { + typec_unregister_port(type_c->port); + type_c->port = NULL; + } + + cancel_delayed_work_sync(&type_c->delayed_work); + flush_delayed_work(&type_c->delayed_work); + WARN_ON_ONCE(delayed_work_pending(&type_c->delayed_work)); + + spin_lock_irqsave(&type_c->lock, flags); + /* disable interrupt */ + default_ctrl = readl(type_c->reg_base + USB_TYPEC_CTRL) & + DEBOUNCE_TIME_MASK; + writel(default_ctrl, type_c->reg_base + USB_TYPEC_CTRL); + + /* disable cc detect, rp, rd */ + writel(PLR_EN, type_c->reg_base + USB_TYPEC_CTRL_CC1_0); + writel(0, type_c->reg_base + USB_TYPEC_CTRL_CC2_0); + + spin_unlock_irqrestore(&type_c->lock, flags); + + if (type_c->rd_ctrl_gpio_desc) + gpiod_put(type_c->rd_ctrl_gpio_desc); + type_c->rd_ctrl_gpio_desc = NULL; + + free_irq(type_c->irq, type_c); +} + +static const struct type_c_cfg rtd1295_type_c_cfg = { + .parameter_ver = PARAMETER_V0, + .cc_dfp_mode = CC_MODE_DFP_3_0, + .cc1_param = { .rp_4p7k_code = 0xb, + .rp_36k_code = 0x17, + .rp_12k_code = 0x10, + .rd_code = 0, + .ra_code = 0, + .vref_2p6v = 0x0, + .vref_1p23v = 0x0, + .vref_0p8v = 0x3, + .vref_0p66v = 0x0, + .vref_0p4v = 0x0, + .vref_0p2v = 0x4, + .vref_1_1p6v = 0, + .vref_0_1p6v = 0 }, + .cc2_param = { .rp_4p7k_code = 0xc, + .rp_36k_code = 0x17, + .rp_12k_code = 0x12, + .rd_code = 0, + .ra_code = 0, + .vref_2p6v = 0x2, + .vref_1p23v = 0x0, + .vref_0p8v = 0x3, + .vref_0p66v = 0x0, + .vref_0p4v = 0x0, + .vref_0p2v = 0x5, + .vref_1_1p6v = 0, + .vref_0_1p6v = 0 }, + .debounce_val = 0x7f, /* 1b,1us 7f,4.7us */ + .use_defalut_parameter = false, +}; + +static const struct type_c_cfg rtd1395_type_c_cfg = { + .parameter_ver = PARAMETER_V0, + .cc_dfp_mode = CC_MODE_DFP_3_0, + .cc1_param = { .rp_4p7k_code = 0xc, + .rp_36k_code = 0xb, + .rp_12k_code = 0xe, + .rd_code = 0x10, + .ra_code = 0x0, + .vref_2p6v = 0x0, + .vref_1p23v = 0x1, + .vref_0p8v = 0x0, + .vref_0p66v = 0x0, + .vref_0p4v = 0x3, + .vref_0p2v = 0x0, + .vref_1_1p6v = 0x7, + .vref_0_1p6v = 0x7 }, + .cc2_param = { .rp_4p7k_code = 0xb, + .rp_36k_code = 0x9, + .rp_12k_code = 0xe, + .rd_code = 0xf, + .ra_code = 0x0, + .vref_2p6v = 0x1, + .vref_1p23v = 0x3, + .vref_0p8v = 0x3, + .vref_0p66v = 0x2, + .vref_0p4v = 0x3, + .vref_0p2v = 0x2, + .vref_1_1p6v = 0x7, + .vref_0_1p6v = 0x7 }, + .debounce_val = 0x7f, /* 1b,1us 7f,4.7us */ + .use_defalut_parameter = false, +}; + +static const struct type_c_cfg rtd1619_type_c_cfg = { + .parameter_ver = PARAMETER_V0, + .cc_dfp_mode = CC_MODE_DFP_3_0, + .cc1_param = { .rp_4p7k_code = 0xc, + .rp_36k_code = 0xf, + .rp_12k_code = 0xe, + .rd_code = 0x11, + .ra_code = 0x0, + .vref_2p6v = 0x5, + .vref_1p23v = 0x7, + .vref_0p8v = 0xa, + .vref_0p66v = 0xa, + .vref_0p4v = 0x3, + .vref_0p2v = 0x2, + .vref_1_1p6v = 0x7, + .vref_0_1p6v = 0x7 }, + .cc2_param = { .rp_4p7k_code = 0xc, + .rp_36k_code = 0xf, + .rp_12k_code = 0xe, + .rd_code = 0xf, + .ra_code = 0x0, + .vref_2p6v = 0x5, + .vref_1p23v = 0x8, + .vref_0p8v = 0xa, + .vref_0p66v = 0xa, + .vref_0p4v = 0x3, + .vref_0p2v = 0x2, + .vref_1_1p6v = 0x7, + .vref_0_1p6v = 0x7 }, + .debounce_val = 0x7f, /* 1b,1us 7f,4.7us */ + .use_defalut_parameter = false, +}; + +static const struct type_c_cfg rtd1319_type_c_cfg = { + .parameter_ver = PARAMETER_V0, + .cc_dfp_mode = CC_MODE_DFP_1_5, + .cc1_param = { .rp_4p7k_code = 0x9, + .rp_36k_code = 0xe, + .rp_12k_code = 0x9, + .rd_code = 0x9, + .ra_code = 0x7, + .vref_2p6v = 0x3, + .vref_1p23v = 0x7, + .vref_0p8v = 0x7, + .vref_0p66v = 0x6, + .vref_0p4v = 0x2, + .vref_0p2v = 0x3, + .vref_1_1p6v = 0x4, + .vref_0_1p6v = 0x7 }, + .cc2_param = { .rp_4p7k_code = 0x8, + .rp_36k_code = 0xe, + .rp_12k_code = 0x9, + .rd_code = 0x9, + .ra_code = 0x7, + .vref_2p6v = 0x3, + .vref_1p23v = 0x7, + .vref_0p8v = 0x7, + .vref_0p66v = 0x6, + .vref_0p4v = 0x3, + .vref_0p2v = 0x3, + .vref_1_1p6v = 0x6, + .vref_0_1p6v = 0x7 }, + .debounce_val = 0x7f, /* 1b,1us 7f,4.7us */ + .use_defalut_parameter = false, +}; + +static const struct type_c_cfg rtd1312c_type_c_cfg = { + .parameter_ver = PARAMETER_V0, + .cc_dfp_mode = CC_MODE_DFP_1_5, + .cc1_param = { .rp_4p7k_code = 0xe, + .rp_36k_code = 0xc, + .rp_12k_code = 0xc, + .rd_code = 0xa, + .ra_code = 0x3, + .vref_2p6v = 0xa, + .vref_1p23v = 0x7, + .vref_0p8v = 0x7, + .vref_0p66v = 0x7, + .vref_0p4v = 0x4, + .vref_0p2v = 0x4, + .vref_1_1p6v = 0x7, + .vref_0_1p6v = 0x7 }, + .cc2_param = { .rp_4p7k_code = 0xe, + .rp_36k_code = 0xc, + .rp_12k_code = 0xc, + .rd_code = 0xa, + .ra_code = 0x3, + .vref_2p6v = 0xa, + .vref_1p23v = 0x7, + .vref_0p8v = 0x7, + .vref_0p66v = 0x7, + .vref_0p4v = 0x4, + .vref_0p2v = 0x4, + .vref_1_1p6v = 0x7, + .vref_0_1p6v = 0x7 }, + .debounce_val = 0x7f, /* 1b,1us 7f,4.7us */ + .use_defalut_parameter = false, +}; + +static const struct type_c_cfg rtd1619b_type_c_cfg = { + .parameter_ver = PARAMETER_V1, + .cc_dfp_mode = CC_MODE_DFP_1_5, + .cc1_param = { .rp_4p7k_code = 0xf, + .rp_36k_code = 0xf, + .rp_12k_code = 0xf, + .rd_code = 0xf, + .ra_code = 0x7, + .vref_2p6v = 0x9, + .vref_1p23v = 0x7, + .vref_0p8v = 0x9, + .vref_0p66v = 0x8, + .vref_0p4v = 0x7, + .vref_0p2v = 0x9, + .vref_1_1p6v = 0x7, + .vref_0_1p6v = 0x7 }, + .cc2_param = { .rp_4p7k_code = 0xf, + .rp_36k_code = 0xf, + .rp_12k_code = 0xf, + .rd_code = 0xf, + .ra_code = 0x7, + .vref_1p23v = 0x7, + .vref_0p8v = 0x9, + .vref_0p66v = 0x8, + .vref_0p4v = 0x7, + .vref_0p2v = 0x8, + .vref_1_1p6v = 0x7, + .vref_0_1p6v = 0x7 }, + .debounce_val = 0x7f, /* 1b,1us 7f,4.7us */ + .use_defalut_parameter = false, +}; + +static const struct type_c_cfg rtd1319d_type_c_cfg = { + .parameter_ver = PARAMETER_V1, + .cc_dfp_mode = CC_MODE_DFP_1_5, + .cc1_param = { .rp_4p7k_code = 0xe, + .rp_36k_code = 0x3, + .rp_12k_code = 0xe, + .rd_code = 0xf, + .ra_code = 0x6, + .vref_2p6v = 0x7, + .vref_1p23v = 0x7, + .vref_0p8v = 0x8, + .vref_0p66v = 0x7, + .vref_0p4v = 0x7, + .vref_0p2v = 0x7, + .vref_1_1p6v = 0x7, + .vref_0_1p6v = 0x7 }, + .cc2_param = { .rp_4p7k_code = 0xe, + .rp_36k_code = 0x3, + .rp_12k_code = 0xe, + .rd_code = 0xf, + .ra_code = 0x6, + .vref_2p6v = 0x7, + .vref_1p23v = 0x7, + .vref_0p8v = 0x8, + .vref_0p66v = 0x7, + .vref_0p4v = 0x7, + .vref_0p2v = 0x8, + .vref_1_1p6v = 0x7, + .vref_0_1p6v = 0x7 }, + .debounce_val = 0x7f, /* 1b,1us 7f,4.7us */ + .use_defalut_parameter = false, +}; + +static const struct type_c_cfg rtd1315e_type_c_cfg = { + .parameter_ver = PARAMETER_V1, + .cc_dfp_mode = CC_MODE_DFP_1_5, + .cc1_param = { .rp_4p7k_code = 0xe, + .rp_36k_code = 0x3, + .rp_12k_code = 0xe, + .rd_code = 0xf, + .ra_code = 0x6, + .vref_2p6v = 0x7, + .vref_1p23v = 0x7, + .vref_0p8v = 0x8, + .vref_0p66v = 0x7, + .vref_0p4v = 0x7, + .vref_0p2v = 0x7, + .vref_1_1p6v = 0x7, + .vref_0_1p6v = 0x7 }, + .cc2_param = { .rp_4p7k_code = 0xe, + .rp_36k_code = 0x3, + .rp_12k_code = 0xe, + .rd_code = 0xf, + .ra_code = 0x6, + .vref_2p6v = 0x7, + .vref_1p23v = 0x7, + .vref_0p8v = 0x8, + .vref_0p66v = 0x7, + .vref_0p4v = 0x7, + .vref_0p2v = 0x8, + .vref_1_1p6v = 0x7, + .vref_0_1p6v = 0x7 }, + .debounce_val = 0x7f, /* 1b,1us 7f,4.7us */ + .use_defalut_parameter = false, +}; + +static const struct of_device_id extcon_rtk_type_c_match[] = { + { .compatible = "realtek,rtd1295-type-c", .data = &rtd1295_type_c_cfg }, + { .compatible = "realtek,rtd1312c-type-c", .data = &rtd1312c_type_c_cfg }, + { .compatible = "realtek,rtd1315e-type-c", .data = &rtd1315e_type_c_cfg }, + { .compatible = "realtek,rtd1319-type-c", .data = &rtd1319_type_c_cfg }, + { .compatible = "realtek,rtd1319d-type-c", .data = &rtd1319d_type_c_cfg }, + { .compatible = "realtek,rtd1395-type-c", .data = &rtd1395_type_c_cfg }, + { .compatible = "realtek,rtd1619-type-c", .data = &rtd1619_type_c_cfg }, + { .compatible = "realtek,rtd1619b-type-c", .data = &rtd1619b_type_c_cfg }, + {}, +}; +MODULE_DEVICE_TABLE(of, extcon_rtk_type_c_match); + +#ifdef CONFIG_PM_SLEEP +static int extcon_rtk_type_c_prepare(struct device *dev) +{ + struct type_c_data *type_c = dev_get_drvdata(dev); + u32 default_ctrl; + unsigned long flags; + + cancel_delayed_work_sync(&type_c->delayed_work); + flush_delayed_work(&type_c->delayed_work); + WARN_ON_ONCE(delayed_work_pending(&type_c->delayed_work)); + + spin_lock_irqsave(&type_c->lock, flags); + /* disable interrupt */ + default_ctrl = readl(type_c->reg_base + USB_TYPEC_CTRL) & + DEBOUNCE_TIME_MASK; + writel(default_ctrl, type_c->reg_base + USB_TYPEC_CTRL); + + /* disable cc detect, rp, rd */ + writel(PLR_EN, type_c->reg_base + USB_TYPEC_CTRL_CC1_0); + writel(0, type_c->reg_base + USB_TYPEC_CTRL_CC2_0); + + spin_unlock_irqrestore(&type_c->lock, flags); + + return 0; +} + +static void extcon_rtk_type_c_complete(struct device *dev) +{ + /* nothing */ +} + +static int extcon_rtk_type_c_suspend(struct device *dev) +{ + /* nothing */ + + return 0; +} + +static int extcon_rtk_type_c_resume(struct device *dev) +{ + struct type_c_data *type_c = dev_get_drvdata(dev); + int ret; + + ret = extcon_rtk_type_c_init(type_c); + if (ret) { + dev_err(dev, "%s failed to init type_c\n", __func__); + return ret; + } + + return 0; +} + +static const struct dev_pm_ops extcon_rtk_type_c_pm_ops = { + SET_LATE_SYSTEM_SLEEP_PM_OPS(extcon_rtk_type_c_suspend, extcon_rtk_type_c_resume) + .prepare = extcon_rtk_type_c_prepare, + .complete = extcon_rtk_type_c_complete, +}; + +#define DEV_PM_OPS (&extcon_rtk_type_c_pm_ops) +#else +#define DEV_PM_OPS NULL +#endif /* CONFIG_PM_SLEEP */ + +static struct platform_driver extcon_rtk_type_c_driver = { + .probe = extcon_rtk_type_c_probe, + .remove_new = extcon_rtk_type_c_remove, + .driver = { + .name = "extcon-rtk-type_c", + .of_match_table = extcon_rtk_type_c_match, + .pm = DEV_PM_OPS, + }, +}; + +module_platform_driver(extcon_rtk_type_c_driver); + +MODULE_DESCRIPTION("Realtek Extcon Type C driver"); +MODULE_AUTHOR("Stanley Chang "); +MODULE_LICENSE("GPL"); From a1e932cefac987b5e4a7ddde37c99e3d2e6fe73e Mon Sep 17 00:00:00 2001 From: Stanley Chang Date: Mon, 4 Sep 2023 13:12:48 +0800 Subject: [PATCH 198/326] dt-bindings: usb: Add Realtek DHC RTD SoC Type-C Document the device-tree bindings for Realtek SoCs Type-C. Realtek DHC (digital home center) RTD SoCs support a Type-C module. Link: https://lore.kernel.org/lkml/20230904051253.23208-2-stanley_chang@realtek.com/ Signed-off-by: Stanley Chang Reviewed-by: Krzysztof Kozlowski Signed-off-by: Chanwoo Choi --- .../bindings/usb/realtek,rtd-type-c.yaml | 82 +++++++++++++++++++ 1 file changed, 82 insertions(+) create mode 100644 Documentation/devicetree/bindings/usb/realtek,rtd-type-c.yaml diff --git a/Documentation/devicetree/bindings/usb/realtek,rtd-type-c.yaml b/Documentation/devicetree/bindings/usb/realtek,rtd-type-c.yaml new file mode 100644 index 000000000000..6142b0b5b534 --- /dev/null +++ b/Documentation/devicetree/bindings/usb/realtek,rtd-type-c.yaml @@ -0,0 +1,82 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +# Copyright 2023 Realtek Semiconductor Corporation +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/usb/realtek,rtd-type-c.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Realtek DHC RTD SoCs USB Type-C Connector detection + +maintainers: + - Stanley Chang + +description: + Realtek digital home center (DHC) RTD series SoCs include a type c module. + This module is able to detect the state of type c connector. + +properties: + compatible: + enum: + - realtek,rtd1295-type-c + - realtek,rtd1312c-type-c + - realtek,rtd1315e-type-c + - realtek,rtd1319-type-c + - realtek,rtd1319d-type-c + - realtek,rtd1395-type-c + - realtek,rtd1619-type-c + - realtek,rtd1619b-type-c + + reg: + maxItems: 1 + + interrupts: + maxItems: 1 + + nvmem-cell-names: + items: + - const: usb-cal + + nvmem-cells: + maxItems: 1 + description: + The phandle to nvmem cell that contains the trimming data. + The type c parameter trimming data specified via efuse. + If unspecified, default value is used. + + realtek,rd-ctrl-gpios: + description: The gpio node to control external Rd on board. + maxItems: 1 + + connector: + $ref: /schemas/connector/usb-connector.yaml# + description: Properties for usb c connector. + type: object + +required: + - compatible + - reg + - interrupts + +additionalProperties: false + +examples: + - | + #include + + type-c@7220 { + compatible = "realtek,rtd1619b-type-c"; + reg = <0x7220 0x20>; + interrupts = <0 60 IRQ_TYPE_LEVEL_HIGH>; + + pinctrl-names = "default"; + pinctrl-0 = <&usb_cc1_pins>, <&usb_cc2_pins>; + nvmem-cells = <&otp_usb_cal>; + nvmem-cell-names = "usb-cal"; + + connector { + compatible = "usb-c-connector"; + label = "USB-C"; + data-role = "dual"; + power-role = "dual"; + }; + }; From 36d301f3da0a7a1fb626a3265aa677127efa9854 Mon Sep 17 00:00:00 2001 From: Marek Szyprowski Date: Fri, 6 Oct 2023 12:04:33 +0200 Subject: [PATCH 199/326] extcon: max77693: add device-tree compatible string Commit 57f706bf7307 ("ARM: dts: samsung: exynos4412-midas: add USB connector and USB OTG") added a 'muic' node to the MAX77693 PMIC definition in various device-tree files. Since that commit, the newly created MFD cell gained its own of_node and compatible string. This changed its modalias, what in turn broke automated loading of the driver module, because the new modalias is based on the of_node compatible string, not the platform device name. Fix this by adding the needed device-tree compatible string. Link: https://lore.kernel.org/all/20231006100434.2908243-1-m.szyprowski@samsung.com/ Signed-off-by: Marek Szyprowski Reviewed-by: Krzysztof Kozlowski Signed-off-by: Chanwoo Choi --- drivers/extcon/extcon-max77693.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/extcon/extcon-max77693.c b/drivers/extcon/extcon-max77693.c index 1f1d9ab0c5c7..2c567e0b7b7f 100644 --- a/drivers/extcon/extcon-max77693.c +++ b/drivers/extcon/extcon-max77693.c @@ -1258,9 +1258,16 @@ static int max77693_muic_probe(struct platform_device *pdev) return ret; } +static const struct of_device_id of_max77693_muic_dt_match[] = { + { .compatible = "maxim,max77693-muic", }, + { /* sentinel */ }, +}; +MODULE_DEVICE_TABLE(of, of_max77693_muic_dt_match); + static struct platform_driver max77693_muic_driver = { .driver = { .name = DEV_NAME, + .of_match_table = of_max77693_muic_dt_match, }, .probe = max77693_muic_probe, }; From da886ba844791d11c9d1526fddf8607eb0198243 Mon Sep 17 00:00:00 2001 From: Marek Szyprowski Date: Fri, 6 Oct 2023 12:04:34 +0200 Subject: [PATCH 200/326] extcon: max77843: add device-tree compatible string Add the needed device-tree compatible string to the MAX77843 extcon driver, so it can be automatically loaded when compiled as a kernel module and given device-tree contains separate 'muic' node under the main MAX77843 PMIC node. Link: https://lore.kernel.org/all/20231006100434.2908243-2-m.szyprowski@samsung.com/ Signed-off-by: Marek Szyprowski Reviewed-by: Krzysztof Kozlowski Signed-off-by: Chanwoo Choi --- drivers/extcon/extcon-max77843.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/extcon/extcon-max77843.c b/drivers/extcon/extcon-max77843.c index 1bc0426ce3f1..acb11a54f875 100644 --- a/drivers/extcon/extcon-max77843.c +++ b/drivers/extcon/extcon-max77843.c @@ -946,9 +946,16 @@ static const struct platform_device_id max77843_muic_id[] = { }; MODULE_DEVICE_TABLE(platform, max77843_muic_id); +static const struct of_device_id of_max77843_muic_dt_match[] = { + { .compatible = "maxim,max77843-muic", }, + { /* sentinel */ }, +}; +MODULE_DEVICE_TABLE(of, of_max77843_muic_dt_match); + static struct platform_driver max77843_muic_driver = { .driver = { .name = "max77843-muic", + .of_match_table = of_max77843_muic_dt_match, }, .probe = max77843_muic_probe, .remove = max77843_muic_remove, From dd014803f260b337daaabcde259daf70d5b26b5e Mon Sep 17 00:00:00 2001 From: Konrad Dybcio Date: Fri, 25 Aug 2023 17:38:23 +0200 Subject: [PATCH 201/326] interconnect: qcom: icc-rpm: Add AB/IB calculations coefficients Presumably due to the hardware being so complex, some nodes (or busses) have different (usually higher) requirements for bandwidth than what the usual calculations would suggest. Looking at the available downstream files, it seems like AB values are adjusted per-bus and IB values are adjusted per-node. With that in mind, introduce percentage-based coefficient struct members and use them in the calculations. One thing to note is that the IB coefficient is inverse (100/ib_percent) which feels a bit backwards, but it's necessary for precision.. Signed-off-by: Konrad Dybcio Link: https://lore.kernel.org/r/20230726-topic-icc_coeff-v4-1-c04b60caa467@linaro.org Signed-off-by: Georgi Djakov --- drivers/interconnect/qcom/icc-rpm.c | 18 +++++++++++++++--- drivers/interconnect/qcom/icc-rpm.h | 6 ++++++ 2 files changed, 21 insertions(+), 3 deletions(-) diff --git a/drivers/interconnect/qcom/icc-rpm.c b/drivers/interconnect/qcom/icc-rpm.c index 2c16917ba1fd..8b02aa8aa96a 100644 --- a/drivers/interconnect/qcom/icc-rpm.c +++ b/drivers/interconnect/qcom/icc-rpm.c @@ -298,7 +298,8 @@ static int qcom_icc_bw_aggregate(struct icc_node *node, u32 tag, u32 avg_bw, */ static void qcom_icc_bus_aggregate(struct icc_provider *provider, u64 *agg_clk_rate) { - u64 agg_avg_rate, agg_rate; + struct qcom_icc_provider *qp = to_qcom_provider(provider); + u64 agg_avg_rate, agg_peak_rate, agg_rate; struct qcom_icc_node *qn; struct icc_node *node; int i; @@ -315,8 +316,19 @@ static void qcom_icc_bus_aggregate(struct icc_provider *provider, u64 *agg_clk_r else agg_avg_rate = qn->sum_avg[i]; - agg_rate = max_t(u64, agg_avg_rate, qn->max_peak[i]); - do_div(agg_rate, qn->buswidth); + if (qp->ab_coeff) { + agg_avg_rate = agg_avg_rate * qp->ab_coeff; + agg_avg_rate = div_u64(agg_avg_rate, 100); + } + + if (qp->ib_coeff) { + agg_peak_rate = qn->max_peak[i] * 100; + agg_peak_rate = div_u64(qn->max_peak[i], qp->ib_coeff); + } else { + agg_peak_rate = qn->max_peak[i]; + } + + agg_rate = max_t(u64, agg_avg_rate, agg_peak_rate); agg_clk_rate[i] = max_t(u64, agg_clk_rate[i], agg_rate); } diff --git a/drivers/interconnect/qcom/icc-rpm.h b/drivers/interconnect/qcom/icc-rpm.h index eed3451af3e6..5e7d6a4fd2f3 100644 --- a/drivers/interconnect/qcom/icc-rpm.h +++ b/drivers/interconnect/qcom/icc-rpm.h @@ -44,6 +44,8 @@ struct rpm_clk_resource { * @type: the ICC provider type * @regmap: regmap for QoS registers read/write access * @qos_offset: offset to QoS registers + * @ab_coeff: a percentage-based coefficient for compensating the AB calculations + * @ib_coeff: an inverse-percentage-based coefficient for compensating the IB calculations * @bus_clk_rate: bus clock rate in Hz * @bus_clk_desc: a pointer to a rpm_clk_resource description of bus clocks * @bus_clk: a pointer to a HLOS-owned bus clock @@ -57,6 +59,8 @@ struct qcom_icc_provider { enum qcom_icc_type type; struct regmap *regmap; unsigned int qos_offset; + u16 ab_coeff; + u16 ib_coeff; u32 bus_clk_rate[QCOM_SMD_RPM_STATE_NUM]; const struct rpm_clk_resource *bus_clk_desc; struct clk *bus_clk; @@ -123,6 +127,8 @@ struct qcom_icc_desc { enum qcom_icc_type type; const struct regmap_config *regmap_cfg; unsigned int qos_offset; + u16 ab_coeff; + u16 ib_coeff; }; /* Valid for all bus types */ From db8fc1002c53bc17a3ca6fad2c524de42b77c146 Mon Sep 17 00:00:00 2001 From: Konrad Dybcio Date: Fri, 25 Aug 2023 17:38:24 +0200 Subject: [PATCH 202/326] interconnect: qcom: icc-rpm: Separate out clock rate calulcations In preparation for also setting per-node clock rates, separate out the logic that computes it. Signed-off-by: Konrad Dybcio Link: https://lore.kernel.org/r/20230726-topic-icc_coeff-v4-2-c04b60caa467@linaro.org Signed-off-by: Georgi Djakov --- drivers/interconnect/qcom/icc-rpm.c | 53 ++++++++++++++++------------- 1 file changed, 30 insertions(+), 23 deletions(-) diff --git a/drivers/interconnect/qcom/icc-rpm.c b/drivers/interconnect/qcom/icc-rpm.c index 8b02aa8aa96a..8c1bfd65d774 100644 --- a/drivers/interconnect/qcom/icc-rpm.c +++ b/drivers/interconnect/qcom/icc-rpm.c @@ -291,6 +291,32 @@ static int qcom_icc_bw_aggregate(struct icc_node *node, u32 tag, u32 avg_bw, return 0; } +static u64 qcom_icc_calc_rate(struct qcom_icc_provider *qp, struct qcom_icc_node *qn, int ctx) +{ + u64 agg_avg_rate, agg_peak_rate, agg_rate; + + if (qn->channels) + agg_avg_rate = div_u64(qn->sum_avg[ctx], qn->channels); + else + agg_avg_rate = qn->sum_avg[ctx]; + + if (qp->ab_coeff) { + agg_avg_rate = agg_avg_rate * qp->ab_coeff; + agg_avg_rate = div_u64(agg_avg_rate, 100); + } + + if (qp->ib_coeff) { + agg_peak_rate = qn->max_peak[ctx] * 100; + agg_peak_rate = div_u64(qn->max_peak[ctx], qp->ib_coeff); + } else { + agg_peak_rate = qn->max_peak[ctx]; + } + + agg_rate = max_t(u64, agg_avg_rate, agg_peak_rate); + + return div_u64(agg_rate, qn->buswidth); +} + /** * qcom_icc_bus_aggregate - calculate bus clock rates by traversing all nodes * @provider: generic interconnect provider @@ -299,10 +325,9 @@ static int qcom_icc_bw_aggregate(struct icc_node *node, u32 tag, u32 avg_bw, static void qcom_icc_bus_aggregate(struct icc_provider *provider, u64 *agg_clk_rate) { struct qcom_icc_provider *qp = to_qcom_provider(provider); - u64 agg_avg_rate, agg_peak_rate, agg_rate; struct qcom_icc_node *qn; struct icc_node *node; - int i; + int ctx; /* * Iterate nodes on the provider, aggregate bandwidth requests for @@ -310,27 +335,9 @@ static void qcom_icc_bus_aggregate(struct icc_provider *provider, u64 *agg_clk_r */ list_for_each_entry(node, &provider->nodes, node_list) { qn = node->data; - for (i = 0; i < QCOM_SMD_RPM_STATE_NUM; i++) { - if (qn->channels) - agg_avg_rate = div_u64(qn->sum_avg[i], qn->channels); - else - agg_avg_rate = qn->sum_avg[i]; - - if (qp->ab_coeff) { - agg_avg_rate = agg_avg_rate * qp->ab_coeff; - agg_avg_rate = div_u64(agg_avg_rate, 100); - } - - if (qp->ib_coeff) { - agg_peak_rate = qn->max_peak[i] * 100; - agg_peak_rate = div_u64(qn->max_peak[i], qp->ib_coeff); - } else { - agg_peak_rate = qn->max_peak[i]; - } - - agg_rate = max_t(u64, agg_avg_rate, agg_peak_rate); - - agg_clk_rate[i] = max_t(u64, agg_clk_rate[i], agg_rate); + for (ctx = 0; ctx < QCOM_SMD_RPM_STATE_NUM; ctx++) { + agg_clk_rate[ctx] = max_t(u64, agg_clk_rate[ctx], + qcom_icc_calc_rate(qp, qn, ctx)); } } } From 919791d82d3b878094e9edc39b0d9a4eafcc0860 Mon Sep 17 00:00:00 2001 From: Konrad Dybcio Date: Fri, 25 Aug 2023 17:38:25 +0200 Subject: [PATCH 203/326] interconnect: qcom: icc-rpm: Let nodes drive their own bus clock If this hardware couldn't get messier, some nodes are supposed to drive their own bus clock.. Presumably to connect to some intermediate interface between the node itself and the bus it's (supposed to be) connected to. Expand the node struct with the necessary data and hook up the allocations & calculations. Note that the node-specific AB/IB coefficients contribute (by design) to both the node-level and the bus-level aggregation. Signed-off-by: Konrad Dybcio Link: https://lore.kernel.org/r/20230726-topic-icc_coeff-v4-3-c04b60caa467@linaro.org Signed-off-by: Georgi Djakov --- drivers/interconnect/qcom/icc-rpm.c | 27 +++++++++++++++++++++++++++ drivers/interconnect/qcom/icc-rpm.h | 4 ++++ 2 files changed, 31 insertions(+) diff --git a/drivers/interconnect/qcom/icc-rpm.c b/drivers/interconnect/qcom/icc-rpm.c index 8c1bfd65d774..1d3af4e9ead8 100644 --- a/drivers/interconnect/qcom/icc-rpm.c +++ b/drivers/interconnect/qcom/icc-rpm.c @@ -414,6 +414,33 @@ static int qcom_icc_set(struct icc_node *src, struct icc_node *dst) qp->bus_clk_rate[QCOM_SMD_RPM_SLEEP_STATE] = sleep_rate; } + /* Handle the node-specific clock */ + if (!src_qn->bus_clk_desc) + return 0; + + active_rate = qcom_icc_calc_rate(qp, src_qn, QCOM_SMD_RPM_ACTIVE_STATE); + sleep_rate = qcom_icc_calc_rate(qp, src_qn, QCOM_SMD_RPM_SLEEP_STATE); + + if (active_rate != src_qn->bus_clk_rate[QCOM_SMD_RPM_ACTIVE_STATE]) { + ret = qcom_icc_rpm_set_bus_rate(src_qn->bus_clk_desc, QCOM_SMD_RPM_ACTIVE_STATE, + active_rate); + if (ret) + return ret; + + /* Cache the rate after we've successfully committed it to RPM */ + src_qn->bus_clk_rate[QCOM_SMD_RPM_ACTIVE_STATE] = active_rate; + } + + if (sleep_rate != src_qn->bus_clk_rate[QCOM_SMD_RPM_SLEEP_STATE]) { + ret = qcom_icc_rpm_set_bus_rate(src_qn->bus_clk_desc, QCOM_SMD_RPM_SLEEP_STATE, + sleep_rate); + if (ret) + return ret; + + /* Cache the rate after we've successfully committed it to RPM */ + src_qn->bus_clk_rate[QCOM_SMD_RPM_SLEEP_STATE] = sleep_rate; + } + return 0; } diff --git a/drivers/interconnect/qcom/icc-rpm.h b/drivers/interconnect/qcom/icc-rpm.h index 5e7d6a4fd2f3..725e0d4840e4 100644 --- a/drivers/interconnect/qcom/icc-rpm.h +++ b/drivers/interconnect/qcom/icc-rpm.h @@ -97,11 +97,13 @@ struct qcom_icc_qos { * @num_links: the total number of @links * @channels: number of channels at this node (e.g. DDR channels) * @buswidth: width of the interconnect between a node and the bus (bytes) + * @bus_clk_desc: a pointer to a rpm_clk_resource description of bus clocks * @sum_avg: current sum aggregate value of all avg bw requests * @max_peak: current max aggregate value of all peak bw requests * @mas_rpm_id: RPM id for devices that are bus masters * @slv_rpm_id: RPM id for devices that are bus slaves * @qos: NoC QoS setting parameters + * @bus_clk_rate: a pointer to an array containing bus clock rates in Hz */ struct qcom_icc_node { unsigned char *name; @@ -110,11 +112,13 @@ struct qcom_icc_node { u16 num_links; u16 channels; u16 buswidth; + const struct rpm_clk_resource *bus_clk_desc; u64 sum_avg[QCOM_SMD_RPM_STATE_NUM]; u64 max_peak[QCOM_SMD_RPM_STATE_NUM]; int mas_rpm_id; int slv_rpm_id; struct qcom_icc_qos qos; + u32 bus_clk_rate[QCOM_SMD_RPM_STATE_NUM]; }; struct qcom_icc_desc { From ba3f826639782587b70a684dae79d39f6d3c433e Mon Sep 17 00:00:00 2001 From: Konrad Dybcio Date: Fri, 25 Aug 2023 17:38:26 +0200 Subject: [PATCH 204/326] interconnect: qcom: icc-rpm: Check for node-specific rate coefficients Some nodes may have different coefficients than the general values for bus they're attached to. Check for that and use them if present. See [1], [2] for reference. [1] https://github.com/sonyxperiadev/kernel/commit/7456d9779af9ad6bb9c7ee6f33d5c5a8d3648e24 [2] https://github.com/artem/android_kernel_sony_msm8996/commit/bf7a8985dcaf0eab5bc2562d2d6775e7e29c0f30 Signed-off-by: Konrad Dybcio Link: https://lore.kernel.org/r/20230726-topic-icc_coeff-v4-4-c04b60caa467@linaro.org Signed-off-by: Georgi Djakov --- drivers/interconnect/qcom/icc-rpm.c | 14 ++++++++++---- drivers/interconnect/qcom/icc-rpm.h | 4 ++++ 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/drivers/interconnect/qcom/icc-rpm.c b/drivers/interconnect/qcom/icc-rpm.c index 1d3af4e9ead8..9c40314e03b5 100644 --- a/drivers/interconnect/qcom/icc-rpm.c +++ b/drivers/interconnect/qcom/icc-rpm.c @@ -300,14 +300,14 @@ static u64 qcom_icc_calc_rate(struct qcom_icc_provider *qp, struct qcom_icc_node else agg_avg_rate = qn->sum_avg[ctx]; - if (qp->ab_coeff) { - agg_avg_rate = agg_avg_rate * qp->ab_coeff; + if (qn->ab_coeff) { + agg_avg_rate = agg_avg_rate * qn->ab_coeff; agg_avg_rate = div_u64(agg_avg_rate, 100); } - if (qp->ib_coeff) { + if (qn->ib_coeff) { agg_peak_rate = qn->max_peak[ctx] * 100; - agg_peak_rate = div_u64(qn->max_peak[ctx], qp->ib_coeff); + agg_peak_rate = div_u64(qn->max_peak[ctx], qn->ib_coeff); } else { agg_peak_rate = qn->max_peak[ctx]; } @@ -563,6 +563,12 @@ regmap_done: for (i = 0; i < num_nodes; i++) { size_t j; + if (!qnodes[i]->ab_coeff) + qnodes[i]->ab_coeff = qp->ab_coeff; + + if (!qnodes[i]->ib_coeff) + qnodes[i]->ib_coeff = qp->ib_coeff; + node = icc_node_create(qnodes[i]->id); if (IS_ERR(node)) { ret = PTR_ERR(node); diff --git a/drivers/interconnect/qcom/icc-rpm.h b/drivers/interconnect/qcom/icc-rpm.h index 725e0d4840e4..4abf99ce2690 100644 --- a/drivers/interconnect/qcom/icc-rpm.h +++ b/drivers/interconnect/qcom/icc-rpm.h @@ -103,6 +103,8 @@ struct qcom_icc_qos { * @mas_rpm_id: RPM id for devices that are bus masters * @slv_rpm_id: RPM id for devices that are bus slaves * @qos: NoC QoS setting parameters + * @ab_coeff: a percentage-based coefficient for compensating the AB calculations + * @ib_coeff: an inverse-percentage-based coefficient for compensating the IB calculations * @bus_clk_rate: a pointer to an array containing bus clock rates in Hz */ struct qcom_icc_node { @@ -118,6 +120,8 @@ struct qcom_icc_node { int mas_rpm_id; int slv_rpm_id; struct qcom_icc_qos qos; + u16 ab_coeff; + u16 ib_coeff; u32 bus_clk_rate[QCOM_SMD_RPM_STATE_NUM]; }; From fa35757ae0a5a88bd1b7df8578ee9dac9d147c64 Mon Sep 17 00:00:00 2001 From: Konrad Dybcio Date: Fri, 25 Aug 2023 17:38:27 +0200 Subject: [PATCH 205/326] interconnect: qcom: qcm2290: Hook up MAS_APPS_PROC's bus clock This single node has its own clock which seems to be responsible for transactions between CPUSS (CPU + some stuff) and the GNOC. See [1] for reference. Define it and hook it up. [1] https://android.googlesource.com/kernel/msm-extra/devicetree/+/02f8c342b23c20a5cf967df649814be37a08227c%5E%21/#F0 Signed-off-by: Konrad Dybcio Link: https://lore.kernel.org/r/20230726-topic-icc_coeff-v4-5-c04b60caa467@linaro.org Signed-off-by: Georgi Djakov --- drivers/interconnect/qcom/icc-rpm-clocks.c | 6 ++++++ drivers/interconnect/qcom/icc-rpm.h | 1 + drivers/interconnect/qcom/qcm2290.c | 3 +++ 3 files changed, 10 insertions(+) diff --git a/drivers/interconnect/qcom/icc-rpm-clocks.c b/drivers/interconnect/qcom/icc-rpm-clocks.c index 63c82a91bbc7..ac1677de7dfd 100644 --- a/drivers/interconnect/qcom/icc-rpm-clocks.c +++ b/drivers/interconnect/qcom/icc-rpm-clocks.c @@ -25,6 +25,12 @@ const struct rpm_clk_resource bimc_clk = { }; EXPORT_SYMBOL_GPL(bimc_clk); +const struct rpm_clk_resource mem_1_clk = { + .resource_type = QCOM_SMD_RPM_MEM_CLK, + .clock_id = 1, +}; +EXPORT_SYMBOL_GPL(mem_1_clk); + const struct rpm_clk_resource bus_0_clk = { .resource_type = QCOM_SMD_RPM_BUS_CLK, .clock_id = 0, diff --git a/drivers/interconnect/qcom/icc-rpm.h b/drivers/interconnect/qcom/icc-rpm.h index 4abf99ce2690..a13768cfd231 100644 --- a/drivers/interconnect/qcom/icc-rpm.h +++ b/drivers/interconnect/qcom/icc-rpm.h @@ -152,6 +152,7 @@ extern const struct rpm_clk_resource bimc_clk; extern const struct rpm_clk_resource bus_0_clk; extern const struct rpm_clk_resource bus_1_clk; extern const struct rpm_clk_resource bus_2_clk; +extern const struct rpm_clk_resource mem_1_clk; extern const struct rpm_clk_resource mmaxi_0_clk; extern const struct rpm_clk_resource mmaxi_1_clk; extern const struct rpm_clk_resource qup_clk; diff --git a/drivers/interconnect/qcom/qcm2290.c b/drivers/interconnect/qcom/qcm2290.c index 5bc4b7516608..026e4c82d6d4 100644 --- a/drivers/interconnect/qcom/qcm2290.c +++ b/drivers/interconnect/qcom/qcm2290.c @@ -112,6 +112,9 @@ static struct qcom_icc_node mas_appss_proc = { .qos.qos_mode = NOC_QOS_MODE_FIXED, .qos.prio_level = 0, .qos.areq_prio = 0, + .bus_clk_desc = &mem_1_clk, + .ab_coeff = 159, + .ib_coeff = 96, .mas_rpm_id = 0, .slv_rpm_id = -1, .num_links = ARRAY_SIZE(mas_appss_proc_links), From 8657ed471196f4dc8e7917453a39363e0014840c Mon Sep 17 00:00:00 2001 From: Konrad Dybcio Date: Fri, 25 Aug 2023 17:38:28 +0200 Subject: [PATCH 206/326] interconnect: qcom: qcm2290: Set AB coefficients Some buses need additional manual adjustments atop the usual calculations. Fill in the missing coefficients. Signed-off-by: Konrad Dybcio Link: https://lore.kernel.org/r/20230726-topic-icc_coeff-v4-6-c04b60caa467@linaro.org Signed-off-by: Georgi Djakov --- drivers/interconnect/qcom/qcm2290.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/interconnect/qcom/qcm2290.c b/drivers/interconnect/qcom/qcm2290.c index 026e4c82d6d4..7abc0c449220 100644 --- a/drivers/interconnect/qcom/qcm2290.c +++ b/drivers/interconnect/qcom/qcm2290.c @@ -1202,6 +1202,7 @@ static const struct qcom_icc_desc qcm2290_bimc = { .keep_alive = true, /* M_REG_BASE() in vendor msm_bus_bimc_adhoc driver */ .qos_offset = 0x8000, + .ab_coeff = 153, }; static struct qcom_icc_node * const qcm2290_cnoc_nodes[] = { @@ -1332,6 +1333,7 @@ static const struct qcom_icc_desc qcm2290_mmnrt_virt = { .regmap_cfg = &qcm2290_snoc_regmap_config, .keep_alive = true, .qos_offset = 0x15000, + .ab_coeff = 142, }; static struct qcom_icc_node * const qcm2290_mmrt_virt_nodes[] = { @@ -1348,6 +1350,7 @@ static const struct qcom_icc_desc qcm2290_mmrt_virt = { .regmap_cfg = &qcm2290_snoc_regmap_config, .keep_alive = true, .qos_offset = 0x15000, + .ab_coeff = 139, }; static const struct of_device_id qcm2290_noc_of_match[] = { From 550064a85ba564cfb508a995f45e39a6ad0e26ed Mon Sep 17 00:00:00 2001 From: Konrad Dybcio Date: Fri, 25 Aug 2023 17:38:29 +0200 Subject: [PATCH 207/326] interconnect: qcom: qcm2290: Update EBI channel configuration QCM2290 can support two memory configurations: single-channel, 32-bit wide LPDDR3 @ up to 933MHz (bus clock) or dual-channel, 16-bit wide LPDDR4X @ up to 1804 MHz. The interconnect driver in its current form seems to gravitate towards the first one, however there are no LPDDR3- equipped boards upstream and we still don't have a great way to discern the DDR generations on the kernel side. To make DDR scaling possible on the only currently-supported 2290 board, stick with the LPDDR4X config by default. The side effect on any potential LPDDR3 board would be that the requested bus clock rate is too high (but still capped to the firmware-configured FMAX). Signed-off-by: Konrad Dybcio Link: https://lore.kernel.org/r/20230726-topic-icc_coeff-v4-7-c04b60caa467@linaro.org Signed-off-by: Georgi Djakov --- drivers/interconnect/qcom/qcm2290.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/interconnect/qcom/qcm2290.c b/drivers/interconnect/qcom/qcm2290.c index 7abc0c449220..b88cf9a022e0 100644 --- a/drivers/interconnect/qcom/qcm2290.c +++ b/drivers/interconnect/qcom/qcm2290.c @@ -678,7 +678,8 @@ static struct qcom_icc_node mas_gfx3d = { static struct qcom_icc_node slv_ebi1 = { .name = "slv_ebi1", .id = QCM2290_SLAVE_EBI1, - .buswidth = 8, + .buswidth = 4, + .channels = 2, .mas_rpm_id = -1, .slv_rpm_id = 0, }; From a4a9251760185af9ca7ff1592a05a0eabfe0cd00 Mon Sep 17 00:00:00 2001 From: Konrad Dybcio Date: Fri, 25 Aug 2023 17:38:30 +0200 Subject: [PATCH 208/326] interconnect: qcom: sdm660: Set AB/IB coefficients Some buses and nodes need additional manual adjustments atop the usual calculations. Fill in the missing coefficients. Signed-off-by: Konrad Dybcio Link: https://lore.kernel.org/r/20230726-topic-icc_coeff-v4-8-c04b60caa467@linaro.org Signed-off-by: Georgi Djakov --- drivers/interconnect/qcom/sdm660.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/interconnect/qcom/sdm660.c b/drivers/interconnect/qcom/sdm660.c index 36962f7bd7bb..7392bebba334 100644 --- a/drivers/interconnect/qcom/sdm660.c +++ b/drivers/interconnect/qcom/sdm660.c @@ -602,6 +602,7 @@ static struct qcom_icc_node mas_mdp_p0 = { .name = "mas_mdp_p0", .id = SDM660_MASTER_MDP_P0, .buswidth = 16, + .ib_coeff = 50, .mas_rpm_id = 8, .slv_rpm_id = -1, .qos.ap_owned = true, @@ -621,6 +622,7 @@ static struct qcom_icc_node mas_mdp_p1 = { .name = "mas_mdp_p1", .id = SDM660_MASTER_MDP_P1, .buswidth = 16, + .ib_coeff = 50, .mas_rpm_id = 61, .slv_rpm_id = -1, .qos.ap_owned = true, @@ -1540,6 +1542,7 @@ static const struct qcom_icc_desc sdm660_bimc = { .num_nodes = ARRAY_SIZE(sdm660_bimc_nodes), .bus_clk_desc = &bimc_clk, .regmap_cfg = &sdm660_bimc_regmap_config, + .ab_coeff = 153, }; static struct qcom_icc_node * const sdm660_cnoc_nodes[] = { @@ -1659,6 +1662,7 @@ static const struct qcom_icc_desc sdm660_mnoc = { .intf_clocks = mm_intf_clocks, .num_intf_clocks = ARRAY_SIZE(mm_intf_clocks), .regmap_cfg = &sdm660_mnoc_regmap_config, + .ab_coeff = 153, }; static struct qcom_icc_node * const sdm660_snoc_nodes[] = { From 1255f23c219a74f2577c9ca5521abeb36db35d3b Mon Sep 17 00:00:00 2001 From: Konrad Dybcio Date: Fri, 25 Aug 2023 17:38:31 +0200 Subject: [PATCH 209/326] interconnect: qcom: msm8996: Set AB/IB coefficients Some buses and nodes need additional manual adjustments atop the usual calculations. Fill in the missing coefficients. Signed-off-by: Konrad Dybcio Link: https://lore.kernel.org/r/20230726-topic-icc_coeff-v4-9-c04b60caa467@linaro.org Signed-off-by: Georgi Djakov --- drivers/interconnect/qcom/msm8996.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/interconnect/qcom/msm8996.c b/drivers/interconnect/qcom/msm8996.c index 88683dfa468f..b73566c9b21f 100644 --- a/drivers/interconnect/qcom/msm8996.c +++ b/drivers/interconnect/qcom/msm8996.c @@ -448,6 +448,7 @@ static struct qcom_icc_node mas_mdp_p0 = { .name = "mas_mdp_p0", .id = MSM8996_MASTER_MDP_PORT0, .buswidth = 32, + .ib_coeff = 25, .mas_rpm_id = 8, .slv_rpm_id = -1, .qos.ap_owned = true, @@ -463,6 +464,7 @@ static struct qcom_icc_node mas_mdp_p1 = { .name = "mas_mdp_p1", .id = MSM8996_MASTER_MDP_PORT1, .buswidth = 32, + .ib_coeff = 25, .mas_rpm_id = 61, .slv_rpm_id = -1, .qos.ap_owned = true, @@ -1889,7 +1891,8 @@ static const struct qcom_icc_desc msm8996_bimc = { .nodes = bimc_nodes, .num_nodes = ARRAY_SIZE(bimc_nodes), .bus_clk_desc = &bimc_clk, - .regmap_cfg = &msm8996_bimc_regmap_config + .regmap_cfg = &msm8996_bimc_regmap_config, + .ab_coeff = 154, }; static struct qcom_icc_node * const cnoc_nodes[] = { @@ -2004,7 +2007,8 @@ static const struct qcom_icc_desc msm8996_mnoc = { .bus_clk_desc = &mmaxi_0_clk, .intf_clocks = mm_intf_clocks, .num_intf_clocks = ARRAY_SIZE(mm_intf_clocks), - .regmap_cfg = &msm8996_mnoc_regmap_config + .regmap_cfg = &msm8996_mnoc_regmap_config, + .ab_coeff = 154, }; static struct qcom_icc_node * const pnoc_nodes[] = { From 400e531bcdf1dc702c9d560f57cea3b9547030fc Mon Sep 17 00:00:00 2001 From: Konrad Dybcio Date: Mon, 24 Jul 2023 16:06:27 +0200 Subject: [PATCH 210/326] dt-bindings: interconnect: qcom: Introduce qcom,rpm-common The current RPM interconnect bindings are messy. Start cleaning them up with a common include. Signed-off-by: Konrad Dybcio Link: https://lore.kernel.org/r/20230721-topic-icc_bindings-v2-1-e33d5acbf3bd@linaro.org Signed-off-by: Georgi Djakov --- .../bindings/interconnect/qcom,qcm2290.yaml | 18 ++++++------ .../interconnect/qcom,rpm-common.yaml | 28 +++++++++++++++++++ 2 files changed, 36 insertions(+), 10 deletions(-) create mode 100644 Documentation/devicetree/bindings/interconnect/qcom,rpm-common.yaml diff --git a/Documentation/devicetree/bindings/interconnect/qcom,qcm2290.yaml b/Documentation/devicetree/bindings/interconnect/qcom,qcm2290.yaml index f65a2fe846de..df89f390a9b0 100644 --- a/Documentation/devicetree/bindings/interconnect/qcom,qcm2290.yaml +++ b/Documentation/devicetree/bindings/interconnect/qcom,qcm2290.yaml @@ -13,6 +13,9 @@ description: | The Qualcomm QCM2290 interconnect providers support adjusting the bandwidth requirements between the various NoC fabrics. +allOf: + - $ref: qcom,rpm-common.yaml# + properties: reg: maxItems: 1 @@ -23,9 +26,6 @@ properties: - qcom,qcm2290-cnoc - qcom,qcm2290-snoc - '#interconnect-cells': - const: 1 - clock-names: items: - const: bus @@ -44,6 +44,9 @@ patternProperties: The interconnect providers do not have a separate QoS register space, but share parent's space. + allOf: + - $ref: qcom,rpm-common.yaml# + properties: compatible: enum: @@ -51,9 +54,6 @@ patternProperties: - qcom,qcm2290-mmrt-virt - qcom,qcm2290-mmnrt-virt - '#interconnect-cells': - const: 1 - clock-names: items: - const: bus @@ -66,20 +66,18 @@ patternProperties: required: - compatible - - '#interconnect-cells' - clock-names - clocks - additionalProperties: false + unevaluatedProperties: false required: - compatible - reg - - '#interconnect-cells' - clock-names - clocks -additionalProperties: false +unevaluatedProperties: false examples: - | diff --git a/Documentation/devicetree/bindings/interconnect/qcom,rpm-common.yaml b/Documentation/devicetree/bindings/interconnect/qcom,rpm-common.yaml new file mode 100644 index 000000000000..1ea52b091609 --- /dev/null +++ b/Documentation/devicetree/bindings/interconnect/qcom,rpm-common.yaml @@ -0,0 +1,28 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/interconnect/qcom,rpm-common.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Qualcomm RPMh Network-On-Chip Interconnect + +maintainers: + - Konrad Dybcio + +description: + RPM interconnect providers support for managing system bandwidth requirements + through manual requests based on either predefined values or as indicated by + the bus monitor hardware. Each provider node represents a NoC bus master, + driven by a dedicated clock source. + +properties: + '#interconnect-cells': + oneOf: + - const: 2 + - const: 1 + deprecated: true + +required: + - '#interconnect-cells' + +additionalProperties: true From 5d4268b31ef060a18ce0e7af7e8f7ccf815456ff Mon Sep 17 00:00:00 2001 From: Konrad Dybcio Date: Mon, 24 Jul 2023 16:06:28 +0200 Subject: [PATCH 211/326] dt-bindings: interconnect: qcom: qcm2290: Remove RPM bus clocks After the recent reshuffling, bus clocks are no longer exposed as RPM clocks. Remove the old description. Reviewed-by: Krzysztof Kozlowski Signed-off-by: Konrad Dybcio Link: https://lore.kernel.org/r/20230721-topic-icc_bindings-v2-2-e33d5acbf3bd@linaro.org Signed-off-by: Georgi Djakov --- .../bindings/interconnect/qcom,qcm2290.yaml | 42 ------------------- 1 file changed, 42 deletions(-) diff --git a/Documentation/devicetree/bindings/interconnect/qcom,qcm2290.yaml b/Documentation/devicetree/bindings/interconnect/qcom,qcm2290.yaml index df89f390a9b0..b6c15314c5c5 100644 --- a/Documentation/devicetree/bindings/interconnect/qcom,qcm2290.yaml +++ b/Documentation/devicetree/bindings/interconnect/qcom,qcm2290.yaml @@ -26,16 +26,6 @@ properties: - qcom,qcm2290-cnoc - qcom,qcm2290-snoc - clock-names: - items: - - const: bus - - const: bus_a - - clocks: - items: - - description: Bus Clock - - description: Bus A Clock - # Child node's properties patternProperties: '^interconnect-[a-z0-9]+$': @@ -54,28 +44,14 @@ patternProperties: - qcom,qcm2290-mmrt-virt - qcom,qcm2290-mmnrt-virt - clock-names: - items: - - const: bus - - const: bus_a - - clocks: - items: - - description: Bus Clock - - description: Bus A Clock - required: - compatible - - clock-names - - clocks unevaluatedProperties: false required: - compatible - reg - - clock-names - - clocks unevaluatedProperties: false @@ -87,32 +63,20 @@ examples: compatible = "qcom,qcm2290-snoc"; reg = <0x01880000 0x60200>; #interconnect-cells = <1>; - clock-names = "bus", "bus_a"; - clocks = <&rpmcc RPM_SMD_SNOC_CLK>, - <&rpmcc RPM_SMD_SNOC_A_CLK>; qup_virt: interconnect-qup { compatible = "qcom,qcm2290-qup-virt"; #interconnect-cells = <1>; - clock-names = "bus", "bus_a"; - clocks = <&rpmcc RPM_SMD_QUP_CLK>, - <&rpmcc RPM_SMD_QUP_A_CLK>; }; mmnrt_virt: interconnect-mmnrt { compatible = "qcom,qcm2290-mmnrt-virt"; #interconnect-cells = <1>; - clock-names = "bus", "bus_a"; - clocks = <&rpmcc RPM_SMD_MMNRT_CLK>, - <&rpmcc RPM_SMD_MMNRT_A_CLK>; }; mmrt_virt: interconnect-mmrt { compatible = "qcom,qcm2290-mmrt-virt"; #interconnect-cells = <1>; - clock-names = "bus", "bus_a"; - clocks = <&rpmcc RPM_SMD_MMRT_CLK>, - <&rpmcc RPM_SMD_MMRT_A_CLK>; }; }; @@ -120,16 +84,10 @@ examples: compatible = "qcom,qcm2290-cnoc"; reg = <0x01900000 0x8200>; #interconnect-cells = <1>; - clock-names = "bus", "bus_a"; - clocks = <&rpmcc RPM_SMD_CNOC_CLK>, - <&rpmcc RPM_SMD_CNOC_A_CLK>; }; bimc: interconnect@4480000 { compatible = "qcom,qcm2290-bimc"; reg = <0x04480000 0x80000>; #interconnect-cells = <1>; - clock-names = "bus", "bus_a"; - clocks = <&rpmcc RPM_SMD_BIMC_CLK>, - <&rpmcc RPM_SMD_BIMC_A_CLK>; }; From c19bcc762796a128beafffa77558f9c1fdc50398 Mon Sep 17 00:00:00 2001 From: Konrad Dybcio Date: Mon, 24 Jul 2023 16:06:29 +0200 Subject: [PATCH 212/326] dt-bindings: interconnect: qcom: Fix and separate out SDM660 Separate out SDM660 icc bindings from the common file and fix the clocks description by removing the wrong internal RPM bus clock representation that we've been carrying for years. Signed-off-by: Konrad Dybcio Link: https://lore.kernel.org/r/20230721-topic-icc_bindings-v2-3-e33d5acbf3bd@linaro.org Signed-off-by: Georgi Djakov --- .../bindings/interconnect/qcom,rpm.yaml | 40 ------- .../bindings/interconnect/qcom,sdm660.yaml | 108 ++++++++++++++++++ 2 files changed, 108 insertions(+), 40 deletions(-) create mode 100644 Documentation/devicetree/bindings/interconnect/qcom,sdm660.yaml diff --git a/Documentation/devicetree/bindings/interconnect/qcom,rpm.yaml b/Documentation/devicetree/bindings/interconnect/qcom,rpm.yaml index 4f95d512012a..59895cca6a8c 100644 --- a/Documentation/devicetree/bindings/interconnect/qcom,rpm.yaml +++ b/Documentation/devicetree/bindings/interconnect/qcom,rpm.yaml @@ -37,12 +37,6 @@ properties: - qcom,qcs404-bimc - qcom,qcs404-pcnoc - qcom,qcs404-snoc - - qcom,sdm660-a2noc - - qcom,sdm660-bimc - - qcom,sdm660-cnoc - - qcom,sdm660-gnoc - - qcom,sdm660-mnoc - - qcom,sdm660-snoc '#interconnect-cells': description: | @@ -123,10 +117,6 @@ allOf: - qcom,qcs404-bimc - qcom,qcs404-pcnoc - qcom,qcs404-snoc - - qcom,sdm660-bimc - - qcom,sdm660-cnoc - - qcom,sdm660-gnoc - - qcom,sdm660-snoc then: properties: @@ -146,7 +136,6 @@ allOf: contains: enum: - qcom,msm8996-mnoc - - qcom,sdm660-mnoc then: properties: @@ -209,35 +198,6 @@ allOf: - description: Aggregate2 NoC UFS AXI Clock - description: UFS AXI Clock - - if: - properties: - compatible: - contains: - enum: - - qcom,sdm660-a2noc - - then: - properties: - clock-names: - items: - - const: bus - - const: bus_a - - const: ipa - - const: ufs_axi - - const: aggre2_ufs_axi - - const: aggre2_usb3_axi - - const: cfg_noc_usb2_axi - - clocks: - items: - - description: Bus Clock. - - description: Bus A Clock. - - description: IPA Clock. - - description: UFS AXI Clock. - - description: Aggregate2 UFS AXI Clock. - - description: Aggregate2 USB3 AXI Clock. - - description: Config NoC USB2 AXI Clock. - - if: not: properties: diff --git a/Documentation/devicetree/bindings/interconnect/qcom,sdm660.yaml b/Documentation/devicetree/bindings/interconnect/qcom,sdm660.yaml new file mode 100644 index 000000000000..8f6bc6399626 --- /dev/null +++ b/Documentation/devicetree/bindings/interconnect/qcom,sdm660.yaml @@ -0,0 +1,108 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/interconnect/qcom,sdm660.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Qualcomm SDM660 Network-On-Chip interconnect + +maintainers: + - Konrad Dybcio + +description: | + The Qualcomm SDM660 interconnect providers support adjusting the + bandwidth requirements between the various NoC fabrics. + +properties: + compatible: + enum: + - qcom,sdm660-a2noc + - qcom,sdm660-bimc + - qcom,sdm660-cnoc + - qcom,sdm660-gnoc + - qcom,sdm660-mnoc + - qcom,sdm660-snoc + + reg: + maxItems: 1 + + clock-names: + minItems: 1 + maxItems: 5 + + clocks: + minItems: 1 + maxItems: 5 + +required: + - compatible + - reg + +unevaluatedProperties: false + +allOf: + - $ref: qcom,rpm-common.yaml# + - if: + properties: + compatible: + const: qcom,sdm660-mnoc + + then: + properties: + clocks: + items: + - description: CPU-NoC High-performance Bus Clock. + + clock-names: + const: iface + + - if: + properties: + compatible: + const: qcom,sdm660-a2noc + + then: + properties: + clocks: + items: + - description: IPA Clock. + - description: UFS AXI Clock. + - description: Aggregate2 UFS AXI Clock. + - description: Aggregate2 USB3 AXI Clock. + - description: Config NoC USB2 AXI Clock. + + clock-names: + items: + - const: ipa + - const: ufs_axi + - const: aggre2_ufs_axi + - const: aggre2_usb3_axi + - const: cfg_noc_usb2_axi + +examples: + - | + #include + #include + #include + + bimc: interconnect@1008000 { + compatible = "qcom,sdm660-bimc"; + reg = <0x01008000 0x78000>; + #interconnect-cells = <1>; + }; + + a2noc: interconnect@1704000 { + compatible = "qcom,sdm660-a2noc"; + reg = <0x01704000 0xc100>; + #interconnect-cells = <1>; + clocks = <&rpmcc RPM_SMD_IPA_CLK>, + <&gcc GCC_UFS_AXI_CLK>, + <&gcc GCC_AGGRE2_UFS_AXI_CLK>, + <&gcc GCC_AGGRE2_USB3_AXI_CLK>, + <&gcc GCC_CFG_NOC_USB2_AXI_CLK>; + clock-names = "ipa", + "ufs_axi", + "aggre2_ufs_axi", + "aggre2_usb3_axi", + "cfg_noc_usb2_axi"; + }; From d03374a61b0fce165ec51529652ec55ed0ac305c Mon Sep 17 00:00:00 2001 From: Konrad Dybcio Date: Mon, 24 Jul 2023 16:06:30 +0200 Subject: [PATCH 213/326] dt-bindings: interconnect: qcom: Fix and separate out MSM8996 Separate out MSM8996 icc bindings from the common file and fix the clocks description by removing the wrong internal RPM bus clock representation that we've been carrying for years. Signed-off-by: Konrad Dybcio Link: https://lore.kernel.org/r/20230721-topic-icc_bindings-v2-4-e33d5acbf3bd@linaro.org Signed-off-by: Georgi Djakov --- .../bindings/interconnect/qcom,msm8996.yaml | 126 ++++++++++++++++++ .../bindings/interconnect/qcom,rpm.yaml | 81 ----------- 2 files changed, 126 insertions(+), 81 deletions(-) create mode 100644 Documentation/devicetree/bindings/interconnect/qcom,msm8996.yaml diff --git a/Documentation/devicetree/bindings/interconnect/qcom,msm8996.yaml b/Documentation/devicetree/bindings/interconnect/qcom,msm8996.yaml new file mode 100644 index 000000000000..e3f964aaad1b --- /dev/null +++ b/Documentation/devicetree/bindings/interconnect/qcom,msm8996.yaml @@ -0,0 +1,126 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/interconnect/qcom,msm8996.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Qualcomm MSM8996 Network-On-Chip interconnect + +maintainers: + - Konrad Dybcio + +description: | + The Qualcomm MSM8996 interconnect providers support adjusting the + bandwidth requirements between the various NoC fabrics. + +properties: + compatible: + enum: + - qcom,msm8996-a0noc + - qcom,msm8996-a1noc + - qcom,msm8996-a2noc + - qcom,msm8996-bimc + - qcom,msm8996-cnoc + - qcom,msm8996-mnoc + - qcom,msm8996-pnoc + - qcom,msm8996-snoc + + reg: + maxItems: 1 + + clock-names: + minItems: 1 + maxItems: 3 + + clocks: + minItems: 1 + maxItems: 3 + + power-domains: + maxItems: 1 + +required: + - compatible + - reg + +unevaluatedProperties: false + +allOf: + - $ref: qcom,rpm-common.yaml# + - if: + properties: + compatible: + const: qcom,msm8996-a0noc + + then: + properties: + clocks: + items: + - description: Aggregate0 System NoC AXI Clock. + - description: Aggregate0 Config NoC AHB Clock. + - description: Aggregate0 NoC MPU Clock. + + clock-names: + items: + - const: aggre0_snoc_axi + - const: aggre0_cnoc_ahb + - const: aggre0_noc_mpu_cfg + + required: + - power-domains + + - if: + properties: + compatible: + const: qcom,msm8996-mnoc + + then: + properties: + clocks: + items: + - description: CPU-NoC High-performance Bus Clock. + + clock-names: + const: iface + + - if: + properties: + compatible: + const: qcom,msm8996-a2noc + + then: + properties: + clocks: + items: + - description: Aggregate2 NoC UFS AXI Clock + - description: UFS AXI Clock + + clock-names: + items: + - const: aggre2_ufs_axi + - const: ufs_axi + +examples: + - | + #include + #include + #include + + bimc: interconnect@408000 { + compatible = "qcom,msm8996-bimc"; + reg = <0x00408000 0x5a000>; + #interconnect-cells = <1>; + }; + + a0noc: interconnect@543000 { + compatible = "qcom,msm8996-a0noc"; + reg = <0x00543000 0x6000>; + #interconnect-cells = <1>; + clocks = <&gcc GCC_AGGRE0_SNOC_AXI_CLK>, + <&gcc GCC_AGGRE0_CNOC_AHB_CLK>, + <&gcc GCC_AGGRE0_NOC_MPU_CFG_AHB_CLK>; + clock-names = "aggre0_snoc_axi", + "aggre0_cnoc_ahb", + "aggre0_noc_mpu_cfg"; + power-domains = <&gcc AGGRE0_NOC_GDSC>; + }; diff --git a/Documentation/devicetree/bindings/interconnect/qcom,rpm.yaml b/Documentation/devicetree/bindings/interconnect/qcom,rpm.yaml index 59895cca6a8c..3e1bcbbdb532 100644 --- a/Documentation/devicetree/bindings/interconnect/qcom,rpm.yaml +++ b/Documentation/devicetree/bindings/interconnect/qcom,rpm.yaml @@ -26,14 +26,6 @@ properties: - qcom,msm8939-bimc - qcom,msm8939-pcnoc - qcom,msm8939-snoc - - qcom,msm8996-a0noc - - qcom,msm8996-a1noc - - qcom,msm8996-a2noc - - qcom,msm8996-bimc - - qcom,msm8996-cnoc - - qcom,msm8996-mnoc - - qcom,msm8996-pnoc - - qcom,msm8996-snoc - qcom,qcs404-bimc - qcom,qcs404-pcnoc - qcom,qcs404-snoc @@ -109,11 +101,6 @@ allOf: - qcom,msm8939-bimc - qcom,msm8939-pcnoc - qcom,msm8939-snoc - - qcom,msm8996-a1noc - - qcom,msm8996-bimc - - qcom,msm8996-cnoc - - qcom,msm8996-pnoc - - qcom,msm8996-snoc - qcom,qcs404-bimc - qcom,qcs404-pcnoc - qcom,qcs404-snoc @@ -130,74 +117,6 @@ allOf: - description: Bus Clock - description: Bus A Clock - - if: - properties: - compatible: - contains: - enum: - - qcom,msm8996-mnoc - - then: - properties: - clock-names: - items: - - const: bus - - const: bus_a - - const: iface - - clocks: - items: - - description: Bus Clock. - - description: Bus A Clock. - - description: CPU-NoC High-performance Bus Clock. - - - if: - properties: - compatible: - contains: - enum: - - qcom,msm8996-a0noc - - then: - properties: - clock-names: - items: - - const: aggre0_snoc_axi - - const: aggre0_cnoc_ahb - - const: aggre0_noc_mpu_cfg - - clocks: - items: - - description: Aggregate0 System NoC AXI Clock. - - description: Aggregate0 Config NoC AHB Clock. - - description: Aggregate0 NoC MPU Clock. - - required: - - power-domains - - - if: - properties: - compatible: - contains: - enum: - - qcom,msm8996-a2noc - - then: - properties: - clock-names: - items: - - const: bus - - const: bus_a - - const: aggre2_ufs_axi - - const: ufs_axi - - clocks: - items: - - description: Bus Clock - - description: Bus A Clock - - description: Aggregate2 NoC UFS AXI Clock - - description: UFS AXI Clock - - if: not: properties: From 462baaf4c6281550b0d57131f95d51e6949889ec Mon Sep 17 00:00:00 2001 From: Konrad Dybcio Date: Mon, 24 Jul 2023 16:06:31 +0200 Subject: [PATCH 214/326] dt-bindings: interconnect: qcom: Fix and separate out MSM8939 Separate out MSM8939 icc bindings from the common file and fix the clocks description by removing the wrong internal RPM bus clock representation that we've been carrying for years. This was the final one, so also retire the shared file. Signed-off-by: Konrad Dybcio Link: https://lore.kernel.org/r/20230721-topic-icc_bindings-v2-5-e33d5acbf3bd@linaro.org Signed-off-by: Georgi Djakov --- .../bindings/interconnect/qcom,msm8939.yaml | 74 +++++++++++++++++++ .../bindings/interconnect/qcom,rpm.yaml | 49 ------------ 2 files changed, 74 insertions(+), 49 deletions(-) create mode 100644 Documentation/devicetree/bindings/interconnect/qcom,msm8939.yaml diff --git a/Documentation/devicetree/bindings/interconnect/qcom,msm8939.yaml b/Documentation/devicetree/bindings/interconnect/qcom,msm8939.yaml new file mode 100644 index 000000000000..fd15ab5014fb --- /dev/null +++ b/Documentation/devicetree/bindings/interconnect/qcom,msm8939.yaml @@ -0,0 +1,74 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/interconnect/qcom,msm8939.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Qualcomm MSM8939 Network-On-Chip interconnect + +maintainers: + - Konrad Dybcio + +description: | + The Qualcomm MSM8939 interconnect providers support adjusting the + bandwidth requirements between the various NoC fabrics. + +allOf: + - $ref: qcom,rpm-common.yaml# + +properties: + compatible: + enum: + - qcom,msm8939-bimc + - qcom,msm8939-pcnoc + - qcom,msm8939-snoc + + reg: + maxItems: 1 + +patternProperties: + '^interconnect-[a-z0-9\-]+$': + type: object + $ref: qcom,rpm-common.yaml# + description: + The interconnect providers do not have a separate QoS register space, + but share parent's space. + + allOf: + - $ref: qcom,rpm-common.yaml# + + properties: + compatible: + const: qcom,msm8939-snoc-mm + + required: + - compatible + + unevaluatedProperties: false + +required: + - compatible + - reg + +unevaluatedProperties: false + +examples: + - | + #include + + snoc: interconnect@580000 { + compatible = "qcom,msm8939-snoc"; + reg = <0x00580000 0x14000>; + #interconnect-cells = <1>; + }; + + bimc: interconnect@400000 { + compatible = "qcom,msm8939-bimc"; + reg = <0x00400000 0x62000>; + #interconnect-cells = <1>; + + snoc_mm: interconnect-snoc { + compatible = "qcom,msm8939-snoc-mm"; + #interconnect-cells = <1>; + }; + }; diff --git a/Documentation/devicetree/bindings/interconnect/qcom,rpm.yaml b/Documentation/devicetree/bindings/interconnect/qcom,rpm.yaml index 3e1bcbbdb532..72856b1c4210 100644 --- a/Documentation/devicetree/bindings/interconnect/qcom,rpm.yaml +++ b/Documentation/devicetree/bindings/interconnect/qcom,rpm.yaml @@ -23,9 +23,6 @@ properties: - qcom,msm8916-bimc - qcom,msm8916-pcnoc - qcom,msm8916-snoc - - qcom,msm8939-bimc - - qcom,msm8939-pcnoc - - qcom,msm8939-snoc - qcom,qcs404-bimc - qcom,qcs404-pcnoc - qcom,qcs404-snoc @@ -48,38 +45,6 @@ properties: power-domains: maxItems: 1 -# Child node's properties -patternProperties: - '^interconnect-[a-z0-9]+$': - type: object - additionalProperties: false - description: - snoc-mm is a child of snoc, sharing snoc's register address space. - - properties: - compatible: - enum: - - qcom,msm8939-snoc-mm - - '#interconnect-cells': - const: 1 - - clock-names: - items: - - const: bus - - const: bus_a - - clocks: - items: - - description: Bus Clock - - description: Bus A Clock - - required: - - compatible - - '#interconnect-cells' - - clock-names - - clocks - required: - compatible - reg @@ -98,9 +63,6 @@ allOf: - qcom,msm8916-bimc - qcom,msm8916-pcnoc - qcom,msm8916-snoc - - qcom,msm8939-bimc - - qcom,msm8939-pcnoc - - qcom,msm8939-snoc - qcom,qcs404-bimc - qcom,qcs404-pcnoc - qcom,qcs404-snoc @@ -117,17 +79,6 @@ allOf: - description: Bus Clock - description: Bus A Clock - - if: - not: - properties: - compatible: - contains: - enum: - - qcom,msm8939-snoc - then: - patternProperties: - '^interconnect-[a-z0-9]+$': false - examples: - | #include From df786235af03eeb09e5dc139ad8dcbba6346e357 Mon Sep 17 00:00:00 2001 From: Konrad Dybcio Date: Mon, 24 Jul 2023 16:06:32 +0200 Subject: [PATCH 215/326] dt-bindings: interconnect: qcom: rpm: Clean up the file Following the recent cleanups and untanglements, remove abusive direct references to RPM bus clocks, include the rpm-common YAML and update Georgi's email. Signed-off-by: Konrad Dybcio Link: https://lore.kernel.org/r/20230721-topic-icc_bindings-v2-6-e33d5acbf3bd@linaro.org Signed-off-by: Georgi Djakov --- .../bindings/interconnect/qcom,rpm.yaml | 62 ++----------------- 1 file changed, 5 insertions(+), 57 deletions(-) diff --git a/Documentation/devicetree/bindings/interconnect/qcom,rpm.yaml b/Documentation/devicetree/bindings/interconnect/qcom,rpm.yaml index 72856b1c4210..157efd47904d 100644 --- a/Documentation/devicetree/bindings/interconnect/qcom,rpm.yaml +++ b/Documentation/devicetree/bindings/interconnect/qcom,rpm.yaml @@ -7,13 +7,16 @@ $schema: http://devicetree.org/meta-schemas/core.yaml# title: Qualcomm RPM Network-On-Chip Interconnect maintainers: - - Georgi Djakov + - Georgi Djakov description: | RPM interconnect providers support system bandwidth requirements through RPM processor. The provider is able to communicate with the RPM through the RPM shared memory device. +allOf: + - $ref: qcom,rpm-common.yaml# + properties: reg: maxItems: 1 @@ -27,57 +30,11 @@ properties: - qcom,qcs404-pcnoc - qcom,qcs404-snoc - '#interconnect-cells': - description: | - Value: <1> is one cell in an interconnect specifier for the - interconnect node id, <2> requires the interconnect node id and an - extra path tag. - enum: [ 1, 2 ] - - clocks: - minItems: 2 - maxItems: 7 - - clock-names: - minItems: 2 - maxItems: 7 - - power-domains: - maxItems: 1 - required: - compatible - reg - - '#interconnect-cells' - - clock-names - - clocks -additionalProperties: false - -allOf: - - if: - properties: - compatible: - contains: - enum: - - qcom,msm8916-bimc - - qcom,msm8916-pcnoc - - qcom,msm8916-snoc - - qcom,qcs404-bimc - - qcom,qcs404-pcnoc - - qcom,qcs404-snoc - - then: - properties: - clock-names: - items: - - const: bus - - const: bus_a - - clocks: - items: - - description: Bus Clock - - description: Bus A Clock +unevaluatedProperties: false examples: - | @@ -87,25 +44,16 @@ examples: compatible = "qcom,msm8916-bimc"; reg = <0x00400000 0x62000>; #interconnect-cells = <1>; - clock-names = "bus", "bus_a"; - clocks = <&rpmcc RPM_SMD_BIMC_CLK>, - <&rpmcc RPM_SMD_BIMC_A_CLK>; }; pcnoc: interconnect@500000 { compatible = "qcom,msm8916-pcnoc"; reg = <0x00500000 0x11000>; #interconnect-cells = <1>; - clock-names = "bus", "bus_a"; - clocks = <&rpmcc RPM_SMD_PCNOC_CLK>, - <&rpmcc RPM_SMD_PCNOC_A_CLK>; }; snoc: interconnect@580000 { compatible = "qcom,msm8916-snoc"; reg = <0x00580000 0x14000>; #interconnect-cells = <1>; - clock-names = "bus", "bus_a"; - clocks = <&rpmcc RPM_SMD_SNOC_CLK>, - <&rpmcc RPM_SMD_SNOC_A_CLK>; }; From 1ecbcc0d5be444415c139d2c8d84dd9bf94845cb Mon Sep 17 00:00:00 2001 From: Konrad Dybcio Date: Mon, 24 Jul 2023 16:06:33 +0200 Subject: [PATCH 216/326] dt-bindings: interconnect: qcom: rpm: Clean up the example One example is enough, remove the others and fix up the indentation while at it. Signed-off-by: Konrad Dybcio Link: https://lore.kernel.org/r/20230721-topic-icc_bindings-v2-7-e33d5acbf3bd@linaro.org Signed-off-by: Georgi Djakov --- .../bindings/interconnect/qcom,rpm.yaml | 18 +++--------------- 1 file changed, 3 insertions(+), 15 deletions(-) diff --git a/Documentation/devicetree/bindings/interconnect/qcom,rpm.yaml b/Documentation/devicetree/bindings/interconnect/qcom,rpm.yaml index 157efd47904d..08c1c6b9d7cf 100644 --- a/Documentation/devicetree/bindings/interconnect/qcom,rpm.yaml +++ b/Documentation/devicetree/bindings/interconnect/qcom,rpm.yaml @@ -41,19 +41,7 @@ examples: #include bimc: interconnect@400000 { - compatible = "qcom,msm8916-bimc"; - reg = <0x00400000 0x62000>; - #interconnect-cells = <1>; - }; - - pcnoc: interconnect@500000 { - compatible = "qcom,msm8916-pcnoc"; - reg = <0x00500000 0x11000>; - #interconnect-cells = <1>; - }; - - snoc: interconnect@580000 { - compatible = "qcom,msm8916-snoc"; - reg = <0x00580000 0x14000>; - #interconnect-cells = <1>; + compatible = "qcom,msm8916-bimc"; + reg = <0x00400000 0x62000>; + #interconnect-cells = <1>; }; From 8517824f0e94d52ab82742106314f0b8875e03c4 Mon Sep 17 00:00:00 2001 From: Konrad Dybcio Date: Sat, 12 Aug 2023 01:20:44 +0200 Subject: [PATCH 217/326] interconnect: qcom: qdu1000: Set ACV enable_mask ACV expects an enable_mask corresponding to the APPS RSC, fill it in. Fixes: 1f51339f7dd0 ("interconnect: qcom: Add QDU1000/QRU1000 interconnect driver") Signed-off-by: Konrad Dybcio Link: https://lore.kernel.org/r/20230811-topic-acv-v2-1-765ad70e539a@linaro.org Signed-off-by: Georgi Djakov --- drivers/interconnect/qcom/qdu1000.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/interconnect/qcom/qdu1000.c b/drivers/interconnect/qcom/qdu1000.c index bf800dd7d4ba..a7392eb73d4a 100644 --- a/drivers/interconnect/qcom/qdu1000.c +++ b/drivers/interconnect/qcom/qdu1000.c @@ -769,6 +769,7 @@ static struct qcom_icc_node xs_sys_tcu_cfg = { static struct qcom_icc_bcm bcm_acv = { .name = "ACV", + .enable_mask = BIT(3), .num_nodes = 1, .nodes = { &ebi }, }; From 1ad83c4792722fe134c1352591420702ff7b9091 Mon Sep 17 00:00:00 2001 From: Konrad Dybcio Date: Sat, 12 Aug 2023 01:20:45 +0200 Subject: [PATCH 218/326] interconnect: qcom: sc7180: Set ACV enable_mask ACV expects an enable_mask corresponding to the APPS RSC, fill it in. Fixes: 2d1f95ab9feb ("interconnect: qcom: Add SC7180 interconnect provider driver") Signed-off-by: Konrad Dybcio Link: https://lore.kernel.org/r/20230811-topic-acv-v2-2-765ad70e539a@linaro.org Signed-off-by: Georgi Djakov --- drivers/interconnect/qcom/sc7180.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/interconnect/qcom/sc7180.c b/drivers/interconnect/qcom/sc7180.c index d94ab9b39f3d..af2be1543840 100644 --- a/drivers/interconnect/qcom/sc7180.c +++ b/drivers/interconnect/qcom/sc7180.c @@ -1238,6 +1238,7 @@ static struct qcom_icc_node xs_sys_tcu_cfg = { static struct qcom_icc_bcm bcm_acv = { .name = "ACV", + .enable_mask = BIT(3), .keepalive = false, .num_nodes = 1, .nodes = { &ebi }, From 437b8e7fcd5df792cb8b8095e9f6eccefec6c099 Mon Sep 17 00:00:00 2001 From: Konrad Dybcio Date: Sat, 12 Aug 2023 01:20:46 +0200 Subject: [PATCH 219/326] interconnect: qcom: sc7280: Set ACV enable_mask ACV expects an enable_mask corresponding to the APPS RSC, fill it in. Fixes: 46bdcac533cc ("interconnect: qcom: Add SC7280 interconnect provider driver") Signed-off-by: Konrad Dybcio Link: https://lore.kernel.org/r/20230811-topic-acv-v2-3-765ad70e539a@linaro.org Signed-off-by: Georgi Djakov --- drivers/interconnect/qcom/sc7280.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/interconnect/qcom/sc7280.c b/drivers/interconnect/qcom/sc7280.c index 6592839b4d94..a626dbc71999 100644 --- a/drivers/interconnect/qcom/sc7280.c +++ b/drivers/interconnect/qcom/sc7280.c @@ -1285,6 +1285,7 @@ static struct qcom_icc_node srvc_snoc = { static struct qcom_icc_bcm bcm_acv = { .name = "ACV", + .enable_mask = BIT(3), .num_nodes = 1, .nodes = { &ebi }, }; From 0fcaaed3ff4b99e5b688b799f48989f1e4bb8a8b Mon Sep 17 00:00:00 2001 From: Konrad Dybcio Date: Sat, 12 Aug 2023 01:20:47 +0200 Subject: [PATCH 220/326] interconnect: qcom: sc8180x: Set ACV enable_mask ACV expects an enable_mask corresponding to the APPS RSC, fill it in. Fixes: 9c8c6bac1ae8 ("interconnect: qcom: Add SC8180x providers") Signed-off-by: Konrad Dybcio Link: https://lore.kernel.org/r/20230811-topic-acv-v2-4-765ad70e539a@linaro.org Signed-off-by: Georgi Djakov --- drivers/interconnect/qcom/sc8180x.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/interconnect/qcom/sc8180x.c b/drivers/interconnect/qcom/sc8180x.c index 0fb4898dabcf..bdd3471d4ac8 100644 --- a/drivers/interconnect/qcom/sc8180x.c +++ b/drivers/interconnect/qcom/sc8180x.c @@ -1345,6 +1345,7 @@ static struct qcom_icc_node slv_qup_core_2 = { static struct qcom_icc_bcm bcm_acv = { .name = "ACV", + .enable_mask = BIT(3), .num_nodes = 1, .nodes = { &slv_ebi } }; From 688ffb3dcf85fc4b7ea82af842493013747a9e2c Mon Sep 17 00:00:00 2001 From: Konrad Dybcio Date: Sat, 12 Aug 2023 01:20:48 +0200 Subject: [PATCH 221/326] interconnect: qcom: sc8280xp: Set ACV enable_mask ACV expects an enable_mask corresponding to the APPS RSC, fill it in. Fixes: f29dabda7917 ("interconnect: qcom: Add SC8280XP interconnect provider") Signed-off-by: Konrad Dybcio Link: https://lore.kernel.org/r/20230811-topic-acv-v2-5-765ad70e539a@linaro.org Signed-off-by: Georgi Djakov --- drivers/interconnect/qcom/sc8280xp.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/interconnect/qcom/sc8280xp.c b/drivers/interconnect/qcom/sc8280xp.c index b82c5493cbb5..0270f6c64481 100644 --- a/drivers/interconnect/qcom/sc8280xp.c +++ b/drivers/interconnect/qcom/sc8280xp.c @@ -1712,6 +1712,7 @@ static struct qcom_icc_node srvc_snoc = { static struct qcom_icc_bcm bcm_acv = { .name = "ACV", + .enable_mask = BIT(3), .num_nodes = 1, .nodes = { &ebi }, }; From 7b85ea8b9300be5c2818e1f61a274ff2c4c063ee Mon Sep 17 00:00:00 2001 From: Konrad Dybcio Date: Sat, 12 Aug 2023 01:20:49 +0200 Subject: [PATCH 222/326] interconnect: qcom: sdm670: Set ACV enable_mask ACV expects an enable_mask corresponding to the APPS RSC, fill it in. Fixes: 7e438e18874e ("interconnect: qcom: add sdm670 interconnects") Signed-off-by: Konrad Dybcio Link: https://lore.kernel.org/r/20230811-topic-acv-v2-6-765ad70e539a@linaro.org Signed-off-by: Georgi Djakov --- drivers/interconnect/qcom/sdm670.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/interconnect/qcom/sdm670.c b/drivers/interconnect/qcom/sdm670.c index 540a2108b77c..907e1ff4ff81 100644 --- a/drivers/interconnect/qcom/sdm670.c +++ b/drivers/interconnect/qcom/sdm670.c @@ -1047,6 +1047,7 @@ static struct qcom_icc_node xs_sys_tcu_cfg = { static struct qcom_icc_bcm bcm_acv = { .name = "ACV", + .enable_mask = BIT(3), .keepalive = false, .num_nodes = 1, .nodes = { &ebi }, From f8fe97a9fd2098de0570387029065eef657d50ee Mon Sep 17 00:00:00 2001 From: Konrad Dybcio Date: Sat, 12 Aug 2023 01:20:50 +0200 Subject: [PATCH 223/326] interconnect: qcom: sdm845: Set ACV enable_mask ACV expects an enable_mask corresponding to the APPS RSC, fill it in. Fixes: b5d2f741077a ("interconnect: qcom: Add sdm845 interconnect provider driver") Signed-off-by: Konrad Dybcio Link: https://lore.kernel.org/r/20230811-topic-acv-v2-7-765ad70e539a@linaro.org Signed-off-by: Georgi Djakov --- drivers/interconnect/qcom/sdm845.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/interconnect/qcom/sdm845.c b/drivers/interconnect/qcom/sdm845.c index b9243c0aa626..855802be93fe 100644 --- a/drivers/interconnect/qcom/sdm845.c +++ b/drivers/interconnect/qcom/sdm845.c @@ -1265,6 +1265,7 @@ static struct qcom_icc_node xs_sys_tcu_cfg = { static struct qcom_icc_bcm bcm_acv = { .name = "ACV", + .enable_mask = BIT(3), .keepalive = false, .num_nodes = 1, .nodes = { &ebi }, From fe7a3abf4111992af3de51d22383a8e8a0affe1e Mon Sep 17 00:00:00 2001 From: Konrad Dybcio Date: Sat, 12 Aug 2023 01:20:51 +0200 Subject: [PATCH 224/326] interconnect: qcom: sm6350: Set ACV enable_mask ACV expects an enable_mask corresponding to the APPS RSC, fill it in. Fixes: 6a6eff73a954 ("interconnect: qcom: Add SM6350 driver support") Signed-off-by: Konrad Dybcio Link: https://lore.kernel.org/r/20230811-topic-acv-v2-8-765ad70e539a@linaro.org Signed-off-by: Georgi Djakov --- drivers/interconnect/qcom/sm6350.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/interconnect/qcom/sm6350.c b/drivers/interconnect/qcom/sm6350.c index 49aed492e9b8..f41d7e19ba26 100644 --- a/drivers/interconnect/qcom/sm6350.c +++ b/drivers/interconnect/qcom/sm6350.c @@ -1164,6 +1164,7 @@ static struct qcom_icc_node xs_sys_tcu_cfg = { static struct qcom_icc_bcm bcm_acv = { .name = "ACV", + .enable_mask = BIT(3), .keepalive = false, .num_nodes = 1, .nodes = { &ebi }, From 7ed42176406e5a2c9a5767d0d75690c7d1588027 Mon Sep 17 00:00:00 2001 From: Konrad Dybcio Date: Sat, 12 Aug 2023 01:20:52 +0200 Subject: [PATCH 225/326] interconnect: qcom: sm8150: Set ACV enable_mask ACV expects an enable_mask corresponding to the APPS RSC, fill it in. Fixes: a09b817c8bad ("interconnect: qcom: Add SM8150 interconnect provider driver") Signed-off-by: Konrad Dybcio Link: https://lore.kernel.org/r/20230811-topic-acv-v2-9-765ad70e539a@linaro.org Signed-off-by: Georgi Djakov --- drivers/interconnect/qcom/sm8150.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/interconnect/qcom/sm8150.c b/drivers/interconnect/qcom/sm8150.c index c7c9cf7f746b..edfe824cad35 100644 --- a/drivers/interconnect/qcom/sm8150.c +++ b/drivers/interconnect/qcom/sm8150.c @@ -1282,6 +1282,7 @@ static struct qcom_icc_node xs_sys_tcu_cfg = { static struct qcom_icc_bcm bcm_acv = { .name = "ACV", + .enable_mask = BIT(3), .keepalive = false, .num_nodes = 1, .nodes = { &ebi }, From 9434c6896123141ac1f8f18b3d1751abbecdd03f Mon Sep 17 00:00:00 2001 From: Konrad Dybcio Date: Sat, 12 Aug 2023 01:20:53 +0200 Subject: [PATCH 226/326] interconnect: qcom: sm8250: Set ACV enable_mask ACV expects an enable_mask corresponding to the APPS RSC, fill it in. Fixes: 6df5b349491e ("interconnect: qcom: Add SM8250 interconnect provider driver") Signed-off-by: Konrad Dybcio Link: https://lore.kernel.org/r/20230811-topic-acv-v2-10-765ad70e539a@linaro.org Signed-off-by: Georgi Djakov --- drivers/interconnect/qcom/sm8250.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/interconnect/qcom/sm8250.c b/drivers/interconnect/qcom/sm8250.c index d4a4ecef11f0..661dc18d99db 100644 --- a/drivers/interconnect/qcom/sm8250.c +++ b/drivers/interconnect/qcom/sm8250.c @@ -1397,6 +1397,7 @@ static struct qcom_icc_node qup2_core_slave = { static struct qcom_icc_bcm bcm_acv = { .name = "ACV", + .enable_mask = BIT(3), .keepalive = false, .num_nodes = 1, .nodes = { &ebi }, From df1b8356a80ab47a7623e08facf36fe434ea9722 Mon Sep 17 00:00:00 2001 From: Konrad Dybcio Date: Sat, 12 Aug 2023 01:20:54 +0200 Subject: [PATCH 227/326] interconnect: qcom: sm8350: Set ACV enable_mask ACV expects an enable_mask corresponding to the APPS RSC, fill it in. Fixes: d26a56674497 ("interconnect: qcom: Add SM8350 interconnect provider driver") Signed-off-by: Konrad Dybcio Link: https://lore.kernel.org/r/20230811-topic-acv-v2-11-765ad70e539a@linaro.org Signed-off-by: Georgi Djakov --- drivers/interconnect/qcom/sm8350.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/interconnect/qcom/sm8350.c b/drivers/interconnect/qcom/sm8350.c index bdf75839e6d1..562322d4fc3c 100644 --- a/drivers/interconnect/qcom/sm8350.c +++ b/drivers/interconnect/qcom/sm8350.c @@ -1356,6 +1356,7 @@ static struct qcom_icc_node qns_mem_noc_sf_disp = { static struct qcom_icc_bcm bcm_acv = { .name = "ACV", + .enable_mask = BIT(3), .keepalive = false, .num_nodes = 1, .nodes = { &ebi }, From 956329ec7c5eba430211b48cca1b0372b4a4d702 Mon Sep 17 00:00:00 2001 From: Rohit Agarwal Date: Wed, 13 Sep 2023 19:40:55 +0530 Subject: [PATCH 228/326] dt-bindings: interconnect: Add compatibles for SDX75 Add dt-bindings compatibles and interconnect IDs for Qualcomm SDX75 platform. Signed-off-by: Rohit Agarwal Reviewed-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/1694614256-24109-2-git-send-email-quic_rohiagar@quicinc.com Signed-off-by: Georgi Djakov --- .../interconnect/qcom,sdx75-rpmh.yaml | 92 ++++++++++++++++ include/dt-bindings/interconnect/qcom,sdx75.h | 102 ++++++++++++++++++ 2 files changed, 194 insertions(+) create mode 100644 Documentation/devicetree/bindings/interconnect/qcom,sdx75-rpmh.yaml create mode 100644 include/dt-bindings/interconnect/qcom,sdx75.h diff --git a/Documentation/devicetree/bindings/interconnect/qcom,sdx75-rpmh.yaml b/Documentation/devicetree/bindings/interconnect/qcom,sdx75-rpmh.yaml new file mode 100644 index 000000000000..71cf7e252bfc --- /dev/null +++ b/Documentation/devicetree/bindings/interconnect/qcom,sdx75-rpmh.yaml @@ -0,0 +1,92 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/interconnect/qcom,sdx75-rpmh.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Qualcomm RPMh Network-On-Chip Interconnect on SDX75 + +maintainers: + - Rohit Agarwal + +description: + RPMh interconnect providers support system bandwidth requirements through + RPMh hardware accelerators known as Bus Clock Manager (BCM). The provider is + able to communicate with the BCM through the Resource State Coordinator (RSC) + associated with each execution environment. Provider nodes must point to at + least one RPMh device child node pertaining to their RSC and each provider + can map to multiple RPMh resources. + +properties: + compatible: + enum: + - qcom,sdx75-clk-virt + - qcom,sdx75-dc-noc + - qcom,sdx75-gem-noc + - qcom,sdx75-mc-virt + - qcom,sdx75-pcie-anoc + - qcom,sdx75-system-noc + + '#interconnect-cells': true + + reg: + maxItems: 1 + + clocks: + maxItems: 1 + +required: + - compatible + +allOf: + - $ref: qcom,rpmh-common.yaml# + - if: + properties: + compatible: + contains: + enum: + - qcom,sdx75-clk-virt + - qcom,sdx75-mc-virt + then: + properties: + reg: false + else: + required: + - reg + + - if: + properties: + compatible: + contains: + enum: + - qcom,sdx75-clk-virt + then: + properties: + clocks: + items: + - description: RPMH CC QPIC Clock + required: + - clocks + else: + properties: + clocks: false + +unevaluatedProperties: false + +examples: + - | + #include + + clk_virt: interconnect-0 { + compatible = "qcom,sdx75-clk-virt"; + #interconnect-cells = <2>; + qcom,bcm-voters = <&apps_bcm_voter>; + clocks = <&rpmhcc RPMH_QPIC_CLK>; + }; + + system_noc: interconnect@1640000 { + compatible = "qcom,sdx75-system-noc"; + reg = <0x1640000 0x4b400>; + #interconnect-cells = <2>; + qcom,bcm-voters = <&apps_bcm_voter>; + }; diff --git a/include/dt-bindings/interconnect/qcom,sdx75.h b/include/dt-bindings/interconnect/qcom,sdx75.h new file mode 100644 index 000000000000..e903f5f3dd8f --- /dev/null +++ b/include/dt-bindings/interconnect/qcom,sdx75.h @@ -0,0 +1,102 @@ +/* SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) */ +/* + * Copyright (c) 2023, Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#ifndef __DT_BINDINGS_INTERCONNECT_QCOM_SDX75_H +#define __DT_BINDINGS_INTERCONNECT_QCOM_SDX75_H + +#define MASTER_QPIC_CORE 0 +#define MASTER_QUP_CORE_0 1 +#define SLAVE_QPIC_CORE 2 +#define SLAVE_QUP_CORE_0 3 + +#define MASTER_LLCC 0 +#define SLAVE_EBI1 1 + +#define MASTER_CNOC_DC_NOC 0 +#define SLAVE_LAGG_CFG 1 +#define SLAVE_MCCC_MASTER 2 +#define SLAVE_GEM_NOC_CFG 3 +#define SLAVE_SNOOP_BWMON 4 + +#define MASTER_SYS_TCU 0 +#define MASTER_APPSS_PROC 1 +#define MASTER_GEM_NOC_CFG 2 +#define MASTER_MSS_PROC 3 +#define MASTER_ANOC_PCIE_GEM_NOC 4 +#define MASTER_SNOC_SF_MEM_NOC 5 +#define MASTER_GIC 6 +#define MASTER_IPA_PCIE 7 +#define SLAVE_GEM_NOC_CNOC 8 +#define SLAVE_LLCC 9 +#define SLAVE_MEM_NOC_PCIE_SNOC 10 +#define SLAVE_SERVICE_GEM_NOC 11 + +#define MASTER_PCIE_0 0 +#define MASTER_PCIE_1 1 +#define MASTER_PCIE_2 2 +#define SLAVE_ANOC_PCIE_GEM_NOC 3 + +#define MASTER_AUDIO 0 +#define MASTER_GIC_AHB 1 +#define MASTER_PCIE_RSCC 2 +#define MASTER_QDSS_BAM 3 +#define MASTER_QPIC 4 +#define MASTER_QUP_0 5 +#define MASTER_ANOC_SNOC 6 +#define MASTER_GEM_NOC_CNOC 7 +#define MASTER_GEM_NOC_PCIE_SNOC 8 +#define MASTER_SNOC_CFG 9 +#define MASTER_PCIE_ANOC_CFG 10 +#define MASTER_CRYPTO 11 +#define MASTER_IPA 12 +#define MASTER_MVMSS 13 +#define MASTER_EMAC_0 14 +#define MASTER_EMAC_1 15 +#define MASTER_QDSS_ETR 16 +#define MASTER_QDSS_ETR_1 17 +#define MASTER_SDCC_1 18 +#define MASTER_SDCC_4 19 +#define MASTER_USB3_0 20 +#define SLAVE_ETH0_CFG 21 +#define SLAVE_ETH1_CFG 22 +#define SLAVE_AUDIO 23 +#define SLAVE_CLK_CTL 24 +#define SLAVE_CRYPTO_0_CFG 25 +#define SLAVE_IMEM_CFG 26 +#define SLAVE_IPA_CFG 27 +#define SLAVE_IPC_ROUTER_CFG 28 +#define SLAVE_CNOC_MSS 29 +#define SLAVE_ICBDI_MVMSS_CFG 30 +#define SLAVE_PCIE_0_CFG 31 +#define SLAVE_PCIE_1_CFG 32 +#define SLAVE_PCIE_2_CFG 33 +#define SLAVE_PCIE_RSC_CFG 34 +#define SLAVE_PDM 35 +#define SLAVE_PRNG 36 +#define SLAVE_QDSS_CFG 37 +#define SLAVE_QPIC 38 +#define SLAVE_QUP_0 39 +#define SLAVE_SDCC_1 40 +#define SLAVE_SDCC_4 41 +#define SLAVE_SPMI_VGI_COEX 42 +#define SLAVE_TCSR 43 +#define SLAVE_TLMM 44 +#define SLAVE_USB3 45 +#define SLAVE_USB3_PHY_CFG 46 +#define SLAVE_A1NOC_CFG 47 +#define SLAVE_DDRSS_CFG 48 +#define SLAVE_SNOC_GEM_NOC_SF 49 +#define SLAVE_SNOC_CFG 50 +#define SLAVE_PCIE_ANOC_CFG 51 +#define SLAVE_IMEM 52 +#define SLAVE_SERVICE_PCIE_ANOC 53 +#define SLAVE_SERVICE_SNOC 54 +#define SLAVE_PCIE_0 55 +#define SLAVE_PCIE_1 56 +#define SLAVE_PCIE_2 57 +#define SLAVE_QDSS_STM 58 +#define SLAVE_TCU 59 + +#endif From 3642b4e5cbfe480892858f0209c6fd0a3172a103 Mon Sep 17 00:00:00 2001 From: Rohit Agarwal Date: Wed, 13 Sep 2023 19:40:56 +0530 Subject: [PATCH 229/326] interconnect: qcom: Add SDX75 interconnect provider driver Add driver for the Qualcomm interconnect buses found in SDX75. Signed-off-by: Rohit Agarwal Reviewed-by: Konrad Dybcio Link: https://lore.kernel.org/r/1694614256-24109-3-git-send-email-quic_rohiagar@quicinc.com Signed-off-by: Georgi Djakov --- drivers/interconnect/qcom/Kconfig | 9 + drivers/interconnect/qcom/Makefile | 2 + drivers/interconnect/qcom/sdx75.c | 1107 ++++++++++++++++++++++++++++ drivers/interconnect/qcom/sdx75.h | 97 +++ 4 files changed, 1215 insertions(+) create mode 100644 drivers/interconnect/qcom/sdx75.c create mode 100644 drivers/interconnect/qcom/sdx75.h diff --git a/drivers/interconnect/qcom/Kconfig b/drivers/interconnect/qcom/Kconfig index 825b647d9169..62b516d38d03 100644 --- a/drivers/interconnect/qcom/Kconfig +++ b/drivers/interconnect/qcom/Kconfig @@ -182,6 +182,15 @@ config INTERCONNECT_QCOM_SDX65 This is a driver for the Qualcomm Network-on-Chip on sdx65-based platforms. +config INTERCONNECT_QCOM_SDX75 + tristate "Qualcomm SDX75 interconnect driver" + depends on INTERCONNECT_QCOM_RPMH_POSSIBLE + select INTERCONNECT_QCOM_RPMH + select INTERCONNECT_QCOM_BCM_VOTER + help + This is a driver for the Qualcomm Network-on-Chip on sdx75-based + platforms. + config INTERCONNECT_QCOM_SM6350 tristate "Qualcomm SM6350 interconnect driver" depends on INTERCONNECT_QCOM_RPMH_POSSIBLE diff --git a/drivers/interconnect/qcom/Makefile b/drivers/interconnect/qcom/Makefile index 80d9d2da95d1..c5320e293960 100644 --- a/drivers/interconnect/qcom/Makefile +++ b/drivers/interconnect/qcom/Makefile @@ -23,6 +23,7 @@ qnoc-sdm670-objs := sdm670.o qnoc-sdm845-objs := sdm845.o qnoc-sdx55-objs := sdx55.o qnoc-sdx65-objs := sdx65.o +qnoc-sdx75-objs := sdx75.o qnoc-sm6350-objs := sm6350.o qnoc-sm8150-objs := sm8150.o qnoc-sm8250-objs := sm8250.o @@ -51,6 +52,7 @@ obj-$(CONFIG_INTERCONNECT_QCOM_SDM670) += qnoc-sdm670.o obj-$(CONFIG_INTERCONNECT_QCOM_SDM845) += qnoc-sdm845.o obj-$(CONFIG_INTERCONNECT_QCOM_SDX55) += qnoc-sdx55.o obj-$(CONFIG_INTERCONNECT_QCOM_SDX65) += qnoc-sdx65.o +obj-$(CONFIG_INTERCONNECT_QCOM_SDX75) += qnoc-sdx75.o obj-$(CONFIG_INTERCONNECT_QCOM_SM6350) += qnoc-sm6350.o obj-$(CONFIG_INTERCONNECT_QCOM_SM8150) += qnoc-sm8150.o obj-$(CONFIG_INTERCONNECT_QCOM_SM8250) += qnoc-sm8250.o diff --git a/drivers/interconnect/qcom/sdx75.c b/drivers/interconnect/qcom/sdx75.c new file mode 100644 index 000000000000..7ef1f17f3292 --- /dev/null +++ b/drivers/interconnect/qcom/sdx75.c @@ -0,0 +1,1107 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2023, Qualcomm Innovation Center, Inc. All rights reserved. + * + */ + +#include +#include +#include +#include +#include +#include + +#include "bcm-voter.h" +#include "icc-common.h" +#include "icc-rpmh.h" +#include "sdx75.h" + +static struct qcom_icc_node qpic_core_master = { + .name = "qpic_core_master", + .id = SDX75_MASTER_QPIC_CORE, + .channels = 1, + .buswidth = 4, + .num_links = 1, + .links = { SDX75_SLAVE_QPIC_CORE }, +}; + +static struct qcom_icc_node qup0_core_master = { + .name = "qup0_core_master", + .id = SDX75_MASTER_QUP_CORE_0, + .channels = 1, + .buswidth = 4, + .num_links = 1, + .links = { SDX75_SLAVE_QUP_CORE_0 }, +}; + +static struct qcom_icc_node qnm_cnoc = { + .name = "qnm_cnoc", + .id = SDX75_MASTER_CNOC_DC_NOC, + .channels = 1, + .buswidth = 4, + .num_links = 4, + .links = { SDX75_SLAVE_LAGG_CFG, SDX75_SLAVE_MCCC_MASTER, + SDX75_SLAVE_GEM_NOC_CFG, SDX75_SLAVE_SNOOP_BWMON }, +}; + +static struct qcom_icc_node alm_sys_tcu = { + .name = "alm_sys_tcu", + .id = SDX75_MASTER_SYS_TCU, + .channels = 1, + .buswidth = 8, + .num_links = 2, + .links = { SDX75_SLAVE_GEM_NOC_CNOC, SDX75_SLAVE_LLCC }, +}; + +static struct qcom_icc_node chm_apps = { + .name = "chm_apps", + .id = SDX75_MASTER_APPSS_PROC, + .channels = 1, + .buswidth = 16, + .num_links = 3, + .links = { SDX75_SLAVE_GEM_NOC_CNOC, SDX75_SLAVE_LLCC, + SDX75_SLAVE_MEM_NOC_PCIE_SNOC }, +}; + +static struct qcom_icc_node qnm_gemnoc_cfg = { + .name = "qnm_gemnoc_cfg", + .id = SDX75_MASTER_GEM_NOC_CFG, + .channels = 1, + .buswidth = 4, + .num_links = 1, + .links = { SDX75_SLAVE_SERVICE_GEM_NOC }, +}; + +static struct qcom_icc_node qnm_mdsp = { + .name = "qnm_mdsp", + .id = SDX75_MASTER_MSS_PROC, + .channels = 1, + .buswidth = 16, + .num_links = 3, + .links = { SDX75_SLAVE_GEM_NOC_CNOC, SDX75_SLAVE_LLCC, + SDX75_SLAVE_MEM_NOC_PCIE_SNOC }, +}; + +static struct qcom_icc_node qnm_pcie = { + .name = "qnm_pcie", + .id = SDX75_MASTER_ANOC_PCIE_GEM_NOC, + .channels = 1, + .buswidth = 16, + .num_links = 2, + .links = { SDX75_SLAVE_GEM_NOC_CNOC, SDX75_SLAVE_LLCC }, +}; + +static struct qcom_icc_node qnm_snoc_sf = { + .name = "qnm_snoc_sf", + .id = SDX75_MASTER_SNOC_SF_MEM_NOC, + .channels = 1, + .buswidth = 16, + .num_links = 3, + .links = { SDX75_SLAVE_GEM_NOC_CNOC, SDX75_SLAVE_LLCC, + SDX75_SLAVE_MEM_NOC_PCIE_SNOC }, +}; + +static struct qcom_icc_node xm_gic = { + .name = "xm_gic", + .id = SDX75_MASTER_GIC, + .channels = 1, + .buswidth = 8, + .num_links = 1, + .links = { SDX75_SLAVE_LLCC }, +}; + +static struct qcom_icc_node xm_ipa2pcie = { + .name = "xm_ipa2pcie", + .id = SDX75_MASTER_IPA_PCIE, + .channels = 1, + .buswidth = 8, + .num_links = 1, + .links = { SDX75_SLAVE_MEM_NOC_PCIE_SNOC }, +}; + +static struct qcom_icc_node llcc_mc = { + .name = "llcc_mc", + .id = SDX75_MASTER_LLCC, + .channels = 1, + .buswidth = 4, + .num_links = 1, + .links = { SDX75_SLAVE_EBI1 }, +}; + +static struct qcom_icc_node xm_pcie3_0 = { + .name = "xm_pcie3_0", + .id = SDX75_MASTER_PCIE_0, + .channels = 1, + .buswidth = 8, + .num_links = 1, + .links = { SDX75_SLAVE_ANOC_PCIE_GEM_NOC }, +}; + +static struct qcom_icc_node xm_pcie3_1 = { + .name = "xm_pcie3_1", + .id = SDX75_MASTER_PCIE_1, + .channels = 1, + .buswidth = 8, + .num_links = 1, + .links = { SDX75_SLAVE_ANOC_PCIE_GEM_NOC }, +}; + +static struct qcom_icc_node xm_pcie3_2 = { + .name = "xm_pcie3_2", + .id = SDX75_MASTER_PCIE_2, + .channels = 1, + .buswidth = 8, + .num_links = 1, + .links = { SDX75_SLAVE_ANOC_PCIE_GEM_NOC }, +}; + +static struct qcom_icc_node qhm_audio = { + .name = "qhm_audio", + .id = SDX75_MASTER_AUDIO, + .channels = 1, + .buswidth = 4, + .num_links = 1, + .links = { SDX75_SLAVE_SNOC_GEM_NOC_SF }, +}; + +static struct qcom_icc_node qhm_gic = { + .name = "qhm_gic", + .id = SDX75_MASTER_GIC_AHB, + .channels = 1, + .buswidth = 4, + .num_links = 1, + .links = { SDX75_SLAVE_SNOC_GEM_NOC_SF }, +}; + +static struct qcom_icc_node qhm_pcie_rscc = { + .name = "qhm_pcie_rscc", + .id = SDX75_MASTER_PCIE_RSCC, + .channels = 1, + .buswidth = 4, + .num_links = 31, + .links = { SDX75_SLAVE_ETH0_CFG, SDX75_SLAVE_ETH1_CFG, + SDX75_SLAVE_AUDIO, SDX75_SLAVE_CLK_CTL, + SDX75_SLAVE_CRYPTO_0_CFG, SDX75_SLAVE_IMEM_CFG, + SDX75_SLAVE_IPA_CFG, SDX75_SLAVE_IPC_ROUTER_CFG, + SDX75_SLAVE_CNOC_MSS, SDX75_SLAVE_ICBDI_MVMSS_CFG, + SDX75_SLAVE_PCIE_0_CFG, SDX75_SLAVE_PCIE_1_CFG, + SDX75_SLAVE_PCIE_2_CFG, SDX75_SLAVE_PDM, + SDX75_SLAVE_PRNG, SDX75_SLAVE_QDSS_CFG, + SDX75_SLAVE_QPIC, SDX75_SLAVE_QUP_0, + SDX75_SLAVE_SDCC_1, SDX75_SLAVE_SDCC_4, + SDX75_SLAVE_SPMI_VGI_COEX, SDX75_SLAVE_TCSR, + SDX75_SLAVE_TLMM, SDX75_SLAVE_USB3, + SDX75_SLAVE_USB3_PHY_CFG, SDX75_SLAVE_DDRSS_CFG, + SDX75_SLAVE_SNOC_CFG, SDX75_SLAVE_PCIE_ANOC_CFG, + SDX75_SLAVE_IMEM, SDX75_SLAVE_QDSS_STM, + SDX75_SLAVE_TCU }, +}; + +static struct qcom_icc_node qhm_qdss_bam = { + .name = "qhm_qdss_bam", + .id = SDX75_MASTER_QDSS_BAM, + .channels = 1, + .buswidth = 4, + .num_links = 1, + .links = { SDX75_SLAVE_A1NOC_CFG }, +}; + +static struct qcom_icc_node qhm_qpic = { + .name = "qhm_qpic", + .id = SDX75_MASTER_QPIC, + .channels = 1, + .buswidth = 4, + .num_links = 1, + .links = { SDX75_SLAVE_A1NOC_CFG }, +}; + +static struct qcom_icc_node qhm_qup0 = { + .name = "qhm_qup0", + .id = SDX75_MASTER_QUP_0, + .channels = 1, + .buswidth = 4, + .num_links = 1, + .links = { SDX75_SLAVE_A1NOC_CFG }, +}; + +static struct qcom_icc_node qnm_aggre_noc = { + .name = "qnm_aggre_noc", + .id = SDX75_MASTER_ANOC_SNOC, + .channels = 1, + .buswidth = 8, + .num_links = 1, + .links = { SDX75_SLAVE_SNOC_GEM_NOC_SF }, +}; + +static struct qcom_icc_node qnm_gemnoc_cnoc = { + .name = "qnm_gemnoc_cnoc", + .id = SDX75_MASTER_GEM_NOC_CNOC, + .channels = 1, + .buswidth = 8, + .num_links = 32, + .links = { SDX75_SLAVE_ETH0_CFG, SDX75_SLAVE_ETH1_CFG, + SDX75_SLAVE_AUDIO, SDX75_SLAVE_CLK_CTL, + SDX75_SLAVE_CRYPTO_0_CFG, SDX75_SLAVE_IMEM_CFG, + SDX75_SLAVE_IPA_CFG, SDX75_SLAVE_IPC_ROUTER_CFG, + SDX75_SLAVE_CNOC_MSS, SDX75_SLAVE_ICBDI_MVMSS_CFG, + SDX75_SLAVE_PCIE_0_CFG, SDX75_SLAVE_PCIE_1_CFG, + SDX75_SLAVE_PCIE_2_CFG, SDX75_SLAVE_PCIE_RSC_CFG, + SDX75_SLAVE_PDM, SDX75_SLAVE_PRNG, + SDX75_SLAVE_QDSS_CFG, SDX75_SLAVE_QPIC, + SDX75_SLAVE_QUP_0, SDX75_SLAVE_SDCC_1, + SDX75_SLAVE_SDCC_4, SDX75_SLAVE_SPMI_VGI_COEX, + SDX75_SLAVE_TCSR, SDX75_SLAVE_TLMM, + SDX75_SLAVE_USB3, SDX75_SLAVE_USB3_PHY_CFG, + SDX75_SLAVE_DDRSS_CFG, SDX75_SLAVE_SNOC_CFG, + SDX75_SLAVE_PCIE_ANOC_CFG, SDX75_SLAVE_IMEM, + SDX75_SLAVE_QDSS_STM, SDX75_SLAVE_TCU }, +}; + +static struct qcom_icc_node qnm_gemnoc_pcie = { + .name = "qnm_gemnoc_pcie", + .id = SDX75_MASTER_GEM_NOC_PCIE_SNOC, + .channels = 1, + .buswidth = 16, + .num_links = 3, + .links = { SDX75_SLAVE_PCIE_0, SDX75_SLAVE_PCIE_1, + SDX75_SLAVE_PCIE_2 }, +}; + +static struct qcom_icc_node qnm_system_noc_cfg = { + .name = "qnm_system_noc_cfg", + .id = SDX75_MASTER_SNOC_CFG, + .channels = 1, + .buswidth = 4, + .num_links = 1, + .links = { SDX75_SLAVE_SERVICE_SNOC }, +}; + +static struct qcom_icc_node qnm_system_noc_pcie_cfg = { + .name = "qnm_system_noc_pcie_cfg", + .id = SDX75_MASTER_PCIE_ANOC_CFG, + .channels = 1, + .buswidth = 4, + .num_links = 1, + .links = { SDX75_SLAVE_SERVICE_PCIE_ANOC }, +}; + +static struct qcom_icc_node qxm_crypto = { + .name = "qxm_crypto", + .id = SDX75_MASTER_CRYPTO, + .channels = 1, + .buswidth = 8, + .num_links = 1, + .links = { SDX75_SLAVE_A1NOC_CFG }, +}; + +static struct qcom_icc_node qxm_ipa = { + .name = "qxm_ipa", + .id = SDX75_MASTER_IPA, + .channels = 1, + .buswidth = 8, + .num_links = 1, + .links = { SDX75_SLAVE_SNOC_GEM_NOC_SF }, +}; + +static struct qcom_icc_node qxm_mvmss = { + .name = "qxm_mvmss", + .id = SDX75_MASTER_MVMSS, + .channels = 1, + .buswidth = 8, + .num_links = 1, + .links = { SDX75_SLAVE_A1NOC_CFG }, +}; + +static struct qcom_icc_node xm_emac_0 = { + .name = "xm_emac_0", + .id = SDX75_MASTER_EMAC_0, + .channels = 1, + .buswidth = 8, + .num_links = 1, + .links = { SDX75_SLAVE_A1NOC_CFG }, +}; + +static struct qcom_icc_node xm_emac_1 = { + .name = "xm_emac_1", + .id = SDX75_MASTER_EMAC_1, + .channels = 1, + .buswidth = 8, + .num_links = 1, + .links = { SDX75_SLAVE_A1NOC_CFG }, +}; + +static struct qcom_icc_node xm_qdss_etr0 = { + .name = "xm_qdss_etr0", + .id = SDX75_MASTER_QDSS_ETR, + .channels = 1, + .buswidth = 8, + .num_links = 1, + .links = { SDX75_SLAVE_A1NOC_CFG }, +}; + +static struct qcom_icc_node xm_qdss_etr1 = { + .name = "xm_qdss_etr1", + .id = SDX75_MASTER_QDSS_ETR_1, + .channels = 1, + .buswidth = 8, + .num_links = 1, + .links = { SDX75_SLAVE_A1NOC_CFG }, +}; + +static struct qcom_icc_node xm_sdc1 = { + .name = "xm_sdc1", + .id = SDX75_MASTER_SDCC_1, + .channels = 1, + .buswidth = 8, + .num_links = 1, + .links = { SDX75_SLAVE_A1NOC_CFG }, +}; + +static struct qcom_icc_node xm_sdc4 = { + .name = "xm_sdc4", + .id = SDX75_MASTER_SDCC_4, + .channels = 1, + .buswidth = 8, + .num_links = 1, + .links = { SDX75_SLAVE_A1NOC_CFG }, +}; + +static struct qcom_icc_node xm_usb3 = { + .name = "xm_usb3", + .id = SDX75_MASTER_USB3_0, + .channels = 1, + .buswidth = 8, + .num_links = 1, + .links = { SDX75_SLAVE_A1NOC_CFG }, +}; + +static struct qcom_icc_node qpic_core_slave = { + .name = "qpic_core_slave", + .id = SDX75_SLAVE_QPIC_CORE, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node qup0_core_slave = { + .name = "qup0_core_slave", + .id = SDX75_SLAVE_QUP_CORE_0, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node qhs_lagg = { + .name = "qhs_lagg", + .id = SDX75_SLAVE_LAGG_CFG, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node qhs_mccc_master = { + .name = "qhs_mccc_master", + .id = SDX75_SLAVE_MCCC_MASTER, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node qns_gemnoc = { + .name = "qns_gemnoc", + .id = SDX75_SLAVE_GEM_NOC_CFG, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node qss_snoop_bwmon = { + .name = "qss_snoop_bwmon", + .id = SDX75_SLAVE_SNOOP_BWMON, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node qns_gemnoc_cnoc = { + .name = "qns_gemnoc_cnoc", + .id = SDX75_SLAVE_GEM_NOC_CNOC, + .channels = 1, + .buswidth = 8, + .num_links = 1, + .links = { SDX75_MASTER_GEM_NOC_CNOC }, +}; + +static struct qcom_icc_node qns_llcc = { + .name = "qns_llcc", + .id = SDX75_SLAVE_LLCC, + .channels = 1, + .buswidth = 16, + .num_links = 1, + .links = { SDX75_MASTER_LLCC }, +}; + +static struct qcom_icc_node qns_pcie = { + .name = "qns_pcie", + .id = SDX75_SLAVE_MEM_NOC_PCIE_SNOC, + .channels = 1, + .buswidth = 16, + .num_links = 1, + .links = { SDX75_MASTER_GEM_NOC_PCIE_SNOC }, +}; + +static struct qcom_icc_node srvc_gemnoc = { + .name = "srvc_gemnoc", + .id = SDX75_SLAVE_SERVICE_GEM_NOC, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node ebi = { + .name = "ebi", + .id = SDX75_SLAVE_EBI1, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node qns_pcie_gemnoc = { + .name = "qns_pcie_gemnoc", + .id = SDX75_SLAVE_ANOC_PCIE_GEM_NOC, + .channels = 1, + .buswidth = 16, + .num_links = 1, + .links = { SDX75_MASTER_ANOC_PCIE_GEM_NOC }, +}; + +static struct qcom_icc_node ps_eth0_cfg = { + .name = "ps_eth0_cfg", + .id = SDX75_SLAVE_ETH0_CFG, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node ps_eth1_cfg = { + .name = "ps_eth1_cfg", + .id = SDX75_SLAVE_ETH1_CFG, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node qhs_audio = { + .name = "qhs_audio", + .id = SDX75_SLAVE_AUDIO, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node qhs_clk_ctl = { + .name = "qhs_clk_ctl", + .id = SDX75_SLAVE_CLK_CTL, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node qhs_crypto_cfg = { + .name = "qhs_crypto_cfg", + .id = SDX75_SLAVE_CRYPTO_0_CFG, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node qhs_imem_cfg = { + .name = "qhs_imem_cfg", + .id = SDX75_SLAVE_IMEM_CFG, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node qhs_ipa = { + .name = "qhs_ipa", + .id = SDX75_SLAVE_IPA_CFG, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node qhs_ipc_router = { + .name = "qhs_ipc_router", + .id = SDX75_SLAVE_IPC_ROUTER_CFG, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node qhs_mss_cfg = { + .name = "qhs_mss_cfg", + .id = SDX75_SLAVE_CNOC_MSS, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node qhs_mvmss_cfg = { + .name = "qhs_mvmss_cfg", + .id = SDX75_SLAVE_ICBDI_MVMSS_CFG, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node qhs_pcie0_cfg = { + .name = "qhs_pcie0_cfg", + .id = SDX75_SLAVE_PCIE_0_CFG, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node qhs_pcie1_cfg = { + .name = "qhs_pcie1_cfg", + .id = SDX75_SLAVE_PCIE_1_CFG, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node qhs_pcie2_cfg = { + .name = "qhs_pcie2_cfg", + .id = SDX75_SLAVE_PCIE_2_CFG, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node qhs_pcie_rscc = { + .name = "qhs_pcie_rscc", + .id = SDX75_SLAVE_PCIE_RSC_CFG, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node qhs_pdm = { + .name = "qhs_pdm", + .id = SDX75_SLAVE_PDM, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node qhs_prng = { + .name = "qhs_prng", + .id = SDX75_SLAVE_PRNG, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node qhs_qdss_cfg = { + .name = "qhs_qdss_cfg", + .id = SDX75_SLAVE_QDSS_CFG, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node qhs_qpic = { + .name = "qhs_qpic", + .id = SDX75_SLAVE_QPIC, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node qhs_qup0 = { + .name = "qhs_qup0", + .id = SDX75_SLAVE_QUP_0, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node qhs_sdc1 = { + .name = "qhs_sdc1", + .id = SDX75_SLAVE_SDCC_1, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node qhs_sdc4 = { + .name = "qhs_sdc4", + .id = SDX75_SLAVE_SDCC_4, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node qhs_spmi_vgi_coex = { + .name = "qhs_spmi_vgi_coex", + .id = SDX75_SLAVE_SPMI_VGI_COEX, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node qhs_tcsr = { + .name = "qhs_tcsr", + .id = SDX75_SLAVE_TCSR, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node qhs_tlmm = { + .name = "qhs_tlmm", + .id = SDX75_SLAVE_TLMM, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node qhs_usb3 = { + .name = "qhs_usb3", + .id = SDX75_SLAVE_USB3, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node qhs_usb3_phy = { + .name = "qhs_usb3_phy", + .id = SDX75_SLAVE_USB3_PHY_CFG, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node qns_a1noc = { + .name = "qns_a1noc", + .id = SDX75_SLAVE_A1NOC_CFG, + .channels = 1, + .buswidth = 8, + .num_links = 1, + .links = { SDX75_MASTER_ANOC_SNOC }, +}; + +static struct qcom_icc_node qns_ddrss_cfg = { + .name = "qns_ddrss_cfg", + .id = SDX75_SLAVE_DDRSS_CFG, + .channels = 1, + .buswidth = 4, + .num_links = 1, + .links = { SDX75_MASTER_CNOC_DC_NOC }, +}; + +static struct qcom_icc_node qns_gemnoc_sf = { + .name = "qns_gemnoc_sf", + .id = SDX75_SLAVE_SNOC_GEM_NOC_SF, + .channels = 1, + .buswidth = 16, + .num_links = 1, + .links = { SDX75_MASTER_SNOC_SF_MEM_NOC }, +}; + +static struct qcom_icc_node qns_system_noc_cfg = { + .name = "qns_system_noc_cfg", + .id = SDX75_SLAVE_SNOC_CFG, + .channels = 1, + .buswidth = 4, + .num_links = 1, + .links = { SDX75_MASTER_SNOC_CFG }, +}; + +static struct qcom_icc_node qns_system_noc_pcie_cfg = { + .name = "qns_system_noc_pcie_cfg", + .id = SDX75_SLAVE_PCIE_ANOC_CFG, + .channels = 1, + .buswidth = 4, + .num_links = 1, + .links = { SDX75_MASTER_PCIE_ANOC_CFG }, +}; + +static struct qcom_icc_node qxs_imem = { + .name = "qxs_imem", + .id = SDX75_SLAVE_IMEM, + .channels = 1, + .buswidth = 8, + .num_links = 0, +}; + +static struct qcom_icc_node srvc_pcie_system_noc = { + .name = "srvc_pcie_system_noc", + .id = SDX75_SLAVE_SERVICE_PCIE_ANOC, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node srvc_system_noc = { + .name = "srvc_system_noc", + .id = SDX75_SLAVE_SERVICE_SNOC, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node xs_pcie_0 = { + .name = "xs_pcie_0", + .id = SDX75_SLAVE_PCIE_0, + .channels = 1, + .buswidth = 8, + .num_links = 0, +}; + +static struct qcom_icc_node xs_pcie_1 = { + .name = "xs_pcie_1", + .id = SDX75_SLAVE_PCIE_1, + .channels = 1, + .buswidth = 8, + .num_links = 0, +}; + +static struct qcom_icc_node xs_pcie_2 = { + .name = "xs_pcie_2", + .id = SDX75_SLAVE_PCIE_2, + .channels = 1, + .buswidth = 8, + .num_links = 0, +}; + +static struct qcom_icc_node xs_qdss_stm = { + .name = "xs_qdss_stm", + .id = SDX75_SLAVE_QDSS_STM, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node xs_sys_tcu_cfg = { + .name = "xs_sys_tcu_cfg", + .id = SDX75_SLAVE_TCU, + .channels = 1, + .buswidth = 8, + .num_links = 0, +}; + +static struct qcom_icc_bcm bcm_ce0 = { + .name = "CE0", + .num_nodes = 1, + .nodes = { &qxm_crypto }, +}; + +static struct qcom_icc_bcm bcm_cn0 = { + .name = "CN0", + .keepalive = true, + .num_nodes = 39, + .nodes = { &qhm_pcie_rscc, &qnm_gemnoc_cnoc, + &ps_eth0_cfg, &ps_eth1_cfg, + &qhs_audio, &qhs_clk_ctl, + &qhs_crypto_cfg, &qhs_imem_cfg, + &qhs_ipa, &qhs_ipc_router, + &qhs_mss_cfg, &qhs_mvmss_cfg, + &qhs_pcie0_cfg, &qhs_pcie1_cfg, + &qhs_pcie2_cfg, &qhs_pcie_rscc, + &qhs_pdm, &qhs_prng, + &qhs_qdss_cfg, &qhs_qpic, + &qhs_qup0, &qhs_sdc1, + &qhs_sdc4, &qhs_spmi_vgi_coex, + &qhs_tcsr, &qhs_tlmm, + &qhs_usb3, &qhs_usb3_phy, + &qns_ddrss_cfg, &qns_system_noc_cfg, + &qns_system_noc_pcie_cfg, &qxs_imem, + &srvc_pcie_system_noc, &srvc_system_noc, + &xs_pcie_0, &xs_pcie_1, + &xs_pcie_2, &xs_qdss_stm, + &xs_sys_tcu_cfg }, +}; + +static struct qcom_icc_bcm bcm_mc0 = { + .name = "MC0", + .keepalive = true, + .num_nodes = 1, + .nodes = { &ebi }, +}; + +static struct qcom_icc_bcm bcm_qp0 = { + .name = "QP0", + .num_nodes = 1, + .nodes = { &qpic_core_slave }, +}; + +static struct qcom_icc_bcm bcm_qup0 = { + .name = "QUP0", + .keepalive = true, + .vote_scale = 1, + .num_nodes = 1, + .nodes = { &qup0_core_slave }, +}; + +static struct qcom_icc_bcm bcm_sh0 = { + .name = "SH0", + .keepalive = true, + .num_nodes = 1, + .nodes = { &qns_llcc }, +}; + +static struct qcom_icc_bcm bcm_sh1 = { + .name = "SH1", + .num_nodes = 10, + .nodes = { &alm_sys_tcu, &chm_apps, + &qnm_gemnoc_cfg, &qnm_mdsp, + &qnm_snoc_sf, &xm_gic, + &xm_ipa2pcie, &qns_gemnoc_cnoc, + &qns_pcie, &srvc_gemnoc }, +}; + +static struct qcom_icc_bcm bcm_sn0 = { + .name = "SN0", + .keepalive = true, + .num_nodes = 1, + .nodes = { &qns_gemnoc_sf }, +}; + +static struct qcom_icc_bcm bcm_sn1 = { + .name = "SN1", + .num_nodes = 21, + .nodes = { &xm_pcie3_0, &xm_pcie3_1, + &xm_pcie3_2, &qhm_audio, + &qhm_gic, &qhm_qdss_bam, + &qhm_qpic, &qhm_qup0, + &qnm_gemnoc_pcie, &qnm_system_noc_cfg, + &qnm_system_noc_pcie_cfg, &qxm_crypto, + &qxm_ipa, &qxm_mvmss, + &xm_emac_0, &xm_emac_1, + &xm_qdss_etr0, &xm_qdss_etr1, + &xm_sdc1, &xm_sdc4, + &xm_usb3 }, +}; + +static struct qcom_icc_bcm bcm_sn2 = { + .name = "SN2", + .num_nodes = 2, + .nodes = { &qnm_aggre_noc, &qns_a1noc }, +}; + +static struct qcom_icc_bcm bcm_sn4 = { + .name = "SN4", + .num_nodes = 2, + .nodes = { &qnm_pcie, &qns_pcie_gemnoc }, +}; + +static struct qcom_icc_bcm * const clk_virt_bcms[] = { + &bcm_qp0, + &bcm_qup0, +}; + +static struct qcom_icc_node * const clk_virt_nodes[] = { + [MASTER_QPIC_CORE] = &qpic_core_master, + [MASTER_QUP_CORE_0] = &qup0_core_master, + [SLAVE_QPIC_CORE] = &qpic_core_slave, + [SLAVE_QUP_CORE_0] = &qup0_core_slave, +}; + +static const struct qcom_icc_desc sdx75_clk_virt = { + .nodes = clk_virt_nodes, + .num_nodes = ARRAY_SIZE(clk_virt_nodes), + .bcms = clk_virt_bcms, + .num_bcms = ARRAY_SIZE(clk_virt_bcms), +}; + +static struct qcom_icc_node * const dc_noc_nodes[] = { + [MASTER_CNOC_DC_NOC] = &qnm_cnoc, + [SLAVE_LAGG_CFG] = &qhs_lagg, + [SLAVE_MCCC_MASTER] = &qhs_mccc_master, + [SLAVE_GEM_NOC_CFG] = &qns_gemnoc, + [SLAVE_SNOOP_BWMON] = &qss_snoop_bwmon, +}; + +static const struct qcom_icc_desc sdx75_dc_noc = { + .nodes = dc_noc_nodes, + .num_nodes = ARRAY_SIZE(dc_noc_nodes), +}; + +static struct qcom_icc_bcm * const gem_noc_bcms[] = { + &bcm_sh0, + &bcm_sh1, + &bcm_sn4, +}; + +static struct qcom_icc_node * const gem_noc_nodes[] = { + [MASTER_SYS_TCU] = &alm_sys_tcu, + [MASTER_APPSS_PROC] = &chm_apps, + [MASTER_GEM_NOC_CFG] = &qnm_gemnoc_cfg, + [MASTER_MSS_PROC] = &qnm_mdsp, + [MASTER_ANOC_PCIE_GEM_NOC] = &qnm_pcie, + [MASTER_SNOC_SF_MEM_NOC] = &qnm_snoc_sf, + [MASTER_GIC] = &xm_gic, + [MASTER_IPA_PCIE] = &xm_ipa2pcie, + [SLAVE_GEM_NOC_CNOC] = &qns_gemnoc_cnoc, + [SLAVE_LLCC] = &qns_llcc, + [SLAVE_MEM_NOC_PCIE_SNOC] = &qns_pcie, + [SLAVE_SERVICE_GEM_NOC] = &srvc_gemnoc, +}; + +static const struct qcom_icc_desc sdx75_gem_noc = { + .nodes = gem_noc_nodes, + .num_nodes = ARRAY_SIZE(gem_noc_nodes), + .bcms = gem_noc_bcms, + .num_bcms = ARRAY_SIZE(gem_noc_bcms), +}; + +static struct qcom_icc_bcm * const mc_virt_bcms[] = { + &bcm_mc0, +}; + +static struct qcom_icc_node * const mc_virt_nodes[] = { + [MASTER_LLCC] = &llcc_mc, + [SLAVE_EBI1] = &ebi, +}; + +static const struct qcom_icc_desc sdx75_mc_virt = { + .nodes = mc_virt_nodes, + .num_nodes = ARRAY_SIZE(mc_virt_nodes), + .bcms = mc_virt_bcms, + .num_bcms = ARRAY_SIZE(mc_virt_bcms), +}; + +static struct qcom_icc_bcm * const pcie_anoc_bcms[] = { + &bcm_sn1, + &bcm_sn4, +}; + +static struct qcom_icc_node * const pcie_anoc_nodes[] = { + [MASTER_PCIE_0] = &xm_pcie3_0, + [MASTER_PCIE_1] = &xm_pcie3_1, + [MASTER_PCIE_2] = &xm_pcie3_2, + [SLAVE_ANOC_PCIE_GEM_NOC] = &qns_pcie_gemnoc, +}; + +static const struct qcom_icc_desc sdx75_pcie_anoc = { + .nodes = pcie_anoc_nodes, + .num_nodes = ARRAY_SIZE(pcie_anoc_nodes), + .bcms = pcie_anoc_bcms, + .num_bcms = ARRAY_SIZE(pcie_anoc_bcms), +}; + +static struct qcom_icc_bcm * const system_noc_bcms[] = { + &bcm_ce0, + &bcm_cn0, + &bcm_sn0, + &bcm_sn1, + &bcm_sn2, +}; + +static struct qcom_icc_node * const system_noc_nodes[] = { + [MASTER_AUDIO] = &qhm_audio, + [MASTER_GIC_AHB] = &qhm_gic, + [MASTER_PCIE_RSCC] = &qhm_pcie_rscc, + [MASTER_QDSS_BAM] = &qhm_qdss_bam, + [MASTER_QPIC] = &qhm_qpic, + [MASTER_QUP_0] = &qhm_qup0, + [MASTER_ANOC_SNOC] = &qnm_aggre_noc, + [MASTER_GEM_NOC_CNOC] = &qnm_gemnoc_cnoc, + [MASTER_GEM_NOC_PCIE_SNOC] = &qnm_gemnoc_pcie, + [MASTER_SNOC_CFG] = &qnm_system_noc_cfg, + [MASTER_PCIE_ANOC_CFG] = &qnm_system_noc_pcie_cfg, + [MASTER_CRYPTO] = &qxm_crypto, + [MASTER_IPA] = &qxm_ipa, + [MASTER_MVMSS] = &qxm_mvmss, + [MASTER_EMAC_0] = &xm_emac_0, + [MASTER_EMAC_1] = &xm_emac_1, + [MASTER_QDSS_ETR] = &xm_qdss_etr0, + [MASTER_QDSS_ETR_1] = &xm_qdss_etr1, + [MASTER_SDCC_1] = &xm_sdc1, + [MASTER_SDCC_4] = &xm_sdc4, + [MASTER_USB3_0] = &xm_usb3, + [SLAVE_ETH0_CFG] = &ps_eth0_cfg, + [SLAVE_ETH1_CFG] = &ps_eth1_cfg, + [SLAVE_AUDIO] = &qhs_audio, + [SLAVE_CLK_CTL] = &qhs_clk_ctl, + [SLAVE_CRYPTO_0_CFG] = &qhs_crypto_cfg, + [SLAVE_IMEM_CFG] = &qhs_imem_cfg, + [SLAVE_IPA_CFG] = &qhs_ipa, + [SLAVE_IPC_ROUTER_CFG] = &qhs_ipc_router, + [SLAVE_CNOC_MSS] = &qhs_mss_cfg, + [SLAVE_ICBDI_MVMSS_CFG] = &qhs_mvmss_cfg, + [SLAVE_PCIE_0_CFG] = &qhs_pcie0_cfg, + [SLAVE_PCIE_1_CFG] = &qhs_pcie1_cfg, + [SLAVE_PCIE_2_CFG] = &qhs_pcie2_cfg, + [SLAVE_PCIE_RSC_CFG] = &qhs_pcie_rscc, + [SLAVE_PDM] = &qhs_pdm, + [SLAVE_PRNG] = &qhs_prng, + [SLAVE_QDSS_CFG] = &qhs_qdss_cfg, + [SLAVE_QPIC] = &qhs_qpic, + [SLAVE_QUP_0] = &qhs_qup0, + [SLAVE_SDCC_1] = &qhs_sdc1, + [SLAVE_SDCC_4] = &qhs_sdc4, + [SLAVE_SPMI_VGI_COEX] = &qhs_spmi_vgi_coex, + [SLAVE_TCSR] = &qhs_tcsr, + [SLAVE_TLMM] = &qhs_tlmm, + [SLAVE_USB3] = &qhs_usb3, + [SLAVE_USB3_PHY_CFG] = &qhs_usb3_phy, + [SLAVE_A1NOC_CFG] = &qns_a1noc, + [SLAVE_DDRSS_CFG] = &qns_ddrss_cfg, + [SLAVE_SNOC_GEM_NOC_SF] = &qns_gemnoc_sf, + [SLAVE_SNOC_CFG] = &qns_system_noc_cfg, + [SLAVE_PCIE_ANOC_CFG] = &qns_system_noc_pcie_cfg, + [SLAVE_IMEM] = &qxs_imem, + [SLAVE_SERVICE_PCIE_ANOC] = &srvc_pcie_system_noc, + [SLAVE_SERVICE_SNOC] = &srvc_system_noc, + [SLAVE_PCIE_0] = &xs_pcie_0, + [SLAVE_PCIE_1] = &xs_pcie_1, + [SLAVE_PCIE_2] = &xs_pcie_2, + [SLAVE_QDSS_STM] = &xs_qdss_stm, + [SLAVE_TCU] = &xs_sys_tcu_cfg, +}; + +static const struct qcom_icc_desc sdx75_system_noc = { + .nodes = system_noc_nodes, + .num_nodes = ARRAY_SIZE(system_noc_nodes), + .bcms = system_noc_bcms, + .num_bcms = ARRAY_SIZE(system_noc_bcms), +}; + +static const struct of_device_id qnoc_of_match[] = { + { .compatible = "qcom,sdx75-clk-virt", .data = &sdx75_clk_virt }, + { .compatible = "qcom,sdx75-dc-noc", .data = &sdx75_dc_noc }, + { .compatible = "qcom,sdx75-gem-noc", .data = &sdx75_gem_noc }, + { .compatible = "qcom,sdx75-mc-virt", .data = &sdx75_mc_virt }, + { .compatible = "qcom,sdx75-pcie-anoc", .data = &sdx75_pcie_anoc }, + { .compatible = "qcom,sdx75-system-noc", .data = &sdx75_system_noc }, + { } +}; +MODULE_DEVICE_TABLE(of, qnoc_of_match); + +static struct platform_driver qnoc_driver = { + .probe = qcom_icc_rpmh_probe, + .remove = qcom_icc_rpmh_remove, + .driver = { + .name = "qnoc-sdx75", + .of_match_table = qnoc_of_match, + .sync_state = icc_sync_state, + }, +}; + +static int __init qnoc_driver_init(void) +{ + return platform_driver_register(&qnoc_driver); +} +core_initcall(qnoc_driver_init); + +static void __exit qnoc_driver_exit(void) +{ + platform_driver_unregister(&qnoc_driver); +} +module_exit(qnoc_driver_exit); + +MODULE_DESCRIPTION("SDX75 NoC driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/interconnect/qcom/sdx75.h b/drivers/interconnect/qcom/sdx75.h new file mode 100644 index 000000000000..24e887159920 --- /dev/null +++ b/drivers/interconnect/qcom/sdx75.h @@ -0,0 +1,97 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2023, Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#ifndef __DRIVERS_INTERCONNECT_QCOM_SDX75_H +#define __DRIVERS_INTERCONNECT_QCOM_SDX75_H + +#define SDX75_MASTER_ANOC_PCIE_GEM_NOC 0 +#define SDX75_MASTER_ANOC_SNOC 1 +#define SDX75_MASTER_APPSS_PROC 2 +#define SDX75_MASTER_AUDIO 3 +#define SDX75_MASTER_CNOC_DC_NOC 4 +#define SDX75_MASTER_CRYPTO 5 +#define SDX75_MASTER_EMAC_0 6 +#define SDX75_MASTER_EMAC_1 7 +#define SDX75_MASTER_GEM_NOC_CFG 8 +#define SDX75_MASTER_GEM_NOC_CNOC 9 +#define SDX75_MASTER_GEM_NOC_PCIE_SNOC 10 +#define SDX75_MASTER_GIC 11 +#define SDX75_MASTER_GIC_AHB 12 +#define SDX75_MASTER_IPA 13 +#define SDX75_MASTER_IPA_PCIE 14 +#define SDX75_MASTER_LLCC 15 +#define SDX75_MASTER_MSS_PROC 16 +#define SDX75_MASTER_MVMSS 17 +#define SDX75_MASTER_PCIE_0 18 +#define SDX75_MASTER_PCIE_1 19 +#define SDX75_MASTER_PCIE_2 20 +#define SDX75_MASTER_PCIE_ANOC_CFG 21 +#define SDX75_MASTER_PCIE_RSCC 22 +#define SDX75_MASTER_QDSS_BAM 23 +#define SDX75_MASTER_QDSS_ETR 24 +#define SDX75_MASTER_QDSS_ETR_1 25 +#define SDX75_MASTER_QPIC 26 +#define SDX75_MASTER_QPIC_CORE 27 +#define SDX75_MASTER_QUP_0 28 +#define SDX75_MASTER_QUP_CORE_0 29 +#define SDX75_MASTER_SDCC_1 30 +#define SDX75_MASTER_SDCC_4 31 +#define SDX75_MASTER_SNOC_CFG 32 +#define SDX75_MASTER_SNOC_SF_MEM_NOC 33 +#define SDX75_MASTER_SYS_TCU 34 +#define SDX75_MASTER_USB3_0 35 +#define SDX75_SLAVE_A1NOC_CFG 36 +#define SDX75_SLAVE_ANOC_PCIE_GEM_NOC 37 +#define SDX75_SLAVE_AUDIO 38 +#define SDX75_SLAVE_CLK_CTL 39 +#define SDX75_SLAVE_CRYPTO_0_CFG 40 +#define SDX75_SLAVE_CNOC_MSS 41 +#define SDX75_SLAVE_DDRSS_CFG 42 +#define SDX75_SLAVE_EBI1 43 +#define SDX75_SLAVE_ETH0_CFG 44 +#define SDX75_SLAVE_ETH1_CFG 45 +#define SDX75_SLAVE_GEM_NOC_CFG 46 +#define SDX75_SLAVE_GEM_NOC_CNOC 47 +#define SDX75_SLAVE_ICBDI_MVMSS_CFG 48 +#define SDX75_SLAVE_IMEM 49 +#define SDX75_SLAVE_IMEM_CFG 50 +#define SDX75_SLAVE_IPA_CFG 51 +#define SDX75_SLAVE_IPC_ROUTER_CFG 52 +#define SDX75_SLAVE_LAGG_CFG 53 +#define SDX75_SLAVE_LLCC 54 +#define SDX75_SLAVE_MCCC_MASTER 55 +#define SDX75_SLAVE_MEM_NOC_PCIE_SNOC 56 +#define SDX75_SLAVE_PCIE_0 57 +#define SDX75_SLAVE_PCIE_1 58 +#define SDX75_SLAVE_PCIE_2 59 +#define SDX75_SLAVE_PCIE_0_CFG 60 +#define SDX75_SLAVE_PCIE_1_CFG 61 +#define SDX75_SLAVE_PCIE_2_CFG 62 +#define SDX75_SLAVE_PCIE_ANOC_CFG 63 +#define SDX75_SLAVE_PCIE_RSC_CFG 64 +#define SDX75_SLAVE_PDM 65 +#define SDX75_SLAVE_PRNG 66 +#define SDX75_SLAVE_QDSS_CFG 67 +#define SDX75_SLAVE_QDSS_STM 68 +#define SDX75_SLAVE_QPIC 69 +#define SDX75_SLAVE_QPIC_CORE 70 +#define SDX75_SLAVE_QUP_0 71 +#define SDX75_SLAVE_QUP_CORE_0 72 +#define SDX75_SLAVE_SDCC_1 73 +#define SDX75_SLAVE_SDCC_4 74 +#define SDX75_SLAVE_SERVICE_GEM_NOC 75 +#define SDX75_SLAVE_SERVICE_PCIE_ANOC 76 +#define SDX75_SLAVE_SERVICE_SNOC 77 +#define SDX75_SLAVE_SNOC_CFG 78 +#define SDX75_SLAVE_SNOC_GEM_NOC_SF 79 +#define SDX75_SLAVE_SNOOP_BWMON 80 +#define SDX75_SLAVE_SPMI_VGI_COEX 81 +#define SDX75_SLAVE_TCSR 82 +#define SDX75_SLAVE_TCU 83 +#define SDX75_SLAVE_TLMM 84 +#define SDX75_SLAVE_USB3 85 +#define SDX75_SLAVE_USB3_PHY_CFG 86 + +#endif From 80f5fef01beeda54ec9c1f9049d331e480be80e8 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Wed, 20 Sep 2023 18:34:32 +0300 Subject: [PATCH 230/326] interconnect: imx: Replace custom implementation of COUNT_ARGS() Replace custom and non-portable implementation of COUNT_ARGS(). Fixes: f0d8048525d7 ("interconnect: Add imx core driver") Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20230920153432.2067664-1-andriy.shevchenko@linux.intel.com Signed-off-by: Georgi Djakov --- drivers/interconnect/imx/imx.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/interconnect/imx/imx.h b/drivers/interconnect/imx/imx.h index 895907cdcb3b..4ec9bc5f383e 100644 --- a/drivers/interconnect/imx/imx.h +++ b/drivers/interconnect/imx/imx.h @@ -10,6 +10,7 @@ #ifndef __DRIVERS_INTERCONNECT_IMX_H #define __DRIVERS_INTERCONNECT_IMX_H +#include #include #include @@ -89,7 +90,7 @@ struct imx_icc_noc_setting { .id = _id, \ .name = _name, \ .adj = _adj, \ - .num_links = ARRAY_SIZE(((int[]){ __VA_ARGS__ })), \ + .num_links = COUNT_ARGS(__VA_ARGS__), \ .links = { __VA_ARGS__ }, \ } From e753741421965e5033c5bf6264fc8370ad01a400 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Wed, 20 Sep 2023 18:41:31 +0300 Subject: [PATCH 231/326] interconnect: msm8974: Replace custom implementation of COUNT_ARGS() Replace custom and non-portable implementation of COUNT_ARGS(). Fixes: 4e60a9568dc6 ("interconnect: qcom: add msm8974 driver") Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20230920154131.2071112-1-andriy.shevchenko@linux.intel.com Signed-off-by: Georgi Djakov --- drivers/interconnect/qcom/msm8974.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/interconnect/qcom/msm8974.c b/drivers/interconnect/qcom/msm8974.c index 885ca9d6d4ed..21f6c852141e 100644 --- a/drivers/interconnect/qcom/msm8974.c +++ b/drivers/interconnect/qcom/msm8974.c @@ -28,6 +28,8 @@ */ #include + +#include #include #include #include @@ -231,7 +233,7 @@ struct msm8974_icc_desc { .buswidth = _buswidth, \ .mas_rpm_id = _mas_rpm_id, \ .slv_rpm_id = _slv_rpm_id, \ - .num_links = ARRAY_SIZE(((int[]){ __VA_ARGS__ })), \ + .num_links = COUNT_ARGS(__VA_ARGS__), \ .links = { __VA_ARGS__ }, \ } From 577a3c5af1fe87b65931ea94d5515266da301f56 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Wed, 20 Sep 2023 18:49:27 +0300 Subject: [PATCH 232/326] interconnect: qcom: osm-l3: Replace custom implementation of COUNT_ARGS() Replace custom and non-portable implementation of COUNT_ARGS(). Fixes: 5bc9900addaf ("interconnect: qcom: Add OSM L3 interconnect provider support") Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20230920154927.2090732-1-andriy.shevchenko@linux.intel.com Signed-off-by: Georgi Djakov --- drivers/interconnect/qcom/osm-l3.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/interconnect/qcom/osm-l3.c b/drivers/interconnect/qcom/osm-l3.c index dc321bb86d0b..e97478bbc282 100644 --- a/drivers/interconnect/qcom/osm-l3.c +++ b/drivers/interconnect/qcom/osm-l3.c @@ -3,6 +3,7 @@ * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved. */ +#include #include #include #include @@ -78,7 +79,7 @@ enum { .name = #_name, \ .id = _id, \ .buswidth = _buswidth, \ - .num_links = ARRAY_SIZE(((int[]){ __VA_ARGS__ })), \ + .num_links = COUNT_ARGS(__VA_ARGS__), \ .links = { __VA_ARGS__ }, \ } From 273f74a2e7d15a5c216a4a26b84b1563c7092c9d Mon Sep 17 00:00:00 2001 From: Yang Yingliang Date: Thu, 3 Aug 2023 21:05:21 +0800 Subject: [PATCH 233/326] interconnect: fix error handling in qnoc_probe() Add missing clk_disable_unprepare() and clk_bulk_disable_unprepare() in the error path in qnoc_probe(). And when qcom_icc_qos_set() fails, it needs remove nodes and disable clks. Fixes: 2e2113c8a64f ("interconnect: qcom: rpm: Handle interface clocks") Signed-off-by: Yang Yingliang Link: https://lore.kernel.org/r/20230803130521.959487-1-yangyingliang@huawei.com Signed-off-by: Georgi Djakov --- drivers/interconnect/qcom/icc-rpm.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/drivers/interconnect/qcom/icc-rpm.c b/drivers/interconnect/qcom/icc-rpm.c index 2c16917ba1fd..e76356f91125 100644 --- a/drivers/interconnect/qcom/icc-rpm.c +++ b/drivers/interconnect/qcom/icc-rpm.c @@ -497,7 +497,7 @@ regmap_done: ret = devm_clk_bulk_get(dev, qp->num_intf_clks, qp->intf_clks); if (ret) - return ret; + goto err_disable_unprepare_clk; provider = &qp->provider; provider->dev = dev; @@ -512,13 +512,15 @@ regmap_done: /* If this fails, bus accesses will crash the platform! */ ret = clk_bulk_prepare_enable(qp->num_intf_clks, qp->intf_clks); if (ret) - return ret; + goto err_disable_unprepare_clk; for (i = 0; i < num_nodes; i++) { size_t j; node = icc_node_create(qnodes[i]->id); if (IS_ERR(node)) { + clk_bulk_disable_unprepare(qp->num_intf_clks, + qp->intf_clks); ret = PTR_ERR(node); goto err_remove_nodes; } @@ -534,8 +536,11 @@ regmap_done: if (qnodes[i]->qos.ap_owned && qnodes[i]->qos.qos_mode != NOC_QOS_MODE_INVALID) { ret = qcom_icc_qos_set(node); - if (ret) - return ret; + if (ret) { + clk_bulk_disable_unprepare(qp->num_intf_clks, + qp->intf_clks); + goto err_remove_nodes; + } } data->nodes[i] = node; @@ -563,6 +568,7 @@ err_deregister_provider: icc_provider_deregister(provider); err_remove_nodes: icc_nodes_remove(provider); +err_disable_unprepare_clk: clk_disable_unprepare(qp->bus_clk); return ret; From 6548ecdfc16327aafeaa1f1d97f63c79995a56cb Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Wed, 20 Sep 2023 18:36:45 +0300 Subject: [PATCH 234/326] interconnect: imx: Replace inclusion of kernel.h in the header The kernel.h is not used here directly, replace it with proper set of headers. Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20230920153645.2068193-1-andriy.shevchenko@linux.intel.com Signed-off-by: Georgi Djakov --- drivers/interconnect/imx/imx.h | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/interconnect/imx/imx.h b/drivers/interconnect/imx/imx.h index 4ec9bc5f383e..d4d0e9888655 100644 --- a/drivers/interconnect/imx/imx.h +++ b/drivers/interconnect/imx/imx.h @@ -11,8 +11,12 @@ #define __DRIVERS_INTERCONNECT_IMX_H #include +#include +#include + #include -#include + +struct platform_device; #define IMX_ICC_MAX_LINKS 4 From 4d8784d84e17529f0f0774d3a946fd07057cd9a4 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Sun, 27 Aug 2023 13:40:26 +0200 Subject: [PATCH 235/326] dt-bindings: interconnect: qcom,rpmh: do not require reg on SDX65 MC virt The MC virt interconnect in SDX65 DTSI does not have reg. Similarly in the downstream DTS, thus assume this is an interconnect without own dedicated IO address space. This fixes dtbs_check warnings like: qcom-sdx65-mtp.dtb: interconnect-mc-virt: 'reg' is a required property Signed-off-by: Krzysztof Kozlowski Acked-by: Rob Herring Link: https://lore.kernel.org/r/20230827114026.47806-1-krzysztof.kozlowski@linaro.org Signed-off-by: Georgi Djakov --- Documentation/devicetree/bindings/interconnect/qcom,rpmh.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/interconnect/qcom,rpmh.yaml b/Documentation/devicetree/bindings/interconnect/qcom,rpmh.yaml index a46497af1fd8..74ab080249ff 100644 --- a/Documentation/devicetree/bindings/interconnect/qcom,rpmh.yaml +++ b/Documentation/devicetree/bindings/interconnect/qcom,rpmh.yaml @@ -113,6 +113,7 @@ allOf: properties: compatible: enum: + - qcom,sdx65-mc-virt - qcom,sm8250-qup-virt then: required: From 4d7c16d08d248952c116f2eb9b7b5abc43a19688 Mon Sep 17 00:00:00 2001 From: Luca Ceresoli Date: Wed, 4 Oct 2023 18:39:28 +0200 Subject: [PATCH 236/326] iio: accel: mxc4005: allow module autoloading via OF compatible Add OF device table with compatible strings to allow automatic module loading. Signed-off-by: Luca Ceresoli Reviewed-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20231004-mxc4005-device-tree-support-v1-2-e7c0faea72e4@bootlin.com Signed-off-by: Jonathan Cameron --- drivers/iio/accel/mxc4005.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/iio/accel/mxc4005.c b/drivers/iio/accel/mxc4005.c index 75d142bc14b4..82e8d0b39049 100644 --- a/drivers/iio/accel/mxc4005.c +++ b/drivers/iio/accel/mxc4005.c @@ -476,6 +476,13 @@ static const struct acpi_device_id mxc4005_acpi_match[] = { }; MODULE_DEVICE_TABLE(acpi, mxc4005_acpi_match); +static const struct of_device_id mxc4005_of_match[] = { + { .compatible = "memsic,mxc4005", }, + { .compatible = "memsic,mxc6655", }, + { }, +}; +MODULE_DEVICE_TABLE(of, mxc4005_of_match); + static const struct i2c_device_id mxc4005_id[] = { {"mxc4005", 0}, {"mxc6655", 0}, @@ -487,6 +494,7 @@ static struct i2c_driver mxc4005_driver = { .driver = { .name = MXC4005_DRV_NAME, .acpi_match_table = ACPI_PTR(mxc4005_acpi_match), + .of_match_table = mxc4005_of_match, }, .probe = mxc4005_probe, .id_table = mxc4005_id, From fca63709310267d942fa4991e65636ab42d51ed3 Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Tue, 10 Oct 2023 09:46:00 +0100 Subject: [PATCH 237/326] Revert "dt-bindings: iio: magnetometer: asahi-kasei,ak8975: Drop deprecated enums" Reverted as Rob Herring is tracking undocumented compatibles and as per discussion in the thread, we can not remove this deprecated compatibles from the driver without potential/likely regressions. So keep it around as it's not that painful anyway. This reverts commit 711fb79a1ea8e79dc600f25d9f8c1ac25870b4de. Signed-off-by: Jonathan Cameron --- .../bindings/iio/magnetometer/asahi-kasei,ak8975.yaml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/Documentation/devicetree/bindings/iio/magnetometer/asahi-kasei,ak8975.yaml b/Documentation/devicetree/bindings/iio/magnetometer/asahi-kasei,ak8975.yaml index ee77558e9800..9790f75fc669 100644 --- a/Documentation/devicetree/bindings/iio/magnetometer/asahi-kasei,ak8975.yaml +++ b/Documentation/devicetree/bindings/iio/magnetometer/asahi-kasei,ak8975.yaml @@ -18,6 +18,13 @@ properties: - asahi-kasei,ak09911 - asahi-kasei,ak09912 - asahi-kasei,ak09916 + - enum: + - ak8975 + - ak8963 + - ak09911 + - ak09912 + - ak09916 + deprecated: true reg: maxItems: 1 From 564cfb28409a265f272f0e7c73ce211827b36204 Mon Sep 17 00:00:00 2001 From: Alisa-Dariana Roman Date: Tue, 10 Oct 2023 15:49:24 +0300 Subject: [PATCH 238/326] iio: adc: ad7192: Organize chip info Move all chip specific data into chip_info structure. Signed-off-by: Alisa-Dariana Roman Link: https://lore.kernel.org/r/20231010124927.143343-2-alisadariana@gmail.com Signed-off-by: Jonathan Cameron --- drivers/iio/adc/ad7192.c | 45 ++++++++++++++++------------------------ 1 file changed, 18 insertions(+), 27 deletions(-) diff --git a/drivers/iio/adc/ad7192.c b/drivers/iio/adc/ad7192.c index e0be394ccb34..d72a190c5109 100644 --- a/drivers/iio/adc/ad7192.c +++ b/drivers/iio/adc/ad7192.c @@ -171,6 +171,9 @@ enum { struct ad7192_chip_info { unsigned int chip_id; const char *name; + const struct iio_chan_spec *channels; + u8 num_channels; + const struct iio_info *info; }; struct ad7192_state { @@ -964,39 +967,33 @@ static const struct ad7192_chip_info ad7192_chip_info_tbl[] = { [ID_AD7190] = { .chip_id = CHIPID_AD7190, .name = "ad7190", + .channels = ad7192_channels, + .num_channels = ARRAY_SIZE(ad7192_channels), + .info = &ad7192_info, }, [ID_AD7192] = { .chip_id = CHIPID_AD7192, .name = "ad7192", + .channels = ad7192_channels, + .num_channels = ARRAY_SIZE(ad7192_channels), + .info = &ad7192_info, }, [ID_AD7193] = { .chip_id = CHIPID_AD7193, .name = "ad7193", + .channels = ad7193_channels, + .num_channels = ARRAY_SIZE(ad7193_channels), + .info = &ad7192_info, }, [ID_AD7195] = { .chip_id = CHIPID_AD7195, .name = "ad7195", + .channels = ad7192_channels, + .num_channels = ARRAY_SIZE(ad7192_channels), + .info = &ad7195_info, }, }; -static int ad7192_channels_config(struct iio_dev *indio_dev) -{ - struct ad7192_state *st = iio_priv(indio_dev); - - switch (st->chip_info->chip_id) { - case CHIPID_AD7193: - indio_dev->channels = ad7193_channels; - indio_dev->num_channels = ARRAY_SIZE(ad7193_channels); - break; - default: - indio_dev->channels = ad7192_channels; - indio_dev->num_channels = ARRAY_SIZE(ad7192_channels); - break; - } - - return 0; -} - static void ad7192_reg_disable(void *reg) { regulator_disable(reg); @@ -1051,15 +1048,9 @@ static int ad7192_probe(struct spi_device *spi) st->chip_info = (void *)spi_get_device_id(spi)->driver_data; indio_dev->name = st->chip_info->name; indio_dev->modes = INDIO_DIRECT_MODE; - - ret = ad7192_channels_config(indio_dev); - if (ret < 0) - return ret; - - if (st->chip_info->chip_id == CHIPID_AD7195) - indio_dev->info = &ad7195_info; - else - indio_dev->info = &ad7192_info; + indio_dev->channels = st->chip_info->channels; + indio_dev->num_channels = st->chip_info->num_channels; + indio_dev->info = st->chip_info->info; ret = ad_sd_init(&st->sd, indio_dev, spi, &ad7192_sigma_delta_info); if (ret) From 15f3b48799f7ebcc49b22211f0fcb58a16874474 Mon Sep 17 00:00:00 2001 From: Alisa-Dariana Roman Date: Tue, 10 Oct 2023 15:49:25 +0300 Subject: [PATCH 239/326] iio: adc: ad7192: Remove unused member Remove extend_name from channel macro since it is not used anywhere. Signed-off-by: Alisa-Dariana Roman Link: https://lore.kernel.org/r/20231010124927.143343-3-alisadariana@gmail.com Signed-off-by: Jonathan Cameron --- drivers/iio/adc/ad7192.c | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/drivers/iio/adc/ad7192.c b/drivers/iio/adc/ad7192.c index d72a190c5109..fe47ef43b3d7 100644 --- a/drivers/iio/adc/ad7192.c +++ b/drivers/iio/adc/ad7192.c @@ -895,8 +895,8 @@ static const struct iio_info ad7195_info = { .update_scan_mode = ad7192_update_scan_mode, }; -#define __AD719x_CHANNEL(_si, _channel1, _channel2, _address, _extend_name, \ - _type, _mask_type_av, _ext_info) \ +#define __AD719x_CHANNEL(_si, _channel1, _channel2, _address, _type, \ + _mask_type_av, _ext_info) \ { \ .type = (_type), \ .differential = ((_channel2) == -1 ? 0 : 1), \ @@ -904,7 +904,6 @@ static const struct iio_info ad7195_info = { .channel = (_channel1), \ .channel2 = (_channel2), \ .address = (_address), \ - .extend_name = (_extend_name), \ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \ BIT(IIO_CHAN_INFO_OFFSET), \ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \ @@ -922,16 +921,15 @@ static const struct iio_info ad7195_info = { } #define AD719x_DIFF_CHANNEL(_si, _channel1, _channel2, _address) \ - __AD719x_CHANNEL(_si, _channel1, _channel2, _address, NULL, \ - IIO_VOLTAGE, BIT(IIO_CHAN_INFO_SCALE), \ - ad7192_calibsys_ext_info) + __AD719x_CHANNEL(_si, _channel1, _channel2, _address, IIO_VOLTAGE, \ + BIT(IIO_CHAN_INFO_SCALE), ad7192_calibsys_ext_info) #define AD719x_CHANNEL(_si, _channel1, _address) \ - __AD719x_CHANNEL(_si, _channel1, -1, _address, NULL, IIO_VOLTAGE, \ + __AD719x_CHANNEL(_si, _channel1, -1, _address, IIO_VOLTAGE, \ BIT(IIO_CHAN_INFO_SCALE), ad7192_calibsys_ext_info) #define AD719x_TEMP_CHANNEL(_si, _address) \ - __AD719x_CHANNEL(_si, 0, -1, _address, NULL, IIO_TEMP, 0, NULL) + __AD719x_CHANNEL(_si, 0, -1, _address, IIO_TEMP, 0, NULL) static const struct iio_chan_spec ad7192_channels[] = { AD719x_DIFF_CHANNEL(0, 1, 2, AD7192_CH_AIN1P_AIN2M), From db7fe1f610b39b398076f6c3fcb33378c4cb58ef Mon Sep 17 00:00:00 2001 From: Alisa-Dariana Roman Date: Tue, 10 Oct 2023 15:49:26 +0300 Subject: [PATCH 240/326] iio: adc: ad7192: Add fast settling support Add fast settling mode support for AD7193. Add two new device specific attributes: oversampling_ratio and oversampling_ratio_available. For AD7193 the user can set the average factor by writing to oversampling_ratio. The possible values are exposed when reading oversampling_ratio_available. Signed-off-by: Alisa-Dariana Roman Link: https://lore.kernel.org/r/20231010124927.143343-4-alisadariana@gmail.com Signed-off-by: Jonathan Cameron --- drivers/iio/adc/ad7192.c | 109 +++++++++++++++++++++++++++++---------- 1 file changed, 82 insertions(+), 27 deletions(-) diff --git a/drivers/iio/adc/ad7192.c b/drivers/iio/adc/ad7192.c index fe47ef43b3d7..954093ee0fbd 100644 --- a/drivers/iio/adc/ad7192.c +++ b/drivers/iio/adc/ad7192.c @@ -60,6 +60,8 @@ #define AD7192_MODE_SEL_MASK GENMASK(23, 21) /* Operation Mode Select Mask */ #define AD7192_MODE_STA_MASK BIT(20) /* Status Register transmission Mask */ #define AD7192_MODE_CLKSRC_MASK GENMASK(19, 18) /* Clock Source Select Mask */ +#define AD7192_MODE_AVG_MASK GENMASK(17, 16) + /* Fast Settling Filter Average Select Mask (AD7193 only) */ #define AD7192_MODE_SINC3 BIT(15) /* SINC3 Filter Select */ #define AD7192_MODE_ENPAR BIT(13) /* Parity Enable */ #define AD7192_MODE_CLKDIV BIT(12) /* Clock divide by 2 (AD7190/2 only)*/ @@ -185,6 +187,7 @@ struct ad7192_state { u32 mode; u32 conf; u32 scale_avail[8][2]; + u32 oversampling_ratio_avail[4]; u8 gpocon; u8 clock_sel; struct mutex lock; /* protect sensor state */ @@ -462,6 +465,11 @@ static int ad7192_setup(struct iio_dev *indio_dev, struct device_node *np) st->scale_avail[i][0] = scale_uv; } + st->oversampling_ratio_avail[0] = 1; + st->oversampling_ratio_avail[1] = 2; + st->oversampling_ratio_avail[2] = 8; + st->oversampling_ratio_avail[3] = 16; + return 0; } @@ -531,15 +539,21 @@ static ssize_t ad7192_set(struct device *dev, return ret ? ret : len; } -static int ad7192_compute_f_order(bool sinc3_en, bool chop_en) +static int ad7192_compute_f_order(struct ad7192_state *st, bool sinc3_en, bool chop_en) { - if (!chop_en) + u8 avg_factor_selected, oversampling_ratio; + + avg_factor_selected = FIELD_GET(AD7192_MODE_AVG_MASK, st->mode); + + if (!avg_factor_selected && !chop_en) return 1; - if (sinc3_en) - return AD7192_SYNC3_FILTER; + oversampling_ratio = st->oversampling_ratio_avail[avg_factor_selected]; - return AD7192_SYNC4_FILTER; + if (sinc3_en) + return AD7192_SYNC3_FILTER + oversampling_ratio - 1; + + return AD7192_SYNC4_FILTER + oversampling_ratio - 1; } static int ad7192_get_f_order(struct ad7192_state *st) @@ -549,13 +563,13 @@ static int ad7192_get_f_order(struct ad7192_state *st) sinc3_en = FIELD_GET(AD7192_MODE_SINC3, st->mode); chop_en = FIELD_GET(AD7192_CONF_CHOP, st->conf); - return ad7192_compute_f_order(sinc3_en, chop_en); + return ad7192_compute_f_order(st, sinc3_en, chop_en); } static int ad7192_compute_f_adc(struct ad7192_state *st, bool sinc3_en, bool chop_en) { - unsigned int f_order = ad7192_compute_f_order(sinc3_en, chop_en); + unsigned int f_order = ad7192_compute_f_order(st, sinc3_en, chop_en); return DIV_ROUND_CLOSEST(st->fclk, f_order * FIELD_GET(AD7192_MODE_RATE_MASK, st->mode)); @@ -753,6 +767,9 @@ static int ad7192_read_raw(struct iio_dev *indio_dev, *val = ad7192_get_3db_filter_freq(st); *val2 = 1000; return IIO_VAL_FRACTIONAL; + case IIO_CHAN_INFO_OVERSAMPLING_RATIO: + *val = st->oversampling_ratio_avail[FIELD_GET(AD7192_MODE_AVG_MASK, st->mode)]; + return IIO_VAL_INT; } return -EINVAL; @@ -810,6 +827,23 @@ static int ad7192_write_raw(struct iio_dev *indio_dev, case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY: ret = ad7192_set_3db_filter_freq(st, val, val2 / 1000); break; + case IIO_CHAN_INFO_OVERSAMPLING_RATIO: + ret = -EINVAL; + mutex_lock(&st->lock); + for (i = 0; i < ARRAY_SIZE(st->oversampling_ratio_avail); i++) + if (val == st->oversampling_ratio_avail[i]) { + ret = 0; + tmp = st->mode; + st->mode &= ~AD7192_MODE_AVG_MASK; + st->mode |= FIELD_PREP(AD7192_MODE_AVG_MASK, i); + if (tmp == st->mode) + break; + ad_sd_write_reg(&st->sd, AD7192_REG_MODE, + 3, st->mode); + break; + } + mutex_unlock(&st->lock); + break; default: ret = -EINVAL; } @@ -830,6 +864,8 @@ static int ad7192_write_raw_get_fmt(struct iio_dev *indio_dev, return IIO_VAL_INT; case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY: return IIO_VAL_INT_PLUS_MICRO; + case IIO_CHAN_INFO_OVERSAMPLING_RATIO: + return IIO_VAL_INT; default: return -EINVAL; } @@ -849,6 +885,12 @@ static int ad7192_read_avail(struct iio_dev *indio_dev, /* Values are stored in a 2D matrix */ *length = ARRAY_SIZE(st->scale_avail) * 2; + return IIO_AVAIL_LIST; + case IIO_CHAN_INFO_OVERSAMPLING_RATIO: + *vals = (int *)st->oversampling_ratio_avail; + *type = IIO_VAL_INT; + *length = ARRAY_SIZE(st->oversampling_ratio_avail); + return IIO_AVAIL_LIST; } @@ -896,7 +938,7 @@ static const struct iio_info ad7195_info = { }; #define __AD719x_CHANNEL(_si, _channel1, _channel2, _address, _type, \ - _mask_type_av, _ext_info) \ + _mask_all, _mask_type_av, _mask_all_av, _ext_info) \ { \ .type = (_type), \ .differential = ((_channel2) == -1 ? 0 : 1), \ @@ -908,8 +950,10 @@ static const struct iio_info ad7195_info = { BIT(IIO_CHAN_INFO_OFFSET), \ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \ .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ) | \ - BIT(IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY), \ + BIT(IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY) | \ + (_mask_all), \ .info_mask_shared_by_type_available = (_mask_type_av), \ + .info_mask_shared_by_all_available = (_mask_all_av), \ .ext_info = (_ext_info), \ .scan_index = (_si), \ .scan_type = { \ @@ -921,15 +965,26 @@ static const struct iio_info ad7195_info = { } #define AD719x_DIFF_CHANNEL(_si, _channel1, _channel2, _address) \ - __AD719x_CHANNEL(_si, _channel1, _channel2, _address, IIO_VOLTAGE, \ - BIT(IIO_CHAN_INFO_SCALE), ad7192_calibsys_ext_info) + __AD719x_CHANNEL(_si, _channel1, _channel2, _address, IIO_VOLTAGE, 0, \ + BIT(IIO_CHAN_INFO_SCALE), 0, ad7192_calibsys_ext_info) #define AD719x_CHANNEL(_si, _channel1, _address) \ - __AD719x_CHANNEL(_si, _channel1, -1, _address, IIO_VOLTAGE, \ - BIT(IIO_CHAN_INFO_SCALE), ad7192_calibsys_ext_info) + __AD719x_CHANNEL(_si, _channel1, -1, _address, IIO_VOLTAGE, 0, \ + BIT(IIO_CHAN_INFO_SCALE), 0, ad7192_calibsys_ext_info) #define AD719x_TEMP_CHANNEL(_si, _address) \ - __AD719x_CHANNEL(_si, 0, -1, _address, IIO_TEMP, 0, NULL) + __AD719x_CHANNEL(_si, 0, -1, _address, IIO_TEMP, 0, 0, 0, NULL) + +#define AD7193_DIFF_CHANNEL(_si, _channel1, _channel2, _address) \ + __AD719x_CHANNEL(_si, _channel1, _channel2, _address, \ + IIO_VOLTAGE, \ + BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), \ + BIT(IIO_CHAN_INFO_SCALE), \ + BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), \ + ad7192_calibsys_ext_info) + +#define AD7193_CHANNEL(_si, _channel1, _address) \ + AD7193_DIFF_CHANNEL(_si, _channel1, -1, _address) static const struct iio_chan_spec ad7192_channels[] = { AD719x_DIFF_CHANNEL(0, 1, 2, AD7192_CH_AIN1P_AIN2M), @@ -944,20 +999,20 @@ static const struct iio_chan_spec ad7192_channels[] = { }; static const struct iio_chan_spec ad7193_channels[] = { - AD719x_DIFF_CHANNEL(0, 1, 2, AD7193_CH_AIN1P_AIN2M), - AD719x_DIFF_CHANNEL(1, 3, 4, AD7193_CH_AIN3P_AIN4M), - AD719x_DIFF_CHANNEL(2, 5, 6, AD7193_CH_AIN5P_AIN6M), - AD719x_DIFF_CHANNEL(3, 7, 8, AD7193_CH_AIN7P_AIN8M), + AD7193_DIFF_CHANNEL(0, 1, 2, AD7193_CH_AIN1P_AIN2M), + AD7193_DIFF_CHANNEL(1, 3, 4, AD7193_CH_AIN3P_AIN4M), + AD7193_DIFF_CHANNEL(2, 5, 6, AD7193_CH_AIN5P_AIN6M), + AD7193_DIFF_CHANNEL(3, 7, 8, AD7193_CH_AIN7P_AIN8M), AD719x_TEMP_CHANNEL(4, AD7193_CH_TEMP), - AD719x_DIFF_CHANNEL(5, 2, 2, AD7193_CH_AIN2P_AIN2M), - AD719x_CHANNEL(6, 1, AD7193_CH_AIN1), - AD719x_CHANNEL(7, 2, AD7193_CH_AIN2), - AD719x_CHANNEL(8, 3, AD7193_CH_AIN3), - AD719x_CHANNEL(9, 4, AD7193_CH_AIN4), - AD719x_CHANNEL(10, 5, AD7193_CH_AIN5), - AD719x_CHANNEL(11, 6, AD7193_CH_AIN6), - AD719x_CHANNEL(12, 7, AD7193_CH_AIN7), - AD719x_CHANNEL(13, 8, AD7193_CH_AIN8), + AD7193_DIFF_CHANNEL(5, 2, 2, AD7193_CH_AIN2P_AIN2M), + AD7193_CHANNEL(6, 1, AD7193_CH_AIN1), + AD7193_CHANNEL(7, 2, AD7193_CH_AIN2), + AD7193_CHANNEL(8, 3, AD7193_CH_AIN3), + AD7193_CHANNEL(9, 4, AD7193_CH_AIN4), + AD7193_CHANNEL(10, 5, AD7193_CH_AIN5), + AD7193_CHANNEL(11, 6, AD7193_CH_AIN6), + AD7193_CHANNEL(12, 7, AD7193_CH_AIN7), + AD7193_CHANNEL(13, 8, AD7193_CH_AIN8), IIO_CHAN_SOFT_TIMESTAMP(14), }; From 6eb14ffa1873d756b9141837720ff70f07d849f1 Mon Sep 17 00:00:00 2001 From: AngeloGioacchino Del Regno Date: Tue, 10 Oct 2023 14:19:40 +0200 Subject: [PATCH 241/326] iio: adc: mt6577_auxadc: Fix kernel panic on suspend Commit a2d518fbe376 ("iio: adc: mt6577_auxadc: Simplify with device managed function") simplified the driver with devm hooks, but wrongly states that the platform_set_drvdata(), platform_get_drvdata() are unused after the simplification: the driver data is infact used in .suspend() and .resume() PM callbacks, currently producing a kernel panic. Reintroduce the call to platform_set_drvdata() in the probe function Fixes: a2d518fbe376 ("iio: adc: mt6577_auxadc: Simplify with device managed function") Signed-off-by: AngeloGioacchino Del Regno Reviewed-by: Markus Schneider-Pargmann Reviewed-by: Alexandre Mergnat Link: https://lore.kernel.org/r/20231010121940.159696-1-angelogioacchino.delregno@collabora.com Signed-off-by: Jonathan Cameron --- drivers/iio/adc/mt6577_auxadc.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/iio/adc/mt6577_auxadc.c b/drivers/iio/adc/mt6577_auxadc.c index 370b84c2d0ba..3343b54e8e44 100644 --- a/drivers/iio/adc/mt6577_auxadc.c +++ b/drivers/iio/adc/mt6577_auxadc.c @@ -293,6 +293,7 @@ static int mt6577_auxadc_probe(struct platform_device *pdev) mt6577_auxadc_mod_reg(adc_dev->reg_base + MT6577_AUXADC_MISC, MT6577_AUXADC_PDN_EN, 0); mdelay(MT6577_AUXADC_POWER_READY_MS); + platform_set_drvdata(pdev, indio_dev); ret = devm_add_action_or_reset(&pdev->dev, mt6577_power_off, adc_dev); if (ret) From d97d11c70f25726fc21b2b2f1a26e16ac96a8ccf Mon Sep 17 00:00:00 2001 From: David Lechner Date: Thu, 5 Oct 2023 19:50:18 -0500 Subject: [PATCH 242/326] staging: iio: resolver: ad2s1210: do not use fault register for dummy read When reading registers on the AD2S1210 chip, we have to supply a "dummy" address for the second SPI tx byte so that we don't accidentally write to a register. This register will be read and the value discarded on the next regmap read or write call. Reading the fault register has a side-effect of clearing the faults so we should not use this register for the dummy read. Signed-off-by: David Lechner Link: https://lore.kernel.org/r/20231005-ad2s1210-mainline-v4-1-ec00746840fc@baylibre.com Signed-off-by: Jonathan Cameron --- drivers/staging/iio/resolver/ad2s1210.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/staging/iio/resolver/ad2s1210.c b/drivers/staging/iio/resolver/ad2s1210.c index 67d8af0dd7ae..8fbde9517fe9 100644 --- a/drivers/staging/iio/resolver/ad2s1210.c +++ b/drivers/staging/iio/resolver/ad2s1210.c @@ -166,9 +166,10 @@ static int ad2s1210_regmap_reg_read(void *context, unsigned int reg, st->tx[0] = reg; /* * Must be valid register address here otherwise this could write data. - * It doesn't matter which one. + * It doesn't matter which one as long as reading doesn't have side- + * effects. */ - st->tx[1] = AD2S1210_REG_FAULT; + st->tx[1] = AD2S1210_REG_CONTROL; ret = spi_sync_transfer(st->sdev, xfers, ARRAY_SIZE(xfers)); if (ret < 0) From bae023765199bef243b49c0f8860a3290a5c9f6d Mon Sep 17 00:00:00 2001 From: David Lechner Date: Thu, 5 Oct 2023 19:50:19 -0500 Subject: [PATCH 243/326] staging: iio: resolver: ad2s1210: implement hysteresis as channel attr The AD2S1210 resolver has a hysteresis feature that can be used to prevent flicker in the LSB of the position register. This can be either enabled or disabled. Disabling hysteresis is useful for increasing precision by oversampling. Signed-off-by: David Lechner Link: https://lore.kernel.org/r/20231005-ad2s1210-mainline-v4-2-ec00746840fc@baylibre.com Signed-off-by: Jonathan Cameron --- drivers/staging/iio/resolver/ad2s1210.c | 91 ++++++++++++++++++++++++- 1 file changed, 88 insertions(+), 3 deletions(-) diff --git a/drivers/staging/iio/resolver/ad2s1210.c b/drivers/staging/iio/resolver/ad2s1210.c index 8fbde9517fe9..af063eb25e9c 100644 --- a/drivers/staging/iio/resolver/ad2s1210.c +++ b/drivers/staging/iio/resolver/ad2s1210.c @@ -76,7 +76,8 @@ struct ad2s1210_state { struct regmap *regmap; /** The external oscillator frequency in Hz. */ unsigned long clkin_hz; - bool hysteresis; + /** Available raw hysteresis values based on resolution. */ + int hysteresis_available[2]; u8 resolution; /** For reading raw sample value via SPI. */ __be16 sample __aligned(IIO_DMA_MINALIGN); @@ -311,6 +312,7 @@ static ssize_t ad2s1210_store_resolution(struct device *dev, goto error_ret; st->resolution = udata; + st->hysteresis_available[1] = 1 << (16 - st->resolution); ret = len; error_ret: @@ -447,6 +449,35 @@ error_ret: return ret; } +static int ad2s1210_get_hysteresis(struct ad2s1210_state *st, int *val) +{ + int ret; + + mutex_lock(&st->lock); + ret = regmap_test_bits(st->regmap, AD2S1210_REG_CONTROL, + AD2S1210_ENABLE_HYSTERESIS); + mutex_unlock(&st->lock); + + if (ret < 0) + return ret; + + *val = ret << (16 - st->resolution); + return IIO_VAL_INT; +} + +static int ad2s1210_set_hysteresis(struct ad2s1210_state *st, int val) +{ + int ret; + + mutex_lock(&st->lock); + ret = regmap_update_bits(st->regmap, AD2S1210_REG_CONTROL, + AD2S1210_ENABLE_HYSTERESIS, + val ? AD2S1210_ENABLE_HYSTERESIS : 0); + mutex_unlock(&st->lock); + + return ret; +} + static const int ad2s1210_velocity_scale[] = { 17089132, /* 8.192MHz / (2*pi * 2500 / 2^15) */ 42722830, /* 8.192MHz / (2*pi * 1000 / 2^15) */ @@ -479,7 +510,55 @@ static int ad2s1210_read_raw(struct iio_dev *indio_dev, default: return -EINVAL; } + case IIO_CHAN_INFO_HYSTERESIS: + switch (chan->type) { + case IIO_ANGL: + return ad2s1210_get_hysteresis(st, val); + default: + return -EINVAL; + } + default: + return -EINVAL; + } +} +static int ad2s1210_read_avail(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + const int **vals, int *type, + int *length, long mask) +{ + struct ad2s1210_state *st = iio_priv(indio_dev); + + switch (mask) { + case IIO_CHAN_INFO_HYSTERESIS: + switch (chan->type) { + case IIO_ANGL: + *vals = st->hysteresis_available; + *type = IIO_VAL_INT; + *length = ARRAY_SIZE(st->hysteresis_available); + return IIO_AVAIL_LIST; + default: + return -EINVAL; + } + default: + return -EINVAL; + } +} + +static int ad2s1210_write_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int val, int val2, long mask) +{ + struct ad2s1210_state *st = iio_priv(indio_dev); + + switch (mask) { + case IIO_CHAN_INFO_HYSTERESIS: + switch (chan->type) { + case IIO_ANGL: + return ad2s1210_set_hysteresis(st, val); + default: + return -EINVAL; + } default: return -EINVAL; } @@ -520,7 +599,10 @@ static const struct iio_chan_spec ad2s1210_channels[] = { .indexed = 1, .channel = 0, .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | - BIT(IIO_CHAN_INFO_SCALE), + BIT(IIO_CHAN_INFO_SCALE) | + BIT(IIO_CHAN_INFO_HYSTERESIS), + .info_mask_separate_available = + BIT(IIO_CHAN_INFO_HYSTERESIS), }, { .type = IIO_ANGL_VEL, .indexed = 1, @@ -596,6 +678,8 @@ static int ad2s1210_debugfs_reg_access(struct iio_dev *indio_dev, static const struct iio_info ad2s1210_info = { .read_raw = ad2s1210_read_raw, + .read_avail = ad2s1210_read_avail, + .write_raw = ad2s1210_write_raw, .attrs = &ad2s1210_attribute_group, .debugfs_reg_access = &ad2s1210_debugfs_reg_access, }; @@ -711,8 +795,9 @@ static int ad2s1210_probe(struct spi_device *spi) mutex_init(&st->lock); st->sdev = spi; - st->hysteresis = true; st->resolution = 12; + st->hysteresis_available[0] = 0; + st->hysteresis_available[1] = 1 << (16 - st->resolution); ret = ad2s1210_setup_clocks(st); if (ret < 0) From 7dde2719fb3892ad69da4b1c5790bac5ea958a09 Mon Sep 17 00:00:00 2001 From: David Lechner Date: Thu, 5 Oct 2023 19:50:20 -0500 Subject: [PATCH 244/326] staging: iio: resolver: ad2s1210: convert fexcit to channel attribute The ad2s1210 driver has a device-specific attribute `fexcit` for setting the frequency of the excitation output. This converts it to a channel in order to use standard IIO ABI. The excitation frequency is an analog output that generates a sine wave. Only the frequency is configurable. According to the datasheet, the specified range of the excitation frequency is from 2 kHz to 20 kHz and can be set in increments of 250 Hz. Signed-off-by: David Lechner Link: https://lore.kernel.org/r/20231005-ad2s1210-mainline-v4-3-ec00746840fc@baylibre.com Signed-off-by: Jonathan Cameron --- drivers/staging/iio/resolver/ad2s1210.c | 123 ++++++++++++++---------- 1 file changed, 71 insertions(+), 52 deletions(-) diff --git a/drivers/staging/iio/resolver/ad2s1210.c b/drivers/staging/iio/resolver/ad2s1210.c index af063eb25e9c..0c7772725330 100644 --- a/drivers/staging/iio/resolver/ad2s1210.c +++ b/drivers/staging/iio/resolver/ad2s1210.c @@ -227,54 +227,6 @@ static int ad2s1210_set_resolution_gpios(struct ad2s1210_state *st, bitmap); } -static ssize_t ad2s1210_show_fexcit(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - struct ad2s1210_state *st = iio_priv(dev_to_iio_dev(dev)); - unsigned int value; - u16 fexcit; - int ret; - - mutex_lock(&st->lock); - ret = regmap_read(st->regmap, AD2S1210_REG_EXCIT_FREQ, &value); - if (ret < 0) - goto error_ret; - - fexcit = value * st->clkin_hz / (1 << 15); - - ret = sprintf(buf, "%u\n", fexcit); - -error_ret: - mutex_unlock(&st->lock); - return ret; -} - -static ssize_t ad2s1210_store_fexcit(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t len) -{ - struct ad2s1210_state *st = iio_priv(dev_to_iio_dev(dev)); - u16 fexcit; - int ret; - - ret = kstrtou16(buf, 10, &fexcit); - if (ret < 0 || fexcit < AD2S1210_MIN_EXCIT || fexcit > AD2S1210_MAX_EXCIT) - return -EINVAL; - - mutex_lock(&st->lock); - ret = ad2s1210_reinit_excitation_frequency(st, fexcit); - if (ret < 0) - goto error_ret; - - ret = len; - -error_ret: - mutex_unlock(&st->lock); - - return ret; -} - static ssize_t ad2s1210_show_resolution(struct device *dev, struct device_attribute *attr, char *buf) @@ -478,6 +430,38 @@ static int ad2s1210_set_hysteresis(struct ad2s1210_state *st, int val) return ret; } +static int ad2s1210_get_excitation_frequency(struct ad2s1210_state *st, int *val) +{ + unsigned int reg_val; + int ret; + + mutex_lock(&st->lock); + ret = regmap_read(st->regmap, AD2S1210_REG_EXCIT_FREQ, ®_val); + if (ret < 0) + goto error_ret; + + *val = reg_val * st->clkin_hz / (1 << 15); + ret = IIO_VAL_INT; + +error_ret: + mutex_unlock(&st->lock); + return ret; +} + +static int ad2s1210_set_excitation_frequency(struct ad2s1210_state *st, int val) +{ + int ret; + + if (val < AD2S1210_MIN_EXCIT || val > AD2S1210_MAX_EXCIT) + return -EINVAL; + + mutex_lock(&st->lock); + ret = ad2s1210_reinit_excitation_frequency(st, val); + mutex_unlock(&st->lock); + + return ret; +} + static const int ad2s1210_velocity_scale[] = { 17089132, /* 8.192MHz / (2*pi * 2500 / 2^15) */ 42722830, /* 8.192MHz / (2*pi * 1000 / 2^15) */ @@ -510,6 +494,13 @@ static int ad2s1210_read_raw(struct iio_dev *indio_dev, default: return -EINVAL; } + case IIO_CHAN_INFO_FREQUENCY: + switch (chan->type) { + case IIO_ALTVOLTAGE: + return ad2s1210_get_excitation_frequency(st, val); + default: + return -EINVAL; + } case IIO_CHAN_INFO_HYSTERESIS: switch (chan->type) { case IIO_ANGL: @@ -527,9 +518,24 @@ static int ad2s1210_read_avail(struct iio_dev *indio_dev, const int **vals, int *type, int *length, long mask) { + static const int excitation_frequency_available[] = { + AD2S1210_MIN_EXCIT, + 250, /* step */ + AD2S1210_MAX_EXCIT, + }; + struct ad2s1210_state *st = iio_priv(indio_dev); switch (mask) { + case IIO_CHAN_INFO_FREQUENCY: + switch (chan->type) { + case IIO_ALTVOLTAGE: + *type = IIO_VAL_INT; + *vals = excitation_frequency_available; + return IIO_AVAIL_RANGE; + default: + return -EINVAL; + } case IIO_CHAN_INFO_HYSTERESIS: switch (chan->type) { case IIO_ANGL: @@ -552,6 +558,13 @@ static int ad2s1210_write_raw(struct iio_dev *indio_dev, struct ad2s1210_state *st = iio_priv(indio_dev); switch (mask) { + case IIO_CHAN_INFO_FREQUENCY: + switch (chan->type) { + case IIO_ALTVOLTAGE: + return ad2s1210_set_excitation_frequency(st, val); + default: + return -EINVAL; + } case IIO_CHAN_INFO_HYSTERESIS: switch (chan->type) { case IIO_ANGL: @@ -564,8 +577,6 @@ static int ad2s1210_write_raw(struct iio_dev *indio_dev, } } -static IIO_DEVICE_ATTR(fexcit, 0644, - ad2s1210_show_fexcit, ad2s1210_store_fexcit, 0); static IIO_DEVICE_ATTR(bits, 0644, ad2s1210_show_resolution, ad2s1210_store_resolution, 0); static IIO_DEVICE_ATTR(fault, 0644, @@ -609,11 +620,19 @@ static const struct iio_chan_spec ad2s1210_channels[] = { .channel = 0, .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE), - } + }, { + /* excitation frequency output */ + .type = IIO_ALTVOLTAGE, + .indexed = 1, + .channel = 0, + .output = 1, + .scan_index = -1, + .info_mask_separate = BIT(IIO_CHAN_INFO_FREQUENCY), + .info_mask_separate_available = BIT(IIO_CHAN_INFO_FREQUENCY), + }, }; static struct attribute *ad2s1210_attributes[] = { - &iio_dev_attr_fexcit.dev_attr.attr, &iio_dev_attr_bits.dev_attr.attr, &iio_dev_attr_fault.dev_attr.attr, &iio_dev_attr_los_thrd.dev_attr.attr, From 3e7d173aef28d05a8db2941d78498f67746b27bc Mon Sep 17 00:00:00 2001 From: David Lechner Date: Thu, 5 Oct 2023 19:50:21 -0500 Subject: [PATCH 245/326] staging: iio: resolver: ad2s1210: convert resolution to devicetree property Selecting the resolution was implemented as the `bits` sysfs attribute. However, the selection of the resolution depends on how the hardware is wired and the specific application, so this is rather a job for devicetree to describe. A new devicetree property `assigned-resolution-bits` to specify the resolution required for each chip is added and the `bits` sysfs attribute is removed. Since the resolution is now supplied by a devicetree property, the resolution-gpios are now optional and we can allow for the case where the resolution pins on the AD2S1210 are hard-wired instead of requiring them to be connected to gpios. Signed-off-by: David Lechner Link: https://lore.kernel.org/r/20231005-ad2s1210-mainline-v4-4-ec00746840fc@baylibre.com Signed-off-by: Jonathan Cameron --- drivers/staging/iio/resolver/ad2s1210.c | 150 +++++++++++------------- 1 file changed, 71 insertions(+), 79 deletions(-) diff --git a/drivers/staging/iio/resolver/ad2s1210.c b/drivers/staging/iio/resolver/ad2s1210.c index 0c7772725330..66ef35fbb6fe 100644 --- a/drivers/staging/iio/resolver/ad2s1210.c +++ b/drivers/staging/iio/resolver/ad2s1210.c @@ -63,6 +63,13 @@ enum ad2s1210_mode { MOD_CONFIG = 0b11, }; +enum ad2s1210_resolution { + AD2S1210_RES_10 = 0b00, + AD2S1210_RES_12 = 0b01, + AD2S1210_RES_14 = 0b10, + AD2S1210_RES_16 = 0b11, +}; + struct ad2s1210_state { struct mutex lock; struct spi_device *sdev; @@ -70,15 +77,14 @@ struct ad2s1210_state { struct gpio_desc *sample_gpio; /** GPIO pins connected to A0 and A1 lines. */ struct gpio_descs *mode_gpios; - /** GPIO pins connected to RES0 and RES1 lines. */ - struct gpio_descs *resolution_gpios; /** Used to access config registers. */ struct regmap *regmap; /** The external oscillator frequency in Hz. */ unsigned long clkin_hz; /** Available raw hysteresis values based on resolution. */ int hysteresis_available[2]; - u8 resolution; + /** The selected resolution */ + enum ad2s1210_resolution resolution; /** For reading raw sample value via SPI. */ __be16 sample __aligned(IIO_DMA_MINALIGN); /** SPI transmit buffer. */ @@ -215,63 +221,6 @@ static int ad2s1210_reinit_excitation_frequency(struct ad2s1210_state *st, return regmap_write(st->regmap, AD2S1210_REG_SOFT_RESET, 0); } -static int ad2s1210_set_resolution_gpios(struct ad2s1210_state *st, - u8 resolution) -{ - struct gpio_descs *gpios = st->resolution_gpios; - DECLARE_BITMAP(bitmap, 2); - - bitmap[0] = (resolution - 10) >> 1; - - return gpiod_set_array_value(gpios->ndescs, gpios->desc, gpios->info, - bitmap); -} - -static ssize_t ad2s1210_show_resolution(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - struct ad2s1210_state *st = iio_priv(dev_to_iio_dev(dev)); - - return sprintf(buf, "%d\n", st->resolution); -} - -static ssize_t ad2s1210_store_resolution(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t len) -{ - struct ad2s1210_state *st = iio_priv(dev_to_iio_dev(dev)); - unsigned char data; - unsigned char udata; - int ret; - - ret = kstrtou8(buf, 10, &udata); - if (ret || udata < 10 || udata > 16) { - dev_err(dev, "ad2s1210: resolution out of range\n"); - return -EINVAL; - } - - data = (udata - 10) >> 1; - - mutex_lock(&st->lock); - ret = regmap_update_bits(st->regmap, AD2S1210_REG_CONTROL, - AD2S1210_SET_RES, data); - if (ret < 0) - goto error_ret; - - ret = ad2s1210_set_resolution_gpios(st, udata); - if (ret < 0) - goto error_ret; - - st->resolution = udata; - st->hysteresis_available[1] = 1 << (16 - st->resolution); - ret = len; - -error_ret: - mutex_unlock(&st->lock); - return ret; -} - /* read the fault register since last sample */ static ssize_t ad2s1210_show_fault(struct device *dev, struct device_attribute *attr, char *buf) @@ -413,7 +362,7 @@ static int ad2s1210_get_hysteresis(struct ad2s1210_state *st, int *val) if (ret < 0) return ret; - *val = ret << (16 - st->resolution); + *val = ret << (2 * (AD2S1210_RES_16 - st->resolution)); return IIO_VAL_INT; } @@ -577,8 +526,6 @@ static int ad2s1210_write_raw(struct iio_dev *indio_dev, } } -static IIO_DEVICE_ATTR(bits, 0644, - ad2s1210_show_resolution, ad2s1210_store_resolution, 0); static IIO_DEVICE_ATTR(fault, 0644, ad2s1210_show_fault, ad2s1210_clear_fault, 0); @@ -633,7 +580,6 @@ static const struct iio_chan_spec ad2s1210_channels[] = { }; static struct attribute *ad2s1210_attributes[] = { - &iio_dev_attr_bits.dev_attr.attr, &iio_dev_attr_fault.dev_attr.attr, &iio_dev_attr_los_thrd.dev_attr.attr, &iio_dev_attr_dos_ovr_thrd.dev_attr.attr, @@ -655,15 +601,12 @@ static int ad2s1210_initial(struct ad2s1210_state *st) int ret; mutex_lock(&st->lock); - ret = ad2s1210_set_resolution_gpios(st, st->resolution); - if (ret < 0) - goto error_ret; /* Use default config register value plus resolution from devicetree. */ data = FIELD_PREP(AD2S1210_PHASE_LOCK_RANGE_44, 1); data |= FIELD_PREP(AD2S1210_ENABLE_HYSTERESIS, 1); data |= FIELD_PREP(AD2S1210_SET_ENRES, 0x3); - data |= FIELD_PREP(AD2S1210_SET_RES, (st->resolution - 10) >> 1); + data |= FIELD_PREP(AD2S1210_SET_RES, st->resolution); ret = regmap_write(st->regmap, AD2S1210_REG_CONTROL, data); if (ret < 0) @@ -703,6 +646,35 @@ static const struct iio_info ad2s1210_info = { .debugfs_reg_access = &ad2s1210_debugfs_reg_access, }; +static int ad2s1210_setup_properties(struct ad2s1210_state *st) +{ + struct device *dev = &st->sdev->dev; + u32 val; + int ret; + + ret = device_property_read_u32(dev, "assigned-resolution-bits", &val); + if (ret < 0) + return dev_err_probe(dev, ret, + "failed to read assigned-resolution-bits property\n"); + + if (val < 10 || val > 16) + return dev_err_probe(dev, -EINVAL, + "resolution out of range: %u\n", val); + + st->resolution = (val - 10) >> 1; + /* + * These are values that correlate to the hysteresis bit in the Control + * register. 0 = disabled, 1 = enabled. When enabled, the actual + * hysteresis is +/- 1 LSB of the raw position value. Which bit is the + * LSB depends on the specified resolution. + */ + st->hysteresis_available[0] = 0; + st->hysteresis_available[1] = 1 << (2 * (AD2S1210_RES_16 - + st->resolution)); + + return 0; +} + static int ad2s1210_setup_clocks(struct ad2s1210_state *st) { struct device *dev = &st->sdev->dev; @@ -724,6 +696,9 @@ static int ad2s1210_setup_clocks(struct ad2s1210_state *st) static int ad2s1210_setup_gpios(struct ad2s1210_state *st) { struct device *dev = &st->sdev->dev; + struct gpio_descs *resolution_gpios; + DECLARE_BITMAP(bitmap, 2); + int ret; /* should not be sampling on startup */ st->sample_gpio = devm_gpiod_get(dev, "sample", GPIOD_OUT_LOW); @@ -741,16 +716,32 @@ static int ad2s1210_setup_gpios(struct ad2s1210_state *st) return dev_err_probe(dev, -EINVAL, "requires exactly 2 mode-gpios\n"); - /* both pins high means that we start with 16-bit resolution */ - st->resolution_gpios = devm_gpiod_get_array(dev, "resolution", - GPIOD_OUT_HIGH); - if (IS_ERR(st->resolution_gpios)) - return dev_err_probe(dev, PTR_ERR(st->resolution_gpios), + /* + * If resolution gpios are provided, they get set to the required + * resolution, otherwise it is assumed the RES0 and RES1 pins are + * hard-wired to match the resolution indicated in the devicetree. + */ + resolution_gpios = devm_gpiod_get_array_optional(dev, "resolution", + GPIOD_ASIS); + if (IS_ERR(resolution_gpios)) + return dev_err_probe(dev, PTR_ERR(resolution_gpios), "failed to request resolution GPIOs\n"); - if (st->resolution_gpios->ndescs != 2) - return dev_err_probe(dev, -EINVAL, - "requires exactly 2 resolution-gpios\n"); + if (resolution_gpios) { + if (resolution_gpios->ndescs != 2) + return dev_err_probe(dev, -EINVAL, + "requires exactly 2 resolution-gpios\n"); + + bitmap[0] = st->resolution; + + ret = gpiod_set_array_value(resolution_gpios->ndescs, + resolution_gpios->desc, + resolution_gpios->info, + bitmap); + if (ret < 0) + return dev_err_probe(dev, ret, + "failed to set resolution gpios\n"); + } return 0; } @@ -814,9 +805,10 @@ static int ad2s1210_probe(struct spi_device *spi) mutex_init(&st->lock); st->sdev = spi; - st->resolution = 12; - st->hysteresis_available[0] = 0; - st->hysteresis_available[1] = 1 << (16 - st->resolution); + + ret = ad2s1210_setup_properties(st); + if (ret < 0) + return ret; ret = ad2s1210_setup_clocks(st); if (ret < 0) From b3335cd557fb886cd58ac6f9d0b283bbab120411 Mon Sep 17 00:00:00 2001 From: David Lechner Date: Thu, 5 Oct 2023 19:50:22 -0500 Subject: [PATCH 246/326] staging: iio: resolver: ad2s1210: add phase lock range support The AD2S1210 chip has a phase lock range feature that allows selecting the allowable phase difference between the excitation output and the sine and cosine inputs. This can be set to either 44 degrees (default) or 360 degrees. This patch adds a new phase channel with a phase0_mag_rising event that can be used to configure the phase lock range. Actually emitting the event will be added in a subsequent patch. Signed-off-by: David Lechner Link: https://lore.kernel.org/r/20231005-ad2s1210-mainline-v4-5-ec00746840fc@baylibre.com Signed-off-by: Jonathan Cameron --- drivers/staging/iio/resolver/ad2s1210.c | 125 ++++++++++++++++++++++++ 1 file changed, 125 insertions(+) diff --git a/drivers/staging/iio/resolver/ad2s1210.c b/drivers/staging/iio/resolver/ad2s1210.c index 66ef35fbb6fe..83f6ac890dbc 100644 --- a/drivers/staging/iio/resolver/ad2s1210.c +++ b/drivers/staging/iio/resolver/ad2s1210.c @@ -56,6 +56,13 @@ #define AD2S1210_MIN_FCW 0x4 #define AD2S1210_MAX_FCW 0x50 +/* 44 degrees ~= 0.767945 radians */ +#define PHASE_44_DEG_TO_RAD_INT 0 +#define PHASE_44_DEG_TO_RAD_MICRO 767945 +/* 360 degrees ~= 6.283185 radians */ +#define PHASE_360_DEG_TO_RAD_INT 6 +#define PHASE_360_DEG_TO_RAD_MICRO 283185 + enum ad2s1210_mode { MOD_POS = 0b00, MOD_VEL = 0b01, @@ -379,6 +386,54 @@ static int ad2s1210_set_hysteresis(struct ad2s1210_state *st, int val) return ret; } +static int ad2s1210_get_phase_lock_range(struct ad2s1210_state *st, + int *val, int *val2) +{ + int ret; + + mutex_lock(&st->lock); + ret = regmap_test_bits(st->regmap, AD2S1210_REG_CONTROL, + AD2S1210_PHASE_LOCK_RANGE_44); + mutex_unlock(&st->lock); + + if (ret < 0) + return ret; + + if (ret) { + /* 44 degrees as radians */ + *val = PHASE_44_DEG_TO_RAD_INT; + *val2 = PHASE_44_DEG_TO_RAD_MICRO; + } else { + /* 360 degrees as radians */ + *val = PHASE_360_DEG_TO_RAD_INT; + *val2 = PHASE_360_DEG_TO_RAD_MICRO; + } + + return IIO_VAL_INT_PLUS_MICRO; +} + +static int ad2s1210_set_phase_lock_range(struct ad2s1210_state *st, + int val, int val2) +{ + int deg, ret; + + /* convert radians to degrees - only two allowable values */ + if (val == PHASE_44_DEG_TO_RAD_INT && val2 == PHASE_44_DEG_TO_RAD_MICRO) + deg = 44; + else if (val == PHASE_360_DEG_TO_RAD_INT && + val2 == PHASE_360_DEG_TO_RAD_MICRO) + deg = 360; + else + return -EINVAL; + + mutex_lock(&st->lock); + ret = regmap_update_bits(st->regmap, AD2S1210_REG_CONTROL, + AD2S1210_PHASE_LOCK_RANGE_44, + deg == 44 ? AD2S1210_PHASE_LOCK_RANGE_44 : 0); + mutex_unlock(&st->lock); + return ret; +} + static int ad2s1210_get_excitation_frequency(struct ad2s1210_state *st, int *val) { unsigned int reg_val; @@ -551,6 +606,16 @@ static IIO_DEVICE_ATTR(lot_low_thrd, 0644, ad2s1210_show_reg, ad2s1210_store_reg, AD2S1210_REG_LOT_LOW_THRD); +static const struct iio_event_spec ad2s1210_phase_event_spec[] = { + { + /* Phase error fault. */ + .type = IIO_EV_TYPE_MAG, + .dir = IIO_EV_DIR_RISING, + /* Phase lock range. */ + .mask_separate = BIT(IIO_EV_INFO_VALUE), + }, +}; + static const struct iio_chan_spec ad2s1210_channels[] = { { .type = IIO_ANGL, @@ -567,6 +632,14 @@ static const struct iio_chan_spec ad2s1210_channels[] = { .channel = 0, .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE), + }, { + /* used to configure phase lock range and get phase lock error */ + .type = IIO_PHASE, + .indexed = 1, + .channel = 0, + .scan_index = -1, + .event_spec = ad2s1210_phase_event_spec, + .num_event_specs = ARRAY_SIZE(ad2s1210_phase_event_spec), }, { /* excitation frequency output */ .type = IIO_ALTVOLTAGE, @@ -595,6 +668,21 @@ static const struct attribute_group ad2s1210_attribute_group = { .attrs = ad2s1210_attributes, }; +static IIO_CONST_ATTR(in_phase0_mag_rising_value_available, + __stringify(PHASE_44_DEG_TO_RAD_INT) "." + __stringify(PHASE_44_DEG_TO_RAD_MICRO) " " + __stringify(PHASE_360_DEG_TO_RAD_INT) "." + __stringify(PHASE_360_DEG_TO_RAD_MICRO)); + +static struct attribute *ad2s1210_event_attributes[] = { + &iio_const_attr_in_phase0_mag_rising_value_available.dev_attr.attr, + NULL, +}; + +static const struct attribute_group ad2s1210_event_attribute_group = { + .attrs = ad2s1210_event_attributes, +}; + static int ad2s1210_initial(struct ad2s1210_state *st) { unsigned char data; @@ -619,6 +707,40 @@ error_ret: return ret; } +static int ad2s1210_read_event_value(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, + enum iio_event_type type, + enum iio_event_direction dir, + enum iio_event_info info, + int *val, int *val2) +{ + struct ad2s1210_state *st = iio_priv(indio_dev); + + switch (chan->type) { + case IIO_PHASE: + return ad2s1210_get_phase_lock_range(st, val, val2); + default: + return -EINVAL; + } +} + +static int ad2s1210_write_event_value(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, + enum iio_event_type type, + enum iio_event_direction dir, + enum iio_event_info info, + int val, int val2) +{ + struct ad2s1210_state *st = iio_priv(indio_dev); + + switch (chan->type) { + case IIO_PHASE: + return ad2s1210_set_phase_lock_range(st, val, val2); + default: + return -EINVAL; + } +} + static int ad2s1210_debugfs_reg_access(struct iio_dev *indio_dev, unsigned int reg, unsigned int writeval, unsigned int *readval) @@ -639,10 +761,13 @@ static int ad2s1210_debugfs_reg_access(struct iio_dev *indio_dev, } static const struct iio_info ad2s1210_info = { + .event_attrs = &ad2s1210_event_attribute_group, .read_raw = ad2s1210_read_raw, .read_avail = ad2s1210_read_avail, .write_raw = ad2s1210_write_raw, .attrs = &ad2s1210_attribute_group, + .read_event_value = ad2s1210_read_event_value, + .write_event_value = ad2s1210_write_event_value, .debugfs_reg_access = &ad2s1210_debugfs_reg_access, }; From 128b9389db0ed66ab0a108a1b439cabf2537032f Mon Sep 17 00:00:00 2001 From: David Lechner Date: Thu, 5 Oct 2023 19:50:23 -0500 Subject: [PATCH 247/326] staging: iio: resolver: ad2s1210: add triggered buffer support This adds support for triggered buffers to the AD2S1210 resolver driver. Signed-off-by: David Lechner Link: https://lore.kernel.org/r/20231005-ad2s1210-mainline-v4-6-ec00746840fc@baylibre.com Signed-off-by: Jonathan Cameron --- drivers/staging/iio/resolver/ad2s1210.c | 83 ++++++++++++++++++++++++- 1 file changed, 82 insertions(+), 1 deletion(-) diff --git a/drivers/staging/iio/resolver/ad2s1210.c b/drivers/staging/iio/resolver/ad2s1210.c index 83f6ac890dbc..4d651a2d0f38 100644 --- a/drivers/staging/iio/resolver/ad2s1210.c +++ b/drivers/staging/iio/resolver/ad2s1210.c @@ -20,8 +20,11 @@ #include #include +#include #include #include +#include +#include #define DRV_NAME "ad2s1210" @@ -94,6 +97,12 @@ struct ad2s1210_state { enum ad2s1210_resolution resolution; /** For reading raw sample value via SPI. */ __be16 sample __aligned(IIO_DMA_MINALIGN); + /** Scan buffer */ + struct { + __be16 chan[2]; + /* Ensure timestamp is naturally aligned. */ + s64 timestamp __aligned(8); + } scan; /** SPI transmit buffer. */ u8 rx[2]; /** SPI receive buffer. */ @@ -621,6 +630,13 @@ static const struct iio_chan_spec ad2s1210_channels[] = { .type = IIO_ANGL, .indexed = 1, .channel = 0, + .scan_index = 0, + .scan_type = { + .sign = 'u', + .realbits = 16, + .storagebits = 16, + .endianness = IIO_BE, + }, .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE) | BIT(IIO_CHAN_INFO_HYSTERESIS), @@ -630,9 +646,18 @@ static const struct iio_chan_spec ad2s1210_channels[] = { .type = IIO_ANGL_VEL, .indexed = 1, .channel = 0, + .scan_index = 1, + .scan_type = { + .sign = 's', + .realbits = 16, + .storagebits = 16, + .endianness = IIO_BE, + }, .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE), - }, { + }, + IIO_CHAN_SOFT_TIMESTAMP(2), + { /* used to configure phase lock range and get phase lock error */ .type = IIO_PHASE, .indexed = 1, @@ -760,6 +785,55 @@ static int ad2s1210_debugfs_reg_access(struct iio_dev *indio_dev, return ret; } +static irqreturn_t ad2s1210_trigger_handler(int irq, void *p) +{ + struct iio_poll_func *pf = p; + struct iio_dev *indio_dev = pf->indio_dev; + struct ad2s1210_state *st = iio_priv(indio_dev); + size_t chan = 0; + int ret; + + mutex_lock(&st->lock); + + memset(&st->scan, 0, sizeof(st->scan)); + gpiod_set_value(st->sample_gpio, 1); + + if (test_bit(0, indio_dev->active_scan_mask)) { + ret = ad2s1210_set_mode(st, MOD_POS); + if (ret < 0) + goto error_ret; + + /* REVIST: we can read 3 bytes here and also get fault flags */ + ret = spi_read(st->sdev, st->rx, 2); + if (ret < 0) + goto error_ret; + + memcpy(&st->scan.chan[chan++], st->rx, 2); + } + + if (test_bit(1, indio_dev->active_scan_mask)) { + ret = ad2s1210_set_mode(st, MOD_VEL); + if (ret < 0) + goto error_ret; + + /* REVIST: we can read 3 bytes here and also get fault flags */ + ret = spi_read(st->sdev, st->rx, 2); + if (ret < 0) + goto error_ret; + + memcpy(&st->scan.chan[chan++], st->rx, 2); + } + + iio_push_to_buffers_with_timestamp(indio_dev, &st->scan, pf->timestamp); + +error_ret: + gpiod_set_value(st->sample_gpio, 0); + mutex_unlock(&st->lock); + iio_trigger_notify_done(indio_dev->trig); + + return IRQ_HANDLED; +} + static const struct iio_info ad2s1210_info = { .event_attrs = &ad2s1210_event_attribute_group, .read_raw = ad2s1210_read_raw, @@ -957,6 +1031,13 @@ static int ad2s1210_probe(struct spi_device *spi) indio_dev->num_channels = ARRAY_SIZE(ad2s1210_channels); indio_dev->name = spi_get_device_id(spi)->name; + ret = devm_iio_triggered_buffer_setup(&spi->dev, indio_dev, + &iio_pollfunc_store_time, + &ad2s1210_trigger_handler, NULL); + if (ret < 0) + return dev_err_probe(&spi->dev, ret, + "iio triggered buffer setup failed\n"); + return devm_iio_device_register(&spi->dev, indio_dev); } From 235e4b988046d29097523703bb5e5e3ba77259ca Mon Sep 17 00:00:00 2001 From: David Lechner Date: Thu, 5 Oct 2023 19:50:24 -0500 Subject: [PATCH 248/326] staging: iio: resolver: ad2s1210: convert LOT threshold attrs to event attrs The AD2S1210 monitors the internal error signal (difference between estimated angle and measured angle) to determine a loss of position tracking (LOT) condition. When the error value exceeds a threshold, a fault is triggered. This threshold is user-configurable. This patch converts the custom lot_high_thrd and lot_low_thrd attributes in the ad2s1210 driver to standard event attributes. This will allow tooling to be able to expose these in a generic way. Since the low threshold determines the hysteresis, it requires some special handling to expose the difference between the high and low register values as the hysteresis instead of exposing the low register value directly. The attributes also return the values in radians now as required by the ABI. Actually emitting the fault event will be done in a later patch. Signed-off-by: David Lechner Link: https://lore.kernel.org/r/20231005-ad2s1210-mainline-v4-7-ec00746840fc@baylibre.com Signed-off-by: Jonathan Cameron --- drivers/staging/iio/resolver/ad2s1210.c | 191 +++++++++++++++++++++++- 1 file changed, 183 insertions(+), 8 deletions(-) diff --git a/drivers/staging/iio/resolver/ad2s1210.c b/drivers/staging/iio/resolver/ad2s1210.c index 4d651a2d0f38..12437f697f79 100644 --- a/drivers/staging/iio/resolver/ad2s1210.c +++ b/drivers/staging/iio/resolver/ad2s1210.c @@ -443,6 +443,123 @@ static int ad2s1210_set_phase_lock_range(struct ad2s1210_state *st, return ret; } +/* map resolution to microradians/LSB for LOT registers */ +static const int ad2s1210_lot_threshold_urad_per_lsb[] = { + 6184, /* 10-bit: ~0.35 deg/LSB, 45 deg max */ + 2473, /* 12-bit: ~0.14 deg/LSB, 18 deg max */ + 1237, /* 14-bit: ~0.07 deg/LSB, 9 deg max */ + 1237, /* 16-bit: same as 14-bit */ +}; + +static int ad2s1210_get_lot_high_threshold(struct ad2s1210_state *st, + int *val, int *val2) +{ + unsigned int reg_val; + int ret; + + mutex_lock(&st->lock); + ret = regmap_read(st->regmap, AD2S1210_REG_LOT_HIGH_THRD, ®_val); + mutex_unlock(&st->lock); + + if (ret < 0) + return ret; + + *val = 0; + *val2 = reg_val * ad2s1210_lot_threshold_urad_per_lsb[st->resolution]; + return IIO_VAL_INT_PLUS_MICRO; +} + +static int ad2s1210_set_lot_high_threshold(struct ad2s1210_state *st, + int val, int val2) +{ + unsigned int high_reg_val, low_reg_val, hysteresis; + int ret; + + /* all valid values are between 0 and pi/4 radians */ + if (val != 0) + return -EINVAL; + + mutex_lock(&st->lock); + /* + * We need to read both high and low registers first so we can preserve + * the hysteresis. + */ + ret = regmap_read(st->regmap, AD2S1210_REG_LOT_HIGH_THRD, &high_reg_val); + if (ret < 0) + goto error_ret; + + ret = regmap_read(st->regmap, AD2S1210_REG_LOT_LOW_THRD, &low_reg_val); + if (ret < 0) + goto error_ret; + + hysteresis = high_reg_val - low_reg_val; + high_reg_val = val2 / ad2s1210_lot_threshold_urad_per_lsb[st->resolution]; + low_reg_val = high_reg_val - hysteresis; + + ret = regmap_write(st->regmap, AD2S1210_REG_LOT_HIGH_THRD, high_reg_val); + if (ret < 0) + goto error_ret; + + ret = regmap_write(st->regmap, AD2S1210_REG_LOT_LOW_THRD, low_reg_val); + +error_ret: + mutex_unlock(&st->lock); + + return ret; +} + +static int ad2s1210_get_lot_low_threshold(struct ad2s1210_state *st, + int *val, int *val2) +{ + unsigned int high_reg_val, low_reg_val; + int ret; + + mutex_lock(&st->lock); + ret = regmap_read(st->regmap, AD2S1210_REG_LOT_HIGH_THRD, &high_reg_val); + if (ret < 0) + goto error_ret; + + ret = regmap_read(st->regmap, AD2S1210_REG_LOT_LOW_THRD, &low_reg_val); + +error_ret: + mutex_unlock(&st->lock); + + if (ret < 0) + return ret; + + /* sysfs value is hysteresis rather than actual low value */ + *val = 0; + *val2 = (high_reg_val - low_reg_val) * + ad2s1210_lot_threshold_urad_per_lsb[st->resolution]; + return IIO_VAL_INT_PLUS_MICRO; +} + +static int ad2s1210_set_lot_low_threshold(struct ad2s1210_state *st, + int val, int val2) +{ + unsigned int reg_val, hysteresis; + int ret; + + /* all valid values are between 0 and pi/4 radians */ + if (val != 0) + return -EINVAL; + + hysteresis = val2 / ad2s1210_lot_threshold_urad_per_lsb[st->resolution]; + + mutex_lock(&st->lock); + ret = regmap_read(st->regmap, AD2S1210_REG_LOT_HIGH_THRD, ®_val); + if (ret < 0) + goto error_ret; + + ret = regmap_write(st->regmap, AD2S1210_REG_LOT_LOW_THRD, + reg_val - hysteresis); + +error_ret: + mutex_unlock(&st->lock); + + return ret; +} + static int ad2s1210_get_excitation_frequency(struct ad2s1210_state *st, int *val) { unsigned int reg_val; @@ -608,12 +725,19 @@ static IIO_DEVICE_ATTR(dos_rst_max_thrd, 0644, static IIO_DEVICE_ATTR(dos_rst_min_thrd, 0644, ad2s1210_show_reg, ad2s1210_store_reg, AD2S1210_REG_DOS_RST_MIN_THRD); -static IIO_DEVICE_ATTR(lot_high_thrd, 0644, - ad2s1210_show_reg, ad2s1210_store_reg, - AD2S1210_REG_LOT_HIGH_THRD); -static IIO_DEVICE_ATTR(lot_low_thrd, 0644, - ad2s1210_show_reg, ad2s1210_store_reg, - AD2S1210_REG_LOT_LOW_THRD); + +static const struct iio_event_spec ad2s1210_position_event_spec[] = { + { + /* Tracking error exceeds LOT threshold fault. */ + .type = IIO_EV_TYPE_THRESH, + .dir = IIO_EV_DIR_RISING, + .mask_separate = + /* Loss of tracking high threshold. */ + BIT(IIO_EV_INFO_VALUE) | + /* Loss of tracking low threshold. */ + BIT(IIO_EV_INFO_HYSTERESIS), + }, +}; static const struct iio_event_spec ad2s1210_phase_event_spec[] = { { @@ -657,6 +781,15 @@ static const struct iio_chan_spec ad2s1210_channels[] = { BIT(IIO_CHAN_INFO_SCALE), }, IIO_CHAN_SOFT_TIMESTAMP(2), + { + /* used to configure LOT thresholds and get tracking error */ + .type = IIO_ANGL, + .indexed = 1, + .channel = 1, + .scan_index = -1, + .event_spec = ad2s1210_position_event_spec, + .num_event_specs = ARRAY_SIZE(ad2s1210_position_event_spec), + }, { /* used to configure phase lock range and get phase lock error */ .type = IIO_PHASE, @@ -684,8 +817,6 @@ static struct attribute *ad2s1210_attributes[] = { &iio_dev_attr_dos_mis_thrd.dev_attr.attr, &iio_dev_attr_dos_rst_max_thrd.dev_attr.attr, &iio_dev_attr_dos_rst_min_thrd.dev_attr.attr, - &iio_dev_attr_lot_high_thrd.dev_attr.attr, - &iio_dev_attr_lot_low_thrd.dev_attr.attr, NULL, }; @@ -693,14 +824,40 @@ static const struct attribute_group ad2s1210_attribute_group = { .attrs = ad2s1210_attributes, }; +static ssize_t +in_angl1_thresh_rising_value_available_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct ad2s1210_state *st = iio_priv(dev_to_iio_dev(dev)); + int step = ad2s1210_lot_threshold_urad_per_lsb[st->resolution]; + + return sysfs_emit(buf, "[0 0.%06d 0.%06d]\n", step, step * 0x7F); +} + +static ssize_t +in_angl1_thresh_rising_hysteresis_available_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct ad2s1210_state *st = iio_priv(dev_to_iio_dev(dev)); + int step = ad2s1210_lot_threshold_urad_per_lsb[st->resolution]; + + return sysfs_emit(buf, "[0 0.%06d 0.%06d]\n", step, step * 0x7F); +} + static IIO_CONST_ATTR(in_phase0_mag_rising_value_available, __stringify(PHASE_44_DEG_TO_RAD_INT) "." __stringify(PHASE_44_DEG_TO_RAD_MICRO) " " __stringify(PHASE_360_DEG_TO_RAD_INT) "." __stringify(PHASE_360_DEG_TO_RAD_MICRO)); +static IIO_DEVICE_ATTR_RO(in_angl1_thresh_rising_value_available, 0); +static IIO_DEVICE_ATTR_RO(in_angl1_thresh_rising_hysteresis_available, 0); static struct attribute *ad2s1210_event_attributes[] = { &iio_const_attr_in_phase0_mag_rising_value_available.dev_attr.attr, + &iio_dev_attr_in_angl1_thresh_rising_value_available.dev_attr.attr, + &iio_dev_attr_in_angl1_thresh_rising_hysteresis_available.dev_attr.attr, NULL, }; @@ -742,6 +899,15 @@ static int ad2s1210_read_event_value(struct iio_dev *indio_dev, struct ad2s1210_state *st = iio_priv(indio_dev); switch (chan->type) { + case IIO_ANGL: + switch (info) { + case IIO_EV_INFO_VALUE: + return ad2s1210_get_lot_high_threshold(st, val, val2); + case IIO_EV_INFO_HYSTERESIS: + return ad2s1210_get_lot_low_threshold(st, val, val2); + default: + return -EINVAL; + } case IIO_PHASE: return ad2s1210_get_phase_lock_range(st, val, val2); default: @@ -759,6 +925,15 @@ static int ad2s1210_write_event_value(struct iio_dev *indio_dev, struct ad2s1210_state *st = iio_priv(indio_dev); switch (chan->type) { + case IIO_ANGL: + switch (info) { + case IIO_EV_INFO_VALUE: + return ad2s1210_set_lot_high_threshold(st, val, val2); + case IIO_EV_INFO_HYSTERESIS: + return ad2s1210_set_lot_low_threshold(st, val, val2); + default: + return -EINVAL; + } case IIO_PHASE: return ad2s1210_set_phase_lock_range(st, val, val2); default: From af8b284f23a600a86bb51a591d27e85d5f861b93 Mon Sep 17 00:00:00 2001 From: David Lechner Date: Thu, 5 Oct 2023 19:50:25 -0500 Subject: [PATCH 249/326] staging: iio: resolver: ad2s1210: convert LOS threshold to event attr The AD2S1210 has a programmable threshold for the loss of signal (LOS) fault. This fault is triggered when either the sine or cosine input falls below the threshold voltage. This patch converts the custom device LOS threshold attribute to an event falling edge threshold attribute on a new monitor signal channel. The monitor signal is an internal signal that combines the amplitudes of the sine and cosine inputs as well as the current angle and position output. This signal is used to detect faults in the input signals. The attribute now uses millivolts instead of the raw register value in accordance with the IIO ABI. Emitting the event will be implemented in a later patch. Signed-off-by: David Lechner Link: https://lore.kernel.org/r/20231005-ad2s1210-mainline-v4-8-ec00746840fc@baylibre.com Signed-off-by: Jonathan Cameron --- drivers/staging/iio/resolver/ad2s1210.c | 76 +++++++++++++++++++++++-- 1 file changed, 72 insertions(+), 4 deletions(-) diff --git a/drivers/staging/iio/resolver/ad2s1210.c b/drivers/staging/iio/resolver/ad2s1210.c index 12437f697f79..d52aed30ca66 100644 --- a/drivers/staging/iio/resolver/ad2s1210.c +++ b/drivers/staging/iio/resolver/ad2s1210.c @@ -66,6 +66,11 @@ #define PHASE_360_DEG_TO_RAD_INT 6 #define PHASE_360_DEG_TO_RAD_MICRO 283185 +/* Threshold voltage registers have 1 LSB == 38 mV */ +#define THRESHOLD_MILLIVOLT_PER_LSB 38 +/* max voltage for threshold registers is 0x7F * 38 mV */ +#define THRESHOLD_RANGE_STR "[0 38 4826]" + enum ad2s1210_mode { MOD_POS = 0b00, MOD_VEL = 0b01, @@ -451,6 +456,38 @@ static const int ad2s1210_lot_threshold_urad_per_lsb[] = { 1237, /* 16-bit: same as 14-bit */ }; +static int ad2s1210_get_voltage_threshold(struct ad2s1210_state *st, + unsigned int reg, int *val) +{ + unsigned int reg_val; + int ret; + + mutex_lock(&st->lock); + ret = regmap_read(st->regmap, reg, ®_val); + mutex_unlock(&st->lock); + + if (ret < 0) + return ret; + + *val = reg_val * THRESHOLD_MILLIVOLT_PER_LSB; + return IIO_VAL_INT; +} + +static int ad2s1210_set_voltage_threshold(struct ad2s1210_state *st, + unsigned int reg, int val) +{ + unsigned int reg_val; + int ret; + + reg_val = val / THRESHOLD_MILLIVOLT_PER_LSB; + + mutex_lock(&st->lock); + ret = regmap_write(st->regmap, reg, reg_val); + mutex_unlock(&st->lock); + + return ret; +} + static int ad2s1210_get_lot_high_threshold(struct ad2s1210_state *st, int *val, int *val2) { @@ -710,9 +747,6 @@ static int ad2s1210_write_raw(struct iio_dev *indio_dev, static IIO_DEVICE_ATTR(fault, 0644, ad2s1210_show_fault, ad2s1210_clear_fault, 0); -static IIO_DEVICE_ATTR(los_thrd, 0644, - ad2s1210_show_reg, ad2s1210_store_reg, - AD2S1210_REG_LOS_THRD); static IIO_DEVICE_ATTR(dos_ovr_thrd, 0644, ad2s1210_show_reg, ad2s1210_store_reg, AD2S1210_REG_DOS_OVR_THRD); @@ -749,6 +783,16 @@ static const struct iio_event_spec ad2s1210_phase_event_spec[] = { }, }; +static const struct iio_event_spec ad2s1210_monitor_signal_event_spec[] = { + { + /* Sine/cosine below LOS threshold fault. */ + .type = IIO_EV_TYPE_THRESH, + .dir = IIO_EV_DIR_FALLING, + /* Loss of signal threshold. */ + .mask_separate = BIT(IIO_EV_INFO_VALUE), + }, +}; + static const struct iio_chan_spec ad2s1210_channels[] = { { .type = IIO_ANGL, @@ -807,12 +851,19 @@ static const struct iio_chan_spec ad2s1210_channels[] = { .scan_index = -1, .info_mask_separate = BIT(IIO_CHAN_INFO_FREQUENCY), .info_mask_separate_available = BIT(IIO_CHAN_INFO_FREQUENCY), + }, { + /* monitor signal */ + .type = IIO_ALTVOLTAGE, + .indexed = 1, + .channel = 0, + .scan_index = -1, + .event_spec = ad2s1210_monitor_signal_event_spec, + .num_event_specs = ARRAY_SIZE(ad2s1210_monitor_signal_event_spec), }, }; static struct attribute *ad2s1210_attributes[] = { &iio_dev_attr_fault.dev_attr.attr, - &iio_dev_attr_los_thrd.dev_attr.attr, &iio_dev_attr_dos_ovr_thrd.dev_attr.attr, &iio_dev_attr_dos_mis_thrd.dev_attr.attr, &iio_dev_attr_dos_rst_max_thrd.dev_attr.attr, @@ -851,11 +902,14 @@ static IIO_CONST_ATTR(in_phase0_mag_rising_value_available, __stringify(PHASE_44_DEG_TO_RAD_MICRO) " " __stringify(PHASE_360_DEG_TO_RAD_INT) "." __stringify(PHASE_360_DEG_TO_RAD_MICRO)); +static IIO_CONST_ATTR(in_altvoltage0_thresh_falling_value_available, + THRESHOLD_RANGE_STR); static IIO_DEVICE_ATTR_RO(in_angl1_thresh_rising_value_available, 0); static IIO_DEVICE_ATTR_RO(in_angl1_thresh_rising_hysteresis_available, 0); static struct attribute *ad2s1210_event_attributes[] = { &iio_const_attr_in_phase0_mag_rising_value_available.dev_attr.attr, + &iio_const_attr_in_altvoltage0_thresh_falling_value_available.dev_attr.attr, &iio_dev_attr_in_angl1_thresh_rising_value_available.dev_attr.attr, &iio_dev_attr_in_angl1_thresh_rising_hysteresis_available.dev_attr.attr, NULL, @@ -908,6 +962,13 @@ static int ad2s1210_read_event_value(struct iio_dev *indio_dev, default: return -EINVAL; } + case IIO_ALTVOLTAGE: + if (chan->output) + return -EINVAL; + if (type == IIO_EV_TYPE_THRESH && dir == IIO_EV_DIR_FALLING) + return ad2s1210_get_voltage_threshold(st, + AD2S1210_REG_LOS_THRD, val); + return -EINVAL; case IIO_PHASE: return ad2s1210_get_phase_lock_range(st, val, val2); default: @@ -934,6 +995,13 @@ static int ad2s1210_write_event_value(struct iio_dev *indio_dev, default: return -EINVAL; } + case IIO_ALTVOLTAGE: + if (chan->output) + return -EINVAL; + if (type == IIO_EV_TYPE_THRESH && dir == IIO_EV_DIR_FALLING) + return ad2s1210_set_voltage_threshold(st, + AD2S1210_REG_LOS_THRD, val); + return -EINVAL; case IIO_PHASE: return ad2s1210_set_phase_lock_range(st, val, val2); default: From 6c5cc2b4a01e8e10d38bad17720ec55ae60a5299 Mon Sep 17 00:00:00 2001 From: David Lechner Date: Thu, 5 Oct 2023 19:50:26 -0500 Subject: [PATCH 250/326] staging: iio: resolver: ad2s1210: convert DOS overrange threshold to event attr The AD2S1210 has a programmable threshold for the degradation of signal (DOS) overrange fault. This fault is triggered when either the sine or cosine input rises above the threshold voltage. This patch converts the custom device DOS overrange threshold attribute to an event rising edge threshold attribute on the monitor signal channel. The attribute now uses millivolts instead of the raw register value in accordance with the IIO ABI. Emitting the event will be implemented in a later patch. Signed-off-by: David Lechner Link: https://lore.kernel.org/r/20231005-ad2s1210-mainline-v4-9-ec00746840fc@baylibre.com Signed-off-by: Jonathan Cameron --- drivers/staging/iio/resolver/ad2s1210.c | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/drivers/staging/iio/resolver/ad2s1210.c b/drivers/staging/iio/resolver/ad2s1210.c index d52aed30ca66..3c224bbeae17 100644 --- a/drivers/staging/iio/resolver/ad2s1210.c +++ b/drivers/staging/iio/resolver/ad2s1210.c @@ -747,9 +747,6 @@ static int ad2s1210_write_raw(struct iio_dev *indio_dev, static IIO_DEVICE_ATTR(fault, 0644, ad2s1210_show_fault, ad2s1210_clear_fault, 0); -static IIO_DEVICE_ATTR(dos_ovr_thrd, 0644, - ad2s1210_show_reg, ad2s1210_store_reg, - AD2S1210_REG_DOS_OVR_THRD); static IIO_DEVICE_ATTR(dos_mis_thrd, 0644, ad2s1210_show_reg, ad2s1210_store_reg, AD2S1210_REG_DOS_MIS_THRD); @@ -791,6 +788,13 @@ static const struct iio_event_spec ad2s1210_monitor_signal_event_spec[] = { /* Loss of signal threshold. */ .mask_separate = BIT(IIO_EV_INFO_VALUE), }, + { + /* Sine/cosine DOS overrange fault.*/ + .type = IIO_EV_TYPE_THRESH, + .dir = IIO_EV_DIR_RISING, + /* Degredation of signal overrange threshold. */ + .mask_separate = BIT(IIO_EV_INFO_VALUE), + }, }; static const struct iio_chan_spec ad2s1210_channels[] = { @@ -864,7 +868,6 @@ static const struct iio_chan_spec ad2s1210_channels[] = { static struct attribute *ad2s1210_attributes[] = { &iio_dev_attr_fault.dev_attr.attr, - &iio_dev_attr_dos_ovr_thrd.dev_attr.attr, &iio_dev_attr_dos_mis_thrd.dev_attr.attr, &iio_dev_attr_dos_rst_max_thrd.dev_attr.attr, &iio_dev_attr_dos_rst_min_thrd.dev_attr.attr, @@ -904,12 +907,15 @@ static IIO_CONST_ATTR(in_phase0_mag_rising_value_available, __stringify(PHASE_360_DEG_TO_RAD_MICRO)); static IIO_CONST_ATTR(in_altvoltage0_thresh_falling_value_available, THRESHOLD_RANGE_STR); +static IIO_CONST_ATTR(in_altvoltage0_thresh_rising_value_available, + THRESHOLD_RANGE_STR); static IIO_DEVICE_ATTR_RO(in_angl1_thresh_rising_value_available, 0); static IIO_DEVICE_ATTR_RO(in_angl1_thresh_rising_hysteresis_available, 0); static struct attribute *ad2s1210_event_attributes[] = { &iio_const_attr_in_phase0_mag_rising_value_available.dev_attr.attr, &iio_const_attr_in_altvoltage0_thresh_falling_value_available.dev_attr.attr, + &iio_const_attr_in_altvoltage0_thresh_rising_value_available.dev_attr.attr, &iio_dev_attr_in_angl1_thresh_rising_value_available.dev_attr.attr, &iio_dev_attr_in_angl1_thresh_rising_hysteresis_available.dev_attr.attr, NULL, @@ -968,6 +974,9 @@ static int ad2s1210_read_event_value(struct iio_dev *indio_dev, if (type == IIO_EV_TYPE_THRESH && dir == IIO_EV_DIR_FALLING) return ad2s1210_get_voltage_threshold(st, AD2S1210_REG_LOS_THRD, val); + if (type == IIO_EV_TYPE_THRESH && dir == IIO_EV_DIR_RISING) + return ad2s1210_get_voltage_threshold(st, + AD2S1210_REG_DOS_OVR_THRD, val); return -EINVAL; case IIO_PHASE: return ad2s1210_get_phase_lock_range(st, val, val2); @@ -1001,6 +1010,9 @@ static int ad2s1210_write_event_value(struct iio_dev *indio_dev, if (type == IIO_EV_TYPE_THRESH && dir == IIO_EV_DIR_FALLING) return ad2s1210_set_voltage_threshold(st, AD2S1210_REG_LOS_THRD, val); + if (type == IIO_EV_TYPE_THRESH && dir == IIO_EV_DIR_RISING) + return ad2s1210_set_voltage_threshold(st, + AD2S1210_REG_DOS_OVR_THRD, val); return -EINVAL; case IIO_PHASE: return ad2s1210_set_phase_lock_range(st, val, val2); From e025cb2c684827ffde62f99dd7c911540136b347 Mon Sep 17 00:00:00 2001 From: David Lechner Date: Thu, 5 Oct 2023 19:50:27 -0500 Subject: [PATCH 251/326] staging: iio: resolver: ad2s1210: convert DOS mismatch threshold to event attr The AD2S1210 has a programmable threshold for the degradation of signal (DOS) mismatch fault. This fault is triggered when the difference in voltage between the sine and cosine inputs exceeds the threshold. In other words, when the magnitude of sine and cosine inputs are equal, the AC component of the monitor signal is zero and when the magnitudes of the sine and cosine inputs are not equal, the AC component of the monitor signal is the difference between the sine and cosine inputs. So the fault occurs when the magnitude of the AC component of the monitor signal exceeds the DOS mismatch threshold voltage. This patch converts the custom device DOS mismatch threshold attribute to an event magnitude attribute on the monitor signal channel. The attribute now uses millivolts instead of the raw register value in accordance with the IIO ABI. Emitting the event will be implemented in a later patch. Signed-off-by: David Lechner Link: https://lore.kernel.org/r/20231005-ad2s1210-mainline-v4-10-ec00746840fc@baylibre.com Signed-off-by: Jonathan Cameron --- drivers/staging/iio/resolver/ad2s1210.c | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/drivers/staging/iio/resolver/ad2s1210.c b/drivers/staging/iio/resolver/ad2s1210.c index 3c224bbeae17..870c4a9a6214 100644 --- a/drivers/staging/iio/resolver/ad2s1210.c +++ b/drivers/staging/iio/resolver/ad2s1210.c @@ -747,9 +747,6 @@ static int ad2s1210_write_raw(struct iio_dev *indio_dev, static IIO_DEVICE_ATTR(fault, 0644, ad2s1210_show_fault, ad2s1210_clear_fault, 0); -static IIO_DEVICE_ATTR(dos_mis_thrd, 0644, - ad2s1210_show_reg, ad2s1210_store_reg, - AD2S1210_REG_DOS_MIS_THRD); static IIO_DEVICE_ATTR(dos_rst_max_thrd, 0644, ad2s1210_show_reg, ad2s1210_store_reg, AD2S1210_REG_DOS_RST_MAX_THRD); @@ -795,6 +792,12 @@ static const struct iio_event_spec ad2s1210_monitor_signal_event_spec[] = { /* Degredation of signal overrange threshold. */ .mask_separate = BIT(IIO_EV_INFO_VALUE), }, + { + /* Sine/cosine DOS mismatch fault.*/ + .type = IIO_EV_TYPE_MAG, + .dir = IIO_EV_DIR_RISING, + .mask_separate = BIT(IIO_EV_INFO_VALUE), + }, }; static const struct iio_chan_spec ad2s1210_channels[] = { @@ -868,7 +871,6 @@ static const struct iio_chan_spec ad2s1210_channels[] = { static struct attribute *ad2s1210_attributes[] = { &iio_dev_attr_fault.dev_attr.attr, - &iio_dev_attr_dos_mis_thrd.dev_attr.attr, &iio_dev_attr_dos_rst_max_thrd.dev_attr.attr, &iio_dev_attr_dos_rst_min_thrd.dev_attr.attr, NULL, @@ -909,6 +911,8 @@ static IIO_CONST_ATTR(in_altvoltage0_thresh_falling_value_available, THRESHOLD_RANGE_STR); static IIO_CONST_ATTR(in_altvoltage0_thresh_rising_value_available, THRESHOLD_RANGE_STR); +static IIO_CONST_ATTR(in_altvoltage0_mag_rising_value_available, + THRESHOLD_RANGE_STR); static IIO_DEVICE_ATTR_RO(in_angl1_thresh_rising_value_available, 0); static IIO_DEVICE_ATTR_RO(in_angl1_thresh_rising_hysteresis_available, 0); @@ -916,6 +920,7 @@ static struct attribute *ad2s1210_event_attributes[] = { &iio_const_attr_in_phase0_mag_rising_value_available.dev_attr.attr, &iio_const_attr_in_altvoltage0_thresh_falling_value_available.dev_attr.attr, &iio_const_attr_in_altvoltage0_thresh_rising_value_available.dev_attr.attr, + &iio_const_attr_in_altvoltage0_mag_rising_value_available.dev_attr.attr, &iio_dev_attr_in_angl1_thresh_rising_value_available.dev_attr.attr, &iio_dev_attr_in_angl1_thresh_rising_hysteresis_available.dev_attr.attr, NULL, @@ -977,6 +982,9 @@ static int ad2s1210_read_event_value(struct iio_dev *indio_dev, if (type == IIO_EV_TYPE_THRESH && dir == IIO_EV_DIR_RISING) return ad2s1210_get_voltage_threshold(st, AD2S1210_REG_DOS_OVR_THRD, val); + if (type == IIO_EV_TYPE_MAG) + return ad2s1210_get_voltage_threshold(st, + AD2S1210_REG_DOS_MIS_THRD, val); return -EINVAL; case IIO_PHASE: return ad2s1210_get_phase_lock_range(st, val, val2); @@ -1013,6 +1021,9 @@ static int ad2s1210_write_event_value(struct iio_dev *indio_dev, if (type == IIO_EV_TYPE_THRESH && dir == IIO_EV_DIR_RISING) return ad2s1210_set_voltage_threshold(st, AD2S1210_REG_DOS_OVR_THRD, val); + if (type == IIO_EV_TYPE_MAG) + return ad2s1210_set_voltage_threshold(st, + AD2S1210_REG_DOS_MIS_THRD, val); return -EINVAL; case IIO_PHASE: return ad2s1210_set_phase_lock_range(st, val, val2); From 86a333c59806bc170156209e9a52c6393d00c652 Mon Sep 17 00:00:00 2001 From: David Lechner Date: Thu, 5 Oct 2023 19:50:28 -0500 Subject: [PATCH 252/326] staging: iio: resolver: ad2s1210: rename DOS reset min/max attrs The AD2S1210 has a programmable threshold for the degradation of signal (DOS) mismatch fault. This fault is triggered when the difference in amplitude between the sine and cosine inputs exceeds the threshold. The DOS reset min/max registers on the chip provide initial values for internal tracking of the min/max of the monitor signal after the fault register is cleared. This patch converts the custom device DOS reset min/max threshold attributes custom event attributes on the monitor signal channel. The attributes now use millivolts instead of the raw register value in accordance with the IIO ABI. Signed-off-by: David Lechner Link: https://lore.kernel.org/r/20231005-ad2s1210-mainline-v4-11-ec00746840fc@baylibre.com Signed-off-by: Jonathan Cameron --- .../sysfs-bus-iio-resolver-ad2s1210 | 27 +++++ drivers/staging/iio/resolver/ad2s1210.c | 99 ++++++++++--------- 2 files changed, 82 insertions(+), 44 deletions(-) create mode 100644 drivers/staging/iio/Documentation/sysfs-bus-iio-resolver-ad2s1210 diff --git a/drivers/staging/iio/Documentation/sysfs-bus-iio-resolver-ad2s1210 b/drivers/staging/iio/Documentation/sysfs-bus-iio-resolver-ad2s1210 new file mode 100644 index 000000000000..f92c79342b93 --- /dev/null +++ b/drivers/staging/iio/Documentation/sysfs-bus-iio-resolver-ad2s1210 @@ -0,0 +1,27 @@ +What: /sys/bus/iio/devices/iio:deviceX/events/in_altvoltage0_mag_rising_reset_max +KernelVersion: 6.7 +Contact: linux-iio@vger.kernel.org +Description: + Reading returns the current Degradation of Signal Reset Maximum + Threshold value in millivolts. Writing sets the value. + +What: /sys/bus/iio/devices/iio:deviceX/events/in_altvoltage0_mag_rising_reset_max_available +KernelVersion: 6.7 +Contact: linux-iio@vger.kernel.org +Description: + Reading returns the allowable voltage range for + in_altvoltage0_mag_rising_reset_max. + +What: /sys/bus/iio/devices/iio:deviceX/events/in_altvoltage0_mag_rising_reset_min +KernelVersion: 6.7 +Contact: linux-iio@vger.kernel.org +Description: + Reading returns the current Degradation of Signal Reset Minimum + Threshold value in millivolts. Writing sets the value. + +What: /sys/bus/iio/devices/iio:deviceX/events/in_altvoltage0_mag_rising_reset_min_available +KernelVersion: 6.7 +Contact: linux-iio@vger.kernel.org +Description: + Reading returns the allowable voltage range for + in_altvoltage0_mag_rising_reset_min. diff --git a/drivers/staging/iio/resolver/ad2s1210.c b/drivers/staging/iio/resolver/ad2s1210.c index 870c4a9a6214..9fac806c2a5f 100644 --- a/drivers/staging/iio/resolver/ad2s1210.c +++ b/drivers/staging/iio/resolver/ad2s1210.c @@ -286,41 +286,6 @@ error_ret: return ret < 0 ? ret : len; } -static ssize_t ad2s1210_show_reg(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - struct ad2s1210_state *st = iio_priv(dev_to_iio_dev(dev)); - struct iio_dev_attr *iattr = to_iio_dev_attr(attr); - unsigned int value; - int ret; - - mutex_lock(&st->lock); - ret = regmap_read(st->regmap, iattr->address, &value); - mutex_unlock(&st->lock); - - return ret < 0 ? ret : sprintf(buf, "%d\n", value); -} - -static ssize_t ad2s1210_store_reg(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t len) -{ - struct ad2s1210_state *st = iio_priv(dev_to_iio_dev(dev)); - unsigned char data; - int ret; - struct iio_dev_attr *iattr = to_iio_dev_attr(attr); - - ret = kstrtou8(buf, 10, &data); - if (ret) - return -EINVAL; - - mutex_lock(&st->lock); - ret = regmap_write(st->regmap, iattr->address, data); - mutex_unlock(&st->lock); - return ret < 0 ? ret : len; -} - static int ad2s1210_single_conversion(struct ad2s1210_state *st, struct iio_chan_spec const *chan, int *val) @@ -747,13 +712,6 @@ static int ad2s1210_write_raw(struct iio_dev *indio_dev, static IIO_DEVICE_ATTR(fault, 0644, ad2s1210_show_fault, ad2s1210_clear_fault, 0); -static IIO_DEVICE_ATTR(dos_rst_max_thrd, 0644, - ad2s1210_show_reg, ad2s1210_store_reg, - AD2S1210_REG_DOS_RST_MAX_THRD); -static IIO_DEVICE_ATTR(dos_rst_min_thrd, 0644, - ad2s1210_show_reg, ad2s1210_store_reg, - AD2S1210_REG_DOS_RST_MIN_THRD); - static const struct iio_event_spec ad2s1210_position_event_spec[] = { { /* Tracking error exceeds LOT threshold fault. */ @@ -871,8 +829,6 @@ static const struct iio_chan_spec ad2s1210_channels[] = { static struct attribute *ad2s1210_attributes[] = { &iio_dev_attr_fault.dev_attr.attr, - &iio_dev_attr_dos_rst_max_thrd.dev_attr.attr, - &iio_dev_attr_dos_rst_min_thrd.dev_attr.attr, NULL, }; @@ -880,6 +836,49 @@ static const struct attribute_group ad2s1210_attribute_group = { .attrs = ad2s1210_attributes, }; +static ssize_t event_attr_voltage_reg_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct ad2s1210_state *st = iio_priv(dev_to_iio_dev(dev)); + struct iio_dev_attr *iattr = to_iio_dev_attr(attr); + unsigned int value; + int ret; + + mutex_lock(&st->lock); + ret = regmap_read(st->regmap, iattr->address, &value); + mutex_unlock(&st->lock); + + if (ret < 0) + return ret; + + return sprintf(buf, "%d\n", value * THRESHOLD_MILLIVOLT_PER_LSB); +} + +static ssize_t event_attr_voltage_reg_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t len) +{ + struct ad2s1210_state *st = iio_priv(dev_to_iio_dev(dev)); + struct iio_dev_attr *iattr = to_iio_dev_attr(attr); + u16 data; + int ret; + + ret = kstrtou16(buf, 10, &data); + if (ret) + return -EINVAL; + + mutex_lock(&st->lock); + ret = regmap_write(st->regmap, iattr->address, + data / THRESHOLD_MILLIVOLT_PER_LSB); + mutex_unlock(&st->lock); + + if (ret < 0) + return ret; + + return len; +} + static ssize_t in_angl1_thresh_rising_value_available_show(struct device *dev, struct device_attribute *attr, @@ -913,6 +912,14 @@ static IIO_CONST_ATTR(in_altvoltage0_thresh_rising_value_available, THRESHOLD_RANGE_STR); static IIO_CONST_ATTR(in_altvoltage0_mag_rising_value_available, THRESHOLD_RANGE_STR); +static IIO_DEVICE_ATTR(in_altvoltage0_mag_rising_reset_max, 0644, + event_attr_voltage_reg_show, event_attr_voltage_reg_store, + AD2S1210_REG_DOS_RST_MAX_THRD); +static IIO_CONST_ATTR(in_altvoltage0_mag_rising_reset_max_available, THRESHOLD_RANGE_STR); +static IIO_DEVICE_ATTR(in_altvoltage0_mag_rising_reset_min, 0644, + event_attr_voltage_reg_show, event_attr_voltage_reg_store, + AD2S1210_REG_DOS_RST_MIN_THRD); +static IIO_CONST_ATTR(in_altvoltage0_mag_rising_reset_min_available, THRESHOLD_RANGE_STR); static IIO_DEVICE_ATTR_RO(in_angl1_thresh_rising_value_available, 0); static IIO_DEVICE_ATTR_RO(in_angl1_thresh_rising_hysteresis_available, 0); @@ -921,6 +928,10 @@ static struct attribute *ad2s1210_event_attributes[] = { &iio_const_attr_in_altvoltage0_thresh_falling_value_available.dev_attr.attr, &iio_const_attr_in_altvoltage0_thresh_rising_value_available.dev_attr.attr, &iio_const_attr_in_altvoltage0_mag_rising_value_available.dev_attr.attr, + &iio_dev_attr_in_altvoltage0_mag_rising_reset_max.dev_attr.attr, + &iio_const_attr_in_altvoltage0_mag_rising_reset_max_available.dev_attr.attr, + &iio_dev_attr_in_altvoltage0_mag_rising_reset_min.dev_attr.attr, + &iio_const_attr_in_altvoltage0_mag_rising_reset_min_available.dev_attr.attr, &iio_dev_attr_in_angl1_thresh_rising_value_available.dev_attr.attr, &iio_dev_attr_in_angl1_thresh_rising_hysteresis_available.dev_attr.attr, NULL, From 5987279373446e97206a7078b2229446ba871ea0 Mon Sep 17 00:00:00 2001 From: David Lechner Date: Thu, 5 Oct 2023 19:50:29 -0500 Subject: [PATCH 253/326] iio: event: add optional event label support This adds a new optional field to struct iio_info to allow drivers to specify a label for the event. This is useful for cases where there are many events or the event attribute name is not descriptive enough or where an event doesn't have any other attributes. The implementation is based on the existing label support for channels. So either all events of a device have a label attribute or none do. Signed-off-by: David Lechner Link: https://lore.kernel.org/r/20231005-ad2s1210-mainline-v4-12-ec00746840fc@baylibre.com Signed-off-by: Jonathan Cameron --- drivers/iio/industrialio-event.c | 55 ++++++++++++++++++++++++++++++++ include/linux/iio/iio.h | 8 +++++ 2 files changed, 63 insertions(+) diff --git a/drivers/iio/industrialio-event.c b/drivers/iio/industrialio-event.c index 19f7a91157ee..910c1f14abd5 100644 --- a/drivers/iio/industrialio-event.c +++ b/drivers/iio/industrialio-event.c @@ -355,6 +355,21 @@ static ssize_t iio_ev_value_store(struct device *dev, return len; } +static ssize_t iio_ev_label_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct iio_dev *indio_dev = dev_to_iio_dev(dev); + struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); + + if (indio_dev->info->read_event_label) + return indio_dev->info->read_event_label(indio_dev, + this_attr->c, iio_ev_attr_type(this_attr), + iio_ev_attr_dir(this_attr), buf); + + return -EINVAL; +} + static int iio_device_add_event(struct iio_dev *indio_dev, const struct iio_chan_spec *chan, unsigned int spec_index, enum iio_event_type type, enum iio_event_direction dir, @@ -411,6 +426,41 @@ static int iio_device_add_event(struct iio_dev *indio_dev, return attrcount; } +static int iio_device_add_event_label(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, + unsigned int spec_index, + enum iio_event_type type, + enum iio_event_direction dir) +{ + struct iio_dev_opaque *iio_dev_opaque = to_iio_dev_opaque(indio_dev); + char *postfix; + int ret; + + if (!indio_dev->info->read_event_label) + return 0; + + if (dir != IIO_EV_DIR_NONE) + postfix = kasprintf(GFP_KERNEL, "%s_%s_label", + iio_ev_type_text[type], + iio_ev_dir_text[dir]); + else + postfix = kasprintf(GFP_KERNEL, "%s_label", + iio_ev_type_text[type]); + if (postfix == NULL) + return -ENOMEM; + + ret = __iio_add_chan_devattr(postfix, chan, &iio_ev_label_show, NULL, + spec_index, IIO_SEPARATE, &indio_dev->dev, NULL, + &iio_dev_opaque->event_interface->dev_attr_list); + + kfree(postfix); + + if (ret < 0) + return ret; + + return 1; +} + static int iio_device_add_event_sysfs(struct iio_dev *indio_dev, struct iio_chan_spec const *chan) { @@ -448,6 +498,11 @@ static int iio_device_add_event_sysfs(struct iio_dev *indio_dev, if (ret < 0) return ret; attrcount += ret; + + ret = iio_device_add_event_label(indio_dev, chan, i, type, dir); + if (ret < 0) + return ret; + attrcount += ret; } ret = attrcount; return ret; diff --git a/include/linux/iio/iio.h b/include/linux/iio/iio.h index 7bfa1b9bc8a2..d0ce3b71106a 100644 --- a/include/linux/iio/iio.h +++ b/include/linux/iio/iio.h @@ -427,6 +427,8 @@ struct iio_trigger; /* forward declaration */ * @write_event_config: set if the event is enabled. * @read_event_value: read a configuration value associated with the event. * @write_event_value: write a configuration value for the event. + * @read_event_label: function to request label name for a specified label, + * for better event identification. * @validate_trigger: function to validate the trigger when the * current trigger gets changed. * @update_scan_mode: function to configure device and scan buffer when @@ -511,6 +513,12 @@ struct iio_info { enum iio_event_direction dir, enum iio_event_info info, int val, int val2); + int (*read_event_label)(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + enum iio_event_type type, + enum iio_event_direction dir, + char *label); + int (*validate_trigger)(struct iio_dev *indio_dev, struct iio_trigger *trig); int (*update_scan_mode)(struct iio_dev *indio_dev, From a5101e91e94d4f12e402fb4e8b46caa0213ea03a Mon Sep 17 00:00:00 2001 From: David Lechner Date: Thu, 5 Oct 2023 19:50:30 -0500 Subject: [PATCH 254/326] staging: iio: resolver: ad2s1210: implement fault events When reading the position and velocity on the AD2S1210, there is also a 3rd byte following the two data bytes that contains the fault flag bits. This patch adds support for reading this byte and generating events when faults occur. The faults are mapped to various channels and event type in order to have a unique event for each fault. Signed-off-by: David Lechner Link: https://lore.kernel.org/r/20231005-ad2s1210-mainline-v4-13-ec00746840fc@baylibre.com Signed-off-by: Jonathan Cameron --- Documentation/ABI/testing/sysfs-bus-iio | 15 ++ drivers/staging/iio/resolver/ad2s1210.c | 211 ++++++++++++++++++++++-- 2 files changed, 212 insertions(+), 14 deletions(-) diff --git a/Documentation/ABI/testing/sysfs-bus-iio b/Documentation/ABI/testing/sysfs-bus-iio index 8e13642bbe23..19cde14f3869 100644 --- a/Documentation/ABI/testing/sysfs-bus-iio +++ b/Documentation/ABI/testing/sysfs-bus-iio @@ -2239,3 +2239,18 @@ Contact: linux-iio@vger.kernel.org Description: The x and y light color coordinate on the CIE 1931 chromaticity diagram. + +What: /sys/bus/iio/devices/iio:deviceX/events/in_altvoltageY_mag_either_label +What: /sys/bus/iio/devices/iio:deviceX/events/in_altvoltageY_mag_rising_label +What: /sys/bus/iio/devices/iio:deviceX/events/in_altvoltageY_thresh_falling_label +What: /sys/bus/iio/devices/iio:deviceX/events/in_altvoltageY_thresh_rising_label +What: /sys/bus/iio/devices/iio:deviceX/events/in_anglvelY_mag_rising_label +What: /sys/bus/iio/devices/iio:deviceX/events/in_anglY_thresh_rising_label +What: /sys/bus/iio/devices/iio:deviceX/events/in_phaseY_mag_rising_label +KernelVersion: 6.7 +Contact: linux-iio@vger.kernel.org +Description: + Optional symbolic label to a device channel event. + If a label is defined for this event add that to the event + specific attributes. This is useful for userspace to be able to + better identify an individual event. diff --git a/drivers/staging/iio/resolver/ad2s1210.c b/drivers/staging/iio/resolver/ad2s1210.c index 9fac806c2a5f..f3f26b1438c0 100644 --- a/drivers/staging/iio/resolver/ad2s1210.c +++ b/drivers/staging/iio/resolver/ad2s1210.c @@ -21,6 +21,7 @@ #include #include +#include #include #include #include @@ -35,6 +36,16 @@ #define AD2S1210_SET_ENRES GENMASK(3, 2) #define AD2S1210_SET_RES GENMASK(1, 0) +/* fault register flags */ +#define AD2S1210_FAULT_CLIP BIT(7) +#define AD2S1210_FAULT_LOS BIT(6) +#define AD2S1210_FAULT_DOS_OVR BIT(5) +#define AD2S1210_FAULT_DOS_MIS BIT(4) +#define AD2S1210_FAULT_LOT BIT(3) +#define AD2S1210_FAULT_VELOCITY BIT(2) +#define AD2S1210_FAULT_PHASE BIT(1) +#define AD2S1210_FAULT_CONFIG_PARITY BIT(0) + #define AD2S1210_REG_POSITION_MSB 0x80 #define AD2S1210_REG_POSITION_LSB 0x81 #define AD2S1210_REG_VELOCITY_MSB 0x82 @@ -71,6 +82,8 @@ /* max voltage for threshold registers is 0x7F * 38 mV */ #define THRESHOLD_RANGE_STR "[0 38 4826]" +#define FAULT_ONESHOT(bit, new, old) (new & bit && !(old & bit)) + enum ad2s1210_mode { MOD_POS = 0b00, MOD_VEL = 0b01, @@ -100,8 +113,13 @@ struct ad2s1210_state { int hysteresis_available[2]; /** The selected resolution */ enum ad2s1210_resolution resolution; + /** Copy of fault register from the previous read. */ + u8 prev_fault_flags; /** For reading raw sample value via SPI. */ - __be16 sample __aligned(IIO_DMA_MINALIGN); + struct { + __be16 raw; + u8 fault; + } sample __aligned(IIO_DMA_MINALIGN); /** Scan buffer */ struct { __be16 chan[2]; @@ -160,7 +178,15 @@ static int ad2s1210_regmap_reg_write(void *context, unsigned int reg, if (ret < 0) return ret; - return spi_sync_transfer(st->sdev, xfers, ARRAY_SIZE(xfers)); + ret = spi_sync_transfer(st->sdev, xfers, ARRAY_SIZE(xfers)); + if (ret < 0) + return ret; + + /* soft reset also clears the fault register */ + if (reg == AD2S1210_REG_SOFT_RESET) + st->prev_fault_flags = 0; + + return 0; } /* @@ -203,6 +229,10 @@ static int ad2s1210_regmap_reg_read(void *context, unsigned int reg, if (ret < 0) return ret; + /* reading the fault register also clears it */ + if (reg == AD2S1210_REG_FAULT) + st->prev_fault_flags = 0; + /* * If the D7 bit is set on any read/write register, it indicates a * parity error. The fault register is read-only and the D7 bit means @@ -286,14 +316,101 @@ error_ret: return ret < 0 ? ret : len; } -static int ad2s1210_single_conversion(struct ad2s1210_state *st, +static void ad2s1210_push_events(struct iio_dev *indio_dev, + u8 flags, s64 timestamp) +{ + struct ad2s1210_state *st = iio_priv(indio_dev); + + /* Sine/cosine inputs clipped */ + if (FAULT_ONESHOT(AD2S1210_FAULT_CLIP, flags, st->prev_fault_flags)) { + /* + * The chip does not differentiate between fault on sine vs. + * cosine channel so we just send an event on both channels. + */ + iio_push_event(indio_dev, + IIO_UNMOD_EVENT_CODE(IIO_ALTVOLTAGE, 1, + IIO_EV_TYPE_MAG, + IIO_EV_DIR_EITHER), + timestamp); + iio_push_event(indio_dev, + IIO_UNMOD_EVENT_CODE(IIO_ALTVOLTAGE, 2, + IIO_EV_TYPE_MAG, + IIO_EV_DIR_EITHER), + timestamp); + } + + /* Sine/cosine inputs below LOS threshold */ + if (FAULT_ONESHOT(AD2S1210_FAULT_LOS, flags, st->prev_fault_flags)) + iio_push_event(indio_dev, + IIO_UNMOD_EVENT_CODE(IIO_ALTVOLTAGE, 0, + IIO_EV_TYPE_THRESH, + IIO_EV_DIR_FALLING), + timestamp); + + /* Sine/cosine inputs exceed DOS overrange threshold */ + if (FAULT_ONESHOT(AD2S1210_FAULT_DOS_OVR, flags, st->prev_fault_flags)) + iio_push_event(indio_dev, + IIO_UNMOD_EVENT_CODE(IIO_ALTVOLTAGE, 0, + IIO_EV_TYPE_THRESH, + IIO_EV_DIR_RISING), + timestamp); + + /* Sine/cosine inputs exceed DOS mismatch threshold */ + if (FAULT_ONESHOT(AD2S1210_FAULT_DOS_MIS, flags, st->prev_fault_flags)) + iio_push_event(indio_dev, + IIO_UNMOD_EVENT_CODE(IIO_ALTVOLTAGE, 0, + IIO_EV_TYPE_MAG, + IIO_EV_DIR_RISING), + timestamp); + + /* Tracking error exceeds LOT threshold */ + if (FAULT_ONESHOT(AD2S1210_FAULT_LOT, flags, st->prev_fault_flags)) + iio_push_event(indio_dev, + IIO_UNMOD_EVENT_CODE(IIO_ANGL, 1, + IIO_EV_TYPE_THRESH, + IIO_EV_DIR_RISING), + timestamp); + + /* Velocity exceeds maximum tracking rate */ + if (FAULT_ONESHOT(AD2S1210_FAULT_VELOCITY, flags, st->prev_fault_flags)) + iio_push_event(indio_dev, + IIO_UNMOD_EVENT_CODE(IIO_ANGL_VEL, 0, + IIO_EV_TYPE_THRESH, + IIO_EV_DIR_RISING), + timestamp); + + /* Phase error exceeds phase lock range */ + if (FAULT_ONESHOT(AD2S1210_FAULT_PHASE, flags, st->prev_fault_flags)) + iio_push_event(indio_dev, + IIO_UNMOD_EVENT_CODE(IIO_PHASE, 0, + IIO_EV_TYPE_MAG, + IIO_EV_DIR_RISING), + timestamp); + + /* Configuration parity error */ + if (FAULT_ONESHOT(AD2S1210_FAULT_CONFIG_PARITY, flags, + st->prev_fault_flags)) + /* + * Userspace should also get notified of this via error return + * when trying to write to any attribute that writes a register. + */ + dev_err_ratelimited(&indio_dev->dev, + "Configuration parity error\n"); + + st->prev_fault_flags = flags; +} + +static int ad2s1210_single_conversion(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, int *val) { + struct ad2s1210_state *st = iio_priv(indio_dev); + s64 timestamp; int ret; mutex_lock(&st->lock); gpiod_set_value(st->sample_gpio, 1); + timestamp = iio_get_time_ns(indio_dev); /* delay (6 * tck + 20) nano seconds */ udelay(1); @@ -310,17 +427,17 @@ static int ad2s1210_single_conversion(struct ad2s1210_state *st, } if (ret < 0) goto error_ret; - ret = spi_read(st->sdev, &st->sample, 2); + ret = spi_read(st->sdev, &st->sample, 3); if (ret < 0) goto error_ret; switch (chan->type) { case IIO_ANGL: - *val = be16_to_cpu(st->sample); + *val = be16_to_cpu(st->sample.raw); ret = IIO_VAL_INT; break; case IIO_ANGL_VEL: - *val = (s16)be16_to_cpu(st->sample); + *val = (s16)be16_to_cpu(st->sample.raw); ret = IIO_VAL_INT; break; default: @@ -328,6 +445,8 @@ static int ad2s1210_single_conversion(struct ad2s1210_state *st, break; } + ad2s1210_push_events(indio_dev, st->sample.fault, timestamp); + error_ret: gpiod_set_value(st->sample_gpio, 0); /* delay (2 * tck + 20) nano seconds */ @@ -611,7 +730,7 @@ static int ad2s1210_read_raw(struct iio_dev *indio_dev, switch (mask) { case IIO_CHAN_INFO_RAW: - return ad2s1210_single_conversion(st, chan, val); + return ad2s1210_single_conversion(indio_dev, chan, val); case IIO_CHAN_INFO_SCALE: switch (chan->type) { case IIO_ANGL: @@ -725,6 +844,14 @@ static const struct iio_event_spec ad2s1210_position_event_spec[] = { }, }; +static const struct iio_event_spec ad2s1210_velocity_event_spec[] = { + { + /* Velocity exceeds maximum tracking rate fault. */ + .type = IIO_EV_TYPE_MAG, + .dir = IIO_EV_DIR_RISING, + }, +}; + static const struct iio_event_spec ad2s1210_phase_event_spec[] = { { /* Phase error fault. */ @@ -758,6 +885,14 @@ static const struct iio_event_spec ad2s1210_monitor_signal_event_spec[] = { }, }; +static const struct iio_event_spec ad2s1210_sin_cos_event_spec[] = { + { + /* Sine/cosine clipping fault. */ + .type = IIO_EV_TYPE_MAG, + .dir = IIO_EV_DIR_EITHER, + }, +}; + static const struct iio_chan_spec ad2s1210_channels[] = { { .type = IIO_ANGL, @@ -788,6 +923,8 @@ static const struct iio_chan_spec ad2s1210_channels[] = { }, .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE), + .event_spec = ad2s1210_velocity_event_spec, + .num_event_specs = ARRAY_SIZE(ad2s1210_velocity_event_spec), }, IIO_CHAN_SOFT_TIMESTAMP(2), { @@ -824,6 +961,22 @@ static const struct iio_chan_spec ad2s1210_channels[] = { .scan_index = -1, .event_spec = ad2s1210_monitor_signal_event_spec, .num_event_specs = ARRAY_SIZE(ad2s1210_monitor_signal_event_spec), + }, { + /* sine input */ + .type = IIO_ALTVOLTAGE, + .indexed = 1, + .channel = 1, + .scan_index = -1, + .event_spec = ad2s1210_sin_cos_event_spec, + .num_event_specs = ARRAY_SIZE(ad2s1210_sin_cos_event_spec), + }, { + /* cosine input */ + .type = IIO_ALTVOLTAGE, + .indexed = 1, + .channel = 2, + .scan_index = -1, + .event_spec = ad2s1210_sin_cos_event_spec, + .num_event_specs = ARRAY_SIZE(ad2s1210_sin_cos_event_spec), }, }; @@ -943,7 +1096,7 @@ static const struct attribute_group ad2s1210_event_attribute_group = { static int ad2s1210_initial(struct ad2s1210_state *st) { - unsigned char data; + unsigned int data; int ret; mutex_lock(&st->lock); @@ -1043,6 +1196,36 @@ static int ad2s1210_write_event_value(struct iio_dev *indio_dev, } } +static int ad2s1210_read_event_label(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + enum iio_event_type type, + enum iio_event_direction dir, + char *label) +{ + if (chan->type == IIO_ANGL) + return sprintf(label, "LOT\n"); + if (chan->type == IIO_ANGL_VEL) + return sprintf(label, "max tracking rate\n"); + if (chan->type == IIO_PHASE) + return sprintf(label, "phase lock\n"); + if (chan->type == IIO_ALTVOLTAGE) { + if (chan->channel == 0) { + if (type == IIO_EV_TYPE_THRESH && + dir == IIO_EV_DIR_FALLING) + return sprintf(label, "LOS\n"); + if (type == IIO_EV_TYPE_THRESH && + dir == IIO_EV_DIR_RISING) + return sprintf(label, "DOS overrange\n"); + if (type == IIO_EV_TYPE_MAG) + return sprintf(label, "DOS mismatch\n"); + } + if (chan->channel == 1 || chan->channel == 2) + return sprintf(label, "clipped\n"); + } + + return -EINVAL; +} + static int ad2s1210_debugfs_reg_access(struct iio_dev *indio_dev, unsigned int reg, unsigned int writeval, unsigned int *readval) @@ -1080,12 +1263,11 @@ static irqreturn_t ad2s1210_trigger_handler(int irq, void *p) if (ret < 0) goto error_ret; - /* REVIST: we can read 3 bytes here and also get fault flags */ - ret = spi_read(st->sdev, st->rx, 2); + ret = spi_read(st->sdev, &st->sample, 3); if (ret < 0) goto error_ret; - memcpy(&st->scan.chan[chan++], st->rx, 2); + memcpy(&st->scan.chan[chan++], &st->sample.raw, 2); } if (test_bit(1, indio_dev->active_scan_mask)) { @@ -1093,14 +1275,14 @@ static irqreturn_t ad2s1210_trigger_handler(int irq, void *p) if (ret < 0) goto error_ret; - /* REVIST: we can read 3 bytes here and also get fault flags */ - ret = spi_read(st->sdev, st->rx, 2); + ret = spi_read(st->sdev, &st->sample, 3); if (ret < 0) goto error_ret; - memcpy(&st->scan.chan[chan++], st->rx, 2); + memcpy(&st->scan.chan[chan++], &st->sample.raw, 2); } + ad2s1210_push_events(indio_dev, st->sample.fault, pf->timestamp); iio_push_to_buffers_with_timestamp(indio_dev, &st->scan, pf->timestamp); error_ret: @@ -1119,6 +1301,7 @@ static const struct iio_info ad2s1210_info = { .attrs = &ad2s1210_attribute_group, .read_event_value = ad2s1210_read_event_value, .write_event_value = ad2s1210_write_event_value, + .read_event_label = ad2s1210_read_event_label, .debugfs_reg_access = &ad2s1210_debugfs_reg_access, }; From 1638b6d4f7c9515a6c26b2401ab3624fcef20916 Mon Sep 17 00:00:00 2001 From: David Lechner Date: Thu, 5 Oct 2023 19:50:31 -0500 Subject: [PATCH 255/326] staging: iio: resolver: ad2s1210: add register/fault support summary The ad2s1210 driver shoe-horns the register and fault support into IIO events. The mapping between the registers/faults and the events is not obvious. To save users from having to read the entire driver to figure out how to use it, add a summary of the register/fault support to the top of the file. Signed-off-by: David Lechner Link: https://lore.kernel.org/r/20231005-ad2s1210-mainline-v4-14-ec00746840fc@baylibre.com Signed-off-by: Jonathan Cameron --- drivers/staging/iio/resolver/ad2s1210.c | 40 +++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/drivers/staging/iio/resolver/ad2s1210.c b/drivers/staging/iio/resolver/ad2s1210.c index f3f26b1438c0..b843a1f5b45a 100644 --- a/drivers/staging/iio/resolver/ad2s1210.c +++ b/drivers/staging/iio/resolver/ad2s1210.c @@ -4,7 +4,47 @@ * * Copyright (c) 2010-2010 Analog Devices Inc. * Copyright (c) 2023 BayLibre, SAS + * + * Device register to IIO ABI mapping: + * + * Register | Addr | IIO ABI (sysfs) + * ----------------------------|------|------------------------------------------- + * DOS Overrange Threshold | 0x89 | events/in_altvoltage0_thresh_rising_value + * DOS Mismatch Threshold | 0x8A | events/in_altvoltage0_mag_rising_value + * DOS Reset Maximum Threshold | 0x8B | events/in_altvoltage0_mag_rising_reset_max + * DOS Reset Minimum Threshold | 0x8C | events/in_altvoltage0_mag_rising_reset_min + * LOT High Threshold | 0x8D | events/in_angl1_thresh_rising_value + * LOT Low Threshold [1] | 0x8E | events/in_angl1_thresh_rising_hysteresis + * Excitation Frequency | 0x91 | out_altvoltage0_frequency + * Control | 0x92 | *as bit fields* + * Phase lock range | D5 | events/in_phase0_mag_rising_value + * Hysteresis | D4 | in_angl0_hysteresis + * Encoder resolution | D3:2 | *not implemented* + * Resolution | D1:0 | *device tree: assigned-resolution-bits* + * Soft Reset | 0xF0 | [2] + * Fault | 0xFF | *not implemented* + * + * [1]: The value written to the LOT low register is high value minus the + * hysteresis. + * [2]: Soft reset is performed when `out_altvoltage0_frequency` is written. + * + * Fault to event mapping: + * + * Fault | | Channel | Type | Direction + * ----------------------------------------|----|--------------------------------- + * Sine/cosine inputs clipped [3] | D7 | altvoltage1 | mag | either + * Sine/cosine inputs below LOS | D6 | altvoltage0 | thresh | falling + * Sine/cosine inputs exceed DOS overrange | D5 | altvoltage0 | thresh | rising + * Sine/cosine inputs exceed DOS mismatch | D4 | altvoltage0 | mag | rising + * Tracking error exceeds LOT | D3 | angl1 | thresh | rising + * Velocity exceeds maximum tracking rate | D2 | anglvel0 | mag | rising + * Phase error exceeds phase lock range | D1 | phase0 | mag | rising + * Configuration parity error | D0 | *writes to kernel log* + * + * [3]: The chip does not differentiate between fault on sine vs. cosine so + * there will also be an event on the altvoltage2 channel. */ + #include #include #include From 40efeec7600949c2f6319c11d8a7f294a1c5e590 Mon Sep 17 00:00:00 2001 From: David Lechner Date: Thu, 5 Oct 2023 19:50:32 -0500 Subject: [PATCH 256/326] staging: iio: resolver: ad2s1210: add label attribute support The ad2s1210 resolver driver has quite a few channels, mostly for internal signals for event support. This makes it difficult to know which channel is which. This patch adds a label attribute to the channels to make it easier to identify them. Signed-off-by: David Lechner Link: https://lore.kernel.org/r/20231005-ad2s1210-mainline-v4-15-ec00746840fc@baylibre.com Signed-off-by: Jonathan Cameron --- drivers/staging/iio/resolver/ad2s1210.c | 29 +++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/drivers/staging/iio/resolver/ad2s1210.c b/drivers/staging/iio/resolver/ad2s1210.c index b843a1f5b45a..2d7b9bfeabd3 100644 --- a/drivers/staging/iio/resolver/ad2s1210.c +++ b/drivers/staging/iio/resolver/ad2s1210.c @@ -1158,6 +1158,34 @@ error_ret: return ret; } +static int ad2s1210_read_label(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + char *label) +{ + if (chan->type == IIO_ANGL) { + if (chan->channel == 0) + return sprintf(label, "position\n"); + if (chan->channel == 1) + return sprintf(label, "tracking error\n"); + } + if (chan->type == IIO_ANGL_VEL) + return sprintf(label, "velocity\n"); + if (chan->type == IIO_PHASE) + return sprintf(label, "synthetic reference\n"); + if (chan->type == IIO_ALTVOLTAGE) { + if (chan->output) + return sprintf(label, "excitation\n"); + if (chan->channel == 0) + return sprintf(label, "monitor signal\n"); + if (chan->channel == 1) + return sprintf(label, "cosine\n"); + if (chan->channel == 2) + return sprintf(label, "sine\n"); + } + + return -EINVAL; +} + static int ad2s1210_read_event_value(struct iio_dev *indio_dev, const struct iio_chan_spec *chan, enum iio_event_type type, @@ -1338,6 +1366,7 @@ static const struct iio_info ad2s1210_info = { .read_raw = ad2s1210_read_raw, .read_avail = ad2s1210_read_avail, .write_raw = ad2s1210_write_raw, + .read_label = ad2s1210_read_label, .attrs = &ad2s1210_attribute_group, .read_event_value = ad2s1210_read_event_value, .write_event_value = ad2s1210_write_event_value, From 73aa842baf877cc8c8da819f4ea927307dd8b6e4 Mon Sep 17 00:00:00 2001 From: David Lechner Date: Thu, 5 Oct 2023 19:50:33 -0500 Subject: [PATCH 257/326] staging: iio: resolver: ad2s1210: remove fault attribute Faults have been converted to events and we are now polling the fault register each time we read a sample, so we no longer need the fault attribute. This attribute was not suitable for promotion out of staging anyway since it was returning multiple values in a single attribute. The fault clearing feature should not be needed unless we need to support the fault output pins on the chip which is not currently supported. So we can add this feature back in if we need it later. Signed-off-by: David Lechner Link: https://lore.kernel.org/r/20231005-ad2s1210-mainline-v4-16-ec00746840fc@baylibre.com Signed-off-by: Jonathan Cameron --- drivers/staging/iio/resolver/ad2s1210.c | 57 ------------------------- 1 file changed, 57 deletions(-) diff --git a/drivers/staging/iio/resolver/ad2s1210.c b/drivers/staging/iio/resolver/ad2s1210.c index 2d7b9bfeabd3..e0bea3c68664 100644 --- a/drivers/staging/iio/resolver/ad2s1210.c +++ b/drivers/staging/iio/resolver/ad2s1210.c @@ -312,50 +312,6 @@ static int ad2s1210_reinit_excitation_frequency(struct ad2s1210_state *st, return regmap_write(st->regmap, AD2S1210_REG_SOFT_RESET, 0); } -/* read the fault register since last sample */ -static ssize_t ad2s1210_show_fault(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct ad2s1210_state *st = iio_priv(dev_to_iio_dev(dev)); - unsigned int value; - int ret; - - mutex_lock(&st->lock); - ret = regmap_read(st->regmap, AD2S1210_REG_FAULT, &value); - mutex_unlock(&st->lock); - - return ret < 0 ? ret : sprintf(buf, "0x%02x\n", value); -} - -static ssize_t ad2s1210_clear_fault(struct device *dev, - struct device_attribute *attr, - const char *buf, - size_t len) -{ - struct ad2s1210_state *st = iio_priv(dev_to_iio_dev(dev)); - unsigned int value; - int ret; - - mutex_lock(&st->lock); - - gpiod_set_value(st->sample_gpio, 1); - /* delay (2 * tck + 20) nano seconds */ - udelay(1); - gpiod_set_value(st->sample_gpio, 0); - - ret = regmap_read(st->regmap, AD2S1210_REG_FAULT, &value); - if (ret < 0) - goto error_ret; - - gpiod_set_value(st->sample_gpio, 1); - gpiod_set_value(st->sample_gpio, 0); - -error_ret: - mutex_unlock(&st->lock); - - return ret < 0 ? ret : len; -} - static void ad2s1210_push_events(struct iio_dev *indio_dev, u8 flags, s64 timestamp) { @@ -868,9 +824,6 @@ static int ad2s1210_write_raw(struct iio_dev *indio_dev, } } -static IIO_DEVICE_ATTR(fault, 0644, - ad2s1210_show_fault, ad2s1210_clear_fault, 0); - static const struct iio_event_spec ad2s1210_position_event_spec[] = { { /* Tracking error exceeds LOT threshold fault. */ @@ -1020,15 +973,6 @@ static const struct iio_chan_spec ad2s1210_channels[] = { }, }; -static struct attribute *ad2s1210_attributes[] = { - &iio_dev_attr_fault.dev_attr.attr, - NULL, -}; - -static const struct attribute_group ad2s1210_attribute_group = { - .attrs = ad2s1210_attributes, -}; - static ssize_t event_attr_voltage_reg_show(struct device *dev, struct device_attribute *attr, char *buf) @@ -1367,7 +1311,6 @@ static const struct iio_info ad2s1210_info = { .read_avail = ad2s1210_read_avail, .write_raw = ad2s1210_write_raw, .read_label = ad2s1210_read_label, - .attrs = &ad2s1210_attribute_group, .read_event_value = ad2s1210_read_event_value, .write_event_value = ad2s1210_write_event_value, .read_event_label = ad2s1210_read_event_label, From 27ffa2216acfab3527064ec13666f35d70f76045 Mon Sep 17 00:00:00 2001 From: David Lechner Date: Tue, 10 Oct 2023 16:12:33 -0500 Subject: [PATCH 258/326] staging: iio: resolver: ad2s1210: refactor sample toggle This refactors the sample line toggle in the ad2s1210 resolver driver to a separate function. The sample has some timing requirements, so this ensures that it is always done the same way, both in the existing call sites and any future usage. Previously, the sample line was kept on for the duration of the read, but this is not necessary. Data is latched in on the rising edge and after the specified delay the state of the sample line does not matter. Signed-off-by: David Lechner Link: https://lore.kernel.org/r/20231010-ad2s1210-mainline-v5-1-35a0f6ffa04a@baylibre.com Signed-off-by: Jonathan Cameron --- drivers/staging/iio/resolver/ad2s1210.c | 30 ++++++++++++++++++------- 1 file changed, 22 insertions(+), 8 deletions(-) diff --git a/drivers/staging/iio/resolver/ad2s1210.c b/drivers/staging/iio/resolver/ad2s1210.c index e0bea3c68664..59c273a4b6a9 100644 --- a/drivers/staging/iio/resolver/ad2s1210.c +++ b/drivers/staging/iio/resolver/ad2s1210.c @@ -286,6 +286,26 @@ static int ad2s1210_regmap_reg_read(void *context, unsigned int reg, return 0; } +/* + * Toggles the SAMPLE line on the AD2S1210 to latch in the current position, + * velocity, and faults. + * + * Must be called with lock held. + */ +static void ad2s1210_toggle_sample_line(struct ad2s1210_state *st) +{ + /* + * Datasheet specifies minimum hold time t16 = 2 * tck + 20 ns. So the + * longest time needed is when CLKIN is 6.144 MHz, in which case t16 + * ~= 350 ns. The same delay is also needed before re-asserting the + * SAMPLE line. + */ + gpiod_set_value(st->sample_gpio, 1); + ndelay(350); + gpiod_set_value(st->sample_gpio, 0); + ndelay(350); +} + /* * Sets the excitation frequency and performs software reset. * @@ -405,10 +425,8 @@ static int ad2s1210_single_conversion(struct iio_dev *indio_dev, int ret; mutex_lock(&st->lock); - gpiod_set_value(st->sample_gpio, 1); + ad2s1210_toggle_sample_line(st); timestamp = iio_get_time_ns(indio_dev); - /* delay (6 * tck + 20) nano seconds */ - udelay(1); switch (chan->type) { case IIO_ANGL: @@ -444,9 +462,6 @@ static int ad2s1210_single_conversion(struct iio_dev *indio_dev, ad2s1210_push_events(indio_dev, st->sample.fault, timestamp); error_ret: - gpiod_set_value(st->sample_gpio, 0); - /* delay (2 * tck + 20) nano seconds */ - udelay(1); mutex_unlock(&st->lock); return ret; } @@ -1268,7 +1283,7 @@ static irqreturn_t ad2s1210_trigger_handler(int irq, void *p) mutex_lock(&st->lock); memset(&st->scan, 0, sizeof(st->scan)); - gpiod_set_value(st->sample_gpio, 1); + ad2s1210_toggle_sample_line(st); if (test_bit(0, indio_dev->active_scan_mask)) { ret = ad2s1210_set_mode(st, MOD_POS); @@ -1298,7 +1313,6 @@ static irqreturn_t ad2s1210_trigger_handler(int irq, void *p) iio_push_to_buffers_with_timestamp(indio_dev, &st->scan, pf->timestamp); error_ret: - gpiod_set_value(st->sample_gpio, 0); mutex_unlock(&st->lock); iio_trigger_notify_done(indio_dev->trig); From 4efa877ac942d63c335820bf52d262e76901bea9 Mon Sep 17 00:00:00 2001 From: David Lechner Date: Tue, 10 Oct 2023 16:12:34 -0500 Subject: [PATCH 259/326] staging: iio: resolver: ad2s1210: clear faults after soft reset When a software reset is performed on the AD2S1210 to make the selected excitation frequency take effect, it always triggers faults on the input signals because the output signal is interrupted momentarily. So we need to clear the faults after the software reset to avoid triggering fault events the next time a sample is read. The datasheet specifies a time t[track] in Table 27 that specifies the settle time in milliseconds after a reset depending on the selected resolution. This is used in the driver to add an appropriate delay. Signed-off-by: David Lechner Link: https://lore.kernel.org/r/20231010-ad2s1210-mainline-v5-2-35a0f6ffa04a@baylibre.com Signed-off-by: Jonathan Cameron --- drivers/staging/iio/resolver/ad2s1210.c | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/drivers/staging/iio/resolver/ad2s1210.c b/drivers/staging/iio/resolver/ad2s1210.c index 59c273a4b6a9..cf4018434447 100644 --- a/drivers/staging/iio/resolver/ad2s1210.c +++ b/drivers/staging/iio/resolver/ad2s1210.c @@ -314,6 +314,9 @@ static void ad2s1210_toggle_sample_line(struct ad2s1210_state *st) static int ad2s1210_reinit_excitation_frequency(struct ad2s1210_state *st, u16 fexcit) { + /* Map resolution to settle time in milliseconds. */ + static const int track_time_ms[] = { 10, 20, 25, 60 }; + unsigned int ignored; int ret; u8 fcw; @@ -329,7 +332,27 @@ static int ad2s1210_reinit_excitation_frequency(struct ad2s1210_state *st, * Software reset reinitializes the excitation frequency output. * It does not reset any of the configuration registers. */ - return regmap_write(st->regmap, AD2S1210_REG_SOFT_RESET, 0); + ret = regmap_write(st->regmap, AD2S1210_REG_SOFT_RESET, 0); + if (ret < 0) + return ret; + + /* + * Soft reset always triggers some faults due the change in the output + * signal so clear the faults too. We need to delay for some time + * (what datasheet calls t[track]) to allow things to settle before + * clearing the faults. + */ + msleep(track_time_ms[st->resolution] * 8192000 / st->clkin_hz); + + /* Reading the fault register clears the faults. */ + ret = regmap_read(st->regmap, AD2S1210_REG_FAULT, &ignored); + if (ret < 0) + return ret; + + /* Have to toggle sample line to get fault output pins to reset. */ + ad2s1210_toggle_sample_line(st); + + return 0; } static void ad2s1210_push_events(struct iio_dev *indio_dev, From 169dc2adafecc19ecf53a101398edd7f3ff03529 Mon Sep 17 00:00:00 2001 From: David Lechner Date: Tue, 10 Oct 2023 16:12:35 -0500 Subject: [PATCH 260/326] staging: iio: resolver: ad2s1210: simplify code with guard(mutex) We can simplify the code and get rid of most of the gotos by using guard(mutex) from cleanup.h. Signed-off-by: David Lechner Link: https://lore.kernel.org/r/20231010-ad2s1210-mainline-v5-3-35a0f6ffa04a@baylibre.com Signed-off-by: Jonathan Cameron --- drivers/staging/iio/resolver/ad2s1210.c | 153 ++++++++---------------- 1 file changed, 49 insertions(+), 104 deletions(-) diff --git a/drivers/staging/iio/resolver/ad2s1210.c b/drivers/staging/iio/resolver/ad2s1210.c index cf4018434447..bd4a90c222b5 100644 --- a/drivers/staging/iio/resolver/ad2s1210.c +++ b/drivers/staging/iio/resolver/ad2s1210.c @@ -47,6 +47,7 @@ #include #include +#include #include #include #include @@ -447,7 +448,8 @@ static int ad2s1210_single_conversion(struct iio_dev *indio_dev, s64 timestamp; int ret; - mutex_lock(&st->lock); + guard(mutex)(&st->lock); + ad2s1210_toggle_sample_line(st); timestamp = iio_get_time_ns(indio_dev); @@ -459,14 +461,13 @@ static int ad2s1210_single_conversion(struct iio_dev *indio_dev, ret = ad2s1210_set_mode(st, MOD_VEL); break; default: - ret = -EINVAL; - break; + return -EINVAL; } if (ret < 0) - goto error_ret; + return ret; ret = spi_read(st->sdev, &st->sample, 3); if (ret < 0) - goto error_ret; + return ret; switch (chan->type) { case IIO_ANGL: @@ -478,14 +479,11 @@ static int ad2s1210_single_conversion(struct iio_dev *indio_dev, ret = IIO_VAL_INT; break; default: - ret = -EINVAL; - break; + return -EINVAL; } ad2s1210_push_events(indio_dev, st->sample.fault, timestamp); -error_ret: - mutex_unlock(&st->lock); return ret; } @@ -493,11 +491,9 @@ static int ad2s1210_get_hysteresis(struct ad2s1210_state *st, int *val) { int ret; - mutex_lock(&st->lock); + guard(mutex)(&st->lock); ret = regmap_test_bits(st->regmap, AD2S1210_REG_CONTROL, AD2S1210_ENABLE_HYSTERESIS); - mutex_unlock(&st->lock); - if (ret < 0) return ret; @@ -507,15 +503,10 @@ static int ad2s1210_get_hysteresis(struct ad2s1210_state *st, int *val) static int ad2s1210_set_hysteresis(struct ad2s1210_state *st, int val) { - int ret; - - mutex_lock(&st->lock); - ret = regmap_update_bits(st->regmap, AD2S1210_REG_CONTROL, - AD2S1210_ENABLE_HYSTERESIS, - val ? AD2S1210_ENABLE_HYSTERESIS : 0); - mutex_unlock(&st->lock); - - return ret; + guard(mutex)(&st->lock); + return regmap_update_bits(st->regmap, AD2S1210_REG_CONTROL, + AD2S1210_ENABLE_HYSTERESIS, + val ? AD2S1210_ENABLE_HYSTERESIS : 0); } static int ad2s1210_get_phase_lock_range(struct ad2s1210_state *st, @@ -523,11 +514,9 @@ static int ad2s1210_get_phase_lock_range(struct ad2s1210_state *st, { int ret; - mutex_lock(&st->lock); + guard(mutex)(&st->lock); ret = regmap_test_bits(st->regmap, AD2S1210_REG_CONTROL, AD2S1210_PHASE_LOCK_RANGE_44); - mutex_unlock(&st->lock); - if (ret < 0) return ret; @@ -547,7 +536,7 @@ static int ad2s1210_get_phase_lock_range(struct ad2s1210_state *st, static int ad2s1210_set_phase_lock_range(struct ad2s1210_state *st, int val, int val2) { - int deg, ret; + int deg; /* convert radians to degrees - only two allowable values */ if (val == PHASE_44_DEG_TO_RAD_INT && val2 == PHASE_44_DEG_TO_RAD_MICRO) @@ -558,12 +547,10 @@ static int ad2s1210_set_phase_lock_range(struct ad2s1210_state *st, else return -EINVAL; - mutex_lock(&st->lock); - ret = regmap_update_bits(st->regmap, AD2S1210_REG_CONTROL, - AD2S1210_PHASE_LOCK_RANGE_44, - deg == 44 ? AD2S1210_PHASE_LOCK_RANGE_44 : 0); - mutex_unlock(&st->lock); - return ret; + guard(mutex)(&st->lock); + return regmap_update_bits(st->regmap, AD2S1210_REG_CONTROL, + AD2S1210_PHASE_LOCK_RANGE_44, + deg == 44 ? AD2S1210_PHASE_LOCK_RANGE_44 : 0); } /* map resolution to microradians/LSB for LOT registers */ @@ -580,10 +567,8 @@ static int ad2s1210_get_voltage_threshold(struct ad2s1210_state *st, unsigned int reg_val; int ret; - mutex_lock(&st->lock); + guard(mutex)(&st->lock); ret = regmap_read(st->regmap, reg, ®_val); - mutex_unlock(&st->lock); - if (ret < 0) return ret; @@ -595,15 +580,11 @@ static int ad2s1210_set_voltage_threshold(struct ad2s1210_state *st, unsigned int reg, int val) { unsigned int reg_val; - int ret; reg_val = val / THRESHOLD_MILLIVOLT_PER_LSB; - mutex_lock(&st->lock); - ret = regmap_write(st->regmap, reg, reg_val); - mutex_unlock(&st->lock); - - return ret; + guard(mutex)(&st->lock); + return regmap_write(st->regmap, reg, reg_val); } static int ad2s1210_get_lot_high_threshold(struct ad2s1210_state *st, @@ -612,10 +593,8 @@ static int ad2s1210_get_lot_high_threshold(struct ad2s1210_state *st, unsigned int reg_val; int ret; - mutex_lock(&st->lock); + guard(mutex)(&st->lock); ret = regmap_read(st->regmap, AD2S1210_REG_LOT_HIGH_THRD, ®_val); - mutex_unlock(&st->lock); - if (ret < 0) return ret; @@ -634,18 +613,18 @@ static int ad2s1210_set_lot_high_threshold(struct ad2s1210_state *st, if (val != 0) return -EINVAL; - mutex_lock(&st->lock); + guard(mutex)(&st->lock); /* * We need to read both high and low registers first so we can preserve * the hysteresis. */ ret = regmap_read(st->regmap, AD2S1210_REG_LOT_HIGH_THRD, &high_reg_val); if (ret < 0) - goto error_ret; + return ret; ret = regmap_read(st->regmap, AD2S1210_REG_LOT_LOW_THRD, &low_reg_val); if (ret < 0) - goto error_ret; + return ret; hysteresis = high_reg_val - low_reg_val; high_reg_val = val2 / ad2s1210_lot_threshold_urad_per_lsb[st->resolution]; @@ -653,14 +632,9 @@ static int ad2s1210_set_lot_high_threshold(struct ad2s1210_state *st, ret = regmap_write(st->regmap, AD2S1210_REG_LOT_HIGH_THRD, high_reg_val); if (ret < 0) - goto error_ret; + return ret; - ret = regmap_write(st->regmap, AD2S1210_REG_LOT_LOW_THRD, low_reg_val); - -error_ret: - mutex_unlock(&st->lock); - - return ret; + return regmap_write(st->regmap, AD2S1210_REG_LOT_LOW_THRD, low_reg_val); } static int ad2s1210_get_lot_low_threshold(struct ad2s1210_state *st, @@ -669,16 +643,13 @@ static int ad2s1210_get_lot_low_threshold(struct ad2s1210_state *st, unsigned int high_reg_val, low_reg_val; int ret; - mutex_lock(&st->lock); + guard(mutex)(&st->lock); + ret = regmap_read(st->regmap, AD2S1210_REG_LOT_HIGH_THRD, &high_reg_val); if (ret < 0) - goto error_ret; + return ret; ret = regmap_read(st->regmap, AD2S1210_REG_LOT_LOW_THRD, &low_reg_val); - -error_ret: - mutex_unlock(&st->lock); - if (ret < 0) return ret; @@ -701,18 +672,14 @@ static int ad2s1210_set_lot_low_threshold(struct ad2s1210_state *st, hysteresis = val2 / ad2s1210_lot_threshold_urad_per_lsb[st->resolution]; - mutex_lock(&st->lock); + guard(mutex)(&st->lock); + ret = regmap_read(st->regmap, AD2S1210_REG_LOT_HIGH_THRD, ®_val); if (ret < 0) - goto error_ret; + return ret; - ret = regmap_write(st->regmap, AD2S1210_REG_LOT_LOW_THRD, + return regmap_write(st->regmap, AD2S1210_REG_LOT_LOW_THRD, reg_val - hysteresis); - -error_ret: - mutex_unlock(&st->lock); - - return ret; } static int ad2s1210_get_excitation_frequency(struct ad2s1210_state *st, int *val) @@ -720,31 +687,23 @@ static int ad2s1210_get_excitation_frequency(struct ad2s1210_state *st, int *val unsigned int reg_val; int ret; - mutex_lock(&st->lock); + guard(mutex)(&st->lock); + ret = regmap_read(st->regmap, AD2S1210_REG_EXCIT_FREQ, ®_val); if (ret < 0) - goto error_ret; + return ret; *val = reg_val * st->clkin_hz / (1 << 15); - ret = IIO_VAL_INT; - -error_ret: - mutex_unlock(&st->lock); - return ret; + return IIO_VAL_INT; } static int ad2s1210_set_excitation_frequency(struct ad2s1210_state *st, int val) { - int ret; - if (val < AD2S1210_MIN_EXCIT || val > AD2S1210_MAX_EXCIT) return -EINVAL; - mutex_lock(&st->lock); - ret = ad2s1210_reinit_excitation_frequency(st, val); - mutex_unlock(&st->lock); - - return ret; + guard(mutex)(&st->lock); + return ad2s1210_reinit_excitation_frequency(st, val); } static const int ad2s1210_velocity_scale[] = { @@ -1020,10 +979,8 @@ static ssize_t event_attr_voltage_reg_show(struct device *dev, unsigned int value; int ret; - mutex_lock(&st->lock); + guard(mutex)(&st->lock); ret = regmap_read(st->regmap, iattr->address, &value); - mutex_unlock(&st->lock); - if (ret < 0) return ret; @@ -1043,11 +1000,9 @@ static ssize_t event_attr_voltage_reg_store(struct device *dev, if (ret) return -EINVAL; - mutex_lock(&st->lock); + guard(mutex)(&st->lock); ret = regmap_write(st->regmap, iattr->address, data / THRESHOLD_MILLIVOLT_PER_LSB); - mutex_unlock(&st->lock); - if (ret < 0) return ret; @@ -1121,7 +1076,7 @@ static int ad2s1210_initial(struct ad2s1210_state *st) unsigned int data; int ret; - mutex_lock(&st->lock); + guard(mutex)(&st->lock); /* Use default config register value plus resolution from devicetree. */ data = FIELD_PREP(AD2S1210_PHASE_LOCK_RANGE_44, 1); @@ -1131,13 +1086,9 @@ static int ad2s1210_initial(struct ad2s1210_state *st) ret = regmap_write(st->regmap, AD2S1210_REG_CONTROL, data); if (ret < 0) - goto error_ret; + return ret; - ret = ad2s1210_reinit_excitation_frequency(st, AD2S1210_DEF_EXCIT); - -error_ret: - mutex_unlock(&st->lock); - return ret; + return ad2s1210_reinit_excitation_frequency(st, AD2S1210_DEF_EXCIT); } static int ad2s1210_read_label(struct iio_dev *indio_dev, @@ -1281,18 +1232,13 @@ static int ad2s1210_debugfs_reg_access(struct iio_dev *indio_dev, unsigned int *readval) { struct ad2s1210_state *st = iio_priv(indio_dev); - int ret; - mutex_lock(&st->lock); + guard(mutex)(&st->lock); if (readval) - ret = regmap_read(st->regmap, reg, readval); - else - ret = regmap_write(st->regmap, reg, writeval); + return regmap_read(st->regmap, reg, readval); - mutex_unlock(&st->lock); - - return ret; + return regmap_write(st->regmap, reg, writeval); } static irqreturn_t ad2s1210_trigger_handler(int irq, void *p) @@ -1303,7 +1249,7 @@ static irqreturn_t ad2s1210_trigger_handler(int irq, void *p) size_t chan = 0; int ret; - mutex_lock(&st->lock); + guard(mutex)(&st->lock); memset(&st->scan, 0, sizeof(st->scan)); ad2s1210_toggle_sample_line(st); @@ -1336,7 +1282,6 @@ static irqreturn_t ad2s1210_trigger_handler(int irq, void *p) iio_push_to_buffers_with_timestamp(indio_dev, &st->scan, pf->timestamp); error_ret: - mutex_unlock(&st->lock); iio_trigger_notify_done(indio_dev->trig); return IRQ_HANDLED; From 291e45eeeb901b1d22b74ac5ea48cab3c407c705 Mon Sep 17 00:00:00 2001 From: David Lechner Date: Tue, 10 Oct 2023 16:12:36 -0500 Subject: [PATCH 261/326] iio: resolver: ad2s1210: move out of staging This moves the ad2s1210 resolver driver out of staging. The driver has been fixed up and is ready to graduate. Signed-off-by: David Lechner Link: https://lore.kernel.org/r/20231010-ad2s1210-mainline-v5-4-35a0f6ffa04a@baylibre.com Signed-off-by: Jonathan Cameron --- .../testing}/sysfs-bus-iio-resolver-ad2s1210 | 0 drivers/iio/resolver/Kconfig | 13 +++++++++++++ drivers/iio/resolver/Makefile | 1 + drivers/{staging => }/iio/resolver/ad2s1210.c | 0 drivers/staging/iio/Kconfig | 1 - drivers/staging/iio/Makefile | 1 - drivers/staging/iio/resolver/Kconfig | 19 ------------------- drivers/staging/iio/resolver/Makefile | 6 ------ 8 files changed, 14 insertions(+), 27 deletions(-) rename {drivers/staging/iio/Documentation => Documentation/ABI/testing}/sysfs-bus-iio-resolver-ad2s1210 (100%) rename drivers/{staging => }/iio/resolver/ad2s1210.c (100%) delete mode 100644 drivers/staging/iio/resolver/Kconfig delete mode 100644 drivers/staging/iio/resolver/Makefile diff --git a/drivers/staging/iio/Documentation/sysfs-bus-iio-resolver-ad2s1210 b/Documentation/ABI/testing/sysfs-bus-iio-resolver-ad2s1210 similarity index 100% rename from drivers/staging/iio/Documentation/sysfs-bus-iio-resolver-ad2s1210 rename to Documentation/ABI/testing/sysfs-bus-iio-resolver-ad2s1210 diff --git a/drivers/iio/resolver/Kconfig b/drivers/iio/resolver/Kconfig index 47dbfead9b31..424529d36080 100644 --- a/drivers/iio/resolver/Kconfig +++ b/drivers/iio/resolver/Kconfig @@ -25,4 +25,17 @@ config AD2S1200 To compile this driver as a module, choose M here: the module will be called ad2s1200. + +config AD2S1210 + tristate "Analog Devices ad2s1210 driver" + depends on SPI + depends on COMMON_CLK + depends on GPIOLIB || COMPILE_TEST + help + Say yes here to build support for Analog Devices spi resolver + to digital converters, ad2s1210, provides direct access via sysfs. + + To compile this driver as a module, choose M here: the + module will be called ad2s1210. + endmenu diff --git a/drivers/iio/resolver/Makefile b/drivers/iio/resolver/Makefile index fa558138ce45..7f6c876c35ae 100644 --- a/drivers/iio/resolver/Makefile +++ b/drivers/iio/resolver/Makefile @@ -5,3 +5,4 @@ obj-$(CONFIG_AD2S90) += ad2s90.o obj-$(CONFIG_AD2S1200) += ad2s1200.o +obj-$(CONFIG_AD2S1210) += ad2s1210.o diff --git a/drivers/staging/iio/resolver/ad2s1210.c b/drivers/iio/resolver/ad2s1210.c similarity index 100% rename from drivers/staging/iio/resolver/ad2s1210.c rename to drivers/iio/resolver/ad2s1210.c diff --git a/drivers/staging/iio/Kconfig b/drivers/staging/iio/Kconfig index d3968fe2ebb8..a60631c1f449 100644 --- a/drivers/staging/iio/Kconfig +++ b/drivers/staging/iio/Kconfig @@ -10,6 +10,5 @@ source "drivers/staging/iio/adc/Kconfig" source "drivers/staging/iio/addac/Kconfig" source "drivers/staging/iio/frequency/Kconfig" source "drivers/staging/iio/impedance-analyzer/Kconfig" -source "drivers/staging/iio/resolver/Kconfig" endmenu diff --git a/drivers/staging/iio/Makefile b/drivers/staging/iio/Makefile index c50f1019f829..628583535393 100644 --- a/drivers/staging/iio/Makefile +++ b/drivers/staging/iio/Makefile @@ -8,4 +8,3 @@ obj-y += adc/ obj-y += addac/ obj-y += frequency/ obj-y += impedance-analyzer/ -obj-y += resolver/ diff --git a/drivers/staging/iio/resolver/Kconfig b/drivers/staging/iio/resolver/Kconfig deleted file mode 100644 index bebb35822c9e..000000000000 --- a/drivers/staging/iio/resolver/Kconfig +++ /dev/null @@ -1,19 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 -# -# Resolver/Synchro drivers -# -menu "Resolver to digital converters" - -config AD2S1210 - tristate "Analog Devices ad2s1210 driver" - depends on SPI - depends on COMMON_CLK - depends on GPIOLIB || COMPILE_TEST - help - Say yes here to build support for Analog Devices spi resolver - to digital converters, ad2s1210, provides direct access via sysfs. - - To compile this driver as a module, choose M here: the - module will be called ad2s1210. - -endmenu diff --git a/drivers/staging/iio/resolver/Makefile b/drivers/staging/iio/resolver/Makefile deleted file mode 100644 index 398631f7e79b..000000000000 --- a/drivers/staging/iio/resolver/Makefile +++ /dev/null @@ -1,6 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 -# -# Makefile for Resolver/Synchro drivers -# - -obj-$(CONFIG_AD2S1210) += ad2s1210.o From 4e807eb05dff41d500822f81744ec5f9c0591aa5 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Fri, 6 Oct 2023 17:46:33 -0500 Subject: [PATCH 262/326] fpga: Use device_get_match_data() Use preferred device_get_match_data() instead of of_match_device() to get the driver match data. With this, adjust the includes to explicitly include the correct headers. Also drop of_match_ptr for xlnx_pr_decoupler_of_match, which is not necessary because DT is always used for this driver. Signed-off-by: Rob Herring Acked-by: Xu Yilun Link: https://lore.kernel.org/r/20231006224633.445035-1-robh@kernel.org [yilun.xu@intel.com: merge the fix 20231012192149.1546368-1-robh@kernel.org] Link: https://lore.kernel.org/r/20231012192149.1546368-1-robh@kernel.org Signed-off-by: Xu Yilun --- drivers/fpga/altera-hps2fpga.c | 12 +++--------- drivers/fpga/xilinx-pr-decoupler.c | 17 +++++------------ 2 files changed, 8 insertions(+), 21 deletions(-) diff --git a/drivers/fpga/altera-hps2fpga.c b/drivers/fpga/altera-hps2fpga.c index aa758426c22b..578663503297 100644 --- a/drivers/fpga/altera-hps2fpga.c +++ b/drivers/fpga/altera-hps2fpga.c @@ -24,7 +24,8 @@ #include #include #include -#include +#include +#include #include #include #include @@ -127,18 +128,11 @@ static int alt_fpga_bridge_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct altera_hps2fpga_data *priv; - const struct of_device_id *of_id; struct fpga_bridge *br; u32 enable; int ret; - of_id = of_match_device(altera_fpga_of_match, dev); - if (!of_id) { - dev_err(dev, "failed to match device\n"); - return -ENODEV; - } - - priv = (struct altera_hps2fpga_data *)of_id->data; + priv = (struct altera_hps2fpga_data *)device_get_match_data(dev); priv->bridge_reset = of_reset_control_get_exclusive_by_index(dev->of_node, 0); diff --git a/drivers/fpga/xilinx-pr-decoupler.c b/drivers/fpga/xilinx-pr-decoupler.c index 208d9560f56d..68835896f180 100644 --- a/drivers/fpga/xilinx-pr-decoupler.c +++ b/drivers/fpga/xilinx-pr-decoupler.c @@ -10,8 +10,10 @@ #include #include #include -#include #include +#include +#include +#include #include #define CTRL_CMD_DECOUPLE BIT(0) @@ -81,7 +83,6 @@ static const struct fpga_bridge_ops xlnx_pr_decoupler_br_ops = { .enable_show = xlnx_pr_decoupler_enable_show, }; -#ifdef CONFIG_OF static const struct xlnx_config_data decoupler_config = { .name = "Xilinx PR Decoupler", }; @@ -100,11 +101,9 @@ static const struct of_device_id xlnx_pr_decoupler_of_match[] = { {}, }; MODULE_DEVICE_TABLE(of, xlnx_pr_decoupler_of_match); -#endif static int xlnx_pr_decoupler_probe(struct platform_device *pdev) { - struct device_node *np = pdev->dev.of_node; struct xlnx_pr_decoupler_data *priv; struct fpga_bridge *br; int err; @@ -113,13 +112,7 @@ static int xlnx_pr_decoupler_probe(struct platform_device *pdev) if (!priv) return -ENOMEM; - if (np) { - const struct of_device_id *match; - - match = of_match_node(xlnx_pr_decoupler_of_match, np); - if (match && match->data) - priv->ipconfig = match->data; - } + priv->ipconfig = device_get_match_data(&pdev->dev); priv->io_base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(priv->io_base)) @@ -174,7 +167,7 @@ static struct platform_driver xlnx_pr_decoupler_driver = { .remove = xlnx_pr_decoupler_remove, .driver = { .name = "xlnx_pr_decoupler", - .of_match_table = of_match_ptr(xlnx_pr_decoupler_of_match), + .of_match_table = xlnx_pr_decoupler_of_match, }, }; From 0f7fa242b355ed102deb49f8b85e0d0f0d323717 Mon Sep 17 00:00:00 2001 From: David Lechner Date: Thu, 12 Oct 2023 11:18:12 -0500 Subject: [PATCH 263/326] iio: resolver: ad2s1210: remove DRV_NAME macro The DRV_NAME macro is only used in one place in the ad2s1210 driver and is not really needed so let's remove it. Suggested-by: Jonathan Cameron Signed-off-by: David Lechner Link: https://lore.kernel.org/r/20231012-ad2s1210-mainline-v1-1-b2ee31c0e9dd@baylibre.com Signed-off-by: Jonathan Cameron --- drivers/iio/resolver/ad2s1210.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/iio/resolver/ad2s1210.c b/drivers/iio/resolver/ad2s1210.c index bd4a90c222b5..00562bc542bb 100644 --- a/drivers/iio/resolver/ad2s1210.c +++ b/drivers/iio/resolver/ad2s1210.c @@ -68,8 +68,6 @@ #include #include -#define DRV_NAME "ad2s1210" - /* control register flags */ #define AD2S1210_ADDRESS_DATA BIT(7) #define AD2S1210_PHASE_LOCK_RANGE_44 BIT(5) @@ -1509,7 +1507,7 @@ MODULE_DEVICE_TABLE(spi, ad2s1210_id); static struct spi_driver ad2s1210_driver = { .driver = { - .name = DRV_NAME, + .name = "ad2s1210", .of_match_table = of_match_ptr(ad2s1210_of_match), }, .probe = ad2s1210_probe, From 73006239ef2313f1986f86af86f8b06150a807e9 Mon Sep 17 00:00:00 2001 From: David Lechner Date: Thu, 12 Oct 2023 11:18:13 -0500 Subject: [PATCH 264/326] iio: resolver: ad2s1210: remove of_match_ptr() To be consistent with the rest of iio, remove of_match_ptr(). It does not do anything useful here. Suggested-by: Jonathan Cameron Signed-off-by: David Lechner Link: https://lore.kernel.org/r/20231012-ad2s1210-mainline-v1-2-b2ee31c0e9dd@baylibre.com Signed-off-by: Jonathan Cameron --- drivers/iio/resolver/ad2s1210.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/iio/resolver/ad2s1210.c b/drivers/iio/resolver/ad2s1210.c index 00562bc542bb..1bd1b950e7cc 100644 --- a/drivers/iio/resolver/ad2s1210.c +++ b/drivers/iio/resolver/ad2s1210.c @@ -54,7 +54,6 @@ #include #include #include -#include #include #include #include @@ -1508,7 +1507,7 @@ MODULE_DEVICE_TABLE(spi, ad2s1210_id); static struct spi_driver ad2s1210_driver = { .driver = { .name = "ad2s1210", - .of_match_table = of_match_ptr(ad2s1210_of_match), + .of_match_table = ad2s1210_of_match, }, .probe = ad2s1210_probe, .id_table = ad2s1210_id, From e9d8add6e72b1642bcf895601146c713d068775a Mon Sep 17 00:00:00 2001 From: Martin Kepplinger Date: Thu, 12 Oct 2023 14:20:41 +0000 Subject: [PATCH 265/326] dt-bindings: iio: imu: st,lsm6dsx: add mount-matrix property Add the mount-matrix optional property to the binding since it's supported and very useful when using the chip on a board. Signed-off-by: Martin Kepplinger Acked-by: Conor Dooley Link: https://lore.kernel.org/r/20231012142041.253332-1-martink@posteo.de Signed-off-by: Jonathan Cameron --- Documentation/devicetree/bindings/iio/imu/st,lsm6dsx.yaml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Documentation/devicetree/bindings/iio/imu/st,lsm6dsx.yaml b/Documentation/devicetree/bindings/iio/imu/st,lsm6dsx.yaml index ee8724ad33ab..28b667a9cb76 100644 --- a/Documentation/devicetree/bindings/iio/imu/st,lsm6dsx.yaml +++ b/Documentation/devicetree/bindings/iio/imu/st,lsm6dsx.yaml @@ -93,6 +93,9 @@ properties: wakeup-source: $ref: /schemas/types.yaml#/definitions/flag + mount-matrix: + description: an optional 3x3 mounting rotation matrix + required: - compatible - reg From ba251b20152c3bc6edaa05413090ca5b5f8deb7f Mon Sep 17 00:00:00 2001 From: Ramona Gradinariu Date: Thu, 12 Oct 2023 15:24:56 +0300 Subject: [PATCH 266/326] drivers: imu: adis16475.c: Remove scan index from delta channels Some devices do not support delta angle and delta velocity burst readings, which means there should be no buffer support for these types of channels. A new list of channels is created which contains the delta channels structures with the scan index equal to -1 to allow for raw register readings, without buffer support. This list of channels is assigned to the devices which do not support delta angle and delta velocity burst readings. Fixes: 8f6bc87d67c0 ("iio: imu: adis16475.c: Add delta angle and delta velocity channels") Signed-off-by: Ramona Gradinariu Reviewed-by: Nuno Sa Link: https://lore.kernel.org/r/20231012122456.765709-2-ramona.gradinariu@analog.com Signed-off-by: Jonathan Cameron --- drivers/iio/imu/adis16475.c | 67 +++++++++++++++++++++++++------------ 1 file changed, 46 insertions(+), 21 deletions(-) diff --git a/drivers/iio/imu/adis16475.c b/drivers/iio/imu/adis16475.c index 9af07fec0d89..b7cbe1565aee 100644 --- a/drivers/iio/imu/adis16475.c +++ b/drivers/iio/imu/adis16475.c @@ -604,7 +604,15 @@ static int adis16475_write_raw(struct iio_dev *indio_dev, ADIS16475_MOD_CHAN_DELTA(IIO_DELTA_VELOCITY, IIO_MOD_ ## _mod, \ ADIS16475_REG_ ## _mod ## _DELTVEL_L, ADIS16475_SCAN_DELTVEL_ ## _mod, 32, 32) -static const struct iio_chan_spec adis16475_channels[] = { +#define ADIS16475_DELTANG_CHAN_NO_SCAN(_mod) \ + ADIS16475_MOD_CHAN_DELTA(IIO_DELTA_ANGL, IIO_MOD_ ## _mod, \ + ADIS16475_REG_ ## _mod ## _DELTANG_L, -1, 32, 32) + +#define ADIS16475_DELTVEL_CHAN_NO_SCAN(_mod) \ + ADIS16475_MOD_CHAN_DELTA(IIO_DELTA_VELOCITY, IIO_MOD_ ## _mod, \ + ADIS16475_REG_ ## _mod ## _DELTVEL_L, -1, 32, 32) + +static const struct iio_chan_spec adis16477_channels[] = { ADIS16475_GYRO_CHANNEL(X), ADIS16475_GYRO_CHANNEL(Y), ADIS16475_GYRO_CHANNEL(Z), @@ -621,6 +629,23 @@ static const struct iio_chan_spec adis16475_channels[] = { IIO_CHAN_SOFT_TIMESTAMP(13) }; +static const struct iio_chan_spec adis16475_channels[] = { + ADIS16475_GYRO_CHANNEL(X), + ADIS16475_GYRO_CHANNEL(Y), + ADIS16475_GYRO_CHANNEL(Z), + ADIS16475_ACCEL_CHANNEL(X), + ADIS16475_ACCEL_CHANNEL(Y), + ADIS16475_ACCEL_CHANNEL(Z), + ADIS16475_TEMP_CHANNEL(), + ADIS16475_DELTANG_CHAN_NO_SCAN(X), + ADIS16475_DELTANG_CHAN_NO_SCAN(Y), + ADIS16475_DELTANG_CHAN_NO_SCAN(Z), + ADIS16475_DELTVEL_CHAN_NO_SCAN(X), + ADIS16475_DELTVEL_CHAN_NO_SCAN(Y), + ADIS16475_DELTVEL_CHAN_NO_SCAN(Z), + IIO_CHAN_SOFT_TIMESTAMP(7) +}; + enum adis16475_variant { ADIS16470, ADIS16475_1, @@ -782,8 +807,8 @@ static const struct adis16475_chip_info adis16475_chip_info[] = { }, [ADIS16477_1] = { .name = "adis16477-1", - .num_channels = ARRAY_SIZE(adis16475_channels), - .channels = adis16475_channels, + .num_channels = ARRAY_SIZE(adis16477_channels), + .channels = adis16477_channels, .gyro_max_val = 1, .gyro_max_scale = IIO_RAD_TO_DEGREE(160 << 16), .accel_max_val = 1, @@ -800,8 +825,8 @@ static const struct adis16475_chip_info adis16475_chip_info[] = { }, [ADIS16477_2] = { .name = "adis16477-2", - .num_channels = ARRAY_SIZE(adis16475_channels), - .channels = adis16475_channels, + .num_channels = ARRAY_SIZE(adis16477_channels), + .channels = adis16477_channels, .gyro_max_val = 1, .gyro_max_scale = IIO_RAD_TO_DEGREE(40 << 16), .accel_max_val = 1, @@ -818,8 +843,8 @@ static const struct adis16475_chip_info adis16475_chip_info[] = { }, [ADIS16477_3] = { .name = "adis16477-3", - .num_channels = ARRAY_SIZE(adis16475_channels), - .channels = adis16475_channels, + .num_channels = ARRAY_SIZE(adis16477_channels), + .channels = adis16477_channels, .gyro_max_val = 1, .gyro_max_scale = IIO_RAD_TO_DEGREE(10 << 16), .accel_max_val = 1, @@ -938,8 +963,8 @@ static const struct adis16475_chip_info adis16475_chip_info[] = { }, [ADIS16500] = { .name = "adis16500", - .num_channels = ARRAY_SIZE(adis16475_channels), - .channels = adis16475_channels, + .num_channels = ARRAY_SIZE(adis16477_channels), + .channels = adis16477_channels, .gyro_max_val = 1, .gyro_max_scale = IIO_RAD_TO_DEGREE(10 << 16), .accel_max_val = 392, @@ -957,8 +982,8 @@ static const struct adis16475_chip_info adis16475_chip_info[] = { }, [ADIS16505_1] = { .name = "adis16505-1", - .num_channels = ARRAY_SIZE(adis16475_channels), - .channels = adis16475_channels, + .num_channels = ARRAY_SIZE(adis16477_channels), + .channels = adis16477_channels, .gyro_max_val = 1, .gyro_max_scale = IIO_RAD_TO_DEGREE(160 << 16), .accel_max_val = 78, @@ -976,8 +1001,8 @@ static const struct adis16475_chip_info adis16475_chip_info[] = { }, [ADIS16505_2] = { .name = "adis16505-2", - .num_channels = ARRAY_SIZE(adis16475_channels), - .channels = adis16475_channels, + .num_channels = ARRAY_SIZE(adis16477_channels), + .channels = adis16477_channels, .gyro_max_val = 1, .gyro_max_scale = IIO_RAD_TO_DEGREE(40 << 16), .accel_max_val = 78, @@ -995,8 +1020,8 @@ static const struct adis16475_chip_info adis16475_chip_info[] = { }, [ADIS16505_3] = { .name = "adis16505-3", - .num_channels = ARRAY_SIZE(adis16475_channels), - .channels = adis16475_channels, + .num_channels = ARRAY_SIZE(adis16477_channels), + .channels = adis16477_channels, .gyro_max_val = 1, .gyro_max_scale = IIO_RAD_TO_DEGREE(10 << 16), .accel_max_val = 78, @@ -1014,8 +1039,8 @@ static const struct adis16475_chip_info adis16475_chip_info[] = { }, [ADIS16507_1] = { .name = "adis16507-1", - .num_channels = ARRAY_SIZE(adis16475_channels), - .channels = adis16475_channels, + .num_channels = ARRAY_SIZE(adis16477_channels), + .channels = adis16477_channels, .gyro_max_val = 1, .gyro_max_scale = IIO_RAD_TO_DEGREE(160 << 16), .accel_max_val = 392, @@ -1033,8 +1058,8 @@ static const struct adis16475_chip_info adis16475_chip_info[] = { }, [ADIS16507_2] = { .name = "adis16507-2", - .num_channels = ARRAY_SIZE(adis16475_channels), - .channels = adis16475_channels, + .num_channels = ARRAY_SIZE(adis16477_channels), + .channels = adis16477_channels, .gyro_max_val = 1, .gyro_max_scale = IIO_RAD_TO_DEGREE(40 << 16), .accel_max_val = 392, @@ -1052,8 +1077,8 @@ static const struct adis16475_chip_info adis16475_chip_info[] = { }, [ADIS16507_3] = { .name = "adis16507-3", - .num_channels = ARRAY_SIZE(adis16475_channels), - .channels = adis16475_channels, + .num_channels = ARRAY_SIZE(adis16477_channels), + .channels = adis16477_channels, .gyro_max_val = 1, .gyro_max_scale = IIO_RAD_TO_DEGREE(10 << 16), .accel_max_val = 392, From b1a078a8b0dbfcac8b61618282295124e30a9dce Mon Sep 17 00:00:00 2001 From: Javier Carrasco Date: Thu, 12 Oct 2023 22:07:07 +0200 Subject: [PATCH 267/326] iio: si7005: Add device tree support This device supports ACPI detection but lacks of the device tree counterpart. Add device tree support. Signed-off-by: Javier Carrasco Link: https://lore.kernel.org/r/20231012-topic-si7005_devicetree-v1-1-6c8a6fa7b3ec@gmail.com Signed-off-by: Jonathan Cameron --- drivers/iio/humidity/si7005.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/iio/humidity/si7005.c b/drivers/iio/humidity/si7005.c index ebfb79bc9edc..9465908cc65e 100644 --- a/drivers/iio/humidity/si7005.c +++ b/drivers/iio/humidity/si7005.c @@ -169,9 +169,16 @@ static const struct i2c_device_id si7005_id[] = { }; MODULE_DEVICE_TABLE(i2c, si7005_id); +static const struct of_device_id si7005_dt_ids[] = { + { .compatible = "silabs,si7005" }, + { } +}; +MODULE_DEVICE_TABLE(of, si7005_dt_ids); + static struct i2c_driver si7005_driver = { .driver = { .name = "si7005", + .of_match_table = si7005_dt_ids, }, .probe = si7005_probe, .id_table = si7005_id, From e16247acaeb9cae49ca92133ac18a1bfc4c40060 Mon Sep 17 00:00:00 2001 From: Javier Carrasco Date: Thu, 12 Oct 2023 22:07:08 +0200 Subject: [PATCH 268/326] dt-bindings: trivial-devices: add silabs,si7005 This simple I2C humidity sensor does not have any additional properties and can be added to the trivial-devices binding. Signed-off-by: Javier Carrasco Acked-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20231012-topic-si7005_devicetree-v1-2-6c8a6fa7b3ec@gmail.com Signed-off-by: Jonathan Cameron --- Documentation/devicetree/bindings/trivial-devices.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Documentation/devicetree/bindings/trivial-devices.yaml b/Documentation/devicetree/bindings/trivial-devices.yaml index cd58179ae337..216d9ae9f206 100644 --- a/Documentation/devicetree/bindings/trivial-devices.yaml +++ b/Documentation/devicetree/bindings/trivial-devices.yaml @@ -348,6 +348,8 @@ properties: # Silicon Labs SI3210 Programmable CMOS SLIC/CODEC with SPI interface - silabs,si3210 # Relative Humidity and Temperature Sensors + - silabs,si7005 + # Relative Humidity and Temperature Sensors - silabs,si7020 # Skyworks SKY81452: Six-Channel White LED Driver with Touch Panel Bias Supply - skyworks,sky81452 From 349c1b49ffafd9f0e49153599efd5cd251ba60b1 Mon Sep 17 00:00:00 2001 From: Marius Cristea Date: Fri, 13 Oct 2023 16:23:33 +0300 Subject: [PATCH 269/326] iio: adc: MCP3564: fix warn: unsigned '__x' is never less than zero. The patch 33ec3e5fc1ea: "iio: adc: adding support for MCP3564 ADC" leads to the following Smatch static checker warning: smatch warnings: drivers/iio/adc/mcp3564.c:1105 mcp3564_fill_scale_tbls() warn: unsigned '__x' is never less than zero. vim +/__x +1105 drivers/iio/adc/mcp3564.c 1094 1095 static void mcp3564_fill_scale_tbls(struct mcp3564_state *adc) 1096 { ..... 1103 for (i = 0; i < MCP3564_MAX_PGA; i++) { 1104 ref = adc->vref_mv; > 1105 tmp1 = shift_right((u64)ref * NANO, pow); 1106 div_u64_rem(tmp1, NANO, &tmp0); 1107 ..... 1113 } Reported-by: kernel test robot Closes: https://lore.kernel.org/oe-kbuild-all/202309280738.NWjVfVt4-lkp@intel.com/ Fixes: 33ec3e5fc1ea (iio: adc: adding support for MCP3564 ADC) Signed-off-by: Marius Cristea Link: https://lore.kernel.org/r/20231013132333.10582-1-marius.cristea@microchip.com Signed-off-by: Jonathan Cameron --- drivers/iio/adc/mcp3564.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/iio/adc/mcp3564.c b/drivers/iio/adc/mcp3564.c index 9ede1a5d5d7b..e3f1de5fcc5a 100644 --- a/drivers/iio/adc/mcp3564.c +++ b/drivers/iio/adc/mcp3564.c @@ -1102,7 +1102,7 @@ static void mcp3564_fill_scale_tbls(struct mcp3564_state *adc) for (i = 0; i < MCP3564_MAX_PGA; i++) { ref = adc->vref_mv; - tmp1 = shift_right((u64)ref * NANO, pow); + tmp1 = ((u64)ref * NANO) >> pow; div_u64_rem(tmp1, NANO, &tmp0); tmp1 = tmp1 * mcp3564_hwgain_frac[(2 * i) + 1]; From 89a1d2f064d2ae77a9cd6a8c7ac42b3c1647efa5 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Fri, 6 Oct 2023 17:44:39 -0500 Subject: [PATCH 270/326] iio: Use device_get_match_data() Use preferred device_get_match_data() instead of of_match_device() to get the driver match data. With this, adjust the includes to explicitly include the correct headers. Signed-off-by: Rob Herring Link: https://lore.kernel.org/r/20231006224440.442864-1-robh@kernel.org Signed-off-by: Jonathan Cameron --- drivers/iio/adc/stm32-adc-core.c | 11 +++-------- drivers/iio/adc/twl6030-gpadc.c | 10 ++++------ drivers/iio/dac/stm32-dac-core.c | 9 ++++----- 3 files changed, 11 insertions(+), 19 deletions(-) diff --git a/drivers/iio/adc/stm32-adc-core.c b/drivers/iio/adc/stm32-adc-core.c index c19506b0aac8..616dd729666a 100644 --- a/drivers/iio/adc/stm32-adc-core.c +++ b/drivers/iio/adc/stm32-adc-core.c @@ -17,10 +17,11 @@ #include #include #include -#include +#include #include #include #include +#include #include #include #include @@ -708,8 +709,6 @@ static int stm32_adc_probe(struct platform_device *pdev) struct stm32_adc_priv *priv; struct device *dev = &pdev->dev; struct device_node *np = pdev->dev.of_node; - const struct of_device_id *of_id; - struct resource *res; u32 max_rate; int ret; @@ -722,11 +721,7 @@ static int stm32_adc_probe(struct platform_device *pdev) return -ENOMEM; platform_set_drvdata(pdev, &priv->common); - of_id = of_match_device(dev->driver->of_match_table, dev); - if (!of_id) - return -ENODEV; - - priv->cfg = (const struct stm32_adc_priv_cfg *)of_id->data; + priv->cfg = device_get_match_data(dev); priv->nb_adc_max = priv->cfg->num_adcs; spin_lock_init(&priv->common.lock); diff --git a/drivers/iio/adc/twl6030-gpadc.c b/drivers/iio/adc/twl6030-gpadc.c index 224e9cb5e147..78bf55438b2c 100644 --- a/drivers/iio/adc/twl6030-gpadc.c +++ b/drivers/iio/adc/twl6030-gpadc.c @@ -16,9 +16,10 @@ */ #include #include +#include #include #include -#include +#include #include #include #include @@ -879,17 +880,14 @@ static int twl6030_gpadc_probe(struct platform_device *pdev) struct device *dev = &pdev->dev; struct twl6030_gpadc_data *gpadc; const struct twl6030_gpadc_platform_data *pdata; - const struct of_device_id *match; struct iio_dev *indio_dev; int irq; int ret; - match = of_match_device(of_twl6030_match_tbl, dev); - if (!match) + pdata = device_get_match_data(&pdev->dev); + if (!pdata) return -EINVAL; - pdata = match->data; - indio_dev = devm_iio_device_alloc(dev, sizeof(*gpadc)); if (!indio_dev) return -ENOMEM; diff --git a/drivers/iio/dac/stm32-dac-core.c b/drivers/iio/dac/stm32-dac-core.c index 15abe048729e..e150ac729154 100644 --- a/drivers/iio/dac/stm32-dac-core.c +++ b/drivers/iio/dac/stm32-dac-core.c @@ -9,9 +9,12 @@ #include #include +#include #include #include +#include #include +#include #include #include @@ -94,16 +97,12 @@ static int stm32_dac_probe(struct platform_device *pdev) struct reset_control *rst; int ret; - if (!dev->of_node) - return -ENODEV; - priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); if (!priv) return -ENOMEM; platform_set_drvdata(pdev, &priv->common); - cfg = (const struct stm32_dac_cfg *) - of_match_device(dev->driver->of_match_table, dev)->data; + cfg = device_get_match_data(dev); mmio = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(mmio)) From 3b08f52c256189b7c0d5cf1a031fa464ec20393b Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Fri, 6 Oct 2023 17:46:24 -0500 Subject: [PATCH 271/326] fpga: altera-ps-spi: Use spi_get_device_match_data() Use preferred spi_get_device_match_data() instead of of_match_device() and spi_get_device_id() to get the driver match data. With this, adjust the includes to explicitly include the correct headers. Also drop of_match_ptr for of_ef_match, which is not necessary because DT is always used for this driver. Signed-off-by: Rob Herring Acked-by: Xu Yilun Link: https://lore.kernel.org/r/20231006224624.444857-1-robh@kernel.org [yilun.xu@intel.com: drop of_match_ptr for of_ef_match] Signed-off-by: Xu Yilun --- drivers/fpga/altera-ps-spi.c | 46 +++++------------------------------- 1 file changed, 6 insertions(+), 40 deletions(-) diff --git a/drivers/fpga/altera-ps-spi.c b/drivers/fpga/altera-ps-spi.c index 5e1e009dba89..740980e7cef8 100644 --- a/drivers/fpga/altera-ps-spi.c +++ b/drivers/fpga/altera-ps-spi.c @@ -18,8 +18,7 @@ #include #include #include -#include -#include +#include #include #include @@ -72,12 +71,6 @@ static struct altera_ps_data a10_data = { .t_st2ck_us = 10, /* min(t_ST2CK) */ }; -/* Array index is enum altera_ps_devtype */ -static const struct altera_ps_data *altera_ps_data_map[] = { - &c5_data, - &a10_data, -}; - static const struct of_device_id of_ef_match[] = { { .compatible = "altr,fpga-passive-serial", .data = &c5_data }, { .compatible = "altr,fpga-arria10-passive-serial", .data = &a10_data }, @@ -237,43 +230,16 @@ static const struct fpga_manager_ops altera_ps_ops = { .write_complete = altera_ps_write_complete, }; -static const struct altera_ps_data *id_to_data(const struct spi_device_id *id) -{ - kernel_ulong_t devtype = id->driver_data; - const struct altera_ps_data *data; - - /* someone added a altera_ps_devtype without adding to the map array */ - if (devtype >= ARRAY_SIZE(altera_ps_data_map)) - return NULL; - - data = altera_ps_data_map[devtype]; - if (!data || data->devtype != devtype) - return NULL; - - return data; -} - static int altera_ps_probe(struct spi_device *spi) { struct altera_ps_conf *conf; - const struct of_device_id *of_id; struct fpga_manager *mgr; conf = devm_kzalloc(&spi->dev, sizeof(*conf), GFP_KERNEL); if (!conf) return -ENOMEM; - if (spi->dev.of_node) { - of_id = of_match_device(of_ef_match, &spi->dev); - if (!of_id) - return -ENODEV; - conf->data = of_id->data; - } else { - conf->data = id_to_data(spi_get_device_id(spi)); - if (!conf->data) - return -ENODEV; - } - + conf->data = spi_get_device_match_data(spi); conf->spi = spi; conf->config = devm_gpiod_get(&spi->dev, "nconfig", GPIOD_OUT_LOW); if (IS_ERR(conf->config)) { @@ -308,9 +274,9 @@ static int altera_ps_probe(struct spi_device *spi) } static const struct spi_device_id altera_ps_spi_ids[] = { - { "cyclone-ps-spi", CYCLONE5 }, - { "fpga-passive-serial", CYCLONE5 }, - { "fpga-arria10-passive-serial", ARRIA10 }, + { "cyclone-ps-spi", (uintptr_t)&c5_data }, + { "fpga-passive-serial", (uintptr_t)&c5_data }, + { "fpga-arria10-passive-serial", (uintptr_t)&a10_data }, {} }; MODULE_DEVICE_TABLE(spi, altera_ps_spi_ids); @@ -319,7 +285,7 @@ static struct spi_driver altera_ps_driver = { .driver = { .name = "altera-ps-spi", .owner = THIS_MODULE, - .of_match_table = of_match_ptr(of_ef_match), + .of_match_table = of_ef_match, }, .id_table = altera_ps_spi_ids, .probe = altera_ps_probe, From d79eed22ba97c3031b2ef86f8b7ed0be2da5667d Mon Sep 17 00:00:00 2001 From: Nava kishore Manne Date: Tue, 3 Oct 2023 12:44:09 +0530 Subject: [PATCH 272/326] fpga: versal: Add support for 44-bit DMA operations The existing implementation support only 32-bit DMA operation. So, it fails to load the bitstream for the high DDR designs(Beyond 4GB). To fix this issue update the DMA mask handling logic to support 44-bit DMA operations. Signed-off-by: Nava kishore Manne Reviewed-by: Radhey Shyam Pandey Acked-by: Xu Yilun Link: https://lore.kernel.org/r/20231003071409.4165149-1-nava.kishore.manne@amd.com Signed-off-by: Xu Yilun --- drivers/fpga/versal-fpga.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/fpga/versal-fpga.c b/drivers/fpga/versal-fpga.c index e1601b3a345b..3710e8f01be2 100644 --- a/drivers/fpga/versal-fpga.c +++ b/drivers/fpga/versal-fpga.c @@ -48,7 +48,7 @@ static int versal_fpga_probe(struct platform_device *pdev) struct fpga_manager *mgr; int ret; - ret = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32)); + ret = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(44)); if (ret < 0) { dev_err(dev, "no usable DMA configuration\n"); return ret; From 7904cdf1397c9391178ce53a7ebfa099c6bc4a59 Mon Sep 17 00:00:00 2001 From: Fabrice Gasnier Date: Tue, 29 Aug 2023 15:40:23 +0200 Subject: [PATCH 273/326] counter: chrdev: remove a typo in header file comment Replace COUNTER_COUNT_SCOPE that doesn't exist by the defined COUNTER_SCOPE_COUNT. Signed-off-by: Fabrice Gasnier Link: https://lore.kernel.org/r/20230829134029.2402868-3-fabrice.gasnier@foss.st.com Signed-off-by: William Breathitt Gray --- include/uapi/linux/counter.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/uapi/linux/counter.h b/include/uapi/linux/counter.h index fc248ef00e86..008a691c254b 100644 --- a/include/uapi/linux/counter.h +++ b/include/uapi/linux/counter.h @@ -38,7 +38,7 @@ enum counter_scope { * * For example, if the Count 2 ceiling extension of Counter device 4 is desired, * set type equal to COUNTER_COMPONENT_EXTENSION, scope equal to - * COUNTER_COUNT_SCOPE, parent equal to 2, and id equal to the value provided by + * COUNTER_SCOPE_COUNT, parent equal to 2, and id equal to the value provided by * the respective /sys/bus/counter/devices/counter4/count2/ceiling_component_id * sysfs attribute. */ From b3edc3463d64bc469162138a6bec6913fbeef931 Mon Sep 17 00:00:00 2001 From: Stanley Chang Date: Mon, 16 Oct 2023 13:35:04 +0800 Subject: [PATCH 274/326] extcon: realtek: add the error handler for nvmem_cell_read There are following smatch warning: drivers/extcon/extcon-rtk-type-c.c:905 __updated_type_c_parameter_by_efuse() error: 'buf' dereferencing possible ERR_PTR() The nvmem_cell_read may fail to read. So, driver must handle failure cases. Link: https://lore.kernel.org/all/20231016053510.28881-1-stanley_chang@realtek.com/ Fixes: 8a590d7371f0 ("extcon: add Realtek DHC RTD SoC Type-C driver") Reported-by: Dan Carpenter Closes: https://lore.kernel.org/all/a469dd51-f5d5-4e8f-ba36-6c7cea046fb8@moroto.mountain/ Signed-off-by: Stanley Chang Signed-off-by: Chanwoo Choi --- drivers/extcon/extcon-rtk-type-c.c | 74 +++++++++++++++--------------- 1 file changed, 38 insertions(+), 36 deletions(-) diff --git a/drivers/extcon/extcon-rtk-type-c.c b/drivers/extcon/extcon-rtk-type-c.c index 00465cfba23e..a592bab77538 100644 --- a/drivers/extcon/extcon-rtk-type-c.c +++ b/drivers/extcon/extcon-rtk-type-c.c @@ -901,25 +901,26 @@ static int __updated_type_c_parameter_by_efuse(struct type_c_data *type_c) int value_mask = (BIT(value_size) - 1); buf = nvmem_cell_read(cell, &buf_size); + if (!IS_ERR(buf)) { + cc1_0p2v = get_value((buf[0] >> value_size * 0) & value_mask); + cc1_0p8v = get_value((buf[0] >> value_size * 1) & value_mask); + cc1_2p6v = get_value((buf[1] >> value_size * 0) & value_mask); + cc1_0p66v = get_value((buf[1] >> value_size * 1) & value_mask); + cc1_1p23v = get_value((buf[2] >> value_size * 0) & value_mask); - cc1_0p2v = get_value((buf[0] >> value_size * 0) & value_mask); - cc1_0p8v = get_value((buf[0] >> value_size * 1) & value_mask); - cc1_2p6v = get_value((buf[1] >> value_size * 0) & value_mask); - cc1_0p66v = get_value((buf[1] >> value_size * 1) & value_mask); - cc1_1p23v = get_value((buf[2] >> value_size * 0) & value_mask); + cc2_0p2v = get_value((buf[3] >> value_size * 0) & value_mask); + cc2_0p8v = get_value((buf[3] >> value_size * 1) & value_mask); + cc2_2p6v = get_value((buf[4] >> value_size * 0) & value_mask); + cc2_0p66v = get_value((buf[4] >> value_size * 1) & value_mask); + cc2_1p23v = get_value((buf[5] >> value_size * 0) & value_mask); - cc2_0p2v = get_value((buf[3] >> value_size * 0) & value_mask); - cc2_0p8v = get_value((buf[3] >> value_size * 1) & value_mask); - cc2_2p6v = get_value((buf[4] >> value_size * 0) & value_mask); - cc2_0p66v = get_value((buf[4] >> value_size * 1) & value_mask); - cc2_1p23v = get_value((buf[5] >> value_size * 0) & value_mask); + cc1_4p7k = get_value((buf[6] >> value_size * 0) & value_mask); + cc1_12k = get_value((buf[6] >> value_size * 1) & value_mask); + cc2_4p7k = get_value((buf[7] >> value_size * 0) & value_mask); + cc2_12k = get_value((buf[7] >> value_size * 1) & value_mask); - cc1_4p7k = get_value((buf[6] >> value_size * 0) & value_mask); - cc1_12k = get_value((buf[6] >> value_size * 1) & value_mask); - cc2_4p7k = get_value((buf[7] >> value_size * 0) & value_mask); - cc2_12k = get_value((buf[7] >> value_size * 1) & value_mask); - - kfree(buf); + kfree(buf); + } nvmem_cell_put(cell); } @@ -984,29 +985,30 @@ static int __updated_type_c_parameter_by_efuse_v2(struct type_c_data *type_c) int value_mask = (BIT(value_size) - 1); buf = nvmem_cell_read(cell, &buf_size); + if (!IS_ERR(buf)) { + value_size = 5; + value_mask = (BIT(value_size) - 1); + cc1_4p7k = buf[0] & value_mask; + cc1_12k = buf[1] & value_mask; + cc2_4p7k = buf[2] & value_mask; + cc2_12k = buf[3] & value_mask; - value_size = 5; - value_mask = (BIT(value_size) - 1); - cc1_4p7k = buf[0] & value_mask; - cc1_12k = buf[1] & value_mask; - cc2_4p7k = buf[2] & value_mask; - cc2_12k = buf[3] & value_mask; + value_size = 4; + value_mask = (BIT(value_size) - 1); + cc1_0p2v = (buf[4] >> value_size * 0) & value_mask; + cc1_0p66v = (buf[4] >> value_size * 1) & value_mask; + cc1_0p8v = (buf[5] >> value_size * 0) & value_mask; + cc1_1p23v = (buf[5] >> value_size * 1) & value_mask; + cc1_2p6v = (buf[6] >> value_size * 0) & value_mask; - value_size = 4; - value_mask = (BIT(value_size) - 1); - cc1_0p2v = (buf[4] >> value_size * 0) & value_mask; - cc1_0p66v = (buf[4] >> value_size * 1) & value_mask; - cc1_0p8v = (buf[5] >> value_size * 0) & value_mask; - cc1_1p23v = (buf[5] >> value_size * 1) & value_mask; - cc1_2p6v = (buf[6] >> value_size * 0) & value_mask; + cc2_0p2v = (buf[6] >> value_size * 1) & value_mask; + cc2_0p66v = (buf[7] >> value_size * 0) & value_mask; + cc2_0p8v = (buf[7] >> value_size * 1) & value_mask; + cc2_1p23v = (buf[8] >> value_size * 0) & value_mask; + cc2_2p6v = (buf[8] >> value_size * 1) & value_mask; - cc2_0p2v = (buf[6] >> value_size * 1) & value_mask; - cc2_0p66v = (buf[7] >> value_size * 0) & value_mask; - cc2_0p8v = (buf[7] >> value_size * 1) & value_mask; - cc2_1p23v = (buf[8] >> value_size * 0) & value_mask; - cc2_2p6v = (buf[8] >> value_size * 1) & value_mask; - - kfree(buf); + kfree(buf); + } nvmem_cell_put(cell); } From cf439721f66719c6aa73b5ea23320c2f8cba100f Mon Sep 17 00:00:00 2001 From: Alexander Usyskin Date: Wed, 11 Oct 2023 14:01:54 +0300 Subject: [PATCH 275/326] mei: bus: add send and recv api with timeout Add variation of the send and recv functions on bus that define timeout. Caller can use such functions in flow that can stuck to bail out and not to put down the whole system. Signed-off-by: Alexander Usyskin Signed-off-by: Alan Previn Signed-off-by: Tomas Winkler Link: https://lore.kernel.org/r/20231011110157.247552-2-tomas.winkler@intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/misc/mei/bus.c | 88 +++++++++++++++++++++++++++++++++++++- include/linux/mei_cl_bus.h | 8 ++++ 2 files changed, 94 insertions(+), 2 deletions(-) diff --git a/drivers/misc/mei/bus.c b/drivers/misc/mei/bus.c index 2e65ce6bdec7..7f4ee9a47404 100644 --- a/drivers/misc/mei/bus.c +++ b/drivers/misc/mei/bus.c @@ -257,7 +257,7 @@ out: } /** - * mei_cldev_send_vtag - me device send with vtag (write) + * mei_cldev_send_vtag - me device send with vtag (write) * * @cldev: me client device * @buf: buffer to send @@ -278,6 +278,29 @@ ssize_t mei_cldev_send_vtag(struct mei_cl_device *cldev, const u8 *buf, } EXPORT_SYMBOL_GPL(mei_cldev_send_vtag); +/** + * mei_cldev_send_vtag_timeout - me device send with vtag and timeout (write) + * + * @cldev: me client device + * @buf: buffer to send + * @length: buffer length + * @vtag: virtual tag + * @timeout: send timeout in milliseconds, 0 for infinite timeout + * + * Return: + * * written size in bytes + * * < 0 on error + */ + +ssize_t mei_cldev_send_vtag_timeout(struct mei_cl_device *cldev, const u8 *buf, + size_t length, u8 vtag, unsigned long timeout) +{ + struct mei_cl *cl = cldev->cl; + + return __mei_cl_send_timeout(cl, buf, length, vtag, MEI_CL_IO_TX_BLOCKING, timeout); +} +EXPORT_SYMBOL_GPL(mei_cldev_send_vtag_timeout); + /** * mei_cldev_recv_vtag - client receive with vtag (read) * @@ -323,7 +346,49 @@ ssize_t mei_cldev_recv_nonblock_vtag(struct mei_cl_device *cldev, u8 *buf, EXPORT_SYMBOL_GPL(mei_cldev_recv_nonblock_vtag); /** - * mei_cldev_send - me device send (write) + * mei_cldev_recv_timeout - client receive with timeout (read) + * + * @cldev: me client device + * @buf: buffer to receive + * @length: buffer length + * @timeout: send timeout in milliseconds, 0 for infinite timeout + * + * Return: + * * read size in bytes + * * < 0 on error + */ +ssize_t mei_cldev_recv_timeout(struct mei_cl_device *cldev, u8 *buf, size_t length, + unsigned long timeout) +{ + return mei_cldev_recv_vtag_timeout(cldev, buf, length, NULL, timeout); +} +EXPORT_SYMBOL_GPL(mei_cldev_recv_timeout); + +/** + * mei_cldev_recv_vtag_timeout - client receive with vtag (read) + * + * @cldev: me client device + * @buf: buffer to receive + * @length: buffer length + * @vtag: virtual tag + * @timeout: recv timeout in milliseconds, 0 for infinite timeout + * + * Return: + * * read size in bytes + * * < 0 on error + */ + +ssize_t mei_cldev_recv_vtag_timeout(struct mei_cl_device *cldev, u8 *buf, size_t length, + u8 *vtag, unsigned long timeout) +{ + struct mei_cl *cl = cldev->cl; + + return __mei_cl_recv(cl, buf, length, vtag, 0, timeout); +} +EXPORT_SYMBOL_GPL(mei_cldev_recv_vtag_timeout); + +/** + * mei_cldev_send - me device send (write) * * @cldev: me client device * @buf: buffer to send @@ -339,6 +404,25 @@ ssize_t mei_cldev_send(struct mei_cl_device *cldev, const u8 *buf, size_t length } EXPORT_SYMBOL_GPL(mei_cldev_send); +/** + * mei_cldev_send_timeout - me device send with timeout (write) + * + * @cldev: me client device + * @buf: buffer to send + * @length: buffer length + * @timeout: send timeout in milliseconds, 0 for infinite timeout + * + * Return: + * * written size in bytes + * * < 0 on error + */ +ssize_t mei_cldev_send_timeout(struct mei_cl_device *cldev, const u8 *buf, size_t length, + unsigned long timeout) +{ + return mei_cldev_send_vtag_timeout(cldev, buf, length, 0, timeout); +} +EXPORT_SYMBOL_GPL(mei_cldev_send_timeout); + /** * mei_cldev_recv - client receive (read) * diff --git a/include/linux/mei_cl_bus.h b/include/linux/mei_cl_bus.h index fd6e0620658d..b77cefd4f0c0 100644 --- a/include/linux/mei_cl_bus.h +++ b/include/linux/mei_cl_bus.h @@ -94,15 +94,23 @@ void mei_cldev_driver_unregister(struct mei_cl_driver *cldrv); ssize_t mei_cldev_send(struct mei_cl_device *cldev, const u8 *buf, size_t length); +ssize_t mei_cldev_send_timeout(struct mei_cl_device *cldev, const u8 *buf, + size_t length, unsigned long timeout); ssize_t mei_cldev_recv(struct mei_cl_device *cldev, u8 *buf, size_t length); ssize_t mei_cldev_recv_nonblock(struct mei_cl_device *cldev, u8 *buf, size_t length); +ssize_t mei_cldev_recv_timeout(struct mei_cl_device *cldev, u8 *buf, size_t length, + unsigned long timeout); ssize_t mei_cldev_send_vtag(struct mei_cl_device *cldev, const u8 *buf, size_t length, u8 vtag); +ssize_t mei_cldev_send_vtag_timeout(struct mei_cl_device *cldev, const u8 *buf, + size_t length, u8 vtag, unsigned long timeout); ssize_t mei_cldev_recv_vtag(struct mei_cl_device *cldev, u8 *buf, size_t length, u8 *vtag); ssize_t mei_cldev_recv_nonblock_vtag(struct mei_cl_device *cldev, u8 *buf, size_t length, u8 *vtag); +ssize_t mei_cldev_recv_vtag_timeout(struct mei_cl_device *cldev, u8 *buf, size_t length, + u8 *vtag, unsigned long timeout); int mei_cldev_register_rx_cb(struct mei_cl_device *cldev, mei_cldev_cb_t rx_cb); int mei_cldev_register_notif_cb(struct mei_cl_device *cldev, From ee5cb39348e69a61a865801970ba8fdc399335de Mon Sep 17 00:00:00 2001 From: Alexander Usyskin Date: Wed, 11 Oct 2023 14:01:55 +0300 Subject: [PATCH 276/326] mei: pxp: recover from recv fail under memory pressure Under memory pressure recv fails due to kmalloc failure, and if drivers(pxp) retry send/receive, send blocks indefinitely. Send without recv leaves the channel in a bad state. Retry send attempt after small timeout and reset the channel if the retry failed on kmalloc failure too. Signed-off-by: Alexander Usyskin Signed-off-by: Alan Previn Signed-off-by: Tomas Winkler Link: https://lore.kernel.org/r/20231011110157.247552-3-tomas.winkler@intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/misc/mei/pxp/mei_pxp.c | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/drivers/misc/mei/pxp/mei_pxp.c b/drivers/misc/mei/pxp/mei_pxp.c index 2dcb9169e404..c6cdd6a47308 100644 --- a/drivers/misc/mei/pxp/mei_pxp.c +++ b/drivers/misc/mei/pxp/mei_pxp.c @@ -11,6 +11,7 @@ * negotiation messages to ME FW command payloads and vice versa. */ +#include #include #include #include @@ -61,16 +62,38 @@ mei_pxp_receive_message(struct device *dev, void *buffer, size_t size) { struct mei_cl_device *cldev; ssize_t byte; + bool retry = false; if (!dev || !buffer) return -EINVAL; cldev = to_mei_cl_device(dev); +retry: byte = mei_cldev_recv(cldev, buffer, size); if (byte < 0) { dev_dbg(dev, "mei_cldev_recv failed. %zd\n", byte); - return byte; + if (byte != -ENOMEM) + return byte; + + /* Retry the read when pages are reclaimed */ + msleep(20); + if (!retry) { + retry = true; + goto retry; + } else { + dev_warn(dev, "No memory on data receive after retry, trying to reset the channel...\n"); + byte = mei_cldev_disable(cldev); + if (byte < 0) + dev_warn(dev, "mei_cldev_disable failed. %zd\n", byte); + /* + * Explicitly ignoring disable failure, + * enable may fix the states and succeed + */ + byte = mei_cldev_enable(cldev); + if (byte < 0) + dev_err(dev, "mei_cldev_enable failed. %zd\n", byte); + } } return byte; From dab79a2235e5a1d6aadfeb601c84f31b5cb97141 Mon Sep 17 00:00:00 2001 From: Alexander Usyskin Date: Wed, 11 Oct 2023 14:01:56 +0300 Subject: [PATCH 277/326] mei: pxp: re-enable client on errors Disable and enable mei-pxp client on errors to clean the internal state. Signed-off-by: Alexander Usyskin Signed-off-by: Tomas Winkler Link: https://lore.kernel.org/r/20231011110157.247552-4-tomas.winkler@intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/misc/mei/pxp/mei_pxp.c | 70 +++++++++++++++++++++++----------- 1 file changed, 48 insertions(+), 22 deletions(-) diff --git a/drivers/misc/mei/pxp/mei_pxp.c b/drivers/misc/mei/pxp/mei_pxp.c index c6cdd6a47308..9875d16445bb 100644 --- a/drivers/misc/mei/pxp/mei_pxp.c +++ b/drivers/misc/mei/pxp/mei_pxp.c @@ -23,6 +23,24 @@ #include "mei_pxp.h" +static inline int mei_pxp_reenable(const struct device *dev, struct mei_cl_device *cldev) +{ + int ret; + + dev_warn(dev, "Trying to reset the channel...\n"); + ret = mei_cldev_disable(cldev); + if (ret < 0) + dev_warn(dev, "mei_cldev_disable failed. %d\n", ret); + /* + * Explicitly ignoring disable failure, + * enable may fix the states and succeed + */ + ret = mei_cldev_enable(cldev); + if (ret < 0) + dev_err(dev, "mei_cldev_enable failed. %d\n", ret); + return ret; +} + /** * mei_pxp_send_message() - Sends a PXP message to ME FW. * @dev: device corresponding to the mei_cl_device @@ -35,6 +53,7 @@ mei_pxp_send_message(struct device *dev, const void *message, size_t size) { struct mei_cl_device *cldev; ssize_t byte; + int ret; if (!dev || !message) return -EINVAL; @@ -44,10 +63,20 @@ mei_pxp_send_message(struct device *dev, const void *message, size_t size) byte = mei_cldev_send(cldev, message, size); if (byte < 0) { dev_dbg(dev, "mei_cldev_send failed. %zd\n", byte); - return byte; + switch (byte) { + case -ENOMEM: + fallthrough; + case -ENODEV: + fallthrough; + case -ETIME: + ret = mei_pxp_reenable(dev, cldev); + if (ret) + byte = ret; + break; + } } - return 0; + return byte; } /** @@ -63,6 +92,7 @@ mei_pxp_receive_message(struct device *dev, void *buffer, size_t size) struct mei_cl_device *cldev; ssize_t byte; bool retry = false; + int ret; if (!dev || !buffer) return -EINVAL; @@ -73,26 +103,22 @@ retry: byte = mei_cldev_recv(cldev, buffer, size); if (byte < 0) { dev_dbg(dev, "mei_cldev_recv failed. %zd\n", byte); - if (byte != -ENOMEM) - return byte; - - /* Retry the read when pages are reclaimed */ - msleep(20); - if (!retry) { - retry = true; - goto retry; - } else { - dev_warn(dev, "No memory on data receive after retry, trying to reset the channel...\n"); - byte = mei_cldev_disable(cldev); - if (byte < 0) - dev_warn(dev, "mei_cldev_disable failed. %zd\n", byte); - /* - * Explicitly ignoring disable failure, - * enable may fix the states and succeed - */ - byte = mei_cldev_enable(cldev); - if (byte < 0) - dev_err(dev, "mei_cldev_enable failed. %zd\n", byte); + switch (byte) { + case -ENOMEM: + /* Retry the read when pages are reclaimed */ + msleep(20); + if (!retry) { + retry = true; + goto retry; + } + fallthrough; + case -ENODEV: + fallthrough; + case -ETIME: + ret = mei_pxp_reenable(dev, cldev); + if (ret) + byte = ret; + break; } } From fb99e79ee62aaa07d9e77cb3a15c5f1ae2790e6a Mon Sep 17 00:00:00 2001 From: Alan Previn Date: Wed, 11 Oct 2023 14:01:57 +0300 Subject: [PATCH 278/326] mei: update mei-pxp's component interface with timeouts In debugging platform or firmware related MEI-PXP connection issues, having a timeout when clients (such as i915) calling into mei-pxp's send/receive functions have proven useful as opposed to blocking forever until the kernel triggers a watchdog panic (when platform issues are experienced). Update the mei-pxp component interface send and receive functions to take in timeouts. Signed-off-by: Alan Previn Signed-off-by: Alexander Usyskin Signed-off-by: Tomas Winkler Link: https://lore.kernel.org/r/20231011110157.247552-5-tomas.winkler@intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/i915/pxp/intel_pxp_tee.c | 8 ++++-- drivers/misc/mei/pxp/mei_pxp.c | 33 +++++++++++++++++++----- include/drm/i915_pxp_tee_interface.h | 6 +++-- 3 files changed, 37 insertions(+), 10 deletions(-) diff --git a/drivers/gpu/drm/i915/pxp/intel_pxp_tee.c b/drivers/gpu/drm/i915/pxp/intel_pxp_tee.c index 80bb00189865..dfc2878426fc 100644 --- a/drivers/gpu/drm/i915/pxp/intel_pxp_tee.c +++ b/drivers/gpu/drm/i915/pxp/intel_pxp_tee.c @@ -20,6 +20,8 @@ #include "intel_pxp_tee.h" #include "intel_pxp_types.h" +#define PXP_TRANSPORT_TIMEOUT_MS 5000 /* 5 sec */ + static bool is_fw_err_platform_config(u32 type) { @@ -71,13 +73,15 @@ static int intel_pxp_tee_io_message(struct intel_pxp *pxp, goto unlock; } - ret = pxp_component->ops->send(pxp_component->tee_dev, msg_in, msg_in_size); + ret = pxp_component->ops->send(pxp_component->tee_dev, msg_in, msg_in_size, + PXP_TRANSPORT_TIMEOUT_MS); if (ret) { drm_err(&i915->drm, "Failed to send PXP TEE message\n"); goto unlock; } - ret = pxp_component->ops->recv(pxp_component->tee_dev, msg_out, msg_out_max_size); + ret = pxp_component->ops->recv(pxp_component->tee_dev, msg_out, msg_out_max_size, + PXP_TRANSPORT_TIMEOUT_MS); if (ret < 0) { drm_err(&i915->drm, "Failed to receive PXP TEE message\n"); goto unlock; diff --git a/drivers/misc/mei/pxp/mei_pxp.c b/drivers/misc/mei/pxp/mei_pxp.c index 9875d16445bb..f77d78fa5054 100644 --- a/drivers/misc/mei/pxp/mei_pxp.c +++ b/drivers/misc/mei/pxp/mei_pxp.c @@ -46,10 +46,20 @@ static inline int mei_pxp_reenable(const struct device *dev, struct mei_cl_devic * @dev: device corresponding to the mei_cl_device * @message: a message buffer to send * @size: size of the message - * Return: 0 on Success, <0 on Failure + * @timeout_ms: timeout in milliseconds, zero means wait indefinitely. + * + * Returns: 0 on Success, <0 on Failure with the following defined failures. + * -ENODEV: Client was not connected. + * Caller may attempt to try again immediately. + * -ENOMEM: Internal memory allocation failure experienced. + * Caller may sleep to allow kernel reclaim before retrying. + * -EINTR : Calling thread received a signal. Caller may choose + * to abandon with the same thread id. + * -ETIME : Request is timed out. + * Caller may attempt to try again immediately. */ static int -mei_pxp_send_message(struct device *dev, const void *message, size_t size) +mei_pxp_send_message(struct device *dev, const void *message, size_t size, unsigned long timeout_ms) { struct mei_cl_device *cldev; ssize_t byte; @@ -60,7 +70,7 @@ mei_pxp_send_message(struct device *dev, const void *message, size_t size) cldev = to_mei_cl_device(dev); - byte = mei_cldev_send(cldev, message, size); + byte = mei_cldev_send_timeout(cldev, message, size, timeout_ms); if (byte < 0) { dev_dbg(dev, "mei_cldev_send failed. %zd\n", byte); switch (byte) { @@ -84,10 +94,21 @@ mei_pxp_send_message(struct device *dev, const void *message, size_t size) * @dev: device corresponding to the mei_cl_device * @buffer: a message buffer to contain the received message * @size: size of the buffer - * Return: bytes sent on Success, <0 on Failure + * @timeout_ms: timeout in milliseconds, zero means wait indefinitely. + * + * Returns: number of bytes send on Success, <0 on Failure with the following defined failures. + * -ENODEV: Client was not connected. + * Caller may attempt to try again from send immediately. + * -ENOMEM: Internal memory allocation failure experienced. + * Caller may sleep to allow kernel reclaim before retrying. + * -EINTR : Calling thread received a signal. Caller will need to repeat calling + * (with a different owning thread) to retrieve existing unclaimed response + * (and may discard it). + * -ETIME : Request is timed out. + * Caller may attempt to try again from send immediately. */ static int -mei_pxp_receive_message(struct device *dev, void *buffer, size_t size) +mei_pxp_receive_message(struct device *dev, void *buffer, size_t size, unsigned long timeout_ms) { struct mei_cl_device *cldev; ssize_t byte; @@ -100,7 +121,7 @@ mei_pxp_receive_message(struct device *dev, void *buffer, size_t size) cldev = to_mei_cl_device(dev); retry: - byte = mei_cldev_recv(cldev, buffer, size); + byte = mei_cldev_recv_timeout(cldev, buffer, size, timeout_ms); if (byte < 0) { dev_dbg(dev, "mei_cldev_recv failed. %zd\n", byte); switch (byte) { diff --git a/include/drm/i915_pxp_tee_interface.h b/include/drm/i915_pxp_tee_interface.h index a702b6ec17f7..7d96985f2d05 100644 --- a/include/drm/i915_pxp_tee_interface.h +++ b/include/drm/i915_pxp_tee_interface.h @@ -22,8 +22,10 @@ struct i915_pxp_component_ops { */ struct module *owner; - int (*send)(struct device *dev, const void *message, size_t size); - int (*recv)(struct device *dev, void *buffer, size_t size); + int (*send)(struct device *dev, const void *message, size_t size, + unsigned long timeout_ms); + int (*recv)(struct device *dev, void *buffer, size_t size, + unsigned long timeout_ms); ssize_t (*gsc_command)(struct device *dev, u8 client_id, u32 fence_id, struct scatterlist *sg_in, size_t total_in_len, struct scatterlist *sg_out); From 64459c626b5a08aa8e8fdaa128a218215df93675 Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Wed, 11 Oct 2023 10:42:59 +0300 Subject: [PATCH 279/326] mei: docs: use correct structures name in kdoc Fix misalignment between structures names and their kdoc in hw.h Signed-off-by: Tomas Winkler Reviewed-by: Randy Dunlap Link: https://lore.kernel.org/r/20231011074301.223879-2-tomas.winkler@intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/misc/mei/hw.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/misc/mei/hw.h b/drivers/misc/mei/hw.h index e910302fcd1f..3ad3080519c4 100644 --- a/drivers/misc/mei/hw.h +++ b/drivers/misc/mei/hw.h @@ -429,7 +429,7 @@ struct mei_bus_message { } __packed; /** - * struct hbm_cl_cmd - client specific host bus command + * struct mei_hbm_cl_cmd - client specific host bus command * CONNECT, DISCONNECT, and FlOW CONTROL * * @hbm_cmd: bus message command header @@ -733,7 +733,7 @@ struct hbm_dma_setup_response { } __packed; /** - * struct mei_dma_ring_ctrl - dma ring control block + * struct hbm_dma_ring_ctrl - dma ring control block * * @hbuf_wr_idx: host circular buffer write index in slots * @reserved1: reserved for alignment From d37b59c716a972834a614b093910fa345a469ee2 Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Wed, 11 Oct 2023 10:43:00 +0300 Subject: [PATCH 280/326] mei: docs: add missing entries to kdoc in struct mei_cfg_idx Document all entries in struct mei_cfg_idx. Signed-off-by: Tomas Winkler Reviewed-by: Randy Dunlap Link: https://lore.kernel.org/r/20231011074301.223879-3-tomas.winkler@intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/misc/mei/hw-me.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/misc/mei/hw-me.h b/drivers/misc/mei/hw-me.h index 95cf830b7c7b..204b92af6c47 100644 --- a/drivers/misc/mei/hw-me.h +++ b/drivers/misc/mei/hw-me.h @@ -102,10 +102,14 @@ static inline bool mei_me_hw_use_polling(const struct mei_me_hw *hw) * @MEI_ME_PCH12_SPS_CFG: Platform Controller Hub Gen12 5.0 and newer * servers platforms with quirk for * SPS firmware exclusion. + * @MEI_ME_PCH12_SPS_ITOUCH_CFG: Platform Controller Hub Gen12 + * client platforms (iTouch) * @MEI_ME_PCH15_CFG: Platform Controller Hub Gen15 and newer * @MEI_ME_PCH15_SPS_CFG: Platform Controller Hub Gen15 and newer * servers platforms with quirk for * SPS firmware exclusion. + * @MEI_ME_GSC_CFG: Graphics System Controller + * @MEI_ME_GSCFI_CFG: Graphics System Controller Firmware Interface * @MEI_ME_NUM_CFG: Upper Sentinel. */ enum mei_cfg_idx { From ae4cb6bd5039a659d71632dbc2e176bf9227e294 Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Wed, 11 Oct 2023 10:43:01 +0300 Subject: [PATCH 281/326] mei: docs: fix spelling errors Fix spelling errors in the mei code base. Signed-off-by: Tomas Winkler Reviewed-by: Randy Dunlap Link: https://lore.kernel.org/r/20231011074301.223879-4-tomas.winkler@intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/misc/mei/bus.c | 4 ++-- drivers/misc/mei/dma-ring.c | 2 +- drivers/misc/mei/hbm.c | 4 ++-- drivers/misc/mei/interrupt.c | 2 +- drivers/misc/mei/mei_dev.h | 4 ++-- include/linux/mei_cl_bus.h | 4 ++-- 6 files changed, 10 insertions(+), 10 deletions(-) diff --git a/drivers/misc/mei/bus.c b/drivers/misc/mei/bus.c index 7f4ee9a47404..f9bcff197615 100644 --- a/drivers/misc/mei/bus.c +++ b/drivers/misc/mei/bus.c @@ -1385,7 +1385,7 @@ static inline void mei_cl_bus_set_name(struct mei_cl_device *cldev) * @bus: mei device * @me_cl: me client * - * Return: allocated device structur or NULL on allocation failure + * Return: allocated device structure or NULL on allocation failure */ static struct mei_cl_device *mei_cl_bus_dev_alloc(struct mei_device *bus, struct mei_me_client *me_cl) @@ -1445,7 +1445,7 @@ static bool mei_cl_bus_dev_setup(struct mei_device *bus, * * @cldev: me client device * - * Return: 0 on success; < 0 on failre + * Return: 0 on success; < 0 on failure */ static int mei_cl_bus_dev_add(struct mei_cl_device *cldev) { diff --git a/drivers/misc/mei/dma-ring.c b/drivers/misc/mei/dma-ring.c index ef56f849b251..e5d800e68cb1 100644 --- a/drivers/misc/mei/dma-ring.c +++ b/drivers/misc/mei/dma-ring.c @@ -161,7 +161,7 @@ static size_t mei_dma_copy_to(struct mei_device *dev, unsigned char *buf, /** * mei_dma_ring_read() - read data from the ring * @dev: mei device - * @buf: buffer to read into: may be NULL in case of droping the data. + * @buf: buffer to read into: may be NULL in case of dropping the data. * @len: length to read. */ void mei_dma_ring_read(struct mei_device *dev, unsigned char *buf, u32 len) diff --git a/drivers/misc/mei/hbm.c b/drivers/misc/mei/hbm.c index 12a62a911e42..15737655c896 100644 --- a/drivers/misc/mei/hbm.c +++ b/drivers/misc/mei/hbm.c @@ -111,7 +111,7 @@ void mei_hbm_idle(struct mei_device *dev) } /** - * mei_hbm_reset - reset hbm counters and book keeping data structurs + * mei_hbm_reset - reset hbm counters and book keeping data structures * * @dev: the device structure */ @@ -907,7 +907,7 @@ int mei_hbm_cl_disconnect_req(struct mei_device *dev, struct mei_cl *cl) } /** - * mei_hbm_cl_disconnect_rsp - sends disconnect respose to the FW + * mei_hbm_cl_disconnect_rsp - sends disconnect response to the FW * * @dev: the device structure * @cl: a client to disconnect from diff --git a/drivers/misc/mei/interrupt.c b/drivers/misc/mei/interrupt.c index 0a0e984e5673..5a050f50f33e 100644 --- a/drivers/misc/mei/interrupt.c +++ b/drivers/misc/mei/interrupt.c @@ -72,7 +72,7 @@ static void mei_irq_discard_msg(struct mei_device *dev, struct mei_msg_hdr *hdr, discard_len = 0; } /* - * no need to check for size as it is guarantied + * no need to check for size as it is guaranteed * that length fits into rd_msg_buf */ mei_read_slots(dev, dev->rd_msg_buf, discard_len); diff --git a/drivers/misc/mei/mei_dev.h b/drivers/misc/mei/mei_dev.h index cdf8a2edf0b3..fca0094a2310 100644 --- a/drivers/misc/mei/mei_dev.h +++ b/drivers/misc/mei/mei_dev.h @@ -70,9 +70,9 @@ enum mei_dev_state { /** * enum mei_dev_pxp_mode - MEI PXP mode state * - * @MEI_DEV_PXP_DEFAULT: PCH based device, no initailization required + * @MEI_DEV_PXP_DEFAULT: PCH based device, no initialization required * @MEI_DEV_PXP_INIT: device requires initialization, send setup message to firmware - * @MEI_DEV_PXP_SETUP: device is in setup stage, waiting for firmware repsonse + * @MEI_DEV_PXP_SETUP: device is in setup stage, waiting for firmware response * @MEI_DEV_PXP_READY: device initialized */ enum mei_dev_pxp_mode { diff --git a/include/linux/mei_cl_bus.h b/include/linux/mei_cl_bus.h index b77cefd4f0c0..b38a56a13f39 100644 --- a/include/linux/mei_cl_bus.h +++ b/include/linux/mei_cl_bus.h @@ -31,11 +31,11 @@ typedef void (*mei_cldev_cb_t)(struct mei_cl_device *cldev); * @rx_work: async work to execute Rx event callback * @rx_cb: Drivers register this callback to get asynchronous ME * Rx buffer pending notifications. - * @notif_work: async work to execute FW notif event callback + * @notif_work: async work to execute FW notify event callback * @notif_cb: Drivers register this callback to get asynchronous ME * FW notification pending notifications. * - * @do_match: wheather device can be matched with a driver + * @do_match: whether the device can be matched with a driver * @is_added: device is already scanned * @priv_data: client private data */ From 5d33dc7df2ba14e963c094f0d0ab7a20ad4a5310 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Wed, 11 Oct 2023 19:48:39 -0700 Subject: [PATCH 282/326] misc: mei: hw.h: fix kernel-doc warnings Fix kernel-doc warnings in hw.h: hw.h:809: warning: missing initial short description on line: * struct hbm_client_dma_unmap_request hw.h:812: warning: contents before sections hw.h:825: warning: missing initial short description on line: * struct hbm_client_dma_response hw.h:828: warning: contents before sections Signed-off-by: Randy Dunlap Cc: Tomas Winkler Cc: Arnd Bergmann Cc: Greg Kroah-Hartman Link: https://lore.kernel.org/r/20231012024845.29169-2-rdunlap@infradead.org Signed-off-by: Greg Kroah-Hartman --- drivers/misc/mei/hw.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/misc/mei/hw.h b/drivers/misc/mei/hw.h index 3ad3080519c4..eb800a07a84b 100644 --- a/drivers/misc/mei/hw.h +++ b/drivers/misc/mei/hw.h @@ -806,8 +806,8 @@ struct hbm_client_dma_map_request { } __packed; /** - * struct hbm_client_dma_unmap_request - * client dma unmap request from the host to the firmware + * struct hbm_client_dma_unmap_request - client dma unmap request + * from the host to the firmware * * @hbm_cmd: bus message command header * @status: unmap status @@ -822,8 +822,8 @@ struct hbm_client_dma_unmap_request { } __packed; /** - * struct hbm_client_dma_response - * client dma unmap response from the firmware to the host + * struct hbm_client_dma_response - client dma unmap response + * from the firmware to the host * * @hbm_cmd: bus message command header * @status: command status From daa0c28d3bdeeca0be3d617feac379c4a979a5f7 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Wed, 11 Oct 2023 19:48:40 -0700 Subject: [PATCH 283/326] misc: mei: client.c: fix kernel-doc warnings Fix kernel-doc warnings in client.c: client.c:53: warning: contents before sections client.c:68: warning: contents before sections client.c:334: warning: contents before sections client.c:349: warning: contents before sections client.c:364: warning: contents before sections Signed-off-by: Randy Dunlap Cc: Tomas Winkler Cc: Arnd Bergmann Cc: Greg Kroah-Hartman Link: https://lore.kernel.org/r/20231012024845.29169-3-rdunlap@infradead.org Signed-off-by: Greg Kroah-Hartman --- drivers/misc/mei/client.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/drivers/misc/mei/client.c b/drivers/misc/mei/client.c index 5c19097266fe..9c8fc87938a7 100644 --- a/drivers/misc/mei/client.c +++ b/drivers/misc/mei/client.c @@ -48,9 +48,9 @@ struct mei_me_client *mei_me_cl_get(struct mei_me_client *me_cl) /** * mei_me_cl_release - free me client * - * Locking: called under "dev->device_lock" lock - * * @ref: me_client refcount + * + * Locking: called under "dev->device_lock" lock */ static void mei_me_cl_release(struct kref *ref) { @@ -63,9 +63,9 @@ static void mei_me_cl_release(struct kref *ref) /** * mei_me_cl_put - decrease me client refcount and free client if necessary * - * Locking: called under "dev->device_lock" lock - * * @me_cl: me client + * + * Locking: called under "dev->device_lock" lock */ void mei_me_cl_put(struct mei_me_client *me_cl) { @@ -329,10 +329,10 @@ void mei_io_cb_free(struct mei_cl_cb *cb) /** * mei_tx_cb_enqueue - queue tx callback * - * Locking: called under "dev->device_lock" lock - * * @cb: mei callback struct * @head: an instance of list to queue on + * + * Locking: called under "dev->device_lock" lock */ static inline void mei_tx_cb_enqueue(struct mei_cl_cb *cb, struct list_head *head) @@ -344,9 +344,9 @@ static inline void mei_tx_cb_enqueue(struct mei_cl_cb *cb, /** * mei_tx_cb_dequeue - dequeue tx callback * - * Locking: called under "dev->device_lock" lock - * * @cb: mei callback struct to dequeue and free + * + * Locking: called under "dev->device_lock" lock */ static inline void mei_tx_cb_dequeue(struct mei_cl_cb *cb) { @@ -359,10 +359,10 @@ static inline void mei_tx_cb_dequeue(struct mei_cl_cb *cb) /** * mei_cl_set_read_by_fp - set pending_read flag to vtag struct for given fp * - * Locking: called under "dev->device_lock" lock - * * @cl: mei client * @fp: pointer to file structure + * + * Locking: called under "dev->device_lock" lock */ static void mei_cl_set_read_by_fp(const struct mei_cl *cl, const struct file *fp) From 4efa1e2a05d6b4340c4ca39ad0664f0e160e5d8d Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Wed, 11 Oct 2023 19:48:41 -0700 Subject: [PATCH 284/326] misc: mei: dma-ring.c: fix kernel-doc warnings Fix kernel-doc warnings in dma-ring.c: dma-ring.c:130: warning: No description found for return value of 'mei_dma_copy_from' dma-ring.c:150: warning: No description found for return value of 'mei_dma_copy_to' Signed-off-by: Randy Dunlap Cc: Tomas Winkler Cc: Arnd Bergmann Cc: Greg Kroah-Hartman Link: https://lore.kernel.org/r/20231012024845.29169-4-rdunlap@infradead.org Signed-off-by: Greg Kroah-Hartman --- drivers/misc/mei/dma-ring.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/misc/mei/dma-ring.c b/drivers/misc/mei/dma-ring.c index e5d800e68cb1..651e77ef82bd 100644 --- a/drivers/misc/mei/dma-ring.c +++ b/drivers/misc/mei/dma-ring.c @@ -124,6 +124,8 @@ void mei_dma_ring_reset(struct mei_device *dev) * @buf: data buffer * @offset: offset in slots. * @n: number of slots to copy. + * + * Return: number of bytes copied */ static size_t mei_dma_copy_from(struct mei_device *dev, unsigned char *buf, u32 offset, u32 n) @@ -144,6 +146,8 @@ static size_t mei_dma_copy_from(struct mei_device *dev, unsigned char *buf, * @buf: data buffer * @offset: offset in slots. * @n: number of slots to copy. + * + * Return: number of bytes copied */ static size_t mei_dma_copy_to(struct mei_device *dev, unsigned char *buf, u32 offset, u32 n) From fbe3599ee65de93cac243862df777775e23dbd83 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Wed, 11 Oct 2023 19:48:42 -0700 Subject: [PATCH 285/326] misc: mei: hbm.c: fix kernel-doc warnings Fix kernel-doc warnings in hbm.c: hbm.c:98: warning: No description found for return value of 'mei_hbm_write_message' Signed-off-by: Randy Dunlap Cc: Tomas Winkler Cc: Arnd Bergmann Cc: Greg Kroah-Hartman Link: https://lore.kernel.org/r/20231012024845.29169-5-rdunlap@infradead.org Signed-off-by: Greg Kroah-Hartman --- drivers/misc/mei/hbm.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/misc/mei/hbm.c b/drivers/misc/mei/hbm.c index 15737655c896..026b1f686c16 100644 --- a/drivers/misc/mei/hbm.c +++ b/drivers/misc/mei/hbm.c @@ -91,6 +91,8 @@ static int mei_cl_conn_status_to_errno(enum mei_cl_connect_status status) * @dev: mei device * @hdr: mei header * @data: payload + * + * Return: >=0 on success, <0 on error */ static inline int mei_hbm_write_message(struct mei_device *dev, struct mei_msg_hdr *hdr, From de735e7fda11a27eb2eed81daf2a17548efb63f7 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Wed, 11 Oct 2023 19:48:43 -0700 Subject: [PATCH 286/326] misc: mei: hw-me.c: fix kernel-doc warnings Fix kernel-doc warnings in hw-me.c: hw-me.c:1391: warning: contents before sections hw-me.c:1475: warning: contents before sections hw-me.c:1501: warning: contents before sections hw-me.c:1525: warning: contents before sections Signed-off-by: Randy Dunlap Cc: Tomas Winkler Cc: Arnd Bergmann Cc: Greg Kroah-Hartman Link: https://lore.kernel.org/r/20231012024845.29169-6-rdunlap@infradead.org Signed-off-by: Greg Kroah-Hartman --- drivers/misc/mei/hw-me.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/drivers/misc/mei/hw-me.c b/drivers/misc/mei/hw-me.c index da4ef0b51954..e72c0d78932e 100644 --- a/drivers/misc/mei/hw-me.c +++ b/drivers/misc/mei/hw-me.c @@ -1379,6 +1379,8 @@ EXPORT_SYMBOL_GPL(mei_me_irq_thread_handler); /** * mei_me_polling_thread - interrupt register polling thread * + * @_dev: mei device + * * The thread monitors the interrupt source register and calls * mei_me_irq_thread_handler() to handle the firmware * input. @@ -1388,8 +1390,6 @@ EXPORT_SYMBOL_GPL(mei_me_irq_thread_handler); * time increases yet again by MEI_POLLING_TIMEOUT_ACTIVE * up to MEI_POLLING_TIMEOUT_IDLE. * - * @_dev: mei device - * * Return: always 0 */ int mei_me_polling_thread(void *_dev) @@ -1468,12 +1468,12 @@ static const struct mei_hw_ops mei_me_hw_ops = { /** * mei_me_fw_type_nm() - check for nm sku * + * @pdev: pci device + * * Read ME FW Status register to check for the Node Manager (NM) Firmware. * The NM FW is only signaled in PCI function 0. * __Note__: Deprecated by PCH8 and newer. * - * @pdev: pci device - * * Return: true in case of NM firmware */ static bool mei_me_fw_type_nm(const struct pci_dev *pdev) @@ -1494,12 +1494,12 @@ static bool mei_me_fw_type_nm(const struct pci_dev *pdev) /** * mei_me_fw_type_sps_4() - check for sps 4.0 sku * + * @pdev: pci device + * * Read ME FW Status register to check for SPS Firmware. * The SPS FW is only signaled in the PCI function 0. * __Note__: Deprecated by SPS 5.0 and newer. * - * @pdev: pci device - * * Return: true in case of SPS firmware */ static bool mei_me_fw_type_sps_4(const struct pci_dev *pdev) @@ -1519,11 +1519,11 @@ static bool mei_me_fw_type_sps_4(const struct pci_dev *pdev) /** * mei_me_fw_type_sps_ign() - check for sps or ign sku * + * @pdev: pci device + * * Read ME FW Status register to check for SPS or IGN Firmware. * The SPS/IGN FW is only signaled in pci function 0 * - * @pdev: pci device - * * Return: true in case of SPS/IGN firmware */ static bool mei_me_fw_type_sps_ign(const struct pci_dev *pdev) From 980dcc7e43bddedb755a41a375817ee5de80222f Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Wed, 11 Oct 2023 19:48:44 -0700 Subject: [PATCH 287/326] misc: mei: interrupt.c: fix kernel-doc warnings Fix kernel-doc warnings in interrupt.c: interrupt.c:631: warning: contents before sections Signed-off-by: Randy Dunlap Cc: Tomas Winkler Cc: Arnd Bergmann Cc: Greg Kroah-Hartman Link: https://lore.kernel.org/r/20231012024845.29169-7-rdunlap@infradead.org Signed-off-by: Greg Kroah-Hartman --- drivers/misc/mei/interrupt.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/misc/mei/interrupt.c b/drivers/misc/mei/interrupt.c index 5a050f50f33e..b09b79fedaba 100644 --- a/drivers/misc/mei/interrupt.c +++ b/drivers/misc/mei/interrupt.c @@ -626,9 +626,9 @@ static void mei_connect_timeout(struct mei_cl *cl) /** * mei_schedule_stall_timer - re-arm stall_timer work * - * Schedule stall timer - * * @dev: the device structure + * + * Schedule stall timer */ void mei_schedule_stall_timer(struct mei_device *dev) { From 3b54a111bb7e558e4a40e483ded7c123fe94382c Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Wed, 11 Oct 2023 19:48:45 -0700 Subject: [PATCH 288/326] misc: mei: main.c: fix kernel-doc warnings Fix kernel-doc warnings in main.c: main.c:465: warning: contents before sections main.c:590: warning: missing initial short description on line: * mei_ioctl_client_notify_request - Signed-off-by: Randy Dunlap Cc: Tomas Winkler Cc: Arnd Bergmann Cc: Greg Kroah-Hartman Link: https://lore.kernel.org/r/20231012024845.29169-8-rdunlap@infradead.org Signed-off-by: Greg Kroah-Hartman --- drivers/misc/mei/main.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/misc/mei/main.c b/drivers/misc/mei/main.c index bb4e9eabda97..79e6f3c1341f 100644 --- a/drivers/misc/mei/main.c +++ b/drivers/misc/mei/main.c @@ -460,11 +460,11 @@ end: /** * mei_vt_support_check - check if client support vtags * - * Locking: called under "dev->device_lock" lock - * * @dev: mei_device * @uuid: client UUID * + * Locking: called under "dev->device_lock" lock + * * Return: * 0 - supported * -ENOTTY - no such client @@ -587,8 +587,8 @@ static int mei_ioctl_connect_vtag(struct file *file, } /** - * mei_ioctl_client_notify_request - - * propagate event notification request to client + * mei_ioctl_client_notify_request - propagate event notification + * request to client * * @file: pointer to file structure * @request: 0 - disable, 1 - enable From 34a674e99acd6ec4b541cd4c630e126ba1a4c22f Mon Sep 17 00:00:00 2001 From: Vitaly Lubart Date: Sun, 15 Oct 2023 11:05:40 +0300 Subject: [PATCH 289/326] mei: me: emit error only if reset was unexpected GSC devices perform legal firmware initiated resets due to state transition that may appear as unexpected to the driver. Lower the log level for those devices to debug level and save the firmware status registers. When the device comes out of the reset it is possible to check whether the resets was due to a firmware error or an exception and only than produce a warning. Signed-off-by: Vitaly Lubart Signed-off-by: Tomas Winkler Link: https://lore.kernel.org/r/20231015080540.95922-1-tomas.winkler@intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/misc/mei/hw-me-regs.h | 3 ++ drivers/misc/mei/hw-me.c | 61 +++++++++++++++++++++++++++++++++-- drivers/misc/mei/init.c | 27 ++++++++++++++-- drivers/misc/mei/mei_dev.h | 47 +++++++++++++++++++++++++++ 4 files changed, 133 insertions(+), 5 deletions(-) diff --git a/drivers/misc/mei/hw-me-regs.h b/drivers/misc/mei/hw-me-regs.h index bdc65d50b945..961e5d53a27a 100644 --- a/drivers/misc/mei/hw-me-regs.h +++ b/drivers/misc/mei/hw-me-regs.h @@ -123,6 +123,9 @@ # define PCI_CFG_HFS_1_OPMODE_MSK 0xf0000 /* OP MODE Mask: SPS <= 4.0 */ # define PCI_CFG_HFS_1_OPMODE_SPS 0xf0000 /* SPS SKU : SPS <= 4.0 */ #define PCI_CFG_HFS_2 0x48 +# define PCI_CFG_HFS_2_PM_CMOFF_TO_CMX_ERROR 0x1000000 /* CMoff->CMx wake after an error */ +# define PCI_CFG_HFS_2_PM_CM_RESET_ERROR 0x5000000 /* CME reset due to exception */ +# define PCI_CFG_HFS_2_PM_EVENT_MASK 0xf000000 #define PCI_CFG_HFS_3 0x60 # define PCI_CFG_HFS_3_FW_SKU_MSK 0x00000070 # define PCI_CFG_HFS_3_FW_SKU_IGN 0x00000000 diff --git a/drivers/misc/mei/hw-me.c b/drivers/misc/mei/hw-me.c index e72c0d78932e..d11a0740b47c 100644 --- a/drivers/misc/mei/hw-me.c +++ b/drivers/misc/mei/hw-me.c @@ -443,11 +443,22 @@ static void mei_gsc_pxp_check(struct mei_device *dev) struct mei_me_hw *hw = to_me_hw(dev); u32 fwsts5 = 0; - if (dev->pxp_mode == MEI_DEV_PXP_DEFAULT) + if (!kind_is_gsc(dev) && !kind_is_gscfi(dev)) return; hw->read_fws(dev, PCI_CFG_HFS_5, &fwsts5); trace_mei_pci_cfg_read(dev->dev, "PCI_CFG_HFS_5", PCI_CFG_HFS_5, fwsts5); + + if ((fwsts5 & GSC_CFG_HFS_5_BOOT_TYPE_MSK) == GSC_CFG_HFS_5_BOOT_TYPE_PXP) { + if (dev->gsc_reset_to_pxp == MEI_DEV_RESET_TO_PXP_DEFAULT) + dev->gsc_reset_to_pxp = MEI_DEV_RESET_TO_PXP_PERFORMED; + } else { + dev->gsc_reset_to_pxp = MEI_DEV_RESET_TO_PXP_DEFAULT; + } + + if (dev->pxp_mode == MEI_DEV_PXP_DEFAULT) + return; + if ((fwsts5 & GSC_CFG_HFS_5_BOOT_TYPE_MSK) == GSC_CFG_HFS_5_BOOT_TYPE_PXP) { dev_dbg(dev->dev, "pxp mode is ready 0x%08x\n", fwsts5); dev->pxp_mode = MEI_DEV_PXP_READY; @@ -482,6 +493,43 @@ static int mei_me_hw_ready_wait(struct mei_device *dev) return 0; } +/** + * mei_me_check_fw_reset - check for the firmware reset error and exception conditions + * + * @dev: mei device + */ +static void mei_me_check_fw_reset(struct mei_device *dev) +{ + struct mei_fw_status fw_status; + char fw_sts_str[MEI_FW_STATUS_STR_SZ] = {0}; + int ret; + u32 fw_pm_event = 0; + + if (!dev->saved_fw_status_flag) + goto end; + + if (dev->gsc_reset_to_pxp == MEI_DEV_RESET_TO_PXP_PERFORMED) { + ret = mei_fw_status(dev, &fw_status); + if (!ret) { + fw_pm_event = fw_status.status[1] & PCI_CFG_HFS_2_PM_EVENT_MASK; + if (fw_pm_event != PCI_CFG_HFS_2_PM_CMOFF_TO_CMX_ERROR && + fw_pm_event != PCI_CFG_HFS_2_PM_CM_RESET_ERROR) + goto end; + } else { + dev_err(dev->dev, "failed to read firmware status: %d\n", ret); + } + } + + mei_fw_status2str(&dev->saved_fw_status, fw_sts_str, sizeof(fw_sts_str)); + dev_warn(dev->dev, "unexpected reset: fw_pm_event = 0x%x, dev_state = %u fw status = %s\n", + fw_pm_event, dev->saved_dev_state, fw_sts_str); + +end: + if (dev->gsc_reset_to_pxp == MEI_DEV_RESET_TO_PXP_PERFORMED) + dev->gsc_reset_to_pxp = MEI_DEV_RESET_TO_PXP_DONE; + dev->saved_fw_status_flag = false; +} + /** * mei_me_hw_start - hw start routine * @@ -492,6 +540,8 @@ static int mei_me_hw_start(struct mei_device *dev) { int ret = mei_me_hw_ready_wait(dev); + if (kind_is_gsc(dev) || kind_is_gscfi(dev)) + mei_me_check_fw_reset(dev); if (ret) return ret; dev_dbg(dev->dev, "hw is ready\n"); @@ -1300,8 +1350,13 @@ irqreturn_t mei_me_irq_thread_handler(int irq, void *dev_id) /* check if ME wants a reset */ if (!mei_hw_is_ready(dev) && dev->dev_state != MEI_DEV_RESETTING) { - dev_warn(dev->dev, "FW not ready: resetting: dev_state = %d pxp = %d\n", - dev->dev_state, dev->pxp_mode); + if (kind_is_gsc(dev) || kind_is_gscfi(dev)) { + dev_dbg(dev->dev, "FW not ready: resetting: dev_state = %d\n", + dev->dev_state); + } else { + dev_warn(dev->dev, "FW not ready: resetting: dev_state = %d\n", + dev->dev_state); + } if (dev->dev_state == MEI_DEV_POWERING_DOWN || dev->dev_state == MEI_DEV_POWER_DOWN) mei_cl_all_disconnect(dev); diff --git a/drivers/misc/mei/init.c b/drivers/misc/mei/init.c index c35e005b26be..8ef2b1df8ac7 100644 --- a/drivers/misc/mei/init.c +++ b/drivers/misc/mei/init.c @@ -89,6 +89,22 @@ void mei_cancel_work(struct mei_device *dev) } EXPORT_SYMBOL_GPL(mei_cancel_work); +static void mei_save_fw_status(struct mei_device *dev) +{ + struct mei_fw_status fw_status; + int ret; + + ret = mei_fw_status(dev, &fw_status); + if (ret) { + dev_err(dev->dev, "failed to read firmware status: %d\n", ret); + return; + } + + dev->saved_dev_state = dev->dev_state; + dev->saved_fw_status_flag = true; + memcpy(&dev->saved_fw_status, &fw_status, sizeof(fw_status)); +} + /** * mei_reset - resets host and fw. * @@ -109,8 +125,14 @@ int mei_reset(struct mei_device *dev) char fw_sts_str[MEI_FW_STATUS_STR_SZ]; mei_fw_status_str(dev, fw_sts_str, MEI_FW_STATUS_STR_SZ); - dev_warn(dev->dev, "unexpected reset: dev_state = %s fw status = %s\n", - mei_dev_state_str(state), fw_sts_str); + if (kind_is_gsc(dev) || kind_is_gscfi(dev)) { + dev_dbg(dev->dev, "unexpected reset: dev_state = %s fw status = %s\n", + mei_dev_state_str(state), fw_sts_str); + mei_save_fw_status(dev); + } else { + dev_warn(dev->dev, "unexpected reset: dev_state = %s fw status = %s\n", + mei_dev_state_str(state), fw_sts_str); + } } mei_clear_interrupts(dev); @@ -394,6 +416,7 @@ void mei_device_init(struct mei_device *dev, dev->open_handle_count = 0; dev->pxp_mode = MEI_DEV_PXP_DEFAULT; + dev->gsc_reset_to_pxp = MEI_DEV_RESET_TO_PXP_DEFAULT; /* * Reserving the first client ID diff --git a/drivers/misc/mei/mei_dev.h b/drivers/misc/mei/mei_dev.h index fca0094a2310..37d7fb15cad7 100644 --- a/drivers/misc/mei/mei_dev.h +++ b/drivers/misc/mei/mei_dev.h @@ -82,6 +82,19 @@ enum mei_dev_pxp_mode { MEI_DEV_PXP_READY = 3, }; +/** + * enum mei_dev_reset_to_pxp - reset to PXP mode performed + * + * @MEI_DEV_RESET_TO_PXP_DEFAULT: before reset + * @MEI_DEV_RESET_TO_PXP_PERFORMED: reset performed + * @MEI_DEV_RESET_TO_PXP_DONE: reset processed + */ +enum mei_dev_reset_to_pxp { + MEI_DEV_RESET_TO_PXP_DEFAULT = 0, + MEI_DEV_RESET_TO_PXP_PERFORMED = 1, + MEI_DEV_RESET_TO_PXP_DONE = 2, +}; + const char *mei_dev_state_str(int state); enum mei_file_transaction_states { @@ -534,6 +547,11 @@ struct mei_dev_timeouts { * * @dbgfs_dir : debugfs mei root directory * + * @saved_fw_status : saved firmware status + * @saved_dev_state : saved device state + * @saved_fw_status_flag : flag indicating that firmware status was saved + * @gsc_reset_to_pxp : state of reset to the PXP mode + * * @ops: : hw specific operations * @hw : hw specific data */ @@ -630,6 +648,11 @@ struct mei_device { struct dentry *dbgfs_dir; #endif /* CONFIG_DEBUG_FS */ + struct mei_fw_status saved_fw_status; + enum mei_dev_state saved_dev_state; + bool saved_fw_status_flag; + enum mei_dev_reset_to_pxp gsc_reset_to_pxp; + const struct mei_hw_ops *ops; char hw[] __aligned(sizeof(void *)); }; @@ -874,5 +897,29 @@ static inline ssize_t mei_fw_status_str(struct mei_device *dev, return ret; } +/** + * kind_is_gsc - checks whether the device is gsc + * + * @dev: the device structure + * + * Return: whether the device is gsc + */ +static inline bool kind_is_gsc(struct mei_device *dev) +{ + /* check kind for NULL because it may be not set, like at the fist call to hw_start */ + return dev->kind && (strcmp(dev->kind, "gsc") == 0); +} +/** + * kind_is_gscfi - checks whether the device is gscfi + * + * @dev: the device structure + * + * Return: whether the device is gscfi + */ +static inline bool kind_is_gscfi(struct mei_device *dev) +{ + /* check kind for NULL because it may be not set, like at the fist call to hw_start */ + return dev->kind && (strcmp(dev->kind, "gscfi") == 0); +} #endif From 35479e2e490992e5bc976d1394f1e1274903af15 Mon Sep 17 00:00:00 2001 From: Lukas Bulwahn Date: Thu, 12 Oct 2023 06:28:34 +0200 Subject: [PATCH 290/326] eeprom: remove doc and MAINTAINERS section after driver was removed Commit 0113a99b8a75 ("eeprom: Remove deprecated legacy eeprom driver") already removes the eeprom driver's code. Remove also the eeprom driver's documentation and MAINTAINERS section. Signed-off-by: Lukas Bulwahn Link: https://lore.kernel.org/r/20231012042834.6663-1-lukas.bulwahn@gmail.com Signed-off-by: Greg Kroah-Hartman --- Documentation/misc-devices/eeprom.rst | 107 -------------------------- Documentation/misc-devices/index.rst | 1 - MAINTAINERS | 6 -- 3 files changed, 114 deletions(-) delete mode 100644 Documentation/misc-devices/eeprom.rst diff --git a/Documentation/misc-devices/eeprom.rst b/Documentation/misc-devices/eeprom.rst deleted file mode 100644 index 008249675ccc..000000000000 --- a/Documentation/misc-devices/eeprom.rst +++ /dev/null @@ -1,107 +0,0 @@ -==================== -Kernel driver eeprom -==================== - -Supported chips: - - * Any EEPROM chip in the designated address range - - Prefix: 'eeprom' - - Addresses scanned: I2C 0x50 - 0x57 - - Datasheets: Publicly available from: - - Atmel (www.atmel.com), - Catalyst (www.catsemi.com), - Fairchild (www.fairchildsemi.com), - Microchip (www.microchip.com), - Philips (www.semiconductor.philips.com), - Rohm (www.rohm.com), - ST (www.st.com), - Xicor (www.xicor.com), - and others. - - ========= ============= ============================================ - Chip Size (bits) Address - ========= ============= ============================================ - 24C01 1K 0x50 (shadows at 0x51 - 0x57) - 24C01A 1K 0x50 - 0x57 (Typical device on DIMMs) - 24C02 2K 0x50 - 0x57 - 24C04 4K 0x50, 0x52, 0x54, 0x56 - (additional data at 0x51, 0x53, 0x55, 0x57) - 24C08 8K 0x50, 0x54 (additional data at 0x51, 0x52, - 0x53, 0x55, 0x56, 0x57) - 24C16 16K 0x50 (additional data at 0x51 - 0x57) - Sony 2K 0x57 - - Atmel 34C02B 2K 0x50 - 0x57, SW write protect at 0x30-37 - Catalyst 34FC02 2K 0x50 - 0x57, SW write protect at 0x30-37 - Catalyst 34RC02 2K 0x50 - 0x57, SW write protect at 0x30-37 - Fairchild 34W02 2K 0x50 - 0x57, SW write protect at 0x30-37 - Microchip 24AA52 2K 0x50 - 0x57, SW write protect at 0x30-37 - ST M34C02 2K 0x50 - 0x57, SW write protect at 0x30-37 - ========= ============= ============================================ - - -Authors: - - Frodo Looijaard , - - Philip Edelbrock , - - Jean Delvare , - - Greg Kroah-Hartman , - - IBM Corp. - -Description ------------ - -This is a simple EEPROM module meant to enable reading the first 256 bytes -of an EEPROM (on a SDRAM DIMM for example). However, it will access serial -EEPROMs on any I2C adapter. The supported devices are generically called -24Cxx, and are listed above; however the numbering for these -industry-standard devices may vary by manufacturer. - -This module was a programming exercise to get used to the new project -organization laid out by Frodo, but it should be at least completely -effective for decoding the contents of EEPROMs on DIMMs. - -DIMMS will typically contain a 24C01A or 24C02, or the 34C02 variants. -The other devices will not be found on a DIMM because they respond to more -than one address. - -DDC Monitors may contain any device. Often a 24C01, which responds to all 8 -addresses, is found. - -Recent Sony Vaio laptops have an EEPROM at 0x57. We couldn't get the -specification, so it is guess work and far from being complete. - -The Microchip 24AA52/24LCS52, ST M34C02, and others support an additional -software write protect register at 0x30 - 0x37 (0x20 less than the memory -location). The chip responds to "write quick" detection at this address but -does not respond to byte reads. If this register is present, the lower 128 -bytes of the memory array are not write protected. Any byte data write to -this address will write protect the memory array permanently, and the -device will no longer respond at the 0x30-37 address. The eeprom driver -does not support this register. - -Lacking functionality ---------------------- - -* Full support for larger devices (24C04, 24C08, 24C16). These are not - typically found on a PC. These devices will appear as separate devices at - multiple addresses. - -* Support for really large devices (24C32, 24C64, 24C128, 24C256, 24C512). - These devices require two-byte address fields and are not supported. - -* Enable Writing. Again, no technical reason why not, but making it easy - to change the contents of the EEPROMs (on DIMMs anyway) also makes it easy - to disable the DIMMs (potentially preventing the computer from booting) - until the values are restored somehow. - -Use ---- - -After inserting the module (and any other required SMBus/i2c modules), you -should have some EEPROM directories in ``/sys/bus/i2c/devices/*`` of names such -as "0-0050". Inside each of these is a series of files, the eeprom file -contains the binary data from EEPROM. diff --git a/Documentation/misc-devices/index.rst b/Documentation/misc-devices/index.rst index ecc40fbbcfb8..7de16797987a 100644 --- a/Documentation/misc-devices/index.rst +++ b/Documentation/misc-devices/index.rst @@ -17,7 +17,6 @@ fit into other categories. ad525x_dpot apds990x bh1770glc - eeprom c2port dw-xdata-pcie ibmvmc diff --git a/MAINTAINERS b/MAINTAINERS index 7a7bd8bd80e9..59831c69a275 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -11893,12 +11893,6 @@ F: drivers/leds/ F: include/dt-bindings/leds/ F: include/linux/leds.h -LEGACY EEPROM DRIVER -M: Jean Delvare -S: Maintained -F: Documentation/misc-devices/eeprom.rst -F: drivers/misc/eeprom/eeprom.c - LEGO MINDSTORMS EV3 R: David Lechner S: Maintained From 066eaa69b05b92efd25bc2fe9964d68122c6aa2b Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Fri, 6 Oct 2023 16:00:14 +0200 Subject: [PATCH 291/326] tee: make tee_class constant Now that the driver core allows for struct class to be in read-only memory, we should make all 'class' structures declared at build time placing them into read-only memory, instead of having to be dynamically allocated at runtime. Cc: Jens Wiklander Reviewed-by: Sumit Garg Link: https://lore.kernel.org/r/2023100613-lustiness-affiliate-7dcb@gregkh Signed-off-by: Greg Kroah-Hartman --- drivers/tee/tee_core.c | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/drivers/tee/tee_core.c b/drivers/tee/tee_core.c index 0eb342de0b00..5ddfd5d9ac7f 100644 --- a/drivers/tee/tee_core.c +++ b/drivers/tee/tee_core.c @@ -40,7 +40,10 @@ static const uuid_t tee_client_uuid_ns = UUID_INIT(0x58ac9ca0, 0x2086, 0x4683, static DECLARE_BITMAP(dev_mask, TEE_NUM_DEVICES); static DEFINE_SPINLOCK(driver_lock); -static struct class *tee_class; +static const struct class tee_class = { + .name = "tee", +}; + static dev_t tee_devt; struct tee_context *teedev_open(struct tee_device *teedev) @@ -919,7 +922,7 @@ struct tee_device *tee_device_alloc(const struct tee_desc *teedesc, teedesc->flags & TEE_DESC_PRIVILEGED ? "priv" : "", teedev->id - offs); - teedev->dev.class = tee_class; + teedev->dev.class = &tee_class; teedev->dev.release = tee_release_device; teedev->dev.parent = dev; @@ -1112,7 +1115,7 @@ tee_client_open_context(struct tee_context *start, dev = &start->teedev->dev; do { - dev = class_find_device(tee_class, dev, &match_data, match_dev); + dev = class_find_device(&tee_class, dev, &match_data, match_dev); if (!dev) { ctx = ERR_PTR(-ENOENT); break; @@ -1226,10 +1229,10 @@ static int __init tee_init(void) { int rc; - tee_class = class_create("tee"); - if (IS_ERR(tee_class)) { + rc = class_register(&tee_class); + if (rc) { pr_err("couldn't create class\n"); - return PTR_ERR(tee_class); + return rc; } rc = alloc_chrdev_region(&tee_devt, 0, TEE_NUM_DEVICES, "tee"); @@ -1249,8 +1252,7 @@ static int __init tee_init(void) out_unreg_chrdev: unregister_chrdev_region(tee_devt, TEE_NUM_DEVICES); out_unreg_class: - class_destroy(tee_class); - tee_class = NULL; + class_unregister(&tee_class); return rc; } @@ -1259,8 +1261,7 @@ static void __exit tee_exit(void) { bus_unregister(&tee_bus_type); unregister_chrdev_region(tee_devt, TEE_NUM_DEVICES); - class_destroy(tee_class); - tee_class = NULL; + class_unregister(&tee_class); } subsys_initcall(tee_init); From 67237183219351e53e0cf2486ad9ea00db99cd5a Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Fri, 6 Oct 2023 16:42:28 -0500 Subject: [PATCH 292/326] char: xilinx_hwicap: Modernize driver probe Rework Xilinx hwicap driver probe to use current best practices using devres APIs, device_get_match_data(), and typed firmware property accessors. There's no longer any non-DT probing, so CONFIG_OF ifdefs can be dropped. Signed-off-by: Rob Herring Link: https://lore.kernel.org/r/20231006214228.337064-1-robh@kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/char/xilinx_hwicap/xilinx_hwicap.c | 138 +++------------------ 1 file changed, 19 insertions(+), 119 deletions(-) diff --git a/drivers/char/xilinx_hwicap/xilinx_hwicap.c b/drivers/char/xilinx_hwicap/xilinx_hwicap.c index f60bb6151402..019cf6079cec 100644 --- a/drivers/char/xilinx_hwicap/xilinx_hwicap.c +++ b/drivers/char/xilinx_hwicap/xilinx_hwicap.c @@ -84,18 +84,13 @@ #include #include #include +#include #include +#include #include #include #include -#ifdef CONFIG_OF -/* For open firmware. */ -#include -#include -#include -#endif - #include "xilinx_hwicap.h" #include "buffer_icap.h" #include "fifo_icap.h" @@ -601,14 +596,14 @@ static const struct file_operations hwicap_fops = { .llseek = noop_llseek, }; -static int hwicap_setup(struct device *dev, int id, - const struct resource *regs_res, +static int hwicap_setup(struct platform_device *pdev, int id, const struct hwicap_driver_config *config, const struct config_registers *config_regs) { dev_t devt; struct hwicap_drvdata *drvdata = NULL; - int retval = 0; + struct device *dev = &pdev->dev; + int retval; dev_info(dev, "Xilinx icap port driver\n"); @@ -636,72 +631,39 @@ static int hwicap_setup(struct device *dev, int id, devt = MKDEV(XHWICAP_MAJOR, XHWICAP_MINOR + id); - drvdata = kzalloc(sizeof(struct hwicap_drvdata), GFP_KERNEL); + drvdata = devm_kzalloc(dev, sizeof(struct hwicap_drvdata), GFP_KERNEL); if (!drvdata) { retval = -ENOMEM; - goto failed0; + goto failed; } dev_set_drvdata(dev, (void *)drvdata); - if (!regs_res) { - dev_err(dev, "Couldn't get registers resource\n"); - retval = -EFAULT; - goto failed1; - } - - drvdata->mem_start = regs_res->start; - drvdata->mem_end = regs_res->end; - drvdata->mem_size = resource_size(regs_res); - - if (!request_mem_region(drvdata->mem_start, - drvdata->mem_size, DRIVER_NAME)) { - dev_err(dev, "Couldn't lock memory region at %Lx\n", - (unsigned long long) regs_res->start); - retval = -EBUSY; - goto failed1; + drvdata->base_address = devm_platform_ioremap_resource(pdev, 0); + if (!drvdata->base_address) { + retval = -ENODEV; + goto failed; } drvdata->devt = devt; drvdata->dev = dev; - drvdata->base_address = ioremap(drvdata->mem_start, drvdata->mem_size); - if (!drvdata->base_address) { - dev_err(dev, "ioremap() failed\n"); - retval = -ENOMEM; - goto failed2; - } - drvdata->config = config; drvdata->config_regs = config_regs; mutex_init(&drvdata->sem); drvdata->is_open = 0; - dev_info(dev, "ioremap %llx to %p with size %llx\n", - (unsigned long long) drvdata->mem_start, - drvdata->base_address, - (unsigned long long) drvdata->mem_size); - cdev_init(&drvdata->cdev, &hwicap_fops); drvdata->cdev.owner = THIS_MODULE; retval = cdev_add(&drvdata->cdev, devt, 1); if (retval) { dev_err(dev, "cdev_add() failed\n"); - goto failed3; + goto failed; } device_create(&icap_class, dev, devt, NULL, "%s%d", DRIVER_NAME, id); return 0; /* success */ - failed3: - iounmap(drvdata->base_address); - - failed2: - release_mem_region(regs_res->start, drvdata->mem_size); - - failed1: - kfree(drvdata); - - failed0: + failed: mutex_lock(&icap_sem); probed_devices[id] = 0; mutex_unlock(&icap_sem); @@ -723,75 +685,22 @@ static struct hwicap_driver_config fifo_icap_config = { .reset = fifo_icap_reset, }; -#ifdef CONFIG_OF -static int hwicap_of_probe(struct platform_device *op, - const struct hwicap_driver_config *config) -{ - struct resource res; - const unsigned int *id; - const char *family; - int rc; - const struct config_registers *regs; - - - rc = of_address_to_resource(op->dev.of_node, 0, &res); - if (rc) { - dev_err(&op->dev, "invalid address\n"); - return rc; - } - - id = of_get_property(op->dev.of_node, "port-number", NULL); - - /* It's most likely that we're using V4, if the family is not - * specified - */ - regs = &v4_config_registers; - family = of_get_property(op->dev.of_node, "xlnx,family", NULL); - - if (family) { - if (!strcmp(family, "virtex2p")) - regs = &v2_config_registers; - else if (!strcmp(family, "virtex4")) - regs = &v4_config_registers; - else if (!strcmp(family, "virtex5")) - regs = &v5_config_registers; - else if (!strcmp(family, "virtex6")) - regs = &v6_config_registers; - } - return hwicap_setup(&op->dev, id ? *id : -1, &res, config, - regs); -} -#else -static inline int hwicap_of_probe(struct platform_device *op, - const struct hwicap_driver_config *config) -{ - return -EINVAL; -} -#endif /* CONFIG_OF */ - -static const struct of_device_id hwicap_of_match[]; static int hwicap_drv_probe(struct platform_device *pdev) { - const struct of_device_id *match; - struct resource *res; const struct config_registers *regs; + const struct hwicap_driver_config *config; const char *family; + int id = -1; - match = of_match_device(hwicap_of_match, &pdev->dev); - if (match) - return hwicap_of_probe(pdev, match->data); + config = device_get_match_data(&pdev->dev); - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) - return -ENODEV; + of_property_read_u32(pdev->dev.of_node, "port-number", &id); /* It's most likely that we're using V4, if the family is not * specified */ regs = &v4_config_registers; - family = pdev->dev.platform_data; - - if (family) { + if (!of_property_read_string(pdev->dev.of_node, "xlnx,family", &family)) { if (!strcmp(family, "virtex2p")) regs = &v2_config_registers; else if (!strcmp(family, "virtex4")) @@ -801,9 +710,7 @@ static int hwicap_drv_probe(struct platform_device *pdev) else if (!strcmp(family, "virtex6")) regs = &v6_config_registers; } - - return hwicap_setup(&pdev->dev, pdev->id, res, - &buffer_icap_config, regs); + return hwicap_setup(pdev, id, config, regs); } static void hwicap_drv_remove(struct platform_device *pdev) @@ -815,16 +722,12 @@ static void hwicap_drv_remove(struct platform_device *pdev) device_destroy(&icap_class, drvdata->devt); cdev_del(&drvdata->cdev); - iounmap(drvdata->base_address); - release_mem_region(drvdata->mem_start, drvdata->mem_size); - kfree(drvdata); mutex_lock(&icap_sem); probed_devices[MINOR(dev->devt)-XHWICAP_MINOR] = 0; mutex_unlock(&icap_sem); } -#ifdef CONFIG_OF /* Match table for device tree binding */ static const struct of_device_id hwicap_of_match[] = { { .compatible = "xlnx,opb-hwicap-1.00.b", .data = &buffer_icap_config}, @@ -832,9 +735,6 @@ static const struct of_device_id hwicap_of_match[] = { {}, }; MODULE_DEVICE_TABLE(of, hwicap_of_match); -#else -#define hwicap_of_match NULL -#endif static struct platform_driver hwicap_platform_driver = { .probe = hwicap_drv_probe, From c1426d392aebc51da4944d950d89e483e43f6f14 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Wei=C3=9Fschuh?= Date: Wed, 11 Oct 2023 09:18:27 +0200 Subject: [PATCH 293/326] misc/pvpanic: deduplicate common code MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit pvpanic-mmio.c and pvpanic-pci.c share a lot of code. Refactor it into pvpanic.c where it doesn't have to be kept in sync manually and where the core logic can be understood more easily. No functional change. Signed-off-by: Thomas Weißschuh Link: https://lore.kernel.org/r/20231011-pvpanic-cleanup-v2-1-4b21d56f779f@weissschuh.net Signed-off-by: Greg Kroah-Hartman --- drivers/misc/pvpanic/pvpanic-mmio.c | 58 +--------------------- drivers/misc/pvpanic/pvpanic-pci.c | 58 +--------------------- drivers/misc/pvpanic/pvpanic.c | 76 ++++++++++++++++++++++++++++- drivers/misc/pvpanic/pvpanic.h | 10 +--- 4 files changed, 80 insertions(+), 122 deletions(-) diff --git a/drivers/misc/pvpanic/pvpanic-mmio.c b/drivers/misc/pvpanic/pvpanic-mmio.c index eb97167c03fb..9715798acce3 100644 --- a/drivers/misc/pvpanic/pvpanic-mmio.c +++ b/drivers/misc/pvpanic/pvpanic-mmio.c @@ -24,52 +24,9 @@ MODULE_AUTHOR("Hu Tao "); MODULE_DESCRIPTION("pvpanic-mmio device driver"); MODULE_LICENSE("GPL"); -static ssize_t capability_show(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct pvpanic_instance *pi = dev_get_drvdata(dev); - - return sysfs_emit(buf, "%x\n", pi->capability); -} -static DEVICE_ATTR_RO(capability); - -static ssize_t events_show(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct pvpanic_instance *pi = dev_get_drvdata(dev); - - return sysfs_emit(buf, "%x\n", pi->events); -} - -static ssize_t events_store(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) -{ - struct pvpanic_instance *pi = dev_get_drvdata(dev); - unsigned int tmp; - int err; - - err = kstrtouint(buf, 16, &tmp); - if (err) - return err; - - if ((tmp & pi->capability) != tmp) - return -EINVAL; - - pi->events = tmp; - - return count; -} -static DEVICE_ATTR_RW(events); - -static struct attribute *pvpanic_mmio_dev_attrs[] = { - &dev_attr_capability.attr, - &dev_attr_events.attr, - NULL -}; -ATTRIBUTE_GROUPS(pvpanic_mmio_dev); - static int pvpanic_mmio_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; - struct pvpanic_instance *pi; struct resource *res; void __iomem *base; @@ -92,18 +49,7 @@ static int pvpanic_mmio_probe(struct platform_device *pdev) return -EINVAL; } - pi = devm_kmalloc(dev, sizeof(*pi), GFP_KERNEL); - if (!pi) - return -ENOMEM; - - pi->base = base; - pi->capability = PVPANIC_PANICKED | PVPANIC_CRASH_LOADED; - - /* initialize capability by RDPT */ - pi->capability &= ioread8(base); - pi->events = pi->capability; - - return devm_pvpanic_probe(dev, pi); + return devm_pvpanic_probe(dev, base); } static const struct of_device_id pvpanic_mmio_match[] = { @@ -123,7 +69,7 @@ static struct platform_driver pvpanic_mmio_driver = { .name = "pvpanic-mmio", .of_match_table = pvpanic_mmio_match, .acpi_match_table = pvpanic_device_ids, - .dev_groups = pvpanic_mmio_dev_groups, + .dev_groups = pvpanic_dev_groups, }, .probe = pvpanic_mmio_probe, }; diff --git a/drivers/misc/pvpanic/pvpanic-pci.c b/drivers/misc/pvpanic/pvpanic-pci.c index 07eddb5ea30f..689af4c28c2a 100644 --- a/drivers/misc/pvpanic/pvpanic-pci.c +++ b/drivers/misc/pvpanic/pvpanic-pci.c @@ -22,51 +22,8 @@ MODULE_AUTHOR("Mihai Carabas "); MODULE_DESCRIPTION("pvpanic device driver"); MODULE_LICENSE("GPL"); -static ssize_t capability_show(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct pvpanic_instance *pi = dev_get_drvdata(dev); - - return sysfs_emit(buf, "%x\n", pi->capability); -} -static DEVICE_ATTR_RO(capability); - -static ssize_t events_show(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct pvpanic_instance *pi = dev_get_drvdata(dev); - - return sysfs_emit(buf, "%x\n", pi->events); -} - -static ssize_t events_store(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) -{ - struct pvpanic_instance *pi = dev_get_drvdata(dev); - unsigned int tmp; - int err; - - err = kstrtouint(buf, 16, &tmp); - if (err) - return err; - - if ((tmp & pi->capability) != tmp) - return -EINVAL; - - pi->events = tmp; - - return count; -} -static DEVICE_ATTR_RW(events); - -static struct attribute *pvpanic_pci_dev_attrs[] = { - &dev_attr_capability.attr, - &dev_attr_events.attr, - NULL -}; -ATTRIBUTE_GROUPS(pvpanic_pci_dev); - static int pvpanic_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) { - struct pvpanic_instance *pi; void __iomem *base; int ret; @@ -78,18 +35,7 @@ static int pvpanic_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e if (!base) return -ENOMEM; - pi = devm_kmalloc(&pdev->dev, sizeof(*pi), GFP_KERNEL); - if (!pi) - return -ENOMEM; - - pi->base = base; - pi->capability = PVPANIC_PANICKED | PVPANIC_CRASH_LOADED; - - /* initlize capability by RDPT */ - pi->capability &= ioread8(base); - pi->events = pi->capability; - - return devm_pvpanic_probe(&pdev->dev, pi); + return devm_pvpanic_probe(&pdev->dev, base); } static const struct pci_device_id pvpanic_pci_id_tbl[] = { @@ -103,7 +49,7 @@ static struct pci_driver pvpanic_pci_driver = { .id_table = pvpanic_pci_id_tbl, .probe = pvpanic_pci_probe, .driver = { - .dev_groups = pvpanic_pci_dev_groups, + .dev_groups = pvpanic_dev_groups, }, }; module_pci_driver(pvpanic_pci_driver); diff --git a/drivers/misc/pvpanic/pvpanic.c b/drivers/misc/pvpanic/pvpanic.c index 049a12006348..305b367e0ce3 100644 --- a/drivers/misc/pvpanic/pvpanic.c +++ b/drivers/misc/pvpanic/pvpanic.c @@ -7,6 +7,7 @@ * Copyright (C) 2021 Oracle. */ +#include #include #include #include @@ -26,6 +27,13 @@ MODULE_AUTHOR("Mihai Carabas "); MODULE_DESCRIPTION("pvpanic device driver"); MODULE_LICENSE("GPL"); +struct pvpanic_instance { + void __iomem *base; + unsigned int capability; + unsigned int events; + struct list_head list; +}; + static struct list_head pvpanic_list; static spinlock_t pvpanic_lock; @@ -81,11 +89,75 @@ static void pvpanic_remove(void *param) spin_unlock(&pvpanic_lock); } -int devm_pvpanic_probe(struct device *dev, struct pvpanic_instance *pi) +static ssize_t capability_show(struct device *dev, struct device_attribute *attr, char *buf) { - if (!pi || !pi->base) + struct pvpanic_instance *pi = dev_get_drvdata(dev); + + return sysfs_emit(buf, "%x\n", pi->capability); +} +static DEVICE_ATTR_RO(capability); + +static ssize_t events_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct pvpanic_instance *pi = dev_get_drvdata(dev); + + return sysfs_emit(buf, "%x\n", pi->events); +} + +static ssize_t events_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct pvpanic_instance *pi = dev_get_drvdata(dev); + unsigned int tmp; + int err; + + err = kstrtouint(buf, 16, &tmp); + if (err) + return err; + + if ((tmp & pi->capability) != tmp) return -EINVAL; + pi->events = tmp; + + return count; +} +static DEVICE_ATTR_RW(events); + +static struct attribute *pvpanic_dev_attrs[] = { + &dev_attr_capability.attr, + &dev_attr_events.attr, + NULL +}; + +static const struct attribute_group pvpanic_dev_group = { + .attrs = pvpanic_dev_attrs, +}; + +const struct attribute_group *pvpanic_dev_groups[] = { + &pvpanic_dev_group, + NULL +}; +EXPORT_SYMBOL_GPL(pvpanic_dev_groups); + +int devm_pvpanic_probe(struct device *dev, void __iomem *base) +{ + struct pvpanic_instance *pi; + + if (!base) + return -EINVAL; + + pi = devm_kmalloc(dev, sizeof(*pi), GFP_KERNEL); + if (!pi) + return -ENOMEM; + + pi->base = base; + pi->capability = PVPANIC_PANICKED | PVPANIC_CRASH_LOADED; + + /* initlize capability by RDPT */ + pi->capability &= ioread8(base); + pi->events = pi->capability; + spin_lock(&pvpanic_lock); list_add(&pi->list, &pvpanic_list); spin_unlock(&pvpanic_lock); diff --git a/drivers/misc/pvpanic/pvpanic.h b/drivers/misc/pvpanic/pvpanic.h index 493545951754..46ffb10438ad 100644 --- a/drivers/misc/pvpanic/pvpanic.h +++ b/drivers/misc/pvpanic/pvpanic.h @@ -8,13 +8,7 @@ #ifndef PVPANIC_H_ #define PVPANIC_H_ -struct pvpanic_instance { - void __iomem *base; - unsigned int capability; - unsigned int events; - struct list_head list; -}; - -int devm_pvpanic_probe(struct device *dev, struct pvpanic_instance *pi); +int devm_pvpanic_probe(struct device *dev, void __iomem *base); +extern const struct attribute_group *pvpanic_dev_groups[]; #endif /* PVPANIC_H_ */ From 8d8ae17eb0de1fcdff6e7ddee3b641a16eefe8f6 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 16 Oct 2023 16:31:33 +0300 Subject: [PATCH 294/326] parport: Use kasprintf() instead of fixed buffer formatting Improve readability and maintainability by replacing a hardcoded string allocation and formatting by the use of the kasprintf() helper. Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20231016133135.1203643-2-andriy.shevchenko@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/parport/procfs.c | 53 +++++++--------------------------------- drivers/parport/share.c | 15 +++++------- include/linux/parport.h | 2 -- 3 files changed, 15 insertions(+), 55 deletions(-) diff --git a/drivers/parport/procfs.c b/drivers/parport/procfs.c index 4e5b972c3e26..7aa99c65b934 100644 --- a/drivers/parport/procfs.c +++ b/drivers/parport/procfs.c @@ -32,13 +32,6 @@ #define PARPORT_MAX_TIMESLICE_VALUE ((unsigned long) HZ) #define PARPORT_MIN_SPINTIME_VALUE 1 #define PARPORT_MAX_SPINTIME_VALUE 1000 -/* - * PARPORT_BASE_* is the size of the known parts of the sysctl path - * in dev/partport/%s/devices/%s. "dev/parport/"(12), "/devices/"(9 - * and null char(1). - */ -#define PARPORT_BASE_PATH_SIZE 13 -#define PARPORT_BASE_DEVICES_PATH_SIZE 22 static int do_active_device(struct ctl_table *table, int write, void *result, size_t *lenp, loff_t *ppos) @@ -431,8 +424,7 @@ int parport_proc_register(struct parport *port) { struct parport_sysctl_table *t; char *tmp_dir_path; - size_t tmp_path_len, port_name_len; - int bytes_written, i, err = 0; + int i, err = 0; t = kmemdup(&parport_sysctl_template, sizeof(*t), GFP_KERNEL); if (t == NULL) @@ -446,35 +438,23 @@ int parport_proc_register(struct parport *port) t->vars[5 + i].extra2 = &port->probe_info[i]; } - port_name_len = strnlen(port->name, PARPORT_NAME_MAX_LEN); - /* - * Allocate a buffer for two paths: dev/parport/PORT and dev/parport/PORT/devices. - * We calculate for the second as that will give us enough for the first. - */ - tmp_path_len = PARPORT_BASE_DEVICES_PATH_SIZE + port_name_len; - tmp_dir_path = kzalloc(tmp_path_len, GFP_KERNEL); + tmp_dir_path = kasprintf(GFP_KERNEL, "dev/parport/%s/devices", port->name); if (!tmp_dir_path) { err = -ENOMEM; goto exit_free_t; } - bytes_written = snprintf(tmp_dir_path, tmp_path_len, - "dev/parport/%s/devices", port->name); - if (tmp_path_len <= bytes_written) { - err = -ENOENT; - goto exit_free_tmp_dir_path; - } t->devices_header = register_sysctl(tmp_dir_path, t->device_dir); if (t->devices_header == NULL) { err = -ENOENT; goto exit_free_tmp_dir_path; } - tmp_path_len = PARPORT_BASE_PATH_SIZE + port_name_len; - bytes_written = snprintf(tmp_dir_path, tmp_path_len, - "dev/parport/%s", port->name); - if (tmp_path_len <= bytes_written) { - err = -ENOENT; + kfree(tmp_dir_path); + + tmp_dir_path = kasprintf(GFP_KERNEL, "dev/parport/%s", port->name); + if (!tmp_dir_path) { + err = -ENOMEM; goto unregister_devices_h; } @@ -514,34 +494,22 @@ int parport_proc_unregister(struct parport *port) int parport_device_proc_register(struct pardevice *device) { - int bytes_written, err = 0; struct parport_device_sysctl_table *t; struct parport * port = device->port; - size_t port_name_len, device_name_len, tmp_dir_path_len; char *tmp_dir_path; + int err = 0; t = kmemdup(&parport_device_sysctl_template, sizeof(*t), GFP_KERNEL); if (t == NULL) return -ENOMEM; - port_name_len = strnlen(port->name, PARPORT_NAME_MAX_LEN); - device_name_len = strnlen(device->name, PATH_MAX); - /* Allocate a buffer for two paths: dev/parport/PORT/devices/DEVICE. */ - tmp_dir_path_len = PARPORT_BASE_DEVICES_PATH_SIZE + port_name_len + device_name_len; - tmp_dir_path = kzalloc(tmp_dir_path_len, GFP_KERNEL); + tmp_dir_path = kasprintf(GFP_KERNEL, "dev/parport/%s/devices/%s", port->name, device->name); if (!tmp_dir_path) { err = -ENOMEM; goto exit_free_t; } - bytes_written = snprintf(tmp_dir_path, tmp_dir_path_len, "dev/parport/%s/devices/%s", - port->name, device->name); - if (tmp_dir_path_len <= bytes_written) { - err = -ENOENT; - goto exit_free_path; - } - t->vars[0].data = &device->timeslice; t->sysctl_header = register_sysctl(tmp_dir_path, t->vars); @@ -554,9 +522,6 @@ int parport_device_proc_register(struct pardevice *device) kfree(tmp_dir_path); return 0; -exit_free_path: - kfree(tmp_dir_path); - exit_free_t: kfree(t); diff --git a/drivers/parport/share.c b/drivers/parport/share.c index 2d46b1d4fd69..8037bcd07bcf 100644 --- a/drivers/parport/share.c +++ b/drivers/parport/share.c @@ -438,7 +438,6 @@ struct parport *parport_register_port(unsigned long base, int irq, int dma, struct parport *tmp; int num; int device; - char *name; int ret; tmp = kzalloc(sizeof(struct parport), GFP_KERNEL); @@ -467,11 +466,6 @@ struct parport *parport_register_port(unsigned long base, int irq, int dma, atomic_set(&tmp->ref_count, 1); INIT_LIST_HEAD(&tmp->full_list); - name = kmalloc(PARPORT_NAME_MAX_LEN, GFP_KERNEL); - if (!name) { - kfree(tmp); - return NULL; - } /* Search for the lowest free parport number. */ spin_lock(&full_list_lock); @@ -487,11 +481,14 @@ struct parport *parport_register_port(unsigned long base, int irq, int dma, /* * Now that the portnum is known finish doing the Init. */ - sprintf(name, "parport%d", tmp->portnum = tmp->number); - tmp->name = name; + tmp->name = kasprintf(GFP_KERNEL, "parport%d", tmp->portnum); + if (!tmp->name) { + kfree(tmp); + return NULL; + } + dev_set_name(&tmp->bus_dev, tmp->name); tmp->bus_dev.bus = &parport_bus_type; tmp->bus_dev.release = free_port; - dev_set_name(&tmp->bus_dev, name); tmp->bus_dev.type = &parport_device_type; for (device = 0; device < 5; device++) diff --git a/include/linux/parport.h b/include/linux/parport.h index 999eddd619b7..fff39bc30629 100644 --- a/include/linux/parport.h +++ b/include/linux/parport.h @@ -180,8 +180,6 @@ struct ieee1284_info { struct semaphore irq; }; -#define PARPORT_NAME_MAX_LEN 15 - /* A parallel port */ struct parport { unsigned long base; /* base address */ From b8cb855d1b2ee6669e46c54a132024bd1dd0dcbb Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 16 Oct 2023 16:31:34 +0300 Subject: [PATCH 295/326] parport: Use list_for_each() helper Convert hard to read custom code to list_for_each(). No functional changes intended. Note, we may not use list_for_each_entry() as at the end of the list the iterator will point to an invalid entry and may not be dereferenced. Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20231016133135.1203643-3-andriy.shevchenko@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/parport/share.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/parport/share.c b/drivers/parport/share.c index 8037bcd07bcf..38780f6a9119 100644 --- a/drivers/parport/share.c +++ b/drivers/parport/share.c @@ -469,9 +469,11 @@ struct parport *parport_register_port(unsigned long base, int irq, int dma, /* Search for the lowest free parport number. */ spin_lock(&full_list_lock); - for (l = all_ports.next, num = 0; l != &all_ports; l = l->next, num++) { + num = 0; + list_for_each(l, &all_ports) { struct parport *p = list_entry(l, struct parport, full_list); - if (p->number != num) + + if (p->number != num++) break; } tmp->portnum = tmp->number = num; From f7572e93d5f6bc4f659d2a9b603574cd126482d8 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 16 Oct 2023 16:31:35 +0300 Subject: [PATCH 296/326] parport: Drop unneeded NULL or 0 assignments kzalloc() gives us a zeroed memory, no need to explicitly assing 0 or NULL or similar to the members of the data structure that has been allocated with the above mentioned API. Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20231016133135.1203643-4-andriy.shevchenko@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/parport/share.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/drivers/parport/share.c b/drivers/parport/share.c index 38780f6a9119..a9a9cb0477ea 100644 --- a/drivers/parport/share.c +++ b/drivers/parport/share.c @@ -449,13 +449,9 @@ struct parport *parport_register_port(unsigned long base, int irq, int dma, tmp->irq = irq; tmp->dma = dma; tmp->muxport = tmp->daisy = tmp->muxsel = -1; - tmp->modes = 0; INIT_LIST_HEAD(&tmp->list); - tmp->devices = tmp->cad = NULL; - tmp->flags = 0; tmp->ops = ops; tmp->physport = tmp; - memset(tmp->probe_info, 0, 5 * sizeof(struct parport_device_info)); rwlock_init(&tmp->cad_lock); spin_lock_init(&tmp->waitlist_lock); spin_lock_init(&tmp->pardevice_lock); From c8fd5a37340f9dfb02f7c340d7b602bd2f7ec449 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Sun, 15 Oct 2023 15:59:56 +0200 Subject: [PATCH 297/326] interconnect: qcom: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new() which already returns void. Eventually after all drivers are converted, .remove_new() will be renamed to .remove(). Several drivers use qcom_icc_rpmh_remove() as remove callback which returns zero unconditionally. Make it return void and use .remove_new in the drivers. There is no change in behaviour. Signed-off-by: Uwe Kleine-König Reviewed-by: Konrad Dybcio Link: https://lore.kernel.org/r/20231015135955.1537751-2-u.kleine-koenig@pengutronix.de Signed-off-by: Georgi Djakov --- drivers/interconnect/qcom/icc-rpmh.c | 4 +--- drivers/interconnect/qcom/icc-rpmh.h | 2 +- drivers/interconnect/qcom/qdu1000.c | 2 +- drivers/interconnect/qcom/sa8775p.c | 2 +- drivers/interconnect/qcom/sc7180.c | 2 +- drivers/interconnect/qcom/sc7280.c | 2 +- drivers/interconnect/qcom/sc8180x.c | 2 +- drivers/interconnect/qcom/sc8280xp.c | 2 +- drivers/interconnect/qcom/sdm670.c | 2 +- drivers/interconnect/qcom/sdm845.c | 2 +- drivers/interconnect/qcom/sdx55.c | 2 +- drivers/interconnect/qcom/sdx65.c | 2 +- drivers/interconnect/qcom/sdx75.c | 2 +- drivers/interconnect/qcom/sm6350.c | 2 +- drivers/interconnect/qcom/sm8150.c | 2 +- drivers/interconnect/qcom/sm8250.c | 2 +- drivers/interconnect/qcom/sm8350.c | 2 +- drivers/interconnect/qcom/sm8450.c | 2 +- drivers/interconnect/qcom/sm8550.c | 2 +- 19 files changed, 19 insertions(+), 21 deletions(-) diff --git a/drivers/interconnect/qcom/icc-rpmh.c b/drivers/interconnect/qcom/icc-rpmh.c index b9f27ce3b607..c1aa265c1f4e 100644 --- a/drivers/interconnect/qcom/icc-rpmh.c +++ b/drivers/interconnect/qcom/icc-rpmh.c @@ -253,14 +253,12 @@ err_remove_nodes: } EXPORT_SYMBOL_GPL(qcom_icc_rpmh_probe); -int qcom_icc_rpmh_remove(struct platform_device *pdev) +void qcom_icc_rpmh_remove(struct platform_device *pdev) { struct qcom_icc_provider *qp = platform_get_drvdata(pdev); icc_provider_deregister(&qp->provider); icc_nodes_remove(&qp->provider); - - return 0; } EXPORT_SYMBOL_GPL(qcom_icc_rpmh_remove); diff --git a/drivers/interconnect/qcom/icc-rpmh.h b/drivers/interconnect/qcom/icc-rpmh.h index 5f0af8b1fc43..2de29460e808 100644 --- a/drivers/interconnect/qcom/icc-rpmh.h +++ b/drivers/interconnect/qcom/icc-rpmh.h @@ -126,6 +126,6 @@ int qcom_icc_set(struct icc_node *src, struct icc_node *dst); int qcom_icc_bcm_init(struct qcom_icc_bcm *bcm, struct device *dev); void qcom_icc_pre_aggregate(struct icc_node *node); int qcom_icc_rpmh_probe(struct platform_device *pdev); -int qcom_icc_rpmh_remove(struct platform_device *pdev); +void qcom_icc_rpmh_remove(struct platform_device *pdev); #endif diff --git a/drivers/interconnect/qcom/qdu1000.c b/drivers/interconnect/qcom/qdu1000.c index bf800dd7d4ba..4a5089002364 100644 --- a/drivers/interconnect/qcom/qdu1000.c +++ b/drivers/interconnect/qcom/qdu1000.c @@ -1045,7 +1045,7 @@ MODULE_DEVICE_TABLE(of, qnoc_of_match); static struct platform_driver qnoc_driver = { .probe = qnoc_probe, - .remove = qcom_icc_rpmh_remove, + .remove_new = qcom_icc_rpmh_remove, .driver = { .name = "qnoc-qdu1000", .of_match_table = qnoc_of_match, diff --git a/drivers/interconnect/qcom/sa8775p.c b/drivers/interconnect/qcom/sa8775p.c index ef1b5e326089..dd6281db08ad 100644 --- a/drivers/interconnect/qcom/sa8775p.c +++ b/drivers/interconnect/qcom/sa8775p.c @@ -2519,7 +2519,7 @@ MODULE_DEVICE_TABLE(of, qnoc_of_match); static struct platform_driver qnoc_driver = { .probe = qcom_icc_rpmh_probe, - .remove = qcom_icc_rpmh_remove, + .remove_new = qcom_icc_rpmh_remove, .driver = { .name = "qnoc-sa8775p", .of_match_table = qnoc_of_match, diff --git a/drivers/interconnect/qcom/sc7180.c b/drivers/interconnect/qcom/sc7180.c index d94ab9b39f3d..3f1a0f358e0d 100644 --- a/drivers/interconnect/qcom/sc7180.c +++ b/drivers/interconnect/qcom/sc7180.c @@ -1806,7 +1806,7 @@ MODULE_DEVICE_TABLE(of, qnoc_of_match); static struct platform_driver qnoc_driver = { .probe = qcom_icc_rpmh_probe, - .remove = qcom_icc_rpmh_remove, + .remove_new = qcom_icc_rpmh_remove, .driver = { .name = "qnoc-sc7180", .of_match_table = qnoc_of_match, diff --git a/drivers/interconnect/qcom/sc7280.c b/drivers/interconnect/qcom/sc7280.c index 6592839b4d94..6292af8242d4 100644 --- a/drivers/interconnect/qcom/sc7280.c +++ b/drivers/interconnect/qcom/sc7280.c @@ -1834,7 +1834,7 @@ MODULE_DEVICE_TABLE(of, qnoc_of_match); static struct platform_driver qnoc_driver = { .probe = qcom_icc_rpmh_probe, - .remove = qcom_icc_rpmh_remove, + .remove_new = qcom_icc_rpmh_remove, .driver = { .name = "qnoc-sc7280", .of_match_table = qnoc_of_match, diff --git a/drivers/interconnect/qcom/sc8180x.c b/drivers/interconnect/qcom/sc8180x.c index 0fb4898dabcf..6eaf4e1e4384 100644 --- a/drivers/interconnect/qcom/sc8180x.c +++ b/drivers/interconnect/qcom/sc8180x.c @@ -1887,7 +1887,7 @@ MODULE_DEVICE_TABLE(of, qnoc_of_match); static struct platform_driver qnoc_driver = { .probe = qcom_icc_rpmh_probe, - .remove = qcom_icc_rpmh_remove, + .remove_new = qcom_icc_rpmh_remove, .driver = { .name = "qnoc-sc8180x", .of_match_table = qnoc_of_match, diff --git a/drivers/interconnect/qcom/sc8280xp.c b/drivers/interconnect/qcom/sc8280xp.c index b82c5493cbb5..633b5740b9a3 100644 --- a/drivers/interconnect/qcom/sc8280xp.c +++ b/drivers/interconnect/qcom/sc8280xp.c @@ -2390,7 +2390,7 @@ MODULE_DEVICE_TABLE(of, qnoc_of_match); static struct platform_driver qnoc_driver = { .probe = qcom_icc_rpmh_probe, - .remove = qcom_icc_rpmh_remove, + .remove_new = qcom_icc_rpmh_remove, .driver = { .name = "qnoc-sc8280xp", .of_match_table = qnoc_of_match, diff --git a/drivers/interconnect/qcom/sdm670.c b/drivers/interconnect/qcom/sdm670.c index 540a2108b77c..900ee47b2b87 100644 --- a/drivers/interconnect/qcom/sdm670.c +++ b/drivers/interconnect/qcom/sdm670.c @@ -1532,7 +1532,7 @@ MODULE_DEVICE_TABLE(of, qnoc_of_match); static struct platform_driver qnoc_driver = { .probe = qcom_icc_rpmh_probe, - .remove = qcom_icc_rpmh_remove, + .remove_new = qcom_icc_rpmh_remove, .driver = { .name = "qnoc-sdm670", .of_match_table = qnoc_of_match, diff --git a/drivers/interconnect/qcom/sdm845.c b/drivers/interconnect/qcom/sdm845.c index b9243c0aa626..5176addf347b 100644 --- a/drivers/interconnect/qcom/sdm845.c +++ b/drivers/interconnect/qcom/sdm845.c @@ -1801,7 +1801,7 @@ MODULE_DEVICE_TABLE(of, qnoc_of_match); static struct platform_driver qnoc_driver = { .probe = qcom_icc_rpmh_probe, - .remove = qcom_icc_rpmh_remove, + .remove_new = qcom_icc_rpmh_remove, .driver = { .name = "qnoc-sdm845", .of_match_table = qnoc_of_match, diff --git a/drivers/interconnect/qcom/sdx55.c b/drivers/interconnect/qcom/sdx55.c index 4117db046fa0..e97f28b8d2b2 100644 --- a/drivers/interconnect/qcom/sdx55.c +++ b/drivers/interconnect/qcom/sdx55.c @@ -913,7 +913,7 @@ MODULE_DEVICE_TABLE(of, qnoc_of_match); static struct platform_driver qnoc_driver = { .probe = qcom_icc_rpmh_probe, - .remove = qcom_icc_rpmh_remove, + .remove_new = qcom_icc_rpmh_remove, .driver = { .name = "qnoc-sdx55", .of_match_table = qnoc_of_match, diff --git a/drivers/interconnect/qcom/sdx65.c b/drivers/interconnect/qcom/sdx65.c index d3a6c6c148e5..2f3f5479d8a5 100644 --- a/drivers/interconnect/qcom/sdx65.c +++ b/drivers/interconnect/qcom/sdx65.c @@ -897,7 +897,7 @@ MODULE_DEVICE_TABLE(of, qnoc_of_match); static struct platform_driver qnoc_driver = { .probe = qcom_icc_rpmh_probe, - .remove = qcom_icc_rpmh_remove, + .remove_new = qcom_icc_rpmh_remove, .driver = { .name = "qnoc-sdx65", .of_match_table = qnoc_of_match, diff --git a/drivers/interconnect/qcom/sdx75.c b/drivers/interconnect/qcom/sdx75.c index 7ef1f17f3292..7f422c27488d 100644 --- a/drivers/interconnect/qcom/sdx75.c +++ b/drivers/interconnect/qcom/sdx75.c @@ -1083,7 +1083,7 @@ MODULE_DEVICE_TABLE(of, qnoc_of_match); static struct platform_driver qnoc_driver = { .probe = qcom_icc_rpmh_probe, - .remove = qcom_icc_rpmh_remove, + .remove_new = qcom_icc_rpmh_remove, .driver = { .name = "qnoc-sdx75", .of_match_table = qnoc_of_match, diff --git a/drivers/interconnect/qcom/sm6350.c b/drivers/interconnect/qcom/sm6350.c index 49aed492e9b8..f1907cb9891f 100644 --- a/drivers/interconnect/qcom/sm6350.c +++ b/drivers/interconnect/qcom/sm6350.c @@ -1701,7 +1701,7 @@ MODULE_DEVICE_TABLE(of, qnoc_of_match); static struct platform_driver qnoc_driver = { .probe = qcom_icc_rpmh_probe, - .remove = qcom_icc_rpmh_remove, + .remove_new = qcom_icc_rpmh_remove, .driver = { .name = "qnoc-sm6350", .of_match_table = qnoc_of_match, diff --git a/drivers/interconnect/qcom/sm8150.c b/drivers/interconnect/qcom/sm8150.c index c7c9cf7f746b..ce2ebbd404f6 100644 --- a/drivers/interconnect/qcom/sm8150.c +++ b/drivers/interconnect/qcom/sm8150.c @@ -1863,7 +1863,7 @@ MODULE_DEVICE_TABLE(of, qnoc_of_match); static struct platform_driver qnoc_driver = { .probe = qcom_icc_rpmh_probe, - .remove = qcom_icc_rpmh_remove, + .remove_new = qcom_icc_rpmh_remove, .driver = { .name = "qnoc-sm8150", .of_match_table = qnoc_of_match, diff --git a/drivers/interconnect/qcom/sm8250.c b/drivers/interconnect/qcom/sm8250.c index d4a4ecef11f0..4db468f3ec39 100644 --- a/drivers/interconnect/qcom/sm8250.c +++ b/drivers/interconnect/qcom/sm8250.c @@ -1990,7 +1990,7 @@ MODULE_DEVICE_TABLE(of, qnoc_of_match); static struct platform_driver qnoc_driver = { .probe = qcom_icc_rpmh_probe, - .remove = qcom_icc_rpmh_remove, + .remove_new = qcom_icc_rpmh_remove, .driver = { .name = "qnoc-sm8250", .of_match_table = qnoc_of_match, diff --git a/drivers/interconnect/qcom/sm8350.c b/drivers/interconnect/qcom/sm8350.c index bdf75839e6d1..046e20046054 100644 --- a/drivers/interconnect/qcom/sm8350.c +++ b/drivers/interconnect/qcom/sm8350.c @@ -1960,7 +1960,7 @@ MODULE_DEVICE_TABLE(of, qnoc_of_match); static struct platform_driver qnoc_driver = { .probe = qcom_icc_rpmh_probe, - .remove = qcom_icc_rpmh_remove, + .remove_new = qcom_icc_rpmh_remove, .driver = { .name = "qnoc-sm8350", .of_match_table = qnoc_of_match, diff --git a/drivers/interconnect/qcom/sm8450.c b/drivers/interconnect/qcom/sm8450.c index eb7e17df32ba..b3cd0087377c 100644 --- a/drivers/interconnect/qcom/sm8450.c +++ b/drivers/interconnect/qcom/sm8450.c @@ -1884,7 +1884,7 @@ MODULE_DEVICE_TABLE(of, qnoc_of_match); static struct platform_driver qnoc_driver = { .probe = qcom_icc_rpmh_probe, - .remove = qcom_icc_rpmh_remove, + .remove_new = qcom_icc_rpmh_remove, .driver = { .name = "qnoc-sm8450", .of_match_table = qnoc_of_match, diff --git a/drivers/interconnect/qcom/sm8550.c b/drivers/interconnect/qcom/sm8550.c index a10c8b6549ee..629faa4c9aae 100644 --- a/drivers/interconnect/qcom/sm8550.c +++ b/drivers/interconnect/qcom/sm8550.c @@ -2219,7 +2219,7 @@ MODULE_DEVICE_TABLE(of, qnoc_of_match); static struct platform_driver qnoc_driver = { .probe = qcom_icc_rpmh_probe, - .remove = qcom_icc_rpmh_remove, + .remove_new = qcom_icc_rpmh_remove, .driver = { .name = "qnoc-sm8550", .of_match_table = qnoc_of_match, From 16724d6ea40a2c9315f5a0d81005dfa4d7a6da24 Mon Sep 17 00:00:00 2001 From: Luca Weiss Date: Fri, 20 Oct 2023 11:55:40 +0100 Subject: [PATCH 298/326] nvmem: qfprom: Mark core clk as optional On some platforms like sc7280 on non-ChromeOS devices the core clock cannot be touched by Linux so we cannot provide it. Mark it as optional as accessing qfprom for reading works without it but we still prohibit writing if we cannot provide the clock. Signed-off-by: Luca Weiss Reviewed-by: Douglas Anderson Signed-off-by: Srinivas Kandagatla Link: https://lore.kernel.org/r/20231020105545.216052-2-srinivas.kandagatla@linaro.org Signed-off-by: Greg Kroah-Hartman --- drivers/nvmem/qfprom.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/nvmem/qfprom.c b/drivers/nvmem/qfprom.c index 14814cba2dd6..525be03b7bba 100644 --- a/drivers/nvmem/qfprom.c +++ b/drivers/nvmem/qfprom.c @@ -423,12 +423,12 @@ static int qfprom_probe(struct platform_device *pdev) if (IS_ERR(priv->vcc)) return PTR_ERR(priv->vcc); - priv->secclk = devm_clk_get(dev, "core"); + priv->secclk = devm_clk_get_optional(dev, "core"); if (IS_ERR(priv->secclk)) return dev_err_probe(dev, PTR_ERR(priv->secclk), "Error getting clock\n"); - /* Only enable writing if we have SoC data. */ - if (priv->soc_data) + /* Only enable writing if we have SoC data and a valid clock */ + if (priv->soc_data && priv->secclk) econfig.reg_write = qfprom_reg_write; } From 2cc3b37f5b6df8189d55d0e812d9658ce256dfec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Fri, 20 Oct 2023 11:55:41 +0100 Subject: [PATCH 299/326] nvmem: add explicit config option to read old syntax fixed OF cells MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Binding for fixed NVMEM cells defined directly as NVMEM device subnodes has been deprecated. It has been replaced by the "fixed-layout" NVMEM layout binding. New syntax is meant to be clearer and should help avoiding imprecise bindings. NVMEM subsystem already supports the new binding. It should be a good idea to limit support for old syntax to existing drivers that actually support & use it (we can't break backward compatibility!). That way we additionally encourage new bindings & drivers to ignore deprecated binding. It wasn't clear (to me) if rtc and w1 code actually uses old syntax fixed cells. I enabled them to don't risk any breakage. Signed-off-by: Rafał Miłecki [for meson-{efuse,mx-efuse}.c] Acked-by: Martin Blumenstingl [for mtk-efuse.c, nvmem/core.c, nvmem-provider.h] Reviewed-by: AngeloGioacchino Del Regno [MT8192, MT8195 Chromebooks] Tested-by: AngeloGioacchino Del Regno [for microchip-otpc.c] Reviewed-by: Claudiu Beznea [SAMA7G5-EK] Tested-by: Claudiu Beznea Acked-by: Jernej Skrabec Signed-off-by: Srinivas Kandagatla Link: https://lore.kernel.org/r/20231020105545.216052-3-srinivas.kandagatla@linaro.org Signed-off-by: Greg Kroah-Hartman --- drivers/mtd/mtdcore.c | 2 ++ drivers/nvmem/apple-efuses.c | 1 + drivers/nvmem/core.c | 8 +++++--- drivers/nvmem/imx-ocotp-scu.c | 1 + drivers/nvmem/imx-ocotp.c | 1 + drivers/nvmem/meson-efuse.c | 1 + drivers/nvmem/meson-mx-efuse.c | 1 + drivers/nvmem/microchip-otpc.c | 1 + drivers/nvmem/mtk-efuse.c | 1 + drivers/nvmem/qcom-spmi-sdam.c | 1 + drivers/nvmem/qfprom.c | 1 + drivers/nvmem/rave-sp-eeprom.c | 1 + drivers/nvmem/rockchip-efuse.c | 1 + drivers/nvmem/sc27xx-efuse.c | 1 + drivers/nvmem/sec-qfprom.c | 1 + drivers/nvmem/sprd-efuse.c | 1 + drivers/nvmem/stm32-romem.c | 1 + drivers/nvmem/sunplus-ocotp.c | 1 + drivers/nvmem/sunxi_sid.c | 1 + drivers/nvmem/uniphier-efuse.c | 1 + drivers/nvmem/zynqmp_nvmem.c | 1 + drivers/rtc/nvmem.c | 1 + drivers/w1/slaves/w1_ds250x.c | 1 + include/linux/nvmem-provider.h | 2 ++ 24 files changed, 30 insertions(+), 3 deletions(-) diff --git a/drivers/mtd/mtdcore.c b/drivers/mtd/mtdcore.c index 9bd661be3ae9..fbf60d1364f0 100644 --- a/drivers/mtd/mtdcore.c +++ b/drivers/mtd/mtdcore.c @@ -552,6 +552,7 @@ static int mtd_nvmem_add(struct mtd_info *mtd) config.dev = &mtd->dev; config.name = dev_name(&mtd->dev); config.owner = THIS_MODULE; + config.add_legacy_fixed_of_cells = of_device_is_compatible(node, "nvmem-cells"); config.reg_read = mtd_nvmem_reg_read; config.size = mtd->size; config.word_size = 1; @@ -898,6 +899,7 @@ static struct nvmem_device *mtd_otp_nvmem_register(struct mtd_info *mtd, config.name = compatible; config.id = NVMEM_DEVID_AUTO; config.owner = THIS_MODULE; + config.add_legacy_fixed_of_cells = true; config.type = NVMEM_TYPE_OTP; config.root_only = true; config.ignore_wp = true; diff --git a/drivers/nvmem/apple-efuses.c b/drivers/nvmem/apple-efuses.c index 9b7c87102104..d3d49d22338b 100644 --- a/drivers/nvmem/apple-efuses.c +++ b/drivers/nvmem/apple-efuses.c @@ -36,6 +36,7 @@ static int apple_efuses_probe(struct platform_device *pdev) struct resource *res; struct nvmem_config config = { .dev = &pdev->dev, + .add_legacy_fixed_of_cells = true, .read_only = true, .reg_read = apple_efuses_read, .stride = sizeof(u32), diff --git a/drivers/nvmem/core.c b/drivers/nvmem/core.c index eaf6a3fe8ca6..2710943f53c4 100644 --- a/drivers/nvmem/core.c +++ b/drivers/nvmem/core.c @@ -997,9 +997,11 @@ struct nvmem_device *nvmem_register(const struct nvmem_config *config) if (rval) goto err_remove_cells; - rval = nvmem_add_cells_from_legacy_of(nvmem); - if (rval) - goto err_remove_cells; + if (config->add_legacy_fixed_of_cells) { + rval = nvmem_add_cells_from_legacy_of(nvmem); + if (rval) + goto err_remove_cells; + } rval = nvmem_add_cells_from_fixed_layout(nvmem); if (rval) diff --git a/drivers/nvmem/imx-ocotp-scu.c b/drivers/nvmem/imx-ocotp-scu.c index c38d9c1c3f48..517d83e11af2 100644 --- a/drivers/nvmem/imx-ocotp-scu.c +++ b/drivers/nvmem/imx-ocotp-scu.c @@ -220,6 +220,7 @@ static int imx_scu_ocotp_write(void *context, unsigned int offset, static struct nvmem_config imx_scu_ocotp_nvmem_config = { .name = "imx-scu-ocotp", + .add_legacy_fixed_of_cells = true, .read_only = false, .word_size = 4, .stride = 1, diff --git a/drivers/nvmem/imx-ocotp.c b/drivers/nvmem/imx-ocotp.c index a223d9537f22..434f197e27bf 100644 --- a/drivers/nvmem/imx-ocotp.c +++ b/drivers/nvmem/imx-ocotp.c @@ -615,6 +615,7 @@ static int imx_ocotp_probe(struct platform_device *pdev) return PTR_ERR(priv->clk); priv->params = of_device_get_match_data(&pdev->dev); + imx_ocotp_nvmem_config.add_legacy_fixed_of_cells = true; imx_ocotp_nvmem_config.size = 4 * priv->params->nregs; imx_ocotp_nvmem_config.dev = dev; imx_ocotp_nvmem_config.priv = priv; diff --git a/drivers/nvmem/meson-efuse.c b/drivers/nvmem/meson-efuse.c index d6b533497ce1..b922df99f9bc 100644 --- a/drivers/nvmem/meson-efuse.c +++ b/drivers/nvmem/meson-efuse.c @@ -93,6 +93,7 @@ static int meson_efuse_probe(struct platform_device *pdev) econfig->dev = dev; econfig->name = dev_name(dev); + econfig->add_legacy_fixed_of_cells = true; econfig->stride = 1; econfig->word_size = 1; econfig->reg_read = meson_efuse_read; diff --git a/drivers/nvmem/meson-mx-efuse.c b/drivers/nvmem/meson-mx-efuse.c index d6d7aeda31f9..3ff04d5ca8f8 100644 --- a/drivers/nvmem/meson-mx-efuse.c +++ b/drivers/nvmem/meson-mx-efuse.c @@ -210,6 +210,7 @@ static int meson_mx_efuse_probe(struct platform_device *pdev) efuse->config.owner = THIS_MODULE; efuse->config.dev = &pdev->dev; efuse->config.priv = efuse; + efuse->config.add_legacy_fixed_of_cells = true; efuse->config.stride = drvdata->word_size; efuse->config.word_size = drvdata->word_size; efuse->config.size = SZ_512; diff --git a/drivers/nvmem/microchip-otpc.c b/drivers/nvmem/microchip-otpc.c index 436e0dc4f337..7cf81738a3e0 100644 --- a/drivers/nvmem/microchip-otpc.c +++ b/drivers/nvmem/microchip-otpc.c @@ -261,6 +261,7 @@ static int mchp_otpc_probe(struct platform_device *pdev) return ret; mchp_nvmem_config.dev = otpc->dev; + mchp_nvmem_config.add_legacy_fixed_of_cells = true; mchp_nvmem_config.size = size; mchp_nvmem_config.priv = otpc; nvmem = devm_nvmem_register(&pdev->dev, &mchp_nvmem_config); diff --git a/drivers/nvmem/mtk-efuse.c b/drivers/nvmem/mtk-efuse.c index b36cd0dcc8c7..87c94686cfd2 100644 --- a/drivers/nvmem/mtk-efuse.c +++ b/drivers/nvmem/mtk-efuse.c @@ -83,6 +83,7 @@ static int mtk_efuse_probe(struct platform_device *pdev) return PTR_ERR(priv->base); pdata = device_get_match_data(dev); + econfig.add_legacy_fixed_of_cells = true; econfig.stride = 1; econfig.word_size = 1; econfig.reg_read = mtk_reg_read; diff --git a/drivers/nvmem/qcom-spmi-sdam.c b/drivers/nvmem/qcom-spmi-sdam.c index 70f2d4f2efbf..9aa8f42faa4c 100644 --- a/drivers/nvmem/qcom-spmi-sdam.c +++ b/drivers/nvmem/qcom-spmi-sdam.c @@ -142,6 +142,7 @@ static int sdam_probe(struct platform_device *pdev) sdam->sdam_config.name = "spmi_sdam"; sdam->sdam_config.id = NVMEM_DEVID_AUTO; sdam->sdam_config.owner = THIS_MODULE; + sdam->sdam_config.add_legacy_fixed_of_cells = true; sdam->sdam_config.stride = 1; sdam->sdam_config.word_size = 1; sdam->sdam_config.reg_read = sdam_read; diff --git a/drivers/nvmem/qfprom.c b/drivers/nvmem/qfprom.c index 525be03b7bba..116a39e804c7 100644 --- a/drivers/nvmem/qfprom.c +++ b/drivers/nvmem/qfprom.c @@ -357,6 +357,7 @@ static int qfprom_probe(struct platform_device *pdev) { struct nvmem_config econfig = { .name = "qfprom", + .add_legacy_fixed_of_cells = true, .stride = 1, .word_size = 1, .id = NVMEM_DEVID_AUTO, diff --git a/drivers/nvmem/rave-sp-eeprom.c b/drivers/nvmem/rave-sp-eeprom.c index df6a1c594b78..9ecf3873cbb7 100644 --- a/drivers/nvmem/rave-sp-eeprom.c +++ b/drivers/nvmem/rave-sp-eeprom.c @@ -328,6 +328,7 @@ static int rave_sp_eeprom_probe(struct platform_device *pdev) of_property_read_string(np, "zii,eeprom-name", &config.name); config.priv = eeprom; config.dev = dev; + config.add_legacy_fixed_of_cells = true; config.size = size; config.reg_read = rave_sp_eeprom_reg_read; config.reg_write = rave_sp_eeprom_reg_write; diff --git a/drivers/nvmem/rockchip-efuse.c b/drivers/nvmem/rockchip-efuse.c index 4004c5bece42..2b40978ddb18 100644 --- a/drivers/nvmem/rockchip-efuse.c +++ b/drivers/nvmem/rockchip-efuse.c @@ -205,6 +205,7 @@ static int rockchip_rk3399_efuse_read(void *context, unsigned int offset, static struct nvmem_config econfig = { .name = "rockchip-efuse", + .add_legacy_fixed_of_cells = true, .stride = 1, .word_size = 1, .read_only = true, diff --git a/drivers/nvmem/sc27xx-efuse.c b/drivers/nvmem/sc27xx-efuse.c index 2210da40dfbd..bff27011f4ff 100644 --- a/drivers/nvmem/sc27xx-efuse.c +++ b/drivers/nvmem/sc27xx-efuse.c @@ -247,6 +247,7 @@ static int sc27xx_efuse_probe(struct platform_device *pdev) econfig.reg_read = sc27xx_efuse_read; econfig.priv = efuse; econfig.dev = &pdev->dev; + econfig.add_legacy_fixed_of_cells = true; nvmem = devm_nvmem_register(&pdev->dev, &econfig); if (IS_ERR(nvmem)) { dev_err(&pdev->dev, "failed to register nvmem config\n"); diff --git a/drivers/nvmem/sec-qfprom.c b/drivers/nvmem/sec-qfprom.c index e48c2dc0c44b..19799b3fe00a 100644 --- a/drivers/nvmem/sec-qfprom.c +++ b/drivers/nvmem/sec-qfprom.c @@ -47,6 +47,7 @@ static int sec_qfprom_probe(struct platform_device *pdev) { struct nvmem_config econfig = { .name = "sec-qfprom", + .add_legacy_fixed_of_cells = true, .stride = 1, .word_size = 1, .id = NVMEM_DEVID_AUTO, diff --git a/drivers/nvmem/sprd-efuse.c b/drivers/nvmem/sprd-efuse.c index 7e6e31db4baa..bb3105f3291f 100644 --- a/drivers/nvmem/sprd-efuse.c +++ b/drivers/nvmem/sprd-efuse.c @@ -408,6 +408,7 @@ static int sprd_efuse_probe(struct platform_device *pdev) econfig.read_only = false; econfig.name = "sprd-efuse"; econfig.size = efuse->data->blk_nums * SPRD_EFUSE_BLOCK_WIDTH; + econfig.add_legacy_fixed_of_cells = true; econfig.reg_read = sprd_efuse_read; econfig.reg_write = sprd_efuse_write; econfig.priv = efuse; diff --git a/drivers/nvmem/stm32-romem.c b/drivers/nvmem/stm32-romem.c index 0f84044bd1ad..1541c20709d2 100644 --- a/drivers/nvmem/stm32-romem.c +++ b/drivers/nvmem/stm32-romem.c @@ -207,6 +207,7 @@ static int stm32_romem_probe(struct platform_device *pdev) priv->cfg.priv = priv; priv->cfg.owner = THIS_MODULE; priv->cfg.type = NVMEM_TYPE_OTP; + priv->cfg.add_legacy_fixed_of_cells = true; priv->lower = 0; diff --git a/drivers/nvmem/sunplus-ocotp.c b/drivers/nvmem/sunplus-ocotp.c index f3a18aa0a6c7..38f5d9df39cd 100644 --- a/drivers/nvmem/sunplus-ocotp.c +++ b/drivers/nvmem/sunplus-ocotp.c @@ -145,6 +145,7 @@ disable_clk: static struct nvmem_config sp_ocotp_nvmem_config = { .name = "sp-ocotp", + .add_legacy_fixed_of_cells = true, .read_only = true, .word_size = 1, .size = QAC628_OTP_SIZE, diff --git a/drivers/nvmem/sunxi_sid.c b/drivers/nvmem/sunxi_sid.c index 5d364d85347f..ba14a76208ab 100644 --- a/drivers/nvmem/sunxi_sid.c +++ b/drivers/nvmem/sunxi_sid.c @@ -153,6 +153,7 @@ static int sunxi_sid_probe(struct platform_device *pdev) nvmem_cfg->dev = dev; nvmem_cfg->name = "sunxi-sid"; nvmem_cfg->type = NVMEM_TYPE_OTP; + nvmem_cfg->add_legacy_fixed_of_cells = true; nvmem_cfg->read_only = true; nvmem_cfg->size = cfg->size; nvmem_cfg->word_size = 1; diff --git a/drivers/nvmem/uniphier-efuse.c b/drivers/nvmem/uniphier-efuse.c index 0a1dbb80537e..6ad3295d3195 100644 --- a/drivers/nvmem/uniphier-efuse.c +++ b/drivers/nvmem/uniphier-efuse.c @@ -52,6 +52,7 @@ static int uniphier_efuse_probe(struct platform_device *pdev) econfig.size = resource_size(res); econfig.priv = priv; econfig.dev = dev; + econfig.add_legacy_fixed_of_cells = true; nvmem = devm_nvmem_register(dev, &econfig); return PTR_ERR_OR_ZERO(nvmem); diff --git a/drivers/nvmem/zynqmp_nvmem.c b/drivers/nvmem/zynqmp_nvmem.c index f49bb9a26d05..7f15aa89a9d0 100644 --- a/drivers/nvmem/zynqmp_nvmem.c +++ b/drivers/nvmem/zynqmp_nvmem.c @@ -58,6 +58,7 @@ static int zynqmp_nvmem_probe(struct platform_device *pdev) priv->dev = dev; econfig.dev = dev; + econfig.add_legacy_fixed_of_cells = true; econfig.reg_read = zynqmp_nvmem_read; econfig.priv = priv; diff --git a/drivers/rtc/nvmem.c b/drivers/rtc/nvmem.c index 07ede21cee34..37df7e80525b 100644 --- a/drivers/rtc/nvmem.c +++ b/drivers/rtc/nvmem.c @@ -21,6 +21,7 @@ int devm_rtc_nvmem_register(struct rtc_device *rtc, nvmem_config->dev = dev; nvmem_config->owner = rtc->owner; + nvmem_config->add_legacy_fixed_of_cells = true; nvmem = devm_nvmem_register(dev, nvmem_config); if (IS_ERR(nvmem)) dev_err(dev, "failed to register nvmem device for RTC\n"); diff --git a/drivers/w1/slaves/w1_ds250x.c b/drivers/w1/slaves/w1_ds250x.c index 7592c7050d1d..cb426f7dd23d 100644 --- a/drivers/w1/slaves/w1_ds250x.c +++ b/drivers/w1/slaves/w1_ds250x.c @@ -168,6 +168,7 @@ static int w1_eprom_add_slave(struct w1_slave *sl) struct nvmem_device *nvmem; struct nvmem_config nvmem_cfg = { .dev = &sl->dev, + .add_legacy_fixed_of_cells = true, .reg_read = w1_nvmem_read, .type = NVMEM_TYPE_OTP, .read_only = true, diff --git a/include/linux/nvmem-provider.h b/include/linux/nvmem-provider.h index dae26295e6be..1b81adebdb8b 100644 --- a/include/linux/nvmem-provider.h +++ b/include/linux/nvmem-provider.h @@ -82,6 +82,7 @@ struct nvmem_cell_info { * @owner: Pointer to exporter module. Used for refcounting. * @cells: Optional array of pre-defined NVMEM cells. * @ncells: Number of elements in cells. + * @add_legacy_fixed_of_cells: Read fixed NVMEM cells from old OF syntax. * @keepout: Optional array of keepout ranges (sorted ascending by start). * @nkeepout: Number of elements in the keepout array. * @type: Type of the nvmem storage @@ -112,6 +113,7 @@ struct nvmem_config { struct module *owner; const struct nvmem_cell_info *cells; int ncells; + bool add_legacy_fixed_of_cells; const struct nvmem_keepout *keepout; unsigned int nkeepout; enum nvmem_type type; From c5330723d5a0c77299a38a46e5611a584e887b87 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Fri, 20 Oct 2023 11:55:42 +0100 Subject: [PATCH 300/326] dt-bindings: nvmem: move deprecated cells binding to its own file MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Support for old NVMEM fixed cells was deprecated in favour of "fixed-layout". It's still part of the nvmem.yaml though and may be unknowingly used by new bindings added without much of analyze. To make it more difficult to accidentally support old syntax move its binding to separated file with "deprecated" in its name. Signed-off-by: Rafał Miłecki Acked-by: Neil Armstrong Reviewed-by: Rob Herring Acked-by: Heiko Stuebner Signed-off-by: Srinivas Kandagatla Link: https://lore.kernel.org/r/20231020105545.216052-4-srinivas.kandagatla@linaro.org Signed-off-by: Greg Kroah-Hartman --- .../devicetree/bindings/mtd/mtd.yaml | 7 ++++- .../bindings/mtd/partitions/nvmem-cells.yaml | 1 + .../nvmem/amlogic,meson-gxbb-efuse.yaml | 1 + .../bindings/nvmem/amlogic,meson6-efuse.yaml | 1 + .../bindings/nvmem/apple,efuses.yaml | 1 + .../devicetree/bindings/nvmem/imx-ocotp.yaml | 1 + .../bindings/nvmem/mediatek,efuse.yaml | 1 + .../nvmem/microchip,sama7g5-otpc.yaml | 1 + .../devicetree/bindings/nvmem/mxs-ocotp.yaml | 1 + .../nvmem/nvmem-deprecated-cells.yaml | 28 +++++++++++++++++++ .../devicetree/bindings/nvmem/nvmem.yaml | 9 ------ .../bindings/nvmem/qcom,qfprom.yaml | 1 + .../bindings/nvmem/qcom,sec-qfprom.yaml | 1 + .../bindings/nvmem/qcom,spmi-sdam.yaml | 1 + .../bindings/nvmem/rockchip,otp.yaml | 1 + .../bindings/nvmem/rockchip-efuse.yaml | 1 + .../nvmem/socionext,uniphier-efuse.yaml | 1 + .../bindings/nvmem/sunplus,sp7021-ocotp.yaml | 1 + .../bindings/rtc/amlogic,meson6-rtc.yaml | 1 + 19 files changed, 50 insertions(+), 10 deletions(-) create mode 100644 Documentation/devicetree/bindings/nvmem/nvmem-deprecated-cells.yaml diff --git a/Documentation/devicetree/bindings/mtd/mtd.yaml b/Documentation/devicetree/bindings/mtd/mtd.yaml index b82ca03e969c..f322290ee516 100644 --- a/Documentation/devicetree/bindings/mtd/mtd.yaml +++ b/Documentation/devicetree/bindings/mtd/mtd.yaml @@ -43,7 +43,12 @@ patternProperties: deprecated: true "^otp(-[0-9]+)?$": - $ref: ../nvmem/nvmem.yaml# + type: object + + allOf: + - $ref: ../nvmem/nvmem.yaml# + - $ref: ../nvmem/nvmem-deprecated-cells.yaml# + unevaluatedProperties: false description: | diff --git a/Documentation/devicetree/bindings/mtd/partitions/nvmem-cells.yaml b/Documentation/devicetree/bindings/mtd/partitions/nvmem-cells.yaml index 5474d63268dc..9518281007af 100644 --- a/Documentation/devicetree/bindings/mtd/partitions/nvmem-cells.yaml +++ b/Documentation/devicetree/bindings/mtd/partitions/nvmem-cells.yaml @@ -19,6 +19,7 @@ maintainers: allOf: - $ref: /schemas/mtd/partitions/partition.yaml# - $ref: /schemas/nvmem/nvmem.yaml# + - $ref: /schemas/nvmem/nvmem-deprecated-cells.yaml# properties: compatible: diff --git a/Documentation/devicetree/bindings/nvmem/amlogic,meson-gxbb-efuse.yaml b/Documentation/devicetree/bindings/nvmem/amlogic,meson-gxbb-efuse.yaml index e49c2754ff55..9801fe6f91b5 100644 --- a/Documentation/devicetree/bindings/nvmem/amlogic,meson-gxbb-efuse.yaml +++ b/Documentation/devicetree/bindings/nvmem/amlogic,meson-gxbb-efuse.yaml @@ -11,6 +11,7 @@ maintainers: allOf: - $ref: nvmem.yaml# + - $ref: nvmem-deprecated-cells.yaml# properties: compatible: diff --git a/Documentation/devicetree/bindings/nvmem/amlogic,meson6-efuse.yaml b/Documentation/devicetree/bindings/nvmem/amlogic,meson6-efuse.yaml index 84b3dfd21e09..b5cf740f96fa 100644 --- a/Documentation/devicetree/bindings/nvmem/amlogic,meson6-efuse.yaml +++ b/Documentation/devicetree/bindings/nvmem/amlogic,meson6-efuse.yaml @@ -12,6 +12,7 @@ maintainers: allOf: - $ref: nvmem.yaml# + - $ref: nvmem-deprecated-cells.yaml# properties: compatible: diff --git a/Documentation/devicetree/bindings/nvmem/apple,efuses.yaml b/Documentation/devicetree/bindings/nvmem/apple,efuses.yaml index e0860b6b85f3..d3abdafdbca0 100644 --- a/Documentation/devicetree/bindings/nvmem/apple,efuses.yaml +++ b/Documentation/devicetree/bindings/nvmem/apple,efuses.yaml @@ -16,6 +16,7 @@ maintainers: allOf: - $ref: nvmem.yaml# + - $ref: nvmem-deprecated-cells.yaml# properties: compatible: diff --git a/Documentation/devicetree/bindings/nvmem/imx-ocotp.yaml b/Documentation/devicetree/bindings/nvmem/imx-ocotp.yaml index 99e60d713dac..be1314454bec 100644 --- a/Documentation/devicetree/bindings/nvmem/imx-ocotp.yaml +++ b/Documentation/devicetree/bindings/nvmem/imx-ocotp.yaml @@ -16,6 +16,7 @@ description: | allOf: - $ref: nvmem.yaml# + - $ref: nvmem-deprecated-cells.yaml# properties: compatible: diff --git a/Documentation/devicetree/bindings/nvmem/mediatek,efuse.yaml b/Documentation/devicetree/bindings/nvmem/mediatek,efuse.yaml index 7ec2988b597e..cf5f9e22bb7e 100644 --- a/Documentation/devicetree/bindings/nvmem/mediatek,efuse.yaml +++ b/Documentation/devicetree/bindings/nvmem/mediatek,efuse.yaml @@ -16,6 +16,7 @@ maintainers: allOf: - $ref: nvmem.yaml# + - $ref: nvmem-deprecated-cells.yaml# properties: $nodename: diff --git a/Documentation/devicetree/bindings/nvmem/microchip,sama7g5-otpc.yaml b/Documentation/devicetree/bindings/nvmem/microchip,sama7g5-otpc.yaml index a296d348adb4..cc25f2927682 100644 --- a/Documentation/devicetree/bindings/nvmem/microchip,sama7g5-otpc.yaml +++ b/Documentation/devicetree/bindings/nvmem/microchip,sama7g5-otpc.yaml @@ -16,6 +16,7 @@ description: | allOf: - $ref: nvmem.yaml# + - $ref: nvmem-deprecated-cells.yaml# properties: compatible: diff --git a/Documentation/devicetree/bindings/nvmem/mxs-ocotp.yaml b/Documentation/devicetree/bindings/nvmem/mxs-ocotp.yaml index a9b822aeaa7e..f43186f98607 100644 --- a/Documentation/devicetree/bindings/nvmem/mxs-ocotp.yaml +++ b/Documentation/devicetree/bindings/nvmem/mxs-ocotp.yaml @@ -11,6 +11,7 @@ maintainers: allOf: - $ref: nvmem.yaml# + - $ref: nvmem-deprecated-cells.yaml# properties: compatible: diff --git a/Documentation/devicetree/bindings/nvmem/nvmem-deprecated-cells.yaml b/Documentation/devicetree/bindings/nvmem/nvmem-deprecated-cells.yaml new file mode 100644 index 000000000000..951af28bbfb3 --- /dev/null +++ b/Documentation/devicetree/bindings/nvmem/nvmem-deprecated-cells.yaml @@ -0,0 +1,28 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/nvmem/nvmem-deprecated-cells.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: NVMEM old syntax for fixed cells + +maintainers: + - Srinivas Kandagatla + +description: | + Before introducing NVMEM layouts all NVMEM (fixed) cells were defined + as direct device subnodes. That syntax was replaced by "fixed-layout" + and is deprecated now. No new bindings should use it. + +patternProperties: + "@[0-9a-f]+(,[0-7])?$": + type: object + allOf: + - $ref: layouts/fixed-cell.yaml + - properties: + compatible: false + deprecated: true + +additionalProperties: true + +... diff --git a/Documentation/devicetree/bindings/nvmem/nvmem.yaml b/Documentation/devicetree/bindings/nvmem/nvmem.yaml index 9f921d940142..4fd015d402ce 100644 --- a/Documentation/devicetree/bindings/nvmem/nvmem.yaml +++ b/Documentation/devicetree/bindings/nvmem/nvmem.yaml @@ -46,15 +46,6 @@ properties: container may reference more advanced (dynamic) layout parsers. -patternProperties: - "@[0-9a-f]+(,[0-7])?$": - type: object - allOf: - - $ref: layouts/fixed-cell.yaml - - properties: - compatible: false - deprecated: true - additionalProperties: true examples: diff --git a/Documentation/devicetree/bindings/nvmem/qcom,qfprom.yaml b/Documentation/devicetree/bindings/nvmem/qcom,qfprom.yaml index 8740938c32eb..8c8f05d9eaf1 100644 --- a/Documentation/devicetree/bindings/nvmem/qcom,qfprom.yaml +++ b/Documentation/devicetree/bindings/nvmem/qcom,qfprom.yaml @@ -11,6 +11,7 @@ maintainers: allOf: - $ref: nvmem.yaml# + - $ref: nvmem-deprecated-cells.yaml# properties: compatible: diff --git a/Documentation/devicetree/bindings/nvmem/qcom,sec-qfprom.yaml b/Documentation/devicetree/bindings/nvmem/qcom,sec-qfprom.yaml index 9b133f783d29..2ada2099946d 100644 --- a/Documentation/devicetree/bindings/nvmem/qcom,sec-qfprom.yaml +++ b/Documentation/devicetree/bindings/nvmem/qcom,sec-qfprom.yaml @@ -16,6 +16,7 @@ description: allOf: - $ref: nvmem.yaml# + - $ref: nvmem-deprecated-cells.yaml# properties: compatible: diff --git a/Documentation/devicetree/bindings/nvmem/qcom,spmi-sdam.yaml b/Documentation/devicetree/bindings/nvmem/qcom,spmi-sdam.yaml index cd980def97b8..068bedf5dbc9 100644 --- a/Documentation/devicetree/bindings/nvmem/qcom,spmi-sdam.yaml +++ b/Documentation/devicetree/bindings/nvmem/qcom,spmi-sdam.yaml @@ -16,6 +16,7 @@ description: | allOf: - $ref: nvmem.yaml# + - $ref: nvmem-deprecated-cells.yaml# properties: compatible: diff --git a/Documentation/devicetree/bindings/nvmem/rockchip,otp.yaml b/Documentation/devicetree/bindings/nvmem/rockchip,otp.yaml index 9c6eff788928..a44d44b32809 100644 --- a/Documentation/devicetree/bindings/nvmem/rockchip,otp.yaml +++ b/Documentation/devicetree/bindings/nvmem/rockchip,otp.yaml @@ -49,6 +49,7 @@ required: allOf: - $ref: nvmem.yaml# + - $ref: nvmem-deprecated-cells.yaml# - if: properties: diff --git a/Documentation/devicetree/bindings/nvmem/rockchip-efuse.yaml b/Documentation/devicetree/bindings/nvmem/rockchip-efuse.yaml index c5403e149080..b80fd8d1ae5b 100644 --- a/Documentation/devicetree/bindings/nvmem/rockchip-efuse.yaml +++ b/Documentation/devicetree/bindings/nvmem/rockchip-efuse.yaml @@ -11,6 +11,7 @@ maintainers: allOf: - $ref: nvmem.yaml# + - $ref: nvmem-deprecated-cells.yaml# properties: compatible: diff --git a/Documentation/devicetree/bindings/nvmem/socionext,uniphier-efuse.yaml b/Documentation/devicetree/bindings/nvmem/socionext,uniphier-efuse.yaml index efccc5aacbe0..e27cbae2d63a 100644 --- a/Documentation/devicetree/bindings/nvmem/socionext,uniphier-efuse.yaml +++ b/Documentation/devicetree/bindings/nvmem/socionext,uniphier-efuse.yaml @@ -12,6 +12,7 @@ maintainers: allOf: - $ref: nvmem.yaml# + - $ref: nvmem-deprecated-cells.yaml# properties: compatible: diff --git a/Documentation/devicetree/bindings/nvmem/sunplus,sp7021-ocotp.yaml b/Documentation/devicetree/bindings/nvmem/sunplus,sp7021-ocotp.yaml index da3f1de7d281..af97eeb8316c 100644 --- a/Documentation/devicetree/bindings/nvmem/sunplus,sp7021-ocotp.yaml +++ b/Documentation/devicetree/bindings/nvmem/sunplus,sp7021-ocotp.yaml @@ -12,6 +12,7 @@ maintainers: allOf: - $ref: nvmem.yaml# + - $ref: nvmem-deprecated-cells.yaml# properties: compatible: diff --git a/Documentation/devicetree/bindings/rtc/amlogic,meson6-rtc.yaml b/Documentation/devicetree/bindings/rtc/amlogic,meson6-rtc.yaml index 8bf7d3a9be98..3a4551253e3e 100644 --- a/Documentation/devicetree/bindings/rtc/amlogic,meson6-rtc.yaml +++ b/Documentation/devicetree/bindings/rtc/amlogic,meson6-rtc.yaml @@ -13,6 +13,7 @@ maintainers: allOf: - $ref: rtc.yaml# - $ref: /schemas/nvmem/nvmem.yaml# + - $ref: /schemas/nvmem/nvmem-deprecated-cells.yaml# properties: compatible: From 716a8027efbb84291111764847d37cb0648ef69b Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Fri, 20 Oct 2023 11:55:44 +0100 Subject: [PATCH 301/326] dt-bindings: nvmem: u-boot,env: Add missing additionalProperties on child node schemas MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Just as unevaluatedProperties or additionalProperties are required at the top level of schemas, they should (and will) also be required for child node schemas. That ensures only documented properties are present for any node. Signed-off-by: Rob Herring Acked-by: Conor Dooley Acked-by: Rafał Miłecki Signed-off-by: Srinivas Kandagatla Link: https://lore.kernel.org/r/20231020105545.216052-6-srinivas.kandagatla@linaro.org Signed-off-by: Greg Kroah-Hartman --- Documentation/devicetree/bindings/nvmem/u-boot,env.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Documentation/devicetree/bindings/nvmem/u-boot,env.yaml b/Documentation/devicetree/bindings/nvmem/u-boot,env.yaml index 36d97fb87865..9c36afc7084b 100644 --- a/Documentation/devicetree/bindings/nvmem/u-boot,env.yaml +++ b/Documentation/devicetree/bindings/nvmem/u-boot,env.yaml @@ -51,6 +51,8 @@ properties: ethaddr: type: object description: Ethernet interfaces base MAC address. + additionalProperties: false + properties: "#nvmem-cell-cells": description: The first argument is a MAC address offset. From 0720219f4d34a88a9badb4de70cfad7585687d48 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Fri, 20 Oct 2023 11:55:45 +0100 Subject: [PATCH 302/326] nvmem: Use device_get_match_data() Use preferred device_get_match_data() instead of of_match_device() to get the driver match data. With this, adjust the includes to explicitly include the correct headers. Signed-off-by: Rob Herring Signed-off-by: Srinivas Kandagatla Link: https://lore.kernel.org/r/20231020105545.216052-7-srinivas.kandagatla@linaro.org Signed-off-by: Greg Kroah-Hartman --- drivers/nvmem/mxs-ocotp.c | 10 ++++------ drivers/nvmem/stm32-romem.c | 7 ++++--- 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/drivers/nvmem/mxs-ocotp.c b/drivers/nvmem/mxs-ocotp.c index 588ab56d75b7..7b78f18f9545 100644 --- a/drivers/nvmem/mxs-ocotp.c +++ b/drivers/nvmem/mxs-ocotp.c @@ -13,8 +13,9 @@ #include #include #include -#include +#include #include +#include #include #include @@ -140,11 +141,10 @@ static int mxs_ocotp_probe(struct platform_device *pdev) struct device *dev = &pdev->dev; const struct mxs_data *data; struct mxs_ocotp *otp; - const struct of_device_id *match; int ret; - match = of_match_device(dev->driver->of_match_table, dev); - if (!match || !match->data) + data = device_get_match_data(dev); + if (!data) return -EINVAL; otp = devm_kzalloc(dev, sizeof(*otp), GFP_KERNEL); @@ -169,8 +169,6 @@ static int mxs_ocotp_probe(struct platform_device *pdev) if (ret) return ret; - data = match->data; - ocotp_config.size = data->size; ocotp_config.priv = otp; ocotp_config.dev = dev; diff --git a/drivers/nvmem/stm32-romem.c b/drivers/nvmem/stm32-romem.c index 1541c20709d2..8a553b1799a8 100644 --- a/drivers/nvmem/stm32-romem.c +++ b/drivers/nvmem/stm32-romem.c @@ -10,7 +10,9 @@ #include #include #include -#include +#include +#include +#include #include #include "stm32-bsec-optee-ta.h" @@ -211,8 +213,7 @@ static int stm32_romem_probe(struct platform_device *pdev) priv->lower = 0; - cfg = (const struct stm32_romem_cfg *) - of_match_device(dev->driver->of_match_table, dev)->data; + cfg = device_get_match_data(dev); if (!cfg) { priv->cfg.read_only = true; priv->cfg.size = resource_size(res); From 28cbfe09ff20964d293cd7af10d2ec0782cf86cb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rodr=C3=ADguez=20Barbarin=2C=20Jos=C3=A9=20Javier?= Date: Fri, 20 Oct 2023 12:44:32 +0000 Subject: [PATCH 303/326] mcb: Use the actual bus passed to init and release functions The functions mcb_bus_add_devices() and mcb_devices_unregister() take a mcb_bus as argument that is never being used. This implies that there is only one bus. Do not ignore mcb_bus parameter and get the actual bus_type from the device related to this mcb_bus. Co-developed-by: Jorge Sanjuan Garcia Signed-off-by: Jorge Sanjuan Garcia Signed-off-by: Jose Javier Rodriguez Barbarin Link: https://lore.kernel.org/r/20231020124324.54692-2-JoseJavier.Rodriguez@duagon.com Signed-off-by: Greg Kroah-Hartman --- drivers/mcb/mcb-core.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/mcb/mcb-core.c b/drivers/mcb/mcb-core.c index 5c6157b0db75..2a4a5e71ad4e 100644 --- a/drivers/mcb/mcb-core.c +++ b/drivers/mcb/mcb-core.c @@ -311,7 +311,7 @@ static int __mcb_devices_unregister(struct device *dev, void *data) static void mcb_devices_unregister(struct mcb_bus *bus) { - bus_for_each_dev(&mcb_bus_type, NULL, NULL, __mcb_devices_unregister); + bus_for_each_dev(bus->dev.bus, NULL, NULL, __mcb_devices_unregister); } /** * mcb_release_bus() - Free a @mcb_bus @@ -406,7 +406,7 @@ static int __mcb_bus_add_devices(struct device *dev, void *data) */ void mcb_bus_add_devices(const struct mcb_bus *bus) { - bus_for_each_dev(&mcb_bus_type, NULL, NULL, __mcb_bus_add_devices); + bus_for_each_dev(bus->dev.bus, NULL, NULL, __mcb_bus_add_devices); } EXPORT_SYMBOL_NS_GPL(mcb_bus_add_devices, MCB); From 63ba2d07b4be72b94216d20561f43e1150b25d98 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sanju=C3=A1n=20Garc=C3=ADa=2C=20Jorge?= Date: Thu, 19 Oct 2023 14:15:34 +0000 Subject: [PATCH 304/326] mcb: fix error handling for different scenarios when parsing chameleon_parse_gdd() may fail for different reasons and end up in the err tag. Make sure we at least always free the mcb_device allocated with mcb_alloc_dev(). If mcb_device_register() fails, make sure to give up the reference in the same place the device was added. Fixes: 728ac3389296 ("mcb: mcb-parse: fix error handing in chameleon_parse_gdd()") Cc: stable Reviewed-by: Jose Javier Rodriguez Barbarin Signed-off-by: Jorge Sanjuan Garcia Link: https://lore.kernel.org/r/20231019141434.57971-2-jorge.sanjuangarcia@duagon.com Signed-off-by: Greg Kroah-Hartman --- drivers/mcb/mcb-core.c | 1 + drivers/mcb/mcb-parse.c | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/mcb/mcb-core.c b/drivers/mcb/mcb-core.c index 2a4a5e71ad4e..ba4530459de8 100644 --- a/drivers/mcb/mcb-core.c +++ b/drivers/mcb/mcb-core.c @@ -246,6 +246,7 @@ int mcb_device_register(struct mcb_bus *bus, struct mcb_device *dev) return 0; out: + put_device(&dev->dev); return ret; } diff --git a/drivers/mcb/mcb-parse.c b/drivers/mcb/mcb-parse.c index 656b6b71c768..1ae37e693de0 100644 --- a/drivers/mcb/mcb-parse.c +++ b/drivers/mcb/mcb-parse.c @@ -106,7 +106,7 @@ static int chameleon_parse_gdd(struct mcb_bus *bus, return 0; err: - put_device(&mdev->dev); + mcb_free_dev(mdev); return ret; } From 12280cc708f28357e7ad85bab2bcc3715e59a8f7 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Wed, 18 Oct 2023 17:59:47 +0300 Subject: [PATCH 305/326] parport: Clean up resources correctly when parport_register_port() fails The smatch warns about uncleaned resources in case the parport_register_port() fails: parport_register_port() warn: '&tmp->full_list' not removed from list This is indeed an issue introduced when converting code to use kasprintf(). However, the whole kasprintf() dance in this case is not needed as dev_set_name() can handle the formatted input and produces the same result. So, the solution is to delegate name forming to the dev_set_name() and make device_register() error path to deal with error handling (via put_device() call). Fixes: 8d8ae17eb0de ("parport: Use kasprintf() instead of fixed buffer formatting") Reported-by: kernel test robot Reported-by: Dan Carpenter Closes: https://lore.kernel.org/r/202310180809.hepZB9k6-lkp@intel.com/ Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20231018145948.1367648-1-andriy.shevchenko@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/parport/share.c | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/drivers/parport/share.c b/drivers/parport/share.c index a9a9cb0477ea..048a459ce4b0 100644 --- a/drivers/parport/share.c +++ b/drivers/parport/share.c @@ -361,7 +361,6 @@ static void free_port(struct device *dev) kfree(port->probe_info[d].description); } - kfree(port->name); kfree(port); } @@ -479,16 +478,13 @@ struct parport *parport_register_port(unsigned long base, int irq, int dma, /* * Now that the portnum is known finish doing the Init. */ - tmp->name = kasprintf(GFP_KERNEL, "parport%d", tmp->portnum); - if (!tmp->name) { - kfree(tmp); - return NULL; - } - dev_set_name(&tmp->bus_dev, tmp->name); + dev_set_name(&tmp->bus_dev, "parport%d", tmp->portnum); tmp->bus_dev.bus = &parport_bus_type; tmp->bus_dev.release = free_port; tmp->bus_dev.type = &parport_device_type; + tmp->name = dev_name(&tmp->bus_dev); + for (device = 0; device < 5; device++) /* assume the worst */ tmp->probe_info[device].class = PARPORT_CLASS_LEGACY; From 421359cbdbdcaea93b83e1e6b61eb261b75b1998 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Wed, 18 Oct 2023 17:59:48 +0300 Subject: [PATCH 306/326] parport: Drop even more unneeded NULL or 0 assignments kzalloc() gives us a zeroed memory, no need to explicitly assing 0 or NULL or similar to the members of the data structure that has been allocated with the above mentioned API. Note, the initializstion of full_list member is not needed anymore as list_add_tail will rewrite the contents of the prev and next pointers. Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20231018145948.1367648-2-andriy.shevchenko@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/parport/share.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/parport/share.c b/drivers/parport/share.c index 048a459ce4b0..e21831d93305 100644 --- a/drivers/parport/share.c +++ b/drivers/parport/share.c @@ -459,7 +459,6 @@ struct parport *parport_register_port(unsigned long base, int irq, int dma, sema_init(&tmp->ieee1284.irq, 0); tmp->spintime = parport_default_spintime; atomic_set(&tmp->ref_count, 1); - INIT_LIST_HEAD(&tmp->full_list); /* Search for the lowest free parport number. */ @@ -489,8 +488,6 @@ struct parport *parport_register_port(unsigned long base, int irq, int dma, /* assume the worst */ tmp->probe_info[device].class = PARPORT_CLASS_LEGACY; - tmp->waithead = tmp->waittail = NULL; - ret = device_register(&tmp->bus_dev); if (ret) { put_device(&tmp->bus_dev); From f6c086ef8417b4c6941628ab043c4688e2fd17c2 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Tue, 24 Oct 2023 13:49:35 +0200 Subject: [PATCH 307/326] misc: phantom: make phantom_class constant Now that the driver core allows for struct class to be in read-only memory, we should make all 'class' structures declared at build time placing them into read-only memory, instead of having to be dynamically allocated at runtime. Cc: Arnd Bergmann Reviewed-by: Jiri Slaby Link: https://lore.kernel.org/r/2023102434-font-feast-98e3@gregkh Signed-off-by: Greg Kroah-Hartman --- drivers/misc/phantom.c | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/drivers/misc/phantom.c b/drivers/misc/phantom.c index 7966a6b8b5b3..30bd7c39c261 100644 --- a/drivers/misc/phantom.c +++ b/drivers/misc/phantom.c @@ -35,9 +35,12 @@ #define PHB_NOT_OH 2 static DEFINE_MUTEX(phantom_mutex); -static struct class *phantom_class; static int phantom_major; +static const struct class phantom_class = { + .name = "phantom", +}; + struct phantom_device { unsigned int opened; void __iomem *caddr; @@ -403,7 +406,7 @@ static int phantom_probe(struct pci_dev *pdev, goto err_irq; } - if (IS_ERR(device_create(phantom_class, &pdev->dev, + if (IS_ERR(device_create(&phantom_class, &pdev->dev, MKDEV(phantom_major, minor), NULL, "phantom%u", minor))) dev_err(&pdev->dev, "can't create device\n"); @@ -436,7 +439,7 @@ static void phantom_remove(struct pci_dev *pdev) struct phantom_device *pht = pci_get_drvdata(pdev); unsigned int minor = MINOR(pht->cdev.dev); - device_destroy(phantom_class, MKDEV(phantom_major, minor)); + device_destroy(&phantom_class, MKDEV(phantom_major, minor)); cdev_del(&pht->cdev); @@ -503,13 +506,12 @@ static int __init phantom_init(void) int retval; dev_t dev; - phantom_class = class_create("phantom"); - if (IS_ERR(phantom_class)) { - retval = PTR_ERR(phantom_class); + retval = class_register(&phantom_class); + if (retval) { printk(KERN_ERR "phantom: can't register phantom class\n"); goto err; } - retval = class_create_file(phantom_class, &class_attr_version.attr); + retval = class_create_file(&phantom_class, &class_attr_version.attr); if (retval) { printk(KERN_ERR "phantom: can't create sysfs version file\n"); goto err_class; @@ -535,9 +537,9 @@ static int __init phantom_init(void) err_unchr: unregister_chrdev_region(dev, PHANTOM_MAX_MINORS); err_attr: - class_remove_file(phantom_class, &class_attr_version.attr); + class_remove_file(&phantom_class, &class_attr_version.attr); err_class: - class_destroy(phantom_class); + class_unregister(&phantom_class); err: return retval; } @@ -548,8 +550,8 @@ static void __exit phantom_exit(void) unregister_chrdev_region(MKDEV(phantom_major, 0), PHANTOM_MAX_MINORS); - class_remove_file(phantom_class, &class_attr_version.attr); - class_destroy(phantom_class); + class_remove_file(&phantom_class, &class_attr_version.attr); + class_unregister(&phantom_class); pr_debug("phantom: module successfully removed\n"); } From d223192634ffac3182cc38fda3cca0a8814276ea Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Tue, 24 Oct 2023 13:48:35 +0200 Subject: [PATCH 308/326] cxl: make cxl_class constant Now that the driver core allows for struct class to be in read-only memory, we should make all 'class' structures declared at build time placing them into read-only memory, instead of having to be dynamically allocated at runtime. Cc: Andrew Donnellan Cc: Arnd Bergmann Cc: linuxppc-dev@lists.ozlabs.org Acked-by: Frederic Barrat Link: https://lore.kernel.org/r/2023102434-haiku-uphill-0c11@gregkh Signed-off-by: Greg Kroah-Hartman --- drivers/misc/cxl/file.c | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/drivers/misc/cxl/file.c b/drivers/misc/cxl/file.c index 144d1f2d78ce..012e11b959bc 100644 --- a/drivers/misc/cxl/file.c +++ b/drivers/misc/cxl/file.c @@ -38,8 +38,6 @@ static dev_t cxl_dev; -static struct class *cxl_class; - static int __afu_open(struct inode *inode, struct file *file, bool master) { struct cxl *adapter; @@ -559,7 +557,10 @@ static char *cxl_devnode(const struct device *dev, umode_t *mode) return kasprintf(GFP_KERNEL, "cxl/%s", dev_name(dev)); } -extern struct class *cxl_class; +static const struct class cxl_class = { + .name = "cxl", + .devnode = cxl_devnode, +}; static int cxl_add_chardev(struct cxl_afu *afu, dev_t devt, struct cdev *cdev, struct device **chardev, char *postfix, char *desc, @@ -575,7 +576,7 @@ static int cxl_add_chardev(struct cxl_afu *afu, dev_t devt, struct cdev *cdev, return rc; } - dev = device_create(cxl_class, &afu->dev, devt, afu, + dev = device_create(&cxl_class, &afu->dev, devt, afu, "afu%i.%i%s", afu->adapter->adapter_num, afu->slice, postfix); if (IS_ERR(dev)) { rc = PTR_ERR(dev); @@ -633,14 +634,14 @@ void cxl_chardev_afu_remove(struct cxl_afu *afu) int cxl_register_afu(struct cxl_afu *afu) { - afu->dev.class = cxl_class; + afu->dev.class = &cxl_class; return device_register(&afu->dev); } int cxl_register_adapter(struct cxl *adapter) { - adapter->dev.class = cxl_class; + adapter->dev.class = &cxl_class; /* * Future: When we support dynamically reprogramming the PSL & AFU we @@ -678,13 +679,11 @@ int __init cxl_file_init(void) pr_devel("CXL device allocated, MAJOR %i\n", MAJOR(cxl_dev)); - cxl_class = class_create("cxl"); - if (IS_ERR(cxl_class)) { + rc = class_register(&cxl_class); + if (rc) { pr_err("Unable to create CXL class\n"); - rc = PTR_ERR(cxl_class); goto err; } - cxl_class->devnode = cxl_devnode; return 0; @@ -696,5 +695,5 @@ err: void cxl_file_exit(void) { unregister_chrdev_region(cxl_dev, CXL_NUM_MINORS); - class_destroy(cxl_class); + class_unregister(&cxl_class); } From cf3c415d7d2c21288fc85d7ed5da9b9af36d0de9 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Tue, 24 Oct 2023 13:49:04 +0200 Subject: [PATCH 309/326] ocxl: make ocxl_class constant Now that the driver core allows for struct class to be in read-only memory, we should make all 'class' structures declared at build time placing them into read-only memory, instead of having to be dynamically allocated at runtime. Cc: Andrew Donnellan Cc: Arnd Bergmann Cc: linuxppc-dev@lists.ozlabs.org Acked-by: Frederic Barrat Link: https://lore.kernel.org/r/2023102403-squirt-defraud-6c0c@gregkh Signed-off-by: Greg Kroah-Hartman --- drivers/misc/ocxl/file.c | 27 +++++++++++++++------------ 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/drivers/misc/ocxl/file.c b/drivers/misc/ocxl/file.c index 6e63f060e4cc..ac69b7f361f5 100644 --- a/drivers/misc/ocxl/file.c +++ b/drivers/misc/ocxl/file.c @@ -14,7 +14,6 @@ #define OCXL_NUM_MINORS 256 /* Total to reserve */ static dev_t ocxl_dev; -static struct class *ocxl_class; static DEFINE_MUTEX(minors_idr_lock); static struct idr minors_idr; @@ -509,6 +508,16 @@ static void ocxl_file_make_invisible(struct ocxl_file_info *info) cdev_del(&info->cdev); } +static char *ocxl_devnode(const struct device *dev, umode_t *mode) +{ + return kasprintf(GFP_KERNEL, "ocxl/%s", dev_name(dev)); +} + +static const struct class ocxl_class = { + .name = "ocxl", + .devnode = ocxl_devnode, +}; + int ocxl_file_register_afu(struct ocxl_afu *afu) { int minor; @@ -529,7 +538,7 @@ int ocxl_file_register_afu(struct ocxl_afu *afu) info->dev.parent = &fn->dev; info->dev.devt = MKDEV(MAJOR(ocxl_dev), minor); - info->dev.class = ocxl_class; + info->dev.class = &ocxl_class; info->dev.release = info_release; info->afu = afu; @@ -584,11 +593,6 @@ void ocxl_file_unregister_afu(struct ocxl_afu *afu) device_unregister(&info->dev); } -static char *ocxl_devnode(const struct device *dev, umode_t *mode) -{ - return kasprintf(GFP_KERNEL, "ocxl/%s", dev_name(dev)); -} - int ocxl_file_init(void) { int rc; @@ -601,20 +605,19 @@ int ocxl_file_init(void) return rc; } - ocxl_class = class_create("ocxl"); - if (IS_ERR(ocxl_class)) { + rc = class_register(&ocxl_class); + if (rc) { pr_err("Unable to create ocxl class\n"); unregister_chrdev_region(ocxl_dev, OCXL_NUM_MINORS); - return PTR_ERR(ocxl_class); + return rc; } - ocxl_class->devnode = ocxl_devnode; return 0; } void ocxl_file_exit(void) { - class_destroy(ocxl_class); + class_unregister(&ocxl_class); unregister_chrdev_region(ocxl_dev, OCXL_NUM_MINORS); idr_destroy(&minors_idr); } From 40ea89fb19fdb73472f63a4b00c728ebb55af1b5 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Tue, 24 Oct 2023 13:49:59 +0200 Subject: [PATCH 310/326] uacce: make uacce_class constant Now that the driver core allows for struct class to be in read-only memory, we should make all 'class' structures declared at build time placing them into read-only memory, instead of having to be dynamically allocated at runtime. Cc: Zhou Wang Cc: Arnd Bergmann Cc: linux-accelerators@lists.ozlabs.org Tested-by: Zhangfei Gao Link: https://lore.kernel.org/r/2023102458-designate-vicinity-4c86@gregkh Signed-off-by: Greg Kroah-Hartman --- drivers/misc/uacce/uacce.c | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/drivers/misc/uacce/uacce.c b/drivers/misc/uacce/uacce.c index 930c252753a0..bdc2e6fda782 100644 --- a/drivers/misc/uacce/uacce.c +++ b/drivers/misc/uacce/uacce.c @@ -7,10 +7,13 @@ #include #include -static struct class *uacce_class; static dev_t uacce_devt; static DEFINE_XARRAY_ALLOC(uacce_xa); +static const struct class uacce_class = { + .name = UACCE_NAME, +}; + /* * If the parent driver or the device disappears, the queue state is invalid and * ops are not usable anymore. @@ -530,7 +533,7 @@ struct uacce_device *uacce_alloc(struct device *parent, mutex_init(&uacce->mutex); device_initialize(&uacce->dev); uacce->dev.devt = MKDEV(MAJOR(uacce_devt), uacce->dev_id); - uacce->dev.class = uacce_class; + uacce->dev.class = &uacce_class; uacce->dev.groups = uacce_dev_groups; uacce->dev.parent = uacce->parent; uacce->dev.release = uacce_release; @@ -623,13 +626,13 @@ static int __init uacce_init(void) { int ret; - uacce_class = class_create(UACCE_NAME); - if (IS_ERR(uacce_class)) - return PTR_ERR(uacce_class); + ret = class_register(&uacce_class); + if (ret) + return ret; ret = alloc_chrdev_region(&uacce_devt, 0, MINORMASK, UACCE_NAME); if (ret) - class_destroy(uacce_class); + class_unregister(&uacce_class); return ret; } @@ -637,7 +640,7 @@ static int __init uacce_init(void) static __exit void uacce_exit(void) { unregister_chrdev_region(uacce_devt, MINORMASK); - class_destroy(uacce_class); + class_unregister(&uacce_class); } subsys_initcall(uacce_init); From 79614953e815b8c3b063fe68efa3cf508260ac0d Mon Sep 17 00:00:00 2001 From: Rajan Vaja Date: Fri, 27 Oct 2023 00:53:58 +0530 Subject: [PATCH 311/326] firmware: xilinx: Move EXPORT_SYMBOL_GPL next to zynqmp_pm_feature definition As mentioned in Documentation/process/coding-style.rst: In source files, separate functions with one blank line. If the function is exported, the **EXPORT** macro for it should follow immediately after the closing function brace line. So inline with guideline move zynqmp_pm_feature export symbol after its definition. Signed-off-by: Rajan Vaja Signed-off-by: Radhey Shyam Pandey Link: https://lore.kernel.org/r/1698348238-2320426-1-git-send-email-radhey.shyam.pandey@amd.com Signed-off-by: Greg Kroah-Hartman --- drivers/firmware/xilinx/zynqmp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/firmware/xilinx/zynqmp.c b/drivers/firmware/xilinx/zynqmp.c index 4cc1ac7f76ed..b0d22d4455d9 100644 --- a/drivers/firmware/xilinx/zynqmp.c +++ b/drivers/firmware/xilinx/zynqmp.c @@ -226,7 +226,6 @@ static int do_feature_check_call(const u32 api_id) return ret; } -EXPORT_SYMBOL_GPL(zynqmp_pm_feature); /** * zynqmp_pm_feature() - Check whether given feature is supported or not and @@ -246,6 +245,7 @@ int zynqmp_pm_feature(const u32 api_id) return ret; } +EXPORT_SYMBOL_GPL(zynqmp_pm_feature); /** * zynqmp_pm_is_function_supported() - Check whether given IOCTL/QUERY function From 8293703a492ae97c86af27c75b76e6239ec86483 Mon Sep 17 00:00:00 2001 From: Siddharth Vadapalli Date: Fri, 20 Oct 2023 17:32:48 +0530 Subject: [PATCH 312/326] misc: pci_endpoint_test: Add deviceID for J721S2 PCIe EP device support Add DEVICE_ID for J721S2 and enable support for endpoints configured with this DEVICE_ID in the pci_endpoint_test driver. Signed-off-by: Siddharth Vadapalli Cc: stable Reviewed-by: Manivannan Sadhasivam Link: https://lore.kernel.org/r/20231020120248.3168406-1-s-vadapalli@ti.com Signed-off-by: Greg Kroah-Hartman --- drivers/misc/pci_endpoint_test.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/misc/pci_endpoint_test.c b/drivers/misc/pci_endpoint_test.c index ed4d0ef5e5c3..7e1acc68d435 100644 --- a/drivers/misc/pci_endpoint_test.c +++ b/drivers/misc/pci_endpoint_test.c @@ -71,6 +71,7 @@ #define PCI_DEVICE_ID_TI_AM654 0xb00c #define PCI_DEVICE_ID_TI_J7200 0xb00f #define PCI_DEVICE_ID_TI_AM64 0xb010 +#define PCI_DEVICE_ID_TI_J721S2 0xb013 #define PCI_DEVICE_ID_LS1088A 0x80c0 #define PCI_DEVICE_ID_IMX8 0x0808 @@ -999,6 +1000,9 @@ static const struct pci_device_id pci_endpoint_test_tbl[] = { { PCI_DEVICE(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_AM64), .driver_data = (kernel_ulong_t)&j721e_data, }, + { PCI_DEVICE(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_J721S2), + .driver_data = (kernel_ulong_t)&j721e_data, + }, { } }; MODULE_DEVICE_TABLE(pci, pci_endpoint_test_tbl); From 61e54dea807d202d5bfd563d926b163b43b7fecd Mon Sep 17 00:00:00 2001 From: James Clark Date: Fri, 20 Oct 2023 16:41:03 +0100 Subject: [PATCH 313/326] MAINTAINERS: coresight: Add missing Coresight files There are a few files missing from the list like test_arm_coresight.sh and arm-coresight.txt so add the missing entries. Signed-off-by: James Clark Link: https://lore.kernel.org/r/20231020154103.55936-1-james.clark@arm.com Signed-off-by: Greg Kroah-Hartman --- MAINTAINERS | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index eac660dd6adb..cb127b1a3a13 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -2068,12 +2068,16 @@ F: Documentation/trace/coresight/* F: drivers/hwtracing/coresight/* F: include/dt-bindings/arm/coresight-cti-dt.h F: include/linux/coresight* +F: include/uapi/linux/coresight* F: samples/coresight/* +F: tools/perf/Documentation/arm-coresight.txt F: tools/perf/arch/arm/util/auxtrace.c F: tools/perf/arch/arm/util/cs-etm.c F: tools/perf/arch/arm/util/cs-etm.h F: tools/perf/arch/arm/util/pmu.c +F: tools/perf/tests/shell/*coresight* F: tools/perf/tests/shell/coresight/* +F: tools/perf/tests/shell/lib/*coresight* F: tools/perf/util/cs-etm-decoder/* F: tools/perf/util/cs-etm.* From f4cf4e5db331a5ce69e3f0b21d322cac0f4e4b5d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Mon, 23 Oct 2023 12:27:59 +0200 Subject: [PATCH 314/326] Revert "nvmem: add new config option" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This reverts commit 517f14d9cf3533d5ab4fded195ab6f80a92e378f. Config option "no_of_node" is no longer needed since adding a more explicit and targeted option "add_legacy_fixed_of_cells". That "no_of_node" config option was needed *earlier* to help mtd's case. DT nodes of MTD partitions (that are also NVMEM devices) may contain subnodes. Those SHOULD NOT be treated as NVMEM fixed cells. To prevent NVMEM core code from parsing subnodes a "no_of_node" option was added (and set to true in mtd) to make for_each_child_of_node() in NVMEM a no-op. That was a bit hacky because it was messing with "of_node" pointer to achieve some side-effect. With the introduction of "add_legacy_fixed_of_cells" config option things got more explicit. MTD subsystem simply tells NVMEM when to look for fixed cells and there is no need to hack "of_node" pointer anymore. Signed-off-by: Rafał Miłecki Reviewed-by: Miquel Raynal Signed-off-by: Srinivas Kandagatla Link: https://lore.kernel.org/r/20231023102759.31529-1-zajec5@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/mtd/mtdcore.c | 1 - drivers/nvmem/core.c | 2 +- include/linux/nvmem-provider.h | 2 -- 3 files changed, 1 insertion(+), 4 deletions(-) diff --git a/drivers/mtd/mtdcore.c b/drivers/mtd/mtdcore.c index fbf60d1364f0..74dd1b74008d 100644 --- a/drivers/mtd/mtdcore.c +++ b/drivers/mtd/mtdcore.c @@ -560,7 +560,6 @@ static int mtd_nvmem_add(struct mtd_info *mtd) config.read_only = true; config.root_only = true; config.ignore_wp = true; - config.no_of_node = !of_device_is_compatible(node, "nvmem-cells"); config.priv = mtd; mtd->nvmem = nvmem_register(&config); diff --git a/drivers/nvmem/core.c b/drivers/nvmem/core.c index 2710943f53c4..bf42b7e826db 100644 --- a/drivers/nvmem/core.c +++ b/drivers/nvmem/core.c @@ -935,7 +935,7 @@ struct nvmem_device *nvmem_register(const struct nvmem_config *config) nvmem->nkeepout = config->nkeepout; if (config->of_node) nvmem->dev.of_node = config->of_node; - else if (!config->no_of_node) + else nvmem->dev.of_node = config->dev->of_node; switch (config->id) { diff --git a/include/linux/nvmem-provider.h b/include/linux/nvmem-provider.h index 1b81adebdb8b..e3930835235b 100644 --- a/include/linux/nvmem-provider.h +++ b/include/linux/nvmem-provider.h @@ -89,7 +89,6 @@ struct nvmem_cell_info { * @read_only: Device is read-only. * @root_only: Device is accessibly to root only. * @of_node: If given, this will be used instead of the parent's of_node. - * @no_of_node: Device should not use the parent's of_node even if it's !NULL. * @reg_read: Callback to read data. * @reg_write: Callback to write data. * @size: Device size. @@ -122,7 +121,6 @@ struct nvmem_config { bool ignore_wp; struct nvmem_layout *layout; struct device_node *of_node; - bool no_of_node; nvmem_reg_read_t reg_read; nvmem_reg_write_t reg_write; int size; From ed758ca69c0c0fe5820403e98c4fe427a302d553 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Tue, 24 Oct 2023 19:12:52 +0200 Subject: [PATCH 315/326] dt-bindings: nvmem: SID: allow NVMEM cells based on old syntax MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This binding supported NVMEM cells as subnodes and that syntax is used by few in-kenel DTS files. Modify binding to allow it. Reported-by: Rob Herring Fixes: c5330723d5a0 ("dt-bindings: nvmem: move deprecated cells binding to its own file") Signed-off-by: Rafał Miłecki Reviewed-by: Rob Herring Link: https://lore.kernel.org/r/20231024171253.19976-1-zajec5@gmail.com Signed-off-by: Greg Kroah-Hartman --- .../devicetree/bindings/nvmem/allwinner,sun4i-a10-sid.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/nvmem/allwinner,sun4i-a10-sid.yaml b/Documentation/devicetree/bindings/nvmem/allwinner,sun4i-a10-sid.yaml index 296001e7f498..3f32e8e39903 100644 --- a/Documentation/devicetree/bindings/nvmem/allwinner,sun4i-a10-sid.yaml +++ b/Documentation/devicetree/bindings/nvmem/allwinner,sun4i-a10-sid.yaml @@ -12,6 +12,7 @@ maintainers: allOf: - $ref: nvmem.yaml# + - $ref: nvmem-deprecated-cells.yaml# properties: compatible: From 2b107158f8095d0de9773080b68b1df38a6017bd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Tue, 24 Oct 2023 19:12:53 +0200 Subject: [PATCH 316/326] dt-bindings: eeprom: at24: allow NVMEM cells based on old syntax MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This binding supported NVMEM cells as subnodes and that syntax is used by few in-kenel DTS files. Modify binding to allow it. Reported-by: Rob Herring Fixes: c5330723d5a0 ("dt-bindings: nvmem: move deprecated cells binding to its own file") Signed-off-by: Rafał Miłecki Reviewed-by: Rob Herring Acked-by: Bartosz Golaszewski Link: https://lore.kernel.org/r/20231024171253.19976-2-zajec5@gmail.com Signed-off-by: Greg Kroah-Hartman --- Documentation/devicetree/bindings/eeprom/at24.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/eeprom/at24.yaml b/Documentation/devicetree/bindings/eeprom/at24.yaml index 98139489d4b5..bfff71ff3d6a 100644 --- a/Documentation/devicetree/bindings/eeprom/at24.yaml +++ b/Documentation/devicetree/bindings/eeprom/at24.yaml @@ -12,6 +12,7 @@ maintainers: allOf: - $ref: /schemas/nvmem/nvmem.yaml + - $ref: /schemas/nvmem/nvmem-deprecated-cells.yaml select: properties: From c966c715c77717bd8bdda32a46b33868acb7a4e2 Mon Sep 17 00:00:00 2001 From: Ayush Singh Date: Tue, 17 Oct 2023 15:41:12 +0530 Subject: [PATCH 317/326] dt-bindings: net: Add ti,cc1352p7 Add DT bindings for Texas Instruments Simplelink CC1352P7 wireless MCU BeaglePlay has CC1352P7 co-processor connected to the main AM62 (running Linux) over UART. In the BeagleConnect Technology, CC1352 is responsible for handling 6LoWPAN communication with beagleconnect freedom nodes as well as their discovery. Signed-off-by: Ayush Singh Reviewed-by: Krzysztof Kozlowski Reviewed-by: Nishanth Menon Link: https://lore.kernel.org/r/20231017101116.178041-2-ayushdevel1325@gmail.com Signed-off-by: Greg Kroah-Hartman --- .../devicetree/bindings/net/ti,cc1352p7.yaml | 51 +++++++++++++++++++ MAINTAINERS | 6 +++ 2 files changed, 57 insertions(+) create mode 100644 Documentation/devicetree/bindings/net/ti,cc1352p7.yaml diff --git a/Documentation/devicetree/bindings/net/ti,cc1352p7.yaml b/Documentation/devicetree/bindings/net/ti,cc1352p7.yaml new file mode 100644 index 000000000000..3dde10de4630 --- /dev/null +++ b/Documentation/devicetree/bindings/net/ti,cc1352p7.yaml @@ -0,0 +1,51 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/net/ti,cc1352p7.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Texas Instruments Simplelink CC1352P7 wireless MCU + +description: + The CC1352P7 MCU can be connected via SPI or UART. + +maintainers: + - Ayush Singh + +properties: + compatible: + const: ti,cc1352p7 + + clocks: + items: + - description: high-frequency main system (MCU and peripherals) clock + - description: low-frequency system clock + + clock-names: + items: + - const: sclk_hf + - const: sclk_lf + + reset-gpios: + maxItems: 1 + + vdds-supply: true + +required: + - compatible + +additionalProperties: false + +examples: + - | + #include + + serial { + mcu { + compatible = "ti,cc1352p7"; + clocks = <&sclk_hf 0>, <&sclk_lf 25>; + clock-names = "sclk_hf", "sclk_lf"; + reset-gpios = <&pio 35 GPIO_ACTIVE_LOW>; + vdds-supply = <&vdds>; + }; + }; diff --git a/MAINTAINERS b/MAINTAINERS index cb127b1a3a13..9aeb8558978d 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -8991,6 +8991,12 @@ F: drivers/staging/greybus/sdio.c F: drivers/staging/greybus/spi.c F: drivers/staging/greybus/spilib.c +GREYBUS BEAGLEPLAY DRIVERS +M: Ayush Singh +L: greybus-dev@lists.linaro.org (moderated for non-subscribers) +S: Maintained +F: Documentation/devicetree/bindings/net/ti,cc1352p7.yaml + GREYBUS SUBSYSTEM M: Johan Hovold M: Alex Elder From ec558bbfea671ac020a6dc6be8bf8f0ee556cce0 Mon Sep 17 00:00:00 2001 From: Ayush Singh Date: Tue, 17 Oct 2023 15:41:13 +0530 Subject: [PATCH 318/326] greybus: Add BeaglePlay Linux Driver Add the Greybus host driver for BeaglePlay board by BeagleBoard.org. The current greybus setup involves running SVC in a user-space application (GBridge) and using netlink to communicate with kernel space. GBridge itself uses wpanusb kernel driver, so the greybus messages travel from kernel space (gb_netlink) to user-space (GBridge) and then back to kernel space (wpanusb) before reaching CC1352. This driver directly communicates with CC1352 (running SVC Zephyr application). Thus, it simplifies the complete greybus setup eliminating user-space GBridge. This driver is responsible for the following: - Start SVC (CC1352) on driver load. - Send/Receive Greybus messages to/from CC1352 using HDLC over UART. - Print Logs from CC1352. - Stop SVC (CC1352) on driver load. Signed-off-by: Ayush Singh Link: https://lore.kernel.org/r/20231017101116.178041-3-ayushdevel1325@gmail.com Signed-off-by: Greg Kroah-Hartman --- MAINTAINERS | 1 + drivers/greybus/Kconfig | 10 + drivers/greybus/Makefile | 2 + drivers/greybus/gb-beagleplay.c | 501 ++++++++++++++++++++++++++++++++ 4 files changed, 514 insertions(+) create mode 100644 drivers/greybus/gb-beagleplay.c diff --git a/MAINTAINERS b/MAINTAINERS index 9aeb8558978d..00b30b8bddae 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -8996,6 +8996,7 @@ M: Ayush Singh L: greybus-dev@lists.linaro.org (moderated for non-subscribers) S: Maintained F: Documentation/devicetree/bindings/net/ti,cc1352p7.yaml +F: drivers/greybus/gb-beagleplay.c GREYBUS SUBSYSTEM M: Johan Hovold diff --git a/drivers/greybus/Kconfig b/drivers/greybus/Kconfig index 78ba3c3083d5..033d31dbf3b8 100644 --- a/drivers/greybus/Kconfig +++ b/drivers/greybus/Kconfig @@ -17,6 +17,16 @@ menuconfig GREYBUS if GREYBUS +config GREYBUS_BEAGLEPLAY + tristate "Greybus BeaglePlay driver" + depends on SERIAL_DEV_BUS + help + Select this option if you have a BeaglePlay where CC1352 + co-processor acts as Greybus SVC. + + To compile this code as a module, chose M here: the module + will be called gb-beagleplay.ko + config GREYBUS_ES2 tristate "Greybus ES3 USB host controller" depends on USB diff --git a/drivers/greybus/Makefile b/drivers/greybus/Makefile index 9bccdd229aa2..d986e94f8897 100644 --- a/drivers/greybus/Makefile +++ b/drivers/greybus/Makefile @@ -18,6 +18,8 @@ obj-$(CONFIG_GREYBUS) += greybus.o # needed for trace events ccflags-y += -I$(src) +obj-$(CONFIG_GREYBUS_BEAGLEPLAY) += gb-beagleplay.o + # Greybus Host controller drivers gb-es2-y := es2.o diff --git a/drivers/greybus/gb-beagleplay.c b/drivers/greybus/gb-beagleplay.c new file mode 100644 index 000000000000..43318c1993ba --- /dev/null +++ b/drivers/greybus/gb-beagleplay.c @@ -0,0 +1,501 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Beagleplay Linux Driver for Greybus + * + * Copyright (c) 2023 Ayush Singh + * Copyright (c) 2023 BeagleBoard.org Foundation + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define RX_HDLC_PAYLOAD 256 +#define CRC_LEN 2 +#define MAX_RX_HDLC (1 + RX_HDLC_PAYLOAD + CRC_LEN) +#define TX_CIRC_BUF_SIZE 1024 + +#define ADDRESS_GREYBUS 0x01 +#define ADDRESS_DBG 0x02 +#define ADDRESS_CONTROL 0x03 + +#define HDLC_FRAME 0x7E +#define HDLC_ESC 0x7D +#define HDLC_XOR 0x20 + +#define CONTROL_SVC_START 0x01 +#define CONTROL_SVC_STOP 0x02 + +/* The maximum number of CPorts supported by Greybus Host Device */ +#define GB_MAX_CPORTS 32 + +/** + * struct gb_beagleplay - BeaglePlay Greybus driver + * + * @sd: underlying serdev device + * + * @gb_hd: greybus host device + * + * @tx_work: hdlc transmit work + * @tx_producer_lock: hdlc transmit data producer lock. acquired when appending data to buffer. + * @tx_consumer_lock: hdlc transmit data consumer lock. acquired when sending data over uart. + * @tx_circ_buf: hdlc transmit circular buffer. + * @tx_crc: hdlc transmit crc-ccitt fcs + * + * @rx_buffer_len: length of receive buffer filled. + * @rx_buffer: hdlc frame receive buffer + * @rx_in_esc: hdlc rx flag to indicate ESC frame + */ +struct gb_beagleplay { + struct serdev_device *sd; + + struct gb_host_device *gb_hd; + + struct work_struct tx_work; + spinlock_t tx_producer_lock; + spinlock_t tx_consumer_lock; + struct circ_buf tx_circ_buf; + u16 tx_crc; + + u16 rx_buffer_len; + bool rx_in_esc; + u8 rx_buffer[MAX_RX_HDLC]; +}; + +/** + * struct hdlc_payload - Structure to represent part of HDCL frame payload data. + * + * @len: buffer length in bytes + * @buf: payload buffer + */ +struct hdlc_payload { + u16 len; + void *buf; +}; + +static void hdlc_rx_greybus_frame(struct gb_beagleplay *bg, u8 *buf, u16 len) +{ + u16 cport_id; + struct gb_operation_msg_hdr *hdr = (struct gb_operation_msg_hdr *)buf; + + memcpy(&cport_id, hdr->pad, sizeof(cport_id)); + + dev_dbg(&bg->sd->dev, "Greybus Operation %u type %X cport %u status %u received", + hdr->operation_id, hdr->type, cport_id, hdr->result); + + greybus_data_rcvd(bg->gb_hd, cport_id, buf, len); +} + +static void hdlc_rx_dbg_frame(const struct gb_beagleplay *bg, const char *buf, u16 len) +{ + dev_dbg(&bg->sd->dev, "CC1352 Log: %.*s", (int)len, buf); +} + +/** + * hdlc_write() - Consume HDLC Buffer. + * @bg: beagleplay greybus driver + * + * Assumes that consumer lock has been acquired. + */ +static void hdlc_write(struct gb_beagleplay *bg) +{ + int written; + /* Start consuming HDLC data */ + int head = smp_load_acquire(&bg->tx_circ_buf.head); + int tail = bg->tx_circ_buf.tail; + int count = CIRC_CNT_TO_END(head, tail, TX_CIRC_BUF_SIZE); + const unsigned char *buf = &bg->tx_circ_buf.buf[tail]; + + if (count > 0) { + written = serdev_device_write_buf(bg->sd, buf, count); + + /* Finish consuming HDLC data */ + smp_store_release(&bg->tx_circ_buf.tail, (tail + written) & (TX_CIRC_BUF_SIZE - 1)); + } +} + +/** + * hdlc_append() - Queue HDLC data for sending. + * @bg: beagleplay greybus driver + * @value: hdlc byte to transmit + * + * Assumes that producer lock as been acquired. + */ +static void hdlc_append(struct gb_beagleplay *bg, u8 value) +{ + int tail, head = bg->tx_circ_buf.head; + + while (true) { + tail = READ_ONCE(bg->tx_circ_buf.tail); + + if (CIRC_SPACE(head, tail, TX_CIRC_BUF_SIZE) >= 1) { + bg->tx_circ_buf.buf[head] = value; + + /* Finish producing HDLC byte */ + smp_store_release(&bg->tx_circ_buf.head, + (head + 1) & (TX_CIRC_BUF_SIZE - 1)); + return; + } + dev_warn(&bg->sd->dev, "Tx circ buf full"); + usleep_range(3000, 5000); + } +} + +static void hdlc_append_escaped(struct gb_beagleplay *bg, u8 value) +{ + if (value == HDLC_FRAME || value == HDLC_ESC) { + hdlc_append(bg, HDLC_ESC); + value ^= HDLC_XOR; + } + hdlc_append(bg, value); +} + +static void hdlc_append_tx_frame(struct gb_beagleplay *bg) +{ + bg->tx_crc = 0xFFFF; + hdlc_append(bg, HDLC_FRAME); +} + +static void hdlc_append_tx_u8(struct gb_beagleplay *bg, u8 value) +{ + bg->tx_crc = crc_ccitt(bg->tx_crc, &value, 1); + hdlc_append_escaped(bg, value); +} + +static void hdlc_append_tx_buf(struct gb_beagleplay *bg, const u8 *buf, u16 len) +{ + size_t i; + + for (i = 0; i < len; i++) + hdlc_append_tx_u8(bg, buf[i]); +} + +static void hdlc_append_tx_crc(struct gb_beagleplay *bg) +{ + bg->tx_crc ^= 0xffff; + hdlc_append_escaped(bg, bg->tx_crc & 0xff); + hdlc_append_escaped(bg, (bg->tx_crc >> 8) & 0xff); +} + +static void hdlc_transmit(struct work_struct *work) +{ + struct gb_beagleplay *bg = container_of(work, struct gb_beagleplay, tx_work); + + spin_lock_bh(&bg->tx_consumer_lock); + hdlc_write(bg); + spin_unlock_bh(&bg->tx_consumer_lock); +} + +static void hdlc_tx_frames(struct gb_beagleplay *bg, u8 address, u8 control, + const struct hdlc_payload payloads[], size_t count) +{ + size_t i; + + spin_lock(&bg->tx_producer_lock); + + hdlc_append_tx_frame(bg); + hdlc_append_tx_u8(bg, address); + hdlc_append_tx_u8(bg, control); + + for (i = 0; i < count; ++i) + hdlc_append_tx_buf(bg, payloads[i].buf, payloads[i].len); + + hdlc_append_tx_crc(bg); + hdlc_append_tx_frame(bg); + + spin_unlock(&bg->tx_producer_lock); + + schedule_work(&bg->tx_work); +} + +static void hdlc_tx_s_frame_ack(struct gb_beagleplay *bg) +{ + hdlc_tx_frames(bg, bg->rx_buffer[0], (bg->rx_buffer[1] >> 1) & 0x7, NULL, 0); +} + +static void hdlc_rx_frame(struct gb_beagleplay *bg) +{ + u16 crc, len; + u8 ctrl, *buf; + u8 address = bg->rx_buffer[0]; + + crc = crc_ccitt(0xffff, bg->rx_buffer, bg->rx_buffer_len); + if (crc != 0xf0b8) { + dev_warn_ratelimited(&bg->sd->dev, "CRC failed from %02x: 0x%04x", address, crc); + return; + } + + ctrl = bg->rx_buffer[1]; + buf = &bg->rx_buffer[2]; + len = bg->rx_buffer_len - 4; + + /* I-Frame, send S-Frame ACK */ + if ((ctrl & 1) == 0) + hdlc_tx_s_frame_ack(bg); + + switch (address) { + case ADDRESS_DBG: + hdlc_rx_dbg_frame(bg, buf, len); + break; + case ADDRESS_GREYBUS: + hdlc_rx_greybus_frame(bg, buf, len); + break; + default: + dev_warn_ratelimited(&bg->sd->dev, "unknown frame %u", address); + } +} + +static int hdlc_rx(struct gb_beagleplay *bg, const u8 *data, size_t count) +{ + size_t i; + u8 c; + + for (i = 0; i < count; ++i) { + c = data[i]; + + switch (c) { + case HDLC_FRAME: + if (bg->rx_buffer_len) + hdlc_rx_frame(bg); + + bg->rx_buffer_len = 0; + break; + case HDLC_ESC: + bg->rx_in_esc = true; + break; + default: + if (bg->rx_in_esc) { + c ^= 0x20; + bg->rx_in_esc = false; + } + + if (bg->rx_buffer_len < MAX_RX_HDLC) { + bg->rx_buffer[bg->rx_buffer_len] = c; + bg->rx_buffer_len++; + } else { + dev_err_ratelimited(&bg->sd->dev, "RX Buffer Overflow"); + bg->rx_buffer_len = 0; + } + } + } + + return count; +} + +static int hdlc_init(struct gb_beagleplay *bg) +{ + INIT_WORK(&bg->tx_work, hdlc_transmit); + spin_lock_init(&bg->tx_producer_lock); + spin_lock_init(&bg->tx_consumer_lock); + bg->tx_circ_buf.head = 0; + bg->tx_circ_buf.tail = 0; + + bg->tx_circ_buf.buf = devm_kmalloc(&bg->sd->dev, TX_CIRC_BUF_SIZE, GFP_KERNEL); + if (!bg->tx_circ_buf.buf) + return -ENOMEM; + + bg->rx_buffer_len = 0; + bg->rx_in_esc = false; + + return 0; +} + +static void hdlc_deinit(struct gb_beagleplay *bg) +{ + flush_work(&bg->tx_work); +} + +static int gb_tty_receive(struct serdev_device *sd, const unsigned char *data, size_t count) +{ + struct gb_beagleplay *bg = serdev_device_get_drvdata(sd); + + return hdlc_rx(bg, data, count); +} + +static void gb_tty_wakeup(struct serdev_device *serdev) +{ + struct gb_beagleplay *bg = serdev_device_get_drvdata(serdev); + + schedule_work(&bg->tx_work); +} + +static struct serdev_device_ops gb_beagleplay_ops = { + .receive_buf = gb_tty_receive, + .write_wakeup = gb_tty_wakeup, +}; + +static int gb_message_send(struct gb_host_device *hd, u16 cport, struct gb_message *msg, gfp_t mask) +{ + struct gb_beagleplay *bg = dev_get_drvdata(&hd->dev); + struct hdlc_payload payloads[2]; + + dev_dbg(&hd->dev, "Sending greybus message with Operation %u, Type: %X on Cport %u", + msg->header->operation_id, msg->header->type, cport); + + if (msg->header->size > RX_HDLC_PAYLOAD) + return dev_err_probe(&hd->dev, -E2BIG, "Greybus message too big"); + + memcpy(msg->header->pad, &cport, sizeof(cport)); + + payloads[0].buf = msg->header; + payloads[0].len = sizeof(*msg->header); + payloads[1].buf = msg->payload; + payloads[1].len = msg->payload_size; + + hdlc_tx_frames(bg, ADDRESS_GREYBUS, 0x03, payloads, 2); + greybus_message_sent(bg->gb_hd, msg, 0); + + return 0; +} + +static void gb_message_cancel(struct gb_message *message) +{ +} + +static struct gb_hd_driver gb_hdlc_driver = { .message_send = gb_message_send, + .message_cancel = gb_message_cancel }; + +static void gb_beagleplay_start_svc(struct gb_beagleplay *bg) +{ + const u8 command = CONTROL_SVC_START; + const struct hdlc_payload payload = { .len = 1, .buf = (void *)&command }; + + hdlc_tx_frames(bg, ADDRESS_CONTROL, 0x03, &payload, 1); +} + +static void gb_beagleplay_stop_svc(struct gb_beagleplay *bg) +{ + const u8 command = CONTROL_SVC_STOP; + const struct hdlc_payload payload = { .len = 1, .buf = (void *)&command }; + + hdlc_tx_frames(bg, ADDRESS_CONTROL, 0x03, &payload, 1); +} + +static void gb_greybus_deinit(struct gb_beagleplay *bg) +{ + gb_hd_del(bg->gb_hd); + gb_hd_put(bg->gb_hd); +} + +static int gb_greybus_init(struct gb_beagleplay *bg) +{ + int ret; + + bg->gb_hd = gb_hd_create(&gb_hdlc_driver, &bg->sd->dev, TX_CIRC_BUF_SIZE, GB_MAX_CPORTS); + if (IS_ERR(bg->gb_hd)) { + dev_err(&bg->sd->dev, "Failed to create greybus host device"); + return PTR_ERR(bg->gb_hd); + } + + ret = gb_hd_add(bg->gb_hd); + if (ret) { + dev_err(&bg->sd->dev, "Failed to add greybus host device"); + goto free_gb_hd; + } + dev_set_drvdata(&bg->gb_hd->dev, bg); + + return 0; + +free_gb_hd: + gb_greybus_deinit(bg); + return ret; +} + +static void gb_serdev_deinit(struct gb_beagleplay *bg) +{ + serdev_device_close(bg->sd); +} + +static int gb_serdev_init(struct gb_beagleplay *bg) +{ + int ret; + + serdev_device_set_drvdata(bg->sd, bg); + serdev_device_set_client_ops(bg->sd, &gb_beagleplay_ops); + ret = serdev_device_open(bg->sd); + if (ret) + return dev_err_probe(&bg->sd->dev, ret, "Unable to open serial device"); + + serdev_device_set_baudrate(bg->sd, 115200); + serdev_device_set_flow_control(bg->sd, false); + + return 0; +} + +static int gb_beagleplay_probe(struct serdev_device *serdev) +{ + int ret = 0; + struct gb_beagleplay *bg; + + bg = devm_kmalloc(&serdev->dev, sizeof(*bg), GFP_KERNEL); + if (!bg) + return -ENOMEM; + + bg->sd = serdev; + ret = gb_serdev_init(bg); + if (ret) + return ret; + + ret = hdlc_init(bg); + if (ret) + goto free_serdev; + + ret = gb_greybus_init(bg); + if (ret) + goto free_hdlc; + + gb_beagleplay_start_svc(bg); + + return 0; + +free_hdlc: + hdlc_deinit(bg); +free_serdev: + gb_serdev_deinit(bg); + return ret; +} + +static void gb_beagleplay_remove(struct serdev_device *serdev) +{ + struct gb_beagleplay *bg = serdev_device_get_drvdata(serdev); + + gb_greybus_deinit(bg); + gb_beagleplay_stop_svc(bg); + hdlc_deinit(bg); + gb_serdev_deinit(bg); +} + +static const struct of_device_id gb_beagleplay_of_match[] = { + { + .compatible = "ti,cc1352p7", + }, + {}, +}; +MODULE_DEVICE_TABLE(of, gb_beagleplay_of_match); + +static struct serdev_device_driver gb_beagleplay_driver = { + .probe = gb_beagleplay_probe, + .remove = gb_beagleplay_remove, + .driver = { + .name = "gb_beagleplay", + .of_match_table = gb_beagleplay_of_match, + }, +}; + +module_serdev_device_driver(gb_beagleplay_driver); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Ayush Singh "); +MODULE_DESCRIPTION("A Greybus driver for BeaglePlay"); From c40e66539051158e1c9fdc4cf18babe3a7b34e8e Mon Sep 17 00:00:00 2001 From: Ayush Singh Date: Tue, 17 Oct 2023 15:41:14 +0530 Subject: [PATCH 319/326] dts: ti: k3-am625-beagleplay: Add beaglecc1352 The BeaglePlay board by BeagleBoard.org has a CC1352P7 co-processor connected to the main AM62 (running Linux) over UART. In the BeagleConnect Technology, CC1352 is responsible for handling 6LoWPAN communication with beagleconnect freedom nodes as well as their discovery. This mcu is used by gb-beagleplay, a Greybus driver for BeaglePlay. Signed-off-by: Ayush Singh Link: https://lore.kernel.org/r/20231017101116.178041-4-ayushdevel1325@gmail.com Signed-off-by: Greg Kroah-Hartman --- arch/arm64/boot/dts/ti/k3-am625-beagleplay.dts | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/arch/arm64/boot/dts/ti/k3-am625-beagleplay.dts b/arch/arm64/boot/dts/ti/k3-am625-beagleplay.dts index 7cfdf562b53b..d2e0b11242b6 100644 --- a/arch/arm64/boot/dts/ti/k3-am625-beagleplay.dts +++ b/arch/arm64/boot/dts/ti/k3-am625-beagleplay.dts @@ -870,6 +870,12 @@ pinctrl-names = "default"; pinctrl-0 = <&wifi_debug_uart_pins_default>; status = "okay"; + + mcu { + compatible = "ti,cc1352p7"; + reset-gpios = <&main_gpio0 72 GPIO_ACTIVE_LOW>; + vdds-supply = <&vdd_3v3>; + }; }; &dss { From 54b406e10f0334ee0245d5129c8def444a49cd9b Mon Sep 17 00:00:00 2001 From: Abhijit Gangurde Date: Tue, 17 Oct 2023 21:34:59 +0530 Subject: [PATCH 320/326] cdx: Remove cdx controller list from cdx bus system Remove xarray list of cdx controller. Instead, use platform bus to locate the cdx controller using compat string used by cdx controller platform driver. Also, use ida to allocate a unique id for the controller. Signed-off-by: Abhijit Gangurde Link: https://lore.kernel.org/r/20231017160505.10640-2-abhijit.gangurde@amd.com Signed-off-by: Greg Kroah-Hartman --- drivers/cdx/cdx.c | 42 ++++++++++++++++++++++++------------- include/linux/cdx/cdx_bus.h | 2 ++ 2 files changed, 30 insertions(+), 14 deletions(-) diff --git a/drivers/cdx/cdx.c b/drivers/cdx/cdx.c index d2cad4c670a0..0252fc92433d 100644 --- a/drivers/cdx/cdx.c +++ b/drivers/cdx/cdx.c @@ -60,7 +60,7 @@ #include #include #include -#include +#include #include #include #include @@ -70,8 +70,10 @@ #define CDX_DEFAULT_DMA_MASK (~0ULL) #define MAX_CDX_CONTROLLERS 16 -/* CDX controllers registered with the CDX bus */ -static DEFINE_XARRAY_ALLOC(cdx_controllers); +/* IDA for CDX controllers registered with the CDX bus */ +static DEFINE_IDA(cdx_controller_ida); + +static char *compat_node_name = "xlnx,versal-net-cdx"; /** * cdx_dev_reset - Reset a CDX device @@ -384,7 +386,8 @@ static ssize_t rescan_store(const struct bus_type *bus, const char *buf, size_t count) { struct cdx_controller *cdx; - unsigned long index; + struct platform_device *pd; + struct device_node *np; bool val; if (kstrtobool(buf, &val) < 0) @@ -397,12 +400,19 @@ static ssize_t rescan_store(const struct bus_type *bus, cdx_unregister_devices(&cdx_bus_type); /* Rescan all the devices */ - xa_for_each(&cdx_controllers, index, cdx) { - int ret; + for_each_compatible_node(np, NULL, compat_node_name) { + if (!np) + return -EINVAL; - ret = cdx->ops->scan(cdx); - if (ret) - dev_err(cdx->dev, "cdx bus scanning failed\n"); + pd = of_find_device_by_node(np); + if (!pd) + return -EINVAL; + + cdx = platform_get_drvdata(pd); + if (cdx && cdx->controller_registered && cdx->ops->scan) + cdx->ops->scan(cdx); + + put_device(&pd->dev); } return count; @@ -520,17 +530,20 @@ int cdx_register_controller(struct cdx_controller *cdx) { int ret; - ret = xa_alloc(&cdx_controllers, &cdx->id, cdx, - XA_LIMIT(0, MAX_CDX_CONTROLLERS - 1), GFP_KERNEL); - if (ret) { + ret = ida_alloc_range(&cdx_controller_ida, 0, MAX_CDX_CONTROLLERS - 1, GFP_KERNEL); + if (ret < 0) { dev_err(cdx->dev, "No free index available. Maximum controllers already registered\n"); cdx->id = (u8)MAX_CDX_CONTROLLERS; return ret; } + cdx->id = ret; + /* Scan all the devices */ - cdx->ops->scan(cdx); + if (cdx->ops->scan) + cdx->ops->scan(cdx); + cdx->controller_registered = true; return 0; } @@ -541,8 +554,9 @@ void cdx_unregister_controller(struct cdx_controller *cdx) if (cdx->id >= MAX_CDX_CONTROLLERS) return; + cdx->controller_registered = false; device_for_each_child(cdx->dev, NULL, cdx_unregister_device); - xa_erase(&cdx_controllers, cdx->id); + ida_free(&cdx_controller_ida, cdx->id); } EXPORT_SYMBOL_GPL(cdx_unregister_controller); diff --git a/include/linux/cdx/cdx_bus.h b/include/linux/cdx/cdx_bus.h index bead71b7bc73..82c27b8c94e1 100644 --- a/include/linux/cdx/cdx_bus.h +++ b/include/linux/cdx/cdx_bus.h @@ -63,12 +63,14 @@ struct cdx_ops { * @dev: Linux device associated with the CDX controller. * @priv: private data * @id: Controller ID + * @controller_registered: controller registered with bus * @ops: CDX controller ops */ struct cdx_controller { struct device *dev; void *priv; u32 id; + bool controller_registered; struct cdx_ops *ops; }; From f0af816834667b626dc5a3aa09cced82c46f0e62 Mon Sep 17 00:00:00 2001 From: Abhijit Gangurde Date: Tue, 17 Oct 2023 21:35:00 +0530 Subject: [PATCH 321/326] cdx: Introduce lock to protect controller ops Add a mutex lock to prevent race between controller ops initiated by the bus subsystem and the controller registration/unregistration. Signed-off-by: Abhijit Gangurde Link: https://lore.kernel.org/r/20231017160505.10640-3-abhijit.gangurde@amd.com Signed-off-by: Greg Kroah-Hartman --- drivers/cdx/cdx.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/drivers/cdx/cdx.c b/drivers/cdx/cdx.c index 0252fc92433d..75760388f5e7 100644 --- a/drivers/cdx/cdx.c +++ b/drivers/cdx/cdx.c @@ -72,6 +72,8 @@ /* IDA for CDX controllers registered with the CDX bus */ static DEFINE_IDA(cdx_controller_ida); +/* Lock to protect controller ops */ +static DEFINE_MUTEX(cdx_controller_lock); static char *compat_node_name = "xlnx,versal-net-cdx"; @@ -396,6 +398,8 @@ static ssize_t rescan_store(const struct bus_type *bus, if (!val) return -EINVAL; + mutex_lock(&cdx_controller_lock); + /* Unregister all the devices on the bus */ cdx_unregister_devices(&cdx_bus_type); @@ -415,6 +419,8 @@ static ssize_t rescan_store(const struct bus_type *bus, put_device(&pd->dev); } + mutex_unlock(&cdx_controller_lock); + return count; } static BUS_ATTR_WO(rescan); @@ -538,12 +544,14 @@ int cdx_register_controller(struct cdx_controller *cdx) return ret; } + mutex_lock(&cdx_controller_lock); cdx->id = ret; /* Scan all the devices */ if (cdx->ops->scan) cdx->ops->scan(cdx); cdx->controller_registered = true; + mutex_unlock(&cdx_controller_lock); return 0; } @@ -554,9 +562,13 @@ void cdx_unregister_controller(struct cdx_controller *cdx) if (cdx->id >= MAX_CDX_CONTROLLERS) return; + mutex_lock(&cdx_controller_lock); + cdx->controller_registered = false; device_for_each_child(cdx->dev, NULL, cdx_unregister_device); ida_free(&cdx_controller_ida, cdx->id); + + mutex_unlock(&cdx_controller_lock); } EXPORT_SYMBOL_GPL(cdx_unregister_controller); From e3ed12f37e261a0b35cf0b4ae505adf7ea0f48ec Mon Sep 17 00:00:00 2001 From: Abhijit Gangurde Date: Tue, 17 Oct 2023 21:35:01 +0530 Subject: [PATCH 322/326] cdx: Create symbol namespaces for cdx subsystem Create CDX_BUS and CDX_BUS_CONTROLLER symbol namespace for cdx bus subsystem. CDX controller modules are required to import symbols from CDX_BUS_CONTROLLER namespace and other than controller modules to import from CDX_BUS namespace. Signed-off-by: Abhijit Gangurde Link: https://lore.kernel.org/r/20231017160505.10640-4-abhijit.gangurde@amd.com Signed-off-by: Greg Kroah-Hartman --- drivers/cdx/Makefile | 2 ++ drivers/cdx/cdx.c | 6 +++--- drivers/cdx/controller/cdx_controller.c | 1 + drivers/vfio/cdx/main.c | 1 + 4 files changed, 7 insertions(+), 3 deletions(-) diff --git a/drivers/cdx/Makefile b/drivers/cdx/Makefile index 0324e4914f6e..5d1ea482419f 100644 --- a/drivers/cdx/Makefile +++ b/drivers/cdx/Makefile @@ -5,4 +5,6 @@ # Copyright (C) 2022-2023, Advanced Micro Devices, Inc. # +ccflags-y += -DDEFAULT_SYMBOL_NAMESPACE=CDX_BUS + obj-$(CONFIG_CDX_BUS) += cdx.o controller/ diff --git a/drivers/cdx/cdx.c b/drivers/cdx/cdx.c index 75760388f5e7..ee0913f04758 100644 --- a/drivers/cdx/cdx.c +++ b/drivers/cdx/cdx.c @@ -530,7 +530,7 @@ fail: return ret; } -EXPORT_SYMBOL_GPL(cdx_device_add); +EXPORT_SYMBOL_NS_GPL(cdx_device_add, CDX_BUS_CONTROLLER); int cdx_register_controller(struct cdx_controller *cdx) { @@ -555,7 +555,7 @@ int cdx_register_controller(struct cdx_controller *cdx) return 0; } -EXPORT_SYMBOL_GPL(cdx_register_controller); +EXPORT_SYMBOL_NS_GPL(cdx_register_controller, CDX_BUS_CONTROLLER); void cdx_unregister_controller(struct cdx_controller *cdx) { @@ -570,7 +570,7 @@ void cdx_unregister_controller(struct cdx_controller *cdx) mutex_unlock(&cdx_controller_lock); } -EXPORT_SYMBOL_GPL(cdx_unregister_controller); +EXPORT_SYMBOL_NS_GPL(cdx_unregister_controller, CDX_BUS_CONTROLLER); static int __init cdx_bus_init(void) { diff --git a/drivers/cdx/controller/cdx_controller.c b/drivers/cdx/controller/cdx_controller.c index bb4ae7970e21..3f86663fbacf 100644 --- a/drivers/cdx/controller/cdx_controller.c +++ b/drivers/cdx/controller/cdx_controller.c @@ -229,3 +229,4 @@ module_exit(cdx_controller_exit); MODULE_AUTHOR("AMD Inc."); MODULE_DESCRIPTION("CDX controller for AMD devices"); MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS(CDX_BUS_CONTROLLER); diff --git a/drivers/vfio/cdx/main.c b/drivers/vfio/cdx/main.c index de56686581ae..b3e482fa717b 100644 --- a/drivers/vfio/cdx/main.c +++ b/drivers/vfio/cdx/main.c @@ -231,3 +231,4 @@ module_driver(vfio_cdx_driver, cdx_driver_register, cdx_driver_unregister); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("VFIO for CDX devices - User Level meta-driver"); +MODULE_IMPORT_NS(CDX_BUS); From ce558a391d80b9f47a462107977e8e81fe2f2962 Mon Sep 17 00:00:00 2001 From: Abhijit Gangurde Date: Tue, 17 Oct 2023 21:35:02 +0530 Subject: [PATCH 323/326] cdx: Register cdx bus as a device on cdx subsystem While scanning for CDX devices, register newly discovered bus as a cdx device. CDX device attributes are visible based on device type. Signed-off-by: Abhijit Gangurde Link: https://lore.kernel.org/r/20231017160505.10640-5-abhijit.gangurde@amd.com Signed-off-by: Greg Kroah-Hartman --- drivers/cdx/cdx.c | 77 +++++++++++++++++++++++-- drivers/cdx/cdx.h | 14 ++++- drivers/cdx/controller/cdx_controller.c | 7 +++ include/linux/cdx/cdx_bus.h | 2 + 4 files changed, 93 insertions(+), 7 deletions(-) diff --git a/drivers/cdx/cdx.c b/drivers/cdx/cdx.c index ee0913f04758..cf5306580c21 100644 --- a/drivers/cdx/cdx.c +++ b/drivers/cdx/cdx.c @@ -125,8 +125,13 @@ static int cdx_unregister_device(struct device *dev, { struct cdx_device *cdx_dev = to_cdx_device(dev); - kfree(cdx_dev->driver_override); - cdx_dev->driver_override = NULL; + if (cdx_dev->is_bus) { + device_for_each_child(dev, NULL, cdx_unregister_device); + } else { + kfree(cdx_dev->driver_override); + cdx_dev->driver_override = NULL; + } + /* * Do not free cdx_dev here as it would be freed in * cdx_device_release() called from within put_device(). @@ -201,6 +206,9 @@ static int cdx_bus_match(struct device *dev, struct device_driver *drv) const struct cdx_device_id *found_id = NULL; const struct cdx_device_id *ids; + if (cdx_dev->is_bus) + return false; + ids = cdx_drv->match_id_table; /* When driver_override is set, only bind to the matching driver */ @@ -265,10 +273,11 @@ static int cdx_dma_configure(struct device *dev) { struct cdx_driver *cdx_drv = to_cdx_driver(dev->driver); struct cdx_device *cdx_dev = to_cdx_device(dev); + struct cdx_controller *cdx = cdx_dev->cdx; u32 input_id = cdx_dev->req_id; int ret; - ret = of_dma_configure_id(dev, dev->parent->of_node, 0, &input_id); + ret = of_dma_configure_id(dev, cdx->dev->of_node, 0, &input_id); if (ret && ret != -EPROBE_DEFER) { dev_err(dev, "of_dma_configure_id() failed\n"); return ret; @@ -374,6 +383,18 @@ static ssize_t driver_override_show(struct device *dev, } static DEVICE_ATTR_RW(driver_override); +static umode_t cdx_dev_attrs_are_visible(struct kobject *kobj, struct attribute *a, int n) +{ + struct device *dev = kobj_to_dev(kobj); + struct cdx_device *cdx_dev; + + cdx_dev = to_cdx_device(dev); + if (!cdx_dev->is_bus) + return a->mode; + + return 0; +} + static struct attribute *cdx_dev_attrs[] = { &dev_attr_remove.attr, &dev_attr_reset.attr, @@ -382,7 +403,16 @@ static struct attribute *cdx_dev_attrs[] = { &dev_attr_driver_override.attr, NULL, }; -ATTRIBUTE_GROUPS(cdx_dev); + +static const struct attribute_group cdx_dev_group = { + .attrs = cdx_dev_attrs, + .is_visible = cdx_dev_attrs_are_visible, +}; + +static const struct attribute_group *cdx_dev_groups[] = { + &cdx_dev_group, + NULL, +}; static ssize_t rescan_store(const struct bus_type *bus, const char *buf, size_t count) @@ -479,7 +509,6 @@ static void cdx_device_release(struct device *dev) int cdx_device_add(struct cdx_dev_params *dev_params) { struct cdx_controller *cdx = dev_params->cdx; - struct device *parent = cdx->dev; struct cdx_device *cdx_dev; int ret; @@ -503,7 +532,7 @@ int cdx_device_add(struct cdx_dev_params *dev_params) /* Initialize generic device */ device_initialize(&cdx_dev->dev); - cdx_dev->dev.parent = parent; + cdx_dev->dev.parent = dev_params->parent; cdx_dev->dev.bus = &cdx_bus_type; cdx_dev->dev.dma_mask = &cdx_dev->dma_mask; cdx_dev->dev.release = cdx_device_release; @@ -532,6 +561,42 @@ fail: } EXPORT_SYMBOL_NS_GPL(cdx_device_add, CDX_BUS_CONTROLLER); +struct device *cdx_bus_add(struct cdx_controller *cdx, u8 bus_num) +{ + struct cdx_device *cdx_dev; + int ret; + + cdx_dev = kzalloc(sizeof(*cdx_dev), GFP_KERNEL); + if (!cdx_dev) + return NULL; + + device_initialize(&cdx_dev->dev); + cdx_dev->cdx = cdx; + + cdx_dev->dev.parent = cdx->dev; + cdx_dev->dev.bus = &cdx_bus_type; + cdx_dev->dev.release = cdx_device_release; + cdx_dev->is_bus = true; + cdx_dev->bus_num = bus_num; + + dev_set_name(&cdx_dev->dev, "cdx-%02x", + ((cdx->id << CDX_CONTROLLER_ID_SHIFT) | (bus_num & CDX_BUS_NUM_MASK))); + + ret = device_add(&cdx_dev->dev); + if (ret) { + dev_err(&cdx_dev->dev, "cdx bus device add failed: %d\n", ret); + goto device_add_fail; + } + + return &cdx_dev->dev; + +device_add_fail: + put_device(&cdx_dev->dev); + + return NULL; +} +EXPORT_SYMBOL_NS_GPL(cdx_bus_add, CDX_BUS_CONTROLLER); + int cdx_register_controller(struct cdx_controller *cdx) { int ret; diff --git a/drivers/cdx/cdx.h b/drivers/cdx/cdx.h index c436ac7ac86f..1f593deb4c9e 100644 --- a/drivers/cdx/cdx.h +++ b/drivers/cdx/cdx.h @@ -13,7 +13,7 @@ /** * struct cdx_dev_params - CDX device parameters * @cdx: CDX controller associated with the device - * @parent: Associated CDX controller + * @parent: Associated CDX Bus device * @vendor: Vendor ID for CDX device * @device: Device ID for CDX device * @bus_num: Bus number for this CDX device @@ -24,6 +24,7 @@ */ struct cdx_dev_params { struct cdx_controller *cdx; + struct device *parent; u16 vendor; u16 device; u8 bus_num; @@ -59,4 +60,15 @@ void cdx_unregister_controller(struct cdx_controller *cdx); */ int cdx_device_add(struct cdx_dev_params *dev_params); +/** + * cdx_bus_add - Add a CDX bus. This function adds a bus on the CDX bus + * subsystem. It creates a CDX device for the corresponding bus and + * also registers an associated Linux generic device. + * @cdx: Associated CDX controller + * @us_num: Bus number + * + * Return: associated Linux generic device pointer on success or NULL on failure. + */ +struct device *cdx_bus_add(struct cdx_controller *cdx, u8 bus_num); + #endif /* _CDX_H_ */ diff --git a/drivers/cdx/controller/cdx_controller.c b/drivers/cdx/controller/cdx_controller.c index 3f86663fbacf..b4e0d6b40339 100644 --- a/drivers/cdx/controller/cdx_controller.c +++ b/drivers/cdx/controller/cdx_controller.c @@ -79,8 +79,14 @@ static int cdx_scan_devices(struct cdx_controller *cdx) num_cdx_bus = (u8)ret; for (bus_num = 0; bus_num < num_cdx_bus; bus_num++) { + struct device *bus_dev; u8 num_cdx_dev; + /* Add the bus on cdx subsystem */ + bus_dev = cdx_bus_add(cdx, bus_num); + if (!bus_dev) + continue; + /* MCDI FW Read: Fetch the number of devices present */ ret = cdx_mcdi_get_num_devs(cdx_mcdi, bus_num); if (ret < 0) { @@ -103,6 +109,7 @@ static int cdx_scan_devices(struct cdx_controller *cdx) continue; } dev_params.cdx = cdx; + dev_params.parent = bus_dev; /* Add the device to the cdx bus */ ret = cdx_device_add(&dev_params); diff --git a/include/linux/cdx/cdx_bus.h b/include/linux/cdx/cdx_bus.h index 82c27b8c94e1..b5e4b7e05666 100644 --- a/include/linux/cdx/cdx_bus.h +++ b/include/linux/cdx/cdx_bus.h @@ -88,6 +88,7 @@ struct cdx_controller { * @dma_mask: Default DMA mask * @flags: CDX device flags * @req_id: Requestor ID associated with CDX device + * @is_bus: Is this bus device * @driver_override: driver name to force a match; do not set directly, * because core frees it; use driver_set_override() to * set or clear it. @@ -104,6 +105,7 @@ struct cdx_device { u64 dma_mask; u16 flags; u32 req_id; + bool is_bus; const char *driver_override; }; From e3cfd49cb9491ac1cc233a4b9e098688b4ab281d Mon Sep 17 00:00:00 2001 From: Abhijit Gangurde Date: Tue, 17 Oct 2023 21:35:03 +0530 Subject: [PATCH 324/326] cdx: add support for bus enable and disable CDX bus needs to be disabled before updating/writing devices in the FPGA. Once the devices are written, the bus shall be rescanned. This change provides sysfs entry to enable/disable the CDX bus. Co-developed-by: Nipun Gupta Signed-off-by: Nipun Gupta Signed-off-by: Abhijit Gangurde Link: https://lore.kernel.org/r/20231017160505.10640-6-abhijit.gangurde@amd.com Signed-off-by: Greg Kroah-Hartman --- Documentation/ABI/testing/sysfs-bus-cdx | 13 +++++ drivers/cdx/cdx.c | 72 +++++++++++++++++++++++++ drivers/cdx/controller/cdx_controller.c | 12 +++++ drivers/cdx/controller/mc_cdx_pcol.h | 54 +++++++++++++++++++ drivers/cdx/controller/mcdi_functions.c | 24 +++++++++ drivers/cdx/controller/mcdi_functions.h | 18 +++++++ include/linux/cdx/cdx_bus.h | 10 ++++ 7 files changed, 203 insertions(+) diff --git a/Documentation/ABI/testing/sysfs-bus-cdx b/Documentation/ABI/testing/sysfs-bus-cdx index 7af477f49998..c12bdaa4152a 100644 --- a/Documentation/ABI/testing/sysfs-bus-cdx +++ b/Documentation/ABI/testing/sysfs-bus-cdx @@ -28,6 +28,19 @@ Description: of a device manufacturer. Combination of Vendor ID and Device ID identifies a device. +What: /sys/bus/cdx/devices/.../enable +Date: October 2023 +Contact: abhijit.gangurde@amd.com +Description: + CDX bus should be disabled before updating the devices in FPGA. + Writing n/0/off will attempt to disable the CDX bus and. + writing y/1/on will attempt to enable the CDX bus. Reading this file + gives the current state of the bus, 1 for enabled and 0 for disabled. + + For example:: + + # echo 1 > /sys/bus/cdx/.../enable + What: /sys/bus/cdx/devices/.../reset Date: March 2023 Contact: nipun.gupta@amd.com diff --git a/drivers/cdx/cdx.c b/drivers/cdx/cdx.c index cf5306580c21..8eb484c37e97 100644 --- a/drivers/cdx/cdx.c +++ b/drivers/cdx/cdx.c @@ -124,9 +124,12 @@ static int cdx_unregister_device(struct device *dev, void *data) { struct cdx_device *cdx_dev = to_cdx_device(dev); + struct cdx_controller *cdx = cdx_dev->cdx; if (cdx_dev->is_bus) { device_for_each_child(dev, NULL, cdx_unregister_device); + if (cdx_dev->enabled && cdx->ops->bus_disable) + cdx->ops->bus_disable(cdx, cdx_dev->bus_num); } else { kfree(cdx_dev->driver_override); cdx_dev->driver_override = NULL; @@ -383,6 +386,41 @@ static ssize_t driver_override_show(struct device *dev, } static DEVICE_ATTR_RW(driver_override); +static ssize_t enable_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct cdx_device *cdx_dev = to_cdx_device(dev); + struct cdx_controller *cdx = cdx_dev->cdx; + bool enable; + int ret; + + if (kstrtobool(buf, &enable) < 0) + return -EINVAL; + + if (enable == cdx_dev->enabled) + return count; + + if (enable && cdx->ops->bus_enable) + ret = cdx->ops->bus_enable(cdx, cdx_dev->bus_num); + else if (!enable && cdx->ops->bus_disable) + ret = cdx->ops->bus_disable(cdx, cdx_dev->bus_num); + else + ret = -EOPNOTSUPP; + + if (!ret) + cdx_dev->enabled = enable; + + return ret < 0 ? ret : count; +} + +static ssize_t enable_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct cdx_device *cdx_dev = to_cdx_device(dev); + + return sysfs_emit(buf, "%u\n", cdx_dev->enabled); +} +static DEVICE_ATTR_RW(enable); + static umode_t cdx_dev_attrs_are_visible(struct kobject *kobj, struct attribute *a, int n) { struct device *dev = kobj_to_dev(kobj); @@ -395,6 +433,18 @@ static umode_t cdx_dev_attrs_are_visible(struct kobject *kobj, struct attribute return 0; } +static umode_t cdx_bus_attrs_are_visible(struct kobject *kobj, struct attribute *a, int n) +{ + struct device *dev = kobj_to_dev(kobj); + struct cdx_device *cdx_dev; + + cdx_dev = to_cdx_device(dev); + if (cdx_dev->is_bus) + return a->mode; + + return 0; +} + static struct attribute *cdx_dev_attrs[] = { &dev_attr_remove.attr, &dev_attr_reset.attr, @@ -409,8 +459,19 @@ static const struct attribute_group cdx_dev_group = { .is_visible = cdx_dev_attrs_are_visible, }; +static struct attribute *cdx_bus_dev_attrs[] = { + &dev_attr_enable.attr, + NULL, +}; + +static const struct attribute_group cdx_bus_dev_group = { + .attrs = cdx_bus_dev_attrs, + .is_visible = cdx_bus_attrs_are_visible, +}; + static const struct attribute_group *cdx_dev_groups[] = { &cdx_dev_group, + &cdx_bus_dev_group, NULL, }; @@ -588,8 +649,19 @@ struct device *cdx_bus_add(struct cdx_controller *cdx, u8 bus_num) goto device_add_fail; } + if (cdx->ops->bus_enable) { + ret = cdx->ops->bus_enable(cdx, bus_num); + if (ret && ret != -EALREADY) { + dev_err(cdx->dev, "cdx bus enable failed: %d\n", ret); + goto bus_enable_fail; + } + } + + cdx_dev->enabled = true; return &cdx_dev->dev; +bus_enable_fail: + device_del(&cdx_dev->dev); device_add_fail: put_device(&cdx_dev->dev); diff --git a/drivers/cdx/controller/cdx_controller.c b/drivers/cdx/controller/cdx_controller.c index b4e0d6b40339..f2a691efd1f1 100644 --- a/drivers/cdx/controller/cdx_controller.c +++ b/drivers/cdx/controller/cdx_controller.c @@ -33,6 +33,16 @@ static const struct cdx_mcdi_ops mcdi_ops = { .mcdi_request = cdx_mcdi_request, }; +static int cdx_bus_enable(struct cdx_controller *cdx, u8 bus_num) +{ + return cdx_mcdi_bus_enable(cdx->priv, bus_num); +} + +static int cdx_bus_disable(struct cdx_controller *cdx, u8 bus_num) +{ + return cdx_mcdi_bus_disable(cdx->priv, bus_num); +} + void cdx_rpmsg_post_probe(struct cdx_controller *cdx) { /* Register CDX controller with CDX bus driver */ @@ -128,6 +138,8 @@ static int cdx_scan_devices(struct cdx_controller *cdx) } static struct cdx_ops cdx_ops = { + .bus_enable = cdx_bus_enable, + .bus_disable = cdx_bus_disable, .scan = cdx_scan_devices, .dev_configure = cdx_configure_device, }; diff --git a/drivers/cdx/controller/mc_cdx_pcol.h b/drivers/cdx/controller/mc_cdx_pcol.h index 4ccb7b52951b..2de019406b57 100644 --- a/drivers/cdx/controller/mc_cdx_pcol.h +++ b/drivers/cdx/controller/mc_cdx_pcol.h @@ -455,6 +455,60 @@ #define MC_CMD_CDX_BUS_GET_DEVICE_CONFIG_OUT_REQUESTER_ID_OFST 84 #define MC_CMD_CDX_BUS_GET_DEVICE_CONFIG_OUT_REQUESTER_ID_LEN 4 +/***********************************/ +/* + * MC_CMD_CDX_BUS_DOWN + * Asserting reset on the CDX bus causes all devices on the bus to be quiesced. + * DMA bus mastering is disabled and any pending DMA request are flushed. Once + * the response is returned, the devices are guaranteed to no longer issue DMA + * requests or raise MSI interrupts. Further device MMIO accesses may have + * undefined results. While the bus reset is asserted, any of the enumeration + * or device configuration MCDIs will fail with EAGAIN. It is only legal to + * reload the relevant PL region containing CDX devices if the corresponding CDX + * bus is in reset. Depending on the implementation, the firmware may or may + * not enforce this restriction and it is up to the caller to make sure this + * requirement is satisfied. + */ +#define MC_CMD_CDX_BUS_DOWN 0x4 +#define MC_CMD_CDX_BUS_DOWN_MSGSET 0x4 + +/* MC_CMD_CDX_BUS_DOWN_IN msgrequest */ +#define MC_CMD_CDX_BUS_DOWN_IN_LEN 4 +/* Bus number to put in reset, in range 0 to BUS_COUNT-1 */ +#define MC_CMD_CDX_BUS_DOWN_IN_BUS_OFST 0 +#define MC_CMD_CDX_BUS_DOWN_IN_BUS_LEN 4 + +/* + * MC_CMD_CDX_BUS_DOWN_OUT msgresponse: The bus is quiesced, no further + * upstream traffic for devices on this bus. + */ +#define MC_CMD_CDX_BUS_DOWN_OUT_LEN 0 + +/***********************************/ +/* + * MC_CMD_CDX_BUS_UP + * After bus reset is de-asserted, devices are in a state which is functionally + * equivalent to each device having been reset with MC_CMD_CDX_DEVICE_RESET. In + * other words, device logic is reset in a hardware-specific way, MMIO accesses + * are forwarded to the device, DMA bus mastering is disabled and needs to be + * re-enabled with MC_CMD_CDX_DEVICE_DMA_ENABLE once the driver is ready to + * start servicing DMA. If the underlying number of devices or device resources + * changed (e.g. if PL was reloaded) while the bus was in reset, the bus driver + * is expected to re-enumerate the bus. Returns EALREADY if the bus was already + * up before the call. + */ +#define MC_CMD_CDX_BUS_UP 0x5 +#define MC_CMD_CDX_BUS_UP_MSGSET 0x5 + +/* MC_CMD_CDX_BUS_UP_IN msgrequest */ +#define MC_CMD_CDX_BUS_UP_IN_LEN 4 +/* Bus number to take out of reset, in range 0 to BUS_COUNT-1 */ +#define MC_CMD_CDX_BUS_UP_IN_BUS_OFST 0 +#define MC_CMD_CDX_BUS_UP_IN_BUS_LEN 4 + +/* MC_CMD_CDX_BUS_UP_OUT msgresponse: The bus can now be enumerated. */ +#define MC_CMD_CDX_BUS_UP_OUT_LEN 0 + /***********************************/ /* * MC_CMD_CDX_DEVICE_RESET diff --git a/drivers/cdx/controller/mcdi_functions.c b/drivers/cdx/controller/mcdi_functions.c index 0158f26533dd..0e1e35d91242 100644 --- a/drivers/cdx/controller/mcdi_functions.c +++ b/drivers/cdx/controller/mcdi_functions.c @@ -124,6 +124,30 @@ int cdx_mcdi_get_dev_config(struct cdx_mcdi *cdx, return 0; } +int cdx_mcdi_bus_enable(struct cdx_mcdi *cdx, u8 bus_num) +{ + MCDI_DECLARE_BUF(inbuf, MC_CMD_CDX_BUS_UP_IN_LEN); + int ret; + + MCDI_SET_DWORD(inbuf, CDX_BUS_UP_IN_BUS, bus_num); + ret = cdx_mcdi_rpc(cdx, MC_CMD_CDX_BUS_UP, inbuf, sizeof(inbuf), + NULL, 0, NULL); + + return ret; +} + +int cdx_mcdi_bus_disable(struct cdx_mcdi *cdx, u8 bus_num) +{ + MCDI_DECLARE_BUF(inbuf, MC_CMD_CDX_BUS_DOWN_IN_LEN); + int ret; + + MCDI_SET_DWORD(inbuf, CDX_BUS_DOWN_IN_BUS, bus_num); + ret = cdx_mcdi_rpc(cdx, MC_CMD_CDX_BUS_DOWN, inbuf, sizeof(inbuf), + NULL, 0, NULL); + + return ret; +} + int cdx_mcdi_reset_device(struct cdx_mcdi *cdx, u8 bus_num, u8 dev_num) { MCDI_DECLARE_BUF(inbuf, MC_CMD_CDX_DEVICE_RESET_IN_LEN); diff --git a/drivers/cdx/controller/mcdi_functions.h b/drivers/cdx/controller/mcdi_functions.h index 7440ace5539a..28973d5ec3ab 100644 --- a/drivers/cdx/controller/mcdi_functions.h +++ b/drivers/cdx/controller/mcdi_functions.h @@ -47,6 +47,24 @@ int cdx_mcdi_get_dev_config(struct cdx_mcdi *cdx, u8 bus_num, u8 dev_num, struct cdx_dev_params *dev_params); +/** + * cdx_mcdi_bus_enable - Enable CDX bus represented by bus_num + * @cdx: pointer to MCDI interface. + * @bus_num: Bus number. + * + * Return: 0 on success, <0 on failure + */ +int cdx_mcdi_bus_enable(struct cdx_mcdi *cdx, u8 bus_num); + +/** + * cdx_mcdi_bus_disable - Disable CDX bus represented by bus_num + * @cdx: pointer to MCDI interface. + * @bus_num: Bus number. + * + * Return: 0 on success, <0 on failure + */ +int cdx_mcdi_bus_disable(struct cdx_mcdi *cdx, u8 bus_num); + /** * cdx_mcdi_reset_device - Reset cdx device represented by bus_num:dev_num * @cdx: pointer to MCDI interface. diff --git a/include/linux/cdx/cdx_bus.h b/include/linux/cdx/cdx_bus.h index b5e4b7e05666..18e95076d1d5 100644 --- a/include/linux/cdx/cdx_bus.h +++ b/include/linux/cdx/cdx_bus.h @@ -28,6 +28,10 @@ struct cdx_device_config { u8 type; }; +typedef int (*cdx_bus_enable_cb)(struct cdx_controller *cdx, u8 bus_num); + +typedef int (*cdx_bus_disable_cb)(struct cdx_controller *cdx, u8 bus_num); + typedef int (*cdx_scan_cb)(struct cdx_controller *cdx); typedef int (*cdx_dev_configure_cb)(struct cdx_controller *cdx, @@ -49,11 +53,15 @@ typedef int (*cdx_dev_configure_cb)(struct cdx_controller *cdx, /** * struct cdx_ops - Callbacks supported by CDX controller. + * @bus_enable: enable bus on the controller + * @bus_disable: disable bus on the controller * @scan: scan the devices on the controller * @dev_configure: configuration like reset, master_enable, * msi_config etc for a CDX device */ struct cdx_ops { + cdx_bus_enable_cb bus_enable; + cdx_bus_disable_cb bus_disable; cdx_scan_cb scan; cdx_dev_configure_cb dev_configure; }; @@ -89,6 +97,7 @@ struct cdx_controller { * @flags: CDX device flags * @req_id: Requestor ID associated with CDX device * @is_bus: Is this bus device + * @enabled: is this bus enabled * @driver_override: driver name to force a match; do not set directly, * because core frees it; use driver_set_override() to * set or clear it. @@ -106,6 +115,7 @@ struct cdx_device { u16 flags; u32 req_id; bool is_bus; + bool enabled; const char *driver_override; }; From 0174f5810401ae6390bfe15354346b5ea660d40c Mon Sep 17 00:00:00 2001 From: Abhijit Gangurde Date: Tue, 17 Oct 2023 21:35:04 +0530 Subject: [PATCH 325/326] cdx: add sysfs for bus reset Add sysfs interface reset to reset all the devices on the CDX bus. Signed-off-by: Abhijit Gangurde Link: https://lore.kernel.org/r/20231017160505.10640-7-abhijit.gangurde@amd.com Signed-off-by: Greg Kroah-Hartman --- Documentation/ABI/testing/sysfs-bus-cdx | 8 ++++---- drivers/cdx/cdx.c | 26 +++++++++++++++++++++---- 2 files changed, 26 insertions(+), 8 deletions(-) diff --git a/Documentation/ABI/testing/sysfs-bus-cdx b/Documentation/ABI/testing/sysfs-bus-cdx index c12bdaa4152a..c2c54abffed5 100644 --- a/Documentation/ABI/testing/sysfs-bus-cdx +++ b/Documentation/ABI/testing/sysfs-bus-cdx @@ -45,10 +45,10 @@ What: /sys/bus/cdx/devices/.../reset Date: March 2023 Contact: nipun.gupta@amd.com Description: - Writing y/1/on to this file resets the CDX device. - On resetting the device, the corresponding driver is notified - twice, once before the device is being reset, and again after - the reset has been complete. + Writing y/1/on to this file resets the CDX device or all devices + on the bus. On resetting the device, the corresponding driver is + notified twice, once before the device is being reset, and again + after the reset has been complete. For example:: diff --git a/drivers/cdx/cdx.c b/drivers/cdx/cdx.c index 8eb484c37e97..e22a7138292e 100644 --- a/drivers/cdx/cdx.c +++ b/drivers/cdx/cdx.c @@ -110,6 +110,20 @@ int cdx_dev_reset(struct device *dev) } EXPORT_SYMBOL_GPL(cdx_dev_reset); +/** + * reset_cdx_device - Reset a CDX device + * @dev: CDX device + * @data: This is always passed as NULL, and is not used in this API, + * but is required here as the device_for_each_child() API expects + * the passed function to have this as an argument. + * + * Return: -errno on failure, 0 on success. + */ +static int reset_cdx_device(struct device *dev, void *data) +{ + return cdx_dev_reset(dev); +} + /** * cdx_unregister_device - Unregister a CDX device * @dev: CDX device @@ -343,6 +357,7 @@ static DEVICE_ATTR_WO(remove); static ssize_t reset_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { + struct cdx_device *cdx_dev = to_cdx_device(dev); bool val; int ret; @@ -352,11 +367,13 @@ static ssize_t reset_store(struct device *dev, struct device_attribute *attr, if (!val) return -EINVAL; - ret = cdx_dev_reset(dev); - if (ret) - return ret; + if (cdx_dev->is_bus) + /* Reset all the devices attached to cdx bus */ + ret = device_for_each_child(dev, NULL, reset_cdx_device); + else + ret = cdx_dev_reset(dev); - return count; + return ret < 0 ? ret : count; } static DEVICE_ATTR_WO(reset); @@ -461,6 +478,7 @@ static const struct attribute_group cdx_dev_group = { static struct attribute *cdx_bus_dev_attrs[] = { &dev_attr_enable.attr, + &dev_attr_reset.attr, NULL, }; From fa10f413091a43f801f82b3cf484f15d6fc9266f Mon Sep 17 00:00:00 2001 From: Abhijit Gangurde Date: Tue, 17 Oct 2023 21:35:05 +0530 Subject: [PATCH 326/326] cdx: add sysfs for subsystem, class and revision CDX controller provides subsystem vendor, subsystem device, class and revision info of the device along with vendor and device ID in native endian format. CDX Bus system uses this information to bind the cdx device to the cdx device driver. Co-developed-by: Puneet Gupta Signed-off-by: Puneet Gupta Co-developed-by: Nipun Gupta Signed-off-by: Nipun Gupta Signed-off-by: Abhijit Gangurde Reviewed-by: Pieter Jansen van Vuuren Tested-by: Nikhil Agarwal Link: https://lore.kernel.org/r/20231017160505.10640-8-abhijit.gangurde@amd.com Signed-off-by: Greg Kroah-Hartman --- Documentation/ABI/testing/sysfs-bus-cdx | 45 +++++++++++++++++++++++++ drivers/cdx/cdx.c | 29 +++++++++++++++- drivers/cdx/cdx.h | 8 +++++ drivers/cdx/controller/mcdi_functions.c | 7 ++++ include/linux/cdx/cdx_bus.h | 27 +++++++++++++-- include/linux/mod_devicetable.h | 10 ++++++ scripts/mod/devicetable-offsets.c | 4 +++ scripts/mod/file2alias.c | 8 +++++ 8 files changed, 135 insertions(+), 3 deletions(-) diff --git a/Documentation/ABI/testing/sysfs-bus-cdx b/Documentation/ABI/testing/sysfs-bus-cdx index c2c54abffed5..8c067ff99e54 100644 --- a/Documentation/ABI/testing/sysfs-bus-cdx +++ b/Documentation/ABI/testing/sysfs-bus-cdx @@ -28,6 +28,36 @@ Description: of a device manufacturer. Combination of Vendor ID and Device ID identifies a device. +What: /sys/bus/cdx/devices/.../subsystem_vendor +Date: July 2023 +Contact: puneet.gupta@amd.com +Description: + Subsystem Vendor ID for this CDX device, in hexadecimal. + Subsystem Vendor ID is 16 bit identifier specific to the + card manufacturer. + +What: /sys/bus/cdx/devices/.../subsystem_device +Date: July 2023 +Contact: puneet.gupta@amd.com +Description: + Subsystem Device ID for this CDX device, in hexadecimal + Subsystem Device ID is 16 bit identifier specific to the + card manufacturer. + +What: /sys/bus/cdx/devices/.../class +Date: July 2023 +Contact: puneet.gupta@amd.com +Description: + This file contains the class of the CDX device, in hexadecimal. + Class is 24 bit identifier specifies the functionality of the device. + +What: /sys/bus/cdx/devices/.../revision +Date: July 2023 +Contact: puneet.gupta@amd.com +Description: + This file contains the revision field of the CDX device, in hexadecimal. + Revision is 8 bit revision identifier of the device. + What: /sys/bus/cdx/devices/.../enable Date: October 2023 Contact: abhijit.gangurde@amd.com @@ -67,3 +97,18 @@ Description: For example:: # echo 1 > /sys/bus/cdx/devices/.../remove + +What: /sys/bus/cdx/devices/.../modalias +Date: July 2023 +Contact: nipun.gupta@amd.com +Description: + This attribute indicates the CDX ID of the device. + That is in the format: + cdx:vXXXXdXXXXsvXXXXsdXXXXcXXXXXX, + where: + + - vXXXX contains the vendor ID; + - dXXXX contains the device ID; + - svXXXX contains the subsystem vendor ID; + - sdXXXX contains the subsystem device ID; + - cXXXXXX contains the device class. diff --git a/drivers/cdx/cdx.c b/drivers/cdx/cdx.c index e22a7138292e..3dcda7513818 100644 --- a/drivers/cdx/cdx.c +++ b/drivers/cdx/cdx.c @@ -179,7 +179,10 @@ cdx_match_one_device(const struct cdx_device_id *id, { /* Use vendor ID and device ID for matching */ if ((id->vendor == CDX_ANY_ID || id->vendor == dev->vendor) && - (id->device == CDX_ANY_ID || id->device == dev->device)) + (id->device == CDX_ANY_ID || id->device == dev->device) && + (id->subvendor == CDX_ANY_ID || id->subvendor == dev->subsystem_vendor) && + (id->subdevice == CDX_ANY_ID || id->subdevice == dev->subsystem_device) && + !((id->class ^ dev->class) & id->class_mask)) return id; return NULL; } @@ -329,6 +332,10 @@ static DEVICE_ATTR_RO(field) cdx_config_attr(vendor, "0x%04x\n"); cdx_config_attr(device, "0x%04x\n"); +cdx_config_attr(subsystem_vendor, "0x%04x\n"); +cdx_config_attr(subsystem_device, "0x%04x\n"); +cdx_config_attr(revision, "0x%02x\n"); +cdx_config_attr(class, "0x%06x\n"); static ssize_t remove_store(struct device *dev, struct device_attribute *attr, @@ -377,6 +384,17 @@ static ssize_t reset_store(struct device *dev, struct device_attribute *attr, } static DEVICE_ATTR_WO(reset); +static ssize_t modalias_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct cdx_device *cdx_dev = to_cdx_device(dev); + + return sprintf(buf, "cdx:v%04Xd%04Xsv%04Xsd%04Xc%06X\n", cdx_dev->vendor, + cdx_dev->device, cdx_dev->subsystem_vendor, cdx_dev->subsystem_device, + cdx_dev->class); +} +static DEVICE_ATTR_RO(modalias); + static ssize_t driver_override_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) @@ -467,6 +485,11 @@ static struct attribute *cdx_dev_attrs[] = { &dev_attr_reset.attr, &dev_attr_vendor.attr, &dev_attr_device.attr, + &dev_attr_subsystem_vendor.attr, + &dev_attr_subsystem_device.attr, + &dev_attr_class.attr, + &dev_attr_revision.attr, + &dev_attr_modalias.attr, &dev_attr_driver_override.attr, NULL, }; @@ -604,6 +627,10 @@ int cdx_device_add(struct cdx_dev_params *dev_params) cdx_dev->req_id = dev_params->req_id; cdx_dev->vendor = dev_params->vendor; cdx_dev->device = dev_params->device; + cdx_dev->subsystem_vendor = dev_params->subsys_vendor; + cdx_dev->subsystem_device = dev_params->subsys_device; + cdx_dev->class = dev_params->class; + cdx_dev->revision = dev_params->revision; cdx_dev->bus_num = dev_params->bus_num; cdx_dev->dev_num = dev_params->dev_num; cdx_dev->cdx = dev_params->cdx; diff --git a/drivers/cdx/cdx.h b/drivers/cdx/cdx.h index 1f593deb4c9e..300ad8be7a34 100644 --- a/drivers/cdx/cdx.h +++ b/drivers/cdx/cdx.h @@ -16,22 +16,30 @@ * @parent: Associated CDX Bus device * @vendor: Vendor ID for CDX device * @device: Device ID for CDX device + * @subsys_vendor: Sub vendor ID for CDX device + * @subsys_device: Sub device ID for CDX device * @bus_num: Bus number for this CDX device * @dev_num: Device number for this device * @res: array of MMIO region entries * @res_count: number of valid MMIO regions * @req_id: Requestor ID associated with CDX device + * @class: Class of the CDX Device + * @revision: Revision of the CDX device */ struct cdx_dev_params { struct cdx_controller *cdx; struct device *parent; u16 vendor; u16 device; + u16 subsys_vendor; + u16 subsys_device; u8 bus_num; u8 dev_num; struct resource res[MAX_CDX_DEV_RESOURCES]; u8 res_count; u32 req_id; + u32 class; + u8 revision; }; /** diff --git a/drivers/cdx/controller/mcdi_functions.c b/drivers/cdx/controller/mcdi_functions.c index 0e1e35d91242..65dca2aa1d3f 100644 --- a/drivers/cdx/controller/mcdi_functions.c +++ b/drivers/cdx/controller/mcdi_functions.c @@ -120,6 +120,13 @@ int cdx_mcdi_get_dev_config(struct cdx_mcdi *cdx, dev_params->vendor = MCDI_WORD(outbuf, CDX_BUS_GET_DEVICE_CONFIG_OUT_VENDOR_ID); dev_params->device = MCDI_WORD(outbuf, CDX_BUS_GET_DEVICE_CONFIG_OUT_DEVICE_ID); + dev_params->subsys_vendor = MCDI_WORD(outbuf, + CDX_BUS_GET_DEVICE_CONFIG_OUT_SUBSYS_VENDOR_ID); + dev_params->subsys_device = MCDI_WORD(outbuf, + CDX_BUS_GET_DEVICE_CONFIG_OUT_SUBSYS_DEVICE_ID); + dev_params->class = MCDI_DWORD(outbuf, + CDX_BUS_GET_DEVICE_CONFIG_OUT_DEVICE_CLASS) & 0xFFFFFF; + dev_params->revision = MCDI_BYTE(outbuf, CDX_BUS_GET_DEVICE_CONFIG_OUT_DEVICE_REVISION); return 0; } diff --git a/include/linux/cdx/cdx_bus.h b/include/linux/cdx/cdx_bus.h index 18e95076d1d5..cf9738e3a957 100644 --- a/include/linux/cdx/cdx_bus.h +++ b/include/linux/cdx/cdx_bus.h @@ -38,6 +38,19 @@ typedef int (*cdx_dev_configure_cb)(struct cdx_controller *cdx, u8 bus_num, u8 dev_num, struct cdx_device_config *dev_config); +/** + * CDX_DEVICE - macro used to describe a specific CDX device + * @vend: the 16 bit CDX Vendor ID + * @dev: the 16 bit CDX Device ID + * + * This macro is used to create a struct cdx_device_id that matches a + * specific device. The subvendor and subdevice fields will be set to + * CDX_ANY_ID. + */ +#define CDX_DEVICE(vend, dev) \ + .vendor = (vend), .device = (dev), \ + .subvendor = CDX_ANY_ID, .subdevice = CDX_ANY_ID + /** * CDX_DEVICE_DRIVER_OVERRIDE - macro used to describe a CDX device with * override_only flags. @@ -46,10 +59,12 @@ typedef int (*cdx_dev_configure_cb)(struct cdx_controller *cdx, * @driver_override: the 32 bit CDX Device override_only * * This macro is used to create a struct cdx_device_id that matches only a - * driver_override device. + * driver_override device. The subvendor and subdevice fields will be set to + * CDX_ANY_ID. */ #define CDX_DEVICE_DRIVER_OVERRIDE(vend, dev, driver_override) \ - .vendor = (vend), .device = (dev), .override_only = (driver_override) + .vendor = (vend), .device = (dev), .subvendor = CDX_ANY_ID,\ + .subdevice = CDX_ANY_ID, .override_only = (driver_override) /** * struct cdx_ops - Callbacks supported by CDX controller. @@ -88,6 +103,10 @@ struct cdx_controller { * @cdx: CDX controller associated with the device * @vendor: Vendor ID for CDX device * @device: Device ID for CDX device + * @subsystem_vendor: Subsystem Vendor ID for CDX device + * @subsystem_device: Subsystem Device ID for CDX device + * @class: Class for the CDX device + * @revision: Revision of the CDX device * @bus_num: Bus number for this CDX device * @dev_num: Device number for this device * @res: array of MMIO region entries @@ -107,6 +126,10 @@ struct cdx_device { struct cdx_controller *cdx; u16 vendor; u16 device; + u16 subsystem_vendor; + u16 subsystem_device; + u32 class; + u8 revision; u8 bus_num; u8 dev_num; struct resource res[MAX_CDX_DEV_RESOURCES]; diff --git a/include/linux/mod_devicetable.h b/include/linux/mod_devicetable.h index b0678b093cb2..aa3c28781248 100644 --- a/include/linux/mod_devicetable.h +++ b/include/linux/mod_devicetable.h @@ -935,6 +935,12 @@ enum { * struct cdx_device_id - CDX device identifier * @vendor: Vendor ID * @device: Device ID + * @subvendor: Subsystem vendor ID (or CDX_ANY_ID) + * @subdevice: Subsystem device ID (or CDX_ANY_ID) + * @class: Device class + * Most drivers do not need to specify class/class_mask + * as vendor/device is normally sufficient. + * @class_mask: Limit which sub-fields of the class field are compared. * @override_only: Match only when dev->driver_override is this driver. * * Type of entries in the "device Id" table for CDX devices supported by @@ -943,6 +949,10 @@ enum { struct cdx_device_id { __u16 vendor; __u16 device; + __u16 subvendor; + __u16 subdevice; + __u32 class; + __u32 class_mask; __u32 override_only; }; diff --git a/scripts/mod/devicetable-offsets.c b/scripts/mod/devicetable-offsets.c index abe65f8968dd..7a659aa3114a 100644 --- a/scripts/mod/devicetable-offsets.c +++ b/scripts/mod/devicetable-offsets.c @@ -265,6 +265,10 @@ int main(void) DEVID(cdx_device_id); DEVID_FIELD(cdx_device_id, vendor); DEVID_FIELD(cdx_device_id, device); + DEVID_FIELD(cdx_device_id, subvendor); + DEVID_FIELD(cdx_device_id, subdevice); + DEVID_FIELD(cdx_device_id, class); + DEVID_FIELD(cdx_device_id, class_mask); DEVID_FIELD(cdx_device_id, override_only); return 0; diff --git a/scripts/mod/file2alias.c b/scripts/mod/file2alias.c index 7056751c29b1..2b28faca9585 100644 --- a/scripts/mod/file2alias.c +++ b/scripts/mod/file2alias.c @@ -1458,6 +1458,10 @@ static int do_cdx_entry(const char *filename, void *symval, { DEF_FIELD(symval, cdx_device_id, vendor); DEF_FIELD(symval, cdx_device_id, device); + DEF_FIELD(symval, cdx_device_id, subvendor); + DEF_FIELD(symval, cdx_device_id, subdevice); + DEF_FIELD(symval, cdx_device_id, class); + DEF_FIELD(symval, cdx_device_id, class_mask); DEF_FIELD(symval, cdx_device_id, override_only); switch (override_only) { @@ -1475,6 +1479,10 @@ static int do_cdx_entry(const char *filename, void *symval, ADD(alias, "v", vendor != CDX_ANY_ID, vendor); ADD(alias, "d", device != CDX_ANY_ID, device); + ADD(alias, "sv", subvendor != CDX_ANY_ID, subvendor); + ADD(alias, "sd", subdevice != CDX_ANY_ID, subdevice); + ADD(alias, "c", class_mask == 0xFFFFFF, class); + return 1; }