Received: by 2002:a05:6a10:413:0:0:0:0 with SMTP id 19csp2225858pxp; Mon, 21 Mar 2022 14:19:28 -0700 (PDT) X-Google-Smtp-Source: ABdhPJz0Pq+9P8rWOjseLSzI43SNAaoGJ0cUpF7i92uRZtpYCIKTvjbv0jvOcs7RbvXGtTpWIQZm X-Received: by 2002:a17:902:c3c5:b0:154:e07:275a with SMTP id j5-20020a170902c3c500b001540e07275amr14676406plj.106.1647897568717; Mon, 21 Mar 2022 14:19:28 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1647897568; cv=none; d=google.com; s=arc-20160816; b=N7a16ZxXm8rUfJZk9j1gD2F2PXZql4MdWuF9K2757It6MnQzqO6C8E6AYtCo6Bi8Bk sOCmgB3JoLi4/5OpG/ow6xDRD5pX8wvbIrbsGxL6cSsIkFiOP5IEHimPeOfpT6xf1452 nnn1iKyC3SUYUH/+Z2bue31DImbz5kgX8dh1yHBQ86D3KUvfFjpFLyKmQuTQws0ZgOuV AYURBRvr/4J0Hk4pmToNPB108HCPLOsPa3+/zxvdRr+zk4Xo7lI04b8KYdDgnq0KMQk0 1cK3V0RTKi8XpgNRSxgbSHyXBiOdvgErFAiNqKDIK8NNkvCXfbUmeLgPu0AI0IkWYZLl mshA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:content-transfer-encoding:mime-version :message-id:date:subject:cc:to:from; bh=z6YcumYA5KJ8h43+AkHAxuKaBnzqU8Xsp1y3a9SDy6o=; b=VnVXe5SctjdBhM8Zf7N9Y8/i1Y7R/llyoXF9bvTl13hPQZ3irjJ/qtPsJvvSQpVKrq RsxNJ0OR4SwCELcj34Dy9ffSdZaww3G0ozrx8Oo9/+OyCFAfoUu/B+TZaboBtNFdmkQJ f2cGD8UkI+84uz9dDsbnbvOXwTooF0MWrEyYYYe0FvOuPdL7iLMaM12FFPX43F2Qys+B pXEyUAo+dEP003PQDNFdr9TIremZ6+7i0w2KTbWTPv9Fbjz6V1l07NpqA7rrVYvNgLbj XG/wsLA+gmarPBO8IfC7Hxc+OXOZfLUC4VyG52kECQ1COIc5cz5ctOArnohadDNGIPmh Bbsg== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Return-Path: Received: from lindbergh.monkeyblade.net (lindbergh.monkeyblade.net. [2620:137:e000::1:18]) by mx.google.com with ESMTPS id h22-20020a63df56000000b003820706bc3dsi13311044pgj.137.2022.03.21.14.19.28 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 21 Mar 2022 14:19:28 -0700 (PDT) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:18 as permitted sender) client-ip=2620:137:e000::1:18; Authentication-Results: mx.google.com; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by lindbergh.monkeyblade.net (Postfix) with ESMTP id 3557B1DB3EA; Mon, 21 Mar 2022 14:06:22 -0700 (PDT) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S244074AbiCSUHV (ORCPT + 99 others); Sat, 19 Mar 2022 16:07:21 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:51960 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S244070AbiCSUHU (ORCPT ); Sat, 19 Mar 2022 16:07:20 -0400 Received: from relay06.th.seeweb.it (relay06.th.seeweb.it [IPv6:2001:4b7a:2000:18::167]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 70864243718 for ; Sat, 19 Mar 2022 13:05:56 -0700 (PDT) Received: from localhost.localdomain (abxi119.neoplus.adsl.tpnet.pl [83.9.2.119]) by m-r2.th.seeweb.it (Postfix) with ESMTPA id ED29F3F424; Sat, 19 Mar 2022 21:05:53 +0100 (CET) From: Konrad Dybcio To: ~postmarketos/upstreaming@lists.sr.ht Cc: martin.botka@somainline.org, angelogioacchino.delregno@somainline.org, marijn.suijten@somainline.org, jamipkettunen@somainline.org, Konrad Dybcio , Loic Poulain , Robert Foss , linux-i2c@vger.kernel.org, linux-arm-msm@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [RFC DNM PATCH] i2c: busses: qcom-cci: Add support for passing data in DT Date: Sat, 19 Mar 2022 21:05:49 +0100 Message-Id: <20220319200549.530387-1-konrad.dybcio@somainline.org> X-Mailer: git-send-email 2.35.1 MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Spam-Status: No, score=-1.9 required=5.0 tests=BAYES_00, HEADER_FROM_DIFFERENT_DOMAINS,MAILING_LIST_MULTI,RDNS_NONE, SPF_HELO_NONE,T_SCC_BODY_TEXT_LINE autolearn=no autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Some vendors, such as SONY, fine-tune CCI parameters to better suit their specific combinations of devices and camera sensors, mostly in order to save a tiny bit more power. Add support for specifying all the CCI parameters in DT to avoid adding millions of structs in the driver itself. --- This is a ridiculously blatant RFC and PoC just to start the discussion. (thus it's missing the S-o-b on purpose) My point is that our favourite (cough cough) phone vendor likes to fine-tune every bit of the hardware and they are probably not alone doing this. Moving the properties into the DT would allow for more flexibility with the configuration, instead of having to add a separate set of structs for each one. If it were to make it in any form, it would probably be much saner to represent each mode as an individual subnode in the dt, specifying its parameters over there (which would incidentally also allow for adding more/less modes if need be), something like this: cci@0badbeef { /* compatible and stuff */ mode-standard { parameter-1 = <1>; }; mode-fast { parameter-1 = <1>; }; mode-supercustomlightspeed { parameter-1 = <1>; parameter-2 = <1337>; }; }; What are your thoughts about this, and do you think the form shown above (and probably not the one in the patch) would be fitting, or is there a better approach to this? drivers/i2c/busses/i2c-qcom-cci.c | 274 ++++++++++++++++++++++++++++++ 1 file changed, 274 insertions(+) diff --git a/drivers/i2c/busses/i2c-qcom-cci.c b/drivers/i2c/busses/i2c-qcom-cci.c index 07c11e2a446d..6754b5d11c52 100644 --- a/drivers/i2c/busses/i2c-qcom-cci.c +++ b/drivers/i2c/busses/i2c-qcom-cci.c @@ -117,6 +117,7 @@ struct cci_master { }; struct cci_data { + bool read_params_from_dt; unsigned int num_masters; struct i2c_adapter_quirks quirks; u16 queue_size[NUM_QUEUES]; @@ -520,11 +521,20 @@ static const struct dev_pm_ops qcom_cci_pm = { SET_RUNTIME_PM_OPS(cci_suspend_runtime, cci_resume_runtime, NULL) }; +static struct cci_data cci_dt_data = { + .read_params_from_dt = true, + .quirks = {}, + .params[I2C_MODE_STANDARD] = {}, + .params[I2C_MODE_FAST] = {}, + .params[I2C_MODE_FAST_PLUS] = {}, +}; + static int cci_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; unsigned long cci_clk_rate = 0; struct device_node *child; + struct cci_data *dt_data; struct resource *r; struct cci *cci; int ret, i; @@ -540,6 +550,267 @@ static int cci_probe(struct platform_device *pdev) if (!cci->data) return -ENOENT; + if (cci->data->read_params_from_dt) { + dt_data = &cci_dt_data; + + /* CCI params */ + ret = of_property_read_u32(dev->of_node, "num-masters", &val); + if (ret) { + dev_err(dev, "Error reading num-masters from DT, ret = %d", ret); + return ret; + } + dt_data->num_masters = val; + + ret = of_property_read_u16_array(dev->of_node, "queue-size", dt_data->queue_size, + (size_t)&dt_data->num_masters); + if (ret) { + dev_err(dev, "Error reading queue-size from DT, ret = %d", ret); + return ret; + } + + if (ARRAY_SIZE(dt_data->queue_size) != dt_data->num_masters) { + dev_err(dev, "num-masters doesn't match the number of queue-size elements!"); + return -EINVAL; + } + + ret = of_property_read_u32(dev->of_node, "max-write-len", &val); + if (ret) { + dev_err(dev, "Error reading max-write-len from DT, ret = %d", ret); + return ret; + } + dt_data->quirks.max_write_len = (u16)val; + + ret = of_property_read_u32(dev->of_node, "max-read-len", &val); + if (ret) { + dev_err(dev, "Error reading max-read-len from DT, ret = %d", ret); + return ret; + } + dt_data->quirks.max_read_len = (u16)val; + + ret = of_property_read_u32(dev->of_node, "cci-clk-rate", &val); + if (ret) { + dev_err(dev, "Error reading cci-clk-rate from DT, ret = %d", ret); + return ret; + } + dt_data->cci_clk_rate = (unsigned long)val; + + /* STANDARD mode params */ + ret = of_property_read_u32(dev->of_node, "thigh-standard", &val); + if (ret) { + dev_err(dev, "Error reading thigh-standard from DT, ret = %d", ret); + return ret; + } + dt_data->params[I2C_MODE_STANDARD].thigh = (u16)val; + + ret = of_property_read_u32(dev->of_node, "tlow-standard", &val); + if (ret) { + dev_err(dev, "Error reading tlow-standard from DT, ret = %d", ret); + return ret; + } + dt_data->params[I2C_MODE_STANDARD].tlow = (u16)val; + + ret = of_property_read_u32(dev->of_node, "tsu-sto-standard", &val); + if (ret) { + dev_err(dev, "Error reading tsu-sto-standard from DT, ret = %d", ret); + return ret; + } + dt_data->params[I2C_MODE_STANDARD].tsu_sto = (u16)val; + + ret = of_property_read_u32(dev->of_node, "tsu-sta-standard", &val); + if (ret) { + dev_err(dev, "Error reading tsu-sta-standard from DT, ret = %d", ret); + return ret; + } + dt_data->params[I2C_MODE_STANDARD].tsu_sta = (u16)val; + + ret = of_property_read_u32(dev->of_node, "thd-dat-standard", &val); + if (ret) { + dev_err(dev, "Error reading thd-dat-standard from DT, ret = %d", ret); + return ret; + } + dt_data->params[I2C_MODE_STANDARD].thd_dat = (u16)val; + + ret = of_property_read_u32(dev->of_node, "thd-sta-standard", &val); + if (ret) { + dev_err(dev, "Error reading thd-sta-standard from DT, ret = %d", ret); + return ret; + } + dt_data->params[I2C_MODE_STANDARD].thd_sta = (u16)val; + + ret = of_property_read_u32(dev->of_node, "tbuf-standard", &val); + if (ret) { + dev_err(dev, "Error reading tbuf-standard from DT, ret = %d", ret); + return ret; + } + dt_data->params[I2C_MODE_STANDARD].tbuf = (u16)val; + + ret = of_property_read_u32(dev->of_node, "scl-stretch-en-standard", &val); + if (ret) { + dev_err(dev, "Error reading scl-stretch-en-standard from DT, ret = %d", ret); + return ret; + } + dt_data->params[I2C_MODE_STANDARD].scl_stretch_en = (u8)val; + + ret = of_property_read_u32(dev->of_node, "trdhld-standard", &val); + if (ret) { + dev_err(dev, "Error reading trdhld-standard from DT, ret = %d", ret); + return ret; + } + dt_data->params[I2C_MODE_STANDARD].trdhld = (u16)val; + + ret = of_property_read_u32(dev->of_node, "tsp-standard", &val); + if (ret) { + dev_err(dev, "Error reading tsp-standard from DT, ret = %d", ret); + return ret; + } + dt_data->params[I2C_MODE_STANDARD].tsp = (u16)val; + + /* FAST mode params */ + ret = of_property_read_u32(dev->of_node, "thigh-fast", &val); + if (ret) { + dev_err(dev, "Error reading thigh-fast from DT, ret = %d", ret); + return ret; + } + dt_data->params[I2C_MODE_FAST].thigh = (u16)val; + + ret = of_property_read_u32(dev->of_node, "tlow-fast", &val); + if (ret) { + dev_err(dev, "Error reading tlow-fast from DT, ret = %d", ret); + return ret; + } + dt_data->params[I2C_MODE_FAST].tlow = (u16)val; + + ret = of_property_read_u32(dev->of_node, "tsu-sto-fast", &val); + if (ret) { + dev_err(dev, "Error reading tsu-sto-fast from DT, ret = %d", ret); + return ret; + } + dt_data->params[I2C_MODE_FAST].tsu_sto = (u16)val; + + ret = of_property_read_u32(dev->of_node, "tsu-sta-fast", &val); + if (ret) { + dev_err(dev, "Error reading tsu-sta-fast from DT, ret = %d", ret); + return ret; + } + dt_data->params[I2C_MODE_FAST].tsu_sta = (u16)val; + + ret = of_property_read_u32(dev->of_node, "thd-dat-fast", &val); + if (ret) { + dev_err(dev, "Error reading thd-dat-fast from DT, ret = %d", ret); + return ret; + } + dt_data->params[I2C_MODE_FAST].thd_dat = (u16)val; + + ret = of_property_read_u32(dev->of_node, "thd-sta-fast", &val); + if (ret) { + dev_err(dev, "Error reading thd-sta-fast from DT, ret = %d", ret); + return ret; + } + dt_data->params[I2C_MODE_FAST].thd_sta = (u16)val; + + ret = of_property_read_u32(dev->of_node, "tbuf-fast", &val); + if (ret) { + dev_err(dev, "Error reading tbuf-fast from DT, ret = %d", ret); + return ret; + } + dt_data->params[I2C_MODE_FAST].tbuf = (u16)val; + + ret = of_property_read_u32(dev->of_node, "scl-stretch-en-fast", &val); + if (ret) { + dev_err(dev, "Error reading scl-stretch-en-fast from DT, ret = %d", ret); + return ret; + } + dt_data->params[I2C_MODE_FAST].scl_stretch_en = (u8)val; + + ret = of_property_read_u32(dev->of_node, "trdhld-fast", &val); + if (ret) { + dev_err(dev, "Error reading trdhld-fast from DT, ret = %d", ret); + return ret; + } + dt_data->params[I2C_MODE_FAST].trdhld = (u16)val; + + ret = of_property_read_u32(dev->of_node, "tsp-fast", &val); + if (ret) { + dev_err(dev, "Error reading tsp-fast from DT, ret = %d", ret); + return ret; + } + dt_data->params[I2C_MODE_FAST].tsp = (u16)val; + + /* FAST_PLUS mode params */ + ret = of_property_read_u32(dev->of_node, "thigh-fast-plus", &val); + if (ret) { + dev_err(dev, "Error reading thigh-fast-plus from DT, ret = %d", ret); + return ret; + } + dt_data->params[I2C_MODE_FAST_PLUS].thigh = (u16)val; + + ret = of_property_read_u32(dev->of_node, "tlow-fast-plus", &val); + if (ret) { + dev_err(dev, "Error reading tlow-fast-plus from DT, ret = %d", ret); + return ret; + } + dt_data->params[I2C_MODE_FAST_PLUS].tlow = (u16)val; + + ret = of_property_read_u32(dev->of_node, "tsu-sto-fast-plus", &val); + if (ret) { + dev_err(dev, "Error reading tsu-sto-fast-plus from DT, ret = %d", ret); + return ret; + } + dt_data->params[I2C_MODE_FAST_PLUS].tsu_sto = (u16)val; + + ret = of_property_read_u32(dev->of_node, "tsu-sta-fast-plus", &val); + if (ret) { + dev_err(dev, "Error reading tsu-sta-fast-plus from DT, ret = %d", ret); + return ret; + } + dt_data->params[I2C_MODE_FAST_PLUS].tsu_sta = (u16)val; + + ret = of_property_read_u32(dev->of_node, "thd-dat-fast-plus", &val); + if (ret) { + dev_err(dev, "Error reading thd-dat-fast-plus from DT, ret = %d", ret); + return ret; + } + dt_data->params[I2C_MODE_FAST_PLUS].thd_dat = (u16)val; + + ret = of_property_read_u32(dev->of_node, "thd-sta-fast-plus", &val); + if (ret) { + dev_err(dev, "Error reading thd-sta-fast-plus from DT, ret = %d", ret); + return ret; + } + dt_data->params[I2C_MODE_FAST_PLUS].thd_sta = (u16)val; + + ret = of_property_read_u32(dev->of_node, "tbuf-fast-plus", &val); + if (ret) { + dev_err(dev, "Error reading tbuf-fast-plus from DT, ret = %d", ret); + return ret; + } + dt_data->params[I2C_MODE_FAST_PLUS].tbuf = (u16)val; + + ret = of_property_read_u32(dev->of_node, "scl-stretch-en-fast-plus", &val); + if (ret) { + dev_err(dev, "Error reading scl-stretch-en-fast-plus from DT, ret = %d", ret); + return ret; + } + dt_data->params[I2C_MODE_FAST_PLUS].scl_stretch_en = (u8)val; + + ret = of_property_read_u32(dev->of_node, "trdhld-fast-plus", &val); + if (ret) { + dev_err(dev, "Error reading trdhld-fast-plus from DT, ret = %d", ret); + return ret; + } + dt_data->params[I2C_MODE_FAST_PLUS].trdhld = (u16)val; + + ret = of_property_read_u32(dev->of_node, "tsp-fast-plus", &val); + if (ret) { + dev_err(dev, "Error reading tsp-fast-plus from DT, ret = %d", ret); + return ret; + } + dt_data->params[I2C_MODE_FAST_PLUS].tsp = (u16)val; + + /* Let's ship it! */ + cci->data = dt_data; + } + for_each_available_child_of_node(dev->of_node, child) { u32 idx; @@ -818,6 +1089,9 @@ static const struct cci_data cci_msm8994_data = { }; static const struct of_device_id cci_dt_match[] = { + { .compatible = "qcom,cci", .data = &cci_dt_data }, + + /* Legacy compatibles for older DTs */ { .compatible = "qcom,msm8916-cci", .data = &cci_v1_data}, { .compatible = "qcom,msm8994-cci", .data = &cci_msm8994_data}, { .compatible = "qcom,msm8996-cci", .data = &cci_v2_data}, -- 2.35.1