xref: /openbmc/linux/drivers/soundwire/bus_type.c (revision bf03473d)
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