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" 109251345dSVinod Koul 119251345dSVinod Koul /** 129251345dSVinod Koul * sdw_get_device_id - find the matching SoundWire device id 139251345dSVinod Koul * @slave: SoundWire Slave Device 149251345dSVinod Koul * @drv: SoundWire Slave Driver 159251345dSVinod Koul * 169251345dSVinod Koul * The match is done by comparing the mfg_id and part_id from the 179251345dSVinod Koul * struct sdw_device_id. 189251345dSVinod Koul */ 199251345dSVinod Koul static const struct sdw_device_id * 209251345dSVinod Koul sdw_get_device_id(struct sdw_slave *slave, struct sdw_driver *drv) 219251345dSVinod Koul { 229251345dSVinod Koul const struct sdw_device_id *id = drv->id_table; 239251345dSVinod Koul 249251345dSVinod Koul while (id && id->mfg_id) { 259251345dSVinod Koul if (slave->id.mfg_id == id->mfg_id && 269251345dSVinod Koul slave->id.part_id == id->part_id) 279251345dSVinod Koul return id; 289251345dSVinod Koul id++; 299251345dSVinod Koul } 309251345dSVinod Koul 319251345dSVinod Koul return NULL; 329251345dSVinod Koul } 339251345dSVinod Koul 349251345dSVinod Koul static int sdw_bus_match(struct device *dev, struct device_driver *ddrv) 359251345dSVinod Koul { 369251345dSVinod Koul struct sdw_slave *slave = dev_to_sdw_dev(dev); 379251345dSVinod Koul struct sdw_driver *drv = drv_to_sdw_driver(ddrv); 389251345dSVinod Koul 399251345dSVinod Koul return !!sdw_get_device_id(slave, drv); 409251345dSVinod Koul } 419251345dSVinod Koul 429251345dSVinod Koul int sdw_slave_modalias(const struct sdw_slave *slave, char *buf, size_t size) 439251345dSVinod Koul { 449251345dSVinod Koul /* modalias is sdw:m<mfg_id>p<part_id> */ 459251345dSVinod Koul 469251345dSVinod Koul return snprintf(buf, size, "sdw:m%04Xp%04X\n", 479251345dSVinod Koul slave->id.mfg_id, slave->id.part_id); 489251345dSVinod Koul } 499251345dSVinod Koul 509251345dSVinod Koul static int sdw_uevent(struct device *dev, struct kobj_uevent_env *env) 519251345dSVinod Koul { 529251345dSVinod Koul struct sdw_slave *slave = dev_to_sdw_dev(dev); 539251345dSVinod Koul char modalias[32]; 549251345dSVinod Koul 559251345dSVinod Koul sdw_slave_modalias(slave, modalias, sizeof(modalias)); 569251345dSVinod Koul 579251345dSVinod Koul if (add_uevent_var(env, "MODALIAS=%s", modalias)) 589251345dSVinod Koul return -ENOMEM; 599251345dSVinod Koul 609251345dSVinod Koul return 0; 619251345dSVinod Koul } 629251345dSVinod Koul 639251345dSVinod Koul struct bus_type sdw_bus_type = { 649251345dSVinod Koul .name = "soundwire", 659251345dSVinod Koul .match = sdw_bus_match, 669251345dSVinod Koul .uevent = sdw_uevent, 679251345dSVinod Koul }; 689251345dSVinod Koul EXPORT_SYMBOL_GPL(sdw_bus_type); 699251345dSVinod Koul 709251345dSVinod Koul static int sdw_drv_probe(struct device *dev) 719251345dSVinod Koul { 729251345dSVinod Koul struct sdw_slave *slave = dev_to_sdw_dev(dev); 739251345dSVinod Koul struct sdw_driver *drv = drv_to_sdw_driver(dev->driver); 749251345dSVinod Koul const struct sdw_device_id *id; 759251345dSVinod Koul int ret; 769251345dSVinod Koul 779251345dSVinod Koul id = sdw_get_device_id(slave, drv); 789251345dSVinod Koul if (!id) 799251345dSVinod Koul return -ENODEV; 809251345dSVinod Koul 8156d4fe31SVinod Koul slave->ops = drv->ops; 8256d4fe31SVinod Koul 839251345dSVinod Koul /* 849251345dSVinod Koul * attach to power domain but don't turn on (last arg) 859251345dSVinod Koul */ 869251345dSVinod Koul ret = dev_pm_domain_attach(dev, false); 8729ffcc88SUlf Hansson if (ret) 8829ffcc88SUlf Hansson return ret; 8929ffcc88SUlf Hansson 909251345dSVinod Koul ret = drv->probe(slave, id); 919251345dSVinod Koul if (ret) { 929251345dSVinod Koul dev_err(dev, "Probe of %s failed: %d\n", drv->name, ret); 939251345dSVinod Koul dev_pm_domain_detach(dev, false); 949251345dSVinod Koul return ret; 9529ffcc88SUlf Hansson } 9656d4fe31SVinod Koul 9756d4fe31SVinod Koul /* device is probed so let's read the properties now */ 9856d4fe31SVinod Koul if (slave->ops && slave->ops->read_prop) 9956d4fe31SVinod Koul slave->ops->read_prop(slave); 10056d4fe31SVinod Koul 10156d4fe31SVinod Koul /* 10256d4fe31SVinod Koul * Check for valid clk_stop_timeout, use DisCo worst case value of 10356d4fe31SVinod Koul * 300ms 10456d4fe31SVinod Koul * 10556d4fe31SVinod Koul * TODO: check the timeouts and driver removal case 10656d4fe31SVinod Koul */ 10756d4fe31SVinod Koul if (slave->prop.clk_stop_timeout == 0) 10856d4fe31SVinod Koul slave->prop.clk_stop_timeout = 300; 10956d4fe31SVinod Koul 11056d4fe31SVinod Koul slave->bus->clk_stop_timeout = max_t(u32, slave->bus->clk_stop_timeout, 11156d4fe31SVinod Koul slave->prop.clk_stop_timeout); 11256d4fe31SVinod Koul 11356d4fe31SVinod Koul return 0; 1149251345dSVinod Koul } 1159251345dSVinod Koul 1169251345dSVinod Koul static int sdw_drv_remove(struct device *dev) 1179251345dSVinod Koul { 1189251345dSVinod Koul struct sdw_slave *slave = dev_to_sdw_dev(dev); 1199251345dSVinod Koul struct sdw_driver *drv = drv_to_sdw_driver(dev->driver); 1209251345dSVinod Koul int ret = 0; 1219251345dSVinod Koul 1229251345dSVinod Koul if (drv->remove) 1239251345dSVinod Koul ret = drv->remove(slave); 1249251345dSVinod Koul 1259251345dSVinod Koul dev_pm_domain_detach(dev, false); 1269251345dSVinod Koul 1279251345dSVinod Koul return ret; 1289251345dSVinod Koul } 1299251345dSVinod Koul 1309251345dSVinod Koul static void sdw_drv_shutdown(struct device *dev) 1319251345dSVinod Koul { 1329251345dSVinod Koul struct sdw_slave *slave = dev_to_sdw_dev(dev); 1339251345dSVinod Koul struct sdw_driver *drv = drv_to_sdw_driver(dev->driver); 1349251345dSVinod Koul 1359251345dSVinod Koul if (drv->shutdown) 1369251345dSVinod Koul drv->shutdown(slave); 1379251345dSVinod Koul } 1389251345dSVinod Koul 1399251345dSVinod Koul /** 1409251345dSVinod Koul * __sdw_register_driver() - register a SoundWire Slave driver 1419251345dSVinod Koul * @drv: driver to register 1429251345dSVinod Koul * @owner: owning module/driver 1439251345dSVinod Koul * 1449251345dSVinod Koul * Return: zero on success, else a negative error code. 1459251345dSVinod Koul */ 1469251345dSVinod Koul int __sdw_register_driver(struct sdw_driver *drv, struct module *owner) 1479251345dSVinod Koul { 1489251345dSVinod Koul drv->driver.bus = &sdw_bus_type; 1499251345dSVinod Koul 1509251345dSVinod Koul if (!drv->probe) { 1519251345dSVinod Koul pr_err("driver %s didn't provide SDW probe routine\n", 1529251345dSVinod Koul drv->name); 1539251345dSVinod Koul return -EINVAL; 1549251345dSVinod Koul } 1559251345dSVinod Koul 1569251345dSVinod Koul drv->driver.owner = owner; 1579251345dSVinod Koul drv->driver.probe = sdw_drv_probe; 1589251345dSVinod Koul 1599251345dSVinod Koul if (drv->remove) 1609251345dSVinod Koul drv->driver.remove = sdw_drv_remove; 1619251345dSVinod Koul 1629251345dSVinod Koul if (drv->shutdown) 1639251345dSVinod Koul drv->driver.shutdown = sdw_drv_shutdown; 1649251345dSVinod Koul 1659251345dSVinod Koul return driver_register(&drv->driver); 1669251345dSVinod Koul } 1679251345dSVinod Koul EXPORT_SYMBOL_GPL(__sdw_register_driver); 1689251345dSVinod Koul 1699251345dSVinod Koul /** 1709251345dSVinod Koul * sdw_unregister_driver() - unregisters the SoundWire Slave driver 1719251345dSVinod Koul * @drv: driver to unregister 1729251345dSVinod Koul */ 1739251345dSVinod Koul void sdw_unregister_driver(struct sdw_driver *drv) 1749251345dSVinod Koul { 1759251345dSVinod Koul driver_unregister(&drv->driver); 1769251345dSVinod Koul } 1779251345dSVinod Koul EXPORT_SYMBOL_GPL(sdw_unregister_driver); 1789251345dSVinod Koul 1799251345dSVinod Koul static int __init sdw_bus_init(void) 1809251345dSVinod Koul { 181bf03473dSPierre-Louis Bossart sdw_debugfs_init(); 1829251345dSVinod Koul return bus_register(&sdw_bus_type); 1839251345dSVinod Koul } 1849251345dSVinod Koul 1859251345dSVinod Koul static void __exit sdw_bus_exit(void) 1869251345dSVinod Koul { 187bf03473dSPierre-Louis Bossart sdw_debugfs_exit(); 1889251345dSVinod Koul bus_unregister(&sdw_bus_type); 1899251345dSVinod Koul } 1909251345dSVinod Koul 1919251345dSVinod Koul postcore_initcall(sdw_bus_init); 1929251345dSVinod Koul module_exit(sdw_bus_exit); 1939251345dSVinod Koul 1949251345dSVinod Koul MODULE_DESCRIPTION("SoundWire bus"); 1959251345dSVinod Koul MODULE_LICENSE("GPL v2"); 196