linux_dsm_epyc7002/drivers/phy/qualcomm/phy-qcom-usb-hsic.c
Vivek Gautam 0b56e9a7e8 phy: Group vendor specific phy drivers
Adding vendor specific directories in phy to group
phy drivers under their respective vendor umbrella.

Also updated the MAINTAINERS file to reflect the correct
directory structure for phy drivers.

Signed-off-by: Vivek Gautam <vivek.gautam@codeaurora.org>
Acked-by: Heiko Stuebner <heiko@sntech.de>
Acked-by: Viresh Kumar <viresh.kumar@linaro.org>
Acked-by: Krzysztof Kozlowski <krzk@kernel.org>
Acked-by: Yoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com>
Reviewed-by: Jaehoon Chung <jh80.chung@samsung.com>
Cc: Kishon Vijay Abraham I <kishon@ti.com>
Cc: David S. Miller <davem@davemloft.net>
Cc: Geert Uytterhoeven <geert+renesas@glider.be>
Cc: Yoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com>
Cc: Guenter Roeck <linux@roeck-us.net>
Cc: Heiko Stuebner <heiko@sntech.de>
Cc: Viresh Kumar <viresh.kumar@linaro.org>
Cc: Maxime Ripard <maxime.ripard@free-electrons.com>
Cc: Chen-Yu Tsai <wens@csie.org>
Cc: Sylwester Nawrocki <s.nawrocki@samsung.com>
Cc: Krzysztof Kozlowski <krzk@kernel.org>
Cc: Jaehoon Chung <jh80.chung@samsung.com>
Cc: Stephen Boyd <stephen.boyd@linaro.org>
Cc: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
Cc: linux-arm-kernel@lists.infradead.org
Cc: linux-arm-msm@vger.kernel.org
Cc: linux-kernel@vger.kernel.org
Cc: linux-omap@vger.kernel.org
Cc: linux-renesas-soc@vger.kernel.org
Cc: linux-rockchip@lists.infradead.org
Cc: linux-samsung-soc@vger.kernel.org
Cc: linux-usb@vger.kernel.org
Signed-off-by: Kishon Vijay Abraham I <kishon@ti.com>
2017-06-01 15:28:33 +05:30

160 lines
3.8 KiB
C

/**
* Copyright (C) 2016 Linaro Ltd
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/module.h>
#include <linux/ulpi/driver.h>
#include <linux/ulpi/regs.h>
#include <linux/phy/phy.h>
#include <linux/pinctrl/consumer.h>
#include <linux/pinctrl/pinctrl-state.h>
#include <linux/delay.h>
#include <linux/clk.h>
#define ULPI_HSIC_CFG 0x30
#define ULPI_HSIC_IO_CAL 0x33
struct qcom_usb_hsic_phy {
struct ulpi *ulpi;
struct phy *phy;
struct pinctrl *pctl;
struct clk *phy_clk;
struct clk *cal_clk;
struct clk *cal_sleep_clk;
};
static int qcom_usb_hsic_phy_power_on(struct phy *phy)
{
struct qcom_usb_hsic_phy *uphy = phy_get_drvdata(phy);
struct ulpi *ulpi = uphy->ulpi;
struct pinctrl_state *pins_default;
int ret;
ret = clk_prepare_enable(uphy->phy_clk);
if (ret)
return ret;
ret = clk_prepare_enable(uphy->cal_clk);
if (ret)
goto err_cal;
ret = clk_prepare_enable(uphy->cal_sleep_clk);
if (ret)
goto err_sleep;
/* Set periodic calibration interval to ~2.048sec in HSIC_IO_CAL_REG */
ret = ulpi_write(ulpi, ULPI_HSIC_IO_CAL, 0xff);
if (ret)
goto err_ulpi;
/* Enable periodic IO calibration in HSIC_CFG register */
ret = ulpi_write(ulpi, ULPI_HSIC_CFG, 0xa8);
if (ret)
goto err_ulpi;
/* Configure pins for HSIC functionality */
pins_default = pinctrl_lookup_state(uphy->pctl, PINCTRL_STATE_DEFAULT);
if (IS_ERR(pins_default))
return PTR_ERR(pins_default);
ret = pinctrl_select_state(uphy->pctl, pins_default);
if (ret)
goto err_ulpi;
/* Enable HSIC mode in HSIC_CFG register */
ret = ulpi_write(ulpi, ULPI_SET(ULPI_HSIC_CFG), 0x01);
if (ret)
goto err_ulpi;
/* Disable auto-resume */
ret = ulpi_write(ulpi, ULPI_CLR(ULPI_IFC_CTRL),
ULPI_IFC_CTRL_AUTORESUME);
if (ret)
goto err_ulpi;
return ret;
err_ulpi:
clk_disable_unprepare(uphy->cal_sleep_clk);
err_sleep:
clk_disable_unprepare(uphy->cal_clk);
err_cal:
clk_disable_unprepare(uphy->phy_clk);
return ret;
}
static int qcom_usb_hsic_phy_power_off(struct phy *phy)
{
struct qcom_usb_hsic_phy *uphy = phy_get_drvdata(phy);
clk_disable_unprepare(uphy->cal_sleep_clk);
clk_disable_unprepare(uphy->cal_clk);
clk_disable_unprepare(uphy->phy_clk);
return 0;
}
static const struct phy_ops qcom_usb_hsic_phy_ops = {
.power_on = qcom_usb_hsic_phy_power_on,
.power_off = qcom_usb_hsic_phy_power_off,
.owner = THIS_MODULE,
};
static int qcom_usb_hsic_phy_probe(struct ulpi *ulpi)
{
struct qcom_usb_hsic_phy *uphy;
struct phy_provider *p;
struct clk *clk;
uphy = devm_kzalloc(&ulpi->dev, sizeof(*uphy), GFP_KERNEL);
if (!uphy)
return -ENOMEM;
ulpi_set_drvdata(ulpi, uphy);
uphy->ulpi = ulpi;
uphy->pctl = devm_pinctrl_get(&ulpi->dev);
if (IS_ERR(uphy->pctl))
return PTR_ERR(uphy->pctl);
uphy->phy_clk = clk = devm_clk_get(&ulpi->dev, "phy");
if (IS_ERR(clk))
return PTR_ERR(clk);
uphy->cal_clk = clk = devm_clk_get(&ulpi->dev, "cal");
if (IS_ERR(clk))
return PTR_ERR(clk);
uphy->cal_sleep_clk = clk = devm_clk_get(&ulpi->dev, "cal_sleep");
if (IS_ERR(clk))
return PTR_ERR(clk);
uphy->phy = devm_phy_create(&ulpi->dev, ulpi->dev.of_node,
&qcom_usb_hsic_phy_ops);
if (IS_ERR(uphy->phy))
return PTR_ERR(uphy->phy);
phy_set_drvdata(uphy->phy, uphy);
p = devm_of_phy_provider_register(&ulpi->dev, of_phy_simple_xlate);
return PTR_ERR_OR_ZERO(p);
}
static const struct of_device_id qcom_usb_hsic_phy_match[] = {
{ .compatible = "qcom,usb-hsic-phy", },
{ }
};
MODULE_DEVICE_TABLE(of, qcom_usb_hsic_phy_match);
static struct ulpi_driver qcom_usb_hsic_phy_driver = {
.probe = qcom_usb_hsic_phy_probe,
.driver = {
.name = "qcom_usb_hsic_phy",
.of_match_table = qcom_usb_hsic_phy_match,
},
};
module_ulpi_driver(qcom_usb_hsic_phy_driver);
MODULE_DESCRIPTION("Qualcomm USB HSIC phy");
MODULE_LICENSE("GPL v2");