linux/drivers/soundwire/slave.c
<<
>>
Prefs
   1// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause)
   2// Copyright(c) 2015-17 Intel Corporation.
   3
   4#include <linux/acpi.h>
   5#include <linux/soundwire/sdw.h>
   6#include <linux/soundwire/sdw_type.h>
   7#include "bus.h"
   8
   9static void sdw_slave_release(struct device *dev)
  10{
  11        struct sdw_slave *slave = dev_to_sdw_dev(dev);
  12
  13        kfree(slave);
  14}
  15
  16static int sdw_slave_add(struct sdw_bus *bus,
  17                         struct sdw_slave_id *id, struct fwnode_handle *fwnode)
  18{
  19        struct sdw_slave *slave;
  20        int ret;
  21
  22        slave = kzalloc(sizeof(*slave), GFP_KERNEL);
  23        if (!slave)
  24                return -ENOMEM;
  25
  26        /* Initialize data structure */
  27        memcpy(&slave->id, id, sizeof(*id));
  28        slave->dev.parent = bus->dev;
  29        slave->dev.fwnode = fwnode;
  30
  31        /* name shall be sdw:link:mfg:part:class:unique */
  32        dev_set_name(&slave->dev, "sdw:%x:%x:%x:%x:%x",
  33                     bus->link_id, id->mfg_id, id->part_id,
  34                     id->class_id, id->unique_id);
  35
  36        slave->dev.release = sdw_slave_release;
  37        slave->dev.bus = &sdw_bus_type;
  38        slave->bus = bus;
  39        slave->status = SDW_SLAVE_UNATTACHED;
  40        slave->dev_num = 0;
  41
  42        mutex_lock(&bus->bus_lock);
  43        list_add_tail(&slave->node, &bus->slaves);
  44        mutex_unlock(&bus->bus_lock);
  45
  46        ret = device_register(&slave->dev);
  47        if (ret) {
  48                dev_err(bus->dev, "Failed to add slave: ret %d\n", ret);
  49
  50                /*
  51                 * On err, don't free but drop ref as this will be freed
  52                 * when release method is invoked.
  53                 */
  54                mutex_lock(&bus->bus_lock);
  55                list_del(&slave->node);
  56                mutex_unlock(&bus->bus_lock);
  57                put_device(&slave->dev);
  58        }
  59
  60        return ret;
  61}
  62
  63#if IS_ENABLED(CONFIG_ACPI)
  64/*
  65 * sdw_acpi_find_slaves() - Find Slave devices in Master ACPI node
  66 * @bus: SDW bus instance
  67 *
  68 * Scans Master ACPI node for SDW child Slave devices and registers it.
  69 */
  70int sdw_acpi_find_slaves(struct sdw_bus *bus)
  71{
  72        struct acpi_device *adev, *parent;
  73
  74        parent = ACPI_COMPANION(bus->dev);
  75        if (!parent) {
  76                dev_err(bus->dev, "Can't find parent for acpi bind\n");
  77                return -ENODEV;
  78        }
  79
  80        list_for_each_entry(adev, &parent->children, node) {
  81                unsigned long long addr;
  82                struct sdw_slave_id id;
  83                unsigned int link_id;
  84                acpi_status status;
  85
  86                status = acpi_evaluate_integer(adev->handle,
  87                                               METHOD_NAME__ADR, NULL, &addr);
  88
  89                if (ACPI_FAILURE(status)) {
  90                        dev_err(bus->dev, "_ADR resolution failed: %x\n",
  91                                status);
  92                        return status;
  93                }
  94
  95                /* Extract link id from ADR, Bit 51 to 48 (included) */
  96                link_id = (addr >> 48) & GENMASK(3, 0);
  97
  98                /* Check for link_id match */
  99                if (link_id != bus->link_id)
 100                        continue;
 101
 102                sdw_extract_slave_id(bus, addr, &id);
 103
 104                /*
 105                 * don't error check for sdw_slave_add as we want to continue
 106                 * adding Slaves
 107                 */
 108                sdw_slave_add(bus, &id, acpi_fwnode_handle(adev));
 109        }
 110
 111        return 0;
 112}
 113
 114#endif
 115