168cf027fSGrygorii Strashko // SPDX-License-Identifier: GPL-2.0+
2b544dbacSJeff Kirsher /*
3b544dbacSJeff Kirsher * DaVinci MDIO Module driver
4b544dbacSJeff Kirsher *
5b544dbacSJeff Kirsher * Copyright (C) 2010 Texas Instruments.
6b544dbacSJeff Kirsher *
7b544dbacSJeff Kirsher * Shamelessly ripped out of davinci_emac.c, original copyrights follow:
8b544dbacSJeff Kirsher *
9b544dbacSJeff Kirsher * Copyright (C) 2009 Texas Instruments.
10b544dbacSJeff Kirsher *
11b544dbacSJeff Kirsher */
12b544dbacSJeff Kirsher #include <linux/module.h>
13b544dbacSJeff Kirsher #include <linux/kernel.h>
14b544dbacSJeff Kirsher #include <linux/platform_device.h>
15b544dbacSJeff Kirsher #include <linux/delay.h>
16b544dbacSJeff Kirsher #include <linux/sched.h>
17b544dbacSJeff Kirsher #include <linux/slab.h>
18b544dbacSJeff Kirsher #include <linux/phy.h>
19b544dbacSJeff Kirsher #include <linux/clk.h>
20b544dbacSJeff Kirsher #include <linux/err.h>
21b544dbacSJeff Kirsher #include <linux/io.h>
2254472edfSSekhar Nori #include <linux/iopoll.h>
238e476d9dSMugunthan V N #include <linux/pm_runtime.h>
24b544dbacSJeff Kirsher #include <linux/davinci_emac.h>
25ec03e6a8SMugunthan V N #include <linux/of.h>
260a0ea068SGrygorii Strashko #include <linux/of_mdio.h>
275c0e3580SMugunthan V N #include <linux/pinctrl/consumer.h>
28d04807b8SRavi Gunasekaran #include <linux/mdio-bitbang.h>
29d04807b8SRavi Gunasekaran #include <linux/sys_soc.h>
30b544dbacSJeff Kirsher
31b544dbacSJeff Kirsher /*
32b544dbacSJeff Kirsher * This timeout definition is a worst-case ultra defensive measure against
33b544dbacSJeff Kirsher * unexpected controller lock ups. Ideally, we should never ever hit this
34b544dbacSJeff Kirsher * scenario in practice.
35b544dbacSJeff Kirsher */
36b544dbacSJeff Kirsher #define MDIO_TIMEOUT 100 /* msecs */
37b544dbacSJeff Kirsher
38b544dbacSJeff Kirsher #define PHY_REG_MASK 0x1f
39b544dbacSJeff Kirsher #define PHY_ID_MASK 0x1f
40b544dbacSJeff Kirsher
41b544dbacSJeff Kirsher #define DEF_OUT_FREQ 2200000 /* 2.2 MHz */
42b544dbacSJeff Kirsher
439eae9c7dSGrygorii Strashko struct davinci_mdio_of_param {
449eae9c7dSGrygorii Strashko int autosuspend_delay_ms;
45d04807b8SRavi Gunasekaran bool manual_mode;
469eae9c7dSGrygorii Strashko };
479eae9c7dSGrygorii Strashko
48b544dbacSJeff Kirsher struct davinci_mdio_regs {
49b544dbacSJeff Kirsher u32 version;
50b544dbacSJeff Kirsher u32 control;
51b544dbacSJeff Kirsher #define CONTROL_IDLE BIT(31)
52b544dbacSJeff Kirsher #define CONTROL_ENABLE BIT(30)
537c3a95a1SChristian Riesch #define CONTROL_MAX_DIV (0xffff)
54d04807b8SRavi Gunasekaran #define CONTROL_CLKDIV GENMASK(15, 0)
55d04807b8SRavi Gunasekaran
56d04807b8SRavi Gunasekaran #define MDIO_MAN_MDCLK_O BIT(2)
57d04807b8SRavi Gunasekaran #define MDIO_MAN_OE BIT(1)
58d04807b8SRavi Gunasekaran #define MDIO_MAN_PIN BIT(0)
59d04807b8SRavi Gunasekaran #define MDIO_MANUALMODE BIT(31)
60d04807b8SRavi Gunasekaran
61d04807b8SRavi Gunasekaran #define MDIO_PIN 0
62d04807b8SRavi Gunasekaran
63b544dbacSJeff Kirsher
64b544dbacSJeff Kirsher u32 alive;
65b544dbacSJeff Kirsher u32 link;
66b544dbacSJeff Kirsher u32 linkintraw;
67b544dbacSJeff Kirsher u32 linkintmasked;
68b544dbacSJeff Kirsher u32 __reserved_0[2];
69b544dbacSJeff Kirsher u32 userintraw;
70b544dbacSJeff Kirsher u32 userintmasked;
71b544dbacSJeff Kirsher u32 userintmaskset;
72b544dbacSJeff Kirsher u32 userintmaskclr;
73d04807b8SRavi Gunasekaran u32 manualif;
74d04807b8SRavi Gunasekaran u32 poll;
75d04807b8SRavi Gunasekaran u32 __reserved_1[18];
76b544dbacSJeff Kirsher
77b544dbacSJeff Kirsher struct {
78b544dbacSJeff Kirsher u32 access;
79b544dbacSJeff Kirsher #define USERACCESS_GO BIT(31)
80b544dbacSJeff Kirsher #define USERACCESS_WRITE BIT(30)
81b544dbacSJeff Kirsher #define USERACCESS_ACK BIT(29)
82b544dbacSJeff Kirsher #define USERACCESS_READ (0)
83b544dbacSJeff Kirsher #define USERACCESS_DATA (0xffff)
84b544dbacSJeff Kirsher
85b544dbacSJeff Kirsher u32 physel;
865224f790SGustavo A. R. Silva } user[];
87b544dbacSJeff Kirsher };
88b544dbacSJeff Kirsher
899b05f462SLad, Prabhakar static const struct mdio_platform_data default_pdata = {
90b544dbacSJeff Kirsher .bus_freq = DEF_OUT_FREQ,
91b544dbacSJeff Kirsher };
92b544dbacSJeff Kirsher
93b544dbacSJeff Kirsher struct davinci_mdio_data {
94b544dbacSJeff Kirsher struct mdio_platform_data pdata;
95d04807b8SRavi Gunasekaran struct mdiobb_ctrl bb_ctrl;
96b544dbacSJeff Kirsher struct davinci_mdio_regs __iomem *regs;
97b544dbacSJeff Kirsher struct clk *clk;
98b544dbacSJeff Kirsher struct device *dev;
99b544dbacSJeff Kirsher struct mii_bus *bus;
1008ea63bbaSGrygorii Strashko bool active_in_suspend;
101b544dbacSJeff Kirsher unsigned long access_time; /* jiffies */
1020a0ea068SGrygorii Strashko /* Indicates that driver shouldn't modify phy_mask in case
1030a0ea068SGrygorii Strashko * if MDIO bus is registered from DT.
1040a0ea068SGrygorii Strashko */
1050a0ea068SGrygorii Strashko bool skip_scan;
10628f0ccb9SGrygorii Strashko u32 clk_div;
107d04807b8SRavi Gunasekaran bool manual_mode;
108b544dbacSJeff Kirsher };
109b544dbacSJeff Kirsher
davinci_mdio_init_clk(struct davinci_mdio_data * data)11028f0ccb9SGrygorii Strashko static void davinci_mdio_init_clk(struct davinci_mdio_data *data)
111b544dbacSJeff Kirsher {
112b544dbacSJeff Kirsher u32 mdio_in, div, mdio_out_khz, access_time;
113b544dbacSJeff Kirsher
114b544dbacSJeff Kirsher mdio_in = clk_get_rate(data->clk);
115b544dbacSJeff Kirsher div = (mdio_in / data->pdata.bus_freq) - 1;
116b544dbacSJeff Kirsher if (div > CONTROL_MAX_DIV)
117b544dbacSJeff Kirsher div = CONTROL_MAX_DIV;
118b544dbacSJeff Kirsher
11928f0ccb9SGrygorii Strashko data->clk_div = div;
120b544dbacSJeff Kirsher /*
121b544dbacSJeff Kirsher * One mdio transaction consists of:
122b544dbacSJeff Kirsher * 32 bits of preamble
123b544dbacSJeff Kirsher * 32 bits of transferred data
124b544dbacSJeff Kirsher * 24 bits of bus yield (not needed unless shared?)
125b544dbacSJeff Kirsher */
126b544dbacSJeff Kirsher mdio_out_khz = mdio_in / (1000 * (div + 1));
127b544dbacSJeff Kirsher access_time = (88 * 1000) / mdio_out_khz;
128b544dbacSJeff Kirsher
129b544dbacSJeff Kirsher /*
130b544dbacSJeff Kirsher * In the worst case, we could be kicking off a user-access immediately
131b544dbacSJeff Kirsher * after the mdio bus scan state-machine triggered its own read. If
132b544dbacSJeff Kirsher * so, our request could get deferred by one access cycle. We
133b544dbacSJeff Kirsher * defensively allow for 4 access cycles.
134b544dbacSJeff Kirsher */
135b544dbacSJeff Kirsher data->access_time = usecs_to_jiffies(access_time * 4);
136b544dbacSJeff Kirsher if (!data->access_time)
137b544dbacSJeff Kirsher data->access_time = 1;
138b544dbacSJeff Kirsher }
139b544dbacSJeff Kirsher
davinci_mdio_enable(struct davinci_mdio_data * data)14028f0ccb9SGrygorii Strashko static void davinci_mdio_enable(struct davinci_mdio_data *data)
14128f0ccb9SGrygorii Strashko {
14228f0ccb9SGrygorii Strashko /* set enable and clock divider */
143191aeea4SGrygorii Strashko writel(data->clk_div | CONTROL_ENABLE, &data->regs->control);
14428f0ccb9SGrygorii Strashko }
14528f0ccb9SGrygorii Strashko
davinci_mdio_disable(struct davinci_mdio_data * data)146d04807b8SRavi Gunasekaran static void davinci_mdio_disable(struct davinci_mdio_data *data)
147b544dbacSJeff Kirsher {
148d04807b8SRavi Gunasekaran u32 reg;
149d04807b8SRavi Gunasekaran
150d04807b8SRavi Gunasekaran /* Disable MDIO state machine */
151d04807b8SRavi Gunasekaran reg = readl(&data->regs->control);
152d04807b8SRavi Gunasekaran
153d04807b8SRavi Gunasekaran reg &= ~CONTROL_CLKDIV;
154d04807b8SRavi Gunasekaran reg |= data->clk_div;
155d04807b8SRavi Gunasekaran
156d04807b8SRavi Gunasekaran reg &= ~CONTROL_ENABLE;
157d04807b8SRavi Gunasekaran writel(reg, &data->regs->control);
158d04807b8SRavi Gunasekaran }
159d04807b8SRavi Gunasekaran
davinci_mdio_enable_manual_mode(struct davinci_mdio_data * data)160d04807b8SRavi Gunasekaran static void davinci_mdio_enable_manual_mode(struct davinci_mdio_data *data)
161d04807b8SRavi Gunasekaran {
162d04807b8SRavi Gunasekaran u32 reg;
163d04807b8SRavi Gunasekaran /* set manual mode */
164d04807b8SRavi Gunasekaran reg = readl(&data->regs->poll);
165d04807b8SRavi Gunasekaran reg |= MDIO_MANUALMODE;
166d04807b8SRavi Gunasekaran writel(reg, &data->regs->poll);
167d04807b8SRavi Gunasekaran }
168d04807b8SRavi Gunasekaran
davinci_set_mdc(struct mdiobb_ctrl * ctrl,int level)169d04807b8SRavi Gunasekaran static void davinci_set_mdc(struct mdiobb_ctrl *ctrl, int level)
170d04807b8SRavi Gunasekaran {
171d04807b8SRavi Gunasekaran struct davinci_mdio_data *data;
172d04807b8SRavi Gunasekaran u32 reg;
173d04807b8SRavi Gunasekaran
174d04807b8SRavi Gunasekaran data = container_of(ctrl, struct davinci_mdio_data, bb_ctrl);
175d04807b8SRavi Gunasekaran reg = readl(&data->regs->manualif);
176d04807b8SRavi Gunasekaran
177d04807b8SRavi Gunasekaran if (level)
178d04807b8SRavi Gunasekaran reg |= MDIO_MAN_MDCLK_O;
179d04807b8SRavi Gunasekaran else
180d04807b8SRavi Gunasekaran reg &= ~MDIO_MAN_MDCLK_O;
181d04807b8SRavi Gunasekaran
182d04807b8SRavi Gunasekaran writel(reg, &data->regs->manualif);
183d04807b8SRavi Gunasekaran }
184d04807b8SRavi Gunasekaran
davinci_set_mdio_dir(struct mdiobb_ctrl * ctrl,int output)185d04807b8SRavi Gunasekaran static void davinci_set_mdio_dir(struct mdiobb_ctrl *ctrl, int output)
186d04807b8SRavi Gunasekaran {
187d04807b8SRavi Gunasekaran struct davinci_mdio_data *data;
188d04807b8SRavi Gunasekaran u32 reg;
189d04807b8SRavi Gunasekaran
190d04807b8SRavi Gunasekaran data = container_of(ctrl, struct davinci_mdio_data, bb_ctrl);
191d04807b8SRavi Gunasekaran reg = readl(&data->regs->manualif);
192d04807b8SRavi Gunasekaran
193d04807b8SRavi Gunasekaran if (output)
194d04807b8SRavi Gunasekaran reg |= MDIO_MAN_OE;
195d04807b8SRavi Gunasekaran else
196d04807b8SRavi Gunasekaran reg &= ~MDIO_MAN_OE;
197d04807b8SRavi Gunasekaran
198d04807b8SRavi Gunasekaran writel(reg, &data->regs->manualif);
199d04807b8SRavi Gunasekaran }
200d04807b8SRavi Gunasekaran
davinci_set_mdio_data(struct mdiobb_ctrl * ctrl,int value)201d04807b8SRavi Gunasekaran static void davinci_set_mdio_data(struct mdiobb_ctrl *ctrl, int value)
202d04807b8SRavi Gunasekaran {
203d04807b8SRavi Gunasekaran struct davinci_mdio_data *data;
204d04807b8SRavi Gunasekaran u32 reg;
205d04807b8SRavi Gunasekaran
206d04807b8SRavi Gunasekaran data = container_of(ctrl, struct davinci_mdio_data, bb_ctrl);
207d04807b8SRavi Gunasekaran reg = readl(&data->regs->manualif);
208d04807b8SRavi Gunasekaran
209d04807b8SRavi Gunasekaran if (value)
210d04807b8SRavi Gunasekaran reg |= MDIO_MAN_PIN;
211d04807b8SRavi Gunasekaran else
212d04807b8SRavi Gunasekaran reg &= ~MDIO_MAN_PIN;
213d04807b8SRavi Gunasekaran
214d04807b8SRavi Gunasekaran writel(reg, &data->regs->manualif);
215d04807b8SRavi Gunasekaran }
216d04807b8SRavi Gunasekaran
davinci_get_mdio_data(struct mdiobb_ctrl * ctrl)217d04807b8SRavi Gunasekaran static int davinci_get_mdio_data(struct mdiobb_ctrl *ctrl)
218d04807b8SRavi Gunasekaran {
219d04807b8SRavi Gunasekaran struct davinci_mdio_data *data;
220d04807b8SRavi Gunasekaran unsigned long reg;
221d04807b8SRavi Gunasekaran
222d04807b8SRavi Gunasekaran data = container_of(ctrl, struct davinci_mdio_data, bb_ctrl);
223d04807b8SRavi Gunasekaran reg = readl(&data->regs->manualif);
224d04807b8SRavi Gunasekaran return test_bit(MDIO_PIN, ®);
225d04807b8SRavi Gunasekaran }
226d04807b8SRavi Gunasekaran
davinci_mdiobb_read_c22(struct mii_bus * bus,int phy,int reg)227*002dd3deSAndrew Lunn static int davinci_mdiobb_read_c22(struct mii_bus *bus, int phy, int reg)
228d04807b8SRavi Gunasekaran {
229d04807b8SRavi Gunasekaran int ret;
230d04807b8SRavi Gunasekaran
231d04807b8SRavi Gunasekaran ret = pm_runtime_resume_and_get(bus->parent);
232d04807b8SRavi Gunasekaran if (ret < 0)
233d04807b8SRavi Gunasekaran return ret;
234d04807b8SRavi Gunasekaran
235*002dd3deSAndrew Lunn ret = mdiobb_read_c22(bus, phy, reg);
236d04807b8SRavi Gunasekaran
237d04807b8SRavi Gunasekaran pm_runtime_mark_last_busy(bus->parent);
238d04807b8SRavi Gunasekaran pm_runtime_put_autosuspend(bus->parent);
239d04807b8SRavi Gunasekaran
240d04807b8SRavi Gunasekaran return ret;
241d04807b8SRavi Gunasekaran }
242d04807b8SRavi Gunasekaran
davinci_mdiobb_write_c22(struct mii_bus * bus,int phy,int reg,u16 val)243*002dd3deSAndrew Lunn static int davinci_mdiobb_write_c22(struct mii_bus *bus, int phy, int reg,
244d04807b8SRavi Gunasekaran u16 val)
245d04807b8SRavi Gunasekaran {
246d04807b8SRavi Gunasekaran int ret;
247d04807b8SRavi Gunasekaran
248d04807b8SRavi Gunasekaran ret = pm_runtime_resume_and_get(bus->parent);
249d04807b8SRavi Gunasekaran if (ret < 0)
250d04807b8SRavi Gunasekaran return ret;
251d04807b8SRavi Gunasekaran
252*002dd3deSAndrew Lunn ret = mdiobb_write_c22(bus, phy, reg, val);
253*002dd3deSAndrew Lunn
254*002dd3deSAndrew Lunn pm_runtime_mark_last_busy(bus->parent);
255*002dd3deSAndrew Lunn pm_runtime_put_autosuspend(bus->parent);
256*002dd3deSAndrew Lunn
257*002dd3deSAndrew Lunn return ret;
258*002dd3deSAndrew Lunn }
259*002dd3deSAndrew Lunn
davinci_mdiobb_read_c45(struct mii_bus * bus,int phy,int devad,int reg)260*002dd3deSAndrew Lunn static int davinci_mdiobb_read_c45(struct mii_bus *bus, int phy, int devad,
261*002dd3deSAndrew Lunn int reg)
262*002dd3deSAndrew Lunn {
263*002dd3deSAndrew Lunn int ret;
264*002dd3deSAndrew Lunn
265*002dd3deSAndrew Lunn ret = pm_runtime_resume_and_get(bus->parent);
266*002dd3deSAndrew Lunn if (ret < 0)
267*002dd3deSAndrew Lunn return ret;
268*002dd3deSAndrew Lunn
269*002dd3deSAndrew Lunn ret = mdiobb_read_c45(bus, phy, devad, reg);
270*002dd3deSAndrew Lunn
271*002dd3deSAndrew Lunn pm_runtime_mark_last_busy(bus->parent);
272*002dd3deSAndrew Lunn pm_runtime_put_autosuspend(bus->parent);
273*002dd3deSAndrew Lunn
274*002dd3deSAndrew Lunn return ret;
275*002dd3deSAndrew Lunn }
276*002dd3deSAndrew Lunn
davinci_mdiobb_write_c45(struct mii_bus * bus,int phy,int devad,int reg,u16 val)277*002dd3deSAndrew Lunn static int davinci_mdiobb_write_c45(struct mii_bus *bus, int phy, int devad,
278*002dd3deSAndrew Lunn int reg, u16 val)
279*002dd3deSAndrew Lunn {
280*002dd3deSAndrew Lunn int ret;
281*002dd3deSAndrew Lunn
282*002dd3deSAndrew Lunn ret = pm_runtime_resume_and_get(bus->parent);
283*002dd3deSAndrew Lunn if (ret < 0)
284*002dd3deSAndrew Lunn return ret;
285*002dd3deSAndrew Lunn
286*002dd3deSAndrew Lunn ret = mdiobb_write_c45(bus, phy, devad, reg, val);
287d04807b8SRavi Gunasekaran
288d04807b8SRavi Gunasekaran pm_runtime_mark_last_busy(bus->parent);
289d04807b8SRavi Gunasekaran pm_runtime_put_autosuspend(bus->parent);
290d04807b8SRavi Gunasekaran
291d04807b8SRavi Gunasekaran return ret;
292d04807b8SRavi Gunasekaran }
293d04807b8SRavi Gunasekaran
davinci_mdio_common_reset(struct davinci_mdio_data * data)294d04807b8SRavi Gunasekaran static int davinci_mdio_common_reset(struct davinci_mdio_data *data)
295d04807b8SRavi Gunasekaran {
296b544dbacSJeff Kirsher u32 phy_mask, ver;
2978ea63bbaSGrygorii Strashko int ret;
298b544dbacSJeff Kirsher
2994facbe3dSMinghao Chi ret = pm_runtime_resume_and_get(data->dev);
3004facbe3dSMinghao Chi if (ret < 0)
3018ea63bbaSGrygorii Strashko return ret;
302b544dbacSJeff Kirsher
303d04807b8SRavi Gunasekaran if (data->manual_mode) {
304d04807b8SRavi Gunasekaran davinci_mdio_disable(data);
305d04807b8SRavi Gunasekaran davinci_mdio_enable_manual_mode(data);
306d04807b8SRavi Gunasekaran }
307d04807b8SRavi Gunasekaran
308b544dbacSJeff Kirsher /* wait for scan logic to settle */
309b544dbacSJeff Kirsher msleep(PHY_MAX_ADDR * data->access_time);
310b544dbacSJeff Kirsher
311b544dbacSJeff Kirsher /* dump hardware version info */
312191aeea4SGrygorii Strashko ver = readl(&data->regs->version);
313cc147a0dSMaxim Uvarov dev_info(data->dev,
314cc147a0dSMaxim Uvarov "davinci mdio revision %d.%d, bus freq %ld\n",
315cc147a0dSMaxim Uvarov (ver >> 8) & 0xff, ver & 0xff,
316cc147a0dSMaxim Uvarov data->pdata.bus_freq);
317b544dbacSJeff Kirsher
3180a0ea068SGrygorii Strashko if (data->skip_scan)
3198ea63bbaSGrygorii Strashko goto done;
3200a0ea068SGrygorii Strashko
321b544dbacSJeff Kirsher /* get phy mask from the alive register */
322191aeea4SGrygorii Strashko phy_mask = readl(&data->regs->alive);
323b544dbacSJeff Kirsher if (phy_mask) {
324b544dbacSJeff Kirsher /* restrict mdio bus to live phys only */
325b544dbacSJeff Kirsher dev_info(data->dev, "detected phy mask %x\n", ~phy_mask);
326b544dbacSJeff Kirsher phy_mask = ~phy_mask;
327b544dbacSJeff Kirsher } else {
328b544dbacSJeff Kirsher /* desperately scan all phys */
329b544dbacSJeff Kirsher dev_warn(data->dev, "no live phy, scanning all\n");
330b544dbacSJeff Kirsher phy_mask = 0;
331b544dbacSJeff Kirsher }
332b544dbacSJeff Kirsher data->bus->phy_mask = phy_mask;
333b544dbacSJeff Kirsher
3348ea63bbaSGrygorii Strashko done:
3358ea63bbaSGrygorii Strashko pm_runtime_mark_last_busy(data->dev);
3368ea63bbaSGrygorii Strashko pm_runtime_put_autosuspend(data->dev);
3378ea63bbaSGrygorii Strashko
338b544dbacSJeff Kirsher return 0;
339b544dbacSJeff Kirsher }
340b544dbacSJeff Kirsher
davinci_mdio_reset(struct mii_bus * bus)341d04807b8SRavi Gunasekaran static int davinci_mdio_reset(struct mii_bus *bus)
342d04807b8SRavi Gunasekaran {
343d04807b8SRavi Gunasekaran struct davinci_mdio_data *data = bus->priv;
344d04807b8SRavi Gunasekaran
345d04807b8SRavi Gunasekaran return davinci_mdio_common_reset(data);
346d04807b8SRavi Gunasekaran }
347d04807b8SRavi Gunasekaran
davinci_mdiobb_reset(struct mii_bus * bus)348d04807b8SRavi Gunasekaran static int davinci_mdiobb_reset(struct mii_bus *bus)
349d04807b8SRavi Gunasekaran {
350d04807b8SRavi Gunasekaran struct mdiobb_ctrl *ctrl = bus->priv;
351d04807b8SRavi Gunasekaran struct davinci_mdio_data *data;
352d04807b8SRavi Gunasekaran
353d04807b8SRavi Gunasekaran data = container_of(ctrl, struct davinci_mdio_data, bb_ctrl);
354d04807b8SRavi Gunasekaran
355d04807b8SRavi Gunasekaran return davinci_mdio_common_reset(data);
356d04807b8SRavi Gunasekaran }
357d04807b8SRavi Gunasekaran
358b544dbacSJeff Kirsher /* wait until hardware is ready for another user access */
wait_for_user_access(struct davinci_mdio_data * data)359b544dbacSJeff Kirsher static inline int wait_for_user_access(struct davinci_mdio_data *data)
360b544dbacSJeff Kirsher {
361b544dbacSJeff Kirsher struct davinci_mdio_regs __iomem *regs = data->regs;
362b544dbacSJeff Kirsher unsigned long timeout = jiffies + msecs_to_jiffies(MDIO_TIMEOUT);
363b544dbacSJeff Kirsher u32 reg;
364b544dbacSJeff Kirsher
365b544dbacSJeff Kirsher while (time_after(timeout, jiffies)) {
366191aeea4SGrygorii Strashko reg = readl(®s->user[0].access);
367b544dbacSJeff Kirsher if ((reg & USERACCESS_GO) == 0)
368b544dbacSJeff Kirsher return 0;
369b544dbacSJeff Kirsher
370191aeea4SGrygorii Strashko reg = readl(®s->control);
3712e1c8084SMaxim Uvarov if ((reg & CONTROL_IDLE) == 0) {
3722e1c8084SMaxim Uvarov usleep_range(100, 200);
373b544dbacSJeff Kirsher continue;
3742e1c8084SMaxim Uvarov }
375b544dbacSJeff Kirsher
376b544dbacSJeff Kirsher /*
377b544dbacSJeff Kirsher * An emac soft_reset may have clobbered the mdio controller's
378b544dbacSJeff Kirsher * state machine. We need to reset and retry the current
379b544dbacSJeff Kirsher * operation
380b544dbacSJeff Kirsher */
381b544dbacSJeff Kirsher dev_warn(data->dev, "resetting idled controller\n");
38228f0ccb9SGrygorii Strashko davinci_mdio_enable(data);
383b544dbacSJeff Kirsher return -EAGAIN;
384b544dbacSJeff Kirsher }
3855b76d060SChristian Riesch
386191aeea4SGrygorii Strashko reg = readl(®s->user[0].access);
3875b76d060SChristian Riesch if ((reg & USERACCESS_GO) == 0)
3885b76d060SChristian Riesch return 0;
3895b76d060SChristian Riesch
390b544dbacSJeff Kirsher dev_err(data->dev, "timed out waiting for user access\n");
391b544dbacSJeff Kirsher return -ETIMEDOUT;
392b544dbacSJeff Kirsher }
393b544dbacSJeff Kirsher
394b544dbacSJeff Kirsher /* wait until hardware state machine is idle */
wait_for_idle(struct davinci_mdio_data * data)395b544dbacSJeff Kirsher static inline int wait_for_idle(struct davinci_mdio_data *data)
396b544dbacSJeff Kirsher {
397b544dbacSJeff Kirsher struct davinci_mdio_regs __iomem *regs = data->regs;
39854472edfSSekhar Nori u32 val, ret;
399b544dbacSJeff Kirsher
40054472edfSSekhar Nori ret = readl_poll_timeout(®s->control, val, val & CONTROL_IDLE,
40154472edfSSekhar Nori 0, MDIO_TIMEOUT * 1000);
40254472edfSSekhar Nori if (ret)
403b544dbacSJeff Kirsher dev_err(data->dev, "timed out waiting for idle\n");
40454472edfSSekhar Nori
40554472edfSSekhar Nori return ret;
406b544dbacSJeff Kirsher }
407b544dbacSJeff Kirsher
davinci_mdio_read(struct mii_bus * bus,int phy_id,int phy_reg)408b544dbacSJeff Kirsher static int davinci_mdio_read(struct mii_bus *bus, int phy_id, int phy_reg)
409b544dbacSJeff Kirsher {
410b544dbacSJeff Kirsher struct davinci_mdio_data *data = bus->priv;
411b544dbacSJeff Kirsher u32 reg;
412b544dbacSJeff Kirsher int ret;
413b544dbacSJeff Kirsher
414b544dbacSJeff Kirsher if (phy_reg & ~PHY_REG_MASK || phy_id & ~PHY_ID_MASK)
415b544dbacSJeff Kirsher return -EINVAL;
416b544dbacSJeff Kirsher
4174facbe3dSMinghao Chi ret = pm_runtime_resume_and_get(data->dev);
4184facbe3dSMinghao Chi if (ret < 0)
4198ea63bbaSGrygorii Strashko return ret;
4208ea63bbaSGrygorii Strashko
421b544dbacSJeff Kirsher reg = (USERACCESS_GO | USERACCESS_READ | (phy_reg << 21) |
422b544dbacSJeff Kirsher (phy_id << 16));
423b544dbacSJeff Kirsher
424b544dbacSJeff Kirsher while (1) {
425b544dbacSJeff Kirsher ret = wait_for_user_access(data);
426b544dbacSJeff Kirsher if (ret == -EAGAIN)
427b544dbacSJeff Kirsher continue;
428b544dbacSJeff Kirsher if (ret < 0)
429b544dbacSJeff Kirsher break;
430b544dbacSJeff Kirsher
431191aeea4SGrygorii Strashko writel(reg, &data->regs->user[0].access);
432b544dbacSJeff Kirsher
433b544dbacSJeff Kirsher ret = wait_for_user_access(data);
434b544dbacSJeff Kirsher if (ret == -EAGAIN)
435b544dbacSJeff Kirsher continue;
436b544dbacSJeff Kirsher if (ret < 0)
437b544dbacSJeff Kirsher break;
438b544dbacSJeff Kirsher
439191aeea4SGrygorii Strashko reg = readl(&data->regs->user[0].access);
440b544dbacSJeff Kirsher ret = (reg & USERACCESS_ACK) ? (reg & USERACCESS_DATA) : -EIO;
441b544dbacSJeff Kirsher break;
442b544dbacSJeff Kirsher }
443b544dbacSJeff Kirsher
4448ea63bbaSGrygorii Strashko pm_runtime_mark_last_busy(data->dev);
4458ea63bbaSGrygorii Strashko pm_runtime_put_autosuspend(data->dev);
446b544dbacSJeff Kirsher return ret;
447b544dbacSJeff Kirsher }
448b544dbacSJeff Kirsher
davinci_mdio_write(struct mii_bus * bus,int phy_id,int phy_reg,u16 phy_data)449b544dbacSJeff Kirsher static int davinci_mdio_write(struct mii_bus *bus, int phy_id,
450b544dbacSJeff Kirsher int phy_reg, u16 phy_data)
451b544dbacSJeff Kirsher {
452b544dbacSJeff Kirsher struct davinci_mdio_data *data = bus->priv;
453b544dbacSJeff Kirsher u32 reg;
454b544dbacSJeff Kirsher int ret;
455b544dbacSJeff Kirsher
456b544dbacSJeff Kirsher if (phy_reg & ~PHY_REG_MASK || phy_id & ~PHY_ID_MASK)
457b544dbacSJeff Kirsher return -EINVAL;
458b544dbacSJeff Kirsher
4594facbe3dSMinghao Chi ret = pm_runtime_resume_and_get(data->dev);
4604facbe3dSMinghao Chi if (ret < 0)
4618ea63bbaSGrygorii Strashko return ret;
4628ea63bbaSGrygorii Strashko
463b544dbacSJeff Kirsher reg = (USERACCESS_GO | USERACCESS_WRITE | (phy_reg << 21) |
464b544dbacSJeff Kirsher (phy_id << 16) | (phy_data & USERACCESS_DATA));
465b544dbacSJeff Kirsher
466b544dbacSJeff Kirsher while (1) {
467b544dbacSJeff Kirsher ret = wait_for_user_access(data);
468b544dbacSJeff Kirsher if (ret == -EAGAIN)
469b544dbacSJeff Kirsher continue;
470b544dbacSJeff Kirsher if (ret < 0)
471b544dbacSJeff Kirsher break;
472b544dbacSJeff Kirsher
473191aeea4SGrygorii Strashko writel(reg, &data->regs->user[0].access);
474b544dbacSJeff Kirsher
475b544dbacSJeff Kirsher ret = wait_for_user_access(data);
476b544dbacSJeff Kirsher if (ret == -EAGAIN)
477b544dbacSJeff Kirsher continue;
478b544dbacSJeff Kirsher break;
479b544dbacSJeff Kirsher }
480b544dbacSJeff Kirsher
4818ea63bbaSGrygorii Strashko pm_runtime_mark_last_busy(data->dev);
4828ea63bbaSGrygorii Strashko pm_runtime_put_autosuspend(data->dev);
4838ea63bbaSGrygorii Strashko
4848ea63bbaSGrygorii Strashko return ret;
485b544dbacSJeff Kirsher }
486b544dbacSJeff Kirsher
davinci_mdio_probe_dt(struct mdio_platform_data * data,struct platform_device * pdev)487ec03e6a8SMugunthan V N static int davinci_mdio_probe_dt(struct mdio_platform_data *data,
488ec03e6a8SMugunthan V N struct platform_device *pdev)
489ec03e6a8SMugunthan V N {
490ec03e6a8SMugunthan V N struct device_node *node = pdev->dev.of_node;
491ec03e6a8SMugunthan V N u32 prop;
492ec03e6a8SMugunthan V N
493ec03e6a8SMugunthan V N if (!node)
494ec03e6a8SMugunthan V N return -EINVAL;
495ec03e6a8SMugunthan V N
496ec03e6a8SMugunthan V N if (of_property_read_u32(node, "bus_freq", &prop)) {
497a92f40a9SGeorge Cherian dev_err(&pdev->dev, "Missing bus_freq property in the DT.\n");
498ec03e6a8SMugunthan V N return -EINVAL;
499ec03e6a8SMugunthan V N }
500ec03e6a8SMugunthan V N data->bus_freq = prop;
501ec03e6a8SMugunthan V N
502ec03e6a8SMugunthan V N return 0;
503ec03e6a8SMugunthan V N }
504ec03e6a8SMugunthan V N
505d04807b8SRavi Gunasekaran struct k3_mdio_soc_data {
506d04807b8SRavi Gunasekaran bool manual_mode;
507d04807b8SRavi Gunasekaran };
508d04807b8SRavi Gunasekaran
509d04807b8SRavi Gunasekaran static const struct k3_mdio_soc_data am65_mdio_soc_data = {
510d04807b8SRavi Gunasekaran .manual_mode = true,
511d04807b8SRavi Gunasekaran };
512d04807b8SRavi Gunasekaran
513d04807b8SRavi Gunasekaran static const struct soc_device_attribute k3_mdio_socinfo[] = {
514d04807b8SRavi Gunasekaran { .family = "AM62X", .revision = "SR1.0", .data = &am65_mdio_soc_data },
515d04807b8SRavi Gunasekaran { .family = "AM64X", .revision = "SR1.0", .data = &am65_mdio_soc_data },
516d04807b8SRavi Gunasekaran { .family = "AM64X", .revision = "SR2.0", .data = &am65_mdio_soc_data },
517d04807b8SRavi Gunasekaran { .family = "AM65X", .revision = "SR1.0", .data = &am65_mdio_soc_data },
518d04807b8SRavi Gunasekaran { .family = "AM65X", .revision = "SR2.0", .data = &am65_mdio_soc_data },
519d04807b8SRavi Gunasekaran { .family = "J7200", .revision = "SR1.0", .data = &am65_mdio_soc_data },
520d04807b8SRavi Gunasekaran { .family = "J7200", .revision = "SR2.0", .data = &am65_mdio_soc_data },
521d04807b8SRavi Gunasekaran { .family = "J721E", .revision = "SR1.0", .data = &am65_mdio_soc_data },
522d04807b8SRavi Gunasekaran { .family = "J721E", .revision = "SR2.0", .data = &am65_mdio_soc_data },
523d04807b8SRavi Gunasekaran { .family = "J721S2", .revision = "SR1.0", .data = &am65_mdio_soc_data},
524d04807b8SRavi Gunasekaran { /* sentinel */ },
525d04807b8SRavi Gunasekaran };
526d04807b8SRavi Gunasekaran
5279eae9c7dSGrygorii Strashko #if IS_ENABLED(CONFIG_OF)
5289eae9c7dSGrygorii Strashko static const struct davinci_mdio_of_param of_cpsw_mdio_data = {
5299eae9c7dSGrygorii Strashko .autosuspend_delay_ms = 100,
5309eae9c7dSGrygorii Strashko };
5319eae9c7dSGrygorii Strashko
5329eae9c7dSGrygorii Strashko static const struct of_device_id davinci_mdio_of_mtable[] = {
5339eae9c7dSGrygorii Strashko { .compatible = "ti,davinci_mdio", },
5349eae9c7dSGrygorii Strashko { .compatible = "ti,cpsw-mdio", .data = &of_cpsw_mdio_data},
5359eae9c7dSGrygorii Strashko { /* sentinel */ },
5369eae9c7dSGrygorii Strashko };
5379eae9c7dSGrygorii Strashko MODULE_DEVICE_TABLE(of, davinci_mdio_of_mtable);
5389eae9c7dSGrygorii Strashko #endif
5399eae9c7dSGrygorii Strashko
540d04807b8SRavi Gunasekaran static const struct mdiobb_ops davinci_mdiobb_ops = {
541d04807b8SRavi Gunasekaran .owner = THIS_MODULE,
542d04807b8SRavi Gunasekaran .set_mdc = davinci_set_mdc,
543d04807b8SRavi Gunasekaran .set_mdio_dir = davinci_set_mdio_dir,
544d04807b8SRavi Gunasekaran .set_mdio_data = davinci_set_mdio_data,
545d04807b8SRavi Gunasekaran .get_mdio_data = davinci_get_mdio_data,
546d04807b8SRavi Gunasekaran };
547d04807b8SRavi Gunasekaran
davinci_mdio_probe(struct platform_device * pdev)548e38921d4SBill Pemberton static int davinci_mdio_probe(struct platform_device *pdev)
549b544dbacSJeff Kirsher {
550894cdbb0SJingoo Han struct mdio_platform_data *pdata = dev_get_platdata(&pdev->dev);
551b544dbacSJeff Kirsher struct device *dev = &pdev->dev;
552b544dbacSJeff Kirsher struct davinci_mdio_data *data;
553b544dbacSJeff Kirsher struct resource *res;
554b544dbacSJeff Kirsher struct phy_device *phy;
555b544dbacSJeff Kirsher int ret, addr;
5569eae9c7dSGrygorii Strashko int autosuspend_delay_ms = -1;
557b544dbacSJeff Kirsher
55850d0636eSGrygorii Strashko data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
559b2adaca9SJoe Perches if (!data)
560b544dbacSJeff Kirsher return -ENOMEM;
561b544dbacSJeff Kirsher
562d04807b8SRavi Gunasekaran data->manual_mode = false;
563d04807b8SRavi Gunasekaran data->bb_ctrl.ops = &davinci_mdiobb_ops;
564d04807b8SRavi Gunasekaran
565d04807b8SRavi Gunasekaran if (IS_ENABLED(CONFIG_OF) && dev->of_node) {
566d04807b8SRavi Gunasekaran const struct soc_device_attribute *soc_match_data;
567d04807b8SRavi Gunasekaran
568d04807b8SRavi Gunasekaran soc_match_data = soc_device_match(k3_mdio_socinfo);
569d04807b8SRavi Gunasekaran if (soc_match_data && soc_match_data->data) {
570d04807b8SRavi Gunasekaran const struct k3_mdio_soc_data *socdata =
571d04807b8SRavi Gunasekaran soc_match_data->data;
572d04807b8SRavi Gunasekaran
573d04807b8SRavi Gunasekaran data->manual_mode = socdata->manual_mode;
574d04807b8SRavi Gunasekaran }
575d04807b8SRavi Gunasekaran }
576d04807b8SRavi Gunasekaran
577d04807b8SRavi Gunasekaran if (data->manual_mode)
578d04807b8SRavi Gunasekaran data->bus = alloc_mdio_bitbang(&data->bb_ctrl);
579d04807b8SRavi Gunasekaran else
58050d0636eSGrygorii Strashko data->bus = devm_mdiobus_alloc(dev);
581d04807b8SRavi Gunasekaran
582b544dbacSJeff Kirsher if (!data->bus) {
583b544dbacSJeff Kirsher dev_err(dev, "failed to alloc mii bus\n");
58450d0636eSGrygorii Strashko return -ENOMEM;
585b544dbacSJeff Kirsher }
586b544dbacSJeff Kirsher
58737c9102fSArnd Bergmann if (IS_ENABLED(CONFIG_OF) && dev->of_node) {
5880e658fddSStephen Boyd const struct davinci_mdio_of_param *of_mdio_data;
5899eae9c7dSGrygorii Strashko
5909eae9c7dSGrygorii Strashko ret = davinci_mdio_probe_dt(&data->pdata, pdev);
5919eae9c7dSGrygorii Strashko if (ret)
5929eae9c7dSGrygorii Strashko return ret;
593ec03e6a8SMugunthan V N snprintf(data->bus->id, MII_BUS_ID_SIZE, "%s", pdev->name);
5949eae9c7dSGrygorii Strashko
5950e658fddSStephen Boyd of_mdio_data = of_device_get_match_data(&pdev->dev);
5960e658fddSStephen Boyd if (of_mdio_data) {
5979eae9c7dSGrygorii Strashko autosuspend_delay_ms =
5989eae9c7dSGrygorii Strashko of_mdio_data->autosuspend_delay_ms;
5999eae9c7dSGrygorii Strashko }
600ec03e6a8SMugunthan V N } else {
601ec03e6a8SMugunthan V N data->pdata = pdata ? (*pdata) : default_pdata;
602ec03e6a8SMugunthan V N snprintf(data->bus->id, MII_BUS_ID_SIZE, "%s-%x",
603ec03e6a8SMugunthan V N pdev->name, pdev->id);
604ec03e6a8SMugunthan V N }
605ec03e6a8SMugunthan V N
606b544dbacSJeff Kirsher data->bus->name = dev_name(dev);
607d04807b8SRavi Gunasekaran
608d04807b8SRavi Gunasekaran if (data->manual_mode) {
609*002dd3deSAndrew Lunn data->bus->read = davinci_mdiobb_read_c22;
610*002dd3deSAndrew Lunn data->bus->write = davinci_mdiobb_write_c22;
611*002dd3deSAndrew Lunn data->bus->read_c45 = davinci_mdiobb_read_c45;
612*002dd3deSAndrew Lunn data->bus->write_c45 = davinci_mdiobb_write_c45;
613d04807b8SRavi Gunasekaran data->bus->reset = davinci_mdiobb_reset;
614d04807b8SRavi Gunasekaran
615d04807b8SRavi Gunasekaran dev_info(dev, "Configuring MDIO in manual mode\n");
616d04807b8SRavi Gunasekaran } else {
617011446cdSZheng Yongjun data->bus->read = davinci_mdio_read;
618011446cdSZheng Yongjun data->bus->write = davinci_mdio_write;
619011446cdSZheng Yongjun data->bus->reset = davinci_mdio_reset;
620b544dbacSJeff Kirsher data->bus->priv = data;
621d04807b8SRavi Gunasekaran }
622d04807b8SRavi Gunasekaran data->bus->parent = dev;
623b544dbacSJeff Kirsher
62450d0636eSGrygorii Strashko data->clk = devm_clk_get(dev, "fck");
625b544dbacSJeff Kirsher if (IS_ERR(data->clk)) {
626b544dbacSJeff Kirsher dev_err(dev, "failed to get device clock\n");
627909892a6SGrygorii Strashko return PTR_ERR(data->clk);
628b544dbacSJeff Kirsher }
629b544dbacSJeff Kirsher
630b544dbacSJeff Kirsher dev_set_drvdata(dev, data);
631b544dbacSJeff Kirsher data->dev = dev;
632b544dbacSJeff Kirsher
633b544dbacSJeff Kirsher res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
634e00edb4eSWei Yongjun if (!res)
635e00edb4eSWei Yongjun return -EINVAL;
63603f66f06SGrygorii Strashko data->regs = devm_ioremap(dev, res->start, resource_size(res));
637cc0d47b8SWei Yongjun if (!data->regs)
638cc0d47b8SWei Yongjun return -ENOMEM;
639909892a6SGrygorii Strashko
64028f0ccb9SGrygorii Strashko davinci_mdio_init_clk(data);
64128f0ccb9SGrygorii Strashko
6429eae9c7dSGrygorii Strashko pm_runtime_set_autosuspend_delay(&pdev->dev, autosuspend_delay_ms);
6438ea63bbaSGrygorii Strashko pm_runtime_use_autosuspend(&pdev->dev);
644909892a6SGrygorii Strashko pm_runtime_enable(&pdev->dev);
645b544dbacSJeff Kirsher
6460a0ea068SGrygorii Strashko /* register the mii bus
6470a0ea068SGrygorii Strashko * Create PHYs from DT only in case if PHY child nodes are explicitly
6480a0ea068SGrygorii Strashko * defined to support backward compatibility with DTs which assume that
6490a0ea068SGrygorii Strashko * Davinci MDIO will always scan the bus for PHYs detection.
6500a0ea068SGrygorii Strashko */
65100e798c7SFlorian Fainelli if (dev->of_node && of_get_child_count(dev->of_node))
6520a0ea068SGrygorii Strashko data->skip_scan = true;
65300e798c7SFlorian Fainelli
6540a0ea068SGrygorii Strashko ret = of_mdiobus_register(data->bus, dev->of_node);
655b544dbacSJeff Kirsher if (ret)
656b544dbacSJeff Kirsher goto bail_out;
657b544dbacSJeff Kirsher
658b544dbacSJeff Kirsher /* scan and dump the bus */
659b544dbacSJeff Kirsher for (addr = 0; addr < PHY_MAX_ADDR; addr++) {
6607f854420SAndrew Lunn phy = mdiobus_get_phy(data->bus, addr);
661b544dbacSJeff Kirsher if (phy) {
662b544dbacSJeff Kirsher dev_info(dev, "phy[%d]: device %s, driver %s\n",
663e5a03bfdSAndrew Lunn phy->mdio.addr, phydev_name(phy),
664b544dbacSJeff Kirsher phy->drv ? phy->drv->name : "unknown");
665b544dbacSJeff Kirsher }
666b544dbacSJeff Kirsher }
667b544dbacSJeff Kirsher
668b544dbacSJeff Kirsher return 0;
669b544dbacSJeff Kirsher
670b544dbacSJeff Kirsher bail_out:
6718ea63bbaSGrygorii Strashko pm_runtime_dont_use_autosuspend(&pdev->dev);
6728e476d9dSMugunthan V N pm_runtime_disable(&pdev->dev);
673b544dbacSJeff Kirsher return ret;
674b544dbacSJeff Kirsher }
675b544dbacSJeff Kirsher
davinci_mdio_remove(struct platform_device * pdev)676e38921d4SBill Pemberton static int davinci_mdio_remove(struct platform_device *pdev)
677b544dbacSJeff Kirsher {
67884ce22dfSLibo Chen struct davinci_mdio_data *data = platform_get_drvdata(pdev);
679b544dbacSJeff Kirsher
680d04807b8SRavi Gunasekaran if (data->bus) {
681b27393aeSBin Liu mdiobus_unregister(data->bus);
682b544dbacSJeff Kirsher
683d04807b8SRavi Gunasekaran if (data->manual_mode)
684d04807b8SRavi Gunasekaran free_mdio_bitbang(data->bus);
685d04807b8SRavi Gunasekaran }
686d04807b8SRavi Gunasekaran
6878ea63bbaSGrygorii Strashko pm_runtime_dont_use_autosuspend(&pdev->dev);
6888e476d9dSMugunthan V N pm_runtime_disable(&pdev->dev);
689b544dbacSJeff Kirsher
690b544dbacSJeff Kirsher return 0;
691b544dbacSJeff Kirsher }
692b544dbacSJeff Kirsher
693651652aaSGrygorii Strashko #ifdef CONFIG_PM
davinci_mdio_runtime_suspend(struct device * dev)694651652aaSGrygorii Strashko static int davinci_mdio_runtime_suspend(struct device *dev)
695b544dbacSJeff Kirsher {
696b544dbacSJeff Kirsher struct davinci_mdio_data *data = dev_get_drvdata(dev);
697b544dbacSJeff Kirsher u32 ctrl;
698b544dbacSJeff Kirsher
699b544dbacSJeff Kirsher /* shutdown the scan state machine */
700191aeea4SGrygorii Strashko ctrl = readl(&data->regs->control);
701b544dbacSJeff Kirsher ctrl &= ~CONTROL_ENABLE;
702191aeea4SGrygorii Strashko writel(ctrl, &data->regs->control);
703d04807b8SRavi Gunasekaran
704d04807b8SRavi Gunasekaran if (!data->manual_mode)
705b544dbacSJeff Kirsher wait_for_idle(data);
706b544dbacSJeff Kirsher
707651652aaSGrygorii Strashko return 0;
708651652aaSGrygorii Strashko }
709651652aaSGrygorii Strashko
davinci_mdio_runtime_resume(struct device * dev)710651652aaSGrygorii Strashko static int davinci_mdio_runtime_resume(struct device *dev)
711651652aaSGrygorii Strashko {
712651652aaSGrygorii Strashko struct davinci_mdio_data *data = dev_get_drvdata(dev);
713651652aaSGrygorii Strashko
714d04807b8SRavi Gunasekaran if (data->manual_mode) {
715d04807b8SRavi Gunasekaran davinci_mdio_disable(data);
716d04807b8SRavi Gunasekaran davinci_mdio_enable_manual_mode(data);
717d04807b8SRavi Gunasekaran } else {
718651652aaSGrygorii Strashko davinci_mdio_enable(data);
719d04807b8SRavi Gunasekaran }
720651652aaSGrygorii Strashko return 0;
721651652aaSGrygorii Strashko }
722651652aaSGrygorii Strashko #endif
723651652aaSGrygorii Strashko
724651652aaSGrygorii Strashko #ifdef CONFIG_PM_SLEEP
davinci_mdio_suspend(struct device * dev)725651652aaSGrygorii Strashko static int davinci_mdio_suspend(struct device *dev)
726651652aaSGrygorii Strashko {
727651652aaSGrygorii Strashko struct davinci_mdio_data *data = dev_get_drvdata(dev);
728651652aaSGrygorii Strashko int ret = 0;
729651652aaSGrygorii Strashko
7308ea63bbaSGrygorii Strashko data->active_in_suspend = !pm_runtime_status_suspended(dev);
7318ea63bbaSGrygorii Strashko if (data->active_in_suspend)
732651652aaSGrygorii Strashko ret = pm_runtime_force_suspend(dev);
733651652aaSGrygorii Strashko if (ret < 0)
734651652aaSGrygorii Strashko return ret;
735651652aaSGrygorii Strashko
7365c0e3580SMugunthan V N /* Select sleep pin state */
7375c0e3580SMugunthan V N pinctrl_pm_select_sleep_state(dev);
7385c0e3580SMugunthan V N
739b544dbacSJeff Kirsher return 0;
740b544dbacSJeff Kirsher }
741b544dbacSJeff Kirsher
davinci_mdio_resume(struct device * dev)742b544dbacSJeff Kirsher static int davinci_mdio_resume(struct device *dev)
743b544dbacSJeff Kirsher {
744b544dbacSJeff Kirsher struct davinci_mdio_data *data = dev_get_drvdata(dev);
745b544dbacSJeff Kirsher
7465c0e3580SMugunthan V N /* Select default pin state */
7475c0e3580SMugunthan V N pinctrl_pm_select_default_state(dev);
7485c0e3580SMugunthan V N
7498ea63bbaSGrygorii Strashko if (data->active_in_suspend)
750651652aaSGrygorii Strashko pm_runtime_force_resume(dev);
751b544dbacSJeff Kirsher
752b544dbacSJeff Kirsher return 0;
753b544dbacSJeff Kirsher }
7542f5c54ceSGrygorii Strashko #endif
755b544dbacSJeff Kirsher
756b544dbacSJeff Kirsher static const struct dev_pm_ops davinci_mdio_pm_ops = {
757651652aaSGrygorii Strashko SET_RUNTIME_PM_OPS(davinci_mdio_runtime_suspend,
758651652aaSGrygorii Strashko davinci_mdio_runtime_resume, NULL)
7592f5c54ceSGrygorii Strashko SET_LATE_SYSTEM_SLEEP_PM_OPS(davinci_mdio_suspend, davinci_mdio_resume)
760b544dbacSJeff Kirsher };
761b544dbacSJeff Kirsher
762b544dbacSJeff Kirsher static struct platform_driver davinci_mdio_driver = {
763b544dbacSJeff Kirsher .driver = {
764b544dbacSJeff Kirsher .name = "davinci_mdio",
765b544dbacSJeff Kirsher .pm = &davinci_mdio_pm_ops,
766ec03e6a8SMugunthan V N .of_match_table = of_match_ptr(davinci_mdio_of_mtable),
767b544dbacSJeff Kirsher },
768b544dbacSJeff Kirsher .probe = davinci_mdio_probe,
769e38921d4SBill Pemberton .remove = davinci_mdio_remove,
770b544dbacSJeff Kirsher };
771b544dbacSJeff Kirsher
davinci_mdio_init(void)772b544dbacSJeff Kirsher static int __init davinci_mdio_init(void)
773b544dbacSJeff Kirsher {
774b544dbacSJeff Kirsher return platform_driver_register(&davinci_mdio_driver);
775b544dbacSJeff Kirsher }
776b544dbacSJeff Kirsher device_initcall(davinci_mdio_init);
777b544dbacSJeff Kirsher
davinci_mdio_exit(void)778b544dbacSJeff Kirsher static void __exit davinci_mdio_exit(void)
779b544dbacSJeff Kirsher {
780b544dbacSJeff Kirsher platform_driver_unregister(&davinci_mdio_driver);
781b544dbacSJeff Kirsher }
782b544dbacSJeff Kirsher module_exit(davinci_mdio_exit);
783b544dbacSJeff Kirsher
784b544dbacSJeff Kirsher MODULE_LICENSE("GPL");
785b544dbacSJeff Kirsher MODULE_DESCRIPTION("DaVinci MDIO driver");
786