From a33debe2706bf61f2cdc2732720533974472a5ae Mon Sep 17 00:00:00 2001
From: Tobias Poganiuch <tobias.poganiuch@seco.com>
Date: Wed, 9 Aug 2023 14:38:08 +0200
Subject: [PATCH] driver:ac97: Added dummy AC97 driver

---
 drivers/staging/Kconfig        |   2 +
 drivers/staging/Makefile       |   1 +
 drivers/staging/misc/Kconfig   |  18 ++++
 drivers/staging/misc/Makefile  |   6 ++
 drivers/staging/misc/mumpitz.c | 157 +++++++++++++++++++++++++++++++++
 5 files changed, 184 insertions(+)
 create mode 100644 drivers/staging/misc/Kconfig
 create mode 100644 drivers/staging/misc/Makefile
 create mode 100644 drivers/staging/misc/mumpitz.c

diff --git a/drivers/staging/Kconfig b/drivers/staging/Kconfig
index c08f68800a932..2f741a1611add 100644
--- a/drivers/staging/Kconfig
+++ b/drivers/staging/Kconfig
@@ -116,4 +116,6 @@ source "drivers/staging/mfd/Kconfig"
 
 source "drivers/staging/input/Kconfig"
 
+source "drivers/staging/misc/Kconfig"
+
 endif # STAGING
diff --git a/drivers/staging/Makefile b/drivers/staging/Makefile
index 69c83d0823728..81221eaa28d1a 100644
--- a/drivers/staging/Makefile
+++ b/drivers/staging/Makefile
@@ -48,3 +48,4 @@ obj-y				+= gpio/
 obj-y				+= gpu/drm/
 obj-y				+= mfd/
 obj-y				+= input/
+obj-y				+= misc/
diff --git a/drivers/staging/misc/Kconfig b/drivers/staging/misc/Kconfig
new file mode 100644
index 0000000000000..8943f86d05a4b
--- /dev/null
+++ b/drivers/staging/misc/Kconfig
@@ -0,0 +1,18 @@
+# SPDX-License-Identifier: GPL-2.0
+#
+# Misc drivers
+#
+
+menu "Misc"
+
+config AC97_MUMPITZ
+	bool "Dummy device driver for AC97"
+	select REGMAP_AC97
+	select AC97_BUS_COMPAT
+	depends on AC97_BUS_NEW
+	help
+	  Say yes here to enable the dummy device driver for AC97.
+	  The driver polls an WM9705 Codec in fixed intervals to
+	  simulate AC97 traffic.
+
+endmenu
diff --git a/drivers/staging/misc/Makefile b/drivers/staging/misc/Makefile
new file mode 100644
index 0000000000000..9aecaf6d5381d
--- /dev/null
+++ b/drivers/staging/misc/Makefile
@@ -0,0 +1,6 @@
+# SPDX-License-Identifier: GPL-2.0
+#
+# Makefile for misc drivers
+#
+
+obj-$(CONFIG_AC97_MUMPITZ)	+= mumpitz.o
diff --git a/drivers/staging/misc/mumpitz.c b/drivers/staging/misc/mumpitz.c
new file mode 100644
index 0000000000000..5e08c5e24523d
--- /dev/null
+++ b/drivers/staging/misc/mumpitz.c
@@ -0,0 +1,157 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include <linux/regmap.h>
+#include <linux/workqueue.h>
+#include <sound/ac97/codec.h>
+#include <sound/ac97/compat.h>
+
+#define MUMPITZ_VENDOR_ID 0x574d4c05
+#define MUMPITZ_VENDOR_ID_MASK 0xffffffff
+#define MUMPITZ_WORK_INTERVAL 10
+
+struct mumpitz_platform_data {
+	struct snd_ac97 *ac97;
+	struct regmap *regmap;
+};
+
+struct mumpitz_priv {
+	struct regmap *regmap;
+	struct snd_ac97 *ac97;
+	struct device *dev;
+	struct mumpitz_platform_data codec_pdata;
+	int vendor_id1;
+	int vendor_id2;
+
+	struct delayed_work reader;
+	struct workqueue_struct *workq;
+};
+
+/* AC97 Read/Write */
+
+int mumpitz_ac97_reg_read(struct mumpitz_priv *mup, u16 reg)
+{
+	if (mup->ac97)
+		return mup->ac97->bus->ops->read(mup->ac97, reg);
+	else
+		return -1;
+}
+
+void mumpitz_ac97_reg_write(struct mumpitz_priv *mup, u16 reg, u16 val)
+{
+	if (mup->ac97)
+		mup->ac97->bus->ops->write(mup->ac97, reg, val);
+}
+
+/* Driver */
+
+static void mumpitz_ac97_worker(struct work_struct *work)
+{
+	struct mumpitz_priv *mup = container_of(work, struct mumpitz_priv,
+						reader.work);
+
+	dev_dbg(mup->dev, "Test #1");
+
+	/* Read/Write to AC97 Codec */
+
+	queue_delayed_work(mup->workq, &mup->reader,
+			   MUMPITZ_WORK_INTERVAL);
+}
+
+static int mumpitz_ac97_probe(struct ac97_codec_device *adev)
+{
+	struct mumpitz_priv *mumpitz;
+	const struct regmap_config *config;
+	struct mumpitz_platform_data *codec_pdata;
+	int ret = -ENODEV; 
+
+	mumpitz = devm_kzalloc(ac97_codec_dev2dev(adev),
+			       sizeof(*mumpitz), GFP_KERNEL);
+
+	if (!mumpitz)
+		return -ENOMEM;
+
+	mumpitz->dev = ac97_codec_dev2dev(adev);
+	mumpitz->ac97 = snd_ac97_compat_alloc(adev);
+
+	if (IS_ERR(mumpitz->ac97))
+		return PTR_ERR(mumpitz->ac97);
+
+	ac97_set_drvdata(adev, mumpitz);
+	dev_info(mumpitz->dev, "mumpitz core found, id=0x%x\n",
+		 adev->vendor_id);
+
+	codec_pdata = &mumpitz->codec_pdata;
+	codec_pdata->ac97 = mumpitz->ac97;
+
+	if (adev->vendor_id != MUMPITZ_VENDOR_ID)
+		goto err_free_compat;
+
+	codec_pdata->regmap = devm_regmap_init_ac97(mumpitz->ac97, config);
+
+	if (IS_ERR(codec_pdata->regmap)) {
+		ret = PTR_ERR(codec_pdata->regmap);
+		goto err_free_compat;
+	}
+
+	/* Check for supported codec */
+
+	mumpitz->vendor_id1 = mumpitz_ac97_reg_read(mumpitz, AC97_VENDOR_ID1);
+
+	if (mumpitz->vendor_id1 != (MUMPITZ_VENDOR_ID >> 4)) {
+		dev_err(mumpitz->dev, "Device with vendor %04x is not a mumpitz\n",
+			mumpitz->vendor_id1);
+		return -ENODEV;
+	}
+
+	mumpitz->vendor_id2 = mumpitz_ac97_reg_read(mumpitz, AC97_VENDOR_ID2);
+
+	dev_info(mumpitz->dev, "id1: %04x id2: %04x",
+		 mumpitz->vendor_id1, mumpitz->vendor_id2);
+
+	/* Start AC97 Polling */
+
+	mumpitz->workq = alloc_ordered_workqueue("kmumpitz", 0);
+
+	if (mumpitz->workq == NULL) {
+		dev_err(mumpitz->dev,
+			"Failed to create workqueue\n");
+		return -EINVAL;
+	}
+
+	INIT_DELAYED_WORK(&mumpitz->reader, mumpitz_ac97_worker);
+
+	queue_delayed_work(mumpitz->workq, &mumpitz->reader,
+			   MUMPITZ_WORK_INTERVAL);
+
+	if (ret)
+		goto err_free_compat;
+
+	return ret;
+
+err_free_compat:
+	snd_ac97_compat_release(mumpitz->ac97);
+	return ret;
+}
+
+static int mumpitz_ac97_remove(struct ac97_codec_device *adev)
+{
+	struct mumpitz_priv *mumpitz = ac97_get_drvdata(adev);
+
+	snd_ac97_compat_release(mumpitz->ac97);
+
+	return 0;
+}
+
+static const struct ac97_id mumpitz_ac97_ids[] = {
+	{ .id = MUMPITZ_VENDOR_ID, .mask = MUMPITZ_VENDOR_ID_MASK },
+	{ }
+};
+
+static struct ac97_codec_driver mumpitz_ac97_driver = {
+	.driver = {
+		.name = "mumpitz",
+	},
+	.probe		= mumpitz_ac97_probe,
+	.remove		= mumpitz_ac97_remove,
+	.id_table	= mumpitz_ac97_ids,
+};
-- 
GitLab