brintos

brintos / linux-shallow public Read only

0
0
Text · 13.2 KiB · 96d4d7e Raw
557 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * Copyright (C) 2016 Robert Jarzmik <robert.jarzmik@free.fr>4 */5 6#include <linux/module.h>7#include <linux/bitops.h>8#include <linux/clk.h>9#include <linux/device.h>10#include <linux/idr.h>11#include <linux/list.h>12#include <linux/mutex.h>13#include <linux/of.h>14#include <linux/pm.h>15#include <linux/pm_runtime.h>16#include <linux/slab.h>17#include <linux/sysfs.h>18#include <sound/ac97_codec.h>19#include <sound/ac97/codec.h>20#include <sound/ac97/controller.h>21#include <sound/ac97/regs.h>22 23#include "ac97_core.h"24 25/*26 * Protects ac97_controllers and each ac97_controller structure.27 */28static DEFINE_MUTEX(ac97_controllers_mutex);29static DEFINE_IDR(ac97_adapter_idr);30static LIST_HEAD(ac97_controllers);31 32static inline struct ac97_controller*33to_ac97_controller(struct device *ac97_adapter)34{35	return container_of(ac97_adapter, struct ac97_controller, adap);36}37 38static int ac97_unbound_ctrl_write(struct ac97_controller *adrv, int slot,39		     unsigned short reg, unsigned short val)40{41	return -ENODEV;42}43 44static int ac97_unbound_ctrl_read(struct ac97_controller *adrv, int slot,45				  unsigned short reg)46{47	return -ENODEV;48}49 50static const struct ac97_controller_ops ac97_unbound_ctrl_ops = {51	.write = ac97_unbound_ctrl_write,52	.read = ac97_unbound_ctrl_read,53};54 55static struct ac97_controller ac97_unbound_ctrl = {56	.ops = &ac97_unbound_ctrl_ops,57};58 59static struct ac97_codec_device *60ac97_codec_find(struct ac97_controller *ac97_ctrl, unsigned int codec_num)61{62	if (codec_num >= AC97_BUS_MAX_CODECS)63		return ERR_PTR(-EINVAL);64 65	return ac97_ctrl->codecs[codec_num];66}67 68static struct device_node *69ac97_of_get_child_device(struct ac97_controller *ac97_ctrl, int idx,70			 unsigned int vendor_id)71{72	struct device_node *node;73	u32 reg;74	char compat[] = "ac97,0000,0000";75 76	snprintf(compat, sizeof(compat), "ac97,%04x,%04x",77		 vendor_id >> 16, vendor_id & 0xffff);78 79	for_each_child_of_node(ac97_ctrl->parent->of_node, node) {80		if ((idx != of_property_read_u32(node, "reg", &reg)) ||81		    !of_device_is_compatible(node, compat))82			continue;83		return node;84	}85 86	return NULL;87}88 89static void ac97_codec_release(struct device *dev)90{91	struct ac97_codec_device *adev;92	struct ac97_controller *ac97_ctrl;93 94	adev = to_ac97_device(dev);95	ac97_ctrl = adev->ac97_ctrl;96	ac97_ctrl->codecs[adev->num] = NULL;97	of_node_put(dev->of_node);98	kfree(adev);99}100 101static int ac97_codec_add(struct ac97_controller *ac97_ctrl, int idx,102		   unsigned int vendor_id)103{104	struct ac97_codec_device *codec;105	int ret;106 107	codec = kzalloc(sizeof(*codec), GFP_KERNEL);108	if (!codec)109		return -ENOMEM;110	ac97_ctrl->codecs[idx] = codec;111	codec->vendor_id = vendor_id;112	codec->dev.release = ac97_codec_release;113	codec->dev.bus = &ac97_bus_type;114	codec->dev.parent = &ac97_ctrl->adap;115	codec->num = idx;116	codec->ac97_ctrl = ac97_ctrl;117 118	device_initialize(&codec->dev);119	dev_set_name(&codec->dev, "%s:%u", dev_name(ac97_ctrl->parent), idx);120	codec->dev.of_node = ac97_of_get_child_device(ac97_ctrl, idx,121						      vendor_id);122 123	ret = device_add(&codec->dev);124	if (ret) {125		put_device(&codec->dev);126		return ret;127	}128 129	return 0;130}131 132unsigned int snd_ac97_bus_scan_one(struct ac97_controller *adrv,133				   unsigned int codec_num)134{135	unsigned short vid1, vid2;136	int ret;137 138	ret = adrv->ops->read(adrv, codec_num, AC97_VENDOR_ID1);139	vid1 = (ret & 0xffff);140	if (ret < 0)141		return 0;142 143	ret = adrv->ops->read(adrv, codec_num, AC97_VENDOR_ID2);144	vid2 = (ret & 0xffff);145	if (ret < 0)146		return 0;147 148	dev_dbg(&adrv->adap, "%s(codec_num=%u): vendor_id=0x%08x\n",149		__func__, codec_num, AC97_ID(vid1, vid2));150	return AC97_ID(vid1, vid2);151}152 153static int ac97_bus_scan(struct ac97_controller *ac97_ctrl)154{155	int ret, i;156	unsigned int vendor_id;157 158	for (i = 0; i < AC97_BUS_MAX_CODECS; i++) {159		if (ac97_codec_find(ac97_ctrl, i))160			continue;161		if (!(ac97_ctrl->slots_available & BIT(i)))162			continue;163		vendor_id = snd_ac97_bus_scan_one(ac97_ctrl, i);164		if (!vendor_id)165			continue;166 167		ret = ac97_codec_add(ac97_ctrl, i, vendor_id);168		if (ret < 0)169			return ret;170	}171	return 0;172}173 174static int ac97_bus_reset(struct ac97_controller *ac97_ctrl)175{176	ac97_ctrl->ops->reset(ac97_ctrl);177 178	return 0;179}180 181/**182 * snd_ac97_codec_driver_register - register an AC97 codec driver183 * @dev: AC97 driver codec to register184 *185 * Register an AC97 codec driver to the ac97 bus driver, aka. the AC97 digital186 * controller.187 *188 * Returns 0 on success or error code189 */190int snd_ac97_codec_driver_register(struct ac97_codec_driver *drv)191{192	drv->driver.bus = &ac97_bus_type;193	return driver_register(&drv->driver);194}195EXPORT_SYMBOL_GPL(snd_ac97_codec_driver_register);196 197/**198 * snd_ac97_codec_driver_unregister - unregister an AC97 codec driver199 * @dev: AC97 codec driver to unregister200 *201 * Unregister a previously registered ac97 codec driver.202 */203void snd_ac97_codec_driver_unregister(struct ac97_codec_driver *drv)204{205	driver_unregister(&drv->driver);206}207EXPORT_SYMBOL_GPL(snd_ac97_codec_driver_unregister);208 209/**210 * snd_ac97_codec_get_platdata - get platform_data211 * @adev: the ac97 codec device212 *213 * For legacy platforms, in order to have platform_data in codec drivers214 * available, while ac97 device are auto-created upon probe, this retrieves the215 * platdata which was setup on ac97 controller registration.216 *217 * Returns the platform data pointer218 */219void *snd_ac97_codec_get_platdata(const struct ac97_codec_device *adev)220{221	struct ac97_controller *ac97_ctrl = adev->ac97_ctrl;222 223	return ac97_ctrl->codecs_pdata[adev->num];224}225EXPORT_SYMBOL_GPL(snd_ac97_codec_get_platdata);226 227static void ac97_ctrl_codecs_unregister(struct ac97_controller *ac97_ctrl)228{229	int i;230 231	for (i = 0; i < AC97_BUS_MAX_CODECS; i++)232		if (ac97_ctrl->codecs[i]) {233			ac97_ctrl->codecs[i]->ac97_ctrl = &ac97_unbound_ctrl;234			device_unregister(&ac97_ctrl->codecs[i]->dev);235		}236}237 238static ssize_t cold_reset_store(struct device *dev,239				struct device_attribute *attr, const char *buf,240				size_t len)241{242	struct ac97_controller *ac97_ctrl;243 244	mutex_lock(&ac97_controllers_mutex);245	ac97_ctrl = to_ac97_controller(dev);246	ac97_ctrl->ops->reset(ac97_ctrl);247	mutex_unlock(&ac97_controllers_mutex);248	return len;249}250static DEVICE_ATTR_WO(cold_reset);251 252static ssize_t warm_reset_store(struct device *dev,253				struct device_attribute *attr, const char *buf,254				size_t len)255{256	struct ac97_controller *ac97_ctrl;257 258	if (!dev)259		return -ENODEV;260 261	mutex_lock(&ac97_controllers_mutex);262	ac97_ctrl = to_ac97_controller(dev);263	ac97_ctrl->ops->warm_reset(ac97_ctrl);264	mutex_unlock(&ac97_controllers_mutex);265	return len;266}267static DEVICE_ATTR_WO(warm_reset);268 269static struct attribute *ac97_controller_device_attrs[] = {270	&dev_attr_cold_reset.attr,271	&dev_attr_warm_reset.attr,272	NULL273};274 275static const struct attribute_group ac97_adapter_attr_group = {276	.name	= "ac97_operations",277	.attrs	= ac97_controller_device_attrs,278};279 280static const struct attribute_group *ac97_adapter_groups[] = {281	&ac97_adapter_attr_group,282	NULL,283};284 285static void ac97_del_adapter(struct ac97_controller *ac97_ctrl)286{287	mutex_lock(&ac97_controllers_mutex);288	ac97_ctrl_codecs_unregister(ac97_ctrl);289	list_del(&ac97_ctrl->controllers);290	mutex_unlock(&ac97_controllers_mutex);291 292	device_unregister(&ac97_ctrl->adap);293}294 295static void ac97_adapter_release(struct device *dev)296{297	struct ac97_controller *ac97_ctrl;298 299	ac97_ctrl = to_ac97_controller(dev);300	idr_remove(&ac97_adapter_idr, ac97_ctrl->nr);301	dev_dbg(&ac97_ctrl->adap, "adapter unregistered by %s\n",302		dev_name(ac97_ctrl->parent));303}304 305static const struct device_type ac97_adapter_type = {306	.groups		= ac97_adapter_groups,307	.release	= ac97_adapter_release,308};309 310static int ac97_add_adapter(struct ac97_controller *ac97_ctrl)311{312	int ret;313 314	mutex_lock(&ac97_controllers_mutex);315	ret = idr_alloc(&ac97_adapter_idr, ac97_ctrl, 0, 0, GFP_KERNEL);316	ac97_ctrl->nr = ret;317	if (ret >= 0) {318		dev_set_name(&ac97_ctrl->adap, "ac97-%d", ret);319		ac97_ctrl->adap.type = &ac97_adapter_type;320		ac97_ctrl->adap.parent = ac97_ctrl->parent;321		ret = device_register(&ac97_ctrl->adap);322		if (ret)323			put_device(&ac97_ctrl->adap);324	}325	if (!ret)326		list_add(&ac97_ctrl->controllers, &ac97_controllers);327	mutex_unlock(&ac97_controllers_mutex);328 329	if (!ret)330		dev_dbg(&ac97_ctrl->adap, "adapter registered by %s\n",331			dev_name(ac97_ctrl->parent));332	return ret;333}334 335/**336 * snd_ac97_controller_register - register an ac97 controller337 * @ops: the ac97 bus operations338 * @dev: the device providing the ac97 DC function339 * @slots_available: mask of the ac97 codecs that can be scanned and probed340 *                   bit0 => codec 0, bit1 => codec 1 ... bit 3 => codec 3341 *342 * Register a digital controller which can control up to 4 ac97 codecs. This is343 * the controller side of the AC97 AC-link, while the slave side are the codecs.344 *345 * Returns a valid controller upon success, negative pointer value upon error346 */347struct ac97_controller *snd_ac97_controller_register(348	const struct ac97_controller_ops *ops, struct device *dev,349	unsigned short slots_available, void **codecs_pdata)350{351	struct ac97_controller *ac97_ctrl;352	int ret, i;353 354	ac97_ctrl = kzalloc(sizeof(*ac97_ctrl), GFP_KERNEL);355	if (!ac97_ctrl)356		return ERR_PTR(-ENOMEM);357 358	for (i = 0; i < AC97_BUS_MAX_CODECS && codecs_pdata; i++)359		ac97_ctrl->codecs_pdata[i] = codecs_pdata[i];360 361	ac97_ctrl->ops = ops;362	ac97_ctrl->slots_available = slots_available;363	ac97_ctrl->parent = dev;364	ret = ac97_add_adapter(ac97_ctrl);365 366	if (ret)367		goto err;368	ac97_bus_reset(ac97_ctrl);369	ac97_bus_scan(ac97_ctrl);370 371	return ac97_ctrl;372err:373	kfree(ac97_ctrl);374	return ERR_PTR(ret);375}376EXPORT_SYMBOL_GPL(snd_ac97_controller_register);377 378/**379 * snd_ac97_controller_unregister - unregister an ac97 controller380 * @ac97_ctrl: the device previously provided to ac97_controller_register()381 *382 */383void snd_ac97_controller_unregister(struct ac97_controller *ac97_ctrl)384{385	ac97_del_adapter(ac97_ctrl);386}387EXPORT_SYMBOL_GPL(snd_ac97_controller_unregister);388 389#ifdef CONFIG_PM390static int ac97_pm_runtime_suspend(struct device *dev)391{392	struct ac97_codec_device *codec = to_ac97_device(dev);393	int ret = pm_generic_runtime_suspend(dev);394 395	if (ret == 0 && dev->driver) {396		if (pm_runtime_is_irq_safe(dev))397			clk_disable(codec->clk);398		else399			clk_disable_unprepare(codec->clk);400	}401 402	return ret;403}404 405static int ac97_pm_runtime_resume(struct device *dev)406{407	struct ac97_codec_device *codec = to_ac97_device(dev);408	int ret;409 410	if (dev->driver) {411		if (pm_runtime_is_irq_safe(dev))412			ret = clk_enable(codec->clk);413		else414			ret = clk_prepare_enable(codec->clk);415		if (ret)416			return ret;417	}418 419	return pm_generic_runtime_resume(dev);420}421#endif /* CONFIG_PM */422 423static const struct dev_pm_ops ac97_pm = {424	.suspend	= pm_generic_suspend,425	.resume		= pm_generic_resume,426	.freeze		= pm_generic_freeze,427	.thaw		= pm_generic_thaw,428	.poweroff	= pm_generic_poweroff,429	.restore	= pm_generic_restore,430	SET_RUNTIME_PM_OPS(431		ac97_pm_runtime_suspend,432		ac97_pm_runtime_resume,433		NULL)434};435 436static int ac97_get_enable_clk(struct ac97_codec_device *adev)437{438	int ret;439 440	adev->clk = clk_get(&adev->dev, "ac97_clk");441	if (IS_ERR(adev->clk))442		return PTR_ERR(adev->clk);443 444	ret = clk_prepare_enable(adev->clk);445	if (ret)446		clk_put(adev->clk);447 448	return ret;449}450 451static void ac97_put_disable_clk(struct ac97_codec_device *adev)452{453	clk_disable_unprepare(adev->clk);454	clk_put(adev->clk);455}456 457static ssize_t vendor_id_show(struct device *dev,458			      struct device_attribute *attr, char *buf)459{460	struct ac97_codec_device *codec = to_ac97_device(dev);461 462	return sysfs_emit(buf, "%08x", codec->vendor_id);463}464static DEVICE_ATTR_RO(vendor_id);465 466static struct attribute *ac97_dev_attrs[] = {467	&dev_attr_vendor_id.attr,468	NULL,469};470ATTRIBUTE_GROUPS(ac97_dev);471 472static int ac97_bus_match(struct device *dev, const struct device_driver *drv)473{474	struct ac97_codec_device *adev = to_ac97_device(dev);475	const struct ac97_codec_driver *adrv = to_ac97_driver(drv);476	const struct ac97_id *id = adrv->id_table;477	int i = 0;478 479	if (adev->vendor_id == 0x0 || adev->vendor_id == 0xffffffff)480		return false;481 482	do {483		if (ac97_ids_match(id[i].id, adev->vendor_id, id[i].mask))484			return true;485	} while (id[i++].id);486 487	return false;488}489 490static int ac97_bus_probe(struct device *dev)491{492	struct ac97_codec_device *adev = to_ac97_device(dev);493	struct ac97_codec_driver *adrv = to_ac97_driver(dev->driver);494	int ret;495 496	ret = ac97_get_enable_clk(adev);497	if (ret)498		return ret;499 500	pm_runtime_get_noresume(dev);501	pm_runtime_set_active(dev);502	pm_runtime_enable(dev);503 504	ret = adrv->probe(adev);505	if (ret == 0)506		return 0;507 508	pm_runtime_disable(dev);509	pm_runtime_set_suspended(dev);510	pm_runtime_put_noidle(dev);511	ac97_put_disable_clk(adev);512 513	return ret;514}515 516static void ac97_bus_remove(struct device *dev)517{518	struct ac97_codec_device *adev = to_ac97_device(dev);519	struct ac97_codec_driver *adrv = to_ac97_driver(dev->driver);520	int ret;521 522	ret = pm_runtime_resume_and_get(dev);523	if (ret < 0)524		return;525 526	adrv->remove(adev);527	pm_runtime_put_noidle(dev);528	ac97_put_disable_clk(adev);529 530	pm_runtime_disable(dev);531}532 533const struct bus_type ac97_bus_type = {534	.name		= "ac97bus",535	.dev_groups	= ac97_dev_groups,536	.match		= ac97_bus_match,537	.pm		= &ac97_pm,538	.probe		= ac97_bus_probe,539	.remove		= ac97_bus_remove,540};541 542static int __init ac97_bus_init(void)543{544	return bus_register(&ac97_bus_type);545}546subsys_initcall(ac97_bus_init);547 548static void __exit ac97_bus_exit(void)549{550	bus_unregister(&ac97_bus_type);551}552module_exit(ac97_bus_exit);553 554MODULE_DESCRIPTION("AC97 bus interface");555MODULE_LICENSE("GPL");556MODULE_AUTHOR("Robert Jarzmik <robert.jarzmik@free.fr>");557