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