1*75a6faf6SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
257991ebaSAndrew Bresticker /*
357991ebaSAndrew Bresticker * IMG Pistachio USB PHY driver
457991ebaSAndrew Bresticker *
557991ebaSAndrew Bresticker * Copyright (C) 2015 Google, Inc.
657991ebaSAndrew Bresticker */
757991ebaSAndrew Bresticker
857991ebaSAndrew Bresticker #include <linux/clk.h>
957991ebaSAndrew Bresticker #include <linux/delay.h>
1057991ebaSAndrew Bresticker #include <linux/io.h>
1157991ebaSAndrew Bresticker #include <linux/kernel.h>
1257991ebaSAndrew Bresticker #include <linux/mfd/syscon.h>
1357991ebaSAndrew Bresticker #include <linux/module.h>
1457991ebaSAndrew Bresticker #include <linux/of.h>
1557991ebaSAndrew Bresticker #include <linux/phy/phy.h>
1657991ebaSAndrew Bresticker #include <linux/platform_device.h>
1757991ebaSAndrew Bresticker #include <linux/regmap.h>
1857991ebaSAndrew Bresticker
1957991ebaSAndrew Bresticker #include <dt-bindings/phy/phy-pistachio-usb.h>
2057991ebaSAndrew Bresticker
2157991ebaSAndrew Bresticker #define USB_PHY_CONTROL1 0x04
2257991ebaSAndrew Bresticker #define USB_PHY_CONTROL1_FSEL_SHIFT 2
2357991ebaSAndrew Bresticker #define USB_PHY_CONTROL1_FSEL_MASK 0x7
2457991ebaSAndrew Bresticker
2557991ebaSAndrew Bresticker #define USB_PHY_STRAP_CONTROL 0x10
2657991ebaSAndrew Bresticker #define USB_PHY_STRAP_CONTROL_REFCLK_SHIFT 4
2757991ebaSAndrew Bresticker #define USB_PHY_STRAP_CONTROL_REFCLK_MASK 0x3
2857991ebaSAndrew Bresticker
2957991ebaSAndrew Bresticker #define USB_PHY_STATUS 0x14
3057991ebaSAndrew Bresticker #define USB_PHY_STATUS_RX_PHY_CLK BIT(9)
3157991ebaSAndrew Bresticker #define USB_PHY_STATUS_RX_UTMI_CLK BIT(8)
3257991ebaSAndrew Bresticker #define USB_PHY_STATUS_VBUS_FAULT BIT(7)
3357991ebaSAndrew Bresticker
3457991ebaSAndrew Bresticker struct pistachio_usb_phy {
3557991ebaSAndrew Bresticker struct device *dev;
3657991ebaSAndrew Bresticker struct regmap *cr_top;
3757991ebaSAndrew Bresticker struct clk *phy_clk;
3857991ebaSAndrew Bresticker unsigned int refclk;
3957991ebaSAndrew Bresticker };
4057991ebaSAndrew Bresticker
4157991ebaSAndrew Bresticker static const unsigned long fsel_rate_map[] = {
4257991ebaSAndrew Bresticker 9600000,
4357991ebaSAndrew Bresticker 10000000,
4457991ebaSAndrew Bresticker 12000000,
4557991ebaSAndrew Bresticker 19200000,
4657991ebaSAndrew Bresticker 20000000,
4757991ebaSAndrew Bresticker 24000000,
4857991ebaSAndrew Bresticker 0,
4957991ebaSAndrew Bresticker 50000000,
5057991ebaSAndrew Bresticker };
5157991ebaSAndrew Bresticker
pistachio_usb_phy_power_on(struct phy * phy)5257991ebaSAndrew Bresticker static int pistachio_usb_phy_power_on(struct phy *phy)
5357991ebaSAndrew Bresticker {
5457991ebaSAndrew Bresticker struct pistachio_usb_phy *p_phy = phy_get_drvdata(phy);
5557991ebaSAndrew Bresticker unsigned long timeout, rate;
5657991ebaSAndrew Bresticker unsigned int i;
5757991ebaSAndrew Bresticker int ret;
5857991ebaSAndrew Bresticker
5957991ebaSAndrew Bresticker ret = clk_prepare_enable(p_phy->phy_clk);
6057991ebaSAndrew Bresticker if (ret < 0) {
6157991ebaSAndrew Bresticker dev_err(p_phy->dev, "Failed to enable PHY clock: %d\n", ret);
6257991ebaSAndrew Bresticker return ret;
6357991ebaSAndrew Bresticker }
6457991ebaSAndrew Bresticker
6557991ebaSAndrew Bresticker regmap_update_bits(p_phy->cr_top, USB_PHY_STRAP_CONTROL,
6657991ebaSAndrew Bresticker USB_PHY_STRAP_CONTROL_REFCLK_MASK <<
6757991ebaSAndrew Bresticker USB_PHY_STRAP_CONTROL_REFCLK_SHIFT,
6857991ebaSAndrew Bresticker p_phy->refclk << USB_PHY_STRAP_CONTROL_REFCLK_SHIFT);
6957991ebaSAndrew Bresticker
7057991ebaSAndrew Bresticker rate = clk_get_rate(p_phy->phy_clk);
7157991ebaSAndrew Bresticker if (p_phy->refclk == REFCLK_XO_CRYSTAL && rate != 12000000) {
7257991ebaSAndrew Bresticker dev_err(p_phy->dev, "Unsupported rate for XO crystal: %ld\n",
7357991ebaSAndrew Bresticker rate);
7457991ebaSAndrew Bresticker ret = -EINVAL;
7557991ebaSAndrew Bresticker goto disable_clk;
7657991ebaSAndrew Bresticker }
7757991ebaSAndrew Bresticker
7857991ebaSAndrew Bresticker for (i = 0; i < ARRAY_SIZE(fsel_rate_map); i++) {
7957991ebaSAndrew Bresticker if (rate == fsel_rate_map[i])
8057991ebaSAndrew Bresticker break;
8157991ebaSAndrew Bresticker }
8257991ebaSAndrew Bresticker if (i == ARRAY_SIZE(fsel_rate_map)) {
8357991ebaSAndrew Bresticker dev_err(p_phy->dev, "Unsupported clock rate: %lu\n", rate);
8457991ebaSAndrew Bresticker ret = -EINVAL;
8557991ebaSAndrew Bresticker goto disable_clk;
8657991ebaSAndrew Bresticker }
8757991ebaSAndrew Bresticker
8857991ebaSAndrew Bresticker regmap_update_bits(p_phy->cr_top, USB_PHY_CONTROL1,
8957991ebaSAndrew Bresticker USB_PHY_CONTROL1_FSEL_MASK <<
9057991ebaSAndrew Bresticker USB_PHY_CONTROL1_FSEL_SHIFT,
9157991ebaSAndrew Bresticker i << USB_PHY_CONTROL1_FSEL_SHIFT);
9257991ebaSAndrew Bresticker
9357991ebaSAndrew Bresticker timeout = jiffies + msecs_to_jiffies(200);
9457991ebaSAndrew Bresticker while (time_before(jiffies, timeout)) {
9557991ebaSAndrew Bresticker unsigned int val;
9657991ebaSAndrew Bresticker
9757991ebaSAndrew Bresticker regmap_read(p_phy->cr_top, USB_PHY_STATUS, &val);
9857991ebaSAndrew Bresticker if (val & USB_PHY_STATUS_VBUS_FAULT) {
9957991ebaSAndrew Bresticker dev_err(p_phy->dev, "VBUS fault detected\n");
10057991ebaSAndrew Bresticker ret = -EIO;
10157991ebaSAndrew Bresticker goto disable_clk;
10257991ebaSAndrew Bresticker }
10357991ebaSAndrew Bresticker if ((val & USB_PHY_STATUS_RX_PHY_CLK) &&
10457991ebaSAndrew Bresticker (val & USB_PHY_STATUS_RX_UTMI_CLK))
10557991ebaSAndrew Bresticker return 0;
10657991ebaSAndrew Bresticker usleep_range(1000, 1500);
10757991ebaSAndrew Bresticker }
10857991ebaSAndrew Bresticker
10957991ebaSAndrew Bresticker dev_err(p_phy->dev, "Timed out waiting for PHY to power on\n");
11057991ebaSAndrew Bresticker ret = -ETIMEDOUT;
11157991ebaSAndrew Bresticker
11257991ebaSAndrew Bresticker disable_clk:
11357991ebaSAndrew Bresticker clk_disable_unprepare(p_phy->phy_clk);
11457991ebaSAndrew Bresticker return ret;
11557991ebaSAndrew Bresticker }
11657991ebaSAndrew Bresticker
pistachio_usb_phy_power_off(struct phy * phy)11757991ebaSAndrew Bresticker static int pistachio_usb_phy_power_off(struct phy *phy)
11857991ebaSAndrew Bresticker {
11957991ebaSAndrew Bresticker struct pistachio_usb_phy *p_phy = phy_get_drvdata(phy);
12057991ebaSAndrew Bresticker
12157991ebaSAndrew Bresticker clk_disable_unprepare(p_phy->phy_clk);
12257991ebaSAndrew Bresticker
12357991ebaSAndrew Bresticker return 0;
12457991ebaSAndrew Bresticker }
12557991ebaSAndrew Bresticker
12657991ebaSAndrew Bresticker static const struct phy_ops pistachio_usb_phy_ops = {
12757991ebaSAndrew Bresticker .power_on = pistachio_usb_phy_power_on,
12857991ebaSAndrew Bresticker .power_off = pistachio_usb_phy_power_off,
12957991ebaSAndrew Bresticker .owner = THIS_MODULE,
13057991ebaSAndrew Bresticker };
13157991ebaSAndrew Bresticker
pistachio_usb_phy_probe(struct platform_device * pdev)13257991ebaSAndrew Bresticker static int pistachio_usb_phy_probe(struct platform_device *pdev)
13357991ebaSAndrew Bresticker {
13457991ebaSAndrew Bresticker struct pistachio_usb_phy *p_phy;
13557991ebaSAndrew Bresticker struct phy_provider *provider;
13657991ebaSAndrew Bresticker struct phy *phy;
13757991ebaSAndrew Bresticker int ret;
13857991ebaSAndrew Bresticker
13957991ebaSAndrew Bresticker p_phy = devm_kzalloc(&pdev->dev, sizeof(*p_phy), GFP_KERNEL);
14057991ebaSAndrew Bresticker if (!p_phy)
14157991ebaSAndrew Bresticker return -ENOMEM;
14257991ebaSAndrew Bresticker p_phy->dev = &pdev->dev;
14357991ebaSAndrew Bresticker platform_set_drvdata(pdev, p_phy);
14457991ebaSAndrew Bresticker
14557991ebaSAndrew Bresticker p_phy->cr_top = syscon_regmap_lookup_by_phandle(p_phy->dev->of_node,
14657991ebaSAndrew Bresticker "img,cr-top");
14757991ebaSAndrew Bresticker if (IS_ERR(p_phy->cr_top)) {
14857991ebaSAndrew Bresticker dev_err(p_phy->dev, "Failed to get CR_TOP registers: %ld\n",
14957991ebaSAndrew Bresticker PTR_ERR(p_phy->cr_top));
15057991ebaSAndrew Bresticker return PTR_ERR(p_phy->cr_top);
15157991ebaSAndrew Bresticker }
15257991ebaSAndrew Bresticker
15357991ebaSAndrew Bresticker p_phy->phy_clk = devm_clk_get(p_phy->dev, "usb_phy");
15457991ebaSAndrew Bresticker if (IS_ERR(p_phy->phy_clk)) {
15557991ebaSAndrew Bresticker dev_err(p_phy->dev, "Failed to get usb_phy clock: %ld\n",
15657991ebaSAndrew Bresticker PTR_ERR(p_phy->phy_clk));
15757991ebaSAndrew Bresticker return PTR_ERR(p_phy->phy_clk);
15857991ebaSAndrew Bresticker }
15957991ebaSAndrew Bresticker
16057991ebaSAndrew Bresticker ret = of_property_read_u32(p_phy->dev->of_node, "img,refclk",
16157991ebaSAndrew Bresticker &p_phy->refclk);
16257991ebaSAndrew Bresticker if (ret < 0) {
16357991ebaSAndrew Bresticker dev_err(p_phy->dev, "No reference clock selector specified\n");
16457991ebaSAndrew Bresticker return ret;
16557991ebaSAndrew Bresticker }
16657991ebaSAndrew Bresticker
16757991ebaSAndrew Bresticker phy = devm_phy_create(p_phy->dev, NULL, &pistachio_usb_phy_ops);
16857991ebaSAndrew Bresticker if (IS_ERR(phy)) {
16957991ebaSAndrew Bresticker dev_err(p_phy->dev, "Failed to create PHY: %ld\n",
17057991ebaSAndrew Bresticker PTR_ERR(phy));
17157991ebaSAndrew Bresticker return PTR_ERR(phy);
17257991ebaSAndrew Bresticker }
17357991ebaSAndrew Bresticker phy_set_drvdata(phy, p_phy);
17457991ebaSAndrew Bresticker
17557991ebaSAndrew Bresticker provider = devm_of_phy_provider_register(p_phy->dev,
17657991ebaSAndrew Bresticker of_phy_simple_xlate);
17757991ebaSAndrew Bresticker if (IS_ERR(provider)) {
17857991ebaSAndrew Bresticker dev_err(p_phy->dev, "Failed to register PHY provider: %ld\n",
17957991ebaSAndrew Bresticker PTR_ERR(provider));
18057991ebaSAndrew Bresticker return PTR_ERR(provider);
18157991ebaSAndrew Bresticker }
18257991ebaSAndrew Bresticker
18357991ebaSAndrew Bresticker return 0;
18457991ebaSAndrew Bresticker }
18557991ebaSAndrew Bresticker
18657991ebaSAndrew Bresticker static const struct of_device_id pistachio_usb_phy_of_match[] = {
18757991ebaSAndrew Bresticker { .compatible = "img,pistachio-usb-phy", },
18857991ebaSAndrew Bresticker { },
18957991ebaSAndrew Bresticker };
19057991ebaSAndrew Bresticker MODULE_DEVICE_TABLE(of, pistachio_usb_phy_of_match);
19157991ebaSAndrew Bresticker
19257991ebaSAndrew Bresticker static struct platform_driver pistachio_usb_phy_driver = {
19357991ebaSAndrew Bresticker .probe = pistachio_usb_phy_probe,
19457991ebaSAndrew Bresticker .driver = {
19557991ebaSAndrew Bresticker .name = "pistachio-usb-phy",
19657991ebaSAndrew Bresticker .of_match_table = pistachio_usb_phy_of_match,
19757991ebaSAndrew Bresticker },
19857991ebaSAndrew Bresticker };
19957991ebaSAndrew Bresticker module_platform_driver(pistachio_usb_phy_driver);
20057991ebaSAndrew Bresticker
20157991ebaSAndrew Bresticker MODULE_AUTHOR("Andrew Bresticker <abrestic@chromium.org>");
20257991ebaSAndrew Bresticker MODULE_DESCRIPTION("IMG Pistachio USB2.0 PHY driver");
20357991ebaSAndrew Bresticker MODULE_LICENSE("GPL v2");
204