LCOV - code coverage report
Current view: top level - drivers/usb/core - phy.c (source / functions) Hit Total Coverage
Test: combined.info Lines: 0 75 0.0 %
Date: 2022-03-28 15:32:58 Functions: 0 9 0.0 %
Branches: 0 82 0.0 %

           Branch data     Line data    Source code
       1                 :            : // SPDX-License-Identifier: GPL-2.0+
       2                 :            : /*
       3                 :            :  * A wrapper for multiple PHYs which passes all phy_* function calls to
       4                 :            :  * multiple (actual) PHY devices. This is comes handy when initializing
       5                 :            :  * all PHYs on a HCD and to keep them all in the same state.
       6                 :            :  *
       7                 :            :  * Copyright (C) 2018 Martin Blumenstingl <martin.blumenstingl@googlemail.com>
       8                 :            :  */
       9                 :            : 
      10                 :            : #include <linux/device.h>
      11                 :            : #include <linux/list.h>
      12                 :            : #include <linux/phy/phy.h>
      13                 :            : #include <linux/of.h>
      14                 :            : 
      15                 :            : #include "phy.h"
      16                 :            : 
      17                 :            : struct usb_phy_roothub {
      18                 :            :         struct phy              *phy;
      19                 :            :         struct list_head        list;
      20                 :            : };
      21                 :            : 
      22                 :            : static int usb_phy_roothub_add_phy(struct device *dev, int index,
      23                 :            :                                    struct list_head *list)
      24                 :            : {
      25                 :            :         struct usb_phy_roothub *roothub_entry;
      26                 :            :         struct phy *phy;
      27                 :            : 
      28                 :            :         phy = devm_of_phy_get_by_index(dev, dev->of_node, index);
      29                 :            :         if (IS_ERR(phy)) {
      30                 :            :                 if (PTR_ERR(phy) == -ENODEV)
      31                 :            :                         return 0;
      32                 :            :                 else
      33                 :            :                         return PTR_ERR(phy);
      34                 :            :         }
      35                 :            : 
      36                 :            :         roothub_entry = devm_kzalloc(dev, sizeof(*roothub_entry), GFP_KERNEL);
      37                 :            :         if (!roothub_entry)
      38                 :            :                 return -ENOMEM;
      39                 :            : 
      40                 :            :         INIT_LIST_HEAD(&roothub_entry->list);
      41                 :            : 
      42                 :            :         roothub_entry->phy = phy;
      43                 :            : 
      44                 :            :         list_add_tail(&roothub_entry->list, list);
      45                 :            : 
      46                 :            :         return 0;
      47                 :            : }
      48                 :            : 
      49                 :          0 : struct usb_phy_roothub *usb_phy_roothub_alloc(struct device *dev)
      50                 :            : {
      51                 :          0 :         struct usb_phy_roothub *phy_roothub;
      52                 :          0 :         int i, num_phys, err;
      53                 :            : 
      54                 :          0 :         if (!IS_ENABLED(CONFIG_GENERIC_PHY))
      55                 :          0 :                 return NULL;
      56                 :            : 
      57                 :            :         num_phys = of_count_phandle_with_args(dev->of_node, "phys",
      58                 :            :                                               "#phy-cells");
      59                 :            :         if (num_phys <= 0)
      60                 :            :                 return NULL;
      61                 :            : 
      62                 :            :         phy_roothub = devm_kzalloc(dev, sizeof(*phy_roothub), GFP_KERNEL);
      63                 :            :         if (!phy_roothub)
      64                 :            :                 return ERR_PTR(-ENOMEM);
      65                 :            : 
      66                 :            :         INIT_LIST_HEAD(&phy_roothub->list);
      67                 :            : 
      68                 :            :         for (i = 0; i < num_phys; i++) {
      69                 :            :                 err = usb_phy_roothub_add_phy(dev, i, &phy_roothub->list);
      70                 :            :                 if (err)
      71                 :            :                         return ERR_PTR(err);
      72                 :            :         }
      73                 :            : 
      74                 :            :         return phy_roothub;
      75                 :            : }
      76                 :            : EXPORT_SYMBOL_GPL(usb_phy_roothub_alloc);
      77                 :            : 
      78                 :          0 : int usb_phy_roothub_init(struct usb_phy_roothub *phy_roothub)
      79                 :            : {
      80                 :          0 :         struct usb_phy_roothub *roothub_entry;
      81                 :          0 :         struct list_head *head;
      82                 :          0 :         int err;
      83                 :            : 
      84         [ #  # ]:          0 :         if (!phy_roothub)
      85                 :            :                 return 0;
      86                 :            : 
      87                 :          0 :         head = &phy_roothub->list;
      88                 :            : 
      89   [ #  #  #  # ]:          0 :         list_for_each_entry(roothub_entry, head, list) {
      90   [ #  #  #  # ]:          0 :                 err = phy_init(roothub_entry->phy);
      91                 :          0 :                 if (err)
      92                 :          0 :                         goto err_exit_phys;
      93                 :            :         }
      94                 :            : 
      95                 :            :         return 0;
      96                 :            : 
      97                 :            : err_exit_phys:
      98   [ #  #  #  # ]:          0 :         list_for_each_entry_continue_reverse(roothub_entry, head, list)
      99                 :          0 :                 phy_exit(roothub_entry->phy);
     100                 :            : 
     101                 :            :         return err;
     102                 :            : }
     103                 :            : EXPORT_SYMBOL_GPL(usb_phy_roothub_init);
     104                 :            : 
     105                 :          0 : int usb_phy_roothub_exit(struct usb_phy_roothub *phy_roothub)
     106                 :            : {
     107                 :          0 :         struct usb_phy_roothub *roothub_entry;
     108                 :          0 :         struct list_head *head;
     109                 :          0 :         int err, ret = 0;
     110                 :            : 
     111         [ #  # ]:          0 :         if (!phy_roothub)
     112                 :            :                 return 0;
     113                 :            : 
     114                 :          0 :         head = &phy_roothub->list;
     115                 :            : 
     116   [ #  #  #  #  :          0 :         list_for_each_entry(roothub_entry, head, list) {
                   #  # ]
     117   [ #  #  #  # ]:          0 :                 err = phy_exit(roothub_entry->phy);
     118                 :          0 :                 if (err)
     119                 :            :                         ret = err;
     120                 :            :         }
     121                 :            : 
     122                 :            :         return ret;
     123                 :            : }
     124                 :            : EXPORT_SYMBOL_GPL(usb_phy_roothub_exit);
     125                 :            : 
     126                 :          0 : int usb_phy_roothub_set_mode(struct usb_phy_roothub *phy_roothub,
     127                 :            :                              enum phy_mode mode)
     128                 :            : {
     129                 :          0 :         struct usb_phy_roothub *roothub_entry;
     130                 :          0 :         struct list_head *head;
     131                 :          0 :         int err;
     132                 :            : 
     133         [ #  # ]:          0 :         if (!phy_roothub)
     134                 :            :                 return 0;
     135                 :            : 
     136                 :          0 :         head = &phy_roothub->list;
     137                 :            : 
     138         [ #  # ]:          0 :         list_for_each_entry(roothub_entry, head, list) {
     139         [ #  # ]:          0 :                 err = phy_set_mode(roothub_entry->phy, mode);
     140                 :          0 :                 if (err)
     141                 :          0 :                         goto err_out;
     142                 :            :         }
     143                 :            : 
     144                 :            :         return 0;
     145                 :            : 
     146                 :            : err_out:
     147         [ #  # ]:          0 :         list_for_each_entry_continue_reverse(roothub_entry, head, list)
     148                 :          0 :                 phy_power_off(roothub_entry->phy);
     149                 :            : 
     150                 :            :         return err;
     151                 :            : }
     152                 :            : EXPORT_SYMBOL_GPL(usb_phy_roothub_set_mode);
     153                 :            : 
     154                 :          0 : int usb_phy_roothub_calibrate(struct usb_phy_roothub *phy_roothub)
     155                 :            : {
     156                 :          0 :         struct usb_phy_roothub *roothub_entry;
     157                 :          0 :         struct list_head *head;
     158                 :          0 :         int err;
     159                 :            : 
     160         [ #  # ]:          0 :         if (!phy_roothub)
     161                 :            :                 return 0;
     162                 :            : 
     163                 :          0 :         head = &phy_roothub->list;
     164                 :            : 
     165         [ #  # ]:          0 :         list_for_each_entry(roothub_entry, head, list) {
     166         [ #  # ]:          0 :                 err = phy_calibrate(roothub_entry->phy);
     167                 :          0 :                 if (err)
     168                 :            :                         return err;
     169                 :            :         }
     170                 :            : 
     171                 :            :         return 0;
     172                 :            : }
     173                 :            : EXPORT_SYMBOL_GPL(usb_phy_roothub_calibrate);
     174                 :            : 
     175                 :          0 : int usb_phy_roothub_power_on(struct usb_phy_roothub *phy_roothub)
     176                 :            : {
     177                 :          0 :         struct usb_phy_roothub *roothub_entry;
     178                 :          0 :         struct list_head *head;
     179                 :          0 :         int err;
     180                 :            : 
     181         [ #  # ]:          0 :         if (!phy_roothub)
     182                 :            :                 return 0;
     183                 :            : 
     184                 :          0 :         head = &phy_roothub->list;
     185                 :            : 
     186   [ #  #  #  # ]:          0 :         list_for_each_entry(roothub_entry, head, list) {
     187   [ #  #  #  # ]:          0 :                 err = phy_power_on(roothub_entry->phy);
     188                 :          0 :                 if (err)
     189                 :          0 :                         goto err_out;
     190                 :            :         }
     191                 :            : 
     192                 :            :         return 0;
     193                 :            : 
     194                 :            : err_out:
     195   [ #  #  #  # ]:          0 :         list_for_each_entry_continue_reverse(roothub_entry, head, list)
     196                 :          0 :                 phy_power_off(roothub_entry->phy);
     197                 :            : 
     198                 :            :         return err;
     199                 :            : }
     200                 :            : EXPORT_SYMBOL_GPL(usb_phy_roothub_power_on);
     201                 :            : 
     202                 :          0 : void usb_phy_roothub_power_off(struct usb_phy_roothub *phy_roothub)
     203                 :            : {
     204                 :          0 :         struct usb_phy_roothub *roothub_entry;
     205                 :            : 
     206         [ #  # ]:          0 :         if (!phy_roothub)
     207                 :            :                 return;
     208                 :            : 
     209   [ #  #  #  # ]:          0 :         list_for_each_entry_reverse(roothub_entry, &phy_roothub->list, list)
     210                 :          0 :                 phy_power_off(roothub_entry->phy);
     211                 :            : }
     212                 :            : EXPORT_SYMBOL_GPL(usb_phy_roothub_power_off);
     213                 :            : 
     214                 :          0 : int usb_phy_roothub_suspend(struct device *controller_dev,
     215                 :            :                             struct usb_phy_roothub *phy_roothub)
     216                 :            : {
     217         [ #  # ]:          0 :         usb_phy_roothub_power_off(phy_roothub);
     218                 :            : 
     219                 :            :         /* keep the PHYs initialized so the device can wake up the system */
     220   [ #  #  #  # ]:          0 :         if (device_may_wakeup(controller_dev))
     221                 :            :                 return 0;
     222                 :            : 
     223         [ #  # ]:          0 :         return usb_phy_roothub_exit(phy_roothub);
     224                 :            : }
     225                 :            : EXPORT_SYMBOL_GPL(usb_phy_roothub_suspend);
     226                 :            : 
     227                 :          0 : int usb_phy_roothub_resume(struct device *controller_dev,
     228                 :            :                            struct usb_phy_roothub *phy_roothub)
     229                 :            : {
     230                 :          0 :         int err;
     231                 :            : 
     232                 :            :         /* if the device can't wake up the system _exit was called */
     233   [ #  #  #  # ]:          0 :         if (!device_may_wakeup(controller_dev)) {
     234         [ #  # ]:          0 :                 err = usb_phy_roothub_init(phy_roothub);
     235         [ #  # ]:          0 :                 if (err)
     236                 :            :                         return err;
     237                 :            :         }
     238                 :            : 
     239         [ #  # ]:          0 :         err = usb_phy_roothub_power_on(phy_roothub);
     240                 :            : 
     241                 :            :         /* undo _init if _power_on failed */
     242   [ #  #  #  # ]:          0 :         if (err && !device_may_wakeup(controller_dev))
     243                 :            :                 usb_phy_roothub_exit(phy_roothub);
     244                 :            : 
     245                 :            :         return err;
     246                 :            : }
     247                 :            : EXPORT_SYMBOL_GPL(usb_phy_roothub_resume);

Generated by: LCOV version 1.14