Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

net: can: mscan: adjust to common clock support for mpc512x

implement a .get_clock() callback for the MPC512x platform which uses
the common clock infrastructure (eliminating direct access to the clock
control registers from within the CAN network driver), and provide the
corresponding .put_clock() callback to release resources after use

acquire both the clock items for register access ("ipg") as well as for
wire communication ("can")

keep the previous implementation of MPC512x support in place during
migration, this results in a readable diff of the change

this change is neutral to the MPC5200 platform

Cc: Wolfgang Grandegger <wg@grandegger.com>
Cc: Marc Kleine-Budde <mkl@pengutronix.de>
Cc: linux-can@vger.kernel.org
Signed-off-by: Gerhard Sittig <gsi@denx.de>
Signed-off-by: Anatolij Gustschin <agust@denx.de>

authored by

Gerhard Sittig and committed by
Anatolij Gustschin
5ac22504 17552189

+179
+179
drivers/net/can/mscan/mpc5xxx_can.c
··· 109 109 #endif /* CONFIG_PPC_MPC52xx */ 110 110 111 111 #ifdef CONFIG_PPC_MPC512x 112 + 113 + #if IS_ENABLED(CONFIG_COMMON_CLK) 114 + 115 + static u32 mpc512x_can_get_clock(struct platform_device *ofdev, 116 + const char *clock_source, int *mscan_clksrc) 117 + { 118 + struct device_node *np; 119 + u32 clockdiv; 120 + enum { 121 + CLK_FROM_AUTO, 122 + CLK_FROM_IPS, 123 + CLK_FROM_SYS, 124 + CLK_FROM_REF, 125 + } clk_from; 126 + struct clk *clk_in, *clk_can; 127 + unsigned long freq_calc; 128 + struct mscan_priv *priv; 129 + struct clk *clk_ipg; 130 + 131 + /* the caller passed in the clock source spec that was read from 132 + * the device tree, get the optional clock divider as well 133 + */ 134 + np = ofdev->dev.of_node; 135 + clockdiv = 1; 136 + of_property_read_u32(np, "fsl,mscan-clock-divider", &clockdiv); 137 + dev_dbg(&ofdev->dev, "device tree specs: clk src[%s] div[%d]\n", 138 + clock_source ? clock_source : "<NULL>", clockdiv); 139 + 140 + /* when clock-source is 'ip', the CANCTL1[CLKSRC] bit needs to 141 + * get set, and the 'ips' clock is the input to the MSCAN 142 + * component 143 + * 144 + * for clock-source values of 'ref' or 'sys' the CANCTL1[CLKSRC] 145 + * bit needs to get cleared, an optional clock-divider may have 146 + * been specified (the default value is 1), the appropriate 147 + * MSCAN related MCLK is the input to the MSCAN component 148 + * 149 + * in the absence of a clock-source spec, first an optimal clock 150 + * gets determined based on the 'sys' clock, if that fails the 151 + * 'ref' clock is used 152 + */ 153 + clk_from = CLK_FROM_AUTO; 154 + if (clock_source) { 155 + /* interpret the device tree's spec for the clock source */ 156 + if (!strcmp(clock_source, "ip")) 157 + clk_from = CLK_FROM_IPS; 158 + else if (!strcmp(clock_source, "sys")) 159 + clk_from = CLK_FROM_SYS; 160 + else if (!strcmp(clock_source, "ref")) 161 + clk_from = CLK_FROM_REF; 162 + else 163 + goto err_invalid; 164 + dev_dbg(&ofdev->dev, "got a clk source spec[%d]\n", clk_from); 165 + } 166 + if (clk_from == CLK_FROM_AUTO) { 167 + /* no spec so far, try the 'sys' clock; round to the 168 + * next MHz and see if we can get a multiple of 16MHz 169 + */ 170 + dev_dbg(&ofdev->dev, "no clk source spec, trying SYS\n"); 171 + clk_in = devm_clk_get(&ofdev->dev, "sys"); 172 + if (IS_ERR(clk_in)) 173 + goto err_notavail; 174 + freq_calc = clk_get_rate(clk_in); 175 + freq_calc += 499999; 176 + freq_calc /= 1000000; 177 + freq_calc *= 1000000; 178 + if ((freq_calc % 16000000) == 0) { 179 + clk_from = CLK_FROM_SYS; 180 + clockdiv = freq_calc / 16000000; 181 + dev_dbg(&ofdev->dev, 182 + "clk fit, sys[%lu] div[%d] freq[%lu]\n", 183 + freq_calc, clockdiv, freq_calc / clockdiv); 184 + } 185 + } 186 + if (clk_from == CLK_FROM_AUTO) { 187 + /* no spec so far, use the 'ref' clock */ 188 + dev_dbg(&ofdev->dev, "no clk source spec, trying REF\n"); 189 + clk_in = devm_clk_get(&ofdev->dev, "ref"); 190 + if (IS_ERR(clk_in)) 191 + goto err_notavail; 192 + clk_from = CLK_FROM_REF; 193 + freq_calc = clk_get_rate(clk_in); 194 + dev_dbg(&ofdev->dev, 195 + "clk fit, ref[%lu] (no div) freq[%lu]\n", 196 + freq_calc, freq_calc); 197 + } 198 + 199 + /* select IPS or MCLK as the MSCAN input (returned to the caller), 200 + * setup the MCLK mux source and rate if applicable, apply the 201 + * optionally specified or derived above divider, and determine 202 + * the actual resulting clock rate to return to the caller 203 + */ 204 + switch (clk_from) { 205 + case CLK_FROM_IPS: 206 + clk_can = devm_clk_get(&ofdev->dev, "ips"); 207 + if (IS_ERR(clk_can)) 208 + goto err_notavail; 209 + priv = netdev_priv(dev_get_drvdata(&ofdev->dev)); 210 + priv->clk_can = clk_can; 211 + freq_calc = clk_get_rate(clk_can); 212 + *mscan_clksrc = MSCAN_CLKSRC_IPS; 213 + dev_dbg(&ofdev->dev, "clk from IPS, clksrc[%d] freq[%lu]\n", 214 + *mscan_clksrc, freq_calc); 215 + break; 216 + case CLK_FROM_SYS: 217 + case CLK_FROM_REF: 218 + clk_can = devm_clk_get(&ofdev->dev, "mclk"); 219 + if (IS_ERR(clk_can)) 220 + goto err_notavail; 221 + priv = netdev_priv(dev_get_drvdata(&ofdev->dev)); 222 + priv->clk_can = clk_can; 223 + if (clk_from == CLK_FROM_SYS) 224 + clk_in = devm_clk_get(&ofdev->dev, "sys"); 225 + if (clk_from == CLK_FROM_REF) 226 + clk_in = devm_clk_get(&ofdev->dev, "ref"); 227 + if (IS_ERR(clk_in)) 228 + goto err_notavail; 229 + clk_set_parent(clk_can, clk_in); 230 + freq_calc = clk_get_rate(clk_in); 231 + freq_calc /= clockdiv; 232 + clk_set_rate(clk_can, freq_calc); 233 + freq_calc = clk_get_rate(clk_can); 234 + *mscan_clksrc = MSCAN_CLKSRC_BUS; 235 + dev_dbg(&ofdev->dev, "clk from MCLK, clksrc[%d] freq[%lu]\n", 236 + *mscan_clksrc, freq_calc); 237 + break; 238 + default: 239 + goto err_invalid; 240 + } 241 + 242 + /* the above clk_can item is used for the bitrate, access to 243 + * the peripheral's register set needs the clk_ipg item 244 + */ 245 + clk_ipg = devm_clk_get(&ofdev->dev, "ipg"); 246 + if (IS_ERR(clk_ipg)) 247 + goto err_notavail_ipg; 248 + if (clk_prepare_enable(clk_ipg)) 249 + goto err_notavail_ipg; 250 + priv = netdev_priv(dev_get_drvdata(&ofdev->dev)); 251 + priv->clk_ipg = clk_ipg; 252 + 253 + /* return the determined clock source rate */ 254 + return freq_calc; 255 + 256 + err_invalid: 257 + dev_err(&ofdev->dev, "invalid clock source specification\n"); 258 + /* clock source rate could not get determined */ 259 + return 0; 260 + 261 + err_notavail: 262 + dev_err(&ofdev->dev, "cannot acquire or setup bitrate clock source\n"); 263 + /* clock source rate could not get determined */ 264 + return 0; 265 + 266 + err_notavail_ipg: 267 + dev_err(&ofdev->dev, "cannot acquire or setup register clock\n"); 268 + /* clock source rate could not get determined */ 269 + return 0; 270 + } 271 + 272 + static void mpc512x_can_put_clock(struct platform_device *ofdev) 273 + { 274 + struct mscan_priv *priv; 275 + 276 + priv = netdev_priv(dev_get_drvdata(&ofdev->dev)); 277 + if (priv->clk_ipg) 278 + clk_disable_unprepare(priv->clk_ipg); 279 + } 280 + 281 + #else /* COMMON_CLK */ 282 + 112 283 struct mpc512x_clockctl { 113 284 u32 spmr; /* System PLL Mode Reg */ 114 285 u32 sccr[2]; /* System Clk Ctrl Reg 1 & 2 */ ··· 410 239 of_node_put(np_clock); 411 240 return freq; 412 241 } 242 + 243 + #define mpc512x_can_put_clock NULL 244 + 245 + #endif /* COMMON_CLK */ 246 + 413 247 #else /* !CONFIG_PPC_MPC512x */ 414 248 static u32 mpc512x_can_get_clock(struct platform_device *ofdev, 415 249 const char *clock_name, int *mscan_clksrc) 416 250 { 417 251 return 0; 418 252 } 253 + #define mpc512x_can_put_clock NULL 419 254 #endif /* CONFIG_PPC_MPC512x */ 420 255 421 256 static const struct of_device_id mpc5xxx_can_table[]; ··· 563 386 static const struct mpc5xxx_can_data mpc5200_can_data = { 564 387 .type = MSCAN_TYPE_MPC5200, 565 388 .get_clock = mpc52xx_can_get_clock, 389 + /* .put_clock not applicable */ 566 390 }; 567 391 568 392 static const struct mpc5xxx_can_data mpc5121_can_data = { 569 393 .type = MSCAN_TYPE_MPC5121, 570 394 .get_clock = mpc512x_can_get_clock, 395 + .put_clock = mpc512x_can_put_clock, 571 396 }; 572 397 573 398 static const struct of_device_id mpc5xxx_can_table[] = {