diff options
| -rw-r--r-- | Documentation/devicetree/bindings/ufs/ufshcd-pltfrm.txt | 12 | ||||
| -rw-r--r-- | drivers/scsi/ufs/ufshcd-pltfrm.c | 48 | ||||
| -rw-r--r-- | drivers/scsi/ufs/ufshcd.h | 2 |
3 files changed, 43 insertions, 19 deletions
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: | |||
| 26 | - clocks : List of phandle and clock specifier pairs | 26 | - clocks : List of phandle and clock specifier pairs |
| 27 | - clock-names : List of clock input name strings sorted in the same | 27 | - clock-names : List of clock input name strings sorted in the same |
| 28 | order as the clocks property. | 28 | order as the clocks property. |
| 29 | - max-clock-frequency-hz : List of maximum operating frequency stored in the same | 29 | - freq-table-hz : Array of <min max> operating frequencies stored in the same |
| 30 | order as the clocks property. If this property is not | 30 | order as the clocks property. If this property is not |
| 31 | defined or a value in the array is "0" then it is assumed | 31 | defined or a value in the array is "0" then it is assumed |
| 32 | that the frequency is set by the parent clock or a | 32 | that the frequency is set by the parent clock or a |
| 33 | fixed rate clock source. | 33 | fixed rate clock source. |
| 34 | 34 | ||
| 35 | Note: If above properties are not defined it can be assumed that the supply | 35 | Note: If above properties are not defined it can be assumed that the supply |
| 36 | regulators or clocks are always on. | 36 | regulators or clocks are always on. |
| @@ -53,5 +53,5 @@ Example: | |||
| 53 | 53 | ||
| 54 | clocks = <&core 0>, <&ref 0>, <&iface 0>; | 54 | clocks = <&core 0>, <&ref 0>, <&iface 0>; |
| 55 | clock-names = "core_clk", "ref_clk", "iface_clk"; | 55 | clock-names = "core_clk", "ref_clk", "iface_clk"; |
| 56 | max-clock-frequency-hz = <100000000 19200000 0>; | 56 | freq-table-hz = <100000000 200000000>, <0 0>, <0 0>; |
| 57 | }; | 57 | }; |
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) | |||
| 63 | char *name; | 63 | char *name; |
| 64 | u32 *clkfreq = NULL; | 64 | u32 *clkfreq = NULL; |
| 65 | struct ufs_clk_info *clki; | 65 | struct ufs_clk_info *clki; |
| 66 | int len = 0; | ||
| 67 | size_t sz = 0; | ||
| 66 | 68 | ||
| 67 | if (!np) | 69 | if (!np) |
| 68 | goto out; | 70 | goto out; |
| @@ -82,39 +84,59 @@ static int ufshcd_parse_clock_info(struct ufs_hba *hba) | |||
| 82 | if (cnt <= 0) | 84 | if (cnt <= 0) |
| 83 | goto out; | 85 | goto out; |
| 84 | 86 | ||
| 85 | clkfreq = kzalloc(cnt * sizeof(*clkfreq), GFP_KERNEL); | 87 | if (!of_get_property(np, "freq-table-hz", &len)) { |
| 88 | dev_info(dev, "freq-table-hz property not specified\n"); | ||
| 89 | goto out; | ||
| 90 | } | ||
| 91 | |||
| 92 | if (len <= 0) | ||
| 93 | goto out; | ||
| 94 | |||
| 95 | sz = len / sizeof(*clkfreq); | ||
| 96 | if (sz != 2 * cnt) { | ||
| 97 | dev_err(dev, "%s len mismatch\n", "freq-table-hz"); | ||
| 98 | ret = -EINVAL; | ||
| 99 | goto out; | ||
| 100 | } | ||
| 101 | |||
| 102 | clkfreq = devm_kzalloc(dev, sz * sizeof(*clkfreq), | ||
| 103 | GFP_KERNEL); | ||
| 86 | if (!clkfreq) { | 104 | if (!clkfreq) { |
| 105 | dev_err(dev, "%s: no memory\n", "freq-table-hz"); | ||
| 87 | ret = -ENOMEM; | 106 | ret = -ENOMEM; |
| 88 | dev_err(dev, "%s: memory alloc failed\n", __func__); | ||
| 89 | goto out; | 107 | goto out; |
| 90 | } | 108 | } |
| 91 | 109 | ||
| 92 | ret = of_property_read_u32_array(np, | 110 | ret = of_property_read_u32_array(np, "freq-table-hz", |
| 93 | "max-clock-frequency-hz", clkfreq, cnt); | 111 | clkfreq, sz); |
| 94 | if (ret && (ret != -EINVAL)) { | 112 | if (ret && (ret != -EINVAL)) { |
| 95 | dev_err(dev, "%s: invalid max-clock-frequency-hz property, %d\n", | 113 | dev_err(dev, "%s: error reading array %d\n", |
| 96 | __func__, ret); | 114 | "freq-table-hz", ret); |
| 97 | goto out; | 115 | goto free_clkfreq; |
| 98 | } | 116 | } |
| 99 | 117 | ||
| 100 | for (i = 0; i < cnt; i++) { | 118 | for (i = 0; i < sz; i += 2) { |
| 101 | ret = of_property_read_string_index(np, | 119 | ret = of_property_read_string_index(np, |
| 102 | "clock-names", i, (const char **)&name); | 120 | "clock-names", i/2, (const char **)&name); |
| 103 | if (ret) | 121 | if (ret) |
| 104 | goto out; | 122 | goto free_clkfreq; |
| 105 | 123 | ||
| 106 | clki = devm_kzalloc(dev, sizeof(*clki), GFP_KERNEL); | 124 | clki = devm_kzalloc(dev, sizeof(*clki), GFP_KERNEL); |
| 107 | if (!clki) { | 125 | if (!clki) { |
| 108 | ret = -ENOMEM; | 126 | ret = -ENOMEM; |
| 109 | goto out; | 127 | goto free_clkfreq; |
| 110 | } | 128 | } |
| 111 | 129 | ||
| 112 | clki->max_freq = clkfreq[i]; | 130 | clki->min_freq = clkfreq[i]; |
| 131 | clki->max_freq = clkfreq[i+1]; | ||
| 113 | clki->name = kstrdup(name, GFP_KERNEL); | 132 | clki->name = kstrdup(name, GFP_KERNEL); |
| 133 | dev_dbg(dev, "%s: min %u max %u name %s\n", "freq-table-hz", | ||
| 134 | clki->min_freq, clki->max_freq, clki->name); | ||
| 114 | list_add_tail(&clki->list, &hba->clk_list_head); | 135 | list_add_tail(&clki->list, &hba->clk_list_head); |
| 115 | } | 136 | } |
| 116 | out: | 137 | free_clkfreq: |
| 117 | kfree(clkfreq); | 138 | kfree(clkfreq); |
| 139 | out: | ||
| 118 | return ret; | 140 | return ret; |
| 119 | } | 141 | } |
| 120 | 142 | ||
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 { | |||
| 209 | * @clk: clock node | 209 | * @clk: clock node |
| 210 | * @name: clock name | 210 | * @name: clock name |
| 211 | * @max_freq: maximum frequency supported by the clock | 211 | * @max_freq: maximum frequency supported by the clock |
| 212 | * @min_freq: min frequency that can be used for clock scaling | ||
| 212 | * @enabled: variable to check against multiple enable/disable | 213 | * @enabled: variable to check against multiple enable/disable |
| 213 | */ | 214 | */ |
| 214 | struct ufs_clk_info { | 215 | struct ufs_clk_info { |
| @@ -216,6 +217,7 @@ struct ufs_clk_info { | |||
| 216 | struct clk *clk; | 217 | struct clk *clk; |
| 217 | const char *name; | 218 | const char *name; |
| 218 | u32 max_freq; | 219 | u32 max_freq; |
| 220 | u32 min_freq; | ||
| 219 | bool enabled; | 221 | bool enabled; |
| 220 | }; | 222 | }; |
| 221 | 223 | ||
