brintos

brintos / linux-shallow public Read only

0
0
Text · 10.7 KiB · c0221e7 Raw
443 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * Renesas R-Car Gen2 PHY driver4 *5 * Copyright (C) 2014 Renesas Solutions Corp.6 * Copyright (C) 2014 Cogent Embedded, Inc.7 * Copyright (C) 2019 Renesas Electronics Corp.8 */9 10#include <linux/clk.h>11#include <linux/delay.h>12#include <linux/io.h>13#include <linux/module.h>14#include <linux/of.h>15#include <linux/phy/phy.h>16#include <linux/platform_device.h>17#include <linux/spinlock.h>18#include <linux/atomic.h>19 20#define USBHS_LPSTS			0x0221#define USBHS_UGCTRL			0x8022#define USBHS_UGCTRL2			0x8423#define USBHS_UGSTS			0x88	/* From technical update */24 25/* Low Power Status register (LPSTS) */26#define USBHS_LPSTS_SUSPM		0x400027 28/* USB General control register (UGCTRL) */29#define USBHS_UGCTRL_CONNECT		0x0000000430#define USBHS_UGCTRL_PLLRESET		0x0000000131 32/* USB General control register 2 (UGCTRL2) */33#define USBHS_UGCTRL2_USB2SEL		0x8000000034#define USBHS_UGCTRL2_USB2SEL_PCI	0x0000000035#define USBHS_UGCTRL2_USB2SEL_USB30	0x8000000036#define USBHS_UGCTRL2_USB0SEL		0x0000003037#define USBHS_UGCTRL2_USB0SEL_PCI	0x0000001038#define USBHS_UGCTRL2_USB0SEL_HS_USB	0x0000003039#define USBHS_UGCTRL2_USB0SEL_USB20	0x0000001040#define USBHS_UGCTRL2_USB0SEL_HS_USB20	0x0000002041 42/* USB General status register (UGSTS) */43#define USBHS_UGSTS_LOCK		0x00000100 /* From technical update */44 45#define PHYS_PER_CHANNEL	246 47struct rcar_gen2_phy {48	struct phy *phy;49	struct rcar_gen2_channel *channel;50	int number;51	u32 select_value;52};53 54struct rcar_gen2_channel {55	struct device_node *of_node;56	struct rcar_gen2_phy_driver *drv;57	struct rcar_gen2_phy phys[PHYS_PER_CHANNEL];58	int selected_phy;59	u32 select_mask;60};61 62struct rcar_gen2_phy_driver {63	void __iomem *base;64	struct clk *clk;65	spinlock_t lock;66	int num_channels;67	struct rcar_gen2_channel *channels;68};69 70struct rcar_gen2_phy_data {71	const struct phy_ops *gen2_phy_ops;72	const u32 (*select_value)[PHYS_PER_CHANNEL];73	const u32 num_channels;74};75 76static int rcar_gen2_phy_init(struct phy *p)77{78	struct rcar_gen2_phy *phy = phy_get_drvdata(p);79	struct rcar_gen2_channel *channel = phy->channel;80	struct rcar_gen2_phy_driver *drv = channel->drv;81	unsigned long flags;82	u32 ugctrl2;83 84	/*85	 * Try to acquire exclusive access to PHY.  The first driver calling86	 * phy_init()  on a given channel wins, and all attempts  to use another87	 * PHY on this channel will fail until phy_exit() is called by the first88	 * driver.   Achieving this with cmpxcgh() should be SMP-safe.89	 */90	if (cmpxchg(&channel->selected_phy, -1, phy->number) != -1)91		return -EBUSY;92 93	clk_prepare_enable(drv->clk);94 95	spin_lock_irqsave(&drv->lock, flags);96	ugctrl2 = readl(drv->base + USBHS_UGCTRL2);97	ugctrl2 &= ~channel->select_mask;98	ugctrl2 |= phy->select_value;99	writel(ugctrl2, drv->base + USBHS_UGCTRL2);100	spin_unlock_irqrestore(&drv->lock, flags);101	return 0;102}103 104static int rcar_gen2_phy_exit(struct phy *p)105{106	struct rcar_gen2_phy *phy = phy_get_drvdata(p);107	struct rcar_gen2_channel *channel = phy->channel;108 109	clk_disable_unprepare(channel->drv->clk);110 111	channel->selected_phy = -1;112 113	return 0;114}115 116static int rcar_gen2_phy_power_on(struct phy *p)117{118	struct rcar_gen2_phy *phy = phy_get_drvdata(p);119	struct rcar_gen2_phy_driver *drv = phy->channel->drv;120	void __iomem *base = drv->base;121	unsigned long flags;122	u32 value;123	int err = 0, i;124 125	/* Skip if it's not USBHS */126	if (phy->select_value != USBHS_UGCTRL2_USB0SEL_HS_USB)127		return 0;128 129	spin_lock_irqsave(&drv->lock, flags);130 131	/* Power on USBHS PHY */132	value = readl(base + USBHS_UGCTRL);133	value &= ~USBHS_UGCTRL_PLLRESET;134	writel(value, base + USBHS_UGCTRL);135 136	value = readw(base + USBHS_LPSTS);137	value |= USBHS_LPSTS_SUSPM;138	writew(value, base + USBHS_LPSTS);139 140	for (i = 0; i < 20; i++) {141		value = readl(base + USBHS_UGSTS);142		if ((value & USBHS_UGSTS_LOCK) == USBHS_UGSTS_LOCK) {143			value = readl(base + USBHS_UGCTRL);144			value |= USBHS_UGCTRL_CONNECT;145			writel(value, base + USBHS_UGCTRL);146			goto out;147		}148		udelay(1);149	}150 151	/* Timed out waiting for the PLL lock */152	err = -ETIMEDOUT;153 154out:155	spin_unlock_irqrestore(&drv->lock, flags);156 157	return err;158}159 160static int rcar_gen2_phy_power_off(struct phy *p)161{162	struct rcar_gen2_phy *phy = phy_get_drvdata(p);163	struct rcar_gen2_phy_driver *drv = phy->channel->drv;164	void __iomem *base = drv->base;165	unsigned long flags;166	u32 value;167 168	/* Skip if it's not USBHS */169	if (phy->select_value != USBHS_UGCTRL2_USB0SEL_HS_USB)170		return 0;171 172	spin_lock_irqsave(&drv->lock, flags);173 174	/* Power off USBHS PHY */175	value = readl(base + USBHS_UGCTRL);176	value &= ~USBHS_UGCTRL_CONNECT;177	writel(value, base + USBHS_UGCTRL);178 179	value = readw(base + USBHS_LPSTS);180	value &= ~USBHS_LPSTS_SUSPM;181	writew(value, base + USBHS_LPSTS);182 183	value = readl(base + USBHS_UGCTRL);184	value |= USBHS_UGCTRL_PLLRESET;185	writel(value, base + USBHS_UGCTRL);186 187	spin_unlock_irqrestore(&drv->lock, flags);188 189	return 0;190}191 192static int rz_g1c_phy_power_on(struct phy *p)193{194	struct rcar_gen2_phy *phy = phy_get_drvdata(p);195	struct rcar_gen2_phy_driver *drv = phy->channel->drv;196	void __iomem *base = drv->base;197	unsigned long flags;198	u32 value;199 200	spin_lock_irqsave(&drv->lock, flags);201 202	/* Power on USBHS PHY */203	value = readl(base + USBHS_UGCTRL);204	value &= ~USBHS_UGCTRL_PLLRESET;205	writel(value, base + USBHS_UGCTRL);206 207	/* As per the data sheet wait 340 micro sec for power stable */208	udelay(340);209 210	if (phy->select_value == USBHS_UGCTRL2_USB0SEL_HS_USB20) {211		value = readw(base + USBHS_LPSTS);212		value |= USBHS_LPSTS_SUSPM;213		writew(value, base + USBHS_LPSTS);214	}215 216	spin_unlock_irqrestore(&drv->lock, flags);217 218	return 0;219}220 221static int rz_g1c_phy_power_off(struct phy *p)222{223	struct rcar_gen2_phy *phy = phy_get_drvdata(p);224	struct rcar_gen2_phy_driver *drv = phy->channel->drv;225	void __iomem *base = drv->base;226	unsigned long flags;227	u32 value;228 229	spin_lock_irqsave(&drv->lock, flags);230	/* Power off USBHS PHY */231	if (phy->select_value == USBHS_UGCTRL2_USB0SEL_HS_USB20) {232		value = readw(base + USBHS_LPSTS);233		value &= ~USBHS_LPSTS_SUSPM;234		writew(value, base + USBHS_LPSTS);235	}236 237	value = readl(base + USBHS_UGCTRL);238	value |= USBHS_UGCTRL_PLLRESET;239	writel(value, base + USBHS_UGCTRL);240 241	spin_unlock_irqrestore(&drv->lock, flags);242 243	return 0;244}245 246static const struct phy_ops rcar_gen2_phy_ops = {247	.init		= rcar_gen2_phy_init,248	.exit		= rcar_gen2_phy_exit,249	.power_on	= rcar_gen2_phy_power_on,250	.power_off	= rcar_gen2_phy_power_off,251	.owner		= THIS_MODULE,252};253 254static const struct phy_ops rz_g1c_phy_ops = {255	.init		= rcar_gen2_phy_init,256	.exit		= rcar_gen2_phy_exit,257	.power_on	= rz_g1c_phy_power_on,258	.power_off	= rz_g1c_phy_power_off,259	.owner		= THIS_MODULE,260};261 262static const u32 pci_select_value[][PHYS_PER_CHANNEL] = {263	[0]	= { USBHS_UGCTRL2_USB0SEL_PCI, USBHS_UGCTRL2_USB0SEL_HS_USB },264	[2]	= { USBHS_UGCTRL2_USB2SEL_PCI, USBHS_UGCTRL2_USB2SEL_USB30 },265};266 267static const u32 usb20_select_value[][PHYS_PER_CHANNEL] = {268	{ USBHS_UGCTRL2_USB0SEL_USB20, USBHS_UGCTRL2_USB0SEL_HS_USB20 },269};270 271static const struct rcar_gen2_phy_data rcar_gen2_usb_phy_data = {272	.gen2_phy_ops = &rcar_gen2_phy_ops,273	.select_value = pci_select_value,274	.num_channels = ARRAY_SIZE(pci_select_value),275};276 277static const struct rcar_gen2_phy_data rz_g1c_usb_phy_data = {278	.gen2_phy_ops = &rz_g1c_phy_ops,279	.select_value = usb20_select_value,280	.num_channels = ARRAY_SIZE(usb20_select_value),281};282 283static const struct of_device_id rcar_gen2_phy_match_table[] = {284	{285		.compatible = "renesas,usb-phy-r8a77470",286		.data = &rz_g1c_usb_phy_data,287	},288	{289		.compatible = "renesas,usb-phy-r8a7790",290		.data = &rcar_gen2_usb_phy_data,291	},292	{293		.compatible = "renesas,usb-phy-r8a7791",294		.data = &rcar_gen2_usb_phy_data,295	},296	{297		.compatible = "renesas,usb-phy-r8a7794",298		.data = &rcar_gen2_usb_phy_data,299	},300	{301		.compatible = "renesas,rcar-gen2-usb-phy",302		.data = &rcar_gen2_usb_phy_data,303	},304	{ /* sentinel */ },305};306MODULE_DEVICE_TABLE(of, rcar_gen2_phy_match_table);307 308static struct phy *rcar_gen2_phy_xlate(struct device *dev,309				       const struct of_phandle_args *args)310{311	struct rcar_gen2_phy_driver *drv;312	struct device_node *np = args->np;313	int i;314 315	drv = dev_get_drvdata(dev);316	if (!drv)317		return ERR_PTR(-EINVAL);318 319	for (i = 0; i < drv->num_channels; i++) {320		if (np == drv->channels[i].of_node)321			break;322	}323 324	if (i >= drv->num_channels || args->args[0] >= 2)325		return ERR_PTR(-ENODEV);326 327	return drv->channels[i].phys[args->args[0]].phy;328}329 330static const u32 select_mask[] = {331	[0]	= USBHS_UGCTRL2_USB0SEL,332	[2]	= USBHS_UGCTRL2_USB2SEL,333};334 335static int rcar_gen2_phy_probe(struct platform_device *pdev)336{337	struct device *dev = &pdev->dev;338	struct rcar_gen2_phy_driver *drv;339	struct phy_provider *provider;340	struct device_node *np;341	void __iomem *base;342	struct clk *clk;343	const struct rcar_gen2_phy_data *data;344	int i = 0;345 346	if (!dev->of_node) {347		dev_err(dev,348			"This driver is required to be instantiated from device tree\n");349		return -EINVAL;350	}351 352	clk = devm_clk_get(dev, "usbhs");353	if (IS_ERR(clk)) {354		dev_err(dev, "Can't get USBHS clock\n");355		return PTR_ERR(clk);356	}357 358	base = devm_platform_ioremap_resource(pdev, 0);359	if (IS_ERR(base))360		return PTR_ERR(base);361 362	drv = devm_kzalloc(dev, sizeof(*drv), GFP_KERNEL);363	if (!drv)364		return -ENOMEM;365 366	spin_lock_init(&drv->lock);367 368	drv->clk = clk;369	drv->base = base;370 371	data = of_device_get_match_data(dev);372	if (!data)373		return -EINVAL;374 375	drv->num_channels = of_get_child_count(dev->of_node);376	drv->channels = devm_kcalloc(dev, drv->num_channels,377				     sizeof(struct rcar_gen2_channel),378				     GFP_KERNEL);379	if (!drv->channels)380		return -ENOMEM;381 382	for_each_child_of_node(dev->of_node, np) {383		struct rcar_gen2_channel *channel = drv->channels + i;384		u32 channel_num;385		int error, n;386 387		channel->of_node = np;388		channel->drv = drv;389		channel->selected_phy = -1;390 391		error = of_property_read_u32(np, "reg", &channel_num);392		if (error || channel_num >= data->num_channels) {393			dev_err(dev, "Invalid \"reg\" property\n");394			of_node_put(np);395			return error;396		}397		channel->select_mask = select_mask[channel_num];398 399		for (n = 0; n < PHYS_PER_CHANNEL; n++) {400			struct rcar_gen2_phy *phy = &channel->phys[n];401 402			phy->channel = channel;403			phy->number = n;404			phy->select_value = data->select_value[channel_num][n];405 406			phy->phy = devm_phy_create(dev, NULL,407						   data->gen2_phy_ops);408			if (IS_ERR(phy->phy)) {409				dev_err(dev, "Failed to create PHY\n");410				of_node_put(np);411				return PTR_ERR(phy->phy);412			}413			phy_set_drvdata(phy->phy, phy);414		}415 416		i++;417	}418 419	provider = devm_of_phy_provider_register(dev, rcar_gen2_phy_xlate);420	if (IS_ERR(provider)) {421		dev_err(dev, "Failed to register PHY provider\n");422		return PTR_ERR(provider);423	}424 425	dev_set_drvdata(dev, drv);426 427	return 0;428}429 430static struct platform_driver rcar_gen2_phy_driver = {431	.driver = {432		.name		= "phy_rcar_gen2",433		.of_match_table	= rcar_gen2_phy_match_table,434	},435	.probe	= rcar_gen2_phy_probe,436};437 438module_platform_driver(rcar_gen2_phy_driver);439 440MODULE_LICENSE("GPL v2");441MODULE_DESCRIPTION("Renesas R-Car Gen2 PHY");442MODULE_AUTHOR("Sergei Shtylyov <sergei.shtylyov@cogentembedded.com>");443