.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
---|
1 | 2 | /* |
---|
2 | 3 | * Rockchip emmc PHY driver |
---|
3 | 4 | * |
---|
4 | 5 | * Copyright (C) 2016 Shawn Lin <shawn.lin@rock-chips.com> |
---|
5 | 6 | * Copyright (C) 2016 ROCKCHIP, Inc. |
---|
6 | | - * |
---|
7 | | - * This program is free software; you can redistribute it and/or modify |
---|
8 | | - * it under the terms of the GNU General Public License as published by |
---|
9 | | - * the Free Software Foundation; either version 2 of the License. |
---|
10 | | - * |
---|
11 | | - * This program is distributed in the hope that it will be useful, |
---|
12 | | - * but WITHOUT ANY WARRANTY; without even the implied warranty of |
---|
13 | | - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
---|
14 | | - * GNU General Public License for more details. |
---|
15 | 7 | */ |
---|
16 | 8 | |
---|
17 | 9 | #include <linux/clk.h> |
---|
.. | .. |
---|
87 | 79 | unsigned int reg_offset; |
---|
88 | 80 | struct regmap *reg_base; |
---|
89 | 81 | struct clk *emmcclk; |
---|
| 82 | + unsigned int drive_impedance; |
---|
90 | 83 | }; |
---|
91 | 84 | |
---|
92 | 85 | static int rockchip_emmc_phy_power(struct phy *phy, bool on_off) |
---|
.. | .. |
---|
176 | 169 | ret = regmap_read_poll_timeout(rk_phy->reg_base, |
---|
177 | 170 | rk_phy->reg_offset + GRF_EMMCPHY_STATUS, |
---|
178 | 171 | caldone, PHYCTRL_IS_CALDONE(caldone), |
---|
179 | | - 0, 500); |
---|
| 172 | + 0, 50); |
---|
180 | 173 | if (ret) { |
---|
181 | 174 | pr_err("%s: caldone failed, ret=%d\n", __func__, ret); |
---|
182 | 175 | return ret; |
---|
.. | .. |
---|
247 | 240 | * - SDHCI driver to get the PHY |
---|
248 | 241 | * - SDHCI driver to init the PHY |
---|
249 | 242 | * |
---|
250 | | - * The clock is optional, so upon any error we just set to NULL. |
---|
| 243 | + * The clock is optional, using clk_get_optional() to get the clock |
---|
| 244 | + * and do error processing if the return value != NULL |
---|
251 | 245 | * |
---|
252 | 246 | * NOTE: we don't do anything special for EPROBE_DEFER here. Given the |
---|
253 | 247 | * above expected use case, EPROBE_DEFER isn't sensible to expect, so |
---|
254 | 248 | * it's just like any other error. |
---|
255 | 249 | */ |
---|
256 | | - rk_phy->emmcclk = clk_get(&phy->dev, "emmcclk"); |
---|
| 250 | + rk_phy->emmcclk = clk_get_optional(&phy->dev, "emmcclk"); |
---|
257 | 251 | if (IS_ERR(rk_phy->emmcclk)) { |
---|
258 | | - dev_dbg(&phy->dev, "Error getting emmcclk: %d\n", ret); |
---|
| 252 | + ret = PTR_ERR(rk_phy->emmcclk); |
---|
| 253 | + dev_err(&phy->dev, "Error getting emmcclk: %d\n", ret); |
---|
259 | 254 | rk_phy->emmcclk = NULL; |
---|
260 | 255 | } |
---|
261 | 256 | |
---|
.. | .. |
---|
281 | 276 | { |
---|
282 | 277 | struct rockchip_emmc_phy *rk_phy = phy_get_drvdata(phy); |
---|
283 | 278 | |
---|
284 | | - /* Drive impedance: 50 Ohm */ |
---|
| 279 | + /* Drive impedance: from DTS */ |
---|
285 | 280 | regmap_write(rk_phy->reg_base, |
---|
286 | 281 | rk_phy->reg_offset + GRF_EMMCPHY_CON6, |
---|
287 | | - HIWORD_UPDATE(PHYCTRL_DR_50OHM, |
---|
| 282 | + HIWORD_UPDATE(rk_phy->drive_impedance, |
---|
288 | 283 | PHYCTRL_DR_MASK, |
---|
289 | 284 | PHYCTRL_DR_SHIFT)); |
---|
290 | 285 | |
---|
.. | .. |
---|
314 | 309 | .owner = THIS_MODULE, |
---|
315 | 310 | }; |
---|
316 | 311 | |
---|
| 312 | +static u32 convert_drive_impedance_ohm(struct platform_device *pdev, u32 dr_ohm) |
---|
| 313 | +{ |
---|
| 314 | + switch (dr_ohm) { |
---|
| 315 | + case 100: |
---|
| 316 | + return PHYCTRL_DR_100OHM; |
---|
| 317 | + case 66: |
---|
| 318 | + return PHYCTRL_DR_66OHM; |
---|
| 319 | + case 50: |
---|
| 320 | + return PHYCTRL_DR_50OHM; |
---|
| 321 | + case 40: |
---|
| 322 | + return PHYCTRL_DR_40OHM; |
---|
| 323 | + case 33: |
---|
| 324 | + return PHYCTRL_DR_33OHM; |
---|
| 325 | + } |
---|
| 326 | + |
---|
| 327 | + dev_warn(&pdev->dev, "Invalid value %u for drive-impedance-ohm.\n", |
---|
| 328 | + dr_ohm); |
---|
| 329 | + return PHYCTRL_DR_50OHM; |
---|
| 330 | +} |
---|
| 331 | + |
---|
317 | 332 | static int rockchip_emmc_phy_probe(struct platform_device *pdev) |
---|
318 | 333 | { |
---|
319 | 334 | struct device *dev = &pdev->dev; |
---|
.. | .. |
---|
322 | 337 | struct phy_provider *phy_provider; |
---|
323 | 338 | struct regmap *grf; |
---|
324 | 339 | unsigned int reg_offset; |
---|
| 340 | + u32 val; |
---|
325 | 341 | |
---|
326 | 342 | if (!dev->parent || !dev->parent->of_node) |
---|
327 | 343 | return -ENODEV; |
---|
.. | .. |
---|
337 | 353 | return -ENOMEM; |
---|
338 | 354 | |
---|
339 | 355 | if (of_property_read_u32(dev->of_node, "reg", ®_offset)) { |
---|
340 | | - dev_err(dev, "missing reg property in node %s\n", |
---|
341 | | - dev->of_node->name); |
---|
| 356 | + dev_err(dev, "missing reg property in node %pOFn\n", |
---|
| 357 | + dev->of_node); |
---|
342 | 358 | return -EINVAL; |
---|
343 | 359 | } |
---|
344 | 360 | |
---|
345 | 361 | rk_phy->reg_offset = reg_offset; |
---|
346 | 362 | rk_phy->reg_base = grf; |
---|
| 363 | + rk_phy->drive_impedance = PHYCTRL_DR_50OHM; |
---|
| 364 | + |
---|
| 365 | + if (!of_property_read_u32(dev->of_node, "drive-impedance-ohm", &val)) |
---|
| 366 | + rk_phy->drive_impedance = convert_drive_impedance_ohm(pdev, val); |
---|
347 | 367 | |
---|
348 | 368 | generic_phy = devm_phy_create(dev, dev->of_node, &ops); |
---|
349 | 369 | if (IS_ERR(generic_phy)) { |
---|