Linux Audio

Check our new training course

Loading...
Note: File does not exist in v3.1.
  1/*
  2 * Renesas R-Car Gen3 for USB2.0 PHY driver
  3 *
  4 * Copyright (C) 2015 Renesas Electronics Corporation
  5 *
  6 * This is based on the phy-rcar-gen2 driver:
  7 * Copyright (C) 2014 Renesas Solutions Corp.
  8 * Copyright (C) 2014 Cogent Embedded, Inc.
  9 *
 10 * This program is free software; you can redistribute it and/or modify
 11 * it under the terms of the GNU General Public License version 2 as
 12 * published by the Free Software Foundation.
 13 */
 14
 15#include <linux/interrupt.h>
 16#include <linux/io.h>
 17#include <linux/module.h>
 18#include <linux/of.h>
 19#include <linux/of_address.h>
 20#include <linux/phy/phy.h>
 21#include <linux/platform_device.h>
 22
 23/******* USB2.0 Host registers (original offset is +0x200) *******/
 24#define USB2_INT_ENABLE		0x000
 25#define USB2_USBCTR		0x00c
 26#define USB2_SPD_RSM_TIMSET	0x10c
 27#define USB2_OC_TIMSET		0x110
 28#define USB2_COMMCTRL		0x600
 29#define USB2_OBINTSTA		0x604
 30#define USB2_OBINTEN		0x608
 31#define USB2_VBCTRL		0x60c
 32#define USB2_LINECTRL1		0x610
 33#define USB2_ADPCTRL		0x630
 34
 35/* INT_ENABLE */
 36#define USB2_INT_ENABLE_UCOM_INTEN	BIT(3)
 37#define USB2_INT_ENABLE_USBH_INTB_EN	BIT(2)
 38#define USB2_INT_ENABLE_USBH_INTA_EN	BIT(1)
 39#define USB2_INT_ENABLE_INIT		(USB2_INT_ENABLE_UCOM_INTEN | \
 40					 USB2_INT_ENABLE_USBH_INTB_EN | \
 41					 USB2_INT_ENABLE_USBH_INTA_EN)
 42
 43/* USBCTR */
 44#define USB2_USBCTR_DIRPD	BIT(2)
 45#define USB2_USBCTR_PLL_RST	BIT(1)
 46
 47/* SPD_RSM_TIMSET */
 48#define USB2_SPD_RSM_TIMSET_INIT	0x014e029b
 49
 50/* OC_TIMSET */
 51#define USB2_OC_TIMSET_INIT		0x000209ab
 52
 53/* COMMCTRL */
 54#define USB2_COMMCTRL_OTG_PERI		BIT(31)	/* 1 = Peripheral mode */
 55
 56/* OBINTSTA and OBINTEN */
 57#define USB2_OBINT_SESSVLDCHG		BIT(12)
 58#define USB2_OBINT_IDDIGCHG		BIT(11)
 59#define USB2_OBINT_BITS			(USB2_OBINT_SESSVLDCHG | \
 60					 USB2_OBINT_IDDIGCHG)
 61
 62/* VBCTRL */
 63#define USB2_VBCTRL_DRVVBUSSEL		BIT(8)
 64
 65/* LINECTRL1 */
 66#define USB2_LINECTRL1_DPRPD_EN		BIT(19)
 67#define USB2_LINECTRL1_DP_RPD		BIT(18)
 68#define USB2_LINECTRL1_DMRPD_EN		BIT(17)
 69#define USB2_LINECTRL1_DM_RPD		BIT(16)
 70
 71/* ADPCTRL */
 72#define USB2_ADPCTRL_OTGSESSVLD		BIT(20)
 73#define USB2_ADPCTRL_IDDIG		BIT(19)
 74#define USB2_ADPCTRL_IDPULLUP		BIT(5)	/* 1 = ID sampling is enabled */
 75#define USB2_ADPCTRL_DRVVBUS		BIT(4)
 76
 77struct rcar_gen3_data {
 78	void __iomem *base;
 79	struct clk *clk;
 80};
 81
 82struct rcar_gen3_chan {
 83	struct rcar_gen3_data usb2;
 84	struct phy *phy;
 85	bool has_otg;
 86};
 87
 88static void rcar_gen3_set_host_mode(struct rcar_gen3_chan *ch, int host)
 89{
 90	void __iomem *usb2_base = ch->usb2.base;
 91	u32 val = readl(usb2_base + USB2_COMMCTRL);
 92
 93	dev_vdbg(&ch->phy->dev, "%s: %08x, %d\n", __func__, val, host);
 94	if (host)
 95		val &= ~USB2_COMMCTRL_OTG_PERI;
 96	else
 97		val |= USB2_COMMCTRL_OTG_PERI;
 98	writel(val, usb2_base + USB2_COMMCTRL);
 99}
100
101static void rcar_gen3_set_linectrl(struct rcar_gen3_chan *ch, int dp, int dm)
102{
103	void __iomem *usb2_base = ch->usb2.base;
104	u32 val = readl(usb2_base + USB2_LINECTRL1);
105
106	dev_vdbg(&ch->phy->dev, "%s: %08x, %d, %d\n", __func__, val, dp, dm);
107	val &= ~(USB2_LINECTRL1_DP_RPD | USB2_LINECTRL1_DM_RPD);
108	if (dp)
109		val |= USB2_LINECTRL1_DP_RPD;
110	if (dm)
111		val |= USB2_LINECTRL1_DM_RPD;
112	writel(val, usb2_base + USB2_LINECTRL1);
113}
114
115static void rcar_gen3_enable_vbus_ctrl(struct rcar_gen3_chan *ch, int vbus)
116{
117	void __iomem *usb2_base = ch->usb2.base;
118	u32 val = readl(usb2_base + USB2_ADPCTRL);
119
120	dev_vdbg(&ch->phy->dev, "%s: %08x, %d\n", __func__, val, vbus);
121	if (vbus)
122		val |= USB2_ADPCTRL_DRVVBUS;
123	else
124		val &= ~USB2_ADPCTRL_DRVVBUS;
125	writel(val, usb2_base + USB2_ADPCTRL);
126}
127
128static void rcar_gen3_init_for_host(struct rcar_gen3_chan *ch)
129{
130	rcar_gen3_set_linectrl(ch, 1, 1);
131	rcar_gen3_set_host_mode(ch, 1);
132	rcar_gen3_enable_vbus_ctrl(ch, 1);
133}
134
135static void rcar_gen3_init_for_peri(struct rcar_gen3_chan *ch)
136{
137	rcar_gen3_set_linectrl(ch, 0, 1);
138	rcar_gen3_set_host_mode(ch, 0);
139	rcar_gen3_enable_vbus_ctrl(ch, 0);
140}
141
142static bool rcar_gen3_check_vbus(struct rcar_gen3_chan *ch)
143{
144	return !!(readl(ch->usb2.base + USB2_ADPCTRL) &
145		  USB2_ADPCTRL_OTGSESSVLD);
146}
147
148static bool rcar_gen3_check_id(struct rcar_gen3_chan *ch)
149{
150	return !!(readl(ch->usb2.base + USB2_ADPCTRL) & USB2_ADPCTRL_IDDIG);
151}
152
153static void rcar_gen3_device_recognition(struct rcar_gen3_chan *ch)
154{
155	bool is_host = true;
156
157	/* B-device? */
158	if (rcar_gen3_check_id(ch) && rcar_gen3_check_vbus(ch))
159		is_host = false;
160
161	if (is_host)
162		rcar_gen3_init_for_host(ch);
163	else
164		rcar_gen3_init_for_peri(ch);
165}
166
167static void rcar_gen3_init_otg(struct rcar_gen3_chan *ch)
168{
169	void __iomem *usb2_base = ch->usb2.base;
170	u32 val;
171
172	val = readl(usb2_base + USB2_VBCTRL);
173	writel(val | USB2_VBCTRL_DRVVBUSSEL, usb2_base + USB2_VBCTRL);
174	writel(USB2_OBINT_BITS, usb2_base + USB2_OBINTSTA);
175	val = readl(usb2_base + USB2_OBINTEN);
176	writel(val | USB2_OBINT_BITS, usb2_base + USB2_OBINTEN);
177	val = readl(usb2_base + USB2_ADPCTRL);
178	writel(val | USB2_ADPCTRL_IDPULLUP, usb2_base + USB2_ADPCTRL);
179	val = readl(usb2_base + USB2_LINECTRL1);
180	rcar_gen3_set_linectrl(ch, 0, 0);
181	writel(val | USB2_LINECTRL1_DPRPD_EN | USB2_LINECTRL1_DMRPD_EN,
182	       usb2_base + USB2_LINECTRL1);
183
184	rcar_gen3_device_recognition(ch);
185}
186
187static int rcar_gen3_phy_usb2_init(struct phy *p)
188{
189	struct rcar_gen3_chan *channel = phy_get_drvdata(p);
190	void __iomem *usb2_base = channel->usb2.base;
191
192	/* Initialize USB2 part */
193	writel(USB2_INT_ENABLE_INIT, usb2_base + USB2_INT_ENABLE);
194	writel(USB2_SPD_RSM_TIMSET_INIT, usb2_base + USB2_SPD_RSM_TIMSET);
195	writel(USB2_OC_TIMSET_INIT, usb2_base + USB2_OC_TIMSET);
196
197	/* Initialize otg part */
198	if (channel->has_otg)
199		rcar_gen3_init_otg(channel);
200
201	return 0;
202}
203
204static int rcar_gen3_phy_usb2_exit(struct phy *p)
205{
206	struct rcar_gen3_chan *channel = phy_get_drvdata(p);
207
208	writel(0, channel->usb2.base + USB2_INT_ENABLE);
209
210	return 0;
211}
212
213static int rcar_gen3_phy_usb2_power_on(struct phy *p)
214{
215	struct rcar_gen3_chan *channel = phy_get_drvdata(p);
216	void __iomem *usb2_base = channel->usb2.base;
217	u32 val;
218
219	val = readl(usb2_base + USB2_USBCTR);
220	val |= USB2_USBCTR_PLL_RST;
221	writel(val, usb2_base + USB2_USBCTR);
222	val &= ~USB2_USBCTR_PLL_RST;
223	writel(val, usb2_base + USB2_USBCTR);
224
225	return 0;
226}
227
228static struct phy_ops rcar_gen3_phy_usb2_ops = {
229	.init		= rcar_gen3_phy_usb2_init,
230	.exit		= rcar_gen3_phy_usb2_exit,
231	.power_on	= rcar_gen3_phy_usb2_power_on,
232	.owner		= THIS_MODULE,
233};
234
235static irqreturn_t rcar_gen3_phy_usb2_irq(int irq, void *_ch)
236{
237	struct rcar_gen3_chan *ch = _ch;
238	void __iomem *usb2_base = ch->usb2.base;
239	u32 status = readl(usb2_base + USB2_OBINTSTA);
240	irqreturn_t ret = IRQ_NONE;
241
242	if (status & USB2_OBINT_BITS) {
243		dev_vdbg(&ch->phy->dev, "%s: %08x\n", __func__, status);
244		writel(USB2_OBINT_BITS, usb2_base + USB2_OBINTSTA);
245		rcar_gen3_device_recognition(ch);
246		ret = IRQ_HANDLED;
247	}
248
249	return ret;
250}
251
252static const struct of_device_id rcar_gen3_phy_usb2_match_table[] = {
253	{ .compatible = "renesas,usb2-phy-r8a7795" },
254	{ }
255};
256MODULE_DEVICE_TABLE(of, rcar_gen3_phy_usb2_match_table);
257
258static int rcar_gen3_phy_usb2_probe(struct platform_device *pdev)
259{
260	struct device *dev = &pdev->dev;
261	struct rcar_gen3_chan *channel;
262	struct phy_provider *provider;
263	struct resource *res;
264	int irq;
265
266	if (!dev->of_node) {
267		dev_err(dev, "This driver needs device tree\n");
268		return -EINVAL;
269	}
270
271	channel = devm_kzalloc(dev, sizeof(*channel), GFP_KERNEL);
272	if (!channel)
273		return -ENOMEM;
274
275	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
276	channel->usb2.base = devm_ioremap_resource(dev, res);
277	if (IS_ERR(channel->usb2.base))
278		return PTR_ERR(channel->usb2.base);
279
280	/* call request_irq for OTG */
281	irq = platform_get_irq(pdev, 0);
282	if (irq >= 0) {
283		irq = devm_request_irq(dev, irq, rcar_gen3_phy_usb2_irq,
284				       IRQF_SHARED, dev_name(dev), channel);
285		if (irq < 0)
286			dev_err(dev, "No irq handler (%d)\n", irq);
287		channel->has_otg = true;
288	}
289
290	/* devm_phy_create() will call pm_runtime_enable(dev); */
291	channel->phy = devm_phy_create(dev, NULL, &rcar_gen3_phy_usb2_ops);
292	if (IS_ERR(channel->phy)) {
293		dev_err(dev, "Failed to create USB2 PHY\n");
294		return PTR_ERR(channel->phy);
295	}
296
297	phy_set_drvdata(channel->phy, channel);
298
299	provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
300	if (IS_ERR(provider))
301		dev_err(dev, "Failed to register PHY provider\n");
302
303	return PTR_ERR_OR_ZERO(provider);
304}
305
306static struct platform_driver rcar_gen3_phy_usb2_driver = {
307	.driver = {
308		.name		= "phy_rcar_gen3_usb2",
309		.of_match_table	= rcar_gen3_phy_usb2_match_table,
310	},
311	.probe	= rcar_gen3_phy_usb2_probe,
312};
313module_platform_driver(rcar_gen3_phy_usb2_driver);
314
315MODULE_LICENSE("GPL v2");
316MODULE_DESCRIPTION("Renesas R-Car Gen3 USB 2.0 PHY");
317MODULE_AUTHOR("Yoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com>");