LCOV - code coverage report
Current view: top level - drivers/base - devcon.c (source / functions) Hit Total Coverage
Test: combined.info Lines: 0 71 0.0 %
Date: 2022-04-01 14:17:54 Functions: 0 8 0.0 %
Branches: 0 36 0.0 %

           Branch data     Line data    Source code
       1                 :            : // SPDX-License-Identifier: GPL-2.0
       2                 :            : /**
       3                 :            :  * Device connections
       4                 :            :  *
       5                 :            :  * Copyright (C) 2018 Intel Corporation
       6                 :            :  * Author: Heikki Krogerus <heikki.krogerus@linux.intel.com>
       7                 :            :  */
       8                 :            : 
       9                 :            : #include <linux/device.h>
      10                 :            : #include <linux/property.h>
      11                 :            : 
      12                 :            : static DEFINE_MUTEX(devcon_lock);
      13                 :            : static LIST_HEAD(devcon_list);
      14                 :            : 
      15                 :            : static void *
      16                 :          0 : fwnode_graph_devcon_match(struct fwnode_handle *fwnode, const char *con_id,
      17                 :            :                           void *data, devcon_match_fn_t match)
      18                 :            : {
      19                 :          0 :         struct device_connection con = { .id = con_id };
      20                 :          0 :         struct fwnode_handle *ep;
      21                 :          0 :         void *ret;
      22                 :            : 
      23         [ #  # ]:          0 :         fwnode_graph_for_each_endpoint(fwnode, ep) {
      24                 :          0 :                 con.fwnode = fwnode_graph_get_remote_port_parent(ep);
      25         [ #  # ]:          0 :                 if (!fwnode_device_is_available(con.fwnode))
      26                 :          0 :                         continue;
      27                 :            : 
      28                 :          0 :                 ret = match(&con, -1, data);
      29                 :          0 :                 fwnode_handle_put(con.fwnode);
      30         [ #  # ]:          0 :                 if (ret) {
      31                 :          0 :                         fwnode_handle_put(ep);
      32                 :          0 :                         return ret;
      33                 :            :                 }
      34                 :            :         }
      35                 :            :         return NULL;
      36                 :            : }
      37                 :            : 
      38                 :            : static void *
      39                 :          0 : fwnode_devcon_match(struct fwnode_handle *fwnode, const char *con_id,
      40                 :            :                     void *data, devcon_match_fn_t match)
      41                 :            : {
      42                 :          0 :         struct device_connection con = { };
      43                 :          0 :         void *ret;
      44                 :          0 :         int i;
      45                 :            : 
      46                 :          0 :         for (i = 0; ; i++) {
      47                 :          0 :                 con.fwnode = fwnode_find_reference(fwnode, con_id, i);
      48         [ #  # ]:          0 :                 if (IS_ERR(con.fwnode))
      49                 :            :                         break;
      50                 :            : 
      51                 :          0 :                 ret = match(&con, -1, data);
      52                 :          0 :                 fwnode_handle_put(con.fwnode);
      53         [ #  # ]:          0 :                 if (ret)
      54                 :          0 :                         return ret;
      55                 :            :         }
      56                 :            : 
      57                 :            :         return NULL;
      58                 :            : }
      59                 :            : 
      60                 :            : /**
      61                 :            :  * fwnode_connection_find_match - Find connection from a device node
      62                 :            :  * @fwnode: Device node with the connection
      63                 :            :  * @con_id: Identifier for the connection
      64                 :            :  * @data: Data for the match function
      65                 :            :  * @match: Function to check and convert the connection description
      66                 :            :  *
      67                 :            :  * Find a connection with unique identifier @con_id between @fwnode and another
      68                 :            :  * device node. @match will be used to convert the connection description to
      69                 :            :  * data the caller is expecting to be returned.
      70                 :            :  */
      71                 :          0 : void *fwnode_connection_find_match(struct fwnode_handle *fwnode,
      72                 :            :                                    const char *con_id, void *data,
      73                 :            :                                    devcon_match_fn_t match)
      74                 :            : {
      75                 :          0 :         void *ret;
      76                 :            : 
      77         [ #  # ]:          0 :         if (!fwnode || !match)
      78                 :            :                 return NULL;
      79                 :            : 
      80                 :          0 :         ret = fwnode_graph_devcon_match(fwnode, con_id, data, match);
      81         [ #  # ]:          0 :         if (ret)
      82                 :            :                 return ret;
      83                 :            : 
      84                 :          0 :         return fwnode_devcon_match(fwnode, con_id, data, match);
      85                 :            : }
      86                 :            : EXPORT_SYMBOL_GPL(fwnode_connection_find_match);
      87                 :            : 
      88                 :            : /**
      89                 :            :  * device_connection_find_match - Find physical connection to a device
      90                 :            :  * @dev: Device with the connection
      91                 :            :  * @con_id: Identifier for the connection
      92                 :            :  * @data: Data for the match function
      93                 :            :  * @match: Function to check and convert the connection description
      94                 :            :  *
      95                 :            :  * Find a connection with unique identifier @con_id between @dev and another
      96                 :            :  * device. @match will be used to convert the connection description to data the
      97                 :            :  * caller is expecting to be returned.
      98                 :            :  */
      99                 :          0 : void *device_connection_find_match(struct device *dev, const char *con_id,
     100                 :            :                                    void *data, devcon_match_fn_t match)
     101                 :            : {
     102                 :          0 :         struct fwnode_handle *fwnode = dev_fwnode(dev);
     103         [ #  # ]:          0 :         const char *devname = dev_name(dev);
     104                 :          0 :         struct device_connection *con;
     105                 :          0 :         void *ret = NULL;
     106                 :          0 :         int ep;
     107                 :            : 
     108         [ #  # ]:          0 :         if (!match)
     109                 :            :                 return NULL;
     110                 :            : 
     111                 :          0 :         ret = fwnode_connection_find_match(fwnode, con_id, data, match);
     112         [ #  # ]:          0 :         if (ret)
     113                 :            :                 return ret;
     114                 :            : 
     115                 :          0 :         mutex_lock(&devcon_lock);
     116                 :            : 
     117         [ #  # ]:          0 :         list_for_each_entry(con, &devcon_list, list) {
     118                 :          0 :                 ep = match_string(con->endpoint, 2, devname);
     119         [ #  # ]:          0 :                 if (ep < 0)
     120                 :          0 :                         continue;
     121                 :            : 
     122   [ #  #  #  # ]:          0 :                 if (con_id && strcmp(con->id, con_id))
     123                 :          0 :                         continue;
     124                 :            : 
     125                 :          0 :                 ret = match(con, !ep, data);
     126         [ #  # ]:          0 :                 if (ret)
     127                 :            :                         break;
     128                 :            :         }
     129                 :            : 
     130                 :          0 :         mutex_unlock(&devcon_lock);
     131                 :            : 
     132                 :          0 :         return ret;
     133                 :            : }
     134                 :            : EXPORT_SYMBOL_GPL(device_connection_find_match);
     135                 :            : 
     136                 :            : extern struct bus_type platform_bus_type;
     137                 :            : extern struct bus_type pci_bus_type;
     138                 :            : extern struct bus_type i2c_bus_type;
     139                 :            : extern struct bus_type spi_bus_type;
     140                 :            : 
     141                 :            : static struct bus_type *generic_match_buses[] = {
     142                 :            :         &platform_bus_type,
     143                 :            : #ifdef CONFIG_PCI
     144                 :            :         &pci_bus_type,
     145                 :            : #endif
     146                 :            : #ifdef CONFIG_I2C
     147                 :            :         &i2c_bus_type,
     148                 :            : #endif
     149                 :            : #ifdef CONFIG_SPI_MASTER
     150                 :            :         &spi_bus_type,
     151                 :            : #endif
     152                 :            :         NULL,
     153                 :            : };
     154                 :            : 
     155                 :            : static void *device_connection_fwnode_match(struct device_connection *con)
     156                 :            : {
     157                 :            :         struct bus_type *bus;
     158                 :            :         struct device *dev;
     159                 :            : 
     160                 :            :         for (bus = generic_match_buses[0]; bus; bus++) {
     161                 :            :                 dev = bus_find_device_by_fwnode(bus, con->fwnode);
     162                 :            :                 if (dev && !strncmp(dev_name(dev), con->id, strlen(con->id)))
     163                 :            :                         return dev;
     164                 :            : 
     165                 :            :                 put_device(dev);
     166                 :            :         }
     167                 :            :         return NULL;
     168                 :            : }
     169                 :            : 
     170                 :            : /* This tries to find the device from the most common bus types by name. */
     171                 :          0 : static void *generic_match(struct device_connection *con, int ep, void *data)
     172                 :            : {
     173                 :          0 :         struct bus_type *bus;
     174                 :          0 :         struct device *dev;
     175                 :            : 
     176         [ #  # ]:          0 :         if (con->fwnode)
     177                 :          0 :                 return device_connection_fwnode_match(con);
     178                 :            : 
     179         [ #  # ]:          0 :         for (bus = generic_match_buses[0]; bus; bus++) {
     180                 :          0 :                 dev = bus_find_device_by_name(bus, NULL, con->endpoint[ep]);
     181         [ #  # ]:          0 :                 if (dev)
     182                 :          0 :                         return dev;
     183                 :            :         }
     184                 :            : 
     185                 :            :         /*
     186                 :            :          * We only get called if a connection was found, tell the caller to
     187                 :            :          * wait for the other device to show up.
     188                 :            :          */
     189                 :            :         return ERR_PTR(-EPROBE_DEFER);
     190                 :            : }
     191                 :            : 
     192                 :            : /**
     193                 :            :  * device_connection_find - Find two devices connected together
     194                 :            :  * @dev: Device with the connection
     195                 :            :  * @con_id: Identifier for the connection
     196                 :            :  *
     197                 :            :  * Find a connection with unique identifier @con_id between @dev and
     198                 :            :  * another device. On success returns handle to the device that is connected
     199                 :            :  * to @dev, with the reference count for the found device incremented. Returns
     200                 :            :  * NULL if no matching connection was found, or ERR_PTR(-EPROBE_DEFER) when a
     201                 :            :  * connection was found but the other device has not been enumerated yet.
     202                 :            :  */
     203                 :          0 : struct device *device_connection_find(struct device *dev, const char *con_id)
     204                 :            : {
     205                 :          0 :         return device_connection_find_match(dev, con_id, NULL, generic_match);
     206                 :            : }
     207                 :            : EXPORT_SYMBOL_GPL(device_connection_find);
     208                 :            : 
     209                 :            : /**
     210                 :            :  * device_connection_add - Register a connection description
     211                 :            :  * @con: The connection description to be registered
     212                 :            :  */
     213                 :          0 : void device_connection_add(struct device_connection *con)
     214                 :            : {
     215                 :          0 :         mutex_lock(&devcon_lock);
     216                 :          0 :         list_add_tail(&con->list, &devcon_list);
     217                 :          0 :         mutex_unlock(&devcon_lock);
     218                 :          0 : }
     219                 :            : EXPORT_SYMBOL_GPL(device_connection_add);
     220                 :            : 
     221                 :            : /**
     222                 :            :  * device_connections_remove - Unregister connection description
     223                 :            :  * @con: The connection description to be unregistered
     224                 :            :  */
     225                 :          0 : void device_connection_remove(struct device_connection *con)
     226                 :            : {
     227                 :          0 :         mutex_lock(&devcon_lock);
     228                 :          0 :         list_del(&con->list);
     229                 :          0 :         mutex_unlock(&devcon_lock);
     230                 :          0 : }
     231                 :            : EXPORT_SYMBOL_GPL(device_connection_remove);

Generated by: LCOV version 1.14