18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * omap-control-phy.c - The PHY part of control module.
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Copyright (C) 2013 Texas Instruments Incorporated - http://www.ti.com
68c2ecf20Sopenharmony_ci * Author: Kishon Vijay Abraham I <kishon@ti.com>
78c2ecf20Sopenharmony_ci */
88c2ecf20Sopenharmony_ci
98c2ecf20Sopenharmony_ci#include <linux/module.h>
108c2ecf20Sopenharmony_ci#include <linux/platform_device.h>
118c2ecf20Sopenharmony_ci#include <linux/slab.h>
128c2ecf20Sopenharmony_ci#include <linux/of.h>
138c2ecf20Sopenharmony_ci#include <linux/of_device.h>
148c2ecf20Sopenharmony_ci#include <linux/err.h>
158c2ecf20Sopenharmony_ci#include <linux/io.h>
168c2ecf20Sopenharmony_ci#include <linux/clk.h>
178c2ecf20Sopenharmony_ci#include <linux/phy/omap_control_phy.h>
188c2ecf20Sopenharmony_ci
198c2ecf20Sopenharmony_ci/**
208c2ecf20Sopenharmony_ci * omap_control_pcie_pcs - set the PCS delay count
218c2ecf20Sopenharmony_ci * @dev: the control module device
228c2ecf20Sopenharmony_ci * @delay: 8 bit delay value
238c2ecf20Sopenharmony_ci */
248c2ecf20Sopenharmony_civoid omap_control_pcie_pcs(struct device *dev, u8 delay)
258c2ecf20Sopenharmony_ci{
268c2ecf20Sopenharmony_ci	u32 val;
278c2ecf20Sopenharmony_ci	struct omap_control_phy	*control_phy;
288c2ecf20Sopenharmony_ci
298c2ecf20Sopenharmony_ci	if (IS_ERR(dev) || !dev) {
308c2ecf20Sopenharmony_ci		pr_err("%s: invalid device\n", __func__);
318c2ecf20Sopenharmony_ci		return;
328c2ecf20Sopenharmony_ci	}
338c2ecf20Sopenharmony_ci
348c2ecf20Sopenharmony_ci	control_phy = dev_get_drvdata(dev);
358c2ecf20Sopenharmony_ci	if (!control_phy) {
368c2ecf20Sopenharmony_ci		dev_err(dev, "%s: invalid control phy device\n", __func__);
378c2ecf20Sopenharmony_ci		return;
388c2ecf20Sopenharmony_ci	}
398c2ecf20Sopenharmony_ci
408c2ecf20Sopenharmony_ci	if (control_phy->type != OMAP_CTRL_TYPE_PCIE) {
418c2ecf20Sopenharmony_ci		dev_err(dev, "%s: unsupported operation\n", __func__);
428c2ecf20Sopenharmony_ci		return;
438c2ecf20Sopenharmony_ci	}
448c2ecf20Sopenharmony_ci
458c2ecf20Sopenharmony_ci	val = readl(control_phy->pcie_pcs);
468c2ecf20Sopenharmony_ci	val &= ~(OMAP_CTRL_PCIE_PCS_MASK <<
478c2ecf20Sopenharmony_ci		OMAP_CTRL_PCIE_PCS_DELAY_COUNT_SHIFT);
488c2ecf20Sopenharmony_ci	val |= (delay << OMAP_CTRL_PCIE_PCS_DELAY_COUNT_SHIFT);
498c2ecf20Sopenharmony_ci	writel(val, control_phy->pcie_pcs);
508c2ecf20Sopenharmony_ci}
518c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(omap_control_pcie_pcs);
528c2ecf20Sopenharmony_ci
538c2ecf20Sopenharmony_ci/**
548c2ecf20Sopenharmony_ci * omap_control_phy_power - power on/off the phy using control module reg
558c2ecf20Sopenharmony_ci * @dev: the control module device
568c2ecf20Sopenharmony_ci * @on: 0 or 1, based on powering on or off the PHY
578c2ecf20Sopenharmony_ci */
588c2ecf20Sopenharmony_civoid omap_control_phy_power(struct device *dev, int on)
598c2ecf20Sopenharmony_ci{
608c2ecf20Sopenharmony_ci	u32 val;
618c2ecf20Sopenharmony_ci	unsigned long rate;
628c2ecf20Sopenharmony_ci	struct omap_control_phy	*control_phy;
638c2ecf20Sopenharmony_ci
648c2ecf20Sopenharmony_ci	if (IS_ERR(dev) || !dev) {
658c2ecf20Sopenharmony_ci		pr_err("%s: invalid device\n", __func__);
668c2ecf20Sopenharmony_ci		return;
678c2ecf20Sopenharmony_ci	}
688c2ecf20Sopenharmony_ci
698c2ecf20Sopenharmony_ci	control_phy = dev_get_drvdata(dev);
708c2ecf20Sopenharmony_ci	if (!control_phy) {
718c2ecf20Sopenharmony_ci		dev_err(dev, "%s: invalid control phy device\n", __func__);
728c2ecf20Sopenharmony_ci		return;
738c2ecf20Sopenharmony_ci	}
748c2ecf20Sopenharmony_ci
758c2ecf20Sopenharmony_ci	if (control_phy->type == OMAP_CTRL_TYPE_OTGHS)
768c2ecf20Sopenharmony_ci		return;
778c2ecf20Sopenharmony_ci
788c2ecf20Sopenharmony_ci	val = readl(control_phy->power);
798c2ecf20Sopenharmony_ci
808c2ecf20Sopenharmony_ci	switch (control_phy->type) {
818c2ecf20Sopenharmony_ci	case OMAP_CTRL_TYPE_USB2:
828c2ecf20Sopenharmony_ci		if (on)
838c2ecf20Sopenharmony_ci			val &= ~OMAP_CTRL_DEV_PHY_PD;
848c2ecf20Sopenharmony_ci		else
858c2ecf20Sopenharmony_ci			val |= OMAP_CTRL_DEV_PHY_PD;
868c2ecf20Sopenharmony_ci		break;
878c2ecf20Sopenharmony_ci
888c2ecf20Sopenharmony_ci	case OMAP_CTRL_TYPE_PCIE:
898c2ecf20Sopenharmony_ci	case OMAP_CTRL_TYPE_PIPE3:
908c2ecf20Sopenharmony_ci		rate = clk_get_rate(control_phy->sys_clk);
918c2ecf20Sopenharmony_ci		rate = rate/1000000;
928c2ecf20Sopenharmony_ci
938c2ecf20Sopenharmony_ci		if (on) {
948c2ecf20Sopenharmony_ci			val &= ~(OMAP_CTRL_PIPE3_PHY_PWRCTL_CLK_CMD_MASK |
958c2ecf20Sopenharmony_ci				OMAP_CTRL_PIPE3_PHY_PWRCTL_CLK_FREQ_MASK);
968c2ecf20Sopenharmony_ci			val |= OMAP_CTRL_PIPE3_PHY_TX_RX_POWERON <<
978c2ecf20Sopenharmony_ci				OMAP_CTRL_PIPE3_PHY_PWRCTL_CLK_CMD_SHIFT;
988c2ecf20Sopenharmony_ci			val |= rate <<
998c2ecf20Sopenharmony_ci				OMAP_CTRL_PIPE3_PHY_PWRCTL_CLK_FREQ_SHIFT;
1008c2ecf20Sopenharmony_ci		} else {
1018c2ecf20Sopenharmony_ci			val &= ~OMAP_CTRL_PIPE3_PHY_PWRCTL_CLK_CMD_MASK;
1028c2ecf20Sopenharmony_ci			val |= OMAP_CTRL_PIPE3_PHY_TX_RX_POWEROFF <<
1038c2ecf20Sopenharmony_ci				OMAP_CTRL_PIPE3_PHY_PWRCTL_CLK_CMD_SHIFT;
1048c2ecf20Sopenharmony_ci		}
1058c2ecf20Sopenharmony_ci		break;
1068c2ecf20Sopenharmony_ci
1078c2ecf20Sopenharmony_ci	case OMAP_CTRL_TYPE_DRA7USB2:
1088c2ecf20Sopenharmony_ci		if (on)
1098c2ecf20Sopenharmony_ci			val &= ~OMAP_CTRL_USB2_PHY_PD;
1108c2ecf20Sopenharmony_ci		else
1118c2ecf20Sopenharmony_ci			val |= OMAP_CTRL_USB2_PHY_PD;
1128c2ecf20Sopenharmony_ci		break;
1138c2ecf20Sopenharmony_ci
1148c2ecf20Sopenharmony_ci	case OMAP_CTRL_TYPE_AM437USB2:
1158c2ecf20Sopenharmony_ci		if (on) {
1168c2ecf20Sopenharmony_ci			val &= ~(AM437X_CTRL_USB2_PHY_PD |
1178c2ecf20Sopenharmony_ci					AM437X_CTRL_USB2_OTG_PD);
1188c2ecf20Sopenharmony_ci			val |= (AM437X_CTRL_USB2_OTGVDET_EN |
1198c2ecf20Sopenharmony_ci					AM437X_CTRL_USB2_OTGSESSEND_EN);
1208c2ecf20Sopenharmony_ci		} else {
1218c2ecf20Sopenharmony_ci			val &= ~(AM437X_CTRL_USB2_OTGVDET_EN |
1228c2ecf20Sopenharmony_ci					AM437X_CTRL_USB2_OTGSESSEND_EN);
1238c2ecf20Sopenharmony_ci			val |= (AM437X_CTRL_USB2_PHY_PD |
1248c2ecf20Sopenharmony_ci					 AM437X_CTRL_USB2_OTG_PD);
1258c2ecf20Sopenharmony_ci		}
1268c2ecf20Sopenharmony_ci		break;
1278c2ecf20Sopenharmony_ci	default:
1288c2ecf20Sopenharmony_ci		dev_err(dev, "%s: type %d not recognized\n",
1298c2ecf20Sopenharmony_ci			__func__, control_phy->type);
1308c2ecf20Sopenharmony_ci		break;
1318c2ecf20Sopenharmony_ci	}
1328c2ecf20Sopenharmony_ci
1338c2ecf20Sopenharmony_ci	writel(val, control_phy->power);
1348c2ecf20Sopenharmony_ci}
1358c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(omap_control_phy_power);
1368c2ecf20Sopenharmony_ci
1378c2ecf20Sopenharmony_ci/**
1388c2ecf20Sopenharmony_ci * omap_control_usb_host_mode - set AVALID, VBUSVALID and ID pin in grounded
1398c2ecf20Sopenharmony_ci * @ctrl_phy: struct omap_control_phy *
1408c2ecf20Sopenharmony_ci *
1418c2ecf20Sopenharmony_ci * Writes to the mailbox register to notify the usb core that a usb
1428c2ecf20Sopenharmony_ci * device has been connected.
1438c2ecf20Sopenharmony_ci */
1448c2ecf20Sopenharmony_cistatic void omap_control_usb_host_mode(struct omap_control_phy *ctrl_phy)
1458c2ecf20Sopenharmony_ci{
1468c2ecf20Sopenharmony_ci	u32 val;
1478c2ecf20Sopenharmony_ci
1488c2ecf20Sopenharmony_ci	val = readl(ctrl_phy->otghs_control);
1498c2ecf20Sopenharmony_ci	val &= ~(OMAP_CTRL_DEV_IDDIG | OMAP_CTRL_DEV_SESSEND);
1508c2ecf20Sopenharmony_ci	val |= OMAP_CTRL_DEV_AVALID | OMAP_CTRL_DEV_VBUSVALID;
1518c2ecf20Sopenharmony_ci	writel(val, ctrl_phy->otghs_control);
1528c2ecf20Sopenharmony_ci}
1538c2ecf20Sopenharmony_ci
1548c2ecf20Sopenharmony_ci/**
1558c2ecf20Sopenharmony_ci * omap_control_usb_device_mode - set AVALID, VBUSVALID and ID pin in high
1568c2ecf20Sopenharmony_ci * impedance
1578c2ecf20Sopenharmony_ci * @ctrl_phy: struct omap_control_phy *
1588c2ecf20Sopenharmony_ci *
1598c2ecf20Sopenharmony_ci * Writes to the mailbox register to notify the usb core that it has been
1608c2ecf20Sopenharmony_ci * connected to a usb host.
1618c2ecf20Sopenharmony_ci */
1628c2ecf20Sopenharmony_cistatic void omap_control_usb_device_mode(struct omap_control_phy *ctrl_phy)
1638c2ecf20Sopenharmony_ci{
1648c2ecf20Sopenharmony_ci	u32 val;
1658c2ecf20Sopenharmony_ci
1668c2ecf20Sopenharmony_ci	val = readl(ctrl_phy->otghs_control);
1678c2ecf20Sopenharmony_ci	val &= ~OMAP_CTRL_DEV_SESSEND;
1688c2ecf20Sopenharmony_ci	val |= OMAP_CTRL_DEV_IDDIG | OMAP_CTRL_DEV_AVALID |
1698c2ecf20Sopenharmony_ci		OMAP_CTRL_DEV_VBUSVALID;
1708c2ecf20Sopenharmony_ci	writel(val, ctrl_phy->otghs_control);
1718c2ecf20Sopenharmony_ci}
1728c2ecf20Sopenharmony_ci
1738c2ecf20Sopenharmony_ci/**
1748c2ecf20Sopenharmony_ci * omap_control_usb_set_sessionend - Enable SESSIONEND and IDIG to high
1758c2ecf20Sopenharmony_ci * impedance
1768c2ecf20Sopenharmony_ci * @ctrl_phy: struct omap_control_phy *
1778c2ecf20Sopenharmony_ci *
1788c2ecf20Sopenharmony_ci * Writes to the mailbox register to notify the usb core it's now in
1798c2ecf20Sopenharmony_ci * disconnected state.
1808c2ecf20Sopenharmony_ci */
1818c2ecf20Sopenharmony_cistatic void omap_control_usb_set_sessionend(struct omap_control_phy *ctrl_phy)
1828c2ecf20Sopenharmony_ci{
1838c2ecf20Sopenharmony_ci	u32 val;
1848c2ecf20Sopenharmony_ci
1858c2ecf20Sopenharmony_ci	val = readl(ctrl_phy->otghs_control);
1868c2ecf20Sopenharmony_ci	val &= ~(OMAP_CTRL_DEV_AVALID | OMAP_CTRL_DEV_VBUSVALID);
1878c2ecf20Sopenharmony_ci	val |= OMAP_CTRL_DEV_IDDIG | OMAP_CTRL_DEV_SESSEND;
1888c2ecf20Sopenharmony_ci	writel(val, ctrl_phy->otghs_control);
1898c2ecf20Sopenharmony_ci}
1908c2ecf20Sopenharmony_ci
1918c2ecf20Sopenharmony_ci/**
1928c2ecf20Sopenharmony_ci * omap_control_usb_set_mode - Calls to functions to set USB in one of host mode
1938c2ecf20Sopenharmony_ci * or device mode or to denote disconnected state
1948c2ecf20Sopenharmony_ci * @dev: the control module device
1958c2ecf20Sopenharmony_ci * @mode: The mode to which usb should be configured
1968c2ecf20Sopenharmony_ci *
1978c2ecf20Sopenharmony_ci * This is an API to write to the mailbox register to notify the usb core that
1988c2ecf20Sopenharmony_ci * a usb device has been connected.
1998c2ecf20Sopenharmony_ci */
2008c2ecf20Sopenharmony_civoid omap_control_usb_set_mode(struct device *dev,
2018c2ecf20Sopenharmony_ci	enum omap_control_usb_mode mode)
2028c2ecf20Sopenharmony_ci{
2038c2ecf20Sopenharmony_ci	struct omap_control_phy	*ctrl_phy;
2048c2ecf20Sopenharmony_ci
2058c2ecf20Sopenharmony_ci	if (IS_ERR(dev) || !dev)
2068c2ecf20Sopenharmony_ci		return;
2078c2ecf20Sopenharmony_ci
2088c2ecf20Sopenharmony_ci	ctrl_phy = dev_get_drvdata(dev);
2098c2ecf20Sopenharmony_ci	if (!ctrl_phy) {
2108c2ecf20Sopenharmony_ci		dev_err(dev, "Invalid control phy device\n");
2118c2ecf20Sopenharmony_ci		return;
2128c2ecf20Sopenharmony_ci	}
2138c2ecf20Sopenharmony_ci
2148c2ecf20Sopenharmony_ci	if (ctrl_phy->type != OMAP_CTRL_TYPE_OTGHS)
2158c2ecf20Sopenharmony_ci		return;
2168c2ecf20Sopenharmony_ci
2178c2ecf20Sopenharmony_ci	switch (mode) {
2188c2ecf20Sopenharmony_ci	case USB_MODE_HOST:
2198c2ecf20Sopenharmony_ci		omap_control_usb_host_mode(ctrl_phy);
2208c2ecf20Sopenharmony_ci		break;
2218c2ecf20Sopenharmony_ci	case USB_MODE_DEVICE:
2228c2ecf20Sopenharmony_ci		omap_control_usb_device_mode(ctrl_phy);
2238c2ecf20Sopenharmony_ci		break;
2248c2ecf20Sopenharmony_ci	case USB_MODE_DISCONNECT:
2258c2ecf20Sopenharmony_ci		omap_control_usb_set_sessionend(ctrl_phy);
2268c2ecf20Sopenharmony_ci		break;
2278c2ecf20Sopenharmony_ci	default:
2288c2ecf20Sopenharmony_ci		dev_vdbg(dev, "invalid omap control usb mode\n");
2298c2ecf20Sopenharmony_ci	}
2308c2ecf20Sopenharmony_ci}
2318c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(omap_control_usb_set_mode);
2328c2ecf20Sopenharmony_ci
2338c2ecf20Sopenharmony_cistatic const enum omap_control_phy_type otghs_data = OMAP_CTRL_TYPE_OTGHS;
2348c2ecf20Sopenharmony_cistatic const enum omap_control_phy_type usb2_data = OMAP_CTRL_TYPE_USB2;
2358c2ecf20Sopenharmony_cistatic const enum omap_control_phy_type pipe3_data = OMAP_CTRL_TYPE_PIPE3;
2368c2ecf20Sopenharmony_cistatic const enum omap_control_phy_type pcie_data = OMAP_CTRL_TYPE_PCIE;
2378c2ecf20Sopenharmony_cistatic const enum omap_control_phy_type dra7usb2_data = OMAP_CTRL_TYPE_DRA7USB2;
2388c2ecf20Sopenharmony_cistatic const enum omap_control_phy_type am437usb2_data = OMAP_CTRL_TYPE_AM437USB2;
2398c2ecf20Sopenharmony_ci
2408c2ecf20Sopenharmony_cistatic const struct of_device_id omap_control_phy_id_table[] = {
2418c2ecf20Sopenharmony_ci	{
2428c2ecf20Sopenharmony_ci		.compatible = "ti,control-phy-otghs",
2438c2ecf20Sopenharmony_ci		.data = &otghs_data,
2448c2ecf20Sopenharmony_ci	},
2458c2ecf20Sopenharmony_ci	{
2468c2ecf20Sopenharmony_ci		.compatible = "ti,control-phy-usb2",
2478c2ecf20Sopenharmony_ci		.data = &usb2_data,
2488c2ecf20Sopenharmony_ci	},
2498c2ecf20Sopenharmony_ci	{
2508c2ecf20Sopenharmony_ci		.compatible = "ti,control-phy-pipe3",
2518c2ecf20Sopenharmony_ci		.data = &pipe3_data,
2528c2ecf20Sopenharmony_ci	},
2538c2ecf20Sopenharmony_ci	{
2548c2ecf20Sopenharmony_ci		.compatible = "ti,control-phy-pcie",
2558c2ecf20Sopenharmony_ci		.data = &pcie_data,
2568c2ecf20Sopenharmony_ci	},
2578c2ecf20Sopenharmony_ci	{
2588c2ecf20Sopenharmony_ci		.compatible = "ti,control-phy-usb2-dra7",
2598c2ecf20Sopenharmony_ci		.data = &dra7usb2_data,
2608c2ecf20Sopenharmony_ci	},
2618c2ecf20Sopenharmony_ci	{
2628c2ecf20Sopenharmony_ci		.compatible = "ti,control-phy-usb2-am437",
2638c2ecf20Sopenharmony_ci		.data = &am437usb2_data,
2648c2ecf20Sopenharmony_ci	},
2658c2ecf20Sopenharmony_ci	{},
2668c2ecf20Sopenharmony_ci};
2678c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, omap_control_phy_id_table);
2688c2ecf20Sopenharmony_ci
2698c2ecf20Sopenharmony_cistatic int omap_control_phy_probe(struct platform_device *pdev)
2708c2ecf20Sopenharmony_ci{
2718c2ecf20Sopenharmony_ci	struct resource	*res;
2728c2ecf20Sopenharmony_ci	const struct of_device_id *of_id;
2738c2ecf20Sopenharmony_ci	struct omap_control_phy *control_phy;
2748c2ecf20Sopenharmony_ci
2758c2ecf20Sopenharmony_ci	of_id = of_match_device(omap_control_phy_id_table, &pdev->dev);
2768c2ecf20Sopenharmony_ci	if (!of_id)
2778c2ecf20Sopenharmony_ci		return -EINVAL;
2788c2ecf20Sopenharmony_ci
2798c2ecf20Sopenharmony_ci	control_phy = devm_kzalloc(&pdev->dev, sizeof(*control_phy),
2808c2ecf20Sopenharmony_ci		GFP_KERNEL);
2818c2ecf20Sopenharmony_ci	if (!control_phy)
2828c2ecf20Sopenharmony_ci		return -ENOMEM;
2838c2ecf20Sopenharmony_ci
2848c2ecf20Sopenharmony_ci	control_phy->dev = &pdev->dev;
2858c2ecf20Sopenharmony_ci	control_phy->type = *(enum omap_control_phy_type *)of_id->data;
2868c2ecf20Sopenharmony_ci
2878c2ecf20Sopenharmony_ci	if (control_phy->type == OMAP_CTRL_TYPE_OTGHS) {
2888c2ecf20Sopenharmony_ci		res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
2898c2ecf20Sopenharmony_ci			"otghs_control");
2908c2ecf20Sopenharmony_ci		control_phy->otghs_control = devm_ioremap_resource(
2918c2ecf20Sopenharmony_ci			&pdev->dev, res);
2928c2ecf20Sopenharmony_ci		if (IS_ERR(control_phy->otghs_control))
2938c2ecf20Sopenharmony_ci			return PTR_ERR(control_phy->otghs_control);
2948c2ecf20Sopenharmony_ci	} else {
2958c2ecf20Sopenharmony_ci		res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
2968c2ecf20Sopenharmony_ci				"power");
2978c2ecf20Sopenharmony_ci		control_phy->power = devm_ioremap_resource(&pdev->dev, res);
2988c2ecf20Sopenharmony_ci		if (IS_ERR(control_phy->power)) {
2998c2ecf20Sopenharmony_ci			dev_err(&pdev->dev, "Couldn't get power register\n");
3008c2ecf20Sopenharmony_ci			return PTR_ERR(control_phy->power);
3018c2ecf20Sopenharmony_ci		}
3028c2ecf20Sopenharmony_ci	}
3038c2ecf20Sopenharmony_ci
3048c2ecf20Sopenharmony_ci	if (control_phy->type == OMAP_CTRL_TYPE_PIPE3 ||
3058c2ecf20Sopenharmony_ci	    control_phy->type == OMAP_CTRL_TYPE_PCIE) {
3068c2ecf20Sopenharmony_ci		control_phy->sys_clk = devm_clk_get(control_phy->dev,
3078c2ecf20Sopenharmony_ci			"sys_clkin");
3088c2ecf20Sopenharmony_ci		if (IS_ERR(control_phy->sys_clk)) {
3098c2ecf20Sopenharmony_ci			pr_err("%s: unable to get sys_clkin\n", __func__);
3108c2ecf20Sopenharmony_ci			return -EINVAL;
3118c2ecf20Sopenharmony_ci		}
3128c2ecf20Sopenharmony_ci	}
3138c2ecf20Sopenharmony_ci
3148c2ecf20Sopenharmony_ci	if (control_phy->type == OMAP_CTRL_TYPE_PCIE) {
3158c2ecf20Sopenharmony_ci		res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
3168c2ecf20Sopenharmony_ci						   "pcie_pcs");
3178c2ecf20Sopenharmony_ci		control_phy->pcie_pcs = devm_ioremap_resource(&pdev->dev, res);
3188c2ecf20Sopenharmony_ci		if (IS_ERR(control_phy->pcie_pcs))
3198c2ecf20Sopenharmony_ci			return PTR_ERR(control_phy->pcie_pcs);
3208c2ecf20Sopenharmony_ci	}
3218c2ecf20Sopenharmony_ci
3228c2ecf20Sopenharmony_ci	dev_set_drvdata(control_phy->dev, control_phy);
3238c2ecf20Sopenharmony_ci
3248c2ecf20Sopenharmony_ci	return 0;
3258c2ecf20Sopenharmony_ci}
3268c2ecf20Sopenharmony_ci
3278c2ecf20Sopenharmony_cistatic struct platform_driver omap_control_phy_driver = {
3288c2ecf20Sopenharmony_ci	.probe		= omap_control_phy_probe,
3298c2ecf20Sopenharmony_ci	.driver		= {
3308c2ecf20Sopenharmony_ci		.name	= "omap-control-phy",
3318c2ecf20Sopenharmony_ci		.of_match_table = omap_control_phy_id_table,
3328c2ecf20Sopenharmony_ci	},
3338c2ecf20Sopenharmony_ci};
3348c2ecf20Sopenharmony_ci
3358c2ecf20Sopenharmony_cistatic int __init omap_control_phy_init(void)
3368c2ecf20Sopenharmony_ci{
3378c2ecf20Sopenharmony_ci	return platform_driver_register(&omap_control_phy_driver);
3388c2ecf20Sopenharmony_ci}
3398c2ecf20Sopenharmony_cisubsys_initcall(omap_control_phy_init);
3408c2ecf20Sopenharmony_ci
3418c2ecf20Sopenharmony_cistatic void __exit omap_control_phy_exit(void)
3428c2ecf20Sopenharmony_ci{
3438c2ecf20Sopenharmony_ci	platform_driver_unregister(&omap_control_phy_driver);
3448c2ecf20Sopenharmony_ci}
3458c2ecf20Sopenharmony_cimodule_exit(omap_control_phy_exit);
3468c2ecf20Sopenharmony_ci
3478c2ecf20Sopenharmony_ciMODULE_ALIAS("platform:omap_control_phy");
3488c2ecf20Sopenharmony_ciMODULE_AUTHOR("Texas Instruments Inc.");
3498c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("OMAP Control Module PHY Driver");
3508c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2");
351