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
  11/**
  12 * sdw_get_device_id - find the matching SoundWire device id
  13 * @slave: SoundWire Slave Device
  14 * @drv: SoundWire Slave Driver
  15 *
  16 * The match is done by comparing the mfg_id and part_id from the
  17 * struct sdw_device_id.
  18 */
  19static const struct sdw_device_id *
  20sdw_get_device_id(struct sdw_slave *slave, struct sdw_driver *drv)
  21{
  22        const struct sdw_device_id *id = drv->id_table;
  23
  24        while (id && id->mfg_id) {
  25                if (slave->id.mfg_id == id->mfg_id &&
  26                    slave->id.part_id == id->part_id)
  27                        return id;
  28                id++;
  29        }
  30
  31        return NULL;
  32}
  33
  34static int sdw_bus_match(struct device *dev, struct device_driver *ddrv)
  35{
  36        struct sdw_slave *slave = dev_to_sdw_dev(dev);
  37        struct sdw_driver *drv = drv_to_sdw_driver(ddrv);
  38
  39        return !!sdw_get_device_id(slave, drv);
  40}
  41
  42int sdw_slave_modalias(const struct sdw_slave *slave, char *buf, size_t size)
  43{
  44        /* modalias is sdw:m<mfg_id>p<part_id> */
  45
  46        return snprintf(buf, size, "sdw:m%04Xp%04X\n",
  47                        slave->id.mfg_id, slave->id.part_id);
  48}
  49
  50static int sdw_uevent(struct device *dev, struct kobj_uevent_env *env)
  51{
  52        struct sdw_slave *slave = dev_to_sdw_dev(dev);
  53        char modalias[32];
  54
  55        sdw_slave_modalias(slave, modalias, sizeof(modalias));
  56
  57        if (add_uevent_var(env, "MODALIAS=%s", modalias))
  58                return -ENOMEM;
  59
  60        return 0;
  61}
  62
  63struct bus_type sdw_bus_type = {
  64        .name = "soundwire",
  65        .match = sdw_bus_match,
  66        .uevent = sdw_uevent,
  67};
  68EXPORT_SYMBOL_GPL(sdw_bus_type);
  69
  70static int sdw_drv_probe(struct device *dev)
  71{
  72        struct sdw_slave *slave = dev_to_sdw_dev(dev);
  73        struct sdw_driver *drv = drv_to_sdw_driver(dev->driver);
  74        const struct sdw_device_id *id;
  75        int ret;
  76
  77        id = sdw_get_device_id(slave, drv);
  78        if (!id)
  79                return -ENODEV;
  80
  81        slave->ops = drv->ops;
  82
  83        /*
  84         * attach to power domain but don't turn on (last arg)
  85         */
  86        ret = dev_pm_domain_attach(dev, false);
  87        if (ret)
  88                return ret;
  89
  90        ret = drv->probe(slave, id);
  91        if (ret) {
  92                dev_err(dev, "Probe of %s failed: %d\n", drv->name, ret);
  93                dev_pm_domain_detach(dev, false);
  94                return ret;
  95        }
  96
  97        /* device is probed so let's read the properties now */
  98        if (slave->ops && slave->ops->read_prop)
  99                slave->ops->read_prop(slave);
 100
 101        /*
 102         * Check for valid clk_stop_timeout, use DisCo worst case value of
 103         * 300ms
 104         *
 105         * TODO: check the timeouts and driver removal case
 106         */
 107        if (slave->prop.clk_stop_timeout == 0)
 108                slave->prop.clk_stop_timeout = 300;
 109
 110        slave->bus->clk_stop_timeout = max_t(u32, slave->bus->clk_stop_timeout,
 111                                             slave->prop.clk_stop_timeout);
 112
 113        return 0;
 114}
 115
 116static int sdw_drv_remove(struct device *dev)
 117{
 118        struct sdw_slave *slave = dev_to_sdw_dev(dev);
 119        struct sdw_driver *drv = drv_to_sdw_driver(dev->driver);
 120        int ret = 0;
 121
 122        if (drv->remove)
 123                ret = drv->remove(slave);
 124
 125        dev_pm_domain_detach(dev, false);
 126
 127        return ret;
 128}
 129
 130static void sdw_drv_shutdown(struct device *dev)
 131{
 132        struct sdw_slave *slave = dev_to_sdw_dev(dev);
 133        struct sdw_driver *drv = drv_to_sdw_driver(dev->driver);
 134
 135        if (drv->shutdown)
 136                drv->shutdown(slave);
 137}
 138
 139/**
 140 * __sdw_register_driver() - register a SoundWire Slave driver
 141 * @drv: driver to register
 142 * @owner: owning module/driver
 143 *
 144 * Return: zero on success, else a negative error code.
 145 */
 146int __sdw_register_driver(struct sdw_driver *drv, struct module *owner)
 147{
 148        drv->driver.bus = &sdw_bus_type;
 149
 150        if (!drv->probe) {
 151                pr_err("driver %s didn't provide SDW probe routine\n",
 152                       drv->name);
 153                return -EINVAL;
 154        }
 155
 156        drv->driver.owner = owner;
 157        drv->driver.probe = sdw_drv_probe;
 158
 159        if (drv->remove)
 160                drv->driver.remove = sdw_drv_remove;
 161
 162        if (drv->shutdown)
 163                drv->driver.shutdown = sdw_drv_shutdown;
 164
 165        return driver_register(&drv->driver);
 166}
 167EXPORT_SYMBOL_GPL(__sdw_register_driver);
 168
 169/**
 170 * sdw_unregister_driver() - unregisters the SoundWire Slave driver
 171 * @drv: driver to unregister
 172 */
 173void sdw_unregister_driver(struct sdw_driver *drv)
 174{
 175        driver_unregister(&drv->driver);
 176}
 177EXPORT_SYMBOL_GPL(sdw_unregister_driver);
 178
 179static int __init sdw_bus_init(void)
 180{
 181        sdw_debugfs_init();
 182        return bus_register(&sdw_bus_type);
 183}
 184
 185static void __exit sdw_bus_exit(void)
 186{
 187        sdw_debugfs_exit();
 188        bus_unregister(&sdw_bus_type);
 189}
 190
 191postcore_initcall(sdw_bus_init);
 192module_exit(sdw_bus_exit);
 193
 194MODULE_DESCRIPTION("SoundWire bus");
 195MODULE_LICENSE("GPL v2");
 196