Version:  2.0.40 2.2.26 2.4.37 3.11 3.12 3.13 3.14 3.15 3.16 3.17 3.18 3.19 4.0 4.1 4.2 4.3 4.4 4.5 4.6 4.7 4.8

Linux/drivers/usb/phy/phy-mxs-usb.c

  1 /*
  2  * Copyright 2012-2014 Freescale Semiconductor, Inc.
  3  * Copyright (C) 2012 Marek Vasut <marex@denx.de>
  4  * on behalf of DENX Software Engineering GmbH
  5  *
  6  * The code contained herein is licensed under the GNU General Public
  7  * License. You may obtain a copy of the GNU General Public License
  8  * Version 2 or later at the following locations:
  9  *
 10  * http://www.opensource.org/licenses/gpl-license.html
 11  * http://www.gnu.org/copyleft/gpl.html
 12  */
 13 
 14 #include <linux/module.h>
 15 #include <linux/kernel.h>
 16 #include <linux/platform_device.h>
 17 #include <linux/clk.h>
 18 #include <linux/usb/otg.h>
 19 #include <linux/stmp_device.h>
 20 #include <linux/delay.h>
 21 #include <linux/err.h>
 22 #include <linux/io.h>
 23 #include <linux/of_device.h>
 24 #include <linux/regmap.h>
 25 #include <linux/mfd/syscon.h>
 26 
 27 #define DRIVER_NAME "mxs_phy"
 28 
 29 #define HW_USBPHY_PWD                           0x00
 30 #define HW_USBPHY_CTRL                          0x30
 31 #define HW_USBPHY_CTRL_SET                      0x34
 32 #define HW_USBPHY_CTRL_CLR                      0x38
 33 
 34 #define HW_USBPHY_DEBUG_SET                     0x54
 35 #define HW_USBPHY_DEBUG_CLR                     0x58
 36 
 37 #define HW_USBPHY_IP                            0x90
 38 #define HW_USBPHY_IP_SET                        0x94
 39 #define HW_USBPHY_IP_CLR                        0x98
 40 
 41 #define BM_USBPHY_CTRL_SFTRST                   BIT(31)
 42 #define BM_USBPHY_CTRL_CLKGATE                  BIT(30)
 43 #define BM_USBPHY_CTRL_OTG_ID_VALUE             BIT(27)
 44 #define BM_USBPHY_CTRL_ENAUTOSET_USBCLKS        BIT(26)
 45 #define BM_USBPHY_CTRL_ENAUTOCLR_USBCLKGATE     BIT(25)
 46 #define BM_USBPHY_CTRL_ENVBUSCHG_WKUP           BIT(23)
 47 #define BM_USBPHY_CTRL_ENIDCHG_WKUP             BIT(22)
 48 #define BM_USBPHY_CTRL_ENDPDMCHG_WKUP           BIT(21)
 49 #define BM_USBPHY_CTRL_ENAUTOCLR_PHY_PWD        BIT(20)
 50 #define BM_USBPHY_CTRL_ENAUTOCLR_CLKGATE        BIT(19)
 51 #define BM_USBPHY_CTRL_ENAUTO_PWRON_PLL         BIT(18)
 52 #define BM_USBPHY_CTRL_ENUTMILEVEL3             BIT(15)
 53 #define BM_USBPHY_CTRL_ENUTMILEVEL2             BIT(14)
 54 #define BM_USBPHY_CTRL_ENHOSTDISCONDETECT       BIT(1)
 55 
 56 #define BM_USBPHY_IP_FIX                       (BIT(17) | BIT(18))
 57 
 58 #define BM_USBPHY_DEBUG_CLKGATE                 BIT(30)
 59 
 60 /* Anatop Registers */
 61 #define ANADIG_ANA_MISC0                        0x150
 62 #define ANADIG_ANA_MISC0_SET                    0x154
 63 #define ANADIG_ANA_MISC0_CLR                    0x158
 64 
 65 #define ANADIG_USB1_VBUS_DET_STAT               0x1c0
 66 #define ANADIG_USB2_VBUS_DET_STAT               0x220
 67 
 68 #define ANADIG_USB1_LOOPBACK_SET                0x1e4
 69 #define ANADIG_USB1_LOOPBACK_CLR                0x1e8
 70 #define ANADIG_USB2_LOOPBACK_SET                0x244
 71 #define ANADIG_USB2_LOOPBACK_CLR                0x248
 72 
 73 #define ANADIG_USB1_MISC                        0x1f0
 74 #define ANADIG_USB2_MISC                        0x250
 75 
 76 #define BM_ANADIG_ANA_MISC0_STOP_MODE_CONFIG    BIT(12)
 77 #define BM_ANADIG_ANA_MISC0_STOP_MODE_CONFIG_SL BIT(11)
 78 
 79 #define BM_ANADIG_USB1_VBUS_DET_STAT_VBUS_VALID BIT(3)
 80 #define BM_ANADIG_USB2_VBUS_DET_STAT_VBUS_VALID BIT(3)
 81 
 82 #define BM_ANADIG_USB1_LOOPBACK_UTMI_DIG_TST1   BIT(2)
 83 #define BM_ANADIG_USB1_LOOPBACK_TSTI_TX_EN      BIT(5)
 84 #define BM_ANADIG_USB2_LOOPBACK_UTMI_DIG_TST1   BIT(2)
 85 #define BM_ANADIG_USB2_LOOPBACK_TSTI_TX_EN      BIT(5)
 86 
 87 #define BM_ANADIG_USB1_MISC_RX_VPIN_FS          BIT(29)
 88 #define BM_ANADIG_USB1_MISC_RX_VMIN_FS          BIT(28)
 89 #define BM_ANADIG_USB2_MISC_RX_VPIN_FS          BIT(29)
 90 #define BM_ANADIG_USB2_MISC_RX_VMIN_FS          BIT(28)
 91 
 92 #define to_mxs_phy(p) container_of((p), struct mxs_phy, phy)
 93 
 94 /* Do disconnection between PHY and controller without vbus */
 95 #define MXS_PHY_DISCONNECT_LINE_WITHOUT_VBUS    BIT(0)
 96 
 97 /*
 98  * The PHY will be in messy if there is a wakeup after putting
 99  * bus to suspend (set portsc.suspendM) but before setting PHY to low
100  * power mode (set portsc.phcd).
101  */
102 #define MXS_PHY_ABNORMAL_IN_SUSPEND             BIT(1)
103 
104 /*
105  * The SOF sends too fast after resuming, it will cause disconnection
106  * between host and high speed device.
107  */
108 #define MXS_PHY_SENDING_SOF_TOO_FAST            BIT(2)
109 
110 /*
111  * IC has bug fixes logic, they include
112  * MXS_PHY_ABNORMAL_IN_SUSPEND and MXS_PHY_SENDING_SOF_TOO_FAST
113  * which are described at above flags, the RTL will handle it
114  * according to different versions.
115  */
116 #define MXS_PHY_NEED_IP_FIX                     BIT(3)
117 
118 struct mxs_phy_data {
119         unsigned int flags;
120 };
121 
122 static const struct mxs_phy_data imx23_phy_data = {
123         .flags = MXS_PHY_ABNORMAL_IN_SUSPEND | MXS_PHY_SENDING_SOF_TOO_FAST,
124 };
125 
126 static const struct mxs_phy_data imx6q_phy_data = {
127         .flags = MXS_PHY_SENDING_SOF_TOO_FAST |
128                 MXS_PHY_DISCONNECT_LINE_WITHOUT_VBUS |
129                 MXS_PHY_NEED_IP_FIX,
130 };
131 
132 static const struct mxs_phy_data imx6sl_phy_data = {
133         .flags = MXS_PHY_DISCONNECT_LINE_WITHOUT_VBUS |
134                 MXS_PHY_NEED_IP_FIX,
135 };
136 
137 static const struct mxs_phy_data vf610_phy_data = {
138         .flags = MXS_PHY_DISCONNECT_LINE_WITHOUT_VBUS |
139                 MXS_PHY_NEED_IP_FIX,
140 };
141 
142 static const struct mxs_phy_data imx6sx_phy_data = {
143         .flags = MXS_PHY_DISCONNECT_LINE_WITHOUT_VBUS,
144 };
145 
146 static const struct mxs_phy_data imx6ul_phy_data = {
147         .flags = MXS_PHY_DISCONNECT_LINE_WITHOUT_VBUS,
148 };
149 
150 static const struct of_device_id mxs_phy_dt_ids[] = {
151         { .compatible = "fsl,imx6sx-usbphy", .data = &imx6sx_phy_data, },
152         { .compatible = "fsl,imx6sl-usbphy", .data = &imx6sl_phy_data, },
153         { .compatible = "fsl,imx6q-usbphy", .data = &imx6q_phy_data, },
154         { .compatible = "fsl,imx23-usbphy", .data = &imx23_phy_data, },
155         { .compatible = "fsl,vf610-usbphy", .data = &vf610_phy_data, },
156         { .compatible = "fsl,imx6ul-usbphy", .data = &imx6ul_phy_data, },
157         { /* sentinel */ }
158 };
159 MODULE_DEVICE_TABLE(of, mxs_phy_dt_ids);
160 
161 struct mxs_phy {
162         struct usb_phy phy;
163         struct clk *clk;
164         const struct mxs_phy_data *data;
165         struct regmap *regmap_anatop;
166         int port_id;
167 };
168 
169 static inline bool is_imx6q_phy(struct mxs_phy *mxs_phy)
170 {
171         return mxs_phy->data == &imx6q_phy_data;
172 }
173 
174 static inline bool is_imx6sl_phy(struct mxs_phy *mxs_phy)
175 {
176         return mxs_phy->data == &imx6sl_phy_data;
177 }
178 
179 /*
180  * PHY needs some 32K cycles to switch from 32K clock to
181  * bus (such as AHB/AXI, etc) clock.
182  */
183 static void mxs_phy_clock_switch_delay(void)
184 {
185         usleep_range(300, 400);
186 }
187 
188 static int mxs_phy_hw_init(struct mxs_phy *mxs_phy)
189 {
190         int ret;
191         void __iomem *base = mxs_phy->phy.io_priv;
192 
193         ret = stmp_reset_block(base + HW_USBPHY_CTRL);
194         if (ret)
195                 return ret;
196 
197         /* Power up the PHY */
198         writel(0, base + HW_USBPHY_PWD);
199 
200         /*
201          * USB PHY Ctrl Setting
202          * - Auto clock/power on
203          * - Enable full/low speed support
204          */
205         writel(BM_USBPHY_CTRL_ENAUTOSET_USBCLKS |
206                 BM_USBPHY_CTRL_ENAUTOCLR_USBCLKGATE |
207                 BM_USBPHY_CTRL_ENAUTOCLR_PHY_PWD |
208                 BM_USBPHY_CTRL_ENAUTOCLR_CLKGATE |
209                 BM_USBPHY_CTRL_ENAUTO_PWRON_PLL |
210                 BM_USBPHY_CTRL_ENUTMILEVEL2 |
211                 BM_USBPHY_CTRL_ENUTMILEVEL3,
212                base + HW_USBPHY_CTRL_SET);
213 
214         if (mxs_phy->data->flags & MXS_PHY_NEED_IP_FIX)
215                 writel(BM_USBPHY_IP_FIX, base + HW_USBPHY_IP_SET);
216 
217         return 0;
218 }
219 
220 /* Return true if the vbus is there */
221 static bool mxs_phy_get_vbus_status(struct mxs_phy *mxs_phy)
222 {
223         unsigned int vbus_value = 0;
224 
225         if (!mxs_phy->regmap_anatop)
226                 return false;
227 
228         if (mxs_phy->port_id == 0)
229                 regmap_read(mxs_phy->regmap_anatop,
230                         ANADIG_USB1_VBUS_DET_STAT,
231                         &vbus_value);
232         else if (mxs_phy->port_id == 1)
233                 regmap_read(mxs_phy->regmap_anatop,
234                         ANADIG_USB2_VBUS_DET_STAT,
235                         &vbus_value);
236 
237         if (vbus_value & BM_ANADIG_USB1_VBUS_DET_STAT_VBUS_VALID)
238                 return true;
239         else
240                 return false;
241 }
242 
243 static void __mxs_phy_disconnect_line(struct mxs_phy *mxs_phy, bool disconnect)
244 {
245         void __iomem *base = mxs_phy->phy.io_priv;
246         u32 reg;
247 
248         if (disconnect)
249                 writel_relaxed(BM_USBPHY_DEBUG_CLKGATE,
250                         base + HW_USBPHY_DEBUG_CLR);
251 
252         if (mxs_phy->port_id == 0) {
253                 reg = disconnect ? ANADIG_USB1_LOOPBACK_SET
254                         : ANADIG_USB1_LOOPBACK_CLR;
255                 regmap_write(mxs_phy->regmap_anatop, reg,
256                         BM_ANADIG_USB1_LOOPBACK_UTMI_DIG_TST1 |
257                         BM_ANADIG_USB1_LOOPBACK_TSTI_TX_EN);
258         } else if (mxs_phy->port_id == 1) {
259                 reg = disconnect ? ANADIG_USB2_LOOPBACK_SET
260                         : ANADIG_USB2_LOOPBACK_CLR;
261                 regmap_write(mxs_phy->regmap_anatop, reg,
262                         BM_ANADIG_USB2_LOOPBACK_UTMI_DIG_TST1 |
263                         BM_ANADIG_USB2_LOOPBACK_TSTI_TX_EN);
264         }
265 
266         if (!disconnect)
267                 writel_relaxed(BM_USBPHY_DEBUG_CLKGATE,
268                         base + HW_USBPHY_DEBUG_SET);
269 
270         /* Delay some time, and let Linestate be SE0 for controller */
271         if (disconnect)
272                 usleep_range(500, 1000);
273 }
274 
275 static bool mxs_phy_is_otg_host(struct mxs_phy *mxs_phy)
276 {
277         void __iomem *base = mxs_phy->phy.io_priv;
278         u32 phyctrl = readl(base + HW_USBPHY_CTRL);
279 
280         if (IS_ENABLED(CONFIG_USB_OTG) &&
281                         !(phyctrl & BM_USBPHY_CTRL_OTG_ID_VALUE))
282                 return true;
283 
284         return false;
285 }
286 
287 static void mxs_phy_disconnect_line(struct mxs_phy *mxs_phy, bool on)
288 {
289         bool vbus_is_on = false;
290 
291         /* If the SoCs don't need to disconnect line without vbus, quit */
292         if (!(mxs_phy->data->flags & MXS_PHY_DISCONNECT_LINE_WITHOUT_VBUS))
293                 return;
294 
295         /* If the SoCs don't have anatop, quit */
296         if (!mxs_phy->regmap_anatop)
297                 return;
298 
299         vbus_is_on = mxs_phy_get_vbus_status(mxs_phy);
300 
301         if (on && !vbus_is_on && !mxs_phy_is_otg_host(mxs_phy))
302                 __mxs_phy_disconnect_line(mxs_phy, true);
303         else
304                 __mxs_phy_disconnect_line(mxs_phy, false);
305 
306 }
307 
308 static int mxs_phy_init(struct usb_phy *phy)
309 {
310         int ret;
311         struct mxs_phy *mxs_phy = to_mxs_phy(phy);
312 
313         mxs_phy_clock_switch_delay();
314         ret = clk_prepare_enable(mxs_phy->clk);
315         if (ret)
316                 return ret;
317 
318         return mxs_phy_hw_init(mxs_phy);
319 }
320 
321 static void mxs_phy_shutdown(struct usb_phy *phy)
322 {
323         struct mxs_phy *mxs_phy = to_mxs_phy(phy);
324         u32 value = BM_USBPHY_CTRL_ENVBUSCHG_WKUP |
325                         BM_USBPHY_CTRL_ENDPDMCHG_WKUP |
326                         BM_USBPHY_CTRL_ENIDCHG_WKUP |
327                         BM_USBPHY_CTRL_ENAUTOSET_USBCLKS |
328                         BM_USBPHY_CTRL_ENAUTOCLR_USBCLKGATE |
329                         BM_USBPHY_CTRL_ENAUTOCLR_PHY_PWD |
330                         BM_USBPHY_CTRL_ENAUTOCLR_CLKGATE |
331                         BM_USBPHY_CTRL_ENAUTO_PWRON_PLL;
332 
333         writel(value, phy->io_priv + HW_USBPHY_CTRL_CLR);
334         writel(0xffffffff, phy->io_priv + HW_USBPHY_PWD);
335 
336         writel(BM_USBPHY_CTRL_CLKGATE,
337                phy->io_priv + HW_USBPHY_CTRL_SET);
338 
339         clk_disable_unprepare(mxs_phy->clk);
340 }
341 
342 static bool mxs_phy_is_low_speed_connection(struct mxs_phy *mxs_phy)
343 {
344         unsigned int line_state;
345         /* bit definition is the same for all controllers */
346         unsigned int dp_bit = BM_ANADIG_USB1_MISC_RX_VPIN_FS,
347                      dm_bit = BM_ANADIG_USB1_MISC_RX_VMIN_FS;
348         unsigned int reg = ANADIG_USB1_MISC;
349 
350         /* If the SoCs don't have anatop, quit */
351         if (!mxs_phy->regmap_anatop)
352                 return false;
353 
354         if (mxs_phy->port_id == 0)
355                 reg = ANADIG_USB1_MISC;
356         else if (mxs_phy->port_id == 1)
357                 reg = ANADIG_USB2_MISC;
358 
359         regmap_read(mxs_phy->regmap_anatop, reg, &line_state);
360 
361         if ((line_state & (dp_bit | dm_bit)) ==  dm_bit)
362                 return true;
363         else
364                 return false;
365 }
366 
367 static int mxs_phy_suspend(struct usb_phy *x, int suspend)
368 {
369         int ret;
370         struct mxs_phy *mxs_phy = to_mxs_phy(x);
371         bool low_speed_connection, vbus_is_on;
372 
373         low_speed_connection = mxs_phy_is_low_speed_connection(mxs_phy);
374         vbus_is_on = mxs_phy_get_vbus_status(mxs_phy);
375 
376         if (suspend) {
377                 /*
378                  * FIXME: Do not power down RXPWD1PT1 bit for low speed
379                  * connect. The low speed connection will have problem at
380                  * very rare cases during usb suspend and resume process.
381                  */
382                 if (low_speed_connection & vbus_is_on) {
383                         /*
384                          * If value to be set as pwd value is not 0xffffffff,
385                          * several 32Khz cycles are needed.
386                          */
387                         mxs_phy_clock_switch_delay();
388                         writel(0xffbfffff, x->io_priv + HW_USBPHY_PWD);
389                 } else {
390                         writel(0xffffffff, x->io_priv + HW_USBPHY_PWD);
391                 }
392                 writel(BM_USBPHY_CTRL_CLKGATE,
393                        x->io_priv + HW_USBPHY_CTRL_SET);
394                 clk_disable_unprepare(mxs_phy->clk);
395         } else {
396                 mxs_phy_clock_switch_delay();
397                 ret = clk_prepare_enable(mxs_phy->clk);
398                 if (ret)
399                         return ret;
400                 writel(BM_USBPHY_CTRL_CLKGATE,
401                        x->io_priv + HW_USBPHY_CTRL_CLR);
402                 writel(0, x->io_priv + HW_USBPHY_PWD);
403         }
404 
405         return 0;
406 }
407 
408 static int mxs_phy_set_wakeup(struct usb_phy *x, bool enabled)
409 {
410         struct mxs_phy *mxs_phy = to_mxs_phy(x);
411         u32 value = BM_USBPHY_CTRL_ENVBUSCHG_WKUP |
412                         BM_USBPHY_CTRL_ENDPDMCHG_WKUP |
413                                 BM_USBPHY_CTRL_ENIDCHG_WKUP;
414         if (enabled) {
415                 mxs_phy_disconnect_line(mxs_phy, true);
416                 writel_relaxed(value, x->io_priv + HW_USBPHY_CTRL_SET);
417         } else {
418                 writel_relaxed(value, x->io_priv + HW_USBPHY_CTRL_CLR);
419                 mxs_phy_disconnect_line(mxs_phy, false);
420         }
421 
422         return 0;
423 }
424 
425 static int mxs_phy_on_connect(struct usb_phy *phy,
426                 enum usb_device_speed speed)
427 {
428         dev_dbg(phy->dev, "%s device has connected\n",
429                 (speed == USB_SPEED_HIGH) ? "HS" : "FS/LS");
430 
431         if (speed == USB_SPEED_HIGH)
432                 writel(BM_USBPHY_CTRL_ENHOSTDISCONDETECT,
433                        phy->io_priv + HW_USBPHY_CTRL_SET);
434 
435         return 0;
436 }
437 
438 static int mxs_phy_on_disconnect(struct usb_phy *phy,
439                 enum usb_device_speed speed)
440 {
441         dev_dbg(phy->dev, "%s device has disconnected\n",
442                 (speed == USB_SPEED_HIGH) ? "HS" : "FS/LS");
443 
444         /* Sometimes, the speed is not high speed when the error occurs */
445         if (readl(phy->io_priv + HW_USBPHY_CTRL) &
446                         BM_USBPHY_CTRL_ENHOSTDISCONDETECT)
447                 writel(BM_USBPHY_CTRL_ENHOSTDISCONDETECT,
448                        phy->io_priv + HW_USBPHY_CTRL_CLR);
449 
450         return 0;
451 }
452 
453 static int mxs_phy_probe(struct platform_device *pdev)
454 {
455         struct resource *res;
456         void __iomem *base;
457         struct clk *clk;
458         struct mxs_phy *mxs_phy;
459         int ret;
460         const struct of_device_id *of_id;
461         struct device_node *np = pdev->dev.of_node;
462 
463         of_id = of_match_device(mxs_phy_dt_ids, &pdev->dev);
464         if (!of_id)
465                 return -ENODEV;
466 
467         res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
468         base = devm_ioremap_resource(&pdev->dev, res);
469         if (IS_ERR(base))
470                 return PTR_ERR(base);
471 
472         clk = devm_clk_get(&pdev->dev, NULL);
473         if (IS_ERR(clk)) {
474                 dev_err(&pdev->dev,
475                         "can't get the clock, err=%ld", PTR_ERR(clk));
476                 return PTR_ERR(clk);
477         }
478 
479         mxs_phy = devm_kzalloc(&pdev->dev, sizeof(*mxs_phy), GFP_KERNEL);
480         if (!mxs_phy)
481                 return -ENOMEM;
482 
483         /* Some SoCs don't have anatop registers */
484         if (of_get_property(np, "fsl,anatop", NULL)) {
485                 mxs_phy->regmap_anatop = syscon_regmap_lookup_by_phandle
486                         (np, "fsl,anatop");
487                 if (IS_ERR(mxs_phy->regmap_anatop)) {
488                         dev_dbg(&pdev->dev,
489                                 "failed to find regmap for anatop\n");
490                         return PTR_ERR(mxs_phy->regmap_anatop);
491                 }
492         }
493 
494         ret = of_alias_get_id(np, "usbphy");
495         if (ret < 0)
496                 dev_dbg(&pdev->dev, "failed to get alias id, errno %d\n", ret);
497         mxs_phy->port_id = ret;
498 
499         mxs_phy->phy.io_priv            = base;
500         mxs_phy->phy.dev                = &pdev->dev;
501         mxs_phy->phy.label              = DRIVER_NAME;
502         mxs_phy->phy.init               = mxs_phy_init;
503         mxs_phy->phy.shutdown           = mxs_phy_shutdown;
504         mxs_phy->phy.set_suspend        = mxs_phy_suspend;
505         mxs_phy->phy.notify_connect     = mxs_phy_on_connect;
506         mxs_phy->phy.notify_disconnect  = mxs_phy_on_disconnect;
507         mxs_phy->phy.type               = USB_PHY_TYPE_USB2;
508         mxs_phy->phy.set_wakeup         = mxs_phy_set_wakeup;
509 
510         mxs_phy->clk = clk;
511         mxs_phy->data = of_id->data;
512 
513         platform_set_drvdata(pdev, mxs_phy);
514 
515         device_set_wakeup_capable(&pdev->dev, true);
516 
517         return usb_add_phy_dev(&mxs_phy->phy);
518 }
519 
520 static int mxs_phy_remove(struct platform_device *pdev)
521 {
522         struct mxs_phy *mxs_phy = platform_get_drvdata(pdev);
523 
524         usb_remove_phy(&mxs_phy->phy);
525 
526         return 0;
527 }
528 
529 #ifdef CONFIG_PM_SLEEP
530 static void mxs_phy_enable_ldo_in_suspend(struct mxs_phy *mxs_phy, bool on)
531 {
532         unsigned int reg = on ? ANADIG_ANA_MISC0_SET : ANADIG_ANA_MISC0_CLR;
533 
534         /* If the SoCs don't have anatop, quit */
535         if (!mxs_phy->regmap_anatop)
536                 return;
537 
538         if (is_imx6q_phy(mxs_phy))
539                 regmap_write(mxs_phy->regmap_anatop, reg,
540                         BM_ANADIG_ANA_MISC0_STOP_MODE_CONFIG);
541         else if (is_imx6sl_phy(mxs_phy))
542                 regmap_write(mxs_phy->regmap_anatop,
543                         reg, BM_ANADIG_ANA_MISC0_STOP_MODE_CONFIG_SL);
544 }
545 
546 static int mxs_phy_system_suspend(struct device *dev)
547 {
548         struct mxs_phy *mxs_phy = dev_get_drvdata(dev);
549 
550         if (device_may_wakeup(dev))
551                 mxs_phy_enable_ldo_in_suspend(mxs_phy, true);
552 
553         return 0;
554 }
555 
556 static int mxs_phy_system_resume(struct device *dev)
557 {
558         struct mxs_phy *mxs_phy = dev_get_drvdata(dev);
559 
560         if (device_may_wakeup(dev))
561                 mxs_phy_enable_ldo_in_suspend(mxs_phy, false);
562 
563         return 0;
564 }
565 #endif /* CONFIG_PM_SLEEP */
566 
567 static SIMPLE_DEV_PM_OPS(mxs_phy_pm, mxs_phy_system_suspend,
568                 mxs_phy_system_resume);
569 
570 static struct platform_driver mxs_phy_driver = {
571         .probe = mxs_phy_probe,
572         .remove = mxs_phy_remove,
573         .driver = {
574                 .name = DRIVER_NAME,
575                 .of_match_table = mxs_phy_dt_ids,
576                 .pm = &mxs_phy_pm,
577          },
578 };
579 
580 static int __init mxs_phy_module_init(void)
581 {
582         return platform_driver_register(&mxs_phy_driver);
583 }
584 postcore_initcall(mxs_phy_module_init);
585 
586 static void __exit mxs_phy_module_exit(void)
587 {
588         platform_driver_unregister(&mxs_phy_driver);
589 }
590 module_exit(mxs_phy_module_exit);
591 
592 MODULE_ALIAS("platform:mxs-usb-phy");
593 MODULE_AUTHOR("Marek Vasut <marex@denx.de>");
594 MODULE_AUTHOR("Richard Zhao <richard.zhao@freescale.com>");
595 MODULE_DESCRIPTION("Freescale MXS USB PHY driver");
596 MODULE_LICENSE("GPL");
597 

This page was automatically generated by LXR 0.3.1 (source).  •  Linux is a registered trademark of Linus Torvalds  •  Contact us