diff --git a/Documentation/devicetree/bindings/ufs/ufshcd-pltfrm.txt b/Documentation/devicetree/bindings/ufs/ufshcd-pltfrm.txt index fb1234e0532c..53579197eca2 100644 --- a/Documentation/devicetree/bindings/ufs/ufshcd-pltfrm.txt +++ b/Documentation/devicetree/bindings/ufs/ufshcd-pltfrm.txt @@ -26,11 +26,11 @@ Optional properties: - clocks : List of phandle and clock specifier pairs - clock-names : List of clock input name strings sorted in the same order as the clocks property. -- max-clock-frequency-hz : List of maximum operating frequency stored in the same - order as the clocks property. If this property is not - defined or a value in the array is "0" then it is assumed - that the frequency is set by the parent clock or a - fixed rate clock source. +- freq-table-hz : Array of operating frequencies stored in the same + order as the clocks property. If this property is not + defined or a value in the array is "0" then it is assumed + that the frequency is set by the parent clock or a + fixed rate clock source. Note: If above properties are not defined it can be assumed that the supply regulators or clocks are always on. @@ -53,5 +53,5 @@ Example: clocks = <&core 0>, <&ref 0>, <&iface 0>; clock-names = "core_clk", "ref_clk", "iface_clk"; - max-clock-frequency-hz = <100000000 19200000 0>; + freq-table-hz = <100000000 200000000>, <0 0>, <0 0>; }; diff --git a/drivers/scsi/ufs/ufshcd-pltfrm.c b/drivers/scsi/ufs/ufshcd-pltfrm.c index 2482bbac3681..8adf067ff019 100644 --- a/drivers/scsi/ufs/ufshcd-pltfrm.c +++ b/drivers/scsi/ufs/ufshcd-pltfrm.c @@ -63,6 +63,8 @@ static int ufshcd_parse_clock_info(struct ufs_hba *hba) char *name; u32 *clkfreq = NULL; struct ufs_clk_info *clki; + int len = 0; + size_t sz = 0; if (!np) goto out; @@ -82,39 +84,59 @@ static int ufshcd_parse_clock_info(struct ufs_hba *hba) if (cnt <= 0) goto out; - clkfreq = kzalloc(cnt * sizeof(*clkfreq), GFP_KERNEL); + if (!of_get_property(np, "freq-table-hz", &len)) { + dev_info(dev, "freq-table-hz property not specified\n"); + goto out; + } + + if (len <= 0) + goto out; + + sz = len / sizeof(*clkfreq); + if (sz != 2 * cnt) { + dev_err(dev, "%s len mismatch\n", "freq-table-hz"); + ret = -EINVAL; + goto out; + } + + clkfreq = devm_kzalloc(dev, sz * sizeof(*clkfreq), + GFP_KERNEL); if (!clkfreq) { + dev_err(dev, "%s: no memory\n", "freq-table-hz"); ret = -ENOMEM; - dev_err(dev, "%s: memory alloc failed\n", __func__); goto out; } - ret = of_property_read_u32_array(np, - "max-clock-frequency-hz", clkfreq, cnt); + ret = of_property_read_u32_array(np, "freq-table-hz", + clkfreq, sz); if (ret && (ret != -EINVAL)) { - dev_err(dev, "%s: invalid max-clock-frequency-hz property, %d\n", - __func__, ret); - goto out; + dev_err(dev, "%s: error reading array %d\n", + "freq-table-hz", ret); + goto free_clkfreq; } - for (i = 0; i < cnt; i++) { + for (i = 0; i < sz; i += 2) { ret = of_property_read_string_index(np, - "clock-names", i, (const char **)&name); + "clock-names", i/2, (const char **)&name); if (ret) - goto out; + goto free_clkfreq; clki = devm_kzalloc(dev, sizeof(*clki), GFP_KERNEL); if (!clki) { ret = -ENOMEM; - goto out; + goto free_clkfreq; } - clki->max_freq = clkfreq[i]; + clki->min_freq = clkfreq[i]; + clki->max_freq = clkfreq[i+1]; clki->name = kstrdup(name, GFP_KERNEL); + dev_dbg(dev, "%s: min %u max %u name %s\n", "freq-table-hz", + clki->min_freq, clki->max_freq, clki->name); list_add_tail(&clki->list, &hba->clk_list_head); } -out: +free_clkfreq: kfree(clkfreq); +out: return ret; } diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h index 29d34d3aa5ee..ac72a6daf50e 100644 --- a/drivers/scsi/ufs/ufshcd.h +++ b/drivers/scsi/ufs/ufshcd.h @@ -209,6 +209,7 @@ struct ufs_dev_cmd { * @clk: clock node * @name: clock name * @max_freq: maximum frequency supported by the clock + * @min_freq: min frequency that can be used for clock scaling * @enabled: variable to check against multiple enable/disable */ struct ufs_clk_info { @@ -216,6 +217,7 @@ struct ufs_clk_info { struct clk *clk; const char *name; u32 max_freq; + u32 min_freq; bool enabled; };