19251345dSVinod Koul // SPDX-License-Identifier: GPL-2.0 29251345dSVinod Koul // Copyright(c) 2015-17 Intel Corporation. 39251345dSVinod Koul 49251345dSVinod Koul #include <linux/module.h> 59251345dSVinod Koul #include <linux/mod_devicetable.h> 69251345dSVinod Koul #include <linux/pm_domain.h> 79251345dSVinod Koul #include <linux/soundwire/sdw.h> 89251345dSVinod Koul #include <linux/soundwire/sdw_type.h> 9bf03473dSPierre-Louis Bossart #include "bus.h" 10bcac5902SPierre-Louis Bossart #include "sysfs_local.h" 119251345dSVinod Koul 129251345dSVinod Koul /** 139251345dSVinod Koul * sdw_get_device_id - find the matching SoundWire device id 149251345dSVinod Koul * @slave: SoundWire Slave Device 159251345dSVinod Koul * @drv: SoundWire Slave Driver 169251345dSVinod Koul * 179251345dSVinod Koul * The match is done by comparing the mfg_id and part_id from the 189251345dSVinod Koul * struct sdw_device_id. 199251345dSVinod Koul */ 209251345dSVinod Koul static const struct sdw_device_id * 219251345dSVinod Koul sdw_get_device_id(struct sdw_slave *slave, struct sdw_driver *drv) 229251345dSVinod Koul { 23ee9173dbSPierre-Louis Bossart const struct sdw_device_id *id; 249251345dSVinod Koul 25ee9173dbSPierre-Louis Bossart for (id = drv->id_table; id && id->mfg_id; id++) 269251345dSVinod Koul if (slave->id.mfg_id == id->mfg_id && 27b5924268SPierre-Louis Bossart slave->id.part_id == id->part_id && 28b5924268SPierre-Louis Bossart (!id->sdw_version || 29b5924268SPierre-Louis Bossart slave->id.sdw_version == id->sdw_version) && 30b5924268SPierre-Louis Bossart (!id->class_id || 31b5924268SPierre-Louis Bossart slave->id.class_id == id->class_id)) 329251345dSVinod Koul return id; 339251345dSVinod Koul 349251345dSVinod Koul return NULL; 359251345dSVinod Koul } 369251345dSVinod Koul 379251345dSVinod Koul static int sdw_bus_match(struct device *dev, struct device_driver *ddrv) 389251345dSVinod Koul { 3990acca1dSPierre-Louis Bossart struct sdw_slave *slave; 4090acca1dSPierre-Louis Bossart struct sdw_driver *drv; 4190acca1dSPierre-Louis Bossart int ret = 0; 429251345dSVinod Koul 4390acca1dSPierre-Louis Bossart if (is_sdw_slave(dev)) { 4490acca1dSPierre-Louis Bossart slave = dev_to_sdw_dev(dev); 4590acca1dSPierre-Louis Bossart drv = drv_to_sdw_driver(ddrv); 4690acca1dSPierre-Louis Bossart 4790acca1dSPierre-Louis Bossart ret = !!sdw_get_device_id(slave, drv); 4890acca1dSPierre-Louis Bossart } 4990acca1dSPierre-Louis Bossart return ret; 509251345dSVinod Koul } 519251345dSVinod Koul 52bcac5902SPierre-Louis Bossart int sdw_slave_modalias(const struct sdw_slave *slave, char *buf, size_t size) 539251345dSVinod Koul { 54b5924268SPierre-Louis Bossart /* modalias is sdw:m<mfg_id>p<part_id>v<version>c<class_id> */ 559251345dSVinod Koul 56b5924268SPierre-Louis Bossart return snprintf(buf, size, "sdw:m%04Xp%04Xv%02Xc%02X\n", 57b5924268SPierre-Louis Bossart slave->id.mfg_id, slave->id.part_id, 58b5924268SPierre-Louis Bossart slave->id.sdw_version, slave->id.class_id); 599251345dSVinod Koul } 609251345dSVinod Koul 6190acca1dSPierre-Louis Bossart int sdw_slave_uevent(struct device *dev, struct kobj_uevent_env *env) 629251345dSVinod Koul { 639251345dSVinod Koul struct sdw_slave *slave = dev_to_sdw_dev(dev); 649251345dSVinod Koul char modalias[32]; 659251345dSVinod Koul 669251345dSVinod Koul sdw_slave_modalias(slave, modalias, sizeof(modalias)); 679251345dSVinod Koul 689251345dSVinod Koul if (add_uevent_var(env, "MODALIAS=%s", modalias)) 699251345dSVinod Koul return -ENOMEM; 709251345dSVinod Koul 719251345dSVinod Koul return 0; 729251345dSVinod Koul } 739251345dSVinod Koul 749251345dSVinod Koul struct bus_type sdw_bus_type = { 759251345dSVinod Koul .name = "soundwire", 769251345dSVinod Koul .match = sdw_bus_match, 779251345dSVinod Koul }; 789251345dSVinod Koul EXPORT_SYMBOL_GPL(sdw_bus_type); 799251345dSVinod Koul 809251345dSVinod Koul static int sdw_drv_probe(struct device *dev) 819251345dSVinod Koul { 829251345dSVinod Koul struct sdw_slave *slave = dev_to_sdw_dev(dev); 839251345dSVinod Koul struct sdw_driver *drv = drv_to_sdw_driver(dev->driver); 849251345dSVinod Koul const struct sdw_device_id *id; 850196b52bSPierre-Louis Bossart const char *name; 869251345dSVinod Koul int ret; 879251345dSVinod Koul 88fcb9d730SSrinivas Kandagatla /* 89fcb9d730SSrinivas Kandagatla * fw description is mandatory to bind 90fcb9d730SSrinivas Kandagatla */ 91fcb9d730SSrinivas Kandagatla if (!dev->fwnode) 92fcb9d730SSrinivas Kandagatla return -ENODEV; 93fcb9d730SSrinivas Kandagatla 94fcb9d730SSrinivas Kandagatla if (!IS_ENABLED(CONFIG_ACPI) && !dev->of_node) 95fcb9d730SSrinivas Kandagatla return -ENODEV; 96fcb9d730SSrinivas Kandagatla 979251345dSVinod Koul id = sdw_get_device_id(slave, drv); 989251345dSVinod Koul if (!id) 999251345dSVinod Koul return -ENODEV; 1009251345dSVinod Koul 1019251345dSVinod Koul /* 1029251345dSVinod Koul * attach to power domain but don't turn on (last arg) 1039251345dSVinod Koul */ 1049251345dSVinod Koul ret = dev_pm_domain_attach(dev, false); 10529ffcc88SUlf Hansson if (ret) 10629ffcc88SUlf Hansson return ret; 10729ffcc88SUlf Hansson 1089251345dSVinod Koul ret = drv->probe(slave, id); 1099251345dSVinod Koul if (ret) { 1100196b52bSPierre-Louis Bossart name = drv->name; 1110196b52bSPierre-Louis Bossart if (!name) 1120196b52bSPierre-Louis Bossart name = drv->driver.name; 113bd29c00eSPierre-Louis Bossart 1140196b52bSPierre-Louis Bossart dev_err(dev, "Probe of %s failed: %d\n", name, ret); 1159251345dSVinod Koul dev_pm_domain_detach(dev, false); 1169251345dSVinod Koul return ret; 11729ffcc88SUlf Hansson } 11856d4fe31SVinod Koul 119*3dca1f89SRichard Fitzgerald mutex_lock(&slave->sdw_dev_lock); 120*3dca1f89SRichard Fitzgerald 12156d4fe31SVinod Koul /* device is probed so let's read the properties now */ 122bd29c00eSPierre-Louis Bossart if (drv->ops && drv->ops->read_prop) 123bd29c00eSPierre-Louis Bossart drv->ops->read_prop(slave); 12456d4fe31SVinod Koul 125bcac5902SPierre-Louis Bossart /* init the sysfs as we have properties now */ 126bcac5902SPierre-Louis Bossart ret = sdw_slave_sysfs_init(slave); 127bcac5902SPierre-Louis Bossart if (ret < 0) 128bcac5902SPierre-Louis Bossart dev_warn(dev, "Slave sysfs init failed:%d\n", ret); 129bcac5902SPierre-Louis Bossart 13056d4fe31SVinod Koul /* 13156d4fe31SVinod Koul * Check for valid clk_stop_timeout, use DisCo worst case value of 13256d4fe31SVinod Koul * 300ms 13356d4fe31SVinod Koul * 13456d4fe31SVinod Koul * TODO: check the timeouts and driver removal case 13556d4fe31SVinod Koul */ 13656d4fe31SVinod Koul if (slave->prop.clk_stop_timeout == 0) 13756d4fe31SVinod Koul slave->prop.clk_stop_timeout = 300; 13856d4fe31SVinod Koul 13956d4fe31SVinod Koul slave->bus->clk_stop_timeout = max_t(u32, slave->bus->clk_stop_timeout, 14056d4fe31SVinod Koul slave->prop.clk_stop_timeout); 14156d4fe31SVinod Koul 1422140b66bSPierre-Louis Bossart slave->probed = true; 143bd29c00eSPierre-Louis Bossart 144bd29c00eSPierre-Louis Bossart /* 145bd29c00eSPierre-Louis Bossart * if the probe happened after the bus was started, notify the codec driver 146bd29c00eSPierre-Louis Bossart * of the current hardware status to e.g. start the initialization. 147bd29c00eSPierre-Louis Bossart * Errors are only logged as warnings to avoid failing the probe. 148bd29c00eSPierre-Louis Bossart */ 149bd29c00eSPierre-Louis Bossart if (drv->ops && drv->ops->update_status) { 150bd29c00eSPierre-Louis Bossart ret = drv->ops->update_status(slave, slave->status); 151bd29c00eSPierre-Louis Bossart if (ret < 0) 152bd29c00eSPierre-Louis Bossart dev_warn(dev, "%s: update_status failed with status %d\n", __func__, ret); 153bd29c00eSPierre-Louis Bossart } 154bd29c00eSPierre-Louis Bossart 155bd29c00eSPierre-Louis Bossart mutex_unlock(&slave->sdw_dev_lock); 1562140b66bSPierre-Louis Bossart 1572140b66bSPierre-Louis Bossart dev_dbg(dev, "probe complete\n"); 1582140b66bSPierre-Louis Bossart 15956d4fe31SVinod Koul return 0; 1609251345dSVinod Koul } 1619251345dSVinod Koul 1629251345dSVinod Koul static int sdw_drv_remove(struct device *dev) 1639251345dSVinod Koul { 1649251345dSVinod Koul struct sdw_slave *slave = dev_to_sdw_dev(dev); 1659251345dSVinod Koul struct sdw_driver *drv = drv_to_sdw_driver(dev->driver); 1669251345dSVinod Koul int ret = 0; 1679251345dSVinod Koul 168bd29c00eSPierre-Louis Bossart mutex_lock(&slave->sdw_dev_lock); 169bd29c00eSPierre-Louis Bossart slave->probed = false; 170*3dca1f89SRichard Fitzgerald mutex_unlock(&slave->sdw_dev_lock); 171bd29c00eSPierre-Louis Bossart 1729251345dSVinod Koul if (drv->remove) 1739251345dSVinod Koul ret = drv->remove(slave); 1749251345dSVinod Koul 1759251345dSVinod Koul dev_pm_domain_detach(dev, false); 1769251345dSVinod Koul 1779251345dSVinod Koul return ret; 1789251345dSVinod Koul } 1799251345dSVinod Koul 1809251345dSVinod Koul static void sdw_drv_shutdown(struct device *dev) 1819251345dSVinod Koul { 1829251345dSVinod Koul struct sdw_slave *slave = dev_to_sdw_dev(dev); 1839251345dSVinod Koul struct sdw_driver *drv = drv_to_sdw_driver(dev->driver); 1849251345dSVinod Koul 1859251345dSVinod Koul if (drv->shutdown) 1869251345dSVinod Koul drv->shutdown(slave); 1879251345dSVinod Koul } 1889251345dSVinod Koul 1899251345dSVinod Koul /** 1909251345dSVinod Koul * __sdw_register_driver() - register a SoundWire Slave driver 1919251345dSVinod Koul * @drv: driver to register 1929251345dSVinod Koul * @owner: owning module/driver 1939251345dSVinod Koul * 1949251345dSVinod Koul * Return: zero on success, else a negative error code. 1959251345dSVinod Koul */ 1969251345dSVinod Koul int __sdw_register_driver(struct sdw_driver *drv, struct module *owner) 1979251345dSVinod Koul { 1980196b52bSPierre-Louis Bossart const char *name; 1990196b52bSPierre-Louis Bossart 2009251345dSVinod Koul drv->driver.bus = &sdw_bus_type; 2019251345dSVinod Koul 2029251345dSVinod Koul if (!drv->probe) { 2030196b52bSPierre-Louis Bossart name = drv->name; 2040196b52bSPierre-Louis Bossart if (!name) 2050196b52bSPierre-Louis Bossart name = drv->driver.name; 2060196b52bSPierre-Louis Bossart 2070196b52bSPierre-Louis Bossart pr_err("driver %s didn't provide SDW probe routine\n", name); 2089251345dSVinod Koul return -EINVAL; 2099251345dSVinod Koul } 2109251345dSVinod Koul 2119251345dSVinod Koul drv->driver.owner = owner; 2129251345dSVinod Koul drv->driver.probe = sdw_drv_probe; 2139251345dSVinod Koul drv->driver.remove = sdw_drv_remove; 2149251345dSVinod Koul drv->driver.shutdown = sdw_drv_shutdown; 2159251345dSVinod Koul 2169251345dSVinod Koul return driver_register(&drv->driver); 2179251345dSVinod Koul } 2189251345dSVinod Koul EXPORT_SYMBOL_GPL(__sdw_register_driver); 2199251345dSVinod Koul 2209251345dSVinod Koul /** 2219251345dSVinod Koul * sdw_unregister_driver() - unregisters the SoundWire Slave driver 2229251345dSVinod Koul * @drv: driver to unregister 2239251345dSVinod Koul */ 2249251345dSVinod Koul void sdw_unregister_driver(struct sdw_driver *drv) 2259251345dSVinod Koul { 2269251345dSVinod Koul driver_unregister(&drv->driver); 2279251345dSVinod Koul } 2289251345dSVinod Koul EXPORT_SYMBOL_GPL(sdw_unregister_driver); 2299251345dSVinod Koul 2309251345dSVinod Koul static int __init sdw_bus_init(void) 2319251345dSVinod Koul { 232bf03473dSPierre-Louis Bossart sdw_debugfs_init(); 2339251345dSVinod Koul return bus_register(&sdw_bus_type); 2349251345dSVinod Koul } 2359251345dSVinod Koul 2369251345dSVinod Koul static void __exit sdw_bus_exit(void) 2379251345dSVinod Koul { 238bf03473dSPierre-Louis Bossart sdw_debugfs_exit(); 2399251345dSVinod Koul bus_unregister(&sdw_bus_type); 2409251345dSVinod Koul } 2419251345dSVinod Koul 2429251345dSVinod Koul postcore_initcall(sdw_bus_init); 2439251345dSVinod Koul module_exit(sdw_bus_exit); 2449251345dSVinod Koul 2459251345dSVinod Koul MODULE_DESCRIPTION("SoundWire bus"); 2469251345dSVinod Koul MODULE_LICENSE("GPL v2"); 247