Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause)
0002 // Copyright(c) 2015-17 Intel Corporation.
0003 
0004 #include <linux/acpi.h>
0005 #include <linux/of.h>
0006 #include <linux/soundwire/sdw.h>
0007 #include <linux/soundwire/sdw_type.h>
0008 #include "bus.h"
0009 #include "sysfs_local.h"
0010 
0011 static void sdw_slave_release(struct device *dev)
0012 {
0013     struct sdw_slave *slave = dev_to_sdw_dev(dev);
0014 
0015     mutex_destroy(&slave->sdw_dev_lock);
0016     kfree(slave);
0017 }
0018 
0019 struct device_type sdw_slave_type = {
0020     .name =     "sdw_slave",
0021     .release =  sdw_slave_release,
0022     .uevent =   sdw_slave_uevent,
0023 };
0024 
0025 int sdw_slave_add(struct sdw_bus *bus,
0026           struct sdw_slave_id *id, struct fwnode_handle *fwnode)
0027 {
0028     struct sdw_slave *slave;
0029     int ret;
0030     int i;
0031 
0032     slave = kzalloc(sizeof(*slave), GFP_KERNEL);
0033     if (!slave)
0034         return -ENOMEM;
0035 
0036     /* Initialize data structure */
0037     memcpy(&slave->id, id, sizeof(*id));
0038     slave->dev.parent = bus->dev;
0039     slave->dev.fwnode = fwnode;
0040 
0041     if (id->unique_id == SDW_IGNORED_UNIQUE_ID) {
0042         /* name shall be sdw:link:mfg:part:class */
0043         dev_set_name(&slave->dev, "sdw:%01x:%04x:%04x:%02x",
0044                  bus->link_id, id->mfg_id, id->part_id,
0045                  id->class_id);
0046     } else {
0047         /* name shall be sdw:link:mfg:part:class:unique */
0048         dev_set_name(&slave->dev, "sdw:%01x:%04x:%04x:%02x:%01x",
0049                  bus->link_id, id->mfg_id, id->part_id,
0050                  id->class_id, id->unique_id);
0051     }
0052 
0053     slave->dev.bus = &sdw_bus_type;
0054     slave->dev.of_node = of_node_get(to_of_node(fwnode));
0055     slave->dev.type = &sdw_slave_type;
0056     slave->dev.groups = sdw_slave_status_attr_groups;
0057     slave->bus = bus;
0058     slave->status = SDW_SLAVE_UNATTACHED;
0059     init_completion(&slave->enumeration_complete);
0060     init_completion(&slave->initialization_complete);
0061     slave->dev_num = 0;
0062     slave->probed = false;
0063     slave->first_interrupt_done = false;
0064     mutex_init(&slave->sdw_dev_lock);
0065 
0066     for (i = 0; i < SDW_MAX_PORTS; i++)
0067         init_completion(&slave->port_ready[i]);
0068 
0069     mutex_lock(&bus->bus_lock);
0070     list_add_tail(&slave->node, &bus->slaves);
0071     mutex_unlock(&bus->bus_lock);
0072 
0073     ret = device_register(&slave->dev);
0074     if (ret) {
0075         dev_err(bus->dev, "Failed to add slave: ret %d\n", ret);
0076 
0077         /*
0078          * On err, don't free but drop ref as this will be freed
0079          * when release method is invoked.
0080          */
0081         mutex_lock(&bus->bus_lock);
0082         list_del(&slave->node);
0083         mutex_unlock(&bus->bus_lock);
0084         put_device(&slave->dev);
0085 
0086         return ret;
0087     }
0088     sdw_slave_debugfs_init(slave);
0089 
0090     return ret;
0091 }
0092 EXPORT_SYMBOL(sdw_slave_add);
0093 
0094 #if IS_ENABLED(CONFIG_ACPI)
0095 
0096 static bool find_slave(struct sdw_bus *bus,
0097                struct acpi_device *adev,
0098                struct sdw_slave_id *id)
0099 {
0100     u64 addr;
0101     unsigned int link_id;
0102     acpi_status status;
0103 
0104     status = acpi_evaluate_integer(adev->handle,
0105                        METHOD_NAME__ADR, NULL, &addr);
0106 
0107     if (ACPI_FAILURE(status)) {
0108         dev_err(bus->dev, "_ADR resolution failed: %x\n",
0109             status);
0110         return false;
0111     }
0112 
0113     if (bus->ops->override_adr)
0114         addr = bus->ops->override_adr(bus, addr);
0115 
0116     if (!addr)
0117         return false;
0118 
0119     /* Extract link id from ADR, Bit 51 to 48 (included) */
0120     link_id = SDW_DISCO_LINK_ID(addr);
0121 
0122     /* Check for link_id match */
0123     if (link_id != bus->link_id)
0124         return false;
0125 
0126     sdw_extract_slave_id(bus, addr, id);
0127 
0128     return true;
0129 }
0130 
0131 struct sdw_acpi_child_walk_data {
0132     struct sdw_bus *bus;
0133     struct acpi_device *adev;
0134     struct sdw_slave_id id;
0135     bool ignore_unique_id;
0136 };
0137 
0138 static int sdw_acpi_check_duplicate(struct acpi_device *adev, void *data)
0139 {
0140     struct sdw_acpi_child_walk_data *cwd = data;
0141     struct sdw_bus *bus = cwd->bus;
0142     struct sdw_slave_id id;
0143 
0144     if (adev == cwd->adev)
0145         return 0;
0146 
0147     if (!find_slave(bus, adev, &id))
0148         return 0;
0149 
0150     if (cwd->id.sdw_version != id.sdw_version || cwd->id.mfg_id != id.mfg_id ||
0151         cwd->id.part_id != id.part_id || cwd->id.class_id != id.class_id)
0152         return 0;
0153 
0154     if (cwd->id.unique_id != id.unique_id) {
0155         dev_dbg(bus->dev,
0156             "Valid unique IDs 0x%x 0x%x for Slave mfg_id 0x%04x, part_id 0x%04x\n",
0157             cwd->id.unique_id, id.unique_id, cwd->id.mfg_id,
0158             cwd->id.part_id);
0159         cwd->ignore_unique_id = false;
0160         return 0;
0161     }
0162 
0163     dev_err(bus->dev,
0164         "Invalid unique IDs 0x%x 0x%x for Slave mfg_id 0x%04x, part_id 0x%04x\n",
0165         cwd->id.unique_id, id.unique_id, cwd->id.mfg_id, cwd->id.part_id);
0166     return -ENODEV;
0167 }
0168 
0169 static int sdw_acpi_find_one(struct acpi_device *adev, void *data)
0170 {
0171     struct sdw_bus *bus = data;
0172     struct sdw_acpi_child_walk_data cwd = {
0173         .bus = bus,
0174         .adev = adev,
0175         .ignore_unique_id = true,
0176     };
0177     int ret;
0178 
0179     if (!find_slave(bus, adev, &cwd.id))
0180         return 0;
0181 
0182     /* Brute-force O(N^2) search for duplicates. */
0183     ret = acpi_dev_for_each_child(ACPI_COMPANION(bus->dev),
0184                       sdw_acpi_check_duplicate, &cwd);
0185     if (ret)
0186         return ret;
0187 
0188     if (cwd.ignore_unique_id)
0189         cwd.id.unique_id = SDW_IGNORED_UNIQUE_ID;
0190 
0191     /* Ignore errors and continue. */
0192     sdw_slave_add(bus, &cwd.id, acpi_fwnode_handle(adev));
0193     return 0;
0194 }
0195 
0196 /*
0197  * sdw_acpi_find_slaves() - Find Slave devices in Master ACPI node
0198  * @bus: SDW bus instance
0199  *
0200  * Scans Master ACPI node for SDW child Slave devices and registers it.
0201  */
0202 int sdw_acpi_find_slaves(struct sdw_bus *bus)
0203 {
0204     struct acpi_device *parent;
0205 
0206     parent = ACPI_COMPANION(bus->dev);
0207     if (!parent) {
0208         dev_err(bus->dev, "Can't find parent for acpi bind\n");
0209         return -ENODEV;
0210     }
0211 
0212     return acpi_dev_for_each_child(parent, sdw_acpi_find_one, bus);
0213 }
0214 
0215 #endif
0216 
0217 /*
0218  * sdw_of_find_slaves() - Find Slave devices in master device tree node
0219  * @bus: SDW bus instance
0220  *
0221  * Scans Master DT node for SDW child Slave devices and registers it.
0222  */
0223 int sdw_of_find_slaves(struct sdw_bus *bus)
0224 {
0225     struct device *dev = bus->dev;
0226     struct device_node *node;
0227 
0228     for_each_child_of_node(bus->dev->of_node, node) {
0229         int link_id, ret, len;
0230         unsigned int sdw_version;
0231         const char *compat = NULL;
0232         struct sdw_slave_id id;
0233         const __be32 *addr;
0234 
0235         compat = of_get_property(node, "compatible", NULL);
0236         if (!compat)
0237             continue;
0238 
0239         ret = sscanf(compat, "sdw%01x%04hx%04hx%02hhx", &sdw_version,
0240                  &id.mfg_id, &id.part_id, &id.class_id);
0241 
0242         if (ret != 4) {
0243             dev_err(dev, "Invalid compatible string found %s\n",
0244                 compat);
0245             continue;
0246         }
0247 
0248         addr = of_get_property(node, "reg", &len);
0249         if (!addr || (len < 2 * sizeof(u32))) {
0250             dev_err(dev, "Invalid Link and Instance ID\n");
0251             continue;
0252         }
0253 
0254         link_id = be32_to_cpup(addr++);
0255         id.unique_id = be32_to_cpup(addr);
0256         id.sdw_version = sdw_version;
0257 
0258         /* Check for link_id match */
0259         if (link_id != bus->link_id)
0260             continue;
0261 
0262         sdw_slave_add(bus, &id, of_fwnode_handle(node));
0263     }
0264 
0265     return 0;
0266 }