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