brintos

brintos / linux-shallow public Read only

0
0
Text · 3.4 KiB · da6f290 Raw
146 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3 * Copyright (C) 2018 John Crispin <john@phrozen.org>4 *5 * Based on code from6 * Allwinner Technology Co., Ltd. <www.allwinnertech.com>7 *8 */9 10#include <linux/delay.h>11#include <linux/err.h>12#include <linux/io.h>13#include <linux/kernel.h>14#include <linux/module.h>15#include <linux/mutex.h>16#include <linux/of.h>17#include <linux/phy/phy.h>18#include <linux/platform_device.h>19#include <linux/reset.h>20 21struct ipq4019_usb_phy {22	struct device		*dev;23	struct phy		*phy;24	void __iomem		*base;25	struct reset_control	*por_rst;26	struct reset_control	*srif_rst;27};28 29static int ipq4019_ss_phy_power_off(struct phy *_phy)30{31	struct ipq4019_usb_phy *phy = phy_get_drvdata(_phy);32 33	reset_control_assert(phy->por_rst);34	msleep(10);35 36	return 0;37}38 39static int ipq4019_ss_phy_power_on(struct phy *_phy)40{41	struct ipq4019_usb_phy *phy = phy_get_drvdata(_phy);42 43	ipq4019_ss_phy_power_off(_phy);44 45	reset_control_deassert(phy->por_rst);46 47	return 0;48}49 50static const struct phy_ops ipq4019_usb_ss_phy_ops = {51	.power_on	= ipq4019_ss_phy_power_on,52	.power_off	= ipq4019_ss_phy_power_off,53};54 55static int ipq4019_hs_phy_power_off(struct phy *_phy)56{57	struct ipq4019_usb_phy *phy = phy_get_drvdata(_phy);58 59	reset_control_assert(phy->por_rst);60	msleep(10);61 62	reset_control_assert(phy->srif_rst);63	msleep(10);64 65	return 0;66}67 68static int ipq4019_hs_phy_power_on(struct phy *_phy)69{70	struct ipq4019_usb_phy *phy = phy_get_drvdata(_phy);71 72	ipq4019_hs_phy_power_off(_phy);73 74	reset_control_deassert(phy->srif_rst);75	msleep(10);76 77	reset_control_deassert(phy->por_rst);78 79	return 0;80}81 82static const struct phy_ops ipq4019_usb_hs_phy_ops = {83	.power_on	= ipq4019_hs_phy_power_on,84	.power_off	= ipq4019_hs_phy_power_off,85};86 87static const struct of_device_id ipq4019_usb_phy_of_match[] = {88	{ .compatible = "qcom,usb-hs-ipq4019-phy", .data = &ipq4019_usb_hs_phy_ops},89	{ .compatible = "qcom,usb-ss-ipq4019-phy", .data = &ipq4019_usb_ss_phy_ops},90	{ },91};92MODULE_DEVICE_TABLE(of, ipq4019_usb_phy_of_match);93 94static int ipq4019_usb_phy_probe(struct platform_device *pdev)95{96	struct device *dev = &pdev->dev;97	struct phy_provider *phy_provider;98	struct ipq4019_usb_phy *phy;99 100	phy = devm_kzalloc(dev, sizeof(*phy), GFP_KERNEL);101	if (!phy)102		return -ENOMEM;103 104	phy->dev = &pdev->dev;105	phy->base = devm_platform_ioremap_resource(pdev, 0);106	if (IS_ERR(phy->base)) {107		dev_err(dev, "failed to remap register memory\n");108		return PTR_ERR(phy->base);109	}110 111	phy->por_rst = devm_reset_control_get(phy->dev, "por_rst");112	if (IS_ERR(phy->por_rst)) {113		if (PTR_ERR(phy->por_rst) != -EPROBE_DEFER)114			dev_err(dev, "POR reset is missing\n");115		return PTR_ERR(phy->por_rst);116	}117 118	phy->srif_rst = devm_reset_control_get_optional(phy->dev, "srif_rst");119	if (IS_ERR(phy->srif_rst))120		return PTR_ERR(phy->srif_rst);121 122	phy->phy = devm_phy_create(dev, NULL, of_device_get_match_data(dev));123	if (IS_ERR(phy->phy)) {124		dev_err(dev, "failed to create PHY\n");125		return PTR_ERR(phy->phy);126	}127	phy_set_drvdata(phy->phy, phy);128 129	phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);130 131	return PTR_ERR_OR_ZERO(phy_provider);132}133 134static struct platform_driver ipq4019_usb_phy_driver = {135	.probe	= ipq4019_usb_phy_probe,136	.driver = {137		.of_match_table	= ipq4019_usb_phy_of_match,138		.name  = "ipq4019-usb-phy",139	}140};141module_platform_driver(ipq4019_usb_phy_driver);142 143MODULE_DESCRIPTION("QCOM/IPQ4019 USB phy driver");144MODULE_AUTHOR("John Crispin <john@phrozen.org>");145MODULE_LICENSE("GPL v2");146