linux/drivers/soundwire/bus_type.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2// Copyright(c) 2015-17 Intel Corporation.
   3
   4#include <linux/module.h>
   5#include <linux/mod_devicetable.h>
   6#include <linux/pm_domain.h>
   7#include <linux/soundwire/sdw.h>
   8#include <linux/soundwire/sdw_type.h>
   9#include "bus.h"
  10#include "sysfs_local.h"
  11
  12/**
  13 * sdw_get_device_id - find the matching SoundWire device id
  14 * @slave: SoundWire Slave Device
  15 * @drv: SoundWire Slave Driver
  16 *
  17 * The match is done by comparing the mfg_id and part_id from the
  18 * struct sdw_device_id.
  19 */
  20static const struct sdw_device_id *
  21sdw_get_device_id(struct sdw_slave *slave, struct sdw_driver *drv)
  22{
  23        const struct sdw_device_id *id;
  24
  25        for (id = drv->id_table; id && id->mfg_id; id++)
  26                if (slave->id.mfg_id == id->mfg_id &&
  27                    slave->id.part_id == id->part_id  &&
  28                    (!id->sdw_version ||
  29                     slave->id.sdw_version == id->sdw_version) &&
  30                    (!id->class_id ||
  31                     slave->id.class_id == id->class_id))
  32                        return id;
  33
  34        return NULL;
  35}
  36
  37static int sdw_bus_match(struct device *dev, struct device_driver *ddrv)
  38{
  39        struct sdw_slave *slave;
  40        struct sdw_driver *drv;
  41        int ret = 0;
  42
  43        if (is_sdw_slave(dev)) {
  44                slave = dev_to_sdw_dev(dev);
  45                drv = drv_to_sdw_driver(ddrv);
  46
  47                ret = !!sdw_get_device_id(slave, drv);
  48        }
  49        return ret;
  50}
  51
  52int sdw_slave_modalias(const struct sdw_slave *slave, char *buf, size_t size)
  53{
  54        /* modalias is sdw:m<mfg_id>p<part_id>v<version>c<class_id> */
  55
  56        return snprintf(buf, size, "sdw:m%04Xp%04Xv%02Xc%02X\n",
  57                        slave->id.mfg_id, slave->id.part_id,
  58                        slave->id.sdw_version, slave->id.class_id);
  59}
  60
  61int sdw_slave_uevent(struct device *dev, struct kobj_uevent_env *env)
  62{
  63        struct sdw_slave *slave = dev_to_sdw_dev(dev);
  64        char modalias[32];
  65
  66        sdw_slave_modalias(slave, modalias, sizeof(modalias));
  67
  68        if (add_uevent_var(env, "MODALIAS=%s", modalias))
  69                return -ENOMEM;
  70
  71        return 0;
  72}
  73
  74struct bus_type sdw_bus_type = {
  75        .name = "soundwire",
  76        .match = sdw_bus_match,
  77};
  78EXPORT_SYMBOL_GPL(sdw_bus_type);
  79
  80static int sdw_drv_probe(struct device *dev)
  81{
  82        struct sdw_slave *slave = dev_to_sdw_dev(dev);
  83        struct sdw_driver *drv = drv_to_sdw_driver(dev->driver);
  84        const struct sdw_device_id *id;
  85        const char *name;
  86        int ret;
  87
  88        /*
  89         * fw description is mandatory to bind
  90         */
  91        if (!dev->fwnode)
  92                return -ENODEV;
  93
  94        if (!IS_ENABLED(CONFIG_ACPI) && !dev->of_node)
  95                return -ENODEV;
  96
  97        id = sdw_get_device_id(slave, drv);
  98        if (!id)
  99                return -ENODEV;
 100
 101        slave->ops = drv->ops;
 102
 103        /*
 104         * attach to power domain but don't turn on (last arg)
 105         */
 106        ret = dev_pm_domain_attach(dev, false);
 107        if (ret)
 108                return ret;
 109
 110        ret = drv->probe(slave, id);
 111        if (ret) {
 112                name = drv->name;
 113                if (!name)
 114                        name = drv->driver.name;
 115                dev_err(dev, "Probe of %s failed: %d\n", name, ret);
 116                dev_pm_domain_detach(dev, false);
 117                return ret;
 118        }
 119
 120        /* device is probed so let's read the properties now */
 121        if (slave->ops && slave->ops->read_prop)
 122                slave->ops->read_prop(slave);
 123
 124        /* init the sysfs as we have properties now */
 125        ret = sdw_slave_sysfs_init(slave);
 126        if (ret < 0)
 127                dev_warn(dev, "Slave sysfs init failed:%d\n", ret);
 128
 129        /*
 130         * Check for valid clk_stop_timeout, use DisCo worst case value of
 131         * 300ms
 132         *
 133         * TODO: check the timeouts and driver removal case
 134         */
 135        if (slave->prop.clk_stop_timeout == 0)
 136                slave->prop.clk_stop_timeout = 300;
 137
 138        slave->bus->clk_stop_timeout = max_t(u32, slave->bus->clk_stop_timeout,
 139                                             slave->prop.clk_stop_timeout);
 140
 141        slave->probed = true;
 142        complete(&slave->probe_complete);
 143
 144        dev_dbg(dev, "probe complete\n");
 145
 146        return 0;
 147}
 148
 149static int sdw_drv_remove(struct device *dev)
 150{
 151        struct sdw_slave *slave = dev_to_sdw_dev(dev);
 152        struct sdw_driver *drv = drv_to_sdw_driver(dev->driver);
 153        int ret = 0;
 154
 155        if (drv->remove)
 156                ret = drv->remove(slave);
 157
 158        dev_pm_domain_detach(dev, false);
 159
 160        return ret;
 161}
 162
 163static void sdw_drv_shutdown(struct device *dev)
 164{
 165        struct sdw_slave *slave = dev_to_sdw_dev(dev);
 166        struct sdw_driver *drv = drv_to_sdw_driver(dev->driver);
 167
 168        if (drv->shutdown)
 169                drv->shutdown(slave);
 170}
 171
 172/**
 173 * __sdw_register_driver() - register a SoundWire Slave driver
 174 * @drv: driver to register
 175 * @owner: owning module/driver
 176 *
 177 * Return: zero on success, else a negative error code.
 178 */
 179int __sdw_register_driver(struct sdw_driver *drv, struct module *owner)
 180{
 181        const char *name;
 182
 183        drv->driver.bus = &sdw_bus_type;
 184
 185        if (!drv->probe) {
 186                name = drv->name;
 187                if (!name)
 188                        name = drv->driver.name;
 189
 190                pr_err("driver %s didn't provide SDW probe routine\n", name);
 191                return -EINVAL;
 192        }
 193
 194        drv->driver.owner = owner;
 195        drv->driver.probe = sdw_drv_probe;
 196
 197        if (drv->remove)
 198                drv->driver.remove = sdw_drv_remove;
 199
 200        if (drv->shutdown)
 201                drv->driver.shutdown = sdw_drv_shutdown;
 202
 203        return driver_register(&drv->driver);
 204}
 205EXPORT_SYMBOL_GPL(__sdw_register_driver);
 206
 207/**
 208 * sdw_unregister_driver() - unregisters the SoundWire Slave driver
 209 * @drv: driver to unregister
 210 */
 211void sdw_unregister_driver(struct sdw_driver *drv)
 212{
 213        driver_unregister(&drv->driver);
 214}
 215EXPORT_SYMBOL_GPL(sdw_unregister_driver);
 216
 217static int __init sdw_bus_init(void)
 218{
 219        sdw_debugfs_init();
 220        return bus_register(&sdw_bus_type);
 221}
 222
 223static void __exit sdw_bus_exit(void)
 224{
 225        sdw_debugfs_exit();
 226        bus_unregister(&sdw_bus_type);
 227}
 228
 229postcore_initcall(sdw_bus_init);
 230module_exit(sdw_bus_exit);
 231
 232MODULE_DESCRIPTION("SoundWire bus");
 233MODULE_LICENSE("GPL v2");
 234