Until now, the MDIO bus will have the hardware default bus frequency. Read the desired frequency of the bus from the device tree and configure it.
Unified · Split
| @@ -7,6 +7,7 @@ · 6 unmodified lines | ||
| 7 | 7 | */ |
| 8 | 8 | |
| 9 | 9 | #include <linux/bitops.h> |
| 10 | +#include <linux/clk.h> | |
| 10 | 11 | #include <linux/io.h> |
| 11 | 12 | #include <linux/iopoll.h> |
| 12 | 13 | #include <linux/kernel.h> |
| @@ -30,6 +31,8 @@ · 17 unmodified lines | ||
| 30 | 31 | #define MSCC_MIIM_CMD_VLD BIT(31) |
| 31 | 32 | #define MSCC_MIIM_REG_DATA 0xC |
| 32 | 33 | #define MSCC_MIIM_DATA_ERROR (BIT(16) | BIT(17)) |
| 34 | +#define MSCC_MIIM_REG_CFG 0x10 | |
| 35 | +#define MSCC_MIIM_CFG_PRESCALE_MASK GENMASK(7, 0) | |
| 33 | 36 | |
| 34 | 37 | #define MSCC_PHY_REG_PHY_CFG 0x0 |
| 35 | 38 | #define PHY_CFG_PHY_ENA (BIT(0) | BIT(1) | BIT(2) | BIT(3)) |
| @@ -50,6 +53,8 @@ struct mscc_miim_dev { · 14 unmodified lines | ||
| 50 | 53 | int mii_status_offset; |
| 51 | 54 | struct regmap *phy_regs; |
| 52 | 55 | const struct mscc_miim_info *info; |
| 56 | + struct clk *clk; | |
| 57 | + u32 bus_freq; | |
| 53 | 58 | }; |
| 54 | 59 | |
| 55 | 60 | /* When high resolution timers aren't built-in: we can't use usleep_range() as |
| @@ -235,9 +240,32 @@ int mscc_miim_setup(struct device *dev, struct mii_bus **pbus, const char *name, · 179 unmodified lines | ||
| 235 | 240 | } |
| 236 | 241 | EXPORT_SYMBOL(mscc_miim_setup); |
| 237 | 242 | |
| 243 | +static int mscc_miim_clk_set(struct mii_bus *bus) | |
| 244 | +{ | |
| 245 | + struct mscc_miim_dev *miim = bus->priv; | |
| 246 | + unsigned long rate; | |
| 247 | + u32 div; | |
| 248 | + | |
| 249 | + /* Keep the current settings */ | |
| 250 | + if (!miim->bus_freq) | |
| 251 | + return 0; | |
| 252 | + | |
| 253 | + rate = clk_get_rate(miim->clk); | |
| 254 | + | |
| 255 | + div = DIV_ROUND_UP(rate, 2 * miim->bus_freq) - 1; | |
| 256 | + if (div == 0 || div & ~MSCC_MIIM_CFG_PRESCALE_MASK) { | |
| 257 | + dev_err(&bus->dev, "Incorrect MDIO clock frequency\n"); | |
| 258 | + return -EINVAL; | |
| 259 | + } | |
| 260 | + | |
| 261 | + return regmap_update_bits(miim->regs, MSCC_MIIM_REG_CFG, | |
| 262 | + MSCC_MIIM_CFG_PRESCALE_MASK, div); | |
| 263 | +} | |
| 264 | + | |
| 238 | 265 | static int mscc_miim_probe(struct platform_device *pdev) |
| 239 | 266 | { |
| 240 | 267 | struct regmap *mii_regmap, *phy_regmap = NULL; |
| 268 | + struct device_node *np = pdev->dev.of_node; | |
| 241 | 269 | void __iomem *regs, *phy_regs; |
| 242 | 270 | struct mscc_miim_dev *miim; |
| 243 | 271 | struct resource *res; |
| @@ -288,21 +316,47 @@ static int mscc_miim_probe(struct platform_device *pdev) · 44 unmodified lines | ||
| 288 | 316 | if (!miim->info) |
| 289 | 317 | return -EINVAL; |
| 290 | 318 | |
| 291 | − ret = of_mdiobus_register(bus, pdev->dev.of_node); | |
| 319 | + miim->clk = devm_clk_get_optional(&pdev->dev, NULL); | |
| 320 | + if (IS_ERR(miim->clk)) | |
| 321 | + return PTR_ERR(miim->clk); | |
| 322 | + | |
| 323 | + of_property_read_u32(np, "clock-frequency", &miim->bus_freq); | |
| 324 | + | |
| 325 | + if (miim->bus_freq && !miim->clk) { | |
| 326 | + dev_err(&pdev->dev, | |
| 327 | + "cannot use clock-frequency without a clock\n"); | |
| 328 | + return -EINVAL; | |
| 329 | + } | |
| 330 | + | |
| 331 | + ret = clk_prepare_enable(miim->clk); | |
| 332 | + if (ret) | |
| 333 | + return ret; | |
| 334 | + | |
| 335 | + ret = mscc_miim_clk_set(bus); | |
| 336 | + if (ret) | |
| 337 | + goto out_disable_clk; | |
| 338 | + | |
| 339 | + ret = of_mdiobus_register(bus, np); | |
| 292 | 340 | if (ret < 0) { |
| 293 | 341 | dev_err(&pdev->dev, "Cannot register MDIO bus (%d)\n", ret); |
| 294 | − return ret; | |
| 342 | + goto out_disable_clk; | |
| 295 | 343 | } |
| 296 | 344 | |
| 297 | 345 | platform_set_drvdata(pdev, bus); |
| 298 | 346 | |
| 299 | 347 | return 0; |
| 348 | + | |
| 349 | +out_disable_clk: | |
| 350 | + clk_disable_unprepare(miim->clk); | |
| 351 | + return ret; | |
| 300 | 352 | } |
| 301 | 353 | |
| 302 | 354 | static int mscc_miim_remove(struct platform_device *pdev) |
| 303 | 355 | { |
| 304 | 356 | struct mii_bus *bus = platform_get_drvdata(pdev); |
| 357 | + struct mscc_miim_dev *miim = bus->priv; | |
| 305 | 358 | |
| 359 | + clk_disable_unprepare(miim->clk); | |
| 306 | 360 | mdiobus_unregister(bus); |
| 307 | 361 | |
| 308 | 362 | return 0; |