brintos

brintos / linux-shallow public Read only

0
0
Text · 6.1 KiB · 0ff07e2 Raw
234 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3 * Copyright (C) 2017 John Crispin <john@phrozen.org>4 *5 * Based on code from6 * Allwinner Technology Co., Ltd. <www.allwinnertech.com>7 */8 9#include <linux/delay.h>10#include <linux/err.h>11#include <linux/io.h>12#include <linux/kernel.h>13#include <linux/mfd/syscon.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/regmap.h>20#include <linux/reset.h>21 22#define RT_SYSC_REG_SYSCFG1		0x01423#define RT_SYSC_REG_CLKCFG1		0x03024#define RT_SYSC_REG_USB_PHY_CFG		0x05c25 26#define OFS_U2_PHY_AC0			0x80027#define OFS_U2_PHY_AC1			0x80428#define OFS_U2_PHY_AC2			0x80829#define OFS_U2_PHY_ACR0			0x81030#define OFS_U2_PHY_ACR1			0x81431#define OFS_U2_PHY_ACR2			0x81832#define OFS_U2_PHY_ACR3			0x81C33#define OFS_U2_PHY_ACR4			0x82034#define OFS_U2_PHY_AMON0		0x82435#define OFS_U2_PHY_DCR0			0x86036#define OFS_U2_PHY_DCR1			0x86437#define OFS_U2_PHY_DTM0			0x86838#define OFS_U2_PHY_DTM1			0x86C39 40#define RT_RSTCTRL_UDEV			BIT(25)41#define RT_RSTCTRL_UHST			BIT(22)42#define RT_SYSCFG1_USB0_HOST_MODE	BIT(10)43 44#define MT7620_CLKCFG1_UPHY0_CLK_EN	BIT(25)45#define MT7620_CLKCFG1_UPHY1_CLK_EN	BIT(22)46#define RT_CLKCFG1_UPHY1_CLK_EN		BIT(20)47#define RT_CLKCFG1_UPHY0_CLK_EN		BIT(18)48 49#define USB_PHY_UTMI_8B60M		BIT(1)50#define UDEV_WAKEUP			BIT(0)51 52struct ralink_usb_phy {53	struct reset_control	*rstdev;54	struct reset_control	*rsthost;55	u32			clk;56	struct phy		*phy;57	void __iomem		*base;58	struct regmap		*sysctl;59};60 61static void u2_phy_w32(struct ralink_usb_phy *phy, u32 val, u32 reg)62{63	writel(val, phy->base + reg);64}65 66static u32 u2_phy_r32(struct ralink_usb_phy *phy, u32 reg)67{68	return readl(phy->base + reg);69}70 71static void ralink_usb_phy_init(struct ralink_usb_phy *phy)72{73	u2_phy_r32(phy, OFS_U2_PHY_AC2);74	u2_phy_r32(phy, OFS_U2_PHY_ACR0);75	u2_phy_r32(phy, OFS_U2_PHY_DCR0);76 77	u2_phy_w32(phy, 0x00ffff02, OFS_U2_PHY_DCR0);78	u2_phy_r32(phy, OFS_U2_PHY_DCR0);79	u2_phy_w32(phy, 0x00555502, OFS_U2_PHY_DCR0);80	u2_phy_r32(phy, OFS_U2_PHY_DCR0);81	u2_phy_w32(phy, 0x00aaaa02, OFS_U2_PHY_DCR0);82	u2_phy_r32(phy, OFS_U2_PHY_DCR0);83	u2_phy_w32(phy, 0x00000402, OFS_U2_PHY_DCR0);84	u2_phy_r32(phy, OFS_U2_PHY_DCR0);85	u2_phy_w32(phy, 0x0048086a, OFS_U2_PHY_AC0);86	u2_phy_w32(phy, 0x4400001c, OFS_U2_PHY_AC1);87	u2_phy_w32(phy, 0xc0200000, OFS_U2_PHY_ACR3);88	u2_phy_w32(phy, 0x02000000, OFS_U2_PHY_DTM0);89}90 91static int ralink_usb_phy_power_on(struct phy *_phy)92{93	struct ralink_usb_phy *phy = phy_get_drvdata(_phy);94	u32 t;95 96	/* enable the phy */97	regmap_update_bits(phy->sysctl, RT_SYSC_REG_CLKCFG1,98			   phy->clk, phy->clk);99 100	/* setup host mode */101	regmap_update_bits(phy->sysctl, RT_SYSC_REG_SYSCFG1,102			   RT_SYSCFG1_USB0_HOST_MODE,103			   RT_SYSCFG1_USB0_HOST_MODE);104 105	/* deassert the reset lines */106	reset_control_deassert(phy->rsthost);107	reset_control_deassert(phy->rstdev);108 109	/*110	 * The SDK kernel had a delay of 100ms. however on device111	 * testing showed that 10ms is enough112	 */113	mdelay(10);114 115	if (phy->base)116		ralink_usb_phy_init(phy);117 118	/* print some status info */119	regmap_read(phy->sysctl, RT_SYSC_REG_USB_PHY_CFG, &t);120	dev_info(&phy->phy->dev, "remote usb device wakeup %s\n",121		(t & UDEV_WAKEUP) ? ("enabled") : ("disabled"));122	if (t & USB_PHY_UTMI_8B60M)123		dev_info(&phy->phy->dev, "UTMI 8bit 60MHz\n");124	else125		dev_info(&phy->phy->dev, "UTMI 16bit 30MHz\n");126 127	return 0;128}129 130static int ralink_usb_phy_power_off(struct phy *_phy)131{132	struct ralink_usb_phy *phy = phy_get_drvdata(_phy);133 134	/* disable the phy */135	regmap_update_bits(phy->sysctl, RT_SYSC_REG_CLKCFG1,136			   phy->clk, 0);137 138	/* assert the reset lines */139	reset_control_assert(phy->rstdev);140	reset_control_assert(phy->rsthost);141 142	return 0;143}144 145static const struct phy_ops ralink_usb_phy_ops = {146	.power_on	= ralink_usb_phy_power_on,147	.power_off	= ralink_usb_phy_power_off,148	.owner		= THIS_MODULE,149};150 151static const struct of_device_id ralink_usb_phy_of_match[] = {152	{153		.compatible = "ralink,rt3352-usbphy",154		.data = (void *)(uintptr_t)(RT_CLKCFG1_UPHY1_CLK_EN |155					    RT_CLKCFG1_UPHY0_CLK_EN)156	},157	{158		.compatible = "mediatek,mt7620-usbphy",159		.data = (void *)(uintptr_t)(MT7620_CLKCFG1_UPHY1_CLK_EN |160					    MT7620_CLKCFG1_UPHY0_CLK_EN)161	},162	{163		.compatible = "mediatek,mt7628-usbphy",164		.data = (void *)(uintptr_t)(MT7620_CLKCFG1_UPHY1_CLK_EN |165					    MT7620_CLKCFG1_UPHY0_CLK_EN) },166	{ },167};168MODULE_DEVICE_TABLE(of, ralink_usb_phy_of_match);169 170static int ralink_usb_phy_probe(struct platform_device *pdev)171{172	struct device *dev = &pdev->dev;173	struct phy_provider *phy_provider;174	struct ralink_usb_phy *phy;175 176	phy = devm_kzalloc(dev, sizeof(*phy), GFP_KERNEL);177	if (!phy)178		return -ENOMEM;179 180	phy->clk = (uintptr_t)device_get_match_data(&pdev->dev);181	phy->base = NULL;182 183	phy->sysctl = syscon_regmap_lookup_by_phandle(dev->of_node, "ralink,sysctl");184	if (IS_ERR(phy->sysctl)) {185		dev_err(dev, "failed to get sysctl registers\n");186		return PTR_ERR(phy->sysctl);187	}188 189	/* The MT7628 and MT7688 require extra setup of PHY registers. */190	if (of_device_is_compatible(dev->of_node, "mediatek,mt7628-usbphy")) {191		phy->base = devm_platform_ioremap_resource(pdev, 0);192		if (IS_ERR(phy->base)) {193			dev_err(dev, "failed to remap register memory\n");194			return PTR_ERR(phy->base);195		}196	}197 198	phy->rsthost = devm_reset_control_get(&pdev->dev, "host");199	if (IS_ERR(phy->rsthost)) {200		dev_err(dev, "host reset is missing\n");201		return PTR_ERR(phy->rsthost);202	}203 204	phy->rstdev = devm_reset_control_get(&pdev->dev, "device");205	if (IS_ERR(phy->rstdev)) {206		dev_err(dev, "device reset is missing\n");207		return PTR_ERR(phy->rstdev);208	}209 210	phy->phy = devm_phy_create(dev, NULL, &ralink_usb_phy_ops);211	if (IS_ERR(phy->phy)) {212		dev_err(dev, "failed to create PHY\n");213		return PTR_ERR(phy->phy);214	}215	phy_set_drvdata(phy->phy, phy);216 217	phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);218 219	return PTR_ERR_OR_ZERO(phy_provider);220}221 222static struct platform_driver ralink_usb_phy_driver = {223	.probe	= ralink_usb_phy_probe,224	.driver = {225		.of_match_table	= ralink_usb_phy_of_match,226		.name  = "ralink-usb-phy",227	}228};229module_platform_driver(ralink_usb_phy_driver);230 231MODULE_DESCRIPTION("Ralink USB phy driver");232MODULE_AUTHOR("John Crispin <john@phrozen.org>");233MODULE_LICENSE("GPL v2");234