18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci *  Copyright (C) 2016 Robert Jarzmik <robert.jarzmik@free.fr>
48c2ecf20Sopenharmony_ci */
58c2ecf20Sopenharmony_ci
68c2ecf20Sopenharmony_ci#include <linux/list.h>
78c2ecf20Sopenharmony_ci#include <linux/slab.h>
88c2ecf20Sopenharmony_ci#include <sound/ac97/codec.h>
98c2ecf20Sopenharmony_ci#include <sound/ac97/compat.h>
108c2ecf20Sopenharmony_ci#include <sound/ac97/controller.h>
118c2ecf20Sopenharmony_ci#include <sound/soc.h>
128c2ecf20Sopenharmony_ci
138c2ecf20Sopenharmony_ci#include "ac97_core.h"
148c2ecf20Sopenharmony_ci
158c2ecf20Sopenharmony_cistatic void compat_ac97_release(struct device *dev)
168c2ecf20Sopenharmony_ci{
178c2ecf20Sopenharmony_ci	kfree(to_ac97_t(dev));
188c2ecf20Sopenharmony_ci}
198c2ecf20Sopenharmony_ci
208c2ecf20Sopenharmony_cistatic void compat_ac97_reset(struct snd_ac97 *ac97)
218c2ecf20Sopenharmony_ci{
228c2ecf20Sopenharmony_ci	struct ac97_codec_device *adev = to_ac97_device(ac97->private_data);
238c2ecf20Sopenharmony_ci	struct ac97_controller *actrl = adev->ac97_ctrl;
248c2ecf20Sopenharmony_ci
258c2ecf20Sopenharmony_ci	if (actrl->ops->reset)
268c2ecf20Sopenharmony_ci		actrl->ops->reset(actrl);
278c2ecf20Sopenharmony_ci}
288c2ecf20Sopenharmony_ci
298c2ecf20Sopenharmony_cistatic void compat_ac97_warm_reset(struct snd_ac97 *ac97)
308c2ecf20Sopenharmony_ci{
318c2ecf20Sopenharmony_ci	struct ac97_codec_device *adev = to_ac97_device(ac97->private_data);
328c2ecf20Sopenharmony_ci	struct ac97_controller *actrl = adev->ac97_ctrl;
338c2ecf20Sopenharmony_ci
348c2ecf20Sopenharmony_ci	if (actrl->ops->warm_reset)
358c2ecf20Sopenharmony_ci		actrl->ops->warm_reset(actrl);
368c2ecf20Sopenharmony_ci}
378c2ecf20Sopenharmony_ci
388c2ecf20Sopenharmony_cistatic void compat_ac97_write(struct snd_ac97 *ac97, unsigned short reg,
398c2ecf20Sopenharmony_ci			      unsigned short val)
408c2ecf20Sopenharmony_ci{
418c2ecf20Sopenharmony_ci	struct ac97_codec_device *adev = to_ac97_device(ac97->private_data);
428c2ecf20Sopenharmony_ci	struct ac97_controller *actrl = adev->ac97_ctrl;
438c2ecf20Sopenharmony_ci
448c2ecf20Sopenharmony_ci	actrl->ops->write(actrl, ac97->num, reg, val);
458c2ecf20Sopenharmony_ci}
468c2ecf20Sopenharmony_ci
478c2ecf20Sopenharmony_cistatic unsigned short compat_ac97_read(struct snd_ac97 *ac97,
488c2ecf20Sopenharmony_ci				       unsigned short reg)
498c2ecf20Sopenharmony_ci{
508c2ecf20Sopenharmony_ci	struct ac97_codec_device *adev = to_ac97_device(ac97->private_data);
518c2ecf20Sopenharmony_ci	struct ac97_controller *actrl = adev->ac97_ctrl;
528c2ecf20Sopenharmony_ci
538c2ecf20Sopenharmony_ci	return actrl->ops->read(actrl, ac97->num, reg);
548c2ecf20Sopenharmony_ci}
558c2ecf20Sopenharmony_ci
568c2ecf20Sopenharmony_cistatic const struct snd_ac97_bus_ops compat_snd_ac97_bus_ops = {
578c2ecf20Sopenharmony_ci	.reset = compat_ac97_reset,
588c2ecf20Sopenharmony_ci	.warm_reset = compat_ac97_warm_reset,
598c2ecf20Sopenharmony_ci	.write = compat_ac97_write,
608c2ecf20Sopenharmony_ci	.read = compat_ac97_read,
618c2ecf20Sopenharmony_ci};
628c2ecf20Sopenharmony_ci
638c2ecf20Sopenharmony_cistatic struct snd_ac97_bus compat_soc_ac97_bus = {
648c2ecf20Sopenharmony_ci	.ops = &compat_snd_ac97_bus_ops,
658c2ecf20Sopenharmony_ci};
668c2ecf20Sopenharmony_ci
678c2ecf20Sopenharmony_cistruct snd_ac97 *snd_ac97_compat_alloc(struct ac97_codec_device *adev)
688c2ecf20Sopenharmony_ci{
698c2ecf20Sopenharmony_ci	struct snd_ac97 *ac97;
708c2ecf20Sopenharmony_ci	int ret;
718c2ecf20Sopenharmony_ci
728c2ecf20Sopenharmony_ci	ac97 = kzalloc(sizeof(struct snd_ac97), GFP_KERNEL);
738c2ecf20Sopenharmony_ci	if (ac97 == NULL)
748c2ecf20Sopenharmony_ci		return ERR_PTR(-ENOMEM);
758c2ecf20Sopenharmony_ci
768c2ecf20Sopenharmony_ci	ac97->private_data = adev;
778c2ecf20Sopenharmony_ci	ac97->bus = &compat_soc_ac97_bus;
788c2ecf20Sopenharmony_ci
798c2ecf20Sopenharmony_ci	ac97->dev.parent = &adev->dev;
808c2ecf20Sopenharmony_ci	ac97->dev.release = compat_ac97_release;
818c2ecf20Sopenharmony_ci	dev_set_name(&ac97->dev, "%s-compat", dev_name(&adev->dev));
828c2ecf20Sopenharmony_ci	ret = device_register(&ac97->dev);
838c2ecf20Sopenharmony_ci	if (ret) {
848c2ecf20Sopenharmony_ci		put_device(&ac97->dev);
858c2ecf20Sopenharmony_ci		return ERR_PTR(ret);
868c2ecf20Sopenharmony_ci	}
878c2ecf20Sopenharmony_ci
888c2ecf20Sopenharmony_ci	return ac97;
898c2ecf20Sopenharmony_ci}
908c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(snd_ac97_compat_alloc);
918c2ecf20Sopenharmony_ci
928c2ecf20Sopenharmony_civoid snd_ac97_compat_release(struct snd_ac97 *ac97)
938c2ecf20Sopenharmony_ci{
948c2ecf20Sopenharmony_ci	device_unregister(&ac97->dev);
958c2ecf20Sopenharmony_ci}
968c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(snd_ac97_compat_release);
978c2ecf20Sopenharmony_ci
988c2ecf20Sopenharmony_ciint snd_ac97_reset(struct snd_ac97 *ac97, bool try_warm, unsigned int id,
998c2ecf20Sopenharmony_ci	unsigned int id_mask)
1008c2ecf20Sopenharmony_ci{
1018c2ecf20Sopenharmony_ci	struct ac97_codec_device *adev = to_ac97_device(ac97->private_data);
1028c2ecf20Sopenharmony_ci	struct ac97_controller *actrl = adev->ac97_ctrl;
1038c2ecf20Sopenharmony_ci	unsigned int scanned;
1048c2ecf20Sopenharmony_ci
1058c2ecf20Sopenharmony_ci	if (try_warm) {
1068c2ecf20Sopenharmony_ci		compat_ac97_warm_reset(ac97);
1078c2ecf20Sopenharmony_ci		scanned = snd_ac97_bus_scan_one(actrl, adev->num);
1088c2ecf20Sopenharmony_ci		if (ac97_ids_match(scanned, adev->vendor_id, id_mask))
1098c2ecf20Sopenharmony_ci			return 1;
1108c2ecf20Sopenharmony_ci	}
1118c2ecf20Sopenharmony_ci
1128c2ecf20Sopenharmony_ci	compat_ac97_reset(ac97);
1138c2ecf20Sopenharmony_ci	compat_ac97_warm_reset(ac97);
1148c2ecf20Sopenharmony_ci	scanned = snd_ac97_bus_scan_one(actrl, adev->num);
1158c2ecf20Sopenharmony_ci	if (ac97_ids_match(scanned, adev->vendor_id, id_mask))
1168c2ecf20Sopenharmony_ci		return 0;
1178c2ecf20Sopenharmony_ci
1188c2ecf20Sopenharmony_ci	return -ENODEV;
1198c2ecf20Sopenharmony_ci}
1208c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(snd_ac97_reset);
121