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; 859251345dSVinod Koul int ret; 869251345dSVinod Koul 879251345dSVinod Koul id = sdw_get_device_id(slave, drv); 889251345dSVinod Koul if (!id) 899251345dSVinod Koul return -ENODEV; 909251345dSVinod Koul 9156d4fe31SVinod Koul slave->ops = drv->ops; 9256d4fe31SVinod Koul 939251345dSVinod Koul /* 949251345dSVinod Koul * attach to power domain but don't turn on (last arg) 959251345dSVinod Koul */ 969251345dSVinod Koul ret = dev_pm_domain_attach(dev, false); 9729ffcc88SUlf Hansson if (ret) 9829ffcc88SUlf Hansson return ret; 9929ffcc88SUlf Hansson 1009251345dSVinod Koul ret = drv->probe(slave, id); 1019251345dSVinod Koul if (ret) { 1029251345dSVinod Koul dev_err(dev, "Probe of %s failed: %d\n", drv->name, ret); 1039251345dSVinod Koul dev_pm_domain_detach(dev, false); 1049251345dSVinod Koul return ret; 10529ffcc88SUlf Hansson } 10656d4fe31SVinod Koul 10756d4fe31SVinod Koul /* device is probed so let's read the properties now */ 10856d4fe31SVinod Koul if (slave->ops && slave->ops->read_prop) 10956d4fe31SVinod Koul slave->ops->read_prop(slave); 11056d4fe31SVinod Koul 111bcac5902SPierre-Louis Bossart /* init the sysfs as we have properties now */ 112bcac5902SPierre-Louis Bossart ret = sdw_slave_sysfs_init(slave); 113bcac5902SPierre-Louis Bossart if (ret < 0) 114bcac5902SPierre-Louis Bossart dev_warn(dev, "Slave sysfs init failed:%d\n", ret); 115bcac5902SPierre-Louis Bossart 11656d4fe31SVinod Koul /* 11756d4fe31SVinod Koul * Check for valid clk_stop_timeout, use DisCo worst case value of 11856d4fe31SVinod Koul * 300ms 11956d4fe31SVinod Koul * 12056d4fe31SVinod Koul * TODO: check the timeouts and driver removal case 12156d4fe31SVinod Koul */ 12256d4fe31SVinod Koul if (slave->prop.clk_stop_timeout == 0) 12356d4fe31SVinod Koul slave->prop.clk_stop_timeout = 300; 12456d4fe31SVinod Koul 12556d4fe31SVinod Koul slave->bus->clk_stop_timeout = max_t(u32, slave->bus->clk_stop_timeout, 12656d4fe31SVinod Koul slave->prop.clk_stop_timeout); 12756d4fe31SVinod Koul 1282140b66bSPierre-Louis Bossart slave->probed = true; 1292140b66bSPierre-Louis Bossart complete(&slave->probe_complete); 1302140b66bSPierre-Louis Bossart 1312140b66bSPierre-Louis Bossart dev_dbg(dev, "probe complete\n"); 1322140b66bSPierre-Louis Bossart 13356d4fe31SVinod Koul return 0; 1349251345dSVinod Koul } 1359251345dSVinod Koul 1369251345dSVinod Koul static int sdw_drv_remove(struct device *dev) 1379251345dSVinod Koul { 1389251345dSVinod Koul struct sdw_slave *slave = dev_to_sdw_dev(dev); 1399251345dSVinod Koul struct sdw_driver *drv = drv_to_sdw_driver(dev->driver); 1409251345dSVinod Koul int ret = 0; 1419251345dSVinod Koul 1429251345dSVinod Koul if (drv->remove) 1439251345dSVinod Koul ret = drv->remove(slave); 1449251345dSVinod Koul 1459251345dSVinod Koul dev_pm_domain_detach(dev, false); 1469251345dSVinod Koul 1479251345dSVinod Koul return ret; 1489251345dSVinod Koul } 1499251345dSVinod Koul 1509251345dSVinod Koul static void sdw_drv_shutdown(struct device *dev) 1519251345dSVinod Koul { 1529251345dSVinod Koul struct sdw_slave *slave = dev_to_sdw_dev(dev); 1539251345dSVinod Koul struct sdw_driver *drv = drv_to_sdw_driver(dev->driver); 1549251345dSVinod Koul 1559251345dSVinod Koul if (drv->shutdown) 1569251345dSVinod Koul drv->shutdown(slave); 1579251345dSVinod Koul } 1589251345dSVinod Koul 1599251345dSVinod Koul /** 1609251345dSVinod Koul * __sdw_register_driver() - register a SoundWire Slave driver 1619251345dSVinod Koul * @drv: driver to register 1629251345dSVinod Koul * @owner: owning module/driver 1639251345dSVinod Koul * 1649251345dSVinod Koul * Return: zero on success, else a negative error code. 1659251345dSVinod Koul */ 1669251345dSVinod Koul int __sdw_register_driver(struct sdw_driver *drv, struct module *owner) 1679251345dSVinod Koul { 1689251345dSVinod Koul drv->driver.bus = &sdw_bus_type; 1699251345dSVinod Koul 1709251345dSVinod Koul if (!drv->probe) { 1719251345dSVinod Koul pr_err("driver %s didn't provide SDW probe routine\n", 1729251345dSVinod Koul drv->name); 1739251345dSVinod Koul return -EINVAL; 1749251345dSVinod Koul } 1759251345dSVinod Koul 1769251345dSVinod Koul drv->driver.owner = owner; 1779251345dSVinod Koul drv->driver.probe = sdw_drv_probe; 1789251345dSVinod Koul 1799251345dSVinod Koul if (drv->remove) 1809251345dSVinod Koul drv->driver.remove = sdw_drv_remove; 1819251345dSVinod Koul 1829251345dSVinod Koul if (drv->shutdown) 1839251345dSVinod Koul drv->driver.shutdown = sdw_drv_shutdown; 1849251345dSVinod Koul 1859251345dSVinod Koul return driver_register(&drv->driver); 1869251345dSVinod Koul } 1879251345dSVinod Koul EXPORT_SYMBOL_GPL(__sdw_register_driver); 1889251345dSVinod Koul 1899251345dSVinod Koul /** 1909251345dSVinod Koul * sdw_unregister_driver() - unregisters the SoundWire Slave driver 1919251345dSVinod Koul * @drv: driver to unregister 1929251345dSVinod Koul */ 1939251345dSVinod Koul void sdw_unregister_driver(struct sdw_driver *drv) 1949251345dSVinod Koul { 1959251345dSVinod Koul driver_unregister(&drv->driver); 1969251345dSVinod Koul } 1979251345dSVinod Koul EXPORT_SYMBOL_GPL(sdw_unregister_driver); 1989251345dSVinod Koul 1999251345dSVinod Koul static int __init sdw_bus_init(void) 2009251345dSVinod Koul { 201bf03473dSPierre-Louis Bossart sdw_debugfs_init(); 2029251345dSVinod Koul return bus_register(&sdw_bus_type); 2039251345dSVinod Koul } 2049251345dSVinod Koul 2059251345dSVinod Koul static void __exit sdw_bus_exit(void) 2069251345dSVinod Koul { 207bf03473dSPierre-Louis Bossart sdw_debugfs_exit(); 2089251345dSVinod Koul bus_unregister(&sdw_bus_type); 2099251345dSVinod Koul } 2109251345dSVinod Koul 2119251345dSVinod Koul postcore_initcall(sdw_bus_init); 2129251345dSVinod Koul module_exit(sdw_bus_exit); 2139251345dSVinod Koul 2149251345dSVinod Koul MODULE_DESCRIPTION("SoundWire bus"); 2159251345dSVinod Koul MODULE_LICENSE("GPL v2"); 216